diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -8,31 +8,44 @@
 
 ## Versioning
 
-Binaryen evolves fast and can introduce C API changes in every release. Before
-building the Haskell bindings, please check the Binaryen version and make sure
+Starting from `0.0.5.0`, we bundle the C++ sources of `binaryen` with this
+package, so the package can be built and used as long as the C++ toolchain is
+present in the build environment. The `system-binaryen` Cabal flag defaults to
+`False`, but it can be manually enabled to link against the system-wide
+`binaryen` library and avoid building the bundled C++ library.
+
+| Haskell bindings version | Bundled Binaryen version |
+| ------------------------ | ------------------------ |
+| 0.0.5.\*                 | version_98               |
+
+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
 it's no less than the minimum version listed below.
 
 | Haskell bindings version | Minimum Binaryen version |
-|--------------------------|--------------------------|
-| 0.0.1.*                  | version_91               |
-| 0.0.2.*                  | version_94               |
-| 0.0.3.*                  | version_96               |
-| 0.0.4.*                  | version_97               |
-
+| ------------------------ | ------------------------ |
+| 0.0.1.\*                 | version_91               |
+| 0.0.2.\*                 | version_94               |
+| 0.0.3.\*                 | version_96               |
+| 0.0.4.\*                 | version_97               |
 
 ## How to build
 
-This package relies on the system-provided Binaryen library. As long as that's
-available, a simple `stack build` or `cabal build` command should work.
+A simple `stack build` or `cabal build` command should work.
 
-`Nix`-based build is also supported. Install [Stack][stack] and [Nix][nix].
-Then,
+For Windows `cabal` users: run the build in a msys2 mingw64 shell.
 
+[`nix`][nix]-based build is also supported:
+
 ```shell
-$ stack --nix build
+$ nix-shell --pure --run "cabal v2-run binaryen:test"
+$ nix-shell --pure --run "cabal v2-run binaryen:test --flags=system-binaryen --extra-include-dirs=\$binaryenIncludeDir --extra-lib-dirs=\$binaryenLibDir"
 ```
 
+Use the [`asterius`][cachix-asterius] Cachix bucket for reusing binary cache
+built on CI.
+
 [binaryen]: https://github.com/WebAssembly/binaryen
 [binaryen-api]: https://github.com/WebAssembly/binaryen/blob/master/src/binaryen-c.h
+[cachix-asterius]: https://app.cachix.org/cache/asterius
 [nix]: https://nixos.org/nix
-[stack]: https://docs.haskellstack.org/en/stable/README
diff --git a/Setup.hs b/Setup.hs
deleted file mode 100644
--- a/Setup.hs
+++ /dev/null
@@ -1,2 +0,0 @@
-import Distribution.Simple
-main = defaultMain
diff --git a/binaryen.cabal b/binaryen.cabal
--- a/binaryen.cabal
+++ b/binaryen.cabal
@@ -1,59 +1,2168 @@
-cabal-version: 1.12
-
--- This file has been generated from package.yaml by hpack version 0.33.0.
---
--- see: https://github.com/sol/hpack
---
--- hash: a97a536c6a54def78b714cf926b75e3dc2ede559d014ec6295143c608c11c1c9
-
-name:           binaryen
-version:        0.0.4.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
-homepage:       https://github.com/tweag/haskell-binaryen#readme
-bug-reports:    https://github.com/tweag/haskell-binaryen/issues
-maintainer:     Cheng Shao <cheng.shao@tweag.io>
-copyright:      (c) 2018 Tweag I/O
-license:        BSD3
-license-file:   LICENSE
-build-type:     Simple
-extra-source-files:
-    CHANGELOG.md
-    LICENSE
-    README.md
-
-source-repository head
-  type: git
-  location: https://github.com/tweag/haskell-binaryen
-
-library
-  exposed-modules:
-      Binaryen
-      Binaryen.Event
-      Binaryen.Export
-      Binaryen.Expression
-      Binaryen.ExpressionId
-      Binaryen.ExternalKind
-      Binaryen.Features
-      Binaryen.Function
-      Binaryen.Global
-      Binaryen.Index
-      Binaryen.Module
-      Binaryen.Op
-      Binaryen.Relooper
-      Binaryen.SideEffects
-      Binaryen.Type
-  other-modules:
-      Paths_binaryen
-  hs-source-dirs:
-      src
-  ghc-options: -Wall
-  c-sources:
-      cbits/wrappers.c
-  extra-libraries:
-      binaryen
-      stdc++
-  build-depends:
-      base <5
+cabal-version: 2.2
+
+-- This file has been generated from package.yaml by hpack version 0.33.0.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: dd229f4cad11bdebeaef89df68685de75858bc5d1ec3d969f606f0519e5e34b8
+
+name:           binaryen
+version:        0.0.5.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
+homepage:       https://github.com/tweag/haskell-binaryen#readme
+bug-reports:    https://github.com/tweag/haskell-binaryen/issues
+maintainer:     Cheng Shao <cheng.shao@tweag.io>
+copyright:      (c) 2018 Tweag I/O
+license:        BSD-3-Clause
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    binaryen/auto_update_tests.py
+    binaryen/CHANGELOG.md
+    binaryen/check.py
+    binaryen/CMakeLists.txt
+    binaryen/config.h.in
+    binaryen/Contributing.md
+    binaryen/LICENSE
+    binaryen/media/example.png
+    binaryen/README.md
+    binaryen/scripts/__init__.py
+    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
+    binaryen/scripts/fuzz_passes.py
+    binaryen/scripts/fuzz_passes_wast.py
+    binaryen/scripts/fuzz_relooper.py
+    binaryen/scripts/fuzz_shell.js
+    binaryen/scripts/gen-s-parser.py
+    binaryen/scripts/process_optimize_instructions.py
+    binaryen/scripts/storage.py
+    binaryen/scripts/strip_local_names.py
+    binaryen/scripts/test/__init__.py
+    binaryen/scripts/test/binaryenjs.py
+    binaryen/scripts/test/env.js
+    binaryen/scripts/test/generate_lld_tests.py
+    binaryen/scripts/test/lld.py
+    binaryen/scripts/test/mod.ule.js
+    binaryen/scripts/test/node-esm-loader.mjs
+    binaryen/scripts/test/shared.py
+    binaryen/scripts/test/spectest.js
+    binaryen/scripts/test/support.py
+    binaryen/scripts/test/wasm2js.py
+    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
+    binaryen/src/asmjs/asmangle.h
+    binaryen/src/asmjs/CMakeLists.txt
+    binaryen/src/asmjs/shared-constants.cpp
+    binaryen/src/asmjs/shared-constants.h
+    binaryen/src/binaryen-c.cpp
+    binaryen/src/binaryen-c.h
+    binaryen/src/cfg/cfg-traversal.h
+    binaryen/src/cfg/CMakeLists.txt
+    binaryen/src/cfg/liveness-traversal.h
+    binaryen/src/cfg/Relooper.cpp
+    binaryen/src/cfg/Relooper.h
+    binaryen/src/compiler-support.h
+    binaryen/src/config.h
+    binaryen/src/dataflow/graph.h
+    binaryen/src/dataflow/node.h
+    binaryen/src/dataflow/users.h
+    binaryen/src/dataflow/utils.h
+    binaryen/src/emscripten-optimizer/CMakeLists.txt
+    binaryen/src/emscripten-optimizer/istring.h
+    binaryen/src/emscripten-optimizer/optimizer-shared.cpp
+    binaryen/src/emscripten-optimizer/optimizer.h
+    binaryen/src/emscripten-optimizer/parser.cpp
+    binaryen/src/emscripten-optimizer/parser.h
+    binaryen/src/emscripten-optimizer/simple_ast.cpp
+    binaryen/src/emscripten-optimizer/simple_ast.h
+    binaryen/src/emscripten-optimizer/snprintf.h
+    binaryen/src/gen-s-parser.inc
+    binaryen/src/ir/abstract.h
+    binaryen/src/ir/bits.h
+    binaryen/src/ir/block-utils.h
+    binaryen/src/ir/branch-utils.h
+    binaryen/src/ir/CMakeLists.txt
+    binaryen/src/ir/cost.h
+    binaryen/src/ir/debug.h
+    binaryen/src/ir/effects.h
+    binaryen/src/ir/equivalent_sets.h
+    binaryen/src/ir/ExpressionAnalyzer.cpp
+    binaryen/src/ir/ExpressionManipulator.cpp
+    binaryen/src/ir/features.h
+    binaryen/src/ir/find_all.h
+    binaryen/src/ir/flat.h
+    binaryen/src/ir/function-utils.h
+    binaryen/src/ir/global-utils.h
+    binaryen/src/ir/hashed.h
+    binaryen/src/ir/import-utils.h
+    binaryen/src/ir/iteration.h
+    binaryen/src/ir/label-utils.h
+    binaryen/src/ir/literal-utils.h
+    binaryen/src/ir/load-utils.h
+    binaryen/src/ir/local-graph.h
+    binaryen/src/ir/local-utils.h
+    binaryen/src/ir/LocalGraph.cpp
+    binaryen/src/ir/localize.h
+    binaryen/src/ir/manipulation.h
+    binaryen/src/ir/match.h
+    binaryen/src/ir/memory-utils.h
+    binaryen/src/ir/module-utils.h
+    binaryen/src/ir/names.h
+    binaryen/src/ir/parents.h
+    binaryen/src/ir/properties.h
+    binaryen/src/ir/ReFinalize.cpp
+    binaryen/src/ir/stack-utils.cpp
+    binaryen/src/ir/stack-utils.h
+    binaryen/src/ir/table-utils.h
+    binaryen/src/ir/trapping.h
+    binaryen/src/ir/type-updating.h
+    binaryen/src/ir/utils.h
+    binaryen/src/js/binaryen.js-extern-post.js
+    binaryen/src/js/binaryen.js-extern-pre.js
+    binaryen/src/js/binaryen.js-post.js
+    binaryen/src/literal.h
+    binaryen/src/mixed_arena.h
+    binaryen/src/parsing.h
+    binaryen/src/pass.h
+    binaryen/src/passes/AlignmentLowering.cpp
+    binaryen/src/passes/Asyncify.cpp
+    binaryen/src/passes/AvoidReinterprets.cpp
+    binaryen/src/passes/CMakeLists.txt
+    binaryen/src/passes/CoalesceLocals.cpp
+    binaryen/src/passes/CodeFolding.cpp
+    binaryen/src/passes/CodePushing.cpp
+    binaryen/src/passes/ConstHoisting.cpp
+    binaryen/src/passes/DataFlowOpts.cpp
+    binaryen/src/passes/DeadArgumentElimination.cpp
+    binaryen/src/passes/DeadCodeElimination.cpp
+    binaryen/src/passes/DeAlign.cpp
+    binaryen/src/passes/DeNaN.cpp
+    binaryen/src/passes/Directize.cpp
+    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
+    binaryen/src/passes/GenerateDynCalls.cpp
+    binaryen/src/passes/I64ToI32Lowering.cpp
+    binaryen/src/passes/Inlining.cpp
+    binaryen/src/passes/InstrumentLocals.cpp
+    binaryen/src/passes/InstrumentMemory.cpp
+    binaryen/src/passes/intrinsics-module.h
+    binaryen/src/passes/LegalizeJSInterface.cpp
+    binaryen/src/passes/LimitSegments.cpp
+    binaryen/src/passes/LocalCSE.cpp
+    binaryen/src/passes/LogExecution.cpp
+    binaryen/src/passes/LoopInvariantCodeMotion.cpp
+    binaryen/src/passes/MemoryPacking.cpp
+    binaryen/src/passes/MergeBlocks.cpp
+    binaryen/src/passes/MergeLocals.cpp
+    binaryen/src/passes/Metrics.cpp
+    binaryen/src/passes/MinifyImportsAndExports.cpp
+    binaryen/src/passes/NameList.cpp
+    binaryen/src/passes/NoExitRuntime.cpp
+    binaryen/src/passes/opt-utils.h
+    binaryen/src/passes/OptimizeAddedConstants.cpp
+    binaryen/src/passes/OptimizeInstructions.cpp
+    binaryen/src/passes/pass.cpp
+    binaryen/src/passes/passes.h
+    binaryen/src/passes/PickLoadSigns.cpp
+    binaryen/src/passes/PostAssemblyScript.cpp
+    binaryen/src/passes/PostEmscripten.cpp
+    binaryen/src/passes/Precompute.cpp
+    binaryen/src/passes/Print.cpp
+    binaryen/src/passes/PrintCallGraph.cpp
+    binaryen/src/passes/PrintFeatures.cpp
+    binaryen/src/passes/PrintFunctionMap.cpp
+    binaryen/src/passes/RedundantSetElimination.cpp
+    binaryen/src/passes/RemoveImports.cpp
+    binaryen/src/passes/RemoveMemory.cpp
+    binaryen/src/passes/RemoveNonJSOps.cpp
+    binaryen/src/passes/RemoveUnusedBrs.cpp
+    binaryen/src/passes/RemoveUnusedModuleElements.cpp
+    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
+    binaryen/src/passes/Strip.cpp
+    binaryen/src/passes/StripTargetFeatures.cpp
+    binaryen/src/passes/TrapMode.cpp
+    binaryen/src/passes/Untee.cpp
+    binaryen/src/passes/Vacuum.cpp
+    binaryen/src/passes/wasm-intrinsics.wat
+    binaryen/src/passes/WasmIntrinsics.cpp
+    binaryen/src/pretty_printing.h
+    binaryen/src/shared-constants.h
+    binaryen/src/shell-interface.h
+    binaryen/src/support/alloc.h
+    binaryen/src/support/archive.cpp
+    binaryen/src/support/archive.h
+    binaryen/src/support/base64.h
+    binaryen/src/support/bits.cpp
+    binaryen/src/support/bits.h
+    binaryen/src/support/CMakeLists.txt
+    binaryen/src/support/colors.cpp
+    binaryen/src/support/colors.h
+    binaryen/src/support/command-line.cpp
+    binaryen/src/support/command-line.h
+    binaryen/src/support/debug.cpp
+    binaryen/src/support/debug.h
+    binaryen/src/support/file.cpp
+    binaryen/src/support/file.h
+    binaryen/src/support/hash.h
+    binaryen/src/support/json.h
+    binaryen/src/support/learning.h
+    binaryen/src/support/name.h
+    binaryen/src/support/path.cpp
+    binaryen/src/support/path.h
+    binaryen/src/support/permutations.h
+    binaryen/src/support/safe_integer.cpp
+    binaryen/src/support/safe_integer.h
+    binaryen/src/support/small_vector.h
+    binaryen/src/support/sorted_vector.h
+    binaryen/src/support/string.h
+    binaryen/src/support/threads.cpp
+    binaryen/src/support/threads.h
+    binaryen/src/support/timing.h
+    binaryen/src/support/unique_deferring_queue.h
+    binaryen/src/support/utilities.cpp
+    binaryen/src/support/utilities.h
+    binaryen/src/templates/normal.js
+    binaryen/src/templates/wasm.js
+    binaryen/src/tools/execution-results.h
+    binaryen/src/tools/fuzzing.h
+    binaryen/src/tools/js-wrapper.h
+    binaryen/src/tools/optimization-options.h
+    binaryen/src/tools/spec-wrapper.h
+    binaryen/src/tools/tool-options.h
+    binaryen/src/tools/tool-utils.h
+    binaryen/src/tools/wasm-as.cpp
+    binaryen/src/tools/wasm-ctor-eval.cpp
+    binaryen/src/tools/wasm-dis.cpp
+    binaryen/src/tools/wasm-emscripten-finalize.cpp
+    binaryen/src/tools/wasm-metadce.cpp
+    binaryen/src/tools/wasm-opt.cpp
+    binaryen/src/tools/wasm-reduce.cpp
+    binaryen/src/tools/wasm-shell.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-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
+    binaryen/src/wasm-type.h
+    binaryen/src/wasm-validator.h
+    binaryen/src/wasm.h
+    binaryen/src/wasm/CMakeLists.txt
+    binaryen/src/wasm/literal.cpp
+    binaryen/src/wasm/wasm-binary.cpp
+    binaryen/src/wasm/wasm-debug.cpp
+    binaryen/src/wasm/wasm-emscripten.cpp
+    binaryen/src/wasm/wasm-interpreter.cpp
+    binaryen/src/wasm/wasm-io.cpp
+    binaryen/src/wasm/wasm-s-parser.cpp
+    binaryen/src/wasm/wasm-stack.cpp
+    binaryen/src/wasm/wasm-type.cpp
+    binaryen/src/wasm/wasm-validator.cpp
+    binaryen/src/wasm/wasm.cpp
+    binaryen/src/wasm2js.h
+    binaryen/test/__init__.py
+    binaryen/test/atomics-unshared.wast
+    binaryen/test/atomics-unshared.wast.from-wast
+    binaryen/test/atomics-unshared.wast.fromBinary
+    binaryen/test/atomics-unshared.wast.fromBinary.noDebugInfo
+    binaryen/test/atomics.wast
+    binaryen/test/atomics.wast.from-wast
+    binaryen/test/atomics.wast.fromBinary
+    binaryen/test/atomics.wast.fromBinary.noDebugInfo
+    binaryen/test/atomics64.wast
+    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
+    binaryen/test/binaryen.js/atomics.js.txt
+    binaryen/test/binaryen.js/copy-expression.js
+    binaryen/test/binaryen.js/copy-expression.js.txt
+    binaryen/test/binaryen.js/custom-section.js
+    binaryen/test/binaryen.js/custom-section.js.txt
+    binaryen/test/binaryen.js/debug-info.js
+    binaryen/test/binaryen.js/debug-info.js.txt
+    binaryen/test/binaryen.js/debug-names.js
+    binaryen/test/binaryen.js/debug-names.js.txt
+    binaryen/test/binaryen.js/emit_asmjs.js
+    binaryen/test/binaryen.js/emit_asmjs.js.txt
+    binaryen/test/binaryen.js/event.js
+    binaryen/test/binaryen.js/event.js.txt
+    binaryen/test/binaryen.js/exception-handling.js
+    binaryen/test/binaryen.js/exception-handling.js.txt
+    binaryen/test/binaryen.js/expressionrunner.js
+    binaryen/test/binaryen.js/expressionrunner.js.txt
+    binaryen/test/binaryen.js/expressions.js
+    binaryen/test/binaryen.js/expressions.js.txt
+    binaryen/test/binaryen.js/fast-math.js
+    binaryen/test/binaryen.js/fast-math.js.txt
+    binaryen/test/binaryen.js/functions.js
+    binaryen/test/binaryen.js/functions.js.txt
+    binaryen/test/binaryen.js/global.js
+    binaryen/test/binaryen.js/global.js.txt
+    binaryen/test/binaryen.js/hello-world.js
+    binaryen/test/binaryen.js/hello-world.js.txt
+    binaryen/test/binaryen.js/inlining-options.js
+    binaryen/test/binaryen.js/inlining-options.js.txt
+    binaryen/test/binaryen.js/kitchen-sink.js
+    binaryen/test/binaryen.js/kitchen-sink.js.txt
+    binaryen/test/binaryen.js/low-memory-unused.js
+    binaryen/test/binaryen.js/low-memory-unused.js.txt
+    binaryen/test/binaryen.js/optimize-levels.js
+    binaryen/test/binaryen.js/optimize-levels.js.txt
+    binaryen/test/binaryen.js/pass-arguments.js
+    binaryen/test/binaryen.js/pass-arguments.js.txt
+    binaryen/test/binaryen.js/reloc.js
+    binaryen/test/binaryen.js/reloc.js.txt
+    binaryen/test/binaryen.js/sideffects.js
+    binaryen/test/binaryen.js/sideffects.js.txt
+    binaryen/test/binaryen.js/sieve.js
+    binaryen/test/binaryen.js/sieve.js.txt
+    binaryen/test/binaryen.js/simd.js
+    binaryen/test/binaryen.js/simd.js.txt
+    binaryen/test/binaryen.js/sourcemap.js
+    binaryen/test/binaryen.js/sourcemap.js.txt
+    binaryen/test/binaryen.js/stackir.js
+    binaryen/test/binaryen.js/stackir.js.txt
+    binaryen/test/binaryen.js/tail_calls.js
+    binaryen/test/binaryen.js/tail_calls.js.txt
+    binaryen/test/binaryen.js/validation_errors.js
+    binaryen/test/binaryen.js/validation_errors.js.txt
+    binaryen/test/br_to_exit.wasm
+    binaryen/test/br_to_exit.wasm.fromBinary
+    binaryen/test/break-to-return.wasm
+    binaryen/test/break-to-return.wasm.fromBinary
+    binaryen/test/break-within-catch.wasm
+    binaryen/test/break-within-catch.wasm.fromBinary
+    binaryen/test/calls.cpp
+    binaryen/test/calls.emcc
+    binaryen/test/calls.post.js
+    binaryen/test/calls.txt
+    binaryen/test/complexBinaryNames.wasm
+    binaryen/test/complexBinaryNames.wasm.fromBinary
+    binaryen/test/complexTextNames.wast
+    binaryen/test/complexTextNames.wast.from-wast
+    binaryen/test/complexTextNames.wast.fromBinary
+    binaryen/test/complexTextNames.wast.fromBinary.noDebugInfo
+    binaryen/test/consume-stacky.wasm
+    binaryen/test/consume-stacky.wasm.fromBinary
+    binaryen/test/control_flow.cpp
+    binaryen/test/control_flow.emcc
+    binaryen/test/control_flow.post.js
+    binaryen/test/control_flow.txt
+    binaryen/test/crash/expression-past-end-of-input.wasm
+    binaryen/test/crash/outside.wasm
+    binaryen/test/crash/use_var_outside_func.wasm
+    binaryen/test/ctor-eval/bad-indirect-call.wast
+    binaryen/test/ctor-eval/bad-indirect-call.wast.ctors
+    binaryen/test/ctor-eval/bad-indirect-call.wast.out
+    binaryen/test/ctor-eval/bad-indirect-call2.wast
+    binaryen/test/ctor-eval/bad-indirect-call2.wast.ctors
+    binaryen/test/ctor-eval/bad-indirect-call2.wast.out
+    binaryen/test/ctor-eval/bad-indirect-call3.wast
+    binaryen/test/ctor-eval/bad-indirect-call3.wast.ctors
+    binaryen/test/ctor-eval/bad-indirect-call3.wast.out
+    binaryen/test/ctor-eval/basics-flatten.wast
+    binaryen/test/ctor-eval/basics-flatten.wast.ctors
+    binaryen/test/ctor-eval/basics-flatten.wast.out
+    binaryen/test/ctor-eval/basics.wast
+    binaryen/test/ctor-eval/basics.wast.ctors
+    binaryen/test/ctor-eval/basics.wast.out
+    binaryen/test/ctor-eval/imported-min.wast
+    binaryen/test/ctor-eval/imported-min.wast.ctors
+    binaryen/test/ctor-eval/imported-min.wast.out
+    binaryen/test/ctor-eval/imported.wast
+    binaryen/test/ctor-eval/imported.wast.ctors
+    binaryen/test/ctor-eval/imported.wast.out
+    binaryen/test/ctor-eval/imported2.wast
+    binaryen/test/ctor-eval/imported2.wast.ctors
+    binaryen/test/ctor-eval/imported2.wast.out
+    binaryen/test/ctor-eval/imported3.wast
+    binaryen/test/ctor-eval/imported3.wast.ctors
+    binaryen/test/ctor-eval/imported3.wast.out
+    binaryen/test/ctor-eval/indirect-call3.wast
+    binaryen/test/ctor-eval/indirect-call3.wast.ctors
+    binaryen/test/ctor-eval/indirect-call3.wast.out
+    binaryen/test/ctor-eval/just_some.wast
+    binaryen/test/ctor-eval/just_some.wast.ctors
+    binaryen/test/ctor-eval/just_some.wast.out
+    binaryen/test/ctor-eval/no_partial.wast
+    binaryen/test/ctor-eval/no_partial.wast.ctors
+    binaryen/test/ctor-eval/no_partial.wast.out
+    binaryen/test/ctor-eval/stack-direction.wast
+    binaryen/test/ctor-eval/stack-direction.wast.ctors
+    binaryen/test/ctor-eval/stack-direction.wast.out
+    binaryen/test/ctor-eval/unsafe_call.wast
+    binaryen/test/ctor-eval/unsafe_call.wast.ctors
+    binaryen/test/ctor-eval/unsafe_call.wast.out
+    binaryen/test/ctor-eval/unsafe_store.wast
+    binaryen/test/ctor-eval/unsafe_store.wast.ctors
+    binaryen/test/ctor-eval/unsafe_store.wast.out
+    binaryen/test/ctor-eval/unsafe_store2.wast
+    binaryen/test/ctor-eval/unsafe_store2.wast.ctors
+    binaryen/test/ctor-eval/unsafe_store2.wast.out
+    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
+    binaryen/test/duplicate_types.wast.fromBinary.noDebugInfo
+    binaryen/test/duplicated_names.wasm
+    binaryen/test/duplicated_names.wasm.fromBinary
+    binaryen/test/duplicated_names_collision.wasm
+    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
+    binaryen/test/empty_imported_table.wast.fromBinary.noDebugInfo
+    binaryen/test/empty_table.wast
+    binaryen/test/empty_table.wast.from-wast
+    binaryen/test/empty_table.wast.fromBinary
+    binaryen/test/empty_table.wast.fromBinary.noDebugInfo
+    binaryen/test/events.wast
+    binaryen/test/events.wast.from-wast
+    binaryen/test/events.wast.fromBinary
+    binaryen/test/events.wast.fromBinary.noDebugInfo
+    binaryen/test/example/c-api-hello-world.c
+    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
+    binaryen/test/example/c-api-unused-mem.txt
+    binaryen/test/example/cpp-threads.cpp
+    binaryen/test/example/cpp-threads.txt
+    binaryen/test/example/cpp-unit.cpp
+    binaryen/test/example/cpp-unit.txt
+    binaryen/test/example/match.cpp
+    binaryen/test/example/match.txt
+    binaryen/test/example/relooper-fuzz.c
+    binaryen/test/example/relooper-fuzz.txt
+    binaryen/test/example/relooper-fuzz1.c
+    binaryen/test/example/relooper-fuzz1.txt
+    binaryen/test/example/relooper-fuzz2.c
+    binaryen/test/example/relooper-fuzz2.txt
+    binaryen/test/example/relooper-merge1.c
+    binaryen/test/example/relooper-merge1.txt
+    binaryen/test/example/relooper-merge2.c
+    binaryen/test/example/relooper-merge2.txt
+    binaryen/test/example/relooper-merge3.c
+    binaryen/test/example/relooper-merge3.txt
+    binaryen/test/example/relooper-merge4.c
+    binaryen/test/example/relooper-merge4.txt
+    binaryen/test/example/relooper-merge5.c
+    binaryen/test/example/relooper-merge5.txt
+    binaryen/test/example/relooper-merge6.c
+    binaryen/test/example/relooper-merge6.txt
+    binaryen/test/example/relooper-merge7.c
+    binaryen/test/example/relooper-merge7.txt
+    binaryen/test/example/small_vector.cpp
+    binaryen/test/example/small_vector.txt
+    binaryen/test/example/stack-utils.cpp
+    binaryen/test/example/stack-utils.txt
+    binaryen/test/example/typeinfo.cpp
+    binaryen/test/example/typeinfo.txt
+    binaryen/test/exception-handling.wast
+    binaryen/test/exception-handling.wast.from-wast
+    binaryen/test/exception-handling.wast.fromBinary
+    binaryen/test/exception-handling.wast.fromBinary.noDebugInfo
+    binaryen/test/export-import.wast
+    binaryen/test/export-import.wast.from-wast
+    binaryen/test/export-import.wast.fromBinary
+    binaryen/test/export-import.wast.fromBinary.noDebugInfo
+    binaryen/test/externref.wast.from-wast
+    binaryen/test/externref.wast.fromBinary
+    binaryen/test/externref.wast.fromBinary.noDebugInfo
+    binaryen/test/extra-unreachable.wast
+    binaryen/test/extra-unreachable.wast.from-wast
+    binaryen/test/extra-unreachable.wast.fromBinary
+    binaryen/test/extra-unreachable.wast.fromBinary.noDebugInfo
+    binaryen/test/fannkuch.args
+    binaryen/test/fannkuch.cpp
+    binaryen/test/fannkuch.txt
+    binaryen/test/fasta.args
+    binaryen/test/fasta.cpp
+    binaryen/test/fasta.txt
+    binaryen/test/fib-dbg.wasm
+    binaryen/test/fib-dbg.wasm.fromBinary
+    binaryen/test/fib-dbg.wasm.map
+    binaryen/test/float_ops.cpp
+    binaryen/test/float_ops.emcc
+    binaryen/test/float_ops.post.js
+    binaryen/test/float_ops.txt
+    binaryen/test/fn_prolog_epilog.debugInfo.wasm
+    binaryen/test/fn_prolog_epilog.debugInfo.wasm.fromBinary
+    binaryen/test/fn_prolog_epilog.debugInfo.wasm.map
+    binaryen/test/fn_prolog_epilog.debugInfo.wast
+    binaryen/test/fn_prolog_epilog.debugInfo.wast.from-wast
+    binaryen/test/fn_prolog_epilog.debugInfo.wast.fromBinary
+    binaryen/test/fn_prolog_epilog.debugInfo.wast.fromBinary.noDebugInfo
+    binaryen/test/gc.wast
+    binaryen/test/gc.wast.from-wast
+    binaryen/test/gc.wast.fromBinary
+    binaryen/test/gc.wast.fromBinary.noDebugInfo
+    binaryen/test/grow_memory.cpp
+    binaryen/test/grow_memory.emcc
+    binaryen/test/grow_memory.txt
+    binaryen/test/grow_memory.wast
+    binaryen/test/grow_memory.wast.from-wast
+    binaryen/test/grow_memory.wast.fromBinary
+    binaryen/test/grow_memory.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
+    binaryen/test/imported_memory.wast.fromBinary.noDebugInfo
+    binaryen/test/imported_memory_growth.wast
+    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
+    binaryen/test/int_ops.txt
+    binaryen/test/kitchen_sink.wast
+    binaryen/test/kitchen_sink.wast.from-wast
+    binaryen/test/kitchen_sink.wast.fromBinary
+    binaryen/test/kitchen_sink.wast.fromBinary.noDebugInfo
+    binaryen/test/linker/archive/barlong.a
+    binaryen/test/linker/archive/foobar.a
+    binaryen/test/linker/bar.c
+    binaryen/test/linker/baz.c
+    binaryen/test/linker/foo.c
+    binaryen/test/linker/main.c
+    binaryen/test/linker/quux.c
+    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
+    binaryen/test/lld/em_asm.wat
+    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_asm_main_thread.wat
+    binaryen/test/lld/em_asm_main_thread.wat.out
+    binaryen/test/lld/em_asm_O0.c
+    binaryen/test/lld/em_asm_O0.wat
+    binaryen/test/lld/em_asm_O0.wat.out
+    binaryen/test/lld/em_asm_shared.cpp
+    binaryen/test/lld/em_asm_shared.wat
+    binaryen/test/lld/em_asm_shared.wat.out
+    binaryen/test/lld/em_asm_table.wat
+    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
+    binaryen/test/lld/hello_world.wat
+    binaryen/test/lld/hello_world.wat.mem.mem
+    binaryen/test/lld/hello_world.wat.mem.out
+    binaryen/test/lld/hello_world.wat.out
+    binaryen/test/lld/init.c
+    binaryen/test/lld/init.wat
+    binaryen/test/lld/init.wat.out
+    binaryen/test/lld/longjmp.c
+    binaryen/test/lld/longjmp.wat
+    binaryen/test/lld/longjmp.wat.out
+    binaryen/test/lld/main_module.wat
+    binaryen/test/lld/main_module.wat.out
+    binaryen/test/lld/main_module_table.wat
+    binaryen/test/lld/main_module_table.wat.out
+    binaryen/test/lld/main_module_table_2.wat
+    binaryen/test/lld/main_module_table_2.wat.out
+    binaryen/test/lld/main_module_table_3.wat
+    binaryen/test/lld/main_module_table_3.wat.out
+    binaryen/test/lld/main_module_table_4.wat
+    binaryen/test/lld/main_module_table_4.wat.out
+    binaryen/test/lld/main_module_table_5.wat
+    binaryen/test/lld/main_module_table_5.wat.out
+    binaryen/test/lld/recursive.c
+    binaryen/test/lld/recursive.wat
+    binaryen/test/lld/recursive.wat.out
+    binaryen/test/lld/recursive_safe_stack.wat
+    binaryen/test/lld/recursive_safe_stack.wat.out
+    binaryen/test/lld/reserved_func_ptr.cpp
+    binaryen/test/lld/reserved_func_ptr.wat
+    binaryen/test/lld/reserved_func_ptr.wat.out
+    binaryen/test/lld/safe_stack_standalone-wasm.wat
+    binaryen/test/lld/safe_stack_standalone-wasm.wat.out
+    binaryen/test/lld/shared.cpp
+    binaryen/test/lld/shared.wat
+    binaryen/test/lld/shared.wat.out
+    binaryen/test/lld/shared_add_to_table.wasm
+    binaryen/test/lld/shared_add_to_table.wasm.out
+    binaryen/test/lld/shared_longjmp.c
+    binaryen/test/lld/shared_longjmp.wat
+    binaryen/test/lld/shared_longjmp.wat.out
+    binaryen/test/lld/standalone-wasm-with-start.wat
+    binaryen/test/lld/standalone-wasm-with-start.wat.out
+    binaryen/test/lld/standalone-wasm.wat
+    binaryen/test/lld/standalone-wasm.wat.out
+    binaryen/test/lld/standalone-wasm2.wat
+    binaryen/test/lld/standalone-wasm2.wat.out
+    binaryen/test/lld/standalone-wasm3.wat
+    binaryen/test/lld/standalone-wasm3.wat.out
+    binaryen/test/mem.cpp
+    binaryen/test/mem.emcc
+    binaryen/test/mem.post.js
+    binaryen/test/mem.txt
+    binaryen/test/memory-import.wast
+    binaryen/test/memory-import.wast.from-wast
+    binaryen/test/memory-import.wast.fromBinary
+    binaryen/test/memory-import.wast.fromBinary.noDebugInfo
+    binaryen/test/memory-import64.wast
+    binaryen/test/memory-import64.wast.from-wast
+    binaryen/test/memory-import64.wast.fromBinary
+    binaryen/test/memory-import64.wast.fromBinary.noDebugInfo
+    binaryen/test/memory-import64.wast.wasm.fromBinary
+    binaryen/test/memory-shared.wast
+    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
+    binaryen/test/metadce/all-outside.wast.dced
+    binaryen/test/metadce/all-outside.wast.dced.stdout
+    binaryen/test/metadce/all-outside.wast.graph.txt
+    binaryen/test/metadce/corners.wast
+    binaryen/test/metadce/corners.wast.dced
+    binaryen/test/metadce/corners.wast.dced.stdout
+    binaryen/test/metadce/corners.wast.graph.txt
+    binaryen/test/metadce/no-outside.wast
+    binaryen/test/metadce/no-outside.wast.dced
+    binaryen/test/metadce/no-outside.wast.dced.stdout
+    binaryen/test/metadce/no-outside.wast.graph.txt
+    binaryen/test/metadce/outside.wast
+    binaryen/test/metadce/outside.wast.dced
+    binaryen/test/metadce/outside.wast.dced.stdout
+    binaryen/test/metadce/outside.wast.graph.txt
+    binaryen/test/metadce/rooted-export.wast
+    binaryen/test/metadce/rooted-export.wast.dced
+    binaryen/test/metadce/rooted-export.wast.dced.stdout
+    binaryen/test/metadce/rooted-export.wast.graph.txt
+    binaryen/test/metadce/spanning_cycle.wast
+    binaryen/test/metadce/spanning_cycle.wast.dced
+    binaryen/test/metadce/spanning_cycle.wast.dced.stdout
+    binaryen/test/metadce/spanning_cycle.wast.graph.txt
+    binaryen/test/metadce/spanning_cycle_unrooted.wast
+    binaryen/test/metadce/spanning_cycle_unrooted.wast.dced
+    binaryen/test/metadce/spanning_cycle_unrooted.wast.dced.stdout
+    binaryen/test/metadce/spanning_cycle_unrooted.wast.graph.txt
+    binaryen/test/metadce/threaded.wast
+    binaryen/test/metadce/threaded.wast.dced
+    binaryen/test/metadce/threaded.wast.dced.stdout
+    binaryen/test/metadce/threaded.wast.graph.txt
+    binaryen/test/metadce/threaded_cycle.wast
+    binaryen/test/metadce/threaded_cycle.wast.dced
+    binaryen/test/metadce/threaded_cycle.wast.dced.stdout
+    binaryen/test/metadce/threaded_cycle.wast.graph.txt
+    binaryen/test/metadce/threaded_unrooted.wast
+    binaryen/test/metadce/threaded_unrooted.wast.dced
+    binaryen/test/metadce/threaded_unrooted.wast.dced.stdout
+    binaryen/test/metadce/threaded_unrooted.wast.graph.txt
+    binaryen/test/metadce/threaded_unrooted_cycle.wast
+    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
+    binaryen/test/min.wast.fromBinary.noDebugInfo
+    binaryen/test/multivalue.wast
+    binaryen/test/multivalue.wast.from-wast
+    binaryen/test/multivalue.wast.fromBinary
+    binaryen/test/multivalue.wast.fromBinary.noDebugInfo
+    binaryen/test/mutable-global.wasm
+    binaryen/test/mutable-global.wasm.fromBinary
+    binaryen/test/mutable-global.wast
+    binaryen/test/mutable-global.wast.from-wast
+    binaryen/test/mutable-global.wast.fromBinary
+    binaryen/test/mutable-global.wast.fromBinary.noDebugInfo
+    binaryen/test/newsyntax.wast
+    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
+    binaryen/test/nonspec-bulk-memory.wast.fromBinary.noDebugInfo
+    binaryen/test/passes/alignment-lowering.txt
+    binaryen/test/passes/alignment-lowering.wast
+    binaryen/test/passes/alignment-lowering64.passes
+    binaryen/test/passes/alignment-lowering64.txt
+    binaryen/test/passes/alignment-lowering64.wast
+    binaryen/test/passes/asyncify.txt
+    binaryen/test/passes/asyncify.wast
+    binaryen/test/passes/asyncify_enable-multivalue.txt
+    binaryen/test/passes/asyncify_enable-multivalue.wast
+    binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind.txt
+    binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind.wast
+    binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.txt
+    binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.wast
+    binaryen/test/passes/asyncify_mod-asyncify-never-unwind.txt
+    binaryen/test/passes/asyncify_mod-asyncify-never-unwind.wast
+    binaryen/test/passes/asyncify_mod-asyncify-never-unwind_O.txt
+    binaryen/test/passes/asyncify_mod-asyncify-never-unwind_O.wast
+    binaryen/test/passes/asyncify_optimize-level=1.txt
+    binaryen/test/passes/asyncify_optimize-level=1.wast
+    binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo.txt
+    binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo.wast
+    binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo_pass-arg=asyncify-ignore-indirect.txt
+    binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo_pass-arg=asyncify-ignore-indirect.wast
+    binaryen/test/passes/asyncify_pass-arg=asyncify-asserts_pass-arg=asyncify-onlylist@waka.txt
+    binaryen/test/passes/asyncify_pass-arg=asyncify-asserts_pass-arg=asyncify-onlylist@waka.wast
+    "binaryen/test/passes/asyncify_pass-arg=asyncify-blacklist@foo,bar.txt"
+    "binaryen/test/passes/asyncify_pass-arg=asyncify-blacklist@foo,bar.wast"
+    binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-imports.txt
+    binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-imports.wast
+    binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-indirect.txt
+    binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-indirect.wast
+    "binaryen/test/passes/asyncify_pass-arg=asyncify-imports@env.import,env.import2.txt"
+    "binaryen/test/passes/asyncify_pass-arg=asyncify-imports@env.import,env.import2.wast"
+    "binaryen/test/passes/asyncify_pass-arg=asyncify-onlylist@foo,bar.txt"
+    "binaryen/test/passes/asyncify_pass-arg=asyncify-onlylist@foo,bar.wast"
+    binaryen/test/passes/asyncify_pass-arg=asyncify-verbose.txt
+    binaryen/test/passes/asyncify_pass-arg=asyncify-verbose.wast
+    binaryen/test/passes/avoid-reinterprets.txt
+    binaryen/test/passes/avoid-reinterprets.wast
+    binaryen/test/passes/avoid-reinterprets64.passes
+    binaryen/test/passes/avoid-reinterprets64.txt
+    binaryen/test/passes/avoid-reinterprets64.wast
+    binaryen/test/passes/class_with_dwarf_noprint.bin.txt
+    binaryen/test/passes/class_with_dwarf_noprint.passes
+    binaryen/test/passes/class_with_dwarf_noprint.wasm
+    binaryen/test/passes/coalesce-locals-learning.txt
+    binaryen/test/passes/coalesce-locals-learning.wast
+    binaryen/test/passes/coalesce-locals.txt
+    binaryen/test/passes/coalesce-locals.wast
+    binaryen/test/passes/code-folding_enable-threads.txt
+    binaryen/test/passes/code-folding_enable-threads.wast
+    binaryen/test/passes/code-pushing_all-features.txt
+    binaryen/test/passes/code-pushing_all-features.wast
+    binaryen/test/passes/code-pushing_ignore-implicit-traps.txt
+    binaryen/test/passes/code-pushing_ignore-implicit-traps.wast
+    binaryen/test/passes/const-hoisting.txt
+    binaryen/test/passes/const-hoisting.wast
+    binaryen/test/passes/converge_O3_metrics.bin.txt
+    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/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/dealign.txt
+    binaryen/test/passes/dealign.wast
+    binaryen/test/passes/dealign64.passes
+    binaryen/test/passes/dealign64.txt
+    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/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
+    binaryen/test/passes/duplicate-function-elimination_optimize-level=1.wast
+    binaryen/test/passes/duplicate-function-elimination_optimize-level=2.txt
+    binaryen/test/passes/duplicate-function-elimination_optimize-level=2.wast
+    binaryen/test/passes/duplicate-import-elimination.txt
+    binaryen/test/passes/duplicate-import-elimination.wast
+    binaryen/test/passes/dwarf-local-order.bin.txt
+    binaryen/test/passes/dwarf-local-order.passes
+    binaryen/test/passes/dwarf-local-order.wasm
+    binaryen/test/passes/dwarf_unit_with_no_abbrevs_noprint.bin.txt
+    binaryen/test/passes/dwarf_unit_with_no_abbrevs_noprint.passes
+    binaryen/test/passes/dwarf_unit_with_no_abbrevs_noprint.wasm
+    binaryen/test/passes/dwarfdump.bin.txt
+    binaryen/test/passes/dwarfdump.wasm
+    binaryen/test/passes/dwarfdump_roundtrip_dwarfdump.bin.txt
+    binaryen/test/passes/dwarfdump_roundtrip_dwarfdump.wasm
+    binaryen/test/passes/emit-js-wrapper=a.js.txt
+    binaryen/test/passes/emit-js-wrapper=a.js.wast
+    binaryen/test/passes/emit-js-wrapper=a.js.wast.js
+    binaryen/test/passes/emit-spec-wrapper=a.wat.txt
+    binaryen/test/passes/emit-spec-wrapper=a.wat.wast
+    binaryen/test/passes/emit-spec-wrapper=a.wat.wast.wat
+    binaryen/test/passes/extract-function_pass-arg=extract@foo.txt
+    binaryen/test/passes/extract-function_pass-arg=extract@foo.wast
+    binaryen/test/passes/fannkuch0_dwarf.bin.txt
+    binaryen/test/passes/fannkuch0_dwarf.passes
+    binaryen/test/passes/fannkuch0_dwarf.wasm
+    binaryen/test/passes/fannkuch3_dwarf.bin.txt
+    binaryen/test/passes/fannkuch3_dwarf.passes
+    binaryen/test/passes/fannkuch3_dwarf.wasm
+    binaryen/test/passes/fannkuch3_manyopts_dwarf.bin.txt
+    binaryen/test/passes/fannkuch3_manyopts_dwarf.passes
+    binaryen/test/passes/fannkuch3_manyopts_dwarf.wasm
+    binaryen/test/passes/fib2_dwarf.bin.txt
+    binaryen/test/passes/fib2_dwarf.passes
+    binaryen/test/passes/fib2_dwarf.wasm
+    binaryen/test/passes/fib2_emptylocspan_dwarf.bin.txt
+    binaryen/test/passes/fib2_emptylocspan_dwarf.passes
+    binaryen/test/passes/fib2_emptylocspan_dwarf.wasm
+    binaryen/test/passes/fib_nonzero-low-pc_dwarf.bin.txt
+    binaryen/test/passes/fib_nonzero-low-pc_dwarf.passes
+    binaryen/test/passes/fib_nonzero-low-pc_dwarf.wasm
+    binaryen/test/passes/flatten.bin.txt
+    binaryen/test/passes/flatten.wasm
+    binaryen/test/passes/flatten_all-features.txt
+    binaryen/test/passes/flatten_all-features.wast
+    binaryen/test/passes/flatten_dfo_O3_enable-threads.txt
+    binaryen/test/passes/flatten_dfo_O3_enable-threads.wast
+    binaryen/test/passes/flatten_i64-to-i32-lowering.txt
+    binaryen/test/passes/flatten_i64-to-i32-lowering.wast
+    binaryen/test/passes/flatten_local-cse_all-features.txt
+    binaryen/test/passes/flatten_local-cse_all-features.wast
+    binaryen/test/passes/flatten_local-cse_Os.txt
+    binaryen/test/passes/flatten_local-cse_Os.wast
+    binaryen/test/passes/flatten_rereloop.txt
+    binaryen/test/passes/flatten_rereloop.wast
+    binaryen/test/passes/flatten_simplify-locals-nonesting_dfo_O3.txt
+    binaryen/test/passes/flatten_simplify-locals-nonesting_dfo_O3.wast
+    binaryen/test/passes/flatten_simplify-locals-nonesting_souperify-single-use_enable-threads.txt
+    binaryen/test/passes/flatten_simplify-locals-nonesting_souperify-single-use_enable-threads.wast
+    binaryen/test/passes/flatten_simplify-locals-nonesting_souperify_enable-threads.txt
+    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/func-metrics.txt
+    binaryen/test/passes/func-metrics.wast
+    binaryen/test/passes/fuzz-exec_all-features.txt
+    binaryen/test/passes/fuzz-exec_all-features.wast
+    binaryen/test/passes/fuzz-exec_O.txt
+    binaryen/test/passes/fuzz-exec_O.wast
+    binaryen/test/passes/fuzz_metrics_noprint.bin.txt
+    binaryen/test/passes/fuzz_metrics_noprint.passes
+    binaryen/test/passes/fuzz_metrics_noprint.wasm
+    binaryen/test/passes/generate-dyncalls.txt
+    binaryen/test/passes/generate-dyncalls.wast
+    binaryen/test/passes/generate-i64-dyncalls.txt
+    binaryen/test/passes/generate-i64-dyncalls.wast
+    binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_all-features.txt
+    binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_all-features.wast
+    binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_optimize-level=3.txt
+    binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_optimize-level=3.wast
+    binaryen/test/passes/ignore_missing_func_dwarf.bin.txt
+    binaryen/test/passes/ignore_missing_func_dwarf.passes
+    binaryen/test/passes/ignore_missing_func_dwarf.wasm
+    binaryen/test/passes/inline-main.txt
+    binaryen/test/passes/inline-main.wast
+    binaryen/test/passes/inlined_to_start_dwarf.bin.txt
+    binaryen/test/passes/inlined_to_start_dwarf.passes
+    binaryen/test/passes/inlined_to_start_dwarf.wasm
+    binaryen/test/passes/inlining-optimizing_enable-threads.txt
+    binaryen/test/passes/inlining-optimizing_enable-threads.wast
+    binaryen/test/passes/inlining-optimizing_optimize-level=3.txt
+    binaryen/test/passes/inlining-optimizing_optimize-level=3.wast
+    binaryen/test/passes/inlining_all-features.txt
+    binaryen/test/passes/inlining_all-features.wast
+    binaryen/test/passes/inlining_enable-tail-call.txt
+    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-memory.txt
+    binaryen/test/passes/instrument-memory.wast
+    binaryen/test/passes/instrument-memory64.passes
+    binaryen/test/passes/instrument-memory64.txt
+    binaryen/test/passes/instrument-memory64.wast
+    binaryen/test/passes/interesting-pass-mix.passes
+    binaryen/test/passes/interesting-pass-mix.txt
+    binaryen/test/passes/interesting-pass-mix.wast
+    binaryen/test/passes/legalize-js-interface-minimally.txt
+    binaryen/test/passes/legalize-js-interface-minimally.wast
+    binaryen/test/passes/legalize-js-interface_all-features.txt
+    binaryen/test/passes/legalize-js-interface_all-features.wast
+    binaryen/test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.txt
+    binaryen/test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.wast
+    binaryen/test/passes/licm.txt
+    binaryen/test/passes/licm.wast
+    binaryen/test/passes/limit-segments_disable-bulk-memory.txt
+    binaryen/test/passes/limit-segments_disable-bulk-memory.wast
+    binaryen/test/passes/log-execution.txt
+    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/merge-blocks.txt
+    binaryen/test/passes/merge-blocks.wast
+    binaryen/test/passes/merge-blocks_remove-unused-brs.txt
+    binaryen/test/passes/merge-blocks_remove-unused-brs.wast
+    binaryen/test/passes/merge-locals_all-features.txt
+    binaryen/test/passes/merge-locals_all-features.wast
+    binaryen/test/passes/metrics_all-features.txt
+    binaryen/test/passes/metrics_all-features.wast
+    binaryen/test/passes/metrics_strip-debug_metrics.bin.txt
+    binaryen/test/passes/metrics_strip-debug_metrics.wasm
+    binaryen/test/passes/metrics_strip-producers_metrics.bin.txt
+    binaryen/test/passes/metrics_strip-producers_metrics.wasm
+    binaryen/test/passes/minify-imports-and-exports-and-modules.txt
+    binaryen/test/passes/minify-imports-and-exports-and-modules.wast
+    binaryen/test/passes/minify-imports-and-exports_all-features.txt
+    binaryen/test/passes/minify-imports-and-exports_all-features.wast
+    binaryen/test/passes/minify-imports_all-features.txt
+    binaryen/test/passes/minify-imports_all-features.wast
+    binaryen/test/passes/multi_line_table_dwarf.bin.txt
+    binaryen/test/passes/multi_line_table_dwarf.passes
+    binaryen/test/passes/multi_line_table_dwarf.wasm
+    binaryen/test/passes/multi_unit_abbrev_noprint.bin.txt
+    binaryen/test/passes/multi_unit_abbrev_noprint.passes
+    binaryen/test/passes/multi_unit_abbrev_noprint.wasm
+    binaryen/test/passes/nm.txt
+    binaryen/test/passes/nm.wast
+    binaryen/test/passes/no-exit-runtime.txt
+    binaryen/test/passes/no-exit-runtime.wast
+    binaryen/test/passes/O.bin.txt
+    binaryen/test/passes/O.txt
+    binaryen/test/passes/O.wasm
+    binaryen/test/passes/O.wast
+    binaryen/test/passes/O1.txt
+    binaryen/test/passes/O1.wast
+    binaryen/test/passes/O1_print-stack-ir.txt
+    binaryen/test/passes/O1_print-stack-ir.wast
+    binaryen/test/passes/O2_precompute-propagate_print-stack-ir.txt
+    binaryen/test/passes/O2_precompute-propagate_print-stack-ir.wast
+    binaryen/test/passes/O2_print-stack-ir.txt
+    binaryen/test/passes/O2_print-stack-ir.wast
+    binaryen/test/passes/O3_inline-functions-with-loops_flexible-inline-max-function-size=30.txt
+    binaryen/test/passes/O3_inline-functions-with-loops_flexible-inline-max-function-size=30.wast
+    binaryen/test/passes/O3_inlining.txt
+    binaryen/test/passes/O3_inlining.wast
+    binaryen/test/passes/O3_low-memory-unused_metrics.txt
+    binaryen/test/passes/O3_low-memory-unused_metrics.wast
+    binaryen/test/passes/O3_print-stack-ir.txt
+    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_fast-math.txt
+    binaryen/test/passes/O_fast-math.wast
+    binaryen/test/passes/optimize-added-constants-propagate_low-memory-unused.txt
+    binaryen/test/passes/optimize-added-constants-propagate_low-memory-unused.wast
+    binaryen/test/passes/optimize-added-constants_low-memory-unused.txt
+    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_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/pick-load-signs.txt
+    binaryen/test/passes/pick-load-signs.wast
+    binaryen/test/passes/post-assemblyscript-finalize.txt
+    binaryen/test/passes/post-assemblyscript-finalize.wast
+    binaryen/test/passes/post-assemblyscript.txt
+    binaryen/test/passes/post-assemblyscript.wast
+    binaryen/test/passes/post-emscripten.txt
+    binaryen/test/passes/post-emscripten.wast
+    binaryen/test/passes/precompute-propagate_all-features.txt
+    binaryen/test/passes/precompute-propagate_all-features.wast
+    binaryen/test/passes/precompute_all-features.txt
+    binaryen/test/passes/precompute_all-features.wast
+    binaryen/test/passes/precompute_coalesce-locals_vacuum.txt
+    binaryen/test/passes/precompute_coalesce-locals_vacuum.wast
+    binaryen/test/passes/print-call-graph.txt
+    binaryen/test/passes/print-call-graph.wast
+    binaryen/test/passes/print-function-map.txt
+    binaryen/test/passes/print-function-map.wast
+    binaryen/test/passes/print.bin.txt
+    binaryen/test/passes/print.wasm
+    binaryen/test/passes/print_g.bin.txt
+    binaryen/test/passes/print_g.wasm
+    binaryen/test/passes/print_g_metrics.bin.txt
+    binaryen/test/passes/print_g_metrics.wasm
+    binaryen/test/passes/print_g_strip-dwarf.bin.txt
+    binaryen/test/passes/print_g_strip-dwarf.wasm
+    binaryen/test/passes/remove-imports.txt
+    binaryen/test/passes/remove-imports.wast
+    binaryen/test/passes/remove-memory.txt
+    binaryen/test/passes/remove-memory.wast
+    binaryen/test/passes/remove-non-js-ops.txt
+    binaryen/test/passes/remove-non-js-ops.wast
+    binaryen/test/passes/remove-unused-brs_enable-multivalue.txt
+    binaryen/test/passes/remove-unused-brs_enable-multivalue.wast
+    binaryen/test/passes/remove-unused-brs_generate-stack-ir_print-stack-ir.txt
+    binaryen/test/passes/remove-unused-brs_generate-stack-ir_print-stack-ir.wast
+    binaryen/test/passes/remove-unused-brs_precompute_vacuum_remove-unused-brs.txt
+    binaryen/test/passes/remove-unused-brs_precompute_vacuum_remove-unused-brs.wast
+    binaryen/test/passes/remove-unused-brs_shrink-level=1.txt
+    binaryen/test/passes/remove-unused-brs_shrink-level=1.wast
+    binaryen/test/passes/remove-unused-brs_shrink-level=1_ignore-implicit-traps.txt
+    binaryen/test/passes/remove-unused-brs_shrink-level=1_ignore-implicit-traps.wast
+    binaryen/test/passes/remove-unused-module-elements_all-features.txt
+    binaryen/test/passes/remove-unused-module-elements_all-features.wast
+    binaryen/test/passes/remove-unused-names.txt
+    binaryen/test/passes/remove-unused-names.wast
+    binaryen/test/passes/remove-unused-names_code-folding_all-features.txt
+    binaryen/test/passes/remove-unused-names_code-folding_all-features.wast
+    binaryen/test/passes/remove-unused-names_merge-blocks_all-features.txt
+    binaryen/test/passes/remove-unused-names_merge-blocks_all-features.wast
+    binaryen/test/passes/remove-unused-names_optimize-instructions_all-features.txt
+    binaryen/test/passes/remove-unused-names_optimize-instructions_all-features.wast
+    binaryen/test/passes/remove-unused-names_precompute.txt
+    binaryen/test/passes/remove-unused-names_precompute.wast
+    binaryen/test/passes/remove-unused-names_remove-unused-brs_vacuum.txt
+    binaryen/test/passes/remove-unused-names_remove-unused-brs_vacuum.wast
+    binaryen/test/passes/remove-unused-names_vacuum.txt
+    binaryen/test/passes/remove-unused-names_vacuum.wast
+    binaryen/test/passes/remove-unused-names_vacuum_ignore-implicit-traps.txt
+    binaryen/test/passes/remove-unused-names_vacuum_ignore-implicit-traps.wast
+    binaryen/test/passes/remove-unused-nonfunction-module-elements_all-features.txt
+    binaryen/test/passes/remove-unused-nonfunction-module-elements_all-features.wast
+    binaryen/test/passes/reorder-functions.txt
+    binaryen/test/passes/reorder-functions.wast
+    binaryen/test/passes/reorder-locals.txt
+    binaryen/test/passes/reorder-locals.wast
+    binaryen/test/passes/reverse_dwarf_abbrevs.bin.txt
+    binaryen/test/passes/reverse_dwarf_abbrevs.passes
+    binaryen/test/passes/reverse_dwarf_abbrevs.wasm
+    binaryen/test/passes/roundtrip.txt
+    binaryen/test/passes/roundtrip.wast
+    binaryen/test/passes/rse_all-features.txt
+    binaryen/test/passes/rse_all-features.wast
+    binaryen/test/passes/safe-heap_disable-simd.txt
+    binaryen/test/passes/safe-heap_disable-simd.wast
+    binaryen/test/passes/safe-heap_enable-threads_enable-simd.txt
+    binaryen/test/passes/safe-heap_enable-threads_enable-simd.wast
+    binaryen/test/passes/safe-heap_enable-threads_enable-simd64.passes
+    binaryen/test/passes/safe-heap_enable-threads_enable-simd64.txt
+    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/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-locals-nonesting.txt
+    binaryen/test/passes/simplify-locals-nonesting.wast
+    binaryen/test/passes/simplify-locals-nostructure.txt
+    binaryen/test/passes/simplify-locals-nostructure.wast
+    binaryen/test/passes/simplify-locals-notee-nostructure.txt
+    binaryen/test/passes/simplify-locals-notee-nostructure.wast
+    binaryen/test/passes/simplify-locals-notee.txt
+    binaryen/test/passes/simplify-locals-notee.wast
+    binaryen/test/passes/simplify-locals.txt
+    binaryen/test/passes/simplify-locals.wast
+    binaryen/test/passes/simplify-locals_all-features.txt
+    binaryen/test/passes/simplify-locals_all-features.wast
+    binaryen/test/passes/simplify-locals_all-features_disable-exception-handling.txt
+    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
+    binaryen/test/passes/ssa_enable-threads.wast
+    binaryen/test/passes/ssa_fuzz-exec_enable-threads.txt
+    binaryen/test/passes/ssa_fuzz-exec_enable-threads.wast
+    binaryen/test/passes/stack-check_enable-mutable-globals.txt
+    binaryen/test/passes/stack-check_enable-mutable-globals.wast
+    binaryen/test/passes/strip-debug.bin.txt
+    binaryen/test/passes/strip-debug.wasm
+    binaryen/test/passes/strip-dwarf.bin.txt
+    binaryen/test/passes/strip-dwarf.wasm
+    binaryen/test/passes/strip-producers.bin.txt
+    binaryen/test/passes/strip-producers.wasm
+    binaryen/test/passes/strip-target-features.bin.txt
+    binaryen/test/passes/strip-target-features.wasm
+    binaryen/test/passes/strip-target-features_roundtrip_print-features_all-features.txt
+    binaryen/test/passes/strip-target-features_roundtrip_print-features_all-features.wast
+    binaryen/test/passes/stub-unsupported-js.txt
+    binaryen/test/passes/stub-unsupported-js.wast
+    binaryen/test/passes/too_much_for_liveness.bin.txt
+    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/trap-mode-clamp.txt
+    binaryen/test/passes/trap-mode-clamp.wast
+    binaryen/test/passes/trap-mode-js.txt
+    binaryen/test/passes/trap-mode-js.wast
+    binaryen/test/passes/untee.txt
+    binaryen/test/passes/untee.wast
+    binaryen/test/passes/vacuum_all-features.txt
+    binaryen/test/passes/vacuum_all-features.wast
+    binaryen/test/passes/vacuum_ignore-implicit-traps.txt
+    binaryen/test/passes/vacuum_ignore-implicit-traps.wast
+    binaryen/test/passes/vacuum_remove-unused-names_merge-blocks.txt
+    binaryen/test/passes/vacuum_remove-unused-names_merge-blocks.wast
+    binaryen/test/polymorphic_stack.wast
+    binaryen/test/polymorphic_stack.wast.from-wast
+    binaryen/test/polymorphic_stack.wast.fromBinary
+    binaryen/test/polymorphic_stack.wast.fromBinary.noDebugInfo
+    binaryen/test/print/memory-import-shared.minified.txt
+    binaryen/test/print/memory-import-shared.txt
+    binaryen/test/print/memory-import-shared.wast
+    binaryen/test/print/memory-shared.minified.txt
+    binaryen/test/print/memory-shared.txt
+    binaryen/test/print/memory-shared.wast
+    binaryen/test/print/min.minified.txt
+    binaryen/test/print/min.txt
+    binaryen/test/print/min.wast
+    binaryen/test/printf.c
+    binaryen/test/printf.txt
+    binaryen/test/reduce/destructive.wast
+    binaryen/test/reduce/destructive.wast.txt
+    binaryen/test/reduce/imports.wast
+    binaryen/test/reduce/imports.wast.txt
+    binaryen/test/reduce/memory_table.wast
+    binaryen/test/reduce/memory_table.wast.txt
+    binaryen/test/reduce/simple.wast
+    binaryen/test/reduce/simple.wast.txt
+    binaryen/test/reference-types.wast
+    binaryen/test/reference-types.wast.from-wast
+    binaryen/test/reference-types.wast.fromBinary
+    binaryen/test/reference-types.wast.fromBinary.noDebugInfo
+    binaryen/test/reg_switch.wast
+    binaryen/test/reg_switch.wast.from-wast
+    binaryen/test/reg_switch.wast.fromBinary
+    binaryen/test/reg_switch.wast.fromBinary.noDebugInfo
+    binaryen/test/revision
+    binaryen/test/segment-overlap.wast
+    binaryen/test/segment-overlap.wast.from-wast
+    binaryen/test/segment-overlap.wast.fromBinary
+    binaryen/test/segment-overlap.wast.fromBinary.noDebugInfo
+    binaryen/test/signext.wast
+    binaryen/test/signext.wast.from-wast
+    binaryen/test/signext.wast.fromBinary
+    binaryen/test/signext.wast.fromBinary.noDebugInfo
+    binaryen/test/simd.wast
+    binaryen/test/simd.wast.from-wast
+    binaryen/test/simd.wast.fromBinary
+    binaryen/test/simd.wast.fromBinary.noDebugInfo
+    binaryen/test/simd64.wast
+    binaryen/test/simd64.wast.from-wast
+    binaryen/test/simd64.wast.fromBinary
+    binaryen/test/simd64.wast.fromBinary.noDebugInfo
+    binaryen/test/spec/address-offset-range.fail.wast
+    binaryen/test/spec/address.wast
+    binaryen/test/spec/address64.wast
+    binaryen/test/spec/align.wast
+    binaryen/test/spec/align64.wast
+    binaryen/test/spec/atomics.wast
+    binaryen/test/spec/binary-leb128.wast
+    binaryen/test/spec/binary.wast
+    binaryen/test/spec/block.wast
+    binaryen/test/spec/br.wast
+    binaryen/test/spec/br_if.wast
+    binaryen/test/spec/br_table.wast
+    binaryen/test/spec/break-drop.wast
+    binaryen/test/spec/bulk-memory.wast
+    binaryen/test/spec/bulk-memory64.wast
+    binaryen/test/spec/call.wast
+    binaryen/test/spec/call_indirect.wast
+    binaryen/test/spec/call_indirect_sig_mismatch.wast
+    binaryen/test/spec/comments.wast
+    binaryen/test/spec/const.wast
+    binaryen/test/spec/Contributing.md
+    binaryen/test/spec/conversions.wast
+    binaryen/test/spec/custom.wast
+    binaryen/test/spec/data.wast
+    binaryen/test/spec/elem.wast
+    binaryen/test/spec/endianness.wast
+    binaryen/test/spec/endianness64.wast
+    binaryen/test/spec/events.wast
+    binaryen/test/spec/exception-handling.wast
+    binaryen/test/spec/expected-output/func_ptrs.wast.log
+    binaryen/test/spec/expected-output/names.wast.log
+    binaryen/test/spec/expected-output/old_imports.wast.log
+    binaryen/test/spec/expected-output/old_start.wast.log
+    binaryen/test/spec/exports.wast
+    binaryen/test/spec/f32.load32.fail.wast
+    binaryen/test/spec/f32.load64.fail.wast
+    binaryen/test/spec/f32.store32.fail.wast
+    binaryen/test/spec/f32.store64.fail.wast
+    binaryen/test/spec/f32.wast
+    binaryen/test/spec/f32_bitwise.wast
+    binaryen/test/spec/f32_cmp.wast
+    binaryen/test/spec/f64.load32.fail.wast
+    binaryen/test/spec/f64.load64.fail.wast
+    binaryen/test/spec/f64.store32.fail.wast
+    binaryen/test/spec/f64.store64.fail.wast
+    binaryen/test/spec/f64.wast
+    binaryen/test/spec/f64_bitwise.wast
+    binaryen/test/spec/f64_cmp.wast
+    binaryen/test/spec/fac.wast
+    binaryen/test/spec/float_exprs.wast
+    binaryen/test/spec/float_literals.wast
+    binaryen/test/spec/float_memory.wast
+    binaryen/test/spec/float_memory64.wast
+    binaryen/test/spec/float_misc.wast
+    binaryen/test/spec/forward.wast
+    binaryen/test/spec/func-local-after-body.fail.wast
+    binaryen/test/spec/func-local-before-param.fail.wast
+    binaryen/test/spec/func-local-before-result.fail.wast
+    binaryen/test/spec/func-param-after-body.fail.wast
+    binaryen/test/spec/func-result-after-body.fail.wast
+    binaryen/test/spec/func-result-before-param.fail.wast
+    binaryen/test/spec/func.wast
+    binaryen/test/spec/func_ptrs.wast
+    binaryen/test/spec/get_local.wast
+    binaryen/test/spec/globals.wast
+    binaryen/test/spec/i32.load32_s.fail.wast
+    binaryen/test/spec/i32.load32_u.fail.wast
+    binaryen/test/spec/i32.load64_s.fail.wast
+    binaryen/test/spec/i32.load64_u.fail.wast
+    binaryen/test/spec/i32.store32.fail.wast
+    binaryen/test/spec/i32.store64.fail.wast
+    binaryen/test/spec/i32.wast
+    binaryen/test/spec/i64.load64_s.fail.wast
+    binaryen/test/spec/i64.load64_u.fail.wast
+    binaryen/test/spec/i64.store64.fail.wast
+    binaryen/test/spec/i64.wast
+    binaryen/test/spec/if.wast
+    binaryen/test/spec/import-after-func.fail.wast
+    binaryen/test/spec/import-after-global.fail.wast
+    binaryen/test/spec/import-after-memory.fail.wast
+    binaryen/test/spec/import-after-table.fail.wast
+    binaryen/test/spec/imports.wast
+    binaryen/test/spec/inline-module.wast
+    binaryen/test/spec/int_exprs.wast
+    binaryen/test/spec/int_literals.wast
+    binaryen/test/spec/labels.wast
+    binaryen/test/spec/left-to-right.wast
+    binaryen/test/spec/LICENSE
+    binaryen/test/spec/linking.wast
+    binaryen/test/spec/load.wast
+    binaryen/test/spec/load64.wast
+    binaryen/test/spec/local_get.wast
+    binaryen/test/spec/local_set.wast
+    binaryen/test/spec/local_tee.wast
+    binaryen/test/spec/loop.wast
+    binaryen/test/spec/memory.wast
+    binaryen/test/spec/memory64.wast
+    binaryen/test/spec/memory_grow.wast
+    binaryen/test/spec/memory_grow64.wast
+    binaryen/test/spec/memory_redundancy.wast
+    binaryen/test/spec/memory_redundancy64.wast
+    binaryen/test/spec/memory_size.wast
+    binaryen/test/spec/memory_trap.wast
+    binaryen/test/spec/memory_trap64.wast
+    binaryen/test/spec/multivalue.wast
+    binaryen/test/spec/names.wast
+    binaryen/test/spec/nop.wast
+    binaryen/test/spec/of_string-overflow-hex-u32.fail.wast
+    binaryen/test/spec/of_string-overflow-hex-u64.fail.wast
+    binaryen/test/spec/of_string-overflow-s32.fail.wast
+    binaryen/test/spec/of_string-overflow-s64.fail.wast
+    binaryen/test/spec/of_string-overflow-u32.fail.wast
+    binaryen/test/spec/of_string-overflow-u64.fail.wast
+    binaryen/test/spec/old_address.wast
+    binaryen/test/spec/old_address64.wast
+    binaryen/test/spec/old_block.wast
+    binaryen/test/spec/old_br_if.wast
+    binaryen/test/spec/old_call.wast
+    binaryen/test/spec/old_call_indirect.wast
+    binaryen/test/spec/old_exports.wast
+    binaryen/test/spec/old_float_exprs.wast
+    binaryen/test/spec/old_float_literals.wast
+    binaryen/test/spec/old_func.wast
+    binaryen/test/spec/old_globals.wast
+    binaryen/test/spec/old_import.wast
+    binaryen/test/spec/old_int_literals.wast
+    binaryen/test/spec/old_loop.wast
+    binaryen/test/spec/old_select.wast
+    binaryen/test/spec/old_start.wast
+    binaryen/test/spec/old_unreachable.wast
+    binaryen/test/spec/README.md
+    binaryen/test/spec/ref_func.wast
+    binaryen/test/spec/ref_is_null.wast
+    binaryen/test/spec/ref_null.wast
+    binaryen/test/spec/resizing.wast
+    binaryen/test/spec/resizing64.wast
+    binaryen/test/spec/return.wast
+    binaryen/test/spec/run.py
+    binaryen/test/spec/select.wast
+    binaryen/test/spec/set_local.wast
+    binaryen/test/spec/simd.wast
+    binaryen/test/spec/skip-stack-guard-page.wast
+    binaryen/test/spec/stack.wast
+    binaryen/test/spec/start.wast
+    binaryen/test/spec/store.wast
+    binaryen/test/spec/store_retval.wast
+    binaryen/test/spec/switch.wast
+    binaryen/test/spec/tee_local.wast
+    binaryen/test/spec/token.wast
+    binaryen/test/spec/traps.wast
+    binaryen/test/spec/type.wast
+    binaryen/test/spec/typecheck.wast
+    binaryen/test/spec/unreachable.wast
+    binaryen/test/spec/unreached-invalid.wast
+    binaryen/test/spec/unwind.wast
+    binaryen/test/spec/utf8-custom-section-id.wast
+    binaryen/test/spec/utf8-import-field.wast
+    binaryen/test/spec/utf8-import-module.wast
+    binaryen/test/spec/utf8-invalid-encoding.wast
+    binaryen/test/stacky.wasm
+    binaryen/test/stacky.wasm.fromBinary
+    binaryen/test/table-import.wast
+    binaryen/test/table-import.wast.from-wast
+    binaryen/test/table-import.wast.fromBinary
+    binaryen/test/table-import.wast.fromBinary.noDebugInfo
+    binaryen/test/tail-call.wast
+    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/unit.wast.from-wast
+    binaryen/test/unit.wast.fromBinary
+    binaryen/test/unit.wast.fromBinary.noDebugInfo
+    binaryen/test/unit.wat
+    binaryen/test/unit/__init__.py
+    binaryen/test/unit/input/asyncify-coroutine.wat
+    binaryen/test/unit/input/asyncify-pure.txt
+    binaryen/test/unit/input/asyncify-pure.wat
+    binaryen/test/unit/input/asyncify-sleep.wat
+    binaryen/test/unit/input/asyncify-stackOverflow.wat
+    binaryen/test/unit/input/asyncify.js
+    binaryen/test/unit/input/atomics_target_feature.wasm
+    binaryen/test/unit/input/bulkmem_bad_datacount.wasm
+    binaryen/test/unit/input/bulkmem_data.wasm
+    binaryen/test/unit/input/bulkmem_target_feature.wasm
+    binaryen/test/unit/input/dwarf/cubescript.wasm
+    binaryen/test/unit/input/dwarf/zlib.wasm
+    binaryen/test/unit/input/em_asm_mangled_string.wat
+    binaryen/test/unit/input/empty.wasm
+    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/mutable_globals_target_feature.wasm
+    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
+    binaryen/test/unit/input/stack_ir.wat
+    binaryen/test/unit/input/tail_call_target_feature.wasm
+    binaryen/test/unit/input/truncsat_target_feature.wasm
+    binaryen/test/unit/input/update.sh
+    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_memory_packing.py
+    binaryen/test/unit/test_poppy_validation.py
+    binaryen/test/unit/test_stack_ir.py
+    binaryen/test/unit/test_tail_call_type.py
+    binaryen/test/unit/test_warnings.py
+    binaryen/test/unit/test_wasm2c.py
+    binaryen/test/unit/utils.py
+    binaryen/test/unreachable-code.wast
+    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
+    binaryen/test/unreachable-instr-type.wast.fromBinary.noDebugInfo
+    binaryen/test/unreachable-pops.wasm
+    binaryen/test/unreachable-pops.wasm.fromBinary
+    binaryen/test/untaken-br_if.wast
+    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
+    binaryen/test/wasm2js.traps.js
+    binaryen/test/wasm2js/add_div.2asm.js
+    binaryen/test/wasm2js/add_div.2asm.js.opt
+    binaryen/test/wasm2js/add_div.wast
+    binaryen/test/wasm2js/atomic_fence.2asm.js
+    binaryen/test/wasm2js/atomic_fence.2asm.js.opt
+    binaryen/test/wasm2js/atomic_fence.wast
+    binaryen/test/wasm2js/atomics_32.2asm.js
+    binaryen/test/wasm2js/atomics_32.2asm.js.opt
+    binaryen/test/wasm2js/atomics_32.wast
+    binaryen/test/wasm2js/base64.2asm.js
+    binaryen/test/wasm2js/base64.2asm.js.opt
+    binaryen/test/wasm2js/base64.wast
+    binaryen/test/wasm2js/br.2asm.js
+    binaryen/test/wasm2js/br_table.2asm.js
+    binaryen/test/wasm2js/br_table_hoisting.2asm.js
+    binaryen/test/wasm2js/br_table_hoisting.2asm.js.opt
+    binaryen/test/wasm2js/br_table_hoisting.wast
+    binaryen/test/wasm2js/br_table_temp.2asm.js
+    binaryen/test/wasm2js/br_table_temp.2asm.js.opt
+    binaryen/test/wasm2js/br_table_temp.wast
+    binaryen/test/wasm2js/br_table_to_loop.2asm.js
+    binaryen/test/wasm2js/br_table_to_loop.2asm.js.opt
+    binaryen/test/wasm2js/br_table_to_loop.wast
+    binaryen/test/wasm2js/break-drop.2asm.js
+    binaryen/test/wasm2js/bulk-memory.2asm.js
+    binaryen/test/wasm2js/bulk-memory.2asm.js.opt
+    binaryen/test/wasm2js/comments.2asm.js
+    binaryen/test/wasm2js/conversions-modified.2asm.js
+    binaryen/test/wasm2js/conversions-modified.2asm.js.opt
+    binaryen/test/wasm2js/conversions-modified.wast
+    binaryen/test/wasm2js/deterministic.2asm.js
+    binaryen/test/wasm2js/deterministic.2asm.js.opt
+    binaryen/test/wasm2js/deterministic.wast
+    binaryen/test/wasm2js/dot_import.2asm.js
+    binaryen/test/wasm2js/dot_import.2asm.js.opt
+    binaryen/test/wasm2js/dot_import.wast
+    binaryen/test/wasm2js/dynamicLibrary.2asm.js
+    binaryen/test/wasm2js/dynamicLibrary.2asm.js.opt
+    binaryen/test/wasm2js/dynamicLibrary.wast
+    binaryen/test/wasm2js/empty_export.2asm.js
+    binaryen/test/wasm2js/empty_export.2asm.js.opt
+    binaryen/test/wasm2js/empty_export.wast
+    binaryen/test/wasm2js/empty_imported_table.2asm.js
+    binaryen/test/wasm2js/empty_table.2asm.js
+    binaryen/test/wasm2js/emscripten-grow-no.2asm.js
+    binaryen/test/wasm2js/emscripten-grow-no.2asm.js.opt
+    binaryen/test/wasm2js/emscripten-grow-no.wast
+    binaryen/test/wasm2js/emscripten-grow-yes.2asm.js
+    binaryen/test/wasm2js/emscripten-grow-yes.2asm.js.opt
+    binaryen/test/wasm2js/emscripten-grow-yes.wast
+    binaryen/test/wasm2js/emscripten.2asm.js
+    binaryen/test/wasm2js/emscripten.2asm.js.opt
+    binaryen/test/wasm2js/emscripten.wast
+    binaryen/test/wasm2js/endianness.2asm.js
+    binaryen/test/wasm2js/excess_fallthrough.2asm.js
+    binaryen/test/wasm2js/excess_fallthrough.2asm.js.opt
+    binaryen/test/wasm2js/excess_fallthrough.wast
+    binaryen/test/wasm2js/f32.2asm.js
+    binaryen/test/wasm2js/f32_cmp.2asm.js
+    binaryen/test/wasm2js/f64_cmp.2asm.js
+    binaryen/test/wasm2js/fac.2asm.js
+    binaryen/test/wasm2js/float-ops.2asm.js
+    binaryen/test/wasm2js/float-ops.2asm.js.opt
+    binaryen/test/wasm2js/float-ops.wast
+    binaryen/test/wasm2js/float_literals-modified.2asm.js
+    binaryen/test/wasm2js/float_literals-modified.2asm.js.opt
+    binaryen/test/wasm2js/float_literals-modified.wast
+    binaryen/test/wasm2js/float_misc.2asm.js
+    binaryen/test/wasm2js/forward.2asm.js
+    binaryen/test/wasm2js/func-ptr-offset.2asm.js
+    binaryen/test/wasm2js/func-ptr-offset.2asm.js.opt
+    binaryen/test/wasm2js/func-ptr-offset.wast
+    binaryen/test/wasm2js/func_ptrs.2asm.js
+    binaryen/test/wasm2js/get-set-local.2asm.js
+    binaryen/test/wasm2js/get-set-local.2asm.js.opt
+    binaryen/test/wasm2js/get-set-local.wast
+    binaryen/test/wasm2js/get_local.2asm.js
+    binaryen/test/wasm2js/global_i64.2asm.js
+    binaryen/test/wasm2js/global_i64.2asm.js.opt
+    binaryen/test/wasm2js/global_i64.wast
+    binaryen/test/wasm2js/grow-memory-tricky.2asm.js
+    binaryen/test/wasm2js/grow-memory-tricky.2asm.js.opt
+    binaryen/test/wasm2js/grow-memory-tricky.wast
+    binaryen/test/wasm2js/grow_memory.2asm.js
+    binaryen/test/wasm2js/i32.2asm.js
+    binaryen/test/wasm2js/i64-add-sub.2asm.js
+    binaryen/test/wasm2js/i64-add-sub.2asm.js.opt
+    binaryen/test/wasm2js/i64-add-sub.wast
+    binaryen/test/wasm2js/i64-ctz.2asm.js
+    binaryen/test/wasm2js/i64-ctz.2asm.js.opt
+    binaryen/test/wasm2js/i64-ctz.wast
+    binaryen/test/wasm2js/i64-lowering.2asm.js
+    binaryen/test/wasm2js/i64-lowering.2asm.js.opt
+    binaryen/test/wasm2js/i64-lowering.wast
+    binaryen/test/wasm2js/i64-rotate.2asm.js
+    binaryen/test/wasm2js/i64-rotate.2asm.js.opt
+    binaryen/test/wasm2js/i64-rotate.wast
+    binaryen/test/wasm2js/i64-select.2asm.js
+    binaryen/test/wasm2js/i64-select.2asm.js.opt
+    binaryen/test/wasm2js/i64-select.wast
+    binaryen/test/wasm2js/i64-shifts.2asm.js
+    binaryen/test/wasm2js/i64-shifts.2asm.js.opt
+    binaryen/test/wasm2js/i64-shifts.wast
+    binaryen/test/wasm2js/if_unreachable.2asm.js
+    binaryen/test/wasm2js/if_unreachable.2asm.js.opt
+    binaryen/test/wasm2js/if_unreachable.wast
+    binaryen/test/wasm2js/indirect-select.2asm.js
+    binaryen/test/wasm2js/indirect-select.2asm.js.opt
+    binaryen/test/wasm2js/indirect-select.wast
+    binaryen/test/wasm2js/int_exprs.2asm.js
+    binaryen/test/wasm2js/labels.2asm.js
+    binaryen/test/wasm2js/left-to-right.2asm.js
+    binaryen/test/wasm2js/minified-memory.2asm.js
+    binaryen/test/wasm2js/minified-memory.2asm.js.opt
+    binaryen/test/wasm2js/minified-memory.wast
+    binaryen/test/wasm2js/minus_minus.2asm.js
+    binaryen/test/wasm2js/minus_minus.2asm.js.opt
+    binaryen/test/wasm2js/minus_minus.wast
+    binaryen/test/wasm2js/nested-selects.2asm.js
+    binaryen/test/wasm2js/nested-selects.2asm.js.opt
+    binaryen/test/wasm2js/nested-selects.wast
+    binaryen/test/wasm2js/ordering.2asm.js
+    binaryen/test/wasm2js/ordering.2asm.js.opt
+    binaryen/test/wasm2js/ordering.wast
+    binaryen/test/wasm2js/reinterpret.2asm.js
+    binaryen/test/wasm2js/reinterpret.2asm.js.opt
+    binaryen/test/wasm2js/reinterpret.wast
+    binaryen/test/wasm2js/reinterpret_scratch.2asm.js
+    binaryen/test/wasm2js/reinterpret_scratch.2asm.js.opt
+    binaryen/test/wasm2js/reinterpret_scratch.wast
+    binaryen/test/wasm2js/set_local.2asm.js
+    binaryen/test/wasm2js/sign_ext.2asm.js
+    binaryen/test/wasm2js/sign_ext.2asm.js.opt
+    binaryen/test/wasm2js/sign_ext.wast
+    binaryen/test/wasm2js/stack-modified.2asm.js
+    binaryen/test/wasm2js/stack-modified.2asm.js.opt
+    binaryen/test/wasm2js/stack-modified.wast
+    binaryen/test/wasm2js/start_func.2asm.js
+    binaryen/test/wasm2js/start_func.2asm.js.opt
+    binaryen/test/wasm2js/start_func.wast
+    binaryen/test/wasm2js/switch.2asm.js
+    binaryen/test/wasm2js/tee_local.2asm.js
+    binaryen/test/wasm2js/traps.2asm.js
+    binaryen/test/wasm2js/unaligned.2asm.js
+    binaryen/test/wasm2js/unaligned.2asm.js.opt
+    binaryen/test/wasm2js/unaligned.wast
+    binaryen/test/wasm2js/unary-ops.2asm.js
+    binaryen/test/wasm2js/unary-ops.2asm.js.opt
+    binaryen/test/wasm2js/unary-ops.wast
+    binaryen/test/wasm2js/unreachable-get-cycle.2asm.js
+    binaryen/test/wasm2js/unreachable-get-cycle.2asm.js.opt
+    binaryen/test/wasm2js/unreachable-get-cycle.wast
+    binaryen/test/wasm2js/unreachable-insts.2asm.js
+    binaryen/test/wasm2js/unreachable-insts.2asm.js.opt
+    binaryen/test/wasm2js/unreachable-insts.wast
+    binaryen/test/wasm2js/unreachable-later.2asm.js
+    binaryen/test/wasm2js/unreachable-later.2asm.js.opt
+    binaryen/test/wasm2js/unreachable-later.wast
+    binaryen/test/wasm2js/wasm2js.wast.asserts
+    binaryen/third_party/CMakeLists.txt
+    binaryen/third_party/llvm-project/Binary.cpp
+    binaryen/third_party/llvm-project/CMakeLists.txt
+    binaryen/third_party/llvm-project/ConvertUTF.cpp
+    binaryen/third_party/llvm-project/DataExtractor.cpp
+    binaryen/third_party/llvm-project/Debug.cpp
+    binaryen/third_party/llvm-project/DJB.cpp
+    binaryen/third_party/llvm-project/Dwarf.cpp
+    binaryen/third_party/llvm-project/dwarf2yaml.cpp
+    binaryen/third_party/llvm-project/DWARFAbbreviationDeclaration.cpp
+    binaryen/third_party/llvm-project/DWARFAcceleratorTable.cpp
+    binaryen/third_party/llvm-project/DWARFAddressRange.cpp
+    binaryen/third_party/llvm-project/DWARFCompileUnit.cpp
+    binaryen/third_party/llvm-project/DWARFContext.cpp
+    binaryen/third_party/llvm-project/DWARFDataExtractor.cpp
+    binaryen/third_party/llvm-project/DWARFDebugAbbrev.cpp
+    binaryen/third_party/llvm-project/DWARFDebugAddr.cpp
+    binaryen/third_party/llvm-project/DWARFDebugAranges.cpp
+    binaryen/third_party/llvm-project/DWARFDebugArangeSet.cpp
+    binaryen/third_party/llvm-project/DWARFDebugFrame.cpp
+    binaryen/third_party/llvm-project/DWARFDebugInfoEntry.cpp
+    binaryen/third_party/llvm-project/DWARFDebugLine.cpp
+    binaryen/third_party/llvm-project/DWARFDebugLoc.cpp
+    binaryen/third_party/llvm-project/DWARFDebugMacro.cpp
+    binaryen/third_party/llvm-project/DWARFDebugPubTable.cpp
+    binaryen/third_party/llvm-project/DWARFDebugRangeList.cpp
+    binaryen/third_party/llvm-project/DWARFDebugRnglists.cpp
+    binaryen/third_party/llvm-project/DWARFDie.cpp
+    binaryen/third_party/llvm-project/DWARFEmitter.cpp
+    binaryen/third_party/llvm-project/DWARFExpression.cpp
+    binaryen/third_party/llvm-project/DWARFFormValue.cpp
+    binaryen/third_party/llvm-project/DWARFGdbIndex.cpp
+    binaryen/third_party/llvm-project/DWARFListTable.cpp
+    binaryen/third_party/llvm-project/DWARFTypeUnit.cpp
+    binaryen/third_party/llvm-project/DWARFUnit.cpp
+    binaryen/third_party/llvm-project/DWARFUnitIndex.cpp
+    binaryen/third_party/llvm-project/DWARFVerifier.cpp
+    binaryen/third_party/llvm-project/DWARFVisitor.cpp
+    binaryen/third_party/llvm-project/DWARFVisitor.h
+    binaryen/third_party/llvm-project/DWARFYAML.cpp
+    binaryen/third_party/llvm-project/Error.cpp
+    binaryen/third_party/llvm-project/Error.h
+    binaryen/third_party/llvm-project/ErrorHandling.cpp
+    binaryen/third_party/llvm-project/FormatVariadic.cpp
+    binaryen/third_party/llvm-project/Hashing.cpp
+    binaryen/third_party/llvm-project/include/llvm-c/DataTypes.h
+    binaryen/third_party/llvm-project/include/llvm-c/DisassemblerTypes.h
+    binaryen/third_party/llvm-project/include/llvm-c/Error.h
+    binaryen/third_party/llvm-project/include/llvm-c/ErrorHandling.h
+    binaryen/third_party/llvm-project/include/llvm-c/Types.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/AllocatorList.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/APFloat.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/APInt.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/APSInt.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/ArrayRef.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/bit.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/BitmaskEnum.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/DenseMap.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/DenseMapInfo.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/DenseSet.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/edit_distance.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/EpochTracker.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/fallible_iterator.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/FoldingSet.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/FunctionExtras.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/Hashing.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/ilist_base.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/ilist_iterator.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/ilist_node.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/ilist_node_base.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/ilist_node_options.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/iterator.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/iterator_range.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/MapVector.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/None.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/Optional.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/PointerIntPair.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/PointerUnion.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/simple_ilist.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/SmallPtrSet.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/SmallSet.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/SmallString.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/SmallVector.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/STLExtras.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/StringExtras.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/StringMap.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/StringRef.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/StringSet.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/StringSwitch.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/Triple.h
+    binaryen/third_party/llvm-project/include/llvm/ADT/Twine.h
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/COFF.h
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Dwarf.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Dwarf.h
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/DynamicTags.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELF.h
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/AArch64.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/AMDGPU.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/ARC.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/ARM.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/AVR.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/BPF.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Hexagon.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/i386.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Lanai.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Mips.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/MSP430.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/PowerPC.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/RISCV.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Sparc.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/SystemZ.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/x86_64.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/MachO.def
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/MachO.h
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Magic.h
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Wasm.h
+    binaryen/third_party/llvm-project/include/llvm/BinaryFormat/WasmRelocs.def
+    binaryen/third_party/llvm-project/include/llvm/Config/abi-breaking.h
+    binaryen/third_party/llvm-project/include/llvm/Config/config.h
+    binaryen/third_party/llvm-project/include/llvm/Config/llvm-config.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DIContext.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAttribute.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFContext.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAddr.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAranges.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDie.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFExpression.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFFormValue.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFGdbIndex.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFListTable.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFObject.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFSection.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFUnit.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h
+    binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
+    binaryen/third_party/llvm-project/include/llvm/include/llvm/DebugInfo/DWARFContext.h
+    binaryen/third_party/llvm-project/include/llvm/LICENSE.TXT
+    binaryen/third_party/llvm-project/include/llvm/MC/LaneBitmask.h
+    binaryen/third_party/llvm-project/include/llvm/MC/MCExpr.h
+    binaryen/third_party/llvm-project/include/llvm/MC/MCFixup.h
+    binaryen/third_party/llvm-project/include/llvm/MC/MCFragment.h
+    binaryen/third_party/llvm-project/include/llvm/MC/MCInst.h
+    binaryen/third_party/llvm-project/include/llvm/MC/MCRegister.h
+    binaryen/third_party/llvm-project/include/llvm/MC/MCRegisterInfo.h
+    binaryen/third_party/llvm-project/include/llvm/MC/MCSymbol.h
+    binaryen/third_party/llvm-project/include/llvm/MC/MCSymbolWasm.h
+    binaryen/third_party/llvm-project/include/llvm/MC/SubtargetFeature.h
+    binaryen/third_party/llvm-project/include/llvm/Object/Archive.h
+    binaryen/third_party/llvm-project/include/llvm/Object/Binary.h
+    binaryen/third_party/llvm-project/include/llvm/Object/COFF.h
+    binaryen/third_party/llvm-project/include/llvm/Object/CVDebugRecord.h
+    binaryen/third_party/llvm-project/include/llvm/Object/Decompressor.h
+    binaryen/third_party/llvm-project/include/llvm/Object/ELF.h
+    binaryen/third_party/llvm-project/include/llvm/Object/ELFObjectFile.h
+    binaryen/third_party/llvm-project/include/llvm/Object/ELFTypes.h
+    binaryen/third_party/llvm-project/include/llvm/Object/Error.h
+    binaryen/third_party/llvm-project/include/llvm/Object/MachO.h
+    binaryen/third_party/llvm-project/include/llvm/Object/Minidump.h
+    binaryen/third_party/llvm-project/include/llvm/Object/ObjectFile.h
+    binaryen/third_party/llvm-project/include/llvm/Object/RelocationResolver.h
+    binaryen/third_party/llvm-project/include/llvm/Object/SymbolicFile.h
+    binaryen/third_party/llvm-project/include/llvm/Object/Wasm.h
+    binaryen/third_party/llvm-project/include/llvm/ObjectYAML/DWARFEmitter.h
+    binaryen/third_party/llvm-project/include/llvm/ObjectYAML/DWARFYAML.h
+    binaryen/third_party/llvm-project/include/llvm/ObjectYAML/ObjectYAML.h
+    binaryen/third_party/llvm-project/include/llvm/readme.txt
+    binaryen/third_party/llvm-project/include/llvm/Support/AArch64TargetParser.def
+    binaryen/third_party/llvm-project/include/llvm/Support/AArch64TargetParser.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Alignment.h
+    binaryen/third_party/llvm-project/include/llvm/Support/AlignOf.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Allocator.h
+    binaryen/third_party/llvm-project/include/llvm/Support/ARMAttributeParser.h
+    binaryen/third_party/llvm-project/include/llvm/Support/ARMBuildAttributes.h
+    binaryen/third_party/llvm-project/include/llvm/Support/ARMTargetParser.def
+    binaryen/third_party/llvm-project/include/llvm/Support/ARMTargetParser.h
+    binaryen/third_party/llvm-project/include/llvm/Support/BinaryByteStream.h
+    binaryen/third_party/llvm-project/include/llvm/Support/BinaryStream.h
+    binaryen/third_party/llvm-project/include/llvm/Support/BinaryStreamError.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Casting.h
+    binaryen/third_party/llvm-project/include/llvm/Support/CBindingWrapping.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Chrono.h
+    binaryen/third_party/llvm-project/include/llvm/Support/circular_raw_ostream.h
+    binaryen/third_party/llvm-project/include/llvm/Support/CodeGen.h
+    binaryen/third_party/llvm-project/include/llvm/Support/CommandLine.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Compiler.h
+    binaryen/third_party/llvm-project/include/llvm/Support/ConvertUTF.h
+    binaryen/third_party/llvm-project/include/llvm/Support/DataExtractor.h
+    binaryen/third_party/llvm-project/include/llvm/Support/DataTypes.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Debug.h
+    binaryen/third_party/llvm-project/include/llvm/Support/DJB.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Endian.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Errc.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Errno.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Error.h
+    binaryen/third_party/llvm-project/include/llvm/Support/ErrorHandling.h
+    binaryen/third_party/llvm-project/include/llvm/Support/ErrorOr.h
+    binaryen/third_party/llvm-project/include/llvm/Support/FileOutputBuffer.h
+    binaryen/third_party/llvm-project/include/llvm/Support/FileSystem.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Format.h
+    binaryen/third_party/llvm-project/include/llvm/Support/FormatAdapters.h
+    binaryen/third_party/llvm-project/include/llvm/Support/FormatCommon.h
+    binaryen/third_party/llvm-project/include/llvm/Support/FormatProviders.h
+    binaryen/third_party/llvm-project/include/llvm/Support/FormattedStream.h
+    binaryen/third_party/llvm-project/include/llvm/Support/FormatVariadic.h
+    binaryen/third_party/llvm-project/include/llvm/Support/FormatVariadicDetails.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Host.h
+    binaryen/third_party/llvm-project/include/llvm/Support/LEB128.h
+    binaryen/third_party/llvm-project/include/llvm/Support/LICENSE.TXT
+    binaryen/third_party/llvm-project/include/llvm/Support/LineIterator.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Locale.h
+    binaryen/third_party/llvm-project/include/llvm/Support/ManagedStatic.h
+    binaryen/third_party/llvm-project/include/llvm/Support/MathExtras.h
+    binaryen/third_party/llvm-project/include/llvm/Support/MD5.h
+    binaryen/third_party/llvm-project/include/llvm/Support/MemAlloc.h
+    binaryen/third_party/llvm-project/include/llvm/Support/MemoryBuffer.h
+    binaryen/third_party/llvm-project/include/llvm/Support/NativeFormatting.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Path.h
+    binaryen/third_party/llvm-project/include/llvm/Support/PointerLikeTypeTraits.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Printable.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Process.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Program.h
+    binaryen/third_party/llvm-project/include/llvm/Support/raw_ostream.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Regex.h
+    binaryen/third_party/llvm-project/include/llvm/Support/ReverseIteration.h
+    binaryen/third_party/llvm-project/include/llvm/Support/ScopedPrinter.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Signals.h
+    binaryen/third_party/llvm-project/include/llvm/Support/SmallVectorMemoryBuffer.h
+    binaryen/third_party/llvm-project/include/llvm/Support/SMLoc.h
+    binaryen/third_party/llvm-project/include/llvm/Support/SourceMgr.h
+    binaryen/third_party/llvm-project/include/llvm/Support/SwapByteOrder.h
+    binaryen/third_party/llvm-project/include/llvm/Support/TargetParser.h
+    binaryen/third_party/llvm-project/include/llvm/Support/TargetRegistry.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Threading.h
+    binaryen/third_party/llvm-project/include/llvm/Support/type_traits.h
+    binaryen/third_party/llvm-project/include/llvm/Support/TypeSize.h
+    binaryen/third_party/llvm-project/include/llvm/Support/Unicode.h
+    binaryen/third_party/llvm-project/include/llvm/Support/UnicodeCharRanges.h
+    binaryen/third_party/llvm-project/include/llvm/Support/WindowsError.h
+    binaryen/third_party/llvm-project/include/llvm/Support/WithColor.h
+    binaryen/third_party/llvm-project/include/llvm/Support/X86TargetParser.def
+    binaryen/third_party/llvm-project/include/llvm/Support/YAMLParser.h
+    binaryen/third_party/llvm-project/include/llvm/Support/YAMLTraits.h
+    binaryen/third_party/llvm-project/LEB128.cpp
+    binaryen/third_party/llvm-project/LineIterator.cpp
+    binaryen/third_party/llvm-project/MCRegisterInfo.cpp
+    binaryen/third_party/llvm-project/MD5.cpp
+    binaryen/third_party/llvm-project/MemoryBuffer.cpp
+    binaryen/third_party/llvm-project/NativeFormatting.cpp
+    binaryen/third_party/llvm-project/obj2yaml_Error.cpp
+    binaryen/third_party/llvm-project/ObjectFile.cpp
+    binaryen/third_party/llvm-project/Optional.cpp
+    binaryen/third_party/llvm-project/Path.cpp
+    binaryen/third_party/llvm-project/raw_ostream.cpp
+    binaryen/third_party/llvm-project/readme.txt
+    binaryen/third_party/llvm-project/ScopedPrinter.cpp
+    binaryen/third_party/llvm-project/SmallVector.cpp
+    binaryen/third_party/llvm-project/SourceMgr.cpp
+    binaryen/third_party/llvm-project/StringMap.cpp
+    binaryen/third_party/llvm-project/StringRef.cpp
+    binaryen/third_party/llvm-project/SymbolicFile.cpp
+    binaryen/third_party/llvm-project/Twine.cpp
+    binaryen/third_party/llvm-project/UnicodeCaseFold.cpp
+    binaryen/third_party/llvm-project/Unix/Path.inc
+    binaryen/third_party/llvm-project/Unix/Unix.h
+    binaryen/third_party/llvm-project/WithColor.cpp
+    binaryen/third_party/llvm-project/YAMLParser.cpp
+    binaryen/third_party/llvm-project/YAMLTraits.cpp
+    binaryen/third_party/setup.py
+    binaryen/third_party/wabt/wasm2c/README.md
+    binaryen/third_party/wabt/wasm2c/wasm-rt-impl.c
+    binaryen/third_party/wabt/wasm2c/wasm-rt-impl.h
+    binaryen/third_party/wabt/wasm2c/wasm-rt.h
+    binaryen/ubsan.blacklist
+    cbits/wrappers.c
+    CHANGELOG.md
+    LICENSE
+    README.md
+
+source-repository head
+  type: git
+  location: https://github.com/tweag/haskell-binaryen
+
+flag system-binaryen
+  description: Link against system-wide binaryen and don't build bundled binaryen
+  manual: True
+  default: False
+
+library
+  exposed-modules:
+      Binaryen
+      Binaryen.Event
+      Binaryen.Export
+      Binaryen.Expression
+      Binaryen.ExpressionId
+      Binaryen.ExternalKind
+      Binaryen.Features
+      Binaryen.Function
+      Binaryen.Global
+      Binaryen.Index
+      Binaryen.Module
+      Binaryen.Op
+      Binaryen.Relooper
+      Binaryen.SideEffects
+      Binaryen.Type
+  other-modules:
+      Paths_binaryen
+  autogen-modules:
+      Paths_binaryen
+  hs-source-dirs:
+      src
+  ghc-options: -Wall
+  build-depends:
+      base <5
+    , libbinaryen
+  default-language: Haskell2010
+
+library libbinaryen
+  other-modules:
+      Paths_binaryen
+  autogen-modules:
+      Paths_binaryen
+  ghc-options: -Wall
+  cc-options: -std=c11 -Wall -Wextra
+  c-sources:
+      cbits/wrappers.c
+  extra-libraries:
+      pthread
+      stdc++
+  build-depends:
+      base <5
+  if flag(system-binaryen)
+    extra-libraries:
+        binaryen
+  else
+    cxx-options: -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DBUILD_LLVM_DWARF -std=c++14 -Wall -Wextra -Wno-unused-parameter -Wno-implicit-int-float-conversion -Wno-unknown-warning-option -Wswitch
+    include-dirs:
+        binaryen/src
+        binaryen/third_party/llvm-project/include
+    cxx-sources:
+        binaryen/src/binaryen-c.cpp
+        binaryen/src/asmjs/asm_v_wasm.cpp
+        binaryen/src/asmjs/asmangle.cpp
+        binaryen/src/asmjs/shared-constants.cpp
+        binaryen/src/cfg/Relooper.cpp
+        binaryen/src/emscripten-optimizer/optimizer-shared.cpp
+        binaryen/src/emscripten-optimizer/parser.cpp
+        binaryen/src/emscripten-optimizer/simple_ast.cpp
+        binaryen/src/ir/ExpressionAnalyzer.cpp
+        binaryen/src/ir/ExpressionManipulator.cpp
+        binaryen/src/ir/LocalGraph.cpp
+        binaryen/src/ir/ReFinalize.cpp
+        binaryen/src/ir/stack-utils.cpp
+        binaryen/src/passes/AlignmentLowering.cpp
+        binaryen/src/passes/Asyncify.cpp
+        binaryen/src/passes/AvoidReinterprets.cpp
+        binaryen/src/passes/CoalesceLocals.cpp
+        binaryen/src/passes/CodeFolding.cpp
+        binaryen/src/passes/CodePushing.cpp
+        binaryen/src/passes/ConstHoisting.cpp
+        binaryen/src/passes/DataFlowOpts.cpp
+        binaryen/src/passes/DeadArgumentElimination.cpp
+        binaryen/src/passes/DeadCodeElimination.cpp
+        binaryen/src/passes/DeAlign.cpp
+        binaryen/src/passes/DeNaN.cpp
+        binaryen/src/passes/Directize.cpp
+        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
+        binaryen/src/passes/GenerateDynCalls.cpp
+        binaryen/src/passes/I64ToI32Lowering.cpp
+        binaryen/src/passes/Inlining.cpp
+        binaryen/src/passes/InstrumentLocals.cpp
+        binaryen/src/passes/InstrumentMemory.cpp
+        binaryen/src/passes/LegalizeJSInterface.cpp
+        binaryen/src/passes/LimitSegments.cpp
+        binaryen/src/passes/LocalCSE.cpp
+        binaryen/src/passes/LogExecution.cpp
+        binaryen/src/passes/LoopInvariantCodeMotion.cpp
+        binaryen/src/passes/MemoryPacking.cpp
+        binaryen/src/passes/MergeBlocks.cpp
+        binaryen/src/passes/MergeLocals.cpp
+        binaryen/src/passes/Metrics.cpp
+        binaryen/src/passes/MinifyImportsAndExports.cpp
+        binaryen/src/passes/NameList.cpp
+        binaryen/src/passes/NoExitRuntime.cpp
+        binaryen/src/passes/OptimizeAddedConstants.cpp
+        binaryen/src/passes/OptimizeInstructions.cpp
+        binaryen/src/passes/pass.cpp
+        binaryen/src/passes/PickLoadSigns.cpp
+        binaryen/src/passes/PostAssemblyScript.cpp
+        binaryen/src/passes/PostEmscripten.cpp
+        binaryen/src/passes/Precompute.cpp
+        binaryen/src/passes/Print.cpp
+        binaryen/src/passes/PrintCallGraph.cpp
+        binaryen/src/passes/PrintFeatures.cpp
+        binaryen/src/passes/PrintFunctionMap.cpp
+        binaryen/src/passes/RedundantSetElimination.cpp
+        binaryen/src/passes/RemoveImports.cpp
+        binaryen/src/passes/RemoveMemory.cpp
+        binaryen/src/passes/RemoveNonJSOps.cpp
+        binaryen/src/passes/RemoveUnusedBrs.cpp
+        binaryen/src/passes/RemoveUnusedModuleElements.cpp
+        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
+        binaryen/src/passes/Strip.cpp
+        binaryen/src/passes/StripTargetFeatures.cpp
+        binaryen/src/passes/TrapMode.cpp
+        binaryen/src/passes/Untee.cpp
+        binaryen/src/passes/Vacuum.cpp
+        binaryen/src/passes/WasmIntrinsics.cpp
+        binaryen/src/support/archive.cpp
+        binaryen/src/support/bits.cpp
+        binaryen/src/support/colors.cpp
+        binaryen/src/support/command-line.cpp
+        binaryen/src/support/debug.cpp
+        binaryen/src/support/file.cpp
+        binaryen/src/support/path.cpp
+        binaryen/src/support/safe_integer.cpp
+        binaryen/src/support/threads.cpp
+        binaryen/src/support/utilities.cpp
+        binaryen/src/wasm/literal.cpp
+        binaryen/src/wasm/wasm-binary.cpp
+        binaryen/src/wasm/wasm-debug.cpp
+        binaryen/src/wasm/wasm-emscripten.cpp
+        binaryen/src/wasm/wasm-interpreter.cpp
+        binaryen/src/wasm/wasm-io.cpp
+        binaryen/src/wasm/wasm-s-parser.cpp
+        binaryen/src/wasm/wasm-stack.cpp
+        binaryen/src/wasm/wasm-type.cpp
+        binaryen/src/wasm/wasm-validator.cpp
+        binaryen/src/wasm/wasm.cpp
+        binaryen/third_party/llvm-project/Binary.cpp
+        binaryen/third_party/llvm-project/ConvertUTF.cpp
+        binaryen/third_party/llvm-project/DataExtractor.cpp
+        binaryen/third_party/llvm-project/Debug.cpp
+        binaryen/third_party/llvm-project/DJB.cpp
+        binaryen/third_party/llvm-project/Dwarf.cpp
+        binaryen/third_party/llvm-project/dwarf2yaml.cpp
+        binaryen/third_party/llvm-project/DWARFAbbreviationDeclaration.cpp
+        binaryen/third_party/llvm-project/DWARFAcceleratorTable.cpp
+        binaryen/third_party/llvm-project/DWARFAddressRange.cpp
+        binaryen/third_party/llvm-project/DWARFCompileUnit.cpp
+        binaryen/third_party/llvm-project/DWARFContext.cpp
+        binaryen/third_party/llvm-project/DWARFDataExtractor.cpp
+        binaryen/third_party/llvm-project/DWARFDebugAbbrev.cpp
+        binaryen/third_party/llvm-project/DWARFDebugAddr.cpp
+        binaryen/third_party/llvm-project/DWARFDebugAranges.cpp
+        binaryen/third_party/llvm-project/DWARFDebugArangeSet.cpp
+        binaryen/third_party/llvm-project/DWARFDebugFrame.cpp
+        binaryen/third_party/llvm-project/DWARFDebugInfoEntry.cpp
+        binaryen/third_party/llvm-project/DWARFDebugLine.cpp
+        binaryen/third_party/llvm-project/DWARFDebugLoc.cpp
+        binaryen/third_party/llvm-project/DWARFDebugMacro.cpp
+        binaryen/third_party/llvm-project/DWARFDebugPubTable.cpp
+        binaryen/third_party/llvm-project/DWARFDebugRangeList.cpp
+        binaryen/third_party/llvm-project/DWARFDebugRnglists.cpp
+        binaryen/third_party/llvm-project/DWARFDie.cpp
+        binaryen/third_party/llvm-project/DWARFEmitter.cpp
+        binaryen/third_party/llvm-project/DWARFExpression.cpp
+        binaryen/third_party/llvm-project/DWARFFormValue.cpp
+        binaryen/third_party/llvm-project/DWARFGdbIndex.cpp
+        binaryen/third_party/llvm-project/DWARFListTable.cpp
+        binaryen/third_party/llvm-project/DWARFTypeUnit.cpp
+        binaryen/third_party/llvm-project/DWARFUnit.cpp
+        binaryen/third_party/llvm-project/DWARFUnitIndex.cpp
+        binaryen/third_party/llvm-project/DWARFVerifier.cpp
+        binaryen/third_party/llvm-project/DWARFVisitor.cpp
+        binaryen/third_party/llvm-project/DWARFYAML.cpp
+        binaryen/third_party/llvm-project/Error.cpp
+        binaryen/third_party/llvm-project/ErrorHandling.cpp
+        binaryen/third_party/llvm-project/FormatVariadic.cpp
+        binaryen/third_party/llvm-project/Hashing.cpp
+        binaryen/third_party/llvm-project/LEB128.cpp
+        binaryen/third_party/llvm-project/LineIterator.cpp
+        binaryen/third_party/llvm-project/MCRegisterInfo.cpp
+        binaryen/third_party/llvm-project/MD5.cpp
+        binaryen/third_party/llvm-project/MemoryBuffer.cpp
+        binaryen/third_party/llvm-project/NativeFormatting.cpp
+        binaryen/third_party/llvm-project/obj2yaml_Error.cpp
+        binaryen/third_party/llvm-project/ObjectFile.cpp
+        binaryen/third_party/llvm-project/Optional.cpp
+        binaryen/third_party/llvm-project/Path.cpp
+        binaryen/third_party/llvm-project/raw_ostream.cpp
+        binaryen/third_party/llvm-project/ScopedPrinter.cpp
+        binaryen/third_party/llvm-project/SmallVector.cpp
+        binaryen/third_party/llvm-project/SourceMgr.cpp
+        binaryen/third_party/llvm-project/StringMap.cpp
+        binaryen/third_party/llvm-project/StringRef.cpp
+        binaryen/third_party/llvm-project/SymbolicFile.cpp
+        binaryen/third_party/llvm-project/Twine.cpp
+        binaryen/third_party/llvm-project/UnicodeCaseFold.cpp
+        binaryen/third_party/llvm-project/WithColor.cpp
+        binaryen/third_party/llvm-project/YAMLParser.cpp
+        binaryen/third_party/llvm-project/YAMLTraits.cpp
+  default-language: Haskell2010
+
+test-suite test
+  type: exitcode-stdio-1.0
+  main-is: test.hs
+  other-modules:
+      Paths_binaryen
+  autogen-modules:
+      Paths_binaryen
+  hs-source-dirs:
+      test
+  ghc-options: -Wall -threaded -rtsopts
+  build-depends:
+      base <5
+    , binaryen
   default-language: Haskell2010
diff --git a/binaryen/CHANGELOG.md b/binaryen/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/binaryen/CHANGELOG.md
@@ -0,0 +1,241 @@
+Changelog
+=========
+
+This document describes changes between tagged Binaryen versions.
+
+To browse or download snapshots of old tagged versions, visit
+https://github.com/WebAssembly/binaryen/releases.
+
+Not all changes are documented here. In particular, new features, user-oriented
+fixes, options, command-line parameters, usage changes, deprecations,
+significant internal modifications and optimizations etc. generally deserve a
+mention. To examine the full set of changes between versions, visit the link to
+full changeset diff at the end of each section.
+
+Current Trunk
+-------------
+
+v98
+---
+
+- Add `--fast-math` mode. (#3155)
+- Initial implementation of "Memory64" proposal (#3130)
+- Lots of changes in support of GC proposal
+
+v97
+---
+
+- Remove asm2wasm, which supported Emscripten's fastcomp backend, after fastcomp
+  was removed.
+- The new feature flag `--enable-anyref` enables just the `anyref` type incl.
+  basic subtyping of `externref`, `funcref` and `exnref` (if enabled).
+- Enabling the exception handling or anyref features without also enabling
+  reference types is a validation error now.
+- The `Host` expression and its respective APIs have been refactored into
+  separate `MemorySize` and `MemoryGrow` expressions to align with other memory
+  instructions.
+
+v96
+---
+
+- Fuzzing: Compare wasm2js to the interpreter (#3026)
+- Fix CountLeadingZeroes on MSVC, which lead to bad optimizations (#3028)
+- Asyncify verbose option (#3022)
+- wasm2js: Add an "Export" scope for name resolution, avoids annoying
+  warnings (#2998)
+- Extend the C- and JS-APIs (#2586)
+
+v95
+---
+
+- Add Asyncify "add list" that adds to the list of functions to be instrumented.
+  Rename old lists to be clearer and more consistent with that, so now there is
+  "remove list" to remove, "add list" to add, and "only list" which if set means
+  that only those functions should be instrumented and nothing else.
+- Renamed various ambiguous C-API functions for consistency:
+  - `BinaryenBlockGetChild` to `BinaryenBlockGetChildAt`
+  - `BinaryenSwitchGetName` to `BinaryenSwitchGetNameAt`
+  - `BinaryenCallGetOperand` to `BinaryenCallGetOperandAt`
+  - `BinaryenCallIndirectGetOperand` to `BinaryenCallIndirectGetOperandAt`
+  - `BinaryenHostGetOperand` to `BinaryenHostGetOperandAt`
+  - `BinaryenThrowGetOperand` to `BinaryenThrowGetOperandAt`
+  - `BinaryenTupleMakeGetOperand` to `BinaryenTupleMakeGetOperandAt`
+
+v94
+---
+
+- The C-API's `BinaryenSetAPITracing` and the JS-API's `setAPITracing` have been
+  removed because this feature was not very useful anymore and had a significant
+  maintainance cost.
+- wasm-emscripten-finalize will no longer generate `stackSave`, `stackAlloc`,
+  `stackRestore` function.  It not expects them to be included in the input
+  file.
+
+v93
+---
+
+- First release with binaries built with github actions.
+
+
+v92
+---
+
+- The `multivalue` feature has been added. It allows functions and control flow
+  structures to return tuples and for locals and globals to have tuple types.
+  Tuples are created with the new `tuple.make` pseudoinstruction and their
+  elements are retrieved with the new `tuple.extract` pseudoinstruction.
+- The internal type interner has been rewritten to avoid taking locks in far
+  more situations. Depending on the workload, this may result in large speedups
+  and increased parallelism.
+- Represent the `dylink` section in Binaryen IR, so we can read, write, and
+  update it.
+
+v91
+---
+
+- `BinaryenExpressionGetSideEffects` (C API) and `getSideEffects` (JS API) now
+  takes an additional `features` parameter.
+- Reference type support is added. Supported instructions are `ref.null`,
+  `ref.is_null`, `ref.func`, and typed `select`. Table instructions are not
+  supported yet. For typed `select`, C/JS API can take an additional 'type'
+  parameter.
+
+v90
+---
+
+- `local.tee`'s C/Binaryen.js API now takes an additional type parameter for its
+  local type, like `local.get`. This is required to handle subtypes.
+- Added load_splat SIMD instructions
+- Binaryen.js instruction API changes:
+  - `notify` -> `atomic.notify`
+  - `i32.wait` / `i64.wait` -> `i32.atomic.wait` / `i64.atomic.wait`
+- Binaryen.js: `flags` argument in `setMemory` function is removed.
+- `atomic.fence` instruction support is added.
+- wasm-emscripten-finalize: Don't rely on name section being present in the
+  input. Use the exported names for things instead.
+- Added `mutable` parameter to BinaryenAddGlobalImport.
+- Replace BinaryenSIMDBitselect* with BinaryenSIMDTernary* in the C API and add
+  qfma/qfms instructions.
+- Added `offset` parameter to BinaryenSetFunctionTable.
+- Add the ability to create multivalue Types in the C and JS APIs.
+- Remove named function types. They are replaced by `params` and `results` types
+  local to each function.
+- Binaryen.js can now be compiled to Wasm using the `binaryen_wasm` target.
+  Unlike the JS variant, the Wasm variant requires asynchronously awaiting the
+  Wasm blob's instantiation and initialization before being usable, using the
+  `binaryen.ready` promise, e.g. `binaryen.ready.then(() => ...)`.
+- Binaryen.js now uses `binaryen` (was `Binaryen`) as its global name to align
+  with the npm package.
+- Binaryen.js: The result of `getMemorySegmentInfoByIndex` now has the same
+  structure as the respective inputs on creation (`byteOffset` -> `offset`).
+
+v88
+---
+
+- wasm-emscripten-finalize: For -pie binaries that import a mutable stack
+  pointer we internalize this an import it as immutable.
+- The `tail-call` feature including the `return_call` and `return_call_indirect`
+  instructions is ready to use.
+
+v87
+---
+
+- Rename Bysyncify => Asyncify
+
+v86
+---
+
+- The --initial-stack-pointer argument to wasm-emscripten-finalize no longer
+  has any effect.  It will be removed completely in future release.
+
+v85
+---
+
+- Wast file parsing rules now don't allow a few invalid formats for typeuses
+  that were previously allowed. Typeuse entries should follow this format,
+  meaning they should have (type) -> (param) -> (result) order if more than one
+  of them exist.
+  ```
+  typeuse ::= (type index|name)+ |
+              (type index|name)+ (param ..)* (result ..)* |
+              (param ..)* (result ..)*
+  ```
+  Also, all (local) nodes in function definition should be after all typeuse
+  elements.
+- Removed APIs related to deprecated instruction names in Binaryen.js:
+  - `get_local` / `getLocal`
+  - `set_local` / `setLocal`
+  - `tee_local` / `teeLocal`
+  - `get_global` / `getGlobal`
+  - `set_global` / `setGlobal`
+  - `current_memory` / `currentMemory`
+  - `grow_memory` / `growMemory`
+  They are now available as their new instruction names:
+  `local.get`, `local.set`, `local.tee`, `global.get`, `global.set`,
+  `memory.size`, and `memory.grow`.
+- Add feature handling to the C/JS API with no feature enabled by default.
+
+v84
+---
+
+- Generate dynCall thunks for any signatures used in "invoke" calls.
+
+v81
+---
+
+- Fix AsmConstWalker handling of string address in arg0 with -fPIC code
+
+v80
+---
+
+- Change default feature set in the absence of a target features section from
+  all features to MVP.
+
+v79
+---
+
+- Improve support for side modules
+
+v78
+---
+
+- Add `namedGlobals` to metadata output of wasm-emscripten-finalize
+- Add support for llvm PIC code.
+- Add --side-module option to wasm-emscripten-finalize.
+- Add `segmentPassive` argument to `BinaryenSetMemory` for marking segments
+  passive.
+- Make `-o -` print to stdout instead of a file named "-".
+
+v73
+---
+
+- Remove wasm-merge tool.
+
+v73
+---
+
+- Remove jsCall generation from wasm-emscripten-finalize.  This is not needed
+  as of https://github.com/emscripten-core/emscripten/pull/8255.
+
+v55
+---
+
+- `RelooperCreate` in the C API now has a Module parameter, and
+  `RelooperRenderAndDispose` does not.
+  - The JS API now has the `Relooper` constructor receive the `Module`.
+- Relooper: Condition properties on Branches must not have side effects.
+
+older
+-----
+
+- `BinaryenSetFunctionTable` in the C API no longer accepts an array of
+  functions, instead it accepts an array of function names, `const char**
+  funcNames`. Previously, you could not include imported functions because they
+  are of type `BinaryenImportRef` instead of `BinaryenFunctionRef`. #1650
+
+- `BinaryenSetFunctionTable` in the C API now expects the initial and maximum
+  table size as additional parameters, like `BinaryenSetMemory` does for pages,
+  so tables can be grown dynamically. #1687
+
+- Add `shared` parameters to `BinaryenAddMemoryImport` and `BinaryenSetMemory`,
+  to support a shared memory. #1686
diff --git a/binaryen/CMakeLists.txt b/binaryen/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/CMakeLists.txt
@@ -0,0 +1,390 @@
+cmake_minimum_required(VERSION 3.1.3)
+project(binaryen LANGUAGES C CXX VERSION 98)
+include(GNUInstallDirs)
+
+# The C++ standard whose features are required to build Binaryen.
+# Keep in sync with scripts/test/shared.py cxx_standard
+set(CXX_STANDARD 14)
+
+if(NOT CMAKE_BUILD_TYPE)
+  message(STATUS "No build type selected, default to Release")
+  set(CMAKE_BUILD_TYPE "Release")
+endif()
+
+# We default to assertions enabled, even in release builds so that we get
+# more useful error reports from users.
+option(BYN_ENABLE_ASSERTIONS "Enable assertions" ON)
+
+# For git users, attempt to generate a more useful version string
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
+  find_package(Git QUIET REQUIRED)
+  execute_process(COMMAND
+               "${GIT_EXECUTABLE}" --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git describe --tags --match version_*
+           RESULT_VARIABLE
+               GIT_VERSION_RESULT
+           OUTPUT_VARIABLE
+               GIT_VERSION
+           OUTPUT_STRIP_TRAILING_WHITESPACE)
+  if(${GIT_VERSION_RESULT})
+    message(WARNING "Error running git describe to determine version")
+  else()
+    set(PROJECT_VERSION "${PROJECT_VERSION} (${GIT_VERSION})")
+  endif()
+endif()
+
+configure_file(config.h.in config.h)
+
+# Support functionality.
+
+function(ADD_COMPILE_FLAG value)
+  message(STATUS "Building with ${value}")
+  FOREACH(variable CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+    set(${variable} "${${variable}} ${value}" PARENT_SCOPE)
+  ENDFOREACH(variable)
+endfunction()
+
+function(ADD_CXX_FLAG value)
+  message(STATUS "Building with ${value}")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${value}" PARENT_SCOPE)
+endfunction()
+
+function(ADD_DEBUG_COMPILE_FLAG value)
+  if("${CMAKE_BUILD_TYPE}" MATCHES "Debug")
+    message(STATUS "Building with ${value}")
+  endif()
+  FOREACH(variable CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG)
+    set(${variable} "${${variable}} ${value}" PARENT_SCOPE)
+  ENDFOREACH(variable)
+endfunction()
+
+function(ADD_NONDEBUG_COMPILE_FLAG value)
+  if(NOT "${CMAKE_BUILD_TYPE}" MATCHES "Debug")
+    message(STATUS "Building with ${value}")
+  endif()
+  FOREACH(variable CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_MINSIZEREL)
+    set(${variable} "${${variable}} ${value}" PARENT_SCOPE)
+  ENDFOREACH(variable)
+endfunction()
+
+function(ADD_LINK_FLAG value)
+  message(STATUS "Linking with ${value}")
+  FOREACH(variable CMAKE_EXE_LINKER_FLAGS)
+    set(${variable} "${${variable}} ${value}" PARENT_SCOPE)
+  ENDFOREACH(variable)
+endfunction()
+
+function(binaryen_setup_rpath name)
+  if(CMAKE_INSTALL_RPATH)
+    return()
+  endif()
+
+  if (APPLE)
+    set(_install_name_dir INSTALL_NAME_DIR "@rpath")
+    set(_install_rpath "@loader_path/../lib")
+  elseif(UNIX)
+    set(_install_rpath "\$ORIGIN/../lib")
+    if(${CMAKE_SYSTEM_NAME} MATCHES "(FreeBSD|DragonFly)")
+      set_property(TARGET ${name} APPEND_STRING PROPERTY
+                   LINK_FLAGS " -Wl,-z,origin ")
+    endif()
+  else()
+    return()
+  endif()
+
+  set_target_properties(${name} PROPERTIES
+                        BUILD_WITH_INSTALL_RPATH On
+                        INSTALL_RPATH "${_install_rpath}"
+                        ${_install_name_dir})
+endfunction()
+
+# Options
+
+option(BUILD_STATIC_LIB "Build as a static library" OFF)
+if (MSVC)
+  # We don't have dllexport declarations set up for windows yet.
+  set(BUILD_STATIC_LIB ON)
+endif()
+
+# For now, don't include full DWARF support in JS builds, for size.
+if (NOT EMSCRIPTEN)
+  option(BUILD_LLVM_DWARF "Enable full DWARF support" ON)
+
+  if(BUILD_LLVM_DWARF)
+    if(MSVC)
+      ADD_COMPILE_FLAG("/DBUILD_LLVM_DWARF")
+    else()
+      ADD_COMPILE_FLAG("-DBUILD_LLVM_DWARF")
+    endif()
+  endif()
+endif()
+
+# Compiler setup.
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
+if(BUILD_LLVM_DWARF)
+  include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third_party/llvm-project/include)
+endif()
+
+# Add output directory to include path so config.h can be found
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+# Force output to bin/ and lib/. This is to suppress CMake multigenerator output paths and avoid bin/Debug, bin/Release/ and so on, which is CMake default.
+FOREACH(SUFFIX "_DEBUG" "_RELEASE" "_RELWITHDEBINFO" "_MINSIZEREL" "")
+  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY${SUFFIX} "${PROJECT_BINARY_DIR}/bin")
+  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY${SUFFIX} "${PROJECT_BINARY_DIR}/lib")
+  set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY${SUFFIX} "${PROJECT_BINARY_DIR}/lib")
+ENDFOREACH()
+
+if(MSVC)
+  if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.0") # VS2013 and older explicitly need /arch:sse2 set, VS2015 no longer has that option, but always enabled.
+    add_compile_flag("/arch:sse2")
+  endif()
+  add_compile_flag("/wd4146") # Ignore warning "warning C4146: unary minus operator applied to unsigned type, result still unsigned", this pattern is used somewhat commonly in the code.
+  # 4267 and 4244 are conversion/truncation warnings. We might want to fix these but they are currently pervasive.
+  add_compile_flag("/wd4267")
+  add_compile_flag("/wd4244")
+  # 4722 warns that destructors never return, even with WASM_NORETURN.
+  add_compile_flag("/wd4722")
+  # "destructor was implicitly defined as deleted" caused by LLVM headers.
+  add_compile_flag("/wd4624")
+  add_compile_flag("/WX-")
+  add_debug_compile_flag("/Od")
+  add_nondebug_compile_flag("/O2")
+  add_compile_flag("/D_CRT_SECURE_NO_WARNINGS")
+  add_compile_flag("/D_SCL_SECURE_NO_WARNINGS")
+  # Visual Studio 2018 15.8 implemented conformant support for std::aligned_storage, but the conformant support is only enabled when the following flag is passed, to avoid
+  # breaking backwards compatibility with code that relied on the non-conformant behavior (the old nonconformant behavior is not used with Binaryen)
+  add_compile_flag("/D_ENABLE_EXTENDED_ALIGNED_STORAGE")
+  # Don't warn about using "strdup" as a reserved name.
+  add_compile_flag("/D_CRT_NONSTDC_NO_DEPRECATE")
+
+  # multi-core build.
+  add_compile_flag("/MP")
+
+  if(BYN_ENABLE_ASSERTIONS)
+    # On non-Debug builds cmake automatically defines NDEBUG, so we
+    # explicitly undefine it:
+    add_nondebug_compile_flag("/UNDEBUG") # Keep asserts.
+  endif()
+  # Also remove /D NDEBUG to avoid MSVC warnings about conflicting defines.
+  if( NOT CMAKE_BUILD_TYPE MATCHES "Debug" )
+    foreach(flags_var_to_scrub
+        CMAKE_CXX_FLAGS_RELEASE
+        CMAKE_CXX_FLAGS_RELWITHDEBINFO
+        CMAKE_CXX_FLAGS_MINSIZEREL
+        CMAKE_C_FLAGS_RELEASE
+        CMAKE_C_FLAGS_RELWITHDEBINFO
+        CMAKE_C_FLAGS_MINSIZEREL)
+      string(REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" " "
+        "${flags_var_to_scrub}" "${${flags_var_to_scrub}}")
+
+      # Compile with `/MT` to link against `libcmt.lib`, removing a dependency
+      # on `msvcrt.dll`. May result in slightly larger binaries but they should
+      # be more portable across systems.
+      string(REPLACE "/MD" "/MT" ${flags_var_to_scrub} "${${flags_var_to_scrub}}")
+    endforeach()
+  endif()
+
+  add_link_flag("/STACK:8388608")
+
+  if(RUN_STATIC_ANALYZER)
+    add_definitions(/analyze)
+  endif()
+else()
+
+  option(ENABLE_WERROR "Enable -Werror" ON)
+
+  set(THREADS_PREFER_PTHREAD_FLAG ON)
+  set(CMAKE_THREAD_PREFER_PTHREAD ON)
+  find_package(Threads REQUIRED)
+  add_cxx_flag("-std=c++${CXX_STANDARD}")
+  if(NOT EMSCRIPTEN)
+    if(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$")
+      # wasm doesn't allow for x87 floating point math
+      add_compile_flag("-msse2")
+      add_compile_flag("-mfpmath=sse")
+    elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^armv[2-6]" AND NOT CMAKE_CXX_FLAGS MATCHES "-mfpu=")
+      add_compile_flag("-mfpu=vfpv3")
+    endif()
+  endif()
+  add_compile_flag("-Wall")
+  if(ENABLE_WERROR)
+    add_compile_flag("-Werror")
+  endif()
+  add_compile_flag("-Wextra")
+  add_compile_flag("-Wno-unused-parameter")
+  add_compile_flag("-fno-omit-frame-pointer")
+  # 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")
+  add_compile_flag("-Wno-unknown-warning-option")
+  add_compile_flag("-Wswitch") # we explicitly expect this in the code
+  if(WIN32)
+    add_compile_flag("-D_GNU_SOURCE")
+    add_link_flag("-Wl,--stack,8388608")
+  elseif(NOT EMSCRIPTEN)
+    add_compile_flag("-fPIC")
+  endif()
+  add_debug_compile_flag("-O0")
+  add_debug_compile_flag("-g3")
+  if(EMSCRIPTEN)
+    # really focus on minimizing output size when compiling sources
+    add_nondebug_compile_flag("-Oz")
+  else()
+    add_nondebug_compile_flag("-O2")
+  endif()
+  if(BYN_ENABLE_ASSERTIONS)
+    # On non-Debug builds cmake automatically defines NDEBUG, so we
+    # explicitly undefine it:
+    add_nondebug_compile_flag("-UNDEBUG")
+  endif()
+endif()
+
+if(EMSCRIPTEN)
+  # link with -O3 for metadce and other powerful optimizations. note that we
+  # must use add_link_options so that this appears after CMake's default -O2
+  add_link_options("-O3")
+  add_link_flag("-s SINGLE_FILE")
+  add_link_flag("-s ALLOW_MEMORY_GROWTH=1")
+  add_compile_flag("-s DISABLE_EXCEPTION_CATCHING=0")
+  add_link_flag("-s DISABLE_EXCEPTION_CATCHING=0")
+  # make the tools immediately usable on Node.js
+  add_link_flag("-s NODERAWFS")
+  # in opt builds, LTO helps so much (>20%) it's worth slow compile times
+  add_nondebug_compile_flag("-flto")
+endif()
+
+# clang doesn't print colored diagnostics when invoked from Ninja
+if(UNIX AND CMAKE_GENERATOR STREQUAL "Ninja")
+  if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+    add_compile_flag("-fdiagnostics-color=always")
+  elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+    add_compile_flag("-fcolor-diagnostics")
+  endif()
+endif()
+
+# Static libraries
+# Current (partial) dependency structure is as follows:
+# passes -> wasm -> asmjs -> support
+# TODO: It's odd that wasm should depend on asmjs, maybe we should fix that.
+add_subdirectory(src/ir)
+add_subdirectory(src/asmjs)
+add_subdirectory(src/cfg)
+add_subdirectory(src/emscripten-optimizer)
+add_subdirectory(src/passes)
+add_subdirectory(src/support)
+add_subdirectory(src/wasm)
+add_subdirectory(third_party)
+
+# Object files
+set(binaryen_objs
+    $<TARGET_OBJECTS:passes>
+    $<TARGET_OBJECTS:wasm>
+    $<TARGET_OBJECTS:asmjs>
+    $<TARGET_OBJECTS:emscripten-optimizer>
+    $<TARGET_OBJECTS:ir>
+    $<TARGET_OBJECTS:cfg>
+    $<TARGET_OBJECTS:support>)
+
+IF(BUILD_LLVM_DWARF)
+  SET(binaryen_objs ${binaryen_objs} $<TARGET_OBJECTS:llvm_dwarf>)
+ENDIF()
+
+# Sources.
+
+file(GLOB binaryen_HEADERS src/*.h)
+set(binaryen_SOURCES
+  src/binaryen-c.cpp
+  ${binaryen_HEADERS}
+)
+if(BUILD_STATIC_LIB)
+  message(STATUS "Building libbinaryen as statically linked library.")
+  add_library(binaryen STATIC ${binaryen_SOURCES} ${binaryen_objs})
+  add_definitions(-DBUILD_STATIC_LIBRARY)
+else()
+  message(STATUS "Building libbinaryen as shared library.")
+  add_library(binaryen SHARED ${binaryen_SOURCES} ${binaryen_objs})
+endif()
+install(TARGETS binaryen
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+
+install(FILES src/binaryen-c.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+function(binaryen_add_executable name sources)
+  add_executable(${name} ${sources})
+  target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT})
+  target_link_libraries(${name} binaryen)
+  set_property(TARGET ${name} PROPERTY CXX_STANDARD ${CXX_STANDARD})
+  set_property(TARGET ${name} PROPERTY CXX_STANDARD_REQUIRED ON)
+  binaryen_setup_rpath(${name})
+  install(TARGETS ${name} DESTINATION ${CMAKE_INSTALL_BINDIR})
+endfunction()
+
+binaryen_add_executable(wasm-opt src/tools/wasm-opt.cpp)
+binaryen_add_executable(wasm-shell src/tools/wasm-shell.cpp)
+binaryen_add_executable(wasm-metadce src/tools/wasm-metadce.cpp)
+binaryen_add_executable(wasm2js src/tools/wasm2js.cpp)
+binaryen_add_executable(wasm-emscripten-finalize src/tools/wasm-emscripten-finalize.cpp)
+binaryen_add_executable(wasm-as src/tools/wasm-as.cpp)
+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.js
+#
+# Note that we can't emit binaryen.js directly, as there is libbinaryen already
+# declared earlier, so we create binaryen_wasm/js.js, which must then be copied.
+# Note that SHELL: is needed as otherwise cmake will coalesce -s link flags
+# in an incorrect way for emscripten.
+if(EMSCRIPTEN)
+  set(binaryen_emscripten_SOURCES
+    src/binaryen-c.cpp
+    ${binaryen_HEADERS}
+  )
+
+  # binaryen.js WebAssembly variant
+  add_executable(binaryen_wasm
+                 ${binaryen_emscripten_SOURCES})
+  target_link_libraries(binaryen_wasm wasm asmjs emscripten-optimizer passes ir cfg support wasm)
+  target_link_libraries(binaryen_wasm "-s NO_FILESYSTEM=0")
+  target_link_libraries(binaryen_wasm "-s NODERAWFS=0")
+  target_link_libraries(binaryen_wasm "-s EXPORT_NAME=binaryen")
+  target_link_libraries(binaryen_wasm "--post-js ${CMAKE_CURRENT_SOURCE_DIR}/src/js/binaryen.js-post.js")
+  target_link_libraries(binaryen_wasm "--extern-pre-js ${CMAKE_CURRENT_SOURCE_DIR}/src/js/binaryen.js-extern-pre.js")
+  target_link_libraries(binaryen_wasm "--extern-post-js ${CMAKE_CURRENT_SOURCE_DIR}/src/js/binaryen.js-extern-post.js")
+  target_link_libraries(binaryen_wasm optimized "--closure 1")
+  target_link_libraries(binaryen_wasm optimized "--closure-args \"--language_in=ECMASCRIPT6 --language_out=ECMASCRIPT6\"")
+  target_link_libraries(binaryen_wasm optimized "-flto")
+  target_link_libraries(binaryen_wasm debug "--profiling")
+  set_property(TARGET binaryen_wasm PROPERTY CXX_STANDARD ${CXX_STANDARD})
+  set_property(TARGET binaryen_wasm PROPERTY CXX_STANDARD_REQUIRED ON)
+  install(TARGETS binaryen_wasm DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+  # binaryen.js JavaScript variant
+  add_executable(binaryen_js
+                 ${binaryen_emscripten_SOURCES})
+  target_link_libraries(binaryen_js wasm asmjs emscripten-optimizer passes ir cfg support wasm)
+  target_link_libraries(binaryen_js "-s WASM=0")
+  target_link_libraries(binaryen_js "-s WASM_ASYNC_COMPILATION=0")
+  if(${CMAKE_CXX_COMPILER_VERSION} STREQUAL "6.0.1")
+    # only valid with fastcomp and WASM=0
+    target_link_libraries(binaryen_js "-s ELIMINATE_DUPLICATE_FUNCTIONS=1")
+  endif()
+  target_link_libraries(binaryen_js "-s NO_FILESYSTEM=0")
+  target_link_libraries(binaryen_js "-s NODERAWFS=0")
+  target_link_libraries(binaryen_js "-s EXPORT_NAME=binaryen")
+  target_link_libraries(binaryen_js "--post-js ${CMAKE_CURRENT_SOURCE_DIR}/src/js/binaryen.js-post.js")
+  target_link_libraries(binaryen_js "--extern-pre-js ${CMAKE_CURRENT_SOURCE_DIR}/src/js/binaryen.js-extern-pre.js")
+  target_link_libraries(binaryen_js "--extern-post-js ${CMAKE_CURRENT_SOURCE_DIR}/src/js/binaryen.js-extern-post.js")
+  target_link_libraries(binaryen_js optimized "--closure 1")
+  target_link_libraries(binaryen_js optimized "--closure-args \"--language_in=ECMASCRIPT6 --language_out=ECMASCRIPT6\"")
+  target_link_libraries(binaryen_js optimized "-flto")
+  target_link_libraries(binaryen_js debug "--profiling")
+  target_link_libraries(binaryen_js debug "-s ASSERTIONS")
+  set_property(TARGET binaryen_js PROPERTY CXX_STANDARD ${CXX_STANDARD})
+  set_property(TARGET binaryen_js PROPERTY CXX_STANDARD_REQUIRED ON)
+  install(TARGETS binaryen_js DESTINATION ${CMAKE_INSTALL_BINDIR})
+endif()
diff --git a/binaryen/Contributing.md b/binaryen/Contributing.md
new file mode 100644
--- /dev/null
+++ b/binaryen/Contributing.md
@@ -0,0 +1,33 @@
+# Contributing to WebAssembly
+
+Interested in participating? Please follow
+[the same contributing guidelines as the design repository][].
+
+  [the same contributing guidelines as the design repository]: https://github.com/WebAssembly/design/blob/master/Contributing.md
+
+Also, please be sure to read [the README.md](README.md) for this repository.
+
+## Adding support for new instructions
+
+Use this handy checklist to make sure your new instructions are fully supported:
+
+ - [ ] Instruction class or opcode added to src/wasm.h
+ - [ ] Instruction class added to src/wasm-builder.h
+ - [ ] Instruction class added to src/wasm-traversal.h
+ - [ ] Validation added to src/wasm/wasm-validator.cpp
+ - [ ] Interpretation added to src/wasm-interpreter.h
+ - [ ] Effects handled in src/ir/effects.h
+ - [ ] Precomputing handled in src/passes/Precompute.cpp
+ - [ ] Hashing and comparing in src/ir/ExpressionAnalyzer.cpp
+ - [ ] Parsing added in scripts/gen-s-parser.py, src/wasm-s-parser.h and src/wasm/wasm-s-parser.cpp
+ - [ ] Printing added in src/passes/Print.cpp
+ - [ ] Decoding added in src/wasm-binary.h and src/wasm/wasm-binary.cpp
+ - [ ] Binary writing added in src/wasm-stack.h and src/wasm/wasm-stack.cpp
+ - [ ] Support added in various classes inheriting OverriddenVisitor (and possibly other non-OverriddenVisitor classes as necessary)
+ - [ ] Support added to src/tools/fuzzing.h
+ - [ ] C API support added in src/binaryen-c.h and src/binaryen-c.cpp
+ - [ ] JS API support added in src/js/binaryen.js-post.js
+ - [ ] C API tested in test/example/c-api-kitchen-sink.c
+ - [ ] JS API tested in test/binaryen.js/kitchen-sink.js
+ - [ ] Tests added in test/spec
+ - [ ] Tests added in top-level test/
diff --git a/binaryen/LICENSE b/binaryen/LICENSE
new file mode 100644
--- /dev/null
+++ b/binaryen/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   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.
diff --git a/binaryen/README.md b/binaryen/README.md
new file mode 100644
--- /dev/null
+++ b/binaryen/README.md
@@ -0,0 +1,495 @@
+[![CI](https://github.com/WebAssembly/binaryen/workflows/CI/badge.svg?branch=master&event=push)](https://github.com/WebAssembly/binaryen/actions?query=workflow%3ACI)
+
+# Binaryen
+
+Binaryen is a compiler and toolchain infrastructure library for WebAssembly,
+written in C++. It aims to make [compiling to WebAssembly] **easy, fast, and
+effective**:
+
+ * **Easy**: Binaryen has a simple [C API] in a single header, and can also be
+   [used from JavaScript][JS_API]. It accepts input in [WebAssembly-like
+   form][compile_to_wasm] but also accepts a general [control flow graph] for
+   compilers that prefer that.
+
+ * **Fast**: Binaryen's internal IR uses compact data structures and is designed
+   for completely parallel codegen and optimization, using all available CPU
+   cores. Binaryen's IR also compiles down to WebAssembly extremely easily and
+   quickly because it is essentially a subset of WebAssembly.
+
+ * **Effective**: Binaryen's optimizer has many passes (see an overview later
+   down) that can improve code size and speed. These optimizations aim to make
+   Binaryen powerful enough to be used as a [compiler backend][backend] by
+   itself.  One specific area of focus is on WebAssembly-specific optimizations
+   (that general-purpose compilers might not do), which you can think of as
+   wasm [minification], similar to minification for JavaScript, CSS, etc., all
+   of which are language-specific.
+
+Compilers using Binaryen include:
+
+ * [`AssemblyScript`](https://github.com/AssemblyScript/assemblyscript) which compiles a subset of TypeScript to WebAssembly
+ * [`wasm2js`](https://github.com/WebAssembly/binaryen/blob/master/src/wasm2js.h) which compiles WebAssembly to JS
+ * [`Asterius`](https://github.com/tweag/asterius) which compiles Haskell to WebAssembly
+ * [`Grain`](https://github.com/grain-lang/grain) which compiles Grain to WebAssembly
+
+Binaryen also provides a set of **toolchain utilities** that can
+
+ * **Parse** and **emit** WebAssembly. In particular this lets you load
+   WebAssembly, optimize it using Binaryen, and re-emit it, thus implementing a
+   wasm-to-wasm optimizer in a single command.
+ * **Interpret** WebAssembly as well as run the WebAssembly spec tests.
+ * Integrate with **[Emscripten](http://emscripten.org)** in order to provide a
+   complete compiler toolchain from C and C++ to WebAssembly.
+ * **Polyfill** WebAssembly by running it in the interpreter compiled to
+   JavaScript, if the browser does not yet have native support (useful for
+   testing).
+
+Consult the [contributing instructions](Contributing.md) if you're interested in
+participating.
+
+## Binaryen IR
+
+Binaryen's internal IR is designed to be
+
+ * **Flexible and fast** for optimization.
+ * **As close as possible to WebAssembly** so it is simple and fast to convert
+   it to and from WebAssembly.
+
+There are a few differences between Binaryen IR and the WebAssembly language:
+
+ * Tree structure
+   * Binaryen IR [is a tree][binaryen_ir], i.e., it has hierarchical structure,
+     for convenience of optimization. This differs from the WebAssembly binary
+     format which is a stack machine.
+   * Consequently Binaryen's text format allows only s-expressions.
+     WebAssembly's official text format is primarily a linear instruction list
+     (with s-expression extensions). Binaryen can't read the linear style, but
+     it can read a wasm text file if it contains only s-expressions.
+   * Binaryen uses Stack IR to optimize "stacky" code (that can't be
+     represented in structured form).
+   * When stacky code must be represented in Binaryen IR, such as with
+     multivalue instructions and blocks, it is represented with tuple types that
+     do not exist in the WebAssembly language. In addition to multivalue
+     instructions, locals and globals can also have tuple types in Binaryen IR
+     but not in WebAssembly.
+ * Types and unreachable code
+   * WebAssembly limits block/if/loop types to none and the concrete value types
+     (i32, i64, f32, f64). Binaryen IR has an unreachable type, and it allows
+     block/if/loop to take it, allowing [local transforms that don't need to
+     know the global context][unreachable]. As a result, Binaryen's default
+     text output is not necessarily valid wasm text. (To get valid wasm text,
+     you can do `--generate-stack-ir --print-stack-ir`, which prints Stack IR,
+     this is guaranteed to be valid for wasm parsers.)
+   * Binaryen ignores unreachable code when reading WebAssembly binaries. That
+     means that if you read a wasm file with unreachable code, that code will be
+     discarded as if it were optimized out (often this is what you want anyhow,
+     and optimized programs have no unreachable code anyway, but if you write an
+     unoptimized file and then read it, it may look different). The reason for
+     this behavior is that unreachable code in WebAssembly has corner cases that
+     are tricky to handle in Binaryen IR (it can be very unstructured, and
+     Binaryen IR is more structured than WebAssembly as noted earlier). Note
+     that Binaryen does support unreachable code in .wat text files, since as we
+     saw Binaryen only supports s-expressions there, which are structured.
+ * Blocks
+   * Binaryen IR has only one node that contains a variable-length list of
+     operands: the block. WebAssembly on the other hand allows lists in loops,
+     if arms, and the top level of a function. Binaryen's IR has a single
+     operand for all non-block nodes; this operand may of course be a block.
+     The motivation for this property is that many passes need special code
+     for iterating on lists, so having a single IR node with a list simplifies
+     them.
+   * As in wasm, blocks and loops may have names. Branch targets in the IR are
+     resolved by name (as opposed to nesting depth). This has 2 consequences:
+     * Blocks without names may not be branch targets.
+     * Names are required to be unique. (Reading .wat files with duplicate names
+       is supported; the names are modified when the IR is constructed).
+   * As an optimization, a block that is the child of a loop (or if arm, or
+     function toplevel) and which has no branches targeting it will not be
+     emitted when generating wasm. Instead its list of operands will be directly
+     used in the containing node. Such a block is sometimes called an "implicit
+     block".
+ * Multivalue
+   * Binaryen will not represent multivalue instructions and values directly.
+     Binaryen's main focus is on optimization of wasm, and therefore the question
+     of whether we should have multivalue in the main IR is whether it justifes
+     the extra complexity there. Experiments show that the shrinking of code
+     size thanks to multivalue is useful but small, just 1-3% or so. Given that,
+     we prefer to keep the main IR simple, and focus on multivalue optimizations
+     in Stack IR, which is more suitable for such things.
+   * Binaryen does still need to implement the "ABI" level of multivalue, that
+     is, we need multivalue calls because those may cross module boundaries,
+     and so they are observable externally. To support that, Binaryen may use
+     `push` and `pop` as mentioned earlier; another option is to add LLVM-like
+     `extractvalue/composevalue` instructions.
+
+As a result, you might notice that round-trip conversions (wasm => Binaryen IR
+=> wasm) change code a little in some corner cases.
+
+ * When optimizing Binaryen uses an additional IR, Stack IR (see
+   `src/wasm-stack.h`). Stack IR allows a bunch of optimizations that are
+   tailored for the stack machine form of WebAssembly's binary format (but Stack
+   IR is less efficient for general optimizations than the main Binaryen IR). If
+   you have a wasm file that has been particularly well-optimized, a simple
+   round-trip conversion (just read and write, without optimization) may cause
+   more noticeable differences, as Binaryen fits it into Binaryen IR's more
+   structured format. If you also optimize during the round-trip conversion then
+   Stack IR opts will be run and the final wasm will be better optimized.
+
+Notes when working with Binaryen IR:
+
+ * As mentioned above, Binaryen IR has a tree structure. As a result, each
+   expression should have exactly one parent - you should not "reuse" a node by
+   having it appear more than once in the tree. The motivation for this
+   limitation is that when we optimize we modify nodes, so if they appear more
+   than once in the tree, a change in one place can appear in another
+   incorrectly.
+ * For similar reasons, nodes should not appear in more than one functions.
+
+## Tools
+
+This repository contains code that builds the following tools in `bin/`:
+
+ * **wasm-opt**: Loads WebAssembly and runs Binaryen IR passes on it.
+ * **wasm-as**: Assembles WebAssembly in text format (currently S-Expression
+   format) into binary format (going through Binaryen IR).
+ * **wasm-dis**: Un-assembles WebAssembly in binary format into text format
+   (going through Binaryen IR).
+ * **wasm2js**: A WebAssembly-to-JS compiler. This is used by Emscripten to
+   generate JavaScript as an alternative to WebAssembly.
+ * **wasm-reduce**: A testcase reducer for WebAssembly files. Given a wasm file
+   that is interesting for some reason (say, it crashes a specific VM),
+   wasm-reduce can find a smaller wasm file that has the same property, which is
+   often easier to debug. See the
+   [docs](https://github.com/WebAssembly/binaryen/wiki/Fuzzing#reducing)
+   for more details.
+ * **wasm-shell**: A shell that can load and interpret WebAssembly code. It can
+   also run the spec test suite.
+ * **wasm-emscripten-finalize**: Takes a wasm binary produced by llvm+lld and
+   performs emscripten-specific passes over it.
+ * **wasm-ctor-eval**: A tool that can execute C++ global constructors ahead of
+   time. Used by Emscripten.
+ * **binaryen.js**: A standalone JavaScript library that exposes Binaryen methods for [creating and optimizing WASM modules](https://github.com/WebAssembly/binaryen/blob/master/test/binaryen.js/hello-world.js). For builds, see [binaryen.js on npm](https://www.npmjs.com/package/binaryen) (or download it directly from [github](https://raw.githubusercontent.com/AssemblyScript/binaryen.js/master/index.js), [rawgit](https://cdn.rawgit.com/AssemblyScript/binaryen.js/master/index.js), or [unpkg](https://unpkg.com/binaryen@latest/index.js)).
+
+Usage instructions for each are below.
+
+## Binaryen Optimizations
+
+Binaryen contains
+[a lot of optimization passes](https://github.com/WebAssembly/binaryen/tree/master/src/passes)
+to make WebAssembly smaller and faster. You can run the Binaryen optimizer by
+using ``wasm-opt``, but also they can be run while using other tools, like
+``wasm2js`` and ``wasm-metadce``.
+
+* The default optimization pipeline is set up by functions like
+  [`addDefaultFunctionOptimizationPasses`](https://github.com/WebAssembly/binaryen/blob/369b8bdd3d9d49e4d9e0edf62e14881c14d9e352/src/passes/pass.cpp#L396).
+* There are various
+  [pass options](https://github.com/WebAssembly/binaryen/blob/369b8bdd3d9d49e4d9e0edf62e14881c14d9e352/src/pass.h#L85)
+  that you can set, to adjust the optimization and shrink levels, whether to
+  ignore unlikely traps, inlining heuristics, fast-math, and so forth. See
+  ``wasm-opt --help`` for how to set them and other details.
+
+See each optimization pass for details of what it does, but here is a quick
+overview of some of the relevant ones:
+
+* **CoalesceLocals** - Key “register allocation” pass. Does a live range
+  analysis and then reuses locals in order to minimize their number, as well as
+  to remove copies between them.
+* **CodeFolding** - Avoids duplicate code by merging it (e.g. if two `if` arms
+  have some shared instructions at their end).
+* **CodePushing** - “Pushes” code forward past branch operations, potentially
+  allowing the code to not be run if the branch is taken.
+* **DeadArgumentElimination** - LTO pass to remove arguments to a function if it
+  is always called with the same constants.
+* **DeadCodeElimination**
+* **Directize** - Turn an indirect call into a normal call, when the table index
+  is constant.
+* **DuplicateFunctionElimination** - LTO pass.
+* **Inlining** - LTO pass.
+* **LocalCSE** - Simple local common subexpression elimination.
+* **LoopInvariantCodeMotion**
+* **MemoryPacking** - Key "optimize data segments" pass that combines segments,
+  removes unneeded parts, etc.
+* **MergeBlocks** - Merge a `block` to an outer one where possible, reducing
+  their number.
+* **MergeLocals** - When two locals have the same value in part of their
+  overlap, pick in a way to help CoalesceLocals do better later (split off from
+  CoalesceLocals to keep the latter simple).
+* **MinifyImportsAndExports** - Minifies them to “a”, “b”, etc.
+* **OptimizeAddedConstants** - Optimize a load/store with an added constant into
+  a constant offset.
+* **OptimizeInstructions** - Key peephole optimization pass with a constantly
+  increasing list of patterns.
+* **PickLoadSigns** - Adjust whether a load is signed or unsigned in order to
+  avoid sign/unsign operations later.
+* **Precompute** - Calculates constant expressions at compile time, using the
+  built-in interpreter (which is guaranteed to be able to handle any constant
+  expression).
+* **ReReloop** - Transforms wasm structured control flow to a CFG and then goes
+  back to structured form using the Relooper algorithm, which may find more
+  optimal shapes.
+* **RedundantSetElimination** - Removes a `local.set` of a value that is already
+  present in a local. (Overlaps with CoalesceLocals; this achieves the specific
+  operation just mentioned without all the other work CoalesceLocals does, and
+  therefore is useful in other places in the optimization pipeline.)
+* **RemoveUnsedBrs** - Key “minor control flow optimizations” pass, including
+  jump threading and various transforms that can get rid of a `br` or `br_table`
+  (like turning a `block` with a `br` in the middle into an `if` when possible).
+* **RemoveUnusedModuleElements** - “Global DCE”, an LTO pass that removes
+  imports, functions, globals, etc., when they are not used.
+* **ReorderFunctions** - Put more-called functions first, potentially allowing
+  the LEB emitted to call them to be smaller (in a very large program).
+* **ReorderLocals** - Put more-used locals first, potentially allowing the LEB
+  emitted to use them to be smaller (in a very large function). After the
+  sorting, it also removes locals not used at all.
+* **SimplifyGlobals** - Optimizes globals in various ways, for example,
+  coalescing them, removing mutability from a global never modified, applying a
+  constant value from an immutable global, etc.
+* **SimplifyLocals** - Key “`local.get/set/tee`” optimization pass, doing things
+  like replacing a set and a get with moving the set’s value to the get (and
+  creating a tee) where possible. Also creates `block/if/loop` return values
+  instead of using a local to pass the value.
+* **Vacuum** - Key “remove silly unneeded code” pass, doing things like removing
+  an `if` arm that has no contents, a drop of a constant value with no side
+  effects, a `block` with a single child, etc.
+
+“LTO” in the above means an optimization is Link Time Optimization-like in that
+it works across multiple functions, but in a sense Binaryen is always “LTO” as
+it usually is run on the final linked wasm.
+
+Advanced optimization techniques in the Binaryen optimizer include
+[SSAification](https://github.com/WebAssembly/binaryen/blob/master/src/passes/SSAify.cpp),
+[Flat IR](https://github.com/WebAssembly/binaryen/blob/master/src/ir/flat.h), and
+[Stack/Poppy IR](https://github.com/WebAssembly/binaryen/blob/master/src/ir/stack-utils.h).
+
+Binaryen also contains various passes that do other things than optimizations,
+like
+[legalization for JavaScript](https://github.com/WebAssembly/binaryen/blob/master/src/passes/LegalizeJSInterface.cpp),
+[Asyncify](https://github.com/WebAssembly/binaryen/blob/master/src/passes/Asyncify.cpp),
+etc.
+
+## Building
+
+```
+cmake . && make
+```
+
+A C++14 compiler is required. Note that you can also use `ninja` as your generator: `cmake -G Ninja . && ninja`.
+
+Binaryen.js can be built using Emscripten, which can be installed via [the SDK](http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html)).
+
+```
+emcmake cmake . && emmake make binaryen_js
+```
+
+### Visual C++
+
+1. Using the Microsoft Visual Studio Installer, install the "Visual C++ tools for CMake" component.
+
+1. Generate the projects:
+
+   ```
+   mkdir build
+   cd build
+   "%VISUAL_STUDIO_ROOT%\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" ..
+   ```
+
+   Substitute VISUAL_STUDIO_ROOT with the path to your Visual Studio
+   installation. In case you are using the Visual Studio Build Tools, the path
+   will be "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools".
+
+1. From the Developer Command Prompt, build the desired projects:
+
+   ```
+   msbuild binaryen.vcxproj
+   ```
+
+   CMake generates a project named "ALL_BUILD.vcxproj" for conveniently building all the projects.
+
+## Running
+
+### wasm-opt
+
+Run
+
+````
+bin/wasm-opt [.wasm or .wat file] [options] [passes, see --help] [--help]
+````
+
+The wasm optimizer receives WebAssembly as input, and can run transformation
+passes on it, as well as print it (before and/or after the transformations). For
+example, try
+
+````
+bin/wasm-opt test/passes/lower-if-else.wat --print
+````
+
+That will pretty-print out one of the test cases in the test suite. To run a
+transformation pass on it, try
+
+````
+bin/wasm-opt test/passes/lower-if-else.wat --print --lower-if-else
+````
+
+The `lower-if-else` pass lowers if-else into a block and a break. You can see
+the change the transformation causes by comparing the output of the two print
+commands.
+
+It's easy to add your own transformation passes to the shell, just add `.cpp`
+files into `src/passes`, and rebuild the shell. For example code, take a look at
+the [`lower-if-else` pass](https://github.com/WebAssembly/binaryen/blob/master/src/passes/LowerIfElse.cpp).
+
+Some more notes:
+
+ * See `bin/wasm-opt --help` for the full list of options and passes.
+ * Passing `--debug` will emit some debugging info.
+
+### wasm2js
+
+Run
+
+```
+bin/wasm2js [input.wasm file]
+```
+
+This will print out JavaScript to the console.
+
+For example, try
+
+```
+$ bin/wasm2js test/hello_world.wat
+```
+
+That output contains
+
+```
+ function add(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x + y | 0 | 0;
+ }
+```
+
+as a translation of
+
+```
+ (func $add (; 0 ;) (type $0) (param $x i32) (param $y i32) (result i32)
+  (i32.add
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+```
+
+wasm2js's output is in ES6 module format - basically, it converts a wasm
+module into an ES6 module (to run on older browsers and Node.js versions
+you can use Babel etc. to convert it to ES5). Let's look at a full example
+of calling that hello world wat; first, create the main JS file:
+
+```javascript
+// main.mjs
+import { add } from "./hello_world.mjs";
+console.log('the sum of 1 and 2 is:', add(1, 2));
+```
+
+The run this (note that you need a new enough Node.js with ES6 module
+support):
+
+```shell
+$ bin/wasm2js test/hello_world.wat -o hello_world.mjs
+$ node --experimental-modules main.mjs
+the sum of 1 and 2 is: 3
+```
+
+Things keep to in mind with wasm2js's output:
+
+ * You should run wasm2js with optimizations for release builds, using `-O`
+   or another optimization level. That will optimize along the entire pipeline
+   (wasm and JS). It won't do everything a JS minifer would, though, like
+   minify whitespace, so you should still run a normal JS minifer afterwards.
+ * It is not possible to match WebAssembly semantics 100% precisely with fast
+   JavaScript code. For example, every load and store may trap, and to make
+   JavaScript do the same we'd need to add checks everywhere, which would be
+   large and slow. Instead, wasm2js assumes loads and stores do not trap, that
+   int/float conversions do not trap, and so forth. There may also be slight
+   differences in corner cases of conversions, like non-trapping float to int.
+
+## Testing
+
+```
+./check.py
+```
+
+(or `python check.py`) will run `wasm-shell`, `wasm-opt`, etc. on the testcases in `test/`, and verify their outputs.
+
+The `check.py` script supports some options:
+
+```
+./check.py [--interpreter=/path/to/interpreter] [TEST1] [TEST2]..
+```
+
+ * If an interpreter is provided, we run the output through it, checking for
+   parse errors.
+ * If tests are provided, we run exactly those. If none are provided, we run
+   them all. To see what tests are available, run `./check.py --list-suites`.
+ * Some tests require `emcc` or `nodejs` in the path. They will not run if the
+   tool cannot be found, and you'll see a warning.
+ * We have tests from upstream in `tests/spec`, in git submodules. Running
+   `./check.py` should update those.
+
+### Setting up dependencies
+
+```
+./third_party/setup.py [mozjs|v8|wabt|all]
+```
+
+(or `python third_party/setup.py`) installs required dependencies like the SpiderMonkey JS shell, the V8 JS shell
+and WABT in `third_party/`. Other scripts automatically pick these up when installed.
+
+### Fuzzing
+
+```
+./scripts/fuzz_opt.py [--binaryen-bin=build/bin]
+```
+
+(or `python scripts/fuzz_opt.py`) will run various fuzzing modes on random inputs with random passes until it finds
+a possible bug. See [the wiki page](https://github.com/WebAssembly/binaryen/wiki/Fuzzing) for all the details.
+
+## Design Principles
+
+ * **Interned strings for names**: It's very convenient to have names on nodes,
+   instead of just numeric indices etc. To avoid most of the performance
+   difference between strings and numeric indices, all strings are interned,
+   which means there is a single copy of each string in memory, string
+   comparisons are just a pointer comparison, etc.
+ * **Allocate in arenas**: Based on experience with other
+   optimizing/transformating toolchains, it's not worth the overhead to
+   carefully track memory of individual nodes. Instead, we allocate all elements
+   of a module in an arena, and the entire arena can be freed when the module is
+   no longer needed.
+
+## FAQ
+
+* Why the weird name for the project?
+
+"Binaryen" is a combination of **binary** - since WebAssembly is a binary format
+for the web - and **Emscripten** - with which it can integrate in order to
+compile C and C++ all the way to WebAssembly, via asm.js. Binaryen began as
+Emscripten's WebAssembly processing library (`wasm-emscripten`).
+
+"Binaryen" is pronounced [in the same manner](http://www.makinggameofthrones.com/production-diary/2011/2/11/official-pronunciation-guide-for-game-of-thrones.html) as "[Targaryen](https://en.wikipedia.org/wiki/List_of_A_Song_of_Ice_and_Fire_characters#House_Targaryen)": *bi-NAIR-ee-in*. Or something like that? Anyhow, however Targaryen is correctly pronounced, they should rhyme. Aside from pronunciation, the Targaryen house words, "Fire and Blood", have also inspired Binaryen's: "Code and Bugs."
+
+* Does it compile under Windows and/or Visual Studio?
+
+Yes, it does. Here's a step-by-step [tutorial][win32]  on how to compile it
+under **Windows 10 x64** with with **CMake** and **Visual Studio 2015**. Help
+would be appreciated on Windows and OS X as most of the core devs are on Linux.
+
+[compiling to WebAssembly]: https://github.com/WebAssembly/binaryen/wiki/Compiling-to-WebAssembly-with-Binaryen
+[win32]: https://github.com/brakmic/bazaar/blob/master/webassembly/COMPILING_WIN32.md
+[C API]: https://github.com/WebAssembly/binaryen/wiki/Compiling-to-WebAssembly-with-Binaryen#c-api-1
+[control flow graph]: https://github.com/WebAssembly/binaryen/wiki/Compiling-to-WebAssembly-with-Binaryen#cfg-api
+[JS_API]: https://github.com/WebAssembly/binaryen/wiki/binaryen.js-API
+[compile_to_wasm]: https://github.com/WebAssembly/binaryen/wiki/Compiling-to-WebAssembly-with-Binaryen#what-do-i-need-to-have-in-order-to-use-binaryen-to-compile-to-webassembly
+[backend]: https://kripken.github.io/talks/binaryen.html#/9
+[minification]: https://kripken.github.io/talks/binaryen.html#/2
+[unreachable]: https://github.com/WebAssembly/binaryen/issues/903
+[binaryen_ir]: https://github.com/WebAssembly/binaryen/issues/663
diff --git a/binaryen/auto_update_tests.py b/binaryen/auto_update_tests.py
new file mode 100644
--- /dev/null
+++ b/binaryen/auto_update_tests.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python3
+#
+# Copyright 2015 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
+import subprocess
+import sys
+from collections import OrderedDict
+
+from scripts.test import binaryenjs
+from scripts.test import lld
+from scripts.test import shared
+from scripts.test import support
+from scripts.test import wasm2js
+from scripts.test import wasm_opt
+
+
+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)
+        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
+        # windows + gcc will need some work
+        if shared.skip_if_on_windows('gcc'):
+            return
+        # build the C file separately
+        extra = [os.environ.get('CC') or 'gcc',
+                 src, '-c', '-o', 'example.o',
+                 '-I' + os.path.join(shared.options.binaryen_root, 'src'), '-g', '-L' + libdir, '-pthread']
+        print('build: ', ' '.join(extra))
+        if src.endswith('.cpp'):
+            extra += ['-std=c++' + str(shared.cxx_standard)]
+        print(os.getcwd())
+        subprocess.check_call(extra)
+        # Link against the binaryen C library DSO, using rpath
+        cmd = ['example.o', '-L' + libdir, '-lbinaryen', '-Wl,-rpath,' + os.path.abspath(libdir)] + cmd
+        print('    ', basename, src, expected)
+        if os.environ.get('COMPILER_FLAGS'):
+            for f in os.environ.get('COMPILER_FLAGS').split(' '):
+                cmd.append(f)
+        cmd = [os.environ.get('CXX') or 'g++', '-std=c++' + str(shared.cxx_standard)] + cmd
+        try:
+            print('link: ', ' '.join(cmd))
+            subprocess.check_call(cmd)
+            print('run...', output_file)
+            proc = subprocess.Popen([output_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            actual, err = proc.communicate()
+            assert proc.returncode == 0, [proc.returncode, actual, err]
+            with open(expected, 'wb') as o:
+                o.write(actual)
+        finally:
+            os.remove(output_file)
+
+
+def update_wasm_dis_tests():
+    print('\n[ checking wasm-dis on provided binaries... ]\n')
+    for t in shared.get_tests(shared.options.binaryen_test, ['.wasm']):
+        print('..', os.path.basename(t))
+        cmd = shared.WASM_DIS + [t]
+        if os.path.isfile(t + '.map'):
+            cmd += ['--source-map', t + '.map']
+        actual = support.run_command(cmd)
+
+        open(t + '.fromBinary', 'w').write(actual)
+
+
+def update_ctor_eval_tests():
+    print('\n[ checking wasm-ctor-eval... ]\n')
+    for t in shared.get_tests(shared.get_test_dir('ctor-eval'), ['.wast', '.wasm']):
+        print('..', os.path.basename(t))
+        ctors = open(t + '.ctors').read().strip()
+        cmd = shared.WASM_CTOR_EVAL + [t, '-all', '-o', 'a.wast', '-S', '--ctors', ctors]
+        support.run_command(cmd)
+        actual = open('a.wast').read()
+        out = t + '.out'
+        with open(out, 'w') as o:
+            o.write(actual)
+
+
+def update_metadce_tests():
+    print('\n[ checking wasm-metadce... ]\n')
+    for t in shared.get_tests(shared.get_test_dir('metadce'), ['.wast', '.wasm']):
+        print('..', os.path.basename(t))
+        graph = t + '.graph.txt'
+        cmd = shared.WASM_METADCE + [t, '--graph-file=' + graph, '-o', 'a.wast', '-S', '-all']
+        stdout = support.run_command(cmd)
+        actual = open('a.wast').read()
+        out = t + '.dced'
+        with open(out, 'w') as o:
+            o.write(actual)
+        with open(out + '.stdout', 'w') as o:
+            o.write(stdout)
+
+
+def update_reduce_tests():
+    print('\n[ checking wasm-reduce ]\n')
+    for t in shared.get_tests(shared.get_test_dir('reduce'), ['.wast']):
+        print('..', os.path.basename(t))
+        # convert to wasm
+        support.run_command(shared.WASM_AS + [t, '-o', 'a.wasm'])
+        print(support.run_command(shared.WASM_REDUCE + ['a.wasm', '--command=%s b.wasm --fuzz-exec' % shared.WASM_OPT[0], '-t', 'b.wasm', '-w', 'c.wasm']))
+        expected = t + '.txt'
+        support.run_command(shared.WASM_DIS + ['c.wasm', '-o', expected])
+
+
+def update_spec_tests():
+    print('\n[ updating wasm-shell spec testcases... ]\n')
+
+    for t in shared.options.spec_tests:
+        print('..', os.path.basename(t))
+
+        cmd = shared.WASM_SHELL + [t]
+        expected = os.path.join(shared.get_test_dir('spec'), 'expected-output', os.path.basename(t) + '.log')
+        if os.path.isfile(expected):
+            stdout = support.run_command(cmd, stderr=subprocess.PIPE)
+            # filter out binaryen interpreter logging that the spec suite
+            # doesn't expect
+            filtered = [line for line in stdout.splitlines() if not line.startswith('[trap')]
+            stdout = '\n'.join(filtered) + '\n'
+            with open(expected, 'w') as o:
+                o.write(stdout)
+
+
+TEST_SUITES = OrderedDict([
+    ('wasm-opt', wasm_opt.update_wasm_opt_tests),
+    ('wasm-dis', update_wasm_dis_tests),
+    ('example', update_example_tests),
+    ('ctor-eval', update_ctor_eval_tests),
+    ('wasm-metadce', update_metadce_tests),
+    ('wasm-reduce', update_reduce_tests),
+    ('spec', update_spec_tests),
+    ('lld', lld.update_lld_tests),
+    ('wasm2js', wasm2js.update_wasm2js_tests),
+    ('binaryenjs', binaryenjs.update_binaryen_js_tests),
+])
+
+
+def main():
+    all_suites = TEST_SUITES.keys()
+    skip_by_default = ['binaryenjs']
+
+    if shared.options.list_suites:
+        for suite in all_suites:
+            print(suite)
+        return 0
+
+    if not shared.requested:
+        shared.requested = [s for s in all_suites if s not in skip_by_default]
+
+    for test in shared.requested:
+        TEST_SUITES[test]()
+
+    print('\n[ success! ]')
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/binaryen/check.py b/binaryen/check.py
new file mode 100644
--- /dev/null
+++ b/binaryen/check.py
@@ -0,0 +1,405 @@
+#!/usr/bin/env python3
+#
+# Copyright 2015 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 glob
+import os
+import subprocess
+import sys
+import unittest
+from collections import OrderedDict
+
+from scripts.test import binaryenjs
+from scripts.test import lld
+from scripts.test import shared
+from scripts.test import support
+from scripts.test import wasm2js
+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()
+    lines = [l for l in lines if len(l.split()) == 1]
+    lines = [l for l in lines if l.startswith('v')]
+    version = lines[0][1:]
+    print("Parsed CHANGELOG.md version: %s" % version)
+    return int(version)
+
+
+def run_help_tests():
+    print('[ checking --help is useful... ]\n')
+
+    not_executable_suffix = ['.txt', '.js', '.ilk', '.pdb', '.dll', '.wasm', '.manifest']
+    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)
+    assert len(executables)
+
+    for e in executables:
+        print('.. %s --help' % e)
+        out, err = subprocess.Popen([e, '--help'],
+                                    stdout=subprocess.PIPE,
+                                    stderr=subprocess.PIPE).communicate()
+        out = out.decode('utf-8')
+        err = err.decode('utf-8')
+        assert len(err) == 0, 'Expected no stderr, got:\n%s' % err
+        assert os.path.basename(e).replace('.exe', '') in out, 'Expected help to contain program name, got:\n%s' % out
+        assert len(out.split('\n')) > 8, 'Expected some help, got:\n%s' % out
+
+    print('[ checking --version ... ]\n')
+    changelog_version = get_changelog_version()
+    for e in executables:
+        print('.. %s --version' % e)
+        out, err = subprocess.Popen([e, '--version'],
+                                    stdout=subprocess.PIPE,
+                                    stderr=subprocess.PIPE).communicate()
+        out = out.decode('utf-8')
+        err = err.decode('utf-8')
+        assert len(err) == 0, 'Expected no stderr, got:\n%s' % err
+        assert os.path.basename(e).replace('.exe', '') in out, 'Expected version to contain program name, got:\n%s' % out
+        assert len(out.strip().splitlines()) == 1, 'Expected only version info, got:\n%s' % out
+        parts = out.split()
+        assert parts[1] == 'version'
+        version = int(parts[2])
+        assert version == changelog_version
+
+
+def run_wasm_dis_tests():
+    print('\n[ checking wasm-dis on provided binaries... ]\n')
+
+    for t in shared.get_tests(shared.options.binaryen_test, ['.wasm']):
+        print('..', os.path.basename(t))
+        cmd = shared.WASM_DIS + [t]
+        if os.path.isfile(t + '.map'):
+            cmd += ['--source-map', t + '.map']
+
+        actual = support.run_command(cmd)
+        shared.fail_if_not_identical_to_file(actual, t + '.fromBinary')
+
+        # also verify there are no validation errors
+        def check():
+            cmd = shared.WASM_OPT + [t, '-all']
+            support.run_command(cmd)
+
+        shared.with_pass_debug(check)
+
+
+def run_crash_tests():
+    print("\n[ checking we don't crash on tricky inputs... ]\n")
+
+    for t in shared.get_tests(shared.get_test_dir('crash'), ['.wast', '.wasm']):
+        print('..', os.path.basename(t))
+        cmd = shared.WASM_OPT + [t]
+        # expect a parse error to be reported
+        support.run_command(cmd, expected_err='parse exception:', err_contains=True, expected_status=1)
+
+
+def run_dylink_tests():
+    print("\n[ we emit dylink sections properly... ]\n")
+
+    dylink_tests = glob.glob(os.path.join(shared.options.binaryen_test, 'dylib*.wasm'))
+    for t in sorted(dylink_tests):
+        print('..', os.path.basename(t))
+        cmd = shared.WASM_OPT + [t, '-o', 'a.wasm']
+        support.run_command(cmd)
+        with open('a.wasm', 'rb') as output:
+            index = output.read().find(b'dylink')
+            print('  ', index)
+            assert index == 11, 'dylink section must be first, right after the magic number etc.'
+
+
+def run_ctor_eval_tests():
+    print('\n[ checking wasm-ctor-eval... ]\n')
+
+    for t in shared.get_tests(shared.get_test_dir('ctor-eval'), ['.wast', '.wasm']):
+        print('..', os.path.basename(t))
+        ctors = open(t + '.ctors').read().strip()
+        cmd = shared.WASM_CTOR_EVAL + [t, '-all', '-o', 'a.wat', '-S', '--ctors', ctors]
+        support.run_command(cmd)
+        actual = open('a.wat').read()
+        out = t + '.out'
+        shared.fail_if_not_identical_to_file(actual, out)
+
+
+def run_wasm_metadce_tests():
+    print('\n[ checking wasm-metadce ]\n')
+
+    for t in shared.get_tests(shared.get_test_dir('metadce'), ['.wast', '.wasm']):
+        print('..', os.path.basename(t))
+        graph = t + '.graph.txt'
+        cmd = shared.WASM_METADCE + [t, '--graph-file=' + graph, '-o', 'a.wat', '-S', '-all']
+        stdout = support.run_command(cmd)
+        expected = t + '.dced'
+        with open('a.wat') as seen:
+            shared.fail_if_not_identical_to_file(seen.read(), expected)
+        shared.fail_if_not_identical_to_file(stdout, expected + '.stdout')
+
+
+def run_wasm_reduce_tests():
+    if not shared.has_shell_timeout():
+        print('\n[ skipping wasm-reduce testcases]\n')
+        return
+
+    print('\n[ checking wasm-reduce testcases]\n')
+
+    # fixed testcases
+    for t in shared.get_tests(shared.get_test_dir('reduce'), ['.wast']):
+        print('..', os.path.basename(t))
+        # convert to wasm
+        support.run_command(shared.WASM_AS + [t, '-o', 'a.wasm'])
+        support.run_command(shared.WASM_REDUCE + ['a.wasm', '--command=%s b.wasm --fuzz-exec --detect-features ' % shared.WASM_OPT[0], '-t', 'b.wasm', '-w', 'c.wasm', '--timeout=4'])
+        expected = t + '.txt'
+        support.run_command(shared.WASM_DIS + ['c.wasm', '-o', 'a.wat'])
+        with open('a.wat') as seen:
+            shared.fail_if_not_identical_to_file(seen.read(), expected)
+
+    # run on a nontrivial fuzz testcase, for general coverage
+    # this is very slow in ThreadSanitizer, so avoid it there
+    if 'fsanitize=thread' not in str(os.environ):
+        print('\n[ checking wasm-reduce fuzz testcase ]\n')
+        # TODO: re-enable multivalue once it is better optimized
+        support.run_command(shared.WASM_OPT + [os.path.join(shared.options.binaryen_test, 'signext.wast'), '-ttf', '-Os', '-o', 'a.wasm', '--detect-features', '--disable-multivalue'])
+        before = os.stat('a.wasm').st_size
+        support.run_command(shared.WASM_REDUCE + ['a.wasm', '--command=%s b.wasm --fuzz-exec --detect-features' % shared.WASM_OPT[0], '-t', 'b.wasm', '-w', 'c.wasm'])
+        after = os.stat('c.wasm').st_size
+        # This number is a custom threshold to check if we have shrunk the
+        # output sufficiently
+        assert after < 0.85 * before, [before, after]
+
+
+def run_spec_tests():
+    print('\n[ checking wasm-shell spec testcases... ]\n')
+
+    for wast in shared.options.spec_tests:
+        base = os.path.basename(wast)
+        print('..', base)
+        # windows has some failures that need to be investigated
+        if base == 'names.wast' and shared.skip_if_on_windows('spec: ' + base):
+            continue
+
+        def run_spec_test(wast):
+            cmd = shared.WASM_SHELL + [wast]
+            output = support.run_command(cmd, stderr=subprocess.PIPE)
+            # filter out binaryen interpreter logging that the spec suite
+            # doesn't expect
+            filtered = [line for line in output.splitlines() if not line.startswith('[trap')]
+            return '\n'.join(filtered) + '\n'
+
+        def run_opt_test(wast):
+            # check optimization validation
+            cmd = shared.WASM_OPT + [wast, '-O', '-all']
+            support.run_command(cmd)
+
+        def check_expected(actual, expected):
+            if expected and os.path.exists(expected):
+                expected = open(expected).read()
+                print('       (using expected output)')
+                actual = actual.strip()
+                expected = expected.strip()
+                if actual != expected:
+                    shared.fail(actual, expected)
+
+        expected = os.path.join(shared.get_test_dir('spec'), 'expected-output', base + '.log')
+
+        # some spec tests should fail (actual process failure, not just assert_invalid)
+        try:
+            actual = run_spec_test(wast)
+        except Exception as e:
+            if ('wasm-validator error' in str(e) or 'parse exception' in str(e)) and '.fail.' in base:
+                print('<< test failed as expected >>')
+                continue  # don't try all the binary format stuff TODO
+            else:
+                shared.fail_with_error(str(e))
+
+        check_expected(actual, expected)
+
+        # skip binary checks for tests that reuse previous modules by name, as that's a wast-only feature
+        if 'exports.wast' in base:  # FIXME
+            continue
+
+        # check binary format. here we can verify execution of the final
+        # result, no need for an output verification
+        # some wast files cannot be split:
+        #     * comments.wast: contains characters that are not valid utf-8,
+        #       so our string splitting code fails there
+
+        # FIXME Remove reference type tests from this list after nullref is
+        # implemented in V8
+        if base not in ['comments.wast', 'ref_null.wast', 'ref_is_null.wast', 'ref_func.wast', 'old_select.wast']:
+            split_num = 0
+            actual = ''
+            for module, asserts in support.split_wast(wast):
+                print('        testing split module', split_num)
+                split_num += 1
+                support.write_wast('split.wast', module, asserts)
+                run_spec_test('split.wast')    # before binary stuff - just check it's still ok split out
+                run_opt_test('split.wast')    # also that our optimizer doesn't break on it
+                result_wast = shared.binary_format_check('split.wast', verify_final_result=False, original_wast=wast)
+                # add the asserts, and verify that the test still passes
+                open(result_wast, 'a').write('\n' + '\n'.join(asserts))
+                actual += run_spec_test(result_wast)
+            # compare all the outputs to the expected output
+            check_expected(actual, os.path.join(shared.get_test_dir('spec'), 'expected-output', base + '.log'))
+        else:
+            # handle unsplittable wast files
+            run_spec_test(wast)
+
+
+def run_validator_tests():
+    print('\n[ running validation tests... ]\n')
+    # Ensure the tests validate by default
+    cmd = shared.WASM_AS + [os.path.join(shared.get_test_dir('validator'), 'invalid_export.wast'), '-o', 'a.wasm']
+    support.run_command(cmd)
+    cmd = shared.WASM_AS + [os.path.join(shared.get_test_dir('validator'), 'invalid_import.wast'), '-o', 'a.wasm']
+    support.run_command(cmd)
+    cmd = shared.WASM_AS + ['--validate=web', os.path.join(shared.get_test_dir('validator'), 'invalid_export.wast'), '-o', 'a.wasm']
+    support.run_command(cmd, expected_status=1)
+    cmd = shared.WASM_AS + ['--validate=web', os.path.join(shared.get_test_dir('validator'), 'invalid_import.wast'), '-o', 'a.wasm']
+    support.run_command(cmd, expected_status=1)
+    cmd = shared.WASM_AS + ['--validate=none', os.path.join(shared.get_test_dir('validator'), 'invalid_return.wast'), '-o', 'a.wasm']
+    support.run_command(cmd)
+    cmd = shared.WASM_AS + [os.path.join(shared.get_test_dir('validator'), 'invalid_number.wast'), '-o', 'a.wasm']
+    support.run_command(cmd, expected_status=1)
+
+
+def run_gcc_tests():
+    print('\n[ checking native gcc testcases...]\n')
+    if not shared.NATIVECC or not shared.NATIVEXX:
+        shared.fail_with_error('Native compiler (e.g. gcc/g++) was not found in PATH!')
+        return
+    # windows + gcc will need some work
+    if shared.skip_if_on_windows('gcc'):
+        return
+
+    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:
+            continue
+        print('  ', t, src, expected)
+        if os.environ.get('COMPILER_FLAGS'):
+            for f in os.environ.get('COMPILER_FLAGS').split(' '):
+                cmd.append(f)
+        cmd = [shared.NATIVEXX, '-std=c++' + str(shared.cxx_standard)] + cmd
+        print('link: ', ' '.join(cmd))
+        subprocess.check_call(cmd)
+        print('run...', output_file)
+        actual = subprocess.check_output([os.path.abspath(output_file)]).decode('utf-8')
+        os.remove(output_file)
+        shared.fail_if_not_identical_to_file(actual, expected)
+
+
+def run_unittest():
+    print('\n[ checking unit tests...]\n')
+
+    # equivalent to `python -m unittest discover -s ./test -v`
+    suite = unittest.defaultTestLoader.discover(os.path.dirname(shared.options.binaryen_test))
+    result = unittest.TextTestRunner(verbosity=2, failfast=shared.options.abort_on_first_failure).run(suite)
+    shared.num_failures += len(result.errors) + len(result.failures)
+    if shared.options.abort_on_first_failure and shared.num_failures:
+        raise Exception("unittest failed")
+
+
+TEST_SUITES = OrderedDict([
+    ('help-messages', run_help_tests),
+    ('wasm-opt', wasm_opt.test_wasm_opt),
+    ('wasm-dis', run_wasm_dis_tests),
+    ('crash', run_crash_tests),
+    ('dylink', run_dylink_tests),
+    ('ctor-eval', run_ctor_eval_tests),
+    ('wasm-metadce', run_wasm_metadce_tests),
+    ('wasm-reduce', run_wasm_reduce_tests),
+    ('spec', run_spec_tests),
+    ('lld', lld.test_wasm_emscripten_finalize),
+    ('wasm2js', wasm2js.test_wasm2js),
+    ('validator', run_validator_tests),
+    ('gcc', run_gcc_tests),
+    ('unit', run_unittest),
+    ('binaryenjs', binaryenjs.test_binaryen_js),
+    ('binaryenjs_wasm', binaryenjs.test_binaryen_wasm),
+])
+
+
+# Run all the tests
+def main():
+    all_suites = TEST_SUITES.keys()
+    skip_by_default = ['binaryenjs', 'binaryenjs_wasm']
+
+    if shared.options.list_suites:
+        for suite in all_suites:
+            print(suite)
+        return 0
+
+    for r in shared.requested:
+        if r not in all_suites:
+            print('invalid test suite: %s (see --list-suites)\n' % r)
+            return 1
+
+    if not shared.requested:
+        shared.requested = [s for s in all_suites if s not in skip_by_default]
+
+    for test in shared.requested:
+        TEST_SUITES[test]()
+
+    # Check/display the results
+    if shared.num_failures == 0:
+        print('\n[ success! ]')
+
+    if shared.warnings:
+        print('\n' + '\n'.join(shared.warnings))
+
+    if shared.num_failures > 0:
+        print('\n[ ' + str(shared.num_failures) + ' failures! ]')
+        return 1
+
+    return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/binaryen/config.h.in b/binaryen/config.h.in
new file mode 100644
--- /dev/null
+++ b/binaryen/config.h.in
@@ -0,0 +1,1 @@
+#cmakedefine PROJECT_VERSION "${PROJECT_VERSION}"
diff --git a/binaryen/media/example.png b/binaryen/media/example.png
new file mode 100644
Binary files /dev/null and b/binaryen/media/example.png differ
diff --git a/binaryen/scripts/__init__.py b/binaryen/scripts/__init__.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/__init__.py
@@ -0,0 +1,15 @@
+# Copyright 2015 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.
+
+# Empty __init__.py file: Python treats the directory as containing a package.
diff --git a/binaryen/scripts/clang-format-diff.sh b/binaryen/scripts/clang-format-diff.sh
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/clang-format-diff.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+set -o errexit
+
+# When we are running on travis and *not* part of a pull request we don't
+# have any upstream branch to compare against.
+if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
+  echo "Skipping since not running on travis PR"
+  exit 0
+fi
+
+if [ -n "$TRAVIS_BRANCH" ]; then
+  BRANCH=$TRAVIS_BRANCH
+else
+  BRANCH=origin/master
+fi
+
+MERGE_BASE=$(git merge-base $BRANCH HEAD)
+FORMAT_MSG=$(git clang-format $MERGE_BASE -q --diff -- src/)
+if [ -n "$FORMAT_MSG" -a "$FORMAT_MSG" != "no modified files to format" ]
+then
+  echo "Please run git clang-format before committing, or apply this diff:"
+  echo
+  # Run git clang-format again, this time without capruting stdout.  This way
+  # clang-format format the message nicely and add color.
+  git clang-format $MERGE_BASE -q --diff -- src/
+  exit 1
+fi
diff --git a/binaryen/scripts/clang-tidy-diff.sh b/binaryen/scripts/clang-tidy-diff.sh
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/clang-tidy-diff.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+set -o errexit
+
+# When we are running on travis and *not* part of a pull request we don't
+# have any upstream branch to compare against.
+if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
+  echo "Skipping since not running on travis PR"
+  exit 0
+fi
+
+if [ -n "$TRAVIS_BRANCH" ]; then
+  BRANCH=$TRAVIS_BRANCH
+else
+  BRANCH=origin/master
+fi
+
+CLANG_TIDY=$(which clang-tidy)
+if [ ! -e "$CLANG_TIDY" ]; then
+  echo "Failed to find clang-tidy ($CLANG_TIDY)"
+  exit 1
+fi
+
+CLANG_DIR=$(dirname $(dirname $(readlink -f $CLANG_TIDY)))
+CLANG_TIDY_DIFF=$CLANG_DIR/share/clang/clang-tidy-diff.py
+if [ ! -e "$CLANG_TIDY_DIFF" ]; then
+  echo "Failed to find clang-tidy-diff.py ($CLANG_TIDY_DIFF)"
+  exit 1
+fi
+TIDY_MSG=$(git diff -U0 $BRANCH... | $CLANG_TIDY_DIFF -quiet -p1 2> /dev/null)
+if [ -n "$TIDY_MSG" -a "$TIDY_MSG" != "No relevant changes found." ]; then
+  echo "Please fix clang-tidy errors before committing"
+  echo
+  # Run clang-tidy once again to show the error
+  git diff -U0 $BRANCH... | $CLANG_TIDY_DIFF -quiet -p1 2> /dev/null
+  exit 1
+fi
diff --git a/binaryen/scripts/clean_c_api_trace.py b/binaryen/scripts/clean_c_api_trace.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/clean_c_api_trace.py
@@ -0,0 +1,37 @@
+#!/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/embedwat.py b/binaryen/scripts/embedwat.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/embedwat.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+#
+# 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.
+
+import sys
+
+input_file = sys.argv[1]
+output_file = sys.argv[2]
+
+with open(input_file) as f:
+    wat = f.read()
+
+output = """\
+// Automatically generated by embedwat.py
+
+#include "passes/intrinsics-module.h"
+
+static const char theModule[%d] = {
+""" % (len(wat) + 1)
+
+for c in wat:
+    output += str(ord(c)) + ', '
+
+output += '''0
+};
+
+namespace wasm {
+const char* IntrinsicsModuleWast = theModule;
+}
+'''
+
+with open(output_file, 'w') as f:
+    f.write(output)
diff --git a/binaryen/scripts/emcc-tests.sh b/binaryen/scripts/emcc-tests.sh
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/emcc-tests.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+set -e
+
+mkdir -p emcc-build
+echo "emcc-tests: build:wasm"
+emcmake cmake -B emcc-build -DCMAKE_BUILD_TYPE=Release -G Ninja
+ninja -C emcc-build binaryen_wasm
+echo "emcc-tests: test:wasm"
+./check.py --binaryen-bin=emcc-build/bin binaryenjs_wasm
+echo "emcc-tests: done:wasm"
+
+echo "emcc-tests: build:js"
+ninja -C emcc-build  binaryen_js
+echo "emcc-tests: test:js"
+./check.py --binaryen-bin=emcc-build/bin binaryenjs
+echo "emcc-tests: done:js"
diff --git a/binaryen/scripts/fuzz_opt.py b/binaryen/scripts/fuzz_opt.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/fuzz_opt.py
@@ -0,0 +1,1058 @@
+#!/usr/bin/python3
+
+'''
+Runs random passes and options on random inputs, using wasm-opt.
+
+Can be configured to run just wasm-opt itself (using --fuzz-exec)
+or also run VMs on it.
+
+For afl-fuzz integration, you probably don't want this, and can use
+something like
+
+BINARYEN_CORES=1 BINARYEN_PASS_DEBUG=1 afl-fuzz -i afl-testcases/ -o afl-findings/ -m 100 -d -- bin/wasm-opt -ttf --fuzz-exec --Os @@
+
+(that is on a fixed set of arguments to wasm-opt, though - this
+script covers different options being passed)
+'''
+
+import contextlib
+import os
+import difflib
+import math
+import shutil
+import subprocess
+import random
+import re
+import sys
+import time
+import traceback
+
+from test import shared
+
+assert sys.version_info.major == 3, 'requires Python 3!'
+
+# parameters
+
+# feature options that are always passed to the tools.
+# * multivalue: https://github.com/WebAssembly/binaryen/issues/2770
+CONSTANT_FEATURE_OPTS = ['--all-features']
+
+INPUT_SIZE_MIN = 1024
+INPUT_SIZE_MEAN = 40 * 1024
+INPUT_SIZE_MAX = 5 * INPUT_SIZE_MEAN
+
+PRINT_WATS = False
+
+
+# utilities
+
+def in_binaryen(*args):
+    return os.path.join(shared.options.binaryen_root, *args)
+
+
+def in_bin(tool):
+    return os.path.join(shared.options.binaryen_bin, tool)
+
+
+def random_size():
+    if random.random() < 0.25:
+        # sometimes do an exponential distribution, which prefers smaller sizes but may
+        # also get very high
+        ret = int(random.expovariate(1.0 / INPUT_SIZE_MEAN))
+        # if the result is valid, use it, otherwise do the normal thing
+        # (don't clamp, which would give us a lot of values on the borders)
+        if ret >= INPUT_SIZE_MIN and ret <= INPUT_SIZE_MAX:
+            return ret
+
+    # most of the time do a simple linear range around the mean
+    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_unchecked(cmd):
+    print(' '.join(cmd))
+    return subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True).communicate()[0]
+
+
+def randomize_pass_debug():
+    if random.random() < 0.1:
+        print('[pass-debug]')
+        os.environ['BINARYEN_PASS_DEBUG'] = '1'
+    else:
+        os.environ['BINARYEN_PASS_DEBUG'] = '0'
+        del os.environ['BINARYEN_PASS_DEBUG']
+    print('randomized pass debug:', os.environ.get('BINARYEN_PASS_DEBUG', ''))
+
+
+@contextlib.contextmanager
+def no_pass_debug():
+    old_env = os.environ.copy()
+    if os.environ.get('BINARYEN_PASS_DEBUG'):
+        del os.environ['BINARYEN_PASS_DEBUG']
+    try:
+        yield
+    finally:
+        os.environ.update(old_env)
+
+
+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:
+        FEATURE_OPTS += POSSIBLE_FEATURE_OPTS
+    else:
+        for possible in POSSIBLE_FEATURE_OPTS:
+            if random.random() < 0.5:
+                FEATURE_OPTS.append(possible)
+                if possible in IMPLIED_FEATURE_OPTS:
+                    FEATURE_OPTS.extend(IMPLIED_FEATURE_OPTS[possible])
+    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():
+    global FUZZ_OPTS, NANS, OOB, LEGALIZE
+    FUZZ_OPTS = []
+    if random.random() < 0.5:
+        NANS = True
+    else:
+        NANS = False
+        FUZZ_OPTS += ['--denan']
+    if random.random() < 0.5:
+        OOB = True
+    else:
+        OOB = False
+        FUZZ_OPTS += ['--no-fuzz-oob']
+    if random.random() < 0.5:
+        LEGALIZE = True
+        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).
+    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)
+
+
+# Test outputs we want to ignore are marked this way.
+IGNORE = '[binaryen-fuzzer-ignore]'
+
+# Traps are reported as [trap REASON]
+TRAP_PREFIX = '[trap '
+
+# --fuzz-exec reports calls as [fuzz-exec] calling foo
+FUZZ_EXEC_CALL_PREFIX = '[fuzz-exec] calling'
+
+
+# compare two strings, strictly
+def compare(x, y, context):
+    if x != y and x != IGNORE and y != IGNORE:
+        message = ''.join([a + '\n' for a in difflib.unified_diff(x.splitlines(), y.splitlines(), fromfile='expected', tofile='actual')])
+        raise Exception(context + " comparison error, expected to have '%s' == '%s', diff:\n\n%s" % (
+            x, y,
+            message
+        ))
+
+
+# numbers are "close enough" if they just differ in printing, as different
+# vms may print at different precision levels and verbosity
+def numbers_are_close_enough(x, y):
+    # handle nan comparisons like -nan:0x7ffff0 vs NaN, ignoring the bits
+    if 'nan' in x.lower() and 'nan' in y.lower():
+        return True
+    # float() on the strings will handle many minor differences, like
+    # float('1.0') == float('1') , float('inf') == float('Infinity'), etc.
+    try:
+        return float(x) == float(y)
+    except Exception:
+        pass
+    # otherwise, try a full eval which can handle i64s too
+    try:
+        ex = eval(x)
+        ey = eval(y)
+        return ex == ey or float(ex) == float(ey)
+    except Exception as e:
+        print('failed to check if numbers are close enough:', e)
+        return False
+
+
+# compare between vms, which may slightly change how numbers are printed
+def compare_between_vms(x, y, context):
+    x_lines = x.splitlines()
+    y_lines = y.splitlines()
+    if len(x_lines) != len(y_lines):
+        return compare(x, y, context + ' (note: different number of lines between vms)')
+
+    num_lines = len(x_lines)
+    for i in range(num_lines):
+        x_line = x_lines[i]
+        y_line = y_lines[i]
+        if x_line != y_line:
+            # this is different, but maybe it's a vm difference we can ignore
+            LEI_LOGGING = '[LoggingExternalInterface logging'
+            if x_line.startswith(LEI_LOGGING) and y_line.startswith(LEI_LOGGING):
+                x_val = x_line[len(LEI_LOGGING) + 1:-1]
+                y_val = y_line[len(LEI_LOGGING) + 1:-1]
+                if numbers_are_close_enough(x_val, y_val):
+                    continue
+            NOTE_RESULT = '[fuzz-exec] note result'
+            if x_line.startswith(NOTE_RESULT) and y_line.startswith(NOTE_RESULT):
+                x_val = x_line.split(' ')[-1]
+                y_val = y_line.split(' ')[-1]
+                if numbers_are_close_enough(x_val, y_val):
+                    continue
+
+            # this failed to compare. print a custom diff of the relevant lines
+            MARGIN = 3
+            start = max(i - MARGIN, 0)
+            end = min(i + MARGIN, num_lines)
+            return compare('\n'.join(x_lines[start:end]), '\n'.join(y_lines[start:end]), context)
+
+
+def fix_output(out):
+    # large doubles may print slightly different on different VMs
+    def fix_double(x):
+        x = x.group(1)
+        if 'nan' in x or 'NaN' in x:
+            x = 'nan'
+        else:
+            x = x.replace('Infinity', 'inf')
+            x = str(float(x))
+        return 'f64.const ' + x
+    out = re.sub(r'f64\.const (-?[nanN:abcdefxIity\d+-.]+)', fix_double, out)
+    # mark traps from wasm-opt as exceptions, even though they didn't run in a vm
+    out = out.replace(TRAP_PREFIX, 'exception: ' + TRAP_PREFIX)
+    lines = out.splitlines()
+    for i in range(len(lines)):
+        line = lines[i]
+        if 'Warning: unknown flag' in line or 'Try --help for options' in line:
+            # ignore some VM warnings that don't matter, like if a newer V8 has
+            # removed a flag that is no longer needed. but print the line so the
+            # developer can see it.
+            print(line)
+            lines[i] = None
+        elif 'exception' in line:
+            # exceptions may differ when optimizing, but an exception should
+            # occur, so ignore their types (also js engines print them out
+            # slightly differently)
+            lines[i] = '     *exception*'
+    return '\n'.join([line for line in lines if line is not None])
+
+
+def fix_spec_output(out):
+    out = fix_output(out)
+    # spec shows a pointer when it traps, remove that
+    out = '\n'.join(map(lambda x: x if 'runtime trap' not in x else x[x.find('runtime trap'):], out.splitlines()))
+    # https://github.com/WebAssembly/spec/issues/543 , float consts are messed up
+    out = '\n'.join(map(lambda x: x if 'f32' not in x and 'f64' not in x else '', out.splitlines()))
+    return out
+
+
+def run_vm(cmd):
+    # ignore some vm assertions, if bugs have already been filed
+    known_issues = [
+        'local count too large',    # ignore this; can be caused by flatten, ssa, etc. passes
+    ]
+    try:
+        return run(cmd)
+    except subprocess.CalledProcessError:
+        output = run_unchecked(cmd)
+        for issue in known_issues:
+            if issue in output:
+                return IGNORE
+        raise
+
+
+MAX_INTERPRETER_ENV_VAR = 'BINARYEN_MAX_INTERPRETER_DEPTH'
+MAX_INTERPRETER_DEPTH = 1000
+
+
+def run_bynterp(wasm, args):
+    # increase the interpreter stack depth, to test more things
+    os.environ[MAX_INTERPRETER_ENV_VAR] = str(MAX_INTERPRETER_DEPTH)
+    try:
+        return run_vm([in_bin('wasm-opt'), wasm] + FEATURE_OPTS + args)
+    finally:
+        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)
+
+
+def run_d8_wasm(wasm):
+    return run_d8_js(in_binaryen('scripts', 'fuzz_shell.js'), [wasm])
+
+
+class TestCaseHandler:
+    # how frequent this handler will be run. 1 means always run it, 0.5 means half the
+    # time
+    frequency = 1
+
+    def __init__(self):
+        self.num_runs = 0
+
+    # If the core handle_pair() method is not overridden, it calls handle() on
+    # each of the items. That is useful if you just want the two wasms and don't
+    # care about their relationship.
+    def handle_pair(self, input, before_wasm, after_wasm, opts):
+        self.handle(before_wasm)
+        self.handle(after_wasm)
+
+    def can_run_on_feature_opts(self, feature_opts):
+        return True
+
+    def increment_runs(self):
+        self.num_runs += 1
+
+    def count_runs(self):
+        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
+
+    def handle_pair(self, input, before_wasm, after_wasm, opts):
+        run([in_bin('wasm-opt'), before_wasm] + opts + ['--fuzz-exec'])
+
+
+class CompareVMs(TestCaseHandler):
+    frequency = 0.6
+
+    def __init__(self):
+        super(CompareVMs, self).__init__()
+
+        def byn_run(wasm):
+            return run_bynterp(wasm, ['--fuzz-exec-before'])
+
+        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 yes():
+            return True
+
+        def if_legal_and_no_nans():
+            return LEGALIZE and not NANS
+
+        def if_no_nans():
+            return not NANS
+
+        class Wasm2C(VM):
+            name = 'wasm2c'
+
+            def __init__(self):
+                # look for wabt in the path. if it's not here, don't run wasm2c
+                try:
+                    wabt_bin = shared.which('wasm2c')
+                    wabt_root = os.path.dirname(os.path.dirname(wabt_bin))
+                    self.wasm2c_dir = os.path.join(wabt_root, 'wasm2c')
+                    if not os.path.isdir(self.wasm2c_dir):
+                        print('wabt found, but not wasm2c support dir')
+                        self.wasm2c_dir = None
+                except Exception as e:
+                    print('warning: no wabt found:', e)
+                    self.wasm2c_dir = None
+
+            def can_run(self, wasm):
+                if self.wasm2c_dir is None:
+                    return False
+                # if we legalize for JS, the ABI is not what C wants
+                if LEGALIZE:
+                    return False
+                # relatively slow, so run it less frequently
+                if random.random() < 0.5:
+                    return False
+                # wasm2c doesn't support most features
+                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']])
+
+            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 = ['clang', 'main.c', 'wasm.c', os.path.join(self.wasm2c_dir, 'wasm-rt-impl.c'), '-I' + self.wasm2c_dir, '-lm', '-Werror']
+                run(compile_cmd)
+                return run_vm(['./a.out'])
+
+            def can_compare_to_self(self):
+                # The binaryen optimizer changes NaNs in the ways that wasm
+                # expects, but that's not quite what C has
+                return not NANS
+
+            def can_compare_to_others(self):
+                # C won't trap on OOB, and NaNs can differ from wasm VMs
+                return not OOB and not NANS
+
+        class Wasm2C2Wasm(Wasm2C):
+            name = 'wasm2c2wasm'
+
+            def __init__(self):
+                super(Wasm2C2Wasm, self).__init__()
+
+                self.has_emcc = shared.which('emcc') is not None
+
+            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']
+                # disable the signal handler: emcc looks like unix, but wasm has
+                # no signals
+                compile_cmd += ['-DWASM_RT_MEMCHECK_SIGNAL_HANDLER=0']
+                if random.random() < 0.5:
+                    compile_cmd += ['-O' + str(random.randint(1, 3))]
+                elif random.random() < 0.5:
+                    if random.random() < 0.5:
+                        compile_cmd += ['-Os']
+                    else:
+                        compile_cmd += ['-Oz']
+                # avoid pass-debug on the emcc invocation itself (which runs
+                # binaryen to optimize the wasm), as the wasm here can be very
+                # large and it isn't what we are focused on testing here
+                with no_pass_debug():
+                    run(compile_cmd)
+                return run_d8_js('a.out.js')
+
+            def can_run(self, wasm):
+                # quite slow (more steps), so run it less frequently
+                if random.random() < 0.8:
+                    return False
+                # prefer not to run if the wasm is very large, as it can OOM
+                # the JS engine.
+                return super(Wasm2C2Wasm, self).can_run(wasm) and self.has_emcc and \
+                    os.path.getsize(wasm) <= INPUT_SIZE_MEAN
+
+            def can_compare_to_others(self):
+                # 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(),
+        ]
+
+    def handle_pair(self, input, before_wasm, after_wasm, opts):
+        before = self.run_vms(before_wasm)
+        after = self.run_vms(after_wasm)
+        self.compare_before_and_after(before, after)
+
+    def run_vms(self, wasm):
+        # vm_results will map vms to their results
+        vm_results = {}
+        for vm in self.vms:
+            if vm.can_run(wasm):
+                vm_results[vm] = fix_output(vm.run(wasm))
+
+        # compare between the vms on this specific input
+
+        first_vm = None
+        for vm in vm_results.keys():
+            if vm.can_compare_to_others():
+                if first_vm is None:
+                    first_vm = vm
+                else:
+                    compare_between_vms(vm_results[first_vm], vm_results[vm], 'CompareVMs between VMs: ' + first_vm.name + ' and ' + vm.name)
+
+        return vm_results
+
+    def compare_before_and_after(self, before, after):
+        # compare each VM to itself on the before and after inputs
+        for vm in before.keys():
+            if vm in after and vm.can_compare_to_self():
+                compare(before[vm], after[vm], 'CompareVMs between before and after: ' + vm.name)
+
+    def can_run_on_feature_opts(self, feature_opts):
+        return all([x in feature_opts for x in ['--disable-simd', '--disable-reference-types', '--disable-exception-handling', '--disable-multivalue', '--disable-gc']])
+
+
+# Check for determinism - the same command must have the same output.
+class CheckDeterminism(TestCaseHandler):
+    # not that important
+    frequency = 0.1
+
+    def handle_pair(self, input, before_wasm, after_wasm, opts):
+        # check for determinism
+        run([in_bin('wasm-opt'), before_wasm, '-o', 'b1.wasm'] + opts)
+        run([in_bin('wasm-opt'), before_wasm, '-o', 'b2.wasm'] + opts)
+        assert open('b1.wasm', 'rb').read() == open('b2.wasm', 'rb').read(), 'output must be deterministic'
+
+
+class Wasm2JS(TestCaseHandler):
+    frequency = 0.6
+
+    def handle_pair(self, input, before_wasm, after_wasm, opts):
+        before_wasm_temp = before_wasm + '.temp.wasm'
+        after_wasm_temp = after_wasm + '.temp.wasm'
+        # legalize the before wasm, so that comparisons to the interpreter
+        # later make sense (if we don't do this, the wasm may have i64 exports).
+        # after applying other necessary fixes, we'll recreate the after wasm
+        # from scratch.
+        run([in_bin('wasm-opt'), before_wasm, '--legalize-js-interface', '-o', before_wasm_temp] + FEATURE_OPTS)
+        compare_before_to_after = random.random() < 0.5
+        compare_to_interpreter = compare_before_to_after and random.random() < 0.5
+        if compare_before_to_after:
+            # to compare the wasm before and after optimizations, we must
+            # remove operations that wasm2js does not support with full
+            # precision, such as i64-to-f32, as the optimizer can give different
+            # results.
+            simplification_passes = ['--stub-unsupported-js']
+            if compare_to_interpreter:
+                # unexpectedly-unaligned loads/stores work fine in wasm in general but
+                # not in wasm2js, since typed arrays silently round down, effectively.
+                # if we want to compare to the interpreter, remove unaligned
+                # operations (by forcing alignment 1, then lowering those into aligned
+                # components, which means all loads and stores are of a single byte).
+                simplification_passes += ['--dealign', '--alignment-lowering']
+            run([in_bin('wasm-opt'), before_wasm_temp, '-o', before_wasm_temp] + simplification_passes + FEATURE_OPTS)
+        # now that the before wasm is fixed up, generate a proper after wasm
+        run([in_bin('wasm-opt'), before_wasm_temp, '-o', after_wasm_temp] + opts + FEATURE_OPTS)
+        # always check for compiler crashes
+        before = self.run(before_wasm_temp)
+        after = self.run(after_wasm_temp)
+        if NANS:
+            # with NaNs we can't compare the output, as a reinterpret through
+            # memory might end up different in JS than wasm
+            return
+        # we also cannot compare if the wasm hits a trap, as wasm2js does not
+        # trap on many things wasm would, and in those cases it can do weird
+        # undefined things. in such a case, at least compare up until before
+        # the trap, which lets us compare at least some results in some cases.
+        # (this is why wasm2js is not in CompareVMs, which does full
+        # comparisons - we need to limit the comparison in a special way here)
+        interpreter = run([in_bin('wasm-opt'), before_wasm_temp, '--fuzz-exec-before'])
+        if TRAP_PREFIX in interpreter:
+            trap_index = interpreter.index(TRAP_PREFIX)
+            # we can't test this function, which the trap is in the middle of.
+            # erase everything from this function's output and onward, so we
+            # only compare the previous trap-free code
+            call_start = interpreter.rindex(FUZZ_EXEC_CALL_PREFIX, 0, trap_index)
+            call_end = interpreter.index('\n', call_start)
+            call_line = interpreter[call_start:call_end]
+            before = before[:before.index(call_line)]
+            after = after[:after.index(call_line)]
+            interpreter = interpreter[:interpreter.index(call_line)]
+
+        def fix_output_for_js(x):
+            # start with the normal output fixes that all VMs need
+            x = fix_output(x)
+
+            # check if a number is 0 or a subnormal, which is basically zero
+            def is_basically_zero(x):
+                # to check if something is a subnormal, compare it to the largest one
+                return x >= 0 and x <= 2.22507385850720088902e-308
+
+            def fix_number(x):
+                x = x.group(1)
+                try:
+                    x = float(x)
+                    # There appear to be some cases where JS VMs will print
+                    # subnormals in full detail while other VMs do not, and vice
+                    # versa. Ignore such really tiny numbers.
+                    if is_basically_zero(x):
+                        x = 0
+                except ValueError:
+                    # not a floating-point number, nothing to do
+                    pass
+                return ' => ' + str(x)
+
+            # logging notation is "function_name => result", look for that with
+            # a floating-point result that may need to be fixed up
+            return re.sub(r' => (-?[\d+-.e\-+]+)', fix_number, x)
+
+        before = fix_output_for_js(before)
+        after = fix_output_for_js(after)
+        if compare_before_to_after:
+            compare_between_vms(before, after, 'Wasm2JS (before/after)')
+            if compare_to_interpreter:
+                interpreter = fix_output_for_js(interpreter)
+                compare_between_vms(before, interpreter, 'Wasm2JS (vs interpreter)')
+
+    def run(self, wasm):
+        wrapper = run([in_bin('wasm-opt'), wasm, '--emit-js-wrapper=/dev/stdout'] + FEATURE_OPTS)
+        cmd = [in_bin('wasm2js'), wasm, '--emscripten']
+        # avoid optimizations if we have nans, as we don't handle them with
+        # full precision and optimizations can change things
+        # OOB accesses are also an issue with optimizations, that can turn the
+        # loaded "undefined" into either 0 (with an |0) or stay undefined
+        # in optimized code.
+        if not NANS and not OOB and random.random() < 0.5:
+            # when optimizing also enable deterministic mode, to avoid things
+            # like integer divide by zero causing false positives (1 / 0 is
+            # Infinity without a  | 0 , and 0 with one, and the truthiness of
+            # those differs; we don't want to care about this because it
+            # would trap in wasm anyhow)
+            cmd += ['-O', '--deterministic']
+        main = run(cmd + FEATURE_OPTS)
+        with open(os.path.join(shared.options.binaryen_root, 'scripts', 'wasm2js.js')) as f:
+            glue = f.read()
+        js_file = wasm + '.js'
+        with open(js_file, 'w') as f:
+            f.write(glue)
+            f.write(main)
+            f.write(wrapper)
+        return run_vm([shared.NODEJS, js_file, 'a.wasm'])
+
+    def can_run_on_feature_opts(self, feature_opts):
+        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']])
+
+
+class Asyncify(TestCaseHandler):
+    frequency = 0.6
+
+    def handle_pair(self, input, before_wasm, after_wasm, opts):
+        # we must legalize in order to run in JS
+        run([in_bin('wasm-opt'), before_wasm, '--legalize-js-interface', '-o', 'async.' + before_wasm] + FEATURE_OPTS)
+        run([in_bin('wasm-opt'), after_wasm, '--legalize-js-interface', '-o', 'async.' + after_wasm] + FEATURE_OPTS)
+        before_wasm = 'async.' + before_wasm
+        after_wasm = 'async.' + after_wasm
+        before = fix_output(run_d8_wasm(before_wasm))
+        after = fix_output(run_d8_wasm(after_wasm))
+
+        try:
+            compare(before, after, 'Asyncify (before/after)')
+        except Exception:
+            # if we failed to just compare the builds before asyncify even runs,
+            # then it may use NaNs or be sensitive to legalization; ignore it
+            print('ignoring due to pre-asyncify difference')
+            return
+
+        def do_asyncify(wasm):
+            cmd = [in_bin('wasm-opt'), wasm, '--asyncify', '-o', 'async.t.wasm']
+            # if we allow NaNs, running binaryen optimizations and then
+            # executing in d8 may lead to different results due to NaN
+            # nondeterminism between VMs.
+            if not NANS:
+                if random.random() < 0.5:
+                    cmd += ['--optimize-level=%d' % random.randint(1, 3)]
+                if random.random() < 0.5:
+                    cmd += ['--shrink-level=%d' % random.randint(1, 2)]
+            cmd += FEATURE_OPTS
+            run(cmd)
+            out = run_d8_wasm('async.t.wasm')
+            # ignore the output from the new asyncify API calls - the ones with asserts will trap, too
+            for ignore in ['[fuzz-exec] calling asyncify_start_unwind\nexception!\n',
+                           '[fuzz-exec] calling asyncify_start_unwind\n',
+                           '[fuzz-exec] calling asyncify_start_rewind\nexception!\n',
+                           '[fuzz-exec] calling asyncify_start_rewind\n',
+                           '[fuzz-exec] calling asyncify_stop_rewind\n',
+                           '[fuzz-exec] calling asyncify_stop_unwind\n']:
+                out = out.replace(ignore, '')
+            out = '\n'.join([l for l in out.splitlines() if 'asyncify: ' not in l])
+            return fix_output(out)
+
+        before_asyncify = do_asyncify(before_wasm)
+        after_asyncify = do_asyncify(after_wasm)
+
+        compare(before, before_asyncify, 'Asyncify (before/before_asyncify)')
+        compare(before, after_asyncify, 'Asyncify (before/after_asyncify)')
+
+    def can_run_on_feature_opts(self, feature_opts):
+        return all([x in feature_opts for x in ['--disable-exception-handling', '--disable-simd', '--disable-tail-call', '--disable-reference-types', '--disable-multivalue', '--disable-gc']])
+
+
+# The global list of all test case handlers
+testcase_handlers = [
+    FuzzExec(),
+    CompareVMs(),
+    CheckDeterminism(),
+    Wasm2JS(),
+    Asyncify(),
+]
+
+
+# Do one test, given an input file for -ttf and some optimizations to run
+def test_one(random_input, opts, given_wasm):
+    randomize_pass_debug()
+    randomize_feature_opts()
+    randomize_fuzz_settings()
+    print()
+
+    if given_wasm:
+        # if given a wasm file we want to use it as is, but we also want to
+        # apply properties like not having any NaNs, which the original fuzz
+        # wasm had applied. that is, we need to preserve properties like not
+        # having nans through reduction.
+        run([in_bin('wasm-opt'), given_wasm, '-o', 'a.wasm'] + FUZZ_OPTS + FEATURE_OPTS)
+    else:
+        # 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 PRINT_WATS:
+            printed = run(generate_command + ['--print'])
+            with open('a.printed.wast', 'w') as f:
+                f.write(printed)
+        else:
+            run(generate_command)
+    wasm_size = os.stat('a.wasm').st_size
+    bytes = wasm_size
+    print('pre wasm size:', wasm_size)
+
+    # create a second wasm for handlers that want to look at pairs.
+    generate_command = [in_bin('wasm-opt'), 'a.wasm', '-o', 'b.wasm'] + opts + FUZZ_OPTS + FEATURE_OPTS
+    if PRINT_WATS:
+        printed = run(generate_command + ['--print'])
+        with open('b.printed.wast', 'w') as f:
+            f.write(printed)
+    else:
+        run(generate_command)
+    wasm_size = os.stat('b.wasm').st_size
+    bytes += wasm_size
+    print('post wasm size:', wasm_size)
+
+    # first, find which handlers can even run here
+    relevant_handlers = [handler for handler in testcase_handlers if not hasattr(handler, 'get_commands') and handler.can_run_on_feature_opts(FEATURE_OPTS)]
+    if len(relevant_handlers) == 0:
+        return 0
+    # filter by frequency
+    filtered_handlers = [handler for handler in relevant_handlers if random.random() < handler.frequency]
+    if len(filtered_handlers) == 0:
+        # pick at least one, to not waste the effort we put into making the wasm
+        filtered_handlers = [random.choice(relevant_handlers)]
+    # run only some of the pair handling handlers. if we ran them all all the
+    # time that would mean we have less variety in wasm files and passes run
+    # on them in the same amount of time.
+    NUM_PAIR_HANDLERS = 3
+    used_handlers = set()
+    for i in range(NUM_PAIR_HANDLERS):
+        testcase_handler = random.choice(filtered_handlers)
+        if testcase_handler in used_handlers:
+            continue
+        used_handlers.add(testcase_handler)
+        assert testcase_handler.can_run_on_feature_opts(FEATURE_OPTS)
+        print('running testcase handler:', testcase_handler.__class__.__name__)
+        testcase_handler.increment_runs()
+
+        # let the testcase handler handle this testcase however it wants. in this case we give it
+        # the input and both wasms.
+        testcase_handler.handle_pair(input=random_input, before_wasm='a.wasm', after_wasm='b.wasm', opts=opts + FEATURE_OPTS)
+        print('')
+
+    return bytes
+
+
+def write_commands(commands, filename):
+    with open(filename, 'w') as f:
+        f.write('set -e\n')
+        for command in commands:
+            f.write('echo "%s"\n' % command)
+            pre = 'BINARYEN_PASS_DEBUG=%s ' % (os.environ.get('BINARYEN_PASS_DEBUG') or '0')
+            f.write(pre + command + ' &> /dev/null\n')
+        f.write('echo "ok"\n')
+
+
+# main
+
+opt_choices = [
+    [],
+    ['-O1'], ['-O2'], ['-O3'], ['-O4'], ['-Os'], ['-Oz'],
+    ["--coalesce-locals"],
+    # XXX slow, non-default ["--coalesce-locals-learning"],
+    ["--code-pushing"],
+    ["--code-folding"],
+    ["--const-hoisting"],
+    ["--dae"],
+    ["--dae-optimizing"],
+    ["--dce"],
+    ["--directize"],
+    ["--flatten", "--dfo"],
+    ["--duplicate-function-elimination"],
+    ["--flatten"],
+    # ["--fpcast-emu"], # removes indirect call failures as it makes them go through regardless of type
+    ["--inlining"],
+    ["--inlining-optimizing"],
+    ["--flatten", "--local-cse"],
+    ["--generate-stack-ir"],
+    ["--licm"],
+    ["--memory-packing"],
+    ["--merge-blocks"],
+    ['--merge-locals'],
+    ["--optimize-instructions"],
+    ["--optimize-stack-ir"],
+    ["--generate-stack-ir", "--optimize-stack-ir"],
+    ["--pick-load-signs"],
+    ["--precompute"],
+    ["--precompute-propagate"],
+    ["--print"],
+    ["--remove-unused-brs"],
+    ["--remove-unused-nonfunction-module-elements"],
+    ["--remove-unused-module-elements"],
+    ["--remove-unused-names"],
+    ["--reorder-functions"],
+    ["--reorder-locals"],
+    ["--flatten", "--rereloop"],
+    ["--roundtrip"],
+    ["--rse"],
+    ["--simplify-locals"],
+    ["--simplify-locals-nonesting"],
+    ["--simplify-locals-nostructure"],
+    ["--simplify-locals-notee"],
+    ["--simplify-locals-notee-nostructure"],
+    ["--ssa"],
+    ["--vacuum"],
+]
+
+
+def randomize_opt_flags():
+    flag_groups = []
+    has_flatten = False
+    # core opts
+    while 1:
+        choice = random.choice(opt_choices)
+        if '--flatten' in choice:
+            if has_flatten:
+                print('avoiding multiple --flatten in a single command, due to exponential overhead')
+                continue
+            else:
+                has_flatten = True
+        flag_groups.append(choice)
+        if len(flag_groups) > 20 or random.random() < 0.3:
+            break
+    # maybe add an extra round trip
+    if random.random() < 0.5:
+        pos = random.randint(0, len(flag_groups))
+        flag_groups = flag_groups[:pos] + [['--roundtrip']] + flag_groups[pos:]
+    ret = [flag for group in flag_groups for flag in group]
+    # modifiers (if not already implied by a -O? option)
+    if '-O' not in str(ret):
+        if random.random() < 0.5:
+            ret += ['--optimize-level=' + str(random.randint(0, 3))]
+        if random.random() < 0.5:
+            ret += ['--shrink-level=' + str(random.randint(0, 3))]
+    assert ret.count('--flatten') <= 1
+    return ret
+
+
+# main
+
+# possible feature options that are sometimes passed to the tools. this
+# contains the list of all possible feature flags we can disable (after
+# we enable all before that in the constant options)
+POSSIBLE_FEATURE_OPTS = run([in_bin('wasm-opt'), '--print-features', in_binaryen('test', 'hello_world.wat')] + CONSTANT_FEATURE_OPTS).replace('--enable', '--disable').strip().split('\n')
+print('POSSIBLE_FEATURE_OPTS:', POSSIBLE_FEATURE_OPTS)
+
+# some features depend on other features, so if a required feature is
+# disabled, its dependent features need to be disabled as well.
+IMPLIED_FEATURE_OPTS = {
+    '--disable-reference-types': ['--disable-exception-handling', '--disable-gc']
+}
+
+if __name__ == '__main__':
+    # if we are given a seed, run exactly that one testcase. otherwise,
+    # run new ones until we fail
+    # if we are given a seed, we can also be given a wasm file, which we use
+    # instead of the randomly generating one. this can be useful for
+    # reduction.
+    given_wasm = None
+    if len(shared.requested) >= 1:
+        given_seed = int(shared.requested[0])
+        print('checking a single given seed', given_seed)
+        if len(shared.requested) >= 2:
+            given_wasm = shared.requested[1]
+            print('using given wasm file', given_wasm)
+    else:
+        given_seed = None
+        print('checking infinite random inputs')
+    seed = time.time() * os.getpid()
+    raw_input_data = 'input.dat'
+    counter = 0
+    total_wasm_size = 0
+    total_input_size = 0
+    total_input_size_squares = 0
+    start_time = time.time()
+    while True:
+        counter += 1
+        if given_seed is not None:
+            seed = given_seed
+            given_seed_passed = True
+        else:
+            seed = random.randint(0, 1 << 64)
+        random.seed(seed)
+        input_size = random_size()
+        total_input_size += input_size
+        total_input_size_squares += input_size ** 2
+        print('')
+        mean = float(total_input_size) / counter
+        mean_of_squares = float(total_input_size_squares) / counter
+        stddev = math.sqrt(mean_of_squares - (mean ** 2))
+        elapsed = max(0.000001, time.time() - start_time)
+        print('ITERATION:', counter, 'seed:', seed, 'size:', input_size,
+              '(mean:', str(mean) + ', stddev:', str(stddev) + ')',
+              'speed:', counter / elapsed,
+              'iters/sec, ', total_wasm_size / elapsed,
+              'wasm_bytes/sec\n')
+        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))
+        try:
+            total_wasm_size += test_one(raw_input_data, opts, given_wasm)
+        except KeyboardInterrupt:
+            print('(stopping by user request)')
+            break
+        except Exception as e:
+            # print the exception manually, so that we can show our message at
+            # the very end where it won't be missed
+            ex_type, ex, tb = sys.exc_info()
+            print('!')
+            print('-----------------------------------------')
+            print('Exception:')
+            traceback.print_tb(tb)
+            print('-----------------------------------------')
+            print('!')
+            for arg in e.args:
+                print(arg)
+            if given_seed is not None:
+                given_seed_passed = False
+
+            # We want to generate a template reducer script only when there is
+            # no given wasm file. That we have a given wasm file means we are no
+            # longer working on the original test case but modified one, which
+            # is likely to be called within wasm-reduce script itself, so
+            # original.wasm and reduce.sh should not be overwritten.
+            if not given_wasm:
+                # 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"
+                # which we use internally)
+                original_wasm = os.path.abspath('original.wasm')
+                shutil.copyfile('a.wasm', original_wasm)
+                # write out a useful reduce.sh
+                with open('reduce.sh', 'w') as reduce_sh:
+                    reduce_sh.write('''\
+# check the input is even a valid wasm file
+%(wasm_opt)s --detect-features %(temp_wasm)s
+echo "should be 0:" $?
+
+# run the command
+./scripts/fuzz_opt.py --binaryen-bin %(bin)s %(seed)d %(temp_wasm)s > o 2> e
+echo "should be 1:" $?
+
+#
+# You may want to print out part of "o" or "e", if the output matters and not
+# just the return code. For example,
+#
+#   cat o | tail -n 10
+#
+# would print out the last few lines of stdout, which might be useful if that
+# mentions the specific error you want. Make sure that includes the right
+# details (sometimes stderr matters too), and preferably no more (less details
+# allow more reduction, but raise the risk of it reducing to something you don't
+# quite want).
+#
+# To do a "dry run" of what the reducer will do, copy the original file to the
+# test file that this script will run on,
+#
+#   cp %(original_wasm)s %(temp_wasm)s
+#
+# and then run
+#
+#   bash %(reduce_sh)s
+#
+# You may also need to add  --timeout 5  or such if the testcase is a slow one.
+#
+                  ''' % {'wasm_opt': in_bin('wasm-opt'),
+                         'bin': shared.options.binaryen_bin,
+                         'seed': seed,
+                         'original_wasm': original_wasm,
+                         'temp_wasm': os.path.abspath('t.wasm'),
+                         'reduce_sh': os.path.abspath('reduce.sh')})
+
+                print('''\
+================================================================================
+You found a bug! 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"
+
+The initial wasm file used here is saved as %(original_wasm)s
+
+You can reduce the testcase by running this now:
+
+||||
+vvvv
+
+
+%(wasm_reduce)s %(original_wasm)s '--command=bash %(reduce_sh)s' -t %(temp_wasm)s -w %(working_wasm)s
+
+
+^^^^
+||||
+
+Make sure to verify by eye that the output says
+
+should be 0: 0
+should be 1: 1
+
+You can also read "%(reduce_sh)s" which has been filled out for you and includes
+docs and suggestions.
+
+After reduction, the reduced file will be in %(working_wasm)s
+================================================================================
+                ''' % {'seed': seed,
+                       'original_wasm': original_wasm,
+                       'temp_wasm': os.path.abspath('t.wasm'),
+                       'working_wasm': os.path.abspath('w.wasm'),
+                       'wasm_reduce': in_bin('wasm-reduce'),
+                       'reduce_sh': os.path.abspath('reduce.sh')})
+                break
+        if given_seed is not None:
+            break
+
+        print('\nInvocations so far:')
+        for testcase_handler in testcase_handlers:
+            print('  ', testcase_handler.__class__.__name__ + ':', testcase_handler.count_runs())
+
+    if given_seed is not None:
+        if given_seed_passed:
+            print('(finished running seed %d without error)' % given_seed)
+            sys.exit(0)
+        else:
+            print('(finished running seed %d, see error above)' % given_seed)
+            sys.exit(1)
diff --git a/binaryen/scripts/fuzz_passes.py b/binaryen/scripts/fuzz_passes.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/fuzz_passes.py
@@ -0,0 +1,147 @@
+#!/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.
+
+'''
+This fuzzes passes, by starting with a working program, then running
+random passes on the wast, and seeing if they break something
+
+Usage: Provide a base filename for a runnable program, e.g. a.out.js.
+       Then we will modify a.out.wast. Note that the program must
+       be built to run using that wast (BINARYEN_METHOD=interpret-s-expr)
+
+       Other parameters after the first are used when calling the program.
+'''
+
+from __future__ import print_function
+
+import os
+import random
+import shutil
+import subprocess
+import sys
+
+PASSES = [
+    "duplicate-function-elimination",
+    "dce",
+    "remove-unused-brs",
+    "remove-unused-names",
+    "optimize-instructions",
+    "precompute",
+    "simplify-locals",
+    "vacuum",
+    "coalesce-locals",
+    "reorder-locals",
+    "merge-blocks",
+    "remove-unused-functions",
+]
+
+# main
+
+base = sys.argv[1]
+wast = base[:-3] + '.wast'
+print('>>> base program:', base, ', wast:', wast)
+
+args = sys.argv[2:]
+
+
+def run():
+    if os.path.exists(wast):
+        print('>>> running using a wast of size', os.stat(wast).st_size)
+    cmd = ['mozjs', base] + args
+    try:
+        return subprocess.check_output(cmd, stderr=subprocess.STDOUT)
+    except Exception as e:
+        print(">>> !!! ", e, " !!!")
+
+
+original_wast = None
+
+try:
+    # get normal output
+
+    normal = run()
+    print('>>> normal output:\n', normal)
+    assert normal, 'must be output'
+
+    # ensure we actually use the wast
+
+    original_wast = wast + '.original.wast'
+    shutil.move(wast, original_wast)
+    assert run() != normal, 'running without the wast must fail'
+
+    # ensure a bad pass makes it fail
+
+    def apply_passes(passes):
+        wasm_opt = os.path.join('bin', 'wasm-opt')
+        subprocess.check_call([wasm_opt, original_wast] + passes + ['-o', wast])
+
+    apply_passes(['--remove-imports'])
+    assert run() != normal, 'running after a breaking pass must fail'
+
+    # loop, looking for failures
+
+    def simplify(passes):
+        # passes is known to fail, try to simplify down by removing
+        more = True
+        while more:
+            more = False
+            print('>>> trying to reduce:', ' '.join(passes), '  [' + str(len(passes)) + ']')
+            for i in range(len(passes)):
+                smaller = passes[:i] + passes[i + 1:]
+                print('>>>>>> try to reduce to:', ' '.join(smaller), '  [' + str(len(smaller)) + ']')
+                try:
+                    apply_passes(smaller)
+                    assert run() == normal
+                except Exception:
+                    # this failed too, so it's a good reduction
+                    passes = smaller
+                    print('>>> reduction successful')
+                    more = True
+                    break
+        print('>>> reduced to:', ' '.join(passes))
+
+    tested = set()
+
+    def pick_passes():
+        ret = []
+        while 1:
+            str_ret = str(ret)
+            if random.random() < 0.1 and str_ret not in tested:
+                tested.add(str_ret)
+                return ret
+            ret.append('--' + random.choice(PASSES))
+
+    counter = 0
+
+    while 1:
+        passes = pick_passes()
+        print('>>> [' + str(counter) + '] testing:', ' '.join(passes))
+        counter += 1
+        try:
+            apply_passes(passes)
+        except Exception as e:
+            print(e)
+            simplify(passes)
+            break
+        seen = run()
+        if seen != normal:
+            print('>>> bad output:\n', seen)
+            simplify(passes)
+            break
+
+finally:
+    if original_wast:
+        shutil.move(original_wast, wast)
diff --git a/binaryen/scripts/fuzz_passes_wast.py b/binaryen/scripts/fuzz_passes_wast.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/fuzz_passes_wast.py
@@ -0,0 +1,139 @@
+#!/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.
+
+'''
+This fuzzes passes, by starting with a wast, then running
+random passes on the wast, and seeing if they break optimization
+or validation
+
+Usage: Provide the filename of the wast.
+'''
+
+from __future__ import print_function
+
+import os
+import random
+import shutil
+import subprocess
+import sys
+
+PASSES = [
+    "duplicate-function-elimination",
+    "dce",
+    "remove-unused-brs",
+    "remove-unused-names",
+    "optimize-instructions",
+    "precompute",
+    "simplify-locals",
+    "vacuum",
+    "coalesce-locals",
+    "reorder-locals",
+    "merge-blocks",
+    "remove-unused-functions",
+]
+
+# main
+
+wast = sys.argv[1]
+print('>>> wast:', wast)
+
+args = sys.argv[2:]
+
+
+def run():
+    try:
+        cmd = ['bin/wasm-opt', wast]
+        print('run', cmd)
+        subprocess.check_call(cmd, stderr=open('/dev/null'))
+    except Exception as e:
+        return ">>> !!! ", e, " !!!"
+    return 'ok'
+
+
+original_wast = None
+
+try:
+    # get normal output
+
+    normal = run()
+    print('>>> normal output:\n', normal)
+    assert normal, 'must be output'
+
+    # ensure we actually use the wast
+
+    original_wast = wast + '.original.wast'
+    shutil.move(wast, original_wast)
+
+    def apply_passes(passes):
+        wasm_opt = os.path.join('bin', 'wasm-opt')
+        subprocess.check_call([wasm_opt, original_wast] + passes + ['-o', wast],
+                              stderr=open('/dev/null'))
+
+    # loop, looking for failures
+
+    def simplify(passes):
+        # passes is known to fail, try to simplify down by removing
+        more = True
+        while more:
+            more = False
+            print('>>> trying to reduce:', ' '.join(passes), '  [' + str(len(passes)) + ']')
+            for i in range(len(passes)):
+                smaller = passes[:i] + passes[i + 1:]
+                print('>>>>>> try to reduce to:', ' '.join(smaller), '  [' + str(len(smaller)) + ']')
+                try:
+                    apply_passes(smaller)
+                    assert run() == normal
+                except Exception:
+                    # this failed too, so it's a good reduction
+                    passes = smaller
+                    print('>>> reduction successful')
+                    more = True
+                    break
+        print('>>> reduced to:', ' '.join(passes))
+
+    tested = set()
+
+    def pick_passes():
+        # return '--waka'.split(' ')
+        ret = []
+        while 1:
+            str_ret = str(ret)
+            if random.random() < 0.5 and str_ret not in tested:
+                tested.add(str_ret)
+                return ret
+            ret.append('--' + random.choice(PASSES))
+
+    counter = 0
+
+    while 1:
+        passes = pick_passes()
+        print('>>> [' + str(counter) + '] testing:', ' '.join(passes))
+        counter += 1
+        try:
+            apply_passes(passes)
+        except Exception as e:
+            print(e)
+            simplify(passes)
+            break
+        seen = run()
+        if seen != normal:
+            print('>>> bad output:\n', seen)
+            simplify(passes)
+            break
+
+finally:
+    if original_wast:
+        shutil.move(original_wast, wast)
diff --git a/binaryen/scripts/fuzz_relooper.py b/binaryen/scripts/fuzz_relooper.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/fuzz_relooper.py
@@ -0,0 +1,389 @@
+#!/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.
+
+'''
+This fuzzes the relooper using the C API.
+'''
+
+from __future__ import print_function
+
+import difflib
+import os
+import random
+import subprocess
+import time
+
+seed_init = int(time.time())
+seed_init *= seed_init
+seed_init %= (2**32)
+
+if os.environ.get('LD_LIBRARY_PATH'):
+    os.environ['LD_LIBRARY_PATH'] += os.pathsep + 'lib'
+else:
+    os.environ['LD_LIBRARY_PATH'] = 'lib'
+
+counter = 0
+
+while True:
+    # Random decisions
+    seed = seed_init
+    random.seed(seed)
+    seed_init += 1
+    num = random.randint(2, 250)
+    density = random.random() * random.random()
+    code_likelihood = random.random()
+    code_max = random.randint(0, num if random.random() < 0.5 else 3)
+    max_printed = random.randint(1, num if random.random() < 0.5 else 3)
+    max_decision = num * 20
+    decisions = [random.randint(1, max_decision) for x in range(num * 3)]
+    branches = [0] * num
+    defaults = [0] * num
+    branch_codes = [0] * num  # code on the branch, which may alter the global state
+
+    # with some probability print the same id for different blocks,
+    # as the printing is the block contents - allow merging etc. opts
+    def printed_id(i):
+        if random.random() < 0.5:
+            return i
+        return i % max_printed
+
+    printed_ids = [printed_id(i) for i in range(num)]
+
+    def random_code():
+        if code_max == 0 or random.random() > code_likelihood:
+            return 0    # no code
+        # A random number to perturb/increment the global state
+        return random.randint(1, code_max)
+
+    for i in range(num):
+        b = set([])
+        bs = random.randint(1, max(1,
+                            round(density * random.random() * (num - 1))))
+        for j in range(bs):
+            b.add(random.randint(1, num - 1))
+        b = list(b)
+        defaults[i] = random.choice(b)
+        b.remove(defaults[i])
+        branches[i] = b
+        branch_codes[i] = [random_code() for item in range(len(b) + 1)]  # one for each branch, plus the default
+    optimize = random.random() < 0.5
+    print(counter, ':', num, density, optimize, code_likelihood, code_max, max_printed, ', seed =', seed)
+    counter += 1
+
+    for temp in ['fuzz.wasm', 'fuzz.wast', 'fast.txt', 'fuzz.slow.js',
+                 'fuzz.c']:
+        try:
+            os.unlink(temp)
+        except OSError:
+            pass
+
+    # parts
+    entry = '''
+var label = 0;
+var state;
+var decisions = %s;
+var index = 0;
+function check() {
+  if (index >= decisions.length) throw 'HALT';
+  console.log('(i32.const ' + (-decisions[index]) + ')');
+  return decisions[index++];
+}
+''' % str(decisions)
+
+    slow = entry + '\n'
+    slow += 'label = 0;\n'
+
+    slow += '''
+while(1) switch(label) {
+'''
+
+    fast = '''
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "binaryen-c.h"
+
+// globals: address 4 is index
+// decisions are at address 8+
+
+int main() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+
+  // check()
+
+  // if the end, halt
+  BinaryenExpressionRef halter = BinaryenIf(module,
+    BinaryenBinary(module,
+      BinaryenGeUInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4 * %d)) // jumps of 4 bytes
+    ),
+    BinaryenUnreachable(module),
+    NULL
+  );
+  // increment index
+  BinaryenExpressionRef incer = BinaryenStore(module,
+    4, 0, 0,
+    BinaryenConst(module, BinaryenLiteralInt32(4)),
+    BinaryenBinary(module,
+      BinaryenAddInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4))
+    ),
+    BinaryenTypeInt32()
+  );
+
+  // optionally, print the return value
+  BinaryenExpressionRef args[] = {
+    BinaryenBinary(module,
+      BinaryenSubInt32(),
+      BinaryenConst(module, BinaryenLiteralInt32(0)),
+      BinaryenLoad(module,
+        4, 0, 4, 0, BinaryenTypeInt32(),
+        BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4)))
+      )
+    )
+  };
+  BinaryenExpressionRef debugger;
+  if (1) debugger = BinaryenCall(module, "print", args, 1,
+                                 BinaryenTypeNone());
+  else debugger = BinaryenNop(module);
+
+  // return the decision. need to subtract 4 that we just added,
+  // and add 8 since that's where we start, so overall offset 4
+  BinaryenExpressionRef returner = BinaryenLoad(module,
+    4, 0, 4, 0, BinaryenTypeInt32(),
+    BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+    BinaryenConst(module, BinaryenLiteralInt32(4)))
+  );
+  BinaryenExpressionRef checkBodyList[] = { halter, incer, debugger,
+                                            returner };
+  BinaryenExpressionRef checkBody = BinaryenBlock(module,
+    NULL, checkBodyList, sizeof(checkBodyList) / sizeof(BinaryenExpressionRef),
+    BinaryenTypeInt32()
+  );
+  BinaryenFunctionTypeRef i = BinaryenAddFunctionType(module, "i",
+                                                      BinaryenTypeInt32(),
+                                                      NULL, 0);
+  BinaryenAddFunction(module, "check", i, NULL, 0, checkBody);
+
+  // contents of main() begin here
+
+  RelooperRef relooper = RelooperCreate(module);
+
+''' % len(decisions)
+
+    for i in range(num):
+        slow += '  case %d: console.log("(i32.const %d)"); state = check(); \n' % (
+            i, printed_ids[i])
+        b = branches[i]
+        bc = branch_codes[i]
+
+        def get_phi(j):
+            phi = ''
+            if bc[j]:
+                phi = 'index += %d; ' % bc[j]
+            return phi
+
+        for j in range(len(b)):
+            slow += '    if (state %% %d == %d) { %s label = %d; break }\n' % (
+                len(b) + 1, j, get_phi(j), b[j])    # TODO: split range 1-n into these options
+        slow += '    %slabel = %d; break\n' % (get_phi(-1), defaults[i])
+
+    use_switch = [random.random() < 0.5 for i in range(num)]
+
+    for i in range(num):
+        fast += '''
+  RelooperBlockRef b%d;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(%d))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+''' % (i, printed_ids[i])
+        if use_switch[i]:
+            fast += '''
+    b%d = RelooperAddBlockWithSwitch(relooper,
+      BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()),
+      BinaryenBinary(module,
+        BinaryenRemUInt32(),
+        BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+        BinaryenConst(module, BinaryenLiteralInt32(%d))
+      )
+    );
+''' % (i, len(branches[i]) + 1)
+        else:    # non-switch
+            fast += '''
+    b%d = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+''' % i
+        fast += '''
+  }
+'''
+
+    for i in range(num):
+        b = branches[i]
+        bc = branch_codes[i]
+
+        def get_phi(j):
+            phi = 'NULL'
+            if bc[j]:
+                # increment the index of global state
+                phi = '''
+    BinaryenStore(module,
+      4, 0, 0,
+      BinaryenConst(module, BinaryenLiteralInt32(4)),
+      BinaryenBinary(module,
+        BinaryenAddInt32(),
+        BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4))),
+        BinaryenConst(module, BinaryenLiteralInt32(4 * %d))
+      ),
+      BinaryenTypeInt32()
+    )''' % bc[j]
+            return phi
+
+        for j in range(len(b)):
+            if use_switch[i]:
+                total = len(b) + 1
+                values = ','.join([str(x) for x in range(random.randint(len(b) + 1,
+                                   max_decision + 2)) if x % total == j])
+                fast += '''
+  {
+    BinaryenIndex values[] = { %s };
+    RelooperAddBranchForSwitch(b%d, b%d, values,
+                               sizeof(values) / sizeof(BinaryenIndex), %s);
+  }
+''' % (values, i, b[j], get_phi(j))
+            else:    # non-switch
+                fast += '''
+  RelooperAddBranch(b%d, b%d, BinaryenBinary(module,
+    BinaryenEqInt32(),
+    BinaryenBinary(module,
+      BinaryenRemUInt32(),
+      BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+      BinaryenConst(module, BinaryenLiteralInt32(%d))
+    ),
+    BinaryenConst(module, BinaryenLiteralInt32(%d))
+  ), %s);
+''' % (i, b[j], len(b) + 1, j, get_phi(j))
+        # default branch
+        if use_switch[i]:
+            fast += '''
+  RelooperAddBranchForSwitch(b%d, b%d, NULL, 0, %s);
+''' % (i, defaults[i], get_phi(-1))
+        else:
+            fast += '''
+  RelooperAddBranch(b%d, b%d, NULL, %s);
+''' % (i, defaults[i], get_phi(-1))
+
+    fast += '''
+  BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, b0, 1);
+
+  int decisions[] = { %s };
+  int numDecisions = sizeof(decisions)/sizeof(int);
+
+  // write out all the decisions, then the body of the function
+  BinaryenExpressionRef full[numDecisions + 1];
+
+  {
+    int i;
+    for (i = 0; i < numDecisions; i++) {
+      full[i] = BinaryenStore(module,
+        4, 0, 0,
+        BinaryenConst(module, BinaryenLiteralInt32(8 + 4 * i)),
+        BinaryenConst(module, BinaryenLiteralInt32(decisions[i])),
+        BinaryenTypeInt32()
+      );
+    }
+  }
+  full[numDecisions] = body;
+  BinaryenExpressionRef all = BinaryenBlock(module, NULL, full,
+                                            numDecisions + 1,
+                                            BinaryenTypeNone());
+
+  BinaryenFunctionTypeRef v = BinaryenAddFunctionType(module, "v",
+                                                      BinaryenTypeNone(),
+                                                      NULL, 0);
+  // locals: state, free-for-label
+  BinaryenType localTypes[] = { BinaryenTypeInt32(), BinaryenTypeInt32() };
+  BinaryenFunctionRef theMain = BinaryenAddFunction(module, "main", v,
+                                                    localTypes, 2, all);
+  BinaryenSetStart(module, theMain);
+
+  // import
+
+  BinaryenType iparams[] = { BinaryenTypeInt32() };
+  BinaryenFunctionTypeRef vi = BinaryenAddFunctionType(module, "vi",
+                                                       BinaryenTypeNone(),
+                                                       iparams, 1);
+  BinaryenAddFunctionImport(module, "print", "spectest", "print", vi);
+
+  // memory
+  BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, 0, 0);
+
+  // optionally, optimize
+  if (%d) BinaryenModuleOptimize(module);
+
+  assert(BinaryenModuleValidate(module));
+
+  // write it out
+
+  BinaryenModulePrint(module);
+
+  BinaryenModuleDispose(module);
+
+  return 0;
+}
+''' % (', '.join(map(str, decisions)), optimize)
+
+    slow += '}'
+
+    open('fuzz.slow.js', 'w').write(slow)
+    open('fuzz.c', 'w').write(fast)
+
+    print('.')
+    cmd = [os.environ.get('CC') or 'gcc', 'fuzz.c', '-Isrc',
+           '-lbinaryen', '-lasmjs',
+           '-lsupport', '-Llib/.', '-pthread', '-o', 'fuzz']
+    subprocess.check_call(cmd)
+    print('^')
+    subprocess.check_call(['./fuzz'], stdout=open('fuzz.wast', 'w'))
+    print('*')
+    fast_out = subprocess.Popen(['bin/wasm-shell', 'fuzz.wast'],
+                                stdout=subprocess.PIPE,
+                                stderr=subprocess.PIPE).communicate()[0]
+    print('-')
+    node = os.getenv('NODE', 'nodejs')
+    slow_out = subprocess.Popen([node, 'fuzz.slow.js'],
+                                stdout=subprocess.PIPE,
+                                stderr=subprocess.PIPE).communicate()[0]
+    print('_')
+
+    if slow_out != fast_out:
+        print(''.join([a.rstrip() + '\n' for a in difflib.unified_diff(
+            slow_out.split('\n'),
+            fast_out.split('\n'),
+            fromfile='slow',
+            tofile='fast')]))
+        assert False
diff --git a/binaryen/scripts/fuzz_shell.js b/binaryen/scripts/fuzz_shell.js
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/fuzz_shell.js
@@ -0,0 +1,219 @@
+// Shell integration.
+if (typeof console === 'undefined') {
+  console = { log: print };
+}
+var tempRet0;
+var binary;
+if (typeof process === 'object' && typeof require === 'function' /* node.js detection */) {
+  var args = process.argv.slice(2);
+  binary = require('fs').readFileSync(args[0]);
+  if (!binary.buffer) binary = new Uint8Array(binary);
+} else {
+  var args;
+  if (typeof scriptArgs != 'undefined') {
+    args = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    args = arguments;
+  }
+  if (typeof readbuffer === 'function') {
+    binary = new Uint8Array(readbuffer(args[0]));
+  } else {
+    binary = read(args[0], 'binary');
+  }
+}
+
+// Utilities.
+function assert(x, y) {
+  if (!x) throw (y || 'assertion failed');// + new Error().stack;
+}
+
+// Deterministic randomness.
+var detrand = (function() {
+  var hash = 5381; // TODO DET_RAND_SEED;
+  var x = 0;
+  return function() {
+    hash = (((hash << 5) + hash) ^ (x & 0xff)) >>> 0;
+    x = (x + 1) % 256;
+    return (hash % 256) / 256;
+  };
+})();
+
+// Asyncify integration.
+var Asyncify = {
+  sleeping: false,
+  sleepingFunction: null,
+  sleeps: 0,
+  maxDepth: 0,
+  DATA_ADDR: 4,
+  DATA_MAX: 65536,
+  savedMemory: null,
+  instrumentImports: function(imports) {
+    var ret = {};
+    for (var module in imports) {
+      ret[module] = {};
+      for (var i in imports[module]) {
+        if (typeof imports[module][i] === 'function') {
+          (function(module, i) {
+            ret[module][i] = function() {
+              refreshView();
+              if (!Asyncify.sleeping) {
+                // Sleep if asyncify support is present (which also requires
+                // that the memory be exported), and at a certain probability.
+                if (exports.asyncify_start_unwind &&
+                    view &&
+                    detrand() < 0.5) {
+                  // We are called in order to start a sleep/unwind.
+                  console.log('asyncify: sleep in ' + i + '...');
+                  Asyncify.sleepingFunction = i;
+                  Asyncify.sleeps++;
+                  var depth = new Error().stack.split('\n').length - 6;
+                  Asyncify.maxDepth = Math.max(Asyncify.maxDepth, depth);
+                  // Save the memory we use for data, so after we restore it later, the
+                  // sleep/resume appears to have had no change to memory.
+                  Asyncify.savedMemory = new Int32Array(view.subarray(Asyncify.DATA_ADDR >> 2, Asyncify.DATA_MAX >> 2));
+                  // Unwinding.
+                  // Fill in the data structure. The first value has the stack location,
+                  // which for simplicity we can start right after the data structure itself.
+                  view[Asyncify.DATA_ADDR >> 2] = Asyncify.DATA_ADDR + 8;
+                  // The end of the stack will not be reached here anyhow.
+                  view[Asyncify.DATA_ADDR + 4 >> 2] = Asyncify.DATA_MAX;
+                  exports.asyncify_start_unwind(Asyncify.DATA_ADDR);
+                  Asyncify.sleeping = true;
+                } else {
+                  // Don't sleep, normal execution.
+                  return imports[module][i].apply(null, arguments);
+                }
+              } else {
+                // We are called as part of a resume/rewind. Stop sleeping.
+                console.log('asyncify: resume in ' + i + '...');
+                assert(Asyncify.sleepingFunction === i);
+                exports.asyncify_stop_rewind();
+                // The stack should have been all used up, and so returned to the original state.
+                assert(view[Asyncify.DATA_ADDR >> 2] == Asyncify.DATA_ADDR + 8);
+                assert(view[Asyncify.DATA_ADDR + 4 >> 2] == Asyncify.DATA_MAX);
+                Asyncify.sleeping = false;
+                // Restore the memory to the state from before we slept.
+                view.set(Asyncify.savedMemory, Asyncify.DATA_ADDR >> 2);
+                return imports[module][i].apply(null, arguments);
+              }
+            };
+          })(module, i);
+        } else {
+          ret[module][i] = imports[module][i];
+        }
+      }
+    }
+    // Add ignored.print, which is ignored by asyncify, and allows debugging of asyncified code.
+    ret['ignored'] = { 'print': function(x, y) { console.log(x, y) } };
+    return ret;
+  },
+  instrumentExports: function(exports) {
+    var ret = {};
+    for (var e in exports) {
+      if (typeof exports[e] === 'function' &&
+          !e.startsWith('asyncify_')) {
+        (function(e) {
+          ret[e] = function() {
+            while (1) {
+              var ret = exports[e].apply(null, arguments);
+              // If we are sleeping, then the stack was unwound; rewind it.
+              if (Asyncify.sleeping) {
+                console.log('asyncify: stop unwind; rewind');
+                assert(!ret, 'results during sleep are meaningless, just 0');
+                //console.log('asyncify: after unwind', view[Asyncify.DATA_ADDR >> 2], view[Asyncify.DATA_ADDR + 4 >> 2]);
+                try {
+                  exports.asyncify_stop_unwind();
+                  exports.asyncify_start_rewind(Asyncify.DATA_ADDR);
+                } catch (e) {
+                  console.log('error in unwind/rewind switch', e);
+                }
+                continue;
+              }
+              return ret;
+            }
+          };
+        })(e);
+      } else {
+        ret[e] = exports[e];
+      }
+    }
+    return ret;
+  },
+  check: function() {
+    assert(!Asyncify.sleeping);
+  },
+  finish: function() {
+    if (Asyncify.sleeps > 0) {
+      print('asyncify:', 'sleeps:', Asyncify.sleeps, 'max depth:', Asyncify.maxDepth);
+    }
+  },
+};
+
+// Fuzz integration.
+function logValue(x, y) {
+  if (typeof y !== 'undefined') {
+    console.log('[LoggingExternalInterface logging ' + x + ' ' + y + ']');
+  } else {
+    console.log('[LoggingExternalInterface logging ' + x + ']');
+  }
+}
+
+// Set up the imports.
+var imports = {
+  'fuzzing-support': {
+    'log-i32': logValue,
+    'log-i64': logValue,
+    'log-f32': logValue,
+    'log-f64': logValue,
+  },
+  'env': {
+    'setTempRet0': function(x) { tempRet0 = x },
+    'getTempRet0': function() { return tempRet0 },
+  },
+};
+
+imports = Asyncify.instrumentImports(imports);
+
+// Create the wasm.
+var instance = new WebAssembly.Instance(new WebAssembly.Module(binary), imports);
+
+// Handle the exports.
+var exports = instance.exports;
+exports = Asyncify.instrumentExports(exports);
+
+var view;
+
+// Recreate the view. This is important both initially and after a growth.
+function refreshView() {
+  if (exports.memory) {
+    view = new Int32Array(exports.memory.buffer);
+  }
+}
+
+// Run the wasm.
+var sortedExports = [];
+for (var e in exports) {
+  sortedExports.push(e);
+}
+sortedExports.sort();
+sortedExports = sortedExports.filter(function(e) {
+  // Filter special intrinsic functions.
+  return !e.startsWith('asyncify_');
+});
+sortedExports.forEach(function(e) {
+  Asyncify.check();
+  if (typeof exports[e] !== 'function') return;
+  try {
+    console.log('[fuzz-exec] calling ' + e);
+    var result = exports[e]();
+    if (typeof result !== 'undefined') {
+      console.log('[fuzz-exec] note result: $' + e + ' => ' + result);
+    }
+  } catch (e) {
+    console.log('exception!');// + [e, e.stack]);
+  }
+});
+
+// Finish up
+Asyncify.finish();
+
diff --git a/binaryen/scripts/gen-s-parser.py b/binaryen/scripts/gen-s-parser.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/gen-s-parser.py
@@ -0,0 +1,665 @@
+#!/usr/bin/env python3
+#
+# 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.
+
+import sys
+
+instructions = [
+    ("unreachable",    "makeUnreachable()"),
+    ("nop",            "makeNop()"),
+    ("block",          "makeBlock(s)"),
+    ("loop",           "makeLoop(s)"),
+    ("if",             "makeIf(s)"),
+    ("then",           "makeThenOrElse(s)"),
+    ("else",           "makeThenOrElse(s)"),
+    ("br",             "makeBreak(s)"),
+    ("br_if",          "makeBreak(s)"),
+    ("br_table",       "makeBreakTable(s)"),
+    ("return",         "makeReturn(s)"),
+    ("call",           "makeCall(s, /*isReturn=*/false)"),
+    ("call_indirect",  "makeCallIndirect(s, /*isReturn=*/false)"),
+    ("return_call",    "makeCall(s, /*isReturn=*/true)"),
+    ("return_call_indirect", "makeCallIndirect(s, /*isReturn=*/true)"),
+    ("drop",           "makeDrop(s)"),
+    ("select",         "makeSelect(s)"),
+    ("local.get",      "makeLocalGet(s)"),
+    ("local.set",      "makeLocalSet(s)"),
+    ("local.tee",      "makeLocalTee(s)"),
+    ("global.get",     "makeGlobalGet(s)"),
+    ("global.set",     "makeGlobalSet(s)"),
+    ("memory.init",    "makeMemoryInit(s)"),
+    ("data.drop",      "makeDataDrop(s)"),
+    ("memory.copy",    "makeMemoryCopy(s)"),
+    ("memory.fill",    "makeMemoryFill(s)"),
+    ("i32.load",       "makeLoad(s, Type::i32, /*isAtomic=*/false)"),
+    ("i64.load",       "makeLoad(s, Type::i64, /*isAtomic=*/false)"),
+    ("f32.load",       "makeLoad(s, Type::f32, /*isAtomic=*/false)"),
+    ("f64.load",       "makeLoad(s, Type::f64, /*isAtomic=*/false)"),
+    ("i32.load8_s",    "makeLoad(s, Type::i32, /*isAtomic=*/false)"),
+    ("i32.load8_u",    "makeLoad(s, Type::i32, /*isAtomic=*/false)"),
+    ("i32.load16_s",   "makeLoad(s, Type::i32, /*isAtomic=*/false)"),
+    ("i32.load16_u",   "makeLoad(s, Type::i32, /*isAtomic=*/false)"),
+    ("i64.load8_s",    "makeLoad(s, Type::i64, /*isAtomic=*/false)"),
+    ("i64.load8_u",    "makeLoad(s, Type::i64, /*isAtomic=*/false)"),
+    ("i64.load16_s",   "makeLoad(s, Type::i64, /*isAtomic=*/false)"),
+    ("i64.load16_u",   "makeLoad(s, Type::i64, /*isAtomic=*/false)"),
+    ("i64.load32_s",   "makeLoad(s, Type::i64, /*isAtomic=*/false)"),
+    ("i64.load32_u",   "makeLoad(s, Type::i64, /*isAtomic=*/false)"),
+    ("i32.store",      "makeStore(s, Type::i32, /*isAtomic=*/false)"),
+    ("i64.store",      "makeStore(s, Type::i64, /*isAtomic=*/false)"),
+    ("f32.store",      "makeStore(s, Type::f32, /*isAtomic=*/false)"),
+    ("f64.store",      "makeStore(s, Type::f64, /*isAtomic=*/false)"),
+    ("i32.store8",     "makeStore(s, Type::i32, /*isAtomic=*/false)"),
+    ("i32.store16",    "makeStore(s, Type::i32, /*isAtomic=*/false)"),
+    ("i64.store8",     "makeStore(s, Type::i64, /*isAtomic=*/false)"),
+    ("i64.store16",    "makeStore(s, Type::i64, /*isAtomic=*/false)"),
+    ("i64.store32",    "makeStore(s, Type::i64, /*isAtomic=*/false)"),
+    ("memory.size",    "makeMemorySize(s)"),
+    ("memory.grow",    "makeMemoryGrow(s)"),
+    ("i32.const",      "makeConst(s, Type::i32)"),
+    ("i64.const",      "makeConst(s, Type::i64)"),
+    ("f32.const",      "makeConst(s, Type::f32)"),
+    ("f64.const",      "makeConst(s, Type::f64)"),
+    ("i32.eqz",        "makeUnary(s, UnaryOp::EqZInt32)"),
+    ("i32.eq",         "makeBinary(s, BinaryOp::EqInt32)"),
+    ("i32.ne",         "makeBinary(s, BinaryOp::NeInt32)"),
+    ("i32.lt_s",       "makeBinary(s, BinaryOp::LtSInt32)"),
+    ("i32.lt_u",       "makeBinary(s, BinaryOp::LtUInt32)"),
+    ("i32.gt_s",       "makeBinary(s, BinaryOp::GtSInt32)"),
+    ("i32.gt_u",       "makeBinary(s, BinaryOp::GtUInt32)"),
+    ("i32.le_s",       "makeBinary(s, BinaryOp::LeSInt32)"),
+    ("i32.le_u",       "makeBinary(s, BinaryOp::LeUInt32)"),
+    ("i32.ge_s",       "makeBinary(s, BinaryOp::GeSInt32)"),
+    ("i32.ge_u",       "makeBinary(s, BinaryOp::GeUInt32)"),
+    ("i64.eqz",        "makeUnary(s, UnaryOp::EqZInt64)"),
+    ("i64.eq",         "makeBinary(s, BinaryOp::EqInt64)"),
+    ("i64.ne",         "makeBinary(s, BinaryOp::NeInt64)"),
+    ("i64.lt_s",       "makeBinary(s, BinaryOp::LtSInt64)"),
+    ("i64.lt_u",       "makeBinary(s, BinaryOp::LtUInt64)"),
+    ("i64.gt_s",       "makeBinary(s, BinaryOp::GtSInt64)"),
+    ("i64.gt_u",       "makeBinary(s, BinaryOp::GtUInt64)"),
+    ("i64.le_s",       "makeBinary(s, BinaryOp::LeSInt64)"),
+    ("i64.le_u",       "makeBinary(s, BinaryOp::LeUInt64)"),
+    ("i64.ge_s",       "makeBinary(s, BinaryOp::GeSInt64)"),
+    ("i64.ge_u",       "makeBinary(s, BinaryOp::GeUInt64)"),
+    ("f32.eq",         "makeBinary(s, BinaryOp::EqFloat32)"),
+    ("f32.ne",         "makeBinary(s, BinaryOp::NeFloat32)"),
+    ("f32.lt",         "makeBinary(s, BinaryOp::LtFloat32)"),
+    ("f32.gt",         "makeBinary(s, BinaryOp::GtFloat32)"),
+    ("f32.le",         "makeBinary(s, BinaryOp::LeFloat32)"),
+    ("f32.ge",         "makeBinary(s, BinaryOp::GeFloat32)"),
+    ("f64.eq",         "makeBinary(s, BinaryOp::EqFloat64)"),
+    ("f64.ne",         "makeBinary(s, BinaryOp::NeFloat64)"),
+    ("f64.lt",         "makeBinary(s, BinaryOp::LtFloat64)"),
+    ("f64.gt",         "makeBinary(s, BinaryOp::GtFloat64)"),
+    ("f64.le",         "makeBinary(s, BinaryOp::LeFloat64)"),
+    ("f64.ge",         "makeBinary(s, BinaryOp::GeFloat64)"),
+    ("i32.clz",        "makeUnary(s, UnaryOp::ClzInt32)"),
+    ("i32.ctz",        "makeUnary(s, UnaryOp::CtzInt32)"),
+    ("i32.popcnt",     "makeUnary(s, UnaryOp::PopcntInt32)"),
+    ("i32.add",        "makeBinary(s, BinaryOp::AddInt32)"),
+    ("i32.sub",        "makeBinary(s, BinaryOp::SubInt32)"),
+    ("i32.mul",        "makeBinary(s, BinaryOp::MulInt32)"),
+    ("i32.div_s",      "makeBinary(s, BinaryOp::DivSInt32)"),
+    ("i32.div_u",      "makeBinary(s, BinaryOp::DivUInt32)"),
+    ("i32.rem_s",      "makeBinary(s, BinaryOp::RemSInt32)"),
+    ("i32.rem_u",      "makeBinary(s, BinaryOp::RemUInt32)"),
+    ("i32.and",        "makeBinary(s, BinaryOp::AndInt32)"),
+    ("i32.or",         "makeBinary(s, BinaryOp::OrInt32)"),
+    ("i32.xor",        "makeBinary(s, BinaryOp::XorInt32)"),
+    ("i32.shl",        "makeBinary(s, BinaryOp::ShlInt32)"),
+    ("i32.shr_s",      "makeBinary(s, BinaryOp::ShrSInt32)"),
+    ("i32.shr_u",      "makeBinary(s, BinaryOp::ShrUInt32)"),
+    ("i32.rotl",       "makeBinary(s, BinaryOp::RotLInt32)"),
+    ("i32.rotr",       "makeBinary(s, BinaryOp::RotRInt32)"),
+    ("i64.clz",        "makeUnary(s, UnaryOp::ClzInt64)"),
+    ("i64.ctz",        "makeUnary(s, UnaryOp::CtzInt64)"),
+    ("i64.popcnt",     "makeUnary(s, UnaryOp::PopcntInt64)"),
+    ("i64.add",        "makeBinary(s, BinaryOp::AddInt64)"),
+    ("i64.sub",        "makeBinary(s, BinaryOp::SubInt64)"),
+    ("i64.mul",        "makeBinary(s, BinaryOp::MulInt64)"),
+    ("i64.div_s",      "makeBinary(s, BinaryOp::DivSInt64)"),
+    ("i64.div_u",      "makeBinary(s, BinaryOp::DivUInt64)"),
+    ("i64.rem_s",      "makeBinary(s, BinaryOp::RemSInt64)"),
+    ("i64.rem_u",      "makeBinary(s, BinaryOp::RemUInt64)"),
+    ("i64.and",        "makeBinary(s, BinaryOp::AndInt64)"),
+    ("i64.or",         "makeBinary(s, BinaryOp::OrInt64)"),
+    ("i64.xor",        "makeBinary(s, BinaryOp::XorInt64)"),
+    ("i64.shl",        "makeBinary(s, BinaryOp::ShlInt64)"),
+    ("i64.shr_s",      "makeBinary(s, BinaryOp::ShrSInt64)"),
+    ("i64.shr_u",      "makeBinary(s, BinaryOp::ShrUInt64)"),
+    ("i64.rotl",       "makeBinary(s, BinaryOp::RotLInt64)"),
+    ("i64.rotr",       "makeBinary(s, BinaryOp::RotRInt64)"),
+    ("f32.abs",        "makeUnary(s, UnaryOp::AbsFloat32)"),
+    ("f32.neg",        "makeUnary(s, UnaryOp::NegFloat32)"),
+    ("f32.ceil",       "makeUnary(s, UnaryOp::CeilFloat32)"),
+    ("f32.floor",      "makeUnary(s, UnaryOp::FloorFloat32)"),
+    ("f32.trunc",      "makeUnary(s, UnaryOp::TruncFloat32)"),
+    ("f32.nearest",    "makeUnary(s, UnaryOp::NearestFloat32)"),
+    ("f32.sqrt",       "makeUnary(s, UnaryOp::SqrtFloat32)"),
+    ("f32.add",        "makeBinary(s, BinaryOp::AddFloat32)"),
+    ("f32.sub",        "makeBinary(s, BinaryOp::SubFloat32)"),
+    ("f32.mul",        "makeBinary(s, BinaryOp::MulFloat32)"),
+    ("f32.div",        "makeBinary(s, BinaryOp::DivFloat32)"),
+    ("f32.min",        "makeBinary(s, BinaryOp::MinFloat32)"),
+    ("f32.max",        "makeBinary(s, BinaryOp::MaxFloat32)"),
+    ("f32.copysign",   "makeBinary(s, BinaryOp::CopySignFloat32)"),
+    ("f64.abs",        "makeUnary(s, UnaryOp::AbsFloat64)"),
+    ("f64.neg",        "makeUnary(s, UnaryOp::NegFloat64)"),
+    ("f64.ceil",       "makeUnary(s, UnaryOp::CeilFloat64)"),
+    ("f64.floor",      "makeUnary(s, UnaryOp::FloorFloat64)"),
+    ("f64.trunc",      "makeUnary(s, UnaryOp::TruncFloat64)"),
+    ("f64.nearest",    "makeUnary(s, UnaryOp::NearestFloat64)"),
+    ("f64.sqrt",       "makeUnary(s, UnaryOp::SqrtFloat64)"),
+    ("f64.add",        "makeBinary(s, BinaryOp::AddFloat64)"),
+    ("f64.sub",        "makeBinary(s, BinaryOp::SubFloat64)"),
+    ("f64.mul",        "makeBinary(s, BinaryOp::MulFloat64)"),
+    ("f64.div",        "makeBinary(s, BinaryOp::DivFloat64)"),
+    ("f64.min",        "makeBinary(s, BinaryOp::MinFloat64)"),
+    ("f64.max",        "makeBinary(s, BinaryOp::MaxFloat64)"),
+    ("f64.copysign",   "makeBinary(s, BinaryOp::CopySignFloat64)"),
+    ("i32.wrap_i64",   "makeUnary(s, UnaryOp::WrapInt64)"),
+    ("i32.trunc_f32_s",     "makeUnary(s, UnaryOp::TruncSFloat32ToInt32)"),
+    ("i32.trunc_f32_u",     "makeUnary(s, UnaryOp::TruncUFloat32ToInt32)"),
+    ("i32.trunc_f64_s",     "makeUnary(s, UnaryOp::TruncSFloat64ToInt32)"),
+    ("i32.trunc_f64_u",     "makeUnary(s, UnaryOp::TruncUFloat64ToInt32)"),
+    ("i64.extend_i32_s",    "makeUnary(s, UnaryOp::ExtendSInt32)"),
+    ("i64.extend_i32_u",    "makeUnary(s, UnaryOp::ExtendUInt32)"),
+    ("i64.trunc_f32_s",     "makeUnary(s, UnaryOp::TruncSFloat32ToInt64)"),
+    ("i64.trunc_f32_u",     "makeUnary(s, UnaryOp::TruncUFloat32ToInt64)"),
+    ("i64.trunc_f64_s",     "makeUnary(s, UnaryOp::TruncSFloat64ToInt64)"),
+    ("i64.trunc_f64_u",     "makeUnary(s, UnaryOp::TruncUFloat64ToInt64)"),
+    ("f32.convert_i32_s",   "makeUnary(s, UnaryOp::ConvertSInt32ToFloat32)"),
+    ("f32.convert_i32_u",   "makeUnary(s, UnaryOp::ConvertUInt32ToFloat32)"),
+    ("f32.convert_i64_s",   "makeUnary(s, UnaryOp::ConvertSInt64ToFloat32)"),
+    ("f32.convert_i64_u",   "makeUnary(s, UnaryOp::ConvertUInt64ToFloat32)"),
+    ("f32.demote_f64",      "makeUnary(s, UnaryOp::DemoteFloat64)"),
+    ("f64.convert_i32_s",   "makeUnary(s, UnaryOp::ConvertSInt32ToFloat64)"),
+    ("f64.convert_i32_u",   "makeUnary(s, UnaryOp::ConvertUInt32ToFloat64)"),
+    ("f64.convert_i64_s",   "makeUnary(s, UnaryOp::ConvertSInt64ToFloat64)"),
+    ("f64.convert_i64_u",   "makeUnary(s, UnaryOp::ConvertUInt64ToFloat64)"),
+    ("f64.promote_f32",     "makeUnary(s, UnaryOp::PromoteFloat32)"),
+    ("i32.reinterpret_f32", "makeUnary(s, UnaryOp::ReinterpretFloat32)"),
+    ("i64.reinterpret_f64", "makeUnary(s, UnaryOp::ReinterpretFloat64)"),
+    ("f32.reinterpret_i32", "makeUnary(s, UnaryOp::ReinterpretInt32)"),
+    ("f64.reinterpret_i64", "makeUnary(s, UnaryOp::ReinterpretInt64)"),
+    ("i32.extend8_s",       "makeUnary(s, UnaryOp::ExtendS8Int32)"),
+    ("i32.extend16_s",      "makeUnary(s, UnaryOp::ExtendS16Int32)"),
+    ("i64.extend8_s",       "makeUnary(s, UnaryOp::ExtendS8Int64)"),
+    ("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)"),
+    ("atomic.fence",            "makeAtomicFence(s)"),
+    ("i32.atomic.load8_u",      "makeLoad(s, Type::i32, /*isAtomic=*/true)"),
+    ("i32.atomic.load16_u",     "makeLoad(s, Type::i32, /*isAtomic=*/true)"),
+    ("i32.atomic.load",         "makeLoad(s, Type::i32, /*isAtomic=*/true)"),
+    ("i64.atomic.load8_u",      "makeLoad(s, Type::i64, /*isAtomic=*/true)"),
+    ("i64.atomic.load16_u",     "makeLoad(s, Type::i64, /*isAtomic=*/true)"),
+    ("i64.atomic.load32_u",     "makeLoad(s, Type::i64, /*isAtomic=*/true)"),
+    ("i64.atomic.load",         "makeLoad(s, Type::i64, /*isAtomic=*/true)"),
+    ("i32.atomic.store8",       "makeStore(s, Type::i32, /*isAtomic=*/true)"),
+    ("i32.atomic.store16",      "makeStore(s, Type::i32, /*isAtomic=*/true)"),
+    ("i32.atomic.store",        "makeStore(s, Type::i32, /*isAtomic=*/true)"),
+    ("i64.atomic.store8",       "makeStore(s, Type::i64, /*isAtomic=*/true)"),
+    ("i64.atomic.store16",      "makeStore(s, Type::i64, /*isAtomic=*/true)"),
+    ("i64.atomic.store32",      "makeStore(s, Type::i64, /*isAtomic=*/true)"),
+    ("i64.atomic.store",        "makeStore(s, Type::i64, /*isAtomic=*/true)"),
+    ("i32.atomic.rmw8.add_u",   "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i32.atomic.rmw16.add_u",  "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i32.atomic.rmw.add",      "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i64.atomic.rmw8.add_u",   "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw16.add_u",  "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw32.add_u",  "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw.add",      "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i32.atomic.rmw8.sub_u",   "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i32.atomic.rmw16.sub_u",  "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i32.atomic.rmw.sub",      "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i64.atomic.rmw8.sub_u",   "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw16.sub_u",  "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw32.sub_u",  "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw.sub",      "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i32.atomic.rmw8.and_u",   "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i32.atomic.rmw16.and_u",  "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i32.atomic.rmw.and",      "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i64.atomic.rmw8.and_u",   "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw16.and_u",  "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw32.and_u",  "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw.and",      "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i32.atomic.rmw8.or_u",    "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i32.atomic.rmw16.or_u",   "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i32.atomic.rmw.or",       "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i64.atomic.rmw8.or_u",    "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw16.or_u",   "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw32.or_u",   "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw.or",       "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i32.atomic.rmw8.xor_u",   "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i32.atomic.rmw16.xor_u",  "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i32.atomic.rmw.xor",      "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i64.atomic.rmw8.xor_u",   "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw16.xor_u",  "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw32.xor_u",  "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw.xor",      "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i32.atomic.rmw8.xchg_u",  "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i32.atomic.rmw16.xchg_u", "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i32.atomic.rmw.xchg",     "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i64.atomic.rmw8.xchg_u",  "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw16.xchg_u", "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw32.xchg_u", "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw.xchg",     "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i32.atomic.rmw8.cmpxchg_u",  "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i32.atomic.rmw16.cmpxchg_u", "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i32.atomic.rmw.cmpxchg",     "makeAtomicRMWOrCmpxchg(s, Type::i32)"),
+    ("i64.atomic.rmw8.cmpxchg_u",  "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw16.cmpxchg_u", "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw32.cmpxchg_u", "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    ("i64.atomic.rmw.cmpxchg",     "makeAtomicRMWOrCmpxchg(s, Type::i64)"),
+    # nontrapping float-to-int instructions
+    ("i32.trunc_sat_f32_s", "makeUnary(s, UnaryOp::TruncSatSFloat32ToInt32)"),
+    ("i32.trunc_sat_f32_u", "makeUnary(s, UnaryOp::TruncSatUFloat32ToInt32)"),
+    ("i32.trunc_sat_f64_s", "makeUnary(s, UnaryOp::TruncSatSFloat64ToInt32)"),
+    ("i32.trunc_sat_f64_u", "makeUnary(s, UnaryOp::TruncSatUFloat64ToInt32)"),
+    ("i64.trunc_sat_f32_s", "makeUnary(s, UnaryOp::TruncSatSFloat32ToInt64)"),
+    ("i64.trunc_sat_f32_u", "makeUnary(s, UnaryOp::TruncSatUFloat32ToInt64)"),
+    ("i64.trunc_sat_f64_s", "makeUnary(s, UnaryOp::TruncSatSFloat64ToInt64)"),
+    ("i64.trunc_sat_f64_u", "makeUnary(s, UnaryOp::TruncSatUFloat64ToInt64)"),
+    # SIMD ops
+    ("v128.load",            "makeLoad(s, Type::v128, /*isAtomic=*/false)"),
+    ("v128.store",           "makeStore(s, Type::v128, /*isAtomic=*/false)"),
+    ("v128.const",           "makeConst(s, Type::v128)"),
+    ("v8x16.shuffle",        "makeSIMDShuffle(s)"),
+    ("i8x16.splat",          "makeUnary(s, UnaryOp::SplatVecI8x16)"),
+    ("i8x16.extract_lane_s", "makeSIMDExtract(s, SIMDExtractOp::ExtractLaneSVecI8x16, 16)"),
+    ("i8x16.extract_lane_u", "makeSIMDExtract(s, SIMDExtractOp::ExtractLaneUVecI8x16, 16)"),
+    ("i8x16.replace_lane",   "makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecI8x16, 16)"),
+    ("i16x8.splat",          "makeUnary(s, UnaryOp::SplatVecI16x8)"),
+    ("i16x8.extract_lane_s", "makeSIMDExtract(s, SIMDExtractOp::ExtractLaneSVecI16x8, 8)"),
+    ("i16x8.extract_lane_u", "makeSIMDExtract(s, SIMDExtractOp::ExtractLaneUVecI16x8, 8)"),
+    ("i16x8.replace_lane",   "makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecI16x8, 8)"),
+    ("i32x4.splat",          "makeUnary(s, UnaryOp::SplatVecI32x4)"),
+    ("i32x4.extract_lane",   "makeSIMDExtract(s, SIMDExtractOp::ExtractLaneVecI32x4, 4)"),
+    ("i32x4.replace_lane",   "makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecI32x4, 4)"),
+    ("i64x2.splat",          "makeUnary(s, UnaryOp::SplatVecI64x2)"),
+    ("i64x2.extract_lane",   "makeSIMDExtract(s, SIMDExtractOp::ExtractLaneVecI64x2, 2)"),
+    ("i64x2.replace_lane",   "makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecI64x2, 2)"),
+    ("f32x4.splat",          "makeUnary(s, UnaryOp::SplatVecF32x4)"),
+    ("f32x4.extract_lane",   "makeSIMDExtract(s, SIMDExtractOp::ExtractLaneVecF32x4, 4)"),
+    ("f32x4.replace_lane",   "makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecF32x4, 4)"),
+    ("f64x2.splat",          "makeUnary(s, UnaryOp::SplatVecF64x2)"),
+    ("f64x2.extract_lane",   "makeSIMDExtract(s, SIMDExtractOp::ExtractLaneVecF64x2, 2)"),
+    ("f64x2.replace_lane",   "makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecF64x2, 2)"),
+    ("i8x16.eq",             "makeBinary(s, BinaryOp::EqVecI8x16)"),
+    ("i8x16.ne",             "makeBinary(s, BinaryOp::NeVecI8x16)"),
+    ("i8x16.lt_s",           "makeBinary(s, BinaryOp::LtSVecI8x16)"),
+    ("i8x16.lt_u",           "makeBinary(s, BinaryOp::LtUVecI8x16)"),
+    ("i8x16.gt_s",           "makeBinary(s, BinaryOp::GtSVecI8x16)"),
+    ("i8x16.gt_u",           "makeBinary(s, BinaryOp::GtUVecI8x16)"),
+    ("i8x16.le_s",           "makeBinary(s, BinaryOp::LeSVecI8x16)"),
+    ("i8x16.le_u",           "makeBinary(s, BinaryOp::LeUVecI8x16)"),
+    ("i8x16.ge_s",           "makeBinary(s, BinaryOp::GeSVecI8x16)"),
+    ("i8x16.ge_u",           "makeBinary(s, BinaryOp::GeUVecI8x16)"),
+    ("i16x8.eq",             "makeBinary(s, BinaryOp::EqVecI16x8)"),
+    ("i16x8.ne",             "makeBinary(s, BinaryOp::NeVecI16x8)"),
+    ("i16x8.lt_s",           "makeBinary(s, BinaryOp::LtSVecI16x8)"),
+    ("i16x8.lt_u",           "makeBinary(s, BinaryOp::LtUVecI16x8)"),
+    ("i16x8.gt_s",           "makeBinary(s, BinaryOp::GtSVecI16x8)"),
+    ("i16x8.gt_u",           "makeBinary(s, BinaryOp::GtUVecI16x8)"),
+    ("i16x8.le_s",           "makeBinary(s, BinaryOp::LeSVecI16x8)"),
+    ("i16x8.le_u",           "makeBinary(s, BinaryOp::LeUVecI16x8)"),
+    ("i16x8.ge_s",           "makeBinary(s, BinaryOp::GeSVecI16x8)"),
+    ("i16x8.ge_u",           "makeBinary(s, BinaryOp::GeUVecI16x8)"),
+    ("i32x4.eq",             "makeBinary(s, BinaryOp::EqVecI32x4)"),
+    ("i32x4.ne",             "makeBinary(s, BinaryOp::NeVecI32x4)"),
+    ("i32x4.lt_s",           "makeBinary(s, BinaryOp::LtSVecI32x4)"),
+    ("i32x4.lt_u",           "makeBinary(s, BinaryOp::LtUVecI32x4)"),
+    ("i32x4.gt_s",           "makeBinary(s, BinaryOp::GtSVecI32x4)"),
+    ("i32x4.gt_u",           "makeBinary(s, BinaryOp::GtUVecI32x4)"),
+    ("i32x4.le_s",           "makeBinary(s, BinaryOp::LeSVecI32x4)"),
+    ("i32x4.le_u",           "makeBinary(s, BinaryOp::LeUVecI32x4)"),
+    ("i32x4.ge_s",           "makeBinary(s, BinaryOp::GeSVecI32x4)"),
+    ("i32x4.ge_u",           "makeBinary(s, BinaryOp::GeUVecI32x4)"),
+    ("f32x4.eq",             "makeBinary(s, BinaryOp::EqVecF32x4)"),
+    ("f32x4.ne",             "makeBinary(s, BinaryOp::NeVecF32x4)"),
+    ("f32x4.lt",             "makeBinary(s, BinaryOp::LtVecF32x4)"),
+    ("f32x4.gt",             "makeBinary(s, BinaryOp::GtVecF32x4)"),
+    ("f32x4.le",             "makeBinary(s, BinaryOp::LeVecF32x4)"),
+    ("f32x4.ge",             "makeBinary(s, BinaryOp::GeVecF32x4)"),
+    ("f64x2.eq",             "makeBinary(s, BinaryOp::EqVecF64x2)"),
+    ("f64x2.ne",             "makeBinary(s, BinaryOp::NeVecF64x2)"),
+    ("f64x2.lt",             "makeBinary(s, BinaryOp::LtVecF64x2)"),
+    ("f64x2.gt",             "makeBinary(s, BinaryOp::GtVecF64x2)"),
+    ("f64x2.le",             "makeBinary(s, BinaryOp::LeVecF64x2)"),
+    ("f64x2.ge",             "makeBinary(s, BinaryOp::GeVecF64x2)"),
+    ("v128.not",             "makeUnary(s, UnaryOp::NotVec128)"),
+    ("v128.and",             "makeBinary(s, BinaryOp::AndVec128)"),
+    ("v128.or",              "makeBinary(s, BinaryOp::OrVec128)"),
+    ("v128.xor",             "makeBinary(s, BinaryOp::XorVec128)"),
+    ("v128.andnot",          "makeBinary(s, BinaryOp::AndNotVec128)"),
+    ("v128.bitselect",       "makeSIMDTernary(s, SIMDTernaryOp::Bitselect)"),
+    ("i8x16.abs",            "makeUnary(s, UnaryOp::AbsVecI8x16)"),
+    ("i8x16.neg",            "makeUnary(s, UnaryOp::NegVecI8x16)"),
+    ("i8x16.any_true",       "makeUnary(s, UnaryOp::AnyTrueVecI8x16)"),
+    ("i8x16.all_true",       "makeUnary(s, UnaryOp::AllTrueVecI8x16)"),
+    ("i8x16.bitmask",        "makeUnary(s, UnaryOp::BitmaskVecI8x16)"),
+    ("i8x16.shl",            "makeSIMDShift(s, SIMDShiftOp::ShlVecI8x16)"),
+    ("i8x16.shr_s",          "makeSIMDShift(s, SIMDShiftOp::ShrSVecI8x16)"),
+    ("i8x16.shr_u",          "makeSIMDShift(s, SIMDShiftOp::ShrUVecI8x16)"),
+    ("i8x16.add",            "makeBinary(s, BinaryOp::AddVecI8x16)"),
+    ("i8x16.add_saturate_s", "makeBinary(s, BinaryOp::AddSatSVecI8x16)"),
+    ("i8x16.add_saturate_u", "makeBinary(s, BinaryOp::AddSatUVecI8x16)"),
+    ("i8x16.sub",            "makeBinary(s, BinaryOp::SubVecI8x16)"),
+    ("i8x16.sub_saturate_s", "makeBinary(s, BinaryOp::SubSatSVecI8x16)"),
+    ("i8x16.sub_saturate_u", "makeBinary(s, BinaryOp::SubSatUVecI8x16)"),
+    ("i8x16.mul",            "makeBinary(s, BinaryOp::MulVecI8x16)"),
+    ("i8x16.min_s",          "makeBinary(s, BinaryOp::MinSVecI8x16)"),
+    ("i8x16.min_u",          "makeBinary(s, BinaryOp::MinUVecI8x16)"),
+    ("i8x16.max_s",          "makeBinary(s, BinaryOp::MaxSVecI8x16)"),
+    ("i8x16.max_u",          "makeBinary(s, BinaryOp::MaxUVecI8x16)"),
+    ("i8x16.avgr_u",         "makeBinary(s, BinaryOp::AvgrUVecI8x16)"),
+    ("i16x8.abs",            "makeUnary(s, UnaryOp::AbsVecI16x8)"),
+    ("i16x8.neg",            "makeUnary(s, UnaryOp::NegVecI16x8)"),
+    ("i16x8.any_true",       "makeUnary(s, UnaryOp::AnyTrueVecI16x8)"),
+    ("i16x8.all_true",       "makeUnary(s, UnaryOp::AllTrueVecI16x8)"),
+    ("i16x8.bitmask",        "makeUnary(s, UnaryOp::BitmaskVecI16x8)"),
+    ("i16x8.shl",            "makeSIMDShift(s, SIMDShiftOp::ShlVecI16x8)"),
+    ("i16x8.shr_s",          "makeSIMDShift(s, SIMDShiftOp::ShrSVecI16x8)"),
+    ("i16x8.shr_u",          "makeSIMDShift(s, SIMDShiftOp::ShrUVecI16x8)"),
+    ("i16x8.add",            "makeBinary(s, BinaryOp::AddVecI16x8)"),
+    ("i16x8.add_saturate_s", "makeBinary(s, BinaryOp::AddSatSVecI16x8)"),
+    ("i16x8.add_saturate_u", "makeBinary(s, BinaryOp::AddSatUVecI16x8)"),
+    ("i16x8.sub",            "makeBinary(s, BinaryOp::SubVecI16x8)"),
+    ("i16x8.sub_saturate_s", "makeBinary(s, BinaryOp::SubSatSVecI16x8)"),
+    ("i16x8.sub_saturate_u", "makeBinary(s, BinaryOp::SubSatUVecI16x8)"),
+    ("i16x8.mul",            "makeBinary(s, BinaryOp::MulVecI16x8)"),
+    ("i16x8.min_s",          "makeBinary(s, BinaryOp::MinSVecI16x8)"),
+    ("i16x8.min_u",          "makeBinary(s, BinaryOp::MinUVecI16x8)"),
+    ("i16x8.max_s",          "makeBinary(s, BinaryOp::MaxSVecI16x8)"),
+    ("i16x8.max_u",          "makeBinary(s, BinaryOp::MaxUVecI16x8)"),
+    ("i16x8.avgr_u",         "makeBinary(s, BinaryOp::AvgrUVecI16x8)"),
+    ("i32x4.abs",            "makeUnary(s, UnaryOp::AbsVecI32x4)"),
+    ("i32x4.neg",            "makeUnary(s, UnaryOp::NegVecI32x4)"),
+    ("i32x4.any_true",       "makeUnary(s, UnaryOp::AnyTrueVecI32x4)"),
+    ("i32x4.all_true",       "makeUnary(s, UnaryOp::AllTrueVecI32x4)"),
+    ("i32x4.bitmask",        "makeUnary(s, UnaryOp::BitmaskVecI32x4)"),
+    ("i32x4.shl",            "makeSIMDShift(s, SIMDShiftOp::ShlVecI32x4)"),
+    ("i32x4.shr_s",          "makeSIMDShift(s, SIMDShiftOp::ShrSVecI32x4)"),
+    ("i32x4.shr_u",          "makeSIMDShift(s, SIMDShiftOp::ShrUVecI32x4)"),
+    ("i32x4.add",            "makeBinary(s, BinaryOp::AddVecI32x4)"),
+    ("i32x4.sub",            "makeBinary(s, BinaryOp::SubVecI32x4)"),
+    ("i32x4.mul",            "makeBinary(s, BinaryOp::MulVecI32x4)"),
+    ("i32x4.min_s",          "makeBinary(s, BinaryOp::MinSVecI32x4)"),
+    ("i32x4.min_u",          "makeBinary(s, BinaryOp::MinUVecI32x4)"),
+    ("i32x4.max_s",          "makeBinary(s, BinaryOp::MaxSVecI32x4)"),
+    ("i32x4.max_u",          "makeBinary(s, BinaryOp::MaxUVecI32x4)"),
+    ("i32x4.dot_i16x8_s",    "makeBinary(s, BinaryOp::DotSVecI16x8ToVecI32x4)"),
+    ("i64x2.neg",            "makeUnary(s, UnaryOp::NegVecI64x2)"),
+    ("i64x2.any_true",       "makeUnary(s, UnaryOp::AnyTrueVecI64x2)"),
+    ("i64x2.all_true",       "makeUnary(s, UnaryOp::AllTrueVecI64x2)"),
+    ("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)"),
+    ("f32x4.abs",            "makeUnary(s, UnaryOp::AbsVecF32x4)"),
+    ("f32x4.neg",            "makeUnary(s, UnaryOp::NegVecF32x4)"),
+    ("f32x4.sqrt",           "makeUnary(s, UnaryOp::SqrtVecF32x4)"),
+    ("f32x4.qfma",           "makeSIMDTernary(s, SIMDTernaryOp::QFMAF32x4)"),
+    ("f32x4.qfms",           "makeSIMDTernary(s, SIMDTernaryOp::QFMSF32x4)"),
+    ("f32x4.add",            "makeBinary(s, BinaryOp::AddVecF32x4)"),
+    ("f32x4.sub",            "makeBinary(s, BinaryOp::SubVecF32x4)"),
+    ("f32x4.mul",            "makeBinary(s, BinaryOp::MulVecF32x4)"),
+    ("f32x4.div",            "makeBinary(s, BinaryOp::DivVecF32x4)"),
+    ("f32x4.min",            "makeBinary(s, BinaryOp::MinVecF32x4)"),
+    ("f32x4.max",            "makeBinary(s, BinaryOp::MaxVecF32x4)"),
+    ("f32x4.pmin",           "makeBinary(s, BinaryOp::PMinVecF32x4)"),
+    ("f32x4.pmax",           "makeBinary(s, BinaryOp::PMaxVecF32x4)"),
+    ("f32x4.ceil",           "makeUnary(s, UnaryOp::CeilVecF32x4)"),
+    ("f32x4.floor",          "makeUnary(s, UnaryOp::FloorVecF32x4)"),
+    ("f32x4.trunc",          "makeUnary(s, UnaryOp::TruncVecF32x4)"),
+    ("f32x4.nearest",        "makeUnary(s, UnaryOp::NearestVecF32x4)"),
+    ("f64x2.abs",            "makeUnary(s, UnaryOp::AbsVecF64x2)"),
+    ("f64x2.neg",            "makeUnary(s, UnaryOp::NegVecF64x2)"),
+    ("f64x2.sqrt",           "makeUnary(s, UnaryOp::SqrtVecF64x2)"),
+    ("f64x2.qfma",           "makeSIMDTernary(s, SIMDTernaryOp::QFMAF64x2)"),
+    ("f64x2.qfms",           "makeSIMDTernary(s, SIMDTernaryOp::QFMSF64x2)"),
+    ("f64x2.add",            "makeBinary(s, BinaryOp::AddVecF64x2)"),
+    ("f64x2.sub",            "makeBinary(s, BinaryOp::SubVecF64x2)"),
+    ("f64x2.mul",            "makeBinary(s, BinaryOp::MulVecF64x2)"),
+    ("f64x2.div",            "makeBinary(s, BinaryOp::DivVecF64x2)"),
+    ("f64x2.min",            "makeBinary(s, BinaryOp::MinVecF64x2)"),
+    ("f64x2.max",            "makeBinary(s, BinaryOp::MaxVecF64x2)"),
+    ("f64x2.pmin",           "makeBinary(s, BinaryOp::PMinVecF64x2)"),
+    ("f64x2.pmax",           "makeBinary(s, BinaryOp::PMaxVecF64x2)"),
+    ("f64x2.ceil",           "makeUnary(s, UnaryOp::CeilVecF64x2)"),
+    ("f64x2.floor",          "makeUnary(s, UnaryOp::FloorVecF64x2)"),
+    ("f64x2.trunc",          "makeUnary(s, UnaryOp::TruncVecF64x2)"),
+    ("f64x2.nearest",        "makeUnary(s, UnaryOp::NearestVecF64x2)"),
+    ("i32x4.trunc_sat_f32x4_s",  "makeUnary(s, UnaryOp::TruncSatSVecF32x4ToVecI32x4)"),
+    ("i32x4.trunc_sat_f32x4_u",  "makeUnary(s, UnaryOp::TruncSatUVecF32x4ToVecI32x4)"),
+    ("i64x2.trunc_sat_f64x2_s",  "makeUnary(s, UnaryOp::TruncSatSVecF64x2ToVecI64x2)"),
+    ("i64x2.trunc_sat_f64x2_u",  "makeUnary(s, UnaryOp::TruncSatUVecF64x2ToVecI64x2)"),
+    ("f32x4.convert_i32x4_s",    "makeUnary(s, UnaryOp::ConvertSVecI32x4ToVecF32x4)"),
+    ("f32x4.convert_i32x4_u",    "makeUnary(s, UnaryOp::ConvertUVecI32x4ToVecF32x4)"),
+    ("f64x2.convert_i64x2_s",    "makeUnary(s, UnaryOp::ConvertSVecI64x2ToVecF64x2)"),
+    ("f64x2.convert_i64x2_u",    "makeUnary(s, UnaryOp::ConvertUVecI64x2ToVecF64x2)"),
+    ("v8x16.load_splat",         "makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec8x16)"),
+    ("v16x8.load_splat",         "makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec16x8)"),
+    ("v32x4.load_splat",         "makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec32x4)"),
+    ("v64x2.load_splat",         "makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec64x2)"),
+    ("i16x8.load8x8_s",          "makeSIMDLoad(s, SIMDLoadOp::LoadExtSVec8x8ToVecI16x8)"),
+    ("i16x8.load8x8_u",          "makeSIMDLoad(s, SIMDLoadOp::LoadExtUVec8x8ToVecI16x8)"),
+    ("i32x4.load16x4_s",         "makeSIMDLoad(s, SIMDLoadOp::LoadExtSVec16x4ToVecI32x4)"),
+    ("i32x4.load16x4_u",         "makeSIMDLoad(s, SIMDLoadOp::LoadExtUVec16x4ToVecI32x4)"),
+    ("i64x2.load32x2_s",         "makeSIMDLoad(s, SIMDLoadOp::LoadExtSVec32x2ToVecI64x2)"),
+    ("i64x2.load32x2_u",         "makeSIMDLoad(s, SIMDLoadOp::LoadExtUVec32x2ToVecI64x2)"),
+    ("v128.load32_zero",         "makeSIMDLoad(s, SIMDLoadOp::Load32Zero)"),
+    ("v128.load64_zero",         "makeSIMDLoad(s, SIMDLoadOp::Load64Zero)"),
+    ("i8x16.narrow_i16x8_s",     "makeBinary(s, BinaryOp::NarrowSVecI16x8ToVecI8x16)"),
+    ("i8x16.narrow_i16x8_u",     "makeBinary(s, BinaryOp::NarrowUVecI16x8ToVecI8x16)"),
+    ("i16x8.narrow_i32x4_s",     "makeBinary(s, BinaryOp::NarrowSVecI32x4ToVecI16x8)"),
+    ("i16x8.narrow_i32x4_u",     "makeBinary(s, BinaryOp::NarrowUVecI32x4ToVecI16x8)"),
+    ("i16x8.widen_low_i8x16_s",  "makeUnary(s, UnaryOp::WidenLowSVecI8x16ToVecI16x8)"),
+    ("i16x8.widen_high_i8x16_s", "makeUnary(s, UnaryOp::WidenHighSVecI8x16ToVecI16x8)"),
+    ("i16x8.widen_low_i8x16_u",  "makeUnary(s, UnaryOp::WidenLowUVecI8x16ToVecI16x8)"),
+    ("i16x8.widen_high_i8x16_u", "makeUnary(s, UnaryOp::WidenHighUVecI8x16ToVecI16x8)"),
+    ("i32x4.widen_low_i16x8_s",  "makeUnary(s, UnaryOp::WidenLowSVecI16x8ToVecI32x4)"),
+    ("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)"),
+    ("v8x16.swizzle",            "makeBinary(s, BinaryOp::SwizzleVec8x16)"),
+    # reference types instructions
+    # TODO Add table instructions
+    ("ref.null",             "makeRefNull(s)"),
+    ("ref.is_null",          "makeRefIsNull(s)"),
+    ("ref.func",             "makeRefFunc(s)"),
+    # exception handling instructions
+    ("try",                  "makeTry(s)"),
+    ("throw",                "makeThrow(s)"),
+    ("rethrow",              "makeRethrow(s)"),
+    ("br_on_exn",            "makeBrOnExn(s)"),
+    # Multivalue pseudoinstructions
+    ("tuple.make",           "makeTupleMake(s)"),
+    ("tuple.extract",        "makeTupleExtract(s)"),
+    ("pop",                  "makePop(s)"),
+    # GC
+    ("ref.eq",               "makeRefEq(s)"),
+    ("i31.new",              "makeI31New(s)"),
+    ("i31.get_s",            "makeI31Get(s, true)"),
+    ("i31.get_u",            "makeI31Get(s, false)"),
+    ("ref.test",             "makeRefTest(s)"),
+    ("ref.cast",             "makeRefCast(s)"),
+    ("br_on_cast",           "makeBrOnCast(s)"),
+    ("rtt.canon",            "makeRttCanon(s)"),
+    ("rtt.sub",              "makeRttSub(s)"),
+    ("struct.new_with_rtt",  "makeStructNew(s, false)"),
+    ("struct.new_default_with_rtt", "makeStructNew(s, true)"),
+    ("struct.get",           "makeStructGet(s)"),
+    ("struct.get_s",         "makeStructGet(s, true)"),
+    ("struct.get_u",         "makeStructGet(s, false)"),
+    ("struct.set",           "makeStructSet(s)"),
+    ("array.new_with_rtt",   "makeArrayNew(s, false)"),
+    ("array.new_default_with_rtt", "makeArrayNew(s, true)"),
+    ("array.get",           "makeArrayGet(s)"),
+    ("array.get_s",         "makeArrayGet(s, true)"),
+    ("array.get_u",         "makeArrayGet(s, false)"),
+    ("array.set",           "makeArraySet(s)"),
+    ("array.len",           "makeArrayLen(s)")
+]
+
+
+class CodePrinter:
+    indents = 0
+
+    def __enter__(self):
+        CodePrinter.indents += 1
+
+    def __exit__(self, *args):
+        CodePrinter.indents -= 1
+
+    def indent(self):
+        # call in a 'with' statement
+        return self
+
+    def print_line(self, line):
+        print("  " * CodePrinter.indents + line)
+
+
+class Node:
+    def __init__(self, expr=None, children=None, inst=None):
+        # the expression to return if this is the string has ended
+        self.expr = expr
+        # map unique strings to children nodes
+        self.children = children if children else {}
+        # full instruction leading to this node
+        self.inst = inst
+
+    def _common_prefix(a, b):
+        """Return the common prefix of two strings."""
+        prefix = []
+        while a and b and a[0] == b[0]:
+            prefix.append(a[0])
+            a = a[1:]
+            b = b[1:]
+        return "".join(prefix)
+
+    def do_insert(self, full_inst, inst, expr):
+        if not inst:
+            assert self.expr is None, "Repeated instruction " + full_inst
+            self.expr = expr
+            self.inst = full_inst
+            return
+        # find key with shared prefix
+        prefix, key = "", None
+        for k in self.children:
+            prefix = Node._common_prefix(inst, k)
+            if prefix:
+                key = k
+                break
+        if key is None:
+            # unique prefix, insert and stop
+            self.children[inst] = Node(expr, inst=full_inst)
+            return
+        key_remainder = key[len(prefix):]
+        if key_remainder:
+            # split key and move everything after the prefix to a new node
+            child = self.children.pop(key)
+            self.children[prefix] = Node(children={key_remainder: child})
+            # update key for recursive insert
+            key = prefix
+        # chop off prefix and recurse
+        self.children[key].do_insert(full_inst, inst[len(key):], expr)
+
+    def insert(self, inst, expr):
+        self.do_insert(inst, inst, expr)
+
+
+def instruction_parser():
+    """Build a trie out of all the instructions, then emit it as C++ code."""
+    trie = Node()
+    inst_length = 0
+    for inst, expr in instructions:
+        inst_length = max(inst_length, len(inst))
+        trie.insert(inst, expr)
+
+    printer = CodePrinter()
+
+    printer.print_line("char op[{}] = {{'\\0'}};".format(inst_length + 1))
+    printer.print_line("strncpy(op, s[0]->c_str(), {});".format(inst_length))
+
+    def print_leaf(expr, inst):
+        printer.print_line("if (strcmp(op, \"{inst}\") == 0) {{ return {expr}; }}"
+                           .format(inst=inst, expr=expr))
+        printer.print_line("goto parse_error;")
+
+    def emit(node, idx=0):
+        assert node.children
+        printer.print_line("switch (op[{}]) {{".format(idx))
+        with printer.indent():
+            if node.expr:
+                printer.print_line("case '\\0':")
+                with printer.indent():
+                    print_leaf(node.expr, node.inst)
+            children = sorted(node.children.items(), key=lambda pair: pair[0])
+            for prefix, child in children:
+                if child.children:
+                    printer.print_line("case '{}': {{".format(prefix[0]))
+                    with printer.indent():
+                        emit(child, idx + len(prefix))
+                    printer.print_line("}")
+                else:
+                    assert child.expr
+                    printer.print_line("case '{}':".format(prefix[0]))
+                    with printer.indent():
+                        print_leaf(child.expr, child.inst)
+            printer.print_line("default: goto parse_error;")
+        printer.print_line("}")
+
+    emit(trie)
+    printer.print_line("parse_error:")
+    with printer.indent():
+        printer.print_line("throw ParseException(std::string(op), s.line, s.col);")
+
+
+def print_header():
+    print("// DO NOT EDIT! This file generated by scripts/gen-s-parser.py\n")
+    print("// clang-format off\n")
+
+
+def print_footer():
+    print("\n// clang-format on")
+
+
+def generate_with_guard(generator, guard):
+    print("#ifdef {}".format(guard))
+    print("#undef {}".format(guard))
+    generator()
+    print("#endif // {}".format(guard))
+
+
+def main():
+    if sys.version_info.major != 3:
+        import datetime
+        print("It's " + str(datetime.datetime.now().year) + "! Use Python 3!")
+        sys.exit(1)
+    print_header()
+    generate_with_guard(instruction_parser, "INSTRUCTION_PARSER")
+    print_footer()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/binaryen/scripts/process_optimize_instructions.py b/binaryen/scripts/process_optimize_instructions.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/process_optimize_instructions.py
@@ -0,0 +1,16 @@
+#!/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/storage.py b/binaryen/scripts/storage.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/storage.py
@@ -0,0 +1,55 @@
+#!/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.
+
+from __future__ import print_function
+
+import glob
+import json
+import os
+import urllib2
+
+
+STORAGE_BASE = 'https://storage.googleapis.com/wasm-llvm/builds/git/'
+
+
+def download_revision(force_latest):
+    name = 'latest' if force_latest else 'lkgr'
+    downloaded = urllib2.urlopen(STORAGE_BASE + name).read().strip()
+    # TODO: for now try opening as JSON, if that doesn't work then the content is
+    #       just a hash. The waterfall is in the process of migrating to JSON.
+    info = None
+    try:
+        info = json.loads(downloaded)
+    except ValueError:
+        pass
+    return info['build'] if type(info) == dict else downloaded
+
+
+def download_tar(tar_pattern, directory, revision):
+    tar_path = os.path.join(directory, tar_pattern)
+    revision_tar_path = tar_path % revision
+    if os.path.isfile(revision_tar_path):
+        print('Already have `%s`' % revision_tar_path)
+    else:
+        print('Downloading `%s`' % revision_tar_path)
+        with open(revision_tar_path, 'w+') as f:
+            f.write(urllib2.urlopen(STORAGE_BASE + tar_pattern % revision).read())
+    # Remove any previous tarfiles.
+    for older_tar in glob.glob(tar_path % '*'):
+        if older_tar != revision_tar_path:
+            print('Removing older tar file `%s`' % older_tar)
+            os.remove(older_tar)
+    return revision_tar_path
diff --git a/binaryen/scripts/strip_local_names.py b/binaryen/scripts/strip_local_names.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/strip_local_names.py
@@ -0,0 +1,12 @@
+
+"""Removes local names. When you don't care about local names but do want
+to diff for structural changes, this can help.
+"""
+
+import sys
+
+for line in open(sys.argv[1]).readlines():
+    if '(local.tee ' in line or '(local.set ' in line or '(local.get ' in line:
+        print(line[:line.find('$')])
+    else:
+        print(line.rstrip())
diff --git a/binaryen/scripts/test/__init__.py b/binaryen/scripts/test/__init__.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/test/__init__.py
@@ -0,0 +1,15 @@
+# Copyright 2015 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.
+
+# Empty __init__.py file: Python treats the directory as containing a package.
diff --git a/binaryen/scripts/test/binaryenjs.py b/binaryen/scripts/test/binaryenjs.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/test/binaryenjs.py
@@ -0,0 +1,106 @@
+# 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.
+
+import os
+import subprocess
+
+from . import shared
+from . import support
+
+
+def do_test_binaryen_js_with(which):
+    if not (shared.MOZJS or shared.NODEJS):
+        shared.fail_with_error('no vm to run binaryen.js tests')
+
+    node_has_wasm = shared.NODEJS and support.node_has_webassembly(shared.NODEJS)
+    if not os.path.exists(which):
+        shared.fail_with_error('no ' + which + ' build to test')
+
+    print('\n[ checking binaryen.js testcases (' + which + ')... ]\n')
+
+    for s in sorted(os.listdir(os.path.join(shared.options.binaryen_test, 'binaryen.js'))):
+        if not s.endswith('.js'):
+            continue
+        print(s)
+        f = open('a.js', 'w')
+        # avoid stdout/stderr ordering issues in some js shells - use just stdout
+        f.write('''
+            console.warn = console.error = console.log;
+        ''')
+        binaryen_js = open(which).read()
+        f.write(binaryen_js)
+        test_path = os.path.join(shared.options.binaryen_test, 'binaryen.js', s)
+        test_src = open(test_path).read()
+        f.write(support.js_test_wrap().replace('%TEST%', test_src))
+        f.close()
+
+        def test(engine):
+            cmd = [engine, 'a.js']
+            if 'fatal' not in s:
+                out = support.run_command(cmd, stderr=subprocess.STDOUT)
+            else:
+                # expect an error - the specific error code will depend on the vm
+                out = support.run_command(cmd, stderr=subprocess.STDOUT, expected_status=None)
+            expected = open(os.path.join(shared.options.binaryen_test, 'binaryen.js', s + '.txt')).read()
+            if expected not in out:
+                shared.fail(out, expected)
+
+        # run in all possible shells
+        if shared.MOZJS:
+            test(shared.MOZJS)
+        if shared.NODEJS:
+            if node_has_wasm or 'WebAssembly.' not in test_src:
+                test(shared.NODEJS)
+            else:
+                print('Skipping ' + test_path + ' because WebAssembly might not be supported')
+
+
+def update_binaryen_js_tests():
+    if not (shared.MOZJS or shared.NODEJS):
+        print('no vm to run binaryen.js tests')
+        return
+
+    if not os.path.exists(shared.BINARYEN_JS):
+        print('no binaryen.js build to test')
+        return
+
+    print('\n[ checking binaryen.js testcases... ]\n')
+    node_has_wasm = shared.NODEJS and support.node_has_webassembly(shared.NODEJS)
+    for s in shared.get_tests(shared.get_test_dir('binaryen.js'), ['.js']):
+        basename = os.path.basename(s)
+        print(basename)
+        f = open('a.js', 'w')
+        f.write(open(shared.BINARYEN_JS).read())
+        test_src = open(s).read()
+        f.write(support.js_test_wrap().replace('%TEST%', test_src))
+        f.close()
+        if shared.MOZJS or node_has_wasm or 'WebAssembly.' not in test_src:
+            cmd = [shared.MOZJS or shared.NODEJS, 'a.js']
+            if 'fatal' not in basename:
+                out = support.run_command(cmd, stderr=subprocess.STDOUT)
+            else:
+                # expect an error - the specific error code will depend on the vm
+                out = support.run_command(cmd, stderr=subprocess.STDOUT, expected_status=None)
+            with open(s + '.txt', 'w') as o:
+                o.write(out)
+        else:
+            print('Skipping ' + basename + ' because WebAssembly might not be supported')
+
+
+def test_binaryen_js():
+    do_test_binaryen_js_with(shared.BINARYEN_JS)
+
+
+def test_binaryen_wasm():
+    do_test_binaryen_js_with(shared.BINARYEN_WASM)
diff --git a/binaryen/scripts/test/env.js b/binaryen/scripts/test/env.js
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/test/env.js
@@ -0,0 +1,15 @@
+// This is the name by which the tests import the wasm table.
+export const table = [];
+
+var tempRet0 = 0;
+
+export function setTempRet0(x) {
+  tempRet0 = x;
+}
+
+export function getTempRet0() {
+  return tempRet0;
+}
+
+export const memoryBase = 0;
+export const tableBase = 0;
diff --git a/binaryen/scripts/test/generate_lld_tests.py b/binaryen/scripts/test/generate_lld_tests.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/test/generate_lld_tests.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3
+#
+# 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.
+
+from __future__ import print_function
+
+import os
+import sys
+
+import shared
+import support
+
+
+def files_with_extensions(path, extensions):
+    for file in sorted(os.listdir(path)):
+        ext = os.path.splitext(file)[1]
+        if ext in extensions:
+            yield file, ext
+
+
+def generate_wat_files(llvm_bin, emscripten_root):
+    print('\n[ building wat files from C sources... ]\n')
+
+    lld_path = os.path.join(shared.options.binaryen_test, 'lld')
+    for src_file, ext in files_with_extensions(lld_path, ['.c', '.cpp', '.s']):
+        print('..', src_file)
+        obj_file = src_file.replace(ext, '.o')
+
+        src_path = os.path.join(lld_path, src_file)
+        obj_path = os.path.join(lld_path, obj_file)
+
+        wasm_file = src_file.replace(ext, '.wasm')
+        wat_file = src_file.replace(ext, '.wat')
+
+        obj_path = os.path.join(lld_path, obj_file)
+        wasm_path = os.path.join(lld_path, wasm_file)
+        wat_path = os.path.join(lld_path, wat_file)
+        is_shared = 'shared' 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',
+            '-Xclang', '-nobuiltininc',
+            '-Xclang', '-nostdsysteminc',
+            '-Xclang', '-I%s/system/include' % emscripten_root,
+            '-O1',
+        ]
+
+        link_cmd = [
+            os.path.join(llvm_bin, 'wasm-ld'), '-flavor', 'wasm',
+            '-z', '-stack-size=1048576',
+            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
+        # were included.
+        if 'longjmp' in src_file:
+            link_cmd.append('--strip-debug')
+        if is_shared:
+            compile_cmd.append('-fPIC')
+            compile_cmd.append('-fvisibility=default')
+            link_cmd.append('-shared')
+            link_cmd.append('--experimental-pic')
+        else:
+            link_cmd.append('--entry=main')
+
+        try:
+            support.run_command(compile_cmd)
+            support.run_command(link_cmd)
+            support.run_command(shared.WASM_DIS + [wasm_path, '-o', wat_path])
+        finally:
+            # Don't need the .o or .wasm files, don't leave them around
+            shared.delete_from_orbit(obj_path)
+            shared.delete_from_orbit(wasm_path)
+
+
+if __name__ == '__main__':
+    if len(shared.options.positional_args) != 2:
+        print('Usage: generate_lld_tests.py [llvm/bin/dir] [path/to/emscripten]')
+        sys.exit(1)
+    generate_wat_files(*shared.options.positional_args)
diff --git a/binaryen/scripts/test/lld.py b/binaryen/scripts/test/lld.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/test/lld.py
@@ -0,0 +1,104 @@
+# 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.
+
+import json
+import os
+from . import shared
+from . import support
+
+
+def args_for_finalize(filename):
+    ret = ['--global-base=568']
+    if 'safe_stack' in filename:
+        ret += ['--check-stack-overflow']
+    if 'shared' in filename:
+        ret += ['--side-module']
+    if 'standalone-wasm' in filename:
+        ret += ['--standalone-wasm']
+    if 'bigint' in filename:
+        ret += ['--bigint']
+    return ret
+
+
+def run_test(input_path):
+    print('..', input_path)
+    is_passive = '.passive.' in input_path
+    mem_file = input_path + '.mem'
+    extension_arg_map = {
+        '.out': [],
+    }
+    if not is_passive:
+        extension_arg_map.update({
+            '.mem.out': ['--separate-data-segments', mem_file],
+        })
+    for ext, args in extension_arg_map.items():
+        expected_file = input_path + ext
+        if not os.path.exists(expected_file):
+            if ext == '.out':
+                shared.fail_with_error('output ' + expected_file +
+                                       ' does not exist')
+            else:
+                continue
+
+        cmd = shared.WASM_EMSCRIPTEN_FINALIZE + [input_path, '-S'] + args
+        cmd += args_for_finalize(os.path.basename(input_path))
+        actual = support.run_command(cmd)
+
+        shared.fail_if_not_identical_to_file(actual, expected_file)
+        if ext == '.out':
+            start = actual.find('--BEGIN METADATA --\n')
+            end = actual.find('-- END METADATA --\n')
+            if start == -1 or end == -1:
+                shared.fail_with_error('json metadata tags not found')
+            the_json = actual[start + len('--BEGIN METADATA --\n'):end]
+            json.loads(the_json)
+
+        if ext == '.mem.out':
+            with open(mem_file) as mf:
+                mem = mf.read()
+                shared.fail_if_not_identical_to_file(mem, input_path + '.mem.mem')
+            os.remove(mem_file)
+
+
+def test_wasm_emscripten_finalize():
+    print('\n[ checking wasm-emscripten-finalize testcases... ]\n')
+
+    for input_path in shared.get_tests(shared.get_test_dir('lld'), ['.wat', '.wasm']):
+        run_test(input_path)
+
+
+def update_lld_tests():
+    print('\n[ updating wasm-emscripten-finalize testcases... ]\n')
+
+    for input_path in shared.get_tests(shared.get_test_dir('lld'), ['.wat', '.wasm']):
+        print('..', input_path)
+        is_passive = '.passive.' in input_path
+        mem_file = input_path + '.mem'
+        extension_arg_map = {
+            '.out': [],
+        }
+        if not is_passive:
+            extension_arg_map.update({
+                '.mem.out': ['--separate-data-segments', mem_file + '.mem'],
+            })
+        for ext, ext_args in extension_arg_map.items():
+            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 += 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/mod.ule.js b/binaryen/scripts/test/mod.ule.js
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/test/mod.ule.js
@@ -0,0 +1,4 @@
+
+export function ba_se() {
+  console.log('"mod.ule"."ba.se"');
+}
diff --git a/binaryen/scripts/test/node-esm-loader.mjs b/binaryen/scripts/test/node-esm-loader.mjs
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/test/node-esm-loader.mjs
@@ -0,0 +1,42 @@
+// originally lifted from https://nodejs.org/api/esm.html
+
+import path from 'path';
+import process from 'process';
+
+const baseURL = new URL('file://');
+const binaryen_root = path.dirname(path.dirname(process.cwd()));
+baseURL.pathname = `${binaryen_root}/`;
+
+const specialTestSuiteModules = {
+  'spectest': {
+    url: new URL('scripts/test/spectest.js', baseURL).href,
+    format: 'module'
+  },
+  'env': {
+    url: new URL('scripts/test/env.js', baseURL).href,
+    format: 'module'
+  },
+  'mod.ule': {
+    url: new URL('scripts/test/mod.ule.js', baseURL).href,
+    format: 'module'
+  }
+};
+
+export async function resolve(specifier, context, defaultResolve) {
+  const specialModule = specialTestSuiteModules[specifier];
+  if (specialModule) {
+    return specialModule;
+  }
+  return defaultResolve(specifier, context, defaultResolve);
+}
+
+export async function getFormat(url, context, defaultGetFormat) {
+  const specifiers = Object.keys(specialTestSuiteModules);
+  for (let i = 0, k = specifiers.length; i < k; ++i) {
+    const specialModule = specialTestSuiteModules[specifiers[i]];
+    if (specialModule.url == url) {
+      return specialModule;
+    }
+  }
+  return defaultGetFormat(url, context, defaultGetFormat);
+}
diff --git a/binaryen/scripts/test/shared.py b/binaryen/scripts/test/shared.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/test/shared.py
@@ -0,0 +1,536 @@
+# Copyright 2015 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.
+
+from __future__ import print_function
+
+import argparse
+import difflib
+import fnmatch
+import glob
+import os
+import shutil
+import subprocess
+import sys
+
+# The C++ standard whose features are required to build Binaryen.
+# Keep in sync with CMakeLists.txt CXX_STANDARD
+cxx_standard = 14
+
+
+def parse_args(args):
+    usage_str = ("usage: 'python check.py [options]'\n\n"
+                 "Runs the Binaryen test suite.")
+    parser = argparse.ArgumentParser(description=usage_str)
+    parser.add_argument(
+        '--torture', dest='torture', action='store_true', default=True,
+        help='Chooses whether to run the torture testcases. Default: true.')
+    parser.add_argument(
+        '--no-torture', dest='torture', action='store_false',
+        help='Disables running the torture testcases.')
+    parser.add_argument(
+        '--abort-on-first-failure', dest='abort_on_first_failure',
+        action='store_true', default=True,
+        help=('Specifies whether to halt test suite execution on first test error.'
+              ' Default: true.'))
+    parser.add_argument(
+        '--no-abort-on-first-failure', dest='abort_on_first_failure',
+        action='store_false',
+        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).'
+              ' If not specified, the environment variable BINARYEN_ROOT= can also'
+              ' be used to adjust this.'))
+    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.'))
+    parser.add_argument(
+        '--out-dir', dest='out_dir', default='',
+        help=('Specifies a path to the output directory for temp files, which '
+              'is also where the test runner changes directory into.'
+              ' Default:. out/test under the binaryen root.'))
+    parser.add_argument(
+        '--valgrind', dest='valgrind', default='',
+        help=('Specifies a path to Valgrind tool, which will be used to validate'
+              ' execution if specified. (Pass --valgrind=valgrind to search in'
+              ' PATH)'))
+    parser.add_argument(
+        '--valgrind-full-leak-check', dest='valgrind_full_leak_check',
+        action='store_true', default=False,
+        help=('If specified, all unfreed (but still referenced) pointers at the'
+              ' end of execution are considered memory leaks. Default: disabled.'))
+    parser.add_argument(
+        '--spec-test', action='append', nargs='*', default=[], dest='spec_tests',
+        help='Names specific spec tests to run.')
+    parser.add_argument(
+        'positional_args', metavar='TEST_SUITE', nargs='*',
+        help=('Names specific test suites to run. Use --list-suites to see a '
+              'list of all test suites'))
+    parser.add_argument(
+        '--list-suites', action='store_true',
+        help='List the test suites that can be run.')
+    parser.add_argument(
+        '--filter', dest='test_name_filter', default='',
+        help=('Specifies a filter. Only tests whose paths contains this '
+              'substring will be run'))
+
+    return parser.parse_args(args)
+
+
+options = parse_args(sys.argv[1:])
+requested = options.positional_args
+script_dir = os.path.dirname(os.path.abspath(__file__))
+
+num_failures = 0
+warnings = []
+
+
+def warn(text):
+    global warnings
+    warnings.append(text)
+    print('warning:', text, file=sys.stderr)
+
+
+# setup
+
+# Locate Binaryen build artifacts directory (bin/ by default)
+if not options.binaryen_bin:
+    if os.environ.get('BINARYEN_ROOT'):
+        if os.path.isdir(os.path.join(os.environ.get('BINARYEN_ROOT'), 'bin')):
+            options.binaryen_bin = os.path.join(
+                os.environ.get('BINARYEN_ROOT'), 'bin')
+        else:
+            options.binaryen_bin = os.environ.get('BINARYEN_ROOT')
+    else:
+        options.binaryen_bin = 'bin'
+
+options.binaryen_bin = os.path.normpath(os.path.abspath(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']
+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/ ?')
+
+# Locate Binaryen source directory if not specified.
+if not options.binaryen_root:
+    options.binaryen_root = os.path.dirname(os.path.dirname(script_dir))
+
+options.binaryen_test = os.path.join(options.binaryen_root, 'test')
+
+if not options.out_dir:
+    options.out_dir = os.path.join(options.binaryen_root, 'out', 'test')
+
+if not os.path.exists(options.out_dir):
+    os.makedirs(options.out_dir)
+os.chdir(options.out_dir)
+
+
+# Finds the given executable 'program' in PATH.
+# Operates like the Unix tool 'which'.
+def which(program):
+    def is_exe(fpath):
+        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+    fpath, fname = os.path.split(program)
+    if fpath:
+        if is_exe(program):
+            return program
+    else:
+        paths = [
+            # Prefer tools installed using third_party/setup.py
+            os.path.join(options.binaryen_root, 'third_party', 'mozjs'),
+            os.path.join(options.binaryen_root, 'third_party', 'v8'),
+            os.path.join(options.binaryen_root, 'third_party', 'wabt', 'bin')
+        ] + os.environ['PATH'].split(os.pathsep)
+        for path in paths:
+            path = path.strip('"')
+            exe_file = os.path.join(path, program)
+            if is_exe(exe_file):
+                return exe_file
+            if '.' not in fname:
+                if is_exe(exe_file + '.exe'):
+                    return exe_file + '.exe'
+                if is_exe(exe_file + '.cmd'):
+                    return exe_file + '.cmd'
+                if is_exe(exe_file + '.bat'):
+                    return exe_file + '.bat'
+
+
+WATERFALL_BUILD_DIR = os.path.join(options.binaryen_test, 'wasm-install')
+BIN_DIR = os.path.abspath(os.path.join(WATERFALL_BUILD_DIR, 'wasm-install', 'bin'))
+
+NATIVECC = (os.environ.get('CC') or which('mingw32-gcc') or
+            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'))
+MOZJS = which('mozjs') or which('spidermonkey')
+V8 = which('v8') or which('d8')
+
+BINARYEN_INSTALL_DIR = os.path.dirname(options.binaryen_bin)
+WASM_OPT = [os.path.join(options.binaryen_bin, 'wasm-opt')]
+WASM_AS = [os.path.join(options.binaryen_bin, 'wasm-as')]
+WASM_DIS = [os.path.join(options.binaryen_bin, 'wasm-dis')]
+ASM2WASM = [os.path.join(options.binaryen_bin, 'asm2wasm')]
+WASM2JS = [os.path.join(options.binaryen_bin, 'wasm2js')]
+WASM_CTOR_EVAL = [os.path.join(options.binaryen_bin, 'wasm-ctor-eval')]
+WASM_SHELL = [os.path.join(options.binaryen_bin, 'wasm-shell')]
+WASM_REDUCE = [os.path.join(options.binaryen_bin, 'wasm-reduce')]
+WASM_METADCE = [os.path.join(options.binaryen_bin, 'wasm-metadce')]
+WASM_EMSCRIPTEN_FINALIZE = [os.path.join(options.binaryen_bin,
+                                         'wasm-emscripten-finalize')]
+BINARYEN_JS = os.path.join(options.binaryen_bin, 'binaryen_js.js')
+BINARYEN_WASM = os.path.join(options.binaryen_bin, 'binaryen_wasm.js')
+
+
+def wrap_with_valgrind(cmd):
+    # Exit code 97 is arbitrary, used to easily detect when an error occurs that
+    # is detected by Valgrind.
+    valgrind = [options.valgrind, '--quiet', '--error-exitcode=97']
+    if options.valgrind_full_leak_check:
+        valgrind += ['--leak-check=full', '--show-leak-kinds=all']
+    return valgrind + cmd
+
+
+if options.valgrind:
+    WASM_OPT = wrap_with_valgrind(WASM_OPT)
+    WASM_AS = wrap_with_valgrind(WASM_AS)
+    WASM_DIS = wrap_with_valgrind(WASM_DIS)
+    ASM2WASM = wrap_with_valgrind(ASM2WASM)
+    WASM_SHELL = wrap_with_valgrind(WASM_SHELL)
+
+
+def in_binaryen(*args):
+    return os.path.join(options.binaryen_root, *args)
+
+
+os.environ['BINARYEN'] = in_binaryen()
+
+
+def get_platform():
+    return {'linux': 'linux',
+            'linux2': 'linux',
+            'darwin': 'mac',
+            'win32': 'windows',
+            'cygwin': 'windows'}[sys.platform]
+
+
+def has_shell_timeout():
+    return get_platform() != 'windows' and os.system('timeout 1s pwd') == 0
+
+
+# Default options to pass to v8. These enable all features.
+# See https://github.com/v8/v8/blob/master/src/wasm/wasm-feature-flags.h
+V8_OPTS = [
+    '--wasm-staging',
+    '--experimental-wasm-eh',
+    '--experimental-wasm-simd',
+    '--experimental-wasm-reftypes',
+    '--experimental-wasm-compilation-hints',
+    '--experimental-wasm-return-call'
+]
+
+# external tools
+
+try:
+    if NODEJS is not None:
+        subprocess.check_call([NODEJS, '--version'],
+                              stdout=subprocess.PIPE,
+                              stderr=subprocess.PIPE)
+except (OSError, subprocess.CalledProcessError):
+    NODEJS = None
+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
+def delete_from_orbit(filename):
+    try:
+        os.unlink(filename)
+    except OSError:
+        pass
+    if not os.path.exists(filename):
+        return
+    try:
+        shutil.rmtree(filename, ignore_errors=True)
+    except OSError:
+        pass
+    if not os.path.exists(filename):
+        return
+    try:
+        import stat
+        os.chmod(filename, os.stat(filename).st_mode | stat.S_IWRITE)
+
+        def remove_readonly_and_try_again(func, path, exc_info):
+            if not (os.stat(path).st_mode & stat.S_IWRITE):
+                os.chmod(path, os.stat(path).st_mode | stat.S_IWRITE)
+                func(path)
+            else:
+                raise
+        shutil.rmtree(filename, onerror=remove_readonly_and_try_again)
+    except OSError:
+        pass
+
+
+# This is a workaround for https://bugs.python.org/issue9400
+class Py2CalledProcessError(subprocess.CalledProcessError):
+    def __init__(self, returncode, cmd, output=None, stderr=None):
+        super(Exception, self).__init__(returncode, cmd, output, stderr)
+        self.returncode = returncode
+        self.cmd = cmd
+        self.output = output
+        self.stderr = stderr
+
+
+def run_process(cmd, check=True, input=None, capture_output=False, decode_output=True, *args, **kw):
+    if input and type(input) == str:
+        input = bytes(input, 'utf-8')
+    if capture_output:
+        kw['stdout'] = subprocess.PIPE
+        kw['stderr'] = subprocess.PIPE
+    ret = subprocess.run(cmd, check=check, input=input, *args, **kw)
+    if decode_output and ret.stdout is not None:
+        ret.stdout = ret.stdout.decode('utf-8')
+    if ret.stderr is not None:
+        ret.stderr = ret.stderr.decode('utf-8')
+    return ret
+
+
+def fail_with_error(msg):
+    global num_failures
+    try:
+        num_failures += 1
+        raise Exception(msg)
+    except Exception as e:
+        print(str(e))
+        if options.abort_on_first_failure:
+            raise
+
+
+def fail(actual, expected, fromfile='expected'):
+    diff_lines = difflib.unified_diff(
+        expected.split('\n'), actual.split('\n'),
+        fromfile=fromfile, tofile='actual')
+    diff_str = ''.join([a.rstrip() + '\n' for a in diff_lines])[:]
+    fail_with_error("incorrect output, diff:\n\n%s" % diff_str)
+
+
+def fail_if_not_identical(actual, expected, fromfile='expected'):
+    if expected != actual:
+        fail(actual, expected, fromfile=fromfile)
+
+
+def fail_if_not_contained(actual, expected):
+    if expected not in actual:
+        fail(actual, expected)
+
+
+def fail_if_not_identical_to_file(actual, expected_file):
+    binary = expected_file.endswith(".wasm") or type(actual) == bytes
+    with open(expected_file, 'rb' if binary else 'r') as f:
+        fail_if_not_identical(actual, f.read(), fromfile=expected_file)
+
+
+def get_test_dir(name):
+    """Returns the test directory located at BINARYEN_ROOT/test/[name]."""
+    return os.path.join(options.binaryen_test, name)
+
+
+def get_tests(test_dir, extensions=[]):
+    """Returns the list of test files in a given directory. 'extensions' is a
+    list of file extensions. If 'extensions' is empty, returns all files.
+    """
+    tests = []
+    if not extensions:
+        tests += glob.glob(os.path.join(test_dir, '*'))
+    for ext in extensions:
+        tests += glob.glob(os.path.join(test_dir, '*' + ext))
+    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:
+    options.spec_tests = get_tests(get_test_dir('spec'), ['.wast'])
+else:
+    options.spec_tests = options.spec_tests[:]
+
+# 11/27/2019: We updated the spec test suite to upstream spec repo. For some
+# files that started failing after this update, we added the new files to this
+# skip-list and preserved old ones by renaming them to 'old_[FILENAME].wast'
+# not to lose coverage. When the cause of the error is fixed or the unsupported
+# construct gets support so the new test passes, we can delete the
+# corresponding 'old_[FILENAME].wast' file. When you fix the new file and
+# delete the old file, make sure you rename the corresponding .wast.log file in
+# expected-output/ if any.
+SPEC_TESTS_TO_SKIP = [
+    # Stacky code / notation
+    'block.wast',
+    'call.wast',
+    'float_exprs.wast',
+    'globals.wast',
+    'loop.wast',
+    'nop.wast',
+    'select.wast',
+    'stack.wast',
+    'unwind.wast',
+
+    # Binary module
+    'binary.wast',
+    'binary-leb128.wast',
+    'custom.wast',
+
+    # Empty 'then' or 'else' in 'if'
+    'if.wast',
+    'local_set.wast',
+    'store.wast',
+
+    # No module in a file
+    'token.wast',
+    'utf8-custom-section-id.wast',
+    'utf8-import-field.wast',
+    'utf8-import-module.wast',
+    'utf8-invalid-encoding.wast',
+
+    # 'register' command
+    'imports.wast',
+    'linking.wast',
+
+    # Misc. unsupported constructs
+    'call_indirect.wast',  # Empty (param) and (result)
+    'const.wast',  # Unparenthesized expression
+    'data.wast',  # Various unsupported (data) notations
+    'elem.wast',  # Unsupported 'offset' syntax in (elem)
+    'exports.wast',  # Multiple inlined exports for a function
+    'func.wast',  # Forward named type reference
+    'skip-stack-guard-page.wast',  # Hexadecimal style (0x..) in memory offset
+
+    # Untriaged: We don't know the cause of the error yet
+    'address.wast',  # wasm2js 'assert_return' failure
+    'br_if.wast',  # Validation error
+    'float_literals.wast',  # 'assert_return' failure
+    'int_literals.wast',  # 'assert_return' failure
+    'local_tee.wast',  # Validation failure
+    'memory_grow.wast',  # 'assert_return' failure
+    'start.wast',  # Assertion failure
+    'type.wast',  # 'assertion_invalid' failure
+    'unreachable.wast',  # Validation failure
+    'unreached-invalid.wast'  # 'assert_invalid' failure
+]
+options.spec_tests = [t for t in options.spec_tests if os.path.basename(t) not
+                      in SPEC_TESTS_TO_SKIP]
+
+
+# check utilities
+
+def binary_format_check(wast, verify_final_result=True, wasm_as_args=['-g'],
+                        binary_suffix='.fromBinary', original_wast=None):
+    # checks we can convert the wast to binary and back
+
+    print('         (binary format check)')
+    cmd = WASM_AS + [wast, '-o', 'a.wasm', '-all'] + wasm_as_args
+    print('            ', ' '.join(cmd))
+    if os.path.exists('a.wasm'):
+        os.unlink('a.wasm')
+    subprocess.check_call(cmd, stdout=subprocess.PIPE)
+    assert os.path.exists('a.wasm')
+
+    cmd = WASM_DIS + ['a.wasm', '-o', 'ab.wast']
+    print('            ', ' '.join(cmd))
+    if os.path.exists('ab.wast'):
+        os.unlink('ab.wast')
+    subprocess.check_call(cmd, stdout=subprocess.PIPE)
+    assert os.path.exists('ab.wast')
+
+    # make sure it is a valid wast
+    cmd = WASM_OPT + ['ab.wast', '-all']
+    print('            ', ' '.join(cmd))
+    subprocess.check_call(cmd, stdout=subprocess.PIPE)
+
+    if verify_final_result:
+        actual = open('ab.wast').read()
+        fail_if_not_identical_to_file(actual, wast + binary_suffix)
+
+    return 'ab.wast'
+
+
+def minify_check(wast, verify_final_result=True):
+    # checks we can parse minified output
+
+    print('     (minify check)')
+    cmd = WASM_OPT + [wast, '--print-minified', '-all']
+    print('      ', ' '.join(cmd))
+    subprocess.check_call(cmd, stdout=open('a.wast', 'w'), stderr=subprocess.PIPE)
+    assert os.path.exists('a.wast')
+    subprocess.check_call(WASM_OPT + ['a.wast', '--print-minified', '-all'],
+                          stdout=open('b.wast', 'w'), stderr=subprocess.PIPE)
+    assert os.path.exists('b.wast')
+    if verify_final_result:
+        expected = open('a.wast').read()
+        actual = open('b.wast').read()
+        if actual != expected:
+            fail(actual, expected)
+    if os.path.exists('a.wast'):
+        os.unlink('a.wast')
+    if os.path.exists('b.wast'):
+        os.unlink('b.wast')
+
+
+# run a check with BINARYEN_PASS_DEBUG set, to do full validation
+def with_pass_debug(check):
+    old_pass_debug = os.environ.get('BINARYEN_PASS_DEBUG')
+    try:
+        os.environ['BINARYEN_PASS_DEBUG'] = '1'
+        check()
+    finally:
+        if old_pass_debug is not None:
+            os.environ['BINARYEN_PASS_DEBUG'] = old_pass_debug
+        else:
+            if 'BINARYEN_PASS_DEBUG' in os.environ:
+                del os.environ['BINARYEN_PASS_DEBUG']
+
+
+# checks if we are on windows, and if so logs out that a test is being skipped,
+# and returns True. This is a central location for all test skipping on
+# windows, so that we can easily find which tests are skipped.
+def skip_if_on_windows(name):
+    if get_platform() == 'windows':
+        print('skipping test "%s" on windows' % name)
+        return True
+    return False
diff --git a/binaryen/scripts/test/spectest.js b/binaryen/scripts/test/spectest.js
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/test/spectest.js
@@ -0,0 +1,20 @@
+export function print() {
+  console.log();
+}
+export function print_i32(arg) {
+  console.log(arg, ': i32');
+}
+export function print_f32(arg) {
+  console.log(arg, ': f32');
+}
+export function print_f64(arg) {
+  console.log(arg, ': f64');
+}
+export function print_i32_f32(arg0, arg1) {
+  console.log(arg0, ': i32');
+  console.log(arg1, ': f32');
+}
+export function print_f64_f64(arg0, arg1) {
+  console.log(arg0, ': f64');
+  console.log(arg1, ': f64');
+}
diff --git a/binaryen/scripts/test/support.py b/binaryen/scripts/test/support.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/test/support.py
@@ -0,0 +1,206 @@
+# 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.
+
+import filecmp
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+
+
+def _open_archive(tarfile, tmp_dir):
+    with tempfile.TemporaryFile(mode='w+') as f:
+        try:
+            subprocess.check_call(['tar', '-xvf', tarfile], cwd=tmp_dir, stdout=f)
+        except Exception:
+            f.seek(0)
+            sys.stderr.write(f.read())
+            raise
+    return os.listdir(tmp_dir)
+
+
+def _files_same(dir1, dir2, basenames):
+    diff = filecmp.cmpfiles(dir1, dir2, basenames)
+    return 0 == len(diff[1] + diff[2])
+
+
+def _dirs_same(dir1, dir2, basenames):
+    for d in basenames:
+        left = os.path.join(dir1, d)
+        right = os.path.join(dir2, d)
+        if not (os.path.isdir(left) and os.path.isdir(right)):
+            return False
+        diff = filecmp.dircmp(right, right)
+        if 0 != len(diff.left_only + diff.right_only + diff.diff_files +
+                    diff.common_funny + diff.funny_files):
+            return False
+    return True
+
+
+def _move_files(dirfrom, dirto, basenames):
+    for f in basenames:
+        from_file = os.path.join(dirfrom, f)
+        to_file = os.path.join(dirto, f)
+        if os.path.isfile(to_file):
+            os.path.remove(to_file)
+        shutil.move(from_file, to_file)
+
+
+def _move_dirs(dirfrom, dirto, basenames):
+    for d in basenames:
+        from_dir = os.path.join(dirfrom, d)
+        to_dir = os.path.join(dirto, d)
+        if os.path.isdir(to_dir):
+            shutil.rmtree(to_dir)
+        shutil.move(from_dir, to_dir)
+
+
+def untar(tarfile, outdir):
+    """Returns True if untar content differs from pre-existing outdir content."""
+    tmpdir = tempfile.mkdtemp()
+    try:
+        untared = _open_archive(tarfile, tmpdir)
+        files = [f for f in untared if os.path.isfile(os.path.join(tmpdir, f))]
+        dirs = [d for d in untared if os.path.isdir(os.path.join(tmpdir, d))]
+        assert len(files) + len(dirs) == len(untared), 'Only files and directories'
+        if _files_same(tmpdir, outdir, files) and _dirs_same(tmpdir, outdir, dirs):
+            # Nothing new or different in the tarfile.
+            return False
+        # Some or all of the files / directories are new.
+        _move_files(tmpdir, outdir, files)
+        _move_dirs(tmpdir, outdir, dirs)
+        return True
+    finally:
+        if os.path.isdir(tmpdir):
+            shutil.rmtree(tmpdir)
+
+
+def split_wast(wastFile):
+    # if it's a binary, leave it as is, we can't split it
+    wast = None
+    if not wastFile.endswith('.wasm'):
+        try:
+            wast = open(wastFile, 'r').read()
+        except Exception:
+            pass
+
+    if not wast:
+        return ((open(wastFile, 'rb').read(), []),)
+
+    # .wast files can contain multiple modules, and assertions for each one.
+    # this splits out a wast into [(module, assertions), ..]
+    # we ignore module invalidity tests here.
+    ret = []
+
+    def to_end(j):
+        depth = 1
+        while depth > 0 and j < len(wast):
+            if wast[j] == '"':
+                while 1:
+                    j = wast.find('"', j + 1)
+                    if wast[j - 1] == '\\':
+                        continue
+                    break
+                assert j > 0
+            elif wast[j] == '(':
+                depth += 1
+            elif wast[j] == ')':
+                depth -= 1
+            elif wast[j] == ';' and wast[j + 1] == ';':
+                j = wast.find('\n', j)
+            j += 1
+        return j
+
+    i = 0
+    while i >= 0:
+        start = wast.find('(', i)
+        if start >= 0 and wast[start + 1] == ';':
+            # block comment
+            i = wast.find(';)', start + 2)
+            assert i > 0, wast[start:]
+            i += 2
+            continue
+        skip = wast.find(';', i)
+        if skip >= 0 and skip < start and skip + 1 < len(wast):
+            if wast[skip + 1] == ';':
+                i = wast.find('\n', i) + 1
+                continue
+        if start < 0:
+            break
+        i = to_end(start + 1)
+        chunk = wast[start:i]
+        if chunk.startswith('(module'):
+            ret += [(chunk, [])]
+        elif chunk.startswith('(assert_invalid'):
+            continue
+        elif chunk.startswith(('(assert', '(invoke')):
+            # ret may be empty if there are some asserts before the first
+            # module. in that case these are asserts *without* a module, which
+            # are valid (they may check something that doesn't refer to a module
+            # in any way).
+            if not ret:
+                ret += [(None, [])]
+            ret[-1][1].append(chunk)
+    return ret
+
+
+# write a split wast from split_wast. the wast may be binary if the original
+# file was binary
+def write_wast(filename, wast, asserts=[]):
+    if type(wast) == bytes:
+        assert not asserts
+        with open(filename, 'wb') as o:
+            o.write(wast)
+    else:
+        with open(filename, 'w') as o:
+            o.write(wast + '\n'.join(asserts))
+
+
+def run_command(cmd, expected_status=0, stderr=None,
+                expected_err=None, err_contains=False, err_ignore=None):
+    if expected_err is not None:
+        assert stderr == subprocess.PIPE or stderr is None,\
+            "Can't redirect stderr if using expected_err"
+        stderr = subprocess.PIPE
+    print('executing: ', ' '.join(cmd))
+    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=stderr, universal_newlines=True, encoding='UTF-8')
+    out, err = proc.communicate()
+    code = proc.returncode
+    if expected_status is not None and code != expected_status:
+        raise Exception(('run_command failed (%s)' % code, out + str(err or '')))
+    if expected_err is not None:
+        if err_ignore is not None:
+            err = "\n".join([line for line in err.split('\n') if err_ignore not in line])
+        err_correct = expected_err in err if err_contains else expected_err == err
+        if not err_correct:
+            raise Exception(('run_command unexpected stderr',
+                             "expected '%s', actual '%s'" % (expected_err, err)))
+    return out
+
+
+def node_has_webassembly(cmd):
+    cmd = [cmd, '-e', 'process.stdout.write(typeof WebAssembly)']
+    return run_command(cmd) == 'object'
+
+
+def js_test_wrap():
+    # common wrapper code for JS tests, waiting for binaryen.js to become ready
+    # and providing common utility used by all tests:
+    return '''
+        binaryen.ready.then(function() {
+            function assert(x) { if (!x) throw Error('Test assertion failed'); }
+            %TEST%
+        });
+    '''
diff --git a/binaryen/scripts/test/wasm2js.py b/binaryen/scripts/test/wasm2js.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/test/wasm2js.py
@@ -0,0 +1,214 @@
+# 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.
+
+import os
+
+from scripts.test import shared
+from scripts.test import support
+
+tests = shared.get_tests(shared.options.binaryen_test)
+# memory64 is not supported in wasm2js yet (but may be with BigInt eventually).
+tests = [t for t in tests if '64.wast' not in t]
+spec_tests = shared.options.spec_tests
+spec_tests = [t for t in spec_tests if '.fail' not in t]
+spec_tests = [t for t in spec_tests if '64.wast' not in t]
+wasm2js_tests = shared.get_tests(shared.get_test_dir('wasm2js'), ['.wast'])
+assert_tests = ['wasm2js.wast.asserts']
+# These tests exercise functionality not supported by wasm2js
+wasm2js_blacklist = ['empty_imported_table.wast']
+
+
+def check_for_stale_files():
+    if shared.options.test_name_filter:
+        return
+
+    # TODO(sbc): Generalize and apply other test suites
+    all_tests = []
+    for t in tests + spec_tests + wasm2js_tests:
+        all_tests.append(os.path.basename(os.path.splitext(t)[0]))
+
+    all_files = os.listdir(shared.get_test_dir('wasm2js'))
+    for f in all_files:
+        prefix = f.split('.')[0]
+        if prefix not in all_tests:
+            shared.fail_with_error('orphan test output: %s' % f)
+
+
+def test_wasm2js_output():
+    for opt in (0, 1):
+        for t in tests + spec_tests + wasm2js_tests:
+            basename = os.path.basename(t)
+            if basename in wasm2js_blacklist:
+                continue
+
+            asm = basename.replace('.wast', '.2asm.js')
+            expected_file = os.path.join(shared.get_test_dir('wasm2js'), asm)
+            if opt:
+                expected_file += '.opt'
+
+            if not os.path.exists(expected_file):
+                continue
+
+            print('..', os.path.basename(t))
+
+            all_js = []
+            all_out = ''
+
+            for module, asserts in support.split_wast(t):
+                support.write_wast('split.wast', module, asserts)
+
+                # wasm2js does not yet support EH, and enabling it can reduce
+                # optimization opportunities
+                cmd = shared.WASM2JS + ['split.wast', '-all',
+                                        '--disable-exception-handling']
+                if opt:
+                    cmd += ['-O']
+                if 'emscripten' in t:
+                    cmd += ['--emscripten']
+                if 'deterministic' in t:
+                    cmd += ['--deterministic']
+                js = support.run_command(cmd)
+                all_js.append(js)
+
+                if not shared.NODEJS and not shared.MOZJS:
+                    print('No JS interpreters. Skipping spec tests.')
+                    continue
+
+                open('a.2asm.mjs', 'w').write(js)
+
+                cmd += ['--allow-asserts']
+                js = support.run_command(cmd)
+                # also verify it passes pass-debug verifications
+                shared.with_pass_debug(lambda: support.run_command(cmd))
+
+                open('a.2asm.asserts.mjs', 'w').write(js)
+
+                # verify asm.js is valid js, note that we're using --experimental-modules
+                # to enable ESM syntax and we're also passing a custom loader to handle the
+                # `spectest` and `env` modules in our tests.
+                if shared.NODEJS:
+                    loader = os.path.join(shared.options.binaryen_root, 'scripts', 'test', 'node-esm-loader.mjs')
+                    node = [shared.NODEJS, '--experimental-modules', '--no-warnings', '--loader', loader]
+                    cmd = node[:]
+                    cmd.append('a.2asm.mjs')
+                    out = support.run_command(cmd)
+                    shared.fail_if_not_identical(out, '')
+                    cmd = node[:]
+                    cmd.append('a.2asm.asserts.mjs')
+                    out = support.run_command(cmd, expected_err='', err_ignore='ExperimentalWarning')
+                    all_out += out
+
+            shared.fail_if_not_identical_to_file(''.join(all_js), expected_file)
+            expected_out = os.path.join(shared.get_test_dir('spec'), 'expected-output', os.path.basename(t) + '.log')
+            if os.path.exists(expected_out):
+                expected_out = open(expected_out).read()
+            else:
+                expected_out = ''
+            shared.fail_if_not_identical(all_out, expected_out)
+
+
+def test_asserts_output():
+    for wasm in assert_tests:
+        print('..', wasm)
+
+        asserts = os.path.basename(wasm).replace('.wast.asserts', '.asserts.js')
+        traps = os.path.basename(wasm).replace('.wast.asserts', '.traps.js')
+        asserts_expected_file = os.path.join(shared.options.binaryen_test, asserts)
+        traps_expected_file = os.path.join(shared.options.binaryen_test, traps)
+
+        wasm = os.path.join(shared.get_test_dir('wasm2js'), wasm)
+        cmd = shared.WASM2JS + [wasm, '--allow-asserts', '-all',
+                                '--disable-exception-handling']
+        out = support.run_command(cmd)
+        shared.fail_if_not_identical_to_file(out, asserts_expected_file)
+
+        cmd += ['--pedantic']
+        out = support.run_command(cmd)
+        shared.fail_if_not_identical_to_file(out, traps_expected_file)
+
+
+def test_wasm2js():
+    print('\n[ checking wasm2js testcases... ]\n')
+    check_for_stale_files()
+    if shared.skip_if_on_windows('wasm2js'):
+        return
+    test_wasm2js_output()
+    test_asserts_output()
+
+
+def update_wasm2js_tests():
+    print('\n[ checking wasm2js ]\n')
+
+    for opt in (0, 1):
+        for wasm in tests + spec_tests + wasm2js_tests:
+            if not wasm.endswith('.wast'):
+                continue
+
+            if os.path.basename(wasm) in wasm2js_blacklist:
+                continue
+
+            asm = os.path.basename(wasm).replace('.wast', '.2asm.js')
+            expected_file = os.path.join(shared.get_test_dir('wasm2js'), asm)
+            if opt:
+                expected_file += '.opt'
+
+            # we run wasm2js on tests and spec tests only if the output
+            # exists - only some work so far. the tests in extra are in
+            # the test/wasm2js dir and so are specific to wasm2js, and
+            # we run all of those.
+            if wasm not in wasm2js_tests and not os.path.exists(expected_file):
+                continue
+
+            print('..', wasm)
+
+            t = os.path.join(shared.options.binaryen_test, wasm)
+
+            all_out = []
+
+            for module, asserts in support.split_wast(t):
+                support.write_wast('split.wast', module, asserts)
+
+                # wasm2js does not yet support EH, and enable it can reduce
+                # optimization opportunities
+                cmd = shared.WASM2JS + ['split.wast', '-all',
+                                        '--disable-exception-handling']
+                if opt:
+                    cmd += ['-O']
+                if 'emscripten' in wasm:
+                    cmd += ['--emscripten']
+                if 'deterministic' in t:
+                    cmd += ['--deterministic']
+                out = support.run_command(cmd)
+                all_out.append(out)
+
+            with open(expected_file, 'w') as o:
+                o.write(''.join(all_out))
+
+    for wasm in assert_tests:
+        print('..', wasm)
+
+        asserts = os.path.basename(wasm).replace('.wast.asserts', '.asserts.js')
+        traps = os.path.basename(wasm).replace('.wast.asserts', '.traps.js')
+        asserts_expected_file = os.path.join(shared.options.binaryen_test, asserts)
+        traps_expected_file = os.path.join(shared.options.binaryen_test, traps)
+
+        cmd = shared.WASM2JS + [os.path.join(shared.get_test_dir('wasm2js'), wasm), '--allow-asserts', '-all', '--disable-exception-handling']
+        out = support.run_command(cmd)
+        with open(asserts_expected_file, 'w') as o:
+            o.write(out)
+
+        cmd += ['--pedantic']
+        out = support.run_command(cmd)
+        with open(traps_expected_file, 'w') as o:
+            o.write(out)
diff --git a/binaryen/scripts/test/wasm_opt.py b/binaryen/scripts/test/wasm_opt.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/test/wasm_opt.py
@@ -0,0 +1,238 @@
+# 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.
+
+import os
+import shutil
+import subprocess
+
+from . import shared
+from . import support
+
+
+def test_wasm_opt():
+    print('\n[ checking wasm-opt -o notation... ]\n')
+
+    for extra_args in [[], ['--no-validation']]:
+        wast = os.path.join(shared.options.binaryen_test, 'hello_world.wat')
+        shared.delete_from_orbit('a.wat')
+        out = 'a.wat'
+        cmd = shared.WASM_OPT + [wast, '-o', out, '-S'] + extra_args
+        support.run_command(cmd)
+        shared.fail_if_not_identical_to_file(open(out).read(), wast)
+
+    print('\n[ checking wasm-opt binary reading/writing... ]\n')
+
+    shutil.copyfile(os.path.join(shared.options.binaryen_test, 'hello_world.wat'), 'a.wat')
+    shared.delete_from_orbit('a.wasm')
+    shared.delete_from_orbit('b.wast')
+    support.run_command(shared.WASM_OPT + ['a.wat', '-o', 'a.wasm'])
+    assert open('a.wasm', 'rb').read()[0] == 0, 'we emit binary by default'
+    support.run_command(shared.WASM_OPT + ['a.wasm', '-o', 'b.wast', '-S'])
+    assert open('b.wast', 'rb').read()[0] != 0, 'we emit text with -S'
+
+    print('\n[ checking wasm-opt passes... ]\n')
+
+    for t in shared.get_tests(shared.get_test_dir('passes'), ['.wast', '.wasm']):
+        print('..', os.path.basename(t))
+        # windows has some failures that need to be investigated:
+        # * ttf tests have different outputs - order of execution of params?
+        # * dwarf tests print windows slashes instead of unix
+        if ('translate-to-fuzz' in t or 'dwarf' in t) and \
+           shared.skip_if_on_windows('fuzz translation tests'):
+            continue
+        binary = '.wasm' in t
+        base = os.path.basename(t).replace('.wast', '').replace('.wasm', '')
+        passname = base
+        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('_')]
+        actual = ''
+        for module, asserts in support.split_wast(t):
+            assert len(asserts) == 0
+            support.write_wast('split.wast', module)
+            cmd = shared.WASM_OPT + opts + ['split.wast']
+            if 'noprint' not in t:
+                cmd.append('--print')
+            curr = support.run_command(cmd)
+            actual += curr
+            # also check debug mode output is valid
+            debugged = support.run_command(cmd + ['--debug'], stderr=subprocess.PIPE)
+            shared.fail_if_not_contained(actual, debugged)
+
+            # also check pass-debug mode
+            def check():
+                pass_debug = support.run_command(cmd)
+                shared.fail_if_not_identical(curr, pass_debug)
+            shared.with_pass_debug(check)
+
+        expected_file = os.path.join(shared.get_test_dir('passes'), base + ('.bin' if binary else '') + '.txt')
+        shared.fail_if_not_identical_to_file(actual, expected_file)
+
+        if 'emit-js-wrapper' in t:
+            with open('a.js') as actual:
+                shared.fail_if_not_identical_to_file(actual.read(), t + '.js')
+        if 'emit-spec-wrapper' in t:
+            with open('a.wat') as actual:
+                shared.fail_if_not_identical_to_file(actual.read(), t + '.wat')
+
+    print('\n[ checking wasm-opt parsing & printing... ]\n')
+
+    for t in shared.get_tests(shared.get_test_dir('print'), ['.wast']):
+        print('..', os.path.basename(t))
+        wasm = os.path.basename(t).replace('.wast', '')
+        cmd = shared.WASM_OPT + [t, '--print', '-all']
+        print('    ', ' '.join(cmd))
+        actual, err = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True).communicate()
+        expected_file = os.path.join(shared.get_test_dir('print'), wasm + '.txt')
+        shared.fail_if_not_identical_to_file(actual, expected_file)
+        cmd = shared.WASM_OPT + [os.path.join(shared.get_test_dir('print'), t), '--print-minified', '-all']
+        print('    ', ' '.join(cmd))
+        actual, err = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True).communicate()
+        shared.fail_if_not_identical(actual.strip(), open(os.path.join(shared.get_test_dir('print'), wasm + '.minified.txt')).read().strip())
+
+    print('\n[ checking wasm-opt testcases... ]\n')
+
+    for t in shared.get_tests(shared.options.binaryen_test, ['.wast']):
+        print('..', os.path.basename(t))
+        f = t + '.from-wast'
+        cmd = shared.WASM_OPT + [t, '--print', '-all']
+        actual = support.run_command(cmd)
+        actual = actual.replace('printing before:\n', '')
+
+        shared.fail_if_not_identical_to_file(actual, f)
+
+        # FIXME Remove this condition after nullref is implemented in V8
+        if 'reference-types.wast' not in t:
+            shared.binary_format_check(t, wasm_as_args=['-g'])  # test with debuginfo
+            shared.binary_format_check(t, wasm_as_args=[], binary_suffix='.fromBinary.noDebugInfo')  # test without debuginfo
+
+        shared.minify_check(t)
+
+    print('\n[ checking wasm-opt debugInfo read-write... ]\n')
+
+    for t in shared.get_tests(shared.options.binaryen_test, ['.fromasm']):
+        if 'debugInfo' not in t:
+            continue
+        print('..', os.path.basename(t))
+        f = t + '.read-written'
+        support.run_command(shared.WASM_AS + [t, '--source-map=a.map', '-o', 'a.wasm', '-g'])
+        support.run_command(shared.WASM_OPT + ['a.wasm', '--input-source-map=a.map', '-o', 'b.wasm', '--output-source-map=b.map', '-g'])
+        actual = support.run_command(shared.WASM_DIS + ['b.wasm', '--source-map=b.map'])
+        shared.fail_if_not_identical_to_file(actual, f)
+
+
+def update_wasm_opt_tests():
+    print('\n[ checking wasm-opt -o notation... ]\n')
+    wast = os.path.join(shared.options.binaryen_test, 'hello_world.wat')
+    cmd = shared.WASM_OPT + [wast, '-o', 'a.wast', '-S']
+    support.run_command(cmd)
+    open(wast, 'w').write(open('a.wast').read())
+
+    print('\n[ checking wasm-opt parsing & printing... ]\n')
+    for t in shared.get_tests(shared.get_test_dir('print'), ['.wast']):
+        print('..', os.path.basename(t))
+        wasm = t.replace('.wast', '')
+        cmd = shared.WASM_OPT + [t, '--print', '-all']
+        print('    ', ' '.join(cmd))
+        actual = subprocess.check_output(cmd)
+        print(cmd, actual)
+        with open(wasm + '.txt', 'wb') as o:
+            o.write(actual)
+        cmd = shared.WASM_OPT + [t, '--print-minified', '-all']
+        print('    ', ' '.join(cmd))
+        actual = subprocess.check_output(cmd)
+        with open(wasm + '.minified.txt', 'wb') as o:
+            o.write(actual)
+
+    print('\n[ checking wasm-opt passes... ]\n')
+    for t in shared.get_tests(shared.get_test_dir('passes'), ['.wast', '.wasm']):
+        print('..', os.path.basename(t))
+        # windows has some failures that need to be investigated:
+        # * ttf tests have different outputs - order of execution of params?
+        # * dwarf tests print windows slashes instead of unix
+        if ('translate-to-fuzz' in t or 'dwarf' in t) and \
+           shared.skip_if_on_windows('fuzz translation tests'):
+            continue
+        binary = t.endswith('.wasm')
+        base = os.path.basename(t).replace('.wast', '').replace('.wasm', '')
+        passname = base
+        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('_')]
+        actual = ''
+        for module, asserts in support.split_wast(t):
+            assert len(asserts) == 0
+            support.write_wast('split.wast', module)
+            cmd = shared.WASM_OPT + opts + ['split.wast']
+            if 'noprint' not in t:
+                cmd.append('--print')
+            actual += support.run_command(cmd)
+        with open(os.path.join(shared.options.binaryen_test, 'passes', base + ('.bin' if binary else '') + '.txt'), 'w') as o:
+            o.write(actual)
+        if 'emit-js-wrapper' in t:
+            with open('a.js') as i:
+                with open(t + '.js', 'w') as o:
+                    o.write(i.read())
+        if 'emit-spec-wrapper' in t:
+            with open('a.wat') as i:
+                with open(t + '.wat', 'w') as o:
+                    o.write(i.read())
+
+    print('\n[ checking wasm-opt testcases... ]\n')
+    for t in shared.get_tests(shared.options.binaryen_test, ['.wast']):
+        print('..', os.path.basename(t))
+        f = t + '.from-wast'
+        cmd = shared.WASM_OPT + [t, '--print', '-all']
+        actual = support.run_command(cmd)
+        actual = actual.replace('printing before:\n', '')
+        open(f, 'w').write(actual)
+
+    print('\n[ checking wasm-opt debugInfo read-write... ]\n')
+    for t in shared.get_tests(shared.options.binaryen_test, ['.fromasm']):
+        if 'debugInfo' not in t:
+            continue
+        print('..', os.path.basename(t))
+        f = t + '.read-written'
+        support.run_command(shared.WASM_AS + [t, '--source-map=a.map', '-o', 'a.wasm', '-g'])
+        support.run_command(shared.WASM_OPT + ['a.wasm', '--input-source-map=a.map', '-o', 'b.wasm', '--output-source-map=b.map', '-g'])
+        actual = support.run_command(shared.WASM_DIS + ['b.wasm', '--source-map=b.map'])
+        open(f, 'w').write(actual)
+
+    print('\n[ checking binary format testcases... ]\n')
+    for wast in shared.get_tests(shared.options.binaryen_test, ['.wast']):
+        for debug_info in [0, 1]:
+            cmd = shared.WASM_AS + [wast, '-o', 'a.wasm', '-all']
+            if debug_info:
+                cmd += ['-g']
+            print(' '.join(cmd))
+            if os.path.exists('a.wasm'):
+                os.unlink('a.wasm')
+            subprocess.check_call(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            assert os.path.exists('a.wasm')
+
+            cmd = shared.WASM_DIS + ['a.wasm', '-o', 'a.wast']
+            print(' '.join(cmd))
+            if os.path.exists('a.wast'):
+                os.unlink('a.wast')
+            subprocess.check_call(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            assert os.path.exists('a.wast')
+            actual = open('a.wast').read()
+            binary_file = wast + '.fromBinary'
+            if not debug_info:
+                binary_file += '.noDebugInfo'
+            with open(binary_file, 'w') as o:
+                print('writey', binary_file)
+                o.write(actual)
diff --git a/binaryen/scripts/validation_shell.js b/binaryen/scripts/validation_shell.js
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/validation_shell.js
@@ -0,0 +1,28 @@
+// Test a file is valid, by just loading it.
+
+// Shell integration.
+if (typeof console === 'undefined') {
+  console = { log: print };
+}
+var binary;
+if (typeof process === 'object' && typeof require === 'function' /* node.js detection */) {
+  var args = process.argv.slice(2);
+  binary = require('fs').readFileSync(args[0]);
+  if (!binary.buffer) binary = new Uint8Array(binary);
+} else {
+  var args;
+  if (typeof scriptArgs != 'undefined') {
+    args = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    args = arguments;
+  }
+  if (typeof readbuffer === 'function') {
+    binary = new Uint8Array(readbuffer(args[0]));
+  } else {
+    binary = read(args[0], 'binary');
+  }
+}
+
+// Test the wasm for validity by compiling it.
+new WebAssembly.Module(binary);
+
diff --git a/binaryen/scripts/wasm2js.js b/binaryen/scripts/wasm2js.js
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/wasm2js.js
@@ -0,0 +1,204 @@
+// wasm2js.js - enough of a polyfill for the WebAssembly object so that we can load
+// wasm2js code that way. Similar to the same file in emscripten, but tailored for
+// fuzzing purposes here.
+
+var WebAssembly = {
+  Memory: function(opts) {
+    return {
+      buffer: new ArrayBuffer(opts['initial'] * 64 * 1024),
+    };
+  },
+
+  Table: function(opts) {
+    var ret = new Array(opts['initial']);
+    ret.grow = function(by) {
+      ret.push(null);
+    };
+    ret.set = function(i, func) {
+      ret[i] = func;
+    };
+    ret.get = function(i) {
+      return ret[i];
+    };
+    return ret;
+  },
+
+  Module: function(binary) {
+    // TODO: use the binary and info somehow - right now the wasm2js output is embedded in
+    // the main JS
+    return {};
+  },
+
+  Instance: function(module, info) {
+    // TODO: use the module and info somehow - right now the wasm2js output is embedded in
+    // the main JS
+    var decodeBase64 = typeof atob === 'function' ? atob : function (input) {
+      var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
+
+      var output = '';
+      var chr1, chr2, chr3;
+      var enc1, enc2, enc3, enc4;
+      var i = 0;
+      // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
+      input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');
+      do {
+        enc1 = keyStr.indexOf(input.charAt(i++));
+        enc2 = keyStr.indexOf(input.charAt(i++));
+        enc3 = keyStr.indexOf(input.charAt(i++));
+        enc4 = keyStr.indexOf(input.charAt(i++));
+
+        chr1 = (enc1 << 2) | (enc2 >> 4);
+        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+        chr3 = ((enc3 & 3) << 6) | enc4;
+
+        output = output + String.fromCharCode(chr1);
+
+        if (enc3 !== 64) {
+          output = output + String.fromCharCode(chr2);
+        }
+        if (enc4 !== 64) {
+          output = output + String.fromCharCode(chr3);
+        }
+      } while (i < input.length);
+      return output;
+    };
+    var atob = decodeBase64;
+    // Additional imports
+    asmLibraryArg['__tempMemory__'] = 0; // risky!
+    // This will be replaced by the actual wasm2js code.
+    var exports = instantiate(asmLibraryArg, wasmMemory);
+    return {
+      'exports': exports
+    };
+  },
+
+  instantiate: function(binary, info) {
+    return {
+      then: function(ok, err) {
+        ok({
+          'instance': new WebAssembly.Instance(new WebAssembly.Module(binary, info))
+        });
+      }
+    };
+  }
+};
+
+var tempRet0 = 0;
+
+var asmLibraryArg = {
+  log_i32: function(x) {
+    console.log('[LoggingExternalInterface logging ' + literal(x, 'i32') + ']');
+  },
+  log_i64: function(x, h) {
+    console.log('[LoggingExternalInterface logging ' + literal(x, 'i32') + ' ' + literal(h, 'i32') + ']');
+  },
+  log_f32: function(x) {
+    console.log('[LoggingExternalInterface logging ' + literal(x, 'f64') + ']');
+  },
+  log_f64: function(x) {
+    console.log('[LoggingExternalInterface logging ' + literal(x, 'f64') + ']');
+  },
+  log_execution: function(loc) {
+    console.log('log_execution ' + loc);
+  },
+  setTempRet0: function(x) {
+    tempRet0 = x;
+  },
+  getTempRet0: function() {
+    return x;
+  },
+  get_i32: function(loc, index, value) {
+    console.log('get_i32 ' + [loc, index, value]);
+    return value;
+  },
+  get_i64: function(loc, index, low, high) {
+    console.log('get_i64 ' + [loc, index, low, high]);
+    asmLibraryArg['setTempRet0'](high);
+    return low;
+  },
+  get_f32: function(loc, index, value) {
+    console.log('get_f32 ' + [loc, index, value]);
+    return value;
+  },
+  get_f64: function(loc, index, value) {
+    console.log('get_f64 ' + [loc, index, value]);
+    return value;
+  },
+  get_externref: function(loc, index, value) {
+    console.log('get_externref ' + [loc, index, value]);
+    return value;
+  },
+  get_exnref: function(loc, index, value) {
+    console.log('get_exnref ' + [loc, index, value]);
+    return value;
+  },
+  set_i32: function(loc, index, value) {
+    console.log('set_i32 ' + [loc, index, value]);
+    return value;
+  },
+  set_i64: function(loc, index, low, high) {
+    console.log('set_i64 ' + [loc, index, low, high]);
+    asmLibraryArg['setTempRet0'](high);
+    return low;
+  },
+  set_f32: function(loc, index, value) {
+    console.log('set_f32 ' + [loc, index, value]);
+    return value;
+  },
+  set_f64: function(loc, index, value) {
+    console.log('set_f64 ' + [loc, index, value]);
+    return value;
+  },
+  set_externref: function(loc, index, value) {
+    console.log('set_externref ' + [loc, index, value]);
+    return value;
+  },
+  set_exnref: function(loc, index, value) {
+    console.log('set_exnref ' + [loc, index, value]);
+    return value;
+  },
+  load_ptr: function(loc, bytes, offset, ptr) {
+    console.log('load_ptr ' + [loc, bytes, offset, ptr]);
+    return ptr;
+  },
+  load_val_i32: function(loc, value) {
+    console.log('load_val_i32 ' + [loc, value]);
+    return value;
+  },
+  load_val_i64: function(loc, low, high) {
+    console.log('load_val_i64 ' + [loc, low, high]);
+    asmLibraryArg['setTempRet0'](high);
+    return low;
+  },
+  load_val_f32: function(loc, value) {
+    console.log('loaload_val_i32d_ptr ' + [loc, value]);
+    return value;
+  },
+  load_val_f64: function(loc, value) {
+    console.log('load_val_f64 ' + [loc, value]);
+    return value;
+  },
+  store_ptr: function(loc, bytes, offset, ptr) {
+    console.log('store_ptr ' + [loc, bytes, offset, ptr]);
+    return ptr;
+  },
+  store_val_i32: function(loc, value) {
+    console.log('store_val_i32 ' + [loc, value]);
+    return value;
+  },
+  store_val_i64: function(loc, low, high) {
+    console.log('store_val_i64 ' + [loc, low, high]);
+    asmLibraryArg['setTempRet0'](high);
+    return low;
+  },
+  store_val_f32: function(loc, value) {
+    console.log('loastore_val_i32d_ptr ' + [loc, value]);
+    return value;
+  },
+  store_val_f64: function(loc, value) {
+    console.log('store_val_f64 ' + [loc, value]);
+    return value;
+  },
+};
+
+var wasmMemory = new WebAssembly.Memory({ initial: 1 });
diff --git a/binaryen/src/abi/abi.h b/binaryen/src/abi/abi.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/abi/abi.h
@@ -0,0 +1,33 @@
+/*
+ * 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/js.h b/binaryen/src/abi/js.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/abi/js.h
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#ifndef wasm_abi_abi_h
+#define wasm_abi_abi_h
+
+#include "asmjs/shared-constants.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace ABI {
+
+enum class LegalizationLevel { Full = 0, Minimal = 1 };
+
+inline std::string getLegalizationPass(LegalizationLevel level) {
+  if (level == LegalizationLevel::Full) {
+    return "legalize-js-interface";
+  } else {
+    return "legalize-js-interface-minimally";
+  }
+}
+
+namespace wasm2js {
+
+extern cashew::IString SCRATCH_LOAD_I32;
+extern cashew::IString SCRATCH_STORE_I32;
+extern cashew::IString SCRATCH_LOAD_F32;
+extern cashew::IString SCRATCH_STORE_F32;
+extern cashew::IString SCRATCH_LOAD_F64;
+extern cashew::IString SCRATCH_STORE_F64;
+extern cashew::IString MEMORY_INIT;
+extern cashew::IString MEMORY_FILL;
+extern cashew::IString MEMORY_COPY;
+extern cashew::IString DATA_DROP;
+extern cashew::IString ATOMIC_WAIT_I32;
+extern cashew::IString ATOMIC_RMW_I64;
+extern cashew::IString GET_STASHED_BITS;
+
+// The wasm2js helpers let us do things that can't be done without special help,
+// like read and write to scratch memory for purposes of implementing things
+// like reinterpret, etc.
+// The optional "specific" parameter is a specific function we want. If not
+// provided, we create them all.
+inline void ensureHelpers(Module* wasm,
+                          cashew::IString specific = cashew::IString()) {
+  auto ensureImport = [&](Name name, Type params, Type results) {
+    if (wasm->getFunctionOrNull(name)) {
+      return;
+    }
+    if (specific.is() && name != specific) {
+      return;
+    }
+    auto func = make_unique<Function>();
+    func->name = name;
+    func->sig = Signature(params, results);
+    func->module = ENV;
+    func->base = name;
+    wasm->addFunction(std::move(func));
+  };
+
+  ensureImport(SCRATCH_LOAD_I32, {Type::i32}, Type::i32);
+  ensureImport(SCRATCH_STORE_I32, {Type::i32, Type::i32}, Type::none);
+  ensureImport(SCRATCH_LOAD_F32, {}, Type::f32);
+  ensureImport(SCRATCH_STORE_F32, {Type::f32}, Type::none);
+  ensureImport(SCRATCH_LOAD_F64, {}, Type::f64);
+  ensureImport(SCRATCH_STORE_F64, {Type::f64}, Type::none);
+  ensureImport(
+    MEMORY_INIT, {Type::i32, Type::i32, Type::i32, Type::i32}, Type::none);
+  ensureImport(MEMORY_FILL, {Type::i32, Type::i32, Type::i32}, Type::none);
+  ensureImport(MEMORY_COPY, {Type::i32, Type::i32, Type::i32}, Type::none);
+  ensureImport(DATA_DROP, {Type::i32}, Type::none);
+  ensureImport(
+    ATOMIC_WAIT_I32, {Type::i32, Type::i32, Type::i32, Type::i32}, Type::i32);
+  ensureImport(
+    ATOMIC_RMW_I64,
+    {Type::i32, Type::i32, Type::i32, Type::i32, Type::i32, Type::i32},
+    Type::i32);
+  ensureImport(GET_STASHED_BITS, {}, Type::i32);
+}
+
+inline bool isHelper(cashew::IString name) {
+  return name == SCRATCH_LOAD_I32 || name == SCRATCH_STORE_I32 ||
+         name == SCRATCH_LOAD_F32 || name == SCRATCH_STORE_F32 ||
+         name == SCRATCH_LOAD_F64 || name == SCRATCH_STORE_F64 ||
+         name == ATOMIC_WAIT_I32 || name == MEMORY_INIT ||
+         name == MEMORY_FILL || name == MEMORY_COPY || name == DATA_DROP ||
+         name == ATOMIC_RMW_I64 || name == GET_STASHED_BITS;
+}
+
+} // namespace wasm2js
+
+} // namespace ABI
+
+} // namespace wasm
+
+#endif // wasm_abi_abi_h
diff --git a/binaryen/src/abi/stack.h b/binaryen/src/abi/stack.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/abi/stack.h
@@ -0,0 +1,144 @@
+/*
+ * 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
new file mode 100644
--- /dev/null
+++ b/binaryen/src/abi/wasm-object.h
@@ -0,0 +1,40 @@
+/*
+ * 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
new file mode 100644
--- /dev/null
+++ b/binaryen/src/asm_v_wasm.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015 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_asm_v_wasm_h
+#define wasm_asm_v_wasm_h
+
+#include "emscripten-optimizer/optimizer.h"
+#include "mixed_arena.h"
+#include "wasm.h"
+
+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;
+  ret += getSig(result);
+  for (auto operand : operands) {
+    ret += getSig(operand->type);
+  }
+  return ret;
+}
+
+template<typename ListType>
+std::string getSigFromStructs(Type result, const ListType& operands) {
+  std::string ret;
+  ret += getSig(result);
+  for (auto operand : operands) {
+    ret += getSig(operand.type);
+  }
+  return ret;
+}
+
+// converts an f32 to an f64 if necessary
+Expression* ensureDouble(Expression* expr, MixedArena& allocator);
+
+} // namespace wasm
+
+#endif // wasm_asm_v_wasm_h
diff --git a/binaryen/src/asmjs/CMakeLists.txt b/binaryen/src/asmjs/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/src/asmjs/CMakeLists.txt
@@ -0,0 +1,8 @@
+FILE(GLOB asmjs_HEADERS *.h)
+set(asmjs_SOURCES
+  asm_v_wasm.cpp
+  asmangle.cpp
+  shared-constants.cpp
+  ${asmjs_HEADERS}
+)
+add_library(asmjs OBJECT ${asmjs_SOURCES})
diff --git a/binaryen/src/asmjs/asm_v_wasm.cpp b/binaryen/src/asmjs/asm_v_wasm.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/asmjs/asm_v_wasm.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2015 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "asm_v_wasm.h"
+#include "wasm.h"
+
+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()) {
+    case Type::i32:
+      return ASM_INT;
+    case Type::f32:
+      return ASM_FLOAT;
+    case Type::f64:
+      return ASM_DOUBLE;
+    case Type::i64:
+      return ASM_INT64;
+    case Type::v128:
+      assert(false && "v128 not implemented yet");
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+      assert(false && "reference types are not supported by asm2wasm");
+    case Type::none:
+      return ASM_NONE;
+    case Type::unreachable:
+      WASM_UNREACHABLE("invalid type");
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+char getSig(Type type) {
+  TODO_SINGLE_COMPOUND(type);
+  switch (type.getBasic()) {
+    case Type::i32:
+      return 'i';
+    case Type::i64:
+      return 'j';
+    case Type::f32:
+      return 'f';
+    case Type::f64:
+      return 'd';
+    case Type::v128:
+      return 'V';
+    case Type::funcref:
+      return 'F';
+    case Type::externref:
+      return 'X';
+    case Type::exnref:
+      return 'E';
+    case Type::anyref:
+      return 'A';
+    case Type::eqref:
+      return 'Q';
+    case Type::i31ref:
+      return 'I';
+    case Type::none:
+      return 'v';
+    case Type::unreachable:
+      WASM_UNREACHABLE("invalid type");
+  }
+  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;
+  sig += getSig(results);
+  for (const auto& param : params) {
+    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/asmangle.cpp b/binaryen/src/asmjs/asmangle.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/asmjs/asmangle.cpp
@@ -0,0 +1,204 @@
+/*
+ * 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.
+ */
+
+#include "asmjs/asmangle.h"
+#include <assert.h>
+
+namespace wasm {
+
+std::string asmangle(std::string name) {
+  // Wasm allows empty names as exports etc., but JS doesn't allow such
+  // identifiers.
+  if (name.empty()) {
+    name = "$";
+  }
+
+  bool mightBeKeyword = true;
+  size_t i = 1;
+
+  assert(!name.empty());
+
+  // Names must start with a character, $ or _
+  switch (auto ch = name[0]) {
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9': {
+      name = "$" + name;
+      i = 2;
+      goto notKeyword;
+    }
+    notKeyword:
+    case '$':
+    case '_': {
+      mightBeKeyword = false;
+      break;
+    }
+    default: {
+      if (!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z')) {
+        name = "$" + name.substr(1);
+        mightBeKeyword = false;
+      }
+    }
+  }
+
+  // Names must contain only characters, digits, $ or _
+  size_t len = name.length();
+  for (; i < len; ++i) {
+    switch (char ch = name[i]) {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+      case '$':
+      case '_': {
+        mightBeKeyword = false;
+        break;
+      }
+      default: {
+        if (!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z')) {
+          name = name.substr(0, i) + "_" + name.substr(i + 1);
+          mightBeKeyword = false;
+        }
+      }
+    }
+  }
+
+  // Names must not collide with keywords
+  if (mightBeKeyword && len >= 2 && len <= 10) {
+    switch (name[0]) {
+      case 'a': {
+        if (name == "arguments") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      case 'b': {
+        if (name == "break") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      case 'c': {
+        if (name == "case" || name == "continue" || name == "catch" ||
+            name == "const" || name == "class") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      case 'd': {
+        if (name == "do" || name == "default" || name == "debugger") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      case 'e': {
+        if (name == "else" || name == "enum" || name == "eval" || // to be sure
+            name == "export" || name == "extends") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      case 'f': {
+        if (name == "for" || name == "false" || name == "finally" ||
+            name == "function") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      case 'i': {
+        if (name == "if" || name == "in" || name == "import" ||
+            name == "interface" || name == "implements" ||
+            name == "instanceof") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      case 'l': {
+        if (name == "let") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      case 'n': {
+        if (name == "new" || name == "null") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      case 'p': {
+        if (name == "public" || name == "package" || name == "private" ||
+            name == "protected") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      case 'r': {
+        if (name == "return") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      case 's': {
+        if (name == "super" || name == "static" || name == "switch") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      case 't': {
+        if (name == "try" || name == "this" || name == "true" ||
+            name == "throw" || name == "typeof") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      case 'v': {
+        if (name == "var" || name == "void") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      case 'w': {
+        if (name == "with" || name == "while") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      case 'y': {
+        if (name == "yield") {
+          goto mangleKeyword;
+        }
+        break;
+      }
+      mangleKeyword : { name = name + "_"; }
+    }
+  }
+  return name;
+}
+
+} // namespace wasm
diff --git a/binaryen/src/asmjs/asmangle.h b/binaryen/src/asmjs/asmangle.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/asmjs/asmangle.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#ifndef wasm_asmjs_asmangle_h
+#define wasm_asmjs_asmangle_h
+
+#include <string>
+
+namespace wasm {
+
+// Mangles a WebAssembly name to a valid JavaScript identifier.
+std::string asmangle(std::string name);
+
+} // namespace wasm
+
+#endif // wasm_asmjs_asmangle_h
diff --git a/binaryen/src/asmjs/shared-constants.cpp b/binaryen/src/asmjs/shared-constants.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/asmjs/shared-constants.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "asmjs/shared-constants.h"
+
+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");
+cashew::IString INT32ARRAY("Int32Array");
+cashew::IString UINT8ARRAY("Uint8Array");
+cashew::IString UINT16ARRAY("Uint16Array");
+cashew::IString UINT32ARRAY("Uint32Array");
+cashew::IString FLOAT32ARRAY("Float32Array");
+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");
+cashew::IString FROUND("fround");
+cashew::IString ASM2WASM("asm2wasm");
+cashew::IString MIN("min");
+cashew::IString MAX("max");
+cashew::IString F64_REM("f64-rem");
+cashew::IString F64_TO_INT("f64-to-int");
+cashew::IString F64_TO_UINT("f64-to-uint");
+cashew::IString F64_TO_INT64("f64-to-int64");
+cashew::IString F64_TO_UINT64("f64-to-uint64");
+cashew::IString F32_TO_INT("f32-to-int");
+cashew::IString F32_TO_UINT("f32-to-uint");
+cashew::IString F32_TO_INT64("f32-to-int64");
+cashew::IString F32_TO_UINT64("f32-to-uint64");
+cashew::IString I32S_DIV("i32s-div");
+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 SQRT("sqrt");
+cashew::IString POW("pow");
+cashew::IString I32_TEMP("asm2wasm_i32_temp");
+cashew::IString DEBUGGER("debugger");
+cashew::IString BUFFER("buffer");
+cashew::IString ENV("env");
+cashew::IString STACKTOP("STACKTOP");
+cashew::IString STACK_MAX("STACK_MAX");
+cashew::IString INSTRUMENT("instrument");
+cashew::IString MATH_IMUL("Math_imul");
+cashew::IString MATH_ABS("Math_abs");
+cashew::IString MATH_CEIL("Math_ceil");
+cashew::IString MATH_CLZ32("Math_clz32");
+cashew::IString MATH_FLOOR("Math_floor");
+cashew::IString MATH_TRUNC("Math_trunc");
+cashew::IString MATH_SQRT("Math_sqrt");
+cashew::IString MATH_MIN("Math_min");
+cashew::IString MATH_MAX("Math_max");
+cashew::IString WASM_CTZ32("__wasm_ctz_i32");
+cashew::IString WASM_CTZ64("__wasm_ctz_i64");
+cashew::IString WASM_CLZ32("__wasm_clz_i32");
+cashew::IString WASM_CLZ64("__wasm_clz_i64");
+cashew::IString WASM_POPCNT32("__wasm_popcnt_i32");
+cashew::IString WASM_POPCNT64("__wasm_popcnt_i64");
+cashew::IString WASM_ROTL32("__wasm_rotl_i32");
+cashew::IString WASM_ROTL64("__wasm_rotl_i64");
+cashew::IString WASM_ROTR32("__wasm_rotr_i32");
+cashew::IString WASM_ROTR64("__wasm_rotr_i64");
+cashew::IString WASM_MEMORY_GROW("__wasm_memory_grow");
+cashew::IString WASM_MEMORY_SIZE("__wasm_memory_size");
+cashew::IString WASM_FETCH_HIGH_BITS("__wasm_fetch_high_bits");
+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");
+cashew::IString WASM_I64_SREM("__wasm_i64_srem");
+cashew::IString WASM_I64_UREM("__wasm_i64_urem");
+
+cashew::IString ASM_FUNC("asmFunc");
+cashew::IString ABORT_FUNC("abort");
+cashew::IString FUNCTION_TABLE("FUNCTION_TABLE");
+cashew::IString NO_RESULT("wasm2js$noresult"); // no result at all
+// result in an expression, no temp var
+cashew::IString EXPRESSION_RESULT("wasm2js$expresult");
+
+namespace ABI {
+namespace wasm2js {
+
+cashew::IString SCRATCH_LOAD_I32("wasm2js_scratch_load_i32");
+cashew::IString SCRATCH_STORE_I32("wasm2js_scratch_store_i32");
+cashew::IString SCRATCH_LOAD_F32("wasm2js_scratch_load_f32");
+cashew::IString SCRATCH_STORE_F32("wasm2js_scratch_store_f32");
+cashew::IString SCRATCH_LOAD_F64("wasm2js_scratch_load_f64");
+cashew::IString SCRATCH_STORE_F64("wasm2js_scratch_store_f64");
+cashew::IString MEMORY_INIT("wasm2js_memory_init");
+cashew::IString MEMORY_FILL("wasm2js_memory_fill");
+cashew::IString MEMORY_COPY("wasm2js_memory_copy");
+cashew::IString DATA_DROP("wasm2js_data_drop");
+cashew::IString ATOMIC_WAIT_I32("wasm2js_atomic_wait_i32");
+cashew::IString ATOMIC_RMW_I64("wasm2js_atomic_rmw_i64");
+cashew::IString GET_STASHED_BITS("wasm2js_get_stashed_bits");
+
+} // namespace wasm2js
+} // namespace ABI
+
+} // namespace wasm
diff --git a/binaryen/src/asmjs/shared-constants.h b/binaryen/src/asmjs/shared-constants.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/asmjs/shared-constants.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2015 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_asmjs_shared_constants_h
+#define wasm_asmjs_shared_constants_h
+
+#include "emscripten-optimizer/istring.h"
+
+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;
+extern cashew::IString INT32ARRAY;
+extern cashew::IString UINT8ARRAY;
+extern cashew::IString UINT16ARRAY;
+extern cashew::IString UINT32ARRAY;
+extern cashew::IString FLOAT32ARRAY;
+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;
+extern cashew::IString FROUND;
+extern cashew::IString ASM2WASM;
+extern cashew::IString MIN;
+extern cashew::IString MAX;
+extern cashew::IString F64_REM;
+extern cashew::IString F64_TO_INT;
+extern cashew::IString F64_TO_UINT;
+extern cashew::IString F64_TO_INT64;
+extern cashew::IString F64_TO_UINT64;
+extern cashew::IString F32_TO_INT;
+extern cashew::IString F32_TO_UINT;
+extern cashew::IString F32_TO_INT64;
+extern cashew::IString F32_TO_UINT64;
+extern cashew::IString I32S_DIV;
+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 SQRT;
+extern cashew::IString POW;
+extern cashew::IString I32_TEMP;
+extern cashew::IString DEBUGGER;
+extern cashew::IString BUFFER;
+extern cashew::IString ENV;
+extern cashew::IString STACKTOP;
+extern cashew::IString STACK_MAX;
+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_FLOOR;
+extern cashew::IString MATH_TRUNC;
+extern cashew::IString MATH_SQRT;
+extern cashew::IString MATH_MIN;
+extern cashew::IString MATH_MAX;
+extern cashew::IString WASM_CTZ32;
+extern cashew::IString WASM_CTZ64;
+extern cashew::IString WASM_CLZ32;
+extern cashew::IString WASM_CLZ64;
+extern cashew::IString WASM_POPCNT32;
+extern cashew::IString WASM_POPCNT64;
+extern cashew::IString WASM_ROTL32;
+extern cashew::IString WASM_ROTL64;
+extern cashew::IString WASM_ROTR32;
+extern cashew::IString WASM_ROTR64;
+extern cashew::IString WASM_MEMORY_GROW;
+extern cashew::IString WASM_MEMORY_SIZE;
+extern cashew::IString WASM_FETCH_HIGH_BITS;
+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;
+extern cashew::IString WASM_I64_SREM;
+extern cashew::IString WASM_I64_UREM;
+// wasm2js constants
+extern cashew::IString ASM_FUNC;
+extern cashew::IString ABORT_FUNC;
+extern cashew::IString FUNCTION_TABLE;
+extern cashew::IString NO_RESULT;
+extern cashew::IString EXPRESSION_RESULT;
+} // namespace wasm
+
+#endif // wasm_asmjs_shared_constants_h
diff --git a/binaryen/src/binaryen-c.cpp b/binaryen/src/binaryen-c.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/binaryen-c.cpp
@@ -0,0 +1,4259 @@
+/*
+ * 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.
+ */
+
+//===============================
+// Binaryen C API implementation
+//===============================
+
+#include <mutex>
+
+#include "binaryen-c.h"
+#include "cfg/Relooper.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "shell-interface.h"
+#include "support/colors.h"
+#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"
+#include "wasm2js.h"
+#include <iostream>
+#include <sstream>
+
+#ifdef __EMSCRIPTEN__
+#include <emscripten.h>
+#endif
+
+using namespace wasm;
+
+// Literal utilities
+
+static_assert(sizeof(BinaryenLiteral) == sizeof(Literal),
+              "Binaryen C API literal must match wasm.h");
+
+BinaryenLiteral toBinaryenLiteral(Literal x) {
+  BinaryenLiteral ret;
+  ret.type = x.type.getID();
+  TODO_SINGLE_COMPOUND(x.type);
+  switch (x.type.getBasic()) {
+    case Type::i32:
+      ret.i32 = x.geti32();
+      break;
+    case Type::i64:
+      ret.i64 = x.geti64();
+      break;
+    case Type::f32:
+      ret.i32 = x.reinterpreti32();
+      break;
+    case Type::f64:
+      ret.i64 = x.reinterpreti64();
+      break;
+    case Type::v128:
+      memcpy(&ret.v128, x.getv128Ptr(), 16);
+      break;
+    case Type::funcref:
+      ret.func = x.isNull() ? nullptr : x.getFunc().c_str();
+      break;
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+      assert(x.isNull() && "unexpected non-null reference type literal");
+      break;
+    case Type::i31ref:
+      WASM_UNREACHABLE("TODO: i31ref");
+    case Type::none:
+    case Type::unreachable:
+      WASM_UNREACHABLE("unexpected type");
+  }
+  return ret;
+}
+
+Literal fromBinaryenLiteral(BinaryenLiteral x) {
+  switch (x.type) {
+    case Type::i32:
+      return Literal(x.i32);
+    case Type::i64:
+      return Literal(x.i64);
+    case Type::f32:
+      return Literal(x.i32).castToF32();
+    case Type::f64:
+      return Literal(x.i64).castToF64();
+    case Type::v128:
+      return Literal(x.v128);
+    case Type::funcref:
+      return Literal::makeFunc(x.func);
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+      return Literal::makeNull(Type(x.type));
+    case Type::i31ref:
+      WASM_UNREACHABLE("TODO: i31ref");
+    case Type::none:
+    case Type::unreachable:
+      WASM_UNREACHABLE("unexpected type");
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+// Mutexes (global for now; in theory if multiple modules
+// are used at once this should be optimized to be per-
+// module, but likely it doesn't matter)
+
+static std::mutex BinaryenFunctionMutex;
+
+// Optimization options
+static PassOptions globalPassOptions =
+  PassOptions::getWithDefaultOptimizationOptions();
+
+extern "C" {
+
+//
+// ========== Module Creation ==========
+//
+
+// Core types
+
+BinaryenType BinaryenTypeNone(void) { return Type::none; }
+BinaryenType BinaryenTypeInt32(void) { return Type::i32; }
+BinaryenType BinaryenTypeInt64(void) { return Type::i64; }
+BinaryenType BinaryenTypeFloat32(void) { return Type::f32; }
+BinaryenType BinaryenTypeFloat64(void) { return Type::f64; }
+BinaryenType BinaryenTypeVec128(void) { return Type::v128; }
+BinaryenType BinaryenTypeFuncref(void) { return Type::funcref; }
+BinaryenType BinaryenTypeExternref(void) { return Type::externref; }
+BinaryenType BinaryenTypeExnref(void) { return Type::exnref; }
+BinaryenType BinaryenTypeAnyref(void) { return Type::anyref; }
+BinaryenType BinaryenTypeEqref(void) { return Type::eqref; }
+BinaryenType BinaryenTypeI31ref(void) { return Type::i31ref; }
+BinaryenType BinaryenTypeUnreachable(void) { return Type::unreachable; }
+BinaryenType BinaryenTypeAuto(void) { return uintptr_t(-1); }
+
+BinaryenType BinaryenTypeCreate(BinaryenType* types, uint32_t numTypes) {
+  std::vector<Type> typeVec;
+  typeVec.reserve(numTypes);
+  for (size_t i = 0; i < numTypes; ++i) {
+    typeVec.push_back(Type(types[i]));
+  }
+  return Type(typeVec).getID();
+}
+
+uint32_t BinaryenTypeArity(BinaryenType t) { return Type(t).size(); }
+
+void BinaryenTypeExpand(BinaryenType t, BinaryenType* buf) {
+  Type types(t);
+  size_t i = 0;
+  for (const auto& type : types) {
+    buf[i++] = type.getID();
+  }
+}
+
+WASM_DEPRECATED BinaryenType BinaryenNone(void) { return Type::none; }
+WASM_DEPRECATED BinaryenType BinaryenInt32(void) { return Type::i32; }
+WASM_DEPRECATED BinaryenType BinaryenInt64(void) { return Type::i64; }
+WASM_DEPRECATED BinaryenType BinaryenFloat32(void) { return Type::f32; }
+WASM_DEPRECATED BinaryenType BinaryenFloat64(void) { return Type::f64; }
+WASM_DEPRECATED BinaryenType BinaryenUndefined(void) { return uint32_t(-1); }
+
+// Expression ids
+
+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;
+}
+
+// External kinds
+
+BinaryenExternalKind BinaryenExternalFunction(void) {
+  return static_cast<BinaryenExternalKind>(ExternalKind::Function);
+}
+BinaryenExternalKind BinaryenExternalTable(void) {
+  return static_cast<BinaryenExternalKind>(ExternalKind::Table);
+}
+BinaryenExternalKind BinaryenExternalMemory(void) {
+  return static_cast<BinaryenExternalKind>(ExternalKind::Memory);
+}
+BinaryenExternalKind BinaryenExternalGlobal(void) {
+  return static_cast<BinaryenExternalKind>(ExternalKind::Global);
+}
+BinaryenExternalKind BinaryenExternalEvent(void) {
+  return static_cast<BinaryenExternalKind>(ExternalKind::Event);
+}
+
+// Features
+
+BinaryenFeatures BinaryenFeatureMVP(void) {
+  return static_cast<BinaryenFeatures>(FeatureSet::MVP);
+}
+BinaryenFeatures BinaryenFeatureAtomics(void) {
+  return static_cast<BinaryenFeatures>(FeatureSet::Atomics);
+}
+BinaryenFeatures BinaryenFeatureBulkMemory(void) {
+  return static_cast<BinaryenFeatures>(FeatureSet::BulkMemory);
+}
+BinaryenFeatures BinaryenFeatureMutableGlobals(void) {
+  return static_cast<BinaryenFeatures>(FeatureSet::MutableGlobals);
+}
+BinaryenFeatures BinaryenFeatureNontrappingFPToInt(void) {
+  return static_cast<BinaryenFeatures>(FeatureSet::TruncSat);
+}
+BinaryenFeatures BinaryenFeatureSignExt(void) {
+  return static_cast<BinaryenFeatures>(FeatureSet::SignExt);
+}
+BinaryenFeatures BinaryenFeatureSIMD128(void) {
+  return static_cast<BinaryenFeatures>(FeatureSet::SIMD);
+}
+BinaryenFeatures BinaryenFeatureExceptionHandling(void) {
+  return static_cast<BinaryenFeatures>(FeatureSet::ExceptionHandling);
+}
+BinaryenFeatures BinaryenFeatureTailCall(void) {
+  return static_cast<BinaryenFeatures>(FeatureSet::TailCall);
+}
+BinaryenFeatures BinaryenFeatureReferenceTypes(void) {
+  return static_cast<BinaryenFeatures>(FeatureSet::ReferenceTypes);
+}
+BinaryenFeatures BinaryenFeatureMultivalue(void) {
+  return static_cast<BinaryenFeatures>(FeatureSet::Multivalue);
+}
+BinaryenFeatures BinaryenFeatureGC(void) {
+  return static_cast<BinaryenFeatures>(FeatureSet::GC);
+}
+BinaryenFeatures BinaryenFeatureMemory64(void) {
+  return static_cast<BinaryenFeatures>(FeatureSet::Memory64);
+}
+BinaryenFeatures BinaryenFeatureAll(void) {
+  return static_cast<BinaryenFeatures>(FeatureSet::All);
+}
+
+// Modules
+
+BinaryenModuleRef BinaryenModuleCreate(void) { return new Module(); }
+void BinaryenModuleDispose(BinaryenModuleRef module) { delete (Module*)module; }
+
+// Literals
+
+BinaryenLiteral BinaryenLiteralInt32(int32_t x) {
+  return toBinaryenLiteral(Literal(x));
+}
+BinaryenLiteral BinaryenLiteralInt64(int64_t x) {
+  return toBinaryenLiteral(Literal(x));
+}
+BinaryenLiteral BinaryenLiteralFloat32(float x) {
+  return toBinaryenLiteral(Literal(x));
+}
+BinaryenLiteral BinaryenLiteralFloat64(double x) {
+  return toBinaryenLiteral(Literal(x));
+}
+BinaryenLiteral BinaryenLiteralVec128(const uint8_t x[16]) {
+  return toBinaryenLiteral(Literal(x));
+}
+BinaryenLiteral BinaryenLiteralFloat32Bits(int32_t x) {
+  return toBinaryenLiteral(Literal(x).castToF32());
+}
+BinaryenLiteral BinaryenLiteralFloat64Bits(int64_t x) {
+  return toBinaryenLiteral(Literal(x).castToF64());
+}
+
+// Expressions
+
+BinaryenOp BinaryenClzInt32(void) { return ClzInt32; }
+BinaryenOp BinaryenCtzInt32(void) { return CtzInt32; }
+BinaryenOp BinaryenPopcntInt32(void) { return PopcntInt32; }
+BinaryenOp BinaryenNegFloat32(void) { return NegFloat32; }
+BinaryenOp BinaryenAbsFloat32(void) { return AbsFloat32; }
+BinaryenOp BinaryenCeilFloat32(void) { return CeilFloat32; }
+BinaryenOp BinaryenFloorFloat32(void) { return FloorFloat32; }
+BinaryenOp BinaryenTruncFloat32(void) { return TruncFloat32; }
+BinaryenOp BinaryenNearestFloat32(void) { return NearestFloat32; }
+BinaryenOp BinaryenSqrtFloat32(void) { return SqrtFloat32; }
+BinaryenOp BinaryenEqZInt32(void) { return EqZInt32; }
+BinaryenOp BinaryenClzInt64(void) { return ClzInt64; }
+BinaryenOp BinaryenCtzInt64(void) { return CtzInt64; }
+BinaryenOp BinaryenPopcntInt64(void) { return PopcntInt64; }
+BinaryenOp BinaryenNegFloat64(void) { return NegFloat64; }
+BinaryenOp BinaryenAbsFloat64(void) { return AbsFloat64; }
+BinaryenOp BinaryenCeilFloat64(void) { return CeilFloat64; }
+BinaryenOp BinaryenFloorFloat64(void) { return FloorFloat64; }
+BinaryenOp BinaryenTruncFloat64(void) { return TruncFloat64; }
+BinaryenOp BinaryenNearestFloat64(void) { return NearestFloat64; }
+BinaryenOp BinaryenSqrtFloat64(void) { return SqrtFloat64; }
+BinaryenOp BinaryenEqZInt64(void) { return EqZInt64; }
+BinaryenOp BinaryenExtendSInt32(void) { return ExtendSInt32; }
+BinaryenOp BinaryenExtendUInt32(void) { return ExtendUInt32; }
+BinaryenOp BinaryenWrapInt64(void) { return WrapInt64; }
+BinaryenOp BinaryenTruncSFloat32ToInt32(void) { return TruncSFloat32ToInt32; }
+BinaryenOp BinaryenTruncSFloat32ToInt64(void) { return TruncSFloat32ToInt64; }
+BinaryenOp BinaryenTruncUFloat32ToInt32(void) { return TruncUFloat32ToInt32; }
+BinaryenOp BinaryenTruncUFloat32ToInt64(void) { return TruncUFloat32ToInt64; }
+BinaryenOp BinaryenTruncSFloat64ToInt32(void) { return TruncSFloat64ToInt32; }
+BinaryenOp BinaryenTruncSFloat64ToInt64(void) { return TruncSFloat64ToInt64; }
+BinaryenOp BinaryenTruncUFloat64ToInt32(void) { return TruncUFloat64ToInt32; }
+BinaryenOp BinaryenTruncUFloat64ToInt64(void) { return TruncUFloat64ToInt64; }
+BinaryenOp BinaryenReinterpretFloat32(void) { return ReinterpretFloat32; }
+BinaryenOp BinaryenReinterpretFloat64(void) { return ReinterpretFloat64; }
+BinaryenOp BinaryenExtendS8Int32(void) { return ExtendS8Int32; }
+BinaryenOp BinaryenExtendS16Int32(void) { return ExtendS16Int32; }
+BinaryenOp BinaryenExtendS8Int64(void) { return ExtendS8Int64; }
+BinaryenOp BinaryenExtendS16Int64(void) { return ExtendS16Int64; }
+BinaryenOp BinaryenExtendS32Int64(void) { return ExtendS32Int64; }
+BinaryenOp BinaryenConvertSInt32ToFloat32(void) {
+  return ConvertSInt32ToFloat32;
+}
+BinaryenOp BinaryenConvertSInt32ToFloat64(void) {
+  return ConvertSInt32ToFloat64;
+}
+BinaryenOp BinaryenConvertUInt32ToFloat32(void) {
+  return ConvertUInt32ToFloat32;
+}
+BinaryenOp BinaryenConvertUInt32ToFloat64(void) {
+  return ConvertUInt32ToFloat64;
+}
+BinaryenOp BinaryenConvertSInt64ToFloat32(void) {
+  return ConvertSInt64ToFloat32;
+}
+BinaryenOp BinaryenConvertSInt64ToFloat64(void) {
+  return ConvertSInt64ToFloat64;
+}
+BinaryenOp BinaryenConvertUInt64ToFloat32(void) {
+  return ConvertUInt64ToFloat32;
+}
+BinaryenOp BinaryenConvertUInt64ToFloat64(void) {
+  return ConvertUInt64ToFloat64;
+}
+BinaryenOp BinaryenPromoteFloat32(void) { return PromoteFloat32; }
+BinaryenOp BinaryenDemoteFloat64(void) { return DemoteFloat64; }
+BinaryenOp BinaryenReinterpretInt32(void) { return ReinterpretInt32; }
+BinaryenOp BinaryenReinterpretInt64(void) { return ReinterpretInt64; }
+BinaryenOp BinaryenAddInt32(void) { return AddInt32; }
+BinaryenOp BinaryenSubInt32(void) { return SubInt32; }
+BinaryenOp BinaryenMulInt32(void) { return MulInt32; }
+BinaryenOp BinaryenDivSInt32(void) { return DivSInt32; }
+BinaryenOp BinaryenDivUInt32(void) { return DivUInt32; }
+BinaryenOp BinaryenRemSInt32(void) { return RemSInt32; }
+BinaryenOp BinaryenRemUInt32(void) { return RemUInt32; }
+BinaryenOp BinaryenAndInt32(void) { return AndInt32; }
+BinaryenOp BinaryenOrInt32(void) { return OrInt32; }
+BinaryenOp BinaryenXorInt32(void) { return XorInt32; }
+BinaryenOp BinaryenShlInt32(void) { return ShlInt32; }
+BinaryenOp BinaryenShrUInt32(void) { return ShrUInt32; }
+BinaryenOp BinaryenShrSInt32(void) { return ShrSInt32; }
+BinaryenOp BinaryenRotLInt32(void) { return RotLInt32; }
+BinaryenOp BinaryenRotRInt32(void) { return RotRInt32; }
+BinaryenOp BinaryenEqInt32(void) { return EqInt32; }
+BinaryenOp BinaryenNeInt32(void) { return NeInt32; }
+BinaryenOp BinaryenLtSInt32(void) { return LtSInt32; }
+BinaryenOp BinaryenLtUInt32(void) { return LtUInt32; }
+BinaryenOp BinaryenLeSInt32(void) { return LeSInt32; }
+BinaryenOp BinaryenLeUInt32(void) { return LeUInt32; }
+BinaryenOp BinaryenGtSInt32(void) { return GtSInt32; }
+BinaryenOp BinaryenGtUInt32(void) { return GtUInt32; }
+BinaryenOp BinaryenGeSInt32(void) { return GeSInt32; }
+BinaryenOp BinaryenGeUInt32(void) { return GeUInt32; }
+BinaryenOp BinaryenAddInt64(void) { return AddInt64; }
+BinaryenOp BinaryenSubInt64(void) { return SubInt64; }
+BinaryenOp BinaryenMulInt64(void) { return MulInt64; }
+BinaryenOp BinaryenDivSInt64(void) { return DivSInt64; }
+BinaryenOp BinaryenDivUInt64(void) { return DivUInt64; }
+BinaryenOp BinaryenRemSInt64(void) { return RemSInt64; }
+BinaryenOp BinaryenRemUInt64(void) { return RemUInt64; }
+BinaryenOp BinaryenAndInt64(void) { return AndInt64; }
+BinaryenOp BinaryenOrInt64(void) { return OrInt64; }
+BinaryenOp BinaryenXorInt64(void) { return XorInt64; }
+BinaryenOp BinaryenShlInt64(void) { return ShlInt64; }
+BinaryenOp BinaryenShrUInt64(void) { return ShrUInt64; }
+BinaryenOp BinaryenShrSInt64(void) { return ShrSInt64; }
+BinaryenOp BinaryenRotLInt64(void) { return RotLInt64; }
+BinaryenOp BinaryenRotRInt64(void) { return RotRInt64; }
+BinaryenOp BinaryenEqInt64(void) { return EqInt64; }
+BinaryenOp BinaryenNeInt64(void) { return NeInt64; }
+BinaryenOp BinaryenLtSInt64(void) { return LtSInt64; }
+BinaryenOp BinaryenLtUInt64(void) { return LtUInt64; }
+BinaryenOp BinaryenLeSInt64(void) { return LeSInt64; }
+BinaryenOp BinaryenLeUInt64(void) { return LeUInt64; }
+BinaryenOp BinaryenGtSInt64(void) { return GtSInt64; }
+BinaryenOp BinaryenGtUInt64(void) { return GtUInt64; }
+BinaryenOp BinaryenGeSInt64(void) { return GeSInt64; }
+BinaryenOp BinaryenGeUInt64(void) { return GeUInt64; }
+BinaryenOp BinaryenAddFloat32(void) { return AddFloat32; }
+BinaryenOp BinaryenSubFloat32(void) { return SubFloat32; }
+BinaryenOp BinaryenMulFloat32(void) { return MulFloat32; }
+BinaryenOp BinaryenDivFloat32(void) { return DivFloat32; }
+BinaryenOp BinaryenCopySignFloat32(void) { return CopySignFloat32; }
+BinaryenOp BinaryenMinFloat32(void) { return MinFloat32; }
+BinaryenOp BinaryenMaxFloat32(void) { return MaxFloat32; }
+BinaryenOp BinaryenEqFloat32(void) { return EqFloat32; }
+BinaryenOp BinaryenNeFloat32(void) { return NeFloat32; }
+BinaryenOp BinaryenLtFloat32(void) { return LtFloat32; }
+BinaryenOp BinaryenLeFloat32(void) { return LeFloat32; }
+BinaryenOp BinaryenGtFloat32(void) { return GtFloat32; }
+BinaryenOp BinaryenGeFloat32(void) { return GeFloat32; }
+BinaryenOp BinaryenAddFloat64(void) { return AddFloat64; }
+BinaryenOp BinaryenSubFloat64(void) { return SubFloat64; }
+BinaryenOp BinaryenMulFloat64(void) { return MulFloat64; }
+BinaryenOp BinaryenDivFloat64(void) { return DivFloat64; }
+BinaryenOp BinaryenCopySignFloat64(void) { return CopySignFloat64; }
+BinaryenOp BinaryenMinFloat64(void) { return MinFloat64; }
+BinaryenOp BinaryenMaxFloat64(void) { return MaxFloat64; }
+BinaryenOp BinaryenEqFloat64(void) { return EqFloat64; }
+BinaryenOp BinaryenNeFloat64(void) { return NeFloat64; }
+BinaryenOp BinaryenLtFloat64(void) { return LtFloat64; }
+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 BinaryenTruncSatSFloat32ToInt32(void) {
+  return TruncSatSFloat32ToInt32;
+}
+BinaryenOp BinaryenTruncSatSFloat32ToInt64(void) {
+  return TruncSatSFloat32ToInt64;
+}
+BinaryenOp BinaryenTruncSatUFloat32ToInt32(void) {
+  return TruncSatUFloat32ToInt32;
+}
+BinaryenOp BinaryenTruncSatUFloat32ToInt64(void) {
+  return TruncSatUFloat32ToInt64;
+}
+BinaryenOp BinaryenTruncSatSFloat64ToInt32(void) {
+  return TruncSatSFloat64ToInt32;
+}
+BinaryenOp BinaryenTruncSatSFloat64ToInt64(void) {
+  return TruncSatSFloat64ToInt64;
+}
+BinaryenOp BinaryenTruncSatUFloat64ToInt32(void) {
+  return TruncSatUFloat64ToInt32;
+}
+BinaryenOp BinaryenTruncSatUFloat64ToInt64(void) {
+  return TruncSatUFloat64ToInt64;
+}
+BinaryenOp BinaryenSplatVecI8x16(void) { return SplatVecI8x16; }
+BinaryenOp BinaryenExtractLaneSVecI8x16(void) { return ExtractLaneSVecI8x16; }
+BinaryenOp BinaryenExtractLaneUVecI8x16(void) { return ExtractLaneUVecI8x16; }
+BinaryenOp BinaryenReplaceLaneVecI8x16(void) { return ReplaceLaneVecI8x16; }
+BinaryenOp BinaryenSplatVecI16x8(void) { return SplatVecI16x8; }
+BinaryenOp BinaryenExtractLaneSVecI16x8(void) { return ExtractLaneSVecI16x8; }
+BinaryenOp BinaryenExtractLaneUVecI16x8(void) { return ExtractLaneUVecI16x8; }
+BinaryenOp BinaryenReplaceLaneVecI16x8(void) { return ReplaceLaneVecI16x8; }
+BinaryenOp BinaryenSplatVecI32x4(void) { return SplatVecI32x4; }
+BinaryenOp BinaryenExtractLaneVecI32x4(void) { return ExtractLaneVecI32x4; }
+BinaryenOp BinaryenReplaceLaneVecI32x4(void) { return ReplaceLaneVecI32x4; }
+BinaryenOp BinaryenSplatVecI64x2(void) { return SplatVecI64x2; }
+BinaryenOp BinaryenExtractLaneVecI64x2(void) { return ExtractLaneVecI64x2; }
+BinaryenOp BinaryenReplaceLaneVecI64x2(void) { return ReplaceLaneVecI64x2; }
+BinaryenOp BinaryenSplatVecF32x4(void) { return SplatVecF32x4; }
+BinaryenOp BinaryenExtractLaneVecF32x4(void) { return ExtractLaneVecF32x4; }
+BinaryenOp BinaryenReplaceLaneVecF32x4(void) { return ReplaceLaneVecF32x4; }
+BinaryenOp BinaryenSplatVecF64x2(void) { return SplatVecF64x2; }
+BinaryenOp BinaryenExtractLaneVecF64x2(void) { return ExtractLaneVecF64x2; }
+BinaryenOp BinaryenReplaceLaneVecF64x2(void) { return ReplaceLaneVecF64x2; }
+BinaryenOp BinaryenEqVecI8x16(void) { return EqVecI8x16; }
+BinaryenOp BinaryenNeVecI8x16(void) { return NeVecI8x16; }
+BinaryenOp BinaryenLtSVecI8x16(void) { return LtSVecI8x16; }
+BinaryenOp BinaryenLtUVecI8x16(void) { return LtUVecI8x16; }
+BinaryenOp BinaryenGtSVecI8x16(void) { return GtSVecI8x16; }
+BinaryenOp BinaryenGtUVecI8x16(void) { return GtUVecI8x16; }
+BinaryenOp BinaryenLeSVecI8x16(void) { return LeSVecI8x16; }
+BinaryenOp BinaryenLeUVecI8x16(void) { return LeUVecI8x16; }
+BinaryenOp BinaryenGeSVecI8x16(void) { return GeSVecI8x16; }
+BinaryenOp BinaryenGeUVecI8x16(void) { return GeUVecI8x16; }
+BinaryenOp BinaryenEqVecI16x8(void) { return EqVecI16x8; }
+BinaryenOp BinaryenNeVecI16x8(void) { return NeVecI16x8; }
+BinaryenOp BinaryenLtSVecI16x8(void) { return LtSVecI16x8; }
+BinaryenOp BinaryenLtUVecI16x8(void) { return LtUVecI16x8; }
+BinaryenOp BinaryenGtSVecI16x8(void) { return GtSVecI16x8; }
+BinaryenOp BinaryenGtUVecI16x8(void) { return GtUVecI16x8; }
+BinaryenOp BinaryenLeSVecI16x8(void) { return LeSVecI16x8; }
+BinaryenOp BinaryenLeUVecI16x8(void) { return LeUVecI16x8; }
+BinaryenOp BinaryenGeSVecI16x8(void) { return GeSVecI16x8; }
+BinaryenOp BinaryenGeUVecI16x8(void) { return GeUVecI16x8; }
+BinaryenOp BinaryenEqVecI32x4(void) { return EqVecI32x4; }
+BinaryenOp BinaryenNeVecI32x4(void) { return NeVecI32x4; }
+BinaryenOp BinaryenLtSVecI32x4(void) { return LtSVecI32x4; }
+BinaryenOp BinaryenLtUVecI32x4(void) { return LtUVecI32x4; }
+BinaryenOp BinaryenGtSVecI32x4(void) { return GtSVecI32x4; }
+BinaryenOp BinaryenGtUVecI32x4(void) { return GtUVecI32x4; }
+BinaryenOp BinaryenLeSVecI32x4(void) { return LeSVecI32x4; }
+BinaryenOp BinaryenLeUVecI32x4(void) { return LeUVecI32x4; }
+BinaryenOp BinaryenGeSVecI32x4(void) { return GeSVecI32x4; }
+BinaryenOp BinaryenGeUVecI32x4(void) { return GeUVecI32x4; }
+BinaryenOp BinaryenEqVecF32x4(void) { return EqVecF32x4; }
+BinaryenOp BinaryenNeVecF32x4(void) { return NeVecF32x4; }
+BinaryenOp BinaryenLtVecF32x4(void) { return LtVecF32x4; }
+BinaryenOp BinaryenGtVecF32x4(void) { return GtVecF32x4; }
+BinaryenOp BinaryenLeVecF32x4(void) { return LeVecF32x4; }
+BinaryenOp BinaryenGeVecF32x4(void) { return GeVecF32x4; }
+BinaryenOp BinaryenEqVecF64x2(void) { return EqVecF64x2; }
+BinaryenOp BinaryenNeVecF64x2(void) { return NeVecF64x2; }
+BinaryenOp BinaryenLtVecF64x2(void) { return LtVecF64x2; }
+BinaryenOp BinaryenGtVecF64x2(void) { return GtVecF64x2; }
+BinaryenOp BinaryenLeVecF64x2(void) { return LeVecF64x2; }
+BinaryenOp BinaryenGeVecF64x2(void) { return GeVecF64x2; }
+BinaryenOp BinaryenNotVec128(void) { return NotVec128; }
+BinaryenOp BinaryenAndVec128(void) { return AndVec128; }
+BinaryenOp BinaryenOrVec128(void) { return OrVec128; }
+BinaryenOp BinaryenXorVec128(void) { return XorVec128; }
+BinaryenOp BinaryenAndNotVec128(void) { return AndNotVec128; }
+BinaryenOp BinaryenBitselectVec128(void) { return Bitselect; }
+BinaryenOp BinaryenAbsVecI8x16(void) { return AbsVecI8x16; }
+BinaryenOp BinaryenNegVecI8x16(void) { return NegVecI8x16; }
+BinaryenOp BinaryenAnyTrueVecI8x16(void) { return AnyTrueVecI8x16; }
+BinaryenOp BinaryenAllTrueVecI8x16(void) { return AllTrueVecI8x16; }
+BinaryenOp BinaryenBitmaskVecI8x16(void) { return BitmaskVecI8x16; }
+BinaryenOp BinaryenShlVecI8x16(void) { return ShlVecI8x16; }
+BinaryenOp BinaryenShrSVecI8x16(void) { return ShrSVecI8x16; }
+BinaryenOp BinaryenShrUVecI8x16(void) { return ShrUVecI8x16; }
+BinaryenOp BinaryenAddVecI8x16(void) { return AddVecI8x16; }
+BinaryenOp BinaryenAddSatSVecI8x16(void) { return AddSatSVecI8x16; }
+BinaryenOp BinaryenAddSatUVecI8x16(void) { return AddSatUVecI8x16; }
+BinaryenOp BinaryenSubVecI8x16(void) { return SubVecI8x16; }
+BinaryenOp BinaryenSubSatSVecI8x16(void) { return SubSatSVecI8x16; }
+BinaryenOp BinaryenSubSatUVecI8x16(void) { return SubSatUVecI8x16; }
+BinaryenOp BinaryenMulVecI8x16(void) { return MulVecI8x16; }
+BinaryenOp BinaryenMinSVecI8x16(void) { return MinSVecI8x16; }
+BinaryenOp BinaryenMinUVecI8x16(void) { return MinUVecI8x16; }
+BinaryenOp BinaryenMaxSVecI8x16(void) { return MaxSVecI8x16; }
+BinaryenOp BinaryenMaxUVecI8x16(void) { return MaxUVecI8x16; }
+BinaryenOp BinaryenAvgrUVecI8x16(void) { return AvgrUVecI8x16; }
+BinaryenOp BinaryenAbsVecI16x8(void) { return AbsVecI16x8; }
+BinaryenOp BinaryenNegVecI16x8(void) { return NegVecI16x8; }
+BinaryenOp BinaryenAnyTrueVecI16x8(void) { return AnyTrueVecI16x8; }
+BinaryenOp BinaryenAllTrueVecI16x8(void) { return AllTrueVecI16x8; }
+BinaryenOp BinaryenBitmaskVecI16x8(void) { return BitmaskVecI16x8; }
+BinaryenOp BinaryenShlVecI16x8(void) { return ShlVecI16x8; }
+BinaryenOp BinaryenShrSVecI16x8(void) { return ShrSVecI16x8; }
+BinaryenOp BinaryenShrUVecI16x8(void) { return ShrUVecI16x8; }
+BinaryenOp BinaryenAddVecI16x8(void) { return AddVecI16x8; }
+BinaryenOp BinaryenAddSatSVecI16x8(void) { return AddSatSVecI16x8; }
+BinaryenOp BinaryenAddSatUVecI16x8(void) { return AddSatUVecI16x8; }
+BinaryenOp BinaryenSubVecI16x8(void) { return SubVecI16x8; }
+BinaryenOp BinaryenSubSatSVecI16x8(void) { return SubSatSVecI16x8; }
+BinaryenOp BinaryenSubSatUVecI16x8(void) { return SubSatUVecI16x8; }
+BinaryenOp BinaryenMulVecI16x8(void) { return MulVecI16x8; }
+BinaryenOp BinaryenMinSVecI16x8(void) { return MinSVecI16x8; }
+BinaryenOp BinaryenMinUVecI16x8(void) { return MinUVecI16x8; }
+BinaryenOp BinaryenMaxSVecI16x8(void) { return MaxSVecI16x8; }
+BinaryenOp BinaryenMaxUVecI16x8(void) { return MaxUVecI16x8; }
+BinaryenOp BinaryenAvgrUVecI16x8(void) { return AvgrUVecI16x8; }
+BinaryenOp BinaryenAbsVecI32x4(void) { return AbsVecI32x4; }
+BinaryenOp BinaryenNegVecI32x4(void) { return NegVecI32x4; }
+BinaryenOp BinaryenAnyTrueVecI32x4(void) { return AnyTrueVecI32x4; }
+BinaryenOp BinaryenAllTrueVecI32x4(void) { return AllTrueVecI32x4; }
+BinaryenOp BinaryenBitmaskVecI32x4(void) { return BitmaskVecI32x4; }
+BinaryenOp BinaryenShlVecI32x4(void) { return ShlVecI32x4; }
+BinaryenOp BinaryenShrSVecI32x4(void) { return ShrSVecI32x4; }
+BinaryenOp BinaryenShrUVecI32x4(void) { return ShrUVecI32x4; }
+BinaryenOp BinaryenAddVecI32x4(void) { return AddVecI32x4; }
+BinaryenOp BinaryenSubVecI32x4(void) { return SubVecI32x4; }
+BinaryenOp BinaryenMulVecI32x4(void) { return MulVecI32x4; }
+BinaryenOp BinaryenMinSVecI32x4(void) { return MinSVecI32x4; }
+BinaryenOp BinaryenMinUVecI32x4(void) { return MinUVecI32x4; }
+BinaryenOp BinaryenMaxSVecI32x4(void) { return MaxSVecI32x4; }
+BinaryenOp BinaryenMaxUVecI32x4(void) { return MaxUVecI32x4; }
+BinaryenOp BinaryenDotSVecI16x8ToVecI32x4(void) {
+  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; }
+BinaryenOp BinaryenAddVecI64x2(void) { return AddVecI64x2; }
+BinaryenOp BinaryenSubVecI64x2(void) { return SubVecI64x2; }
+BinaryenOp BinaryenMulVecI64x2(void) { return MulVecI64x2; }
+BinaryenOp BinaryenAbsVecF32x4(void) { return AbsVecF32x4; }
+BinaryenOp BinaryenNegVecF32x4(void) { return NegVecF32x4; }
+BinaryenOp BinaryenSqrtVecF32x4(void) { return SqrtVecF32x4; }
+BinaryenOp BinaryenQFMAVecF32x4(void) { return QFMAF32x4; }
+BinaryenOp BinaryenQFMSVecF32x4(void) { return QFMSF32x4; }
+BinaryenOp BinaryenAddVecF32x4(void) { return AddVecF32x4; }
+BinaryenOp BinaryenSubVecF32x4(void) { return SubVecF32x4; }
+BinaryenOp BinaryenMulVecF32x4(void) { return MulVecF32x4; }
+BinaryenOp BinaryenDivVecF32x4(void) { return DivVecF32x4; }
+BinaryenOp BinaryenMinVecF32x4(void) { return MinVecF32x4; }
+BinaryenOp BinaryenMaxVecF32x4(void) { return MaxVecF32x4; }
+BinaryenOp BinaryenPMinVecF32x4(void) { return PMinVecF32x4; }
+BinaryenOp BinaryenCeilVecF32x4(void) { return CeilVecF32x4; }
+BinaryenOp BinaryenFloorVecF32x4(void) { return FloorVecF32x4; }
+BinaryenOp BinaryenTruncVecF32x4(void) { return TruncVecF32x4; }
+BinaryenOp BinaryenNearestVecF32x4(void) { return NearestVecF32x4; }
+BinaryenOp BinaryenPMaxVecF32x4(void) { return PMaxVecF32x4; }
+BinaryenOp BinaryenAbsVecF64x2(void) { return AbsVecF64x2; }
+BinaryenOp BinaryenNegVecF64x2(void) { return NegVecF64x2; }
+BinaryenOp BinaryenSqrtVecF64x2(void) { return SqrtVecF64x2; }
+BinaryenOp BinaryenQFMAVecF64x2(void) { return QFMAF64x2; }
+BinaryenOp BinaryenQFMSVecF64x2(void) { return QFMSF64x2; }
+BinaryenOp BinaryenAddVecF64x2(void) { return AddVecF64x2; }
+BinaryenOp BinaryenSubVecF64x2(void) { return SubVecF64x2; }
+BinaryenOp BinaryenMulVecF64x2(void) { return MulVecF64x2; }
+BinaryenOp BinaryenDivVecF64x2(void) { return DivVecF64x2; }
+BinaryenOp BinaryenMinVecF64x2(void) { return MinVecF64x2; }
+BinaryenOp BinaryenMaxVecF64x2(void) { return MaxVecF64x2; }
+BinaryenOp BinaryenPMinVecF64x2(void) { return PMinVecF64x2; }
+BinaryenOp BinaryenPMaxVecF64x2(void) { return PMaxVecF64x2; }
+BinaryenOp BinaryenCeilVecF64x2(void) { return CeilVecF64x2; }
+BinaryenOp BinaryenFloorVecF64x2(void) { return FloorVecF64x2; }
+BinaryenOp BinaryenTruncVecF64x2(void) { return TruncVecF64x2; }
+BinaryenOp BinaryenNearestVecF64x2(void) { return NearestVecF64x2; }
+BinaryenOp BinaryenTruncSatSVecF32x4ToVecI32x4(void) {
+  return TruncSatSVecF32x4ToVecI32x4;
+}
+BinaryenOp BinaryenTruncSatUVecF32x4ToVecI32x4(void) {
+  return TruncSatUVecF32x4ToVecI32x4;
+}
+BinaryenOp BinaryenTruncSatSVecF64x2ToVecI64x2(void) {
+  return TruncSatSVecF64x2ToVecI64x2;
+}
+BinaryenOp BinaryenTruncSatUVecF64x2ToVecI64x2(void) {
+  return TruncSatUVecF64x2ToVecI64x2;
+}
+BinaryenOp BinaryenConvertSVecI32x4ToVecF32x4(void) {
+  return ConvertSVecI32x4ToVecF32x4;
+}
+BinaryenOp BinaryenConvertUVecI32x4ToVecF32x4(void) {
+  return ConvertUVecI32x4ToVecF32x4;
+}
+BinaryenOp BinaryenConvertSVecI64x2ToVecF64x2(void) {
+  return ConvertSVecI64x2ToVecF64x2;
+}
+BinaryenOp BinaryenConvertUVecI64x2ToVecF64x2(void) {
+  return ConvertUVecI64x2ToVecF64x2;
+}
+BinaryenOp BinaryenLoadSplatVec8x16(void) { return LoadSplatVec8x16; }
+BinaryenOp BinaryenLoadSplatVec16x8(void) { return LoadSplatVec16x8; }
+BinaryenOp BinaryenLoadSplatVec32x4(void) { return LoadSplatVec32x4; }
+BinaryenOp BinaryenLoadSplatVec64x2(void) { return LoadSplatVec64x2; }
+BinaryenOp BinaryenLoadExtSVec8x8ToVecI16x8(void) {
+  return LoadExtSVec8x8ToVecI16x8;
+}
+BinaryenOp BinaryenLoadExtUVec8x8ToVecI16x8(void) {
+  return LoadExtUVec8x8ToVecI16x8;
+}
+BinaryenOp BinaryenLoadExtSVec16x4ToVecI32x4(void) {
+  return LoadExtSVec16x4ToVecI32x4;
+}
+BinaryenOp BinaryenLoadExtUVec16x4ToVecI32x4(void) {
+  return LoadExtUVec16x4ToVecI32x4;
+}
+BinaryenOp BinaryenLoadExtSVec32x2ToVecI64x2(void) {
+  return LoadExtSVec32x2ToVecI64x2;
+}
+BinaryenOp BinaryenLoadExtUVec32x2ToVecI64x2(void) {
+  return LoadExtUVec32x2ToVecI64x2;
+}
+BinaryenOp BinaryenNarrowSVecI16x8ToVecI8x16(void) {
+  return NarrowSVecI16x8ToVecI8x16;
+}
+BinaryenOp BinaryenNarrowUVecI16x8ToVecI8x16(void) {
+  return NarrowUVecI16x8ToVecI8x16;
+}
+BinaryenOp BinaryenNarrowSVecI32x4ToVecI16x8(void) {
+  return NarrowSVecI32x4ToVecI16x8;
+}
+BinaryenOp BinaryenNarrowUVecI32x4ToVecI16x8(void) {
+  return NarrowUVecI32x4ToVecI16x8;
+}
+BinaryenOp BinaryenWidenLowSVecI8x16ToVecI16x8(void) {
+  return WidenLowSVecI8x16ToVecI16x8;
+}
+BinaryenOp BinaryenWidenHighSVecI8x16ToVecI16x8(void) {
+  return WidenHighSVecI8x16ToVecI16x8;
+}
+BinaryenOp BinaryenWidenLowUVecI8x16ToVecI16x8(void) {
+  return WidenLowUVecI8x16ToVecI16x8;
+}
+BinaryenOp BinaryenWidenHighUVecI8x16ToVecI16x8(void) {
+  return WidenHighUVecI8x16ToVecI16x8;
+}
+BinaryenOp BinaryenWidenLowSVecI16x8ToVecI32x4(void) {
+  return WidenLowSVecI16x8ToVecI32x4;
+}
+BinaryenOp BinaryenWidenHighSVecI16x8ToVecI32x4(void) {
+  return WidenHighSVecI16x8ToVecI32x4;
+}
+BinaryenOp BinaryenWidenLowUVecI16x8ToVecI32x4(void) {
+  return WidenLowUVecI16x8ToVecI32x4;
+}
+BinaryenOp BinaryenWidenHighUVecI16x8ToVecI32x4(void) {
+  return WidenHighUVecI16x8ToVecI32x4;
+}
+BinaryenOp BinaryenSwizzleVec8x16(void) { return SwizzleVec8x16; }
+
+BinaryenExpressionRef BinaryenBlock(BinaryenModuleRef module,
+                                    const char* name,
+                                    BinaryenExpressionRef* children,
+                                    BinaryenIndex numChildren,
+                                    BinaryenType type) {
+  auto* ret = ((Module*)module)->allocator.alloc<Block>();
+  if (name) {
+    ret->name = name;
+  }
+  for (BinaryenIndex i = 0; i < numChildren; i++) {
+    ret->list.push_back((Expression*)children[i]);
+  }
+  if (type != BinaryenTypeAuto()) {
+    ret->finalize(Type(type));
+  } else {
+    ret->finalize();
+  }
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenIf(BinaryenModuleRef module,
+                                 BinaryenExpressionRef condition,
+                                 BinaryenExpressionRef ifTrue,
+                                 BinaryenExpressionRef ifFalse) {
+  auto* ret = ((Module*)module)->allocator.alloc<If>();
+  ret->condition = (Expression*)condition;
+  ret->ifTrue = (Expression*)ifTrue;
+  ret->ifFalse = (Expression*)ifFalse;
+  ret->finalize();
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenLoop(BinaryenModuleRef module,
+                                   const char* name,
+                                   BinaryenExpressionRef body) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module)
+      .makeLoop(name ? Name(name) : Name(), (Expression*)body));
+}
+BinaryenExpressionRef BinaryenBreak(BinaryenModuleRef module,
+                                    const char* name,
+                                    BinaryenExpressionRef condition,
+                                    BinaryenExpressionRef value) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module)
+      .makeBreak(name, (Expression*)value, (Expression*)condition));
+}
+BinaryenExpressionRef BinaryenSwitch(BinaryenModuleRef module,
+                                     const char** names,
+                                     BinaryenIndex numNames,
+                                     const char* defaultName,
+                                     BinaryenExpressionRef condition,
+                                     BinaryenExpressionRef value) {
+  auto* ret = ((Module*)module)->allocator.alloc<Switch>();
+  for (BinaryenIndex i = 0; i < numNames; i++) {
+    ret->targets.push_back(names[i]);
+  }
+  ret->default_ = defaultName;
+  ret->condition = (Expression*)condition;
+  ret->value = (Expression*)value;
+  ret->finalize();
+  return static_cast<Expression*>(ret);
+}
+static BinaryenExpressionRef makeBinaryenCall(BinaryenModuleRef module,
+                                              const char* target,
+                                              BinaryenExpressionRef* operands,
+                                              BinaryenIndex numOperands,
+                                              BinaryenType returnType,
+                                              bool isReturn) {
+  auto* ret = ((Module*)module)->allocator.alloc<Call>();
+  ret->target = target;
+  for (BinaryenIndex i = 0; i < numOperands; i++) {
+    ret->operands.push_back((Expression*)operands[i]);
+  }
+  ret->type = Type(returnType);
+  ret->isReturn = isReturn;
+  ret->finalize();
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenCall(BinaryenModuleRef module,
+                                   const char* target,
+                                   BinaryenExpressionRef* operands,
+                                   BinaryenIndex numOperands,
+                                   BinaryenType returnType) {
+  return makeBinaryenCall(
+    module, target, operands, numOperands, returnType, false);
+}
+BinaryenExpressionRef BinaryenReturnCall(BinaryenModuleRef module,
+                                         const char* target,
+                                         BinaryenExpressionRef* operands,
+                                         BinaryenIndex numOperands,
+                                         BinaryenType returnType) {
+  return makeBinaryenCall(
+    module, target, operands, numOperands, returnType, true);
+}
+static BinaryenExpressionRef
+makeBinaryenCallIndirect(BinaryenModuleRef module,
+                         BinaryenExpressionRef target,
+                         BinaryenExpressionRef* operands,
+                         BinaryenIndex numOperands,
+                         BinaryenType params,
+                         BinaryenType results,
+                         bool isReturn) {
+  auto* ret = ((Module*)module)->allocator.alloc<CallIndirect>();
+  ret->target = (Expression*)target;
+  for (BinaryenIndex i = 0; i < numOperands; i++) {
+    ret->operands.push_back((Expression*)operands[i]);
+  }
+  ret->sig = Signature(Type(params), Type(results));
+  ret->type = Type(results);
+  ret->isReturn = isReturn;
+  ret->finalize();
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenCallIndirect(BinaryenModuleRef module,
+                                           BinaryenExpressionRef target,
+                                           BinaryenExpressionRef* operands,
+                                           BinaryenIndex numOperands,
+                                           BinaryenType params,
+                                           BinaryenType results) {
+  return makeBinaryenCallIndirect(
+    module, target, operands, numOperands, params, results, false);
+}
+BinaryenExpressionRef
+BinaryenReturnCallIndirect(BinaryenModuleRef module,
+                           BinaryenExpressionRef target,
+                           BinaryenExpressionRef* operands,
+                           BinaryenIndex numOperands,
+                           BinaryenType params,
+                           BinaryenType results) {
+  return makeBinaryenCallIndirect(
+    module, target, operands, numOperands, params, results, true);
+}
+BinaryenExpressionRef BinaryenLocalGet(BinaryenModuleRef module,
+                                       BinaryenIndex index,
+                                       BinaryenType type) {
+  auto* ret = ((Module*)module)->allocator.alloc<LocalGet>();
+  ret->index = index;
+  ret->type = Type(type);
+  ret->finalize();
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenLocalSet(BinaryenModuleRef module,
+                                       BinaryenIndex index,
+                                       BinaryenExpressionRef value) {
+  auto* ret = ((Module*)module)->allocator.alloc<LocalSet>();
+  ret->index = index;
+  ret->value = (Expression*)value;
+  ret->makeSet();
+  ret->finalize();
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenLocalTee(BinaryenModuleRef module,
+                                       BinaryenIndex index,
+                                       BinaryenExpressionRef value,
+                                       BinaryenType type) {
+  auto* ret = ((Module*)module)->allocator.alloc<LocalSet>();
+  ret->index = index;
+  ret->value = (Expression*)value;
+  ret->makeTee(Type(type));
+  ret->finalize();
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenGlobalGet(BinaryenModuleRef module,
+                                        const char* name,
+                                        BinaryenType type) {
+  auto* ret = ((Module*)module)->allocator.alloc<GlobalGet>();
+  ret->name = name;
+  ret->type = Type(type);
+  ret->finalize();
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenGlobalSet(BinaryenModuleRef module,
+                                        const char* name,
+                                        BinaryenExpressionRef value) {
+  auto* ret = ((Module*)module)->allocator.alloc<GlobalSet>();
+  ret->name = name;
+  ret->value = (Expression*)value;
+  ret->finalize();
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module,
+                                   uint32_t bytes,
+                                   int8_t signed_,
+                                   uint32_t offset,
+                                   uint32_t align,
+                                   BinaryenType type,
+                                   BinaryenExpressionRef ptr) {
+  auto* ret = ((Module*)module)->allocator.alloc<Load>();
+  ret->isAtomic = false;
+  ret->bytes = bytes;
+  ret->signed_ = !!signed_;
+  ret->offset = offset;
+  ret->align = align ? align : bytes;
+  ret->type = Type(type);
+  ret->ptr = (Expression*)ptr;
+  ret->finalize();
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module,
+                                    uint32_t bytes,
+                                    uint32_t offset,
+                                    uint32_t align,
+                                    BinaryenExpressionRef ptr,
+                                    BinaryenExpressionRef value,
+                                    BinaryenType type) {
+  auto* ret = ((Module*)module)->allocator.alloc<Store>();
+  ret->isAtomic = false;
+  ret->bytes = bytes;
+  ret->offset = offset;
+  ret->align = align ? align : bytes;
+  ret->ptr = (Expression*)ptr;
+  ret->value = (Expression*)value;
+  ret->valueType = Type(type);
+  ret->finalize();
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenConst(BinaryenModuleRef module,
+                                    BinaryenLiteral value) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module).makeConst(fromBinaryenLiteral(value)));
+}
+BinaryenExpressionRef BinaryenUnary(BinaryenModuleRef module,
+                                    BinaryenOp op,
+                                    BinaryenExpressionRef value) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module).makeUnary(UnaryOp(op), (Expression*)value));
+}
+BinaryenExpressionRef BinaryenBinary(BinaryenModuleRef module,
+                                     BinaryenOp op,
+                                     BinaryenExpressionRef left,
+                                     BinaryenExpressionRef right) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module)
+      .makeBinary(BinaryOp(op), (Expression*)left, (Expression*)right));
+}
+BinaryenExpressionRef BinaryenSelect(BinaryenModuleRef module,
+                                     BinaryenExpressionRef condition,
+                                     BinaryenExpressionRef ifTrue,
+                                     BinaryenExpressionRef ifFalse,
+                                     BinaryenType type) {
+  auto* ret = ((Module*)module)->allocator.alloc<Select>();
+  ret->condition = (Expression*)condition;
+  ret->ifTrue = (Expression*)ifTrue;
+  ret->ifFalse = (Expression*)ifFalse;
+  if (type != BinaryenTypeAuto()) {
+    ret->finalize(Type(type));
+  } else {
+    ret->finalize();
+  }
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module,
+                                   BinaryenExpressionRef value) {
+  auto* ret = ((Module*)module)->allocator.alloc<Drop>();
+  ret->value = (Expression*)value;
+  ret->finalize();
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenReturn(BinaryenModuleRef module,
+                                     BinaryenExpressionRef value) {
+  auto* ret = Builder(*(Module*)module).makeReturn((Expression*)value);
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenMemorySize(BinaryenModuleRef module) {
+  auto* ret = Builder(*(Module*)module).makeMemorySize();
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenMemoryGrow(BinaryenModuleRef module,
+                                         BinaryenExpressionRef delta) {
+  auto* ret = Builder(*(Module*)module).makeMemoryGrow((Expression*)delta);
+  return static_cast<Expression*>(ret);
+}
+BinaryenExpressionRef BinaryenNop(BinaryenModuleRef module) {
+  return static_cast<Expression*>(((Module*)module)->allocator.alloc<Nop>());
+}
+BinaryenExpressionRef BinaryenUnreachable(BinaryenModuleRef module) {
+  return static_cast<Expression*>(
+    ((Module*)module)->allocator.alloc<Unreachable>());
+}
+BinaryenExpressionRef BinaryenAtomicLoad(BinaryenModuleRef module,
+                                         uint32_t bytes,
+                                         uint32_t offset,
+                                         BinaryenType type,
+                                         BinaryenExpressionRef ptr) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module)
+      .makeAtomicLoad(bytes, offset, (Expression*)ptr, Type(type)));
+}
+BinaryenExpressionRef BinaryenAtomicStore(BinaryenModuleRef module,
+                                          uint32_t bytes,
+                                          uint32_t offset,
+                                          BinaryenExpressionRef ptr,
+                                          BinaryenExpressionRef value,
+                                          BinaryenType type) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module)
+      .makeAtomicStore(
+        bytes, offset, (Expression*)ptr, (Expression*)value, Type(type)));
+}
+BinaryenExpressionRef BinaryenAtomicRMW(BinaryenModuleRef module,
+                                        BinaryenOp op,
+                                        BinaryenIndex bytes,
+                                        BinaryenIndex offset,
+                                        BinaryenExpressionRef ptr,
+                                        BinaryenExpressionRef value,
+                                        BinaryenType type) {
+  return static_cast<Expression*>(Builder(*(Module*)module)
+                                    .makeAtomicRMW(AtomicRMWOp(op),
+                                                   bytes,
+                                                   offset,
+                                                   (Expression*)ptr,
+                                                   (Expression*)value,
+                                                   Type(type)));
+}
+BinaryenExpressionRef BinaryenAtomicCmpxchg(BinaryenModuleRef module,
+                                            BinaryenIndex bytes,
+                                            BinaryenIndex offset,
+                                            BinaryenExpressionRef ptr,
+                                            BinaryenExpressionRef expected,
+                                            BinaryenExpressionRef replacement,
+                                            BinaryenType type) {
+  return static_cast<Expression*>(Builder(*(Module*)module)
+                                    .makeAtomicCmpxchg(bytes,
+                                                       offset,
+                                                       (Expression*)ptr,
+                                                       (Expression*)expected,
+                                                       (Expression*)replacement,
+                                                       Type(type)));
+}
+BinaryenExpressionRef BinaryenAtomicWait(BinaryenModuleRef module,
+                                         BinaryenExpressionRef ptr,
+                                         BinaryenExpressionRef expected,
+                                         BinaryenExpressionRef timeout,
+                                         BinaryenType expectedType) {
+  return static_cast<Expression*>(Builder(*(Module*)module)
+                                    .makeAtomicWait((Expression*)ptr,
+                                                    (Expression*)expected,
+                                                    (Expression*)timeout,
+                                                    Type(expectedType),
+                                                    0));
+}
+BinaryenExpressionRef BinaryenAtomicNotify(BinaryenModuleRef module,
+                                           BinaryenExpressionRef ptr,
+                                           BinaryenExpressionRef notifyCount) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module)
+      .makeAtomicNotify((Expression*)ptr, (Expression*)notifyCount, 0));
+}
+BinaryenExpressionRef BinaryenAtomicFence(BinaryenModuleRef module) {
+  return static_cast<Expression*>(Builder(*(Module*)module).makeAtomicFence());
+}
+BinaryenExpressionRef BinaryenSIMDExtract(BinaryenModuleRef module,
+                                          BinaryenOp op,
+                                          BinaryenExpressionRef vec,
+                                          uint8_t index) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module)
+      .makeSIMDExtract(SIMDExtractOp(op), (Expression*)vec, index));
+}
+BinaryenExpressionRef BinaryenSIMDReplace(BinaryenModuleRef module,
+                                          BinaryenOp op,
+                                          BinaryenExpressionRef vec,
+                                          uint8_t index,
+                                          BinaryenExpressionRef value) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module)
+      .makeSIMDReplace(
+        SIMDReplaceOp(op), (Expression*)vec, index, (Expression*)value));
+}
+BinaryenExpressionRef BinaryenSIMDShuffle(BinaryenModuleRef module,
+                                          BinaryenExpressionRef left,
+                                          BinaryenExpressionRef right,
+                                          const uint8_t mask_[16]) {
+  assert(mask_); // nullptr would be wrong
+  std::array<uint8_t, 16> mask;
+  memcpy(mask.data(), mask_, 16);
+  return static_cast<Expression*>(
+    Builder(*(Module*)module)
+      .makeSIMDShuffle((Expression*)left, (Expression*)right, mask));
+}
+BinaryenExpressionRef BinaryenSIMDTernary(BinaryenModuleRef module,
+                                          BinaryenOp op,
+                                          BinaryenExpressionRef a,
+                                          BinaryenExpressionRef b,
+                                          BinaryenExpressionRef c) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module)
+      .makeSIMDTernary(
+        SIMDTernaryOp(op), (Expression*)a, (Expression*)b, (Expression*)c));
+}
+BinaryenExpressionRef BinaryenSIMDShift(BinaryenModuleRef module,
+                                        BinaryenOp op,
+                                        BinaryenExpressionRef vec,
+                                        BinaryenExpressionRef shift) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module)
+      .makeSIMDShift(SIMDShiftOp(op), (Expression*)vec, (Expression*)shift));
+}
+BinaryenExpressionRef BinaryenSIMDLoad(BinaryenModuleRef module,
+                                       BinaryenOp op,
+                                       uint32_t offset,
+                                       uint32_t align,
+                                       BinaryenExpressionRef ptr) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module)
+      .makeSIMDLoad(
+        SIMDLoadOp(op), Address(offset), Address(align), (Expression*)ptr));
+}
+BinaryenExpressionRef BinaryenMemoryInit(BinaryenModuleRef module,
+                                         uint32_t segment,
+                                         BinaryenExpressionRef dest,
+                                         BinaryenExpressionRef offset,
+                                         BinaryenExpressionRef size) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module)
+      .makeMemoryInit(
+        segment, (Expression*)dest, (Expression*)offset, (Expression*)size));
+}
+
+BinaryenExpressionRef BinaryenDataDrop(BinaryenModuleRef module,
+                                       uint32_t segment) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module).makeDataDrop(segment));
+}
+
+BinaryenExpressionRef BinaryenMemoryCopy(BinaryenModuleRef module,
+                                         BinaryenExpressionRef dest,
+                                         BinaryenExpressionRef source,
+                                         BinaryenExpressionRef size) {
+  return static_cast<Expression*>(Builder(*(Module*)module)
+                                    .makeMemoryCopy((Expression*)dest,
+                                                    (Expression*)source,
+                                                    (Expression*)size));
+}
+
+BinaryenExpressionRef BinaryenMemoryFill(BinaryenModuleRef module,
+                                         BinaryenExpressionRef dest,
+                                         BinaryenExpressionRef value,
+                                         BinaryenExpressionRef size) {
+  return static_cast<Expression*>(Builder(*(Module*)module)
+                                    .makeMemoryFill((Expression*)dest,
+                                                    (Expression*)value,
+                                                    (Expression*)size));
+}
+
+BinaryenExpressionRef BinaryenTupleMake(BinaryenModuleRef module,
+                                        BinaryenExpressionRef* operands,
+                                        BinaryenIndex numOperands) {
+  std::vector<Expression*> ops;
+  ops.resize(numOperands);
+  for (size_t i = 0; i < numOperands; ++i) {
+    ops[i] = (Expression*)operands[i];
+  }
+  return static_cast<Expression*>(Builder(*(Module*)module).makeTupleMake(ops));
+}
+
+BinaryenExpressionRef BinaryenTupleExtract(BinaryenModuleRef module,
+                                           BinaryenExpressionRef tuple,
+                                           BinaryenIndex index) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module).makeTupleExtract((Expression*)tuple, index));
+}
+
+BinaryenExpressionRef BinaryenPop(BinaryenModuleRef module, BinaryenType type) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module).makePop(Type(type)));
+}
+
+BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module,
+                                      BinaryenType type) {
+  Type type_(type);
+  assert(type_.isNullable());
+  return static_cast<Expression*>(Builder(*(Module*)module).makeRefNull(type_));
+}
+
+BinaryenExpressionRef BinaryenRefIsNull(BinaryenModuleRef module,
+                                        BinaryenExpressionRef value) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module).makeRefIsNull((Expression*)value));
+}
+
+BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module,
+                                      const char* func) {
+  return static_cast<Expression*>(Builder(*(Module*)module).makeRefFunc(func));
+}
+
+BinaryenExpressionRef BinaryenRefEq(BinaryenModuleRef module,
+                                    BinaryenExpressionRef left,
+                                    BinaryenExpressionRef right) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module).makeRefEq((Expression*)left, (Expression*)right));
+}
+
+BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module,
+                                  BinaryenExpressionRef body,
+                                  BinaryenExpressionRef catchBody) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module)
+      .makeTry((Expression*)body, (Expression*)catchBody));
+}
+
+BinaryenExpressionRef BinaryenThrow(BinaryenModuleRef module,
+                                    const char* event,
+                                    BinaryenExpressionRef* operands,
+                                    BinaryenIndex numOperands) {
+  std::vector<Expression*> args;
+  for (BinaryenIndex i = 0; i < numOperands; i++) {
+    args.push_back((Expression*)operands[i]);
+  }
+  return static_cast<Expression*>(
+    Builder(*(Module*)module).makeThrow(event, args));
+}
+
+BinaryenExpressionRef BinaryenRethrow(BinaryenModuleRef module,
+                                      BinaryenExpressionRef exnref) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module).makeRethrow((Expression*)exnref));
+}
+
+BinaryenExpressionRef BinaryenBrOnExn(BinaryenModuleRef module,
+                                      const char* name,
+                                      const char* eventName,
+                                      BinaryenExpressionRef exnref) {
+  auto* wasm = (Module*)module;
+  auto* event = wasm->getEventOrNull(eventName);
+  assert(event && "br_on_exn's event must exist");
+  return static_cast<Expression*>(
+    Builder(*wasm).makeBrOnExn(name, event, (Expression*)exnref));
+}
+
+BinaryenExpressionRef BinaryenI31New(BinaryenModuleRef module,
+                                     BinaryenExpressionRef value) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module).makeI31New((Expression*)value));
+}
+
+BinaryenExpressionRef BinaryenI31Get(BinaryenModuleRef module,
+                                     BinaryenExpressionRef i31,
+                                     int signed_) {
+  return static_cast<Expression*>(
+    Builder(*(Module*)module).makeI31Get((Expression*)i31, signed_ != 0));
+}
+
+// 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
+
+// Expression utility
+
+BinaryenExpressionId BinaryenExpressionGetId(BinaryenExpressionRef expr) {
+  return ((Expression*)expr)->_id;
+}
+BinaryenType BinaryenExpressionGetType(BinaryenExpressionRef expr) {
+  return ((Expression*)expr)->type.getID();
+}
+void BinaryenExpressionSetType(BinaryenExpressionRef expr, BinaryenType type) {
+  ((Expression*)expr)->type = Type(type);
+}
+void BinaryenExpressionPrint(BinaryenExpressionRef expr) {
+  WasmPrinter::printExpression((Expression*)expr, std::cout);
+  std::cout << '\n';
+}
+void BinaryenExpressionFinalize(BinaryenExpressionRef expr) {
+  ReFinalizeNode().visit((Expression*)expr);
+}
+
+BinaryenExpressionRef BinaryenExpressionCopy(BinaryenExpressionRef expr,
+                                             BinaryenModuleRef module) {
+  return ExpressionManipulator::copy(expr, *(Module*)module);
+}
+
+// Specific expression utility
+
+// Block
+const char* BinaryenBlockGetName(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Block>());
+  return static_cast<Block*>(expression)->name.c_str();
+}
+void BinaryenBlockSetName(BinaryenExpressionRef expr, const char* name) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Block>());
+  // may be null or empty
+  static_cast<Block*>(expression)->name = name;
+}
+BinaryenIndex BinaryenBlockGetNumChildren(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Block>());
+  return static_cast<Block*>(expression)->list.size();
+}
+BinaryenExpressionRef BinaryenBlockGetChildAt(BinaryenExpressionRef expr,
+                                              BinaryenIndex index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Block>());
+  assert(index < static_cast<Block*>(expression)->list.size());
+  return static_cast<Block*>(expression)->list[index];
+}
+void BinaryenBlockSetChildAt(BinaryenExpressionRef expr,
+                             BinaryenIndex index,
+                             BinaryenExpressionRef childExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Block>());
+  assert(childExpr);
+  auto& list = static_cast<Block*>(expression)->list;
+  assert(index < list.size());
+  list[index] = (Expression*)childExpr;
+}
+BinaryenIndex BinaryenBlockAppendChild(BinaryenExpressionRef expr,
+                                       BinaryenExpressionRef childExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Block>());
+  assert(childExpr);
+  auto& list = static_cast<Block*>(expression)->list;
+  auto index = list.size();
+  list.push_back((Expression*)childExpr);
+  return index;
+}
+void BinaryenBlockInsertChildAt(BinaryenExpressionRef expr,
+                                BinaryenIndex index,
+                                BinaryenExpressionRef childExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Block>());
+  assert(childExpr);
+  static_cast<Block*>(expression)->list.insertAt(index, (Expression*)childExpr);
+}
+BinaryenExpressionRef BinaryenBlockRemoveChildAt(BinaryenExpressionRef expr,
+                                                 BinaryenIndex index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Block>());
+  return static_cast<Block*>(expression)->list.removeAt(index);
+}
+// If
+BinaryenExpressionRef BinaryenIfGetCondition(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<If>());
+  return static_cast<If*>(expression)->condition;
+}
+void BinaryenIfSetCondition(BinaryenExpressionRef expr,
+                            BinaryenExpressionRef condExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<If>());
+  assert(condExpr);
+  static_cast<If*>(expression)->condition = (Expression*)condExpr;
+}
+BinaryenExpressionRef BinaryenIfGetIfTrue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<If>());
+  return static_cast<If*>(expression)->ifTrue;
+}
+void BinaryenIfSetIfTrue(BinaryenExpressionRef expr,
+                         BinaryenExpressionRef ifTrueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<If>());
+  assert(ifTrueExpr);
+  static_cast<If*>(expression)->ifTrue = (Expression*)ifTrueExpr;
+}
+BinaryenExpressionRef BinaryenIfGetIfFalse(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<If>());
+  return static_cast<If*>(expression)->ifFalse;
+}
+void BinaryenIfSetIfFalse(BinaryenExpressionRef expr,
+                          BinaryenExpressionRef ifFalseExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<If>());
+  // may be null
+  static_cast<If*>(expression)->ifFalse = (Expression*)ifFalseExpr;
+}
+// Loop
+const char* BinaryenLoopGetName(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Loop>());
+  return static_cast<Loop*>(expression)->name.c_str();
+}
+void BinaryenLoopSetName(BinaryenExpressionRef expr, const char* name) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Loop>());
+  // may be null or empty
+  static_cast<Loop*>(expression)->name = name;
+}
+BinaryenExpressionRef BinaryenLoopGetBody(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Loop>());
+  return static_cast<Loop*>(expression)->body;
+}
+void BinaryenLoopSetBody(BinaryenExpressionRef expr,
+                         BinaryenExpressionRef bodyExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Loop>());
+  assert(bodyExpr);
+  static_cast<Loop*>(expression)->body = (Expression*)bodyExpr;
+}
+// Break
+const char* BinaryenBreakGetName(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Break>());
+  return static_cast<Break*>(expression)->name.c_str();
+}
+void BinaryenBreakSetName(BinaryenExpressionRef expr, const char* name) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Break>());
+  assert(name);
+  static_cast<Break*>(expression)->name = name;
+}
+BinaryenExpressionRef BinaryenBreakGetCondition(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Break>());
+  return static_cast<Break*>(expression)->condition;
+}
+void BinaryenBreakSetCondition(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef condExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Break>());
+  // may be null (br)
+  static_cast<Break*>(expression)->condition = (Expression*)condExpr;
+}
+BinaryenExpressionRef BinaryenBreakGetValue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Break>());
+  return static_cast<Break*>(expression)->value;
+}
+void BinaryenBreakSetValue(BinaryenExpressionRef expr,
+                           BinaryenExpressionRef valueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Break>());
+  // may be null
+  static_cast<Break*>(expression)->value = (Expression*)valueExpr;
+}
+// Switch
+BinaryenIndex BinaryenSwitchGetNumNames(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Switch>());
+  return static_cast<Switch*>(expression)->targets.size();
+}
+const char* BinaryenSwitchGetNameAt(BinaryenExpressionRef expr,
+                                    BinaryenIndex index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Switch>());
+  assert(index < static_cast<Switch*>(expression)->targets.size());
+  return static_cast<Switch*>(expression)->targets[index].c_str();
+}
+void BinaryenSwitchSetNameAt(BinaryenExpressionRef expr,
+                             BinaryenIndex index,
+                             const char* name) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Switch>());
+  assert(index < static_cast<Switch*>(expression)->targets.size());
+  assert(name);
+  static_cast<Switch*>(expression)->targets[index] = name;
+}
+BinaryenIndex BinaryenSwitchAppendName(BinaryenExpressionRef expr,
+                                       const char* name) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Switch>());
+  assert(name);
+  auto& list = static_cast<Switch*>(expression)->targets;
+  auto index = list.size();
+  list.push_back(name);
+  return index;
+}
+void BinaryenSwitchInsertNameAt(BinaryenExpressionRef expr,
+                                BinaryenIndex index,
+                                const char* name) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Switch>());
+  assert(name);
+  static_cast<Switch*>(expression)->targets.insertAt(index, name);
+}
+const char* BinaryenSwitchRemoveNameAt(BinaryenExpressionRef expr,
+                                       BinaryenIndex index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Switch>());
+  return static_cast<Switch*>(expression)->targets.removeAt(index).c_str();
+}
+const char* BinaryenSwitchGetDefaultName(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Switch>());
+  return static_cast<Switch*>(expression)->default_.c_str();
+}
+void BinaryenSwitchSetDefaultName(BinaryenExpressionRef expr,
+                                  const char* name) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Switch>());
+  // may be null or empty
+  static_cast<Switch*>(expression)->default_ = name;
+}
+BinaryenExpressionRef BinaryenSwitchGetCondition(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Switch>());
+  return static_cast<Switch*>(expression)->condition;
+}
+void BinaryenSwitchSetCondition(BinaryenExpressionRef expr,
+                                BinaryenExpressionRef condExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Switch>());
+  assert(condExpr);
+  static_cast<Switch*>(expression)->condition = (Expression*)condExpr;
+}
+BinaryenExpressionRef BinaryenSwitchGetValue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Switch>());
+  return static_cast<Switch*>(expression)->value;
+}
+void BinaryenSwitchSetValue(BinaryenExpressionRef expr,
+                            BinaryenExpressionRef valueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Switch>());
+  // may be null
+  static_cast<Switch*>(expression)->value = (Expression*)valueExpr;
+}
+// Call
+const char* BinaryenCallGetTarget(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Call>());
+  return static_cast<Call*>(expression)->target.c_str();
+}
+void BinaryenCallSetTarget(BinaryenExpressionRef expr, const char* target) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Call>());
+  assert(target);
+  static_cast<Call*>(expression)->target = target;
+}
+BinaryenIndex BinaryenCallGetNumOperands(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Call>());
+  return static_cast<Call*>(expression)->operands.size();
+}
+BinaryenExpressionRef BinaryenCallGetOperandAt(BinaryenExpressionRef expr,
+                                               BinaryenIndex index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Call>());
+  assert(index < static_cast<Call*>(expression)->operands.size());
+  return static_cast<Call*>(expression)->operands[index];
+}
+void BinaryenCallSetOperandAt(BinaryenExpressionRef expr,
+                              BinaryenIndex index,
+                              BinaryenExpressionRef operandExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Call>());
+  assert(index < static_cast<Call*>(expression)->operands.size());
+  assert(operandExpr);
+  static_cast<Call*>(expression)->operands[index] = (Expression*)operandExpr;
+}
+BinaryenIndex BinaryenCallAppendOperand(BinaryenExpressionRef expr,
+                                        BinaryenExpressionRef operandExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Call>());
+  assert(operandExpr);
+  auto& list = static_cast<Call*>(expression)->operands;
+  auto index = list.size();
+  list.push_back((Expression*)operandExpr);
+  return index;
+}
+void BinaryenCallInsertOperandAt(BinaryenExpressionRef expr,
+                                 BinaryenIndex index,
+                                 BinaryenExpressionRef operandExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Call>());
+  assert(operandExpr);
+  static_cast<Call*>(expression)
+    ->operands.insertAt(index, (Expression*)operandExpr);
+}
+BinaryenExpressionRef BinaryenCallRemoveOperandAt(BinaryenExpressionRef expr,
+                                                  BinaryenIndex index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Call>());
+  return static_cast<Call*>(expression)->operands.removeAt(index);
+}
+int BinaryenCallIsReturn(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Call>());
+  return static_cast<Call*>(expression)->isReturn;
+}
+void BinaryenCallSetReturn(BinaryenExpressionRef expr, int isReturn) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Call>());
+  static_cast<Call*>(expression)->isReturn = isReturn != 0;
+}
+// CallIndirect
+BinaryenExpressionRef
+BinaryenCallIndirectGetTarget(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<CallIndirect>());
+  return static_cast<CallIndirect*>(expression)->target;
+}
+void BinaryenCallIndirectSetTarget(BinaryenExpressionRef expr,
+                                   BinaryenExpressionRef targetExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<CallIndirect>());
+  assert(targetExpr);
+  static_cast<CallIndirect*>(expression)->target = (Expression*)targetExpr;
+}
+BinaryenIndex BinaryenCallIndirectGetNumOperands(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<CallIndirect>());
+  return static_cast<CallIndirect*>(expression)->operands.size();
+}
+BinaryenExpressionRef
+BinaryenCallIndirectGetOperandAt(BinaryenExpressionRef expr,
+                                 BinaryenIndex index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<CallIndirect>());
+  assert(index < static_cast<CallIndirect*>(expression)->operands.size());
+  return static_cast<CallIndirect*>(expression)->operands[index];
+}
+void BinaryenCallIndirectSetOperandAt(BinaryenExpressionRef expr,
+                                      BinaryenIndex index,
+                                      BinaryenExpressionRef operandExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<CallIndirect>());
+  assert(index < static_cast<CallIndirect*>(expression)->operands.size());
+  assert(operandExpr);
+  static_cast<CallIndirect*>(expression)->operands[index] =
+    (Expression*)operandExpr;
+}
+BinaryenIndex
+BinaryenCallIndirectAppendOperand(BinaryenExpressionRef expr,
+                                  BinaryenExpressionRef operandExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<CallIndirect>());
+  assert(operandExpr);
+  auto& list = static_cast<CallIndirect*>(expression)->operands;
+  auto index = list.size();
+  list.push_back((Expression*)operandExpr);
+  return index;
+}
+void BinaryenCallIndirectInsertOperandAt(BinaryenExpressionRef expr,
+                                         BinaryenIndex index,
+                                         BinaryenExpressionRef operandExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<CallIndirect>());
+  assert(operandExpr);
+  static_cast<CallIndirect*>(expression)
+    ->operands.insertAt(index, (Expression*)operandExpr);
+}
+BinaryenExpressionRef
+BinaryenCallIndirectRemoveOperandAt(BinaryenExpressionRef expr,
+                                    BinaryenIndex index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<CallIndirect>());
+  return static_cast<CallIndirect*>(expression)->operands.removeAt(index);
+}
+int BinaryenCallIndirectIsReturn(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<CallIndirect>());
+  return static_cast<CallIndirect*>(expression)->isReturn;
+}
+void BinaryenCallIndirectSetReturn(BinaryenExpressionRef expr, int isReturn) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<CallIndirect>());
+  static_cast<CallIndirect*>(expression)->isReturn = isReturn != 0;
+}
+BinaryenType BinaryenCallIndirectGetParams(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<CallIndirect>());
+  return static_cast<CallIndirect*>(expression)->sig.params.getID();
+}
+void BinaryenCallIndirectSetParams(BinaryenExpressionRef expr,
+                                   BinaryenType params) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<CallIndirect>());
+  static_cast<CallIndirect*>(expression)->sig.params = Type(params);
+}
+BinaryenType BinaryenCallIndirectGetResults(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<CallIndirect>());
+  return static_cast<CallIndirect*>(expression)->sig.results.getID();
+}
+void BinaryenCallIndirectSetResults(BinaryenExpressionRef expr,
+                                    BinaryenType results) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<CallIndirect>());
+  static_cast<CallIndirect*>(expression)->sig.results = Type(results);
+}
+// LocalGet
+BinaryenIndex BinaryenLocalGetGetIndex(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<LocalGet>());
+  return static_cast<LocalGet*>(expression)->index;
+}
+void BinaryenLocalGetSetIndex(BinaryenExpressionRef expr, BinaryenIndex index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<LocalGet>());
+  static_cast<LocalGet*>(expression)->index = index;
+}
+// LocalSet
+int BinaryenLocalSetIsTee(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<LocalSet>());
+  return static_cast<LocalSet*>(expression)->isTee();
+  // has no setter
+}
+BinaryenIndex BinaryenLocalSetGetIndex(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<LocalSet>());
+  return static_cast<LocalSet*>(expression)->index;
+}
+void BinaryenLocalSetSetIndex(BinaryenExpressionRef expr, BinaryenIndex index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<LocalSet>());
+  static_cast<LocalSet*>(expression)->index = index;
+}
+BinaryenExpressionRef BinaryenLocalSetGetValue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<LocalSet>());
+  return static_cast<LocalSet*>(expression)->value;
+}
+void BinaryenLocalSetSetValue(BinaryenExpressionRef expr,
+                              BinaryenExpressionRef valueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<LocalSet>());
+  assert(valueExpr);
+  static_cast<LocalSet*>(expression)->value = (Expression*)valueExpr;
+}
+// GlobalGet
+const char* BinaryenGlobalGetGetName(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<GlobalGet>());
+  return static_cast<GlobalGet*>(expression)->name.c_str();
+}
+void BinaryenGlobalGetSetName(BinaryenExpressionRef expr, const char* name) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<GlobalGet>());
+  assert(name);
+  static_cast<GlobalGet*>(expression)->name = name;
+}
+// GlobalSet
+const char* BinaryenGlobalSetGetName(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<GlobalSet>());
+  return static_cast<GlobalSet*>(expression)->name.c_str();
+}
+void BinaryenGlobalSetSetName(BinaryenExpressionRef expr, const char* name) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<GlobalSet>());
+  assert(name);
+  static_cast<GlobalSet*>(expression)->name = name;
+}
+BinaryenExpressionRef BinaryenGlobalSetGetValue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<GlobalSet>());
+  return static_cast<GlobalSet*>(expression)->value;
+}
+void BinaryenGlobalSetSetValue(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef valueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<GlobalSet>());
+  assert(valueExpr);
+  static_cast<GlobalSet*>(expression)->value = (Expression*)valueExpr;
+}
+// MemoryGrow
+BinaryenExpressionRef BinaryenMemoryGrowGetDelta(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryGrow>());
+  return static_cast<MemoryGrow*>(expression)->delta;
+}
+void BinaryenMemoryGrowSetDelta(BinaryenExpressionRef expr,
+                                BinaryenExpressionRef deltaExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryGrow>());
+  assert(deltaExpr);
+  static_cast<MemoryGrow*>(expression)->delta = (Expression*)deltaExpr;
+}
+// Load
+int BinaryenLoadIsAtomic(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Load>());
+  return static_cast<Load*>(expression)->isAtomic;
+}
+void BinaryenLoadSetAtomic(BinaryenExpressionRef expr, int isAtomic) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Load>());
+  static_cast<Load*>(expression)->isAtomic = isAtomic != 0;
+}
+int BinaryenLoadIsSigned(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Load>());
+  return static_cast<Load*>(expression)->signed_;
+}
+void BinaryenLoadSetSigned(BinaryenExpressionRef expr, int isSigned) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Load>());
+  static_cast<Load*>(expression)->signed_ = isSigned != 0;
+}
+uint32_t BinaryenLoadGetBytes(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Load>());
+  return static_cast<Load*>(expression)->bytes;
+}
+void BinaryenLoadSetBytes(BinaryenExpressionRef expr, uint32_t bytes) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Load>());
+  static_cast<Load*>(expression)->bytes = bytes;
+}
+uint32_t BinaryenLoadGetOffset(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Load>());
+  return static_cast<Load*>(expression)->offset;
+}
+void BinaryenLoadSetOffset(BinaryenExpressionRef expr, uint32_t offset) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Load>());
+  static_cast<Load*>(expression)->offset = offset;
+}
+uint32_t BinaryenLoadGetAlign(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Load>());
+  return static_cast<Load*>(expression)->align;
+}
+void BinaryenLoadSetAlign(BinaryenExpressionRef expr, uint32_t align) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Load>());
+  static_cast<Load*>(expression)->align = align;
+}
+BinaryenExpressionRef BinaryenLoadGetPtr(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Load>());
+  return static_cast<Load*>(expression)->ptr;
+}
+void BinaryenLoadSetPtr(BinaryenExpressionRef expr,
+                        BinaryenExpressionRef ptrExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Load>());
+  assert(ptrExpr);
+  static_cast<Load*>(expression)->ptr = (Expression*)ptrExpr;
+}
+// Store
+int BinaryenStoreIsAtomic(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Store>());
+  return static_cast<Store*>(expression)->isAtomic;
+}
+void BinaryenStoreSetAtomic(BinaryenExpressionRef expr, int isAtomic) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Store>());
+  static_cast<Store*>(expression)->isAtomic = isAtomic != 0;
+}
+uint32_t BinaryenStoreGetBytes(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Store>());
+  return static_cast<Store*>(expression)->bytes;
+}
+void BinaryenStoreSetBytes(BinaryenExpressionRef expr, uint32_t bytes) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Store>());
+  static_cast<Store*>(expression)->bytes = bytes;
+}
+uint32_t BinaryenStoreGetOffset(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Store>());
+  return static_cast<Store*>(expression)->offset;
+}
+void BinaryenStoreSetOffset(BinaryenExpressionRef expr, uint32_t offset) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Store>());
+  static_cast<Store*>(expression)->offset = offset;
+}
+uint32_t BinaryenStoreGetAlign(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Store>());
+  return static_cast<Store*>(expression)->align;
+}
+void BinaryenStoreSetAlign(BinaryenExpressionRef expr, uint32_t align) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Store>());
+  static_cast<Store*>(expression)->align = align;
+}
+BinaryenExpressionRef BinaryenStoreGetPtr(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Store>());
+  return static_cast<Store*>(expression)->ptr;
+}
+void BinaryenStoreSetPtr(BinaryenExpressionRef expr,
+                         BinaryenExpressionRef ptrExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Store>());
+  assert(ptrExpr);
+  static_cast<Store*>(expression)->ptr = (Expression*)ptrExpr;
+}
+BinaryenExpressionRef BinaryenStoreGetValue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Store>());
+  return static_cast<Store*>(expression)->value;
+}
+void BinaryenStoreSetValue(BinaryenExpressionRef expr,
+                           BinaryenExpressionRef valueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Store>());
+  assert(valueExpr);
+  static_cast<Store*>(expression)->value = (Expression*)valueExpr;
+}
+BinaryenType BinaryenStoreGetValueType(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Store>());
+  return static_cast<Store*>(expression)->valueType.getID();
+}
+void BinaryenStoreSetValueType(BinaryenExpressionRef expr,
+                               BinaryenType valueType) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Store>());
+  static_cast<Store*>(expression)->valueType = Type(valueType);
+}
+// Const
+int32_t BinaryenConstGetValueI32(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Const>());
+  return static_cast<Const*>(expression)->value.geti32();
+}
+void BinaryenConstSetValueI32(BinaryenExpressionRef expr, int32_t value) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Const>());
+  static_cast<Const*>(expression)->value = Literal(value);
+}
+int64_t BinaryenConstGetValueI64(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Const>());
+  return static_cast<Const*>(expression)->value.geti64();
+}
+void BinaryenConstSetValueI64(BinaryenExpressionRef expr, int64_t value) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Const>());
+  static_cast<Const*>(expression)->value = Literal(value);
+}
+int32_t BinaryenConstGetValueI64Low(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Const>());
+  return (int32_t)(static_cast<Const*>(expression)->value.geti64() &
+                   0xffffffff);
+}
+void BinaryenConstSetValueI64Low(BinaryenExpressionRef expr, int32_t valueLow) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Const>());
+  auto& value = static_cast<Const*>(expression)->value;
+  int64_t valueI64 = value.type == Type::i64 ? value.geti64() : 0;
+  static_cast<Const*>(expression)->value =
+    Literal((valueI64 & ~0xffffffff) | (int64_t(valueLow) & 0xffffffff));
+}
+int32_t BinaryenConstGetValueI64High(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Const>());
+  return (int32_t)(static_cast<Const*>(expression)->value.geti64() >> 32);
+}
+void BinaryenConstSetValueI64High(BinaryenExpressionRef expr,
+                                  int32_t valueHigh) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Const>());
+  auto& value = static_cast<Const*>(expression)->value;
+  int64_t valueI64 = value.type == Type::i64 ? value.geti64() : 0;
+  static_cast<Const*>(expression)->value =
+    Literal((int64_t(valueHigh) << 32) | (valueI64 & 0xffffffff));
+}
+float BinaryenConstGetValueF32(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Const>());
+  return static_cast<Const*>(expression)->value.getf32();
+}
+void BinaryenConstSetValueF32(BinaryenExpressionRef expr, float value) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Const>());
+  static_cast<Const*>(expression)->value = Literal(value);
+}
+double BinaryenConstGetValueF64(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Const>());
+  return static_cast<Const*>(expression)->value.getf64();
+}
+void BinaryenConstSetValueF64(BinaryenExpressionRef expr, double value) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Const>());
+  static_cast<Const*>(expression)->value = Literal(value);
+}
+void BinaryenConstGetValueV128(BinaryenExpressionRef expr, uint8_t* out) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Const>());
+  memcpy(out, static_cast<Const*>(expression)->value.getv128().data(), 16);
+}
+void BinaryenConstSetValueV128(BinaryenExpressionRef expr,
+                               const uint8_t value[16]) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Const>());
+  assert(value); // nullptr would be wrong
+  static_cast<Const*>(expression)->value = Literal(value);
+}
+// Unary
+BinaryenOp BinaryenUnaryGetOp(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Unary>());
+  return static_cast<Unary*>(expression)->op;
+}
+void BinaryenUnarySetOp(BinaryenExpressionRef expr, BinaryenOp op) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Unary>());
+  static_cast<Unary*>(expression)->op = UnaryOp(op);
+}
+BinaryenExpressionRef BinaryenUnaryGetValue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Unary>());
+  return static_cast<Unary*>(expression)->value;
+}
+void BinaryenUnarySetValue(BinaryenExpressionRef expr,
+                           BinaryenExpressionRef valueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Unary>());
+  assert(valueExpr);
+  static_cast<Unary*>(expression)->value = (Expression*)valueExpr;
+}
+// Binary
+BinaryenOp BinaryenBinaryGetOp(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Binary>());
+  return static_cast<Binary*>(expression)->op;
+}
+void BinaryenBinarySetOp(BinaryenExpressionRef expr, BinaryenOp op) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Binary>());
+  static_cast<Binary*>(expression)->op = BinaryOp(op);
+}
+BinaryenExpressionRef BinaryenBinaryGetLeft(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Binary>());
+  return static_cast<Binary*>(expression)->left;
+}
+void BinaryenBinarySetLeft(BinaryenExpressionRef expr,
+                           BinaryenExpressionRef leftExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Binary>());
+  assert(leftExpr);
+  static_cast<Binary*>(expression)->left = (Expression*)leftExpr;
+}
+BinaryenExpressionRef BinaryenBinaryGetRight(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Binary>());
+  return static_cast<Binary*>(expression)->right;
+}
+void BinaryenBinarySetRight(BinaryenExpressionRef expr,
+                            BinaryenExpressionRef rightExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Binary>());
+  assert(rightExpr);
+  static_cast<Binary*>(expression)->right = (Expression*)rightExpr;
+}
+// Select
+BinaryenExpressionRef BinaryenSelectGetIfTrue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Select>());
+  return static_cast<Select*>(expression)->ifTrue;
+}
+void BinaryenSelectSetIfTrue(BinaryenExpressionRef expr,
+                             BinaryenExpressionRef ifTrueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Select>());
+  assert(ifTrueExpr);
+  static_cast<Select*>(expression)->ifTrue = (Expression*)ifTrueExpr;
+}
+BinaryenExpressionRef BinaryenSelectGetIfFalse(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Select>());
+  return static_cast<Select*>(expression)->ifFalse;
+}
+void BinaryenSelectSetIfFalse(BinaryenExpressionRef expr,
+                              BinaryenExpressionRef ifFalseExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Select>());
+  assert(ifFalseExpr);
+  static_cast<Select*>(expression)->ifFalse = (Expression*)ifFalseExpr;
+}
+BinaryenExpressionRef BinaryenSelectGetCondition(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Select>());
+  return static_cast<Select*>(expression)->condition;
+}
+void BinaryenSelectSetCondition(BinaryenExpressionRef expr,
+                                BinaryenExpressionRef condExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Select>());
+  assert(condExpr);
+  static_cast<Select*>(expression)->condition = (Expression*)condExpr;
+}
+// Drop
+BinaryenExpressionRef BinaryenDropGetValue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Drop>());
+  return static_cast<Drop*>(expression)->value;
+}
+void BinaryenDropSetValue(BinaryenExpressionRef expr,
+                          BinaryenExpressionRef valueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Drop>());
+  assert(valueExpr);
+  static_cast<Drop*>(expression)->value = (Expression*)valueExpr;
+}
+// Return
+BinaryenExpressionRef BinaryenReturnGetValue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Return>());
+  return static_cast<Return*>(expression)->value;
+}
+void BinaryenReturnSetValue(BinaryenExpressionRef expr,
+                            BinaryenExpressionRef valueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Return>());
+  // may be null
+  static_cast<Return*>(expression)->value = (Expression*)valueExpr;
+}
+// AtomicRMW
+BinaryenOp BinaryenAtomicRMWGetOp(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicRMW>());
+  return static_cast<AtomicRMW*>(expression)->op;
+}
+void BinaryenAtomicRMWSetOp(BinaryenExpressionRef expr, BinaryenOp op) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicRMW>());
+  static_cast<AtomicRMW*>(expression)->op = AtomicRMWOp(op);
+}
+uint32_t BinaryenAtomicRMWGetBytes(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicRMW>());
+  return static_cast<AtomicRMW*>(expression)->bytes;
+}
+void BinaryenAtomicRMWSetBytes(BinaryenExpressionRef expr, uint32_t bytes) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicRMW>());
+  static_cast<AtomicRMW*>(expression)->bytes = bytes;
+}
+uint32_t BinaryenAtomicRMWGetOffset(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicRMW>());
+  return static_cast<AtomicRMW*>(expression)->offset;
+}
+void BinaryenAtomicRMWSetOffset(BinaryenExpressionRef expr, uint32_t offset) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicRMW>());
+  static_cast<AtomicRMW*>(expression)->offset = offset;
+}
+BinaryenExpressionRef BinaryenAtomicRMWGetPtr(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicRMW>());
+  return static_cast<AtomicRMW*>(expression)->ptr;
+}
+void BinaryenAtomicRMWSetPtr(BinaryenExpressionRef expr,
+                             BinaryenExpressionRef ptrExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicRMW>());
+  assert(ptrExpr);
+  static_cast<AtomicRMW*>(expression)->ptr = (Expression*)ptrExpr;
+}
+BinaryenExpressionRef BinaryenAtomicRMWGetValue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicRMW>());
+  return static_cast<AtomicRMW*>(expression)->value;
+}
+void BinaryenAtomicRMWSetValue(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef valueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicRMW>());
+  assert(valueExpr);
+  static_cast<AtomicRMW*>(expression)->value = (Expression*)valueExpr;
+}
+// AtomicCmpxchg
+uint32_t BinaryenAtomicCmpxchgGetBytes(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicCmpxchg>());
+  return static_cast<AtomicCmpxchg*>(expression)->bytes;
+}
+void BinaryenAtomicCmpxchgSetBytes(BinaryenExpressionRef expr, uint32_t bytes) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicCmpxchg>());
+  static_cast<AtomicCmpxchg*>(expression)->bytes = bytes;
+}
+uint32_t BinaryenAtomicCmpxchgGetOffset(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicCmpxchg>());
+  return static_cast<AtomicCmpxchg*>(expression)->offset;
+}
+void BinaryenAtomicCmpxchgSetOffset(BinaryenExpressionRef expr,
+                                    uint32_t offset) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicCmpxchg>());
+  static_cast<AtomicCmpxchg*>(expression)->offset = offset;
+}
+BinaryenExpressionRef BinaryenAtomicCmpxchgGetPtr(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicCmpxchg>());
+  return static_cast<AtomicCmpxchg*>(expression)->ptr;
+}
+void BinaryenAtomicCmpxchgSetPtr(BinaryenExpressionRef expr,
+                                 BinaryenExpressionRef ptrExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicCmpxchg>());
+  assert(ptrExpr);
+  static_cast<AtomicCmpxchg*>(expression)->ptr = (Expression*)ptrExpr;
+}
+BinaryenExpressionRef
+BinaryenAtomicCmpxchgGetExpected(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicCmpxchg>());
+  return static_cast<AtomicCmpxchg*>(expression)->expected;
+}
+void BinaryenAtomicCmpxchgSetExpected(BinaryenExpressionRef expr,
+                                      BinaryenExpressionRef expectedExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicCmpxchg>());
+  assert(expectedExpr);
+  static_cast<AtomicCmpxchg*>(expression)->expected = (Expression*)expectedExpr;
+}
+BinaryenExpressionRef
+BinaryenAtomicCmpxchgGetReplacement(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicCmpxchg>());
+  return static_cast<AtomicCmpxchg*>(expression)->replacement;
+}
+void BinaryenAtomicCmpxchgSetReplacement(
+  BinaryenExpressionRef expr, BinaryenExpressionRef replacementExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicCmpxchg>());
+  assert(replacementExpr);
+  static_cast<AtomicCmpxchg*>(expression)->replacement =
+    (Expression*)replacementExpr;
+}
+// AtomicWait
+BinaryenExpressionRef BinaryenAtomicWaitGetPtr(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicWait>());
+  return static_cast<AtomicWait*>(expression)->ptr;
+}
+void BinaryenAtomicWaitSetPtr(BinaryenExpressionRef expr,
+                              BinaryenExpressionRef ptrExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicWait>());
+  assert(ptrExpr);
+  static_cast<AtomicWait*>(expression)->ptr = (Expression*)ptrExpr;
+}
+BinaryenExpressionRef
+BinaryenAtomicWaitGetExpected(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicWait>());
+  return static_cast<AtomicWait*>(expression)->expected;
+}
+void BinaryenAtomicWaitSetExpected(BinaryenExpressionRef expr,
+                                   BinaryenExpressionRef expectedExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicWait>());
+  assert(expectedExpr);
+  static_cast<AtomicWait*>(expression)->expected = (Expression*)expectedExpr;
+}
+BinaryenExpressionRef BinaryenAtomicWaitGetTimeout(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicWait>());
+  return static_cast<AtomicWait*>(expression)->timeout;
+}
+void BinaryenAtomicWaitSetTimeout(BinaryenExpressionRef expr,
+                                  BinaryenExpressionRef timeoutExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicWait>());
+  assert(timeoutExpr);
+  static_cast<AtomicWait*>(expression)->timeout = (Expression*)timeoutExpr;
+}
+BinaryenType BinaryenAtomicWaitGetExpectedType(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicWait>());
+  return static_cast<AtomicWait*>(expression)->expectedType.getID();
+}
+void BinaryenAtomicWaitSetExpectedType(BinaryenExpressionRef expr,
+                                       BinaryenType expectedType) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicWait>());
+  static_cast<AtomicWait*>(expression)->expectedType = Type(expectedType);
+}
+// AtomicNotify
+BinaryenExpressionRef BinaryenAtomicNotifyGetPtr(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicNotify>());
+  return static_cast<AtomicNotify*>(expression)->ptr;
+}
+void BinaryenAtomicNotifySetPtr(BinaryenExpressionRef expr,
+                                BinaryenExpressionRef ptrExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicNotify>());
+  assert(ptrExpr);
+  static_cast<AtomicNotify*>(expression)->ptr = (Expression*)ptrExpr;
+}
+BinaryenExpressionRef
+BinaryenAtomicNotifyGetNotifyCount(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicNotify>());
+  return static_cast<AtomicNotify*>(expression)->notifyCount;
+}
+void BinaryenAtomicNotifySetNotifyCount(BinaryenExpressionRef expr,
+                                        BinaryenExpressionRef notifyCountExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicNotify>());
+  assert(notifyCountExpr);
+  static_cast<AtomicNotify*>(expression)->notifyCount =
+    (Expression*)notifyCountExpr;
+}
+// AtomicFence
+uint8_t BinaryenAtomicFenceGetOrder(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicFence>());
+  return static_cast<AtomicFence*>(expression)->order;
+}
+void BinaryenAtomicFenceSetOrder(BinaryenExpressionRef expr, uint8_t order) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<AtomicFence>());
+  static_cast<AtomicFence*>(expression)->order = order;
+}
+// SIMDExtract
+BinaryenOp BinaryenSIMDExtractGetOp(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDExtract>());
+  return static_cast<SIMDExtract*>(expression)->op;
+}
+void BinaryenSIMDExtractSetOp(BinaryenExpressionRef expr, BinaryenOp op) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDExtract>());
+  static_cast<SIMDExtract*>(expression)->op = SIMDExtractOp(op);
+}
+BinaryenExpressionRef BinaryenSIMDExtractGetVec(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDExtract>());
+  return static_cast<SIMDExtract*>(expression)->vec;
+}
+void BinaryenSIMDExtractSetVec(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef vecExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDExtract>());
+  assert(vecExpr);
+  static_cast<SIMDExtract*>(expression)->vec = (Expression*)vecExpr;
+}
+uint8_t BinaryenSIMDExtractGetIndex(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDExtract>());
+  return static_cast<SIMDExtract*>(expression)->index;
+}
+void BinaryenSIMDExtractSetIndex(BinaryenExpressionRef expr, uint8_t index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDExtract>());
+  static_cast<SIMDExtract*>(expression)->index = index;
+}
+// SIMDReplace
+BinaryenOp BinaryenSIMDReplaceGetOp(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDReplace>());
+  return static_cast<SIMDReplace*>(expression)->op;
+}
+void BinaryenSIMDReplaceSetOp(BinaryenExpressionRef expr, BinaryenOp op) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDReplace>());
+  static_cast<SIMDReplace*>(expression)->op = SIMDReplaceOp(op);
+}
+BinaryenExpressionRef BinaryenSIMDReplaceGetVec(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDReplace>());
+  return static_cast<SIMDReplace*>(expression)->vec;
+}
+void BinaryenSIMDReplaceSetVec(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef vecExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDReplace>());
+  assert(vecExpr);
+  static_cast<SIMDReplace*>(expression)->vec = (Expression*)vecExpr;
+}
+uint8_t BinaryenSIMDReplaceGetIndex(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDReplace>());
+  return static_cast<SIMDReplace*>(expression)->index;
+}
+void BinaryenSIMDReplaceSetIndex(BinaryenExpressionRef expr, uint8_t index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDReplace>());
+  static_cast<SIMDReplace*>(expression)->index = index;
+}
+BinaryenExpressionRef BinaryenSIMDReplaceGetValue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDReplace>());
+  return static_cast<SIMDReplace*>(expression)->value;
+}
+void BinaryenSIMDReplaceSetValue(BinaryenExpressionRef expr,
+                                 BinaryenExpressionRef valueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDReplace>());
+  assert(valueExpr);
+  static_cast<SIMDReplace*>(expression)->value = (Expression*)valueExpr;
+}
+// SIMDShuffle
+BinaryenExpressionRef BinaryenSIMDShuffleGetLeft(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDShuffle>());
+  return static_cast<SIMDShuffle*>(expression)->left;
+}
+void BinaryenSIMDShuffleSetLeft(BinaryenExpressionRef expr,
+                                BinaryenExpressionRef leftExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDShuffle>());
+  assert(leftExpr);
+  static_cast<SIMDShuffle*>(expression)->left = (Expression*)leftExpr;
+}
+BinaryenExpressionRef BinaryenSIMDShuffleGetRight(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDShuffle>());
+  return static_cast<SIMDShuffle*>(expression)->right;
+}
+void BinaryenSIMDShuffleSetRight(BinaryenExpressionRef expr,
+                                 BinaryenExpressionRef rightExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDShuffle>());
+  assert(rightExpr);
+  static_cast<SIMDShuffle*>(expression)->right = (Expression*)rightExpr;
+}
+void BinaryenSIMDShuffleGetMask(BinaryenExpressionRef expr, uint8_t* mask) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDShuffle>());
+  assert(mask); // nullptr would be wrong
+  memcpy(mask, static_cast<SIMDShuffle*>(expression)->mask.data(), 16);
+}
+void BinaryenSIMDShuffleSetMask(BinaryenExpressionRef expr,
+                                const uint8_t mask_[16]) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDShuffle>());
+  assert(mask_); // nullptr would be wrong
+  auto& mask = static_cast<SIMDShuffle*>(expression)->mask;
+  memcpy(mask.data(), mask_, 16);
+}
+// SIMDTernary
+BinaryenOp BinaryenSIMDTernaryGetOp(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDTernary>());
+  return static_cast<SIMDTernary*>(expression)->op;
+}
+void BinaryenSIMDTernarySetOp(BinaryenExpressionRef expr, BinaryenOp op) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDTernary>());
+  static_cast<SIMDTernary*>(expression)->op = SIMDTernaryOp(op);
+}
+BinaryenExpressionRef BinaryenSIMDTernaryGetA(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDTernary>());
+  return static_cast<SIMDTernary*>(expression)->a;
+}
+void BinaryenSIMDTernarySetA(BinaryenExpressionRef expr,
+                             BinaryenExpressionRef aExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDTernary>());
+  assert(aExpr);
+  static_cast<SIMDTernary*>(expression)->a = (Expression*)aExpr;
+}
+BinaryenExpressionRef BinaryenSIMDTernaryGetB(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDTernary>());
+  return static_cast<SIMDTernary*>(expression)->b;
+}
+void BinaryenSIMDTernarySetB(BinaryenExpressionRef expr,
+                             BinaryenExpressionRef bExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDTernary>());
+  assert(bExpr);
+  static_cast<SIMDTernary*>(expression)->b = (Expression*)bExpr;
+}
+BinaryenExpressionRef BinaryenSIMDTernaryGetC(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDTernary>());
+  return static_cast<SIMDTernary*>(expression)->c;
+}
+void BinaryenSIMDTernarySetC(BinaryenExpressionRef expr,
+                             BinaryenExpressionRef cExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDTernary>());
+  assert(cExpr);
+  static_cast<SIMDTernary*>(expression)->c = (Expression*)cExpr;
+}
+// SIMDShift
+BinaryenOp BinaryenSIMDShiftGetOp(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDShift>());
+  return static_cast<SIMDShift*>(expression)->op;
+}
+void BinaryenSIMDShiftSetOp(BinaryenExpressionRef expr, BinaryenOp op) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDShift>());
+  static_cast<SIMDShift*>(expression)->op = SIMDShiftOp(op);
+}
+BinaryenExpressionRef BinaryenSIMDShiftGetVec(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDShift>());
+  return static_cast<SIMDShift*>(expression)->vec;
+}
+void BinaryenSIMDShiftSetVec(BinaryenExpressionRef expr,
+                             BinaryenExpressionRef vecExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDShift>());
+  assert(vecExpr);
+  static_cast<SIMDShift*>(expression)->vec = (Expression*)vecExpr;
+}
+BinaryenExpressionRef BinaryenSIMDShiftGetShift(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDShift>());
+  return static_cast<SIMDShift*>(expression)->shift;
+}
+void BinaryenSIMDShiftSetShift(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef shiftExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDShift>());
+  assert(shiftExpr);
+  static_cast<SIMDShift*>(expression)->shift = (Expression*)shiftExpr;
+}
+// SIMDLoad
+BinaryenOp BinaryenSIMDLoadGetOp(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDLoad>());
+  return static_cast<SIMDLoad*>(expression)->op;
+}
+void BinaryenSIMDLoadSetOp(BinaryenExpressionRef expr, BinaryenOp op) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDLoad>());
+  static_cast<SIMDLoad*>(expression)->op = SIMDLoadOp(op);
+}
+uint32_t BinaryenSIMDLoadGetOffset(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDLoad>());
+  return static_cast<SIMDLoad*>(expression)->offset;
+}
+void BinaryenSIMDLoadSetOffset(BinaryenExpressionRef expr, uint32_t offset) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDLoad>());
+  static_cast<SIMDLoad*>(expression)->offset = offset;
+}
+uint32_t BinaryenSIMDLoadGetAlign(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDLoad>());
+  return static_cast<SIMDLoad*>(expression)->align;
+}
+void BinaryenSIMDLoadSetAlign(BinaryenExpressionRef expr, uint32_t align) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDLoad>());
+  static_cast<SIMDLoad*>(expression)->align = align;
+}
+BinaryenExpressionRef BinaryenSIMDLoadGetPtr(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDLoad>());
+  return static_cast<SIMDLoad*>(expression)->ptr;
+}
+void BinaryenSIMDLoadSetPtr(BinaryenExpressionRef expr,
+                            BinaryenExpressionRef ptrExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<SIMDLoad>());
+  assert(ptrExpr);
+  static_cast<SIMDLoad*>(expression)->ptr = (Expression*)ptrExpr;
+}
+// MemoryInit
+uint32_t BinaryenMemoryInitGetSegment(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryInit>());
+  return static_cast<MemoryInit*>(expression)->segment;
+}
+void BinaryenMemoryInitSetSegment(BinaryenExpressionRef expr,
+                                  uint32_t segment) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryInit>());
+  static_cast<MemoryInit*>(expression)->segment = segment;
+}
+BinaryenExpressionRef BinaryenMemoryInitGetDest(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryInit>());
+  return static_cast<MemoryInit*>(expression)->dest;
+}
+void BinaryenMemoryInitSetDest(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef destExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryInit>());
+  assert(destExpr);
+  static_cast<MemoryInit*>(expression)->dest = (Expression*)destExpr;
+}
+BinaryenExpressionRef BinaryenMemoryInitGetOffset(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryInit>());
+  return static_cast<MemoryInit*>(expression)->offset;
+}
+void BinaryenMemoryInitSetOffset(BinaryenExpressionRef expr,
+                                 BinaryenExpressionRef offsetExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryInit>());
+  assert(offsetExpr);
+  static_cast<MemoryInit*>(expression)->offset = (Expression*)offsetExpr;
+}
+BinaryenExpressionRef BinaryenMemoryInitGetSize(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryInit>());
+  return static_cast<MemoryInit*>(expression)->size;
+}
+void BinaryenMemoryInitSetSize(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef sizeExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryInit>());
+  assert(sizeExpr);
+  static_cast<MemoryInit*>(expression)->size = (Expression*)sizeExpr;
+}
+// DataDrop
+uint32_t BinaryenDataDropGetSegment(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<DataDrop>());
+  return static_cast<DataDrop*>(expression)->segment;
+}
+void BinaryenDataDropSetSegment(BinaryenExpressionRef expr, uint32_t segment) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<DataDrop>());
+  static_cast<DataDrop*>(expression)->segment = segment;
+}
+// MemoryCopy
+BinaryenExpressionRef BinaryenMemoryCopyGetDest(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryCopy>());
+  return static_cast<MemoryCopy*>(expression)->dest;
+}
+void BinaryenMemoryCopySetDest(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef destExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryCopy>());
+  assert(destExpr);
+  static_cast<MemoryCopy*>(expression)->dest = (Expression*)destExpr;
+}
+BinaryenExpressionRef BinaryenMemoryCopyGetSource(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryCopy>());
+  return static_cast<MemoryCopy*>(expression)->source;
+}
+void BinaryenMemoryCopySetSource(BinaryenExpressionRef expr,
+                                 BinaryenExpressionRef sourceExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryCopy>());
+  assert(sourceExpr);
+  static_cast<MemoryCopy*>(expression)->source = (Expression*)sourceExpr;
+}
+BinaryenExpressionRef BinaryenMemoryCopyGetSize(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryCopy>());
+  return static_cast<MemoryCopy*>(expression)->size;
+}
+void BinaryenMemoryCopySetSize(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef sizeExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryCopy>());
+  assert(sizeExpr);
+  static_cast<MemoryCopy*>(expression)->size = (Expression*)sizeExpr;
+}
+// MemoryFill
+BinaryenExpressionRef BinaryenMemoryFillGetDest(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryFill>());
+  return static_cast<MemoryFill*>(expression)->dest;
+}
+void BinaryenMemoryFillSetDest(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef destExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryFill>());
+  assert(destExpr);
+  static_cast<MemoryFill*>(expression)->dest = (Expression*)destExpr;
+}
+BinaryenExpressionRef BinaryenMemoryFillGetValue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryFill>());
+  return static_cast<MemoryFill*>(expression)->value;
+}
+void BinaryenMemoryFillSetValue(BinaryenExpressionRef expr,
+                                BinaryenExpressionRef valueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryFill>());
+  assert(valueExpr);
+  static_cast<MemoryFill*>(expression)->value = (Expression*)valueExpr;
+}
+BinaryenExpressionRef BinaryenMemoryFillGetSize(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryFill>());
+  return static_cast<MemoryFill*>(expression)->size;
+}
+void BinaryenMemoryFillSetSize(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef sizeExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<MemoryFill>());
+  assert(sizeExpr);
+  static_cast<MemoryFill*>(expression)->size = (Expression*)sizeExpr;
+}
+// RefIsNull
+BinaryenExpressionRef BinaryenRefIsNullGetValue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<RefIsNull>());
+  return static_cast<RefIsNull*>(expression)->value;
+}
+void BinaryenRefIsNullSetValue(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef valueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<RefIsNull>());
+  assert(valueExpr);
+  static_cast<RefIsNull*>(expression)->value = (Expression*)valueExpr;
+}
+// RefFunc
+const char* BinaryenRefFuncGetFunc(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<RefFunc>());
+  return static_cast<RefFunc*>(expression)->func.c_str();
+}
+void BinaryenRefFuncSetFunc(BinaryenExpressionRef expr, const char* funcName) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<RefFunc>());
+  static_cast<RefFunc*>(expression)->func = funcName;
+}
+// RefEq
+BinaryenExpressionRef BinaryenRefEqGetLeft(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<RefEq>());
+  return static_cast<RefEq*>(expression)->left;
+}
+void BinaryenRefEqSetLeft(BinaryenExpressionRef expr,
+                          BinaryenExpressionRef left) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<RefEq>());
+  static_cast<RefEq*>(expression)->left = (Expression*)left;
+}
+BinaryenExpressionRef BinaryenRefEqGetRight(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<RefEq>());
+  return static_cast<RefEq*>(expression)->right;
+}
+void BinaryenRefEqSetRight(BinaryenExpressionRef expr,
+                           BinaryenExpressionRef right) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<RefEq>());
+  static_cast<RefEq*>(expression)->right = (Expression*)right;
+}
+// Try
+BinaryenExpressionRef BinaryenTryGetBody(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Try>());
+  return static_cast<Try*>(expression)->body;
+}
+void BinaryenTrySetBody(BinaryenExpressionRef expr,
+                        BinaryenExpressionRef bodyExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Try>());
+  assert(bodyExpr);
+  static_cast<Try*>(expression)->body = (Expression*)bodyExpr;
+}
+BinaryenExpressionRef BinaryenTryGetCatchBody(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Try>());
+  return static_cast<Try*>(expression)->catchBody;
+}
+void BinaryenTrySetCatchBody(BinaryenExpressionRef expr,
+                             BinaryenExpressionRef catchBodyExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Try>());
+  assert(catchBodyExpr);
+  static_cast<Try*>(expression)->catchBody = (Expression*)catchBodyExpr;
+}
+// Throw
+const char* BinaryenThrowGetEvent(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Throw>());
+  return static_cast<Throw*>(expression)->event.c_str();
+}
+void BinaryenThrowSetEvent(BinaryenExpressionRef expr, const char* eventName) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Throw>());
+  static_cast<Throw*>(expression)->event = eventName;
+}
+BinaryenIndex BinaryenThrowGetNumOperands(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Throw>());
+  return static_cast<Throw*>(expression)->operands.size();
+}
+BinaryenExpressionRef BinaryenThrowGetOperandAt(BinaryenExpressionRef expr,
+                                                BinaryenIndex index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Throw>());
+  assert(index < static_cast<Throw*>(expression)->operands.size());
+  return static_cast<Throw*>(expression)->operands[index];
+}
+void BinaryenThrowSetOperandAt(BinaryenExpressionRef expr,
+                               BinaryenIndex index,
+                               BinaryenExpressionRef operandExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Throw>());
+  assert(index < static_cast<Throw*>(expression)->operands.size());
+  assert(operandExpr);
+  static_cast<Throw*>(expression)->operands[index] = (Expression*)operandExpr;
+}
+BinaryenIndex BinaryenThrowAppendOperand(BinaryenExpressionRef expr,
+                                         BinaryenExpressionRef operandExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Throw>());
+  assert(operandExpr);
+  auto& list = static_cast<Throw*>(expression)->operands;
+  auto index = list.size();
+  list.push_back((Expression*)operandExpr);
+  return index;
+}
+void BinaryenThrowInsertOperandAt(BinaryenExpressionRef expr,
+                                  BinaryenIndex index,
+                                  BinaryenExpressionRef operandExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Throw>());
+  assert(operandExpr);
+  static_cast<Throw*>(expression)
+    ->operands.insertAt(index, (Expression*)operandExpr);
+}
+BinaryenExpressionRef BinaryenThrowRemoveOperandAt(BinaryenExpressionRef expr,
+                                                   BinaryenIndex index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Throw>());
+  return static_cast<Throw*>(expression)->operands.removeAt(index);
+}
+// Rethrow
+BinaryenExpressionRef BinaryenRethrowGetExnref(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Rethrow>());
+  return static_cast<Rethrow*>(expression)->exnref;
+}
+void BinaryenRethrowSetExnref(BinaryenExpressionRef expr,
+                              BinaryenExpressionRef exnrefExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<Rethrow>());
+  assert(exnrefExpr);
+  static_cast<Rethrow*>(expression)->exnref = (Expression*)exnrefExpr;
+}
+// BrOnExn
+const char* BinaryenBrOnExnGetEvent(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<BrOnExn>());
+  return static_cast<BrOnExn*>(expression)->event.c_str();
+}
+void BinaryenBrOnExnSetEvent(BinaryenExpressionRef expr,
+                             const char* eventName) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<BrOnExn>());
+  static_cast<BrOnExn*>(expression)->event = eventName;
+}
+const char* BinaryenBrOnExnGetName(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<BrOnExn>());
+  return static_cast<BrOnExn*>(expression)->name.c_str();
+}
+void BinaryenBrOnExnSetName(BinaryenExpressionRef expr, const char* name) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<BrOnExn>());
+  static_cast<BrOnExn*>(expression)->name = name;
+}
+BinaryenExpressionRef BinaryenBrOnExnGetExnref(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<BrOnExn>());
+  return static_cast<BrOnExn*>(expression)->exnref;
+}
+void BinaryenBrOnExnSetExnref(BinaryenExpressionRef expr,
+                              BinaryenExpressionRef exnrefExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<BrOnExn>());
+  assert(exnrefExpr);
+  static_cast<BrOnExn*>(expression)->exnref = (Expression*)exnrefExpr;
+}
+// TupleMake
+BinaryenIndex BinaryenTupleMakeGetNumOperands(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<TupleMake>());
+  return static_cast<TupleMake*>(expression)->operands.size();
+}
+BinaryenExpressionRef BinaryenTupleMakeGetOperandAt(BinaryenExpressionRef expr,
+                                                    BinaryenIndex index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<TupleMake>());
+  return static_cast<TupleMake*>(expression)->operands[index];
+}
+void BinaryenTupleMakeSetOperandAt(BinaryenExpressionRef expr,
+                                   BinaryenIndex index,
+                                   BinaryenExpressionRef operandExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<TupleMake>());
+  assert(index < static_cast<TupleMake*>(expression)->operands.size());
+  assert(operandExpr);
+  static_cast<TupleMake*>(expression)->operands[index] =
+    (Expression*)operandExpr;
+}
+BinaryenIndex
+BinaryenTupleMakeAppendOperand(BinaryenExpressionRef expr,
+                               BinaryenExpressionRef operandExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<TupleMake>());
+  assert(operandExpr);
+  auto& list = static_cast<TupleMake*>(expression)->operands;
+  auto index = list.size();
+  list.push_back((Expression*)operandExpr);
+  return index;
+}
+void BinaryenTupleMakeInsertOperandAt(BinaryenExpressionRef expr,
+                                      BinaryenIndex index,
+                                      BinaryenExpressionRef operandExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<TupleMake>());
+  assert(operandExpr);
+  static_cast<TupleMake*>(expression)
+    ->operands.insertAt(index, (Expression*)operandExpr);
+}
+BinaryenExpressionRef
+BinaryenTupleMakeRemoveOperandAt(BinaryenExpressionRef expr,
+                                 BinaryenIndex index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<TupleMake>());
+  return static_cast<TupleMake*>(expression)->operands.removeAt(index);
+}
+// TupleExtract
+BinaryenExpressionRef BinaryenTupleExtractGetTuple(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<TupleExtract>());
+  return static_cast<TupleExtract*>(expression)->tuple;
+}
+void BinaryenTupleExtractSetTuple(BinaryenExpressionRef expr,
+                                  BinaryenExpressionRef tupleExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<TupleExtract>());
+  assert(tupleExpr);
+  static_cast<TupleExtract*>(expression)->tuple = (Expression*)tupleExpr;
+}
+BinaryenIndex BinaryenTupleExtractGetIndex(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<TupleExtract>());
+  return static_cast<TupleExtract*>(expression)->index;
+}
+void BinaryenTupleExtractSetIndex(BinaryenExpressionRef expr,
+                                  BinaryenIndex index) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<TupleExtract>());
+  static_cast<TupleExtract*>(expression)->index = index;
+}
+// I31New
+BinaryenExpressionRef BinaryenI31NewGetValue(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<I31New>());
+  return static_cast<I31New*>(expression)->value;
+}
+void BinaryenI31NewSetValue(BinaryenExpressionRef expr,
+                            BinaryenExpressionRef valueExpr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<I31New>());
+  assert(valueExpr);
+  static_cast<I31New*>(expression)->value = (Expression*)valueExpr;
+}
+// I31Get
+BinaryenExpressionRef BinaryenI31GetGetI31(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<I31Get>());
+  return static_cast<I31Get*>(expression)->i31;
+}
+void BinaryenI31GetSetI31(BinaryenExpressionRef expr,
+                          BinaryenExpressionRef i31Expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<I31Get>());
+  assert(i31Expr);
+  static_cast<I31Get*>(expression)->i31 = (Expression*)i31Expr;
+}
+int BinaryenI31GetIsSigned(BinaryenExpressionRef expr) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<I31Get>());
+  return static_cast<I31Get*>(expression)->signed_;
+}
+void BinaryenI31GetSetSigned(BinaryenExpressionRef expr, int signed_) {
+  auto* expression = (Expression*)expr;
+  assert(expression->is<I31Get>());
+  static_cast<I31Get*>(expression)->signed_ = signed_ != 0;
+}
+
+// Functions
+
+BinaryenFunctionRef BinaryenAddFunction(BinaryenModuleRef module,
+                                        const char* name,
+                                        BinaryenType params,
+                                        BinaryenType results,
+                                        BinaryenType* varTypes,
+                                        BinaryenIndex numVarTypes,
+                                        BinaryenExpressionRef body) {
+  auto* ret = new Function;
+  ret->name = name;
+  ret->sig = Signature(Type(params), Type(results));
+  for (BinaryenIndex i = 0; i < numVarTypes; i++) {
+    ret->vars.push_back(Type(varTypes[i]));
+  }
+  ret->body = (Expression*)body;
+
+  // Lock. This can be called from multiple threads at once, and is a
+  // point where they all access and modify the module.
+  {
+    std::lock_guard<std::mutex> lock(BinaryenFunctionMutex);
+    ((Module*)module)->addFunction(ret);
+  }
+
+  return ret;
+}
+BinaryenFunctionRef BinaryenGetFunction(BinaryenModuleRef module,
+                                        const char* name) {
+  return ((Module*)module)->getFunction(name);
+}
+void BinaryenRemoveFunction(BinaryenModuleRef module, const char* name) {
+  ((Module*)module)->removeFunction(name);
+}
+uint32_t BinaryenGetNumFunctions(BinaryenModuleRef module) {
+  return ((Module*)module)->functions.size();
+}
+BinaryenFunctionRef BinaryenGetFunctionByIndex(BinaryenModuleRef module,
+                                               BinaryenIndex id) {
+  const auto& functions = ((Module*)module)->functions;
+  if (functions.size() <= id) {
+    Fatal() << "invalid function id.";
+  }
+  return functions[id].get();
+}
+
+// Globals
+
+BinaryenGlobalRef BinaryenAddGlobal(BinaryenModuleRef module,
+                                    const char* name,
+                                    BinaryenType type,
+                                    int8_t mutable_,
+                                    BinaryenExpressionRef init) {
+  auto* ret = new Global();
+  ret->name = name;
+  ret->type = Type(type);
+  ret->mutable_ = !!mutable_;
+  ret->init = (Expression*)init;
+  ((Module*)module)->addGlobal(ret);
+  return ret;
+}
+BinaryenGlobalRef BinaryenGetGlobal(BinaryenModuleRef module,
+                                    const char* name) {
+  return ((Module*)module)->getGlobal(name);
+}
+void BinaryenRemoveGlobal(BinaryenModuleRef module, const char* name) {
+  ((Module*)module)->removeGlobal(name);
+}
+
+// Events
+
+BinaryenEventRef BinaryenAddEvent(BinaryenModuleRef module,
+                                  const char* name,
+                                  uint32_t attribute,
+                                  BinaryenType params,
+                                  BinaryenType results) {
+  auto* ret = new Event();
+  ret->name = name;
+  ret->attribute = attribute;
+  ret->sig = Signature(Type(params), Type(results));
+  ((Module*)module)->addEvent(ret);
+  return ret;
+}
+
+BinaryenEventRef BinaryenGetEvent(BinaryenModuleRef module, const char* name) {
+  return ((Module*)module)->getEvent(name);
+}
+void BinaryenRemoveEvent(BinaryenModuleRef module, const char* name) {
+  ((Module*)module)->removeEvent(name);
+}
+
+// Imports
+
+void BinaryenAddFunctionImport(BinaryenModuleRef module,
+                               const char* internalName,
+                               const char* externalModuleName,
+                               const char* externalBaseName,
+                               BinaryenType params,
+                               BinaryenType results) {
+  auto* ret = new Function();
+  ret->name = internalName;
+  ret->module = externalModuleName;
+  ret->base = externalBaseName;
+  ret->sig = Signature(Type(params), Type(results));
+  ((Module*)module)->addFunction(ret);
+}
+void BinaryenAddTableImport(BinaryenModuleRef module,
+                            const char* internalName,
+                            const char* externalModuleName,
+                            const char* externalBaseName) {
+  auto& table = ((Module*)module)->table;
+  table.module = externalModuleName;
+  table.base = externalBaseName;
+}
+void BinaryenAddMemoryImport(BinaryenModuleRef module,
+                             const char* internalName,
+                             const char* externalModuleName,
+                             const char* externalBaseName,
+                             uint8_t shared) {
+  auto& memory = ((Module*)module)->memory;
+  memory.module = externalModuleName;
+  memory.base = externalBaseName;
+  memory.shared = shared;
+}
+void BinaryenAddGlobalImport(BinaryenModuleRef module,
+                             const char* internalName,
+                             const char* externalModuleName,
+                             const char* externalBaseName,
+                             BinaryenType globalType,
+                             int mutable_) {
+  auto* ret = new Global();
+  ret->name = internalName;
+  ret->module = externalModuleName;
+  ret->base = externalBaseName;
+  ret->type = Type(globalType);
+  ret->mutable_ = mutable_ != 0;
+  ((Module*)module)->addGlobal(ret);
+}
+void BinaryenAddEventImport(BinaryenModuleRef module,
+                            const char* internalName,
+                            const char* externalModuleName,
+                            const char* externalBaseName,
+                            uint32_t attribute,
+                            BinaryenType params,
+                            BinaryenType results) {
+  auto* ret = new Event();
+  ret->name = internalName;
+  ret->module = externalModuleName;
+  ret->base = externalBaseName;
+  ret->sig = Signature(Type(params), Type(results));
+  ((Module*)module)->addEvent(ret);
+}
+
+// Exports
+
+WASM_DEPRECATED BinaryenExportRef BinaryenAddExport(BinaryenModuleRef module,
+                                                    const char* internalName,
+                                                    const char* externalName) {
+  return BinaryenAddFunctionExport(module, internalName, externalName);
+}
+BinaryenExportRef BinaryenAddFunctionExport(BinaryenModuleRef module,
+                                            const char* internalName,
+                                            const char* externalName) {
+  auto* ret = new Export();
+  ret->value = internalName;
+  ret->name = externalName;
+  ret->kind = ExternalKind::Function;
+  ((Module*)module)->addExport(ret);
+  return ret;
+}
+BinaryenExportRef BinaryenAddTableExport(BinaryenModuleRef module,
+                                         const char* internalName,
+                                         const char* externalName) {
+  auto* ret = new Export();
+  ret->value = internalName;
+  ret->name = externalName;
+  ret->kind = ExternalKind::Table;
+  ((Module*)module)->addExport(ret);
+  return ret;
+}
+BinaryenExportRef BinaryenAddMemoryExport(BinaryenModuleRef module,
+                                          const char* internalName,
+                                          const char* externalName) {
+  auto* ret = new Export();
+  ret->value = internalName;
+  ret->name = externalName;
+  ret->kind = ExternalKind::Memory;
+  ((Module*)module)->addExport(ret);
+  return ret;
+}
+BinaryenExportRef BinaryenAddGlobalExport(BinaryenModuleRef module,
+                                          const char* internalName,
+                                          const char* externalName) {
+  auto* ret = new Export();
+  ret->value = internalName;
+  ret->name = externalName;
+  ret->kind = ExternalKind::Global;
+  ((Module*)module)->addExport(ret);
+  return ret;
+}
+BinaryenExportRef BinaryenAddEventExport(BinaryenModuleRef module,
+                                         const char* internalName,
+                                         const char* externalName) {
+  auto* ret = new Export();
+  ret->value = internalName;
+  ret->name = externalName;
+  ret->kind = ExternalKind::Event;
+  ((Module*)module)->addExport(ret);
+  return ret;
+}
+void BinaryenRemoveExport(BinaryenModuleRef module, const char* externalName) {
+  ((Module*)module)->removeExport(externalName);
+}
+
+// Function table. One per module
+
+void BinaryenSetFunctionTable(BinaryenModuleRef module,
+                              BinaryenIndex initial,
+                              BinaryenIndex maximum,
+                              const char** funcNames,
+                              BinaryenIndex numFuncNames,
+                              BinaryenExpressionRef offset) {
+  Table::Segment segment((Expression*)offset);
+  for (BinaryenIndex i = 0; i < numFuncNames; i++) {
+    segment.data.push_back(funcNames[i]);
+  }
+  auto& table = ((Module*)module)->table;
+  table.initial = initial;
+  table.max = maximum;
+  table.exists = true;
+  table.segments.push_back(segment);
+}
+
+int BinaryenIsFunctionTableImported(BinaryenModuleRef module) {
+  return ((Module*)module)->table.imported();
+}
+BinaryenIndex BinaryenGetNumFunctionTableSegments(BinaryenModuleRef module) {
+  return ((Module*)module)->table.segments.size();
+}
+BinaryenExpressionRef
+BinaryenGetFunctionTableSegmentOffset(BinaryenModuleRef module,
+                                      BinaryenIndex segmentId) {
+  const auto& segments = ((Module*)module)->table.segments;
+  if (segments.size() <= segmentId) {
+    Fatal() << "invalid function table segment id.";
+  }
+  return segments[segmentId].offset;
+}
+BinaryenIndex BinaryenGetFunctionTableSegmentLength(BinaryenModuleRef module,
+                                                    BinaryenIndex segmentId) {
+  const auto& segments = ((Module*)module)->table.segments;
+  if (segments.size() <= segmentId) {
+    Fatal() << "invalid function table segment id.";
+  }
+  return segments[segmentId].data.size();
+}
+const char* BinaryenGetFunctionTableSegmentData(BinaryenModuleRef module,
+                                                BinaryenIndex segmentId,
+                                                BinaryenIndex dataId) {
+  const auto& segments = ((Module*)module)->table.segments;
+  if (segments.size() <= segmentId ||
+      segments[segmentId].data.size() <= dataId) {
+    Fatal() << "invalid function table segment or data id.";
+  }
+  return segments[segmentId].data[dataId].c_str();
+}
+
+// Memory. One per module
+
+void BinaryenSetMemory(BinaryenModuleRef module,
+                       BinaryenIndex initial,
+                       BinaryenIndex maximum,
+                       const char* exportName,
+                       const char** segments,
+                       int8_t* segmentPassive,
+                       BinaryenExpressionRef* segmentOffsets,
+                       BinaryenIndex* segmentSizes,
+                       BinaryenIndex numSegments,
+                       uint8_t shared) {
+  auto* wasm = (Module*)module;
+  wasm->memory.initial = initial;
+  wasm->memory.max = int32_t(maximum); // Make sure -1 extends.
+  wasm->memory.exists = true;
+  wasm->memory.shared = shared;
+  if (exportName) {
+    auto memoryExport = make_unique<Export>();
+    memoryExport->name = exportName;
+    memoryExport->value = Name::fromInt(0);
+    memoryExport->kind = ExternalKind::Memory;
+    wasm->addExport(memoryExport.release());
+  }
+  for (BinaryenIndex i = 0; i < numSegments; i++) {
+    wasm->memory.segments.emplace_back(segmentPassive[i],
+                                       (Expression*)segmentOffsets[i],
+                                       segments[i],
+                                       segmentSizes[i]);
+  }
+}
+
+// Memory segments
+
+uint32_t BinaryenGetNumMemorySegments(BinaryenModuleRef module) {
+  return ((Module*)module)->memory.segments.size();
+}
+uint32_t BinaryenGetMemorySegmentByteOffset(BinaryenModuleRef module,
+                                            BinaryenIndex id) {
+  auto* wasm = (Module*)module;
+  if (wasm->memory.segments.size() <= id) {
+    Fatal() << "invalid segment id.";
+  }
+
+  auto globalOffset = [&](const Expression* const& expr,
+                          int64_t& result) -> bool {
+    if (auto* c = expr->dynCast<Const>()) {
+      result = c->value.getInteger();
+      return true;
+    }
+    return false;
+  };
+
+  const auto& segment = wasm->memory.segments[id];
+
+  int64_t ret;
+  if (globalOffset(segment.offset, ret)) {
+    return ret;
+  }
+  if (auto* get = segment.offset->dynCast<GlobalGet>()) {
+    Global* global = wasm->getGlobal(get->name);
+    if (globalOffset(global->init, ret)) {
+      return ret;
+    }
+  }
+
+  Fatal() << "non-constant offsets aren't supported yet";
+  return 0;
+}
+size_t BinaryenGetMemorySegmentByteLength(BinaryenModuleRef module,
+                                          BinaryenIndex id) {
+  const auto& segments = ((Module*)module)->memory.segments;
+  if (segments.size() <= id) {
+    Fatal() << "invalid segment id.";
+  }
+  return segments[id].data.size();
+}
+int BinaryenGetMemorySegmentPassive(BinaryenModuleRef module,
+                                    BinaryenIndex id) {
+  const auto& segments = ((Module*)module)->memory.segments;
+  if (segments.size() <= id) {
+    Fatal() << "invalid segment id.";
+  }
+  return segments[id].isPassive;
+}
+void BinaryenCopyMemorySegmentData(BinaryenModuleRef module,
+                                   BinaryenIndex id,
+                                   char* buffer) {
+  const auto& segments = ((Module*)module)->memory.segments;
+  if (segments.size() <= id) {
+    Fatal() << "invalid segment id.";
+  }
+  const auto& segment = segments[id];
+  std::copy(segment.data.cbegin(), segment.data.cend(), buffer);
+}
+
+// Start function. One per module
+
+void BinaryenSetStart(BinaryenModuleRef module, BinaryenFunctionRef start) {
+  ((Module*)module)->addStart(((Function*)start)->name);
+}
+
+// Features
+
+BinaryenFeatures BinaryenModuleGetFeatures(BinaryenModuleRef module) {
+  return ((Module*)module)->features.features;
+}
+
+void BinaryenModuleSetFeatures(BinaryenModuleRef module,
+                               BinaryenFeatures features) {
+  ((Module*)module)->features.features = features;
+}
+
+//
+// ========== Module Operations ==========
+//
+
+BinaryenModuleRef BinaryenModuleParse(const char* text) {
+  auto* wasm = new Module;
+  try {
+    SExpressionParser parser(const_cast<char*>(text));
+    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 BinaryenModulePrint(BinaryenModuleRef module) {
+  WasmPrinter::printModule((Module*)module);
+}
+
+void BinaryenModulePrintAsmjs(BinaryenModuleRef module) {
+  auto* wasm = (Module*)module;
+  Wasm2JSBuilder::Flags flags;
+  Wasm2JSBuilder wasm2js(flags, globalPassOptions);
+  auto asmjs = wasm2js.processWasm(wasm);
+  JSPrinter jser(true, true, asmjs);
+  Output out("", Flags::Text); // stdout
+  Wasm2JSGlue glue(*wasm, out, flags, "asmFunc");
+  glue.emitPre();
+  jser.printAst();
+  std::cout << jser.buffer << std::endl;
+  glue.emitPost();
+}
+
+int BinaryenModuleValidate(BinaryenModuleRef module) {
+  return WasmValidator().validate(*(Module*)module) ? 1 : 0;
+}
+
+void BinaryenModuleOptimize(BinaryenModuleRef module) {
+  PassRunner passRunner((Module*)module);
+  passRunner.options = globalPassOptions;
+  passRunner.addDefaultOptimizationPasses();
+  passRunner.run();
+}
+
+int BinaryenGetOptimizeLevel(void) { return globalPassOptions.optimizeLevel; }
+
+void BinaryenSetOptimizeLevel(int level) {
+  globalPassOptions.optimizeLevel = level;
+}
+
+int BinaryenGetShrinkLevel(void) { return globalPassOptions.shrinkLevel; }
+
+void BinaryenSetShrinkLevel(int level) {
+  globalPassOptions.shrinkLevel = level;
+}
+
+int BinaryenGetDebugInfo(void) { return globalPassOptions.debugInfo; }
+
+void BinaryenSetDebugInfo(int on) { globalPassOptions.debugInfo = on != 0; }
+
+int BinaryenGetLowMemoryUnused(void) {
+  return globalPassOptions.lowMemoryUnused;
+}
+
+void BinaryenSetLowMemoryUnused(int on) {
+  globalPassOptions.lowMemoryUnused = on != 0;
+}
+
+int BinaryenGetFastMath(void) { return globalPassOptions.fastMath; }
+
+void BinaryenSetFastMath(int value) { globalPassOptions.fastMath = value != 0; }
+
+const char* BinaryenGetPassArgument(const char* key) {
+  assert(key);
+  const auto& args = globalPassOptions.arguments;
+  auto it = args.find(key);
+  if (it == args.end()) {
+    return nullptr;
+  }
+  // internalize the string so it remains valid while the module is
+  return Name(it->second).c_str();
+}
+
+void BinaryenSetPassArgument(const char* key, const char* value) {
+  assert(key);
+  if (value) {
+    globalPassOptions.arguments[key] = value;
+  } else {
+    globalPassOptions.arguments.erase(key);
+  }
+}
+
+void BinaryenClearPassArguments(void) { globalPassOptions.arguments.clear(); }
+
+BinaryenIndex BinaryenGetAlwaysInlineMaxSize(void) {
+  return globalPassOptions.inlining.alwaysInlineMaxSize;
+}
+
+void BinaryenSetAlwaysInlineMaxSize(BinaryenIndex size) {
+  globalPassOptions.inlining.alwaysInlineMaxSize = size;
+}
+
+BinaryenIndex BinaryenGetFlexibleInlineMaxSize(void) {
+  return globalPassOptions.inlining.flexibleInlineMaxSize;
+}
+
+void BinaryenSetFlexibleInlineMaxSize(BinaryenIndex size) {
+  globalPassOptions.inlining.flexibleInlineMaxSize = size;
+}
+
+BinaryenIndex BinaryenGetOneCallerInlineMaxSize(void) {
+  return globalPassOptions.inlining.oneCallerInlineMaxSize;
+}
+
+void BinaryenSetOneCallerInlineMaxSize(BinaryenIndex size) {
+  globalPassOptions.inlining.oneCallerInlineMaxSize = size;
+}
+
+int BinaryenGetAllowInliningFunctionsWithLoops(void) {
+  return globalPassOptions.inlining.allowFunctionsWithLoops;
+}
+
+void BinaryenSetAllowInliningFunctionsWithLoops(int enabled) {
+  globalPassOptions.inlining.allowFunctionsWithLoops = enabled;
+}
+
+void BinaryenModuleRunPasses(BinaryenModuleRef module,
+                             const char** passes,
+                             BinaryenIndex numPasses) {
+  PassRunner passRunner((Module*)module);
+  passRunner.options = globalPassOptions;
+  for (BinaryenIndex i = 0; i < numPasses; i++) {
+    passRunner.add(passes[i]);
+  }
+  passRunner.run();
+}
+
+void BinaryenModuleAutoDrop(BinaryenModuleRef module) {
+  auto* wasm = (Module*)module;
+  PassRunner runner(wasm, globalPassOptions);
+  AutoDrop().run(&runner, wasm);
+}
+
+static BinaryenBufferSizes writeModule(BinaryenModuleRef module,
+                                       char* output,
+                                       size_t outputSize,
+                                       const char* sourceMapUrl,
+                                       char* sourceMap,
+                                       size_t sourceMapSize) {
+  BufferWithRandomAccess buffer;
+  WasmBinaryWriter writer((Module*)module, buffer);
+  writer.setNamesSection(globalPassOptions.debugInfo);
+  std::ostringstream os;
+  if (sourceMapUrl) {
+    writer.setSourceMap(&os, sourceMapUrl);
+  }
+  writer.write();
+  size_t bytes = std::min(buffer.size(), outputSize);
+  std::copy_n(buffer.begin(), bytes, output);
+  size_t sourceMapBytes = 0;
+  if (sourceMapUrl) {
+    auto str = os.str();
+    sourceMapBytes = std::min(str.length(), sourceMapSize);
+    std::copy_n(str.c_str(), sourceMapBytes, sourceMap);
+  }
+  return {bytes, sourceMapBytes};
+}
+
+size_t
+BinaryenModuleWrite(BinaryenModuleRef module, char* output, size_t outputSize) {
+  return writeModule((Module*)module, output, outputSize, nullptr, nullptr, 0)
+    .outputBytes;
+}
+
+size_t BinaryenModuleWriteText(BinaryenModuleRef module,
+                               char* output,
+                               size_t outputSize) {
+  // 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);
+
+  const auto temp = ss.str();
+  const auto ctemp = temp.c_str();
+
+  strncpy(output, ctemp, outputSize);
+  return std::min(outputSize, temp.size());
+}
+
+BinaryenBufferSizes BinaryenModuleWriteWithSourceMap(BinaryenModuleRef module,
+                                                     const char* url,
+                                                     char* output,
+                                                     size_t outputSize,
+                                                     char* sourceMap,
+                                                     size_t sourceMapSize) {
+  assert(url);
+  assert(sourceMap);
+  return writeModule(
+    (Module*)module, output, outputSize, url, sourceMap, sourceMapSize);
+}
+
+BinaryenModuleAllocateAndWriteResult
+BinaryenModuleAllocateAndWrite(BinaryenModuleRef module,
+                               const char* sourceMapUrl) {
+  BufferWithRandomAccess buffer;
+  WasmBinaryWriter writer((Module*)module, buffer);
+  writer.setNamesSection(globalPassOptions.debugInfo);
+  std::ostringstream os;
+  if (sourceMapUrl) {
+    writer.setSourceMap(&os, sourceMapUrl);
+  }
+  writer.write();
+  void* binary = malloc(buffer.size());
+  std::copy_n(buffer.begin(), buffer.size(), static_cast<char*>(binary));
+  char* sourceMap = nullptr;
+  if (sourceMapUrl) {
+    auto str = os.str();
+    sourceMap = (char*)malloc(str.length() + 1);
+    std::copy_n(str.c_str(), str.length() + 1, sourceMap);
+  }
+  return {binary, buffer.size(), sourceMap};
+}
+
+char* BinaryenModuleAllocateAndWriteText(BinaryenModuleRef module) {
+  std::stringstream ss;
+  WasmPrinter::printModule((Module*)module, ss);
+
+  const std::string out = ss.str();
+  const int len = out.length() + 1;
+  char* cout = (char*)malloc(len);
+  strncpy(cout, out.c_str(), len);
+  return cout;
+}
+
+BinaryenModuleRef BinaryenModuleRead(char* input, size_t inputSize) {
+  auto* wasm = new Module;
+  std::vector<char> buffer(false);
+  buffer.resize(inputSize);
+  std::copy_n(input, inputSize, buffer.begin());
+  try {
+    WasmBinaryBuilder parser(*wasm, buffer);
+    parser.read();
+  } catch (ParseException& p) {
+    p.dump(std::cerr);
+    Fatal() << "error in parsing wasm binary";
+  }
+  return wasm;
+}
+
+void BinaryenModuleInterpret(BinaryenModuleRef module) {
+  ShellExternalInterface interface;
+  ModuleInstance instance(*(Module*)module, &interface);
+}
+
+BinaryenIndex BinaryenModuleAddDebugInfoFileName(BinaryenModuleRef module,
+                                                 const char* filename) {
+  auto& debugInfoFileNames = ((Module*)module)->debugInfoFileNames;
+  BinaryenIndex index = debugInfoFileNames.size();
+  debugInfoFileNames.push_back(filename);
+  return index;
+}
+
+const char* BinaryenModuleGetDebugInfoFileName(BinaryenModuleRef module,
+                                               BinaryenIndex index) {
+  const auto& debugInfoFileNames = ((Module*)module)->debugInfoFileNames;
+  return index < debugInfoFileNames.size()
+           ? debugInfoFileNames.at(index).c_str()
+           : nullptr;
+}
+
+//
+// ========== Function Operations ==========
+//
+
+const char* BinaryenFunctionGetName(BinaryenFunctionRef func) {
+  return ((Function*)func)->name.c_str();
+}
+BinaryenType BinaryenFunctionGetParams(BinaryenFunctionRef func) {
+  return ((Function*)func)->sig.params.getID();
+}
+BinaryenType BinaryenFunctionGetResults(BinaryenFunctionRef func) {
+  return ((Function*)func)->sig.results.getID();
+}
+BinaryenIndex BinaryenFunctionGetNumVars(BinaryenFunctionRef func) {
+  return ((Function*)func)->vars.size();
+}
+BinaryenType BinaryenFunctionGetVar(BinaryenFunctionRef func,
+                                    BinaryenIndex index) {
+  const auto& vars = ((Function*)func)->vars;
+  assert(index < vars.size());
+  return vars[index].getID();
+}
+BinaryenIndex BinaryenFunctionGetNumLocals(BinaryenFunctionRef func) {
+  return ((Function*)func)->getNumLocals();
+}
+int BinaryenFunctionHasLocalName(BinaryenFunctionRef func,
+                                 BinaryenIndex index) {
+  return ((Function*)func)->hasLocalName(index);
+}
+const char* BinaryenFunctionGetLocalName(BinaryenFunctionRef func,
+                                         BinaryenIndex index) {
+  return ((Function*)func)->getLocalName(index).str;
+}
+void BinaryenFunctionSetLocalName(BinaryenFunctionRef func,
+                                  BinaryenIndex index,
+                                  const char* name) {
+  ((Function*)func)->setLocalName(index, name);
+}
+BinaryenExpressionRef BinaryenFunctionGetBody(BinaryenFunctionRef func) {
+  return ((Function*)func)->body;
+}
+void BinaryenFunctionSetBody(BinaryenFunctionRef func,
+                             BinaryenExpressionRef body) {
+  assert(body);
+  ((Function*)func)->body = (Expression*)body;
+}
+void BinaryenFunctionOptimize(BinaryenFunctionRef func,
+                              BinaryenModuleRef module) {
+  PassRunner passRunner((Module*)module);
+  passRunner.options = globalPassOptions;
+  passRunner.addDefaultOptimizationPasses();
+  passRunner.runOnFunction((Function*)func);
+}
+void BinaryenFunctionRunPasses(BinaryenFunctionRef func,
+                               BinaryenModuleRef module,
+                               const char** passes,
+                               BinaryenIndex numPasses) {
+  PassRunner passRunner((Module*)module);
+  passRunner.options = globalPassOptions;
+  for (BinaryenIndex i = 0; i < numPasses; i++) {
+    passRunner.add(passes[i]);
+  }
+  passRunner.runOnFunction((Function*)func);
+}
+void BinaryenFunctionSetDebugLocation(BinaryenFunctionRef func,
+                                      BinaryenExpressionRef expr,
+                                      BinaryenIndex fileIndex,
+                                      BinaryenIndex lineNumber,
+                                      BinaryenIndex columnNumber) {
+  Function::DebugLocation loc;
+  loc.fileIndex = fileIndex;
+  loc.lineNumber = lineNumber;
+  loc.columnNumber = columnNumber;
+  ((Function*)func)->debugLocations[(Expression*)expr] = loc;
+}
+
+//
+// =========== Global operations ===========
+//
+
+const char* BinaryenGlobalGetName(BinaryenGlobalRef global) {
+  return ((Global*)global)->name.c_str();
+}
+BinaryenType BinaryenGlobalGetType(BinaryenGlobalRef global) {
+  return ((Global*)global)->type.getID();
+}
+int BinaryenGlobalIsMutable(BinaryenGlobalRef global) {
+  return ((Global*)global)->mutable_;
+}
+BinaryenExpressionRef BinaryenGlobalGetInitExpr(BinaryenGlobalRef global) {
+  return ((Global*)global)->init;
+}
+
+//
+// =========== Event operations ===========
+//
+
+const char* BinaryenEventGetName(BinaryenEventRef event) {
+  return ((Event*)event)->name.c_str();
+}
+int BinaryenEventGetAttribute(BinaryenEventRef event) {
+  return ((Event*)event)->attribute;
+}
+BinaryenType BinaryenEventGetParams(BinaryenEventRef event) {
+  return ((Event*)event)->sig.params.getID();
+}
+
+BinaryenType BinaryenEventGetResults(BinaryenEventRef event) {
+  return ((Event*)event)->sig.results.getID();
+}
+
+//
+// =========== Import operations ===========
+//
+
+const char* BinaryenFunctionImportGetModule(BinaryenFunctionRef import) {
+  auto* func = (Function*)import;
+  if (func->imported()) {
+    return func->module.c_str();
+  } else {
+    return "";
+  }
+}
+const char* BinaryenGlobalImportGetModule(BinaryenGlobalRef import) {
+  auto* global = (Global*)import;
+  if (global->imported()) {
+    return global->module.c_str();
+  } else {
+    return "";
+  }
+}
+const char* BinaryenEventImportGetModule(BinaryenEventRef import) {
+  auto* event = (Event*)import;
+  if (event->imported()) {
+    return event->module.c_str();
+  } else {
+    return "";
+  }
+}
+const char* BinaryenFunctionImportGetBase(BinaryenFunctionRef import) {
+  auto* func = (Function*)import;
+  if (func->imported()) {
+    return func->base.c_str();
+  } else {
+    return "";
+  }
+}
+const char* BinaryenGlobalImportGetBase(BinaryenGlobalRef import) {
+  auto* global = (Global*)import;
+  if (global->imported()) {
+    return global->base.c_str();
+  } else {
+    return "";
+  }
+}
+const char* BinaryenEventImportGetBase(BinaryenEventRef import) {
+  auto* event = (Event*)import;
+  if (event->imported()) {
+    return event->base.c_str();
+  } else {
+    return "";
+  }
+}
+
+//
+// =========== Export operations ===========
+//
+
+BinaryenExternalKind BinaryenExportGetKind(BinaryenExportRef export_) {
+  return BinaryenExternalKind(((Export*)export_)->kind);
+}
+const char* BinaryenExportGetName(BinaryenExportRef export_) {
+  return ((Export*)export_)->name.c_str();
+}
+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();
+}
+
+//
+// ========= Custom sections =========
+//
+
+void BinaryenAddCustomSection(BinaryenModuleRef module,
+                              const char* name,
+                              const char* contents,
+                              BinaryenIndex contentsSize) {
+  wasm::UserSection customSection;
+  customSection.name = name;
+  customSection.data = std::vector<char>(contents, contents + contentsSize);
+  ((Module*)module)->userSections.push_back(customSection);
+}
+
+//
+// ========= Effect analyzer =========
+//
+
+BinaryenSideEffects BinaryenSideEffectNone(void) {
+  return static_cast<BinaryenSideEffects>(EffectAnalyzer::SideEffects::None);
+}
+BinaryenSideEffects BinaryenSideEffectBranches(void) {
+  return static_cast<BinaryenSideEffects>(
+    EffectAnalyzer::SideEffects::Branches);
+}
+BinaryenSideEffects BinaryenSideEffectCalls(void) {
+  return static_cast<BinaryenSideEffects>(EffectAnalyzer::SideEffects::Calls);
+}
+BinaryenSideEffects BinaryenSideEffectReadsLocal(void) {
+  return static_cast<BinaryenSideEffects>(
+    EffectAnalyzer::SideEffects::ReadsLocal);
+}
+BinaryenSideEffects BinaryenSideEffectWritesLocal(void) {
+  return static_cast<BinaryenSideEffects>(
+    EffectAnalyzer::SideEffects::WritesLocal);
+}
+BinaryenSideEffects BinaryenSideEffectReadsGlobal(void) {
+  return static_cast<BinaryenSideEffects>(
+    EffectAnalyzer::SideEffects::ReadsGlobal);
+}
+BinaryenSideEffects BinaryenSideEffectWritesGlobal(void) {
+  return static_cast<BinaryenSideEffects>(
+    EffectAnalyzer::SideEffects::WritesGlobal);
+}
+BinaryenSideEffects BinaryenSideEffectReadsMemory(void) {
+  return static_cast<BinaryenSideEffects>(
+    EffectAnalyzer::SideEffects::ReadsMemory);
+}
+BinaryenSideEffects BinaryenSideEffectWritesMemory(void) {
+  return static_cast<BinaryenSideEffects>(
+    EffectAnalyzer::SideEffects::WritesMemory);
+}
+BinaryenSideEffects BinaryenSideEffectImplicitTrap(void) {
+  return static_cast<BinaryenSideEffects>(
+    EffectAnalyzer::SideEffects::ImplicitTrap);
+}
+BinaryenSideEffects BinaryenSideEffectIsAtomic(void) {
+  return static_cast<BinaryenSideEffects>(
+    EffectAnalyzer::SideEffects::IsAtomic);
+}
+BinaryenSideEffects BinaryenSideEffectThrows(void) {
+  return static_cast<BinaryenSideEffects>(EffectAnalyzer::SideEffects::Throws);
+}
+BinaryenSideEffects BinaryenSideEffectDanglingPop(void) {
+  return static_cast<BinaryenSideEffects>(
+    EffectAnalyzer::SideEffects::DanglingPop);
+}
+BinaryenSideEffects BinaryenSideEffectAny(void) {
+  return static_cast<BinaryenSideEffects>(EffectAnalyzer::SideEffects::Any);
+}
+
+BinaryenSideEffects
+BinaryenExpressionGetSideEffects(BinaryenExpressionRef expr,
+                                 BinaryenFeatures features) {
+  return EffectAnalyzer(globalPassOptions, features, (Expression*)expr)
+    .getSideEffects();
+}
+
+//
+// ========== CFG / Relooper ==========
+//
+
+RelooperRef RelooperCreate(BinaryenModuleRef module) {
+  return RelooperRef(new CFG::Relooper((Module*)module));
+}
+
+RelooperBlockRef RelooperAddBlock(RelooperRef relooper,
+                                  BinaryenExpressionRef code) {
+  return RelooperBlockRef(
+    ((CFG::Relooper*)relooper)->AddBlock((Expression*)code));
+}
+
+void RelooperAddBranch(RelooperBlockRef from,
+                       RelooperBlockRef to,
+                       BinaryenExpressionRef condition,
+                       BinaryenExpressionRef code) {
+  ((CFG::Block*)from)
+    ->AddBranchTo((CFG::Block*)to, (Expression*)condition, (Expression*)code);
+}
+
+RelooperBlockRef RelooperAddBlockWithSwitch(RelooperRef relooper,
+                                            BinaryenExpressionRef code,
+                                            BinaryenExpressionRef condition) {
+  return RelooperBlockRef(
+    ((CFG::Relooper*)relooper)
+      ->AddBlock((Expression*)code, (Expression*)condition));
+}
+
+void RelooperAddBranchForSwitch(RelooperBlockRef from,
+                                RelooperBlockRef to,
+                                BinaryenIndex* indexes,
+                                BinaryenIndex numIndexes,
+                                BinaryenExpressionRef code) {
+  std::vector<Index> values;
+  for (Index i = 0; i < numIndexes; i++) {
+    values.push_back(indexes[i]);
+  }
+  ((CFG::Block*)from)
+    ->AddSwitchBranchTo((CFG::Block*)to, std::move(values), (Expression*)code);
+}
+
+BinaryenExpressionRef RelooperRenderAndDispose(RelooperRef relooper,
+                                               RelooperBlockRef entry,
+                                               BinaryenIndex labelHelper) {
+  auto* R = (CFG::Relooper*)relooper;
+  R->Calculate((CFG::Block*)entry);
+  CFG::RelooperBuilder builder(*R->Module, labelHelper);
+  auto* ret = R->Render(builder);
+  delete R;
+  return BinaryenExpressionRef(ret);
+}
+
+//
+// ========= ExpressionRunner =========
+//
+
+namespace wasm {
+
+// Evaluates a suspected constant expression via the C-API. Inherits most of its
+// functionality from ConstantExpressionRunner, which it shares with the
+// precompute pass, but must be `final` so we can `delete` its instances.
+class CExpressionRunner final
+  : public ConstantExpressionRunner<CExpressionRunner> {
+public:
+  CExpressionRunner(Module* module,
+                    CExpressionRunner::Flags flags,
+                    Index maxDepth,
+                    Index maxLoopIterations)
+    : ConstantExpressionRunner<CExpressionRunner>(
+        module, flags, maxDepth, maxLoopIterations) {}
+};
+
+} // namespace wasm
+
+ExpressionRunnerFlags ExpressionRunnerFlagsDefault() {
+  return CExpressionRunner::FlagValues::DEFAULT;
+}
+
+ExpressionRunnerFlags ExpressionRunnerFlagsPreserveSideeffects() {
+  return CExpressionRunner::FlagValues::PRESERVE_SIDEEFFECTS;
+}
+
+ExpressionRunnerFlags ExpressionRunnerFlagsTraverseCalls() {
+  return CExpressionRunner::FlagValues::TRAVERSE_CALLS;
+}
+
+ExpressionRunnerRef ExpressionRunnerCreate(BinaryenModuleRef module,
+                                           ExpressionRunnerFlags flags,
+                                           BinaryenIndex maxDepth,
+                                           BinaryenIndex maxLoopIterations) {
+  return static_cast<ExpressionRunnerRef>(
+    new CExpressionRunner((Module*)module, flags, maxDepth, maxLoopIterations));
+}
+
+int ExpressionRunnerSetLocalValue(ExpressionRunnerRef runner,
+                                  BinaryenIndex index,
+                                  BinaryenExpressionRef value) {
+  auto* R = (CExpressionRunner*)runner;
+  auto setFlow = R->visit(value);
+  if (!setFlow.breaking()) {
+    R->setLocalValue(index, setFlow.values);
+    return 1;
+  }
+  return 0;
+}
+
+int ExpressionRunnerSetGlobalValue(ExpressionRunnerRef runner,
+                                   const char* name,
+                                   BinaryenExpressionRef value) {
+  auto* R = (CExpressionRunner*)runner;
+  auto setFlow = R->visit(value);
+  if (!setFlow.breaking()) {
+    R->setGlobalValue(name, setFlow.values);
+    return 1;
+  }
+  return 0;
+}
+
+BinaryenExpressionRef
+ExpressionRunnerRunAndDispose(ExpressionRunnerRef runner,
+                              BinaryenExpressionRef expr) {
+  auto* R = (CExpressionRunner*)runner;
+  Expression* ret = nullptr;
+  try {
+    auto flow = R->visit(expr);
+    if (!flow.breaking() && !flow.values.empty()) {
+      ret = flow.getConstExpression(*R->getModule());
+    }
+  } catch (CExpressionRunner::NonconstantException&) {
+  }
+  delete R;
+  return ret;
+}
+
+//
+// ========= Utilities =========
+//
+
+void BinaryenSetColorsEnabled(int enabled) { Colors::setEnabled(enabled); }
+
+int BinaryenAreColorsEnabled() { return Colors::isEnabled(); }
+
+#ifdef __EMSCRIPTEN__
+// Override atexit - we don't need any global ctors to actually run, and
+// otherwise we get clutter in the output in debug builds
+int atexit(void (*function)(void)) { return 0; }
+
+// Internal binaryen.js APIs
+
+// Returns the size of a Literal object.
+EMSCRIPTEN_KEEPALIVE
+size_t BinaryenSizeofLiteral(void) { return sizeof(Literal); }
+
+// Returns the size of an allocate and write result object.
+EMSCRIPTEN_KEEPALIVE
+size_t BinaryenSizeofAllocateAndWriteResult(void) {
+  return sizeof(BinaryenModuleAllocateAndWriteResult);
+}
+
+// Helpers for accessing Binaryen's memory from another module without the
+// need to round-trip through JS, e.g. when allocating and initializing
+// strings passed to / reading strings returned by the C-API.
+
+// TODO: Remove these once Wasm supports multiple memories.
+
+// Stores an 8-bit integer to Binaryen memory.
+EMSCRIPTEN_KEEPALIVE
+void _i32_store8(int8_t* ptr, int8_t value) { *ptr = value; }
+
+// Stores a 16-bit integer to Binaryen memory.
+EMSCRIPTEN_KEEPALIVE
+void _i32_store16(int16_t* ptr, int16_t value) { *ptr = value; }
+
+// Stores a 32-bit integer to Binaryen memory.
+EMSCRIPTEN_KEEPALIVE
+void _i32_store(int32_t* ptr, int32_t value) { *ptr = value; }
+
+// Stores a 32-bit float to Binaryen memory.
+EMSCRIPTEN_KEEPALIVE
+void _f32_store(float* ptr, float value) { *ptr = value; }
+
+// Stores a 64-bit float to Binaryen memory.
+EMSCRIPTEN_KEEPALIVE
+void _f64_store(double* ptr, double value) { *ptr = value; }
+
+// Loads an 8-bit signed integer from Binaryen memory.
+EMSCRIPTEN_KEEPALIVE
+int8_t _i32_load8_s(int8_t* ptr) { return *ptr; }
+
+// Loads an 8-bit unsigned integer from Binaryen memory.
+EMSCRIPTEN_KEEPALIVE
+uint8_t _i32_load8_u(uint8_t* ptr) { return *ptr; }
+
+// Loads a 16-bit signed integer from Binaryen memory.
+EMSCRIPTEN_KEEPALIVE
+int16_t _i32_load16_s(int16_t* ptr) { return *ptr; }
+
+// Loads a 16-bit unsigned integer from Binaryen memory.
+EMSCRIPTEN_KEEPALIVE
+uint16_t _i32_load16_u(uint16_t* ptr) { return *ptr; }
+
+// Loads a 32-bit integer from Binaryen memory.
+EMSCRIPTEN_KEEPALIVE
+int32_t _i32_load(int32_t* ptr) { return *ptr; }
+
+// Loads a 32-bit float from Binaryen memory.
+EMSCRIPTEN_KEEPALIVE
+float _f32_load(float* ptr) { return *ptr; }
+
+// Loads a 64-bit float from Binaryen memory.
+EMSCRIPTEN_KEEPALIVE
+double _f64_load(double* ptr) { return *ptr; }
+
+#endif // __EMSCRIPTEN__
+
+} // extern "C"
diff --git a/binaryen/src/binaryen-c.h b/binaryen/src/binaryen-c.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/binaryen-c.h
@@ -0,0 +1,2561 @@
+/*
+ * 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.
+ */
+
+//================
+// Binaryen C API
+//
+// The first part of the API lets you create modules and their parts.
+//
+// The second part of the API lets you perform operations on modules.
+//
+// The third part of the API lets you provide a general control-flow
+//   graph (CFG) as input.
+//
+// The final part of the API contains miscellaneous utilities like
+//   debugging/tracing for the API itself.
+//
+// ---------------
+//
+// Thread safety: You can create Expressions in parallel, as they do not
+//                refer to global state. BinaryenAddFunction is also
+//                thread-safe, which means that you can create functions and
+//                their contents in multiple threads. This is important since
+//                functions are where the majority of the work is done.
+//                Other methods - creating imports, exports, etc. - are
+//                not currently thread-safe (as there is typically no need
+//                to parallelize them).
+//
+//================
+
+#ifndef wasm_binaryen_c_h
+#define wasm_binaryen_c_h
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __GNUC__
+#define WASM_DEPRECATED __attribute__((deprecated))
+#elif defined(_MSC_VER)
+#define WASM_DEPRECATED __declspec(deprecated)
+#else
+#define WASM_DEPRECATED
+#endif
+
+#if defined(__EMSCRIPTEN__)
+#include <emscripten.h>
+#define BINARYEN_API EMSCRIPTEN_KEEPALIVE
+#elif defined(_MSC_VER) && !defined(BUILD_STATIC_LIBRARY)
+#define BINARYEN_API __declspec(dllexport)
+#else
+#define BINARYEN_API
+#endif
+
+#ifdef __cplusplus
+#define BINARYEN_REF(NAME)                                                     \
+  namespace wasm {                                                             \
+  class NAME;                                                                  \
+  };                                                                           \
+  typedef class wasm::NAME* Binaryen##NAME##Ref;
+#else
+#define BINARYEN_REF(NAME) typedef struct Binaryen##NAME* Binaryen##NAME##Ref;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//
+// ========== Module Creation ==========
+//
+
+// BinaryenIndex
+//
+// Used for internal indexes and list sizes.
+
+typedef uint32_t BinaryenIndex;
+
+// Core types (call to get the value of each; you can cache them, they
+// never change)
+
+typedef uintptr_t BinaryenType;
+
+BINARYEN_API BinaryenType BinaryenTypeNone(void);
+BINARYEN_API BinaryenType BinaryenTypeInt32(void);
+BINARYEN_API BinaryenType BinaryenTypeInt64(void);
+BINARYEN_API BinaryenType BinaryenTypeFloat32(void);
+BINARYEN_API BinaryenType BinaryenTypeFloat64(void);
+BINARYEN_API BinaryenType BinaryenTypeVec128(void);
+BINARYEN_API BinaryenType BinaryenTypeFuncref(void);
+BINARYEN_API BinaryenType BinaryenTypeExternref(void);
+BINARYEN_API BinaryenType BinaryenTypeExnref(void);
+BINARYEN_API BinaryenType BinaryenTypeAnyref(void);
+BINARYEN_API BinaryenType BinaryenTypeEqref(void);
+BINARYEN_API BinaryenType BinaryenTypeI31ref(void);
+BINARYEN_API BinaryenType BinaryenTypeUnreachable(void);
+// Not a real type. Used as the last parameter to BinaryenBlock to let
+// the API figure out the type instead of providing one.
+BINARYEN_API BinaryenType BinaryenTypeAuto(void);
+BINARYEN_API BinaryenType BinaryenTypeCreate(BinaryenType* valueTypes,
+                                             uint32_t numTypes);
+BINARYEN_API uint32_t BinaryenTypeArity(BinaryenType t);
+BINARYEN_API void BinaryenTypeExpand(BinaryenType t, BinaryenType* buf);
+
+WASM_DEPRECATED BinaryenType BinaryenNone(void);
+WASM_DEPRECATED BinaryenType BinaryenInt32(void);
+WASM_DEPRECATED BinaryenType BinaryenInt64(void);
+WASM_DEPRECATED BinaryenType BinaryenFloat32(void);
+WASM_DEPRECATED BinaryenType BinaryenFloat64(void);
+WASM_DEPRECATED BinaryenType BinaryenUndefined(void);
+
+// Expression ids (call to get the value of each; you can cache them)
+
+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);
+
+// External kinds (call to get the value of each; you can cache them)
+
+typedef uint32_t BinaryenExternalKind;
+
+BINARYEN_API BinaryenExternalKind BinaryenExternalFunction(void);
+BINARYEN_API BinaryenExternalKind BinaryenExternalTable(void);
+BINARYEN_API BinaryenExternalKind BinaryenExternalMemory(void);
+BINARYEN_API BinaryenExternalKind BinaryenExternalGlobal(void);
+BINARYEN_API BinaryenExternalKind BinaryenExternalEvent(void);
+
+// Features. Call to get the value of each; you can cache them. Use bitwise
+// operators to combine and test particular features.
+
+typedef uint32_t BinaryenFeatures;
+
+BINARYEN_API BinaryenFeatures BinaryenFeatureMVP(void);
+BINARYEN_API BinaryenFeatures BinaryenFeatureAtomics(void);
+BINARYEN_API BinaryenFeatures BinaryenFeatureBulkMemory(void);
+BINARYEN_API BinaryenFeatures BinaryenFeatureMutableGlobals(void);
+BINARYEN_API BinaryenFeatures BinaryenFeatureNontrappingFPToInt(void);
+BINARYEN_API BinaryenFeatures BinaryenFeatureSignExt(void);
+BINARYEN_API BinaryenFeatures BinaryenFeatureSIMD128(void);
+BINARYEN_API BinaryenFeatures BinaryenFeatureExceptionHandling(void);
+BINARYEN_API BinaryenFeatures BinaryenFeatureTailCall(void);
+BINARYEN_API BinaryenFeatures BinaryenFeatureReferenceTypes(void);
+BINARYEN_API BinaryenFeatures BinaryenFeatureMultivalue(void);
+BINARYEN_API BinaryenFeatures BinaryenFeatureGC(void);
+BINARYEN_API BinaryenFeatures BinaryenFeatureMemory64(void);
+BINARYEN_API BinaryenFeatures BinaryenFeatureAll(void);
+
+// Modules
+//
+// Modules contain lists of functions, imports, exports, function types. The
+// Add* methods create them on a module. The module owns them and will free
+// their memory when the module is disposed of.
+//
+// Expressions are also allocated inside modules, and freed with the module.
+// They are not created by Add* methods, since they are not added directly on
+// the module, instead, they are arguments to other expressions (and then they
+// are the children of that AST node), or to a function (and then they are the
+// body of that function).
+//
+// A module can also contain a function table for indirect calls, a memory,
+// and a start method.
+
+BINARYEN_REF(Module);
+
+BINARYEN_API BinaryenModuleRef BinaryenModuleCreate(void);
+BINARYEN_API void BinaryenModuleDispose(BinaryenModuleRef module);
+
+// Literals. These are passed by value.
+
+struct BinaryenLiteral {
+  uintptr_t type;
+  union {
+    int32_t i32;
+    int64_t i64;
+    float f32;
+    double f64;
+    uint8_t v128[16];
+    const char* func;
+    // TODO: exn
+  };
+};
+
+BINARYEN_API struct BinaryenLiteral BinaryenLiteralInt32(int32_t x);
+BINARYEN_API struct BinaryenLiteral BinaryenLiteralInt64(int64_t x);
+BINARYEN_API struct BinaryenLiteral BinaryenLiteralFloat32(float x);
+BINARYEN_API struct BinaryenLiteral BinaryenLiteralFloat64(double x);
+BINARYEN_API struct BinaryenLiteral BinaryenLiteralVec128(const uint8_t x[16]);
+BINARYEN_API struct BinaryenLiteral BinaryenLiteralFloat32Bits(int32_t x);
+BINARYEN_API struct BinaryenLiteral BinaryenLiteralFloat64Bits(int64_t x);
+
+// Expressions
+//
+// Some expressions have a BinaryenOp, which is the more
+// specific operation/opcode.
+//
+// Some expressions have optional parameters, like Return may not
+// return a value. You can supply a NULL pointer in those cases.
+//
+// For more information, see wasm.h
+
+typedef int32_t BinaryenOp;
+
+BINARYEN_API BinaryenOp BinaryenClzInt32(void);
+BINARYEN_API BinaryenOp BinaryenCtzInt32(void);
+BINARYEN_API BinaryenOp BinaryenPopcntInt32(void);
+BINARYEN_API BinaryenOp BinaryenNegFloat32(void);
+BINARYEN_API BinaryenOp BinaryenAbsFloat32(void);
+BINARYEN_API BinaryenOp BinaryenCeilFloat32(void);
+BINARYEN_API BinaryenOp BinaryenFloorFloat32(void);
+BINARYEN_API BinaryenOp BinaryenTruncFloat32(void);
+BINARYEN_API BinaryenOp BinaryenNearestFloat32(void);
+BINARYEN_API BinaryenOp BinaryenSqrtFloat32(void);
+BINARYEN_API BinaryenOp BinaryenEqZInt32(void);
+BINARYEN_API BinaryenOp BinaryenClzInt64(void);
+BINARYEN_API BinaryenOp BinaryenCtzInt64(void);
+BINARYEN_API BinaryenOp BinaryenPopcntInt64(void);
+BINARYEN_API BinaryenOp BinaryenNegFloat64(void);
+BINARYEN_API BinaryenOp BinaryenAbsFloat64(void);
+BINARYEN_API BinaryenOp BinaryenCeilFloat64(void);
+BINARYEN_API BinaryenOp BinaryenFloorFloat64(void);
+BINARYEN_API BinaryenOp BinaryenTruncFloat64(void);
+BINARYEN_API BinaryenOp BinaryenNearestFloat64(void);
+BINARYEN_API BinaryenOp BinaryenSqrtFloat64(void);
+BINARYEN_API BinaryenOp BinaryenEqZInt64(void);
+BINARYEN_API BinaryenOp BinaryenExtendSInt32(void);
+BINARYEN_API BinaryenOp BinaryenExtendUInt32(void);
+BINARYEN_API BinaryenOp BinaryenWrapInt64(void);
+BINARYEN_API BinaryenOp BinaryenTruncSFloat32ToInt32(void);
+BINARYEN_API BinaryenOp BinaryenTruncSFloat32ToInt64(void);
+BINARYEN_API BinaryenOp BinaryenTruncUFloat32ToInt32(void);
+BINARYEN_API BinaryenOp BinaryenTruncUFloat32ToInt64(void);
+BINARYEN_API BinaryenOp BinaryenTruncSFloat64ToInt32(void);
+BINARYEN_API BinaryenOp BinaryenTruncSFloat64ToInt64(void);
+BINARYEN_API BinaryenOp BinaryenTruncUFloat64ToInt32(void);
+BINARYEN_API BinaryenOp BinaryenTruncUFloat64ToInt64(void);
+BINARYEN_API BinaryenOp BinaryenReinterpretFloat32(void);
+BINARYEN_API BinaryenOp BinaryenReinterpretFloat64(void);
+BINARYEN_API BinaryenOp BinaryenConvertSInt32ToFloat32(void);
+BINARYEN_API BinaryenOp BinaryenConvertSInt32ToFloat64(void);
+BINARYEN_API BinaryenOp BinaryenConvertUInt32ToFloat32(void);
+BINARYEN_API BinaryenOp BinaryenConvertUInt32ToFloat64(void);
+BINARYEN_API BinaryenOp BinaryenConvertSInt64ToFloat32(void);
+BINARYEN_API BinaryenOp BinaryenConvertSInt64ToFloat64(void);
+BINARYEN_API BinaryenOp BinaryenConvertUInt64ToFloat32(void);
+BINARYEN_API BinaryenOp BinaryenConvertUInt64ToFloat64(void);
+BINARYEN_API BinaryenOp BinaryenPromoteFloat32(void);
+BINARYEN_API BinaryenOp BinaryenDemoteFloat64(void);
+BINARYEN_API BinaryenOp BinaryenReinterpretInt32(void);
+BINARYEN_API BinaryenOp BinaryenReinterpretInt64(void);
+BINARYEN_API BinaryenOp BinaryenExtendS8Int32(void);
+BINARYEN_API BinaryenOp BinaryenExtendS16Int32(void);
+BINARYEN_API BinaryenOp BinaryenExtendS8Int64(void);
+BINARYEN_API BinaryenOp BinaryenExtendS16Int64(void);
+BINARYEN_API BinaryenOp BinaryenExtendS32Int64(void);
+BINARYEN_API BinaryenOp BinaryenAddInt32(void);
+BINARYEN_API BinaryenOp BinaryenSubInt32(void);
+BINARYEN_API BinaryenOp BinaryenMulInt32(void);
+BINARYEN_API BinaryenOp BinaryenDivSInt32(void);
+BINARYEN_API BinaryenOp BinaryenDivUInt32(void);
+BINARYEN_API BinaryenOp BinaryenRemSInt32(void);
+BINARYEN_API BinaryenOp BinaryenRemUInt32(void);
+BINARYEN_API BinaryenOp BinaryenAndInt32(void);
+BINARYEN_API BinaryenOp BinaryenOrInt32(void);
+BINARYEN_API BinaryenOp BinaryenXorInt32(void);
+BINARYEN_API BinaryenOp BinaryenShlInt32(void);
+BINARYEN_API BinaryenOp BinaryenShrUInt32(void);
+BINARYEN_API BinaryenOp BinaryenShrSInt32(void);
+BINARYEN_API BinaryenOp BinaryenRotLInt32(void);
+BINARYEN_API BinaryenOp BinaryenRotRInt32(void);
+BINARYEN_API BinaryenOp BinaryenEqInt32(void);
+BINARYEN_API BinaryenOp BinaryenNeInt32(void);
+BINARYEN_API BinaryenOp BinaryenLtSInt32(void);
+BINARYEN_API BinaryenOp BinaryenLtUInt32(void);
+BINARYEN_API BinaryenOp BinaryenLeSInt32(void);
+BINARYEN_API BinaryenOp BinaryenLeUInt32(void);
+BINARYEN_API BinaryenOp BinaryenGtSInt32(void);
+BINARYEN_API BinaryenOp BinaryenGtUInt32(void);
+BINARYEN_API BinaryenOp BinaryenGeSInt32(void);
+BINARYEN_API BinaryenOp BinaryenGeUInt32(void);
+BINARYEN_API BinaryenOp BinaryenAddInt64(void);
+BINARYEN_API BinaryenOp BinaryenSubInt64(void);
+BINARYEN_API BinaryenOp BinaryenMulInt64(void);
+BINARYEN_API BinaryenOp BinaryenDivSInt64(void);
+BINARYEN_API BinaryenOp BinaryenDivUInt64(void);
+BINARYEN_API BinaryenOp BinaryenRemSInt64(void);
+BINARYEN_API BinaryenOp BinaryenRemUInt64(void);
+BINARYEN_API BinaryenOp BinaryenAndInt64(void);
+BINARYEN_API BinaryenOp BinaryenOrInt64(void);
+BINARYEN_API BinaryenOp BinaryenXorInt64(void);
+BINARYEN_API BinaryenOp BinaryenShlInt64(void);
+BINARYEN_API BinaryenOp BinaryenShrUInt64(void);
+BINARYEN_API BinaryenOp BinaryenShrSInt64(void);
+BINARYEN_API BinaryenOp BinaryenRotLInt64(void);
+BINARYEN_API BinaryenOp BinaryenRotRInt64(void);
+BINARYEN_API BinaryenOp BinaryenEqInt64(void);
+BINARYEN_API BinaryenOp BinaryenNeInt64(void);
+BINARYEN_API BinaryenOp BinaryenLtSInt64(void);
+BINARYEN_API BinaryenOp BinaryenLtUInt64(void);
+BINARYEN_API BinaryenOp BinaryenLeSInt64(void);
+BINARYEN_API BinaryenOp BinaryenLeUInt64(void);
+BINARYEN_API BinaryenOp BinaryenGtSInt64(void);
+BINARYEN_API BinaryenOp BinaryenGtUInt64(void);
+BINARYEN_API BinaryenOp BinaryenGeSInt64(void);
+BINARYEN_API BinaryenOp BinaryenGeUInt64(void);
+BINARYEN_API BinaryenOp BinaryenAddFloat32(void);
+BINARYEN_API BinaryenOp BinaryenSubFloat32(void);
+BINARYEN_API BinaryenOp BinaryenMulFloat32(void);
+BINARYEN_API BinaryenOp BinaryenDivFloat32(void);
+BINARYEN_API BinaryenOp BinaryenCopySignFloat32(void);
+BINARYEN_API BinaryenOp BinaryenMinFloat32(void);
+BINARYEN_API BinaryenOp BinaryenMaxFloat32(void);
+BINARYEN_API BinaryenOp BinaryenEqFloat32(void);
+BINARYEN_API BinaryenOp BinaryenNeFloat32(void);
+BINARYEN_API BinaryenOp BinaryenLtFloat32(void);
+BINARYEN_API BinaryenOp BinaryenLeFloat32(void);
+BINARYEN_API BinaryenOp BinaryenGtFloat32(void);
+BINARYEN_API BinaryenOp BinaryenGeFloat32(void);
+BINARYEN_API BinaryenOp BinaryenAddFloat64(void);
+BINARYEN_API BinaryenOp BinaryenSubFloat64(void);
+BINARYEN_API BinaryenOp BinaryenMulFloat64(void);
+BINARYEN_API BinaryenOp BinaryenDivFloat64(void);
+BINARYEN_API BinaryenOp BinaryenCopySignFloat64(void);
+BINARYEN_API BinaryenOp BinaryenMinFloat64(void);
+BINARYEN_API BinaryenOp BinaryenMaxFloat64(void);
+BINARYEN_API BinaryenOp BinaryenEqFloat64(void);
+BINARYEN_API BinaryenOp BinaryenNeFloat64(void);
+BINARYEN_API BinaryenOp BinaryenLtFloat64(void);
+BINARYEN_API BinaryenOp BinaryenLeFloat64(void);
+BINARYEN_API BinaryenOp BinaryenGtFloat64(void);
+BINARYEN_API BinaryenOp BinaryenGeFloat64(void);
+BINARYEN_API BinaryenOp BinaryenAtomicRMWAdd(void);
+BINARYEN_API BinaryenOp BinaryenAtomicRMWSub(void);
+BINARYEN_API BinaryenOp BinaryenAtomicRMWAnd(void);
+BINARYEN_API BinaryenOp BinaryenAtomicRMWOr(void);
+BINARYEN_API BinaryenOp BinaryenAtomicRMWXor(void);
+BINARYEN_API BinaryenOp BinaryenAtomicRMWXchg(void);
+BINARYEN_API BinaryenOp BinaryenTruncSatSFloat32ToInt32(void);
+BINARYEN_API BinaryenOp BinaryenTruncSatSFloat32ToInt64(void);
+BINARYEN_API BinaryenOp BinaryenTruncSatUFloat32ToInt32(void);
+BINARYEN_API BinaryenOp BinaryenTruncSatUFloat32ToInt64(void);
+BINARYEN_API BinaryenOp BinaryenTruncSatSFloat64ToInt32(void);
+BINARYEN_API BinaryenOp BinaryenTruncSatSFloat64ToInt64(void);
+BINARYEN_API BinaryenOp BinaryenTruncSatUFloat64ToInt32(void);
+BINARYEN_API BinaryenOp BinaryenTruncSatUFloat64ToInt64(void);
+BINARYEN_API BinaryenOp BinaryenSplatVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenExtractLaneSVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenExtractLaneUVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenReplaceLaneVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenSplatVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenExtractLaneSVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenExtractLaneUVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenReplaceLaneVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenSplatVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenExtractLaneVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenReplaceLaneVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenSplatVecI64x2(void);
+BINARYEN_API BinaryenOp BinaryenExtractLaneVecI64x2(void);
+BINARYEN_API BinaryenOp BinaryenReplaceLaneVecI64x2(void);
+BINARYEN_API BinaryenOp BinaryenSplatVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenExtractLaneVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenReplaceLaneVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenSplatVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenExtractLaneVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenReplaceLaneVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenEqVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenNeVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenLtSVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenLtUVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenGtSVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenGtUVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenLeSVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenLeUVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenGeSVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenGeUVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenEqVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenNeVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenLtSVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenLtUVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenGtSVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenGtUVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenLeSVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenLeUVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenGeSVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenGeUVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenEqVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenNeVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenLtSVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenLtUVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenGtSVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenGtUVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenLeSVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenLeUVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenGeSVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenGeUVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenEqVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenNeVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenLtVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenGtVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenLeVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenGeVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenEqVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenNeVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenLtVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenGtVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenLeVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenGeVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenNotVec128(void);
+BINARYEN_API BinaryenOp BinaryenAndVec128(void);
+BINARYEN_API BinaryenOp BinaryenOrVec128(void);
+BINARYEN_API BinaryenOp BinaryenXorVec128(void);
+BINARYEN_API BinaryenOp BinaryenAndNotVec128(void);
+BINARYEN_API BinaryenOp BinaryenBitselectVec128(void);
+BINARYEN_API BinaryenOp BinaryenAbsVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenNegVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenAnyTrueVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenAllTrueVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenBitmaskVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenShlVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenShrSVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenShrUVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenAddVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenAddSatSVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenAddSatUVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenSubVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenSubSatSVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenSubSatUVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenMulVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenMinSVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenMinUVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenMaxSVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenMaxUVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenAvgrUVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenAbsVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenNegVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenAnyTrueVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenAllTrueVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenBitmaskVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenShlVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenShrSVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenShrUVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenAddVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenAddSatSVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenAddSatUVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenSubVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenSubSatSVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenSubSatUVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenMulVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenMinSVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenMinUVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenMaxSVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenMaxUVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenAvgrUVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenAbsVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenNegVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenAnyTrueVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenAllTrueVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenBitmaskVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenShlVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenShrSVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenShrUVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenAddVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenSubVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenMulVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenMinSVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenMinUVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenMaxSVecI32x4(void);
+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);
+BINARYEN_API BinaryenOp BinaryenAddVecI64x2(void);
+BINARYEN_API BinaryenOp BinaryenSubVecI64x2(void);
+BINARYEN_API BinaryenOp BinaryenMulVecI64x2(void);
+BINARYEN_API BinaryenOp BinaryenAbsVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenNegVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenSqrtVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenQFMAVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenQFMSVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenAddVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenSubVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenMulVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenDivVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenMinVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenMaxVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenPMinVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenPMaxVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenCeilVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenFloorVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenTruncVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenNearestVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenAbsVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenNegVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenSqrtVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenQFMAVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenQFMSVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenAddVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenSubVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenMulVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenDivVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenMinVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenMaxVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenPMinVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenPMaxVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenCeilVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenFloorVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenTruncVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenNearestVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenTruncSatSVecF32x4ToVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenTruncSatUVecF32x4ToVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenTruncSatSVecF64x2ToVecI64x2(void);
+BINARYEN_API BinaryenOp BinaryenTruncSatUVecF64x2ToVecI64x2(void);
+BINARYEN_API BinaryenOp BinaryenConvertSVecI32x4ToVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenConvertUVecI32x4ToVecF32x4(void);
+BINARYEN_API BinaryenOp BinaryenConvertSVecI64x2ToVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenConvertUVecI64x2ToVecF64x2(void);
+BINARYEN_API BinaryenOp BinaryenLoadSplatVec8x16(void);
+BINARYEN_API BinaryenOp BinaryenLoadSplatVec16x8(void);
+BINARYEN_API BinaryenOp BinaryenLoadSplatVec32x4(void);
+BINARYEN_API BinaryenOp BinaryenLoadSplatVec64x2(void);
+BINARYEN_API BinaryenOp BinaryenLoadExtSVec8x8ToVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenLoadExtUVec8x8ToVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenLoadExtSVec16x4ToVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenLoadExtUVec16x4ToVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenLoadExtSVec32x2ToVecI64x2(void);
+BINARYEN_API BinaryenOp BinaryenLoadExtUVec32x2ToVecI64x2(void);
+// TODO: Add Load{32,64}Zero to C and JS APIs once merged to proposal
+BINARYEN_API BinaryenOp BinaryenNarrowSVecI16x8ToVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenNarrowUVecI16x8ToVecI8x16(void);
+BINARYEN_API BinaryenOp BinaryenNarrowSVecI32x4ToVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenNarrowUVecI32x4ToVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenWidenLowSVecI8x16ToVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenWidenHighSVecI8x16ToVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenWidenLowUVecI8x16ToVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenWidenHighUVecI8x16ToVecI16x8(void);
+BINARYEN_API BinaryenOp BinaryenWidenLowSVecI16x8ToVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenWidenHighSVecI16x8ToVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenWidenLowUVecI16x8ToVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenWidenHighUVecI16x8ToVecI32x4(void);
+BINARYEN_API BinaryenOp BinaryenSwizzleVec8x16(void);
+
+BINARYEN_REF(Expression);
+
+// Block: name can be NULL. Specifying BinaryenUndefined() as the 'type'
+//        parameter indicates that the block's type shall be figured out
+//        automatically instead of explicitly providing it. This conforms
+//        to the behavior before the 'type' parameter has been introduced.
+BINARYEN_API BinaryenExpressionRef
+BinaryenBlock(BinaryenModuleRef module,
+              const char* name,
+              BinaryenExpressionRef* children,
+              BinaryenIndex numChildren,
+              BinaryenType type);
+// If: ifFalse can be NULL
+BINARYEN_API BinaryenExpressionRef BinaryenIf(BinaryenModuleRef module,
+                                              BinaryenExpressionRef condition,
+                                              BinaryenExpressionRef ifTrue,
+                                              BinaryenExpressionRef ifFalse);
+BINARYEN_API BinaryenExpressionRef BinaryenLoop(BinaryenModuleRef module,
+                                                const char* in,
+                                                BinaryenExpressionRef body);
+// Break: value and condition can be NULL
+BINARYEN_API BinaryenExpressionRef
+BinaryenBreak(BinaryenModuleRef module,
+              const char* name,
+              BinaryenExpressionRef condition,
+              BinaryenExpressionRef value);
+// Switch: value can be NULL
+BINARYEN_API BinaryenExpressionRef
+BinaryenSwitch(BinaryenModuleRef module,
+               const char** names,
+               BinaryenIndex numNames,
+               const char* defaultName,
+               BinaryenExpressionRef condition,
+               BinaryenExpressionRef value);
+// Call: Note the 'returnType' parameter. You must declare the
+//       type returned by the function being called, as that
+//       function might not have been created yet, so we don't
+//       know what it is.
+BINARYEN_API BinaryenExpressionRef BinaryenCall(BinaryenModuleRef module,
+                                                const char* target,
+                                                BinaryenExpressionRef* operands,
+                                                BinaryenIndex numOperands,
+                                                BinaryenType returnType);
+BINARYEN_API BinaryenExpressionRef
+BinaryenCallIndirect(BinaryenModuleRef module,
+                     BinaryenExpressionRef target,
+                     BinaryenExpressionRef* operands,
+                     BinaryenIndex numOperands,
+                     BinaryenType params,
+                     BinaryenType results);
+BINARYEN_API BinaryenExpressionRef
+BinaryenReturnCall(BinaryenModuleRef module,
+                   const char* target,
+                   BinaryenExpressionRef* operands,
+                   BinaryenIndex numOperands,
+                   BinaryenType returnType);
+BINARYEN_API BinaryenExpressionRef
+BinaryenReturnCallIndirect(BinaryenModuleRef module,
+                           BinaryenExpressionRef target,
+                           BinaryenExpressionRef* operands,
+                           BinaryenIndex numOperands,
+                           BinaryenType params,
+                           BinaryenType results);
+
+// LocalGet: Note the 'type' parameter. It might seem redundant, since the
+//           local at that index must have a type. However, this API lets you
+//           build code "top-down": create a node, then its parents, and so
+//           on, and finally create the function at the end. (Note that in fact
+//           you do not mention a function when creating ExpressionRefs, only
+//           a module.) And since LocalGet is a leaf node, we need to be told
+//           its type. (Other nodes detect their type either from their
+//           type or their opcode, or failing that, their children. But
+//           LocalGet has no children, it is where a "stream" of type info
+//           begins.)
+//           Note also that the index of a local can refer to a param or
+//           a var, that is, either a parameter to the function or a variable
+//           declared when you call BinaryenAddFunction. See BinaryenAddFunction
+//           for more details.
+BINARYEN_API BinaryenExpressionRef BinaryenLocalGet(BinaryenModuleRef module,
+                                                    BinaryenIndex index,
+                                                    BinaryenType type);
+BINARYEN_API BinaryenExpressionRef BinaryenLocalSet(
+  BinaryenModuleRef module, BinaryenIndex index, BinaryenExpressionRef value);
+BINARYEN_API BinaryenExpressionRef BinaryenLocalTee(BinaryenModuleRef module,
+                                                    BinaryenIndex index,
+                                                    BinaryenExpressionRef value,
+                                                    BinaryenType type);
+BINARYEN_API BinaryenExpressionRef BinaryenGlobalGet(BinaryenModuleRef module,
+                                                     const char* name,
+                                                     BinaryenType type);
+BINARYEN_API BinaryenExpressionRef BinaryenGlobalSet(
+  BinaryenModuleRef module, const char* name, BinaryenExpressionRef value);
+// Load: align can be 0, in which case it will be the natural alignment (equal
+// to bytes)
+BINARYEN_API BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module,
+                                                uint32_t bytes,
+                                                int8_t signed_,
+                                                uint32_t offset,
+                                                uint32_t align,
+                                                BinaryenType type,
+                                                BinaryenExpressionRef ptr);
+// Store: align can be 0, in which case it will be the natural alignment (equal
+// to bytes)
+BINARYEN_API BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module,
+                                                 uint32_t bytes,
+                                                 uint32_t offset,
+                                                 uint32_t align,
+                                                 BinaryenExpressionRef ptr,
+                                                 BinaryenExpressionRef value,
+                                                 BinaryenType type);
+BINARYEN_API BinaryenExpressionRef BinaryenConst(BinaryenModuleRef module,
+                                                 struct BinaryenLiteral value);
+BINARYEN_API BinaryenExpressionRef BinaryenUnary(BinaryenModuleRef module,
+                                                 BinaryenOp op,
+                                                 BinaryenExpressionRef value);
+BINARYEN_API BinaryenExpressionRef BinaryenBinary(BinaryenModuleRef module,
+                                                  BinaryenOp op,
+                                                  BinaryenExpressionRef left,
+                                                  BinaryenExpressionRef right);
+BINARYEN_API BinaryenExpressionRef
+BinaryenSelect(BinaryenModuleRef module,
+               BinaryenExpressionRef condition,
+               BinaryenExpressionRef ifTrue,
+               BinaryenExpressionRef ifFalse,
+               BinaryenType type);
+BINARYEN_API BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module,
+                                                BinaryenExpressionRef value);
+// Return: value can be NULL
+BINARYEN_API BinaryenExpressionRef BinaryenReturn(BinaryenModuleRef module,
+                                                  BinaryenExpressionRef value);
+BINARYEN_API BinaryenExpressionRef BinaryenMemorySize(BinaryenModuleRef module);
+BINARYEN_API BinaryenExpressionRef
+BinaryenMemoryGrow(BinaryenModuleRef module, BinaryenExpressionRef delta);
+BINARYEN_API BinaryenExpressionRef BinaryenNop(BinaryenModuleRef module);
+BINARYEN_API BinaryenExpressionRef
+BinaryenUnreachable(BinaryenModuleRef module);
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicLoad(BinaryenModuleRef module,
+                   uint32_t bytes,
+                   uint32_t offset,
+                   BinaryenType type,
+                   BinaryenExpressionRef ptr);
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicStore(BinaryenModuleRef module,
+                    uint32_t bytes,
+                    uint32_t offset,
+                    BinaryenExpressionRef ptr,
+                    BinaryenExpressionRef value,
+                    BinaryenType type);
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicRMW(BinaryenModuleRef module,
+                  BinaryenOp op,
+                  BinaryenIndex bytes,
+                  BinaryenIndex offset,
+                  BinaryenExpressionRef ptr,
+                  BinaryenExpressionRef value,
+                  BinaryenType type);
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicCmpxchg(BinaryenModuleRef module,
+                      BinaryenIndex bytes,
+                      BinaryenIndex offset,
+                      BinaryenExpressionRef ptr,
+                      BinaryenExpressionRef expected,
+                      BinaryenExpressionRef replacement,
+                      BinaryenType type);
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicWait(BinaryenModuleRef module,
+                   BinaryenExpressionRef ptr,
+                   BinaryenExpressionRef expected,
+                   BinaryenExpressionRef timeout,
+                   BinaryenType type);
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicNotify(BinaryenModuleRef module,
+                     BinaryenExpressionRef ptr,
+                     BinaryenExpressionRef notifyCount);
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicFence(BinaryenModuleRef module);
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDExtract(BinaryenModuleRef module,
+                    BinaryenOp op,
+                    BinaryenExpressionRef vec,
+                    uint8_t index);
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDReplace(BinaryenModuleRef module,
+                    BinaryenOp op,
+                    BinaryenExpressionRef vec,
+                    uint8_t index,
+                    BinaryenExpressionRef value);
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDShuffle(BinaryenModuleRef module,
+                    BinaryenExpressionRef left,
+                    BinaryenExpressionRef right,
+                    const uint8_t mask[16]);
+BINARYEN_API BinaryenExpressionRef BinaryenSIMDTernary(BinaryenModuleRef module,
+                                                       BinaryenOp op,
+                                                       BinaryenExpressionRef a,
+                                                       BinaryenExpressionRef b,
+                                                       BinaryenExpressionRef c);
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDShift(BinaryenModuleRef module,
+                  BinaryenOp op,
+                  BinaryenExpressionRef vec,
+                  BinaryenExpressionRef shift);
+BINARYEN_API BinaryenExpressionRef BinaryenSIMDLoad(BinaryenModuleRef module,
+                                                    BinaryenOp op,
+                                                    uint32_t offset,
+                                                    uint32_t align,
+                                                    BinaryenExpressionRef ptr);
+BINARYEN_API BinaryenExpressionRef
+BinaryenMemoryInit(BinaryenModuleRef module,
+                   uint32_t segment,
+                   BinaryenExpressionRef dest,
+                   BinaryenExpressionRef offset,
+                   BinaryenExpressionRef size);
+BINARYEN_API BinaryenExpressionRef BinaryenDataDrop(BinaryenModuleRef module,
+                                                    uint32_t segment);
+BINARYEN_API BinaryenExpressionRef
+BinaryenMemoryCopy(BinaryenModuleRef module,
+                   BinaryenExpressionRef dest,
+                   BinaryenExpressionRef source,
+                   BinaryenExpressionRef size);
+BINARYEN_API BinaryenExpressionRef
+BinaryenMemoryFill(BinaryenModuleRef module,
+                   BinaryenExpressionRef dest,
+                   BinaryenExpressionRef value,
+                   BinaryenExpressionRef size);
+BINARYEN_API BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module,
+                                                   BinaryenType type);
+BINARYEN_API BinaryenExpressionRef
+BinaryenRefIsNull(BinaryenModuleRef module, BinaryenExpressionRef value);
+BINARYEN_API BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module,
+                                                   const char* func);
+BINARYEN_API BinaryenExpressionRef BinaryenRefEq(BinaryenModuleRef module,
+                                                 BinaryenExpressionRef left,
+                                                 BinaryenExpressionRef right);
+BINARYEN_API BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module,
+                                               BinaryenExpressionRef body,
+                                               BinaryenExpressionRef catchBody);
+BINARYEN_API BinaryenExpressionRef
+BinaryenThrow(BinaryenModuleRef module,
+              const char* event,
+              BinaryenExpressionRef* operands,
+              BinaryenIndex numOperands);
+BINARYEN_API BinaryenExpressionRef
+BinaryenRethrow(BinaryenModuleRef module, BinaryenExpressionRef exnref);
+BINARYEN_API BinaryenExpressionRef
+BinaryenBrOnExn(BinaryenModuleRef module,
+                const char* name,
+                const char* eventName,
+                BinaryenExpressionRef exnref);
+BINARYEN_API BinaryenExpressionRef
+BinaryenTupleMake(BinaryenModuleRef module,
+                  BinaryenExpressionRef* operands,
+                  BinaryenIndex numOperands);
+BINARYEN_API BinaryenExpressionRef BinaryenTupleExtract(
+  BinaryenModuleRef module, BinaryenExpressionRef tuple, BinaryenIndex index);
+BINARYEN_API BinaryenExpressionRef BinaryenPop(BinaryenModuleRef module,
+                                               BinaryenType type);
+BINARYEN_API BinaryenExpressionRef BinaryenI31New(BinaryenModuleRef module,
+                                                  BinaryenExpressionRef value);
+BINARYEN_API BinaryenExpressionRef BinaryenI31Get(BinaryenModuleRef module,
+                                                  BinaryenExpressionRef i31,
+                                                  int signed_);
+// 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
+
+// Expression
+
+// Gets the id (kind) of the given expression.
+BINARYEN_API BinaryenExpressionId
+BinaryenExpressionGetId(BinaryenExpressionRef expr);
+// Gets the type of the given expression.
+BINARYEN_API BinaryenType BinaryenExpressionGetType(BinaryenExpressionRef expr);
+// Sets the type of the given expression.
+BINARYEN_API void BinaryenExpressionSetType(BinaryenExpressionRef expr,
+                                            BinaryenType type);
+// Prints text format of the given expression to stdout.
+BINARYEN_API void BinaryenExpressionPrint(BinaryenExpressionRef expr);
+// Re-finalizes an expression after it has been modified.
+BINARYEN_API void BinaryenExpressionFinalize(BinaryenExpressionRef expr);
+// Makes a deep copy of the given expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenExpressionCopy(BinaryenExpressionRef expr, BinaryenModuleRef module);
+
+// Block
+
+// Gets the name (label) of a `block` expression.
+BINARYEN_API const char* BinaryenBlockGetName(BinaryenExpressionRef expr);
+// Sets the name (label) of a `block` expression.
+BINARYEN_API void BinaryenBlockSetName(BinaryenExpressionRef expr,
+                                       const char* name);
+// Gets the number of child expressions of a `block` expression.
+BINARYEN_API BinaryenIndex
+BinaryenBlockGetNumChildren(BinaryenExpressionRef expr);
+// Gets the child expression at the specified index of a `block` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenBlockGetChildAt(BinaryenExpressionRef expr, BinaryenIndex index);
+// Sets (replaces) the child expression at the specified index of a `block`
+// expression.
+BINARYEN_API void BinaryenBlockSetChildAt(BinaryenExpressionRef expr,
+                                          BinaryenIndex index,
+                                          BinaryenExpressionRef childExpr);
+// Appends a child expression to a `block` expression, returning its insertion
+// index.
+BINARYEN_API BinaryenIndex BinaryenBlockAppendChild(
+  BinaryenExpressionRef expr, BinaryenExpressionRef childExpr);
+// Inserts a child expression at the specified index of a `block` expression,
+// moving existing children including the one previously at that index one index
+// up.
+BINARYEN_API void BinaryenBlockInsertChildAt(BinaryenExpressionRef expr,
+                                             BinaryenIndex index,
+                                             BinaryenExpressionRef childExpr);
+// Removes the child expression at the specified index of a `block` expression,
+// moving all subsequent children one index down. Returns the child expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenBlockRemoveChildAt(BinaryenExpressionRef expr, BinaryenIndex index);
+
+// If
+
+// Gets the condition expression of an `if` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenIfGetCondition(BinaryenExpressionRef expr);
+// Sets the condition expression of an `if` expression.
+BINARYEN_API void BinaryenIfSetCondition(BinaryenExpressionRef expr,
+                                         BinaryenExpressionRef condExpr);
+// Gets the ifTrue (then) expression of an `if` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenIfGetIfTrue(BinaryenExpressionRef expr);
+// Sets the ifTrue (then) expression of an `if` expression.
+BINARYEN_API void BinaryenIfSetIfTrue(BinaryenExpressionRef expr,
+                                      BinaryenExpressionRef ifTrueExpr);
+// Gets the ifFalse (else) expression, if any, of an `if` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenIfGetIfFalse(BinaryenExpressionRef expr);
+// Sets the ifFalse (else) expression, if any, of an `if` expression.
+BINARYEN_API void BinaryenIfSetIfFalse(BinaryenExpressionRef expr,
+                                       BinaryenExpressionRef ifFalseExpr);
+
+// Loop
+
+// Gets the name (label) of a `loop` expression.
+BINARYEN_API const char* BinaryenLoopGetName(BinaryenExpressionRef expr);
+// Sets the name (label) of a `loop` expression.
+BINARYEN_API void BinaryenLoopSetName(BinaryenExpressionRef expr,
+                                      const char* name);
+// Gets the body expression of a `loop` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenLoopGetBody(BinaryenExpressionRef expr);
+// Sets the body expression of a `loop` expression.
+BINARYEN_API void BinaryenLoopSetBody(BinaryenExpressionRef expr,
+                                      BinaryenExpressionRef bodyExpr);
+
+// Break
+
+// Gets the name (target label) of a `br` or `br_if` expression.
+BINARYEN_API const char* BinaryenBreakGetName(BinaryenExpressionRef expr);
+// Sets the name (target label) of a `br` or `br_if` expression.
+BINARYEN_API void BinaryenBreakSetName(BinaryenExpressionRef expr,
+                                       const char* name);
+// Gets the condition expression, if any, of a `br_if` expression. No condition
+// indicates a `br` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenBreakGetCondition(BinaryenExpressionRef expr);
+// Sets the condition expression, if any, of a `br_if` expression. No condition
+// makes it a `br` expression.
+BINARYEN_API void BinaryenBreakSetCondition(BinaryenExpressionRef expr,
+                                            BinaryenExpressionRef condExpr);
+// Gets the value expression, if any, of a `br` or `br_if` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenBreakGetValue(BinaryenExpressionRef expr);
+// Sets the value expression, if any, of a `br` or `br_if` expression.
+BINARYEN_API void BinaryenBreakSetValue(BinaryenExpressionRef expr,
+                                        BinaryenExpressionRef valueExpr);
+
+// Switch
+
+// Gets the number of names (target labels) of a `br_table` expression.
+BINARYEN_API BinaryenIndex
+BinaryenSwitchGetNumNames(BinaryenExpressionRef expr);
+// Gets the name (target label) at the specified index of a `br_table`
+// expression.
+BINARYEN_API const char* BinaryenSwitchGetNameAt(BinaryenExpressionRef expr,
+                                                 BinaryenIndex index);
+// Sets the name (target label) at the specified index of a `br_table`
+// expression.
+BINARYEN_API void BinaryenSwitchSetNameAt(BinaryenExpressionRef expr,
+                                          BinaryenIndex index,
+                                          const char* name);
+// Appends a name to a `br_table` expression, returning its insertion index.
+BINARYEN_API BinaryenIndex BinaryenSwitchAppendName(BinaryenExpressionRef expr,
+                                                    const char* name);
+// Inserts a name at the specified index of a `br_table` expression, moving
+// existing names including the one previously at that index one index up.
+BINARYEN_API void BinaryenSwitchInsertNameAt(BinaryenExpressionRef expr,
+                                             BinaryenIndex index,
+                                             const char* name);
+// Removes the name at the specified index of a `br_table` expression, moving
+// all subsequent names one index down. Returns the name.
+BINARYEN_API const char* BinaryenSwitchRemoveNameAt(BinaryenExpressionRef expr,
+                                                    BinaryenIndex index);
+// Gets the default name (target label), if any, of a `br_table` expression.
+BINARYEN_API const char*
+BinaryenSwitchGetDefaultName(BinaryenExpressionRef expr);
+// Sets the default name (target label), if any, of a `br_table` expression.
+BINARYEN_API void BinaryenSwitchSetDefaultName(BinaryenExpressionRef expr,
+                                               const char* name);
+// Gets the condition expression of a `br_table` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSwitchGetCondition(BinaryenExpressionRef expr);
+// Sets the condition expression of a `br_table` expression.
+BINARYEN_API void BinaryenSwitchSetCondition(BinaryenExpressionRef expr,
+                                             BinaryenExpressionRef condExpr);
+// Gets the value expression, if any, of a `br_table` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSwitchGetValue(BinaryenExpressionRef expr);
+// Sets the value expression, if any, of a `br_table` expression.
+BINARYEN_API void BinaryenSwitchSetValue(BinaryenExpressionRef expr,
+                                         BinaryenExpressionRef valueExpr);
+
+// Call
+
+// Gets the target function name of a `call` expression.
+BINARYEN_API const char* BinaryenCallGetTarget(BinaryenExpressionRef expr);
+// Sets the target function name of a `call` expression.
+BINARYEN_API void BinaryenCallSetTarget(BinaryenExpressionRef expr,
+                                        const char* target);
+// Gets the number of operands of a `call` expression.
+BINARYEN_API BinaryenIndex
+BinaryenCallGetNumOperands(BinaryenExpressionRef expr);
+// Gets the operand expression at the specified index of a `call` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenCallGetOperandAt(BinaryenExpressionRef expr, BinaryenIndex index);
+// Sets the operand expression at the specified index of a `call` expression.
+BINARYEN_API void BinaryenCallSetOperandAt(BinaryenExpressionRef expr,
+                                           BinaryenIndex index,
+                                           BinaryenExpressionRef operandExpr);
+// Appends an operand expression to a `call` expression, returning its insertion
+// index.
+BINARYEN_API BinaryenIndex BinaryenCallAppendOperand(
+  BinaryenExpressionRef expr, BinaryenExpressionRef operandExpr);
+// Inserts an operand expression at the specified index of a `call` expression,
+// moving existing operands including the one previously at that index one index
+// up.
+BINARYEN_API void
+BinaryenCallInsertOperandAt(BinaryenExpressionRef expr,
+                            BinaryenIndex index,
+                            BinaryenExpressionRef operandExpr);
+// Removes the operand expression at the specified index of a `call` expression,
+// moving all subsequent operands one index down. Returns the operand
+// expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenCallRemoveOperandAt(BinaryenExpressionRef expr, BinaryenIndex index);
+// Gets whether the specified `call` expression is a tail call.
+BINARYEN_API int BinaryenCallIsReturn(BinaryenExpressionRef expr);
+// Sets whether the specified `call` expression is a tail call.
+BINARYEN_API void BinaryenCallSetReturn(BinaryenExpressionRef expr,
+                                        int isReturn);
+
+// CallIndirect
+
+// Gets the target expression of a `call_indirect` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenCallIndirectGetTarget(BinaryenExpressionRef expr);
+// Sets the target expression of a `call_indirect` expression.
+BINARYEN_API void
+BinaryenCallIndirectSetTarget(BinaryenExpressionRef expr,
+                              BinaryenExpressionRef targetExpr);
+// Gets the number of operands of a `call_indirect` expression.
+BINARYEN_API BinaryenIndex
+BinaryenCallIndirectGetNumOperands(BinaryenExpressionRef expr);
+// Gets the operand expression at the specified index of a `call_indirect`
+// expression.
+BINARYEN_API BinaryenExpressionRef BinaryenCallIndirectGetOperandAt(
+  BinaryenExpressionRef expr, BinaryenIndex index);
+// Sets the operand expression at the specified index of a `call_indirect`
+// expression.
+BINARYEN_API void
+BinaryenCallIndirectSetOperandAt(BinaryenExpressionRef expr,
+                                 BinaryenIndex index,
+                                 BinaryenExpressionRef operandExpr);
+// Appends an operand expression to a `call_indirect` expression, returning its
+// insertion index.
+BINARYEN_API BinaryenIndex BinaryenCallIndirectAppendOperand(
+  BinaryenExpressionRef expr, BinaryenExpressionRef operandExpr);
+// Inserts an operand expression at the specified index of a `call_indirect`
+// expression, moving existing operands including the one previously at that
+// index one index up.
+BINARYEN_API void
+BinaryenCallIndirectInsertOperandAt(BinaryenExpressionRef expr,
+                                    BinaryenIndex index,
+                                    BinaryenExpressionRef operandExpr);
+// Removes the operand expression at the specified index of a `call_indirect`
+// expression, moving all subsequent operands one index down. Returns the
+// operand expression.
+BINARYEN_API BinaryenExpressionRef BinaryenCallIndirectRemoveOperandAt(
+  BinaryenExpressionRef expr, BinaryenIndex index);
+// Gets whether the specified `call_indirect` expression is a tail call.
+BINARYEN_API int BinaryenCallIndirectIsReturn(BinaryenExpressionRef expr);
+// Sets whether the specified `call_indirect` expression is a tail call.
+BINARYEN_API void BinaryenCallIndirectSetReturn(BinaryenExpressionRef expr,
+                                                int isReturn);
+// Gets the parameter types of the specified `call_indirect` expression.
+BINARYEN_API BinaryenType
+BinaryenCallIndirectGetParams(BinaryenExpressionRef expr);
+// Sets the parameter types of the specified `call_indirect` expression.
+BINARYEN_API void BinaryenCallIndirectSetParams(BinaryenExpressionRef expr,
+                                                BinaryenType params);
+// Gets the result types of the specified `call_indirect` expression.
+BINARYEN_API BinaryenType
+BinaryenCallIndirectGetResults(BinaryenExpressionRef expr);
+// Sets the result types of the specified `call_indirect` expression.
+BINARYEN_API void BinaryenCallIndirectSetResults(BinaryenExpressionRef expr,
+                                                 BinaryenType params);
+
+// LocalGet
+
+// Gets the local index of a `local.get` expression.
+BINARYEN_API BinaryenIndex BinaryenLocalGetGetIndex(BinaryenExpressionRef expr);
+// Sets the local index of a `local.get` expression.
+BINARYEN_API void BinaryenLocalGetSetIndex(BinaryenExpressionRef expr,
+                                           BinaryenIndex index);
+
+// LocalSet
+
+// Gets whether a `local.set` tees its value (is a `local.tee`). True if the
+// expression has a type other than `none`.
+BINARYEN_API int BinaryenLocalSetIsTee(BinaryenExpressionRef expr);
+// Gets the local index of a `local.set` or `local.tee` expression.
+BINARYEN_API BinaryenIndex BinaryenLocalSetGetIndex(BinaryenExpressionRef expr);
+// Sets the local index of a `local.set` or `local.tee` expression.
+BINARYEN_API void BinaryenLocalSetSetIndex(BinaryenExpressionRef expr,
+                                           BinaryenIndex index);
+// Gets the value expression of a `local.set` or `local.tee` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenLocalSetGetValue(BinaryenExpressionRef expr);
+// Sets the value expression of a `local.set` or `local.tee` expression.
+BINARYEN_API void BinaryenLocalSetSetValue(BinaryenExpressionRef expr,
+                                           BinaryenExpressionRef valueExpr);
+
+// GlobalGet
+
+// Gets the name of the global being accessed by a `global.get` expression.
+BINARYEN_API const char* BinaryenGlobalGetGetName(BinaryenExpressionRef expr);
+// Sets the name of the global being accessed by a `global.get` expression.
+BINARYEN_API void BinaryenGlobalGetSetName(BinaryenExpressionRef expr,
+                                           const char* name);
+
+// GlobalSet
+
+// Gets the name of the global being accessed by a `global.set` expression.
+BINARYEN_API const char* BinaryenGlobalSetGetName(BinaryenExpressionRef expr);
+// Sets the name of the global being accessed by a `global.set` expression.
+BINARYEN_API void BinaryenGlobalSetSetName(BinaryenExpressionRef expr,
+                                           const char* name);
+// Gets the value expression of a `global.set` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenGlobalSetGetValue(BinaryenExpressionRef expr);
+// Sets the value expression of a `global.set` expression.
+BINARYEN_API void BinaryenGlobalSetSetValue(BinaryenExpressionRef expr,
+                                            BinaryenExpressionRef valueExpr);
+
+// MemoryGrow
+
+// Gets the delta of a `memory.grow` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenMemoryGrowGetDelta(BinaryenExpressionRef expr);
+// Sets the delta of a `memory.grow` expression.
+BINARYEN_API void BinaryenMemoryGrowSetDelta(BinaryenExpressionRef expr,
+                                             BinaryenExpressionRef delta);
+
+// Load
+
+// Gets whether a `load` expression is atomic (is an `atomic.load`).
+BINARYEN_API int BinaryenLoadIsAtomic(BinaryenExpressionRef expr);
+// Sets whether a `load` expression is atomic (is an `atomic.load`).
+BINARYEN_API void BinaryenLoadSetAtomic(BinaryenExpressionRef expr,
+                                        int isAtomic);
+// Gets whether a `load` expression operates on a signed value (`_s`).
+BINARYEN_API int BinaryenLoadIsSigned(BinaryenExpressionRef expr);
+// Sets whether a `load` expression operates on a signed value (`_s`).
+BINARYEN_API void BinaryenLoadSetSigned(BinaryenExpressionRef expr,
+                                        int isSigned);
+// Gets the constant offset of a `load` expression.
+BINARYEN_API uint32_t BinaryenLoadGetOffset(BinaryenExpressionRef expr);
+// Sets the constant offset of a `load` expression.
+BINARYEN_API void BinaryenLoadSetOffset(BinaryenExpressionRef expr,
+                                        uint32_t offset);
+// Gets the number of bytes loaded by a `load` expression.
+BINARYEN_API uint32_t BinaryenLoadGetBytes(BinaryenExpressionRef expr);
+// Sets the number of bytes loaded by a `load` expression.
+BINARYEN_API void BinaryenLoadSetBytes(BinaryenExpressionRef expr,
+                                       uint32_t bytes);
+// Gets the byte alignment of a `load` expression.
+BINARYEN_API uint32_t BinaryenLoadGetAlign(BinaryenExpressionRef expr);
+// Sets the byte alignment of a `load` expression.
+BINARYEN_API void BinaryenLoadSetAlign(BinaryenExpressionRef expr,
+                                       uint32_t align);
+// Gets the pointer expression of a `load` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenLoadGetPtr(BinaryenExpressionRef expr);
+// Sets the pointer expression of a `load` expression.
+BINARYEN_API void BinaryenLoadSetPtr(BinaryenExpressionRef expr,
+                                     BinaryenExpressionRef ptrExpr);
+
+// Store
+
+// Gets whether a `store` expression is atomic (is an `atomic.store`).
+BINARYEN_API int BinaryenStoreIsAtomic(BinaryenExpressionRef expr);
+// Sets whether a `store` expression is atomic (is an `atomic.store`).
+BINARYEN_API void BinaryenStoreSetAtomic(BinaryenExpressionRef expr,
+                                         int isAtomic);
+// Gets the number of bytes stored by a `store` expression.
+BINARYEN_API uint32_t BinaryenStoreGetBytes(BinaryenExpressionRef expr);
+// Sets the number of bytes stored by a `store` expression.
+BINARYEN_API void BinaryenStoreSetBytes(BinaryenExpressionRef expr,
+                                        uint32_t bytes);
+// Gets the constant offset of a `store` expression.
+BINARYEN_API uint32_t BinaryenStoreGetOffset(BinaryenExpressionRef expr);
+// Sets the constant offset of a `store` expression.
+BINARYEN_API void BinaryenStoreSetOffset(BinaryenExpressionRef expr,
+                                         uint32_t offset);
+// Gets the byte alignment of a `store` expression.
+BINARYEN_API uint32_t BinaryenStoreGetAlign(BinaryenExpressionRef expr);
+// Sets the byte alignment of a `store` expression.
+BINARYEN_API void BinaryenStoreSetAlign(BinaryenExpressionRef expr,
+                                        uint32_t align);
+// Gets the pointer expression of a `store` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenStoreGetPtr(BinaryenExpressionRef expr);
+// Sets the pointer expression of a `store` expression.
+BINARYEN_API void BinaryenStoreSetPtr(BinaryenExpressionRef expr,
+                                      BinaryenExpressionRef ptrExpr);
+// Gets the value expression of a `store` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenStoreGetValue(BinaryenExpressionRef expr);
+// Sets the value expression of a `store` expression.
+BINARYEN_API void BinaryenStoreSetValue(BinaryenExpressionRef expr,
+                                        BinaryenExpressionRef valueExpr);
+// Gets the value type of a `store` expression.
+BINARYEN_API BinaryenType BinaryenStoreGetValueType(BinaryenExpressionRef expr);
+// Sets the value type of a `store` expression.
+BINARYEN_API void BinaryenStoreSetValueType(BinaryenExpressionRef expr,
+                                            BinaryenType valueType);
+
+// Const
+
+// Gets the 32-bit integer value of an `i32.const` expression.
+BINARYEN_API int32_t BinaryenConstGetValueI32(BinaryenExpressionRef expr);
+// Sets the 32-bit integer value of an `i32.const` expression.
+BINARYEN_API void BinaryenConstSetValueI32(BinaryenExpressionRef expr,
+                                           int32_t value);
+// Gets the 64-bit integer value of an `i64.const` expression.
+BINARYEN_API int64_t BinaryenConstGetValueI64(BinaryenExpressionRef expr);
+// Sets the 64-bit integer value of an `i64.const` expression.
+BINARYEN_API void BinaryenConstSetValueI64(BinaryenExpressionRef expr,
+                                           int64_t value);
+// Gets the low 32-bits of the 64-bit integer value of an `i64.const`
+// expression.
+BINARYEN_API int32_t BinaryenConstGetValueI64Low(BinaryenExpressionRef expr);
+// Sets the low 32-bits of the 64-bit integer value of an `i64.const`
+// expression.
+BINARYEN_API void BinaryenConstSetValueI64Low(BinaryenExpressionRef expr,
+                                              int32_t valueLow);
+// Gets the high 32-bits of the 64-bit integer value of an `i64.const`
+// expression.
+BINARYEN_API int32_t BinaryenConstGetValueI64High(BinaryenExpressionRef expr);
+// Sets the high 32-bits of the 64-bit integer value of an `i64.const`
+// expression.
+BINARYEN_API void BinaryenConstSetValueI64High(BinaryenExpressionRef expr,
+                                               int32_t valueHigh);
+// Gets the 32-bit float value of a `f32.const` expression.
+BINARYEN_API float BinaryenConstGetValueF32(BinaryenExpressionRef expr);
+// Sets the 32-bit float value of a `f32.const` expression.
+BINARYEN_API void BinaryenConstSetValueF32(BinaryenExpressionRef expr,
+                                           float value);
+// Gets the 64-bit float (double) value of a `f64.const` expression.
+BINARYEN_API double BinaryenConstGetValueF64(BinaryenExpressionRef expr);
+// Sets the 64-bit float (double) value of a `f64.const` expression.
+BINARYEN_API void BinaryenConstSetValueF64(BinaryenExpressionRef expr,
+                                           double value);
+// Reads the 128-bit vector value of a `v128.const` expression.
+BINARYEN_API void BinaryenConstGetValueV128(BinaryenExpressionRef expr,
+                                            uint8_t* out);
+// Sets the 128-bit vector value of a `v128.const` expression.
+BINARYEN_API void BinaryenConstSetValueV128(BinaryenExpressionRef expr,
+                                            const uint8_t value[16]);
+
+// Unary
+
+// Gets the operation being performed by a unary expression.
+BINARYEN_API BinaryenOp BinaryenUnaryGetOp(BinaryenExpressionRef expr);
+// Sets the operation being performed by a unary expression.
+BINARYEN_API void BinaryenUnarySetOp(BinaryenExpressionRef expr, BinaryenOp op);
+// Gets the value expression of a unary expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenUnaryGetValue(BinaryenExpressionRef expr);
+// Sets the value expression of a unary expression.
+BINARYEN_API void BinaryenUnarySetValue(BinaryenExpressionRef expr,
+                                        BinaryenExpressionRef valueExpr);
+
+// Binary
+
+// Gets the operation being performed by a binary expression.
+BINARYEN_API BinaryenOp BinaryenBinaryGetOp(BinaryenExpressionRef expr);
+// Sets the operation being performed by a binary expression.
+BINARYEN_API void BinaryenBinarySetOp(BinaryenExpressionRef expr,
+                                      BinaryenOp op);
+// Gets the left expression of a binary expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenBinaryGetLeft(BinaryenExpressionRef expr);
+// Sets the left expression of a binary expression.
+BINARYEN_API void BinaryenBinarySetLeft(BinaryenExpressionRef expr,
+                                        BinaryenExpressionRef leftExpr);
+// Gets the right expression of a binary expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenBinaryGetRight(BinaryenExpressionRef expr);
+// Sets the right expression of a binary expression.
+BINARYEN_API void BinaryenBinarySetRight(BinaryenExpressionRef expr,
+                                         BinaryenExpressionRef rightExpr);
+
+// Select
+
+// Gets the expression becoming selected by a `select` expression if the
+// condition turns out true.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSelectGetIfTrue(BinaryenExpressionRef expr);
+// Sets the expression becoming selected by a `select` expression if the
+// condition turns out true.
+BINARYEN_API void BinaryenSelectSetIfTrue(BinaryenExpressionRef expr,
+                                          BinaryenExpressionRef ifTrueExpr);
+// Gets the expression becoming selected by a `select` expression if the
+// condition turns out false.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSelectGetIfFalse(BinaryenExpressionRef expr);
+// Sets the expression becoming selected by a `select` expression if the
+// condition turns out false.
+BINARYEN_API void BinaryenSelectSetIfFalse(BinaryenExpressionRef expr,
+                                           BinaryenExpressionRef ifFalseExpr);
+// Gets the condition expression of a `select` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSelectGetCondition(BinaryenExpressionRef expr);
+// Sets the condition expression of a `select` expression.
+BINARYEN_API void BinaryenSelectSetCondition(BinaryenExpressionRef expr,
+                                             BinaryenExpressionRef condExpr);
+
+// Drop
+
+// Gets the value expression being dropped by a `drop` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenDropGetValue(BinaryenExpressionRef expr);
+// Sets the value expression being dropped by a `drop` expression.
+BINARYEN_API void BinaryenDropSetValue(BinaryenExpressionRef expr,
+                                       BinaryenExpressionRef valueExpr);
+
+// Return
+
+// Gets the value expression, if any, being returned by a `return` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenReturnGetValue(BinaryenExpressionRef expr);
+// Sets the value expression, if any, being returned by a `return` expression.
+BINARYEN_API void BinaryenReturnSetValue(BinaryenExpressionRef expr,
+                                         BinaryenExpressionRef valueExpr);
+
+// AtomicRMW
+
+// Gets the operation being performed by an atomic read-modify-write expression.
+BINARYEN_API BinaryenOp BinaryenAtomicRMWGetOp(BinaryenExpressionRef expr);
+// Sets the operation being performed by an atomic read-modify-write expression.
+BINARYEN_API void BinaryenAtomicRMWSetOp(BinaryenExpressionRef expr,
+                                         BinaryenOp op);
+// Gets the number of bytes affected by an atomic read-modify-write expression.
+BINARYEN_API uint32_t BinaryenAtomicRMWGetBytes(BinaryenExpressionRef expr);
+// Sets the number of bytes affected by an atomic read-modify-write expression.
+BINARYEN_API void BinaryenAtomicRMWSetBytes(BinaryenExpressionRef expr,
+                                            uint32_t bytes);
+// Gets the constant offset of an atomic read-modify-write expression.
+BINARYEN_API uint32_t BinaryenAtomicRMWGetOffset(BinaryenExpressionRef expr);
+// Sets the constant offset of an atomic read-modify-write expression.
+BINARYEN_API void BinaryenAtomicRMWSetOffset(BinaryenExpressionRef expr,
+                                             uint32_t offset);
+// Gets the pointer expression of an atomic read-modify-write expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicRMWGetPtr(BinaryenExpressionRef expr);
+// Sets the pointer expression of an atomic read-modify-write expression.
+BINARYEN_API void BinaryenAtomicRMWSetPtr(BinaryenExpressionRef expr,
+                                          BinaryenExpressionRef ptrExpr);
+// Gets the value expression of an atomic read-modify-write expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicRMWGetValue(BinaryenExpressionRef expr);
+// Sets the value expression of an atomic read-modify-write expression.
+BINARYEN_API void BinaryenAtomicRMWSetValue(BinaryenExpressionRef expr,
+                                            BinaryenExpressionRef valueExpr);
+
+// AtomicCmpxchg
+
+// Gets the number of bytes affected by an atomic compare and exchange
+// expression.
+BINARYEN_API uint32_t BinaryenAtomicCmpxchgGetBytes(BinaryenExpressionRef expr);
+// Sets the number of bytes affected by an atomic compare and exchange
+// expression.
+BINARYEN_API void BinaryenAtomicCmpxchgSetBytes(BinaryenExpressionRef expr,
+                                                uint32_t bytes);
+// Gets the constant offset of an atomic compare and exchange expression.
+BINARYEN_API uint32_t
+BinaryenAtomicCmpxchgGetOffset(BinaryenExpressionRef expr);
+// Sets the constant offset of an atomic compare and exchange expression.
+BINARYEN_API void BinaryenAtomicCmpxchgSetOffset(BinaryenExpressionRef expr,
+                                                 uint32_t offset);
+// Gets the pointer expression of an atomic compare and exchange expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicCmpxchgGetPtr(BinaryenExpressionRef expr);
+// Sets the pointer expression of an atomic compare and exchange expression.
+BINARYEN_API void BinaryenAtomicCmpxchgSetPtr(BinaryenExpressionRef expr,
+                                              BinaryenExpressionRef ptrExpr);
+// Gets the expression representing the expected value of an atomic compare and
+// exchange expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicCmpxchgGetExpected(BinaryenExpressionRef expr);
+// Sets the expression representing the expected value of an atomic compare and
+// exchange expression.
+BINARYEN_API void
+BinaryenAtomicCmpxchgSetExpected(BinaryenExpressionRef expr,
+                                 BinaryenExpressionRef expectedExpr);
+// Gets the replacement expression of an atomic compare and exchange expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicCmpxchgGetReplacement(BinaryenExpressionRef expr);
+// Sets the replacement expression of an atomic compare and exchange expression.
+BINARYEN_API void
+BinaryenAtomicCmpxchgSetReplacement(BinaryenExpressionRef expr,
+                                    BinaryenExpressionRef replacementExpr);
+
+// AtomicWait
+
+// Gets the pointer expression of an `atomic.wait` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicWaitGetPtr(BinaryenExpressionRef expr);
+// Sets the pointer expression of an `atomic.wait` expression.
+BINARYEN_API void BinaryenAtomicWaitSetPtr(BinaryenExpressionRef expr,
+                                           BinaryenExpressionRef ptrExpr);
+// Gets the expression representing the expected value of an `atomic.wait`
+// expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicWaitGetExpected(BinaryenExpressionRef expr);
+// Sets the expression representing the expected value of an `atomic.wait`
+// expression.
+BINARYEN_API void
+BinaryenAtomicWaitSetExpected(BinaryenExpressionRef expr,
+                              BinaryenExpressionRef expectedExpr);
+// Gets the timeout expression of an `atomic.wait` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicWaitGetTimeout(BinaryenExpressionRef expr);
+// Sets the timeout expression of an `atomic.wait` expression.
+BINARYEN_API void
+BinaryenAtomicWaitSetTimeout(BinaryenExpressionRef expr,
+                             BinaryenExpressionRef timeoutExpr);
+// Gets the expected type of an `atomic.wait` expression.
+BINARYEN_API BinaryenType
+BinaryenAtomicWaitGetExpectedType(BinaryenExpressionRef expr);
+// Sets the expected type of an `atomic.wait` expression.
+BINARYEN_API void BinaryenAtomicWaitSetExpectedType(BinaryenExpressionRef expr,
+                                                    BinaryenType expectedType);
+
+// AtomicNotify
+
+// Gets the pointer expression of an `atomic.notify` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicNotifyGetPtr(BinaryenExpressionRef expr);
+// Sets the pointer expression of an `atomic.notify` expression.
+BINARYEN_API void BinaryenAtomicNotifySetPtr(BinaryenExpressionRef expr,
+                                             BinaryenExpressionRef ptrExpr);
+// Gets the notify count expression of an `atomic.notify` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenAtomicNotifyGetNotifyCount(BinaryenExpressionRef expr);
+// Sets the notify count expression of an `atomic.notify` expression.
+BINARYEN_API void
+BinaryenAtomicNotifySetNotifyCount(BinaryenExpressionRef expr,
+                                   BinaryenExpressionRef notifyCountExpr);
+
+// AtomicFence
+
+// Gets the order of an `atomic.fence` expression.
+BINARYEN_API uint8_t BinaryenAtomicFenceGetOrder(BinaryenExpressionRef expr);
+// Sets the order of an `atomic.fence` expression.
+BINARYEN_API void BinaryenAtomicFenceSetOrder(BinaryenExpressionRef expr,
+                                              uint8_t order);
+
+// SIMDExtract
+
+// Gets the operation being performed by a SIMD extract expression.
+BINARYEN_API BinaryenOp BinaryenSIMDExtractGetOp(BinaryenExpressionRef expr);
+// Sets the operation being performed by a SIMD extract expression.
+BINARYEN_API void BinaryenSIMDExtractSetOp(BinaryenExpressionRef expr,
+                                           BinaryenOp op);
+// Gets the vector expression a SIMD extract expression extracts from.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDExtractGetVec(BinaryenExpressionRef expr);
+// Sets the vector expression a SIMD extract expression extracts from.
+BINARYEN_API void BinaryenSIMDExtractSetVec(BinaryenExpressionRef expr,
+                                            BinaryenExpressionRef vecExpr);
+// Gets the index of the extracted lane of a SIMD extract expression.
+BINARYEN_API uint8_t BinaryenSIMDExtractGetIndex(BinaryenExpressionRef expr);
+// Sets the index of the extracted lane of a SIMD extract expression.
+BINARYEN_API void BinaryenSIMDExtractSetIndex(BinaryenExpressionRef expr,
+                                              uint8_t index);
+
+// SIMDReplace
+
+// Gets the operation being performed by a SIMD replace expression.
+BINARYEN_API BinaryenOp BinaryenSIMDReplaceGetOp(BinaryenExpressionRef expr);
+// Sets the operation being performed by a SIMD replace expression.
+BINARYEN_API void BinaryenSIMDReplaceSetOp(BinaryenExpressionRef expr,
+                                           BinaryenOp op);
+// Gets the vector expression a SIMD replace expression replaces in.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDReplaceGetVec(BinaryenExpressionRef expr);
+// Sets the vector expression a SIMD replace expression replaces in.
+BINARYEN_API void BinaryenSIMDReplaceSetVec(BinaryenExpressionRef expr,
+                                            BinaryenExpressionRef vecExpr);
+// Gets the index of the replaced lane of a SIMD replace expression.
+BINARYEN_API uint8_t BinaryenSIMDReplaceGetIndex(BinaryenExpressionRef expr);
+// Sets the index of the replaced lane of a SIMD replace expression.
+BINARYEN_API void BinaryenSIMDReplaceSetIndex(BinaryenExpressionRef expr,
+                                              uint8_t index);
+// Gets the value expression a SIMD replace expression replaces with.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDReplaceGetValue(BinaryenExpressionRef expr);
+// Sets the value expression a SIMD replace expression replaces with.
+BINARYEN_API void BinaryenSIMDReplaceSetValue(BinaryenExpressionRef expr,
+                                              BinaryenExpressionRef valueExpr);
+
+// SIMDShuffle
+
+// Gets the left expression of a SIMD shuffle expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDShuffleGetLeft(BinaryenExpressionRef expr);
+// Sets the left expression of a SIMD shuffle expression.
+BINARYEN_API void BinaryenSIMDShuffleSetLeft(BinaryenExpressionRef expr,
+                                             BinaryenExpressionRef leftExpr);
+// Gets the right expression of a SIMD shuffle expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDShuffleGetRight(BinaryenExpressionRef expr);
+// Sets the right expression of a SIMD shuffle expression.
+BINARYEN_API void BinaryenSIMDShuffleSetRight(BinaryenExpressionRef expr,
+                                              BinaryenExpressionRef rightExpr);
+// Gets the 128-bit mask of a SIMD shuffle expression.
+BINARYEN_API void BinaryenSIMDShuffleGetMask(BinaryenExpressionRef expr,
+                                             uint8_t* mask);
+// Sets the 128-bit mask of a SIMD shuffle expression.
+BINARYEN_API void BinaryenSIMDShuffleSetMask(BinaryenExpressionRef expr,
+                                             const uint8_t mask[16]);
+
+// SIMDTernary
+
+// Gets the operation being performed by a SIMD ternary expression.
+BINARYEN_API BinaryenOp BinaryenSIMDTernaryGetOp(BinaryenExpressionRef expr);
+// Sets the operation being performed by a SIMD ternary expression.
+BINARYEN_API void BinaryenSIMDTernarySetOp(BinaryenExpressionRef expr,
+                                           BinaryenOp op);
+// Gets the first operand expression of a SIMD ternary expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDTernaryGetA(BinaryenExpressionRef expr);
+// Sets the first operand expression of a SIMD ternary expression.
+BINARYEN_API void BinaryenSIMDTernarySetA(BinaryenExpressionRef expr,
+                                          BinaryenExpressionRef aExpr);
+// Gets the second operand expression of a SIMD ternary expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDTernaryGetB(BinaryenExpressionRef expr);
+// Sets the second operand expression of a SIMD ternary expression.
+BINARYEN_API void BinaryenSIMDTernarySetB(BinaryenExpressionRef expr,
+                                          BinaryenExpressionRef bExpr);
+// Gets the third operand expression of a SIMD ternary expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDTernaryGetC(BinaryenExpressionRef expr);
+// Sets the third operand expression of a SIMD ternary expression.
+BINARYEN_API void BinaryenSIMDTernarySetC(BinaryenExpressionRef expr,
+                                          BinaryenExpressionRef cExpr);
+
+// SIMDShift
+
+// Gets the operation being performed by a SIMD shift expression.
+BINARYEN_API BinaryenOp BinaryenSIMDShiftGetOp(BinaryenExpressionRef expr);
+// Sets the operation being performed by a SIMD shift expression.
+BINARYEN_API void BinaryenSIMDShiftSetOp(BinaryenExpressionRef expr,
+                                         BinaryenOp op);
+// Gets the expression being shifted by a SIMD shift expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDShiftGetVec(BinaryenExpressionRef expr);
+// Sets the expression being shifted by a SIMD shift expression.
+BINARYEN_API void BinaryenSIMDShiftSetVec(BinaryenExpressionRef expr,
+                                          BinaryenExpressionRef vecExpr);
+// Gets the expression representing the shift of a SIMD shift expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDShiftGetShift(BinaryenExpressionRef expr);
+// Sets the expression representing the shift of a SIMD shift expression.
+BINARYEN_API void BinaryenSIMDShiftSetShift(BinaryenExpressionRef expr,
+                                            BinaryenExpressionRef shiftExpr);
+
+// SIMDLoad
+
+// Gets the operation being performed by a SIMD load expression.
+BINARYEN_API BinaryenOp BinaryenSIMDLoadGetOp(BinaryenExpressionRef expr);
+// Sets the operation being performed by a SIMD load expression.
+BINARYEN_API void BinaryenSIMDLoadSetOp(BinaryenExpressionRef expr,
+                                        BinaryenOp op);
+// Gets the constant offset of a SIMD load expression.
+BINARYEN_API uint32_t BinaryenSIMDLoadGetOffset(BinaryenExpressionRef expr);
+// Sets the constant offset of a SIMD load expression.
+BINARYEN_API void BinaryenSIMDLoadSetOffset(BinaryenExpressionRef expr,
+                                            uint32_t offset);
+// Gets the byte alignment of a SIMD load expression.
+BINARYEN_API uint32_t BinaryenSIMDLoadGetAlign(BinaryenExpressionRef expr);
+// Sets the byte alignment of a SIMD load expression.
+BINARYEN_API void BinaryenSIMDLoadSetAlign(BinaryenExpressionRef expr,
+                                           uint32_t align);
+// Gets the pointer expression of a SIMD load expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenSIMDLoadGetPtr(BinaryenExpressionRef expr);
+// Sets the pointer expression of a SIMD load expression.
+BINARYEN_API void BinaryenSIMDLoadSetPtr(BinaryenExpressionRef expr,
+                                         BinaryenExpressionRef ptrExpr);
+
+// MemoryInit
+
+// Gets the index of the segment being initialized by a `memory.init`
+// expression.
+BINARYEN_API uint32_t BinaryenMemoryInitGetSegment(BinaryenExpressionRef expr);
+// Sets the index of the segment being initialized by a `memory.init`
+// expression.
+BINARYEN_API void BinaryenMemoryInitSetSegment(BinaryenExpressionRef expr,
+                                               uint32_t segmentIndex);
+// Gets the destination expression of a `memory.init` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenMemoryInitGetDest(BinaryenExpressionRef expr);
+// Sets the destination expression of a `memory.init` expression.
+BINARYEN_API void BinaryenMemoryInitSetDest(BinaryenExpressionRef expr,
+                                            BinaryenExpressionRef destExpr);
+// Gets the offset expression of a `memory.init` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenMemoryInitGetOffset(BinaryenExpressionRef expr);
+// Sets the offset expression of a `memory.init` expression.
+BINARYEN_API void BinaryenMemoryInitSetOffset(BinaryenExpressionRef expr,
+                                              BinaryenExpressionRef offsetExpr);
+// Gets the size expression of a `memory.init` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenMemoryInitGetSize(BinaryenExpressionRef expr);
+// Sets the size expression of a `memory.init` expression.
+BINARYEN_API void BinaryenMemoryInitSetSize(BinaryenExpressionRef expr,
+                                            BinaryenExpressionRef sizeExpr);
+
+// DataDrop
+
+// Gets the index of the segment being dropped by a `memory.drop` expression.
+BINARYEN_API uint32_t BinaryenDataDropGetSegment(BinaryenExpressionRef expr);
+// Sets the index of the segment being dropped by a `memory.drop` expression.
+BINARYEN_API void BinaryenDataDropSetSegment(BinaryenExpressionRef expr,
+                                             uint32_t segmentIndex);
+
+// MemoryCopy
+
+// Gets the destination expression of a `memory.copy` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenMemoryCopyGetDest(BinaryenExpressionRef expr);
+// Sets the destination expression of a `memory.copy` expression.
+BINARYEN_API void BinaryenMemoryCopySetDest(BinaryenExpressionRef expr,
+                                            BinaryenExpressionRef destExpr);
+// Gets the source expression of a `memory.copy` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenMemoryCopyGetSource(BinaryenExpressionRef expr);
+// Sets the source expression of a `memory.copy` expression.
+BINARYEN_API void BinaryenMemoryCopySetSource(BinaryenExpressionRef expr,
+                                              BinaryenExpressionRef sourceExpr);
+// Gets the size expression (number of bytes copied) of a `memory.copy`
+// expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenMemoryCopyGetSize(BinaryenExpressionRef expr);
+// Sets the size expression (number of bytes copied) of a `memory.copy`
+// expression.
+BINARYEN_API void BinaryenMemoryCopySetSize(BinaryenExpressionRef expr,
+                                            BinaryenExpressionRef sizeExpr);
+
+// MemoryFill
+
+// Gets the destination expression of a `memory.fill` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenMemoryFillGetDest(BinaryenExpressionRef expr);
+// Sets the destination expression of a `memory.fill` expression.
+BINARYEN_API void BinaryenMemoryFillSetDest(BinaryenExpressionRef expr,
+                                            BinaryenExpressionRef destExpr);
+// Gets the value expression of a `memory.fill` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenMemoryFillGetValue(BinaryenExpressionRef expr);
+// Sets the value expression of a `memory.fill` expression.
+BINARYEN_API void BinaryenMemoryFillSetValue(BinaryenExpressionRef expr,
+                                             BinaryenExpressionRef valueExpr);
+// Gets the size expression (number of bytes filled) of a `memory.fill`
+// expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenMemoryFillGetSize(BinaryenExpressionRef expr);
+// Sets the size expression (number of bytes filled) of a `memory.fill`
+// expression.
+BINARYEN_API void BinaryenMemoryFillSetSize(BinaryenExpressionRef expr,
+                                            BinaryenExpressionRef sizeExpr);
+
+// RefIsNull
+
+// Gets the value expression tested to be null of a `ref.is_null` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenRefIsNullGetValue(BinaryenExpressionRef expr);
+// Sets the value expression tested to be null of a `ref.is_null` expression.
+BINARYEN_API void BinaryenRefIsNullSetValue(BinaryenExpressionRef expr,
+                                            BinaryenExpressionRef valueExpr);
+
+// RefFunc
+
+// Gets the name of the function being wrapped by a `ref.func` expression.
+BINARYEN_API const char* BinaryenRefFuncGetFunc(BinaryenExpressionRef expr);
+// Sets the name of the function being wrapped by a `ref.func` expression.
+BINARYEN_API void BinaryenRefFuncSetFunc(BinaryenExpressionRef expr,
+                                         const char* funcName);
+
+// RefEq
+
+// Gets the left expression of a `ref.eq` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenRefEqGetLeft(BinaryenExpressionRef expr);
+// Sets the left expression of a `ref.eq` expression.
+BINARYEN_API void BinaryenRefEqSetLeft(BinaryenExpressionRef expr,
+                                       BinaryenExpressionRef left);
+// Gets the right expression of a `ref.eq` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenRefEqGetRight(BinaryenExpressionRef expr);
+// Sets the right expression of a `ref.eq` expression.
+BINARYEN_API void BinaryenRefEqSetRight(BinaryenExpressionRef expr,
+                                        BinaryenExpressionRef right);
+
+// Try
+
+// Gets the body expression of a `try` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenTryGetBody(BinaryenExpressionRef expr);
+// Sets the body expression of a `try` expression.
+BINARYEN_API void BinaryenTrySetBody(BinaryenExpressionRef expr,
+                                     BinaryenExpressionRef bodyExpr);
+// Gets the catch body expression of a `try` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenTryGetCatchBody(BinaryenExpressionRef expr);
+// Sets the catch body expression of a `try` expression.
+BINARYEN_API void BinaryenTrySetCatchBody(BinaryenExpressionRef expr,
+                                          BinaryenExpressionRef catchBodyExpr);
+
+// Throw
+
+// Gets the name of the event being thrown by a `throw` expression.
+BINARYEN_API const char* BinaryenThrowGetEvent(BinaryenExpressionRef expr);
+// Sets the name of the event being thrown by a `throw` expression.
+BINARYEN_API void BinaryenThrowSetEvent(BinaryenExpressionRef expr,
+                                        const char* eventName);
+// Gets the number of operands of a `throw` expression.
+BINARYEN_API BinaryenIndex
+BinaryenThrowGetNumOperands(BinaryenExpressionRef expr);
+// Gets the operand at the specified index of a `throw` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenThrowGetOperandAt(BinaryenExpressionRef expr, BinaryenIndex index);
+// Sets the operand at the specified index of a `throw` expression.
+BINARYEN_API void BinaryenThrowSetOperandAt(BinaryenExpressionRef expr,
+                                            BinaryenIndex index,
+                                            BinaryenExpressionRef operandExpr);
+// Appends an operand expression to a `throw` expression, returning its
+// insertion index.
+BINARYEN_API BinaryenIndex BinaryenThrowAppendOperand(
+  BinaryenExpressionRef expr, BinaryenExpressionRef operandExpr);
+// Inserts an operand expression at the specified index of a `throw` expression,
+// moving existing operands including the one previously at that index one index
+// up.
+BINARYEN_API void
+BinaryenThrowInsertOperandAt(BinaryenExpressionRef expr,
+                             BinaryenIndex index,
+                             BinaryenExpressionRef operandExpr);
+// Removes the operand expression at the specified index of a `throw`
+// expression, moving all subsequent operands one index down. Returns the
+// operand expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenThrowRemoveOperandAt(BinaryenExpressionRef expr, BinaryenIndex index);
+
+// Rethrow
+
+// Gets the exception reference expression of a `rethrow` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenRethrowGetExnref(BinaryenExpressionRef expr);
+// Sets the exception reference expression of a `rethrow` expression.
+BINARYEN_API void BinaryenRethrowSetExnref(BinaryenExpressionRef expr,
+                                           BinaryenExpressionRef exnrefExpr);
+
+// BrOnExn
+
+// Gets the name of the event triggering a `br_on_exn` expression.
+BINARYEN_API const char* BinaryenBrOnExnGetEvent(BinaryenExpressionRef expr);
+// Sets the name of the event triggering a `br_on_exn` expression.
+BINARYEN_API void BinaryenBrOnExnSetEvent(BinaryenExpressionRef expr,
+                                          const char* eventName);
+// Gets the name (target label) of a `br_on_exn` expression.
+BINARYEN_API const char* BinaryenBrOnExnGetName(BinaryenExpressionRef expr);
+// Sets the name (target label) of a `br_on_exn` expression.
+BINARYEN_API void BinaryenBrOnExnSetName(BinaryenExpressionRef expr,
+                                         const char* name);
+// Gets the expression reference expression of a `br_on_exn` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenBrOnExnGetExnref(BinaryenExpressionRef expr);
+// Sets the expression reference expression of a `br_on_exn` expression.
+BINARYEN_API void BinaryenBrOnExnSetExnref(BinaryenExpressionRef expr,
+                                           BinaryenExpressionRef exnrefExpr);
+
+// TupleMake
+
+// Gets the number of operands of a `tuple.make` expression.
+BINARYEN_API BinaryenIndex
+BinaryenTupleMakeGetNumOperands(BinaryenExpressionRef expr);
+// Gets the operand at the specified index of a `tuple.make` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenTupleMakeGetOperandAt(BinaryenExpressionRef expr, BinaryenIndex index);
+// Sets the operand at the specified index of a `tuple.make` expression.
+BINARYEN_API void
+BinaryenTupleMakeSetOperandAt(BinaryenExpressionRef expr,
+                              BinaryenIndex index,
+                              BinaryenExpressionRef operandExpr);
+// Appends an operand expression to a `tuple.make` expression, returning its
+// insertion index.
+BINARYEN_API BinaryenIndex BinaryenTupleMakeAppendOperand(
+  BinaryenExpressionRef expr, BinaryenExpressionRef operandExpr);
+// Inserts an operand expression at the specified index of a `tuple.make`
+// expression, moving existing operands including the one previously at that
+// index one index up.
+BINARYEN_API void
+BinaryenTupleMakeInsertOperandAt(BinaryenExpressionRef expr,
+                                 BinaryenIndex index,
+                                 BinaryenExpressionRef operandExpr);
+// Removes the operand expression at the specified index of a `tuple.make`
+// expression, moving all subsequent operands one index down. Returns the
+// operand expression.
+BINARYEN_API BinaryenExpressionRef BinaryenTupleMakeRemoveOperandAt(
+  BinaryenExpressionRef expr, BinaryenIndex index);
+
+// TupleExtract
+
+// Gets the tuple extracted from of a `tuple.extract` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenTupleExtractGetTuple(BinaryenExpressionRef expr);
+// Sets the tuple extracted from of a `tuple.extract` expression.
+BINARYEN_API void BinaryenTupleExtractSetTuple(BinaryenExpressionRef expr,
+                                               BinaryenExpressionRef tupleExpr);
+// Gets the index extracted at of a `tuple.extract` expression.
+BINARYEN_API BinaryenIndex
+BinaryenTupleExtractGetIndex(BinaryenExpressionRef expr);
+// Sets the index extracted at of a `tuple.extract` expression.
+BINARYEN_API void BinaryenTupleExtractSetIndex(BinaryenExpressionRef expr,
+                                               BinaryenIndex index);
+
+// I31New
+
+// Gets the value expression of an `i31.new` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenI31NewGetValue(BinaryenExpressionRef expr);
+// Sets the value expression of an `i31.new` expression.
+BINARYEN_API void BinaryenI31NewSetValue(BinaryenExpressionRef expr,
+                                         BinaryenExpressionRef valueExpr);
+
+// I31Get
+
+// Gets the i31 expression of an `i31.get` expression.
+BINARYEN_API BinaryenExpressionRef
+BinaryenI31GetGetI31(BinaryenExpressionRef expr);
+// Sets the i31 expression of an `i31.get` expression.
+BINARYEN_API void BinaryenI31GetSetI31(BinaryenExpressionRef expr,
+                                       BinaryenExpressionRef i31Expr);
+// Gets whether an `i31.get` expression returns a signed value (`_s`).
+BINARYEN_API int BinaryenI31GetIsSigned(BinaryenExpressionRef expr);
+// Sets whether an `i31.get` expression returns a signed value (`_s`).
+BINARYEN_API void BinaryenI31GetSetSigned(BinaryenExpressionRef expr,
+                                          int signed_);
+
+// Functions
+
+BINARYEN_REF(Function);
+
+// Adds a function to the module. This is thread-safe.
+// @varTypes: the types of variables. In WebAssembly, vars share
+//            an index space with params. In other words, params come from
+//            the function type, and vars are provided in this call, and
+//            together they are all the locals. The order is first params
+//            and then vars, so if you have one param it will be at index
+//            0 (and written $0), and if you also have 2 vars they will be
+//            at indexes 1 and 2, etc., that is, they share an index space.
+BINARYEN_API BinaryenFunctionRef
+BinaryenAddFunction(BinaryenModuleRef module,
+                    const char* name,
+                    BinaryenType params,
+                    BinaryenType results,
+                    BinaryenType* varTypes,
+                    BinaryenIndex numVarTypes,
+                    BinaryenExpressionRef body);
+// Gets a function reference by name.
+BINARYEN_API BinaryenFunctionRef BinaryenGetFunction(BinaryenModuleRef module,
+                                                     const char* name);
+// Removes a function by name.
+BINARYEN_API void BinaryenRemoveFunction(BinaryenModuleRef module,
+                                         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 BinaryenFunctionRef
+BinaryenGetFunctionByIndex(BinaryenModuleRef module, BinaryenIndex id);
+
+// Imports
+
+BINARYEN_API void BinaryenAddFunctionImport(BinaryenModuleRef module,
+                                            const char* internalName,
+                                            const char* externalModuleName,
+                                            const char* externalBaseName,
+                                            BinaryenType params,
+                                            BinaryenType results);
+BINARYEN_API void BinaryenAddTableImport(BinaryenModuleRef module,
+                                         const char* internalName,
+                                         const char* externalModuleName,
+                                         const char* externalBaseName);
+BINARYEN_API void BinaryenAddMemoryImport(BinaryenModuleRef module,
+                                          const char* internalName,
+                                          const char* externalModuleName,
+                                          const char* externalBaseName,
+                                          uint8_t shared);
+BINARYEN_API void BinaryenAddGlobalImport(BinaryenModuleRef module,
+                                          const char* internalName,
+                                          const char* externalModuleName,
+                                          const char* externalBaseName,
+                                          BinaryenType globalType,
+                                          int mutable_);
+BINARYEN_API void BinaryenAddEventImport(BinaryenModuleRef module,
+                                         const char* internalName,
+                                         const char* externalModuleName,
+                                         const char* externalBaseName,
+                                         uint32_t attribute,
+                                         BinaryenType params,
+                                         BinaryenType results);
+
+// Exports
+
+BINARYEN_REF(Export);
+
+WASM_DEPRECATED BinaryenExportRef BinaryenAddExport(BinaryenModuleRef module,
+                                                    const char* internalName,
+                                                    const char* externalName);
+BINARYEN_API BinaryenExportRef BinaryenAddFunctionExport(
+  BinaryenModuleRef module, const char* internalName, const char* externalName);
+BINARYEN_API BinaryenExportRef BinaryenAddTableExport(BinaryenModuleRef module,
+                                                      const char* internalName,
+                                                      const char* externalName);
+BINARYEN_API BinaryenExportRef BinaryenAddMemoryExport(
+  BinaryenModuleRef module, const char* internalName, const char* externalName);
+BINARYEN_API BinaryenExportRef BinaryenAddGlobalExport(
+  BinaryenModuleRef module, const char* internalName, const char* externalName);
+BINARYEN_API BinaryenExportRef BinaryenAddEventExport(BinaryenModuleRef module,
+                                                      const char* internalName,
+                                                      const char* externalName);
+BINARYEN_API void BinaryenRemoveExport(BinaryenModuleRef module,
+                                       const char* externalName);
+
+// Globals
+
+BINARYEN_REF(Global);
+
+BINARYEN_API BinaryenGlobalRef BinaryenAddGlobal(BinaryenModuleRef module,
+                                                 const char* name,
+                                                 BinaryenType type,
+                                                 int8_t mutable_,
+                                                 BinaryenExpressionRef init);
+// Gets a global reference by name.
+BINARYEN_API BinaryenGlobalRef BinaryenGetGlobal(BinaryenModuleRef module,
+                                                 const char* name);
+BINARYEN_API void BinaryenRemoveGlobal(BinaryenModuleRef module,
+                                       const char* name);
+
+// Events
+
+BINARYEN_REF(Event);
+
+BINARYEN_API BinaryenEventRef BinaryenAddEvent(BinaryenModuleRef module,
+                                               const char* name,
+                                               uint32_t attribute,
+                                               BinaryenType params,
+                                               BinaryenType results);
+BINARYEN_API BinaryenEventRef BinaryenGetEvent(BinaryenModuleRef module,
+                                               const char* name);
+BINARYEN_API void BinaryenRemoveEvent(BinaryenModuleRef module,
+                                      const char* name);
+
+// Function table. One per module
+
+// TODO: Add support for multiple segments in BinaryenSetFunctionTable.
+BINARYEN_API void BinaryenSetFunctionTable(BinaryenModuleRef module,
+                                           BinaryenIndex initial,
+                                           BinaryenIndex maximum,
+                                           const char** funcNames,
+                                           BinaryenIndex numFuncNames,
+                                           BinaryenExpressionRef offset);
+BINARYEN_API int BinaryenIsFunctionTableImported(BinaryenModuleRef module);
+BINARYEN_API BinaryenIndex
+BinaryenGetNumFunctionTableSegments(BinaryenModuleRef module);
+BINARYEN_API BinaryenExpressionRef BinaryenGetFunctionTableSegmentOffset(
+  BinaryenModuleRef module, BinaryenIndex segmentId);
+BINARYEN_API BinaryenIndex BinaryenGetFunctionTableSegmentLength(
+  BinaryenModuleRef module, BinaryenIndex segmentId);
+BINARYEN_API const char* BinaryenGetFunctionTableSegmentData(
+  BinaryenModuleRef module, BinaryenIndex segmentId, BinaryenIndex dataId);
+
+// Memory. One per module
+
+// Each segment has data in segments, a start offset in segmentOffsets, and a
+// size in segmentSizes. exportName can be NULL
+BINARYEN_API void BinaryenSetMemory(BinaryenModuleRef module,
+                                    BinaryenIndex initial,
+                                    BinaryenIndex maximum,
+                                    const char* exportName,
+                                    const char** segments,
+                                    int8_t* segmentPassive,
+                                    BinaryenExpressionRef* segmentOffsets,
+                                    BinaryenIndex* segmentSizes,
+                                    BinaryenIndex numSegments,
+                                    uint8_t shared);
+
+// Memory segments. Query utilities.
+
+BINARYEN_API uint32_t BinaryenGetNumMemorySegments(BinaryenModuleRef module);
+BINARYEN_API uint32_t
+BinaryenGetMemorySegmentByteOffset(BinaryenModuleRef module, BinaryenIndex id);
+BINARYEN_API size_t BinaryenGetMemorySegmentByteLength(BinaryenModuleRef module,
+                                                       BinaryenIndex id);
+BINARYEN_API int BinaryenGetMemorySegmentPassive(BinaryenModuleRef module,
+                                                 BinaryenIndex id);
+BINARYEN_API void BinaryenCopyMemorySegmentData(BinaryenModuleRef module,
+                                                BinaryenIndex id,
+                                                char* buffer);
+
+// Start function. One per module
+
+BINARYEN_API void BinaryenSetStart(BinaryenModuleRef module,
+                                   BinaryenFunctionRef start);
+
+// Features
+
+// These control what features are allowed when validation and in passes.
+BINARYEN_API BinaryenFeatures
+BinaryenModuleGetFeatures(BinaryenModuleRef module);
+BINARYEN_API void BinaryenModuleSetFeatures(BinaryenModuleRef module,
+                                            BinaryenFeatures features);
+
+//
+// ========== Module Operations ==========
+//
+
+// Parse a module in s-expression text format
+BINARYEN_API BinaryenModuleRef BinaryenModuleParse(const char* text);
+
+// Print a module to stdout in s-expression text format. Useful for debugging.
+BINARYEN_API void BinaryenModulePrint(BinaryenModuleRef module);
+
+// Print a module to stdout in asm.js syntax.
+BINARYEN_API void BinaryenModulePrintAsmjs(BinaryenModuleRef module);
+
+// Validate a module, showing errors on problems.
+//  @return 0 if an error occurred, 1 if validated succesfully
+BINARYEN_API int BinaryenModuleValidate(BinaryenModuleRef module);
+
+// Runs the standard optimization passes on the module. Uses the currently set
+// global optimize and shrink level.
+BINARYEN_API void BinaryenModuleOptimize(BinaryenModuleRef module);
+
+// Gets the currently set optimize level. Applies to all modules, globally.
+// 0, 1, 2 correspond to -O0, -O1, -O2 (default), etc.
+BINARYEN_API int BinaryenGetOptimizeLevel(void);
+
+// Sets the optimization level to use. Applies to all modules, globally.
+// 0, 1, 2 correspond to -O0, -O1, -O2 (default), etc.
+BINARYEN_API void BinaryenSetOptimizeLevel(int level);
+
+// Gets the currently set shrink level. Applies to all modules, globally.
+// 0, 1, 2 correspond to -O0, -Os (default), -Oz.
+BINARYEN_API int BinaryenGetShrinkLevel(void);
+
+// Sets the shrink level to use. Applies to all modules, globally.
+// 0, 1, 2 correspond to -O0, -Os (default), -Oz.
+BINARYEN_API void BinaryenSetShrinkLevel(int level);
+
+// Gets whether generating debug information is currently enabled or not.
+// Applies to all modules, globally.
+BINARYEN_API int BinaryenGetDebugInfo(void);
+
+// Enables or disables debug information in emitted binaries.
+// Applies to all modules, globally.
+BINARYEN_API void BinaryenSetDebugInfo(int on);
+
+// Gets whether the low 1K of memory can be considered unused when optimizing.
+// Applies to all modules, globally.
+BINARYEN_API int BinaryenGetLowMemoryUnused(void);
+
+// Enables or disables whether the low 1K of memory can be considered unused
+// when optimizing. Applies to all modules, globally.
+BINARYEN_API void BinaryenSetLowMemoryUnused(int on);
+
+// Gets whether fast math optimizations are enabled, ignoring for example
+// corner cases of floating-point math like NaN changes.
+// Applies to all modules, globally.
+BINARYEN_API int BinaryenGetFastMath(void);
+
+// Enables or disables fast math optimizations, ignoring for example
+// corner cases of floating-point math like NaN changes.
+// Applies to all modules, globally.
+BINARYEN_API void BinaryenSetFastMath(int value);
+
+// Gets the value of the specified arbitrary pass argument.
+// Applies to all modules, globally.
+BINARYEN_API const char* BinaryenGetPassArgument(const char* name);
+
+// Sets the value of the specified arbitrary pass argument. Removes the
+// respective argument if `value` is NULL. Applies to all modules, globally.
+BINARYEN_API void BinaryenSetPassArgument(const char* name, const char* value);
+
+// Clears all arbitrary pass arguments.
+// Applies to all modules, globally.
+BINARYEN_API void BinaryenClearPassArguments();
+
+// Gets the function size at which we always inline.
+// Applies to all modules, globally.
+BINARYEN_API BinaryenIndex BinaryenGetAlwaysInlineMaxSize(void);
+
+// Sets the function size at which we always inline.
+// Applies to all modules, globally.
+BINARYEN_API void BinaryenSetAlwaysInlineMaxSize(BinaryenIndex size);
+
+// Gets the function size which we inline when functions are lightweight.
+// Applies to all modules, globally.
+BINARYEN_API BinaryenIndex BinaryenGetFlexibleInlineMaxSize(void);
+
+// Sets the function size which we inline when functions are lightweight.
+// Applies to all modules, globally.
+BINARYEN_API void BinaryenSetFlexibleInlineMaxSize(BinaryenIndex size);
+
+// Gets the function size which we inline when there is only one caller.
+// Applies to all modules, globally.
+BINARYEN_API BinaryenIndex BinaryenGetOneCallerInlineMaxSize(void);
+
+// Sets the function size which we inline when there is only one caller.
+// Applies to all modules, globally.
+BINARYEN_API void BinaryenSetOneCallerInlineMaxSize(BinaryenIndex size);
+
+// Gets whether functions with loops are allowed to be inlined.
+// Applies to all modules, globally.
+BINARYEN_API int BinaryenGetAllowInliningFunctionsWithLoops(void);
+
+// Sets whether functions with loops are allowed to be inlined.
+// Applies to all modules, globally.
+BINARYEN_API void BinaryenSetAllowInliningFunctionsWithLoops(int enabled);
+
+// Runs the specified passes on the module. Uses the currently set global
+// optimize and shrink level.
+BINARYEN_API void BinaryenModuleRunPasses(BinaryenModuleRef module,
+                                          const char** passes,
+                                          BinaryenIndex numPasses);
+
+// Auto-generate drop() operations where needed. This lets you generate code
+// without worrying about where they are needed. (It is more efficient to do it
+// yourself, but simpler to use autodrop).
+BINARYEN_API void BinaryenModuleAutoDrop(BinaryenModuleRef module);
+
+// Serialize a module into binary form. Uses the currently set global debugInfo
+// option.
+// @return how many bytes were written. This will be less than or equal to
+//         outputSize
+size_t BINARYEN_API BinaryenModuleWrite(BinaryenModuleRef module,
+                                        char* output,
+                                        size_t outputSize);
+
+// Serialize a module in s-expression text format.
+// @return how many bytes were written. This will be less than or equal to
+//         outputSize
+BINARYEN_API size_t BinaryenModuleWriteText(BinaryenModuleRef module,
+                                            char* output,
+                                            size_t outputSize);
+
+typedef struct BinaryenBufferSizes {
+  size_t outputBytes;
+  size_t sourceMapBytes;
+} BinaryenBufferSizes;
+
+// Serialize a module into binary form including its source map. Uses the
+// currently set global debugInfo option.
+// @returns how many bytes were written. This will be less than or equal to
+//          outputSize
+BINARYEN_API BinaryenBufferSizes
+BinaryenModuleWriteWithSourceMap(BinaryenModuleRef module,
+                                 const char* url,
+                                 char* output,
+                                 size_t outputSize,
+                                 char* sourceMap,
+                                 size_t sourceMapSize);
+
+// Result structure of BinaryenModuleAllocateAndWrite. Contained buffers have
+// been allocated using malloc() and the user is expected to free() them
+// manually once not needed anymore.
+typedef struct BinaryenModuleAllocateAndWriteResult {
+  void* binary;
+  size_t binaryBytes;
+  char* sourceMap;
+} BinaryenModuleAllocateAndWriteResult;
+
+// Serializes a module into binary form, optionally including its source map if
+// sourceMapUrl has been specified. Uses the currently set global debugInfo
+// option. Differs from BinaryenModuleWrite in that it implicitly allocates
+// appropriate buffers using malloc(), and expects the user to free() them
+// manually once not needed anymore.
+BINARYEN_API BinaryenModuleAllocateAndWriteResult
+BinaryenModuleAllocateAndWrite(BinaryenModuleRef module,
+                               const char* sourceMapUrl);
+
+// Serialize a module in s-expression form. Implicity allocates the returned
+// char* with malloc(), and expects the user to free() them manually
+// once not needed anymore.
+BINARYEN_API char* BinaryenModuleAllocateAndWriteText(BinaryenModuleRef module);
+
+// Deserialize a module from binary form.
+BINARYEN_API BinaryenModuleRef BinaryenModuleRead(char* input,
+                                                  size_t inputSize);
+
+// Execute a module in the Binaryen interpreter. This will create an instance of
+// the module, run it in the interpreter - which means running the start method
+// - and then destroying the instance.
+BINARYEN_API void BinaryenModuleInterpret(BinaryenModuleRef module);
+
+// Adds a debug info file name to the module and returns its index.
+BINARYEN_API BinaryenIndex BinaryenModuleAddDebugInfoFileName(
+  BinaryenModuleRef module, const char* filename);
+
+// Gets the name of the debug info file at the specified index. Returns `NULL`
+// if it does not exist.
+BINARYEN_API const char*
+BinaryenModuleGetDebugInfoFileName(BinaryenModuleRef module,
+                                   BinaryenIndex index);
+
+//
+// ========== Function Operations ==========
+//
+
+// Gets the name of the specified `Function`.
+BINARYEN_API const char* BinaryenFunctionGetName(BinaryenFunctionRef func);
+// Gets the type of the parameter at the specified index of the specified
+// `Function`.
+BINARYEN_API BinaryenType BinaryenFunctionGetParams(BinaryenFunctionRef func);
+// Gets the result type of the specified `Function`.
+BINARYEN_API BinaryenType BinaryenFunctionGetResults(BinaryenFunctionRef func);
+// Gets the number of additional locals within the specified `Function`.
+BINARYEN_API BinaryenIndex BinaryenFunctionGetNumVars(BinaryenFunctionRef func);
+// Gets the type of the additional local at the specified index within the
+// specified `Function`.
+BINARYEN_API BinaryenType BinaryenFunctionGetVar(BinaryenFunctionRef func,
+                                                 BinaryenIndex index);
+// Gets the number of locals within the specified function. Includes parameters.
+BINARYEN_API BinaryenIndex
+BinaryenFunctionGetNumLocals(BinaryenFunctionRef func);
+// Tests if the local at the specified index has a name.
+BINARYEN_API int BinaryenFunctionHasLocalName(BinaryenFunctionRef func,
+                                              BinaryenIndex index);
+// Gets the name of the local at the specified index.
+BINARYEN_API const char* BinaryenFunctionGetLocalName(BinaryenFunctionRef func,
+                                                      BinaryenIndex index);
+// Sets the name of the local at the specified index.
+BINARYEN_API void BinaryenFunctionSetLocalName(BinaryenFunctionRef func,
+                                               BinaryenIndex index,
+                                               const char* name);
+// Gets the body of the specified `Function`.
+BINARYEN_API BinaryenExpressionRef
+BinaryenFunctionGetBody(BinaryenFunctionRef func);
+// Sets the body of the specified `Function`.
+BINARYEN_API void BinaryenFunctionSetBody(BinaryenFunctionRef func,
+                                          BinaryenExpressionRef body);
+
+// Runs the standard optimization passes on the function. Uses the currently set
+// global optimize and shrink level.
+BINARYEN_API void BinaryenFunctionOptimize(BinaryenFunctionRef func,
+                                           BinaryenModuleRef module);
+
+// Runs the specified passes on the function. Uses the currently set global
+// optimize and shrink level.
+BINARYEN_API void BinaryenFunctionRunPasses(BinaryenFunctionRef func,
+                                            BinaryenModuleRef module,
+                                            const char** passes,
+                                            BinaryenIndex numPasses);
+
+// Sets the debug location of the specified `Expression` within the specified
+// `Function`.
+BINARYEN_API void BinaryenFunctionSetDebugLocation(BinaryenFunctionRef func,
+                                                   BinaryenExpressionRef expr,
+                                                   BinaryenIndex fileIndex,
+                                                   BinaryenIndex lineNumber,
+                                                   BinaryenIndex columnNumber);
+
+//
+// ========== Global Operations ==========
+//
+
+// Gets the name of the specified `Global`.
+BINARYEN_API const char* BinaryenGlobalGetName(BinaryenGlobalRef global);
+// Gets the name of the `GlobalType` associated with the specified `Global`. May
+// be `NULL` if the signature is implicit.
+BINARYEN_API BinaryenType BinaryenGlobalGetType(BinaryenGlobalRef global);
+// Returns true if the specified `Global` is mutable.
+BINARYEN_API int BinaryenGlobalIsMutable(BinaryenGlobalRef global);
+// Gets the initialization expression of the specified `Global`.
+BINARYEN_API BinaryenExpressionRef
+BinaryenGlobalGetInitExpr(BinaryenGlobalRef global);
+
+//
+// ========== Event Operations ==========
+//
+
+// Gets the name of the specified `Event`.
+BINARYEN_API const char* BinaryenEventGetName(BinaryenEventRef event);
+// Gets the attribute of the specified `Event`.
+BINARYEN_API int BinaryenEventGetAttribute(BinaryenEventRef event);
+// Gets the parameters type of the specified `Event`.
+BINARYEN_API BinaryenType BinaryenEventGetParams(BinaryenEventRef event);
+// Gets the results type of the specified `Event`.
+BINARYEN_API BinaryenType BinaryenEventGetResults(BinaryenEventRef event);
+
+//
+// ========== Import Operations ==========
+//
+
+// Gets the external module name of the specified import.
+BINARYEN_API const char*
+BinaryenFunctionImportGetModule(BinaryenFunctionRef import);
+BINARYEN_API const char*
+BinaryenGlobalImportGetModule(BinaryenGlobalRef import);
+BINARYEN_API const char* BinaryenEventImportGetModule(BinaryenEventRef import);
+// Gets the external base name of the specified import.
+BINARYEN_API const char*
+BinaryenFunctionImportGetBase(BinaryenFunctionRef import);
+BINARYEN_API const char* BinaryenGlobalImportGetBase(BinaryenGlobalRef import);
+BINARYEN_API const char* BinaryenEventImportGetBase(BinaryenEventRef import);
+
+//
+// ========== Export Operations ==========
+//
+
+// Gets the external kind of the specified export.
+BINARYEN_API BinaryenExternalKind
+BinaryenExportGetKind(BinaryenExportRef export_);
+// Gets the external name of the specified export.
+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 =========
+//
+
+BINARYEN_API void BinaryenAddCustomSection(BinaryenModuleRef module,
+                                           const char* name,
+                                           const char* contents,
+                                           BinaryenIndex contentsSize);
+
+//
+// ========= Effect analyzer =========
+//
+
+typedef uint32_t BinaryenSideEffects;
+
+BINARYEN_API BinaryenSideEffects BinaryenSideEffectNone(void);
+BINARYEN_API BinaryenSideEffects BinaryenSideEffectBranches(void);
+BINARYEN_API BinaryenSideEffects BinaryenSideEffectCalls(void);
+BINARYEN_API BinaryenSideEffects BinaryenSideEffectReadsLocal(void);
+BINARYEN_API BinaryenSideEffects BinaryenSideEffectWritesLocal(void);
+BINARYEN_API BinaryenSideEffects BinaryenSideEffectReadsGlobal(void);
+BINARYEN_API BinaryenSideEffects BinaryenSideEffectWritesGlobal(void);
+BINARYEN_API BinaryenSideEffects BinaryenSideEffectReadsMemory(void);
+BINARYEN_API BinaryenSideEffects BinaryenSideEffectWritesMemory(void);
+BINARYEN_API BinaryenSideEffects BinaryenSideEffectImplicitTrap(void);
+BINARYEN_API BinaryenSideEffects BinaryenSideEffectIsAtomic(void);
+BINARYEN_API BinaryenSideEffects BinaryenSideEffectThrows(void);
+BINARYEN_API BinaryenSideEffects BinaryenSideEffectDanglingPop(void);
+BINARYEN_API BinaryenSideEffects BinaryenSideEffectAny(void);
+
+BINARYEN_API BinaryenSideEffects BinaryenExpressionGetSideEffects(
+  BinaryenExpressionRef expr, BinaryenFeatures features);
+
+//
+// ========== CFG / Relooper ==========
+//
+// General usage is (1) create a relooper, (2) create blocks, (3) add
+// branches between them, (4) render the output.
+//
+// For more details, see src/cfg/Relooper.h and
+// https://github.com/WebAssembly/binaryen/wiki/Compiling-to-WebAssembly-with-Binaryen#cfg-api
+
+#ifdef __cplusplus
+namespace CFG {
+struct Relooper;
+struct Block;
+} // namespace CFG
+typedef struct CFG::Relooper* RelooperRef;
+typedef struct CFG::Block* RelooperBlockRef;
+#else
+typedef struct Relooper* RelooperRef;
+typedef struct RelooperBlock* RelooperBlockRef;
+#endif
+
+// Create a relooper instance
+BINARYEN_API RelooperRef RelooperCreate(BinaryenModuleRef module);
+
+// Create a basic block that ends with nothing, or with some simple branching
+BINARYEN_API RelooperBlockRef RelooperAddBlock(RelooperRef relooper,
+                                               BinaryenExpressionRef code);
+
+// Create a branch to another basic block
+// The branch can have code on it, that is executed as the branch happens. this
+// is useful for phis. otherwise, code can be NULL
+BINARYEN_API void RelooperAddBranch(RelooperBlockRef from,
+                                    RelooperBlockRef to,
+                                    BinaryenExpressionRef condition,
+                                    BinaryenExpressionRef code);
+
+// Create a basic block that ends a switch on a condition
+BINARYEN_API RelooperBlockRef
+RelooperAddBlockWithSwitch(RelooperRef relooper,
+                           BinaryenExpressionRef code,
+                           BinaryenExpressionRef condition);
+
+// Create a switch-style branch to another basic block. The block's switch table
+// will have these indexes going to that target
+BINARYEN_API void RelooperAddBranchForSwitch(RelooperBlockRef from,
+                                             RelooperBlockRef to,
+                                             BinaryenIndex* indexes,
+                                             BinaryenIndex numIndexes,
+                                             BinaryenExpressionRef code);
+
+// Generate structed wasm control flow from the CFG of blocks and branches that
+// were created on this relooper instance. This returns the rendered output, and
+// also disposes of the relooper and its blocks and branches, as they are no
+// longer needed.
+// @param labelHelper To render irreducible control flow, we may need a helper
+//        variable to guide us to the right target label. This value should be
+//        an index of an i32 local variable that is free for us to use.
+BINARYEN_API BinaryenExpressionRef RelooperRenderAndDispose(
+  RelooperRef relooper, RelooperBlockRef entry, BinaryenIndex labelHelper);
+
+//
+// ========= ExpressionRunner ==========
+//
+
+#ifdef __cplusplus
+namespace wasm {
+class CExpressionRunner;
+} // namespace wasm
+typedef class wasm::CExpressionRunner* ExpressionRunnerRef;
+#else
+typedef struct CExpressionRunner* ExpressionRunnerRef;
+#endif
+
+typedef uint32_t ExpressionRunnerFlags;
+
+// By default, just evaluate the expression, i.e. all we want to know is whether
+// it computes down to a concrete value, where it is not necessary to preserve
+// side effects like those of a `local.tee`.
+BINARYEN_API ExpressionRunnerFlags ExpressionRunnerFlagsDefault();
+
+// Be very careful to preserve any side effects. For example, if we are
+// intending to replace the expression with a constant afterwards, even if we
+// can technically evaluate down to a constant, we still cannot replace the
+// expression if it also sets a local, which must be preserved in this scenario
+// so subsequent code keeps functioning.
+BINARYEN_API ExpressionRunnerFlags ExpressionRunnerFlagsPreserveSideeffects();
+
+// Traverse through function calls, attempting to compute their concrete value.
+// Must not be used in function-parallel scenarios, where the called function
+// might be concurrently modified, leading to undefined behavior. Traversing
+// another function reuses all of this runner's flags.
+BINARYEN_API ExpressionRunnerFlags ExpressionRunnerFlagsTraverseCalls();
+
+// Creates an ExpressionRunner instance
+BINARYEN_API ExpressionRunnerRef
+ExpressionRunnerCreate(BinaryenModuleRef module,
+                       ExpressionRunnerFlags flags,
+                       BinaryenIndex maxDepth,
+                       BinaryenIndex maxLoopIterations);
+
+// Sets a known local value to use. Order matters if expressions have side
+// effects. For example, if the expression also sets a local, this side effect
+// will also happen (not affected by any flags). Returns `true` if the
+// expression actually evaluates to a constant.
+BINARYEN_API int ExpressionRunnerSetLocalValue(ExpressionRunnerRef runner,
+                                               BinaryenIndex index,
+                                               BinaryenExpressionRef value);
+
+// Sets a known global value to use. Order matters if expressions have side
+// effects. For example, if the expression also sets a local, this side effect
+// will also happen (not affected by any flags). Returns `true` if the
+// expression actually evaluates to a constant.
+BINARYEN_API int ExpressionRunnerSetGlobalValue(ExpressionRunnerRef runner,
+                                                const char* name,
+                                                BinaryenExpressionRef value);
+
+// Runs the expression and returns the constant value expression it evaluates
+// to, if any. Otherwise returns `NULL`. Also disposes the runner.
+BINARYEN_API BinaryenExpressionRef ExpressionRunnerRunAndDispose(
+  ExpressionRunnerRef runner, BinaryenExpressionRef expr);
+
+//
+// ========= Utilities =========
+//
+
+// Enable or disable coloring for the WASM printer
+BINARYEN_API void BinaryenSetColorsEnabled(int enabled);
+
+// Query whether color is enable for the WASM printer
+BINARYEN_API int BinaryenAreColorsEnabled();
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // wasm_binaryen_c_h
diff --git a/binaryen/src/cfg/CMakeLists.txt b/binaryen/src/cfg/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/src/cfg/CMakeLists.txt
@@ -0,0 +1,6 @@
+FILE(GLOB cfg_HEADERS *.h)
+set(cfg_SOURCES
+  Relooper.cpp
+  ${cfg_HEADERS}
+)
+add_library(cfg OBJECT ${cfg_SOURCES})
diff --git a/binaryen/src/cfg/Relooper.cpp b/binaryen/src/cfg/Relooper.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/cfg/Relooper.cpp
@@ -0,0 +1,1707 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Relooper.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <list>
+#include <stack>
+#include <string>
+
+#include "ir/branch-utils.h"
+#include "ir/utils.h"
+#include "parsing.h"
+
+namespace CFG {
+
+template<class T, class U>
+static bool contains(const T& container, const U& contained) {
+  return !!container.count(contained);
+}
+
+#ifdef RELOOPER_DEBUG
+static void PrintDebug(const char* Format, ...);
+#define DebugDump(x, ...) Debugging::Dump(x, __VA_ARGS__)
+#else
+#define PrintDebug(x, ...)
+#define DebugDump(x, ...)
+#endif
+
+// Rendering utilities
+
+static wasm::Expression* HandleFollowupMultiples(wasm::Expression* Ret,
+                                                 Shape* Parent,
+                                                 RelooperBuilder& Builder,
+                                                 bool InLoop) {
+  if (!Parent->Next) {
+    return Ret;
+  }
+
+  auto* Curr = Ret->dynCast<wasm::Block>();
+  if (!Curr || Curr->name.is()) {
+    Curr = Builder.makeBlock(Ret);
+  }
+  // for each multiple after us, we create a block target for breaks to reach
+  while (Parent->Next) {
+    auto* Multiple = Shape::IsMultiple(Parent->Next);
+    if (!Multiple) {
+      break;
+    }
+    for (auto& iter : Multiple->InnerMap) {
+      int Id = iter.first;
+      Shape* Body = iter.second;
+      Curr->name = Builder.getBlockBreakName(Id);
+      Curr->finalize(); // it may now be reachable, via a break
+      auto* Outer = Builder.makeBlock(Curr);
+      Outer->list.push_back(Body->Render(Builder, InLoop));
+      Outer->finalize(); // TODO: not really necessary
+      Curr = Outer;
+    }
+    Parent->Next = Parent->Next->Next;
+  }
+  // after the multiples is a simple or a loop, in both cases we must hit an
+  // entry block, and so this is the last one we need to take into account now
+  // (this is why we require that loops hit an entry).
+  if (Parent->Next) {
+    auto* Simple = Shape::IsSimple(Parent->Next);
+    if (Simple) {
+      // breaking on the next block's id takes us out, where we
+      // will reach its rendering
+      Curr->name = Builder.getBlockBreakName(Simple->Inner->Id);
+    } else {
+      // add one break target per entry for the loop
+      auto* Loop = Shape::IsLoop(Parent->Next);
+      assert(Loop);
+      assert(Loop->Entries.size() > 0);
+      if (Loop->Entries.size() == 1) {
+        Curr->name = Builder.getBlockBreakName((*Loop->Entries.begin())->Id);
+      } else {
+        for (auto* Entry : Loop->Entries) {
+          Curr->name = Builder.getBlockBreakName(Entry->Id);
+          Curr->finalize();
+          auto* Outer = Builder.makeBlock(Curr);
+          Outer->finalize(); // TODO: not really necessary
+          Curr = Outer;
+        }
+      }
+    }
+  }
+  Curr->finalize();
+  return Curr;
+}
+
+// Branch
+
+Branch::Branch(wasm::Expression* ConditionInit, wasm::Expression* CodeInit)
+  : Condition(ConditionInit), Code(CodeInit) {}
+
+Branch::Branch(std::vector<wasm::Index>&& ValuesInit,
+               wasm::Expression* CodeInit)
+  : Condition(nullptr), Code(CodeInit) {
+  if (ValuesInit.size() > 0) {
+    SwitchValues = wasm::make_unique<std::vector<wasm::Index>>(ValuesInit);
+  }
+  // otherwise, it is the default
+}
+
+wasm::Expression*
+Branch::Render(RelooperBuilder& Builder, Block* Target, bool SetLabel) {
+  auto* Ret = Builder.makeBlock();
+  if (Code) {
+    Ret->list.push_back(Code);
+  }
+  if (SetLabel) {
+    Ret->list.push_back(Builder.makeSetLabel(Target->Id));
+  }
+  if (Type == Break) {
+    Ret->list.push_back(Builder.makeBlockBreak(Target->Id));
+  } else if (Type == Continue) {
+    assert(Ancestor);
+    Ret->list.push_back(Builder.makeShapeContinue(Ancestor->Id));
+  }
+  Ret->finalize();
+  return Ret;
+}
+
+// Block
+
+Block::Block(Relooper* relooper,
+             wasm::Expression* CodeInit,
+             wasm::Expression* SwitchConditionInit)
+  : relooper(relooper), Code(CodeInit), SwitchCondition(SwitchConditionInit),
+    IsCheckedMultipleEntry(false) {}
+
+void Block::AddBranchTo(Block* Target,
+                        wasm::Expression* Condition,
+                        wasm::Expression* Code) {
+  // cannot add more than one branch to the same target
+  assert(!contains(BranchesOut, Target));
+  BranchesOut[Target] = relooper->AddBranch(Condition, Code);
+}
+
+void Block::AddSwitchBranchTo(Block* Target,
+                              std::vector<wasm::Index>&& Values,
+                              wasm::Expression* Code) {
+  // cannot add more than one branch to the same target
+  assert(!contains(BranchesOut, Target));
+  BranchesOut[Target] = relooper->AddBranch(std::move(Values), Code);
+}
+
+wasm::Expression* Block::Render(RelooperBuilder& Builder, bool InLoop) {
+  auto* Ret = Builder.makeBlock();
+  if (IsCheckedMultipleEntry && InLoop) {
+    Ret->list.push_back(Builder.makeSetLabel(0));
+  }
+  if (Code) {
+    Ret->list.push_back(Code);
+  }
+
+  if (!ProcessedBranchesOut.size()) {
+    Ret->finalize();
+    return Ret;
+  }
+
+  // in some cases it is clear we can avoid setting label, see later
+  bool SetLabel = true;
+
+  // A setting of the label variable (label = x) is necessary if it can
+  // cause an impact. The main case is where we set label to x, then elsewhere
+  // we check if label is equal to that value, i.e., that label is an entry
+  // in a multiple block. We also need to reset the label when we enter
+  // that block, so that each setting is a one-time action: consider
+  //
+  //    while (1) {
+  //      if (check) label = 1;
+  //      if (label == 1) { label = 0 }
+  //    }
+  //
+  // (Note that this case is impossible due to fusing, but that is not
+  // material here.) So setting to 0 is important just to clear the 1 for
+  // future iterations.
+  // TODO: When inside a loop, if necessary clear the label variable
+  //       once on the top, and never do settings that are in effect clears
+
+  // Fusing: If the next is a Multiple, we can fuse it with this block. Note
+  // that we must be the Inner of a Simple, so fusing means joining a Simple
+  // to a Multiple. What happens there is that all options in the Multiple
+  // *must* appear in the Simple (the Simple is the only one reaching the
+  // Multiple), so we can remove the Multiple and add its independent groups
+  // into the Simple's branches.
+  MultipleShape* Fused = Shape::IsMultiple(Parent->Next);
+  if (Fused) {
+    PrintDebug("Fusing Multiple to Simple\n", 0);
+    Parent->Next = Parent->Next->Next;
+    // When the Multiple has the same number of groups as we have branches,
+    // they will all be fused, so it is safe to not set the label at all.
+    // If a switch, then we can have multiple branches to the same target
+    // (in different table indexes), and so this check is not sufficient
+    // TODO: optimize
+    if (SetLabel && Fused->InnerMap.size() == ProcessedBranchesOut.size() &&
+        !SwitchCondition) {
+      SetLabel = false;
+    }
+  }
+
+  // The block we branch to without checking the condition, if none of the other
+  // conditions held.
+  Block* DefaultTarget = nullptr;
+
+  // Find the default target, the one without a condition
+  for (auto& iter : ProcessedBranchesOut) {
+    if ((!SwitchCondition && !iter.second->Condition) ||
+        (SwitchCondition && !iter.second->SwitchValues)) {
+      assert(!DefaultTarget &&
+             "block has branches without a default (nullptr for the "
+             "condition)"); // Must be exactly one default // nullptr
+      DefaultTarget = iter.first;
+    }
+  }
+  // Since each Block* must* branch somewhere, this must be set
+  assert(DefaultTarget);
+
+  // root of the main part, that we are about to emit
+  wasm::Expression* Root = nullptr;
+
+  if (!SwitchCondition) {
+    // We'll emit a chain of if-elses
+    wasm::If* CurrIf = nullptr;
+
+    // we build an if, then add a child, then add a child to that, etc., so we
+    // must finalize them in reverse order
+    std::vector<wasm::If*> finalizeStack;
+
+    wasm::Expression* RemainingConditions = nullptr;
+
+    for (auto iter = ProcessedBranchesOut.begin();; iter++) {
+      Block* Target;
+      Branch* Details;
+      if (iter != ProcessedBranchesOut.end()) {
+        Target = iter->first;
+        if (Target == DefaultTarget) {
+          continue; // done at the end
+        }
+        Details = iter->second;
+        // must have a condition if this is not the default target
+        assert(Details->Condition);
+      } else {
+        Target = DefaultTarget;
+        Details = ProcessedBranchesOut[DefaultTarget];
+      }
+      bool SetCurrLabel = SetLabel && Target->IsCheckedMultipleEntry;
+      bool HasFusedContent = Fused && contains(Fused->InnerMap, Target->Id);
+      if (HasFusedContent) {
+        assert(Details->Type == Branch::Break);
+        Details->Type = Branch::Direct;
+      }
+      wasm::Expression* CurrContent = nullptr;
+      bool IsDefault = iter == ProcessedBranchesOut.end();
+      if (SetCurrLabel || Details->Type != Branch::Direct || HasFusedContent ||
+          Details->Code) {
+        CurrContent = Details->Render(Builder, Target, SetCurrLabel);
+        if (HasFusedContent) {
+          CurrContent = Builder.blockify(
+            CurrContent,
+            Fused->InnerMap.find(Target->Id)->second->Render(Builder, InLoop));
+        }
+      }
+      // If there is nothing to show in this branch, omit the condition
+      if (CurrContent) {
+        if (IsDefault) {
+          wasm::Expression* Now;
+          if (RemainingConditions) {
+            Now = Builder.makeIf(RemainingConditions, CurrContent);
+            finalizeStack.push_back(Now->cast<wasm::If>());
+          } else {
+            Now = CurrContent;
+          }
+          if (!CurrIf) {
+            assert(!Root);
+            Root = Now;
+          } else {
+            CurrIf->ifFalse = Now;
+            CurrIf->finalize();
+          }
+        } else {
+          auto* Now = Builder.makeIf(Details->Condition, CurrContent);
+          finalizeStack.push_back(Now);
+          if (!CurrIf) {
+            assert(!Root);
+            Root = CurrIf = Now;
+          } else {
+            CurrIf->ifFalse = Now;
+            CurrIf->finalize();
+            CurrIf = Now;
+          }
+        }
+      } else {
+        auto* Now = Builder.makeUnary(wasm::EqZInt32, Details->Condition);
+        if (RemainingConditions) {
+          RemainingConditions =
+            Builder.makeBinary(wasm::AndInt32, RemainingConditions, Now);
+        } else {
+          RemainingConditions = Now;
+        }
+      }
+      if (IsDefault) {
+        break;
+      }
+    }
+
+    // finalize the if-chains
+    while (finalizeStack.size() > 0) {
+      wasm::If* curr = finalizeStack.back();
+      finalizeStack.pop_back();
+      curr->finalize();
+    }
+
+  } else {
+    // Emit a switch
+    auto Base = std::string("switch$") + std::to_string(Id);
+    auto SwitchDefault = wasm::Name(Base + "$default");
+    auto SwitchLeave = wasm::Name(Base + "$leave");
+    std::map<Block*, wasm::Name> BlockNameMap;
+    auto* Outer = Builder.makeBlock();
+    auto* Inner = Outer;
+    std::vector<wasm::Name> Table;
+    for (auto& iter : ProcessedBranchesOut) {
+      Block* Target = iter.first;
+      Branch* Details = iter.second;
+      wasm::Name CurrName;
+      if (Details->SwitchValues) {
+        CurrName = wasm::Name(Base + "$case$" + std::to_string(Target->Id));
+      } else {
+        CurrName = SwitchDefault;
+      }
+      // generate the content for this block
+      bool SetCurrLabel = SetLabel && Target->IsCheckedMultipleEntry;
+      bool HasFusedContent = Fused && contains(Fused->InnerMap, Target->Id);
+      if (HasFusedContent) {
+        assert(Details->Type == Branch::Break);
+        Details->Type = Branch::Direct;
+      }
+      wasm::Expression* CurrContent = nullptr;
+      if (SetCurrLabel || Details->Type != Branch::Direct || HasFusedContent ||
+          Details->Code) {
+        CurrContent = Details->Render(Builder, Target, SetCurrLabel);
+        if (HasFusedContent) {
+          CurrContent = Builder.blockify(
+            CurrContent,
+            Fused->InnerMap.find(Target->Id)->second->Render(Builder, InLoop));
+        }
+      }
+      // generate a block to branch to, if we have content
+      if (CurrContent) {
+        auto* NextOuter = Builder.makeBlock();
+        NextOuter->list.push_back(Outer);
+        // breaking on Outer leads to the content in NextOuter
+        Outer->name = CurrName;
+        NextOuter->list.push_back(CurrContent);
+        // if this is not a dead end, also need to break to the outside this is
+        // both an optimization, and avoids incorrectness as adding a break in
+        // unreachable code can make a place look reachable that isn't
+        if (CurrContent->type != wasm::Type::unreachable) {
+          NextOuter->list.push_back(Builder.makeBreak(SwitchLeave));
+        }
+        // prepare for more nesting
+        Outer = NextOuter;
+      } else {
+        CurrName = SwitchLeave; // just go out straight from the table
+        if (!Details->SwitchValues) {
+          // this is the default, and it has no content. So make the default be
+          // the leave
+          for (auto& Value : Table) {
+            if (Value == SwitchDefault) {
+              Value = SwitchLeave;
+            }
+          }
+          SwitchDefault = SwitchLeave;
+        }
+      }
+      if (Details->SwitchValues) {
+        for (auto Value : *Details->SwitchValues) {
+          while (Table.size() <= Value) {
+            Table.push_back(SwitchDefault);
+          }
+          Table[Value] = CurrName;
+        }
+      }
+    }
+    // finish up the whole pattern
+    Outer->name = SwitchLeave;
+    Inner->list.push_back(
+      Builder.makeSwitch(Table, SwitchDefault, SwitchCondition));
+    Root = Outer;
+  }
+
+  if (Root) {
+    Ret->list.push_back(Root);
+  }
+  Ret->finalize();
+
+  return Ret;
+}
+
+// SimpleShape
+
+wasm::Expression* SimpleShape::Render(RelooperBuilder& Builder, bool InLoop) {
+  auto* Ret = Inner->Render(Builder, InLoop);
+  Ret = HandleFollowupMultiples(Ret, this, Builder, InLoop);
+  if (Next) {
+    Ret = Builder.makeSequence(Ret, Next->Render(Builder, InLoop));
+  }
+  return Ret;
+}
+
+// MultipleShape
+
+wasm::Expression* MultipleShape::Render(RelooperBuilder& Builder, bool InLoop) {
+  // TODO: consider switch
+  // emit an if-else chain
+  wasm::If* FirstIf = nullptr;
+  wasm::If* CurrIf = nullptr;
+  std::vector<wasm::If*> finalizeStack;
+  for (auto& iter : InnerMap) {
+    auto* Now = Builder.makeIf(Builder.makeCheckLabel(iter.first),
+                               iter.second->Render(Builder, InLoop));
+    finalizeStack.push_back(Now);
+    if (!CurrIf) {
+      FirstIf = CurrIf = Now;
+    } else {
+      CurrIf->ifFalse = Now;
+      CurrIf->finalize();
+      CurrIf = Now;
+    }
+  }
+  while (finalizeStack.size() > 0) {
+    wasm::If* curr = finalizeStack.back();
+    finalizeStack.pop_back();
+    curr->finalize();
+  }
+  wasm::Expression* Ret = Builder.makeBlock(FirstIf);
+  Ret = HandleFollowupMultiples(Ret, this, Builder, InLoop);
+  if (Next) {
+    Ret = Builder.makeSequence(Ret, Next->Render(Builder, InLoop));
+  }
+  return Ret;
+}
+
+// LoopShape
+
+wasm::Expression* LoopShape::Render(RelooperBuilder& Builder, bool InLoop) {
+  wasm::Expression* Ret = Builder.makeLoop(Builder.getShapeContinueName(Id),
+                                           Inner->Render(Builder, true));
+  Ret = HandleFollowupMultiples(Ret, this, Builder, InLoop);
+  if (Next) {
+    Ret = Builder.makeSequence(Ret, Next->Render(Builder, InLoop));
+  }
+  return Ret;
+}
+
+// Relooper
+
+Relooper::Relooper(wasm::Module* ModuleInit)
+  : Module(ModuleInit), Root(nullptr), MinSize(false), BlockIdCounter(1),
+    ShapeIdCounter(0) { // block ID 0 is reserved for clearings
+}
+
+Block* Relooper::AddBlock(wasm::Expression* CodeInit,
+                          wasm::Expression* SwitchConditionInit) {
+
+  auto block = std::make_unique<Block>(this, CodeInit, SwitchConditionInit);
+  block->Id = BlockIdCounter++;
+  auto* blockPtr = block.get();
+  Blocks.push_back(std::move(block));
+  return blockPtr;
+}
+
+Branch* Relooper::AddBranch(wasm::Expression* ConditionInit,
+                            wasm::Expression* CodeInit) {
+  auto branch = std::make_unique<Branch>(ConditionInit, CodeInit);
+  auto* branchPtr = branch.get();
+  Branches.push_back(std::move(branch));
+  return branchPtr;
+}
+Branch* Relooper::AddBranch(std::vector<wasm::Index>&& ValuesInit,
+                            wasm::Expression* CodeInit) {
+  auto branch = std::make_unique<Branch>(std::move(ValuesInit), CodeInit);
+  auto* branchPtr = branch.get();
+  Branches.push_back(std::move(branch));
+  return branchPtr;
+}
+
+SimpleShape* Relooper::AddSimpleShape() {
+  auto shape = std::make_unique<SimpleShape>();
+  shape->Id = ShapeIdCounter++;
+  auto* shapePtr = shape.get();
+  Shapes.push_back(std::move(shape));
+  return shapePtr;
+}
+
+MultipleShape* Relooper::AddMultipleShape() {
+  auto shape = std::make_unique<MultipleShape>();
+  shape->Id = ShapeIdCounter++;
+  auto* shapePtr = shape.get();
+  Shapes.push_back(std::move(shape));
+  return shapePtr;
+}
+
+LoopShape* Relooper::AddLoopShape() {
+  auto shape = std::make_unique<LoopShape>();
+  shape->Id = ShapeIdCounter++;
+  auto* shapePtr = shape.get();
+  Shapes.push_back(std::move(shape));
+  return shapePtr;
+}
+
+namespace {
+
+typedef std::list<Block*> BlockList;
+
+struct RelooperRecursor {
+  Relooper* Parent;
+  RelooperRecursor(Relooper* ParentInit) : Parent(ParentInit) {}
+};
+
+struct Liveness : public RelooperRecursor {
+  Liveness(Relooper* Parent) : RelooperRecursor(Parent) {}
+  BlockSet Live;
+
+  void FindLive(Block* Root) {
+    BlockList ToInvestigate;
+    ToInvestigate.push_back(Root);
+    while (ToInvestigate.size() > 0) {
+      Block* Curr = ToInvestigate.front();
+      ToInvestigate.pop_front();
+      if (contains(Live, Curr)) {
+        continue;
+      }
+      Live.insert(Curr);
+      for (auto& iter : Curr->BranchesOut) {
+        ToInvestigate.push_back(iter.first);
+      }
+    }
+  }
+};
+
+typedef std::pair<Branch*, Block*> BranchBlock;
+
+struct Optimizer : public RelooperRecursor {
+  Block* Entry;
+
+  Optimizer(Relooper* Parent, Block* EntryInit)
+    : RelooperRecursor(Parent), Entry(EntryInit) {
+    // TODO: there are likely some rare but possible O(N^2) cases with this
+    // looping
+    bool More = true;
+#if RELOOPER_OPTIMIZER_DEBUG
+    std::cout << "pre-optimize\n";
+    for (auto* Block : Parent->Blocks) {
+      DebugDump(Block, "pre-block");
+    }
+#endif
+
+    // First, run one-time preparatory passes.
+    CanonicalizeCode();
+
+    // Loop over passes that allow further reduction.
+    while (More) {
+      More = false;
+      More = SkipEmptyBlocks() || More;
+      More = MergeEquivalentBranches() || More;
+      More = UnSwitch() || More;
+      More = MergeConsecutiveBlocks() || More;
+      // TODO: Merge identical blocks. This would avoid taking into account
+      // their position / how they are reached, which means that the merging may
+      // add overhead, so we do it carefully:
+      //  * Merging a large-enough block is good for size, and we do it
+      //    in we are in MinSize mode, which means we can tolerate slightly
+      //    slower throughput.
+      // TODO: Fuse a non-empty block with a single successor.
+    }
+
+    // Finally, run one-time final passes.
+    // TODO
+
+#if RELOOPER_OPTIMIZER_DEBUG
+    std::cout << "post-optimize\n";
+    for (auto* Block : Parent->Blocks) {
+      DebugDump(Block, "post-block");
+    }
+#endif
+  }
+
+  // We will be performing code comparisons, so do some basic canonicalization
+  // to avoid things being unequal for silly reasons.
+  void CanonicalizeCode() {
+    for (auto& Block : Parent->Blocks) {
+      Block->Code = Canonicalize(Block->Code);
+      for (auto& iter : Block->BranchesOut) {
+        auto* Branch = iter.second;
+        if (Branch->Code) {
+          Branch->Code = Canonicalize(Branch->Code);
+        }
+      }
+    }
+  }
+
+  // If a branch goes to an empty block which has one target,
+  // and there is no phi or switch to worry us, just skip through.
+  bool SkipEmptyBlocks() {
+    bool Worked = false;
+    for (auto& CurrBlock : Parent->Blocks) {
+      // Generate a new set of branches out TODO optimize
+      BlockBranchMap NewBranchesOut;
+      for (auto& iter : CurrBlock->BranchesOut) {
+        auto* Next = iter.first;
+        auto* NextBranch = iter.second;
+        auto* First = Next;
+        auto* Replacement = First;
+#if RELOOPER_OPTIMIZER_DEBUG
+        std::cout << " maybeskip from " << Block->Id << " to next=" << Next->Id
+                  << '\n';
+#endif
+        std::unordered_set<decltype(Replacement)> Seen;
+        while (1) {
+          if (IsEmpty(Next) && Next->BranchesOut.size() == 1) {
+            auto iter = Next->BranchesOut.begin();
+            Block* NextNext = iter->first;
+            Branch* NextNextBranch = iter->second;
+            assert(!NextNextBranch->Condition && !NextNextBranch->SwitchValues);
+            if (!NextNextBranch->Code) { // TODO: handle extra code too
+              // We can skip through!
+              Next = Replacement = NextNext;
+              // If we've already seen this, stop - it's an infinite loop of
+              // empty blocks we can skip through.
+              if (Seen.count(Replacement)) {
+                // Stop here. Note that if we started from X and ended up with X
+                // once more, then Replacement == First and so lower down we
+                // will not report that we did any work, avoiding an infinite
+                // loop due to always thinking there is more work to do.
+                break;
+              } else {
+                // Otherwise, keep going.
+                Seen.insert(Replacement);
+                continue;
+              }
+            }
+          }
+          break;
+        }
+        if (Replacement != First) {
+#if RELOOPER_OPTIMIZER_DEBUG
+          std::cout << "  skip to replacement! " << CurrBlock->Id << " -> "
+                    << First->Id << " -> " << Replacement->Id << '\n';
+#endif
+          Worked = true;
+        }
+        // Add a branch to the target (which may be the unchanged original) in
+        // the set of new branches. If it's a replacement, it may collide, and
+        // we need to merge.
+        if (NewBranchesOut.count(Replacement)) {
+#if RELOOPER_OPTIMIZER_DEBUG
+          std::cout << "  merge\n";
+#endif
+          MergeBranchInto(NextBranch, NewBranchesOut[Replacement]);
+        } else {
+          NewBranchesOut[Replacement] = NextBranch;
+        }
+      }
+      CurrBlock->BranchesOut.swap(NewBranchesOut);
+    }
+    return Worked;
+  }
+
+  // Our IR has one Branch from each block to one of its targets, so there
+  // is nothing to reduce there, but different targets may in fact be
+  // equivalent in their *contents*.
+  bool MergeEquivalentBranches() {
+    bool Worked = false;
+    for (auto& ParentBlock : Parent->Blocks) {
+#if RELOOPER_OPTIMIZER_DEBUG
+      std::cout << "at parent " << ParentBlock->Id << '\n';
+#endif
+      if (ParentBlock->BranchesOut.size() >= 2) {
+        std::unordered_map<size_t, std::vector<BranchBlock>> HashedBranchesOut;
+        std::vector<Block*> BlocksToErase;
+        for (auto& iter : ParentBlock->BranchesOut) {
+          Block* CurrBlock = iter.first;
+#if RELOOPER_OPTIMIZER_DEBUG
+          std::cout << "  consider child " << CurrBlock->Id << '\n';
+#endif
+          Branch* CurrBranch = iter.second;
+          if (CurrBranch->Code) {
+            // We can't merge code; ignore
+            continue;
+          }
+          auto HashValue = Hash(CurrBlock);
+          auto& HashedSiblings = HashedBranchesOut[HashValue];
+          // Check if we are equivalent to any of them - if so, merge us.
+          bool Merged = false;
+          for (auto& Pair : HashedSiblings) {
+            Branch* SiblingBranch = Pair.first;
+            Block* SiblingBlock = Pair.second;
+            if (HaveEquivalentContents(CurrBlock, SiblingBlock)) {
+#if RELOOPER_OPTIMIZER_DEBUG
+              std::cout << "    equiv! to " << SiblingBlock->Id << '\n';
+#endif
+              MergeBranchInto(CurrBranch, SiblingBranch);
+              BlocksToErase.push_back(CurrBlock);
+              Merged = true;
+              Worked = true;
+            }
+#if RELOOPER_OPTIMIZER_DEBUG
+            else {
+              std::cout << "    same hash, but not equiv to "
+                        << SiblingBlock->Id << '\n';
+            }
+#endif
+          }
+          if (!Merged) {
+            HashedSiblings.emplace_back(CurrBranch, CurrBlock);
+          }
+        }
+        for (auto* Curr : BlocksToErase) {
+          ParentBlock->BranchesOut.erase(Curr);
+        }
+      }
+    }
+    return Worked;
+  }
+
+  // Merge consecutive blocks, that is, A -> B where no other branches go to B.
+  // In that case we are guaranteed to not increase code size.
+  bool MergeConsecutiveBlocks() {
+    bool Worked = false;
+    // First, count predecessors.
+    std::map<Block*, size_t> NumPredecessors;
+    for (auto& CurrBlock : Parent->Blocks) {
+      for (auto& iter : CurrBlock->BranchesOut) {
+        auto* NextBlock = iter.first;
+        NumPredecessors[NextBlock]++;
+      }
+    }
+    NumPredecessors[Entry]++;
+    for (auto& CurrBlock : Parent->Blocks) {
+      if (CurrBlock->BranchesOut.size() == 1) {
+        auto iter = CurrBlock->BranchesOut.begin();
+        auto* NextBlock = iter->first;
+        auto* NextBranch = iter->second;
+        assert(NumPredecessors[NextBlock] > 0);
+        if (NextBlock != CurrBlock.get() && NumPredecessors[NextBlock] == 1) {
+          // Good to merge!
+          wasm::Builder Builder(*Parent->Module);
+          // Merge in code on the branch as well, if any.
+          if (NextBranch->Code) {
+            CurrBlock->Code =
+              Builder.makeSequence(CurrBlock->Code, NextBranch->Code);
+          }
+          CurrBlock->Code =
+            Builder.makeSequence(CurrBlock->Code, NextBlock->Code);
+          // Use the next block's branching behavior
+          CurrBlock->BranchesOut.swap(NextBlock->BranchesOut);
+          NextBlock->BranchesOut.clear();
+          CurrBlock->SwitchCondition = NextBlock->SwitchCondition;
+          // The next block now has no predecessors.
+          NumPredecessors[NextBlock] = 0;
+          Worked = true;
+        }
+      }
+    }
+    return Worked;
+  }
+
+  // Removes unneeded switches - if only one branch is left, the default, then
+  // no switch is needed.
+  bool UnSwitch() {
+    bool Worked = false;
+    for (auto& ParentBlock : Parent->Blocks) {
+#if RELOOPER_OPTIMIZER_DEBUG
+      std::cout << "un-switching at " << ParentBlock->Id << ' '
+                << !!ParentBlock->SwitchCondition << ' '
+                << ParentBlock->BranchesOut.size() << '\n';
+#endif
+      if (ParentBlock->SwitchCondition) {
+        if (ParentBlock->BranchesOut.size() <= 1) {
+#if RELOOPER_OPTIMIZER_DEBUG
+          std::cout << "  un-switching!: " << ParentBlock->Id << '\n';
+#endif
+          ParentBlock->SwitchCondition = nullptr;
+          if (!ParentBlock->BranchesOut.empty()) {
+            assert(!ParentBlock->BranchesOut.begin()->second->SwitchValues);
+          }
+          Worked = true;
+        }
+      } else {
+        // If the block has no switch, the branches must not as well.
+#ifndef NDEBUG
+        for (auto& iter : ParentBlock->BranchesOut) {
+          assert(!iter.second->SwitchValues);
+        }
+#endif
+      }
+    }
+    return Worked;
+  }
+
+private:
+  wasm::Expression* Canonicalize(wasm::Expression* Curr) {
+    wasm::Builder Builder(*Parent->Module);
+    // Our preferred form is a block with no name and a flat list
+    // with Nops removed, and extra Unreachables removed as well.
+    // If the block would contain one item, return just the item.
+    wasm::Block* Outer = Curr->dynCast<wasm::Block>();
+    if (!Outer) {
+      Outer = Builder.makeBlock(Curr);
+    } else if (Outer->name.is()) {
+      // Perhaps the name can be removed.
+      if (!wasm::BranchUtils::BranchSeeker::has(Outer, Outer->name)) {
+        Outer->name = wasm::Name();
+      } else {
+        Outer = Builder.makeBlock(Curr);
+      }
+    }
+    Flatten(Outer);
+    if (Outer->list.size() == 1) {
+      return Outer->list[0];
+    } else {
+      return Outer;
+    }
+  }
+
+  void Flatten(wasm::Block* Outer) {
+    wasm::ExpressionList NewList(Parent->Module->allocator);
+    bool SeenUnreachableType = false;
+    auto Add = [&](wasm::Expression* Curr) {
+      if (Curr->is<wasm::Nop>()) {
+        // Do nothing with it.
+        return;
+      } else if (Curr->is<wasm::Unreachable>()) {
+        // If we already saw an unreachable-typed item, emit no
+        // Unreachable nodes after it.
+        if (SeenUnreachableType) {
+          return;
+        }
+      }
+      NewList.push_back(Curr);
+      if (Curr->type == wasm::Type::unreachable) {
+        SeenUnreachableType = true;
+      }
+    };
+    std::function<void(wasm::Block*)> FlattenIntoNewList =
+      [&](wasm::Block* Curr) {
+        assert(!Curr->name.is());
+        for (auto* Item : Curr->list) {
+          if (auto* Block = Item->dynCast<wasm::Block>()) {
+            if (Block->name.is()) {
+              // Leave it whole, it's not a trivial block.
+              Add(Block);
+            } else {
+              FlattenIntoNewList(Block);
+            }
+          } else {
+            // A random item.
+            Add(Item);
+          }
+        }
+        // All the items have been moved out.
+        Curr->list.clear();
+      };
+    FlattenIntoNewList(Outer);
+    assert(Outer->list.empty());
+    Outer->list.swap(NewList);
+  }
+
+  bool IsEmpty(Block* Curr) {
+    if (Curr->SwitchCondition) {
+      // This is non-trivial, so treat it as a non-empty block.
+      return false;
+    }
+    return IsEmpty(Curr->Code);
+  }
+
+  bool IsEmpty(wasm::Expression* Code) {
+    if (Code->is<wasm::Nop>()) {
+      return true; // a nop
+    }
+    if (auto* WasmBlock = Code->dynCast<wasm::Block>()) {
+      for (auto* Item : WasmBlock->list) {
+        if (!IsEmpty(Item)) {
+          return false;
+        }
+      }
+      return true; // block with no non-empty contents
+    }
+    return false;
+  }
+
+  // Checks functional equivalence, namely: the Code and SwitchCondition.
+  // We also check the branches out, *non-recursively*: that is, we check
+  // that they are literally identical, not that they can be computed to
+  // be equivalent.
+  bool HaveEquivalentContents(Block* A, Block* B) {
+    if (!IsPossibleCodeEquivalent(A->SwitchCondition, B->SwitchCondition)) {
+      return false;
+    }
+    if (!IsCodeEquivalent(A->Code, B->Code)) {
+      return false;
+    }
+    if (A->BranchesOut.size() != B->BranchesOut.size()) {
+      return false;
+    }
+    for (auto& aiter : A->BranchesOut) {
+      Block* ABlock = aiter.first;
+      Branch* ABranch = aiter.second;
+      if (B->BranchesOut.count(ABlock) == 0) {
+        return false;
+      }
+      auto* BBranch = B->BranchesOut[ABlock];
+      if (!IsPossibleCodeEquivalent(ABranch->Condition, BBranch->Condition)) {
+        return false;
+      }
+      if (!IsPossibleUniquePtrEquivalent(ABranch->SwitchValues,
+                                         BBranch->SwitchValues)) {
+        return false;
+      }
+      if (!IsPossibleCodeEquivalent(ABranch->Code, BBranch->Code)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  // Checks if values referred to by pointers are identical, allowing the code
+  // to also be nullptr
+  template<typename T>
+  static bool IsPossibleUniquePtrEquivalent(std::unique_ptr<T>& A,
+                                            std::unique_ptr<T>& B) {
+    if (A == B) {
+      return true;
+    }
+    if (!A || !B) {
+      return false;
+    }
+    return *A == *B;
+  }
+
+  // Checks if code is equivalent, allowing the code to also be nullptr
+  static bool IsPossibleCodeEquivalent(wasm::Expression* A,
+                                       wasm::Expression* B) {
+    if (A == B) {
+      return true;
+    }
+    if (!A || !B) {
+      return false;
+    }
+    return IsCodeEquivalent(A, B);
+  }
+
+  static bool IsCodeEquivalent(wasm::Expression* A, wasm::Expression* B) {
+    return wasm::ExpressionAnalyzer::equal(A, B);
+  }
+
+  // Merges one branch into another. Valid under the assumption that the
+  // blocks they reach are identical, and so one branch is enough for both
+  // with a unified condition.
+  // Only one is allowed to have code, as the code may have side effects,
+  // and we don't have a way to order or resolve those, unless the code
+  // is equivalent.
+  void MergeBranchInto(Branch* Curr, Branch* Into) {
+    assert(Curr != Into);
+    if (Curr->SwitchValues) {
+      if (!Into->SwitchValues) {
+        assert(!Into->Condition);
+        // Merging into the already-default, nothing to do.
+      } else {
+        Into->SwitchValues->insert(Into->SwitchValues->end(),
+                                   Curr->SwitchValues->begin(),
+                                   Curr->SwitchValues->end());
+      }
+    } else {
+      if (!Curr->Condition) {
+        // This is now the new default. Whether Into has a condition
+        // or switch values, remove them all to make us the default.
+        Into->Condition = nullptr;
+        Into->SwitchValues.reset();
+      } else if (!Into->Condition) {
+        // Nothing to do, already the default.
+      } else {
+        assert(!Into->SwitchValues);
+        // Merge them, checking both.
+        Into->Condition =
+          wasm::Builder(*Parent->Module)
+            .makeBinary(wasm::OrInt32, Into->Condition, Curr->Condition);
+      }
+    }
+    if (!Curr->Code) {
+      // No code to merge in.
+    } else if (!Into->Code) {
+      // Just use the code being merged in.
+      Into->Code = Curr->Code;
+    } else {
+      assert(IsCodeEquivalent(Into->Code, Curr->Code));
+      // Keep the code already there, either is fine.
+    }
+  }
+
+  // Hashes the direct block contents, but not Relooper internals
+  // (like Shapes). Only partially hashes the branches out, no
+  // recursion: hashes the branch infos, looks at raw pointers
+  // for the blocks.
+  size_t Hash(Block* Curr) {
+    auto digest = wasm::ExpressionAnalyzer::hash(Curr->Code);
+    wasm::rehash(digest, uint8_t(1));
+    if (Curr->SwitchCondition) {
+      wasm::hash_combine(digest,
+                         wasm::ExpressionAnalyzer::hash(Curr->SwitchCondition));
+    }
+    wasm::rehash(digest, uint8_t(2));
+    for (auto& Pair : Curr->BranchesOut) {
+      // Hash the Block* as a pointer TODO: full hash?
+      wasm::rehash(digest, reinterpret_cast<size_t>(Pair.first));
+      // Hash the Branch info properly
+      wasm::hash_combine(digest, Hash(Pair.second));
+    }
+    return digest;
+  }
+
+  // Hashes the direct block contents, but not Relooper internals
+  // (like Shapes).
+  size_t Hash(Branch* Curr) {
+    auto digest = wasm::hash(0);
+    if (Curr->SwitchValues) {
+      for (auto i : *Curr->SwitchValues) {
+        wasm::rehash(digest, i); // TODO hash i
+      }
+    } else {
+      if (Curr->Condition) {
+        wasm::hash_combine(digest,
+                           wasm::ExpressionAnalyzer::hash(Curr->Condition));
+      }
+    }
+    wasm::rehash(digest, uint8_t(1));
+    if (Curr->Code) {
+      wasm::hash_combine(digest, wasm::ExpressionAnalyzer::hash(Curr->Code));
+    }
+    return digest;
+  }
+};
+
+} // namespace
+
+void Relooper::Calculate(Block* Entry) {
+  // Optimize.
+  Optimizer(this, Entry);
+
+  // Find live blocks.
+  Liveness Live(this);
+  Live.FindLive(Entry);
+
+  // Add incoming branches from live blocks, ignoring dead code
+  for (unsigned i = 0; i < Blocks.size(); i++) {
+    Block* Curr = Blocks[i].get();
+    if (!contains(Live.Live, Curr)) {
+      continue;
+    }
+    for (auto& iter : Curr->BranchesOut) {
+      iter.first->BranchesIn.insert(Curr);
+    }
+  }
+
+  // Recursively process the graph
+
+  struct Analyzer : public RelooperRecursor {
+    Analyzer(Relooper* Parent) : RelooperRecursor(Parent) {}
+
+    // Create a list of entries from a block. If LimitTo is provided, only
+    // results in that set will appear
+    void GetBlocksOut(Block* Source,
+                      BlockSet& Entries,
+                      BlockSet* LimitTo = nullptr) {
+      for (auto& iter : Source->BranchesOut) {
+        if (!LimitTo || contains(*LimitTo, iter.first)) {
+          Entries.insert(iter.first);
+        }
+      }
+    }
+
+    // Converts/processes all branchings to a specific target
+    void Solipsize(Block* Target,
+                   Branch::FlowType Type,
+                   Shape* Ancestor,
+                   BlockSet& From) {
+      PrintDebug("Solipsizing branches into %d\n", Target->Id);
+      DebugDump(From, "  relevant to solipsize: ");
+      for (auto iter = Target->BranchesIn.begin();
+           iter != Target->BranchesIn.end();) {
+        Block* Prior = *iter;
+        if (!contains(From, Prior)) {
+          iter++;
+          continue;
+        }
+        Branch* PriorOut = Prior->BranchesOut[Target];
+        PriorOut->Ancestor = Ancestor;
+        PriorOut->Type = Type;
+        iter++; // carefully increment iter before erasing
+        Target->BranchesIn.erase(Prior);
+        Target->ProcessedBranchesIn.insert(Prior);
+        Prior->BranchesOut.erase(Target);
+        Prior->ProcessedBranchesOut[Target] = PriorOut;
+        PrintDebug("  eliminated branch from %d\n", Prior->Id);
+      }
+    }
+
+    Shape* MakeSimple(BlockSet& Blocks, Block* Inner, BlockSet& NextEntries) {
+      PrintDebug("creating simple block with block #%d\n", Inner->Id);
+      SimpleShape* Simple = Parent->AddSimpleShape();
+      Simple->Inner = Inner;
+      Inner->Parent = Simple;
+      if (Blocks.size() > 1) {
+        Blocks.erase(Inner);
+        GetBlocksOut(Inner, NextEntries, &Blocks);
+        BlockSet JustInner;
+        JustInner.insert(Inner);
+        for (auto* Next : NextEntries) {
+          Solipsize(Next, Branch::Break, Simple, JustInner);
+        }
+      }
+      return Simple;
+    }
+
+    Shape*
+    MakeLoop(BlockSet& Blocks, BlockSet& Entries, BlockSet& NextEntries) {
+      // Find the inner blocks in this loop. Proceed backwards from the entries
+      // until you reach a seen block, collecting as you go.
+      BlockSet InnerBlocks;
+      BlockSet Queue = Entries;
+      while (Queue.size() > 0) {
+        Block* Curr = *(Queue.begin());
+        Queue.erase(Queue.begin());
+        if (!contains(InnerBlocks, Curr)) {
+          // This element is new, mark it as inner and remove from outer
+          InnerBlocks.insert(Curr);
+          Blocks.erase(Curr);
+          // Add the elements prior to it
+          for (auto* Prev : Curr->BranchesIn) {
+            Queue.insert(Prev);
+          }
+#if 0
+          // Add elements it leads to, if they are dead ends. There is no reason not to hoist dead ends
+          // into loops, as it can avoid multiple entries after the loop
+          for (auto iter = Curr->BranchesOut.begin(); iter != Curr->BranchesOut.end(); iter++) {
+            Block* Target = iter->first;
+            if (Target->BranchesIn.size() <= 1 && Target->BranchesOut.size() == 0) {
+              Queue.insert(Target);
+            }
+          }
+#endif
+        }
+      }
+      assert(InnerBlocks.size() > 0);
+
+      for (auto* Curr : InnerBlocks) {
+        for (auto& iter : Curr->BranchesOut) {
+          Block* Possible = iter.first;
+          if (!contains(InnerBlocks, Possible)) {
+            NextEntries.insert(Possible);
+          }
+        }
+      }
+
+#if 0
+      // We can avoid multiple next entries by hoisting them into the loop.
+      if (NextEntries.size() > 1) {
+        BlockBlockSetMap IndependentGroups;
+        FindIndependentGroups(NextEntries, IndependentGroups, &InnerBlocks);
+
+        while (IndependentGroups.size() > 0 && NextEntries.size() > 1) {
+          Block* Min = nullptr;
+          int MinSize = 0;
+          for (auto iter = IndependentGroups.begin(); iter != IndependentGroups.end(); iter++) {
+            Block* Entry = iter->first;
+            BlockSet &Blocks = iter->second;
+            if (!Min || Blocks.size() < MinSize) { // TODO: code size, not # of blocks
+              Min = Entry;
+              MinSize = Blocks.size();
+            }
+          }
+          // check how many new entries this would cause
+          BlockSet &Hoisted = IndependentGroups[Min];
+          bool abort = false;
+          for (auto iter = Hoisted.begin(); iter != Hoisted.end() && !abort; iter++) {
+            Block* Curr = *iter;
+            for (auto iter = Curr->BranchesOut.begin(); iter != Curr->BranchesOut.end(); iter++) {
+              Block* Target = iter->first;
+              if (!contains(Hoisted, Target) && !contains(NextEntries, Target)) {
+                // abort this hoisting
+                abort = true;
+                break;
+              }
+            }
+          }
+          if (abort) {
+            IndependentGroups.erase(Min);
+            continue;
+          }
+          // hoist this entry
+          PrintDebug("hoisting %d into loop\n", Min->Id);
+          NextEntries.erase(Min);
+          for (auto iter = Hoisted.begin(); iter != Hoisted.end(); iter++) {
+            Block* Curr = *iter;
+            InnerBlocks.insert(Curr);
+            Blocks.erase(Curr);
+          }
+          IndependentGroups.erase(Min);
+        }
+      }
+#endif
+
+      PrintDebug("creating loop block:\n", 0);
+      DebugDump(InnerBlocks, "  inner blocks:");
+      DebugDump(Entries, "  inner entries:");
+      DebugDump(Blocks, "  outer blocks:");
+      DebugDump(NextEntries, "  outer entries:");
+
+      LoopShape* Loop = Parent->AddLoopShape();
+
+      // Solipsize the loop, replacing with break/continue and marking branches
+      // as Processed (will not affect later calculations) A. Branches to the
+      // loop entries become a continue to this shape
+      for (auto* Entry : Entries) {
+        Solipsize(Entry, Branch::Continue, Loop, InnerBlocks);
+      }
+      // B. Branches to outside the loop (a next entry) become breaks on this
+      // shape
+      for (auto* Next : NextEntries) {
+        Solipsize(Next, Branch::Break, Loop, InnerBlocks);
+      }
+      // Finish up
+      Shape* Inner = Process(InnerBlocks, Entries);
+      Loop->Inner = Inner;
+      Loop->Entries = Entries;
+      return Loop;
+    }
+
+    // For each entry, find the independent group reachable by it. The
+    // independent group is the entry itself, plus all the blocks it can reach
+    // that cannot be directly reached by another entry. Note that we ignore
+    // directly reaching the entry itself by another entry.
+    //   @param Ignore - previous blocks that are irrelevant
+    void FindIndependentGroups(BlockSet& Entries,
+                               BlockBlockSetMap& IndependentGroups,
+                               BlockSet* Ignore = nullptr) {
+      typedef std::map<Block*, Block*> BlockBlockMap;
+
+      struct HelperClass {
+        BlockBlockSetMap& IndependentGroups;
+        // For each block, which entry it belongs to. We have reached it from
+        // there.
+        BlockBlockMap Ownership;
+
+        HelperClass(BlockBlockSetMap& IndependentGroupsInit)
+          : IndependentGroups(IndependentGroupsInit) {}
+        void InvalidateWithChildren(Block* New) { // TODO: rename New
+          // Being in the list means you need to be invalidated
+          BlockList ToInvalidate;
+          ToInvalidate.push_back(New);
+          while (ToInvalidate.size() > 0) {
+            Block* Invalidatee = ToInvalidate.front();
+            ToInvalidate.pop_front();
+            Block* Owner = Ownership[Invalidatee];
+            // Owner may have been invalidated, do not add to IndependentGroups!
+            if (contains(IndependentGroups, Owner)) {
+              IndependentGroups[Owner].erase(Invalidatee);
+            }
+            // may have been seen before and invalidated already
+            if (Ownership[Invalidatee]) {
+              Ownership[Invalidatee] = nullptr;
+              for (auto& iter : Invalidatee->BranchesOut) {
+                Block* Target = iter.first;
+                auto Known = Ownership.find(Target);
+                if (Known != Ownership.end()) {
+                  Block* TargetOwner = Known->second;
+                  if (TargetOwner) {
+                    ToInvalidate.push_back(Target);
+                  }
+                }
+              }
+            }
+          }
+        }
+      };
+      HelperClass Helper(IndependentGroups);
+
+      // We flow out from each of the entries, simultaneously.
+      // When we reach a new block, we add it as belonging to the one we got to
+      // it from. If we reach a new block that is already marked as belonging to
+      // someone, it is reachable by two entries and is not valid for any of
+      // them. Remove it and all it can reach that have been visited.
+
+      // Being in the queue means we just added this item, and we need to add
+      // its children
+      BlockList Queue;
+      for (auto* Entry : Entries) {
+        Helper.Ownership[Entry] = Entry;
+        IndependentGroups[Entry].insert(Entry);
+        Queue.push_back(Entry);
+      }
+      while (Queue.size() > 0) {
+        Block* Curr = Queue.front();
+        Queue.pop_front();
+        // Curr must be in the ownership map if we are in the queue
+        Block* Owner = Helper.Ownership[Curr];
+        if (!Owner) {
+          // we have been invalidated meanwhile after being reached from two
+          // entries
+          continue;
+        }
+        // Add all children
+        for (auto& iter : Curr->BranchesOut) {
+          Block* New = iter.first;
+          auto Known = Helper.Ownership.find(New);
+          if (Known == Helper.Ownership.end()) {
+            // New node. Add it, and put it in the queue
+            Helper.Ownership[New] = Owner;
+            IndependentGroups[Owner].insert(New);
+            Queue.push_back(New);
+            continue;
+          }
+          Block* NewOwner = Known->second;
+          if (!NewOwner) {
+            continue; // We reached an invalidated node
+          }
+          if (NewOwner != Owner) {
+            // Invalidate this and all reachable that we have seen - we reached
+            // this from two locations
+            Helper.InvalidateWithChildren(New);
+          }
+          // otherwise, we have the same owner, so do nothing
+        }
+      }
+
+      // Having processed all the interesting blocks, we remain with just one
+      // potential issue: If a->b, and a was invalidated, but then b was later
+      // reached by someone else, we must invalidate b. To check for this, we go
+      // over all elements in the independent groups, if an element has a parent
+      // which does *not* have the same owner, we must remove it and all its
+      // children.
+
+      for (auto* Entry : Entries) {
+        BlockSet& CurrGroup = IndependentGroups[Entry];
+        BlockList ToInvalidate;
+        for (auto* Child : CurrGroup) {
+          for (auto* Parent : Child->BranchesIn) {
+            if (Ignore && contains(*Ignore, Parent)) {
+              continue;
+            }
+            if (Helper.Ownership[Parent] != Helper.Ownership[Child]) {
+              ToInvalidate.push_back(Child);
+            }
+          }
+        }
+        while (ToInvalidate.size() > 0) {
+          Block* Invalidatee = ToInvalidate.front();
+          ToInvalidate.pop_front();
+          Helper.InvalidateWithChildren(Invalidatee);
+        }
+      }
+
+      // Remove empty groups
+      for (auto* Entry : Entries) {
+        if (IndependentGroups[Entry].size() == 0) {
+          IndependentGroups.erase(Entry);
+        }
+      }
+
+#ifdef RELOOPER_DEBUG
+      PrintDebug("Investigated independent groups:\n");
+      for (auto& iter : IndependentGroups) {
+        DebugDump(iter.second, " group: ");
+      }
+#endif
+    }
+
+    Shape* MakeMultiple(BlockSet& Blocks,
+                        BlockSet& Entries,
+                        BlockBlockSetMap& IndependentGroups,
+                        BlockSet& NextEntries,
+                        bool IsCheckedMultiple) {
+      PrintDebug("creating multiple block with %d inner groups\n",
+                 IndependentGroups.size());
+      MultipleShape* Multiple = Parent->AddMultipleShape();
+      BlockSet CurrEntries;
+      for (auto& iter : IndependentGroups) {
+        Block* CurrEntry = iter.first;
+        BlockSet& CurrBlocks = iter.second;
+        PrintDebug("  multiple group with entry %d:\n", CurrEntry->Id);
+        DebugDump(CurrBlocks, "    ");
+        // Create inner block
+        CurrEntries.clear();
+        CurrEntries.insert(CurrEntry);
+        for (auto* CurrInner : CurrBlocks) {
+          // Remove the block from the remaining blocks
+          Blocks.erase(CurrInner);
+          // Find new next entries and fix branches to them
+          for (auto iter = CurrInner->BranchesOut.begin();
+               iter != CurrInner->BranchesOut.end();) {
+            Block* CurrTarget = iter->first;
+            auto Next = iter;
+            Next++;
+            if (!contains(CurrBlocks, CurrTarget)) {
+              NextEntries.insert(CurrTarget);
+              Solipsize(CurrTarget, Branch::Break, Multiple, CurrBlocks);
+            }
+            iter = Next; // increment carefully because Solipsize can remove us
+          }
+        }
+        Multiple->InnerMap[CurrEntry->Id] = Process(CurrBlocks, CurrEntries);
+        if (IsCheckedMultiple) {
+          CurrEntry->IsCheckedMultipleEntry = true;
+        }
+      }
+      DebugDump(Blocks, "  remaining blocks after multiple:");
+      // Add entries not handled as next entries, they are deferred
+      for (auto* Entry : Entries) {
+        if (!contains(IndependentGroups, Entry)) {
+          NextEntries.insert(Entry);
+        }
+      }
+      return Multiple;
+    }
+
+    // Main function.
+    // Process a set of blocks with specified entries, returns a shape
+    // The Make* functions receive a NextEntries. If they fill it with data,
+    // those are the entries for the
+    //   ->Next block on them, and the blocks are what remains in Blocks (which
+    //   Make* modify). In this way we avoid recursing on Next (imagine a long
+    //   chain of Simples, if we recursed we could blow the stack).
+    Shape* Process(BlockSet& Blocks, BlockSet& InitialEntries) {
+      PrintDebug("Process() called\n", 0);
+      BlockSet* Entries = &InitialEntries;
+      BlockSet TempEntries[2];
+      int CurrTempIndex = 0;
+      BlockSet* NextEntries;
+      Shape* Ret = nullptr;
+      Shape* Prev = nullptr;
+#define Make(call)                                                             \
+  Shape* Temp = call;                                                          \
+  if (Prev)                                                                    \
+    Prev->Next = Temp;                                                         \
+  if (!Ret)                                                                    \
+    Ret = Temp;                                                                \
+  if (!NextEntries->size()) {                                                  \
+    PrintDebug("Process() returning\n", 0);                                    \
+    return Ret;                                                                \
+  }                                                                            \
+  Prev = Temp;                                                                 \
+  Entries = NextEntries;                                                       \
+  continue;
+      while (1) {
+        PrintDebug("Process() running\n", 0);
+        DebugDump(Blocks, "  blocks : ");
+        DebugDump(*Entries, "  entries: ");
+
+        CurrTempIndex = 1 - CurrTempIndex;
+        NextEntries = &TempEntries[CurrTempIndex];
+        NextEntries->clear();
+
+        if (Entries->size() == 0) {
+          return Ret;
+        }
+        if (Entries->size() == 1) {
+          Block* Curr = *(Entries->begin());
+          if (Curr->BranchesIn.size() == 0) {
+            // One entry, no looping ==> Simple
+            Make(MakeSimple(Blocks, Curr, *NextEntries));
+          }
+          // One entry, looping ==> Loop
+          Make(MakeLoop(Blocks, *Entries, *NextEntries));
+        }
+
+        // More than one entry, try to eliminate through a Multiple groups of
+        // independent blocks from an entry/ies. It is important to remove
+        // through multiples as opposed to looping since the former is more
+        // performant.
+        BlockBlockSetMap IndependentGroups;
+        FindIndependentGroups(*Entries, IndependentGroups);
+
+        PrintDebug("Independent groups: %d\n", IndependentGroups.size());
+
+        if (IndependentGroups.size() > 0) {
+          // We can handle a group in a multiple if its entry cannot be reached
+          // by another group. Note that it might be reachable by itself - a
+          // loop. But that is fine, we will create a loop inside the multiple
+          // block, which is both the performant order to do it, and preserves
+          // the property that a loop will always reach an entry.
+          for (auto iter = IndependentGroups.begin();
+               iter != IndependentGroups.end();) {
+            Block* Entry = iter->first;
+            BlockSet& Group = iter->second;
+            auto curr = iter++; // iterate carefully, we may delete
+            for (auto iterBranch = Entry->BranchesIn.begin();
+                 iterBranch != Entry->BranchesIn.end();
+                 iterBranch++) {
+              Block* Origin = *iterBranch;
+              if (!contains(Group, Origin)) {
+                // Reached from outside the group, so we cannot handle this
+                PrintDebug("Cannot handle group with entry %d because of "
+                           "incoming branch from %d\n",
+                           Entry->Id,
+                           Origin->Id);
+                IndependentGroups.erase(curr);
+                break;
+              }
+            }
+          }
+
+          // As an optimization, if we have 2 independent groups, and one is a
+          // small dead end, we can handle only that dead end. The other then
+          // becomes a Next - without nesting in the code and recursion in the
+          // analysis.
+          // TODO: if the larger is the only dead end, handle that too
+          // TODO: handle >2 groups
+          // TODO: handle not just dead ends, but also that do not branch to the
+          //       NextEntries. However, must be careful
+          //       there since we create a Next, and that Next can prevent
+          //       eliminating a break (since we no longer naturally reach the
+          //       same place), which may necessitate a one-time loop, which
+          //       makes the unnesting pointless.
+          if (IndependentGroups.size() == 2) {
+            // Find the smaller one
+            auto iter = IndependentGroups.begin();
+            Block* SmallEntry = iter->first;
+            int SmallSize = iter->second.size();
+            iter++;
+            Block* LargeEntry = iter->first;
+            int LargeSize = iter->second.size();
+            // ignore the case where they are identical - keep things
+            // symmetrical there
+            if (SmallSize != LargeSize) {
+              if (SmallSize > LargeSize) {
+                Block* Temp = SmallEntry;
+                SmallEntry = LargeEntry;
+                // Note: we did not flip the Sizes too, they are now invalid.
+                // TODO: use the smaller size as a limit?
+                LargeEntry = Temp;
+              }
+              // Check if dead end
+              bool DeadEnd = true;
+              BlockSet& SmallGroup = IndependentGroups[SmallEntry];
+              for (auto* Curr : SmallGroup) {
+                for (auto& iter : Curr->BranchesOut) {
+                  Block* Target = iter.first;
+                  if (!contains(SmallGroup, Target)) {
+                    DeadEnd = false;
+                    break;
+                  }
+                }
+                if (!DeadEnd) {
+                  break;
+                }
+              }
+              if (DeadEnd) {
+                PrintDebug("Removing nesting by not handling large group "
+                           "because small group is dead end\n",
+                           0);
+                IndependentGroups.erase(LargeEntry);
+              }
+            }
+          }
+
+          PrintDebug("Handleable independent groups: %d\n",
+                     IndependentGroups.size());
+
+          if (IndependentGroups.size() > 0) {
+            // Some groups removable ==> Multiple
+            // This is a checked multiple if it has an entry that is an entry to
+            // this Process call, that is, if we can reach it from outside this
+            // set of blocks, then we must check the label variable to do so.
+            // Otherwise, if it is just internal blocks, those can always be
+            // jumped to forward, without using the label variable
+            bool Checked = false;
+            for (auto* Entry : *Entries) {
+              if (InitialEntries.count(Entry)) {
+                Checked = true;
+                break;
+              }
+            }
+            Make(MakeMultiple(
+              Blocks, *Entries, IndependentGroups, *NextEntries, Checked));
+          }
+        }
+        // No independent groups, must be loopable ==> Loop
+        Make(MakeLoop(Blocks, *Entries, *NextEntries));
+      }
+    }
+  };
+
+  // Main
+
+  BlockSet AllBlocks;
+  for (auto* Curr : Live.Live) {
+    AllBlocks.insert(Curr);
+#ifdef RELOOPER_DEBUG
+    PrintDebug("Adding block %d (%s)\n", Curr->Id, Curr->Code);
+#endif
+  }
+
+  BlockSet Entries;
+  Entries.insert(Entry);
+  Root = Analyzer(this).Process(AllBlocks, Entries);
+  assert(Root);
+}
+
+wasm::Expression* Relooper::Render(RelooperBuilder& Builder) {
+  assert(Root);
+  auto* ret = Root->Render(Builder, false);
+  // we may use the same name for more than one block in HandleFollowupMultiples
+  wasm::UniqueNameMapper::uniquify(ret);
+  return ret;
+}
+
+#ifdef RELOOPER_DEBUG
+// Debugging
+
+void Debugging::Dump(Block* Curr, const char* prefix) {
+  if (prefix)
+    std::cout << prefix << ": ";
+  std::cout << Curr->Id << " [code " << *Curr->Code << "] [switch? "
+            << !!Curr->SwitchCondition << "]\n";
+  for (auto iter2 = Curr->BranchesOut.begin(); iter2 != Curr->BranchesOut.end();
+       iter2++) {
+    Block* Other = iter2->first;
+    Branch* Br = iter2->second;
+    std::cout << "  -> " << Other->Id << ' ';
+    if (Br->Condition) {
+      std::cout << "[if " << *Br->Condition << "] ";
+    } else if (Br->SwitchValues) {
+      std::cout << "[cases ";
+      for (auto x : *Br->SwitchValues) {
+        std::cout << x << ' ';
+      }
+      std::cout << "] ";
+    } else {
+      std::cout << "[default] ";
+    }
+    if (Br->Code)
+      std::cout << "[phi " << *Br->Code << "] ";
+    std::cout << '\n';
+  }
+  std::cout << '\n';
+}
+
+void Debugging::Dump(BlockSet& Blocks, const char* prefix) {
+  if (prefix)
+    std::cout << prefix << ": ";
+  for (auto* Curr : Blocks) {
+    Dump(Curr);
+  }
+}
+
+void Debugging::Dump(Shape* S, const char* prefix) {
+  if (prefix)
+    std::cout << prefix << ": ";
+  if (!S) {
+    printf(" (null)\n");
+    return;
+  }
+  printf(" %d ", S->Id);
+  if (SimpleShape* Simple = Shape::IsSimple(S)) {
+    printf("<< Simple with block %d\n", Simple->Inner->Id);
+  } else if (MultipleShape* Multiple = Shape::IsMultiple(S)) {
+    printf("<< Multiple\n");
+    for (auto& iter : Multiple->InnerMap) {
+      printf("     with entry %d\n", iter.first);
+    }
+  } else if (Shape::IsLoop(S)) {
+    printf("<< Loop\n");
+  } else {
+    abort();
+  }
+}
+
+static void PrintDebug(const char* Format, ...) {
+  printf("// ");
+  va_list Args;
+  va_start(Args, Format);
+  vprintf(Format, Args);
+  va_end(Args);
+}
+#endif
+
+} // namespace CFG
diff --git a/binaryen/src/cfg/Relooper.h b/binaryen/src/cfg/Relooper.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/cfg/Relooper.h
@@ -0,0 +1,438 @@
+/*
+ * 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.
+ */
+
+/*
+This is an optimized C++ implemention of the Relooper algorithm originally
+developed as part of Emscripten. This implementation includes optimizations
+added since the original academic paper [1] was published about it.
+
+[1] Alon Zakai. 2011. Emscripten: an LLVM-to-JavaScript compiler. In Proceedings
+of the ACM international conference companion on Object oriented programming
+systems languages and applications companion (SPLASH '11). ACM, New York, NY,
+USA, 301-312. DOI=10.1145/2048147.2048224
+http://doi.acm.org/10.1145/2048147.2048224
+*/
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <deque>
+#include <list>
+#include <map>
+#include <memory>
+#include <set>
+
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace CFG {
+
+class RelooperBuilder : public wasm::Builder {
+  wasm::Index labelHelper;
+
+public:
+  RelooperBuilder(wasm::Module& wasm, wasm::Index labelHelper)
+    : wasm::Builder(wasm), labelHelper(labelHelper) {}
+
+  wasm::LocalGet* makeGetLabel() {
+    return makeLocalGet(labelHelper, wasm::Type::i32);
+  }
+  wasm::LocalSet* makeSetLabel(wasm::Index value) {
+    return makeLocalSet(labelHelper, makeConst(wasm::Literal(int32_t(value))));
+  }
+  wasm::Binary* makeCheckLabel(wasm::Index value) {
+    return makeBinary(
+      wasm::EqInt32, makeGetLabel(), makeConst(wasm::Literal(int32_t(value))));
+  }
+
+  // breaks are on blocks, as they can be specific, we make one wasm block per
+  // basic block
+  wasm::Break* makeBlockBreak(int id) {
+    return wasm::Builder::makeBreak(getBlockBreakName(id));
+  }
+  // continues are on shapes, as there is one per loop, and if we have more than
+  // one going there, it is irreducible control flow anyhow
+  wasm::Break* makeShapeContinue(int id) {
+    return wasm::Builder::makeBreak(getShapeContinueName(id));
+  }
+
+  wasm::Name getBlockBreakName(int id) {
+    return wasm::Name(std::string("block$") + std::to_string(id) + "$break");
+  }
+  wasm::Name getShapeContinueName(int id) {
+    return wasm::Name(std::string("shape$") + std::to_string(id) + "$continue");
+  }
+};
+
+struct Relooper;
+struct Block;
+struct Shape;
+
+// Info about a branching from one block to another
+struct Branch {
+  enum FlowType {
+    Direct = 0, // We will directly reach the right location through other
+                // means, no need for continue or break
+    Break = 1,
+    Continue = 2
+  };
+  // If not NULL, this shape is the relevant one for purposes of getting to the
+  // target block. We break or continue on it
+  Shape* Ancestor = nullptr;
+  // If Ancestor is not NULL, this says whether to break or continue
+  Branch::FlowType Type;
+
+  // A branch either has a condition expression if the block ends in ifs, or if
+  // the block ends in a switch, then a list of indexes, which becomes the
+  // indexes in the table of the switch. If not a switch, the condition can be
+  // any expression (or nullptr for the branch taken when no other condition is
+  // true) A condition must not have side effects, as the Relooper can reorder
+  // or eliminate condition checking. This must not have side effects.
+  wasm::Expression* Condition;
+  // Switches are rare, so have just a pointer for their values. This contains
+  // the values for which the branch will be taken, or for the default it is
+  // simply not present.
+  std::unique_ptr<std::vector<wasm::Index>> SwitchValues;
+
+  // If provided, code that is run right before the branch is taken. This is
+  // useful for phis.
+  wasm::Expression* Code;
+
+  Branch(wasm::Expression* ConditionInit, wasm::Expression* CodeInit = nullptr);
+
+  Branch(std::vector<wasm::Index>&& ValuesInit,
+         wasm::Expression* CodeInit = nullptr);
+
+  // Emits code for branch
+  wasm::Expression*
+  Render(RelooperBuilder& Builder, Block* Target, bool SetLabel);
+};
+
+// like std::set, except that begin() -> end() iterates in the
+// order that elements were added to the set (not in the order
+// of operator<(T, T))
+template<typename T> struct InsertOrderedSet {
+  std::map<T, typename std::list<T>::iterator> Map;
+  std::list<T> List;
+
+  typedef typename std::list<T>::iterator iterator;
+  iterator begin() { return List.begin(); }
+  iterator end() { return List.end(); }
+
+  void erase(const T& val) {
+    auto it = Map.find(val);
+    if (it != Map.end()) {
+      List.erase(it->second);
+      Map.erase(it);
+    }
+  }
+
+  void erase(iterator position) {
+    Map.erase(*position);
+    List.erase(position);
+  }
+
+  // cheating a bit, not returning the iterator
+  void insert(const T& val) {
+    auto it = Map.find(val);
+    if (it == Map.end()) {
+      List.push_back(val);
+      Map.insert(std::make_pair(val, --List.end()));
+    }
+  }
+
+  size_t size() const { return Map.size(); }
+  bool empty() const { return Map.empty(); }
+
+  void clear() {
+    Map.clear();
+    List.clear();
+  }
+
+  size_t count(const T& val) const { return Map.count(val); }
+
+  InsertOrderedSet() = default;
+  InsertOrderedSet(const InsertOrderedSet& other) { *this = other; }
+  InsertOrderedSet& operator=(const InsertOrderedSet& other) {
+    clear();
+    for (auto i : other.List) {
+      insert(i); // inserting manually creates proper iterators
+    }
+    return *this;
+  }
+};
+
+// like std::map, except that begin() -> end() iterates in the
+// order that elements were added to the map (not in the order
+// of operator<(Key, Key))
+template<typename Key, typename T> struct InsertOrderedMap {
+  std::map<Key, typename std::list<std::pair<Key, T>>::iterator> Map;
+  std::list<std::pair<Key, T>> List;
+
+  T& operator[](const Key& k) {
+    auto it = Map.find(k);
+    if (it == Map.end()) {
+      List.push_back(std::make_pair(k, T()));
+      auto e = --List.end();
+      Map.insert(std::make_pair(k, e));
+      return e->second;
+    }
+    return it->second->second;
+  }
+
+  typedef typename std::list<std::pair<Key, T>>::iterator iterator;
+  iterator begin() { return List.begin(); }
+  iterator end() { return List.end(); }
+
+  void erase(const Key& k) {
+    auto it = Map.find(k);
+    if (it != Map.end()) {
+      List.erase(it->second);
+      Map.erase(it);
+    }
+  }
+
+  void erase(iterator position) { erase(position->first); }
+
+  void clear() {
+    Map.clear();
+    List.clear();
+  }
+
+  void swap(InsertOrderedMap<Key, T>& Other) {
+    Map.swap(Other.Map);
+    List.swap(Other.List);
+  }
+
+  size_t size() const { return Map.size(); }
+  bool empty() const { return Map.empty(); }
+  size_t count(const Key& k) const { return Map.count(k); }
+
+  InsertOrderedMap() = default;
+  InsertOrderedMap(InsertOrderedMap& other) {
+    abort(); // TODO, watch out for iterators
+  }
+  InsertOrderedMap& operator=(const InsertOrderedMap& other) {
+    abort(); // TODO, watch out for iterators
+  }
+  bool operator==(const InsertOrderedMap& other) {
+    return Map == other.Map && List == other.List;
+  }
+  bool operator!=(const InsertOrderedMap& other) { return !(*this == other); }
+};
+
+typedef InsertOrderedSet<Block*> BlockSet;
+typedef InsertOrderedMap<Block*, Branch*> BlockBranchMap;
+
+// Represents a basic block of code - some instructions that end with a
+// control flow modifier (a branch, return or throw).
+struct Block {
+  // Reference to the relooper containing this block.
+  Relooper* relooper;
+  // Branches become processed after we finish the shape relevant to them. For
+  // example, when we recreate a loop, branches to the loop start become
+  // continues and are now processed. When we calculate what shape to generate
+  // from a set of blocks, we ignore processed branches. Blocks own the Branch
+  // objects they use, and destroy them when done.
+  BlockBranchMap BranchesOut;
+  BlockSet BranchesIn;
+  BlockBranchMap ProcessedBranchesOut;
+  BlockSet ProcessedBranchesIn;
+  Shape* Parent = nullptr; // The shape we are directly inside
+  int Id = -1; // A unique identifier, defined when added to relooper
+  // The code in this block. This can be arbitrary wasm code, including internal
+  // control flow, it should just not branch to the outside
+  wasm::Expression* Code;
+  // If nullptr, then this block ends in ifs (or nothing). otherwise, this block
+  // ends in a switch, done on this condition
+  wasm::Expression* SwitchCondition;
+  // If true, we are a multiple entry, so reaching us requires setting the label
+  // variable
+  bool IsCheckedMultipleEntry;
+
+  Block(Relooper* relooper,
+        wasm::Expression* CodeInit,
+        wasm::Expression* SwitchConditionInit = nullptr);
+
+  // Add a branch: if the condition holds we branch (or if null, we branch if
+  // all others failed) Note that there can be only one branch from A to B (if
+  // you need multiple conditions for the branch, create a more interesting
+  // expression in the Condition). If a Block has no outgoing branches, the
+  // contents in Code must contain a terminating instruction, as the relooper
+  // doesn't know whether you want control flow to stop with an `unreachable` or
+  // a `return` or something else (if you forget to do this, control flow may
+  // continue into the block that happens to be emitted right after it).
+  // Internally, adding a branch only adds the outgoing branch. The matching
+  // incoming branch on the target is added by the Relooper itself as it works.
+  void AddBranchTo(Block* Target,
+                   wasm::Expression* Condition,
+                   wasm::Expression* Code = nullptr);
+
+  // Add a switch branch: if the switch condition is one of these values, we
+  // branch (or if the list is empty, we are the default) Note that there can be
+  // only one branch from A to B (if you need multiple values for the branch,
+  // that's what the array and default are for).
+  void AddSwitchBranchTo(Block* Target,
+                         std::vector<wasm::Index>&& Values,
+                         wasm::Expression* Code = nullptr);
+
+  // Emit code for the block, including its contents and branchings out
+  wasm::Expression* Render(RelooperBuilder& Builder, bool InLoop);
+};
+
+// Represents a structured control flow shape, one of
+//
+//  Simple: No control flow at all, just instructions in a single
+//          basic block.
+//
+//  Multiple: A shape with at least one entry. We may visit one of
+//            the entries, or none, before continuing to the next
+//            shape after this.
+//
+//  Loop: An infinite loop. We assume the property that a loop
+//        will always visit one of its entries, and so for example
+//        we cannot have a loop containing a multiple and nothing
+//        else (since we might not visit any of the multiple's
+//        blocks). Multiple entries are possible for the block,
+//        however, which is necessary for irreducible control
+//        flow, of course.
+//
+
+struct SimpleShape;
+struct MultipleShape;
+struct LoopShape;
+
+struct Shape {
+  // A unique identifier. Used to identify loops, labels are Lx where x is the
+  // Id. Defined when added to relooper
+  int Id = -1;
+  // The shape that will appear in the code right after this one
+  Shape* Next = nullptr;
+  // The shape that control flow gets to naturally (if there is Next, then this
+  // is Next)
+  Shape* Natural;
+
+  enum ShapeType { Simple, Multiple, Loop };
+  ShapeType Type;
+
+  Shape(ShapeType TypeInit) : Type(TypeInit) {}
+  virtual ~Shape() = default;
+
+  virtual wasm::Expression* Render(RelooperBuilder& Builder, bool InLoop) = 0;
+
+  static SimpleShape* IsSimple(Shape* It) {
+    return It && It->Type == Simple ? (SimpleShape*)It : NULL;
+  }
+  static MultipleShape* IsMultiple(Shape* It) {
+    return It && It->Type == Multiple ? (MultipleShape*)It : NULL;
+  }
+  static LoopShape* IsLoop(Shape* It) {
+    return It && It->Type == Loop ? (LoopShape*)It : NULL;
+  }
+};
+
+struct SimpleShape : public Shape {
+  Block* Inner = nullptr;
+
+  SimpleShape() : Shape(Simple) {}
+  wasm::Expression* Render(RelooperBuilder& Builder, bool InLoop) override;
+};
+
+typedef std::map<int, Shape*> IdShapeMap;
+
+struct MultipleShape : public Shape {
+  IdShapeMap InnerMap; // entry block ID -> shape
+
+  MultipleShape() : Shape(Multiple) {}
+
+  wasm::Expression* Render(RelooperBuilder& Builder, bool InLoop) override;
+};
+
+struct LoopShape : public Shape {
+  Shape* Inner = nullptr;
+
+  BlockSet Entries; // we must visit at least one of these
+
+  LoopShape() : Shape(Loop) {}
+  wasm::Expression* Render(RelooperBuilder& Builder, bool InLoop) override;
+};
+
+// Implements the relooper algorithm for a function's blocks.
+//
+// Usage:
+//  1. Instantiate this struct.
+//  2. Create the blocks you have. Each should have its
+//     branchings in specified (the branchings out will
+//     be calculated by the relooper).
+//  3. Call Render().
+//
+// Implementation details: The Relooper instance takes ownership of the blocks,
+// branches and shapes when created using the `AddBlock` etc. methods, and frees
+// them when done.
+struct Relooper {
+  wasm::Module* Module;
+  std::deque<std::unique_ptr<Block>> Blocks;
+  std::deque<std::unique_ptr<Branch>> Branches;
+  std::deque<std::unique_ptr<Shape>> Shapes;
+  Shape* Root;
+  bool MinSize;
+  int BlockIdCounter;
+  int ShapeIdCounter;
+
+  Relooper(wasm::Module* ModuleInit);
+
+  // Creates a new block associated with (and cleaned up along) this relooper.
+  Block* AddBlock(wasm::Expression* CodeInit,
+                  wasm::Expression* SwitchConditionInit = nullptr);
+  // Creates a new branch associated with (and cleaned up along) this relooper.
+  Branch* AddBranch(wasm::Expression* ConditionInit,
+                    wasm::Expression* CodeInit);
+  // Creates a new branch associated with (and cleaned up along) this relooper.
+  Branch* AddBranch(std::vector<wasm::Index>&& ValuesInit,
+                    wasm::Expression* CodeInit = nullptr);
+  // Creates a new simple shape associated with (and cleaned up along) this
+  // relooper.
+  SimpleShape* AddSimpleShape();
+  // Creates a new multiple shape associated with (and cleaned up along) this
+  // relooper.
+  MultipleShape* AddMultipleShape();
+  // Creates a new loop shape associated with (and cleaned up along) this
+  // relooper.
+  LoopShape* AddLoopShape();
+
+  // Calculates the shapes
+  void Calculate(Block* Entry);
+
+  // Renders the result.
+  wasm::Expression* Render(RelooperBuilder& Builder);
+
+  // Sets us to try to minimize size
+  void SetMinSize(bool MinSize_) { MinSize = MinSize_; }
+};
+
+typedef InsertOrderedMap<Block*, BlockSet> BlockBlockSetMap;
+
+#ifdef RELOOPER_DEBUG
+struct Debugging {
+  static void Dump(Block* Curr, const char* prefix = NULL);
+  static void Dump(BlockSet& Blocks, const char* prefix = NULL);
+  static void Dump(Shape* S, const char* prefix = NULL);
+};
+#endif
+
+} // namespace CFG
diff --git a/binaryen/src/cfg/cfg-traversal.h b/binaryen/src/cfg/cfg-traversal.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/cfg/cfg-traversal.h
@@ -0,0 +1,458 @@
+/*
+ * 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.
+ */
+
+//
+// Convert the AST to a CFG, while traversing it.
+//
+// Note that this is not the same as the relooper CFG. The relooper is
+// designed for compilation to an AST, this is for processing. There is
+// no built-in support for transforming this CFG into the AST back
+// again, it is just metadata on the side for computation purposes.
+//
+// Usage: As the traversal proceeds, you can note information and add it to
+// the current basic block using currBasicBlock, on the contents
+// property, whose type is user-defined.
+//
+
+#ifndef cfg_traversal_h
+#define cfg_traversal_h
+
+#include "wasm-traversal.h"
+#include "wasm.h"
+
+namespace wasm {
+
+template<typename SubType, typename VisitorType, typename Contents>
+struct CFGWalker : public ControlFlowWalker<SubType, VisitorType> {
+
+  // public interface
+
+  struct BasicBlock {
+    Contents contents; // custom contents
+    std::vector<BasicBlock*> out, in;
+  };
+
+  BasicBlock* entry; // the entry block
+
+  // override this with code to create a BasicBlock if necessary
+  BasicBlock* makeBasicBlock() { return new BasicBlock(); }
+
+  // internal details
+
+  std::vector<std::unique_ptr<BasicBlock>> basicBlocks; // all the blocks
+  // blocks that are the tops of loops, i.e., have backedges to them
+  std::vector<BasicBlock*> loopTops;
+
+  // traversal state
+  // the current block in play during traversal. can be nullptr if unreachable,
+  // but note that we don't do a deep unreachability analysis - just enough to
+  // avoid constructing obviously-unreachable blocks (we do a full reachability
+  // analysis on the CFG once it is constructed).
+  BasicBlock* currBasicBlock;
+  // a block or loop => its branches
+  std::map<Expression*, std::vector<BasicBlock*>> branches;
+  // stack of the last blocks of if conditions + the last blocks of if true
+  // bodies
+  std::vector<BasicBlock*> ifStack;
+  // stack of the first blocks of loops
+  std::vector<BasicBlock*> loopStack;
+  // stack of the last blocks of try bodies
+  std::vector<BasicBlock*> tryStack;
+  // stack of the first blocks of catch bodies
+  std::vector<BasicBlock*> catchStack;
+
+  void startBasicBlock() {
+    currBasicBlock = ((SubType*)this)->makeBasicBlock();
+    basicBlocks.push_back(std::unique_ptr<BasicBlock>(currBasicBlock));
+  }
+
+  void startUnreachableBlock() { currBasicBlock = nullptr; }
+
+  static void doStartUnreachableBlock(SubType* self, Expression** currp) {
+    self->startUnreachableBlock();
+  }
+
+  void link(BasicBlock* from, BasicBlock* to) {
+    if (!from || !to) {
+      return; // if one of them is not reachable, ignore
+    }
+    from->out.push_back(to);
+    to->in.push_back(from);
+  }
+
+  static void doEndBlock(SubType* self, Expression** currp) {
+    auto* curr = (*currp)->cast<Block>();
+    if (!curr->name.is()) {
+      return;
+    }
+    auto iter = self->branches.find(curr);
+    if (iter == self->branches.end()) {
+      return;
+    }
+    auto& origins = iter->second;
+    if (origins.size() == 0) {
+      return;
+    }
+    // we have branches to here, so we need a new block
+    auto* last = self->currBasicBlock;
+    self->startBasicBlock();
+    self->link(last, self->currBasicBlock); // fallthrough
+    // branches to the new one
+    for (auto* origin : origins) {
+      self->link(origin, self->currBasicBlock);
+    }
+    self->branches.erase(curr);
+  }
+
+  static void doStartIfTrue(SubType* self, Expression** currp) {
+    auto* last = self->currBasicBlock;
+    self->startBasicBlock();
+    self->link(last, self->currBasicBlock); // ifTrue
+    self->ifStack.push_back(last);          // the block before the ifTrue
+  }
+
+  static void doStartIfFalse(SubType* self, Expression** currp) {
+    self->ifStack.push_back(self->currBasicBlock); // the ifTrue fallthrough
+    self->startBasicBlock();
+    self->link(self->ifStack[self->ifStack.size() - 2],
+               self->currBasicBlock); // before if -> ifFalse
+  }
+
+  static void doEndIf(SubType* self, Expression** currp) {
+    auto* last = self->currBasicBlock;
+    self->startBasicBlock();
+    // last one is ifFalse's fallthrough if there was one, otherwise it's the
+    // ifTrue fallthrough
+    self->link(last, self->currBasicBlock);
+    if ((*currp)->cast<If>()->ifFalse) {
+      // we just linked ifFalse, need to link ifTrue to the end
+      self->link(self->ifStack.back(), self->currBasicBlock);
+      self->ifStack.pop_back();
+    } else {
+      // no ifFalse, so add a fallthrough for if the if is not taken
+      self->link(self->ifStack.back(), self->currBasicBlock);
+    }
+    self->ifStack.pop_back();
+  }
+
+  static void doStartLoop(SubType* self, Expression** currp) {
+    auto* last = self->currBasicBlock;
+    self->startBasicBlock();
+    // a loop with no backedges would still be counted here, but oh well
+    self->loopTops.push_back(self->currBasicBlock);
+    self->link(last, self->currBasicBlock);
+    self->loopStack.push_back(self->currBasicBlock);
+  }
+
+  static void doEndLoop(SubType* self, Expression** currp) {
+    auto* last = self->currBasicBlock;
+    self->startBasicBlock();
+    self->link(last, self->currBasicBlock); // fallthrough
+    auto* curr = (*currp)->cast<Loop>();
+    // branches to the top of the loop
+    if (curr->name.is()) {
+      auto* loopStart = self->loopStack.back();
+      auto& origins = self->branches[curr];
+      for (auto* origin : origins) {
+        self->link(origin, loopStart);
+      }
+      self->branches.erase(curr);
+    }
+    self->loopStack.pop_back();
+  }
+
+  static void doEndBreak(SubType* self, Expression** currp) {
+    auto* curr = (*currp)->cast<Break>();
+    self->branches[self->findBreakTarget(curr->name)].push_back(
+      self->currBasicBlock); // branch to the target
+    if (curr->condition) {
+      auto* last = self->currBasicBlock;
+      self->startBasicBlock();
+      self->link(last, self->currBasicBlock); // we might fall through
+    } else {
+      self->startUnreachableBlock();
+    }
+  }
+
+  static void doEndSwitch(SubType* self, Expression** currp) {
+    auto* curr = (*currp)->cast<Switch>();
+    // we might see the same label more than once; do not spam branches
+    std::set<Name> seen;
+    for (Name target : curr->targets) {
+      if (!seen.count(target)) {
+        self->branches[self->findBreakTarget(target)].push_back(
+          self->currBasicBlock); // branch to the target
+        seen.insert(target);
+      }
+    }
+    if (!seen.count(curr->default_)) {
+      self->branches[self->findBreakTarget(curr->default_)].push_back(
+        self->currBasicBlock); // branch to the target
+    }
+    self->startUnreachableBlock();
+  }
+
+  static void doEndCall(SubType* self, Expression** currp) {
+    // Every call can possibly throw, but we don't end the current basic block
+    // unless the call is within a try-catch, because the CFG will have too many
+    // blocks that way, and if an exception is thrown, the function will be
+    // exited anyway.
+    if (!self->catchStack.empty()) {
+      auto* last = self->currBasicBlock;
+      self->startBasicBlock();
+      self->link(last, self->currBasicBlock);    // exception not thrown
+      self->link(last, self->catchStack.back()); // exception thrown
+    }
+  }
+
+  static void doStartTry(SubType* self, Expression** currp) {
+    auto* last = self->currBasicBlock;
+    self->startBasicBlock(); // catch body's first block
+    self->catchStack.push_back(self->currBasicBlock);
+    self->currBasicBlock = last; // reset to the current block
+  }
+
+  static void doStartCatch(SubType* self, Expression** currp) {
+    self->tryStack.push_back(self->currBasicBlock); // last block of try body
+    self->currBasicBlock = self->catchStack.back();
+    self->catchStack.pop_back();
+  }
+
+  static void doEndTry(SubType* self, Expression** currp) {
+    auto* last = self->currBasicBlock;
+    self->startBasicBlock(); // continuation block after try-catch
+    // catch body's last block -> continuation block
+    self->link(last, self->currBasicBlock);
+    // try body's last block -> continuation block
+    self->link(self->tryStack.back(), self->currBasicBlock);
+    self->tryStack.pop_back();
+  }
+
+  static void doEndThrow(SubType* self, Expression** currp) {
+    // We unwind to the innermost catch, if any
+    if (!self->catchStack.empty()) {
+      self->link(self->currBasicBlock, self->catchStack.back());
+    }
+    self->startUnreachableBlock();
+  }
+
+  static void doEndBrOnExn(SubType* self, Expression** currp) {
+    auto* curr = (*currp)->cast<BrOnExn>();
+    self->branches[self->findBreakTarget(curr->name)].push_back(
+      self->currBasicBlock); // branch to the target
+    auto* last = self->currBasicBlock;
+    self->startBasicBlock();
+    self->link(last, self->currBasicBlock); // we might fall through
+  }
+
+  static void scan(SubType* self, Expression** currp) {
+    Expression* curr = *currp;
+
+    switch (curr->_id) {
+      case Expression::Id::BlockId: {
+        self->pushTask(SubType::doEndBlock, currp);
+        break;
+      }
+      case Expression::Id::IfId: {
+        self->pushTask(SubType::doEndIf, currp);
+        auto* ifFalse = curr->cast<If>()->ifFalse;
+        if (ifFalse) {
+          self->pushTask(SubType::scan, &curr->cast<If>()->ifFalse);
+          self->pushTask(SubType::doStartIfFalse, currp);
+        }
+        self->pushTask(SubType::scan, &curr->cast<If>()->ifTrue);
+        self->pushTask(SubType::doStartIfTrue, currp);
+        self->pushTask(SubType::scan, &curr->cast<If>()->condition);
+        return; // don't do anything else
+      }
+      case Expression::Id::LoopId: {
+        self->pushTask(SubType::doEndLoop, currp);
+        break;
+      }
+      case Expression::Id::BreakId: {
+        self->pushTask(SubType::doEndBreak, currp);
+        break;
+      }
+      case Expression::Id::SwitchId: {
+        self->pushTask(SubType::doEndSwitch, currp);
+        break;
+      }
+      case Expression::Id::ReturnId: {
+        self->pushTask(SubType::doStartUnreachableBlock, currp);
+        break;
+      }
+      case Expression::Id::UnreachableId: {
+        self->pushTask(SubType::doStartUnreachableBlock, currp);
+        break;
+      }
+      case Expression::Id::CallId:
+      case Expression::Id::CallIndirectId: {
+        self->pushTask(SubType::doEndCall, currp);
+        break;
+      }
+      case Expression::Id::TryId: {
+        self->pushTask(SubType::doEndTry, currp);
+        self->pushTask(SubType::scan, &curr->cast<Try>()->catchBody);
+        self->pushTask(SubType::doStartCatch, currp);
+        self->pushTask(SubType::scan, &curr->cast<Try>()->body);
+        self->pushTask(SubType::doStartTry, currp);
+        return; // don't do anything else
+      }
+      case Expression::Id::ThrowId:
+      case Expression::Id::RethrowId: {
+        self->pushTask(SubType::doEndThrow, currp);
+        break;
+      }
+      case Expression::Id::BrOnExnId: {
+        self->pushTask(SubType::doEndBrOnExn, currp);
+        break;
+      }
+      default: {}
+    }
+
+    ControlFlowWalker<SubType, VisitorType>::scan(self, currp);
+
+    switch (curr->_id) {
+      case Expression::Id::LoopId: {
+        self->pushTask(SubType::doStartLoop, currp);
+        break;
+      }
+      default: {}
+    }
+  }
+
+  void doWalkFunction(Function* func) {
+    basicBlocks.clear();
+    debugIds.clear();
+
+    startBasicBlock();
+    entry = currBasicBlock;
+    ControlFlowWalker<SubType, VisitorType>::doWalkFunction(func);
+
+    assert(branches.size() == 0);
+    assert(ifStack.size() == 0);
+    assert(loopStack.size() == 0);
+    assert(tryStack.size() == 0);
+    assert(catchStack.size() == 0);
+  }
+
+  std::unordered_set<BasicBlock*> findLiveBlocks() {
+    std::unordered_set<BasicBlock*> alive;
+    std::unordered_set<BasicBlock*> queue;
+    queue.insert(entry);
+    while (queue.size() > 0) {
+      auto iter = queue.begin();
+      auto* curr = *iter;
+      queue.erase(iter);
+      alive.insert(curr);
+      for (auto* out : curr->out) {
+        if (!alive.count(out)) {
+          queue.insert(out);
+        }
+      }
+    }
+    return alive;
+  }
+
+  void unlinkDeadBlocks(std::unordered_set<BasicBlock*> alive) {
+    for (auto& block : basicBlocks) {
+      if (!alive.count(block.get())) {
+        block->in.clear();
+        block->out.clear();
+        continue;
+      }
+      block->in.erase(std::remove_if(block->in.begin(),
+                                     block->in.end(),
+                                     [&alive](BasicBlock* other) {
+                                       return !alive.count(other);
+                                     }),
+                      block->in.end());
+      block->out.erase(std::remove_if(block->out.begin(),
+                                      block->out.end(),
+                                      [&alive](BasicBlock* other) {
+                                        return !alive.count(other);
+                                      }),
+                       block->out.end());
+    }
+  }
+
+  // TODO: utility method for optimizing cfg, removing empty blocks depending on
+  // their .content
+
+  std::map<BasicBlock*, size_t> debugIds;
+
+  void generateDebugIds() {
+    if (debugIds.size() > 0) {
+      return;
+    }
+    for (auto& block : basicBlocks) {
+      debugIds[block.get()] = debugIds.size();
+    }
+  }
+
+  void dumpCFG(std::string message) {
+    std::cout << "<==\nCFG [" << message << "]:\n";
+    generateDebugIds();
+    for (auto& block : basicBlocks) {
+      assert(debugIds.count(block.get()) > 0);
+      std::cout << "  block " << debugIds[block.get()] << ":\n";
+      block->contents.dump(static_cast<SubType*>(this)->getFunction());
+      for (auto& in : block->in) {
+        assert(debugIds.count(in) > 0);
+        assert(std::find(in->out.begin(), in->out.end(), block.get()) !=
+               in->out.end()); // must be a parallel link back
+      }
+      for (auto& out : block->out) {
+        assert(debugIds.count(out) > 0);
+        std::cout << "    out: " << debugIds[out] << "\n";
+        assert(std::find(out->in.begin(), out->in.end(), block.get()) !=
+               out->in.end()); // must be a parallel link back
+      }
+      checkDuplicates(block->in);
+      checkDuplicates(block->out);
+    }
+    std::cout << "==>\n";
+  }
+
+private:
+  // links in out and in must be unique
+  void checkDuplicates(std::vector<BasicBlock*>& list) {
+    std::unordered_set<BasicBlock*> seen;
+    for (auto* curr : list) {
+      assert(seen.count(curr) == 0);
+      seen.insert(curr);
+    }
+  }
+
+  void removeLink(std::vector<BasicBlock*>& list, BasicBlock* toRemove) {
+    if (list.size() == 1) {
+      list.clear();
+      return;
+    }
+    for (size_t i = 0; i < list.size(); i++) {
+      if (list[i] == toRemove) {
+        list[i] = list.back();
+        list.pop_back();
+        return;
+      }
+    }
+    WASM_UNREACHABLE("not found");
+  }
+};
+
+} // namespace wasm
+
+#endif // cfg_traversal_h
diff --git a/binaryen/src/cfg/liveness-traversal.h b/binaryen/src/cfg/liveness-traversal.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/cfg/liveness-traversal.h
@@ -0,0 +1,293 @@
+/*
+ * 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.
+ */
+
+//
+// Computes liveness information for locals.
+//
+
+#ifndef liveness_traversal_h
+#define liveness_traversal_h
+
+#include "cfg-traversal.h"
+#include "ir/utils.h"
+#include "support/sorted_vector.h"
+#include "wasm-builder.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
+
+namespace wasm {
+
+// A set of locals. This is optimized for comparisons,
+// mergings, and iteration on elements, assuming that there
+// may be a great many potential elements but actual sets
+// may be fairly small. Specifically, we use a sorted
+// vector.
+typedef SortedVector SetOfLocals;
+
+// A liveness-relevant action. Supports a get, a set, or an
+// "other" which can be used for other purposes, to mark
+// their position in a block
+struct LivenessAction {
+  enum What { Get = 0, Set = 1, Other = 2 };
+  What what;
+  Index index;         // the local index read or written
+  Expression** origin; // the origin
+  bool effective; // whether a store is actually effective, i.e., may be read
+
+  LivenessAction(What what, Index index, Expression** origin)
+    : what(what), index(index), origin(origin), effective(false) {
+    assert(what != Other);
+    if (what == Get) {
+      assert((*origin)->is<LocalGet>());
+    }
+    if (what == Set) {
+      assert((*origin)->is<LocalSet>());
+    }
+  }
+  LivenessAction(Expression** origin) : what(Other), origin(origin) {}
+
+  bool isGet() { return what == Get; }
+  bool isSet() { return what == Set; }
+  bool isOther() { return what == Other; }
+
+  // Helper to remove a set that is a copy we know is not needed. This
+  // updates both the IR and the action.
+  void removeCopy() {
+    auto* set = (*origin)->cast<LocalSet>();
+    if (set->isTee()) {
+      *origin = set->value->cast<LocalGet>();
+    } else {
+      ExpressionManipulator::nop(set);
+    }
+    // Mark as an other: even if we turned the origin into a get,
+    // we already have another Action for that get, that properly
+    // represents it.
+    what = Other;
+  }
+};
+
+// information about liveness in a basic block
+struct Liveness {
+  SetOfLocals start, end;              // live locals at the start and end
+  std::vector<LivenessAction> actions; // actions occurring in this block
+
+#if LIVENESS_DEBUG
+  void dump(Function* func) {
+    if (actions.empty())
+      return;
+    std::cout << "    actions:\n";
+    for (auto& action : actions) {
+      std::cout << "      "
+                << (action.isGet() ? "get" : (action.isSet() ? "set" : "other"))
+                << " " << func->getLocalName(action.index) << "\n";
+    }
+  }
+#endif // LIVENESS_DEBUG
+};
+
+template<typename SubType, typename VisitorType>
+struct LivenessWalker : public CFGWalker<SubType, VisitorType, Liveness> {
+  typedef
+    typename CFGWalker<SubType, VisitorType, Liveness>::BasicBlock BasicBlock;
+
+  Index numLocals;
+  std::unordered_set<BasicBlock*> liveBlocks;
+  // canonicalized - accesses should check (low, high)
+  // TODO: use a map for high N, as this tends to be sparse? or don't look at
+  // copies at all for big N?
+  std::vector<uint8_t> copies;
+  // total # of copies for each local, with all others
+  std::vector<Index> totalCopies;
+
+  // cfg traversal work
+
+  static void doVisitLocalGet(SubType* self, Expression** currp) {
+    auto* curr = (*currp)->cast<LocalGet>();
+    // if in unreachable code, ignore
+    if (!self->currBasicBlock) {
+      *currp = Builder(*self->getModule()).replaceWithIdenticalType(curr);
+      return;
+    }
+    self->currBasicBlock->contents.actions.emplace_back(
+      LivenessAction::Get, curr->index, currp);
+  }
+
+  static void doVisitLocalSet(SubType* self, Expression** currp) {
+    auto* curr = (*currp)->cast<LocalSet>();
+    // if in unreachable code, we don't need the tee (but might need the value,
+    // if it has side effects)
+    if (!self->currBasicBlock) {
+      if (curr->isTee()) {
+        *currp = curr->value;
+      } else {
+        *currp = Builder(*self->getModule()).makeDrop(curr->value);
+      }
+      return;
+    }
+    self->currBasicBlock->contents.actions.emplace_back(
+      LivenessAction::Set, curr->index, currp);
+    // if this is a copy, note it
+    if (auto* get = self->getCopy(curr)) {
+      // add 2 units, so that backedge prioritization can decide ties, but not
+      // much more
+      self->addCopy(curr->index, get->index);
+      self->addCopy(curr->index, get->index);
+    }
+  }
+
+  // A simple copy is a set of a get. A more interesting copy
+  // is a set of an if with a value, where one side a get.
+  // That can happen when we create an if value in simplify-locals. TODO:
+  // recurse into nested ifs, and block return values? Those cases are trickier,
+  // need to count to see if worth it.
+  // TODO: an if can have two copies
+  LocalGet* getCopy(LocalSet* set) {
+    if (auto* get = set->value->dynCast<LocalGet>()) {
+      return get;
+    }
+    if (auto* iff = set->value->dynCast<If>()) {
+      if (auto* get = iff->ifTrue->dynCast<LocalGet>()) {
+        return get;
+      }
+      if (iff->ifFalse) {
+        if (auto* get = iff->ifFalse->dynCast<LocalGet>()) {
+          return get;
+        }
+      }
+    }
+    return nullptr;
+  }
+
+  // If there are too many locals, we cannot run currently as
+  // numLocals * numLocals might overflow. We may want to add an option for
+  // a sparse matrix at some point TODO
+  bool canRun(Function* func) {
+    Index numLocals = func->getNumLocals();
+    if (uint64_t(numLocals) * uint64_t(numLocals) <=
+        std::numeric_limits<Index>::max()) {
+      return true;
+    }
+    std::cerr << "warning: too many locals (" << numLocals
+              << ") to run liveness analysis in " << this->getFunction()->name
+              << '\n';
+    return false;
+  }
+
+  // main entry point
+
+  void doWalkFunction(Function* func) {
+    numLocals = func->getNumLocals();
+    assert(canRun(func));
+    copies.resize(numLocals * numLocals);
+    std::fill(copies.begin(), copies.end(), 0);
+    totalCopies.resize(numLocals);
+    std::fill(totalCopies.begin(), totalCopies.end(), 0);
+    // create the CFG by walking the IR
+    CFGWalker<SubType, VisitorType, Liveness>::doWalkFunction(func);
+    // ignore links to dead blocks, so they don't confuse us and we can see
+    // their stores are all ineffective
+    liveBlocks = CFGWalker<SubType, VisitorType, Liveness>::findLiveBlocks();
+    CFGWalker<SubType, VisitorType, Liveness>::unlinkDeadBlocks(liveBlocks);
+    // flow liveness across blocks
+    flowLiveness();
+  }
+
+  void flowLiveness() {
+    // keep working while stuff is flowing
+    std::unordered_set<BasicBlock*> queue;
+    for (auto& curr : CFGWalker<SubType, VisitorType, Liveness>::basicBlocks) {
+      if (liveBlocks.count(curr.get()) == 0) {
+        continue; // ignore dead blocks
+      }
+      queue.insert(curr.get());
+      // do the first scan through the block, starting with nothing live at the
+      // end, and updating the liveness at the start
+      scanLivenessThroughActions(curr->contents.actions, curr->contents.start);
+    }
+    // at every point in time, we assume we already noted interferences between
+    // things already known alive at the end, and scanned back through the block
+    // using that
+    while (queue.size() > 0) {
+      auto iter = queue.begin();
+      auto* curr = *iter;
+      queue.erase(iter);
+      SetOfLocals live;
+      if (!mergeStartsAndCheckChange(curr->out, curr->contents.end, live)) {
+        continue;
+      }
+      assert(curr->contents.end.size() < live.size());
+      curr->contents.end = live;
+      scanLivenessThroughActions(curr->contents.actions, live);
+      // liveness is now calculated at the start. if something
+      // changed, all predecessor blocks need recomputation
+      if (curr->contents.start == live) {
+        continue;
+      }
+      assert(curr->contents.start.size() < live.size());
+      curr->contents.start = live;
+      for (auto* in : curr->in) {
+        queue.insert(in);
+      }
+    }
+  }
+
+  // merge starts of a list of blocks. return
+  // whether anything changed vs an old state (which indicates further
+  // processing is necessary).
+  bool mergeStartsAndCheckChange(std::vector<BasicBlock*>& blocks,
+                                 SetOfLocals& old,
+                                 SetOfLocals& ret) {
+    if (blocks.size() == 0) {
+      return false;
+    }
+    ret = blocks[0]->contents.start;
+    if (blocks.size() > 1) {
+      // more than one, so we must merge
+      for (Index i = 1; i < blocks.size(); i++) {
+        ret = ret.merge(blocks[i]->contents.start);
+      }
+    }
+    return old != ret;
+  }
+
+  void scanLivenessThroughActions(std::vector<LivenessAction>& actions,
+                                  SetOfLocals& live) {
+    // move towards the front
+    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);
+      }
+    }
+  }
+
+  void addCopy(Index i, Index j) {
+    auto k = std::min(i, j) * numLocals + std::max(i, j);
+    copies[k] = std::min(copies[k], uint8_t(254)) + 1;
+    totalCopies[i]++;
+    totalCopies[j]++;
+  }
+
+  uint8_t getCopies(Index i, Index j) {
+    return copies[std::min(i, j) * numLocals + std::max(i, j)];
+  }
+};
+
+} // namespace wasm
+
+#endif // liveness_traversal_h
diff --git a/binaryen/src/compiler-support.h b/binaryen/src/compiler-support.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/compiler-support.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 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_compiler_support_h
+#define wasm_compiler_support_h
+
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+#if __has_builtin(__builtin_unreachable)
+#define WASM_BUILTIN_UNREACHABLE __builtin_unreachable()
+#elif defined(_MSC_VER)
+#define WASM_BUILTIN_UNREACHABLE __assume(false)
+#endif
+
+#ifdef __GNUC__
+#define WASM_NORETURN __attribute__((noreturn))
+#elif defined(_MSC_VER)
+#define WASM_NORETURN __declspec(noreturn)
+#else
+#define WASM_NORETURN
+#endif
+
+// The code might contain TODOs or stubs that read some values but do nothing
+// with them. The compiler might fail with [-Werror,-Wunused-variable].
+// The WASM_UNUSED(varible) is a wrapper that helps to suppress the error.
+#define WASM_UNUSED(expr)                                                      \
+  do {                                                                         \
+    if (sizeof expr) {                                                         \
+      (void)0;                                                                 \
+    }                                                                          \
+  } while (0)
+
+#endif // wasm_compiler_support_h
diff --git a/binaryen/src/config.h b/binaryen/src/config.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/config.h
@@ -0,0 +1,1 @@
+#define PROJECT_VERSION "98"
diff --git a/binaryen/src/dataflow/graph.h b/binaryen/src/dataflow/graph.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/dataflow/graph.h
@@ -0,0 +1,805 @@
+/*
+ * 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.
+ */
+
+//
+// DataFlow IR is an SSA representation. It can be built from the main
+// Binaryen IR.
+//
+// THe main initial use case was an IR that could easily be converted to
+// Souper IR, and the design favors that.
+//
+
+#ifndef wasm_dataflow_graph_h
+#define wasm_dataflow_graph_h
+
+#include "dataflow/node.h"
+#include "ir/abstract.h"
+#include "ir/iteration.h"
+#include "ir/literal-utils.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace DataFlow {
+
+// Main logic to generate IR for a function. This is implemented as a
+// visitor on the wasm, where visitors return a Node* that either
+// contains the DataFlow IR for that expression, which can be a
+// Bad node if not supported, or nullptr if not relevant (we only
+// use the return value for internal expressions, that is, the
+// value of a local.set or the condition of an if etc).
+struct Graph : public UnifiedExpressionVisitor<Graph, Node*> {
+  // We only need one canonical bad node. It is never modified.
+  Node bad = Node(Node::Type::Bad);
+
+  // Connects a specific set to the data in its value.
+  std::unordered_map<LocalSet*, Node*> setNodeMap;
+
+  // Maps a control-flow expression to the conditions for it. Currently,
+  // this maps an if to the conditions for its arms
+  std::unordered_map<Expression*, std::vector<Node*>> expressionConditionMap;
+
+  // Maps each expression to its control-flow parent (or null if
+  // there is none). We only map expressions we need to know about,
+  // which are sets, set values, and control-flow constructs.
+  std::unordered_map<Expression*, Expression*> expressionParentMap;
+
+  // The same, for nodes. Note that we currently don't know the parents
+  // of nodes like phis that don't exist in wasm - we need to add more
+  // stuff to handle that. But we will know the parent of anything using
+  // that phi and storing to a local, which is probably enough anyhow
+  // for pc generation.
+  std::unordered_map<Node*, Expression*> nodeParentMap;
+
+  // All the sets, in order of appearance.
+  std::vector<LocalSet*> sets;
+
+  // The function being processed.
+  Function* func;
+
+  // The module we are working in.
+  Module* module;
+
+  // All of our nodes
+  std::vector<std::unique_ptr<Node>> nodes;
+
+  // Tracking state during building
+
+  // We need to track the parents of control flow nodes.
+  Expression* parent = nullptr;
+
+  // Tracks the state of locals in a control flow path:
+  //   locals[i] = the node whose value it contains
+  // When we are in unreachable code (i.e., a path that does not
+  // need to be merged in anywhere), we set the length of this
+  // vector to 0 to indicate that.
+  typedef std::vector<Node*> Locals;
+
+  // The current local state in the control flow path being emitted.
+  Locals locals;
+
+  // The local states on branches to a specific target.
+  std::unordered_map<Name, std::vector<Locals>> breakStates;
+
+  // The local state in a control flow path, including a possible
+  // condition as well.
+  struct FlowState {
+    Locals locals;
+    Node* condition;
+    FlowState(Locals locals, Node* condition)
+      : locals(locals), condition(condition) {}
+  };
+
+  // API
+
+  void build(Function* funcInit, Module* moduleInit) {
+    func = funcInit;
+    module = moduleInit;
+
+    auto numLocals = func->getNumLocals();
+    if (numLocals == 0) {
+      return; // nothing to do
+    }
+    // Set up initial local state IR.
+    setInReachable();
+    for (Index i = 0; i < numLocals; i++) {
+      if (!isRelevantType(func->getLocalType(i))) {
+        continue;
+      }
+      Node* node;
+      auto type = func->getLocalType(i);
+      if (func->isParam(i)) {
+        node = makeVar(type);
+      } else {
+        node = makeZero(type);
+      }
+      locals[i] = node;
+    }
+    // Process the function body, generating the rest of the IR.
+    visit(func->body);
+  }
+
+  // Makes a Var node, representing a value that could be anything.
+  Node* makeVar(wasm::Type type) {
+    if (isRelevantType(type)) {
+      return addNode(Node::makeVar(type));
+    } else {
+      return &bad;
+    }
+  }
+
+  // We create one node per constant value
+  std::unordered_map<Literal, Node*> constantNodes;
+
+  Node* makeConst(Literal value) {
+    auto iter = constantNodes.find(value);
+    if (iter != constantNodes.end()) {
+      return iter->second;
+    }
+    // Create one for this literal.
+    Builder builder(*module);
+    auto* c = builder.makeConst(value);
+    auto* ret = addNode(Node::makeExpr(c, c));
+    constantNodes[value] = ret;
+    return ret;
+  }
+
+  Node* makeZero(wasm::Type type) { return makeConst(Literal::makeZero(type)); }
+
+  // Add a new node to our list of owned nodes.
+  Node* addNode(Node* node) {
+    nodes.push_back(std::unique_ptr<Node>(node));
+    return node;
+  }
+
+  Node* makeZeroComp(Node* node, bool equal, Expression* origin) {
+    assert(!node->isBad());
+    Builder builder(*module);
+    auto type = node->getWasmType();
+    if (!type.isConcrete()) {
+      return &bad;
+    }
+    auto* zero = makeZero(type);
+    auto* expr = builder.makeBinary(
+      Abstract::getBinary(type, equal ? Abstract::Eq : Abstract::Ne),
+      makeUse(node),
+      makeUse(zero));
+    auto* check = addNode(Node::makeExpr(expr, origin));
+    check->addValue(expandFromI1(node, origin));
+    check->addValue(zero);
+    return check;
+  }
+
+  void setInUnreachable() { locals.clear(); }
+
+  void setInReachable() { locals.resize(func->getNumLocals()); }
+
+  bool isInUnreachable() { return isInUnreachable(locals); }
+
+  bool isInUnreachable(const Locals& state) { return state.empty(); }
+
+  bool isInUnreachable(const FlowState& state) {
+    return isInUnreachable(state.locals);
+  }
+
+  // Visiting.
+
+  Node* visitExpression(Expression* curr) {
+    // TODO Exception handling instruction support
+
+    // Control flow and get/set etc. are special. Aside from them, we just need
+    // to do something very generic.
+    if (auto* block = curr->dynCast<Block>()) {
+      return doVisitBlock(block);
+    } else if (auto* iff = curr->dynCast<If>()) {
+      return doVisitIf(iff);
+    } else if (auto* loop = curr->dynCast<Loop>()) {
+      return doVisitLoop(loop);
+    } else if (auto* get = curr->dynCast<LocalGet>()) {
+      return doVisitLocalGet(get);
+    } else if (auto* set = curr->dynCast<LocalSet>()) {
+      return doVisitLocalSet(set);
+    } else if (auto* br = curr->dynCast<Break>()) {
+      return doVisitBreak(br);
+    } else if (auto* sw = curr->dynCast<Switch>()) {
+      return doVisitSwitch(sw);
+    } else if (auto* c = curr->dynCast<Const>()) {
+      return doVisitConst(c);
+    } else if (auto* unary = curr->dynCast<Unary>()) {
+      return doVisitUnary(unary);
+    } else if (auto* binary = curr->dynCast<Binary>()) {
+      return doVisitBinary(binary);
+    } else if (auto* select = curr->dynCast<Select>()) {
+      return doVisitSelect(select);
+    } else if (auto* unreachable = curr->dynCast<Unreachable>()) {
+      return doVisitUnreachable(unreachable);
+    } else if (auto* drop = curr->dynCast<Drop>()) {
+      return doVisitDrop(drop);
+    } else if (curr->is<Try>() || curr->is<Throw>() || curr->is<Rethrow>() ||
+               curr->is<BrOnExn>()) {
+      Fatal() << "DataFlow does not support EH instructions yet";
+    } else {
+      return doVisitGeneric(curr);
+    }
+  }
+
+  Node* doVisitBlock(Block* curr) {
+    // TODO: handle super-deep nesting
+    auto* oldParent = parent;
+    expressionParentMap[curr] = oldParent;
+    parent = curr;
+    for (auto* child : curr->list) {
+      visit(child);
+    }
+    // Merge the outputs
+    // TODO handle conditions on these breaks
+    if (curr->name.is()) {
+      auto iter = breakStates.find(curr->name);
+      if (iter != breakStates.end()) {
+        auto& states = iter->second;
+        // Add the state flowing out
+        if (!isInUnreachable()) {
+          states.push_back(locals);
+        }
+        mergeBlock(states, locals);
+      }
+    }
+    parent = oldParent;
+    return &bad;
+  }
+  Node* doVisitIf(If* curr) {
+    auto* oldParent = parent;
+    expressionParentMap[curr] = oldParent;
+    parent = curr;
+    // Set up the condition.
+    Node* condition = visit(curr->condition);
+    assert(condition);
+    // Handle the contents.
+    auto initialState = locals;
+    visit(curr->ifTrue);
+    auto afterIfTrueState = locals;
+    if (curr->ifFalse) {
+      locals = initialState;
+      visit(curr->ifFalse);
+      auto afterIfFalseState = locals; // TODO: optimize
+      mergeIf(afterIfTrueState, afterIfFalseState, condition, curr, locals);
+    } else {
+      mergeIf(initialState, afterIfTrueState, condition, curr, locals);
+    }
+    parent = oldParent;
+    return &bad;
+  }
+  Node* doVisitLoop(Loop* curr) {
+    auto* oldParent = parent;
+    expressionParentMap[curr] = oldParent;
+    parent = curr;
+    // As in Souper's LLVM extractor, we avoid loop phis, as we don't want
+    // our traces to represent a value that differs across loop iterations.
+    // For example,
+    //   %b = block
+    //   %x = phi %b, 1, %y
+    //   %y = phi %b, 2, %x
+    //   %z = eq %x %y
+    //   infer %z
+    // Here %y refers to the previous iteration's %x.
+    // To do this, we set all locals to a Var at the loop entry, then process
+    // the inside of the loop. When that is done, we can see if a phi was
+    // actually needed for each local. If it was, we leave the Var (it
+    // represents an unknown value; analysis stops there), and if not, we
+    // can replace the Var with the fixed value.
+    // TODO: perhaps some more general uses of DataFlow will want loop phis?
+    // TODO: optimize stuff here
+    if (isInUnreachable()) {
+      return &bad; // none of this matters
+    }
+    if (!curr->name.is()) {
+      visit(curr->body);
+      return &bad; // no phis are possible
+    }
+    auto previous = locals;
+    auto numLocals = func->getNumLocals();
+    for (Index i = 0; i < numLocals; i++) {
+      locals[i] = makeVar(func->getLocalType(i));
+    }
+    auto vars = locals; // all the Vars we just created
+    // We may need to replace values later - only new nodes added from
+    // here are relevant.
+    auto firstNodeFromLoop = nodes.size();
+    // Process the loop body.
+    visit(curr->body);
+    // Find all incoming paths.
+    auto& breaks = breakStates[curr->name];
+    // Phis are possible, check for them.
+    for (Index i = 0; i < numLocals; i++) {
+      if (!isRelevantType(func->getLocalType(i))) {
+        continue;
+      }
+      bool needPhi = false;
+      // We replaced the proper value with a Var. If it's still that
+      // Var - or it's the original proper value, which can happen with
+      // constants - on all incoming paths, then a phi is not needed.
+      auto* var = vars[i];
+      auto* proper = previous[i];
+      for (auto& other : breaks) {
+        assert(!isInUnreachable(other));
+        auto& curr = *(other[i]);
+        if (curr != *var && curr != *proper) {
+          // A phi would be necessary here.
+          needPhi = true;
+          break;
+        }
+      }
+      if (needPhi) {
+        // Nothing to do - leave the Vars, the loop phis are
+        // unknown values to us.
+      } else {
+        // Undo the Var for this local: In every new node added for
+        // the loop body, replace references to the Var with the
+        // previous value (the value that is all we need instead of a phi).
+        for (auto j = firstNodeFromLoop; j < nodes.size(); j++) {
+          for (auto*& value : nodes[j].get()->values) {
+            if (value == var) {
+              value = proper;
+            }
+          }
+        }
+        // Also undo in the current local state, which is flowing out
+        // of the loop.
+        for (auto*& node : locals) {
+          if (node == var) {
+            node = proper;
+          }
+        }
+      }
+    }
+    return &bad;
+  }
+  Node* doVisitBreak(Break* curr) {
+    if (!isInUnreachable()) {
+      breakStates[curr->name].push_back(locals);
+    }
+    if (!curr->condition) {
+      setInUnreachable();
+    } else {
+      visit(curr->condition);
+    }
+    return &bad;
+  }
+  Node* doVisitSwitch(Switch* curr) {
+    visit(curr->condition);
+    if (!isInUnreachable()) {
+      std::unordered_set<Name> targets;
+      for (auto target : curr->targets) {
+        targets.insert(target);
+      }
+      targets.insert(curr->default_);
+      for (auto target : targets) {
+        breakStates[target].push_back(locals);
+      }
+    }
+    setInUnreachable();
+    return &bad;
+  }
+  Node* doVisitLocalGet(LocalGet* curr) {
+    if (!isRelevantLocal(curr->index) || isInUnreachable()) {
+      return &bad;
+    }
+    // We now know which IR node this get refers to
+    auto* node = locals[curr->index];
+    return node;
+  }
+  Node* doVisitLocalSet(LocalSet* curr) {
+    if (!isRelevantLocal(curr->index) || isInUnreachable()) {
+      return &bad;
+    }
+    assert(curr->value->type.isConcrete());
+    sets.push_back(curr);
+    expressionParentMap[curr] = parent;
+    expressionParentMap[curr->value] = curr;
+    // Set the current node in the local state.
+    auto* node = visit(curr->value);
+    locals[curr->index] = setNodeMap[curr] = node;
+    // If we created a new node (and not just did a get of a set, which
+    // passes around an existing node), mark its parent.
+    if (nodeParentMap.find(node) == nodeParentMap.end()) {
+      nodeParentMap[node] = curr;
+    }
+    return &bad;
+  }
+  Node* doVisitConst(Const* curr) { return makeConst(curr->value); }
+  Node* doVisitUnary(Unary* curr) {
+    // First, check if we support this op.
+    switch (curr->op) {
+      case ClzInt32:
+      case ClzInt64:
+      case CtzInt32:
+      case CtzInt64:
+      case PopcntInt32:
+      case PopcntInt64: {
+        // These are ok as-is.
+        // Check if our child is supported.
+        auto* value = expandFromI1(visit(curr->value), curr);
+        if (value->isBad()) {
+          return value;
+        }
+        // Great, we are supported!
+        auto* ret = addNode(Node::makeExpr(curr, curr));
+        ret->addValue(value);
+        return ret;
+      }
+      case EqZInt32:
+      case EqZInt64: {
+        // These can be implemented using a binary.
+        // Check if our child is supported.
+        auto* value = expandFromI1(visit(curr->value), curr);
+        if (value->isBad()) {
+          return value;
+        }
+        // Great, we are supported!
+        return makeZeroComp(value, true, curr);
+      }
+      default: {
+        // Anything else is an unknown value.
+        return makeVar(curr->type);
+      }
+    }
+  }
+  Node* doVisitBinary(Binary* curr) {
+    // First, check if we support this op.
+    switch (curr->op) {
+      case AddInt32:
+      case AddInt64:
+      case SubInt32:
+      case SubInt64:
+      case MulInt32:
+      case MulInt64:
+      case DivSInt32:
+      case DivSInt64:
+      case DivUInt32:
+      case DivUInt64:
+      case RemSInt32:
+      case RemSInt64:
+      case RemUInt32:
+      case RemUInt64:
+      case AndInt32:
+      case AndInt64:
+      case OrInt32:
+      case OrInt64:
+      case XorInt32:
+      case XorInt64:
+      case ShlInt32:
+      case ShlInt64:
+      case ShrUInt32:
+      case ShrUInt64:
+      case ShrSInt32:
+      case ShrSInt64:
+      case RotLInt32:
+      case RotLInt64:
+      case RotRInt32:
+      case RotRInt64:
+      case EqInt32:
+      case EqInt64:
+      case NeInt32:
+      case NeInt64:
+      case LtSInt32:
+      case LtSInt64:
+      case LtUInt32:
+      case LtUInt64:
+      case LeSInt32:
+      case LeSInt64:
+      case LeUInt32:
+      case LeUInt64: {
+        // These are ok as-is.
+        // Check if our children are supported.
+        auto* left = expandFromI1(visit(curr->left), curr);
+        if (left->isBad()) {
+          return left;
+        }
+        auto* right = expandFromI1(visit(curr->right), curr);
+        if (right->isBad()) {
+          return right;
+        }
+        // Great, we are supported!
+        auto* ret = addNode(Node::makeExpr(curr, curr));
+        ret->addValue(left);
+        ret->addValue(right);
+        return ret;
+      }
+      case GtSInt32:
+      case GtSInt64:
+      case GeSInt32:
+      case GeSInt64:
+      case GtUInt32:
+      case GtUInt64:
+      case GeUInt32:
+      case GeUInt64: {
+        // These need to be flipped as Souper does not support redundant ops.
+        Builder builder(*module);
+        BinaryOp opposite;
+        switch (curr->op) {
+          case GtSInt32:
+            opposite = LtSInt32;
+            break;
+          case GtSInt64:
+            opposite = LtSInt64;
+            break;
+          case GeSInt32:
+            opposite = LeSInt32;
+            break;
+          case GeSInt64:
+            opposite = LeSInt64;
+            break;
+          case GtUInt32:
+            opposite = LtUInt32;
+            break;
+          case GtUInt64:
+            opposite = LtUInt64;
+            break;
+          case GeUInt32:
+            opposite = LeUInt32;
+            break;
+          case GeUInt64:
+            opposite = LeUInt64;
+            break;
+          default:
+            WASM_UNREACHABLE("unexpected op");
+        }
+        auto* ret =
+          visitBinary(builder.makeBinary(opposite, curr->right, curr->left));
+        // We just created a new binary node, but we need to set the origin
+        // properly to the original.
+        ret->origin = curr;
+        return ret;
+      }
+      default: {
+        // Anything else is an unknown value.
+        return makeVar(curr->type);
+      }
+    }
+  }
+  Node* doVisitSelect(Select* curr) {
+    auto* ifTrue = expandFromI1(visit(curr->ifTrue), curr);
+    if (ifTrue->isBad()) {
+      return ifTrue;
+    }
+    auto* ifFalse = expandFromI1(visit(curr->ifFalse), curr);
+    if (ifFalse->isBad()) {
+      return ifFalse;
+    }
+    auto* condition = ensureI1(visit(curr->condition), curr);
+    if (condition->isBad()) {
+      return condition;
+    }
+    // Great, we are supported!
+    auto* ret = addNode(Node::makeExpr(curr, curr));
+    ret->addValue(condition);
+    ret->addValue(ifTrue);
+    ret->addValue(ifFalse);
+    return ret;
+  }
+  Node* doVisitUnreachable(Unreachable* curr) {
+    setInUnreachable();
+    return &bad;
+  }
+  Node* doVisitDrop(Drop* curr) {
+    visit(curr->value);
+    // We need to know that the value's parent is a drop, indicating
+    // the value is not actually used here.
+    expressionParentMap[curr->value] = curr;
+    return &bad;
+  }
+  Node* doVisitGeneric(Expression* curr) {
+    // Just need to visit the nodes so we note all the gets
+    for (auto* child : ChildIterator(curr)) {
+      visit(child);
+    }
+    return makeVar(curr->type);
+  }
+
+  // Helpers.
+
+  bool isRelevantType(wasm::Type type) { return type.isInteger(); }
+
+  bool isRelevantLocal(Index index) {
+    return isRelevantType(func->getLocalType(index));
+  }
+
+  // Merge local state for an if, also creating a block and conditions.
+  void mergeIf(Locals& aState,
+               Locals& bState,
+               Node* condition,
+               Expression* expr,
+               Locals& out) {
+    // Create the conditions (if we can).
+    Node* ifTrue;
+    Node* ifFalse;
+    if (!condition->isBad()) {
+      // Generate boolean (i1 returning) conditions for the two branches.
+      auto& conditions = expressionConditionMap[expr];
+      ifTrue = ensureI1(condition, nullptr);
+      conditions.push_back(ifTrue);
+      ifFalse = makeZeroComp(condition, true, nullptr);
+      conditions.push_back(ifFalse);
+    } else {
+      ifTrue = ifFalse = &bad;
+    }
+    // Finally, merge the state with that block. TODO optimize
+    std::vector<FlowState> states;
+    if (!isInUnreachable(aState)) {
+      states.emplace_back(aState, ifTrue);
+    }
+    if (!isInUnreachable(bState)) {
+      states.emplace_back(bState, ifFalse);
+    }
+    merge(states, out);
+  }
+
+  // Merge local state for a block
+  void mergeBlock(std::vector<Locals>& localses, Locals& out) {
+    // TODO: conditions
+    std::vector<FlowState> states;
+    for (auto& locals : localses) {
+      states.emplace_back(locals, &bad);
+    }
+    merge(states, out);
+  }
+
+  // Merge local state for multiple control flow paths, creating phis as needed.
+  void merge(std::vector<FlowState>& states, Locals& out) {
+    // We should only receive reachable states.
+#ifndef NDEBUG
+    for (auto& state : states) {
+      assert(!isInUnreachable(state.locals));
+    }
+#endif
+    Index numStates = states.size();
+    if (numStates == 0) {
+      // We were unreachable, and still are.
+      assert(isInUnreachable());
+      return;
+    }
+    // We may have just become reachable, if we were not before.
+    setInReachable();
+    // Just one thing to merge is trivial.
+    if (numStates == 1) {
+      out = states[0].locals;
+      return;
+    }
+    // We create a block if we need one.
+    Index numLocals = func->getNumLocals();
+    Node* block = nullptr;
+    for (Index i = 0; i < numLocals; i++) {
+      if (!isRelevantType(func->getLocalType(i))) {
+        continue;
+      }
+      // Process the inputs. If any is bad, the phi is bad.
+      bool bad = false;
+      for (auto& state : states) {
+        auto* node = state.locals[i];
+        if (node->isBad()) {
+          bad = true;
+          out[i] = node;
+          break;
+        }
+      }
+      if (bad) {
+        continue;
+      }
+      // Nothing is bad, proceed.
+      Node* first = nullptr;
+      for (auto& state : states) {
+        if (!first) {
+          first = out[i] = state.locals[i];
+        } else if (state.locals[i] != first) {
+          // We need to actually merge some stuff.
+          if (!block) {
+            block = addNode(Node::makeBlock());
+            for (Index index = 0; index < numStates; index++) {
+              auto* condition = states[index].condition;
+              if (!condition->isBad()) {
+                condition = addNode(Node::makeCond(block, index, condition));
+              }
+              block->addValue(condition);
+            }
+          }
+          auto* phi = addNode(Node::makePhi(block, i));
+          for (auto& state : states) {
+            auto* value = expandFromI1(state.locals[i], nullptr);
+            phi->addValue(value);
+          }
+          out[i] = phi;
+          break;
+        }
+      }
+    }
+  }
+
+  // If the node returns an i1, then we are called from a context that needs
+  // to use it normally as in wasm - extend it
+  Node* expandFromI1(Node* node, Expression* origin) {
+    if (!node->isBad() && node->returnsI1()) {
+      node = addNode(Node::makeZext(node, origin));
+    }
+    return node;
+  }
+
+  Node* ensureI1(Node* node, Expression* origin) {
+    if (!node->isBad() && !node->returnsI1()) {
+      node = makeZeroComp(node, false, origin);
+    }
+    return node;
+  }
+
+  // Given a node representing something that is local.set'd, return
+  // the set.
+  LocalSet* getSet(Node* node) {
+    auto iter = nodeParentMap.find(node);
+    if (iter == nodeParentMap.end()) {
+      return nullptr;
+    }
+    return iter->second->dynCast<LocalSet>();
+  }
+
+  // Given an expression, return the parent if such exists.
+  Expression* getParent(Expression* curr) {
+    auto iter = expressionParentMap.find(curr);
+    if (iter == expressionParentMap.end()) {
+      return nullptr;
+    }
+    return iter->second;
+  }
+
+  // Given an expression, return the set for it if such exists.
+  LocalSet* getSet(Expression* curr) {
+    auto* parent = getParent(curr);
+    return parent ? parent->dynCast<LocalSet>() : nullptr;
+  }
+
+  // Creates an expression that uses a node. Generally, a node represents
+  // a value in a local, so we create a local.get for it.
+  Expression* makeUse(Node* node) {
+    Builder builder(*module);
+    if (node->isPhi()) {
+      // The index is the wasm local that we assign to when implementing
+      // the phi; get from there.
+      auto index = node->index;
+      return builder.makeLocalGet(index, func->getLocalType(index));
+    } else if (node->isConst()) {
+      return builder.makeConst(node->expr->cast<Const>()->value);
+    } else if (node->isExpr()) {
+      // Find the set we are a value of.
+      auto index = getSet(node)->index;
+      return builder.makeLocalGet(index, func->getLocalType(index));
+    } else if (node->isZext()) {
+      // i1 zexts are a no-op for wasm
+      return makeUse(node->values[0]);
+    } else if (node->isVar()) {
+      // Nothing valid for us to read here. Emit a call, representing an unknown
+      // variable value.
+      return Builder(*module).makeCall(FAKE_CALL, {}, node->wasmType);
+    } else {
+      WASM_UNREACHABLE("unexpected node type"); // TODO
+    }
+  }
+
+  const Name FAKE_CALL = "fake$dfo$call";
+};
+
+} // namespace DataFlow
+
+} // namespace wasm
+
+#endif // wasm_dataflow_graph_h
diff --git a/binaryen/src/dataflow/node.h b/binaryen/src/dataflow/node.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/dataflow/node.h
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ */
+
+//
+// DataFlow IR is an SSA representation. It can be built from the main
+// Binaryen IR.
+//
+// THe main initial use case was an IR that could easily be converted to
+// Souper IR, and the design favors that.
+//
+
+#ifndef wasm_dataflow_node_h
+#define wasm_dataflow_node_h
+
+#include "ir/utils.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace DataFlow {
+
+//
+// The core IR representation in DataFlow: a Node.
+//
+// We reuse the Binaryen IR as much as possible: when things are identical
+// between the two IRs, we just create an Expr node, which stores the opcode and
+// other details, and we can emit them to Souper by reading the Binaryen
+// Expression. Other node types here are special things from Souper IR that we
+// can't represent that way.
+//
+// * Souper comparisons return an i1. We extend them immediately if they are
+//   going to be used as i32s or i64s.
+// * When we use an Expression node, we just use its immediate fields, like the
+//   op in a binary, alignment etc. in a load, etc. We don't look into the
+//   pointers to child nodes. Instead, the DataFlow IR has its own pointers
+//   directly to DataFlow children. In particular, this means that it's easy
+//   to create an Expression with the info you need and not care about linking
+//   it up to other Expressions.
+//
+
+struct Node {
+  enum Type {
+    Var,  // an unknown variable number (not to be confused with var/param/local
+          // in wasm)
+    Expr, // a value represented by a Binaryen Expression
+    Phi,  // a phi from converging control flow
+    Cond, // a blockpc, representing one of the branchs for a Block
+    Block, // a source of phis
+    Zext, // zero-extend an i1 (from an op where Souper returns i1 but wasm does
+          // not, and so we need a special way to get back to an i32/i64 if we
+          // operate on that value instead of just passing it straight to
+          // Souper).
+    Bad   // something we can't handle and should ignore
+  } type;
+
+  Node(Type type) : type(type) {}
+
+  // TODO: the others, if we need them
+  bool isVar() { return type == Var; }
+  bool isExpr() { return type == Expr; }
+  bool isPhi() { return type == Phi; }
+  bool isCond() { return type == Cond; }
+  bool isBlock() { return type == Block; }
+  bool isZext() { return type == Zext; }
+  bool isBad() { return type == Bad; }
+
+  bool isConst() { return type == Expr && expr->is<Const>(); }
+
+  union {
+    // For Var
+    wasm::Type wasmType;
+    // For Expr
+    Expression* expr;
+    // For Phi and Cond (the local index for phi, the block
+    // index for cond)
+    Index index;
+  };
+
+  // The wasm expression that we originate from (if such exists). A single
+  // wasm instruction may be turned into multiple dataflow IR nodes, and some
+  // nodes have no wasm origin (like phis).
+  Expression* origin = nullptr;
+
+  // Extra list of related nodes.
+  // For Expr, these are the Nodes for the inputs to the expression (e.g.
+  // a binary would have 2 in this vector here).
+  // For Phi, this is the block and then the list of values to pick from.
+  // For Cond, this is the block and node.
+  // For Block, this is the list of Conds. Note that that block does not
+  // depend on them - the Phis do, but we store them in the block so that
+  // we can avoid duplication.
+  // For Zext, this is the value we extend.
+  std::vector<Node*> values;
+
+  // Constructors
+  static Node* makeVar(wasm::Type wasmType) {
+    Node* ret = new Node(Var);
+    ret->wasmType = wasmType;
+    return ret;
+  }
+  static Node* makeExpr(Expression* expr, Expression* origin) {
+    Node* ret = new Node(Expr);
+    ret->expr = expr;
+    ret->origin = origin;
+    return ret;
+  }
+  static Node* makePhi(Node* block, Index index) {
+    Node* ret = new Node(Phi);
+    ret->addValue(block);
+    ret->index = index;
+    return ret;
+  }
+  static Node* makeCond(Node* block, Index index, Node* node) {
+    Node* ret = new Node(Cond);
+    ret->addValue(block);
+    ret->index = index;
+    ret->addValue(node);
+    return ret;
+  }
+  static Node* makeBlock() {
+    Node* ret = new Node(Block);
+    return ret;
+  }
+  static Node* makeZext(Node* child, Expression* origin) {
+    Node* ret = new Node(Zext);
+    ret->addValue(child);
+    ret->origin = origin;
+    return ret;
+  }
+  static Node* makeBad() {
+    Node* ret = new Node(Bad);
+    return ret;
+  }
+
+  // Helpers
+
+  void addValue(Node* value) { values.push_back(value); }
+  Node* getValue(Index i) { return values.at(i); }
+
+  // Gets the wasm type of the node. If there isn't a valid one,
+  // return unreachable.
+  wasm::Type getWasmType() {
+    switch (type) {
+      case Var:
+        return wasmType;
+      case Expr:
+        return expr->type;
+      case Phi:
+        return getValue(1)->getWasmType();
+      case Zext:
+        return getValue(0)->getWasmType();
+      case Bad:
+        return wasm::Type::unreachable;
+      default:
+        WASM_UNREACHABLE("invalid node type");
+    }
+  }
+
+  bool operator==(const Node& other) {
+    if (type != other.type) {
+      return false;
+    }
+    switch (type) {
+      case Var:
+      case Block:
+        return this == &other;
+      case Expr: {
+        if (!ExpressionAnalyzer::equal(expr, other.expr)) {
+          return false;
+        }
+        break;
+      }
+      case Cond:
+        if (index != other.index) {
+          return false;
+        }
+      default: {}
+    }
+    if (values.size() != other.values.size()) {
+      return false;
+    }
+    for (Index i = 0; i < values.size(); i++) {
+      if (*(values[i]) != *(other.values[i])) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool operator!=(const Node& other) { return !(*this == other); }
+
+  // As mentioned above, comparisons return i1. This checks
+  // if an operation is of that sort.
+  bool returnsI1() {
+    if (isExpr()) {
+      if (auto* binary = expr->dynCast<Binary>()) {
+        return binary->isRelational();
+      } else if (auto* unary = expr->dynCast<Unary>()) {
+        return unary->isRelational();
+      }
+    }
+    return false;
+  }
+};
+
+} // namespace DataFlow
+
+} // namespace wasm
+
+#endif // wasm_dataflow_node
diff --git a/binaryen/src/dataflow/users.h b/binaryen/src/dataflow/users.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/dataflow/users.h
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+//
+// DataFlow IR is an SSA representation. It can be built from the main
+// Binaryen IR.
+//
+// THe main initial use case was an IR that could easily be converted to
+// Souper IR, and the design favors that.
+//
+
+#ifndef wasm_dataflow_users_h
+#define wasm_dataflow_users_h
+
+#include "dataflow/graph.h"
+
+namespace wasm {
+
+namespace DataFlow {
+
+// Calculates the users of each node.
+//   users[x] = { y, z, .. }
+// where y, z etc. are nodes that use x, that is, x is in their
+// values vector.
+class Users {
+  typedef std::unordered_set<DataFlow::Node*> UserSet;
+
+  std::unordered_map<DataFlow::Node*, UserSet> users;
+
+public:
+  void build(Graph& graph) {
+    for (auto& node : graph.nodes) {
+      for (auto* value : node->values) {
+        users[value].insert(node.get());
+      }
+    }
+  }
+
+  UserSet& getUsers(Node* node) {
+    auto iter = users.find(node);
+    if (iter == users.end()) {
+      static UserSet empty; // FIXME thread_local?
+      return empty;
+    }
+    return iter->second;
+  }
+
+  Index getNumUses(Node* node) {
+    auto& users = getUsers(node);
+    // A user may have more than one use
+    Index numUses = 0;
+    for (auto* user : users) {
+#ifndef NDEBUG
+      bool found = false;
+#endif
+      for (auto* value : user->values) {
+        if (value == node) {
+          numUses++;
+#ifndef NDEBUG
+          found = true;
+#endif
+        }
+      }
+      assert(found);
+    }
+    return numUses;
+  }
+
+  // Stops using all the values of this node. Called when a node is being
+  // removed.
+  void stopUsingValues(Node* node) {
+    for (auto* value : node->values) {
+      auto& users = getUsers(value);
+      users.erase(node);
+    }
+  }
+
+  // Adds a new user to a node. Called when we add or change a value of a node.
+  void addUser(Node* node, Node* newUser) { users[node].insert(newUser); }
+
+  // Remove all uses of a node. Called when a node is being removed.
+  void removeAllUsesOf(Node* node) { users.erase(node); }
+};
+
+} // namespace DataFlow
+
+} // namespace wasm
+
+#endif // wasm_dataflow_users
diff --git a/binaryen/src/dataflow/utils.h b/binaryen/src/dataflow/utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/dataflow/utils.h
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+//
+// DataFlow IR is an SSA representation. It can be built from the main
+// Binaryen IR.
+//
+// THe main initial use case was an IR that could easily be converted to
+// Souper IR, and the design favors that.
+//
+
+#ifndef wasm_dataflow_utils_h
+#define wasm_dataflow_utils_h
+
+#include "dataflow/node.h"
+#include "wasm-printing.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace DataFlow {
+
+inline std::ostream& dump(Node* node, std::ostream& o, size_t indent = 0) {
+  auto doIndent = [&]() {
+    for (size_t i = 0; i < indent; i++) {
+      o << ' ';
+    }
+  };
+  doIndent();
+  o << '[' << node << ' ';
+  switch (node->type) {
+    case Node::Type::Var:
+      o << "var " << node->wasmType << ' ' << node;
+      break;
+    case Node::Type::Expr: {
+      o << "expr ";
+      WasmPrinter::printExpression(node->expr, o, true);
+      break;
+    }
+    case Node::Type::Phi:
+      o << "phi " << node->index;
+      break;
+    case Node::Type::Cond:
+      o << "cond " << node->index;
+      break;
+    case Node::Type::Block: {
+      // don't print the conds - they would recurse
+      o << "block (" << node->values.size() << " conds)]\n";
+      return o;
+    }
+    case Node::Type::Zext:
+      o << "zext";
+      break;
+    case Node::Type::Bad:
+      o << "bad";
+      break;
+  }
+  if (!node->values.empty()) {
+    o << '\n';
+    for (auto* value : node->values) {
+      dump(value, o, indent + 1);
+    }
+    doIndent();
+  }
+  o << "] (origin: " << (void*)(node->origin) << ")\n";
+  return o;
+}
+
+inline std::ostream& dump(Graph& graph, std::ostream& o) {
+  for (auto& node : graph.nodes) {
+    o << "NODE " << node.get() << ": ";
+    dump(node.get(), o);
+    if (auto* set = graph.getSet(node.get())) {
+      o << "  and that is set to local " << set->index << '\n';
+    }
+  }
+  return o;
+}
+
+// Checks if the inputs are all identical - something we could
+// probably optimize. Returns false if irrelevant.
+inline bool allInputsIdentical(Node* node) {
+  switch (node->type) {
+    case Node::Type::Expr: {
+      if (node->expr->is<Binary>()) {
+        return *(node->getValue(0)) == *(node->getValue(1));
+      } else if (node->expr->is<Select>()) {
+        return *(node->getValue(1)) == *(node->getValue(2));
+      }
+      break;
+    }
+    case Node::Type::Phi: {
+      auto* first = node->getValue(1);
+      // Check if any of the others are not equal
+      for (Index i = 2; i < node->values.size(); i++) {
+        auto* curr = node->getValue(i);
+        if (*first != *curr) {
+          return false;
+        }
+      }
+      return true;
+    }
+    default: {}
+  }
+  return false;
+}
+
+// Checks if the inputs are all constant - something we could
+// probably optimize. Returns false if irrelevant.
+inline bool allInputsConstant(Node* node) {
+  switch (node->type) {
+    case Node::Type::Expr: {
+      if (node->expr->is<Unary>()) {
+        return node->getValue(0)->isConst();
+      } else if (node->expr->is<Binary>()) {
+        return node->getValue(0)->isConst() && node->getValue(1)->isConst();
+      } else if (node->expr->is<Select>()) {
+        return node->getValue(0)->isConst() && node->getValue(1)->isConst() &&
+               node->getValue(2)->isConst();
+      }
+      break;
+    }
+    case Node::Type::Phi: {
+      // Check if any of the others are not equal
+      for (Index i = 1; i < node->values.size(); i++) {
+        if (!node->getValue(i)->isConst()) {
+          return false;
+        }
+      }
+      return true;
+    }
+    default: {}
+  }
+  return false;
+}
+
+} // namespace DataFlow
+
+} // namespace wasm
+
+#endif // wasm_dataflow_utils
diff --git a/binaryen/src/emscripten-optimizer/CMakeLists.txt b/binaryen/src/emscripten-optimizer/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/src/emscripten-optimizer/CMakeLists.txt
@@ -0,0 +1,8 @@
+FILE(GLOB emscripten-optimizer_HEADERS *.h)
+set(emscripten-optimizer_SOURCES
+  optimizer-shared.cpp
+  parser.cpp
+  simple_ast.cpp
+  ${emscripten-optimizer_HEADERS}
+)
+add_library(emscripten-optimizer OBJECT ${emscripten-optimizer_SOURCES})
diff --git a/binaryen/src/emscripten-optimizer/istring.h b/binaryen/src/emscripten-optimizer/istring.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/emscripten-optimizer/istring.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2015 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.
+ */
+
+// Interned String type, 100% interned on creation. Comparisons are always just
+// a pointer comparison
+
+#ifndef wasm_istring_h
+#define wasm_istring_h
+
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "support/threads.h"
+#include "support/utilities.h"
+
+namespace cashew {
+
+struct IString {
+  const char* str = nullptr;
+
+  static size_t
+  hash_c(const char* str) { // see http://www.cse.yorku.ca/~oz/hash.html
+    unsigned int hash = 5381;
+    int c;
+    while ((c = *str++)) {
+      hash = ((hash << 5) + hash) ^ c;
+    }
+    return (size_t)hash;
+  }
+
+  class CStringHash : public std::hash<const char*> {
+  public:
+    size_t operator()(const char* str) const { return IString::hash_c(str); }
+  };
+  class CStringEqual : public std::equal_to<const char*> {
+  public:
+    bool operator()(const char* x, const char* y) const {
+      return strcmp(x, y) == 0;
+    }
+  };
+
+  IString() = default;
+  // if reuse=true, then input is assumed to remain alive; not copied
+  IString(const char* s, bool reuse = true) {
+    assert(s);
+    set(s, reuse);
+  }
+
+  void set(const char* s, bool reuse = true) {
+    typedef std::unordered_set<const char*, CStringHash, CStringEqual>
+      StringSet;
+    // one global store of strings per thread, we must not access this
+    // in parallel
+    thread_local static StringSet strings;
+
+    auto existing = strings.find(s);
+
+    if (existing == strings.end()) {
+      // if the string isn't already known, we must use a single global
+      // storage location, guarded by a mutex, so each string is allocated
+      // exactly once
+      static std::mutex mutex;
+      std::unique_lock<std::mutex> lock(mutex);
+      // a single global set contains the actual strings, so we allocate each
+      // one exactly once.
+      static StringSet globalStrings;
+      auto globalExisting = globalStrings.find(s);
+      if (globalExisting == globalStrings.end()) {
+        if (!reuse) {
+          static std::vector<std::unique_ptr<std::string>> allocated;
+          allocated.emplace_back(wasm::make_unique<std::string>(s));
+          s = allocated.back()->c_str(); // we'll never modify it, so this is ok
+        }
+        // insert into global set
+        globalStrings.insert(s);
+      } else {
+        s = *globalExisting;
+      }
+      // add the string to our thread-local set
+      strings.insert(s);
+    } else {
+      s = *existing;
+    }
+
+    str = s;
+  }
+
+  void set(const IString& s) { str = s.str; }
+
+  void clear() { str = nullptr; }
+
+  bool operator==(const IString& other) const {
+    // assert((str == other.str) == !strcmp(str, other.str));
+    return str == other.str; // fast!
+  }
+  bool operator!=(const IString& other) const {
+    // assert((str == other.str) == !strcmp(str, other.str));
+    return str != other.str; // fast!
+  }
+  bool operator<(const IString& other) const {
+    return strcmp(str ? str : "", other.str ? other.str : "") < 0;
+  }
+
+  char operator[](int x) const { return str[x]; }
+
+  bool operator!() const { // no string, or empty string
+    return !str || str[0] == 0;
+  }
+
+  const char* c_str() const { return str; }
+  bool equals(const char* other) const { return !strcmp(str, other); }
+
+  bool is() const { return str != nullptr; }
+  bool isNull() const { return str == nullptr; }
+
+  const char* stripPrefix(const char* prefix) const {
+    const char* ptr = str;
+    while (true) {
+      if (*prefix == 0) {
+        return ptr;
+      }
+      if (*ptr == 0) {
+        return nullptr;
+      }
+      if (*ptr++ != *prefix++) {
+        return nullptr;
+      }
+    }
+  }
+
+  bool startsWith(const char* prefix) const {
+    return stripPrefix(prefix) != nullptr;
+  }
+  bool startsWith(const IString& prefix) const {
+    return startsWith(prefix.str);
+  }
+
+  size_t size() const { return str ? strlen(str) : 0; }
+};
+
+} // namespace cashew
+
+// Utilities for creating hashmaps/sets over IStrings
+
+namespace std {
+
+template<> struct hash<cashew::IString> {
+  size_t operator()(const cashew::IString& str) const {
+    return std::hash<size_t>{}(size_t(str.str));
+  }
+};
+
+template<> struct equal_to<cashew::IString> {
+  bool operator()(const cashew::IString& x, const cashew::IString& y) const {
+    return x == y;
+  }
+};
+
+} // namespace std
+
+namespace cashew {
+
+// IStringSet
+
+class IStringSet : public std::unordered_set<IString> {
+  std::vector<char> data;
+
+public:
+  IStringSet() = default;
+  IStringSet(const char* init) { // comma-delimited list
+    int size = strlen(init) + 1;
+    data.resize(size);
+    char* curr = &data[0];
+    strncpy(curr, init, size);
+    while (1) {
+      char* end = strchr(curr, ' ');
+      if (end) {
+        *end = 0;
+      }
+      insert(curr);
+      if (!end) {
+        break;
+      }
+      curr = end + 1;
+    }
+  }
+
+  bool has(const IString& str) { return count(str) > 0; }
+};
+
+class IOrderedStringSet : public std::set<IString> {
+public:
+  bool has(const IString& str) { return count(str) > 0; }
+};
+
+} // namespace cashew
+
+#endif // wasm_istring_h
diff --git a/binaryen/src/emscripten-optimizer/optimizer-shared.cpp b/binaryen/src/emscripten-optimizer/optimizer-shared.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/emscripten-optimizer/optimizer-shared.cpp
@@ -0,0 +1,357 @@
+/*
+ * Copyright 2015 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <limits>
+
+#include "optimizer.h"
+#include "support/safe_integer.h"
+
+using namespace cashew;
+
+IString ASM_FLOAT_ZERO;
+
+IString SIMD_INT8X16_CHECK("SIMD_Int8x16_check");
+IString SIMD_INT16X8_CHECK("SIMD_Int16x8_check");
+IString SIMD_INT32X4_CHECK("SIMD_Int32x4_check");
+IString SIMD_FLOAT32X4_CHECK("SIMD_Float32x4_check");
+IString SIMD_FLOAT64X2_CHECK("SIMD_Float64x2_check");
+IString TEMP_RET0("tempRet0");
+
+int parseInt(const char* str) {
+  int ret = *str - '0';
+  while (*(++str)) {
+    ret *= 10;
+    ret += *str - '0';
+  }
+  return ret;
+}
+
+HeapInfo parseHeap(const char* name) {
+  HeapInfo ret;
+  if (name[0] != 'H' || name[1] != 'E' || name[2] != 'A' || name[3] != 'P') {
+    ret.valid = false;
+    return ret;
+  }
+  ret.valid = true;
+  ret.unsign = name[4] == 'U';
+  ret.floaty = name[4] == 'F';
+  ret.bits = parseInt(name + (ret.unsign || ret.floaty ? 5 : 4));
+  ret.type = !ret.floaty ? ASM_INT : (ret.bits == 64 ? ASM_DOUBLE : ASM_FLOAT);
+  return ret;
+}
+
+AsmType detectType(Ref node,
+                   AsmData* asmData,
+                   bool inVarDef,
+                   IString minifiedFround,
+                   bool allowI64) {
+  if (node->isString()) {
+    if (asmData) {
+      AsmType ret = asmData->getType(node->getCString());
+      if (ret != ASM_NONE) {
+        return ret;
+      }
+    }
+    if (!inVarDef) {
+      if (node == INF || node == NaN) {
+        return ASM_DOUBLE;
+      }
+      if (node == TEMP_RET0) {
+        return ASM_INT;
+      }
+      return ASM_NONE;
+    }
+    // We are in a variable definition, where Math_fround(0) optimized into a
+    // global constant becomes f0 = Math_fround(0)
+    if (ASM_FLOAT_ZERO.isNull()) {
+      ASM_FLOAT_ZERO = node->getIString();
+    } else {
+      assert(node == ASM_FLOAT_ZERO);
+    }
+    return ASM_FLOAT;
+  }
+  if (node->isNumber()) {
+    if (!wasm::isInteger(node->getNumber())) {
+      return ASM_DOUBLE;
+    }
+    return ASM_INT;
+  }
+  switch (node[0]->getCString()[0]) {
+    case 'u': {
+      if (node[0] == UNARY_PREFIX) {
+        switch (node[1]->getCString()[0]) {
+          case '+':
+            return ASM_DOUBLE;
+          case '-':
+            return detectType(
+              node[2], asmData, inVarDef, minifiedFround, allowI64);
+          case '!':
+          case '~':
+            return ASM_INT;
+        }
+        break;
+      }
+      break;
+    }
+    case 'c': {
+      if (node[0] == CALL) {
+        if (node[1]->isString()) {
+          IString name = node[1]->getIString();
+          if (name == MATH_FROUND || name == minifiedFround) {
+            return ASM_FLOAT;
+          } else if (allowI64 && (name == INT64 || name == INT64_CONST)) {
+            return ASM_INT64;
+          } else if (name == SIMD_FLOAT32X4 || name == SIMD_FLOAT32X4_CHECK) {
+            return ASM_FLOAT32X4;
+          } else if (name == SIMD_FLOAT64X2 || name == SIMD_FLOAT64X2_CHECK) {
+            return ASM_FLOAT64X2;
+          } else if (name == SIMD_INT8X16 || name == SIMD_INT8X16_CHECK) {
+            return ASM_INT8X16;
+          } else if (name == SIMD_INT16X8 || name == SIMD_INT16X8_CHECK) {
+            return ASM_INT16X8;
+          } else if (name == SIMD_INT32X4 || name == SIMD_INT32X4_CHECK) {
+            return ASM_INT32X4;
+          }
+        }
+        return ASM_NONE;
+      } else if (node[0] == CONDITIONAL) {
+        return detectType(node[2], asmData, inVarDef, minifiedFround, allowI64);
+      }
+      break;
+    }
+    case 'b': {
+      if (node[0] == BINARY) {
+        switch (node[1]->getCString()[0]) {
+          case '+':
+          case '-':
+          case '*':
+          case '/':
+          case '%':
+            return detectType(
+              node[2], asmData, inVarDef, minifiedFround, allowI64);
+          case '|':
+          case '&':
+          case '^':
+          case '<':
+          case '>': // handles <<, >>, >>=, <=, >=
+          case '=':
+          case '!': { // handles ==, !=
+            return ASM_INT;
+          }
+        }
+      }
+      break;
+    }
+    case 's': {
+      if (node[0] == SEQ) {
+        return detectType(node[2], asmData, inVarDef, minifiedFround, allowI64);
+      } else if (node[0] == SUB) {
+        assert(node[1]->isString());
+        HeapInfo info = parseHeap(node[1][1]->getCString());
+        if (info.valid) {
+          return ASM_NONE;
+        }
+        return info.floaty ? ASM_DOUBLE : ASM_INT; // XXX ASM_FLOAT?
+      }
+      break;
+    }
+  }
+  // dump("horrible", node);
+  // assert(0);
+  return ASM_NONE;
+}
+
+static void abort_on(Ref node) {
+  node->stringify(std::cerr);
+  std::cerr << '\n';
+  abort();
+}
+
+AsmSign detectSign(Ref node, IString minifiedFround) {
+  if (node->isString()) {
+    return ASM_FLEXIBLE;
+  }
+  if (node->isNumber()) {
+    double value = node->getNumber();
+    if (value < 0) {
+      return ASM_SIGNED;
+    }
+    if (value > uint32_t(-1) || !wasm::isInteger(value)) {
+      return ASM_NONSIGNED;
+    }
+    if (wasm::isSInteger32(value)) {
+      return ASM_FLEXIBLE;
+    }
+    return ASM_UNSIGNED;
+  }
+  IString type = node[0]->getIString();
+  if (type == BINARY) {
+    IString op = node[1]->getIString();
+    switch (op.str[0]) {
+      case '>': {
+        if (op == TRSHIFT) {
+          return ASM_UNSIGNED;
+        }
+      } // fallthrough
+      case '|':
+      case '&':
+      case '^':
+      case '<':
+      case '=':
+      case '!':
+        return ASM_SIGNED;
+      case '+':
+      case '-':
+        return ASM_FLEXIBLE;
+      case '*':
+      case '/':
+      case '%':
+        return ASM_NONSIGNED; // without a coercion, these are double
+      default:
+        abort_on(node);
+    }
+  } else if (type == UNARY_PREFIX) {
+    IString op = node[1]->getIString();
+    switch (op.str[0]) {
+      case '-':
+        return ASM_FLEXIBLE;
+      case '+':
+        return ASM_NONSIGNED; // XXX double
+      case '~':
+        return ASM_SIGNED;
+      default:
+        abort_on(node);
+    }
+  } else if (type == CONDITIONAL) {
+    return detectSign(node[2], minifiedFround);
+  } else if (type == CALL) {
+    if (node[1]->isString() &&
+        (node[1] == MATH_FROUND || node[1] == minifiedFround)) {
+      return ASM_NONSIGNED;
+    }
+  } else if (type == SEQ) {
+    return detectSign(node[2], minifiedFround);
+  }
+  abort_on(node);
+  abort(); // avoid warning
+}
+
+Ref makeAsmCoercedZero(AsmType type) {
+  switch (type) {
+    case ASM_INT:
+      return ValueBuilder::makeNum(0);
+      break;
+    case ASM_DOUBLE:
+      return ValueBuilder::makeUnary(PLUS, ValueBuilder::makeNum(0));
+      break;
+    case ASM_FLOAT: {
+      if (!ASM_FLOAT_ZERO.isNull()) {
+        return ValueBuilder::makeName(ASM_FLOAT_ZERO);
+      } else {
+        return ValueBuilder::makeCall(MATH_FROUND, ValueBuilder::makeNum(0));
+      }
+      break;
+    }
+    case ASM_FLOAT32X4: {
+      return ValueBuilder::makeCall(SIMD_FLOAT32X4,
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0));
+      break;
+    }
+    case ASM_FLOAT64X2: {
+      return ValueBuilder::makeCall(
+        SIMD_FLOAT64X2, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0));
+      break;
+    }
+    case ASM_INT8X16: {
+      return ValueBuilder::makeCall(SIMD_INT8X16,
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0));
+      break;
+    }
+    case ASM_INT16X8: {
+      return ValueBuilder::makeCall(SIMD_INT16X8,
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0));
+      break;
+    }
+    case ASM_INT32X4: {
+      return ValueBuilder::makeCall(SIMD_INT32X4,
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0),
+                                    ValueBuilder::makeNum(0));
+      break;
+    }
+    default:
+      assert(0);
+  }
+  abort();
+}
+
+Ref makeAsmCoercion(Ref node, AsmType type) {
+  switch (type) {
+    case ASM_INT:
+      return ValueBuilder::makeBinary(node, OR, ValueBuilder::makeNum(0));
+    case ASM_DOUBLE:
+      return ValueBuilder::makeUnary(PLUS, node);
+    case ASM_FLOAT:
+      return ValueBuilder::makeCall(MATH_FROUND, node);
+    case ASM_FLOAT32X4:
+      return ValueBuilder::makeCall(SIMD_FLOAT32X4_CHECK, node);
+    case ASM_FLOAT64X2:
+      return ValueBuilder::makeCall(SIMD_FLOAT64X2_CHECK, node);
+    case ASM_INT8X16:
+      return ValueBuilder::makeCall(SIMD_INT8X16_CHECK, node);
+    case ASM_INT16X8:
+      return ValueBuilder::makeCall(SIMD_INT16X8_CHECK, node);
+    case ASM_INT32X4:
+      return ValueBuilder::makeCall(SIMD_INT32X4_CHECK, node);
+    case ASM_NONE:
+    default:
+      // non-validating code, emit nothing XXX this is dangerous, we should only
+      // allow this when we know we are not validating
+      return node;
+  }
+}
+
+Ref makeSigning(Ref node, AsmSign sign) {
+  assert(sign == ASM_SIGNED || sign == ASM_UNSIGNED);
+  return ValueBuilder::makeBinary(
+    node, sign == ASM_SIGNED ? OR : TRSHIFT, ValueBuilder::makeNum(0));
+}
diff --git a/binaryen/src/emscripten-optimizer/optimizer.h b/binaryen/src/emscripten-optimizer/optimizer.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/emscripten-optimizer/optimizer.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2015 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_optimizer_h
+#define wasm_optimizer_h
+
+#include "simple_ast.h"
+
+extern bool preciseF32, receiveJSON, emitJSON, minifyWhitespace, last;
+
+extern cashew::Ref extraInfo;
+
+//
+
+enum AsmType {
+  ASM_INT = 0,
+  ASM_DOUBLE,
+  ASM_FLOAT,
+  ASM_FLOAT32X4,
+  ASM_FLOAT64X2,
+  ASM_INT8X16,
+  ASM_INT16X8,
+  ASM_INT32X4,
+  ASM_INT64, // non-asm.js
+  ASM_NONE   // number of types
+};
+
+struct AsmData;
+
+AsmType detectType(cashew::Ref node,
+                   AsmData* asmData = nullptr,
+                   bool inVarDef = false,
+                   cashew::IString minifiedFround = cashew::IString(),
+                   bool allowI64 = false);
+
+struct AsmData {
+  struct Local {
+    Local() = default;
+    Local(AsmType type, bool param) : type(type), param(param) {}
+    AsmType type;
+    bool param; // false if a var
+  };
+  typedef std::unordered_map<cashew::IString, Local> Locals;
+
+  Locals locals;
+  std::vector<cashew::IString> params; // in order
+  std::vector<cashew::IString> vars;   // in order
+  AsmType ret;
+
+  cashew::Ref func;
+
+  AsmType getType(const cashew::IString& name) {
+    auto ret = locals.find(name);
+    if (ret != locals.end()) {
+      return ret->second.type;
+    }
+    return ASM_NONE;
+  }
+  void setType(const cashew::IString& name, AsmType type) {
+    locals[name].type = type;
+  }
+
+  bool isLocal(const cashew::IString& name) { return locals.count(name) > 0; }
+  bool isParam(const cashew::IString& name) {
+    return isLocal(name) && locals[name].param;
+  }
+  bool isVar(const cashew::IString& name) {
+    return isLocal(name) && !locals[name].param;
+  }
+
+  // if you want to fill in the data yourself
+  AsmData() = default;
+  // if you want to read data from f, and modify it as you go (parallel to
+  // denormalize)
+  AsmData(cashew::Ref f);
+
+  void denormalize();
+
+  void addParam(cashew::IString name, AsmType type) {
+    locals[name] = Local(type, true);
+    params.push_back(name);
+  }
+  void addVar(cashew::IString name, AsmType type) {
+    locals[name] = Local(type, false);
+    vars.push_back(name);
+  }
+
+  void deleteVar(cashew::IString name) {
+    locals.erase(name);
+    for (size_t i = 0; i < vars.size(); i++) {
+      if (vars[i] == name) {
+        vars.erase(vars.begin() + i);
+        break;
+      }
+    }
+  }
+};
+
+extern cashew::IString ASM_FLOAT_ZERO;
+
+extern cashew::IString SIMD_INT8X16_CHECK;
+extern cashew::IString SIMD_INT16X8_CHECK;
+extern cashew::IString SIMD_INT32X4_CHECK;
+extern cashew::IString SIMD_FLOAT32X4_CHECK;
+extern cashew::IString SIMD_FLOAT64X2_CHECK;
+
+int parseInt(const char* str);
+
+struct HeapInfo {
+  bool valid, unsign, floaty;
+  int bits;
+  AsmType type;
+};
+
+HeapInfo parseHeap(const char* name);
+
+enum AsmSign {
+  // small constants can be signed or unsigned, variables are also flexible
+  ASM_FLEXIBLE = 0,
+  ASM_SIGNED = 1,
+  ASM_UNSIGNED = 2,
+  ASM_NONSIGNED = 3,
+};
+
+extern AsmSign detectSign(cashew::Ref node, cashew::IString minifiedFround);
+
+cashew::Ref makeAsmCoercedZero(AsmType type);
+cashew::Ref makeAsmCoercion(cashew::Ref node, AsmType type);
+
+cashew::Ref makeSigning(cashew::Ref node, AsmSign sign);
+
+#endif // wasm_optimizer_h
diff --git a/binaryen/src/emscripten-optimizer/parser.cpp b/binaryen/src/emscripten-optimizer/parser.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/emscripten-optimizer/parser.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2015 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "parser.h"
+
+namespace cashew {
+
+// common strings
+
+IString TOPLEVEL("toplevel");
+IString DEFUN("defun");
+IString BLOCK("block");
+IString VAR("var");
+IString CONST("const");
+IString CONDITIONAL("conditional");
+IString BINARY("binary");
+IString RETURN("return");
+IString IF("if");
+IString ELSE("else");
+IString WHILE("while");
+IString DO("do");
+IString FOR("for");
+IString SEQ("seq");
+IString SUB("sub");
+IString CALL("call");
+IString LABEL("label");
+IString BREAK("break");
+IString CONTINUE("continue");
+IString SWITCH("switch");
+IString STRING("string");
+IString TRY("try");
+IString INF("inf");
+IString NaN("nan");
+IString LLVM_CTTZ_I32("_llvm_cttz_i32");
+IString UDIVMODDI4("___udivmoddi4");
+IString UNARY_PREFIX("unary-prefix");
+IString UNARY_POSTFIX("unary-postfix");
+IString MATH_FROUND("Math_fround");
+IString MATH_CLZ32("Math_clz32");
+IString INT64("i64");
+IString INT64_CONST("i64_const");
+IString SIMD_FLOAT32X4("SIMD_Float32x4");
+IString SIMD_FLOAT64X2("SIMD_Float64x2");
+IString SIMD_INT8X16("SIMD_Int8x16");
+IString SIMD_INT16X8("SIMD_Int16x8");
+IString SIMD_INT32X4("SIMD_Int32x4");
+IString PLUS("+");
+IString MINUS("-");
+IString OR("|");
+IString AND("&");
+IString XOR("^");
+IString L_NOT("!");
+IString B_NOT("~");
+IString LT("<");
+IString GE(">=");
+IString LE("<=");
+IString GT(">");
+IString EQ("==");
+IString NE("!=");
+IString DIV("/");
+IString MOD("%");
+IString MUL("*");
+IString RSHIFT(">>");
+IString LSHIFT("<<");
+IString TRSHIFT(">>>");
+IString HEAP8("HEAP8");
+IString HEAP16("HEAP16");
+IString HEAP32("HEAP32");
+IString HEAPF32("HEAPF32");
+IString HEAPU8("HEAPU8");
+IString HEAPU16("HEAPU16");
+IString HEAPU32("HEAPU32");
+IString HEAPF64("HEAPF64");
+IString F0("f0");
+IString EMPTY("");
+IString FUNCTION("function");
+IString OPEN_PAREN("(");
+IString OPEN_BRACE("[");
+IString OPEN_CURLY("{");
+IString CLOSE_CURLY("}");
+IString COMMA(",");
+IString QUESTION("?");
+IString COLON(":");
+IString CASE("case");
+IString DEFAULT("default");
+IString DOT("dot");
+IString PERIOD(".");
+IString NEW("new");
+IString ARRAY("array");
+IString OBJECT("object");
+IString THROW("throw");
+IString SET("=");
+IString ATOMICS("Atomics");
+IString COMPARE_EXCHANGE("compareExchange");
+IString LOAD("load");
+IString STORE("store");
+
+IStringSet
+  keywords("var const function if else do while for break continue return "
+           "switch case default throw try catch finally true false null new");
+
+const char *OPERATOR_INITS = "+-*/%<>&^|~=!,?:.", *SEPARATORS = "([;{}";
+
+int MAX_OPERATOR_SIZE = 3;
+
+std::vector<OperatorClass> operatorClasses;
+
+static std::vector<std::unordered_map<IString, int>>
+  precedences; // op, type => prec
+
+struct Init {
+  Init() {
+    // operators, rtl, type
+    operatorClasses.emplace_back(".", false, OperatorClass::Binary);
+    operatorClasses.emplace_back("! ~ + -", true, OperatorClass::Prefix);
+    operatorClasses.emplace_back("* / %", false, OperatorClass::Binary);
+    operatorClasses.emplace_back("+ -", false, OperatorClass::Binary);
+    operatorClasses.emplace_back("<< >> >>>", false, OperatorClass::Binary);
+    operatorClasses.emplace_back("< <= > >=", false, OperatorClass::Binary);
+    operatorClasses.emplace_back("== !=", false, OperatorClass::Binary);
+    operatorClasses.emplace_back("&", false, OperatorClass::Binary);
+    operatorClasses.emplace_back("^", false, OperatorClass::Binary);
+    operatorClasses.emplace_back("|", false, OperatorClass::Binary);
+    operatorClasses.emplace_back("? :", true, OperatorClass::Tertiary);
+    operatorClasses.emplace_back("=", true, OperatorClass::Binary);
+    operatorClasses.emplace_back(",", true, OperatorClass::Binary);
+
+    precedences.resize(OperatorClass::Tertiary + 1);
+
+    for (size_t prec = 0; prec < operatorClasses.size(); prec++) {
+      for (auto curr : operatorClasses[prec].ops) {
+        precedences[operatorClasses[prec].type][curr] = prec;
+      }
+    }
+  }
+};
+
+Init init;
+
+int OperatorClass::getPrecedence(Type type, IString op) {
+  return precedences[type][op];
+}
+
+bool OperatorClass::getRtl(int prec) { return operatorClasses[prec].rtl; }
+
+bool isIdentInit(char x) {
+  return (x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || x == '_' ||
+         x == '$';
+}
+bool isIdentPart(char x) { return isIdentInit(x) || (x >= '0' && x <= '9'); }
+
+} // namespace cashew
diff --git a/binaryen/src/emscripten-optimizer/parser.h b/binaryen/src/emscripten-optimizer/parser.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/emscripten-optimizer/parser.h
@@ -0,0 +1,1136 @@
+/*
+ * Copyright 2015 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.
+ */
+
+// Pure parsing. Calls methods on a Builder (template argument) to actually
+// construct the AST
+//
+// XXX All parsing methods assume they take ownership of the input string. This
+//     lets them reuse parts of it. You will segfault if the input string cannot
+//     be reused and written to.
+
+#ifndef wasm_parser_h
+#define wasm_parser_h
+
+#include <algorithm>
+#include <cstdio>
+#include <iostream>
+#include <limits>
+#include <vector>
+
+#include "istring.h"
+#include "support/safe_integer.h"
+
+namespace cashew {
+
+// common strings
+
+extern IString TOPLEVEL;
+extern IString DEFUN;
+extern IString BLOCK;
+extern IString VAR;
+extern IString CONST;
+extern IString CONDITIONAL;
+extern IString BINARY;
+extern IString RETURN;
+extern IString IF;
+extern IString ELSE;
+extern IString WHILE;
+extern IString DO;
+extern IString FOR;
+extern IString SEQ;
+extern IString SUB;
+extern IString CALL;
+extern IString LABEL;
+extern IString BREAK;
+extern IString CONTINUE;
+extern IString SWITCH;
+extern IString STRING;
+extern IString TRY;
+extern IString INF;
+extern IString NaN;
+extern IString LLVM_CTTZ_I32;
+extern IString UDIVMODDI4;
+extern IString UNARY_PREFIX;
+extern IString UNARY_POSTFIX;
+extern IString MATH_FROUND;
+extern IString MATH_CLZ32;
+extern IString INT64;
+extern IString INT64_CONST;
+extern IString SIMD_FLOAT32X4;
+extern IString SIMD_FLOAT64X2;
+extern IString SIMD_INT8X16;
+extern IString SIMD_INT16X8;
+extern IString SIMD_INT32X4;
+extern IString PLUS;
+extern IString MINUS;
+extern IString OR;
+extern IString AND;
+extern IString XOR;
+extern IString L_NOT;
+extern IString B_NOT;
+extern IString LT;
+extern IString GE;
+extern IString LE;
+extern IString GT;
+extern IString EQ;
+extern IString NE;
+extern IString DIV;
+extern IString MOD;
+extern IString MUL;
+extern IString RSHIFT;
+extern IString LSHIFT;
+extern IString TRSHIFT;
+extern IString HEAP8;
+extern IString HEAP16;
+extern IString HEAP32;
+extern IString HEAPF32;
+extern IString HEAPU8;
+extern IString HEAPU16;
+extern IString HEAPU32;
+extern IString HEAPF64;
+extern IString F0;
+extern IString EMPTY;
+extern IString FUNCTION;
+extern IString OPEN_PAREN;
+extern IString OPEN_BRACE;
+extern IString OPEN_CURLY;
+extern IString CLOSE_CURLY;
+extern IString COMMA;
+extern IString QUESTION;
+extern IString COLON;
+extern IString CASE;
+extern IString DEFAULT;
+extern IString DOT;
+extern IString PERIOD;
+extern IString NEW;
+extern IString ARRAY;
+extern IString OBJECT;
+extern IString THROW;
+extern IString SET;
+extern IString ATOMICS;
+extern IString COMPARE_EXCHANGE;
+extern IString LOAD;
+extern IString STORE;
+
+extern IStringSet keywords;
+
+extern const char *OPERATOR_INITS, *SEPARATORS;
+
+extern int MAX_OPERATOR_SIZE, LOWEST_PREC;
+
+struct OperatorClass {
+  enum Type { Binary = 0, Prefix = 1, Postfix = 2, Tertiary = 3 };
+
+  IStringSet ops;
+  bool rtl;
+  Type type;
+
+  OperatorClass(const char* o, bool r, Type t) : ops(o), rtl(r), type(t) {}
+
+  static int getPrecedence(Type type, IString op);
+  static bool getRtl(int prec);
+};
+
+extern std::vector<OperatorClass> operatorClasses;
+
+extern bool isIdentInit(char x);
+extern bool isIdentPart(char x);
+
+// parser
+
+template<class NodeRef, class Builder> class Parser {
+
+  static bool isSpace(char x) {
+    return x == 32 || x == 9 || x == 10 || x == 13;
+  } /* space, tab, linefeed/newline, or return */
+  static void skipSpace(char*& curr) {
+    while (*curr) {
+      if (isSpace(*curr)) {
+        curr++;
+        continue;
+      }
+      if (curr[0] == '/' && curr[1] == '/') {
+        curr += 2;
+        while (*curr && *curr != '\n') {
+          curr++;
+        }
+        if (*curr) {
+          curr++;
+        }
+        continue;
+      }
+      if (curr[0] == '/' && curr[1] == '*') {
+        curr += 2;
+        while (*curr && (curr[0] != '*' || curr[1] != '/')) {
+          curr++;
+        }
+        curr += 2;
+        continue;
+      }
+      return;
+    }
+  }
+
+  static bool isDigit(char x) { return x >= '0' && x <= '9'; }
+
+  static bool hasChar(const char* list, char x) {
+    while (*list) {
+      if (*list++ == x) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // An atomic fragment of something. Stops at a natural boundary.
+  enum FragType {
+    KEYWORD = 0,
+    OPERATOR = 1,
+    IDENT = 2,
+    STRING = 3, // without quotes
+    INT = 4,
+    DOUBLE = 5,
+    SEPARATOR = 6
+  };
+
+  struct Frag {
+  // MSVC does not allow unrestricted unions:
+  // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
+#ifndef _MSC_VER
+    union {
+#endif
+      IString str;
+      double num;
+#ifndef _MSC_VER
+    };
+#endif
+    int size;
+    FragType type;
+
+    bool isNumber() const { return type == INT || type == DOUBLE; }
+
+    explicit Frag(char* src) {
+      char* start = src;
+      if (isIdentInit(*src)) {
+        // read an identifier or a keyword
+        src++;
+        while (isIdentPart(*src)) {
+          src++;
+        }
+        if (*src == 0) {
+          str.set(start);
+        } else {
+          char temp = *src;
+          *src = 0;
+          str.set(start, false);
+          *src = temp;
+        }
+        type = keywords.has(str) ? KEYWORD : IDENT;
+      } else if (isDigit(*src) || (src[0] == '.' && isDigit(src[1]))) {
+        if (src[0] == '0' && (src[1] == 'x' || src[1] == 'X')) {
+          // Explicitly parse hex numbers of form "0x...", because strtod
+          // supports hex number strings only in C++11, and Visual Studio 2013
+          // does not yet support that functionality.
+          src += 2;
+          num = 0;
+          while (1) {
+            if (*src >= '0' && *src <= '9') {
+              num *= 16;
+              num += *src - '0';
+            } else if (*src >= 'a' && *src <= 'f') {
+              num *= 16;
+              num += *src - 'a' + 10;
+            } else if (*src >= 'A' && *src <= 'F') {
+              num *= 16;
+              num += *src - 'A' + 10;
+            } else {
+              break;
+            }
+            src++;
+          }
+        } else {
+          num = strtod(start, &src);
+        }
+        // asm.js must have a '.' for double values. however, we also tolerate
+        // uglify's tendency to emit without a '.' (and fix it later with a +).
+        // for valid asm.js input, the '.' should be enough, and for uglify
+        // in the emscripten optimizer pipeline, we use simple_ast where
+        // INT/DOUBLE is quite the same at this point anyhow
+        type = (std::find(start, src, '.') == src &&
+                (wasm::isSInteger32(num) || wasm::isUInteger32(num)))
+                 ? INT
+                 : DOUBLE;
+        assert(src > start);
+      } else if (hasChar(OPERATOR_INITS, *src)) {
+        switch (*src) {
+          case '!':
+            str = src[1] == '=' ? NE : L_NOT;
+            break;
+          case '%':
+            str = MOD;
+            break;
+          case '&':
+            str = AND;
+            break;
+          case '*':
+            str = MUL;
+            break;
+          case '+':
+            str = PLUS;
+            break;
+          case ',':
+            str = COMMA;
+            break;
+          case '-':
+            str = MINUS;
+            break;
+          case '.':
+            str = PERIOD;
+            break;
+          case '/':
+            str = DIV;
+            break;
+          case ':':
+            str = COLON;
+            break;
+          case '<':
+            str = src[1] == '<' ? LSHIFT : (src[1] == '=' ? LE : LT);
+            break;
+          case '=':
+            str = src[1] == '=' ? EQ : SET;
+            break;
+          case '>':
+            str = src[1] == '>' ? (src[2] == '>' ? TRSHIFT : RSHIFT)
+                                : (src[1] == '=' ? GE : GT);
+            break;
+          case '?':
+            str = QUESTION;
+            break;
+          case '^':
+            str = XOR;
+            break;
+          case '|':
+            str = OR;
+            break;
+          case '~':
+            str = B_NOT;
+            break;
+          default:
+            abort();
+        }
+        size = strlen(str.str);
+#ifndef NDEBUG
+        char temp = start[size];
+        start[size] = 0;
+        assert(strcmp(str.str, start) == 0);
+        start[size] = temp;
+#endif
+        type = OPERATOR;
+        return;
+      } else if (hasChar(SEPARATORS, *src)) {
+        type = SEPARATOR;
+        char temp = src[1];
+        src[1] = 0;
+        str.set(src, false);
+        src[1] = temp;
+        src++;
+      } else if (*src == '"' || *src == '\'') {
+        char* end = strchr(src + 1, *src);
+        *end = 0;
+        str.set(src + 1);
+        src = end + 1;
+        type = STRING;
+      } else {
+        dump("frag parsing", src);
+        abort();
+      }
+      size = src - start;
+    }
+  };
+
+  struct ExpressionElement {
+    bool isNode;
+    // MSVC does not allow unrestricted unions:
+    // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
+#ifndef _MSC_VER
+    union {
+#endif
+      NodeRef node;
+      IString op;
+#ifndef _MSC_VER
+    };
+#endif
+    ExpressionElement(NodeRef n) : isNode(true), node(n) {}
+    ExpressionElement(IString o) : isNode(false), op(o) {}
+
+    NodeRef getNode() {
+      assert(isNode);
+      return node;
+    }
+    IString getOp() {
+      assert(!isNode);
+      return op;
+    }
+  };
+
+  // This is a list of the current stack of node-operator-node-operator-etc.
+  // this works by each parseExpression call appending to the vector; then
+  // recursing out, and the toplevel sorts it all
+  typedef std::vector<ExpressionElement> ExpressionParts;
+  std::vector<ExpressionParts> expressionPartsStack;
+
+  // Parses an element in a list of such elements, e.g. list of statements in a
+  // block, or list of parameters in a call
+  NodeRef parseElement(char*& src, const char* seps = ";") {
+    // dump("parseElement", src);
+    skipSpace(src);
+    Frag frag(src);
+    src += frag.size;
+    switch (frag.type) {
+      case KEYWORD: {
+        return parseAfterKeyword(frag, src, seps);
+      }
+      case IDENT: {
+        return parseAfterIdent(frag, src, seps);
+      }
+      case STRING:
+      case INT:
+      case DOUBLE: {
+        return parseExpression(parseFrag(frag), src, seps);
+      }
+      case SEPARATOR: {
+        if (frag.str == OPEN_PAREN) {
+          return parseExpression(parseAfterParen(src), src, seps);
+        }
+        if (frag.str == OPEN_BRACE) {
+          return parseExpression(parseAfterBrace(src), src, seps);
+        }
+        if (frag.str == OPEN_CURLY) {
+          return parseExpression(parseAfterCurly(src), src, seps);
+        }
+        abort();
+      }
+      case OPERATOR: {
+        return parseExpression(frag.str, src, seps);
+      }
+      default:
+        /* dump("parseElement", src); printf("bad frag type: %d\n",frag.type);
+         */
+        abort();
+    }
+    return nullptr;
+  }
+
+  NodeRef parseFrag(Frag& frag) {
+    switch (frag.type) {
+      case IDENT:
+        return Builder::makeName(frag.str);
+      case STRING:
+        return Builder::makeString(frag.str);
+      case INT:
+        return Builder::makeInt(uint32_t(frag.num));
+      case DOUBLE:
+        return Builder::makeDouble(frag.num);
+      default:
+        abort();
+    }
+    return nullptr;
+  }
+
+  NodeRef parseAfterKeyword(Frag& frag, char*& src, const char* seps) {
+    skipSpace(src);
+    if (frag.str == FUNCTION) {
+      return parseFunction(src, seps);
+    } else if (frag.str == VAR) {
+      return parseVar(src, seps, false);
+    } else if (frag.str == CONST) {
+      return parseVar(src, seps, true);
+    } else if (frag.str == RETURN) {
+      return parseReturn(src, seps);
+    } else if (frag.str == IF) {
+      return parseIf(src, seps);
+    } else if (frag.str == DO) {
+      return parseDo(src, seps);
+    } else if (frag.str == WHILE) {
+      return parseWhile(src, seps);
+    } else if (frag.str == BREAK) {
+      return parseBreak(src, seps);
+    } else if (frag.str == CONTINUE) {
+      return parseContinue(src, seps);
+    } else if (frag.str == SWITCH) {
+      return parseSwitch(src, seps);
+    } else if (frag.str == NEW) {
+      return parseNew(src, seps);
+    } else if (frag.str == FOR) {
+      return parseFor(src, seps);
+    }
+    dump(frag.str.str, src);
+    abort();
+    return nullptr;
+  }
+
+  NodeRef parseFunction(char*& src, const char* seps) {
+    Frag name(src);
+    if (name.type == IDENT) {
+      src += name.size;
+    } else {
+      assert(name.type == SEPARATOR && name.str[0] == '(');
+      name.str = IString();
+    }
+    NodeRef ret = Builder::makeFunction(name.str);
+    skipSpace(src);
+    assert(*src == '(');
+    src++;
+    while (1) {
+      skipSpace(src);
+      if (*src == ')') {
+        break;
+      }
+      Frag arg(src);
+      assert(arg.type == IDENT);
+      src += arg.size;
+      Builder::appendArgumentToFunction(ret, arg.str);
+      skipSpace(src);
+      if (*src == ')') {
+        break;
+      }
+      if (*src == ',') {
+        src++;
+        continue;
+      }
+      abort();
+    }
+    src++;
+    Builder::setBlockContent(ret, parseBracketedBlock(src));
+    // TODO: parse expression?
+    return ret;
+  }
+
+  NodeRef parseVar(char*& src, const char* seps, bool is_const) {
+    NodeRef ret = Builder::makeVar(is_const);
+    while (1) {
+      skipSpace(src);
+      if (*src == ';') {
+        break;
+      }
+      Frag name(src);
+      assert(name.type == IDENT);
+      NodeRef value;
+      src += name.size;
+      skipSpace(src);
+      if (*src == '=') {
+        src++;
+        skipSpace(src);
+        value = parseElement(src, ";,");
+      }
+      Builder::appendToVar(ret, name.str, value);
+      skipSpace(src);
+      if (*src == ';') {
+        break;
+      }
+      if (*src == ',') {
+        src++;
+        continue;
+      }
+      abort();
+    }
+    src++;
+    return ret;
+  }
+
+  NodeRef parseReturn(char*& src, const char* seps) {
+    skipSpace(src);
+    NodeRef value = !hasChar(seps, *src) ? parseElement(src, seps) : nullptr;
+    skipSpace(src);
+    assert(hasChar(seps, *src));
+    if (*src == ';') {
+      src++;
+    }
+    return Builder::makeReturn(value);
+  }
+
+  NodeRef parseIf(char*& src, const char* seps) {
+    NodeRef condition = parseParenned(src);
+    NodeRef ifTrue = parseMaybeBracketed(src, seps);
+    skipSpace(src);
+    NodeRef ifFalse;
+    if (!hasChar(seps, *src)) {
+      Frag next(src);
+      if (next.type == KEYWORD && next.str == ELSE) {
+        src += next.size;
+        ifFalse = parseMaybeBracketed(src, seps);
+      }
+    }
+    return Builder::makeIf(condition, ifTrue, ifFalse);
+  }
+
+  NodeRef parseDo(char*& src, const char* seps) {
+    NodeRef body = parseMaybeBracketed(src, seps);
+    skipSpace(src);
+    Frag next(src);
+    assert(next.type == KEYWORD && next.str == WHILE);
+    src += next.size;
+    NodeRef condition = parseParenned(src);
+    return Builder::makeDo(body, condition);
+  }
+
+  NodeRef parseWhile(char*& src, const char* seps) {
+    NodeRef condition = parseParenned(src);
+    NodeRef body = parseMaybeBracketed(src, seps);
+    return Builder::makeWhile(condition, body);
+  }
+
+  NodeRef parseFor(char*& src, const char* seps) {
+    skipSpace(src);
+    assert(*src == '(');
+    src++;
+    NodeRef init = parseElement(src, ";");
+    skipSpace(src);
+    assert(*src == ';');
+    src++;
+    NodeRef condition = parseElement(src, ";");
+    skipSpace(src);
+    assert(*src == ';');
+    src++;
+    NodeRef inc = parseElement(src, ")");
+    skipSpace(src);
+    assert(*src == ')');
+    src++;
+    NodeRef body = parseMaybeBracketed(src, seps);
+    return Builder::makeFor(init, condition, inc, body);
+  }
+
+  NodeRef parseBreak(char*& src, const char* seps) {
+    skipSpace(src);
+    Frag next(src);
+    if (next.type == IDENT) {
+      src += next.size;
+    }
+    return Builder::makeBreak(next.type == IDENT ? next.str : IString());
+  }
+
+  NodeRef parseContinue(char*& src, const char* seps) {
+    skipSpace(src);
+    Frag next(src);
+    if (next.type == IDENT) {
+      src += next.size;
+    }
+    return Builder::makeContinue(next.type == IDENT ? next.str : IString());
+  }
+
+  NodeRef parseSwitch(char*& src, const char* seps) {
+    NodeRef ret = Builder::makeSwitch(parseParenned(src));
+    skipSpace(src);
+    assert(*src == '{');
+    src++;
+    while (1) {
+      // find all cases and possibly a default
+      skipSpace(src);
+      if (*src == '}') {
+        break;
+      }
+      Frag next(src);
+      if (next.type == KEYWORD) {
+        if (next.str == CASE) {
+          src += next.size;
+          skipSpace(src);
+          NodeRef arg;
+          Frag value(src);
+          if (value.isNumber()) {
+            arg = parseFrag(value);
+            src += value.size;
+          } else if (value.type == OPERATOR) {
+            // negative number
+            assert(value.str == MINUS);
+            src += value.size;
+            skipSpace(src);
+            Frag value2(src);
+            assert(value2.isNumber());
+            arg = Builder::makePrefix(MINUS, parseFrag(value2));
+            src += value2.size;
+          } else {
+            // identifier and function call
+            assert(value.type == IDENT);
+            src += value.size;
+            skipSpace(src);
+            arg = parseCall(parseFrag(value), src);
+          }
+          Builder::appendCaseToSwitch(ret, arg);
+          skipSpace(src);
+          assert(*src == ':');
+          src++;
+          continue;
+        } else if (next.str == DEFAULT) {
+          src += next.size;
+          Builder::appendDefaultToSwitch(ret);
+          skipSpace(src);
+          assert(*src == ':');
+          src++;
+          continue;
+        }
+        // otherwise, may be some keyword that happens to start a block (e.g.
+        // case 1: _return_ 5)
+      }
+      // not case X: or default: or }, so must be some code
+      skipSpace(src);
+      bool explicitBlock = *src == '{';
+      NodeRef subBlock = explicitBlock ? parseBracketedBlock(src)
+                                       : parseBlock(src, ";}", CASE, DEFAULT);
+      Builder::appendCodeToSwitch(ret, subBlock, explicitBlock);
+    }
+    skipSpace(src);
+    assert(*src == '}');
+    src++;
+    return ret;
+  }
+
+  NodeRef parseNew(char*& src, const char* seps) {
+    return Builder::makeNew(parseElement(src, seps));
+  }
+
+  NodeRef parseAfterIdent(Frag& frag, char*& src, const char* seps) {
+    skipSpace(src);
+    if (*src == '(') {
+      return parseExpression(parseCall(parseFrag(frag), src), src, seps);
+    }
+    if (*src == '[') {
+      return parseExpression(parseIndexing(parseFrag(frag), src), src, seps);
+    }
+    if (*src == ':' && expressionPartsStack.back().size() == 0) {
+      src++;
+      skipSpace(src);
+      NodeRef inner;
+      if (*src == '{') {
+        // context lets us know this is not an object, but a block
+        inner = parseBracketedBlock(src);
+      } else {
+        inner = parseElement(src, seps);
+      }
+      return Builder::makeLabel(frag.str, inner);
+    }
+    if (*src == '.') {
+      return parseExpression(parseDotting(parseFrag(frag), src), src, seps);
+    }
+    return parseExpression(parseFrag(frag), src, seps);
+  }
+
+  NodeRef parseCall(NodeRef target, char*& src) {
+    expressionPartsStack.resize(expressionPartsStack.size() + 1);
+    assert(*src == '(');
+    src++;
+    NodeRef ret = Builder::makeCall(target);
+    while (1) {
+      skipSpace(src);
+      if (*src == ')') {
+        break;
+      }
+      Builder::appendToCall(ret, parseElement(src, ",)"));
+      skipSpace(src);
+      if (*src == ')') {
+        break;
+      }
+      if (*src == ',') {
+        src++;
+        continue;
+      }
+      abort();
+    }
+    src++;
+    assert(expressionPartsStack.back().size() == 0);
+    expressionPartsStack.pop_back();
+    return ret;
+  }
+
+  NodeRef parseIndexing(NodeRef target, char*& src) {
+    expressionPartsStack.resize(expressionPartsStack.size() + 1);
+    assert(*src == '[');
+    src++;
+    NodeRef ret = Builder::makeIndexing(target, parseElement(src, "]"));
+    skipSpace(src);
+    assert(*src == ']');
+    src++;
+    assert(expressionPartsStack.back().size() == 0);
+    expressionPartsStack.pop_back();
+    return ret;
+  }
+
+  NodeRef parseDotting(NodeRef target, char*& src) {
+    assert(*src == '.');
+    src++;
+    Frag key(src);
+    assert(key.type == IDENT);
+    src += key.size;
+    return Builder::makeDot(target, key.str);
+  }
+
+  NodeRef parseAfterParen(char*& src) {
+    expressionPartsStack.resize(expressionPartsStack.size() + 1);
+    skipSpace(src);
+    NodeRef ret = parseElement(src, ")");
+    skipSpace(src);
+    assert(*src == ')');
+    src++;
+    assert(expressionPartsStack.back().size() == 0);
+    expressionPartsStack.pop_back();
+    return ret;
+  }
+
+  NodeRef parseAfterBrace(char*& src) {
+    expressionPartsStack.resize(expressionPartsStack.size() + 1);
+    NodeRef ret = Builder::makeArray();
+    while (1) {
+      skipSpace(src);
+      assert(*src);
+      if (*src == ']') {
+        break;
+      }
+      NodeRef element = parseElement(src, ",]");
+      Builder::appendToArray(ret, element);
+      skipSpace(src);
+      if (*src == ']') {
+        break;
+      }
+      if (*src == ',') {
+        src++;
+        continue;
+      }
+      abort();
+    }
+    src++;
+    return ret;
+  }
+
+  NodeRef parseAfterCurly(char*& src) {
+    expressionPartsStack.resize(expressionPartsStack.size() + 1);
+    NodeRef ret = Builder::makeObject();
+    while (1) {
+      skipSpace(src);
+      assert(*src);
+      if (*src == '}') {
+        break;
+      }
+      Frag key(src);
+      assert(key.type == IDENT || key.type == STRING);
+      src += key.size;
+      skipSpace(src);
+      assert(*src == ':');
+      src++;
+      NodeRef value = parseElement(src, ",}");
+      Builder::appendToObject(ret, key.str, value);
+      skipSpace(src);
+      if (*src == '}') {
+        break;
+      }
+      if (*src == ',') {
+        src++;
+        continue;
+      }
+      abort();
+    }
+    src++;
+    return ret;
+  }
+
+  void dumpParts(ExpressionParts& parts, int i) {
+    printf("expressionparts: %d (at %d)\n", parts.size(), i);
+    printf("| ");
+    for (int i = 0; i < parts.size(); i++) {
+      if (parts[i].isNode) {
+        parts[i].getNode()->stringify(std::cout);
+        printf("    ");
+      } else {
+        printf("    _%s_    ", parts[i].getOp().str);
+      }
+    }
+    printf("|\n");
+  }
+
+  NodeRef makeBinary(NodeRef left, IString op, NodeRef right) {
+    if (op == PERIOD) {
+      return Builder::makeDot(left, right);
+    } else {
+      return Builder::makeBinary(left, op, right);
+    }
+  }
+
+  NodeRef
+  parseExpression(ExpressionElement initial, char*& src, const char* seps) {
+    // dump("parseExpression", src);
+    ExpressionParts& parts = expressionPartsStack.back();
+    skipSpace(src);
+    if (*src == 0 || hasChar(seps, *src)) {
+      if (parts.size() > 0) {
+        parts.push_back(initial); // cherry on top of the cake
+      }
+      return initial.getNode();
+    }
+    bool top = parts.size() == 0;
+    if (initial.isNode) {
+      Frag next(src);
+      if (next.type == OPERATOR) {
+        parts.push_back(initial);
+        src += next.size;
+        parts.push_back(next.str);
+      } else {
+        if (*src == '(') {
+          initial = parseCall(initial.getNode(), src);
+        } else if (*src == '[') {
+          initial = parseIndexing(initial.getNode(), src);
+        } else {
+          dump("bad parseExpression state", src);
+          abort();
+        }
+        return parseExpression(initial, src, seps);
+      }
+    } else {
+      parts.push_back(initial);
+    }
+    NodeRef last = parseElement(src, seps);
+    if (!top) {
+      return last;
+    }
+    {
+      // |parts| may have been invalidated by that call
+      ExpressionParts& parts = expressionPartsStack.back();
+      // we are the toplevel. sort it all out
+      // collapse right to left, highest priority first
+      // dumpParts(parts, 0);
+      for (auto& ops : operatorClasses) {
+        if (ops.rtl) {
+          // right to left
+          for (int i = parts.size() - 1; i >= 0; i--) {
+            if (parts[i].isNode) {
+              continue;
+            }
+            IString op = parts[i].getOp();
+            if (!ops.ops.has(op)) {
+              continue;
+            }
+            if (ops.type == OperatorClass::Binary && i > 0 &&
+                i < (int)parts.size() - 1) {
+              parts[i] =
+                makeBinary(parts[i - 1].getNode(), op, parts[i + 1].getNode());
+              parts.erase(parts.begin() + i + 1);
+              parts.erase(parts.begin() + i - 1);
+            } else if (ops.type == OperatorClass::Prefix &&
+                       i < (int)parts.size() - 1) {
+              if (i > 0 && parts[i - 1].isNode) {
+                // cannot apply prefix operator if it would join two nodes
+                continue;
+              }
+              parts[i] = Builder::makePrefix(op, parts[i + 1].getNode());
+              parts.erase(parts.begin() + i + 1);
+            } else if (ops.type == OperatorClass::Tertiary) {
+              // we must be at  X ? Y : Z
+              //                      ^
+              // dumpParts(parts, i);
+              if (op != COLON) {
+                continue;
+              }
+              assert(i < (int)parts.size() - 1 && i >= 3);
+              if (parts[i - 2].getOp() != QUESTION) {
+                continue; // e.g. x ? y ? 1 : 0 : 2
+              }
+              parts[i - 3] = Builder::makeConditional(parts[i - 3].getNode(),
+                                                      parts[i - 1].getNode(),
+                                                      parts[i + 1].getNode());
+              parts.erase(parts.begin() + i - 2, parts.begin() + i + 2);
+              // basically a reset, due to things like x ? y ? 1 : 0 : 2
+              i = parts.size();
+            } // TODO: postfix
+          }
+        } else {
+          // left to right
+          for (int i = 0; i < (int)parts.size(); i++) {
+            if (parts[i].isNode) {
+              continue;
+            }
+            IString op = parts[i].getOp();
+            if (!ops.ops.has(op)) {
+              continue;
+            }
+            if (ops.type == OperatorClass::Binary && i > 0 &&
+                i < (int)parts.size() - 1) {
+              parts[i] =
+                makeBinary(parts[i - 1].getNode(), op, parts[i + 1].getNode());
+              parts.erase(parts.begin() + i + 1);
+              parts.erase(parts.begin() + i - 1);
+              i--;
+            } else if (ops.type == OperatorClass::Prefix &&
+                       i < (int)parts.size() - 1) {
+              if (i > 0 && parts[i - 1].isNode) {
+                // cannot apply prefix operator if it would join two nodes
+                continue;
+              }
+              parts[i] = Builder::makePrefix(op, parts[i + 1].getNode());
+              parts.erase(parts.begin() + i + 1);
+              // allow a previous prefix operator to cascade
+              i = std::max(i - 2, 0);
+            } // TODO: tertiary, postfix
+          }
+        }
+      }
+      assert(parts.size() == 1);
+      NodeRef ret = parts[0].getNode();
+      parts.clear();
+      return ret;
+    }
+  }
+
+  // Parses a block of code (e.g. a bunch of statements inside {,}, or the top
+  // level of o file)
+  NodeRef parseBlock(char*& src,
+                     const char* seps = ";",
+                     IString keywordSep1 = IString(),
+                     IString keywordSep2 = IString()) {
+    NodeRef block = Builder::makeBlock();
+    // dump("parseBlock", src);
+    while (1) {
+      skipSpace(src);
+      if (*src == 0) {
+        break;
+      }
+      if (*src == ';') {
+        src++; // skip a statement in this block
+        continue;
+      }
+      if (hasChar(seps, *src)) {
+        break;
+      }
+      if (!!keywordSep1) {
+        Frag next(src);
+        if (next.type == KEYWORD && next.str == keywordSep1) {
+          break;
+        }
+      }
+      if (!!keywordSep2) {
+        Frag next(src);
+        if (next.type == KEYWORD && next.str == keywordSep2) {
+          break;
+        }
+      }
+      NodeRef element = parseElementOrStatement(src, seps);
+      Builder::appendToBlock(block, element);
+    }
+    return block;
+  }
+
+  NodeRef parseBracketedBlock(char*& src) {
+    skipSpace(src);
+    assert(*src == '{');
+    src++;
+    // the two are not symmetrical, ; is just internally separating, } is the
+    // final one - parseBlock knows all this
+    NodeRef block = parseBlock(src, ";}");
+    assert(*src == '}');
+    src++;
+    return block;
+  }
+
+  NodeRef parseElementOrStatement(char*& src, const char* seps) {
+    skipSpace(src);
+    if (*src == ';') {
+      src++;
+      // we don't need the brackets here, but oh well
+      return Builder::makeBlock();
+    }
+    if (*src == '{') { // detect a trivial {} in a statement context
+      char* before = src;
+      src++;
+      skipSpace(src);
+      if (*src == '}') {
+        src++;
+        // we don't need the brackets here, but oh well
+        return Builder::makeBlock();
+      }
+      src = before;
+    }
+    NodeRef ret = parseElement(src, seps);
+    skipSpace(src);
+    if (*src == ';') {
+      ret = Builder::makeStatement(ret);
+      src++;
+    }
+    return ret;
+  }
+
+  NodeRef parseMaybeBracketed(char*& src, const char* seps) {
+    skipSpace(src);
+    return *src == '{' ? parseBracketedBlock(src)
+                       : parseElementOrStatement(src, seps);
+  }
+
+  NodeRef parseParenned(char*& src) {
+    skipSpace(src);
+    assert(*src == '(');
+    src++;
+    NodeRef ret = parseElement(src, ")");
+    skipSpace(src);
+    assert(*src == ')');
+    src++;
+    return ret;
+  }
+
+  // Debugging
+
+  char* allSource = nullptr;
+  int allSize = 0;
+
+  static void dump(const char* where, char* curr) {
+    /*
+    printf("%s:\n=============\n", where);
+    for (int i = 0; i < allSize; i++)
+      printf("%c", allSource[i] ? allSource[i] :
+    '?');
+    printf("\n");
+    for (int i = 0; i < (curr - allSource); i++) printf(" ");
+    printf("^\n=============\n");
+    */
+    fprintf(stderr, "%s:\n==========\n", where);
+    int newlinesLeft = 2;
+    int charsLeft = 200;
+    while (*curr) {
+      if (*curr == '\n') {
+        newlinesLeft--;
+        if (newlinesLeft == 0) {
+          break;
+        }
+      }
+      charsLeft--;
+      if (charsLeft == 0) {
+        break;
+      }
+      fprintf(stderr, "%c", *curr++);
+    }
+    fprintf(stderr, "\n\n");
+  }
+
+public:
+  Parser() { expressionPartsStack.resize(1); }
+
+  // Highest-level parsing, as of a JavaScript script file.
+  NodeRef parseToplevel(char* src) {
+    allSource = src;
+    allSize = strlen(src);
+    NodeRef toplevel = Builder::makeToplevel();
+    Builder::setBlockContent(toplevel, parseBlock(src));
+    return toplevel;
+  }
+};
+
+} // namespace cashew
+
+#endif // wasm_parser_h
diff --git a/binaryen/src/emscripten-optimizer/simple_ast.cpp b/binaryen/src/emscripten-optimizer/simple_ast.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/emscripten-optimizer/simple_ast.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2015 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "simple_ast.h"
+
+namespace cashew {
+
+// Ref methods
+
+Ref& Ref::operator[](unsigned x) { return (*get())[x]; }
+
+Ref& Ref::operator[](IString x) { return (*get())[x]; }
+
+bool Ref::operator==(const char* str) {
+  return get()->isString() && !strcmp(get()->str.str, str);
+}
+
+bool Ref::operator!=(const char* str) {
+  return get()->isString() ? !!strcmp(get()->str.str, str) : true;
+}
+
+bool Ref::operator==(const IString& str) {
+  return get()->isString() && get()->str == str;
+}
+
+bool Ref::operator!=(const IString& str) {
+  return get()->isString() && get()->str != str;
+}
+
+bool Ref::operator==(Ref other) { return **this == *other; }
+
+bool Ref::operator!() { return !get() || get()->isNull(); }
+
+// Arena
+
+GlobalMixedArena arena;
+
+// Value
+
+Value& Value::setAssign(Ref target, Ref value) {
+  asAssign()->target() = target;
+  asAssign()->value() = value;
+  return *this;
+}
+
+Value& Value::setAssignName(IString target, Ref value) {
+  asAssignName()->target() = target;
+  asAssignName()->value() = value;
+  return *this;
+}
+
+Assign* Value::asAssign() {
+  assert(isAssign());
+  return static_cast<Assign*>(this);
+}
+
+AssignName* Value::asAssignName() {
+  assert(isAssignName());
+  return static_cast<AssignName*>(this);
+}
+
+void Value::stringify(std::ostream& os, bool pretty) {
+  static int indent = 0;
+#define indentify()                                                            \
+  {                                                                            \
+    for (int i_ = 0; i_ < indent; i_++)                                        \
+      os << "  ";                                                              \
+  }
+  switch (type) {
+    case String: {
+      if (str.str) {
+        os << '"' << str.str << '"';
+      } else {
+        os << "\"(null)\"";
+      }
+      break;
+    }
+    case Number: {
+      // doubles can have 17 digits of precision
+      os << std::setprecision(17) << num;
+      break;
+    }
+    case Array: {
+      if (arr->size() == 0) {
+        os << "[]";
+        break;
+      }
+      os << '[';
+      if (pretty) {
+        os << std::endl;
+        indent++;
+      }
+      for (size_t i = 0; i < arr->size(); i++) {
+        if (i > 0) {
+          if (pretty) {
+            os << "," << std::endl;
+          } else {
+            os << ", ";
+          }
+        }
+        indentify();
+        (*arr)[i]->stringify(os, pretty);
+      }
+      if (pretty) {
+        os << std::endl;
+        indent--;
+      }
+      indentify();
+      os << ']';
+      break;
+    }
+    case Null: {
+      os << "null";
+      break;
+    }
+    case Bool: {
+      os << (boo ? "true" : "false");
+      break;
+    }
+    case Object: {
+      os << '{';
+      if (pretty) {
+        os << std::endl;
+        indent++;
+      }
+      bool first = true;
+      for (auto i : *obj) {
+        if (first) {
+          first = false;
+        } else {
+          os << ", ";
+          if (pretty) {
+            os << std::endl;
+          }
+        }
+        indentify();
+        os << '"' << i.first.c_str() << "\": ";
+        i.second->stringify(os, pretty);
+      }
+      if (pretty) {
+        os << std::endl;
+        indent--;
+      }
+      indentify();
+      os << '}';
+      break;
+    }
+    case Assign_: {
+      os << "[";
+      ref->stringify(os, pretty);
+      os << ", ";
+      asAssign()->value()->stringify(os, pretty);
+      os << "]";
+      break;
+    }
+    case AssignName_: {
+      os << "[\"" << asAssignName()->target().str << "\"";
+      os << ", ";
+      asAssignName()->value()->stringify(os, pretty);
+      os << "]";
+      break;
+    }
+  }
+}
+
+// dump
+
+void dump(const char* str, Ref node, bool pretty) {
+  std::cerr << str << ": ";
+  if (!!node) {
+    node->stringify(std::cerr, pretty);
+  } else {
+    std::cerr << "(nullptr)";
+  }
+  std::cerr << std::endl;
+}
+
+} // namespace cashew
diff --git a/binaryen/src/emscripten-optimizer/simple_ast.h b/binaryen/src/emscripten-optimizer/simple_ast.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/emscripten-optimizer/simple_ast.h
@@ -0,0 +1,1851 @@
+/*
+ * Copyright 2015 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_simple_ast_h
+#define wasm_simple_ast_h
+
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <iomanip>
+#include <iostream>
+#include <limits>
+#include <ostream>
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "mixed_arena.h"
+#include "parser.h"
+#include "snprintf.h"
+#include "support/safe_integer.h"
+
+#define err(str) fprintf(stderr, str "\n");
+#define errv(str, ...) fprintf(stderr, str "\n", __VA_ARGS__);
+#define printErr err
+
+namespace cashew {
+
+struct Value;
+struct Ref;
+
+void dump(const char* str, Ref node, bool pretty = false);
+
+// Reference to a value, plus some operators for convenience
+struct Ref {
+  Value* inst;
+
+  Ref(Value* v = nullptr) : inst(v) {}
+
+  Value* get() { return inst; }
+
+  Value& operator*() { return *inst; }
+  Value* operator->() { return inst; }
+  Ref& operator[](unsigned x);
+  Ref& operator[](IString x);
+
+  // special conveniences
+  bool operator==(const char* str); // comparison to string, which is by value
+  bool operator!=(const char* str);
+  bool operator==(const IString& str);
+  bool operator!=(const IString& str);
+  // prevent Ref == number, which is potentially ambiguous; use ->getNumber() ==
+  // number
+  bool operator==(double d) {
+    abort();
+    return false;
+  }
+  bool operator==(Ref other);
+  bool operator!(); // check if null, in effect
+};
+
+// Arena allocation, free it all on process exit
+
+// A mixed arena for global allocation only, so members do not
+// receive an allocator, they all use the global one anyhow
+class GlobalMixedArena : public MixedArena {
+public:
+  template<class T> T* alloc() {
+    auto* ret = static_cast<T*>(allocSpace(sizeof(T), alignof(T)));
+    new (ret) T();
+    return ret;
+  }
+};
+
+extern GlobalMixedArena arena;
+
+class ArrayStorage : public ArenaVectorBase<ArrayStorage, Ref> {
+public:
+  void allocate(size_t size) {
+    allocatedElements = size;
+    data = static_cast<Ref*>(
+      arena.allocSpace(sizeof(Ref) * allocatedElements, alignof(Ref)));
+  }
+};
+
+struct Assign;
+struct AssignName;
+
+// Main value type
+struct Value {
+  enum Type {
+    String = 0,
+    Number = 1,
+    Array = 2,
+    Null = 3,
+    Bool = 4,
+    Object = 5,
+    Assign_ = 6, // ref = target
+    AssignName_ = 7
+  };
+
+  Type type = Null;
+
+  typedef std::unordered_map<IString, Ref> ObjectStorage;
+
+  // MSVC does not allow unrestricted unions:
+  // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
+#ifdef _MSC_VER
+  IString str;
+#endif
+  union { // TODO: optimize
+#ifndef _MSC_VER
+    IString str;
+#endif
+    double num;
+    ArrayStorage* arr;
+    bool boo;
+    ObjectStorage* obj;
+    Ref ref;
+  };
+
+  // constructors all copy their input
+  Value() {}
+  explicit Value(const char* s) { setString(s); }
+  explicit Value(double n) { setNumber(n); }
+  explicit Value(ArrayStorage& a) {
+    setArray();
+    *arr = a;
+  }
+  // no bool constructor - would endanger the double one (int might convert the
+  // wrong way)
+
+  ~Value() { free(); }
+
+  void free() {
+    if (type == Array) {
+      arr->clear();
+    } else if (type == Object) {
+      delete obj;
+    }
+    type = Null;
+    num = 0;
+  }
+
+  Value& setString(const char* s) {
+    free();
+    type = String;
+    str.set(s);
+    return *this;
+  }
+  Value& setString(const IString& s) {
+    free();
+    type = String;
+    str.set(s);
+    return *this;
+  }
+  Value& setNumber(double n) {
+    free();
+    type = Number;
+    num = n;
+    return *this;
+  }
+  Value& setArray(ArrayStorage& a) {
+    free();
+    type = Array;
+    arr = arena.alloc<ArrayStorage>();
+    *arr = a;
+    return *this;
+  }
+  Value& setArray(size_t size_hint = 0) {
+    free();
+    type = Array;
+    arr = arena.alloc<ArrayStorage>();
+    arr->reserve(size_hint);
+    return *this;
+  }
+  Value& setNull() {
+    free();
+    type = Null;
+    return *this;
+  }
+  // Bool in the name, as otherwise might overload over int
+  Value& setBool(bool b) {
+    free();
+    type = Bool;
+    boo = b;
+    return *this;
+  }
+  Value& setObject() {
+    free();
+    type = Object;
+    obj = new ObjectStorage();
+    return *this;
+  }
+  Value& setAssign(Ref target, Ref value);
+  Value& setAssignName(IString target, Ref value);
+
+  bool isString() { return type == String; }
+  bool isNumber() { return type == Number; }
+  bool isArray() { return type == Array; }
+  bool isNull() { return type == Null; }
+  bool isBool() { return type == Bool; }
+  bool isObject() { return type == Object; }
+  bool isAssign() { return type == Assign_; }
+  bool isAssignName() { return type == AssignName_; }
+
+  // avoid overloading == as it might overload over int
+  bool isBool(bool b) { return type == Bool && b == boo; }
+
+  // convenience function to check if something is an array and
+  // also has a certain string as the first element. This is a
+  // very common operation as the first element defines the node
+  // type for most ast nodes
+  bool isArray(IString name) { return isArray() && (*this)[0] == name; }
+
+  const char* getCString() {
+    assert(isString());
+    return str.str;
+  }
+  IString& getIString() {
+    assert(isString());
+    return str;
+  }
+  double& getNumber() {
+    assert(isNumber());
+    return num;
+  }
+  ArrayStorage& getArray() {
+    assert(isArray());
+    return *arr;
+  }
+  bool& getBool() {
+    assert(isBool());
+    return boo;
+  }
+
+  Assign* asAssign();
+  AssignName* asAssignName();
+
+  int32_t getInteger() { // convenience function to get a known integer
+    assert(wasm::isInteger(getNumber()));
+    int32_t ret = getNumber();
+    assert(double(ret) == getNumber()); // no loss in conversion
+    return ret;
+  }
+
+  Value& operator=(const Value& other) {
+    free();
+    switch (other.type) {
+      case String:
+        setString(other.str);
+        break;
+      case Number:
+        setNumber(other.num);
+        break;
+      case Array:
+        setArray(*other.arr);
+        break;
+      case Null:
+        setNull();
+        break;
+      case Bool:
+        setBool(other.boo);
+        break;
+      default:
+        abort(); // TODO
+    }
+    return *this;
+  }
+
+  bool operator==(const Value& other) {
+    if (type != other.type) {
+      return false;
+    }
+    switch (other.type) {
+      case String:
+        return str == other.str;
+      case Number:
+        return num == other.num;
+      case Array:
+        return this == &other; // if you want a deep compare, use deepCompare
+      case Null:
+        break;
+      case Bool:
+        return boo == other.boo;
+      case Object:
+        return this == &other; // if you want a deep compare, use deepCompare
+      default:
+        abort();
+    }
+    return true;
+  }
+
+  char* parse(char* curr) {
+  /* space, tab, linefeed/newline, or return */
+#define is_json_space(x) (x == 32 || x == 9 || x == 10 || x == 13)
+#define skip()                                                                 \
+  {                                                                            \
+    while (*curr && is_json_space(*curr))                                      \
+      curr++;                                                                  \
+  }
+    skip();
+    if (*curr == '"') {
+      // String
+      curr++;
+      char* close = strchr(curr, '"');
+      assert(close);
+      *close = 0; // end this string, and reuse it straight from the input
+      setString(curr);
+      curr = close + 1;
+    } else if (*curr == '[') {
+      // Array
+      curr++;
+      skip();
+      setArray();
+      while (*curr != ']') {
+        Ref temp = arena.alloc<Value>();
+        arr->push_back(temp);
+        curr = temp->parse(curr);
+        skip();
+        if (*curr == ']') {
+          break;
+        }
+        assert(*curr == ',');
+        curr++;
+        skip();
+      }
+      curr++;
+    } else if (*curr == 'n') {
+      // Null
+      assert(strncmp(curr, "null", 4) == 0);
+      setNull();
+      curr += 4;
+    } else if (*curr == 't') {
+      // Bool true
+      assert(strncmp(curr, "true", 4) == 0);
+      setBool(true);
+      curr += 4;
+    } else if (*curr == 'f') {
+      // Bool false
+      assert(strncmp(curr, "false", 5) == 0);
+      setBool(false);
+      curr += 5;
+    } else if (*curr == '{') {
+      // Object
+      curr++;
+      skip();
+      setObject();
+      while (*curr != '}') {
+        assert(*curr == '"');
+        curr++;
+        char* close = strchr(curr, '"');
+        assert(close);
+        *close = 0; // end this string, and reuse it straight from the input
+        IString key(curr);
+        curr = close + 1;
+        skip();
+        assert(*curr == ':');
+        curr++;
+        skip();
+        Ref value = arena.alloc<Value>();
+        curr = value->parse(curr);
+        (*obj)[key] = value;
+        skip();
+        if (*curr == '}') {
+          break;
+        }
+        assert(*curr == ',');
+        curr++;
+        skip();
+      }
+      curr++;
+    } else {
+      // Number
+      char* after;
+      setNumber(strtod(curr, &after));
+      curr = after;
+    }
+    return curr;
+  }
+
+  void stringify(std::ostream& os, bool pretty = false);
+
+  // String operations
+
+  // Number operations
+
+  // Array operations
+
+  size_t size() {
+    assert(isArray());
+    return arr->size();
+  }
+
+  bool empty() { return size() == 0; }
+
+  void setSize(size_t size) {
+    assert(isArray());
+    auto old = arr->size();
+    if (old != size) {
+      arr->resize(size);
+    }
+    if (old < size) {
+      for (auto i = old; i < size; i++) {
+        (*arr)[i] = arena.alloc<Value>();
+      }
+    }
+  }
+
+  Ref& operator[](unsigned x) {
+    assert(isArray());
+    return (*arr)[x];
+  }
+
+  Value& push_back(Ref r) {
+    assert(isArray());
+    arr->push_back(r);
+    return *this;
+  }
+  Ref pop_back() {
+    assert(isArray());
+    Ref ret = arr->back();
+    arr->pop_back();
+    return ret;
+  }
+
+  Ref back() {
+    assert(isArray());
+    if (arr->size() == 0) {
+      return nullptr;
+    }
+    return arr->back();
+  }
+
+  void splice(int x, int num) {
+    assert(isArray());
+    arr->erase(arr->begin() + x, arr->begin() + x + num);
+  }
+
+  int indexOf(Ref other) {
+    assert(isArray());
+    for (size_t i = 0; i < arr->size(); i++) {
+      if (other == (*arr)[i]) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  Ref map(std::function<Ref(Ref node)> func) {
+    assert(isArray());
+    Ref ret = arena.alloc<Value>();
+    ret->setArray();
+    for (size_t i = 0; i < arr->size(); i++) {
+      ret->push_back(func((*arr)[i]));
+    }
+    return ret;
+  }
+
+  Ref filter(std::function<bool(Ref node)> func) {
+    assert(isArray());
+    Ref ret = arena.alloc<Value>();
+    ret->setArray();
+    for (size_t i = 0; i < arr->size(); i++) {
+      Ref curr = (*arr)[i];
+      if (func(curr)) {
+        ret->push_back(curr);
+      }
+    }
+    return ret;
+  }
+
+  /*
+  void forEach(std::function<void (Ref)> func) {
+    for (size_t i = 0; i < arr->size(); i++) {
+      func((*arr)[i]);
+    }
+  }
+  */
+
+  // Null operations
+
+  // Bool operations
+
+  // Object operations
+
+  Ref& operator[](IString x) {
+    assert(isObject());
+    return (*obj)[x];
+  }
+
+  bool has(IString x) {
+    assert(isObject());
+    return obj->count(x) > 0;
+  }
+};
+
+struct Assign : public Value {
+  Ref value_;
+
+  Assign(Ref targetInit, Ref valueInit) {
+    type = Assign_;
+    target() = targetInit;
+    value() = valueInit;
+  }
+
+  Assign() : Assign(nullptr, nullptr) {}
+
+  Ref& target() { return ref; }
+  Ref& value() { return value_; }
+};
+
+struct AssignName : public Value {
+  IString target_;
+
+  AssignName(IString targetInit, Ref valueInit) {
+    type = AssignName_;
+    target() = targetInit;
+    value() = valueInit;
+  }
+
+  AssignName() : AssignName(IString(), nullptr) {}
+
+  IString& target() { return target_; }
+  Ref& value() { return ref; }
+};
+
+// JS printing support
+
+struct JSPrinter {
+  bool pretty, finalize;
+
+  char* buffer = nullptr;
+  size_t size = 0;
+  size_t used = 0;
+
+  int indent = 0;
+  bool possibleSpace = false; // add a space to separate identifiers
+
+  Ref ast;
+
+  JSPrinter(bool pretty_, bool finalize_, Ref ast_)
+    : pretty(pretty_), finalize(finalize_), ast(ast_) {}
+
+  ~JSPrinter() { free(buffer); }
+
+  void printAst() {
+    print(ast);
+    ensure(1);
+    buffer[used] = 0;
+  }
+
+  // Utils
+
+  void ensure(int safety = 100) {
+    if (size >= used + safety) {
+      return;
+    }
+    size = std::max((size_t)1024, size * 2) + safety;
+    if (!buffer) {
+      buffer = (char*)malloc(size);
+      if (!buffer) {
+        errv("Out of memory allocating %zd bytes for output buffer!", size);
+        abort();
+      }
+    } else {
+      char* buf = (char*)realloc(buffer, size);
+      if (!buf) {
+        free(buffer);
+        errv("Out of memory allocating %zd bytes for output buffer!", size);
+        abort();
+      }
+      buffer = buf;
+    }
+  }
+
+  void emit(char c) {
+    maybeSpace(c);
+    if (!pretty && c == '}' && buffer[used - 1] == ';') {
+      used--; // optimize ;} into }, the ; is not separating anything
+    }
+    ensure(1);
+    buffer[used++] = c;
+  }
+
+  void emit(const char* s) {
+    maybeSpace(*s);
+    int len = strlen(s);
+    ensure(len + 1);
+    strncpy(buffer + used, s, len + 1);
+    used += len;
+  }
+
+  void newline() {
+    if (!pretty) {
+      return;
+    }
+    emit('\n');
+    for (int i = 0; i < indent; i++) {
+      emit(' ');
+    }
+  }
+
+  void space() {
+    if (pretty) {
+      emit(' ');
+    }
+  }
+
+  void safeSpace() {
+    if (pretty) {
+      emit(' ');
+    } else {
+      possibleSpace = true;
+    }
+  }
+
+  void maybeSpace(char s) {
+    if (possibleSpace) {
+      possibleSpace = false;
+      if (isIdentPart(s)) {
+        emit(' ');
+      }
+    }
+  }
+
+  bool isNothing(Ref node) {
+    return node->isArray() && node[0] == TOPLEVEL && node[1]->size() == 0;
+  }
+
+  bool isDefun(Ref node) { return node->isArray() && node[0] == DEFUN; }
+
+  bool endsInBlock(Ref node) {
+    if (node->isArray() && node[0] == BLOCK) {
+      return true;
+    }
+    // Check for a label on a block
+    if (node->isArray() && node[0] == LABEL && endsInBlock(node[2])) {
+      return true;
+    }
+    // Check for an if
+    if (node->isArray() && node[0] == IF &&
+        endsInBlock(ifHasElse(node) ? node[3] : node[2])) {
+      return true;
+    }
+    return false;
+  }
+
+  bool isIf(Ref node) { return node->isArray() && node[0] == IF; }
+
+  void print(Ref node) {
+    ensure();
+    if (node->isString()) {
+      printName(node);
+      return;
+    }
+    if (node->isNumber()) {
+      printNum(node);
+      return;
+    }
+    if (node->isAssignName()) {
+      printAssignName(node);
+      return;
+    }
+    if (node->isAssign()) {
+      printAssign(node);
+      return;
+    }
+    IString type = node[0]->getIString();
+    switch (type.str[0]) {
+      case 'a': {
+        if (type == ARRAY) {
+          printArray(node);
+        } else {
+          abort();
+        }
+        break;
+      }
+      case 'b': {
+        if (type == BINARY) {
+          printBinary(node);
+        } else if (type == BLOCK) {
+          printBlock(node);
+        } else if (type == BREAK) {
+          printBreak(node);
+        } else {
+          abort();
+        }
+        break;
+      }
+      case 'c': {
+        if (type == CALL) {
+          printCall(node);
+        } else if (type == CONDITIONAL) {
+          printConditional(node);
+        } else if (type == CONTINUE) {
+          printContinue(node);
+        } else {
+          abort();
+        }
+        break;
+      }
+      case 'd': {
+        if (type == DEFUN) {
+          printDefun(node);
+        } else if (type == DO) {
+          printDo(node);
+        } else if (type == DOT) {
+          printDot(node);
+        } else {
+          abort();
+        }
+        break;
+      }
+      case 'i': {
+        if (type == IF) {
+          printIf(node);
+        } else {
+          abort();
+        }
+        break;
+      }
+      case 'l': {
+        if (type == LABEL) {
+          printLabel(node);
+        } else {
+          abort();
+        }
+        break;
+      }
+      case 'n': {
+        if (type == NEW) {
+          printNew(node);
+        } else {
+          abort();
+        }
+        break;
+      }
+      case 'o': {
+        if (type == OBJECT) {
+          printObject(node);
+        }
+        break;
+      }
+      case 'r': {
+        if (type == RETURN) {
+          printReturn(node);
+        } else {
+          abort();
+        }
+        break;
+      }
+      case 's': {
+        if (type == SUB) {
+          printSub(node);
+        } else if (type == SEQ) {
+          printSeq(node);
+        } else if (type == SWITCH) {
+          printSwitch(node);
+        } else if (type == STRING) {
+          printString(node);
+        } else {
+          abort();
+        }
+        break;
+      }
+      case 't': {
+        if (type == TOPLEVEL) {
+          printToplevel(node);
+        } else if (type == TRY) {
+          printTry(node);
+        } else {
+          abort();
+        }
+        break;
+      }
+      case 'u': {
+        if (type == UNARY_PREFIX) {
+          printUnaryPrefix(node);
+        } else {
+          abort();
+        }
+        break;
+      }
+      case 'v': {
+        if (type == VAR) {
+          printVar(node);
+        } else {
+          abort();
+        }
+        break;
+      }
+      case 'w': {
+        if (type == WHILE) {
+          printWhile(node);
+        } else {
+          abort();
+        }
+        break;
+      }
+      default: {
+        errv("cannot yet print %s\n", type.str);
+        abort();
+      }
+    }
+  }
+
+  // print a node, and if nothing is emitted, emit something instead
+  void print(Ref node, const char* otherwise) {
+    auto last = used;
+    print(node);
+    if (used == last) {
+      emit(otherwise);
+    }
+  }
+
+  void printStats(Ref stats) {
+    bool first = true;
+    for (size_t i = 0; i < stats->size(); i++) {
+      Ref curr = stats[i];
+      if (!isNothing(curr)) {
+        if (first) {
+          first = false;
+        } else {
+          newline();
+        }
+        print(curr);
+        if (!isDefun(curr) && !endsInBlock(curr) && !isIf(curr)) {
+          emit(';');
+        }
+      }
+    }
+  }
+
+  void printToplevel(Ref node) {
+    if (node[1]->size() > 0) {
+      printStats(node[1]);
+    }
+  }
+
+  void printBlock(Ref node) {
+    if (node->size() == 1 || node[1]->size() == 0) {
+      emit("{}");
+      return;
+    }
+    emit('{');
+    indent++;
+    newline();
+    printStats(node[1]);
+    indent--;
+    newline();
+    emit('}');
+  }
+
+  void printDefun(Ref node) {
+    emit("function ");
+    emit(node[1]->getCString());
+    emit('(');
+    Ref args = node[2];
+    for (size_t i = 0; i < args->size(); i++) {
+      if (i > 0) {
+        (pretty ? emit(", ") : emit(','));
+      }
+      emit(args[i]->getCString());
+    }
+    emit(')');
+    space();
+    if (node->size() == 3 || node[3]->size() == 0) {
+      emit("{}");
+      return;
+    }
+    emit('{');
+    indent++;
+    newline();
+    printStats(node[3]);
+    indent--;
+    newline();
+    emit('}');
+    newline();
+  }
+
+  void printAssign(Ref node) {
+    auto* assign = node->asAssign();
+    printChild(assign->target(), node, -1);
+    space();
+    emit('=');
+    space();
+    printChild(assign->value(), node, 1);
+  }
+
+  void printAssignName(Ref node) {
+    auto* assign = node->asAssignName();
+    emit(assign->target().c_str());
+    space();
+    emit('=');
+    space();
+    printChild(assign->value(), node, 1);
+  }
+
+  void printName(Ref node) { emit(node->getCString()); }
+
+  static char* numToString(double d, bool finalize = true) {
+    // If this number is NaN or infinite then things are a bit tricky. In JS we
+    // want to eventually use `NaN` and/or `Infinity`, but neither of those
+    // identifiers are valid in asm.js. Instead we have to explicitly import
+    // `NaN` and `Infinity` from the global environment, and those names are
+    // bound locally in an asm function as `nan` and `infinity`.
+    //
+    // TODO: the JS names of `NaN` and `Infinity` should be used once literal
+    // asm.js code isn't generated any more
+    if (std::isnan(d)) {
+      if (std::signbit(d)) {
+        return (char*)"-nan";
+      } else {
+        return (char*)"nan";
+      }
+    } else if (!std::isfinite(d)) {
+      if (std::signbit(d)) {
+        return (char*)"-infinity";
+      } else {
+        return (char*)"infinity";
+      }
+    }
+    bool neg = d < 0;
+    if (neg) {
+      d = -d;
+    }
+    // try to emit the fewest necessary characters
+    bool integer = wasm::isInteger(d);
+#define BUFFERSIZE 1000
+    // f is normal, e is scientific for float, x for integer
+    static char full_storage_f[BUFFERSIZE], full_storage_e[BUFFERSIZE];
+    // full has one more char, for a possible '-'
+    static char *storage_f = full_storage_f + 1,
+                *storage_e = full_storage_e + 1;
+    auto err_f = std::numeric_limits<double>::quiet_NaN();
+    auto err_e = std::numeric_limits<double>::quiet_NaN();
+    for (int e = 0; e <= 1; e++) {
+      char* buffer = e ? storage_e : storage_f;
+      double temp;
+      if (!integer) {
+        static char format[6];
+        for (int i = 0; i <= 18; i++) {
+          format[0] = '%';
+          format[1] = '.';
+          if (i < 10) {
+            format[2] = '0' + i;
+            format[3] = e ? 'e' : 'f';
+            format[4] = 0;
+          } else {
+            format[2] = '1';
+            format[3] = '0' + (i - 10);
+            format[4] = e ? 'e' : 'f';
+            format[5] = 0;
+          }
+          snprintf(buffer, BUFFERSIZE - 1, format, d);
+          sscanf(buffer, "%lf", &temp);
+          // errv("%.18f, %.18e   =>   %s   =>   %.18f, %.18e   (%d), ", d, d,
+          // buffer, temp, temp, temp == d);
+          if (temp == d) {
+            break;
+          }
+        }
+      } else {
+        // integer
+        assert(d >= 0);
+        if (wasm::isUInteger64(d)) {
+          unsigned long long uu = wasm::toUInteger64(d);
+          bool asHex = e && !finalize;
+          snprintf(buffer, BUFFERSIZE - 1, asHex ? "0x%llx" : "%llu", uu);
+          if (asHex) {
+            unsigned long long tempULL;
+            sscanf(buffer, "%llx", &tempULL);
+            temp = (double)tempULL;
+          } else {
+            sscanf(buffer, "%lf", &temp);
+          }
+        } else {
+          // too large for a machine integer, just use floats
+          // even on integers, e with a dot is useful, e.g. 1.2e+200
+          snprintf(buffer, BUFFERSIZE - 1, e ? "%e" : "%.0f", d);
+          sscanf(buffer, "%lf", &temp);
+        }
+        // errv("%.18f, %.18e   =>   %s   =>   %.18f, %.18e, %llu   (%d)\n", d,
+        //      d, buffer, temp, temp, uu, temp == d);
+      }
+      (e ? err_e : err_f) = fabs(temp - d);
+      // errv("current attempt: %.18f  =>  %s", d, buffer);
+      // assert(temp == d);
+      char* dot = strchr(buffer, '.');
+      if (dot) {
+        // remove trailing zeros
+        char* end = dot + 1;
+        while (*end >= '0' && *end <= '9') {
+          end++;
+        }
+        end--;
+        while (*end == '0') {
+          char* copy = end;
+          do {
+            copy[0] = copy[1];
+          } while (*copy++ != 0);
+          end--;
+        }
+        // errv("%.18f  =>   %s", d, buffer);
+        // remove preceding zeros
+        while (*buffer == '0') {
+          char* copy = buffer;
+          do {
+            copy[0] = copy[1];
+          } while (*copy++ != 0);
+        }
+        // errv("%.18f ===>  %s", d, buffer);
+      } else if (!integer || !e) {
+        // no dot. try to change 12345000 => 12345e3
+        char* end = strchr(buffer, 0);
+        end--;
+        char* test = end;
+        // remove zeros, and also doubles can use at most 24 digits, we can
+        // truncate any extras even if not zero
+        while ((*test == '0' || test - buffer > 24) && test > buffer) {
+          test--;
+        }
+        int num = end - test;
+        if (num >= 3) {
+          test++;
+          test[0] = 'e';
+          if (num < 10) {
+            test[1] = '0' + num;
+            test[2] = 0;
+          } else if (num < 100) {
+            test[1] = '0' + (num / 10);
+            test[2] = '0' + (num % 10);
+            test[3] = 0;
+          } else {
+            assert(num < 1000);
+            test[1] = '0' + (num / 100);
+            test[2] = '0' + (num % 100) / 10;
+            test[3] = '0' + (num % 10);
+            test[4] = 0;
+          }
+        }
+      }
+      // errv("..current attempt: %.18f  =>  %s", d, buffer);
+    }
+    // fprintf(stderr, "options:\n%s\n%s\n (first? %d)\n", storage_e, storage_f,
+    //         strlen(storage_e) < strlen(storage_f));
+    char* ret;
+    if (err_e == err_f) {
+      ret = strlen(storage_e) < strlen(storage_f) ? storage_e : storage_f;
+    } else {
+      ret = err_e < err_f ? storage_e : storage_f;
+    }
+    if (neg) {
+      ret--; // safe to go back one, there is one more char in full_*
+      *ret = '-';
+    }
+    return ret;
+  }
+
+  void printNum(Ref node) {
+    if (node->getNumber() < 0 && buffer[used - 1] == '-') {
+      emit(' '); // cannot join - and - to --, looks like the -- operator
+    }
+    emit(numToString(node->getNumber(), finalize));
+  }
+
+  void printString(Ref node) {
+    emit('"');
+    emit(node[1]->getCString());
+    emit('"');
+  }
+
+  // Parens optimizing
+
+  bool capturesOperators(Ref node) {
+    Ref type = node[0];
+    return type == CALL || type == ARRAY || type == OBJECT || type == SEQ;
+  }
+
+  int getPrecedence(Ref node, bool parent) {
+    if (node->isAssign() || node->isAssignName()) {
+      return OperatorClass::getPrecedence(OperatorClass::Binary, SET);
+    }
+    if (!node->isArray()) {
+      // node is a value
+      return -1;
+    }
+    Ref type = node[0];
+    if (type == BINARY || type == UNARY_PREFIX) {
+      return OperatorClass::getPrecedence(
+        type == BINARY ? OperatorClass::Binary : OperatorClass::Prefix,
+        node[1]->getIString());
+    } else if (type == SEQ) {
+      return OperatorClass::getPrecedence(OperatorClass::Binary, COMMA);
+    } else if (type == CALL) {
+      // call arguments are split by commas, but call itself is safe
+      return parent ? OperatorClass::getPrecedence(OperatorClass::Binary, COMMA)
+                    : -1;
+    } else if (type == CONDITIONAL) {
+      return OperatorClass::getPrecedence(OperatorClass::Tertiary, QUESTION);
+    }
+    // otherwise, this is something that fixes precedence explicitly, and we can
+    // ignore
+    return -1; // XXX
+  }
+
+  // check whether we need parens for the child, when rendered in the parent
+  // @param childPosition -1 means it is printed to the left of parent, 0 means
+  //        "anywhere", 1 means right
+  bool needParens(Ref parent, Ref child, int childPosition) {
+    int parentPrecedence = getPrecedence(parent, true);
+    int childPrecedence = getPrecedence(child, false);
+
+    if (childPrecedence > parentPrecedence) {
+      return true; // child is definitely a danger
+    }
+    if (childPrecedence < parentPrecedence) {
+      return false; //          definitely cool
+    }
+    // equal precedence, so associativity (rtl/ltr) is what matters
+    // (except for some exceptions, where multiple operators can combine into
+    // confusion)
+    if (parent->isArray() && parent[0] == UNARY_PREFIX) {
+      assert(child[0] == UNARY_PREFIX);
+      if ((parent[1] == PLUS || parent[1] == MINUS) && child[1] == parent[1]) {
+        // cannot emit ++x when we mean +(+x)
+        return true;
+      }
+    }
+    if (childPosition == 0) {
+      return true; // child could be anywhere, so always paren
+    }
+    if (childPrecedence < 0) {
+      return false; // both precedences are safe
+    }
+    // check if child is on the dangerous side
+    if (OperatorClass::getRtl(parentPrecedence)) {
+      return childPosition < 0;
+    } else {
+      return childPosition > 0;
+    }
+  }
+
+  void printChild(Ref child, Ref parent, int childPosition = 0) {
+    bool parens = needParens(parent, child, childPosition);
+    if (parens) {
+      emit('(');
+    }
+    print(child);
+    if (parens) {
+      emit(')');
+    }
+  }
+
+  void printBinary(Ref node) {
+    printChild(node[2], node, -1);
+    space();
+    emit(node[1]->getCString());
+    space();
+    printChild(node[3], node, 1);
+  }
+
+  void printUnaryPrefix(Ref node) {
+    if (finalize && node[1] == PLUS &&
+        (node[2]->isNumber() ||
+         (node[2]->isArray() && node[2][0] == UNARY_PREFIX &&
+          node[2][1] == MINUS && node[2][2]->isNumber()))) {
+      // emit a finalized number
+      int last = used;
+      print(node[2]);
+      ensure(1);                  // we temporarily append a 0
+      char* curr = buffer + last; // ensure might invalidate
+      buffer[used] = 0;
+      if (strstr(curr, "infinity")) {
+        return;
+      }
+      if (strstr(curr, "nan")) {
+        return;
+      }
+      if (strchr(curr, '.')) {
+        return; // already a decimal point, all good
+      }
+      char* e = strchr(curr, 'e');
+      if (!e) {
+        emit(".0");
+        return;
+      }
+      ensure(3);
+      curr = buffer + last; // ensure might invalidate
+      char* end = strchr(curr, 0);
+      while (end >= e) {
+        end[2] = end[0];
+        end--;
+      }
+      e[0] = '.';
+      e[1] = '0';
+      used += 2;
+      return;
+    }
+    if ((buffer[used - 1] == '-' && node[1] == MINUS) ||
+        (buffer[used - 1] == '+' && node[1] == PLUS)) {
+      emit(' '); // cannot join - and - to --, looks like the -- operator
+    }
+    emit(node[1]->getCString());
+    printChild(node[2], node, 1);
+  }
+
+  void printConditional(Ref node) {
+    printChild(node[1], node, -1);
+    space();
+    emit('?');
+    space();
+    printChild(node[2], node, 0);
+    space();
+    emit(':');
+    space();
+    printChild(node[3], node, 1);
+  }
+
+  void printCall(Ref node) {
+    printChild(node[1], node, 0);
+    emit('(');
+    Ref args = node[2];
+    for (size_t i = 0; i < args->size(); i++) {
+      if (i > 0) {
+        (pretty ? emit(", ") : emit(','));
+      }
+      printChild(args[i], node, 0);
+    }
+    emit(')');
+  }
+
+  void printSeq(Ref node) {
+    printChild(node[1], node, -1);
+    emit(',');
+    space();
+    printChild(node[2], node, 1);
+  }
+
+  void printDot(Ref node) {
+    print(node[1]);
+    emit('.');
+    emit(node[2]->getCString());
+  }
+
+  void printSwitch(Ref node) {
+    emit("switch");
+    space();
+    emit('(');
+    print(node[1]);
+    emit(')');
+    space();
+    emit('{');
+    newline();
+    Ref cases = node[2];
+    for (size_t i = 0; i < cases->size(); i++) {
+      Ref c = cases[i];
+      if (!c[0]) {
+        emit("default:");
+      } else {
+        emit("case ");
+        print(c[0]);
+        emit(':');
+      }
+      if (c[1]->size() > 0) {
+        indent++;
+        newline();
+        auto curr = used;
+        printStats(c[1]);
+        indent--;
+        if (curr != used) {
+          newline();
+        } else {
+          used--; // avoid the extra indentation we added tentatively
+        }
+      } else {
+        newline();
+      }
+    }
+    emit('}');
+  }
+
+  void printTry(Ref node) {
+    emit("try ");
+    printBlock(node[1]);
+    emit(" catch (");
+    printName(node[2]);
+    emit(") ");
+    printBlock(node[3]);
+  }
+
+  void printSub(Ref node) {
+    printChild(node[1], node, -1);
+    emit('[');
+    print(node[2]);
+    emit(']');
+  }
+
+  void printVar(Ref node) {
+    emit("var ");
+    Ref args = node[1];
+    for (size_t i = 0; i < args->size(); i++) {
+      if (i > 0) {
+        (pretty ? emit(", ") : emit(','));
+      }
+      emit(args[i][0]->getCString());
+      if (args[i]->size() > 1) {
+        space();
+        emit('=');
+        space();
+        print(args[i][1]);
+      }
+    }
+  }
+
+  static bool isBlock(Ref node) {
+    return node->isArray() && !node->empty() && node[0] == BLOCK;
+  }
+
+  static bool ifHasElse(Ref node) {
+    assert(node->isArray() && node[0] == IF);
+    return node->size() >= 4 && !!node[3];
+  }
+
+  void printIf(Ref node) {
+    emit("if");
+    safeSpace();
+    emit('(');
+    print(node[1]);
+    emit(')');
+    space();
+    bool emitsBracesAnyhow = isBlock(node[2]);
+    if (!emitsBracesAnyhow) {
+      emit('{');
+      indent++;
+      newline();
+    }
+    print(node[2]);
+    if (!emitsBracesAnyhow) {
+      indent--;
+      newline();
+      emit('}');
+    }
+    if (ifHasElse(node)) {
+      space();
+      emit("else");
+      safeSpace();
+      bool emitsBracesAnyhow = isBlock(node[3]);
+      if (!emitsBracesAnyhow) {
+        emit('{');
+        indent++;
+        newline();
+      }
+      print(node[3]);
+      if (!emitsBracesAnyhow) {
+        indent--;
+        newline();
+        emit('}');
+      }
+    }
+  }
+
+  void printDo(Ref node) {
+    emit("do");
+    safeSpace();
+    print(node[2], "{}");
+    space();
+    emit("while");
+    space();
+    emit('(');
+    print(node[1]);
+    emit(')');
+  }
+
+  void printWhile(Ref node) {
+    emit("while");
+    space();
+    emit('(');
+    print(node[1]);
+    emit(')');
+    space();
+    print(node[2], "{}");
+  }
+
+  void printLabel(Ref node) {
+    emit(node[1]->getCString());
+    space();
+    emit(':');
+    space();
+    print(node[2]);
+  }
+
+  void printReturn(Ref node) {
+    emit("return");
+    if (!!node[1]) {
+      emit(' ');
+      print(node[1]);
+    }
+  }
+
+  void printBreak(Ref node) {
+    emit("break");
+    if (!!node[1]) {
+      emit(' ');
+      emit(node[1]->getCString());
+    }
+  }
+
+  void printContinue(Ref node) {
+    emit("continue");
+    if (!!node[1]) {
+      emit(' ');
+      emit(node[1]->getCString());
+    }
+  }
+
+  void printNew(Ref node) {
+    emit("new ");
+    print(node[1]);
+  }
+
+  void printArray(Ref node) {
+    emit('[');
+    Ref args = node[1];
+    for (size_t i = 0; i < args->size(); i++) {
+      if (i > 0) {
+        (pretty ? emit(", ") : emit(','));
+      }
+      print(args[i]);
+    }
+    emit(']');
+  }
+
+  void printObject(Ref node) {
+    emit('{');
+    indent++;
+    newline();
+    Ref args = node[1];
+    for (size_t i = 0; i < args->size(); i++) {
+      if (i > 0) {
+        pretty ? emit(", ") : emit(',');
+        newline();
+      }
+      bool needQuote = false;
+      const char* str;
+      if (args[i][0]->isArray()) {
+        assert(args[i][0][0] == STRING);
+        // A quoted string.
+        needQuote = true;
+        str = args[i][0][1]->getCString();
+      } else {
+        // Just a raw string, no quotes.
+        str = args[i][0]->getCString();
+      }
+      const char* check = str;
+      while (*check) {
+        if (!isalnum(*check) && *check != '_' && *check != '$') {
+          needQuote = true;
+          break;
+        }
+        check++;
+      }
+      if (needQuote) {
+        emit('"');
+      }
+      emit(str);
+      if (needQuote) {
+        emit('"');
+      }
+      emit(":");
+      space();
+      print(args[i][1]);
+    }
+    indent--;
+    newline();
+    emit('}');
+  }
+};
+
+// cashew builder
+
+class ValueBuilder {
+  static Ref makeRawString(const IString& s) {
+    return &arena.alloc<Value>()->setString(s);
+  }
+
+  static Ref makeNull() { return &arena.alloc<Value>()->setNull(); }
+
+public:
+  static Ref makeRawArray(int size_hint = 0) {
+    return &arena.alloc<Value>()->setArray(size_hint);
+  }
+
+  static Ref makeToplevel() {
+    return &makeRawArray(2)
+              ->push_back(makeRawString(TOPLEVEL))
+              .push_back(makeRawArray());
+  }
+
+  static Ref makeString(IString str) {
+    return &makeRawArray(2)
+              ->push_back(makeRawString(STRING))
+              .push_back(makeRawString(str));
+  }
+
+  static Ref makeBlock() {
+    return &makeRawArray(2)
+              ->push_back(makeRawString(BLOCK))
+              .push_back(makeRawArray());
+  }
+
+  static Ref makeName(IString name) { return makeRawString(name); }
+
+  static void setBlockContent(Ref target, Ref block) {
+    if (target[0] == TOPLEVEL) {
+      target[1]->setArray(block[1]->getArray());
+    } else if (target[0] == DEFUN) {
+      target[3]->setArray(block[1]->getArray());
+    } else {
+      abort();
+    }
+  }
+
+  static void appendToBlock(Ref block, Ref element) {
+    assert(block[0] == BLOCK);
+    block[1]->push_back(element);
+  }
+
+  static Ref makeCall(Ref target) {
+    return &makeRawArray(3)
+              ->push_back(makeRawString(CALL))
+              .push_back(target)
+              .push_back(makeRawArray());
+  }
+  static Ref makeCall(Ref target, Ref arg) {
+    Ref ret = &makeRawArray(3)
+                 ->push_back(makeRawString(CALL))
+                 .push_back(target)
+                 .push_back(makeRawArray());
+    ret[2]->push_back(arg);
+    return ret;
+  }
+  static Ref makeCall(IString target) {
+    Ref ret = &makeRawArray(3)
+                 ->push_back(makeRawString(CALL))
+                 .push_back(makeName(target))
+                 .push_back(makeRawArray());
+    return ret;
+  }
+
+  template<typename... Ts> static Ref makeCall(IString target, Ts... args) {
+    size_t nArgs = sizeof...(Ts);
+    Ref callArgs = makeRawArray(nArgs);
+    Ref argArray[] = {args...};
+    for (size_t i = 0; i < nArgs; ++i) {
+      callArgs->push_back(argArray[i]);
+    }
+    return &makeRawArray(3)
+              ->push_back(makeRawString(CALL))
+              .push_back(makeName(target))
+              .push_back(callArgs);
+  }
+
+  static void appendToCall(Ref call, Ref element) {
+    assert(call[0] == CALL);
+    call[2]->push_back(element);
+  }
+
+  static Ref makeStatement(Ref contents) { return contents; }
+
+  static Ref makeDouble(double num) {
+    return &arena.alloc<Value>()->setNumber(num);
+  }
+  static Ref makeInt(uint32_t num) { return makeDouble(double(num)); }
+  static Ref makeInt(int32_t num) { return makeDouble(double(num)); }
+  static Ref makeNum(double num) { return makeDouble(num); }
+
+  static Ref makeUnary(IString op, Ref value) {
+    return &makeRawArray(3)
+              ->push_back(makeRawString(UNARY_PREFIX))
+              .push_back(makeRawString(op))
+              .push_back(value);
+  }
+
+  static Ref makeBinary(Ref left, IString op, Ref right) {
+    if (op == SET) {
+      if (left->isString()) {
+        return &arena.alloc<AssignName>()->setAssignName(left->getIString(),
+                                                         right);
+      } else {
+        return &arena.alloc<Assign>()->setAssign(left, right);
+      }
+    } else if (op == COMMA) {
+      return &makeRawArray(3)
+                ->push_back(makeRawString(SEQ))
+                .push_back(left)
+                .push_back(right);
+    } else {
+      return &makeRawArray(4)
+                ->push_back(makeRawString(BINARY))
+                .push_back(makeRawString(op))
+                .push_back(left)
+                .push_back(right);
+    }
+  }
+
+  static Ref makePrefix(IString op, Ref right) {
+    return &makeRawArray(3)
+              ->push_back(makeRawString(UNARY_PREFIX))
+              .push_back(makeRawString(op))
+              .push_back(right);
+  }
+
+  static Ref makeFunction(IString name) {
+    return &makeRawArray(4)
+              ->push_back(makeRawString(DEFUN))
+              .push_back(makeRawString(name))
+              .push_back(makeRawArray())
+              .push_back(makeRawArray());
+  }
+
+  static void appendArgumentToFunction(Ref func, IString arg) {
+    assert(func[0] == DEFUN);
+    func[2]->push_back(makeRawString(arg));
+  }
+
+  static Ref makeVar(bool is_const = false) {
+    return &makeRawArray(2)
+              ->push_back(makeRawString(VAR))
+              .push_back(makeRawArray());
+  }
+
+  static void appendToVar(Ref var, IString name, Ref value) {
+    assert(var[0] == VAR);
+    Ref array = &makeRawArray(1)->push_back(makeRawString(name));
+    if (!!value) {
+      array->push_back(value);
+    }
+    var[1]->push_back(array);
+  }
+
+  static Ref makeReturn(Ref value) {
+    return &makeRawArray(2)
+              ->push_back(makeRawString(RETURN))
+              .push_back(!!value ? value : makeNull());
+  }
+
+  static Ref makeIndexing(Ref target, Ref index) {
+    return &makeRawArray(3)
+              ->push_back(makeRawString(SUB))
+              .push_back(target)
+              .push_back(index);
+  }
+
+  static Ref makeIf(Ref condition, Ref ifTrue, Ref ifFalse) {
+    return &makeRawArray(4)
+              ->push_back(makeRawString(IF))
+              .push_back(condition)
+              .push_back(ifTrue)
+              .push_back(!!ifFalse ? ifFalse : makeNull());
+  }
+
+  static Ref makeConditional(Ref condition, Ref ifTrue, Ref ifFalse) {
+    return &makeRawArray(4)
+              ->push_back(makeRawString(CONDITIONAL))
+              .push_back(condition)
+              .push_back(ifTrue)
+              .push_back(ifFalse);
+  }
+
+  static Ref makeSeq(Ref left, Ref right) {
+    return &makeRawArray(3)
+              ->push_back(makeRawString(SEQ))
+              .push_back(left)
+              .push_back(right);
+  }
+
+  static Ref makeDo(Ref body, Ref condition) {
+    return &makeRawArray(3)
+              ->push_back(makeRawString(DO))
+              .push_back(condition)
+              .push_back(body);
+  }
+
+  static Ref makeWhile(Ref condition, Ref body) {
+    return &makeRawArray(3)
+              ->push_back(makeRawString(WHILE))
+              .push_back(condition)
+              .push_back(body);
+  }
+
+  static Ref makeFor(Ref init, Ref condition, Ref inc, Ref body) {
+    return &makeRawArray(5)
+              ->push_back(makeRawString(FOR))
+              .push_back(init)
+              .push_back(condition)
+              .push_back(inc)
+              .push_back(body);
+  }
+
+  static Ref makeBreak(IString label) {
+    return &makeRawArray(2)
+              ->push_back(makeRawString(BREAK))
+              .push_back(!!label ? makeRawString(label) : makeNull());
+  }
+
+  static Ref makeContinue(IString label) {
+    return &makeRawArray(2)
+              ->push_back(makeRawString(CONTINUE))
+              .push_back(!!label ? makeRawString(label) : makeNull());
+  }
+
+  static Ref makeLabel(IString name, Ref body) {
+    return &makeRawArray(3)
+              ->push_back(makeRawString(LABEL))
+              .push_back(makeRawString(name))
+              .push_back(body);
+  }
+
+  static Ref makeSwitch(Ref input) {
+    return &makeRawArray(3)
+              ->push_back(makeRawString(SWITCH))
+              .push_back(input)
+              .push_back(makeRawArray());
+  }
+
+  static void appendCaseToSwitch(Ref switch_, Ref arg) {
+    assert(switch_[0] == SWITCH);
+    switch_[2]->push_back(
+      &makeRawArray(2)->push_back(arg).push_back(makeRawArray()));
+  }
+
+  static void appendDefaultToSwitch(Ref switch_) {
+    assert(switch_[0] == SWITCH);
+    switch_[2]->push_back(
+      &makeRawArray(2)->push_back(makeNull()).push_back(makeRawArray()));
+  }
+
+  static void appendCodeToSwitch(Ref switch_, Ref code, bool explicitBlock) {
+    assert(switch_[0] == SWITCH);
+    assert(code[0] == BLOCK);
+    if (!explicitBlock) {
+      for (size_t i = 0; i < code[1]->size(); i++) {
+        switch_[2]->back()->back()->push_back(code[1][i]);
+      }
+    } else {
+      switch_[2]->back()->back()->push_back(code);
+    }
+  }
+
+  static Ref makeTry(Ref try_, Ref arg, Ref catch_) {
+    assert(try_[0] == BLOCK);
+    assert(catch_[0] == BLOCK);
+    return &makeRawArray(3)
+              ->push_back(makeRawString(TRY))
+              .push_back(try_)
+              .push_back(arg)
+              .push_back(catch_);
+  }
+
+  static Ref makeDot(Ref obj, IString key) {
+    return &makeRawArray(3)
+              ->push_back(makeRawString(DOT))
+              .push_back(obj)
+              .push_back(makeRawString(key));
+  }
+
+  template<typename... Ts> static Ref makeDot(Ref obj, Ref key, Ts... args) {
+    return makeDot(makeDot(obj, key), args...);
+  }
+
+  static Ref makeDot(Ref obj, Ref key) {
+    assert(key->isString());
+    return makeDot(obj, key->getIString());
+  }
+
+  static Ref makeNew(Ref call) {
+    return &makeRawArray(2)->push_back(makeRawString(NEW)).push_back(call);
+  }
+
+  static Ref makeArray() {
+    return &makeRawArray(2)
+              ->push_back(makeRawString(ARRAY))
+              .push_back(makeRawArray());
+  }
+
+  static void appendToArray(Ref array, Ref element) {
+    assert(array[0] == ARRAY);
+    array[1]->push_back(element);
+  }
+
+  static Ref makeObject() {
+    return &makeRawArray(2)
+              ->push_back(makeRawString(OBJECT))
+              .push_back(makeRawArray());
+  }
+
+  static void appendToObject(Ref array, IString key, Ref value) {
+    assert(array[0] == OBJECT);
+    array[1]->push_back(
+      &makeRawArray(2)->push_back(makeRawString(key)).push_back(value));
+  }
+
+  static void appendToObjectWithQuotes(Ref array, IString key, Ref value) {
+    assert(array[0] == OBJECT);
+    array[1]->push_back(
+      &makeRawArray(2)->push_back(makeString(key)).push_back(value));
+  }
+
+  static Ref makeSub(Ref obj, Ref index) {
+    return &makeRawArray(2)
+              ->push_back(makeRawString(SUB))
+              .push_back(obj)
+              .push_back(index);
+  }
+
+  static Ref makePtrShift(Ref ptr, int shifts) {
+    return makeBinary(ptr, RSHIFT, makeInt(shifts));
+  }
+};
+
+// Tolerates 0.0 in the input; does not trust a +() to be there.
+class DotZeroValueBuilder : public ValueBuilder {
+public:
+  static Ref makeDouble(double num) {
+    return makePrefix(PLUS, ValueBuilder::makeDouble(num));
+  }
+};
+
+} // namespace cashew
+
+#endif // wasm_simple_ast_h
diff --git a/binaryen/src/emscripten-optimizer/snprintf.h b/binaryen/src/emscripten-optimizer/snprintf.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/emscripten-optimizer/snprintf.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 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_snprintf_h
+#define wasm_snprintf_h
+
+#include <stdarg.h>
+
+// Visual Studio does not support C99, so emulate snprintf support for it
+// manually.
+
+#ifdef _MSC_VER
+
+#define snprintf c99_snprintf
+
+inline int
+c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) {
+  int count = -1;
+
+  if (size != 0)
+    count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
+  if (count == -1)
+    count = _vscprintf(format, ap);
+
+  return count;
+}
+
+inline int c99_snprintf(char* str, size_t size, const char* format, ...) {
+  int count;
+  va_list ap;
+
+  va_start(ap, format);
+  count = c99_vsnprintf(str, size, format, ap);
+  va_end(ap);
+
+  return count;
+}
+#endif
+
+#endif // wasm_snprintf_h
diff --git a/binaryen/src/gen-s-parser.inc b/binaryen/src/gen-s-parser.inc
new file mode 100644
--- /dev/null
+++ b/binaryen/src/gen-s-parser.inc
@@ -0,0 +1,2843 @@
+// DO NOT EDIT! This file generated by scripts/gen-s-parser.py
+
+// clang-format off
+
+#ifdef INSTRUCTION_PARSER
+#undef INSTRUCTION_PARSER
+char op[28] = {'\0'};
+strncpy(op, s[0]->c_str(), 27);
+switch (op[0]) {
+  case 'a': {
+    switch (op[1]) {
+      case 'r': {
+        switch (op[6]) {
+          case 'g': {
+            switch (op[9]) {
+              case '\0':
+                if (strcmp(op, "array.get") == 0) { return makeArrayGet(s); }
+                goto parse_error;
+              case '_': {
+                switch (op[10]) {
+                  case 's':
+                    if (strcmp(op, "array.get_s") == 0) { return makeArrayGet(s, true); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "array.get_u") == 0) { return makeArrayGet(s, false); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          case 'l':
+            if (strcmp(op, "array.len") == 0) { return makeArrayLen(s); }
+            goto parse_error;
+          case 'n': {
+            switch (op[10]) {
+              case 'd':
+                if (strcmp(op, "array.new_default_with_rtt") == 0) { return makeArrayNew(s, true); }
+                goto parse_error;
+              case 'w':
+                if (strcmp(op, "array.new_with_rtt") == 0) { return makeArrayNew(s, false); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          case 's':
+            if (strcmp(op, "array.set") == 0) { return makeArraySet(s); }
+            goto parse_error;
+          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;
+        }
+      }
+      default: goto parse_error;
+    }
+  }
+  case 'b': {
+    switch (op[1]) {
+      case 'l':
+        if (strcmp(op, "block") == 0) { return makeBlock(s); }
+        goto parse_error;
+      case 'r': {
+        switch (op[2]) {
+          case '\0':
+            if (strcmp(op, "br") == 0) { return makeBreak(s); }
+            goto parse_error;
+          case '_': {
+            switch (op[3]) {
+              case 'i':
+                if (strcmp(op, "br_if") == 0) { return makeBreak(s); }
+                goto parse_error;
+              case 'o': {
+                switch (op[6]) {
+                  case 'c':
+                    if (strcmp(op, "br_on_cast") == 0) { return makeBrOnCast(s); }
+                    goto parse_error;
+                  case 'e':
+                    if (strcmp(op, "br_on_exn") == 0) { return makeBrOnExn(s); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 't':
+                if (strcmp(op, "br_table") == 0) { return makeBreakTable(s); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          default: goto parse_error;
+        }
+      }
+      default: goto parse_error;
+    }
+  }
+  case 'c': {
+    switch (op[4]) {
+      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;
+      default: goto parse_error;
+    }
+  }
+  case 'd': {
+    switch (op[1]) {
+      case 'a':
+        if (strcmp(op, "data.drop") == 0) { return makeDataDrop(s); }
+        goto parse_error;
+      case 'r':
+        if (strcmp(op, "drop") == 0) { return makeDrop(s); }
+        goto parse_error;
+      default: goto parse_error;
+    }
+  }
+  case 'e':
+    if (strcmp(op, "else") == 0) { return makeThenOrElse(s); }
+    goto parse_error;
+  case 'f': {
+    switch (op[1]) {
+      case '3': {
+        switch (op[3]) {
+          case '.': {
+            switch (op[4]) {
+              case 'a': {
+                switch (op[5]) {
+                  case 'b':
+                    if (strcmp(op, "f32.abs") == 0) { return makeUnary(s, UnaryOp::AbsFloat32); }
+                    goto parse_error;
+                  case 'd':
+                    if (strcmp(op, "f32.add") == 0) { return makeBinary(s, BinaryOp::AddFloat32); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'c': {
+                switch (op[5]) {
+                  case 'e':
+                    if (strcmp(op, "f32.ceil") == 0) { return makeUnary(s, UnaryOp::CeilFloat32); }
+                    goto parse_error;
+                  case 'o': {
+                    switch (op[6]) {
+                      case 'n': {
+                        switch (op[7]) {
+                          case 's':
+                            if (strcmp(op, "f32.const") == 0) { return makeConst(s, Type::f32); }
+                            goto parse_error;
+                          case 'v': {
+                            switch (op[13]) {
+                              case '3': {
+                                switch (op[16]) {
+                                  case 's':
+                                    if (strcmp(op, "f32.convert_i32_s") == 0) { return makeUnary(s, UnaryOp::ConvertSInt32ToFloat32); }
+                                    goto parse_error;
+                                  case 'u':
+                                    if (strcmp(op, "f32.convert_i32_u") == 0) { return makeUnary(s, UnaryOp::ConvertUInt32ToFloat32); }
+                                    goto parse_error;
+                                  default: goto parse_error;
+                                }
+                              }
+                              case '6': {
+                                switch (op[16]) {
+                                  case 's':
+                                    if (strcmp(op, "f32.convert_i64_s") == 0) { return makeUnary(s, UnaryOp::ConvertSInt64ToFloat32); }
+                                    goto parse_error;
+                                  case 'u':
+                                    if (strcmp(op, "f32.convert_i64_u") == 0) { return makeUnary(s, UnaryOp::ConvertUInt64ToFloat32); }
+                                    goto parse_error;
+                                  default: goto parse_error;
+                                }
+                              }
+                              default: goto parse_error;
+                            }
+                          }
+                          default: goto parse_error;
+                        }
+                      }
+                      case 'p':
+                        if (strcmp(op, "f32.copysign") == 0) { return makeBinary(s, BinaryOp::CopySignFloat32); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              case 'd': {
+                switch (op[5]) {
+                  case 'e':
+                    if (strcmp(op, "f32.demote_f64") == 0) { return makeUnary(s, UnaryOp::DemoteFloat64); }
+                    goto parse_error;
+                  case 'i':
+                    if (strcmp(op, "f32.div") == 0) { return makeBinary(s, BinaryOp::DivFloat32); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'e':
+                if (strcmp(op, "f32.eq") == 0) { return makeBinary(s, BinaryOp::EqFloat32); }
+                goto parse_error;
+              case 'f':
+                if (strcmp(op, "f32.floor") == 0) { return makeUnary(s, UnaryOp::FloorFloat32); }
+                goto parse_error;
+              case 'g': {
+                switch (op[5]) {
+                  case 'e':
+                    if (strcmp(op, "f32.ge") == 0) { return makeBinary(s, BinaryOp::GeFloat32); }
+                    goto parse_error;
+                  case 't':
+                    if (strcmp(op, "f32.gt") == 0) { return makeBinary(s, BinaryOp::GtFloat32); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'l': {
+                switch (op[5]) {
+                  case 'e':
+                    if (strcmp(op, "f32.le") == 0) { return makeBinary(s, BinaryOp::LeFloat32); }
+                    goto parse_error;
+                  case 'o':
+                    if (strcmp(op, "f32.load") == 0) { return makeLoad(s, Type::f32, /*isAtomic=*/false); }
+                    goto parse_error;
+                  case 't':
+                    if (strcmp(op, "f32.lt") == 0) { return makeBinary(s, BinaryOp::LtFloat32); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'm': {
+                switch (op[5]) {
+                  case 'a':
+                    if (strcmp(op, "f32.max") == 0) { return makeBinary(s, BinaryOp::MaxFloat32); }
+                    goto parse_error;
+                  case 'i':
+                    if (strcmp(op, "f32.min") == 0) { return makeBinary(s, BinaryOp::MinFloat32); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "f32.mul") == 0) { return makeBinary(s, BinaryOp::MulFloat32); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'n': {
+                switch (op[6]) {
+                  case '\0':
+                    if (strcmp(op, "f32.ne") == 0) { return makeBinary(s, BinaryOp::NeFloat32); }
+                    goto parse_error;
+                  case 'a':
+                    if (strcmp(op, "f32.nearest") == 0) { return makeUnary(s, UnaryOp::NearestFloat32); }
+                    goto parse_error;
+                  case 'g':
+                    if (strcmp(op, "f32.neg") == 0) { return makeUnary(s, UnaryOp::NegFloat32); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'r':
+                if (strcmp(op, "f32.reinterpret_i32") == 0) { return makeUnary(s, UnaryOp::ReinterpretInt32); }
+                goto parse_error;
+              case 's': {
+                switch (op[5]) {
+                  case 'q':
+                    if (strcmp(op, "f32.sqrt") == 0) { return makeUnary(s, UnaryOp::SqrtFloat32); }
+                    goto parse_error;
+                  case 't':
+                    if (strcmp(op, "f32.store") == 0) { return makeStore(s, Type::f32, /*isAtomic=*/false); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "f32.sub") == 0) { return makeBinary(s, BinaryOp::SubFloat32); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 't':
+                if (strcmp(op, "f32.trunc") == 0) { return makeUnary(s, UnaryOp::TruncFloat32); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          case 'x': {
+            switch (op[6]) {
+              case 'a': {
+                switch (op[7]) {
+                  case 'b':
+                    if (strcmp(op, "f32x4.abs") == 0) { return makeUnary(s, UnaryOp::AbsVecF32x4); }
+                    goto parse_error;
+                  case 'd':
+                    if (strcmp(op, "f32x4.add") == 0) { return makeBinary(s, BinaryOp::AddVecF32x4); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'c': {
+                switch (op[7]) {
+                  case 'e':
+                    if (strcmp(op, "f32x4.ceil") == 0) { return makeUnary(s, UnaryOp::CeilVecF32x4); }
+                    goto parse_error;
+                  case 'o': {
+                    switch (op[20]) {
+                      case 's':
+                        if (strcmp(op, "f32x4.convert_i32x4_s") == 0) { return makeUnary(s, UnaryOp::ConvertSVecI32x4ToVecF32x4); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "f32x4.convert_i32x4_u") == 0) { return makeUnary(s, UnaryOp::ConvertUVecI32x4ToVecF32x4); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              case 'd':
+                if (strcmp(op, "f32x4.div") == 0) { return makeBinary(s, BinaryOp::DivVecF32x4); }
+                goto parse_error;
+              case 'e': {
+                switch (op[7]) {
+                  case 'q':
+                    if (strcmp(op, "f32x4.eq") == 0) { return makeBinary(s, BinaryOp::EqVecF32x4); }
+                    goto parse_error;
+                  case 'x':
+                    if (strcmp(op, "f32x4.extract_lane") == 0) { return makeSIMDExtract(s, SIMDExtractOp::ExtractLaneVecF32x4, 4); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'f':
+                if (strcmp(op, "f32x4.floor") == 0) { return makeUnary(s, UnaryOp::FloorVecF32x4); }
+                goto parse_error;
+              case 'g': {
+                switch (op[7]) {
+                  case 'e':
+                    if (strcmp(op, "f32x4.ge") == 0) { return makeBinary(s, BinaryOp::GeVecF32x4); }
+                    goto parse_error;
+                  case 't':
+                    if (strcmp(op, "f32x4.gt") == 0) { return makeBinary(s, BinaryOp::GtVecF32x4); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'l': {
+                switch (op[7]) {
+                  case 'e':
+                    if (strcmp(op, "f32x4.le") == 0) { return makeBinary(s, BinaryOp::LeVecF32x4); }
+                    goto parse_error;
+                  case 't':
+                    if (strcmp(op, "f32x4.lt") == 0) { return makeBinary(s, BinaryOp::LtVecF32x4); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'm': {
+                switch (op[7]) {
+                  case 'a':
+                    if (strcmp(op, "f32x4.max") == 0) { return makeBinary(s, BinaryOp::MaxVecF32x4); }
+                    goto parse_error;
+                  case 'i':
+                    if (strcmp(op, "f32x4.min") == 0) { return makeBinary(s, BinaryOp::MinVecF32x4); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "f32x4.mul") == 0) { return makeBinary(s, BinaryOp::MulVecF32x4); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'n': {
+                switch (op[8]) {
+                  case '\0':
+                    if (strcmp(op, "f32x4.ne") == 0) { return makeBinary(s, BinaryOp::NeVecF32x4); }
+                    goto parse_error;
+                  case 'a':
+                    if (strcmp(op, "f32x4.nearest") == 0) { return makeUnary(s, UnaryOp::NearestVecF32x4); }
+                    goto parse_error;
+                  case 'g':
+                    if (strcmp(op, "f32x4.neg") == 0) { return makeUnary(s, UnaryOp::NegVecF32x4); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'p': {
+                switch (op[8]) {
+                  case 'a':
+                    if (strcmp(op, "f32x4.pmax") == 0) { return makeBinary(s, BinaryOp::PMaxVecF32x4); }
+                    goto parse_error;
+                  case 'i':
+                    if (strcmp(op, "f32x4.pmin") == 0) { return makeBinary(s, BinaryOp::PMinVecF32x4); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'q': {
+                switch (op[9]) {
+                  case 'a':
+                    if (strcmp(op, "f32x4.qfma") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::QFMAF32x4); }
+                    goto parse_error;
+                  case 's':
+                    if (strcmp(op, "f32x4.qfms") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::QFMSF32x4); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'r':
+                if (strcmp(op, "f32x4.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecF32x4, 4); }
+                goto parse_error;
+              case 's': {
+                switch (op[7]) {
+                  case 'p':
+                    if (strcmp(op, "f32x4.splat") == 0) { return makeUnary(s, UnaryOp::SplatVecF32x4); }
+                    goto parse_error;
+                  case 'q':
+                    if (strcmp(op, "f32x4.sqrt") == 0) { return makeUnary(s, UnaryOp::SqrtVecF32x4); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "f32x4.sub") == 0) { return makeBinary(s, BinaryOp::SubVecF32x4); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 't':
+                if (strcmp(op, "f32x4.trunc") == 0) { return makeUnary(s, UnaryOp::TruncVecF32x4); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          default: goto parse_error;
+        }
+      }
+      case '6': {
+        switch (op[3]) {
+          case '.': {
+            switch (op[4]) {
+              case 'a': {
+                switch (op[5]) {
+                  case 'b':
+                    if (strcmp(op, "f64.abs") == 0) { return makeUnary(s, UnaryOp::AbsFloat64); }
+                    goto parse_error;
+                  case 'd':
+                    if (strcmp(op, "f64.add") == 0) { return makeBinary(s, BinaryOp::AddFloat64); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'c': {
+                switch (op[5]) {
+                  case 'e':
+                    if (strcmp(op, "f64.ceil") == 0) { return makeUnary(s, UnaryOp::CeilFloat64); }
+                    goto parse_error;
+                  case 'o': {
+                    switch (op[6]) {
+                      case 'n': {
+                        switch (op[7]) {
+                          case 's':
+                            if (strcmp(op, "f64.const") == 0) { return makeConst(s, Type::f64); }
+                            goto parse_error;
+                          case 'v': {
+                            switch (op[13]) {
+                              case '3': {
+                                switch (op[16]) {
+                                  case 's':
+                                    if (strcmp(op, "f64.convert_i32_s") == 0) { return makeUnary(s, UnaryOp::ConvertSInt32ToFloat64); }
+                                    goto parse_error;
+                                  case 'u':
+                                    if (strcmp(op, "f64.convert_i32_u") == 0) { return makeUnary(s, UnaryOp::ConvertUInt32ToFloat64); }
+                                    goto parse_error;
+                                  default: goto parse_error;
+                                }
+                              }
+                              case '6': {
+                                switch (op[16]) {
+                                  case 's':
+                                    if (strcmp(op, "f64.convert_i64_s") == 0) { return makeUnary(s, UnaryOp::ConvertSInt64ToFloat64); }
+                                    goto parse_error;
+                                  case 'u':
+                                    if (strcmp(op, "f64.convert_i64_u") == 0) { return makeUnary(s, UnaryOp::ConvertUInt64ToFloat64); }
+                                    goto parse_error;
+                                  default: goto parse_error;
+                                }
+                              }
+                              default: goto parse_error;
+                            }
+                          }
+                          default: goto parse_error;
+                        }
+                      }
+                      case 'p':
+                        if (strcmp(op, "f64.copysign") == 0) { return makeBinary(s, BinaryOp::CopySignFloat64); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              case 'd':
+                if (strcmp(op, "f64.div") == 0) { return makeBinary(s, BinaryOp::DivFloat64); }
+                goto parse_error;
+              case 'e':
+                if (strcmp(op, "f64.eq") == 0) { return makeBinary(s, BinaryOp::EqFloat64); }
+                goto parse_error;
+              case 'f':
+                if (strcmp(op, "f64.floor") == 0) { return makeUnary(s, UnaryOp::FloorFloat64); }
+                goto parse_error;
+              case 'g': {
+                switch (op[5]) {
+                  case 'e':
+                    if (strcmp(op, "f64.ge") == 0) { return makeBinary(s, BinaryOp::GeFloat64); }
+                    goto parse_error;
+                  case 't':
+                    if (strcmp(op, "f64.gt") == 0) { return makeBinary(s, BinaryOp::GtFloat64); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'l': {
+                switch (op[5]) {
+                  case 'e':
+                    if (strcmp(op, "f64.le") == 0) { return makeBinary(s, BinaryOp::LeFloat64); }
+                    goto parse_error;
+                  case 'o':
+                    if (strcmp(op, "f64.load") == 0) { return makeLoad(s, Type::f64, /*isAtomic=*/false); }
+                    goto parse_error;
+                  case 't':
+                    if (strcmp(op, "f64.lt") == 0) { return makeBinary(s, BinaryOp::LtFloat64); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'm': {
+                switch (op[5]) {
+                  case 'a':
+                    if (strcmp(op, "f64.max") == 0) { return makeBinary(s, BinaryOp::MaxFloat64); }
+                    goto parse_error;
+                  case 'i':
+                    if (strcmp(op, "f64.min") == 0) { return makeBinary(s, BinaryOp::MinFloat64); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "f64.mul") == 0) { return makeBinary(s, BinaryOp::MulFloat64); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'n': {
+                switch (op[6]) {
+                  case '\0':
+                    if (strcmp(op, "f64.ne") == 0) { return makeBinary(s, BinaryOp::NeFloat64); }
+                    goto parse_error;
+                  case 'a':
+                    if (strcmp(op, "f64.nearest") == 0) { return makeUnary(s, UnaryOp::NearestFloat64); }
+                    goto parse_error;
+                  case 'g':
+                    if (strcmp(op, "f64.neg") == 0) { return makeUnary(s, UnaryOp::NegFloat64); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'p':
+                if (strcmp(op, "f64.promote_f32") == 0) { return makeUnary(s, UnaryOp::PromoteFloat32); }
+                goto parse_error;
+              case 'r':
+                if (strcmp(op, "f64.reinterpret_i64") == 0) { return makeUnary(s, UnaryOp::ReinterpretInt64); }
+                goto parse_error;
+              case 's': {
+                switch (op[5]) {
+                  case 'q':
+                    if (strcmp(op, "f64.sqrt") == 0) { return makeUnary(s, UnaryOp::SqrtFloat64); }
+                    goto parse_error;
+                  case 't':
+                    if (strcmp(op, "f64.store") == 0) { return makeStore(s, Type::f64, /*isAtomic=*/false); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "f64.sub") == 0) { return makeBinary(s, BinaryOp::SubFloat64); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 't':
+                if (strcmp(op, "f64.trunc") == 0) { return makeUnary(s, UnaryOp::TruncFloat64); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          case 'x': {
+            switch (op[6]) {
+              case 'a': {
+                switch (op[7]) {
+                  case 'b':
+                    if (strcmp(op, "f64x2.abs") == 0) { return makeUnary(s, UnaryOp::AbsVecF64x2); }
+                    goto parse_error;
+                  case 'd':
+                    if (strcmp(op, "f64x2.add") == 0) { return makeBinary(s, BinaryOp::AddVecF64x2); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'c': {
+                switch (op[7]) {
+                  case 'e':
+                    if (strcmp(op, "f64x2.ceil") == 0) { return makeUnary(s, UnaryOp::CeilVecF64x2); }
+                    goto parse_error;
+                  case 'o': {
+                    switch (op[20]) {
+                      case 's':
+                        if (strcmp(op, "f64x2.convert_i64x2_s") == 0) { return makeUnary(s, UnaryOp::ConvertSVecI64x2ToVecF64x2); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "f64x2.convert_i64x2_u") == 0) { return makeUnary(s, UnaryOp::ConvertUVecI64x2ToVecF64x2); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              case 'd':
+                if (strcmp(op, "f64x2.div") == 0) { return makeBinary(s, BinaryOp::DivVecF64x2); }
+                goto parse_error;
+              case 'e': {
+                switch (op[7]) {
+                  case 'q':
+                    if (strcmp(op, "f64x2.eq") == 0) { return makeBinary(s, BinaryOp::EqVecF64x2); }
+                    goto parse_error;
+                  case 'x':
+                    if (strcmp(op, "f64x2.extract_lane") == 0) { return makeSIMDExtract(s, SIMDExtractOp::ExtractLaneVecF64x2, 2); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'f':
+                if (strcmp(op, "f64x2.floor") == 0) { return makeUnary(s, UnaryOp::FloorVecF64x2); }
+                goto parse_error;
+              case 'g': {
+                switch (op[7]) {
+                  case 'e':
+                    if (strcmp(op, "f64x2.ge") == 0) { return makeBinary(s, BinaryOp::GeVecF64x2); }
+                    goto parse_error;
+                  case 't':
+                    if (strcmp(op, "f64x2.gt") == 0) { return makeBinary(s, BinaryOp::GtVecF64x2); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'l': {
+                switch (op[7]) {
+                  case 'e':
+                    if (strcmp(op, "f64x2.le") == 0) { return makeBinary(s, BinaryOp::LeVecF64x2); }
+                    goto parse_error;
+                  case 't':
+                    if (strcmp(op, "f64x2.lt") == 0) { return makeBinary(s, BinaryOp::LtVecF64x2); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'm': {
+                switch (op[7]) {
+                  case 'a':
+                    if (strcmp(op, "f64x2.max") == 0) { return makeBinary(s, BinaryOp::MaxVecF64x2); }
+                    goto parse_error;
+                  case 'i':
+                    if (strcmp(op, "f64x2.min") == 0) { return makeBinary(s, BinaryOp::MinVecF64x2); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "f64x2.mul") == 0) { return makeBinary(s, BinaryOp::MulVecF64x2); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'n': {
+                switch (op[8]) {
+                  case '\0':
+                    if (strcmp(op, "f64x2.ne") == 0) { return makeBinary(s, BinaryOp::NeVecF64x2); }
+                    goto parse_error;
+                  case 'a':
+                    if (strcmp(op, "f64x2.nearest") == 0) { return makeUnary(s, UnaryOp::NearestVecF64x2); }
+                    goto parse_error;
+                  case 'g':
+                    if (strcmp(op, "f64x2.neg") == 0) { return makeUnary(s, UnaryOp::NegVecF64x2); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'p': {
+                switch (op[8]) {
+                  case 'a':
+                    if (strcmp(op, "f64x2.pmax") == 0) { return makeBinary(s, BinaryOp::PMaxVecF64x2); }
+                    goto parse_error;
+                  case 'i':
+                    if (strcmp(op, "f64x2.pmin") == 0) { return makeBinary(s, BinaryOp::PMinVecF64x2); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'q': {
+                switch (op[9]) {
+                  case 'a':
+                    if (strcmp(op, "f64x2.qfma") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::QFMAF64x2); }
+                    goto parse_error;
+                  case 's':
+                    if (strcmp(op, "f64x2.qfms") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::QFMSF64x2); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'r':
+                if (strcmp(op, "f64x2.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecF64x2, 2); }
+                goto parse_error;
+              case 's': {
+                switch (op[7]) {
+                  case 'p':
+                    if (strcmp(op, "f64x2.splat") == 0) { return makeUnary(s, UnaryOp::SplatVecF64x2); }
+                    goto parse_error;
+                  case 'q':
+                    if (strcmp(op, "f64x2.sqrt") == 0) { return makeUnary(s, UnaryOp::SqrtVecF64x2); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "f64x2.sub") == 0) { return makeBinary(s, BinaryOp::SubVecF64x2); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 't':
+                if (strcmp(op, "f64x2.trunc") == 0) { return makeUnary(s, UnaryOp::TruncVecF64x2); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          default: goto parse_error;
+        }
+      }
+      default: goto parse_error;
+    }
+  }
+  case 'g': {
+    switch (op[7]) {
+      case 'g':
+        if (strcmp(op, "global.get") == 0) { return makeGlobalGet(s); }
+        goto parse_error;
+      case 's':
+        if (strcmp(op, "global.set") == 0) { return makeGlobalSet(s); }
+        goto parse_error;
+      default: goto parse_error;
+    }
+  }
+  case 'i': {
+    switch (op[1]) {
+      case '1': {
+        switch (op[6]) {
+          case 'a': {
+            switch (op[7]) {
+              case 'b':
+                if (strcmp(op, "i16x8.abs") == 0) { return makeUnary(s, UnaryOp::AbsVecI16x8); }
+                goto parse_error;
+              case 'd': {
+                switch (op[9]) {
+                  case '\0':
+                    if (strcmp(op, "i16x8.add") == 0) { return makeBinary(s, BinaryOp::AddVecI16x8); }
+                    goto parse_error;
+                  case '_': {
+                    switch (op[19]) {
+                      case 's':
+                        if (strcmp(op, "i16x8.add_saturate_s") == 0) { return makeBinary(s, BinaryOp::AddSatSVecI16x8); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i16x8.add_saturate_u") == 0) { return makeBinary(s, BinaryOp::AddSatUVecI16x8); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              case 'l':
+                if (strcmp(op, "i16x8.all_true") == 0) { return makeUnary(s, UnaryOp::AllTrueVecI16x8); }
+                goto parse_error;
+              case 'n':
+                if (strcmp(op, "i16x8.any_true") == 0) { return makeUnary(s, UnaryOp::AnyTrueVecI16x8); }
+                goto parse_error;
+              case 'v':
+                if (strcmp(op, "i16x8.avgr_u") == 0) { return makeBinary(s, BinaryOp::AvgrUVecI16x8); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          case 'b':
+            if (strcmp(op, "i16x8.bitmask") == 0) { return makeUnary(s, UnaryOp::BitmaskVecI16x8); }
+            goto parse_error;
+          case 'e': {
+            switch (op[7]) {
+              case 'q':
+                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;
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          case 'g': {
+            switch (op[7]) {
+              case 'e': {
+                switch (op[9]) {
+                  case 's':
+                    if (strcmp(op, "i16x8.ge_s") == 0) { return makeBinary(s, BinaryOp::GeSVecI16x8); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i16x8.ge_u") == 0) { return makeBinary(s, BinaryOp::GeUVecI16x8); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 't': {
+                switch (op[9]) {
+                  case 's':
+                    if (strcmp(op, "i16x8.gt_s") == 0) { return makeBinary(s, BinaryOp::GtSVecI16x8); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i16x8.gt_u") == 0) { return makeBinary(s, BinaryOp::GtUVecI16x8); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          case 'l': {
+            switch (op[7]) {
+              case 'e': {
+                switch (op[9]) {
+                  case 's':
+                    if (strcmp(op, "i16x8.le_s") == 0) { return makeBinary(s, BinaryOp::LeSVecI16x8); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i16x8.le_u") == 0) { return makeBinary(s, BinaryOp::LeUVecI16x8); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'o': {
+                switch (op[14]) {
+                  case 's':
+                    if (strcmp(op, "i16x8.load8x8_s") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadExtSVec8x8ToVecI16x8); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i16x8.load8x8_u") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadExtUVec8x8ToVecI16x8); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 't': {
+                switch (op[9]) {
+                  case 's':
+                    if (strcmp(op, "i16x8.lt_s") == 0) { return makeBinary(s, BinaryOp::LtSVecI16x8); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i16x8.lt_u") == 0) { return makeBinary(s, BinaryOp::LtUVecI16x8); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          case 'm': {
+            switch (op[7]) {
+              case 'a': {
+                switch (op[10]) {
+                  case 's':
+                    if (strcmp(op, "i16x8.max_s") == 0) { return makeBinary(s, BinaryOp::MaxSVecI16x8); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i16x8.max_u") == 0) { return makeBinary(s, BinaryOp::MaxUVecI16x8); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'i': {
+                switch (op[10]) {
+                  case 's':
+                    if (strcmp(op, "i16x8.min_s") == 0) { return makeBinary(s, BinaryOp::MinSVecI16x8); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i16x8.min_u") == 0) { return makeBinary(s, BinaryOp::MinUVecI16x8); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'u':
+                if (strcmp(op, "i16x8.mul") == 0) { return makeBinary(s, BinaryOp::MulVecI16x8); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          case 'n': {
+            switch (op[7]) {
+              case 'a': {
+                switch (op[19]) {
+                  case 's':
+                    if (strcmp(op, "i16x8.narrow_i32x4_s") == 0) { return makeBinary(s, BinaryOp::NarrowSVecI32x4ToVecI16x8); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i16x8.narrow_i32x4_u") == 0) { return makeBinary(s, BinaryOp::NarrowUVecI32x4ToVecI16x8); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'e': {
+                switch (op[8]) {
+                  case '\0':
+                    if (strcmp(op, "i16x8.ne") == 0) { return makeBinary(s, BinaryOp::NeVecI16x8); }
+                    goto parse_error;
+                  case 'g':
+                    if (strcmp(op, "i16x8.neg") == 0) { return makeUnary(s, UnaryOp::NegVecI16x8); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          case 'r':
+            if (strcmp(op, "i16x8.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecI16x8, 8); }
+            goto parse_error;
+          case 's': {
+            switch (op[7]) {
+              case 'h': {
+                switch (op[8]) {
+                  case 'l':
+                    if (strcmp(op, "i16x8.shl") == 0) { return makeSIMDShift(s, SIMDShiftOp::ShlVecI16x8); }
+                    goto parse_error;
+                  case 'r': {
+                    switch (op[10]) {
+                      case 's':
+                        if (strcmp(op, "i16x8.shr_s") == 0) { return makeSIMDShift(s, SIMDShiftOp::ShrSVecI16x8); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i16x8.shr_u") == 0) { return makeSIMDShift(s, SIMDShiftOp::ShrUVecI16x8); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              case 'p':
+                if (strcmp(op, "i16x8.splat") == 0) { return makeUnary(s, UnaryOp::SplatVecI16x8); }
+                goto parse_error;
+              case 'u': {
+                switch (op[9]) {
+                  case '\0':
+                    if (strcmp(op, "i16x8.sub") == 0) { return makeBinary(s, BinaryOp::SubVecI16x8); }
+                    goto parse_error;
+                  case '_': {
+                    switch (op[19]) {
+                      case 's':
+                        if (strcmp(op, "i16x8.sub_saturate_s") == 0) { return makeBinary(s, BinaryOp::SubSatSVecI16x8); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i16x8.sub_saturate_u") == 0) { return makeBinary(s, BinaryOp::SubSatUVecI16x8); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          case 'w': {
+            switch (op[12]) {
+              case 'h': {
+                switch (op[23]) {
+                  case 's':
+                    if (strcmp(op, "i16x8.widen_high_i8x16_s") == 0) { return makeUnary(s, UnaryOp::WidenHighSVecI8x16ToVecI16x8); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i16x8.widen_high_i8x16_u") == 0) { return makeUnary(s, UnaryOp::WidenHighUVecI8x16ToVecI16x8); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'l': {
+                switch (op[22]) {
+                  case 's':
+                    if (strcmp(op, "i16x8.widen_low_i8x16_s") == 0) { return makeUnary(s, UnaryOp::WidenLowSVecI8x16ToVecI16x8); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i16x8.widen_low_i8x16_u") == 0) { return makeUnary(s, UnaryOp::WidenLowUVecI8x16ToVecI16x8); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          default: goto parse_error;
+        }
+      }
+      case '3': {
+        switch (op[2]) {
+          case '1': {
+            switch (op[4]) {
+              case 'g': {
+                switch (op[8]) {
+                  case 's':
+                    if (strcmp(op, "i31.get_s") == 0) { return makeI31Get(s, true); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i31.get_u") == 0) { return makeI31Get(s, false); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'n':
+                if (strcmp(op, "i31.new") == 0) { return makeI31New(s); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          case '2': {
+            switch (op[3]) {
+              case '.': {
+                switch (op[4]) {
+                  case 'a': {
+                    switch (op[5]) {
+                      case 'd':
+                        if (strcmp(op, "i32.add") == 0) { return makeBinary(s, BinaryOp::AddInt32); }
+                        goto parse_error;
+                      case 'n':
+                        if (strcmp(op, "i32.and") == 0) { return makeBinary(s, BinaryOp::AndInt32); }
+                        goto parse_error;
+                      case 't': {
+                        switch (op[11]) {
+                          case 'l': {
+                            switch (op[15]) {
+                              case '\0':
+                                if (strcmp(op, "i32.atomic.load") == 0) { return makeLoad(s, Type::i32, /*isAtomic=*/true); }
+                                goto parse_error;
+                              case '1':
+                                if (strcmp(op, "i32.atomic.load16_u") == 0) { return makeLoad(s, Type::i32, /*isAtomic=*/true); }
+                                goto parse_error;
+                              case '8':
+                                if (strcmp(op, "i32.atomic.load8_u") == 0) { return makeLoad(s, Type::i32, /*isAtomic=*/true); }
+                                goto parse_error;
+                              default: goto parse_error;
+                            }
+                          }
+                          case 'r': {
+                            switch (op[14]) {
+                              case '.': {
+                                switch (op[15]) {
+                                  case 'a': {
+                                    switch (op[16]) {
+                                      case 'd':
+                                        if (strcmp(op, "i32.atomic.rmw.add") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                        goto parse_error;
+                                      case 'n':
+                                        if (strcmp(op, "i32.atomic.rmw.and") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                        goto parse_error;
+                                      default: goto parse_error;
+                                    }
+                                  }
+                                  case 'c':
+                                    if (strcmp(op, "i32.atomic.rmw.cmpxchg") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                    goto parse_error;
+                                  case 'o':
+                                    if (strcmp(op, "i32.atomic.rmw.or") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                    goto parse_error;
+                                  case 's':
+                                    if (strcmp(op, "i32.atomic.rmw.sub") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                    goto parse_error;
+                                  case 'x': {
+                                    switch (op[16]) {
+                                      case 'c':
+                                        if (strcmp(op, "i32.atomic.rmw.xchg") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                        goto parse_error;
+                                      case 'o':
+                                        if (strcmp(op, "i32.atomic.rmw.xor") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                        goto parse_error;
+                                      default: goto parse_error;
+                                    }
+                                  }
+                                  default: goto parse_error;
+                                }
+                              }
+                              case '1': {
+                                switch (op[17]) {
+                                  case 'a': {
+                                    switch (op[18]) {
+                                      case 'd':
+                                        if (strcmp(op, "i32.atomic.rmw16.add_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                        goto parse_error;
+                                      case 'n':
+                                        if (strcmp(op, "i32.atomic.rmw16.and_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                        goto parse_error;
+                                      default: goto parse_error;
+                                    }
+                                  }
+                                  case 'c':
+                                    if (strcmp(op, "i32.atomic.rmw16.cmpxchg_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                    goto parse_error;
+                                  case 'o':
+                                    if (strcmp(op, "i32.atomic.rmw16.or_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                    goto parse_error;
+                                  case 's':
+                                    if (strcmp(op, "i32.atomic.rmw16.sub_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                    goto parse_error;
+                                  case 'x': {
+                                    switch (op[18]) {
+                                      case 'c':
+                                        if (strcmp(op, "i32.atomic.rmw16.xchg_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                        goto parse_error;
+                                      case 'o':
+                                        if (strcmp(op, "i32.atomic.rmw16.xor_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                        goto parse_error;
+                                      default: goto parse_error;
+                                    }
+                                  }
+                                  default: goto parse_error;
+                                }
+                              }
+                              case '8': {
+                                switch (op[16]) {
+                                  case 'a': {
+                                    switch (op[17]) {
+                                      case 'd':
+                                        if (strcmp(op, "i32.atomic.rmw8.add_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                        goto parse_error;
+                                      case 'n':
+                                        if (strcmp(op, "i32.atomic.rmw8.and_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                        goto parse_error;
+                                      default: goto parse_error;
+                                    }
+                                  }
+                                  case 'c':
+                                    if (strcmp(op, "i32.atomic.rmw8.cmpxchg_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                    goto parse_error;
+                                  case 'o':
+                                    if (strcmp(op, "i32.atomic.rmw8.or_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                    goto parse_error;
+                                  case 's':
+                                    if (strcmp(op, "i32.atomic.rmw8.sub_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                    goto parse_error;
+                                  case 'x': {
+                                    switch (op[17]) {
+                                      case 'c':
+                                        if (strcmp(op, "i32.atomic.rmw8.xchg_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                        goto parse_error;
+                                      case 'o':
+                                        if (strcmp(op, "i32.atomic.rmw8.xor_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i32); }
+                                        goto parse_error;
+                                      default: goto parse_error;
+                                    }
+                                  }
+                                  default: goto parse_error;
+                                }
+                              }
+                              default: goto parse_error;
+                            }
+                          }
+                          case 's': {
+                            switch (op[16]) {
+                              case '\0':
+                                if (strcmp(op, "i32.atomic.store") == 0) { return makeStore(s, Type::i32, /*isAtomic=*/true); }
+                                goto parse_error;
+                              case '1':
+                                if (strcmp(op, "i32.atomic.store16") == 0) { return makeStore(s, Type::i32, /*isAtomic=*/true); }
+                                goto parse_error;
+                              case '8':
+                                if (strcmp(op, "i32.atomic.store8") == 0) { return makeStore(s, Type::i32, /*isAtomic=*/true); }
+                                goto parse_error;
+                              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;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'c': {
+                    switch (op[5]) {
+                      case 'l':
+                        if (strcmp(op, "i32.clz") == 0) { return makeUnary(s, UnaryOp::ClzInt32); }
+                        goto parse_error;
+                      case 'o':
+                        if (strcmp(op, "i32.const") == 0) { return makeConst(s, Type::i32); }
+                        goto parse_error;
+                      case 't':
+                        if (strcmp(op, "i32.ctz") == 0) { return makeUnary(s, UnaryOp::CtzInt32); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'd': {
+                    switch (op[8]) {
+                      case 's':
+                        if (strcmp(op, "i32.div_s") == 0) { return makeBinary(s, BinaryOp::DivSInt32); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i32.div_u") == 0) { return makeBinary(s, BinaryOp::DivUInt32); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'e': {
+                    switch (op[5]) {
+                      case 'q': {
+                        switch (op[6]) {
+                          case '\0':
+                            if (strcmp(op, "i32.eq") == 0) { return makeBinary(s, BinaryOp::EqInt32); }
+                            goto parse_error;
+                          case 'z':
+                            if (strcmp(op, "i32.eqz") == 0) { return makeUnary(s, UnaryOp::EqZInt32); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case 'x': {
+                        switch (op[10]) {
+                          case '1':
+                            if (strcmp(op, "i32.extend16_s") == 0) { return makeUnary(s, UnaryOp::ExtendS16Int32); }
+                            goto parse_error;
+                          case '8':
+                            if (strcmp(op, "i32.extend8_s") == 0) { return makeUnary(s, UnaryOp::ExtendS8Int32); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'g': {
+                    switch (op[5]) {
+                      case 'e': {
+                        switch (op[7]) {
+                          case 's':
+                            if (strcmp(op, "i32.ge_s") == 0) { return makeBinary(s, BinaryOp::GeSInt32); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i32.ge_u") == 0) { return makeBinary(s, BinaryOp::GeUInt32); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case 't': {
+                        switch (op[7]) {
+                          case 's':
+                            if (strcmp(op, "i32.gt_s") == 0) { return makeBinary(s, BinaryOp::GtSInt32); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i32.gt_u") == 0) { return makeBinary(s, BinaryOp::GtUInt32); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'l': {
+                    switch (op[5]) {
+                      case 'e': {
+                        switch (op[7]) {
+                          case 's':
+                            if (strcmp(op, "i32.le_s") == 0) { return makeBinary(s, BinaryOp::LeSInt32); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i32.le_u") == 0) { return makeBinary(s, BinaryOp::LeUInt32); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case 'o': {
+                        switch (op[8]) {
+                          case '\0':
+                            if (strcmp(op, "i32.load") == 0) { return makeLoad(s, Type::i32, /*isAtomic=*/false); }
+                            goto parse_error;
+                          case '1': {
+                            switch (op[11]) {
+                              case 's':
+                                if (strcmp(op, "i32.load16_s") == 0) { return makeLoad(s, Type::i32, /*isAtomic=*/false); }
+                                goto parse_error;
+                              case 'u':
+                                if (strcmp(op, "i32.load16_u") == 0) { return makeLoad(s, Type::i32, /*isAtomic=*/false); }
+                                goto parse_error;
+                              default: goto parse_error;
+                            }
+                          }
+                          case '8': {
+                            switch (op[10]) {
+                              case 's':
+                                if (strcmp(op, "i32.load8_s") == 0) { return makeLoad(s, Type::i32, /*isAtomic=*/false); }
+                                goto parse_error;
+                              case 'u':
+                                if (strcmp(op, "i32.load8_u") == 0) { return makeLoad(s, Type::i32, /*isAtomic=*/false); }
+                                goto parse_error;
+                              default: goto parse_error;
+                            }
+                          }
+                          default: goto parse_error;
+                        }
+                      }
+                      case 't': {
+                        switch (op[7]) {
+                          case 's':
+                            if (strcmp(op, "i32.lt_s") == 0) { return makeBinary(s, BinaryOp::LtSInt32); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i32.lt_u") == 0) { return makeBinary(s, BinaryOp::LtUInt32); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'm':
+                    if (strcmp(op, "i32.mul") == 0) { return makeBinary(s, BinaryOp::MulInt32); }
+                    goto parse_error;
+                  case 'n':
+                    if (strcmp(op, "i32.ne") == 0) { return makeBinary(s, BinaryOp::NeInt32); }
+                    goto parse_error;
+                  case 'o':
+                    if (strcmp(op, "i32.or") == 0) { return makeBinary(s, BinaryOp::OrInt32); }
+                    goto parse_error;
+                  case 'p':
+                    if (strcmp(op, "i32.popcnt") == 0) { return makeUnary(s, UnaryOp::PopcntInt32); }
+                    goto parse_error;
+                  case 'r': {
+                    switch (op[5]) {
+                      case 'e': {
+                        switch (op[6]) {
+                          case 'i':
+                            if (strcmp(op, "i32.reinterpret_f32") == 0) { return makeUnary(s, UnaryOp::ReinterpretFloat32); }
+                            goto parse_error;
+                          case 'm': {
+                            switch (op[8]) {
+                              case 's':
+                                if (strcmp(op, "i32.rem_s") == 0) { return makeBinary(s, BinaryOp::RemSInt32); }
+                                goto parse_error;
+                              case 'u':
+                                if (strcmp(op, "i32.rem_u") == 0) { return makeBinary(s, BinaryOp::RemUInt32); }
+                                goto parse_error;
+                              default: goto parse_error;
+                            }
+                          }
+                          default: goto parse_error;
+                        }
+                      }
+                      case 'o': {
+                        switch (op[7]) {
+                          case 'l':
+                            if (strcmp(op, "i32.rotl") == 0) { return makeBinary(s, BinaryOp::RotLInt32); }
+                            goto parse_error;
+                          case 'r':
+                            if (strcmp(op, "i32.rotr") == 0) { return makeBinary(s, BinaryOp::RotRInt32); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  case 's': {
+                    switch (op[5]) {
+                      case 'h': {
+                        switch (op[6]) {
+                          case 'l':
+                            if (strcmp(op, "i32.shl") == 0) { return makeBinary(s, BinaryOp::ShlInt32); }
+                            goto parse_error;
+                          case 'r': {
+                            switch (op[8]) {
+                              case 's':
+                                if (strcmp(op, "i32.shr_s") == 0) { return makeBinary(s, BinaryOp::ShrSInt32); }
+                                goto parse_error;
+                              case 'u':
+                                if (strcmp(op, "i32.shr_u") == 0) { return makeBinary(s, BinaryOp::ShrUInt32); }
+                                goto parse_error;
+                              default: goto parse_error;
+                            }
+                          }
+                          default: goto parse_error;
+                        }
+                      }
+                      case 't': {
+                        switch (op[9]) {
+                          case '\0':
+                            if (strcmp(op, "i32.store") == 0) { return makeStore(s, Type::i32, /*isAtomic=*/false); }
+                            goto parse_error;
+                          case '1':
+                            if (strcmp(op, "i32.store16") == 0) { return makeStore(s, Type::i32, /*isAtomic=*/false); }
+                            goto parse_error;
+                          case '8':
+                            if (strcmp(op, "i32.store8") == 0) { return makeStore(s, Type::i32, /*isAtomic=*/false); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case 'u':
+                        if (strcmp(op, "i32.sub") == 0) { return makeBinary(s, BinaryOp::SubInt32); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case 't': {
+                    switch (op[10]) {
+                      case 'f': {
+                        switch (op[11]) {
+                          case '3': {
+                            switch (op[14]) {
+                              case 's':
+                                if (strcmp(op, "i32.trunc_f32_s") == 0) { return makeUnary(s, UnaryOp::TruncSFloat32ToInt32); }
+                                goto parse_error;
+                              case 'u':
+                                if (strcmp(op, "i32.trunc_f32_u") == 0) { return makeUnary(s, UnaryOp::TruncUFloat32ToInt32); }
+                                goto parse_error;
+                              default: goto parse_error;
+                            }
+                          }
+                          case '6': {
+                            switch (op[14]) {
+                              case 's':
+                                if (strcmp(op, "i32.trunc_f64_s") == 0) { return makeUnary(s, UnaryOp::TruncSFloat64ToInt32); }
+                                goto parse_error;
+                              case 'u':
+                                if (strcmp(op, "i32.trunc_f64_u") == 0) { return makeUnary(s, UnaryOp::TruncUFloat64ToInt32); }
+                                goto parse_error;
+                              default: goto parse_error;
+                            }
+                          }
+                          default: goto parse_error;
+                        }
+                      }
+                      case 's': {
+                        switch (op[15]) {
+                          case '3': {
+                            switch (op[18]) {
+                              case 's':
+                                if (strcmp(op, "i32.trunc_sat_f32_s") == 0) { return makeUnary(s, UnaryOp::TruncSatSFloat32ToInt32); }
+                                goto parse_error;
+                              case 'u':
+                                if (strcmp(op, "i32.trunc_sat_f32_u") == 0) { return makeUnary(s, UnaryOp::TruncSatUFloat32ToInt32); }
+                                goto parse_error;
+                              default: goto parse_error;
+                            }
+                          }
+                          case '6': {
+                            switch (op[18]) {
+                              case 's':
+                                if (strcmp(op, "i32.trunc_sat_f64_s") == 0) { return makeUnary(s, UnaryOp::TruncSatSFloat64ToInt32); }
+                                goto parse_error;
+                              case 'u':
+                                if (strcmp(op, "i32.trunc_sat_f64_u") == 0) { return makeUnary(s, UnaryOp::TruncSatUFloat64ToInt32); }
+                                goto parse_error;
+                              default: goto parse_error;
+                            }
+                          }
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'w':
+                    if (strcmp(op, "i32.wrap_i64") == 0) { return makeUnary(s, UnaryOp::WrapInt64); }
+                    goto parse_error;
+                  case 'x':
+                    if (strcmp(op, "i32.xor") == 0) { return makeBinary(s, BinaryOp::XorInt32); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'x': {
+                switch (op[6]) {
+                  case 'a': {
+                    switch (op[7]) {
+                      case 'b':
+                        if (strcmp(op, "i32x4.abs") == 0) { return makeUnary(s, UnaryOp::AbsVecI32x4); }
+                        goto parse_error;
+                      case 'd':
+                        if (strcmp(op, "i32x4.add") == 0) { return makeBinary(s, BinaryOp::AddVecI32x4); }
+                        goto parse_error;
+                      case 'l':
+                        if (strcmp(op, "i32x4.all_true") == 0) { return makeUnary(s, UnaryOp::AllTrueVecI32x4); }
+                        goto parse_error;
+                      case 'n':
+                        if (strcmp(op, "i32x4.any_true") == 0) { return makeUnary(s, UnaryOp::AnyTrueVecI32x4); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'b':
+                    if (strcmp(op, "i32x4.bitmask") == 0) { return makeUnary(s, UnaryOp::BitmaskVecI32x4); }
+                    goto parse_error;
+                  case 'd':
+                    if (strcmp(op, "i32x4.dot_i16x8_s") == 0) { return makeBinary(s, BinaryOp::DotSVecI16x8ToVecI32x4); }
+                    goto parse_error;
+                  case 'e': {
+                    switch (op[7]) {
+                      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;
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'g': {
+                    switch (op[7]) {
+                      case 'e': {
+                        switch (op[9]) {
+                          case 's':
+                            if (strcmp(op, "i32x4.ge_s") == 0) { return makeBinary(s, BinaryOp::GeSVecI32x4); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i32x4.ge_u") == 0) { return makeBinary(s, BinaryOp::GeUVecI32x4); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case 't': {
+                        switch (op[9]) {
+                          case 's':
+                            if (strcmp(op, "i32x4.gt_s") == 0) { return makeBinary(s, BinaryOp::GtSVecI32x4); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i32x4.gt_u") == 0) { return makeBinary(s, BinaryOp::GtUVecI32x4); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'l': {
+                    switch (op[7]) {
+                      case 'e': {
+                        switch (op[9]) {
+                          case 's':
+                            if (strcmp(op, "i32x4.le_s") == 0) { return makeBinary(s, BinaryOp::LeSVecI32x4); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i32x4.le_u") == 0) { return makeBinary(s, BinaryOp::LeUVecI32x4); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case 'o': {
+                        switch (op[15]) {
+                          case 's':
+                            if (strcmp(op, "i32x4.load16x4_s") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadExtSVec16x4ToVecI32x4); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i32x4.load16x4_u") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadExtUVec16x4ToVecI32x4); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case 't': {
+                        switch (op[9]) {
+                          case 's':
+                            if (strcmp(op, "i32x4.lt_s") == 0) { return makeBinary(s, BinaryOp::LtSVecI32x4); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i32x4.lt_u") == 0) { return makeBinary(s, BinaryOp::LtUVecI32x4); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'm': {
+                    switch (op[7]) {
+                      case 'a': {
+                        switch (op[10]) {
+                          case 's':
+                            if (strcmp(op, "i32x4.max_s") == 0) { return makeBinary(s, BinaryOp::MaxSVecI32x4); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i32x4.max_u") == 0) { return makeBinary(s, BinaryOp::MaxUVecI32x4); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case 'i': {
+                        switch (op[10]) {
+                          case 's':
+                            if (strcmp(op, "i32x4.min_s") == 0) { return makeBinary(s, BinaryOp::MinSVecI32x4); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i32x4.min_u") == 0) { return makeBinary(s, BinaryOp::MinUVecI32x4); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case 'u':
+                        if (strcmp(op, "i32x4.mul") == 0) { return makeBinary(s, BinaryOp::MulVecI32x4); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'n': {
+                    switch (op[8]) {
+                      case '\0':
+                        if (strcmp(op, "i32x4.ne") == 0) { return makeBinary(s, BinaryOp::NeVecI32x4); }
+                        goto parse_error;
+                      case 'g':
+                        if (strcmp(op, "i32x4.neg") == 0) { return makeUnary(s, UnaryOp::NegVecI32x4); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'r':
+                    if (strcmp(op, "i32x4.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecI32x4, 4); }
+                    goto parse_error;
+                  case 's': {
+                    switch (op[7]) {
+                      case 'h': {
+                        switch (op[8]) {
+                          case 'l':
+                            if (strcmp(op, "i32x4.shl") == 0) { return makeSIMDShift(s, SIMDShiftOp::ShlVecI32x4); }
+                            goto parse_error;
+                          case 'r': {
+                            switch (op[10]) {
+                              case 's':
+                                if (strcmp(op, "i32x4.shr_s") == 0) { return makeSIMDShift(s, SIMDShiftOp::ShrSVecI32x4); }
+                                goto parse_error;
+                              case 'u':
+                                if (strcmp(op, "i32x4.shr_u") == 0) { return makeSIMDShift(s, SIMDShiftOp::ShrUVecI32x4); }
+                                goto parse_error;
+                              default: goto parse_error;
+                            }
+                          }
+                          default: goto parse_error;
+                        }
+                      }
+                      case 'p':
+                        if (strcmp(op, "i32x4.splat") == 0) { return makeUnary(s, UnaryOp::SplatVecI32x4); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i32x4.sub") == 0) { return makeBinary(s, BinaryOp::SubVecI32x4); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case 't': {
+                    switch (op[22]) {
+                      case 's':
+                        if (strcmp(op, "i32x4.trunc_sat_f32x4_s") == 0) { return makeUnary(s, UnaryOp::TruncSatSVecF32x4ToVecI32x4); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i32x4.trunc_sat_f32x4_u") == 0) { return makeUnary(s, UnaryOp::TruncSatUVecF32x4ToVecI32x4); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'w': {
+                    switch (op[12]) {
+                      case 'h': {
+                        switch (op[23]) {
+                          case 's':
+                            if (strcmp(op, "i32x4.widen_high_i16x8_s") == 0) { return makeUnary(s, UnaryOp::WidenHighSVecI16x8ToVecI32x4); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i32x4.widen_high_i16x8_u") == 0) { return makeUnary(s, UnaryOp::WidenHighUVecI16x8ToVecI32x4); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case 'l': {
+                        switch (op[22]) {
+                          case 's':
+                            if (strcmp(op, "i32x4.widen_low_i16x8_s") == 0) { return makeUnary(s, UnaryOp::WidenLowSVecI16x8ToVecI32x4); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i32x4.widen_low_i16x8_u") == 0) { return makeUnary(s, UnaryOp::WidenLowUVecI16x8ToVecI32x4); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          default: goto parse_error;
+        }
+      }
+      case '6': {
+        switch (op[3]) {
+          case '.': {
+            switch (op[4]) {
+              case 'a': {
+                switch (op[5]) {
+                  case 'd':
+                    if (strcmp(op, "i64.add") == 0) { return makeBinary(s, BinaryOp::AddInt64); }
+                    goto parse_error;
+                  case 'n':
+                    if (strcmp(op, "i64.and") == 0) { return makeBinary(s, BinaryOp::AndInt64); }
+                    goto parse_error;
+                  case 't': {
+                    switch (op[11]) {
+                      case 'l': {
+                        switch (op[15]) {
+                          case '\0':
+                            if (strcmp(op, "i64.atomic.load") == 0) { return makeLoad(s, Type::i64, /*isAtomic=*/true); }
+                            goto parse_error;
+                          case '1':
+                            if (strcmp(op, "i64.atomic.load16_u") == 0) { return makeLoad(s, Type::i64, /*isAtomic=*/true); }
+                            goto parse_error;
+                          case '3':
+                            if (strcmp(op, "i64.atomic.load32_u") == 0) { return makeLoad(s, Type::i64, /*isAtomic=*/true); }
+                            goto parse_error;
+                          case '8':
+                            if (strcmp(op, "i64.atomic.load8_u") == 0) { return makeLoad(s, Type::i64, /*isAtomic=*/true); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case 'r': {
+                        switch (op[14]) {
+                          case '.': {
+                            switch (op[15]) {
+                              case 'a': {
+                                switch (op[16]) {
+                                  case 'd':
+                                    if (strcmp(op, "i64.atomic.rmw.add") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  case 'n':
+                                    if (strcmp(op, "i64.atomic.rmw.and") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  default: goto parse_error;
+                                }
+                              }
+                              case 'c':
+                                if (strcmp(op, "i64.atomic.rmw.cmpxchg") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                goto parse_error;
+                              case 'o':
+                                if (strcmp(op, "i64.atomic.rmw.or") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                goto parse_error;
+                              case 's':
+                                if (strcmp(op, "i64.atomic.rmw.sub") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                goto parse_error;
+                              case 'x': {
+                                switch (op[16]) {
+                                  case 'c':
+                                    if (strcmp(op, "i64.atomic.rmw.xchg") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  case 'o':
+                                    if (strcmp(op, "i64.atomic.rmw.xor") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  default: goto parse_error;
+                                }
+                              }
+                              default: goto parse_error;
+                            }
+                          }
+                          case '1': {
+                            switch (op[17]) {
+                              case 'a': {
+                                switch (op[18]) {
+                                  case 'd':
+                                    if (strcmp(op, "i64.atomic.rmw16.add_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  case 'n':
+                                    if (strcmp(op, "i64.atomic.rmw16.and_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  default: goto parse_error;
+                                }
+                              }
+                              case 'c':
+                                if (strcmp(op, "i64.atomic.rmw16.cmpxchg_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                goto parse_error;
+                              case 'o':
+                                if (strcmp(op, "i64.atomic.rmw16.or_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                goto parse_error;
+                              case 's':
+                                if (strcmp(op, "i64.atomic.rmw16.sub_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                goto parse_error;
+                              case 'x': {
+                                switch (op[18]) {
+                                  case 'c':
+                                    if (strcmp(op, "i64.atomic.rmw16.xchg_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  case 'o':
+                                    if (strcmp(op, "i64.atomic.rmw16.xor_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  default: goto parse_error;
+                                }
+                              }
+                              default: goto parse_error;
+                            }
+                          }
+                          case '3': {
+                            switch (op[17]) {
+                              case 'a': {
+                                switch (op[18]) {
+                                  case 'd':
+                                    if (strcmp(op, "i64.atomic.rmw32.add_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  case 'n':
+                                    if (strcmp(op, "i64.atomic.rmw32.and_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  default: goto parse_error;
+                                }
+                              }
+                              case 'c':
+                                if (strcmp(op, "i64.atomic.rmw32.cmpxchg_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                goto parse_error;
+                              case 'o':
+                                if (strcmp(op, "i64.atomic.rmw32.or_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                goto parse_error;
+                              case 's':
+                                if (strcmp(op, "i64.atomic.rmw32.sub_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                goto parse_error;
+                              case 'x': {
+                                switch (op[18]) {
+                                  case 'c':
+                                    if (strcmp(op, "i64.atomic.rmw32.xchg_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  case 'o':
+                                    if (strcmp(op, "i64.atomic.rmw32.xor_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  default: goto parse_error;
+                                }
+                              }
+                              default: goto parse_error;
+                            }
+                          }
+                          case '8': {
+                            switch (op[16]) {
+                              case 'a': {
+                                switch (op[17]) {
+                                  case 'd':
+                                    if (strcmp(op, "i64.atomic.rmw8.add_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  case 'n':
+                                    if (strcmp(op, "i64.atomic.rmw8.and_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  default: goto parse_error;
+                                }
+                              }
+                              case 'c':
+                                if (strcmp(op, "i64.atomic.rmw8.cmpxchg_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                goto parse_error;
+                              case 'o':
+                                if (strcmp(op, "i64.atomic.rmw8.or_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                goto parse_error;
+                              case 's':
+                                if (strcmp(op, "i64.atomic.rmw8.sub_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                goto parse_error;
+                              case 'x': {
+                                switch (op[17]) {
+                                  case 'c':
+                                    if (strcmp(op, "i64.atomic.rmw8.xchg_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  case 'o':
+                                    if (strcmp(op, "i64.atomic.rmw8.xor_u") == 0) { return makeAtomicRMWOrCmpxchg(s, Type::i64); }
+                                    goto parse_error;
+                                  default: goto parse_error;
+                                }
+                              }
+                              default: goto parse_error;
+                            }
+                          }
+                          default: goto parse_error;
+                        }
+                      }
+                      case 's': {
+                        switch (op[16]) {
+                          case '\0':
+                            if (strcmp(op, "i64.atomic.store") == 0) { return makeStore(s, Type::i64, /*isAtomic=*/true); }
+                            goto parse_error;
+                          case '1':
+                            if (strcmp(op, "i64.atomic.store16") == 0) { return makeStore(s, Type::i64, /*isAtomic=*/true); }
+                            goto parse_error;
+                          case '3':
+                            if (strcmp(op, "i64.atomic.store32") == 0) { return makeStore(s, Type::i64, /*isAtomic=*/true); }
+                            goto parse_error;
+                          case '8':
+                            if (strcmp(op, "i64.atomic.store8") == 0) { return makeStore(s, Type::i64, /*isAtomic=*/true); }
+                            goto parse_error;
+                          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;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              case 'c': {
+                switch (op[5]) {
+                  case 'l':
+                    if (strcmp(op, "i64.clz") == 0) { return makeUnary(s, UnaryOp::ClzInt64); }
+                    goto parse_error;
+                  case 'o':
+                    if (strcmp(op, "i64.const") == 0) { return makeConst(s, Type::i64); }
+                    goto parse_error;
+                  case 't':
+                    if (strcmp(op, "i64.ctz") == 0) { return makeUnary(s, UnaryOp::CtzInt64); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'd': {
+                switch (op[8]) {
+                  case 's':
+                    if (strcmp(op, "i64.div_s") == 0) { return makeBinary(s, BinaryOp::DivSInt64); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i64.div_u") == 0) { return makeBinary(s, BinaryOp::DivUInt64); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'e': {
+                switch (op[5]) {
+                  case 'q': {
+                    switch (op[6]) {
+                      case '\0':
+                        if (strcmp(op, "i64.eq") == 0) { return makeBinary(s, BinaryOp::EqInt64); }
+                        goto parse_error;
+                      case 'z':
+                        if (strcmp(op, "i64.eqz") == 0) { return makeUnary(s, UnaryOp::EqZInt64); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'x': {
+                    switch (op[10]) {
+                      case '1':
+                        if (strcmp(op, "i64.extend16_s") == 0) { return makeUnary(s, UnaryOp::ExtendS16Int64); }
+                        goto parse_error;
+                      case '3':
+                        if (strcmp(op, "i64.extend32_s") == 0) { return makeUnary(s, UnaryOp::ExtendS32Int64); }
+                        goto parse_error;
+                      case '8':
+                        if (strcmp(op, "i64.extend8_s") == 0) { return makeUnary(s, UnaryOp::ExtendS8Int64); }
+                        goto parse_error;
+                      case '_': {
+                        switch (op[15]) {
+                          case 's':
+                            if (strcmp(op, "i64.extend_i32_s") == 0) { return makeUnary(s, UnaryOp::ExtendSInt32); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i64.extend_i32_u") == 0) { return makeUnary(s, UnaryOp::ExtendUInt32); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              case 'g': {
+                switch (op[5]) {
+                  case 'e': {
+                    switch (op[7]) {
+                      case 's':
+                        if (strcmp(op, "i64.ge_s") == 0) { return makeBinary(s, BinaryOp::GeSInt64); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i64.ge_u") == 0) { return makeBinary(s, BinaryOp::GeUInt64); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case 't': {
+                    switch (op[7]) {
+                      case 's':
+                        if (strcmp(op, "i64.gt_s") == 0) { return makeBinary(s, BinaryOp::GtSInt64); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i64.gt_u") == 0) { return makeBinary(s, BinaryOp::GtUInt64); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              case 'l': {
+                switch (op[5]) {
+                  case 'e': {
+                    switch (op[7]) {
+                      case 's':
+                        if (strcmp(op, "i64.le_s") == 0) { return makeBinary(s, BinaryOp::LeSInt64); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i64.le_u") == 0) { return makeBinary(s, BinaryOp::LeUInt64); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'o': {
+                    switch (op[8]) {
+                      case '\0':
+                        if (strcmp(op, "i64.load") == 0) { return makeLoad(s, Type::i64, /*isAtomic=*/false); }
+                        goto parse_error;
+                      case '1': {
+                        switch (op[11]) {
+                          case 's':
+                            if (strcmp(op, "i64.load16_s") == 0) { return makeLoad(s, Type::i64, /*isAtomic=*/false); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i64.load16_u") == 0) { return makeLoad(s, Type::i64, /*isAtomic=*/false); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case '3': {
+                        switch (op[11]) {
+                          case 's':
+                            if (strcmp(op, "i64.load32_s") == 0) { return makeLoad(s, Type::i64, /*isAtomic=*/false); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i64.load32_u") == 0) { return makeLoad(s, Type::i64, /*isAtomic=*/false); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case '8': {
+                        switch (op[10]) {
+                          case 's':
+                            if (strcmp(op, "i64.load8_s") == 0) { return makeLoad(s, Type::i64, /*isAtomic=*/false); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i64.load8_u") == 0) { return makeLoad(s, Type::i64, /*isAtomic=*/false); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  case 't': {
+                    switch (op[7]) {
+                      case 's':
+                        if (strcmp(op, "i64.lt_s") == 0) { return makeBinary(s, BinaryOp::LtSInt64); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i64.lt_u") == 0) { return makeBinary(s, BinaryOp::LtUInt64); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              case 'm':
+                if (strcmp(op, "i64.mul") == 0) { return makeBinary(s, BinaryOp::MulInt64); }
+                goto parse_error;
+              case 'n':
+                if (strcmp(op, "i64.ne") == 0) { return makeBinary(s, BinaryOp::NeInt64); }
+                goto parse_error;
+              case 'o':
+                if (strcmp(op, "i64.or") == 0) { return makeBinary(s, BinaryOp::OrInt64); }
+                goto parse_error;
+              case 'p':
+                if (strcmp(op, "i64.popcnt") == 0) { return makeUnary(s, UnaryOp::PopcntInt64); }
+                goto parse_error;
+              case 'r': {
+                switch (op[5]) {
+                  case 'e': {
+                    switch (op[6]) {
+                      case 'i':
+                        if (strcmp(op, "i64.reinterpret_f64") == 0) { return makeUnary(s, UnaryOp::ReinterpretFloat64); }
+                        goto parse_error;
+                      case 'm': {
+                        switch (op[8]) {
+                          case 's':
+                            if (strcmp(op, "i64.rem_s") == 0) { return makeBinary(s, BinaryOp::RemSInt64); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i64.rem_u") == 0) { return makeBinary(s, BinaryOp::RemUInt64); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'o': {
+                    switch (op[7]) {
+                      case 'l':
+                        if (strcmp(op, "i64.rotl") == 0) { return makeBinary(s, BinaryOp::RotLInt64); }
+                        goto parse_error;
+                      case 'r':
+                        if (strcmp(op, "i64.rotr") == 0) { return makeBinary(s, BinaryOp::RotRInt64); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              case 's': {
+                switch (op[5]) {
+                  case 'h': {
+                    switch (op[6]) {
+                      case 'l':
+                        if (strcmp(op, "i64.shl") == 0) { return makeBinary(s, BinaryOp::ShlInt64); }
+                        goto parse_error;
+                      case 'r': {
+                        switch (op[8]) {
+                          case 's':
+                            if (strcmp(op, "i64.shr_s") == 0) { return makeBinary(s, BinaryOp::ShrSInt64); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i64.shr_u") == 0) { return makeBinary(s, BinaryOp::ShrUInt64); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  case 't': {
+                    switch (op[9]) {
+                      case '\0':
+                        if (strcmp(op, "i64.store") == 0) { return makeStore(s, Type::i64, /*isAtomic=*/false); }
+                        goto parse_error;
+                      case '1':
+                        if (strcmp(op, "i64.store16") == 0) { return makeStore(s, Type::i64, /*isAtomic=*/false); }
+                        goto parse_error;
+                      case '3':
+                        if (strcmp(op, "i64.store32") == 0) { return makeStore(s, Type::i64, /*isAtomic=*/false); }
+                        goto parse_error;
+                      case '8':
+                        if (strcmp(op, "i64.store8") == 0) { return makeStore(s, Type::i64, /*isAtomic=*/false); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'u':
+                    if (strcmp(op, "i64.sub") == 0) { return makeBinary(s, BinaryOp::SubInt64); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 't': {
+                switch (op[10]) {
+                  case 'f': {
+                    switch (op[11]) {
+                      case '3': {
+                        switch (op[14]) {
+                          case 's':
+                            if (strcmp(op, "i64.trunc_f32_s") == 0) { return makeUnary(s, UnaryOp::TruncSFloat32ToInt64); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i64.trunc_f32_u") == 0) { return makeUnary(s, UnaryOp::TruncUFloat32ToInt64); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case '6': {
+                        switch (op[14]) {
+                          case 's':
+                            if (strcmp(op, "i64.trunc_f64_s") == 0) { return makeUnary(s, UnaryOp::TruncSFloat64ToInt64); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i64.trunc_f64_u") == 0) { return makeUnary(s, UnaryOp::TruncUFloat64ToInt64); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  case 's': {
+                    switch (op[15]) {
+                      case '3': {
+                        switch (op[18]) {
+                          case 's':
+                            if (strcmp(op, "i64.trunc_sat_f32_s") == 0) { return makeUnary(s, UnaryOp::TruncSatSFloat32ToInt64); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i64.trunc_sat_f32_u") == 0) { return makeUnary(s, UnaryOp::TruncSatUFloat32ToInt64); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case '6': {
+                        switch (op[18]) {
+                          case 's':
+                            if (strcmp(op, "i64.trunc_sat_f64_s") == 0) { return makeUnary(s, UnaryOp::TruncSatSFloat64ToInt64); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i64.trunc_sat_f64_u") == 0) { return makeUnary(s, UnaryOp::TruncSatUFloat64ToInt64); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              case 'x':
+                if (strcmp(op, "i64.xor") == 0) { return makeBinary(s, BinaryOp::XorInt64); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          case 'x': {
+            switch (op[6]) {
+              case 'a': {
+                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); }
+                    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':
+                    if (strcmp(op, "i64x2.load32x2_s") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadExtSVec32x2ToVecI64x2); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i64x2.load32x2_u") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadExtUVec32x2ToVecI64x2); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'm':
+                if (strcmp(op, "i64x2.mul") == 0) { return makeBinary(s, BinaryOp::MulVecI64x2); }
+                goto parse_error;
+              case 'n':
+                if (strcmp(op, "i64x2.neg") == 0) { return makeUnary(s, UnaryOp::NegVecI64x2); }
+                goto parse_error;
+              case 'r':
+                if (strcmp(op, "i64x2.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecI64x2, 2); }
+                goto parse_error;
+              case 's': {
+                switch (op[7]) {
+                  case 'h': {
+                    switch (op[8]) {
+                      case 'l':
+                        if (strcmp(op, "i64x2.shl") == 0) { return makeSIMDShift(s, SIMDShiftOp::ShlVecI64x2); }
+                        goto parse_error;
+                      case 'r': {
+                        switch (op[10]) {
+                          case 's':
+                            if (strcmp(op, "i64x2.shr_s") == 0) { return makeSIMDShift(s, SIMDShiftOp::ShrSVecI64x2); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i64x2.shr_u") == 0) { return makeSIMDShift(s, SIMDShiftOp::ShrUVecI64x2); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'p':
+                    if (strcmp(op, "i64x2.splat") == 0) { return makeUnary(s, UnaryOp::SplatVecI64x2); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i64x2.sub") == 0) { return makeBinary(s, BinaryOp::SubVecI64x2); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 't': {
+                switch (op[22]) {
+                  case 's':
+                    if (strcmp(op, "i64x2.trunc_sat_f64x2_s") == 0) { return makeUnary(s, UnaryOp::TruncSatSVecF64x2ToVecI64x2); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i64x2.trunc_sat_f64x2_u") == 0) { return makeUnary(s, UnaryOp::TruncSatUVecF64x2ToVecI64x2); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          default: goto parse_error;
+        }
+      }
+      case '8': {
+        switch (op[6]) {
+          case 'a': {
+            switch (op[7]) {
+              case 'b':
+                if (strcmp(op, "i8x16.abs") == 0) { return makeUnary(s, UnaryOp::AbsVecI8x16); }
+                goto parse_error;
+              case 'd': {
+                switch (op[9]) {
+                  case '\0':
+                    if (strcmp(op, "i8x16.add") == 0) { return makeBinary(s, BinaryOp::AddVecI8x16); }
+                    goto parse_error;
+                  case '_': {
+                    switch (op[19]) {
+                      case 's':
+                        if (strcmp(op, "i8x16.add_saturate_s") == 0) { return makeBinary(s, BinaryOp::AddSatSVecI8x16); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i8x16.add_saturate_u") == 0) { return makeBinary(s, BinaryOp::AddSatUVecI8x16); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              case 'l':
+                if (strcmp(op, "i8x16.all_true") == 0) { return makeUnary(s, UnaryOp::AllTrueVecI8x16); }
+                goto parse_error;
+              case 'n':
+                if (strcmp(op, "i8x16.any_true") == 0) { return makeUnary(s, UnaryOp::AnyTrueVecI8x16); }
+                goto parse_error;
+              case 'v':
+                if (strcmp(op, "i8x16.avgr_u") == 0) { return makeBinary(s, BinaryOp::AvgrUVecI8x16); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          case 'b':
+            if (strcmp(op, "i8x16.bitmask") == 0) { return makeUnary(s, UnaryOp::BitmaskVecI8x16); }
+            goto parse_error;
+          case 'e': {
+            switch (op[7]) {
+              case 'q':
+                if (strcmp(op, "i8x16.eq") == 0) { return makeBinary(s, BinaryOp::EqVecI8x16); }
+                goto parse_error;
+              case 'x': {
+                switch (op[19]) {
+                  case 's':
+                    if (strcmp(op, "i8x16.extract_lane_s") == 0) { return makeSIMDExtract(s, SIMDExtractOp::ExtractLaneSVecI8x16, 16); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i8x16.extract_lane_u") == 0) { return makeSIMDExtract(s, SIMDExtractOp::ExtractLaneUVecI8x16, 16); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          case 'g': {
+            switch (op[7]) {
+              case 'e': {
+                switch (op[9]) {
+                  case 's':
+                    if (strcmp(op, "i8x16.ge_s") == 0) { return makeBinary(s, BinaryOp::GeSVecI8x16); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i8x16.ge_u") == 0) { return makeBinary(s, BinaryOp::GeUVecI8x16); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 't': {
+                switch (op[9]) {
+                  case 's':
+                    if (strcmp(op, "i8x16.gt_s") == 0) { return makeBinary(s, BinaryOp::GtSVecI8x16); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i8x16.gt_u") == 0) { return makeBinary(s, BinaryOp::GtUVecI8x16); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          case 'l': {
+            switch (op[7]) {
+              case 'e': {
+                switch (op[9]) {
+                  case 's':
+                    if (strcmp(op, "i8x16.le_s") == 0) { return makeBinary(s, BinaryOp::LeSVecI8x16); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i8x16.le_u") == 0) { return makeBinary(s, BinaryOp::LeUVecI8x16); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 't': {
+                switch (op[9]) {
+                  case 's':
+                    if (strcmp(op, "i8x16.lt_s") == 0) { return makeBinary(s, BinaryOp::LtSVecI8x16); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i8x16.lt_u") == 0) { return makeBinary(s, BinaryOp::LtUVecI8x16); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          case 'm': {
+            switch (op[7]) {
+              case 'a': {
+                switch (op[10]) {
+                  case 's':
+                    if (strcmp(op, "i8x16.max_s") == 0) { return makeBinary(s, BinaryOp::MaxSVecI8x16); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i8x16.max_u") == 0) { return makeBinary(s, BinaryOp::MaxUVecI8x16); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'i': {
+                switch (op[10]) {
+                  case 's':
+                    if (strcmp(op, "i8x16.min_s") == 0) { return makeBinary(s, BinaryOp::MinSVecI8x16); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i8x16.min_u") == 0) { return makeBinary(s, BinaryOp::MinUVecI8x16); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'u':
+                if (strcmp(op, "i8x16.mul") == 0) { return makeBinary(s, BinaryOp::MulVecI8x16); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          case 'n': {
+            switch (op[7]) {
+              case 'a': {
+                switch (op[19]) {
+                  case 's':
+                    if (strcmp(op, "i8x16.narrow_i16x8_s") == 0) { return makeBinary(s, BinaryOp::NarrowSVecI16x8ToVecI8x16); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "i8x16.narrow_i16x8_u") == 0) { return makeBinary(s, BinaryOp::NarrowUVecI16x8ToVecI8x16); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'e': {
+                switch (op[8]) {
+                  case '\0':
+                    if (strcmp(op, "i8x16.ne") == 0) { return makeBinary(s, BinaryOp::NeVecI8x16); }
+                    goto parse_error;
+                  case 'g':
+                    if (strcmp(op, "i8x16.neg") == 0) { return makeUnary(s, UnaryOp::NegVecI8x16); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          case 'r':
+            if (strcmp(op, "i8x16.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecI8x16, 16); }
+            goto parse_error;
+          case 's': {
+            switch (op[7]) {
+              case 'h': {
+                switch (op[8]) {
+                  case 'l':
+                    if (strcmp(op, "i8x16.shl") == 0) { return makeSIMDShift(s, SIMDShiftOp::ShlVecI8x16); }
+                    goto parse_error;
+                  case 'r': {
+                    switch (op[10]) {
+                      case 's':
+                        if (strcmp(op, "i8x16.shr_s") == 0) { return makeSIMDShift(s, SIMDShiftOp::ShrSVecI8x16); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i8x16.shr_u") == 0) { return makeSIMDShift(s, SIMDShiftOp::ShrUVecI8x16); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              case 'p':
+                if (strcmp(op, "i8x16.splat") == 0) { return makeUnary(s, UnaryOp::SplatVecI8x16); }
+                goto parse_error;
+              case 'u': {
+                switch (op[9]) {
+                  case '\0':
+                    if (strcmp(op, "i8x16.sub") == 0) { return makeBinary(s, BinaryOp::SubVecI8x16); }
+                    goto parse_error;
+                  case '_': {
+                    switch (op[19]) {
+                      case 's':
+                        if (strcmp(op, "i8x16.sub_saturate_s") == 0) { return makeBinary(s, BinaryOp::SubSatSVecI8x16); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i8x16.sub_saturate_u") == 0) { return makeBinary(s, BinaryOp::SubSatUVecI8x16); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          default: goto parse_error;
+        }
+      }
+      case 'f':
+        if (strcmp(op, "if") == 0) { return makeIf(s); }
+        goto parse_error;
+      default: goto parse_error;
+    }
+  }
+  case 'l': {
+    switch (op[2]) {
+      case 'c': {
+        switch (op[6]) {
+          case 'g':
+            if (strcmp(op, "local.get") == 0) { return makeLocalGet(s); }
+            goto parse_error;
+          case 's':
+            if (strcmp(op, "local.set") == 0) { return makeLocalSet(s); }
+            goto parse_error;
+          case 't':
+            if (strcmp(op, "local.tee") == 0) { return makeLocalTee(s); }
+            goto parse_error;
+          default: goto parse_error;
+        }
+      }
+      case 'o':
+        if (strcmp(op, "loop") == 0) { return makeLoop(s); }
+        goto parse_error;
+      default: goto parse_error;
+    }
+  }
+  case 'm': {
+    switch (op[7]) {
+      case 'c':
+        if (strcmp(op, "memory.copy") == 0) { return makeMemoryCopy(s); }
+        goto parse_error;
+      case 'f':
+        if (strcmp(op, "memory.fill") == 0) { return makeMemoryFill(s); }
+        goto parse_error;
+      case 'g':
+        if (strcmp(op, "memory.grow") == 0) { return makeMemoryGrow(s); }
+        goto parse_error;
+      case 'i':
+        if (strcmp(op, "memory.init") == 0) { return makeMemoryInit(s); }
+        goto parse_error;
+      case 's':
+        if (strcmp(op, "memory.size") == 0) { return makeMemorySize(s); }
+        goto parse_error;
+      default: goto parse_error;
+    }
+  }
+  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 'r': {
+    switch (op[1]) {
+      case 'e': {
+        switch (op[2]) {
+          case 'f': {
+            switch (op[4]) {
+              case 'c':
+                if (strcmp(op, "ref.cast") == 0) { return makeRefCast(s); }
+                goto parse_error;
+              case 'e':
+                if (strcmp(op, "ref.eq") == 0) { return makeRefEq(s); }
+                goto parse_error;
+              case 'f':
+                if (strcmp(op, "ref.func") == 0) { return makeRefFunc(s); }
+                goto parse_error;
+              case 'i':
+                if (strcmp(op, "ref.is_null") == 0) { return makeRefIsNull(s); }
+                goto parse_error;
+              case 'n':
+                if (strcmp(op, "ref.null") == 0) { return makeRefNull(s); }
+                goto parse_error;
+              case 't':
+                if (strcmp(op, "ref.test") == 0) { return makeRefTest(s); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          case 't': {
+            switch (op[3]) {
+              case 'h':
+                if (strcmp(op, "rethrow") == 0) { return makeRethrow(s); }
+                goto parse_error;
+              case 'u': {
+                switch (op[6]) {
+                  case '\0':
+                    if (strcmp(op, "return") == 0) { return makeReturn(s); }
+                    goto parse_error;
+                  case '_': {
+                    switch (op[11]) {
+                      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;
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          default: goto parse_error;
+        }
+      }
+      case 't': {
+        switch (op[4]) {
+          case 'c':
+            if (strcmp(op, "rtt.canon") == 0) { return makeRttCanon(s); }
+            goto parse_error;
+          case 's':
+            if (strcmp(op, "rtt.sub") == 0) { return makeRttSub(s); }
+            goto parse_error;
+          default: goto parse_error;
+        }
+      }
+      default: goto parse_error;
+    }
+  }
+  case 's': {
+    switch (op[1]) {
+      case 'e':
+        if (strcmp(op, "select") == 0) { return makeSelect(s); }
+        goto parse_error;
+      case 't': {
+        switch (op[7]) {
+          case 'g': {
+            switch (op[10]) {
+              case '\0':
+                if (strcmp(op, "struct.get") == 0) { return makeStructGet(s); }
+                goto parse_error;
+              case '_': {
+                switch (op[11]) {
+                  case 's':
+                    if (strcmp(op, "struct.get_s") == 0) { return makeStructGet(s, true); }
+                    goto parse_error;
+                  case 'u':
+                    if (strcmp(op, "struct.get_u") == 0) { return makeStructGet(s, false); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              default: goto parse_error;
+            }
+          }
+          case 'n': {
+            switch (op[11]) {
+              case 'd':
+                if (strcmp(op, "struct.new_default_with_rtt") == 0) { return makeStructNew(s, true); }
+                goto parse_error;
+              case 'w':
+                if (strcmp(op, "struct.new_with_rtt") == 0) { return makeStructNew(s, false); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          case 's':
+            if (strcmp(op, "struct.set") == 0) { return makeStructSet(s); }
+            goto parse_error;
+          default: goto parse_error;
+        }
+      }
+      default: goto parse_error;
+    }
+  }
+  case 't': {
+    switch (op[1]) {
+      case 'h': {
+        switch (op[2]) {
+          case 'e':
+            if (strcmp(op, "then") == 0) { return makeThenOrElse(s); }
+            goto parse_error;
+          case 'r':
+            if (strcmp(op, "throw") == 0) { return makeThrow(s); }
+            goto parse_error;
+          default: goto parse_error;
+        }
+      }
+      case 'r':
+        if (strcmp(op, "try") == 0) { return makeTry(s); }
+        goto parse_error;
+      case 'u': {
+        switch (op[6]) {
+          case 'e':
+            if (strcmp(op, "tuple.extract") == 0) { return makeTupleExtract(s); }
+            goto parse_error;
+          case 'm':
+            if (strcmp(op, "tuple.make") == 0) { return makeTupleMake(s); }
+            goto parse_error;
+          default: goto parse_error;
+        }
+      }
+      default: goto parse_error;
+    }
+  }
+  case 'u':
+    if (strcmp(op, "unreachable") == 0) { return makeUnreachable(); }
+    goto parse_error;
+  case 'v': {
+    switch (op[1]) {
+      case '1': {
+        switch (op[2]) {
+          case '2': {
+            switch (op[5]) {
+              case 'a': {
+                switch (op[8]) {
+                  case '\0':
+                    if (strcmp(op, "v128.and") == 0) { return makeBinary(s, BinaryOp::AndVec128); }
+                    goto parse_error;
+                  case 'n':
+                    if (strcmp(op, "v128.andnot") == 0) { return makeBinary(s, BinaryOp::AndNotVec128); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'b':
+                if (strcmp(op, "v128.bitselect") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::Bitselect); }
+                goto parse_error;
+              case 'c':
+                if (strcmp(op, "v128.const") == 0) { return makeConst(s, Type::v128); }
+                goto parse_error;
+              case 'l': {
+                switch (op[9]) {
+                  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); }
+                    goto parse_error;
+                  case '6':
+                    if (strcmp(op, "v128.load64_zero") == 0) { return makeSIMDLoad(s, SIMDLoadOp::Load64Zero); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
+              case 'n':
+                if (strcmp(op, "v128.not") == 0) { return makeUnary(s, UnaryOp::NotVec128); }
+                goto parse_error;
+              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 '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); }
+            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 '8': {
+        switch (op[6]) {
+          case 'l':
+            if (strcmp(op, "v8x16.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec8x16); }
+            goto parse_error;
+          case 's': {
+            switch (op[7]) {
+              case 'h':
+                if (strcmp(op, "v8x16.shuffle") == 0) { return makeSIMDShuffle(s); }
+                goto parse_error;
+              case 'w':
+                if (strcmp(op, "v8x16.swizzle") == 0) { return makeBinary(s, BinaryOp::SwizzleVec8x16); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          default: goto parse_error;
+        }
+      }
+      default: goto parse_error;
+    }
+  }
+  default: goto parse_error;
+}
+parse_error:
+  throw ParseException(std::string(op), s.line, s.col);
+#endif // INSTRUCTION_PARSER
+
+// clang-format on
diff --git a/binaryen/src/ir/CMakeLists.txt b/binaryen/src/ir/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/CMakeLists.txt
@@ -0,0 +1,10 @@
+FILE(GLOB ir_HEADERS *.h)
+set(ir_SOURCES
+  ExpressionAnalyzer.cpp
+  ExpressionManipulator.cpp
+  LocalGraph.cpp
+  ReFinalize.cpp
+  stack-utils.cpp
+  ${ir_HEADERS}
+)
+add_library(ir OBJECT ${ir_SOURCES})
diff --git a/binaryen/src/ir/ExpressionAnalyzer.cpp b/binaryen/src/ir/ExpressionAnalyzer.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/ExpressionAnalyzer.cpp
@@ -0,0 +1,525 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/iteration.h"
+#include "ir/load-utils.h"
+#include "ir/utils.h"
+#include "support/hash.h"
+#include "support/small_vector.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
+
+namespace wasm {
+
+// Given a stack of expressions, checks if the topmost is used as a result.
+// For example, if the parent is a block and the node is before the last
+// position, it is not used.
+bool ExpressionAnalyzer::isResultUsed(ExpressionStack& stack, Function* func) {
+  for (int i = int(stack.size()) - 2; i >= 0; i--) {
+    auto* curr = stack[i];
+    auto* above = stack[i + 1];
+    // only if and block can drop values (pre-drop expression was added) FIXME
+    if (curr->is<Block>()) {
+      auto* block = curr->cast<Block>();
+      for (size_t j = 0; j < block->list.size() - 1; j++) {
+        if (block->list[j] == above) {
+          return false;
+        }
+      }
+      assert(block->list.back() == above);
+      // continue down
+    } else if (curr->is<If>()) {
+      auto* iff = curr->cast<If>();
+      if (above == iff->condition) {
+        return true;
+      }
+      if (!iff->ifFalse) {
+        return false;
+      }
+      assert(above == iff->ifTrue || above == iff->ifFalse);
+      // continue down
+    } else {
+      if (curr->is<Drop>()) {
+        return false;
+      }
+      return true; // all other node types use the result
+    }
+  }
+  // The value might be used, so it depends on if the function returns
+  return func->sig.results != Type::none;
+}
+
+// Checks if a value is dropped.
+bool ExpressionAnalyzer::isResultDropped(ExpressionStack& stack) {
+  for (int i = int(stack.size()) - 2; i >= 0; i--) {
+    auto* curr = stack[i];
+    auto* above = stack[i + 1];
+    if (curr->is<Block>()) {
+      auto* block = curr->cast<Block>();
+      for (size_t j = 0; j < block->list.size() - 1; j++) {
+        if (block->list[j] == above) {
+          return false;
+        }
+      }
+      assert(block->list.back() == above);
+      // continue down
+    } else if (curr->is<If>()) {
+      auto* iff = curr->cast<If>();
+      if (above == iff->condition) {
+        return false;
+      }
+      if (!iff->ifFalse) {
+        return false;
+      }
+      assert(above == iff->ifTrue || above == iff->ifFalse);
+      // continue down
+    } else {
+      if (curr->is<Drop>()) {
+        return true; // dropped
+      }
+      return false; // all other node types use the result
+    }
+  }
+  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) {
+  struct Comparer {
+    // for each name on the left, the corresponding name on the right
+    std::map<Name, Name> rightNames;
+    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;
+      }
+      if (left.is()) {
+        assert(rightNames.find(left) == rightNames.end());
+        rightNames[left] = right;
+      }
+      return true;
+    }
+
+    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();
+
+      leftStack.push_back(left);
+      rightStack.push_back(right);
+
+      while (leftStack.size() > 0 && rightStack.size() > 0) {
+        left = leftStack.back();
+        leftStack.pop_back();
+        right = rightStack.back();
+        rightStack.pop_back();
+        if (!left != !right) {
+          return false;
+        }
+        if (!left) {
+          continue;
+        }
+        if (comparer(left, right)) {
+          continue; // comparison hook, before all the rest
+        }
+        // continue with normal structural comparison
+        if (left->_id != right->_id) {
+          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) {
+          return false;
+        }
+      }
+      if (leftStack.size() > 0 || rightStack.size() > 0) {
+        return false;
+      }
+      return true;
+    }
+  };
+
+  return Comparer().compare(left, right, comparer);
+}
+
+// hash an expression, ignoring superficial details like specific internal names
+size_t ExpressionAnalyzer::hash(Expression* curr) {
+  struct Hasher {
+    size_t digest = wasm::hash(0);
+
+    Index internalCounter = 0;
+    // for each internal name, its unique id
+    std::map<Name, Index> internalNames;
+    ExpressionStack stack;
+
+    void noteScopeName(Name curr) {
+      if (curr.is()) {
+        internalNames[curr] = internalCounter++;
+      }
+    }
+
+    Hasher(Expression* curr) {
+      stack.push_back(curr);
+
+      while (stack.size() > 0) {
+        curr = stack.back();
+        stack.pop_back();
+        if (!curr) {
+          continue;
+        }
+        rehash(digest, curr->_id);
+        // we often don't need to hash the type, as it is tied to other values
+        // we are hashing anyhow, but there are exceptions: for example, a
+        // local.get's type is determined by the function, so if we are
+        // hashing only expression fragments, then two from different
+        // functions may turn out the same even if the type differs. Likewise,
+        // if we hash between modules, then we need to take int account
+        // 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);
+      }
+    }
+
+    void visitScopeName(Name curr) {
+      // Names are relative, we give the same hash for
+      // (block $x (br $x))
+      // (block $y (br $y))
+      static_assert(sizeof(Index) == sizeof(int32_t),
+                    "wasm64 will need changes here");
+      assert(internalNames.find(curr) != internalNames.end());
+      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); }
+  };
+
+  return Hasher(curr).digest;
+}
+
+} // namespace wasm
diff --git a/binaryen/src/ir/ExpressionManipulator.cpp b/binaryen/src/ir/ExpressionManipulator.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/ExpressionManipulator.cpp
@@ -0,0 +1,338 @@
+/*
+ * 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.
+ */
+
+#include "ir/load-utils.h"
+#include "ir/utils.h"
+
+namespace wasm {
+
+namespace ExpressionManipulator {
+
+Expression*
+flexibleCopy(Expression* original, Module& wasm, CustomCopier custom) {
+  struct Copier : public OverriddenVisitor<Copier, Expression*> {
+    Module& wasm;
+    CustomCopier custom;
+
+    Builder builder;
+
+    Copier(Module& wasm, CustomCopier custom)
+      : wasm(wasm), custom(custom), builder(wasm) {}
+
+    Expression* copy(Expression* curr) {
+      if (!curr) {
+        return nullptr;
+      }
+      auto* ret = custom(curr);
+      if (ret) {
+        return ret;
+      }
+      return OverriddenVisitor<Copier, Expression*>::visit(curr);
+    }
+
+    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");
+    }
+  };
+
+  Copier copier(wasm, custom);
+  return copier.copy(original);
+}
+
+// Splice an item into the middle of a block's list
+void spliceIntoBlock(Block* block, Index index, Expression* add) {
+  auto& list = block->list;
+  if (index == list.size()) {
+    list.push_back(add); // simple append
+  } else {
+    // we need to make room
+    list.push_back(nullptr);
+    for (Index i = list.size() - 1; i > index; i--) {
+      list[i] = list[i - 1];
+    }
+    list[index] = add;
+  }
+  block->finalize(block->type);
+}
+
+} // namespace ExpressionManipulator
+
+} // namespace wasm
diff --git a/binaryen/src/ir/LocalGraph.cpp b/binaryen/src/ir/LocalGraph.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/LocalGraph.cpp
@@ -0,0 +1,296 @@
+/*
+ * 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.
+ */
+
+#include <iterator>
+
+#include <cfg/cfg-traversal.h>
+#include <ir/find_all.h>
+#include <ir/local-graph.h>
+#include <wasm-builder.h>
+#include <wasm-printing.h>
+
+namespace wasm {
+
+namespace LocalGraphInternal {
+
+// Information about a basic block.
+struct Info {
+  // actions occurring in this block: local.gets and local.sets
+  std::vector<Expression*> actions;
+  // for each index, the last local.set for it
+  std::unordered_map<Index, LocalSet*> lastSets;
+};
+
+// flow helper class. flows the gets to their sets
+
+struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
+  LocalGraph::GetSetses& getSetses;
+  LocalGraph::Locations& locations;
+
+  Flower(LocalGraph::GetSetses& getSetses,
+         LocalGraph::Locations& locations,
+         Function* func)
+    : getSetses(getSetses), locations(locations) {
+    setFunction(func);
+    // create the CFG by walking the IR
+    CFGWalker<Flower, Visitor<Flower>, Info>::doWalkFunction(func);
+    // flow gets across blocks
+    flow(func);
+  }
+
+  BasicBlock* makeBasicBlock() { return new BasicBlock(); }
+
+  // cfg traversal work
+
+  static void doVisitLocalGet(Flower* self, Expression** currp) {
+    auto* curr = (*currp)->cast<LocalGet>();
+    // if in unreachable code, skip
+    if (!self->currBasicBlock) {
+      return;
+    }
+    self->currBasicBlock->contents.actions.emplace_back(curr);
+    self->locations[curr] = currp;
+  }
+
+  static void doVisitLocalSet(Flower* self, Expression** currp) {
+    auto* curr = (*currp)->cast<LocalSet>();
+    // if in unreachable code, skip
+    if (!self->currBasicBlock) {
+      return;
+    }
+    self->currBasicBlock->contents.actions.emplace_back(curr);
+    self->currBasicBlock->contents.lastSets[curr->index] = curr;
+    self->locations[curr] = currp;
+  }
+
+  void flow(Function* func) {
+    // This block struct is optimized for this flow process (Minimal
+    // information, iteration index).
+    struct FlowBlock {
+      // Last Traversed Iteration: This value helps us to find if this block has
+      // been seen while traversing blocks. We compare this value to the current
+      // iteration index in order to determine if we already process this block
+      // in the current iteration. This speeds up the processing compared to
+      // unordered_set or other struct usage. (No need to reset internal values,
+      // lookup into container, ...)
+      size_t lastTraversedIteration;
+      std::vector<Expression*> actions;
+      std::vector<FlowBlock*> in;
+      // Sor each index, the last local.set for it
+      // The unordered_map from BasicBlock.Info is converted into a vector
+      // This speeds up search as there are usually few sets in a block, so just
+      // scanning them linearly is efficient, avoiding hash computations (while
+      // in Info, it's convenient to have a map so we can assign them easily,
+      // where the last one seen overwrites the previous; and, we do that O(1)).
+      std::vector<std::pair<Index, LocalSet*>> lastSets;
+    };
+
+    auto numLocals = func->getNumLocals();
+    std::vector<std::vector<LocalGet*>> allGets;
+    allGets.resize(numLocals);
+    std::vector<FlowBlock*> work;
+
+    // Convert input blocks (basicBlocks) into more efficient flow blocks to
+    // improve memory access.
+    std::vector<FlowBlock> flowBlocks;
+    flowBlocks.resize(basicBlocks.size());
+
+    // Init mapping between basicblocks and flowBlocks
+    std::unordered_map<BasicBlock*, FlowBlock*> basicToFlowMap;
+    for (Index i = 0; i < basicBlocks.size(); ++i) {
+      basicToFlowMap[basicBlocks[i].get()] = &flowBlocks[i];
+    }
+
+    const size_t NULL_ITERATION = -1;
+
+    FlowBlock* entryFlowBlock = nullptr;
+    for (Index i = 0; i < flowBlocks.size(); ++i) {
+      auto& block = basicBlocks[i];
+      auto& flowBlock = flowBlocks[i];
+      // Get the equivalent block to entry in the flow list
+      if (block.get() == entry) {
+        entryFlowBlock = &flowBlock;
+      }
+      flowBlock.lastTraversedIteration = NULL_ITERATION;
+      flowBlock.actions.swap(block->contents.actions);
+      // Map in block to flow blocks
+      auto& in = block->in;
+      flowBlock.in.resize(in.size());
+      std::transform(in.begin(),
+                     in.end(),
+                     flowBlock.in.begin(),
+                     [&](BasicBlock* block) { return basicToFlowMap[block]; });
+      // Convert unordered_map to vector.
+      flowBlock.lastSets.reserve(block->contents.lastSets.size());
+      for (auto set : block->contents.lastSets) {
+        flowBlock.lastSets.emplace_back(std::make_pair(set.first, set.second));
+      }
+    }
+    assert(entryFlowBlock != nullptr);
+
+    size_t currentIteration = 0;
+    for (auto& block : flowBlocks) {
+#ifdef LOCAL_GRAPH_DEBUG
+      std::cout << "basic block " << block.get() << " :\n";
+      for (auto& action : block->contents.actions) {
+        std::cout << "  action: " << *action << '\n';
+      }
+      for (auto* lastSet : block->contents.lastSets) {
+        std::cout << "  last set " << lastSet << '\n';
+      }
+#endif
+      // go through the block, finding each get and adding it to its index,
+      // and seeing how sets affect that
+      auto& actions = block.actions;
+      // move towards the front, handling things as we go
+      for (int i = int(actions.size()) - 1; i >= 0; i--) {
+        auto* action = actions[i];
+        if (auto* get = action->dynCast<LocalGet>()) {
+          allGets[get->index].push_back(get);
+        } else {
+          // This set is the only set for all those gets.
+          auto* set = action->cast<LocalSet>();
+          auto& gets = allGets[set->index];
+          for (auto* get : gets) {
+            getSetses[get].insert(set);
+          }
+          gets.clear();
+        }
+      }
+      // If anything is left, we must flow it back through other blocks. we
+      // can do that for all gets as a whole, they will get the same results.
+      for (Index index = 0; index < numLocals; index++) {
+        auto& gets = allGets[index];
+        if (gets.empty()) {
+          continue;
+        }
+        work.push_back(&block);
+        // Note that we may need to revisit the later parts of this initial
+        // block, if we are in a loop, so don't mark it as seen.
+        while (!work.empty()) {
+          auto* curr = work.back();
+          work.pop_back();
+          // We have gone through this block; now we must handle flowing to
+          // the inputs.
+          if (curr->in.empty()) {
+            if (curr == entryFlowBlock) {
+              // These receive a param or zero init value.
+              for (auto* get : gets) {
+                getSetses[get].insert(nullptr);
+              }
+            }
+          } else {
+            for (auto* pred : curr->in) {
+              if (pred->lastTraversedIteration == currentIteration) {
+                // We've already seen pred in this iteration.
+                continue;
+              }
+              pred->lastTraversedIteration = currentIteration;
+              auto lastSet =
+                std::find_if(pred->lastSets.begin(),
+                             pred->lastSets.end(),
+                             [&](std::pair<Index, LocalSet*>& value) {
+                               return value.first == index;
+                             });
+              if (lastSet != pred->lastSets.end()) {
+                // There is a set here, apply it, and stop the flow.
+                for (auto* get : gets) {
+                  getSetses[get].insert(lastSet->second);
+                }
+              } else {
+                // Keep on flowing.
+                work.push_back(pred);
+              }
+            }
+          }
+        }
+        gets.clear();
+        currentIteration++;
+      }
+    }
+  }
+};
+
+} // namespace LocalGraphInternal
+
+// LocalGraph implementation
+
+LocalGraph::LocalGraph(Function* func) {
+  LocalGraphInternal::Flower flower(getSetses, locations, func);
+
+#ifdef LOCAL_GRAPH_DEBUG
+  std::cout << "LocalGraph::dump\n";
+  for (auto& pair : getSetses) {
+    auto* get = pair.first;
+    auto& sets = pair.second;
+    std::cout << "GET\n" << get << " is influenced by\n";
+    for (auto* set : sets) {
+      std::cout << set << '\n';
+    }
+  }
+  std::cout << "total locations: " << locations.size() << '\n';
+#endif
+}
+
+void LocalGraph::computeInfluences() {
+  for (auto& pair : locations) {
+    auto* curr = pair.first;
+    if (auto* set = curr->dynCast<LocalSet>()) {
+      FindAll<LocalGet> findAll(set->value);
+      for (auto* get : findAll.list) {
+        getInfluences[get].insert(set);
+      }
+    } else {
+      auto* get = curr->cast<LocalGet>();
+      for (auto* set : getSetses[get]) {
+        setInfluences[set].insert(get);
+      }
+    }
+  }
+}
+
+void LocalGraph::computeSSAIndexes() {
+  std::unordered_map<Index, std::set<LocalSet*>> indexSets;
+  for (auto& pair : getSetses) {
+    auto* get = pair.first;
+    auto& sets = pair.second;
+    for (auto* set : sets) {
+      indexSets[get->index].insert(set);
+    }
+  }
+  for (auto& pair : locations) {
+    auto* curr = pair.first;
+    if (auto* set = curr->dynCast<LocalSet>()) {
+      auto& sets = indexSets[set->index];
+      if (sets.size() == 1 && *sets.begin() != curr) {
+        // While it has just one set, it is not the right one (us),
+        // so mark it invalid.
+        sets.clear();
+      }
+    }
+  }
+  for (auto& pair : indexSets) {
+    auto index = pair.first;
+    auto& sets = pair.second;
+    if (sets.size() == 1) {
+      SSAIndexes.insert(index);
+    }
+  }
+}
+
+bool LocalGraph::isSSA(Index x) { return SSAIndexes.count(x); }
+
+} // namespace wasm
diff --git a/binaryen/src/ir/ReFinalize.cpp b/binaryen/src/ir/ReFinalize.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/ReFinalize.cpp
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ */
+
+#include "ir/branch-utils.h"
+#include "ir/find_all.h"
+#include "ir/utils.h"
+
+namespace wasm {
+
+static Type getValueType(Expression* value) {
+  return value ? value->type : Type::none;
+}
+
+namespace {
+
+// Handles a branch fixup for visitBlock: if the branch goes to the
+// target name, give it a value which is unreachable.
+template<typename T>
+void handleBranchForVisitBlock(T* curr, Name name, Module* module) {
+  if (BranchUtils::getUniqueTargets(curr).count(name)) {
+    assert(!curr->value);
+    Builder builder(*module);
+    curr->value = builder.makeUnreachable();
+  }
+}
+
+} // anonymous namespace
+
+void ReFinalize::visitBlock(Block* curr) {
+  if (curr->list.size() == 0) {
+    curr->type = Type::none;
+    return;
+  }
+  // Get the least upper bound type of the last element and all branch return
+  // values
+  curr->type = curr->list.back()->type;
+  if (curr->name.is()) {
+    auto iter = breakValues.find(curr->name);
+    if (iter != breakValues.end()) {
+      curr->type = Type::getLeastUpperBound(curr->type, iter->second);
+      return;
+    }
+  }
+  if (curr->type == Type::unreachable) {
+    return;
+  }
+  // type is none, but we might be unreachable
+  if (curr->type == Type::none) {
+    for (auto* child : curr->list) {
+      if (child->type == Type::unreachable) {
+        curr->type = Type::unreachable;
+        break;
+      }
+    }
+  }
+}
+void ReFinalize::visitIf(If* curr) { curr->finalize(); }
+void ReFinalize::visitLoop(Loop* curr) { curr->finalize(); }
+void ReFinalize::visitBreak(Break* curr) {
+  curr->finalize();
+  auto valueType = getValueType(curr->value);
+  if (valueType == Type::unreachable) {
+    replaceUntaken(curr->value, curr->condition);
+  } else {
+    updateBreakValueType(curr->name, valueType);
+  }
+}
+void ReFinalize::visitSwitch(Switch* curr) {
+  curr->finalize();
+  auto valueType = getValueType(curr->value);
+  if (valueType == Type::unreachable) {
+    replaceUntaken(curr->value, curr->condition);
+  } else {
+    for (auto target : curr->targets) {
+      updateBreakValueType(target, valueType);
+    }
+    updateBreakValueType(curr->default_, valueType);
+  }
+}
+void ReFinalize::visitCall(Call* curr) { curr->finalize(); }
+void ReFinalize::visitCallIndirect(CallIndirect* curr) { curr->finalize(); }
+void ReFinalize::visitLocalGet(LocalGet* curr) { curr->finalize(); }
+void ReFinalize::visitLocalSet(LocalSet* curr) { curr->finalize(); }
+void ReFinalize::visitGlobalGet(GlobalGet* curr) { curr->finalize(); }
+void ReFinalize::visitGlobalSet(GlobalSet* curr) { curr->finalize(); }
+void ReFinalize::visitLoad(Load* curr) { curr->finalize(); }
+void ReFinalize::visitStore(Store* curr) { curr->finalize(); }
+void ReFinalize::visitAtomicRMW(AtomicRMW* curr) { curr->finalize(); }
+void ReFinalize::visitAtomicCmpxchg(AtomicCmpxchg* curr) { curr->finalize(); }
+void ReFinalize::visitAtomicWait(AtomicWait* curr) { curr->finalize(); }
+void ReFinalize::visitAtomicNotify(AtomicNotify* curr) { curr->finalize(); }
+void ReFinalize::visitAtomicFence(AtomicFence* curr) { curr->finalize(); }
+void ReFinalize::visitSIMDExtract(SIMDExtract* curr) { curr->finalize(); }
+void ReFinalize::visitSIMDReplace(SIMDReplace* curr) { curr->finalize(); }
+void ReFinalize::visitSIMDShuffle(SIMDShuffle* curr) { curr->finalize(); }
+void ReFinalize::visitSIMDTernary(SIMDTernary* curr) { curr->finalize(); }
+void ReFinalize::visitSIMDShift(SIMDShift* curr) { curr->finalize(); }
+void ReFinalize::visitSIMDLoad(SIMDLoad* curr) { curr->finalize(); }
+void ReFinalize::visitMemoryInit(MemoryInit* curr) { curr->finalize(); }
+void ReFinalize::visitDataDrop(DataDrop* curr) { curr->finalize(); }
+void ReFinalize::visitMemoryCopy(MemoryCopy* curr) { curr->finalize(); }
+void ReFinalize::visitMemoryFill(MemoryFill* curr) { curr->finalize(); }
+void ReFinalize::visitConst(Const* curr) { curr->finalize(); }
+void ReFinalize::visitUnary(Unary* curr) { curr->finalize(); }
+void ReFinalize::visitBinary(Binary* curr) { curr->finalize(); }
+void ReFinalize::visitSelect(Select* curr) { curr->finalize(); }
+void ReFinalize::visitDrop(Drop* curr) { curr->finalize(); }
+void ReFinalize::visitReturn(Return* curr) { curr->finalize(); }
+void ReFinalize::visitMemorySize(MemorySize* curr) { curr->finalize(); }
+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::visitRefEq(RefEq* curr) { curr->finalize(); }
+void ReFinalize::visitTry(Try* curr) { curr->finalize(); }
+void ReFinalize::visitThrow(Throw* curr) { curr->finalize(); }
+void ReFinalize::visitRethrow(Rethrow* curr) { curr->finalize(); }
+void ReFinalize::visitBrOnExn(BrOnExn* curr) {
+  curr->finalize();
+  if (curr->exnref->type == Type::unreachable) {
+    replaceUntaken(curr->exnref, nullptr);
+  } else {
+    updateBreakValueType(curr->name, curr->sent);
+  }
+}
+void ReFinalize::visitNop(Nop* curr) { curr->finalize(); }
+void ReFinalize::visitUnreachable(Unreachable* curr) { curr->finalize(); }
+void ReFinalize::visitPop(Pop* curr) { curr->finalize(); }
+void ReFinalize::visitTupleMake(TupleMake* curr) { curr->finalize(); }
+void ReFinalize::visitTupleExtract(TupleExtract* curr) { curr->finalize(); }
+void ReFinalize::visitI31New(I31New* curr) { curr->finalize(); }
+void ReFinalize::visitI31Get(I31Get* 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");
+}
+void ReFinalize::visitRttCanon(RttCanon* curr) { curr->finalize(); }
+void ReFinalize::visitRttSub(RttSub* curr) { curr->finalize(); }
+void ReFinalize::visitStructNew(StructNew* curr) { curr->finalize(); }
+void ReFinalize::visitStructGet(StructGet* curr) { curr->finalize(); }
+void ReFinalize::visitStructSet(StructSet* curr) { curr->finalize(); }
+void ReFinalize::visitArrayNew(ArrayNew* curr) { curr->finalize(); }
+void ReFinalize::visitArrayGet(ArrayGet* curr) { curr->finalize(); }
+void ReFinalize::visitArraySet(ArraySet* curr) { curr->finalize(); }
+void ReFinalize::visitArrayLen(ArrayLen* curr) { curr->finalize(); }
+
+void ReFinalize::visitFunction(Function* curr) {
+  // we may have changed the body from unreachable to none, which might be bad
+  // if the function has a return value
+  if (curr->sig.results != Type::none && curr->body->type == Type::none) {
+    Builder builder(*getModule());
+    curr->body = builder.blockify(curr->body, builder.makeUnreachable());
+  }
+}
+
+void ReFinalize::visitExport(Export* curr) { WASM_UNREACHABLE("unimp"); }
+void ReFinalize::visitGlobal(Global* curr) { WASM_UNREACHABLE("unimp"); }
+void ReFinalize::visitTable(Table* curr) { WASM_UNREACHABLE("unimp"); }
+void ReFinalize::visitMemory(Memory* curr) { WASM_UNREACHABLE("unimp"); }
+void ReFinalize::visitEvent(Event* curr) { WASM_UNREACHABLE("unimp"); }
+void ReFinalize::visitModule(Module* curr) { WASM_UNREACHABLE("unimp"); }
+
+void ReFinalize::updateBreakValueType(Name name, Type type) {
+  if (type != Type::unreachable) {
+    if (breakValues.count(name) == 0) {
+      breakValues[name] = type;
+    } else {
+      breakValues[name] = Type::getLeastUpperBound(breakValues[name], type);
+    }
+  }
+}
+
+// Replace an untaken branch/switch with an unreachable value.
+// A condition may also exist and may or may not be unreachable.
+void ReFinalize::replaceUntaken(Expression* value, Expression* condition) {
+  assert(value->type == Type::unreachable);
+  auto* replacement = value;
+  if (condition) {
+    Builder builder(*getModule());
+    // Even if we have
+    //  (block
+    //   (unreachable)
+    //   (i32.const 1)
+    //  )
+    // we want the block type to be unreachable. That is valid as
+    // the value is unreachable, and necessary since the type of
+    // the condition did not have an impact before (the break/switch
+    // type was unreachable), and might not fit in.
+    if (condition->type.isConcrete()) {
+      condition = builder.makeDrop(condition);
+    }
+    replacement = builder.makeSequence(value, condition);
+    assert(replacement->type.isBasic() && "Basic type expected");
+  }
+  replaceCurrent(replacement);
+}
+
+} // namespace wasm
diff --git a/binaryen/src/ir/abstract.h b/binaryen/src/ir/abstract.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/abstract.h
@@ -0,0 +1,302 @@
+/*
+ * 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.
+ */
+
+// Abstracts out operations from specific opcodes.
+
+#ifndef wasm_ir_abstract_h
+#define wasm_ir_abstract_h
+
+#include <wasm.h>
+
+namespace wasm {
+
+namespace Abstract {
+
+enum Op {
+  // Unary
+  Neg,
+  // Binary
+  Add,
+  Sub,
+  Mul,
+  DivU,
+  DivS,
+  Rem,
+  RemU,
+  RemS,
+  Shl,
+  ShrU,
+  ShrS,
+  RotL,
+  RotR,
+  And,
+  Or,
+  Xor,
+  // Relational
+  EqZ,
+  Eq,
+  Ne,
+  LtS,
+  LtU,
+  LeS,
+  LeU,
+  GtS,
+  GtU,
+  GeS,
+  GeU
+};
+
+inline bool hasAnyShift(BinaryOp op) {
+  return op == ShlInt32 || op == ShrSInt32 || op == ShrUInt32 ||
+         op == RotLInt32 || op == RotRInt32 || op == ShlInt64 ||
+         op == ShrSInt64 || op == ShrUInt64 || op == RotLInt64 ||
+         op == RotRInt64;
+}
+
+// Provide a wasm type and an abstract op and get the concrete one. For example,
+// you can provide i32 and Add and receive the specific opcode for a 32-bit
+// addition, AddInt32. If the op does not exist, it returns Invalid.
+inline UnaryOp getUnary(Type type, Op op) {
+  switch (type.getBasic()) {
+    case Type::i32: {
+      switch (op) {
+        case EqZ:
+          return EqZInt32;
+        default:
+          return InvalidUnary;
+      }
+      break;
+    }
+    case Type::i64: {
+      switch (op) {
+        case EqZ:
+          return EqZInt64;
+        default:
+          return InvalidUnary;
+      }
+      break;
+    }
+    case Type::f32: {
+      switch (op) {
+        case Neg:
+          return NegFloat32;
+        default:
+          return InvalidUnary;
+      }
+      break;
+    }
+    case Type::f64: {
+      switch (op) {
+        case Neg:
+          return NegFloat64;
+        default:
+          return InvalidUnary;
+      }
+      break;
+    }
+    case Type::v128:
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+    case Type::none:
+    case Type::unreachable: {
+      return InvalidUnary;
+    }
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+inline BinaryOp getBinary(Type type, Op op) {
+  switch (type.getBasic()) {
+    case Type::i32: {
+      switch (op) {
+        case Add:
+          return AddInt32;
+        case Sub:
+          return SubInt32;
+        case Mul:
+          return MulInt32;
+        case DivU:
+          return DivUInt32;
+        case DivS:
+          return DivSInt32;
+        case RemU:
+          return RemUInt32;
+        case RemS:
+          return RemSInt32;
+        case Shl:
+          return ShlInt32;
+        case ShrU:
+          return ShrUInt32;
+        case ShrS:
+          return ShrSInt32;
+        case RotL:
+          return RotLInt32;
+        case RotR:
+          return RotRInt32;
+        case And:
+          return AndInt32;
+        case Or:
+          return OrInt32;
+        case Xor:
+          return XorInt32;
+        case Eq:
+          return EqInt32;
+        case Ne:
+          return NeInt32;
+        case LtS:
+          return LtSInt32;
+        case LtU:
+          return LtUInt32;
+        case LeS:
+          return LeSInt32;
+        case LeU:
+          return LeUInt32;
+        case GtS:
+          return GtSInt32;
+        case GtU:
+          return GtUInt32;
+        case GeS:
+          return GeSInt32;
+        case GeU:
+          return GeUInt32;
+        default:
+          return InvalidBinary;
+      }
+      break;
+    }
+    case Type::i64: {
+      switch (op) {
+        case Add:
+          return AddInt64;
+        case Sub:
+          return SubInt64;
+        case Mul:
+          return MulInt64;
+        case DivU:
+          return DivUInt64;
+        case DivS:
+          return DivSInt64;
+        case RemU:
+          return RemUInt64;
+        case RemS:
+          return RemSInt64;
+        case Shl:
+          return ShlInt64;
+        case ShrU:
+          return ShrUInt64;
+        case ShrS:
+          return ShrSInt64;
+        case RotL:
+          return RotLInt64;
+        case RotR:
+          return RotRInt64;
+        case And:
+          return AndInt64;
+        case Or:
+          return OrInt64;
+        case Xor:
+          return XorInt64;
+        case Eq:
+          return EqInt64;
+        case Ne:
+          return NeInt64;
+        case LtS:
+          return LtSInt64;
+        case LtU:
+          return LtUInt64;
+        case LeS:
+          return LeSInt64;
+        case LeU:
+          return LeUInt64;
+        case GtS:
+          return GtSInt64;
+        case GtU:
+          return GtUInt64;
+        case GeS:
+          return GeSInt64;
+        case GeU:
+          return GeUInt64;
+        default:
+          return InvalidBinary;
+      }
+      break;
+    }
+    case Type::f32: {
+      switch (op) {
+        case Add:
+          return AddFloat32;
+        case Sub:
+          return SubFloat32;
+        case Mul:
+          return MulFloat32;
+        case DivU:
+          return DivFloat32;
+        case DivS:
+          return DivFloat32;
+        case Eq:
+          return EqFloat32;
+        case Ne:
+          return NeFloat32;
+        default:
+          return InvalidBinary;
+      }
+      break;
+    }
+    case Type::f64: {
+      switch (op) {
+        case Add:
+          return AddFloat64;
+        case Sub:
+          return SubFloat64;
+        case Mul:
+          return MulFloat64;
+        case DivU:
+          return DivFloat64;
+        case DivS:
+          return DivFloat64;
+        case Eq:
+          return EqFloat64;
+        case Ne:
+          return NeFloat64;
+        default:
+          return InvalidBinary;
+      }
+      break;
+    }
+    case Type::v128:
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+    case Type::none:
+    case Type::unreachable: {
+      return InvalidBinary;
+    }
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+} // namespace Abstract
+
+} // namespace wasm
+
+#endif // wasm_ir_abstract_h
diff --git a/binaryen/src/ir/bits.h b/binaryen/src/ir/bits.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/bits.h
@@ -0,0 +1,423 @@
+/*
+ * 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_ir_bits_h
+#define wasm_ir_bits_h
+
+#include "ir/literal-utils.h"
+#include "support/bits.h"
+#include "wasm-builder.h"
+#include <ir/load-utils.h>
+
+namespace wasm {
+
+namespace Bits {
+
+// get a mask to keep only the low # of bits
+inline int32_t lowBitMask(int32_t bits) {
+  uint32_t ret = -1;
+  if (bits >= 32) {
+    return ret;
+  }
+  return ret >> (32 - bits);
+}
+
+// checks if the input is a mask of lower bits, i.e., all 1s up to some high
+// bit, and all zeros from there. returns the number of masked bits, or 0 if
+// this is not such a mask
+inline uint32_t getMaskedBits(uint32_t mask) {
+  if (mask == uint32_t(-1)) {
+    return 32; // all the bits
+  }
+  if (mask == 0) {
+    return 0; // trivially not a mask
+  }
+  // otherwise, see if x & (x + 1) turns this into non-zero value
+  // 00011111 & (00011111 + 1) => 0
+  if (mask & (mask + 1)) {
+    return 0;
+  }
+  // this is indeed a mask
+  return 32 - countLeadingZeroes(mask);
+}
+
+// gets the number of effective shifts a shift operation does. In
+// wasm, only 5 bits matter for 32-bit shifts, and 6 for 64.
+inline Index getEffectiveShifts(Index amount, Type type) {
+  if (type == Type::i32) {
+    return amount & 31;
+  } else if (type == Type::i64) {
+    return amount & 63;
+  }
+  WASM_UNREACHABLE("unexpected type");
+}
+
+inline Index getEffectiveShifts(Expression* expr) {
+  auto* amount = expr->cast<Const>();
+  if (amount->type == Type::i32) {
+    return getEffectiveShifts(amount->value.geti32(), Type::i32);
+  } else if (amount->type == Type::i64) {
+    return getEffectiveShifts(amount->value.geti64(), Type::i64);
+  }
+  WASM_UNREACHABLE("unexpected type");
+}
+
+inline Expression* makeSignExt(Expression* value, Index bytes, Module& wasm) {
+  if (value->type == Type::i32) {
+    if (bytes == 1 || bytes == 2) {
+      auto shifts = bytes == 1 ? 24 : 16;
+      Builder builder(wasm);
+      return builder.makeBinary(
+        ShrSInt32,
+        builder.makeBinary(
+          ShlInt32,
+          value,
+          LiteralUtils::makeFromInt32(shifts, Type::i32, wasm)),
+        LiteralUtils::makeFromInt32(shifts, Type::i32, wasm));
+    }
+    assert(bytes == 4);
+    return value; // nothing to do
+  } else {
+    assert(value->type == Type::i64);
+    if (bytes == 1 || bytes == 2 || bytes == 4) {
+      auto shifts = bytes == 1 ? 56 : (bytes == 2 ? 48 : 32);
+      Builder builder(wasm);
+      return builder.makeBinary(
+        ShrSInt64,
+        builder.makeBinary(
+          ShlInt64,
+          value,
+          LiteralUtils::makeFromInt32(shifts, Type::i64, wasm)),
+        LiteralUtils::makeFromInt32(shifts, Type::i64, wasm));
+    }
+    assert(bytes == 8);
+    return value; // nothing to do
+  }
+}
+
+// getMaxBits() helper that has pessimistic results for the bits used in locals.
+struct DummyLocalInfoProvider {
+  Index getMaxBitsForLocal(LocalGet* get) {
+    if (get->type == Type::i32) {
+      return 32;
+    } else if (get->type == Type::i64) {
+      return 64;
+    }
+    WASM_UNREACHABLE("type has no integer bit size");
+  }
+};
+
+// Returns the maximum amount of bits used in an integer expression
+// not extremely precise (doesn't look into add operands, etc.)
+// LocalInfoProvider is an optional class that can provide answers about
+// local.get.
+template<typename LocalInfoProvider = DummyLocalInfoProvider>
+Index getMaxBits(Expression* curr,
+                 LocalInfoProvider* localInfoProvider = nullptr) {
+  if (auto* c = curr->dynCast<Const>()) {
+    switch (curr->type.getBasic()) {
+      case Type::i32:
+        return 32 - c->value.countLeadingZeroes().geti32();
+      case Type::i64:
+        return 64 - c->value.countLeadingZeroes().geti64();
+      default:
+        WASM_UNREACHABLE("invalid type");
+    }
+  } else if (auto* binary = curr->dynCast<Binary>()) {
+    switch (binary->op) {
+      // 32-bit
+      case RotLInt32:
+      case RotRInt32:
+      case SubInt32:
+        return 32;
+      case AddInt32: {
+        auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
+        auto maxBitsRight = getMaxBits(binary->right, localInfoProvider);
+        return std::min(Index(32), std::max(maxBitsLeft, maxBitsRight) + 1);
+      }
+      case MulInt32: {
+        auto maxBitsRight = getMaxBits(binary->right, localInfoProvider);
+        auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
+        return std::min(Index(32), maxBitsLeft + maxBitsRight);
+      }
+      case DivSInt32: {
+        if (auto* c = binary->right->dynCast<Const>()) {
+          int32_t maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
+          // If either side might be negative, then the result will be negative
+          if (maxBitsLeft == 32 || c->value.geti32() < 0) {
+            return 32;
+          }
+          int32_t bitsRight = getMaxBits(c);
+          return std::max(0, maxBitsLeft - bitsRight + 1);
+        }
+        return 32;
+      }
+      case DivUInt32: {
+        int32_t maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
+        if (auto* c = binary->right->dynCast<Const>()) {
+          int32_t bitsRight = getMaxBits(c);
+          return std::max(0, maxBitsLeft - bitsRight + 1);
+        }
+        return maxBitsLeft;
+      }
+      case RemSInt32: {
+        if (auto* c = binary->right->dynCast<Const>()) {
+          auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
+          // if left may be negative, the result may be negative
+          if (maxBitsLeft == 32) {
+            return 32;
+          }
+          auto bitsRight = Index(ceilLog2(c->value.geti32()));
+          return std::min(maxBitsLeft, bitsRight);
+        }
+        return 32;
+      }
+      case RemUInt32: {
+        if (auto* c = binary->right->dynCast<Const>()) {
+          auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
+          auto bitsRight = Index(ceilLog2(c->value.geti32()));
+          return std::min(maxBitsLeft, bitsRight);
+        }
+        return 32;
+      }
+      case AndInt32: {
+        return std::min(getMaxBits(binary->left, localInfoProvider),
+                        getMaxBits(binary->right, localInfoProvider));
+      }
+      case OrInt32:
+      case XorInt32: {
+        return std::max(getMaxBits(binary->left, localInfoProvider),
+                        getMaxBits(binary->right, localInfoProvider));
+      }
+      case ShlInt32: {
+        if (auto* shifts = binary->right->dynCast<Const>()) {
+          return std::min(Index(32),
+                          getMaxBits(binary->left, localInfoProvider) +
+                            Bits::getEffectiveShifts(shifts));
+        }
+        return 32;
+      }
+      case ShrUInt32: {
+        if (auto* shift = binary->right->dynCast<Const>()) {
+          auto maxBits = getMaxBits(binary->left, localInfoProvider);
+          auto shifts =
+            std::min(Index(Bits::getEffectiveShifts(shift)),
+                     maxBits); // can ignore more shifts than zero us out
+          return std::max(Index(0), maxBits - shifts);
+        }
+        return 32;
+      }
+      case ShrSInt32: {
+        if (auto* shift = binary->right->dynCast<Const>()) {
+          auto maxBits = getMaxBits(binary->left, localInfoProvider);
+          // if left may be negative, the result may be negative
+          if (maxBits == 32) {
+            return 32;
+          }
+          auto shifts =
+            std::min(Index(Bits::getEffectiveShifts(shift)),
+                     maxBits); // can ignore more shifts than zero us out
+          return std::max(Index(0), maxBits - shifts);
+        }
+        return 32;
+      }
+      case RotLInt64:
+      case RotRInt64:
+      case SubInt64:
+        return 64;
+      case AddInt64: {
+        auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
+        auto maxBitsRight = getMaxBits(binary->right, localInfoProvider);
+        return std::min(Index(64), std::max(maxBitsLeft, maxBitsRight) + 1);
+      }
+      case MulInt64: {
+        auto maxBitsRight = getMaxBits(binary->right, localInfoProvider);
+        auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
+        return std::min(Index(64), maxBitsLeft + maxBitsRight);
+      }
+      case DivSInt64: {
+        if (auto* c = binary->right->dynCast<Const>()) {
+          int32_t maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
+          // if left or right const value is negative
+          if (maxBitsLeft == 64 || c->value.geti64() < 0) {
+            return 64;
+          }
+          int32_t bitsRight = getMaxBits(c);
+          return std::max(0, maxBitsLeft - bitsRight + 1);
+        }
+        return 64;
+      }
+      case DivUInt64: {
+        int32_t maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
+        if (auto* c = binary->right->dynCast<Const>()) {
+          int32_t bitsRight = getMaxBits(c);
+          return std::max(0, maxBitsLeft - bitsRight + 1);
+        }
+        return maxBitsLeft;
+      }
+      case RemSInt64: {
+        if (auto* c = binary->right->dynCast<Const>()) {
+          auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
+          // if left may be negative, the result may be negative
+          if (maxBitsLeft == 64) {
+            return 64;
+          }
+          auto bitsRight = Index(ceilLog2(c->value.geti64()));
+          return std::min(maxBitsLeft, bitsRight);
+        }
+        return 64;
+      }
+      case RemUInt64: {
+        if (auto* c = binary->right->dynCast<Const>()) {
+          auto maxBitsLeft = getMaxBits(binary->left, localInfoProvider);
+          auto bitsRight = Index(ceilLog2(c->value.geti64()));
+          return std::min(maxBitsLeft, bitsRight);
+        }
+        return 64;
+      }
+      case AndInt64: {
+        return std::min(getMaxBits(binary->left, localInfoProvider),
+                        getMaxBits(binary->right, localInfoProvider));
+      }
+      case OrInt64:
+      case XorInt64: {
+        return std::max(getMaxBits(binary->left, localInfoProvider),
+                        getMaxBits(binary->right, localInfoProvider));
+      }
+      case ShlInt64: {
+        if (auto* shifts = binary->right->dynCast<Const>()) {
+          auto maxBits = getMaxBits(binary->left, localInfoProvider);
+          return std::min(Index(64),
+                          Bits::getEffectiveShifts(shifts) + maxBits);
+        }
+        return 64;
+      }
+      case ShrUInt64: {
+        if (auto* shift = binary->right->dynCast<Const>()) {
+          auto maxBits = getMaxBits(binary->left, localInfoProvider);
+          auto shifts =
+            std::min(Index(Bits::getEffectiveShifts(shift)),
+                     maxBits); // can ignore more shifts than zero us out
+          return std::max(Index(0), maxBits - shifts);
+        }
+        return 64;
+      }
+      case ShrSInt64: {
+        if (auto* shift = binary->right->dynCast<Const>()) {
+          auto maxBits = getMaxBits(binary->left, localInfoProvider);
+          // if left may be negative, the result may be negative
+          if (maxBits == 64) {
+            return 64;
+          }
+          auto shifts =
+            std::min(Index(Bits::getEffectiveShifts(shift)),
+                     maxBits); // can ignore more shifts than zero us out
+          return std::max(Index(0), maxBits - shifts);
+        }
+        return 64;
+      }
+      // comparisons
+      case EqInt32:
+      case NeInt32:
+      case LtSInt32:
+      case LtUInt32:
+      case LeSInt32:
+      case LeUInt32:
+      case GtSInt32:
+      case GtUInt32:
+      case GeSInt32:
+      case GeUInt32:
+
+      case EqInt64:
+      case NeInt64:
+      case LtSInt64:
+      case LtUInt64:
+      case LeSInt64:
+      case LeUInt64:
+      case GtSInt64:
+      case GtUInt64:
+      case GeSInt64:
+      case GeUInt64:
+
+      case EqFloat32:
+      case NeFloat32:
+      case LtFloat32:
+      case LeFloat32:
+      case GtFloat32:
+      case GeFloat32:
+
+      case EqFloat64:
+      case NeFloat64:
+      case LtFloat64:
+      case LeFloat64:
+      case GtFloat64:
+      case GeFloat64:
+        return 1;
+      default: {
+      }
+    }
+  } else if (auto* unary = curr->dynCast<Unary>()) {
+    switch (unary->op) {
+      case ClzInt32:
+      case CtzInt32:
+      case PopcntInt32:
+        return 6;
+      case ClzInt64:
+      case CtzInt64:
+      case PopcntInt64:
+        return 7;
+      case EqZInt32:
+      case EqZInt64:
+        return 1;
+      case WrapInt64:
+      case ExtendUInt32:
+        return std::min(Index(32), getMaxBits(unary->value, localInfoProvider));
+      case ExtendSInt32: {
+        auto maxBits = getMaxBits(unary->value, localInfoProvider);
+        return maxBits == 32 ? Index(64) : maxBits;
+      }
+      default: {
+      }
+    }
+  } else if (auto* set = curr->dynCast<LocalSet>()) {
+    // a tee passes through the value
+    return getMaxBits(set->value, localInfoProvider);
+  } else if (auto* get = curr->dynCast<LocalGet>()) {
+    return localInfoProvider->getMaxBitsForLocal(get);
+  } else if (auto* load = curr->dynCast<Load>()) {
+    // if signed, then the sign-extension might fill all the bits
+    // if unsigned, then we have a limit
+    if (LoadUtils::isSignRelevant(load) && !load->signed_) {
+      return 8 * load->bytes;
+    }
+  }
+  switch (curr->type.getBasic()) {
+    case Type::i32:
+      return 32;
+    case Type::i64:
+      return 64;
+    case Type::unreachable:
+      return 64; // not interesting, but don't crash
+    default:
+      WASM_UNREACHABLE("invalid type");
+  }
+}
+
+} // namespace Bits
+
+} // namespace wasm
+
+#endif // wasm_ir_bits_h
diff --git a/binaryen/src/ir/block-utils.h b/binaryen/src/ir/block-utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/block-utils.h
@@ -0,0 +1,76 @@
+/*
+ * 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_ir_block_h
+#define wasm_ir_block_h
+
+#include "ir/branch-utils.h"
+#include "ir/effects.h"
+#include "ir/manipulation.h"
+#include "literal.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace BlockUtils {
+// if a block has just one element, it can often be replaced
+// with that content
+template<typename T>
+inline Expression*
+simplifyToContents(Block* block, T* parent, bool allowTypeChange = false) {
+  auto& list = block->list;
+  if (list.size() == 1 &&
+      !BranchUtils::BranchSeeker::has(list[0], block->name)) {
+    // just one element. try to replace the block
+    auto* singleton = list[0];
+    auto sideEffects = EffectAnalyzer(parent->getPassOptions(),
+                                      parent->getModule()->features,
+                                      singleton)
+                         .hasSideEffects();
+    if (!sideEffects && !singleton->type.isConcrete()) {
+      // no side effects, and singleton is not returning a value, so we can
+      // throw away the block and its contents, basically
+      return Builder(*parent->getModule()).replaceWithIdenticalType(block);
+    } else if (Type::isSubType(singleton->type, block->type) ||
+               allowTypeChange) {
+      return singleton;
+    } else {
+      // (side effects +) type change, must be block with declared value but
+      // inside is unreachable (if both concrete, must match, and since no name
+      // on block, we can't be branched to, so if singleton is unreachable, so
+      // is the block)
+      assert(block->type.isConcrete() && singleton->type == Type::unreachable);
+      // we could replace with unreachable, but would need to update all
+      // the parent's types
+    }
+  } else if (list.size() == 0) {
+    ExpressionManipulator::nop(block);
+  }
+  return block;
+}
+
+// similar, but when we allow the type to change while doing so
+template<typename T>
+inline Expression* simplifyToContentsWithPossibleTypeChange(Block* block,
+                                                            T* parent) {
+  return simplifyToContents(block, parent, true);
+}
+} // namespace BlockUtils
+
+} // namespace wasm
+
+#endif // wasm_ir_block_h
diff --git a/binaryen/src/ir/branch-utils.h b/binaryen/src/ir/branch-utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/branch-utils.h
@@ -0,0 +1,311 @@
+/*
+ * 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_ir_branch_h
+#define wasm_ir_branch_h
+
+#include "ir/iteration.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace BranchUtils {
+
+// 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(Switch* sw) {
+  return !(sw->value && sw->value->type == Type::unreachable) &&
+         sw->condition->type != Type::unreachable;
+}
+
+inline bool isBranchReachable(BrOnExn* br) {
+  return br->exnref->type != Type::unreachable;
+}
+
+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");
+}
+
+using NameSet = std::set<Name>;
+
+inline NameSet getUniqueTargets(Break* br) { return {br->name}; }
+
+inline NameSet getUniqueTargets(Switch* sw) {
+  NameSet ret;
+  for (auto target : sw->targets) {
+    ret.insert(target);
+  }
+  ret.insert(sw->default_);
+  return ret;
+}
+
+inline NameSet getUniqueTargets(BrOnExn* br) { return {br->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 {};
+}
+// 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;
+      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
+inline NameSet getExitingBranches(Expression* ast) {
+  struct Scanner : public PostWalker<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);
+      }
+    }
+  };
+  Scanner scanner;
+  scanner.walk(ast);
+  // anything not erased is a branch out
+  return scanner.targets;
+}
+
+// returns the list of all branch targets in a node
+
+inline NameSet getBranchTargets(Expression* ast) {
+  struct Scanner : public PostWalker<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);
+      }
+    }
+  };
+  Scanner scanner;
+  scanner.walk(ast);
+  return scanner.targets;
+}
+
+// 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> {
+  Name target;
+
+  Index found = 0;
+  Type valueType;
+
+  BranchSeeker(Name target) : target(target) {}
+
+  void noteFound(Expression* value) {
+    noteFound(value ? value->type : Type::none);
+  }
+
+  void noteFound(Type type) {
+    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);
+    }
+  }
+
+  void visitSwitch(Switch* curr) {
+    // check the switch
+    for (auto name : curr->targets) {
+      if (name == target) {
+        noteFound(curr->value);
+      }
+    }
+    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) {
+    if (!target.is()) {
+      return false;
+    }
+    BranchSeeker seeker(target);
+    seeker.walk(tree);
+    return seeker.found > 0;
+  }
+
+  static Index count(Expression* tree, Name target) {
+    if (!target.is()) {
+      return 0;
+    }
+    BranchSeeker seeker(target);
+    seeker.walk(tree);
+    return seeker.found;
+  }
+};
+
+// Accumulates all the branches in an entire tree.
+struct BranchAccumulator
+  : public PostWalker<BranchAccumulator,
+                      UnifiedExpressionVisitor<BranchAccumulator>> {
+  NameSet branches;
+
+  void visitExpression(Expression* curr) {
+    auto selfBranches = getUniqueTargets(curr);
+    branches.insert(selfBranches.begin(), selfBranches.end());
+  }
+};
+
+// A helper structure for the common case of post-walking some IR while querying
+// whether a branch is present. We can cache results for children in order to
+// avoid quadratic time searches.
+// We assume that a node will be scanned *once* here. That means that if we
+// scan a node, we can discard all information for its children. This avoids
+// linearly increasing memory usage over time.
+class BranchSeekerCache {
+  // Maps all the branches present in an expression and all its nested children.
+  std::unordered_map<Expression*, NameSet> branches;
+
+public:
+  const NameSet& getBranches(Expression* curr) {
+    auto iter = branches.find(curr);
+    if (iter != branches.end()) {
+      return iter->second;
+    }
+    NameSet currBranches;
+    auto add = [&](NameSet& moreBranches) {
+      // Make sure to do a fast swap for the first set of branches to arrive.
+      // This helps the case of the first child being a block with a very large
+      // set of names.
+      if (currBranches.empty()) {
+        currBranches.swap(moreBranches);
+      } else {
+        currBranches.insert(moreBranches.begin(), moreBranches.end());
+      }
+    };
+    // Add from the children, which are hopefully cached.
+    for (auto child : ChildIterator(curr)) {
+      auto iter = branches.find(child);
+      if (iter != branches.end()) {
+        add(iter->second);
+        // We are scanning the parent, which means we assume the child will
+        // never be visited again.
+        branches.erase(iter);
+      } else {
+        // The child was not cached. Scan it manually.
+        BranchAccumulator childBranches;
+        childBranches.walk(child);
+        add(childBranches.branches);
+        // Don't bother caching anything - we are scanning the parent, so the
+        // child will presumably not be scanned again.
+      }
+    }
+    // Finish with the parent's own branches.
+    auto selfBranches = getUniqueTargets(curr);
+    add(selfBranches);
+    return branches[curr] = std::move(currBranches);
+  }
+
+  bool hasBranch(Expression* curr, Name target) {
+    bool result = getBranches(curr).count(target);
+#ifdef BRANCH_UTILS_DEBUG
+    assert(bresult == BranchSeeker::has(curr, target));
+#endif
+    return result;
+  }
+};
+
+} // namespace BranchUtils
+
+} // namespace wasm
+
+#endif // wasm_ir_branch_h
diff --git a/binaryen/src/ir/cost.h b/binaryen/src/ir/cost.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/cost.h
@@ -0,0 +1,780 @@
+/*
+ * 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_ir_cost_h
+#define wasm_ir_cost_h
+
+#include <wasm-traversal.h>
+#include <wasm.h>
+
+namespace wasm {
+
+// Measure the execution cost of an AST. Very handwave-ey
+
+struct CostAnalyzer : public Visitor<CostAnalyzer, Index> {
+  CostAnalyzer(Expression* ast) { cost = visit(ast); }
+
+  Index cost;
+
+  Index maybeVisit(Expression* curr) { return curr ? visit(curr) : 0; }
+
+  Index visitBlock(Block* curr) {
+    Index ret = 0;
+    for (auto* child : curr->list) {
+      ret += visit(child);
+    }
+    return ret;
+  }
+  Index visitIf(If* curr) {
+    return 1 + visit(curr->condition) +
+           std::max(visit(curr->ifTrue), maybeVisit(curr->ifFalse));
+  }
+  Index visitLoop(Loop* curr) { return 5 * visit(curr->body); }
+  Index visitBreak(Break* curr) {
+    return 1 + maybeVisit(curr->value) + maybeVisit(curr->condition);
+  }
+  Index visitSwitch(Switch* curr) {
+    return 2 + visit(curr->condition) + maybeVisit(curr->value);
+  }
+  Index visitCall(Call* curr) {
+    // XXX this does not take into account if the call is to an import, which
+    //     may be costlier in general
+    Index ret = 4;
+    for (auto* child : curr->operands) {
+      ret += visit(child);
+    }
+    return ret;
+  }
+  Index visitCallIndirect(CallIndirect* curr) {
+    Index ret = 6 + 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 visitGlobalGet(GlobalGet* curr) { return 1; }
+  Index visitGlobalSet(GlobalSet* curr) { return 2; }
+  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 visitConst(Const* curr) { return 1; }
+  Index visitUnary(Unary* curr) {
+    Index ret = 0;
+    switch (curr->op) {
+      case ClzInt32:
+      case CtzInt32:
+      case PopcntInt32:
+      case NegFloat32:
+      case AbsFloat32:
+      case CeilFloat32:
+      case FloorFloat32:
+      case TruncFloat32:
+      case NearestFloat32:
+      case ClzInt64:
+      case CtzInt64:
+      case PopcntInt64:
+      case NegFloat64:
+      case AbsFloat64:
+      case CeilFloat64:
+      case FloorFloat64:
+      case TruncFloat64:
+      case NearestFloat64:
+      case EqZInt32:
+      case EqZInt64:
+      case ExtendSInt32:
+      case ExtendUInt32:
+      case WrapInt64:
+      case PromoteFloat32:
+      case DemoteFloat64:
+      case TruncSFloat32ToInt32:
+      case TruncUFloat32ToInt32:
+      case TruncSFloat64ToInt32:
+      case TruncUFloat64ToInt32:
+      case ReinterpretFloat32:
+      case TruncSFloat32ToInt64:
+      case TruncUFloat32ToInt64:
+      case TruncSFloat64ToInt64:
+      case TruncUFloat64ToInt64:
+      case ReinterpretFloat64:
+      case ReinterpretInt32:
+      case ConvertSInt32ToFloat32:
+      case ConvertUInt32ToFloat32:
+      case ConvertSInt64ToFloat32:
+      case ConvertUInt64ToFloat32:
+      case ReinterpretInt64:
+      case ConvertSInt32ToFloat64:
+      case ConvertUInt32ToFloat64:
+      case ConvertSInt64ToFloat64:
+      case ConvertUInt64ToFloat64:
+      case ExtendS8Int32:
+      case ExtendS16Int32:
+      case ExtendS8Int64:
+      case ExtendS16Int64:
+      case ExtendS32Int64:
+      case TruncSatSFloat32ToInt32:
+      case TruncSatUFloat32ToInt32:
+      case TruncSatSFloat64ToInt32:
+      case TruncSatUFloat64ToInt32:
+      case TruncSatSFloat32ToInt64:
+      case TruncSatUFloat32ToInt64:
+      case TruncSatSFloat64ToInt64:
+      case TruncSatUFloat64ToInt64:
+        ret = 1;
+        break;
+      case SqrtFloat32:
+      case SqrtFloat64:
+        ret = 2;
+        break;
+      case SplatVecI8x16:
+      case SplatVecI16x8:
+      case SplatVecI32x4:
+      case SplatVecI64x2:
+      case SplatVecF32x4:
+      case SplatVecF64x2:
+      case NotVec128:
+      case AbsVecI8x16:
+      case NegVecI8x16:
+      case AnyTrueVecI8x16:
+      case AllTrueVecI8x16:
+      case BitmaskVecI8x16:
+      case AbsVecI16x8:
+      case NegVecI16x8:
+      case AnyTrueVecI16x8:
+      case AllTrueVecI16x8:
+      case BitmaskVecI16x8:
+      case AbsVecI32x4:
+      case NegVecI32x4:
+      case AnyTrueVecI32x4:
+      case AllTrueVecI32x4:
+      case BitmaskVecI32x4:
+      case NegVecI64x2:
+      case AnyTrueVecI64x2:
+      case AllTrueVecI64x2:
+      case AbsVecF32x4:
+      case NegVecF32x4:
+      case SqrtVecF32x4:
+      case CeilVecF32x4:
+      case FloorVecF32x4:
+      case TruncVecF32x4:
+      case NearestVecF32x4:
+      case AbsVecF64x2:
+      case NegVecF64x2:
+      case SqrtVecF64x2:
+      case CeilVecF64x2:
+      case FloorVecF64x2:
+      case TruncVecF64x2:
+      case NearestVecF64x2:
+      case TruncSatSVecF32x4ToVecI32x4:
+      case TruncSatUVecF32x4ToVecI32x4:
+      case TruncSatSVecF64x2ToVecI64x2:
+      case TruncSatUVecF64x2ToVecI64x2:
+      case ConvertSVecI32x4ToVecF32x4:
+      case ConvertUVecI32x4ToVecF32x4:
+      case ConvertSVecI64x2ToVecF64x2:
+      case ConvertUVecI64x2ToVecF64x2:
+      case WidenLowSVecI8x16ToVecI16x8:
+      case WidenHighSVecI8x16ToVecI16x8:
+      case WidenLowUVecI8x16ToVecI16x8:
+      case WidenHighUVecI8x16ToVecI16x8:
+      case WidenLowSVecI16x8ToVecI32x4:
+      case WidenHighSVecI16x8ToVecI32x4:
+      case WidenLowUVecI16x8ToVecI32x4:
+      case WidenHighUVecI16x8ToVecI32x4:
+        return 1;
+      case InvalidUnary:
+        WASM_UNREACHABLE("invalid unary op");
+    }
+    return ret + visit(curr->value);
+  }
+  Index visitBinary(Binary* curr) {
+    Index ret = 0;
+    switch (curr->op) {
+      case AddInt32:
+        ret = 1;
+        break;
+      case SubInt32:
+        ret = 1;
+        break;
+      case MulInt32:
+        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;
+      case MulInt64:
+        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;
+      case MulFloat32:
+        ret = 2;
+        break;
+      case DivFloat32:
+        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;
+      case MulFloat64:
+        ret = 2;
+        break;
+      case DivFloat64:
+        ret = 3;
+        break;
+      case CopySignFloat64:
+        ret = 1;
+        break;
+      case MinFloat64:
+        ret = 1;
+        break;
+      case MaxFloat64:
+        ret = 1;
+        break;
+      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 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 LtFloat32:
+        ret = 1;
+        break;
+      case GtFloat32:
+        ret = 1;
+        break;
+      case LeFloat32:
+        ret = 1;
+        break;
+      case GeFloat32:
+        ret = 1;
+        break;
+      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 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;
+      case MulVecI8x16:
+        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;
+      case MulVecI16x8:
+        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 AddVecI32x4:
+        ret = 1;
+        break;
+      case SubVecI32x4:
+        ret = 1;
+        break;
+      case MulVecI32x4:
+        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 AddVecI64x2:
+        ret = 1;
+        break;
+      case SubVecI64x2:
+        ret = 1;
+        break;
+      case MulVecI64x2:
+        ret = 1;
+        break;
+      case AddVecF32x4:
+        ret = 1;
+        break;
+      case SubVecF32x4:
+        ret = 1;
+        break;
+      case MulVecF32x4:
+        ret = 2;
+        break;
+      case DivVecF32x4:
+        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;
+      case MulVecF64x2:
+        ret = 2;
+        break;
+      case DivVecF64x2:
+        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;
+      case InvalidBinary:
+        WASM_UNREACHABLE("invalid binary op");
+    }
+    return ret + visit(curr->left) + visit(curr->right);
+  }
+  Index visitSelect(Select* curr) {
+    return 2 + 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 visitRefNull(RefNull* curr) { return 1; }
+  Index visitRefIsNull(RefIsNull* curr) { return 1 + visit(curr->value); }
+  Index visitRefFunc(RefFunc* curr) { return 1; }
+  Index visitRefEq(RefEq* curr) {
+    return 1 + visit(curr->left) + visit(curr->right);
+  }
+  Index visitTry(Try* curr) {
+    // We assume no exception will be thrown in most cases
+    return visit(curr->body);
+  }
+  Index visitThrow(Throw* curr) { return 100; }
+  Index visitRethrow(Rethrow* curr) { return 100; }
+  Index visitBrOnExn(BrOnExn* curr) {
+    return 1 + visit(curr->exnref) + curr->sent.size();
+  }
+  Index visitNop(Nop* curr) { return 0; }
+  Index visitUnreachable(Unreachable* curr) { return 0; }
+};
+
+} // namespace wasm
+
+#endif // wasm_ir_cost_h
diff --git a/binaryen/src/ir/debug.h b/binaryen/src/ir/debug.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/debug.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019 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_ir_debug_h
+#define wasm_ir_debug_h
+
+#include <wasm-traversal.h>
+
+namespace wasm {
+
+namespace debug {
+
+// Given an expression and a copy of it in another function, copy the debug
+// info into the second function.
+inline void copyDebugInfo(Expression* origin,
+                          Expression* copy,
+                          Function* originFunc,
+                          Function* copyFunc) {
+  struct Lister : public PostWalker<Lister, UnifiedExpressionVisitor<Lister>> {
+    std::vector<Expression*> list;
+    void visitExpression(Expression* curr) { list.push_back(curr); }
+  };
+
+  Lister originList;
+  originList.walk(origin);
+  Lister copyList;
+  copyList.walk(copy);
+
+  auto& originDebug = originFunc->debugLocations;
+  auto& copyDebug = copyFunc->debugLocations;
+
+  assert(originList.list.size() == copyList.list.size());
+  for (Index i = 0; i < originList.list.size(); i++) {
+    auto iter = originDebug.find(originList.list[i]);
+    if (iter != originDebug.end()) {
+      auto location = iter->second;
+      copyDebug[copyList.list[i]] = location;
+    }
+  }
+};
+
+} // namespace debug
+
+} // namespace wasm
+
+#endif // wasm_ir_debug_h
diff --git a/binaryen/src/ir/effects.h b/binaryen/src/ir/effects.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/effects.h
@@ -0,0 +1,619 @@
+/*
+ * 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_ir_effects_h
+#define wasm_ir_effects_h
+
+#include "pass.h"
+#include "wasm-traversal.h"
+
+namespace wasm {
+
+// Look for side effects, including control flow
+// TODO: optimize
+
+struct EffectAnalyzer
+  : public PostWalker<EffectAnalyzer, OverriddenVisitor<EffectAnalyzer>> {
+  EffectAnalyzer(const PassOptions& passOptions,
+                 FeatureSet features,
+                 Expression* ast = nullptr)
+    : ignoreImplicitTraps(passOptions.ignoreImplicitTraps),
+      debugInfo(passOptions.debugInfo), features(features) {
+    if (ast) {
+      analyze(ast);
+    }
+  }
+
+  bool ignoreImplicitTraps;
+  bool debugInfo;
+  FeatureSet features;
+
+  void analyze(Expression* ast) {
+    breakTargets.clear();
+    walk(ast);
+    assert(tryDepth == 0);
+  }
+
+  // Core effect tracking
+
+  // Definitely branches out of this expression, or does a return, etc.
+  // breakTargets tracks individual targets, which we may eventually see are
+  // internal, while this is set when we see something that will definitely
+  // not be internal, or is otherwise special like an infinite loop (which
+  // does not technically branch "out", but it does break the normal assumption
+  // of control flow proceeding normally).
+  bool branchesOut = false;
+  bool calls = false;
+  std::set<Index> localsRead;
+  std::set<Index> localsWritten;
+  std::set<Name> globalsRead;
+  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
+  bool implicitTrap = false;
+  // An atomic load/store/RMW/Cmpxchg or an operator that has a defined ordering
+  // wrt atomics (e.g. memory.grow)
+  bool isAtomic = false;
+  bool throws = false;
+  // The nested depth of try. If an instruction that may throw is inside an
+  // inner try, we don't mark it as 'throws', because it will be caught by an
+  // inner catch.
+  size_t tryDepth = 0;
+  // The nested depth of catch. This is necessary to track danglng pops.
+  size_t catchDepth = 0;
+  // If this expression contains 'exnref.pop's that are not enclosed in 'catch'
+  // 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 {
+    return localsRead.size() + localsWritten.size() > 0;
+  }
+  bool accessesGlobal() const {
+    return globalsRead.size() + globalsWritten.size() > 0;
+  }
+  bool accessesMemory() const { return calls || readsMemory || writesMemory; }
+  // Check whether this may transfer control flow to somewhere outside of this
+  // expression (aside from just flowing out normally). That includes a break
+  // or a throw (if the throw is not known to be caught inside this expression;
+  // note that if the throw is not caught in this expression then it might be
+  // caught in this function but outside of this expression, or it might not be
+  // caught in the function at all, which would mean control flow cannot be
+  // transferred inside the function, but this expression does not know that).
+  bool transfersControlFlow() const {
+    return branchesOut || throws || hasExternalBreakTargets();
+  }
+
+  bool hasGlobalSideEffects() const {
+    return calls || globalsWritten.size() > 0 || writesMemory || isAtomic ||
+           throws;
+  }
+  bool hasSideEffects() const {
+    return hasGlobalSideEffects() || localsWritten.size() > 0 ||
+           transfersControlFlow() || implicitTrap || danglingPop;
+  }
+  bool hasAnything() const {
+    return hasSideEffects() || accessesLocal() || readsMemory ||
+           accessesGlobal() || isAtomic;
+  }
+
+  bool noticesGlobalSideEffects() const {
+    return calls || readsMemory || isAtomic || globalsRead.size();
+  }
+
+  // check if we break to anything external from ourselves
+  bool hasExternalBreakTargets() const { return !breakTargets.empty(); }
+
+  // checks if these effects would invalidate another set (e.g., if we write, we
+  // invalidate someone that reads, they can't be moved past us)
+  bool invalidates(const EffectAnalyzer& other) {
+    if ((transfersControlFlow() && other.hasSideEffects()) ||
+        (other.transfersControlFlow() && hasSideEffects()) ||
+        ((writesMemory || calls) && other.accessesMemory()) ||
+        (accessesMemory() && (other.writesMemory || other.calls)) ||
+        (danglingPop || other.danglingPop)) {
+      return true;
+    }
+    // All atomics are sequentially consistent for now, and ordered wrt other
+    // memory references.
+    if ((isAtomic && other.accessesMemory()) ||
+        (other.isAtomic && accessesMemory())) {
+      return true;
+    }
+    for (auto local : localsWritten) {
+      if (other.localsWritten.count(local) || other.localsRead.count(local)) {
+        return true;
+      }
+    }
+    for (auto local : localsRead) {
+      if (other.localsWritten.count(local)) {
+        return true;
+      }
+    }
+    if ((accessesGlobal() && other.calls) ||
+        (other.accessesGlobal() && calls)) {
+      return true;
+    }
+    for (auto global : globalsWritten) {
+      if (other.globalsWritten.count(global) ||
+          other.globalsRead.count(global)) {
+        return true;
+      }
+    }
+    for (auto global : globalsRead) {
+      if (other.globalsWritten.count(global)) {
+        return true;
+      }
+    }
+    // we are ok to reorder implicit traps, but not conditionalize them
+    if ((implicitTrap && other.transfersControlFlow()) ||
+        (other.implicitTrap && transfersControlFlow())) {
+      return true;
+    }
+    // we can't reorder an implicit trap in a way that alters global state
+    if ((implicitTrap && other.hasGlobalSideEffects()) ||
+        (other.implicitTrap && hasGlobalSideEffects())) {
+      return true;
+    }
+    return false;
+  }
+
+  void mergeIn(EffectAnalyzer& other) {
+    branchesOut = branchesOut || other.branchesOut;
+    calls = calls || other.calls;
+    readsMemory = readsMemory || other.readsMemory;
+    writesMemory = writesMemory || other.writesMemory;
+    implicitTrap = implicitTrap || other.implicitTrap;
+    isAtomic = isAtomic || other.isAtomic;
+    throws = throws || other.throws;
+    danglingPop = danglingPop || other.danglingPop;
+    for (auto i : other.localsRead) {
+      localsRead.insert(i);
+    }
+    for (auto i : other.localsWritten) {
+      localsWritten.insert(i);
+    }
+    for (auto i : other.globalsRead) {
+      globalsRead.insert(i);
+    }
+    for (auto i : other.globalsWritten) {
+      globalsWritten.insert(i);
+    }
+    for (auto i : other.breakTargets) {
+      breakTargets.insert(i);
+    }
+  }
+
+  // the checks above happen after the node's children were processed, in the
+  // order of execution we must also check for control flow that happens before
+  // the children, i.e., loops
+  bool checkPre(Expression* curr) {
+    if (curr->is<Loop>()) {
+      branchesOut = true;
+      return true;
+    }
+    return false;
+  }
+
+  bool checkPost(Expression* curr) {
+    visit(curr);
+    if (curr->is<Loop>()) {
+      branchesOut = true;
+    }
+    return hasAnything();
+  }
+
+  std::set<Name> breakTargets;
+
+  void visitBlock(Block* curr) {
+    if (curr->name.is()) {
+      breakTargets.erase(curr->name); // these were internal breaks
+    }
+  }
+  void visitIf(If* curr) {}
+  void visitLoop(Loop* curr) {
+    if (curr->name.is()) {
+      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) {
+      branchesOut = true;
+    }
+  }
+  void visitBreak(Break* curr) { breakTargets.insert(curr->name); }
+  void visitSwitch(Switch* curr) {
+    for (auto name : curr->targets) {
+      breakTargets.insert(name);
+    }
+    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;
+    }
+    if (curr->isReturn) {
+      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 visitCallIndirect(CallIndirect* curr) {
+    calls = true;
+    if (features.hasExceptionHandling() && tryDepth == 0) {
+      throws = true;
+    }
+    if (curr->isReturn) {
+      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 visitStore(Store* curr) {
+    writesMemory = true;
+    isAtomic |= curr->isAtomic;
+    if (!ignoreImplicitTraps) {
+      implicitTrap = true;
+    }
+  }
+  void visitAtomicRMW(AtomicRMW* curr) {
+    readsMemory = true;
+    writesMemory = true;
+    isAtomic = true;
+    if (!ignoreImplicitTraps) {
+      implicitTrap = true;
+    }
+  }
+  void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+    readsMemory = true;
+    writesMemory = true;
+    isAtomic = true;
+    if (!ignoreImplicitTraps) {
+      implicitTrap = true;
+    }
+  }
+  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 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 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 visitMemoryInit(MemoryInit* curr) {
+    writesMemory = true;
+    if (!ignoreImplicitTraps) {
+      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 visitMemoryCopy(MemoryCopy* curr) {
+    readsMemory = true;
+    writesMemory = true;
+    if (!ignoreImplicitTraps) {
+      implicitTrap = true;
+    }
+  }
+  void visitMemoryFill(MemoryFill* curr) {
+    writesMemory = true;
+    if (!ignoreImplicitTraps) {
+      implicitTrap = true;
+    }
+  }
+  void visitConst(Const* curr) {}
+  void visitUnary(Unary* curr) {
+    if (!ignoreImplicitTraps) {
+      switch (curr->op) {
+        case TruncSFloat32ToInt32:
+        case TruncSFloat32ToInt64:
+        case TruncUFloat32ToInt32:
+        case TruncUFloat32ToInt64:
+        case TruncSFloat64ToInt32:
+        case TruncSFloat64ToInt64:
+        case TruncUFloat64ToInt32:
+        case TruncUFloat64ToInt64: {
+          implicitTrap = true;
+          break;
+        }
+        default: {
+        }
+      }
+    }
+  }
+  void visitBinary(Binary* curr) {
+    if (!ignoreImplicitTraps) {
+      switch (curr->op) {
+        case DivSInt32:
+        case DivUInt32:
+        case RemSInt32:
+        case RemUInt32:
+        case DivSInt64:
+        case DivUInt64:
+        case RemSInt64:
+        case RemUInt64: {
+          implicitTrap = true;
+          break;
+        }
+        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 visitRethrow(Rethrow* curr) {
+    if (tryDepth == 0) {
+      throws = true;
+    }
+    if (!ignoreImplicitTraps) { // rethrow traps when the arg is null
+      implicitTrap = true;
+    }
+  }
+  void visitBrOnExn(BrOnExn* curr) {
+    breakTargets.insert(curr->name);
+    if (!ignoreImplicitTraps) { // br_on_exn traps when the arg is null
+      implicitTrap = true;
+    }
+  }
+  void visitNop(Nop* curr) {}
+  void visitUnreachable(Unreachable* curr) { branchesOut = true; }
+  void visitPop(Pop* curr) {
+    if (catchDepth == 0) {
+      danglingPop = 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");
+  }
+
+  // Helpers
+
+  static bool canReorder(const PassOptions& passOptions,
+                         FeatureSet features,
+                         Expression* a,
+                         Expression* b) {
+    EffectAnalyzer aEffects(passOptions, features, a);
+    EffectAnalyzer bEffects(passOptions, features, b);
+    return !aEffects.invalidates(bEffects);
+  }
+
+  // C-API
+
+  enum SideEffects : uint32_t {
+    None = 0,
+    Branches = 1 << 0,
+    Calls = 1 << 1,
+    ReadsLocal = 1 << 2,
+    WritesLocal = 1 << 3,
+    ReadsGlobal = 1 << 4,
+    WritesGlobal = 1 << 5,
+    ReadsMemory = 1 << 6,
+    WritesMemory = 1 << 7,
+    ImplicitTrap = 1 << 8,
+    IsAtomic = 1 << 9,
+    Throws = 1 << 10,
+    DanglingPop = 1 << 11,
+    Any = (1 << 12) - 1
+  };
+  uint32_t getSideEffects() const {
+    uint32_t effects = 0;
+    if (branchesOut || hasExternalBreakTargets()) {
+      effects |= SideEffects::Branches;
+    }
+    if (calls) {
+      effects |= SideEffects::Calls;
+    }
+    if (localsRead.size() > 0) {
+      effects |= SideEffects::ReadsLocal;
+    }
+    if (localsWritten.size() > 0) {
+      effects |= SideEffects::WritesLocal;
+    }
+    if (globalsRead.size() > 0) {
+      effects |= SideEffects::ReadsGlobal;
+    }
+    if (globalsWritten.size() > 0) {
+      effects |= SideEffects::WritesGlobal;
+    }
+    if (readsMemory) {
+      effects |= SideEffects::ReadsMemory;
+    }
+    if (writesMemory) {
+      effects |= SideEffects::WritesMemory;
+    }
+    if (implicitTrap) {
+      effects |= SideEffects::ImplicitTrap;
+    }
+    if (isAtomic) {
+      effects |= SideEffects::IsAtomic;
+    }
+    if (throws) {
+      effects |= SideEffects::Throws;
+    }
+    if (danglingPop) {
+      effects |= SideEffects::DanglingPop;
+    }
+    return effects;
+  }
+
+  void ignoreBranches() {
+    branchesOut = false;
+    breakTargets.clear();
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_ir_effects_h
diff --git a/binaryen/src/ir/equivalent_sets.h b/binaryen/src/ir/equivalent_sets.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/equivalent_sets.h
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#ifndef wasm_ir_equivalent_sets_h
+#define wasm_ir_equivalent_sets_h
+
+#include <wasm.h>
+
+namespace wasm {
+
+//
+// A map of each index to all those it is equivalent to, and some helpers.
+//
+struct EquivalentSets {
+  // A set of indexes. This is ordered for deterministic iteration.
+  typedef std::set<Index> Set;
+
+  std::unordered_map<Index, std::shared_ptr<Set>> indexSets;
+
+  // Clears the state completely, removing all equivalences.
+  void clear() { indexSets.clear(); }
+
+  // Resets an index, removing any equivalences between it and others.
+  void reset(Index index) {
+    auto iter = indexSets.find(index);
+    if (iter != indexSets.end()) {
+      auto& set = iter->second;
+      assert(!set->empty()); // can't be empty - we are equal to ourselves!
+      if (set->size() > 1) {
+        // We are not the last item, fix things up
+        set->erase(index);
+      }
+      indexSets.erase(iter);
+    }
+  }
+
+  // Adds a new equivalence between two indexes.
+  // `justReset` is an index that was just reset, and has no
+  // equivalences. `other` may have existing equivalences.
+  void add(Index justReset, Index other) {
+    auto iter = indexSets.find(other);
+    if (iter != indexSets.end()) {
+      auto& set = iter->second;
+      set->insert(justReset);
+      indexSets[justReset] = set;
+    } else {
+      auto set = std::make_shared<Set>();
+      set->insert(justReset);
+      set->insert(other);
+      indexSets[justReset] = set;
+      indexSets[other] = set;
+    }
+  }
+
+  // Checks whether two indexes contain the same data.
+  bool check(Index a, Index b) {
+    if (a == b) {
+      return true;
+    }
+    if (auto* set = getEquivalents(a)) {
+      if (set->find(b) != set->end()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // Returns the equivalent set, or nullptr
+  Set* getEquivalents(Index index) {
+    auto iter = indexSets.find(index);
+    if (iter != indexSets.end()) {
+      return iter->second.get();
+    }
+    return nullptr;
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_ir_equivalent_sets_h
diff --git a/binaryen/src/ir/features.h b/binaryen/src/ir/features.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/features.h
@@ -0,0 +1,183 @@
+/*
+ * 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.
+ */
+
+#ifndef wasm_ir_features_h
+#define wasm_ir_features_h
+
+#include <ir/iteration.h>
+#include <wasm-binary.h>
+#include <wasm-traversal.h>
+#include <wasm.h>
+
+namespace wasm {
+
+namespace Features {
+
+inline FeatureSet get(UnaryOp op) {
+  FeatureSet ret;
+  switch (op) {
+    case TruncSatSFloat32ToInt32:
+    case TruncSatUFloat32ToInt32:
+    case TruncSatSFloat64ToInt32:
+    case TruncSatUFloat64ToInt32:
+    case TruncSatSFloat32ToInt64:
+    case TruncSatUFloat32ToInt64:
+    case TruncSatSFloat64ToInt64:
+    case TruncSatUFloat64ToInt64: {
+      ret.setTruncSat();
+      break;
+    }
+    case SplatVecI8x16:
+    case SplatVecI16x8:
+    case SplatVecI32x4:
+    case SplatVecI64x2:
+    case SplatVecF32x4:
+    case SplatVecF64x2:
+    case NotVec128:
+    case NegVecI8x16:
+    case AnyTrueVecI8x16:
+    case AllTrueVecI8x16:
+    case NegVecI16x8:
+    case AnyTrueVecI16x8:
+    case AllTrueVecI16x8:
+    case NegVecI32x4:
+    case AnyTrueVecI32x4:
+    case AllTrueVecI32x4:
+    case NegVecI64x2:
+    case AnyTrueVecI64x2:
+    case AllTrueVecI64x2:
+    case AbsVecF32x4:
+    case NegVecF32x4:
+    case SqrtVecF32x4:
+    case AbsVecF64x2:
+    case NegVecF64x2:
+    case SqrtVecF64x2:
+    case TruncSatSVecF32x4ToVecI32x4:
+    case TruncSatUVecF32x4ToVecI32x4:
+    case TruncSatSVecF64x2ToVecI64x2:
+    case TruncSatUVecF64x2ToVecI64x2:
+    case ConvertSVecI32x4ToVecF32x4:
+    case ConvertUVecI32x4ToVecF32x4:
+    case ConvertSVecI64x2ToVecF64x2:
+    case ConvertUVecI64x2ToVecF64x2: {
+      ret.setSIMD();
+      break;
+    }
+    case ExtendS8Int32:
+    case ExtendS16Int32:
+    case ExtendS8Int64:
+    case ExtendS16Int64:
+    case ExtendS32Int64: {
+      ret.setSignExt();
+      break;
+    }
+    default: {}
+  }
+  return ret;
+}
+
+inline FeatureSet get(BinaryOp op) {
+  FeatureSet ret;
+  switch (op) {
+    case EqVecI8x16:
+    case NeVecI8x16:
+    case LtSVecI8x16:
+    case LtUVecI8x16:
+    case GtSVecI8x16:
+    case GtUVecI8x16:
+    case LeSVecI8x16:
+    case LeUVecI8x16:
+    case GeSVecI8x16:
+    case GeUVecI8x16:
+    case EqVecI16x8:
+    case NeVecI16x8:
+    case LtSVecI16x8:
+    case LtUVecI16x8:
+    case GtSVecI16x8:
+    case GtUVecI16x8:
+    case LeSVecI16x8:
+    case LeUVecI16x8:
+    case GeSVecI16x8:
+    case GeUVecI16x8:
+    case EqVecI32x4:
+    case NeVecI32x4:
+    case LtSVecI32x4:
+    case LtUVecI32x4:
+    case GtSVecI32x4:
+    case GtUVecI32x4:
+    case LeSVecI32x4:
+    case LeUVecI32x4:
+    case GeSVecI32x4:
+    case GeUVecI32x4:
+    case EqVecF32x4:
+    case NeVecF32x4:
+    case LtVecF32x4:
+    case GtVecF32x4:
+    case LeVecF32x4:
+    case GeVecF32x4:
+    case EqVecF64x2:
+    case NeVecF64x2:
+    case LtVecF64x2:
+    case GtVecF64x2:
+    case LeVecF64x2:
+    case GeVecF64x2:
+    case AndVec128:
+    case OrVec128:
+    case XorVec128:
+    case AddVecI8x16:
+    case AddSatSVecI8x16:
+    case AddSatUVecI8x16:
+    case SubVecI8x16:
+    case SubSatSVecI8x16:
+    case SubSatUVecI8x16:
+    case MulVecI8x16:
+    case AddVecI16x8:
+    case AddSatSVecI16x8:
+    case AddSatUVecI16x8:
+    case SubVecI16x8:
+    case SubSatSVecI16x8:
+    case SubSatUVecI16x8:
+    case MulVecI16x8:
+    case AddVecI32x4:
+    case SubVecI32x4:
+    case MulVecI32x4:
+    case AddVecI64x2:
+    case SubVecI64x2:
+    case AddVecF32x4:
+    case SubVecF32x4:
+    case MulVecF32x4:
+    case DivVecF32x4:
+    case MinVecF32x4:
+    case MaxVecF32x4:
+    case AddVecF64x2:
+    case SubVecF64x2:
+    case MulVecF64x2:
+    case DivVecF64x2:
+    case MinVecF64x2:
+    case MaxVecF64x2: {
+      ret.setSIMD();
+      break;
+    }
+    default: {}
+  }
+  return ret;
+}
+
+} // namespace Features
+
+} // namespace wasm
+
+#endif // wasm_ir_features_h
diff --git a/binaryen/src/ir/find_all.h b/binaryen/src/ir/find_all.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/find_all.h
@@ -0,0 +1,73 @@
+/*
+ * 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_ir_find_all_h
+#define wasm_ir_find_all_h
+
+#include <wasm-traversal.h>
+
+namespace wasm {
+
+// Find all instances of a certain node type
+
+template<typename T> struct FindAll {
+  std::vector<T*> list;
+
+  FindAll(Expression* ast) {
+    struct Finder
+      : public PostWalker<Finder, UnifiedExpressionVisitor<Finder>> {
+      std::vector<T*>* list;
+      void visitExpression(Expression* curr) {
+        if (curr->is<T>()) {
+          (*list).push_back(curr->cast<T>());
+        }
+      }
+    };
+    Finder finder;
+    finder.list = &list;
+    finder.walk(ast);
+  }
+};
+
+// Find all pointers to instances of a certain node type
+
+struct PointerFinder
+  : public PostWalker<PointerFinder, UnifiedExpressionVisitor<PointerFinder>> {
+  Expression::Id id;
+  std::vector<Expression**>* list;
+  void visitExpression(Expression* curr) {
+    if (curr->_id == id) {
+      (*list).push_back(getCurrentPointer());
+    }
+  }
+};
+
+template<typename T> struct FindAllPointers {
+  std::vector<Expression**> list;
+
+  // Note that a pointer may be to the function->body itself, so we must
+  // take \ast by reference.
+  FindAllPointers(Expression*& ast) {
+    PointerFinder finder;
+    finder.id = (Expression::Id)T::SpecificId;
+    finder.list = &list;
+    finder.walk(ast);
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_ir_find_all_h
diff --git a/binaryen/src/ir/flat.h b/binaryen/src/ir/flat.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/flat.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2019 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.
+ */
+
+//
+// Flattens code, removing nesting.e.g. an if return value would be
+// converted to a local
+//
+//  (i32.add
+//    (if (..condition..)
+//      (..if true..)
+//      (..if false..)
+//    )
+//    (i32.const 1)
+//  )
+// =>
+//  (if (..condition..)
+//    (local.set $temp
+//      (..if true..)
+//    )
+//    (local.set $temp
+//      (..if false..)
+//    )
+//  )
+//  (i32.add
+//    (local.get $temp)
+//    (i32.const 1)
+//  )
+//
+// Formally, this pass flattens in the precise sense of
+// making the AST have these properties:
+//
+//  1. Aside from a local.set, the operands of an instruction must be a
+//     local.get, a const, or an unreachable. Anything else is written
+//     to a local earlier.
+//  2. Disallow control flow (block, loop, if, and try) return values, and do
+//     not allow the function body to have a concrete type, i.e., do not use
+//     control flow to pass around values.
+//  3. Disallow local.tee, setting a local is always done in a local.set
+//     on a non-nested-expression location.
+//  4. local.set cannot have an operand that is control flow (control flow with
+//     values is prohibited already, but e.g. a block ending in unreachable,
+//     which can normally be nested, is also disallowed).
+//
+
+#ifndef wasm_ir_flat_h
+#define wasm_ir_flat_h
+
+#include "ir/iteration.h"
+#include "ir/properties.h"
+#include "pass.h"
+#include "wasm-traversal.h"
+
+namespace wasm {
+
+namespace Flat {
+
+inline void verifyFlatness(Function* func) {
+  struct VerifyFlatness
+    : public PostWalker<VerifyFlatness,
+                        UnifiedExpressionVisitor<VerifyFlatness>> {
+    void visitExpression(Expression* curr) {
+      if (Properties::isControlFlowStructure(curr)) {
+        verify(!curr->type.isConcrete(),
+               "control flow structures must not flow values");
+      } else if (auto* set = curr->dynCast<LocalSet>()) {
+        verify(!set->isTee() || set->type == Type::unreachable,
+               "tees are not allowed, only sets");
+        verify(!Properties::isControlFlowStructure(set->value),
+               "set values cannot be control flow");
+      } else {
+        for (auto* child : ChildIterator(curr)) {
+          verify(Properties::isConstantExpression(child) ||
+                   child->is<LocalGet>() || child->is<Unreachable>(),
+                 "instructions must only have constant expressions, local.get, "
+                 "or unreachable as children");
+        }
+      }
+    }
+
+    void verify(bool condition, const char* message) {
+      if (!condition) {
+        Fatal() << "IR must be flat: run --flatten beforehand (" << message
+                << ", in " << getFunction()->name << ')';
+      }
+    }
+  };
+
+  VerifyFlatness verifier;
+  verifier.walkFunction(func);
+  verifier.setFunction(func);
+  verifier.verify(!func->body->type.isConcrete(),
+                  "function bodies must not flow values");
+}
+
+inline void verifyFlatness(Module* module) {
+  struct VerifyFlatness
+    : public WalkerPass<
+        PostWalker<VerifyFlatness, UnifiedExpressionVisitor<VerifyFlatness>>> {
+    bool isFunctionParallel() override { return true; }
+
+    VerifyFlatness* create() override { return new VerifyFlatness(); }
+
+    void doVisitFunction(Function* func) { verifyFlatness(func); }
+  };
+
+  PassRunner runner(module);
+  VerifyFlatness().run(&runner, module);
+}
+
+} // namespace Flat
+
+} // namespace wasm
+
+#endif // wasm_ir_flat_h
diff --git a/binaryen/src/ir/function-utils.h b/binaryen/src/ir/function-utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/function-utils.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef wasm_ir_function_h
+#define wasm_ir_function_h
+
+#include "ir/utils.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace FunctionUtils {
+
+// Checks if two functions are equal in all functional aspects,
+// everything but their name (which can't be the same, in the same
+// module!) - same params, vars, body, result, etc.
+inline bool equal(Function* left, Function* right) {
+  if (left->sig != right->sig) {
+    return false;
+  }
+  if (left->getNumVars() != right->getNumVars()) {
+    return false;
+  }
+  for (Index i = left->sig.params.size(); i < left->getNumLocals(); i++) {
+    if (left->getLocalType(i) != right->getLocalType(i)) {
+      return false;
+    }
+  }
+  if (!left->imported() && !right->imported()) {
+    return ExpressionAnalyzer::equal(left->body, right->body);
+  }
+  return left->imported() && right->imported();
+}
+
+} // namespace FunctionUtils
+
+} // namespace wasm
+
+#endif // wasm_ir_function_h
diff --git a/binaryen/src/ir/global-utils.h b/binaryen/src/ir/global-utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/global-utils.h
@@ -0,0 +1,72 @@
+/*
+ * 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_ir_global_h
+#define wasm_ir_global_h
+
+#include <algorithm>
+#include <vector>
+
+#include "ir/module-utils.h"
+#include "literal.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace GlobalUtils {
+// find a global initialized to the value of an import, or null if no such
+// global
+inline Global*
+getGlobalInitializedToImport(Module& wasm, Name module, Name base) {
+  // find the import
+  Name imported;
+  ModuleUtils::iterImportedGlobals(wasm, [&](Global* import) {
+    if (import->module == module && import->base == base) {
+      imported = import->name;
+    }
+  });
+  if (imported.isNull()) {
+    return nullptr;
+  }
+  // find a global inited to it
+  Global* ret = nullptr;
+  ModuleUtils::iterDefinedGlobals(wasm, [&](Global* defined) {
+    if (auto* init = defined->init->dynCast<GlobalGet>()) {
+      if (init->name == imported) {
+        ret = defined;
+      }
+    }
+  });
+  return ret;
+}
+
+inline bool canInitializeGlobal(const Expression* curr) {
+  if (auto* tuple = curr->dynCast<TupleMake>()) {
+    for (auto* op : tuple->operands) {
+      if (!Properties::isSingleConstantExpression(op) && !op->is<GlobalGet>()) {
+        return false;
+      }
+    }
+    return true;
+  }
+  return Properties::isSingleConstantExpression(curr) || curr->is<GlobalGet>();
+}
+
+} // namespace GlobalUtils
+
+} // namespace wasm
+
+#endif // wasm_ir_global_h
diff --git a/binaryen/src/ir/hashed.h b/binaryen/src/ir/hashed.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/hashed.h
@@ -0,0 +1,82 @@
+/*
+ * 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_ir_hashed_h
+#define _wasm_ir_hashed_h
+
+#include "ir/utils.h"
+#include "support/hash.h"
+#include "wasm.h"
+
+namespace wasm {
+
+// An expression with a cached hash value
+struct HashedExpression {
+  Expression* expr;
+  size_t digest;
+
+  HashedExpression(Expression* expr) : expr(expr) {
+    if (expr) {
+      digest = ExpressionAnalyzer::hash(expr);
+    } else {
+      digest = hash(0);
+    }
+  }
+
+  HashedExpression(const HashedExpression& other)
+    : expr(other.expr), digest(other.digest) {}
+};
+
+// A pass that hashes all functions
+
+struct FunctionHasher : public WalkerPass<PostWalker<FunctionHasher>> {
+  bool isFunctionParallel() override { return true; }
+
+  struct Map : public std::map<Function*, size_t> {};
+
+  FunctionHasher(Map* output) : output(output) {}
+
+  FunctionHasher* create() override { return new FunctionHasher(output); }
+
+  static Map createMap(Module* module) {
+    Map hashes;
+    for (auto& func : module->functions) {
+      // ensure an entry for each function - we must not modify the map shape in
+      // parallel, just the values
+      hashes[func.get()] = hash(0);
+    }
+    return hashes;
+  }
+
+  void doWalkFunction(Function* func) { output->at(func) = hashFunction(func); }
+
+  static size_t hashFunction(Function* func) {
+    auto digest = hash(func->sig.params.getID());
+    rehash(digest, func->sig.results.getID());
+    for (auto type : func->vars) {
+      rehash(digest, type.getID());
+    }
+    hash_combine(digest, ExpressionAnalyzer::hash(func->body));
+    return digest;
+  }
+
+private:
+  Map* output;
+};
+
+} // namespace wasm
+
+#endif // _wasm_ir_hashed_h
diff --git a/binaryen/src/ir/import-utils.h b/binaryen/src/ir/import-utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/import-utils.h
@@ -0,0 +1,106 @@
+/*
+ * 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_ir_import_h
+#define wasm_ir_import_h
+
+#include "literal.h"
+#include "wasm.h"
+
+namespace wasm {
+
+// Collects info on imports, into a form convenient for summarizing
+// and searching.
+struct ImportInfo {
+  Module& wasm;
+
+  std::vector<Global*> importedGlobals;
+  std::vector<Function*> importedFunctions;
+  std::vector<Event*> importedEvents;
+
+  ImportInfo(Module& wasm) : wasm(wasm) {
+    for (auto& import : wasm.globals) {
+      if (import->imported()) {
+        importedGlobals.push_back(import.get());
+      }
+    }
+    for (auto& import : wasm.functions) {
+      if (import->imported()) {
+        importedFunctions.push_back(import.get());
+      }
+    }
+    for (auto& import : wasm.events) {
+      if (import->imported()) {
+        importedEvents.push_back(import.get());
+      }
+    }
+  }
+
+  Global* getImportedGlobal(Name module, Name base) {
+    for (auto* import : importedGlobals) {
+      if (import->module == module && import->base == base) {
+        return import;
+      }
+    }
+    return nullptr;
+  }
+
+  Function* getImportedFunction(Name module, Name base) {
+    for (auto* import : importedFunctions) {
+      if (import->module == module && import->base == base) {
+        return import;
+      }
+    }
+    return nullptr;
+  }
+
+  Event* getImportedEvent(Name module, Name base) {
+    for (auto* import : importedEvents) {
+      if (import->module == module && import->base == base) {
+        return import;
+      }
+    }
+    return nullptr;
+  }
+
+  Index getNumImportedGlobals() { return importedGlobals.size(); }
+
+  Index getNumImportedFunctions() { return importedFunctions.size(); }
+
+  Index getNumImportedEvents() { return importedEvents.size(); }
+
+  Index getNumImports() {
+    return getNumImportedGlobals() + getNumImportedFunctions() +
+           getNumImportedEvents() + (wasm.memory.imported() ? 1 : 0) +
+           (wasm.table.imported() ? 1 : 0);
+  }
+
+  Index getNumDefinedGlobals() {
+    return wasm.globals.size() - getNumImportedGlobals();
+  }
+
+  Index getNumDefinedFunctions() {
+    return wasm.functions.size() - getNumImportedFunctions();
+  }
+
+  Index getNumDefinedEvents() {
+    return wasm.events.size() - getNumImportedEvents();
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_ir_import_h
diff --git a/binaryen/src/ir/iteration.h b/binaryen/src/ir/iteration.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/iteration.h
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+#ifndef wasm_ir_iteration_h
+#define wasm_ir_iteration_h
+
+#include "ir/properties.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
+
+namespace wasm {
+
+//
+// Allows iteration over the children of the expression, in order of execution
+// where relevant.
+//
+//  * This skips missing children, e.g. if an if has no else, it is represented
+//    as having 2 children (and not 3 with the last a nullptr).
+//
+// In general, it is preferable not to use this class and to directly access the
+// children (using e.g. iff->ifTrue etc.), as that is faster. However, in cases
+// where speed does not matter, this can be convenient. TODO: reimplement these
+// to avoid materializing all the chilren at once.
+//
+//   ChildIterator - Iterates over all children
+//
+//   ValueChildIterator - Iterates over all children that produce values used by
+//                        this instruction. For example, includes If::condition
+//                        but not If::ifTrue.
+//
+template<template<class, class> class Scanner> class AbstractChildIterator {
+  using Self = AbstractChildIterator<Scanner>;
+  struct Iterator {
+    const Self& parent;
+    Index index;
+
+    Iterator(const Self& parent, Index index) : parent(parent), index(index) {}
+
+    bool operator!=(const Iterator& other) const {
+      return index != other.index || &parent != &(other.parent);
+    }
+
+    void operator++() { index++; }
+
+    Expression* operator*() { return parent.children[index]; }
+  };
+
+public:
+  SmallVector<Expression*, 4> children;
+
+  AbstractChildIterator(Expression* parent) {
+    struct Traverser : public PostWalker<Traverser> {
+      Expression* parent;
+      SmallVector<Expression*, 4>* children;
+
+      // We need to scan subchildren exactly once - just the parent.
+      bool scanned = false;
+
+      static void scan(Traverser* self, Expression** currp) {
+        if (!self->scanned) {
+          self->scanned = true;
+          Scanner<Traverser, UnifiedExpressionVisitor<Traverser>>::scan(self,
+                                                                        currp);
+        } else {
+          // This is one of the children. Do not scan further, just note it.
+          self->children->push_back(*currp);
+        }
+      }
+    } traverser;
+    traverser.parent = parent;
+    traverser.children = &children;
+    traverser.walk(parent);
+  }
+
+  Iterator begin() const { return Iterator(*this, 0); }
+  Iterator end() const { return Iterator(*this, children.size()); }
+};
+
+template<class SubType, class Visitor>
+struct ValueChildScanner : PostWalker<SubType, Visitor> {
+  static void scan(SubType* self, Expression** currp) {
+    auto* curr = *currp;
+    if (Properties::isControlFlowStructure(curr)) {
+      // If conditions are the only value children of control flow structures
+      if (auto* iff = curr->dynCast<If>()) {
+        self->pushTask(SubType::scan, &iff->condition);
+      }
+    } else {
+      // All children on non-control flow expressions are value children
+      PostWalker<SubType, Visitor>::scan(self, currp);
+    }
+  }
+};
+
+using ChildIterator = AbstractChildIterator<PostWalker>;
+using ValueChildIterator = AbstractChildIterator<ValueChildScanner>;
+
+// Returns true if the current expression contains a certain kind of expression,
+// within the given depth of BFS. If depth is -1, this searches all children.
+template<typename T> bool containsChild(Expression* parent, int depth = -1) {
+  std::vector<Expression*> exprs;
+  std::vector<Expression*> nextExprs;
+  exprs.push_back(parent);
+  while (!exprs.empty() && depth > 0) {
+    for (auto* expr : exprs) {
+      for (auto* child : ChildIterator(expr)) {
+        if (child->is<T>()) {
+          return true;
+        }
+        nextExprs.push_back(child);
+      }
+    }
+    exprs.swap(nextExprs);
+    nextExprs.clear();
+    if (depth > 0) {
+      depth--;
+    }
+  }
+  return false;
+}
+
+} // namespace wasm
+
+#endif // wasm_ir_iteration_h
diff --git a/binaryen/src/ir/label-utils.h b/binaryen/src/ir/label-utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/label-utils.h
@@ -0,0 +1,55 @@
+/*
+ * 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_ir_label_h
+#define wasm_ir_label_h
+
+#include "wasm-traversal.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace LabelUtils {
+
+// Handles branch/loop labels in a function; makes it easy to add new
+// ones without duplicates
+class LabelManager : public PostWalker<LabelManager> {
+public:
+  LabelManager(Function* func) { walkFunction(func); }
+
+  Name getUnique(std::string prefix) {
+    while (1) {
+      auto curr = Name(prefix + std::to_string(counter++));
+      if (labels.find(curr) == labels.end()) {
+        labels.insert(curr);
+        return curr;
+      }
+    }
+  }
+
+  void visitBlock(Block* curr) { labels.insert(curr->name); }
+  void visitLoop(Loop* curr) { labels.insert(curr->name); }
+
+private:
+  std::set<Name> labels;
+  size_t counter = 0;
+};
+
+} // namespace LabelUtils
+
+} // namespace wasm
+
+#endif // wasm_ir_label_h
diff --git a/binaryen/src/ir/literal-utils.h b/binaryen/src/ir/literal-utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/literal-utils.h
@@ -0,0 +1,48 @@
+/*
+ * 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_ir_literal_utils_h
+#define wasm_ir_literal_utils_h
+
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace LiteralUtils {
+
+inline Expression* makeFromInt32(int32_t x, Type type, Module& wasm) {
+  auto* ret = wasm.allocator.alloc<Const>();
+  ret->value = Literal::makeFromInt32(x, type);
+  ret->type = type;
+  return ret;
+}
+
+inline Expression* makeZero(Type type, Module& wasm) {
+  // TODO: Remove this function once V8 supports v128.const
+  // (https://bugs.chromium.org/p/v8/issues/detail?id=8460)
+  Builder builder(wasm);
+  if (type == Type::v128) {
+    return builder.makeUnary(SplatVecI32x4, builder.makeConst(int32_t(0)));
+  }
+  return builder.makeConstantExpression(Literal::makeZeros(type));
+}
+
+} // namespace LiteralUtils
+
+} // namespace wasm
+
+#endif // wasm_ir_literal_utils_h
diff --git a/binaryen/src/ir/load-utils.h b/binaryen/src/ir/load-utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/load-utils.h
@@ -0,0 +1,44 @@
+/*
+ * 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_ir_load_h
+#define wasm_ir_load_h
+
+#include "wasm.h"
+
+namespace wasm {
+
+namespace LoadUtils {
+
+// checks if the sign of a load matters, which is when an integer
+// load is of fewer bytes than the size of the type (so we must
+// fill in bits either signed or unsigned wise)
+inline bool isSignRelevant(Load* load) {
+  auto type = load->type;
+  if (load->type == Type::unreachable) {
+    return false;
+  }
+  return !type.isFloat() && load->bytes < type.getByteSize();
+}
+
+// check if a load can be signed (which some opts want to do)
+inline bool canBeSigned(Load* load) { return !load->isAtomic; }
+
+} // namespace LoadUtils
+
+} // namespace wasm
+
+#endif // wasm_ir_load_h
diff --git a/binaryen/src/ir/local-graph.h b/binaryen/src/ir/local-graph.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/local-graph.h
@@ -0,0 +1,92 @@
+/*
+ * 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_ir_local_graph_h
+#define wasm_ir_local_graph_h
+
+#include "wasm.h"
+
+namespace wasm {
+
+//
+// Finds the connections between local.gets and local.sets, creating
+// a graph of those ties. This is useful for "ssa-style" optimization,
+// in which you want to know exactly which sets are relevant for a
+// a get, so it is as if each get has just one set, logically speaking
+// (see the SSA pass for actually creating new local indexes based
+// on this).
+//
+struct LocalGraph {
+  // main API
+
+  // the constructor computes getSetses, the sets affecting each get
+  LocalGraph(Function* func);
+
+  // the local.sets relevant for an index or a get.
+  typedef std::set<LocalSet*> Sets;
+
+  typedef std::map<LocalGet*, Sets> GetSetses;
+
+  typedef std::map<Expression*, Expression**> Locations;
+
+  // externally useful information
+  GetSetses getSetses; // the sets affecting each get. a nullptr set means the
+                       // initial value (0 for a var, the received value for a
+                       // param)
+  Locations locations; // where each get and set is (for easy replacing)
+
+  // Optional: compute the influence graphs between sets and gets
+  // (useful for algorithms that propagate changes).
+
+  void computeInfluences();
+
+  // for each get, the sets whose values are influenced by that get
+  std::unordered_map<LocalGet*, std::unordered_set<LocalSet*>> getInfluences;
+  // for each set, the gets whose values are influenced by that set
+  std::unordered_map<LocalSet*, std::unordered_set<LocalGet*>> setInfluences;
+
+  // Optional: Compute the local indexes that are SSA, in the sense of
+  //  * a single set for all the gets for that local index
+  //  * the set dominates all the gets (logically implied by the former
+  //  property)
+  //  * no other set (aside from the zero-init)
+  // The third property is not exactly standard SSA, but is useful since we are
+  // not in SSA form in our IR. To see why it matters, consider these:
+  //
+  // x = 0 // zero init
+  // [..]
+  // x = 10
+  // y = x + 20
+  // x = 30 // !!!
+  // f(y)
+  //
+  // The !!! line violates that property - it is another set for x, and it may
+  // interfere say with replacing f(y) with f(x + 20). Instead, if we know the
+  // only other possible set for x is the zero init, then things like the !!!
+  // line cannot exist, and it is valid to replace f(y) with f(x + 20). (This
+  // could be simpler, but in wasm the zero init always exists.)
+
+  void computeSSAIndexes();
+
+  bool isSSA(Index x);
+
+private:
+  std::set<Index> SSAIndexes;
+};
+
+} // namespace wasm
+
+#endif // wasm_ir_local_graph_h
diff --git a/binaryen/src/ir/local-utils.h b/binaryen/src/ir/local-utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/local-utils.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2019 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_ir_local_utils_h
+#define wasm_ir_local_utils_h
+
+#include <ir/effects.h>
+#include <ir/manipulation.h>
+
+namespace wasm {
+
+struct LocalGetCounter : public PostWalker<LocalGetCounter> {
+  std::vector<Index> num;
+
+  LocalGetCounter() = default;
+  LocalGetCounter(Function* func) { analyze(func, func->body); }
+  LocalGetCounter(Function* func, Expression* ast) { analyze(func, ast); }
+
+  void analyze(Function* func) { analyze(func, func->body); }
+  void analyze(Function* func, Expression* ast) {
+    num.resize(func->getNumLocals());
+    std::fill(num.begin(), num.end(), 0);
+    walk(ast);
+  }
+
+  void visitLocalGet(LocalGet* curr) { num[curr->index]++; }
+};
+
+// Removes trivially unneeded sets: sets for whom there is no possible get, and
+// sets of the same value immediately.
+struct UnneededSetRemover : public PostWalker<UnneededSetRemover> {
+  PassOptions& passOptions;
+
+  LocalGetCounter* localGetCounter = nullptr;
+  FeatureSet features;
+
+  UnneededSetRemover(Function* func,
+                     PassOptions& passOptions,
+                     FeatureSet features)
+    : passOptions(passOptions), features(features) {
+    LocalGetCounter counter(func);
+    UnneededSetRemover inner(counter, func, passOptions, features);
+    removed = inner.removed;
+  }
+
+  UnneededSetRemover(LocalGetCounter& localGetCounter,
+                     Function* func,
+                     PassOptions& passOptions,
+                     FeatureSet features)
+    : passOptions(passOptions), localGetCounter(&localGetCounter),
+      features(features) {
+    walk(func->body);
+  }
+
+  bool removed = false;
+
+  void visitLocalSet(LocalSet* curr) {
+    // If no possible uses, remove.
+    if (localGetCounter->num[curr->index] == 0) {
+      remove(curr);
+    }
+    // If setting the same value as we already have, remove.
+    auto* value = curr->value;
+    while (true) {
+      if (auto* set = value->dynCast<LocalSet>()) {
+        if (set->index == curr->index) {
+          remove(curr);
+        } else {
+          // Handle tee chains.
+          value = set->value;
+          continue;
+        }
+      } else if (auto* get = value->dynCast<LocalGet>()) {
+        if (get->index == curr->index) {
+          remove(curr);
+        }
+      }
+      break;
+    }
+  }
+
+  void remove(LocalSet* set) {
+    auto* value = set->value;
+    if (set->isTee()) {
+      replaceCurrent(value);
+    } else if (EffectAnalyzer(passOptions, features, set->value)
+                 .hasSideEffects()) {
+      Drop* drop = ExpressionManipulator::convert<LocalSet, Drop>(set);
+      drop->value = value;
+      drop->finalize();
+    } else {
+      ExpressionManipulator::nop(set);
+    }
+    removed = true;
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_ir_local_utils_h
diff --git a/binaryen/src/ir/localize.h b/binaryen/src/ir/localize.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/localize.h
@@ -0,0 +1,46 @@
+/*
+ * 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_ir_localizer_h
+#define wasm_ir_localizer_h
+
+#include <wasm-builder.h>
+
+namespace wasm {
+
+// Make an expression available in a local. If already in one, just
+// use that local, otherwise use a new local
+
+struct Localizer {
+  Index index;
+  Expression* expr;
+
+  Localizer(Expression* input, Function* func, Module* wasm) {
+    expr = input;
+    if (auto* get = expr->dynCast<LocalGet>()) {
+      index = get->index;
+    } else if (auto* set = expr->dynCast<LocalSet>()) {
+      index = set->index;
+    } else {
+      index = Builder::addVar(func, expr->type);
+      expr = Builder(*wasm).makeLocalTee(index, expr, expr->type);
+    }
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_ir_localizer_h
diff --git a/binaryen/src/ir/manipulation.h b/binaryen/src/ir/manipulation.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/manipulation.h
@@ -0,0 +1,82 @@
+/*
+ * 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_ir_manipulation_h
+#define wasm_ir_manipulation_h
+
+#include "wasm.h"
+
+namespace wasm {
+
+namespace ExpressionManipulator {
+// Re-use a node's memory. This helps avoid allocation when optimizing.
+template<typename InputType, typename OutputType>
+inline OutputType* convert(InputType* input) {
+  static_assert(sizeof(OutputType) <= sizeof(InputType),
+                "Can only convert to a smaller size Expression node");
+  input->~InputType(); // arena-allocaed, so no destructor, but avoid UB.
+  OutputType* output = (OutputType*)(input);
+  new (output) OutputType;
+  return output;
+}
+
+// Convenience methods for certain instructions, which are common conversions
+template<typename InputType> inline Nop* nop(InputType* target) {
+  auto* ret = convert<InputType, Nop>(target);
+  ret->finalize();
+  return ret;
+}
+
+template<typename InputType>
+inline RefNull* refNull(InputType* target, Type type) {
+  auto* ret = convert<InputType, RefNull>(target);
+  ret->finalize(type);
+  return ret;
+}
+
+template<typename InputType>
+inline Unreachable* unreachable(InputType* target) {
+  auto* ret = convert<InputType, Unreachable>(target);
+  ret->finalize();
+  return ret;
+}
+
+// Convert a node that allocates
+template<typename InputType, typename OutputType>
+inline OutputType* convert(InputType* input, MixedArena& allocator) {
+  assert(sizeof(OutputType) <= sizeof(InputType));
+  input->~InputType(); // arena-allocaed, so no destructor, but avoid UB.
+  OutputType* output = (OutputType*)(input);
+  new (output) OutputType(allocator);
+  return output;
+}
+
+using CustomCopier = std::function<Expression*(Expression*)>;
+Expression*
+flexibleCopy(Expression* original, Module& wasm, CustomCopier custom);
+
+inline Expression* copy(Expression* original, Module& wasm) {
+  auto copy = [](Expression* curr) { return nullptr; };
+  return flexibleCopy(original, wasm, copy);
+}
+
+// Splice an item into the middle of a block's list
+void spliceIntoBlock(Block* block, Index index, Expression* add);
+} // namespace ExpressionManipulator
+
+} // namespace wasm
+
+#endif // wams_ir_manipulation_h
diff --git a/binaryen/src/ir/match.h b/binaryen/src/ir/match.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/match.h
@@ -0,0 +1,848 @@
+/*
+ * 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.
+ */
+
+//
+// match.h - Provides an easily extensible layered API for matching expression
+// patterns and extracting their components. The low-level API provides modular
+// building blocks for creating matchers for any data type and the high-level
+// API provides a succinct and flexible interface for matching expressions and
+// extracting useful information from them.
+
+#ifndef wasm_ir_match_h
+#define wasm_ir_match_h
+
+#include "ir/abstract.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace Match {
+
+// The available matchers are:
+//
+//  i32, i64, f32, f64
+//
+//    Match constants of the corresponding type. Takes zero or one argument. The
+//    argument can be a specific value to match or it can be a pointer to a
+//    value, Literal, or Const* at which to store the matched entity.
+//
+//  ival, fval
+//
+//    Match any integer constant or any floating point constant. Takes neither,
+//    either, or both of two possible arguments: first, a pointer to a value,
+//    Literal, or Const* at which to store the matched entity and second, a
+//    specific value to match.
+//
+//  constant
+//
+//    Matches any numeric Const expression. Takes neither, either, or both of
+//    two possible arguments: first, a pointer to either Literal or Const* at
+//    which to store the matched entity and second, a specific value (given as
+//    an int32_t) to match..
+//
+//  any
+//
+//    Matches any Expression. Optionally takes as an argument a pointer to
+//    Expression* at which to store the matched Expression*.
+//
+//  unary
+//
+//    Matches Unary expressions. Takes an optional pointer to Unary* at which to
+//    store the matched Unary*, followed by either a UnaryOp or an Abstract::Op
+//    describing which unary expressions to match, followed by a matcher to
+//    apply to the unary expression's operand.
+//
+//  binary
+//
+//    Matches Binary expressions. Takes an optional pointer to Binary* at which
+//    to store the matched Binary*, followed by either a BinaryOp or an
+//    Abstract::Op describing which binary expresions to match, followed by
+//    matchers to apply to the binary expression's left and right operands.
+//
+//  select
+//
+//    Matches Select expressions. Takes an optional pointer to Select* at which
+//    to store the matched Select*, followed by matchers to apply to the ifTrue,
+//    ifFalse, and condition operands.
+//
+//
+// How to create new matchers:
+//
+//  Lets add a matcher for an expression type that is declared in wasm.h:
+//
+//    class Frozzle : public SpecificExpression<Expression::FrozzleId> {
+//    public:
+//      Expression* foo;
+//      Expression* bar;
+//      Expression* baz;
+//    };
+//
+//  This expression is very simple; in order to match it, all we need to do is
+//  apply other matchers to its subexpressions. The matcher infrastructure will
+//  handle this automatically once we tell it how to access the subexpressions.
+//  To tell the matcher infrastructure how many subexpressions there are we need
+//  to specialize `NumComponents`.
+//
+//    template<> struct NumComponents<Frozzle*> {
+//      static constexpr size_t value = 3;
+//    };
+//
+//  And to tell the matcher infrastructure how to access those three
+//  subexpressions, we need to specialize `GetComponent` three times.
+//
+//    template<> struct GetComponent<Frozzle*, 0> {
+//      Expression* operator()(Frozzle* curr) { return curr->foo; }
+//    };
+//    template<> struct GetComponent<Frozzle*, 1> {
+//      Expression* operator()(Frozzle* curr) { return curr->bar; }
+//    };
+//    template<> struct GetComponent<Frozzle*, 2> {
+//      Expression* operator()(Frozzle* curr) { return curr->baz; }
+//    };
+//
+//  For simple expressions, that's all we need to do to get a fully functional
+//  matcher that we can construct and use like this, where S1, S2, and S3 are
+//  the types of the submatchers to use and s1, s2, and s3 are instances of
+//  those types:
+//
+//    Frozzle* extracted;
+//    auto matcher = Matcher<Frozzle*, S1, S2, S3>(&extracted, {}, s1, s2, s3);
+//    if (matches(expr, matcher)) {
+//      // `extracted` set to `expr` here
+//    }
+//
+//  It's annoying to have to write out the types S1, S2, and S3 and we don't get
+//  class template argument deduction (CTAD) until C++17, so it's useful to
+//  create a wrapper function so can take advantage of function template
+//  argument deduction. We can also take this opportunity to make the interface
+//  more compact.
+//
+//    template<class S1, class S2, class S3>
+//    inline decltype(auto) frozzle(Frozzle** binder,
+//                                  S1&& s1, S2&& s2, S3&& s3) {
+//      return Matcher<Frozzle*, S1, S2, S3>(binder, {}, s1, s2, s3);
+//    }
+//    template<class S1, class S2, class S3>
+//    inline decltype(auto) frozzle(S1&& s1, S2&& s2, S3&& s3) {
+//      return Matcher<Frozzle*, S1, S2, S3>(nullptr, {}, s1, s2, s3);
+//    }
+//
+//  Notice that we make the interface more compact by providing overloads with
+//  and without the binder. Here is the final matcher usage:
+//
+//    Frozzle* extracted;
+//    if (matches(expr, frozzle(&extracted, s1, s2, s3))) {
+//      // `extracted` set to `expr` here
+//    }
+//
+//  Some matchers are more complicated, though, because they need to do
+//  something besides just applying submatchers to the components of an
+//  expression. These matchers require slightly more work.
+//
+//
+// Complex matchers:
+//
+//  Lets add a matcher that will match calls to functions whose names start with
+//  certain prefixes. Since this is not a normal matcher for Call expressions,
+//  we can't identify it by the Call* type. Instead, we have to create a new
+//  identifier type, called a "Kind" for it.
+//
+//    struct PrefixCallKind {};
+//
+//  Next, since we're not in the common case of using a specific expression
+//  pointer as our kind, we have to tell the matcher infrastructure what type of
+//  thing this matcher matches. Since we want this matcher to be able to match
+//  any given prefix, we also need the matcher to contain the given prefix as
+//  state, and we need to tell the matcher infrastructure what type that state
+//  is as well. To specify these types, we need to specialize
+//  `KindTypeRegistry` for `PrefixCallKind`.
+//
+//    template<> struct KindTypeRegistry<PrefixCallKind> {
+//      using matched_t = Call*;
+//      using data_t = Name;
+//    };
+//
+//  Note that because `matched_t` is set to a specific expression pointer, this
+//  matcher will automatically be able to be applied to any `Expression*`, not
+//  just `Call*`. If `matched_t` were not a specific expression pointer, this
+//  matcher would only be able to be applied to types compatible with
+//  `matched_t`. Also note that if a matcher does not need to store any state,
+//  its `data_t` should be set to `unused_t`.
+//
+//  Now we need to tell the matcher infrastructure what custom logic to apply
+//  for this matcher. We do this by specializing `MatchSelf`.
+//
+//    template<> struct MatchSelf<PrefixCallKind> {
+//      bool operator()(Call* curr, Name prefix) {
+//        return curr->name.startsWith(prefix);
+//      }
+//    };
+//
+//  Note that the first parameter to `MatchSelf<Kind>::operator()` will be that
+//  kind's `matched_t` and the second parameter will be that kind's `data_t`,
+//  which may be `unused_t`. (TODO: detect if `data_t` is `unused_t` and don't
+//  expose it in the Matcher interface if so.)
+//
+//  After this, everything is the same as in the simple matcher case. This
+//  particular matcher doesn't need to recurse into any subcomponents, so we can
+//  skip straight to creating the wrapper function.
+//
+//    decltype(auto) prefixCall(Call** binder, Name prefix) {
+//      return Matcher<PrefixCallKind>(binder, prefix);
+//    }
+//
+//  Now we can use the new matcher:
+//
+//    Call* call;
+//    if (matches(expr, prefixCall(&call, "__foo"))) {
+//      // `call` set to `expr` here
+//    }
+//
+
+// The main entrypoint for matching. If the match succeeds, all variables bound
+// in the matcher will be set to their corresponding matched values. Otherwise,
+// the value of the bound variables is unspecified and may have changed.
+template<class Matcher> inline bool matches(Expression* expr, Matcher matcher) {
+  return matcher.matches(expr);
+}
+
+namespace Internal {
+
+struct unused_t {};
+
+// Each matcher has a `Kind`, which controls how candidate values are
+// destructured and inspected. For most matchers, `Kind` is a pointer to the
+// matched subtype of Expression, but when there are multiple matchers for the
+// same kind of expression, they are disambiguated by having different `Kind`s.
+// In this case, or if the matcher matches something besides a pointer to a
+// subtype of Expression, or if the matcher requires additional state, the
+// matched type and the type of additional state must be associated with the
+// `Kind` via a specialization of `KindTypeRegistry`.
+template<class Kind> struct KindTypeRegistry {
+  // The matched type
+  using matched_t = void;
+  // The type of additional state needed to perform a match. Can be set to
+  // `unused_t` if it's not needed.
+  using data_t = unused_t;
+};
+
+// Given a `Kind`, produce the type `matched_t` that is matched by that Kind and
+// the type `candidate_t` that is the type of the parameter of the `matches`
+// method. These types are only different if `matched_t` is a pointer to a
+// subtype of Expression, in which case `candidate_t` is Expression*.
+template<class Kind> struct MatchTypes {
+  using matched_t = typename std::conditional_t<
+    std::is_base_of<Expression, std::remove_pointer_t<Kind>>::value,
+    Kind,
+    typename KindTypeRegistry<Kind>::matched_t>;
+
+  static constexpr bool isExpr =
+    std::is_base_of<Expression, std::remove_pointer_t<matched_t>>::value;
+
+  using candidate_t =
+    typename std::conditional_t<isExpr, Expression*, matched_t>;
+};
+
+template<class Kind> using matched_t = typename MatchTypes<Kind>::matched_t;
+template<class Kind> using candidate_t = typename MatchTypes<Kind>::candidate_t;
+template<class Kind> using data_t = typename KindTypeRegistry<Kind>::data_t;
+
+// Defined if the matched type is a specific expression pointer, so can be
+// `dynCast`ed to from Expression*.
+template<class Kind>
+using enable_if_castable_t = typename std::enable_if<
+  std::is_base_of<Expression, std::remove_pointer_t<matched_t<Kind>>>::value &&
+    !std::is_same<Expression*, matched_t<Kind>>::value,
+  int>::type;
+
+// Opposite of above
+template<class Kind>
+using enable_if_not_castable_t = typename std::enable_if<
+  !std::is_base_of<Expression, std::remove_pointer_t<matched_t<Kind>>>::value ||
+    std::is_same<Expression*, matched_t<Kind>>::value,
+  int>::type;
+
+// Do a normal dynCast from Expression* to the subtype, storing the result in
+// `out` and returning `true` iff the cast succeeded.
+template<class Kind, enable_if_castable_t<Kind> = 0>
+inline bool dynCastCandidate(candidate_t<Kind> candidate,
+                             matched_t<Kind>& out) {
+  out = candidate->template dynCast<std::remove_pointer_t<matched_t<Kind>>>();
+  return out != nullptr;
+}
+
+// Otherwise we are not matching an Expression, so this is infallible.
+template<class Kind, enable_if_not_castable_t<Kind> = 0>
+inline bool dynCastCandidate(candidate_t<Kind> candidate,
+                             matched_t<Kind>& out) {
+  out = candidate;
+  return true;
+}
+
+// Matchers can optionally specialize this to perform custom matching logic
+// before recursing into submatchers, potentially short-circuiting the match.
+// Uses a struct because partial specialization of functions is not allowed.
+template<class Kind> struct MatchSelf {
+  bool operator()(matched_t<Kind>, data_t<Kind>) { return true; }
+};
+
+// Used to statically ensure that each matcher has the correct number of
+// submatchers. This needs to be specialized for each kind of matcher that has
+// submatchers.
+template<class Kind> struct NumComponents {
+  static constexpr size_t value = 0;
+};
+
+// Every kind of matcher needs to partially specialize this for each of its
+// components. Each specialization should define
+//
+//   T operator()(matched_t<Kind>)
+//
+// where T is the component's type. Components will be matched from first to
+// last. Uses a struct instead of a function because partial specialization of
+// functions is not allowed.
+template<class Kind, int pos> struct GetComponent;
+
+// A type-level linked list to hold an arbitrary number of matchers.
+template<class...> struct SubMatchers {};
+template<class CurrMatcher, class... NextMatchers>
+struct SubMatchers<CurrMatcher, NextMatchers...> {
+  CurrMatcher curr;
+  SubMatchers<NextMatchers...> next;
+  SubMatchers(CurrMatcher curr, NextMatchers... next)
+    : curr(curr), next(next...){};
+};
+
+// Iterates through the components of the candidate, applying a submatcher to
+// each component. Uses a struct instead of a function because partial
+// specialization of functions is not allowed.
+template<class Kind, int pos, class CurrMatcher = void, class... NextMatchers>
+struct Components {
+  static inline bool
+  match(matched_t<Kind> candidate,
+        SubMatchers<CurrMatcher, NextMatchers...>& matchers) {
+    return matchers.curr.matches(GetComponent<Kind, pos>{}(candidate)) &&
+           Components<Kind, pos + 1, NextMatchers...>::match(candidate,
+                                                             matchers.next);
+  }
+};
+template<class Kind, int pos> struct Components<Kind, pos> {
+  static_assert(pos == NumComponents<Kind>::value,
+                "Unexpected number of submatchers");
+  static inline bool match(matched_t<Kind>, SubMatchers<>) {
+    // Base case when there are no components left; trivially true.
+    return true;
+  }
+};
+
+template<class Kind, class... Matchers> struct Matcher {
+  matched_t<Kind>* binder;
+  data_t<Kind> data;
+  SubMatchers<Matchers...> submatchers;
+
+  Matcher(matched_t<Kind>* binder, data_t<Kind> data, Matchers... submatchers)
+    : binder(binder), data(data), submatchers(submatchers...) {}
+
+  inline bool matches(candidate_t<Kind> candidate) {
+    matched_t<Kind> casted;
+    if (dynCastCandidate<Kind>(candidate, casted)) {
+      if (binder != nullptr) {
+        *binder = casted;
+      }
+      return MatchSelf<Kind>{}(casted, data) &&
+             Components<Kind, 0, Matchers...>::match(casted, submatchers);
+    }
+    return false;
+  }
+};
+
+// Concrete low-level matcher implementations. Not intended for direct external
+// use.
+
+// Any<T>: matches any value of the expected type
+template<class T> struct AnyKind {};
+template<class T> struct KindTypeRegistry<AnyKind<T>> {
+  using matched_t = T;
+  using data_t = unused_t;
+};
+template<class T> inline decltype(auto) Any(T* binder) {
+  return Matcher<AnyKind<T>>(binder, {});
+}
+
+// Exact<T>: matches exact values of the expected type
+template<class T> struct ExactKind {};
+template<class T> struct KindTypeRegistry<ExactKind<T>> {
+  using matched_t = T;
+  using data_t = T;
+};
+template<class T> struct MatchSelf<ExactKind<T>> {
+  bool operator()(T self, T expected) { return self == expected; }
+};
+template<class T> inline decltype(auto) Exact(T* binder, T data) {
+  return Matcher<ExactKind<T>>(binder, data);
+}
+
+// {I32,I64,Int,F32,F64,Float,Number}Lit: match `Literal` of the expected `Type`
+struct I32LK {
+  static bool matchType(Literal lit) { return lit.type == Type::i32; }
+  static int32_t getVal(Literal lit) { return lit.geti32(); }
+};
+struct I64LK {
+  static bool matchType(Literal lit) { return lit.type == Type::i64; }
+  static int64_t getVal(Literal lit) { return lit.geti64(); }
+};
+struct IntLK {
+  static bool matchType(Literal lit) { return lit.type.isInteger(); }
+  static int64_t getVal(Literal lit) { return lit.getInteger(); }
+};
+struct F32LK {
+  static bool matchType(Literal lit) { return lit.type == Type::f32; }
+  static float getVal(Literal lit) { return lit.getf32(); }
+};
+struct F64LK {
+  static bool matchType(Literal lit) { return lit.type == Type::f64; }
+  static double getVal(Literal lit) { return lit.getf64(); }
+};
+struct FloatLK {
+  static bool matchType(Literal lit) { return lit.type.isFloat(); }
+  static double getVal(Literal lit) { return lit.getFloat(); }
+};
+template<class T> struct LitKind {};
+template<class T> struct KindTypeRegistry<LitKind<T>> {
+  using matched_t = Literal;
+  using data_t = unused_t;
+};
+template<class T> struct MatchSelf<LitKind<T>> {
+  bool operator()(Literal lit, unused_t) { return T::matchType(lit); }
+};
+template<class T> struct NumComponents<LitKind<T>> {
+  static constexpr size_t value = 1;
+};
+template<class T> struct GetComponent<LitKind<T>, 0> {
+  decltype(auto) operator()(Literal lit) { return T::getVal(lit); }
+};
+template<class S> inline decltype(auto) I32Lit(Literal* binder, S&& s) {
+  return Matcher<LitKind<I32LK>, S>(binder, {}, s);
+}
+template<class S> inline decltype(auto) I64Lit(Literal* binder, S&& s) {
+  return Matcher<LitKind<I64LK>, S>(binder, {}, s);
+}
+template<class S> inline decltype(auto) IntLit(Literal* binder, S&& s) {
+  return Matcher<LitKind<IntLK>, S>(binder, {}, s);
+}
+template<class S> inline decltype(auto) F32Lit(Literal* binder, S&& s) {
+  return Matcher<LitKind<F32LK>, S>(binder, {}, s);
+}
+template<class S> inline decltype(auto) F64Lit(Literal* binder, S&& s) {
+  return Matcher<LitKind<F64LK>, S>(binder, {}, s);
+}
+template<class S> inline decltype(auto) FloatLit(Literal* binder, S&& s) {
+  return Matcher<LitKind<FloatLK>, S>(binder, {}, s);
+}
+struct NumberLitKind {};
+template<> struct KindTypeRegistry<NumberLitKind> {
+  using matched_t = Literal;
+  using data_t = int32_t;
+};
+template<> struct MatchSelf<NumberLitKind> {
+  bool operator()(Literal lit, int32_t expected) {
+    return lit.type.isNumber() &&
+           Literal::makeFromInt32(expected, lit.type) == lit;
+  }
+};
+inline decltype(auto) NumberLit(Literal* binder, int32_t expected) {
+  return Matcher<NumberLitKind>(binder, expected);
+}
+
+// Const
+template<> struct NumComponents<Const*> { static constexpr size_t value = 1; };
+template<> struct GetComponent<Const*, 0> {
+  Literal operator()(Const* c) { return c->value; }
+};
+template<class S> inline decltype(auto) ConstMatcher(Const** binder, S&& s) {
+  return Matcher<Const*, S>(binder, {}, s);
+}
+
+// Unary, UnaryOp and AbstractUnaryOp
+template<> struct NumComponents<Unary*> { static constexpr size_t value = 2; };
+template<> struct GetComponent<Unary*, 0> {
+  UnaryOp operator()(Unary* curr) { return curr->op; }
+};
+template<> struct GetComponent<Unary*, 1> {
+  Expression* operator()(Unary* curr) { return curr->value; }
+};
+struct UnaryOpK {
+  using Op = UnaryOp;
+  static UnaryOp getOp(Type, Op op) { return op; }
+};
+struct AbstractUnaryOpK {
+  using Op = Abstract::Op;
+  static UnaryOp getOp(Type type, Abstract::Op op) {
+    return Abstract::getUnary(type, op);
+  }
+};
+template<class T> struct UnaryOpKind {};
+template<class T> struct KindTypeRegistry<UnaryOpKind<T>> {
+  using matched_t = Unary*;
+  using data_t = typename T::Op;
+};
+template<class T> struct MatchSelf<UnaryOpKind<T>> {
+  bool operator()(Unary* curr, typename T::Op op) {
+    return curr->op == T::getOp(curr->value->type, op);
+  }
+};
+template<class T> struct NumComponents<UnaryOpKind<T>> {
+  static constexpr size_t value = 1;
+};
+template<class T> struct GetComponent<UnaryOpKind<T>, 0> {
+  Expression* operator()(Unary* curr) { return curr->value; }
+};
+template<class S1, class S2>
+inline decltype(auto) UnaryMatcher(Unary** binder, S1&& s1, S2&& s2) {
+  return Matcher<Unary*, S1, S2>(binder, {}, s1, s2);
+}
+template<class S>
+inline decltype(auto) UnaryOpMatcher(Unary** binder, UnaryOp op, S&& s) {
+  return Matcher<UnaryOpKind<UnaryOpK>, S>(binder, op, s);
+}
+template<class S>
+inline decltype(auto)
+AbstractUnaryOpMatcher(Unary** binder, Abstract::Op op, S&& s) {
+  return Matcher<UnaryOpKind<AbstractUnaryOpK>, S>(binder, op, s);
+}
+
+// Binary, BinaryOp and AbstractBinaryOp
+template<> struct NumComponents<Binary*> { static constexpr size_t value = 3; };
+template<> struct GetComponent<Binary*, 0> {
+  BinaryOp operator()(Binary* curr) { return curr->op; }
+};
+template<> struct GetComponent<Binary*, 1> {
+  Expression* operator()(Binary* curr) { return curr->left; }
+};
+template<> struct GetComponent<Binary*, 2> {
+  Expression* operator()(Binary* curr) { return curr->right; }
+};
+struct BinaryOpK {
+  using Op = BinaryOp;
+  static BinaryOp getOp(Type, Op op) { return op; }
+};
+struct AbstractBinaryOpK {
+  using Op = Abstract::Op;
+  static BinaryOp getOp(Type type, Abstract::Op op) {
+    return Abstract::getBinary(type, op);
+  }
+};
+template<class T> struct BinaryOpKind {};
+template<class T> struct KindTypeRegistry<BinaryOpKind<T>> {
+  using matched_t = Binary*;
+  using data_t = typename T::Op;
+};
+template<class T> struct MatchSelf<BinaryOpKind<T>> {
+  bool operator()(Binary* curr, typename T::Op op) {
+    return curr->op == T::getOp(curr->left->type, op);
+  }
+};
+template<class T> struct NumComponents<BinaryOpKind<T>> {
+  static constexpr size_t value = 2;
+};
+template<class T> struct GetComponent<BinaryOpKind<T>, 0> {
+  Expression* operator()(Binary* curr) { return curr->left; }
+};
+template<class T> struct GetComponent<BinaryOpKind<T>, 1> {
+  Expression* operator()(Binary* curr) { return curr->right; }
+};
+template<class S1, class S2, class S3>
+inline decltype(auto)
+BinaryMatcher(Binary** binder, S1&& s1, S2&& s2, S3&& s3) {
+  return Matcher<Binary*, S1, S2, S3>(binder, {}, s1, s2, s3);
+}
+template<class S1, class S2>
+inline decltype(auto)
+BinaryOpMatcher(Binary** binder, BinaryOp op, S1&& s1, S2&& s2) {
+  return Matcher<BinaryOpKind<BinaryOpK>, S1, S2>(binder, op, s1, s2);
+}
+template<class S1, class S2>
+inline decltype(auto)
+AbstractBinaryOpMatcher(Binary** binder, Abstract::Op op, S1&& s1, S2&& s2) {
+  return Matcher<BinaryOpKind<AbstractBinaryOpK>, S1, S2>(binder, op, s1, s2);
+}
+
+// Select
+template<> struct NumComponents<Select*> { static constexpr size_t value = 3; };
+template<> struct GetComponent<Select*, 0> {
+  Expression* operator()(Select* curr) { return curr->ifTrue; }
+};
+template<> struct GetComponent<Select*, 1> {
+  Expression* operator()(Select* curr) { return curr->ifFalse; }
+};
+template<> struct GetComponent<Select*, 2> {
+  Expression* operator()(Select* curr) { return curr->condition; }
+};
+template<class S1, class S2, class S3>
+inline decltype(auto)
+SelectMatcher(Select** binder, S1&& s1, S2&& s2, S3&& s3) {
+  return Matcher<Select*, S1, S2, S3>(binder, {}, s1, s2, s3);
+}
+
+} // namespace Internal
+
+// Public matching API
+
+inline decltype(auto) i32() {
+  return Internal::ConstMatcher(
+    nullptr, Internal::I32Lit(nullptr, Internal::Any<int32_t>(nullptr)));
+}
+// Use int rather than int32_t to disambiguate literal 0, which otherwise could
+// be resolved to either the int32_t overload or any of the pointer overloads.
+inline decltype(auto) i32(int x) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::I32Lit(nullptr, Internal::Exact<int32_t>(nullptr, x)));
+}
+inline decltype(auto) i32(int32_t* binder) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::I32Lit(nullptr, Internal::Any(binder)));
+}
+inline decltype(auto) i32(Literal* binder) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::I32Lit(binder, Internal::Any<int32_t>(nullptr)));
+}
+inline decltype(auto) i32(Const** binder) {
+  return Internal::ConstMatcher(
+    binder, Internal::I32Lit(nullptr, Internal::Any<int32_t>(nullptr)));
+}
+
+inline decltype(auto) i64() {
+  return Internal::ConstMatcher(
+    nullptr, Internal::I64Lit(nullptr, Internal::Any<int64_t>(nullptr)));
+}
+inline decltype(auto) i64(int64_t x) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::I64Lit(nullptr, Internal::Exact<int64_t>(nullptr, x)));
+}
+// Disambiguate literal 0, which could otherwise be interpreted as a pointer
+inline decltype(auto) i64(int x) { return i64(int64_t(x)); }
+inline decltype(auto) i64(int64_t* binder) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::I64Lit(nullptr, Internal::Any(binder)));
+}
+inline decltype(auto) i64(Literal* binder) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::I64Lit(binder, Internal::Any<int64_t>(nullptr)));
+}
+inline decltype(auto) i64(Const** binder) {
+  return Internal::ConstMatcher(
+    binder, Internal::I64Lit(nullptr, Internal::Any<int64_t>(nullptr)));
+}
+
+inline decltype(auto) f32() {
+  return Internal::ConstMatcher(
+    nullptr, Internal::F32Lit(nullptr, Internal::Any<float>(nullptr)));
+}
+inline decltype(auto) f32(float x) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::F32Lit(nullptr, Internal::Exact<float>(nullptr, x)));
+}
+// Disambiguate literal 0, which could otherwise be interpreted as a pointer
+inline decltype(auto) f32(int x) { return f32(float(x)); }
+inline decltype(auto) f32(float* binder) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::F32Lit(nullptr, Internal::Any(binder)));
+}
+inline decltype(auto) f32(Literal* binder) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::F32Lit(binder, Internal::Any<float>(nullptr)));
+}
+inline decltype(auto) f32(Const** binder) {
+  return Internal::ConstMatcher(
+    binder, Internal::F32Lit(nullptr, Internal::Any<float>(nullptr)));
+}
+
+inline decltype(auto) f64() {
+  return Internal::ConstMatcher(
+    nullptr, Internal::F64Lit(nullptr, Internal::Any<double>(nullptr)));
+}
+inline decltype(auto) f64(double x) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::F64Lit(nullptr, Internal::Exact<double>(nullptr, x)));
+}
+// Disambiguate literal 0, which could otherwise be interpreted as a pointer
+inline decltype(auto) f64(int x) { return f64(double(x)); }
+inline decltype(auto) f64(double* binder) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::F64Lit(nullptr, Internal::Any(binder)));
+}
+inline decltype(auto) f64(Literal* binder) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::F64Lit(binder, Internal::Any<double>(nullptr)));
+}
+inline decltype(auto) f64(Const** binder) {
+  return Internal::ConstMatcher(
+    binder, Internal::F64Lit(nullptr, Internal::Any<double>(nullptr)));
+}
+
+inline decltype(auto) ival() {
+  return Internal::ConstMatcher(
+    nullptr, Internal::IntLit(nullptr, Internal::Any<int64_t>(nullptr)));
+}
+inline decltype(auto) ival(int64_t x) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::IntLit(nullptr, Internal::Exact<int64_t>(nullptr, x)));
+}
+// Disambiguate literal 0, which could otherwise be interpreted as a pointer
+inline decltype(auto) ival(int x) { return ival(int64_t(x)); }
+inline decltype(auto) ival(int64_t* binder) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::IntLit(nullptr, Internal::Any(binder)));
+}
+inline decltype(auto) ival(Literal* binder) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::IntLit(binder, Internal::Any<int64_t>(nullptr)));
+}
+inline decltype(auto) ival(Const** binder) {
+  return Internal::ConstMatcher(
+    binder, Internal::IntLit(nullptr, Internal::Any<int64_t>(nullptr)));
+}
+inline decltype(auto) ival(Literal* binder, int64_t x) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::IntLit(binder, Internal::Exact<int64_t>(nullptr, x)));
+}
+inline decltype(auto) ival(Const** binder, int64_t x) {
+  return Internal::ConstMatcher(
+    binder, Internal::IntLit(nullptr, Internal::Exact<int64_t>(nullptr, x)));
+}
+
+inline decltype(auto) fval() {
+  return Internal::ConstMatcher(
+    nullptr, Internal::FloatLit(nullptr, Internal::Any<double>(nullptr)));
+}
+inline decltype(auto) fval(double x) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::FloatLit(nullptr, Internal::Exact<double>(nullptr, x)));
+}
+// Disambiguate literal 0, which could otherwise be interpreted as a pointer
+inline decltype(auto) fval(int x) { return fval(double(x)); }
+inline decltype(auto) fval(double* binder) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::FloatLit(nullptr, Internal::Any(binder)));
+}
+inline decltype(auto) fval(Literal* binder) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::FloatLit(binder, Internal::Any<double>(nullptr)));
+}
+inline decltype(auto) fval(Const** binder) {
+  return Internal::ConstMatcher(
+    binder, Internal::FloatLit(nullptr, Internal::Any<double>(nullptr)));
+}
+inline decltype(auto) fval(Literal* binder, double x) {
+  return Internal::ConstMatcher(
+    nullptr, Internal::FloatLit(binder, Internal::Exact<double>(nullptr, x)));
+}
+inline decltype(auto) fval(Const** binder, double x) {
+  return Internal::ConstMatcher(
+    binder, Internal::FloatLit(nullptr, Internal::Exact<double>(nullptr, x)));
+}
+
+inline decltype(auto) constant() {
+  return Internal::ConstMatcher(nullptr, Internal::Any<Literal>(nullptr));
+}
+inline decltype(auto) constant(int x) {
+  return Internal::ConstMatcher(nullptr, Internal::NumberLit(nullptr, x));
+}
+inline decltype(auto) constant(Literal* binder) {
+  return Internal::ConstMatcher(nullptr, Internal::Any(binder));
+}
+inline decltype(auto) constant(Const** binder) {
+  return Internal::ConstMatcher(binder, Internal::Any<Literal>(nullptr));
+}
+inline decltype(auto) constant(Literal* binder, int32_t x) {
+  return Internal::ConstMatcher(nullptr, Internal::NumberLit(binder, x));
+}
+inline decltype(auto) constant(Const** binder, int32_t x) {
+  return Internal::ConstMatcher(binder, Internal::NumberLit(nullptr, x));
+}
+
+inline decltype(auto) any() { return Internal::Any<Expression*>(nullptr); }
+inline decltype(auto) any(Expression** binder) { return Internal::Any(binder); }
+
+template<class S> inline decltype(auto) unary(S&& s) {
+  return Internal::UnaryMatcher(nullptr, Internal::Any<UnaryOp>(nullptr), s);
+}
+template<class S> inline decltype(auto) unary(Unary** binder, S&& s) {
+  return Internal::UnaryMatcher(binder, Internal::Any<UnaryOp>(nullptr), s);
+}
+template<class S> inline decltype(auto) unary(UnaryOp* binder, S&& s) {
+  return Internal::UnaryMatcher(nullptr, Internal::Any<UnaryOp>(binder), s);
+}
+template<class S> inline decltype(auto) unary(UnaryOp op, S&& s) {
+  return Internal::UnaryOpMatcher(nullptr, op, s);
+}
+template<class S> inline decltype(auto) unary(Abstract::Op op, S&& s) {
+  return Internal::AbstractUnaryOpMatcher(nullptr, op, s);
+}
+template<class S>
+inline decltype(auto) unary(Unary** binder, UnaryOp op, S&& s) {
+  return Internal::UnaryOpMatcher(binder, op, s);
+}
+template<class S>
+inline decltype(auto) unary(Unary** binder, Abstract::Op op, S&& s) {
+  return Internal::AbstractUnaryOpMatcher(binder, op, s);
+}
+template<class S1, class S2> inline decltype(auto) binary(S1&& s1, S2&& s2) {
+  return Internal::BinaryMatcher(
+    nullptr, Internal::Any<BinaryOp>(nullptr), s1, s2);
+}
+template<class S1, class S2>
+inline decltype(auto) binary(Binary** binder, S1&& s1, S2&& s2) {
+  return Internal::BinaryMatcher(
+    binder, Internal::Any<BinaryOp>(nullptr), s1, s2);
+}
+template<class S1, class S2>
+inline decltype(auto) binary(BinaryOp* binder, S1&& s1, S2&& s2) {
+  return Internal::BinaryMatcher(
+    nullptr, Internal::Any<BinaryOp>(binder), s1, s2);
+}
+template<class S1, class S2>
+inline decltype(auto) binary(BinaryOp op, S1&& s1, S2&& s2) {
+  return Internal::BinaryOpMatcher(nullptr, op, s1, s2);
+}
+template<class S1, class S2>
+inline decltype(auto) binary(Abstract::Op op, S1&& s1, S2&& s2) {
+  return Internal::AbstractBinaryOpMatcher(nullptr, op, s1, s2);
+}
+template<class S1, class S2>
+inline decltype(auto) binary(Binary** binder, BinaryOp op, S1&& s1, S2&& s2) {
+  return Internal::BinaryOpMatcher(binder, op, s1, s2);
+}
+template<class S1, class S2>
+inline decltype(auto)
+binary(Binary** binder, Abstract::Op op, S1&& s1, S2&& s2) {
+  return Internal::AbstractBinaryOpMatcher(binder, op, s1, s2);
+}
+
+template<class S1, class S2, class S3>
+inline decltype(auto) select(S1&& s1, S2&& s2, S3&& s3) {
+  return Internal::SelectMatcher(nullptr, s1, s2, s3);
+}
+template<class S1, class S2, class S3>
+inline decltype(auto) select(Select** binder, S1&& s1, S2&& s2, S3&& s3) {
+  return Internal::SelectMatcher(binder, s1, s2, s3);
+}
+
+} // namespace Match
+
+} // namespace wasm
+
+#endif // wasm_ir_match_h
diff --git a/binaryen/src/ir/memory-utils.h b/binaryen/src/ir/memory-utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/memory-utils.h
@@ -0,0 +1,205 @@
+/*
+ * 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_ir_memory_h
+#define wasm_ir_memory_h
+
+#include <algorithm>
+#include <vector>
+
+#include "literal.h"
+#include "wasm-binary.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace MemoryUtils {
+// Flattens memory into a single data segment, or no segment. If there is
+// a segment, it starts at 0.
+// If ensuredSegmentSize is provided, then a segment is always emitted,
+// and of at least that size.
+// Returns true if successful (e.g. relocatable segments cannot be flattened).
+inline bool flatten(Memory& memory,
+                    Index ensuredSegmentSize = 0,
+                    Module* module = nullptr) {
+  if (memory.segments.size() == 0) {
+    if (ensuredSegmentSize > 0) {
+      assert(module); // must provide a module if ensuring a size.
+      Builder builder(*module);
+      memory.segments.emplace_back(builder.makeConst(int32_t(0)));
+      memory.segments[0].data.resize(ensuredSegmentSize);
+    }
+    return true;
+  }
+  std::vector<char> data;
+  data.resize(ensuredSegmentSize);
+  for (auto& segment : memory.segments) {
+    if (segment.isPassive) {
+      return false;
+    }
+    auto* offset = segment.offset->dynCast<Const>();
+    if (!offset) {
+      return false;
+    }
+  }
+  for (auto& segment : memory.segments) {
+    auto* offset = segment.offset->dynCast<Const>();
+    Index start = offset->value.getInteger();
+    Index end = start + segment.data.size();
+    if (end > data.size()) {
+      data.resize(end);
+    }
+    std::copy(segment.data.begin(), segment.data.end(), data.begin() + start);
+  }
+  memory.segments.resize(1);
+  memory.segments[0].offset->cast<Const>()->value = Literal(int32_t(0));
+  memory.segments[0].data.swap(data);
+  return true;
+}
+
+// Ensures that the memory exists (of minimal size).
+inline void ensureExists(Memory& memory) {
+  if (!memory.exists) {
+    memory.exists = true;
+    memory.initial = memory.max = 1;
+  }
+}
+
+// Try to merge segments until they fit into web limitations.
+// Return true if successful.
+inline bool ensureLimitedSegments(Module& module) {
+  Memory& memory = module.memory;
+  if (memory.segments.size() <= WebLimitations::MaxDataSegments) {
+    return true;
+  }
+
+  // Conservatively refuse to change segments if there might be memory.init
+  // and data.drop instructions.
+  if (module.features.hasBulkMemory()) {
+    return false;
+  }
+
+  auto isEmpty = [](Memory::Segment& segment) {
+    return segment.data.size() == 0;
+  };
+
+  auto isConstantOffset = [](Memory::Segment& segment) {
+    return segment.offset && segment.offset->is<Const>();
+  };
+
+  Index numConstant = 0, numDynamic = 0;
+  bool hasPassiveSegments = false;
+  for (auto& segment : memory.segments) {
+    if (!isEmpty(segment)) {
+      if (isConstantOffset(segment)) {
+        numConstant++;
+      } else {
+        numDynamic++;
+      }
+    }
+    hasPassiveSegments |= segment.isPassive;
+  }
+
+  if (hasPassiveSegments) {
+    return false;
+  }
+
+  // check if we have too many dynamic data segments, which we can do nothing
+  // about
+  if (numDynamic + 1 >= WebLimitations::MaxDataSegments) {
+    return false;
+  }
+
+  // we'll merge constant segments if we must
+  if (numConstant + numDynamic >= WebLimitations::MaxDataSegments) {
+    numConstant = WebLimitations::MaxDataSegments - numDynamic - 1;
+    auto num = numConstant + numDynamic;
+    WASM_UNUSED(num);
+    assert(num == WebLimitations::MaxDataSegments - 1);
+  }
+
+  std::vector<Memory::Segment> mergedSegments;
+  mergedSegments.reserve(WebLimitations::MaxDataSegments);
+
+  // drop empty segments and pass through dynamic-offset segments
+  for (auto& segment : memory.segments) {
+    if (isEmpty(segment)) {
+      continue;
+    }
+    if (isConstantOffset(segment)) {
+      continue;
+    }
+    mergedSegments.push_back(segment);
+  }
+
+  // from here on, we concern ourselves with non-empty constant-offset
+  // segments, the ones which we may need to merge
+  auto isRelevant = [&](Memory::Segment& segment) {
+    return !isEmpty(segment) && isConstantOffset(segment);
+  };
+  for (Index i = 0; i < memory.segments.size(); i++) {
+    auto& segment = memory.segments[i];
+    if (!isRelevant(segment)) {
+      continue;
+    }
+    if (mergedSegments.size() + 2 < WebLimitations::MaxDataSegments) {
+      mergedSegments.push_back(segment);
+      continue;
+    }
+    // we can emit only one more segment! merge everything into one
+    // start the combined segment at the bottom of them all
+    auto start = segment.offset->cast<Const>()->value.getInteger();
+    for (Index j = i + 1; j < memory.segments.size(); j++) {
+      auto& segment = memory.segments[j];
+      if (!isRelevant(segment)) {
+        continue;
+      }
+      auto offset = segment.offset->cast<Const>()->value.getInteger();
+      start = std::min(start, offset);
+    }
+    // create the segment and add in all the data
+    auto* c = module.allocator.alloc<Const>();
+    c->value = Literal(int32_t(start));
+    c->type = Type::i32;
+
+    Memory::Segment combined(c);
+    for (Index j = i; j < memory.segments.size(); j++) {
+      auto& segment = memory.segments[j];
+      if (!isRelevant(segment)) {
+        continue;
+      }
+      auto offset = segment.offset->cast<Const>()->value.getInteger();
+      auto needed = offset + segment.data.size() - start;
+      if (combined.data.size() < needed) {
+        combined.data.resize(needed);
+      }
+      std::copy(segment.data.begin(),
+                segment.data.end(),
+                combined.data.begin() + (offset - start));
+    }
+    mergedSegments.push_back(combined);
+    break;
+  }
+
+  memory.segments.swap(mergedSegments);
+  return true;
+}
+} // namespace MemoryUtils
+
+} // namespace wasm
+
+#endif // wasm_ir_memory_h
diff --git a/binaryen/src/ir/module-utils.h b/binaryen/src/ir/module-utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/module-utils.h
@@ -0,0 +1,464 @@
+/*
+ * 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_ir_module_h
+#define wasm_ir_module_h
+
+#include "ir/find_all.h"
+#include "ir/manipulation.h"
+#include "ir/properties.h"
+#include "pass.h"
+#include "support/unique_deferring_queue.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace ModuleUtils {
+
+inline Function* copyFunction(Function* func, Module& out) {
+  auto* ret = new Function();
+  ret->name = func->name;
+  ret->sig = func->sig;
+  ret->vars = func->vars;
+  ret->localNames = func->localNames;
+  ret->localIndices = func->localIndices;
+  ret->debugLocations = func->debugLocations;
+  ret->body = ExpressionManipulator::copy(func->body, out);
+  ret->module = func->module;
+  ret->base = func->base;
+  // TODO: copy Stack IR
+  assert(!func->stackIR);
+  out.addFunction(ret);
+  return ret;
+}
+
+inline Global* copyGlobal(Global* global, Module& out) {
+  auto* ret = new Global();
+  ret->name = global->name;
+  ret->type = global->type;
+  ret->mutable_ = global->mutable_;
+  ret->module = global->module;
+  ret->base = global->base;
+  if (global->imported()) {
+    ret->init = nullptr;
+  } else {
+    ret->init = ExpressionManipulator::copy(global->init, out);
+  }
+  out.addGlobal(ret);
+  return ret;
+}
+
+inline Event* copyEvent(Event* event, Module& out) {
+  auto* ret = new Event();
+  ret->name = event->name;
+  ret->attribute = event->attribute;
+  ret->sig = event->sig;
+  out.addEvent(ret);
+  return ret;
+}
+
+inline void copyModule(const Module& in, Module& out) {
+  // we use names throughout, not raw pointers, so simple copying is fine
+  // for everything *but* expressions
+  for (auto& curr : in.exports) {
+    out.addExport(new Export(*curr));
+  }
+  for (auto& curr : in.functions) {
+    copyFunction(curr.get(), out);
+  }
+  for (auto& curr : in.globals) {
+    copyGlobal(curr.get(), out);
+  }
+  for (auto& curr : in.events) {
+    copyEvent(curr.get(), out);
+  }
+  out.table = in.table;
+  for (auto& segment : out.table.segments) {
+    segment.offset = ExpressionManipulator::copy(segment.offset, out);
+  }
+  out.memory = in.memory;
+  for (auto& segment : out.memory.segments) {
+    segment.offset = ExpressionManipulator::copy(segment.offset, out);
+  }
+  out.start = in.start;
+  out.userSections = in.userSections;
+  out.debugInfoFileNames = in.debugInfoFileNames;
+}
+
+inline void clearModule(Module& wasm) {
+  wasm.~Module();
+  new (&wasm) Module;
+}
+
+// Renaming
+
+// Rename functions along with all their uses.
+// Note that for this to work the functions themselves don't necessarily need
+// to exist.  For example, it is possible to remove a given function and then
+// call this redirect all of its uses.
+template<typename T> inline void renameFunctions(Module& wasm, T& map) {
+  // Update the function itself.
+  for (auto& pair : map) {
+    if (Function* F = wasm.getFunctionOrNull(pair.first)) {
+      assert(!wasm.getFunctionOrNull(pair.second) || F->name == pair.second);
+      F->name = pair.second;
+    }
+  }
+  wasm.updateMaps();
+  // Update other global things.
+  auto maybeUpdate = [&](Name& name) {
+    auto iter = map.find(name);
+    if (iter != map.end()) {
+      name = iter->second;
+    }
+  };
+  maybeUpdate(wasm.start);
+  for (auto& segment : wasm.table.segments) {
+    for (auto& name : segment.data) {
+      maybeUpdate(name);
+    }
+  }
+  for (auto& exp : wasm.exports) {
+    if (exp->kind == ExternalKind::Function) {
+      maybeUpdate(exp->value);
+    }
+  }
+  // Update call instructions.
+  for (auto& func : wasm.functions) {
+    // TODO: parallelize
+    if (!func->imported()) {
+      FindAll<Call> calls(func->body);
+      for (auto* call : calls.list) {
+        maybeUpdate(call->target);
+      }
+    }
+  }
+}
+
+inline void renameFunction(Module& wasm, Name oldName, Name newName) {
+  std::map<Name, Name> map;
+  map[oldName] = newName;
+  renameFunctions(wasm, map);
+}
+
+// Convenient iteration over imported/non-imported module elements
+
+template<typename T> inline void iterImportedMemories(Module& wasm, T visitor) {
+  if (wasm.memory.exists && wasm.memory.imported()) {
+    visitor(&wasm.memory);
+  }
+}
+
+template<typename T> inline void iterDefinedMemories(Module& wasm, T visitor) {
+  if (wasm.memory.exists && !wasm.memory.imported()) {
+    visitor(&wasm.memory);
+  }
+}
+
+template<typename T> inline void iterImportedTables(Module& wasm, T visitor) {
+  if (wasm.table.exists && wasm.table.imported()) {
+    visitor(&wasm.table);
+  }
+}
+
+template<typename T> inline void iterDefinedTables(Module& wasm, T visitor) {
+  if (wasm.table.exists && !wasm.table.imported()) {
+    visitor(&wasm.table);
+  }
+}
+
+template<typename T> inline void iterImportedGlobals(Module& wasm, T visitor) {
+  for (auto& import : wasm.globals) {
+    if (import->imported()) {
+      visitor(import.get());
+    }
+  }
+}
+
+template<typename T> inline void iterDefinedGlobals(Module& wasm, T visitor) {
+  for (auto& import : wasm.globals) {
+    if (!import->imported()) {
+      visitor(import.get());
+    }
+  }
+}
+
+template<typename T>
+inline void iterImportedFunctions(Module& wasm, T visitor) {
+  for (auto& import : wasm.functions) {
+    if (import->imported()) {
+      visitor(import.get());
+    }
+  }
+}
+
+template<typename T> inline void iterDefinedFunctions(Module& wasm, T visitor) {
+  for (auto& import : wasm.functions) {
+    if (!import->imported()) {
+      visitor(import.get());
+    }
+  }
+}
+
+template<typename T> inline void iterImportedEvents(Module& wasm, T visitor) {
+  for (auto& import : wasm.events) {
+    if (import->imported()) {
+      visitor(import.get());
+    }
+  }
+}
+
+template<typename T> inline void iterDefinedEvents(Module& wasm, T visitor) {
+  for (auto& import : wasm.events) {
+    if (!import->imported()) {
+      visitor(import.get());
+    }
+  }
+}
+
+template<typename T> inline void iterImports(Module& wasm, T visitor) {
+  iterImportedMemories(wasm, visitor);
+  iterImportedTables(wasm, visitor);
+  iterImportedGlobals(wasm, visitor);
+  iterImportedFunctions(wasm, visitor);
+  iterImportedEvents(wasm, visitor);
+}
+
+// Helper class for performing an operation on all the functions in the module,
+// in parallel, with an Info object for each one that can contain results of
+// some computation that the operation performs.
+// The operation performend should not modify the wasm module in any way.
+// TODO: enforce this
+template<typename T> struct ParallelFunctionAnalysis {
+  Module& wasm;
+
+  typedef std::map<Function*, T> Map;
+  Map map;
+
+  typedef std::function<void(Function*, T&)> Func;
+
+  ParallelFunctionAnalysis(Module& wasm, Func work) : wasm(wasm) {
+    // Fill in map, as we operate on it in parallel (each function to its own
+    // entry).
+    for (auto& func : wasm.functions) {
+      map[func.get()];
+    }
+
+    // Run on the imports first. TODO: parallelize this too
+    for (auto& func : wasm.functions) {
+      if (func->imported()) {
+        work(func.get(), map[func.get()]);
+      }
+    }
+
+    struct Mapper : public WalkerPass<PostWalker<Mapper>> {
+      bool isFunctionParallel() override { return true; }
+      bool modifiesBinaryenIR() override { return false; }
+
+      Mapper(Module& module, Map& map, Func work)
+        : module(module), map(map), work(work) {}
+
+      Mapper* create() override { return new Mapper(module, map, work); }
+
+      void doWalkFunction(Function* curr) {
+        assert(map.count(curr));
+        work(curr, map[curr]);
+      }
+
+    private:
+      Module& module;
+      Map& map;
+      Func work;
+    };
+
+    PassRunner runner(&wasm);
+    Mapper(wasm, map, work).run(&runner, &wasm);
+  }
+};
+
+// Helper class for analyzing the call graph.
+//
+// Provides hooks for running some initial calculation on each function (which
+// is done in parallel), writing to a FunctionInfo structure for each function.
+// Then you can call propagateBack() to propagate a property of interest to the
+// calling functions, transitively.
+//
+// For example, if some functions are known to call an import "foo", then you
+// can use this to find which functions call something that might eventually
+// reach foo, by initially marking the direct callers as "calling foo" and
+// propagating that backwards.
+template<typename T> struct CallGraphPropertyAnalysis {
+  Module& wasm;
+
+  // The basic information for each function about whom it calls and who is
+  // called by it.
+  struct FunctionInfo {
+    std::set<Function*> callsTo;
+    std::set<Function*> calledBy;
+    bool hasIndirectCall = false;
+  };
+
+  typedef std::map<Function*, T> Map;
+  Map map;
+
+  typedef std::function<void(Function*, T&)> Func;
+
+  CallGraphPropertyAnalysis(Module& wasm, Func work) : wasm(wasm) {
+    ParallelFunctionAnalysis<T> analysis(wasm, [&](Function* func, T& info) {
+      work(func, info);
+      if (func->imported()) {
+        return;
+      }
+      struct Mapper : public PostWalker<Mapper> {
+        Mapper(Module* module, T& info, Func work)
+          : module(module), info(info), work(work) {}
+
+        void visitCall(Call* curr) {
+          info.callsTo.insert(module->getFunction(curr->target));
+        }
+
+        void visitCallIndirect(CallIndirect* curr) {
+          info.hasIndirectCall = true;
+        }
+
+      private:
+        Module* module;
+        T& info;
+        Func work;
+      } mapper(&wasm, info, work);
+      mapper.walk(func->body);
+    });
+
+    map.swap(analysis.map);
+
+    // Find what is called by what.
+    for (auto& pair : map) {
+      auto* func = pair.first;
+      auto& info = pair.second;
+      for (auto* target : info.callsTo) {
+        map[target].calledBy.insert(func);
+      }
+    }
+  }
+
+  enum IndirectCalls { IgnoreIndirectCalls, IndirectCallsHaveProperty };
+
+  // Propagate a property from a function to those that call it.
+  //
+  // hasProperty() - Check if the property is present.
+  // canHaveProperty() - Check if the property could be present.
+  // addProperty() - Adds the property. This receives a second parameter which
+  //                 is the function due to which we are adding the property.
+  void propagateBack(std::function<bool(const T&)> hasProperty,
+                     std::function<bool(const T&)> canHaveProperty,
+                     std::function<void(T&, Function*)> addProperty,
+                     IndirectCalls indirectCalls) {
+    // 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)) {
+        addProperty(map[func.get()], func.get());
+        work.push(func.get());
+      }
+    }
+    while (!work.empty()) {
+      auto* func = work.pop();
+      for (auto* caller : map[func].calledBy) {
+        // If we don't already have the property, and we are not forbidden
+        // from getting it, then it propagates back to us now.
+        if (!hasProperty(map[caller]) && canHaveProperty(map[caller])) {
+          addProperty(map[caller], func);
+          work.push(caller);
+        }
+      }
+    }
+  }
+};
+
+// Helper function for collecting the type signatures used in a module
+//
+// Used when emitting or printing a module to give signatures canonical
+// indices. Signatures 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>;
+
+  // Collect the signature use counts for a single function
+  auto updateCounts = [&](Function* func, Counts& counts) {
+    if (func->imported()) {
+      return;
+    }
+    struct TypeCounter
+      : PostWalker<TypeCounter, UnifiedExpressionVisitor<TypeCounter>> {
+      Counts& counts;
+
+      TypeCounter(Counts& counts) : counts(counts) {}
+      void visitExpression(Expression* curr) {
+        if (auto* call = curr->dynCast<CallIndirect>()) {
+          counts[call->sig]++;
+        } else if (Properties::isControlFlowStructure(curr)) {
+          // TODO: Allow control flow to have input types as well
+          if (curr->type.isTuple()) {
+            counts[Signature(Type::none, curr->type)]++;
+          }
+        }
+      }
+    };
+    TypeCounter(counts).walk(func->body);
+  };
+
+  ModuleUtils::ParallelFunctionAnalysis<Counts> analysis(wasm, updateCounts);
+
+  // Collect all the counts.
+  Counts counts;
+  for (auto& curr : wasm.functions) {
+    counts[curr->sig]++;
+  }
+  for (auto& curr : wasm.events) {
+    counts[curr->sig]++;
+  }
+  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());
+  std::sort(sorted.begin(), sorted.end(), [&](auto a, auto b) {
+    // order by frequency then simplicity
+    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);
+  }
+}
+
+} // namespace ModuleUtils
+
+} // namespace wasm
+
+#endif // wasm_ir_module_h
diff --git a/binaryen/src/ir/names.h b/binaryen/src/ir/names.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/names.h
@@ -0,0 +1,53 @@
+/*
+ * 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_ir_names_h
+#define wasm_ir_names_h
+
+#include "wasm.h"
+
+namespace wasm {
+
+namespace Names {
+
+// Add explicit names for function locals not yet named, and do not
+// modify existing names
+inline void ensureNames(Function* func) {
+  std::unordered_set<Name> seen;
+  for (auto& pair : func->localNames) {
+    seen.insert(pair.second);
+  }
+  Index nameIndex = seen.size();
+  for (Index i = 0; i < func->getNumLocals(); i++) {
+    if (!func->hasLocalName(i)) {
+      while (1) {
+        auto name = Name::fromInt(nameIndex++);
+        if (seen.count(name) == 0) {
+          func->localNames[i] = name;
+          func->localIndices[name] = i;
+          seen.insert(name);
+          break;
+        }
+      }
+    }
+  }
+}
+
+} // namespace Names
+
+} // namespace wasm
+
+#endif // wasm_ir_names_h
diff --git a/binaryen/src/ir/parents.h b/binaryen/src/ir/parents.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/parents.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 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_ir_parents_h
+#define wasm_ir_parents_h
+
+namespace wasm {
+
+struct Parents {
+  Parents(Expression* expr) { inner.walk(expr); }
+
+  Expression* getParent(Expression* curr) { return inner.parentMap[curr]; }
+
+private:
+  struct Inner
+    : public ExpressionStackWalker<Inner, UnifiedExpressionVisitor<Inner>> {
+    void visitExpression(Expression* curr) { parentMap[curr] = getParent(); }
+
+    std::map<Expression*, Expression*> parentMap;
+  } inner;
+};
+
+} // namespace wasm
+
+#endif // wasm_ir_parents_h
diff --git a/binaryen/src/ir/properties.h b/binaryen/src/ir/properties.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/properties.h
@@ -0,0 +1,281 @@
+/*
+ * 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_ir_properties_h
+#define wasm_ir_properties_h
+
+#include "ir/bits.h"
+#include "ir/effects.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace Properties {
+
+inline bool emitsBoolean(Expression* curr) {
+  if (auto* unary = curr->dynCast<Unary>()) {
+    return unary->isRelational();
+  } else if (auto* binary = curr->dynCast<Binary>()) {
+    return binary->isRelational();
+  }
+  return false;
+}
+
+inline bool isSymmetric(Binary* binary) {
+  switch (binary->op) {
+    case AddInt32:
+    case MulInt32:
+    case AndInt32:
+    case OrInt32:
+    case XorInt32:
+    case EqInt32:
+    case NeInt32:
+
+    case AddInt64:
+    case MulInt64:
+    case AndInt64:
+    case OrInt64:
+    case XorInt64:
+    case EqInt64:
+    case NeInt64:
+
+    case EqFloat32:
+    case NeFloat32:
+    case EqFloat64:
+    case NeFloat64:
+      return true;
+
+    default:
+      return false;
+  }
+}
+
+inline bool isControlFlowStructure(Expression* curr) {
+  return curr->is<Block>() || curr->is<If>() || curr->is<Loop>() ||
+         curr->is<Try>();
+}
+
+// Check if an expression is a control flow construct with a name,
+// which implies it may have breaks to it.
+inline bool isNamedControlFlow(Expression* curr) {
+  if (auto* block = curr->dynCast<Block>()) {
+    return block->name.is();
+  } else if (auto* loop = curr->dynCast<Loop>()) {
+    return loop->name.is();
+  }
+  return false;
+}
+
+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>());
+}
+
+inline bool isConstantExpression(const Expression* curr) {
+  if (isSingleConstantExpression(curr)) {
+    return true;
+  }
+  if (auto* tuple = curr->dynCast<TupleMake>()) {
+    for (auto* op : tuple->operands) {
+      if (!isSingleConstantExpression(op)) {
+        return false;
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
+inline Literal getLiteral(const Expression* curr) {
+  if (auto* c = curr->dynCast<Const>()) {
+    return c->value;
+  } else if (auto* n = curr->dynCast<RefNull>()) {
+    return Literal(n->type);
+  } else if (auto* r = curr->dynCast<RefFunc>()) {
+    return Literal(r->func);
+  } else if (auto* i = curr->dynCast<I31New>()) {
+    if (auto* c = i->value->dynCast<Const>()) {
+      return Literal::makeI31(c->value.geti32());
+    }
+  }
+  WASM_UNREACHABLE("non-constant expression");
+}
+
+inline Literals getLiterals(const Expression* curr) {
+  if (isSingleConstantExpression(curr)) {
+    return {getLiteral(curr)};
+  } else if (auto* tuple = curr->dynCast<TupleMake>()) {
+    Literals literals;
+    for (auto* op : tuple->operands) {
+      literals.push_back(getLiteral(op));
+    }
+    return literals;
+  } else {
+    WASM_UNREACHABLE("non-constant expression");
+  }
+}
+
+// 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;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  return nullptr;
+}
+
+// gets the size of the sign-extended value
+inline Index getSignExtBits(Expression* curr) {
+  return 32 - Bits::getEffectiveShifts(curr->cast<Binary>()->right);
+}
+
+// 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;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  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);
+  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;
+        }
+      }
+    }
+  }
+  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());
+}
+
+// Returns a falling-through value, that is, it looks through a local.tee
+// and other operations that receive a value and let it flow through them. If
+// there is no value falling through, returns the node itself (as that is the
+// value that trivially falls through, with 0 steps in the middle).
+inline Expression* getFallthrough(Expression* curr,
+                                  const PassOptions& passOptions,
+                                  FeatureSet features) {
+  // If the current node is unreachable, there is no value
+  // falling through.
+  if (curr->type == Type::unreachable) {
+    return curr;
+  }
+  if (auto* set = curr->dynCast<LocalSet>()) {
+    if (set->isTee()) {
+      return getFallthrough(set->value, passOptions, features);
+    }
+  } else if (auto* block = curr->dynCast<Block>()) {
+    // if no name, we can't be broken to, and then can look at the fallthrough
+    if (!block->name.is() && block->list.size() > 0) {
+      return getFallthrough(block->list.back(), passOptions, features);
+    }
+  } else if (auto* loop = curr->dynCast<Loop>()) {
+    return getFallthrough(loop->body, passOptions, features);
+  } else if (auto* iff = curr->dynCast<If>()) {
+    if (iff->ifFalse) {
+      // Perhaps just one of the two actually returns.
+      if (iff->ifTrue->type == Type::unreachable) {
+        return getFallthrough(iff->ifFalse, passOptions, features);
+      } else if (iff->ifFalse->type == Type::unreachable) {
+        return getFallthrough(iff->ifTrue, passOptions, features);
+      }
+    }
+  } else if (auto* br = curr->dynCast<Break>()) {
+    if (br->condition && br->value) {
+      return getFallthrough(br->value, passOptions, features);
+    }
+  } else if (auto* tryy = curr->dynCast<Try>()) {
+    if (!EffectAnalyzer(passOptions, features, tryy->body).throws) {
+      return getFallthrough(tryy->body, passOptions, features);
+    }
+  }
+  return curr;
+}
+
+// Returns whether the resulting value here must fall through without being
+// modified. For example, a tee always does so. That is, this returns false if
+// and only if the return value may have some computation performed on it to
+// change it from the inputs the instruction receives.
+// This differs from getFallthrough() which returns a single value that falls
+// through - here if more than one value can fall through, like in if-else,
+// we can return true. That is, there we care about a value falling through and
+// for us to get that actual value to look at; here we just care whether the
+// value falls through without being changed, even if it might be one of
+// several options.
+inline bool isResultFallthrough(Expression* curr) {
+  // Note that we don't check if there is a return value here; the node may be
+  // unreachable, for example, but then there is no meaningful answer to give
+  // anyhow.
+  return curr->is<LocalSet>() || curr->is<Block>() || curr->is<If>() ||
+         curr->is<Loop>() || curr->is<Try>() || curr->is<Select>() ||
+         curr->is<Break>();
+}
+
+} // namespace Properties
+
+} // namespace wasm
+
+#endif // wasm_ir_properties_h
diff --git a/binaryen/src/ir/stack-utils.cpp b/binaryen/src/ir/stack-utils.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/stack-utils.cpp
@@ -0,0 +1,309 @@
+/*
+ * 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.
+ */
+
+#include "stack-utils.h"
+#include "ir/iteration.h"
+#include "ir/properties.h"
+
+namespace wasm {
+
+namespace StackUtils {
+
+void removeNops(Block* block) {
+  size_t newIndex = 0;
+  for (size_t i = 0, size = block->list.size(); i < size; ++i) {
+    if (!block->list[i]->is<Nop>()) {
+      block->list[newIndex++] = block->list[i];
+    }
+  }
+  block->list.resize(newIndex);
+}
+
+bool mayBeUnreachable(Expression* expr) {
+  if (Properties::isControlFlowStructure(expr)) {
+    return true;
+  }
+  switch (expr->_id) {
+    case Expression::Id::BreakId:
+      return expr->cast<Break>()->condition == nullptr;
+    case Expression::Id::CallId:
+      return expr->cast<Call>()->isReturn;
+    case Expression::Id::CallIndirectId:
+      return expr->cast<CallIndirect>()->isReturn;
+    case Expression::Id::ReturnId:
+    case Expression::Id::SwitchId:
+    case Expression::Id::UnreachableId:
+    case Expression::Id::ThrowId:
+    case Expression::Id::RethrowId:
+      return true;
+    default:
+      return false;
+  }
+}
+
+} // namespace StackUtils
+
+StackSignature::StackSignature(Expression* expr) {
+  std::vector<Type> inputs;
+  for (auto* child : ValueChildIterator(expr)) {
+    assert(child->type.isConcrete());
+    // Children might be tuple pops, so expand their types
+    inputs.insert(inputs.end(), child->type.begin(), child->type.end());
+  }
+  params = Type(inputs);
+  if (expr->type == Type::unreachable) {
+    unreachable = true;
+    results = Type::none;
+  } else {
+    unreachable = false;
+    results = expr->type;
+  }
+}
+
+bool StackSignature::composes(const StackSignature& next) const {
+  auto checked = std::min(results.size(), next.params.size());
+  return std::equal(results.end() - checked,
+                    results.end(),
+                    next.params.end() - checked,
+                    [](const Type& produced, const Type& consumed) {
+                      return Type::isSubType(produced, consumed);
+                    });
+}
+
+bool StackSignature::satisfies(Signature sig) const {
+  if (sig.params.size() < params.size() ||
+      sig.results.size() < results.size()) {
+    // Not enough values provided or too many produced
+    return false;
+  }
+  bool paramSuffixMatches =
+    std::equal(params.begin(),
+               params.end(),
+               sig.params.end() - params.size(),
+               [](const Type& consumed, const Type& provided) {
+                 return Type::isSubType(provided, consumed);
+               });
+  if (!paramSuffixMatches) {
+    return false;
+  }
+  bool resultSuffixMatches =
+    std::equal(results.begin(),
+               results.end(),
+               sig.results.end() - results.size(),
+               [](const Type& produced, const Type& expected) {
+                 return Type::isSubType(produced, expected);
+               });
+  if (!resultSuffixMatches) {
+    return false;
+  }
+  if (unreachable) {
+    // The unreachable can consume any additional provided params and produce
+    // any additional expected results, so we are done.
+    return true;
+  }
+  // Any additional provided params will pass through untouched, so they must be
+  // equivalent to the additional produced results.
+  return std::equal(sig.params.begin(),
+                    sig.params.end() - params.size(),
+                    sig.results.begin(),
+                    sig.results.end() - results.size(),
+                    [](const Type& produced, const Type& expected) {
+                      return Type::isSubType(produced, expected);
+                    });
+}
+
+StackSignature& StackSignature::operator+=(const StackSignature& next) {
+  assert(composes(next));
+  std::vector<Type> stack(results.begin(), results.end());
+  size_t required = next.params.size();
+  // Consume stack values according to next's parameters
+  if (stack.size() >= required) {
+    stack.resize(stack.size() - required);
+  } else {
+    if (!unreachable) {
+      // Prepend the unsatisfied params of `next` to the current params
+      size_t unsatisfied = required - stack.size();
+      std::vector<Type> newParams(next.params.begin(),
+                                  next.params.begin() + unsatisfied);
+      newParams.insert(newParams.end(), params.begin(), params.end());
+      params = Type(newParams);
+    }
+    stack.clear();
+  }
+  // Add stack values according to next's results
+  if (next.unreachable) {
+    results = next.results;
+    unreachable = true;
+  } else {
+    stack.insert(stack.end(), next.results.begin(), next.results.end());
+    results = Type(stack);
+  }
+  return *this;
+}
+
+StackSignature StackSignature::operator+(const StackSignature& next) const {
+  StackSignature sig = *this;
+  sig += next;
+  return sig;
+}
+
+StackFlow::StackFlow(Block* block) {
+  // Encapsulates the logic for treating the block and its children
+  // uniformly. The end of the block is treated as if it consumed values
+  // corresponding to the its result type and produced no values, which is why
+  // the block's result type is used as the params of its processed stack
+  // signature.
+  auto processBlock = [&block](auto process) {
+    // TODO: Once we support block parameters, set up the stack by calling
+    // `process` before iterating through the block.
+    for (auto* expr : block->list) {
+      process(expr, StackSignature(expr));
+    }
+    bool unreachable = block->type == Type::unreachable;
+    Type params = unreachable ? Type::none : block->type;
+    process(block, StackSignature(params, Type::none, unreachable));
+  };
+
+  // We need to make an initial pass through the block to figure out how many
+  // values each unreachable instruction produces.
+  std::unordered_map<Expression*, size_t> producedByUnreachable;
+  {
+    size_t stackSize = 0;
+    size_t produced = 0;
+    Expression* lastUnreachable = nullptr;
+    processBlock([&](Expression* expr, const StackSignature sig) {
+      // Consume params
+      if (sig.params.size() > stackSize) {
+        // We need more values than are available, so they must come from the
+        // last unreachable.
+        assert(lastUnreachable);
+        produced += sig.params.size() - stackSize;
+        stackSize = 0;
+      } else {
+        stackSize -= sig.params.size();
+      }
+
+      // Handle unreachable or produce results
+      if (sig.unreachable) {
+        if (lastUnreachable) {
+          producedByUnreachable[lastUnreachable] = produced;
+          produced = 0;
+        }
+        assert(produced == 0);
+        lastUnreachable = expr;
+        stackSize = 0;
+      } else {
+        stackSize += sig.results.size();
+      }
+    });
+
+    // Finish record for final unreachable
+    if (lastUnreachable) {
+      producedByUnreachable[lastUnreachable] = produced;
+    }
+  }
+
+  // Take another pass through the block, recording srcs and dests.
+  std::vector<Location> values;
+  Expression* lastUnreachable = nullptr;
+  processBlock([&](Expression* expr, const StackSignature sig) {
+    assert((sig.params.size() <= values.size() || lastUnreachable) &&
+           "Block inputs not yet supported");
+
+    // Unreachable instructions consume all available values
+    size_t consumed = sig.unreachable
+                        ? std::max(values.size(), sig.params.size())
+                        : sig.params.size();
+
+    // We previously calculated how many values unreachable instructions produce
+    size_t produced =
+      sig.unreachable ? producedByUnreachable[expr] : sig.results.size();
+
+    srcs[expr] = std::vector<Location>(consumed);
+    dests[expr] = std::vector<Location>(produced);
+
+    // Figure out what kind of unreachable values we have
+    assert(sig.params.size() <= consumed);
+    size_t unreachableBeyondStack = 0;
+    size_t unreachableFromStack = 0;
+    if (consumed > values.size()) {
+      assert(consumed == sig.params.size());
+      unreachableBeyondStack = consumed - values.size();
+    } else if (consumed > sig.params.size()) {
+      assert(consumed == values.size());
+      unreachableFromStack = consumed - sig.params.size();
+    }
+
+    // Consume values
+    for (Index i = 0; i < consumed; ++i) {
+      if (i < unreachableBeyondStack) {
+        // This value comes from the polymorphic stack of the last unreachable
+        // because the stack did not have enough values to satisfy this
+        // instruction.
+        assert(lastUnreachable);
+        assert(producedByUnreachable[lastUnreachable] >=
+               unreachableBeyondStack);
+        Index destIndex =
+          producedByUnreachable[lastUnreachable] - unreachableBeyondStack + i;
+        Type type = sig.params[i];
+        srcs[expr][i] = {lastUnreachable, destIndex, type, true};
+        dests[lastUnreachable][destIndex] = {expr, i, type, false};
+      } else {
+        // A normal value from the value stack
+        bool unreachable = i < unreachableFromStack;
+        auto& src = values[values.size() + i - consumed];
+        srcs[expr][i] = src;
+        dests[src.expr][src.index] = {expr, i, src.type, unreachable};
+      }
+    }
+
+    // Update available values
+    if (unreachableBeyondStack) {
+      producedByUnreachable[lastUnreachable] -= unreachableBeyondStack;
+      values.resize(0);
+    } else {
+      values.resize(values.size() - consumed);
+    }
+
+    // Produce values
+    for (Index i = 0; i < sig.results.size(); ++i) {
+      values.push_back({expr, i, sig.results[i], false});
+    }
+
+    // Update the last unreachable instruction
+    if (sig.unreachable) {
+      assert(producedByUnreachable[lastUnreachable] == 0);
+      lastUnreachable = expr;
+    }
+  });
+}
+
+StackSignature StackFlow::getSignature(Expression* expr) {
+  auto exprSrcs = srcs.find(expr);
+  auto exprDests = dests.find(expr);
+  assert(exprSrcs != srcs.end() && exprDests != dests.end());
+  std::vector<Type> params, results;
+  for (auto& src : exprSrcs->second) {
+    params.push_back(src.type);
+  }
+  for (auto& dest : exprDests->second) {
+    results.push_back(dest.type);
+  }
+  bool unreachable = expr->type == Type::unreachable;
+  return StackSignature(Type(params), Type(results), unreachable);
+}
+
+} // namespace wasm
diff --git a/binaryen/src/ir/stack-utils.h b/binaryen/src/ir/stack-utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/stack-utils.h
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ */
+
+//
+// stack-utils.h: Utilities for manipulating and analyzing stack machine code in
+// the form of Poppy IR.
+//
+// Poppy IR represents stack machine code using normal Binaryen IR types by
+// imposing the following constraints:
+//
+//  1. Function bodies and children of control flow (except If conditions) must
+//     be blocks.
+//
+//  2. Blocks may have any Expressions except for Pops as children. The sequence
+//     of instructions in a block follows the same validation rules as in
+//     WebAssembly. That means that any expression may have a concrete type, not
+//     just the final expression in the block.
+//
+//  3. All other children must be Pops, which are used to determine the input
+//     stack type of each instruction. Pops may not have `unreachable` type.
+//
+//  4. Only control flow structures and instructions that have polymorphic
+//     unreachable behavior in WebAssembly may have unreachable type. Blocks may
+//     be unreachable when they are not branch targets and when they have an
+//     unreachable child. Note that this means a block may be unreachable even
+//     if it would otherwise have a concrete type, unlike in Binaryen IR.
+//
+// For example, the following Binaryen IR Function:
+//
+//   (func $foo (result i32)
+//    (i32.add
+//     (i32.const 42)
+//     (i32.const 5)
+//    )
+//   )
+//
+// would look like this in Poppy IR:
+//
+//   (func $foo (result i32)
+//    (block
+//     (i32.const 42)
+//     (i32.const 5)
+//     (i32.add
+//      (i32.pop)
+//      (i32.pop)
+//     )
+//    )
+//   )
+//
+// Notice that the sequence of instructions in the block is now identical to the
+// sequence of instructions in raw WebAssembly. Also note that Poppy IR's
+// validation rules are largely additional on top of the normal Binaryen IR
+// validation rules, with the only exceptions being block body validation and
+// block unreahchability rules.
+//
+
+#ifndef wasm_ir_stack_h
+#define wasm_ir_stack_h
+
+#include "ir/properties.h"
+#include "wasm-type.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace StackUtils {
+
+// Iterate through `block` and remove nops.
+void removeNops(Block* block);
+
+// Whether `expr` may be unreachable in Poppy IR. True for control flow
+// structures and polymorphic unreachable instructions.
+bool mayBeUnreachable(Expression* expr);
+
+} // namespace StackUtils
+
+// Stack signatures are like regular function signatures, but they are used to
+// represent the stack parameters and results of arbitrary sequences of stacky
+// instructions. They have to record whether they cover an unreachable
+// instruction because their composition takes into account the polymorphic
+// results of unreachable instructions. For example, the following instruction
+// sequences both have params {i32, i32} and results {f32}, but only sequence B
+// is unreachable:
+//
+//  A:
+//    i32.add
+//    drop
+//    f32.const 42
+//
+//  B:
+//    i32.add
+//    unreachable
+//    f32.const 42
+//
+// Notice that this distinction is important because sequence B can be the body
+// of the blocks below but sequence A cannot. In other words, the stack
+// signature of sequence B satisfies the signatures of these blocks, but the
+// stack signature of sequence A does not.
+//
+//  (block (param f64 i32 i32) (result f32) ... )
+//  (block (param i32 i32) (result f64 f32) ... )
+//  (block (param f64 i32 i32) (result f64 f32) ... )
+//
+struct StackSignature {
+  Type params;
+  Type results;
+  bool unreachable;
+
+  StackSignature()
+    : params(Type::none), results(Type::none), unreachable(false) {}
+  StackSignature(Type params, Type results, bool unreachable = false)
+    : params(params), results(results), unreachable(unreachable) {}
+
+  StackSignature(const StackSignature&) = default;
+  StackSignature& operator=(const StackSignature&) = default;
+
+  // Get the stack signature of `expr`
+  explicit StackSignature(Expression* expr);
+
+  // Get the stack signature of the range of instructions [first, last). The
+  // sequence of instructions is assumed to be valid, i.e. their signatures
+  // compose.
+  template<class InputIt>
+  explicit StackSignature(InputIt first, InputIt last)
+    : params(Type::none), results(Type::none), unreachable(false) {
+    // TODO: It would be more efficient to build the signature directly and
+    // construct the params in reverse to avoid quadratic behavior.
+    while (first != last) {
+      *this += StackSignature(*first++);
+    }
+  }
+
+  // Return `true` iff `next` composes after this stack signature.
+  bool composes(const StackSignature& next) const;
+
+  // Whether a block whose contents have this stack signature could be typed
+  // with `sig`.
+  bool satisfies(Signature sig) const;
+
+  // Compose stack signatures. Assumes they actually compose.
+  StackSignature& operator+=(const StackSignature& next);
+  StackSignature operator+(const StackSignature& next) const;
+
+  bool operator==(const StackSignature& other) const {
+    return params == other.params && results == other.results &&
+           unreachable == other.unreachable;
+  }
+};
+
+// Calculates stack machine data flow, associating the sources and destinations
+// of all values in a block.
+struct StackFlow {
+  // The destination (source) location at which a value of type `type` is
+  // consumed (produced), corresponding to the `index`th value consumed by
+  // (produced by) instruction `expr`. For destination locations, `unreachable`
+  // is true iff the corresponding value is consumed by the polymorphic behavior
+  // of an unreachable instruction rather than being used directly. For source
+  // locations, `unreachable` is true iff the corresponding value is produced by
+  // an unreachable instruction. For produced values that are not consumed
+  // within the block (TODO: also for consumed values that are not produced
+  // within the block), `expr` will be the enclosing block.
+  struct Location {
+    Expression* expr;
+    Index index;
+    Type type;
+    bool unreachable;
+
+    bool operator==(const Location& other) const {
+      return expr == other.expr && index == other.index && type == other.type &&
+             unreachable == other.unreachable;
+    }
+  };
+
+  using LocationMap = std::unordered_map<Expression*, std::vector<Location>>;
+
+  // Maps each instruction to the set of source locations producing its inputs.
+  LocationMap srcs;
+
+  // Maps each instruction to the set of output locations consuming its results.
+  LocationMap dests;
+
+  // Gets the effective stack signature of `expr`, which must be a child of the
+  // block. If `expr` is unreachable, the returned signature will reflect the
+  // values consumed and produced by its polymorphic unreachable behavior.
+  StackSignature getSignature(Expression* expr);
+
+  // Calculates `srcs` and `dests`.
+  StackFlow(Block* curr);
+};
+
+} // namespace wasm
+
+#endif // wasm_ir_stack_h
diff --git a/binaryen/src/ir/table-utils.h b/binaryen/src/ir/table-utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/table-utils.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019 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_ir_table_h
+#define wasm_ir_table_h
+
+#include "ir/literal-utils.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace TableUtils {
+
+struct FlatTable {
+  std::vector<Name> names;
+  bool valid;
+
+  FlatTable(Table& table) {
+    valid = true;
+    for (auto& segment : table.segments) {
+      auto offset = segment.offset;
+      if (!offset->is<Const>()) {
+        // TODO: handle some non-constant segments
+        valid = false;
+        return;
+      }
+      Index start = offset->cast<Const>()->value.geti32();
+      Index end = start + segment.data.size();
+      if (end > names.size()) {
+        names.resize(end);
+      }
+      for (Index i = 0; i < segment.data.size(); i++) {
+        names[start + i] = segment.data[i];
+      }
+    }
+  }
+};
+
+inline Table::Segment& getSingletonSegment(Table& table, Module& wasm) {
+  if (table.segments.size() != 1) {
+    Fatal() << "Table doesn't have a singleton segment.";
+  }
+  return table.segments[0];
+}
+
+// Appends a name to the table. This assumes the table has 0 or 1 segments,
+// as with 2 or more it's ambiguous what we should do (use a hole in the middle
+// or not).
+// This works on code from wasm-ld, but on arbitrary code it may not be valid
+// in the presence of a dynamic linking section. Specifically, we assume the
+// module has a single table segment, and that the dylink section indicates
+// we can validly append to that segment, see the check below.
+inline Index append(Table& table, Name name, Module& wasm) {
+  auto& segment = getSingletonSegment(table, wasm);
+  auto tableIndex = segment.data.size();
+  if (wasm.dylinkSection) {
+    if (segment.data.size() != wasm.dylinkSection->tableSize) {
+      Fatal() << "Appending to the table in a module with a dylink section "
+                 "that has tableSize which indicates it wants to reserve more "
+                 "table space than the actual table elements in the module. "
+                 "We don't know how to correctly update the dylink section in "
+                 "that case.";
+    }
+    wasm.dylinkSection->tableSize++;
+  }
+  segment.data.push_back(name);
+  table.initial = table.initial + 1;
+  return tableIndex;
+}
+
+// Checks if a function is already in the table. Returns that index if so,
+// otherwise appends it.
+inline Index getOrAppend(Table& table, Name name, Module& wasm) {
+  auto& segment = getSingletonSegment(table, wasm);
+  for (Index i = 0; i < segment.data.size(); i++) {
+    if (segment.data[i] == name) {
+      return i;
+    }
+  }
+  return append(table, name, wasm);
+}
+
+} // namespace TableUtils
+
+} // namespace wasm
+
+#endif // wasm_ir_table_h
diff --git a/binaryen/src/ir/trapping.h b/binaryen/src/ir/trapping.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/trapping.h
@@ -0,0 +1,109 @@
+/*
+ * 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_ir_trapping_h
+#define wasm_ir_trapping_h
+
+#include <exception>
+
+#include "pass.h"
+
+namespace wasm {
+
+enum class TrapMode { Allow, Clamp, JS };
+
+inline void addTrapModePass(PassRunner& runner, TrapMode trapMode) {
+  if (trapMode == TrapMode::Clamp) {
+    runner.add("trap-mode-clamp");
+  } else if (trapMode == TrapMode::JS) {
+    runner.add("trap-mode-js");
+  }
+}
+
+class TrappingFunctionContainer {
+public:
+  TrappingFunctionContainer(TrapMode mode, Module& wasm, bool immediate = false)
+    : mode(mode), wasm(wasm), immediate(immediate) {}
+
+  bool hasFunction(Name name) {
+    return functions.find(name) != functions.end();
+  }
+  bool hasImport(Name name) { return imports.find(name) != imports.end(); }
+
+  void addFunction(Function* function) {
+    functions[function->name] = function;
+    if (immediate) {
+      wasm.addFunction(function);
+    }
+  }
+  void addImport(Function* import) {
+    imports[import->name] = import;
+    if (immediate) {
+      wasm.addFunction(import);
+    }
+  }
+
+  void addToModule() {
+    if (!immediate) {
+      for (auto& pair : functions) {
+        wasm.addFunction(pair.second);
+      }
+      for (auto& pair : imports) {
+        wasm.addFunction(pair.second);
+      }
+    }
+    functions.clear();
+    imports.clear();
+  }
+
+  TrapMode getMode() { return mode; }
+
+  Module& getModule() { return wasm; }
+
+  std::map<Name, Function*>& getFunctions() { return functions; }
+
+private:
+  std::map<Name, Function*> functions;
+  std::map<Name, Function*> imports;
+
+  TrapMode mode;
+  Module& wasm;
+  bool immediate;
+};
+
+Expression* makeTrappingBinary(Binary* curr,
+                               TrappingFunctionContainer& trappingFunctions);
+Expression* makeTrappingUnary(Unary* curr,
+                              TrappingFunctionContainer& trappingFunctions);
+
+inline TrapMode trapModeFromString(std::string const& str) {
+  if (str == "allow") {
+    return TrapMode::Allow;
+  } else if (str == "clamp") {
+    return TrapMode::Clamp;
+  } else if (str == "js") {
+    return TrapMode::JS;
+  } else {
+    throw std::invalid_argument(
+      "Unsupported trap mode \"" + str +
+      "\". "
+      "Valid modes are \"allow\", \"js\", and \"clamp\"");
+  }
+}
+
+} // namespace wasm
+
+#endif // wasm_ir_trapping_h
diff --git a/binaryen/src/ir/type-updating.h b/binaryen/src/ir/type-updating.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/type-updating.h
@@ -0,0 +1,321 @@
+/*
+ * 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_ir_type_updating_h
+#define wasm_ir_type_updating_h
+
+#include "wasm-traversal.h"
+
+namespace wasm {
+
+// a class that tracks type dependencies between nodes, letting you
+// update types efficiently when removing and altering code.
+// altering code can alter types in the following way:
+//   * removing a break can make a block unreachable, if nothing else
+//     reaches it
+//   * altering the type of a child to unreachable can make the parent
+//     unreachable
+struct TypeUpdater
+  : public ExpressionStackWalker<TypeUpdater,
+                                 UnifiedExpressionVisitor<TypeUpdater>> {
+  // Part 1: Scanning
+
+  // track names to their blocks, so that when we remove a break to
+  // a block, we know how to find it if we need to update it
+  struct BlockInfo {
+    Block* block = nullptr;
+    int numBreaks = 0;
+  };
+  std::map<Name, BlockInfo> blockInfos;
+
+  // track the parent of each node, as child type changes may lead to
+  // unreachability
+  std::map<Expression*, Expression*> parents;
+
+  void visitExpression(Expression* curr) {
+    if (expressionStack.size() > 1) {
+      parents[curr] = expressionStack[expressionStack.size() - 2];
+    } else {
+      parents[curr] = nullptr; // this is the top level
+    }
+    // discover block/break relationships
+    if (auto* block = curr->dynCast<Block>()) {
+      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];
+    }
+    // add a break to the info, for break and switch
+    discoverBreaks(curr, +1);
+  }
+
+  // Part 2: Updating
+
+  // Node replacements, additions, removals and type changes should be noted. An
+  // exception is nodes you know will never be looked at again.
+
+  // note the replacement of one node with another. this should be called
+  // after performing the replacement.
+  // this does *not* look into the node by default. see
+  // noteReplacementWithRecursiveRemoval (we don't support recursive addition
+  // because in practice we do not create new trees in the passes that use this,
+  // they just move around children)
+  void noteReplacement(Expression* from,
+                       Expression* to,
+                       bool recursivelyRemove = false) {
+    auto parent = parents[from];
+    if (recursivelyRemove) {
+      noteRecursiveRemoval(from);
+    } else {
+      noteRemoval(from);
+    }
+    // if we are replacing with a child, i.e. a node that was already present
+    // in the ast, then we just have a type and parent to update
+    if (parents.find(to) != parents.end()) {
+      parents[to] = parent;
+      if (from->type != to->type) {
+        propagateTypesUp(to);
+      }
+    } else {
+      noteAddition(to, parent, from);
+    }
+  }
+
+  void noteReplacementWithRecursiveRemoval(Expression* from, Expression* to) {
+    noteReplacement(from, to, true);
+  }
+
+  // note the removal of a node
+  void noteRemoval(Expression* curr) {
+    noteRemovalOrAddition(curr, nullptr);
+    parents.erase(curr);
+  }
+
+  // note the removal of a node and all its children
+  void noteRecursiveRemoval(Expression* curr) {
+    struct Recurser
+      : public PostWalker<Recurser, UnifiedExpressionVisitor<Recurser>> {
+      TypeUpdater& parent;
+
+      Recurser(TypeUpdater& parent, Expression* root) : parent(parent) {
+        walk(root);
+      }
+
+      void visitExpression(Expression* curr) { parent.noteRemoval(curr); }
+    };
+
+    Recurser(*this, curr);
+  }
+
+  void noteAddition(Expression* curr,
+                    Expression* parent,
+                    Expression* previous = nullptr) {
+    assert(parents.find(curr) == parents.end()); // must not already exist
+    noteRemovalOrAddition(curr, parent);
+    // if we didn't replace with the exact same type, propagate types up
+    if (!(previous && previous->type == curr->type)) {
+      propagateTypesUp(curr);
+    }
+  }
+
+  // if parent is nullptr, this is a removal
+  void noteRemovalOrAddition(Expression* curr, Expression* parent) {
+    parents[curr] = parent;
+    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);
+    }
+  }
+
+  // note the addition of a node
+  void noteBreakChange(Name name, int change, Expression* value) {
+    noteBreakChange(name, change, value ? value->type : Type::none);
+  }
+
+  void noteBreakChange(Name name, int change, Type type) {
+    auto iter = blockInfos.find(name);
+    if (iter == blockInfos.end()) {
+      return; // we can ignore breaks to loops
+    }
+    auto& info = iter->second;
+    info.numBreaks += change;
+    assert(info.numBreaks >= 0);
+    auto* block = info.block;
+    if (block) { // if to a loop, can ignore
+      if (info.numBreaks == 0) {
+        // dropped to 0! the block may now be unreachable. that
+        // requires that it doesn't have a fallthrough
+        makeBlockUnreachableIfNoFallThrough(block);
+      } else if (change == 1 && info.numBreaks == 1) {
+        // bumped to 1! the block may now be reachable
+        if (block->type != Type::unreachable) {
+          return; // was already reachable, had a fallthrough
+        }
+        changeTypeTo(block, type);
+      }
+    }
+  }
+
+  // alters the type of a node to a new type.
+  // this propagates the type change through all the parents.
+  void changeTypeTo(Expression* curr, Type newType) {
+    if (curr->type == newType) {
+      return; // nothing to do
+    }
+    curr->type = newType;
+    propagateTypesUp(curr);
+  }
+
+  // given a node that has a new type, or is a new node, update
+  // all the parents accordingly. the existence of the node and
+  // any changes to it already occurred, this just updates the
+  // parents following that. i.e., nothing is done to the
+  // node we start on, it's done.
+  // the one thing we need to do here is propagate unreachability,
+  // no other change is possible
+  void propagateTypesUp(Expression* curr) {
+    if (curr->type != Type::unreachable) {
+      return;
+    }
+    while (1) {
+      auto* child = curr;
+      curr = parents[child];
+      if (!curr) {
+        return;
+      }
+      // get ready to apply unreachability to this node
+      if (curr->type == Type::unreachable) {
+        return; // already unreachable, stop here
+      }
+      // most nodes become unreachable if a child is unreachable,
+      // but exceptions exist
+      if (auto* block = curr->dynCast<Block>()) {
+        // if the block has a fallthrough, it can keep its type
+        if (block->list.back()->type.isConcrete()) {
+          return; // did not turn
+        }
+        // if the block has breaks, it can keep its type
+        if (!block->name.is() || blockInfos[block->name].numBreaks == 0) {
+          curr->type = Type::unreachable;
+        } else {
+          return; // did not turn
+        }
+      } else if (auto* iff = curr->dynCast<If>()) {
+        // may not be unreachable if just one side is
+        iff->finalize();
+        if (curr->type != Type::unreachable) {
+          return; // did not turn
+        }
+      } else if (auto* tryy = curr->dynCast<Try>()) {
+        tryy->finalize();
+        if (curr->type != Type::unreachable) {
+          return; // did not turn
+        }
+      } else {
+        curr->type = Type::unreachable;
+      }
+    }
+  }
+
+  // efficiently update the type of a block, given the data we know. this
+  // can remove a concrete type and turn the block unreachable when it is
+  // unreachable, and it does this efficiently, without scanning the full
+  // contents
+  void maybeUpdateTypeToUnreachable(Block* curr) {
+    if (!curr->type.isConcrete()) {
+      return; // nothing concrete to change to unreachable
+    }
+    if (curr->name.is() && blockInfos[curr->name].numBreaks > 0) {
+      return; // has a break, not unreachable
+    }
+    // look for a fallthrough
+    makeBlockUnreachableIfNoFallThrough(curr);
+  }
+
+  void makeBlockUnreachableIfNoFallThrough(Block* curr) {
+    if (curr->type == Type::unreachable) {
+      return; // no change possible
+    }
+    if (!curr->list.empty() && curr->list.back()->type.isConcrete()) {
+      // should keep type due to fallthrough, even if has an unreachable child
+      return;
+    }
+    for (auto* child : curr->list) {
+      if (child->type == Type::unreachable) {
+        // no fallthrough, and an unreachable, => this block is now unreachable
+        changeTypeTo(curr, Type::unreachable);
+        return;
+      }
+    }
+  }
+
+  // efficiently update the type of an if, given the data we know. this
+  // can remove a concrete type and turn the if unreachable when it is
+  // unreachable
+  void maybeUpdateTypeToUnreachable(If* curr) {
+    if (!curr->type.isConcrete()) {
+      return; // nothing concrete to change to unreachable
+    }
+    curr->finalize();
+    if (curr->type == Type::unreachable) {
+      propagateTypesUp(curr);
+    }
+  }
+
+  void maybeUpdateTypeToUnreachable(Try* curr) {
+    if (!curr->type.isConcrete()) {
+      return; // nothing concrete to change to unreachable
+    }
+    curr->finalize();
+    if (curr->type == Type::unreachable) {
+      propagateTypesUp(curr);
+    }
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_ir_type_updating_h
diff --git a/binaryen/src/ir/utils.h b/binaryen/src/ir/utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/utils.h
@@ -0,0 +1,394 @@
+/*
+ * 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_ir_utils_h
+#define wasm_ir_utils_h
+
+#include "ir/branch-utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
+
+namespace wasm {
+
+// Measure the size of an AST
+
+struct Measurer
+  : public PostWalker<Measurer, UnifiedExpressionVisitor<Measurer>> {
+  Index size = 0;
+
+  void visitExpression(Expression* curr) { size++; }
+
+  static Index measure(Expression* tree) {
+    Measurer measurer;
+    measurer.walk(tree);
+    return measurer.size;
+  }
+};
+
+struct ExpressionAnalyzer {
+  // Given a stack of expressions, checks if the topmost is used as a result.
+  // For example, if the parent is a block and the node is before the last
+  // position, it is not used.
+  static bool isResultUsed(ExpressionStack& stack, Function* func);
+
+  // Checks if a value is dropped.
+  static bool isResultDropped(ExpressionStack& stack);
+
+  // Checks if a break is a simple - no condition, no value, just a plain
+  // branching
+  static bool isSimple(Break* curr) { return !curr->condition && !curr->value; }
+
+  using ExprComparer = std::function<bool(Expression*, Expression*)>;
+  static bool
+  flexibleEqual(Expression* left, Expression* right, ExprComparer comparer);
+
+  // Compares two expressions for equivalence.
+  static bool equal(Expression* left, Expression* right) {
+    auto comparer = [](Expression* left, Expression* right) { return false; };
+    return flexibleEqual(left, right, comparer);
+  }
+
+  // A shallow comparison, ignoring child nodes.
+  static bool shallowEqual(Expression* left, Expression* right) {
+    auto comparer = [left, right](Expression* currLeft, Expression* currRight) {
+      if (currLeft == left && currRight == right) {
+        // these are the ones we want to compare
+        return false;
+      }
+      // otherwise, don't do the comparison, we don't care
+      return true;
+    };
+    return flexibleEqual(left, right, comparer);
+  }
+
+  // hash an expression, ignoring superficial details like specific internal
+  // names
+  static size_t hash(Expression* curr);
+};
+
+// Re-Finalizes all node types. This can be run after code was modified in
+// various ways that require propagating types around, and it does such an
+// "incremental" update. This is done under the assumption that there is
+// a valid assignment of types to apply.
+// This removes "unnecessary' block/if/loop types, i.e., that are added
+// specifically, as in
+//  (block (result i32) (unreachable))
+// vs
+//  (block (unreachable))
+// This converts to the latter form.
+// This also removes un-taken branches that would be a problem for
+// refinalization: if a block has been marked unreachable, and has
+// branches to it with values of type unreachable, then we don't
+// know the type for the block: it can't be none since the breaks
+// exist, but the breaks don't declare the type, rather everything
+// depends on the block. To avoid looking at the parent or something
+// else, just remove such un-taken branches.
+struct ReFinalize
+  : public WalkerPass<PostWalker<ReFinalize, OverriddenVisitor<ReFinalize>>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new ReFinalize; }
+
+  ReFinalize() { name = "refinalize"; }
+
+  // block finalization is O(bad) if we do each block by itself, so do it in
+  // bulk, tracking break value types so we just do a linear pass
+
+  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);
+
+  void visitFunction(Function* curr);
+
+  void visitExport(Export* curr);
+  void visitGlobal(Global* curr);
+  void visitTable(Table* curr);
+  void visitMemory(Memory* curr);
+  void visitEvent(Event* curr);
+  void visitModule(Module* curr);
+
+private:
+  void updateBreakValueType(Name name, Type type);
+
+  // Replace an untaken branch/switch with an unreachable value.
+  // A condition may also exist and may or may not be unreachable.
+  void replaceUntaken(Expression* value, Expression* condition);
+};
+
+// 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(); }
+
+  void visitExport(Export* curr) { WASM_UNREACHABLE("unimp"); }
+  void visitGlobal(Global* curr) { WASM_UNREACHABLE("unimp"); }
+  void visitTable(Table* curr) { WASM_UNREACHABLE("unimp"); }
+  void visitMemory(Memory* curr) { WASM_UNREACHABLE("unimp"); }
+  void visitEvent(Event* curr) { WASM_UNREACHABLE("unimp"); }
+  void visitModule(Module* curr) { WASM_UNREACHABLE("unimp"); }
+
+  // given a stack of nested expressions, update them all from child to parent
+  static void updateStack(ExpressionStack& expressionStack) {
+    for (int i = int(expressionStack.size()) - 1; i >= 0; i--) {
+      auto* curr = expressionStack[i];
+      ReFinalizeNode().visit(curr);
+    }
+  }
+};
+
+// Adds drop() operations where necessary. This lets you not worry about adding
+// drop when generating code. This also refinalizes before and after, as
+// dropping can change types, and depends on types being cleaned up - no
+// unnecessary block/if/loop types (see refinalize)
+// TODO: optimize that, interleave them
+struct AutoDrop : public WalkerPass<ExpressionStackWalker<AutoDrop>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new AutoDrop; }
+
+  AutoDrop() { name = "autodrop"; }
+
+  bool maybeDrop(Expression*& child) {
+    bool acted = false;
+    if (child->type.isConcrete()) {
+      expressionStack.push_back(child);
+      if (!ExpressionAnalyzer::isResultUsed(expressionStack, getFunction()) &&
+          !ExpressionAnalyzer::isResultDropped(expressionStack)) {
+        child = Builder(*getModule()).makeDrop(child);
+        acted = true;
+      }
+      expressionStack.pop_back();
+    }
+    return acted;
+  }
+
+  void reFinalize() { ReFinalizeNode::updateStack(expressionStack); }
+
+  void visitBlock(Block* curr) {
+    if (curr->list.size() == 0) {
+      return;
+    }
+    for (Index i = 0; i < curr->list.size() - 1; i++) {
+      auto* child = curr->list[i];
+      if (child->type.isConcrete()) {
+        curr->list[i] = Builder(*getModule()).makeDrop(child);
+      }
+    }
+    if (maybeDrop(curr->list.back())) {
+      reFinalize();
+      assert(curr->type == Type::none || curr->type == Type::unreachable);
+    }
+  }
+
+  void visitIf(If* curr) {
+    bool acted = false;
+    if (maybeDrop(curr->ifTrue)) {
+      acted = true;
+    }
+    if (curr->ifFalse) {
+      if (maybeDrop(curr->ifFalse)) {
+        acted = true;
+      }
+    }
+    if (acted) {
+      reFinalize();
+      assert(curr->type == Type::none);
+    }
+  }
+
+  void visitTry(Try* curr) {
+    bool acted = false;
+    if (maybeDrop(curr->body)) {
+      acted = true;
+    }
+    if (maybeDrop(curr->catchBody)) {
+      acted = true;
+    }
+    if (acted) {
+      reFinalize();
+      assert(curr->type == Type::none);
+    }
+  }
+
+  void doWalkFunction(Function* curr) {
+    ReFinalize().walkFunctionInModule(curr, getModule());
+    walk(curr->body);
+    if (curr->sig.results == Type::none && curr->body->type.isConcrete()) {
+      curr->body = Builder(*getModule()).makeDrop(curr->body);
+    }
+    ReFinalize().walkFunctionInModule(curr, getModule());
+  }
+};
+
+struct I64Utilities {
+  static Expression*
+  recreateI64(Builder& builder, Expression* low, Expression* high) {
+    return builder.makeBinary(
+      OrInt64,
+      builder.makeUnary(ExtendUInt32, low),
+      builder.makeBinary(ShlInt64,
+                         builder.makeUnary(ExtendUInt32, high),
+                         builder.makeConst(int64_t(32))));
+  };
+
+  static Expression* recreateI64(Builder& builder, Index low, Index high) {
+    return recreateI64(builder,
+                       builder.makeLocalGet(low, Type::i32),
+                       builder.makeLocalGet(high, Type::i32));
+  };
+
+  static Expression* getI64High(Builder& builder, Index index) {
+    return builder.makeUnary(
+      WrapInt64,
+      builder.makeBinary(ShrUInt64,
+                         builder.makeLocalGet(index, Type::i64),
+                         builder.makeConst(int64_t(32))));
+  }
+
+  static Expression* getI64Low(Builder& builder, Index index) {
+    return builder.makeUnary(WrapInt64, builder.makeLocalGet(index, Type::i64));
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_ir_utils_h
diff --git a/binaryen/src/js/binaryen.js-extern-post.js b/binaryen/src/js/binaryen.js-extern-post.js
new file mode 100644
--- /dev/null
+++ b/binaryen/src/js/binaryen.js-extern-post.js
@@ -0,0 +1,8 @@
+
+})();
+if (typeof exports === 'object' && typeof module === 'object')
+  module.exports = binaryen;
+else if (typeof define === 'function' && define['amd'])
+  define([], function() { return binaryen; });
+else if (typeof exports === 'object')
+  exports["binaryen"] = binaryen;
diff --git a/binaryen/src/js/binaryen.js-extern-pre.js b/binaryen/src/js/binaryen.js-extern-pre.js
new file mode 100644
--- /dev/null
+++ b/binaryen/src/js/binaryen.js-extern-pre.js
@@ -0,0 +1,2 @@
+var binaryen = {};
+(function() {
diff --git a/binaryen/src/js/binaryen.js-post.js b/binaryen/src/js/binaryen.js-post.js
new file mode 100644
--- /dev/null
+++ b/binaryen/src/js/binaryen.js-post.js
@@ -0,0 +1,4467 @@
+// export friendly API methods
+function preserveStack(func) {
+  try {
+    var stack = stackSave();
+    return func();
+  } finally {
+    stackRestore(stack);
+  }
+}
+
+function strToStack(str) {
+  return str ? allocate(intArrayFromString(str), 'i8', ALLOC_STACK) : 0;
+}
+
+function i32sToStack(i32s) {
+  const ret = stackAlloc(i32s.length << 2);
+  HEAP32.set(i32s, ret >>> 2);
+  return ret;
+}
+
+function i8sToStack(i8s) {
+  const ret = stackAlloc(i8s.length);
+  HEAP8.set(i8s, ret);
+  return ret;
+}
+
+function initializeConstants() {
+
+  // Types
+  [ ['none', 'None'],
+    ['i32', 'Int32'],
+    ['i64', 'Int64'],
+    ['f32', 'Float32'],
+    ['f64', 'Float64'],
+    ['v128', 'Vec128'],
+    ['funcref', 'Funcref'],
+    ['externref', 'Externref'],
+    ['exnref', 'Exnref'],
+    ['anyref', 'Anyref'],
+    ['eqref', 'Eqref'],
+    ['i31ref', 'I31ref'],
+    ['unreachable', 'Unreachable'],
+    ['auto', 'Auto']
+  ].forEach(entry => {
+    Module[entry[0]] = Module['_BinaryenType' + entry[1]]();
+  });
+
+  // Expression ids
+  Module['ExpressionIds'] = {};
+  [ 'Invalid',
+    'Block',
+    'If',
+    'Loop',
+    'Break',
+    'Switch',
+    'Call',
+    'CallIndirect',
+    'LocalGet',
+    'LocalSet',
+    'GlobalGet',
+    'GlobalSet',
+    'Load',
+    'Store',
+    'Const',
+    'Unary',
+    'Binary',
+    'Select',
+    'Drop',
+    'Return',
+    'MemorySize',
+    'MemoryGrow',
+    'Nop',
+    'Unreachable',
+    'AtomicCmpxchg',
+    'AtomicRMW',
+    'AtomicWait',
+    'AtomicNotify',
+    'AtomicFence',
+    'SIMDExtract',
+    'SIMDReplace',
+    'SIMDShuffle',
+    'SIMDTernary',
+    'SIMDShift',
+    'SIMDLoad',
+    'MemoryInit',
+    'DataDrop',
+    'MemoryCopy',
+    'MemoryFill',
+    'RefNull',
+    'RefIsNull',
+    'RefFunc',
+    'RefEq',
+    'Try',
+    'Throw',
+    'Rethrow',
+    'BrOnExn',
+    'TupleMake',
+    'TupleExtract',
+    'Pop',
+    'I31New',
+    'I31Get',
+    'RefTest',
+    'RefCast',
+    'BrOnCast',
+    'RttCanon',
+    'RttSub',
+    'StructNew',
+    'StructGet',
+    'StructSet',
+    'ArrayNew',
+    'ArrayGet',
+    'ArraySet',
+    'ArrayLen'
+  ].forEach(name => {
+    Module['ExpressionIds'][name] = Module[name + 'Id'] = Module['_Binaryen' + name + 'Id']();
+  });
+
+  // External kinds
+  Module['ExternalKinds'] = {};
+  [ 'Function',
+    'Table',
+    'Memory',
+    'Global',
+    'Event'
+  ].forEach(name => {
+    Module['ExternalKinds'][name] = Module['External' + name] = Module['_BinaryenExternal' + name]();
+  });
+
+  // Features
+  Module['Features'] = {};
+  [ 'MVP',
+    'Atomics',
+    'BulkMemory',
+    'MutableGlobals',
+    'NontrappingFPToInt',
+    'SignExt',
+    'SIMD128',
+    'ExceptionHandling',
+    'TailCall',
+    'ReferenceTypes',
+    'Multivalue',
+    'GC',
+    'Memory64',
+    'All'
+  ].forEach(name => {
+    Module['Features'][name] = Module['_BinaryenFeature' + name]();
+  });
+
+  // Operations
+  Module['Operations'] = {};
+  [ 'ClzInt32',
+    'CtzInt32',
+    'PopcntInt32',
+    'NegFloat32',
+    'AbsFloat32',
+    'CeilFloat32',
+    'FloorFloat32',
+    'TruncFloat32',
+    'NearestFloat32',
+    'SqrtFloat32',
+    'EqZInt32',
+    'ClzInt64',
+    'CtzInt64',
+    'PopcntInt64',
+    'NegFloat64',
+    'AbsFloat64',
+    'CeilFloat64',
+    'FloorFloat64',
+    'TruncFloat64',
+    'NearestFloat64',
+    'SqrtFloat64',
+    'EqZInt64',
+    'ExtendSInt32',
+    'ExtendUInt32',
+    'WrapInt64',
+    'TruncSFloat32ToInt32',
+    'TruncSFloat32ToInt64',
+    'TruncUFloat32ToInt32',
+    'TruncUFloat32ToInt64',
+    'TruncSFloat64ToInt32',
+    'TruncSFloat64ToInt64',
+    'TruncUFloat64ToInt32',
+    'TruncUFloat64ToInt64',
+    'TruncSatSFloat32ToInt32',
+    'TruncSatSFloat32ToInt64',
+    'TruncSatUFloat32ToInt32',
+    'TruncSatUFloat32ToInt64',
+    'TruncSatSFloat64ToInt32',
+    'TruncSatSFloat64ToInt64',
+    'TruncSatUFloat64ToInt32',
+    'TruncSatUFloat64ToInt64',
+    'ReinterpretFloat32',
+    'ReinterpretFloat64',
+    'ConvertSInt32ToFloat32',
+    'ConvertSInt32ToFloat64',
+    'ConvertUInt32ToFloat32',
+    'ConvertUInt32ToFloat64',
+    'ConvertSInt64ToFloat32',
+    'ConvertSInt64ToFloat64',
+    'ConvertUInt64ToFloat32',
+    'ConvertUInt64ToFloat64',
+    'PromoteFloat32',
+    'DemoteFloat64',
+    'ReinterpretInt32',
+    'ReinterpretInt64',
+    'ExtendS8Int32',
+    'ExtendS16Int32',
+    'ExtendS8Int64',
+    'ExtendS16Int64',
+    'ExtendS32Int64',
+    'AddInt32',
+    'SubInt32',
+    'MulInt32',
+    'DivSInt32',
+    'DivUInt32',
+    'RemSInt32',
+    'RemUInt32',
+    'AndInt32',
+    'OrInt32',
+    'XorInt32',
+    'ShlInt32',
+    'ShrUInt32',
+    'ShrSInt32',
+    'RotLInt32',
+    'RotRInt32',
+    'EqInt32',
+    'NeInt32',
+    'LtSInt32',
+    'LtUInt32',
+    'LeSInt32',
+    'LeUInt32',
+    'GtSInt32',
+    'GtUInt32',
+    'GeSInt32',
+    'GeUInt32',
+    'AddInt64',
+    'SubInt64',
+    'MulInt64',
+    'DivSInt64',
+    'DivUInt64',
+    'RemSInt64',
+    'RemUInt64',
+    'AndInt64',
+    'OrInt64',
+    'XorInt64',
+    'ShlInt64',
+    'ShrUInt64',
+    'ShrSInt64',
+    'RotLInt64',
+    'RotRInt64',
+    'EqInt64',
+    'NeInt64',
+    'LtSInt64',
+    'LtUInt64',
+    'LeSInt64',
+    'LeUInt64',
+    'GtSInt64',
+    'GtUInt64',
+    'GeSInt64',
+    'GeUInt64',
+    'AddFloat32',
+    'SubFloat32',
+    'MulFloat32',
+    'DivFloat32',
+    'CopySignFloat32',
+    'MinFloat32',
+    'MaxFloat32',
+    'EqFloat32',
+    'NeFloat32',
+    'LtFloat32',
+    'LeFloat32',
+    'GtFloat32',
+    'GeFloat32',
+    'AddFloat64',
+    'SubFloat64',
+    'MulFloat64',
+    'DivFloat64',
+    'CopySignFloat64',
+    'MinFloat64',
+    'MaxFloat64',
+    'EqFloat64',
+    'NeFloat64',
+    'LtFloat64',
+    'LeFloat64',
+    'GtFloat64',
+    'GeFloat64',
+    'AtomicRMWAdd',
+    'AtomicRMWSub',
+    'AtomicRMWAnd',
+    'AtomicRMWOr',
+    'AtomicRMWXor',
+    'AtomicRMWXchg',
+    'SplatVecI8x16',
+    'ExtractLaneSVecI8x16',
+    'ExtractLaneUVecI8x16',
+    'ReplaceLaneVecI8x16',
+    'SplatVecI16x8',
+    'ExtractLaneSVecI16x8',
+    'ExtractLaneUVecI16x8',
+    'ReplaceLaneVecI16x8',
+    'SplatVecI32x4',
+    'ExtractLaneVecI32x4',
+    'ReplaceLaneVecI32x4',
+    'SplatVecI64x2',
+    'ExtractLaneVecI64x2',
+    'ReplaceLaneVecI64x2',
+    'SplatVecF32x4',
+    'ExtractLaneVecF32x4',
+    'ReplaceLaneVecF32x4',
+    'SplatVecF64x2',
+    'ExtractLaneVecF64x2',
+    'ReplaceLaneVecF64x2',
+    'EqVecI8x16',
+    'NeVecI8x16',
+    'LtSVecI8x16',
+    'LtUVecI8x16',
+    'GtSVecI8x16',
+    'GtUVecI8x16',
+    'LeSVecI8x16',
+    'LeUVecI8x16',
+    'GeSVecI8x16',
+    'GeUVecI8x16',
+    'EqVecI16x8',
+    'NeVecI16x8',
+    'LtSVecI16x8',
+    'LtUVecI16x8',
+    'GtSVecI16x8',
+    'GtUVecI16x8',
+    'LeSVecI16x8',
+    'LeUVecI16x8',
+    'GeSVecI16x8',
+    'GeUVecI16x8',
+    'EqVecI32x4',
+    'NeVecI32x4',
+    'LtSVecI32x4',
+    'LtUVecI32x4',
+    'GtSVecI32x4',
+    'GtUVecI32x4',
+    'LeSVecI32x4',
+    'LeUVecI32x4',
+    'GeSVecI32x4',
+    'GeUVecI32x4',
+    'EqVecF32x4',
+    'NeVecF32x4',
+    'LtVecF32x4',
+    'GtVecF32x4',
+    'LeVecF32x4',
+    'GeVecF32x4',
+    'EqVecF64x2',
+    'NeVecF64x2',
+    'LtVecF64x2',
+    'GtVecF64x2',
+    'LeVecF64x2',
+    'GeVecF64x2',
+    'NotVec128',
+    'AndVec128',
+    'OrVec128',
+    'XorVec128',
+    'AndNotVec128',
+    'BitselectVec128',
+    'AbsVecI8x16',
+    'NegVecI8x16',
+    'AnyTrueVecI8x16',
+    'AllTrueVecI8x16',
+    'BitmaskVecI8x16',
+    'ShlVecI8x16',
+    'ShrSVecI8x16',
+    'ShrUVecI8x16',
+    'AddVecI8x16',
+    'AddSatSVecI8x16',
+    'AddSatUVecI8x16',
+    'SubVecI8x16',
+    'SubSatSVecI8x16',
+    'SubSatUVecI8x16',
+    'MulVecI8x16',
+    'MinSVecI8x16',
+    'MinUVecI8x16',
+    'MaxSVecI8x16',
+    'MaxUVecI8x16',
+    'AvgrUVecI8x16',
+    'AbsVecI16x8',
+    'NegVecI16x8',
+    'AnyTrueVecI16x8',
+    'AllTrueVecI16x8',
+    'BitmaskVecI16x8',
+    'ShlVecI16x8',
+    'ShrSVecI16x8',
+    'ShrUVecI16x8',
+    'AddVecI16x8',
+    'AddSatSVecI16x8',
+    'AddSatUVecI16x8',
+    'SubVecI16x8',
+    'SubSatSVecI16x8',
+    'SubSatUVecI16x8',
+    'MulVecI16x8',
+    'MinSVecI16x8',
+    'MinUVecI16x8',
+    'MaxSVecI16x8',
+    'MaxUVecI16x8',
+    'AvgrUVecI16x8',
+    'DotSVecI16x8ToVecI32x4',
+    'AbsVecI32x4',
+    'NegVecI32x4',
+    'AnyTrueVecI32x4',
+    'AllTrueVecI32x4',
+    'BitmaskVecI32x4',
+    'ShlVecI32x4',
+    'ShrSVecI32x4',
+    'ShrUVecI32x4',
+    'AddVecI32x4',
+    'SubVecI32x4',
+    'MulVecI32x4',
+    'MinSVecI32x4',
+    'MinUVecI32x4',
+    'MaxSVecI32x4',
+    'MaxUVecI32x4',
+    'NegVecI64x2',
+    'AnyTrueVecI64x2',
+    'AllTrueVecI64x2',
+    'ShlVecI64x2',
+    'ShrSVecI64x2',
+    'ShrUVecI64x2',
+    'AddVecI64x2',
+    'SubVecI64x2',
+    'MulVecI64x2',
+    'AbsVecF32x4',
+    'NegVecF32x4',
+    'SqrtVecF32x4',
+    'QFMAVecF32x4',
+    'QFMSVecF32x4',
+    'AddVecF32x4',
+    'SubVecF32x4',
+    'MulVecF32x4',
+    'DivVecF32x4',
+    'MinVecF32x4',
+    'MaxVecF32x4',
+    'PMinVecF32x4',
+    'PMaxVecF32x4',
+    'CeilVecF32x4',
+    'FloorVecF32x4',
+    'TruncVecF32x4',
+    'NearestVecF32x4',
+    'AbsVecF64x2',
+    'NegVecF64x2',
+    'SqrtVecF64x2',
+    'QFMAVecF64x2',
+    'QFMSVecF64x2',
+    'AddVecF64x2',
+    'SubVecF64x2',
+    'MulVecF64x2',
+    'DivVecF64x2',
+    'MinVecF64x2',
+    'MaxVecF64x2',
+    'PMinVecF64x2',
+    'PMaxVecF64x2',
+    'CeilVecF64x2',
+    'FloorVecF64x2',
+    'TruncVecF64x2',
+    'NearestVecF64x2',
+    'TruncSatSVecF32x4ToVecI32x4',
+    'TruncSatUVecF32x4ToVecI32x4',
+    'TruncSatSVecF64x2ToVecI64x2',
+    'TruncSatUVecF64x2ToVecI64x2',
+    'ConvertSVecI32x4ToVecF32x4',
+    'ConvertUVecI32x4ToVecF32x4',
+    'ConvertSVecI64x2ToVecF64x2',
+    'ConvertUVecI64x2ToVecF64x2',
+    'LoadSplatVec8x16',
+    'LoadSplatVec16x8',
+    'LoadSplatVec32x4',
+    'LoadSplatVec64x2',
+    'LoadExtSVec8x8ToVecI16x8',
+    'LoadExtUVec8x8ToVecI16x8',
+    'LoadExtSVec16x4ToVecI32x4',
+    'LoadExtUVec16x4ToVecI32x4',
+    'LoadExtSVec32x2ToVecI64x2',
+    'LoadExtUVec32x2ToVecI64x2',
+    'NarrowSVecI16x8ToVecI8x16',
+    'NarrowUVecI16x8ToVecI8x16',
+    'NarrowSVecI32x4ToVecI16x8',
+    'NarrowUVecI32x4ToVecI16x8',
+    'WidenLowSVecI8x16ToVecI16x8',
+    'WidenHighSVecI8x16ToVecI16x8',
+    'WidenLowUVecI8x16ToVecI16x8',
+    'WidenHighUVecI8x16ToVecI16x8',
+    'WidenLowSVecI16x8ToVecI32x4',
+    'WidenHighSVecI16x8ToVecI32x4',
+    'WidenLowUVecI16x8ToVecI32x4',
+    'WidenHighUVecI16x8ToVecI32x4',
+    'SwizzleVec8x16',
+  ].forEach(name => {
+    Module['Operations'][name] = Module[name] = Module['_Binaryen' + name]();
+  });
+
+  // Expression side effects
+  Module['SideEffects'] = {};
+  [ 'None',
+    'Branches',
+    'Calls',
+    'ReadsLocal',
+    'WritesLocal',
+    'ReadsGlobal',
+    'WritesGlobal',
+    'ReadsMemory',
+    'WritesMemory',
+    'ImplicitTrap',
+    'IsAtomic',
+    'Throws',
+    'DanglingPop',
+    'Any'
+  ].forEach(name => {
+    Module['SideEffects'][name] = Module['_BinaryenSideEffect' + name]();
+  });
+
+  // ExpressionRunner flags
+  Module['ExpressionRunner']['Flags'] = {
+    'Default': Module['_ExpressionRunnerFlagsDefault'](),
+    'PreserveSideeffects': Module['_ExpressionRunnerFlagsPreserveSideeffects'](),
+    'TraverseCalls': Module['_ExpressionRunnerFlagsTraverseCalls']()
+  };
+}
+
+// 'Module' interface
+Module['Module'] = function(module) {
+  assert(!module); // guard against incorrect old API usage
+  wrapModule(Module['_BinaryenModuleCreate'](), this);
+};
+
+// Receives a C pointer to a C Module and a JS object, and creates
+// the JS wrappings on the object to access the C data.
+// This is meant for internal use only, and is necessary as we
+// want to access Module from JS that were perhaps not created
+// from JS.
+function wrapModule(module, self = {}) {
+  assert(module); // guard against incorrect old API usage
+
+  self['ptr'] = module;
+
+  // The size of a single literal in memory as used in Const creation,
+  // which is a little different: we don't want users to need to make
+  // their own Literals, as the C API handles them by value, which means
+  // we would leak them. Instead, Const creation is fused together with
+  // an intermediate stack allocation of this size to pass the value.
+  const sizeOfLiteral = _BinaryenSizeofLiteral();
+
+  // 'Expression' creation
+  self['block'] = function(name, children, type) {
+    return preserveStack(() =>
+      Module['_BinaryenBlock'](module, name ? strToStack(name) : 0,
+                               i32sToStack(children), children.length,
+                               typeof type !== 'undefined' ? type : Module['none'])
+    );
+  };
+  self['if'] = function(condition, ifTrue, ifFalse) {
+    return Module['_BinaryenIf'](module, condition, ifTrue, ifFalse);
+  };
+  self['loop'] = function(label, body) {
+    return preserveStack(() => Module['_BinaryenLoop'](module, strToStack(label), body));
+  };
+  self['break'] = self['br'] = function(label, condition, value) {
+    return preserveStack(() => Module['_BinaryenBreak'](module, strToStack(label), condition, value));
+  };
+  self['br_if'] = function(label, condition, value) {
+    return self['br'](label, condition, value);
+  };
+  self['switch'] = function(names, defaultName, condition, value) {
+    return preserveStack(() =>
+      Module['_BinaryenSwitch'](module, i32sToStack(names.map(strToStack)), names.length, strToStack(defaultName), condition, value)
+    );
+  };
+  self['call'] = function(name, operands, type) {
+    return preserveStack(() => Module['_BinaryenCall'](module, strToStack(name), i32sToStack(operands), operands.length, type));
+  };
+  // 'callIndirect', 'returnCall', 'returnCallIndirect' are deprecated and may
+  // be removed in a future release. Please use the the snake_case names
+  // instead.
+  self['callIndirect'] = self['call_indirect'] = function(target, operands, params, results) {
+    return preserveStack(() =>
+      Module['_BinaryenCallIndirect'](module, target, i32sToStack(operands), operands.length, params, results)
+    );
+  };
+  self['returnCall'] = self['return_call'] = function(name, operands, type) {
+    return preserveStack(() =>
+      Module['_BinaryenReturnCall'](module, strToStack(name), i32sToStack(operands), operands.length, type)
+    );
+  };
+  self['returnCallIndirect'] = self['return_call_indirect'] = function(target, operands, params, results) {
+    return preserveStack(() =>
+      Module['_BinaryenReturnCallIndirect'](module, target, i32sToStack(operands), operands.length, params, results)
+    );
+  };
+
+  self['local'] = {
+    'get'(index, type) {
+      return Module['_BinaryenLocalGet'](module, index, type);
+    },
+    'set'(index, value) {
+      return Module['_BinaryenLocalSet'](module, index, value);
+    },
+    'tee'(index, value, type) {
+      if (typeof type === 'undefined') {
+        throw new Error("local.tee's type should be defined");
+      }
+      return Module['_BinaryenLocalTee'](module, index, value, type);
+    }
+  }
+
+  self['global'] = {
+    'get'(name, type) {
+      return Module['_BinaryenGlobalGet'](module, strToStack(name), type);
+    },
+    'set'(name, value) {
+      return Module['_BinaryenGlobalSet'](module, strToStack(name), value);
+    }
+  }
+
+  self['memory'] = {
+    'size'() {
+      return Module['_BinaryenMemorySize'](module);
+    },
+    'grow'(value) {
+      return Module['_BinaryenMemoryGrow'](module, value);
+    },
+    'init'(segment, dest, offset, size) {
+      return Module['_BinaryenMemoryInit'](module, segment, dest, offset, size);
+    },
+    'copy'(dest, source, size) {
+      return Module['_BinaryenMemoryCopy'](module, dest, source, size);
+    },
+    'fill'(dest, value, size) {
+      return Module['_BinaryenMemoryFill'](module, dest, value, size);
+    }
+  }
+
+  self['data'] = {
+    'drop'(segment) {
+      return Module['_BinaryenDataDrop'](module, segment);
+    }
+  }
+
+  self['i32'] = {
+    'load'(offset, align, ptr) {
+      return Module['_BinaryenLoad'](module, 4, true, offset, align, Module['i32'], ptr);
+    },
+    'load8_s'(offset, align, ptr) {
+      return Module['_BinaryenLoad'](module, 1, true, offset, align, Module['i32'], ptr);
+    },
+    'load8_u'(offset, align, ptr) {
+      return Module['_BinaryenLoad'](module, 1, false, offset, align, Module['i32'], ptr);
+    },
+    'load16_s'(offset, align, ptr) {
+      return Module['_BinaryenLoad'](module, 2, true, offset, align, Module['i32'], ptr);
+    },
+    'load16_u'(offset, align, ptr) {
+      return Module['_BinaryenLoad'](module, 2, false, offset, align, Module['i32'], ptr);
+    },
+    'store'(offset, align, ptr, value) {
+      return Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['i32']);
+    },
+    'store8'(offset, align, ptr, value) {
+      return Module['_BinaryenStore'](module, 1, offset, align, ptr, value, Module['i32']);
+    },
+    'store16'(offset, align, ptr, value) {
+      return Module['_BinaryenStore'](module, 2, offset, align, ptr, value, Module['i32']);
+    },
+    'const'(x) {
+      return preserveStack(() => {
+        const tempLiteral = stackAlloc(sizeOfLiteral);
+        Module['_BinaryenLiteralInt32'](tempLiteral, x);
+        return Module['_BinaryenConst'](module, tempLiteral);
+      });
+    },
+    'clz'(value) {
+      return Module['_BinaryenUnary'](module, Module['ClzInt32'], value);
+    },
+    'ctz'(value) {
+      return Module['_BinaryenUnary'](module, Module['CtzInt32'], value);
+    },
+    'popcnt'(value) {
+      return Module['_BinaryenUnary'](module, Module['PopcntInt32'], value);
+    },
+    'eqz'(value) {
+      return Module['_BinaryenUnary'](module, Module['EqZInt32'], value);
+    },
+    'trunc_s': {
+      'f32'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncSFloat32ToInt32'], value);
+      },
+      'f64'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncSFloat64ToInt32'], value);
+      },
+    },
+    'trunc_u': {
+      'f32'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncUFloat32ToInt32'], value);
+      },
+      'f64'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncUFloat64ToInt32'], value);
+      },
+    },
+    'trunc_s_sat': {
+      'f32'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncSatSFloat32ToInt32'], value);
+      },
+      'f64'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncSatSFloat64ToInt32'], value);
+      },
+    },
+    'trunc_u_sat': {
+      'f32'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncSatUFloat32ToInt32'], value);
+      },
+      'f64'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncSatUFloat64ToInt32'], value);
+      },
+    },
+    'reinterpret'(value) {
+      return Module['_BinaryenUnary'](module, Module['ReinterpretFloat32'], value);
+    },
+    'extend8_s'(value) {
+      return Module['_BinaryenUnary'](module, Module['ExtendS8Int32'], value);
+    },
+    'extend16_s'(value) {
+      return Module['_BinaryenUnary'](module, Module['ExtendS16Int32'], value);
+    },
+    'wrap'(value) {
+      return Module['_BinaryenUnary'](module, Module['WrapInt64'], value);
+    },
+    'add'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AddInt32'], left, right);
+    },
+    'sub'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['SubInt32'], left, right);
+    },
+    'mul'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MulInt32'], left, right);
+    },
+    'div_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['DivSInt32'], left, right);
+    },
+    'div_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['DivUInt32'], left, right);
+    },
+    'rem_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['RemSInt32'], left, right);
+    },
+    'rem_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['RemUInt32'], left, right);
+    },
+    'and'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AndInt32'], left, right);
+    },
+    'or'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['OrInt32'], left, right);
+    },
+    'xor'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['XorInt32'], left, right);
+    },
+    'shl'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['ShlInt32'], left, right);
+    },
+    'shr_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['ShrUInt32'], left, right);
+    },
+    'shr_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['ShrSInt32'], left, right);
+    },
+    'rotl'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['RotLInt32'], left, right);
+    },
+    'rotr'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['RotRInt32'], left, right);
+    },
+    'eq'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['EqInt32'], left, right);
+    },
+    'ne'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['NeInt32'], left, right);
+    },
+    'lt_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LtSInt32'], left, right);
+    },
+    'lt_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LtUInt32'], left, right);
+    },
+    'le_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LeSInt32'], left, right);
+    },
+    'le_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LeUInt32'], left, right);
+    },
+    'gt_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GtSInt32'], left, right);
+    },
+    'gt_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GtUInt32'], left, right);
+    },
+    'ge_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GeSInt32'], left, right);
+    },
+    'ge_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GeUInt32'], left, right);
+    },
+    'atomic': {
+      'load'(offset, ptr) {
+        return Module['_BinaryenAtomicLoad'](module, 4, offset, Module['i32'], ptr);
+      },
+      'load8_u'(offset, ptr) {
+        return Module['_BinaryenAtomicLoad'](module, 1, offset, Module['i32'], ptr);
+      },
+      'load16_u'(offset, ptr) {
+        return Module['_BinaryenAtomicLoad'](module, 2, offset, Module['i32'], ptr);
+      },
+      'store'(offset, ptr, value) {
+        return Module['_BinaryenAtomicStore'](module, 4, offset, ptr, value, Module['i32']);
+      },
+      'store8'(offset, ptr, value) {
+        return Module['_BinaryenAtomicStore'](module, 1, offset, ptr, value, Module['i32']);
+      },
+      'store16'(offset, ptr, value) {
+        return Module['_BinaryenAtomicStore'](module, 2, offset, ptr, value, Module['i32']);
+      },
+      'rmw': {
+        'add'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 4, offset, ptr, value, Module['i32']);
+        },
+        'sub'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 4, offset, ptr, value, Module['i32']);
+        },
+        'and'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 4, offset, ptr, value, Module['i32']);
+        },
+        'or'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 4, offset, ptr, value, Module['i32']);
+        },
+        'xor'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 4, offset, ptr, value, Module['i32']);
+        },
+        'xchg'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 4, offset, ptr, value, Module['i32']);
+        },
+        'cmpxchg'(offset, ptr, expected, replacement) {
+          return Module['_BinaryenAtomicCmpxchg'](module, 4, offset, ptr, expected, replacement, Module['i32'])
+        },
+      },
+      'rmw8_u': {
+        'add'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 1, offset, ptr, value, Module['i32']);
+        },
+        'sub'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 1, offset, ptr, value, Module['i32']);
+        },
+        'and'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 1, offset, ptr, value, Module['i32']);
+        },
+        'or'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 1, offset, ptr, value, Module['i32']);
+        },
+        'xor'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 1, offset, ptr, value, Module['i32']);
+        },
+        'xchg'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 1, offset, ptr, value, Module['i32']);
+        },
+        'cmpxchg'(offset, ptr, expected, replacement) {
+          return Module['_BinaryenAtomicCmpxchg'](module, 1, offset, ptr, expected, replacement, Module['i32'])
+        },
+      },
+      'rmw16_u': {
+        'add'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 2, offset, ptr, value, Module['i32']);
+        },
+        'sub'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 2, offset, ptr, value, Module['i32']);
+        },
+        'and'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 2, offset, ptr, value, Module['i32']);
+        },
+        'or'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 2, offset, ptr, value, Module['i32']);
+        },
+        'xor'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 2, offset, ptr, value, Module['i32']);
+        },
+        'xchg'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 2, offset, ptr, value, Module['i32']);
+        },
+        'cmpxchg'(offset, ptr, expected, replacement) {
+          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']);
+    }
+  };
+
+  self['i64'] = {
+    'load'(offset, align, ptr) {
+      return Module['_BinaryenLoad'](module, 8, true, offset, align, Module['i64'], ptr);
+    },
+    'load8_s'(offset, align, ptr) {
+      return Module['_BinaryenLoad'](module, 1, true, offset, align, Module['i64'], ptr);
+    },
+    'load8_u'(offset, align, ptr) {
+      return Module['_BinaryenLoad'](module, 1, false, offset, align, Module['i64'], ptr);
+    },
+    'load16_s'(offset, align, ptr) {
+      return Module['_BinaryenLoad'](module, 2, true, offset, align, Module['i64'], ptr);
+    },
+    'load16_u'(offset, align, ptr) {
+      return Module['_BinaryenLoad'](module, 2, false, offset, align, Module['i64'], ptr);
+    },
+    'load32_s'(offset, align, ptr) {
+      return Module['_BinaryenLoad'](module, 4, true, offset, align, Module['i64'], ptr);
+    },
+    'load32_u'(offset, align, ptr) {
+      return Module['_BinaryenLoad'](module, 4, false, offset, align, Module['i64'], ptr);
+    },
+    'store'(offset, align, ptr, value) {
+      return Module['_BinaryenStore'](module, 8, offset, align, ptr, value, Module['i64']);
+    },
+    'store8'(offset, align, ptr, value) {
+      return Module['_BinaryenStore'](module, 1, offset, align, ptr, value, Module['i64']);
+    },
+    'store16'(offset, align, ptr, value) {
+      return Module['_BinaryenStore'](module, 2, offset, align, ptr, value, Module['i64']);
+    },
+    'store32'(offset, align, ptr, value) {
+      return Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['i64']);
+    },
+    'const'(x, y) {
+      return preserveStack(() => {
+        const tempLiteral = stackAlloc(sizeOfLiteral);
+        Module['_BinaryenLiteralInt64'](tempLiteral, x, y);
+        return Module['_BinaryenConst'](module, tempLiteral);
+      });
+    },
+    'clz'(value) {
+      return Module['_BinaryenUnary'](module, Module['ClzInt64'], value);
+    },
+    'ctz'(value) {
+      return Module['_BinaryenUnary'](module, Module['CtzInt64'], value);
+    },
+    'popcnt'(value) {
+      return Module['_BinaryenUnary'](module, Module['PopcntInt64'], value);
+    },
+    'eqz'(value) {
+      return Module['_BinaryenUnary'](module, Module['EqZInt64'], value);
+    },
+    'trunc_s': {
+      'f32'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncSFloat32ToInt64'], value);
+      },
+      'f64'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncSFloat64ToInt64'], value);
+      },
+    },
+    'trunc_u': {
+      'f32'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncUFloat32ToInt64'], value);
+      },
+      'f64'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncUFloat64ToInt64'], value);
+      },
+    },
+    'trunc_s_sat': {
+      'f32'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncSatSFloat32ToInt64'], value);
+      },
+      'f64'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncSatSFloat64ToInt64'], value);
+      },
+    },
+    'trunc_u_sat': {
+      'f32'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncSatUFloat32ToInt64'], value);
+      },
+      'f64'(value) {
+        return Module['_BinaryenUnary'](module, Module['TruncSatUFloat64ToInt64'], value);
+      },
+    },
+    'reinterpret'(value) {
+      return Module['_BinaryenUnary'](module, Module['ReinterpretFloat64'], value);
+    },
+    'extend8_s'(value) {
+      return Module['_BinaryenUnary'](module, Module['ExtendS8Int64'], value);
+    },
+    'extend16_s'(value) {
+      return Module['_BinaryenUnary'](module, Module['ExtendS16Int64'], value);
+    },
+    'extend32_s'(value) {
+      return Module['_BinaryenUnary'](module, Module['ExtendS32Int64'], value);
+    },
+    'extend_s'(value) {
+      return Module['_BinaryenUnary'](module, Module['ExtendSInt32'], value);
+    },
+    'extend_u'(value) {
+      return Module['_BinaryenUnary'](module, Module['ExtendUInt32'], value);
+    },
+    'add'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AddInt64'], left, right);
+    },
+    'sub'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['SubInt64'], left, right);
+    },
+    'mul'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MulInt64'], left, right);
+    },
+    'div_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['DivSInt64'], left, right);
+    },
+    'div_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['DivUInt64'], left, right);
+    },
+    'rem_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['RemSInt64'], left, right);
+    },
+    'rem_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['RemUInt64'], left, right);
+    },
+    'and'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AndInt64'], left, right);
+    },
+    'or'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['OrInt64'], left, right);
+    },
+    'xor'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['XorInt64'], left, right);
+    },
+    'shl'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['ShlInt64'], left, right);
+    },
+    'shr_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['ShrUInt64'], left, right);
+    },
+    'shr_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['ShrSInt64'], left, right);
+    },
+    'rotl'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['RotLInt64'], left, right);
+    },
+    'rotr'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['RotRInt64'], left, right);
+    },
+    'eq'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['EqInt64'], left, right);
+    },
+    'ne'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['NeInt64'], left, right);
+    },
+    'lt_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LtSInt64'], left, right);
+    },
+    'lt_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LtUInt64'], left, right);
+    },
+    'le_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LeSInt64'], left, right);
+    },
+    'le_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LeUInt64'], left, right);
+    },
+    'gt_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GtSInt64'], left, right);
+    },
+    'gt_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GtUInt64'], left, right);
+    },
+    'ge_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GeSInt64'], left, right);
+    },
+    'ge_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GeUInt64'], left, right);
+    },
+    'atomic': {
+      'load'(offset, ptr) {
+        return Module['_BinaryenAtomicLoad'](module, 8, offset, Module['i64'], ptr);
+      },
+      'load8_u'(offset, ptr) {
+        return Module['_BinaryenAtomicLoad'](module, 1, offset, Module['i64'], ptr);
+      },
+      'load16_u'(offset, ptr) {
+        return Module['_BinaryenAtomicLoad'](module, 2, offset, Module['i64'], ptr);
+      },
+      'load32_u'(offset, ptr) {
+        return Module['_BinaryenAtomicLoad'](module, 4, offset, Module['i64'], ptr);
+      },
+      'store'(offset, ptr, value) {
+        return Module['_BinaryenAtomicStore'](module, 8, offset, ptr, value, Module['i64']);
+      },
+      'store8'(offset, ptr, value) {
+        return Module['_BinaryenAtomicStore'](module, 1, offset, ptr, value, Module['i64']);
+      },
+      'store16'(offset, ptr, value) {
+        return Module['_BinaryenAtomicStore'](module, 2, offset, ptr, value, Module['i64']);
+      },
+      'store32'(offset, ptr, value) {
+        return Module['_BinaryenAtomicStore'](module, 4, offset, ptr, value, Module['i64']);
+      },
+      'rmw': {
+        'add'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 8, offset, ptr, value, Module['i64']);
+        },
+        'sub'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 8, offset, ptr, value, Module['i64']);
+        },
+        'and'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 8, offset, ptr, value, Module['i64']);
+        },
+        'or'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 8, offset, ptr, value, Module['i64']);
+        },
+        'xor'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 8, offset, ptr, value, Module['i64']);
+        },
+        'xchg'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 8, offset, ptr, value, Module['i64']);
+        },
+        'cmpxchg'(offset, ptr, expected, replacement) {
+          return Module['_BinaryenAtomicCmpxchg'](module, 8, offset, ptr, expected, replacement, Module['i64'])
+        },
+      },
+      'rmw8_u': {
+        'add'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 1, offset, ptr, value, Module['i64']);
+        },
+        'sub'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 1, offset, ptr, value, Module['i64']);
+        },
+        'and'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 1, offset, ptr, value, Module['i64']);
+        },
+        'or'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 1, offset, ptr, value, Module['i64']);
+        },
+        'xor'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 1, offset, ptr, value, Module['i64']);
+        },
+        'xchg'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 1, offset, ptr, value, Module['i64']);
+        },
+        'cmpxchg'(offset, ptr, expected, replacement) {
+          return Module['_BinaryenAtomicCmpxchg'](module, 1, offset, ptr, expected, replacement, Module['i64'])
+        },
+      },
+      'rmw16_u': {
+        'add'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 2, offset, ptr, value, Module['i64']);
+        },
+        'sub'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 2, offset, ptr, value, Module['i64']);
+        },
+        'and'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 2, offset, ptr, value, Module['i64']);
+        },
+        'or'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 2, offset, ptr, value, Module['i64']);
+        },
+        'xor'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 2, offset, ptr, value, Module['i64']);
+        },
+        'xchg'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 2, offset, ptr, value, Module['i64']);
+        },
+        'cmpxchg'(offset, ptr, expected, replacement) {
+          return Module['_BinaryenAtomicCmpxchg'](module, 2, offset, ptr, expected, replacement, Module['i64'])
+        },
+      },
+      'rmw32_u': {
+        'add'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 4, offset, ptr, value, Module['i64']);
+        },
+        'sub'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 4, offset, ptr, value, Module['i64']);
+        },
+        'and'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 4, offset, ptr, value, Module['i64']);
+        },
+        'or'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 4, offset, ptr, value, Module['i64']);
+        },
+        'xor'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 4, offset, ptr, value, Module['i64']);
+        },
+        'xchg'(offset, ptr, value) {
+          return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 4, offset, ptr, value, Module['i64']);
+        },
+        'cmpxchg'(offset, ptr, expected, replacement) {
+          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']);
+    }
+  };
+
+  self['f32'] = {
+    'load'(offset, align, ptr) {
+      return Module['_BinaryenLoad'](module, 4, true, offset, align, Module['f32'], ptr);
+    },
+    'store'(offset, align, ptr, value) {
+      return Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['f32']);
+    },
+    'const'(x) {
+      return preserveStack(() => {
+        const tempLiteral = stackAlloc(sizeOfLiteral);
+        Module['_BinaryenLiteralFloat32'](tempLiteral, x);
+        return Module['_BinaryenConst'](module, tempLiteral);
+      });
+    },
+    'const_bits'(x) {
+      return preserveStack(() => {
+        const tempLiteral = stackAlloc(sizeOfLiteral);
+        Module['_BinaryenLiteralFloat32Bits'](tempLiteral, x);
+        return Module['_BinaryenConst'](module, tempLiteral);
+      });
+    },
+    'neg'(value) {
+      return Module['_BinaryenUnary'](module, Module['NegFloat32'], value);
+    },
+    'abs'(value) {
+      return Module['_BinaryenUnary'](module, Module['AbsFloat32'], value);
+    },
+    'ceil'(value) {
+      return Module['_BinaryenUnary'](module, Module['CeilFloat32'], value);
+    },
+    'floor'(value) {
+      return Module['_BinaryenUnary'](module, Module['FloorFloat32'], value);
+    },
+    'trunc'(value) {
+      return Module['_BinaryenUnary'](module, Module['TruncFloat32'], value);
+    },
+    'nearest'(value) {
+      return Module['_BinaryenUnary'](module, Module['NearestFloat32'], value);
+    },
+    'sqrt'(value) {
+      return Module['_BinaryenUnary'](module, Module['SqrtFloat32'], value);
+    },
+    'reinterpret'(value) {
+      return Module['_BinaryenUnary'](module, Module['ReinterpretInt32'], value);
+    },
+    'convert_s': {
+      'i32'(value) {
+        return Module['_BinaryenUnary'](module, Module['ConvertSInt32ToFloat32'], value);
+      },
+      'i64'(value) {
+        return Module['_BinaryenUnary'](module, Module['ConvertSInt64ToFloat32'], value);
+      },
+    },
+    'convert_u': {
+      'i32'(value) {
+        return Module['_BinaryenUnary'](module, Module['ConvertUInt32ToFloat32'], value);
+      },
+      'i64'(value) {
+        return Module['_BinaryenUnary'](module, Module['ConvertUInt64ToFloat32'], value);
+      },
+    },
+    'demote'(value) {
+      return Module['_BinaryenUnary'](module, Module['DemoteFloat64'], value);
+    },
+    'add'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AddFloat32'], left, right);
+    },
+    'sub'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['SubFloat32'], left, right);
+    },
+    'mul'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MulFloat32'], left, right);
+    },
+    'div'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['DivFloat32'], left, right);
+    },
+    'copysign'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['CopySignFloat32'], left, right);
+    },
+    'min'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MinFloat32'], left, right);
+    },
+    'max'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MaxFloat32'], left, right);
+    },
+    'eq'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['EqFloat32'], left, right);
+    },
+    'ne'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['NeFloat32'], left, right);
+    },
+    'lt'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LtFloat32'], left, right);
+    },
+    'le'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LeFloat32'], left, right);
+    },
+    'gt'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GtFloat32'], left, right);
+    },
+    'ge'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GeFloat32'], left, right);
+    },
+    'pop'() {
+      return Module['_BinaryenPop'](module, Module['f32']);
+    }
+  };
+
+  self['f64'] = {
+    'load'(offset, align, ptr) {
+      return Module['_BinaryenLoad'](module, 8, true, offset, align, Module['f64'], ptr);
+    },
+    'store'(offset, align, ptr, value) {
+      return Module['_BinaryenStore'](module, 8, offset, align, ptr, value, Module['f64']);
+    },
+    'const'(x) {
+      return preserveStack(() => {
+        const tempLiteral = stackAlloc(sizeOfLiteral);
+        Module['_BinaryenLiteralFloat64'](tempLiteral, x);
+        return Module['_BinaryenConst'](module, tempLiteral);
+      });
+    },
+    'const_bits'(x, y) {
+      return preserveStack(() => {
+        const tempLiteral = stackAlloc(sizeOfLiteral);
+        Module['_BinaryenLiteralFloat64Bits'](tempLiteral, x, y);
+        return Module['_BinaryenConst'](module, tempLiteral);
+      });
+    },
+    'neg'(value) {
+      return Module['_BinaryenUnary'](module, Module['NegFloat64'], value);
+    },
+    'abs'(value) {
+      return Module['_BinaryenUnary'](module, Module['AbsFloat64'], value);
+    },
+    'ceil'(value) {
+      return Module['_BinaryenUnary'](module, Module['CeilFloat64'], value);
+    },
+    'floor'(value) {
+      return Module['_BinaryenUnary'](module, Module['FloorFloat64'], value);
+    },
+    'trunc'(value) {
+      return Module['_BinaryenUnary'](module, Module['TruncFloat64'], value);
+    },
+    'nearest'(value) {
+      return Module['_BinaryenUnary'](module, Module['NearestFloat64'], value);
+    },
+    'sqrt'(value) {
+      return Module['_BinaryenUnary'](module, Module['SqrtFloat64'], value);
+    },
+    'reinterpret'(value) {
+      return Module['_BinaryenUnary'](module, Module['ReinterpretInt64'], value);
+    },
+    'convert_s': {
+      'i32'(value) {
+        return Module['_BinaryenUnary'](module, Module['ConvertSInt32ToFloat64'], value);
+      },
+      'i64'(value) {
+        return Module['_BinaryenUnary'](module, Module['ConvertSInt64ToFloat64'], value);
+      },
+    },
+    'convert_u': {
+      'i32'(value) {
+        return Module['_BinaryenUnary'](module, Module['ConvertUInt32ToFloat64'], value);
+      },
+      'i64'(value) {
+        return Module['_BinaryenUnary'](module, Module['ConvertUInt64ToFloat64'], value);
+      },
+    },
+    'promote'(value) {
+      return Module['_BinaryenUnary'](module, Module['PromoteFloat32'], value);
+    },
+    'add'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AddFloat64'], left, right);
+    },
+    'sub'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['SubFloat64'], left, right);
+    },
+    'mul'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MulFloat64'], left, right);
+    },
+    'div'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['DivFloat64'], left, right);
+    },
+    'copysign'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['CopySignFloat64'], left, right);
+    },
+    'min'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MinFloat64'], left, right);
+    },
+    'max'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MaxFloat64'], left, right);
+    },
+    'eq'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['EqFloat64'], left, right);
+    },
+    'ne'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['NeFloat64'], left, right);
+    },
+    'lt'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LtFloat64'], left, right);
+    },
+    'le'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LeFloat64'], left, right);
+    },
+    'gt'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GtFloat64'], left, right);
+    },
+    'ge'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GeFloat64'], left, right);
+    },
+    'pop'() {
+      return Module['_BinaryenPop'](module, Module['f64']);
+    }
+  };
+
+  self['v128'] = {
+    'load'(offset, align, ptr) {
+      return Module['_BinaryenLoad'](module, 16, false, offset, align, Module['v128'], ptr);
+    },
+    'store'(offset, align, ptr, value) {
+      return Module['_BinaryenStore'](module, 16, offset, align, ptr, value, Module['v128']);
+    },
+    'const'(i8s) {
+      return preserveStack(() => {
+        const tempLiteral = stackAlloc(sizeOfLiteral);
+        Module['_BinaryenLiteralVec128'](tempLiteral, i8sToStack(i8s));
+        return Module['_BinaryenConst'](module, tempLiteral);
+      });
+    },
+    'not'(value) {
+      return Module['_BinaryenUnary'](module, Module['NotVec128'], value);
+    },
+    'and'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AndVec128'], left, right);
+    },
+    'or'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['OrVec128'], left, right);
+    },
+    'xor'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['XorVec128'], left, right);
+    },
+    'andnot'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AndNotVec128'], left, right);
+    },
+    'bitselect'(left, right, cond) {
+      return Module['_BinaryenSIMDTernary'](module, Module['BitselectVec128'], left, right, cond);
+    },
+    'pop'() {
+      return Module['_BinaryenPop'](module, Module['v128']);
+    }
+  };
+
+  self['i8x16'] = {
+    'splat'(value) {
+      return Module['_BinaryenUnary'](module, Module['SplatVecI8x16'], value);
+    },
+    'extract_lane_s'(vec, index) {
+      return Module['_BinaryenSIMDExtract'](module, Module['ExtractLaneSVecI8x16'], vec, index);
+    },
+    'extract_lane_u'(vec, index) {
+      return Module['_BinaryenSIMDExtract'](module, Module['ExtractLaneUVecI8x16'], vec, index);
+    },
+    'replace_lane'(vec, index, value) {
+      return Module['_BinaryenSIMDReplace'](module, Module['ReplaceLaneVecI8x16'], vec, index, value);
+    },
+    'eq'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['EqVecI8x16'], left, right);
+    },
+    'ne'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['NeVecI8x16'], left, right);
+    },
+    'lt_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LtSVecI8x16'], left, right);
+    },
+    'lt_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LtUVecI8x16'], left, right);
+    },
+    'gt_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GtSVecI8x16'], left, right);
+    },
+    'gt_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GtUVecI8x16'], left, right);
+    },
+    'le_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LeSVecI8x16'], left, right);
+    },
+    'le_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LeUVecI8x16'], left, right);
+    },
+    'ge_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GeSVecI8x16'], left, right);
+    },
+    'ge_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GeUVecI8x16'], left, right);
+    },
+    'abs'(value) {
+      return Module['_BinaryenUnary'](module, Module['AbsVecI8x16'], value);
+    },
+    'neg'(value) {
+      return Module['_BinaryenUnary'](module, Module['NegVecI8x16'], value);
+    },
+    'any_true'(value) {
+      return Module['_BinaryenUnary'](module, Module['AnyTrueVecI8x16'], value);
+    },
+    'all_true'(value) {
+      return Module['_BinaryenUnary'](module, Module['AllTrueVecI8x16'], value);
+    },
+    'bitmask'(value) {
+      return Module['_BinaryenUnary'](module, Module['BitmaskVecI8x16'], value);
+    },
+    'shl'(vec, shift) {
+      return Module['_BinaryenSIMDShift'](module, Module['ShlVecI8x16'], vec, shift);
+    },
+    'shr_s'(vec, shift) {
+      return Module['_BinaryenSIMDShift'](module, Module['ShrSVecI8x16'], vec, shift);
+    },
+    'shr_u'(vec, shift) {
+      return Module['_BinaryenSIMDShift'](module, Module['ShrUVecI8x16'], vec, shift);
+    },
+    'add'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AddVecI8x16'], left, right);
+    },
+    'add_saturate_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AddSatSVecI8x16'], left, right);
+    },
+    'add_saturate_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AddSatUVecI8x16'], left, right);
+    },
+    'sub'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['SubVecI8x16'], left, right);
+    },
+    'sub_saturate_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['SubSatSVecI8x16'], left, right);
+    },
+    'sub_saturate_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['SubSatUVecI8x16'], left, right);
+    },
+    'mul'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MulVecI8x16'], left, right);
+    },
+    'min_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MinSVecI8x16'], left, right);
+    },
+    'min_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MinUVecI8x16'], left, right);
+    },
+    'max_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MaxSVecI8x16'], left, right);
+    },
+    'max_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MaxUVecI8x16'], left, right);
+    },
+    'avgr_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AvgrUVecI8x16'], left, right);
+    },
+    'narrow_i16x8_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['NarrowSVecI16x8ToVecI8x16'], left, right);
+    },
+    'narrow_i16x8_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['NarrowUVecI16x8ToVecI8x16'], left, right);
+    },
+  };
+
+  self['i16x8'] = {
+    'splat'(value) {
+      return Module['_BinaryenUnary'](module, Module['SplatVecI16x8'], value);
+    },
+    'extract_lane_s'(vec, index) {
+      return Module['_BinaryenSIMDExtract'](module, Module['ExtractLaneSVecI16x8'], vec, index);
+    },
+    'extract_lane_u'(vec, index) {
+      return Module['_BinaryenSIMDExtract'](module, Module['ExtractLaneUVecI16x8'], vec, index);
+    },
+    'replace_lane'(vec, index, value) {
+      return Module['_BinaryenSIMDReplace'](module, Module['ReplaceLaneVecI16x8'], vec, index, value);
+    },
+    'eq'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['EqVecI16x8'], left, right);
+    },
+    'ne'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['NeVecI16x8'], left, right);
+    },
+    'lt_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LtSVecI16x8'], left, right);
+    },
+    'lt_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LtUVecI16x8'], left, right);
+    },
+    'gt_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GtSVecI16x8'], left, right);
+    },
+    'gt_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GtUVecI16x8'], left, right);
+    },
+    'le_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LeSVecI16x8'], left, right);
+    },
+    'le_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LeUVecI16x8'], left, right);
+    },
+    'ge_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GeSVecI16x8'], left, right);
+    },
+    'ge_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GeUVecI16x8'], left, right);
+    },
+    'abs'(value) {
+      return Module['_BinaryenUnary'](module, Module['AbsVecI16x8'], value);
+    },
+    'neg'(value) {
+      return Module['_BinaryenUnary'](module, Module['NegVecI16x8'], value);
+    },
+    'any_true'(value) {
+      return Module['_BinaryenUnary'](module, Module['AnyTrueVecI16x8'], value);
+    },
+    'all_true'(value) {
+      return Module['_BinaryenUnary'](module, Module['AllTrueVecI16x8'], value);
+    },
+    'bitmask'(value) {
+      return Module['_BinaryenUnary'](module, Module['BitmaskVecI16x8'], value);
+    },
+    'shl'(vec, shift) {
+      return Module['_BinaryenSIMDShift'](module, Module['ShlVecI16x8'], vec, shift);
+    },
+    'shr_s'(vec, shift) {
+      return Module['_BinaryenSIMDShift'](module, Module['ShrSVecI16x8'], vec, shift);
+    },
+    'shr_u'(vec, shift) {
+      return Module['_BinaryenSIMDShift'](module, Module['ShrUVecI16x8'], vec, shift);
+    },
+    'add'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AddVecI16x8'], left, right);
+    },
+    'add_saturate_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AddSatSVecI16x8'], left, right);
+    },
+    'add_saturate_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AddSatUVecI16x8'], left, right);
+    },
+    'sub'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['SubVecI16x8'], left, right);
+    },
+    'sub_saturate_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['SubSatSVecI16x8'], left, right);
+    },
+    'sub_saturate_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['SubSatUVecI16x8'], left, right);
+    },
+    'mul'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MulVecI16x8'], left, right);
+    },
+    'min_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MinSVecI16x8'], left, right);
+    },
+    'min_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MinUVecI16x8'], left, right);
+    },
+    'max_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MaxSVecI16x8'], left, right);
+    },
+    'max_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MaxUVecI16x8'], left, right);
+    },
+    'avgr_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AvgrUVecI16x8'], left, right);
+    },
+    'narrow_i32x4_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['NarrowSVecI32x4ToVecI16x8'], left, right);
+    },
+    'narrow_i32x4_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['NarrowUVecI32x4ToVecI16x8'], left, right);
+    },
+    'widen_low_i8x16_s'(value) {
+      return Module['_BinaryenUnary'](module, Module['WidenLowSVecI8x16ToVecI16x8'], value);
+    },
+    'widen_high_i8x16_s'(value) {
+      return Module['_BinaryenUnary'](module, Module['WidenHighSVecI8x16ToVecI16x8'], value);
+    },
+    'widen_low_i8x16_u'(value) {
+      return Module['_BinaryenUnary'](module, Module['WidenLowUVecI8x16ToVecI16x8'], value);
+    },
+    'widen_high_i8x16_u'(value) {
+      return Module['_BinaryenUnary'](module, Module['WidenHighUVecI8x16ToVecI16x8'], value);
+    },
+    'load8x8_s'(offset, align, ptr) {
+      return Module['_BinaryenSIMDLoad'](module, Module['LoadExtSVec8x8ToVecI16x8'], offset, align, ptr);
+    },
+    'load8x8_u'(offset, align, ptr) {
+      return Module['_BinaryenSIMDLoad'](module, Module['LoadExtUVec8x8ToVecI16x8'], offset, align, ptr);
+    },
+  };
+
+  self['i32x4'] = {
+    'splat'(value) {
+      return Module['_BinaryenUnary'](module, Module['SplatVecI32x4'], value);
+    },
+    'extract_lane'(vec, index) {
+      return Module['_BinaryenSIMDExtract'](module, Module['ExtractLaneVecI32x4'], vec, index);
+    },
+    'replace_lane'(vec, index, value) {
+      return Module['_BinaryenSIMDReplace'](module, Module['ReplaceLaneVecI32x4'], vec, index, value);
+    },
+    'eq'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['EqVecI32x4'], left, right);
+    },
+    'ne'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['NeVecI32x4'], left, right);
+    },
+    'lt_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LtSVecI32x4'], left, right);
+    },
+    'lt_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LtUVecI32x4'], left, right);
+    },
+    'gt_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GtSVecI32x4'], left, right);
+    },
+    'gt_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GtUVecI32x4'], left, right);
+    },
+    'le_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LeSVecI32x4'], left, right);
+    },
+    'le_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LeUVecI32x4'], left, right);
+    },
+    'ge_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GeSVecI32x4'], left, right);
+    },
+    'ge_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GeUVecI32x4'], left, right);
+    },
+    'abs'(value) {
+      return Module['_BinaryenUnary'](module, Module['AbsVecI32x4'], value);
+    },
+    'neg'(value) {
+      return Module['_BinaryenUnary'](module, Module['NegVecI32x4'], value);
+    },
+    'any_true'(value) {
+      return Module['_BinaryenUnary'](module, Module['AnyTrueVecI32x4'], value);
+    },
+    'all_true'(value) {
+      return Module['_BinaryenUnary'](module, Module['AllTrueVecI32x4'], value);
+    },
+    'bitmask'(value) {
+      return Module['_BinaryenUnary'](module, Module['BitmaskVecI32x4'], value);
+    },
+    'shl'(vec, shift) {
+      return Module['_BinaryenSIMDShift'](module, Module['ShlVecI32x4'], vec, shift);
+    },
+    'shr_s'(vec, shift) {
+      return Module['_BinaryenSIMDShift'](module, Module['ShrSVecI32x4'], vec, shift);
+    },
+    'shr_u'(vec, shift) {
+      return Module['_BinaryenSIMDShift'](module, Module['ShrUVecI32x4'], vec, shift);
+    },
+    'add'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AddVecI32x4'], left, right);
+    },
+    'sub'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['SubVecI32x4'], left, right);
+    },
+    'mul'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MulVecI32x4'], left, right);
+    },
+    'min_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MinSVecI32x4'], left, right);
+    },
+    'min_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MinUVecI32x4'], left, right);
+    },
+    'max_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MaxSVecI32x4'], left, right);
+    },
+    'max_u'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MaxUVecI32x4'], left, right);
+    },
+    'dot_i16x8_s'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['DotSVecI16x8ToVecI32x4'], left, right);
+    },
+    'trunc_sat_f32x4_s'(value) {
+      return Module['_BinaryenUnary'](module, Module['TruncSatSVecF32x4ToVecI32x4'], value);
+    },
+    'trunc_sat_f32x4_u'(value) {
+      return Module['_BinaryenUnary'](module, Module['TruncSatUVecF32x4ToVecI32x4'], value);
+    },
+    'widen_low_i16x8_s'(value) {
+      return Module['_BinaryenUnary'](module, Module['WidenLowSVecI16x8ToVecI32x4'], value);
+    },
+    'widen_high_i16x8_s'(value) {
+      return Module['_BinaryenUnary'](module, Module['WidenHighSVecI16x8ToVecI32x4'], value);
+    },
+    'widen_low_i16x8_u'(value) {
+      return Module['_BinaryenUnary'](module, Module['WidenLowUVecI16x8ToVecI32x4'], value);
+    },
+    'widen_high_i16x8_u'(value) {
+      return Module['_BinaryenUnary'](module, Module['WidenHighUVecI16x8ToVecI32x4'], value);
+    },
+    'load16x4_s'(offset, align, ptr) {
+      return Module['_BinaryenSIMDLoad'](module, Module['LoadExtSVec16x4ToVecI32x4'], offset, align, ptr);
+    },
+    'load16x4_u'(offset, align, ptr) {
+      return Module['_BinaryenSIMDLoad'](module, Module['LoadExtUVec16x4ToVecI32x4'], offset, align, ptr);
+    },
+  };
+
+  self['i64x2'] = {
+    'splat'(value) {
+      return Module['_BinaryenUnary'](module, Module['SplatVecI64x2'], value);
+    },
+    'extract_lane'(vec, index) {
+      return Module['_BinaryenSIMDExtract'](module, Module['ExtractLaneVecI64x2'], vec, index);
+    },
+    'replace_lane'(vec, index, value) {
+      return Module['_BinaryenSIMDReplace'](module, Module['ReplaceLaneVecI64x2'], vec, index, value);
+    },
+    '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);
+    },
+    'shr_s'(vec, shift) {
+      return Module['_BinaryenSIMDShift'](module, Module['ShrSVecI64x2'], vec, shift);
+    },
+    'shr_u'(vec, shift) {
+      return Module['_BinaryenSIMDShift'](module, Module['ShrUVecI64x2'], vec, shift);
+    },
+    'add'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AddVecI64x2'], left, right);
+    },
+    'sub'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['SubVecI64x2'], left, right);
+    },
+    'mul'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MulVecI64x2'], left, right);
+    },
+    'trunc_sat_f64x2_s'(value) {
+      return Module['_BinaryenUnary'](module, Module['TruncSatSVecF64x2ToVecI64x2'], value);
+    },
+    'trunc_sat_f64x2_u'(value) {
+      return Module['_BinaryenUnary'](module, Module['TruncSatUVecF64x2ToVecI64x2'], value);
+    },
+    'load32x2_s'(offset, align, ptr) {
+      return Module['_BinaryenSIMDLoad'](module, Module['LoadExtSVec32x2ToVecI64x2'], offset, align, ptr);
+    },
+    'load32x2_u'(offset, align, ptr) {
+      return Module['_BinaryenSIMDLoad'](module, Module['LoadExtUVec32x2ToVecI64x2'], offset, align, ptr);
+    },
+  };
+
+  self['f32x4'] = {
+    'splat'(value) {
+      return Module['_BinaryenUnary'](module, Module['SplatVecF32x4'], value);
+    },
+    'extract_lane'(vec, index) {
+      return Module['_BinaryenSIMDExtract'](module, Module['ExtractLaneVecF32x4'], vec, index);
+    },
+    'replace_lane'(vec, index, value) {
+      return Module['_BinaryenSIMDReplace'](module, Module['ReplaceLaneVecF32x4'], vec, index, value);
+    },
+    'eq'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['EqVecF32x4'], left, right);
+    },
+    'ne'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['NeVecF32x4'], left, right);
+    },
+    'lt'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LtVecF32x4'], left, right);
+    },
+    'gt'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GtVecF32x4'], left, right);
+    },
+    'le'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LeVecF32x4'], left, right);
+    },
+    'ge'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GeVecF32x4'], left, right);
+    },
+    'abs'(value) {
+      return Module['_BinaryenUnary'](module, Module['AbsVecF32x4'], value);
+    },
+    'neg'(value) {
+      return Module['_BinaryenUnary'](module, Module['NegVecF32x4'], value);
+    },
+    'sqrt'(value) {
+      return Module['_BinaryenUnary'](module, Module['SqrtVecF32x4'], value);
+    },
+    'qfma'(a, b, c) {
+      return Module['_BinaryenSIMDTernary'](module, Module['QFMAVecF32x4'], a, b, c);
+    },
+    'qfms'(a, b, c) {
+      return Module['_BinaryenSIMDTernary'](module, Module['QFMSVecF32x4'], a, b, c);
+    },
+    'add'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AddVecF32x4'], left, right);
+    },
+    'sub'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['SubVecF32x4'], left, right);
+    },
+    'mul'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MulVecF32x4'], left, right);
+    },
+    'div'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['DivVecF32x4'], left, right);
+    },
+    'min'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MinVecF32x4'], left, right);
+    },
+    'max'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MaxVecF32x4'], left, right);
+    },
+    'pmin'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['PMinVecF32x4'], left, right);
+    },
+    'pmax'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['PMaxVecF32x4'], left, right);
+    },
+    'ceil'(value) {
+      return Module['_BinaryenUnary'](module, Module['CeilVecF32x4'], value);
+    },
+    'floor'(value) {
+      return Module['_BinaryenUnary'](module, Module['FloorVecF32x4'], value);
+    },
+    'trunc'(value) {
+      return Module['_BinaryenUnary'](module, Module['TruncVecF32x4'], value);
+    },
+    'nearest'(value) {
+      return Module['_BinaryenUnary'](module, Module['NearestVecF32x4'], value);
+    },
+    'convert_i32x4_s'(value) {
+      return Module['_BinaryenUnary'](module, Module['ConvertSVecI32x4ToVecF32x4'], value);
+    },
+    'convert_i32x4_u'(value) {
+      return Module['_BinaryenUnary'](module, Module['ConvertUVecI32x4ToVecF32x4'], value);
+    },
+  };
+
+  self['f64x2'] = {
+    'splat'(value) {
+      return Module['_BinaryenUnary'](module, Module['SplatVecF64x2'], value);
+    },
+    'extract_lane'(vec, index) {
+      return Module['_BinaryenSIMDExtract'](module, Module['ExtractLaneVecF64x2'], vec, index);
+    },
+    'replace_lane'(vec, index, value) {
+      return Module['_BinaryenSIMDReplace'](module, Module['ReplaceLaneVecF64x2'], vec, index, value);
+    },
+    'eq'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['EqVecF64x2'], left, right);
+    },
+    'ne'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['NeVecF64x2'], left, right);
+    },
+    'lt'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LtVecF64x2'], left, right);
+    },
+    'gt'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GtVecF64x2'], left, right);
+    },
+    'le'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['LeVecF64x2'], left, right);
+    },
+    'ge'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['GeVecF64x2'], left, right);
+    },
+    'abs'(value) {
+      return Module['_BinaryenUnary'](module, Module['AbsVecF64x2'], value);
+    },
+    'neg'(value) {
+      return Module['_BinaryenUnary'](module, Module['NegVecF64x2'], value);
+    },
+    'sqrt'(value) {
+      return Module['_BinaryenUnary'](module, Module['SqrtVecF64x2'], value);
+    },
+    'qfma'(a, b, c) {
+      return Module['_BinaryenSIMDTernary'](module, Module['QFMAVecF64x2'], a, b, c);
+    },
+    'qfms'(a, b, c) {
+      return Module['_BinaryenSIMDTernary'](module, Module['QFMSVecF64x2'], a, b, c);
+    },
+    'add'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['AddVecF64x2'], left, right);
+    },
+    'sub'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['SubVecF64x2'], left, right);
+    },
+    'mul'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MulVecF64x2'], left, right);
+    },
+    'div'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['DivVecF64x2'], left, right);
+    },
+    'min'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MinVecF64x2'], left, right);
+    },
+    'max'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['MaxVecF64x2'], left, right);
+    },
+    'pmin'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['PMinVecF64x2'], left, right);
+    },
+    'pmax'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['PMaxVecF64x2'], left, right);
+    },
+    'ceil'(value) {
+      return Module['_BinaryenUnary'](module, Module['CeilVecF64x2'], value);
+    },
+    'floor'(value) {
+      return Module['_BinaryenUnary'](module, Module['FloorVecF64x2'], value);
+    },
+    'trunc'(value) {
+      return Module['_BinaryenUnary'](module, Module['TruncVecF64x2'], value);
+    },
+    'nearest'(value) {
+      return Module['_BinaryenUnary'](module, Module['NearestVecF64x2'], value);
+    },
+    'convert_i64x2_s'(value) {
+      return Module['_BinaryenUnary'](module, Module['ConvertSVecI64x2ToVecF64x2'], value);
+    },
+    'convert_i64x2_u'(value) {
+      return Module['_BinaryenUnary'](module, Module['ConvertUVecI64x2ToVecF64x2'], value);
+    },
+  };
+
+  self['v8x16'] = {
+    'shuffle'(left, right, mask) {
+      return preserveStack(() => Module['_BinaryenSIMDShuffle'](module, left, right, i8sToStack(mask)));
+    },
+    'swizzle'(left, right) {
+      return Module['_BinaryenBinary'](module, Module['SwizzleVec8x16'], left, right);
+    },
+    'load_splat'(offset, align, ptr) {
+      return Module['_BinaryenSIMDLoad'](module, Module['LoadSplatVec8x16'], offset, align, ptr);
+    },
+  };
+
+  self['v16x8'] = {
+    'load_splat'(offset, align, ptr) {
+      return Module['_BinaryenSIMDLoad'](module, Module['LoadSplatVec16x8'], offset, align, ptr);
+    },
+  };
+
+  self['v32x4'] = {
+    'load_splat'(offset, align, ptr) {
+      return Module['_BinaryenSIMDLoad'](module, Module['LoadSplatVec32x4'], offset, align, ptr);
+    },
+  };
+
+  self['v64x2'] = {
+    'load_splat'(offset, align, ptr) {
+      return Module['_BinaryenSIMDLoad'](module, Module['LoadSplatVec64x2'], offset, align, ptr);
+    },
+  };
+
+  self['funcref'] = {
+    'pop'() {
+      return Module['_BinaryenPop'](module, Module['funcref']);
+    }
+  };
+
+  self['externref'] = {
+    'pop'() {
+      return Module['_BinaryenPop'](module, Module['externref']);
+    }
+  };
+
+  self['exnref'] = {
+    'pop'() {
+      return Module['_BinaryenPop'](module, Module['exnref']);
+    }
+  };
+
+  self['anyref'] = {
+    'pop'() {
+      return Module['_BinaryenPop'](module, Module['anyref']);
+    }
+  };
+
+  self['eqref'] = {
+    'pop'() {
+      return Module['_BinaryenPop'](module, Module['eqref']);
+    }
+  };
+
+  self['i31ref'] = {
+    'pop'() {
+      return Module['_BinaryenPop'](module, Module['i31ref']);
+    }
+  };
+
+  self['ref'] = {
+    'null'(type) {
+      return Module['_BinaryenRefNull'](module, type);
+    },
+    'is_null'(value) {
+      return Module['_BinaryenRefIsNull'](module, value);
+    },
+    'func'(func) {
+      return preserveStack(() => Module['_BinaryenRefFunc'](module, strToStack(func)));
+    },
+    'eq'(left, right) {
+      return Module['_BinaryenRefEq'](module, left, right);
+    }
+  };
+
+  self['select'] = function(condition, ifTrue, ifFalse, type) {
+    return Module['_BinaryenSelect'](module, condition, ifTrue, ifFalse, typeof type !== 'undefined' ? type : Module['auto']);
+  };
+  self['drop'] = function(value) {
+    return Module['_BinaryenDrop'](module, value);
+  };
+  self['return'] = function(value) {
+    return Module['_BinaryenReturn'](module, value);
+  };
+  self['nop'] = function() {
+    return Module['_BinaryenNop'](module);
+  };
+  self['unreachable'] = function() {
+    return Module['_BinaryenUnreachable'](module);
+  };
+
+  self['atomic'] = {
+    'notify'(ptr, notifyCount) {
+      return Module['_BinaryenAtomicNotify'](module, ptr, notifyCount);
+    },
+    'fence'() {
+      return Module['_BinaryenAtomicFence'](module);
+    }
+  };
+
+  self['try'] = function(body, catchBody) {
+    return Module['_BinaryenTry'](module, body, catchBody);
+  };
+  self['throw'] = function(event_, operands) {
+    return preserveStack(() => Module['_BinaryenThrow'](module, strToStack(event_), i32sToStack(operands), operands.length));
+  };
+  self['rethrow'] = function(exnref) {
+    return Module['_BinaryenRethrow'](module, exnref);
+  };
+  self['br_on_exn'] = function(label, event_, exnref) {
+    return preserveStack(() => Module['_BinaryenBrOnExn'](module, strToStack(label), strToStack(event_), exnref));
+  };
+
+  self['tuple'] = {
+    'make'(elements) {
+      return preserveStack(() => Module['_BinaryenTupleMake'](module, i32sToStack(elements), elements.length));
+    },
+    'extract'(tuple, index) {
+      return Module['_BinaryenTupleExtract'](module, tuple, index);
+    }
+  };
+
+  self['i31'] = {
+    'new'(value) {
+      return Module['_BinaryenI31New'](module, value);
+    },
+    'get_s'(i31) {
+      return Module['_BinaryenI31Get'](module, i31, 1);
+    },
+    'get_u'(i31) {
+      return Module['_BinaryenI31Get'](module, i31, 0);
+    }
+  };
+
+  // 'Module' operations
+  self['addFunction'] = function(name, params, results, varTypes, body) {
+    return preserveStack(() =>
+      Module['_BinaryenAddFunction'](module, strToStack(name), params, results, i32sToStack(varTypes), varTypes.length, body)
+    );
+  };
+  self['getFunction'] = function(name) {
+    return preserveStack(() => Module['_BinaryenGetFunction'](module, strToStack(name)));
+  };
+  self['removeFunction'] = function(name) {
+    return preserveStack(() => Module['_BinaryenRemoveFunction'](module, strToStack(name)));
+  };
+  self['addGlobal'] = function(name, type, mutable, init) {
+    return preserveStack(() => Module['_BinaryenAddGlobal'](module, strToStack(name), type, mutable, init));
+  }
+  self['getGlobal'] = function(name) {
+    return preserveStack(() => Module['_BinaryenGetGlobal'](module, strToStack(name)));
+  };
+  self['removeGlobal'] = function(name) {
+    return preserveStack(() => Module['_BinaryenRemoveGlobal'](module, strToStack(name)));
+  }
+  self['addEvent'] = function(name, attribute, params, results) {
+    return preserveStack(() => Module['_BinaryenAddEvent'](module, strToStack(name), attribute, params, results));
+  };
+  self['getEvent'] = function(name) {
+    return preserveStack(() => Module['_BinaryenGetEvent'](module, strToStack(name)));
+  };
+  self['removeEvent'] = function(name) {
+    return preserveStack(() => Module['_BinaryenRemoveEvent'](module, strToStack(name)));
+  };
+  self['addFunctionImport'] = function(internalName, externalModuleName, externalBaseName, params, results) {
+    return preserveStack(() =>
+      Module['_BinaryenAddFunctionImport'](module, strToStack(internalName), strToStack(externalModuleName), strToStack(externalBaseName), params, results)
+    );
+  };
+  self['addTableImport'] = function(internalName, externalModuleName, externalBaseName) {
+    return preserveStack(() =>
+      Module['_BinaryenAddTableImport'](module, strToStack(internalName), strToStack(externalModuleName), strToStack(externalBaseName))
+    );
+  };
+  self['addMemoryImport'] = function(internalName, externalModuleName, externalBaseName, shared) {
+    return preserveStack(() =>
+      Module['_BinaryenAddMemoryImport'](module, strToStack(internalName), strToStack(externalModuleName), strToStack(externalBaseName), shared)
+    );
+  };
+  self['addGlobalImport'] = function(internalName, externalModuleName, externalBaseName, globalType, mutable) {
+    return preserveStack(() =>
+      Module['_BinaryenAddGlobalImport'](module, strToStack(internalName), strToStack(externalModuleName), strToStack(externalBaseName), globalType, mutable)
+    );
+  };
+  self['addEventImport'] = function(internalName, externalModuleName, externalBaseName, attribute, params, results) {
+    return preserveStack(() =>
+      Module['_BinaryenAddEventImport'](module, strToStack(internalName), strToStack(externalModuleName), strToStack(externalBaseName), attribute, params, results)
+    );
+  };
+  self['addExport'] = // deprecated
+  self['addFunctionExport'] = function(internalName, externalName) {
+    return preserveStack(() => Module['_BinaryenAddFunctionExport'](module, strToStack(internalName), strToStack(externalName)));
+  };
+  self['addTableExport'] = function(internalName, externalName) {
+    return preserveStack(() => Module['_BinaryenAddTableExport'](module, strToStack(internalName), strToStack(externalName)));
+  };
+  self['addMemoryExport'] = function(internalName, externalName) {
+    return preserveStack(() => Module['_BinaryenAddMemoryExport'](module, strToStack(internalName), strToStack(externalName)));
+  };
+  self['addGlobalExport'] = function(internalName, externalName) {
+    return preserveStack(() => Module['_BinaryenAddGlobalExport'](module, strToStack(internalName), strToStack(externalName)));
+  };
+  self['addEventExport'] = function(internalName, externalName) {
+    return preserveStack(() => Module['_BinaryenAddEventExport'](module, strToStack(internalName), strToStack(externalName)));
+  };
+  self['removeExport'] = function(externalName) {
+    return preserveStack(() => Module['_BinaryenRemoveExport'](module, strToStack(externalName)));
+  };
+  self['setFunctionTable'] = function(initial, maximum, funcNames, offset = self['i32']['const'](0)) {
+    return preserveStack(() => {
+      return Module['_BinaryenSetFunctionTable'](module, initial, maximum,
+        i32sToStack(funcNames.map(strToStack)),
+        funcNames.length,
+        offset
+      );
+    });
+  };
+  self['getFunctionTable'] = function() {
+    return {
+      'imported': Boolean(Module['_BinaryenIsFunctionTableImported'](module)),
+      'segments': (function() {
+        const numSegments = Module['_BinaryenGetNumFunctionTableSegments'](module)
+        const arr = new Array(numSegments);
+        for (let i = 0; i !== numSegments; ++i) {
+          const segmentLength = Module['_BinaryenGetFunctionTableSegmentLength'](module, i);
+          const names = new Array(segmentLength);
+          for (let j = 0; j !== segmentLength; ++j) {
+            const ptr = Module['_BinaryenGetFunctionTableSegmentData'](module, i, j);
+            names[j] = UTF8ToString(ptr);
+          }
+          arr[i] = {
+            'offset': Module['_BinaryenGetFunctionTableSegmentOffset'](module, i),
+            'names': names
+          };
+        }
+        return arr;
+      })()
+    };
+  };
+  self['setMemory'] = function(initial, maximum, exportName, segments = [], shared = false) {
+    // segments are assumed to be { passive: bool, offset: expression ref, data: array of 8-bit data }
+    return preserveStack(() => {
+      const segmentsLen = segments.length;
+      const segmentData = new Array(segmentsLen);
+      const segmentDataLen = new Array(segmentsLen);
+      const segmentPassive = new Array(segmentsLen);
+      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);
+        segmentDataLen[i] = data.length;
+        segmentPassive[i] = passive;
+        segmentOffset[i] = offset;
+      }
+      return Module['_BinaryenSetMemory'](
+        module, initial, maximum, strToStack(exportName),
+        i32sToStack(segmentData),
+        i8sToStack(segmentPassive),
+        i32sToStack(segmentOffset),
+        i32sToStack(segmentDataLen),
+        segmentsLen,
+        shared
+      );
+    });
+  };
+  self['getNumMemorySegments'] = function() {
+    return Module['_BinaryenGetNumMemorySegments'](module);
+  }
+  self['getMemorySegmentInfoByIndex'] = function(id) {
+    return {
+      'offset': Module['_BinaryenGetMemorySegmentByteOffset'](module, id),
+      'data': (function(){
+        const size = Module['_BinaryenGetMemorySegmentByteLength'](module, id);
+        const ptr = _malloc(size);
+        Module['_BinaryenCopyMemorySegmentData'](module, id, ptr);
+        const res = new Uint8Array(size);
+        res.set(new Uint8Array(buffer, ptr, size));
+        _free(ptr);
+        return res.buffer;
+      })(),
+      'passive': Boolean(Module['_BinaryenGetMemorySegmentPassive'](module, id))
+    };
+  }
+  self['setStart'] = function(start) {
+    return Module['_BinaryenSetStart'](module, start);
+  };
+  self['getFeatures'] = function() {
+    return Module['_BinaryenModuleGetFeatures'](module);
+  };
+  self['setFeatures'] = function(features) {
+    Module['_BinaryenModuleSetFeatures'](module, features);
+  };
+  self['addCustomSection'] = function(name, contents) {
+    return preserveStack(() =>
+      Module['_BinaryenAddCustomSection'](module, strToStack(name), i8sToStack(contents), contents.length)
+    );
+  };
+  self['getNumExports'] = function() {
+    return Module['_BinaryenGetNumExports'](module);
+  }
+  self['getExportByIndex'] = function(id) {
+    return Module['_BinaryenGetExportByIndex'](module, id);
+  }
+  self['getNumFunctions'] = function() {
+    return Module['_BinaryenGetNumFunctions'](module);
+  }
+  self['getFunctionByIndex'] = function(id) {
+    return Module['_BinaryenGetFunctionByIndex'](module, id);
+  }
+  self['emitText'] = function() {
+    const old = out;
+    let ret = '';
+    out = x => { ret += x + '\n' };
+    Module['_BinaryenModulePrint'](module);
+    out = old;
+    return ret;
+  };
+  self['emitStackIR'] = function(optimize) {
+    self['runPasses'](['generate-stack-ir']);
+    if (optimize) self['runPasses'](['optimize-stack-ir']);
+    const old = out;
+    let ret = '';
+    out = x => { ret += x + '\n' };
+    self['runPasses'](['print-stack-ir']);
+    out = old;
+    return ret;
+  };
+  self['emitAsmjs'] = function() {
+    const old = out;
+    let ret = '';
+    out = x => { ret += x + '\n' };
+    Module['_BinaryenModulePrintAsmjs'](module);
+    out = old;
+    return ret;
+  };
+  self['validate'] = function() {
+    return Module['_BinaryenModuleValidate'](module);
+  };
+  self['optimize'] = function() {
+    return Module['_BinaryenModuleOptimize'](module);
+  };
+  self['optimizeFunction'] = function(func) {
+    if (typeof func === 'string') func = self['getFunction'](func);
+    return Module['_BinaryenFunctionOptimize'](func, module);
+  };
+  self['runPasses'] = function(passes) {
+    return preserveStack(() =>
+      Module['_BinaryenModuleRunPasses'](module, i32sToStack(passes.map(strToStack)), passes.length)
+    );
+  };
+  self['runPassesOnFunction'] = function(func, passes) {
+    if (typeof func === 'string') func = self['getFunction'](func);
+    return preserveStack(() =>
+      Module['_BinaryenFunctionRunPasses'](func, module, i32sToStack(passes.map(strToStack)), passes.length)
+    );
+  };
+  self['autoDrop'] = function() {
+    return Module['_BinaryenModuleAutoDrop'](module);
+  };
+  self['dispose'] = function() {
+    Module['_BinaryenModuleDispose'](module);
+  };
+  self['emitBinary'] = function(sourceMapUrl) {
+    return preserveStack(() => {
+      const tempBuffer = stackAlloc(_BinaryenSizeofAllocateAndWriteResult());
+      Module['_BinaryenModuleAllocateAndWrite'](tempBuffer, module, strToStack(sourceMapUrl));
+      const binaryPtr    = HEAPU32[ tempBuffer >>> 2     ];
+      const binaryBytes  = HEAPU32[(tempBuffer >>> 2) + 1];
+      const sourceMapPtr = HEAPU32[(tempBuffer >>> 2) + 2];
+      try {
+        const buffer = new Uint8Array(binaryBytes);
+        buffer.set(HEAPU8.subarray(binaryPtr, binaryPtr + binaryBytes));
+        return typeof sourceMapUrl === 'undefined'
+          ? buffer
+          : { 'binary': buffer, 'sourceMap': UTF8ToString(sourceMapPtr) };
+      } finally {
+        _free(binaryPtr);
+        if (sourceMapPtr) _free(sourceMapPtr);
+      }
+    });
+  };
+  self['interpret'] = function() {
+    return Module['_BinaryenModuleInterpret'](module);
+  };
+  self['addDebugInfoFileName'] = function(filename) {
+    return preserveStack(() => Module['_BinaryenModuleAddDebugInfoFileName'](module, strToStack(filename)));
+  };
+  self['getDebugInfoFileName'] = function(index) {
+    return UTF8ToString(Module['_BinaryenModuleGetDebugInfoFileName'](module, index));
+  };
+  self['setDebugLocation'] = function(func, expr, fileIndex, lineNumber, columnNumber) {
+    return Module['_BinaryenFunctionSetDebugLocation'](func, expr, fileIndex, lineNumber, columnNumber);
+  };
+  self['copyExpression'] = function(expr) {
+    return Module['_BinaryenExpressionCopy'](expr, module);
+  };
+
+  return self;
+}
+Module['wrapModule'] = wrapModule;
+
+// 'Relooper' interface
+Module['Relooper'] = function(module) {
+  assert(module && typeof module === 'object' && module['ptr'] && module['block'] && module['if']); // guard against incorrect old API usage
+  const relooper = Module['_RelooperCreate'](module['ptr']);
+  this['ptr'] = relooper;
+
+  this['addBlock'] = function(code) {
+    return Module['_RelooperAddBlock'](relooper, code);
+  };
+  this['addBranch'] = function(from, to, condition, code) {
+    return Module['_RelooperAddBranch'](from, to, condition, code);
+  };
+  this['addBlockWithSwitch'] = function(code, condition) {
+    return Module['_RelooperAddBlockWithSwitch'](relooper, code, condition);
+  };
+  this['addBranchForSwitch'] = function(from, to, indexes, code) {
+    return preserveStack(() => Module['_RelooperAddBranchForSwitch'](from, to, i32sToStack(indexes), indexes.length, code));
+  };
+  this['renderAndDispose'] = function(entry, labelHelper) {
+    return Module['_RelooperRenderAndDispose'](relooper, entry, labelHelper);
+  };
+};
+
+// 'ExpressionRunner' interface
+Module['ExpressionRunner'] = function(module, flags, maxDepth, maxLoopIterations) {
+  const runner = Module['_ExpressionRunnerCreate'](module['ptr'], flags, maxDepth, maxLoopIterations);
+  this['ptr'] = runner;
+
+  this['setLocalValue'] = function(index, valueExpr) {
+    return Boolean(Module['_ExpressionRunnerSetLocalValue'](runner, index, valueExpr));
+  };
+  this['setGlobalValue'] = function(name, valueExpr) {
+    return preserveStack(() => Boolean(Module['_ExpressionRunnerSetGlobalValue'](runner, strToStack(name), valueExpr)));
+  };
+  this['runAndDispose'] = function(expr) {
+    return Module['_ExpressionRunnerRunAndDispose'](runner, expr);
+  };
+};
+
+function getAllNested(ref, numFn, getFn) {
+  const num = numFn(ref);
+  const ret = new Array(num);
+  for (let i = 0; i < num; ++i) ret[i] = getFn(ref, i);
+  return ret;
+}
+
+// Gets the specific id of an 'Expression'
+Module['getExpressionId'] = function(expr) {
+  return Module['_BinaryenExpressionGetId'](expr);
+};
+
+// Gets the result type of an 'Expression'
+Module['getExpressionType'] = function(expr) {
+  return Module['_BinaryenExpressionGetType'](expr);
+};
+
+// Obtains information about an 'Expression'
+Module['getExpressionInfo'] = function(expr) {
+  const id = Module['_BinaryenExpressionGetId'](expr);
+  const type = Module['_BinaryenExpressionGetType'](expr);
+  switch (id) {
+    case Module['BlockId']:
+      return {
+        'id': id,
+        'type': type,
+        'name': UTF8ToString(Module['_BinaryenBlockGetName'](expr)),
+        'children': getAllNested(expr, Module['_BinaryenBlockGetNumChildren'], Module['_BinaryenBlockGetChildAt'])
+      };
+    case Module['IfId']:
+      return {
+        'id': id,
+        'type': type,
+        'condition': Module['_BinaryenIfGetCondition'](expr),
+        'ifTrue': Module['_BinaryenIfGetIfTrue'](expr),
+        'ifFalse': Module['_BinaryenIfGetIfFalse'](expr)
+      };
+    case Module['LoopId']:
+      return {
+        'id': id,
+        'type': type,
+        'name': UTF8ToString(Module['_BinaryenLoopGetName'](expr)),
+        'body': Module['_BinaryenLoopGetBody'](expr)
+      };
+    case Module['BreakId']:
+      return {
+        'id': id,
+        'type': type,
+        'name': UTF8ToString(Module['_BinaryenBreakGetName'](expr)),
+        'condition': Module['_BinaryenBreakGetCondition'](expr),
+        'value': Module['_BinaryenBreakGetValue'](expr)
+      };
+    case Module['SwitchId']:
+      return {
+        'id': id,
+        'type': type,
+         // Do not pass the index as the second parameter to UTF8ToString as that will cut off the string.
+        'names': getAllNested(expr, Module['_BinaryenSwitchGetNumNames'], Module['_BinaryenSwitchGetNameAt']).map(p => UTF8ToString(p)),
+        'defaultName': UTF8ToString(Module['_BinaryenSwitchGetDefaultName'](expr)),
+        'condition': Module['_BinaryenSwitchGetCondition'](expr),
+        'value': Module['_BinaryenSwitchGetValue'](expr)
+      };
+    case Module['CallId']:
+      return {
+        'id': id,
+        'type': type,
+        'isReturn': Boolean(Module['_BinaryenCallIsReturn'](expr)),
+        'target': UTF8ToString(Module['_BinaryenCallGetTarget'](expr)),
+        'operands': getAllNested(expr, Module[ '_BinaryenCallGetNumOperands'], Module['_BinaryenCallGetOperandAt'])
+      };
+    case Module['CallIndirectId']:
+      return {
+        'id': id,
+        'type': type,
+        'isReturn': Boolean(Module['_BinaryenCallIndirectIsReturn'](expr)),
+        'target': Module['_BinaryenCallIndirectGetTarget'](expr),
+        'operands': getAllNested(expr, Module['_BinaryenCallIndirectGetNumOperands'], Module['_BinaryenCallIndirectGetOperandAt'])
+      };
+    case Module['LocalGetId']:
+      return {
+        'id': id,
+        'type': type,
+        'index': Module['_BinaryenLocalGetGetIndex'](expr)
+      };
+    case Module['LocalSetId']:
+      return {
+        'id': id,
+        'type': type,
+        'isTee': Boolean(Module['_BinaryenLocalSetIsTee'](expr)),
+        'index': Module['_BinaryenLocalSetGetIndex'](expr),
+        'value': Module['_BinaryenLocalSetGetValue'](expr)
+      };
+    case Module['GlobalGetId']:
+      return {
+        'id': id,
+        'type': type,
+        'name': UTF8ToString(Module['_BinaryenGlobalGetGetName'](expr))
+      };
+    case Module['GlobalSetId']:
+      return {
+        'id': id,
+        'type': type,
+        'name': UTF8ToString(Module['_BinaryenGlobalSetGetName'](expr)),
+        'value': Module['_BinaryenGlobalSetGetValue'](expr)
+      };
+    case Module['LoadId']:
+      return {
+        'id': id,
+        'type': type,
+        'isAtomic': Boolean(Module['_BinaryenLoadIsAtomic'](expr)),
+        'isSigned': Boolean(Module['_BinaryenLoadIsSigned'](expr)),
+        'offset': Module['_BinaryenLoadGetOffset'](expr),
+        'bytes': Module['_BinaryenLoadGetBytes'](expr),
+        'align': Module['_BinaryenLoadGetAlign'](expr),
+        'ptr': Module['_BinaryenLoadGetPtr'](expr)
+      };
+    case Module['StoreId']:
+      return {
+        'id': id,
+        'type': type,
+        'isAtomic': Boolean(Module['_BinaryenStoreIsAtomic'](expr)),
+        'offset': Module['_BinaryenStoreGetOffset'](expr),
+        'bytes': Module['_BinaryenStoreGetBytes'](expr),
+        'align': Module['_BinaryenStoreGetAlign'](expr),
+        'ptr': Module['_BinaryenStoreGetPtr'](expr),
+        'value': Module['_BinaryenStoreGetValue'](expr)
+      };
+    case Module['ConstId']: {
+      let value;
+      switch (type) {
+        case Module['i32']: value = Module['_BinaryenConstGetValueI32'](expr); break;
+        case Module['i64']: value = {
+          'low':  Module['_BinaryenConstGetValueI64Low'](expr),
+          'high': Module['_BinaryenConstGetValueI64High'](expr)
+        }; break;
+        case Module['f32']: value = Module['_BinaryenConstGetValueF32'](expr); break;
+        case Module['f64']: value = Module['_BinaryenConstGetValueF64'](expr); break;
+        case Module['v128']: {
+          preserveStack(() => {
+            const tempBuffer = stackAlloc(16);
+            Module['_BinaryenConstGetValueV128'](expr, tempBuffer);
+            value = new Array(16);
+            for (let i = 0; i < 16; i++) {
+              value[i] = HEAPU8[tempBuffer + i];
+            }
+          });
+          break;
+        }
+        default: throw Error('unexpected type: ' + type);
+      }
+      return {
+        'id': id,
+        'type': type,
+        'value': value
+      };
+    }
+    case Module['UnaryId']:
+      return {
+        'id': id,
+        'type': type,
+        'op': Module['_BinaryenUnaryGetOp'](expr),
+        'value': Module['_BinaryenUnaryGetValue'](expr)
+      };
+    case Module['BinaryId']:
+      return {
+        'id': id,
+        'type': type,
+        'op': Module['_BinaryenBinaryGetOp'](expr),
+        'left': Module['_BinaryenBinaryGetLeft'](expr),
+        'right':  Module['_BinaryenBinaryGetRight'](expr)
+      };
+    case Module['SelectId']:
+      return {
+        'id': id,
+        'type': type,
+        'ifTrue': Module['_BinaryenSelectGetIfTrue'](expr),
+        'ifFalse': Module['_BinaryenSelectGetIfFalse'](expr),
+        'condition': Module['_BinaryenSelectGetCondition'](expr)
+      };
+    case Module['DropId']:
+      return {
+        'id': id,
+        'type': type,
+        'value': Module['_BinaryenDropGetValue'](expr)
+      };
+    case Module['ReturnId']:
+      return {
+        'id': id,
+        'type': type,
+        'value': Module['_BinaryenReturnGetValue'](expr)
+      };
+    case Module['NopId']:
+    case Module['UnreachableId']:
+    case Module['PopId']:
+      return {
+        'id': id,
+        'type': type
+      };
+    case Module['MemorySizeId']:
+      return {
+        'id': id,
+        'type': type
+      };
+    case Module['MemoryGrowId']:
+      return {
+        'id': id,
+        'type': type,
+        'delta': Module['_BinaryenMemoryGrowGetDelta'](expr)
+      }
+    case Module['AtomicRMWId']:
+      return {
+        'id': id,
+        'type': type,
+        'op': Module['_BinaryenAtomicRMWGetOp'](expr),
+        'bytes': Module['_BinaryenAtomicRMWGetBytes'](expr),
+        'offset': Module['_BinaryenAtomicRMWGetOffset'](expr),
+        'ptr': Module['_BinaryenAtomicRMWGetPtr'](expr),
+        'value': Module['_BinaryenAtomicRMWGetValue'](expr)
+      };
+    case Module['AtomicCmpxchgId']:
+      return {
+        'id': id,
+        'type': type,
+        'bytes': Module['_BinaryenAtomicCmpxchgGetBytes'](expr),
+        'offset': Module['_BinaryenAtomicCmpxchgGetOffset'](expr),
+        'ptr': Module['_BinaryenAtomicCmpxchgGetPtr'](expr),
+        'expected': Module['_BinaryenAtomicCmpxchgGetExpected'](expr),
+        'replacement': Module['_BinaryenAtomicCmpxchgGetReplacement'](expr)
+      };
+    case Module['AtomicWaitId']:
+      return {
+        'id': id,
+        'type': type,
+        'ptr': Module['_BinaryenAtomicWaitGetPtr'](expr),
+        'expected': Module['_BinaryenAtomicWaitGetExpected'](expr),
+        'timeout': Module['_BinaryenAtomicWaitGetTimeout'](expr),
+        'expectedType': Module['_BinaryenAtomicWaitGetExpectedType'](expr)
+      };
+    case Module['AtomicNotifyId']:
+      return {
+        'id': id,
+        'type': type,
+        'ptr': Module['_BinaryenAtomicNotifyGetPtr'](expr),
+        'notifyCount': Module['_BinaryenAtomicNotifyGetNotifyCount'](expr)
+      };
+    case Module['AtomicFenceId']:
+      return {
+        'id': id,
+        'type': type,
+        'order': Module['_BinaryenAtomicFenceGetOrder'](expr)
+      };
+    case Module['SIMDExtractId']:
+      return {
+        'id': id,
+        'type': type,
+        'op': Module['_BinaryenSIMDExtractGetOp'](expr),
+        'vec': Module['_BinaryenSIMDExtractGetVec'](expr),
+        'index': Module['_BinaryenSIMDExtractGetIndex'](expr)
+      };
+    case Module['SIMDReplaceId']:
+      return {
+        'id': id,
+        'type': type,
+        'op': Module['_BinaryenSIMDReplaceGetOp'](expr),
+        'vec': Module['_BinaryenSIMDReplaceGetVec'](expr),
+        'index': Module['_BinaryenSIMDReplaceGetIndex'](expr),
+        'value': Module['_BinaryenSIMDReplaceGetValue'](expr)
+      };
+    case Module['SIMDShuffleId']:
+      return preserveStack(() => {
+        const tempBuffer = stackAlloc(16);
+        Module['_BinaryenSIMDShuffleGetMask'](expr, tempBuffer);
+        const mask = new Array(16);
+        for (let i = 0; i < 16; i++) {
+          mask[i] = HEAPU8[tempBuffer + i];
+        }
+        return {
+          'id': id,
+          'type': type,
+          'left': Module['_BinaryenSIMDShuffleGetLeft'](expr),
+          'right': Module['_BinaryenSIMDShuffleGetRight'](expr),
+          'mask': mask
+        };
+      });
+    case Module['SIMDTernaryId']:
+      return {
+        'id': id,
+        'type': type,
+        'op': Module['_BinaryenSIMDTernaryGetOp'](expr),
+        'a': Module['_BinaryenSIMDTernaryGetA'](expr),
+        'b': Module['_BinaryenSIMDTernaryGetB'](expr),
+        'c': Module['_BinaryenSIMDTernaryGetC'](expr)
+      };
+    case Module['SIMDShiftId']:
+      return {
+        'id': id,
+        'type': type,
+        'op': Module['_BinaryenSIMDShiftGetOp'](expr),
+        'vec': Module['_BinaryenSIMDShiftGetVec'](expr),
+        'shift': Module['_BinaryenSIMDShiftGetShift'](expr)
+      };
+    case Module['SIMDLoadId']:
+      return {
+        'id': id,
+        'type': type,
+        'op': Module['_BinaryenSIMDLoadGetOp'](expr),
+        'offset': Module['_BinaryenSIMDLoadGetOffset'](expr),
+        'align': Module['_BinaryenSIMDLoadGetAlign'](expr),
+        'ptr': Module['_BinaryenSIMDLoadGetPtr'](expr)
+      };
+    case Module['MemoryInitId']:
+      return {
+        'id': id,
+        'segment': Module['_BinaryenMemoryInitGetSegment'](expr),
+        'dest': Module['_BinaryenMemoryInitGetDest'](expr),
+        'offset': Module['_BinaryenMemoryInitGetOffset'](expr),
+        'size': Module['_BinaryenMemoryInitGetSize'](expr)
+      };
+    case Module['DataDropId']:
+      return {
+        'id': id,
+        'segment': Module['_BinaryenDataDropGetSegment'](expr),
+      };
+    case Module['MemoryCopyId']:
+      return {
+        'id': id,
+        'dest': Module['_BinaryenMemoryCopyGetDest'](expr),
+        'source': Module['_BinaryenMemoryCopyGetSource'](expr),
+        'size': Module['_BinaryenMemoryCopyGetSize'](expr)
+      };
+    case Module['MemoryFillId']:
+      return {
+        'id': id,
+        'dest': Module['_BinaryenMemoryFillGetDest'](expr),
+        'value': Module['_BinaryenMemoryFillGetValue'](expr),
+        'size': Module['_BinaryenMemoryFillGetSize'](expr)
+      };
+    case Module['RefNullId']:
+      return {
+        'id': id,
+        'type': type
+      };
+    case Module['RefIsNullId']:
+      return {
+        'id': id,
+        'type': type,
+        'value': Module['_BinaryenRefIsNullGetValue'](expr)
+      };
+    case Module['RefFuncId']:
+      return {
+        'id': id,
+        'type': type,
+        'func': UTF8ToString(Module['_BinaryenRefFuncGetFunc'](expr)),
+      };
+    case Module['RefEqId']:
+      return {
+        'id': id,
+        'type': type,
+        'left': Module['_BinaryenRefEqGetLeft'](expr),
+        'right': Module['_BinaryenRefEqGetRight'](expr)
+      };
+    case Module['TryId']:
+      return {
+        'id': id,
+        'type': type,
+        'body': Module['_BinaryenTryGetBody'](expr),
+        'catchBody': Module['_BinaryenTryGetCatchBody'](expr)
+      };
+    case Module['ThrowId']:
+      return {
+        'id': id,
+        'type': type,
+        'event': UTF8ToString(Module['_BinaryenThrowGetEvent'](expr)),
+        'operands': getAllNested(expr, Module['_BinaryenThrowGetNumOperands'], Module['_BinaryenThrowGetOperandAt'])
+      };
+    case Module['RethrowId']:
+      return {
+        'id': id,
+        'type': type,
+        'exnref': Module['_BinaryenRethrowGetExnref'](expr)
+      };
+    case Module['BrOnExnId']:
+      return {
+        'id': id,
+        'type': type,
+        'name': UTF8ToString(Module['_BinaryenBrOnExnGetName'](expr)),
+        'event': UTF8ToString(Module['_BinaryenBrOnExnGetEvent'](expr)),
+        'exnref': Module['_BinaryenBrOnExnGetExnref'](expr)
+      };
+    case Module['TupleMakeId']:
+      return {
+        'id': id,
+        'type': type,
+        'operands': getAllNested(expr, Module['_BinaryenTupleMakeGetNumOperands'], Module['_BinaryenTupleMakeGetOperandAt'])
+      };
+    case Module['TupleExtractId']:
+      return {
+        'id': id,
+        'type': type,
+        'tuple': Module['_BinaryenTupleExtractGetTuple'](expr),
+        'index': Module['_BinaryenTupleExtractGetIndex'](expr)
+      };
+    case Module['I31NewId']:
+      return {
+        'id': id,
+        'type': type,
+        'value': Module['_BinaryenI31NewGetValue'](expr)
+      };
+    case Module['I31GetId']:
+      return {
+        'id': id,
+        'type': type,
+        'i31': Module['_BinaryenI31GetGetI31'](expr),
+        'isSigned': Boolean(Module['_BinaryenI31GetIsSigned'](expr))
+      };
+
+    default:
+      throw Error('unexpected id: ' + id);
+  }
+};
+
+// Gets the side effects of the specified expression
+Module['getSideEffects'] = function(expr, features) {
+  return Module['_BinaryenExpressionGetSideEffects'](expr, features);
+};
+
+Module['createType'] = function(types) {
+  return preserveStack(() => Module['_BinaryenTypeCreate'](i32sToStack(types), types.length));
+};
+
+Module['expandType'] = function(ty) {
+  return preserveStack(() => {
+    const numTypes = Module['_BinaryenTypeArity'](ty);
+    const array = stackAlloc(numTypes << 2);
+    Module['_BinaryenTypeExpand'](ty, array);
+    const types = new Array(numTypes);
+    for (let i = 0; i < numTypes; i++) {
+      types[i] = HEAPU32[(array >>> 2) + i];
+    }
+    return types;
+  });
+};
+
+// Obtains information about a 'Function'
+Module['getFunctionInfo'] = function(func) {
+  return {
+    'name': UTF8ToString(Module['_BinaryenFunctionGetName'](func)),
+    'module': UTF8ToString(Module['_BinaryenFunctionImportGetModule'](func)),
+    'base': UTF8ToString(Module['_BinaryenFunctionImportGetBase'](func)),
+    'params': Module['_BinaryenFunctionGetParams'](func),
+    'results': Module['_BinaryenFunctionGetResults'](func),
+    'vars': getAllNested(func, Module['_BinaryenFunctionGetNumVars'], Module['_BinaryenFunctionGetVar']),
+    'body': Module['_BinaryenFunctionGetBody'](func)
+  };
+};
+
+// Obtains information about a 'Global'
+Module['getGlobalInfo'] = function(global) {
+  return {
+    'name': UTF8ToString(Module['_BinaryenGlobalGetName'](global)),
+    'module': UTF8ToString(Module['_BinaryenGlobalImportGetModule'](global)),
+    'base': UTF8ToString(Module['_BinaryenGlobalImportGetBase'](global)),
+    'type': Module['_BinaryenGlobalGetType'](global),
+    'mutable': Boolean(Module['_BinaryenGlobalIsMutable'](global)),
+    'init': Module['_BinaryenGlobalGetInitExpr'](global)
+  };
+};
+
+// Obtains information about a 'Event'
+Module['getEventInfo'] = function(event_) {
+  return {
+    'name': UTF8ToString(Module['_BinaryenEventGetName'](event_)),
+    'module': UTF8ToString(Module['_BinaryenEventImportGetModule'](event_)),
+    'base': UTF8ToString(Module['_BinaryenEventImportGetBase'](event_)),
+    'attribute': Module['_BinaryenEventGetAttribute'](event_),
+    'params': Module['_BinaryenEventGetParams'](event_),
+    'results': Module['_BinaryenEventGetResults'](event_)
+  };
+};
+
+// Obtains information about an 'Export'
+Module['getExportInfo'] = function(export_) {
+  return {
+    'kind': Module['_BinaryenExportGetKind'](export_),
+    'name': UTF8ToString(Module['_BinaryenExportGetName'](export_)),
+    'value': UTF8ToString(Module['_BinaryenExportGetValue'](export_))
+  };
+};
+
+// Emits text format of an expression or a module
+Module['emitText'] = function(expr) {
+  if (typeof expr === 'object') {
+    return expr.emitText();
+  }
+  const old = out;
+  let ret = '';
+  out = x => { ret += x + '\n' };
+  Module['_BinaryenExpressionPrint'](expr);
+  out = old;
+  return ret;
+};
+
+// Parses a binary to a module
+
+// If building with Emscripten ASSERTIONS, there is a property added to
+// Module to guard against users mistakening using the removed readBinary()
+// API. We must defuse that carefully.
+Object.defineProperty(Module, 'readBinary', { writable: true });
+
+Module['readBinary'] = function(data) {
+  const buffer = allocate(data, 'i8', ALLOC_NORMAL);
+  const ptr = Module['_BinaryenModuleRead'](buffer, data.length);
+  _free(buffer);
+  return wrapModule(ptr);
+};
+
+// Parses text format to a module
+Module['parseText'] = function(text) {
+  const buffer = _malloc(text.length + 1);
+  writeAsciiToMemory(text, buffer);
+  const ptr = Module['_BinaryenModuleParse'](buffer);
+  _free(buffer);
+  return wrapModule(ptr);
+};
+
+// Gets the currently set optimize level. 0, 1, 2 correspond to -O0, -O1, -O2, etc.
+Module['getOptimizeLevel'] = function() {
+  return Module['_BinaryenGetOptimizeLevel']();
+};
+
+// Sets the optimization level to use. 0, 1, 2 correspond to -O0, -O1, -O2, etc.
+Module['setOptimizeLevel'] = function(level) {
+  Module['_BinaryenSetOptimizeLevel'](level);
+};
+
+// Gets the currently set shrink level. 0, 1, 2 correspond to -O0, -Os, -Oz.
+Module['getShrinkLevel'] = function() {
+  return Module['_BinaryenGetShrinkLevel']();
+};
+
+// Sets the shrink level to use. 0, 1, 2 correspond to -O0, -Os, -Oz.
+Module['setShrinkLevel'] = function(level) {
+  Module['_BinaryenSetShrinkLevel'](level);
+};
+
+// Gets whether generating debug information is currently enabled or not.
+Module['getDebugInfo'] = function() {
+  return Boolean(Module['_BinaryenGetDebugInfo']());
+};
+
+// Enables or disables debug information in emitted binaries.
+Module['setDebugInfo'] = function(on) {
+  Module['_BinaryenSetDebugInfo'](on);
+};
+
+// Gets whether the low 1K of memory can be considered unused when optimizing.
+Module['getLowMemoryUnused'] = function() {
+  return Boolean(Module['_BinaryenGetLowMemoryUnused']());
+};
+
+// Enables or disables whether the low 1K of memory can be considered unused
+// when optimizing.
+Module['setLowMemoryUnused'] = function(on) {
+  Module['_BinaryenSetLowMemoryUnused'](on);
+};
+
+// Gets whether fast math optimizations are enabled, ignoring for example
+// corner cases of floating-point math like NaN changes.
+Module['getFastMath'] = function() {
+  return Boolean(Module['_BinaryenGetFastMath']());
+};
+
+// Enables or disables fast math optimizations, ignoring for example
+// corner cases of floating-point math like NaN changes.
+Module['setFastMath'] = function(value) {
+  Module['_BinaryenSetFastMath'](value);
+};
+
+// Gets the value of the specified arbitrary pass argument.
+Module['getPassArgument'] = function(key) {
+  return preserveStack(() => {
+    const ret = Module['_BinaryenGetPassArgument'](strToStack(key));
+    return ret !== 0 ? UTF8ToString(ret) : null;
+  });
+};
+
+// Sets the value of the specified arbitrary pass argument. Removes the
+// respective argument if `value` is NULL.
+Module['setPassArgument'] = function (key, value) {
+  preserveStack(() => { Module['_BinaryenSetPassArgument'](strToStack(key), strToStack(value)) });
+};
+
+// Clears all arbitrary pass arguments.
+Module['clearPassArguments'] = function() {
+  Module['_BinaryenClearPassArguments']();
+};
+
+// Gets the function size at which we always inline.
+Module['getAlwaysInlineMaxSize'] = function() {
+  return Module['_BinaryenGetAlwaysInlineMaxSize']();
+};
+
+// Sets the function size at which we always inline.
+Module['setAlwaysInlineMaxSize'] = function(size) {
+  Module['_BinaryenSetAlwaysInlineMaxSize'](size);
+};
+
+// Gets the function size which we inline when functions are lightweight.
+Module['getFlexibleInlineMaxSize'] = function() {
+  return Module['_BinaryenGetFlexibleInlineMaxSize']();
+};
+
+// Sets the function size which we inline when functions are lightweight.
+Module['setFlexibleInlineMaxSize'] = function(size) {
+  Module['_BinaryenSetFlexibleInlineMaxSize'](size);
+};
+
+// Gets the function size which we inline when there is only one caller.
+Module['getOneCallerInlineMaxSize'] = function() {
+  return Module['_BinaryenGetOneCallerInlineMaxSize']();
+};
+
+// Sets the function size which we inline when there is only one caller.
+Module['setOneCallerInlineMaxSize'] = function(size) {
+  Module['_BinaryenSetOneCallerInlineMaxSize'](size);
+};
+
+// Gets the value which allow inline functions that are not "lightweight".
+Module['getAllowInliningFunctionsWithLoops'] = function() {
+  return Boolean(Module['_BinaryenGetAllowInliningFunctionsWithLoops']());
+};
+
+// Sets the value which allow inline functions that are not "lightweight".
+Module['setAllowInliningFunctionsWithLoops'] = function(value) {
+  Module['_BinaryenSetAllowInliningFunctionsWithLoops'](value);
+};
+
+// Expression wrappers
+
+// Private symbol used to store the underlying C-API pointer of a wrapped object.
+const thisPtr = Symbol();
+
+// Makes a specific expression wrapper class with the specified static members
+// while automatically deriving instance methods and accessors.
+function makeExpressionWrapper(ownStaticMembers) {
+  function SpecificExpression(expr) {
+    // can call the constructor without `new`
+    if (!(this instanceof SpecificExpression)) {
+      if (!expr) return null;
+      return new SpecificExpression(expr);
+    }
+    Expression.call(this, expr);
+  }
+  // inherit static members of Expression
+  Object.assign(SpecificExpression, Expression);
+  // add own static members
+  Object.assign(SpecificExpression, ownStaticMembers);
+  // inherit from Expression
+  (SpecificExpression.prototype = Object.create(Expression.prototype)).constructor = SpecificExpression;
+  // derive own instance members
+  deriveWrapperInstanceMembers(SpecificExpression.prototype, ownStaticMembers);
+  return SpecificExpression;
+}
+
+// Derives the instance members of a wrapper class from the given static
+// members.
+function deriveWrapperInstanceMembers(prototype, staticMembers) {
+  // Given a static member `getName(ptr)` for example, an instance method
+  // `getName()` and a `name` accessor with the `this` argument bound will be
+  // derived and added to the wrapper's prototype. If a corresponding static
+  // `setName(ptr)` is present, a setter for the `name` accessor will be added
+  // as well.
+  Object.keys(staticMembers).forEach(memberName => {
+    const member = staticMembers[memberName];
+    if (typeof member === "function") {
+      // Instance method calls the respective static method with `this` bound.
+      prototype[memberName] = function(...args) {
+        return this.constructor[memberName](this[thisPtr], ...args);
+      };
+      // Instance accessors call the respective static methods. Accessors are
+      // derived only if the respective underlying static method takes exactly
+      // one argument, the `this` argument, e.g. `getChild(ptr, idx)` does not
+      // trigger an accessor.
+      let match;
+      if (member.length === 1 && (match = memberName.match(/^(get|is)/))) {
+        const index = match[1].length;
+        const propertyName = memberName.charAt(index).toLowerCase() + memberName.substring(index + 1);
+        const setterIfAny = staticMembers["set" + memberName.substring(index)];
+        Object.defineProperty(prototype, propertyName, {
+          get() {
+            return member(this[thisPtr]);
+          },
+          set(value) {
+            if (setterIfAny) setterIfAny(this[thisPtr], value);
+            else throw Error("property '" + propertyName + "' has no setter");
+          }
+        });
+      }
+    }
+  });
+}
+
+// Base class of all expression wrappers
+function Expression(expr) {
+  if (!expr) throw Error("expression reference must not be null");
+  this[thisPtr] = expr;
+}
+Expression['getId'] = function(expr) {
+  return Module['_BinaryenExpressionGetId'](expr);
+};
+Expression['getType'] = function(expr) {
+  return Module['_BinaryenExpressionGetType'](expr);
+};
+Expression['setType'] = function(expr, type) {
+  Module['_BinaryenExpressionSetType'](expr, type);
+};
+Expression['finalize'] = function(expr) {
+  return Module['_BinaryenExpressionFinalize'](expr);
+};
+Expression['toText'] = function(expr) {
+  return Module['emitText'](expr);
+};
+deriveWrapperInstanceMembers(Expression.prototype, Expression);
+Expression.prototype['valueOf'] = function() {
+  return this[thisPtr];
+};
+
+Module['Expression'] = Expression;
+
+Module['Block'] = makeExpressionWrapper({
+  'getName'(expr) {
+    const name = Module['_BinaryenBlockGetName'](expr);
+    return name ? UTF8ToString(name) : null;
+  },
+  'setName'(expr, name) {
+    preserveStack(() => { Module['_BinaryenBlockSetName'](expr, strToStack(name)) });
+  },
+  'getNumChildren'(expr) {
+    return Module['_BinaryenBlockGetNumChildren'](expr);
+  },
+  'getChildren'(expr) {
+    const numChildren = Module['_BinaryenBlockGetNumChildren'](expr);
+    const children = new Array(numChildren);
+    let index = 0;
+    while (index < numChildren) {
+      children[index] = Module['_BinaryenBlockGetChildAt'](expr, index++);
+    }
+    return children;
+  },
+  'setChildren'(expr, children) {
+    const numChildren = children.length;
+    let prevNumChildren = Module['_BinaryenBlockGetNumChildren'](expr);
+    let index = 0;
+    while (index < numChildren) {
+      if (index < prevNumChildren) {
+        Module['_BinaryenBlockSetChildAt'](expr, index, children[index]);
+      } else {
+        Module['_BinaryenBlockAppendChild'](expr, children[index]);
+      }
+      ++index;
+    }
+    while (prevNumChildren > index) {
+      Module['_BinaryenBlockRemoveChildAt'](expr, --prevNumChildren);
+    }
+  },
+  'getChildAt'(expr, index) {
+    return Module['_BinaryenBlockGetChildAt'](expr, index);
+  },
+  'setChildAt'(expr, index, childExpr) {
+    Module['_BinaryenBlockSetChildAt'](expr, index, childExpr);
+  },
+  'appendChild'(expr, childExpr) {
+    return Module['_BinaryenBlockAppendChild'](expr, childExpr);
+  },
+  'insertChildAt'(expr, index, childExpr) {
+    Module['_BinaryenBlockInsertChildAt'](expr, index, childExpr);
+  },
+  'removeChildAt'(expr, index) {
+    return Module['_BinaryenBlockRemoveChildAt'](expr, index);
+  }
+});
+
+Module['If'] = makeExpressionWrapper({
+  'getCondition'(expr) {
+    return Module['_BinaryenIfGetCondition'](expr);
+  },
+  'setCondition'(expr, condExpr) {
+    Module['_BinaryenIfSetCondition'](expr, condExpr);
+  },
+  'getIfTrue'(expr) {
+    return Module['_BinaryenIfGetIfTrue'](expr);
+  },
+  'setIfTrue'(expr, ifTrueExpr) {
+    Module['_BinaryenIfSetIfTrue'](expr, ifTrueExpr);
+  },
+  'getIfFalse'(expr) {
+    return Module['_BinaryenIfGetIfFalse'](expr);
+  },
+  'setIfFalse'(expr, ifFalseExpr) {
+    Module['_BinaryenIfSetIfFalse'](expr, ifFalseExpr);
+  }
+});
+
+Module['Loop'] = makeExpressionWrapper({
+  'getName'(expr) {
+    const name = Module['_BinaryenLoopGetName'](expr);
+    return name ? UTF8ToString(name) : null;
+  },
+  'setName'(expr, name) {
+    preserveStack(() => { Module['_BinaryenLoopSetName'](expr, strToStack(name)) });
+  },
+  'getBody'(expr) {
+    return Module['_BinaryenLoopGetBody'](expr);
+  },
+  'setBody'(expr, bodyExpr) {
+    Module['_BinaryenLoopSetBody'](expr, bodyExpr);
+  }
+});
+
+Module['Break'] = makeExpressionWrapper({
+  'getName'(expr) {
+    const name = Module['_BinaryenBreakGetName'](expr);
+    return name ? UTF8ToString(name) : null;
+  },
+  'setName'(expr, name) {
+    preserveStack(() => { Module['_BinaryenBreakSetName'](expr, strToStack(name)) });
+  },
+  'getCondition'(expr) {
+    return Module['_BinaryenBreakGetCondition'](expr);
+  },
+  'setCondition'(expr, condExpr) {
+    Module['_BinaryenBreakSetCondition'](expr, condExpr);
+  },
+  'getValue'(expr) {
+    return Module['_BinaryenBreakGetValue'](expr);
+  },
+  'setValue'(expr, valueExpr) {
+    Module['_BinaryenBreakSetValue'](expr, valueExpr);
+  }
+});
+
+Module['Switch'] = makeExpressionWrapper({
+  'getNumNames'(expr) {
+    return Module['_BinaryenSwitchGetNumNames'](expr);
+  },
+  'getNames'(expr) {
+    const numNames = Module['_BinaryenSwitchGetNumNames'](expr);
+    const names = new Array(numNames);
+    let index = 0;
+    while (index < numNames) {
+      names[index] = UTF8ToString(Module['_BinaryenSwitchGetNameAt'](expr, index++));
+    }
+    return names;
+  },
+  'setNames'(expr, names) {
+    const numNames = names.length;
+    let prevNumNames = Module['_BinaryenSwitchGetNumNames'](expr);
+    let index = 0;
+    while (index < numNames) {
+      preserveStack(() => {
+        if (index < prevNumNames) {
+          Module['_BinaryenSwitchSetNameAt'](expr, index, strToStack(names[index]));
+        } else {
+          Module['_BinaryenSwitchAppendName'](expr, strToStack(names[index]));
+        }
+      });
+      ++index;
+    }
+    while (prevNumNames > index) {
+      Module['_BinaryenSwitchRemoveNameAt'](expr, --prevNumNames);
+    }
+  },
+  'getDefaultName'(expr) {
+    const name = Module['_BinaryenSwitchGetDefaultName'](expr);
+    return name ? UTF8ToString(name) : null;
+  },
+  'setDefaultName'(expr, defaultName) {
+    preserveStack(() => { Module['_BinaryenSwitchSetDefaultName'](expr, strToStack(defaultName)) });
+  },
+  'getCondition'(expr) {
+    return Module['_BinaryenSwitchGetCondition'](expr);
+  },
+  'setCondition'(expr, condExpr) {
+    Module['_BinaryenSwitchSetCondition'](expr, condExpr);
+  },
+  'getValue'(expr) {
+    return Module['_BinaryenSwitchGetValue'](expr);
+  },
+  'setValue'(expr, valueExpr) {
+    Module['_BinaryenSwitchSetValue'](expr, valueExpr);
+  },
+  'getNameAt'(expr, index) {
+    return UTF8ToString(Module['_BinaryenSwitchGetNameAt'](expr, index));
+  },
+  'setNameAt'(expr, index, name) {
+    preserveStack(() => { Module['_BinaryenSwitchSetNameAt'](expr, index, strToStack(name)) });
+  },
+  'appendName'(expr, name) {
+    preserveStack(() => Module['_BinaryenSwitchAppendName'](expr, strToStack(name)));
+  },
+  'insertNameAt'(expr, index, name) {
+    preserveStack(() => { Module['_BinaryenSwitchInsertNameAt'](expr, index, strToStack(name)) });
+  },
+  'removeNameAt'(expr, index) {
+    return UTF8ToString(Module['_BinaryenSwitchRemoveNameAt'](expr, index));
+  },
+});
+
+Module['Call'] = makeExpressionWrapper({
+  'getTarget'(expr) {
+    return UTF8ToString(Module['_BinaryenCallGetTarget'](expr));
+  },
+  'setTarget'(expr, targetName) {
+    preserveStack(() => { Module['_BinaryenCallSetTarget'](expr, strToStack(targetName)) });
+  },
+  'getNumOperands'(expr) {
+    return Module['_BinaryenCallGetNumOperands'](expr);
+  },
+  'getOperands'(expr) {
+    const numOperands = Module['_BinaryenCallGetNumOperands'](expr);
+    const operands = new Array(numOperands);
+    let index = 0;
+    while (index < numOperands) {
+      operands[index] = Module['_BinaryenCallGetOperandAt'](expr, index++);
+    }
+    return operands;
+  },
+  'setOperands'(expr, operands) {
+    const numOperands = operands.length;
+    let prevNumOperands = Module['_BinaryenCallGetNumOperands'](expr);
+    let index = 0;
+    while (index < numOperands) {
+      if (index < prevNumOperands) {
+        Module['_BinaryenCallSetOperandAt'](expr, index, operands[index]);
+      } else {
+        Module['_BinaryenCallAppendOperand'](expr, operands[index]);
+      }
+      ++index;
+    }
+    while (prevNumOperands > index) {
+      Module['_BinaryenCallRemoveOperandAt'](expr, --prevNumOperands);
+    }
+  },
+  'getOperandAt'(expr, index) {
+    return Module['_BinaryenCallGetOperandAt'](expr, index);
+  },
+  'setOperandAt'(expr, index, operandExpr) {
+    Module['_BinaryenCallSetOperandAt'](expr, index, operandExpr);
+  },
+  'appendOperand'(expr, operandExpr) {
+    return Module['_BinaryenCallAppendOperand'](expr, operandExpr);
+  },
+  'insertOperandAt'(expr, index, operandExpr) {
+    Module['_BinaryenCallInsertOperandAt'](expr, index, operandExpr);
+  },
+  'removeOperandAt'(expr, index) {
+    return Module['_BinaryenCallRemoveOperandAt'](expr, index);
+  },
+  'isReturn'(expr) {
+    return Boolean(Module['_BinaryenCallIsReturn'](expr));
+  },
+  'setReturn'(expr, isReturn) {
+    Module['_BinaryenCallSetReturn'](expr, isReturn);
+  }
+});
+
+Module['CallIndirect'] = makeExpressionWrapper({
+  'getTarget'(expr) {
+    return Module['_BinaryenCallIndirectGetTarget'](expr);
+  },
+  'setTarget'(expr, targetExpr) {
+    Module['_BinaryenCallIndirectSetTarget'](expr, targetExpr);
+  },
+  'getNumOperands'(expr) {
+    return Module['_BinaryenCallIndirectGetNumOperands'](expr);
+  },
+  'getOperands'(expr) {
+    const numOperands = Module['_BinaryenCallIndirectGetNumOperands'](expr);
+    const operands = new Array(numOperands);
+    let index = 0;
+    while (index < numOperands) {
+      operands[index] = Module['_BinaryenCallIndirectGetOperandAt'](expr, index++);
+    }
+    return operands;
+  },
+  'setOperands'(expr, operands) {
+    const numOperands = operands.length;
+    let prevNumOperands = Module['_BinaryenCallIndirectGetNumOperands'](expr);
+    let index = 0;
+    while (index < numOperands) {
+      if (index < prevNumOperands) {
+        Module['_BinaryenCallIndirectSetOperandAt'](expr, index, operands[index]);
+      } else {
+        Module['_BinaryenCallIndirectAppendOperand'](expr, operands[index]);
+      }
+      ++index;
+    }
+    while (prevNumOperands > index) {
+      Module['_BinaryenCallIndirectRemoveOperandAt'](expr, --prevNumOperands);
+    }
+  },
+  'getOperandAt'(expr, index) {
+    return Module['_BinaryenCallIndirectGetOperandAt'](expr, index);
+  },
+  'setOperandAt'(expr, index, operandExpr) {
+    Module['_BinaryenCallIndirectSetOperandAt'](expr, index, operandExpr);
+  },
+  'appendOperand'(expr, operandExpr) {
+    return Module['_BinaryenCallIndirectAppendOperand'](expr, operandExpr);
+  },
+  'insertOperandAt'(expr, index, operandExpr) {
+    Module['_BinaryenCallIndirectInsertOperandAt'](expr, index, operandExpr);
+  },
+  'removeOperandAt'(expr, index) {
+    return Module['_BinaryenCallIndirectRemoveOperandAt'](expr, index);
+  },
+  'isReturn'(expr) {
+    return Boolean(Module['_BinaryenCallIndirectIsReturn'](expr));
+  },
+  'setReturn'(expr, isReturn) {
+    Module['_BinaryenCallIndirectSetReturn'](expr, isReturn);
+  },
+  'getParams'(expr) {
+    return Module['_BinaryenCallIndirectGetParams'](expr);
+  },
+  'setParams'(expr, params) {
+    Module['_BinaryenCallIndirectSetParams'](expr, params);
+  },
+  'getResults'(expr) {
+    return Module['_BinaryenCallIndirectGetResults'](expr);
+  },
+  'setResults'(expr, results) {
+    Module['_BinaryenCallIndirectSetResults'](expr, results);
+  }
+});
+
+Module['LocalGet'] = makeExpressionWrapper({
+  'getIndex'(expr) {
+    return Module['_BinaryenLocalGetGetIndex'](expr);
+  },
+  'setIndex'(expr, index) {
+    Module['_BinaryenLocalGetSetIndex'](expr, index);
+  }
+});
+
+Module['LocalSet'] = makeExpressionWrapper({
+  'getIndex'(expr) {
+    return Module['_BinaryenLocalSetGetIndex'](expr);
+  },
+  'setIndex'(expr, index) {
+    Module['_BinaryenLocalSetSetIndex'](expr, index);
+  },
+  'isTee'(expr) {
+    return Boolean(Module['_BinaryenLocalSetIsTee'](expr));
+  },
+  'getValue'(expr) {
+    return Module['_BinaryenLocalSetGetValue'](expr);
+  },
+  'setValue'(expr, valueExpr) {
+    Module['_BinaryenLocalSetSetValue'](expr, valueExpr);
+  }
+});
+
+Module['GlobalGet'] = makeExpressionWrapper({
+  'getName'(expr) {
+    return UTF8ToString(Module['_BinaryenGlobalGetGetName'](expr));
+  },
+  'setName'(expr, name) {
+    preserveStack(() => { Module['_BinaryenGlobalGetSetName'](expr, strToStack(name)) });
+  }
+});
+
+Module['GlobalSet'] = makeExpressionWrapper({
+  'getName'(expr) {
+    return UTF8ToString(Module['_BinaryenGlobalSetGetName'](expr));
+  },
+  'setName'(expr, name) {
+    preserveStack(() => { Module['_BinaryenGlobalSetSetName'](expr, strToStack(name)) });
+  },
+  'getValue'(expr) {
+    return Module['_BinaryenGlobalSetGetValue'](expr);
+  },
+  'setValue'(expr, valueExpr) {
+    Module['_BinaryenGlobalSetSetValue'](expr, valueExpr);
+  }
+});
+
+Module['MemorySize'] = makeExpressionWrapper({});
+
+Module['MemoryGrow'] = makeExpressionWrapper({
+  'getDelta'(expr) {
+    return Module['_BinaryenMemoryGrowGetDelta'](expr);
+  },
+  'setDelta'(expr, deltaExpr) {
+    Module['_BinaryenMemoryGrowSetDelta'](expr, deltaExpr);
+  }
+});
+
+Module['Load'] = makeExpressionWrapper({
+  'isAtomic'(expr) {
+    return Boolean(Module['_BinaryenLoadIsAtomic'](expr));
+  },
+  'setAtomic'(expr, isAtomic) {
+    Module['_BinaryenLoadSetAtomic'](expr, isAtomic);
+  },
+  'isSigned'(expr) {
+    return Boolean(Module['_BinaryenLoadIsSigned'](expr));
+  },
+  'setSigned'(expr, isSigned) {
+    Module['_BinaryenLoadSetSigned'](expr, isSigned);
+  },
+  'getOffset'(expr) {
+    return Module['_BinaryenLoadGetOffset'](expr);
+  },
+  'setOffset'(expr, offset) {
+    Module['_BinaryenLoadSetOffset'](expr, offset);
+  },
+  'getBytes'(expr) {
+    return Module['_BinaryenLoadGetBytes'](expr);
+  },
+  'setBytes'(expr, bytes) {
+    Module['_BinaryenLoadSetBytes'](expr, bytes);
+  },
+  'getAlign'(expr) {
+    return Module['_BinaryenLoadGetAlign'](expr);
+  },
+  'setAlign'(expr, align) {
+    Module['_BinaryenLoadSetAlign'](expr, align);
+  },
+  'getPtr'(expr) {
+    return Module['_BinaryenLoadGetPtr'](expr);
+  },
+  'setPtr'(expr, ptrExpr) {
+    Module['_BinaryenLoadSetPtr'](expr, ptrExpr);
+  }
+});
+
+Module['Store'] = makeExpressionWrapper({
+  'isAtomic'(expr) {
+    return Boolean(Module['_BinaryenStoreIsAtomic'](expr));
+  },
+  'setAtomic'(expr, isAtomic) {
+    Module['_BinaryenStoreSetAtomic'](expr, isAtomic);
+  },
+  'getBytes'(expr) {
+    return Module['_BinaryenStoreGetBytes'](expr);
+  },
+  'setBytes'(expr, bytes) {
+    Module['_BinaryenStoreSetBytes'](expr, bytes);
+  },
+  'getOffset'(expr) {
+    return Module['_BinaryenStoreGetOffset'](expr);
+  },
+  'setOffset'(expr, offset) {
+    Module['_BinaryenStoreSetOffset'](expr, offset);
+  },
+  'getAlign'(expr) {
+    return Module['_BinaryenStoreGetAlign'](expr);
+  },
+  'setAlign'(expr, align) {
+    Module['_BinaryenStoreSetAlign'](expr, align);
+  },
+  'getPtr'(expr) {
+    return Module['_BinaryenStoreGetPtr'](expr);
+  },
+  'setPtr'(expr, ptrExpr) {
+    Module['_BinaryenStoreSetPtr'](expr, ptrExpr);
+  },
+  'getValue'(expr) {
+    return Module['_BinaryenStoreGetValue'](expr);
+  },
+  'setValue'(expr, valueExpr) {
+    Module['_BinaryenStoreSetValue'](expr, valueExpr);
+  },
+  'getValueType'(expr) {
+    return Module['_BinaryenStoreGetValueType'](expr);
+  },
+  'setValueType'(expr, valueType) {
+    Module['_BinaryenStoreSetValueType'](expr, valueType);
+  }
+});
+
+Module['Const'] = makeExpressionWrapper({
+  'getValueI32'(expr) {
+    return Module['_BinaryenConstGetValueI32'](expr);
+  },
+  'setValueI32'(expr, value) {
+    Module['_BinaryenConstSetValueI32'](expr, value);
+  },
+  'getValueI64Low'(expr) {
+    return Module['_BinaryenConstGetValueI64Low'](expr);
+  },
+  'setValueI64Low'(expr, value) {
+    Module['_BinaryenConstSetValueI64Low'](expr, value);
+  },
+  'getValueI64High'(expr) {
+    return Module['_BinaryenConstGetValueI64High'](expr);
+  },
+  'setValueI64High'(expr, value) {
+    Module['_BinaryenConstSetValueI64High'](expr, value);
+  },
+  'getValueF32'(expr) {
+    return Module['_BinaryenConstGetValueF32'](expr);
+  },
+  'setValueF32'(expr, value) {
+    Module['_BinaryenConstSetValueF32'](expr, value);
+  },
+  'getValueF64'(expr) {
+    return Module['_BinaryenConstGetValueF64'](expr);
+  },
+  'setValueF64'(expr, value) {
+    Module['_BinaryenConstSetValueF64'](expr, value);
+  },
+  'getValueV128'(expr) {
+    let value;
+    preserveStack(() => {
+      const tempBuffer = stackAlloc(16);
+      Module['_BinaryenConstGetValueV128'](expr, tempBuffer);
+      value = new Array(16);
+      for (let i = 0 ; i < 16; ++i) {
+        value[i] = HEAPU8[tempBuffer + i];
+      }
+    });
+    return value;
+  },
+  'setValueV128'(expr, value) {
+    preserveStack(() => {
+      const tempBuffer = stackAlloc(16);
+      for (let i = 0 ; i < 16; ++i) {
+        HEAPU8[tempBuffer + i] = value[i];
+      }
+      Module['_BinaryenConstSetValueV128'](expr, tempBuffer);
+    });
+  }
+});
+
+Module['Unary'] = makeExpressionWrapper({
+  'getOp'(expr) {
+    return Module['_BinaryenUnaryGetOp'](expr);
+  },
+  'setOp'(expr, op) {
+    Module['_BinaryenUnarySetOp'](expr, op);
+  },
+  'getValue'(expr) {
+    return Module['_BinaryenUnaryGetValue'](expr);
+  },
+  'setValue'(expr, valueExpr) {
+    Module['_BinaryenUnarySetValue'](expr, valueExpr);
+  }
+});
+
+Module['Binary'] = makeExpressionWrapper({
+  'getOp'(expr) {
+    return Module['_BinaryenBinaryGetOp'](expr);
+  },
+  'setOp'(expr, op) {
+    Module['_BinaryenBinarySetOp'](expr, op);
+  },
+  'getLeft'(expr) {
+    return Module['_BinaryenBinaryGetLeft'](expr);
+  },
+  'setLeft'(expr, leftExpr) {
+    Module['_BinaryenBinarySetLeft'](expr, leftExpr);
+  },
+  'getRight'(expr) {
+    return Module['_BinaryenBinaryGetRight'](expr);
+  },
+  'setRight'(expr, rightExpr) {
+    Module['_BinaryenBinarySetRight'](expr, rightExpr);
+  }
+});
+
+Module['Select'] = makeExpressionWrapper({
+  'getIfTrue'(expr) {
+    return Module['_BinaryenSelectGetIfTrue'](expr);
+  },
+  'setIfTrue'(expr, ifTrueExpr) {
+    Module['_BinaryenSelectSetIfTrue'](expr, ifTrueExpr);
+  },
+  'getIfFalse'(expr) {
+    return Module['_BinaryenSelectGetIfFalse'](expr);
+  },
+  'setIfFalse'(expr, ifFalseExpr) {
+    Module['_BinaryenSelectSetIfFalse'](expr, ifFalseExpr);
+  },
+  'getCondition'(expr) {
+    return Module['_BinaryenSelectGetCondition'](expr);
+  },
+  'setCondition'(expr, condExpr) {
+    Module['_BinaryenSelectSetCondition'](expr, condExpr);
+  }
+});
+
+Module['Drop'] = makeExpressionWrapper({
+  'getValue'(expr) {
+    return Module['_BinaryenDropGetValue'](expr);
+  },
+  'setValue'(expr, valueExpr) {
+    Module['_BinaryenDropSetValue'](expr, valueExpr);
+  }
+});
+
+Module['Return'] = makeExpressionWrapper({
+  'getValue'(expr) {
+    return Module['_BinaryenReturnGetValue'](expr);
+  },
+  'setValue'(expr, valueExpr) {
+    Module['_BinaryenReturnSetValue'](expr, valueExpr);
+  }
+});
+
+Module['AtomicRMW'] = makeExpressionWrapper({
+  'getOp'(expr) {
+    return Module['_BinaryenAtomicRMWGetOp'](expr);
+  },
+  'setOp'(expr, op) {
+    Module['_BinaryenAtomicRMWSetOp'](expr, op);
+  },
+  'getBytes'(expr) {
+    return Module['_BinaryenAtomicRMWGetBytes'](expr);
+  },
+  'setBytes'(expr, bytes) {
+    Module['_BinaryenAtomicRMWSetBytes'](expr, bytes);
+  },
+  'getOffset'(expr) {
+    return Module['_BinaryenAtomicRMWGetOffset'](expr);
+  },
+  'setOffset'(expr, offset) {
+    Module['_BinaryenAtomicRMWSetOffset'](expr, offset);
+  },
+  'getPtr'(expr) {
+    return Module['_BinaryenAtomicRMWGetPtr'](expr);
+  },
+  'setPtr'(expr, ptrExpr) {
+    Module['_BinaryenAtomicRMWSetPtr'](expr, ptrExpr);
+  },
+  'getValue'(expr) {
+    return Module['_BinaryenAtomicRMWGetValue'](expr);
+  },
+  'setValue'(expr, valueExpr) {
+    Module['_BinaryenAtomicRMWSetValue'](expr, valueExpr);
+  }
+});
+
+Module['AtomicCmpxchg'] = makeExpressionWrapper({
+  'getBytes'(expr) {
+    return Module['_BinaryenAtomicCmpxchgGetBytes'](expr);
+  },
+  'setBytes'(expr, bytes) {
+    Module['_BinaryenAtomicCmpxchgSetBytes'](expr, bytes);
+  },
+  'getOffset'(expr) {
+    return Module['_BinaryenAtomicCmpxchgGetOffset'](expr);
+  },
+  'setOffset'(expr, offset) {
+    Module['_BinaryenAtomicCmpxchgSetOffset'](expr, offset);
+  },
+  'getPtr'(expr) {
+    return Module['_BinaryenAtomicCmpxchgGetPtr'](expr);
+  },
+  'setPtr'(expr, ptrExpr) {
+    Module['_BinaryenAtomicCmpxchgSetPtr'](expr, ptrExpr);
+  },
+  'getExpected'(expr) {
+    return Module['_BinaryenAtomicCmpxchgGetExpected'](expr);
+  },
+  'setExpected'(expr, expectedExpr) {
+    Module['_BinaryenAtomicCmpxchgSetExpected'](expr, expectedExpr);
+  },
+  'getReplacement'(expr) {
+    return Module['_BinaryenAtomicCmpxchgGetReplacement'](expr);
+  },
+  'setReplacement'(expr, replacementExpr) {
+    Module['_BinaryenAtomicCmpxchgSetReplacement'](expr, replacementExpr);
+  }
+});
+
+Module['AtomicWait'] = makeExpressionWrapper({
+  'getPtr'(expr) {
+    return Module['_BinaryenAtomicWaitGetPtr'](expr);
+  },
+  'setPtr'(expr, ptrExpr) {
+    Module['_BinaryenAtomicWaitSetPtr'](expr, ptrExpr);
+  },
+  'getExpected'(expr) {
+    return Module['_BinaryenAtomicWaitGetExpected'](expr);
+  },
+  'setExpected'(expr, expectedExpr) {
+    Module['_BinaryenAtomicWaitSetExpected'](expr, expectedExpr);
+  },
+  'getTimeout'(expr) {
+    return Module['_BinaryenAtomicWaitGetTimeout'](expr);
+  },
+  'setTimeout'(expr, timeoutExpr) {
+    Module['_BinaryenAtomicWaitSetTimeout'](expr, timeoutExpr);
+  },
+  'getExpectedType'(expr) {
+    return Module['_BinaryenAtomicWaitGetExpectedType'](expr);
+  },
+  'setExpectedType'(expr, expectedType) {
+    Module['_BinaryenAtomicWaitSetExpectedType'](expr, expectedType);
+  }
+});
+
+Module['AtomicNotify'] = makeExpressionWrapper({
+  'getPtr'(expr) {
+    return Module['_BinaryenAtomicNotifyGetPtr'](expr);
+  },
+  'setPtr'(expr, ptrExpr) {
+    Module['_BinaryenAtomicNotifySetPtr'](expr, ptrExpr);
+  },
+  'getNotifyCount'(expr) {
+    return Module['_BinaryenAtomicNotifyGetNotifyCount'](expr);
+  },
+  'setNotifyCount'(expr, notifyCountExpr) {
+    Module['_BinaryenAtomicNotifySetNotifyCount'](expr, notifyCountExpr);
+  }
+});
+
+Module['AtomicFence'] = makeExpressionWrapper({
+  'getOrder'(expr) {
+    return Module['_BinaryenAtomicFenceGetOrder'](expr);
+  },
+  'setOrder'(expr, order) {
+    Module['_BinaryenAtomicFenceSetOrder'](expr, order);
+  }
+});
+
+Module['SIMDExtract'] = makeExpressionWrapper({
+  'getOp'(expr) {
+    return Module['_BinaryenSIMDExtractGetOp'](expr);
+  },
+  'setOp'(expr, op) {
+    Module['_BinaryenSIMDExtractSetOp'](expr, op);
+  },
+  'getVec'(expr) {
+    return Module['_BinaryenSIMDExtractGetVec'](expr);
+  },
+  'setVec'(expr, vecExpr) {
+    Module['_BinaryenSIMDExtractSetVec'](expr, vecExpr);
+  },
+  'getIndex'(expr) {
+    return Module['_BinaryenSIMDExtractGetIndex'](expr);
+  },
+  'setIndex'(expr, index) {
+    Module['_BinaryenSIMDExtractSetIndex'](expr, index)
+  }
+});
+
+Module['SIMDReplace'] = makeExpressionWrapper({
+  'getOp'(expr) {
+    return Module['_BinaryenSIMDReplaceGetOp'](expr);
+  },
+  'setOp'(expr, op) {
+    Module['_BinaryenSIMDReplaceSetOp'](expr, op);
+  },
+  'getVec'(expr) {
+    return Module['_BinaryenSIMDReplaceGetVec'](expr);
+  },
+  'setVec'(expr, vecExpr) {
+    Module['_BinaryenSIMDReplaceSetVec'](expr, vecExpr);
+  },
+  'getIndex'(expr) {
+    return Module['_BinaryenSIMDReplaceGetIndex'](expr);
+  },
+  'setIndex'(expr, index) {
+    Module['_BinaryenSIMDReplaceSetIndex'](expr, index);
+  },
+  'getValue'(expr) {
+    return Module['_BinaryenSIMDReplaceGetValue'](expr);
+  },
+  'setValue'(expr, valueExpr) {
+    Module['_BinaryenSIMDReplaceSetValue'](expr, valueExpr);
+  }
+});
+
+Module['SIMDShuffle'] = makeExpressionWrapper({
+  'getLeft'(expr) {
+    return Module['_BinaryenSIMDShuffleGetLeft'](expr);
+  },
+  'setLeft'(expr, leftExpr) {
+    Module['_BinaryenSIMDShuffleSetLeft'](expr, leftExpr)
+  },
+  'getRight'(expr) {
+    return Module['_BinaryenSIMDShuffleGetRight'](expr);
+  },
+  'setRight'(expr, rightExpr) {
+    Module['_BinaryenSIMDShuffleSetRight'](expr, rightExpr);
+  },
+  'getMask'(expr) {
+    let mask;
+    preserveStack(() => {
+      const tempBuffer = stackAlloc(16);
+      Module['_BinaryenSIMDShuffleGetMask'](expr, tempBuffer);
+      mask = new Array(16);
+      for (let i = 0 ; i < 16; ++i) {
+        mask[i] = HEAPU8[tempBuffer + i];
+      }
+    });
+    return mask;
+  },
+  'setMask'(expr, mask) {
+    preserveStack(() => {
+      const tempBuffer = stackAlloc(16);
+      for (let i = 0 ; i < 16; ++i) {
+        HEAPU8[tempBuffer + i] = mask[i];
+      }
+      Module['_BinaryenSIMDShuffleSetMask'](expr, tempBuffer);
+    });
+  }
+});
+
+Module['SIMDTernary'] = makeExpressionWrapper({
+  'getOp'(expr) {
+    return Module['_BinaryenSIMDTernaryGetOp'](expr);
+  },
+  'setOp'(expr, op) {
+    Module['_BinaryenSIMDTernarySetOp'](expr, op);
+  },
+  'getA'(expr) {
+    return Module['_BinaryenSIMDTernaryGetA'](expr);
+  },
+  'setA'(expr, aExpr) {
+    Module['_BinaryenSIMDTernarySetA'](expr, aExpr);
+  },
+  'getB'(expr) {
+    return Module['_BinaryenSIMDTernaryGetB'](expr);
+  },
+  'setB'(expr, bExpr) {
+    Module['_BinaryenSIMDTernarySetB'](expr, bExpr);
+  },
+  'getC'(expr) {
+    return Module['_BinaryenSIMDTernaryGetC'](expr);
+  },
+  'setC'(expr, cExpr) {
+    Module['_BinaryenSIMDTernarySetC'](expr, cExpr);
+  }
+});
+
+Module['SIMDShift'] = makeExpressionWrapper({
+  'getOp'(expr) {
+    return Module['_BinaryenSIMDShiftGetOp'](expr);
+  },
+  'setOp'(expr, op) {
+    Module['_BinaryenSIMDShiftSetOp'](expr, op);
+  },
+  'getVec'(expr) {
+    return Module['_BinaryenSIMDShiftGetVec'](expr);
+  },
+  'setVec'(expr, vecExpr) {
+    Module['_BinaryenSIMDShiftSetVec'](expr, vecExpr);
+  },
+  'getShift'(expr) {
+    return Module['_BinaryenSIMDShiftGetShift'](expr);
+  },
+  'setShift'(expr, shiftExpr) {
+    Module['_BinaryenSIMDShiftSetShift'](expr, shiftExpr);
+  }
+});
+
+Module['SIMDLoad'] = makeExpressionWrapper({
+  'getOp'(expr) {
+    return Module['_BinaryenSIMDLoadGetOp'](expr);
+  },
+  'setOp'(expr, op) {
+    Module['_BinaryenSIMDLoadSetOp'](expr, op);
+  },
+  'getOffset'(expr) {
+    return Module['_BinaryenSIMDLoadGetOffset'](expr);
+  },
+  'setOffset'(expr, offset) {
+    Module['_BinaryenSIMDLoadSetOffset'](expr, offset);
+  },
+  'getAlign'(expr) {
+    return Module['_BinaryenSIMDLoadGetAlign'](expr);
+  },
+  'setAlign'(expr, align) {
+    Module['_BinaryenSIMDLoadSetAlign'](expr, align);
+  },
+  'getPtr'(expr) {
+    return Module['_BinaryenSIMDLoadGetPtr'](expr);
+  },
+  'setPtr'(expr, ptrExpr) {
+    Module['_BinaryenSIMDLoadSetPtr'](expr, ptrExpr);
+  }
+});
+
+Module['MemoryInit'] = makeExpressionWrapper({
+  'getSegment'(expr) {
+    return Module['_BinaryenMemoryInitGetSegment'](expr);
+  },
+  'setSegment'(expr, segmentIndex) {
+    Module['_BinaryenMemoryInitSetSegment'](expr, segmentIndex);
+  },
+  'getDest'(expr) {
+    return Module['_BinaryenMemoryInitGetDest'](expr);
+  },
+  'setDest'(expr, destExpr) {
+    Module['_BinaryenMemoryInitSetDest'](expr, destExpr);
+  },
+  'getOffset'(expr) {
+    return Module['_BinaryenMemoryInitGetOffset'](expr);
+  },
+  'setOffset'(expr, offset) {
+    Module['_BinaryenMemoryInitSetOffset'](expr, offset);
+  },
+  'getSize'(expr) {
+    return Module['_BinaryenMemoryInitGetSize'](expr);
+  },
+  'setSize'(expr, sizeExpr) {
+    Module['_BinaryenMemoryInitSetSize'](expr, sizeExpr);
+  }
+});
+
+Module['DataDrop'] = makeExpressionWrapper({
+  'getSegment'(expr) {
+    return Module['_BinaryenDataDropGetSegment'](expr);
+  },
+  'setSegment'(expr, segmentIndex) {
+    Module['_BinaryenDataDropSetSegment'](expr, segmentIndex);
+  }
+});
+
+Module['MemoryCopy'] = makeExpressionWrapper({
+  'getDest'(expr) {
+    return Module['_BinaryenMemoryCopyGetDest'](expr);
+  },
+  'setDest'(expr, destExpr) {
+    Module['_BinaryenMemoryCopySetDest'](expr, destExpr);
+  },
+  'getSource'(expr) {
+    return Module['_BinaryenMemoryCopyGetSource'](expr);
+  },
+  'setSource'(expr, sourceExpr) {
+    Module['_BinaryenMemoryCopySetSource'](expr, sourceExpr);
+  },
+  'getSize'(expr) {
+    return Module['_BinaryenMemoryCopyGetSize'](expr);
+  },
+  'setSize'(expr, sizeExpr) {
+    Module['_BinaryenMemoryCopySetSize'](expr, sizeExpr);
+  }
+});
+
+Module['MemoryFill'] = makeExpressionWrapper({
+  'getDest'(expr) {
+    return Module['_BinaryenMemoryFillGetDest'](expr);
+  },
+  'setDest'(expr, destExpr) {
+    Module['_BinaryenMemoryFillSetDest'](expr, destExpr);
+  },
+  'getValue'(expr) {
+    return Module['_BinaryenMemoryFillGetValue'](expr);
+  },
+  'setValue'(expr, valueExpr) {
+    Module['_BinaryenMemoryFillSetValue'](expr, valueExpr);
+  },
+  'getSize'(expr) {
+    return Module['_BinaryenMemoryFillGetSize'](expr);
+  },
+  'setSize'(expr, sizeExpr) {
+    Module['_BinaryenMemoryFillSetSize'](expr, sizeExpr);
+  }
+});
+
+Module['RefIsNull'] = makeExpressionWrapper({
+  'getValue'(expr) {
+    return Module['_BinaryenRefIsNullGetValue'](expr);
+  },
+  'setValue'(expr, valueExpr) {
+    Module['_BinaryenRefIsNullSetValue'](expr, valueExpr);
+  }
+});
+
+Module['RefFunc'] = makeExpressionWrapper({
+  'getFunc'(expr) {
+    return UTF8ToString(Module['_BinaryenRefFuncGetFunc'](expr));
+  },
+  'setFunc'(expr, funcName) {
+    preserveStack(() => { Module['_BinaryenRefFuncSetFunc'](expr, strToStack(funcName)) });
+  }
+});
+
+Module['RefEq'] = makeExpressionWrapper({
+  'getLeft'(expr) {
+    return Module['_BinaryenRefEqGetLeft'](expr);
+  },
+  'setLeft'(expr, leftExpr) {
+    return Module['_BinaryenRefEqSetLeft'](expr, leftExpr);
+  },
+  'getRight'(expr) {
+    return Module['_BinaryenRefEqGetRight'](expr);
+  },
+  'setRight'(expr, rightExpr) {
+    return Module['_BinaryenRefEqSetRight'](expr, rightExpr);
+  }
+});
+
+Module['Try'] = makeExpressionWrapper({
+  'getBody'(expr) {
+    return Module['_BinaryenTryGetBody'](expr);
+  },
+  'setBody'(expr, bodyExpr) {
+    Module['_BinaryenTrySetBody'](expr, bodyExpr);
+  },
+  'getCatchBody'(expr) {
+    return Module['_BinaryenTryGetCatchBody'](expr);
+  },
+  'setCatchBody'(expr, catchBodyExpr) {
+    Module['_BinaryenTrySetCatchBody'](expr, catchBodyExpr);
+  }
+});
+
+Module['Throw'] = makeExpressionWrapper({
+  'getEvent'(expr) {
+    return UTF8ToString(Module['_BinaryenThrowGetEvent'](expr));
+  },
+  'setEvent'(expr, eventName) {
+    preserveStack(() => { Module['_BinaryenThrowSetEvent'](expr, strToStack(eventName)) });
+  },
+  'getNumOperands'(expr) {
+    return Module['_BinaryenThrowGetNumOperands'](expr);
+  },
+  'getOperands'(expr) {
+    const numOperands = Module['_BinaryenThrowGetNumOperands'](expr);
+    const operands = new Array(numOperands);
+    let index = 0;
+    while (index < numOperands) {
+      operands[index] = Module['_BinaryenThrowGetOperandAt'](expr, index++);
+    }
+    return operands;
+  },
+  'setOperands'(expr, operands) {
+    const numOperands = operands.length;
+    let prevNumOperands = Module['_BinaryenThrowGetNumOperands'](expr);
+    let index = 0;
+    while (index < numOperands) {
+      if (index < prevNumOperands) {
+        Module['_BinaryenThrowSetOperandAt'](expr, index, operands[index]);
+      } else {
+        Module['_BinaryenThrowAppendOperand'](expr, operands[index]);
+      }
+      ++index;
+    }
+    while (prevNumOperands > index) {
+      Module['_BinaryenThrowRemoveOperandAt'](expr, --prevNumOperands);
+    }
+  },
+  'getOperandAt'(expr, index) {
+    return Module['_BinaryenThrowGetOperandAt'](expr, index);
+  },
+  'setOperandAt'(expr, index, operandExpr) {
+    Module['_BinaryenThrowSetOperandAt'](expr, index, operandExpr);
+  },
+  'appendOperand'(expr, operandExpr) {
+    return Module['_BinaryenThrowAppendOperand'](expr, operandExpr);
+  },
+  'insertOperandAt'(expr, index, operandExpr) {
+    Module['_BinaryenThrowInsertOperandAt'](expr, index, operandExpr);
+  },
+  'removeOperandAt'(expr, index) {
+    return Module['_BinaryenThrowRemoveOperandAt'](expr, index);
+  },
+});
+
+Module['Rethrow'] = makeExpressionWrapper({
+  'getExnref'(expr) {
+    return Module['_BinaryenRethrowGetExnref'](expr);
+  },
+  'setExnref'(expr, exnrefExpr) {
+    Module['_BinaryenRethrowSetExnref'](expr, exnrefExpr);
+  }
+});
+
+Module['BrOnExn'] = makeExpressionWrapper({
+  'getEvent'(expr) {
+    return UTF8ToString(Module['_BinaryenBrOnExnGetEvent'](expr));
+  },
+  'setEvent'(expr, eventName) {
+    preserveStack(() => { Module['_BinaryenBrOnExnSetEvent'](expr, strToStack(eventName)) });
+  },
+  'getName'(expr) {
+    return UTF8ToString(Module['_BinaryenBrOnExnGetName'](expr));
+  },
+  'setName'(expr, name) {
+    preserveStack(() => { Module['_BinaryenBrOnExnSetName'](expr, strToStack(name)) });
+  },
+  'getExnref'(expr) {
+    return Module['_BinaryenBrOnExnGetExnref'](expr);
+  },
+  'setExnref'(expr, exnrefExpr) {
+    Module['_BinaryenBrOnExnSetExnref'](expr, exnrefExpr);
+  }
+});
+
+Module['TupleMake'] = makeExpressionWrapper({
+  'getNumOperands'(expr) {
+    return Module['_BinaryenTupleMakeGetNumOperands'](expr);
+  },
+  'getOperands'(expr) {
+    const numOperands = Module['_BinaryenTupleMakeGetNumOperands'](expr);
+    const operands = new Array(numOperands);
+    let index = 0;
+    while (index < numOperands) {
+      operands[index] = Module['_BinaryenTupleMakeGetOperandAt'](expr, index++);
+    }
+    return operands;
+  },
+  'setOperands'(expr, operands) {
+    const numOperands = operands.length;
+    let prevNumOperands = Module['_BinaryenTupleMakeGetNumOperands'](expr);
+    let index = 0;
+    while (index < numOperands) {
+      if (index < prevNumOperands) {
+        Module['_BinaryenTupleMakeSetOperandAt'](expr, index, operands[index]);
+      } else {
+        Module['_BinaryenTupleMakeAppendOperand'](expr, operands[index]);
+      }
+      ++index;
+    }
+    while (prevNumOperands > index) {
+      Module['_BinaryenTupleMakeRemoveOperandAt'](expr, --prevNumOperands);
+    }
+  },
+  'getOperandAt'(expr, index) {
+    return Module['_BinaryenTupleMakeGetOperandAt'](expr, index);
+  },
+  'setOperandAt'(expr, index, operandExpr) {
+    Module['_BinaryenTupleMakeSetOperandAt'](expr, index, operandExpr);
+  },
+  'appendOperand'(expr, operandExpr) {
+    return Module['_BinaryenTupleMakeAppendOperand'](expr, operandExpr);
+  },
+  'insertOperandAt'(expr, index, operandExpr) {
+    Module['_BinaryenTupleMakeInsertOperandAt'](expr, index, operandExpr);
+  },
+  'removeOperandAt'(expr, index) {
+    return Module['_BinaryenTupleMakeRemoveOperandAt'](expr, index);
+  }
+});
+
+Module['TupleExtract'] = makeExpressionWrapper({
+  'getTuple'(expr) {
+    return Module['_BinaryenTupleExtractGetTuple'](expr);
+  },
+  'setTuple'(expr, tupleExpr) {
+    Module['_BinaryenTupleExtractSetTuple'](expr, tupleExpr);
+  },
+  'getIndex'(expr) {
+    return Module['_BinaryenTupleExtractGetIndex'](expr);
+  },
+  'setIndex'(expr, index) {
+    Module['_BinaryenTupleExtractSetIndex'](expr, index);
+  }
+});
+
+Module['I31New'] = makeExpressionWrapper({
+  'getValue'(expr) {
+    return Module['_BinaryenI31NewGetValue'](expr);
+  },
+  'setValue'(expr, valueExpr) {
+    Module['_BinaryenI31NewSetValue'](expr, valueExpr);
+  }
+});
+
+Module['I31Get'] = makeExpressionWrapper({
+  'getI31'(expr) {
+    return Module['_BinaryenI31GetGetI31'](expr);
+  },
+  'setI31'(expr, i31Expr) {
+    Module['_BinaryenI31GetSetI31'](expr, i31Expr);
+  },
+  'isSigned'(expr) {
+    return Boolean(Module['_BinaryenI31GetIsSigned'](expr));
+  },
+  'setSigned'(expr, isSigned) {
+    Module['_BinaryenI31GetSetSigned'](expr, isSigned);
+  }
+});
+
+// Function wrapper
+
+Module['Function'] = (() => {
+  // Closure compiler doesn't allow multiple `Function`s at top-level, so:
+  function Function(func) {
+    if (!(this instanceof Function)) {
+      if (!func) return null;
+      return new Function(func);
+    }
+    if (!func) throw Error("function reference must not be null");
+    this[thisPtr] = func;
+  }
+  Function['getName'] = function(func) {
+    return UTF8ToString(Module['_BinaryenFunctionGetName'](func));
+  };
+  Function['getParams'] = function(func) {
+    return Module['_BinaryenFunctionGetParams'](func);
+  };
+  Function['getResults'] = function(func) {
+    return Module['_BinaryenFunctionGetResults'](func);
+  };
+  Function['getNumVars'] = function(func) {
+    return Module['_BinaryenFunctionGetNumVars'](func);
+  };
+  Function['getVar'] = function(func, index) {
+    return Module['_BinaryenFunctionGetVar'](func, index);
+  };
+  Function['getNumLocals'] = function(func) {
+    return Module['_BinaryenFunctionGetNumLocals'](func);
+  };
+  Function['hasLocalName'] = function(func, index) {
+    return Boolean(Module['_BinaryenFunctionHasLocalName'](func, index));
+  };
+  Function['getLocalName'] = function(func, index) {
+    return UTF8ToString(Module['_BinaryenFunctionGetLocalName'](func, index));
+  };
+  Function['setLocalName'] = function(func, index, name) {
+    preserveStack(() => {
+      Module['_BinaryenFunctionSetLocalName'](func, index, strToStack(name));
+    });
+  };
+  Function['getBody'] = function(func) {
+    return Module['_BinaryenFunctionGetBody'](func);
+  };
+  Function['setBody'] = function(func, bodyExpr) {
+    Module['_BinaryenFunctionSetBody'](func, bodyExpr);
+  };
+  deriveWrapperInstanceMembers(Function.prototype, Function);
+  Function.prototype['valueOf'] = function() {
+    return this[thisPtr];
+  };
+  return Function;
+})();
+
+// Additional customizations
+
+Module['exit'] = function(status) {
+  // Instead of exiting silently on errors, always show an error with
+  // a stack trace, for debuggability.
+  if (status != 0) throw new Error('exiting due to error: ' + status);
+};
+
+// Indicates if Binaryen has been loaded and is ready
+Module['isReady'] = runtimeInitialized;
+
+// Provide a mechanism to tell when the module is ready
+//
+// if (!binaryen.isReady) await binaryen.ready;
+// ...
+//
+let pendingPromises = [];
+let initializeError = null;
+
+Object.defineProperty(Module, 'ready', {
+  get() {
+    return new Promise((resolve, reject) => {
+      if (initializeError) {
+        reject(initializeError);
+      } else if (runtimeInitialized) {
+        resolve(Module);
+      } else {
+        pendingPromises.push({ resolve, reject });
+      }
+    });
+  }
+});
+
+// Intercept the onRuntimeInitialized hook if necessary
+if (runtimeInitialized) {
+  initializeConstants();
+} else {
+  Module['onRuntimeInitialized'] = (super_ => () => {
+    try {
+      initializeConstants();
+      if (super_) super_();
+      Module['isReady'] = true;
+      pendingPromises.forEach(p => { p.resolve(Module) });
+    } catch (e) {
+      initializeError = e;
+      pendingPromises.forEach(p => { p.reject(e) });
+    } finally {
+      pendingPromises = [];
+    }
+  })(Module['onRuntimeInitialized']);
+}
diff --git a/binaryen/src/literal.h b/binaryen/src/literal.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/literal.h
@@ -0,0 +1,754 @@
+/*
+ * 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_literal_h
+#define wasm_literal_h
+
+#include <array>
+#include <iostream>
+
+#include "compiler-support.h"
+#include "support/hash.h"
+#include "support/name.h"
+#include "support/small_vector.h"
+#include "support/utilities.h"
+#include "wasm-type.h"
+
+namespace wasm {
+
+class Literals;
+struct ExceptionPackage;
+
+class Literal {
+  // store only integers, whose bits are deterministic. floats
+  // can have their signalling bit set, for example.
+  union {
+    int32_t i32;
+    int64_t i64;
+    uint8_t v128[16];
+    // funcref function name. `isNull()` indicates a `null` value.
+    Name func;
+    // exnref package. `nullptr` indicates a `null` value.
+    std::unique_ptr<ExceptionPackage> exn;
+    // 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
+    // 2) avoid bailing out when seeing a reference typed value in precompute
+  };
+
+public:
+  // Type of the literal. Immutable because the literal's payload depends on it.
+  const Type type;
+
+  Literal() : v128(), type(Type::none) {}
+  explicit Literal(Type type);
+  explicit Literal(Type::BasicID typeId) : Literal(Type(typeId)) {}
+  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) {}
+  explicit Literal(uint64_t init) : i64(init), type(Type::i64) {}
+  explicit Literal(float init)
+    : i32(bit_cast<int32_t>(init)), type(Type::f32) {}
+  explicit Literal(double init)
+    : i64(bit_cast<int64_t>(init)), type(Type::f64) {}
+  // v128 literal from bytes
+  explicit Literal(const uint8_t init[16]);
+  // v128 literal from lane value literals
+  explicit Literal(const std::array<Literal, 16>&);
+  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(std::unique_ptr<ExceptionPackage>&& exn)
+    : exn(std::move(exn)), type(Type::exnref) {}
+  Literal(const Literal& other);
+  Literal& operator=(const Literal& other);
+  ~Literal() {
+    if (type.isException()) {
+      exn.~unique_ptr();
+    }
+  }
+
+  bool isConcrete() const { return type != Type::none; }
+  bool isNone() const { return type == Type::none; }
+  bool isNull() const {
+    if (type.isNullable()) {
+      if (type.isFunction()) {
+        return func.isNull();
+      }
+      if (type.isException()) {
+        return !exn;
+      }
+      return true;
+    }
+    return false;
+  }
+  bool isZero() const {
+    switch (type.getBasic()) {
+      case Type::i32:
+        return i32 == 0;
+      case Type::i64:
+        return i64 == 0LL;
+      case Type::f32:
+        return bit_cast<float>(i32) == 0.0f;
+      case Type::f64:
+        return bit_cast<double>(i64) == 0.0;
+      case Type::v128: {
+        uint8_t zeros[16] = {0};
+        return memcmp(&v128, zeros, 16) == 0;
+      }
+      default:
+        WASM_UNREACHABLE("unexpected type");
+    }
+  }
+  bool isSignedMin() const {
+    switch (type.getBasic()) {
+      case Type::i32:
+        return i32 == std::numeric_limits<int32_t>::min();
+      case Type::i64:
+        return i64 == std::numeric_limits<int64_t>::min();
+      default:
+        WASM_UNREACHABLE("unexpected type");
+    }
+  }
+  bool isSignedMax() const {
+    switch (type.getBasic()) {
+      case Type::i32:
+        return i32 == std::numeric_limits<int32_t>::max();
+      case Type::i64:
+        return i64 == std::numeric_limits<int64_t>::max();
+      default:
+        WASM_UNREACHABLE("unexpected type");
+    }
+  }
+  bool isUnsignedMax() const {
+    switch (type.getBasic()) {
+      case Type::i32:
+        return uint32_t(i32) == std::numeric_limits<uint32_t>::max();
+      case Type::i64:
+        return uint64_t(i64) == std::numeric_limits<uint64_t>::max();
+      default:
+        WASM_UNREACHABLE("unexpected type");
+    }
+  }
+
+  static Literals makeZeros(Type type);
+  static Literals makeOnes(Type type);
+  static Literals makeNegOnes(Type type);
+  static Literal makeZero(Type type);
+  static Literal makeOne(Type type);
+  static Literal makeNegOne(Type type);
+  static Literal makeFromInt32(int32_t x, Type type) {
+    switch (type.getBasic()) {
+      case Type::i32:
+        return Literal(int32_t(x));
+      case Type::i64:
+        return Literal(int64_t(x));
+      case Type::f32:
+        return Literal(float(x));
+      case Type::f64:
+        return Literal(double(x));
+      case Type::v128:
+        return Literal(std::array<Literal, 4>{{Literal(x),
+                                               Literal(int32_t(0)),
+                                               Literal(int32_t(0)),
+                                               Literal(int32_t(0))}});
+      default:
+        WASM_UNREACHABLE("unexpected type");
+    }
+  }
+  static Literal makeFromInt64(int64_t x, Type type) {
+    switch (type.getBasic()) {
+      case Type::i32:
+        return Literal(int32_t(x));
+      case Type::i64:
+        return Literal(int64_t(x));
+      case Type::f32:
+        return Literal(float(x));
+      case Type::f64:
+        return Literal(double(x));
+      case Type::v128:
+        return Literal(
+          std::array<Literal, 2>{{Literal(x), Literal(int64_t(0))}});
+      default:
+        WASM_UNREACHABLE("unexpected type");
+    }
+  }
+  static Literal makeSignedMin(Type type) {
+    switch (type.getBasic()) {
+      case Type::i32:
+        return Literal(std::numeric_limits<int32_t>::min());
+      case Type::i64:
+        return Literal(std::numeric_limits<int64_t>::min());
+      default:
+        WASM_UNREACHABLE("unexpected type");
+    }
+  }
+  static Literal makeSignedMax(Type type) {
+    switch (type.getBasic()) {
+      case Type::i32:
+        return Literal(std::numeric_limits<int32_t>::max());
+      case Type::i64:
+        return Literal(std::numeric_limits<int64_t>::max());
+      default:
+        WASM_UNREACHABLE("unexpected type");
+    }
+  }
+  static Literal makeUnsignedMax(Type type) {
+    switch (type.getBasic()) {
+      case Type::i32:
+        return Literal(std::numeric_limits<uint32_t>::max());
+      case Type::i64:
+        return Literal(std::numeric_limits<uint64_t>::max());
+      default:
+        WASM_UNREACHABLE("unexpected type");
+    }
+  }
+  static Literal makeNull(Type type) {
+    assert(type.isNullable());
+    return Literal(type);
+  }
+  static Literal makeFunc(Name func) { return Literal(func.c_str()); }
+  static Literal makeExn(std::unique_ptr<ExceptionPackage>&& exn) {
+    return Literal(std::move(exn));
+  }
+  static Literal makeI31(int32_t value) {
+    auto lit = Literal(Type::i31ref);
+    lit.i32 = value & 0x7fffffff;
+    return lit;
+  }
+
+  Literal castToF32();
+  Literal castToF64();
+  Literal castToI32();
+  Literal castToI64();
+
+  int32_t geti32() const {
+    assert(type == Type::i32);
+    return i32;
+  }
+  int32_t geti31(bool signed_ = true) const {
+    assert(type == Type::i31ref);
+    return signed_ ? (i32 << 1) >> 1 : i32;
+  }
+  int64_t geti64() const {
+    assert(type == Type::i64);
+    return i64;
+  }
+  float getf32() const {
+    assert(type == Type::f32);
+    return bit_cast<float>(i32);
+  }
+  double getf64() const {
+    assert(type == Type::f64);
+    return bit_cast<double>(i64);
+  }
+  std::array<uint8_t, 16> getv128() const;
+  Name getFunc() const {
+    assert(type.isFunction() && !func.isNull());
+    return func;
+  }
+  ExceptionPackage getExceptionPackage() const;
+
+  // careful!
+  int32_t* geti32Ptr() {
+    assert(type == Type::i32);
+    return &i32;
+  }
+  uint8_t* getv128Ptr() {
+    assert(type == Type::v128);
+    return v128;
+  }
+  const uint8_t* getv128Ptr() const {
+    assert(type == Type::v128);
+    return v128;
+  }
+
+  int32_t reinterpreti32() const {
+    assert(type == Type::f32);
+    return i32;
+  }
+  int64_t reinterpreti64() const {
+    assert(type == Type::f64);
+    return i64;
+  }
+  float reinterpretf32() const {
+    assert(type == Type::i32);
+    return bit_cast<float>(i32);
+  }
+  double reinterpretf64() const {
+    assert(type == Type::i64);
+    return bit_cast<double>(i64);
+  }
+
+  int64_t getInteger() const;
+  uint64_t getUnsigned() const;
+  double getFloat() const;
+  // Obtains the bits of a basic value typed literal.
+  void getBits(uint8_t (&buf)[16]) const;
+  // Equality checks for the type and the bits, so a nan float would
+  // be compared bitwise (which means that a Literal containing a nan
+  // would be equal to itself, if the bits are equal).
+  bool operator==(const Literal& other) const;
+  bool operator!=(const Literal& other) const;
+
+  bool isNaN();
+
+  static uint32_t NaNPayload(float f);
+  static uint64_t NaNPayload(double f);
+  static float setQuietNaN(float f);
+  static double setQuietNaN(double f);
+
+  static void printFloat(std::ostream& o, float f);
+  static void printDouble(std::ostream& o, double d);
+  static void printVec128(std::ostream& o, const std::array<uint8_t, 16>& v);
+
+  Literal countLeadingZeroes() const;
+  Literal countTrailingZeroes() const;
+  Literal popCount() const;
+
+  Literal extendToSI64() const;
+  Literal extendToUI64() const;
+  Literal extendToF64() const;
+  Literal extendS8() const;
+  Literal extendS16() const;
+  Literal extendS32() const;
+  Literal wrapToI32() const;
+
+  Literal convertSIToF32() const;
+  Literal convertUIToF32() const;
+  Literal convertSIToF64() const;
+  Literal convertUIToF64() const;
+
+  Literal truncSatToSI32() const;
+  Literal truncSatToSI64() const;
+  Literal truncSatToUI32() const;
+  Literal truncSatToUI64() const;
+
+  Literal eqz() const;
+  Literal neg() const;
+  Literal abs() const;
+  Literal ceil() const;
+  Literal floor() const;
+  Literal trunc() const;
+  Literal nearbyint() const;
+  Literal sqrt() const;
+  Literal demote() const;
+
+  Literal add(const Literal& other) const;
+  Literal sub(const Literal& other) const;
+  Literal mul(const Literal& other) const;
+  Literal div(const Literal& other) const;
+  Literal divS(const Literal& other) const;
+  Literal divU(const Literal& other) const;
+  Literal remS(const Literal& other) const;
+  Literal remU(const Literal& other) const;
+  Literal and_(const Literal& other) const;
+  Literal or_(const Literal& other) const;
+  Literal xor_(const Literal& other) const;
+  Literal shl(const Literal& other) const;
+  Literal shrS(const Literal& other) const;
+  Literal shrU(const Literal& other) const;
+  Literal rotL(const Literal& other) const;
+  Literal rotR(const Literal& other) const;
+
+  // Note that these functions perform equality checks based
+  // on the type of the literal, so that (unlike the == operator)
+  // a float nan would not be identical to itself.
+  Literal eq(const Literal& other) const;
+  Literal ne(const Literal& other) const;
+  Literal ltS(const Literal& other) const;
+  Literal ltU(const Literal& other) const;
+  Literal lt(const Literal& other) const;
+  Literal leS(const Literal& other) const;
+  Literal leU(const Literal& other) const;
+  Literal le(const Literal& other) const;
+
+  Literal gtS(const Literal& other) const;
+  Literal gtU(const Literal& other) const;
+  Literal gt(const Literal& other) const;
+  Literal geS(const Literal& other) const;
+  Literal geU(const Literal& other) const;
+  Literal ge(const Literal& other) const;
+
+  Literal min(const Literal& other) const;
+  Literal max(const Literal& other) const;
+  Literal pmin(const Literal& other) const;
+  Literal pmax(const Literal& other) const;
+  Literal copysign(const Literal& other) const;
+
+  std::array<Literal, 16> getLanesSI8x16() const;
+  std::array<Literal, 16> getLanesUI8x16() const;
+  std::array<Literal, 8> getLanesSI16x8() const;
+  std::array<Literal, 8> getLanesUI16x8() const;
+  std::array<Literal, 4> getLanesI32x4() const;
+  std::array<Literal, 2> getLanesI64x2() const;
+  std::array<Literal, 4> getLanesF32x4() const;
+  std::array<Literal, 2> getLanesF64x2() const;
+
+  Literal shuffleV8x16(const Literal& other,
+                       const std::array<uint8_t, 16>& mask) const;
+  Literal splatI8x16() const;
+  Literal extractLaneSI8x16(uint8_t index) const;
+  Literal extractLaneUI8x16(uint8_t index) const;
+  Literal replaceLaneI8x16(const Literal& other, uint8_t index) const;
+  Literal splatI16x8() const;
+  Literal extractLaneSI16x8(uint8_t index) const;
+  Literal extractLaneUI16x8(uint8_t index) const;
+  Literal replaceLaneI16x8(const Literal& other, uint8_t index) const;
+  Literal splatI32x4() const;
+  Literal extractLaneI32x4(uint8_t index) const;
+  Literal replaceLaneI32x4(const Literal& other, uint8_t index) const;
+  Literal splatI64x2() const;
+  Literal extractLaneI64x2(uint8_t index) const;
+  Literal replaceLaneI64x2(const Literal& other, uint8_t index) const;
+  Literal splatF32x4() const;
+  Literal extractLaneF32x4(uint8_t index) const;
+  Literal replaceLaneF32x4(const Literal& other, uint8_t index) const;
+  Literal splatF64x2() const;
+  Literal extractLaneF64x2(uint8_t index) const;
+  Literal replaceLaneF64x2(const Literal& other, uint8_t index) const;
+  Literal eqI8x16(const Literal& other) const;
+  Literal neI8x16(const Literal& other) const;
+  Literal ltSI8x16(const Literal& other) const;
+  Literal ltUI8x16(const Literal& other) const;
+  Literal gtSI8x16(const Literal& other) const;
+  Literal gtUI8x16(const Literal& other) const;
+  Literal leSI8x16(const Literal& other) const;
+  Literal leUI8x16(const Literal& other) const;
+  Literal geSI8x16(const Literal& other) const;
+  Literal geUI8x16(const Literal& other) const;
+  Literal eqI16x8(const Literal& other) const;
+  Literal neI16x8(const Literal& other) const;
+  Literal ltSI16x8(const Literal& other) const;
+  Literal ltUI16x8(const Literal& other) const;
+  Literal gtSI16x8(const Literal& other) const;
+  Literal gtUI16x8(const Literal& other) const;
+  Literal leSI16x8(const Literal& other) const;
+  Literal leUI16x8(const Literal& other) const;
+  Literal geSI16x8(const Literal& other) const;
+  Literal geUI16x8(const Literal& other) const;
+  Literal eqI32x4(const Literal& other) const;
+  Literal neI32x4(const Literal& other) const;
+  Literal ltSI32x4(const Literal& other) const;
+  Literal ltUI32x4(const Literal& other) const;
+  Literal gtSI32x4(const Literal& other) const;
+  Literal gtUI32x4(const Literal& other) const;
+  Literal leSI32x4(const Literal& other) const;
+  Literal leUI32x4(const Literal& other) const;
+  Literal geSI32x4(const Literal& other) const;
+  Literal geUI32x4(const Literal& other) const;
+  Literal eqF32x4(const Literal& other) const;
+  Literal neF32x4(const Literal& other) const;
+  Literal ltF32x4(const Literal& other) const;
+  Literal gtF32x4(const Literal& other) const;
+  Literal leF32x4(const Literal& other) const;
+  Literal geF32x4(const Literal& other) const;
+  Literal eqF64x2(const Literal& other) const;
+  Literal neF64x2(const Literal& other) const;
+  Literal ltF64x2(const Literal& other) const;
+  Literal gtF64x2(const Literal& other) const;
+  Literal leF64x2(const Literal& other) const;
+  Literal geF64x2(const Literal& other) const;
+  Literal notV128() const;
+  Literal andV128(const Literal& other) const;
+  Literal orV128(const Literal& other) const;
+  Literal xorV128(const Literal& other) const;
+  Literal bitselectV128(const Literal& left, const Literal& right) const;
+  Literal absI8x16() const;
+  Literal negI8x16() const;
+  Literal anyTrueI8x16() const;
+  Literal allTrueI8x16() const;
+  Literal bitmaskI8x16() const;
+  Literal shlI8x16(const Literal& other) const;
+  Literal shrSI8x16(const Literal& other) const;
+  Literal shrUI8x16(const Literal& other) const;
+  Literal addI8x16(const Literal& other) const;
+  Literal addSaturateSI8x16(const Literal& other) const;
+  Literal addSaturateUI8x16(const Literal& other) const;
+  Literal subI8x16(const Literal& other) const;
+  Literal subSaturateSI8x16(const Literal& other) const;
+  Literal subSaturateUI8x16(const Literal& other) const;
+  Literal mulI8x16(const Literal& other) const;
+  Literal minSI8x16(const Literal& other) const;
+  Literal minUI8x16(const Literal& other) const;
+  Literal maxSI8x16(const Literal& other) const;
+  Literal maxUI8x16(const Literal& other) const;
+  Literal avgrUI8x16(const Literal& other) const;
+  Literal absI16x8() const;
+  Literal negI16x8() const;
+  Literal anyTrueI16x8() const;
+  Literal allTrueI16x8() const;
+  Literal bitmaskI16x8() const;
+  Literal shlI16x8(const Literal& other) const;
+  Literal shrSI16x8(const Literal& other) const;
+  Literal shrUI16x8(const Literal& other) const;
+  Literal addI16x8(const Literal& other) const;
+  Literal addSaturateSI16x8(const Literal& other) const;
+  Literal addSaturateUI16x8(const Literal& other) const;
+  Literal subI16x8(const Literal& other) const;
+  Literal subSaturateSI16x8(const Literal& other) const;
+  Literal subSaturateUI16x8(const Literal& other) const;
+  Literal mulI16x8(const Literal& other) const;
+  Literal minSI16x8(const Literal& other) const;
+  Literal minUI16x8(const Literal& other) const;
+  Literal maxSI16x8(const Literal& other) const;
+  Literal maxUI16x8(const Literal& other) const;
+  Literal avgrUI16x8(const Literal& other) const;
+  Literal absI32x4() const;
+  Literal negI32x4() const;
+  Literal anyTrueI32x4() const;
+  Literal allTrueI32x4() const;
+  Literal bitmaskI32x4() const;
+  Literal shlI32x4(const Literal& other) const;
+  Literal shrSI32x4(const Literal& other) const;
+  Literal shrUI32x4(const Literal& other) const;
+  Literal addI32x4(const Literal& other) const;
+  Literal subI32x4(const Literal& other) const;
+  Literal mulI32x4(const Literal& other) const;
+  Literal minSI32x4(const Literal& other) const;
+  Literal minUI32x4(const Literal& other) const;
+  Literal maxSI32x4(const Literal& other) const;
+  Literal maxUI32x4(const Literal& other) const;
+  Literal dotSI16x8toI32x4(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 absF32x4() const;
+  Literal negF32x4() const;
+  Literal sqrtF32x4() const;
+  Literal addF32x4(const Literal& other) const;
+  Literal subF32x4(const Literal& other) const;
+  Literal mulF32x4(const Literal& other) const;
+  Literal divF32x4(const Literal& other) const;
+  Literal minF32x4(const Literal& other) const;
+  Literal maxF32x4(const Literal& other) const;
+  Literal pminF32x4(const Literal& other) const;
+  Literal pmaxF32x4(const Literal& other) const;
+  Literal ceilF32x4() const;
+  Literal floorF32x4() const;
+  Literal truncF32x4() const;
+  Literal nearestF32x4() const;
+  Literal absF64x2() const;
+  Literal negF64x2() const;
+  Literal sqrtF64x2() const;
+  Literal addF64x2(const Literal& other) const;
+  Literal subF64x2(const Literal& other) const;
+  Literal mulF64x2(const Literal& other) const;
+  Literal divF64x2(const Literal& other) const;
+  Literal minF64x2(const Literal& other) const;
+  Literal maxF64x2(const Literal& other) const;
+  Literal pminF64x2(const Literal& other) const;
+  Literal pmaxF64x2(const Literal& other) const;
+  Literal ceilF64x2() const;
+  Literal floorF64x2() const;
+  Literal truncF64x2() const;
+  Literal nearestF64x2() const;
+  Literal truncSatToSI32x4() const;
+  Literal truncSatToUI32x4() const;
+  Literal truncSatToSI64x2() const;
+  Literal truncSatToUI64x2() const;
+  Literal convertSToF32x4() const;
+  Literal convertUToF32x4() const;
+  Literal convertSToF64x2() const;
+  Literal convertUToF64x2() const;
+  Literal narrowSToVecI8x16(const Literal& other) const;
+  Literal narrowUToVecI8x16(const Literal& other) const;
+  Literal narrowSToVecI16x8(const Literal& other) const;
+  Literal narrowUToVecI16x8(const Literal& other) const;
+  Literal widenLowSToVecI16x8() const;
+  Literal widenHighSToVecI16x8() const;
+  Literal widenLowUToVecI16x8() const;
+  Literal widenHighUToVecI16x8() const;
+  Literal widenLowSToVecI32x4() const;
+  Literal widenHighSToVecI32x4() const;
+  Literal widenLowUToVecI32x4() const;
+  Literal widenHighUToVecI32x4() const;
+  Literal swizzleVec8x16(const Literal& other) const;
+
+private:
+  Literal addSatSI8(const Literal& other) const;
+  Literal addSatUI8(const Literal& other) const;
+  Literal addSatSI16(const Literal& other) const;
+  Literal addSatUI16(const Literal& other) const;
+  Literal subSatSI8(const Literal& other) const;
+  Literal subSatUI8(const Literal& other) const;
+  Literal subSatSI16(const Literal& other) const;
+  Literal subSatUI16(const Literal& other) const;
+  Literal minInt(const Literal& other) const;
+  Literal maxInt(const Literal& other) const;
+  Literal minUInt(const Literal& other) const;
+  Literal maxUInt(const Literal& other) const;
+  Literal avgrUInt(const Literal& other) const;
+};
+
+class Literals : public SmallVector<Literal, 1> {
+public:
+  Literals() = default;
+  Literals(std::initializer_list<Literal> init)
+    : SmallVector<Literal, 1>(init) {
+#ifndef NDEBUG
+    for (auto& lit : init) {
+      assert(lit.isConcrete());
+    }
+#endif
+  };
+  Type getType() {
+    std::vector<Type> types;
+    for (auto& val : *this) {
+      types.push_back(val.type);
+    }
+    return Type(types);
+  }
+  bool isNone() { return size() == 0; }
+  bool isConcrete() { return size() != 0; }
+};
+
+// A struct for a thrown exception, which includes a tag (event) and thrown
+// values
+struct ExceptionPackage {
+  Name event;
+  Literals values;
+  bool operator==(const ExceptionPackage& other) const {
+    return event == other.event && values == other.values;
+  }
+  bool operator!=(const ExceptionPackage& other) const {
+    return !(*this == other);
+  }
+};
+
+std::ostream& operator<<(std::ostream& o, wasm::Literal literal);
+std::ostream& operator<<(std::ostream& o, wasm::Literals literals);
+std::ostream& operator<<(std::ostream& o, const ExceptionPackage& exn);
+
+} // namespace wasm
+
+namespace std {
+template<> struct hash<wasm::Literal> {
+  size_t operator()(const wasm::Literal& a) const {
+    auto digest = wasm::hash(a.type.getID());
+    auto hashRef = [&]() {
+      assert(a.type.isRef());
+      if (a.isNull()) {
+        return digest;
+      }
+      if (a.type.isFunction()) {
+        wasm::rehash(digest, a.getFunc());
+        return digest;
+      }
+      if (a.type.isException()) {
+        auto exn = a.getExceptionPackage();
+        wasm::rehash(digest, exn.event);
+        wasm::rehash(digest, exn.values);
+        return digest;
+      }
+      // other non-null reference type literals cannot represent concrete
+      // values, i.e. there is no concrete externref, anyref or eqref other than
+      // null.
+      WASM_UNREACHABLE("unexpected type");
+    };
+    if (a.type.isBasic()) {
+      switch (a.type.getBasic()) {
+        case wasm::Type::i32:
+          wasm::rehash(digest, a.geti32());
+          return digest;
+        case wasm::Type::f32:
+          wasm::rehash(digest, a.reinterpreti32());
+          return digest;
+        case wasm::Type::i64:
+          wasm::rehash(digest, a.geti64());
+          return digest;
+        case wasm::Type::f64:
+          wasm::rehash(digest, a.reinterpreti64());
+          return digest;
+        case wasm::Type::v128:
+          uint64_t chunks[2];
+          memcpy(&chunks, a.getv128Ptr(), 16);
+          wasm::rehash(digest, chunks[0]);
+          wasm::rehash(digest, chunks[1]);
+          return digest;
+        case wasm::Type::funcref:
+        case wasm::Type::externref:
+        case wasm::Type::exnref:
+        case wasm::Type::anyref:
+        case wasm::Type::eqref:
+          return hashRef();
+        case wasm::Type::i31ref:
+          wasm::rehash(digest, a.geti31(true));
+          return digest;
+        case wasm::Type::none:
+        case wasm::Type::unreachable:
+          break;
+      }
+    } else if (a.type.isRef()) {
+      return hashRef();
+    } else if (a.type.isRtt()) {
+      WASM_UNREACHABLE("TODO: rtt literals");
+    }
+    WASM_UNREACHABLE("unexpected type");
+  }
+};
+template<> struct hash<wasm::Literals> {
+  size_t operator()(const wasm::Literals& a) const {
+    auto digest = wasm::hash(a.size());
+    for (const auto& lit : a) {
+      wasm::rehash(digest, lit);
+    }
+    return digest;
+  }
+};
+template<> struct less<wasm::Literal> {
+  bool operator()(const wasm::Literal& a, const wasm::Literal& b) const {
+    if (a.type < b.type) {
+      return true;
+    }
+    if (b.type < a.type) {
+      return false;
+    }
+    TODO_SINGLE_COMPOUND(a.type);
+    switch (a.type.getBasic()) {
+      case wasm::Type::i32:
+        return a.geti32() < b.geti32();
+      case wasm::Type::f32:
+        return a.reinterpreti32() < b.reinterpreti32();
+      case wasm::Type::i64:
+        return a.geti64() < b.geti64();
+      case wasm::Type::f64:
+        return a.reinterpreti64() < b.reinterpreti64();
+      case wasm::Type::v128:
+        return memcmp(a.getv128Ptr(), b.getv128Ptr(), 16) < 0;
+      case wasm::Type::funcref:
+      case wasm::Type::externref:
+      case wasm::Type::exnref:
+      case wasm::Type::anyref:
+      case wasm::Type::eqref:
+      case wasm::Type::i31ref:
+      case wasm::Type::none:
+      case wasm::Type::unreachable:
+        return false;
+    }
+    WASM_UNREACHABLE("unexpected type");
+  }
+};
+} // namespace std
+
+#endif // wasm_literal_h
diff --git a/binaryen/src/mixed_arena.h b/binaryen/src/mixed_arena.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/mixed_arena.h
@@ -0,0 +1,415 @@
+/*
+ * Copyright 2015 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_mixed_arena_h
+#define wasm_mixed_arena_h
+
+#include <atomic>
+#include <cassert>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <type_traits>
+#include <vector>
+
+#include <support/alloc.h>
+
+//
+// Arena allocation for mixed-type data.
+//
+// Arena-style bump allocation is important for two reasons: First, so that
+// allocation is quick, and second, so that allocated items are close together,
+// which is cache-friendy. Arena allocation is also useful for a minor third
+// reason which is to make freeing all the items in an arena very quick.
+//
+// Each WebAssembly Module has an arena allocator, which should be used
+// for all of its AST nodes and so forth. When the Module is destroyed, the
+// entire arena is cleaned up.
+//
+// When allocating an object in an arena, the object's proper constructor
+// is called. Note that destructors are not called, because to make the
+// arena simple and fast we do not track internal allocations inside it
+// (and we can also avoid the need for virtual destructors).
+//
+// In general, optimization passes avoid allocation as much as possible.
+// Many passes only remove or modify nodes anyhow, others can often
+// reuse nodes that are being optimized out. This keeps things
+// cache-friendly, and also makes the operations trivially thread-safe.
+// In the rare case that a pass does need to allocate, and it is a
+// parallel pass (so multiple threads might access the allocator),
+// the MixedArena instance will notice if it is on a different thread
+// than that arena's original thread, and will perform the allocation
+// in a side arena for that other thread. This is done in a transparent
+// way to the outside; as a result, it is always safe to allocate using
+// a MixedArena, no matter which thread you are on. Allocations will
+// of course be fastest on the original thread for the arena.
+//
+
+struct MixedArena {
+  // fast bump allocation
+
+  static const size_t CHUNK_SIZE = 32768;
+  static const size_t MAX_ALIGN = 16; // allow 128bit SIMD
+
+  // Each pointer in chunks is to a multiple of CHUNK_SIZE - typically 1,
+  // but possibly more.
+  std::vector<void*> chunks;
+
+  size_t index = 0; // in last chunk
+
+  std::thread::id threadId;
+
+  // multithreaded allocation - each arena is valid on a specific thread.
+  // if we are on the wrong thread, we atomically look in the linked
+  // list of next, adding an allocator if necessary
+  std::atomic<MixedArena*> next;
+
+  MixedArena() {
+    threadId = std::this_thread::get_id();
+    next.store(nullptr);
+  }
+
+  // Allocate an amount of space with a guaranteed alignment
+  void* allocSpace(size_t size, size_t align) {
+    // the bump allocator data should not be modified by multiple threads at
+    // once.
+    auto myId = std::this_thread::get_id();
+    if (myId != threadId) {
+      MixedArena* curr = this;
+      MixedArena* allocated = nullptr;
+      while (myId != curr->threadId) {
+        auto seen = curr->next.load();
+        if (seen) {
+          curr = seen;
+          continue;
+        }
+        // there is a nullptr for next, so we may be able to place a new
+        // allocator for us there. but carefully, as others may do so as
+        // well. we may waste a few allocations here, but it doesn't matter
+        // as this can only happen as the chain is built up, i.e.,
+        // O(# of cores) per allocator, and our allocatrs are long-lived.
+        if (!allocated) {
+          allocated = new MixedArena(); // has our thread id
+        }
+        if (curr->next.compare_exchange_weak(seen, allocated)) {
+          // we replaced it, so we are the next in the chain
+          // we can forget about allocated, it is owned by the chain now
+          allocated = nullptr;
+          break;
+        }
+        // otherwise, the cmpxchg updated seen, and we continue to loop
+        curr = seen;
+      }
+      if (allocated) {
+        delete allocated;
+      }
+      return curr->allocSpace(size, align);
+    }
+    // First, move the current index in the last chunk to an aligned position.
+    index = (index + align - 1) & (-align);
+    if (index + size > CHUNK_SIZE || chunks.size() == 0) {
+      // Allocate a new chunk.
+      auto numChunks = (size + CHUNK_SIZE - 1) / CHUNK_SIZE;
+      assert(size <= numChunks * CHUNK_SIZE);
+      auto* allocation =
+        wasm::aligned_malloc(MAX_ALIGN, numChunks * CHUNK_SIZE);
+      if (!allocation) {
+        abort();
+      }
+      chunks.push_back(allocation);
+      index = 0;
+    }
+    uint8_t* ret = static_cast<uint8_t*>(chunks.back());
+    ret += index;
+    index += size; // TODO: if we allocated more than 1 chunk, reuse the
+                   // remainder, right now we allocate another next time
+    return static_cast<void*>(ret);
+  }
+
+  template<class T> T* alloc() {
+    static_assert(alignof(T) <= MAX_ALIGN,
+                  "maximum alignment not large enough");
+    auto* ret = static_cast<T*>(allocSpace(sizeof(T), alignof(T)));
+    new (ret) T(*this); // allocated objects receive the allocator, so they can
+                        // allocate more later if necessary
+    return ret;
+  }
+
+  void clear() {
+    for (auto* chunk : chunks) {
+      wasm::aligned_free(chunk);
+    }
+    chunks.clear();
+  }
+
+  ~MixedArena() {
+    clear();
+    if (next.load()) {
+      delete next.load();
+    }
+  }
+};
+
+//
+// A vector that allocates in an arena.
+//
+// TODO: specialize on the initial size of the array
+
+template<typename SubType, typename T> class ArenaVectorBase {
+protected:
+  T* data = nullptr;
+  size_t usedElements = 0, allocatedElements = 0;
+
+  void reallocate(size_t size) {
+    T* old = data;
+    static_cast<SubType*>(this)->allocate(size);
+    for (size_t i = 0; i < usedElements; i++) {
+      data[i] = old[i];
+    }
+  }
+
+public:
+  struct Iterator;
+
+  T& operator[](size_t index) const {
+    assert(index < usedElements);
+    return data[index];
+  }
+
+  size_t size() const { return usedElements; }
+
+  bool empty() const { return size() == 0; }
+
+  void resize(size_t size) {
+    if (size > allocatedElements) {
+      reallocate(size);
+    }
+    // construct new elements
+    for (size_t i = usedElements; i < size; i++) {
+      new (data + i) T();
+    }
+    usedElements = size;
+  }
+
+  T& back() const {
+    assert(usedElements > 0);
+    return data[usedElements - 1];
+  }
+
+  T& pop_back() {
+    assert(usedElements > 0);
+    usedElements--;
+    return data[usedElements];
+  }
+
+  void push_back(T item) {
+    if (usedElements == allocatedElements) {
+      reallocate((allocatedElements + 1) * 2); // TODO: optimize
+    }
+    data[usedElements] = item;
+    usedElements++;
+  }
+
+  T& front() const {
+    assert(usedElements > 0);
+    return data[0];
+  }
+
+  void erase(Iterator start_it, Iterator end_it) {
+    assert(start_it.parent == end_it.parent && start_it.parent == this);
+    assert(start_it.index <= end_it.index && end_it.index <= usedElements);
+    size_t size = end_it.index - start_it.index;
+    for (size_t cur = start_it.index; cur + size < usedElements; ++cur) {
+      data[cur] = data[cur + size];
+    }
+    usedElements -= size;
+  }
+
+  void erase(Iterator it) { erase(it, it + 1); }
+
+  void clear() { usedElements = 0; }
+
+  void reserve(size_t size) {
+    if (size > allocatedElements) {
+      reallocate(size);
+    }
+  }
+
+  template<typename ListType> void set(const ListType& list) {
+    size_t size = list.size();
+    if (allocatedElements < size) {
+      static_cast<SubType*>(this)->allocate(size);
+    }
+    for (size_t i = 0; i < size; i++) {
+      data[i] = list[i];
+    }
+    usedElements = size;
+  }
+
+  void operator=(SubType& other) { set(other); }
+
+  void swap(SubType& other) {
+    data = other.data;
+    usedElements = other.usedElements;
+    allocatedElements = other.allocatedElements;
+
+    other.data = nullptr;
+    other.usedElements = other.allocatedElements = 0;
+  }
+
+  // iteration
+
+  struct Iterator {
+    using iterator_category = std::random_access_iterator_tag;
+    using value_type = T;
+    using difference_type = std::ptrdiff_t;
+    using pointer = T*;
+    using reference = T&;
+
+    const SubType* parent;
+    size_t index;
+
+    Iterator() : parent(nullptr), index(0) {}
+    Iterator(const SubType* parent, size_t index)
+      : parent(parent), index(index) {}
+
+    bool operator==(const Iterator& other) const {
+      return index == other.index && parent == other.parent;
+    }
+
+    bool operator!=(const Iterator& other) const { return !(*this == other); }
+
+    bool operator<(const Iterator& other) const {
+      assert(parent == other.parent);
+      return index < other.index;
+    }
+
+    bool operator>(const Iterator& other) const { return other < *this; }
+
+    bool operator<=(const Iterator& other) const { return !(other < *this); }
+
+    bool operator>=(const Iterator& other) const { return !(*this < other); }
+
+    Iterator& operator++() {
+      index++;
+      return *this;
+    }
+
+    Iterator& operator--() {
+      index--;
+      return *this;
+    }
+
+    Iterator operator++(int) {
+      Iterator it = *this;
+      ++*this;
+      return it;
+    }
+
+    Iterator operator--(int) {
+      Iterator it = *this;
+      --*this;
+      return it;
+    }
+
+    Iterator& operator+=(std::ptrdiff_t off) {
+      index += off;
+      return *this;
+    }
+
+    Iterator& operator-=(std::ptrdiff_t off) { return *this += -off; }
+
+    Iterator operator+(std::ptrdiff_t off) const {
+      return Iterator(*this) += off;
+    }
+
+    Iterator operator-(std::ptrdiff_t off) const { return *this + -off; }
+
+    std::ptrdiff_t operator-(const Iterator& other) const {
+      assert(parent == other.parent);
+      return index - other.index;
+    }
+
+    friend Iterator operator+(std::ptrdiff_t off, const Iterator& it) {
+      return it + off;
+    }
+
+    T& operator*() const { return (*parent)[index]; }
+
+    T& operator[](std::ptrdiff_t off) const { return (*parent)[index + off]; }
+
+    T* operator->() const { return &(*parent)[index]; }
+  };
+
+  Iterator begin() const {
+    return Iterator(static_cast<const SubType*>(this), 0);
+  }
+  Iterator end() const {
+    return Iterator(static_cast<const SubType*>(this), usedElements);
+  }
+
+  void allocate(size_t size) {
+    abort(); // must be implemented in children
+  }
+
+  // C-API
+
+  void insertAt(size_t index, T item) {
+    assert(index <= usedElements); // appending is ok
+    resize(usedElements + 1);
+    for (auto i = usedElements; i > index; --i) {
+      data[i] = data[i - 1];
+    }
+    data[index] = item;
+  }
+
+  T removeAt(size_t index) {
+    assert(index < usedElements);
+    auto item = data[index];
+    for (auto i = index; i < usedElements - 1; ++i) {
+      data[i] = data[i + 1];
+    }
+    resize(usedElements - 1);
+    return item;
+  }
+};
+
+// A vector that has an allocator for arena allocation
+//
+// TODO: consider not saving the allocator, but requiring it be
+//       passed in when needed, would make this (and thus Blocks etc.
+//       smaller)
+
+template<typename T>
+class ArenaVector : public ArenaVectorBase<ArenaVector<T>, T> {
+private:
+  MixedArena& allocator;
+
+public:
+  ArenaVector(MixedArena& allocator) : allocator(allocator) {}
+
+  ArenaVector(ArenaVector<T>&& other) : allocator(other.allocator) {
+    *this = other;
+  }
+
+  void allocate(size_t size) {
+    this->allocatedElements = size;
+    this->data = static_cast<T*>(
+      allocator.allocSpace(sizeof(T) * this->allocatedElements, alignof(T)));
+  }
+};
+
+#endif // wasm_mixed_arena_h
diff --git a/binaryen/src/parsing.h b/binaryen/src/parsing.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/parsing.h
@@ -0,0 +1,397 @@
+/*
+ * Copyright 2015 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_parsing_h
+#define wasm_parsing_h
+
+#include <cmath>
+#include <ostream>
+#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.h"
+
+namespace wasm {
+
+struct ParseException {
+  std::string text;
+  size_t line, col;
+
+  ParseException() : text("unknown parse error"), line(-1), col(-1) {}
+  ParseException(std::string text) : text(text), line(-1), col(-1) {}
+  ParseException(std::string text, size_t line, size_t col)
+    : text(text), line(line), col(col) {}
+
+  void dump(std::ostream& o) const {
+    Colors::magenta(o);
+    o << "[";
+    Colors::red(o);
+    o << "parse exception: ";
+    Colors::green(o);
+    o << text;
+    if (line != size_t(-1)) {
+      Colors::normal(o);
+      o << " (at " << line << ":" << col << ")";
+    }
+    Colors::magenta(o);
+    o << "]";
+    Colors::normal(o);
+  }
+};
+
+struct MapParseException {
+  std::string text;
+
+  MapParseException() : text("unknown parse error") {}
+  MapParseException(std::string text) : text(text) {}
+
+  void dump(std::ostream& o) const {
+    Colors::magenta(o);
+    o << "[";
+    Colors::red(o);
+    o << "map parse exception: ";
+    Colors::green(o);
+    o << text;
+    Colors::magenta(o);
+    o << "]";
+    Colors::normal(o);
+  }
+};
+
+inline Expression*
+parseConst(cashew::IString s, Type type, MixedArena& allocator) {
+  const char* str = s.str;
+  auto ret = allocator.alloc<Const>();
+  ret->type = type;
+  if (type.isFloat()) {
+    if (s == _INFINITY) {
+      switch (type.getBasic()) {
+        case Type::f32:
+          ret->value = Literal(std::numeric_limits<float>::infinity());
+          break;
+        case Type::f64:
+          ret->value = Literal(std::numeric_limits<double>::infinity());
+          break;
+        default:
+          return nullptr;
+      }
+      // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
+      return ret;
+    }
+    if (s == NEG_INFINITY) {
+      switch (type.getBasic()) {
+        case Type::f32:
+          ret->value = Literal(-std::numeric_limits<float>::infinity());
+          break;
+        case Type::f64:
+          ret->value = Literal(-std::numeric_limits<double>::infinity());
+          break;
+        default:
+          return nullptr;
+      }
+      // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
+      return ret;
+    }
+    if (s == _NAN) {
+      switch (type.getBasic()) {
+        case Type::f32:
+          ret->value = Literal(float(std::nan("")));
+          break;
+        case Type::f64:
+          ret->value = Literal(double(std::nan("")));
+          break;
+        default:
+          return nullptr;
+      }
+      // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
+      return ret;
+    }
+    bool negative = str[0] == '-';
+    const char* positive = negative ? str + 1 : str;
+    if (!negative) {
+      if (positive[0] == '+') {
+        positive++;
+      }
+    }
+    if (positive[0] == 'n' && positive[1] == 'a' && positive[2] == 'n') {
+      const char* modifier = positive[3] == ':' ? positive + 4 : nullptr;
+      if (!(modifier ? positive[4] == '0' && positive[5] == 'x' : 1)) {
+        throw ParseException("bad nan input");
+      }
+      switch (type.getBasic()) {
+        case Type::f32: {
+          uint32_t pattern;
+          if (modifier) {
+            std::istringstream istr(modifier);
+            istr >> std::hex >> pattern;
+            if (istr.fail()) {
+              throw ParseException("invalid f32 format");
+            }
+            pattern |= 0x7f800000U;
+          } else {
+            pattern = 0x7fc00000U;
+          }
+          if (negative) {
+            pattern |= 0x80000000U;
+          }
+          if (!std::isnan(bit_cast<float>(pattern))) {
+            pattern |= 1U;
+          }
+          ret->value = Literal(pattern).castToF32();
+          break;
+        }
+        case Type::f64: {
+          uint64_t pattern;
+          if (modifier) {
+            std::istringstream istr(modifier);
+            istr >> std::hex >> pattern;
+            if (istr.fail()) {
+              throw ParseException("invalid f64 format");
+            }
+            pattern |= 0x7ff0000000000000ULL;
+          } else {
+            pattern = 0x7ff8000000000000UL;
+          }
+          if (negative) {
+            pattern |= 0x8000000000000000ULL;
+          }
+          if (!std::isnan(bit_cast<double>(pattern))) {
+            pattern |= 1ULL;
+          }
+          ret->value = Literal(pattern).castToF64();
+          break;
+        }
+        default:
+          return nullptr;
+      }
+      // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
+      return ret;
+    }
+    if (s == NEG_NAN) {
+      switch (type.getBasic()) {
+        case Type::f32:
+          ret->value = Literal(float(-std::nan("")));
+          break;
+        case Type::f64:
+          ret->value = Literal(double(-std::nan("")));
+          break;
+        default:
+          return nullptr;
+      }
+      // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
+      return ret;
+    }
+  }
+  switch (type.getBasic()) {
+    case Type::i32: {
+      if ((str[0] == '0' && str[1] == 'x') ||
+          (str[0] == '-' && str[1] == '0' && str[2] == 'x')) {
+        bool negative = str[0] == '-';
+        if (negative) {
+          str++;
+        }
+        std::istringstream istr(str);
+        uint32_t temp;
+        istr >> std::hex >> temp;
+        if (istr.fail()) {
+          throw ParseException("invalid i32 format");
+        }
+        ret->value = Literal(negative ? -temp : temp);
+      } else {
+        std::istringstream istr(str[0] == '-' ? str + 1 : str);
+        uint32_t temp;
+        istr >> temp;
+        if (istr.fail()) {
+          throw ParseException("invalid i32 format");
+        }
+        ret->value = Literal(str[0] == '-' ? -temp : temp);
+      }
+      break;
+    }
+    case Type::i64: {
+      if ((str[0] == '0' && str[1] == 'x') ||
+          (str[0] == '-' && str[1] == '0' && str[2] == 'x')) {
+        bool negative = str[0] == '-';
+        if (negative) {
+          str++;
+        }
+        std::istringstream istr(str);
+        uint64_t temp;
+        istr >> std::hex >> temp;
+        if (istr.fail()) {
+          throw ParseException("invalid i64 format");
+        }
+        ret->value = Literal(negative ? -temp : temp);
+      } else {
+        std::istringstream istr(str[0] == '-' ? str + 1 : str);
+        uint64_t temp;
+        istr >> temp;
+        if (istr.fail()) {
+          throw ParseException("invalid i64 format");
+        }
+        ret->value = Literal(str[0] == '-' ? -temp : temp);
+      }
+      break;
+    }
+    case Type::f32: {
+      char* end;
+      ret->value = Literal(strtof(str, &end));
+      break;
+    }
+    case Type::f64: {
+      char* end;
+      ret->value = Literal(strtod(str, &end));
+      break;
+    }
+    case Type::v128:
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+      WASM_UNREACHABLE("unexpected const type");
+    case Type::none:
+    case Type::unreachable: {
+      return nullptr;
+    }
+  }
+  if (ret->value.type != type) {
+    throw ParseException("parsed type does not match expected type");
+  }
+  // std::cerr << "make constant " << str << " ==> " << ret->value << '\n';
+  return ret;
+}
+
+// Helper for parsers that may not have unique label names. This transforms
+// the names into unique ones, as required by Binaryen IR.
+struct UniqueNameMapper {
+  std::vector<Name> labelStack;
+  // name in source => stack of uniquified names
+  std::map<Name, std::vector<Name>> labelMappings;
+  std::map<Name, Name> reverseLabelMapping; // uniquified name => name in source
+
+  Index otherIndex = 0;
+
+  Name getPrefixedName(Name prefix) {
+    if (reverseLabelMapping.find(prefix) == reverseLabelMapping.end()) {
+      return prefix;
+    }
+    // make sure to return a unique name not already on the stack
+    while (1) {
+      Name ret = Name(prefix.str + std::to_string(otherIndex++));
+      if (reverseLabelMapping.find(ret) == reverseLabelMapping.end()) {
+        return ret;
+      }
+    }
+  }
+
+  // receives a source name. generates a unique name, pushes it, and returns it
+  Name pushLabelName(Name sName) {
+    Name name = getPrefixedName(sName);
+    labelStack.push_back(name);
+    labelMappings[sName].push_back(name);
+    reverseLabelMapping[name] = sName;
+    return name;
+  }
+
+  void popLabelName(Name name) {
+    assert(labelStack.back() == name);
+    labelStack.pop_back();
+    labelMappings[reverseLabelMapping[name]].pop_back();
+  }
+
+  Name sourceToUnique(Name sName) {
+    if (labelMappings.find(sName) == labelMappings.end()) {
+      throw ParseException("bad label in sourceToUnique");
+    }
+    if (labelMappings[sName].empty()) {
+      throw ParseException("use of popped label in sourceToUnique");
+    }
+    return labelMappings[sName].back();
+  }
+
+  Name uniqueToSource(Name name) {
+    if (reverseLabelMapping.find(name) == reverseLabelMapping.end()) {
+      throw ParseException("label mismatch in uniqueToSource");
+    }
+    return reverseLabelMapping[name];
+  }
+
+  void clear() {
+    labelStack.clear();
+    labelMappings.clear();
+    reverseLabelMapping.clear();
+  }
+
+  // Given an expression, ensures all names are unique
+  static void uniquify(Expression* curr) {
+    struct Walker : public ControlFlowWalker<Walker, Visitor<Walker>> {
+      UniqueNameMapper mapper;
+
+      static void doPreVisitControlFlow(Walker* self, Expression** currp) {
+        auto* curr = *currp;
+        if (auto* block = curr->dynCast<Block>()) {
+          if (block->name.is()) {
+            block->name = self->mapper.pushLabelName(block->name);
+          }
+        } else if (auto* loop = curr->dynCast<Loop>()) {
+          if (loop->name.is()) {
+            loop->name = self->mapper.pushLabelName(loop->name);
+          }
+        }
+      }
+      static void doPostVisitControlFlow(Walker* self, Expression** currp) {
+        auto* curr = *currp;
+        if (auto* block = curr->dynCast<Block>()) {
+          if (block->name.is()) {
+            self->mapper.popLabelName(block->name);
+          }
+        } else if (auto* loop = curr->dynCast<Loop>()) {
+          if (loop->name.is()) {
+            self->mapper.popLabelName(loop->name);
+          }
+        }
+      }
+
+      void visitBreak(Break* curr) {
+        curr->name = mapper.sourceToUnique(curr->name);
+      }
+      void visitBrOnExn(BrOnExn* curr) {
+        curr->name = mapper.sourceToUnique(curr->name);
+      }
+      void visitSwitch(Switch* curr) {
+        for (auto& target : curr->targets) {
+          target = mapper.sourceToUnique(target);
+        }
+        curr->default_ = mapper.sourceToUnique(curr->default_);
+      }
+    };
+
+    Walker walker;
+    walker.walk(curr);
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_parsing_h
diff --git a/binaryen/src/pass.h b/binaryen/src/pass.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/pass.h
@@ -0,0 +1,360 @@
+/*
+ * Copyright 2015 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_pass_h
+#define wasm_pass_h
+
+#include <functional>
+
+#include "mixed_arena.h"
+#include "support/utilities.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
+
+namespace wasm {
+
+class Pass;
+
+//
+// Global registry of all passes in /passes/
+//
+struct PassRegistry {
+  PassRegistry();
+
+  static PassRegistry* get();
+
+  typedef std::function<Pass*()> Creator;
+
+  void registerPass(const char* name, const char* description, Creator create);
+  std::unique_ptr<Pass> createPass(std::string name);
+  std::vector<std::string> getRegisteredNames();
+  std::string getPassDescription(std::string name);
+
+private:
+  void registerPasses();
+
+  struct PassInfo {
+    std::string description;
+    Creator create;
+    PassInfo() = default;
+    PassInfo(std::string description, Creator create)
+      : description(description), create(create) {}
+  };
+  std::map<std::string, PassInfo> passInfos;
+};
+
+struct InliningOptions {
+  // Function size at which we always inline.
+  // Typically a size so small that after optimizations, the inlined code will
+  // be smaller than the call instruction itself. 2 is a safe number because
+  // there is no risk of things like
+  //  (func $reverse (param $x i32) (param $y i32)
+  //   (call $something (local.get $y) (local.get $x))
+  //  )
+  // in which case the reversing of the params means we'll possibly need
+  // a block and a temp local. But that takes at least 3 nodes, and 2 < 3.
+  // 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;
+  // 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;
+};
+
+struct PassOptions {
+  // Run passes in debug mode, doing extra validation and timing checks.
+  bool debug = false;
+  // Whether to run the validator to check for errors.
+  bool validate = true;
+  // When validating validate globally and not just locally
+  bool validateGlobally = false;
+  // 0, 1, 2 correspond to -O0, -O1, -O2, etc.
+  int optimizeLevel = 0;
+  // 0, 1, 2 correspond to -O0, -Os, -Oz
+  int shrinkLevel = 0;
+  // Tweak thresholds for the Inlining pass.
+  InliningOptions inlining;
+  // Optimize assuming things like div by 0, bad load/store, will not trap.
+  bool ignoreImplicitTraps = false;
+  // Optimize assuming that the low 1K of memory is not valid memory for the
+  // application to use. In that case, we can optimize load/store offsets in
+  // many cases.
+  bool lowMemoryUnused = false;
+  enum { LowMemoryBound = 1024 };
+  // Whether to allow "loose" math semantics, ignoring corner cases with NaNs
+  // and assuming math follows the algebraic rules for associativity and so
+  // forth (which IEEE floats do not, strictly speaking). This is inspired by
+  // gcc/clang's -ffast-math flag.
+  bool fastMath = 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
+  // passes.
+  std::map<std::string, std::string> arguments;
+
+  void setDefaultOptimizationOptions() {
+    // -Os is our default
+    optimizeLevel = 2;
+    shrinkLevel = 1;
+  }
+
+  static PassOptions getWithDefaultOptimizationOptions() {
+    PassOptions ret;
+    ret.setDefaultOptimizationOptions();
+    return ret;
+  }
+
+  static PassOptions getWithoutOptimization() {
+    return PassOptions(); // defaults are to not optimize
+  }
+
+  std::string getArgument(std::string key, std::string errorTextIfMissing) {
+    if (arguments.count(key) == 0) {
+      Fatal() << errorTextIfMissing;
+    }
+    return arguments[key];
+  }
+
+  std::string getArgumentOrDefault(std::string key, std::string default_) {
+    if (arguments.count(key) == 0) {
+      return default_;
+    }
+    return arguments[key];
+  }
+};
+
+//
+// Runs a set of passes, in order
+//
+struct PassRunner {
+  Module* wasm;
+  MixedArena* allocator;
+  std::vector<std::unique_ptr<Pass>> passes;
+  PassOptions options;
+
+  PassRunner(Module* wasm) : wasm(wasm), allocator(&wasm->allocator) {}
+  PassRunner(Module* wasm, PassOptions options)
+    : wasm(wasm), allocator(&wasm->allocator), options(options) {}
+
+  // no copying, we control |passes|
+  PassRunner(const PassRunner&) = delete;
+  PassRunner& operator=(const PassRunner&) = delete;
+
+  void setDebug(bool debug) {
+    options.debug = debug;
+    // validate everything by default if debugging
+    options.validateGlobally = debug;
+  }
+  void setDebugInfo(bool debugInfo) { options.debugInfo = debugInfo; }
+  void setValidateGlobally(bool validate) {
+    options.validateGlobally = validate;
+  }
+
+  // Add a pass using its name.
+  void add(std::string passName) {
+    auto pass = PassRegistry::get()->createPass(passName);
+    if (!pass) {
+      Fatal() << "Could not find pass: " << passName << "\n";
+    }
+    doAdd(std::move(pass));
+  }
+
+  // Add a pass given an instance.
+  template<class P> void add(std::unique_ptr<P> pass) {
+    doAdd(std::move(pass));
+  }
+
+  // Adds the default set of optimization passes; this is
+  // what -O does.
+  void addDefaultOptimizationPasses();
+
+  // Adds the default optimization passes that work on
+  // individual functions.
+  void addDefaultFunctionOptimizationPasses();
+
+  // Adds the default optimization passes that work on
+  // entire modules as a whole, and make sense to
+  // run before function passes.
+  void addDefaultGlobalOptimizationPrePasses();
+
+  // Adds the default optimization passes that work on
+  // entire modules as a whole, and make sense to
+  // run after function passes.
+  // This is run at the very end of the optimization
+  // process - you can assume no other opts will be run
+  // afterwards.
+  void addDefaultGlobalOptimizationPostPasses();
+
+  // Run the passes on the module
+  void run();
+
+  // Run the passes on a specific function
+  void runOnFunction(Function* func);
+
+  // Get the last pass that was already executed of a certain type.
+  template<class P> P* getLast();
+
+  // When running a pass runner within another pass runner, this
+  // flag should be set. This influences how pass debugging works,
+  // and may influence other things in the future too.
+  void setIsNested(bool nested) { isNested = nested; }
+
+  // BINARYEN_PASS_DEBUG is a convenient commandline way to log out the toplevel
+  //                     passes, their times, and validate between each pass.
+  //                     (we don't recurse pass debug into sub-passes, as it
+  //                     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
+  static int getPassDebug();
+
+protected:
+  bool isNested = false;
+
+private:
+  void doAdd(std::unique_ptr<Pass> pass);
+
+  void runPass(Pass* pass);
+  void runPassOnFunction(Pass* pass, Function* func);
+
+  // After running a pass, handle any changes due to
+  // how the pass is defined, such as clearing away any
+  // temporary data structures that the pass declares it
+  // invalidates.
+  // If a function is passed, we operate just on that function;
+  // otherwise, the whole module.
+  void handleAfterEffects(Pass* pass, Function* func = nullptr);
+};
+
+//
+// Core pass class
+//
+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) {
+    WASM_UNREACHABLE("unimplemented");
+  }
+
+  // Implement this with code to run the pass on a single function, for
+  // a function-parallel pass
+  virtual void
+  runOnFunction(PassRunner* runner, Module* module, Function* function) {
+    WASM_UNREACHABLE("unimplemented");
+  }
+
+  // Function parallelism. By default, passes are not run in parallel, but you
+  // can override this method to say that functions are parallelizable. This
+  // should always be safe *unless* you do something in the pass that makes it
+  // not thread-safe; in other words, the Module and Function objects and
+  // so forth are set up so that Functions can be processed in parallel, so
+  // if you do not add global state that could be raced on, your pass could be
+  // function-parallel.
+  //
+  // Function-parallel passes create an instance of the Walker class per
+  // function. That means that you can't rely on Walker object properties to
+  // persist across your functions, and you can't expect a new object to be
+  // created for each function either (which could be very inefficient).
+  //
+  // It is valid for function-parallel passes to read (but not modify) global
+  // module state, like globals or imports. However, reading other functions'
+  // contents is invalid, as function-parallel tests can be run while still
+  // adding functions to the module.
+  virtual bool isFunctionParallel() { return false; }
+
+  // This method is used to create instances per function for a
+  // function-parallel pass. You may need to override this if you subclass a
+  // Walker, as otherwise this will create the parent class.
+  virtual Pass* create() { WASM_UNREACHABLE("unimplenented"); }
+
+  // Whether this pass modifies the Binaryen IR in the module. This is true for
+  // most passes, except for passes that have no side effects, or passes that
+  // only modify other things than Binaryen IR (for example, the Stack IR
+  // passes only modify that IR).
+  // This property is important as if Binaryen IR is modified, we need to throw
+  // out any Stack IR - it would need to be regenerated and optimized.
+  virtual bool modifiesBinaryenIR() { return true; }
+
+  std::string name;
+
+protected:
+  Pass() = default;
+  Pass(Pass&) = default;
+  Pass& operator=(const Pass&) = delete;
+};
+
+//
+// Core pass class that uses AST walking. This class can be parameterized by
+// different types of AST walkers.
+//
+template<typename WalkerType>
+class WalkerPass : public Pass, public WalkerType {
+  PassRunner* runner;
+
+protected:
+  typedef WalkerPass<WalkerType> super;
+
+public:
+  void run(PassRunner* runner, Module* module) override {
+    // Parallel pass running is implemented in the PassRunner.
+    if (isFunctionParallel()) {
+      PassRunner runner(module);
+      runner.setIsNested(true);
+      std::unique_ptr<Pass> copy;
+      copy.reset(create());
+      runner.add(std::move(copy));
+      runner.run();
+      return;
+    }
+    // Single-thread running just calls the walkModule traversal.
+    setPassRunner(runner);
+    WalkerType::setModule(module);
+    WalkerType::walkModule(module);
+  }
+
+  void
+  runOnFunction(PassRunner* runner, Module* module, Function* func) override {
+    setPassRunner(runner);
+    WalkerType::setModule(module);
+    WalkerType::walkFunction(func);
+  }
+
+  PassRunner* getPassRunner() { return runner; }
+
+  PassOptions& getPassOptions() { return runner->options; }
+
+  void setPassRunner(PassRunner* runner_) { runner = runner_; }
+};
+
+} // namespace wasm
+
+#endif // wasm_pass_h
diff --git a/binaryen/src/passes/AlignmentLowering.cpp b/binaryen/src/passes/AlignmentLowering.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/AlignmentLowering.cpp
@@ -0,0 +1,377 @@
+/*
+ * 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.
+ */
+
+//
+// Lowers unaligned loads and stores into aligned loads and stores
+// that are smaller. This leaves only aligned operations.
+//
+
+#include "ir/bits.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
+  // Core lowering of a 32-bit load: ensures it is done using aligned
+  // operations, which means we can leave it alone if it's already aligned, or
+  // else we break it up into smaller loads that are.
+  Expression* lowerLoadI32(Load* curr) {
+    if (curr->align == 0 || curr->align == curr->bytes) {
+      return curr;
+    }
+    auto indexType = getModule()->memory.indexType;
+    Builder builder(*getModule());
+    assert(curr->type == Type::i32);
+    auto temp = builder.addVar(getFunction(), indexType);
+    Expression* ret;
+    if (curr->bytes == 2) {
+      ret = builder.makeBinary(
+        OrInt32,
+        builder.makeLoad(1,
+                         false,
+                         curr->offset,
+                         1,
+                         builder.makeLocalGet(temp, indexType),
+                         Type::i32),
+        builder.makeBinary(
+          ShlInt32,
+          builder.makeLoad(1,
+                           false,
+                           curr->offset + 1,
+                           1,
+                           builder.makeLocalGet(temp, indexType),
+                           Type::i32),
+          builder.makeConst(int32_t(8))));
+      if (curr->signed_) {
+        ret = Bits::makeSignExt(ret, 2, *getModule());
+      }
+    } else if (curr->bytes == 4) {
+      if (curr->align == 1) {
+        ret = builder.makeBinary(
+          OrInt32,
+          builder.makeBinary(
+            OrInt32,
+            builder.makeLoad(1,
+                             false,
+                             curr->offset,
+                             1,
+                             builder.makeLocalGet(temp, indexType),
+                             Type::i32),
+            builder.makeBinary(
+              ShlInt32,
+              builder.makeLoad(1,
+                               false,
+                               curr->offset + 1,
+                               1,
+                               builder.makeLocalGet(temp, indexType),
+                               Type::i32),
+              builder.makeConst(int32_t(8)))),
+          builder.makeBinary(
+            OrInt32,
+            builder.makeBinary(
+              ShlInt32,
+              builder.makeLoad(1,
+                               false,
+                               curr->offset + 2,
+                               1,
+                               builder.makeLocalGet(temp, indexType),
+                               Type::i32),
+              builder.makeConst(int32_t(16))),
+            builder.makeBinary(
+              ShlInt32,
+              builder.makeLoad(1,
+                               false,
+                               curr->offset + 3,
+                               1,
+                               builder.makeLocalGet(temp, indexType),
+                               Type::i32),
+              builder.makeConst(int32_t(24)))));
+      } else if (curr->align == 2) {
+        ret = builder.makeBinary(
+          OrInt32,
+          builder.makeLoad(2,
+                           false,
+                           curr->offset,
+                           2,
+                           builder.makeLocalGet(temp, indexType),
+                           Type::i32),
+          builder.makeBinary(
+            ShlInt32,
+            builder.makeLoad(2,
+                             false,
+                             curr->offset + 2,
+                             2,
+                             builder.makeLocalGet(temp, indexType),
+                             Type::i32),
+            builder.makeConst(int32_t(16))));
+      } else {
+        WASM_UNREACHABLE("invalid alignment");
+      }
+    } else {
+      WASM_UNREACHABLE("invalid size");
+    }
+    return builder.makeBlock({builder.makeLocalSet(temp, curr->ptr), ret});
+  }
+
+  // Core lowering of a 32-bit store.
+  Expression* lowerStoreI32(Store* curr) {
+    if (curr->align == 0 || curr->align == curr->bytes) {
+      return curr;
+    }
+    Builder builder(*getModule());
+    assert(curr->value->type == Type::i32);
+    auto indexType = getModule()->memory.indexType;
+    auto tempPtr = builder.addVar(getFunction(), indexType);
+    auto tempValue = builder.addVar(getFunction(), Type::i32);
+    auto* block =
+      builder.makeBlock({builder.makeLocalSet(tempPtr, curr->ptr),
+                         builder.makeLocalSet(tempValue, curr->value)});
+    if (curr->bytes == 2) {
+      block->list.push_back(
+        builder.makeStore(1,
+                          curr->offset,
+                          1,
+                          builder.makeLocalGet(tempPtr, indexType),
+                          builder.makeLocalGet(tempValue, Type::i32),
+                          Type::i32));
+      block->list.push_back(builder.makeStore(
+        1,
+        curr->offset + 1,
+        1,
+        builder.makeLocalGet(tempPtr, indexType),
+        builder.makeBinary(ShrUInt32,
+                           builder.makeLocalGet(tempValue, Type::i32),
+                           builder.makeConst(int32_t(8))),
+        Type::i32));
+    } else if (curr->bytes == 4) {
+      if (curr->align == 1) {
+        block->list.push_back(
+          builder.makeStore(1,
+                            curr->offset,
+                            1,
+                            builder.makeLocalGet(tempPtr, indexType),
+                            builder.makeLocalGet(tempValue, Type::i32),
+                            Type::i32));
+        block->list.push_back(builder.makeStore(
+          1,
+          curr->offset + 1,
+          1,
+          builder.makeLocalGet(tempPtr, indexType),
+          builder.makeBinary(ShrUInt32,
+                             builder.makeLocalGet(tempValue, Type::i32),
+                             builder.makeConst(int32_t(8))),
+          Type::i32));
+        block->list.push_back(builder.makeStore(
+          1,
+          curr->offset + 2,
+          1,
+          builder.makeLocalGet(tempPtr, indexType),
+          builder.makeBinary(ShrUInt32,
+                             builder.makeLocalGet(tempValue, Type::i32),
+                             builder.makeConst(int32_t(16))),
+          Type::i32));
+        block->list.push_back(builder.makeStore(
+          1,
+          curr->offset + 3,
+          1,
+          builder.makeLocalGet(tempPtr, indexType),
+          builder.makeBinary(ShrUInt32,
+                             builder.makeLocalGet(tempValue, Type::i32),
+                             builder.makeConst(int32_t(24))),
+          Type::i32));
+      } else if (curr->align == 2) {
+        block->list.push_back(
+          builder.makeStore(2,
+                            curr->offset,
+                            2,
+                            builder.makeLocalGet(tempPtr, indexType),
+                            builder.makeLocalGet(tempValue, Type::i32),
+                            Type::i32));
+        block->list.push_back(builder.makeStore(
+          2,
+          curr->offset + 2,
+          2,
+          builder.makeLocalGet(tempPtr, indexType),
+          builder.makeBinary(ShrUInt32,
+                             builder.makeLocalGet(tempValue, Type::i32),
+                             builder.makeConst(int32_t(16))),
+          Type::i32));
+      } else {
+        WASM_UNREACHABLE("invalid alignment");
+      }
+    } else {
+      WASM_UNREACHABLE("invalid size");
+    }
+    block->finalize();
+    return block;
+  }
+
+  void visitLoad(Load* curr) {
+    // If unreachable, just remove the load, which removes the unaligned
+    // operation in a trivial way.
+    if (curr->type == Type::unreachable) {
+      replaceCurrent(curr->ptr);
+      return;
+    }
+    if (curr->align == 0 || curr->align == curr->bytes) {
+      // Nothing to do: leave the node unchanged. All code lower down assumes
+      // the operation is unaligned.
+      return;
+    }
+    Builder builder(*getModule());
+    auto type = curr->type.getBasic();
+    Expression* replacement;
+    switch (type) {
+      default:
+        WASM_UNREACHABLE("unhandled unaligned load");
+      case Type::i32:
+        replacement = lowerLoadI32(curr);
+        break;
+      case Type::f32:
+        curr->type = Type::i32;
+        replacement = builder.makeUnary(ReinterpretInt32, lowerLoadI32(curr));
+        break;
+      case Type::i64:
+      case Type::f64:
+        if (type == Type::i64 && curr->bytes != 8) {
+          // A load of <64 bits.
+          curr->type = Type::i32;
+          replacement = builder.makeUnary(
+            curr->signed_ ? ExtendSInt32 : ExtendUInt32, lowerLoadI32(curr));
+          break;
+        }
+        // Load two 32-bit pieces, and combine them.
+        auto indexType = getModule()->memory.indexType;
+        auto temp = builder.addVar(getFunction(), indexType);
+        auto* set = builder.makeLocalSet(temp, curr->ptr);
+        Expression* low =
+          lowerLoadI32(builder.makeLoad(4,
+                                        false,
+                                        curr->offset,
+                                        curr->align,
+                                        builder.makeLocalGet(temp, indexType),
+                                        Type::i32));
+        low = builder.makeUnary(ExtendUInt32, low);
+        // Note that the alignment is assumed to be the same here, even though
+        // we add an offset of 4. That is because this is an unaligned load, so
+        // the alignment is 1, 2, or 4, which means it stays the same after
+        // adding 4.
+        Expression* high =
+          lowerLoadI32(builder.makeLoad(4,
+                                        false,
+                                        curr->offset + 4,
+                                        curr->align,
+                                        builder.makeLocalGet(temp, indexType),
+                                        Type::i32));
+        high = builder.makeUnary(ExtendUInt32, high);
+        high =
+          builder.makeBinary(ShlInt64, high, builder.makeConst(int64_t(32)));
+        auto* combined = builder.makeBinary(OrInt64, low, high);
+        replacement = builder.makeSequence(set, combined);
+        // Ensure the proper output type.
+        if (type == Type::f64) {
+          replacement = builder.makeUnary(ReinterpretInt64, replacement);
+        }
+        break;
+    }
+    replaceCurrent(replacement);
+  }
+
+  void visitStore(Store* curr) {
+    Builder builder(*getModule());
+    // If unreachable, just remove the store, which removes the unaligned
+    // operation in a trivial way.
+    if (curr->type == Type::unreachable) {
+      replaceCurrent(builder.makeBlock(
+        {builder.makeDrop(curr->ptr), builder.makeDrop(curr->value)}));
+      return;
+    }
+    if (curr->align == 0 || curr->align == curr->bytes) {
+      // Nothing to do: leave the node unchanged. All code lower down assumes
+      // the operation is unaligned.
+      return;
+    }
+    auto type = curr->value->type.getBasic();
+    Expression* replacement;
+    switch (type) {
+      default:
+        WASM_UNREACHABLE("unhandled unaligned store");
+      case Type::i32:
+        replacement = lowerStoreI32(curr);
+        break;
+      case Type::f32:
+        curr->type = Type::i32;
+        curr->value = builder.makeUnary(ReinterpretFloat32, curr->value);
+        replacement = lowerStoreI32(curr);
+        break;
+      case Type::i64:
+      case Type::f64:
+        if (type == Type::i64 && curr->bytes != 8) {
+          // A store of <64 bits.
+          curr->type = Type::i32;
+          curr->value = builder.makeUnary(WrapInt64, curr->value);
+          replacement = lowerStoreI32(curr);
+          break;
+        }
+        // Otherwise, fall through to f64 case for a 64-bit load.
+        // Ensure an integer input value.
+        auto* value = curr->value;
+        if (type == Type::f64) {
+          value = builder.makeUnary(ReinterpretFloat64, value);
+        }
+        // Store as two 32-bit pieces.
+        auto indexType = getModule()->memory.indexType;
+        auto tempPtr = builder.addVar(getFunction(), indexType);
+        auto* setPtr = builder.makeLocalSet(tempPtr, curr->ptr);
+        auto tempValue = builder.addVar(getFunction(), Type::i64);
+        auto* setValue = builder.makeLocalSet(tempValue, value);
+        Expression* low = builder.makeUnary(
+          WrapInt64, builder.makeLocalGet(tempValue, Type::i64));
+        low = lowerStoreI32(
+          builder.makeStore(4,
+                            curr->offset,
+                            curr->align,
+                            builder.makeLocalGet(tempPtr, indexType),
+                            low,
+                            Type::i32));
+        Expression* high =
+          builder.makeBinary(ShrUInt64,
+                             builder.makeLocalGet(tempValue, Type::i64),
+                             builder.makeConst(int64_t(32)));
+        high = builder.makeUnary(WrapInt64, high);
+        // Note that the alignment is assumed to be the same here, even though
+        // we add an offset of 4. That is because this is an unaligned store, so
+        // the alignment is 1, 2, or 4, which means it stays the same after
+        // adding 4.
+        high = lowerStoreI32(
+          builder.makeStore(4,
+                            curr->offset + 4,
+                            curr->align,
+                            builder.makeLocalGet(tempPtr, indexType),
+                            high,
+                            Type::i32));
+        replacement = builder.makeBlock({setPtr, setValue, low, high});
+        break;
+    }
+    replaceCurrent(replacement);
+  }
+};
+
+Pass* createAlignmentLoweringPass() { return new AlignmentLowering(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/Asyncify.cpp b/binaryen/src/passes/Asyncify.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/Asyncify.cpp
@@ -0,0 +1,1734 @@
+/*
+ * Copyright 2019 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.
+ */
+
+//
+// Asyncify: async/await style code transformation, that allows pausing
+// and resuming. This lets a language support synchronous operations in
+// an async manner, for example, you can do a blocking wait, and that will
+// be turned into code that unwinds the stack at the "blocking" operation,
+// then is able to rewind it back up when the actual async operation
+// comples, the so the code appears to have been running synchronously
+// all the while. Use cases for this include coroutines, python generators,
+// etc.
+//
+// The approach here is a third-generation design after Emscripten's original
+// Asyncify and then Emterpreter-Async approaches:
+//
+//  * Old Asyncify rewrote control flow in LLVM IR. A problem is that this
+//    needs to save all SSA registers as part of the local state, which can be
+//    very costly. A further increase can happen because of phis that are
+//    added because of control flow transformations. As a result we saw
+//    pathological cases where the code size increase was unacceptable.
+//  * Emterpreter-Async avoids any risk of code size increase by running it
+//    in a little bytecode VM, which also makes pausing/resuming trivial.
+//    Speed is the main downside here; however, the approach did prove that by
+//    *selectively* emterpretifying only certain code, many projects can run
+//    at full speed - often just the "main loop" must be emterpreted, while
+//    high-speed code that it calls, and in which cannot be an async operation,
+//    remain at full speed.
+//
+// New Asyncify's design learns from both of those:
+//
+//  * The code rewrite is done in Binaryen, that is, at the wasm level. At
+//    this level we will only need to save wasm locals, which is a much smaller
+//    number than LLVM's SSA registers.
+//  * We aim for low but non-zero overhead. Low overhead is very important
+//    for obvious reasons, while Emterpreter-Async proved it is tolerable to
+//    have *some* overhead, if the transform can be applied selectively.
+//
+// The specific transform implemented here is nicknamed "Bysyncify" (as it is
+// in BinarYen, and "B" comes after "A"). It is simpler than old Asyncify but
+// has low overhead when properly optimized. Old Asyncify worked at the CFG
+// level and added branches there; new Asyncify on the other hand works on the
+// structured control flow of wasm and simply "skips over" code when rewinding
+// the stack, and jumps out when unwinding. The transformed code looks
+// conceptually like this:
+//
+//   void foo(int x) {
+//     // new prelude
+//     if (rewinding) {
+//       loadLocals();
+//     }
+//     // main body starts here
+//     if (!rewinding) {
+//       // some code we must skip while rewinding
+//       x = x + 1;
+//       x = x / 2;
+//     }
+//     // If rewinding, do this call only if it is the right one.
+//     if (!rewinding or nextCall == 0) {
+//       bar(x);
+//       if (unwinding) {
+//         noteUnWound(0);
+//         saveLocals();
+//         return;
+//       }
+//     }
+//     if (!rewinding) {
+//       // more code we must skip while rewinding
+//       while (x & 7) {
+//         x = x + 1;
+//       }
+//     }
+//     [..]
+//
+// The general idea is that while rewinding we just "keep going forward",
+// skipping code we should not run. That is, instead of jumping directly
+// to the right place, we have ifs that skip along instead. The ifs for
+// rewinding and unwinding should be well-predicted, so the overhead should
+// not be very high. However, we do need to reach the right location via
+// such skipping, which means that in a very large function the rewind
+// takes some extra time. On the other hand, though, code that cannot
+// unwind or rewind (like that loop near the end) can run at full speed.
+// Overall, this should allow good performance with small overhead that is
+// mostly noticed at rewind time.
+//
+// After this pass is run a new i32 global "__asyncify_state" is added, which
+// has the following values:
+//
+//   0: normal execution
+//   1: unwinding the stack
+//   2: rewinding the stack
+//
+// There is also "__asyncify_data" which when rewinding and unwinding
+// contains a pointer to a data structure with the info needed to rewind
+// and unwind:
+//
+//   {                                            // offsets
+//     i32  - current asyncify stack location    //  0
+//     i32  - asyncify stack end                 //  4
+//   }
+//
+// The asyncify stack is a representation of the call frame, as a list of
+// indexes of calls. In the example above, we saw index "0" for calling "bar"
+// from "foo". When unwinding, the indexes are added to the stack; when
+// rewinding, they are popped off; the current asyncify stack location is
+// undated while doing both operations. The asyncify stack is also used to
+// save locals. Note that the stack end location is provided, which is for
+// error detection.
+//
+// Note: all pointers are assumed to be 4-byte aligned.
+//
+// When you start an unwinding operation, you must set the initial fields
+// of the data structure, that is, set the current stack location to the
+// proper place, and the end to the proper end based on how much memory
+// you reserved. Note that asyncify will grow the stack up.
+//
+// The pass will also create five functions that let you control unwinding
+// and rewinding:
+//
+//  * asyncify_start_unwind(data : i32): call this to start unwinding the
+//    stack from the current location. "data" must point to a data
+//    structure as described above (with fields containing valid data).
+//
+//  * asyncify_stop_unwind(): call this to note that unwinding has
+//    concluded. If no other code will run before you start to rewind,
+//    this is not strictly necessary, however, if you swap between
+//    coroutines, or even just want to run some normal code during a
+//    "sleep", then you must call this at the proper time. Otherwise,
+//    the code will think it is still unwinding when it should not be,
+//    which means it will keep unwinding in a meaningless way.
+//
+//  * asyncify_start_rewind(data : i32): call this to start rewinding the
+//    stack vack up to the location stored in the provided data. This prepares
+//    for the rewind; to start it, you must call the first function in the
+//    call stack to be unwound.
+//
+//  * asyncify_stop_rewind(): call this to note that rewinding has
+//    concluded, and normal execution can resume.
+//
+//  * asyncify_get_state(): call this to get the current value of the
+//    internal "__asyncify_state" variable as described above.
+//    It can be used to distinguish between unwinding/rewinding and normal
+//    calls, so that you know when to start an asynchronous operation and
+//    when to propagate results back.
+//
+// These four functions are exported so that you can call them from the
+// outside. If you want to manage things from inside the wasm, then you
+// couldn't have called them before they were created by this pass. To work
+// around that, you can create imports to asyncify.start_unwind,
+// asyncify.stop_unwind, asyncify.start_rewind, and asyncify.stop_rewind;
+// if those exist when this pass runs then it will turn those into direct
+// calls to the functions that it creates. Note that when doing everything
+// in wasm like this, Asyncify must not instrument your "runtime" support
+// code, that is, the code that initiates unwinds and rewinds and stops them.
+// If it did, the unwind would not stop until you left the wasm module
+// entirely, etc. Therefore we do not instrument a function if it has
+// a call to the four asyncify_* methods. Note that you may need to disable
+// inlining if that would cause code that does need to be instrumented
+// show up in that runtime code.
+//
+// To use this API, call asyncify_start_unwind when you want to. The call
+// stack will then be unwound, and so execution will resume in the JS or
+// other host environment on the outside that called into wasm. When you
+// return there after unwinding, call asyncify_stop_unwind. Then when
+// you want to rewind, call asyncify_start_rewind, and then call the same
+// initial function you called before, so that unwinding can begin. The
+// unwinding will reach the same function from which you started, since
+// we are recreating the call stack. At that point you should call
+// asyncify_stop_rewind and then execution can resume normally.
+//
+// Note that the asyncify_* API calls will verify that the data structure
+// is valid, checking if the current location is past the end. If so, they
+// will throw a wasm unreachable. No check is done during unwinding or
+// rewinding, to keep things fast - in principle, from when unwinding begins
+// and until it ends there should be no memory accesses aside from the
+// asyncify code itself (and likewise when rewinding), so there should be
+// no chance of memory corruption causing odd errors. However, the low
+// overhead of this approach does cause an error only to be shown when
+// unwinding/rewinding finishes, and not at the specific spot where the
+// stack end was exceeded.
+//
+// By default this pass is very careful: it assumes that any import and
+// any indirect call may start an unwind/rewind operation. If you know more
+// specific information you can inform asyncify about that, which can reduce
+// a great deal of overhead, as it can instrument less code. The relevant
+// options to wasm-opt etc. are:
+//
+//   --pass-arg=asyncify-imports@module1.base1,module2.base2,module3.base3
+//
+//      Each module.base in that comma-separated list will be considered to
+//      be an import that can unwind/rewind, and all others are assumed not to
+//      (aside from the asyncify.* imports, which are always assumed to).
+//      Each entry can end in a '*' in which case it is matched as a prefix.
+//
+//      The list of imports can be a response file (which is convenient if it
+//      is long, or you don't want to bother escaping it on the commandline
+//      etc.), e.g. --pass-arg=asyncify-imports@@file.txt will load the
+//      contents of file.txt (note the double "@@" - the first is the
+//      separator for --pass-arg, and the second is the usual convention for
+//      indicating a response file).
+//
+//   --pass-arg=asyncify-ignore-imports
+//
+//      Ignore all imports (except for bynsyncify.*), that is, assume none of
+//      them can start an unwind/rewind. (This is effectively the same as
+//      providing asyncify-imports with a list of non-existent imports.)
+//
+//   --pass-arg=asyncify-ignore-indirect
+//
+//      Ignore all indirect calls. This implies that you know an call stack
+//      will never need to be unwound with an indirect call somewhere in it.
+//      If that is true for your codebase, then this can be extremely useful
+//      as otherwise it looks like any indirect call can go to a lot of places.
+//
+//   --pass-arg=asyncify-asserts
+//
+//      This enables extra asserts in the output, like checking if we in
+//      an unwind/rewind in an invalid place (this can be helpful for manual
+//      tweaking of the only-list / remove-list, see later).
+//
+//   --pass-arg=asyncify-verbose
+//
+//      Logs out instrumentation decisions to the console. This can help figure
+//      out why a certain function was instrumented.
+//
+// For manual fine-tuning of the list of instrumented functions, there are lists
+// that you can set. These must be used carefully, as misuse can break your
+// application - for example, if a function is called that should be
+// instrumented but isn't because of these options, then bad things can happen.
+// Note that even if you test this locally then users running your code in
+// production may reach other code paths. Use these carefully!
+//
+// Each of the lists can be used with a response file (@filename, which is then
+// loaded from the file). You can also use '*' wildcard matching in the lists.
+//
+//   --pass-arg=asyncify-removelist@name1,name2,name3
+//
+//      If the "remove-list" is provided, then the functions in it will be
+//      *removed* from the list of instrumented functions. That is, they won't
+//      be instrumented even if it looks like they need to be. This can be
+//      useful if you know things the safe whole-program analysis doesn't, e.g.
+//      that certain code paths will not be taken, where certain indirect calls
+//      will go, etc.
+//
+//   --pass-arg=asyncify-addlist@name1,name2,name3
+//
+//      If the "add-list" is provided, then the functions in the list will be
+//      *added* to the list of instrumented functions, that is, they will be
+//      instrumented even if otherwise we think they don't need to be. As by
+//      default everything will be instrumented in the safest way possible,
+//      this is only useful if you use ignore-indirect and use this to fix up
+//      some indirect calls that *do* need to be instrumented, or if you will
+//      do some later transform of the code that adds more call paths, etc.
+//
+//   --pass-arg=asyncify-onlylist@name1,name2,name3
+//
+//      If the "only-list" is provided, then *only* the functions in the list
+//      will be instrumented, and nothing else.
+//
+// Note that there are two types of instrumentation that happen for each
+// function: if foo() can be part of a pause/resume operation, then we need to
+// instrument code inside it to support pausing and resuming, but also, we need
+// callers of the function to instrument calls to it. Normally this is already
+// taken care of as the callers need to be instrumented as well anyhow. However,
+// the ignore-indirect option makes things more complicated, since we can't tell
+// where all the calls to foo() are - all we see are indirect calls that do not
+// refer to foo() by name. To make it possible for you to use the add-list or
+// only-list with ignore-indirect, those lists affect *both* kinds of
+// instrumentation. That is, if parent() calls foo() indirectly, and you add
+// parent() to the add-list, then the indirect calls in parent() will be
+// instrumented to support pausing/resuming, even if ignore-indirect is set.
+// Typically you don't need to think about this, and just add all the functions
+// that can be on the stack while pausing - what this means is that when you do
+// so, indirect calls will just work. (The cost is that an instrumented function
+// will check for pausing at all indirect calls, which may be unnecessary in
+// some cases; but this is an instrumented function anyhow, and indirect calls
+// are slower anyhow, so this simple model seems good enough - a more complex
+// model where you can specify "instrument, but not indirect calls from me"
+// would likely have little benefit.)
+//
+// TODO When wasm has GC, extending the live ranges of locals can keep things
+//      alive unnecessarily. We may want to set locals to null at the end
+//      of their original range.
+//
+
+#include "cfg/liveness-traversal.h"
+#include "ir/effects.h"
+#include "ir/find_all.h"
+#include "ir/literal-utils.h"
+#include "ir/memory-utils.h"
+#include "ir/module-utils.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "support/file.h"
+#include "support/string.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace {
+
+static const Name ASYNCIFY_STATE = "__asyncify_state";
+static const Name ASYNCIFY_GET_STATE = "asyncify_get_state";
+static const Name ASYNCIFY_DATA = "__asyncify_data";
+static const Name ASYNCIFY_START_UNWIND = "asyncify_start_unwind";
+static const Name ASYNCIFY_STOP_UNWIND = "asyncify_stop_unwind";
+static const Name ASYNCIFY_START_REWIND = "asyncify_start_rewind";
+static const Name ASYNCIFY_STOP_REWIND = "asyncify_stop_rewind";
+static const Name ASYNCIFY_UNWIND = "__asyncify_unwind";
+static const Name ASYNCIFY = "asyncify";
+static const Name START_UNWIND = "start_unwind";
+static const Name STOP_UNWIND = "stop_unwind";
+static const Name START_REWIND = "start_rewind";
+static const Name STOP_REWIND = "stop_rewind";
+static const Name ASYNCIFY_GET_CALL_INDEX = "__asyncify_get_call_index";
+static const Name ASYNCIFY_CHECK_CALL_INDEX = "__asyncify_check_call_index";
+
+// TODO: having just normal/unwind_or_rewind would decrease code
+//       size, but make debugging harder
+enum class State { Normal = 0, Unwinding = 1, Rewinding = 2 };
+
+enum class DataOffset { BStackPos = 0, BStackEnd = 4 };
+
+const auto STACK_ALIGN = 4;
+
+// A helper class for managing fake global names. Creates the globals and
+// provides mappings for using them.
+// Fake globals are used to stash and then use return values from calls. We need
+// to store them somewhere that is valid Binaryen IR, but also will be ignored
+// by the Asyncify instrumentation, so we don't want to use a local. What we do
+// is replace the local used to receive a call's result with a fake global.set
+// to stash it, then do a fake global.get to receive it afterwards. (We do it in
+// two steps so that if we are async, we only do the first and not the second,
+// i.e., we don't store to the target local if not running normally).
+class FakeGlobalHelper {
+  Module& module;
+
+public:
+  FakeGlobalHelper(Module& module) : module(module) {
+    Builder builder(module);
+    std::string prefix = "asyncify_fake_call_global_";
+    for (auto type : collectTypes()) {
+      auto global = prefix + Type(type).toString();
+      map[type] = global;
+      rev[global] = type;
+      module.addGlobal(builder.makeGlobal(
+        global, type, LiteralUtils::makeZero(type, module), Builder::Mutable));
+    }
+  }
+
+  ~FakeGlobalHelper() {
+    for (auto& pair : map) {
+      auto name = pair.second;
+      module.removeGlobal(name);
+    }
+  }
+
+  Name getName(Type type) { return map.at(type); }
+
+  Type getTypeOrNone(Name name) {
+    auto iter = rev.find(name);
+    if (iter != rev.end()) {
+      return iter->second;
+    }
+    return Type::none;
+  }
+
+private:
+  std::map<Type, Name> map;
+  std::map<Name, Type> rev;
+
+  // Collect the types returned from all calls for which call support globals
+  // may need to be generated.
+  using Types = std::unordered_set<Type>;
+  Types collectTypes() {
+    ModuleUtils::ParallelFunctionAnalysis<Types> analysis(
+      module, [&](Function* func, Types& types) {
+        if (!func->body) {
+          return;
+        }
+        struct TypeCollector : PostWalker<TypeCollector> {
+          Types& types;
+          TypeCollector(Types& types) : types(types) {}
+          void visitCall(Call* curr) {
+            if (curr->type.isConcrete()) {
+              types.insert(curr->type);
+            }
+          }
+          void visitCallIndirect(CallIndirect* curr) {
+            if (curr->type.isConcrete()) {
+              types.insert(curr->type);
+            }
+          }
+        };
+        TypeCollector(types).walk(func->body);
+      });
+    Types types;
+    for (auto& pair : analysis.map) {
+      Types& functionTypes = pair.second;
+      for (auto t : functionTypes) {
+        types.insert(t);
+      }
+    }
+    return types;
+  }
+};
+
+class PatternMatcher {
+public:
+  std::string designation;
+  std::set<Name> names;
+  std::set<std::string> patterns;
+  std::set<std::string> patternsMatched;
+  std::map<std::string, std::string> unescaped;
+
+  PatternMatcher(std::string designation,
+                 Module& module,
+                 const String::Split& list)
+    : designation(designation) {
+    // The lists contain human-readable strings. Turn them into the
+    // internal escaped names for later comparisons
+    for (auto& name : list) {
+      auto escaped = WasmBinaryBuilder::escape(name);
+      unescaped[escaped.str] = name;
+      if (name.find('*') != std::string::npos) {
+        patterns.insert(escaped.str);
+      } else {
+        auto* func = module.getFunctionOrNull(escaped);
+        if (!func) {
+          std::cerr << "warning: Asyncify " << designation
+                    << "list contained a non-existing function name: " << name
+                    << " (" << escaped << ")\n";
+        } else if (func->imported()) {
+          Fatal() << "Asyncify " << designation
+                  << "list contained an imported function name (use the import "
+                     "list for imports): "
+                  << name << '\n';
+        }
+        names.insert(escaped.str);
+      }
+    }
+  }
+
+  bool match(Name funcName) {
+    if (names.count(funcName) > 0) {
+      return true;
+    } else {
+      for (auto& pattern : patterns) {
+        if (String::wildcardMatch(pattern, funcName.str)) {
+          patternsMatched.insert(pattern);
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  void checkPatternsMatches() {
+    for (auto& pattern : patterns) {
+      if (patternsMatched.count(pattern) == 0) {
+        std::cerr << "warning: Asyncify " << designation
+                  << "list contained a non-matching pattern: "
+                  << unescaped[pattern] << " (" << pattern << ")\n";
+      }
+    }
+  }
+};
+
+// Analyze the entire module to see which calls may change the state, that
+// is, start an unwind or rewind), either in itself or in something called
+// by it.
+// Handles global module management, needed from the various parts of this
+// transformation.
+class ModuleAnalyzer {
+  Module& module;
+  bool canIndirectChangeState;
+
+  struct Info
+    : public ModuleUtils::CallGraphPropertyAnalysis<Info>::FunctionInfo {
+    // The function name.
+    Name name;
+    // If this function can start an unwind/rewind.
+    bool canChangeState = false;
+    // If this function is part of the runtime that receives an unwinding
+    // and starts a rewinding. If so, we do not instrument it, see above.
+    // This is only relevant when handling things entirely inside wasm,
+    // as opposed to imports.
+    bool isBottomMostRuntime = false;
+    // If this function is part of the runtime that starts an unwinding
+    // and stops a rewinding. If so, we do not instrument it, see above.
+    // The difference between the top-most and bottom-most runtime is that
+    // the top-most part is still marked as changing the state; so things
+    // that call it are instrumented. This is not done for the bottom.
+    bool isTopMostRuntime = false;
+    bool inRemoveList = false;
+    bool addedFromList = false;
+  };
+
+  typedef std::map<Function*, Info> Map;
+  Map map;
+
+public:
+  ModuleAnalyzer(Module& module,
+                 std::function<bool(Name, Name)> canImportChangeState,
+                 bool canIndirectChangeState,
+                 const String::Split& removeListInput,
+                 const String::Split& addListInput,
+                 const String::Split& onlyListInput,
+                 bool asserts,
+                 bool verbose)
+    : module(module), canIndirectChangeState(canIndirectChangeState),
+      fakeGlobals(module), asserts(asserts), verbose(verbose) {
+
+    PatternMatcher removeList("remove", module, removeListInput);
+    PatternMatcher addList("add", module, addListInput);
+    PatternMatcher onlyList("only", module, onlyListInput);
+
+    // Rename the asyncify imports so their internal name matches the
+    // convention. This makes replacing them with the implementations
+    // later easier.
+    std::map<Name, Name> renamings;
+    for (auto& func : module.functions) {
+      if (func->module == ASYNCIFY) {
+        if (func->base == START_UNWIND) {
+          renamings[func->name] = ASYNCIFY_START_UNWIND;
+        } else if (func->base == STOP_UNWIND) {
+          renamings[func->name] = ASYNCIFY_STOP_UNWIND;
+        } else if (func->base == START_REWIND) {
+          renamings[func->name] = ASYNCIFY_START_REWIND;
+        } else if (func->base == STOP_REWIND) {
+          renamings[func->name] = ASYNCIFY_STOP_REWIND;
+        } else {
+          Fatal() << "call to unidenfied asyncify import: " << func->base;
+        }
+      }
+    }
+    ModuleUtils::renameFunctions(module, renamings);
+
+    // Scan to see which functions can directly change the state.
+    // Also handle the asyncify imports, removing them (as we will implement
+    // them later), and replace calls to them with calls to the later proper
+    // name.
+    ModuleUtils::CallGraphPropertyAnalysis<Info> scanner(
+      module, [&](Function* func, Info& info) {
+        info.name = func->name;
+        if (func->imported()) {
+          // The relevant asyncify imports can definitely change the state.
+          if (func->module == ASYNCIFY &&
+              (func->base == START_UNWIND || func->base == STOP_REWIND)) {
+            info.canChangeState = true;
+          } else {
+            info.canChangeState =
+              canImportChangeState(func->module, func->base);
+            if (verbose && info.canChangeState) {
+              std::cout << "[asyncify] " << func->name
+                        << " is an import that can change the state\n";
+            }
+          }
+          return;
+        }
+        struct Walker : PostWalker<Walker> {
+          Info& info;
+          Module& module;
+          bool canIndirectChangeState;
+
+          Walker(Info& info, Module& module, bool canIndirectChangeState)
+            : info(info), module(module),
+              canIndirectChangeState(canIndirectChangeState) {}
+
+          void visitCall(Call* curr) {
+            if (curr->isReturn) {
+              Fatal() << "tail calls not yet supported in asyncify";
+            }
+            auto* target = module.getFunction(curr->target);
+            if (target->imported() && target->module == ASYNCIFY) {
+              // Redirect the imports to the functions we'll add later.
+              if (target->base == START_UNWIND) {
+                info.canChangeState = true;
+                info.isTopMostRuntime = true;
+              } else if (target->base == STOP_UNWIND) {
+                info.isBottomMostRuntime = true;
+              } else if (target->base == START_REWIND) {
+                info.isBottomMostRuntime = true;
+              } else if (target->base == STOP_REWIND) {
+                info.canChangeState = true;
+                info.isTopMostRuntime = true;
+              } else {
+                WASM_UNREACHABLE("call to unidenfied asyncify import");
+              }
+            }
+          }
+          void visitCallIndirect(CallIndirect* curr) {
+            if (curr->isReturn) {
+              Fatal() << "tail calls not yet supported in asyncify";
+            }
+            if (canIndirectChangeState) {
+              info.canChangeState = true;
+            }
+            // TODO optimize the other case, at least by type
+          }
+        };
+        Walker walker(info, module, canIndirectChangeState);
+        walker.walk(func->body);
+
+        if (info.isBottomMostRuntime) {
+          info.canChangeState = false;
+          // TODO: issue warnings on suspicious things, like a function in
+          //       the bottom-most runtime also doing top-most runtime stuff
+          //       like starting and unwinding.
+        }
+        if (verbose && info.canChangeState) {
+          std::cout << "[asyncify] " << func->name
+                    << " can change the state due to initial scan\n";
+        }
+      });
+
+    // Functions in the remove-list are assumed to not change the state.
+    for (auto& pair : scanner.map) {
+      auto* func = pair.first;
+      auto& info = pair.second;
+      if (removeList.match(func->name)) {
+        info.inRemoveList = true;
+        if (verbose && info.canChangeState) {
+          std::cout << "[asyncify] " << func->name
+                    << " is in the remove-list, ignore\n";
+        }
+        info.canChangeState = false;
+      }
+    }
+
+    // Remove the asyncify imports, if any, and any calls to them.
+    std::vector<Name> funcsToDelete;
+    for (auto& pair : scanner.map) {
+      auto* func = pair.first;
+      auto& callsTo = pair.second.callsTo;
+      if (func->imported() && func->module == ASYNCIFY) {
+        funcsToDelete.push_back(func->name);
+      }
+      std::vector<Function*> callersToDelete;
+      for (auto* target : callsTo) {
+        if (target->imported() && target->module == ASYNCIFY) {
+          callersToDelete.push_back(target);
+        }
+      }
+      for (auto* target : callersToDelete) {
+        callsTo.erase(target);
+      }
+    }
+    for (auto name : funcsToDelete) {
+      module.removeFunction(name);
+    }
+
+    scanner.propagateBack([](const Info& info) { return info.canChangeState; },
+                          [](const Info& info) {
+                            return !info.isBottomMostRuntime &&
+                                   !info.inRemoveList;
+                          },
+                          [verbose](Info& info, Function* reason) {
+                            if (verbose && !info.canChangeState) {
+                              std::cout << "[asyncify] " << info.name
+                                        << " can change the state due to "
+                                        << reason->name << "\n";
+                            }
+                            info.canChangeState = true;
+                          },
+                          scanner.IgnoreIndirectCalls);
+
+    map.swap(scanner.map);
+
+    if (!onlyListInput.empty()) {
+      // Only the functions in the only-list can change the state.
+      for (auto& func : module.functions) {
+        if (!func->imported()) {
+          auto& info = map[func.get()];
+          bool matched = onlyList.match(func->name);
+          info.canChangeState = matched;
+          if (matched) {
+            info.addedFromList = true;
+          }
+          if (verbose) {
+            std::cout << "[asyncify] " << func->name
+                      << "'s state is set based on the only-list to " << matched
+                      << '\n';
+          }
+        }
+      }
+    }
+
+    if (!addListInput.empty()) {
+      for (auto& func : module.functions) {
+        if (!func->imported() && addList.match(func->name)) {
+          auto& info = map[func.get()];
+          if (verbose && !info.canChangeState) {
+            std::cout << "[asyncify] " << func->name
+                      << " is in the add-list, add\n";
+          }
+          info.canChangeState = true;
+          info.addedFromList = true;
+        }
+      }
+    }
+
+    removeList.checkPatternsMatches();
+    addList.checkPatternsMatches();
+    onlyList.checkPatternsMatches();
+  }
+
+  bool needsInstrumentation(Function* func) {
+    auto& info = map[func];
+    return info.canChangeState && !info.isTopMostRuntime;
+  }
+
+  bool canChangeState(Expression* curr, Function* func) {
+    // Look inside to see if we call any of the things we know can change the
+    // state.
+    // TODO: caching, this is O(N^2)
+    struct Walker : PostWalker<Walker> {
+      void visitCall(Call* curr) {
+        // We only implement these at the very end, but we know that they
+        // definitely change the state.
+        if (curr->target == ASYNCIFY_START_UNWIND ||
+            curr->target == ASYNCIFY_STOP_REWIND ||
+            curr->target == ASYNCIFY_GET_CALL_INDEX ||
+            curr->target == ASYNCIFY_CHECK_CALL_INDEX) {
+          canChangeState = true;
+          return;
+        }
+        if (curr->target == ASYNCIFY_STOP_UNWIND ||
+            curr->target == ASYNCIFY_START_REWIND) {
+          isBottomMostRuntime = true;
+          return;
+        }
+        // The target may not exist if it is one of our temporary intrinsics.
+        auto* target = module->getFunctionOrNull(curr->target);
+        if (target && (*map)[target].canChangeState) {
+          canChangeState = true;
+        }
+      }
+      void visitCallIndirect(CallIndirect* curr) { hasIndirectCall = true; }
+      Module* module;
+      ModuleAnalyzer* analyzer;
+      Map* map;
+      bool hasIndirectCall = false;
+      bool canChangeState = false;
+      bool isBottomMostRuntime = false;
+    };
+    Walker walker;
+    walker.module = &module;
+    walker.analyzer = this;
+    walker.map = &map;
+    walker.walk(curr);
+    // An indirect call is normally ignored if we are ignoring indirect calls.
+    // However, see the docs at the top: if the function we are inside was
+    // specifically added by the user (in the only-list or the add-list) then we
+    // instrument indirect calls from it (this allows specifically allowing some
+    // indirect calls but not others).
+    if (walker.hasIndirectCall &&
+        (canIndirectChangeState || map[func].addedFromList)) {
+      walker.canChangeState = true;
+    }
+    // The bottom-most runtime can never change the state.
+    return walker.canChangeState && !walker.isBottomMostRuntime;
+  }
+
+  FakeGlobalHelper fakeGlobals;
+  bool asserts;
+  bool verbose;
+};
+
+// Checks if something performs a call: either a direct or indirect call,
+// and perhaps it is dropped or assigned to a local. This captures all the
+// cases of a call in flat IR.
+static bool doesCall(Expression* curr) {
+  if (auto* set = curr->dynCast<LocalSet>()) {
+    curr = set->value;
+  } else if (auto* drop = curr->dynCast<Drop>()) {
+    curr = drop->value;
+  }
+  return curr->is<Call>() || curr->is<CallIndirect>();
+}
+
+class AsyncifyBuilder : public Builder {
+public:
+  AsyncifyBuilder(Module& wasm) : Builder(wasm) {}
+
+  Expression* makeGetStackPos() {
+    return makeLoad(4,
+                    false,
+                    int32_t(DataOffset::BStackPos),
+                    4,
+                    makeGlobalGet(ASYNCIFY_DATA, Type::i32),
+                    Type::i32);
+  }
+
+  Expression* makeIncStackPos(int32_t by) {
+    if (by == 0) {
+      return makeNop();
+    }
+    return makeStore(
+      4,
+      int32_t(DataOffset::BStackPos),
+      4,
+      makeGlobalGet(ASYNCIFY_DATA, Type::i32),
+      makeBinary(AddInt32, makeGetStackPos(), makeConst(Literal(by))),
+      Type::i32);
+  }
+
+  Expression* makeStateCheck(State value) {
+    return makeBinary(EqInt32,
+                      makeGlobalGet(ASYNCIFY_STATE, Type::i32),
+                      makeConst(Literal(int32_t(value))));
+  }
+
+  Expression* makeNegatedStateCheck(State value) {
+    return makeUnary(EqZInt32, makeStateCheck(value));
+  }
+};
+
+// Instrument control flow, around calls and adding skips for rewinding.
+struct AsyncifyFlow : public Pass {
+  bool isFunctionParallel() override { return true; }
+
+  ModuleAnalyzer* analyzer;
+
+  AsyncifyFlow* create() override { return new AsyncifyFlow(analyzer); }
+
+  AsyncifyFlow(ModuleAnalyzer* analyzer) : analyzer(analyzer) {}
+
+  void
+  runOnFunction(PassRunner* runner, Module* module_, Function* func_) override {
+    module = module_;
+    func = func_;
+    builder = make_unique<AsyncifyBuilder>(*module);
+    // If the function cannot change our state, we have nothing to do -
+    // we will never unwind or rewind the stack here.
+    if (!analyzer->needsInstrumentation(func)) {
+      if (analyzer->asserts) {
+        addAssertsInNonInstrumented(func);
+      }
+      return;
+    }
+    // Rewrite the function body.
+    // Each function we enter will pop one from the stack, which is the index
+    // of the next call to make.
+    auto* block = builder->makeBlock(
+      {builder->makeIf(builder->makeStateCheck(
+                         State::Rewinding), // TODO: such checks can be !normal
+                       makeCallIndexPop()),
+       process(func->body)});
+    if (func->sig.results != Type::none) {
+      // Rewriting control flow may alter things; make sure the function ends in
+      // something valid (which the optimizer can remove later).
+      block->list.push_back(builder->makeUnreachable());
+    }
+    block->finalize();
+    func->body = block;
+    // Making things like returns conditional may alter types.
+    ReFinalize().walkFunctionInModule(func, module);
+  }
+
+private:
+  std::unique_ptr<AsyncifyBuilder> builder;
+
+  Module* module;
+  Function* func;
+
+  // Each call in the function has an index, noted during unwind and checked
+  // during rewind.
+  Index callIndex = 0;
+
+  Expression* process(Expression* curr) {
+    if (!analyzer->canChangeState(curr, func)) {
+      return makeMaybeSkip(curr);
+    }
+    // The IR is in flat form, which makes this much simpler: there are no
+    // unnecessarily nested side effects or control flow, so we can add
+    // skips for rewinding in an easy manner, putting a single if around
+    // whole chunks of code. Also calls are separated out so that it is easy
+    // to add the necessary checks for them for unwinding/rewinding support.
+    //
+    // Aside from that, we must "linearize" all control flow so that we can
+    // reach the right part when rewinding, which is done by always skipping
+    // forward. For example, for an if we do this:
+    //
+    //    if (condition()) {
+    //      side1();
+    //    } else {
+    //      side2();
+    //    }
+    // =>
+    //    if (!rewinding) {
+    //      temp = condition();
+    //    }
+    //    if (rewinding || temp) {
+    //      side1();
+    //    }
+    //    if (rewinding || !temp) {
+    //      side2();
+    //    }
+    //
+    // This way we will linearly get through all the code in the function,
+    // if we are rewinding. In a similar way we skip over breaks, etc.; just
+    // "keep on truckin'".
+    //
+    // Note that temp locals added in this way are just normal locals, and in
+    // particular they are saved and loaded. That way if we resume from the
+    // first if arm we will avoid the second.
+    if (auto* block = curr->dynCast<Block>()) {
+      // At least one of our children may change the state. Clump them as
+      // necessary.
+      Index i = 0;
+      auto& list = block->list;
+      while (i < list.size()) {
+        if (analyzer->canChangeState(list[i], func)) {
+          list[i] = process(list[i]);
+          i++;
+        } else {
+          Index end = i + 1;
+          while (end < list.size() &&
+                 !analyzer->canChangeState(list[end], func)) {
+            end++;
+          }
+          // We have a range of [i, end) in which the state cannot change,
+          // so all we need to do is skip it if rewinding.
+          if (end == i + 1) {
+            list[i] = makeMaybeSkip(list[i]);
+          } else {
+            auto* block = builder->makeBlock();
+            for (auto j = i; j < end; j++) {
+              block->list.push_back(list[j]);
+            }
+            block->finalize();
+            list[i] = makeMaybeSkip(block);
+            for (auto j = i + 1; j < end; j++) {
+              list[j] = builder->makeNop();
+            }
+          }
+          i = end;
+        }
+      }
+      return block;
+    } else if (auto* iff = curr->dynCast<If>()) {
+      // The state change cannot be in the condition due to flat form, so it
+      // must be in one of the children.
+      assert(!analyzer->canChangeState(iff->condition, func));
+      // We must linearize this, which means we pass through both arms if we
+      // are rewinding.
+      if (!iff->ifFalse) {
+        iff->condition = builder->makeBinary(
+          OrInt32, iff->condition, builder->makeStateCheck(State::Rewinding));
+        iff->ifTrue = process(iff->ifTrue);
+        iff->finalize();
+        return iff;
+      }
+      auto conditionTemp = builder->addVar(func, Type::i32);
+      // TODO: can avoid pre if the condition is a get or a const
+      auto* pre =
+        makeMaybeSkip(builder->makeLocalSet(conditionTemp, iff->condition));
+      iff->condition = builder->makeLocalGet(conditionTemp, Type::i32);
+      iff->condition = builder->makeBinary(
+        OrInt32, iff->condition, builder->makeStateCheck(State::Rewinding));
+      iff->ifTrue = process(iff->ifTrue);
+      auto* otherArm = iff->ifFalse;
+      iff->ifFalse = nullptr;
+      iff->finalize();
+      // Add support for the second arm as well.
+      auto* otherIf = builder->makeIf(
+        builder->makeBinary(
+          OrInt32,
+          builder->makeUnary(EqZInt32,
+                             builder->makeLocalGet(conditionTemp, Type::i32)),
+          builder->makeStateCheck(State::Rewinding)),
+        process(otherArm));
+      otherIf->finalize();
+      return builder->makeBlock({pre, iff, otherIf});
+    } else if (auto* loop = curr->dynCast<Loop>()) {
+      loop->body = process(loop->body);
+      return loop;
+    } else if (doesCall(curr)) {
+      return makeCallSupport(curr);
+    }
+    // We must handle all control flow above, and all things that can change
+    // the state, so there should be nothing that can reach here - add it
+    // earlier as necessary.
+    // std::cout << *curr << '\n';
+    WASM_UNREACHABLE("unexpected expression type");
+  }
+
+  // Possibly skip some code, if rewinding.
+  Expression* makeMaybeSkip(Expression* curr) {
+    return builder->makeIf(builder->makeStateCheck(State::Normal), curr);
+  }
+
+  Expression* makeCallSupport(Expression* curr) {
+    // TODO: stop doing this after code can no longer reach a call that may
+    //       change the state
+    assert(doesCall(curr));
+    assert(curr->type == Type::none);
+    // The case of a set is tricky: we must *not* execute the set when
+    // unwinding, since at that point we have a fake value for the return,
+    // and if we applied it to the local, it would end up saved and then
+    // potentially used later - and with coalescing, that may interfere
+    // with other things. Note also that at this point in the process we
+    // have not yet written the load saving/loading code, so the optimizer
+    // doesn't see that locals will have another use at the beginning and
+    // end of the function. We don't do that yet because we don't want it
+    // to force the final number of locals to be too high, but we also
+    // must be careful to never touch a local unnecessarily to avoid bugs.
+    // To implement this, write to a fake global; we'll fix it up after
+    // AsyncifyLocals locals adds local saving/restoring.
+    auto* set = curr->dynCast<LocalSet>();
+    if (set) {
+      auto name = analyzer->fakeGlobals.getName(set->value->type);
+      curr = builder->makeGlobalSet(name, set->value);
+      set->value = builder->makeGlobalGet(name, set->value->type);
+    }
+    // Instrument the call itself (or, if a drop, the drop+call).
+    auto index = callIndex++;
+    // Execute the call, if either normal execution, or if rewinding and this
+    // is the right call to go into.
+    // TODO: we can read the next call index once in each function (but should
+    //       avoid saving/restoring that local later)
+    curr = builder->makeIf(
+      builder->makeIf(builder->makeStateCheck(State::Normal),
+                      builder->makeConst(int32_t(1)),
+                      makeCallIndexPeek(index)),
+      builder->makeSequence(curr, makePossibleUnwind(index, set)));
+    return curr;
+  }
+
+  Expression* makePossibleUnwind(Index index, Expression* ifNotUnwinding) {
+    // In this pass we emit an "unwind" as a call to a fake intrinsic. We
+    // will implement it in the later pass. (We can't create the unwind block
+    // target here, as the optimizer would remove it later; we can only add
+    // it when we add its contents, later.)
+    return builder->makeIf(
+      builder->makeStateCheck(State::Unwinding),
+      builder->makeCall(
+        ASYNCIFY_UNWIND, {builder->makeConst(int32_t(index))}, Type::none),
+      ifNotUnwinding);
+  }
+
+  Expression* makeCallIndexPeek(Index index) {
+    // Emit an intrinsic for this, as we store the index into a local, and
+    // don't want it to be seen by asyncify itself.
+    return builder->makeCall(ASYNCIFY_CHECK_CALL_INDEX,
+                             {builder->makeConst(int32_t(index))},
+                             Type::i32);
+  }
+
+  Expression* makeCallIndexPop() {
+    // Emit an intrinsic for this, as we store the index into a local, and
+    // don't want it to be seen by asyncify itself.
+    return builder->makeCall(ASYNCIFY_GET_CALL_INDEX, {}, Type::none);
+  }
+
+  // Given a function that is not instrumented - because we proved it doesn't
+  // need it, or depending on the only-list / remove-list - add assertions that
+  // verify that property at runtime.
+  // Note that it is ok to run code while sleeping (if you are careful not
+  // to break assumptions in the program!) - so what is actually
+  // checked here is if the state *changes* in an uninstrumented function.
+  // That is, if in an uninstrumented function, a sleep should not begin
+  // from any call.
+  void addAssertsInNonInstrumented(Function* func) {
+    auto oldState = builder->addVar(func, Type::i32);
+    // Add a check at the function entry.
+    func->body = builder->makeSequence(
+      builder->makeLocalSet(oldState,
+                            builder->makeGlobalGet(ASYNCIFY_STATE, Type::i32)),
+      func->body);
+    // Add a check around every call.
+    struct Walker : PostWalker<Walker> {
+      void visitCall(Call* curr) {
+        // Tail calls will need another type of check, as they wouldn't reach
+        // this assertion.
+        assert(!curr->isReturn);
+        handleCall(curr);
+      }
+      void visitCallIndirect(CallIndirect* curr) {
+        // Tail calls will need another type of check, as they wouldn't reach
+        // this assertion.
+        assert(!curr->isReturn);
+        handleCall(curr);
+      }
+      void handleCall(Expression* call) {
+        auto* check = builder->makeIf(
+          builder->makeBinary(NeInt32,
+                              builder->makeGlobalGet(ASYNCIFY_STATE, Type::i32),
+                              builder->makeLocalGet(oldState, Type::i32)),
+          builder->makeUnreachable());
+        Expression* rep;
+        if (call->type.isConcrete()) {
+          auto temp = builder->addVar(func, call->type);
+          rep = builder->makeBlock({
+            builder->makeLocalSet(temp, call),
+            check,
+            builder->makeLocalGet(temp, call->type),
+          });
+        } else {
+          rep = builder->makeSequence(call, check);
+        }
+        replaceCurrent(rep);
+      }
+      Function* func;
+      AsyncifyBuilder* builder;
+      Index oldState;
+    };
+    Walker walker;
+    walker.func = func;
+    walker.builder = builder.get();
+    walker.oldState = oldState;
+    walker.walk(func->body);
+  }
+};
+
+// Instrument local saving/restoring.
+struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> {
+  bool isFunctionParallel() override { return true; }
+
+  ModuleAnalyzer* analyzer;
+
+  AsyncifyLocals* create() override { return new AsyncifyLocals(analyzer); }
+
+  AsyncifyLocals(ModuleAnalyzer* analyzer) : analyzer(analyzer) {}
+
+  void visitCall(Call* curr) {
+    // Replace calls to the fake intrinsics.
+    if (curr->target == ASYNCIFY_UNWIND) {
+      replaceCurrent(builder->makeBreak(ASYNCIFY_UNWIND, curr->operands[0]));
+    } else if (curr->target == ASYNCIFY_GET_CALL_INDEX) {
+      replaceCurrent(builder->makeSequence(
+        builder->makeIncStackPos(-4),
+        builder->makeLocalSet(
+          rewindIndex,
+          builder->makeLoad(
+            4, false, 0, 4, builder->makeGetStackPos(), Type::i32))));
+    } else if (curr->target == ASYNCIFY_CHECK_CALL_INDEX) {
+      replaceCurrent(builder->makeBinary(
+        EqInt32,
+        builder->makeLocalGet(rewindIndex, Type::i32),
+        builder->makeConst(
+          Literal(int32_t(curr->operands[0]->cast<Const>()->value.geti32())))));
+    }
+  }
+
+  void visitGlobalSet(GlobalSet* curr) {
+    auto type = analyzer->fakeGlobals.getTypeOrNone(curr->name);
+    if (type != Type::none) {
+      replaceCurrent(
+        builder->makeLocalSet(getFakeCallLocal(type), curr->value));
+    }
+  }
+
+  void visitGlobalGet(GlobalGet* curr) {
+    auto type = analyzer->fakeGlobals.getTypeOrNone(curr->name);
+    if (type != Type::none) {
+      replaceCurrent(builder->makeLocalGet(getFakeCallLocal(type), type));
+    }
+  }
+
+  Index getFakeCallLocal(Type type) {
+    auto iter = fakeCallLocals.find(type);
+    if (iter != fakeCallLocals.end()) {
+      return iter->second;
+    }
+    return fakeCallLocals[type] = builder->addVar(getFunction(), type);
+  }
+
+  void doWalkFunction(Function* func) {
+    // If the function cannot change our state, we have nothing to do -
+    // we will never unwind or rewind the stack here.
+    if (!analyzer->needsInstrumentation(func)) {
+      return;
+    }
+    // Find the locals that we actually need to load and save: any local that is
+    // alive at a relevant call site must be handled, but others can be ignored.
+    findRelevantLiveLocals(func);
+    // The new function body has a prelude to load locals if rewinding,
+    // then the actual main body, which does all its unwindings by breaking
+    // to the unwind block, which then handles pushing the call index, as
+    // well as saving the locals.
+    // An index is needed for getting the unwinding and rewinding call indexes
+    // around TODO: can this be the same index?
+    auto unwindIndex = builder->addVar(func, Type::i32);
+    rewindIndex = builder->addVar(func, Type::i32);
+    // Rewrite the function body.
+    builder = make_unique<AsyncifyBuilder>(*getModule());
+    walk(func->body);
+    // After the normal function body, emit a barrier before the postamble.
+    Expression* barrier;
+    if (func->sig.results == Type::none) {
+      // The function may have ended without a return; ensure one.
+      barrier = builder->makeReturn();
+    } else {
+      // The function must have returned or hit an unreachable, but emit one
+      // to make possible bugs easier to figure out (as this should never be
+      // reached). The optimizer can remove this anyhow.
+      barrier = builder->makeUnreachable();
+    }
+    auto* newBody = builder->makeBlock(
+      {builder->makeIf(builder->makeStateCheck(State::Rewinding),
+                       makeLocalLoading()),
+       builder->makeLocalSet(
+         unwindIndex,
+         builder->makeBlock(ASYNCIFY_UNWIND,
+                            builder->makeSequence(func->body, barrier))),
+       makeCallIndexPush(unwindIndex),
+       makeLocalSaving()});
+    if (func->sig.results != Type::none) {
+      // If we unwind, we must still "return" a value, even if it will be
+      // ignored on the outside.
+      newBody->list.push_back(
+        LiteralUtils::makeZero(func->sig.results, *getModule()));
+      newBody->finalize(func->sig.results);
+    }
+    func->body = newBody;
+    // Making things like returns conditional may alter types.
+    ReFinalize().walkFunctionInModule(func, getModule());
+  }
+
+private:
+  std::unique_ptr<AsyncifyBuilder> builder;
+
+  Index rewindIndex;
+  std::map<Type, Index> fakeCallLocals;
+  std::set<Index> relevantLiveLocals;
+
+  void findRelevantLiveLocals(Function* func) {
+    struct RelevantLiveLocalsWalker
+      : public LivenessWalker<RelevantLiveLocalsWalker,
+                              Visitor<RelevantLiveLocalsWalker>> {
+      // Basic blocks that have a possible unwind/rewind in them.
+      std::set<BasicBlock*> relevantBasicBlocks;
+
+      void visitCall(Call* curr) {
+        if (!currBasicBlock) {
+          return;
+        }
+        // Note blocks where we might unwind/rewind, all of which have a
+        // possible call to ASYNCIFY_CHECK_CALL_INDEX emitted right before the
+        // actual call.
+        // Note that each relevant original call was turned into a sequence of
+        // instructions, one of which is an if and then a call to this special
+        // intrinsic. We rely on the fact that if a local was live at the
+        // original call, it also would be in all that sequence of instructions,
+        // and in particular at the call we look for here (which is right before
+        // the call, and so anything that has its final use at the call is still
+        // live here).
+        if (curr->target == ASYNCIFY_CHECK_CALL_INDEX) {
+          relevantBasicBlocks.insert(currBasicBlock);
+        }
+      }
+    };
+
+    RelevantLiveLocalsWalker walker;
+    walker.walkFunctionInModule(func, getModule());
+    // The relevant live locals are ones that are alive at an unwind/rewind
+    // location. TODO look more precisely inside basic blocks, as one might stop
+    // being live in the middle
+    for (auto* block : walker.liveBlocks) {
+      if (walker.relevantBasicBlocks.count(block)) {
+        for (auto local : block->contents.start) {
+          relevantLiveLocals.insert(local);
+        }
+      }
+    }
+  }
+
+  Expression* makeLocalLoading() {
+    if (relevantLiveLocals.empty()) {
+      return builder->makeNop();
+    }
+    auto* func = getFunction();
+    auto numLocals = func->getNumLocals();
+    Index total = 0;
+    for (Index i = 0; i < numLocals; i++) {
+      if (!relevantLiveLocals.count(i)) {
+        continue;
+      }
+      total += func->getLocalType(i).getByteSize();
+    }
+    auto* block = builder->makeBlock();
+    block->list.push_back(builder->makeIncStackPos(-total));
+    auto tempIndex = builder->addVar(func, Type::i32);
+    block->list.push_back(
+      builder->makeLocalSet(tempIndex, builder->makeGetStackPos()));
+    Index offset = 0;
+    for (Index i = 0; i < numLocals; i++) {
+      if (!relevantLiveLocals.count(i)) {
+        continue;
+      }
+      auto localType = func->getLocalType(i);
+      SmallVector<Expression*, 1> loads;
+      for (const auto& type : localType) {
+        auto size = type.getByteSize();
+        assert(size % STACK_ALIGN == 0);
+        // TODO: higher alignment?
+        loads.push_back(
+          builder->makeLoad(size,
+                            true,
+                            offset,
+                            STACK_ALIGN,
+                            builder->makeLocalGet(tempIndex, Type::i32),
+                            type));
+        offset += size;
+      }
+      Expression* load;
+      if (loads.size() == 1) {
+        load = loads[0];
+      } else if (localType.size() > 1) {
+        load = builder->makeTupleMake(std::move(loads));
+      } else {
+        WASM_UNREACHABLE("Unexpected empty type");
+      }
+      block->list.push_back(builder->makeLocalSet(i, load));
+    }
+    block->finalize();
+    return block;
+  }
+
+  Expression* makeLocalSaving() {
+    if (relevantLiveLocals.empty()) {
+      return builder->makeNop();
+    }
+    auto* func = getFunction();
+    auto numLocals = func->getNumLocals();
+    auto* block = builder->makeBlock();
+    auto tempIndex = builder->addVar(func, Type::i32);
+    block->list.push_back(
+      builder->makeLocalSet(tempIndex, builder->makeGetStackPos()));
+    Index offset = 0;
+    for (Index i = 0; i < numLocals; i++) {
+      if (!relevantLiveLocals.count(i)) {
+        continue;
+      }
+      auto localType = func->getLocalType(i);
+      size_t j = 0;
+      for (const auto& type : localType) {
+        auto size = type.getByteSize();
+        Expression* localGet = builder->makeLocalGet(i, localType);
+        if (localType.size() > 1) {
+          localGet = builder->makeTupleExtract(localGet, j);
+        }
+        assert(size % STACK_ALIGN == 0);
+        // TODO: higher alignment?
+        block->list.push_back(
+          builder->makeStore(size,
+                             offset,
+                             STACK_ALIGN,
+                             builder->makeLocalGet(tempIndex, Type::i32),
+                             localGet,
+                             type));
+        offset += size;
+        ++j;
+      }
+    }
+    block->list.push_back(builder->makeIncStackPos(offset));
+    block->finalize();
+    return block;
+  }
+
+  Expression* makeCallIndexPush(Index tempIndex) {
+    // TODO: add a check against the stack end here
+    return builder->makeSequence(
+      builder->makeStore(4,
+                         0,
+                         4,
+                         builder->makeGetStackPos(),
+                         builder->makeLocalGet(tempIndex, Type::i32),
+                         Type::i32),
+      builder->makeIncStackPos(4));
+  }
+};
+
+} // anonymous namespace
+
+static std::string getFullImportName(Name module, Name base) {
+  return std::string(module.str) + '.' + base.str;
+}
+
+struct Asyncify : public Pass {
+  void run(PassRunner* runner, Module* module) override {
+    bool optimize = runner->options.optimizeLevel > 0;
+
+    // Ensure there is a memory, as we need it.
+    MemoryUtils::ensureExists(module->memory);
+
+    // Find which things can change the state.
+    auto stateChangingImports = String::trim(read_possible_response_file(
+      runner->options.getArgumentOrDefault("asyncify-imports", "")));
+    auto ignoreImports =
+      runner->options.getArgumentOrDefault("asyncify-ignore-imports", "");
+    bool allImportsCanChangeState =
+      stateChangingImports == "" && ignoreImports == "";
+    String::Split listedImports(stateChangingImports, ",");
+    auto ignoreIndirect = runner->options.getArgumentOrDefault(
+                            "asyncify-ignore-indirect", "") == "";
+    std::string removeListInput =
+      runner->options.getArgumentOrDefault("asyncify-removelist", "");
+    if (removeListInput.empty()) {
+      // Support old name for now to avoid immediate breakage TODO remove
+      removeListInput =
+        runner->options.getArgumentOrDefault("asyncify-blacklist", "");
+    }
+    String::Split removeList(
+      String::trim(read_possible_response_file(removeListInput)), ",");
+    String::Split addList(
+      String::trim(read_possible_response_file(
+        runner->options.getArgumentOrDefault("asyncify-addlist", ""))),
+      ",");
+    std::string onlyListInput =
+      runner->options.getArgumentOrDefault("asyncify-onlylist", "");
+    if (onlyListInput.empty()) {
+      // Support old name for now to avoid immediate breakage TODO remove
+      onlyListInput =
+        runner->options.getArgumentOrDefault("asyncify-whitelist", "");
+    }
+    String::Split onlyList(
+      String::trim(read_possible_response_file(onlyListInput)), ",");
+    auto asserts =
+      runner->options.getArgumentOrDefault("asyncify-asserts", "") != "";
+    auto verbose =
+      runner->options.getArgumentOrDefault("asyncify-verbose", "") != "";
+
+    removeList = handleBracketingOperators(removeList);
+    addList = handleBracketingOperators(addList);
+    onlyList = handleBracketingOperators(onlyList);
+
+    if (!onlyList.empty() && (!removeList.empty() || !addList.empty())) {
+      Fatal() << "It makes no sense to use both an asyncify only-list together "
+                 "with another list.";
+    }
+
+    auto canImportChangeState = [&](Name module, Name base) {
+      if (allImportsCanChangeState) {
+        return true;
+      }
+      auto full = getFullImportName(module, base);
+      for (auto& listedImport : listedImports) {
+        if (String::wildcardMatch(listedImport, full)) {
+          return true;
+        }
+      }
+      return false;
+    };
+
+    // Scan the module.
+    ModuleAnalyzer analyzer(*module,
+                            canImportChangeState,
+                            ignoreIndirect,
+                            removeList,
+                            addList,
+                            onlyList,
+                            asserts,
+                            verbose);
+
+    // Add necessary globals before we emit code to use them.
+    addGlobals(module);
+
+    // Instrument the flow of code, adding code instrumentation and
+    // skips for when rewinding. We do this on flat IR so that it is
+    // practical to add code around each call, without affecting
+    // anything else.
+    {
+      PassRunner runner(module);
+      runner.add("flatten");
+      // Dce is useful here, since AsyncifyFlow makes control flow conditional,
+      // which may make unreachable code look reachable. It also lets us ignore
+      // unreachable code here.
+      runner.add("dce");
+      if (optimize) {
+        // Optimizing before BsyncifyFlow is crucial, especially coalescing,
+        // 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("simplify-locals-nonesting");
+        runner.add("reorder-locals");
+        runner.add("coalesce-locals");
+        runner.add("simplify-locals-nonesting");
+        runner.add("reorder-locals");
+        runner.add("merge-blocks");
+      }
+      runner.add(make_unique<AsyncifyFlow>(&analyzer));
+      runner.setIsNested(true);
+      runner.setValidateGlobally(false);
+      runner.run();
+    }
+    // Next, add local saving/restoring logic. We optimize before doing this,
+    // to undo the extra code generated by flattening, and to arrive at the
+    // minimal amount of locals (which is important as we must save and
+    // restore those locals). We also and optimize after as well to simplify
+    // the code as much as possible.
+    {
+      PassRunner runner(module);
+      if (optimize) {
+        runner.addDefaultFunctionOptimizationPasses();
+      }
+      runner.add(make_unique<AsyncifyLocals>(&analyzer));
+      if (optimize) {
+        runner.addDefaultFunctionOptimizationPasses();
+      }
+      runner.setIsNested(true);
+      runner.setValidateGlobally(false);
+      runner.run();
+    }
+    // Finally, add function support (that should not have been seen by
+    // the previous passes).
+    addFunctions(module);
+  }
+
+private:
+  void addGlobals(Module* module) {
+    Builder builder(*module);
+    module->addGlobal(builder.makeGlobal(ASYNCIFY_STATE,
+                                         Type::i32,
+                                         builder.makeConst(int32_t(0)),
+                                         Builder::Mutable));
+    module->addGlobal(builder.makeGlobal(ASYNCIFY_DATA,
+                                         Type::i32,
+                                         builder.makeConst(int32_t(0)),
+                                         Builder::Mutable));
+  }
+
+  void addFunctions(Module* module) {
+    Builder builder(*module);
+    auto makeFunction = [&](Name name, bool setData, State state) {
+      std::vector<Type> params;
+      if (setData) {
+        params.push_back(Type::i32);
+      }
+      auto* body = builder.makeBlock();
+      body->list.push_back(builder.makeGlobalSet(
+        ASYNCIFY_STATE, builder.makeConst(int32_t(state))));
+      if (setData) {
+        body->list.push_back(builder.makeGlobalSet(
+          ASYNCIFY_DATA, builder.makeLocalGet(0, Type::i32)));
+      }
+      // Verify the data is valid.
+      auto* stackPos =
+        builder.makeLoad(4,
+                         false,
+                         int32_t(DataOffset::BStackPos),
+                         4,
+                         builder.makeGlobalGet(ASYNCIFY_DATA, Type::i32),
+                         Type::i32);
+      auto* stackEnd =
+        builder.makeLoad(4,
+                         false,
+                         int32_t(DataOffset::BStackEnd),
+                         4,
+                         builder.makeGlobalGet(ASYNCIFY_DATA, Type::i32),
+                         Type::i32);
+      body->list.push_back(
+        builder.makeIf(builder.makeBinary(GtUInt32, stackPos, stackEnd),
+                       builder.makeUnreachable()));
+      body->finalize();
+      auto* func = builder.makeFunction(
+        name, Signature(Type(params), Type::none), {}, body);
+      module->addFunction(func);
+      module->addExport(builder.makeExport(name, name, ExternalKind::Function));
+    };
+
+    makeFunction(ASYNCIFY_START_UNWIND, true, State::Unwinding);
+    makeFunction(ASYNCIFY_STOP_UNWIND, false, State::Normal);
+    makeFunction(ASYNCIFY_START_REWIND, true, State::Rewinding);
+    makeFunction(ASYNCIFY_STOP_REWIND, false, State::Normal);
+
+    module->addFunction(
+      builder.makeFunction(ASYNCIFY_GET_STATE,
+                           Signature(Type::none, Type::i32),
+                           {},
+                           builder.makeGlobalGet(ASYNCIFY_STATE, Type::i32)));
+    module->addExport(builder.makeExport(
+      ASYNCIFY_GET_STATE, ASYNCIFY_GET_STATE, ExternalKind::Function));
+  }
+};
+
+Pass* createAsyncifyPass() { return new Asyncify(); }
+
+// Helper passes that can be run after Asyncify.
+
+template<bool neverRewind, bool neverUnwind, bool importsAlwaysUnwind>
+struct ModAsyncify
+  : public WalkerPass<LinearExecutionWalker<
+      ModAsyncify<neverRewind, neverUnwind, importsAlwaysUnwind>>> {
+  bool isFunctionParallel() override { return true; }
+
+  ModAsyncify* create() override {
+    return new ModAsyncify<neverRewind, neverUnwind, importsAlwaysUnwind>();
+  }
+
+  void doWalkFunction(Function* func) {
+    // Find the asyncify state name.
+    auto* unwind = this->getModule()->getExport(ASYNCIFY_STOP_UNWIND);
+    auto* unwindFunc = this->getModule()->getFunction(unwind->value);
+    FindAll<GlobalSet> sets(unwindFunc->body);
+    assert(sets.list.size() == 1);
+    asyncifyStateName = sets.list[0]->name;
+    // Walk and optimize.
+    this->walk(func->body);
+  }
+
+  // Note that we don't just implement GetGlobal as we may know the value is
+  // *not* 0, 1, or 2, but not know the actual value. So what we can say depends
+  // on the comparison being done on it, and so we implement Binary and
+  // Select.
+
+  void visitBinary(Binary* curr) {
+    // Check if this is a comparison of the asyncify state to a specific
+    // constant, which we may know is impossible.
+    bool flip = false;
+    if (curr->op == NeInt32) {
+      flip = true;
+    } else if (curr->op != EqInt32) {
+      return;
+    }
+    auto* c = curr->right->dynCast<Const>();
+    if (!c) {
+      return;
+    }
+    auto* get = curr->left->dynCast<GlobalGet>();
+    if (!get || get->name != asyncifyStateName) {
+      return;
+    }
+    // This is a comparison of the state to a constant, check if we know the
+    // value.
+    int32_t value;
+    auto checkedValue = c->value.geti32();
+    if ((checkedValue == int(State::Unwinding) && neverUnwind) ||
+        (checkedValue == int(State::Rewinding) && neverRewind)) {
+      // We know the state is checked against an impossible value.
+      value = 0;
+    } else if (checkedValue == int(State::Unwinding) && this->unwinding) {
+      // We know we are in fact unwinding right now.
+      value = 1;
+      unsetUnwinding();
+    } else {
+      return;
+    }
+    if (flip) {
+      value = 1 - value;
+    }
+    Builder builder(*this->getModule());
+    this->replaceCurrent(builder.makeConst(int32_t(value)));
+  }
+
+  void visitSelect(Select* curr) {
+    auto* get = curr->condition->dynCast<GlobalGet>();
+    if (!get || get->name != asyncifyStateName) {
+      return;
+    }
+    // This is a comparison of the state to zero, which means we are checking
+    // "if running normally, run this code, but if rewinding, ignore it". If
+    // we know we'll never rewind, we can optimize this.
+    if (neverRewind) {
+      Builder builder(*this->getModule());
+      curr->condition = builder.makeConst(int32_t(0));
+    }
+  }
+
+  void visitCall(Call* curr) {
+    unsetUnwinding();
+    if (!importsAlwaysUnwind) {
+      return;
+    }
+    auto* target = this->getModule()->getFunction(curr->target);
+    if (!target->imported()) {
+      return;
+    }
+    // This is an import that definitely unwinds. Await the next check of
+    // the state in this linear execution trace, which we can turn into a
+    // constant.
+    this->unwinding = true;
+  }
+
+  void visitCallIndirect(CallIndirect* curr) { unsetUnwinding(); }
+
+  static void doNoteNonLinear(
+    ModAsyncify<neverRewind, neverUnwind, importsAlwaysUnwind>* self,
+    Expression**) {
+    // When control flow branches, stop tracking an unwinding.
+    self->unsetUnwinding();
+  }
+
+  void visitGlobalSet(GlobalSet* set) {
+    // TODO: this could be more precise
+    unsetUnwinding();
+  }
+
+private:
+  Name asyncifyStateName;
+
+  // Whether we just did a call to an import that indicates we are unwinding.
+  bool unwinding = false;
+
+  void unsetUnwinding() { this->unwinding = false; }
+};
+
+//
+// Assume imports that may unwind will always unwind, and that rewinding never
+// happens.
+//
+
+Pass* createModAsyncifyAlwaysOnlyUnwindPass() {
+  return new ModAsyncify<true, false, true>();
+}
+
+//
+// Assume that we never unwind, but may still rewind.
+//
+struct ModAsyncifyNeverUnwind : public Pass {
+  void run(PassRunner* runner, Module* module) override {}
+};
+
+Pass* createModAsyncifyNeverUnwindPass() {
+  return new ModAsyncify<false, true, false>();
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/AvoidReinterprets.cpp b/binaryen/src/passes/AvoidReinterprets.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/AvoidReinterprets.cpp
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ */
+
+// Avoids reinterprets by using more loads: if we load a value and
+// reinterpret it, we could have loaded it with the other type
+// anyhow. This uses more locals and loads, so it is not generally
+// beneficial, unless reinterprets are very costly (which is the case
+// with wasm2js).
+
+#include <ir/local-graph.h>
+#include <ir/properties.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+namespace wasm {
+
+static bool canReplaceWithReinterpret(Load* load) {
+  // We can replace a full-size load with a valid pointer with
+  // a reinterpret of the same address. A partial load would see
+  // more bytes and possibly invalid data, and an unreachable
+  // pointer is just not interesting to handle.
+  return load->type != Type::unreachable &&
+         load->bytes == load->type.getByteSize();
+}
+
+static Load* getSingleLoad(LocalGraph* localGraph,
+                           LocalGet* get,
+                           const PassOptions& passOptions,
+                           FeatureSet features) {
+  std::set<LocalGet*> seen;
+  seen.insert(get);
+  while (1) {
+    auto& sets = localGraph->getSetses[get];
+    if (sets.size() != 1) {
+      return nullptr;
+    }
+    auto* set = *sets.begin();
+    if (!set) {
+      return nullptr;
+    }
+    auto* value = Properties::getFallthrough(set->value, passOptions, features);
+    if (auto* parentGet = value->dynCast<LocalGet>()) {
+      if (seen.count(parentGet)) {
+        // We are in a cycle of gets, in unreachable code.
+        return nullptr;
+      }
+      get = parentGet;
+      seen.insert(get);
+      continue;
+    }
+    if (auto* load = value->dynCast<Load>()) {
+      return load;
+    }
+    return nullptr;
+  }
+}
+
+static bool isReinterpret(Unary* curr) {
+  return curr->op == ReinterpretInt32 || curr->op == ReinterpretInt64 ||
+         curr->op == ReinterpretFloat32 || curr->op == ReinterpretFloat64;
+}
+
+struct AvoidReinterprets : public WalkerPass<PostWalker<AvoidReinterprets>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new AvoidReinterprets; }
+
+  struct Info {
+    // Info used when analyzing.
+    bool reinterpreted;
+    // Info used when optimizing.
+    Index ptrLocal;
+    Index reinterpretedLocal;
+  };
+  std::map<Load*, Info> infos;
+
+  LocalGraph* localGraph;
+
+  void doWalkFunction(Function* func) {
+    // prepare
+    LocalGraph localGraph_(func);
+    localGraph = &localGraph_;
+    // walk
+    PostWalker<AvoidReinterprets>::doWalkFunction(func);
+    // optimize
+    optimize(func);
+  }
+
+  void visitUnary(Unary* curr) {
+    if (isReinterpret(curr)) {
+      FeatureSet features = getModule()->features;
+      if (auto* get =
+            Properties::getFallthrough(curr->value, getPassOptions(), features)
+              ->dynCast<LocalGet>()) {
+        if (auto* load =
+              getSingleLoad(localGraph, get, getPassOptions(), features)) {
+          auto& info = infos[load];
+          info.reinterpreted = true;
+        }
+      }
+    }
+  }
+
+  void optimize(Function* func) {
+    std::set<Load*> unoptimizables;
+    auto indexType = getModule()->memory.indexType;
+    for (auto& pair : infos) {
+      auto* load = pair.first;
+      auto& info = pair.second;
+      if (info.reinterpreted && canReplaceWithReinterpret(load)) {
+        // We should use another load here, to avoid reinterprets.
+        info.ptrLocal = Builder::addVar(func, indexType);
+        info.reinterpretedLocal =
+          Builder::addVar(func, load->type.reinterpret());
+      } else {
+        unoptimizables.insert(load);
+      }
+    }
+    for (auto* load : unoptimizables) {
+      infos.erase(load);
+    }
+    // We now know which we can optimize, and how.
+    struct FinalOptimizer : public PostWalker<FinalOptimizer> {
+      std::map<Load*, Info>& infos;
+      LocalGraph* localGraph;
+      Module* module;
+      const PassOptions& passOptions;
+
+      FinalOptimizer(std::map<Load*, Info>& infos,
+                     LocalGraph* localGraph,
+                     Module* module,
+                     const PassOptions& passOptions)
+        : infos(infos), localGraph(localGraph), module(module),
+          passOptions(passOptions) {}
+
+      void visitUnary(Unary* curr) {
+        if (isReinterpret(curr)) {
+          auto* value = curr->value;
+          if (auto* load = value->dynCast<Load>()) {
+            // A reinterpret of a load - flip it right here if we can.
+            if (canReplaceWithReinterpret(load)) {
+              replaceCurrent(makeReinterpretedLoad(load, load->ptr));
+            }
+          } else if (auto* get = value->dynCast<LocalGet>()) {
+            if (auto* load = getSingleLoad(
+                  localGraph, get, passOptions, module->features)) {
+              auto iter = infos.find(load);
+              if (iter != infos.end()) {
+                auto& info = iter->second;
+                // A reinterpret of a get of a load - use the new local.
+                Builder builder(*module);
+                replaceCurrent(builder.makeLocalGet(info.reinterpretedLocal,
+                                                    load->type.reinterpret()));
+              }
+            }
+          }
+        }
+      }
+
+      void visitLoad(Load* curr) {
+        auto iter = infos.find(curr);
+        if (iter != infos.end()) {
+          auto& info = iter->second;
+          Builder builder(*module);
+          auto* ptr = curr->ptr;
+          auto indexType = getModule()->memory.indexType;
+          curr->ptr = builder.makeLocalGet(info.ptrLocal, indexType);
+          // Note that the other load can have its sign set to false - if the
+          // original were an integer, the other is a float anyhow; and if
+          // original were a float, we don't know what sign to use.
+          replaceCurrent(builder.makeBlock(
+            {builder.makeLocalSet(info.ptrLocal, ptr),
+             builder.makeLocalSet(
+               info.reinterpretedLocal,
+               makeReinterpretedLoad(
+                 curr, builder.makeLocalGet(info.ptrLocal, indexType))),
+             curr}));
+        }
+      }
+
+      Load* makeReinterpretedLoad(Load* load, Expression* ptr) {
+        Builder builder(*module);
+        return builder.makeLoad(load->bytes,
+                                false,
+                                load->offset,
+                                load->align,
+                                ptr,
+                                load->type.reinterpret());
+      }
+    } finalOptimizer(infos, localGraph, getModule(), getPassOptions());
+
+    finalOptimizer.setModule(getModule());
+    finalOptimizer.walk(func->body);
+  }
+};
+
+Pass* createAvoidReinterpretsPass() { return new AvoidReinterprets(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/CMakeLists.txt b/binaryen/src/passes/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/CMakeLists.txt
@@ -0,0 +1,87 @@
+# Python 3.5 is the version shipped in Ubuntu Xenial
+find_package(PythonInterp 3.5 REQUIRED)
+
+add_custom_command(
+  OUTPUT WasmIntrinsics.cpp
+  COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/scripts/embedwat.py ${PROJECT_SOURCE_DIR}/src/passes/wasm-intrinsics.wat ${CMAKE_CURRENT_BINARY_DIR}/WasmIntrinsics.cpp
+  DEPENDS ${PROJECT_SOURCE_DIR}/scripts/embedwat.py wasm-intrinsics.wat)
+
+FILE(GLOB passes_HEADERS *.h)
+set(passes_SOURCES
+  pass.cpp
+  AlignmentLowering.cpp
+  Asyncify.cpp
+  AvoidReinterprets.cpp
+  CoalesceLocals.cpp
+  CodePushing.cpp
+  CodeFolding.cpp
+  ConstHoisting.cpp
+  DataFlowOpts.cpp
+  DeadArgumentElimination.cpp
+  DeadCodeElimination.cpp
+  DeAlign.cpp
+  DeNaN.cpp
+  Directize.cpp
+  DuplicateImportElimination.cpp
+  DuplicateFunctionElimination.cpp
+  DWARF.cpp
+  EmscriptenPIC.cpp
+  ExtractFunction.cpp
+  Flatten.cpp
+  FuncCastEmulation.cpp
+  GenerateDynCalls.cpp
+  I64ToI32Lowering.cpp
+  Inlining.cpp
+  InstrumentLocals.cpp
+  InstrumentMemory.cpp
+  LegalizeJSInterface.cpp
+  LimitSegments.cpp
+  LocalCSE.cpp
+  LogExecution.cpp
+  LoopInvariantCodeMotion.cpp
+  MemoryPacking.cpp
+  MergeBlocks.cpp
+  MergeLocals.cpp
+  Metrics.cpp
+  MinifyImportsAndExports.cpp
+  NameList.cpp
+  NoExitRuntime.cpp
+  OptimizeAddedConstants.cpp
+  OptimizeInstructions.cpp
+  PickLoadSigns.cpp
+  PostAssemblyScript.cpp
+  PostEmscripten.cpp
+  Precompute.cpp
+  Print.cpp
+  PrintCallGraph.cpp
+  PrintFeatures.cpp
+  PrintFunctionMap.cpp
+  RoundTrip.cpp
+  StackIR.cpp
+  Strip.cpp
+  StripTargetFeatures.cpp
+  RedundantSetElimination.cpp
+  RemoveImports.cpp
+  RemoveMemory.cpp
+  RemoveNonJSOps.cpp
+  ReplaceStackPointer.cpp
+  RemoveUnusedBrs.cpp
+  RemoveUnusedNames.cpp
+  RemoveUnusedModuleElements.cpp
+  ReorderLocals.cpp
+  ReorderFunctions.cpp
+  ReReloop.cpp
+  TrapMode.cpp
+  SafeHeap.cpp
+  SimplifyGlobals.cpp
+  SimplifyLocals.cpp
+  Souperify.cpp
+  SpillPointers.cpp
+  StackCheck.cpp
+  SSAify.cpp
+  Untee.cpp
+  Vacuum.cpp
+  ${CMAKE_CURRENT_BINARY_DIR}/WasmIntrinsics.cpp
+  ${passes_HEADERS}
+)
+add_library(passes OBJECT ${passes_SOURCES})
diff --git a/binaryen/src/passes/CoalesceLocals.cpp b/binaryen/src/passes/CoalesceLocals.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/CoalesceLocals.cpp
@@ -0,0 +1,574 @@
+/*
+ * 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.
+ */
+
+//
+// Coalesce locals, in order to reduce the total number of locals. This
+// is similar to register allocation, however, there is never any
+// spilling, and there isn't a fixed number of locals.
+//
+// NB: This pass is nonlinear in the number of locals. It is best to run it
+//     after the number of locals has been somewhat reduced by other passes,
+//     for example by simplify-locals (to remove unneeded uses of locals) and
+//     reorder-locals (to sort them by # of uses and remove all unneeded ones).
+//
+
+#include <algorithm>
+#include <memory>
+#include <unordered_set>
+
+#include "cfg/liveness-traversal.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "support/learning.h"
+#include "support/permutations.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+#ifdef CFG_PROFILE
+#include "support/timing.h"
+#endif
+
+namespace wasm {
+
+struct CoalesceLocals
+  : public WalkerPass<LivenessWalker<CoalesceLocals, Visitor<CoalesceLocals>>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new CoalesceLocals; }
+
+  // main entry point
+
+  void doWalkFunction(Function* func);
+
+  void increaseBackEdgePriorities();
+
+  void calculateInterferences();
+
+  void calculateInterferences(const SetOfLocals& locals);
+
+  void pickIndicesFromOrder(std::vector<Index>& order,
+                            std::vector<Index>& indices);
+  void pickIndicesFromOrder(std::vector<Index>& order,
+                            std::vector<Index>& indices,
+                            Index& removedCopies);
+
+  // returns a vector of oldIndex => newIndex
+  virtual void pickIndices(std::vector<Index>& indices);
+
+  void applyIndices(std::vector<Index>& indices, Expression* root);
+
+  // interference state
+
+  // canonicalized - accesses should check (low, high)
+  std::vector<bool> interferences;
+
+  void interfere(Index i, Index j) {
+    if (i == j) {
+      return;
+    }
+    interferences[std::min(i, j) * numLocals + std::max(i, j)] = 1;
+  }
+
+  // optimized version where you know that low < high
+  void interfereLowHigh(Index low, Index high) {
+    assert(low < high);
+    interferences[low * numLocals + high] = 1;
+  }
+
+  void unInterfere(Index i, Index j) {
+    interferences[std::min(i, j) * numLocals + std::max(i, j)] = 0;
+  }
+
+  bool interferes(Index i, Index j) {
+    return interferences[std::min(i, j) * numLocals + std::max(i, j)];
+  }
+};
+
+void CoalesceLocals::doWalkFunction(Function* func) {
+  if (!canRun(func)) {
+    return;
+  }
+  super::doWalkFunction(func);
+  // prioritize back edges
+  increaseBackEdgePriorities();
+  // use liveness to find interference
+  calculateInterferences();
+  // pick new indices
+  std::vector<Index> indices;
+  pickIndices(indices);
+  // apply indices
+  applyIndices(indices, func->body);
+}
+
+// A copy on a backedge can be especially costly, forcing us to branch just to
+// do that copy. Add weight to such copies, so we prioritize getting rid of
+// them.
+void CoalesceLocals::increaseBackEdgePriorities() {
+  for (auto* loopTop : loopTops) {
+    // ignore the first edge, it is the initial entry, we just want backedges
+    auto& in = loopTop->in;
+    for (Index i = 1; i < in.size(); i++) {
+      auto* arrivingBlock = in[i];
+      if (arrivingBlock->out.size() > 1) {
+        // we just want unconditional branches to the loop top, true phi
+        // fragments
+        continue;
+      }
+      for (auto& action : arrivingBlock->contents.actions) {
+        if (action.isSet()) {
+          auto* set = (*action.origin)->cast<LocalSet>();
+          if (auto* get = getCopy(set)) {
+            // this is indeed a copy, add to the cost (default cost is 2, so
+            // this adds 50%, and can mostly break ties)
+            addCopy(set->index, get->index);
+          }
+        }
+      }
+    }
+  }
+}
+
+void CoalesceLocals::calculateInterferences() {
+  interferences.resize(numLocals * numLocals);
+  std::fill(interferences.begin(), interferences.end(), false);
+  for (auto& curr : basicBlocks) {
+    if (liveBlocks.count(curr.get()) == 0) {
+      continue; // ignore dead blocks
+    }
+    // everything coming in might interfere, as it might come from a different
+    // block
+    auto live = curr->contents.end;
+    calculateInterferences(live);
+    // scan through the block itself
+    auto& actions = curr->contents.actions;
+    for (int i = int(actions.size()) - 1; i >= 0; i--) {
+      auto& action = actions[i];
+      auto index = action.index;
+      if (action.isGet()) {
+        // new live local, interferes with all the rest
+        live.insert(index);
+        for (auto i : live) {
+          interfere(i, index);
+        }
+      } else {
+        if (live.erase(index)) {
+          action.effective = true;
+        }
+      }
+    }
+  }
+  // Params have a value on entry, so mark them as live, as variables
+  // live at the entry expect their zero-init value.
+  SetOfLocals start = entry->contents.start;
+  auto numParams = getFunction()->getNumParams();
+  for (Index i = 0; i < numParams; i++) {
+    start.insert(i);
+  }
+  calculateInterferences(start);
+}
+
+void CoalesceLocals::calculateInterferences(const SetOfLocals& locals) {
+  Index size = locals.size();
+  for (Index i = 0; i < size; i++) {
+    for (Index j = i + 1; j < size; j++) {
+      interfereLowHigh(locals[i], locals[j]);
+    }
+  }
+}
+
+// Indices decision making
+
+void CoalesceLocals::pickIndicesFromOrder(std::vector<Index>& order,
+                                          std::vector<Index>& indices) {
+  Index removedCopies;
+  pickIndicesFromOrder(order, indices, removedCopies);
+}
+
+void CoalesceLocals::pickIndicesFromOrder(std::vector<Index>& order,
+                                          std::vector<Index>& indices,
+                                          Index& removedCopies) {
+// mostly-simple greedy coloring
+#if CFG_DEBUG
+  std::cerr << "\npickIndicesFromOrder on " << getFunction()->name << '\n';
+  std::cerr << getFunction()->body << '\n';
+  std::cerr << "order:\n";
+  for (auto i : order)
+    std::cerr << i << ' ';
+  std::cerr << '\n';
+  std::cerr << "interferences:\n";
+  for (Index i = 0; i < numLocals; i++) {
+    for (Index j = 0; j < i + 1; j++) {
+      std::cerr << "  ";
+    }
+    for (Index j = i + 1; j < numLocals; j++) {
+      std::cerr << int(interferes(i, j)) << ' ';
+    }
+    std::cerr << " : $" << i << '\n';
+  }
+  std::cerr << "copies:\n";
+  for (Index i = 0; i < numLocals; i++) {
+    for (Index j = 0; j < i + 1; j++) {
+      std::cerr << "  ";
+    }
+    for (Index j = i + 1; j < numLocals; j++) {
+      std::cerr << int(getCopies(i, j)) << ' ';
+    }
+    std::cerr << " : $" << i << '\n';
+  }
+  std::cerr << "total copies:\n";
+  for (Index i = 0; i < numLocals; i++) {
+    std::cerr << " $" << i << ": " << totalCopies[i] << '\n';
+  }
+#endif
+  // TODO: take into account distribution (99-1 is better than 50-50 with two
+  // registers, for gzip)
+  std::vector<Type> types;
+  // new index * numLocals => list of all interferences of locals merged to it
+  std::vector<bool> newInterferences;
+  // new index * numLocals => list of all copies of locals merged to it
+  std::vector<uint8_t> newCopies;
+  indices.resize(numLocals);
+  types.resize(numLocals);
+  newInterferences.resize(numLocals * numLocals);
+  std::fill(newInterferences.begin(), newInterferences.end(), false);
+  auto numParams = getFunction()->getNumParams();
+  // start with enough room for the params
+  newCopies.resize(numParams * numLocals);
+  std::fill(newCopies.begin(), newCopies.end(), 0);
+  Index nextFree = 0;
+  removedCopies = 0;
+  // we can't reorder parameters, they are fixed in order, and cannot coalesce
+  Index i = 0;
+  for (; i < numParams; i++) {
+    assert(order[i] == i); // order must leave the params in place
+    indices[i] = i;
+    types[i] = getFunction()->getLocalType(i);
+    for (Index j = numParams; j < numLocals; j++) {
+      newInterferences[numLocals * i + j] = interferes(i, j);
+      newCopies[numLocals * i + j] = getCopies(i, j);
+    }
+    nextFree++;
+  }
+  for (; i < numLocals; i++) {
+    Index actual = order[i];
+    Index found = -1;
+    uint8_t foundCopies = -1;
+    for (Index j = 0; j < nextFree; j++) {
+      if (!newInterferences[j * numLocals + actual] &&
+          getFunction()->getLocalType(actual) == types[j]) {
+        // this does not interfere, so it might be what we want. but pick the
+        // one eliminating the most copies (we could stop looking forward when
+        // there are no more items that have copies anyhow, but it doesn't seem
+        // to help)
+        auto currCopies = newCopies[j * numLocals + actual];
+        if (found == Index(-1) || currCopies > foundCopies) {
+          indices[actual] = found = j;
+          foundCopies = currCopies;
+        }
+      }
+    }
+    if (found == Index(-1)) {
+      indices[actual] = found = nextFree;
+      types[found] = getFunction()->getLocalType(actual);
+      nextFree++;
+      removedCopies += getCopies(found, actual);
+      newCopies.resize(nextFree * numLocals);
+    } else {
+      removedCopies += foundCopies;
+    }
+#if CFG_DEBUG
+    std::cerr << "set local $" << actual << " to $" << found << '\n';
+#endif
+    // merge new interferences and copies for the new index
+    for (Index k = i + 1; k < numLocals; k++) {
+      // go in the order, we only need to update for those we will see later
+      auto j = order[k];
+      newInterferences[found * numLocals + j] =
+        newInterferences[found * numLocals + j] | interferes(actual, j);
+      newCopies[found * numLocals + j] += getCopies(actual, j);
+    }
+  }
+}
+
+// given a baseline order, adjust it based on an important order of priorities
+// (higher values are higher priority). The priorities take precedence, unless
+// they are equal and then the original order should be kept.
+std::vector<Index> adjustOrderByPriorities(std::vector<Index>& baseline,
+                                           std::vector<Index>& priorities) {
+  std::vector<Index> ret = baseline;
+  std::vector<Index> reversed = makeReversed(baseline);
+  std::sort(ret.begin(), ret.end(), [&priorities, &reversed](Index x, Index y) {
+    return priorities[x] > priorities[y] ||
+           (priorities[x] == priorities[y] && reversed[x] < reversed[y]);
+  });
+  return ret;
+}
+
+void CoalesceLocals::pickIndices(std::vector<Index>& indices) {
+  if (numLocals == 0) {
+    return;
+  }
+  if (numLocals == 1) {
+    indices.push_back(0);
+    return;
+  }
+  // take into account total copies. but we must keep params in place, so give
+  // them max priority
+  auto adjustedTotalCopies = totalCopies;
+  auto numParams = getFunction()->getNumParams();
+  for (Index i = 0; i < numParams; i++) {
+    adjustedTotalCopies[i] = std::numeric_limits<Index>::max();
+  }
+  // first try the natural order. this is less arbitrary than it seems, as the
+  // program may have a natural order of locals inherent in it.
+  auto order = makeIdentity(numLocals);
+  order = adjustOrderByPriorities(order, adjustedTotalCopies);
+  Index removedCopies;
+  pickIndicesFromOrder(order, indices, removedCopies);
+  auto maxIndex = *std::max_element(indices.begin(), indices.end());
+  // next try the reverse order. this both gives us another chance at something
+  // good, and also the very naturalness of the simple order may be quite
+  // suboptimal
+  setIdentity(order);
+  for (Index i = numParams; i < numLocals; i++) {
+    order[i] = numParams + numLocals - 1 - i;
+  }
+  order = adjustOrderByPriorities(order, adjustedTotalCopies);
+  std::vector<Index> reverseIndices;
+  Index reverseRemovedCopies;
+  pickIndicesFromOrder(order, reverseIndices, reverseRemovedCopies);
+  auto reverseMaxIndex =
+    *std::max_element(reverseIndices.begin(), reverseIndices.end());
+  // prefer to remove copies foremost, as it matters more for code size (minus
+  // gzip), and improves throughput.
+  if (reverseRemovedCopies > removedCopies ||
+      (reverseRemovedCopies == removedCopies && reverseMaxIndex < maxIndex)) {
+    indices.swap(reverseIndices);
+  }
+}
+
+void CoalesceLocals::applyIndices(std::vector<Index>& indices,
+                                  Expression* root) {
+  assert(indices.size() == numLocals);
+  for (auto& curr : basicBlocks) {
+    auto& actions = curr->contents.actions;
+    for (auto& action : actions) {
+      if (action.isGet()) {
+        auto* get = (*action.origin)->cast<LocalGet>();
+        get->index = indices[get->index];
+      } else if (action.isSet()) {
+        auto* set = (*action.origin)->cast<LocalSet>();
+        set->index = indices[set->index];
+        // in addition, we can optimize out redundant copies and ineffective
+        // sets
+        LocalGet* get;
+        if ((get = set->value->dynCast<LocalGet>()) &&
+            get->index == set->index) {
+          action.removeCopy();
+          continue;
+        }
+        // remove ineffective actions
+        if (!action.effective) {
+          // value may have no side effects, further optimizations can eliminate
+          // it
+          *action.origin = set->value;
+          if (!set->isTee()) {
+            // we need to drop it
+            Drop* drop = ExpressionManipulator::convert<LocalSet, Drop>(set);
+            drop->value = *action.origin;
+            *action.origin = drop;
+          }
+          continue;
+        }
+      }
+    }
+  }
+  // update type list
+  auto numParams = getFunction()->getNumParams();
+  Index newNumLocals = 0;
+  for (auto index : indices) {
+    newNumLocals = std::max(newNumLocals, index + 1);
+  }
+  auto oldVars = getFunction()->vars;
+  getFunction()->vars.resize(newNumLocals - numParams);
+  for (Index index = numParams; index < numLocals; index++) {
+    Index newIndex = indices[index];
+    if (newIndex >= numParams) {
+      getFunction()->vars[newIndex - numParams] = oldVars[index - numParams];
+    }
+  }
+  // names are gone
+  getFunction()->localNames.clear();
+  getFunction()->localIndices.clear();
+}
+
+struct CoalesceLocalsWithLearning : public CoalesceLocals {
+  virtual Pass* create() override { return new CoalesceLocalsWithLearning; }
+
+  virtual void pickIndices(std::vector<Index>& indices) override;
+};
+
+void CoalesceLocalsWithLearning::pickIndices(std::vector<Index>& indices) {
+  if (getFunction()->getNumVars() <= 1) {
+    // nothing to think about here
+    CoalesceLocals::pickIndices(indices);
+    return;
+  }
+
+  struct Order : public std::vector<Index> {
+    void setFitness(double f) { fitness = f; }
+    double getFitness() { return fitness; }
+    void dump(std::string text) {
+      std::cout << text + ": ( ";
+      for (Index i = 0; i < size(); i++) {
+        std::cout << (*this)[i] << " ";
+      }
+      std::cout << ")\n";
+      std::cout << "of quality: " << getFitness() << "\n";
+    }
+
+  private:
+    double fitness;
+  };
+
+  struct Generator {
+    Generator(CoalesceLocalsWithLearning* parent) : parent(parent), noise(42) {}
+
+    void calculateFitness(Order* order) {
+      // apply the order
+      std::vector<Index> indices; // the phenotype
+      Index removedCopies;
+      parent->pickIndicesFromOrder(*order, indices, removedCopies);
+      auto maxIndex = *std::max_element(indices.begin(), indices.end());
+      assert(maxIndex <= parent->numLocals);
+      // main part of fitness is the number of locals
+      double fitness = parent->numLocals - maxIndex; // higher fitness is better
+      // secondarily, it is nice to not reorder locals unnecessarily
+      double fragment = 1.0 / (2.0 * parent->numLocals);
+      for (Index i = 0; i < parent->numLocals; i++) {
+        if ((*order)[i] == i) {
+          fitness += fragment; // boost for each that wasn't moved
+        }
+      }
+      // removing copies is a secondary concern
+      fitness = (100 * fitness) + removedCopies;
+      order->setFitness(fitness);
+    }
+
+    Order* makeRandom() {
+      auto* ret = new Order;
+      ret->resize(parent->numLocals);
+      for (Index i = 0; i < parent->numLocals; i++) {
+        (*ret)[i] = i;
+      }
+      if (first) {
+        // as the first guess, use the natural order. this is not arbitrary for
+        // two reasons. first, there may be an inherent order in the input
+        // (frequent indices are lower, etc.). second, by ensuring we start with
+        // the natural order, we ensure we are at least as good as the
+        // non-learning variant.
+        // TODO: use ::pickIndices from the parent, so we literally get the
+        //       simpler approach as our first option
+        first = false;
+      } else {
+        // leave params alone, shuffle the rest
+        std::shuffle(ret->begin() + parent->getFunction()->getNumParams(),
+                     ret->end(),
+                     noise);
+      }
+      calculateFitness(ret);
+#ifdef CFG_LEARN_DEBUG
+      order->dump("new rando");
+#endif
+      return ret;
+    }
+
+    Order* makeMixture(Order* left, Order* right) {
+      // perturb left using right. this is useful since
+      // we don't care about absolute locations, relative ones matter more,
+      // and a true merge of two vectors could obscure that (e.g.
+      // a.......... and ..........a would merge a into the middle, for no
+      // reason), and cause a lot of unnecessary noise
+      Index size = left->size();
+      Order reverseRight; // reverseRight[x] is the index of x in right
+      reverseRight.resize(size);
+      for (Index i = 0; i < size; i++) {
+        reverseRight[(*right)[i]] = i;
+      }
+      auto* ret = new Order;
+      *ret = *left;
+      assert(size >= 1);
+      for (Index i = parent->getFunction()->getNumParams(); i < size - 1; i++) {
+        // if (i, i + 1) is in reverse order in right, flip them
+        if (reverseRight[(*ret)[i]] > reverseRight[(*ret)[i + 1]]) {
+          std::swap((*ret)[i], (*ret)[i + 1]);
+          // if we don't skip, we might end up pushing an element all the way to
+          // the end, which is not very perturbation-y
+          i++;
+        }
+      }
+      calculateFitness(ret);
+#ifdef CFG_LEARN_DEBUG
+      ret->dump("new mixture");
+#endif
+      return ret;
+    }
+
+  private:
+    CoalesceLocalsWithLearning* parent;
+    std::mt19937 noise;
+    bool first = true;
+  };
+
+#ifdef CFG_LEARN_DEBUG
+  std::cout << "[learning for " << getFunction()->name << "]\n";
+#endif
+  auto numVars = this->getFunction()->getNumVars();
+  const int GENERATION_SIZE =
+    std::min(Index(numVars * (numVars - 1)), Index(20));
+  Generator generator(this);
+  GeneticLearner<Order, double, Generator> learner(generator, GENERATION_SIZE);
+#ifdef CFG_LEARN_DEBUG
+  learner.getBest()->dump("first best");
+#endif
+  // keep working while we see improvement
+  auto oldBest = learner.getBest()->getFitness();
+  while (1) {
+    learner.runGeneration();
+    auto newBest = learner.getBest()->getFitness();
+    if (newBest == oldBest) {
+      break; // unlikely we can improve
+    }
+    oldBest = newBest;
+#ifdef CFG_LEARN_DEBUG
+    learner.getBest()->dump("current best");
+#endif
+  }
+#ifdef CFG_LEARN_DEBUG
+  learner.getBest()->dump("the best");
+#endif
+  // TODO: cache indices in Orders, at the cost of more memory?
+  this->pickIndicesFromOrder(*learner.getBest(), indices);
+}
+
+// declare passes
+
+Pass* createCoalesceLocalsPass() { return new CoalesceLocals(); }
+
+Pass* createCoalesceLocalsWithLearningPass() {
+  return new CoalesceLocalsWithLearning();
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/CodeFolding.cpp b/binaryen/src/passes/CodeFolding.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/CodeFolding.cpp
@@ -0,0 +1,759 @@
+/*
+ * 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.
+ */
+
+//
+// Folds duplicate code together, saving space (and possibly phis in
+// the wasm VM, which can save time).
+//
+// We fold tails of code where they merge and moving the code
+// to the merge point is helpful. There are two cases here: (1) expressions,
+// in which we merge to right after the expression itself, in these cases:
+//  * blocks, we merge the fallthrough + the breaks
+//  * if-else, we merge the arms
+// and (2) the function body as a whole, in which we can merge returns or
+// unreachables, putting the merged code at the end of the function body.
+//
+// For example, with an if-else, we might merge this:
+//  (if (condition)
+//    (block
+//      A
+//      C
+//    )
+//    (block
+//      B
+//      C
+//    )
+//  )
+// to
+//  (if (condition)
+//    (block
+//      A
+//    )
+//    (block
+//      B
+//    )
+//  )
+//  C
+//
+// Note that the merged code, C in the example above, can be anything,
+// including code with control flow. If C is identical in all the locations,
+// then it must be safe to merge (if it contains a branch to something
+// higher up, then since our branch target names are unique, it must be
+// to the same thing, and after merging it can still reach it).
+//
+
+#include <iterator>
+
+#include "ir/branch-utils.h"
+#include "ir/effects.h"
+#include "ir/find_all.h"
+#include "ir/label-utils.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+static const Index WORTH_ADDING_BLOCK_TO_REMOVE_THIS_MUCH = 3;
+
+struct ExpressionMarker
+  : public PostWalker<ExpressionMarker,
+                      UnifiedExpressionVisitor<ExpressionMarker>> {
+  std::set<Expression*>& marked;
+
+  ExpressionMarker(std::set<Expression*>& marked, Expression* expr)
+    : marked(marked) {
+    walk(expr);
+  }
+
+  void visitExpression(Expression* expr) { marked.insert(expr); }
+};
+
+struct CodeFolding : public WalkerPass<ControlFlowWalker<CodeFolding>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new CodeFolding; }
+
+  // information about a "tail" - code that reaches a point that we can
+  // merge (e.g., a branch and some code leading up to it)
+  struct Tail {
+    Expression* expr; // nullptr if this is a fallthrough
+    Block* block; // the enclosing block of code we hope to merge at its tail
+    Expression** pointer; // for an expr with no parent block, the location it
+                          // is at, so we can replace it
+
+    // For a fallthrough
+    Tail(Block* block) : expr(nullptr), block(block), pointer(nullptr) {}
+    // For a break
+    Tail(Expression* expr, Block* block)
+      : expr(expr), block(block), pointer(nullptr) {
+      validate();
+    }
+    Tail(Expression* expr, Expression** pointer)
+      : expr(expr), block(nullptr), pointer(pointer) {}
+
+    bool isFallthrough() const { return expr == nullptr; }
+
+    void validate() const {
+      if (expr && block) {
+        assert(block->list.back() == expr);
+      }
+    }
+  };
+
+  // state
+
+  bool anotherPass;
+
+  // pass state
+
+  std::map<Name, std::vector<Tail>> breakTails; // break target name => tails
+                                                // that reach it
+  std::vector<Tail> unreachableTails; // tails leading to (unreachable)
+  std::vector<Tail> returnTails;      // tails leading to (return)
+  std::set<Name> unoptimizables;      // break target names that we can't handle
+  std::set<Expression*> modifieds;    // modified code should not be processed
+                                      // again, wait for next pass
+
+  // walking
+
+  void visitBreak(Break* curr) {
+    if (curr->condition || curr->value) {
+      unoptimizables.insert(curr->name);
+    } else {
+      // we can only optimize if we are at the end of the parent block,
+      // and if the parent block does not return a value (we can't move
+      // elements out of it if there is a value being returned)
+      Block* parent = controlFlowStack.back()->dynCast<Block>();
+      if (parent && curr == parent->list.back() &&
+          !parent->list.back()->type.isConcrete()) {
+        breakTails[curr->name].push_back(Tail(curr, parent));
+      } else {
+        unoptimizables.insert(curr->name);
+      }
+    }
+  }
+
+  void visitSwitch(Switch* curr) {
+    for (auto target : curr->targets) {
+      unoptimizables.insert(target);
+    }
+    unoptimizables.insert(curr->default_);
+  }
+
+  void visitBrOnExn(BrOnExn* curr) { unoptimizables.insert(curr->name); }
+
+  void visitUnreachable(Unreachable* curr) {
+    // we can only optimize if we are at the end of the parent block
+    if (!controlFlowStack.empty()) {
+      Block* parent = controlFlowStack.back()->dynCast<Block>();
+      if (parent && curr == parent->list.back()) {
+        unreachableTails.push_back(Tail(curr, parent));
+      }
+    }
+  }
+
+  void visitReturn(Return* curr) {
+    if (!controlFlowStack.empty()) {
+      // we can easily optimize if we are at the end of the parent block
+      Block* parent = controlFlowStack.back()->dynCast<Block>();
+      if (parent && curr == parent->list.back()) {
+        returnTails.push_back(Tail(curr, parent));
+        return;
+      }
+    }
+    // otherwise, if we have a large value, it might be worth optimizing us as
+    // well
+    returnTails.push_back(Tail(curr, getCurrentPointer()));
+  }
+
+  void visitBlock(Block* curr) {
+    if (curr->list.empty()) {
+      return;
+    }
+    if (!curr->name.is()) {
+      return;
+    }
+    if (unoptimizables.count(curr->name) > 0) {
+      return;
+    }
+    // we can't optimize a fallthrough value
+    if (curr->list.back()->type.isConcrete()) {
+      return;
+    }
+    auto iter = breakTails.find(curr->name);
+    if (iter == breakTails.end()) {
+      return;
+    }
+    // looks promising
+    auto& tails = iter->second;
+    // see if there is a fallthrough
+    bool hasFallthrough = true;
+    for (auto* child : curr->list) {
+      if (child->type == Type::unreachable) {
+        hasFallthrough = false;
+      }
+    }
+    if (hasFallthrough) {
+      tails.push_back({Tail(curr)});
+    }
+    optimizeExpressionTails(tails, curr);
+  }
+
+  void visitIf(If* curr) {
+    if (!curr->ifFalse) {
+      return;
+    }
+    // if both sides are identical, this is easy to fold
+    if (ExpressionAnalyzer::equal(curr->ifTrue, curr->ifFalse)) {
+      Builder builder(*getModule());
+      // remove if (4 bytes), remove one arm, add drop (1), add block (3),
+      // so this must be a net savings
+      markAsModified(curr);
+      auto* ret =
+        builder.makeSequence(builder.makeDrop(curr->condition), curr->ifTrue);
+      // we must ensure we present the same type as the if had
+      ret->finalize(curr->type);
+      replaceCurrent(ret);
+    } else {
+      // if both are blocks, look for a tail we can merge
+      auto* left = curr->ifTrue->dynCast<Block>();
+      auto* right = curr->ifFalse->dynCast<Block>();
+      // If one is a block and the other isn't, and the non-block is a tail
+      // of the other, we can fold that - for our convenience, we just add
+      // a block and run the rest of the optimization mormally.
+      auto maybeAddBlock = [this](Block* block, Expression*& other) -> Block* {
+        // if other is a suffix of the block, wrap it in a block
+        if (block->list.empty() ||
+            !ExpressionAnalyzer::equal(other, block->list.back())) {
+          return nullptr;
+        }
+        // do it, assign to the out param `other`, and return the block
+        Builder builder(*getModule());
+        auto* ret = builder.makeBlock(other);
+        other = ret;
+        return ret;
+      };
+      if (left && !right) {
+        right = maybeAddBlock(left, curr->ifFalse);
+      } else if (!left && right) {
+        left = maybeAddBlock(right, curr->ifTrue);
+      }
+      // we need nameless blocks, as if there is a name, someone might branch
+      // to the end, skipping the code we want to merge
+      if (left && right && !left->name.is() && !right->name.is()) {
+        std::vector<Tail> tails = {Tail(left), Tail(right)};
+        optimizeExpressionTails(tails, curr);
+      }
+    }
+  }
+
+  void doWalkFunction(Function* func) {
+    anotherPass = true;
+    while (anotherPass) {
+      anotherPass = false;
+      super::doWalkFunction(func);
+      optimizeTerminatingTails(unreachableTails);
+      // optimize returns at the end, so we can benefit from a fallthrough if
+      // there is a value TODO: separate passes for them?
+      optimizeTerminatingTails(returnTails);
+      // TODO add fallthrough for returns
+      // TODO optimize returns not in blocks, a big return value can be worth it
+      // clean up
+      breakTails.clear();
+      unreachableTails.clear();
+      returnTails.clear();
+      unoptimizables.clear();
+      modifieds.clear();
+      // if we did any work, types may need to be propagated
+      if (anotherPass) {
+        ReFinalize().walkFunctionInModule(func, getModule());
+      }
+    }
+  }
+
+private:
+  // check if we can move a list of items out of another item. we can't do so
+  // if one of the items has a branch to something inside outOf that is not
+  // inside that item
+  bool canMove(const std::vector<Expression*>& items, Expression* outOf) {
+    auto allTargets = BranchUtils::getBranchTargets(outOf);
+    for (auto* item : items) {
+      auto exiting = BranchUtils::getExitingBranches(item);
+      std::vector<Name> intersection;
+      std::set_intersection(allTargets.begin(),
+                            allTargets.end(),
+                            exiting.begin(),
+                            exiting.end(),
+                            std::back_inserter(intersection));
+      if (intersection.size() > 0) {
+        // anything exiting that is in all targets is something bad
+        return false;
+      }
+      if (getModule()->features.hasExceptionHandling()) {
+        EffectAnalyzer effects(getPassOptions(), getModule()->features, item);
+        // Currently pop instructions are only used for exnref.pop, which is a
+        // pseudo instruction following a catch. We cannot move expressions
+        // containing pops if they are not enclosed in a 'catch' body, because a
+        // pop instruction should follow right after 'catch'.
+        if (effects.danglingPop) {
+          return false;
+        }
+        // When an expression can throw and it is within a try scope, taking it
+        // out of the try scope changes the program's behavior, because the
+        // expression that would otherwise have been caught by the try now
+        // throws up to the next try scope or even up to the caller. We restrict
+        // the move if 'outOf' contains a 'try' anywhere in it. This is a
+        // conservative approximation because there can be cases that 'try' is
+        // within the expression that may throw so it is safe to take the
+        // expression out.
+        if (effects.throws && !FindAll<Try>(outOf).list.empty()) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  // optimize tails that reach the outside of an expression. code that is
+  // identical in all paths leading to the block exit can be merged.
+  template<typename T>
+  void optimizeExpressionTails(std::vector<Tail>& tails, T* curr) {
+    if (tails.size() < 2) {
+      return;
+    }
+    // see if anything is untoward, and we should not do this
+    for (auto& tail : tails) {
+      if (tail.expr && modifieds.count(tail.expr) > 0) {
+        return;
+      }
+      if (modifieds.count(tail.block) > 0) {
+        return;
+      }
+      // if we were not modified, then we should be valid for processing
+      tail.validate();
+    }
+    // we can ignore the final br in a tail
+    auto effectiveSize = [&](const Tail& tail) {
+      auto ret = tail.block->list.size();
+      if (!tail.isFallthrough()) {
+        ret--;
+      }
+      return ret;
+    };
+    // the mergeable items do not include the final br in a tail
+    auto getMergeable = [&](const Tail& tail, Index num) {
+      return tail.block->list[effectiveSize(tail) - num - 1];
+    };
+    // we are going to remove duplicate elements and add a block.
+    // so for this to make sense, we need the size of the duplicate
+    // elements to be worth that extra block (although, there is
+    // some chance the block would get merged higher up, see later)
+    std::vector<Expression*> mergeable; // the elements we can merge
+    Index num = 0;   // how many elements back from the tail to look at
+    Index saved = 0; // how much we can save
+    while (1) {
+      // check if this num is still relevant
+      bool stop = false;
+      for (auto& tail : tails) {
+        assert(tail.block);
+        if (num >= effectiveSize(tail)) {
+          // one of the lists is too short
+          stop = true;
+          break;
+        }
+      }
+      if (stop) {
+        break;
+      }
+      auto* item = getMergeable(tails[0], num);
+      for (auto& tail : tails) {
+        if (!ExpressionAnalyzer::equal(item, getMergeable(tail, num))) {
+          // one of the lists has a different item
+          stop = true;
+          break;
+        }
+      }
+      if (stop) {
+        break;
+      }
+      // we may have found another one we can merge - can we move it?
+      if (!canMove({item}, curr)) {
+        break;
+      }
+      // we found another one we can merge
+      mergeable.push_back(item);
+      num++;
+      saved += Measurer::measure(item);
+    }
+    if (saved == 0) {
+      return;
+    }
+    // we may be able to save enough.
+    if (saved < WORTH_ADDING_BLOCK_TO_REMOVE_THIS_MUCH) {
+      // it's not obvious we can save enough. see if we get rid
+      // of a block, that would justify this
+      bool willEmptyBlock = false;
+      for (auto& tail : tails) {
+        // it is enough to zero out the block, or leave just one
+        // element, as then the block can be replaced with that
+        if (num >= tail.block->list.size() - 1) {
+          willEmptyBlock = true;
+          break;
+        }
+      }
+      if (!willEmptyBlock) {
+        // last chance, if our parent is a block, then it should be
+        // fine to create a new block here, it will be merged up
+        // we are an if or a block, at the top
+        assert(curr == controlFlowStack.back());
+        if (controlFlowStack.size() <= 1) {
+          return; // no parent at all
+          // TODO: if we are the toplevel in the function, then in the binary
+          //       format we might avoid emitting a block, so the same logic
+          //       applies here?
+        }
+        auto* parent =
+          controlFlowStack[controlFlowStack.size() - 2]->dynCast<Block>();
+        if (!parent) {
+          return; // parent is not a block
+        }
+        bool isChild = false;
+        for (auto* child : parent->list) {
+          if (child == curr) {
+            isChild = true;
+            break;
+          }
+        }
+        if (!isChild) {
+          return; // not a child, something in between
+        }
+      }
+    }
+    // this is worth doing, do it!
+    for (auto& tail : tails) {
+      // remove the items we are merging / moving
+      // first, mark them as modified, so we don't try to handle them
+      // again in this pass, which might be buggy
+      markAsModified(tail.block);
+      // we must preserve the br if there is one
+      Expression* last = nullptr;
+      if (!tail.isFallthrough()) {
+        last = tail.block->list.back();
+        tail.block->list.pop_back();
+      }
+      for (Index i = 0; i < mergeable.size(); i++) {
+        tail.block->list.pop_back();
+      }
+      if (!tail.isFallthrough()) {
+        tail.block->list.push_back(last);
+      }
+      // the block type may change if we removed unreachable stuff,
+      // but in general it should remain the same, as if it had a
+      // forced type it should remain, *and*, we don't have a
+      // fallthrough value (we would never get here), so a concrete
+      // type was not from that. I.e., any type on the block is
+      // either forced and/or from breaks with a value, so the
+      // type cannot be changed by moving code out.
+      tail.block->finalize(tail.block->type);
+    }
+    // since we managed a merge, then it might open up more opportunities later
+    anotherPass = true;
+    // make a block with curr + the merged code
+    Builder builder(*getModule());
+    auto* block = builder.makeBlock();
+    block->list.push_back(curr);
+    while (!mergeable.empty()) {
+      block->list.push_back(mergeable.back());
+      mergeable.pop_back();
+    }
+    auto oldType = curr->type;
+    // NB: we template-specialize so that this calls the proper finalizer for
+    //     the type
+    curr->finalize();
+    // ensure the replacement has the same type, so the outside is not surprised
+    block->finalize(oldType);
+    replaceCurrent(block);
+  }
+
+  // optimize tails that terminate control flow in this function, so we
+  // are (1) merge just a few of them, we don't need all like with the
+  // branches to a block, and (2) we do it on the function body.
+  // num is the depth, i.e., how many tail items we can merge. 0 means
+  // we are just starting; num > 0 means that tails is guaranteed to be
+  // equal in the last num items, so we can merge there, but we look for
+  // deeper merges first.
+  // returns whether we optimized something.
+  bool optimizeTerminatingTails(std::vector<Tail>& tails, Index num = 0) {
+    if (tails.size() < 2) {
+      return false;
+    }
+    // remove things that are untoward and cannot be optimized
+    tails.erase(
+      std::remove_if(tails.begin(),
+                     tails.end(),
+                     [&](Tail& tail) {
+                       if (tail.expr && modifieds.count(tail.expr) > 0) {
+                         return true;
+                       }
+                       if (tail.block && modifieds.count(tail.block) > 0) {
+                         return true;
+                       }
+                       // if we were not modified, then we should be valid for
+                       // processing
+                       tail.validate();
+                       return false;
+                     }),
+      tails.end());
+    // now let's try to find subsets that are mergeable. we don't look hard
+    // for the most optimal; further passes may find more
+    // effectiveSize: TODO: special-case fallthrough, matters for returns
+    auto effectiveSize = [&](Tail& tail) -> Index {
+      if (tail.block) {
+        return tail.block->list.size();
+      } else {
+        return 1;
+      }
+    };
+    // getItem: returns the relevant item from the tail. this includes the
+    //          final item
+    //          TODO: special-case fallthrough, matters for returns
+    auto getItem = [&](Tail& tail, Index num) {
+      if (tail.block) {
+        return tail.block->list[effectiveSize(tail) - num - 1];
+      } else {
+        return tail.expr;
+      }
+    };
+    // gets the tail elements of a certain depth
+    auto getTailItems = [&](Index num, std::vector<Tail>& tails) {
+      std::vector<Expression*> items;
+      for (Index i = 0; i < num; i++) {
+        auto item = getItem(tails[0], i);
+        items.push_back(item);
+      }
+      return items;
+    };
+    // estimate if a merging is worth the cost
+    auto worthIt = [&](Index num, std::vector<Tail>& tails) {
+      auto items = getTailItems(num, tails); // the elements we can merge
+      Index saved = 0;                       // how much we can save
+      for (auto* item : items) {
+        saved += Measurer::measure(item) * (tails.size() - 1);
+      }
+      // compure the cost: in non-fallthroughs, we are replacing the final
+      // element with a br; for a fallthrough, if there is one, we must
+      // add a return element (for the function body, so it doesn't reach us)
+      // TODO: handle fallthroughts for return
+      Index cost = tails.size();
+      // we also need to add two blocks: for us to break to, and to contain
+      // that block and the merged code. very possibly one of the blocks
+      // can be removed, though
+      cost += WORTH_ADDING_BLOCK_TO_REMOVE_THIS_MUCH;
+      // if we cannot merge to the end, then we definitely need 2 blocks,
+      // and a branch
+      // TODO: efficiency, entire body
+      if (!canMove(items, getFunction()->body)) {
+        cost += 1 + WORTH_ADDING_BLOCK_TO_REMOVE_THIS_MUCH;
+        // TODO: to do this, we need to maintain a map of element=>parent,
+        //       so that we can insert the new blocks in the right place
+        //       for now, just don't do this optimization
+        return false;
+      }
+      // is it worth it?
+      return saved > cost;
+    };
+    // let's see if we can merge deeper than num, to num + 1
+    auto next = tails;
+    // remove tails that are too short, or that we hit an item we can't handle
+    next.erase(std::remove_if(next.begin(),
+                              next.end(),
+                              [&](Tail& tail) {
+                                if (effectiveSize(tail) < num + 1) {
+                                  return true;
+                                }
+                                auto* newItem = getItem(tail, num);
+                                // ignore tails that break to outside blocks. we
+                                // want to move code to the very outermost
+                                // position, so such code cannot be moved
+                                // TODO: this should not be a problem in
+                                //       *non*-terminating tails, but
+                                //       double-verify that
+                                if (EffectAnalyzer(getPassOptions(),
+                                                   getModule()->features,
+                                                   newItem)
+                                      .hasExternalBreakTargets()) {
+                                  return true;
+                                }
+                                return false;
+                              }),
+               next.end());
+    // if we have enough to investigate, do so
+    if (next.size() >= 2) {
+      // now we want to find a mergeable item - any item that is equal among a
+      // subset
+      std::map<Expression*, size_t> hashes; // expression => hash value
+      // hash value => expressions with that hash
+      std::map<size_t, std::vector<Expression*>> hashed;
+      for (auto& tail : next) {
+        auto* item = getItem(tail, num);
+        auto hash = hashes[item] = ExpressionAnalyzer::hash(item);
+        hashed[hash].push_back(item);
+      }
+      // look at each hash value exactly once. we do this in a deterministic
+      // order by iterating over a vector retaining insertion order.
+      std::set<size_t> seen;
+      for (auto& tail : next) {
+        auto* item = getItem(tail, num);
+        auto digest = hashes[item];
+        if (seen.count(digest)) {
+          continue;
+        }
+        seen.insert(digest);
+        auto& items = hashed[digest];
+        if (items.size() == 1) {
+          continue;
+        }
+        assert(items.size() > 0);
+        // look for an item that has another match.
+        while (items.size() >= 2) {
+          auto first = items[0];
+          std::vector<Expression*> others;
+          items.erase(
+            std::remove_if(items.begin(),
+                           items.end(),
+                           [&](Expression* item) {
+                             if (item ==
+                                   first || // don't bother comparing the first
+                                 ExpressionAnalyzer::equal(item, first)) {
+                               // equal, keep it
+                               return false;
+                             } else {
+                               // unequal, look at it later
+                               others.push_back(item);
+                               return true;
+                             }
+                           }),
+            items.end());
+          if (items.size() >= 2) {
+            // possible merge here, investigate it
+            auto* correct = items[0];
+            auto explore = next;
+            explore.erase(std::remove_if(explore.begin(),
+                                         explore.end(),
+                                         [&](Tail& tail) {
+                                           auto* item = getItem(tail, num);
+                                           return !ExpressionAnalyzer::equal(
+                                             item, correct);
+                                         }),
+                          explore.end());
+            // try to optimize this deeper tail. if we succeed, then stop here,
+            // as the changes may influence us. we leave further opts to further
+            // passes (as this is rare in practice, it's generally not a perf
+            // issue, but TODO optimize)
+            if (optimizeTerminatingTails(explore, num + 1)) {
+              return true;
+            }
+          }
+          items.swap(others);
+        }
+      }
+    }
+    // we explored deeper (higher num) options, but perhaps there
+    // was nothing there while there is something we can do at this level
+    // but if we are at num == 0, then we found nothing at all
+    if (num == 0) {
+      return false;
+    }
+    // if not worth it, stop
+    if (!worthIt(num, tails)) {
+      return false;
+    }
+    // this is worth doing, do it!
+    auto mergeable = getTailItems(num, tails); // the elements we can merge
+    // since we managed a merge, then it might open up more opportunities later
+    anotherPass = true;
+    Builder builder(*getModule());
+    // TODO: don't create one per merge, linear in function size
+    LabelUtils::LabelManager labels(getFunction());
+    Name innerName = labels.getUnique("folding-inner");
+    for (auto& tail : tails) {
+      // remove the items we are merging / moving, and add a break
+      // also mark as modified, so we don't try to handle them
+      // again in this pass, which might be buggy
+      if (tail.block) {
+        markAsModified(tail.block);
+        for (Index i = 0; i < mergeable.size(); i++) {
+          tail.block->list.pop_back();
+        }
+        tail.block->list.push_back(builder.makeBreak(innerName));
+        tail.block->finalize(tail.block->type);
+      } else {
+        markAsModified(tail.expr);
+        *tail.pointer = builder.makeBreak(innerName);
+      }
+    }
+    // make a block with the old body + the merged code
+    auto* old = getFunction()->body;
+    auto* inner = builder.makeBlock();
+    inner->name = innerName;
+    if (old->type == Type::unreachable) {
+      // the old body is not flowed out of anyhow, so just put it there
+      inner->list.push_back(old);
+    } else {
+      // otherwise, we must not flow out to the merged code
+      if (old->type == Type::none) {
+        inner->list.push_back(old);
+        inner->list.push_back(builder.makeReturn());
+      } else {
+        // looks like we must return this. but if it's a toplevel block
+        // then it might be marked as having a type, but not actually
+        // returning it (we marked it as such for wasm type-checking
+        // rules, and now it won't be toplevel in the function, it can
+        // change)
+        auto* toplevel = old->dynCast<Block>();
+        if (toplevel) {
+          toplevel->finalize();
+        }
+        if (old->type != Type::unreachable) {
+          inner->list.push_back(builder.makeReturn(old));
+        } else {
+          inner->list.push_back(old);
+        }
+      }
+    }
+    inner->finalize();
+    auto* outer = builder.makeBlock();
+    outer->list.push_back(inner);
+    while (!mergeable.empty()) {
+      outer->list.push_back(mergeable.back());
+      mergeable.pop_back();
+    }
+    // ensure the replacement has the same type, so the outside is not surprised
+    outer->finalize(getFunction()->sig.results);
+    getFunction()->body = outer;
+    return true;
+  }
+
+  void markAsModified(Expression* curr) {
+    ExpressionMarker marker(modifieds, curr);
+  }
+};
+
+Pass* createCodeFoldingPass() { return new CodeFolding(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/CodePushing.cpp b/binaryen/src/passes/CodePushing.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/CodePushing.cpp
@@ -0,0 +1,278 @@
+/*
+ * 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.
+ */
+
+//
+// Pushes code "forward" as much as possible, potentially into
+// a location behind a condition, where it might not always execute.
+//
+
+#include <ir/effects.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+namespace wasm {
+
+//
+// Analyzers some useful local properties: # of sets and gets, and SFA.
+//
+// Single First Assignment (SFA) form: the local has a single local.set, is
+// not a parameter, and has no local.gets before the local.set in postorder.
+// This is a much weaker property than SSA, obviously, but together with
+// our implicit dominance properties in the structured AST is quite useful.
+//
+struct LocalAnalyzer : public PostWalker<LocalAnalyzer> {
+  std::vector<bool> sfa;
+  std::vector<Index> numSets;
+  std::vector<Index> numGets;
+
+  void analyze(Function* func) {
+    auto num = func->getNumLocals();
+    numSets.resize(num);
+    std::fill(numSets.begin(), numSets.end(), 0);
+    numGets.resize(num);
+    std::fill(numGets.begin(), numGets.end(), 0);
+    sfa.resize(num);
+    std::fill(sfa.begin(), sfa.begin() + func->getNumParams(), false);
+    std::fill(sfa.begin() + func->getNumParams(), sfa.end(), true);
+    walk(func->body);
+    for (Index i = 0; i < num; i++) {
+      if (numSets[i] == 0) {
+        sfa[i] = false;
+      }
+    }
+  }
+
+  bool isSFA(Index i) { return sfa[i]; }
+
+  Index getNumGets(Index i) { return numGets[i]; }
+
+  void visitLocalGet(LocalGet* curr) {
+    if (numSets[curr->index] == 0) {
+      sfa[curr->index] = false;
+    }
+    numGets[curr->index]++;
+  }
+
+  void visitLocalSet(LocalSet* curr) {
+    numSets[curr->index]++;
+    if (numSets[curr->index] > 1) {
+      sfa[curr->index] = false;
+    }
+  }
+};
+
+// Implements core optimization logic. Used and then discarded entirely
+// for each block.
+class Pusher {
+  ExpressionList& list;
+  LocalAnalyzer& analyzer;
+  std::vector<Index>& numGetsSoFar;
+  PassOptions& passOptions;
+  FeatureSet features;
+
+public:
+  Pusher(Block* block,
+         LocalAnalyzer& analyzer,
+         std::vector<Index>& numGetsSoFar,
+         PassOptions& passOptions,
+         FeatureSet features)
+    : list(block->list), analyzer(analyzer), numGetsSoFar(numGetsSoFar),
+      passOptions(passOptions), features(features) {
+    // Find an optimization segment: from the first pushable thing, to the first
+    // point past which we want to push. We then push in that range before
+    // continuing forward.
+    // we never need to push past a final element, as we couldn't be used after
+    // it.
+    Index relevant = list.size() - 1;
+    const Index nothing = -1;
+    Index i = 0;
+    Index firstPushable = nothing;
+    while (i < relevant) {
+      if (firstPushable == nothing && isPushable(list[i])) {
+        firstPushable = i;
+        i++;
+        continue;
+      }
+      if (firstPushable != nothing && isPushPoint(list[i])) {
+        // optimize this segment, and proceed from where it tells us
+        i = optimizeSegment(firstPushable, i);
+        firstPushable = nothing;
+        continue;
+      }
+      i++;
+    }
+  }
+
+private:
+  LocalSet* isPushable(Expression* curr) {
+    auto* set = curr->dynCast<LocalSet>();
+    if (!set) {
+      return nullptr;
+    }
+    auto index = set->index;
+    // to be pushable, this must be SFA and the right # of gets,
+    // but also have no side effects, as it may not execute if pushed.
+    if (analyzer.isSFA(index) &&
+        numGetsSoFar[index] == analyzer.getNumGets(index) &&
+        !EffectAnalyzer(passOptions, features, set->value).hasSideEffects()) {
+      return set;
+    }
+    return nullptr;
+  }
+
+  // Push past conditional control flow.
+  // TODO: push into ifs as well
+  bool isPushPoint(Expression* curr) {
+    // look through drops
+    if (auto* drop = curr->dynCast<Drop>()) {
+      curr = drop->value;
+    }
+    if (curr->is<If>() || curr->is<BrOnExn>()) {
+      return true;
+    }
+    if (auto* br = curr->dynCast<Break>()) {
+      return !!br->condition;
+    }
+    return false;
+  }
+
+  Index optimizeSegment(Index firstPushable, Index pushPoint) {
+    // The interesting part. Starting at firstPushable, try to push
+    // code past pushPoint. We start at the end since we are pushing
+    // forward, that way we can push later things out of the way
+    // of earlier ones. Once we know all we can push, we push it all
+    // in one pass, keeping the order of the pushables intact.
+    assert(firstPushable != Index(-1) && pushPoint != Index(-1) &&
+           firstPushable < pushPoint);
+    // everything that matters if you want to be pushed past the pushPoint
+    EffectAnalyzer cumulativeEffects(passOptions, features);
+    cumulativeEffects.analyze(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
+    //       could not be caught and must go outside of the function
+    cumulativeEffects.ignoreBranches();
+    std::vector<LocalSet*> toPush;
+    Index i = pushPoint - 1;
+    while (1) {
+      auto* pushable = isPushable(list[i]);
+      if (pushable) {
+        auto iter = pushableEffects.find(pushable);
+        if (iter == pushableEffects.end()) {
+          iter =
+            pushableEffects
+              .emplace(std::piecewise_construct,
+                       std::forward_as_tuple(pushable),
+                       std::forward_as_tuple(passOptions, features, pushable))
+              .first;
+        }
+        auto& effects = iter->second;
+        if (cumulativeEffects.invalidates(effects)) {
+          // we can't push this, so further pushables must pass it
+          cumulativeEffects.mergeIn(effects);
+        } else {
+          // we can push this, great!
+          toPush.push_back(pushable);
+        }
+        if (i == firstPushable) {
+          // no point in looking further
+          break;
+        }
+      } else {
+        // something that can't be pushed, so it might block further pushing
+        cumulativeEffects.analyze(list[i]);
+      }
+      assert(i > 0);
+      i--;
+    }
+    if (toPush.size() == 0) {
+      // nothing to do, can only continue after the push point
+      return pushPoint + 1;
+    }
+    // we have work to do!
+    Index total = toPush.size();
+    Index last = total - 1;
+    Index skip = 0;
+    for (Index i = firstPushable; i <= pushPoint; i++) {
+      // we see the first elements at the end of toPush
+      if (skip < total && list[i] == toPush[last - skip]) {
+        // this is one of our elements to push, skip it
+        skip++;
+      } else {
+        if (skip) {
+          list[i - skip] = list[i];
+        }
+      }
+    }
+    assert(skip == total);
+    // write out the skipped elements
+    for (Index i = 0; i < total; i++) {
+      list[pushPoint - i] = toPush[i];
+    }
+    // proceed right after the push point, we may push the pushed elements again
+    return pushPoint - total + 1;
+  }
+
+  // Pushables may need to be scanned more than once, so cache their effects.
+  std::unordered_map<LocalSet*, EffectAnalyzer> pushableEffects;
+};
+
+struct CodePushing : public WalkerPass<PostWalker<CodePushing>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new CodePushing; }
+
+  LocalAnalyzer analyzer;
+
+  // gets seen so far in the main traversal
+  std::vector<Index> numGetsSoFar;
+
+  void doWalkFunction(Function* func) {
+    // pre-scan to find which vars are sfa, and also count their gets&sets
+    analyzer.analyze(func);
+    // prepare to walk
+    numGetsSoFar.resize(func->getNumLocals());
+    std::fill(numGetsSoFar.begin(), numGetsSoFar.end(), 0);
+    // walk and optimize
+    walk(func->body);
+  }
+
+  void visitLocalGet(LocalGet* curr) { numGetsSoFar[curr->index]++; }
+
+  void visitBlock(Block* curr) {
+    // Pushing code only makes sense if we are size 3 or above: we need
+    // one element to push, an element to push it past, and an element to use
+    // what we pushed.
+    if (curr->list.size() < 3) {
+      return;
+    }
+    // At this point in the postorder traversal we have gone through all our
+    // children. Therefore any variable whose gets seen so far is equal to the
+    // total gets must have no further users after this block. And therefore
+    // when we see an SFA variable defined here, we know it isn't used before it
+    // either, and has just this one assign. So we can push it forward while we
+    // don't hit a non-control-flow ordering invalidation issue, since if this
+    // isn't a loop, it's fine (we're not used outside), and if it is, we hit
+    // the assign before any use (as we can't push it past a use).
+    Pusher pusher(
+      curr, analyzer, numGetsSoFar, getPassOptions(), getModule()->features);
+  }
+};
+
+Pass* createCodePushingPass() { return new CodePushing(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/ConstHoisting.cpp b/binaryen/src/passes/ConstHoisting.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/ConstHoisting.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2017 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Hoists repeated constants to a local. A local.get takes 2 bytes
+// in most cases, and if a const is larger than that, it may be
+// better to store it to a local, then get it from that local.
+//
+// WARNING: this often shrinks code size, but can *increase* gzip
+//          size. apparently having the constants in their proper
+//          places lets them be compressed better, across
+//          functions, etc. TODO investigate
+// TODO: hoisting a zero does not even require an initial set!
+// TODO: hoisting a float or double zero is especially beneficial as there
+//       is no LEB compression for them, and no need for the set, so
+//       each f32.const is 5 bytes and f64.const is 9 bytes, while it is
+//       <= 1 byte to declare the local and 2-3 to use it!
+//
+
+#include <map>
+
+#include <pass.h>
+#include <wasm-binary.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+namespace wasm {
+
+// with fewer uses than this, it is never beneficial to hoist
+static const Index MIN_USES = 2;
+
+struct ConstHoisting : public WalkerPass<PostWalker<ConstHoisting>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new ConstHoisting; }
+
+  std::map<Literal, std::vector<Expression**>> uses;
+
+  void visitConst(Const* curr) {
+    uses[curr->value].push_back(getCurrentPointer());
+  }
+
+  void visitFunction(Function* curr) {
+    std::vector<Expression*> prelude;
+    for (auto& pair : uses) {
+      auto value = pair.first;
+      auto& vec = pair.second;
+      auto num = vec.size();
+      if (worthHoisting(value, num)) {
+        prelude.push_back(hoist(vec));
+      }
+    }
+    if (!prelude.empty()) {
+      Builder builder(*getModule());
+      // merge-blocks can optimize this into a single block later in most cases
+      curr->body = builder.makeSequence(builder.makeBlock(prelude), curr->body);
+    }
+  }
+
+private:
+  bool worthHoisting(Literal value, Index num) {
+    if (num < MIN_USES) {
+      return false;
+    }
+    // measure the size of the constant
+    Index size = 0;
+    TODO_SINGLE_COMPOUND(value.type);
+    switch (value.type.getBasic()) {
+      case Type::i32: {
+        size = getWrittenSize(S32LEB(value.geti32()));
+        break;
+      }
+      case Type::i64: {
+        size = getWrittenSize(S64LEB(value.geti64()));
+        break;
+      }
+      case Type::f32:
+      case Type::f64: {
+        size = value.type.getByteSize();
+        break;
+      }
+        // not implemented yet
+      case Type::v128:
+      case Type::funcref:
+      case Type::externref:
+      case Type::exnref:
+      case Type::anyref:
+      case Type::eqref:
+      case Type::i31ref: {
+        return false;
+      }
+      case Type::none:
+      case Type::unreachable:
+        WASM_UNREACHABLE("unexpected type");
+    }
+    // compute the benefit, of replacing the uses with
+    // one use + a set and then a get for each use
+    // doing the algebra, the criterion here is when
+    //   size > 2(1+num)/(num-1)
+    // or
+    //   num > (size+2)/(size-2)
+    auto before = num * size;
+    auto after = size + 2 /* local.set */ + (2 /* local.get */ * num);
+    return after < before;
+  }
+
+  template<typename T> Index getWrittenSize(const T& thing) {
+    BufferWithRandomAccess buffer;
+    buffer << thing;
+    return buffer.size();
+  }
+
+  // replace all the uses with gets, for a local set at the top. returns
+  // the set.
+  Expression* hoist(std::vector<Expression**>& vec) {
+    auto type = (*(vec[0]))->type;
+    Builder builder(*getModule());
+    auto temp = builder.addVar(getFunction(), type);
+    auto* ret = builder.makeLocalSet(temp, *(vec[0]));
+    for (auto item : vec) {
+      *item = builder.makeLocalGet(temp, type);
+    }
+    return ret;
+  }
+};
+
+Pass* createConstHoistingPass() { return new ConstHoisting(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/DWARF.cpp b/binaryen/src/passes/DWARF.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/DWARF.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 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.
+ */
+
+//
+// Dump DWARF sections. This results in something similar to llvm-dwarfdump,
+// as it uses the same code.
+//
+// Note that this dumps the DWARF data read from the binary when we loaded it.
+// It does not contain changes made since then, which will only be updated
+// when we write the binary. To see those changes, you must round-trip.
+//
+
+#include "pass.h"
+#include "wasm-debug.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct DWARFDump : public Pass {
+  void run(PassRunner* runner, Module* module) override {
+    Debug::dumpDWARF(*module);
+  }
+};
+
+Pass* createDWARFDumpPass() { return new DWARFDump(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/DataFlowOpts.cpp b/binaryen/src/passes/DataFlowOpts.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/DataFlowOpts.cpp
@@ -0,0 +1,255 @@
+/*
+ * 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.
+ */
+
+//
+// Optimize using the DataFlow SSA IR.
+//
+// This needs 'flatten' to be run before it, and you should run full
+// regular opts afterwards to clean up the flattening. For example,
+// you might use it like this:
+//
+//    --flatten --dfo -Os
+//
+
+#include "dataflow/graph.h"
+#include "dataflow/node.h"
+#include "dataflow/users.h"
+#include "dataflow/utils.h"
+#include "ir/flat.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct DataFlowOpts : public WalkerPass<PostWalker<DataFlowOpts>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new DataFlowOpts; }
+
+  DataFlow::Users nodeUsers;
+
+  // The optimization work left to do: nodes that we need to look at.
+  std::unordered_set<DataFlow::Node*> workLeft;
+
+  DataFlow::Graph graph;
+
+  void doWalkFunction(Function* func) {
+    Flat::verifyFlatness(func);
+    // Build the data-flow IR.
+    graph.build(func, getModule());
+    nodeUsers.build(graph);
+    // Propagate optimizations through the graph.
+    std::unordered_set<DataFlow::Node*> optimized; // which nodes we optimized
+    for (auto& node : graph.nodes) {
+      workLeft.insert(node.get()); // we should try to optimize each node
+    }
+    while (!workLeft.empty()) {
+      // std::cout << "\n\ndump before work iter\n";
+      // dump(graph, std::cout);
+      auto iter = workLeft.begin();
+      auto* node = *iter;
+      workLeft.erase(iter);
+      workOn(node);
+    }
+    // After updating the DataFlow IR, we can update the sets in
+    // the wasm.
+    // TODO: we also need phis, as a phi can flow directly into say
+    //       a return or a call parameter.
+    for (auto* set : graph.sets) {
+      auto* node = graph.setNodeMap[set];
+      auto iter = optimized.find(node);
+      if (iter != optimized.end()) {
+        assert(node->isExpr()); // this is a set, where the node is defined
+        set->value = node->expr;
+      }
+    }
+  }
+
+  void workOn(DataFlow::Node* node) {
+    if (node->isConst()) {
+      return;
+    }
+    // If there are no uses, there is no point to work.
+    if (nodeUsers.getNumUses(node) == 0) {
+      return;
+    }
+    // Optimize: Look for nodes that we can easily convert into
+    // something simpler.
+    // TODO: we can expressionify and run full normal opts on that,
+    //       then copy the result if it's smaller.
+    if (node->isPhi() && DataFlow::allInputsIdentical(node)) {
+      // Note we don't need to check for effects when replacing, as in
+      // flattened IR expression children are local.gets or consts.
+      auto* value = node->getValue(1);
+      if (value->isConst()) {
+        replaceAllUsesWith(node, value);
+      }
+    } else if (node->isExpr() && DataFlow::allInputsConstant(node)) {
+      assert(!node->isConst());
+      // If this is a concrete value (not e.g. an eqz of unreachable),
+      // it can definitely be precomputed into a constant.
+      if (node->expr->type.isConcrete()) {
+        // This can be precomputed.
+        // TODO not just all-constant inputs? E.g. i32.mul of 0 and X.
+        optimizeExprToConstant(node);
+      }
+    }
+  }
+
+  void optimizeExprToConstant(DataFlow::Node* node) {
+    assert(node->isExpr());
+    assert(!node->isConst());
+    // std::cout << "will optimize an Expr of all constant inputs. before" <<
+    //              '\n';
+    // dump(node, std::cout);
+    auto* expr = node->expr;
+    // First, note that some of the expression's children may be
+    // local.gets that we inferred during SSA analysis as constant.
+    // We can apply those now.
+    for (Index i = 0; i < node->values.size(); i++) {
+      if (node->values[i]->isConst()) {
+        auto* currp = getIndexPointer(expr, i);
+        // Directly represent it as a constant. (Note that it may already be
+        // a constant, but for now to avoid corner cases just replace them
+        // all here.)
+        auto* c = node->values[i]->expr->dynCast<Const>();
+        *currp = Builder(*getModule()).makeConst(c->value);
+      }
+    }
+    // Now we know that all our DataFlow inputs are constant, and all
+    // our Binaryen IR representations of them are constant too. RUn
+    // precompute, which will transform the expression into a constanat.
+    Module temp;
+    // XXX we should copy expr here, in principle, and definitely will need to
+    //     when we do arbitrarily regenerated expressions
+    std::unique_ptr<Function> tempFunc(Builder(temp).makeFunction(
+      "temp", Signature(Type::none, Type::none), {}, expr));
+    PassRunner runner(&temp);
+    runner.setIsNested(true);
+    runner.add("precompute");
+    runner.runOnFunction(tempFunc.get());
+    // Get the optimized thing
+    auto* result = tempFunc->body;
+    // It may not be a constant, e.g. 0 / 0 does not optimize to 0
+    if (!result->is<Const>()) {
+      return;
+    }
+    // All good, copy it.
+    node->expr = Builder(*getModule()).makeConst(result->cast<Const>()->value);
+    assert(node->isConst());
+    // We no longer have values, and so do not use anything.
+    nodeUsers.stopUsingValues(node);
+    node->values.clear();
+    // Our contents changed, update our users.
+    replaceAllUsesWith(node, node);
+  }
+
+  // Replaces all uses of a node with another value. This both modifies
+  // the DataFlow IR to make the other users point to this one, and
+  // updates the underlying Binaryen IR as well.
+  // This can be used to "replace" a node with itself, which makes sense
+  // when the node contents have changed and so the users must be updated.
+  void replaceAllUsesWith(DataFlow::Node* node, DataFlow::Node* with) {
+    // Const nodes are trivial to replace, but other stuff is trickier -
+    // in particular phis.
+    assert(with->isConst()); // TODO
+    // All the users should be worked on later, as we will update them.
+    auto& users = nodeUsers.getUsers(node);
+    for (auto* user : users) {
+      // Add the user to the work left to do, as we are modifying it.
+      workLeft.insert(user);
+      // `with` is getting another user.
+      nodeUsers.addUser(with, user);
+      // Replacing in the DataFlow IR is simple - just replace it,
+      // in all the indexes it appears.
+      std::vector<Index> indexes;
+      for (Index i = 0; i < user->values.size(); i++) {
+        if (user->values[i] == node) {
+          user->values[i] = with;
+          indexes.push_back(i);
+        }
+      }
+      assert(!indexes.empty());
+      // Replacing in the Binaryen IR requires more care
+      switch (user->type) {
+        case DataFlow::Node::Type::Expr: {
+          auto* expr = user->expr;
+          for (auto index : indexes) {
+            *(getIndexPointer(expr, index)) = graph.makeUse(with);
+          }
+          break;
+        }
+        case DataFlow::Node::Type::Phi: {
+          // Nothing to do: a phi is not in the Binaryen IR.
+          // If the entire phi can become a constant, that will be
+          // propagated when we process that phi later.
+          break;
+        }
+        case DataFlow::Node::Type::Cond: {
+          // Nothing to do: a cond is not in the Binaryen IR.
+          // If the cond input is a constant, that might indicate
+          // useful optimizations are possible, which perhaps we
+          // should look into TODO
+          break;
+        }
+        case DataFlow::Node::Type::Zext: {
+          // Nothing to do: a zext is not in the Binaryen IR.
+          // If the cond input is a constant, that might indicate
+          // useful optimizations are possible, which perhaps we
+          // should look into TODO
+          break;
+        }
+        default:
+          WASM_UNREACHABLE("unexpected dataflow node type");
+      }
+    }
+    // No one is a user of this node after we replaced all the uses.
+    nodeUsers.removeAllUsesOf(node);
+  }
+
+  // Gets a pointer to the expression pointer in an expression.
+  // That is, given an index in the values() vector, get an
+  // Expression** that we can assign to so as to modify it.
+  Expression** getIndexPointer(Expression* expr, Index index) {
+    if (auto* unary = expr->dynCast<Unary>()) {
+      assert(index == 0);
+      return &unary->value;
+    } else if (auto* binary = expr->dynCast<Binary>()) {
+      if (index == 0) {
+        return &binary->left;
+      } else if (index == 1) {
+        return &binary->right;
+      }
+      WASM_UNREACHABLE("unexpected index");
+    } else if (auto* select = expr->dynCast<Select>()) {
+      if (index == 0) {
+        return &select->condition;
+      } else if (index == 1) {
+        return &select->ifTrue;
+      } else if (index == 2) {
+        return &select->ifFalse;
+      }
+      WASM_UNREACHABLE("unexpected index");
+    }
+    WASM_UNREACHABLE("unexpected expression type");
+  }
+};
+
+Pass* createDataFlowOptsPass() { return new DataFlowOpts(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/DeAlign.cpp b/binaryen/src/passes/DeAlign.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/DeAlign.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+//
+// Forces all loads and stores to be completely unaligned, that is, to have
+// alignment 1.
+//
+
+#include "pass.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct DeAlign : public WalkerPass<PostWalker<DeAlign>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new DeAlign(); }
+
+  void visitLoad(Load* curr) { curr->align = 1; }
+
+  void visitStore(Store* curr) { curr->align = 1; }
+
+  void visitSIMDLoad(SIMDLoad* curr) { curr->align = 1; }
+};
+
+Pass* createDeAlignPass() { return new DeAlign(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/DeNaN.cpp b/binaryen/src/passes/DeNaN.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/DeNaN.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+//
+// Instrument the wasm to convert NaN values at runtime into 0s. That is, every
+// operation that might produce a NaN will go through a helper function which
+// filters out NaNs (replacing them with 0). This ensures that NaNs are never
+// consumed by any instructions, which is useful when fuzzing between VMs that
+// differ on wasm's nondeterminism around NaNs.
+//
+
+#include "ir/properties.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct DeNaN : public WalkerPass<
+                 ControlFlowWalker<DeNaN, UnifiedExpressionVisitor<DeNaN>>> {
+  void visitExpression(Expression* expr) {
+    // If the expression returns a floating-point value, ensure it is not a
+    // NaN. If we can do this at compile time, do it now, which is useful for
+    // initializations of global (which we can't do a function call in). Note
+    // that we don't instrument local.gets, which would cause problems if we
+    // ran this pass more than once (the added functions use gets, and we don't
+    // want to instrument them).
+    if (expr->is<LocalGet>()) {
+      return;
+    }
+    // If the result just falls through without being modified, then we've
+    // already fixed it up earlier.
+    if (Properties::isResultFallthrough(expr)) {
+      return;
+    }
+    Builder builder(*getModule());
+    Expression* replacement = nullptr;
+    auto* c = expr->dynCast<Const>();
+    if (expr->type == Type::f32) {
+      if (c && c->value.isNaN()) {
+        replacement = builder.makeConst(float(0));
+      } else {
+        replacement = builder.makeCall("deNan32", {expr}, Type::f32);
+      }
+    } else if (expr->type == Type::f64) {
+      if (c && c->value.isNaN()) {
+        replacement = builder.makeConst(double(0));
+      } else {
+        replacement = builder.makeCall("deNan64", {expr}, Type::f64);
+      }
+    }
+    if (replacement) {
+      // We can't do this outside of a function, like in a global initializer,
+      // where a call would be illegal.
+      if (replacement->is<Const>() || getFunction()) {
+        replaceCurrent(replacement);
+      } else {
+        std::cerr << "warning: cannot de-nan outside of function context\n";
+      }
+    }
+  }
+
+  void visitFunction(Function* func) {
+    if (func->imported()) {
+      return;
+    }
+    // Instrument all locals as they enter the function.
+    Builder builder(*getModule());
+    std::vector<Expression*> fixes;
+    auto num = func->getNumParams();
+    for (Index i = 0; i < num; i++) {
+      if (func->getLocalType(i) == Type::f32) {
+        fixes.push_back(builder.makeLocalSet(
+          i,
+          builder.makeCall(
+            "deNan32", {builder.makeLocalGet(i, Type::f32)}, Type::f32)));
+      } else if (func->getLocalType(i) == Type::f64) {
+        fixes.push_back(builder.makeLocalSet(
+          i,
+          builder.makeCall(
+            "deNan64", {builder.makeLocalGet(i, Type::f64)}, Type::f64)));
+      }
+    }
+    if (!fixes.empty()) {
+      fixes.push_back(func->body);
+      func->body = builder.makeBlock(fixes);
+      // Merge blocks so we don't add an unnecessary one.
+      PassRunner runner(getModule(), getPassOptions());
+      runner.setIsNested(true);
+      runner.add("merge-blocks");
+      runner.run();
+    }
+  }
+
+  void visitModule(Module* module) {
+    // Add helper functions.
+    Builder builder(*module);
+    auto add = [&](Name name, Type type, Literal literal, BinaryOp op) {
+      auto* func = new Function;
+      func->name = name;
+      func->sig = Signature(type, type);
+      // Compare the value to itself to check if it is a NaN, and return 0 if
+      // so:
+      //
+      //   (if (result f*)
+      //     (f*.eq
+      //       (local.get $0)
+      //       (local.get $0)
+      //     )
+      //     (local.get $0)
+      //     (f*.const 0)
+      //   )
+      func->body = builder.makeIf(
+        builder.makeBinary(
+          op, builder.makeLocalGet(0, type), builder.makeLocalGet(0, type)),
+        builder.makeLocalGet(0, type),
+        builder.makeConst(literal));
+      module->addFunction(func);
+    };
+    add("deNan32", Type::f32, Literal(float(0)), EqFloat32);
+    add("deNan64", Type::f64, Literal(double(0)), EqFloat64);
+  }
+};
+
+Pass* createDeNaNPass() { return new DeNaN(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/DeadArgumentElimination.cpp b/binaryen/src/passes/DeadArgumentElimination.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/DeadArgumentElimination.cpp
@@ -0,0 +1,485 @@
+/*
+ * 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.
+ */
+
+//
+// Optimizes call arguments in a whole-program manner, removing ones
+// that are not used (dead).
+//
+// Specifically, this does these things:
+//
+//  * Find functions for whom an argument is always passed the same
+//    constant. If so, we can just set that local to that constant
+//    in the function.
+//  * Find functions that don't use the value passed to an argument.
+//    If so, we can avoid even sending and receiving it. (Note how if
+//    the previous point was true for an argument, then the second
+//    must as well.)
+//  * Find return values ("return arguments" ;) that are never used.
+//
+// This pass does not depend on flattening, but it may be more effective,
+// as then call arguments never have side effects (which we need to
+// watch for here).
+//
+
+#include <unordered_map>
+#include <unordered_set>
+
+#include "cfg/cfg-traversal.h"
+#include "ir/effects.h"
+#include "ir/module-utils.h"
+#include "pass.h"
+#include "passes/opt-utils.h"
+#include "support/sorted_vector.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+// Information for a function
+struct DAEFunctionInfo {
+  // The unused parameters, if any.
+  SortedVector unusedParams;
+  // Maps a function name to the calls going to it.
+  std::unordered_map<Name, std::vector<Call*>> calls;
+  // Map of all calls that are dropped, to their drops' locations (so that
+  // if we can optimize out the drop, we can replace the drop there).
+  std::unordered_map<Call*, Expression**> droppedCalls;
+  // Whether this function contains any tail calls (including indirect tail
+  // calls) and the set of functions this function tail calls. Tail-callers and
+  // tail-callees cannot have their dropped returns removed because of the
+  // constraint that tail-callees must have the same return type as
+  // tail-callers. Indirectly tail called functions are already not optimized
+  // because being in a table inhibits DAE. TODO: Allow the removal of dropped
+  // returns from tail-callers if their tail-callees can have their returns
+  // removed as well.
+  bool hasTailCalls = false;
+  std::unordered_set<Name> tailCallees;
+  // Whether the function can be called from places that
+  // affect what we can do. For now, any call we don't
+  // see inhibits our optimizations, but TODO: an export
+  // could be worked around by exporting a thunk that
+  // adds the parameter.
+  bool hasUnseenCalls = false;
+};
+
+typedef std::unordered_map<Name, DAEFunctionInfo> DAEFunctionInfoMap;
+
+// Information in a basic block
+struct DAEBlockInfo {
+  // A local may be read, written, or not accessed in this block.
+  // If it is both read and written, we just care about the first
+  // action (if it is read first, that's all the info we are
+  // looking for; if it is written first, it can't be read later).
+  enum LocalUse { Read, Written };
+  std::unordered_map<Index, LocalUse> localUses;
+};
+
+struct DAEScanner
+  : public WalkerPass<
+      CFGWalker<DAEScanner, Visitor<DAEScanner>, DAEBlockInfo>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new DAEScanner(infoMap); }
+
+  DAEScanner(DAEFunctionInfoMap* infoMap) : infoMap(infoMap) {}
+
+  DAEFunctionInfoMap* infoMap;
+  DAEFunctionInfo* info;
+
+  Index numParams;
+
+  // cfg traversal work
+
+  void visitLocalGet(LocalGet* curr) {
+    if (currBasicBlock) {
+      auto& localUses = currBasicBlock->contents.localUses;
+      auto index = curr->index;
+      if (localUses.count(index) == 0) {
+        localUses[index] = DAEBlockInfo::Read;
+      }
+    }
+  }
+
+  void visitLocalSet(LocalSet* curr) {
+    if (currBasicBlock) {
+      auto& localUses = currBasicBlock->contents.localUses;
+      auto index = curr->index;
+      if (localUses.count(index) == 0) {
+        localUses[index] = DAEBlockInfo::Written;
+      }
+    }
+  }
+
+  void visitCall(Call* curr) {
+    if (!getModule()->getFunction(curr->target)->imported()) {
+      info->calls[curr->target].push_back(curr);
+    }
+    if (curr->isReturn) {
+      info->hasTailCalls = true;
+      info->tailCallees.insert(curr->target);
+    }
+  }
+
+  void visitCallIndirect(CallIndirect* curr) {
+    if (curr->isReturn) {
+      info->hasTailCalls = true;
+    }
+  }
+
+  void visitDrop(Drop* curr) {
+    if (auto* call = curr->value->dynCast<Call>()) {
+      info->droppedCalls[call] = getCurrentPointer();
+    }
+  }
+
+  // main entry point
+
+  void doWalkFunction(Function* func) {
+    numParams = func->getNumParams();
+    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 (numParams > 0 && !info->hasUnseenCalls) {
+      findUnusedParams(func);
+    }
+  }
+
+  void findUnusedParams(Function* func) {
+    // 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.
+    std::unordered_map<BasicBlock*, SortedVector> seenBlockIndexes;
+    // Start with all the incoming parameters.
+    SortedVector initial;
+    for (Index i = 0; i < numParams; i++) {
+      initial.push_back(i);
+    }
+    // The used params, which we now compute.
+    std::unordered_set<Index> usedParams;
+    // An item of work is a block plus the values arriving there.
+    typedef std::pair<BasicBlock*, SortedVector> Item;
+    std::vector<Item> work;
+    work.emplace_back(entry, initial);
+    while (!work.empty()) {
+      auto item = std::move(work.back());
+      work.pop_back();
+      auto* block = item.first;
+      auto& indexes = item.second;
+      // Ignore things we've already seen, or we've already seen to be used.
+      auto& seenIndexes = seenBlockIndexes[block];
+      indexes.filter([&](const Index i) {
+        if (seenIndexes.has(i) || usedParams.count(i)) {
+          return false;
+        } else {
+          seenIndexes.insert(i);
+          return true;
+        }
+      });
+      if (indexes.empty()) {
+        continue; // nothing more to flow
+      }
+      auto& localUses = block->contents.localUses;
+      SortedVector remainingIndexes;
+      for (auto i : indexes) {
+        auto iter = localUses.find(i);
+        if (iter != localUses.end()) {
+          auto use = iter->second;
+          if (use == DAEBlockInfo::Read) {
+            usedParams.insert(i);
+          }
+          // Whether it was a read or a write, we can stop looking at that local
+          // here.
+        } else {
+          remainingIndexes.insert(i);
+        }
+      }
+      // If there are remaining indexes, flow them forward.
+      if (!remainingIndexes.empty()) {
+        for (auto* next : block->out) {
+          work.emplace_back(next, remainingIndexes);
+        }
+      }
+    }
+    // We can now compute the unused params.
+    for (Index i = 0; i < numParams; i++) {
+      if (usedParams.count(i) == 0) {
+        info->unusedParams.insert(i);
+      }
+    }
+  }
+};
+
+struct DAE : public Pass {
+  bool optimize = false;
+
+  void run(PassRunner* runner, Module* module) override {
+    // Iterate to convergence.
+    while (1) {
+      if (!iteration(runner, module)) {
+        break;
+      }
+    }
+  }
+
+  bool iteration(PassRunner* runner, Module* module) {
+    allDroppedCalls.clear();
+
+    DAEFunctionInfoMap infoMap;
+    // Ensure they all exist so the parallel threads don't modify the data
+    // structure.
+    ModuleUtils::iterDefinedFunctions(
+      *module, [&](Function* func) { infoMap[func->name]; });
+    // Check the influence of the table and exports.
+    for (auto& curr : module->exports) {
+      if (curr->kind == ExternalKind::Function) {
+        infoMap[curr->value].hasUnseenCalls = true;
+      }
+    }
+    for (auto& segment : module->table.segments) {
+      for (auto name : segment.data) {
+        infoMap[name].hasUnseenCalls = true;
+      }
+    }
+    // Scan all the functions.
+    DAEScanner(&infoMap).run(runner, module);
+    // Combine all the info.
+    std::unordered_map<Name, std::vector<Call*>> allCalls;
+    std::unordered_set<Name> tailCallees;
+    for (auto& pair : infoMap) {
+      auto& info = pair.second;
+      for (auto& pair : info.calls) {
+        auto name = pair.first;
+        auto& calls = pair.second;
+        auto& allCallsToName = allCalls[name];
+        allCallsToName.insert(allCallsToName.end(), calls.begin(), calls.end());
+      }
+      for (auto& callee : info.tailCallees) {
+        tailCallees.insert(callee);
+      }
+      for (auto& pair : info.droppedCalls) {
+        allDroppedCalls[pair.first] = pair.second;
+      }
+    }
+    // We now have a mapping of all call sites for each function. Check which
+    // are always passed the same constant for a particular argument.
+    for (auto& pair : allCalls) {
+      auto name = pair.first;
+      // We can only optimize if we see all the calls and can modify
+      // them.
+      if (infoMap[name].hasUnseenCalls) {
+        continue;
+      }
+      auto& calls = pair.second;
+      auto* func = module->getFunction(name);
+      auto numParams = func->getNumParams();
+      for (Index i = 0; i < numParams; i++) {
+        Literal value;
+        for (auto* call : calls) {
+          assert(call->target == name);
+          assert(call->operands.size() == numParams);
+          auto* operand = call->operands[i];
+          if (auto* c = operand->dynCast<Const>()) {
+            if (value.type == Type::none) {
+              // This is the first value seen.
+              value = c->value;
+            } else if (value != c->value) {
+              // Not identical, give up
+              value = Literal(Type::none);
+              break;
+            }
+          } else {
+            // Not a constant, give up
+            value = Literal(Type::none);
+            break;
+          }
+        }
+        if (value.type != Type::none) {
+          // Success! We can just apply the constant in the function, which
+          // makes the parameter value unused, which lets us remove it later.
+          Builder builder(*module);
+          func->body = builder.makeSequence(
+            builder.makeLocalSet(i, builder.makeConst(value)), func->body);
+          // Mark it as unused, which we know it now is (no point to
+          // re-scan just for that).
+          infoMap[name].unusedParams.insert(i);
+        }
+      }
+    }
+    // Track which functions we changed, and optimize them later if necessary.
+    std::unordered_set<Function*> changed;
+    // We now know which parameters are unused, and can potentially remove them.
+    for (auto& pair : allCalls) {
+      auto name = pair.first;
+      auto& calls = pair.second;
+      auto* func = module->getFunction(name);
+      auto numParams = func->getNumParams();
+      if (numParams == 0) {
+        continue;
+      }
+      // Iterate downwards, as we may remove more than one.
+      Index i = numParams - 1;
+      while (1) {
+        if (infoMap[name].unusedParams.has(i)) {
+          // Great, it's not used. Check if none of the calls has a param with
+          // side effects, as that would prevent us removing them (flattening
+          // should have been done earlier).
+          bool canRemove =
+            std::none_of(calls.begin(), calls.end(), [&](Call* call) {
+              auto* operand = call->operands[i];
+              return EffectAnalyzer(runner->options, module->features, operand)
+                .hasSideEffects();
+            });
+          if (canRemove) {
+            // Wonderful, nothing stands in our way! Do it.
+            // TODO: parallelize this?
+            removeParameter(func, i, calls);
+            changed.insert(func);
+          }
+        }
+        if (i == 0) {
+          break;
+        }
+        i--;
+      }
+    }
+    // We can also tell which calls have all their return values dropped. Note
+    // that we can't do this if we changed anything so far, as we may have
+    // modified allCalls (we can't modify a call site twice in one iteration,
+    // once to remove a param, once to drop the return value).
+    if (changed.empty()) {
+      for (auto& func : module->functions) {
+        if (func->sig.results == Type::none) {
+          continue;
+        }
+        auto name = func->name;
+        if (infoMap[name].hasUnseenCalls) {
+          continue;
+        }
+        if (infoMap[name].hasTailCalls) {
+          continue;
+        }
+        if (tailCallees.find(name) != tailCallees.end()) {
+          continue;
+        }
+        auto iter = allCalls.find(name);
+        if (iter == allCalls.end()) {
+          continue;
+        }
+        auto& calls = iter->second;
+        bool allDropped =
+          std::all_of(calls.begin(), calls.end(), [&](Call* call) {
+            return allDroppedCalls.count(call);
+          });
+        if (!allDropped) {
+          continue;
+        }
+        removeReturnValue(func.get(), calls, module);
+        // TODO Removing a drop may also open optimization opportunities in the
+        // callers.
+        changed.insert(func.get());
+      }
+    }
+    if (optimize && !changed.empty()) {
+      OptUtils::optimizeAfterInlining(changed, module, runner);
+    }
+    return !changed.empty();
+  }
+
+private:
+  std::unordered_map<Call*, Expression**> allDroppedCalls;
+
+  void removeParameter(Function* func, Index i, std::vector<Call*>& calls) {
+    // It's cumbersome to adjust local names - TODO don't clear them?
+    Builder::clearLocalNames(func);
+    // Remove the parameter from the function. We must add a new local
+    // for uses of the parameter, but cannot make it use the same index
+    // (in general).
+    std::vector<Type> params(func->sig.params.begin(), func->sig.params.end());
+    auto type = params[i];
+    params.erase(params.begin() + i);
+    func->sig.params = Type(params);
+    Index newIndex = Builder::addVar(func, type);
+    // Update local operations.
+    struct LocalUpdater : public PostWalker<LocalUpdater> {
+      Index removedIndex;
+      Index newIndex;
+      LocalUpdater(Function* func, Index removedIndex, Index newIndex)
+        : removedIndex(removedIndex), newIndex(newIndex) {
+        walk(func->body);
+      }
+      void visitLocalGet(LocalGet* curr) { updateIndex(curr->index); }
+      void visitLocalSet(LocalSet* curr) { updateIndex(curr->index); }
+      void updateIndex(Index& index) {
+        if (index == removedIndex) {
+          index = newIndex;
+        } else if (index > removedIndex) {
+          index--;
+        }
+      }
+    } localUpdater(func, i, newIndex);
+    // Remove the arguments from the calls.
+    for (auto* call : calls) {
+      call->operands.erase(call->operands.begin() + i);
+    }
+  }
+
+  void
+  removeReturnValue(Function* func, std::vector<Call*>& calls, Module* module) {
+    func->sig.results = Type::none;
+    Builder builder(*module);
+    // Remove any return values.
+    struct ReturnUpdater : public PostWalker<ReturnUpdater> {
+      Module* module;
+      ReturnUpdater(Function* func, Module* module) : module(module) {
+        walk(func->body);
+      }
+      void visitReturn(Return* curr) {
+        auto* value = curr->value;
+        assert(value);
+        curr->value = nullptr;
+        Builder builder(*module);
+        replaceCurrent(builder.makeSequence(builder.makeDrop(value), curr));
+      }
+    } returnUpdater(func, module);
+    // Remove any value flowing out.
+    if (func->body->type.isConcrete()) {
+      func->body = builder.makeDrop(func->body);
+    }
+    // Remove the drops on the calls.
+    for (auto* call : calls) {
+      auto iter = allDroppedCalls.find(call);
+      assert(iter != allDroppedCalls.end());
+      Expression** location = iter->second;
+      *location = call;
+      // Update the call's type.
+      if (call->type != Type::unreachable) {
+        call->type = Type::none;
+      }
+    }
+  }
+};
+
+Pass* createDAEPass() { return new DAE(); }
+
+Pass* createDAEOptimizingPass() {
+  auto* ret = new DAE();
+  ret->optimize = true;
+  return ret;
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/DeadCodeElimination.cpp b/binaryen/src/passes/DeadCodeElimination.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/DeadCodeElimination.cpp
@@ -0,0 +1,573 @@
+/*
+ * 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.
+ */
+
+//
+// Removes dead, i.e. unreachable, code.
+//
+// We keep a record of when control flow is reachable. When it isn't, we
+// kill (turn into unreachable). We then fold away entire unreachable
+// expressions.
+//
+// When dead code causes an operation to not happen, like a store, a call
+// or an add, we replace with a block with a list of what does happen.
+// That isn't necessarily smaller, but blocks are friendlier to other
+// optimizations: blocks can be merged and eliminated, and they clearly
+// have no side effects.
+//
+
+#include <ir/block-utils.h>
+#include <ir/branch-utils.h>
+#include <ir/type-updating.h>
+#include <pass.h>
+#include <vector>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+namespace wasm {
+
+struct DeadCodeElimination
+  : public WalkerPass<PostWalker<DeadCodeElimination>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new DeadCodeElimination; }
+
+  // as we remove code, we must keep the types of other nodes valid
+  TypeUpdater typeUpdater;
+
+  Expression* replaceCurrent(Expression* expression) {
+    auto* old = getCurrent();
+    if (old == expression) {
+      return expression;
+    }
+    super::replaceCurrent(expression);
+    // also update the type updater
+    typeUpdater.noteReplacement(old, expression);
+    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);
+      }
+      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++) {
+        if (list[i]->type == Type::unreachable) {
+          list.resize(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]);
+        }
+      }
+    }
+    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));
+      }
+      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;
+        }
+        replaceCurrent(replacement);
+        return;
+      }
+    }
+  }
+
+  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(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/Directize.cpp b/binaryen/src/passes/Directize.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/Directize.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2019 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.
+ */
+
+//
+// Turn indirect calls into direct calls. This is possible if we know
+// the table cannot change, and if we see a constant argument for the
+// indirect call's index.
+//
+
+#include <unordered_map>
+
+#include "asm_v_wasm.h"
+#include "ir/table-utils.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace {
+
+struct FunctionDirectizer : public WalkerPass<PostWalker<FunctionDirectizer>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new FunctionDirectizer(flatTable); }
+
+  FunctionDirectizer(TableUtils::FlatTable* flatTable) : flatTable(flatTable) {}
+
+  void visitCallIndirect(CallIndirect* curr) {
+    if (auto* c = curr->target->dynCast<Const>()) {
+      Index index = c->value.geti32();
+      // If the index is invalid, or the type is wrong, we can
+      // emit an unreachable here, since in Binaryen it is ok to
+      // reorder/replace traps when optimizing (but never to
+      // remove them, at least not by default).
+      if (index >= flatTable->names.size()) {
+        replaceWithUnreachable(curr);
+        return;
+      }
+      auto name = flatTable->names[index];
+      if (!name.is()) {
+        replaceWithUnreachable(curr);
+        return;
+      }
+      auto* func = getModule()->getFunction(name);
+      if (curr->sig != func->sig) {
+        replaceWithUnreachable(curr);
+        return;
+      }
+      // Everything looks good!
+      replaceCurrent(
+        Builder(*getModule())
+          .makeCall(name, curr->operands, curr->type, curr->isReturn));
+    }
+  }
+
+  void doWalkFunction(Function* func) {
+    WalkerPass<PostWalker<FunctionDirectizer>>::doWalkFunction(func);
+    if (changedTypes) {
+      ReFinalize().walkFunctionInModule(func, getModule());
+    }
+  }
+
+private:
+  TableUtils::FlatTable* flatTable;
+  bool changedTypes = false;
+
+  void replaceWithUnreachable(CallIndirect* call) {
+    Builder builder(*getModule());
+    for (auto*& operand : call->operands) {
+      operand = builder.makeDrop(operand);
+    }
+    replaceCurrent(builder.makeSequence(builder.makeBlock(call->operands),
+                                        builder.makeUnreachable()));
+    changedTypes = true;
+  }
+};
+
+struct Directize : public Pass {
+  void run(PassRunner* runner, Module* module) override {
+    if (!module->table.exists) {
+      return;
+    }
+    if (module->table.imported()) {
+      return;
+    }
+    for (auto& ex : module->exports) {
+      if (ex->kind == ExternalKind::Table) {
+        return;
+      }
+    }
+    TableUtils::FlatTable flatTable(module->table);
+    if (!flatTable.valid) {
+      return;
+    }
+    // The table exists and is constant, so this is possible.
+    FunctionDirectizer(&flatTable).run(runner, module);
+  }
+};
+
+} // anonymous namespace
+
+Pass* createDirectizePass() { return new Directize(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/DuplicateFunctionElimination.cpp b/binaryen/src/passes/DuplicateFunctionElimination.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/DuplicateFunctionElimination.cpp
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+//
+// Removes duplicate functions. That can happen due to C++ templates,
+// and also due to types being different at the source level, but
+// identical when finally lowered into concrete wasm code.
+//
+
+#include "ir/function-utils.h"
+#include "ir/hashed.h"
+#include "ir/module-utils.h"
+#include "ir/utils.h"
+#include "opt-utils.h"
+#include "pass.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct DuplicateFunctionElimination : public Pass {
+  void run(PassRunner* runner, Module* module) override {
+    // Multiple iterations may be necessary: A and B may be identical only after
+    // we see the functions C1 and C2 that they call are in fact identical.
+    // Rarely, such "chains" can be very long, so we limit how many we do.
+    auto& options = runner->options;
+    Index limit;
+    if (options.optimizeLevel >= 3 || options.shrinkLevel >= 1) {
+      limit = module->functions.size(); // no limit
+    } else if (options.optimizeLevel >= 2) {
+      // 10 passes usually does most of the work, as this is typically
+      // logarithmic
+      limit = 10;
+    } else {
+      limit = 1;
+    }
+    while (limit > 0) {
+      limit--;
+      // Hash all the functions
+      auto hashes = FunctionHasher::createMap(module);
+      FunctionHasher(&hashes).run(runner, module);
+      // Find hash-equal groups
+      std::map<uint32_t, std::vector<Function*>> hashGroups;
+      ModuleUtils::iterDefinedFunctions(*module, [&](Function* func) {
+        hashGroups[hashes[func]].push_back(func);
+      });
+      // Find actually equal functions and prepare to replace them
+      std::map<Name, Name> replacements;
+      std::set<Name> duplicates;
+      for (auto& pair : hashGroups) {
+        auto& group = pair.second;
+        Index size = group.size();
+        if (size == 1) {
+          continue;
+        }
+        // The groups should be fairly small, and even if a group is large we
+        // should have almost all of them identical, so we should not hit actual
+        // O(N^2) here unless the hash is quite poor.
+        for (Index i = 0; i < size - 1; i++) {
+          auto* first = group[i];
+          if (duplicates.count(first->name)) {
+            continue;
+          }
+          for (Index j = i + 1; j < size; j++) {
+            auto* second = group[j];
+            if (duplicates.count(second->name)) {
+              continue;
+            }
+            if (FunctionUtils::equal(first, second)) {
+              // great, we can replace the second with the first!
+              replacements[second->name] = first->name;
+              duplicates.insert(second->name);
+            }
+          }
+        }
+      }
+      // perform replacements
+      if (replacements.size() > 0) {
+        // remove the duplicates
+        module->removeFunctions(
+          [&](Function* func) { return duplicates.count(func->name) > 0; });
+        OptUtils::replaceFunctions(runner, *module, replacements);
+      } else {
+        break;
+      }
+    }
+  }
+};
+
+Pass* createDuplicateFunctionEliminationPass() {
+  return new DuplicateFunctionElimination();
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/DuplicateImportElimination.cpp b/binaryen/src/passes/DuplicateImportElimination.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/DuplicateImportElimination.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019 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.
+ */
+
+//
+// Removes duplicate imports.
+//
+// TODO: non-function imports too
+//
+
+#include "asm_v_wasm.h"
+#include "ir/import-utils.h"
+#include "opt-utils.h"
+#include "pass.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct DuplicateImportElimination : public Pass {
+  void run(PassRunner* runner, Module* module) override {
+    ImportInfo imports(*module);
+    std::map<Name, Name> replacements;
+    std::map<std::pair<Name, Name>, Name> seen;
+    std::vector<Name> toRemove;
+    for (auto* func : imports.importedFunctions) {
+      auto pair = std::make_pair(func->module, func->base);
+      auto iter = seen.find(pair);
+      if (iter != seen.end()) {
+        auto previousName = iter->second;
+        auto previousFunc = module->getFunction(previousName);
+        // It is ok to import the same thing with multiple types; we can only
+        // merge if the types match, of course.
+        if (previousFunc->sig == func->sig) {
+          replacements[func->name] = previousName;
+          toRemove.push_back(func->name);
+          continue;
+        }
+      }
+      seen[pair] = func->name;
+    }
+    if (!replacements.empty()) {
+      module->updateMaps();
+      OptUtils::replaceFunctions(runner, *module, replacements);
+      for (auto name : toRemove) {
+        module->removeFunction(name);
+      }
+    }
+  }
+};
+
+Pass* createDuplicateImportEliminationPass() {
+  return new DuplicateImportElimination();
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/EmscriptenPIC.cpp b/binaryen/src/passes/EmscriptenPIC.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/EmscriptenPIC.cpp
@@ -0,0 +1,221 @@
+/*
+ * 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/ExtractFunction.cpp b/binaryen/src/passes/ExtractFunction.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/ExtractFunction.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+// Removes code from all functions but one, leaving a valid module
+// with (mostly) just the code you want to debug (function-parallel,
+// non-lto) passes on.
+
+#include "pass.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct ExtractFunction : public Pass {
+  void run(PassRunner* runner, Module* module) override {
+    Name name = runner->options.getArgument(
+      "extract",
+      "ExtractFunction usage:  wasm-opt --pass-arg=extract@FUNCTION_NAME");
+    std::cerr << "extracting " << name << "\n";
+    bool found = false;
+    for (auto& func : module->functions) {
+      if (func->name != name) {
+        // Turn it into an import.
+        func->module = "env";
+        func->base = func->name;
+        func->vars.clear();
+        func->body = nullptr;
+      } else {
+        found = true;
+      }
+    }
+    if (!found) {
+      Fatal() << "could not find the function to extract\n";
+    }
+    // clear data
+    module->memory.segments.clear();
+    module->table.segments.clear();
+    // leave just an export for the thing we want
+    if (!module->getExportOrNull(name)) {
+      module->exports.clear();
+      auto* export_ = new Export;
+      export_->name = name;
+      export_->value = name;
+      export_->kind = ExternalKind::Function;
+      module->addExport(export_);
+    }
+  }
+};
+
+// declare pass
+
+Pass* createExtractFunctionPass() { return new ExtractFunction(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/Flatten.cpp b/binaryen/src/passes/Flatten.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/Flatten.cpp
@@ -0,0 +1,359 @@
+/*
+ * 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.
+ */
+
+//
+// Flattens code into "Flat IR" form. See ir/flat.h.
+//
+
+#include <ir/branch-utils.h>
+#include <ir/effects.h>
+#include <ir/flat.h>
+#include <ir/properties.h>
+#include <ir/utils.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+namespace wasm {
+
+// We use the following algorithm: we maintain a list of "preludes", code
+// that runs right before an expression. When we visit an expression we
+// must handle it and its preludes. If the expression has side effects,
+// we reduce it to a local.get and add a prelude for that. We then handle
+// the preludes, by moving them to the parent or handling them directly.
+// we can move them to the parent if the parent is not a control flow
+// structure. Otherwise, if the parent is a control flow structure, it
+// will incorporate the preludes of its children accordingly.
+// As a result, when we reach a node, we know its children have no
+// side effects (they have been moved to a prelude), or we are a
+// control flow structure (which allows children with side effects,
+// e.g. a return as a block element).
+// Once exception is that we allow an (unreachable) node, which is used
+// when we move something unreachable to another place, and need a
+// placeholder. We will never reach that (unreachable) anyhow
+struct Flatten
+  : public WalkerPass<
+      ExpressionStackWalker<Flatten, UnifiedExpressionVisitor<Flatten>>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new Flatten; }
+
+  // For each expression, a bunch of expressions that should execute right
+  // before it
+  std::unordered_map<Expression*, std::vector<Expression*>> preludes;
+
+  // Break values are sent through a temp local
+  std::unordered_map<Name, Index> breakTemps;
+
+  void visitExpression(Expression* curr) {
+    std::vector<Expression*> ourPreludes;
+    Builder builder(*getModule());
+
+    // Nothing to do for constants and nop.
+    if (Properties::isConstantExpression(curr) || curr->is<Nop>()) {
+      return;
+    }
+
+    if (curr->is<Try>() || curr->is<Throw>() || curr->is<Rethrow>() ||
+        curr->is<BrOnExn>()) {
+      Fatal() << "Flatten does not support EH instructions yet";
+    }
+
+    if (Properties::isControlFlowStructure(curr)) {
+      // handle control flow explicitly. our children do not have control flow,
+      // but they do have preludes which we need to set up in the right place
+
+      // no one should have given us preludes, they are on the children
+      assert(preludes.find(curr) == preludes.end());
+
+      if (auto* block = curr->dynCast<Block>()) {
+        // make a new list, where each item's preludes are added before it
+        ExpressionList newList(getModule()->allocator);
+        for (auto* item : block->list) {
+          auto iter = preludes.find(item);
+          if (iter != preludes.end()) {
+            auto& itemPreludes = iter->second;
+            for (auto* prelude : itemPreludes) {
+              newList.push_back(prelude);
+            }
+            itemPreludes.clear();
+          }
+          newList.push_back(item);
+        }
+        block->list.swap(newList);
+        // remove a block return value
+        auto type = block->type;
+        if (type.isConcrete()) {
+          // if there is a temp index for breaking to the block, use that
+          Index temp;
+          auto iter = breakTemps.find(block->name);
+          if (iter != breakTemps.end()) {
+            temp = iter->second;
+          } else {
+            temp = builder.addVar(getFunction(), type);
+          }
+          auto*& last = block->list.back();
+          if (last->type.isConcrete()) {
+            last = builder.makeLocalSet(temp, last);
+          }
+          block->finalize(Type::none);
+          // and we leave just a get of the value
+          auto* rep = builder.makeLocalGet(temp, type);
+          replaceCurrent(rep);
+          // the whole block is now a prelude
+          ourPreludes.push_back(block);
+        }
+        // the block now has no return value, and may have become unreachable
+        block->finalize(Type::none);
+
+      } else if (auto* iff = curr->dynCast<If>()) {
+        // condition preludes go before the entire if
+        auto* rep = getPreludesWithExpression(iff->condition, iff);
+        // arm preludes go in the arms. we must also remove an if value
+        auto* originalIfTrue = iff->ifTrue;
+        auto* originalIfFalse = iff->ifFalse;
+        auto type = iff->type;
+        Expression* prelude = nullptr;
+        if (type.isConcrete()) {
+          Index temp = builder.addVar(getFunction(), type);
+          if (iff->ifTrue->type.isConcrete()) {
+            iff->ifTrue = builder.makeLocalSet(temp, iff->ifTrue);
+          }
+          if (iff->ifFalse && iff->ifFalse->type.isConcrete()) {
+            iff->ifFalse = builder.makeLocalSet(temp, iff->ifFalse);
+          }
+          // the whole if (+any preludes from the condition) is now a prelude
+          prelude = rep;
+          // and we leave just a get of the value
+          rep = builder.makeLocalGet(temp, type);
+        }
+        iff->ifTrue = getPreludesWithExpression(originalIfTrue, iff->ifTrue);
+        if (iff->ifFalse) {
+          iff->ifFalse =
+            getPreludesWithExpression(originalIfFalse, iff->ifFalse);
+        }
+        iff->finalize();
+        if (prelude) {
+          ReFinalizeNode().visit(prelude);
+          ourPreludes.push_back(prelude);
+        }
+        replaceCurrent(rep);
+
+      } else if (auto* loop = curr->dynCast<Loop>()) {
+        // remove a loop value
+        Expression* rep = loop;
+        auto* originalBody = loop->body;
+        auto type = loop->type;
+        if (type.isConcrete()) {
+          Index temp = builder.addVar(getFunction(), type);
+          loop->body = builder.makeLocalSet(temp, loop->body);
+          // and we leave just a get of the value
+          rep = builder.makeLocalGet(temp, type);
+          // the whole if is now a prelude
+          ourPreludes.push_back(loop);
+          loop->type = Type::none;
+        }
+        loop->body = getPreludesWithExpression(originalBody, loop->body);
+        loop->finalize();
+        replaceCurrent(rep);
+
+      } else {
+        WASM_UNREACHABLE("unexpected expr type");
+      }
+
+    } else {
+      // for anything else, there may be existing preludes
+      auto iter = preludes.find(curr);
+      if (iter != preludes.end()) {
+        ourPreludes.swap(iter->second);
+      }
+
+      // special handling
+      if (auto* set = curr->dynCast<LocalSet>()) {
+        if (set->isTee()) {
+          // we disallow local.tee
+          if (set->value->type == Type::unreachable) {
+            replaceCurrent(set->value); // trivial, no set happens
+          } else {
+            // use a set in a prelude + a get
+            set->makeSet();
+            ourPreludes.push_back(set);
+            Type localType = getFunction()->getLocalType(set->index);
+            replaceCurrent(builder.makeLocalGet(set->index, localType));
+          }
+        }
+
+      } else if (auto* br = curr->dynCast<Break>()) {
+        if (br->value) {
+          auto type = br->value->type;
+          if (type.isConcrete()) {
+            // we are sending a value. use a local instead
+            Type blockType = findBreakTarget(br->name)->type;
+            Index temp = getTempForBreakTarget(br->name, blockType);
+            ourPreludes.push_back(builder.makeLocalSet(temp, br->value));
+
+            // br_if leaves a value on the stack if not taken, which later can
+            // be the last element of the enclosing innermost block and flow
+            // out. The local we created using 'getTempForBreakTarget' returns
+            // the return type of the block this branch is targetting, which may
+            // not be the same with the innermost block's return type. For
+            // example,
+            // (block $any (result anyref)
+            //   (block (result funcref)
+            //     (local.tee $0
+            //       (br_if $any
+            //         (ref.null func)
+            //         (i32.const 0)
+            //       )
+            //     )
+            //   )
+            // )
+            // In this case we need two locals to store (ref.null); one with
+            // funcref type that's for the target block ($label0) and one more
+            // with anyref type in case for flowing out. Here we create the
+            // second 'flowing out' local in case two block's types are
+            // different.
+            if (type != blockType) {
+              temp = builder.addVar(getFunction(), type);
+              ourPreludes.push_back(builder.makeLocalSet(
+                temp, ExpressionManipulator::copy(br->value, *getModule())));
+            }
+
+            if (br->condition) {
+              // the value must also flow out
+              ourPreludes.push_back(br);
+              if (br->type.isConcrete()) {
+                replaceCurrent(builder.makeLocalGet(temp, type));
+              } else {
+                assert(br->type == Type::unreachable);
+                replaceCurrent(builder.makeUnreachable());
+              }
+            }
+            br->value = nullptr;
+            br->finalize();
+          } else {
+            assert(type == Type::unreachable);
+            // we don't need the br at all
+            replaceCurrent(br->value);
+          }
+        }
+
+      } else if (auto* sw = curr->dynCast<Switch>()) {
+        if (sw->value) {
+          auto type = sw->value->type;
+          if (type.isConcrete()) {
+            // we are sending a value. use a local instead
+            Index temp = builder.addVar(getFunction(), type);
+            ourPreludes.push_back(builder.makeLocalSet(temp, sw->value));
+            // we don't know which break target will be hit - assign to them all
+            auto names = BranchUtils::getUniqueTargets(sw);
+            for (auto name : names) {
+              ourPreludes.push_back(
+                builder.makeLocalSet(getTempForBreakTarget(name, type),
+                                     builder.makeLocalGet(temp, type)));
+            }
+            sw->value = nullptr;
+            sw->finalize();
+          } else {
+            assert(type == Type::unreachable);
+            // we don't need the br at all
+            replaceCurrent(sw->value);
+          }
+        }
+      }
+    }
+    // TODO Handle br_on_exn
+
+    // continue for general handling of everything, control flow or otherwise
+    curr = getCurrent(); // we may have replaced it
+    // we have changed children
+    ReFinalizeNode().visit(curr);
+    if (curr->type == Type::unreachable) {
+      ourPreludes.push_back(curr);
+      replaceCurrent(builder.makeUnreachable());
+    } else if (curr->type.isConcrete()) {
+      // use a local
+      auto type = curr->type;
+      Index temp = builder.addVar(getFunction(), type);
+      ourPreludes.push_back(builder.makeLocalSet(temp, curr));
+      replaceCurrent(builder.makeLocalGet(temp, type));
+    }
+
+    // next, finish up: migrate our preludes if we can
+    if (!ourPreludes.empty()) {
+      auto* parent = getParent();
+      if (parent && !Properties::isControlFlowStructure(parent)) {
+        auto& parentPreludes = preludes[parent];
+        for (auto* prelude : ourPreludes) {
+          parentPreludes.push_back(prelude);
+        }
+      } else {
+        // keep our preludes, parent will handle them
+        preludes[getCurrent()].swap(ourPreludes);
+      }
+    }
+  }
+
+  void visitFunction(Function* curr) {
+    auto* originalBody = curr->body;
+    // if the body is a block with a result, turn that into a return
+    if (curr->body->type.isConcrete()) {
+      curr->body = Builder(*getModule()).makeReturn(curr->body);
+    }
+    // the body may have preludes
+    curr->body = getPreludesWithExpression(originalBody, curr->body);
+  }
+
+private:
+  // gets an expression, either by itself, or in a block with its
+  // preludes (which we use up) before it
+  Expression* getPreludesWithExpression(Expression* curr) {
+    return getPreludesWithExpression(curr, curr);
+  }
+
+  // gets an expression, either by itself, or in a block with some
+  // preludes (which we use up) for another expression before it
+  Expression* getPreludesWithExpression(Expression* preluder,
+                                        Expression* after) {
+    auto iter = preludes.find(preluder);
+    if (iter == preludes.end()) {
+      return after;
+    }
+    // we have preludes
+    auto& thePreludes = iter->second;
+    auto* ret = Builder(*getModule()).makeBlock(thePreludes);
+    thePreludes.clear();
+    ret->list.push_back(after);
+    ret->finalize();
+    return ret;
+  }
+
+  // get the temp local to be used for breaks to that target. allocates
+  // one if there isn't one yet
+  Index getTempForBreakTarget(Name name, Type type) {
+    auto iter = breakTemps.find(name);
+    if (iter != breakTemps.end()) {
+      return iter->second;
+    } else {
+      return breakTemps[name] =
+               Builder(*getModule()).addVar(getFunction(), type);
+    }
+  }
+};
+
+Pass* createFlattenPass() { return new Flatten(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/FuncCastEmulation.cpp b/binaryen/src/passes/FuncCastEmulation.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/FuncCastEmulation.cpp
@@ -0,0 +1,225 @@
+/*
+ * 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.
+ */
+
+//
+// Instruments all indirect calls so that they work even if a function
+// pointer was cast incorrectly. For example, if you cast an int (int, float)
+// to an int (int, float, int) and call it natively, on most archs it will
+// happen to work, ignoring the extra param, whereas in wasm it will trap.
+// When porting code that relies on such casts working (like e.g. Python),
+// this pass may be useful. It sets a new "ABI" for indirect calls, in which
+// they all return an i64 and they have a fixed number of i64 params, and
+// the pass converts everything to go through that.
+//
+// This should work even with dynamic linking, however, the number of
+// params must be identical, i.e., the "ABI" must match.
+//
+
+#include <asm_v_wasm.h>
+#include <ir/literal-utils.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+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);
+  switch (value->type.getBasic()) {
+    case Type::i32: {
+      value = builder.makeUnary(ExtendUInt32, value);
+      break;
+    }
+    case Type::i64: {
+      // already good
+      break;
+    }
+    case Type::f32: {
+      value = builder.makeUnary(ExtendUInt32,
+                                builder.makeUnary(ReinterpretFloat32, value));
+      break;
+    }
+    case Type::f64: {
+      value = builder.makeUnary(ReinterpretFloat64, value);
+      break;
+    }
+    case Type::v128: {
+      WASM_UNREACHABLE("v128 not implemented yet");
+    }
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref: {
+      WASM_UNREACHABLE("reference types cannot be converted to i64");
+    }
+    case Type::none: {
+      // the value is none, but we need a value here
+      value =
+        builder.makeSequence(value, LiteralUtils::makeZero(Type::i64, *module));
+      break;
+    }
+    case Type::unreachable: {
+      // can leave it, the call isn't taken anyhow
+      break;
+    }
+  }
+  return value;
+}
+
+// Converts a value from the ABI type of i64 to the expected type
+static Expression* fromABI(Expression* value, Type type, Module* module) {
+  Builder builder(*module);
+  switch (type.getBasic()) {
+    case Type::i32: {
+      value = builder.makeUnary(WrapInt64, value);
+      break;
+    }
+    case Type::i64: {
+      // already good
+      break;
+    }
+    case Type::f32: {
+      value = builder.makeUnary(ReinterpretInt32,
+                                builder.makeUnary(WrapInt64, value));
+      break;
+    }
+    case Type::f64: {
+      value = builder.makeUnary(ReinterpretInt64, value);
+      break;
+    }
+    case Type::v128: {
+      WASM_UNREACHABLE("v128 not implemented yet");
+    }
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref: {
+      WASM_UNREACHABLE("reference types cannot be converted from i64");
+    }
+    case Type::none: {
+      value = builder.makeDrop(value);
+    }
+    case Type::unreachable: {
+      // can leave it, the call isn't taken anyhow
+      break;
+    }
+  }
+  return value;
+}
+
+struct ParallelFuncCastEmulation
+  : public WalkerPass<PostWalker<ParallelFuncCastEmulation>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new ParallelFuncCastEmulation(ABIType); }
+
+  ParallelFuncCastEmulation(Signature ABIType) : ABIType(ABIType) {}
+
+  void visitCallIndirect(CallIndirect* curr) {
+    if (curr->operands.size() > NUM_PARAMS) {
+      Fatal() << "FuncCastEmulation::NUM_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) {
+      curr->operands.push_back(LiteralUtils::makeZero(Type::i64, *getModule()));
+    }
+    // Set the new types
+    curr->sig = ABIType;
+    auto oldType = curr->type;
+    curr->type = Type::i64;
+    curr->finalize(); // may be unreachable
+    // Fix up return value
+    replaceCurrent(fromABI(curr, oldType, getModule()));
+  }
+
+private:
+  // The signature of a call with the right params and return
+  Signature ABIType;
+};
+
+struct FuncCastEmulation : public Pass {
+  void run(PassRunner* runner, Module* module) override {
+    // we just need the one ABI function type for all indirect calls
+    Signature ABIType(Type(std::vector<Type>(NUM_PARAMS, 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);
+          funcThunks[name] = thunk;
+          name = thunk;
+        } else {
+          name = iter->second;
+        }
+      }
+    }
+    // update call_indirects
+    ParallelFuncCastEmulation(ABIType).run(runner, module);
+  }
+
+private:
+  // Creates a thunk for a function, casting args and return value as needed.
+  Name makeThunk(Name name, Module* module) {
+    Name thunk = std::string("byn$fpcast-emu$") + name.str;
+    if (module->getFunctionOrNull(thunk)) {
+      Fatal() << "FuncCastEmulation::makeThunk seems a thunk name already in "
+                 "use. Was the pass already run on this code?";
+    }
+    // The item in the table may be a function or a function import.
+    auto* func = module->getFunction(name);
+    Type type = func->sig.results;
+    Builder builder(*module);
+    std::vector<Expression*> callOperands;
+    Index i = 0;
+    for (const auto& param : func->sig.params) {
+      callOperands.push_back(
+        fromABI(builder.makeLocalGet(i++, Type::i64), param, module));
+    }
+    auto* call = builder.makeCall(name, callOperands, type);
+    std::vector<Type> thunkParams;
+    for (Index i = 0; i < NUM_PARAMS; i++) {
+      thunkParams.push_back(Type::i64);
+    }
+    auto* thunkFunc =
+      builder.makeFunction(thunk,
+                           Signature(Type(thunkParams), Type::i64),
+                           {}, // no vars
+                           toABI(call, module));
+    module->addFunction(thunkFunc);
+    return thunk;
+  }
+};
+
+Pass* createFuncCastEmulationPass() { return new FuncCastEmulation(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/GenerateDynCalls.cpp b/binaryen/src/passes/GenerateDynCalls.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/GenerateDynCalls.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+//
+// Create `dynCall` helper functions used by emscripten.  These allow JavaScript
+// to call back into WebAssembly given a function pointer (table index). These
+// are used primarily to implement the `invoke` functions which in turn are used
+// to implment exceptions handling and setjmp/longjmp.  Creates one for each
+// signature in the indirect function table.
+//
+
+#include "abi/js.h"
+#include "asm_v_wasm.h"
+#include "ir/import-utils.h"
+#include "pass.h"
+#include "support/debug.h"
+#include "wasm-builder.h"
+
+#define DEBUG_TYPE "generate-dyncalls"
+
+namespace wasm {
+
+struct GenerateDynCalls : public WalkerPass<PostWalker<GenerateDynCalls>> {
+  GenerateDynCalls(bool onlyI64) : onlyI64(onlyI64) {}
+
+  void doWalkModule(Module* wasm) {
+    PostWalker<GenerateDynCalls>::doWalkModule(wasm);
+    for (auto& sig : invokeSigs) {
+      generateDynCallThunk(sig);
+    }
+  }
+
+  void visitTable(Table* table) {
+    // Generate dynCalls for functions in the table
+    if (table->segments.size() > 0) {
+      std::vector<Name> tableSegmentData;
+      for (const auto& indirectFunc : table->segments[0].data) {
+        generateDynCallThunk(getModule()->getFunction(indirectFunc)->sig);
+      }
+    }
+  }
+
+  void visitFunction(Function* func) {
+    // Generate dynCalls for invokes
+    if (func->imported() && func->module == ENV &&
+        func->base.startsWith("invoke_")) {
+      Signature sig = func->sig;
+      // The first parameter is a pointer to the original function that's called
+      // by the invoke, so skip it
+      std::vector<Type> newParams(sig.params.begin() + 1, sig.params.end());
+      invokeSigs.insert(Signature(Type(newParams), sig.results));
+    }
+  }
+
+  void generateDynCallThunk(Signature sig);
+
+  bool onlyI64;
+  // The set of all invokes' signatures
+  std::set<Signature> invokeSigs;
+};
+
+static bool hasI64(Signature sig) {
+  // We only generate dynCall functions for signatures that contain i64. This is
+  // because any other function can be called directly from JavaScript using the
+  // wasm table.
+  for (auto t : sig.results) {
+    if (t.getID() == Type::i64) {
+      return true;
+    }
+  }
+  for (auto t : sig.params) {
+    if (t.getID() == Type::i64) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static void exportFunction(Module& wasm, Name name, bool must_export) {
+  if (!wasm.getFunctionOrNull(name)) {
+    assert(!must_export);
+    return;
+  }
+  if (wasm.getExportOrNull(name)) {
+    return; // Already exported
+  }
+  auto exp = new Export;
+  exp->name = exp->value = name;
+  exp->kind = ExternalKind::Function;
+  wasm.addExport(exp);
+}
+
+void GenerateDynCalls::generateDynCallThunk(Signature sig) {
+  if (onlyI64 && !hasI64(sig)) {
+    return;
+  }
+
+  Module* wasm = getModule();
+  Builder builder(*wasm);
+  Name name = std::string("dynCall_") + getSig(sig.results, sig.params);
+  if (wasm->getFunctionOrNull(name) || wasm->getExportOrNull(name)) {
+    return; // module already contains this dyncall
+  }
+  std::vector<NameType> params;
+  params.emplace_back("fptr", Type::i32); // function pointer param
+  int p = 0;
+  for (const auto& param : sig.params) {
+    params.emplace_back(std::to_string(p++), param);
+  }
+  Function* f = builder.makeFunction(name, std::move(params), sig.results, {});
+  Expression* fptr = builder.makeLocalGet(0, Type::i32);
+  std::vector<Expression*> args;
+  Index i = 0;
+  for (const auto& param : sig.params) {
+    args.push_back(builder.makeLocalGet(++i, param));
+  }
+  Expression* call = builder.makeCallIndirect(fptr, args, sig);
+  f->body = call;
+
+  wasm->addFunction(f);
+  exportFunction(*wasm, f->name, true);
+}
+
+Pass* createGenerateDynCallsPass() { return new GenerateDynCalls(false); }
+Pass* createGenerateI64DynCallsPass() { return new GenerateDynCalls(true); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/I64ToI32Lowering.cpp b/binaryen/src/passes/I64ToI32Lowering.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/I64ToI32Lowering.cpp
@@ -0,0 +1,1591 @@
+/*
+ * 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.
+ */
+
+//
+// Lowers i64s to i32s by splitting variables and arguments
+// into pairs of i32s. i64 return values are lowered by
+// returning the low half and storing the high half into a
+// global.
+//
+
+#include "abi/js.h"
+#include "asmjs/shared-constants.h"
+#include "emscripten-optimizer/istring.h"
+#include "ir/flat.h"
+#include "ir/iteration.h"
+#include "ir/memory-utils.h"
+#include "ir/module-utils.h"
+#include "ir/names.h"
+#include "pass.h"
+#include "support/name.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+#include <algorithm>
+
+namespace wasm {
+
+static Name makeHighName(Name n) { return std::string(n.c_str()) + "$hi"; }
+
+struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
+  struct TempVar {
+    TempVar(Index idx, Type ty, I64ToI32Lowering& pass)
+      : idx(idx), pass(pass), moved(false), ty(ty) {}
+
+    TempVar(TempVar&& other)
+      : idx(other), pass(other.pass), moved(false), ty(other.ty) {
+      assert(!other.moved);
+      other.moved = true;
+    }
+
+    TempVar& operator=(TempVar&& rhs) {
+      assert(!rhs.moved);
+      // free overwritten idx
+      if (!moved) {
+        freeIdx();
+      }
+      idx = rhs.idx;
+      rhs.moved = true;
+      moved = false;
+      return *this;
+    }
+
+    ~TempVar() {
+      if (!moved) {
+        freeIdx();
+      }
+    }
+
+    bool operator==(const TempVar& rhs) {
+      assert(!moved && !rhs.moved);
+      return idx == rhs.idx;
+    }
+
+    operator Index() {
+      assert(!moved);
+      return idx;
+    }
+
+    // disallow copying
+    TempVar(const TempVar&) = delete;
+    TempVar& operator=(const TempVar&) = delete;
+
+  private:
+    void freeIdx() {
+      auto& freeList = pass.freeTemps[ty.getBasic()];
+      assert(std::find(freeList.begin(), freeList.end(), idx) ==
+             freeList.end());
+      freeList.push_back(idx);
+    }
+
+    Index idx;
+    I64ToI32Lowering& pass;
+    bool moved; // since C++ will still destruct moved-from values
+    Type ty;
+  };
+
+  // false since function types need to be lowered
+  // TODO: allow module-level transformations in parallel passes
+  bool isFunctionParallel() override { return false; }
+
+  Pass* create() override { return new I64ToI32Lowering; }
+
+  void doWalkModule(Module* module) {
+    if (!builder) {
+      builder = make_unique<Builder>(*module);
+    }
+    // add new globals for high bits
+    for (size_t i = 0, globals = module->globals.size(); i < globals; ++i) {
+      auto* curr = module->globals[i].get();
+      if (curr->type != Type::i64) {
+        continue;
+      }
+      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);
+      if (curr->imported()) {
+        Fatal() << "TODO: imported i64 globals";
+      } else {
+        if (auto* c = curr->init->dynCast<Const>()) {
+          uint64_t value = c->value.geti64();
+          c->value = Literal(uint32_t(value));
+          c->type = Type::i32;
+          high->init = builder->makeConst(uint32_t(value >> 32));
+        } else if (auto* get = curr->init->dynCast<GlobalGet>()) {
+          high->init =
+            builder->makeGlobalGet(makeHighName(get->name), Type::i32);
+        } else {
+          WASM_UNREACHABLE("unexpected expression type");
+        }
+        curr->init->type = Type::i32;
+      }
+    }
+
+    // For functions that return 64-bit values, we use this global variable
+    // to return the high 32 bits.
+    auto* highBits = new Global();
+    highBits->type = Type::i32;
+    highBits->name = INT64_TO_32_HIGH_BITS;
+    highBits->init = builder->makeConst(int32_t(0));
+    highBits->mutable_ = true;
+    module->addGlobal(highBits);
+    PostWalker<I64ToI32Lowering>::doWalkModule(module);
+  }
+
+  void doWalkFunction(Function* func) {
+    Flat::verifyFlatness(func);
+    // create builder here if this is first entry to module for this object
+    if (!builder) {
+      builder = make_unique<Builder>(*getModule());
+    }
+    indexMap.clear();
+    highBitVars.clear();
+    freeTemps.clear();
+    Module temp;
+    auto* oldFunc = ModuleUtils::copyFunction(func, temp);
+    func->sig.params = Type::none;
+    func->vars.clear();
+    func->localNames.clear();
+    func->localIndices.clear();
+    Index newIdx = 0;
+    Names::ensureNames(oldFunc);
+    for (Index i = 0; i < oldFunc->getNumLocals(); ++i) {
+      assert(oldFunc->hasLocalName(i));
+      Name lowName = oldFunc->getLocalName(i);
+      Name highName = makeHighName(lowName);
+      Type paramType = oldFunc->getLocalType(i);
+      auto builderFunc =
+        (i < oldFunc->getVarIndexBase())
+          ? Builder::addParam
+          : static_cast<Index (*)(Function*, Name, Type)>(Builder::addVar);
+      if (paramType == Type::i64) {
+        builderFunc(func, lowName, Type::i32);
+        builderFunc(func, highName, Type::i32);
+        indexMap[i] = newIdx;
+        newIdx += 2;
+      } else {
+        builderFunc(func, lowName, paramType);
+        indexMap[i] = newIdx++;
+      }
+    }
+    nextTemp = func->getNumLocals();
+    PostWalker<I64ToI32Lowering>::doWalkFunction(func);
+  }
+
+  void visitFunction(Function* func) {
+    if (func->imported()) {
+      return;
+    }
+    if (func->sig.results == Type::i64) {
+      func->sig.results = Type::i32;
+      // body may not have out param if it ends with control flow
+      if (hasOutParam(func->body)) {
+        TempVar highBits = fetchOutParam(func->body);
+        TempVar lowBits = getTemp();
+        LocalSet* setLow = builder->makeLocalSet(lowBits, func->body);
+        GlobalSet* setHigh = builder->makeGlobalSet(
+          INT64_TO_32_HIGH_BITS, builder->makeLocalGet(highBits, Type::i32));
+        LocalGet* getLow = builder->makeLocalGet(lowBits, Type::i32);
+        func->body = builder->blockify(setLow, setHigh, getLow);
+      }
+    }
+    int idx = 0;
+    for (size_t i = func->getNumLocals(); i < nextTemp; i++) {
+      Name tmpName("i64toi32_i32$" + std::to_string(idx++));
+      builder->addVar(func, tmpName, tempTypes[i]);
+    }
+  }
+
+  template<typename T>
+  using BuilderFunc = std::function<T*(std::vector<Expression*>&, Type)>;
+
+  // Fixes up a call. If we performed fixups, returns the call; otherwise
+  // returns nullptr;
+  template<typename T>
+  T* visitGenericCall(T* curr, BuilderFunc<T> callBuilder) {
+    bool fixed = false;
+    std::vector<Expression*> args;
+    for (auto* e : curr->operands) {
+      args.push_back(e);
+      if (hasOutParam(e)) {
+        TempVar argHighBits = fetchOutParam(e);
+        args.push_back(builder->makeLocalGet(argHighBits, Type::i32));
+        fixed = true;
+      }
+    }
+    if (curr->type != Type::i64) {
+      auto* ret = callBuilder(args, curr->type);
+      replaceCurrent(ret);
+      return fixed ? ret : nullptr;
+    }
+    TempVar lowBits = getTemp();
+    TempVar highBits = getTemp();
+    auto* call = callBuilder(args, Type::i32);
+    LocalSet* doCall = builder->makeLocalSet(lowBits, call);
+    LocalSet* setHigh = builder->makeLocalSet(
+      highBits, builder->makeGlobalGet(INT64_TO_32_HIGH_BITS, Type::i32));
+    LocalGet* getLow = builder->makeLocalGet(lowBits, Type::i32);
+    Block* result = builder->blockify(doCall, setHigh, getLow);
+    setOutParam(result, std::move(highBits));
+    replaceCurrent(result);
+    return call;
+  }
+  void visitCall(Call* curr) {
+    if (curr->isReturn &&
+        getModule()->getFunction(curr->target)->sig.results == Type::i64) {
+      Fatal()
+        << "i64 to i32 lowering of return_call values not yet implemented";
+    }
+    auto* fixedCall = visitGenericCall<Call>(
+      curr, [&](std::vector<Expression*>& args, Type results) {
+        return builder->makeCall(curr->target, args, results, curr->isReturn);
+      });
+    // If this was to an import, we need to call the legal version. This assumes
+    // that legalize-js-interface has been run before.
+    if (fixedCall && getModule()->getFunction(fixedCall->target)->imported()) {
+      fixedCall->target = std::string("legalfunc$") + fixedCall->target.str;
+      return;
+    }
+  }
+
+  void visitCallIndirect(CallIndirect* curr) {
+    if (curr->isReturn && curr->sig.results == Type::i64) {
+      Fatal()
+        << "i64 to i32 lowering of return_call values not yet implemented";
+    }
+    visitGenericCall<CallIndirect>(
+      curr, [&](std::vector<Expression*>& args, Type results) {
+        std::vector<Type> params;
+        for (const auto& param : curr->sig.params) {
+          if (param == Type::i64) {
+            params.push_back(Type::i32);
+            params.push_back(Type::i32);
+          } else {
+            params.push_back(param);
+          }
+        }
+        return builder->makeCallIndirect(
+          curr->target, args, Signature(Type(params), results), curr->isReturn);
+      });
+  }
+
+  void visitLocalGet(LocalGet* curr) {
+    const auto mappedIndex = indexMap[curr->index];
+    // Need to remap the local into the new naming scheme, regardless of
+    // the type of the local.
+    curr->index = mappedIndex;
+    if (curr->type != Type::i64) {
+      return;
+    }
+    curr->type = Type::i32;
+    TempVar highBits = getTemp();
+    LocalSet* setHighBits = builder->makeLocalSet(
+      highBits, builder->makeLocalGet(mappedIndex + 1, Type::i32));
+    Block* result = builder->blockify(setHighBits, curr);
+    replaceCurrent(result);
+    setOutParam(result, std::move(highBits));
+  }
+
+  void lowerTee(LocalSet* curr) {
+    TempVar highBits = fetchOutParam(curr->value);
+    TempVar tmp = getTemp();
+    curr->type = Type::i32;
+    LocalSet* setLow = builder->makeLocalSet(tmp, curr);
+    LocalSet* setHigh = builder->makeLocalSet(
+      curr->index + 1, builder->makeLocalGet(highBits, Type::i32));
+    LocalGet* getLow = builder->makeLocalGet(tmp, Type::i32);
+    Block* result = builder->blockify(setLow, setHigh, getLow);
+    replaceCurrent(result);
+    setOutParam(result, std::move(highBits));
+  }
+
+  void visitLocalSet(LocalSet* curr) {
+    const auto mappedIndex = indexMap[curr->index];
+    // Need to remap the local into the new naming scheme, regardless of
+    // the type of the local.  Note that lowerTee depends on this happening.
+    curr->index = mappedIndex;
+    if (!hasOutParam(curr->value)) {
+      return;
+    }
+    if (curr->isTee()) {
+      lowerTee(curr);
+      return;
+    }
+    TempVar highBits = fetchOutParam(curr->value);
+    auto* setHigh = builder->makeLocalSet(
+      mappedIndex + 1, builder->makeLocalGet(highBits, Type::i32));
+    Block* result = builder->blockify(curr, setHigh);
+    replaceCurrent(result);
+  }
+
+  void visitGlobalGet(GlobalGet* curr) {
+    if (!getFunction()) {
+      return; // if in a global init, skip - we already handled that.
+    }
+    if (!originallyI64Globals.count(curr->name)) {
+      return;
+    }
+    curr->type = Type::i32;
+    TempVar highBits = getTemp();
+    LocalSet* setHighBits = builder->makeLocalSet(
+      highBits, builder->makeGlobalGet(makeHighName(curr->name), Type::i32));
+    Block* result = builder->blockify(setHighBits, curr);
+    replaceCurrent(result);
+    setOutParam(result, std::move(highBits));
+  }
+
+  void visitGlobalSet(GlobalSet* curr) {
+    if (!originallyI64Globals.count(curr->name)) {
+      return;
+    }
+    if (handleUnreachable(curr)) {
+      return;
+    }
+    TempVar highBits = fetchOutParam(curr->value);
+    auto* setHigh = builder->makeGlobalSet(
+      makeHighName(curr->name), builder->makeLocalGet(highBits, Type::i32));
+    replaceCurrent(builder->makeSequence(curr, setHigh));
+  }
+
+  void visitLoad(Load* curr) {
+    if (curr->type != Type::i64) {
+      return;
+    }
+    assert(!curr->isAtomic && "64-bit atomic load not implemented");
+    TempVar lowBits = getTemp();
+    TempVar highBits = getTemp();
+    TempVar ptrTemp = getTemp();
+    LocalSet* setPtr = builder->makeLocalSet(ptrTemp, curr->ptr);
+    LocalSet* loadHigh;
+    if (curr->bytes == 8) {
+      loadHigh = builder->makeLocalSet(
+        highBits,
+        builder->makeLoad(4,
+                          curr->signed_,
+                          curr->offset + 4,
+                          std::min(uint32_t(curr->align), uint32_t(4)),
+                          builder->makeLocalGet(ptrTemp, Type::i32),
+                          Type::i32));
+    } else if (curr->signed_) {
+      loadHigh = builder->makeLocalSet(
+        highBits,
+        builder->makeBinary(ShrSInt32,
+                            builder->makeLocalGet(lowBits, Type::i32),
+                            builder->makeConst(int32_t(31))));
+    } else {
+      loadHigh =
+        builder->makeLocalSet(highBits, builder->makeConst(int32_t(0)));
+    }
+    curr->type = Type::i32;
+    curr->bytes = std::min(curr->bytes, uint8_t(4));
+    curr->align = std::min(uint32_t(curr->align), uint32_t(4));
+    curr->ptr = builder->makeLocalGet(ptrTemp, Type::i32);
+    Block* result =
+      builder->blockify(setPtr,
+                        builder->makeLocalSet(lowBits, curr),
+                        loadHigh,
+                        builder->makeLocalGet(lowBits, Type::i32));
+    replaceCurrent(result);
+    setOutParam(result, std::move(highBits));
+  }
+
+  void visitStore(Store* curr) {
+    if (!hasOutParam(curr->value)) {
+      return;
+    }
+    assert(curr->offset + 4 > curr->offset);
+    assert(!curr->isAtomic && "atomic store not implemented");
+    TempVar highBits = fetchOutParam(curr->value);
+    uint8_t bytes = curr->bytes;
+    curr->bytes = std::min(curr->bytes, uint8_t(4));
+    curr->align = std::min(uint32_t(curr->align), uint32_t(4));
+    curr->valueType = Type::i32;
+    if (bytes == 8) {
+      TempVar ptrTemp = getTemp();
+      LocalSet* setPtr = builder->makeLocalSet(ptrTemp, curr->ptr);
+      curr->ptr = builder->makeLocalGet(ptrTemp, Type::i32);
+      curr->finalize();
+      Store* storeHigh =
+        builder->makeStore(4,
+                           curr->offset + 4,
+                           std::min(uint32_t(curr->align), uint32_t(4)),
+                           builder->makeLocalGet(ptrTemp, Type::i32),
+                           builder->makeLocalGet(highBits, Type::i32),
+                           Type::i32);
+      replaceCurrent(builder->blockify(setPtr, curr, storeHigh));
+    }
+  }
+
+  void visitAtomicRMW(AtomicRMW* curr) {
+    if (handleUnreachable(curr)) {
+      return;
+    }
+    if (curr->type != Type::i64) {
+      return;
+    }
+    // We cannot break this up into smaller operations as it must be atomic.
+    // Lower to an instrinsic function that wasm2js will implement.
+    TempVar lowBits = getTemp();
+    TempVar highBits = getTemp();
+    auto* getLow = builder->makeCall(
+      ABI::wasm2js::ATOMIC_RMW_I64,
+      {builder->makeConst(int32_t(curr->op)),
+       builder->makeConst(int32_t(curr->bytes)),
+       builder->makeConst(int32_t(curr->offset)),
+       curr->ptr,
+       curr->value,
+       builder->makeLocalGet(fetchOutParam(curr->value), Type::i32)},
+      Type::i32);
+    auto* getHigh =
+      builder->makeCall(ABI::wasm2js::GET_STASHED_BITS, {}, Type::i32);
+    auto* setLow = builder->makeLocalSet(lowBits, getLow);
+    auto* setHigh = builder->makeLocalSet(highBits, getHigh);
+    auto* finalGet = builder->makeLocalGet(lowBits, Type::i32);
+    auto* result = builder->makeBlock({setLow, setHigh, finalGet});
+    setOutParam(result, std::move(highBits));
+    replaceCurrent(result);
+  }
+
+  void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+    assert(curr->type != Type::i64 && "64-bit AtomicCmpxchg not implemented");
+  }
+
+  void visitAtomicWait(AtomicWait* curr) {
+    // The last parameter is an i64, so we cannot leave it as it is
+    assert(curr->offset == 0);
+    replaceCurrent(builder->makeCall(
+      ABI::wasm2js::ATOMIC_WAIT_I32,
+      {curr->ptr,
+       curr->expected,
+       curr->timeout,
+       builder->makeLocalGet(fetchOutParam(curr->timeout), Type::i32)},
+      Type::i32));
+  }
+
+  void visitConst(Const* curr) {
+    if (!getFunction()) {
+      return; // if in a global init, skip - we already handled that.
+    }
+    if (curr->type != Type::i64) {
+      return;
+    }
+    TempVar highBits = getTemp();
+    Const* lowVal =
+      builder->makeConst(int32_t(curr->value.geti64() & 0xffffffff));
+    LocalSet* setHigh = builder->makeLocalSet(
+      highBits,
+      builder->makeConst(int32_t(uint64_t(curr->value.geti64()) >> 32)));
+    Block* result = builder->blockify(setHigh, lowVal);
+    setOutParam(result, std::move(highBits));
+    replaceCurrent(result);
+  }
+
+  void lowerEqZInt64(Unary* curr) {
+    TempVar highBits = fetchOutParam(curr->value);
+
+    auto* result = builder->makeUnary(
+      EqZInt32,
+      builder->makeBinary(
+        OrInt32, curr->value, builder->makeLocalGet(highBits, Type::i32)));
+
+    replaceCurrent(result);
+  }
+
+  void lowerExtendUInt32(Unary* curr) {
+    TempVar highBits = getTemp();
+    Block* result = builder->blockify(
+      builder->makeLocalSet(highBits, builder->makeConst(int32_t(0))),
+      curr->value);
+    setOutParam(result, std::move(highBits));
+    replaceCurrent(result);
+  }
+
+  void lowerExtendSInt32(Unary* curr) {
+    TempVar highBits = getTemp();
+    TempVar lowBits = getTemp();
+
+    LocalSet* setLow = builder->makeLocalSet(lowBits, curr->value);
+    LocalSet* setHigh = builder->makeLocalSet(
+      highBits,
+      builder->makeBinary(ShrSInt32,
+                          builder->makeLocalGet(lowBits, Type::i32),
+                          builder->makeConst(int32_t(31))));
+
+    Block* result = builder->blockify(
+      setLow, setHigh, builder->makeLocalGet(lowBits, Type::i32));
+
+    setOutParam(result, std::move(highBits));
+    replaceCurrent(result);
+  }
+
+  void lowerWrapInt64(Unary* curr) {
+    // free the temp var
+    fetchOutParam(curr->value);
+    replaceCurrent(curr->value);
+  }
+
+  void lowerReinterpretFloat64(Unary* curr) {
+    // Assume that the wasm file assumes the address 0 is invalid and roundtrip
+    // our f64 through memory at address 0
+    TempVar highBits = getTemp();
+    Block* result = builder->blockify(
+      builder->makeCall(
+        ABI::wasm2js::SCRATCH_STORE_F64, {curr->value}, Type::none),
+      builder->makeLocalSet(highBits,
+                            builder->makeCall(ABI::wasm2js::SCRATCH_LOAD_I32,
+                                              {builder->makeConst(int32_t(1))},
+                                              Type::i32)),
+      builder->makeCall(ABI::wasm2js::SCRATCH_LOAD_I32,
+                        {builder->makeConst(int32_t(0))},
+                        Type::i32));
+    setOutParam(result, std::move(highBits));
+    replaceCurrent(result);
+    MemoryUtils::ensureExists(getModule()->memory);
+    ABI::wasm2js::ensureHelpers(getModule());
+  }
+
+  void lowerReinterpretInt64(Unary* curr) {
+    // Assume that the wasm file assumes the address 0 is invalid and roundtrip
+    // our i64 through memory at address 0
+    TempVar highBits = fetchOutParam(curr->value);
+    Block* result = builder->blockify(
+      builder->makeCall(ABI::wasm2js::SCRATCH_STORE_I32,
+                        {builder->makeConst(int32_t(0)), curr->value},
+                        Type::none),
+      builder->makeCall(ABI::wasm2js::SCRATCH_STORE_I32,
+                        {builder->makeConst(int32_t(1)),
+                         builder->makeLocalGet(highBits, Type::i32)},
+                        Type::none),
+      builder->makeCall(ABI::wasm2js::SCRATCH_LOAD_F64, {}, Type::f64));
+    replaceCurrent(result);
+    MemoryUtils::ensureExists(getModule()->memory);
+    ABI::wasm2js::ensureHelpers(getModule());
+  }
+
+  void lowerTruncFloatToInt(Unary* curr) {
+    // hiBits = if abs(f) >= 1.0 {
+    //    if f > 0.0 {
+    //        (unsigned) min(
+    //          floor(f / (float) U32_MAX),
+    //          (float) U32_MAX - 1,
+    //        )
+    //    } else {
+    //        (unsigned) ceil((f - (float) (unsigned) f) / ((float) U32_MAX))
+    //    }
+    // } else {
+    //    0
+    // }
+    //
+    // loBits = (unsigned) f;
+
+    Literal litZero, litOne, u32Max;
+    UnaryOp trunc, convert, abs, floor, ceil;
+    Type localType;
+    BinaryOp ge, gt, min, div, sub;
+    switch (curr->op) {
+      case TruncSFloat32ToInt64:
+      case TruncUFloat32ToInt64: {
+        litZero = Literal((float)0);
+        litOne = Literal((float)1);
+        u32Max = Literal(((float)UINT_MAX) + 1);
+        trunc = TruncUFloat32ToInt32;
+        convert = ConvertUInt32ToFloat32;
+        localType = Type::f32;
+        abs = AbsFloat32;
+        ge = GeFloat32;
+        gt = GtFloat32;
+        min = MinFloat32;
+        floor = FloorFloat32;
+        ceil = CeilFloat32;
+        div = DivFloat32;
+        sub = SubFloat32;
+        break;
+      }
+      case TruncSFloat64ToInt64:
+      case TruncUFloat64ToInt64: {
+        litZero = Literal((double)0);
+        litOne = Literal((double)1);
+        u32Max = Literal(((double)UINT_MAX) + 1);
+        trunc = TruncUFloat64ToInt32;
+        convert = ConvertUInt32ToFloat64;
+        localType = Type::f64;
+        abs = AbsFloat64;
+        ge = GeFloat64;
+        gt = GtFloat64;
+        min = MinFloat64;
+        floor = FloorFloat64;
+        ceil = CeilFloat64;
+        div = DivFloat64;
+        sub = SubFloat64;
+        break;
+      }
+      default:
+        abort();
+    }
+
+    TempVar f = getTemp(localType);
+    TempVar highBits = getTemp();
+
+    Expression* gtZeroBranch = builder->makeBinary(
+      min,
+      builder->makeUnary(
+        floor,
+        builder->makeBinary(div,
+                            builder->makeLocalGet(f, localType),
+                            builder->makeConst(u32Max))),
+      builder->makeBinary(
+        sub, builder->makeConst(u32Max), builder->makeConst(litOne)));
+    Expression* ltZeroBranch = builder->makeUnary(
+      ceil,
+      builder->makeBinary(
+        div,
+        builder->makeBinary(
+          sub,
+          builder->makeLocalGet(f, localType),
+          builder->makeUnary(
+            convert,
+            builder->makeUnary(trunc, builder->makeLocalGet(f, localType)))),
+        builder->makeConst(u32Max)));
+
+    If* highBitsCalc = builder->makeIf(
+      builder->makeBinary(
+        gt, builder->makeLocalGet(f, localType), builder->makeConst(litZero)),
+      builder->makeUnary(trunc, gtZeroBranch),
+      builder->makeUnary(trunc, ltZeroBranch));
+    If* highBitsVal = builder->makeIf(
+      builder->makeBinary(
+        ge,
+        builder->makeUnary(abs, builder->makeLocalGet(f, localType)),
+        builder->makeConst(litOne)),
+      highBitsCalc,
+      builder->makeConst(int32_t(0)));
+    Block* result = builder->blockify(
+      builder->makeLocalSet(f, curr->value),
+      builder->makeLocalSet(highBits, highBitsVal),
+      builder->makeUnary(trunc, builder->makeLocalGet(f, localType)));
+    setOutParam(result, std::move(highBits));
+    replaceCurrent(result);
+  }
+
+  void lowerConvertIntToFloat(Unary* curr) {
+    // Here the same strategy as `emcc` is taken which takes the two halves of
+    // the 64-bit integer and creates a mathematical expression using float
+    // arithmetic to reassemble the final floating point value.
+    //
+    // For example for i64 -> f32 we generate:
+    //
+    //  ((double) (unsigned) lowBits) +
+    //      ((double) U32_MAX) * ((double) (int) highBits)
+    //
+    // Mostly just shuffling things around here with coercions and whatnot!
+    // Note though that all arithmetic is done with f64 to have as much
+    // precision as we can.
+    //
+    // NB: this is *not* accurate for i64 -> f32. Using f64s for intermediate
+    // operations can give slightly inaccurate results in some cases, as we
+    // round to an f64, then round again to an f32, which is not always the
+    // same as a single rounding of i64 to f32 directly. Example:
+    //
+    //   #include <stdio.h>
+    //   int main() {
+    //     unsigned long long x = 18446743523953737727ULL;
+    //     float y = x;
+    //     double z = x;
+    //     float w = z;
+    //     printf("i64          : %llu\n"
+    //            "i64->f32     : %f\n"
+    //            "i64->f64     : %f\n"
+    //            "i64->f64->f32: %f\n", x, y, z, w);
+    //   }
+    //
+    //   i64          : 18446743523953737727
+    //   i64->f32     : 18446742974197923840.000000 ;; correct rounding to f32
+    //   i64->f64     : 18446743523953737728.000000 ;; correct rounding to f64
+    //   i64->f64->f32: 18446744073709551616.000000 ;; incorrect rounding to f32
+    //
+    // This is even a problem if we use BigInts in JavaScript to represent
+    // i64s, as Math.fround(BigInt) is not supported - the BigInt must be
+    // converted to a Number first, so we again have that extra rounding.
+    //
+    // A more precise approach could use compiled floatdisf/floatundisf from
+    // compiler-rt, but that is much larger and slower. (Note that we are in the
+    // interesting situation of having f32 and f64 operations and only missing
+    // i64 ones, so we have a different problem to solve than compiler-rt, and
+    // maybe there is a better solution we haven't found yet.)
+    TempVar highBits = fetchOutParam(curr->value);
+    TempVar lowBits = getTemp();
+    TempVar highResult = getTemp();
+
+    UnaryOp convertHigh;
+    switch (curr->op) {
+      case ConvertSInt64ToFloat32:
+      case ConvertSInt64ToFloat64:
+        convertHigh = ConvertSInt32ToFloat64;
+        break;
+      case ConvertUInt64ToFloat32:
+      case ConvertUInt64ToFloat64:
+        convertHigh = ConvertUInt32ToFloat64;
+        break;
+      default:
+        abort();
+    }
+
+    Expression* result = builder->blockify(
+      builder->makeLocalSet(lowBits, curr->value),
+      builder->makeLocalSet(highResult, builder->makeConst(int32_t(0))),
+      builder->makeBinary(
+        AddFloat64,
+        builder->makeUnary(ConvertUInt32ToFloat64,
+                           builder->makeLocalGet(lowBits, Type::i32)),
+        builder->makeBinary(
+          MulFloat64,
+          builder->makeConst((double)UINT_MAX + 1),
+          builder->makeUnary(convertHigh,
+                             builder->makeLocalGet(highBits, Type::i32)))));
+
+    switch (curr->op) {
+      case ConvertSInt64ToFloat32:
+      case ConvertUInt64ToFloat32: {
+        result = builder->makeUnary(DemoteFloat64, result);
+        break;
+      }
+      default:
+        break;
+    }
+
+    replaceCurrent(result);
+  }
+
+  void lowerCountZeros(Unary* curr) {
+    auto lower = [&](Block* result,
+                     UnaryOp op32,
+                     TempVar&& first,
+                     TempVar&& second) {
+      TempVar highResult = getTemp();
+      TempVar firstResult = getTemp();
+      LocalSet* setFirst = builder->makeLocalSet(
+        firstResult,
+        builder->makeUnary(op32, builder->makeLocalGet(first, Type::i32)));
+
+      Binary* check =
+        builder->makeBinary(EqInt32,
+                            builder->makeLocalGet(firstResult, Type::i32),
+                            builder->makeConst(int32_t(32)));
+
+      If* conditional = builder->makeIf(
+        check,
+        builder->makeBinary(
+          AddInt32,
+          builder->makeUnary(op32, builder->makeLocalGet(second, Type::i32)),
+          builder->makeConst(int32_t(32))),
+        builder->makeLocalGet(firstResult, Type::i32));
+
+      LocalSet* setHigh =
+        builder->makeLocalSet(highResult, builder->makeConst(int32_t(0)));
+
+      setOutParam(result, std::move(highResult));
+
+      replaceCurrent(builder->blockify(result, setFirst, setHigh, conditional));
+    };
+
+    TempVar highBits = fetchOutParam(curr->value);
+    TempVar lowBits = getTemp();
+    LocalSet* setLow = builder->makeLocalSet(lowBits, curr->value);
+    Block* result = builder->blockify(setLow);
+
+    switch (curr->op) {
+      case ClzInt64:
+        lower(result, ClzInt32, std::move(highBits), std::move(lowBits));
+        break;
+      case CtzInt64:
+        WASM_UNREACHABLE("i64.ctz should be removed already");
+        break;
+      default:
+        abort();
+    }
+  }
+
+  bool unaryNeedsLowering(UnaryOp op) {
+    switch (op) {
+      case ClzInt64:
+      case CtzInt64:
+      case PopcntInt64:
+      case EqZInt64:
+      case ExtendSInt32:
+      case ExtendUInt32:
+      case WrapInt64:
+      case TruncSFloat32ToInt64:
+      case TruncUFloat32ToInt64:
+      case TruncSFloat64ToInt64:
+      case TruncUFloat64ToInt64:
+      case ReinterpretFloat64:
+      case ConvertSInt64ToFloat32:
+      case ConvertSInt64ToFloat64:
+      case ConvertUInt64ToFloat32:
+      case ConvertUInt64ToFloat64:
+      case ReinterpretInt64:
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  void visitUnary(Unary* curr) {
+    if (!unaryNeedsLowering(curr->op)) {
+      return;
+    }
+    if (handleUnreachable(curr)) {
+      return;
+    }
+    assert(hasOutParam(curr->value) || curr->type == Type::i64 ||
+           curr->type == Type::f64);
+    switch (curr->op) {
+      case ClzInt64:
+      case CtzInt64:
+        lowerCountZeros(curr);
+        break;
+      case EqZInt64:
+        lowerEqZInt64(curr);
+        break;
+      case ExtendSInt32:
+        lowerExtendSInt32(curr);
+        break;
+      case ExtendUInt32:
+        lowerExtendUInt32(curr);
+        break;
+      case WrapInt64:
+        lowerWrapInt64(curr);
+        break;
+      case ReinterpretFloat64:
+        lowerReinterpretFloat64(curr);
+        break;
+      case ReinterpretInt64:
+        lowerReinterpretInt64(curr);
+        break;
+      case TruncSFloat32ToInt64:
+      case TruncUFloat32ToInt64:
+      case TruncSFloat64ToInt64:
+      case TruncUFloat64ToInt64:
+        lowerTruncFloatToInt(curr);
+        break;
+      case ConvertSInt64ToFloat32:
+      case ConvertSInt64ToFloat64:
+      case ConvertUInt64ToFloat32:
+      case ConvertUInt64ToFloat64:
+        lowerConvertIntToFloat(curr);
+        break;
+      case PopcntInt64:
+        WASM_UNREACHABLE("i64.popcnt should already be removed");
+      default:
+        std::cerr << "Unhandled unary operator: " << curr->op << std::endl;
+        abort();
+    }
+  }
+
+  Block* lowerAdd(Block* result,
+                  TempVar&& leftLow,
+                  TempVar&& leftHigh,
+                  TempVar&& rightLow,
+                  TempVar&& rightHigh) {
+    TempVar lowResult = getTemp();
+    TempVar highResult = getTemp();
+    LocalSet* addLow = builder->makeLocalSet(
+      lowResult,
+      builder->makeBinary(AddInt32,
+                          builder->makeLocalGet(leftLow, Type::i32),
+                          builder->makeLocalGet(rightLow, Type::i32)));
+    LocalSet* addHigh = builder->makeLocalSet(
+      highResult,
+      builder->makeBinary(AddInt32,
+                          builder->makeLocalGet(leftHigh, Type::i32),
+                          builder->makeLocalGet(rightHigh, Type::i32)));
+    LocalSet* carryBit = builder->makeLocalSet(
+      highResult,
+      builder->makeBinary(AddInt32,
+                          builder->makeLocalGet(highResult, Type::i32),
+                          builder->makeConst(int32_t(1))));
+    If* checkOverflow = builder->makeIf(
+      builder->makeBinary(LtUInt32,
+                          builder->makeLocalGet(lowResult, Type::i32),
+                          builder->makeLocalGet(rightLow, Type::i32)),
+      carryBit);
+    LocalGet* getLow = builder->makeLocalGet(lowResult, Type::i32);
+    result = builder->blockify(result, addLow, addHigh, checkOverflow, getLow);
+    setOutParam(result, std::move(highResult));
+    return result;
+  }
+
+  Block* lowerSub(Block* result,
+                  TempVar&& leftLow,
+                  TempVar&& leftHigh,
+                  TempVar&& rightLow,
+                  TempVar&& rightHigh) {
+    TempVar lowResult = getTemp();
+    TempVar highResult = getTemp();
+    TempVar borrow = getTemp();
+    LocalSet* subLow = builder->makeLocalSet(
+      lowResult,
+      builder->makeBinary(SubInt32,
+                          builder->makeLocalGet(leftLow, Type::i32),
+                          builder->makeLocalGet(rightLow, Type::i32)));
+    LocalSet* borrowBit = builder->makeLocalSet(
+      borrow,
+      builder->makeBinary(LtUInt32,
+                          builder->makeLocalGet(leftLow, Type::i32),
+                          builder->makeLocalGet(rightLow, Type::i32)));
+    LocalSet* subHigh1 = builder->makeLocalSet(
+      highResult,
+      builder->makeBinary(AddInt32,
+                          builder->makeLocalGet(borrow, Type::i32),
+                          builder->makeLocalGet(rightHigh, Type::i32)));
+    LocalSet* subHigh2 = builder->makeLocalSet(
+      highResult,
+      builder->makeBinary(SubInt32,
+                          builder->makeLocalGet(leftHigh, Type::i32),
+                          builder->makeLocalGet(highResult, Type::i32)));
+    LocalGet* getLow = builder->makeLocalGet(lowResult, Type::i32);
+    result =
+      builder->blockify(result, subLow, borrowBit, subHigh1, subHigh2, getLow);
+    setOutParam(result, std::move(highResult));
+    return result;
+  }
+
+  Block* lowerBitwise(BinaryOp op,
+                      Block* result,
+                      TempVar&& leftLow,
+                      TempVar&& leftHigh,
+                      TempVar&& rightLow,
+                      TempVar&& rightHigh) {
+    BinaryOp op32;
+    switch (op) {
+      case AndInt64:
+        op32 = AndInt32;
+        break;
+      case OrInt64:
+        op32 = OrInt32;
+        break;
+      case XorInt64:
+        op32 = XorInt32;
+        break;
+      default:
+        abort();
+    }
+    result = builder->blockify(
+      result,
+      builder->makeLocalSet(
+        rightHigh,
+        builder->makeBinary(op32,
+                            builder->makeLocalGet(leftHigh, Type::i32),
+                            builder->makeLocalGet(rightHigh, Type::i32))),
+      builder->makeBinary(op32,
+                          builder->makeLocalGet(leftLow, Type::i32),
+                          builder->makeLocalGet(rightLow, Type::i32)));
+    setOutParam(result, std::move(rightHigh));
+    return result;
+  }
+
+  Block* makeLargeShl(Index highBits, Index leftLow, Index shift) {
+    return builder->blockify(
+      builder->makeLocalSet(
+        highBits,
+        builder->makeBinary(ShlInt32,
+                            builder->makeLocalGet(leftLow, Type::i32),
+                            builder->makeLocalGet(shift, Type::i32))),
+      builder->makeConst(int32_t(0)));
+  }
+
+  // a >> b where `b` >= 32
+  //
+  // implement as:
+  //
+  // hi = leftHigh >> 31 // copy sign bit
+  // lo = leftHigh >> (b - 32)
+  Block* makeLargeShrS(Index highBits, Index leftHigh, Index shift) {
+    return builder->blockify(
+      builder->makeLocalSet(
+        highBits,
+        builder->makeBinary(ShrSInt32,
+                            builder->makeLocalGet(leftHigh, Type::i32),
+                            builder->makeConst(int32_t(31)))),
+      builder->makeBinary(ShrSInt32,
+                          builder->makeLocalGet(leftHigh, Type::i32),
+                          builder->makeLocalGet(shift, Type::i32)));
+  }
+
+  Block* makeLargeShrU(Index highBits, Index leftHigh, Index shift) {
+    return builder->blockify(
+      builder->makeLocalSet(highBits, builder->makeConst(int32_t(0))),
+      builder->makeBinary(ShrUInt32,
+                          builder->makeLocalGet(leftHigh, Type::i32),
+                          builder->makeLocalGet(shift, Type::i32)));
+  }
+
+  Block* makeSmallShl(Index highBits,
+                      Index leftLow,
+                      Index leftHigh,
+                      Index shift,
+                      Binary* shiftMask,
+                      Binary* widthLessShift) {
+    Binary* shiftedInBits = builder->makeBinary(
+      AndInt32,
+      shiftMask,
+      builder->makeBinary(
+        ShrUInt32, builder->makeLocalGet(leftLow, Type::i32), widthLessShift));
+    Binary* shiftHigh =
+      builder->makeBinary(ShlInt32,
+                          builder->makeLocalGet(leftHigh, Type::i32),
+                          builder->makeLocalGet(shift, Type::i32));
+    return builder->blockify(
+      builder->makeLocalSet(
+        highBits, builder->makeBinary(OrInt32, shiftedInBits, shiftHigh)),
+      builder->makeBinary(ShlInt32,
+                          builder->makeLocalGet(leftLow, Type::i32),
+                          builder->makeLocalGet(shift, Type::i32)));
+  }
+
+  // a >> b where `b` < 32
+  //
+  // implement as:
+  //
+  // hi = leftHigh >> b
+  // lo = (leftLow >>> b) | (leftHigh << (32 - b))
+  Block* makeSmallShrS(Index highBits,
+                       Index leftLow,
+                       Index leftHigh,
+                       Index shift,
+                       Binary* shiftMask,
+                       Binary* widthLessShift) {
+    Binary* shiftedInBits = builder->makeBinary(
+      ShlInt32,
+      builder->makeBinary(
+        AndInt32, shiftMask, builder->makeLocalGet(leftHigh, Type::i32)),
+      widthLessShift);
+    Binary* shiftLow =
+      builder->makeBinary(ShrUInt32,
+                          builder->makeLocalGet(leftLow, Type::i32),
+                          builder->makeLocalGet(shift, Type::i32));
+    return builder->blockify(
+      builder->makeLocalSet(
+        highBits,
+        builder->makeBinary(ShrSInt32,
+                            builder->makeLocalGet(leftHigh, Type::i32),
+                            builder->makeLocalGet(shift, Type::i32))),
+      builder->makeBinary(OrInt32, shiftedInBits, shiftLow));
+  }
+
+  Block* makeSmallShrU(Index highBits,
+                       Index leftLow,
+                       Index leftHigh,
+                       Index shift,
+                       Binary* shiftMask,
+                       Binary* widthLessShift) {
+    Binary* shiftedInBits = builder->makeBinary(
+      ShlInt32,
+      builder->makeBinary(
+        AndInt32, shiftMask, builder->makeLocalGet(leftHigh, Type::i32)),
+      widthLessShift);
+    Binary* shiftLow =
+      builder->makeBinary(ShrUInt32,
+                          builder->makeLocalGet(leftLow, Type::i32),
+                          builder->makeLocalGet(shift, Type::i32));
+    return builder->blockify(
+      builder->makeLocalSet(
+        highBits,
+        builder->makeBinary(ShrUInt32,
+                            builder->makeLocalGet(leftHigh, Type::i32),
+                            builder->makeLocalGet(shift, Type::i32))),
+      builder->makeBinary(OrInt32, shiftedInBits, shiftLow));
+  }
+
+  Block* lowerShift(BinaryOp op,
+                    Block* result,
+                    TempVar&& leftLow,
+                    TempVar&& leftHigh,
+                    TempVar&& rightLow,
+                    TempVar&& rightHigh) {
+    assert(op == ShlInt64 || op == ShrUInt64 || op == ShrSInt64);
+    // shift left lowered as:
+    // if 32 <= rightLow % 64:
+    //     high = leftLow << k; low = 0
+    // else:
+    //     high = (((1 << k) - 1) & (leftLow >> (32 - k))) | (leftHigh << k);
+    //     low = leftLow << k
+    // where k = shift % 32. shift right is similar.
+    TempVar shift = getTemp();
+    LocalSet* setShift = builder->makeLocalSet(
+      shift,
+      builder->makeBinary(AndInt32,
+                          builder->makeLocalGet(rightLow, Type::i32),
+                          builder->makeConst(int32_t(32 - 1))));
+    Binary* isLargeShift = builder->makeBinary(
+      LeUInt32,
+      builder->makeConst(int32_t(32)),
+      builder->makeBinary(AndInt32,
+                          builder->makeLocalGet(rightLow, Type::i32),
+                          builder->makeConst(int32_t(64 - 1))));
+    Block* largeShiftBlock;
+    switch (op) {
+      case ShlInt64:
+        largeShiftBlock = makeLargeShl(rightHigh, leftLow, shift);
+        break;
+      case ShrSInt64:
+        largeShiftBlock = makeLargeShrS(rightHigh, leftHigh, shift);
+        break;
+      case ShrUInt64:
+        largeShiftBlock = makeLargeShrU(rightHigh, leftHigh, shift);
+        break;
+      default:
+        abort();
+    }
+    Binary* shiftMask = builder->makeBinary(
+      SubInt32,
+      builder->makeBinary(ShlInt32,
+                          builder->makeConst(int32_t(1)),
+                          builder->makeLocalGet(shift, Type::i32)),
+      builder->makeConst(int32_t(1)));
+    Binary* widthLessShift =
+      builder->makeBinary(SubInt32,
+                          builder->makeConst(int32_t(32)),
+                          builder->makeLocalGet(shift, Type::i32));
+    Block* smallShiftBlock;
+    switch (op) {
+      case ShlInt64: {
+        smallShiftBlock = makeSmallShl(
+          rightHigh, leftLow, leftHigh, shift, shiftMask, widthLessShift);
+        break;
+      }
+      case ShrSInt64: {
+        smallShiftBlock = makeSmallShrS(
+          rightHigh, leftLow, leftHigh, shift, shiftMask, widthLessShift);
+        break;
+      }
+      case ShrUInt64: {
+        smallShiftBlock = makeSmallShrU(
+          rightHigh, leftLow, leftHigh, shift, shiftMask, widthLessShift);
+        break;
+      }
+      default:
+        abort();
+    }
+    If* ifLargeShift =
+      builder->makeIf(isLargeShift, largeShiftBlock, smallShiftBlock);
+    result = builder->blockify(result, setShift, ifLargeShift);
+    setOutParam(result, std::move(rightHigh));
+    return result;
+  }
+
+  Block* lowerEq(Block* result,
+                 TempVar&& leftLow,
+                 TempVar&& leftHigh,
+                 TempVar&& rightLow,
+                 TempVar&& rightHigh) {
+    return builder->blockify(
+      result,
+      builder->makeBinary(
+        AndInt32,
+        builder->makeBinary(EqInt32,
+                            builder->makeLocalGet(leftLow, Type::i32),
+                            builder->makeLocalGet(rightLow, Type::i32)),
+        builder->makeBinary(EqInt32,
+                            builder->makeLocalGet(leftHigh, Type::i32),
+                            builder->makeLocalGet(rightHigh, Type::i32))));
+  }
+
+  Block* lowerNe(Block* result,
+                 TempVar&& leftLow,
+                 TempVar&& leftHigh,
+                 TempVar&& rightLow,
+                 TempVar&& rightHigh) {
+    return builder->blockify(
+      result,
+      builder->makeBinary(
+        OrInt32,
+        builder->makeBinary(NeInt32,
+                            builder->makeLocalGet(leftLow, Type::i32),
+                            builder->makeLocalGet(rightLow, Type::i32)),
+        builder->makeBinary(NeInt32,
+                            builder->makeLocalGet(leftHigh, Type::i32),
+                            builder->makeLocalGet(rightHigh, Type::i32))));
+  }
+
+  Block* lowerUComp(BinaryOp op,
+                    Block* result,
+                    TempVar&& leftLow,
+                    TempVar&& leftHigh,
+                    TempVar&& rightLow,
+                    TempVar&& rightHigh) {
+    BinaryOp highOp, lowOp;
+    switch (op) {
+      case LtUInt64:
+        highOp = LtUInt32;
+        lowOp = LtUInt32;
+        break;
+      case LeUInt64:
+        highOp = LtUInt32;
+        lowOp = LeUInt32;
+        break;
+      case GtUInt64:
+        highOp = GtUInt32;
+        lowOp = GtUInt32;
+        break;
+      case GeUInt64:
+        highOp = GtUInt32;
+        lowOp = GeUInt32;
+        break;
+      default:
+        abort();
+    }
+    Binary* compHigh =
+      builder->makeBinary(highOp,
+                          builder->makeLocalGet(leftHigh, Type::i32),
+                          builder->makeLocalGet(rightHigh, Type::i32));
+    Binary* eqHigh =
+      builder->makeBinary(EqInt32,
+                          builder->makeLocalGet(leftHigh, Type::i32),
+                          builder->makeLocalGet(rightHigh, Type::i32));
+    Binary* compLow =
+      builder->makeBinary(lowOp,
+                          builder->makeLocalGet(leftLow, Type::i32),
+                          builder->makeLocalGet(rightLow, Type::i32));
+    return builder->blockify(
+      result,
+      builder->makeBinary(
+        OrInt32, compHigh, builder->makeBinary(AndInt32, eqHigh, compLow)));
+  }
+
+  Block* lowerSComp(BinaryOp op,
+                    Block* result,
+                    TempVar&& leftLow,
+                    TempVar&& leftHigh,
+                    TempVar&& rightLow,
+                    TempVar&& rightHigh) {
+    BinaryOp highOp1, highOp2, lowOp;
+    switch (op) {
+      case LtSInt64:
+        highOp1 = LtSInt32;
+        highOp2 = LeSInt32;
+        lowOp = GeUInt32;
+        break;
+      case LeSInt64:
+        highOp1 = LtSInt32;
+        highOp2 = LeSInt32;
+        lowOp = GtUInt32;
+        break;
+      case GtSInt64:
+        highOp1 = GtSInt32;
+        highOp2 = GeSInt32;
+        lowOp = LeUInt32;
+        break;
+      case GeSInt64:
+        highOp1 = GtSInt32;
+        highOp2 = GeSInt32;
+        lowOp = LtUInt32;
+        break;
+      default:
+        abort();
+    }
+    Binary* compHigh1 =
+      builder->makeBinary(highOp1,
+                          builder->makeLocalGet(leftHigh, Type::i32),
+                          builder->makeLocalGet(rightHigh, Type::i32));
+    Binary* compHigh2 =
+      builder->makeBinary(highOp2,
+                          builder->makeLocalGet(leftHigh, Type::i32),
+                          builder->makeLocalGet(rightHigh, Type::i32));
+    Binary* compLow =
+      builder->makeBinary(lowOp,
+                          builder->makeLocalGet(leftLow, Type::i32),
+                          builder->makeLocalGet(rightLow, Type::i32));
+    If* lowIf = builder->makeIf(
+      compLow, builder->makeConst(int32_t(0)), builder->makeConst(int32_t(1)));
+    If* highIf2 =
+      builder->makeIf(compHigh2, lowIf, builder->makeConst(int32_t(0)));
+    If* highIf1 =
+      builder->makeIf(compHigh1, builder->makeConst(int32_t(1)), highIf2);
+    return builder->blockify(result, highIf1);
+  }
+
+  bool binaryNeedsLowering(BinaryOp op) {
+    switch (op) {
+      case AddInt64:
+      case SubInt64:
+      case MulInt64:
+      case DivSInt64:
+      case DivUInt64:
+      case RemSInt64:
+      case RemUInt64:
+      case AndInt64:
+      case OrInt64:
+      case XorInt64:
+      case ShlInt64:
+      case ShrUInt64:
+      case ShrSInt64:
+      case RotLInt64:
+      case RotRInt64:
+      case EqInt64:
+      case NeInt64:
+      case LtSInt64:
+      case LtUInt64:
+      case LeSInt64:
+      case LeUInt64:
+      case GtSInt64:
+      case GtUInt64:
+      case GeSInt64:
+      case GeUInt64:
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  void visitBinary(Binary* curr) {
+    if (handleUnreachable(curr)) {
+      return;
+    }
+    if (!binaryNeedsLowering(curr->op)) {
+      return;
+    }
+    // left and right reachable, lower normally
+    TempVar leftLow = getTemp();
+    TempVar leftHigh = fetchOutParam(curr->left);
+    TempVar rightLow = getTemp();
+    TempVar rightHigh = fetchOutParam(curr->right);
+    LocalSet* setRight = builder->makeLocalSet(rightLow, curr->right);
+    LocalSet* setLeft = builder->makeLocalSet(leftLow, curr->left);
+    Block* result = builder->blockify(setLeft, setRight);
+    switch (curr->op) {
+      case AddInt64: {
+        replaceCurrent(lowerAdd(result,
+                                std::move(leftLow),
+                                std::move(leftHigh),
+                                std::move(rightLow),
+                                std::move(rightHigh)));
+        break;
+      }
+      case SubInt64: {
+        replaceCurrent(lowerSub(result,
+                                std::move(leftLow),
+                                std::move(leftHigh),
+                                std::move(rightLow),
+                                std::move(rightHigh)));
+        break;
+      }
+      case MulInt64:
+      case DivSInt64:
+      case DivUInt64:
+      case RemSInt64:
+      case RemUInt64:
+      case RotLInt64:
+      case RotRInt64:
+        WASM_UNREACHABLE("should have been removed by now");
+
+      case AndInt64:
+      case OrInt64:
+      case XorInt64: {
+        replaceCurrent(lowerBitwise(curr->op,
+                                    result,
+                                    std::move(leftLow),
+                                    std::move(leftHigh),
+                                    std::move(rightLow),
+                                    std::move(rightHigh)));
+        break;
+      }
+      case ShlInt64:
+      case ShrSInt64:
+      case ShrUInt64: {
+        replaceCurrent(lowerShift(curr->op,
+                                  result,
+                                  std::move(leftLow),
+                                  std::move(leftHigh),
+                                  std::move(rightLow),
+                                  std::move(rightHigh)));
+        break;
+      }
+      case EqInt64: {
+        replaceCurrent(lowerEq(result,
+                               std::move(leftLow),
+                               std::move(leftHigh),
+                               std::move(rightLow),
+                               std::move(rightHigh)));
+        break;
+      }
+      case NeInt64: {
+        replaceCurrent(lowerNe(result,
+                               std::move(leftLow),
+                               std::move(leftHigh),
+                               std::move(rightLow),
+                               std::move(rightHigh)));
+        break;
+      }
+      case LtSInt64:
+      case LeSInt64:
+      case GtSInt64:
+      case GeSInt64:
+        replaceCurrent(lowerSComp(curr->op,
+                                  result,
+                                  std::move(leftLow),
+                                  std::move(leftHigh),
+                                  std::move(rightLow),
+                                  std::move(rightHigh)));
+        break;
+      case LtUInt64:
+      case LeUInt64:
+      case GtUInt64:
+      case GeUInt64: {
+        replaceCurrent(lowerUComp(curr->op,
+                                  result,
+                                  std::move(leftLow),
+                                  std::move(leftHigh),
+                                  std::move(rightLow),
+                                  std::move(rightHigh)));
+        break;
+      }
+      default: {
+        std::cerr << "Unhandled binary op " << curr->op << std::endl;
+        abort();
+      }
+    }
+  }
+
+  void visitSelect(Select* curr) {
+    if (handleUnreachable(curr)) {
+      return;
+    }
+    if (!hasOutParam(curr->ifTrue)) {
+      assert(!hasOutParam(curr->ifFalse));
+      return;
+    }
+    assert(hasOutParam(curr->ifFalse));
+    TempVar highBits = getTemp();
+    TempVar lowBits = getTemp();
+    TempVar cond = getTemp();
+    Block* result = builder->blockify(
+      builder->makeLocalSet(cond, curr->condition),
+      builder->makeLocalSet(
+        lowBits,
+        builder->makeSelect(
+          builder->makeLocalGet(cond, Type::i32), curr->ifTrue, curr->ifFalse)),
+      builder->makeLocalSet(
+        highBits,
+        builder->makeSelect(
+          builder->makeLocalGet(cond, Type::i32),
+          builder->makeLocalGet(fetchOutParam(curr->ifTrue), Type::i32),
+          builder->makeLocalGet(fetchOutParam(curr->ifFalse), Type::i32))),
+      builder->makeLocalGet(lowBits, Type::i32));
+    setOutParam(result, std::move(highBits));
+    replaceCurrent(result);
+  }
+
+  void visitDrop(Drop* curr) {
+    if (!hasOutParam(curr->value)) {
+      return;
+    }
+    // free temp var
+    fetchOutParam(curr->value);
+  }
+
+  void visitReturn(Return* curr) {
+    if (!hasOutParam(curr->value)) {
+      return;
+    }
+    TempVar lowBits = getTemp();
+    TempVar highBits = fetchOutParam(curr->value);
+    LocalSet* setLow = builder->makeLocalSet(lowBits, curr->value);
+    GlobalSet* setHigh = builder->makeGlobalSet(
+      INT64_TO_32_HIGH_BITS, builder->makeLocalGet(highBits, Type::i32));
+    curr->value = builder->makeLocalGet(lowBits, Type::i32);
+    Block* result = builder->blockify(setLow, setHigh, curr);
+    replaceCurrent(result);
+  }
+
+private:
+  std::unique_ptr<Builder> builder;
+  std::unordered_map<Index, Index> indexMap;
+  std::unordered_map<int, std::vector<Index>> freeTemps;
+  std::unordered_map<Expression*, TempVar> highBitVars;
+  std::unordered_map<Index, Type> tempTypes;
+  std::unordered_set<Name> originallyI64Globals;
+  Index nextTemp;
+
+  TempVar getTemp(Type ty = Type::i32) {
+    Index ret;
+    auto& freeList = freeTemps[ty.getBasic()];
+    if (freeList.size() > 0) {
+      ret = freeList.back();
+      freeList.pop_back();
+    } else {
+      ret = nextTemp++;
+      tempTypes[ret] = ty;
+    }
+    assert(tempTypes[ret] == ty);
+    return TempVar(ret, ty, *this);
+  }
+
+  bool hasOutParam(Expression* e) {
+    return highBitVars.find(e) != highBitVars.end();
+  }
+
+  void setOutParam(Expression* e, TempVar&& var) {
+    highBitVars.emplace(e, std::move(var));
+  }
+
+  TempVar fetchOutParam(Expression* e) {
+    auto outParamIt = highBitVars.find(e);
+    assert(outParamIt != highBitVars.end());
+    TempVar ret = std::move(outParamIt->second);
+    highBitVars.erase(e);
+    return ret;
+  }
+
+  // If e.g. a select is unreachable, then one arm may have an out param
+  // but not the other. In this case dce should really have been run
+  // before; handle it in a simple way here by replacing the node with
+  // a block of its children.
+  // This is valid only for nodes that execute their children
+  // unconditionally before themselves, so it is not valid for an if,
+  // in particular.
+  bool handleUnreachable(Expression* curr) {
+    if (curr->type != Type::unreachable) {
+      return false;
+    }
+    std::vector<Expression*> children;
+    bool hasUnreachable = false;
+    for (auto* child : ChildIterator(curr)) {
+      if (child->type.isConcrete()) {
+        child = builder->makeDrop(child);
+      } else if (child->type == Type::unreachable) {
+        hasUnreachable = true;
+      }
+      children.push_back(child);
+    }
+    if (!hasUnreachable) {
+      return false;
+    }
+    // This has an unreachable child, so we can replace it with
+    // the children.
+    auto* block = builder->makeBlock(children);
+    assert(block->type == Type::unreachable);
+    replaceCurrent(block);
+    return true;
+  }
+};
+
+Pass* createI64ToI32LoweringPass() { return new I64ToI32Lowering(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/Inlining.cpp b/binaryen/src/passes/Inlining.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/Inlining.cpp
@@ -0,0 +1,454 @@
+/*
+ * 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.
+ */
+
+//
+// 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
+// inlined code, some temp locals, etc., which can usually be removed
+// by optimizations. Note that the two versions use the same heuristics,
+// so we don't take into account the overhead if you don't optimize
+// afterwards. The non-optimizing version is mainly useful for debugging,
+// or if you intend to run a full set of optimizations anyhow on
+// everything later.
+//
+
+#include <atomic>
+
+#include "ir/debug.h"
+#include "ir/literal-utils.h"
+#include "ir/module-utils.h"
+#include "ir/utils.h"
+#include "parsing.h"
+#include "pass.h"
+#include "passes/opt-utils.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+// Useful into on a function, helping us decide if we can inline it
+struct FunctionInfo {
+  std::atomic<Index> refs;
+  Index size;
+  bool hasCalls;
+  bool hasLoops;
+  bool usedGlobally; // in a table or export
+
+  FunctionInfo() {
+    refs = 0;
+    size = 0;
+    hasCalls = false;
+    hasLoops = false;
+    usedGlobally = false;
+  }
+
+  // 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 (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 (refs == 1 && !usedGlobally &&
+        size <= options.inlining.oneCallerInlineMaxSize) {
+      return true;
+    }
+    // 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
+    // likely to speed us up, and also if we want to inline such
+    // functions we would need to be careful to avoid infinite recursion.
+    if (hasCalls) {
+      return false;
+    }
+    return options.optimizeLevel >= 3 && options.shrinkLevel == 0 &&
+           (!hasLoops || options.inlining.allowFunctionsWithLoops);
+  }
+};
+
+typedef std::unordered_map<Name, FunctionInfo> NameInfoMap;
+
+struct FunctionInfoScanner
+  : public WalkerPass<PostWalker<FunctionInfoScanner>> {
+  bool isFunctionParallel() override { return true; }
+
+  FunctionInfoScanner(NameInfoMap* infos) : infos(infos) {}
+
+  FunctionInfoScanner* create() override {
+    return new FunctionInfoScanner(infos);
+  }
+
+  void visitLoop(Loop* curr) {
+    // having a loop
+    (*infos)[getFunction()->name].hasLoops = true;
+  }
+
+  void visitCall(Call* curr) {
+    // can't add a new element in parallel
+    assert(infos->count(curr->target) > 0);
+    (*infos)[curr->target].refs++;
+    // having a call
+    (*infos)[getFunction()->name].hasCalls = true;
+  }
+
+  void visitRefFunc(RefFunc* curr) {
+    assert(infos->count(curr->func) > 0);
+    (*infos)[curr->func].refs++;
+  }
+
+  void visitFunction(Function* curr) {
+    (*infos)[curr->name].size = Measurer::measure(curr->body);
+  }
+
+private:
+  NameInfoMap* infos;
+};
+
+struct InliningAction {
+  Expression** callSite;
+  Function* contents;
+
+  InliningAction(Expression** callSite, Function* contents)
+    : callSite(callSite), contents(contents) {}
+};
+
+struct InliningState {
+  std::unordered_set<Name> worthInlining;
+  // function name => actions that can be performed in it
+  std::unordered_map<Name, std::vector<InliningAction>> actionsForFunction;
+};
+
+struct Planner : public WalkerPass<PostWalker<Planner>> {
+  bool isFunctionParallel() override { return true; }
+
+  Planner(InliningState* state) : state(state) {}
+
+  Planner* create() override { return new Planner(state); }
+
+  void visitCall(Call* curr) {
+    // plan to inline if we know this is valid to inline, and if the call is
+    // actually performed - if it is dead code, it's pointless to inline.
+    // we also cannot inline ourselves.
+    bool isUnreachable;
+    if (curr->isReturn) {
+      // Tail calls are only actually unreachable if an argument is
+      isUnreachable = std::any_of(
+        curr->operands.begin(), curr->operands.end(), [](Expression* op) {
+          return op->type == Type::unreachable;
+        });
+    } else {
+      isUnreachable = curr->type == Type::unreachable;
+    }
+    if (state->worthInlining.count(curr->target) && !isUnreachable &&
+        curr->target != getFunction()->name) {
+      // nest the call in a block. that way the location of the pointer to the
+      // call will not change even if we inline multiple times into the same
+      // function, otherwise call1(call2()) might be a problem
+      auto* block = Builder(*getModule()).makeBlock(curr);
+      replaceCurrent(block);
+      // can't add a new element in parallel
+      assert(state->actionsForFunction.count(getFunction()->name) > 0);
+      state->actionsForFunction[getFunction()->name].emplace_back(
+        &block->list[0], getModule()->getFunction(curr->target));
+    }
+  }
+
+private:
+  InliningState* state;
+};
+
+struct Updater : public PostWalker<Updater> {
+  Module* module;
+  std::map<Index, Index> localMapping;
+  Name returnName;
+  Builder* builder;
+  void visitReturn(Return* curr) {
+    replaceCurrent(builder->makeBreak(returnName, curr->value));
+  }
+  // Return calls in inlined functions should only break out of the scope of
+  // the inlined code, not the entire function they are being inlined into. To
+  // achieve this, make the call a non-return call and add a break. This does
+  // not cause unbounded stack growth because inlining and return calling both
+  // avoid creating a new stack frame.
+  template<typename T> void handleReturnCall(T* curr, Type targetType) {
+    curr->isReturn = false;
+    curr->type = targetType;
+    if (targetType.isConcrete()) {
+      replaceCurrent(builder->makeBreak(returnName, curr));
+    } else {
+      replaceCurrent(builder->blockify(curr, builder->makeBreak(returnName)));
+    }
+  }
+  void visitCall(Call* curr) {
+    if (curr->isReturn) {
+      handleReturnCall(curr, module->getFunction(curr->target)->sig.results);
+    }
+  }
+  void visitCallIndirect(CallIndirect* curr) {
+    if (curr->isReturn) {
+      handleReturnCall(curr, curr->sig.results);
+    }
+  }
+  void visitLocalGet(LocalGet* curr) {
+    curr->index = localMapping[curr->index];
+  }
+  void visitLocalSet(LocalSet* curr) {
+    curr->index = localMapping[curr->index];
+  }
+};
+
+// Core inlining logic. Modifies the outside function (adding locals as
+// needed), and returns the inlined code.
+static Expression*
+doInlining(Module* module, Function* into, const InliningAction& action) {
+  Function* from = action.contents;
+  auto* call = (*action.callSite)->cast<Call>();
+  // Works for return_call, too
+  Type retType = module->getFunction(call->target)->sig.results;
+  Builder builder(*module);
+  auto* block = builder.makeBlock();
+  block->name = Name(std::string("__inlined_func$") + from->name.str);
+  if (call->isReturn) {
+    if (retType.isConcrete()) {
+      *action.callSite = builder.makeReturn(block);
+    } else {
+      *action.callSite = builder.makeSequence(block, builder.makeReturn());
+    }
+  } else {
+    *action.callSite = block;
+  }
+  // Prepare to update the inlined code's locals and other things.
+  Updater updater;
+  updater.module = module;
+  updater.returnName = block->name;
+  updater.builder = &builder;
+  // Set up a locals mapping
+  for (Index i = 0; i < from->getNumLocals(); i++) {
+    updater.localMapping[i] = builder.addVar(into, from->getLocalType(i));
+  }
+  // Assign the operands into the params
+  for (Index i = 0; i < from->sig.params.size(); i++) {
+    block->list.push_back(
+      builder.makeLocalSet(updater.localMapping[i], call->operands[i]));
+  }
+  // Zero out the vars (as we may be in a loop, and may depend on their
+  // zero-init value
+  for (Index i = 0; i < from->vars.size(); i++) {
+    block->list.push_back(
+      builder.makeLocalSet(updater.localMapping[from->getVarIndexBase() + i],
+                           LiteralUtils::makeZero(from->vars[i], *module)));
+  }
+  // Generate and update the inlined contents
+  auto* contents = ExpressionManipulator::copy(from->body, *module);
+  if (!from->debugLocations.empty()) {
+    debug::copyDebugInfo(from->body, contents, from, into);
+  }
+  updater.walk(contents);
+  block->list.push_back(contents);
+  block->type = retType;
+  // If the function returned a value, we just set the block containing the
+  // inlined code to have that type. or, if the function was void and
+  // contained void, that is fine too. a bad case is a void function in which
+  // we have unreachable code, so we would be replacing a void call with an
+  // unreachable.
+  if (contents->type == Type::unreachable && block->type == Type::none) {
+    // Make the block reachable by adding a break to it
+    block->list.push_back(builder.makeBreak(block->name));
+  }
+  return block;
+}
+
+struct Inlining : public Pass {
+  // whether to optimize where we inline
+  bool optimize = false;
+
+  // the information for each function. recomputed in each iteraction
+  NameInfoMap infos;
+
+  Index iterationNumber;
+
+  void run(PassRunner* runner, Module* module) override {
+    Index numFunctions = module->functions.size();
+    // keep going while we inline, to handle nesting. TODO: optimize
+    iterationNumber = 0;
+    // no point to do more iterations than the number of functions, as
+    // it means we infinitely recursing (which should
+    // be very rare in practice, but it is possible that a recursive call
+    // can look like it is worth inlining)
+    while (iterationNumber <= numFunctions) {
+#ifdef INLINING_DEBUG
+      std::cout << "inlining loop iter " << iterationNumber
+                << " (numFunctions: " << numFunctions << ")\n";
+#endif
+      calculateInfos(module);
+      if (!iteration(runner, module)) {
+        return;
+      }
+      iterationNumber++;
+    }
+  }
+
+  void calculateInfos(Module* module) {
+    infos.clear();
+    // fill in info, as we operate on it in parallel (each function to its own
+    // entry)
+    for (auto& func : module->functions) {
+      infos[func->name];
+    }
+    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;
+      }
+    }
+    for (auto& segment : module->table.segments) {
+      for (auto name : segment.data) {
+        infos[name].usedGlobally = true;
+      }
+    }
+  }
+
+  bool iteration(PassRunner* runner, Module* module) {
+    // decide which to inline
+    InliningState state;
+    ModuleUtils::iterDefinedFunctions(*module, [&](Function* func) {
+      if (infos[func->name].worthInlining(runner->options)) {
+        state.worthInlining.insert(func->name);
+      }
+    });
+    if (state.worthInlining.size() == 0) {
+      return false;
+    }
+    // fill in actionsForFunction, as we operate on it in parallel (each
+    // function to its own entry)
+    for (auto& func : module->functions) {
+      state.actionsForFunction[func->name];
+    }
+    // find and plan inlinings
+    Planner(&state).run(runner, module);
+    // perform inlinings TODO: parallelize
+    std::unordered_map<Name, Index> inlinedUses; // how many uses we inlined
+    // which functions were inlined into
+    std::unordered_set<Function*> inlinedInto;
+    for (auto& func : module->functions) {
+      // if we've inlined a function, don't inline into it in this iteration,
+      // avoid risk of races
+      // note that we do not risk stalling progress, as each iteration() will
+      // inline at least one call before hitting this
+      if (inlinedUses.count(func->name)) {
+        continue;
+      }
+      for (auto& action : state.actionsForFunction[func->name]) {
+        auto* inlinedFunction = action.contents;
+        // if we've inlined into a function, don't inline it in this iteration,
+        // avoid risk of races
+        // note that we do not risk stalling progress, as each iteration() will
+        // inline at least one call before hitting this
+        if (inlinedInto.count(inlinedFunction)) {
+          continue;
+        }
+        Name inlinedName = inlinedFunction->name;
+#ifdef INLINING_DEBUG
+        std::cout << "inline " << inlinedName << " into " << func->name << '\n';
+#endif
+        doInlining(module, func.get(), action);
+        inlinedUses[inlinedName]++;
+        inlinedInto.insert(func.get());
+        assert(inlinedUses[inlinedName] <= infos[inlinedName].refs);
+      }
+    }
+    // anything we inlined into may now have non-unique label names, fix it up
+    for (auto func : inlinedInto) {
+      wasm::UniqueNameMapper::uniquify(func->body);
+    }
+    if (optimize && inlinedInto.size() > 0) {
+      OptUtils::optimizeAfterInlining(inlinedInto, module, runner);
+    }
+    // remove functions that we no longer need after inlining
+    module->removeFunctions([&](Function* func) {
+      auto name = func->name;
+      auto& info = infos[name];
+      return inlinedUses.count(name) && inlinedUses[name] == info.refs &&
+             !info.usedGlobally;
+    });
+    // return whether we did any work
+    return inlinedUses.size() > 0;
+  }
+};
+
+Pass* createInliningPass() { return new Inlining(); }
+
+Pass* createInliningOptimizingPass() {
+  auto* ret = new Inlining();
+  ret->optimize = true;
+  return ret;
+}
+
+static const char* MAIN = "main";
+static const char* ORIGINAL_MAIN = "__original_main";
+
+// Inline __original_main into main, if they exist. This works around the odd
+// thing that clang/llvm currently do, where __original_main contains the user's
+// actual main (this is done as a workaround for main having two different
+// possible signatures).
+struct InlineMainPass : public Pass {
+  void run(PassRunner* runner, Module* module) override {
+    auto* main = module->getFunctionOrNull(MAIN);
+    auto* originalMain = module->getFunctionOrNull(ORIGINAL_MAIN);
+    if (!main || main->imported() || !originalMain ||
+        originalMain->imported()) {
+      return;
+    }
+    FindAllPointers<Call> calls(main->body);
+    Expression** callSite = nullptr;
+    for (auto* call : calls.list) {
+      if ((*call)->cast<Call>()->target == ORIGINAL_MAIN) {
+        if (callSite) {
+          // More than one call site.
+          return;
+        }
+        callSite = call;
+      }
+    }
+    if (!callSite) {
+      // No call at all.
+      return;
+    }
+    doInlining(module, main, InliningAction(callSite, originalMain));
+  }
+};
+
+Pass* createInlineMainPass() { return new InlineMainPass(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/InstrumentLocals.cpp b/binaryen/src/passes/InstrumentLocals.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/InstrumentLocals.cpp
@@ -0,0 +1,253 @@
+/*
+ * 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.
+ */
+
+//
+// Instruments the build with code to intercept all local reads and writes.
+//
+// gets:
+//
+//  Before:
+//   (local.get $x)
+//
+//  After:
+//    (call $get_TYPE
+//     (i32.const n) // call id
+//     (i32.const n) // local id
+//     (local.get $x)
+//    )
+//
+// sets:
+//
+//  Before:
+//   (local.set $x (i32.const 1))
+//
+//  After:
+//   (local.set $x
+//    (call $set_TYPE
+//     (i32.const n) // call id
+//     (i32.const n) // local id
+//     (i32.const 1) // value
+//    )
+//   )
+
+#include "asm_v_wasm.h"
+#include "asmjs/shared-constants.h"
+#include "shared-constants.h"
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+namespace wasm {
+
+Name get_i32("get_i32");
+Name get_i64("get_i64");
+Name get_f32("get_f32");
+Name get_f64("get_f64");
+Name get_funcref("get_funcref");
+Name get_externref("get_externref");
+Name get_exnref("get_exnref");
+Name get_anyref("get_anyref");
+Name get_eqref("get_eqref");
+Name get_i31ref("get_i31ref");
+Name get_v128("get_v128");
+
+Name set_i32("set_i32");
+Name set_i64("set_i64");
+Name set_f32("set_f32");
+Name set_f64("set_f64");
+Name set_funcref("set_funcref");
+Name set_externref("set_externref");
+Name set_exnref("set_exnref");
+Name set_anyref("set_anyref");
+Name set_eqref("set_eqref");
+Name set_i31ref("set_i31ref");
+Name set_v128("set_v128");
+
+struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> {
+  void visitLocalGet(LocalGet* curr) {
+    Builder builder(*getModule());
+    Name import;
+    TODO_SINGLE_COMPOUND(curr->type);
+    switch (curr->type.getBasic()) {
+      case Type::i32:
+        import = get_i32;
+        break;
+      case Type::i64:
+        return; // TODO
+      case Type::f32:
+        import = get_f32;
+        break;
+      case Type::f64:
+        import = get_f64;
+        break;
+      case Type::v128:
+        import = get_v128;
+        break;
+      case Type::funcref:
+        import = get_funcref;
+        break;
+      case Type::externref:
+        import = get_externref;
+        break;
+      case Type::exnref:
+        import = get_exnref;
+        break;
+      case Type::anyref:
+        import = get_anyref;
+        break;
+      case Type::eqref:
+        import = get_eqref;
+        break;
+      case Type::i31ref:
+        import = get_i31ref;
+        break;
+      case Type::none:
+      case Type::unreachable:
+        WASM_UNREACHABLE("unexpected type");
+    }
+    replaceCurrent(builder.makeCall(import,
+                                    {builder.makeConst(int32_t(id++)),
+                                     builder.makeConst(int32_t(curr->index)),
+                                     curr},
+                                    curr->type));
+  }
+
+  void visitLocalSet(LocalSet* curr) {
+    // We don't instrument pop instructions. They are automatically deleted when
+    // writing binary and generated when reading binary, so they don't work with
+    // local set/get instrumentation.
+    if (curr->value->is<Pop>()) {
+      return;
+    }
+
+    Builder builder(*getModule());
+    Name import;
+    TODO_SINGLE_COMPOUND(curr->value->type);
+    switch (curr->value->type.getBasic()) {
+      case Type::i32:
+        import = set_i32;
+        break;
+      case Type::i64:
+        return; // TODO
+      case Type::f32:
+        import = set_f32;
+        break;
+      case Type::f64:
+        import = set_f64;
+        break;
+      case Type::v128:
+        import = set_v128;
+        break;
+      case Type::funcref:
+        import = set_funcref;
+        break;
+      case Type::externref:
+        import = set_externref;
+        break;
+      case Type::exnref:
+        import = set_exnref;
+        break;
+      case Type::anyref:
+        import = set_anyref;
+        break;
+      case Type::eqref:
+        import = set_eqref;
+        break;
+      case Type::i31ref:
+        import = set_i31ref;
+        break;
+      case Type::unreachable:
+        return; // nothing to do here
+      case Type::none:
+        WASM_UNREACHABLE("unexpected type");
+    }
+    curr->value = builder.makeCall(import,
+                                   {builder.makeConst(int32_t(id++)),
+                                    builder.makeConst(int32_t(curr->index)),
+                                    curr->value},
+                                   curr->value->type);
+  }
+
+  void visitModule(Module* curr) {
+    addImport(curr, get_i32, {Type::i32, Type::i32, Type::i32}, Type::i32);
+    addImport(curr, get_i64, {Type::i32, Type::i32, Type::i64}, Type::i64);
+    addImport(curr, get_f32, {Type::i32, Type::i32, Type::f32}, Type::f32);
+    addImport(curr, get_f64, {Type::i32, Type::i32, Type::f64}, Type::f64);
+    addImport(curr, set_i32, {Type::i32, Type::i32, Type::i32}, Type::i32);
+    addImport(curr, set_i64, {Type::i32, Type::i32, Type::i64}, Type::i64);
+    addImport(curr, set_f32, {Type::i32, Type::i32, Type::f32}, Type::f32);
+    addImport(curr, set_f64, {Type::i32, Type::i32, Type::f64}, Type::f64);
+
+    if (curr->features.hasReferenceTypes()) {
+      addImport(curr,
+                get_funcref,
+                {Type::i32, Type::i32, Type::funcref},
+                Type::funcref);
+      addImport(curr,
+                set_funcref,
+                {Type::i32, Type::i32, Type::funcref},
+                Type::funcref);
+      addImport(curr,
+                get_externref,
+                {Type::i32, Type::i32, Type::externref},
+                Type::externref);
+      addImport(curr,
+                set_externref,
+                {Type::i32, Type::i32, Type::externref},
+                Type::externref);
+      if (curr->features.hasExceptionHandling()) {
+        addImport(
+          curr, get_exnref, {Type::i32, Type::i32, Type::exnref}, Type::exnref);
+        addImport(
+          curr, set_exnref, {Type::i32, Type::i32, Type::exnref}, Type::exnref);
+      }
+      if (curr->features.hasGC()) {
+        addImport(
+          curr, get_anyref, {Type::i32, Type::i32, Type::anyref}, Type::anyref);
+        addImport(
+          curr, set_anyref, {Type::i32, Type::i32, Type::anyref}, Type::anyref);
+        addImport(
+          curr, get_eqref, {Type::i32, Type::i32, Type::eqref}, Type::eqref);
+        addImport(
+          curr, set_eqref, {Type::i32, Type::i32, Type::eqref}, Type::eqref);
+        addImport(
+          curr, get_i31ref, {Type::i32, Type::i32, Type::i31ref}, Type::i31ref);
+        addImport(
+          curr, set_i31ref, {Type::i32, Type::i32, Type::i31ref}, Type::i31ref);
+      }
+    }
+    if (curr->features.hasSIMD()) {
+      addImport(curr, get_v128, {Type::i32, Type::i32, Type::v128}, Type::v128);
+      addImport(curr, set_v128, {Type::i32, Type::i32, Type::v128}, Type::v128);
+    }
+  }
+
+private:
+  Index id = 0;
+
+  void addImport(Module* wasm, Name name, Type params, Type results) {
+    auto import = new Function;
+    import->name = name;
+    import->module = ENV;
+    import->base = name;
+    import->sig = Signature(params, results);
+    wasm->addFunction(import);
+  }
+};
+
+Pass* createInstrumentLocalsPass() { return new InstrumentLocals(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/InstrumentMemory.cpp b/binaryen/src/passes/InstrumentMemory.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/InstrumentMemory.cpp
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+//
+// Instruments the build with code to intercept all memory reads and writes.
+// This can be useful in building tools that analyze memory access behaviour.
+//
+//  Before:
+//   (i32.load8_s align=1 offset=2 (i32.const 3))
+//
+//  After:
+//   (call $load_val_i32
+//    (i32.const n) // ID
+//    (i32.load8_s align=1 offset=2
+//     (call $load_ptr
+//      (i32.const n) // ID
+//      (i32.const 1) // bytes
+//      (i32.const 2) // offset
+//      (i32.const 3) // address
+//     )
+//    )
+//   )
+// Stores: store(id, bytes, offset, address) => address
+//
+//  Before:
+//   (i32.store8 align=1 offset=2 (i32.const 3) (i32.const 4))
+//
+//  After:
+//   (i32.store16 align=1 offset=2
+//    (call $store_ptr
+//     (i32.const n) // ID
+//     (i32.const 1) // bytes
+//     (i32.const 2) // offset
+//     (i32.const 3) // address
+//    )
+//    (call $store_val_i32
+//     (i32.const n) // ID
+//     (i32.const 4)
+//    )
+//   )
+
+#include "asm_v_wasm.h"
+#include "asmjs/shared-constants.h"
+#include "shared-constants.h"
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+namespace wasm {
+
+static Name load_ptr("load_ptr");
+static Name load_val_i32("load_val_i32");
+static Name load_val_i64("load_val_i64");
+static Name load_val_f32("load_val_f32");
+static Name load_val_f64("load_val_f64");
+static Name store_ptr("store_ptr");
+static Name store_val_i32("store_val_i32");
+static Name store_val_i64("store_val_i64");
+static Name store_val_f32("store_val_f32");
+static Name store_val_f64("store_val_f64");
+
+// TODO: Add support for atomicRMW/cmpxchg
+
+struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
+  void visitLoad(Load* curr) {
+    id++;
+    Builder builder(*getModule());
+    auto indexType = getModule()->memory.indexType;
+    auto offset = builder.makeConstPtr(curr->offset.addr);
+    curr->ptr = builder.makeCall(load_ptr,
+                                 {builder.makeConst(int32_t(id)),
+                                  builder.makeConst(int32_t(curr->bytes)),
+                                  offset,
+                                  curr->ptr},
+                                 indexType);
+    Name target;
+    switch (curr->type.getBasic()) {
+      case Type::i32:
+        target = load_val_i32;
+        break;
+      case Type::i64:
+        target = load_val_i64;
+        break;
+      case Type::f32:
+        target = load_val_f32;
+        break;
+      case Type::f64:
+        target = load_val_f64;
+        break;
+      default:
+        return; // TODO: other types, unreachable, etc.
+    }
+    replaceCurrent(builder.makeCall(
+      target, {builder.makeConst(int32_t(id)), curr}, curr->type));
+  }
+
+  void visitStore(Store* curr) {
+    id++;
+    Builder builder(*getModule());
+    auto indexType = getModule()->memory.indexType;
+    auto offset = builder.makeConstPtr(curr->offset.addr);
+    curr->ptr = builder.makeCall(store_ptr,
+                                 {builder.makeConst(int32_t(id)),
+                                  builder.makeConst(int32_t(curr->bytes)),
+                                  offset,
+                                  curr->ptr},
+                                 indexType);
+    Name target;
+    switch (curr->value->type.getBasic()) {
+      case Type::i32:
+        target = store_val_i32;
+        break;
+      case Type::i64:
+        target = store_val_i64;
+        break;
+      case Type::f32:
+        target = store_val_f32;
+        break;
+      case Type::f64:
+        target = store_val_f64;
+        break;
+      default:
+        return; // TODO: other types, unreachable, etc.
+    }
+    curr->value = builder.makeCall(
+      target, {builder.makeConst(int32_t(id)), curr->value}, curr->value->type);
+  }
+
+  void visitModule(Module* curr) {
+    auto indexType = curr->memory.indexType;
+    addImport(
+      curr, load_ptr, {Type::i32, Type::i32, indexType, indexType}, indexType);
+    addImport(curr, load_val_i32, {Type::i32, Type::i32}, Type::i32);
+    addImport(curr, load_val_i64, {Type::i32, Type::i64}, Type::i64);
+    addImport(curr, load_val_f32, {Type::i32, Type::f32}, Type::f32);
+    addImport(curr, load_val_f64, {Type::i32, Type::f64}, Type::f64);
+    addImport(
+      curr, store_ptr, {Type::i32, Type::i32, indexType, indexType}, indexType);
+    addImport(curr, store_val_i32, {Type::i32, Type::i32}, Type::i32);
+    addImport(curr, store_val_i64, {Type::i32, Type::i64}, Type::i64);
+    addImport(curr, store_val_f32, {Type::i32, Type::f32}, Type::f32);
+    addImport(curr, store_val_f64, {Type::i32, Type::f64}, Type::f64);
+  }
+
+private:
+  Index id;
+
+  void addImport(Module* curr, Name name, Type params, Type results) {
+    auto import = new Function;
+    import->name = name;
+    import->module = ENV;
+    import->base = name;
+    import->sig = Signature(params, results);
+    curr->addFunction(import);
+  }
+};
+
+Pass* createInstrumentMemoryPass() { return new InstrumentMemory(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/LegalizeJSInterface.cpp b/binaryen/src/passes/LegalizeJSInterface.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/LegalizeJSInterface.cpp
@@ -0,0 +1,347 @@
+/*
+ * 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.
+ */
+
+//
+// i64 values are not valid in JS, and must be handled in some other
+// way. This pass transforms all i64s in params and results in imports
+// and exports into pairs of i32, i32 (low, high). If JS on the outside
+// calls with that ABI, then everything should then just work, using
+// stub methods added in this pass, that thunk i64s into i32, i32 and
+// vice versa as necessary.
+//
+// We can also legalize in a "minimal" way, that is, only JS-specific
+// components, that only JS will care about, such as dynCall methods
+// (wasm will never call them, as it can share the table directly). E.g.
+// is dynamic linking, where we can avoid legalizing wasm=>wasm calls
+// across modules, we still want to legalize dynCalls so JS can call into the
+// 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"
+#include "ir/utils.h"
+#include "pass.h"
+#include "shared-constants.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+#include <utility>
+
+namespace wasm {
+
+struct LegalizeJSInterface : public Pass {
+  bool full;
+
+  LegalizeJSInterface(bool full) : full(full) {}
+
+  void run(PassRunner* runner, Module* module) override {
+    auto exportOriginals =
+      !runner->options
+         .getArgumentOrDefault("legalize-js-interface-export-originals", "")
+         .empty();
+    // for each illegal export, we must export a legalized stub instead
+    std::vector<Export*> newExports;
+    for (auto& ex : module->exports) {
+      if (ex->kind == ExternalKind::Function) {
+        // if it's an import, ignore it
+        auto* func = module->getFunction(ex->value);
+        if (isIllegal(func) && shouldBeLegalized(ex.get(), func)) {
+          // Provide a legal function for the export.
+          auto legalName = makeLegalStub(func, module);
+          ex->value = legalName;
+          if (exportOriginals) {
+            // Also export the original function, before legalization. This is
+            // not normally useful for JS, except in cases like dynamic linking
+            // where the JS loader code must copy exported wasm functions into
+            // the table, and they must not be legalized as other wasm code will
+            // do an indirect call to them. However, don't do this for imported
+            // functions, as those would be legalized in their actual module
+            // anyhow. It also makes no sense to do this for dynCalls, as they
+            // are only called from JS.
+            if (!func->imported() && !isDynCall(ex->name)) {
+              Builder builder(*module);
+              Name newName = std::string("orig$") + ex->name.str;
+              newExports.push_back(builder.makeExport(
+                newName, func->name, ExternalKind::Function));
+            }
+          }
+        }
+      }
+    }
+    for (auto* ex : newExports) {
+      module->addExport(ex);
+    }
+    // Avoid iterator invalidation later.
+    std::vector<Function*> originalFunctions;
+    for (auto& func : module->functions) {
+      originalFunctions.push_back(func.get());
+    }
+    // for each illegal import, we must call a legalized stub instead
+    for (auto* im : originalFunctions) {
+      if (im->imported() && isIllegal(im) && shouldBeLegalized(im)) {
+        auto funcName = makeLegalStubForCalledImport(im, module);
+        illegalImportsToLegal[im->name] = funcName;
+        // we need to use the legalized version in the table, as the import from
+        // JS is legal for JS. Our stub makes it look like a native wasm
+        // function.
+        for (auto& segment : module->table.segments) {
+          for (auto& name : segment.data) {
+            if (name == im->name) {
+              name = funcName;
+            }
+          }
+        }
+      }
+    }
+
+    if (!illegalImportsToLegal.empty()) {
+      // Gather functions used in 'ref.func'. They should not be removed.
+      std::unordered_map<Name, std::atomic<bool>> usedInRefFunc;
+
+      // Fill in unordered_map, as we operate on it in parallel.
+      for (auto& func : module->functions) {
+        usedInRefFunc[func->name];
+      }
+
+      struct RefFuncScanner : public WalkerPass<PostWalker<RefFuncScanner>> {
+        Module& wasm;
+        std::unordered_map<Name, std::atomic<bool>>& usedInRefFunc;
+
+        bool isFunctionParallel() override { return true; }
+
+        Pass* create() override {
+          return new RefFuncScanner(wasm, usedInRefFunc);
+        }
+
+        RefFuncScanner(
+          Module& wasm,
+          std::unordered_map<Name, std::atomic<bool>>& usedInRefFunc)
+          : wasm(wasm), usedInRefFunc(usedInRefFunc) {}
+
+        void visitRefFunc(RefFunc* curr) { usedInRefFunc[curr->func] = true; }
+      };
+
+      RefFuncScanner(*module, usedInRefFunc).run(runner, module);
+      for (auto& pair : illegalImportsToLegal) {
+        if (!usedInRefFunc[pair.first]) {
+          module->removeFunction(pair.first);
+        }
+      }
+
+      // fix up imports: call_import of an illegal must be turned to a call of a
+      // legal
+      struct FixImports : public WalkerPass<PostWalker<FixImports>> {
+        bool isFunctionParallel() override { return true; }
+
+        Pass* create() override {
+          return new FixImports(illegalImportsToLegal);
+        }
+
+        std::map<Name, Name>* illegalImportsToLegal;
+
+        FixImports(std::map<Name, Name>* illegalImportsToLegal)
+          : illegalImportsToLegal(illegalImportsToLegal) {}
+
+        void visitCall(Call* curr) {
+          auto iter = illegalImportsToLegal->find(curr->target);
+          if (iter == illegalImportsToLegal->end()) {
+            return;
+          }
+
+          if (iter->second == getFunction()->name) {
+            // inside the stub function itself, is the one safe place to do the
+            // call
+            return;
+          }
+          replaceCurrent(
+            Builder(*getModule())
+              .makeCall(
+                iter->second, curr->operands, curr->type, curr->isReturn));
+        }
+      };
+
+      FixImports(&illegalImportsToLegal).run(runner, module);
+    }
+  }
+
+private:
+  // map of illegal to legal names for imports
+  std::map<Name, Name> illegalImportsToLegal;
+
+  template<typename T> bool isIllegal(T* t) {
+    for (const auto& param : t->sig.params) {
+      if (param == Type::i64) {
+        return true;
+      }
+    }
+    return t->sig.results == Type::i64;
+  }
+
+  bool isDynCall(Name name) { return name.startsWith("dynCall_"); }
+
+  // Check if an export should be legalized.
+  bool shouldBeLegalized(Export* ex, Function* func) {
+    if (full) {
+      return true;
+    }
+    // We are doing minimal legalization - just what JS needs.
+    return isDynCall(ex->name);
+  }
+
+  // Check if an import should be legalized.
+  bool shouldBeLegalized(Function* im) {
+    if (full) {
+      return true;
+    }
+    // We are doing minimal legalization - just what JS needs.
+    return im->module == ENV && im->base.startsWith("invoke_");
+  }
+
+  // JS calls the export, so it must call a legal stub that calls the actual
+  // wasm function
+  Name makeLegalStub(Function* func, Module* module) {
+    Name legalName(std::string("legalstub$") + func->name.str);
+
+    // a method may be exported multiple times
+    if (module->getFunctionOrNull(legalName)) {
+      return legalName;
+    }
+
+    Builder builder(*module);
+    auto* legal = new Function();
+    legal->name = legalName;
+
+    auto* call = module->allocator.alloc<Call>();
+    call->target = func->name;
+    call->type = func->sig.results;
+
+    std::vector<Type> legalParams;
+    for (const auto& param : func->sig.params) {
+      if (param == Type::i64) {
+        call->operands.push_back(I64Utilities::recreateI64(
+          builder, legalParams.size(), legalParams.size() + 1));
+        legalParams.push_back(Type::i32);
+        legalParams.push_back(Type::i32);
+      } else {
+        call->operands.push_back(
+          builder.makeLocalGet(legalParams.size(), param));
+        legalParams.push_back(param);
+      }
+    }
+    legal->sig.params = Type(legalParams);
+
+    if (func->sig.results == Type::i64) {
+      Function* f =
+        getFunctionOrImport(module, SET_TEMP_RET0, Type::i32, Type::none);
+      legal->sig.results = Type::i32;
+      auto index = Builder::addVar(legal, Name(), Type::i64);
+      auto* block = builder.makeBlock();
+      block->list.push_back(builder.makeLocalSet(index, call));
+      block->list.push_back(builder.makeCall(
+        f->name, {I64Utilities::getI64High(builder, index)}, Type::none));
+      block->list.push_back(I64Utilities::getI64Low(builder, index));
+      block->finalize();
+      legal->body = block;
+    } else {
+      legal->sig.results = func->sig.results;
+      legal->body = call;
+    }
+
+    return module->addFunction(legal)->name;
+  }
+
+  // wasm calls the import, so it must call a stub that calls the actual legal
+  // JS import
+  Name makeLegalStubForCalledImport(Function* im, Module* module) {
+    Builder builder(*module);
+    auto legalIm = make_unique<Function>();
+    legalIm->name = Name(std::string("legalimport$") + im->name.str);
+    legalIm->module = im->module;
+    legalIm->base = im->base;
+    auto stub = make_unique<Function>();
+    stub->name = Name(std::string("legalfunc$") + im->name.str);
+    stub->sig = im->sig;
+
+    auto* call = module->allocator.alloc<Call>();
+    call->target = legalIm->name;
+
+    std::vector<Type> params;
+    Index i = 0;
+    for (const auto& param : im->sig.params) {
+      if (param == Type::i64) {
+        call->operands.push_back(I64Utilities::getI64Low(builder, i));
+        call->operands.push_back(I64Utilities::getI64High(builder, i));
+        params.push_back(Type::i32);
+        params.push_back(Type::i32);
+      } else {
+        call->operands.push_back(builder.makeLocalGet(i, param));
+        params.push_back(param);
+      }
+      ++i;
+    }
+
+    if (im->sig.results == Type::i64) {
+      Function* f =
+        getFunctionOrImport(module, GET_TEMP_RET0, Type::none, Type::i32);
+      call->type = Type::i32;
+      Expression* get = builder.makeCall(f->name, {}, call->type);
+      stub->body = I64Utilities::recreateI64(builder, call, get);
+    } else {
+      call->type = im->sig.results;
+      stub->body = call;
+    }
+    legalIm->sig = Signature(Type(params), call->type);
+
+    const auto& stubName = stub->name;
+    if (!module->getFunctionOrNull(stubName)) {
+      module->addFunction(std::move(stub));
+    }
+    if (!module->getFunctionOrNull(legalIm->name)) {
+      module->addFunction(std::move(legalIm));
+    }
+    return stubName;
+  }
+
+  static Function*
+  getFunctionOrImport(Module* module, Name name, Type params, Type results) {
+    // First look for the function by name
+    if (Function* f = module->getFunctionOrNull(name)) {
+      return f;
+    }
+    // Then see if its already imported
+    ImportInfo info(*module);
+    if (Function* f = info.getImportedFunction(ENV, name)) {
+      return f;
+    }
+    // Failing that create a new function import.
+    auto import = new Function;
+    import->name = name;
+    import->module = ENV;
+    import->base = name;
+    import->sig = Signature(params, results);
+    module->addFunction(import);
+    return import;
+  }
+};
+
+Pass* createLegalizeJSInterfacePass() { return new LegalizeJSInterface(true); }
+
+Pass* createLegalizeJSInterfaceMinimallyPass() {
+  return new LegalizeJSInterface(false);
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/LimitSegments.cpp b/binaryen/src/passes/LimitSegments.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/LimitSegments.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2019 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ir/memory-utils.h"
+#include "pass.h"
+#include "wasm.h"
+
+using namespace std;
+
+namespace wasm {
+
+struct LimitSegments : public Pass {
+  void run(PassRunner* runner, Module* module) override {
+    if (!MemoryUtils::ensureLimitedSegments(*module)) {
+      std::cerr << "Unable to merge segments. "
+                << "wasm VMs may not accept this binary" << std::endl;
+    }
+  }
+};
+
+Pass* createLimitSegmentsPass() { return new LimitSegments(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/LocalCSE.cpp b/binaryen/src/passes/LocalCSE.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/LocalCSE.cpp
@@ -0,0 +1,271 @@
+/*
+ * 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.
+ */
+
+//
+// Local CSE
+//
+// This requires --flatten to be run before in order to be effective,
+// and preserves flatness. The reason flatness is required is that
+// this pass assumes everything is stored in a local, and all it does
+// is alter local.sets to do local.gets of an existing value when
+// possible, replacing a recomputing of that value. That design means that
+// if there are block and if return values, nested expressions not stored
+// to a local, etc., then it can't operate on them (and will just not
+// do anything for them).
+//
+// In each linear area of execution,
+//  * track each relevant (big enough) expression
+//  * if already seen, write to a local if not already, and reuse
+//  * invalidate the list as we see effects
+//
+// TODO: global, inter-block gvn etc.
+//
+
+#include <algorithm>
+#include <memory>
+
+#include "ir/flat.h"
+#include <ir/cost.h>
+#include <ir/effects.h>
+#include <ir/equivalent_sets.h>
+#include <ir/hashed.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm-traversal.h>
+#include <wasm.h>
+
+namespace wasm {
+
+struct LocalCSE : public WalkerPass<LinearExecutionWalker<LocalCSE>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new LocalCSE(); }
+
+  struct Usable {
+    HashedExpression hashed;
+    Type localType;
+    Usable(HashedExpression hashed, Type localType)
+      : hashed(hashed), localType(localType) {}
+  };
+
+  struct UsableHasher {
+    size_t operator()(const Usable value) const {
+      auto digest = value.hashed.digest;
+      wasm::rehash(digest, value.localType.getID());
+      return digest;
+    }
+  };
+
+  struct UsableComparer {
+    bool operator()(const Usable a, const Usable b) const {
+      if (a.hashed.digest != b.hashed.digest || a.localType != b.localType) {
+        return false;
+      }
+      return ExpressionAnalyzer::equal(a.hashed.expr, b.hashed.expr);
+    }
+  };
+
+  // information for an expression we can reuse
+  struct UsableInfo {
+    Expression* value; // the value we can reuse
+    Index index; // the local we are assigned to, local.get that to reuse us
+    EffectAnalyzer effects;
+
+    UsableInfo(Expression* value,
+               Index index,
+               PassOptions& passOptions,
+               FeatureSet features)
+      : value(value), index(index), effects(passOptions, features, value) {}
+  };
+
+  // a list of usables in a linear execution trace
+  class Usables
+    : public std::
+        unordered_map<Usable, UsableInfo, UsableHasher, UsableComparer> {};
+
+  // locals in current linear execution trace, which we try to sink
+  Usables usables;
+
+  // We track locals containing the same value - the value is what matters, not
+  // the index.
+  EquivalentSets equivalences;
+
+  bool anotherPass;
+
+  void doWalkFunction(Function* func) {
+    Flat::verifyFlatness(func);
+    anotherPass = true;
+    // we may need multiple rounds
+    while (anotherPass) {
+      anotherPass = false;
+      clear();
+      super::doWalkFunction(func);
+    }
+  }
+
+  static void doNoteNonLinear(LocalCSE* self, Expression** currp) {
+    self->clear();
+  }
+
+  void clear() {
+    usables.clear();
+    equivalences.clear();
+  }
+
+  // Checks invalidations due to a set of effects. Also optionally receive
+  // an expression that was just post-visited, and that also needs to be
+  // taken into account.
+  void checkInvalidations(EffectAnalyzer& effects, Expression* curr = nullptr) {
+    // TODO: this is O(bad)
+    std::vector<Usable> invalidated;
+    for (auto& sinkable : usables) {
+      // Check invalidations of the values we may want to use.
+      if (effects.invalidates(sinkable.second.effects)) {
+        invalidated.push_back(sinkable.first);
+      }
+    }
+    if (curr) {
+      // If we are a set, we have more to check: each of the usable
+      // values was from a set, and we did not consider the set in
+      // the loop above - just the values. So here we must check that
+      // sets do not interfere. (Note that due to flattening we
+      // have no risk of tees etc.)
+      if (auto* set = curr->dynCast<LocalSet>()) {
+        for (auto& sinkable : usables) {
+          // Check if the index is the same. Make sure to ignore
+          // our own value, which we may have just added!
+          if (sinkable.second.index == set->index &&
+              sinkable.second.value != set->value) {
+            invalidated.push_back(sinkable.first);
+          }
+        }
+      }
+    }
+    for (auto index : invalidated) {
+      usables.erase(index);
+    }
+  }
+
+  std::vector<Expression*> expressionStack;
+
+  static void visitPre(LocalCSE* self, Expression** currp) {
+    // pre operations
+    Expression* curr = *currp;
+
+    EffectAnalyzer effects(self->getPassOptions(), self->getModule()->features);
+    if (effects.checkPre(curr)) {
+      self->checkInvalidations(effects);
+    }
+
+    self->expressionStack.push_back(curr);
+  }
+
+  static void visitPost(LocalCSE* self, Expression** currp) {
+    auto* curr = *currp;
+
+    // main operations
+    self->handle(curr);
+
+    // post operations
+
+    EffectAnalyzer effects(self->getPassOptions(), self->getModule()->features);
+    if (effects.checkPost(curr)) {
+      self->checkInvalidations(effects, curr);
+    }
+
+    self->expressionStack.pop_back();
+  }
+
+  // override scan to add a pre and a post check task to all nodes
+  static void scan(LocalCSE* self, Expression** currp) {
+    self->pushTask(visitPost, currp);
+
+    super::scan(self, currp);
+
+    self->pushTask(visitPre, currp);
+  }
+
+  void handle(Expression* curr) {
+    if (auto* set = curr->dynCast<LocalSet>()) {
+      // Calculate equivalences
+      auto* func = getFunction();
+      equivalences.reset(set->index);
+      if (auto* get = set->value->dynCast<LocalGet>()) {
+        if (func->getLocalType(set->index) == func->getLocalType(get->index)) {
+          equivalences.add(set->index, get->index);
+        }
+      }
+      // consider the value
+      auto* value = set->value;
+      if (isRelevant(value)) {
+        Usable usable(value, func->getLocalType(set->index));
+        auto iter = usables.find(usable);
+        if (iter != usables.end()) {
+          // already exists in the table, this is good to reuse
+          auto& info = iter->second;
+          Type localType = func->getLocalType(info.index);
+          set->value =
+            Builder(*getModule()).makeLocalGet(info.index, localType);
+          anotherPass = true;
+        } else {
+          // not in table, add this, maybe we can help others later
+          usables.emplace(std::make_pair(
+            usable,
+            UsableInfo(
+              value, set->index, getPassOptions(), getModule()->features)));
+        }
+      }
+    } else if (auto* get = curr->dynCast<LocalGet>()) {
+      if (auto* set = equivalences.getEquivalents(get->index)) {
+        // Canonicalize to the lowest index. This lets hashing and comparisons
+        // "just work".
+        get->index = *std::min_element(set->begin(), set->end());
+      }
+    }
+  }
+
+  // A relevant value is a non-trivial one, something we may want to reuse
+  // and are able to.
+  bool isRelevant(Expression* value) {
+    if (value->is<LocalGet>()) {
+      return false; // trivial, this is what we optimize to!
+    }
+    if (!value->type.isConcrete()) {
+      return false; // don't bother with unreachable etc.
+    }
+    if (EffectAnalyzer(getPassOptions(), getModule()->features, value)
+          .hasSideEffects()) {
+      return false; // we can't combine things with side effects
+    }
+    auto& options = getPassRunner()->options;
+    // If the size is at least 3, then if we have two of them we have 6,
+    // and so adding one set+two gets and removing one of the items itself
+    // is not detrimental, and may be beneficial.
+    if (options.shrinkLevel > 0 && Measurer::measure(value) >= 3) {
+      return true;
+    }
+    // If we focus on speed, any reduction in cost is beneficial, as the
+    // cost of a get is essentially free.
+    if (options.shrinkLevel == 0 && CostAnalyzer(value).cost > 0) {
+      return true;
+    }
+    return false;
+  }
+};
+
+Pass* createLocalCSEPass() { return new LocalCSE(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/LogExecution.cpp b/binaryen/src/passes/LogExecution.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/LogExecution.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+//
+// Instruments the build with code to log execution at each function
+// entry, loop header, and return. This can be useful in debugging, to log out
+// a trace, and diff it to another (running in another browser, to
+// check for bugs, for example).
+//
+// The logging is performed by calling an ffi with an id for each
+// call site. You need to provide that import on the JS side.
+//
+// This pass is more effective on flat IR (--flatten) since when it
+// instruments say a return, there will be no code run in the return's
+// value.
+//
+
+#include "asm_v_wasm.h"
+#include "asmjs/shared-constants.h"
+#include "shared-constants.h"
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+namespace wasm {
+
+Name LOGGER("log_execution");
+
+struct LogExecution : public WalkerPass<PostWalker<LogExecution>> {
+  void visitLoop(Loop* curr) { curr->body = makeLogCall(curr->body); }
+
+  void visitReturn(Return* curr) { replaceCurrent(makeLogCall(curr)); }
+
+  void visitFunction(Function* curr) {
+    if (curr->imported()) {
+      return;
+    }
+    if (auto* block = curr->body->dynCast<Block>()) {
+      if (!block->list.empty()) {
+        block->list.back() = makeLogCall(block->list.back());
+      }
+    }
+    curr->body = makeLogCall(curr->body);
+  }
+
+  void visitModule(Module* curr) {
+    // Add the import
+    auto import = new Function;
+    import->name = LOGGER;
+    import->module = ENV;
+    import->base = LOGGER;
+    import->sig = Signature(Type::i32, Type::none);
+    curr->addFunction(import);
+  }
+
+private:
+  Expression* makeLogCall(Expression* curr) {
+    static Index id = 0;
+    Builder builder(*getModule());
+    return builder.makeSequence(
+      builder.makeCall(LOGGER, {builder.makeConst(int32_t(id++))}, Type::none),
+      curr);
+  }
+};
+
+Pass* createLogExecutionPass() { return new LogExecution(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/LoopInvariantCodeMotion.cpp b/binaryen/src/passes/LoopInvariantCodeMotion.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/LoopInvariantCodeMotion.cpp
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ */
+
+//
+// Simple loop invariant code motion (licm): for every none-typed
+// expression in a loop, see if we can move it out.
+//
+// Flattening is not necessary here, but may help (as separating
+// out expressions may allow moving at least part of a larger whole).
+//
+
+#include <unordered_map>
+
+#include "ir/effects.h"
+#include "ir/find_all.h"
+#include "ir/local-graph.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct LoopInvariantCodeMotion
+  : public WalkerPass<ExpressionStackWalker<LoopInvariantCodeMotion>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new LoopInvariantCodeMotion; }
+
+  typedef std::unordered_set<LocalSet*> LoopSets;
+
+  // main entry point
+
+  LocalGraph* localGraph;
+
+  void doWalkFunction(Function* func) {
+    // Compute all local dependencies first.
+    LocalGraph localGraphInstance(func);
+    localGraph = &localGraphInstance;
+    // Traverse the function.
+    super::doWalkFunction(func);
+  }
+
+  void visitLoop(Loop* loop) {
+    // We accumulate all the code we can move out, and will place it
+    // in a block just preceding the loop.
+    std::vector<Expression*> movedCode;
+    // Accumulate effects of things we can't move out - things
+    // we move out later must cross them, so we must verify it
+    // is ok to do so.
+    FeatureSet features = getModule()->features;
+    EffectAnalyzer effectsSoFar(getPassOptions(), features);
+    // The loop's total effects also matter. For example, a store
+    // in the loop means we can't move a load outside.
+    // FIXME: we look at the loop "tail" area too, after the last
+    //        possible branch back, which can cause false positives
+    //        for bad effect interactions.
+    EffectAnalyzer loopEffects(getPassOptions(), features, loop);
+    // Note all the sets in each loop, and how many per index. Currently
+    // EffectAnalyzer can't do that, and we need it to know if we
+    // can move a set out of the loop (if there is another set
+    // still there, we can't). Another possible option here is for
+    // LocalGraph to track interfering sets. TODO
+    // FIXME: also the loop tail issue from above.
+    auto numLocals = getFunction()->getNumLocals();
+    std::vector<Index> numSetsForIndex(numLocals);
+    std::fill(numSetsForIndex.begin(), numSetsForIndex.end(), 0);
+    LoopSets loopSets;
+    {
+      FindAll<LocalSet> finder(loop);
+      for (auto* set : finder.list) {
+        numSetsForIndex[set->index]++;
+        loopSets.insert(set);
+      }
+    }
+    // Walk along the loop entrance, while all the code there
+    // is executed unconditionally. That is the code we want to
+    // move out - anything that might or might not be executed
+    // may be best left alone anyhow.
+    std::vector<Expression**> work;
+    work.push_back(&loop->body);
+    while (!work.empty()) {
+      auto** currp = work.back();
+      work.pop_back();
+      auto* curr = *currp;
+      // Look into blocks.
+      if (auto* block = curr->dynCast<Block>()) {
+        auto& list = block->list;
+        Index i = list.size();
+        while (i > 0) {
+          i--;
+          work.push_back(&list[i]);
+        }
+        continue;
+        // Note that if the block had a merge at the end, we would have seen
+        // a branch to it anyhow, so we would stop before that point anyhow.
+      }
+      // If this may branch, we are done.
+      EffectAnalyzer effects(getPassOptions(), features, curr);
+      if (effects.transfersControlFlow()) {
+        break;
+      }
+      if (interestingToMove(curr)) {
+        // Let's see if we can move this out.
+        // Global side effects 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());
+        if (!unsafeToMove) {
+          // So far so good. Check if our local dependencies are all
+          // outside of the loop, in which case everything is good -
+          // either they are before the loop and constant for us, or
+          // they are after and don't matter.
+          if (effects.localsRead.empty() ||
+              !hasGetDependingOnLoopSet(curr, loopSets)) {
+            // We have checked if our gets are influenced by sets in the loop,
+            // and must also check if our sets interfere with them. To do so,
+            // assume temporarily that we are moving curr out; see if any sets
+            // remain for its indexes.
+            FindAll<LocalSet> currSets(curr);
+            for (auto* set : currSets.list) {
+              assert(numSetsForIndex[set->index] > 0);
+              numSetsForIndex[set->index]--;
+            }
+            bool canMove = true;
+            for (auto* set : currSets.list) {
+              if (numSetsForIndex[set->index] > 0) {
+                canMove = false;
+                break;
+              }
+            }
+            if (!canMove) {
+              // We failed to move the code, undo those changes.
+              for (auto* set : currSets.list) {
+                numSetsForIndex[set->index]++;
+              }
+            } else {
+              // We can move it! Leave the changes, move the code, and update
+              // loopSets.
+              movedCode.push_back(curr);
+              *currp = Builder(*getModule()).makeNop();
+              for (auto* set : currSets.list) {
+                loopSets.erase(set);
+              }
+              continue;
+            }
+          }
+        }
+      }
+      // We did not move this item. Accumulate its effects.
+      effectsSoFar.mergeIn(effects);
+    }
+    // If we moved the code out, finish up by emitting it
+    // outside of the loop.
+    // Note that this works with nested loops - after moving outside
+    // of an inner loop, we can encounter it again in an outer loop,
+    // and move it further outside, without requiring any extra pass.
+    if (!movedCode.empty()) {
+      // Finish the moving by emitting the code outside.
+      Builder builder(*getModule());
+      auto* ret = builder.makeBlock(movedCode);
+      ret->list.push_back(loop);
+      ret->finalize(loop->type);
+      replaceCurrent(ret);
+      // Note that we do not need to modify the localGraph - we keep
+      // each get in a position to be influenced by exactly the same
+      // sets as before.
+    }
+  }
+
+  bool interestingToMove(Expression* curr) {
+    // In theory we could consider blocks, but then heavy nesting of
+    // switch patterns would be heavy, and almost always pointless.
+    if (curr->type != Type::none || curr->is<Nop>() || curr->is<Block>() ||
+        curr->is<Loop>()) {
+      return false;
+    }
+    // Don't move copies (set of a get, or set of a tee of a get, etc.),
+    // as they often do not turn into actual work inside the loop
+    // (after later optimizations by us or the VM), and if we move them
+    // out it will prevent other opts from potentially eliminating the
+    // copy, as we don't have another pass that considers moving code
+    // back *into* loops.
+    // Likewise, constants also are not worth moving out.
+    // Note that the issue remains for moving things out which later
+    // optimizations turn into a copy or a constant, so in general
+    // it is beneficial to run this pass later on (but that has downsides
+    // too, as with more nesting moving code is harder - so something
+    // like -O --flatten --licm -O may be best).
+    if (auto* set = curr->dynCast<LocalSet>()) {
+      while (1) {
+        auto* next = set->value->dynCast<LocalSet>();
+        if (!next) {
+          break;
+        }
+        set = next;
+      }
+      if (set->value->is<LocalGet>() || set->value->is<Const>()) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool hasGetDependingOnLoopSet(Expression* curr, LoopSets& loopSets) {
+    FindAll<LocalGet> gets(curr);
+    for (auto* get : gets.list) {
+      auto& sets = localGraph->getSetses[get];
+      for (auto* set : sets) {
+        // nullptr means a parameter or zero-init value;
+        // no danger to us.
+        if (!set) {
+          continue;
+        }
+        // Check if the set is in the loop. If not, it's either before,
+        // which is fine, or after, which is also fine - moving curr
+        // to just outside the loop will preserve those relationships.
+        // TODO: this still counts curr's sets as inside the loop, which
+        //       might matter in non-flat mode.
+        if (loopSets.count(set)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+};
+
+Pass* createLoopInvariantCodeMotionPass() {
+  return new LoopInvariantCodeMotion();
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/MemoryPacking.cpp b/binaryen/src/passes/MemoryPacking.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/MemoryPacking.cpp
@@ -0,0 +1,678 @@
+/*
+ * 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.
+ */
+
+//
+// Memory Packing.
+//
+// Reduces binary size by splitting data segments around ranges of zeros. This
+// pass assumes that memory initialized by active segments is zero on
+// instantiation and therefore simply drops the zero ranges from the active
+// segments. For passive segments, we perform the same splitting, but we also
+// record how each segment was split and update all bulk memory operations
+// accordingly. To preserve trapping semantics for memory.init instructions, it
+// is sometimes necessary to explicitly track whether input segments would have
+// been dropped in globals. We are careful to emit only as many of these globals
+// as necessary.
+//
+
+#include "ir/manipulation.h"
+#include "ir/module-utils.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "wasm-binary.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+// 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 {
+  bool isZero;
+  size_t start;
+  size_t end;
+};
+
+// A function that produces the transformed bulk memory op. We need to use a
+// function here instead of simple data because the replacement code sequence
+// may require allocating new locals, which in turn requires the enclosing
+// Function, which is only available in the parallelized instruction replacement
+// phase. However, we can't move the entire calculation of replacement code
+// sequences into the parallel phase because the lowering of data.drops depends
+// on the lowering of memory.inits to determine whether a drop state global is
+// necessary. The solution is that we calculate the shape of the replacement
+// code sequence up front and use a closure just to allocate and insert new
+// locals as necessary.
+using Replacement = std::function<Expression*(Function*)>;
+
+// Maps each bulk memory op to the replacement that must be applied to it.
+using Replacements = std::unordered_map<Expression*, Replacement>;
+
+// A collection of bulk memory operations referring to a particular segment
+using Referrers = std::vector<Expression*>;
+
+// memory.init: 2 byte opcode + 1 byte segment index + 1 byte memory index +
+//              3 x 2 byte operands
+const size_t MEMORY_INIT_SIZE = 10;
+
+// memory.fill: 2 byte opcode + 1 byte memory index + 3 x 2 byte operands
+const size_t MEMORY_FILL_SIZE = 9;
+
+// 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(
+    module.memory.is64() ? GtUInt64 : GtUInt32,
+    curr->dest,
+    builder.makeBinary(module.memory.is64() ? ShlInt64 : ShlInt32,
+                       builder.makeMemorySize(),
+                       builder.makeConstPtr(16)));
+}
+
+} // 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;
+  void optimizeBulkMemoryOps(PassRunner* runner, Module* module);
+  void getSegmentReferrers(Module* module, std::vector<Referrers>& referrers);
+  void dropUnusedSegments(std::vector<Memory::Segment>& segments,
+                          std::vector<Referrers>& referrers);
+  bool canSplit(const Memory::Segment& segment, const Referrers& referrers);
+  void calculateRanges(const Memory::Segment& segment,
+                       const Referrers& referrers,
+                       std::vector<Range>& ranges);
+  void createSplitSegments(Builder& builder,
+                           const Memory::Segment& segment,
+                           std::vector<Range>& ranges,
+                           std::vector<Memory::Segment>& packed,
+                           size_t segmentsRemaining);
+  void createReplacements(Module* module,
+                          const std::vector<Range>& ranges,
+                          const Referrers& referrers,
+                          Replacements& replacements,
+                          const Index segmentIndex);
+  void replaceBulkMemoryOps(PassRunner* runner,
+                            Module* module,
+                            Replacements& replacements);
+};
+
+void MemoryPacking::run(PassRunner* runner, Module* module) {
+  if (!module->memory.exists) {
+    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
+  std::vector<Referrers> referrers(segments.size());
+
+  if (module->features.hasBulkMemory()) {
+    // Optimize out memory.inits and data.drops that can be entirely replaced
+    // with other instruction sequences. This can increase the number of unused
+    // segments that can be dropped entirely and allows later replacement
+    // creation to make more assumptions about what these instructions will look
+    // like, such as memory.inits not having both zero offset and size.
+    optimizeBulkMemoryOps(runner, module);
+    getSegmentReferrers(module, referrers);
+    dropUnusedSegments(segments, referrers);
+  }
+
+  // The new, split memory segments
+  std::vector<Memory::Segment> packed;
+
+  Replacements replacements;
+  Builder builder(*module);
+  for (size_t origIndex = 0; origIndex < segments.size(); ++origIndex) {
+    auto& segment = segments[origIndex];
+    auto& currReferrers = referrers[origIndex];
+
+    std::vector<Range> ranges;
+    if (canSplit(segment, currReferrers)) {
+      calculateRanges(segment, currReferrers, ranges);
+    } else {
+      // A single range covers the entire segment. Set isZero to false so the
+      // original memory.init will be used even if segment is all zeroes.
+      ranges.push_back({false, 0, segment.data.size()});
+    }
+
+    Index firstNewIndex = packed.size();
+    size_t segmentsRemaining = segments.size() - origIndex;
+    createSplitSegments(builder, segment, ranges, packed, segmentsRemaining);
+    createReplacements(
+      module, ranges, currReferrers, replacements, firstNewIndex);
+  }
+
+  segments.swap(packed);
+
+  if (module->features.hasBulkMemory()) {
+    replaceBulkMemoryOps(runner, module, replacements);
+  }
+}
+
+bool MemoryPacking::canSplit(const Memory::Segment& segment,
+                             const Referrers& referrers) {
+  if (segment.isPassive) {
+    for (auto* referrer : referrers) {
+      if (auto* init = referrer->dynCast<MemoryInit>()) {
+        // Do not try to split if there is a nonconstant offset or size
+        if (!init->offset->is<Const>() || !init->size->is<Const>()) {
+          return false;
+        }
+      }
+    }
+    return true;
+  } else {
+    // Active segments can only be split if they have constant offsets
+    return segment.offset->is<Const>();
+  }
+}
+
+void MemoryPacking::calculateRanges(const Memory::Segment& segment,
+                                    const Referrers& referrers,
+                                    std::vector<Range>& ranges) {
+  auto& data = segment.data;
+  if (data.size() == 0) {
+    return;
+  }
+
+  // Calculate initial zero and nonzero ranges
+  size_t start = 0;
+  while (start < data.size()) {
+    size_t end = start;
+    while (end < data.size() && data[end] == 0) {
+      end++;
+    }
+    if (end > start) {
+      ranges.push_back({true, start, end});
+      start = end;
+    }
+    while (end < data.size() && data[end] != 0) {
+      end++;
+    }
+    if (end > start) {
+      ranges.push_back({false, start, end});
+      start = end;
+    }
+  }
+
+  // Calculate the number of consecutive zeroes for which splitting is
+  // beneficial. This is an approximation that assumes all memory.inits cover an
+  // entire segment and that all its arguments are constants. These assumptions
+  // are true of all memory.inits generated by the tools.
+  size_t threshold = 0;
+  if (segment.isPassive) {
+    // Passive segment metadata size
+    threshold += 2;
+    // Zeroes on the edge do not increase the number of segments or data.drops,
+    // so their threshold is lower. The threshold for interior zeroes depends on
+    // an estimate of the number of new memory.fill and data.drop instructions
+    // splitting would introduce.
+    size_t edgeThreshold = 0;
+    for (auto* referrer : referrers) {
+      if (referrer->is<MemoryInit>()) {
+        // Splitting adds a new memory.fill and a new memory.init
+        threshold += MEMORY_FILL_SIZE + MEMORY_INIT_SIZE;
+        edgeThreshold += MEMORY_FILL_SIZE;
+      } else {
+        threshold += DATA_DROP_SIZE;
+      }
+    }
+
+    // Merge edge zeroes if they are not worth splitting
+    if (ranges.size() >= 2) {
+      auto last = ranges.end() - 1;
+      auto penultimate = ranges.end() - 2;
+      if (last->isZero && last->end - last->start <= edgeThreshold) {
+        penultimate->end = last->end;
+        ranges.erase(last);
+      }
+    }
+    if (ranges.size() >= 2) {
+      auto first = ranges.begin();
+      auto second = ranges.begin() + 1;
+      if (first->isZero && first->end - first->start <= edgeThreshold) {
+        second->start = first->start;
+        ranges.erase(first);
+      }
+    }
+  } else {
+    // Legacy ballpark overhead of active segment with offset
+    // TODO: Tune this
+    threshold = 8;
+  }
+
+  // Merge ranges across small spans of zeroes
+  std::vector<Range> mergedRanges = {ranges.front()};
+  size_t i;
+  for (i = 1; i < ranges.size() - 1; ++i) {
+    auto left = mergedRanges.end() - 1;
+    auto curr = ranges.begin() + i;
+    auto right = ranges.begin() + i + 1;
+    if (curr->isZero && curr->end - curr->start <= threshold) {
+      left->end = right->end;
+      ++i;
+    } else {
+      mergedRanges.push_back(*curr);
+    }
+  }
+  // Add the final range if it hasn't already been merged in
+  if (i < ranges.size()) {
+    mergedRanges.push_back(ranges.back());
+  }
+  std::swap(ranges, mergedRanges);
+}
+
+void MemoryPacking::optimizeBulkMemoryOps(PassRunner* runner, Module* module) {
+  struct Optimizer : WalkerPass<PostWalker<Optimizer>> {
+    bool isFunctionParallel() override { return true; }
+    Pass* create() override { return new Optimizer; }
+
+    bool needsRefinalizing;
+
+    void visitMemoryInit(MemoryInit* curr) {
+      Builder builder(*getModule());
+      Memory::Segment& segment = getModule()->memory.segments[curr->segment];
+      size_t maxRuntimeSize = segment.isPassive ? segment.data.size() : 0;
+      bool mustNop = false;
+      bool mustTrap = false;
+      auto* offset = curr->offset->dynCast<Const>();
+      auto* size = curr->size->dynCast<Const>();
+      if (offset && uint32_t(offset->value.geti32()) > maxRuntimeSize) {
+        mustTrap = true;
+      }
+      if (size && uint32_t(size->value.geti32()) > maxRuntimeSize) {
+        mustTrap = true;
+      }
+      if (offset && size) {
+        uint64_t offsetVal(offset->value.geti32());
+        uint64_t sizeVal(size->value.geti32());
+        if (offsetVal + sizeVal > maxRuntimeSize) {
+          mustTrap = true;
+        } else if (offsetVal == 0 && sizeVal == 0) {
+          mustNop = true;
+        }
+      }
+      assert(!mustNop || !mustTrap);
+      if (mustNop) {
+        // Offset and size are 0, so just trap if dest > memory.size
+        replaceCurrent(
+          builder.makeIf(makeGtShiftedMemorySize(builder, *getModule(), curr),
+                         builder.makeUnreachable()));
+      } else if (mustTrap) {
+        // Drop dest, offset, and size then trap
+        replaceCurrent(builder.blockify(builder.makeDrop(curr->dest),
+                                        builder.makeDrop(curr->offset),
+                                        builder.makeDrop(curr->size),
+                                        builder.makeUnreachable()));
+        needsRefinalizing = true;
+      } else if (!segment.isPassive) {
+        // trap if (dest > memory.size | offset | size) != 0
+        replaceCurrent(builder.makeIf(
+          builder.makeBinary(
+            OrInt32,
+            makeGtShiftedMemorySize(builder, *getModule(), curr),
+            builder.makeBinary(OrInt32, curr->offset, curr->size)),
+          builder.makeUnreachable()));
+      }
+    }
+    void visitDataDrop(DataDrop* curr) {
+      if (!getModule()->memory.segments[curr->segment].isPassive) {
+        ExpressionManipulator::nop(curr);
+      }
+    }
+    void doWalkFunction(Function* func) {
+      needsRefinalizing = false;
+      super::doWalkFunction(func);
+      if (needsRefinalizing) {
+        ReFinalize().walkFunctionInModule(func, getModule());
+      }
+    }
+  } optimizer;
+  optimizer.run(runner, module);
+}
+
+void MemoryPacking::getSegmentReferrers(Module* module,
+                                        std::vector<Referrers>& referrers) {
+  auto collectReferrers = [&](Function* func,
+                              std::vector<Referrers>& referrers) {
+    if (func->imported()) {
+      return;
+    }
+    struct Collector : WalkerPass<PostWalker<Collector>> {
+      std::vector<Referrers>& referrers;
+      Collector(std::vector<Referrers>& referrers) : referrers(referrers) {}
+
+      void visitMemoryInit(MemoryInit* curr) {
+        referrers[curr->segment].push_back(curr);
+      }
+      void visitDataDrop(DataDrop* curr) {
+        referrers[curr->segment].push_back(curr);
+      }
+      void doWalkFunction(Function* func) {
+        referrers.resize(getModule()->memory.segments.size());
+        super::doWalkFunction(func);
+      }
+    } collector(referrers);
+    collector.walkFunctionInModule(func, module);
+  };
+  ModuleUtils::ParallelFunctionAnalysis<std::vector<Referrers>> analysis(
+    *module, collectReferrers);
+  referrers.resize(module->memory.segments.size());
+  for (auto& pair : analysis.map) {
+    std::vector<Referrers>& funcReferrers = pair.second;
+    for (size_t i = 0; i < funcReferrers.size(); ++i) {
+      referrers[i].insert(
+        referrers[i].end(), funcReferrers[i].begin(), funcReferrers[i].end());
+    }
+  }
+}
+
+void MemoryPacking::dropUnusedSegments(std::vector<Memory::Segment>& segments,
+                                       std::vector<Referrers>& referrers) {
+  std::vector<Memory::Segment> usedSegments;
+  std::vector<Referrers> usedReferrers;
+  // Remove segments that are never used
+  // TODO: remove unused portions of partially used segments as well
+  for (size_t i = 0; i < segments.size(); ++i) {
+    bool used = false;
+    if (segments[i].isPassive) {
+      for (auto* referrer : referrers[i]) {
+        if (referrer->is<MemoryInit>()) {
+          used = true;
+          break;
+        }
+      }
+    } else {
+      used = true;
+    }
+    if (used) {
+      usedSegments.push_back(segments[i]);
+      usedReferrers.push_back(referrers[i]);
+    } else {
+      // All referrers are data.drops. Make them nops.
+      for (auto* referrer : referrers[i]) {
+        ExpressionManipulator::nop(referrer);
+      }
+    }
+  }
+  std::swap(segments, usedSegments);
+  std::swap(referrers, usedReferrers);
+}
+
+void MemoryPacking::createSplitSegments(Builder& builder,
+                                        const Memory::Segment& segment,
+                                        std::vector<Range>& ranges,
+                                        std::vector<Memory::Segment>& packed,
+                                        size_t segmentsRemaining) {
+  for (size_t i = 0; i < ranges.size(); ++i) {
+    Range& range = ranges[i];
+    if (range.isZero) {
+      continue;
+    }
+    Expression* offset = nullptr;
+    if (!segment.isPassive) {
+      if (auto* c = segment.offset->dynCast<Const>()) {
+        offset = builder.makeConst(int32_t(c->value.geti32() + range.start));
+      } else {
+        assert(ranges.size() == 1);
+        offset = segment.offset;
+      }
+    }
+    if (maxSegments <= packed.size() + segmentsRemaining) {
+      // Give up splitting and merge all remaining ranges except end zeroes
+      auto lastNonzero = ranges.end() - 1;
+      if (lastNonzero->isZero) {
+        --lastNonzero;
+      }
+      range.end = lastNonzero->end;
+      ranges.erase(ranges.begin() + i + 1, lastNonzero + 1);
+    }
+    packed.emplace_back(segment.isPassive,
+                        offset,
+                        &segment.data[range.start],
+                        range.end - range.start);
+  }
+}
+
+void MemoryPacking::createReplacements(Module* module,
+                                       const std::vector<Range>& ranges,
+                                       const Referrers& referrers,
+                                       Replacements& replacements,
+                                       const Index segmentIndex) {
+  // If there was no transformation, only update the indices
+  if (ranges.size() == 1 && !ranges.front().isZero) {
+    for (auto referrer : referrers) {
+      replacements[referrer] = [referrer, segmentIndex](Function*) {
+        if (auto* init = referrer->dynCast<MemoryInit>()) {
+          init->segment = segmentIndex;
+        } else if (auto* drop = referrer->dynCast<DataDrop>()) {
+          drop->segment = segmentIndex;
+        } else {
+          WASM_UNREACHABLE("Unexpected bulk memory operation");
+        }
+        return referrer;
+      };
+    }
+    return;
+  }
+
+  Builder builder(*module);
+
+  Name dropStateGlobal;
+
+  // Return the drop state global, initializing it if it does not exist. This
+  // may change module-global state and has the important side effect of setting
+  // dropStateGlobal, so it must be evaluated eagerly, not in the replacements.
+  auto getDropStateGlobal = [&]() {
+    if (dropStateGlobal != Name()) {
+      return dropStateGlobal;
+    }
+    dropStateGlobal = Name(std::string("__mem_segment_drop_state_") +
+                           std::to_string(dropStateGlobalCount++));
+    module->addGlobal(builder.makeGlobal(dropStateGlobal,
+                                         Type::i32,
+                                         builder.makeConst(int32_t(0)),
+                                         Builder::Mutable));
+    return dropStateGlobal;
+  };
+
+  // Create replacements for memory.init instructions first
+  for (auto referrer : referrers) {
+    auto* init = referrer->dynCast<MemoryInit>();
+    if (init == nullptr) {
+      continue;
+    }
+
+    // Nonconstant offsets or sizes will have inhibited splitting
+    size_t start = init->offset->cast<Const>()->value.geti32();
+    size_t end = start + init->size->cast<Const>()->value.geti32();
+
+    // Index of the range from which this memory.init starts reading
+    size_t firstRangeIdx = 0;
+    while (firstRangeIdx < ranges.size() &&
+           ranges[firstRangeIdx].end <= start) {
+      ++firstRangeIdx;
+    }
+
+    // Handle zero-length memory.inits separately so we can later assume that
+    // start is in bounds and that some range will be intersected.
+    if (start == end) {
+      // Offset is nonzero because init would otherwise have previously been
+      // optimized out, so trap if the dest is out of bounds or the segment is
+      // dropped
+      Expression* result = builder.makeIf(
+        builder.makeBinary(
+          OrInt32,
+          makeGtShiftedMemorySize(builder, *module, init),
+          builder.makeGlobalGet(getDropStateGlobal(), Type::i32)),
+        builder.makeUnreachable());
+      replacements[init] = [result](Function*) { return result; };
+      continue;
+    }
+
+    assert(firstRangeIdx < ranges.size());
+
+    // Split init into multiple memory.inits and memory.fills, storing the
+    // original base destination in a local if it is not a constant. If the
+    // first access is a memory.fill, explicitly check the drop status first to
+    // avoid writing zeroes when we should have trapped.
+    Expression* result = nullptr;
+    auto appendResult = [&](Expression* expr) {
+      result = result ? builder.blockify(result, expr) : expr;
+    };
+
+    // The local var holding the dest is not known until replacement time. Keep
+    // track of the locations where it will need to be patched in.
+    Index* setVar = nullptr;
+    std::vector<Index*> getVars;
+    if (!init->dest->is<Const>()) {
+      auto set = builder.makeLocalSet(-1, init->dest);
+      setVar = &set->index;
+      appendResult(set);
+    }
+
+    // We only need to explicitly check the drop state when we will emit
+    // memory.fill first, since memory.init will implicitly do the check for us.
+    if (ranges[firstRangeIdx].isZero) {
+      appendResult(
+        builder.makeIf(builder.makeGlobalGet(getDropStateGlobal(), Type::i32),
+                       builder.makeUnreachable()));
+    }
+
+    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];
+
+      // Calculate dest, either as a const or as an addition to the dest local
+      Expression* dest;
+      if (auto* c = init->dest->dynCast<Const>()) {
+        dest = builder.makeConst(int32_t(c->value.geti32() + bytesWritten));
+      } else {
+        auto* get = builder.makeLocalGet(-1, Type::i32);
+        getVars.push_back(&get->index);
+        dest = get;
+        if (bytesWritten > 0) {
+          Const* addend = builder.makeConst(int32_t(bytesWritten));
+          dest = builder.makeBinary(AddInt32, dest, addend);
+        }
+      }
+
+      // How many bytes are read from this range
+      size_t bytes = std::min(range.end, end) - std::max(range.start, start);
+      Expression* size = builder.makeConst(int32_t(bytes));
+      bytesWritten += bytes;
+
+      // Create new memory.init or memory.fill
+      if (range.isZero) {
+        Expression* value = builder.makeConst(Literal::makeZero(Type::i32));
+        appendResult(builder.makeMemoryFill(dest, value, size));
+      } else {
+        size_t offsetBytes = std::max(start, range.start) - range.start;
+        Expression* offset = builder.makeConst(int32_t(offsetBytes));
+        appendResult(builder.makeMemoryInit(initIndex, dest, offset, size));
+        initIndex++;
+      }
+    }
+
+    // Non-zero length memory.inits must have intersected some range
+    assert(result);
+    replacements[init] = [module, setVar, getVars, result](Function* function) {
+      if (setVar != nullptr) {
+        Index destVar = Builder(*module).addVar(function, Type::i32);
+        *setVar = destVar;
+        for (auto* getVar : getVars) {
+          *getVar = destVar;
+        }
+      }
+      return result;
+    };
+  }
+
+  // Create replacements for data.drop instructions now that we know whether we
+  // need a drop state global
+  for (auto drop : referrers) {
+    if (!drop->is<DataDrop>()) {
+      continue;
+    }
+
+    Expression* result = nullptr;
+    auto appendResult = [&](Expression* expr) {
+      result = result ? builder.blockify(result, expr) : expr;
+    };
+
+    // Track drop state in a global only if some memory.init required it
+    if (dropStateGlobal != Name()) {
+      appendResult(
+        builder.makeGlobalSet(dropStateGlobal, builder.makeConst(int32_t(1))));
+    }
+    size_t dropIndex = segmentIndex;
+    for (auto range : ranges) {
+      if (!range.isZero) {
+        appendResult(builder.makeDataDrop(dropIndex++));
+      }
+    }
+    replacements[drop] = [result, module](Function*) {
+      return result ? result : Builder(*module).makeNop();
+    };
+  }
+}
+
+void MemoryPacking::replaceBulkMemoryOps(PassRunner* runner,
+                                         Module* module,
+                                         Replacements& replacements) {
+  struct Replacer : WalkerPass<PostWalker<Replacer>> {
+    bool isFunctionParallel() override { return true; }
+
+    Replacements& replacements;
+
+    Replacer(Replacements& replacements) : replacements(replacements){};
+    Pass* create() override { return new Replacer(replacements); }
+
+    void visitMemoryInit(MemoryInit* curr) {
+      auto replacement = replacements.find(curr);
+      assert(replacement != replacements.end());
+      replaceCurrent(replacement->second(getFunction()));
+    }
+
+    void visitDataDrop(DataDrop* curr) {
+      auto replacement = replacements.find(curr);
+      assert(replacement != replacements.end());
+      replaceCurrent(replacement->second(getFunction()));
+    }
+  } replacer(replacements);
+  replacer.run(runner, module);
+}
+
+Pass* createMemoryPackingPass() { return new MemoryPacking(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/MergeBlocks.cpp b/binaryen/src/passes/MergeBlocks.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/MergeBlocks.cpp
@@ -0,0 +1,603 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// Merges blocks to their parents.
+//
+// We merge both entire blocks when possible, as well as loop tails, like
+//  (block
+//   (loop $child
+//    (br_if $child (..)
+//    (call $foo)
+//   )
+//  )
+// Here we can move the call into the outer block. Doing so may let
+// the inner block become a single expression, and usually outer
+// blocks are larger anyhow. (This also helps readability.)
+//
+// We also restructure blocks in order to enable such merging. For
+// example,
+//
+//  (i32.store
+//    (block
+//      (call $foo)
+//      (i32.load (i32.const 100))
+//    )
+//    (i32.const 0)
+//  )
+//
+// can be transformed into
+//
+//  (block
+//    (call $foo)
+//    (i32.store
+//      (block
+//        (i32.load (i32.const 100))
+//      )
+//      (i32.const 0)
+//    )
+//  )
+//
+// after which the internal block can go away, and
+// the new external block might be mergeable. This is always
+// worth it if the internal block ends up with 1 item.
+// For the second operand,
+//
+//  (i32.store
+//    (i32.const 100)
+//    (block
+//      (call $foo)
+//      (i32.load (i32.const 200))
+//    )
+//  )
+//
+// The order of operations requires that the first execute
+// before. We can do the same operation, but only if the
+// first has no side effects, or the code we are moving out
+// has no side effects.
+// If we can do this to both operands, we can generate a
+// single outside block.
+//
+
+#include <ir/branch-utils.h>
+#include <ir/effects.h>
+#include <ir/utils.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+namespace wasm {
+
+// Looks for reasons we can't remove the values from breaks to an origin
+// For example, if there is a switch targeting us, we can't do it - we can't
+// remove the value from other targets
+struct ProblemFinder : public ControlFlowWalker<ProblemFinder> {
+  Name origin;
+  bool foundProblem = false;
+  // count br_ifs, and dropped br_ifs. if they don't match, then a br_if flow
+  // value is used, and we can't drop it
+  Index brIfs = 0;
+  Index droppedBrIfs = 0;
+  PassOptions& passOptions;
+
+  ProblemFinder(PassOptions& passOptions) : passOptions(passOptions) {}
+
+  void visitBreak(Break* curr) {
+    if (curr->name == origin) {
+      if (curr->condition) {
+        brIfs++;
+      }
+      // if the value has side effects, we can't remove it
+      if (EffectAnalyzer(passOptions, getModule()->features, curr->value)
+            .hasSideEffects()) {
+        foundProblem = true;
+      }
+    }
+  }
+
+  void visitDrop(Drop* curr) {
+    if (auto* br = curr->value->dynCast<Break>()) {
+      if (br->name == origin && br->condition) {
+        droppedBrIfs++;
+      }
+    }
+  }
+
+  void visitSwitch(Switch* curr) {
+    if (curr->default_ == origin) {
+      foundProblem = true;
+      return;
+    }
+    for (auto& target : curr->targets) {
+      if (target == origin) {
+        foundProblem = true;
+        return;
+      }
+    }
+  }
+
+  void visitBrOnExn(BrOnExn* curr) {
+    // We should not take exnref value out of br_on_exn
+    foundProblem = true;
+  }
+
+  bool found() {
+    assert(brIfs >= droppedBrIfs);
+    return foundProblem || brIfs > droppedBrIfs;
+  }
+};
+
+// Drops values from breaks to an origin.
+// While doing so it can create new blocks, so optimize blocks as well.
+struct BreakValueDropper : public ControlFlowWalker<BreakValueDropper> {
+  Name origin;
+  PassOptions& passOptions;
+  BranchUtils::BranchSeekerCache& branchInfo;
+
+  BreakValueDropper(PassOptions& passOptions,
+                    BranchUtils::BranchSeekerCache& branchInfo)
+    : passOptions(passOptions), branchInfo(branchInfo) {}
+
+  void visitBlock(Block* curr);
+
+  void visitBreak(Break* curr) {
+    if (curr->value && curr->name == origin) {
+      Builder builder(*getModule());
+      auto* value = curr->value;
+      if (value->type == Type::unreachable) {
+        // the break isn't even reached
+        replaceCurrent(value);
+        return;
+      }
+      curr->value = nullptr;
+      curr->finalize();
+      replaceCurrent(builder.makeSequence(builder.makeDrop(value), curr));
+    }
+  }
+
+  void visitDrop(Drop* curr) {
+    // if we dropped a br_if whose value we removed, then we are now dropping a
+    // (block (drop value) (br_if)) with type none, which does not need a drop
+    // likewise, unreachable does not need to be dropped, so we just leave drops
+    // of concrete values
+    if (!curr->value->type.isConcrete()) {
+      replaceCurrent(curr->value);
+    }
+  }
+};
+
+static bool hasUnreachableChild(Block* block) {
+  for (auto* test : block->list) {
+    if (test->type == Type::unreachable) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Checks for code after an unreachable element.
+static bool hasDeadCode(Block* block) {
+  auto& list = block->list;
+  auto size = list.size();
+  for (size_t i = 1; i < size; i++) {
+    if (list[i - 1]->type == Type::unreachable) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// core block optimizer routine
+static void optimizeBlock(Block* curr,
+                          Module* module,
+                          PassOptions& passOptions,
+                          BranchUtils::BranchSeekerCache& branchInfo) {
+  auto& list = curr->list;
+  // Main merging loop.
+  bool more = true;
+  bool changed = false;
+  while (more) {
+    more = false;
+    for (size_t i = 0; i < list.size(); i++) {
+      auto* child = list[i];
+      // The child block, if there is one.
+      Block* childBlock = child->dynCast<Block>();
+      // If we are merging an inner block of a loop, then we must not
+      // merge things before and including the name of the loop, moving
+      // those out would break things.
+      Loop* loop = nullptr;
+      // To to handle a non-block child.
+      if (!childBlock) {
+        // if we have a child that is (drop (block ..)) then we can move the
+        // drop into the block, and remove br values. this allows more merging,
+        if (auto* drop = list[i]->dynCast<Drop>()) {
+          childBlock = drop->value->dynCast<Block>();
+          if (childBlock) {
+            if (hasUnreachableChild(childBlock)) {
+              // don't move around unreachable code, as it can change types
+              // dce should have been run anyhow
+              continue;
+            }
+            if (childBlock->name.is()) {
+              Expression* expression = childBlock;
+              // check if it's ok to remove the value from all breaks to us
+              ProblemFinder finder(passOptions);
+              finder.setModule(module);
+              finder.origin = childBlock->name;
+              finder.walk(expression);
+              if (finder.found()) {
+                childBlock = nullptr;
+              } else {
+                // fix up breaks
+                BreakValueDropper fixer(passOptions, branchInfo);
+                fixer.origin = childBlock->name;
+                fixer.setModule(module);
+                fixer.walk(expression);
+              }
+            }
+            if (childBlock) {
+              // we can do it!
+              // reuse the drop, if we still need it
+              auto* last = childBlock->list.back();
+              if (last->type.isConcrete()) {
+                drop->value = last;
+                drop->finalize();
+                childBlock->list.back() = drop;
+              }
+              childBlock->finalize();
+              child = list[i] = childBlock;
+              more = true;
+              changed = true;
+            }
+          }
+        } else if ((loop = list[i]->dynCast<Loop>())) {
+          // We can merge a loop's "tail" - if the body is a block and has
+          // instructions at the end that do not branch back.
+          childBlock = loop->body->dynCast<Block>();
+          // TODO: handle (loop (loop - the bodies of loops may not be blocks
+        }
+      }
+      // If no block, we can't do anything.
+      if (!childBlock) {
+        continue;
+      }
+      auto& childList = childBlock->list;
+      auto childSize = childList.size();
+      if (childSize == 0) {
+        continue;
+      }
+      // If the child has items after an unreachable, ignore it - dce should
+      // have been run, and we prefer to not handle the complexity here.
+      if (hasDeadCode(childBlock)) {
+        continue;
+      }
+      // In some cases we can remove only the head or the tail of the block,
+      // and must keep some things in the child block.
+      Index keepStart = childSize;
+      Index keepEnd = 0;
+      // For a block with a name, we may only be able to remove a head, up
+      // to the first item that branches to the block.
+      if (childBlock->name.is()) {
+        // If it has a concrete value, then breaks may be sending it a value,
+        // and we'd need to handle that. TODO
+        if (childBlock->type.isConcrete()) {
+          continue;
+        }
+        auto childName = childBlock->name;
+        for (size_t j = 0; j < childSize; j++) {
+          auto* item = childList[j];
+          if (branchInfo.hasBranch(item, childName)) {
+            // We can't remove this from the child.
+            keepStart = j;
+            keepEnd = childSize;
+            break;
+          }
+        }
+      }
+      // For a loop, we may only be able to remove a tail
+      if (loop) {
+        auto childName = loop->name;
+        for (auto j = int(childSize - 1); j >= 0; j--) {
+          auto* item = childList[j];
+          if (BranchUtils::BranchSeeker::has(item, childName)) {
+            // We can't remove this from the child.
+            keepStart = 0;
+            keepEnd = std::max(Index(j + 1), keepEnd);
+            break;
+          }
+        }
+        // If we can only do part of the block, and if the block has a flowing
+        // value, we would need special handling for that - not worth it,
+        // probably TODO
+        // FIXME is this not handled by the drop later down?
+        if (keepEnd < childSize && childList.back()->type.isConcrete()) {
+          continue;
+        }
+      }
+      // Maybe there's nothing to do, if we must keep it all in the
+      // child anyhow.
+      if (keepStart == 0 && keepEnd == childSize) {
+        continue;
+      }
+      // There is something to do!
+      bool keepingPart = keepStart < keepEnd;
+      // Create a new merged list, and fill in the code before the
+      // child block we are merging in. TODO better efficiency
+      ExpressionList merged(module->allocator);
+      for (size_t j = 0; j < i; j++) {
+        merged.push_back(list[j]);
+      }
+      // Add the head of the block - the things at the start we do
+      // not need to keep.
+      for (Index j = 0; j < keepStart; j++) {
+        merged.push_back(childList[j]);
+      }
+      // If we can't merge it all, keep and filter the child.
+      if (keepingPart) {
+        merged.push_back(child);
+        // Filter the child.
+        ExpressionList filtered(module->allocator);
+        for (Index j = keepStart; j < keepEnd; j++) {
+          filtered.push_back(childList[j]);
+        }
+        // Add the tail of the block - the things at the end we do
+        // not need to keep.
+        for (Index j = keepEnd; j < childSize; j++) {
+          merged.push_back(childList[j]);
+        }
+        // Update the child.
+        childList.swap(filtered);
+        // We may have removed unreachable items.
+        childBlock->finalize();
+        if (loop) {
+          loop->finalize();
+        }
+        // Note that we modify the child block here, which invalidates info
+        // in branchInfo. However, as we have scanned the parent, we have
+        // already forgotten the child's info, so there is nothing to do here
+        // for the child.
+        // (We also don't need to do anything for the parent - we move code
+        // from a child into the parent, but that doesn't change the total
+        // branches in the parent.)
+      }
+      // Add the rest of the parent block after the child.
+      for (size_t j = i + 1; j < list.size(); j++) {
+        merged.push_back(list[j]);
+      }
+      // if we merged a concrete element in the middle, drop it
+      if (!merged.empty()) {
+        auto* last = merged.back();
+        for (auto*& item : merged) {
+          if (item != last && item->type.isConcrete()) {
+            Builder builder(*module);
+            item = builder.makeDrop(item);
+          }
+        }
+      }
+      list.swap(merged);
+      more = true;
+      changed = true;
+      break;
+    }
+  }
+  if (changed) {
+    curr->finalize(curr->type);
+  }
+}
+
+void BreakValueDropper::visitBlock(Block* curr) {
+  optimizeBlock(curr, getModule(), passOptions, branchInfo);
+}
+
+struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new MergeBlocks; }
+
+  BranchUtils::BranchSeekerCache branchInfo;
+
+  void visitBlock(Block* curr) {
+    optimizeBlock(curr, getModule(), getPassOptions(), branchInfo);
+  }
+
+  // given
+  // (curr
+  //  (block=child
+  //   (..more..)
+  //   (back)
+  //  )
+  //  (..other..children..)
+  // )
+  // if child is a block, we can move this around to
+  // (block
+  //  (..more..)
+  //  (curr
+  //   (back)
+  //   (..other..children..)
+  //  )
+  // )
+  // at which point the block is on the outside and potentially mergeable with
+  // an outer block
+  Block* optimize(Expression* curr,
+                  Expression*& child,
+                  Block* outer = nullptr,
+                  Expression** dependency1 = nullptr,
+                  Expression** dependency2 = nullptr) {
+    if (!child) {
+      return outer;
+    }
+    FeatureSet features = getModule()->features;
+    if ((dependency1 && *dependency1) || (dependency2 && *dependency2)) {
+      // there are dependencies, things we must be reordered through. make sure
+      // no problems there
+      EffectAnalyzer childEffects(getPassOptions(), features, child);
+      if (dependency1 && *dependency1 &&
+          EffectAnalyzer(getPassOptions(), features, *dependency1)
+            .invalidates(childEffects)) {
+        return outer;
+      }
+      if (dependency2 && *dependency2 &&
+          EffectAnalyzer(getPassOptions(), features, *dependency2)
+            .invalidates(childEffects)) {
+        return outer;
+      }
+    }
+    if (auto* block = child->dynCast<Block>()) {
+      if (!block->name.is() && block->list.size() >= 2) {
+        // if we move around unreachable code, type changes could occur. avoid
+        // that, as anyhow it means we should have run dce before getting here
+        if (curr->type == Type::none && hasUnreachableChild(block)) {
+          // moving the block to the outside would replace a none with an
+          // unreachable
+          return outer;
+        }
+        auto* back = block->list.back();
+        if (back->type == Type::unreachable) {
+          // curr is not reachable, dce could remove it; don't try anything
+          // fancy here
+          return outer;
+        }
+        // we are going to replace the block with the final element, so they
+        // should be identically typed
+        if (block->type != back->type) {
+          return outer;
+        }
+        child = back;
+        if (outer == nullptr) {
+          // reuse the block, move it out
+          block->list.back() = curr;
+          // we want the block outside to have the same type as curr had
+          block->finalize(curr->type);
+          replaceCurrent(block);
+          return block;
+        } else {
+          // append to an existing outer block
+          assert(outer->list.back() == curr);
+          outer->list.pop_back();
+          for (Index i = 0; i < block->list.size() - 1; i++) {
+            outer->list.push_back(block->list[i]);
+          }
+          outer->list.push_back(curr);
+        }
+      }
+    }
+    return outer;
+  }
+
+  void visitUnary(Unary* curr) { optimize(curr, curr->value); }
+  void visitLocalSet(LocalSet* curr) { optimize(curr, curr->value); }
+  void visitLoad(Load* curr) { optimize(curr, curr->ptr); }
+  void visitReturn(Return* curr) { optimize(curr, curr->value); }
+
+  void visitBinary(Binary* curr) {
+    optimize(curr, curr->right, optimize(curr, curr->left), &curr->left);
+  }
+  void visitStore(Store* curr) {
+    optimize(curr, curr->value, optimize(curr, curr->ptr), &curr->ptr);
+  }
+  void visitAtomicRMW(AtomicRMW* curr) {
+    optimize(curr, curr->value, optimize(curr, curr->ptr), &curr->ptr);
+  }
+  void optimizeTernary(Expression* curr,
+                       Expression*& first,
+                       Expression*& second,
+                       Expression*& third) {
+    // TODO: for now, just stop when we see any side effect. instead, we could
+    //       check effects carefully for reordering
+    FeatureSet features = getModule()->features;
+    Block* outer = nullptr;
+    if (EffectAnalyzer(getPassOptions(), features, first).hasSideEffects()) {
+      return;
+    }
+    outer = optimize(curr, first, outer);
+    if (EffectAnalyzer(getPassOptions(), features, second).hasSideEffects()) {
+      return;
+    }
+    outer = optimize(curr, second, outer);
+    if (EffectAnalyzer(getPassOptions(), features, third).hasSideEffects()) {
+      return;
+    }
+    optimize(curr, third, outer);
+  }
+  void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+    optimizeTernary(curr, curr->ptr, curr->expected, curr->replacement);
+  }
+
+  void visitSelect(Select* curr) {
+    optimizeTernary(curr, curr->ifTrue, curr->ifFalse, curr->condition);
+  }
+
+  void visitDrop(Drop* curr) { optimize(curr, curr->value); }
+
+  void visitBreak(Break* curr) {
+    optimize(curr, curr->condition, optimize(curr, curr->value), &curr->value);
+  }
+
+  void visitSwitch(Switch* curr) {
+    optimize(curr, curr->condition, optimize(curr, curr->value), &curr->value);
+  }
+
+  template<typename T> void handleCall(T* curr) {
+    Block* outer = nullptr;
+    for (Index i = 0; i < curr->operands.size(); i++) {
+      if (EffectAnalyzer(
+            getPassOptions(), getModule()->features, curr->operands[i])
+            .hasSideEffects()) {
+        return;
+      }
+      outer = optimize(curr, curr->operands[i], outer);
+    }
+  }
+
+  void visitCall(Call* curr) { handleCall(curr); }
+
+  void visitCallIndirect(CallIndirect* curr) {
+    FeatureSet features = getModule()->features;
+    Block* outer = nullptr;
+    for (Index i = 0; i < curr->operands.size(); i++) {
+      if (EffectAnalyzer(getPassOptions(), features, curr->operands[i])
+            .hasSideEffects()) {
+        return;
+      }
+      outer = optimize(curr, curr->operands[i], outer);
+    }
+    if (EffectAnalyzer(getPassOptions(), features, curr->target)
+          .hasSideEffects()) {
+      return;
+    }
+    optimize(curr, curr->target, outer);
+  }
+
+  void visitThrow(Throw* curr) {
+    Block* outer = nullptr;
+    for (Index i = 0; i < curr->operands.size(); i++) {
+      if (EffectAnalyzer(
+            getPassOptions(), getModule()->features, curr->operands[i])
+            .hasSideEffects()) {
+        return;
+      }
+      outer = optimize(curr, curr->operands[i], outer);
+    }
+  }
+
+  void visitRethrow(Rethrow* curr) { optimize(curr, curr->exnref); }
+
+  void visitBrOnExn(BrOnExn* curr) { optimize(curr, curr->exnref); }
+};
+
+Pass* createMergeBlocksPass() { return new MergeBlocks(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/MergeLocals.cpp b/binaryen/src/passes/MergeLocals.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/MergeLocals.cpp
@@ -0,0 +1,236 @@
+/*
+ * 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.
+ */
+
+//
+// Merges locals when it is beneficial to do so.
+//
+// An obvious case is when locals are copied. In that case, two locals have the
+// same value in a range, and we can pick which of the two to use. For
+// example, in
+//
+//  (if (result i32)
+//   (local.tee $x
+//    (local.get $y)
+//   )
+//   (i32.const 100)
+//   (local.get $x)
+//  )
+//
+// If that assignment of $y is never used again, everything is fine. But if
+// if is, then the live range of $y does not end in that get, and will
+// necessarily overlap with that of $x - making them appear to interfere
+// with each other in coalesce-locals, even though the value is identical.
+//
+// To fix that, we replace uses of $y with uses of $x. This extends $x's
+// live range and shrinks $y's live range. This tradeoff is not always good,
+// but $x and $y definitely overlap already, so trying to shrink the overlap
+// makes sense - if we remove the overlap entirely, we may be able to let
+// $x and $y be coalesced later.
+//
+// If we can remove only some of $y's uses, then we are definitely not
+// removing the overlap, and they do conflict. In that case, it's not clear
+// if this is beneficial or not, and we don't do it for now
+// TODO: investigate more
+//
+
+#include <ir/local-graph.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+namespace wasm {
+
+struct MergeLocals
+  : public WalkerPass<
+      PostWalker<MergeLocals, UnifiedExpressionVisitor<MergeLocals>>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new MergeLocals(); }
+
+  void doWalkFunction(Function* func) {
+    // first, instrument the graph by modifying each copy
+    //   (local.set $x
+    //    (local.get $y)
+    //   )
+    // to
+    //   (local.set $x
+    //    (local.tee $y
+    //     (local.get $y)
+    //    )
+    //   )
+    // That is, we add a trivial assign of $y. This ensures we
+    // have a new assignment of $y at the location of the copy,
+    // which makes it easy for us to see if the value if $y
+    // is still used after that point
+    super::doWalkFunction(func);
+
+    // optimize the copies, merging when we can, and removing
+    // the trivial assigns we added temporarily
+    optimizeCopies();
+  }
+
+  std::vector<LocalSet*> copies;
+
+  void visitLocalSet(LocalSet* curr) {
+    if (auto* get = curr->value->dynCast<LocalGet>()) {
+      if (get->index != curr->index) {
+        Builder builder(*getModule());
+        auto* trivial = builder.makeLocalTee(get->index, get, get->type);
+        curr->value = trivial;
+        copies.push_back(curr);
+      }
+    }
+  }
+
+  void optimizeCopies() {
+    if (copies.empty()) {
+      return;
+    }
+    // compute all dependencies
+    auto* func = getFunction();
+    LocalGraph preGraph(func);
+    preGraph.computeInfluences();
+    // optimize each copy
+    std::unordered_map<LocalSet*, LocalSet*> optimizedToCopy,
+      optimizedToTrivial;
+    for (auto* copy : copies) {
+      auto* trivial = copy->value->cast<LocalSet>();
+      bool canOptimizeToCopy = false;
+      auto& trivialInfluences = preGraph.setInfluences[trivial];
+      if (!trivialInfluences.empty()) {
+        canOptimizeToCopy = true;
+        for (auto* influencedGet : trivialInfluences) {
+          // this get uses the trivial write, so it uses the value in the copy.
+          // however, it may depend on other writes too, if there is a
+          // merge/phi, and in that case we can't do anything
+          assert(influencedGet->index == trivial->index);
+          if (preGraph.getSetses[influencedGet].size() == 1) {
+            // this is ok
+            assert(*preGraph.getSetses[influencedGet].begin() == trivial);
+            // If local types are different (when one is a subtype of the
+            // other), don't optimize
+            if (func->getLocalType(copy->index) != influencedGet->type) {
+              canOptimizeToCopy = false;
+            }
+          } else {
+            canOptimizeToCopy = false;
+            break;
+          }
+        }
+      }
+      if (canOptimizeToCopy) {
+        // worth it for this copy, do it
+        for (auto* influencedGet : trivialInfluences) {
+          influencedGet->index = copy->index;
+        }
+        optimizedToCopy[copy] = trivial;
+      } else {
+        // alternatively, we can try to remove the conflict in the opposite way:
+        // given
+        //   (local.set $x
+        //    (local.get $y)
+        //   )
+        // we can look for uses of $x that could instead be uses of $y. this
+        // extends $y's live range, but if it removes the conflict between $x
+        // and $y, it may be worth it
+
+        // if the trivial set we added has influences, it means $y lives on
+        if (!trivialInfluences.empty()) {
+          auto& copyInfluences = preGraph.setInfluences[copy];
+          if (!copyInfluences.empty()) {
+            bool canOptimizeToTrivial = true;
+            for (auto* influencedGet : copyInfluences) {
+              // as above, avoid merges/phis
+              assert(influencedGet->index == copy->index);
+              if (preGraph.getSetses[influencedGet].size() == 1) {
+                // this is ok
+                assert(*preGraph.getSetses[influencedGet].begin() == copy);
+                // If local types are different (when one is a subtype of the
+                // other), don't optimize
+                if (func->getLocalType(trivial->index) != influencedGet->type) {
+                  canOptimizeToTrivial = false;
+                }
+              } else {
+                canOptimizeToTrivial = false;
+                break;
+              }
+            }
+            if (canOptimizeToTrivial) {
+              // worth it for this copy, do it
+              for (auto* influencedGet : copyInfluences) {
+                influencedGet->index = trivial->index;
+              }
+              optimizedToTrivial[copy] = trivial;
+              // note that we don't
+            }
+          }
+        }
+      }
+    }
+    if (!optimizedToCopy.empty() || !optimizedToTrivial.empty()) {
+      // finally, we need to verify that the changes work properly, that is,
+      // they use the value from the right place (and are not affected by
+      // another set of the index we changed to).
+      // if one does not work, we need to undo all its siblings (don't extend
+      // the live range unless we are definitely removing a conflict, same
+      // logic as before).
+      LocalGraph postGraph(func);
+      postGraph.computeInfluences();
+      for (auto& pair : optimizedToCopy) {
+        auto* copy = pair.first;
+        auto* trivial = pair.second;
+        auto& trivialInfluences = preGraph.setInfluences[trivial];
+        for (auto* influencedGet : trivialInfluences) {
+          // verify the set
+          auto& sets = postGraph.getSetses[influencedGet];
+          if (sets.size() != 1 || *sets.begin() != copy) {
+            // not good, undo all the changes for this copy
+            for (auto* undo : trivialInfluences) {
+              undo->index = trivial->index;
+            }
+            break;
+          }
+        }
+      }
+      for (auto& pair : optimizedToTrivial) {
+        auto* copy = pair.first;
+        auto* trivial = pair.second;
+        auto& copyInfluences = preGraph.setInfluences[copy];
+        for (auto* influencedGet : copyInfluences) {
+          // verify the set
+          auto& sets = postGraph.getSetses[influencedGet];
+          if (sets.size() != 1 || *sets.begin() != trivial) {
+            // not good, undo all the changes for this copy
+            for (auto* undo : copyInfluences) {
+              undo->index = copy->index;
+            }
+            break;
+          }
+        }
+        // if this change was ok, we can probably remove the copy itself,
+        // but we leave that for other passes
+      }
+    }
+    // remove the trivial sets
+    for (auto* copy : copies) {
+      copy->value = copy->value->cast<LocalSet>()->value;
+    }
+  }
+};
+
+Pass* createMergeLocalsPass() { return new MergeLocals(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/Metrics.cpp b/binaryen/src/passes/Metrics.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/Metrics.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <iomanip>
+#include <ir/module-utils.h>
+#include <pass.h>
+#include <support/colors.h>
+#include <wasm-binary.h>
+#include <wasm.h>
+
+using namespace std;
+
+namespace wasm {
+
+typedef map<const char*, int> Counts;
+
+static Counts lastCounts;
+
+// Prints metrics between optimization passes.
+struct Metrics
+  : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<Metrics>>> {
+  bool modifiesBinaryenIR() override { return false; }
+
+  bool byFunction;
+
+  Counts counts;
+
+  Metrics(bool byFunction) : byFunction(byFunction) {}
+
+  void visitExpression(Expression* curr) {
+    auto name = getExpressionName(curr);
+    counts[name]++;
+  }
+
+  void doWalkModule(Module* module) {
+    ImportInfo imports(*module);
+
+    // global things
+    for (auto& curr : module->exports) {
+      visitExport(curr.get());
+    }
+    ModuleUtils::iterDefinedGlobals(*module,
+                                    [&](Global* curr) { walkGlobal(curr); });
+    walkTable(&module->table);
+    walkMemory(&module->memory);
+
+    // add imports / funcs / globals/ exports
+    counts["[imports]"] = imports.getNumImports();
+    counts["[funcs]"] = imports.getNumDefinedFunctions();
+    counts["[globals]"] = imports.getNumDefinedGlobals();
+    counts["[events]"] = imports.getNumDefinedEvents();
+    counts["[exports]"] = module->exports.size();
+    // add memory and table
+    if (module->memory.exists) {
+      Index size = 0;
+      for (auto& segment : module->memory.segments) {
+        size += segment.data.size();
+      }
+      counts["[memory-data]"] = size;
+    }
+    if (module->table.exists) {
+      Index size = 0;
+      for (auto& segment : module->table.segments) {
+        size += segment.data.size();
+      }
+      counts["[table-data]"] = size;
+    }
+
+    if (byFunction) {
+      // print global
+      printCounts("global");
+      // compute binary info, so we know function sizes
+      BufferWithRandomAccess buffer;
+      WasmBinaryWriter writer(module, buffer);
+      writer.write();
+      // print for each function
+      Index binaryIndex = 0;
+      ModuleUtils::iterDefinedFunctions(*module, [&](Function* func) {
+        counts.clear();
+        walkFunction(func);
+        counts["[vars]"] = func->getNumVars();
+        counts["[binary-bytes]"] =
+          writer.tableOfContents.functionBodies[binaryIndex++].size;
+        printCounts(std::string("func: ") + func->name.str);
+      });
+      // print for each export how much code size is due to it, i.e.,
+      // how much the module could shrink without it.
+      auto sizeAfterGlobalCleanup = [](Module* module) {
+        PassRunner runner(module,
+                          PassOptions::getWithDefaultOptimizationOptions());
+        runner.setIsNested(true);
+        runner.addDefaultGlobalOptimizationPostPasses(); // remove stuff
+        runner.run();
+        BufferWithRandomAccess buffer;
+        WasmBinaryWriter writer(module, buffer);
+        writer.write();
+        return buffer.size();
+      };
+      size_t baseline;
+      {
+        Module test;
+        ModuleUtils::copyModule(*module, test);
+        baseline = sizeAfterGlobalCleanup(&test);
+      }
+      for (auto& exp : module->exports) {
+        // create a test module where we remove the export and then see how much
+        // can be removed thanks to that
+        Module test;
+        ModuleUtils::copyModule(*module, test);
+        test.removeExport(exp->name);
+        counts.clear();
+        counts["[removable-bytes-without-it]"] =
+          baseline - sizeAfterGlobalCleanup(&test);
+        printCounts(std::string("export: ") + exp->name.str + " (" +
+                    exp->value.str + ')');
+      }
+      // check how much size depends on the start method
+      if (!module->start.isNull()) {
+        Module test;
+        ModuleUtils::copyModule(*module, test);
+        test.start = Name();
+        counts.clear();
+        counts["[removable-bytes-without-it]"] =
+          baseline - sizeAfterGlobalCleanup(&test);
+        printCounts(std::string("start: ") + module->start.str);
+      }
+      // can't compare detailed info between passes yet
+      lastCounts.clear();
+    } else {
+      // add function info
+      size_t vars = 0;
+      ModuleUtils::iterDefinedFunctions(*module, [&](Function* func) {
+        walkFunction(func);
+        vars += func->getNumVars();
+      });
+      counts["[vars]"] = vars;
+      // print
+      printCounts("total");
+      // compare to next time
+      lastCounts = counts;
+    }
+  }
+
+  void printCounts(std::string title) {
+    ostream& o = cout;
+    vector<const char*> keys;
+    // add total
+    int total = 0;
+    for (auto i : counts) {
+      keys.push_back(i.first);
+      // total is of all the normal stuff, not the special [things]
+      if (i.first[0] != '[') {
+        total += i.second;
+      }
+    }
+    keys.push_back("[total]");
+    counts["[total]"] = total;
+    // sort
+    sort(keys.begin(), keys.end(), [](const char* a, const char* b) -> bool {
+      return strcmp(b, a) > 0;
+    });
+    o << title << "\n";
+    for (auto* key : keys) {
+      auto value = counts[key];
+      if (value == 0 && key[0] != '[') {
+        continue;
+      }
+      o << " " << left << setw(15) << key << ": " << setw(8) << value;
+      if (lastCounts.count(key)) {
+        int before = lastCounts[key];
+        int after = value;
+        if (after - before) {
+          if (after > before) {
+            Colors::red(o);
+          } else {
+            Colors::green(o);
+          }
+          o << right << setw(8);
+          o << showpos << after - before << noshowpos;
+          Colors::normal(o);
+        }
+      }
+      o << "\n";
+    }
+  }
+};
+
+Pass* createMetricsPass() { return new Metrics(false); }
+
+Pass* createFunctionMetricsPass() { return new Metrics(true); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/MinifyImportsAndExports.cpp b/binaryen/src/passes/MinifyImportsAndExports.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/MinifyImportsAndExports.cpp
@@ -0,0 +1,219 @@
+/*
+ * 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.
+ */
+
+//
+// Minifies import and export names, renaming them to short versions,
+// and prints out a mapping to the new short versions. That mapping
+// can then be used to minify the JS calling the wasm, together enabling
+// minification of the identifiers on the JS/wasm boundary.
+//
+// For example, this may minify
+//   (import "env" "longname" (func $internal))
+// to
+//   (import "env" "a" (func $internal))
+// "a" is the minified name. If we also minify module names, then the
+// result could be
+//   (import "a" "a" (func $internal))
+//
+// TODO: check if we can minify names to the empty string "", which is even
+//       shorter than one character.
+
+#include <map>
+#include <string>
+#include <unordered_set>
+
+#include <asmjs/shared-constants.h>
+#include <ir/import-utils.h>
+#include <ir/module-utils.h>
+#include <pass.h>
+#include <shared-constants.h>
+#include <wasm.h>
+
+namespace wasm {
+
+struct MinifyImportsAndExports : public Pass {
+  bool minifyExports, minifyModules;
+
+public:
+  explicit MinifyImportsAndExports(bool minifyExports, bool minifyModules)
+    : minifyExports(minifyExports), minifyModules(minifyModules) {}
+
+private:
+  // Generates minified names that are valid in JS.
+  // Names are computed lazily.
+  class MinifiedNames {
+  public:
+    MinifiedNames() {
+      // Reserved words in JS up to size 4 - size 5 and above would mean we use
+      // an astronomical number of symbols, which is not realistic anyhow.
+      reserved.insert("do");
+      reserved.insert("if");
+      reserved.insert("in");
+      reserved.insert("for");
+      reserved.insert("new");
+      reserved.insert("try");
+      reserved.insert("var");
+      reserved.insert("env");
+      reserved.insert("let");
+      reserved.insert("case");
+      reserved.insert("else");
+      reserved.insert("enum");
+      reserved.insert("void");
+      reserved.insert("this");
+      reserved.insert("with");
+
+      validInitialChars =
+        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
+      validLaterChars = validInitialChars + "0123456789";
+
+      minifiedState.push_back(0);
+    }
+
+    // Get the n-th minified name.
+    std::string getName(size_t n) {
+      ensure(n + 1);
+      return names[n];
+    }
+
+  private:
+    // Reserved words we must not emit.
+    std::unordered_set<std::string> reserved;
+
+    // Possible initial letters.
+    std::string validInitialChars;
+
+    // Possible later letters.
+    std::string validLaterChars;
+
+    // The minified names we computed so far.
+    std::vector<std::string> names;
+
+    // Helper state for progressively computing more minified names -
+    // a stack of the current index.
+    std::vector<size_t> minifiedState;
+
+    // Make sure we have at least n minified names.
+    void ensure(size_t n) {
+      while (names.size() < n) {
+        // Generate the current name.
+        std::string name;
+        auto index = minifiedState[0];
+        assert(index < validInitialChars.size());
+        name += validInitialChars[index];
+        for (size_t i = 1; i < minifiedState.size(); i++) {
+          auto index = minifiedState[i];
+          assert(index < validLaterChars.size());
+          name += validLaterChars[index];
+        }
+        if (reserved.count(name) == 0) {
+          names.push_back(name);
+        }
+        // Increment the state.
+        size_t i = 0;
+        while (1) {
+          minifiedState[i]++;
+          if (minifiedState[i] <
+              (i == 0 ? validInitialChars : validLaterChars).size()) {
+            break;
+          }
+          // Overflow.
+          minifiedState[i] = 0;
+          i++;
+          if (i == minifiedState.size()) {
+            // will become 0 after increment in next loop head
+            minifiedState.push_back(-1);
+          }
+        }
+      }
+    }
+  };
+
+  void run(PassRunner* runner, Module* module) override {
+    // Minify the imported names.
+    MinifiedNames names;
+    size_t soFar = 0;
+    std::map<Name, Name> oldToNew;
+    std::map<Name, Name> newToOld;
+    auto process = [&](Name& name) {
+      auto iter = oldToNew.find(name);
+      if (iter == oldToNew.end()) {
+        auto newName = names.getName(soFar++);
+        oldToNew[name] = newName;
+        newToOld[newName] = name;
+        name = newName;
+      } else {
+        name = iter->second;
+      }
+    };
+    ModuleUtils::iterImports(*module, [&](Importable* curr) {
+      // Minify all import base names if we are importing modules (which means
+      // we will minify all modules names, so we are not being careful).
+      // Otherwise, assume we just want to minify "normal" imports like env
+      // and wasi, but not special things like asm2wasm or custom user things.
+      if (minifyModules || curr->module == ENV ||
+          curr->module.startsWith("wasi_")) {
+        process(curr->base);
+      }
+    });
+
+    if (minifyExports) {
+      // Minify the exported names.
+      for (auto& curr : module->exports) {
+        process(curr->name);
+      }
+    }
+    module->updateMaps();
+    // Emit the mapping.
+    for (auto& pair : newToOld) {
+      std::cout << pair.second.str << " => " << pair.first.str << '\n';
+    }
+
+    if (minifyModules) {
+      doMinifyModules(module);
+    }
+  }
+
+  const Name SINGLETON_MODULE_NAME = "a";
+
+  void doMinifyModules(Module* module) {
+    // Minify the module name itself, and also merge all the modules into
+    // one. Assert against overlapping names.
+#ifndef NDEBUG
+    std::set<Name> seenImports;
+#endif
+    ModuleUtils::iterImports(*module, [&](Importable* curr) {
+      curr->module = SINGLETON_MODULE_NAME;
+#ifndef NDEBUG
+      assert(seenImports.count(curr->base) == 0);
+      seenImports.insert(curr->base);
+#endif
+    });
+  }
+};
+
+Pass* createMinifyImportsPass() {
+  return new MinifyImportsAndExports(false, false);
+}
+
+Pass* createMinifyImportsAndExportsPass() {
+  return new MinifyImportsAndExports(true, false);
+}
+
+Pass* createMinifyImportsAndExportsAndModulesPass() {
+  return new MinifyImportsAndExports(true, true);
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/NameList.cpp b/binaryen/src/passes/NameList.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/NameList.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+//
+// Write out the name list of the module, similar to `nm`.
+//
+
+#include "ir/module-utils.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct NameList : public Pass {
+  void run(PassRunner* runner, Module* module) override {
+    ModuleUtils::iterDefinedFunctions(*module, [&](Function* func) {
+      std::cout << "    " << func->name << " : "
+                << Measurer::measure(func->body) << '\n';
+    });
+  }
+};
+
+Pass* createNameListPass() { return new NameList(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/NoExitRuntime.cpp b/binaryen/src/passes/NoExitRuntime.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/NoExitRuntime.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+//
+// Assumes the program will never exit the runtime (as in the emscripten
+// NO_EXIT_RUNTIME option). That means that atexit()s do not need to be
+// run.
+//
+
+#include <asmjs/shared-constants.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+using namespace std;
+
+namespace wasm {
+
+struct NoExitRuntime : public WalkerPass<PostWalker<NoExitRuntime>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new NoExitRuntime; }
+
+  // Remove all possible manifestations of atexit, across asm2wasm and llvm wasm
+  // backend.
+  std::array<Name, 4> ATEXIT_NAMES = {
+    {"___cxa_atexit", "__cxa_atexit", "_atexit", "atexit"}};
+
+  void visitCall(Call* curr) {
+    auto* import = getModule()->getFunctionOrNull(curr->target);
+    if (!import || !import->imported() || import->module != ENV) {
+      return;
+    }
+    for (auto name : ATEXIT_NAMES) {
+      if (name == import->base) {
+        // Remove the call, and drop the arguments (which may have side
+        // effects); let other passes clean that up more.
+        Builder builder(*getModule());
+        std::vector<Expression*> args;
+        for (auto* operand : curr->operands) {
+          args.push_back(builder.makeDrop(operand));
+        }
+        // Ensure the block has the right type using the last arg.
+        args.push_back(builder.replaceWithIdenticalType(curr));
+        replaceCurrent(builder.makeBlock(args));
+        break;
+      }
+    }
+  }
+};
+
+Pass* createNoExitRuntimePass() { return new NoExitRuntime(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/OptimizeAddedConstants.cpp b/binaryen/src/passes/OptimizeAddedConstants.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/OptimizeAddedConstants.cpp
@@ -0,0 +1,410 @@
+/*
+ * Copyright 2019 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.
+ */
+
+//
+// Optimize added constants into load/store offsets. This requires the
+// assumption that low memory is unused, so that we can replace an add (which
+// might wrap) with a load/store offset (which does not).
+//
+// The propagate option also propagates offsets across set/get local pairs.
+//
+// Optimizing constants into load/store offsets is almost always
+// beneficial for speed, as VMs can optimize these operations better.
+// If a LocalGraph is provided, this can also propagate values along get/set
+// pairs. In such a case, we may increase code size slightly or reduce
+// compressibility (e.g., replace (load (get $x)) with (load offset=Z (get $y)),
+// where Z is big enough to not fit in a single byte), but this is good for
+// speed, and may lead to code size reductions elsewhere by using fewer locals.
+//
+
+#include <ir/local-graph.h>
+#include <ir/local-utils.h>
+#include <ir/parents.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+namespace wasm {
+
+template<typename P, typename T> class MemoryAccessOptimizer {
+public:
+  MemoryAccessOptimizer(P* parent,
+                        T* curr,
+                        Module* module,
+                        LocalGraph* localGraph)
+    : parent(parent), curr(curr), module(module), localGraph(localGraph) {}
+
+  // Tries to optimize, and returns whether we propagated a change.
+  bool optimize() {
+    // The pointer itself may be a constant, if e.g. it was precomputed or
+    // a get that we propagated.
+    if (curr->ptr->template is<Const>()) {
+      optimizeConstantPointer();
+      return false;
+    }
+    if (auto* add = curr->ptr->template dynCast<Binary>()) {
+      if (add->op == AddInt32) {
+        // Look for a constant on both sides.
+        if (tryToOptimizeConstant(add->right, add->left) ||
+            tryToOptimizeConstant(add->left, add->right)) {
+          return false;
+        }
+      }
+    }
+    if (localGraph) {
+      // A final important case is a propagated add:
+      //
+      //  x = y + 10
+      //  ..
+      //  load(x)
+      // =>
+      //  x = y + 10
+      //  ..
+      //  load(y, offset=10)
+      //
+      // This is only valid if y does not change in the middle!
+      if (auto* get = curr->ptr->template dynCast<LocalGet>()) {
+        auto& sets = localGraph->getSetses[get];
+        if (sets.size() == 1) {
+          auto* set = *sets.begin();
+          // May be a zero-init (in which case, we can ignore it). Must also be
+          // valid to propagate, as checked earlier in the parent.
+          if (set && parent->isPropagatable(set)) {
+            auto* value = set->value;
+            if (auto* add = value->template dynCast<Binary>()) {
+              if (add->op == AddInt32) {
+                // We can optimize on either side, but only if both we find
+                // a constant *and* the other side cannot change in the middle.
+                // TODO If it could change, we may add a new local to capture
+                //      the old value.
+                if (tryToOptimizePropagatedAdd(
+                      add->right, add->left, get, set) ||
+                    tryToOptimizePropagatedAdd(
+                      add->left, add->right, get, set)) {
+                  return true;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    return false;
+  }
+
+private:
+  P* parent;
+  T* curr;
+  Module* module;
+  LocalGraph* localGraph;
+
+  void optimizeConstantPointer() {
+    // The constant and an offset are interchangeable:
+    //   (load (const X))  <=>  (load offset=X (const 0))
+    // It may not matter if we do this or not - it's the same size,
+    // and in both cases the compiler can see it's a constant location.
+    // For code clarity and compressibility, we prefer to put the
+    // entire address in the constant.
+    if (curr->offset) {
+      // Note that the offset may already be larger than low memory - the
+      // code may know that is valid, even if we can't. Only handle the
+      // obviously valid case where an overflow can't occur.
+      auto* c = curr->ptr->template cast<Const>();
+      uint32_t base = c->value.geti32();
+      uint32_t offset = curr->offset;
+      if (uint64_t(base) + uint64_t(offset) < (uint64_t(1) << 32)) {
+        c->value = c->value.add(Literal(uint32_t(curr->offset)));
+        curr->offset = 0;
+      }
+    }
+  }
+
+  struct Result {
+    bool succeeded;
+    Address total;
+    Result() : succeeded(false) {}
+    Result(Address total) : succeeded(true), total(total) {}
+  };
+
+  // See if we can optimize an offset from an expression. If we report
+  // success, the returned offset can be added as a replacement for the
+  // expression here.
+  bool tryToOptimizeConstant(Expression* oneSide, Expression* otherSide) {
+    if (auto* c = oneSide->dynCast<Const>()) {
+      auto result = canOptimizeConstant(c->value);
+      if (result.succeeded) {
+        curr->offset = result.total;
+        curr->ptr = otherSide;
+        if (curr->ptr->template is<Const>()) {
+          optimizeConstantPointer();
+        }
+        return true;
+      }
+    }
+    return false;
+  }
+
+  bool tryToOptimizePropagatedAdd(Expression* oneSide,
+                                  Expression* otherSide,
+                                  LocalGet* ptr,
+                                  LocalSet* set) {
+    if (auto* c = oneSide->dynCast<Const>()) {
+      if (otherSide->is<Const>()) {
+        // Both sides are constant - this is not optimized code, ignore.
+        return false;
+      }
+      auto result = canOptimizeConstant(c->value);
+      if (result.succeeded) {
+        // Looks good, but we need to make sure the other side cannot change:
+        //
+        //  x = y + 10
+        //  y = y + 1
+        //  load(x)
+        //
+        // This example should not be optimized into
+        //
+        //  load(x, offset=10)
+        //
+        // If the other side is a get, we may be able to prove that we can just
+        // use that same local, if both it and the pointer are in SSA form. In
+        // that case,
+        //
+        //  y = .. // single assignment that dominates all uses
+        //  x = y + 10 // single assignment that dominates all uses
+        //  [..]
+        //  load(x) => load(y, offset=10)
+        //
+        // This is valid since dominance is transitive, so y's definition
+        // dominates the load, and it is ok to replace x with y + 10 there.
+        Index index = -1;
+        bool canReuseIndex = false;
+        if (auto* get = otherSide->dynCast<LocalGet>()) {
+          if (localGraph->isSSA(get->index) && localGraph->isSSA(ptr->index)) {
+            index = get->index;
+            canReuseIndex = true;
+          }
+        }
+        // If we can't reuse the index, then create a new one,
+        //
+        //  x = y + 10
+        //  y = y + 1
+        //  load(x)
+        // =>
+        //  y' = y
+        //  x = y' + 10
+        //  y = y + 1
+        //  load(y', offset=10)
+        //
+        // Often x has no other uses and later passes can remove it.
+        if (!canReuseIndex) {
+          index = parent->getHelperIndex(set);
+        }
+        curr->offset = result.total;
+        curr->ptr = Builder(*module).makeLocalGet(index, Type::i32);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // Sees if we can optimize a particular constant.
+  Result canOptimizeConstant(Literal literal) {
+    auto value = literal.geti32();
+    // Avoid uninteresting corner cases with peculiar offsets.
+    if (value >= 0 && value < PassOptions::LowMemoryBound) {
+      // The total offset must not allow reaching reasonable memory
+      // by overflowing.
+      auto total = curr->offset + value;
+      if (total < PassOptions::LowMemoryBound) {
+        return Result(total);
+      }
+    }
+    return Result();
+  }
+};
+
+struct OptimizeAddedConstants
+  : public WalkerPass<
+      PostWalker<OptimizeAddedConstants,
+                 UnifiedExpressionVisitor<OptimizeAddedConstants>>> {
+  bool isFunctionParallel() override { return true; }
+
+  bool propagate;
+
+  OptimizeAddedConstants(bool propagate) : propagate(propagate) {}
+
+  Pass* create() override { return new OptimizeAddedConstants(propagate); }
+
+  void visitLoad(Load* curr) {
+    MemoryAccessOptimizer<OptimizeAddedConstants, Load> optimizer(
+      this, curr, getModule(), localGraph.get());
+    if (optimizer.optimize()) {
+      propagated = true;
+    }
+  }
+
+  void visitStore(Store* curr) {
+    MemoryAccessOptimizer<OptimizeAddedConstants, Store> optimizer(
+      this, curr, getModule(), localGraph.get());
+    if (optimizer.optimize()) {
+      propagated = true;
+    }
+  }
+
+  void doWalkFunction(Function* func) {
+    // This pass is only valid under the assumption of unused low memory.
+    assert(getPassOptions().lowMemoryUnused);
+    // Multiple passes may be needed if we have x + 4 + 8 etc. (nested structs
+    // in C can cause this, but it's rare). Note that we only need that for the
+    // propagation case (as 4 + 8 would be optimized directly if it were
+    // adjacent).
+    while (1) {
+      propagated = false;
+      helperIndexes.clear();
+      propagatable.clear();
+      if (propagate) {
+        localGraph = make_unique<LocalGraph>(func);
+        localGraph->computeInfluences();
+        localGraph->computeSSAIndexes();
+        findPropagatable();
+      }
+      super::doWalkFunction(func);
+      if (!helperIndexes.empty()) {
+        createHelperIndexes();
+      }
+      if (propagated) {
+        cleanUpAfterPropagation();
+      } else {
+        return;
+      }
+    }
+  }
+
+  // For a given expression, store it to a local and return us the local index
+  // we can use, in order to get that value someplace else. We are provided not
+  // the expression, but the set in which it is in, as the arm of an add that is
+  // the set's value (the other arm is a constant, and we are not a constant).
+  // We cache these, that is, use a single one for all requests.
+  Index getHelperIndex(LocalSet* set) {
+    auto iter = helperIndexes.find(set);
+    if (iter != helperIndexes.end()) {
+      return iter->second;
+    }
+    return helperIndexes[set] =
+             Builder(*getModule()).addVar(getFunction(), Type::i32);
+  }
+
+  bool isPropagatable(LocalSet* set) { return propagatable.count(set); }
+
+private:
+  bool propagated;
+
+  std::unique_ptr<LocalGraph> localGraph;
+
+  // Whether a set is propagatable.
+  std::set<LocalSet*> propagatable;
+
+  void findPropagatable() {
+    // Conservatively, only propagate if all uses can be removed of the
+    // original. That is,
+    //  x = a + 10
+    //  f(x)
+    //  g(x)
+    // should be optimized to
+    //  f(a, offset=10)
+    //  g(a, offset=10)
+    // but if x has other uses, then avoid doing so - we'll be doing that add
+    // anyhow, so the load/store offset trick won't actually help.
+    Parents parents(getFunction()->body);
+    for (auto& pair : localGraph->locations) {
+      auto* location = pair.first;
+      if (auto* set = location->dynCast<LocalSet>()) {
+        if (auto* add = set->value->dynCast<Binary>()) {
+          if (add->op == AddInt32) {
+            if (add->left->is<Const>() || add->right->is<Const>()) {
+              // Looks like this might be relevant, check all uses.
+              bool canPropagate = true;
+              for (auto* get : localGraph->setInfluences[set]) {
+                auto* parent = parents.getParent(get);
+                // if this is at the top level, it's the whole body - no set can
+                // exist!
+                assert(parent);
+                if (!(parent->is<Load>() || parent->is<Store>())) {
+                  canPropagate = false;
+                  break;
+                }
+              }
+              if (canPropagate) {
+                propagatable.insert(set);
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  void cleanUpAfterPropagation() {
+    // Remove sets that no longer have uses. This allows further propagation by
+    // letting us see the accurate amount of uses of each set.
+    UnneededSetRemover remover(
+      getFunction(), getPassOptions(), getModule()->features);
+  }
+
+  std::map<LocalSet*, Index> helperIndexes;
+
+  void createHelperIndexes() {
+    struct Creator : public PostWalker<Creator> {
+      std::map<LocalSet*, Index>& helperIndexes;
+      Module* module;
+
+      Creator(std::map<LocalSet*, Index>& helperIndexes)
+        : helperIndexes(helperIndexes) {}
+
+      void visitLocalSet(LocalSet* curr) {
+        auto iter = helperIndexes.find(curr);
+        if (iter != helperIndexes.end()) {
+          auto index = iter->second;
+          auto* binary = curr->value->cast<Binary>();
+          Expression** target;
+          if (binary->left->is<Const>()) {
+            target = &binary->right;
+          } else {
+            assert(binary->right->is<Const>());
+            target = &binary->left;
+          }
+          auto* value = *target;
+          Builder builder(*module);
+          *target = builder.makeLocalGet(index, Type::i32);
+          replaceCurrent(
+            builder.makeSequence(builder.makeLocalSet(index, value), curr));
+        }
+      }
+    } creator(helperIndexes);
+    creator.module = getModule();
+    creator.walk(getFunction()->body);
+  }
+};
+
+Pass* createOptimizeAddedConstantsPass() {
+  return new OptimizeAddedConstants(false);
+}
+
+Pass* createOptimizeAddedConstantsPropagatePass() {
+  return new OptimizeAddedConstants(true);
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/OptimizeInstructions.cpp b/binaryen/src/passes/OptimizeInstructions.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/OptimizeInstructions.cpp
@@ -0,0 +1,1956 @@
+/*
+ * 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.
+ */
+
+//
+// Optimize combinations of instructions
+//
+
+#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(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/PickLoadSigns.cpp b/binaryen/src/passes/PickLoadSigns.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/PickLoadSigns.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+#include <ir/properties.h>
+#include <pass.h>
+#include <wasm.h>
+
+namespace wasm {
+
+// Adjust load signedness based on usage. If a load only has uses that sign or
+// unsign it anyhow, then it could be either, and picking the popular one can
+// help remove the most sign/unsign operations
+// unsigned, then it could be either
+
+struct PickLoadSigns : public WalkerPass<ExpressionStackWalker<PickLoadSigns>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new PickLoadSigns; }
+
+  struct Usage {
+    Index signedUsages = 0;
+    Index signedBits;
+    Index unsignedUsages = 0;
+    Index unsignedBits;
+    Index totalUsages = 0;
+  };
+  std::vector<Usage> usages; // local index => usage
+
+  // loads that write to a local => the local
+  std::unordered_map<Load*, Index> loads;
+
+  void doWalkFunction(Function* func) {
+    // prepare
+    usages.resize(func->getNumLocals());
+    // walk
+    ExpressionStackWalker<PickLoadSigns>::doWalkFunction(func);
+    // optimize
+    optimize();
+  }
+
+  void visitLocalGet(LocalGet* curr) {
+    // this is a use. check from the context what it is, signed or unsigned,
+    // etc.
+    auto& usage = usages[curr->index];
+    usage.totalUsages++;
+    if (expressionStack.size() >= 2) {
+      auto* parent = expressionStack[expressionStack.size() - 2];
+      if (Properties::getZeroExtValue(parent)) {
+        auto bits = Properties::getZeroExtBits(parent);
+        if (usage.unsignedUsages == 0) {
+          usage.unsignedBits = bits;
+        } else if (usage.unsignedBits != bits) {
+          usage.unsignedBits = 0;
+        }
+        usage.unsignedUsages++;
+      } else if (expressionStack.size() >= 3) {
+        auto* grandparent = expressionStack[expressionStack.size() - 3];
+        if (Properties::getSignExtValue(grandparent)) {
+          auto bits = Properties::getSignExtBits(grandparent);
+          if (usage.signedUsages == 0) {
+            usage.signedBits = bits;
+          } else if (usage.signedBits != bits) {
+            usage.signedBits = 0;
+          }
+          usage.signedUsages++;
+        }
+      }
+    }
+  }
+
+  void visitLocalSet(LocalSet* curr) {
+    if (curr->isTee()) {
+      // we can't modify a tee, the value is used elsewhere
+      return;
+    }
+    if (auto* load = curr->value->dynCast<Load>()) {
+      loads[load] = curr->index;
+    }
+  }
+
+  void optimize() {
+    // optimize based on the info we saw
+    for (auto& pair : loads) {
+      auto* load = pair.first;
+      auto index = pair.second;
+      auto& usage = usages[index];
+      // if we can't optimize, give up
+      if (usage.totalUsages == 0 || // no usages, so no idea
+          usage.signedUsages + usage.unsignedUsages !=
+            usage.totalUsages || // non-sign/unsigned usages, so cannot change
+          (usage.signedUsages != 0 &&
+           usage.signedBits !=
+             load->bytes * 8) || // sign usages exist but the wrong size
+          (usage.unsignedUsages != 0 &&
+           usage.unsignedBits !=
+             load->bytes * 8)) { // unsigned usages exist but the wrong size
+        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;
+    }
+  }
+};
+
+Pass* createPickLoadSignsPass() { return new PickLoadSigns(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/PostAssemblyScript.cpp b/binaryen/src/passes/PostAssemblyScript.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/PostAssemblyScript.cpp
@@ -0,0 +1,641 @@
+/*
+ * Copyright 2019 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.
+ */
+
+//
+// Misc optimizations that are useful for and/or are only valid for
+// AssemblyScript output.
+//
+
+#include "ir/flat.h"
+#include "ir/local-graph.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
+#include <unordered_map>
+#include <unordered_set>
+#ifdef POST_ASSEMBLYSCRIPT_DEBUG
+#include "wasm-printing.h"
+#include <iostream>
+#endif
+
+namespace wasm {
+
+namespace PostAssemblyScript {
+
+static Name RETAIN = Name("~lib/rt/pure/__retain");
+static Name RELEASE = Name("~lib/rt/pure/__release");
+static Name ALLOC = Name("~lib/rt/tlsf/__alloc");
+static Name ALLOCARRAY = Name("~lib/rt/__allocArray");
+
+template<typename K, typename V> using Map = std::unordered_map<K, V>;
+template<typename T> using Set = std::unordered_set<T>;
+
+// A variant of LocalGraph that considers only assignments when computing
+// influences.
+//
+// This allows us to find locals aliasing a retain, while ignoring other
+// influences.
+//
+// For example, we are interested in
+//
+//   var a = __retain(X)
+//   var b = a;
+//   __release(b); // releases X
+//
+// but not in
+//
+//  var a = __retain(X);
+//  var b = someFunction(a);
+//  __release(b);
+//  return a;
+//
+// since the latter releases not 'X' but the reference returned by the call,
+// which is usually something else.
+struct AliasGraph : LocalGraph {
+  AliasGraph(Function* func) : LocalGraph(func) {}
+  void computeInfluences() {
+    for (auto& pair : locations) {
+      auto* curr = pair.first;
+      if (auto* set = curr->dynCast<LocalSet>()) {
+        if (auto* get = set->value->dynCast<LocalGet>()) {
+          getInfluences[get].insert(set);
+        }
+      } else {
+        auto* get = curr->cast<LocalGet>();
+        for (auto* set : getSetses[get]) {
+          setInfluences[set].insert(get);
+        }
+      }
+    }
+  }
+};
+
+// Tests if the given call calls retain. Note that this differs from what we
+// consider a full retain pattern, which must also set a local.
+static bool isRetainCall(Call* expr) {
+  // __retain(...)
+  return expr->target == RETAIN && expr->type == Type::i32 &&
+         expr->operands.size() == 1 && expr->operands[0]->type == Type::i32;
+}
+
+// Tests if a local.set is considered to be a full retain pattern.
+static bool isRetain(LocalSet* expr) {
+  // local.set(X, __retain(...))
+  if (auto* call = expr->value->dynCast<Call>()) {
+    return isRetainCall(call);
+  }
+  return false;
+}
+
+#ifndef NDEBUG
+// Tests if the given location is that of a full retain pattern.
+static bool isRetainLocation(Expression** expr) {
+  if (expr != nullptr) {
+    if (auto localSet = (*expr)->dynCast<LocalSet>()) {
+      return isRetain(localSet);
+    }
+  }
+  return false;
+}
+#endif
+
+// Tests if the given call calls release. Note that this differs from what we
+// consider a full release pattern, which must also get a local.
+static bool isReleaseCall(Call* expr) {
+  // __release(...)
+  return expr->target == RELEASE && expr->type == Type::none &&
+         expr->operands.size() == 1 && expr->operands[0]->type == Type::i32;
+}
+
+// Tests if the given location is that of a full release pattern. Note that
+// the local.get is our key when checking for releases to align with
+// AliasGraph, and not the outer call, which is also the reason why there is
+// no `isRelease` as we can't tell from the local.get alone.
+static bool isReleaseLocation(Expression** expr) {
+  // __release(local.get(X, ...))
+  if (expr != nullptr) {
+    if (auto* call = (*expr)->dynCast<Call>()) {
+      return isReleaseCall(call) && call->operands[0]->is<LocalGet>();
+    }
+  }
+  return false;
+}
+
+// Tests if the given call calls any allocation function.
+static bool isAllocCall(Call* expr) {
+  return (expr->target == ALLOC || expr->target == ALLOCARRAY) &&
+         expr->type == Type::i32;
+}
+
+// A pass that eliminates redundant retain and release calls.
+//
+// Does a cheap traversal first, remembering ARC-style patterns, and goes all-in
+// only if it finds any.
+//
+// This is based on the assumption that the compiler is not allowed to emit
+// unbalanced retains or releases, except if
+//
+// * a value is returned or otherwise escapes in one branch or
+// * a branch is being internally unified by the compiler
+//
+// which we detect below. In turn, we do not have to deal with control
+// structures but can instead look for escapes reached (by any alias) using
+// AliasGraph.
+//
+// For example, in code like
+//
+//   var a = __retain(X);
+//   if (cond) {
+//     return a;
+//   }
+//   __release(a);
+//  return null;
+//
+// we cannot eliminate the retain/release pair because the implementation
+// dictates that returned references must remain retained for the caller since
+// dropping to RC=0 on the boundary would prematurely free the object.
+//
+// Typical patterns this recognizes are simple pairs of the form
+//
+//   var a = __retain(X);
+//   __release(a);
+//
+// retains with balanced releases of the form
+//
+//   var a = __retain(X);
+//   if (cond) {
+//     __release(a);
+//   } else {
+//     __release(a);
+//   }
+//
+// releases with balanced retains of the form
+//
+//   var a;
+//   if (cond) {
+//     a = __retain(X);
+//   } else {
+//     a = __retain(Y);
+//   }
+//   __release(a);
+//
+// including technically invalid patterns assumed to be not present in compiler
+// output, like:
+//
+//   var b = __retain(a);
+//   if (cond) {
+//     __release(b); // unbalanced release
+//   }
+//
+// To detect the latter, we'd have to follow control structures around, which
+// we don't do since it isn't neccessary / to keep the amount of work minimal.
+struct OptimizeARC : public WalkerPass<PostWalker<OptimizeARC>> {
+
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new OptimizeARC; }
+
+  // Sets that are retains, to location
+  Map<LocalSet*, Expression**> retains;
+
+  // Gets that are releases, to location
+  Map<LocalGet*, Expression**> releases;
+
+  // Gets that are escapes, i.e. being returned or thrown
+  Set<LocalGet*> escapes;
+
+  void visitLocalSet(LocalSet* curr) {
+    if (isRetain(curr)) {
+      retains[curr] = getCurrentPointer();
+    }
+  }
+
+  void visitCall(Call* curr) {
+    auto** currp = getCurrentPointer();
+    if (isReleaseLocation(currp)) {
+      releases[curr->operands[0]->cast<LocalGet>()] = currp;
+    }
+  }
+
+  void visitReturn(Return* curr) {
+    // return(local.get(X, ...)) ?
+    // indicates that an object is returned from one function and given to
+    // another, so releasing it would be invalid.
+    auto* value = curr->value;
+    if (value) {
+      if (auto* localGet = value->dynCast<LocalGet>()) {
+        escapes.insert(localGet);
+      }
+    }
+  }
+
+  void visitThrow(Throw* curr) {
+    // throw(..., local.get(X, ...), ...) ?
+    // indicates that an object is thrown in one function and can be caught
+    // anywhere, like in another function, so releasing it would be invalid.
+    for (auto* operand : curr->operands) {
+      if (auto* localGet = operand->dynCast<LocalGet>()) {
+        escapes.insert(localGet);
+        break;
+      }
+    }
+  }
+
+  void eliminateRetain(Expression** location) {
+    assert(isRetainLocation(location));
+    auto* localSet = (*location)->cast<LocalSet>();
+    localSet->value = localSet->value->cast<Call>()->operands[0];
+  }
+
+  void eliminateRelease(Expression** location) {
+    assert(isReleaseLocation(location));
+    Builder builder(*getModule());
+    *location = builder.makeNop();
+  }
+
+  // Tests if a retain reaches an escape and thus is considered necessary.
+  bool
+  testReachesEscape(LocalSet* retain, AliasGraph& graph, Set<LocalSet*>& seen) {
+    for (auto* localGet : graph.setInfluences[retain]) {
+      if (releases.find(localGet) != releases.end()) {
+        continue;
+      }
+      if (escapes.find(localGet) != escapes.end()) {
+        return true;
+      }
+      for (auto* localSet : graph.getInfluences[localGet]) {
+        if (seen.find(localSet) == seen.end()) {
+          seen.insert(localSet);
+          if (testReachesEscape(localSet, graph, seen)) {
+            return true;
+          }
+        }
+      }
+    }
+    return false;
+  }
+
+  bool testReachesEscape(LocalSet* retain, AliasGraph& graph) {
+    Set<LocalSet*> seen;
+    return testReachesEscape(retain, graph, seen);
+  }
+
+  // Collects all reachable releases of a retain.
+  void collectReleases(LocalSet* retain,
+                       AliasGraph& graph,
+                       Set<Expression**>& found,
+                       Set<LocalSet*>& seen) {
+    for (auto* localGet : graph.setInfluences[retain]) {
+      auto foundRelease = releases.find(localGet);
+      if (foundRelease != releases.end()) {
+        found.insert(foundRelease->second);
+      } else {
+        for (auto* localSet : graph.getInfluences[localGet]) {
+          if (seen.find(localSet) == seen.end()) {
+            seen.insert(localSet);
+            collectReleases(localSet, graph, found, seen);
+          }
+        }
+      }
+    }
+  }
+
+  void collectReleases(LocalSet* retain,
+                       AliasGraph& graph,
+                       Set<Expression**>& found) {
+    Set<LocalSet*> seen;
+    collectReleases(retain, graph, found, seen);
+  }
+
+  // Given a retain, gets the retained expression
+  static Expression* getRetainedExpression(LocalSet* retain) {
+    assert(isRetain(retain));
+    return retain->value->cast<Call>()->operands[0];
+  }
+
+  // Tests if a retained value originates at an allocation and thus is
+  // considered necessary.
+  bool testRetainsAllocation(Expression* retained,
+                             AliasGraph& graph,
+                             Set<LocalSet*>& seen) {
+    if (auto* call = retained->dynCast<Call>()) {
+      if (call->target == ALLOC || call->target == ALLOCARRAY) {
+        return true;
+      }
+    } else {
+      if (auto* localGet = retained->dynCast<LocalGet>()) {
+        for (auto* localSet : graph.getSetses[localGet]) {
+          if (localSet != nullptr) {
+            if (seen.find(localSet) == seen.end()) {
+              seen.insert(localSet);
+              if (testRetainsAllocation(localSet->value, graph, seen)) {
+                return true;
+              }
+            }
+          }
+        }
+      }
+    }
+    return false;
+  }
+
+  bool testRetainsAllocation(Expression* retained, AliasGraph& graph) {
+    Set<LocalSet*> seen;
+    return testRetainsAllocation(retained, graph, seen);
+  }
+
+  // Given a release location, gets the local.get that is our release indicator
+  static LocalGet* getReleaseByLocation(Expression** releaseLocation) {
+    assert(isReleaseLocation(releaseLocation));
+    return (*releaseLocation)->cast<Call>()->operands[0]->cast<LocalGet>();
+  }
+
+  // Tests if a release has balanced retains, that is it is being retained in
+  // any path leading to the release. For example
+  //
+  //   var c = somethingElse() || a;
+  //   ...
+  //
+  // which compiles to
+  //
+  //   if (!(b = somethingElse())) {
+  //     b = __retain(a);
+  //   }
+  //   var c = b;
+  //   ...
+  //   __release(c);
+  //
+  // is unbalanced since it reaches a retain and something else. Here, the
+  // compiler inserts the retain call because it must unify the two branches
+  // since the result of `somethingElse()` is known to be retained for the
+  // caller and the other branch must yield a retained value as well.
+  bool testBalancedRetains(LocalGet* release,
+                           AliasGraph& graph,
+                           Map<LocalGet*, bool>& cache,
+                           Set<LocalGet*>& seen) {
+    auto cached = cache.find(release);
+    if (cached != cache.end()) {
+      return cached->second;
+    }
+    for (auto* localSet : graph.getSetses[release]) {
+      if (localSet == nullptr) {
+        return cache[release] = false;
+      }
+      if (retains.find(localSet) == retains.end()) {
+        if (auto* localGet = localSet->value->dynCast<LocalGet>()) {
+          if (seen.find(localGet) == seen.end()) {
+            seen.insert(localGet);
+            if (!testBalancedRetains(localGet, graph, cache, seen)) {
+              return cache[release] = false;
+            }
+          } else {
+            return cache[release] = false;
+          }
+        } else {
+          return cache[release] = false;
+        }
+      }
+    }
+    return cache[release] = true;
+  }
+
+  bool testBalancedRetains(LocalGet* release,
+                           AliasGraph& graph,
+                           Map<LocalGet*, bool>& cache) {
+    Set<LocalGet*> seen;
+    return testBalancedRetains(release, graph, cache, seen);
+  }
+
+  void doWalkFunction(Function* func) {
+    Flat::verifyFlatness(func);
+#ifdef POST_ASSEMBLYSCRIPT_DEBUG
+    std::cerr << "[PostAssemblyScript::OptimizeARC] walking " << func->name
+              << "\n";
+#endif
+    super::doWalkFunction(func);
+    if (retains.empty()) {
+#ifdef POST_ASSEMBLYSCRIPT_DEBUG
+      std::cerr << "  no ARC code\n";
+#endif
+      return;
+    }
+
+    AliasGraph graph(func);
+    graph.computeInfluences();
+
+    Set<Expression**> redundantRetains;
+    Set<Expression**> redundantReleases;
+    Map<LocalGet*, bool> balancedRetainsCache;
+
+    // For each retain, check that it
+    //
+    // * doesn't reach an escape
+    // * doesn't retain an allocation
+    // * reaches at least one release
+    // * reaches only releases with balanced retains
+    //
+    for (auto& pair : retains) {
+      auto* retain = pair.first;
+      auto** retainLocation = pair.second;
+      if (!testReachesEscape(retain, graph)) {
+        if (!testRetainsAllocation(getRetainedExpression(retain), graph)) {
+          Set<Expression**> releaseLocations;
+          collectReleases(retain, graph, releaseLocations);
+          if (!releaseLocations.empty()) {
+            bool allBalanced = true;
+            for (auto** releaseLocation : releaseLocations) {
+              if (!testBalancedRetains(getReleaseByLocation(releaseLocation),
+                                       graph,
+                                       balancedRetainsCache)) {
+                allBalanced = false;
+                break;
+              }
+            }
+            if (allBalanced) {
+#ifdef POST_ASSEMBLYSCRIPT_DEBUG
+              std::cerr << "  eliminating ";
+              WasmPrinter::printExpression(retain, std::cerr, true);
+              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 << "\n";
+#endif
+                redundantReleases.insert(getLocation);
+              }
+#ifdef POST_ASSEMBLYSCRIPT_DEBUG
+            } else {
+              std::cerr << "  cannot eliminate ";
+              WasmPrinter::printExpression(retain, std::cerr, true);
+              std::cerr << " - unbalanced\n";
+#endif
+            }
+#ifdef POST_ASSEMBLYSCRIPT_DEBUG
+          } else {
+            std::cerr << "  cannot eliminate ";
+            WasmPrinter::printExpression(retain, std::cerr, true);
+            std::cerr << " - zero releases\n";
+#endif
+          }
+#ifdef POST_ASSEMBLYSCRIPT_DEBUG
+        } else {
+          std::cerr << "  cannot eliminate ";
+          WasmPrinter::printExpression(retain, std::cerr, true);
+          std::cerr << " - retains allocation\n";
+#endif
+        }
+#ifdef POST_ASSEMBLYSCRIPT_DEBUG
+      } else {
+        std::cerr << "  cannot eliminate ";
+        WasmPrinter::printExpression(retain, std::cerr, true);
+        std::cerr << " - reaches return\n";
+#endif
+      }
+    }
+    for (auto** location : redundantRetains) {
+      eliminateRetain(location);
+    }
+    for (auto** location : redundantReleases) {
+      eliminateRelease(location);
+    }
+#ifdef POST_ASSEMBLYSCRIPT_DEBUG
+    std::cerr << "  eliminated " << redundantRetains.size() << "/"
+              << retains.size() << " retains and " << redundantReleases.size()
+              << "/" << releases.size() << " releases\n";
+#endif
+  }
+};
+
+// Eliminating retains and releases makes it more likely that other passes lead
+// to collapsed release/retain pairs that are not full retain or release
+// patterns, and this pass finalizes such pairs. Typical patterns are entire
+// unnecessary allocations of the form
+//
+//   __release(__retain(__alloc(...));
+//
+// otherwise unnecessary pairs of the form
+//
+//   __release(__retain(...));
+//
+// or retains/releases of constants which indicate data in static memory which
+// are unnecessary to refcount:
+//
+//  __retain("staticString");
+//
+//  __release("staticString");
+//
+struct FinalizeARC : public WalkerPass<PostWalker<FinalizeARC>> {
+
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new FinalizeARC; }
+
+  uint32_t eliminatedAllocations = 0;
+  uint32_t eliminatedRetains = 0;
+  uint32_t eliminatedReleases = 0;
+
+  void visitCall(Call* curr) {
+    if (isReleaseCall(curr)) {
+      if (auto* releasedCall = curr->operands[0]->dynCast<Call>()) {
+        if (isRetainCall(releasedCall)) {
+          if (auto* retainedCall = releasedCall->operands[0]->dynCast<Call>()) {
+            if (isAllocCall(retainedCall)) {
+              // __release(__retain(__alloc(...))) - unnecessary allocation
+#ifdef POST_ASSEMBLYSCRIPT_DEBUG
+              std::cerr << "  finalizing ";
+              WasmPrinter::printExpression(curr, std::cerr, true);
+              std::cerr << " - unnecessary allocation\n";
+#endif
+              Builder builder(*getModule());
+              replaceCurrent(builder.makeNop());
+              ++eliminatedAllocations;
+              ++eliminatedRetains;
+              ++eliminatedReleases;
+              return;
+            }
+          }
+          // __release(__retain(...)) - unnecessary pair
+#ifdef POST_ASSEMBLYSCRIPT_DEBUG
+          std::cerr << "  finalizing ";
+          WasmPrinter::printExpression(curr, std::cerr, true);
+          std::cerr << " - unnecessary pair\n";
+#endif
+          Builder builder(*getModule());
+          replaceCurrent(builder.makeDrop(releasedCall->operands[0]));
+          ++eliminatedRetains;
+          ++eliminatedReleases;
+        }
+      } else if (curr->operands[0]->is<Const>()) {
+        // __release(42) - unnecessary static release
+#ifdef POST_ASSEMBLYSCRIPT_DEBUG
+        std::cerr << "  finalizing ";
+        WasmPrinter::printExpression(curr, std::cerr, true);
+        std::cerr << " - static release\n";
+#endif
+        Builder builder(*getModule());
+        replaceCurrent(builder.makeNop());
+        ++eliminatedReleases;
+      }
+    } else if (isRetainCall(curr)) {
+      if (auto* retainedConst = curr->operands[0]->dynCast<Const>()) {
+        // __retain(42) - unnecessary static retain
+#ifdef POST_ASSEMBLYSCRIPT_DEBUG
+        std::cerr << "  finalizing ";
+        WasmPrinter::printExpression(curr, std::cerr, true);
+        std::cerr << " - static retain\n";
+#endif
+        replaceCurrent(retainedConst);
+        ++eliminatedRetains;
+      }
+    }
+  }
+
+  void doWalkFunction(Function* func) {
+#ifdef POST_ASSEMBLYSCRIPT_DEBUG
+    std::cerr << "[PostAssemblyScript::FinalizeARC] walking " << func->name
+              << "\n";
+#endif
+    super::doWalkFunction(func);
+#ifdef POST_ASSEMBLYSCRIPT_DEBUG
+    if (eliminatedAllocations > 0 || eliminatedRetains > 0 ||
+        eliminatedReleases > 0) {
+      std::cerr << "  finalized " << eliminatedAllocations << " allocations, "
+                << eliminatedRetains << " retains and" << eliminatedReleases
+                << " releases\n";
+    } else {
+      std::cerr << "  nothing to do\n";
+    }
+#endif
+  }
+};
+
+} // namespace PostAssemblyScript
+
+// declare passes
+
+Pass* createPostAssemblyScriptPass() {
+  return new PostAssemblyScript::OptimizeARC();
+}
+
+Pass* createPostAssemblyScriptFinalizePass() {
+  return new PostAssemblyScript::FinalizeARC();
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/PostEmscripten.cpp b/binaryen/src/passes/PostEmscripten.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/PostEmscripten.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// Misc optimizations that are useful for and/or are only valid for
+// emscripten output.
+//
+
+#include <asmjs/shared-constants.h>
+#include <ir/import-utils.h>
+#include <ir/localize.h>
+#include <ir/memory-utils.h>
+#include <ir/module-utils.h>
+#include <ir/table-utils.h>
+#include <pass.h>
+#include <shared-constants.h>
+#include <wasm-builder.h>
+#include <wasm-emscripten.h>
+#include <wasm.h>
+
+#define DEBUG_TYPE "post-emscripten"
+
+namespace wasm {
+
+namespace {
+
+static bool isInvoke(Function* F) {
+  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);
+  }
+
+  // Optimize exceptions (and setjmp) by removing unnecessary invoke* calls.
+  // An invoke is a call to JS with a function pointer; JS does a try-catch
+  // and calls the pointer, catching and reporting any error. If we know no
+  // exception will be thrown, we can simply skip the invoke.
+  void optimizeExceptions(PassRunner* runner, Module* module) {
+    // First, check if this code even uses invokes.
+    bool hasInvokes = false;
+    for (auto& imp : module->functions) {
+      if (isInvoke(imp.get())) {
+        hasInvokes = true;
+      }
+    }
+    if (!hasInvokes) {
+      return;
+    }
+    // Next, see if the Table is flat, which we need in order to see where
+    // invokes go statically. (In dynamic linking, the table is not flat,
+    // and we can't do this.)
+    TableUtils::FlatTable flatTable(module->table);
+    if (!flatTable.valid) {
+      return;
+    }
+    // This code has exceptions. Find functions that definitely cannot throw,
+    // and remove invokes to them.
+    struct Info
+      : public ModuleUtils::CallGraphPropertyAnalysis<Info>::FunctionInfo {
+      bool canThrow = false;
+    };
+    ModuleUtils::CallGraphPropertyAnalysis<Info> analyzer(
+      *module, [&](Function* func, Info& info) {
+        if (func->imported()) {
+          // Assume any import can throw. We may want to reduce this to just
+          // longjmp/cxa_throw/etc.
+          info.canThrow = true;
+        }
+      });
+
+    // Assume an indirect 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);
+
+    // Apply the information.
+    struct OptimizeInvokes : public WalkerPass<PostWalker<OptimizeInvokes>> {
+      bool isFunctionParallel() override { return true; }
+
+      Pass* create() override { return new OptimizeInvokes(map, flatTable); }
+
+      std::map<Function*, Info>& map;
+      TableUtils::FlatTable& flatTable;
+
+      OptimizeInvokes(std::map<Function*, Info>& map,
+                      TableUtils::FlatTable& flatTable)
+        : map(map), flatTable(flatTable) {}
+
+      void visitCall(Call* curr) {
+        auto* target = getModule()->getFunction(curr->target);
+        if (isInvoke(target)) {
+          // The first operand is the function pointer index, which must be
+          // constant if we are to optimize it statically.
+          if (auto* index = curr->operands[0]->dynCast<Const>()) {
+            auto actualTarget = flatTable.names.at(index->value.geti32());
+            if (!map[getModule()->getFunction(actualTarget)].canThrow) {
+              // This invoke cannot throw! Make it a direct call.
+              curr->target = actualTarget;
+              for (Index i = 0; i < curr->operands.size() - 1; i++) {
+                curr->operands[i] = curr->operands[i + 1];
+              }
+              curr->operands.resize(curr->operands.size() - 1);
+            }
+          }
+        }
+      }
+    };
+    OptimizeInvokes(analyzer.map, flatTable).run(runner, module);
+  }
+};
+
+Pass* createPostEmscriptenPass() { return new PostEmscripten(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/Precompute.cpp b/binaryen/src/passes/Precompute.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/Precompute.cpp
@@ -0,0 +1,347 @@
+/*
+ * 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.
+ */
+
+//
+// Computes code at compile time where possible, replacing it with the
+// computed constant.
+//
+// The "propagate" variant of this pass also propagates constants across
+// sets and gets, which implements a standard constant propagation.
+//
+// Possible nondeterminism: WebAssembly NaN signs are nondeterministic,
+// and this pass may optimize e.g. a float 0 / 0 into +nan while a VM may
+// emit -nan, which can be a noticeable difference if the bits are
+// looked at.
+//
+
+#include <ir/literal-utils.h>
+#include <ir/local-graph.h>
+#include <ir/manipulation.h>
+#include <ir/properties.h>
+#include <ir/utils.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm-interpreter.h>
+#include <wasm.h>
+
+namespace wasm {
+
+typedef std::unordered_map<LocalGet*, Literals> GetValues;
+
+// Precomputes an expression. Errors if we hit anything that can't be
+// precomputed. Inherits most of its functionality from
+// ConstantExpressionRunner, which it shares with the C-API, but adds handling
+// of GetValues computed during the precompute pass.
+class PrecomputingExpressionRunner
+  : public ConstantExpressionRunner<PrecomputingExpressionRunner> {
+
+  // Concrete values of gets computed during the pass, which the runner does not
+  // know about since it only records values of sets it visits.
+  GetValues& getValues;
+
+  // Limit evaluation depth for 2 reasons: first, it is highly unlikely
+  // that we can do anything useful to precompute a hugely nested expression
+  // (we should succed at smaller parts of it first). Second, a low limit is
+  // helpful to avoid platform differences in native stack sizes.
+  static const Index MAX_DEPTH = 50;
+
+  // Limit loop iterations since loops might be infinite. Since we are going to
+  // replace the expression and must preserve side effects, we limit this to the
+  // very first iteration because a side effect would be necessary to achieve
+  // more than one iteration before becoming concrete.
+  static const Index MAX_LOOP_ITERATIONS = 1;
+
+public:
+  PrecomputingExpressionRunner(Module* module,
+                               GetValues& getValues,
+                               bool replaceExpression)
+    : ConstantExpressionRunner<PrecomputingExpressionRunner>(
+        module,
+        replaceExpression ? FlagValues::PRESERVE_SIDEEFFECTS
+                          : FlagValues::DEFAULT,
+        MAX_DEPTH,
+        MAX_LOOP_ITERATIONS),
+      getValues(getValues) {}
+
+  Flow visitLocalGet(LocalGet* curr) {
+    auto iter = getValues.find(curr);
+    if (iter != getValues.end()) {
+      auto values = iter->second;
+      if (values.isConcrete()) {
+        return Flow(values);
+      }
+    }
+    return ConstantExpressionRunner<
+      PrecomputingExpressionRunner>::visitLocalGet(curr);
+  }
+};
+
+struct Precompute
+  : public WalkerPass<
+      PostWalker<Precompute, UnifiedExpressionVisitor<Precompute>>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new Precompute(propagate); }
+
+  bool propagate = false;
+
+  Precompute(bool propagate) : propagate(propagate) {}
+
+  GetValues getValues;
+
+  bool worked;
+
+  void doWalkFunction(Function* func) {
+    // if propagating, we may need multiple rounds: each propagation can
+    // lead to the main walk removing code, which might open up more
+    // propagation opportunities
+    do {
+      getValues.clear();
+      // with extra effort, we can utilize the get-set graph to precompute
+      // things that use locals that are known to be constant. otherwise,
+      // we just look at what is immediately before us
+      if (propagate) {
+        optimizeLocals(func);
+      }
+      // do the main walk over everything
+      worked = false;
+      super::doWalkFunction(func);
+    } while (propagate && worked);
+  }
+
+  template<typename T> void reuseConstantNode(T* curr, Flow flow) {
+    if (flow.values.isConcrete()) {
+      // reuse a const / ref.null / ref.func node if there is one
+      if (curr->value && flow.values.size() == 1) {
+        Literal singleValue = flow.getSingleValue();
+        if (singleValue.type.isNumber()) {
+          if (auto* c = curr->value->template dynCast<Const>()) {
+            c->value = singleValue;
+            c->finalize();
+            curr->finalize();
+            return;
+          }
+        } else if (singleValue.isNull()) {
+          if (auto* n = curr->value->template dynCast<RefNull>()) {
+            n->finalize(singleValue.type);
+            curr->finalize();
+            return;
+          }
+        } else if (singleValue.type == Type::funcref) {
+          if (auto* r = curr->value->template dynCast<RefFunc>()) {
+            r->func = singleValue.getFunc();
+            r->finalize();
+            curr->finalize();
+            return;
+          }
+        }
+      }
+      curr->value = flow.getConstExpression(*getModule());
+    } else {
+      curr->value = nullptr;
+    }
+    curr->finalize();
+  }
+
+  void visitExpression(Expression* curr) {
+    // TODO: if local.get, only replace with a constant if we don't care about
+    // size...?
+    if (Properties::isConstantExpression(curr) || curr->is<Nop>()) {
+      return;
+    }
+    // Until engines implement v128.const and we have SIMD-aware optimizations
+    // that can break large v128.const instructions into smaller consts and
+    // splats, do not try to precompute v128 expressions.
+    if (curr->type.isVector()) {
+      return;
+    }
+    // try to evaluate this into a const
+    Flow flow = precomputeExpression(curr);
+    if (flow.getType().hasVector()) {
+      return;
+    }
+    if (flow.breaking()) {
+      if (flow.breakTo == NONCONSTANT_FLOW) {
+        return;
+      }
+      if (flow.breakTo == RETURN_FLOW) {
+        // this expression causes a return. if it's already a return, reuse the
+        // node
+        if (auto* ret = curr->dynCast<Return>()) {
+          reuseConstantNode(ret, flow);
+        } else {
+          Builder builder(*getModule());
+          replaceCurrent(builder.makeReturn(
+            flow.values.isConcrete() ? flow.getConstExpression(*getModule())
+                                     : nullptr));
+        }
+        return;
+      }
+      // this expression causes a break, emit it directly. if it's already a br,
+      // reuse the node.
+      if (auto* br = curr->dynCast<Break>()) {
+        br->name = flow.breakTo;
+        br->condition = nullptr;
+        reuseConstantNode(br, flow);
+      } else {
+        Builder builder(*getModule());
+        replaceCurrent(builder.makeBreak(
+          flow.breakTo,
+          flow.values.isConcrete() ? flow.getConstExpression(*getModule())
+                                   : nullptr));
+      }
+      return;
+    }
+    // this was precomputed
+    if (flow.values.isConcrete()) {
+      replaceCurrent(flow.getConstExpression(*getModule()));
+      worked = true;
+    } else {
+      ExpressionManipulator::nop(curr);
+    }
+  }
+
+  void visitFunction(Function* curr) {
+    // removing breaks can alter types
+    ReFinalize().walkFunctionInModule(curr, getModule());
+  }
+
+private:
+  // 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) {
+    try {
+      return PrecomputingExpressionRunner(
+               getModule(), getValues, replaceExpression)
+        .visit(curr);
+    } catch (PrecomputingExpressionRunner::NonconstantException&) {
+      return Flow(NONCONSTANT_FLOW);
+    }
+  }
+
+  // Precomputes the value of an expression, as opposed to the expression
+  // itself. This differs from precomputeExpression in that we care about
+  // the value the expression will have, which we cannot necessary replace
+  // the expression with. For example,
+  //  (local.tee (i32.const 1))
+  // will have value 1 which we can optimize here, but in precomputeExpression
+  // we could not do anything.
+  Literals precomputeValue(Expression* curr) {
+    // Note that we set replaceExpression to false, as we just care about
+    // the value here.
+    Flow flow = precomputeExpression(curr, false /* replaceExpression */);
+    if (flow.breaking()) {
+      return {};
+    }
+    return flow.values;
+  }
+
+  // Propagates values around. Returns whether we propagated.
+  void optimizeLocals(Function* func) {
+    // using the graph of get-set interactions, do a constant-propagation type
+    // operation: note which sets are assigned locals, then see if that lets us
+    // compute other sets as locals (since some of the gets they read may be
+    // constant).
+    // compute all dependencies
+    LocalGraph localGraph(func);
+    localGraph.computeInfluences();
+    localGraph.computeSSAIndexes();
+    // prepare the work list. we add things here that might change to a constant
+    // initially, that means everything
+    std::unordered_set<Expression*> work;
+    for (auto& pair : localGraph.locations) {
+      auto* curr = pair.first;
+      work.insert(curr);
+    }
+    // the constant value, or none if not a constant
+    std::unordered_map<LocalSet*, Literals> setValues;
+    // propagate constant values
+    while (!work.empty()) {
+      auto iter = work.begin();
+      auto* curr = *iter;
+      work.erase(iter);
+      // see if this set or get is actually a constant value, and if so,
+      // mark it as such and add everything it influences to the work list,
+      // as they may be constant too.
+      if (auto* set = curr->dynCast<LocalSet>()) {
+        if (setValues[set].isConcrete()) {
+          continue; // already known constant
+        }
+        auto values = setValues[set] =
+          precomputeValue(Properties::getFallthrough(
+            set->value, getPassOptions(), getModule()->features));
+        if (values.isConcrete()) {
+          for (auto* get : localGraph.setInfluences[set]) {
+            work.insert(get);
+          }
+        }
+      } else {
+        auto* get = curr->cast<LocalGet>();
+        if (getValues[get].size() >= 1) {
+          continue; // already known constant
+        }
+        // for this get to have constant value, all sets must agree
+        Literals values;
+        bool first = true;
+        for (auto* set : localGraph.getSetses[get]) {
+          Literals curr;
+          if (set == nullptr) {
+            if (getFunction()->isVar(get->index)) {
+              curr =
+                Literal::makeZeros(getFunction()->getLocalType(get->index));
+            } else {
+              // it's a param, so it's hopeless
+              values = {};
+              break;
+            }
+          } else {
+            curr = setValues[set];
+          }
+          if (curr.isNone()) {
+            // not a constant, give up
+            values = {};
+            break;
+          }
+          // we found a concrete value. compare with the current one
+          if (first) {
+            values = curr; // this is the first
+            first = false;
+          } else {
+            if (values != curr) {
+              // not the same, give up
+              values = {};
+              break;
+            }
+          }
+        }
+        // we may have found a value
+        if (values.isConcrete()) {
+          // we did!
+          getValues[get] = values;
+          for (auto* set : localGraph.getInfluences[get]) {
+            work.insert(set);
+          }
+        }
+      }
+    }
+  }
+};
+
+Pass* createPrecomputePass() { return new Precompute(false); }
+
+Pass* createPrecomputePropagatePass() { return new Precompute(true); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/Print.cpp b/binaryen/src/passes/Print.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/Print.cpp
@@ -0,0 +1,2808 @@
+/*
+ * 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.
+ */
+
+//
+// Print out text in s-expression format
+//
+
+#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 {
+
+namespace {
+
+bool isFullForced() {
+  if (getenv("BINARYEN_PRINT_FULL")) {
+    return std::stoi(getenv("BINARYEN_PRINT_FULL")) != 0;
+  }
+  return false;
+}
+
+std::ostream& printName(Name name, std::ostream& o) {
+  // we need to quote names if they have tricky chars
+  if (!name.str || !strpbrk(name.str, "()")) {
+    o << '$' << name.str;
+  } else {
+    o << "\"$" << name.str << '"';
+  }
+  return o;
+}
+
+static std::ostream& printLocal(Index index, Function* func, std::ostream& o) {
+  Name name;
+  if (func) {
+    name = func->getLocalNameOrDefault(index);
+  }
+  if (!name) {
+    name = Name::fromInt(index);
+  }
+  return printName(name, o);
+}
+
+// Unlike the default format, tuple types in s-expressions should not have
+// commas.
+struct SExprType {
+  Type type;
+  SExprType(Type type) : type(type){};
+};
+
+static std::ostream& operator<<(std::ostream& o, const SExprType& localType) {
+  Type type = localType.type;
+  if (type.isTuple()) {
+    o << '(';
+    auto sep = "";
+    for (const auto& t : type) {
+      o << sep << t;
+      sep = " ";
+    }
+    o << ')';
+  } else {
+    o << type;
+  }
+  return o;
+}
+
+// Wrapper for printing signature names
+struct SigName {
+  Signature sig;
+  SigName(Signature sig) : sig(sig) {}
+};
+
+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 = "_";
+      }
+    }
+  };
+
+  os << '$';
+  printType(sigName.sig.params);
+  os << "_=>_";
+  printType(sigName.sig.results);
+  return os;
+}
+
+} // anonymous namespace
+
+// Printing "unreachable" as a instruction prefix type is not valid in wasm text
+// format. Print something else to make it pass.
+static Type forceConcrete(Type type) {
+  return type.isConcrete() ? type : Type::i32;
+}
+
+// Prints the internal contents of an expression: everything but
+// the children.
+struct PrintExpressionContents
+  : public OverriddenVisitor<PrintExpressionContents> {
+  Function* currFunction = nullptr;
+  std::ostream& o;
+
+  PrintExpressionContents(Function* currFunction, std::ostream& o)
+    : currFunction(currFunction), o(o) {}
+
+  void visitBlock(Block* curr) {
+    printMedium(o, "block");
+    if (curr->name.is()) {
+      o << ' ';
+      printName(curr->name, o);
+    }
+    if (curr->type.isConcrete()) {
+      o << ' ' << ResultType(curr->type);
+    }
+  }
+  void visitIf(If* curr) {
+    printMedium(o, "if");
+    if (curr->type.isConcrete()) {
+      o << ' ' << ResultType(curr->type);
+    }
+  }
+  void visitLoop(Loop* curr) {
+    printMedium(o, "loop");
+    if (curr->name.is()) {
+      o << ' ';
+      printName(curr->name, o);
+    }
+    if (curr->type.isConcrete()) {
+      o << ' ' << ResultType(curr->type);
+    }
+  }
+  void visitBreak(Break* curr) {
+    if (curr->condition) {
+      printMedium(o, "br_if ");
+    } else {
+      printMedium(o, "br ");
+    }
+    printName(curr->name, o);
+  }
+  void visitSwitch(Switch* curr) {
+    printMedium(o, "br_table");
+    for (auto& t : curr->targets) {
+      o << ' ';
+      printName(t, o);
+    }
+    o << ' ';
+    printName(curr->default_, o);
+  }
+  void visitCall(Call* curr) {
+    if (curr->isReturn) {
+      printMedium(o, "return_call ");
+    } else {
+      printMedium(o, "call ");
+    }
+    printName(curr->target, o);
+  }
+  void visitCallIndirect(CallIndirect* curr) {
+    if (curr->isReturn) {
+      printMedium(o, "return_call_indirect (type ");
+    } else {
+      printMedium(o, "call_indirect (type ");
+    }
+    o << SigName(curr->sig) << ')';
+  }
+  void visitLocalGet(LocalGet* curr) {
+    printMedium(o, "local.get ");
+    printLocal(curr->index, currFunction, o);
+  }
+  void visitLocalSet(LocalSet* curr) {
+    if (curr->isTee()) {
+      printMedium(o, "local.tee ");
+    } else {
+      printMedium(o, "local.set ");
+    }
+    printLocal(curr->index, currFunction, o);
+  }
+  void visitGlobalGet(GlobalGet* curr) {
+    printMedium(o, "global.get ");
+    printName(curr->name, o);
+  }
+  void visitGlobalSet(GlobalSet* curr) {
+    printMedium(o, "global.set ");
+    printName(curr->name, o);
+  }
+  void visitLoad(Load* curr) {
+    prepareColor(o) << forceConcrete(curr->type);
+    if (curr->isAtomic) {
+      o << ".atomic";
+    }
+    o << ".load";
+    if (curr->type != Type::unreachable &&
+        curr->bytes < curr->type.getByteSize()) {
+      if (curr->bytes == 1) {
+        o << '8';
+      } else if (curr->bytes == 2) {
+        o << "16";
+      } else if (curr->bytes == 4) {
+        o << "32";
+      } else {
+        abort();
+      }
+      o << (curr->signed_ ? "_s" : "_u");
+    }
+    restoreNormalColor(o);
+    if (curr->offset) {
+      o << " offset=" << curr->offset;
+    }
+    if (curr->align != curr->bytes) {
+      o << " align=" << curr->align;
+    }
+  }
+  void visitStore(Store* curr) {
+    prepareColor(o) << forceConcrete(curr->valueType);
+    if (curr->isAtomic) {
+      o << ".atomic";
+    }
+    o << ".store";
+    if (curr->bytes < 4 || (curr->valueType == Type::i64 && curr->bytes < 8)) {
+      if (curr->bytes == 1) {
+        o << '8';
+      } else if (curr->bytes == 2) {
+        o << "16";
+      } else if (curr->bytes == 4) {
+        o << "32";
+      } else {
+        abort();
+      }
+    }
+    restoreNormalColor(o);
+    if (curr->offset) {
+      o << " offset=" << curr->offset;
+    }
+    if (curr->align != curr->bytes) {
+      o << " align=" << curr->align;
+    }
+  }
+  static void printRMWSize(std::ostream& o, Type type, uint8_t bytes) {
+    prepareColor(o) << forceConcrete(type) << ".atomic.rmw";
+    if (type != Type::unreachable && bytes != type.getByteSize()) {
+      if (bytes == 1) {
+        o << '8';
+      } else if (bytes == 2) {
+        o << "16";
+      } else if (bytes == 4) {
+        o << "32";
+      } else {
+        WASM_UNREACHABLE("invalid RMW byte length");
+      }
+    }
+    o << '.';
+  }
+  void visitAtomicRMW(AtomicRMW* curr) {
+    prepareColor(o);
+    printRMWSize(o, curr->type, curr->bytes);
+    switch (curr->op) {
+      case Add:
+        o << "add";
+        break;
+      case Sub:
+        o << "sub";
+        break;
+      case And:
+        o << "and";
+        break;
+      case Or:
+        o << "or";
+        break;
+      case Xor:
+        o << "xor";
+        break;
+      case Xchg:
+        o << "xchg";
+        break;
+    }
+    if (curr->type != Type::unreachable &&
+        curr->bytes != curr->type.getByteSize()) {
+      o << "_u";
+    }
+    restoreNormalColor(o);
+    if (curr->offset) {
+      o << " offset=" << curr->offset;
+    }
+  }
+  void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+    prepareColor(o);
+    printRMWSize(o, curr->type, curr->bytes);
+    o << "cmpxchg";
+    if (curr->type != Type::unreachable &&
+        curr->bytes != curr->type.getByteSize()) {
+      o << "_u";
+    }
+    restoreNormalColor(o);
+    if (curr->offset) {
+      o << " offset=" << curr->offset;
+    }
+  }
+  void visitAtomicWait(AtomicWait* curr) {
+    prepareColor(o);
+    o << forceConcrete(curr->expectedType) << ".atomic.wait";
+    if (curr->offset) {
+      o << " offset=" << curr->offset;
+    }
+  }
+  void visitAtomicNotify(AtomicNotify* curr) {
+    printMedium(o, "atomic.notify");
+    if (curr->offset) {
+      o << " offset=" << curr->offset;
+    }
+  }
+  void visitAtomicFence(AtomicFence* curr) { printMedium(o, "atomic.fence"); }
+  void visitSIMDExtract(SIMDExtract* curr) {
+    prepareColor(o);
+    switch (curr->op) {
+      case ExtractLaneSVecI8x16:
+        o << "i8x16.extract_lane_s";
+        break;
+      case ExtractLaneUVecI8x16:
+        o << "i8x16.extract_lane_u";
+        break;
+      case ExtractLaneSVecI16x8:
+        o << "i16x8.extract_lane_s";
+        break;
+      case ExtractLaneUVecI16x8:
+        o << "i16x8.extract_lane_u";
+        break;
+      case ExtractLaneVecI32x4:
+        o << "i32x4.extract_lane";
+        break;
+      case ExtractLaneVecI64x2:
+        o << "i64x2.extract_lane";
+        break;
+      case ExtractLaneVecF32x4:
+        o << "f32x4.extract_lane";
+        break;
+      case ExtractLaneVecF64x2:
+        o << "f64x2.extract_lane";
+        break;
+    }
+    o << " " << int(curr->index);
+  }
+  void visitSIMDReplace(SIMDReplace* curr) {
+    prepareColor(o);
+    switch (curr->op) {
+      case ReplaceLaneVecI8x16:
+        o << "i8x16.replace_lane";
+        break;
+      case ReplaceLaneVecI16x8:
+        o << "i16x8.replace_lane";
+        break;
+      case ReplaceLaneVecI32x4:
+        o << "i32x4.replace_lane";
+        break;
+      case ReplaceLaneVecI64x2:
+        o << "i64x2.replace_lane";
+        break;
+      case ReplaceLaneVecF32x4:
+        o << "f32x4.replace_lane";
+        break;
+      case ReplaceLaneVecF64x2:
+        o << "f64x2.replace_lane";
+        break;
+    }
+    o << " " << int(curr->index);
+  }
+  void visitSIMDShuffle(SIMDShuffle* curr) {
+    prepareColor(o);
+    o << "v8x16.shuffle";
+    for (uint8_t mask_index : curr->mask) {
+      o << " " << std::to_string(mask_index);
+    }
+  }
+  void visitSIMDTernary(SIMDTernary* curr) {
+    prepareColor(o);
+    switch (curr->op) {
+      case Bitselect:
+        o << "v128.bitselect";
+        break;
+      case QFMAF32x4:
+        o << "f32x4.qfma";
+        break;
+      case QFMSF32x4:
+        o << "f32x4.qfms";
+        break;
+      case QFMAF64x2:
+        o << "f64x2.qfma";
+        break;
+      case QFMSF64x2:
+        o << "f64x2.qfms";
+        break;
+    }
+  }
+  void visitSIMDShift(SIMDShift* curr) {
+    prepareColor(o);
+    switch (curr->op) {
+      case ShlVecI8x16:
+        o << "i8x16.shl";
+        break;
+      case ShrSVecI8x16:
+        o << "i8x16.shr_s";
+        break;
+      case ShrUVecI8x16:
+        o << "i8x16.shr_u";
+        break;
+      case ShlVecI16x8:
+        o << "i16x8.shl";
+        break;
+      case ShrSVecI16x8:
+        o << "i16x8.shr_s";
+        break;
+      case ShrUVecI16x8:
+        o << "i16x8.shr_u";
+        break;
+      case ShlVecI32x4:
+        o << "i32x4.shl";
+        break;
+      case ShrSVecI32x4:
+        o << "i32x4.shr_s";
+        break;
+      case ShrUVecI32x4:
+        o << "i32x4.shr_u";
+        break;
+      case ShlVecI64x2:
+        o << "i64x2.shl";
+        break;
+      case ShrSVecI64x2:
+        o << "i64x2.shr_s";
+        break;
+      case ShrUVecI64x2:
+        o << "i64x2.shr_u";
+        break;
+    }
+  }
+  void visitSIMDLoad(SIMDLoad* curr) {
+    prepareColor(o);
+    switch (curr->op) {
+      case LoadSplatVec8x16:
+        o << "v8x16.load_splat";
+        break;
+      case LoadSplatVec16x8:
+        o << "v16x8.load_splat";
+        break;
+      case LoadSplatVec32x4:
+        o << "v32x4.load_splat";
+        break;
+      case LoadSplatVec64x2:
+        o << "v64x2.load_splat";
+        break;
+      case LoadExtSVec8x8ToVecI16x8:
+        o << "i16x8.load8x8_s";
+        break;
+      case LoadExtUVec8x8ToVecI16x8:
+        o << "i16x8.load8x8_u";
+        break;
+      case LoadExtSVec16x4ToVecI32x4:
+        o << "i32x4.load16x4_s";
+        break;
+      case LoadExtUVec16x4ToVecI32x4:
+        o << "i32x4.load16x4_u";
+        break;
+      case LoadExtSVec32x2ToVecI64x2:
+        o << "i64x2.load32x2_s";
+        break;
+      case LoadExtUVec32x2ToVecI64x2:
+        o << "i64x2.load32x2_u";
+        break;
+      case Load32Zero:
+        o << "v128.load32_zero";
+        break;
+      case Load64Zero:
+        o << "v128.load64_zero";
+        break;
+    }
+    restoreNormalColor(o);
+    if (curr->offset) {
+      o << " offset=" << curr->offset;
+    }
+    if (curr->align != curr->getMemBytes()) {
+      o << " align=" << curr->align;
+    }
+  }
+  void visitMemoryInit(MemoryInit* curr) {
+    prepareColor(o);
+    o << "memory.init " << curr->segment;
+  }
+  void visitDataDrop(DataDrop* curr) {
+    prepareColor(o);
+    o << "data.drop " << curr->segment;
+  }
+  void visitMemoryCopy(MemoryCopy* curr) {
+    prepareColor(o);
+    o << "memory.copy";
+  }
+  void visitMemoryFill(MemoryFill* curr) {
+    prepareColor(o);
+    o << "memory.fill";
+  }
+  void visitConst(Const* curr) {
+    o << curr->value.type << ".const " << curr->value;
+  }
+  void visitUnary(Unary* curr) {
+    prepareColor(o);
+    switch (curr->op) {
+      case ClzInt32:
+        o << "i32.clz";
+        break;
+      case CtzInt32:
+        o << "i32.ctz";
+        break;
+      case PopcntInt32:
+        o << "i32.popcnt";
+        break;
+      case EqZInt32:
+        o << "i32.eqz";
+        break;
+      case ClzInt64:
+        o << "i64.clz";
+        break;
+      case CtzInt64:
+        o << "i64.ctz";
+        break;
+      case PopcntInt64:
+        o << "i64.popcnt";
+        break;
+      case EqZInt64:
+        o << "i64.eqz";
+        break;
+      case NegFloat32:
+        o << "f32.neg";
+        break;
+      case AbsFloat32:
+        o << "f32.abs";
+        break;
+      case CeilFloat32:
+        o << "f32.ceil";
+        break;
+      case FloorFloat32:
+        o << "f32.floor";
+        break;
+      case TruncFloat32:
+        o << "f32.trunc";
+        break;
+      case NearestFloat32:
+        o << "f32.nearest";
+        break;
+      case SqrtFloat32:
+        o << "f32.sqrt";
+        break;
+      case NegFloat64:
+        o << "f64.neg";
+        break;
+      case AbsFloat64:
+        o << "f64.abs";
+        break;
+      case CeilFloat64:
+        o << "f64.ceil";
+        break;
+      case FloorFloat64:
+        o << "f64.floor";
+        break;
+      case TruncFloat64:
+        o << "f64.trunc";
+        break;
+      case NearestFloat64:
+        o << "f64.nearest";
+        break;
+      case SqrtFloat64:
+        o << "f64.sqrt";
+        break;
+      case ExtendSInt32:
+        o << "i64.extend_i32_s";
+        break;
+      case ExtendUInt32:
+        o << "i64.extend_i32_u";
+        break;
+      case WrapInt64:
+        o << "i32.wrap_i64";
+        break;
+      case TruncSFloat32ToInt32:
+        o << "i32.trunc_f32_s";
+        break;
+      case TruncSFloat32ToInt64:
+        o << "i64.trunc_f32_s";
+        break;
+      case TruncUFloat32ToInt32:
+        o << "i32.trunc_f32_u";
+        break;
+      case TruncUFloat32ToInt64:
+        o << "i64.trunc_f32_u";
+        break;
+      case TruncSFloat64ToInt32:
+        o << "i32.trunc_f64_s";
+        break;
+      case TruncSFloat64ToInt64:
+        o << "i64.trunc_f64_s";
+        break;
+      case TruncUFloat64ToInt32:
+        o << "i32.trunc_f64_u";
+        break;
+      case TruncUFloat64ToInt64:
+        o << "i64.trunc_f64_u";
+        break;
+      case ReinterpretFloat32:
+        o << "i32.reinterpret_f32";
+        break;
+      case ReinterpretFloat64:
+        o << "i64.reinterpret_f64";
+        break;
+      case ConvertUInt32ToFloat32:
+        o << "f32.convert_i32_u";
+        break;
+      case ConvertUInt32ToFloat64:
+        o << "f64.convert_i32_u";
+        break;
+      case ConvertSInt32ToFloat32:
+        o << "f32.convert_i32_s";
+        break;
+      case ConvertSInt32ToFloat64:
+        o << "f64.convert_i32_s";
+        break;
+      case ConvertUInt64ToFloat32:
+        o << "f32.convert_i64_u";
+        break;
+      case ConvertUInt64ToFloat64:
+        o << "f64.convert_i64_u";
+        break;
+      case ConvertSInt64ToFloat32:
+        o << "f32.convert_i64_s";
+        break;
+      case ConvertSInt64ToFloat64:
+        o << "f64.convert_i64_s";
+        break;
+      case PromoteFloat32:
+        o << "f64.promote_f32";
+        break;
+      case DemoteFloat64:
+        o << "f32.demote_f64";
+        break;
+      case ReinterpretInt32:
+        o << "f32.reinterpret_i32";
+        break;
+      case ReinterpretInt64:
+        o << "f64.reinterpret_i64";
+        break;
+      case ExtendS8Int32:
+        o << "i32.extend8_s";
+        break;
+      case ExtendS16Int32:
+        o << "i32.extend16_s";
+        break;
+      case ExtendS8Int64:
+        o << "i64.extend8_s";
+        break;
+      case ExtendS16Int64:
+        o << "i64.extend16_s";
+        break;
+      case ExtendS32Int64:
+        o << "i64.extend32_s";
+        break;
+      case TruncSatSFloat32ToInt32:
+        o << "i32.trunc_sat_f32_s";
+        break;
+      case TruncSatUFloat32ToInt32:
+        o << "i32.trunc_sat_f32_u";
+        break;
+      case TruncSatSFloat64ToInt32:
+        o << "i32.trunc_sat_f64_s";
+        break;
+      case TruncSatUFloat64ToInt32:
+        o << "i32.trunc_sat_f64_u";
+        break;
+      case TruncSatSFloat32ToInt64:
+        o << "i64.trunc_sat_f32_s";
+        break;
+      case TruncSatUFloat32ToInt64:
+        o << "i64.trunc_sat_f32_u";
+        break;
+      case TruncSatSFloat64ToInt64:
+        o << "i64.trunc_sat_f64_s";
+        break;
+      case TruncSatUFloat64ToInt64:
+        o << "i64.trunc_sat_f64_u";
+        break;
+      case SplatVecI8x16:
+        o << "i8x16.splat";
+        break;
+      case SplatVecI16x8:
+        o << "i16x8.splat";
+        break;
+      case SplatVecI32x4:
+        o << "i32x4.splat";
+        break;
+      case SplatVecI64x2:
+        o << "i64x2.splat";
+        break;
+      case SplatVecF32x4:
+        o << "f32x4.splat";
+        break;
+      case SplatVecF64x2:
+        o << "f64x2.splat";
+        break;
+      case NotVec128:
+        o << "v128.not";
+        break;
+      case AbsVecI8x16:
+        o << "i8x16.abs";
+        break;
+      case NegVecI8x16:
+        o << "i8x16.neg";
+        break;
+      case AnyTrueVecI8x16:
+        o << "i8x16.any_true";
+        break;
+      case AllTrueVecI8x16:
+        o << "i8x16.all_true";
+        break;
+      case BitmaskVecI8x16:
+        o << "i8x16.bitmask";
+        break;
+      case AbsVecI16x8:
+        o << "i16x8.abs";
+        break;
+      case NegVecI16x8:
+        o << "i16x8.neg";
+        break;
+      case AnyTrueVecI16x8:
+        o << "i16x8.any_true";
+        break;
+      case AllTrueVecI16x8:
+        o << "i16x8.all_true";
+        break;
+      case BitmaskVecI16x8:
+        o << "i16x8.bitmask";
+        break;
+      case AbsVecI32x4:
+        o << "i32x4.abs";
+        break;
+      case NegVecI32x4:
+        o << "i32x4.neg";
+        break;
+      case AnyTrueVecI32x4:
+        o << "i32x4.any_true";
+        break;
+      case AllTrueVecI32x4:
+        o << "i32x4.all_true";
+        break;
+      case BitmaskVecI32x4:
+        o << "i32x4.bitmask";
+        break;
+      case NegVecI64x2:
+        o << "i64x2.neg";
+        break;
+      case AnyTrueVecI64x2:
+        o << "i64x2.any_true";
+        break;
+      case AllTrueVecI64x2:
+        o << "i64x2.all_true";
+        break;
+      case AbsVecF32x4:
+        o << "f32x4.abs";
+        break;
+      case NegVecF32x4:
+        o << "f32x4.neg";
+        break;
+      case SqrtVecF32x4:
+        o << "f32x4.sqrt";
+        break;
+      case CeilVecF32x4:
+        o << "f32x4.ceil";
+        break;
+      case FloorVecF32x4:
+        o << "f32x4.floor";
+        break;
+      case TruncVecF32x4:
+        o << "f32x4.trunc";
+        break;
+      case NearestVecF32x4:
+        o << "f32x4.nearest";
+        break;
+      case AbsVecF64x2:
+        o << "f64x2.abs";
+        break;
+      case NegVecF64x2:
+        o << "f64x2.neg";
+        break;
+      case SqrtVecF64x2:
+        o << "f64x2.sqrt";
+        break;
+      case CeilVecF64x2:
+        o << "f64x2.ceil";
+        break;
+      case FloorVecF64x2:
+        o << "f64x2.floor";
+        break;
+      case TruncVecF64x2:
+        o << "f64x2.trunc";
+        break;
+      case NearestVecF64x2:
+        o << "f64x2.nearest";
+        break;
+      case TruncSatSVecF32x4ToVecI32x4:
+        o << "i32x4.trunc_sat_f32x4_s";
+        break;
+      case TruncSatUVecF32x4ToVecI32x4:
+        o << "i32x4.trunc_sat_f32x4_u";
+        break;
+      case TruncSatSVecF64x2ToVecI64x2:
+        o << "i64x2.trunc_sat_f64x2_s";
+        break;
+      case TruncSatUVecF64x2ToVecI64x2:
+        o << "i64x2.trunc_sat_f64x2_u";
+        break;
+      case ConvertSVecI32x4ToVecF32x4:
+        o << "f32x4.convert_i32x4_s";
+        break;
+      case ConvertUVecI32x4ToVecF32x4:
+        o << "f32x4.convert_i32x4_u";
+        break;
+      case ConvertSVecI64x2ToVecF64x2:
+        o << "f64x2.convert_i64x2_s";
+        break;
+      case ConvertUVecI64x2ToVecF64x2:
+        o << "f64x2.convert_i64x2_u";
+        break;
+      case WidenLowSVecI8x16ToVecI16x8:
+        o << "i16x8.widen_low_i8x16_s";
+        break;
+      case WidenHighSVecI8x16ToVecI16x8:
+        o << "i16x8.widen_high_i8x16_s";
+        break;
+      case WidenLowUVecI8x16ToVecI16x8:
+        o << "i16x8.widen_low_i8x16_u";
+        break;
+      case WidenHighUVecI8x16ToVecI16x8:
+        o << "i16x8.widen_high_i8x16_u";
+        break;
+      case WidenLowSVecI16x8ToVecI32x4:
+        o << "i32x4.widen_low_i16x8_s";
+        break;
+      case WidenHighSVecI16x8ToVecI32x4:
+        o << "i32x4.widen_high_i16x8_s";
+        break;
+      case WidenLowUVecI16x8ToVecI32x4:
+        o << "i32x4.widen_low_i16x8_u";
+        break;
+      case WidenHighUVecI16x8ToVecI32x4:
+        o << "i32x4.widen_high_i16x8_u";
+        break;
+      case InvalidUnary:
+        WASM_UNREACHABLE("unvalid unary operator");
+    }
+  }
+  void visitBinary(Binary* curr) {
+    prepareColor(o);
+    switch (curr->op) {
+      case AddInt32:
+        o << "i32.add";
+        break;
+      case SubInt32:
+        o << "i32.sub";
+        break;
+      case MulInt32:
+        o << "i32.mul";
+        break;
+      case DivSInt32:
+        o << "i32.div_s";
+        break;
+      case DivUInt32:
+        o << "i32.div_u";
+        break;
+      case RemSInt32:
+        o << "i32.rem_s";
+        break;
+      case RemUInt32:
+        o << "i32.rem_u";
+        break;
+      case AndInt32:
+        o << "i32.and";
+        break;
+      case OrInt32:
+        o << "i32.or";
+        break;
+      case XorInt32:
+        o << "i32.xor";
+        break;
+      case ShlInt32:
+        o << "i32.shl";
+        break;
+      case ShrUInt32:
+        o << "i32.shr_u";
+        break;
+      case ShrSInt32:
+        o << "i32.shr_s";
+        break;
+      case RotLInt32:
+        o << "i32.rotl";
+        break;
+      case RotRInt32:
+        o << "i32.rotr";
+        break;
+      case EqInt32:
+        o << "i32.eq";
+        break;
+      case NeInt32:
+        o << "i32.ne";
+        break;
+      case LtSInt32:
+        o << "i32.lt_s";
+        break;
+      case LtUInt32:
+        o << "i32.lt_u";
+        break;
+      case LeSInt32:
+        o << "i32.le_s";
+        break;
+      case LeUInt32:
+        o << "i32.le_u";
+        break;
+      case GtSInt32:
+        o << "i32.gt_s";
+        break;
+      case GtUInt32:
+        o << "i32.gt_u";
+        break;
+      case GeSInt32:
+        o << "i32.ge_s";
+        break;
+      case GeUInt32:
+        o << "i32.ge_u";
+        break;
+
+      case AddInt64:
+        o << "i64.add";
+        break;
+      case SubInt64:
+        o << "i64.sub";
+        break;
+      case MulInt64:
+        o << "i64.mul";
+        break;
+      case DivSInt64:
+        o << "i64.div_s";
+        break;
+      case DivUInt64:
+        o << "i64.div_u";
+        break;
+      case RemSInt64:
+        o << "i64.rem_s";
+        break;
+      case RemUInt64:
+        o << "i64.rem_u";
+        break;
+      case AndInt64:
+        o << "i64.and";
+        break;
+      case OrInt64:
+        o << "i64.or";
+        break;
+      case XorInt64:
+        o << "i64.xor";
+        break;
+      case ShlInt64:
+        o << "i64.shl";
+        break;
+      case ShrUInt64:
+        o << "i64.shr_u";
+        break;
+      case ShrSInt64:
+        o << "i64.shr_s";
+        break;
+      case RotLInt64:
+        o << "i64.rotl";
+        break;
+      case RotRInt64:
+        o << "i64.rotr";
+        break;
+      case EqInt64:
+        o << "i64.eq";
+        break;
+      case NeInt64:
+        o << "i64.ne";
+        break;
+      case LtSInt64:
+        o << "i64.lt_s";
+        break;
+      case LtUInt64:
+        o << "i64.lt_u";
+        break;
+      case LeSInt64:
+        o << "i64.le_s";
+        break;
+      case LeUInt64:
+        o << "i64.le_u";
+        break;
+      case GtSInt64:
+        o << "i64.gt_s";
+        break;
+      case GtUInt64:
+        o << "i64.gt_u";
+        break;
+      case GeSInt64:
+        o << "i64.ge_s";
+        break;
+      case GeUInt64:
+        o << "i64.ge_u";
+        break;
+
+      case AddFloat32:
+        o << "f32.add";
+        break;
+      case SubFloat32:
+        o << "f32.sub";
+        break;
+      case MulFloat32:
+        o << "f32.mul";
+        break;
+      case DivFloat32:
+        o << "f32.div";
+        break;
+      case CopySignFloat32:
+        o << "f32.copysign";
+        break;
+      case MinFloat32:
+        o << "f32.min";
+        break;
+      case MaxFloat32:
+        o << "f32.max";
+        break;
+      case EqFloat32:
+        o << "f32.eq";
+        break;
+      case NeFloat32:
+        o << "f32.ne";
+        break;
+      case LtFloat32:
+        o << "f32.lt";
+        break;
+      case LeFloat32:
+        o << "f32.le";
+        break;
+      case GtFloat32:
+        o << "f32.gt";
+        break;
+      case GeFloat32:
+        o << "f32.ge";
+        break;
+
+      case AddFloat64:
+        o << "f64.add";
+        break;
+      case SubFloat64:
+        o << "f64.sub";
+        break;
+      case MulFloat64:
+        o << "f64.mul";
+        break;
+      case DivFloat64:
+        o << "f64.div";
+        break;
+      case CopySignFloat64:
+        o << "f64.copysign";
+        break;
+      case MinFloat64:
+        o << "f64.min";
+        break;
+      case MaxFloat64:
+        o << "f64.max";
+        break;
+      case EqFloat64:
+        o << "f64.eq";
+        break;
+      case NeFloat64:
+        o << "f64.ne";
+        break;
+      case LtFloat64:
+        o << "f64.lt";
+        break;
+      case LeFloat64:
+        o << "f64.le";
+        break;
+      case GtFloat64:
+        o << "f64.gt";
+        break;
+      case GeFloat64:
+        o << "f64.ge";
+        break;
+
+      case EqVecI8x16:
+        o << "i8x16.eq";
+        break;
+      case NeVecI8x16:
+        o << "i8x16.ne";
+        break;
+      case LtSVecI8x16:
+        o << "i8x16.lt_s";
+        break;
+      case LtUVecI8x16:
+        o << "i8x16.lt_u";
+        break;
+      case GtSVecI8x16:
+        o << "i8x16.gt_s";
+        break;
+      case GtUVecI8x16:
+        o << "i8x16.gt_u";
+        break;
+      case LeSVecI8x16:
+        o << "i8x16.le_s";
+        break;
+      case LeUVecI8x16:
+        o << "i8x16.le_u";
+        break;
+      case GeSVecI8x16:
+        o << "i8x16.ge_s";
+        break;
+      case GeUVecI8x16:
+        o << "i8x16.ge_u";
+        break;
+      case EqVecI16x8:
+        o << "i16x8.eq";
+        break;
+      case NeVecI16x8:
+        o << "i16x8.ne";
+        break;
+      case LtSVecI16x8:
+        o << "i16x8.lt_s";
+        break;
+      case LtUVecI16x8:
+        o << "i16x8.lt_u";
+        break;
+      case GtSVecI16x8:
+        o << "i16x8.gt_s";
+        break;
+      case GtUVecI16x8:
+        o << "i16x8.gt_u";
+        break;
+      case LeSVecI16x8:
+        o << "i16x8.le_s";
+        break;
+      case LeUVecI16x8:
+        o << "i16x8.le_u";
+        break;
+      case GeSVecI16x8:
+        o << "i16x8.ge_s";
+        break;
+      case GeUVecI16x8:
+        o << "i16x8.ge_u";
+        break;
+      case EqVecI32x4:
+        o << "i32x4.eq";
+        break;
+      case NeVecI32x4:
+        o << "i32x4.ne";
+        break;
+      case LtSVecI32x4:
+        o << "i32x4.lt_s";
+        break;
+      case LtUVecI32x4:
+        o << "i32x4.lt_u";
+        break;
+      case GtSVecI32x4:
+        o << "i32x4.gt_s";
+        break;
+      case GtUVecI32x4:
+        o << "i32x4.gt_u";
+        break;
+      case LeSVecI32x4:
+        o << "i32x4.le_s";
+        break;
+      case LeUVecI32x4:
+        o << "i32x4.le_u";
+        break;
+      case GeSVecI32x4:
+        o << "i32x4.ge_s";
+        break;
+      case GeUVecI32x4:
+        o << "i32x4.ge_u";
+        break;
+      case EqVecF32x4:
+        o << "f32x4.eq";
+        break;
+      case NeVecF32x4:
+        o << "f32x4.ne";
+        break;
+      case LtVecF32x4:
+        o << "f32x4.lt";
+        break;
+      case GtVecF32x4:
+        o << "f32x4.gt";
+        break;
+      case LeVecF32x4:
+        o << "f32x4.le";
+        break;
+      case GeVecF32x4:
+        o << "f32x4.ge";
+        break;
+      case EqVecF64x2:
+        o << "f64x2.eq";
+        break;
+      case NeVecF64x2:
+        o << "f64x2.ne";
+        break;
+      case LtVecF64x2:
+        o << "f64x2.lt";
+        break;
+      case GtVecF64x2:
+        o << "f64x2.gt";
+        break;
+      case LeVecF64x2:
+        o << "f64x2.le";
+        break;
+      case GeVecF64x2:
+        o << "f64x2.ge";
+        break;
+
+      case AndVec128:
+        o << "v128.and";
+        break;
+      case OrVec128:
+        o << "v128.or";
+        break;
+      case XorVec128:
+        o << "v128.xor";
+        break;
+      case AndNotVec128:
+        o << "v128.andnot";
+        break;
+
+      case AddVecI8x16:
+        o << "i8x16.add";
+        break;
+      case AddSatSVecI8x16:
+        o << "i8x16.add_saturate_s";
+        break;
+      case AddSatUVecI8x16:
+        o << "i8x16.add_saturate_u";
+        break;
+      case SubVecI8x16:
+        o << "i8x16.sub";
+        break;
+      case SubSatSVecI8x16:
+        o << "i8x16.sub_saturate_s";
+        break;
+      case SubSatUVecI8x16:
+        o << "i8x16.sub_saturate_u";
+        break;
+      case MulVecI8x16:
+        o << "i8x16.mul";
+        break;
+      case MinSVecI8x16:
+        o << "i8x16.min_s";
+        break;
+      case MinUVecI8x16:
+        o << "i8x16.min_u";
+        break;
+      case MaxSVecI8x16:
+        o << "i8x16.max_s";
+        break;
+      case MaxUVecI8x16:
+        o << "i8x16.max_u";
+        break;
+      case AvgrUVecI8x16:
+        o << "i8x16.avgr_u";
+        break;
+      case AddVecI16x8:
+        o << "i16x8.add";
+        break;
+      case AddSatSVecI16x8:
+        o << "i16x8.add_saturate_s";
+        break;
+      case AddSatUVecI16x8:
+        o << "i16x8.add_saturate_u";
+        break;
+      case SubVecI16x8:
+        o << "i16x8.sub";
+        break;
+      case SubSatSVecI16x8:
+        o << "i16x8.sub_saturate_s";
+        break;
+      case SubSatUVecI16x8:
+        o << "i16x8.sub_saturate_u";
+        break;
+      case MulVecI16x8:
+        o << "i16x8.mul";
+        break;
+      case MinSVecI16x8:
+        o << "i16x8.min_s";
+        break;
+      case MinUVecI16x8:
+        o << "i16x8.min_u";
+        break;
+      case MaxSVecI16x8:
+        o << "i16x8.max_s";
+        break;
+      case MaxUVecI16x8:
+        o << "i16x8.max_u";
+        break;
+      case AvgrUVecI16x8:
+        o << "i16x8.avgr_u";
+        break;
+      case AddVecI32x4:
+        o << "i32x4.add";
+        break;
+      case SubVecI32x4:
+        o << "i32x4.sub";
+        break;
+      case MulVecI32x4:
+        o << "i32x4.mul";
+        break;
+      case MinSVecI32x4:
+        o << "i32x4.min_s";
+        break;
+      case MinUVecI32x4:
+        o << "i32x4.min_u";
+        break;
+      case MaxSVecI32x4:
+        o << "i32x4.max_s";
+        break;
+      case MaxUVecI32x4:
+        o << "i32x4.max_u";
+        break;
+      case DotSVecI16x8ToVecI32x4:
+        o << "i32x4.dot_i16x8_s";
+        break;
+      case AddVecI64x2:
+        o << "i64x2.add";
+        break;
+      case SubVecI64x2:
+        o << "i64x2.sub";
+        break;
+      case MulVecI64x2:
+        o << "i64x2.mul";
+        break;
+
+      case AddVecF32x4:
+        o << "f32x4.add";
+        break;
+      case SubVecF32x4:
+        o << "f32x4.sub";
+        break;
+      case MulVecF32x4:
+        o << "f32x4.mul";
+        break;
+      case DivVecF32x4:
+        o << "f32x4.div";
+        break;
+      case MinVecF32x4:
+        o << "f32x4.min";
+        break;
+      case MaxVecF32x4:
+        o << "f32x4.max";
+        break;
+      case PMinVecF32x4:
+        o << "f32x4.pmin";
+        break;
+      case PMaxVecF32x4:
+        o << "f32x4.pmax";
+        break;
+      case AddVecF64x2:
+        o << "f64x2.add";
+        break;
+      case SubVecF64x2:
+        o << "f64x2.sub";
+        break;
+      case MulVecF64x2:
+        o << "f64x2.mul";
+        break;
+      case DivVecF64x2:
+        o << "f64x2.div";
+        break;
+      case MinVecF64x2:
+        o << "f64x2.min";
+        break;
+      case MaxVecF64x2:
+        o << "f64x2.max";
+        break;
+      case PMinVecF64x2:
+        o << "f64x2.pmin";
+        break;
+      case PMaxVecF64x2:
+        o << "f64x2.pmax";
+        break;
+
+      case NarrowSVecI16x8ToVecI8x16:
+        o << "i8x16.narrow_i16x8_s";
+        break;
+      case NarrowUVecI16x8ToVecI8x16:
+        o << "i8x16.narrow_i16x8_u";
+        break;
+      case NarrowSVecI32x4ToVecI16x8:
+        o << "i16x8.narrow_i32x4_s";
+        break;
+      case NarrowUVecI32x4ToVecI16x8:
+        o << "i16x8.narrow_i32x4_u";
+        break;
+
+      case SwizzleVec8x16:
+        o << "v8x16.swizzle";
+        break;
+
+      case InvalidBinary:
+        WASM_UNREACHABLE("unvalid binary operator");
+    }
+    restoreNormalColor(o);
+  }
+  void visitSelect(Select* curr) {
+    prepareColor(o) << "select";
+    if (curr->type.isRef()) {
+      o << " (result " << curr->type << ')';
+    }
+  }
+  void visitDrop(Drop* curr) { printMedium(o, "drop"); }
+  void visitReturn(Return* curr) { printMedium(o, "return"); }
+  void visitMemorySize(MemorySize* curr) { printMedium(o, "memory.size"); }
+  void visitMemoryGrow(MemoryGrow* curr) { printMedium(o, "memory.grow"); }
+  void visitRefNull(RefNull* curr) {
+    printMedium(o, "ref.null ");
+    o << curr->type.getHeapType();
+  }
+  void visitRefIsNull(RefIsNull* curr) { printMedium(o, "ref.is_null"); }
+  void visitRefFunc(RefFunc* curr) {
+    printMedium(o, "ref.func ");
+    printName(curr->func, o);
+  }
+  void visitRefEq(RefEq* curr) { printMedium(o, "ref.eq"); }
+  void visitTry(Try* curr) {
+    printMedium(o, "try");
+    if (curr->type.isConcrete()) {
+      o << ' ' << ResultType(curr->type);
+    }
+  }
+  void visitThrow(Throw* curr) {
+    printMedium(o, "throw ");
+    printName(curr->event, o);
+  }
+  void visitRethrow(Rethrow* curr) { printMedium(o, "rethrow"); }
+  void visitBrOnExn(BrOnExn* curr) {
+    printMedium(o, "br_on_exn ");
+    printName(curr->name, o);
+    o << " ";
+    printName(curr->event, o);
+  }
+  void visitNop(Nop* curr) { printMinor(o, "nop"); }
+  void visitUnreachable(Unreachable* curr) { printMinor(o, "unreachable"); }
+  void visitPop(Pop* curr) {
+    prepareColor(o) << "pop";
+    for (auto type : curr->type) {
+      assert(type.isBasic() && "TODO: print and parse compound types");
+      o << " " << type;
+    }
+    restoreNormalColor(o);
+  }
+  void visitTupleMake(TupleMake* curr) { printMedium(o, "tuple.make"); }
+  void visitTupleExtract(TupleExtract* curr) {
+    printMedium(o, "tuple.extract ");
+    o << curr->index;
+  }
+  void visitI31New(I31New* curr) { printMedium(o, "i31.new"); }
+  void visitI31Get(I31Get* curr) {
+    printMedium(o, curr->signed_ ? "i31.get_s" : "i31.get_u");
+  }
+  void visitRefTest(RefTest* curr) {
+    printMedium(o, "ref.test");
+    WASM_UNREACHABLE("TODO (gc): ref.test");
+  }
+  void visitRefCast(RefCast* curr) {
+    printMedium(o, "ref.cast");
+    WASM_UNREACHABLE("TODO (gc): ref.cast");
+  }
+  void visitBrOnCast(BrOnCast* curr) {
+    printMedium(o, "br_on_cast");
+    WASM_UNREACHABLE("TODO (gc): br_on_cast");
+  }
+  void visitRttCanon(RttCanon* curr) {
+    printMedium(o, "rtt.canon");
+    WASM_UNREACHABLE("TODO (gc): rtt.canon");
+  }
+  void visitRttSub(RttSub* curr) {
+    printMedium(o, "rtt.sub");
+    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) {
+    printMedium(o, "struct.set");
+    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) {
+    printMedium(o, "array.set");
+    WASM_UNREACHABLE("TODO (gc): array.set");
+  }
+  void visitArrayLen(ArrayLen* curr) {
+    printMedium(o, "array.len");
+    WASM_UNREACHABLE("TODO (gc): array.len");
+  }
+};
+
+// Prints an expression in s-expr format, including both the
+// internal contents and the nested children.
+struct PrintSExpression : public OverriddenVisitor<PrintSExpression> {
+  std::ostream& o;
+  unsigned indent = 0;
+
+  bool minify;
+  const char* maybeSpace;
+  const char* maybeNewLine;
+
+  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)
+
+  Module* currModule = nullptr;
+  Function* currFunction = nullptr;
+  Function::DebugLocation lastPrintedLocation;
+  bool debugInfo;
+
+  PrintSExpression(std::ostream& o) : o(o) {
+    setMinify(false);
+    if (!full) {
+      full = isFullForced();
+    }
+  }
+
+  void printDebugLocation(const Function::DebugLocation& location) {
+    if (lastPrintedLocation == location) {
+      return;
+    }
+    lastPrintedLocation = location;
+    auto fileName = currModule->debugInfoFileNames[location.fileIndex];
+    o << ";;@ " << fileName << ":" << location.lineNumber << ":"
+      << location.columnNumber << '\n';
+    doIndent(o, indent);
+  }
+
+  void printDebugLocation(Expression* curr) {
+    if (currFunction) {
+      // show an annotation, if there is one
+      auto& debugLocations = currFunction->debugLocations;
+      auto iter = debugLocations.find(curr);
+      if (iter != debugLocations.end()) {
+        printDebugLocation(iter->second);
+      }
+      // show a binary position, if there is one
+      if (debugInfo) {
+        auto iter = currFunction->expressionLocations.find(curr);
+        if (iter != currFunction->expressionLocations.end()) {
+          Colors::grey(o);
+          o << ";; code offset: 0x" << std::hex << iter->second.start
+            << std::dec << '\n';
+          restoreNormalColor(o);
+          doIndent(o, indent);
+        }
+      }
+    }
+  }
+
+  void visit(Expression* curr) {
+    printDebugLocation(curr);
+    OverriddenVisitor<PrintSExpression>::visit(curr);
+  }
+
+  void setMinify(bool minify_) {
+    minify = minify_;
+    maybeSpace = minify ? "" : " ";
+    maybeNewLine = minify ? "" : "\n";
+  }
+
+  void setFull(bool full_) { full = full_; }
+
+  void setPrintStackIR(bool printStackIR_) { printStackIR = printStackIR_; }
+
+  void setDebugInfo(bool debugInfo_) { debugInfo = debugInfo_; }
+
+  void incIndent() {
+    if (minify) {
+      return;
+    }
+    o << '\n';
+    indent++;
+  }
+  void decIndent() {
+    if (!minify) {
+      assert(indent > 0);
+      indent--;
+      doIndent(o, indent);
+    }
+    o << ')';
+  }
+  void printFullLine(Expression* expression) {
+    if (!minify) {
+      doIndent(o, indent);
+    }
+    if (full) {
+      o << "[" << expression->type << "] ";
+    }
+    visit(expression);
+    o << maybeNewLine;
+  }
+
+  // loop, if, and try can contain implicit blocks. But they are not needed to
+  // be printed in some cases.
+  void maybePrintImplicitBlock(Expression* curr, bool allowMultipleInsts) {
+    auto block = curr->dynCast<Block>();
+    if (!full && block && block->name.isNull() &&
+        (allowMultipleInsts || block->list.size() == 1)) {
+      for (auto expression : block->list) {
+        printFullLine(expression);
+      }
+    } else {
+      printFullLine(curr);
+    }
+  }
+
+  void visitBlock(Block* curr) {
+    // special-case Block, because Block nesting (in their first element) can be
+    // incredibly deep
+    std::vector<Block*> stack;
+    while (1) {
+      if (stack.size() > 0) {
+        doIndent(o, indent);
+        printDebugLocation(curr);
+      }
+      stack.push_back(curr);
+      if (full) {
+        o << "[" << curr->type << "] ";
+      }
+      o << '(';
+      PrintExpressionContents(currFunction, o).visit(curr);
+      incIndent();
+      if (curr->list.size() > 0 && curr->list[0]->is<Block>()) {
+        // recurse into the first element
+        curr = curr->list[0]->cast<Block>();
+        continue;
+      } else {
+        break; // that's all we can recurse, start to unwind
+      }
+    }
+    auto* top = stack.back();
+    while (stack.size() > 0) {
+      curr = stack.back();
+      stack.pop_back();
+      auto& list = curr->list;
+      for (size_t i = 0; i < list.size(); i++) {
+        if (curr != top && i == 0) {
+          // one of the block recursions we already handled
+          decIndent();
+          if (full) {
+            o << " ;; end block";
+            auto* child = list[0]->cast<Block>();
+            if (child->name.is()) {
+              o << ' ' << child->name;
+            }
+          }
+          o << '\n';
+          continue;
+        }
+        printFullLine(list[i]);
+      }
+    }
+    decIndent();
+    if (full) {
+      o << " ;; end block";
+      if (curr->name.is()) {
+        o << ' ' << curr->name;
+      }
+    }
+  }
+  void visitIf(If* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->condition);
+    maybePrintImplicitBlock(curr->ifTrue, false);
+    if (curr->ifFalse) {
+      maybePrintImplicitBlock(curr->ifFalse, false);
+    }
+    decIndent();
+    if (full) {
+      o << " ;; end if";
+    }
+  }
+  void visitLoop(Loop* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    maybePrintImplicitBlock(curr->body, true);
+    decIndent();
+    if (full) {
+      o << " ;; end loop";
+      if (curr->name.is()) {
+        o << ' ' << curr->name;
+      }
+    }
+  }
+  void visitBreak(Break* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    if (curr->condition) {
+      incIndent();
+    } else {
+      if (!curr->value || curr->value->is<Nop>()) {
+        // avoid a new line just for the parens
+        o << ')';
+        return;
+      }
+      incIndent();
+    }
+    if (curr->value && !curr->value->is<Nop>()) {
+      printFullLine(curr->value);
+    }
+    if (curr->condition) {
+      printFullLine(curr->condition);
+    }
+    decIndent();
+  }
+  void visitSwitch(Switch* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    if (curr->value && !curr->value->is<Nop>()) {
+      printFullLine(curr->value);
+    }
+    printFullLine(curr->condition);
+    decIndent();
+  }
+
+  template<typename CallBase> void printCallOperands(CallBase* curr) {
+    if (curr->operands.size() > 0) {
+      incIndent();
+      for (auto operand : curr->operands) {
+        printFullLine(operand);
+      }
+      decIndent();
+    } else {
+      o << ')';
+    }
+  }
+
+  void visitCall(Call* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    printCallOperands(curr);
+  }
+  void visitCallIndirect(CallIndirect* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    for (auto operand : curr->operands) {
+      printFullLine(operand);
+    }
+    printFullLine(curr->target);
+    decIndent();
+  }
+  void visitLocalGet(LocalGet* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    o << ')';
+  }
+  void visitLocalSet(LocalSet* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->value);
+    decIndent();
+  }
+  void visitGlobalGet(GlobalGet* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    o << ')';
+  }
+  void visitGlobalSet(GlobalSet* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->value);
+    decIndent();
+  }
+  void visitLoad(Load* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->ptr);
+    decIndent();
+  }
+  void visitStore(Store* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->ptr);
+    printFullLine(curr->value);
+    decIndent();
+  }
+  void visitAtomicRMW(AtomicRMW* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->ptr);
+    printFullLine(curr->value);
+    decIndent();
+  }
+  void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->ptr);
+    printFullLine(curr->expected);
+    printFullLine(curr->replacement);
+    decIndent();
+  }
+  void visitAtomicWait(AtomicWait* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    restoreNormalColor(o);
+    incIndent();
+    printFullLine(curr->ptr);
+    printFullLine(curr->expected);
+    printFullLine(curr->timeout);
+    decIndent();
+  }
+  void visitAtomicNotify(AtomicNotify* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->ptr);
+    printFullLine(curr->notifyCount);
+    decIndent();
+  }
+  void visitAtomicFence(AtomicFence* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    o << ')';
+  }
+  void visitSIMDExtract(SIMDExtract* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->vec);
+    decIndent();
+  }
+  void visitSIMDReplace(SIMDReplace* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->vec);
+    printFullLine(curr->value);
+    decIndent();
+  }
+  void visitSIMDShuffle(SIMDShuffle* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->left);
+    printFullLine(curr->right);
+    decIndent();
+  }
+  void visitSIMDTernary(SIMDTernary* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->a);
+    printFullLine(curr->b);
+    printFullLine(curr->c);
+    decIndent();
+  }
+  void visitSIMDShift(SIMDShift* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->vec);
+    printFullLine(curr->shift);
+    decIndent();
+  }
+  void visitSIMDLoad(SIMDLoad* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->ptr);
+    decIndent();
+  }
+  void visitMemoryInit(MemoryInit* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->dest);
+    printFullLine(curr->offset);
+    printFullLine(curr->size);
+    decIndent();
+  }
+  void visitDataDrop(DataDrop* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    o << ')';
+  }
+  void visitMemoryCopy(MemoryCopy* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->dest);
+    printFullLine(curr->source);
+    printFullLine(curr->size);
+    decIndent();
+  }
+  void visitMemoryFill(MemoryFill* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->dest);
+    printFullLine(curr->value);
+    printFullLine(curr->size);
+    decIndent();
+  }
+  void visitConst(Const* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    o << ')';
+  }
+  void visitUnary(Unary* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->value);
+    decIndent();
+  }
+  void visitBinary(Binary* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->left);
+    printFullLine(curr->right);
+    decIndent();
+  }
+  void visitSelect(Select* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->ifTrue);
+    printFullLine(curr->ifFalse);
+    printFullLine(curr->condition);
+    decIndent();
+  }
+  void visitDrop(Drop* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->value);
+    decIndent();
+  }
+  void visitReturn(Return* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    if (!curr->value) {
+      // avoid a new line just for the parens
+      o << ')';
+      return;
+    }
+    incIndent();
+    printFullLine(curr->value);
+    decIndent();
+  }
+  void visitMemorySize(MemorySize* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    o << ')';
+  }
+  void visitMemoryGrow(MemoryGrow* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->delta);
+    decIndent();
+  }
+  void visitRefNull(RefNull* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    o << ')';
+  }
+  void visitRefIsNull(RefIsNull* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->value);
+    decIndent();
+  }
+  void visitRefFunc(RefFunc* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    o << ')';
+  }
+  void visitRefEq(RefEq* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->left);
+    printFullLine(curr->right);
+    decIndent();
+  }
+  // try-catch-end is written in the folded wat format as
+  // (try
+  //  (do
+  //   ...
+  //  )
+  //  (catch
+  //   ...
+  //  )
+  // )
+  // The parenthesis wrapping 'catch' is just a syntax and does not affect
+  // nested depths of instructions within.
+  void visitTry(Try* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    doIndent(o, indent);
+    o << "(do";
+    incIndent();
+    maybePrintImplicitBlock(curr->body, true);
+    decIndent();
+    o << "\n";
+    doIndent(o, indent);
+    o << "(catch";
+    incIndent();
+    maybePrintImplicitBlock(curr->catchBody, true);
+    decIndent();
+    o << "\n";
+    decIndent();
+    if (full) {
+      o << " ;; end try";
+    }
+  }
+  void visitThrow(Throw* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    for (auto operand : curr->operands) {
+      printFullLine(operand);
+    }
+    decIndent();
+  }
+  void visitRethrow(Rethrow* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->exnref);
+    decIndent();
+  }
+  void visitBrOnExn(BrOnExn* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->exnref);
+    decIndent();
+  }
+  void visitNop(Nop* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    o << ')';
+  }
+  void visitUnreachable(Unreachable* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    o << ')';
+  }
+  void visitPop(Pop* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    o << ')';
+  }
+  void visitTupleMake(TupleMake* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    for (auto operand : curr->operands) {
+      printFullLine(operand);
+    }
+    decIndent();
+  }
+  void visitTupleExtract(TupleExtract* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->tuple);
+    decIndent();
+  }
+  void visitI31New(I31New* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->value);
+    decIndent();
+  }
+  void visitI31Get(I31Get* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->i31);
+    decIndent();
+  }
+  void visitRefTest(RefTest* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    WASM_UNREACHABLE("TODO (gc): ref.test");
+  }
+  void visitRefCast(RefCast* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    WASM_UNREACHABLE("TODO (gc): ref.cast");
+  }
+  void visitBrOnCast(BrOnCast* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    WASM_UNREACHABLE("TODO (gc): br_on_cast");
+  }
+  void visitRttCanon(RttCanon* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    WASM_UNREACHABLE("TODO (gc): rtt.canon");
+  }
+  void visitRttSub(RttSub* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    WASM_UNREACHABLE("TODO (gc): rtt.sub");
+  }
+  void visitStructNew(StructNew* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    WASM_UNREACHABLE("TODO (gc): struct.new");
+  }
+  void visitStructGet(StructGet* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    WASM_UNREACHABLE("TODO (gc): struct.get");
+  }
+  void visitStructSet(StructSet* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    WASM_UNREACHABLE("TODO (gc): struct.set");
+  }
+  void visitArrayNew(ArrayNew* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    WASM_UNREACHABLE("TODO (gc): array.new");
+  }
+  void visitArrayGet(ArrayGet* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    WASM_UNREACHABLE("TODO (gc): array.get");
+  }
+  void visitArraySet(ArraySet* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    WASM_UNREACHABLE("TODO (gc): array.set");
+  }
+  void visitArrayLen(ArrayLen* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    WASM_UNREACHABLE("TODO (gc): array.len");
+  }
+  // Module-level visitors
+  void handleSignature(Signature curr, Name* funcName = nullptr) {
+    o << "(func";
+    if (funcName) {
+      o << " $" << *funcName;
+    }
+    if (curr.params.size() > 0) {
+      o << maybeSpace;
+      o << ParamType(curr.params);
+    }
+    if (curr.results.size() > 0) {
+      o << maybeSpace;
+      o << ResultType(curr.results);
+    }
+    o << ")";
+  }
+  void visitExport(Export* curr) {
+    o << '(';
+    printMedium(o, "export ");
+    printText(o, curr->name.str) << " (";
+    switch (curr->kind) {
+      case ExternalKind::Function:
+        o << "func";
+        break;
+      case ExternalKind::Table:
+        o << "table";
+        break;
+      case ExternalKind::Memory:
+        o << "memory";
+        break;
+      case ExternalKind::Global:
+        o << "global";
+        break;
+      case ExternalKind::Event:
+        o << "event";
+        break;
+      case ExternalKind::Invalid:
+        WASM_UNREACHABLE("invalid ExternalKind");
+    }
+    o << ' ';
+    printName(curr->value, o) << "))";
+  }
+  void emitImportHeader(Importable* curr) {
+    printMedium(o, "import ");
+    printText(o, curr->module.str) << ' ';
+    printText(o, curr->base.str) << ' ';
+  }
+  void visitGlobal(Global* curr) {
+    if (curr->imported()) {
+      visitImportedGlobal(curr);
+    } else {
+      visitDefinedGlobal(curr);
+    }
+  }
+  void emitGlobalType(Global* curr) {
+    if (curr->mutable_) {
+      o << "(mut " << SExprType(curr->type) << ')';
+    } else {
+      o << SExprType(curr->type);
+    }
+  }
+  void visitImportedGlobal(Global* curr) {
+    doIndent(o, indent);
+    o << '(';
+    emitImportHeader(curr);
+    o << "(global ";
+    printName(curr->name, o) << ' ';
+    emitGlobalType(curr);
+    o << "))" << maybeNewLine;
+  }
+  void visitDefinedGlobal(Global* curr) {
+    doIndent(o, indent);
+    o << '(';
+    printMedium(o, "global ");
+    printName(curr->name, o) << ' ';
+    emitGlobalType(curr);
+    o << ' ';
+    visit(curr->init);
+    o << ')';
+    o << maybeNewLine;
+  }
+  void visitFunction(Function* curr) {
+    if (curr->imported()) {
+      visitImportedFunction(curr);
+    } else {
+      visitDefinedFunction(curr);
+    }
+  }
+  void visitImportedFunction(Function* curr) {
+    doIndent(o, indent);
+    currFunction = curr;
+    lastPrintedLocation = {0, 0, 0};
+    o << '(';
+    emitImportHeader(curr);
+    handleSignature(curr->sig, &curr->name);
+    o << ')';
+    o << maybeNewLine;
+  }
+  void visitDefinedFunction(Function* curr) {
+    doIndent(o, indent);
+    currFunction = curr;
+    lastPrintedLocation = {0, 0, 0};
+    if (currFunction->prologLocation.size()) {
+      printDebugLocation(*currFunction->prologLocation.begin());
+    }
+    o << '(';
+    printMajor(o, "func ");
+    printName(curr->name, o);
+    if (!printStackIR && curr->stackIR && !minify) {
+      o << " (; has Stack IR ;)";
+    }
+    if (curr->sig.params.size() > 0) {
+      Index i = 0;
+      for (const auto& param : curr->sig.params) {
+        o << maybeSpace;
+        o << '(';
+        printMinor(o, "param ");
+        printLocal(i, currFunction, o);
+        o << ' ' << param << ')';
+        ++i;
+      }
+    }
+    if (curr->sig.results != Type::none) {
+      o << maybeSpace;
+      o << ResultType(curr->sig.results);
+    }
+    incIndent();
+    for (size_t i = curr->getVarIndexBase(); i < curr->getNumLocals(); i++) {
+      doIndent(o, indent);
+      o << '(';
+      printMinor(o, "local ");
+      printLocal(i, currFunction, o)
+        << ' ' << SExprType(curr->getLocalType(i)) << ')';
+      o << maybeNewLine;
+    }
+    // Print the body.
+    if (!printStackIR || !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..
+      if (!full && curr->body->is<Block>() &&
+          curr->body->cast<Block>()->name.isNull()) {
+        Block* block = curr->body->cast<Block>();
+        for (auto item : block->list) {
+          printFullLine(item);
+        }
+      } else {
+        printFullLine(curr->body);
+      }
+    } else {
+      // Print the stack IR.
+      WasmPrinter::printStackIR(curr->stackIR.get(), o, curr);
+    }
+    if (currFunction->epilogLocation.size() &&
+        lastPrintedLocation != *currFunction->epilogLocation.begin()) {
+      // Print last debug location: mix of decIndent and printDebugLocation
+      // logic.
+      doIndent(o, indent);
+      if (!minify) {
+        indent--;
+      }
+      printDebugLocation(*currFunction->epilogLocation.begin());
+      o << ')';
+    } else {
+      decIndent();
+    }
+    o << maybeNewLine;
+  }
+  void visitEvent(Event* curr) {
+    if (curr->imported()) {
+      visitImportedEvent(curr);
+    } else {
+      visitDefinedEvent(curr);
+    }
+  }
+  void visitImportedEvent(Event* curr) {
+    doIndent(o, indent);
+    o << '(';
+    emitImportHeader(curr);
+    o << "(event ";
+    printName(curr->name, o);
+    o << maybeSpace << "(attr " << curr->attribute << ')' << maybeSpace;
+    o << ParamType(curr->sig.params);
+    o << "))";
+    o << maybeNewLine;
+  }
+  void visitDefinedEvent(Event* curr) {
+    doIndent(o, indent);
+    o << '(';
+    printMedium(o, "event ");
+    printName(curr->name, o);
+    o << maybeSpace << "(attr " << curr->attribute << ')' << maybeSpace;
+    o << ParamType(curr->sig.params);
+    o << ")" << maybeNewLine;
+  }
+  void printTableHeader(Table* curr) {
+    o << '(';
+    printMedium(o, "table") << ' ';
+    printName(curr->name, o) << ' ';
+    o << curr->initial;
+    if (curr->hasMax()) {
+      o << ' ' << curr->max;
+    }
+    o << " funcref)";
+  }
+  void visitTable(Table* curr) {
+    if (!curr->exists) {
+      return;
+    }
+    if (curr->imported()) {
+      doIndent(o, indent);
+      o << '(';
+      emitImportHeader(curr);
+      printTableHeader(&currModule->table);
+      o << ')' << maybeNewLine;
+    } else {
+      doIndent(o, indent);
+      printTableHeader(curr);
+      o << maybeNewLine;
+    }
+    for (auto& segment : curr->segments) {
+      // Don't print empty segments
+      if (segment.data.empty()) {
+        continue;
+      }
+      doIndent(o, indent);
+      o << '(';
+      printMajor(o, "elem ");
+      visit(segment.offset);
+      for (auto name : segment.data) {
+        o << ' ';
+        printName(name, o);
+      }
+      o << ')' << maybeNewLine;
+    }
+  }
+  void printMemoryHeader(Memory* curr) {
+    o << '(';
+    printMedium(o, "memory") << ' ';
+    printName(curr->name, o) << ' ';
+    if (curr->shared) {
+      o << '(';
+      printMedium(o, "shared ");
+    }
+    if (curr->is64()) {
+      o << "i64 ";
+    }
+    o << curr->initial;
+    if (curr->hasMax()) {
+      o << ' ' << curr->max;
+    }
+    if (curr->shared) {
+      o << ")";
+    }
+    o << ")";
+  }
+  void visitMemory(Memory* curr) {
+    if (!curr->exists) {
+      return;
+    }
+    if (curr->imported()) {
+      doIndent(o, indent);
+      o << '(';
+      emitImportHeader(curr);
+      printMemoryHeader(&currModule->memory);
+      o << ')' << maybeNewLine;
+    } else {
+      doIndent(o, indent);
+      printMemoryHeader(curr);
+      o << '\n';
+    }
+    for (auto segment : curr->segments) {
+      doIndent(o, indent);
+      o << '(';
+      printMajor(o, "data ");
+      if (segment.isPassive) {
+        printMedium(o, "passive");
+      } else {
+        visit(segment.offset);
+      }
+      o << " \"";
+      for (size_t i = 0; i < segment.data.size(); i++) {
+        unsigned char c = segment.data[i];
+        switch (c) {
+          case '\n':
+            o << "\\n";
+            break;
+          case '\r':
+            o << "\\0d";
+            break;
+          case '\t':
+            o << "\\t";
+            break;
+          case '\f':
+            o << "\\0c";
+            break;
+          case '\b':
+            o << "\\08";
+            break;
+          case '\\':
+            o << "\\\\";
+            break;
+          case '"':
+            o << "\\\"";
+            break;
+          case '\'':
+            o << "\\'";
+            break;
+          default: {
+            if (c >= 32 && c < 127) {
+              o << c;
+            } else {
+              o << std::hex << '\\' << (c / 16) << (c % 16) << std::dec;
+            }
+          }
+        }
+      }
+      o << "\")" << maybeNewLine;
+    }
+  }
+  void printDylinkSection(const std::unique_ptr<DylinkSection>& dylinkSection) {
+    doIndent(o, indent) << ";; dylink section\n";
+    doIndent(o, indent) << ";;   memorysize: " << dylinkSection->memorySize
+                        << '\n';
+    doIndent(o, indent) << ";;   memoryalignment: "
+                        << dylinkSection->memoryAlignment << '\n';
+    doIndent(o, indent) << ";;   tablesize: " << dylinkSection->tableSize
+                        << '\n';
+    doIndent(o, indent) << ";;   tablealignment: "
+                        << dylinkSection->tableAlignment << '\n';
+    for (auto& neededDynlib : dylinkSection->neededDynlibs) {
+      doIndent(o, indent) << ";;   needed dynlib: " << neededDynlib << '\n';
+    }
+  }
+  void visitModule(Module* curr) {
+    currModule = curr;
+    o << '(';
+    printMajor(o, "module");
+    if (curr->name.is()) {
+      o << ' ';
+      printName(curr->name, o);
+    }
+    incIndent();
+    std::vector<Signature> signatures;
+    std::unordered_map<Signature, Index> indices;
+    ModuleUtils::collectSignatures(*curr, signatures, indices);
+    for (auto sig : signatures) {
+      doIndent(o, indent);
+      o << '(';
+      printMedium(o, "type") << ' ';
+      o << SigName(sig) << ' ';
+      handleSignature(sig);
+      o << ")" << maybeNewLine;
+    }
+    ModuleUtils::iterImportedMemories(
+      *curr, [&](Memory* memory) { visitMemory(memory); });
+    ModuleUtils::iterImportedTables(*curr,
+                                    [&](Table* table) { visitTable(table); });
+    ModuleUtils::iterImportedGlobals(
+      *curr, [&](Global* global) { visitGlobal(global); });
+    ModuleUtils::iterImportedFunctions(
+      *curr, [&](Function* func) { visitFunction(func); });
+    ModuleUtils::iterImportedEvents(*curr,
+                                    [&](Event* event) { visitEvent(event); });
+    ModuleUtils::iterDefinedMemories(
+      *curr, [&](Memory* memory) { visitMemory(memory); });
+    ModuleUtils::iterDefinedTables(*curr,
+                                   [&](Table* table) { visitTable(table); });
+    ModuleUtils::iterDefinedGlobals(
+      *curr, [&](Global* global) { visitGlobal(global); });
+    ModuleUtils::iterDefinedEvents(*curr,
+                                   [&](Event* event) { visitEvent(event); });
+    for (auto& child : curr->exports) {
+      doIndent(o, indent);
+      visitExport(child.get());
+      o << maybeNewLine;
+    }
+    if (curr->start.is()) {
+      doIndent(o, indent);
+      o << '(';
+      printMedium(o, "start") << ' ';
+      printName(curr->start, o) << ')';
+      o << maybeNewLine;
+    }
+    ModuleUtils::iterDefinedFunctions(
+      *curr, [&](Function* func) { visitFunction(func); });
+    if (curr->dylinkSection) {
+      printDylinkSection(curr->dylinkSection);
+    }
+    for (auto& section : curr->userSections) {
+      doIndent(o, indent);
+      o << ";; custom section \"" << section.name << "\", size "
+        << section.data.size();
+      bool isPrintable = true;
+      for (auto c : section.data) {
+        if (!isprint(static_cast<unsigned char>(c))) {
+          isPrintable = false;
+          break;
+        }
+      }
+      if (isPrintable) {
+        o << ", contents: ";
+        // std::quoted is not available in all the supported compilers yet.
+        o << '"';
+        for (auto c : section.data) {
+          if (c == '\\' || c == '"') {
+            o << '\\';
+          }
+          o << c;
+        }
+        o << '"';
+      }
+      o << maybeNewLine;
+    }
+    decIndent();
+    o << maybeNewLine;
+    currModule = nullptr;
+  }
+};
+
+// Prints out a module
+class Printer : public Pass {
+protected:
+  std::ostream& o;
+
+public:
+  Printer() : o(std::cout) {}
+  Printer(std::ostream* o) : o(*o) {}
+
+  bool modifiesBinaryenIR() override { return false; }
+
+  void run(PassRunner* runner, Module* module) override {
+    PrintSExpression print(o);
+    print.setDebugInfo(runner->options.debugInfo);
+    print.visitModule(module);
+  }
+};
+
+Pass* createPrinterPass() { return new Printer(); }
+
+// Prints out a minified module
+
+class MinifiedPrinter : public Printer {
+public:
+  MinifiedPrinter() = default;
+  MinifiedPrinter(std::ostream* o) : Printer(o) {}
+
+  void run(PassRunner* runner, Module* module) override {
+    PrintSExpression print(o);
+    print.setMinify(true);
+    print.setDebugInfo(runner->options.debugInfo);
+    print.visitModule(module);
+  }
+};
+
+Pass* createMinifiedPrinterPass() { return new MinifiedPrinter(); }
+
+// Prints out a module withough elision, i.e., the full ast
+
+class FullPrinter : public Printer {
+public:
+  FullPrinter() = default;
+  FullPrinter(std::ostream* o) : Printer(o) {}
+
+  void run(PassRunner* runner, Module* module) override {
+    PrintSExpression print(o);
+    print.setFull(true);
+    print.setDebugInfo(runner->options.debugInfo);
+    print.visitModule(module);
+  }
+};
+
+Pass* createFullPrinterPass() { return new FullPrinter(); }
+
+// Print Stack IR (if present)
+
+class PrintStackIR : public Printer {
+public:
+  PrintStackIR() = default;
+  PrintStackIR(std::ostream* o) : Printer(o) {}
+
+  void run(PassRunner* runner, Module* module) override {
+    PrintSExpression print(o);
+    print.setDebugInfo(runner->options.debugInfo);
+    print.setPrintStackIR(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) {
+  if (!expression) {
+    o << "(null expression)";
+    return o;
+  }
+  PrintSExpression print(o);
+  print.setMinify(minify);
+  if (full || isFullForced()) {
+    print.setFull(true);
+    o << "[" << expression->type << "] ";
+  }
+  print.visit(expression);
+  return o;
+}
+
+std::ostream&
+WasmPrinter::printStackInst(StackInst* inst, std::ostream& o, Function* func) {
+  switch (inst->op) {
+    case StackInst::Basic: {
+      PrintExpressionContents(func, o).visit(inst->origin);
+      break;
+    }
+    case StackInst::BlockBegin:
+    case StackInst::IfBegin:
+    case StackInst::LoopBegin:
+    case StackInst::TryBegin: {
+      o << getExpressionName(inst->origin);
+      break;
+    }
+    case StackInst::BlockEnd:
+    case StackInst::IfEnd:
+    case StackInst::LoopEnd:
+    case StackInst::TryEnd: {
+      o << "end (" << inst->type << ')';
+      break;
+    }
+    case StackInst::IfElse: {
+      o << "else";
+      break;
+    }
+    case StackInst::Catch: {
+      o << "catch";
+      break;
+    }
+    default:
+      WASM_UNREACHABLE("unexpeted op");
+  }
+  return o;
+}
+
+std::ostream&
+WasmPrinter::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++) {
+      o << ' ';
+    }
+  };
+  for (Index i = 0; i < (*ir).size(); i++) {
+    auto* inst = (*ir)[i];
+    if (!inst) {
+      continue;
+    }
+    switch (inst->op) {
+      case StackInst::Basic: {
+        doIndent();
+        // Pop is a pseudo instruction and should not be printed in the stack IR
+        // format to make it valid wat form.
+        if (inst->origin->is<Pop>()) {
+          break;
+        }
+        PrintExpressionContents(func, o).visit(inst->origin);
+        break;
+      }
+      case StackInst::BlockBegin:
+      case StackInst::IfBegin:
+      case StackInst::LoopBegin:
+      case StackInst::TryBegin: {
+        doIndent();
+        PrintExpressionContents(func, o).visit(inst->origin);
+        indent++;
+        break;
+      }
+      case StackInst::BlockEnd:
+      case StackInst::IfEnd:
+      case StackInst::LoopEnd:
+      case StackInst::TryEnd: {
+        indent--;
+        doIndent();
+        o << "end";
+        break;
+      }
+      case StackInst::IfElse: {
+        indent--;
+        doIndent();
+        o << "else";
+        indent++;
+        break;
+      }
+      case StackInst::Catch: {
+        indent--;
+        doIndent();
+        o << "catch";
+        indent++;
+        break;
+      }
+      default:
+        WASM_UNREACHABLE("unexpeted op");
+    }
+    std::cout << '\n';
+  }
+  return o;
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/PrintCallGraph.cpp b/binaryen/src/passes/PrintCallGraph.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/PrintCallGraph.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+//
+// Prints the call graph in .dot format. You can use http://www.graphviz.org/ to
+// view .dot files.
+//
+
+#include <iomanip>
+#include <memory>
+
+#include "ir/module-utils.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct PrintCallGraph : public Pass {
+  bool modifiesBinaryenIR() override { return false; }
+
+  void run(PassRunner* runner, Module* module) override {
+    std::ostream& o = std::cout;
+    o << "digraph call {\n"
+         "  rankdir = LR;\n"
+         "  subgraph cluster_key {\n"
+         "    node [shape=box, fontname=courier, fontsize=10];\n"
+         "    edge [fontname=courier, fontsize=10];\n"
+         "    label = \"Key\";\n"
+         "    \"Import\" [style=\"filled\", fillcolor=\"turquoise\"];\n"
+         "    \"Export\" [style=\"filled\", fillcolor=\"gray\"];\n"
+         "    \"Indirect Target\" [style=\"filled, rounded\", "
+         "fillcolor=\"white\"];\n"
+         "    \"A\" -> \"B\" [style=\"filled, rounded\", label = \"Direct "
+         "Call\"];\n"
+         "  }\n\n"
+         "  node [shape=box, fontname=courier, fontsize=10];\n";
+
+    // Defined functions
+    ModuleUtils::iterDefinedFunctions(*module, [&](Function* curr) {
+      std::cout << "  \"" << curr->name
+                << "\" [style=\"filled\", fillcolor=\"white\"];\n";
+    });
+
+    // Imported functions
+    ModuleUtils::iterImportedFunctions(*module, [&](Function* curr) {
+      o << "  \"" << curr->name
+        << "\" [style=\"filled\", fillcolor=\"turquoise\"];\n";
+    });
+
+    // Exports
+    for (auto& curr : module->exports) {
+      if (curr->kind == ExternalKind::Function) {
+        Function* func = module->getFunction(curr->value);
+        o << "  \"" << func->name
+          << "\" [style=\"filled\", fillcolor=\"gray\"];\n";
+      }
+    }
+
+    struct CallPrinter : public PostWalker<CallPrinter> {
+      Module* module;
+      Function* currFunction;
+      std::set<Name> visitedTargets; // Used to avoid printing duplicate edges.
+      std::vector<Function*> allIndirectTargets;
+      CallPrinter(Module* module) : module(module) {
+        // Walk function bodies.
+        ModuleUtils::iterDefinedFunctions(*module, [&](Function* curr) {
+          currFunction = curr;
+          visitedTargets.clear();
+          walk(curr->body);
+        });
+      }
+      void visitCall(Call* curr) {
+        auto* target = module->getFunction(curr->target);
+        if (visitedTargets.count(target->name) > 0) {
+          return;
+        }
+        visitedTargets.insert(target->name);
+        std::cout << "  \"" << currFunction->name << "\" -> \"" << target->name
+                  << "\"; // call\n";
+      }
+    };
+    CallPrinter printer(module);
+
+    // Indirect Targets
+    for (auto& segment : module->table.segments) {
+      for (auto& curr : segment.data) {
+        auto* func = module->getFunction(curr);
+        o << "  \"" << func->name << "\" [style=\"filled, rounded\"];\n";
+      }
+    }
+
+    o << "}\n";
+  }
+};
+
+Pass* createPrintCallGraphPass() { return new PrintCallGraph(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/PrintFeatures.cpp b/binaryen/src/passes/PrintFeatures.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/PrintFeatures.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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.
+ */
+
+//
+// Print out the feature options corresponding to enabled features
+//
+
+#include "pass.h"
+#include "wasm-features.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct PrintFeatures : public Pass {
+  void run(PassRunner* runner, Module* module) override {
+    module->features.iterFeatures([](FeatureSet::Feature f) {
+      std::cout << "--enable-" << FeatureSet::toString(f) << std::endl;
+    });
+  }
+};
+
+Pass* createPrintFeaturesPass() { return new PrintFeatures(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/PrintFunctionMap.cpp b/binaryen/src/passes/PrintFunctionMap.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/PrintFunctionMap.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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.
+ */
+
+//
+// Prints the a map of function indexes to function names. This can be
+// useful for interpreting a stack trace from a production environment
+// where names did not exist on the client. The map looks like this:
+//
+// 0:foo
+// 1:bar
+// 2:baz
+//
+
+#include "pass.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct PrintFunctionMap : public Pass {
+  bool modifiesBinaryenIR() override { return false; }
+
+  void run(PassRunner* runner, Module* module) override {
+    Index i = 0;
+    for (auto& func : module->functions) {
+      std::cout << i++ << ':' << func->name.str << '\n';
+    }
+  }
+};
+
+Pass* createPrintFunctionMapPass() { return new PrintFunctionMap(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/ReReloop.cpp b/binaryen/src/passes/ReReloop.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/ReReloop.cpp
@@ -0,0 +1,371 @@
+/*
+ * 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.
+ */
+
+//
+// Convert the AST to a CFG, and optimize+convert it back to the AST
+// using the relooper.
+//
+// This pass depends on flatten being run before it.
+//
+
+#include <memory>
+
+#include "cfg/Relooper.h"
+#include "ir/flat.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
+
+#ifdef RERELOOP_DEBUG
+#include <wasm-printing.h>
+#endif
+
+namespace wasm {
+
+struct ReReloop final : public Pass {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new ReReloop; }
+
+  std::unique_ptr<CFG::Relooper> relooper;
+  std::unique_ptr<Builder> builder;
+
+  // block handling
+
+  CFG::Block* currCFGBlock = nullptr;
+
+  CFG::Block* makeCFGBlock() {
+    return relooper->AddBlock(builder->makeBlock());
+  }
+
+  CFG::Block* setCurrCFGBlock(CFG::Block* curr) {
+    if (currCFGBlock) {
+      finishBlock();
+    }
+    return currCFGBlock = curr;
+  }
+
+  CFG::Block* startCFGBlock() { return setCurrCFGBlock(makeCFGBlock()); }
+
+  CFG::Block* getCurrCFGBlock() { return currCFGBlock; }
+
+  Block* getCurrBlock() { return currCFGBlock->Code->cast<Block>(); }
+
+  void finishBlock() { getCurrBlock()->finalize(); }
+
+  // break handling
+
+  std::map<Name, CFG::Block*> breakTargets;
+
+  void addBreakTarget(Name name, CFG::Block* target) {
+    breakTargets[name] = target;
+  }
+
+  CFG::Block* getBreakTarget(Name name) { return breakTargets[name]; }
+
+  // branch handling
+
+  void
+  addBranch(CFG::Block* from, CFG::Block* to, Expression* condition = nullptr) {
+    from->AddBranchTo(to, condition);
+  }
+
+  void addSwitchBranch(CFG::Block* from,
+                       CFG::Block* to,
+                       const std::set<Index>& values) {
+    std::vector<Index> list;
+    for (auto i : values) {
+      list.push_back(i);
+    }
+    from->AddSwitchBranchTo(to, std::move(list));
+  }
+
+  // we work using a stack of control flow tasks
+
+  struct Task {
+    ReReloop& parent;
+    Task(ReReloop& parent) : parent(parent) {}
+    virtual void run() { WASM_UNREACHABLE("unimpl"); }
+  };
+
+  typedef std::shared_ptr<Task> TaskPtr;
+  std::vector<TaskPtr> stack;
+
+  struct TriageTask final : public Task {
+    Expression* curr;
+
+    TriageTask(ReReloop& parent, Expression* curr) : Task(parent), curr(curr) {}
+
+    void run() override { parent.triage(curr); }
+  };
+
+  struct BlockTask final : public Task {
+    Block* curr;
+    CFG::Block* later;
+
+    BlockTask(ReReloop& parent, Block* curr) : Task(parent), curr(curr) {}
+
+    static void handle(ReReloop& parent, Block* curr) {
+      if (curr->name.is()) {
+        // we may be branched to. create a target, and
+        // ensure we are called at the join point
+        auto task = std::make_shared<BlockTask>(parent, curr);
+        task->curr = curr;
+        task->later = parent.makeCFGBlock();
+        parent.addBreakTarget(curr->name, task->later);
+        parent.stack.push_back(task);
+      }
+      auto& list = curr->list;
+      for (int i = int(list.size()) - 1; i >= 0; i--) {
+        parent.stack.push_back(std::make_shared<TriageTask>(parent, list[i]));
+      }
+    }
+
+    void run() override {
+      // add fallthrough
+      parent.addBranch(parent.getCurrCFGBlock(), later);
+      parent.setCurrCFGBlock(later);
+    }
+  };
+
+  struct LoopTask final : public Task {
+    static void handle(ReReloop& parent, Loop* curr) {
+      parent.stack.push_back(std::make_shared<TriageTask>(parent, curr->body));
+      if (curr->name.is()) {
+        // we may be branched to. create a target
+        auto* before = parent.getCurrCFGBlock();
+        auto* top = parent.startCFGBlock();
+        parent.addBreakTarget(curr->name, top);
+        parent.addBranch(before, top);
+      }
+    }
+  };
+
+  struct IfTask final : public Task {
+    If* curr;
+    CFG::Block* condition;
+    CFG::Block* ifTrueEnd;
+    int phase = 0;
+
+    IfTask(ReReloop& parent, If* curr) : Task(parent), curr(curr) {}
+
+    static void handle(ReReloop& parent, If* curr) {
+      auto task = std::make_shared<IfTask>(parent, curr);
+      task->curr = curr;
+      task->condition = parent.getCurrCFGBlock();
+      auto* ifTrueBegin = parent.startCFGBlock();
+      parent.addBranch(task->condition, ifTrueBegin, curr->condition);
+      if (curr->ifFalse) {
+        parent.stack.push_back(task);
+        parent.stack.push_back(
+          std::make_shared<TriageTask>(parent, curr->ifFalse));
+      }
+      parent.stack.push_back(task);
+      parent.stack.push_back(
+        std::make_shared<TriageTask>(parent, curr->ifTrue));
+    }
+
+    void run() override {
+      if (phase == 0) {
+        // end of ifTrue
+        ifTrueEnd = parent.getCurrCFGBlock();
+        auto* after = parent.startCFGBlock();
+        // if condition was false, go after the ifTrue, to ifFalse or outside
+        parent.addBranch(condition, after);
+        if (!curr->ifFalse) {
+          parent.addBranch(ifTrueEnd, after);
+        }
+        phase++;
+      } else if (phase == 1) {
+        // end if ifFalse
+        auto* ifFalseEnd = parent.getCurrCFGBlock();
+        auto* after = parent.startCFGBlock();
+        parent.addBranch(ifTrueEnd, after);
+        parent.addBranch(ifFalseEnd, after);
+      } else {
+        WASM_UNREACHABLE("invalid phase");
+      }
+    }
+  };
+
+  struct BreakTask : public Task {
+    static void handle(ReReloop& parent, Break* curr) {
+      // add the branch. note how if the condition is false, it is the right
+      // value there as well
+      auto* before = parent.getCurrCFGBlock();
+      parent.addBranch(
+        before, parent.getBreakTarget(curr->name), curr->condition);
+      if (curr->condition) {
+        auto* after = parent.startCFGBlock();
+        parent.addBranch(before, after);
+      } else {
+        parent.stopControlFlow();
+      }
+    }
+  };
+
+  struct SwitchTask : public Task {
+    static void handle(ReReloop& parent, Switch* curr) {
+      // set the switch condition for the block ending now
+      auto* before = parent.getCurrCFGBlock();
+      assert(!before->SwitchCondition);
+      before->SwitchCondition = curr->condition;
+      std::map<Name, std::set<Index>> targetValues;
+      auto& targets = curr->targets;
+      auto num = targets.size();
+      for (Index i = 0; i < num; i++) {
+        targetValues[targets[i]].insert(i);
+      }
+      for (auto& iter : targetValues) {
+        parent.addSwitchBranch(
+          before, parent.getBreakTarget(iter.first), iter.second);
+      }
+      // the default may be among the targets, in which case, we can't add it
+      // simply as it would be a duplicate, so create a temp block
+      if (targetValues.count(curr->default_) == 0) {
+        parent.addSwitchBranch(
+          before, parent.getBreakTarget(curr->default_), std::set<Index>());
+      } else {
+        auto* temp = parent.startCFGBlock();
+        parent.addSwitchBranch(before, temp, std::set<Index>());
+        parent.addBranch(temp, parent.getBreakTarget(curr->default_));
+      }
+      parent.stopControlFlow();
+    }
+  };
+
+  struct ReturnTask : public Task {
+    static void handle(ReReloop& parent, Return* curr) {
+      // reuse the return
+      parent.getCurrBlock()->list.push_back(curr);
+      parent.stopControlFlow();
+    }
+  };
+
+  struct UnreachableTask : public Task {
+    static void handle(ReReloop& parent, Unreachable* curr) {
+      // reuse the unreachable
+      parent.getCurrBlock()->list.push_back(curr);
+      parent.stopControlFlow();
+    }
+  };
+
+  // handle an element we encounter
+
+  void triage(Expression* curr) {
+    if (auto* block = curr->dynCast<Block>()) {
+      BlockTask::handle(*this, block);
+    } else if (auto* loop = curr->dynCast<Loop>()) {
+      LoopTask::handle(*this, loop);
+    } else if (auto* iff = curr->dynCast<If>()) {
+      IfTask::handle(*this, iff);
+    } else if (auto* br = curr->dynCast<Break>()) {
+      BreakTask::handle(*this, br);
+    } else if (auto* sw = curr->dynCast<Switch>()) {
+      SwitchTask::handle(*this, sw);
+    } else if (auto* ret = curr->dynCast<Return>()) {
+      ReturnTask::handle(*this, ret);
+    } else if (auto* un = curr->dynCast<Unreachable>()) {
+      UnreachableTask::handle(*this, un);
+    } else if (curr->is<Try>() || curr->is<Throw>() || curr->is<Rethrow>() ||
+               curr->is<BrOnExn>()) {
+      Fatal() << "ReReloop does not support EH instructions yet";
+    } else {
+      // not control flow, so just a simple element
+      getCurrBlock()->list.push_back(curr);
+    }
+  }
+
+  void stopControlFlow() {
+    startCFGBlock();
+    // TODO: optimize with this?
+  }
+
+  void runOnFunction(PassRunner* runner,
+                     Module* module,
+                     Function* function) override {
+    Flat::verifyFlatness(function);
+
+    // since control flow is flattened, this is pretty simple
+    // first, traverse the function body. note how we don't need to traverse
+    // into expressions, as we know they contain no control flow
+    builder = make_unique<Builder>(*module);
+    relooper = make_unique<CFG::Relooper>(module);
+    auto* entry = startCFGBlock();
+    stack.push_back(TaskPtr(new TriageTask(*this, function->body)));
+    // main loop
+    while (stack.size() > 0) {
+      TaskPtr curr = stack.back();
+      stack.pop_back();
+      curr->run();
+    }
+    // finish the current block
+    finishBlock();
+    // blocks that do not have any exits are dead ends in the relooper. we need
+    // to make sure that are in fact dead ends, and do not flow control
+    // anywhere. add a return as needed
+    for (auto& cfgBlock : relooper->Blocks) {
+      auto* block = cfgBlock->Code->cast<Block>();
+      if (cfgBlock->BranchesOut.empty() && block->type != Type::unreachable) {
+        block->list.push_back(function->sig.results == Type::none
+                                ? (Expression*)builder->makeReturn()
+                                : (Expression*)builder->makeUnreachable());
+        block->finalize();
+      }
+    }
+#ifdef RERELOOP_DEBUG
+    std::cout << "rerelooping " << function->name << '\n';
+    for (auto* block : relooper->Blocks) {
+      std::cout << block << " block:\n" << block->Code << '\n';
+      for (auto& pair : block->BranchesOut) {
+        auto* target = pair.first;
+        auto* branch = pair.second;
+        std::cout << "branch to " << target << "\n";
+        if (branch->Condition) {
+          std::cout << "  with condition\n" << branch->Condition << '\n';
+        }
+      }
+    }
+#endif
+    // run the relooper to recreate control flow
+    relooper->Calculate(entry);
+    // render
+    {
+      auto temp = builder->addVar(function, Type::i32);
+      CFG::RelooperBuilder builder(*module, temp);
+      function->body = relooper->Render(builder);
+      // if the function has a result, and the relooper emitted
+      // something that seems like it flows out without a value
+      // (but that path is never reached; it just has a br to it
+      // because of the relooper's boilerplate switch-handling
+      // code, for example, which could be optimized out later
+      // but isn't yet), then make sure it has a proper type
+      if (function->sig.results != Type::none &&
+          function->body->type == Type::none) {
+        function->body =
+          builder.makeSequence(function->body, builder.makeUnreachable());
+      }
+    }
+    // TODO: should this be in the relooper itself?
+    ReFinalize().walk(function->body);
+  }
+};
+
+Pass* createReReloopPass() { return new ReReloop(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/RedundantSetElimination.cpp b/binaryen/src/passes/RedundantSetElimination.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/RedundantSetElimination.cpp
@@ -0,0 +1,398 @@
+/*
+ * 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.
+ */
+
+//
+// Eliminate redundant local.sets: if a local already has a particular
+// value, we don't need to set it again. A common case here is loops
+// that start at zero, since the default value is initialized to
+// zero anyhow.
+//
+// A risk here is that we extend live ranges, e.g. we may use the default
+// value at the very end of a function, keeping that local alive throughout.
+// For that reason it is probably better to run this near the end of
+// optimization, and especially after coalesce-locals. A final vaccum
+// should be done after it, as this pass can leave around drop()s of
+// values no longer necessary.
+//
+// So far this tracks constant values, and for everything else it considers
+// them unique (so each local.set of a non-constant is a unique value, each
+// merge is a unique value, etc.; there is no sophisticated value numbering
+// here).
+//
+
+#include <cfg/cfg-traversal.h>
+#include <ir/literal-utils.h>
+#include <ir/properties.h>
+#include <ir/utils.h>
+#include <pass.h>
+#include <support/unique_deferring_queue.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+namespace wasm {
+
+// We do a very simple numbering of local values, just a unique
+// number for constants so far, enough to see
+// trivial duplication. LocalValues maps each local index to
+// its current value
+typedef std::vector<Index> LocalValues;
+
+namespace {
+
+// information in a basic block
+struct Info {
+  LocalValues start, end; // the local values at the start and end of the block
+  std::vector<Expression**> setps;
+};
+
+struct RedundantSetElimination
+  : public WalkerPass<CFGWalker<RedundantSetElimination,
+                                Visitor<RedundantSetElimination>,
+                                Info>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new RedundantSetElimination(); }
+
+  Index numLocals;
+
+  // cfg traversal work
+
+  static void doVisitLocalSet(RedundantSetElimination* self,
+                              Expression** currp) {
+    if (self->currBasicBlock) {
+      self->currBasicBlock->contents.setps.push_back(currp);
+    }
+  }
+
+  // main entry point
+
+  void doWalkFunction(Function* func) {
+    numLocals = func->getNumLocals();
+    if (numLocals == 0) {
+      return; // nothing to do
+    }
+    // create the CFG by walking the IR
+    CFGWalker<RedundantSetElimination, Visitor<RedundantSetElimination>, Info>::
+      doWalkFunction(func);
+    // flow values across blocks
+    flowValues(func);
+    // remove redundant sets
+    optimize();
+  }
+
+  // numbering
+
+  Index nextValue = 1; // 0 is reserved for the "unseen value"
+  // each constant has a value
+  std::unordered_map<Literals, Index> literalValues;
+  // each value can have a value
+  std::unordered_map<Expression*, Index> expressionValues;
+  // each block has values for each merge
+  std::unordered_map<BasicBlock*, std::unordered_map<Index, Index>>
+    blockMergeValues;
+
+  Index getUnseenValue() { // we haven't seen this location yet
+    return 0;
+  }
+  Index getUniqueValue() {
+#ifdef RSE_DEBUG
+    std::cout << "new unique value " << nextValue << '\n';
+#endif
+    return nextValue++;
+  }
+
+  Index getLiteralValue(Literals lit) {
+    auto iter = literalValues.find(lit);
+    if (iter != literalValues.end()) {
+      return iter->second;
+    }
+#ifdef RSE_DEBUG
+    std::cout << "new literal value for " << lit << '\n';
+#endif
+    return literalValues[lit] = getUniqueValue();
+  }
+
+  Index getExpressionValue(Expression* expr) {
+    auto iter = expressionValues.find(expr);
+    if (iter != expressionValues.end()) {
+      return iter->second;
+    }
+#ifdef RSE_DEBUG
+    std::cout << "new expr value for " << expr << '\n';
+#endif
+    return expressionValues[expr] = getUniqueValue();
+  }
+
+  Index getBlockMergeValue(BasicBlock* block, Index index) {
+    auto& mergeValues = blockMergeValues[block];
+    auto iter = mergeValues.find(index);
+    if (iter != mergeValues.end()) {
+      return iter->second;
+    }
+#ifdef RSE_DEBUG
+    std::cout << "new block-merge value for " << block << " : " << index
+              << '\n';
+#endif
+    return mergeValues[index] = getUniqueValue();
+  }
+
+  bool isBlockMergeValue(BasicBlock* block, Index index, Index value) {
+    auto iter = blockMergeValues.find(block);
+    if (iter == blockMergeValues.end()) {
+      return false;
+    }
+    auto& mergeValues = iter->second;
+    auto iter2 = mergeValues.find(index);
+    if (iter2 == mergeValues.end()) {
+      return false;
+    }
+    return value == iter2->second;
+  }
+
+  Index getValue(Expression* value, LocalValues& currValues) {
+    if (Properties::isConstantExpression(value)) {
+      // a constant
+      return getLiteralValue(Properties::getLiterals(value));
+    } else if (auto* get = value->dynCast<LocalGet>()) {
+      // a copy of whatever that was
+      return currValues[get->index];
+    } else {
+      // get the value's own unique value
+      return getExpressionValue(value);
+    }
+  }
+
+  // flowing
+
+  void flowValues(Function* func) {
+    for (auto& block : basicBlocks) {
+      LocalValues& start = block->contents.start;
+      start.resize(numLocals);
+      if (block.get() == entry) {
+        // params are complex values we can't optimize; vars are zeros
+        for (Index i = 0; i < numLocals; i++) {
+          if (func->isParam(i)) {
+#ifdef RSE_DEBUG
+            std::cout << "new param value for " << i << '\n';
+#endif
+            start[i] = getUniqueValue();
+          } else {
+            start[i] =
+              getLiteralValue(Literal::makeZeros(func->getLocalType(i)));
+          }
+        }
+      } else {
+        // other blocks have all unseen values to begin with
+        for (Index i = 0; i < numLocals; i++) {
+          start[i] = getUnseenValue();
+        }
+      }
+      // the ends all begin unseen
+      LocalValues& end = block->contents.end;
+      end.resize(numLocals);
+      for (Index i = 0; i < numLocals; i++) {
+        end[i] = getUnseenValue();
+      }
+    }
+    // keep working while stuff is flowing. we use a unique deferred queue
+    // which ensures both FIFO and that we don't do needless work - if
+    // A and B reach C, and both queue C, we only want to do C at the latest
+    // time, when we have information from all those reaching it.
+    UniqueDeferredQueue<BasicBlock*> work;
+    work.push(entry);
+    while (!work.empty()) {
+      auto* curr = work.pop();
+#ifdef RSE_DEBUG
+      std::cout << "flow block " << curr << '\n';
+#endif
+      // process a block: first, update its start based on those reaching it
+      if (!curr->in.empty()) {
+        if (curr->in.size() == 1) {
+          // just copy the pred, nothing to merge
+          curr->contents.start = (*curr->in.begin())->contents.end;
+        } else {
+          // perform a merge
+          auto in = curr->in;
+          for (Index i = 0; i < numLocals; i++) {
+            auto old = curr->contents.start[i];
+            // If we already had a merge value here, keep it.
+            // TODO This may have some false positives, as we may e.g. have
+            //      a single pred that first gives us x, then later y after
+            //      flow led to a merge, and we may see x and y at the same
+            //      time due to flow from a successor, and then it looks like
+            //      we need a merge but we don't. avoiding that would require
+            //      more memory and is probably not worth it, but might be
+            //      worth investigating
+            // NB While suboptimal, this simplification provides a simple proof
+            //    of convergence. We prove that, in each fixed block+local,
+            //    the value number at the end is nondecreasing across
+            //    iterations, by induction on the iteration:
+            //     * The first iteration is on the entry block. It increases
+            //       the value number at the end from 0 (unseen) to something
+            //       else (a value number for 0 for locals, a unique value
+            //       for params; all >0).
+            //     * Induction step: assuming the property holds for all past
+            //       iterations, consider the current iteration. Of our
+            //       predecessors, those that we iterated on have the property;
+            //       those that we haven't will have 0 (unseen).
+            //        * If we assign to that local in this block, that will be
+            //          the value in the output, forever, and it is greater
+            //          than the initial value of 0.
+            //        * If we see different values coming in, we create a merge
+            //          value number. Its number is higher than everything
+            //          else since we give it the next available number, so we
+            //          do not decrease in this iteration, and we will output
+            //          the same value in the future too (here is where we use
+            //          the simplification property).
+            //        * Otherwise, we will flow the incoming value through,
+            //          and it did not decrease (by induction), so neither do
+            //          we.
+            //    Finally, given value numbers are nondecreasing, we must
+            //    converge since we only keep working as long as we see new
+            //    values at the end of a block.
+            //
+            //    Not that we don't trust this proof, but the convergence
+            //    property (value numbers at block ends do not decrease) is
+            //    verified later down.
+            if (isBlockMergeValue(curr, i, old)) {
+              continue;
+            }
+            auto iter = in.begin();
+            auto value = (*iter)->contents.end[i];
+            iter++;
+            while (iter != in.end()) {
+              auto otherValue = (*iter)->contents.end[i];
+              if (value == getUnseenValue()) {
+                value = otherValue;
+              } else if (otherValue == getUnseenValue()) {
+                // nothing to do, other has no information
+              } else if (value != otherValue) {
+                // 2 different values, this is a merged value
+                value = getBlockMergeValue(curr, i);
+                break; // no more work once we see a merge
+              }
+              iter++;
+            }
+            curr->contents.start[i] = value;
+          }
+        }
+      }
+#ifdef RSE_DEBUG
+      dump("start", curr->contents.start);
+#endif
+      // flow values through it, then add those we can reach if they need an
+      // update.
+      auto currValues = curr->contents.start; // we'll modify this as we go
+      auto& setps = curr->contents.setps;
+      for (auto** setp : setps) {
+        auto* set = (*setp)->cast<LocalSet>();
+        currValues[set->index] = getValue(set->value, currValues);
+      }
+      if (currValues == curr->contents.end) {
+        // nothing changed, so no more work to do
+        // note that the first iteration this is always not the case,
+        // since end contains unseen (and then the comparison ends on
+        // the first element)
+        continue;
+      }
+      // update the end state and update children
+#ifndef NDEBUG
+      // verify the convergence property mentioned in the NB comment
+      // above: the value numbers at the end must be nondecreasing
+      for (Index i = 0; i < numLocals; i++) {
+        assert(currValues[i] >= curr->contents.end[i]);
+      }
+#endif
+      curr->contents.end.swap(currValues);
+#ifdef RSE_DEBUG
+      dump("end  ", curr->contents.end);
+#endif
+      for (auto* next : curr->out) {
+        work.push(next);
+      }
+    }
+  }
+
+  // optimizing
+  void optimize() {
+    // in each block, run the values through the sets,
+    // and remove redundant sets when we see them
+    for (auto& block : basicBlocks) {
+      auto currValues = block->contents.start; // we'll modify this as we go
+      auto& setps = block->contents.setps;
+      for (auto** setp : setps) {
+        auto* set = (*setp)->cast<LocalSet>();
+        auto oldValue = currValues[set->index];
+        auto newValue = getValue(set->value, currValues);
+        auto index = set->index;
+        if (newValue == oldValue) {
+          remove(setp);
+          continue; // no more work to do
+        }
+        // update for later steps
+        currValues[index] = newValue;
+      }
+    }
+  }
+
+  void remove(Expression** setp) {
+    auto* set = (*setp)->cast<LocalSet>();
+    auto* value = set->value;
+    if (!set->isTee()) {
+      auto* drop = ExpressionManipulator::convert<LocalSet, Drop>(set);
+      drop->value = value;
+      drop->finalize();
+    } else {
+      *setp = value;
+    }
+  }
+
+  // debugging
+
+  void dump(BasicBlock* block) {
+    std::cout << "====\n";
+    if (block) {
+      std::cout << "block: " << block << '\n';
+      for (auto* out : block->out) {
+        std::cout << "  goes to " << out << '\n';
+      }
+    }
+    for (Index i = 0; i < block->contents.start.size(); i++) {
+      std::cout << "  start[" << i << "] = " << block->contents.start[i]
+                << '\n';
+    }
+    for (auto** setp : block->contents.setps) {
+      std::cout << "  " << *setp << '\n';
+    }
+    std::cout << "====\n";
+  }
+
+  void dump(const char* desc, LocalValues& values) {
+    std::cout << desc << ": ";
+    for (auto x : values) {
+      std::cout << x << ' ';
+    }
+    std::cout << '\n';
+  }
+};
+
+} // namespace
+
+Pass* createRedundantSetEliminationPass() {
+  return new RedundantSetElimination();
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/RemoveImports.cpp b/binaryen/src/passes/RemoveImports.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/RemoveImports.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// Removes function imports, and replaces them with nops. This is useful
+// for running a module through the reference interpreter, which
+// does not validate imports for a JS environment (by removing
+// imports, we can at least get the reference interpreter to
+// look at all the rest of the code).
+//
+
+#include "ir/module-utils.h"
+#include "pass.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct RemoveImports : public WalkerPass<PostWalker<RemoveImports>> {
+  void visitCall(Call* curr) {
+    auto* func = getModule()->getFunction(curr->target);
+    if (!func->imported()) {
+      return;
+    }
+    Type type = func->sig.results;
+    if (type == Type::none) {
+      replaceCurrent(getModule()->allocator.alloc<Nop>());
+    } else {
+      Literal nopLiteral(type);
+      replaceCurrent(getModule()->allocator.alloc<Const>()->set(nopLiteral));
+    }
+  }
+
+  void visitModule(Module* curr) {
+    std::vector<Name> names;
+    ModuleUtils::iterImportedFunctions(
+      *curr, [&](Function* func) { names.push_back(func->name); });
+    // Do not remove names referenced in a table
+    std::set<Name> indirectNames;
+    if (curr->table.exists) {
+      for (auto& segment : curr->table.segments) {
+        for (auto& name : segment.data) {
+          indirectNames.insert(name);
+        }
+      }
+    }
+    for (auto& name : names) {
+      if (indirectNames.find(name) == indirectNames.end()) {
+        curr->removeFunction(name);
+      }
+    }
+  }
+};
+
+Pass* createRemoveImportsPass() { return new RemoveImports(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/RemoveMemory.cpp b/binaryen/src/passes/RemoveMemory.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/RemoveMemory.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+//
+// Removeds memory segments, leaving only code in the module.
+//
+
+#include <pass.h>
+#include <wasm.h>
+
+namespace wasm {
+
+struct RemoveMemory : public Pass {
+  void run(PassRunner* runner, Module* module) override {
+    module->memory.segments.clear();
+  }
+};
+
+Pass* createRemoveMemoryPass() { return new RemoveMemory(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/RemoveNonJSOps.cpp b/binaryen/src/passes/RemoveNonJSOps.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/RemoveNonJSOps.cpp
@@ -0,0 +1,392 @@
+/*
+ * 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.
+ */
+
+//
+// RemoveNonJSOps removes operations that aren't inherently implementable
+// in JS. This includes things like 64-bit division, `f32.nearest`,
+// `f64.copysign`, etc. Most operations are lowered to a call to an injected
+// intrinsic implementation. Intrinsics don't use themselves to implement
+// themselves.
+//
+// You'll find a large wat blob in `wasm-intrinsics.wat` next to this file
+// which contains all of the injected intrinsics. We manually copy over any
+// needed intrinsics from this module into the module that we're optimizing
+// after walking the current module.
+//
+// StubUnsupportedJSOps stubs out operations that are not fully supported
+// even with RemoveNonJSOps. For example, i64->f32 conversions do not have
+// perfect rounding in all cases. StubUnsupportedJSOps removes those entirely
+// and replaces them with "stub" operations that do nothing. This is only
+// really useful for fuzzing as it changes the behavior of the program.
+//
+
+#include <pass.h>
+#include <wasm.h>
+
+#include "abi/js.h"
+#include "asmjs/shared-constants.h"
+#include "ir/find_all.h"
+#include "ir/literal-utils.h"
+#include "ir/memory-utils.h"
+#include "ir/module-utils.h"
+#include "passes/intrinsics-module.h"
+#include "wasm-builder.h"
+#include "wasm-s-parser.h"
+
+namespace wasm {
+
+struct RemoveNonJSOpsPass : public WalkerPass<PostWalker<RemoveNonJSOpsPass>> {
+  std::unique_ptr<Builder> builder;
+  std::unordered_set<Name> neededIntrinsics;
+  std::set<std::pair<Name, Type>> neededImportedGlobals;
+
+  bool isFunctionParallel() override { return false; }
+
+  Pass* create() override { return new RemoveNonJSOpsPass; }
+
+  void doWalkModule(Module* module) {
+    // Intrinsics may use scratch memory, ensure it.
+    ABI::wasm2js::ensureHelpers(module);
+
+    // Discover all of the intrinsics that we need to inject, lowering all
+    // operations to intrinsic calls while we're at it.
+    if (!builder) {
+      builder = make_unique<Builder>(*module);
+    }
+    PostWalker<RemoveNonJSOpsPass>::doWalkModule(module);
+
+    if (neededIntrinsics.size() == 0) {
+      return;
+    }
+
+    // Parse the wat blob we have at the end of this file.
+    //
+    // TODO: only do this once per invocation of wasm2asm
+    Module intrinsicsModule;
+    std::string input(IntrinsicsModuleWast);
+    SExpressionParser parser(const_cast<char*>(input.c_str()));
+    Element& root = *parser.root;
+    SExpressionWasmBuilder builder(
+      intrinsicsModule, *root[0], IRProfile::Normal);
+
+    std::set<Name> neededFunctions;
+
+    // Iteratively link intrinsics from `intrinsicsModule` into our destination
+    // module, as needed.
+    //
+    // Note that intrinsics often use one another. For example the 64-bit
+    // division intrinsic ends up using the 32-bit ctz intrinsic, but does so
+    // via a native instruction. The loop here is used to continuously reprocess
+    // injected intrinsics to ensure that they never contain non-js ops when
+    // we're done.
+    while (neededIntrinsics.size() > 0) {
+      // Recursively probe all needed intrinsics for transitively used
+      // functions. This is building up a set of functions we'll link into our
+      // module.
+      for (auto& name : neededIntrinsics) {
+        addNeededFunctions(intrinsicsModule, name, neededFunctions);
+      }
+      neededIntrinsics.clear();
+
+      // Link in everything that wasn't already linked in. After we've done the
+      // copy we then walk the function to rewrite any non-js operations it has
+      // as well.
+      for (auto& name : neededFunctions) {
+        auto* func = module->getFunctionOrNull(name);
+        if (!func) {
+          func = ModuleUtils::copyFunction(intrinsicsModule.getFunction(name),
+                                           *module);
+        }
+        doWalkFunction(func);
+      }
+      neededFunctions.clear();
+    }
+
+    // Copy all the globals in the intrinsics module
+    for (auto& global : intrinsicsModule.globals) {
+      ModuleUtils::copyGlobal(global.get(), *module);
+    }
+
+    // Intrinsics may use memory, so ensure the module has one.
+    MemoryUtils::ensureExists(module->memory);
+
+    // Add missing globals
+    for (auto& pair : neededImportedGlobals) {
+      auto name = pair.first;
+      auto type = pair.second;
+      if (!getModule()->getGlobalOrNull(name)) {
+        auto global = make_unique<Global>();
+        global->name = name;
+        global->type = type;
+        global->mutable_ = false;
+        global->module = ENV;
+        global->base = name;
+        module->addGlobal(global.release());
+      }
+    }
+  }
+
+  void addNeededFunctions(Module& m, Name name, std::set<Name>& needed) {
+    if (needed.count(name)) {
+      return;
+    }
+    needed.insert(name);
+
+    auto function = m.getFunction(name);
+    FindAll<Call> calls(function->body);
+    for (auto* call : calls.list) {
+      auto* called = m.getFunction(call->target);
+      if (!called->imported()) {
+        this->addNeededFunctions(m, call->target, needed);
+      }
+    }
+  }
+
+  void doWalkFunction(Function* func) {
+    if (!builder) {
+      builder = make_unique<Builder>(*getModule());
+    }
+    PostWalker<RemoveNonJSOpsPass>::doWalkFunction(func);
+  }
+
+  void visitLoad(Load* curr) {
+    if (curr->align == 0 || curr->align >= curr->bytes) {
+      return;
+    }
+
+    // Switch unaligned loads of floats to unaligned loads of integers (which we
+    // can actually implement) and then use reinterpretation to get the float
+    // back out.
+    switch (curr->type.getBasic()) {
+      case Type::f32:
+        curr->type = Type::i32;
+        replaceCurrent(builder->makeUnary(ReinterpretInt32, curr));
+        break;
+      case Type::f64:
+        curr->type = Type::i64;
+        replaceCurrent(builder->makeUnary(ReinterpretInt64, curr));
+        break;
+      default:
+        break;
+    }
+  }
+
+  void visitStore(Store* curr) {
+    if (curr->align == 0 || curr->align >= curr->bytes) {
+      return;
+    }
+
+    // Switch unaligned stores of floats to unaligned stores of integers (which
+    // we can actually implement) and then use reinterpretation to store the
+    // right value.
+    switch (curr->valueType.getBasic()) {
+      case Type::f32:
+        curr->valueType = Type::i32;
+        curr->value = builder->makeUnary(ReinterpretFloat32, curr->value);
+        break;
+      case Type::f64:
+        curr->valueType = Type::i64;
+        curr->value = builder->makeUnary(ReinterpretFloat64, curr->value);
+        break;
+      default:
+        break;
+    }
+  }
+
+  void visitBinary(Binary* curr) {
+    Name name;
+    switch (curr->op) {
+      case CopySignFloat32:
+      case CopySignFloat64:
+        rewriteCopysign(curr);
+        return;
+
+      case RotLInt32:
+        name = WASM_ROTL32;
+        break;
+      case RotRInt32:
+        name = WASM_ROTR32;
+        break;
+      case RotLInt64:
+        name = WASM_ROTL64;
+        break;
+      case RotRInt64:
+        name = WASM_ROTR64;
+        break;
+      case MulInt64:
+        name = WASM_I64_MUL;
+        break;
+      case DivSInt64:
+        name = WASM_I64_SDIV;
+        break;
+      case DivUInt64:
+        name = WASM_I64_UDIV;
+        break;
+      case RemSInt64:
+        name = WASM_I64_SREM;
+        break;
+      case RemUInt64:
+        name = WASM_I64_UREM;
+        break;
+
+      default:
+        return;
+    }
+    neededIntrinsics.insert(name);
+    replaceCurrent(
+      builder->makeCall(name, {curr->left, curr->right}, curr->type));
+  }
+
+  void rewriteCopysign(Binary* curr) {
+    Literal signBit, otherBits;
+    UnaryOp int2float, float2int;
+    BinaryOp bitAnd, bitOr;
+    switch (curr->op) {
+      case CopySignFloat32:
+        float2int = ReinterpretFloat32;
+        int2float = ReinterpretInt32;
+        bitAnd = AndInt32;
+        bitOr = OrInt32;
+        signBit = Literal(uint32_t(1 << 31));
+        otherBits = Literal(uint32_t(1 << 31) - 1);
+        break;
+
+      case CopySignFloat64:
+        float2int = ReinterpretFloat64;
+        int2float = ReinterpretInt64;
+        bitAnd = AndInt64;
+        bitOr = OrInt64;
+        signBit = Literal(uint64_t(1) << 63);
+        otherBits = Literal((uint64_t(1) << 63) - 1);
+        break;
+
+      default:
+        return;
+    }
+
+    replaceCurrent(builder->makeUnary(
+      int2float,
+      builder->makeBinary(
+        bitOr,
+        builder->makeBinary(bitAnd,
+                            builder->makeUnary(float2int, curr->left),
+                            builder->makeConst(otherBits)),
+        builder->makeBinary(bitAnd,
+                            builder->makeUnary(float2int, curr->right),
+                            builder->makeConst(signBit)))));
+  }
+
+  void visitUnary(Unary* curr) {
+    Name functionCall;
+    switch (curr->op) {
+      case NearestFloat32:
+        functionCall = WASM_NEAREST_F32;
+        break;
+      case NearestFloat64:
+        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;
+      case PopcntInt32:
+        functionCall = WASM_POPCNT32;
+        break;
+
+      case CtzInt64:
+        functionCall = WASM_CTZ64;
+        break;
+      case CtzInt32:
+        functionCall = WASM_CTZ32;
+        break;
+
+      default:
+        return;
+    }
+    neededIntrinsics.insert(functionCall);
+    replaceCurrent(builder->makeCall(functionCall, {curr->value}, curr->type));
+  }
+
+  void visitGlobalGet(GlobalGet* curr) {
+    neededImportedGlobals.insert(std::make_pair(curr->name, curr->type));
+  }
+};
+
+struct StubUnsupportedJSOpsPass
+  : public WalkerPass<PostWalker<StubUnsupportedJSOpsPass>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new StubUnsupportedJSOpsPass; }
+
+  void visitUnary(Unary* curr) {
+    switch (curr->op) {
+      case ConvertUInt64ToFloat32:
+        // See detailed comment in lowerConvertIntToFloat in
+        // I64ToI32Lowering.cpp.
+        stubOut(curr->value, curr->type);
+        break;
+      default: {
+      }
+    }
+  }
+
+  void visitCallIndirect(CallIndirect* curr) {
+    // Indirect calls of the wrong type trap in wasm, but not in wasm2js. Remove
+    // the indirect call, but leave the arguments.
+    Builder builder(*getModule());
+    std::vector<Expression*> items;
+    for (auto* operand : curr->operands) {
+      items.push_back(builder.makeDrop(operand));
+    }
+    items.push_back(builder.makeDrop(curr->target));
+    stubOut(builder.makeBlock(items), curr->type);
+  }
+
+  void stubOut(Expression* value, Type outputType) {
+    Builder builder(*getModule());
+    // In some cases we can just replace with the value.
+    auto* replacement = value;
+    if (outputType == Type::unreachable) {
+      // This is unreachable anyhow; just leave the value instead of the
+      // original node.
+      assert(value->type == Type::unreachable);
+    } else if (outputType != Type::none) {
+      // Drop the value if we need to.
+      if (value->type != Type::none) {
+        value = builder.makeDrop(value);
+      }
+      // Return something with the right output type.
+      replacement = builder.makeSequence(
+        value, LiteralUtils::makeZero(outputType, *getModule()));
+    }
+    replaceCurrent(replacement);
+  }
+};
+
+Pass* createRemoveNonJSOpsPass() { return new RemoveNonJSOpsPass(); }
+
+Pass* createStubUnsupportedJSOpsPass() {
+  return new StubUnsupportedJSOpsPass();
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/RemoveUnusedBrs.cpp b/binaryen/src/passes/RemoveUnusedBrs.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/RemoveUnusedBrs.cpp
@@ -0,0 +1,1299 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// Removes branches for which we go to where they go anyhow
+//
+
+#include <ir/branch-utils.h>
+#include <ir/cost.h>
+#include <ir/effects.h>
+#include <ir/literal-utils.h>
+#include <ir/utils.h>
+#include <parsing.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+namespace wasm {
+
+// to turn an if into a br-if, we must be able to reorder the
+// condition and possible value, and the possible value must
+// not have side effects (as they would run unconditionally)
+static bool canTurnIfIntoBrIf(Expression* ifCondition,
+                              Expression* brValue,
+                              PassOptions& options,
+                              FeatureSet features) {
+  // if the if isn't even reached, this is all dead code anyhow
+  if (ifCondition->type == Type::unreachable) {
+    return false;
+  }
+  if (!brValue) {
+    return true;
+  }
+  EffectAnalyzer value(options, features, brValue);
+  if (value.hasSideEffects()) {
+    return false;
+  }
+  return !EffectAnalyzer(options, features, ifCondition).invalidates(value);
+}
+
+// Check if it is not worth it to run code unconditionally. This
+// assumes we are trying to run two expressions where previously
+// only one of the two might have executed. We assume here that
+// executing both is good for code size.
+static bool tooCostlyToRunUnconditionally(const PassOptions& passOptions,
+                                          Expression* one,
+                                          Expression* two) {
+  // If we care mostly about code size, just do it for that reason.
+  if (passOptions.shrinkLevel) {
+    return false;
+  }
+  // Consider the cost of executing all the code unconditionally.
+  const auto TOO_MUCH = 7;
+  auto total = CostAnalyzer(one).cost + CostAnalyzer(two).cost;
+  return total >= TOO_MUCH;
+}
+
+struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new RemoveUnusedBrs; }
+
+  bool anotherCycle;
+
+  typedef std::vector<Expression**> Flows;
+
+  // list of breaks that are currently flowing. if they reach their target
+  // without interference, they can be removed (or their value forwarded TODO)
+  Flows flows;
+
+  // a stack for if-else contents, we merge their outputs
+  std::vector<Flows> ifStack;
+
+  // list of all loops, so we can optimize them
+  std::vector<Loop*> loops;
+
+  static void visitAny(RemoveUnusedBrs* self, Expression** currp) {
+    auto* curr = *currp;
+    auto& flows = self->flows;
+
+    if (curr->is<Break>()) {
+      flows.clear();
+      auto* br = curr->cast<Break>();
+      if (!br->condition) { // TODO: optimize?
+        // a break, let's see where it flows to
+        flows.push_back(currp);
+      } else {
+        self->stopValueFlow();
+      }
+    } else if (curr->is<Return>()) {
+      flows.clear();
+      flows.push_back(currp);
+    } else if (curr->is<If>()) {
+      auto* iff = curr->cast<If>();
+      if (iff->condition->type == Type::unreachable) {
+        // avoid trying to optimize this, we never reach it anyhow
+        self->stopFlow();
+        return;
+      }
+      if (iff->ifFalse) {
+        assert(self->ifStack.size() > 0);
+        auto ifTrueFlows = std::move(self->ifStack.back());
+        self->ifStack.pop_back();
+        // we can flow values out in most cases, except if one arm
+        // has the none type - we will update the types later, but
+        // there is no way to emit a proper type for one arm being
+        // none and the other flowing a value; and there is no way
+        // to flow a value from a none.
+        if (iff->ifTrue->type == Type::none ||
+            iff->ifFalse->type == Type::none) {
+          self->removeValueFlow(ifTrueFlows);
+          self->stopValueFlow();
+        }
+        for (auto* flow : ifTrueFlows) {
+          flows.push_back(flow);
+        }
+      } else {
+        // if without else stops the flow of values
+        self->stopValueFlow();
+      }
+    } else if (auto* block = curr->dynCast<Block>()) {
+      // any breaks flowing to here are unnecessary, as we get here anyhow
+      auto name = block->name;
+      auto& list = block->list;
+      if (name.is()) {
+        Index size = flows.size();
+        Index skip = 0;
+        for (Index i = 0; i < size; i++) {
+          auto* flow = (*flows[i])->dynCast<Break>();
+          if (flow && flow->name == name) {
+            if (!flow->value) {
+              // br => nop
+              ExpressionManipulator::nop<Break>(flow);
+            } else {
+              // br with value => value
+              *flows[i] = flow->value;
+            }
+            skip++;
+            self->anotherCycle = true;
+          } else if (skip > 0) {
+            flows[i - skip] = flows[i];
+          }
+        }
+        if (skip > 0) {
+          flows.resize(size - skip);
+        }
+        // drop a nop at the end of a block, which prevents a value flowing
+        while (list.size() > 0 && list.back()->is<Nop>()) {
+          list.resize(list.size() - 1);
+          self->anotherCycle = true;
+        }
+      }
+      // A value flowing is only valid if it is a value that the block actually
+      // flows out. If it is never reached, it does not flow out, and may be
+      // invalid to represent as such.
+      auto size = list.size();
+      for (Index i = 0; i < size; i++) {
+        if (i != size - 1 && list[i]->type == Type::unreachable) {
+          // No value flows out of this block.
+          self->stopValueFlow();
+          break;
+        }
+      }
+    } else if (curr->is<Nop>()) {
+      // ignore (could be result of a previous cycle)
+      self->stopValueFlow();
+    } else if (curr->is<Loop>()) {
+      // do nothing - it's ok for values to flow out
+    } else if (auto* sw = curr->dynCast<Switch>()) {
+      self->stopFlow();
+      self->optimizeSwitch(sw);
+    } else {
+      // anything else stops the flow
+      self->stopFlow();
+    }
+  }
+
+  void stopFlow() { flows.clear(); }
+
+  void removeValueFlow(Flows& currFlows) {
+    currFlows.erase(std::remove_if(currFlows.begin(),
+                                   currFlows.end(),
+                                   [&](Expression** currp) {
+                                     auto* curr = *currp;
+                                     if (auto* ret = curr->dynCast<Return>()) {
+                                       return ret->value;
+                                     }
+                                     return curr->cast<Break>()->value;
+                                   }),
+                    currFlows.end());
+  }
+
+  void stopValueFlow() { removeValueFlow(flows); }
+
+  static void clear(RemoveUnusedBrs* self, Expression** currp) {
+    self->flows.clear();
+  }
+
+  static void saveIfTrue(RemoveUnusedBrs* self, Expression** currp) {
+    self->ifStack.push_back(std::move(self->flows));
+  }
+
+  void visitLoop(Loop* curr) { loops.push_back(curr); }
+
+  void optimizeSwitch(Switch* curr) {
+    // if the final element is the default, we don't need it
+    while (!curr->targets.empty() && curr->targets.back() == curr->default_) {
+      curr->targets.pop_back();
+    }
+    // if the first element is the default, we can remove it by shifting
+    // everything (which does add a subtraction of a constant, but often that is
+    // worth it as the constant can be folded away and/or we remove multiple
+    // elements here)
+    Index removable = 0;
+    while (removable < curr->targets.size() &&
+           curr->targets[removable] == curr->default_) {
+      removable++;
+    }
+    if (removable > 0) {
+      for (Index i = removable; i < curr->targets.size(); i++) {
+        curr->targets[i - removable] = curr->targets[i];
+      }
+      curr->targets.resize(curr->targets.size() - removable);
+      Builder builder(*getModule());
+      curr->condition = builder.makeBinary(
+        SubInt32, curr->condition, builder.makeConst(int32_t(removable)));
+    }
+    // when there isn't a value, we can do some trivial optimizations without
+    // worrying about the value being executed before the condition
+    if (curr->value) {
+      return;
+    }
+    if (curr->targets.size() == 0) {
+      // a switch with just a default always goes there
+      Builder builder(*getModule());
+      replaceCurrent(builder.makeSequence(builder.makeDrop(curr->condition),
+                                          builder.makeBreak(curr->default_)));
+    } else if (curr->targets.size() == 1) {
+      // a switch with two options is basically an if
+      Builder builder(*getModule());
+      replaceCurrent(builder.makeIf(curr->condition,
+                                    builder.makeBreak(curr->default_),
+                                    builder.makeBreak(curr->targets.front())));
+    } else {
+      // there are also some other cases where we want to convert a switch into
+      // ifs, especially if the switch is large and we are focusing on size. an
+      // especially egregious case is a switch like this: [a b b [..] b b c]
+      // with default b (which may be arrived at after we trim away excess
+      // default values on both sides). in this case, we really have 3 values in
+      // a simple form, so it is the next logical case after handling 1 and 2
+      // values right above here. to optimize this, we must add a local + a
+      // bunch of nodes (if*2, tee, eq, get, const, break*3), so the table must
+      // be big enough for it to make sense
+
+      // How many targets we need when shrinking. This is literally the size at
+      // which the transformation begins to be smaller.
+      const uint32_t MIN_SHRINK = 13;
+      // How many targets we need when not shrinking, in which case, 2 ifs may
+      // be slower, so we do this when the table is ridiculously large for one
+      // with just 3 values in it.
+      const uint32_t MIN_GENERAL = 128;
+
+      auto shrink = getPassRunner()->options.shrinkLevel > 0;
+      if ((curr->targets.size() >= MIN_SHRINK && shrink) ||
+          (curr->targets.size() >= MIN_GENERAL && !shrink)) {
+        for (Index i = 1; i < curr->targets.size() - 1; i++) {
+          if (curr->targets[i] != curr->default_) {
+            return;
+          }
+        }
+        // great, we are in that case, optimize
+        Builder builder(*getModule());
+        auto temp = builder.addVar(getFunction(), Type::i32);
+        Expression* z;
+        replaceCurrent(z = builder.makeIf(
+                         builder.makeLocalTee(temp, curr->condition, Type::i32),
+                         builder.makeIf(builder.makeBinary(
+                                          EqInt32,
+                                          builder.makeLocalGet(temp, Type::i32),
+                                          builder.makeConst(
+                                            int32_t(curr->targets.size() - 1))),
+                                        builder.makeBreak(curr->targets.back()),
+                                        builder.makeBreak(curr->default_)),
+                         builder.makeBreak(curr->targets.front())));
+      }
+    }
+  }
+
+  void visitIf(If* curr) {
+    FeatureSet features = getModule()->features;
+    if (!curr->ifFalse) {
+      // if without an else. try to reduce
+      //    if (condition) br  =>  br_if (condition)
+      if (Break* br = curr->ifTrue->dynCast<Break>()) {
+        if (canTurnIfIntoBrIf(
+              curr->condition, br->value, getPassOptions(), features)) {
+          if (!br->condition) {
+            br->condition = curr->condition;
+          } else {
+            // In this case we can replace
+            //   if (condition1) br_if (condition2)
+            // =>
+            //   br_if select (condition1) (condition2) (i32.const 0)
+            // In other words, we replace an if (3 bytes) with a select and a
+            // zero (also 3 bytes). The size is unchanged, but the select may
+            // be further optimizable, and if select does not branch we also
+            // avoid one branch.
+            // Multivalue selects are not supported
+            if (br->value && br->value->type.isTuple()) {
+              return;
+            }
+            // If running the br's condition unconditionally is too expensive,
+            // give up.
+            auto* zero = LiteralUtils::makeZero(Type::i32, *getModule());
+            if (tooCostlyToRunUnconditionally(
+                  getPassOptions(), br->condition, zero)) {
+              return;
+            }
+            // Of course we can't do this if the br's condition has side
+            // effects, as we would then execute those unconditionally.
+            if (EffectAnalyzer(getPassOptions(), features, br->condition)
+                  .hasSideEffects()) {
+              return;
+            }
+            Builder builder(*getModule());
+            // Note that we use the br's condition as the select condition.
+            // That keeps the order of the two conditions as it was originally.
+            br->condition =
+              builder.makeSelect(br->condition, curr->condition, zero);
+          }
+          br->finalize();
+          replaceCurrent(Builder(*getModule()).dropIfConcretelyTyped(br));
+          anotherCycle = true;
+        }
+      }
+    }
+    // TODO: if-else can be turned into a br_if as well, if one of the sides is
+    //       a dead end we handle the case of a returned value to a local.set
+    //       later down, see visitLocalSet.
+  }
+
+  // override scan to add a pre and a post check task to all nodes
+  static void scan(RemoveUnusedBrs* self, Expression** currp) {
+    self->pushTask(visitAny, currp);
+
+    auto* iff = (*currp)->dynCast<If>();
+
+    if (iff) {
+      if (iff->condition->type == Type::unreachable) {
+        // avoid trying to optimize this, we never reach it anyhow
+        return;
+      }
+      self->pushTask(doVisitIf, currp);
+      if (iff->ifFalse) {
+        // we need to join up if-else control flow, and clear after the
+        // condition
+        self->pushTask(scan, &iff->ifFalse);
+        // safe the ifTrue flow, we'll join it later
+        self->pushTask(saveIfTrue, currp);
+      }
+      self->pushTask(scan, &iff->ifTrue);
+      self->pushTask(clear, currp); // clear all flow after the condition
+      self->pushTask(scan, &iff->condition);
+    } else {
+      super::scan(self, currp);
+    }
+  }
+
+  // optimizes a loop. returns true if we made changes
+  bool optimizeLoop(Loop* loop) {
+    // if a loop ends in
+    // (loop $in
+    //   (block $out
+    //     if (..) br $in; else br $out;
+    //   )
+    // )
+    // then our normal opts can remove the break out since it flows directly out
+    // (and later passes make the if one-armed). however, the simple analysis
+    // fails on patterns like
+    //     if (..) br $out;
+    //     br $in;
+    // which is a common way to do a while (1) loop (end it with a jump to the
+    // top), so we handle that here. Specifically we want to conditionalize
+    // breaks to the loop top, i.e., put them behind a condition, so that other
+    // code can flow directly out and thus brs out can be removed. (even if
+    // the change is to let a break somewhere else flow out, that can still be
+    // helpful, as it shortens the logical loop. it is also good to generate
+    // an if-else instead of an if, as it might allow an eqz to be removed
+    // by flipping arms)
+    if (!loop->name.is()) {
+      return false;
+    }
+    auto* block = loop->body->dynCast<Block>();
+    if (!block) {
+      return false;
+    }
+    // does the last element break to the top of the loop?
+    auto& list = block->list;
+    if (list.size() <= 1) {
+      return false;
+    }
+    auto* last = list.back()->dynCast<Break>();
+    if (!last || !ExpressionAnalyzer::isSimple(last) ||
+        last->name != loop->name) {
+      return false;
+    }
+    // last is a simple break to the top of the loop. if we can conditionalize
+    // it, it won't block things from flowing out and not needing breaks to do
+    // so.
+    Index i = list.size() - 2;
+    Builder builder(*getModule());
+    while (1) {
+      auto* curr = list[i];
+      if (auto* iff = curr->dynCast<If>()) {
+        // let's try to move the code going to the top of the loop into the
+        // if-else
+        if (!iff->ifFalse) {
+          // we need the ifTrue to break, so it cannot reach the code we want to
+          // move
+          if (iff->ifTrue->type == Type::unreachable) {
+            iff->ifFalse = builder.stealSlice(block, i + 1, list.size());
+            iff->finalize();
+            block->finalize();
+            return true;
+          }
+        } else {
+          // this is already an if-else. if one side is a dead end, we can
+          // append to the other, if there is no returned value to concern us
+
+          // can't be, since in the middle of a block
+          assert(!iff->type.isConcrete());
+
+          // ensures the first node is a block, if it isn't already, and merges
+          // in the second, either as a single element or, if a block, by
+          // appending to the first block. this keeps the order of operations in
+          // place, that is, the appended element will be executed after the
+          // first node's elements
+          auto blockifyMerge = [&](Expression* any,
+                                   Expression* append) -> Block* {
+            Block* block = nullptr;
+            if (any) {
+              block = any->dynCast<Block>();
+            }
+            // if the first isn't a block, or it's a block with a name (so we
+            // might branch to the end, and so can't append to it, we might skip
+            // that code!) then make a new block
+            if (!block || block->name.is()) {
+              block = builder.makeBlock(any);
+            } else {
+              assert(!block->type.isConcrete());
+            }
+            auto* other = append->dynCast<Block>();
+            if (!other) {
+              block->list.push_back(append);
+            } else {
+              for (auto* item : other->list) {
+                block->list.push_back(item);
+              }
+            }
+            block->finalize();
+            return block;
+          };
+
+          if (iff->ifTrue->type == Type::unreachable) {
+            iff->ifFalse = blockifyMerge(
+              iff->ifFalse, builder.stealSlice(block, i + 1, list.size()));
+            iff->finalize();
+            block->finalize();
+            return true;
+          } else if (iff->ifFalse->type == Type::unreachable) {
+            iff->ifTrue = blockifyMerge(
+              iff->ifTrue, builder.stealSlice(block, i + 1, list.size()));
+            iff->finalize();
+            block->finalize();
+            return true;
+          }
+        }
+        return false;
+      } else if (auto* brIf = curr->dynCast<Break>()) {
+        // br_if is similar to if.
+        if (brIf->condition && !brIf->value && brIf->name != loop->name) {
+          if (i == list.size() - 2) {
+            // there is the br_if, and then the br to the top, so just flip them
+            // and the condition
+            brIf->condition = builder.makeUnary(EqZInt32, brIf->condition);
+            last->name = brIf->name;
+            brIf->name = loop->name;
+            return true;
+          } else {
+            // there are elements in the middle,
+            //   br_if $somewhere (condition)
+            //   (..more..)
+            //   br $in
+            // we can convert the br_if to an if. this has a cost, though,
+            // so only do it if it looks useful, which it definitely is if
+            //  (a) $somewhere is straight out (so the br out vanishes), and
+            //  (b) this br_if is the only branch to that block (so the block
+            //      will vanish)
+            if (brIf->name == block->name &&
+                BranchUtils::BranchSeeker::count(block, block->name) == 1) {
+              // note that we could drop the last element here, it is a br we
+              // know for sure is removable, but telling stealSlice to steal all
+              // to the end is more efficient, it can just truncate.
+              list[i] =
+                builder.makeIf(brIf->condition,
+                               builder.makeBreak(brIf->name),
+                               builder.stealSlice(block, i + 1, list.size()));
+              return true;
+            }
+          }
+        }
+        return false;
+      }
+      // if there is control flow, we must stop looking
+      if (EffectAnalyzer(getPassOptions(), getModule()->features, curr)
+            .transfersControlFlow()) {
+        return false;
+      }
+      if (i == 0) {
+        return false;
+      }
+      i--;
+    }
+  }
+
+  bool sinkBlocks(Function* func) {
+    struct Sinker : public PostWalker<Sinker> {
+      bool worked = false;
+
+      void visitBlock(Block* curr) {
+        // If the block has a single child which is a loop, and the block is
+        // named, then it is the exit for the loop. It's better to move it into
+        // the loop, where it can be better optimized by other passes. Similar
+        // logic for ifs: if the block is an exit for the if, we can move the
+        // block in, consider for example:
+        //    (block $label
+        //     (if (..condition1..)
+        //      (block
+        //       (br_if $label (..condition2..))
+        //       (..code..)
+        //      )
+        //     )
+        //    )
+        // After also merging the blocks, we have
+        //    (if (..condition1..)
+        //     (block $label
+        //      (br_if $label (..condition2..))
+        //      (..code..)
+        //     )
+        //    )
+        // which can be further optimized later.
+        if (curr->name.is() && curr->list.size() == 1) {
+          if (auto* loop = curr->list[0]->dynCast<Loop>()) {
+            curr->list[0] = loop->body;
+            loop->body = curr;
+            curr->finalize(curr->type);
+            loop->finalize();
+            replaceCurrent(loop);
+            worked = true;
+          } else if (auto* iff = curr->list[0]->dynCast<If>()) {
+            // The label can't be used in the condition.
+            if (BranchUtils::BranchSeeker::count(iff->condition, curr->name) ==
+                0) {
+              // We can move the block into either arm, if there are no uses in
+              // the other.
+              Expression** target = nullptr;
+              if (!iff->ifFalse || BranchUtils::BranchSeeker::count(
+                                     iff->ifFalse, curr->name) == 0) {
+                target = &iff->ifTrue;
+              } else if (BranchUtils::BranchSeeker::count(iff->ifTrue,
+                                                          curr->name) == 0) {
+                target = &iff->ifFalse;
+              }
+              if (target) {
+                curr->list[0] = *target;
+                *target = curr;
+                // The block used to contain the if, and may have changed type
+                // from unreachable to none, for example, if the if has an
+                // unreachable condition but the arm is not unreachable.
+                curr->finalize();
+                iff->finalize();
+                replaceCurrent(iff);
+                worked = true;
+                // Note that the type might change, e.g. if the if condition is
+                // unreachable but the block that was on the outside had a
+                // break.
+              }
+            }
+          }
+        }
+      }
+    } sinker;
+
+    sinker.doWalkFunction(func);
+    if (sinker.worked) {
+      ReFinalize().walkFunctionInModule(func, getModule());
+      return true;
+    }
+    return false;
+  }
+
+  void doWalkFunction(Function* func) {
+    // multiple cycles may be needed
+    do {
+      anotherCycle = false;
+      super::doWalkFunction(func);
+      assert(ifStack.empty());
+      // flows may contain returns, which are flowing out and so can be
+      // optimized
+      for (Index i = 0; i < flows.size(); i++) {
+        auto* flow = (*flows[i])->dynCast<Return>();
+        if (!flow) {
+          continue;
+        }
+        if (!flow->value) {
+          // return => nop
+          ExpressionManipulator::nop(flow);
+          anotherCycle = true;
+        } else {
+          // return with value => value
+          *flows[i] = flow->value;
+          anotherCycle = true;
+        }
+      }
+      flows.clear();
+      // optimize loops (we don't do it while tracking flows, as they can
+      // interfere)
+      for (auto* loop : loops) {
+        anotherCycle |= optimizeLoop(loop);
+      }
+      loops.clear();
+      if (anotherCycle) {
+        ReFinalize().walkFunctionInModule(func, getModule());
+      }
+      // sink blocks
+      if (sinkBlocks(func)) {
+        anotherCycle = true;
+      }
+    } while (anotherCycle);
+
+    // thread trivial jumps
+    struct JumpThreader : public ControlFlowWalker<JumpThreader> {
+      // map of all value-less breaks and switches going to a block (and not a
+      // loop)
+      std::map<Block*, std::vector<Expression*>> branchesToBlock;
+
+      bool worked = false;
+
+      void visitBreak(Break* curr) {
+        if (!curr->value) {
+          if (auto* target = findBreakTarget(curr->name)->dynCast<Block>()) {
+            branchesToBlock[target].push_back(curr);
+          }
+        }
+      }
+      void visitSwitch(Switch* curr) {
+        if (!curr->value) {
+          auto names = BranchUtils::getUniqueTargets(curr);
+          for (auto name : names) {
+            if (auto* target = findBreakTarget(name)->dynCast<Block>()) {
+              branchesToBlock[target].push_back(curr);
+            }
+          }
+        }
+      }
+      void visitBlock(Block* curr) {
+        auto& list = curr->list;
+        if (list.size() == 1 && curr->name.is()) {
+          // if this block has just one child, a sub-block, then jumps to the
+          // former are jumps to us, really
+          if (auto* child = list[0]->dynCast<Block>()) {
+            // the two blocks must have the same type for us to update the
+            // branch, as otherwise one block may be unreachable and the other
+            // concrete, so one might lack a value
+            if (child->name.is() && child->name != curr->name &&
+                child->type == curr->type) {
+              redirectBranches(child, curr->name);
+            }
+          }
+        } else if (list.size() == 2) {
+          // if this block has two children, a child-block and a simple jump,
+          // then jumps to child-block can be replaced with jumps to the new
+          // target
+          auto* child = list[0]->dynCast<Block>();
+          auto* jump = list[1]->dynCast<Break>();
+          if (child && child->name.is() && jump &&
+              ExpressionAnalyzer::isSimple(jump)) {
+            redirectBranches(child, jump->name);
+          }
+        }
+      }
+
+      void redirectBranches(Block* from, Name to) {
+        auto& branches = branchesToBlock[from];
+        for (auto* branch : branches) {
+          if (BranchUtils::replacePossibleTarget(branch, from->name, to)) {
+            worked = true;
+          }
+        }
+        // if the jump is to another block then we can update the list, and
+        // maybe push it even more later
+        if (auto* newTarget = findBreakTarget(to)->dynCast<Block>()) {
+          for (auto* branch : branches) {
+            branchesToBlock[newTarget].push_back(branch);
+          }
+        }
+      }
+
+      void finish(Function* func) {
+        if (worked) {
+          // by changing where brs go, we may change block types etc.
+          ReFinalize().walkFunctionInModule(func, getModule());
+        }
+      }
+    };
+    JumpThreader jumpThreader;
+    jumpThreader.setModule(getModule());
+    jumpThreader.walkFunction(func);
+    jumpThreader.finish(func);
+
+    // perform some final optimizations
+    struct FinalOptimizer : public PostWalker<FinalOptimizer> {
+      bool shrink;
+      PassOptions& passOptions;
+
+      bool needUniqify = false;
+
+      FinalOptimizer(PassOptions& passOptions) : passOptions(passOptions) {}
+
+      void visitBlock(Block* curr) {
+        // if a block has an if br else br, we can un-conditionalize the latter,
+        // allowing the if to become a br_if.
+        // * note that if not in a block already, then we need to create a block
+        //   for this, so not useful otherwise
+        // * note that this only happens at the end of a block, as code after
+        //   the if is dead
+        // * note that we do this at the end, because un-conditionalizing can
+        //   interfere with optimizeLoop()ing.
+        FeatureSet features = getModule()->features;
+        auto& list = curr->list;
+        for (Index i = 0; i < list.size(); i++) {
+          auto* iff = list[i]->dynCast<If>();
+          if (!iff || !iff->ifFalse) {
+            // if it lacked an if-false, it would already be a br_if, as that's
+            // the easy case
+            continue;
+          }
+          auto* ifTrueBreak = iff->ifTrue->dynCast<Break>();
+          if (ifTrueBreak && !ifTrueBreak->condition &&
+              canTurnIfIntoBrIf(
+                iff->condition, ifTrueBreak->value, passOptions, features)) {
+            // we are an if-else where the ifTrue is a break without a
+            // condition, so we can do this
+            ifTrueBreak->condition = iff->condition;
+            ifTrueBreak->finalize();
+            list[i] = Builder(*getModule()).dropIfConcretelyTyped(ifTrueBreak);
+            ExpressionManipulator::spliceIntoBlock(curr, i + 1, iff->ifFalse);
+            continue;
+          }
+          // otherwise, perhaps we can flip the if
+          auto* ifFalseBreak = iff->ifFalse->dynCast<Break>();
+          if (ifFalseBreak && !ifFalseBreak->condition &&
+              canTurnIfIntoBrIf(
+                iff->condition, ifFalseBreak->value, passOptions, features)) {
+            ifFalseBreak->condition =
+              Builder(*getModule()).makeUnary(EqZInt32, iff->condition);
+            ifFalseBreak->finalize();
+            list[i] = Builder(*getModule()).dropIfConcretelyTyped(ifFalseBreak);
+            ExpressionManipulator::spliceIntoBlock(curr, i + 1, iff->ifTrue);
+            continue;
+          }
+        }
+        if (list.size() >= 2) {
+          // combine/optimize adjacent br_ifs + a br (maybe _if) right after it
+          for (Index i = 0; i < list.size() - 1; i++) {
+            auto* br1 = list[i]->dynCast<Break>();
+            // avoid unreachable brs, as they are dead code anyhow, and after
+            // merging them the outer scope could need type changes
+            if (!br1 || !br1->condition || br1->type == Type::unreachable) {
+              continue;
+            }
+            assert(!br1->value);
+            auto* br2 = list[i + 1]->dynCast<Break>();
+            if (!br2 || br1->name != br2->name) {
+              continue;
+            }
+            assert(!br2->value); // same target as previous, which has no value
+            // a br_if and then a br[_if] with the same target right after it
+            if (br2->condition) {
+              if (shrink && br2->type != Type::unreachable) {
+                // Join adjacent br_ifs to the same target, making one br_if
+                // with a "selectified" condition that executes both.
+                if (!EffectAnalyzer(passOptions, features, br2->condition)
+                       .hasSideEffects()) {
+                  // it's ok to execute them both, do it
+                  Builder builder(*getModule());
+                  br1->condition =
+                    builder.makeBinary(OrInt32, br1->condition, br2->condition);
+                  ExpressionManipulator::nop(br2);
+                }
+              }
+            } else {
+              // merge, we go there anyhow
+              Builder builder(*getModule());
+              list[i] = builder.makeDrop(br1->condition);
+            }
+          }
+          // Combine adjacent br_ifs that test the same value into a br_table,
+          // when that makes sense.
+          tablify(curr);
+          // Pattern-patch ifs, recreating them when it makes sense.
+          restructureIf(curr);
+        }
+      }
+
+      void visitSwitch(Switch* curr) {
+        if (BranchUtils::getUniqueTargets(curr).size() == 1) {
+          // This switch has just one target no matter what; replace with a br
+          // if we can (to do so, we must put the condition before a possible
+          // value).
+          if (!curr->value || EffectAnalyzer::canReorder(passOptions,
+                                                         getModule()->features,
+                                                         curr->condition,
+                                                         curr->value)) {
+            Builder builder(*getModule());
+            replaceCurrent(builder.makeSequence(
+              builder.makeDrop(curr->condition), // might have side effects
+              builder.makeBreak(curr->default_, curr->value)));
+          }
+        }
+      }
+
+      // Restructuring of ifs: if we have
+      //   (block $x
+      //     (br_if $x (cond))
+      //     .., no other references to $x
+      //   )
+      // then we can turn that into (if (!cond) ..).
+      // Code size wise, we turn the block into an if (no change), and
+      // lose the br_if (-2). .. turns into the body of the if in the binary
+      // format. We need to flip the condition, which at worst adds 1.
+      // If the block has a return value, we can do something similar, removing
+      // the drop from the br_if and putting the if on the outside,
+      //   (block $x
+      //     (br_if $x (value) (cond))
+      //     .., no other references to $x
+      //     ..final element..
+      //   )
+      // =>
+      //   (if
+      //     (cond)
+      //     (value) ;; must not have side effects!
+      //     (block
+      //       .., no other references to $x
+      //       ..final element..
+      //     )
+      //   )
+      // This is beneficial as the block will likely go away in the binary
+      // format (the if arm is an implicit block), and the drop is removed.
+      void restructureIf(Block* curr) {
+        auto& list = curr->list;
+        // We should be called only on potentially-interesting lists.
+        assert(list.size() >= 2);
+        if (curr->name.is()) {
+          Break* br = nullptr;
+          Drop* drop = list[0]->dynCast<Drop>();
+          if (drop) {
+            br = drop->value->dynCast<Break>();
+          } else {
+            br = list[0]->dynCast<Break>();
+          }
+          // Check if the br is conditional and goes to the block. It may or may
+          // not have a value, depending on if it was dropped or not. If the
+          // type is unreachable that means it is not actually reached, which we
+          // can ignore.
+          if (br && br->condition && br->name == curr->name &&
+              br->type != Type::unreachable) {
+            if (BranchUtils::BranchSeeker::count(curr, curr->name) == 1) {
+              // no other breaks to that name, so we can do this
+              if (!drop) {
+                assert(!br->value);
+                Builder builder(*getModule());
+                replaceCurrent(builder.makeIf(
+                  builder.makeUnary(EqZInt32, br->condition), curr));
+                ExpressionManipulator::nop(br);
+                curr->finalize(curr->type);
+              } else {
+                // If the items we move around have side effects, we can't do
+                // this.
+                // TODO: we could use a select, in some cases..?
+                FeatureSet features = getModule()->features;
+                if (!EffectAnalyzer(passOptions, features, br->value)
+                       .hasSideEffects() &&
+                    !EffectAnalyzer(passOptions, features, br->condition)
+                       .hasSideEffects()) {
+                  ExpressionManipulator::nop(list[0]);
+                  Builder builder(*getModule());
+                  replaceCurrent(
+                    builder.makeIf(br->condition, br->value, curr));
+                }
+              }
+            }
+          }
+        }
+      }
+
+      void visitIf(If* curr) {
+        // we may have simplified ifs enough to turn them into selects
+        if (auto* select = selectify(curr)) {
+          replaceCurrent(select);
+        }
+      }
+
+      // Convert an if into a select, if possible and beneficial to do so.
+      Select* selectify(If* iff) {
+        if (!iff->ifFalse || !iff->ifTrue->type.isSingle() ||
+            !iff->ifFalse->type.isSingle()) {
+          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.
+        if (tooCostlyToRunUnconditionally(
+              passOptions, iff->ifTrue, iff->ifFalse)) {
+          return nullptr;
+        }
+        // Check if side effects allow this.
+        FeatureSet features = getModule()->features;
+        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);
+            }
+          }
+        }
+        return nullptr;
+      }
+
+      void visitLocalSet(LocalSet* curr) {
+        // Sets of an if can be optimized in various ways that remove part of
+        // the if branching, or all of it.
+        // The optimizations we can do here can recurse and call each
+        // other, so pass around a pointer to the output.
+        optimizeSetIf(getCurrentPointer());
+      }
+
+      void optimizeSetIf(Expression** currp) {
+        if (optimizeSetIfWithBrArm(currp)) {
+          return;
+        }
+        if (optimizeSetIfWithCopyArm(currp)) {
+          return;
+        }
+      }
+
+      // If one arm is a br, we prefer a br_if and the set later:
+      //  (local.set $x
+      //    (if (result i32)
+      //      (..condition..)
+      //      (br $somewhere)
+      //      (..result)
+      //    )
+      //  )
+      // =>
+      //  (br_if $somewhere
+      //    (..condition..)
+      //  )
+      //  (local.set $x
+      //    (..result)
+      //  )
+      // TODO: handle a condition in the br? need to watch for side effects
+      bool optimizeSetIfWithBrArm(Expression** currp) {
+        auto* set = (*currp)->cast<LocalSet>();
+        auto* iff = set->value->dynCast<If>();
+        if (!iff || !iff->type.isConcrete() ||
+            !iff->condition->type.isConcrete()) {
+          return false;
+        }
+        auto tryToOptimize =
+          [&](Expression* one, Expression* two, bool flipCondition) {
+            if (one->type == Type::unreachable &&
+                two->type != Type::unreachable) {
+              if (auto* br = one->dynCast<Break>()) {
+                if (ExpressionAnalyzer::isSimple(br)) {
+                  // Wonderful, do it!
+                  Builder builder(*getModule());
+                  if (flipCondition) {
+                    builder.flip(iff);
+                  }
+                  br->condition = iff->condition;
+                  br->finalize();
+                  set->value = two;
+                  auto* block = builder.makeSequence(br, set);
+                  *currp = block;
+                  // Recurse on the set, which now has a new value.
+                  optimizeSetIf(&block->list[1]);
+                  return true;
+                }
+              }
+            }
+            return false;
+          };
+        return tryToOptimize(iff->ifTrue, iff->ifFalse, false) ||
+               tryToOptimize(iff->ifFalse, iff->ifTrue, true);
+      }
+
+      // If one arm is a get of the same outer set, it is a copy which
+      // we can remove. If this is not a tee, then we remove the get
+      // as well as the if-else opcode in the binary format, which is
+      // great:
+      //  (local.set $x
+      //    (if (result i32)
+      //      (..condition..)
+      //      (..result)
+      //      (local.get $x)
+      //    )
+      //  )
+      // =>
+      //  (if
+      //    (..condition..)
+      //    (local.set $x
+      //      (..result)
+      //    )
+      //  )
+      // If this is a tee, then we can do the same operation but
+      // inside a block, and keep the get:
+      //  (local.tee $x
+      //    (if (result i32)
+      //      (..condition..)
+      //      (..result)
+      //      (local.get $x)
+      //    )
+      //  )
+      // =>
+      //  (block (result i32)
+      //    (if
+      //      (..condition..)
+      //      (local.set $x
+      //        (..result)
+      //      )
+      //    )
+      //    (local.get $x)
+      //  )
+      // We save the if-else opcode, and add the block's opcodes.
+      // This may be detrimental, however, often the block can be
+      // merged or eliminated given the outside scope, and we
+      // removed one of the if branches.
+      bool optimizeSetIfWithCopyArm(Expression** currp) {
+        auto* set = (*currp)->cast<LocalSet>();
+        auto* iff = set->value->dynCast<If>();
+        if (!iff || !iff->type.isConcrete() ||
+            !iff->condition->type.isConcrete()) {
+          return false;
+        }
+        Builder builder(*getModule());
+        LocalGet* get = iff->ifTrue->dynCast<LocalGet>();
+        if (get && get->index == set->index) {
+          builder.flip(iff);
+        } else {
+          get = iff->ifFalse->dynCast<LocalGet>();
+          if (get && get->index != set->index) {
+            get = nullptr;
+          }
+        }
+        if (!get) {
+          return false;
+        }
+        // We can do it!
+        bool tee = set->isTee();
+        assert(set->index == get->index);
+        assert(iff->ifFalse == get);
+        set->value = iff->ifTrue;
+        set->finalize();
+        iff->ifTrue = set;
+        iff->ifFalse = nullptr;
+        iff->finalize();
+        Expression* replacement = iff;
+        if (tee) {
+          set->makeSet();
+          // We need a block too.
+          replacement = builder.makeSequence(iff,
+                                             get // reuse the get
+          );
+        }
+        *currp = replacement;
+        // Recurse on the set, which now has a new value.
+        optimizeSetIf(&iff->ifTrue);
+        return true;
+      }
+
+      // (br_if)+ => br_table
+      // we look for the specific pattern of
+      //  (br_if ..target1..
+      //    (i32.eq
+      //      (..input..)
+      //      (i32.const ..value1..)
+      //    )
+      //  )
+      //  (br_if ..target2..
+      //    (i32.eq
+      //      (..input..)
+      //      (i32.const ..value2..)
+      //    )
+      //  )
+      // TODO: consider also looking at <= etc. and not just eq
+      void tablify(Block* block) {
+        auto& list = block->list;
+        if (list.size() <= 1) {
+          return;
+        }
+
+        // Heuristics. These are slightly inspired by the constants from the
+        // asm.js backend.
+
+        // How many br_ifs we need to see to consider doing this
+        const uint32_t MIN_NUM = 3;
+        // How much of a range of values is definitely too big
+        const uint32_t MAX_RANGE = 1024;
+        // Multiplied by the number of br_ifs, then compared to the range. When
+        // this is high, we allow larger ranges.
+        const uint32_t NUM_TO_RANGE_FACTOR = 3;
+
+        // check if the input is a proper br_if on an i32.eq of a condition
+        // value to a const, and the const is in the proper range,
+        // [0-int32_max), to avoid overflow concerns. returns the br_if if so,
+        // or nullptr otherwise
+        auto getProperBrIf = [](Expression* curr) -> Break* {
+          auto* br = curr->dynCast<Break>();
+          if (!br) {
+            return nullptr;
+          }
+          if (!br->condition || br->value) {
+            return nullptr;
+          }
+          if (br->type != Type::none) {
+            // no value, so can be unreachable or none. ignore unreachable ones,
+            // dce will clean it up
+            return nullptr;
+          }
+          auto* binary = br->condition->dynCast<Binary>();
+          if (!binary) {
+            return nullptr;
+          }
+          if (binary->op != EqInt32) {
+            return nullptr;
+          }
+          auto* c = binary->right->dynCast<Const>();
+          if (!c) {
+            return nullptr;
+          }
+          uint32_t value = c->value.geti32();
+          if (value >= uint32_t(std::numeric_limits<int32_t>::max())) {
+            return nullptr;
+          }
+          return br;
+        };
+
+        // check if the input is a proper br_if
+        // and returns the condition if so, or nullptr otherwise
+        auto getProperBrIfConditionValue =
+          [&getProperBrIf](Expression* curr) -> Expression* {
+          auto* br = getProperBrIf(curr);
+          if (!br) {
+            return nullptr;
+          }
+          return br->condition->cast<Binary>()->left;
+        };
+
+        // returns the constant value, as a uint32_t
+        auto getProperBrIfConstant =
+          [&getProperBrIf](Expression* curr) -> uint32_t {
+          return getProperBrIf(curr)
+            ->condition->cast<Binary>()
+            ->right->cast<Const>()
+            ->value.geti32();
+        };
+        Index start = 0;
+        while (start < list.size() - 1) {
+          auto* conditionValue = getProperBrIfConditionValue(list[start]);
+          if (!conditionValue) {
+            start++;
+            continue;
+          }
+          // if the condition has side effects, we can't replace many
+          // appearances of it with a single one
+          if (EffectAnalyzer(passOptions, getModule()->features, conditionValue)
+                .hasSideEffects()) {
+            start++;
+            continue;
+          }
+          // look for a "run" of br_ifs with all the same conditionValue, and
+          // having unique constants (an overlapping constant could be handled,
+          // just the first branch is taken, but we can't remove the other br_if
+          // (it may be the only branch keeping a block reachable), which may
+          // make this bad for code size.
+          Index end = start + 1;
+          std::unordered_set<uint32_t> usedConstants;
+          usedConstants.insert(getProperBrIfConstant(list[start]));
+          while (end < list.size() &&
+                 ExpressionAnalyzer::equal(
+                   getProperBrIfConditionValue(list[end]), conditionValue)) {
+            if (!usedConstants.insert(getProperBrIfConstant(list[end]))
+                   .second) {
+              // this constant already appeared
+              break;
+            }
+            end++;
+          }
+          auto num = end - start;
+          if (num >= 2 && num >= MIN_NUM) {
+            // we found a suitable range, [start, end), containing more than 1
+            // element. let's see if it's worth it
+            auto min = getProperBrIfConstant(list[start]);
+            auto max = min;
+            for (Index i = start + 1; i < end; i++) {
+              auto* curr = list[i];
+              min = std::min(min, getProperBrIfConstant(curr));
+              max = std::max(max, getProperBrIfConstant(curr));
+            }
+            uint32_t range = max - min;
+            // decision time
+            if (range <= MAX_RANGE && range <= num * NUM_TO_RANGE_FACTOR) {
+              // great! let's do this
+              std::unordered_set<Name> usedNames;
+              for (Index i = start; i < end; i++) {
+                usedNames.insert(getProperBrIf(list[i])->name);
+              }
+              // we need a name for the default too
+              Name defaultName;
+              Index i = 0;
+              while (1) {
+                defaultName = "tablify|" + std::to_string(i++);
+                if (usedNames.count(defaultName) == 0) {
+                  break;
+                }
+              }
+              std::vector<Name> table;
+              for (Index i = start; i < end; i++) {
+                auto name = getProperBrIf(list[i])->name;
+                auto index = getProperBrIfConstant(list[i]);
+                index -= min;
+                while (table.size() <= index) {
+                  table.push_back(defaultName);
+                }
+                // we should have made sure there are no overlaps
+                assert(table[index] == defaultName);
+                table[index] = name;
+              }
+              Builder builder(*getModule());
+              // the table and condition are offset by the min
+              if (min != 0) {
+                conditionValue = builder.makeBinary(
+                  SubInt32, conditionValue, builder.makeConst(int32_t(min)));
+              }
+              list[end - 1] = builder.makeBlock(
+                defaultName,
+                builder.makeSwitch(table, defaultName, conditionValue));
+              for (Index i = start; i < end - 1; i++) {
+                ExpressionManipulator::nop(list[i]);
+              }
+              // the defaultName may exist elsewhere in this function,
+              // uniquify it later
+              needUniqify = true;
+            }
+          }
+          start = end;
+        }
+      }
+    };
+    FinalOptimizer finalOptimizer(getPassOptions());
+    finalOptimizer.setModule(getModule());
+    finalOptimizer.shrink = getPassRunner()->options.shrinkLevel > 0;
+    finalOptimizer.walkFunction(func);
+    if (finalOptimizer.needUniqify) {
+      wasm::UniqueNameMapper::uniquify(func->body);
+    }
+  }
+};
+
+Pass* createRemoveUnusedBrsPass() { return new RemoveUnusedBrs(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/RemoveUnusedModuleElements.cpp b/binaryen/src/passes/RemoveUnusedModuleElements.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/RemoveUnusedModuleElements.cpp
@@ -0,0 +1,243 @@
+/*
+ * 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.
+ */
+
+//
+// Removes module elements that are are never used: functions, globals, and
+// events, which may be imported or not, and function types (which we merge and
+// remove if unneeded)
+//
+
+#include <memory>
+
+#include "asm_v_wasm.h"
+#include "ir/module-utils.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "wasm.h"
+
+namespace wasm {
+
+enum class ModuleElementKind { Function, Global, Event };
+
+typedef std::pair<ModuleElementKind, Name> ModuleElement;
+
+// Finds reachabilities
+// TODO: use Effects to determine if a memory is used
+
+struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
+  Module* module;
+  std::vector<ModuleElement> queue;
+  std::set<ModuleElement> reachable;
+  bool usesMemory = false;
+  bool usesTable = false;
+
+  ReachabilityAnalyzer(Module* module, const std::vector<ModuleElement>& roots)
+    : module(module) {
+    queue = roots;
+    // Globals used in memory/table init expressions are also roots
+    for (auto& segment : module->memory.segments) {
+      if (!segment.isPassive) {
+        walk(segment.offset);
+      }
+    }
+    for (auto& segment : module->table.segments) {
+      walk(segment.offset);
+    }
+    // main loop
+    while (queue.size()) {
+      auto& curr = queue.back();
+      queue.pop_back();
+      if (reachable.count(curr) == 0) {
+        reachable.insert(curr);
+        if (curr.first == ModuleElementKind::Function) {
+          // if not an import, walk it
+          auto* func = module->getFunction(curr.second);
+          if (!func->imported()) {
+            walk(func->body);
+          }
+        } else if (curr.first == ModuleElementKind::Global) {
+          // if not imported, it has an init expression we need to walk
+          auto* global = module->getGlobal(curr.second);
+          if (!global->imported()) {
+            walk(global->init);
+          }
+        }
+      }
+    }
+  }
+
+  void visitCall(Call* curr) {
+    if (reachable.count(
+          ModuleElement(ModuleElementKind::Function, curr->target)) == 0) {
+      queue.emplace_back(ModuleElementKind::Function, curr->target);
+    }
+  }
+  void visitCallIndirect(CallIndirect* curr) { usesTable = true; }
+
+  void visitGlobalGet(GlobalGet* curr) {
+    if (reachable.count(ModuleElement(ModuleElementKind::Global, curr->name)) ==
+        0) {
+      queue.emplace_back(ModuleElementKind::Global, curr->name);
+    }
+  }
+  void visitGlobalSet(GlobalSet* curr) {
+    if (reachable.count(ModuleElement(ModuleElementKind::Global, curr->name)) ==
+        0) {
+      queue.emplace_back(ModuleElementKind::Global, curr->name);
+    }
+  }
+
+  void visitLoad(Load* curr) { usesMemory = true; }
+  void visitStore(Store* curr) { usesMemory = true; }
+  void visitAtomicCmpxchg(AtomicCmpxchg* curr) { usesMemory = true; }
+  void visitAtomicRMW(AtomicRMW* curr) { usesMemory = true; }
+  void visitAtomicWait(AtomicWait* curr) { usesMemory = true; }
+  void visitAtomicNotify(AtomicNotify* curr) { usesMemory = true; }
+  void visitAtomicFence(AtomicFence* curr) { usesMemory = true; }
+  void visitMemoryInit(MemoryInit* curr) { usesMemory = true; }
+  void visitDataDrop(DataDrop* curr) { usesMemory = true; }
+  void visitMemoryCopy(MemoryCopy* curr) { usesMemory = true; }
+  void visitMemoryFill(MemoryFill* curr) { usesMemory = true; }
+  void visitMemorySize(MemorySize* curr) { usesMemory = true; }
+  void visitMemoryGrow(MemoryGrow* curr) { usesMemory = true; }
+  void visitRefFunc(RefFunc* curr) {
+    if (reachable.count(
+          ModuleElement(ModuleElementKind::Function, curr->func)) == 0) {
+      queue.emplace_back(ModuleElementKind::Function, curr->func);
+    }
+  }
+  void visitThrow(Throw* curr) {
+    if (reachable.count(ModuleElement(ModuleElementKind::Event, curr->event)) ==
+        0) {
+      queue.emplace_back(ModuleElementKind::Event, curr->event);
+    }
+  }
+  void visitBrOnExn(BrOnExn* curr) {
+    if (reachable.count(ModuleElement(ModuleElementKind::Event, curr->event)) ==
+        0) {
+      queue.emplace_back(ModuleElementKind::Event, curr->event);
+    }
+  }
+};
+
+struct RemoveUnusedModuleElements : public Pass {
+  bool rootAllFunctions;
+
+  RemoveUnusedModuleElements(bool rootAllFunctions)
+    : rootAllFunctions(rootAllFunctions) {}
+
+  void run(PassRunner* runner, Module* module) override {
+    std::vector<ModuleElement> roots;
+    // Module start is a root.
+    if (module->start.is()) {
+      auto startFunction = module->getFunction(module->start);
+      // Can be skipped if the start function is empty.
+      if (startFunction->body->is<Nop>()) {
+        module->start.clear();
+      } else {
+        roots.emplace_back(ModuleElementKind::Function, module->start);
+      }
+    }
+    // If told to, root all the functions
+    if (rootAllFunctions) {
+      ModuleUtils::iterDefinedFunctions(*module, [&](Function* func) {
+        roots.emplace_back(ModuleElementKind::Function, func->name);
+      });
+    }
+    // Exports are roots.
+    bool exportsMemory = false;
+    bool exportsTable = false;
+    for (auto& curr : module->exports) {
+      if (curr->kind == ExternalKind::Function) {
+        roots.emplace_back(ModuleElementKind::Function, curr->value);
+      } else if (curr->kind == ExternalKind::Global) {
+        roots.emplace_back(ModuleElementKind::Global, curr->value);
+      } else if (curr->kind == ExternalKind::Event) {
+        roots.emplace_back(ModuleElementKind::Event, curr->value);
+      } else if (curr->kind == ExternalKind::Memory) {
+        exportsMemory = true;
+      } else if (curr->kind == ExternalKind::Table) {
+        exportsTable = true;
+      }
+    }
+    // Check for special imports, which are roots.
+    bool importsMemory = false;
+    bool importsTable = false;
+    if (module->memory.imported()) {
+      importsMemory = true;
+    }
+    if (module->table.imported()) {
+      importsTable = true;
+    }
+    // For now, all functions that can be called indirectly are marked as roots.
+    for (auto& segment : module->table.segments) {
+      for (auto& curr : segment.data) {
+        roots.emplace_back(ModuleElementKind::Function, curr);
+      }
+    }
+    // Compute reachability starting from the root set.
+    ReachabilityAnalyzer analyzer(module, roots);
+    // Remove unreachable elements.
+    module->removeFunctions([&](Function* curr) {
+      return analyzer.reachable.count(
+               ModuleElement(ModuleElementKind::Function, curr->name)) == 0;
+    });
+    module->removeGlobals([&](Global* curr) {
+      return analyzer.reachable.count(
+               ModuleElement(ModuleElementKind::Global, curr->name)) == 0;
+    });
+    module->removeEvents([&](Event* curr) {
+      return analyzer.reachable.count(
+               ModuleElement(ModuleElementKind::Event, curr->name)) == 0;
+    });
+    // Handle the memory and table
+    if (!exportsMemory && !analyzer.usesMemory) {
+      if (!importsMemory) {
+        // The memory is unobservable to the outside, we can remove the
+        // contents.
+        module->memory.segments.clear();
+      }
+      if (module->memory.segments.empty()) {
+        module->memory.exists = false;
+        module->memory.module = module->memory.base = Name();
+        module->memory.initial = 0;
+        module->memory.max = 0;
+      }
+    }
+    if (!exportsTable && !analyzer.usesTable) {
+      if (!importsTable) {
+        // The table is unobservable to the outside, we can remove the contents.
+        module->table.segments.clear();
+      }
+      if (module->table.segments.empty()) {
+        module->table.exists = false;
+        module->table.module = module->table.base = Name();
+        module->table.initial = 0;
+        module->table.max = 0;
+      }
+    }
+  }
+};
+
+Pass* createRemoveUnusedModuleElementsPass() {
+  return new RemoveUnusedModuleElements(false);
+}
+
+Pass* createRemoveUnusedNonFunctionModuleElementsPass() {
+  return new RemoveUnusedModuleElements(true);
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/RemoveUnusedNames.cpp b/binaryen/src/passes/RemoveUnusedNames.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/RemoveUnusedNames.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// Removes names from locations that are never branched to, and
+// merge names when possible (by merging their blocks)
+//
+
+#include <pass.h>
+#include <wasm.h>
+
+namespace wasm {
+
+struct RemoveUnusedNames : public WalkerPass<PostWalker<RemoveUnusedNames>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new RemoveUnusedNames; }
+
+  // We maintain a list of branches that we saw in children, then when we reach
+  // 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);
+    }
+    branchesSeen[curr->default_].insert(curr);
+  }
+
+  void visitBrOnExn(BrOnExn* curr) { branchesSeen[curr->name].insert(curr); }
+
+  void handleBreakTarget(Name& name) {
+    if (name.is()) {
+      if (branchesSeen.find(name) == branchesSeen.end()) {
+        name = Name();
+      } else {
+        branchesSeen.erase(name);
+      }
+    }
+  }
+
+  void visitBlock(Block* curr) {
+    if (curr->name.is() && curr->list.size() == 1) {
+      auto* child = curr->list[0]->dynCast<Block>();
+      if (child && child->name.is() && child->type == curr->type) {
+        // we have just one child, this block, so breaking out of it goes to the
+        // 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");
+          }
+        }
+        child->finalize(child->type);
+        replaceCurrent(child);
+      }
+    }
+    handleBreakTarget(curr->name);
+  }
+
+  void visitLoop(Loop* curr) {
+    handleBreakTarget(curr->name);
+    if (!curr->name.is() && curr->body->type == curr->type) {
+      replaceCurrent(curr->body);
+    }
+  }
+
+  void visitFunction(Function* curr) { assert(branchesSeen.empty()); }
+};
+
+Pass* createRemoveUnusedNamesPass() { return new RemoveUnusedNames(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/ReorderFunctions.cpp b/binaryen/src/passes/ReorderFunctions.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/ReorderFunctions.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+//
+// Sorts functions by their static use count. This helps reduce the size of wasm
+// binaries because fewer bytes are needed to encode references to frequently
+// used functions.
+//
+// This may incur a tradeoff, though, as while it reduces binary size, it may
+// increase gzip size. This might be because the new order has the functions in
+// a less beneficial position for compression, that is, mutually-compressible
+// functions are no longer together (when they were before, in the original
+// order, the has some natural tendency one way or the other). TODO: investigate
+// similarity ordering here.
+//
+
+#include <memory>
+
+#include <pass.h>
+#include <wasm.h>
+
+namespace wasm {
+
+typedef std::unordered_map<Name, std::atomic<Index>> NameCountMap;
+
+struct CallCountScanner : public WalkerPass<PostWalker<CallCountScanner>> {
+  bool isFunctionParallel() override { return true; }
+
+  CallCountScanner(NameCountMap* counts) : counts(counts) {}
+
+  CallCountScanner* create() override { return new CallCountScanner(counts); }
+
+  void visitCall(Call* curr) {
+    // can't add a new element in parallel
+    assert(counts->count(curr->target) > 0);
+    (*counts)[curr->target]++;
+  }
+
+private:
+  NameCountMap* counts;
+};
+
+struct ReorderFunctions : public Pass {
+  void run(PassRunner* runner, Module* module) override {
+    NameCountMap counts;
+    // fill in info, as we operate on it in parallel (each function to its own
+    // entry)
+    for (auto& func : module->functions) {
+      counts[func->name];
+    }
+    // find counts on function calls
+    CallCountScanner(&counts).run(runner, module);
+    // find counts on global usages
+    if (module->start.is()) {
+      counts[module->start]++;
+    }
+    for (auto& curr : module->exports) {
+      counts[curr->value]++;
+    }
+    for (auto& segment : module->table.segments) {
+      for (auto& curr : segment.data) {
+        counts[curr]++;
+      }
+    }
+    // sort
+    std::sort(module->functions.begin(),
+              module->functions.end(),
+              [&counts](const std::unique_ptr<Function>& a,
+                        const std::unique_ptr<Function>& b) -> bool {
+                if (counts[a->name] == counts[b->name]) {
+                  return strcmp(a->name.str, b->name.str) > 0;
+                }
+                return counts[a->name] > counts[b->name];
+              });
+  }
+};
+
+Pass* createReorderFunctionsPass() { return new ReorderFunctions(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/ReorderLocals.cpp b/binaryen/src/passes/ReorderLocals.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/ReorderLocals.cpp
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+//
+// Sorts locals by access frequency.
+//
+// Secondarily, sort by first appearance. This canonicalizes the order.
+//
+// While sorting, we remove locals that have no uses at all.
+//
+
+#include <memory>
+
+#include <pass.h>
+#include <wasm.h>
+
+namespace wasm {
+
+struct ReorderLocals : public WalkerPass<PostWalker<ReorderLocals>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new ReorderLocals; }
+
+  // local index => times it is used
+  std::vector<Index> counts;
+  // local index => how many locals we saw before this one, before a use of
+  // this one appeared. that is, one local has 1, another has 2, and so forth,
+  // in the order in which we saw the first uses of them (we use "0" to mark
+  // locals we have not yet seen).
+  std::vector<Index> firstUses;
+  Index firstUseIndex = 1;
+
+  enum { Unseen = 0 };
+
+  void doWalkFunction(Function* curr) {
+    if (curr->getNumVars() == 0) {
+      return; // nothing to do. All locals are parameters
+    }
+    Index num = curr->getNumLocals();
+    counts.resize(num);
+    std::fill(counts.begin(), counts.end(), 0);
+    firstUses.resize(num);
+    std::fill(firstUses.begin(), firstUses.end(), Unseen);
+    // Gather information about local usages.
+    walk(curr->body);
+    // Use the information about local usages.
+    std::vector<Index> newToOld(num);
+    for (size_t i = 0; i < num; i++) {
+      newToOld[i] = i;
+    }
+    // sort, keeping params in front (where they will not be moved)
+    sort(
+      newToOld.begin(), newToOld.end(), [this, curr](Index a, Index b) -> bool {
+        if (curr->isParam(a) && !curr->isParam(b)) {
+          return true;
+        }
+        if (curr->isParam(b) && !curr->isParam(a)) {
+          return false;
+        }
+        if (curr->isParam(b) && curr->isParam(a)) {
+          return a < b;
+        }
+        if (counts[a] == counts[b]) {
+          if (counts[a] == 0) {
+            return a < b;
+          }
+          return firstUses[a] < firstUses[b];
+        }
+        return counts[a] > counts[b];
+      });
+    // sorting left params in front, perhaps slightly reordered. verify and fix.
+    size_t numParams = curr->sig.params.size();
+    for (size_t i = 0; i < numParams; i++) {
+      assert(newToOld[i] < numParams);
+      newToOld[i] = i;
+    }
+    // sort vars, and drop unused ones
+    std::vector<Type> oldVars;
+    std::swap(oldVars, curr->vars);
+    for (size_t i = curr->getVarIndexBase(); i < newToOld.size(); i++) {
+      Index index = newToOld[i];
+      if (counts[index] > 0) {
+        curr->vars.push_back(oldVars[index - curr->getVarIndexBase()]);
+      } else {
+        newToOld.resize(i);
+        break;
+      }
+    }
+    counts.clear();
+    std::vector<Index> oldToNew;
+    oldToNew.resize(num);
+    for (size_t i = 0; i < newToOld.size(); i++) {
+      if (curr->isParam(i)) {
+        oldToNew[i] = i;
+      } else {
+        oldToNew[newToOld[i]] = i;
+      }
+    }
+    // apply the renaming to AST nodes
+    struct ReIndexer : public PostWalker<ReIndexer> {
+      Function* func;
+      std::vector<Index>& oldToNew;
+
+      ReIndexer(Function* func, std::vector<Index>& oldToNew)
+        : func(func), oldToNew(oldToNew) {}
+
+      void visitLocalGet(LocalGet* curr) {
+        curr->index = oldToNew[curr->index];
+      }
+
+      void visitLocalSet(LocalSet* curr) {
+        curr->index = oldToNew[curr->index];
+      }
+    };
+    ReIndexer reIndexer(curr, oldToNew);
+    reIndexer.walk(curr->body);
+    // apply to the names
+    auto oldLocalNames = curr->localNames;
+    auto oldLocalIndices = curr->localIndices;
+    curr->localNames.clear();
+    curr->localIndices.clear();
+    for (size_t i = 0; i < newToOld.size(); i++) {
+      auto iter = oldLocalNames.find(newToOld[i]);
+      if (iter != oldLocalNames.end()) {
+        auto old = iter->second;
+        curr->localNames[i] = old;
+        curr->localIndices[old] = i;
+      }
+    }
+  }
+
+  void visitLocalGet(LocalGet* curr) {
+    counts[curr->index]++;
+    if (firstUses[curr->index] == Unseen) {
+      firstUses[curr->index] = firstUseIndex++;
+    }
+  }
+
+  void visitLocalSet(LocalSet* curr) {
+    counts[curr->index]++;
+    if (firstUses[curr->index] == Unseen) {
+      firstUses[curr->index] = firstUseIndex++;
+    }
+  }
+};
+
+Pass* createReorderLocalsPass() { return new ReorderLocals(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/ReplaceStackPointer.cpp b/binaryen/src/passes/ReplaceStackPointer.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/ReplaceStackPointer.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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/RoundTrip.cpp b/binaryen/src/passes/RoundTrip.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/RoundTrip.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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.
+ */
+
+//
+// Write the module to binary, and load it from there. This is useful in
+// testing to check for the effects of roundtripping in a single wasm-opt
+// parameter.
+//
+
+#include "ir/module-utils.h"
+#include "pass.h"
+#include "wasm-binary.h"
+#include "wasm.h"
+
+using namespace std;
+
+namespace wasm {
+
+struct RoundTrip : public Pass {
+  void run(PassRunner* runner, Module* module) override {
+    BufferWithRandomAccess buffer;
+    // Save features, which would not otherwise make it through a round trip if
+    // the target features section has been stripped.
+    auto features = module->features;
+    // Write, clear, and read the module
+    WasmBinaryWriter(module, buffer).write();
+    ModuleUtils::clearModule(*module);
+    auto input = buffer.getAsChars();
+    WasmBinaryBuilder parser(*module, input);
+    parser.setDWARF(runner->options.debugInfo);
+    parser.read();
+    // Reapply features
+    module->features = features;
+  }
+};
+
+Pass* createRoundTripPass() { return new RoundTrip(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/SSAify.cpp b/binaryen/src/passes/SSAify.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/SSAify.cpp
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+//
+// Transforms code into SSA form. That ensures each variable has a
+// single assignment.
+//
+// Note that "SSA form" usually means SSA + phis. This pass does not
+// create phis, we still emit something in our AST, which does not
+// have a phi instruction. What we emit when control flow joins
+// require more than one input to a value is multiple assignments
+// to the same local, with the SSA guarantee that one and only one
+// of those assignments will arrive at the uses of that "merge local".
+// TODO: consider adding a "proper" phi node to the AST, that passes
+//       can utilize
+//
+// There is also a "no-merge" variant of this pass. That will ignore
+// sets leading to merges, that is, it only creates new SSA indexes
+// for sets whose gets have just that set, e.g.
+//
+//  x = ..
+//  f(x, x)
+//  x = ..
+//  g(x, x)
+// =>
+//  x = ..
+//  f(x, x)
+//  x' = ..
+//  g(x', x')
+//
+// This "untangles" local indexes in a way that helps other passes,
+// while not creating copies with overlapping lifetimes that can
+// lead to a code size increase. In particular, the new variables
+// added by ssa-nomerge can be easily removed by the coalesce-locals
+// pass.
+//
+
+#include <iterator>
+
+#include "ir/find_all.h"
+#include "ir/literal-utils.h"
+#include "ir/local-graph.h"
+#include "pass.h"
+#include "support/permutations.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+// A set we know is impossible / not in the ast
+static LocalSet IMPOSSIBLE_SET;
+
+// Tracks assignments to locals, assuming single-assignment form, i.e.,
+// each assignment creates a new variable.
+
+struct SSAify : public Pass {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new SSAify(allowMerges); }
+
+  SSAify(bool allowMerges) : allowMerges(allowMerges) {}
+
+  bool allowMerges;
+
+  Module* module;
+  Function* func;
+  // things we add to the function prologue
+  std::vector<Expression*> functionPrepends;
+
+  void
+  runOnFunction(PassRunner* runner, Module* module_, Function* func_) override {
+    module = module_;
+    func = func_;
+    LocalGraph graph(func);
+    graph.computeInfluences();
+    graph.computeSSAIndexes();
+    // create new local indexes, one for each set
+    createNewIndexes(graph);
+    // we now know the sets for each get, and can compute get indexes and handle
+    // phis
+    computeGetsAndPhis(graph);
+    // add prepends to function
+    addPrepends();
+  }
+
+  void createNewIndexes(LocalGraph& graph) {
+    FindAll<LocalSet> sets(func->body);
+    for (auto* set : sets.list) {
+      // Indexes already in SSA form do not need to be modified - there is
+      // already just one set for that index. Otherwise, use a new index, unless
+      // merges are disallowed.
+      if (!graph.isSSA(set->index) && (allowMerges || !hasMerges(set, graph))) {
+        set->index = addLocal(func->getLocalType(set->index));
+      }
+    }
+  }
+
+  bool hasMerges(LocalSet* set, LocalGraph& graph) {
+    for (auto* get : graph.setInfluences[set]) {
+      if (graph.getSetses[get].size() > 1) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  void computeGetsAndPhis(LocalGraph& graph) {
+    FindAll<LocalGet> gets(func->body);
+    for (auto* get : gets.list) {
+      auto& sets = graph.getSetses[get];
+      if (sets.size() == 0) {
+        continue; // unreachable, ignore
+      }
+      if (sets.size() == 1) {
+        // easy, just one set, use its index
+        auto* set = *sets.begin();
+        if (set) {
+          get->index = set->index;
+        } else {
+          // no set, assign param or zero
+          if (func->isParam(get->index)) {
+            // leave it, it's fine
+          } else {
+            // zero it out
+            (*graph.locations[get]) =
+              LiteralUtils::makeZero(get->type, *module);
+          }
+        }
+        continue;
+      }
+      if (!allowMerges) {
+        continue;
+      }
+      // more than 1 set, need a phi: a new local written to at each of the sets
+      auto new_ = addLocal(get->type);
+      auto old = get->index;
+      get->index = new_;
+      Builder builder(*module);
+      // write to the local in each of our sets
+      for (auto* set : sets) {
+        if (set) {
+          // a set exists, just add a tee of its value
+          auto* value = set->value;
+          auto* tee = builder.makeLocalTee(new_, value, get->type);
+          set->value = tee;
+          // the value may have been something we tracked the location
+          // of. if so, update that, since we moved it into the tee
+          if (graph.locations.count(value) > 0) {
+            assert(graph.locations[value] == &set->value);
+            graph.locations[value] = &tee->value;
+          }
+        } else {
+          // this is a param or the zero init value.
+          if (func->isParam(old)) {
+            // we add a set with the proper
+            // param value at the beginning of the function
+            auto* set = builder.makeLocalSet(
+              new_, builder.makeLocalGet(old, func->getLocalType(old)));
+            functionPrepends.push_back(set);
+          } else {
+            // this is a zero init, so we don't need to do anything actually
+          }
+        }
+      }
+    }
+  }
+
+  Index addLocal(Type type) { return Builder::addVar(func, type); }
+
+  void addPrepends() {
+    if (functionPrepends.size() > 0) {
+      Builder builder(*module);
+      auto* block = builder.makeBlock();
+      for (auto* pre : functionPrepends) {
+        block->list.push_back(pre);
+      }
+      block->list.push_back(func->body);
+      block->finalize(func->body->type);
+      func->body = block;
+    }
+  }
+};
+
+Pass* createSSAifyPass() { return new SSAify(true); }
+
+Pass* createSSAifyNoMergePass() { return new SSAify(false); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/SafeHeap.cpp b/binaryen/src/passes/SafeHeap.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/SafeHeap.cpp
@@ -0,0 +1,372 @@
+/*
+ * 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.
+ */
+
+//
+// Instruments code to check for incorrect heap access. This checks
+// for dereferencing 0 (null pointer access), reading past the valid
+// 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"
+#include "ir/load-utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+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");
+static const Name ALIGNFAULT_IMPORT("alignfault");
+
+static Name getLoadName(Load* curr) {
+  std::string ret = "SAFE_HEAP_LOAD_";
+  ret += curr->type.toString();
+  ret += "_" + std::to_string(curr->bytes) + "_";
+  if (LoadUtils::isSignRelevant(curr) && !curr->signed_) {
+    ret += "U_";
+  }
+  if (curr->isAtomic) {
+    ret += "A";
+  } else {
+    ret += std::to_string(curr->align);
+  }
+  return ret;
+}
+
+static Name getStoreName(Store* curr) {
+  std::string ret = "SAFE_HEAP_STORE_";
+  ret += curr->valueType.toString();
+  ret += "_" + std::to_string(curr->bytes) + "_";
+  if (curr->isAtomic) {
+    ret += "A";
+  } else {
+    ret += std::to_string(curr->align);
+  }
+  return ret;
+}
+
+struct AccessInstrumenter : public WalkerPass<PostWalker<AccessInstrumenter>> {
+  // 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.
+  Name getSbrkPtr;
+
+  bool isFunctionParallel() override { return true; }
+
+  AccessInstrumenter* create() override {
+    return new AccessInstrumenter(getSbrkPtr);
+  }
+
+  AccessInstrumenter(Name getSbrkPtr) : getSbrkPtr(getSbrkPtr) {}
+
+  void visitLoad(Load* curr) {
+    if (getFunction()->name == getSbrkPtr || curr->type == Type::unreachable) {
+      return;
+    }
+    Builder builder(*getModule());
+    replaceCurrent(
+      builder.makeCall(getLoadName(curr),
+                       {curr->ptr, builder.makeConstPtr(curr->offset.addr)},
+                       curr->type));
+  }
+
+  void visitStore(Store* curr) {
+    if (getFunction()->name == getSbrkPtr || curr->type == Type::unreachable) {
+      return;
+    }
+    Builder builder(*getModule());
+    replaceCurrent(builder.makeCall(
+      getStoreName(curr),
+      {curr->ptr, builder.makeConstPtr(curr->offset.addr), curr->value},
+      Type::none));
+  }
+};
+
+struct SafeHeap : public Pass {
+  PassOptions options;
+
+  void run(PassRunner* runner, Module* module) override {
+    options = runner->options;
+    // add imports
+    addImports(module);
+    // instrument loads and stores
+    AccessInstrumenter(getSbrkPtr).run(runner, module);
+    // add helper checking funcs and imports
+    addGlobals(module, module->features);
+  }
+
+  Name dynamicTopPtr, getSbrkPtr, sbrk, segfault, alignfault;
+
+  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)) {
+      getSbrkPtr = existing->name;
+    } else if (auto* existing = module->getExportOrNull(GET_SBRK_PTR)) {
+      getSbrkPtr = existing->value;
+    } else if (auto* existing = info.getImportedFunction(ENV, SBRK)) {
+      sbrk = existing->name;
+    } else {
+      auto* import = new Function;
+      import->name = getSbrkPtr = GET_SBRK_PTR;
+      import->module = ENV;
+      import->base = GET_SBRK_PTR;
+      import->sig = Signature(Type::none, indexType);
+      module->addFunction(import);
+    }
+    if (auto* existing = info.getImportedFunction(ENV, SEGFAULT_IMPORT)) {
+      segfault = existing->name;
+    } else {
+      auto* import = new Function;
+      import->name = segfault = SEGFAULT_IMPORT;
+      import->module = ENV;
+      import->base = SEGFAULT_IMPORT;
+      import->sig = Signature(Type::none, Type::none);
+      module->addFunction(import);
+    }
+    if (auto* existing = info.getImportedFunction(ENV, ALIGNFAULT_IMPORT)) {
+      alignfault = existing->name;
+    } else {
+      auto* import = new Function;
+      import->name = alignfault = ALIGNFAULT_IMPORT;
+      import->module = ENV;
+      import->base = ALIGNFAULT_IMPORT;
+      import->sig = Signature(Type::none, Type::none);
+      module->addFunction(import);
+    }
+  }
+
+  bool
+  isPossibleAtomicOperation(Index align, Index bytes, bool shared, Type type) {
+    return align == bytes && shared && type.isInteger();
+  }
+
+  void addGlobals(Module* module, FeatureSet features) {
+    // load funcs
+    Load load;
+    for (Type type : {Type::i32, Type::i64, Type::f32, Type::f64, Type::v128}) {
+      if (type == Type::v128 && !features.hasSIMD()) {
+        continue;
+      }
+      load.type = type;
+      for (Index bytes : {1, 2, 4, 8, 16}) {
+        load.bytes = bytes;
+        if (bytes > type.getByteSize() || (type == Type::f32 && bytes != 4) ||
+            (type == Type::f64 && bytes != 8) ||
+            (type == Type::v128 && bytes != 16)) {
+          continue;
+        }
+        for (auto signed_ : {true, false}) {
+          load.signed_ = signed_;
+          if (type.isFloat() && signed_) {
+            continue;
+          }
+          for (Index align : {1, 2, 4, 8, 16}) {
+            load.align = align;
+            if (align > bytes) {
+              continue;
+            }
+            for (auto isAtomic : {true, false}) {
+              load.isAtomic = isAtomic;
+              if (isAtomic && !isPossibleAtomicOperation(
+                                align, bytes, module->memory.shared, type)) {
+                continue;
+              }
+              addLoadFunc(load, module);
+            }
+          }
+        }
+      }
+    }
+    // store funcs
+    Store store;
+    for (Type valueType :
+         {Type::i32, Type::i64, Type::f32, Type::f64, Type::v128}) {
+      if (valueType == Type::v128 && !features.hasSIMD()) {
+        continue;
+      }
+      store.valueType = valueType;
+      store.type = Type::none;
+      for (Index bytes : {1, 2, 4, 8, 16}) {
+        store.bytes = bytes;
+        if (bytes > valueType.getByteSize() ||
+            (valueType == Type::f32 && bytes != 4) ||
+            (valueType == Type::f64 && bytes != 8) ||
+            (valueType == Type::v128 && bytes != 16)) {
+          continue;
+        }
+        for (Index align : {1, 2, 4, 8, 16}) {
+          store.align = align;
+          if (align > bytes) {
+            continue;
+          }
+          for (auto isAtomic : {true, false}) {
+            store.isAtomic = isAtomic;
+            if (isAtomic && !isPossibleAtomicOperation(
+                              align, bytes, module->memory.shared, valueType)) {
+              continue;
+            }
+            addStoreFunc(store, module);
+          }
+        }
+      }
+    }
+  }
+
+  // creates a function for a particular style of load
+  void addLoadFunc(Load style, Module* module) {
+    auto name = getLoadName(&style);
+    if (module->getFunctionOrNull(name)) {
+      return;
+    }
+    auto* func = new Function;
+    func->name = name;
+    // pointer, offset
+    auto indexType = module->memory.indexType;
+    func->sig = Signature({indexType, indexType}, style.type);
+    func->vars.push_back(indexType); // pointer + offset
+    Builder builder(*module);
+    auto* block = builder.makeBlock();
+    block->list.push_back(builder.makeLocalSet(
+      2,
+      builder.makeBinary(module->memory.is64() ? AddInt64 : AddInt32,
+                         builder.makeLocalGet(0, indexType),
+                         builder.makeLocalGet(1, indexType))));
+    // check for reading past valid memory: if pointer + offset + bytes
+    block->list.push_back(
+      makeBoundsCheck(style.type, builder, 2, style.bytes, module));
+    // check proper alignment
+    if (style.align > 1) {
+      block->list.push_back(makeAlignCheck(style.align, builder, 2, module));
+    }
+    // do the load
+    auto* load = module->allocator.alloc<Load>();
+    *load = style; // basically the same as the template we are given!
+    load->ptr = builder.makeLocalGet(2, indexType);
+    Expression* last = load;
+    if (load->isAtomic && load->signed_) {
+      // atomic loads cannot be signed, manually sign it
+      last = Bits::makeSignExt(load, load->bytes, *module);
+      load->signed_ = false;
+    }
+    block->list.push_back(last);
+    block->finalize(style.type);
+    func->body = block;
+    module->addFunction(func);
+  }
+
+  // creates a function for a particular type of store
+  void addStoreFunc(Store style, Module* module) {
+    auto name = getStoreName(&style);
+    if (module->getFunctionOrNull(name)) {
+      return;
+    }
+    auto* func = new Function;
+    func->name = name;
+    // pointer, offset, value
+    auto indexType = module->memory.indexType;
+    func->sig = Signature({indexType, indexType, style.valueType}, Type::none);
+    func->vars.push_back(indexType); // pointer + offset
+    Builder builder(*module);
+    auto* block = builder.makeBlock();
+    block->list.push_back(builder.makeLocalSet(
+      3,
+      builder.makeBinary(module->memory.is64() ? AddInt64 : AddInt32,
+                         builder.makeLocalGet(0, indexType),
+                         builder.makeLocalGet(1, indexType))));
+    // check for reading past valid memory: if pointer + offset + bytes
+    block->list.push_back(
+      makeBoundsCheck(style.valueType, builder, 3, style.bytes, module));
+    // check proper alignment
+    if (style.align > 1) {
+      block->list.push_back(makeAlignCheck(style.align, builder, 3, module));
+    }
+    // do the store
+    auto* store = module->allocator.alloc<Store>();
+    *store = style; // basically the same as the template we are given!
+    store->ptr = builder.makeLocalGet(3, indexType);
+    store->value = builder.makeLocalGet(2, style.valueType);
+    block->list.push_back(store);
+    block->finalize(Type::none);
+    func->body = block;
+    module->addFunction(func);
+  }
+
+  Expression*
+  makeAlignCheck(Address align, Builder& builder, Index local, Module* module) {
+    auto indexType = module->memory.indexType;
+    Expression* ptrBits = builder.makeLocalGet(local, indexType);
+    if (module->memory.is64()) {
+      ptrBits = builder.makeUnary(WrapInt64, ptrBits);
+    }
+    return builder.makeIf(
+      builder.makeBinary(
+        AndInt32, ptrBits, builder.makeConst(int32_t(align - 1))),
+      builder.makeCall(alignfault, {}, Type::none));
+  }
+
+  Expression* makeBoundsCheck(
+    Type type, Builder& builder, Index local, Index bytes, Module* module) {
+    auto indexType = module->memory.indexType;
+    auto upperOp = module->memory.is64()
+                     ? options.lowMemoryUnused ? LtUInt64 : EqInt64
+                     : options.lowMemoryUnused ? LtUInt32 : EqInt32;
+    auto upperBound = options.lowMemoryUnused ? PassOptions::LowMemoryBound : 0;
+    Expression* brkLocation;
+    if (sbrk.is()) {
+      brkLocation =
+        builder.makeCall(sbrk, {builder.makeConstPtr(0)}, indexType);
+    } else {
+      Expression* sbrkPtr;
+      if (dynamicTopPtr.is()) {
+        sbrkPtr = builder.makeGlobalGet(dynamicTopPtr, indexType);
+      } else {
+        sbrkPtr = builder.makeCall(getSbrkPtr, {}, indexType);
+      }
+      auto size = module->memory.is64() ? 8 : 4;
+      brkLocation = builder.makeLoad(size, false, 0, size, sbrkPtr, indexType);
+    }
+    auto gtuOp = module->memory.is64() ? GtUInt64 : GtUInt32;
+    auto addOp = module->memory.is64() ? AddInt64 : AddInt32;
+    return builder.makeIf(
+      builder.makeBinary(
+        OrInt32,
+        builder.makeBinary(upperOp,
+                           builder.makeLocalGet(local, indexType),
+                           builder.makeConstPtr(upperBound)),
+        builder.makeBinary(
+          gtuOp,
+          builder.makeBinary(addOp,
+                             builder.makeLocalGet(local, indexType),
+                             builder.makeConstPtr(bytes)),
+          brkLocation)),
+      builder.makeCall(segfault, {}, Type::none));
+  }
+};
+
+Pass* createSafeHeapPass() { return new SafeHeap(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/SimplifyGlobals.cpp b/binaryen/src/passes/SimplifyGlobals.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/SimplifyGlobals.cpp
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2019 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.
+ */
+
+//
+// Simplify and optimize globals and their use.
+//
+//  * Turns never-written and unwritable (not imported or exported)
+//    globals immutable.
+//  * If an immutable global is a copy of another, use the earlier one,
+//    to allow removal of the copies later.
+//  * Apply the constant values of immutable globals.
+//  * Apply the constant values of previous global.sets, in a linear
+//    execution trace.
+//
+// Some globals may not have uses after these changes, which we leave
+// to other passes to optimize.
+//
+// This pass has a "optimize" variant (similar to inlining and DAE)
+// that also runs general function optimizations where we managed to replace
+// a constant value. That is helpful as such a replacement often opens up
+// further optimization opportunities.
+//
+
+#include <atomic>
+
+#include "ir/effects.h"
+#include "ir/properties.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace {
+
+struct GlobalInfo {
+  bool imported = false;
+  bool exported = false;
+  std::atomic<bool> written;
+  std::atomic<bool> read;
+};
+
+using GlobalInfoMap = std::map<Name, GlobalInfo>;
+
+struct GlobalUseScanner : public WalkerPass<PostWalker<GlobalUseScanner>> {
+  bool isFunctionParallel() override { return true; }
+
+  GlobalUseScanner(GlobalInfoMap* infos) : infos(infos) {}
+
+  GlobalUseScanner* create() override { return new GlobalUseScanner(infos); }
+
+  void visitGlobalSet(GlobalSet* curr) { (*infos)[curr->name].written = true; }
+
+  void visitGlobalGet(GlobalGet* curr) { (*infos)[curr->name].read = true; }
+
+private:
+  GlobalInfoMap* infos;
+};
+
+using NameNameMap = std::map<Name, Name>;
+using NameSet = std::set<Name>;
+
+struct GlobalUseModifier : public WalkerPass<PostWalker<GlobalUseModifier>> {
+  bool isFunctionParallel() override { return true; }
+
+  GlobalUseModifier(NameNameMap* copiedParentMap)
+    : copiedParentMap(copiedParentMap) {}
+
+  GlobalUseModifier* create() override {
+    return new GlobalUseModifier(copiedParentMap);
+  }
+
+  void visitGlobalGet(GlobalGet* curr) {
+    auto iter = copiedParentMap->find(curr->name);
+    if (iter != copiedParentMap->end()) {
+      curr->name = iter->second;
+    }
+  }
+
+private:
+  NameNameMap* copiedParentMap;
+};
+
+struct ConstantGlobalApplier
+  : public WalkerPass<
+      LinearExecutionWalker<ConstantGlobalApplier,
+                            UnifiedExpressionVisitor<ConstantGlobalApplier>>> {
+  bool isFunctionParallel() override { return true; }
+
+  ConstantGlobalApplier(NameSet* constantGlobals, bool optimize)
+    : constantGlobals(constantGlobals), optimize(optimize) {}
+
+  ConstantGlobalApplier* create() override {
+    return new ConstantGlobalApplier(constantGlobals, optimize);
+  }
+
+  void visitExpression(Expression* curr) {
+    if (auto* set = curr->dynCast<GlobalSet>()) {
+      if (Properties::isConstantExpression(set->value)) {
+        currConstantGlobals[set->name] =
+          getLiteralsFromConstExpression(set->value);
+      } else {
+        currConstantGlobals.erase(set->name);
+      }
+      return;
+    } else if (auto* get = curr->dynCast<GlobalGet>()) {
+      // Check if the global is known to be constant all the time.
+      if (constantGlobals->count(get->name)) {
+        auto* global = getModule()->getGlobal(get->name);
+        assert(Properties::isConstantExpression(global->init));
+        replaceCurrent(ExpressionManipulator::copy(global->init, *getModule()));
+        replaced = true;
+        return;
+      }
+      // Check if the global has a known value in this linear trace.
+      auto iter = currConstantGlobals.find(get->name);
+      if (iter != currConstantGlobals.end()) {
+        Builder builder(*getModule());
+        replaceCurrent(builder.makeConstantExpression(iter->second));
+        replaced = true;
+      }
+      return;
+    }
+    // Otherwise, invalidate if we need to.
+    EffectAnalyzer effects(getPassOptions(), getModule()->features);
+    effects.visit(curr);
+    assert(effects.globalsWritten.empty()); // handled above
+    if (effects.calls) {
+      currConstantGlobals.clear();
+    }
+  }
+
+  static void doNoteNonLinear(ConstantGlobalApplier* self, Expression** currp) {
+    self->currConstantGlobals.clear();
+  }
+
+  void visitFunction(Function* curr) {
+    if (replaced && optimize) {
+      PassRunner runner(getModule(), getPassRunner()->options);
+      runner.setIsNested(true);
+      runner.addDefaultFunctionOptimizationPasses();
+      runner.runOnFunction(curr);
+    }
+  }
+
+private:
+  NameSet* constantGlobals;
+  bool optimize;
+  bool replaced = false;
+
+  // The globals currently constant in the linear trace.
+  std::map<Name, Literals> currConstantGlobals;
+};
+
+struct GlobalSetRemover : public WalkerPass<PostWalker<GlobalSetRemover>> {
+  GlobalSetRemover(const NameSet* toRemove, bool optimize)
+    : toRemove(toRemove), optimize(optimize) {}
+
+  bool isFunctionParallel() override { return true; }
+
+  GlobalSetRemover* create() override {
+    return new GlobalSetRemover(toRemove, optimize);
+  }
+
+  void visitGlobalSet(GlobalSet* curr) {
+    if (toRemove->count(curr->name) != 0) {
+      replaceCurrent(Builder(*getModule()).makeDrop(curr->value));
+      removed = true;
+    }
+  }
+
+  void visitFunction(Function* curr) {
+    if (removed && optimize) {
+      PassRunner runner(getModule(), getPassRunner()->options);
+      runner.setIsNested(true);
+      runner.addDefaultFunctionOptimizationPasses();
+      runner.runOnFunction(curr);
+    }
+  }
+
+private:
+  const NameSet* toRemove;
+  bool optimize;
+  bool removed = false;
+};
+
+} // anonymous namespace
+
+struct SimplifyGlobals : public Pass {
+  PassRunner* runner;
+  Module* module;
+
+  GlobalInfoMap map;
+  bool optimize;
+
+  SimplifyGlobals(bool optimize = false) : optimize(optimize) {}
+
+  void run(PassRunner* runner_, Module* module_) override {
+    runner = runner_;
+    module = module_;
+
+    analyze();
+
+    removeWritesToUnreadGlobals();
+
+    preferEarlierImports();
+
+    propagateConstantsToGlobals();
+
+    propagateConstantsToCode();
+  }
+
+  void analyze() {
+    // First, find out all the relevant info.
+    for (auto& global : module->globals) {
+      auto& info = map[global->name];
+      if (global->imported()) {
+        info.imported = true;
+      }
+    }
+    for (auto& ex : module->exports) {
+      if (ex->kind == ExternalKind::Global) {
+        map[ex->value].exported = true;
+      }
+    }
+    GlobalUseScanner(&map).run(runner, module);
+    // We now know which are immutable in practice.
+    for (auto& global : module->globals) {
+      auto& info = map[global->name];
+      if (global->mutable_ && !info.imported && !info.exported &&
+          !info.written) {
+        global->mutable_ = false;
+      }
+    }
+  }
+
+  void removeWritesToUnreadGlobals() {
+    // Globals that are not exports and not read from can be eliminated
+    // (even if they are written to).
+    NameSet unreadGlobals;
+    for (auto& global : module->globals) {
+      auto& info = map[global->name];
+      if (!info.imported && !info.exported && !info.read) {
+        unreadGlobals.insert(global->name);
+        // We can now mark this global as immutable, and un-written, since we
+        // are about to remove all the `.set` operations on it.
+        global->mutable_ = false;
+        info.written = false;
+      }
+    }
+    GlobalSetRemover(&unreadGlobals, optimize).run(runner, module);
+  }
+
+  void preferEarlierImports() {
+    // Optimize uses of immutable globals, prefer the earlier import when
+    // there is a copy.
+    NameNameMap copiedParentMap;
+    for (auto& global : module->globals) {
+      auto child = global->name;
+      if (!global->mutable_ && !global->imported()) {
+        if (auto* get = global->init->dynCast<GlobalGet>()) {
+          auto parent = get->name;
+          if (!module->getGlobal(get->name)->mutable_) {
+            copiedParentMap[child] = parent;
+          }
+        }
+      }
+    }
+    if (!copiedParentMap.empty()) {
+      // Go all the way back.
+      for (auto& global : module->globals) {
+        auto child = global->name;
+        if (copiedParentMap.count(child)) {
+          while (copiedParentMap.count(copiedParentMap[child])) {
+            copiedParentMap[child] = copiedParentMap[copiedParentMap[child]];
+          }
+        }
+      }
+      // Apply to the gets.
+      GlobalUseModifier(&copiedParentMap).run(runner, module);
+    }
+  }
+
+  // Constant propagation part 1: even an mutable global with a constant
+  // value can have that value propagated to another global that reads it,
+  // since we do know the value during startup, it can't be modified until
+  // code runs.
+  void propagateConstantsToGlobals() {
+    // Go over the list of globals in order, which is the order of
+    // initialization as well, tracking their constant values.
+    std::map<Name, Literals> constantGlobals;
+    for (auto& global : module->globals) {
+      if (!global->imported()) {
+        if (Properties::isConstantExpression(global->init)) {
+          constantGlobals[global->name] =
+            getLiteralsFromConstExpression(global->init);
+        } else if (auto* get = global->init->dynCast<GlobalGet>()) {
+          auto iter = constantGlobals.find(get->name);
+          if (iter != constantGlobals.end()) {
+            Builder builder(*module);
+            global->init = builder.makeConstantExpression(iter->second);
+          }
+        }
+      }
+    }
+  }
+
+  // Constant propagation part 2: apply the values of immutable globals
+  // with constant values to to global.gets in the code.
+  void propagateConstantsToCode() {
+    NameSet constantGlobals;
+    for (auto& global : module->globals) {
+      if (!global->mutable_ && !global->imported() &&
+          Properties::isConstantExpression(global->init)) {
+        constantGlobals.insert(global->name);
+      }
+    }
+    ConstantGlobalApplier(&constantGlobals, optimize).run(runner, module);
+  }
+};
+
+Pass* createSimplifyGlobalsPass() { return new SimplifyGlobals(false); }
+
+Pass* createSimplifyGlobalsOptimizingPass() {
+  return new SimplifyGlobals(true);
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/SimplifyLocals.cpp b/binaryen/src/passes/SimplifyLocals.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/SimplifyLocals.cpp
@@ -0,0 +1,1055 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// Locals-related optimizations
+//
+// This "sinks" local.sets, pushing them to the next local.get where possible,
+// and removing the set if there are no gets remaining (the latter is
+// particularly useful in ssa mode, but not only).
+//
+// We also note where local.sets coalesce: if all breaks of a block set
+// a specific local, we can use a block return value for it, in effect
+// removing multiple local.sets and replacing them with one that the
+// block returns to. Further optimization rounds then have the opportunity
+// to remove that local.set as well. TODO: support partial traces; right
+// now, whenever control flow splits, we invalidate everything.
+//
+// After this pass, some locals may be completely unused. reorder-locals
+// can get rid of those (the operation is trivial there after it sorts by use
+// frequency).
+//
+// This pass has options:
+//
+//   * Tee: allow teeing, i.e., sinking a local with more than one use,
+//          and so after sinking we have a tee for the first use.
+//   * Structure: create block and if return values, by merging the
+//                internal local.sets into one on the outside,
+//                that can itself then be sunk further.
+//
+// There is also an option to disallow nesting entirely, which disallows
+// Tee and Structure from those 2 options, and also disallows any sinking
+// operation that would create nesting. This keeps the IR flat while
+// removing redundant locals.
+//
+
+#include "ir/equivalent_sets.h"
+#include <ir/branch-utils.h>
+#include <ir/effects.h>
+#include <ir/find_all.h>
+#include <ir/local-utils.h>
+#include <ir/manipulation.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm-traversal.h>
+#include <wasm.h>
+
+namespace wasm {
+
+// Main class
+
+template<bool allowTee = true,
+         bool allowStructure = true,
+         bool allowNesting = true>
+struct SimplifyLocals
+  : public WalkerPass<LinearExecutionWalker<
+      SimplifyLocals<allowTee, allowStructure, allowNesting>>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override {
+    return new SimplifyLocals<allowTee, allowStructure, allowNesting>();
+  }
+
+  // information for a local.set we can sink
+  struct SinkableInfo {
+    Expression** item;
+    EffectAnalyzer effects;
+
+    SinkableInfo(Expression** item,
+                 PassOptions& passOptions,
+                 FeatureSet features)
+      : item(item), effects(passOptions, features, *item) {}
+  };
+
+  // a list of sinkables in a linear execution trace
+  typedef std::map<Index, SinkableInfo> Sinkables;
+
+  // locals in current linear execution trace, which we try to sink
+  Sinkables sinkables;
+
+  // Information about an exit from a block: the break, and the
+  // sinkables. For the final exit from a block (falling off)
+  // exitter is null.
+  struct BlockBreak {
+    Expression** brp;
+    Sinkables sinkables;
+  };
+
+  // a list of all sinkable traces that exit a block. the last
+  // is falling off the end, others are branches. this is used for
+  // block returns
+  std::map<Name, std::vector<BlockBreak>> blockBreaks;
+
+  // blocks that we can't produce a block return value for them.
+  // (switch target, or some other reason)
+  std::set<Name> unoptimizableBlocks;
+
+  // A stack of sinkables from the current traversal state. When
+  // execution reaches an if-else, it splits, and can then
+  // be merged on return.
+  std::vector<Sinkables> ifStack;
+
+  // whether we need to run an additional cycle
+  bool anotherCycle;
+
+  // whether this is the first cycle, in which we always disallow teeing
+  bool firstCycle;
+
+  // local => # of local.gets for it
+  LocalGetCounter getCounter;
+
+  static void
+  doNoteNonLinear(SimplifyLocals<allowTee, allowStructure, allowNesting>* self,
+                  Expression** currp) {
+    // Main processing.
+    auto* curr = *currp;
+    if (auto* br = curr->dynCast<Break>()) {
+      if (br->value) {
+        // value means the block already has a return value
+        self->unoptimizableBlocks.insert(br->name);
+      } else {
+        self->blockBreaks[br->name].push_back(
+          {currp, std::move(self->sinkables)});
+      }
+    } else if (curr->is<Block>()) {
+      return; // handled in visitBlock
+    } else if (curr->is<If>()) {
+      assert(!curr->cast<If>()
+                ->ifFalse); // if-elses are handled by doNoteIf* methods
+    } else if (curr->is<Switch>()) {
+      auto* sw = curr->cast<Switch>();
+      auto targets = BranchUtils::getUniqueTargets(sw);
+      for (auto target : targets) {
+        self->unoptimizableBlocks.insert(target);
+      }
+      // TODO: we could use this info to stop gathering data on these blocks
+    } else if (auto* br = curr->dynCast<BrOnExn>()) {
+      // We cannot optimize the block this targets to have a return value, as
+      // the br_on_exn doesn't support a change to the block's type
+      self->unoptimizableBlocks.insert(br->name);
+    }
+    self->sinkables.clear();
+  }
+
+  static void doNoteIfCondition(
+    SimplifyLocals<allowTee, allowStructure, allowNesting>* self,
+    Expression** currp) {
+    // we processed the condition of this if-else, and now control flow branches
+    // into either the true or the false sides
+    self->sinkables.clear();
+  }
+
+  static void
+  doNoteIfTrue(SimplifyLocals<allowTee, allowStructure, allowNesting>* self,
+               Expression** currp) {
+    auto* iff = (*currp)->cast<If>();
+    if (iff->ifFalse) {
+      // We processed the ifTrue side of this if-else, save it on the stack.
+      self->ifStack.push_back(std::move(self->sinkables));
+    } else {
+      // This is an if without an else.
+      if (allowStructure) {
+        self->optimizeIfReturn(iff, currp);
+      }
+      self->sinkables.clear();
+    }
+  }
+
+  static void
+  doNoteIfFalse(SimplifyLocals<allowTee, allowStructure, allowNesting>* self,
+                Expression** currp) {
+    // we processed the ifFalse side of this if-else, we can now try to
+    // mere with the ifTrue side and optimize a return value, if possible
+    auto* iff = (*currp)->cast<If>();
+    assert(iff->ifFalse);
+    if (allowStructure) {
+      self->optimizeIfElseReturn(iff, currp, self->ifStack.back());
+    }
+    self->ifStack.pop_back();
+    self->sinkables.clear();
+  }
+
+  void visitBlock(Block* curr) {
+    bool hasBreaks = curr->name.is() && blockBreaks[curr->name].size() > 0;
+
+    if (allowStructure) {
+      optimizeBlockReturn(curr); // can modify blockBreaks
+    }
+
+    // post-block cleanups
+    if (curr->name.is()) {
+      if (unoptimizableBlocks.count(curr->name)) {
+        sinkables.clear();
+        unoptimizableBlocks.erase(curr->name);
+      }
+
+      if (hasBreaks) {
+        // more than one path to here, so nonlinear
+        sinkables.clear();
+        blockBreaks.erase(curr->name);
+      }
+    }
+  }
+
+  void visitLoop(Loop* curr) {
+    if (allowStructure) {
+      optimizeLoopReturn(curr);
+    }
+  }
+
+  void optimizeLocalGet(LocalGet* curr) {
+    auto found = sinkables.find(curr->index);
+    if (found != sinkables.end()) {
+      auto* set = (*found->second.item)
+                    ->template cast<LocalSet>(); // the set we may be sinking
+      bool oneUse = firstCycle || getCounter.num[curr->index] == 1;
+      // the set's value may be a get (i.e., the set is a copy)
+      auto* get = set->value->template dynCast<LocalGet>();
+      // if nesting is not allowed, and this might cause nesting, check if the
+      // sink would cause such a thing
+      if (!allowNesting) {
+        // a get is always ok to sink
+        if (!get) {
+          assert(expressionStack.size() >= 2);
+          assert(expressionStack[expressionStack.size() - 1] == curr);
+          auto* parent = expressionStack[expressionStack.size() - 2];
+          bool parentIsSet = parent->template is<LocalSet>();
+          // if the parent of this get is a set, we can sink into the set's
+          // value, it would not be nested.
+          if (!parentIsSet) {
+            return;
+          }
+        }
+      }
+      // we can optimize here
+      if (!allowNesting && get && !oneUse) {
+        // if we can't nest 's a copy with multiple uses, then we can't create
+        // a tee, and we can't nop the origin, but we can at least switch to
+        // the copied index, which may make the origin unneeded eventually.
+        curr->index = get->index;
+        anotherCycle = true;
+        return;
+      }
+      // sink it, and nop the origin
+      if (oneUse) {
+        // with just one use, we can sink just the value
+        this->replaceCurrent(set->value);
+      } else {
+        this->replaceCurrent(set);
+        assert(!set->isTee());
+        set->makeTee(this->getFunction()->getLocalType(set->index));
+      }
+      // reuse the local.get that is dying
+      *found->second.item = curr;
+      ExpressionManipulator::nop(curr);
+      sinkables.erase(found);
+      anotherCycle = true;
+    }
+  }
+
+  void visitDrop(Drop* curr) {
+    // collapse drop-tee into set, which can occur if a get was sunk into a tee
+    auto* set = curr->value->dynCast<LocalSet>();
+    if (set) {
+      assert(set->isTee());
+      set->makeSet();
+      this->replaceCurrent(set);
+    }
+  }
+
+  void checkInvalidations(EffectAnalyzer& effects) {
+    // TODO: this is O(bad)
+    std::vector<Index> invalidated;
+    for (auto& sinkable : sinkables) {
+      if (effects.invalidates(sinkable.second.effects)) {
+        invalidated.push_back(sinkable.first);
+      }
+    }
+    for (auto index : invalidated) {
+      sinkables.erase(index);
+    }
+  }
+
+  // a full expression stack is used when !allowNesting, so that we can check if
+  // a sink would cause nesting
+  ExpressionStack expressionStack;
+
+  static void
+  visitPre(SimplifyLocals<allowTee, allowStructure, allowNesting>* self,
+           Expression** currp) {
+    Expression* curr = *currp;
+
+    // Expressions that may throw cannot be sinked into 'try'. At the start of
+    // 'try', we drop all sinkables that may throw.
+    if (curr->is<Try>()) {
+      std::vector<Index> invalidated;
+      for (auto& sinkable : self->sinkables) {
+        if (sinkable.second.effects.throws) {
+          invalidated.push_back(sinkable.first);
+        }
+      }
+      for (auto index : invalidated) {
+        self->sinkables.erase(index);
+      }
+    }
+
+    EffectAnalyzer effects(self->getPassOptions(), self->getModule()->features);
+    if (effects.checkPre(curr)) {
+      self->checkInvalidations(effects);
+    }
+
+    if (!allowNesting) {
+      self->expressionStack.push_back(curr);
+    }
+  }
+
+  static void
+  visitPost(SimplifyLocals<allowTee, allowStructure, allowNesting>* self,
+            Expression** currp) {
+    // Handling invalidations in the case where the current node is a get
+    // that we sink into is not trivial in general. In the simple case,
+    // all current sinkables are compatible with each other (otherwise one
+    // would have invalidated a previous one, and removed it). Given that, if
+    // we sink one of the sinkables, then that new code cannot invalidate any
+    // other sinkable - we've already compared them. However, a tricky case
+    // is when a sinkable contains another sinkable,
+    //
+    //  (local.set $x
+    //   (block (result i32)
+    //    (A (local.get $y))
+    //    (local.set $y B)
+    //   )
+    //  )
+    //  (C (local.get $y))
+    //  (D (local.get $x))
+    //
+    // If we sink the set of $y, we have
+    //
+    //  (local.set $x
+    //   (block (result i32)
+    //    (A (local.get $y))
+    //    (nop)
+    //   )
+    //  )
+    //  (C B)
+    //  (D (local.get $x))
+    //
+    // There is now a risk that the set of $x should be invalidated, because
+    // if we sink it then A may happen after B (imagine that B contains
+    // something dangerous for that). To verify the risk, we could recursively
+    // scan all of B, but that is less efficient. Instead, the key thing is
+    // that if we sink out an inner part of a set, we should just leave further
+    // work on it to a later iteration. This is achieved by checking for
+    // invalidation on the original node, the local.get $y, which is guaranteed
+    // to invalidate the parent whose inner part was removed (since the inner
+    // part has a set, and the original node is a get of that same local).
+    //
+    // To implement this, if the current node is a get, note it and use it
+    // for invalidations later down. We must note it since optimizing the get
+    // may perform arbitrary changes to the graph, including reuse the get.
+
+    Expression* original = *currp;
+
+    LocalGet originalGet;
+
+    if (auto* get = (*currp)->dynCast<LocalGet>()) {
+      // Note: no visitor for LocalGet, so that we can handle it here.
+      originalGet = *get;
+      original = &originalGet;
+      self->optimizeLocalGet(get);
+    }
+
+    // perform main LocalSet processing here, since we may be the result of
+    // replaceCurrent, i.e., no visitor for LocalSet, like LocalGet above.
+    auto* set = (*currp)->dynCast<LocalSet>();
+
+    if (set) {
+      // if we see a set that was already potentially-sinkable, then the
+      // previous store is dead, leave just the value
+      auto found = self->sinkables.find(set->index);
+      if (found != self->sinkables.end()) {
+        auto* previous = (*found->second.item)->template cast<LocalSet>();
+        assert(!previous->isTee());
+        auto* previousValue = previous->value;
+        Drop* drop = ExpressionManipulator::convert<LocalSet, Drop>(previous);
+        drop->value = previousValue;
+        drop->finalize();
+        self->sinkables.erase(found);
+        self->anotherCycle = true;
+      }
+    }
+
+    FeatureSet features = self->getModule()->features;
+    EffectAnalyzer effects(self->getPassOptions(), features);
+    if (effects.checkPost(original)) {
+      self->checkInvalidations(effects);
+    }
+
+    if (set && self->canSink(set)) {
+      Index index = set->index;
+      assert(self->sinkables.count(index) == 0);
+      self->sinkables.emplace(std::make_pair(
+        index, SinkableInfo(currp, self->getPassOptions(), features)));
+    }
+
+    if (!allowNesting) {
+      self->expressionStack.pop_back();
+    }
+  }
+
+  bool canSink(LocalSet* set) {
+    // we can never move a tee
+    if (set->isTee()) {
+      return false;
+    }
+    // We cannot move expressions containing exnref.pops that are not enclosed
+    // in 'catch', because 'exnref.pop' should follow right after 'catch'.
+    FeatureSet features = this->getModule()->features;
+    if (features.hasExceptionHandling() &&
+        EffectAnalyzer(this->getPassOptions(), features, set->value)
+          .danglingPop) {
+      return false;
+    }
+    // if in the first cycle, or not allowing tees, then we cannot sink if >1
+    // use as that would make a tee
+    if ((firstCycle || !allowTee) && getCounter.num[set->index] > 1) {
+      return false;
+    }
+    return true;
+  }
+
+  std::vector<Block*> blocksToEnlarge;
+  std::vector<If*> ifsToEnlarge;
+  std::vector<Loop*> loopsToEnlarge;
+
+  void optimizeLoopReturn(Loop* loop) {
+    // If there is a sinkable thing in an eligible loop, we can optimize
+    // it in a trivial way to the outside of the loop.
+    if (loop->type != Type::none) {
+      return;
+    }
+    if (sinkables.empty()) {
+      return;
+    }
+    Index goodIndex = sinkables.begin()->first;
+    // Ensure we have a place to write the return values for, if not, we
+    // need another cycle.
+    auto* block = loop->body->dynCast<Block>();
+    if (!block || block->name.is() || block->list.size() == 0 ||
+        !block->list.back()->is<Nop>()) {
+      loopsToEnlarge.push_back(loop);
+      return;
+    }
+    Builder builder(*this->getModule());
+    auto** item = sinkables.at(goodIndex).item;
+    auto* set = (*item)->template cast<LocalSet>();
+    block->list[block->list.size() - 1] = set->value;
+    *item = builder.makeNop();
+    block->finalize();
+    assert(block->type != Type::none);
+    loop->finalize();
+    set->value = loop;
+    set->finalize();
+    this->replaceCurrent(set);
+    // We moved things around, clear all tracking; we'll do another cycle
+    // anyhow.
+    sinkables.clear();
+    anotherCycle = true;
+  }
+
+  void optimizeBlockReturn(Block* block) {
+    if (!block->name.is() || unoptimizableBlocks.count(block->name) > 0) {
+      return;
+    }
+    auto breaks = std::move(blockBreaks[block->name]);
+    blockBreaks.erase(block->name);
+    if (breaks.size() == 0) {
+      // block has no branches TODO we might optimize trivial stuff here too
+      return;
+    }
+    // block does not already have a return value (if one break has one, they
+    // all do)
+    assert(!(*breaks[0].brp)->template cast<Break>()->value);
+    // look for a local.set that is present in them all
+    bool found = false;
+    Index sharedIndex = -1;
+    for (auto& sinkable : sinkables) {
+      Index index = sinkable.first;
+      bool inAll = true;
+      for (size_t j = 0; j < breaks.size(); j++) {
+        if (breaks[j].sinkables.count(index) == 0) {
+          inAll = false;
+          break;
+        }
+      }
+      if (inAll) {
+        sharedIndex = index;
+        found = true;
+        break;
+      }
+    }
+    if (!found) {
+      return;
+    }
+    // If one of our brs is a br_if, then we will give it a value. since
+    // the value executes before the condition, it is dangerous if we are
+    // moving code out of the condition,
+    //  (br_if
+    //   (block
+    //    ..use $x..
+    //    (local.set $x ..)
+    //   )
+    //  )
+    // =>
+    //  (br_if
+    //   (local.tee $x ..) ;; this now affects the use!
+    //   (block
+    //    ..use $x..
+    //   )
+    //  )
+    // so we must check for that.
+    FeatureSet features = this->getModule()->features;
+    for (size_t j = 0; j < breaks.size(); j++) {
+      // move break local.set's value to the break
+      auto* breakLocalSetPointer = breaks[j].sinkables.at(sharedIndex).item;
+      auto* brp = breaks[j].brp;
+      auto* br = (*brp)->template cast<Break>();
+      auto* set = (*breakLocalSetPointer)->template cast<LocalSet>();
+      if (br->condition) {
+        // TODO: optimize
+        FindAll<LocalSet> findAll(br->condition);
+        for (auto* otherSet : findAll.list) {
+          if (otherSet == set) {
+            // the set is indeed in the condition, so we can't just move it
+            // but maybe there are no effects? see if, ignoring the set
+            // itself, there is any risk
+            Nop nop;
+            *breakLocalSetPointer = &nop;
+            EffectAnalyzer condition(
+              this->getPassOptions(), features, br->condition);
+            EffectAnalyzer value(this->getPassOptions(), features, set);
+            *breakLocalSetPointer = set;
+            if (condition.invalidates(value)) {
+              // indeed, we can't do this, stop
+              return;
+            }
+            break; // we found set in the list, can stop now
+          }
+        }
+      }
+    }
+    // Great, this local is set in them all, we can optimize!
+    if (block->list.size() == 0 || !block->list.back()->is<Nop>()) {
+      // We can't do this here, since we can't push to the block -
+      // it would invalidate sinkable pointers. So we queue a request
+      // to grow the block at the end of the turn, we'll get this next
+      // cycle.
+      blocksToEnlarge.push_back(block);
+      return;
+    }
+    // move block local.set's value to the end, in return position, and nop the
+    // set
+    auto* blockLocalSetPointer = sinkables.at(sharedIndex).item;
+    auto* value = (*blockLocalSetPointer)->template cast<LocalSet>()->value;
+    block->list[block->list.size() - 1] = value;
+    ExpressionManipulator::nop(*blockLocalSetPointer);
+    for (size_t j = 0; j < breaks.size(); j++) {
+      // move break local.set's value to the break
+      auto* breakLocalSetPointer = breaks[j].sinkables.at(sharedIndex).item;
+      auto* brp = breaks[j].brp;
+      auto* br = (*brp)->template cast<Break>();
+      assert(!br->value);
+      // if the break is conditional, then we must set the value here - if the
+      // break is not reached, we must still have the new value in the local
+      auto* set = (*breakLocalSetPointer)->template cast<LocalSet>();
+      if (br->condition) {
+        br->value = set;
+        set->makeTee(this->getFunction()->getLocalType(set->index));
+        *breakLocalSetPointer =
+          this->getModule()->allocator.template alloc<Nop>();
+        // in addition, as this is a conditional br that now has a value, it now
+        // returns a value, so it must be dropped
+        br->finalize();
+        *brp = Builder(*this->getModule()).makeDrop(br);
+      } else {
+        br->value = set->value;
+        ExpressionManipulator::nop(set);
+      }
+    }
+    // finally, create a local.set on the block itself
+    auto* newLocalSet =
+      Builder(*this->getModule()).makeLocalSet(sharedIndex, block);
+    this->replaceCurrent(newLocalSet);
+    sinkables.clear();
+    anotherCycle = true;
+    block->finalize();
+  }
+
+  // optimize local.sets from both sides of an if into a return value
+  void optimizeIfElseReturn(If* iff, Expression** currp, Sinkables& ifTrue) {
+    assert(iff->ifFalse);
+    // if this if already has a result, or is unreachable code, we have
+    // nothing to do
+    if (iff->type != Type::none) {
+      return;
+    }
+    // We now have the sinkables from both sides of the if, and can look
+    // for something to sink. That is either a shared index on both sides,
+    // *or* if one side is unreachable, we can sink anything from the other,
+    //   (if
+    //     (..)
+    //     (br $x)
+    //     (local.set $y (..))
+    //   )
+    //    =>
+    //   (local.set $y
+    //     (if (result i32)
+    //       (..)
+    //       (br $x)
+    //       (..)
+    //     )
+    //   )
+    Sinkables& ifFalse = sinkables;
+    Index goodIndex = -1;
+    bool found = false;
+    if (iff->ifTrue->type == Type::unreachable) {
+      // since the if type is none
+      assert(iff->ifFalse->type != Type::unreachable);
+      if (!ifFalse.empty()) {
+        goodIndex = ifFalse.begin()->first;
+        found = true;
+      }
+    } else if (iff->ifFalse->type == Type::unreachable) {
+      // since the if type is none
+      assert(iff->ifTrue->type != Type::unreachable);
+      if (!ifTrue.empty()) {
+        goodIndex = ifTrue.begin()->first;
+        found = true;
+      }
+    } else {
+      // Look for a shared index.
+      for (auto& sinkable : ifTrue) {
+        Index index = sinkable.first;
+        if (ifFalse.count(index) > 0) {
+          goodIndex = index;
+          found = true;
+          break;
+        }
+      }
+    }
+    if (!found) {
+      return;
+    }
+    // great, we can optimize!
+    // ensure we have a place to write the return values for, if not, we
+    // need another cycle
+    auto* ifTrueBlock = iff->ifTrue->dynCast<Block>();
+    if (iff->ifTrue->type != Type::unreachable) {
+      if (!ifTrueBlock || ifTrueBlock->name.is() ||
+          ifTrueBlock->list.size() == 0 ||
+          !ifTrueBlock->list.back()->is<Nop>()) {
+        ifsToEnlarge.push_back(iff);
+        return;
+      }
+    }
+    auto* ifFalseBlock = iff->ifFalse->dynCast<Block>();
+    if (iff->ifFalse->type != Type::unreachable) {
+      if (!ifFalseBlock || ifFalseBlock->name.is() ||
+          ifFalseBlock->list.size() == 0 ||
+          !ifFalseBlock->list.back()->is<Nop>()) {
+        ifsToEnlarge.push_back(iff);
+        return;
+      }
+    }
+    // all set, go
+    if (iff->ifTrue->type != Type::unreachable) {
+      auto* ifTrueItem = ifTrue.at(goodIndex).item;
+      ifTrueBlock->list[ifTrueBlock->list.size() - 1] =
+        (*ifTrueItem)->template cast<LocalSet>()->value;
+      ExpressionManipulator::nop(*ifTrueItem);
+      ifTrueBlock->finalize();
+      assert(ifTrueBlock->type != Type::none);
+    }
+    if (iff->ifFalse->type != Type::unreachable) {
+      auto* ifFalseItem = ifFalse.at(goodIndex).item;
+      ifFalseBlock->list[ifFalseBlock->list.size() - 1] =
+        (*ifFalseItem)->template cast<LocalSet>()->value;
+      ExpressionManipulator::nop(*ifFalseItem);
+      ifFalseBlock->finalize();
+      assert(ifFalseBlock->type != Type::none);
+    }
+    iff->finalize(); // update type
+    assert(iff->type != Type::none);
+    // finally, create a local.set on the iff itself
+    auto* newLocalSet =
+      Builder(*this->getModule()).makeLocalSet(goodIndex, iff);
+    *currp = newLocalSet;
+    anotherCycle = true;
+  }
+
+  // Optimize local.sets from a one-sided iff, adding a get on the other:
+  //  (if
+  //    (..condition..)
+  //    (block
+  //      (local.set $x (..value..))
+  //    )
+  //  )
+  // =>
+  //  (local.set $x
+  //    (if (result ..)
+  //      (..condition..)
+  //      (block (result ..)
+  //        (..value..)
+  //      )
+  //      (local.get $x)
+  //    )
+  //  )
+  // This is a speculative optimization: we add a get here, as well as a branch
+  // in the if, so this is harmful for code size and for speed. However, later
+  // optimizations may sink the set and enable other useful things. If none of
+  // that happens, other passes can "undo" this by turning an if with a copy
+  // arm into a one-sided if.
+  void optimizeIfReturn(If* iff, Expression** currp) {
+    // If this if is unreachable code, we have nothing to do.
+    if (iff->type != Type::none || iff->ifTrue->type != Type::none) {
+      return;
+    }
+    // Anything sinkable is good for us.
+    if (sinkables.empty()) {
+      return;
+    }
+    Index goodIndex = sinkables.begin()->first;
+    // Ensure we have a place to write the return values for, if not, we
+    // need another cycle.
+    auto* ifTrueBlock = iff->ifTrue->dynCast<Block>();
+    if (!ifTrueBlock || ifTrueBlock->name.is() ||
+        ifTrueBlock->list.size() == 0 || !ifTrueBlock->list.back()->is<Nop>()) {
+      ifsToEnlarge.push_back(iff);
+      return;
+    }
+    // Update the ifTrue side.
+    Builder builder(*this->getModule());
+    auto** item = sinkables.at(goodIndex).item;
+    auto* set = (*item)->template cast<LocalSet>();
+    ifTrueBlock->list[ifTrueBlock->list.size() - 1] = set->value;
+    *item = builder.makeNop();
+    ifTrueBlock->finalize();
+    assert(ifTrueBlock->type != Type::none);
+    // Update the ifFalse side.
+    iff->ifFalse = builder.makeLocalGet(
+      set->index, this->getFunction()->getLocalType(set->index));
+    iff->finalize(); // update type
+    // Update the get count.
+    getCounter.num[set->index]++;
+    assert(iff->type != Type::none);
+    // Finally, reuse the local.set on the iff itself.
+    set->value = iff;
+    set->finalize();
+    *currp = set;
+    anotherCycle = true;
+  }
+
+  // override scan to add a pre and a post check task to all nodes
+  static void scan(SimplifyLocals<allowTee, allowStructure, allowNesting>* self,
+                   Expression** currp) {
+    self->pushTask(visitPost, currp);
+
+    auto* curr = *currp;
+
+    if (auto* iff = curr->dynCast<If>()) {
+      // handle if in a special manner, using the ifStack for if-elses etc.
+      if (iff->ifFalse) {
+        self->pushTask(
+          SimplifyLocals<allowTee, allowStructure, allowNesting>::doNoteIfFalse,
+          currp);
+        self->pushTask(
+          SimplifyLocals<allowTee, allowStructure, allowNesting>::scan,
+          &iff->ifFalse);
+      }
+      self->pushTask(
+        SimplifyLocals<allowTee, allowStructure, allowNesting>::doNoteIfTrue,
+        currp);
+      self->pushTask(
+        SimplifyLocals<allowTee, allowStructure, allowNesting>::scan,
+        &iff->ifTrue);
+      self->pushTask(SimplifyLocals<allowTee, allowStructure, allowNesting>::
+                       doNoteIfCondition,
+                     currp);
+      self->pushTask(
+        SimplifyLocals<allowTee, allowStructure, allowNesting>::scan,
+        &iff->condition);
+    } else {
+      WalkerPass<LinearExecutionWalker<
+        SimplifyLocals<allowTee, allowStructure, allowNesting>>>::scan(self,
+                                                                       currp);
+    }
+
+    self->pushTask(visitPre, currp);
+  }
+
+  void doWalkFunction(Function* func) {
+    if (func->getNumLocals() == 0) {
+      return; // nothing to do
+    }
+    // scan local.gets
+    getCounter.analyze(func);
+    // multiple passes may be required per function, consider this:
+    //    x = load
+    //    y = store
+    //    c(x, y)
+    // the load cannot cross the store, but y can be sunk, after which so can x.
+    //
+    // we start with a cycle focusing on single-use locals, which are easy to
+    // sink (we don't need to put a set), and a good match for common compiler
+    // output patterns. further cycles do fully general sinking.
+    firstCycle = true;
+    do {
+      anotherCycle = runMainOptimizations(func);
+      // After the special first cycle, definitely do another.
+      if (firstCycle) {
+        firstCycle = false;
+        anotherCycle = true;
+      }
+      // If we are all done, run the final optimizations, which may suggest we
+      // can do more work.
+      if (!anotherCycle) {
+        // Don't run multiple cycles of just the final optimizations - in
+        // particular, get canonicalization is not guaranteed to converge.
+        // Instead, if final opts help then see if they enable main
+        // opts; continue only if they do. In other words, do not end up
+        // doing final opts again and again when no main opts are being
+        // enabled.
+        if (runLateOptimizations(func) && runMainOptimizations(func)) {
+          anotherCycle = true;
+        }
+      }
+    } while (anotherCycle);
+  }
+
+  bool runMainOptimizations(Function* func) {
+    anotherCycle = false;
+    WalkerPass<LinearExecutionWalker<
+      SimplifyLocals<allowTee, allowStructure, allowNesting>>>::
+      doWalkFunction(func);
+    // enlarge blocks that were marked, for the next round
+    if (blocksToEnlarge.size() > 0) {
+      for (auto* block : blocksToEnlarge) {
+        block->list.push_back(
+          this->getModule()->allocator.template alloc<Nop>());
+      }
+      blocksToEnlarge.clear();
+      anotherCycle = true;
+    }
+    // enlarge ifs that were marked, for the next round
+    if (ifsToEnlarge.size() > 0) {
+      for (auto* iff : ifsToEnlarge) {
+        auto ifTrue =
+          Builder(*this->getModule()).blockifyWithName(iff->ifTrue, Name());
+        iff->ifTrue = ifTrue;
+        if (ifTrue->list.size() == 0 ||
+            !ifTrue->list.back()->template is<Nop>()) {
+          ifTrue->list.push_back(
+            this->getModule()->allocator.template alloc<Nop>());
+        }
+        if (iff->ifFalse) {
+          auto ifFalse =
+            Builder(*this->getModule()).blockifyWithName(iff->ifFalse, Name());
+          iff->ifFalse = ifFalse;
+          if (ifFalse->list.size() == 0 ||
+              !ifFalse->list.back()->template is<Nop>()) {
+            ifFalse->list.push_back(
+              this->getModule()->allocator.template alloc<Nop>());
+          }
+        }
+      }
+      ifsToEnlarge.clear();
+      anotherCycle = true;
+    }
+    // enlarge loops that were marked, for the next round
+    if (loopsToEnlarge.size() > 0) {
+      for (auto* loop : loopsToEnlarge) {
+        auto block =
+          Builder(*this->getModule()).blockifyWithName(loop->body, Name());
+        loop->body = block;
+        if (block->list.size() == 0 ||
+            !block->list.back()->template is<Nop>()) {
+          block->list.push_back(
+            this->getModule()->allocator.template alloc<Nop>());
+        }
+      }
+      loopsToEnlarge.clear();
+      anotherCycle = true;
+    }
+    // clean up
+    sinkables.clear();
+    blockBreaks.clear();
+    unoptimizableBlocks.clear();
+    return anotherCycle;
+  }
+
+  bool runLateOptimizations(Function* func) {
+    // Finally, after optimizing a function we can do some additional
+    // optimization.
+    getCounter.analyze(func);
+    // Remove equivalent copies - assignment of
+    // a local to another local that already contains that value. Note that
+    // we do that at the very end, and only after structure, as removing
+    // the copy here:
+    //   (if
+    //    (local.get $var$0)
+    //    (local.set $var$0
+    //     (local.get $var$0)
+    //    )
+    //    (local.set $var$0
+    //     (i32.const 208)
+    //    )
+    //   )
+    // will inhibit us creating an if return value.
+    struct EquivalentOptimizer
+      : public LinearExecutionWalker<EquivalentOptimizer> {
+      std::vector<Index>* numLocalGets;
+      bool removeEquivalentSets;
+      Module* module;
+
+      bool anotherCycle = false;
+
+      // We track locals containing the same value.
+      EquivalentSets equivalences;
+
+      static void doNoteNonLinear(EquivalentOptimizer* self,
+                                  Expression** currp) {
+        // TODO do this across non-linear paths too, in coalesce-locals perhaps?
+        //      (would inhibit structure opts here, though.
+        self->equivalences.clear();
+      }
+
+      void visitLocalSet(LocalSet* curr) {
+        // Remove trivial copies, even through a tee
+        auto* value = curr->value;
+        Function* func = this->getFunction();
+        while (auto* subSet = value->dynCast<LocalSet>()) {
+          value = subSet->value;
+        }
+        if (auto* get = value->dynCast<LocalGet>()) {
+          if (equivalences.check(curr->index, get->index)) {
+            // This is an unnecessary copy!
+            if (removeEquivalentSets) {
+              if (curr->isTee()) {
+                this->replaceCurrent(curr->value);
+              } else {
+                this->replaceCurrent(Builder(*module).makeDrop(curr->value));
+              }
+              anotherCycle = true;
+            }
+          } else if (func->getLocalType(curr->index) ==
+                     func->getLocalType(get->index)) {
+            // There is a new equivalence now.
+            equivalences.reset(curr->index);
+            equivalences.add(curr->index, get->index);
+          }
+        } else {
+          // A new value is assigned here.
+          equivalences.reset(curr->index);
+        }
+      }
+
+      void visitLocalGet(LocalGet* curr) {
+        // Canonicalize gets: if some are equivalent, then we can pick more
+        // then one, and other passes may benefit from having more uniformity.
+        if (auto* set = equivalences.getEquivalents(curr->index)) {
+          // Pick the index with the most uses - maximizing the chance to
+          // lower one's uses to zero.
+          // Helper method that returns the # of gets *ignoring the current
+          // get*, as we want to see what is best overall, treating this one as
+          // to be decided upon.
+          auto getNumGetsIgnoringCurr = [&](Index index) {
+            auto ret = (*numLocalGets)[index];
+            if (index == curr->index) {
+              assert(ret >= 1);
+              ret--;
+            }
+            return ret;
+          };
+          Index best = -1;
+          for (auto index : *set) {
+            if (best == Index(-1) ||
+                getNumGetsIgnoringCurr(index) > getNumGetsIgnoringCurr(best)) {
+              best = index;
+            }
+          }
+          assert(best != Index(-1));
+          // Due to ordering, the best index may be different from us but have
+          // the same # of locals - make sure we actually improve.
+          if (best != curr->index && getNumGetsIgnoringCurr(best) >
+                                       getNumGetsIgnoringCurr(curr->index)) {
+            // Update the get counts.
+            (*numLocalGets)[best]++;
+            assert((*numLocalGets)[curr->index] >= 1);
+            (*numLocalGets)[curr->index]--;
+            // Make the change.
+            curr->index = best;
+            anotherCycle = true;
+          }
+        }
+      }
+    };
+
+    EquivalentOptimizer eqOpter;
+    eqOpter.module = this->getModule();
+    eqOpter.numLocalGets = &getCounter.num;
+    eqOpter.removeEquivalentSets = allowStructure;
+    eqOpter.walkFunction(func);
+
+    // We may have already had a local with no uses, or we may have just
+    // gotten there thanks to the EquivalentOptimizer. If there are such
+    // locals, remove all their sets.
+    UnneededSetRemover setRemover(
+      getCounter, func, this->getPassOptions(), this->getModule()->features);
+    setRemover.setModule(this->getModule());
+
+    return eqOpter.anotherCycle || setRemover.removed;
+  }
+};
+
+Pass* createSimplifyLocalsPass() { return new SimplifyLocals<true, true>(); }
+
+Pass* createSimplifyLocalsNoTeePass() {
+  return new SimplifyLocals<false, true>();
+}
+
+Pass* createSimplifyLocalsNoStructurePass() {
+  return new SimplifyLocals<true, false>();
+}
+
+Pass* createSimplifyLocalsNoTeeNoStructurePass() {
+  return new SimplifyLocals<false, false>();
+}
+
+Pass* createSimplifyLocalsNoNestingPass() {
+  return new SimplifyLocals<false, false, false>();
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/Souperify.cpp b/binaryen/src/passes/Souperify.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/Souperify.cpp
@@ -0,0 +1,764 @@
+/*
+ * 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.
+ */
+
+//
+// Souperify - convert to Souper IR in text form.
+//
+// This needs 'flatten' to be run before it, as it assumes the IR is in
+// flat form. You may also want to optimize a little, e.g.
+//    --flatten --simplify-locals-nonesting --reorder-locals
+// (as otherwise flattening introduces many copies; we do ignore boring
+// copies here, but they end up as identical LHSes).
+//
+// See https://github.com/google/souper/issues/323
+//
+// TODO:
+//  * pcs and blockpcs for things other than ifs
+//  * Investigate 'inlining', adding in nodes through calls
+//  * Consider generalizing DataFlow IR for internal Binaryen use.
+//  * Automatic conversion of Binaryen IR opts to run on the DataFlow IR.
+//    This would subsume precompute-propagate, for example. Using DFIR we
+//    can "expand" the BIR into expressions that BIR opts can handle
+//    directly, without the need for *-propagate techniques.
+//
+
+#include "dataflow/graph.h"
+#include "dataflow/node.h"
+#include "dataflow/utils.h"
+#include "ir/flat.h"
+#include "ir/local-graph.h"
+#include "ir/utils.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+static int debug() {
+  static char* str = getenv("BINARYEN_DEBUG_SOUPERIFY");
+  static int ret = str ? atoi(str) : 0;
+  return ret;
+}
+
+namespace DataFlow {
+
+// Internal helper to find all the uses of a set.
+struct UseFinder {
+  // Gets a list of all the uses of an expression. As we are in flat IR,
+  // the expression must be the value of a set, and we seek the other sets
+  // (or rather, their values) that contain a get that uses that value.
+  // There may also be non-set uses of the value, for example in a drop
+  // or a return. We represent those with a nullptr, meaning "other".
+  std::vector<Expression*>
+  getUses(Expression* origin, Graph& graph, LocalGraph& localGraph) {
+    if (debug() >= 2) {
+      std::cout << "getUses\n" << origin << '\n';
+    }
+    std::vector<Expression*> ret;
+    auto* set = graph.getSet(origin);
+    if (!set) {
+      // If the parent is not a set (a drop, call, return, etc.) then
+      // it is not something we need to track.
+      return ret;
+    }
+    addSetUses(set, graph, localGraph, ret);
+    return ret;
+  }
+
+  // There may be loops of sets with copies between them.
+  std::unordered_set<LocalSet*> seenSets;
+
+  void addSetUses(LocalSet* set,
+                  Graph& graph,
+                  LocalGraph& localGraph,
+                  std::vector<Expression*>& ret) {
+    // If already handled, nothing to do here.
+    if (seenSets.count(set)) {
+      return;
+    }
+    seenSets.insert(set);
+    // Find all the uses of that set.
+    auto& gets = localGraph.setInfluences[set];
+    if (debug() >= 2) {
+      std::cout << "addSetUses for " << set << ", " << gets.size() << " gets\n";
+    }
+    for (auto* get : gets) {
+      // Each of these relevant gets is either
+      //  (1) a child of a set, which we can track, or
+      //  (2) not a child of a set, e.g., a call argument or such
+      auto& sets = localGraph.getInfluences[get]; // TODO: iterator
+      // In flat IR, each get can influence at most 1 set.
+      assert(sets.size() <= 1);
+      if (sets.size() == 0) {
+        // This get is not the child of a set. Check if it is a drop,
+        // otherwise it is an actual use, and so an external use.
+        auto* parent = graph.getParent(get);
+        if (parent && parent->is<Drop>()) {
+          // Just ignore it.
+        } else {
+          ret.push_back(nullptr);
+          if (debug() >= 2) {
+            std::cout << "add nullptr\n";
+          }
+        }
+      } else {
+        // This get is the child of a set.
+        auto* subSet = *sets.begin();
+        // If this is a copy, we need to look through it: data-flow IR
+        // counts actual values, not copies, and in particular we need
+        // to look through the copies that implement a phi.
+        if (subSet->value == get) {
+          // Indeed a copy.
+          // TODO: this could be optimized and done all at once beforehand.
+          addSetUses(subSet, graph, localGraph, ret);
+        } else {
+          // Not a copy.
+          auto* value = subSet->value;
+          ret.push_back(value);
+          if (debug() >= 2) {
+            std::cout << "add a value\n" << value << '\n';
+          }
+        }
+      }
+    }
+  }
+};
+
+// Generates a trace: all the information to generate a Souper LHS
+// for a specific local.set whose value we want to infer.
+struct Trace {
+  Graph& graph;
+  Node* toInfer;
+  // Nodes we should exclude from being children of traces (but they
+  // may be the root we try to infer.
+  std::unordered_set<Node*>& excludeAsChildren;
+
+  // A limit on how deep we go - we don't want to create arbitrarily
+  // large traces.
+  size_t depthLimit = 10;
+  size_t totalLimit = 30;
+
+  bool bad = false;
+  std::vector<Node*> nodes;
+  std::unordered_set<Node*> addedNodes;
+  std::vector<Node*> pathConditions;
+  // When we need to (like when the depth is too deep), we replace
+  // expressions with other expressions, and track them here.
+  std::unordered_map<Node*, std::unique_ptr<Node>> replacements;
+  // The nodes that have additional external uses (only computed
+  // for the "work" nodes, not the descriptive nodes arriving for
+  // path conditions).
+  std::unordered_set<Node*> hasExternalUses;
+  // We add path conditions after the "work". We collect them here
+  // and then go through them at the proper time.
+  std::vector<Node*> conditionsToAdd;
+  // Whether we are at the adding-conditions stage (i.e., post
+  // adding the "work").
+  bool addingConditions = false;
+  // The local information graph. Used to check if a node has external uses.
+  LocalGraph& localGraph;
+
+  Trace(Graph& graph,
+        Node* toInfer,
+        std::unordered_set<Node*>& excludeAsChildren,
+        LocalGraph& localGraph)
+    : graph(graph), toInfer(toInfer), excludeAsChildren(excludeAsChildren),
+      localGraph(localGraph) {
+    if (debug() >= 2) {
+      std::cout << "\nstart a trace (in " << graph.func->name << ")\n";
+    }
+    // Check if there is a depth limit override
+    auto* depthLimitStr = getenv("BINARYEN_SOUPERIFY_DEPTH_LIMIT");
+    if (depthLimitStr) {
+      depthLimit = atoi(depthLimitStr);
+    }
+    auto* totalLimitStr = getenv("BINARYEN_SOUPERIFY_TOTAL_LIMIT");
+    if (totalLimitStr) {
+      totalLimit = atoi(totalLimitStr);
+    }
+    // Pull in all the dependencies, starting from the value itself.
+    add(toInfer, 0);
+    if (bad) {
+      return;
+    }
+    // If we are trivial before adding pcs, we are still trivial, and
+    // can ignore this.
+    auto sizeBeforePathConditions = nodes.size();
+    // No input is uninteresting
+    if (sizeBeforePathConditions == 0) {
+      bad = true;
+      return;
+    }
+    // Just a var is uninteresting. TODO: others too?
+    if (sizeBeforePathConditions == 1 && nodes[0]->isVar()) {
+      bad = true;
+      return;
+    }
+    // Before adding the path conditions, we can now compute the
+    // actual number of uses of "work" nodes, the real computation done
+    // here and that we hope to replace, as opposed to path condition
+    // computation which is only descriptive and helps optimization of
+    // the work.
+    findExternalUses();
+    // We can now add conditions.
+    addingConditions = true;
+    for (auto* condition : conditionsToAdd) {
+      add(condition, 0);
+    }
+    // Add in path conditions based on the location of this node: e.g.
+    // if it is inside an if's true branch, we can add a path-condition
+    // for that.
+    auto iter = graph.nodeParentMap.find(toInfer);
+    if (iter != graph.nodeParentMap.end()) {
+      addPath(toInfer, iter->second);
+    }
+  }
+
+  Node* add(Node* node, size_t depth) {
+    depth++;
+    // If replaced, return the replacement.
+    auto iter = replacements.find(node);
+    if (iter != replacements.end()) {
+      return iter->second.get();
+    }
+    // If already added, nothing more to do.
+    if (addedNodes.find(node) != addedNodes.end()) {
+      return node;
+    }
+    switch (node->type) {
+      case Node::Type::Var: {
+        break; // nothing more to add
+      }
+      case Node::Type::Expr: {
+        // If this is a Const, it's not an instruction - nothing to add,
+        // it's just a value.
+        if (node->expr->is<Const>()) {
+          return node;
+        }
+        // If we've gone too deep, emit a var instead.
+        // Do the same if this is a node we should exclude from traces.
+        if (depth >= depthLimit || nodes.size() >= totalLimit ||
+            (node != toInfer &&
+             excludeAsChildren.find(node) != excludeAsChildren.end())) {
+          auto type = node->getWasmType();
+          assert(type.isConcrete());
+          auto* var = Node::makeVar(type);
+          replacements[node] = std::unique_ptr<Node>(var);
+          node = var;
+          break;
+        }
+        // Add the dependencies.
+        assert(!node->expr->is<LocalGet>());
+        for (Index i = 0; i < node->values.size(); i++) {
+          add(node->getValue(i), depth);
+        }
+        break;
+      }
+      case Node::Type::Phi: {
+        auto* block = add(node->getValue(0), depth);
+        assert(block);
+        auto size = block->values.size();
+        // First, add the conditions for the block
+        for (Index i = 0; i < size; i++) {
+          // a condition may be bad, but conditions are not necessary -
+          // we can proceed without the extra condition information
+          auto* condition = block->getValue(i);
+          if (!condition->isBad()) {
+            if (!addingConditions) {
+              // Too early, queue it for later.
+              conditionsToAdd.push_back(condition);
+            } else {
+              add(condition, depth);
+            }
+          }
+        }
+        // Then, add the phi values
+        for (Index i = 1; i < size + 1; i++) {
+          add(node->getValue(i), depth);
+        }
+        break;
+      }
+      case Node::Type::Cond: {
+        add(node->getValue(0), depth); // add the block
+        add(node->getValue(1), depth); // add the node
+        break;
+      }
+      case Node::Type::Block: {
+        break; // nothing more to add
+      }
+      case Node::Type::Zext: {
+        add(node->getValue(0), depth);
+        break;
+      }
+      case Node::Type::Bad: {
+        bad = true;
+        return nullptr;
+      }
+      default:
+        WASM_UNREACHABLE("unexpected node type");
+    }
+    // Assert on no cycles
+    assert(addedNodes.find(node) == addedNodes.end());
+    nodes.push_back(node);
+    addedNodes.insert(node);
+    return node;
+  }
+
+  void addPath(Node* node, Expression* curr) {
+    // We track curr and parent, which are always in the state of parent
+    // being the parent of curr.
+    auto* parent = graph.expressionParentMap.at(curr);
+    while (parent) {
+      auto iter = graph.expressionConditionMap.find(parent);
+      if (iter != graph.expressionConditionMap.end()) {
+        // Given the block, add a proper path-condition
+        addPathTo(parent, curr, iter->second);
+      }
+      curr = parent;
+      parent = graph.expressionParentMap.at(parent);
+    }
+  }
+
+  // curr is a child of parent, and parent has a Block which we are
+  // give as 'node'. Add a path condition for reaching the child.
+  void addPathTo(Expression* parent,
+                 Expression* curr,
+                 std::vector<Node*> conditions) {
+    if (auto* iff = parent->dynCast<If>()) {
+      Index index;
+      if (curr == iff->ifTrue) {
+        index = 0;
+      } else if (curr == iff->ifFalse) {
+        index = 1;
+      } else {
+        WASM_UNREACHABLE("invalid expr");
+      }
+      auto* condition = conditions[index];
+      // Add the condition itself as an instruction in the trace -
+      // the pc uses it as its input.
+      add(condition, 0);
+      // Add it as a pc, which we will emit directly.
+      pathConditions.push_back(condition);
+    } else {
+      WASM_UNREACHABLE("invalid expr");
+    }
+  }
+
+  bool isBad() { return bad; }
+
+  static bool isTraceable(Node* node) {
+    if (!node->origin) {
+      // Ignore artificial etc. nodes.
+      // TODO: perhaps require all the nodes for an origin appear, so we
+      //       don't try to compute an internal part of one, like the
+      //       extra artificial != 0 of a select?
+      return false;
+    }
+    if (node->isExpr()) {
+      // Consider only the simple computational nodes.
+      auto* expr = node->expr;
+      return expr->is<Unary>() || expr->is<Binary>() || expr->is<Select>();
+    }
+    return false;
+  }
+
+  void findExternalUses() {
+    // Find all the wasm code represented in this trace.
+    std::unordered_set<Expression*> origins;
+    for (auto& node : nodes) {
+      if (auto* origin = node->origin) {
+        if (debug() >= 2) {
+          std::cout << "note origin " << origin << '\n';
+        }
+        origins.insert(origin);
+      }
+    }
+    for (auto& node : nodes) {
+      if (node == toInfer) {
+        continue;
+      }
+      if (auto* origin = node->origin) {
+        auto uses = UseFinder().getUses(origin, graph, localGraph);
+        for (auto* use : uses) {
+          // A non-set use (a drop or return etc.) is definitely external.
+          // Otherwise, check if internal or external.
+          if (use == nullptr || origins.count(use) == 0) {
+            if (debug() >= 2) {
+              std::cout << "found external use for\n";
+              dump(node, std::cout);
+              std::cout << "  due to " << use << '\n';
+            }
+            hasExternalUses.insert(node);
+            break;
+          }
+        }
+      }
+    }
+  }
+};
+
+// Emits a trace, which is basically a Souper LHS.
+struct Printer {
+  Graph& graph;
+  Trace& trace;
+
+  // Each Node in a trace has an index, from 0.
+  std::unordered_map<Node*, Index> indexing;
+
+  bool printedHasExternalUses = false;
+
+  Printer(Graph& graph, Trace& trace) : graph(graph), trace(trace) {
+    std::cout << "\n; start LHS (in " << graph.func->name << ")\n";
+    // Index the nodes.
+    for (auto* node : trace.nodes) {
+      // pcs and blockpcs are not instructions and do not need to be indexed
+      if (!node->isCond()) {
+        auto index = indexing.size();
+        indexing[node] = index;
+      }
+    }
+    // Print them out.
+    for (auto* node : trace.nodes) {
+      print(node);
+    }
+    // Print out pcs.
+    for (auto* condition : trace.pathConditions) {
+      printPathCondition(condition);
+    }
+
+    // Finish up
+    std::cout << "infer %" << indexing[trace.toInfer] << "\n\n";
+  }
+
+  Node* getMaybeReplaced(Node* node) {
+    auto iter = trace.replacements.find(node);
+    if (iter != trace.replacements.end()) {
+      return iter->second.get();
+    }
+    return node;
+  }
+
+  void print(Node* node) {
+    // The node may have been replaced during trace building, if so then
+    // print the proper replacement.
+    node = getMaybeReplaced(node);
+    assert(node);
+    switch (node->type) {
+      case Node::Type::Var: {
+        std::cout << "%" << indexing[node] << ":" << node->wasmType << " = var";
+        break; // nothing more to add
+      }
+      case Node::Type::Expr: {
+        if (debug()) {
+          std::cout << "; ";
+          WasmPrinter::printExpression(node->expr, std::cout, true);
+          std::cout << '\n';
+        }
+        std::cout << "%" << indexing[node] << " = ";
+        printExpression(node);
+        break;
+      }
+      case Node::Type::Phi: {
+        auto* block = node->getValue(0);
+        auto size = block->values.size();
+        std::cout << "%" << indexing[node] << " = phi %" << indexing[block];
+        for (Index i = 1; i < size + 1; i++) {
+          std::cout << ", ";
+          printInternal(node->getValue(i));
+        }
+        break;
+      }
+      case Node::Type::Cond: {
+        std::cout << "blockpc %" << indexing[node->getValue(0)] << ' '
+                  << node->index << ' ';
+        printInternal(node->getValue(1));
+        std::cout << " 1:i1";
+        break;
+      }
+      case Node::Type::Block: {
+        std::cout << "%" << indexing[node] << " = block "
+                  << node->values.size();
+        break;
+      }
+      case Node::Type::Zext: {
+        auto* child = node->getValue(0);
+        std::cout << "%" << indexing[node] << ':' << child->getWasmType();
+        std::cout << " = zext ";
+        printInternal(child);
+        break;
+      }
+      case Node::Type::Bad: {
+        WASM_UNREACHABLE("!!!BAD!!!");
+      }
+      default:
+        WASM_UNREACHABLE("unexpted type");
+    }
+    if (node->isExpr() || node->isPhi()) {
+      if (node->origin != trace.toInfer->origin &&
+          trace.hasExternalUses.count(node) > 0) {
+        std::cout << " (hasExternalUses)";
+        printedHasExternalUses = true;
+      }
+    }
+    std::cout << '\n';
+    if (debug() && (node->isExpr() || node->isPhi())) {
+      warnOnSuspiciousValues(node);
+    }
+  }
+
+  void print(Literal value) {
+    std::cout << value.getInteger() << ':' << value.type;
+  }
+
+  void printInternal(Node* node) {
+    node = getMaybeReplaced(node);
+    assert(node);
+    if (node->isConst()) {
+      print(node->expr->cast<Const>()->value);
+    } else {
+      std::cout << "%" << indexing[node];
+    }
+  }
+
+  // Emit an expression
+
+  void printExpression(Node* node) {
+    assert(node->isExpr());
+    // TODO use a Visitor here?
+    auto* curr = node->expr;
+    if (auto* c = curr->dynCast<Const>()) {
+      print(c->value);
+    } else if (auto* unary = curr->dynCast<Unary>()) {
+      switch (unary->op) {
+        case ClzInt32:
+        case ClzInt64:
+          std::cout << "ctlz";
+          break;
+        case CtzInt32:
+        case CtzInt64:
+          std::cout << "cttz";
+          break;
+        case PopcntInt32:
+        case PopcntInt64:
+          std::cout << "ctpop";
+          break;
+        default:
+          WASM_UNREACHABLE("invalid op");
+      }
+      std::cout << ' ';
+      auto* value = node->getValue(0);
+      printInternal(value);
+    } else if (auto* binary = curr->dynCast<Binary>()) {
+      switch (binary->op) {
+        case AddInt32:
+        case AddInt64:
+          std::cout << "add";
+          break;
+        case SubInt32:
+        case SubInt64:
+          std::cout << "sub";
+          break;
+        case MulInt32:
+        case MulInt64:
+          std::cout << "mul";
+          break;
+        case DivSInt32:
+        case DivSInt64:
+          std::cout << "sdiv";
+          break;
+        case DivUInt32:
+        case DivUInt64:
+          std::cout << "udiv";
+          break;
+        case RemSInt32:
+        case RemSInt64:
+          std::cout << "srem";
+          break;
+        case RemUInt32:
+        case RemUInt64:
+          std::cout << "urem";
+          break;
+        case AndInt32:
+        case AndInt64:
+          std::cout << "and";
+          break;
+        case OrInt32:
+        case OrInt64:
+          std::cout << "or";
+          break;
+        case XorInt32:
+        case XorInt64:
+          std::cout << "xor";
+          break;
+        case ShlInt32:
+        case ShlInt64:
+          std::cout << "shl";
+          break;
+        case ShrUInt32:
+        case ShrUInt64:
+          std::cout << "lshr";
+          break;
+        case ShrSInt32:
+        case ShrSInt64:
+          std::cout << "ashr";
+          break;
+        case RotLInt32:
+        case RotLInt64:
+          std::cout << "rotl";
+          break;
+        case RotRInt32:
+        case RotRInt64:
+          std::cout << "rotr";
+          break;
+        case EqInt32:
+        case EqInt64:
+          std::cout << "eq";
+          break;
+        case NeInt32:
+        case NeInt64:
+          std::cout << "ne";
+          break;
+        case LtSInt32:
+        case LtSInt64:
+          std::cout << "slt";
+          break;
+        case LtUInt32:
+        case LtUInt64:
+          std::cout << "ult";
+          break;
+        case LeSInt32:
+        case LeSInt64:
+          std::cout << "sle";
+          break;
+        case LeUInt32:
+        case LeUInt64:
+          std::cout << "ule";
+          break;
+        default:
+          WASM_UNREACHABLE("invalid op");
+      }
+      std::cout << ' ';
+      auto* left = node->getValue(0);
+      printInternal(left);
+      std::cout << ", ";
+      auto* right = node->getValue(1);
+      printInternal(right);
+    } else if (curr->is<Select>()) {
+      std::cout << "select ";
+      printInternal(node->getValue(0));
+      std::cout << ", ";
+      printInternal(node->getValue(1));
+      std::cout << ", ";
+      printInternal(node->getValue(2));
+    } else {
+      WASM_UNREACHABLE("unexecpted node type");
+    }
+  }
+
+  void printPathCondition(Node* condition) {
+    std::cout << "pc ";
+    printInternal(condition);
+    std::cout << " 1:i1\n";
+  }
+
+  // Checks if a value looks suspiciously optimizable.
+  void warnOnSuspiciousValues(Node* node) {
+    assert(debug());
+    // If the node has no uses, it's not interesting enough to be
+    // suspicious. TODO
+    // If an input was replaced with a var, then we should not
+    // look into it, it's not suspiciously trivial.
+    for (auto* value : node->values) {
+      if (value != getMaybeReplaced(value)) {
+        return;
+      }
+    }
+    if (allInputsIdentical(node)) {
+      std::cout << "^^ suspicious identical inputs! missing optimization in "
+                << graph.func->name << "? ^^\n";
+      return;
+    }
+    if (!node->isPhi() && allInputsConstant(node)) {
+      std::cout << "^^ suspicious constant inputs! missing optimization in "
+                << graph.func->name << "? ^^\n";
+      return;
+    }
+  }
+};
+
+} // namespace DataFlow
+
+struct Souperify : public WalkerPass<PostWalker<Souperify>> {
+  // Not parallel, for now - could parallelize and combine outputs at the end.
+  // If Souper is thread-safe, we could also run it in parallel.
+
+  bool singleUseOnly;
+
+  Souperify(bool singleUseOnly) : singleUseOnly(singleUseOnly) {}
+
+  void doWalkFunction(Function* func) {
+    std::cout << "\n; function: " << func->name << '\n';
+    Flat::verifyFlatness(func);
+    // Build the data-flow IR.
+    DataFlow::Graph graph;
+    graph.build(func, getModule());
+    if (debug() >= 2) {
+      dump(graph, std::cout);
+    }
+    // Build the local graph data structure.
+    LocalGraph localGraph(func);
+    localGraph.computeInfluences();
+    // If we only want single-use nodes, exclude all the others.
+    std::unordered_set<DataFlow::Node*> excludeAsChildren;
+    if (singleUseOnly) {
+      for (auto& nodePtr : graph.nodes) {
+        auto* node = nodePtr.get();
+        if (node->origin) {
+          // TODO: work for identical origins could be saved
+          auto uses =
+            DataFlow::UseFinder().getUses(node->origin, graph, localGraph);
+          if (debug() >= 2) {
+            std::cout << "following node has " << uses.size() << " uses\n";
+            dump(node, std::cout);
+          }
+          if (uses.size() > 1) {
+            excludeAsChildren.insert(node);
+          }
+        }
+      }
+    }
+    // Emit possible traces.
+    for (auto& nodePtr : graph.nodes) {
+      auto* node = nodePtr.get();
+      // Trace
+      if (DataFlow::Trace::isTraceable(node)) {
+        DataFlow::Trace trace(graph, node, excludeAsChildren, localGraph);
+        if (!trace.isBad()) {
+          DataFlow::Printer printer(graph, trace);
+          if (singleUseOnly) {
+            assert(!printer.printedHasExternalUses);
+          }
+        }
+      }
+    }
+  }
+};
+
+Pass* createSouperifyPass() { return new Souperify(false); }
+
+Pass* createSouperifySingleUsePass() { return new Souperify(true); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/SpillPointers.cpp b/binaryen/src/passes/SpillPointers.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/SpillPointers.cpp
@@ -0,0 +1,206 @@
+/*
+ * 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
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/StackCheck.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+//
+// Enforce stack pointer limits.  This pass will add checks around all
+// assignments to the __stack_pointer global that LLVM uses for its
+// shadow stack.
+//
+
+#include "abi/js.h"
+#include "ir/import-utils.h"
+#include "pass.h"
+#include "shared-constants.h"
+#include "support/debug.h"
+#include "wasm-emscripten.h"
+
+#define DEBUG_TYPE "stack-check"
+
+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");
+
+static void importStackOverflowHandler(Module& module, Name name) {
+  ImportInfo info(module);
+
+  if (!info.getImportedFunction(ENV, name)) {
+    auto* import = new Function;
+    import->name = name;
+    import->module = ENV;
+    import->base = name;
+    import->sig = Signature(Type::none, Type::none);
+    module.addFunction(import);
+  }
+}
+
+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);
+}
+
+struct EnforceStackLimits : public WalkerPass<PostWalker<EnforceStackLimits>> {
+  EnforceStackLimits(Global* stackPointer,
+                     Global* stackBase,
+                     Global* stackLimit,
+                     Builder& builder,
+                     Name handler)
+    : stackPointer(stackPointer), stackBase(stackBase), stackLimit(stackLimit),
+      builder(builder), handler(handler) {}
+
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override {
+    return new EnforceStackLimits(
+      stackPointer, stackBase, stackLimit, builder, handler);
+  }
+
+  Expression* stackBoundsCheck(Function* func, Expression* value) {
+    // Add a local to store the value of the expression. We need the value
+    // twice: once to check if it has overflowed, and again to assign to store
+    // it.
+    auto newSP = Builder::addVar(func, stackPointer->type);
+    // If we imported a handler, call it. That can show a nice error in JS.
+    // Otherwise, just trap.
+    Expression* handlerExpr;
+    if (handler.is()) {
+      handlerExpr = builder.makeCall(handler, {}, Type::none);
+    } else {
+      handlerExpr = builder.makeUnreachable();
+    }
+    // If it is >= the base or <= the limit, then error.
+    auto check = builder.makeIf(
+      builder.makeBinary(
+        BinaryOp::OrInt32,
+        builder.makeBinary(
+          BinaryOp::GtUInt32,
+          builder.makeLocalTee(newSP, value, stackPointer->type),
+          builder.makeGlobalGet(stackBase->name, stackBase->type)),
+        builder.makeBinary(
+          BinaryOp::LtUInt32,
+          builder.makeLocalGet(newSP, stackPointer->type),
+          builder.makeGlobalGet(stackLimit->name, stackLimit->type))),
+      handlerExpr);
+    // (global.set $__stack_pointer (local.get $newSP))
+    auto newSet = builder.makeGlobalSet(
+      stackPointer->name, builder.makeLocalGet(newSP, stackPointer->type));
+    return builder.blockify(check, newSet);
+  }
+
+  void visitGlobalSet(GlobalSet* curr) {
+    if (getModule()->getGlobalOrNull(curr->name) == stackPointer) {
+      replaceCurrent(stackBoundsCheck(getFunction(), curr->value));
+    }
+  }
+
+private:
+  Global* stackPointer;
+  Global* stackBase;
+  Global* stackLimit;
+  Builder& builder;
+  Name handler;
+};
+
+struct StackCheck : public Pass {
+  void run(PassRunner* runner, Module* module) override {
+    Global* stackPointer = getStackPointerGlobal(*module);
+    if (!stackPointer) {
+      BYN_DEBUG(std::cerr << "no stack pointer found\n");
+      return;
+    }
+
+    Name handler;
+    auto handlerName =
+      runner->options.getArgumentOrDefault("stack-check-handler", "");
+    if (handlerName != "") {
+      handler = handlerName;
+      importStackOverflowHandler(*module, handler);
+    }
+
+    Builder builder(*module);
+    Global* stackBase = builder.makeGlobal(STACK_BASE,
+                                           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);
+
+    PassRunner innerRunner(module);
+    EnforceStackLimits(stackPointer, stackBase, stackLimit, builder, handler)
+      .run(&innerRunner, module);
+    generateSetStackLimitFunctions(*module);
+  }
+};
+
+Pass* createStackCheckPass() { return new StackCheck; }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/StackIR.cpp b/binaryen/src/passes/StackIR.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/StackIR.cpp
@@ -0,0 +1,346 @@
+/*
+ * 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.
+ */
+
+//
+// Operations on Stack IR.
+//
+
+#include "ir/iteration.h"
+#include "ir/local-graph.h"
+#include "pass.h"
+#include "wasm-stack.h"
+#include "wasm.h"
+
+namespace wasm {
+
+// Generate Stack IR from Binaryen IR
+
+struct GenerateStackIR : public WalkerPass<PostWalker<GenerateStackIR>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new GenerateStackIR; }
+
+  bool modifiesBinaryenIR() override { return false; }
+
+  void doWalkFunction(Function* func) {
+    StackIRGenerator stackIRGen(*getModule(), func);
+    stackIRGen.write();
+    func->stackIR = make_unique<StackIR>();
+    func->stackIR->swap(stackIRGen.getStackIR());
+  }
+};
+
+Pass* createGenerateStackIRPass() { return new GenerateStackIR(); }
+
+// Optimize
+
+class StackIROptimizer {
+  Function* func;
+  PassOptions& passOptions;
+  StackIR& insts;
+
+public:
+  StackIROptimizer(Function* func, PassOptions& passOptions)
+    : func(func), passOptions(passOptions), insts(*func->stackIR.get()) {
+    assert(func->stackIR);
+  }
+
+  void run() {
+    dce();
+    // FIXME: local2Stack is currently rather slow (due to localGraph),
+    //        so for now run it only when really optimizing
+    if (passOptions.optimizeLevel >= 3 || passOptions.shrinkLevel >= 1) {
+      local2Stack();
+    }
+    removeUnneededBlocks();
+    dce();
+  }
+
+private:
+  // Passes.
+
+  // Remove unreachable code.
+  void dce() {
+    bool inUnreachableCode = false;
+    for (Index i = 0; i < insts.size(); i++) {
+      auto* inst = insts[i];
+      if (!inst) {
+        continue;
+      }
+      if (inUnreachableCode) {
+        // Does the unreachable code end here?
+        if (isControlFlowBarrier(inst)) {
+          inUnreachableCode = false;
+        } else {
+          // We can remove this.
+          removeAt(i);
+        }
+      } else if (inst->type == Type::unreachable) {
+        inUnreachableCode = true;
+      }
+    }
+  }
+
+  // If ordered properly, we can avoid a local.set/local.get pair,
+  // and use the value directly from the stack, for example
+  //    [..produce a value on the stack..]
+  //    local.set $x
+  //    [..much code..]
+  //    local.get $x
+  //    call $foo ;; use the value, foo(value)
+  // As long as the code in between does not modify $x, and has
+  // no control flow branching out, we can remove both the set
+  // and the get.
+  void local2Stack() {
+    // We use the localGraph to tell us if a get-set pair is indeed
+    // a set that is read by that get, and only that get. Note that we run
+    // this on the Binaryen IR, so we are assuming that no previous opt
+    // has changed the interaction of local operations.
+    // TODO: we can do this a lot faster, as we just care about linear
+    //       control flow.
+    LocalGraph localGraph(func);
+    localGraph.computeInfluences();
+    // We maintain a stack of relevant values. This contains:
+    //  * a null for each actual value that the value stack would have
+    //  * an index of each LocalSet that *could* be on the value
+    //    stack at that location.
+    const Index null = -1;
+    std::vector<Index> values;
+    // We also maintain a stack of values vectors for control flow,
+    // saving the stack as we enter and restoring it when we exit.
+    std::vector<std::vector<Index>> savedValues;
+#ifdef STACK_OPT_DEBUG
+    std::cout << "func: " << func->name << '\n' << insts << '\n';
+#endif
+    for (Index i = 0; i < insts.size(); i++) {
+      auto* inst = insts[i];
+      if (!inst) {
+        continue;
+      }
+      // First, consume values from the stack as required.
+      auto consumed = getNumConsumedValues(inst);
+#ifdef STACK_OPT_DEBUG
+      std::cout << "  " << i << " : " << *inst << ", " << values.size()
+                << " on stack, will consume " << consumed << "\n    ";
+      for (auto s : values)
+        std::cout << s << ' ';
+      std::cout << '\n';
+#endif
+      // TODO: currently we run dce before this, but if we didn't, we'd need
+      //       to handle unreachable code here - it's ok to pop multiple values
+      //       there even if the stack is at size 0.
+      while (consumed > 0) {
+        assert(values.size() > 0);
+        // Whenever we hit a possible stack value, kill it - it would
+        // be consumed here, so we can never optimize to it.
+        while (values.back() != null) {
+          values.pop_back();
+          assert(values.size() > 0);
+        }
+        // Finally, consume the actual value that is consumed here.
+        values.pop_back();
+        consumed--;
+      }
+      // After consuming, we can see what to do with this. First, handle
+      // control flow.
+      if (isControlFlowBegin(inst)) {
+        // Save the stack for when we end this control flow.
+        savedValues.push_back(values); // TODO: optimize copies
+        values.clear();
+      } else if (isControlFlowEnd(inst)) {
+        assert(!savedValues.empty());
+        values = savedValues.back();
+        savedValues.pop_back();
+      } else if (isControlFlow(inst)) {
+        // Otherwise, in the middle of control flow, just clear it
+        values.clear();
+      }
+      // This is something we should handle, look into it.
+      if (inst->type.isConcrete()) {
+        bool optimized = false;
+        if (auto* get = inst->origin->dynCast<LocalGet>()) {
+          // This is a potential optimization opportunity! See if we
+          // can reach the set.
+          if (values.size() > 0) {
+            Index j = values.size() - 1;
+            while (1) {
+              // If there's an actual value in the way, we've failed.
+              auto index = values[j];
+              if (index == null) {
+                break;
+              }
+              auto* set = insts[index]->origin->cast<LocalSet>();
+              if (set->index == get->index) {
+                // This might be a proper set-get pair, where the set is
+                // used by this get and nothing else, check that.
+                auto& sets = localGraph.getSetses[get];
+                if (sets.size() == 1 && *sets.begin() == set) {
+                  auto& setInfluences = localGraph.setInfluences[set];
+                  if (setInfluences.size() == 1) {
+                    assert(*setInfluences.begin() == get);
+                    // Do it! The set and the get can go away, the proper
+                    // value is on the stack.
+#ifdef STACK_OPT_DEBUG
+                    std::cout << "  stackify the get\n";
+#endif
+                    insts[index] = nullptr;
+                    insts[i] = nullptr;
+                    // Continuing on from here, replace this on the stack
+                    // with a null, representing a regular value. We
+                    // keep possible values above us active - they may
+                    // be optimized later, as they would be pushed after
+                    // us, and used before us, so there is no conflict.
+                    values[j] = null;
+                    optimized = true;
+                    break;
+                  }
+                }
+              }
+              // We failed here. Can we look some more?
+              if (j == 0) {
+                break;
+              }
+              j--;
+            }
+          }
+        }
+        if (!optimized) {
+          // This is an actual regular value on the value stack.
+          values.push_back(null);
+        }
+      } else if (inst->origin->is<LocalSet>() && inst->type == Type::none) {
+        // This set is potentially optimizable later, add to stack.
+        values.push_back(i);
+      }
+    }
+  }
+
+  // There may be unnecessary blocks we can remove: blocks
+  // without branches to them are always ok to remove.
+  // TODO: a branch to a block in an if body can become
+  //       a branch to that if body
+  void removeUnneededBlocks() {
+    for (auto*& inst : insts) {
+      if (!inst) {
+        continue;
+      }
+      if (auto* block = inst->origin->dynCast<Block>()) {
+        if (!BranchUtils::BranchSeeker::has(block, block->name)) {
+          // TODO optimize, maybe run remove-unused-names
+          inst = nullptr;
+        }
+      }
+    }
+  }
+
+  // Utilities.
+
+  // A control flow "barrier" - a point where stack machine
+  // unreachability ends.
+  bool isControlFlowBarrier(StackInst* inst) {
+    switch (inst->op) {
+      case StackInst::BlockEnd:
+      case StackInst::IfElse:
+      case StackInst::IfEnd:
+      case StackInst::LoopEnd:
+      case StackInst::Catch:
+      case StackInst::TryEnd: {
+        return true;
+      }
+      default: { return false; }
+    }
+  }
+
+  // A control flow beginning.
+  bool isControlFlowBegin(StackInst* inst) {
+    switch (inst->op) {
+      case StackInst::BlockBegin:
+      case StackInst::IfBegin:
+      case StackInst::LoopBegin:
+      case StackInst::TryBegin: {
+        return true;
+      }
+      default: { return false; }
+    }
+  }
+
+  // A control flow ending.
+  bool isControlFlowEnd(StackInst* inst) {
+    switch (inst->op) {
+      case StackInst::BlockEnd:
+      case StackInst::IfEnd:
+      case StackInst::LoopEnd:
+      case StackInst::TryEnd: {
+        return true;
+      }
+      default: { return false; }
+    }
+  }
+
+  bool isControlFlow(StackInst* inst) { return inst->op != StackInst::Basic; }
+
+  // Remove the instruction at index i. If the instruction
+  // is control flow, and so has been expanded to multiple
+  // instructions, remove them as well.
+  void removeAt(Index i) {
+    auto* inst = insts[i];
+    insts[i] = nullptr;
+    if (inst->op == StackInst::Basic) {
+      return; // that was it
+    }
+    auto* origin = inst->origin;
+    while (1) {
+      i++;
+      assert(i < insts.size());
+      inst = insts[i];
+      insts[i] = nullptr;
+      if (inst && inst->origin == origin && isControlFlowEnd(inst)) {
+        return; // that's it, we removed it all
+      }
+    }
+  }
+
+  Index getNumConsumedValues(StackInst* inst) {
+    if (isControlFlow(inst)) {
+      // If consumes 1; that's it.
+      if (inst->op == StackInst::IfBegin) {
+        return 1;
+      }
+      return 0;
+    }
+    // Otherwise, for basic instructions, just count the expression children.
+    return ChildIterator(inst->origin).children.size();
+  }
+};
+
+struct OptimizeStackIR : public WalkerPass<PostWalker<OptimizeStackIR>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new OptimizeStackIR; }
+
+  bool modifiesBinaryenIR() override { return false; }
+
+  void doWalkFunction(Function* func) {
+    if (!func->stackIR) {
+      return;
+    }
+    StackIROptimizer(func, getPassOptions()).run();
+  }
+};
+
+Pass* createOptimizeStackIRPass() { return new OptimizeStackIR(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/Strip.cpp b/binaryen/src/passes/Strip.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/Strip.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+//
+// Similar to strip-ing a native binary, this family of passes can
+// removes debug info and other things.
+//
+
+#include <functional>
+
+#include "pass.h"
+#include "wasm-binary.h"
+#include "wasm.h"
+
+using namespace std;
+
+namespace wasm {
+
+struct Strip : public Pass {
+  // A function that returns true if the method should be removed.
+  typedef std::function<bool(UserSection&)> Decider;
+  Decider decider;
+
+  Strip(Decider decider) : decider(decider) {}
+
+  void run(PassRunner* runner, Module* module) override {
+    // Remove name and debug sections.
+    auto& sections = module->userSections;
+    sections.erase(std::remove_if(sections.begin(), sections.end(), decider),
+                   sections.end());
+    // If we're cleaning up debug info, clear on the function and module too.
+    UserSection temp;
+    temp.name = BinaryConsts::UserSections::Name;
+    if (decider(temp)) {
+      module->clearDebugInfo();
+      for (auto& func : module->functions) {
+        func->clearNames();
+        func->clearDebugInfo();
+      }
+    }
+  }
+};
+
+Pass* createStripDebugPass() {
+  return new Strip([&](const UserSection& curr) {
+    return curr.name == BinaryConsts::UserSections::Name ||
+           curr.name == BinaryConsts::UserSections::SourceMapUrl ||
+           curr.name.find(".debug") == 0 || curr.name.find("reloc..debug") == 0;
+  });
+}
+
+Pass* createStripDWARFPass() {
+  return new Strip([&](const UserSection& curr) {
+    return curr.name.find(".debug") == 0 || curr.name.find("reloc..debug") == 0;
+  });
+}
+
+Pass* createStripProducersPass() {
+  return new Strip([&](const UserSection& curr) {
+    return curr.name == BinaryConsts::UserSections::Producers;
+  });
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/StripTargetFeatures.cpp b/binaryen/src/passes/StripTargetFeatures.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/StripTargetFeatures.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "pass.h"
+
+namespace wasm {
+
+struct StripTargetFeatures : public Pass {
+  bool isStripped = false;
+  StripTargetFeatures(bool isStripped) : isStripped(isStripped) {}
+  void run(PassRunner* runner, Module* module) override {
+    module->hasFeaturesSection = !isStripped;
+  }
+};
+
+Pass* createStripTargetFeaturesPass() { return new StripTargetFeatures(true); }
+Pass* createEmitTargetFeaturesPass() { return new StripTargetFeatures(false); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/TrapMode.cpp b/binaryen/src/passes/TrapMode.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/TrapMode.cpp
@@ -0,0 +1,327 @@
+/*
+ * 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.
+ */
+
+//
+// Pass that supports potentially-trapping wasm operations.
+// For example, integer division traps when dividing by zero, so this pass
+// 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"
+
+namespace wasm {
+
+Name I64S_REM("i64s-rem");
+Name I64U_REM("i64u-rem");
+Name I64S_DIV("i64s-div");
+Name I64U_DIV("i64u-div");
+
+Name getBinaryFuncName(Binary* curr) {
+  switch (curr->op) {
+    case RemSInt32:
+      return I32S_REM;
+    case RemUInt32:
+      return I32U_REM;
+    case DivSInt32:
+      return I32S_DIV;
+    case DivUInt32:
+      return I32U_DIV;
+    case RemSInt64:
+      return I64S_REM;
+    case RemUInt64:
+      return I64U_REM;
+    case DivSInt64:
+      return I64S_DIV;
+    case DivUInt64:
+      return I64U_DIV;
+    default:
+      return Name();
+  }
+}
+
+Name getUnaryFuncName(Unary* curr) {
+  switch (curr->op) {
+    case TruncSFloat32ToInt32:
+      return F32_TO_INT;
+    case TruncUFloat32ToInt32:
+      return F32_TO_UINT;
+    case TruncSFloat32ToInt64:
+      return F32_TO_INT64;
+    case TruncUFloat32ToInt64:
+      return F32_TO_UINT64;
+    case TruncSFloat64ToInt32:
+      return F64_TO_INT;
+    case TruncUFloat64ToInt32:
+      return F64_TO_UINT;
+    case TruncSFloat64ToInt64:
+      return F64_TO_INT64;
+    case TruncUFloat64ToInt64:
+      return F64_TO_UINT64;
+    default:
+      return Name();
+  }
+}
+
+bool isTruncOpSigned(UnaryOp op) {
+  switch (op) {
+    case TruncUFloat32ToInt32:
+    case TruncUFloat32ToInt64:
+    case TruncUFloat64ToInt32:
+    case TruncUFloat64ToInt64:
+      return false;
+    default:
+      return true;
+  }
+}
+
+Function* generateBinaryFunc(Module& wasm, Binary* curr) {
+  BinaryOp op = curr->op;
+  Type type = curr->type;
+  bool isI64 = type == Type::i64;
+  Builder builder(wasm);
+  Expression* result = builder.makeBinary(
+    op, builder.makeLocalGet(0, type), builder.makeLocalGet(1, type));
+  BinaryOp divSIntOp = isI64 ? DivSInt64 : DivSInt32;
+  UnaryOp eqZOp = isI64 ? EqZInt64 : EqZInt32;
+  Literal minLit = isI64 ? Literal(std::numeric_limits<int64_t>::min())
+                         : Literal(std::numeric_limits<int32_t>::min());
+  Literal zeroLit = isI64 ? Literal(int64_t(0)) : Literal(int32_t(0));
+  if (op == divSIntOp) {
+    // guard against signed division overflow
+    BinaryOp eqOp = isI64 ? EqInt64 : EqInt32;
+    Literal negLit = isI64 ? Literal(int64_t(-1)) : Literal(int32_t(-1));
+    result = builder.makeIf(
+      builder.makeBinary(
+        AndInt32,
+        builder.makeBinary(
+          eqOp, builder.makeLocalGet(0, type), builder.makeConst(minLit)),
+        builder.makeBinary(
+          eqOp, builder.makeLocalGet(1, type), builder.makeConst(negLit))),
+      builder.makeConst(zeroLit),
+      result);
+  }
+  auto func = new Function;
+  func->name = getBinaryFuncName(curr);
+  func->sig = Signature({type, type}, type);
+  func->body =
+    builder.makeIf(builder.makeUnary(eqZOp, builder.makeLocalGet(1, type)),
+                   builder.makeConst(zeroLit),
+                   result);
+  return func;
+}
+
+template<typename IntType, typename FloatType>
+void makeClampLimitLiterals(Literal& iMin, Literal& fMin, Literal& fMax) {
+  IntType minVal = std::numeric_limits<IntType>::min();
+  IntType maxVal = std::numeric_limits<IntType>::max();
+  iMin = Literal(minVal);
+  fMin = Literal(FloatType(minVal) - 1);
+  fMax = Literal(FloatType(maxVal) + 1);
+}
+
+Function* generateUnaryFunc(Module& wasm, Unary* curr) {
+  Type type = curr->value->type;
+  Type retType = curr->type;
+  UnaryOp truncOp = curr->op;
+  bool isF64 = type == Type::f64;
+
+  Builder builder(wasm);
+
+  BinaryOp leOp = isF64 ? LeFloat64 : LeFloat32;
+  BinaryOp geOp = isF64 ? GeFloat64 : GeFloat32;
+  BinaryOp neOp = isF64 ? NeFloat64 : NeFloat32;
+
+  Literal iMin, fMin, fMax;
+  switch (truncOp) {
+    case TruncSFloat32ToInt32:
+      makeClampLimitLiterals<int32_t, float>(iMin, fMin, fMax);
+      break;
+    case TruncUFloat32ToInt32:
+      makeClampLimitLiterals<uint32_t, float>(iMin, fMin, fMax);
+      break;
+    case TruncSFloat32ToInt64:
+      makeClampLimitLiterals<int64_t, float>(iMin, fMin, fMax);
+      break;
+    case TruncUFloat32ToInt64:
+      makeClampLimitLiterals<uint64_t, float>(iMin, fMin, fMax);
+      break;
+    case TruncSFloat64ToInt32:
+      makeClampLimitLiterals<int32_t, double>(iMin, fMin, fMax);
+      break;
+    case TruncUFloat64ToInt32:
+      makeClampLimitLiterals<uint32_t, double>(iMin, fMin, fMax);
+      break;
+    case TruncSFloat64ToInt64:
+      makeClampLimitLiterals<int64_t, double>(iMin, fMin, fMax);
+      break;
+    case TruncUFloat64ToInt64:
+      makeClampLimitLiterals<uint64_t, double>(iMin, fMin, fMax);
+      break;
+    default:
+      WASM_UNREACHABLE("unexpected op");
+  }
+
+  auto func = new Function;
+  func->name = getUnaryFuncName(curr);
+  func->sig = Signature(type, retType);
+  func->body = builder.makeUnary(truncOp, builder.makeLocalGet(0, type));
+  // too small XXX this is different than asm.js, which does frem. here we
+  // clamp, which is much simpler/faster, and similar to native builds
+  func->body = builder.makeIf(builder.makeBinary(leOp,
+                                                 builder.makeLocalGet(0, type),
+                                                 builder.makeConst(fMin)),
+                              builder.makeConst(iMin),
+                              func->body);
+  // too big XXX see above
+  func->body = builder.makeIf(
+    builder.makeBinary(
+      geOp, builder.makeLocalGet(0, type), builder.makeConst(fMax)),
+    // NB: min here as well. anything out of range => to the min
+    builder.makeConst(iMin),
+    func->body);
+  // nan
+  func->body = builder.makeIf(
+    builder.makeBinary(
+      neOp, builder.makeLocalGet(0, type), builder.makeLocalGet(0, type)),
+    // NB: min here as well. anything invalid => to the min
+    builder.makeConst(iMin),
+    func->body);
+  return func;
+}
+
+void ensureBinaryFunc(Binary* curr,
+                      Module& wasm,
+                      TrappingFunctionContainer& trappingFunctions) {
+  Name name = getBinaryFuncName(curr);
+  if (trappingFunctions.hasFunction(name)) {
+    return;
+  }
+  trappingFunctions.addFunction(generateBinaryFunc(wasm, curr));
+}
+
+void ensureUnaryFunc(Unary* curr,
+                     Module& wasm,
+                     TrappingFunctionContainer& trappingFunctions) {
+  Name name = getUnaryFuncName(curr);
+  if (trappingFunctions.hasFunction(name)) {
+    return;
+  }
+  trappingFunctions.addFunction(generateUnaryFunc(wasm, curr));
+}
+
+void ensureF64ToI64JSImport(TrappingFunctionContainer& trappingFunctions) {
+  if (trappingFunctions.hasImport(F64_TO_INT)) {
+    return;
+  }
+
+  // f64-to-int = asm2wasm.f64-to-int;
+  auto import = new Function;
+  import->name = F64_TO_INT;
+  import->module = ASM2WASM;
+  import->base = F64_TO_INT;
+  import->sig = Signature(Type::f64, Type::i32);
+  trappingFunctions.addImport(import);
+}
+
+Expression* makeTrappingBinary(Binary* curr,
+                               TrappingFunctionContainer& trappingFunctions) {
+  Name name = getBinaryFuncName(curr);
+  if (!name.is() || trappingFunctions.getMode() == TrapMode::Allow) {
+    return curr;
+  }
+
+  // the wasm operation might trap if done over 0, so generate a safe call
+  Type type = curr->type;
+  Module& wasm = trappingFunctions.getModule();
+  Builder builder(wasm);
+  ensureBinaryFunc(curr, wasm, trappingFunctions);
+  return builder.makeCall(name, {curr->left, curr->right}, type);
+}
+
+Expression* makeTrappingUnary(Unary* curr,
+                              TrappingFunctionContainer& trappingFunctions) {
+  Name name = getUnaryFuncName(curr);
+  TrapMode mode = trappingFunctions.getMode();
+  if (!name.is() || mode == TrapMode::Allow) {
+    return curr;
+  }
+
+  Module& wasm = trappingFunctions.getModule();
+  Builder builder(wasm);
+  // WebAssembly traps on float-to-int overflows, but asm.js wouldn't, so we
+  // must do something We can handle this in one of two ways: clamping, which is
+  // fast, or JS, which is precisely like JS but in order to do that we do a
+  // slow ffi If i64, there is no "JS" way to handle this, as no i64s in JS, so
+  // always clamp if we don't allow traps asm.js doesn't have unsigned
+  // f64-to-int, so just use the signed one.
+  if (curr->type != Type::i64 && mode == TrapMode::JS) {
+    // WebAssembly traps on float-to-int overflows, but asm.js wouldn't, so we
+    // must emulate that
+    ensureF64ToI64JSImport(trappingFunctions);
+    Expression* f64Value = ensureDouble(curr->value, wasm.allocator);
+    return builder.makeCall(F64_TO_INT, {f64Value}, Type::i32);
+  }
+
+  ensureUnaryFunc(curr, wasm, trappingFunctions);
+  return builder.makeCall(name, {curr->value}, curr->type);
+}
+
+struct TrapModePass : public WalkerPass<PostWalker<TrapModePass>> {
+public:
+  // Needs to be non-parallel so that visitModule gets called after visiting
+  // each node in the module, so we can add the functions that we created.
+  bool isFunctionParallel() override { return false; }
+
+  TrapModePass(TrapMode mode) : mode(mode) { assert(mode != TrapMode::Allow); }
+
+  Pass* create() override { return new TrapModePass(mode); }
+
+  void visitUnary(Unary* curr) {
+    replaceCurrent(makeTrappingUnary(curr, *trappingFunctions));
+  }
+
+  void visitBinary(Binary* curr) {
+    replaceCurrent(makeTrappingBinary(curr, *trappingFunctions));
+  }
+
+  void visitModule(Module* curr) { trappingFunctions->addToModule(); }
+
+  void doWalkModule(Module* module) {
+    trappingFunctions = make_unique<TrappingFunctionContainer>(mode, *module);
+    super::doWalkModule(module);
+  }
+
+private:
+  TrapMode mode;
+  // Need to defer adding generated functions because adding functions while
+  // iterating over existing functions causes problems.
+  std::unique_ptr<TrappingFunctionContainer> trappingFunctions;
+};
+
+Pass* createTrapModeClamp() { return new TrapModePass(TrapMode::Clamp); }
+
+Pass* createTrapModeJS() { return new TrapModePass(TrapMode::JS); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/Untee.cpp b/binaryen/src/passes/Untee.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/Untee.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+//
+// Removes local.tees, replacing them with gets and sets.
+//
+// This makes the code "flatter", with less nested side
+// effects. That can make some passes, like CodePushing,
+// more effective.
+//
+
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+namespace wasm {
+
+struct Untee : public WalkerPass<PostWalker<Untee>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new Untee; }
+
+  void visitLocalSet(LocalSet* curr) {
+    if (curr->isTee()) {
+      if (curr->value->type == Type::unreachable) {
+        // we don't reach the tee, just remove it
+        replaceCurrent(curr->value);
+      } else {
+        // a normal tee. replace with set and get
+        Builder builder(*getModule());
+        LocalGet* get = builder.makeLocalGet(
+          curr->index, getFunction()->getLocalType(curr->index));
+        replaceCurrent(builder.makeSequence(curr, get));
+        curr->makeSet();
+      }
+    }
+  }
+};
+
+Pass* createUnteePass() { return new Untee(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/Vacuum.cpp b/binaryen/src/passes/Vacuum.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/Vacuum.cpp
@@ -0,0 +1,449 @@
+/*
+ * 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.
+ */
+
+//
+// Removes obviously unneeded code
+//
+
+#include <ir/block-utils.h>
+#include <ir/effects.h>
+#include <ir/literal-utils.h>
+#include <ir/type-updating.h>
+#include <ir/utils.h>
+#include <pass.h>
+#include <wasm-builder.h>
+#include <wasm.h>
+
+namespace wasm {
+
+struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new Vacuum; }
+
+  TypeUpdater typeUpdater;
+
+  Expression* replaceCurrent(Expression* expression) {
+    auto* old = getCurrent();
+    super::replaceCurrent(expression);
+    // also update the type updater
+    typeUpdater.noteReplacement(old, expression);
+    return expression;
+  }
+
+  void doWalkFunction(Function* func) {
+    typeUpdater.walk(func->body);
+    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:
+  //  * The result may be used or unused.
+  //  * The type may or may not matter (a drop can drop anything, for example).
+  Expression* optimize(Expression* curr, bool resultUsed, bool typeMatters) {
+    FeatureSet features = getModule()->features;
+    auto type = curr->type;
+    // An unreachable node must not be changed.
+    if (type == Type::unreachable) {
+      return curr;
+    }
+    // We iterate on possible replacements. If a replacement changes the type,
+    // stop and go back.
+    auto* prev = curr;
+    while (1) {
+      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;
+                }
+              }
+            }
+          }
+        }
+
+        default:
+          return curr; // assume needed
+      }
+    }
+  }
+
+  void visitBlock(Block* curr) {
+    // compress out nops and other dead code
+    int skip = 0;
+    auto& list = curr->list;
+    size_t size = list.size();
+    for (size_t z = 0; z < size; z++) {
+      auto* child = list[z];
+      // The last element may be used.
+      bool used =
+        z == size - 1 && curr->type.isConcrete() &&
+        ExpressionAnalyzer::isResultUsed(expressionStack, getFunction());
+      auto* optimized = optimize(child, used, true);
+      if (!optimized) {
+        if (child->type.isConcrete()) {
+          // We can't just skip a final concrete element, even if it isn't used.
+          // Instead, replace it with something that's easy to optimize out (for
+          // example, code-folding can merge out identical zeros at the end of
+          // if arms).
+          optimized = LiteralUtils::makeZero(child->type, *getModule());
+        } else if (child->type == Type::unreachable) {
+          // Don't try to optimize out an unreachable child (dce can do that
+          // properly).
+          optimized = child;
+        }
+      }
+      if (!optimized) {
+        typeUpdater.noteRecursiveRemoval(child);
+        skip++;
+      } else {
+        if (optimized != child) {
+          typeUpdater.noteReplacement(child, optimized);
+          list[z] = optimized;
+        }
+        if (skip > 0) {
+          list[z - skip] = list[z];
+          list[z] = nullptr;
+        }
+        // if this is unreachable, the rest is dead code
+        if (list[z - skip]->type == Type::unreachable && z < size - 1) {
+          for (Index i = z - skip + 1; i < list.size(); i++) {
+            auto* remove = list[i];
+            if (remove) {
+              typeUpdater.noteRecursiveRemoval(remove);
+            }
+          }
+          list.resize(z - skip + 1);
+          typeUpdater.maybeUpdateTypeToUnreachable(curr);
+          skip = 0; // nothing more to do on the list
+          break;
+        }
+      }
+    }
+    if (skip > 0) {
+      list.resize(size - skip);
+      typeUpdater.maybeUpdateTypeToUnreachable(curr);
+    }
+    // the block may now be a trivial one that we can get rid of and just leave
+    // its contents
+    replaceCurrent(BlockUtils::simplifyToContents(curr, this));
+  }
+
+  void visitIf(If* curr) {
+    // if the condition is a constant, just apply it
+    // we can just return the ifTrue or ifFalse.
+    if (auto* value = curr->condition->dynCast<Const>()) {
+      Expression* child;
+      if (value->value.getInteger()) {
+        child = curr->ifTrue;
+        if (curr->ifFalse) {
+          typeUpdater.noteRecursiveRemoval(curr->ifFalse);
+        }
+      } else {
+        if (curr->ifFalse) {
+          child = curr->ifFalse;
+          typeUpdater.noteRecursiveRemoval(curr->ifTrue);
+        } else {
+          typeUpdater.noteRecursiveRemoval(curr);
+          ExpressionManipulator::nop(curr);
+          return;
+        }
+      }
+      replaceCurrent(child);
+      return;
+    }
+    // if the condition is unreachable, just return it
+    if (curr->condition->type == Type::unreachable) {
+      typeUpdater.noteRecursiveRemoval(curr->ifTrue);
+      if (curr->ifFalse) {
+        typeUpdater.noteRecursiveRemoval(curr->ifFalse);
+      }
+      replaceCurrent(curr->condition);
+      return;
+    }
+    // from here on, we can assume the condition executed
+    if (curr->ifFalse) {
+      if (curr->ifFalse->is<Nop>()) {
+        curr->ifFalse = nullptr;
+      } else if (curr->ifTrue->is<Nop>()) {
+        curr->ifTrue = curr->ifFalse;
+        curr->ifFalse = nullptr;
+        curr->condition =
+          Builder(*getModule()).makeUnary(EqZInt32, curr->condition);
+      } else if (curr->ifTrue->is<Drop>() && curr->ifFalse->is<Drop>()) {
+        // instead of dropping both sides, drop the if, if they are the same
+        // type
+        auto* left = curr->ifTrue->cast<Drop>()->value;
+        auto* right = curr->ifFalse->cast<Drop>()->value;
+        if (left->type == right->type) {
+          curr->ifTrue = left;
+          curr->ifFalse = right;
+          curr->finalize();
+          replaceCurrent(Builder(*getModule()).makeDrop(curr));
+        }
+      }
+    } else {
+      // no else
+      if (curr->ifTrue->is<Nop>()) {
+        // no nothing
+        replaceCurrent(Builder(*getModule()).makeDrop(curr->condition));
+      }
+    }
+  }
+
+  void visitLoop(Loop* curr) {
+    if (curr->body->is<Nop>()) {
+      ExpressionManipulator::nop(curr);
+    }
+  }
+
+  void visitDrop(Drop* curr) {
+    // optimize the dropped value, maybe leaving nothing
+    curr->value = optimize(curr->value, false, false);
+    if (curr->value == nullptr) {
+      ExpressionManipulator::nop(curr);
+      return;
+    }
+    // a drop of a tee is a set
+    if (auto* set = curr->value->dynCast<LocalSet>()) {
+      assert(set->isTee());
+      set->makeSet();
+      replaceCurrent(set);
+      return;
+    }
+    // if we are dropping a block's return value, we might be able to remove it
+    // entirely
+    if (auto* block = curr->value->dynCast<Block>()) {
+      auto* last = block->list.back();
+      // note that the last element may be concrete but not the block, if the
+      // block has an unreachable element in the middle, making the block
+      // unreachable despite later elements and in particular the last
+      if (last->type.isConcrete() && block->type == last->type) {
+        last = optimize(last, false, false);
+        if (!last) {
+          // we may be able to remove this, if there are no brs
+          bool canPop = true;
+          if (block->name.is()) {
+            BranchUtils::BranchSeeker seeker(block->name);
+            Expression* temp = block;
+            seeker.walk(temp);
+            if (seeker.found && seeker.valueType != Type::none) {
+              canPop = false;
+            }
+          }
+          if (canPop) {
+            block->list.back() = last;
+            block->list.pop_back();
+            block->type = Type::none;
+            // we don't need the drop anymore, let's see what we have left in
+            // the block
+            if (block->list.size() > 1) {
+              replaceCurrent(block);
+            } else if (block->list.size() == 1) {
+              replaceCurrent(block->list[0]);
+            } else {
+              ExpressionManipulator::nop(curr);
+            }
+            return;
+          }
+        }
+      }
+    }
+    // sink a drop into an arm of an if-else if the other arm ends in an
+    // unreachable, as it if is a branch, this can make that branch optimizable
+    // and more vaccuming possible
+    auto* iff = curr->value->dynCast<If>();
+    if (iff && iff->ifFalse && iff->type.isConcrete()) {
+      // reuse the drop in both cases
+      if (iff->ifTrue->type == Type::unreachable &&
+          iff->ifFalse->type.isConcrete()) {
+        curr->value = iff->ifFalse;
+        iff->ifFalse = curr;
+        iff->type = Type::none;
+        replaceCurrent(iff);
+      } else if (iff->ifFalse->type == Type::unreachable &&
+                 iff->ifTrue->type.isConcrete()) {
+        curr->value = iff->ifTrue;
+        iff->ifTrue = curr;
+        iff->type = Type::none;
+        replaceCurrent(iff);
+      }
+    }
+  }
+
+  void visitTry(Try* curr) {
+    // If try's body does not throw, the whole try-catch can be replaced with
+    // the try's body.
+    if (!EffectAnalyzer(getPassOptions(), getModule()->features, curr->body)
+           .throws) {
+      replaceCurrent(curr->body);
+      typeUpdater.noteRecursiveRemoval(curr->catchBody);
+    }
+  }
+
+  void visitFunction(Function* curr) {
+    auto* optimized =
+      optimize(curr->body, curr->sig.results != Type::none, true);
+    if (optimized) {
+      curr->body = optimized;
+    } else {
+      ExpressionManipulator::nop(curr->body);
+    }
+    if (curr->sig.results == Type::none &&
+        !EffectAnalyzer(getPassOptions(), getModule()->features, curr->body)
+           .hasSideEffects()) {
+      ExpressionManipulator::nop(curr->body);
+    }
+  }
+};
+
+Pass* createVacuumPass() { return new Vacuum(); }
+
+} // namespace wasm
diff --git a/binaryen/src/passes/WasmIntrinsics.cpp b/binaryen/src/passes/WasmIntrinsics.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/WasmIntrinsics.cpp
@@ -0,0 +1,11 @@
+// Automatically generated by embedwat.py
+
+#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
+};
+
+namespace wasm {
+const char* IntrinsicsModuleWast = theModule;
+}
diff --git a/binaryen/src/passes/intrinsics-module.h b/binaryen/src/passes/intrinsics-module.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/intrinsics-module.h
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+#ifndef passes_intrinsics_module_h
+#define passes_intrinsics_module_h
+
+namespace wasm {
+
+extern const char* IntrinsicsModuleWast;
+
+} // namespace wasm
+
+#endif // passes_intrinsics_module_h
diff --git a/binaryen/src/passes/opt-utils.h b/binaryen/src/passes/opt-utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/opt-utils.h
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#ifndef wasm_passes_opt_utils_h
+#define wasm_passes_opt_utils_h
+
+#include <functional>
+#include <unordered_set>
+
+#include <pass.h>
+#include <wasm.h>
+
+namespace wasm {
+
+namespace OptUtils {
+
+// Run useful optimizations after inlining new code into a set
+// of functions.
+inline void optimizeAfterInlining(std::unordered_set<Function*>& funcs,
+                                  Module* module,
+                                  PassRunner* parentRunner) {
+  // save the full list of functions on the side
+  std::vector<std::unique_ptr<Function>> all;
+  all.swap(module->functions);
+  module->updateMaps();
+  for (auto& func : funcs) {
+    module->addFunction(func);
+  }
+  PassRunner runner(module, parentRunner->options);
+  runner.setIsNested(true);
+  runner.setValidateGlobally(false); // not a full valid module
+  // this is especially useful after inlining
+  runner.add("precompute-propagate");
+  runner.addDefaultFunctionOptimizationPasses(); // do all the usual stuff
+  runner.run();
+  // restore all the funcs
+  for (auto& func : module->functions) {
+    func.release();
+  }
+  all.swap(module->functions);
+  module->updateMaps();
+}
+
+struct FunctionRefReplacer
+  : public WalkerPass<PostWalker<FunctionRefReplacer>> {
+  bool isFunctionParallel() override { return true; }
+
+  using MaybeReplace = std::function<void(Name&)>;
+
+  FunctionRefReplacer(MaybeReplace maybeReplace) : maybeReplace(maybeReplace) {}
+
+  FunctionRefReplacer* create() override {
+    return new FunctionRefReplacer(maybeReplace);
+  }
+
+  void visitCall(Call* curr) { maybeReplace(curr->target); }
+
+  void visitRefFunc(RefFunc* curr) { maybeReplace(curr->func); }
+
+private:
+  MaybeReplace maybeReplace;
+};
+
+inline void replaceFunctions(PassRunner* runner,
+                             Module& module,
+                             const std::map<Name, Name>& replacements) {
+  auto maybeReplace = [&](Name& name) {
+    auto iter = replacements.find(name);
+    if (iter != replacements.end()) {
+      name = iter->second;
+    }
+  };
+  // replace direct calls
+  FunctionRefReplacer(maybeReplace).run(runner, &module);
+  // replace in table
+  for (auto& segment : module.table.segments) {
+    for (auto& name : segment.data) {
+      maybeReplace(name);
+    }
+  }
+  // replace in start
+  if (module.start.is()) {
+    maybeReplace(module.start);
+  }
+  // replace in exports
+  for (auto& exp : module.exports) {
+    if (exp->kind == ExternalKind::Function) {
+      maybeReplace(exp->value);
+    }
+  }
+}
+
+} // namespace OptUtils
+} // namespace wasm
+
+#endif // wasm_passes_opt_utils_h
diff --git a/binaryen/src/passes/pass.cpp b/binaryen/src/passes/pass.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/pass.cpp
@@ -0,0 +1,822 @@
+/*
+ * Copyright 2015 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <chrono>
+#include <sstream>
+
+#ifdef __linux__
+#include <unistd.h>
+#endif
+
+#include "ir/hashed.h"
+#include "ir/module-utils.h"
+#include "pass.h"
+#include "passes/passes.h"
+#include "support/colors.h"
+#include "wasm-debug.h"
+#include "wasm-io.h"
+#include "wasm-validator.h"
+
+namespace wasm {
+
+// PassRegistry
+
+PassRegistry::PassRegistry() { registerPasses(); }
+
+static PassRegistry singleton;
+
+PassRegistry* PassRegistry::get() { return &singleton; }
+
+void PassRegistry::registerPass(const char* name,
+                                const char* description,
+                                Creator create) {
+  assert(passInfos.find(name) == passInfos.end());
+  passInfos[name] = PassInfo(description, create);
+}
+
+std::unique_ptr<Pass> PassRegistry::createPass(std::string name) {
+  if (passInfos.find(name) == passInfos.end()) {
+    return nullptr;
+  }
+  std::unique_ptr<Pass> ret;
+  ret.reset(passInfos[name].create());
+  ret->name = name;
+  return ret;
+}
+
+std::vector<std::string> PassRegistry::getRegisteredNames() {
+  std::vector<std::string> ret;
+  for (auto pair : passInfos) {
+    ret.push_back(pair.first);
+  }
+  return ret;
+}
+
+std::string PassRegistry::getPassDescription(std::string name) {
+  assert(passInfos.find(name) != passInfos.end());
+  return passInfos[name].description;
+}
+
+// PassRunner
+
+void PassRegistry::registerPasses() {
+  registerPass("alignment-lowering",
+               "lower unaligned loads and stores to smaller aligned ones",
+               createAlignmentLoweringPass);
+  registerPass("asyncify",
+               "async/await style transform, allowing pausing and resuming",
+               createAsyncifyPass);
+  registerPass("avoid-reinterprets",
+               "Tries to avoid reinterpret operations via more loads",
+               createAvoidReinterpretsPass);
+  registerPass(
+    "dae", "removes arguments to calls in an lto-like manner", createDAEPass);
+  registerPass("dae-optimizing",
+               "removes arguments to calls in an lto-like manner, and "
+               "optimizes where we removed",
+               createDAEOptimizingPass);
+  registerPass("coalesce-locals",
+               "reduce # of locals by coalescing",
+               createCoalesceLocalsPass);
+  registerPass("coalesce-locals-learning",
+               "reduce # of locals by coalescing and learning",
+               createCoalesceLocalsWithLearningPass);
+  registerPass("code-pushing",
+               "push code forward, potentially making it not always execute",
+               createCodePushingPass);
+  registerPass(
+    "code-folding", "fold code, merging duplicates", createCodeFoldingPass);
+  registerPass("const-hoisting",
+               "hoist repeated constants to a local",
+               createConstHoistingPass);
+  registerPass(
+    "dce", "removes unreachable code", createDeadCodeEliminationPass);
+  registerPass("dealign",
+               "forces all loads and stores to have alignment 1",
+               createDeAlignPass);
+  registerPass("denan",
+               "instrument the wasm to convert NaNs into 0 at runtime",
+               createDeNaNPass);
+  registerPass(
+    "directize", "turns indirect calls into direct ones", createDirectizePass);
+  registerPass(
+    "dfo", "optimizes using the DataFlow SSA IR", createDataFlowOptsPass);
+  registerPass("dwarfdump",
+               "dump DWARF debug info sections from the read binary",
+               createDWARFDumpPass);
+  registerPass("duplicate-import-elimination",
+               "removes duplicate imports",
+               createDuplicateImportEliminationPass);
+  registerPass("duplicate-function-elimination",
+               "removes duplicate functions",
+               createDuplicateFunctionEliminationPass);
+  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);
+  registerPass(
+    "flatten", "flattens out code, removing nesting", createFlattenPass);
+  registerPass("fpcast-emu",
+               "emulates function pointer casts, allowing incorrect indirect "
+               "calls to (sometimes) work",
+               createFuncCastEmulationPass);
+  registerPass(
+    "func-metrics", "reports function metrics", createFunctionMetricsPass);
+  registerPass("generate-dyncalls",
+               "generate dynCall fuctions used by emscripten ABI",
+               createGenerateDynCallsPass);
+  registerPass("generate-i64-dyncalls",
+               "generate dynCall functions used by emscripten ABI, but only for "
+               "functions with i64 in their signature (which cannot be invoked "
+               "via the wasm table without JavaScript BigInt support).",
+               createGenerateI64DynCallsPass);
+  registerPass(
+    "generate-stack-ir", "generate Stack IR", createGenerateStackIRPass);
+  registerPass(
+    "inline-main", "inline __original_main into main", createInlineMainPass);
+  registerPass("inlining",
+               "inline functions (you probably want inlining-optimizing)",
+               createInliningPass);
+  registerPass("inlining-optimizing",
+               "inline functions and optimizes where we inlined",
+               createInliningOptimizingPass);
+  registerPass("legalize-js-interface",
+               "legalizes i64 types on the import/export boundary",
+               createLegalizeJSInterfacePass);
+  registerPass("legalize-js-interface-minimally",
+               "legalizes i64 types on the import/export boundary in a minimal "
+               "manner, only on things only JS will call",
+               createLegalizeJSInterfaceMinimallyPass);
+  registerPass("local-cse",
+               "common subexpression elimination inside basic blocks",
+               createLocalCSEPass);
+  registerPass("log-execution",
+               "instrument the build with logging of where execution goes",
+               createLogExecutionPass);
+  registerPass("i64-to-i32-lowering",
+               "lower all uses of i64s to use i32s instead",
+               createI64ToI32LoweringPass);
+  registerPass(
+    "instrument-locals",
+    "instrument the build with code to intercept all loads and stores",
+    createInstrumentLocalsPass);
+  registerPass(
+    "instrument-memory",
+    "instrument the build with code to intercept all loads and stores",
+    createInstrumentMemoryPass);
+  registerPass(
+    "licm", "loop invariant code motion", createLoopInvariantCodeMotionPass);
+  registerPass("limit-segments",
+               "attempt to merge segments to fit within web limits",
+               createLimitSegmentsPass);
+  registerPass("memory-packing",
+               "packs memory into separate segments, skipping zeros",
+               createMemoryPackingPass);
+  registerPass(
+    "merge-blocks", "merges blocks to their parents", createMergeBlocksPass);
+  registerPass(
+    "merge-locals", "merges locals when beneficial", createMergeLocalsPass);
+  registerPass("metrics", "reports metrics", createMetricsPass);
+  registerPass("minify-imports",
+               "minifies import names (only those, and not export names), and "
+               "emits a mapping to the minified ones",
+               createMinifyImportsPass);
+  registerPass("minify-imports-and-exports",
+               "minifies both import and export names, and emits a mapping to "
+               "the minified ones",
+               createMinifyImportsAndExportsPass);
+  registerPass("minify-imports-and-exports-and-modules",
+               "minifies both import and export names, and emits a mapping to "
+               "the minified ones, and minifies the modules as well",
+               createMinifyImportsAndExportsAndModulesPass);
+  registerPass("mod-asyncify-always-and-only-unwind",
+               "apply the assumption that asyncify imports always unwind, "
+               "and we never rewind",
+               createModAsyncifyAlwaysOnlyUnwindPass);
+  registerPass("mod-asyncify-never-unwind",
+               "apply the assumption that asyncify never unwinds",
+               createModAsyncifyNeverUnwindPass);
+  registerPass("nm", "name list", createNameListPass);
+  registerPass("no-exit-runtime",
+               "removes calls to atexit(), which is valid if the C runtime "
+               "will never be exited",
+               createNoExitRuntimePass);
+  registerPass("optimize-added-constants",
+               "optimizes added constants into load/store offsets",
+               createOptimizeAddedConstantsPass);
+  registerPass("optimize-added-constants-propagate",
+               "optimizes added constants into load/store offsets, propagating "
+               "them across locals too",
+               createOptimizeAddedConstantsPropagatePass);
+  registerPass("optimize-instructions",
+               "optimizes instruction combinations",
+               createOptimizeInstructionsPass);
+  registerPass(
+    "optimize-stack-ir", "optimize Stack IR", createOptimizeStackIRPass);
+  registerPass("pick-load-signs",
+               "pick load signs based on their uses",
+               createPickLoadSignsPass);
+  registerPass("post-assemblyscript",
+               "eliminates redundant ARC patterns in AssemblyScript output",
+               createPostAssemblyScriptPass);
+  registerPass("post-assemblyscript-finalize",
+               "eliminates collapsed ARC patterns after other optimizations",
+               createPostAssemblyScriptFinalizePass);
+  registerPass("post-emscripten",
+               "miscellaneous optimizations for Emscripten-generated code",
+               createPostEmscriptenPass);
+  registerPass("precompute",
+               "computes compile-time evaluatable expressions",
+               createPrecomputePass);
+  registerPass("precompute-propagate",
+               "computes compile-time evaluatable expressions and propagates "
+               "them through locals",
+               createPrecomputePropagatePass);
+  registerPass("print", "print in s-expression format", createPrinterPass);
+  registerPass("print-minified",
+               "print in minified s-expression format",
+               createMinifiedPrinterPass);
+  registerPass("print-features",
+               "print options for enabled features",
+               createPrintFeaturesPass);
+  registerPass(
+    "print-full", "print in full s-expression format", createFullPrinterPass);
+  registerPass(
+    "print-call-graph", "print call graph", createPrintCallGraphPass);
+  registerPass("print-function-map",
+               "print a map of function indexes to names",
+               createPrintFunctionMapPass);
+  registerPass("print-stack-ir",
+               "print out Stack IR (useful for internal debugging)",
+               createPrintStackIRPass);
+  registerPass("remove-non-js-ops",
+               "removes operations incompatible with js",
+               createRemoveNonJSOpsPass);
+  registerPass("remove-imports",
+               "removes imports and replaces them with nops",
+               createRemoveImportsPass);
+  registerPass(
+    "remove-memory", "removes memory segments", createRemoveMemoryPass);
+  registerPass("remove-unused-brs",
+               "removes breaks from locations that are not needed",
+               createRemoveUnusedBrsPass);
+  registerPass("remove-unused-module-elements",
+               "removes unused module elements",
+               createRemoveUnusedModuleElementsPass);
+  registerPass("remove-unused-nonfunction-module-elements",
+               "removes unused module elements that are not functions",
+               createRemoveUnusedNonFunctionModuleElementsPass);
+  registerPass("remove-unused-names",
+               "removes names from locations that are never branched to",
+               createRemoveUnusedNamesPass);
+  registerPass("reorder-functions",
+               "sorts functions by access frequency",
+               createReorderFunctionsPass);
+  registerPass("reorder-locals",
+               "sorts locals by access frequency",
+               createReorderLocalsPass);
+  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",
+               "write the module to binary, then read it",
+               createRoundTripPass);
+  registerPass("safe-heap",
+               "instrument loads and stores to check for invalid behavior",
+               createSafeHeapPass);
+  registerPass("simplify-globals",
+               "miscellaneous globals-related optimizations",
+               createSimplifyGlobalsPass);
+  registerPass("simplify-globals-optimizing",
+               "miscellaneous globals-related optimizations, and optimizes "
+               "where we replaced global.gets with constants",
+               createSimplifyGlobalsOptimizingPass);
+  registerPass("simplify-locals",
+               "miscellaneous locals-related optimizations",
+               createSimplifyLocalsPass);
+  registerPass("simplify-locals-nonesting",
+               "miscellaneous locals-related optimizations (no nesting at all; "
+               "preserves flatness)",
+               createSimplifyLocalsNoNestingPass);
+  registerPass("simplify-locals-notee",
+               "miscellaneous locals-related optimizations (no tees)",
+               createSimplifyLocalsNoTeePass);
+  registerPass("simplify-locals-nostructure",
+               "miscellaneous locals-related optimizations (no structure)",
+               createSimplifyLocalsNoStructurePass);
+  registerPass(
+    "simplify-locals-notee-nostructure",
+    "miscellaneous locals-related optimizations (no tees or structure)",
+    createSimplifyLocalsNoTeeNoStructurePass);
+  registerPass("souperify", "emit Souper IR in text form", createSouperifyPass);
+  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);
+  registerPass("ssa",
+               "ssa-ify variables so that they have a single assignment",
+               createSSAifyPass);
+  registerPass(
+    "ssa-nomerge",
+    "ssa-ify variables so that they have a single assignment, ignoring merges",
+    createSSAifyNoMergePass);
+  registerPass(
+    "strip", "deprecated; same as strip-debug", createStripDebugPass);
+  registerPass("stack-check",
+               "enforce limits on llvm's __stack_pointer global",
+               createStackCheckPass);
+  registerPass("strip-debug",
+               "strip debug info (including the names section)",
+               createStripDebugPass);
+  registerPass("strip-dwarf", "strip dwarf debug info", createStripDWARFPass);
+  registerPass("strip-producers",
+               "strip the wasm producers section",
+               createStripProducersPass);
+  registerPass("strip-target-features",
+               "strip the wasm target features section",
+               createStripTargetFeaturesPass);
+  registerPass("trap-mode-clamp",
+               "replace trapping operations with clamping semantics",
+               createTrapModeClamp);
+  registerPass("trap-mode-js",
+               "replace trapping operations with js semantics",
+               createTrapModeJS);
+  registerPass("untee",
+               "removes local.tees, replacing them with sets and gets",
+               createUnteePass);
+  registerPass("vacuum", "removes obviously unneeded code", createVacuumPass);
+  // registerPass(
+  //   "lower-i64", "lowers i64 into pairs of i32s", createLowerInt64Pass);
+}
+
+void PassRunner::addDefaultOptimizationPasses() {
+  addDefaultGlobalOptimizationPrePasses();
+  addDefaultFunctionOptimizationPasses();
+  addDefaultGlobalOptimizationPostPasses();
+}
+
+// Check whether we should preserve valid DWARF while optimizing. If so, we
+// disable optimizations that currently cause issues with debug info.
+static bool shouldPreserveDWARF(PassOptions& options, Module& wasm) {
+  return options.debugInfo && Debug::hasDWARFSections(wasm);
+}
+
+void PassRunner::addDefaultFunctionOptimizationPasses() {
+  auto preserveDWARF = shouldPreserveDWARF(options, *wasm);
+  // Untangling to semi-ssa form is helpful (but best to ignore merges
+  // so as to not introduce new copies).
+  // FIXME DWARF updating does not handle local changes yet.
+  if (!preserveDWARF &&
+      (options.optimizeLevel >= 3 || options.shrinkLevel >= 1)) {
+    add("ssa-nomerge");
+  }
+  // if we are willing to work very very hard, flatten the IR and do opts
+  // that depend on flat IR
+  // FIXME DWARF updating does not handle local changes yet.
+  if (!preserveDWARF && options.optimizeLevel >= 4) {
+    add("flatten");
+    add("local-cse");
+  }
+  add("dce");
+  add("remove-unused-brs");
+  add("remove-unused-names");
+  add("optimize-instructions");
+  if (options.optimizeLevel >= 2 || options.shrinkLevel >= 2) {
+    add("pick-load-signs");
+  }
+  // early propagation
+  if (options.optimizeLevel >= 3 || options.shrinkLevel >= 2) {
+    add("precompute-propagate");
+  } else {
+    add("precompute");
+  }
+  if (options.lowMemoryUnused) {
+    if (options.optimizeLevel >= 3 || options.shrinkLevel >= 1) {
+      add("optimize-added-constants-propagate");
+    } else {
+      add("optimize-added-constants");
+    }
+  }
+  if (options.optimizeLevel >= 2 || options.shrinkLevel >= 2) {
+    add("code-pushing");
+  }
+  // don't create if/block return values yet, as coalesce can remove copies that
+  // that could inhibit
+  add("simplify-locals-nostructure");
+  add("vacuum"); // previous pass creates garbage
+  add("reorder-locals");
+  // simplify-locals opens opportunities for optimizations
+  add("remove-unused-brs");
+  // if we are willing to work hard, also optimize copies before coalescing
+  // FIXME DWARF updating does not handle local changes yet.
+  if (!preserveDWARF &&
+      (options.optimizeLevel >= 3 || options.shrinkLevel >= 2)) {
+    add("merge-locals"); // very slow on e.g. sqlite
+  }
+  // FIXME DWARF updating does not handle local changes yet.
+  if (!preserveDWARF) {
+    add("coalesce-locals");
+  }
+  add("simplify-locals");
+  add("vacuum");
+  add("reorder-locals");
+  // FIXME DWARF updating does not handle local changes yet.
+  if (!preserveDWARF) {
+    add("coalesce-locals");
+    add("reorder-locals");
+  }
+  add("vacuum");
+  if (options.optimizeLevel >= 3 || options.shrinkLevel >= 1) {
+    add("code-folding");
+  }
+  add("merge-blocks");        // makes remove-unused-brs more effective
+  add("remove-unused-brs");   // coalesce-locals opens opportunities
+  add("remove-unused-names"); // remove-unused-brs opens opportunities
+  add("merge-blocks");        // clean up remove-unused-brs new blocks
+  // late propagation
+  if (options.optimizeLevel >= 3 || options.shrinkLevel >= 2) {
+    add("precompute-propagate");
+  } else {
+    add("precompute");
+  }
+  add("optimize-instructions");
+  if (options.optimizeLevel >= 2 || options.shrinkLevel >= 1) {
+    add("rse"); // after all coalesce-locals, and before a final vacuum
+  }
+  add("vacuum"); // just to be safe
+}
+
+void PassRunner::addDefaultGlobalOptimizationPrePasses() {
+  // FIXME DWARF updating does not handle merging debug info with merged code.
+  if (!shouldPreserveDWARF(options, *wasm)) {
+    add("duplicate-function-elimination");
+  }
+  add("memory-packing");
+}
+
+void PassRunner::addDefaultGlobalOptimizationPostPasses() {
+  auto preserveDWARF = shouldPreserveDWARF(options, *wasm);
+  // FIXME DWARF may be badly affected currently as DAE changes function
+  // signatures and hence params and locals.
+  if (!preserveDWARF &&
+      (options.optimizeLevel >= 2 || options.shrinkLevel >= 1)) {
+    add("dae-optimizing");
+  }
+  // FIXME DWARF updating does not handle inlining yet.
+  if (!preserveDWARF &&
+      (options.optimizeLevel >= 2 || options.shrinkLevel >= 2)) {
+    add("inlining-optimizing");
+  }
+  // Optimizations show more functions as duplicate, so run this here in Post.
+  // FIXME DWARF updating does not handle merging debug info with merged code.
+  if (!preserveDWARF) {
+    add("duplicate-function-elimination");
+  }
+  add("duplicate-import-elimination");
+  if (options.optimizeLevel >= 2 || options.shrinkLevel >= 2) {
+    add("simplify-globals-optimizing");
+  } else {
+    add("simplify-globals");
+  }
+  add("remove-unused-module-elements");
+  // may allow more inlining/dae/etc., need --converge for that
+  add("directize");
+  // perform Stack IR optimizations here, at the very end of the
+  // optimization pipeline
+  if (options.optimizeLevel >= 2 || options.shrinkLevel >= 1) {
+    add("generate-stack-ir");
+    add("optimize-stack-ir");
+  }
+}
+
+static void dumpWast(Name name, Module* wasm) {
+  // write out the wat
+  static int counter = 0;
+  std::string numstr = std::to_string(counter++);
+  while (numstr.size() < 3) {
+    numstr = '0' + numstr;
+  }
+  auto fullName = std::string("byn-");
+#ifdef __linux__
+  // TODO: use _getpid() on windows, elsewhere?
+  fullName += std::to_string(getpid()) + '-';
+#endif
+  fullName += numstr + "-" + name.str;
+  Colors::setEnabled(false);
+  ModuleWriter writer;
+  writer.writeText(*wasm, fullName + ".wast");
+  writer.writeBinary(*wasm, fullName + ".wasm");
+}
+
+void PassRunner::run() {
+  static const int passDebug = getPassDebug();
+  if (!isNested && (options.debug || passDebug)) {
+    // 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;
+    for (auto& pass : passes) {
+      padding = std::max(padding, pass->name.size());
+    }
+    if (passDebug >= 3) {
+      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);
+      }
+      // prepare to run
+      std::cerr << "[PassRunner]   running pass: " << pass->name << "... ";
+      for (size_t i = 0; i < padding - pass->name.size(); i++) {
+        std::cerr << ' ';
+      }
+      auto before = std::chrono::steady_clock::now();
+      if (pass->isFunctionParallel()) {
+        // function-parallel passes should get a new instance per function
+        ModuleUtils::iterDefinedFunctions(
+          *wasm, [&](Function* func) { runPassOnFunction(pass.get(), func); });
+      } else {
+        runPass(pass.get());
+      }
+      auto after = std::chrono::steady_clock::now();
+      std::chrono::duration<double> diff = after - before;
+      std::cerr << diff.count() << " seconds." << std::endl;
+      totalTime += diff;
+      if (options.validate) {
+        // validate, ignoring the time
+        std::cerr << "[PassRunner]   (validating)\n";
+        if (!WasmValidator().validate(*wasm, validationFlags)) {
+          WasmPrinter::printModule(wasm);
+          if (passDebug >= 2) {
+            Fatal() << "Last pass (" << pass->name
+                    << ") broke validation. Here is the module before: \n"
+                    << moduleBefore.str() << "\n";
+          } else {
+            Fatal() << "Last pass (" << pass->name
+                    << ") broke validation. Run with BINARYEN_PASS_DEBUG=2 "
+                       "in the env to see the earlier state, or 3 to dump "
+                       "byn-* files for each pass\n";
+          }
+        }
+      }
+      if (passDebug >= 3) {
+        dumpWast(pass->name, wasm);
+      }
+    }
+    std::cerr << "[PassRunner] passes took " << totalTime.count() << " seconds."
+              << std::endl;
+    if (options.validate) {
+      std::cerr << "[PassRunner] (final validation)\n";
+      if (!WasmValidator().validate(*wasm, validationFlags)) {
+        WasmPrinter::printModule(wasm);
+        Fatal() << "final module does not validate\n";
+      }
+    }
+  } else {
+    // non-debug normal mode, run them in an optimal manner - for locality it is
+    // better to run as many passes as possible on a single function before
+    // moving to the next
+    std::vector<Pass*> stack;
+    auto flush = [&]() {
+      if (stack.size() > 0) {
+        // run the stack of passes on all the functions, in parallel
+        size_t num = ThreadPool::get()->size();
+        std::vector<std::function<ThreadWorkState()>> doWorkers;
+        std::atomic<size_t> nextFunction;
+        nextFunction.store(0);
+        size_t numFunctions = wasm->functions.size();
+        for (size_t i = 0; i < num; i++) {
+          doWorkers.push_back([&]() {
+            auto index = nextFunction.fetch_add(1);
+            // get the next task, if there is one
+            if (index >= numFunctions) {
+              return ThreadWorkState::Finished; // nothing left
+            }
+            Function* func = this->wasm->functions[index].get();
+            if (!func->imported()) {
+              // do the current task: run all passes on this function
+              for (auto* pass : stack) {
+                runPassOnFunction(pass, func);
+              }
+            }
+            if (index + 1 == numFunctions) {
+              return ThreadWorkState::Finished; // we did the last one
+            }
+            return ThreadWorkState::More;
+          });
+        }
+        ThreadPool::get()->work(doWorkers);
+      }
+      stack.clear();
+    };
+    for (auto& pass : passes) {
+      if (pass->isFunctionParallel()) {
+        stack.push_back(pass.get());
+      } else {
+        flush();
+        runPass(pass.get());
+      }
+    }
+    flush();
+  }
+}
+
+void PassRunner::runOnFunction(Function* func) {
+  if (options.debug) {
+    std::cerr << "[PassRunner] running passes on function " << func->name
+              << std::endl;
+  }
+  for (auto& pass : passes) {
+    runPassOnFunction(pass.get(), func);
+  }
+}
+
+void PassRunner::doAdd(std::unique_ptr<Pass> pass) {
+  pass->prepareToRun(this, wasm);
+  passes.emplace_back(std::move(pass));
+}
+
+// Checks that the state is valid before and after a
+// pass runs on a function. We run these extra checks when
+// pass-debug mode is enabled.
+struct AfterEffectFunctionChecker {
+  Function* func;
+  Name name;
+
+  // Check Stack IR state: if the main IR changes, there should be no
+  // stack IR, as the stack IR would be wrong.
+  bool beganWithStackIR;
+  size_t originalFunctionHash;
+
+  // In the creator we can scan the state of the module and function before the
+  // pass runs.
+  AfterEffectFunctionChecker(Function* func) : func(func), name(func->name) {
+    beganWithStackIR = func->stackIR != nullptr;
+    if (beganWithStackIR) {
+      originalFunctionHash = FunctionHasher::hashFunction(func);
+    }
+  }
+
+  // This is called after the pass is run, at which time we can check things.
+  void check() {
+    assert(func->name == name); // no global module changes should have occurred
+    if (beganWithStackIR && func->stackIR) {
+      auto after = FunctionHasher::hashFunction(func);
+      if (after != originalFunctionHash) {
+        Fatal() << "[PassRunner] PASS_DEBUG check failed: had Stack IR before "
+                   "and after the pass ran, and the pass modified the main IR, "
+                   "which invalidates Stack IR - pass should have been marked "
+                   "'modifiesBinaryenIR'";
+      }
+    }
+  }
+};
+
+// Runs checks on the entire module, in a non-function-parallel pass.
+// In particular, in such a pass functions may be removed or renamed, track
+// that.
+struct AfterEffectModuleChecker {
+  Module* module;
+
+  std::vector<AfterEffectFunctionChecker> checkers;
+
+  bool beganWithAnyStackIR;
+
+  AfterEffectModuleChecker(Module* module) : module(module) {
+    for (auto& func : module->functions) {
+      checkers.emplace_back(func.get());
+    }
+    beganWithAnyStackIR = hasAnyStackIR();
+  }
+
+  void check() {
+    if (beganWithAnyStackIR && hasAnyStackIR()) {
+      // If anything changed to the functions, that's not good.
+      if (checkers.size() != module->functions.size()) {
+        error();
+      }
+      for (Index i = 0; i < checkers.size(); i++) {
+        // Did a pointer change? (a deallocated function could cause that)
+        if (module->functions[i].get() != checkers[i].func ||
+            module->functions[i]->body != checkers[i].func->body) {
+          error();
+        }
+        // Did a name change?
+        if (module->functions[i]->name != checkers[i].name) {
+          error();
+        }
+      }
+      // Global function state appears to not have been changed: the same
+      // functions are there. Look into their contents.
+      for (auto& checker : checkers) {
+        checker.check();
+      }
+    }
+  }
+
+  void error() {
+    Fatal() << "[PassRunner] PASS_DEBUG check failed: had Stack IR before and "
+               "after the pass ran, and the pass modified global function "
+               "state - pass should have been marked 'modifiesBinaryenIR'";
+  }
+
+  bool hasAnyStackIR() {
+    for (auto& func : module->functions) {
+      if (func->stackIR) {
+        return true;
+      }
+    }
+    return false;
+  }
+};
+
+void PassRunner::runPass(Pass* pass) {
+  std::unique_ptr<AfterEffectModuleChecker> checker;
+  if (getPassDebug()) {
+    checker = std::unique_ptr<AfterEffectModuleChecker>(
+      new AfterEffectModuleChecker(wasm));
+  }
+  pass->run(this, wasm);
+  handleAfterEffects(pass);
+  if (getPassDebug()) {
+    checker->check();
+  }
+}
+
+void PassRunner::runPassOnFunction(Pass* pass, Function* func) {
+  assert(pass->isFunctionParallel());
+  // function-parallel passes get a new instance per function
+  auto instance = std::unique_ptr<Pass>(pass->create());
+  std::unique_ptr<AfterEffectFunctionChecker> checker;
+  if (getPassDebug()) {
+    checker = std::unique_ptr<AfterEffectFunctionChecker>(
+      new AfterEffectFunctionChecker(func));
+  }
+  instance->runOnFunction(this, wasm, func);
+  handleAfterEffects(pass, func);
+  if (getPassDebug()) {
+    checker->check();
+  }
+}
+
+void PassRunner::handleAfterEffects(Pass* pass, Function* func) {
+  if (pass->modifiesBinaryenIR()) {
+    // If Binaryen IR is modified, Stack IR must be cleared - it would
+    // be out of sync in a potentially dangerous way.
+    if (func) {
+      func->stackIR.reset(nullptr);
+    } else {
+      for (auto& func : wasm->functions) {
+        func->stackIR.reset(nullptr);
+      }
+    }
+  }
+}
+
+int PassRunner::getPassDebug() {
+  static const int passDebug =
+    getenv("BINARYEN_PASS_DEBUG") ? atoi(getenv("BINARYEN_PASS_DEBUG")) : 0;
+  return passDebug;
+}
+
+} // namespace wasm
diff --git a/binaryen/src/passes/passes.h b/binaryen/src/passes/passes.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/passes.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2015 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_passes_h
+#define wasm_passes_h
+
+namespace wasm {
+
+class Pass;
+
+// All passes:
+Pass* createAlignmentLoweringPass();
+Pass* createAsyncifyPass();
+Pass* createAvoidReinterpretsPass();
+Pass* createCoalesceLocalsPass();
+Pass* createCoalesceLocalsWithLearningPass();
+Pass* createCodeFoldingPass();
+Pass* createCodePushingPass();
+Pass* createConstHoistingPass();
+Pass* createDAEPass();
+Pass* createDAEOptimizingPass();
+Pass* createDataFlowOptsPass();
+Pass* createDeadCodeEliminationPass();
+Pass* createDeNaNPass();
+Pass* createDeAlignPass();
+Pass* createDirectizePass();
+Pass* createDWARFDumpPass();
+Pass* createDuplicateImportEliminationPass();
+Pass* createDuplicateFunctionEliminationPass();
+Pass* createEmitTargetFeaturesPass();
+Pass* createEmscriptenPICPass();
+Pass* createEmscriptenPICMainModulePass();
+Pass* createExtractFunctionPass();
+Pass* createFlattenPass();
+Pass* createFuncCastEmulationPass();
+Pass* createFullPrinterPass();
+Pass* createFunctionMetricsPass();
+Pass* createGenerateDynCallsPass();
+Pass* createGenerateI64DynCallsPass();
+Pass* createGenerateStackIRPass();
+Pass* createI64ToI32LoweringPass();
+Pass* createInlineMainPass();
+Pass* createInliningPass();
+Pass* createInliningOptimizingPass();
+Pass* createLegalizeJSInterfacePass();
+Pass* createLegalizeJSInterfaceMinimallyPass();
+Pass* createLimitSegmentsPass();
+Pass* createLocalCSEPass();
+Pass* createLogExecutionPass();
+Pass* createInstrumentLocalsPass();
+Pass* createInstrumentMemoryPass();
+Pass* createLoopInvariantCodeMotionPass();
+Pass* createMemoryPackingPass();
+Pass* createMergeBlocksPass();
+Pass* createMergeLocalsPass();
+Pass* createMinifiedPrinterPass();
+Pass* createMinifyImportsPass();
+Pass* createMinifyImportsAndExportsPass();
+Pass* createMinifyImportsAndExportsAndModulesPass();
+Pass* createMetricsPass();
+Pass* createNameListPass();
+Pass* createNoExitRuntimePass();
+Pass* createOptimizeAddedConstantsPass();
+Pass* createOptimizeAddedConstantsPropagatePass();
+Pass* createOptimizeInstructionsPass();
+Pass* createOptimizeStackIRPass();
+Pass* createPickLoadSignsPass();
+Pass* createModAsyncifyAlwaysOnlyUnwindPass();
+Pass* createModAsyncifyNeverUnwindPass();
+Pass* createPostAssemblyScriptPass();
+Pass* createPostAssemblyScriptFinalizePass();
+Pass* createPostEmscriptenPass();
+Pass* createPrecomputePass();
+Pass* createPrecomputePropagatePass();
+Pass* createPrinterPass();
+Pass* createPrintCallGraphPass();
+Pass* createPrintFeaturesPass();
+Pass* createPrintFunctionMapPass();
+Pass* createPrintStackIRPass();
+Pass* createRemoveNonJSOpsPass();
+Pass* createRemoveImportsPass();
+Pass* createRemoveMemoryPass();
+Pass* createRemoveUnusedBrsPass();
+Pass* createRemoveUnusedModuleElementsPass();
+Pass* createRemoveUnusedNonFunctionModuleElementsPass();
+Pass* createRemoveUnusedNamesPass();
+Pass* createReorderFunctionsPass();
+Pass* createReorderLocalsPass();
+Pass* createReplaceStackPointerPass();
+Pass* createReReloopPass();
+Pass* createRedundantSetEliminationPass();
+Pass* createRoundTripPass();
+Pass* createSafeHeapPass();
+Pass* createSimplifyLocalsPass();
+Pass* createSimplifyGlobalsPass();
+Pass* createSimplifyGlobalsOptimizingPass();
+Pass* createSimplifyLocalsNoNestingPass();
+Pass* createSimplifyLocalsNoTeePass();
+Pass* createSimplifyLocalsNoStructurePass();
+Pass* createSimplifyLocalsNoTeeNoStructurePass();
+Pass* createStackCheckPass();
+Pass* createStripDebugPass();
+Pass* createStripDWARFPass();
+Pass* createStripProducersPass();
+Pass* createStripTargetFeaturesPass();
+Pass* createSouperifyPass();
+Pass* createSouperifySingleUsePass();
+Pass* createSpillPointersPass();
+Pass* createStubUnsupportedJSOpsPass();
+Pass* createSSAifyPass();
+Pass* createSSAifyNoMergePass();
+Pass* createTrapModeClamp();
+Pass* createTrapModeJS();
+Pass* createUnteePass();
+Pass* createVacuumPass();
+
+} // namespace wasm
+
+#endif
diff --git a/binaryen/src/passes/wasm-intrinsics.wat b/binaryen/src/passes/wasm-intrinsics.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/wasm-intrinsics.wat
@@ -0,0 +1,1113 @@
+;; A large WAST blob which contains the implementations of all the intrinsics
+;; that we inject as part of this module. This blob was generated from a Rust
+;; program [1] which uses the Rust compiler-builtins project. It's not
+;; necessarily perfect but gets the job done! The idea here is that we inject
+;; these pretty early so they can continue to be optimized by further passes
+;; (aka inlining and whatnot)
+;;
+;; LOCAL MODS done by hand afterwards:
+;;  * Remove hardcoded address 1024 which was used for temporary data; instead
+;;    add $wasm-intrinsics-temp-i64 global for that.
+;;  * Fix function type of __wasm_ctz_i64, which was wrong somehow,
+;;    i32, i32 => i32 instead of i64 => i64
+;;  * Remove unnecessary memory import.
+;;
+;; [1]: https://gist.github.com/alexcrichton/e7ea67bcdd17ce4b6254e66f77165690
+
+(module
+ (type $0 (func (param i64 i64) (result i64)))
+ (type $1 (func (param f32) (result f32)))
+ (type $2 (func (param f64) (result f64)))
+ (type $3 (func (param i32) (result i32)))
+ (type $4 (func (param i32 i32) (result i32)))
+ (type $5 (func (param i64) (result i64)))
+ (export "__wasm_i64_sdiv" (func $__wasm_i64_sdiv))
+ (export "__wasm_i64_udiv" (func $__wasm_i64_udiv))
+ (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))
+ (export "__wasm_rotr_i32" (func $__wasm_rotr_i32))
+ (export "__wasm_rotl_i64" (func $__wasm_rotl_i64))
+ (export "__wasm_rotr_i64" (func $__wasm_rotr_i64))
+ (export "__wasm_nearest_f32" (func $__wasm_nearest_f32))
+ (export "__wasm_nearest_f64" (func $__wasm_nearest_f64))
+ (export "__wasm_popcnt_i32" (func $__wasm_popcnt_i32))
+ (export "__wasm_popcnt_i64" (func $__wasm_popcnt_i64))
+ (global $__wasm-intrinsics-temp-i64 (mut i64) (i64.const 0))
+
+ ;; lowering of the i32.popcnt instruction, counts the number of bits set in the
+ ;; input and returns the result
+ (func $__wasm_popcnt_i32 (param $var$0 i32) (result i32)
+  (local $var$1 i32)
+  (block $label$1 (result i32)
+   (loop $label$2
+    (drop
+     (br_if $label$1
+      (local.get $var$1)
+      (i32.eqz
+       (local.get $var$0)
+      )
+     )
+    )
+    (local.set $var$0
+     (i32.and
+      (local.get $var$0)
+      (i32.sub
+       (local.get $var$0)
+       (i32.const 1)
+      )
+     )
+    )
+    (local.set $var$1
+     (i32.add
+      (local.get $var$1)
+      (i32.const 1)
+     )
+    )
+    (br $label$2)
+   )
+  )
+ )
+ ;; lowering of the i64.popcnt instruction, counts the number of bits set in the
+ ;; input and returns the result
+ (func $__wasm_popcnt_i64 (param $var$0 i64) (result i64)
+  (local $var$1 i64)
+  (block $label$1 (result i64)
+   (loop $label$2
+    (drop
+     (br_if $label$1
+      (local.get $var$1)
+      (i64.eqz
+       (local.get $var$0)
+      )
+     )
+    )
+    (local.set $var$0
+     (i64.and
+      (local.get $var$0)
+      (i64.sub
+       (local.get $var$0)
+       (i64.const 1)
+      )
+     )
+    )
+    (local.set $var$1
+     (i64.add
+      (local.get $var$1)
+      (i64.const 1)
+     )
+    )
+    (br $label$2)
+   )
+  )
+ )
+ ;; lowering of the i64.div_s instruction, return $var0 / $var$1
+ (func $__wasm_i64_sdiv (; 0 ;) (type $0) (param $var$0 i64) (param $var$1 i64) (result i64)
+  (call $_ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E
+   (local.get $var$0)
+   (local.get $var$1)
+  )
+ )
+ ;; lowering of the i64.div_u instruction, return $var0 / $var$1
+ (func $__wasm_i64_udiv (; 1 ;) (type $0) (param $var$0 i64) (param $var$1 i64) (result i64)
+  (call $_ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E
+   (local.get $var$0)
+   (local.get $var$1)
+  )
+ )
+ ;; lowering of the i64.rem_s instruction, return $var0 % $var$1
+ (func $__wasm_i64_srem (; 2 ;) (type $0) (param $var$0 i64) (param $var$1 i64) (result i64)
+  (call $_ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E
+   (local.get $var$0)
+   (local.get $var$1)
+  )
+ )
+ ;; lowering of the i64.rem_u instruction, return $var0 % $var$1
+ (func $__wasm_i64_urem (; 3 ;) (type $0) (param $var$0 i64) (param $var$1 i64) (result i64)
+  (drop
+   (call $_ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E
+    (local.get $var$0)
+    (local.get $var$1)
+   )
+  )
+  (global.get $__wasm-intrinsics-temp-i64)
+ )
+ ;; lowering of the i64.mul instruction, return $var0 * $var$1
+ (func $__wasm_i64_mul (; 4 ;) (type $0) (param $var$0 i64) (param $var$1 i64) (result i64)
+  (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
+ (func $__wasm_ctz_i32 (; 7 ;) (type $3) (param $var$0 i32) (result i32)
+  (if
+   (local.get $var$0)
+   (return
+    (i32.sub
+     (i32.const 31)
+     (i32.clz
+      (i32.xor
+       (i32.add
+        (local.get $var$0)
+        (i32.const -1)
+       )
+       (local.get $var$0)
+      )
+     )
+    )
+   )
+  )
+  (i32.const 32)
+ )
+ ;; lowering of the i64.ctz instruction, counting the number of zeros in $var$0
+ (func $__wasm_ctz_i64 (; 8 ;) (type $5) (param $var$0 i64) (result i64)
+  (if
+   (i32.eqz
+    (i64.eqz
+     (local.get $var$0)
+    )
+   )
+   (return
+    (i64.sub
+     (i64.const 63)
+     (i64.clz
+      (i64.xor
+       (i64.add
+        (local.get $var$0)
+        (i64.const -1)
+       )
+       (local.get $var$0)
+      )
+     )
+    )
+   )
+  )
+  (i64.const 64)
+ )
+ ;; lowering of the i32.rotl instruction, rotating the first argument, with
+ ;; wraparound, by the second argument
+ (func $__wasm_rotl_i32 (; 8 ;) (type $4) (param $var$0 i32) (param $var$1 i32) (result i32)
+  (local $var$2 i32)
+  (i32.or
+   (i32.shl
+    (i32.and
+     (i32.shr_u
+      (i32.const -1)
+      (local.tee $var$2
+       (i32.and
+        (local.get $var$1)
+        (i32.const 31)
+       )
+      )
+     )
+     (local.get $var$0)
+    )
+    (local.get $var$2)
+   )
+   (i32.shr_u
+    (i32.and
+     (i32.shl
+      (i32.const -1)
+      (local.tee $var$1
+       (i32.and
+        (i32.sub
+         (i32.const 0)
+         (local.get $var$1)
+        )
+        (i32.const 31)
+       )
+      )
+     )
+     (local.get $var$0)
+    )
+    (local.get $var$1)
+   )
+  )
+ )
+ ;; lowering of the i32.rotr instruction, rotating the first argument, with
+ ;; wraparound, by the second argument
+ (func $__wasm_rotr_i32 (; 9 ;) (type $4) (param $var$0 i32) (param $var$1 i32) (result i32)
+  (local $var$2 i32)
+  (i32.or
+   (i32.shr_u
+    (i32.and
+     (i32.shl
+      (i32.const -1)
+      (local.tee $var$2
+       (i32.and
+        (local.get $var$1)
+        (i32.const 31)
+       )
+      )
+     )
+     (local.get $var$0)
+    )
+    (local.get $var$2)
+   )
+   (i32.shl
+    (i32.and
+     (i32.shr_u
+      (i32.const -1)
+      (local.tee $var$1
+       (i32.and
+        (i32.sub
+         (i32.const 0)
+         (local.get $var$1)
+        )
+        (i32.const 31)
+       )
+      )
+     )
+     (local.get $var$0)
+    )
+    (local.get $var$1)
+   )
+  )
+ )
+ ;; lowering of the i64.rotl instruction, rotating the first argument, with
+ ;; wraparound, by the second argument
+ (func $__wasm_rotl_i64 (; 10 ;) (type $0) (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $var$2 i64)
+  (i64.or
+   (i64.shl
+    (i64.and
+     (i64.shr_u
+      (i64.const -1)
+      (local.tee $var$2
+       (i64.and
+        (local.get $var$1)
+        (i64.const 63)
+       )
+      )
+     )
+     (local.get $var$0)
+    )
+    (local.get $var$2)
+   )
+   (i64.shr_u
+    (i64.and
+     (i64.shl
+      (i64.const -1)
+      (local.tee $var$1
+       (i64.and
+        (i64.sub
+         (i64.const 0)
+         (local.get $var$1)
+        )
+        (i64.const 63)
+       )
+      )
+     )
+     (local.get $var$0)
+    )
+    (local.get $var$1)
+   )
+  )
+ )
+ ;; lowering of the i64.rotr instruction, rotating the first argument, with
+ ;; wraparound, by the second argument
+ (func $__wasm_rotr_i64 (; 11 ;) (type $0) (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $var$2 i64)
+  (i64.or
+   (i64.shr_u
+    (i64.and
+     (i64.shl
+      (i64.const -1)
+      (local.tee $var$2
+       (i64.and
+        (local.get $var$1)
+        (i64.const 63)
+       )
+      )
+     )
+     (local.get $var$0)
+    )
+    (local.get $var$2)
+   )
+   (i64.shl
+    (i64.and
+     (i64.shr_u
+      (i64.const -1)
+      (local.tee $var$1
+       (i64.and
+        (i64.sub
+         (i64.const 0)
+         (local.get $var$1)
+        )
+        (i64.const 63)
+       )
+      )
+     )
+     (local.get $var$0)
+    )
+    (local.get $var$1)
+   )
+  )
+ )
+ ;; lowering of the f32.nearest instruction, rounding the input to the nearest
+ ;; integer while breaking ties by rounding to even
+ (func $__wasm_nearest_f32 (; 12 ;) (type $1) (param $var$0 f32) (result f32)
+  (local $var$1 f32)
+  (local $var$2 f32)
+  (if
+   (i32.eqz
+    (f32.lt
+     (local.tee $var$2
+      (f32.sub
+       (local.get $var$0)
+       (local.tee $var$1
+        (f32.floor
+         (local.get $var$0)
+        )
+       )
+      )
+     )
+     (f32.const 0.5)
+    )
+   )
+   (block
+    (local.set $var$0
+     (f32.ceil
+      (local.get $var$0)
+     )
+    )
+    (if
+     (f32.gt
+      (local.get $var$2)
+      (f32.const 0.5)
+     )
+     (return
+      (local.get $var$0)
+     )
+    )
+    (local.set $var$1
+     (select
+      (local.get $var$1)
+      (local.get $var$0)
+      (f32.eq
+       (f32.sub
+        (local.tee $var$2
+         (f32.mul
+          (local.get $var$1)
+          (f32.const 0.5)
+         )
+        )
+        (f32.floor
+         (local.get $var$2)
+        )
+       )
+       (f32.const 0)
+      )
+     )
+    )
+   )
+  )
+  (local.get $var$1)
+ )
+ ;; lowering of the f64.nearest instruction, rounding the input to the nearest
+ ;; integer while breaking ties by rounding to even
+ (func $__wasm_nearest_f64 (; 13 ;) (type $2) (param $var$0 f64) (result f64)
+  (local $var$1 f64)
+  (local $var$2 f64)
+  (if
+   (i32.eqz
+    (f64.lt
+     (local.tee $var$2
+      (f64.sub
+       (local.get $var$0)
+       (local.tee $var$1
+        (f64.floor
+         (local.get $var$0)
+        )
+       )
+      )
+     )
+     (f64.const 0.5)
+    )
+   )
+   (block
+    (local.set $var$0
+     (f64.ceil
+      (local.get $var$0)
+     )
+    )
+    (if
+     (f64.gt
+      (local.get $var$2)
+      (f64.const 0.5)
+     )
+     (return
+      (local.get $var$0)
+     )
+    )
+    (local.set $var$1
+     (select
+      (local.get $var$1)
+      (local.get $var$0)
+      (f64.eq
+       (f64.sub
+        (local.tee $var$2
+         (f64.mul
+          (local.get $var$1)
+          (f64.const 0.5)
+         )
+        )
+        (f64.floor
+         (local.get $var$2)
+        )
+       )
+       (f64.const 0)
+      )
+     )
+    )
+   )
+  )
+  (local.get $var$1)
+ )
+ (func $_ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E (; 14 ;) (type $0) (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $var$2 i32)
+  (local $var$3 i32)
+  (local $var$4 i32)
+  (local $var$5 i64)
+  (local $var$6 i64)
+  (local $var$7 i64)
+  (local $var$8 i64)
+  (block $label$1
+   (block $label$2
+    (block $label$3
+     (block $label$4
+      (block $label$5
+       (block $label$6
+        (block $label$7
+         (block $label$8
+          (block $label$9
+           (block $label$10
+            (block $label$11
+             (if
+              (local.tee $var$2
+               (i32.wrap_i64
+                (i64.shr_u
+                 (local.get $var$0)
+                 (i64.const 32)
+                )
+               )
+              )
+              (block
+               (br_if $label$11
+                (i32.eqz
+                 (local.tee $var$3
+                  (i32.wrap_i64
+                   (local.get $var$1)
+                  )
+                 )
+                )
+               )
+               (br_if $label$9
+                (i32.eqz
+                 (local.tee $var$4
+                  (i32.wrap_i64
+                   (i64.shr_u
+                    (local.get $var$1)
+                    (i64.const 32)
+                   )
+                  )
+                 )
+                )
+               )
+               (br_if $label$8
+                (i32.le_u
+                 (local.tee $var$2
+                  (i32.sub
+                   (i32.clz
+                    (local.get $var$4)
+                   )
+                   (i32.clz
+                    (local.get $var$2)
+                   )
+                  )
+                 )
+                 (i32.const 31)
+                )
+               )
+               (br $label$2)
+              )
+             )
+             (br_if $label$2
+              (i64.ge_u
+               (local.get $var$1)
+               (i64.const 4294967296)
+              )
+             )
+             (global.set $__wasm-intrinsics-temp-i64
+              (i64.extend_i32_u
+               (i32.sub
+                (local.tee $var$2
+                 (i32.wrap_i64
+                  (local.get $var$0)
+                 )
+                )
+                (i32.mul
+                 (local.tee $var$2
+                  (i32.div_u
+                   (local.get $var$2)
+                   (local.tee $var$3
+                    (i32.wrap_i64
+                     (local.get $var$1)
+                    )
+                   )
+                  )
+                 )
+                 (local.get $var$3)
+                )
+               )
+              )
+             )
+             (return
+              (i64.extend_i32_u
+               (local.get $var$2)
+              )
+             )
+            )
+            (local.set $var$3
+             (i32.wrap_i64
+              (i64.shr_u
+               (local.get $var$1)
+               (i64.const 32)
+              )
+             )
+            )
+            (br_if $label$7
+             (i32.eqz
+              (i32.wrap_i64
+               (local.get $var$0)
+              )
+             )
+            )
+            (br_if $label$6
+             (i32.eqz
+              (local.get $var$3)
+             )
+            )
+            (br_if $label$6
+             (i32.and
+              (local.tee $var$4
+               (i32.add
+                (local.get $var$3)
+                (i32.const -1)
+               )
+              )
+              (local.get $var$3)
+             )
+            )
+            (global.set $__wasm-intrinsics-temp-i64
+             (i64.or
+              (i64.shl
+               (i64.extend_i32_u
+                (i32.and
+                 (local.get $var$4)
+                 (local.get $var$2)
+                )
+               )
+               (i64.const 32)
+              )
+              (i64.and
+               (local.get $var$0)
+               (i64.const 4294967295)
+              )
+             )
+            )
+            (return
+             (i64.extend_i32_u
+              (i32.shr_u
+               (local.get $var$2)
+               (i32.and
+                (i32.ctz
+                 (local.get $var$3)
+                )
+                (i32.const 31)
+               )
+              )
+             )
+            )
+           )
+           (unreachable)
+          )
+          (br_if $label$5
+           (i32.eqz
+            (i32.and
+             (local.tee $var$4
+              (i32.add
+               (local.get $var$3)
+               (i32.const -1)
+              )
+             )
+             (local.get $var$3)
+            )
+           )
+          )
+          (local.set $var$3
+           (i32.sub
+            (i32.const 0)
+            (local.tee $var$2
+             (i32.sub
+              (i32.add
+               (i32.clz
+                (local.get $var$3)
+               )
+               (i32.const 33)
+              )
+              (i32.clz
+               (local.get $var$2)
+              )
+             )
+            )
+           )
+          )
+          (br $label$3)
+         )
+         (local.set $var$3
+          (i32.sub
+           (i32.const 63)
+           (local.get $var$2)
+          )
+         )
+         (local.set $var$2
+          (i32.add
+           (local.get $var$2)
+           (i32.const 1)
+          )
+         )
+         (br $label$3)
+        )
+        (global.set $__wasm-intrinsics-temp-i64
+         (i64.shl
+          (i64.extend_i32_u
+           (i32.sub
+            (local.get $var$2)
+            (i32.mul
+             (local.tee $var$4
+              (i32.div_u
+               (local.get $var$2)
+               (local.get $var$3)
+              )
+             )
+             (local.get $var$3)
+            )
+           )
+          )
+          (i64.const 32)
+         )
+        )
+        (return
+         (i64.extend_i32_u
+          (local.get $var$4)
+         )
+        )
+       )
+       (br_if $label$4
+        (i32.lt_u
+         (local.tee $var$2
+          (i32.sub
+           (i32.clz
+            (local.get $var$3)
+           )
+           (i32.clz
+            (local.get $var$2)
+           )
+          )
+         )
+         (i32.const 31)
+        )
+       )
+       (br $label$2)
+      )
+      (global.set $__wasm-intrinsics-temp-i64
+       (i64.extend_i32_u
+        (i32.and
+         (local.get $var$4)
+         (i32.wrap_i64
+          (local.get $var$0)
+         )
+        )
+       )
+      )
+      (br_if $label$1
+       (i32.eq
+        (local.get $var$3)
+        (i32.const 1)
+       )
+      )
+      (return
+       (i64.shr_u
+        (local.get $var$0)
+        (i64.extend_i32_u
+         (i32.ctz
+          (local.get $var$3)
+         )
+        )
+       )
+      )
+     )
+     (local.set $var$3
+      (i32.sub
+       (i32.const 63)
+       (local.get $var$2)
+      )
+     )
+     (local.set $var$2
+      (i32.add
+       (local.get $var$2)
+       (i32.const 1)
+      )
+     )
+    )
+    (local.set $var$5
+     (i64.shr_u
+      (local.get $var$0)
+      (i64.extend_i32_u
+       (i32.and
+        (local.get $var$2)
+        (i32.const 63)
+       )
+      )
+     )
+    )
+    (local.set $var$0
+     (i64.shl
+      (local.get $var$0)
+      (i64.extend_i32_u
+       (i32.and
+        (local.get $var$3)
+        (i32.const 63)
+       )
+      )
+     )
+    )
+    (block $label$13
+     (if
+      (local.get $var$2)
+      (block
+       (local.set $var$8
+        (i64.add
+         (local.get $var$1)
+         (i64.const -1)
+        )
+       )
+       (loop $label$15
+        (local.set $var$5
+         (i64.sub
+          (local.tee $var$5
+           (i64.or
+            (i64.shl
+             (local.get $var$5)
+             (i64.const 1)
+            )
+            (i64.shr_u
+             (local.get $var$0)
+             (i64.const 63)
+            )
+           )
+          )
+          (i64.and
+           (local.tee $var$6
+            (i64.shr_s
+             (i64.sub
+              (local.get $var$8)
+              (local.get $var$5)
+             )
+             (i64.const 63)
+            )
+           )
+           (local.get $var$1)
+          )
+         )
+        )
+        (local.set $var$0
+         (i64.or
+          (i64.shl
+           (local.get $var$0)
+           (i64.const 1)
+          )
+          (local.get $var$7)
+         )
+        )
+        (local.set $var$7
+         (local.tee $var$6
+          (i64.and
+           (local.get $var$6)
+           (i64.const 1)
+          )
+         )
+        )
+        (br_if $label$15
+         (local.tee $var$2
+          (i32.add
+           (local.get $var$2)
+           (i32.const -1)
+          )
+         )
+        )
+       )
+       (br $label$13)
+      )
+     )
+    )
+    (global.set $__wasm-intrinsics-temp-i64
+     (local.get $var$5)
+    )
+    (return
+     (i64.or
+      (i64.shl
+       (local.get $var$0)
+       (i64.const 1)
+      )
+      (local.get $var$6)
+     )
+    )
+   )
+   (global.set $__wasm-intrinsics-temp-i64
+    (local.get $var$0)
+   )
+   (local.set $var$0
+    (i64.const 0)
+   )
+  )
+  (local.get $var$0)
+ )
+ (func $_ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE (; 15 ;) (type $0) (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $var$2 i32)
+  (local $var$3 i32)
+  (local $var$4 i32)
+  (local $var$5 i32)
+  (local $var$6 i32)
+  (i64.or
+   (i64.shl
+    (i64.extend_i32_u
+     (i32.add
+      (i32.add
+       (i32.add
+        (i32.add
+         (i32.mul
+          (local.tee $var$4
+           (i32.shr_u
+            (local.tee $var$2
+             (i32.wrap_i64
+              (local.get $var$1)
+             )
+            )
+            (i32.const 16)
+           )
+          )
+          (local.tee $var$5
+           (i32.shr_u
+            (local.tee $var$3
+             (i32.wrap_i64
+              (local.get $var$0)
+             )
+            )
+            (i32.const 16)
+           )
+          )
+         )
+         (i32.mul
+          (local.get $var$2)
+          (i32.wrap_i64
+           (i64.shr_u
+            (local.get $var$0)
+            (i64.const 32)
+           )
+          )
+         )
+        )
+        (i32.mul
+         (i32.wrap_i64
+          (i64.shr_u
+           (local.get $var$1)
+           (i64.const 32)
+          )
+         )
+         (local.get $var$3)
+        )
+       )
+       (i32.shr_u
+        (local.tee $var$2
+         (i32.add
+          (i32.shr_u
+           (local.tee $var$6
+            (i32.mul
+             (local.tee $var$2
+              (i32.and
+               (local.get $var$2)
+               (i32.const 65535)
+              )
+             )
+             (local.tee $var$3
+              (i32.and
+               (local.get $var$3)
+               (i32.const 65535)
+              )
+             )
+            )
+           )
+           (i32.const 16)
+          )
+          (i32.mul
+           (local.get $var$2)
+           (local.get $var$5)
+          )
+         )
+        )
+        (i32.const 16)
+       )
+      )
+      (i32.shr_u
+       (local.tee $var$2
+        (i32.add
+         (i32.and
+          (local.get $var$2)
+          (i32.const 65535)
+         )
+         (i32.mul
+          (local.get $var$4)
+          (local.get $var$3)
+         )
+        )
+       )
+       (i32.const 16)
+      )
+     )
+    )
+    (i64.const 32)
+   )
+   (i64.extend_i32_u
+    (i32.or
+     (i32.shl
+      (local.get $var$2)
+      (i32.const 16)
+     )
+     (i32.and
+      (local.get $var$6)
+      (i32.const 65535)
+     )
+    )
+   )
+  )
+ )
+ (func $_ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E (; 16 ;) (type $0) (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $var$2 i64)
+  (i64.sub
+   (i64.xor
+    (i64.div_u
+     (i64.sub
+      (i64.xor
+       (local.tee $var$2
+        (i64.shr_s
+         (local.get $var$0)
+         (i64.const 63)
+        )
+       )
+       (local.get $var$0)
+      )
+      (local.get $var$2)
+     )
+     (i64.sub
+      (i64.xor
+       (local.tee $var$2
+        (i64.shr_s
+         (local.get $var$1)
+         (i64.const 63)
+        )
+       )
+       (local.get $var$1)
+      )
+      (local.get $var$2)
+     )
+    )
+    (local.tee $var$0
+     (i64.shr_s
+      (i64.xor
+       (local.get $var$1)
+       (local.get $var$0)
+      )
+      (i64.const 63)
+     )
+    )
+   )
+   (local.get $var$0)
+  )
+ )
+ (func $_ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E (; 17 ;) (type $0) (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $var$2 i64)
+  (i64.sub
+   (i64.xor
+    (i64.rem_u
+     (i64.sub
+      (i64.xor
+       (local.tee $var$2
+        (i64.shr_s
+         (local.get $var$0)
+         (i64.const 63)
+        )
+       )
+       (local.get $var$0)
+      )
+      (local.get $var$2)
+     )
+     (i64.sub
+      (i64.xor
+       (local.tee $var$0
+        (i64.shr_s
+         (local.get $var$1)
+         (i64.const 63)
+        )
+       )
+       (local.get $var$1)
+      )
+      (local.get $var$0)
+     )
+    )
+    (local.get $var$2)
+   )
+   (local.get $var$2)
+  )
+ )
+ ;; custom section "linking", size 3
+)
diff --git a/binaryen/src/pretty_printing.h b/binaryen/src/pretty_printing.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/pretty_printing.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// Pretty printing helpers
+//
+
+#ifndef wasm_pretty_printing_h
+#define wasm_pretty_printing_h
+
+#include <ostream>
+
+#include "support/colors.h"
+
+inline std::ostream& doIndent(std::ostream& o, unsigned indent) {
+  for (unsigned i = 0; i < indent; i++) {
+    o << " ";
+  }
+  return o;
+}
+
+inline std::ostream& prepareMajorColor(std::ostream& o) {
+  Colors::red(o);
+  Colors::bold(o);
+  return o;
+}
+
+inline std::ostream& prepareColor(std::ostream& o) {
+  Colors::magenta(o);
+  Colors::bold(o);
+  return o;
+}
+
+inline std::ostream& prepareMinorColor(std::ostream& o) {
+  Colors::orange(o);
+  return o;
+}
+
+inline std::ostream& restoreNormalColor(std::ostream& o) {
+  Colors::normal(o);
+  return o;
+}
+
+inline std::ostream& printText(std::ostream& o, const char* str) {
+  o << '"';
+  Colors::green(o);
+  o << str;
+  Colors::normal(o);
+  return o << '"';
+}
+
+inline std::ostream&
+printMajor(std::ostream& o, const char* str, bool major = false) {
+  prepareMajorColor(o);
+  o << str;
+  restoreNormalColor(o);
+  return o;
+}
+
+inline std::ostream&
+printMedium(std::ostream& o, const char* str, bool major = false) {
+  prepareColor(o);
+  o << str;
+  restoreNormalColor(o);
+  return o;
+}
+
+inline std::ostream& printMinor(std::ostream& o, const char* str) {
+  prepareMinorColor(o);
+  o << str;
+  restoreNormalColor(o);
+  return o;
+}
+
+#endif // wasm_pretty_printing_h
diff --git a/binaryen/src/shared-constants.h b/binaryen/src/shared-constants.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/shared-constants.h
@@ -0,0 +1,71 @@
+/*
+ * 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_shared_constants_h
+#define wasm_shared_constants_h
+
+#include "wasm.h"
+
+namespace wasm {
+
+extern Name WASM_CALL_CTORS;
+extern Name MEMORY_BASE;
+extern Name TABLE_BASE;
+extern Name STACK_POINTER;
+extern Name GET_TEMP_RET0;
+extern Name SET_TEMP_RET0;
+extern Name NEW_SIZE;
+extern Name MODULE;
+extern Name START;
+extern Name FUNC;
+extern Name PARAM;
+extern Name RESULT;
+extern Name MEMORY;
+extern Name DATA;
+extern Name PASSIVE;
+extern Name EXPORT;
+extern Name IMPORT;
+extern Name TABLE;
+extern Name ELEM;
+extern Name LOCAL;
+extern Name TYPE;
+extern Name CALL;
+extern Name CALL_IMPORT;
+extern Name CALL_INDIRECT;
+extern Name BLOCK;
+extern Name BR_IF;
+extern Name THEN;
+extern Name ELSE;
+extern Name _NAN;
+extern Name _INFINITY;
+extern Name NEG_INFINITY;
+extern Name NEG_NAN;
+extern Name CASE;
+extern Name BR;
+extern Name FUNCREF;
+extern Name FAKE_RETURN;
+extern Name MUT;
+extern Name SPECTEST;
+extern Name PRINT;
+extern Name EXIT;
+extern Name SHARED;
+extern Name EVENT;
+extern Name ATTR;
+extern Name ASSIGN_GOT_ENTRIES;
+
+} // namespace wasm
+
+#endif // wasm_shared_constants_h
diff --git a/binaryen/src/shell-interface.h b/binaryen/src/shell-interface.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/shell-interface.h
@@ -0,0 +1,240 @@
+/*
+ * 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.
+ */
+
+//
+// Implementation of the shell interpreter execution environment
+//
+
+#ifndef wasm_shell_interface_h
+#define wasm_shell_interface_h
+
+#include "asmjs/shared-constants.h"
+#include "ir/module-utils.h"
+#include "shared-constants.h"
+#include "support/name.h"
+#include "wasm-interpreter.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct ExitException {};
+struct TrapException {};
+
+struct ShellExternalInterface : ModuleInstance::ExternalInterface {
+  // The underlying memory can be accessed through unaligned pointers which
+  // isn't well-behaved in C++. WebAssembly nonetheless expects it to behave
+  // properly. Avoid emitting unaligned load/store by checking for alignment
+  // explicitly, and performing memcpy if unaligned.
+  //
+  // The allocated memory tries to have the same alignment as the memory being
+  // simulated.
+  class Memory {
+    // Use char because it doesn't run afoul of aliasing rules.
+    std::vector<char> memory;
+    template<typename T> static bool aligned(const char* address) {
+      static_assert(!(sizeof(T) & (sizeof(T) - 1)), "must be a power of 2");
+      return 0 == (reinterpret_cast<uintptr_t>(address) & (sizeof(T) - 1));
+    }
+    Memory(Memory&) = delete;
+    Memory& operator=(const Memory&) = delete;
+
+  public:
+    Memory() = default;
+    void resize(size_t newSize) {
+      // Ensure the smallest allocation is large enough that most allocators
+      // will provide page-aligned storage. This hopefully allows the
+      // interpreter's memory to be as aligned as the memory being simulated,
+      // ensuring that the performance doesn't needlessly degrade.
+      //
+      // The code is optimistic this will work until WG21's p0035r0 happens.
+      const size_t minSize = 1 << 12;
+      size_t oldSize = memory.size();
+      memory.resize(std::max(minSize, newSize));
+      if (newSize < oldSize && newSize < minSize) {
+        std::memset(&memory[newSize], 0, minSize - newSize);
+      }
+    }
+    template<typename T> void set(size_t address, T value) {
+      if (aligned<T>(&memory[address])) {
+        *reinterpret_cast<T*>(&memory[address]) = value;
+      } else {
+        std::memcpy(&memory[address], &value, sizeof(T));
+      }
+    }
+    template<typename T> T get(size_t address) {
+      if (aligned<T>(&memory[address])) {
+        return *reinterpret_cast<T*>(&memory[address]);
+      } else {
+        T loaded;
+        std::memcpy(&loaded, &memory[address], sizeof(T));
+        return loaded;
+      }
+    }
+  } memory;
+
+  std::vector<Name> table;
+
+  ShellExternalInterface() : memory() {}
+  virtual ~ShellExternalInterface() = default;
+
+  void init(Module& wasm, ModuleInstance& instance) override {
+    memory.resize(wasm.memory.initial * wasm::Memory::kPageSize);
+    table.resize(wasm.table.initial);
+  }
+
+  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)) {
+        TODO_SINGLE_COMPOUND(import->type);
+        switch (import->type.getBasic()) {
+          case Type::i32:
+            globals[import->name] = {Literal(int32_t(666))};
+            break;
+          case Type::i64:
+            globals[import->name] = {Literal(int64_t(666))};
+            break;
+          case Type::f32:
+            globals[import->name] = {Literal(float(666.6))};
+            break;
+          case Type::f64:
+            globals[import->name] = {Literal(double(666.6))};
+            break;
+          case Type::v128:
+            assert(false && "v128 not implemented yet");
+          case Type::funcref:
+          case Type::externref:
+          case Type::exnref:
+          case Type::anyref:
+          case Type::eqref:
+            globals[import->name] = {Literal::makeNull(import->type)};
+            break;
+          case Type::i31ref:
+            WASM_UNREACHABLE("TODO: i31ref");
+          case Type::none:
+          case Type::unreachable:
+            WASM_UNREACHABLE("unexpected type");
+        }
+      }
+    });
+    if (wasm.memory.imported() && wasm.memory.module == SPECTEST &&
+        wasm.memory.base == MEMORY) {
+      // imported memory has initial 1 and max 2
+      wasm.memory.initial = 1;
+      wasm.memory.max = 2;
+    }
+  }
+
+  Literals callImport(Function* import, LiteralList& arguments) override {
+    if (import->module == SPECTEST && import->base.startsWith(PRINT)) {
+      for (auto argument : arguments) {
+        std::cout << argument << " : " << argument.type << '\n';
+      }
+      return {};
+    } else if (import->module == ENV && import->base == EXIT) {
+      // XXX hack for torture tests
+      std::cout << "exit()\n";
+      throw ExitException();
+    }
+    Fatal() << "callImport: unknown import: " << import->module.str << "."
+            << import->name.str;
+  }
+
+  Literals callTable(Index index,
+                     Signature sig,
+                     LiteralList& arguments,
+                     Type results,
+                     ModuleInstance& instance) override {
+    if (index >= table.size()) {
+      trap("callTable overflow");
+    }
+    auto* func = instance.wasm.getFunctionOrNull(table[index]);
+    if (!func) {
+      trap("uninitialized table element");
+    }
+    if (sig != func->sig) {
+      trap("callIndirect: function signatures don't match");
+    }
+    if (func->sig.params.size() != arguments.size()) {
+      trap("callIndirect: bad # of arguments");
+    }
+    size_t i = 0;
+    for (const auto& param : func->sig.params) {
+      if (!Type::isSubType(arguments[i++].type, param)) {
+        trap("callIndirect: bad argument type");
+      }
+    }
+    if (func->sig.results != results) {
+      trap("callIndirect: bad result type");
+    }
+    if (func->imported()) {
+      return callImport(func, arguments);
+    } else {
+      return instance.callFunctionInternal(func->name, arguments);
+    }
+  }
+
+  int8_t load8s(Address addr) override { return memory.get<int8_t>(addr); }
+  uint8_t load8u(Address addr) override { return memory.get<uint8_t>(addr); }
+  int16_t load16s(Address addr) override { return memory.get<int16_t>(addr); }
+  uint16_t load16u(Address addr) override { return memory.get<uint16_t>(addr); }
+  int32_t load32s(Address addr) override { return memory.get<int32_t>(addr); }
+  uint32_t load32u(Address addr) override { return memory.get<uint32_t>(addr); }
+  int64_t load64s(Address addr) override { return memory.get<int64_t>(addr); }
+  uint64_t load64u(Address addr) override { return memory.get<uint64_t>(addr); }
+  std::array<uint8_t, 16> load128(Address addr) override {
+    return memory.get<std::array<uint8_t, 16>>(addr);
+  }
+
+  void store8(Address addr, int8_t value) override {
+    memory.set<int8_t>(addr, value);
+  }
+  void store16(Address addr, int16_t value) override {
+    memory.set<int16_t>(addr, value);
+  }
+  void store32(Address addr, int32_t value) override {
+    memory.set<int32_t>(addr, value);
+  }
+  void store64(Address addr, int64_t value) override {
+    memory.set<int64_t>(addr, value);
+  }
+  void store128(Address addr, const std::array<uint8_t, 16>& value) override {
+    memory.set<std::array<uint8_t, 16>>(addr, value);
+  }
+
+  void tableStore(Address addr, Name entry) override { table[addr] = entry; }
+
+  bool growMemory(Address /*oldSize*/, Address newSize) override {
+    // Apply a reasonable limit on memory size, 1GB, to avoid DOS on the
+    // interpreter.
+    if (newSize > 1024 * 1024 * 1024) {
+      return false;
+    }
+    memory.resize(newSize);
+    return true;
+  }
+
+  void trap(const char* why) override {
+    std::cout << "[trap " << why << "]\n";
+    throw TrapException();
+  }
+
+  void throwException(Literal exn) override { throw WasmException(exn); }
+};
+
+} // namespace wasm
+
+#endif // wasm_shell_interface_h
diff --git a/binaryen/src/support/CMakeLists.txt b/binaryen/src/support/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/CMakeLists.txt
@@ -0,0 +1,15 @@
+FILE(GLOB support_HEADERS *.h)
+set(support_SOURCES
+  archive.cpp
+  bits.cpp
+  colors.cpp
+  command-line.cpp
+  debug.cpp
+  file.cpp
+  path.cpp
+  safe_integer.cpp
+  threads.cpp
+  utilities.cpp
+  ${support_HEADERS}
+)
+add_library(support OBJECT ${support_SOURCES})
diff --git a/binaryen/src/support/alloc.h b/binaryen/src/support/alloc.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/alloc.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 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.
+ */
+
+//
+// Allocation helpers
+//
+
+#ifndef wasm_support_alloc_h
+#define wasm_support_alloc_h
+
+#include <stdlib.h>
+
+#if defined(WIN32) || defined(_WIN32)
+#include <malloc.h>
+#endif
+
+namespace wasm {
+
+// An allocation of a specific size and a minimum alignment. Must be freed
+// with aligned_free. Returns nullptr on failure.
+inline void* aligned_malloc(size_t align, size_t size) {
+#if defined(WIN32) || defined(_WIN32)
+  _set_errno(0);
+  void* ret = _aligned_malloc(size, align);
+  if (errno == ENOMEM)
+    ret = nullptr;
+  return ret;
+#elif defined(__APPLE__) || !defined(_ISOC11_SOURCE)
+  void* ptr;
+  int result = posix_memalign(&ptr, align, size);
+  return result == 0 ? ptr : nullptr;
+#else
+  return aligned_alloc(align, size);
+#endif
+}
+
+inline void aligned_free(void* ptr) {
+#if defined(WIN32) || defined(_WIN32)
+  _aligned_free(ptr);
+#else
+  free(ptr);
+#endif
+}
+
+} // namespace wasm
+
+#endif // wasm_support_alloc_h
diff --git a/binaryen/src/support/archive.cpp b/binaryen/src/support/archive.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/archive.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "support/archive.h"
+
+#include "support/utilities.h"
+#include <cstring>
+
+static const char* const magic = "!<arch>\n";
+
+class ArchiveMemberHeader {
+public:
+  uint8_t fileName[16];
+  uint8_t timestamp[12];
+  uint8_t UID[6];
+  uint8_t GID[6];
+  uint8_t accessMode[8];
+  uint8_t size[10]; // Size of data only, not including padding or header
+  uint8_t magic[2];
+
+  std::string getName() const;
+  // Members are not larger than 4GB
+  uint32_t getSize() const;
+};
+
+std::string ArchiveMemberHeader::getName() const {
+  char endChar;
+  if (fileName[0] == '/') {
+    // Special name (string table or reference, or symbol table)
+    endChar = ' ';
+  } else {
+    endChar = '/'; // regular name
+  }
+  auto* end =
+    static_cast<const uint8_t*>(memchr(fileName, endChar, sizeof(fileName)));
+  if (!end) {
+    end = fileName + sizeof(fileName);
+  }
+  return std::string((char*)(fileName), end - fileName);
+}
+
+uint32_t ArchiveMemberHeader::getSize() const {
+  auto* end = static_cast<const char*>(memchr(size, ' ', sizeof(size)));
+  std::string sizeString((const char*)size, end);
+  auto sizeInt = std::stoll(sizeString, nullptr, 10);
+  if (sizeInt < 0 || sizeInt >= std::numeric_limits<uint32_t>::max()) {
+    wasm::Fatal() << "Malformed archive: size parsing failed\n";
+  }
+  return static_cast<uint32_t>(sizeInt);
+}
+
+Archive::Archive(Buffer& b, bool& error)
+  : data(b), symbolTable({nullptr, 0}), stringTable({nullptr, 0}),
+    firstRegularData(nullptr) {
+  error = false;
+  if (data.size() < strlen(magic) ||
+      memcmp(data.data(), magic, strlen(magic))) {
+    error = true;
+    return;
+  }
+
+  // We require GNU format archives. So the first member may be named "/" and it
+  // points to the symbol table.  The next member may optionally be "//" and
+  // point to a string table if a filename is too large to fit in the 16-char
+  // name field of the header.
+  child_iterator it = child_begin(false);
+  if (it.hasError()) {
+    error = true;
+    return;
+  }
+  child_iterator end = child_end();
+  if (it == end) {
+    return; // Empty archive.
+  }
+
+  const Child* c = &*it;
+
+  auto increment = [&]() {
+    ++it;
+    error = it.hasError();
+    if (error) {
+      return true;
+    }
+    c = &*it;
+    return false;
+  };
+
+  std::string name = c->getRawName();
+  if (name == "/") {
+    symbolTable = c->getBuffer();
+    if (increment() || it == end) {
+      return;
+    }
+    name = c->getRawName();
+  }
+
+  if (name == "//") {
+    stringTable = c->getBuffer();
+    if (increment() || it == end) {
+      return;
+    }
+    setFirstRegular(*c);
+    return;
+  }
+  if (name[0] != '/') {
+    setFirstRegular(*c);
+    return;
+  }
+  // Not a GNU archive.
+  error = true;
+}
+
+Archive::Child::Child(const Archive* parent, const uint8_t* data, bool* error)
+  : parent(parent), data(data) {
+  if (!data) {
+    return;
+  }
+  len = sizeof(ArchiveMemberHeader) + getHeader()->getSize();
+  startOfFile = sizeof(ArchiveMemberHeader);
+}
+
+uint32_t Archive::Child::getSize() const { return len - startOfFile; }
+
+Archive::SubBuffer Archive::Child::getBuffer() const {
+  return {data + startOfFile, getSize()};
+}
+
+std::string Archive::Child::getRawName() const {
+  return getHeader()->getName();
+}
+
+Archive::Child Archive::Child::getNext(bool& error) const {
+  // Members are aligned to even byte boundaries.
+  uint32_t nextOffset = len + (len & 1);
+  if ((size_t)(data - (const uint8_t*)parent->data.data() + nextOffset) >=
+      parent->data.size()) { // End of the archive.
+    return Child();
+  }
+  return Child(parent, data + nextOffset, &error);
+}
+
+std::string Archive::Child::getName() const {
+  std::string name = getRawName();
+  // Check if it's a special name.
+  if (name[0] == '/') {
+    if (name.size() == 1) { // Linker member.
+      return name;
+    }
+    if (name.size() == 2 && name[1] == '/') { // String table.
+      return name;
+    }
+    // It's a long name.
+    // Get the offset.
+    int offset = std::stoi(name.substr(1), nullptr, 10);
+
+    // Verify it.
+    if (offset < 0 || (unsigned)offset >= parent->stringTable.len) {
+      wasm::Fatal() << "Malformed archive: name parsing failed\n";
+    }
+
+    std::string addr(parent->stringTable.data + offset,
+                     parent->stringTable.data + parent->stringTable.len);
+
+    // GNU long file names end with a "/\n".
+    size_t end = addr.find('\n');
+    return addr.substr(0, end - 1);
+  }
+  // It's a simple name.
+  if (name[name.size() - 1] == '/') {
+    return name.substr(0, name.size() - 1);
+  }
+  return name;
+}
+
+Archive::child_iterator Archive::child_begin(bool SkipInternal) const {
+  if (data.size() == 0) {
+    return child_end();
+  }
+
+  if (SkipInternal) {
+    child_iterator it;
+    it.child = Child(this, firstRegularData, &it.error);
+    return it;
+  }
+
+  auto* loc = (const uint8_t*)data.data() + strlen(magic);
+  child_iterator it;
+  it.child = Child(this, loc, &it.error);
+  return it;
+}
+
+Archive::child_iterator Archive::child_end() const { return Child(); }
+
+namespace {
+struct Symbol {
+  uint32_t symbolIndex;
+  uint32_t stringIndex;
+  void next(Archive::SubBuffer& symbolTable) {
+    // Symbol table entries are NUL-terminated. Skip past the next NUL.
+    stringIndex = strchr((char*)symbolTable.data + stringIndex, '\0') -
+                  (char*)symbolTable.data + 1;
+    ++symbolIndex;
+  }
+};
+} // namespace
+
+static uint32_t read32be(const uint8_t* buf) {
+  return static_cast<uint32_t>(buf[0]) << 24 |
+         static_cast<uint32_t>(buf[1]) << 16 |
+         static_cast<uint32_t>(buf[2]) << 8 | static_cast<uint32_t>(buf[3]);
+}
+
+void Archive::dump() const {
+  printf("Archive data %p len %zu, firstRegularData %p\n",
+         data.data(),
+         data.size(),
+         firstRegularData);
+  printf("Symbol table %p, len %u\n", symbolTable.data, symbolTable.len);
+  printf("string table %p, len %u\n", stringTable.data, stringTable.len);
+  const uint8_t* buf = symbolTable.data;
+  if (!buf) {
+    for (auto c = child_begin(), e = child_end(); c != e; ++c) {
+      printf("Child %p, len %u, name %s, size %u\n",
+             c->data,
+             c->len,
+             c->getName().c_str(),
+             c->getSize());
+    }
+    return;
+  }
+  uint32_t symbolCount = read32be(buf);
+  printf("Symbol count %u\n", symbolCount);
+  buf += sizeof(uint32_t) + (symbolCount * sizeof(uint32_t));
+  uint32_t string_start_offset = buf - symbolTable.data;
+  Symbol sym = {0, string_start_offset};
+  while (sym.symbolIndex != symbolCount) {
+    printf("Symbol %u, offset %u\n", sym.symbolIndex, sym.stringIndex);
+    // get the member
+    uint32_t offset = read32be(symbolTable.data + sym.symbolIndex * 4);
+    auto* loc = (const uint8_t*)&data[offset];
+    child_iterator it;
+    it.child = Child(this, loc, &it.error);
+    printf("Child %p, len %u\n", it.child.data, it.child.len);
+  }
+}
diff --git a/binaryen/src/support/archive.h b/binaryen/src/support/archive.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/archive.h
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+/* Minimal class for interacting with archives. The API is inspired by LLVM's
+ * Archive class, (in case we want to switch to using that at some point);
+ * however we are missing useful error-handling capabilities and other utilities
+ * that LLVM has (e.g. ErrorOr, MemoryBuffer, StringRef).
+ * We only support the GNU format (not the BSD or COFF variants)
+ */
+
+#ifndef wasm_support_archive_h
+#define wasm_support_archive_h
+
+#include <cstdint>
+#include <vector>
+
+#include "wasm.h"
+
+class ArchiveMemberHeader;
+
+class Archive {
+  // Vector is char instead of uint8_t because read_file only works with char.
+  // Everything else is uint8_t to help distinguish between uses as
+  // uninterpreted bytes (most uses) and C strings (a few uses e.g. strchr)
+  // because most things in these buffers are not nul-terminated
+  using Buffer = std::vector<char>;
+
+public:
+  struct SubBuffer {
+    const uint8_t* data;
+    uint32_t len;
+  };
+  class Child {
+    friend class Archive;
+    const Archive* parent = nullptr;
+    // Includes header but not padding byte.
+    const uint8_t* data = nullptr;
+    uint32_t len = 0;
+    // Offset from data to the start of the file
+    uint16_t startOfFile = 0;
+    const ArchiveMemberHeader* getHeader() const {
+      return reinterpret_cast<const ArchiveMemberHeader*>(data);
+    }
+    Child getNext(bool& error) const;
+
+  public:
+    Child(){};
+    Child(const Archive* parent, const uint8_t* data, bool* error);
+    // Size of actual member data (no header/padding)
+    uint32_t getSize() const;
+    SubBuffer getBuffer() const;
+    std::string getRawName() const;
+    std::string getName() const;
+    bool operator==(const Child& other) const { return data == other.data; }
+  };
+  class child_iterator {
+    friend class Archive;
+    Child child;
+    bool error = false; // TODO: use std::error_code instead?
+  public:
+    child_iterator() = default;
+    explicit child_iterator(bool error) : error(error) {}
+    child_iterator(const Child& c) : child(c) {}
+    const Child* operator->() const { return &child; }
+    const Child& operator*() const { return child; }
+    bool operator==(const child_iterator& other) const {
+      return child == other.child;
+    }
+    bool operator!=(const child_iterator& other) const {
+      return !(*this == other);
+    }
+    child_iterator& operator++() {
+      assert(!error);
+      child = child.getNext(error);
+      return *this;
+    }
+    bool hasError() const { return error; }
+  };
+  Archive(Buffer& buffer, bool& error);
+  child_iterator child_begin(bool SkipInternal = true) const;
+  child_iterator child_end() const;
+  void dump() const;
+
+private:
+  void setFirstRegular(const Child& c) { firstRegularData = c.data; }
+  Buffer& data;
+  SubBuffer symbolTable;
+  SubBuffer stringTable;
+  const uint8_t* firstRegularData;
+};
+
+#endif // wasm_support_archive_h
diff --git a/binaryen/src/support/base64.h b/binaryen/src/support/base64.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/base64.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2019 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_base64_h
+#define wasm_support_base64_h
+
+#include <cassert>
+#include <string>
+#include <vector>
+
+inline std::string base64Encode(std::vector<char>& data) {
+  std::string ret;
+  size_t i = 0;
+
+  const char* alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                         "abcdefghijklmnopqrstuvwxyz"
+                         "0123456789+/";
+
+  while (i + 3 <= data.size()) {
+    uint32_t bits = (((uint32_t)(uint8_t)data[i + 0]) << 16) |
+                    (((uint32_t)(uint8_t)data[i + 1]) << 8) |
+                    (((uint32_t)(uint8_t)data[i + 2]) << 0);
+    ret += alphabet[(bits >> 18) & 0x3f];
+    ret += alphabet[(bits >> 12) & 0x3f];
+    ret += alphabet[(bits >> 6) & 0x3f];
+    ret += alphabet[(bits >> 0) & 0x3f];
+    i += 3;
+  }
+
+  if (i + 2 == data.size()) {
+    uint32_t bits = (((uint32_t)(uint8_t)data[i + 0]) << 8) |
+                    (((uint32_t)(uint8_t)data[i + 1]) << 0);
+    ret += alphabet[(bits >> 10) & 0x3f];
+    ret += alphabet[(bits >> 4) & 0x3f];
+    ret += alphabet[(bits << 2) & 0x3f];
+    ret += '=';
+  } else if (i + 1 == data.size()) {
+    uint32_t bits = (uint32_t)(uint8_t)data[i + 0];
+    ret += alphabet[(bits >> 2) & 0x3f];
+    ret += alphabet[(bits << 4) & 0x3f];
+    ret += '=';
+    ret += '=';
+  } else {
+    assert(i == data.size());
+  }
+
+  return ret;
+}
+
+#endif // wasm_support_base64_h
diff --git a/binaryen/src/support/bits.cpp b/binaryen/src/support/bits.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/bits.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2015 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "support/bits.h"
+#include "../compiler-support.h"
+#include "support/utilities.h"
+
+#ifdef _MSC_VER
+#include <intrin.h>
+#endif
+
+namespace wasm {
+
+namespace Bits {
+
+int popCount(uint8_t v) {
+  // Small table lookup.
+  static const uint8_t tbl[32] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2,
+                                  3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3,
+                                  3, 4, 2, 3, 3, 4, 3, 4, 4, 5};
+  return tbl[v & 0xf] + tbl[v >> 4];
+}
+
+int popCount(uint16_t v) {
+#if __has_builtin(__builtin_popcount) || defined(__GNUC__)
+  return __builtin_popcount(v);
+#else
+  return popCount((uint8_t)(v & 0xFF)) + popCount((uint8_t)(v >> 8));
+#endif
+}
+
+int popCount(uint32_t v) {
+#if __has_builtin(__builtin_popcount) || defined(__GNUC__)
+  return __builtin_popcount(v);
+#else
+  // See Stanford bithacks, counting bits set in parallel, "best method":
+  // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
+  v = v - ((v >> 1) & 0x55555555);
+  v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
+  return (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
+#endif
+}
+
+int popCount(uint64_t v) {
+#if __has_builtin(__builtin_popcount) || defined(__GNUC__)
+  return __builtin_popcountll(v);
+#else
+  return popCount((uint32_t)v) + popCount((uint32_t)(v >> 32));
+#endif
+}
+
+uint32_t bitReverse(uint32_t v) {
+  // See Hacker's Delight, first edition, figure 7-1.
+  v = ((v & 0x55555555) << 1) | ((v >> 1) & 0x55555555);
+  v = ((v & 0x33333333) << 2) | ((v >> 2) & 0x33333333);
+  v = ((v & 0x0F0F0F0F) << 4) | ((v >> 4) & 0x0F0F0F0F);
+  v = (v << 24) | ((v & 0xFF00) << 8) | ((v >> 8) & 0xFF00) | (v >> 24);
+  return v;
+}
+
+int countTrailingZeroes(uint32_t v) {
+  if (v == 0) {
+    return 32;
+  }
+#if __has_builtin(__builtin_ctz) || defined(__GNUC__)
+  return __builtin_ctz(v);
+#elif defined(_MSC_VER)
+  unsigned long count;
+  _BitScanForward(&count, v);
+  return (int)count;
+#else
+  // See Stanford bithacks, count the consecutive zero bits (trailing) on the
+  // right with multiply and lookup:
+  // http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup
+  static const uint8_t tbl[32] = {0,  1,  28, 2,  29, 14, 24, 3,  30, 22, 20,
+                                  15, 25, 17, 4,  8,  31, 27, 13, 23, 21, 19,
+                                  16, 7,  26, 12, 18, 6,  11, 5,  10, 9};
+  return (int)tbl[((uint32_t)((v & -v) * 0x077CB531U)) >> 27];
+#endif
+}
+
+int countTrailingZeroes(uint64_t v) {
+  if (v == 0) {
+    return 64;
+  }
+#if __has_builtin(__builtin_ctzll) || defined(__GNUC__)
+  return __builtin_ctzll(v);
+#elif defined(_MSC_VER) && defined(_M_X64)
+  unsigned long count;
+  _BitScanForward64(&count, v);
+  return (int)count;
+#else
+  return (uint32_t)v ? countTrailingZeroes((uint32_t)v)
+                     : 32 + countTrailingZeroes((uint32_t)(v >> 32));
+#endif
+}
+
+int countLeadingZeroes(uint32_t v) {
+  if (v == 0) {
+    return 32;
+  }
+#if __has_builtin(__builtin_clz) || defined(__GNUC__)
+  return __builtin_clz(v);
+#elif defined(_MSC_VER)
+  unsigned long count;
+  _BitScanReverse(&count, v);
+  // BitScanReverse gives the bit position (0 for the LSB, then 1, etc.) of the
+  // first bit that is 1, when looking from the MSB. To count leading zeros, we
+  // need to adjust that.
+  return 31 - int(count);
+#else
+  // See Stanford bithacks, find the log base 2 of an N-bit integer in
+  // O(lg(N)) operations with multiply and lookup:
+  // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn
+  static const uint8_t tbl[32] = {31, 22, 30, 21, 18, 10, 29, 2,  20, 17, 15,
+                                  13, 9,  6,  28, 1,  23, 19, 11, 3,  16, 14,
+                                  7,  24, 12, 4,  8,  25, 5,  26, 27, 0};
+  v = v | (v >> 1);
+  v = v | (v >> 2);
+  v = v | (v >> 4);
+  v = v | (v >> 8);
+  v = v | (v >> 16);
+  return (int)tbl[((uint32_t)(v * 0x07C4ACDDU)) >> 27];
+#endif
+}
+
+int countLeadingZeroes(uint64_t v) {
+  if (v == 0) {
+    return 64;
+  }
+#if __has_builtin(__builtin_clzll) || defined(__GNUC__)
+  return __builtin_clzll(v);
+#elif defined(_MSC_VER) && defined(_M_X64)
+  unsigned long count;
+  _BitScanReverse64(&count, v);
+  return 63 - int(count);
+#else
+  return v >> 32 ? countLeadingZeroes((uint32_t)(v >> 32))
+                 : 32 + countLeadingZeroes((uint32_t)v);
+#endif
+}
+
+int ceilLog2(uint32_t v) { return 32 - countLeadingZeroes(v - 1); }
+
+int ceilLog2(uint64_t v) { return 64 - countLeadingZeroes(v - 1); }
+
+uint32_t log2(uint32_t v) {
+  if (!isPowerOf2(v)) {
+    WASM_UNREACHABLE("value should be a power of two");
+  }
+  return 31 - countLeadingZeroes(v);
+}
+
+uint32_t pow2(uint32_t v) { return 1 << v; }
+
+} // namespace Bits
+
+} // namespace wasm
diff --git a/binaryen/src/support/bits.h b/binaryen/src/support/bits.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/bits.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2015 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_bits_h
+#define wasm_support_bits_h
+
+#include <climits>
+#include <cstdint>
+#include <type_traits>
+
+/*
+ * Portable bit functions.
+ *
+ * Not all platforms offer fast intrinsics for these functions, and some
+ * compilers require checking CPUID at runtime before using the intrinsic.
+ *
+ * We instead use portable and reasonably-fast implementations, while
+ * avoiding implementations with large lookup tables.
+ */
+
+namespace wasm {
+
+namespace Bits {
+
+int popCount(uint8_t);
+int popCount(uint16_t);
+int popCount(uint32_t);
+int popCount(uint64_t);
+
+inline int popCount(int8_t v) { return popCount(uint8_t(v)); }
+inline int popCount(int16_t v) { return popCount(uint16_t(v)); }
+inline int popCount(int32_t v) { return popCount(uint32_t(v)); }
+inline int popCount(int64_t v) { return popCount(uint64_t(v)); }
+
+uint32_t bitReverse(uint32_t);
+
+int countTrailingZeroes(uint32_t);
+int countTrailingZeroes(uint64_t);
+
+inline int countTrailingZeroes(int32_t v) {
+  return countTrailingZeroes(uint32_t(v));
+}
+inline int countTrailingZeroes(int64_t v) {
+  return countTrailingZeroes(uint64_t(v));
+}
+
+int countLeadingZeroes(uint32_t);
+int countLeadingZeroes(uint64_t);
+
+inline int countLeadingZeroes(int32_t v) {
+  return countLeadingZeroes(uint32_t(v));
+}
+inline int countLeadingZeroes(int64_t v) {
+  return countLeadingZeroes(uint64_t(v));
+}
+
+int ceilLog2(uint32_t);
+int ceilLog2(uint64_t);
+
+inline int ceilLog2(int32_t v) { return ceilLog2(uint32_t(v)); }
+inline int ceilLog2(int64_t v) { return ceilLog2(uint64_t(v)); }
+
+template<typename T> bool isPowerOf2(T v) {
+  return v != 0 && (v & (v - 1)) == 0;
+}
+
+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;
+  count &= mask;
+  return (value << count) | (value >> (-count & mask));
+}
+template<typename T, typename U> inline static T rotateRight(T val, U count) {
+  auto value = typename std::make_unsigned<T>::type(val);
+  U mask = sizeof(T) * CHAR_BIT - 1;
+  count &= mask;
+  return (value >> count) | (value << (-count & mask));
+}
+
+uint32_t log2(uint32_t v);
+uint32_t pow2(uint32_t v);
+
+} // namespace Bits
+
+} // namespace wasm
+
+#endif // wasm_support_bits_h
diff --git a/binaryen/src/support/colors.cpp b/binaryen/src/support/colors.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/colors.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "support/colors.h"
+
+#include <cstdlib>
+#include <ostream>
+
+namespace {
+bool colors_enabled = true;
+} // anonymous namespace
+
+void Colors::setEnabled(bool enabled) { colors_enabled = enabled; }
+bool Colors::isEnabled() { return colors_enabled; }
+
+#if defined(__linux__) || defined(__APPLE__)
+#include <unistd.h>
+
+void Colors::outputColorCode(std::ostream& stream, const char* colorCode) {
+  const static bool has_color = []() {
+    return (getenv("COLORS") && getenv("COLORS")[0] == '1') || // forced
+           (isatty(STDOUT_FILENO) &&
+            (!getenv("COLORS") || getenv("COLORS")[0] != '0')); // implicit
+  }();
+  if (has_color && colors_enabled) {
+    stream << colorCode;
+  }
+}
+#elif defined(_WIN32)
+#include <io.h>
+#include <iostream>
+#include <windows.h>
+
+void Colors::outputColorCode(std::ostream& stream, const WORD& colorCode) {
+  const static bool has_color = []() {
+    return _isatty(_fileno(stdout)) &&
+           (!getenv("COLORS") || getenv("COLORS")[0] != '0'); // implicit
+  }();
+  static HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
+  static HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE);
+  if (has_color && colors_enabled)
+    SetConsoleTextAttribute(&stream == &std::cout ? hStdout : hStderr,
+                            colorCode);
+}
+#endif
diff --git a/binaryen/src/support/colors.h b/binaryen/src/support/colors.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/colors.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2015 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_color_h
+#define wasm_support_color_h
+
+#include <iosfwd>
+
+namespace Colors {
+void setEnabled(bool enabled);
+bool isEnabled();
+
+#if defined(__linux__) || defined(__APPLE__)
+void outputColorCode(std::ostream& stream, const char* colorCode);
+inline void normal(std::ostream& stream) { outputColorCode(stream, "\033[0m"); }
+inline void red(std::ostream& stream) { outputColorCode(stream, "\033[31m"); }
+inline void magenta(std::ostream& stream) {
+  outputColorCode(stream, "\033[35m");
+}
+inline void orange(std::ostream& stream) {
+  outputColorCode(stream, "\033[33m");
+}
+inline void grey(std::ostream& stream) { outputColorCode(stream, "\033[37m"); }
+inline void green(std::ostream& stream) { outputColorCode(stream, "\033[32m"); }
+inline void blue(std::ostream& stream) { outputColorCode(stream, "\033[34m"); }
+inline void bold(std::ostream& stream) { outputColorCode(stream, "\033[1m"); }
+#elif defined(_WIN32)
+void outputColorCode(std::ostream& stream, const unsigned short& colorCode);
+inline void normal(std::ostream& stream) { outputColorCode(stream, 0x07); }
+inline void red(std::ostream& stream) { outputColorCode(stream, 0x0c); }
+inline void magenta(std::ostream& stream) { outputColorCode(stream, 0x05); }
+inline void orange(std::ostream& stream) { outputColorCode(stream, 0x06); }
+inline void grey(std::ostream& stream) { outputColorCode(stream, 0x08); }
+inline void green(std::ostream& stream) { outputColorCode(stream, 0x02); }
+inline void blue(std::ostream& stream) { outputColorCode(stream, 0x09); }
+inline void bold(std::ostream& stream) { /* Do nothing */
+}
+#else
+inline void normal(std::ostream& stream) {}
+inline void red(std::ostream& stream) {}
+inline void magenta(std::ostream& stream) {}
+inline void orange(std::ostream& stream) {}
+inline void grey(std::ostream& stream) {}
+inline void green(std::ostream& stream) {}
+inline void blue(std::ostream& stream) {}
+inline void bold(std::ostream& stream) {}
+#endif
+} // namespace Colors
+
+#endif // wasm_support_color_h
diff --git a/binaryen/src/support/command-line.cpp b/binaryen/src/support/command-line.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/command-line.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2015 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "support/command-line.h"
+#include "config.h"
+#include "support/debug.h"
+
+using namespace wasm;
+
+#ifndef SCREEN_WIDTH
+#define SCREEN_WIDTH 80
+#endif
+
+void printWrap(std::ostream& os, int leftPad, const std::string& content) {
+  int len = content.size();
+  int space = SCREEN_WIDTH - leftPad;
+  std::string nextWord;
+  std::string pad(leftPad, ' ');
+  for (int i = 0; i <= len; ++i) {
+    if (i != len && content[i] != ' ' && content[i] != '\n') {
+      nextWord += content[i];
+    } else {
+      if (static_cast<int>(nextWord.size()) > space) {
+        os << '\n' << pad;
+        space = SCREEN_WIDTH - leftPad;
+      }
+      os << nextWord;
+      space -= nextWord.size() + 1;
+      if (space > 0) {
+        os << ' ';
+      }
+      nextWord.clear();
+      if (content[i] == '\n') {
+        os << '\n';
+        space = SCREEN_WIDTH - leftPad;
+      }
+    }
+  }
+}
+
+Options::Options(const std::string& command, const std::string& description)
+  : debug(false), positional(Arguments::Zero) {
+  add("--version",
+      "",
+      "Output version information and exit",
+      Arguments::Zero,
+      [command](Options*, const std::string&) {
+        std::cout << command << " version " << PROJECT_VERSION << "\n";
+        exit(0);
+      });
+  add("--help",
+      "-h",
+      "Show this help message and exit",
+      Arguments::Zero,
+      [this, command, description](Options* o, const std::string&) {
+        std::cout << command;
+        if (positional != Arguments::Zero) {
+          std::cout << ' ' << positionalName;
+        }
+        std::cout << "\n\n";
+        printWrap(std::cout, 0, description);
+        std::cout << "\n\nOptions:\n";
+        size_t optionWidth = 0;
+        for (const auto& o : options) {
+          optionWidth =
+            std::max(optionWidth, o.longName.size() + o.shortName.size());
+        }
+        for (const auto& o : options) {
+          bool long_n_short = o.longName.size() != 0 && o.shortName.size() != 0;
+          size_t pad = 1 + optionWidth - o.longName.size() - o.shortName.size();
+          std::cout << "  " << o.longName << (long_n_short ? ',' : ' ')
+                    << o.shortName << std::string(pad, ' ');
+          printWrap(std::cout, optionWidth + 4, o.description);
+          std::cout << '\n';
+        }
+        std::cout << '\n';
+        exit(EXIT_SUCCESS);
+      });
+  add("--debug",
+      "-d",
+      "Print debug information to stderr",
+      Arguments::Optional,
+      [&](Options* o, const std::string& arguments) {
+        debug = true;
+        setDebugEnabled(arguments.c_str());
+      });
+}
+
+Options::~Options() {}
+
+Options& Options::add(const std::string& longName,
+                      const std::string& shortName,
+                      const std::string& description,
+                      Arguments arguments,
+                      const Action& action) {
+  options.push_back({longName, shortName, description, arguments, action, 0});
+  return *this;
+}
+
+Options& Options::add_positional(const std::string& name,
+                                 Arguments arguments,
+                                 const Action& action) {
+  positional = arguments;
+  positionalName = name;
+  positionalAction = action;
+  return *this;
+}
+
+void Options::parse(int argc, const char* argv[]) {
+  assert(argc > 0 && "expect at least program name as an argument");
+  size_t positionalsSeen = 0;
+  auto dashes = [](const std::string& s) {
+    for (size_t i = 0;; ++i) {
+      if (s[i] != '-') {
+        return i;
+      }
+    }
+  };
+  for (size_t i = 1, e = argc; i != e; ++i) {
+    std::string currentOption = argv[i];
+
+    if (dashes(currentOption) == 0) {
+      // Positional.
+      switch (positional) {
+        case Arguments::Zero:
+          std::cerr << "Unexpected positional argument '" << currentOption
+                    << "'\n";
+          exit(EXIT_FAILURE);
+        case Arguments::One:
+        case Arguments::Optional:
+          if (positionalsSeen) {
+            std::cerr << "Unexpected second positional argument '"
+                      << currentOption << "' for " << positionalName << '\n';
+            exit(EXIT_FAILURE);
+          }
+        // Fallthrough.
+        case Arguments::N:
+          positionalAction(this, currentOption);
+          ++positionalsSeen;
+          break;
+      }
+      continue;
+    }
+
+    // Non-positional.
+    std::string argument;
+    auto equal = currentOption.find_first_of('=');
+    if (equal != std::string::npos) {
+      argument = currentOption.substr(equal + 1);
+      currentOption = currentOption.substr(0, equal);
+    }
+    Option* option = nullptr;
+    for (auto& o : options) {
+      if (o.longName == currentOption || o.shortName == currentOption) {
+        option = &o;
+      }
+    }
+    if (!option) {
+      std::cerr << "Unknown option '" << currentOption << "'\n";
+      exit(EXIT_FAILURE);
+    }
+    switch (option->arguments) {
+      case Arguments::Zero:
+        if (argument.size()) {
+          std::cerr << "Unexpected argument '" << argument << "' for option '"
+                    << currentOption << "'\n";
+          exit(EXIT_FAILURE);
+        }
+        break;
+      case Arguments::One:
+        if (option->seen) {
+          std::cerr << "Unexpected second argument '" << argument << "' for '"
+                    << currentOption << "'\n";
+          exit(EXIT_FAILURE);
+        }
+      // Fallthrough.
+      case Arguments::N:
+        if (!argument.size()) {
+          if (i + 1 == e) {
+            std::cerr << "Couldn't find expected argument for '"
+                      << currentOption << "'\n";
+            exit(EXIT_FAILURE);
+          }
+          argument = argv[++i];
+        }
+        break;
+      case Arguments::Optional:
+        if (!argument.size()) {
+          if (i + 1 != e) {
+            argument = argv[++i];
+          }
+        }
+        break;
+    }
+    option->action(this, argument);
+    ++option->seen;
+  }
+}
diff --git a/binaryen/src/support/command-line.h b/binaryen/src/support/command-line.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/command-line.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// Command line helpers.
+//
+
+#ifndef wasm_support_command_line_h
+#define wasm_support_command_line_h
+
+#include <functional>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "wasm.h"
+
+namespace wasm {
+
+class Options {
+public:
+  using Action = std::function<void(Options*, const std::string&)>;
+  enum class Arguments { Zero, One, N, Optional };
+
+  bool debug;
+  std::map<std::string, std::string> extra;
+
+  Options(const std::string& command, const std::string& description);
+  ~Options();
+  Options& add(const std::string& longName,
+               const std::string& shortName,
+               const std::string& description,
+               Arguments arguments,
+               const Action& action);
+  Options& add_positional(const std::string& name,
+                          Arguments arguments,
+                          const Action& action);
+  void parse(int argc, const char* argv[]);
+
+private:
+  struct Option {
+    std::string longName;
+    std::string shortName;
+    std::string description;
+    Arguments arguments;
+    Action action;
+    size_t seen;
+  };
+  std::vector<Option> options;
+  Arguments positional;
+  std::string positionalName;
+  Action positionalAction;
+};
+
+} // namespace wasm
+
+#endif // wasm_support_command_line_h
diff --git a/binaryen/src/support/debug.cpp b/binaryen/src/support/debug.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/debug.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "support/debug.h"
+
+#include <cstring>
+#include <set>
+#include <string>
+
+#ifndef NDEBUG
+
+static bool debugEnabled = false;
+static std::set<std::string> debugTypesEnabled;
+
+bool wasm::isDebugEnabled(const char* type) {
+  if (!debugEnabled) {
+    return false;
+  }
+  if (debugTypesEnabled.empty()) {
+    return true;
+  }
+  return debugTypesEnabled.count(type) > 0;
+}
+
+void wasm::setDebugEnabled(const char* types) {
+  debugEnabled = true;
+  // split types on comma and add each string to debugTypesEnabled
+  size_t start = 0;
+  size_t end = strlen(types);
+  while (start < end) {
+    const char* type_end = strchr(types + start, ',');
+    if (type_end == nullptr) {
+      type_end = types + end;
+    }
+    size_t type_size = type_end - (types + start);
+    std::string type(types + start, type_size);
+    debugTypesEnabled.insert(type);
+    start += type_size + 1;
+  }
+}
+
+#endif
diff --git a/binaryen/src/support/debug.h b/binaryen/src/support/debug.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/debug.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019 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 BYN_DEBUG macro similar to llvm's include/llvm/Support/Debug.h,
+// which can include any code, and in addition and printf-file BYN_TRACE.
+//
+// To use these macros you must define DEBUG_TYPE to a C string within your
+// source code which then acts as the name of a channel which can be
+// individually enabled via --debug=<chan>.  Specifying --debug without any
+// argument enables all channels.
+
+#ifndef wasm_support_debug_h
+#define wasm_support_debug_h
+
+#ifndef NDEBUG
+
+namespace wasm {
+bool isDebugEnabled(const char* type);
+void setDebugEnabled(const char* types);
+} // namespace wasm
+
+#define BYN_DEBUG_WITH_TYPE(TYPE, X)                                           \
+  do {                                                                         \
+    if (::wasm::isDebugEnabled(TYPE)) {                                        \
+      X;                                                                       \
+    }                                                                          \
+  } while (false)
+
+#define BYN_TRACE_WITH_TYPE(TYPE, MSG)                                         \
+  BYN_DEBUG_WITH_TYPE(TYPE, std::cerr << MSG);
+
+#else
+
+// We have an option to build with assertions disabled
+// BYN_ASSERTIONS_ENABLED=OFF, but we currently don't recommend using and we
+// don't test with it.
+#error "binaryen is currently designed to be built with assertions enabled."
+#error "remove these #errors if you want to build without them anyway."
+
+#define BYN_DEBUG_WITH_TYPE(...)                                               \
+  do {                                                                         \
+  } while (false)
+#define BYN_TRACE_WITH_TYPE(...)                                               \
+  do {                                                                         \
+  } while (false)
+#define isDebugEnabled(type) (false)
+#define setDebugEnabled(types)
+
+#endif
+
+#define BYN_DEBUG(X) BYN_DEBUG_WITH_TYPE(DEBUG_TYPE, X)
+#define BYN_TRACE(MSG) BYN_TRACE_WITH_TYPE(DEBUG_TYPE, MSG)
+
+#endif // wasm_support_debug_h
diff --git a/binaryen/src/support/file.cpp b/binaryen/src/support/file.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/file.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2015 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "support/file.h"
+#include "support/debug.h"
+
+#include <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <limits>
+
+#define DEBUG_TYPE "file"
+
+std::vector<char> wasm::read_stdin() {
+  BYN_TRACE("Loading stdin...\n");
+  std::vector<char> input;
+  char c;
+  while (std::cin.get(c) && !std::cin.eof()) {
+    input.push_back(c);
+  }
+  return input;
+}
+
+template<typename T>
+T wasm::read_file(const std::string& filename, Flags::BinaryOption binary) {
+  BYN_TRACE("Loading '" << filename << "'...\n");
+  std::ifstream infile;
+  std::ios_base::openmode flags = std::ifstream::in;
+  if (binary == Flags::Binary) {
+    flags |= std::ifstream::binary;
+  }
+  infile.open(filename, flags);
+  if (!infile.is_open()) {
+    std::cerr << "Failed opening '" << filename << "'" << std::endl;
+    exit(EXIT_FAILURE);
+  }
+  infile.seekg(0, std::ios::end);
+  std::streampos insize = infile.tellg();
+  if (uint64_t(insize) >= std::numeric_limits<size_t>::max()) {
+    // Building a 32-bit executable where size_t == 32 bits, we are not able to
+    // create strings larger than 2^32 bytes in length, so must abort here.
+    std::cerr << "Failed opening '" << filename
+              << "': Input file too large: " << insize
+              << " bytes. Try rebuilding in 64-bit mode." << std::endl;
+    exit(EXIT_FAILURE);
+  }
+  T input(size_t(insize) + (binary == Flags::Binary ? 0 : 1), '\0');
+  if (size_t(insize) == 0) {
+    return input;
+  }
+  infile.seekg(0);
+  infile.read(&input[0], insize);
+  if (binary == Flags::Text) {
+    size_t chars = size_t(infile.gcount());
+    // Truncate size to the number of ASCII characters actually read in text
+    // mode (which is generally less than the number of bytes on Windows, if
+    // \r\n line endings are present)
+    input.resize(chars + 1);
+    input[chars] = '\0';
+  }
+  return input;
+}
+
+std::string wasm::read_possible_response_file(const std::string& input) {
+  if (input.size() == 0 || input[0] != '@') {
+    return input;
+  }
+  return wasm::read_file<std::string>(input.substr(1), Flags::Text);
+}
+
+// Explicit instantiations for the explicit specializations.
+template std::string wasm::read_file<>(const std::string&, Flags::BinaryOption);
+template std::vector<char> wasm::read_file<>(const std::string&,
+                                             Flags::BinaryOption);
+
+wasm::Output::Output(const std::string& filename, Flags::BinaryOption binary)
+  : outfile(), out([this, filename, binary]() {
+      if (filename == "-") {
+        return std::cout.rdbuf();
+      }
+      std::streambuf* buffer;
+      if (filename.size()) {
+        BYN_TRACE("Opening '" << filename << "'\n");
+        auto flags = std::ofstream::out | std::ofstream::trunc;
+        if (binary == Flags::Binary) {
+          flags |= std::ofstream::binary;
+        }
+        outfile.open(filename, flags);
+        if (!outfile.is_open()) {
+          std::cerr << "Failed opening '" << filename << "'" << std::endl;
+          exit(EXIT_FAILURE);
+        }
+        buffer = outfile.rdbuf();
+      } else {
+        buffer = std::cout.rdbuf();
+      }
+      return buffer;
+    }()) {}
+
+void wasm::copy_file(std::string input, std::string output) {
+  std::ifstream src(input, std::ios::binary);
+  std::ofstream dst(output, std::ios::binary);
+  dst << src.rdbuf();
+}
+
+size_t wasm::file_size(std::string filename) {
+  std::ifstream infile(filename, std::ifstream::ate | std::ifstream::binary);
+  return infile.tellg();
+}
diff --git a/binaryen/src/support/file.h b/binaryen/src/support/file.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/file.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// FIle helpers.
+//
+
+#ifndef wasm_support_file_h
+#define wasm_support_file_h
+
+#include <fstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace wasm {
+
+namespace Flags {
+enum BinaryOption { Binary, Text };
+} // namespace Flags
+
+std::vector<char> read_stdin();
+
+template<typename T>
+T read_file(const std::string& filename, Flags::BinaryOption binary);
+
+// Declare the valid explicit specializations.
+extern template std::string read_file<>(const std::string&,
+                                        Flags::BinaryOption);
+extern template std::vector<char> read_file<>(const std::string&,
+                                              Flags::BinaryOption);
+
+// Given a string which may be a response file (i.e., a filename starting
+// with "@"), if it is a response file read it and return that, or if it
+// is not a response file, return it as is.
+std::string read_possible_response_file(const std::string&);
+
+class Output {
+public:
+  // An empty filename will open stdout instead.
+  Output(const std::string& filename, Flags::BinaryOption binary);
+  ~Output() = default;
+  template<typename T> std::ostream& operator<<(const T& v) { return out << v; }
+
+  std::ostream& getStream() { return out; }
+
+  std::ostream& write(const char* s, std::streamsize c) {
+    return out.write(s, c);
+  }
+
+private:
+  Output() = delete;
+  Output(const Output&) = delete;
+  Output& operator=(const Output&) = delete;
+  std::ofstream outfile;
+  std::ostream out;
+};
+
+// Copies a file to another file
+void copy_file(std::string input, std::string output);
+
+// Retusn the size of a file
+size_t file_size(std::string filename);
+
+} // namespace wasm
+
+#endif // wasm_support_file_h
diff --git a/binaryen/src/support/hash.h b/binaryen/src/support/hash.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/hash.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 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_hash_h
+#define wasm_support_hash_h
+
+#include <functional>
+#include <stdint.h>
+
+namespace wasm {
+
+// Computes the digest of `value`.
+template<typename T> inline std::size_t hash(const T& value) {
+  return std::hash<T>{}(value);
+}
+
+// Combines two digests into the first digest. Use instead of `rehash` if
+// `otherDigest` is another digest and not a `size_t` value.
+static inline void hash_combine(std::size_t& digest, std::size_t otherDigest) {
+  // see: boost/container_hash/hash.hpp
+  // The constant is the N-bits reciprocal of the golden ratio:
+  //  phi = (1 + sqrt(5)) / 2
+#if SIZE_MAX == UINT64_MAX
+  //  trunc(2^64 / phi) = 0x9e3779b97f4a7c15
+  digest ^= otherDigest + 0x9e3779b97f4a7c15 + (digest << 12) + (digest >> 4);
+#else
+  //  trunc(2^32 / phi) = 0x9e3779b9
+  digest ^= otherDigest + 0x9e3779b9 + (digest << 6) + (digest >> 2);
+#endif
+}
+
+// Hashes `value` and combines the resulting digest into the existing digest.
+// Use instead of `hash_combine` if `value` is not another digest.
+template<typename T> inline void rehash(std::size_t& digest, const T& value) {
+  hash_combine(digest, hash(value));
+}
+
+} // namespace wasm
+
+#endif // wasm_support_hash_h
diff --git a/binaryen/src/support/json.h b/binaryen/src/support/json.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/json.h
@@ -0,0 +1,410 @@
+/*
+ * 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.
+ */
+
+// An arena-free version of emscripten-optimizer/simple_ast.h's JSON
+// class TODO: use this instead of that
+
+#ifndef wasm_support_json_h
+#define wasm_support_json_h
+
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <iomanip>
+#include <iostream>
+#include <limits>
+#include <memory>
+#include <ostream>
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "emscripten-optimizer/istring.h"
+#include "support/safe_integer.h"
+
+namespace json {
+
+typedef cashew::IString IString;
+
+// Main value type
+struct Value {
+  struct Ref : public std::shared_ptr<Value> {
+    Ref() = default;
+    Ref(Value* value) : std::shared_ptr<Value>(value) {}
+
+    Ref& operator[](size_t x) { return (*this->get())[x]; }
+    Ref& operator[](IString x) { return (*this->get())[x]; }
+  };
+
+  enum Type {
+    String = 0,
+    Number = 1,
+    Array = 2,
+    Null = 3,
+    Bool = 4,
+    Object = 5,
+  };
+
+  Type type = Null;
+
+  typedef std::vector<Ref> ArrayStorage;
+  typedef std::unordered_map<IString, Ref> ObjectStorage;
+
+  // MSVC does not allow unrestricted unions:
+  // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
+#ifdef _MSC_VER
+  IString str;
+#endif
+  union { // TODO: optimize
+#ifndef _MSC_VER
+    IString str;
+#endif
+    double num = 0;
+    ArrayStorage* arr; // manually allocated/freed
+    bool boo;
+    ObjectStorage* obj; // manually allocated/freed
+    Ref ref;
+  };
+
+  // constructors all copy their input
+  Value() {}
+  explicit Value(const char* s) : type(Null) { setString(s); }
+  explicit Value(double n) : type(Null) { setNumber(n); }
+  explicit Value(ArrayStorage& a) : type(Null) {
+    setArray();
+    *arr = a;
+  }
+  // no bool constructor - would endanger the double one (int might convert the
+  // wrong way)
+
+  ~Value() { free(); }
+
+  void free() {
+    if (type == Array) {
+      delete arr;
+      arr = nullptr;
+    } else if (type == Object) {
+      delete obj;
+      obj = nullptr;
+    }
+    type = Null;
+    num = 0;
+  }
+
+  Value& setString(const char* s) {
+    free();
+    type = String;
+    str.set(s);
+    return *this;
+  }
+  Value& setString(const IString& s) {
+    free();
+    type = String;
+    str.set(s);
+    return *this;
+  }
+  Value& setNumber(double n) {
+    free();
+    type = Number;
+    num = n;
+    return *this;
+  }
+  Value& setArray(ArrayStorage& a) {
+    free();
+    type = Array;
+    arr = new ArrayStorage;
+    *arr = a;
+    return *this;
+  }
+  Value& setArray(size_t size_hint = 0) {
+    free();
+    type = Array;
+    arr = new ArrayStorage;
+    arr->reserve(size_hint);
+    return *this;
+  }
+  Value& setNull() {
+    free();
+    type = Null;
+    return *this;
+  }
+  Value&
+  setBool(bool b) { // Bool in the name, as otherwise might overload over int
+    free();
+    type = Bool;
+    boo = b;
+    return *this;
+  }
+  Value& setObject() {
+    free();
+    type = Object;
+    obj = new ObjectStorage();
+    return *this;
+  }
+
+  bool isString() { return type == String; }
+  bool isNumber() { return type == Number; }
+  bool isArray() { return type == Array; }
+  bool isNull() { return type == Null; }
+  bool isBool() { return type == Bool; }
+  bool isObject() { return type == Object; }
+
+  bool isBool(bool b) {
+    return type == Bool && b == boo;
+  } // avoid overloading == as it might overload over int
+
+  const char* getCString() {
+    assert(isString());
+    return str.str;
+  }
+  IString& getIString() {
+    assert(isString());
+    return str;
+  }
+  double& getNumber() {
+    assert(isNumber());
+    return num;
+  }
+  ArrayStorage& getArray() {
+    assert(isArray());
+    return *arr;
+  }
+  bool& getBool() {
+    assert(isBool());
+    return boo;
+  }
+
+  int32_t getInteger() { // convenience function to get a known integer
+    assert(wasm::isInteger(getNumber()));
+    int32_t ret = getNumber();
+    assert(double(ret) == getNumber()); // no loss in conversion
+    return ret;
+  }
+
+  Value& operator=(const Value& other) {
+    free();
+    switch (other.type) {
+      case String:
+        setString(other.str);
+        break;
+      case Number:
+        setNumber(other.num);
+        break;
+      case Array:
+        setArray(*other.arr);
+        break;
+      case Null:
+        setNull();
+        break;
+      case Bool:
+        setBool(other.boo);
+        break;
+      default:
+        abort(); // TODO
+    }
+    return *this;
+  }
+
+  bool operator==(const Value& other) {
+    if (type != other.type) {
+      return false;
+    }
+    switch (other.type) {
+      case String:
+        return str == other.str;
+      case Number:
+        return num == other.num;
+      case Array:
+        return this == &other; // if you want a deep compare, use deepCompare
+      case Null:
+        break;
+      case Bool:
+        return boo == other.boo;
+      case Object:
+        return this == &other; // if you want a deep compare, use deepCompare
+      default:
+        abort();
+    }
+    return true;
+  }
+
+  char* parse(char* curr) {
+#define is_json_space(x)                                                       \
+  (x == 32 || x == 9 || x == 10 ||                                             \
+   x == 13) /* space, tab, linefeed/newline, or return */
+#define skip()                                                                 \
+  {                                                                            \
+    while (*curr && is_json_space(*curr))                                      \
+      curr++;                                                                  \
+  }
+    skip();
+    if (*curr == '"') {
+      // String
+      curr++;
+      char* close = strchr(curr, '"');
+      assert(close);
+      *close = 0; // end this string, and reuse it straight from the input
+      setString(curr);
+      curr = close + 1;
+    } else if (*curr == '[') {
+      // Array
+      curr++;
+      skip();
+      setArray();
+      while (*curr != ']') {
+        Ref temp = Ref(new Value());
+        arr->push_back(temp);
+        curr = temp->parse(curr);
+        skip();
+        if (*curr == ']') {
+          break;
+        }
+        assert(*curr == ',');
+        curr++;
+        skip();
+      }
+      curr++;
+    } else if (*curr == 'n') {
+      // Null
+      assert(strncmp(curr, "null", 4) == 0);
+      setNull();
+      curr += 4;
+    } else if (*curr == 't') {
+      // Bool true
+      assert(strncmp(curr, "true", 4) == 0);
+      setBool(true);
+      curr += 4;
+    } else if (*curr == 'f') {
+      // Bool false
+      assert(strncmp(curr, "false", 5) == 0);
+      setBool(false);
+      curr += 5;
+    } else if (*curr == '{') {
+      // Object
+      curr++;
+      skip();
+      setObject();
+      while (*curr != '}') {
+        assert(*curr == '"');
+        curr++;
+        char* close = strchr(curr, '"');
+        assert(close);
+        *close = 0; // end this string, and reuse it straight from the input
+        IString key(curr);
+        curr = close + 1;
+        skip();
+        assert(*curr == ':');
+        curr++;
+        skip();
+        Ref value = Ref(new Value());
+        curr = value->parse(curr);
+        (*obj)[key] = value;
+        skip();
+        if (*curr == '}') {
+          break;
+        }
+        assert(*curr == ',');
+        curr++;
+        skip();
+      }
+      curr++;
+    } else {
+      // Number
+      char* after;
+      setNumber(strtod(curr, &after));
+      curr = after;
+    }
+    return curr;
+  }
+
+  void stringify(std::ostream& os, bool pretty = false);
+
+  // String operations
+
+  // Number operations
+
+  // Array operations
+
+  size_t size() {
+    assert(isArray());
+    return arr->size();
+  }
+
+  void setSize(size_t size) {
+    assert(isArray());
+    auto old = arr->size();
+    if (old != size) {
+      arr->resize(size);
+    }
+    if (old < size) {
+      for (auto i = old; i < size; i++) {
+        (*arr)[i] = Ref(new Value());
+      }
+    }
+  }
+
+  Ref& operator[](unsigned x) {
+    assert(isArray());
+    return (*arr)[x];
+  }
+
+  Value& push_back(Ref r) {
+    assert(isArray());
+    arr->push_back(r);
+    return *this;
+  }
+  Ref pop_back() {
+    assert(isArray());
+    Ref ret = arr->back();
+    arr->pop_back();
+    return ret;
+  }
+
+  Ref back() {
+    assert(isArray());
+    if (arr->size() == 0) {
+      return nullptr;
+    }
+    return arr->back();
+  }
+
+  // Null operations
+
+  // Bool operations
+
+  // Object operations
+
+  Ref& operator[](IString x) {
+    assert(isObject());
+    return (*obj)[x];
+  }
+
+  bool has(IString x) {
+    assert(isObject());
+    return obj->count(x) > 0;
+  }
+};
+
+typedef Value::Ref Ref;
+
+} // namespace json
+
+#endif // wasm_support_json_h
diff --git a/binaryen/src/support/learning.h b/binaryen/src/support/learning.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/learning.h
@@ -0,0 +1,112 @@
+/*
+ * 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_learning_h
+#define wasm_learning_h
+
+#include <algorithm>
+#include <random>
+
+namespace wasm {
+
+//
+// Machine learning using a genetic algorithm.
+//
+// The Genome class is the element on which to learn. It must
+// implement the following:
+//
+//  * Fitness getFitness(); - calculate how good this item is.
+//
+// The Generator must implement the following:
+//
+//  * Genome* makeRandom(); - make a random element
+//  * Genome* makeMixture(Genome* one, Genome* two); - make a new element by
+//    mixing two
+//
+// Fitness is the type of the fitness values, e.g. uint32_t. More is better.
+//
+// Typical usage of this class is to run call runGeneration(), check the best
+// quality using getBest()->getFitness(), and do that repeatedly until the
+// fitness is good enough. Then acquireBest() to get ownership of the best,
+// and the learner can be discarded (with all the rest of the population
+// cleaned up).
+
+template<typename Genome, typename Fitness, typename Generator>
+class GeneticLearner {
+  Generator& generator;
+
+  typedef std::unique_ptr<Genome> unique_ptr;
+  std::vector<unique_ptr> population;
+
+  void sort() {
+    std::sort(population.begin(),
+              population.end(),
+              [](const unique_ptr& left, const unique_ptr& right) {
+                return left->getFitness() > right->getFitness();
+              });
+  }
+
+  std::mt19937 noise;
+
+  size_t randomIndex() { return noise() % population.size(); }
+
+public:
+  GeneticLearner(Generator& generator, size_t size)
+    : generator(generator), noise(1337) {
+    population.resize(size);
+    for (size_t i = 0; i < size; i++) {
+      population[i] = unique_ptr(generator.makeRandom());
+    }
+    sort();
+  }
+
+  Genome* getBest() { return population[0].get(); }
+
+  unique_ptr acquireBest() { return population[0]; }
+
+  void runGeneration() {
+    size_t size = population.size();
+
+    // we have a mix of promoted from the last generation, mixed from the last
+    // generation, and random
+    const size_t promoted = (25 * size) / 100;
+    const size_t mixed = (50 * size) / 100;
+
+    // promoted just stay in place
+    // mixtures are computed, then added back in (as we still need them as we
+    // work)
+    std::vector<unique_ptr> mixtures;
+    mixtures.resize(mixed);
+    for (size_t i = 0; i < mixed; i++) {
+      mixtures[i] = unique_ptr(generator.makeMixture(
+        population[randomIndex()].get(), population[randomIndex()].get()));
+    }
+    for (size_t i = 0; i < mixed; i++) {
+      population[promoted + i].swap(mixtures[i]);
+    }
+    // TODO: de-duplicate at this point
+    // randoms fill in the test
+    for (size_t i = promoted + mixed; i < size; i++) {
+      population[i] = unique_ptr(generator.makeRandom());
+    }
+
+    sort();
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_learning_h
diff --git a/binaryen/src/support/name.h b/binaryen/src/support/name.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/name.h
@@ -0,0 +1,67 @@
+/*
+ * 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_support_name_h
+#define wasm_support_name_h
+
+#include <string>
+
+#include "emscripten-optimizer/istring.h"
+
+namespace wasm {
+
+// We use a Name for all of the identifiers. These are IStrings, so they are
+// all interned - comparisons etc are just pointer comparisons, so there is no
+// perf loss. Having names everywhere makes using the AST much nicer (for
+// example, block names are strings and not offsets, which makes composition
+// - adding blocks, removing blocks - easy). One exception is local variables,
+// where we do use indices, as they are a large proportion of the AST,
+// perf matters a lot there, and compositionality is not a problem.
+// TODO: as an optimization, IString values < some threshold could be considered
+//       numerical indices directly.
+
+struct Name : public cashew::IString {
+  Name() : cashew::IString() {}
+  Name(const char* str) : cashew::IString(str, false) {}
+  Name(cashew::IString str) : cashew::IString(str) {}
+  Name(const std::string& str) : cashew::IString(str.c_str(), false) {}
+
+  friend std::ostream& operator<<(std::ostream& o, Name name) {
+    if (name.str) {
+      return o << name.str;
+    } else {
+      return o << "(null Name)";
+    }
+  }
+
+  static Name fromInt(size_t i) {
+    return cashew::IString(std::to_string(i).c_str(), false);
+  }
+
+  bool hasSubstring(cashew::IString substring) {
+    return strstr(c_str(), substring.c_str()) != nullptr;
+  }
+};
+
+} // namespace wasm
+
+namespace std {
+
+template<> struct hash<wasm::Name> : hash<cashew::IString> {};
+
+} // namespace std
+
+#endif // wasm_support_name_h
diff --git a/binaryen/src/support/path.cpp b/binaryen/src/support/path.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/path.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+//
+// Command line helpers.
+//
+
+#include "support/path.h"
+
+namespace wasm {
+
+namespace Path {
+
+char getPathSeparator() {
+  // TODO: use c++17's path separator
+  //       http://en.cppreference.com/w/cpp/experimental/fs/path
+#if defined(WIN32) || defined(_WIN32)
+  return '\\';
+#else
+  return '/';
+#endif
+}
+
+std::string getDirName(const std::string& path) {
+  auto sep = path.rfind(getPathSeparator());
+  if (sep == std::string::npos) {
+    return "";
+  }
+  return path.substr(0, sep);
+}
+
+std::string getBaseName(const std::string& path) {
+  auto sep = path.rfind(getPathSeparator());
+  if (sep == std::string::npos) {
+    return path;
+  }
+  return path.substr(sep + 1);
+}
+
+std::string getBinaryenRoot() {
+  auto* envVar = getenv("BINARYEN_ROOT");
+  if (envVar) {
+    return envVar;
+  }
+  return ".";
+}
+
+static std::string binDir;
+
+std::string getBinaryenBinDir() {
+  if (binDir.empty()) {
+    return getBinaryenRoot() + getPathSeparator() + "bin" + getPathSeparator();
+  } else {
+    return binDir;
+  }
+}
+
+void setBinaryenBinDir(const std::string& dir) {
+  binDir = dir;
+  if (binDir.back() != getPathSeparator()) {
+    binDir += getPathSeparator();
+  }
+}
+
+// Gets the path to a binaryen binary tool, like wasm-opt
+std::string getBinaryenBinaryTool(const std::string& name) {
+  return getBinaryenBinDir() + name;
+}
+
+} // namespace Path
+
+} // namespace wasm
diff --git a/binaryen/src/support/path.h b/binaryen/src/support/path.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/path.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// Command line helpers.
+//
+
+#ifndef wasm_support_path_h
+#define wasm_support_path_h
+
+#include <cstdlib>
+#include <string>
+
+namespace wasm {
+
+namespace Path {
+
+char getPathSeparator();
+std::string getDirName(const std::string& path);
+std::string getBaseName(const std::string& path);
+
+// Get the binaryen root dor.
+std::string getBinaryenRoot();
+
+// Get the binaryen bin dir.
+std::string getBinaryenBinDir();
+
+// Set the binaryen bin dir (allows tools to change it based on user input).
+void setBinaryenBinDir(const std::string& dir);
+
+// Gets the path to a binaryen binary tool, like wasm-opt.
+std::string getBinaryenBinaryTool(const std::string& name);
+
+} // namespace Path
+
+} // namespace wasm
+
+#endif // wasm_support_path_h
diff --git a/binaryen/src/support/permutations.h b/binaryen/src/support/permutations.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/permutations.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+// Utilities for operating on permutation vectors
+
+#ifndef wasm_support_permutations_h
+#define wasm_support_permutations_h
+
+#include "wasm.h"
+
+namespace wasm {
+
+inline std::vector<Index> makeIdentity(Index num) {
+  std::vector<Index> ret;
+  ret.resize(num);
+  for (Index i = 0; i < num; i++) {
+    ret[i] = i;
+  }
+  return ret;
+}
+
+inline void setIdentity(std::vector<Index>& ret) {
+  auto num = ret.size();
+  assert(num > 0); // must already be of the right size
+  for (Index i = 0; i < num; i++) {
+    ret[i] = i;
+  }
+}
+
+inline std::vector<Index> makeReversed(std::vector<Index>& original) {
+  std::vector<Index> ret;
+  auto num = original.size();
+  ret.resize(num);
+  for (Index i = 0; i < num; i++) {
+    ret[original[i]] = i;
+  }
+  return ret;
+}
+
+} // namespace wasm
+
+#endif // permutations
diff --git a/binaryen/src/support/safe_integer.cpp b/binaryen/src/support/safe_integer.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/safe_integer.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cassert>
+#include <cmath>
+#include <limits>
+
+#include "support/safe_integer.h"
+
+using namespace wasm;
+
+bool wasm::isInteger(double x) { return trunc(x) == x && !std::isinf(x); }
+
+bool wasm::isUInteger32(double x) {
+  return !std::signbit(x) && isInteger(x) &&
+         x <= std::numeric_limits<uint32_t>::max();
+}
+
+bool wasm::isSInteger32(double x) {
+  return isInteger(x) && x >= std::numeric_limits<int32_t>::min() &&
+         x <= std::numeric_limits<int32_t>::max();
+}
+
+uint32_t wasm::toUInteger32(double x) {
+  return std::signbit(x) ? 0
+                         : (x < std::numeric_limits<uint32_t>::max()
+                              ? (uint32_t)x
+                              : std::numeric_limits<uint32_t>::max());
+}
+
+int32_t wasm::toSInteger32(double x) {
+  return (x > std::numeric_limits<int32_t>::min() &&
+          x < std::numeric_limits<int32_t>::max())
+           ? (int32_t)x
+           : (std::signbit(x) ? std::numeric_limits<int32_t>::min()
+                              : std::numeric_limits<int32_t>::max());
+}
+
+bool wasm::isUInteger64(double x) {
+  return !std::signbit(x) && isInteger(x) &&
+         x <= std::numeric_limits<uint64_t>::max();
+}
+
+bool wasm::isSInteger64(double x) {
+  return isInteger(x) && x >= std::numeric_limits<int64_t>::min() &&
+         x <= std::numeric_limits<int64_t>::max();
+}
+
+uint64_t wasm::toUInteger64(double x) {
+  return std::signbit(x) ? 0
+                         : (x < (double)std::numeric_limits<uint64_t>::max()
+                              ? (uint64_t)x
+                              : std::numeric_limits<uint64_t>::max());
+}
+
+int64_t wasm::toSInteger64(double x) {
+  return (x > (double)std::numeric_limits<int64_t>::min() &&
+          x < (double)std::numeric_limits<int64_t>::max())
+           ? (int64_t)x
+           : (std::signbit(x) ? std::numeric_limits<int64_t>::min()
+                              : std::numeric_limits<int64_t>::max());
+}
+
+/* 3 32222222 222...00
+ * 1 09876543 210...10
+ * -------------------
+ * 0 00000000 000...00 => 0x00000000 => 0
+ * 0 10011101 111...11 => 0x4effffff => 2147483520                  (~INT32_MAX)
+ * 0 10011110 000...00 => 0x4f000000 => 2147483648
+ * 0 10011110 111...11 => 0x4f7fffff => 4294967040                 (~UINT32_MAX)
+ * 0 10111110 111...11 => 0x5effffff => 9223371487098961920         (~INT64_MAX)
+ * 0 10111110 000...00 => 0x5f000000 => 9223372036854775808
+ * 0 10111111 111...11 => 0x5f7fffff => 18446742974197923840       (~UINT64_MAX)
+ * 0 10111111 000...00 => 0x5f800000 => 18446744073709551616
+ * 0 11111111 000...00 => 0x7f800000 => inf
+ * 0 11111111 000...01 => 0x7f800001 => nan(0x1)
+ * 0 11111111 111...11 => 0x7fffffff => nan(0x7fffff)
+ * 1 00000000 000...00 => 0x80000000 => -0
+ * 1 01111110 111...11 => 0xbf7fffff => -1 + ulp      (~UINT32_MIN, ~UINT64_MIN)
+ * 1 01111111 000...00 => 0xbf800000 => -1
+ * 1 10011110 000...00 => 0xcf000000 => -2147483648                  (INT32_MIN)
+ * 1 10111110 000...00 => 0xdf000000 => -9223372036854775808         (INT64_MIN)
+ * 1 11111111 000...00 => 0xff800000 => -inf
+ * 1 11111111 000...01 => 0xff800001 => -nan(0x1)
+ * 1 11111111 111...11 => 0xffffffff => -nan(0x7fffff)
+ */
+
+bool wasm::isInRangeI32TruncS(int32_t i) {
+  uint32_t u = i;
+  return (u < 0x4f000000U) || (u >= 0x80000000U && u <= 0xcf000000U);
+}
+
+bool wasm::isInRangeI64TruncS(int32_t i) {
+  uint32_t u = i;
+  return (u < 0x5f000000U) || (u >= 0x80000000U && u <= 0xdf000000U);
+}
+
+bool wasm::isInRangeI32TruncU(int32_t i) {
+  uint32_t u = i;
+  return (u < 0x4f800000U) || (u >= 0x80000000U && u < 0xbf800000U);
+}
+
+bool wasm::isInRangeI64TruncU(int32_t i) {
+  uint32_t u = i;
+  return (u < 0x5f800000U) || (u >= 0x80000000U && u < 0xbf800000U);
+}
+
+/* clang-format off */
+/*
+ * 6 66655555555 5544...222221...000
+ * 3 21098765432 1098...432109...210
+ * ---------------------------------
+ * 0 00000000000 0000...000000...000 0x0000000000000000 => 0
+ * 0 10000011101 1111...111000...111 0x41dfffffffffffff => 2147483647.9999998     (rounds down to INT32_MAX)
+ * 0 10000011110 1111...111111...111 0x41efffffffffffff => 4294967295.9999995     (rounds down to UINT32_MAX)
+ * 0 10000111101 1111...111111...111 0x43dfffffffffffff => 9223372036854774784     (~INT64_MAX)
+ * 0 10000111110 0000...000000...000 0x43e0000000000000 => 9223372036854775808
+ * 0 10000111110 1111...111111...111 0x43efffffffffffff => 18446744073709549568   (~UINT64_MAX)
+ * 0 10000111111 0000...000000...000 0x43f0000000000000 => 18446744073709551616
+ * 0 11111111111 0000...000000...000 0x7ff0000000000000 => inf
+ * 0 11111111111 0000...000000...001 0x7ff0000000000001 => nan(0x1)
+ * 0 11111111111 1111...111111...111 0x7fffffffffffffff => nan(0xfff...)
+ * 1 00000000000 0000...000000...000 0x8000000000000000 => -0
+ * 1 01111111110 1111...111111...111 0xbfefffffffffffff => -1 + ulp  (~UINT32_MIN, ~UINT64_MIN)
+ * 1 01111111111 0000...000000...000 0xbff0000000000000 => -1
+ * 1 10000011110 0000...000000...111 0xc1e00000001fffff => -2147483648.9999995    (rounds up to INT32_MIN)
+ * 1 10000111110 0000...000000...000 0xc3e0000000000000 => -9223372036854775808     (INT64_MIN)
+ * 1 11111111111 0000...000000...000 0xfff0000000000000 => -inf
+ * 1 11111111111 0000...000000...001 0xfff0000000000001 => -nan(0x1)
+ * 1 11111111111 1111...111111...111 0xffffffffffffffff => -nan(0xfff...)
+ */
+/* clang-format on */
+
+bool wasm::isInRangeI32TruncS(int64_t i) {
+  uint64_t u = i;
+  return (u <= 0x41dfffffffffffffULL) ||
+         (u >= 0x8000000000000000ULL && u <= 0xc1e00000001fffffULL);
+}
+
+bool wasm::isInRangeI32TruncU(int64_t i) {
+  uint64_t u = i;
+  return (u <= 0x41efffffffffffffULL) ||
+         (u >= 0x8000000000000000ULL && u <= 0xbfefffffffffffffULL);
+}
+
+bool wasm::isInRangeI64TruncS(int64_t i) {
+  uint64_t u = i;
+  return (u < 0x43e0000000000000ULL) ||
+         (u >= 0x8000000000000000ULL && u <= 0xc3e0000000000000ULL);
+}
+
+bool wasm::isInRangeI64TruncU(int64_t i) {
+  uint64_t u = i;
+  return (u < 0x43f0000000000000ULL) ||
+         (u >= 0x8000000000000000ULL && u <= 0xbfefffffffffffffULL);
+}
diff --git a/binaryen/src/support/safe_integer.h b/binaryen/src/support/safe_integer.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/safe_integer.h
@@ -0,0 +1,46 @@
+/*
+ * 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_safe_integer_h
+#define wasm_safe_integer_h
+
+#include <cstdint>
+
+namespace wasm {
+
+bool isInteger(double x);
+bool isUInteger32(double x);
+bool isSInteger32(double x);
+uint32_t toUInteger32(double x);
+int32_t toSInteger32(double x);
+bool isUInteger64(double x);
+bool isSInteger64(double x);
+uint64_t toUInteger64(double x);
+int64_t toSInteger64(double x);
+// The isInRange* functions all expect to be passed the binary representation
+// of a float or double.
+bool isInRangeI32TruncS(int32_t i);
+bool isInRangeI64TruncS(int32_t i);
+bool isInRangeI32TruncU(int32_t i);
+bool isInRangeI64TruncU(int32_t i);
+bool isInRangeI32TruncS(int64_t i);
+bool isInRangeI32TruncU(int64_t i);
+bool isInRangeI64TruncS(int64_t i);
+bool isInRangeI64TruncU(int64_t i);
+
+} // namespace wasm
+
+#endif // wasm_safe_integer_h
diff --git a/binaryen/src/support/small_vector.h b/binaryen/src/support/small_vector.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/small_vector.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2019 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.
+ */
+
+//
+// A vector of elements, which may be small, and uses a fixed space
+// for those small elements.
+//
+
+#ifndef wasm_support_small_vector_h
+#define wasm_support_small_vector_h
+
+#include <array>
+#include <cassert>
+#include <iterator>
+#include <vector>
+
+namespace wasm {
+
+template<typename T, size_t N> class SmallVector {
+  // fixed-space storage
+  size_t usedFixed = 0;
+  std::array<T, N> fixed;
+
+  // flexible additional storage
+  std::vector<T> flexible;
+
+public:
+  using value_type = T;
+
+  SmallVector() {}
+  SmallVector(std::initializer_list<T> init) {
+    for (T item : init) {
+      push_back(item);
+    }
+  }
+
+  T& operator[](size_t i) {
+    if (i < N) {
+      return fixed[i];
+    } else {
+      return flexible[i - N];
+    }
+  }
+
+  const T& operator[](size_t i) const {
+    return const_cast<SmallVector<T, N>&>(*this)[i];
+  }
+
+  void push_back(const T& x) {
+    if (usedFixed < N) {
+      fixed[usedFixed++] = x;
+    } else {
+      flexible.push_back(x);
+    }
+  }
+
+  template<typename... ArgTypes> void emplace_back(ArgTypes&&... Args) {
+    if (usedFixed < N) {
+      new (&fixed[usedFixed++]) T(std::forward<ArgTypes>(Args)...);
+    } else {
+      flexible.emplace_back(std::forward<ArgTypes>(Args)...);
+    }
+  }
+
+  void pop_back() {
+    if (flexible.empty()) {
+      assert(usedFixed > 0);
+      usedFixed--;
+    } else {
+      flexible.pop_back();
+    }
+  }
+
+  T& back() {
+    if (flexible.empty()) {
+      assert(usedFixed > 0);
+      return fixed[usedFixed - 1];
+    } else {
+      return flexible.back();
+    }
+  }
+
+  const T& back() const {
+    if (flexible.empty()) {
+      assert(usedFixed > 0);
+      return fixed[usedFixed - 1];
+    } else {
+      return flexible.back();
+    }
+  }
+
+  size_t size() const { return usedFixed + flexible.size(); }
+
+  bool empty() const { return size() == 0; }
+
+  void clear() {
+    usedFixed = 0;
+    flexible.clear();
+  }
+
+  bool operator==(const SmallVector<T, N>& other) const {
+    if (usedFixed != other.usedFixed) {
+      return false;
+    }
+    for (size_t i = 0; i < usedFixed; i++) {
+      if (fixed[i] != other.fixed[i]) {
+        return false;
+      }
+    }
+    return flexible == other.flexible;
+  }
+
+  bool operator!=(const SmallVector<T, N>& other) const {
+    return !(*this == other);
+  }
+
+  // iteration
+
+  template<typename Parent, typename Iterator> struct IteratorBase {
+    typedef T value_type;
+    typedef long difference_type;
+    typedef T& reference;
+
+    Parent* parent;
+    size_t index;
+
+    IteratorBase(Parent* parent, size_t index) : parent(parent), index(index) {}
+
+    bool operator!=(const Iterator& other) const {
+      return index != other.index || parent != other.parent;
+    }
+
+    void operator++() { index++; }
+
+    Iterator& operator+=(difference_type off) {
+      index += off;
+      return *this;
+    }
+
+    const Iterator operator+(difference_type off) const {
+      return Iterator(*this) += off;
+    }
+  };
+
+  struct Iterator : IteratorBase<SmallVector<T, N>, Iterator> {
+    Iterator(SmallVector<T, N>* parent, size_t index)
+      : IteratorBase<SmallVector<T, N>, Iterator>(parent, index) {}
+    value_type& operator*() { return (*this->parent)[this->index]; }
+  };
+
+  struct ConstIterator : IteratorBase<const SmallVector<T, N>, ConstIterator> {
+    ConstIterator(const SmallVector<T, N>* parent, size_t index)
+      : IteratorBase<const SmallVector<T, N>, ConstIterator>(parent, index) {}
+    const value_type& operator*() const { return (*this->parent)[this->index]; }
+  };
+
+  Iterator begin() { return Iterator(this, 0); }
+  Iterator end() { return Iterator(this, size()); }
+  ConstIterator begin() const { return ConstIterator(this, 0); }
+  ConstIterator end() const { return ConstIterator(this, size()); }
+};
+
+} // namespace wasm
+
+#endif // wasm_support_small_vector_h
diff --git a/binaryen/src/support/sorted_vector.h b/binaryen/src/support/sorted_vector.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/sorted_vector.h
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+//
+// A vector of sorted elements.
+//
+
+#ifndef wasm_support_sorted_vector_h
+#define wasm_support_sorted_vector_h
+
+#include <vector>
+
+namespace wasm {
+
+struct SortedVector : public std::vector<Index> {
+  SortedVector() = default;
+
+  SortedVector merge(const SortedVector& other) const {
+    SortedVector ret;
+    ret.resize(size() + other.size());
+    Index i = 0, j = 0, t = 0;
+    while (i < size() && j < other.size()) {
+      auto left = (*this)[i];
+      auto right = other[j];
+      if (left < right) {
+        ret[t++] = left;
+        i++;
+      } else if (left > right) {
+        ret[t++] = right;
+        j++;
+      } else {
+        ret[t++] = left;
+        i++;
+        j++;
+      }
+    }
+    while (i < size()) {
+      ret[t++] = (*this)[i];
+      i++;
+    }
+    while (j < other.size()) {
+      ret[t++] = other[j];
+      j++;
+    }
+    ret.resize(t);
+    return ret;
+  }
+
+  void insert(Index x) {
+    auto it = std::lower_bound(begin(), end(), x);
+    if (it == end()) {
+      push_back(x);
+    } else if (*it > x) {
+      Index i = it - begin();
+      resize(size() + 1);
+      std::move_backward(begin() + i, begin() + size() - 1, end());
+      (*this)[i] = x;
+    }
+  }
+
+  bool erase(Index x) {
+    auto it = std::lower_bound(begin(), end(), x);
+    if (it != end() && *it == x) {
+      std::move(it + 1, end(), it);
+      resize(size() - 1);
+      return true;
+    }
+    return false;
+  }
+
+  bool has(Index x) {
+    auto it = std::lower_bound(begin(), end(), x);
+    return it != end() && *it == x;
+  }
+
+  template<typename T> SortedVector& filter(T keep) {
+    size_t skip = 0;
+    for (size_t i = 0; i < size(); i++) {
+      if (keep((*this)[i])) {
+        (*this)[i - skip] = (*this)[i];
+      } else {
+        skip++;
+      }
+    }
+    resize(size() - skip);
+    return *this;
+  }
+
+  void verify() const {
+    for (Index i = 1; i < size(); i++) {
+      assert((*this)[i - 1] < (*this)[i]);
+    }
+  }
+
+  void dump(const char* str = nullptr) const {
+    std::cout << "SortedVector " << (str ? str : "") << ": ";
+    for (auto x : *this) {
+      std::cout << x << " ";
+    }
+    std::cout << '\n';
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_support_sorted_vector_h
diff --git a/binaryen/src/support/string.h b/binaryen/src/support/string.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/string.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2019 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.
+ */
+
+//
+// String helpers.
+//
+
+#ifndef wasm_support_string_h
+#define wasm_support_string_h
+
+#include <cctype>
+#include <string>
+#include <vector>
+
+namespace wasm {
+
+namespace String {
+
+// Creates a vector of the split parts of a string, by a delimiter.
+class Split : public std::vector<std::string> {
+public:
+  Split() = default;
+
+  Split(const std::string& input, const std::string& delim) {
+    size_t lastEnd = 0;
+    while (lastEnd < input.size()) {
+      auto nextDelim = input.find(delim, lastEnd);
+      if (nextDelim == std::string::npos) {
+        nextDelim = input.size();
+      }
+      (*this).push_back(input.substr(lastEnd, nextDelim - lastEnd));
+      lastEnd = nextDelim + delim.size();
+    }
+  }
+};
+
+// Handles bracketing in a list initially split by ",", but the list may
+// contain nested ","s. For example,
+//   void foo(int, double)
+// must be kept together because of the "(". Likewise, "{", "<", "[" are
+// handled.
+inline String::Split handleBracketingOperators(String::Split split) {
+  String::Split ret;
+  std::string last;
+  int nesting = 0;
+  auto handlePart = [&](std::string part) {
+    if (part.empty()) {
+      return;
+    }
+    for (const char c : part) {
+      if (c == '(' || c == '<' || c == '[' || c == '{') {
+        nesting++;
+      } else if (c == ')' || c == '>' || c == ']' || c == '}') {
+        nesting--;
+      }
+    }
+    if (last.empty()) {
+      last = part;
+    } else {
+      last += ',' + part;
+    }
+    if (nesting == 0) {
+      ret.push_back(last);
+      last.clear();
+    }
+  };
+  for (auto& part : split) {
+    handlePart(part);
+  }
+  handlePart("");
+  if (nesting != 0) {
+    Fatal() << "Asyncify: failed to parse lists";
+  }
+  return ret;
+}
+
+// Does a simple '*' wildcard match between a pattern and a value.
+inline bool wildcardMatch(const std::string& pattern,
+                          const std::string& value) {
+  for (size_t i = 0; i < pattern.size(); i++) {
+    if (pattern[i] == '*') {
+      return wildcardMatch(pattern.substr(i + 1), value.substr(i)) ||
+             (value.size() > 0 &&
+              wildcardMatch(pattern.substr(i), value.substr(i + 1)));
+    }
+    if (i >= value.size()) {
+      return false;
+    }
+    if (pattern[i] != value[i]) {
+      return false;
+    }
+  }
+  return value.size() == pattern.size();
+}
+
+// Removes any extra whitespace or \0.
+inline std::string trim(const std::string& input) {
+  size_t size = input.size();
+  while (size > 0 && (isspace(input[size - 1]) || input[size - 1] == '\0')) {
+    size--;
+  }
+  return input.substr(0, size);
+}
+
+} // namespace String
+
+} // namespace wasm
+
+#endif // wasm_support_string_h
diff --git a/binaryen/src/support/threads.cpp b/binaryen/src/support/threads.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/threads.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+
+#include <algorithm>
+#include <iostream>
+#include <string>
+
+#include "compiler-support.h"
+#include "threads.h"
+#include "utilities.h"
+
+// debugging tools
+
+#ifdef BINARYEN_THREAD_DEBUG
+static std::mutex debug;
+#define DEBUG_THREAD(x)                                                        \
+  {                                                                            \
+    std::lock_guard<std::mutex> lock(debug);                                   \
+    std::cerr << "[THREAD " << std::this_thread::get_id() << "] " << x;        \
+  }
+#define DEBUG_POOL(x)                                                          \
+  {                                                                            \
+    std::lock_guard<std::mutex> lock(debug);                                   \
+    std::cerr << "[POOL " << std::this_thread::get_id() << "] " << x;          \
+  }
+#else
+#define DEBUG_THREAD(x)
+#define DEBUG_POOL(x)
+#endif
+
+namespace wasm {
+
+// Thread
+
+Thread::Thread(ThreadPool* parent) : parent(parent) {
+  assert(!parent->isRunning());
+  thread = make_unique<std::thread>(mainLoop, this);
+}
+
+Thread::~Thread() {
+  {
+    std::lock_guard<std::mutex> lock(mutex);
+    // notify the thread that it can exit
+    done = true;
+    condition.notify_one();
+  }
+  thread->join();
+}
+
+void Thread::work(std::function<ThreadWorkState()> doWork_) {
+  // TODO: fancy work stealing
+  DEBUG_THREAD("send work to thread\n");
+  {
+    std::lock_guard<std::mutex> lock(mutex);
+    // notify the thread that it can do some work
+    doWork = doWork_;
+    condition.notify_one();
+    DEBUG_THREAD("work sent\n");
+  }
+}
+
+void Thread::mainLoop(void* self_) {
+  auto* self = static_cast<Thread*>(self_);
+  while (1) {
+    DEBUG_THREAD("checking for work\n");
+    {
+      std::unique_lock<std::mutex> lock(self->mutex);
+      if (self->doWork) {
+        DEBUG_THREAD("doing work\n");
+        // run tasks until they are all done
+        while (self->doWork() == ThreadWorkState::More) {
+        }
+        self->doWork = nullptr;
+      } else if (self->done) {
+        DEBUG_THREAD("done\n");
+        return;
+      }
+    }
+    self->parent->notifyThreadIsReady();
+    {
+      std::unique_lock<std::mutex> lock(self->mutex);
+      if (!self->done && !self->doWork) {
+        DEBUG_THREAD("thread waiting\n");
+        self->condition.wait(lock);
+      }
+    }
+  }
+}
+
+// ThreadPool
+
+// Global threadPool state. We have a singleton pool, which can only be
+// used from one place at a time.
+
+static std::unique_ptr<ThreadPool> pool;
+
+std::mutex ThreadPool::creationMutex;
+std::mutex ThreadPool::workMutex;
+std::mutex ThreadPool::threadMutex;
+
+void ThreadPool::initialize(size_t num) {
+  if (num == 1) {
+    return; // no multiple cores, don't create threads
+  }
+  DEBUG_POOL("initialize()\n");
+  std::unique_lock<std::mutex> lock(threadMutex);
+  // initial state before first resetThreadsAreReady()
+  ready.store(threads.size());
+  resetThreadsAreReady();
+  for (size_t i = 0; i < num; i++) {
+    try {
+      threads.emplace_back(make_unique<Thread>(this));
+    } catch (std::system_error&) {
+      // failed to create a thread - don't use multithreading, as if num cores
+      // == 1
+      DEBUG_POOL("could not create thread\n");
+      threads.clear();
+      return;
+    }
+  }
+  DEBUG_POOL("initialize() waiting\n");
+  condition.wait(lock, [this]() { return areThreadsReady(); });
+  DEBUG_POOL("initialize() is done\n");
+}
+
+size_t ThreadPool::getNumCores() {
+#ifdef __EMSCRIPTEN__
+  return 1;
+#else
+  size_t num = std::max(1U, std::thread::hardware_concurrency());
+  if (getenv("BINARYEN_CORES")) {
+    num = std::stoi(getenv("BINARYEN_CORES"));
+  }
+  return num;
+#endif
+}
+
+ThreadPool* ThreadPool::get() {
+  DEBUG_POOL("::get()\n");
+  // lock on the creation
+  std::lock_guard<std::mutex> poolLock(creationMutex);
+  if (!pool) {
+    DEBUG_POOL("::get() creating\n");
+    std::unique_ptr<ThreadPool> temp = make_unique<ThreadPool>();
+    temp->initialize(getNumCores());
+    // assign it to the global location now that it is all ready
+    pool.swap(temp);
+    DEBUG_POOL("::get() created\n");
+  }
+  return pool.get();
+}
+
+void ThreadPool::work(
+  std::vector<std::function<ThreadWorkState()>>& doWorkers) {
+  size_t num = threads.size();
+  // If no multiple cores, or on a side thread, do not use worker threads
+  if (num == 0) {
+    // just run sequentially
+    DEBUG_POOL("work() sequentially\n");
+    assert(doWorkers.size() > 0);
+    while (doWorkers[0]() == ThreadWorkState::More) {
+    }
+    return;
+  }
+  // run in parallel on threads
+  // TODO: fancy work stealing
+  DEBUG_POOL("work() on threads\n");
+  // lock globally on doing work in the pool - the threadPool can only be used
+  // from one thread at a time, all others must wait patiently
+  std::lock_guard<std::mutex> poolLock(workMutex);
+  assert(doWorkers.size() == num);
+  assert(!running);
+  DEBUG_POOL("running = true\n");
+  running = true;
+  std::unique_lock<std::mutex> lock(threadMutex);
+  resetThreadsAreReady();
+  for (size_t i = 0; i < num; i++) {
+    threads[i]->work(doWorkers[i]);
+  }
+  DEBUG_POOL("main thread waiting\n");
+  condition.wait(lock, [this]() { return areThreadsReady(); });
+  DEBUG_POOL("main thread done waiting\n");
+  DEBUG_POOL("running = false\n");
+  running = false;
+  DEBUG_POOL("work() is done\n");
+}
+
+size_t ThreadPool::size() { return std::max(size_t(1), threads.size()); }
+
+bool ThreadPool::isRunning() {
+  DEBUG_POOL("check if running\n");
+  return running;
+}
+
+void ThreadPool::notifyThreadIsReady() {
+  DEBUG_POOL("notify thread is ready\n";)
+  std::lock_guard<std::mutex> lock(threadMutex);
+  ready.fetch_add(1);
+  condition.notify_one();
+}
+
+void ThreadPool::resetThreadsAreReady() {
+  DEBUG_POOL("reset threads are ready\n";)
+  auto old = ready.exchange(0);
+  WASM_UNUSED(old);
+  assert(old == threads.size());
+}
+
+bool ThreadPool::areThreadsReady() {
+  DEBUG_POOL("are threads ready?\n";)
+  return ready.load() == threads.size();
+}
+
+} // namespace wasm
diff --git a/binaryen/src/support/threads.h b/binaryen/src/support/threads.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/threads.h
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+//
+// Threads helpers.
+//
+
+#ifndef wasm_support_threads_h
+#define wasm_support_threads_h
+
+#include <atomic>
+#include <condition_variable>
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include "compiler-support.h"
+
+namespace wasm {
+
+// The work state of a helper thread - is there more to do,
+// or are we finished for now.
+enum class ThreadWorkState { More, Finished };
+
+class ThreadPool;
+
+//
+// A helper thread.
+//
+// You can only create and destroy these on the main thread.
+//
+
+class Thread {
+  ThreadPool* parent;
+  std::unique_ptr<std::thread> thread;
+  std::mutex mutex;
+  std::condition_variable condition;
+  bool done = false;
+  std::function<ThreadWorkState()> doWork = nullptr;
+
+public:
+  Thread(ThreadPool* parent);
+  ~Thread();
+
+  // Start to do work, calling doWork() until
+  // it returns false.
+  void work(std::function<ThreadWorkState()> doWork);
+
+private:
+  static void mainLoop(void* self);
+};
+
+//
+// A pool of helper threads.
+//
+// There is only one, to avoid recursive pools using too many cores.
+//
+
+class ThreadPool {
+  std::vector<std::unique_ptr<Thread>> threads;
+  bool running = false;
+  std::condition_variable condition;
+  std::atomic<size_t> ready;
+
+  // A mutex for creating the pool safely
+  static std::mutex creationMutex;
+  // A mutex for work() so that the pool can only work on one
+  // thing at a time
+  static std::mutex workMutex;
+  // A mutex for communication with the worker threads
+  static std::mutex threadMutex;
+
+private:
+  void initialize(size_t num);
+
+public:
+  // Get the number of cores we can use.
+  static size_t getNumCores();
+
+  // Get the singleton threadpool.
+  static ThreadPool* get();
+
+  // Execute a bunch of tasks by the pool. This calls
+  // getTask() (in a thread-safe manner) to get tasks, and
+  // sends them to workers to be executed. This method
+  // blocks until all tasks are complete.
+  void work(std::vector<std::function<ThreadWorkState()>>& doWorkers);
+
+  size_t size();
+
+  bool isRunning();
+
+  // Called by helper threads when they are free and ready.
+  void notifyThreadIsReady();
+
+private:
+  void resetThreadsAreReady();
+
+  bool areThreadsReady();
+};
+
+// Verify a code segment is only entered once. Usage:
+//    static OnlyOnce onlyOnce;
+//    onlyOnce.verify();
+
+class OnlyOnce {
+  std::atomic<int> created;
+
+public:
+  OnlyOnce() { created.store(0); }
+
+  void verify() {
+    auto before = created.fetch_add(1);
+    WASM_UNUSED(before);
+    assert(before == 0);
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_support_threads_h
diff --git a/binaryen/src/support/timing.h b/binaryen/src/support/timing.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/timing.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+//
+// Timing helper
+//
+
+#ifndef wasm_support_timing_h
+#define wasm_support_timing_h
+
+#include <chrono>
+
+namespace wasm {
+
+class Timer {
+  std::string name;
+  std::chrono::steady_clock::time_point startTime;
+  double total = 0;
+
+public:
+  Timer(std::string name = "") : name(name) {}
+
+  void start() { startTime = std::chrono::steady_clock::now(); }
+
+  void stop() {
+    total += std::chrono::duration<double>(std::chrono::steady_clock::now() -
+                                           startTime)
+               .count();
+  }
+
+  double getTotal() { return total; }
+
+  void dump() { std::cerr << "<Timer " << name << ": " << getTotal() << ">\n"; }
+};
+
+} // namespace wasm
+
+#endif // wasm_support_timing_h
diff --git a/binaryen/src/support/unique_deferring_queue.h b/binaryen/src/support/unique_deferring_queue.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/unique_deferring_queue.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+//
+// A FIFO queue of unique items, in which if an item is queued that already
+// exists, it is placed at the end. That means that it is done at the
+// last (most deferred) time from all the times it was queued.
+//
+
+#ifndef wasm_support_unique_deferring_queue_h
+#define wasm_support_unique_deferring_queue_h
+
+#include <queue>
+#include <unordered_map>
+
+namespace wasm {
+
+template<typename T> struct UniqueDeferredQueue {
+  // implemented as an internal queue, plus a map
+  // that says how many times an element appears. we
+  // can then skip non-final appearances. this lets us
+  // avoid needing to remove elements from the middle
+  // when there are duplicates.
+  std::queue<T> data;
+  std::unordered_map<T, size_t> count;
+
+  size_t size() { return data.size(); }
+  bool empty() { return size() == 0; }
+
+  void push(T item) {
+    data.push(item);
+    count[item]++;
+  }
+
+  T pop() {
+    while (1) {
+      assert(!empty());
+      T item = data.front();
+      count[item]--;
+      data.pop();
+      if (count[item] == 0) {
+        return item;
+      }
+      // skip this one, keep going
+    }
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_support_unique_deferring_queue_h
diff --git a/binaryen/src/support/utilities.cpp b/binaryen/src/support/utilities.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/utilities.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utilities.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <iostream>
+
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+#include "sanitizer/common_interface_defs.h"
+#endif
+
+void wasm::handle_unreachable(const char* msg,
+                              const char* file,
+                              unsigned line) {
+#ifndef NDEBUG
+  if (msg) {
+    std::cerr << msg << "\n";
+  }
+  std::cerr << "UNREACHABLE executed";
+  if (file) {
+    std::cerr << " at " << file << ":" << line;
+  }
+  std::cerr << "!\n";
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+  __sanitizer_print_stack_trace();
+  __builtin_trap();
+#endif
+#endif
+  abort();
+}
diff --git a/binaryen/src/support/utilities.h b/binaryen/src/support/utilities.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/utilities.h
@@ -0,0 +1,93 @@
+/*
+ * 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_support_utilities_h
+#define wasm_support_utilities_h
+
+#include "compiler-support.h"
+
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <iostream>
+#include <memory>
+#include <type_traits>
+
+#include "support/bits.h"
+
+namespace wasm {
+
+// Type punning needs to be done through this function to avoid undefined
+// behavior: unions and reinterpret_cast aren't valid approaches.
+template<class Destination, class Source>
+inline Destination bit_cast(const Source& source) {
+  static_assert(sizeof(Destination) == sizeof(Source),
+                "bit_cast needs to be between types of the same size");
+  static_assert(std::is_pod<Destination>::value, "non-POD bit_cast undefined");
+  static_assert(std::is_pod<Source>::value, "non-POD bit_cast undefined");
+  Destination destination;
+  std::memcpy(&destination, &source, sizeof(destination));
+  return destination;
+}
+
+inline size_t alignAddr(size_t address, size_t alignment) {
+  assert(alignment && Bits::isPowerOf2((uint32_t)alignment) &&
+         "Alignment is not a power of two!");
+
+  assert(address + alignment - 1 >= address);
+
+  return ((address + alignment - 1) & ~(alignment - 1));
+}
+
+template<typename T, typename... Args>
+std::unique_ptr<T> make_unique(Args&&... args) {
+  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+// For fatal errors which could arise from input (i.e. not assertion failures)
+class Fatal {
+public:
+  Fatal() { std::cerr << "Fatal: "; }
+  template<typename T> Fatal& operator<<(T arg) {
+    std::cerr << arg;
+    return *this;
+  }
+  WASM_NORETURN ~Fatal() {
+    std::cerr << "\n";
+    // Use _Exit here to avoid calling static destructors. This avoids deadlocks
+    // in (for example) the thread worker pool, where workers hold a lock while
+    // performing their work.
+    _Exit(1);
+  }
+};
+
+WASM_NORETURN void handle_unreachable(const char* msg = nullptr,
+                                      const char* file = nullptr,
+                                      unsigned line = 0);
+
+// If control flow reaches the point of the WASM_UNREACHABLE(), the program is
+// undefined.
+#ifndef NDEBUG
+#define WASM_UNREACHABLE(msg) wasm::handle_unreachable(msg, __FILE__, __LINE__)
+#elif defined(WASM_BUILTIN_UNREACHABLE)
+#define WASM_UNREACHABLE(msg) WASM_BUILTIN_UNREACHABLE
+#else
+#define WASM_UNREACHABLE(msg) wasm::handle_unreachable()
+#endif
+
+} // namespace wasm
+
+#endif // wasm_support_utilities_h
diff --git a/binaryen/src/templates/normal.js b/binaryen/src/templates/normal.js
new file mode 100644
--- /dev/null
+++ b/binaryen/src/templates/normal.js
@@ -0,0 +1,4 @@
+
+var Module = {}; // *.asm.js expects this
+
+
diff --git a/binaryen/src/templates/wasm.js b/binaryen/src/templates/wasm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/src/templates/wasm.js
@@ -0,0 +1,5 @@
+
+var Module = {
+  asmjsCodeFile: 'a.asm.js' // tell polyfill (which replaces a.asm.js) where the asm.js code is
+};
+
diff --git a/binaryen/src/tools/execution-results.h b/binaryen/src/tools/execution-results.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/execution-results.h
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+//
+// Shared execution result checking code
+//
+
+#include "shell-interface.h"
+#include "wasm.h"
+
+namespace wasm {
+
+typedef std::vector<Literal> Loggings;
+
+// Logs every relevant import call parameter.
+struct LoggingExternalInterface : public ShellExternalInterface {
+  Loggings& loggings;
+
+  LoggingExternalInterface(Loggings& loggings) : loggings(loggings) {}
+
+  Literals callImport(Function* import, LiteralList& arguments) override {
+    if (import->module == "fuzzing-support") {
+      std::cout << "[LoggingExternalInterface logging";
+      loggings.push_back(Literal()); // buffer with a None between calls
+      for (auto argument : arguments) {
+        std::cout << ' ' << argument;
+        loggings.push_back(argument);
+      }
+      std::cout << "]\n";
+    }
+    return {};
+  }
+};
+
+// gets execution results from a wasm module. this is useful for fuzzing
+//
+// we can only get results when there are no imports. we then call each method
+// that has a result, with some values
+struct ExecutionResults {
+  std::map<Name, Literals> results;
+  Loggings loggings;
+
+  // get results of execution
+  void get(Module& wasm) {
+    LoggingExternalInterface interface(loggings);
+    try {
+      ModuleInstance instance(wasm, &interface);
+      // execute all exported methods (that are therefore preserved through
+      // opts)
+      for (auto& exp : wasm.exports) {
+        if (exp->kind != ExternalKind::Function) {
+          continue;
+        }
+        std::cout << "[fuzz-exec] calling " << exp->name << "\n";
+        auto* func = wasm.getFunction(exp->value);
+        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) {
+            std::cout << "[fuzz-exec] note result: " << exp->name << " => "
+                      << ret << '\n';
+          }
+        } else {
+          // no result, run it anyhow (it might modify memory etc.)
+          run(func, wasm, instance);
+        }
+      }
+    } catch (const TrapException&) {
+      // may throw in instance creation (init of offsets)
+    }
+  }
+
+  // get current results and check them against previous ones
+  void check(Module& wasm) {
+    ExecutionResults optimizedResults;
+    optimizedResults.get(wasm);
+    if (optimizedResults != *this) {
+      std::cout << "[fuzz-exec] optimization passes changed execution results";
+      exit(1);
+    }
+  }
+
+  bool operator==(ExecutionResults& other) {
+    for (auto& iter : other.results) {
+      auto name = iter.first;
+      if (results.find(name) == results.end()) {
+        std::cout << "[fuzz-exec] missing " << name << '\n';
+        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";
+        return false;
+      }
+    }
+    if (loggings != other.loggings) {
+      std::cout << "logging not identical!\n";
+      return false;
+    }
+    return true;
+  }
+
+  bool operator!=(ExecutionResults& other) { return !((*this) == other); }
+
+  Literals run(Function* func, Module& wasm) {
+    LoggingExternalInterface interface(loggings);
+    try {
+      ModuleInstance instance(wasm, &interface);
+      return run(func, wasm, instance);
+    } catch (const TrapException&) {
+      // may throw in instance creation (init of offsets)
+      return {};
+    }
+  }
+
+  Literals run(Function* func, Module& wasm, ModuleInstance& instance) {
+    try {
+      LiteralList arguments;
+      // init hang support, if present
+      if (auto* ex = wasm.getExportOrNull("hangLimitInitializer")) {
+        instance.callFunction(ex->value, arguments);
+      }
+      // call the method
+      for (const auto& param : func->sig.params) {
+        // zeros in arguments TODO: more?
+        arguments.push_back(Literal::makeZero(param));
+      }
+      return instance.callFunction(func->name, arguments);
+    } catch (const TrapException&) {
+      return {};
+    }
+  }
+};
+
+} // namespace wasm
diff --git a/binaryen/src/tools/fuzzing.h b/binaryen/src/tools/fuzzing.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/fuzzing.h
@@ -0,0 +1,2995 @@
+/*
+ * 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.
+ */
+
+//
+// Translate a binary stream of bytes into a valid wasm module, *somehow*.
+// This is helpful for fuzzing.
+//
+
+/*
+high chance for set at start of loop
+  high chance of get of a set local in the scope of that scope
+    high chance of a tee in that case => loop var
+*/
+
+// TODO Generate exception handling instructions
+
+#include "ir/memory-utils.h"
+#include <ir/find_all.h>
+#include <ir/literal-utils.h>
+#include <ir/manipulation.h>
+#include <ir/utils.h>
+#include <support/file.h>
+#include <tools/optimization-options.h>
+#include <wasm-builder.h>
+
+namespace wasm {
+
+// helper structs, since list initialization has a fixed order of
+// evaluation, avoiding UB
+
+struct ThreeArgs {
+  Expression* a;
+  Expression* b;
+  Expression* c;
+};
+
+struct UnaryArgs {
+  UnaryOp a;
+  Expression* b;
+};
+
+struct BinaryArgs {
+  BinaryOp a;
+  Expression* b;
+  Expression* c;
+};
+
+// main reader
+
+class TranslateToFuzzReader {
+public:
+  TranslateToFuzzReader(Module& wasm, std::string& filename)
+    : wasm(wasm), builder(wasm) {
+    auto input(read_file<std::vector<char>>(filename, Flags::Binary));
+    readData(input);
+  }
+
+  TranslateToFuzzReader(Module& wasm, std::vector<char> input)
+    : wasm(wasm), builder(wasm) {
+    readData(input);
+  }
+
+  void pickPasses(OptimizationOptions& options) {
+    while (options.passes.size() < 20 && !finishedInput && !oneIn(3)) {
+      switch (upTo(32)) {
+        case 0:
+        case 1:
+        case 2:
+        case 3:
+        case 4: {
+          options.passes.push_back("O");
+          options.passOptions.optimizeLevel = upTo(4);
+          options.passOptions.shrinkLevel = upTo(4);
+          break;
+        }
+        case 5:
+          options.passes.push_back("coalesce-locals");
+          break;
+        case 6:
+          options.passes.push_back("code-pushing");
+          break;
+        case 7:
+          options.passes.push_back("code-folding");
+          break;
+        case 8:
+          options.passes.push_back("dce");
+          break;
+        case 9:
+          options.passes.push_back("duplicate-function-elimination");
+          break;
+        case 10:
+          options.passes.push_back("flatten");
+          break;
+        case 11:
+          options.passes.push_back("inlining");
+          break;
+        case 12:
+          options.passes.push_back("inlining-optimizing");
+          break;
+        case 13:
+          options.passes.push_back("local-cse");
+          break;
+        case 14:
+          options.passes.push_back("memory-packing");
+          break;
+        case 15:
+          options.passes.push_back("merge-blocks");
+          break;
+        case 16:
+          options.passes.push_back("optimize-instructions");
+          break;
+        case 17:
+          options.passes.push_back("pick-load-signs");
+          break;
+        case 18:
+          options.passes.push_back("precompute");
+          break;
+        case 19:
+          options.passes.push_back("precompute-propagate");
+          break;
+        case 20:
+          options.passes.push_back("remove-unused-brs");
+          break;
+        case 21:
+          options.passes.push_back("remove-unused-module-elements");
+          break;
+        case 22:
+          options.passes.push_back("remove-unused-names");
+          break;
+        case 23:
+          options.passes.push_back("reorder-functions");
+          break;
+        case 24:
+          options.passes.push_back("reorder-locals");
+          break;
+        case 25: {
+          options.passes.push_back("flatten");
+          options.passes.push_back("rereloop");
+          break;
+        }
+        case 26:
+          options.passes.push_back("simplify-locals");
+          break;
+        case 27:
+          options.passes.push_back("simplify-locals-notee");
+          break;
+        case 28:
+          options.passes.push_back("simplify-locals-nostructure");
+          break;
+        case 29:
+          options.passes.push_back("simplify-locals-notee-nostructure");
+          break;
+        case 30:
+          options.passes.push_back("ssa");
+          break;
+        case 31:
+          options.passes.push_back("vacuum");
+          break;
+        default:
+          WASM_UNREACHABLE("unexpected value");
+      }
+    }
+    if (oneIn(2)) {
+      options.passOptions.optimizeLevel = upTo(4);
+    }
+    if (oneIn(2)) {
+      options.passOptions.shrinkLevel = upTo(4);
+    }
+    std::cout << "opt level: " << options.passOptions.optimizeLevel << '\n';
+    std::cout << "shrink level: " << options.passOptions.shrinkLevel << '\n';
+  }
+
+  void setAllowMemory(bool allowMemory_) { allowMemory = allowMemory_; }
+
+  void setAllowOOB(bool allowOOB_) { allowOOB = allowOOB_; }
+
+  void build() {
+    if (allowMemory) {
+      setupMemory();
+    }
+    setupTable();
+    setupGlobals();
+    if (wasm.features.hasExceptionHandling()) {
+      setupEvents();
+    }
+    addImportLoggingSupport();
+    // keep adding functions until we run out of input
+    while (!finishedInput) {
+      auto* func = addFunction();
+      addInvocations(func);
+    }
+    if (HANG_LIMIT > 0) {
+      addHangLimitSupport();
+    }
+    finalizeTable();
+  }
+
+private:
+  Module& wasm;
+  Builder builder;
+  std::vector<char> bytes; // the input bytes
+  size_t pos;              // the position in the input
+  // whether we already cycled through all the input (if so, we should try to
+  // finish things off)
+  bool finishedInput;
+
+  // The maximum amount of params to each function.
+  static const int MAX_PARAMS = 10;
+
+  // The maximum amount of vars in each function.
+  static const int MAX_VARS = 20;
+
+  // The maximum number of globals in a module.
+  static const int MAX_GLOBALS = 20;
+
+  // The maximum number of tuple elements.
+  static const int MAX_TUPLE_SIZE = 6;
+
+  // some things require luck, try them a few times
+  static const int TRIES = 10;
+
+  // beyond a nesting limit, greatly decrease the chance to continue to nest
+  static const int NESTING_LIMIT = 11;
+
+  // the maximum size of a block
+  static const int BLOCK_FACTOR = 5;
+
+  // 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;
+
+  // the number of runtime iterations (function calls, loop backbranches) we
+  // allow before we stop execution with a trap, to prevent hangs. 0 means
+  // no hang protection.
+  static const int HANG_LIMIT = 10;
+
+  // Whether to emit memory operations like loads and stores.
+  bool allowMemory = true;
+
+  // Whether to emit loads, stores, and call_indirects that may be out
+  // of bounds (which traps in wasm, and is undefined behavior in C).
+  bool allowOOB = true;
+
+  // Whether to emit atomic waits (which in single-threaded mode, may hang...)
+  static const bool ATOMIC_WAITS = false;
+
+  // After we finish the input, we start going through it again, but xoring
+  // so it's not identical
+  int xorFactor = 0;
+
+  // The chance to emit a logging operation for a none expression. We
+  // randomize this in each function.
+  unsigned LOGGING_PERCENT = 0;
+
+  void readData(std::vector<char> input) {
+    bytes.swap(input);
+    pos = 0;
+    finishedInput = false;
+    // ensure *some* input to be read
+    if (bytes.size() == 0) {
+      bytes.push_back(0);
+    }
+  }
+
+  int8_t get() {
+    if (pos == bytes.size()) {
+      // we ran out of input, go to the start for more stuff
+      finishedInput = true;
+      pos = 0;
+      xorFactor++;
+    }
+    return bytes[pos++] ^ xorFactor;
+  }
+
+  int16_t get16() {
+    auto temp = uint16_t(get()) << 8;
+    return temp | uint16_t(get());
+  }
+
+  int32_t get32() {
+    auto temp = uint32_t(get16()) << 16;
+    return temp | uint32_t(get16());
+  }
+
+  int64_t get64() {
+    auto temp = uint64_t(get32()) << 32;
+    return temp | uint64_t(get32());
+  }
+
+  float getFloat() { return Literal(get32()).reinterpretf32(); }
+
+  double getDouble() { return Literal(get64()).reinterpretf64(); }
+
+  Type getSubType(Type type) {
+    if (type.isTuple()) {
+      std::vector<Type> types;
+      for (const auto& t : type) {
+        types.push_back(getSubType(t));
+      }
+      return Type(types);
+    }
+    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);
+          }
+          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;
+    }
+    return pick(options);
+  }
+
+  void setupMemory() {
+    // Add memory itself
+    MemoryUtils::ensureExists(wasm.memory);
+    if (wasm.features.hasBulkMemory()) {
+      size_t memCovered = 0;
+      // need at least one segment for memory.inits
+      size_t numSegments = upTo(8) + 1;
+      for (size_t i = 0; i < numSegments; i++) {
+        Memory::Segment segment;
+        segment.isPassive = bool(upTo(2));
+        size_t segSize = upTo(USABLE_MEMORY * 2);
+        segment.data.resize(segSize);
+        for (size_t j = 0; j < segSize; j++) {
+          segment.data[j] = upTo(512);
+        }
+        if (!segment.isPassive) {
+          segment.offset = builder.makeConst(int32_t(memCovered));
+          memCovered += segSize;
+        }
+        wasm.memory.segments.push_back(segment);
+      }
+    } else {
+      // init some data
+      wasm.memory.segments.emplace_back(builder.makeConst(int32_t(0)));
+      auto num = upTo(USABLE_MEMORY * 2);
+      for (size_t i = 0; i < num; i++) {
+        auto value = upTo(512);
+        wasm.memory.segments[0].data.push_back(value >= 256 ? 0
+                                                            : (value & 0xff));
+      }
+    }
+    // Add memory hasher helper (for the hash, see hash.h). The function looks
+    // like:
+    // function hashMemory() {
+    //   hash = 5381;
+    //   hash = ((hash << 5) + hash) ^ mem[0];
+    //   hash = ((hash << 5) + hash) ^ mem[1];
+    //   ..
+    //   return hash;
+    // }
+    std::vector<Expression*> contents;
+    contents.push_back(
+      builder.makeLocalSet(0, builder.makeConst(uint32_t(5381))));
+    auto zero = Literal::makeFromInt32(0, wasm.memory.indexType);
+    for (Index i = 0; i < USABLE_MEMORY; i++) {
+      contents.push_back(builder.makeLocalSet(
+        0,
+        builder.makeBinary(
+          XorInt32,
+          builder.makeBinary(
+            AddInt32,
+            builder.makeBinary(ShlInt32,
+                               builder.makeLocalGet(0, Type::i32),
+                               builder.makeConst(uint32_t(5))),
+            builder.makeLocalGet(0, Type::i32)),
+          builder.makeLoad(
+            1, false, i, 1, builder.makeConst(zero), Type::i32))));
+    }
+    contents.push_back(builder.makeLocalGet(0, Type::i32));
+    auto* body = builder.makeBlock(contents);
+    auto* hasher = wasm.addFunction(builder.makeFunction(
+      "hashMemory", Signature(Type::none, Type::i32), {Type::i32}, body));
+    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));
+  }
+
+  void setupTable() {
+    wasm.table.exists = true;
+    wasm.table.segments.emplace_back(builder.makeConst(int32_t(0)));
+  }
+
+  std::map<Type, std::vector<Name>> globalsByType;
+
+  void setupGlobals() {
+    for (size_t index = upTo(MAX_GLOBALS); index > 0; --index) {
+      auto type = getConcreteType();
+      auto* global =
+        builder.makeGlobal(std::string("global$") + std::to_string(index),
+                           type,
+                           makeConst(type),
+                           Builder::Mutable);
+      wasm.addGlobal(global);
+      globalsByType[type].push_back(global->name);
+    }
+  }
+
+  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),
+                          WASM_EVENT_ATTRIBUTE_EXCEPTION,
+                          Signature(getControlFlowType(), Type::none));
+      wasm.addEvent(event);
+    }
+  }
+
+  void finalizeTable() {
+    wasm.table.initial = wasm.table.segments[0].data.size();
+    wasm.table.max =
+      oneIn(2) ? Address(Table::kUnlimitedSize) : wasm.table.initial;
+  }
+
+  const Name HANG_LIMIT_GLOBAL = "hangLimit";
+
+  void addHangLimitSupport() {
+    auto* glob = builder.makeGlobal(HANG_LIMIT_GLOBAL,
+                                    Type::i32,
+                                    builder.makeConst(int32_t(HANG_LIMIT)),
+                                    Builder::Mutable);
+    wasm.addGlobal(glob);
+
+    auto* func = new Function;
+    func->name = "hangLimitInitializer";
+    func->sig = Signature(Type::none, Type::none);
+    func->body =
+      builder.makeGlobalSet(glob->name, builder.makeConst(int32_t(HANG_LIMIT)));
+    wasm.addFunction(func);
+
+    auto* export_ = new Export;
+    export_->name = func->name;
+    export_->value = func->name;
+    export_->kind = ExternalKind::Function;
+    wasm.addExport(export_);
+  }
+
+  void addImportLoggingSupport() {
+    for (auto type : getLoggableTypes()) {
+      auto* func = new Function;
+      Name name = std::string("log-") + type.toString();
+      func->name = name;
+      func->module = "fuzzing-support";
+      func->base = name;
+      func->sig = Signature(type, Type::none);
+      wasm.addFunction(func);
+    }
+  }
+
+  Expression* makeHangLimitCheck() {
+    return builder.makeSequence(
+      builder.makeIf(
+        builder.makeUnary(UnaryOp::EqZInt32,
+                          builder.makeGlobalGet(HANG_LIMIT_GLOBAL, Type::i32)),
+        makeTrivial(Type::unreachable)),
+      builder.makeGlobalSet(
+        HANG_LIMIT_GLOBAL,
+        builder.makeBinary(BinaryOp::SubInt32,
+                           builder.makeGlobalGet(HANG_LIMIT_GLOBAL, Type::i32),
+                           builder.makeConst(int32_t(1)))));
+  }
+
+  // function generation state
+
+  Function* func = nullptr;
+  std::vector<Expression*> breakableStack; // things we can break to
+  Index labelIndex;
+
+  // 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;
+
+  std::map<Type, std::vector<Index>>
+    typeLocals; // type => list of locals with that type
+
+  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());
+    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());
+      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());
+      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)) {
+      bodyType = Type::unreachable;
+    }
+    // with reasonable chance make the body a block
+    if (oneIn(2)) {
+      func->body = makeBlock(bodyType);
+    } else {
+      func->body = make(bodyType);
+    }
+    // Our OOB checks are already in the code, and if we recombine/mutate we
+    // may end up breaking them. TODO: do them after the fact, like with the
+    // hang limit checks.
+    if (allowOOB) {
+      // Recombinations create duplicate code patterns.
+      recombine(func);
+      // Mutations add random small changes, which can subtly break duplicate
+      // code patterns.
+      mutate(func);
+      // TODO: liveness operations on gets, with some prob alter a get to one
+      // with more possible sets.
+      // Recombination, mutation, etc. can break validation; fix things up
+      // after.
+      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)) {
+      auto* export_ = new Export;
+      export_->name = func->name;
+      export_->value = func->name;
+      export_->kind = ExternalKind::Function;
+      wasm.addExport(export_);
+    }
+    // add some to the table
+    while (oneIn(3) && !finishedInput) {
+      wasm.table.segments[0].data.push_back(func->name);
+    }
+    // cleanup
+    typeLocals.clear();
+    return func;
+  }
+
+  void addHangLimitChecks(Function* func) {
+    // loop limit
+    FindAll<Loop> loops(func->body);
+    for (auto* loop : loops.list) {
+      loop->body =
+        builder.makeSequence(makeHangLimitCheck(), loop->body, loop->type);
+    }
+    // recursion limit
+    func->body =
+      builder.makeSequence(makeHangLimitCheck(), func->body, func->sig.results);
+  }
+
+  void recombine(Function* func) {
+    // Don't always do this.
+    if (oneIn(2)) {
+      return;
+    }
+    // First, scan and group all expressions by type.
+    struct Scanner
+      : public PostWalker<Scanner, UnifiedExpressionVisitor<Scanner>> {
+      // A map of all expressions, categorized by type.
+      std::map<Type, std::vector<Expression*>> exprsByType;
+
+      void visitExpression(Expression* curr) {
+        exprsByType[curr->type].push_back(curr);
+      }
+    };
+    Scanner scanner;
+    scanner.walk(func->body);
+    // Potentially trim the list of possible picks, so replacements are more
+    // likely to collide.
+    for (auto& pair : scanner.exprsByType) {
+      if (oneIn(2)) {
+        continue;
+      }
+      auto& list = pair.second;
+      std::vector<Expression*> trimmed;
+      size_t num = upToSquared(list.size());
+      for (size_t i = 0; i < num; i++) {
+        trimmed.push_back(pick(list));
+      }
+      if (trimmed.empty()) {
+        trimmed.push_back(pick(list));
+      }
+      list.swap(trimmed);
+    }
+    // Replace them with copies, to avoid a copy into one altering another copy
+    for (auto& pair : scanner.exprsByType) {
+      for (auto*& item : pair.second) {
+        item = ExpressionManipulator::copy(item, wasm);
+      }
+    }
+    // Second, with some probability replace an item with another item having
+    // the same type. (This is not always valid due to nesting of labels, but
+    // we'll fix that up later.)
+    struct Modder
+      : public PostWalker<Modder, UnifiedExpressionVisitor<Modder>> {
+      Module& wasm;
+      Scanner& scanner;
+      TranslateToFuzzReader& parent;
+
+      Modder(Module& wasm, Scanner& scanner, TranslateToFuzzReader& parent)
+        : wasm(wasm), scanner(scanner), parent(parent) {}
+
+      void visitExpression(Expression* curr) {
+        if (parent.oneIn(10)) {
+          // Replace it!
+          auto& candidates = scanner.exprsByType[curr->type];
+          assert(!candidates.empty()); // this expression itself must be there
+          replaceCurrent(
+            ExpressionManipulator::copy(parent.pick(candidates), wasm));
+        }
+      }
+    };
+    Modder modder(wasm, scanner, *this);
+    modder.walk(func->body);
+  }
+
+  void mutate(Function* func) {
+    // Don't always do this.
+    if (oneIn(2)) {
+      return;
+    }
+    struct Modder
+      : public PostWalker<Modder, UnifiedExpressionVisitor<Modder>> {
+      Module& wasm;
+      TranslateToFuzzReader& parent;
+
+      Modder(Module& wasm, TranslateToFuzzReader& parent)
+        : wasm(wasm), parent(parent) {}
+
+      void visitExpression(Expression* curr) {
+        if (parent.oneIn(10)) {
+          // Replace it!
+          // (This is not always valid due to nesting of labels, but
+          // we'll fix that up later.)
+          replaceCurrent(parent.make(curr->type));
+        }
+      }
+    };
+    Modder modder(wasm, *this);
+    modder.walk(func->body);
+  }
+
+  // Fix up changes that may have broken validation - types are correct in our
+  // modding, but not necessarily labels.
+  void fixLabels(Function* func) {
+    struct Fixer : public ControlFlowWalker<Fixer> {
+      Module& wasm;
+      TranslateToFuzzReader& parent;
+
+      Fixer(Module& wasm, TranslateToFuzzReader& parent)
+        : wasm(wasm), parent(parent) {}
+
+      // Track seen names to find duplication, which is invalid.
+      std::set<Name> seen;
+
+      void visitBlock(Block* curr) {
+        if (curr->name.is()) {
+          if (seen.count(curr->name)) {
+            replace();
+          } else {
+            seen.insert(curr->name);
+          }
+        }
+      }
+
+      void visitLoop(Loop* curr) {
+        if (curr->name.is()) {
+          if (seen.count(curr->name)) {
+            replace();
+          } else {
+            seen.insert(curr->name);
+          }
+        }
+      }
+
+      void visitSwitch(Switch* curr) {
+        for (auto name : curr->targets) {
+          if (replaceIfInvalid(name)) {
+            return;
+          }
+        }
+        replaceIfInvalid(curr->default_);
+      }
+
+      void visitBreak(Break* curr) { replaceIfInvalid(curr->name); }
+
+      void visitBrOnExn(BrOnExn* curr) { replaceIfInvalid(curr->name); }
+
+      bool replaceIfInvalid(Name target) {
+        if (!hasBreakTarget(target)) {
+          // There is no valid parent, replace with something trivially safe.
+          replace();
+          return true;
+        }
+        return false;
+      }
+
+      void replace() { replaceCurrent(parent.makeTrivial(getCurrent()->type)); }
+
+      bool hasBreakTarget(Name name) {
+        if (controlFlowStack.empty()) {
+          return false;
+        }
+        Index i = controlFlowStack.size() - 1;
+        while (1) {
+          auto* curr = controlFlowStack[i];
+          if (auto* block = curr->dynCast<Block>()) {
+            if (name == block->name) {
+              return true;
+            }
+          } else if (auto* loop = curr->dynCast<Loop>()) {
+            if (name == loop->name) {
+              return true;
+            }
+          } else {
+            // an if or a try, ignorable
+            assert(curr->is<If>() || curr->is<Try>());
+          }
+          if (i == 0) {
+            return false;
+          }
+          i--;
+        }
+      }
+    };
+    Fixer fixer(wasm, *this);
+    fixer.walk(func->body);
+    ReFinalize().walkFunctionInModule(func, &wasm);
+  }
+
+  // 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) {
+    std::vector<Expression*> invocations;
+    while (oneIn(2) && !finishedInput) {
+      std::vector<Expression*> args;
+      for (const auto& type : func->sig.params) {
+        args.push_back(makeConst(type));
+      }
+      Expression* invoke =
+        builder.makeCall(func->name, args, func->sig.results);
+      if (func->sig.results.isConcrete()) {
+        invoke = builder.makeDrop(invoke);
+      }
+      invocations.push_back(invoke);
+      // log out memory in some cases
+      if (oneIn(2)) {
+        invocations.push_back(makeMemoryHashLogging());
+      }
+    }
+    if (invocations.empty()) {
+      return;
+    }
+    auto* invoker = new Function;
+    invoker->name = func->name.str + std::string("_invoker");
+    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_->kind = ExternalKind::Function;
+    wasm.addExport(export_);
+  }
+
+  Name makeLabel() {
+    return std::string("label$") + std::to_string(labelIndex++);
+  }
+
+  // Weighting for the core make* methods. Some nodes are important enough that
+  // we should do them quite often.
+  static const size_t VeryImportant = 4;
+  static const size_t Important = 2;
+
+  // always call the toplevel make(type) command, not the internal specific ones
+
+  int nesting = 0;
+
+  Expression* make(Type type) {
+    // when we should stop, emit something small (but not necessarily trivial)
+    if (finishedInput || nesting >= 5 * NESTING_LIMIT || // hard limit
+        (nesting >= NESTING_LIMIT && !oneIn(3))) {
+      if (type.isConcrete()) {
+        if (oneIn(2)) {
+          return makeConst(type);
+        } else {
+          return makeLocalGet(type);
+        }
+      } else if (type == Type::none) {
+        if (oneIn(2)) {
+          return makeNop(type);
+        } else {
+          return makeLocalSet(type);
+        }
+      }
+      assert(type == Type::unreachable);
+      return makeTrivial(type);
+    }
+    nesting++;
+    Expression* ret = nullptr;
+    if (type.isConcrete()) {
+      ret = _makeConcrete(type);
+    } else if (type == Type::none) {
+      ret = _makenone();
+    } else {
+      assert(type == Type::unreachable);
+      ret = _makeunreachable();
+    }
+    // we should create the right type of thing
+    assert(Type::isSubType(ret->type, type));
+    nesting--;
+    return ret;
+  }
+
+  Expression* _makeConcrete(Type type) {
+    bool canMakeControlFlow = !type.isTuple() || wasm.features.hasMultivalue();
+    using Self = TranslateToFuzzReader;
+    FeatureOptions<Expression* (Self::*)(Type)> options;
+    using WeightedOption = decltype(options)::WeightedOption;
+    options.add(FeatureSet::MVP,
+                WeightedOption{&Self::makeLocalGet, VeryImportant},
+                WeightedOption{&Self::makeLocalSet, VeryImportant},
+                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);
+    }
+    if (type.isSingle()) {
+      options
+        .add(FeatureSet::MVP,
+             WeightedOption{&Self::makeUnary, Important},
+             WeightedOption{&Self::makeBinary, Important},
+             &Self::makeSelect)
+        .add(FeatureSet::Multivalue, &Self::makeTupleExtract);
+    }
+    if (type.isSingle() && !type.isRef()) {
+      options.add(FeatureSet::MVP, {&Self::makeLoad, Important});
+      options.add(FeatureSet::SIMD, &Self::makeSIMD);
+    }
+    if (type.isInteger()) {
+      options.add(FeatureSet::Atomics, &Self::makeAtomic);
+    }
+    if (type == Type::i32) {
+      options.add(FeatureSet::ReferenceTypes, &Self::makeRefIsNull);
+      options.add(FeatureSet::ReferenceTypes | FeatureSet::GC,
+                  &Self::makeRefEq,
+                  &Self::makeI31Get);
+    }
+    if (type.isTuple()) {
+      options.add(FeatureSet::Multivalue, &Self::makeTupleMake);
+    }
+    if (type == Type::i31ref) {
+      options.add(FeatureSet::ReferenceTypes | FeatureSet::GC,
+                  &Self::makeI31New);
+    }
+    return (this->*pick(options))(type);
+  }
+
+  Expression* _makenone() {
+    auto choice = upTo(100);
+    if (choice < LOGGING_PERCENT) {
+      if (choice < LOGGING_PERCENT / 2) {
+        return makeLogging();
+      } else {
+        return makeMemoryHashLogging();
+      }
+    }
+    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},
+           &Self::makeCall,
+           &Self::makeCallIndirect,
+           &Self::makeDrop,
+           &Self::makeNop,
+           &Self::makeGlobalSet)
+      .add(FeatureSet::BulkMemory, &Self::makeBulkMemory)
+      .add(FeatureSet::Atomics, &Self::makeAtomic);
+    return (this->*pick(options))(Type::none);
+  }
+
+  Expression* _makeunreachable() {
+    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);
+    return (this->*pick(options))(Type::unreachable);
+  }
+
+  // make something with no chance of infinite recursion
+  Expression* makeTrivial(Type type) {
+    if (type.isConcrete()) {
+      if (oneIn(2)) {
+        return makeLocalGet(type);
+      } else {
+        return makeConst(type);
+      }
+    } else if (type == Type::none) {
+      return makeNop(type);
+    }
+    assert(type == Type::unreachable);
+    Expression* ret = nullptr;
+    if (func->sig.results.isConcrete()) {
+      ret = makeTrivial(func->sig.results);
+    }
+    return builder.makeReturn(ret);
+  }
+
+  // specific expression creators
+
+  Expression* makeBlock(Type type) {
+    auto* ret = builder.makeBlock();
+    ret->type = type; // so we have it during child creation
+    ret->name = makeLabel();
+    breakableStack.push_back(ret);
+    Index num = upToSquared(BLOCK_FACTOR - 1); // we add another later
+    if (nesting >= NESTING_LIMIT / 2) {
+      // smaller blocks past the limit
+      num /= 2;
+      if (nesting >= NESTING_LIMIT && oneIn(2)) {
+        // smaller blocks past the limit
+        num /= 2;
+      }
+    }
+    // not likely to have a block of size 1
+    if (num == 0 && !oneIn(10)) {
+      num++;
+    }
+    while (num > 0 && !finishedInput) {
+      ret->list.push_back(make(Type::none));
+      num--;
+    }
+    // give a chance to make the final element an unreachable break, instead
+    // of concrete - a common pattern (branch to the top of a loop etc.)
+    if (!finishedInput && type.isConcrete() && oneIn(2)) {
+      ret->list.push_back(makeBreak(Type::unreachable));
+    } else {
+      ret->list.push_back(make(type));
+    }
+    breakableStack.pop_back();
+    if (type.isConcrete()) {
+      ret->finalize(type);
+    } else {
+      ret->finalize();
+    }
+    if (ret->type != type) {
+      // e.g. we might want an unreachable block, but a child breaks to it
+      assert(type == Type::unreachable && ret->type == Type::none);
+      return builder.makeSequence(ret, make(Type::unreachable));
+    }
+    return ret;
+  }
+
+  Expression* makeLoop(Type type) {
+    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);
+    // either create random content, or do something more targeted
+    if (oneIn(2)) {
+      ret->body = makeMaybeBlock(type);
+    } else {
+      // ensure a branch back. also optionally create some loop vars
+      std::vector<Expression*> list;
+      list.push_back(makeMaybeBlock(Type::none)); // primary contents
+      // possible branch back
+      list.push_back(builder.makeBreak(ret->name, nullptr, makeCondition()));
+      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();
+    ret->finalize(type);
+    return ret;
+  }
+
+  Expression* makeCondition() {
+    // we want a 50-50 chance for the condition to be taken, for interesting
+    // execution paths. by itself, there is bias (e.g. most consts are "yes")
+    // so even that out with noise
+    auto* ret = make(Type::i32);
+    if (oneIn(2)) {
+      ret = builder.makeUnary(UnaryOp::EqZInt32, ret);
+    }
+    return ret;
+  }
+
+  // make something, with a good chance of it being a block
+  Expression* makeMaybeBlock(Type type) {
+    // if past the limit, prefer not to emit blocks
+    if (nesting >= NESTING_LIMIT || oneIn(3)) {
+      return make(type);
+    } else {
+      return makeBlock(type);
+    }
+  }
+
+  Expression* buildIf(const struct ThreeArgs& args, Type type) {
+    return builder.makeIf(args.a, args.b, args.c, type);
+  }
+
+  Expression* makeIf(Type type) {
+    auto* condition = makeCondition();
+    hangStack.push_back(nullptr);
+    auto* ret =
+      buildIf({condition, makeMaybeBlock(type), makeMaybeBlock(type)}, type);
+    hangStack.pop_back();
+    return ret;
+  }
+
+  Expression* makeBreak(Type type) {
+    if (breakableStack.empty()) {
+      return makeTrivial(type);
+    }
+    Expression* condition = nullptr;
+    if (type != Type::unreachable) {
+      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 name = getTargetName(target);
+      auto valueType = getTargetType(target);
+      if (type.isConcrete()) {
+        // we are flowing out a value
+        if (valueType != type) {
+          // we need to break to a proper place
+          continue;
+        }
+        auto* ret = builder.makeBreak(name, make(type), condition);
+        hangStack.pop_back();
+        return ret;
+      } else if (type == Type::none) {
+        if (valueType != Type::none) {
+          // we need to break to a proper place
+          continue;
+        }
+        auto* ret = builder.makeBreak(name, nullptr, condition);
+        hangStack.pop_back();
+        return ret;
+      } else {
+        assert(type == Type::unreachable);
+        if (valueType != Type::none) {
+          // we need to break to a proper place
+          continue;
+        }
+        // we are about to make an *un*conditional break. if it is
+        // 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();
+        while (--i >= 0) {
+          auto* item = hangStack[i];
+          if (item == nullptr) {
+            conditions++;
+          } else if (auto* loop = item->cast<Loop>()) {
+            if (loop->name == name) {
+              // we found the target, no more conditions matter
+              break;
+            }
+          }
+        }
+        switch (conditions) {
+          case 0: {
+            if (!oneIn(4)) {
+              continue;
+            }
+            break;
+          }
+          case 1: {
+            if (!oneIn(2)) {
+              continue;
+            }
+            break;
+          }
+          default: {
+            if (oneIn(conditions + 1)) {
+              continue;
+            }
+          }
+        }
+        return builder.makeBreak(name);
+      }
+    }
+    // we failed to find something
+    if (type != Type::unreachable) {
+      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;
+      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;
+      if (target->sig.results != type && !isReturn) {
+        continue;
+      }
+      // we found one!
+      std::vector<Expression*> args;
+      for (const auto& argType : target->sig.params) {
+        args.push_back(make(argType));
+      }
+      return builder.makeCall(target->name, args, type, isReturn);
+    }
+    // we failed to find something
+    return make(type);
+  }
+
+  Expression* makeCallIndirect(Type type) {
+    auto& data = wasm.table.segments[0].data;
+    if (data.empty()) {
+      return make(type);
+    }
+    // look for a call target with the right type
+    Index start = upTo(data.size());
+    Index i = start;
+    Function* targetFn;
+    bool isReturn;
+    while (1) {
+      // TODO: handle unreachable
+      targetFn = wasm.getFunction(data[i]);
+      isReturn = type == Type::unreachable && wasm.features.hasTailCall() &&
+                 func->sig.results == targetFn->sig.results;
+      if (targetFn->sig.results == type || isReturn) {
+        break;
+      }
+      i++;
+      if (i == data.size()) {
+        i = 0;
+      }
+      if (i == start) {
+        return make(type);
+      }
+    }
+    // with high probability, make sure the type is valid  otherwise, most are
+    // going to trap
+    Expression* target;
+    if (!allowOOB || !oneIn(10)) {
+      target = builder.makeConst(int32_t(i));
+    } else {
+      target = make(Type::i32);
+    }
+    std::vector<Expression*> args;
+    for (const auto& type : targetFn->sig.params) {
+      args.push_back(make(type));
+    }
+    return builder.makeCallIndirect(target, args, targetFn->sig, isReturn);
+  }
+
+  Expression* makeLocalGet(Type type) {
+    auto& locals = typeLocals[type];
+    if (locals.empty()) {
+      return makeConst(type);
+    }
+    return builder.makeLocalGet(pick(locals), type);
+  }
+
+  Expression* makeLocalSet(Type type) {
+    bool tee = type != Type::none;
+    Type valueType;
+    if (tee) {
+      valueType = type;
+    } else {
+      valueType = getConcreteType();
+    }
+    auto& locals = typeLocals[valueType];
+    if (locals.empty()) {
+      return makeTrivial(type);
+    }
+    auto* value = make(valueType);
+    if (tee) {
+      return builder.makeLocalTee(pick(locals), value, valueType);
+    } else {
+      return builder.makeLocalSet(pick(locals), value);
+    }
+  }
+
+  // Some globals are for internal use, and should not be modified by random
+  // fuzz code.
+  bool isValidGlobal(Name name) { return name != HANG_LIMIT_GLOBAL; }
+
+  Expression* makeGlobalGet(Type type) {
+    auto it = globalsByType.find(type);
+    if (it == globalsByType.end() || it->second.empty()) {
+      return makeConst(type);
+    }
+    auto name = pick(it->second);
+    if (isValidGlobal(name)) {
+      return builder.makeGlobalGet(name, type);
+    } else {
+      return makeTrivial(type);
+    }
+  }
+
+  Expression* makeGlobalSet(Type type) {
+    assert(type == Type::none);
+    type = getConcreteType();
+    auto it = globalsByType.find(type);
+    if (it == globalsByType.end() || it->second.empty()) {
+      return makeTrivial(Type::none);
+    }
+    auto name = pick(it->second);
+    if (isValidGlobal(name)) {
+      return builder.makeGlobalSet(name, make(type));
+    } else {
+      return makeTrivial(Type::none);
+    }
+  }
+
+  Expression* makeTupleMake(Type type) {
+    assert(wasm.features.hasMultivalue());
+    assert(type.isTuple());
+    std::vector<Expression*> elements;
+    for (const auto& t : type) {
+      elements.push_back(make(t));
+    }
+    return builder.makeTupleMake(std::move(elements));
+  }
+
+  Expression* makeTupleExtract(Type type) {
+    assert(wasm.features.hasMultivalue());
+    assert(type.isSingle() && type.isConcrete());
+    Type tupleType = getTupleType();
+
+    // Find indices from which we can extract `type`
+    std::vector<size_t> extractIndices;
+    size_t i = 0;
+    for (const auto& t : tupleType) {
+      if (t == type) {
+        extractIndices.push_back(i);
+      }
+      ++i;
+    }
+
+    // If there are none, inject one
+    if (extractIndices.size() == 0) {
+      std::vector<Type> newElements(tupleType.begin(), tupleType.end());
+      size_t injected = upTo(newElements.size());
+      newElements[injected] = type;
+      tupleType = Type(newElements);
+      extractIndices.push_back(injected);
+    }
+
+    Index index = pick(extractIndices);
+    Expression* child = make(tupleType);
+    return builder.makeTupleExtract(child, index);
+  }
+
+  Expression* makePointer() {
+    auto* ret = make(wasm.memory.indexType);
+    // with high probability, mask the pointer so it's in a reasonable
+    // range. otherwise, most pointers are going to be out of range and
+    // most memory ops will just trap
+    if (!allowOOB || !oneIn(10)) {
+      if (wasm.memory.is64()) {
+        ret = builder.makeBinary(
+          AndInt64, ret, builder.makeConst(int64_t(USABLE_MEMORY - 1)));
+      } else {
+        ret = builder.makeBinary(
+          AndInt32, ret, builder.makeConst(int32_t(USABLE_MEMORY - 1)));
+      }
+    }
+    return ret;
+  }
+
+  Expression* makeNonAtomicLoad(Type type) {
+    auto offset = logify(get());
+    auto ptr = makePointer();
+    switch (type.getBasic()) {
+      case Type::i32: {
+        bool signed_ = get() & 1;
+        switch (upTo(3)) {
+          case 0:
+            return builder.makeLoad(1, signed_, offset, 1, ptr, type);
+          case 1:
+            return builder.makeLoad(2, signed_, offset, pick(1, 2), ptr, type);
+          case 2:
+            return builder.makeLoad(
+              4, signed_, offset, pick(1, 2, 4), ptr, type);
+        }
+        WASM_UNREACHABLE("unexpected value");
+      }
+      case Type::i64: {
+        bool signed_ = get() & 1;
+        switch (upTo(4)) {
+          case 0:
+            return builder.makeLoad(1, signed_, offset, 1, ptr, type);
+          case 1:
+            return builder.makeLoad(2, signed_, offset, pick(1, 2), ptr, type);
+          case 2:
+            return builder.makeLoad(
+              4, signed_, offset, pick(1, 2, 4), ptr, type);
+          case 3:
+            return builder.makeLoad(
+              8, signed_, offset, pick(1, 2, 4, 8), ptr, type);
+        }
+        WASM_UNREACHABLE("unexpected value");
+      }
+      case Type::f32: {
+        return builder.makeLoad(4, false, offset, pick(1, 2, 4), ptr, type);
+      }
+      case Type::f64: {
+        return builder.makeLoad(8, false, offset, pick(1, 2, 4, 8), ptr, type);
+      }
+      case Type::v128: {
+        if (!wasm.features.hasSIMD()) {
+          return makeTrivial(type);
+        }
+        return builder.makeLoad(
+          16, false, offset, pick(1, 2, 4, 8, 16), ptr, type);
+      }
+      case Type::funcref:
+      case Type::externref:
+      case Type::exnref:
+      case Type::anyref:
+      case Type::eqref:
+      case Type::i31ref:
+      case Type::none:
+      case Type::unreachable:
+        WASM_UNREACHABLE("invalid type");
+    }
+    WASM_UNREACHABLE("invalid type");
+  }
+
+  Expression* makeLoad(Type type) {
+    // reference types cannot be stored in memory
+    if (!allowMemory || type.isRef()) {
+      return makeTrivial(type);
+    }
+    auto* ret = makeNonAtomicLoad(type);
+    if (type != Type::i32 && type != Type::i64) {
+      return ret;
+    }
+    if (!wasm.features.hasAtomics() || oneIn(2)) {
+      return ret;
+    }
+    // make it atomic
+    auto* load = ret->cast<Load>();
+    wasm.memory.shared = true;
+    load->isAtomic = true;
+    load->signed_ = false;
+    load->align = load->bytes;
+    return load;
+  }
+
+  Expression* makeNonAtomicStore(Type type) {
+    if (type == Type::unreachable) {
+      // make a normal store, then make it unreachable
+      auto* ret = makeNonAtomicStore(getStorableType());
+      auto* store = ret->dynCast<Store>();
+      if (!store) {
+        return ret;
+      }
+      switch (upTo(3)) {
+        case 0:
+          store->ptr = make(Type::unreachable);
+          break;
+        case 1:
+          store->value = make(Type::unreachable);
+          break;
+        case 2:
+          store->ptr = make(Type::unreachable);
+          store->value = make(Type::unreachable);
+          break;
+      }
+      store->finalize();
+      return store;
+    }
+    // the type is none or unreachable. we also need to pick the value
+    // type.
+    if (type == Type::none) {
+      type = getStorableType();
+    }
+    auto offset = logify(get());
+    auto ptr = makePointer();
+    auto value = make(type);
+    switch (type.getBasic()) {
+      case Type::i32: {
+        switch (upTo(3)) {
+          case 0:
+            return builder.makeStore(1, offset, 1, ptr, value, type);
+          case 1:
+            return builder.makeStore(2, offset, pick(1, 2), ptr, value, type);
+          case 2:
+            return builder.makeStore(
+              4, offset, pick(1, 2, 4), ptr, value, type);
+        }
+        WASM_UNREACHABLE("invalid value");
+      }
+      case Type::i64: {
+        switch (upTo(4)) {
+          case 0:
+            return builder.makeStore(1, offset, 1, ptr, value, type);
+          case 1:
+            return builder.makeStore(2, offset, pick(1, 2), ptr, value, type);
+          case 2:
+            return builder.makeStore(
+              4, offset, pick(1, 2, 4), ptr, value, type);
+          case 3:
+            return builder.makeStore(
+              8, offset, pick(1, 2, 4, 8), ptr, value, type);
+        }
+        WASM_UNREACHABLE("invalid value");
+      }
+      case Type::f32: {
+        return builder.makeStore(4, offset, pick(1, 2, 4), ptr, value, type);
+      }
+      case Type::f64: {
+        return builder.makeStore(8, offset, pick(1, 2, 4, 8), ptr, value, type);
+      }
+      case Type::v128: {
+        if (!wasm.features.hasSIMD()) {
+          return makeTrivial(type);
+        }
+        return builder.makeStore(
+          16, offset, pick(1, 2, 4, 8, 16), ptr, value, type);
+      }
+      case Type::funcref:
+      case Type::externref:
+      case Type::exnref:
+      case Type::anyref:
+      case Type::eqref:
+      case Type::i31ref:
+      case Type::none:
+      case Type::unreachable:
+        WASM_UNREACHABLE("invalid type");
+    }
+    WASM_UNREACHABLE("invalid type");
+  }
+
+  Expression* makeStore(Type type) {
+    if (!allowMemory || type.isRef()) {
+      return makeTrivial(type);
+    }
+    auto* ret = makeNonAtomicStore(type);
+    auto* store = ret->dynCast<Store>();
+    if (!store) {
+      return ret;
+    }
+    if (store->value->type != Type::i32 && store->value->type != Type::i64) {
+      return store;
+    }
+    if (!wasm.features.hasAtomics() || oneIn(2)) {
+      return store;
+    }
+    // make it atomic
+    wasm.memory.shared = true;
+    store->isAtomic = true;
+    store->align = store->bytes;
+    return store;
+  }
+
+  Literal makeLiteral(Type type) {
+    if (type == Type::v128) {
+      // generate each lane individually for random lane interpretation
+      switch (upTo(6)) {
+        case 0:
+          return Literal(std::array<Literal, 16>{{makeLiteral(Type::i32),
+                                                  makeLiteral(Type::i32),
+                                                  makeLiteral(Type::i32),
+                                                  makeLiteral(Type::i32),
+                                                  makeLiteral(Type::i32),
+                                                  makeLiteral(Type::i32),
+                                                  makeLiteral(Type::i32),
+                                                  makeLiteral(Type::i32),
+                                                  makeLiteral(Type::i32),
+                                                  makeLiteral(Type::i32),
+                                                  makeLiteral(Type::i32),
+                                                  makeLiteral(Type::i32),
+                                                  makeLiteral(Type::i32),
+                                                  makeLiteral(Type::i32),
+                                                  makeLiteral(Type::i32),
+                                                  makeLiteral(Type::i32)}});
+        case 1:
+          return Literal(std::array<Literal, 8>{{makeLiteral(Type::i32),
+                                                 makeLiteral(Type::i32),
+                                                 makeLiteral(Type::i32),
+                                                 makeLiteral(Type::i32),
+                                                 makeLiteral(Type::i32),
+                                                 makeLiteral(Type::i32),
+                                                 makeLiteral(Type::i32),
+                                                 makeLiteral(Type::i32)}});
+        case 2:
+          return Literal(std::array<Literal, 4>{{makeLiteral(Type::i32),
+                                                 makeLiteral(Type::i32),
+                                                 makeLiteral(Type::i32),
+                                                 makeLiteral(Type::i32)}});
+        case 3:
+          return Literal(std::array<Literal, 2>{
+            {makeLiteral(Type::i64), makeLiteral(Type::i64)}});
+        case 4:
+          return Literal(std::array<Literal, 4>{{makeLiteral(Type::f32),
+                                                 makeLiteral(Type::f32),
+                                                 makeLiteral(Type::f32),
+                                                 makeLiteral(Type::f32)}});
+        case 5:
+          return Literal(std::array<Literal, 2>{
+            {makeLiteral(Type::f64), makeLiteral(Type::f64)}});
+        default:
+          WASM_UNREACHABLE("unexpected value");
+      }
+    }
+
+    // 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
+        switch (type.getBasic()) {
+          case Type::i32:
+            return Literal(get32());
+          case Type::i64:
+            return Literal(get64());
+          case Type::f32:
+            return Literal(getFloat());
+          case Type::f64:
+            return Literal(getDouble());
+          case Type::v128:
+          case Type::funcref:
+          case Type::externref:
+          case Type::exnref:
+          case Type::anyref:
+          case Type::eqref:
+          case Type::i31ref:
+          case Type::none:
+          case Type::unreachable:
+            WASM_UNREACHABLE("invalid type");
+        }
+        break;
+      }
+      case 1: {
+        // small range
+        int64_t small;
+        switch (upTo(6)) {
+          case 0:
+            small = int8_t(get());
+            break;
+          case 1:
+            small = uint8_t(get());
+            break;
+          case 2:
+            small = int16_t(get16());
+            break;
+          case 3:
+            small = uint16_t(get16());
+            break;
+          case 4:
+            small = int32_t(get32());
+            break;
+          case 5:
+            small = uint32_t(get32());
+            break;
+          default:
+            WASM_UNREACHABLE("invalid value");
+        }
+        switch (type.getBasic()) {
+          case Type::i32:
+            return Literal(int32_t(small));
+          case Type::i64:
+            return Literal(int64_t(small));
+          case Type::f32:
+            return Literal(float(small));
+          case Type::f64:
+            return Literal(double(small));
+          case Type::v128:
+          case Type::funcref:
+          case Type::externref:
+          case Type::exnref:
+          case Type::anyref:
+          case Type::eqref:
+          case Type::i31ref:
+          case Type::none:
+          case Type::unreachable:
+            WASM_UNREACHABLE("unexpected type");
+        }
+        break;
+      }
+      case 2: {
+        // special values
+        Literal value;
+        switch (type.getBasic()) {
+          case Type::i32:
+            value =
+              Literal(pick<int32_t>(0,
+                                    std::numeric_limits<int8_t>::min(),
+                                    std::numeric_limits<int8_t>::max(),
+                                    std::numeric_limits<int16_t>::min(),
+                                    std::numeric_limits<int16_t>::max(),
+                                    std::numeric_limits<int32_t>::min(),
+                                    std::numeric_limits<int32_t>::max(),
+                                    std::numeric_limits<uint8_t>::max(),
+                                    std::numeric_limits<uint16_t>::max(),
+                                    std::numeric_limits<uint32_t>::max()));
+            break;
+          case Type::i64:
+            value =
+              Literal(pick<int64_t>(0,
+                                    std::numeric_limits<int8_t>::min(),
+                                    std::numeric_limits<int8_t>::max(),
+                                    std::numeric_limits<int16_t>::min(),
+                                    std::numeric_limits<int16_t>::max(),
+                                    std::numeric_limits<int32_t>::min(),
+                                    std::numeric_limits<int32_t>::max(),
+                                    std::numeric_limits<int64_t>::min(),
+                                    std::numeric_limits<int64_t>::max(),
+                                    std::numeric_limits<uint8_t>::max(),
+                                    std::numeric_limits<uint16_t>::max(),
+                                    std::numeric_limits<uint32_t>::max(),
+                                    std::numeric_limits<uint64_t>::max()));
+            break;
+          case Type::f32:
+            value = Literal(pick<float>(0.0f,
+                                        -0.0f,
+                                        std::numeric_limits<float>::min(),
+                                        std::numeric_limits<float>::max(),
+                                        std::numeric_limits<int32_t>::min(),
+                                        std::numeric_limits<int32_t>::max(),
+                                        std::numeric_limits<int64_t>::min(),
+                                        std::numeric_limits<int64_t>::max(),
+                                        std::numeric_limits<uint32_t>::max(),
+                                        std::numeric_limits<uint64_t>::max()));
+            break;
+          case Type::f64:
+            value = Literal(pick<double>(0.0,
+                                         -0.0,
+                                         std::numeric_limits<float>::min(),
+                                         std::numeric_limits<float>::max(),
+                                         std::numeric_limits<double>::min(),
+                                         std::numeric_limits<double>::max(),
+                                         std::numeric_limits<int32_t>::min(),
+                                         std::numeric_limits<int32_t>::max(),
+                                         std::numeric_limits<int64_t>::min(),
+                                         std::numeric_limits<int64_t>::max(),
+                                         std::numeric_limits<uint32_t>::max(),
+                                         std::numeric_limits<uint64_t>::max()));
+            break;
+          case Type::v128:
+          case Type::funcref:
+          case Type::externref:
+          case Type::exnref:
+          case Type::anyref:
+          case Type::eqref:
+          case Type::i31ref:
+          case Type::none:
+          case Type::unreachable:
+            WASM_UNREACHABLE("unexpected type");
+        }
+        return tweak(value);
+      }
+      case 3: {
+        // powers of 2
+        Literal value;
+        switch (type.getBasic()) {
+          case Type::i32:
+            value = Literal(int32_t(1) << upTo(32));
+            break;
+          case Type::i64:
+            value = Literal(int64_t(1) << upTo(64));
+            break;
+          case Type::f32:
+            value = Literal(float(int64_t(1) << upTo(64)));
+            break;
+          case Type::f64:
+            value = Literal(double(int64_t(1) << upTo(64)));
+            break;
+          case Type::v128:
+          case Type::funcref:
+          case Type::externref:
+          case Type::exnref:
+          case Type::anyref:
+          case Type::eqref:
+          case Type::i31ref:
+          case Type::none:
+          case Type::unreachable:
+            WASM_UNREACHABLE("unexpected type");
+        }
+        return tweak(value);
+      }
+    }
+    WASM_UNREACHABLE("invalid value");
+  }
+
+  Expression* makeConst(Type type) {
+    if (type.isRef()) {
+      assert(wasm.features.hasReferenceTypes());
+      // Check if we can use ref.func.
+      // '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)) {
+        // First set to target to the last created function, and try to select
+        // among other existing function if possible
+        Function* target = func;
+        if (!wasm.functions.empty() && !oneIn(wasm.functions.size())) {
+          target = pick(wasm.functions).get();
+        }
+        return builder.makeRefFunc(target->name);
+      }
+      if (type == Type::i31ref) {
+        return builder.makeI31New(makeConst(Type::i32));
+      }
+      return builder.makeRefNull(type);
+    }
+    if (type.isTuple()) {
+      std::vector<Expression*> operands;
+      for (const auto& t : type) {
+        operands.push_back(makeConst(t));
+      }
+      return builder.makeTupleMake(std::move(operands));
+    }
+    auto* ret = wasm.allocator.alloc<Const>();
+    ret->value = makeLiteral(type);
+    ret->type = type;
+    return ret;
+  }
+
+  Expression* buildUnary(const UnaryArgs& args) {
+    return builder.makeUnary(args.a, args.b);
+  }
+
+  Expression* makeUnary(Type type) {
+    assert(!type.isTuple());
+    if (type == Type::unreachable) {
+      if (auto* unary = makeUnary(getSingleConcreteType())->dynCast<Unary>()) {
+        return builder.makeUnary(unary->op, make(Type::unreachable));
+      }
+      // give up
+      return makeTrivial(type);
+    }
+    // There's no unary ops for reference types
+    if (type.isRef()) {
+      return makeTrivial(type);
+    }
+
+    switch (type.getBasic()) {
+      case Type::i32: {
+        auto singleConcreteType = getSingleConcreteType();
+        TODO_SINGLE_COMPOUND(singleConcreteType);
+        switch (singleConcreteType.getBasic()) {
+          case Type::i32: {
+            auto op = pick(
+              FeatureOptions<UnaryOp>()
+                .add(FeatureSet::MVP, EqZInt32, ClzInt32, CtzInt32, PopcntInt32)
+                .add(FeatureSet::SignExt, ExtendS8Int32, ExtendS16Int32));
+            return buildUnary({op, make(Type::i32)});
+          }
+          case Type::i64:
+            return buildUnary({pick(EqZInt64, WrapInt64), make(Type::i64)});
+          case Type::f32: {
+            auto op = pick(FeatureOptions<UnaryOp>()
+                             .add(FeatureSet::MVP,
+                                  TruncSFloat32ToInt32,
+                                  TruncUFloat32ToInt32,
+                                  ReinterpretFloat32)
+                             .add(FeatureSet::TruncSat,
+                                  TruncSatSFloat32ToInt32,
+                                  TruncSatUFloat32ToInt32));
+            return buildUnary({op, make(Type::f32)});
+          }
+          case Type::f64: {
+            auto op = pick(FeatureOptions<UnaryOp>()
+                             .add(FeatureSet::MVP,
+                                  TruncSFloat64ToInt32,
+                                  TruncUFloat64ToInt32)
+                             .add(FeatureSet::TruncSat,
+                                  TruncSatSFloat64ToInt32,
+                                  TruncSatUFloat64ToInt32));
+            return buildUnary({op, make(Type::f64)});
+          }
+          case Type::v128: {
+            assert(wasm.features.hasSIMD());
+            return buildUnary({pick(AnyTrueVecI8x16,
+                                    AllTrueVecI8x16,
+                                    AnyTrueVecI16x8,
+                                    AllTrueVecI16x8,
+                                    AnyTrueVecI32x4,
+                                    AllTrueVecI32x4,
+                                    AnyTrueVecI64x2,
+                                    AllTrueVecI64x2),
+                               make(Type::v128)});
+          }
+          case Type::funcref:
+          case Type::externref:
+          case Type::exnref:
+          case Type::anyref:
+          case Type::eqref:
+          case Type::i31ref:
+            return makeTrivial(type);
+          case Type::none:
+          case Type::unreachable:
+            WASM_UNREACHABLE("unexpected type");
+        }
+        WASM_UNREACHABLE("invalid type");
+      }
+      case Type::i64: {
+        switch (upTo(4)) {
+          case 0: {
+            auto op =
+              pick(FeatureOptions<UnaryOp>()
+                     .add(FeatureSet::MVP, ClzInt64, CtzInt64, PopcntInt64)
+                     .add(FeatureSet::SignExt,
+                          ExtendS8Int64,
+                          ExtendS16Int64,
+                          ExtendS32Int64));
+            return buildUnary({op, make(Type::i64)});
+          }
+          case 1:
+            return buildUnary(
+              {pick(ExtendSInt32, ExtendUInt32), make(Type::i32)});
+          case 2: {
+            auto op = pick(FeatureOptions<UnaryOp>()
+                             .add(FeatureSet::MVP,
+                                  TruncSFloat32ToInt64,
+                                  TruncUFloat32ToInt64)
+                             .add(FeatureSet::TruncSat,
+                                  TruncSatSFloat32ToInt64,
+                                  TruncSatUFloat32ToInt64));
+            return buildUnary({op, make(Type::f32)});
+          }
+          case 3: {
+            auto op = pick(FeatureOptions<UnaryOp>()
+                             .add(FeatureSet::MVP,
+                                  TruncSFloat64ToInt64,
+                                  TruncUFloat64ToInt64,
+                                  ReinterpretFloat64)
+                             .add(FeatureSet::TruncSat,
+                                  TruncSatSFloat64ToInt64,
+                                  TruncSatUFloat64ToInt64));
+            return buildUnary({op, make(Type::f64)});
+          }
+        }
+        WASM_UNREACHABLE("invalid value");
+      }
+      case Type::f32: {
+        switch (upTo(4)) {
+          case 0:
+            return buildUnary({pick(NegFloat32,
+                                    AbsFloat32,
+                                    CeilFloat32,
+                                    FloorFloat32,
+                                    TruncFloat32,
+                                    NearestFloat32,
+                                    SqrtFloat32),
+                               make(Type::f32)});
+          case 1:
+            return buildUnary({pick(ConvertUInt32ToFloat32,
+                                    ConvertSInt32ToFloat32,
+                                    ReinterpretInt32),
+                               make(Type::i32)});
+          case 2:
+            return buildUnary(
+              {pick(ConvertUInt64ToFloat32, ConvertSInt64ToFloat32),
+               make(Type::i64)});
+          case 3:
+            return buildUnary({DemoteFloat64, make(Type::f64)});
+        }
+        WASM_UNREACHABLE("invalid value");
+      }
+      case Type::f64: {
+        switch (upTo(4)) {
+          case 0:
+            return buildUnary({pick(NegFloat64,
+                                    AbsFloat64,
+                                    CeilFloat64,
+                                    FloorFloat64,
+                                    TruncFloat64,
+                                    NearestFloat64,
+                                    SqrtFloat64),
+                               make(Type::f64)});
+          case 1:
+            return buildUnary(
+              {pick(ConvertUInt32ToFloat64, ConvertSInt32ToFloat64),
+               make(Type::i32)});
+          case 2:
+            return buildUnary({pick(ConvertUInt64ToFloat64,
+                                    ConvertSInt64ToFloat64,
+                                    ReinterpretInt64),
+                               make(Type::i64)});
+          case 3:
+            return buildUnary({PromoteFloat32, make(Type::f32)});
+        }
+        WASM_UNREACHABLE("invalid value");
+      }
+      case Type::v128: {
+        assert(wasm.features.hasSIMD());
+        switch (upTo(5)) {
+          case 0:
+            return buildUnary(
+              {pick(SplatVecI8x16, SplatVecI16x8, SplatVecI32x4),
+               make(Type::i32)});
+          case 1:
+            return buildUnary({SplatVecI64x2, make(Type::i64)});
+          case 2:
+            return buildUnary({SplatVecF32x4, make(Type::f32)});
+          case 3:
+            return buildUnary({SplatVecF64x2, make(Type::f64)});
+          case 4:
+            return buildUnary({pick(NotVec128,
+                                    NegVecI8x16,
+                                    NegVecI16x8,
+                                    NegVecI32x4,
+                                    NegVecI64x2,
+                                    AbsVecF32x4,
+                                    NegVecF32x4,
+                                    SqrtVecF32x4,
+                                    AbsVecF64x2,
+                                    NegVecF64x2,
+                                    SqrtVecF64x2,
+                                    TruncSatSVecF32x4ToVecI32x4,
+                                    TruncSatUVecF32x4ToVecI32x4,
+                                    TruncSatSVecF64x2ToVecI64x2,
+                                    TruncSatUVecF64x2ToVecI64x2,
+                                    ConvertSVecI32x4ToVecF32x4,
+                                    ConvertUVecI32x4ToVecF32x4,
+                                    ConvertSVecI64x2ToVecF64x2,
+                                    ConvertUVecI64x2ToVecF64x2,
+                                    WidenLowSVecI8x16ToVecI16x8,
+                                    WidenHighSVecI8x16ToVecI16x8,
+                                    WidenLowUVecI8x16ToVecI16x8,
+                                    WidenHighUVecI8x16ToVecI16x8,
+                                    WidenLowSVecI16x8ToVecI32x4,
+                                    WidenHighSVecI16x8ToVecI32x4,
+                                    WidenLowUVecI16x8ToVecI32x4,
+                                    WidenHighUVecI16x8ToVecI32x4),
+                               make(Type::v128)});
+        }
+        WASM_UNREACHABLE("invalid value");
+      }
+      case Type::funcref:
+      case Type::externref:
+      case Type::exnref:
+      case Type::anyref:
+      case Type::eqref:
+      case Type::i31ref:
+      case Type::none:
+      case Type::unreachable:
+        WASM_UNREACHABLE("unexpected type");
+    }
+    WASM_UNREACHABLE("invalid type");
+  }
+
+  Expression* buildBinary(const BinaryArgs& args) {
+    return builder.makeBinary(args.a, args.b, args.c);
+  }
+
+  Expression* makeBinary(Type type) {
+    assert(!type.isTuple());
+    if (type == Type::unreachable) {
+      if (auto* binary =
+            makeBinary(getSingleConcreteType())->dynCast<Binary>()) {
+        return buildBinary(
+          {binary->op, make(Type::unreachable), make(Type::unreachable)});
+      }
+      // give up
+      return makeTrivial(type);
+    }
+    // There's no binary ops for reference types
+    if (type.isRef()) {
+      return makeTrivial(type);
+    }
+
+    switch (type.getBasic()) {
+      case Type::i32: {
+        switch (upTo(4)) {
+          case 0:
+            return buildBinary({pick(AddInt32,
+                                     SubInt32,
+                                     MulInt32,
+                                     DivSInt32,
+                                     DivUInt32,
+                                     RemSInt32,
+                                     RemUInt32,
+                                     AndInt32,
+                                     OrInt32,
+                                     XorInt32,
+                                     ShlInt32,
+                                     ShrUInt32,
+                                     ShrSInt32,
+                                     RotLInt32,
+                                     RotRInt32,
+                                     EqInt32,
+                                     NeInt32,
+                                     LtSInt32,
+                                     LtUInt32,
+                                     LeSInt32,
+                                     LeUInt32,
+                                     GtSInt32,
+                                     GtUInt32,
+                                     GeSInt32,
+                                     GeUInt32),
+                                make(Type::i32),
+                                make(Type::i32)});
+          case 1:
+            return buildBinary({pick(EqInt64,
+                                     NeInt64,
+                                     LtSInt64,
+                                     LtUInt64,
+                                     LeSInt64,
+                                     LeUInt64,
+                                     GtSInt64,
+                                     GtUInt64,
+                                     GeSInt64,
+                                     GeUInt64),
+                                make(Type::i64),
+                                make(Type::i64)});
+          case 2:
+            return buildBinary({pick(EqFloat32,
+                                     NeFloat32,
+                                     LtFloat32,
+                                     LeFloat32,
+                                     GtFloat32,
+                                     GeFloat32),
+                                make(Type::f32),
+                                make(Type::f32)});
+          case 3:
+            return buildBinary({pick(EqFloat64,
+                                     NeFloat64,
+                                     LtFloat64,
+                                     LeFloat64,
+                                     GtFloat64,
+                                     GeFloat64),
+                                make(Type::f64),
+                                make(Type::f64)});
+        }
+        WASM_UNREACHABLE("invalid value");
+      }
+      case Type::i64: {
+        return buildBinary({pick(AddInt64,
+                                 SubInt64,
+                                 MulInt64,
+                                 DivSInt64,
+                                 DivUInt64,
+                                 RemSInt64,
+                                 RemUInt64,
+                                 AndInt64,
+                                 OrInt64,
+                                 XorInt64,
+                                 ShlInt64,
+                                 ShrUInt64,
+                                 ShrSInt64,
+                                 RotLInt64,
+                                 RotRInt64),
+                            make(Type::i64),
+                            make(Type::i64)});
+      }
+      case Type::f32: {
+        return buildBinary({pick(AddFloat32,
+                                 SubFloat32,
+                                 MulFloat32,
+                                 DivFloat32,
+                                 CopySignFloat32,
+                                 MinFloat32,
+                                 MaxFloat32),
+                            make(Type::f32),
+                            make(Type::f32)});
+      }
+      case Type::f64: {
+        return buildBinary({pick(AddFloat64,
+                                 SubFloat64,
+                                 MulFloat64,
+                                 DivFloat64,
+                                 CopySignFloat64,
+                                 MinFloat64,
+                                 MaxFloat64),
+                            make(Type::f64),
+                            make(Type::f64)});
+      }
+      case Type::v128: {
+        assert(wasm.features.hasSIMD());
+        return buildBinary({pick(EqVecI8x16,
+                                 NeVecI8x16,
+                                 LtSVecI8x16,
+                                 LtUVecI8x16,
+                                 GtSVecI8x16,
+                                 GtUVecI8x16,
+                                 LeSVecI8x16,
+                                 LeUVecI8x16,
+                                 GeSVecI8x16,
+                                 GeUVecI8x16,
+                                 EqVecI16x8,
+                                 NeVecI16x8,
+                                 LtSVecI16x8,
+                                 LtUVecI16x8,
+                                 GtSVecI16x8,
+                                 GtUVecI16x8,
+                                 LeSVecI16x8,
+                                 LeUVecI16x8,
+                                 GeSVecI16x8,
+                                 GeUVecI16x8,
+                                 EqVecI32x4,
+                                 NeVecI32x4,
+                                 LtSVecI32x4,
+                                 LtUVecI32x4,
+                                 GtSVecI32x4,
+                                 GtUVecI32x4,
+                                 LeSVecI32x4,
+                                 LeUVecI32x4,
+                                 GeSVecI32x4,
+                                 GeUVecI32x4,
+                                 EqVecF32x4,
+                                 NeVecF32x4,
+                                 LtVecF32x4,
+                                 GtVecF32x4,
+                                 LeVecF32x4,
+                                 GeVecF32x4,
+                                 EqVecF64x2,
+                                 NeVecF64x2,
+                                 LtVecF64x2,
+                                 GtVecF64x2,
+                                 LeVecF64x2,
+                                 GeVecF64x2,
+                                 AndVec128,
+                                 OrVec128,
+                                 XorVec128,
+                                 AndNotVec128,
+                                 AddVecI8x16,
+                                 AddSatSVecI8x16,
+                                 AddSatUVecI8x16,
+                                 SubVecI8x16,
+                                 SubSatSVecI8x16,
+                                 SubSatUVecI8x16,
+                                 MulVecI8x16,
+                                 MinSVecI8x16,
+                                 MinUVecI8x16,
+                                 MaxSVecI8x16,
+                                 MaxUVecI8x16,
+                                 AddVecI16x8,
+                                 AddSatSVecI16x8,
+                                 AddSatUVecI16x8,
+                                 SubVecI16x8,
+                                 SubSatSVecI16x8,
+                                 SubSatUVecI16x8,
+                                 MulVecI16x8,
+                                 MinSVecI16x8,
+                                 MinUVecI16x8,
+                                 MaxSVecI16x8,
+                                 MaxUVecI16x8,
+                                 AddVecI32x4,
+                                 SubVecI32x4,
+                                 MulVecI32x4,
+                                 MinSVecI32x4,
+                                 MinUVecI32x4,
+                                 MaxSVecI32x4,
+                                 MaxUVecI32x4,
+                                 DotSVecI16x8ToVecI32x4,
+                                 AddVecI64x2,
+                                 SubVecI64x2,
+                                 AddVecF32x4,
+                                 SubVecF32x4,
+                                 MulVecF32x4,
+                                 DivVecF32x4,
+                                 MinVecF32x4,
+                                 MaxVecF32x4,
+                                 AddVecF64x2,
+                                 SubVecF64x2,
+                                 MulVecF64x2,
+                                 DivVecF64x2,
+                                 MinVecF64x2,
+                                 MaxVecF64x2,
+                                 NarrowSVecI16x8ToVecI8x16,
+                                 NarrowUVecI16x8ToVecI8x16,
+                                 NarrowSVecI32x4ToVecI16x8,
+                                 NarrowUVecI32x4ToVecI16x8,
+                                 SwizzleVec8x16),
+                            make(Type::v128),
+                            make(Type::v128)});
+      }
+      case Type::funcref:
+      case Type::externref:
+      case Type::exnref:
+      case Type::anyref:
+      case Type::eqref:
+      case Type::i31ref:
+      case Type::none:
+      case Type::unreachable:
+        WASM_UNREACHABLE("unexpected type");
+    }
+    WASM_UNREACHABLE("invalid type");
+  }
+
+  Expression* buildSelect(const ThreeArgs& args, Type type) {
+    return builder.makeSelect(args.a, args.b, args.c, type);
+  }
+
+  Expression* makeSelect(Type type) {
+    Type subType1 = getSubType(type);
+    Type subType2 = getSubType(type);
+    return buildSelect({make(Type::i32), make(subType1), make(subType2)}, type);
+  }
+
+  Expression* makeSwitch(Type type) {
+    assert(type == Type::unreachable);
+    if (breakableStack.empty()) {
+      return make(type);
+    }
+    // we need to find proper targets to break to; try a bunch
+    int tries = TRIES;
+    std::vector<Name> names;
+    Type valueType = Type::unreachable;
+    while (tries-- > 0) {
+      auto* target = pick(breakableStack);
+      auto name = getTargetName(target);
+      auto currValueType = getTargetType(target);
+      if (names.empty()) {
+        valueType = currValueType;
+      } else {
+        if (valueType != currValueType) {
+          continue; // all values must be the same
+        }
+      }
+      names.push_back(name);
+    }
+    if (names.size() < 2) {
+      // we failed to find enough
+      return make(type);
+    }
+    auto default_ = names.back();
+    names.pop_back();
+    auto temp1 = make(Type::i32),
+         temp2 = valueType.isConcrete() ? make(valueType) : nullptr;
+    return builder.makeSwitch(names, default_, temp1, temp2);
+  }
+
+  Expression* makeDrop(Type type) {
+    return builder.makeDrop(
+      make(type == Type::unreachable ? type : getConcreteType()));
+  }
+
+  Expression* makeReturn(Type type) {
+    return builder.makeReturn(
+      func->sig.results.isConcrete() ? make(func->sig.results) : nullptr);
+  }
+
+  Expression* makeNop(Type type) {
+    assert(type == Type::none);
+    return builder.makeNop();
+  }
+
+  Expression* makeUnreachable(Type type) {
+    assert(type == Type::unreachable);
+    return builder.makeUnreachable();
+  }
+
+  Expression* makeAtomic(Type type) {
+    assert(wasm.features.hasAtomics());
+    if (!allowMemory) {
+      return makeTrivial(type);
+    }
+    wasm.memory.shared = true;
+    if (type == Type::none) {
+      return builder.makeAtomicFence();
+    }
+    if (type == Type::i32 && oneIn(2)) {
+      if (ATOMIC_WAITS && oneIn(2)) {
+        auto* ptr = makePointer();
+        auto expectedType = pick(Type::i32, Type::i64);
+        auto* expected = make(expectedType);
+        auto* timeout = make(Type::i64);
+        return builder.makeAtomicWait(
+          ptr, expected, timeout, expectedType, logify(get()));
+      } else {
+        auto* ptr = makePointer();
+        auto* count = make(Type::i32);
+        return builder.makeAtomicNotify(ptr, count, logify(get()));
+      }
+    }
+    Index bytes;
+    switch (type.getBasic()) {
+      case Type::i32: {
+        switch (upTo(3)) {
+          case 0:
+            bytes = 1;
+            break;
+          case 1:
+            bytes = pick(1, 2);
+            break;
+          case 2:
+            bytes = pick(1, 2, 4);
+            break;
+          default:
+            WASM_UNREACHABLE("invalide value");
+        }
+        break;
+      }
+      case Type::i64: {
+        switch (upTo(4)) {
+          case 0:
+            bytes = 1;
+            break;
+          case 1:
+            bytes = pick(1, 2);
+            break;
+          case 2:
+            bytes = pick(1, 2, 4);
+            break;
+          case 3:
+            bytes = pick(1, 2, 4, 8);
+            break;
+          default:
+            WASM_UNREACHABLE("invalide value");
+        }
+        break;
+      }
+      default:
+        WASM_UNREACHABLE("unexpected type");
+    }
+    auto offset = logify(get());
+    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);
+    } else {
+      auto* expected = make(type);
+      auto* replacement = make(type);
+      return builder.makeAtomicCmpxchg(
+        bytes, offset, ptr, expected, replacement, type);
+    }
+  }
+
+  Expression* makeSIMD(Type type) {
+    assert(wasm.features.hasSIMD());
+    if (type.isRef()) {
+      return makeTrivial(type);
+    }
+    if (type != Type::v128) {
+      return makeSIMDExtract(type);
+    }
+    switch (upTo(7)) {
+      case 0:
+        return makeUnary(Type::v128);
+      case 1:
+        return makeBinary(Type::v128);
+      case 2:
+        return makeSIMDReplace();
+      case 3:
+        return makeSIMDShuffle();
+      case 4:
+        return makeSIMDTernary();
+      case 5:
+        return makeSIMDShift();
+      case 6:
+        return makeSIMDLoad();
+    }
+    WASM_UNREACHABLE("invalid value");
+  }
+
+  Expression* makeSIMDExtract(Type type) {
+    auto op = static_cast<SIMDExtractOp>(0);
+    switch (type.getBasic()) {
+      case Type::i32:
+        op = pick(ExtractLaneSVecI8x16,
+                  ExtractLaneUVecI8x16,
+                  ExtractLaneSVecI16x8,
+                  ExtractLaneUVecI16x8,
+                  ExtractLaneVecI32x4);
+        break;
+      case Type::i64:
+        op = ExtractLaneVecI64x2;
+        break;
+      case Type::f32:
+        op = ExtractLaneVecF32x4;
+        break;
+      case Type::f64:
+        op = ExtractLaneVecF64x2;
+        break;
+      case Type::v128:
+      case Type::funcref:
+      case Type::externref:
+      case Type::exnref:
+      case Type::anyref:
+      case Type::eqref:
+      case Type::i31ref:
+      case Type::none:
+      case Type::unreachable:
+        WASM_UNREACHABLE("unexpected type");
+    }
+    Expression* vec = make(Type::v128);
+    uint8_t index = 0;
+    switch (op) {
+      case ExtractLaneSVecI8x16:
+      case ExtractLaneUVecI8x16:
+        index = upTo(16);
+        break;
+      case ExtractLaneSVecI16x8:
+      case ExtractLaneUVecI16x8:
+        index = upTo(8);
+        break;
+      case ExtractLaneVecI32x4:
+      case ExtractLaneVecF32x4:
+        index = upTo(4);
+        break;
+      case ExtractLaneVecI64x2:
+      case ExtractLaneVecF64x2:
+        index = upTo(2);
+        break;
+    }
+    return builder.makeSIMDExtract(op, vec, index);
+  }
+
+  Expression* makeSIMDReplace() {
+    SIMDReplaceOp op = pick(ReplaceLaneVecI8x16,
+                            ReplaceLaneVecI16x8,
+                            ReplaceLaneVecI32x4,
+                            ReplaceLaneVecI64x2,
+                            ReplaceLaneVecF32x4,
+                            ReplaceLaneVecF64x2);
+    Expression* vec = make(Type::v128);
+    uint8_t index;
+    Type lane_t;
+    switch (op) {
+      case ReplaceLaneVecI8x16:
+        index = upTo(16);
+        lane_t = Type::i32;
+        break;
+      case ReplaceLaneVecI16x8:
+        index = upTo(8);
+        lane_t = Type::i32;
+        break;
+      case ReplaceLaneVecI32x4:
+        index = upTo(4);
+        lane_t = Type::i32;
+        break;
+      case ReplaceLaneVecI64x2:
+        index = upTo(2);
+        lane_t = Type::i64;
+        break;
+      case ReplaceLaneVecF32x4:
+        index = upTo(4);
+        lane_t = Type::f32;
+        break;
+      case ReplaceLaneVecF64x2:
+        index = upTo(2);
+        lane_t = Type::f64;
+        break;
+      default:
+        WASM_UNREACHABLE("unexpected op");
+    }
+    Expression* value = make(lane_t);
+    return builder.makeSIMDReplace(op, vec, index, value);
+  }
+
+  Expression* makeSIMDShuffle() {
+    Expression* left = make(Type::v128);
+    Expression* right = make(Type::v128);
+    std::array<uint8_t, 16> mask;
+    for (size_t i = 0; i < 16; ++i) {
+      mask[i] = upTo(32);
+    }
+    return builder.makeSIMDShuffle(left, right, mask);
+  }
+
+  Expression* makeSIMDTernary() {
+    // TODO: Enable qfma/qfms once it is implemented in V8 and the interpreter
+    // SIMDTernaryOp op = pick(Bitselect,
+    //                         QFMAF32x4,
+    //                         QFMSF32x4,
+    //                         QFMAF64x2,
+    //                         QFMSF64x2);
+    SIMDTernaryOp op = Bitselect;
+    Expression* a = make(Type::v128);
+    Expression* b = make(Type::v128);
+    Expression* c = make(Type::v128);
+    return builder.makeSIMDTernary(op, a, b, c);
+  }
+
+  Expression* makeSIMDShift() {
+    SIMDShiftOp op = pick(ShlVecI8x16,
+                          ShrSVecI8x16,
+                          ShrUVecI8x16,
+                          ShlVecI16x8,
+                          ShrSVecI16x8,
+                          ShrUVecI16x8,
+                          ShlVecI32x4,
+                          ShrSVecI32x4,
+                          ShrUVecI32x4,
+                          ShlVecI64x2,
+                          ShrSVecI64x2,
+                          ShrUVecI64x2);
+    Expression* vec = make(Type::v128);
+    Expression* shift = make(Type::i32);
+    return builder.makeSIMDShift(op, vec, shift);
+  }
+
+  Expression* makeSIMDLoad() {
+    // TODO: add Load{32,64}Zero if merged to proposal
+    SIMDLoadOp op = pick(LoadSplatVec8x16,
+                         LoadSplatVec16x8,
+                         LoadSplatVec32x4,
+                         LoadSplatVec64x2,
+                         LoadExtSVec8x8ToVecI16x8,
+                         LoadExtUVec8x8ToVecI16x8,
+                         LoadExtSVec16x4ToVecI32x4,
+                         LoadExtUVec16x4ToVecI32x4,
+                         LoadExtSVec32x2ToVecI64x2,
+                         LoadExtUVec32x2ToVecI64x2);
+    Address offset = logify(get());
+    Address align;
+    switch (op) {
+      case LoadSplatVec8x16:
+        align = 1;
+        break;
+      case LoadSplatVec16x8:
+        align = pick(1, 2);
+        break;
+      case LoadSplatVec32x4:
+        align = pick(1, 2, 4);
+        break;
+      case LoadSplatVec64x2:
+      case LoadExtSVec8x8ToVecI16x8:
+      case LoadExtUVec8x8ToVecI16x8:
+      case LoadExtSVec16x4ToVecI32x4:
+      case LoadExtUVec16x4ToVecI32x4:
+      case LoadExtSVec32x2ToVecI64x2:
+      case LoadExtUVec32x2ToVecI64x2:
+        align = pick(1, 2, 4, 8);
+        break;
+      case Load32Zero:
+      case Load64Zero:
+        WASM_UNREACHABLE("Unexpected SIMD loads");
+    }
+    Expression* ptr = makePointer();
+    return builder.makeSIMDLoad(op, offset, align, ptr);
+  }
+
+  Expression* makeBulkMemory(Type type) {
+    if (!allowMemory) {
+      return makeTrivial(type);
+    }
+    assert(wasm.features.hasBulkMemory());
+    assert(type == Type::none);
+    switch (upTo(4)) {
+      case 0:
+        return makeMemoryInit();
+      case 1:
+        return makeDataDrop();
+      case 2:
+        return makeMemoryCopy();
+      case 3:
+        return makeMemoryFill();
+    }
+    WASM_UNREACHABLE("invalid value");
+  }
+
+  Expression* makeRefIsNull(Type type) {
+    assert(type == Type::i32);
+    assert(wasm.features.hasReferenceTypes());
+    return builder.makeRefIsNull(make(getReferenceType()));
+  }
+
+  Expression* makeRefEq(Type type) {
+    assert(type == Type::i32);
+    assert(wasm.features.hasReferenceTypes() && wasm.features.hasGC());
+    auto* left = make(getEqReferenceType());
+    auto* right = make(getEqReferenceType());
+    return builder.makeRefEq(left, right);
+  }
+
+  Expression* makeI31New(Type type) {
+    assert(type == Type::i31ref);
+    assert(wasm.features.hasReferenceTypes() && wasm.features.hasGC());
+    auto* value = make(Type::i32);
+    return builder.makeI31New(value);
+  }
+
+  Expression* makeI31Get(Type type) {
+    assert(type == Type::i32);
+    assert(wasm.features.hasReferenceTypes() && wasm.features.hasGC());
+    auto* i31 = make(Type::i31ref);
+    return builder.makeI31Get(i31, bool(oneIn(2)));
+  }
+
+  Expression* makeMemoryInit() {
+    if (!allowMemory) {
+      return makeTrivial(Type::none);
+    }
+    uint32_t segment = upTo(wasm.memory.segments.size());
+    size_t totalSize = wasm.memory.segments[segment].data.size();
+    size_t offsetVal = upTo(totalSize);
+    size_t sizeVal = upTo(totalSize - offsetVal);
+    Expression* dest = makePointer();
+    Expression* offset = builder.makeConst(int32_t(offsetVal));
+    Expression* size = builder.makeConst(int32_t(sizeVal));
+    return builder.makeMemoryInit(segment, dest, offset, size);
+  }
+
+  Expression* makeDataDrop() {
+    if (!allowMemory) {
+      return makeTrivial(Type::none);
+    }
+    return builder.makeDataDrop(upTo(wasm.memory.segments.size()));
+  }
+
+  Expression* makeMemoryCopy() {
+    if (!allowMemory) {
+      return makeTrivial(Type::none);
+    }
+    Expression* dest = makePointer();
+    Expression* source = makePointer();
+    Expression* size = make(wasm.memory.indexType);
+    return builder.makeMemoryCopy(dest, source, size);
+  }
+
+  Expression* makeMemoryFill() {
+    if (!allowMemory) {
+      return makeTrivial(Type::none);
+    }
+    Expression* dest = makePointer();
+    Expression* value = make(Type::i32);
+    Expression* size = make(wasm.memory.indexType);
+    return builder.makeMemoryFill(dest, value, size);
+  }
+
+  // special makers
+
+  Expression* makeLogging() {
+    auto type = getLoggableType();
+    return builder.makeCall(
+      std::string("log-") + type.toString(), {make(type)}, Type::none);
+  }
+
+  Expression* makeMemoryHashLogging() {
+    auto* hash = builder.makeCall(std::string("hashMemory"), {}, Type::i32);
+    return builder.makeCall(std::string("log-i32"), {hash}, Type::none);
+  }
+
+  // special getters
+  std::vector<Type> getSingleConcreteTypes() {
+    return items(
+      FeatureOptions<Type>()
+        .add(FeatureSet::MVP, Type::i32, Type::i64, Type::f32, Type::f64)
+        .add(FeatureSet::SIMD, Type::v128)
+        .add(FeatureSet::ReferenceTypes, Type::funcref, Type::externref)
+        .add(FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling,
+             Type::exnref)
+        .add(FeatureSet::ReferenceTypes | FeatureSet::GC,
+             Type::anyref,
+             Type::eqref,
+             Type::i31ref));
+  }
+
+  Type getSingleConcreteType() { return pick(getSingleConcreteTypes()); }
+
+  std::vector<Type> getReferenceTypes() {
+    return items(
+      FeatureOptions<Type>()
+        .add(FeatureSet::ReferenceTypes, Type::funcref, Type::externref)
+        .add(FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling,
+             Type::exnref)
+        .add(FeatureSet::ReferenceTypes | FeatureSet::GC,
+             Type::anyref,
+             Type::eqref,
+             Type::i31ref));
+  }
+
+  Type getReferenceType() { return pick(getReferenceTypes()); }
+
+  std::vector<Type> getEqReferenceTypes() {
+    return items(FeatureOptions<Type>().add(
+      FeatureSet::ReferenceTypes | FeatureSet::GC, Type::eqref, Type::i31ref));
+  }
+
+  Type getEqReferenceType() { return pick(getEqReferenceTypes()); }
+
+  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();
+    }
+    return Type(elements);
+  }
+
+  Type getConcreteType() {
+    if (wasm.features.hasMultivalue() && oneIn(5)) {
+      return getTupleType();
+    } else {
+      return getSingleConcreteType();
+    }
+  }
+
+  Type getControlFlowType() {
+    if (oneIn(10)) {
+      return Type::none;
+    } else {
+      return getConcreteType();
+    }
+  }
+
+  Type getStorableType() {
+    return pick(
+      FeatureOptions<Type>()
+        .add(FeatureSet::MVP, Type::i32, Type::i64, Type::f32, Type::f64)
+        .add(FeatureSet::SIMD, Type::v128));
+  }
+
+  // - funcref cannot be logged because referenced functions can be inlined or
+  // removed during optimization
+  // - there's no point in logging externref or anyref because these are opaque
+  // - don't bother logging tuples
+  std::vector<Type> loggableTypes;
+
+  const std::vector<Type>& getLoggableTypes() {
+    if (loggableTypes.empty()) {
+      loggableTypes = items(
+        FeatureOptions<Type>()
+          .add(FeatureSet::MVP, Type::i32, Type::i64, Type::f32, Type::f64)
+          .add(FeatureSet::SIMD, Type::v128)
+          .add(FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling,
+               Type::exnref));
+    }
+    return loggableTypes;
+  }
+
+  Type getLoggableType() { return pick(getLoggableTypes()); }
+
+  bool isLoggableType(Type type) {
+    const auto& types = getLoggableTypes();
+    return std::find(types.begin(), types.end(), type) != types.end();
+  }
+
+  // statistical distributions
+
+  // 0 to the limit, logarithmic scale
+  Index logify(Index x) {
+    return std::floor(std::log(std::max(Index(1) + x, Index(1))));
+  }
+
+  // one of the integer values in [0, x)
+  // this isn't a perfectly uniform distribution, but it's fast
+  // and reasonable
+  Index upTo(Index x) {
+    if (x == 0) {
+      return 0;
+    }
+    Index raw;
+    if (x <= 255) {
+      raw = get();
+    } else if (x <= 65535) {
+      raw = get16();
+    } else {
+      raw = get32();
+    }
+    auto ret = raw % x;
+    // use extra bits as "noise" for later
+    xorFactor += raw / x;
+    return ret;
+  }
+
+  bool oneIn(Index x) { return upTo(x) == 0; }
+
+  bool onceEvery(Index x) {
+    static int counter = 0;
+    counter++;
+    return counter % x == 0;
+  }
+
+  // apply upTo twice, generating a skewed distribution towards
+  // low values
+  Index upToSquared(Index x) { return upTo(upTo(x)); }
+
+  // pick from a vector-like container
+  template<typename T> const typename T::value_type& pick(const T& vec) {
+    assert(!vec.empty());
+    auto index = upTo(vec.size());
+    return vec[index];
+  }
+
+  // pick from a fixed list
+  template<typename T, typename... Args> T pick(T first, Args... args) {
+    auto num = sizeof...(Args) + 1;
+    auto temp = upTo(num);
+    return pickGivenNum<T>(temp, first, args...);
+  }
+
+  template<typename T> T pickGivenNum(size_t num, T first) {
+    assert(num == 0);
+    return first;
+  }
+
+// Trick to avoid a bug in GCC 7.x.
+// Upstream bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82800
+#define GCC_VERSION                                                            \
+  (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#if GCC_VERSION > 70000 && GCC_VERSION < 70300
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+
+  template<typename T, typename... Args>
+  T pickGivenNum(size_t num, T first, Args... args) {
+    if (num == 0) {
+      return first;
+    }
+    return pickGivenNum<T>(num - 1, args...);
+  }
+
+#if GCC_VERSION > 70000 && GCC_VERSION < 70300
+#pragma GCC diagnostic pop
+#endif
+
+  template<typename T> struct FeatureOptions {
+    template<typename... Ts>
+    FeatureOptions<T>& add(FeatureSet feature, T option, Ts... rest) {
+      options[feature].push_back(option);
+      return add(feature, rest...);
+    }
+
+    struct WeightedOption {
+      T option;
+      size_t weight;
+    };
+
+    template<typename... Ts>
+    FeatureOptions<T>&
+    add(FeatureSet feature, WeightedOption weightedOption, Ts... rest) {
+      for (size_t i = 0; i < weightedOption.weight; i++) {
+        options[feature].push_back(weightedOption.option);
+      }
+      return add(feature, rest...);
+    }
+
+    FeatureOptions<T>& add(FeatureSet feature) { return *this; }
+
+    std::map<FeatureSet, std::vector<T>> options;
+  };
+
+  template<typename T> std::vector<T> items(FeatureOptions<T>& picker) {
+    std::vector<T> matches;
+    for (const auto& item : picker.options) {
+      if (wasm.features.has(item.first)) {
+        matches.reserve(matches.size() + item.second.size());
+        matches.insert(matches.end(), item.second.begin(), item.second.end());
+      }
+    }
+    return matches;
+  }
+
+  template<typename T> const T pick(FeatureOptions<T>& picker) {
+    return pick(items(picker));
+  }
+
+  // utilities
+
+  Name getTargetName(Expression* target) {
+    if (auto* block = target->dynCast<Block>()) {
+      return block->name;
+    } else if (auto* loop = target->dynCast<Loop>()) {
+      return loop->name;
+    }
+    WASM_UNREACHABLE("unexpected expr type");
+  }
+
+  Type getTargetType(Expression* target) {
+    if (auto* block = target->dynCast<Block>()) {
+      return block->type;
+    } else if (target->is<Loop>()) {
+      return Type::none;
+    }
+    WASM_UNREACHABLE("unexpected expr type");
+  }
+};
+
+} // namespace wasm
+
+// XXX Switch class has a condition?! is it real? should the node type be the
+// value type if it exists?!
+
+// TODO copy an existing function and replace just one node in it
diff --git a/binaryen/src/tools/js-wrapper.h b/binaryen/src/tools/js-wrapper.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/js-wrapper.h
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+//
+// Emit a JavaScript wrapper to run a wasm module with some test
+// values, useful for fuzzing.
+//
+
+namespace wasm {
+
+static std::string generateJSWrapper(Module& wasm) {
+  std::string ret;
+  ret += "if (typeof console === 'undefined') {\n"
+         "  console = { log: print };\n"
+         "}\n"
+         "var tempRet0;\n"
+         "var binary;\n"
+         "if (typeof process === 'object' && typeof require === 'function' /* "
+         "node.js detection */) {\n"
+         "  var args = process.argv.slice(2);\n"
+         "  binary = require('fs').readFileSync(args[0]);\n"
+         "  if (!binary.buffer) binary = new Uint8Array(binary);\n"
+         "} else {\n"
+         "  var args;\n"
+         "  if (typeof scriptArgs != 'undefined') {\n"
+         "    args = scriptArgs;\n"
+         "  } else if (typeof arguments != 'undefined') {\n"
+         "    args = arguments;\n"
+         "  }\n"
+         "  if (typeof readbuffer === 'function') {\n"
+         "    binary = new Uint8Array(readbuffer(args[0]));\n"
+         "  } else {\n"
+         "    binary = read(args[0], 'binary');\n"
+         "  }\n"
+         "}\n"
+         "function literal(x, type) {\n"
+         "  var ret = '';\n"
+         "  switch (type) {\n"
+         "    case 'i32': ret += (x | 0); break;\n"
+         "    case 'f32':\n"
+         "    case 'f64': {\n"
+         "      if (x == 0 && (1 / x) < 0) ret += '-';\n"
+         "      ret += Number(x).toString();\n"
+         "      break;\n"
+         "    }\n"
+         "    default: throw 'what?';\n"
+         "  }\n"
+         "  return ret;\n"
+         "}\n"
+         "var instance = new WebAssembly.Instance(new "
+         "WebAssembly.Module(binary), {\n"
+         "  'fuzzing-support': {\n"
+         "    'log-i32': function(x)    { "
+         "console.log('[LoggingExternalInterface logging ' + literal(x, 'i32') "
+         "+ ']') },\n"
+         "    'log-i64': function(x, y) { "
+         "console.log('[LoggingExternalInterface logging ' + literal(x, 'i32') "
+         "+ ' ' + literal(y, 'i32') + ']') },\n" // legalization: two i32s
+         "    'log-f32': function(x)    { "
+         "console.log('[LoggingExternalInterface logging ' + literal(x, 'f64') "
+         "+ ']') },\n" // legalization: an f64
+         "    'log-f64': function(x)    { "
+         "console.log('[LoggingExternalInterface logging ' + literal(x, 'f64') "
+         "+ ']') },\n"
+         "  },\n"
+         "  'env': {\n"
+         "    'setTempRet0': function(x) { tempRet0 = x },\n"
+         "    'getTempRet0': function() { return tempRet0 },\n"
+         "  },\n"
+         "});\n";
+  for (auto& exp : wasm.exports) {
+    if (exp->kind != ExternalKind::Function) {
+      continue; // something exported other than a function
+    }
+    auto* func = wasm.getFunction(exp->value);
+    ret += "if (instance.exports.hangLimitInitializer) "
+           "instance.exports.hangLimitInitializer();\n";
+    ret += "try {\n";
+    ret += std::string("  console.log('[fuzz-exec] calling ") + exp->name.str +
+           "');\n";
+    if (func->sig.results != Type::none) {
+      ret += std::string("  console.log('[fuzz-exec] note result: ") +
+             exp->name.str + " => ' + literal(";
+    } else {
+      ret += "  ";
+    }
+    ret += std::string("instance.exports.") + exp->name.str + "(";
+    bool first = true;
+    for (const auto& param : func->sig.params) {
+      // zeros in arguments TODO more?
+      if (first) {
+        first = false;
+      } else {
+        ret += ", ";
+      }
+      ret += "0";
+      if (param == Type::i64) {
+        ret += ", 0";
+      }
+    }
+    ret += ")";
+    if (func->sig.results != Type::none) {
+      ret += ", '" + func->sig.results.toString() + "'))";
+      // TODO: getTempRet
+    }
+    ret += ";\n";
+    ret += "} catch (e) {\n";
+    ret += "  console.log('exception!' /* + e */);\n";
+    ret += "}\n";
+  }
+  return ret;
+}
+
+} // namespace wasm
diff --git a/binaryen/src/tools/optimization-options.h b/binaryen/src/tools/optimization-options.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/optimization-options.h
@@ -0,0 +1,237 @@
+/*
+ * 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_tools_optimization_options_h
+#define wasm_tools_optimization_options_h
+
+#include "tool-options.h"
+
+//
+// Shared optimization options for commandline tools
+//
+
+namespace wasm {
+
+struct OptimizationOptions : public ToolOptions {
+  static constexpr const char* DEFAULT_OPT_PASSES = "O";
+
+  std::vector<std::string> passes;
+
+  OptimizationOptions(const std::string& command,
+                      const std::string& description)
+    : ToolOptions(command, description) {
+    (*this)
+      .add("",
+           "-O",
+           "execute default optimization passes",
+           Options::Arguments::Zero,
+           [this](Options*, const std::string&) {
+             passOptions.setDefaultOptimizationOptions();
+             passes.push_back(DEFAULT_OPT_PASSES);
+           })
+      .add("",
+           "-O0",
+           "execute no optimization passes",
+           Options::Arguments::Zero,
+           [this](Options*, const std::string&) {
+             passOptions.optimizeLevel = 0;
+             passOptions.shrinkLevel = 0;
+           })
+      .add("",
+           "-O1",
+           "execute -O1 optimization passes (quick&useful opts, useful for "
+           "iteration builds)",
+           Options::Arguments::Zero,
+           [this](Options*, const std::string&) {
+             passOptions.optimizeLevel = 1;
+             passOptions.shrinkLevel = 0;
+             passes.push_back(DEFAULT_OPT_PASSES);
+           })
+      .add(
+        "",
+        "-O2",
+        "execute -O2 optimization passes (most opts, generally gets most perf)",
+        Options::Arguments::Zero,
+        [this](Options*, const std::string&) {
+          passOptions.optimizeLevel = 2;
+          passOptions.shrinkLevel = 0;
+          passes.push_back(DEFAULT_OPT_PASSES);
+        })
+      .add("",
+           "-O3",
+           "execute -O3 optimization passes (spends potentially a lot of time "
+           "optimizing)",
+           Options::Arguments::Zero,
+           [this](Options*, const std::string&) {
+             passOptions.optimizeLevel = 3;
+             passOptions.shrinkLevel = 0;
+             passes.push_back(DEFAULT_OPT_PASSES);
+           })
+      .add("",
+           "-O4",
+           "execute -O4 optimization passes (also flatten the IR, which can "
+           "take a lot more time and memory, but is useful on more nested / "
+           "complex / less-optimized input)",
+           Options::Arguments::Zero,
+           [this](Options*, const std::string&) {
+             passOptions.optimizeLevel = 4;
+             passOptions.shrinkLevel = 0;
+             passes.push_back(DEFAULT_OPT_PASSES);
+           })
+      .add("",
+           "-Os",
+           "execute default optimization passes, focusing on code size",
+           Options::Arguments::Zero,
+           [this](Options*, const std::string&) {
+             passOptions.optimizeLevel = 2;
+             passOptions.shrinkLevel = 1;
+             passes.push_back(DEFAULT_OPT_PASSES);
+           })
+      .add("",
+           "-Oz",
+           "execute default optimization passes, super-focusing on code size",
+           Options::Arguments::Zero,
+           [this](Options*, const std::string&) {
+             passOptions.optimizeLevel = 2;
+             passOptions.shrinkLevel = 2;
+             passes.push_back(DEFAULT_OPT_PASSES);
+           })
+      .add("--optimize-level",
+           "-ol",
+           "How much to focus on optimizing code",
+           Options::Arguments::One,
+           [this](Options* o, const std::string& argument) {
+             passOptions.optimizeLevel = atoi(argument.c_str());
+           })
+      .add("--shrink-level",
+           "-s",
+           "How much to focus on shrinking code size",
+           Options::Arguments::One,
+           [this](Options* o, const std::string& argument) {
+             passOptions.shrinkLevel = atoi(argument.c_str());
+           })
+      .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("--always-inline-max-function-size",
+           "-aimfs",
+           "Max size of functions that are always inlined (default " +
+             std::to_string(InliningOptions().alwaysInlineMaxSize) +
+             ", which "
+             "is safe for use with -Os builds)",
+           Options::Arguments::One,
+           [this](Options* o, const std::string& argument) {
+             passOptions.inlining.alwaysInlineMaxSize =
+               static_cast<Index>(atoi(argument.c_str()));
+           })
+      .add("--flexible-inline-max-function-size",
+           "-fimfs",
+           "Max size of functions that are inlined when lightweight (no loops "
+           "or function calls) when optimizing aggressively for speed (-O3). "
+           "Default: " +
+             std::to_string(InliningOptions().flexibleInlineMaxSize),
+           Options::Arguments::One,
+           [this](Options* o, const std::string& argument) {
+             passOptions.inlining.flexibleInlineMaxSize =
+               static_cast<Index>(atoi(argument.c_str()));
+           })
+      .add("--one-caller-inline-max-function-size",
+           "-ocimfs",
+           "Max size of functions that are inlined when there is only one "
+           "caller (default " +
+             std::to_string(InliningOptions().oneCallerInlineMaxSize) +
+             "). Reason this is not unbounded is that some "
+             "implementations may have a hard time optimizing really large "
+             "functions",
+           Options::Arguments::One,
+           [this](Options* o, const std::string& argument) {
+             passOptions.inlining.oneCallerInlineMaxSize =
+               static_cast<Index>(atoi(argument.c_str()));
+           })
+      .add("--inline-functions-with-loops",
+           "-ifwl",
+           "Allow inlining functions with loops",
+           Options::Arguments::Zero,
+           [this](Options* o, const std::string&) {
+             passOptions.inlining.allowFunctionsWithLoops = true;
+           })
+      .add("--ignore-implicit-traps",
+           "-iit",
+           "Optimize under the helpful assumption that no surprising traps "
+           "occur (from load, div/mod, etc.)",
+           Options::Arguments::Zero,
+           [this](Options*, const std::string&) {
+             passOptions.ignoreImplicitTraps = true;
+           })
+      .add("--low-memory-unused",
+           "-lmu",
+           "Optimize under the helpful assumption that the low 1K of memory is "
+           "not used by the application",
+           Options::Arguments::Zero,
+           [this](Options*, const std::string&) {
+             passOptions.lowMemoryUnused = true;
+           })
+      .add(
+        "--fast-math",
+        "-ffm",
+        "Optimize floats without handling corner cases of NaNs and rounding",
+        Options::Arguments::Zero,
+        [this](Options*, const std::string&) { passOptions.fastMath = true; });
+    // add passes in registry
+    for (const auto& p : PassRegistry::get()->getRegisteredNames()) {
+      (*this).add(
+        std::string("--") + p,
+        "",
+        PassRegistry::get()->getPassDescription(p),
+        Options::Arguments::Zero,
+        [this, p](Options*, const std::string&) { passes.push_back(p); });
+    }
+  }
+
+  bool runningDefaultOptimizationPasses() {
+    for (auto& pass : passes) {
+      if (pass == DEFAULT_OPT_PASSES) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  bool runningPasses() { return passes.size() > 0; }
+
+  void runPasses(Module& wasm) {
+    PassRunner passRunner(&wasm, passOptions);
+    if (debug) {
+      passRunner.setDebug(true);
+    }
+    for (auto& pass : passes) {
+      if (pass == DEFAULT_OPT_PASSES) {
+        passRunner.addDefaultOptimizationPasses();
+      } else {
+        passRunner.add(pass);
+      }
+    }
+    passRunner.run();
+  }
+};
+
+} // namespace wasm
+
+#endif
diff --git a/binaryen/src/tools/spec-wrapper.h b/binaryen/src/tools/spec-wrapper.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/spec-wrapper.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+//
+// Emit a wasm spec interpreter wrapper to run a wasm module with some test
+// values, useful for fuzzing.
+//
+
+namespace wasm {
+
+static std::string generateSpecWrapper(Module& wasm) {
+  std::string ret;
+  for (auto& exp : wasm.exports) {
+    auto* func = wasm.getFunctionOrNull(exp->value);
+    if (!func) {
+      continue; // something exported other than a function
+    }
+    ret += std::string("(invoke \"hangLimitInitializer\") (invoke \"") +
+           exp->name.str + "\" ";
+    for (const auto& param : func->sig.params) {
+      // zeros in arguments TODO more?
+      TODO_SINGLE_COMPOUND(param);
+      switch (param.getBasic()) {
+        case Type::i32:
+          ret += "(i32.const 0)";
+          break;
+        case Type::i64:
+          ret += "(i64.const 0)";
+          break;
+        case Type::f32:
+          ret += "(f32.const 0)";
+          break;
+        case Type::f64:
+          ret += "(f64.const 0)";
+          break;
+        case Type::v128:
+          ret += "(v128.const i32x4 0 0 0 0)";
+          break;
+        case Type::funcref:
+          ret += "(ref.null func)";
+          break;
+        case Type::externref:
+          ret += "(ref.null extern)";
+          break;
+        case Type::exnref:
+          ret += "(ref.null exn)";
+          break;
+        case Type::anyref:
+          ret += "(ref.null any)";
+          break;
+        case Type::eqref:
+          ret += "(ref.null eq)";
+          break;
+        case Type::i31ref:
+          WASM_UNREACHABLE("TODO: i31ref");
+        case Type::none:
+        case Type::unreachable:
+          WASM_UNREACHABLE("unexpected type");
+      }
+      ret += " ";
+    }
+    ret += ") ";
+  }
+  return ret;
+}
+
+} // namespace wasm
diff --git a/binaryen/src/tools/tool-options.h b/binaryen/src/tools/tool-options.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/tool-options.h
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ */
+
+#ifndef wasm_tools_tool_options_h
+#define wasm_tools_tool_options_h
+
+#include "ir/module-utils.h"
+#include "pass.h"
+#include "support/command-line.h"
+
+//
+// Shared options for commandline tools
+//
+
+namespace wasm {
+
+struct ToolOptions : public Options {
+  PassOptions passOptions;
+
+  bool quiet = false;
+  IRProfile profile = IRProfile::Normal;
+
+  ToolOptions(const std::string& command, const std::string& description)
+    : Options(command, description) {
+    (*this)
+      .add("--mvp-features",
+           "-mvp",
+           "Disable all non-MVP features",
+           Arguments::Zero,
+           [this](Options*, const std::string&) {
+             hasFeatureOptions = true;
+             enabledFeatures.makeMVP();
+             disabledFeatures.setAll();
+           })
+      .add("--all-features",
+           "-all",
+           "Enable all features",
+           Arguments::Zero,
+           [this](Options*, const std::string&) {
+             hasFeatureOptions = true;
+             enabledFeatures.setAll();
+             disabledFeatures.makeMVP();
+           })
+      .add("--detect-features",
+           "",
+           "Use features from the target features section, or MVP (default)",
+           Arguments::Zero,
+           [this](Options*, const std::string&) {
+             hasFeatureOptions = true;
+             detectFeatures = true;
+             enabledFeatures.makeMVP();
+             disabledFeatures.makeMVP();
+           })
+      .add("--quiet",
+           "-q",
+           "Emit less verbose output and hide trivial warnings.",
+           Arguments::Zero,
+           [this](Options*, const std::string&) { quiet = true; })
+      .add(
+        "--experimental-poppy",
+        "",
+        "Parse wast files as Poppy IR for testing purposes.",
+        Arguments::Zero,
+        [this](Options*, const std::string&) { profile = IRProfile::Poppy; });
+    (*this)
+      .addFeature(FeatureSet::SignExt, "sign extension operations")
+      .addFeature(FeatureSet::Atomics, "atomic operations")
+      .addFeature(FeatureSet::MutableGlobals, "mutable globals")
+      .addFeature(FeatureSet::TruncSat, "nontrapping float-to-int operations")
+      .addFeature(FeatureSet::SIMD, "SIMD operations and types")
+      .addFeature(FeatureSet::BulkMemory, "bulk memory operations")
+      .addFeature(FeatureSet::ExceptionHandling,
+                  "exception handling operations")
+      .addFeature(FeatureSet::TailCall, "tail call operations")
+      .addFeature(FeatureSet::ReferenceTypes, "reference types")
+      .addFeature(FeatureSet::Multivalue, "multivalue functions")
+      .addFeature(FeatureSet::GC, "garbage collection")
+      .addFeature(FeatureSet::Memory64, "memory64")
+      .add("--no-validation",
+           "-n",
+           "Disables validation, assumes inputs are correct",
+           Options::Arguments::Zero,
+           [this](Options* o, const std::string& argument) {
+             passOptions.validate = false;
+           })
+      .add("--pass-arg",
+           "-pa",
+           "An argument passed along to optimization passes being run. Must be "
+           "in the form KEY@VALUE",
+           Options::Arguments::N,
+           [this](Options*, const std::string& argument) {
+             std::string key, value;
+             auto colon = argument.find('@');
+             if (colon == std::string::npos) {
+               key = argument;
+               value = "1";
+             } else {
+               key = argument.substr(0, colon);
+               value = argument.substr(colon + 1);
+             }
+             passOptions.arguments[key] = value;
+           });
+  }
+
+  ToolOptions& addFeature(FeatureSet::Feature feature,
+                          const std::string& description) {
+    (*this)
+      .add(std::string("--enable-") + FeatureSet::toString(feature),
+           "",
+           std::string("Enable ") + description,
+           Arguments::Zero,
+           [=](Options*, const std::string&) {
+             hasFeatureOptions = true;
+             enabledFeatures.set(feature, true);
+             disabledFeatures.set(feature, false);
+           })
+
+      .add(std::string("--disable-") + FeatureSet::toString(feature),
+           "",
+           std::string("Disable ") + description,
+           Arguments::Zero,
+           [=](Options*, const std::string&) {
+             hasFeatureOptions = true;
+             enabledFeatures.set(feature, false);
+             disabledFeatures.set(feature, true);
+           });
+    return *this;
+  }
+
+  void applyFeatures(Module& module) {
+    if (hasFeatureOptions) {
+      if (!detectFeatures && module.hasFeaturesSection) {
+        FeatureSet optionsFeatures = FeatureSet::MVP;
+        optionsFeatures.enable(enabledFeatures);
+        optionsFeatures.disable(disabledFeatures);
+        if (module.features != optionsFeatures) {
+          Fatal() << "module features do not match specified features. "
+                  << "Use --detect-features to resolve.";
+        }
+      }
+      module.features.enable(enabledFeatures);
+      module.features.disable(disabledFeatures);
+    }
+  }
+
+private:
+  bool hasFeatureOptions = false;
+  bool detectFeatures = false;
+  FeatureSet enabledFeatures = FeatureSet::MVP;
+  FeatureSet disabledFeatures = FeatureSet::MVP;
+};
+
+} // namespace wasm
+
+#endif
diff --git a/binaryen/src/tools/tool-utils.h b/binaryen/src/tools/tool-utils.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/tool-utils.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+//
+// Shared utilities for commandline tools
+//
+
+#include <string>
+
+namespace wasm {
+
+// Removes a specific suffix if it is present, otherwise no-op
+inline std::string removeSpecificSuffix(std::string str, std::string suffix) {
+  if (str.size() <= suffix.size()) {
+    return str;
+  }
+  if (str.substr(str.size() - suffix.size()).compare(suffix) == 0) {
+    return str.substr(0, str.size() - suffix.size());
+  }
+  return str;
+}
+
+} // namespace wasm
diff --git a/binaryen/src/tools/wasm-as.cpp b/binaryen/src/tools/wasm-as.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/wasm-as.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+//
+// wasm2asm console tool
+//
+
+#include "support/colors.h"
+#include "support/file.h"
+#include "wasm-io.h"
+#include "wasm-s-parser.h"
+#include "wasm-validator.h"
+
+#include "tool-options.h"
+#include "tool-utils.h"
+
+using namespace cashew;
+using namespace wasm;
+
+int main(int argc, const char* argv[]) {
+  bool debugInfo = false;
+  std::string symbolMap;
+  std::string sourceMapFilename;
+  std::string sourceMapUrl;
+  ToolOptions options("wasm-as",
+                      "Assemble a .wat (WebAssembly text format) into a .wasm "
+                      "(WebAssembly binary format)");
+  options.extra["validate"] = "wasm";
+  options
+    .add("--output",
+         "-o",
+         "Output file (stdout if not specified)",
+         Options::Arguments::One,
+         [](Options* o, const std::string& argument) {
+           o->extra["output"] = argument;
+           Colors::setEnabled(false);
+         })
+    .add("--validate",
+         "-v",
+         "Control validation of the output module",
+         Options::Arguments::One,
+         [](Options* o, const std::string& argument) {
+           if (argument != "web" && argument != "none" && argument != "wasm") {
+             Fatal() << "Valid arguments for --validate flag are 'wasm', "
+                        "'web', and 'none'.\n";
+           }
+           o->extra["validate"] = argument;
+         })
+    .add("--debuginfo",
+         "-g",
+         "Emit names section and debug info",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& arguments) { debugInfo = true; })
+    .add("--source-map",
+         "-sm",
+         "Emit source map to the specified file",
+         Options::Arguments::One,
+         [&sourceMapFilename](Options* o, const std::string& argument) {
+           sourceMapFilename = argument;
+         })
+    .add("--source-map-url",
+         "-su",
+         "Use specified string as source map URL",
+         Options::Arguments::One,
+         [&sourceMapUrl](Options* o, const std::string& argument) {
+           sourceMapUrl = argument;
+         })
+    .add("--symbolmap",
+         "-s",
+         "Emit a symbol map (indexes => names)",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) { symbolMap = argument; })
+    .add_positional("INFILE",
+                    Options::Arguments::One,
+                    [](Options* o, const std::string& argument) {
+                      o->extra["infile"] = argument;
+                    });
+  options.parse(argc, argv);
+
+  // default output is infile with changed suffix
+  if (options.extra.find("output") == options.extra.end()) {
+    options.extra["output"] =
+      removeSpecificSuffix(options.extra["infile"], ".wat") + ".wasm";
+  }
+
+  auto input(read_file<std::string>(options.extra["infile"], Flags::Text));
+
+  Module wasm;
+
+  try {
+    if (options.debug) {
+      std::cerr << "s-parsing..." << std::endl;
+    }
+    SExpressionParser parser(const_cast<char*>(input.c_str()));
+    Element& root = *parser.root;
+    if (options.debug) {
+      std::cerr << "w-parsing..." << std::endl;
+    }
+    SExpressionWasmBuilder builder(wasm, *root[0], options.profile);
+  } catch (ParseException& p) {
+    p.dump(std::cerr);
+    Fatal() << "error in parsing input";
+  }
+
+  options.applyFeatures(wasm);
+
+  if (options.extra["validate"] != "none") {
+    if (options.debug) {
+      std::cerr << "Validating..." << std::endl;
+    }
+    if (!wasm::WasmValidator().validate(
+          wasm,
+          WasmValidator::Globally |
+            (options.extra["validate"] == "web" ? WasmValidator::Web : 0))) {
+      Fatal() << "Error: input module is not valid.\n";
+    }
+  }
+
+  if (options.debug) {
+    std::cerr << "writing..." << std::endl;
+  }
+  ModuleWriter writer;
+  writer.setBinary(true);
+  writer.setDebugInfo(debugInfo);
+  if (sourceMapFilename.size()) {
+    writer.setSourceMapFilename(sourceMapFilename);
+    writer.setSourceMapUrl(sourceMapUrl);
+  }
+  if (symbolMap.size() > 0) {
+    writer.setSymbolMap(symbolMap);
+  }
+  writer.write(wasm, options.extra["output"]);
+
+  if (options.debug) {
+    std::cerr << "Done." << std::endl;
+  }
+}
diff --git a/binaryen/src/tools/wasm-ctor-eval.cpp b/binaryen/src/tools/wasm-ctor-eval.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/wasm-ctor-eval.cpp
@@ -0,0 +1,502 @@
+/*
+ * 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.
+ */
+
+//
+// Loads wasm plus a list of functions that are global ctors, i.e.,
+// are to be executed. It then executes as many of them as it can,
+// applying their changes to memory as needed, then writes it. In
+// other words, this executes code at compile time to speed up
+// startup later.
+//
+
+#include <memory>
+
+#include "ir/global-utils.h"
+#include "ir/import-utils.h"
+#include "ir/literal-utils.h"
+#include "ir/memory-utils.h"
+#include "ir/module-utils.h"
+#include "pass.h"
+#include "support/colors.h"
+#include "support/file.h"
+#include "tool-options.h"
+#include "wasm-builder.h"
+#include "wasm-interpreter.h"
+#include "wasm-io.h"
+#include "wasm-validator.h"
+
+using namespace wasm;
+
+struct FailToEvalException {
+  std::string why;
+  FailToEvalException(std::string why) : why(why) {}
+};
+
+// We do not have access to imported globals
+class EvallingGlobalManager {
+  // values of globals
+  std::map<Name, Literals> globals;
+
+  // globals that are dangerous to modify in the module
+  std::set<Name> dangerousGlobals;
+
+  // whether we are done adding new globals
+  bool sealed = false;
+
+public:
+  void addDangerous(Name name) { dangerousGlobals.insert(name); }
+
+  void seal() { sealed = true; }
+
+  // for equality purposes, we just care about the globals
+  // and whether they have changed
+  bool operator==(const EvallingGlobalManager& other) {
+    return globals == other.globals;
+  }
+  bool operator!=(const EvallingGlobalManager& other) {
+    return !(*this == other);
+  }
+
+  Literals& operator[](Name name) {
+    if (dangerousGlobals.count(name) > 0) {
+      std::string extra;
+      if (name == "___dso_handle") {
+        extra = "\nrecommendation: build with -s NO_EXIT_RUNTIME=1 so that "
+                "calls to atexit that use ___dso_handle are not emitted";
+      }
+      throw FailToEvalException(
+        std::string(
+          "tried to access a dangerous (import-initialized) global: ") +
+        name.str + extra);
+    }
+    return globals[name];
+  }
+
+  struct Iterator {
+    Name first;
+    Literals second;
+    bool found;
+
+    Iterator() : found(false) {}
+    Iterator(Name name, Literals value)
+      : first(name), second(value), found(true) {}
+
+    bool operator==(const Iterator& other) {
+      return first == other.first && second == other.second &&
+             found == other.found;
+    }
+    bool operator!=(const Iterator& other) { return !(*this == other); }
+  };
+
+  Iterator find(Name name) {
+    if (globals.find(name) == globals.end()) {
+      return end();
+    }
+    return Iterator(name, globals[name]);
+  }
+
+  Iterator end() { return Iterator(); }
+};
+
+// Use a ridiculously large stack size.
+static Index STACK_SIZE = 32 * 1024 * 1024;
+
+// Start the stack at a ridiculously large location, and do so in
+// a way that works regardless if the stack goes up or down.
+static Index STACK_START = 1024 * 1024 * 1024 + STACK_SIZE;
+
+// Bound the stack location in both directions, so we have bounds
+// that do not depend on the direction it grows.
+static Index STACK_LOWER_LIMIT = STACK_START - STACK_SIZE;
+static Index STACK_UPPER_LIMIT = STACK_START + STACK_SIZE;
+
+class EvallingModuleInstance
+  : public ModuleInstanceBase<EvallingGlobalManager, EvallingModuleInstance> {
+public:
+  EvallingModuleInstance(Module& wasm, ExternalInterface* externalInterface)
+    : ModuleInstanceBase(wasm, externalInterface) {
+    // if any global in the module has a non-const constructor, it is using a
+    // global import, which we don't have, and is illegal to use
+    ModuleUtils::iterDefinedGlobals(wasm, [&](Global* global) {
+      if (!global->init->is<Const>()) {
+        // some constants are ok to use
+        if (auto* get = global->init->dynCast<GlobalGet>()) {
+          auto name = get->name;
+          auto* import = wasm.getGlobal(name);
+          if (import->module == Name(ENV) &&
+              (import->base ==
+                 STACKTOP || // stack constants are special, we handle them
+               import->base == STACK_MAX)) {
+            return; // this is fine
+          }
+        }
+        // this global is dangerously initialized by an import, so if it is
+        // used, we must fail
+        globals.addDangerous(global->name);
+      }
+    });
+  }
+
+  std::vector<char> stack;
+
+  // create C stack space for us to use. We do *NOT* care about their contents,
+  // assuming the stack top was unwound. the memory may have been modified,
+  // but it should not be read afterwards, doing so would be undefined behavior
+  void setupEnvironment() {
+    // prepare scratch memory
+    stack.resize(2 * STACK_SIZE);
+    // tell the module to accept writes up to the stack end
+    auto total = STACK_START + STACK_SIZE;
+    memorySize = total / Memory::kPageSize;
+  }
+};
+
+struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface {
+  Module* wasm;
+  EvallingModuleInstance* instance;
+
+  void init(Module& wasm_, EvallingModuleInstance& instance_) override {
+    wasm = &wasm_;
+    instance = &instance_;
+  }
+
+  void importGlobals(EvallingGlobalManager& globals, Module& wasm_) override {
+    // fill usable values for stack imports, and globals initialized to them
+    ImportInfo imports(wasm_);
+    if (auto* stackTop = imports.getImportedGlobal(ENV, STACKTOP)) {
+      globals[stackTop->name] = {Literal(int32_t(STACK_START))};
+      if (auto* stackTop =
+            GlobalUtils::getGlobalInitializedToImport(wasm_, ENV, STACKTOP)) {
+        globals[stackTop->name] = {Literal(int32_t(STACK_START))};
+      }
+    }
+    if (auto* stackMax = imports.getImportedGlobal(ENV, STACK_MAX)) {
+      globals[stackMax->name] = {Literal(int32_t(STACK_START))};
+      if (auto* stackMax =
+            GlobalUtils::getGlobalInitializedToImport(wasm_, ENV, STACK_MAX)) {
+        globals[stackMax->name] = {Literal(int32_t(STACK_START))};
+      }
+    }
+    // fill in fake values for everything else, which is dangerous to use
+    ModuleUtils::iterDefinedGlobals(wasm_, [&](Global* defined) {
+      if (globals.find(defined->name) == globals.end()) {
+        globals[defined->name] = Literal::makeZeros(defined->type);
+      }
+    });
+    ModuleUtils::iterImportedGlobals(wasm_, [&](Global* import) {
+      if (globals.find(import->name) == globals.end()) {
+        globals[import->name] = Literal::makeZeros(import->type);
+      }
+    });
+  }
+
+  Literals callImport(Function* import, LiteralList& arguments) override {
+    std::string extra;
+    if (import->module == ENV && import->base == "___cxa_atexit") {
+      extra = "\nrecommendation: build with -s NO_EXIT_RUNTIME=1 so that calls "
+              "to atexit are not emitted";
+    }
+    throw FailToEvalException(std::string("call import: ") +
+                              import->module.str + "." + import->base.str +
+                              extra);
+  }
+
+  Literals callTable(Index index,
+                     Signature sig,
+                     LiteralList& arguments,
+                     Type result,
+                     EvallingModuleInstance& instance) override {
+    // we assume the table is not modified (hmm)
+    // look through the segments, try to find the function
+    for (auto& segment : wasm->table.segments) {
+      Index start;
+      // look for the index in this segment. if it has a constant offset, we
+      // look in the proper range. if it instead gets a global, we rely on the
+      // fact that when not dynamically linking then the table is loaded at
+      // offset 0.
+      if (auto* c = segment.offset->dynCast<Const>()) {
+        start = c->value.getInteger();
+      } else if (segment.offset->is<GlobalGet>()) {
+        start = 0;
+      } else {
+        // wasm spec only allows const and global.get there
+        WASM_UNREACHABLE("invalid expr type");
+      }
+      auto end = start + segment.data.size();
+      if (start <= index && index < end) {
+        auto name = segment.data[index - start];
+        // if this is one of our functions, we can call it; if it was imported,
+        // fail
+        auto* func = wasm->getFunction(name);
+        if (func->sig != sig) {
+          throw FailToEvalException(
+            std::string("callTable signature mismatch: ") + name.str);
+        }
+        if (!func->imported()) {
+          return instance.callFunctionInternal(name, arguments);
+        } else {
+          throw FailToEvalException(
+            std::string("callTable on imported function: ") + name.str);
+        }
+      }
+    }
+    throw FailToEvalException(
+      std::string("callTable on index not found in static segments: ") +
+      std::to_string(index));
+  }
+
+  int8_t load8s(Address addr) override { return doLoad<int8_t>(addr); }
+  uint8_t load8u(Address addr) override { return doLoad<uint8_t>(addr); }
+  int16_t load16s(Address addr) override { return doLoad<int16_t>(addr); }
+  uint16_t load16u(Address addr) override { return doLoad<uint16_t>(addr); }
+  int32_t load32s(Address addr) override { return doLoad<int32_t>(addr); }
+  uint32_t load32u(Address addr) override { return doLoad<uint32_t>(addr); }
+  int64_t load64s(Address addr) override { return doLoad<int64_t>(addr); }
+  uint64_t load64u(Address addr) override { return doLoad<uint64_t>(addr); }
+
+  void store8(Address addr, int8_t value) override {
+    doStore<int8_t>(addr, value);
+  }
+  void store16(Address addr, int16_t value) override {
+    doStore<int16_t>(addr, value);
+  }
+  void store32(Address addr, int32_t value) override {
+    doStore<int32_t>(addr, value);
+  }
+  void store64(Address addr, int64_t value) override {
+    doStore<int64_t>(addr, value);
+  }
+
+  // called during initialization, but we don't keep track of a table
+  void tableStore(Address addr, Name value) override {}
+
+  bool growMemory(Address /*oldSize*/, Address newSize) override {
+    throw FailToEvalException("grow memory");
+  }
+
+  void trap(const char* why) override {
+    throw FailToEvalException(std::string("trap: ") + why);
+  }
+
+  void throwException(Literal exn) override {
+    std::stringstream ss;
+    ss << "exception thrown: " << exn;
+    throw FailToEvalException(ss.str());
+  }
+
+private:
+  // TODO: handle unaligned too, see shell-interface
+
+  template<typename T> T* getMemory(Address address) {
+    // if memory is on the stack, use the stack
+    if (address >= STACK_LOWER_LIMIT) {
+      if (address >= STACK_UPPER_LIMIT) {
+        throw FailToEvalException("stack usage too high");
+      }
+      Address relative = address - STACK_LOWER_LIMIT;
+      // in range, all is good, use the stack
+      return (T*)(&instance->stack[relative]);
+    }
+
+    // otherwise, this must be in the singleton segment. resize as needed
+    if (wasm->memory.segments.size() == 0) {
+      std::vector<char> temp;
+      Builder builder(*wasm);
+      wasm->memory.segments.push_back(
+        Memory::Segment(builder.makeConst(int32_t(0)), temp));
+    }
+    // memory should already have been flattened
+    assert(wasm->memory.segments[0].offset->cast<Const>()->value.getInteger() ==
+           0);
+    auto max = address + sizeof(T);
+    auto& data = wasm->memory.segments[0].data;
+    if (max > data.size()) {
+      data.resize(max);
+    }
+    return (T*)(&data[address]);
+  }
+
+  template<typename T> void doStore(Address address, T value) {
+    // do a memcpy to avoid undefined behavior if unaligned
+    memcpy(getMemory<T>(address), &value, sizeof(T));
+  }
+
+  template<typename T> T doLoad(Address address) {
+    // do a memcpy to avoid undefined behavior if unaligned
+    T ret;
+    memcpy(&ret, getMemory<T>(address), sizeof(T));
+    return ret;
+  }
+};
+
+void evalCtors(Module& wasm, std::vector<std::string> ctors) {
+  CtorEvalExternalInterface interface;
+  try {
+    // flatten memory, so we do not depend on the layout of data segments
+    if (!MemoryUtils::flatten(wasm.memory)) {
+      Fatal() << "  ...stopping since could not flatten memory\n";
+    }
+    // create an instance for evalling
+    EvallingModuleInstance instance(wasm, &interface);
+    // set up the stack area and other environment details
+    instance.setupEnvironment();
+    // we should not add new globals from here on; as a result, using
+    // an imported global will fail, as it is missing and so looks new
+    instance.globals.seal();
+    // go one by one, in order, until we fail
+    // TODO: if we knew priorities, we could reorder?
+    for (auto& ctor : ctors) {
+      std::cerr << "trying to eval " << ctor << '\n';
+      // snapshot memory, as either the entire function is done, or none
+      auto memoryBefore = wasm.memory;
+      // snapshot globals (note that STACKTOP might be modified, but should
+      // be returned, so that works out)
+      auto globalsBefore = instance.globals;
+      Export* ex = wasm.getExportOrNull(ctor);
+      if (!ex) {
+        Fatal() << "export not found: " << ctor;
+      }
+      try {
+        instance.callFunction(ex->value, LiteralList());
+      } catch (FailToEvalException& fail) {
+        // that's it, we failed, so stop here, cleaning up partial
+        // memory changes first
+        std::cerr << "  ...stopping since could not eval: " << fail.why << "\n";
+        wasm.memory = memoryBefore;
+        return;
+      }
+      if (instance.globals != globalsBefore) {
+        std::cerr << "  ...stopping since globals modified\n";
+        wasm.memory = memoryBefore;
+        return;
+      }
+      std::cerr << "  ...success on " << ctor << ".\n";
+      // success, the entire function was evalled!
+      // we can nop the function (which may be used elsewhere)
+      // and remove the export
+      auto* exp = wasm.getExport(ctor);
+      auto* func = wasm.getFunction(exp->value);
+      func->body = wasm.allocator.alloc<Nop>();
+      wasm.removeExport(exp->name);
+    }
+  } catch (FailToEvalException& fail) {
+    // that's it, we failed to even create the instance
+    std::cerr << "  ...stopping since could not create module instance: "
+              << fail.why << "\n";
+    return;
+  }
+}
+
+//
+// main
+//
+
+int main(int argc, const char* argv[]) {
+  Name entry;
+  std::vector<std::string> passes;
+  bool emitBinary = true;
+  bool debugInfo = false;
+  std::string ctorsString;
+
+  ToolOptions options("wasm-ctor-eval",
+                      "Execute C++ global constructors ahead of time");
+  options
+    .add("--output",
+         "-o",
+         "Output file (stdout if not specified)",
+         Options::Arguments::One,
+         [](Options* o, const std::string& argument) {
+           o->extra["output"] = argument;
+           Colors::setEnabled(false);
+         })
+    .add("--emit-text",
+         "-S",
+         "Emit text instead of binary for the output file",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& argument) { emitBinary = false; })
+    .add("--debuginfo",
+         "-g",
+         "Emit names section and debug info",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& arguments) { debugInfo = true; })
+    .add(
+      "--ctors",
+      "-c",
+      "Comma-separated list of global constructor functions to evaluate",
+      Options::Arguments::One,
+      [&](Options* o, const std::string& argument) { ctorsString = argument; })
+    .add_positional("INFILE",
+                    Options::Arguments::One,
+                    [](Options* o, const std::string& argument) {
+                      o->extra["infile"] = argument;
+                    });
+  options.parse(argc, argv);
+
+  auto input(read_file<std::string>(options.extra["infile"], Flags::Text));
+
+  Module wasm;
+
+  {
+    if (options.debug) {
+      std::cerr << "reading...\n";
+    }
+    ModuleReader reader;
+    try {
+      reader.read(options.extra["infile"], wasm);
+    } catch (ParseException& p) {
+      p.dump(std::cerr);
+      Fatal() << "error in parsing input";
+    }
+  }
+
+  options.applyFeatures(wasm);
+
+  if (!WasmValidator().validate(wasm)) {
+    WasmPrinter::printModule(&wasm);
+    Fatal() << "error in validating input";
+  }
+
+  // get list of ctors, and eval them
+  std::vector<std::string> ctors;
+  std::istringstream stream(ctorsString);
+  std::string temp;
+  while (std::getline(stream, temp, ',')) {
+    ctors.push_back(temp);
+  }
+  evalCtors(wasm, ctors);
+
+  // Do some useful optimizations after the evalling
+  {
+    PassRunner passRunner(&wasm);
+    passRunner.add("memory-packing"); // we flattened it, so re-optimize
+    passRunner.add("remove-unused-names");
+    passRunner.add("dce");
+    passRunner.add("merge-blocks");
+    passRunner.add("vacuum");
+    passRunner.add("remove-unused-module-elements");
+    passRunner.run();
+  }
+
+  if (options.extra.count("output") > 0) {
+    if (options.debug) {
+      std::cerr << "writing..." << std::endl;
+    }
+    ModuleWriter writer;
+    writer.setBinary(emitBinary);
+    writer.setDebugInfo(debugInfo);
+    writer.write(wasm, options.extra["output"]);
+  }
+}
diff --git a/binaryen/src/tools/wasm-dis.cpp b/binaryen/src/tools/wasm-dis.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/wasm-dis.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+//
+// wasm2asm console tool
+//
+
+#include "support/colors.h"
+#include "support/command-line.h"
+#include "support/file.h"
+#include "wasm-io.h"
+#include "wasm-printing.h"
+
+using namespace cashew;
+using namespace wasm;
+
+int main(int argc, const char* argv[]) {
+  std::string sourceMapFilename;
+  Options options("wasm-dis",
+                  "Un-assemble a .wasm (WebAssembly binary format) into a "
+                  ".wat (WebAssembly text format)");
+  options
+    .add("--output",
+         "-o",
+         "Output file (stdout if not specified)",
+         Options::Arguments::One,
+         [](Options* o, const std::string& argument) {
+           o->extra["output"] = argument;
+           Colors::setEnabled(false);
+         })
+    .add(
+      "--source-map",
+      "-sm",
+      "Consume source map from the specified file to add location information",
+      Options::Arguments::One,
+      [&sourceMapFilename](Options* o, const std::string& argument) {
+        sourceMapFilename = argument;
+      })
+    .add_positional("INFILE",
+                    Options::Arguments::One,
+                    [](Options* o, const std::string& argument) {
+                      o->extra["infile"] = argument;
+                    });
+  options.parse(argc, argv);
+
+  if (options.debug) {
+    std::cerr << "parsing binary..." << std::endl;
+  }
+  Module wasm;
+  try {
+    ModuleReader().readBinary(options.extra["infile"], wasm, sourceMapFilename);
+  } catch (ParseException& p) {
+    p.dump(std::cerr);
+    std::cerr << '\n';
+    Fatal() << "error in parsing wasm binary";
+  } catch (MapParseException& p) {
+    p.dump(std::cerr);
+    std::cerr << '\n';
+    Fatal() << "error in parsing wasm source mapping";
+  }
+
+  if (options.debug) {
+    std::cerr << "Printing..." << std::endl;
+  }
+  Output output(options.extra["output"], Flags::Text);
+  WasmPrinter::printModule(&wasm, output.getStream());
+  output << '\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
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/wasm-emscripten-finalize.cpp
@@ -0,0 +1,398 @@
+/*
+ * 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.
+ */
+
+//
+// wasm-emscripten-finalize console tool
+// Performs Emscripten-specific transforms on .wasm files
+//
+
+#include <exception>
+
+#include "abi/js.h"
+#include "ir/trapping.h"
+#include "support/colors.h"
+#include "support/debug.h"
+#include "support/file.h"
+#include "tool-options.h"
+#include "wasm-binary.h"
+#include "wasm-emscripten.h"
+#include "wasm-io.h"
+#include "wasm-printing.h"
+#include "wasm-validator.h"
+
+#define DEBUG_TYPE "emscripten"
+
+using namespace cashew;
+using namespace wasm;
+
+int main(int argc, const char* argv[]) {
+  const uint64_t INVALID_BASE = -1;
+
+  std::string infile;
+  std::string outfile;
+  std::string inputSourceMapFilename;
+  std::string outputSourceMapFilename;
+  std::string outputSourceMapUrl;
+  std::string dataSegmentFile;
+  bool emitBinary = true;
+  bool debugInfo = false;
+  bool DWARF = false;
+  bool sideModule = false;
+  bool legacyPIC = true;
+  bool legalizeJavaScriptFFI = true;
+  bool bigInt = false;
+  bool checkStackOverflow = false;
+  uint64_t globalBase = INVALID_BASE;
+  bool standaloneWasm = false;
+  // TODO: remove after https://github.com/WebAssembly/binaryen/issues/3043
+  bool minimizeWasmChanges = false;
+  bool noDynCalls = false;
+  bool onlyI64DynCalls = false;
+
+  ToolOptions options("wasm-emscripten-finalize",
+                      "Performs Emscripten-specific transforms on .wasm files");
+  options
+    .add("--output",
+         "-o",
+         "Output file",
+         Options::Arguments::One,
+         [&outfile](Options*, const std::string& argument) {
+           outfile = argument;
+           Colors::setEnabled(false);
+         })
+    .add("--debuginfo",
+         "-g",
+         "Emit names section in wasm binary (or full debuginfo in wast)",
+         Options::Arguments::Zero,
+         [&debugInfo](Options*, const std::string&) { debugInfo = true; })
+    .add("--dwarf",
+         "",
+         "Update DWARF debug info",
+         Options::Arguments::Zero,
+         [&DWARF](Options*, const std::string&) { DWARF = true; })
+    .add("--emit-text",
+         "-S",
+         "Emit text instead of binary for the output file. "
+         "In this mode if no output file is specified, we write to stdout.",
+         Options::Arguments::Zero,
+         [&emitBinary](Options*, const std::string&) { emitBinary = false; })
+    .add("--global-base",
+         "",
+         "The address at which static globals were placed",
+         Options::Arguments::One,
+         [&globalBase](Options*, const std::string& argument) {
+           globalBase = std::stoull(argument);
+         })
+    // TODO(sbc): Remove this one this argument is no longer passed by
+    // emscripten. See https://github.com/emscripten-core/emscripten/issues/8905
+    .add("--initial-stack-pointer",
+         "",
+         "ignored - will be removed in a future release",
+         Options::Arguments::One,
+         [](Options*, const std::string& argument) {})
+    .add("--side-module",
+         "",
+         "Input is an emscripten side module",
+         Options::Arguments::Zero,
+         [&sideModule](Options* o, const std::string& argument) {
+           sideModule = true;
+         })
+    .add("--new-pic-abi",
+         "",
+         "Use new/llvm PIC abi",
+         Options::Arguments::Zero,
+         [&legacyPIC](Options* o, const std::string& argument) {
+           legacyPIC = false;
+         })
+    .add("--input-source-map",
+         "-ism",
+         "Consume source map from the specified file",
+         Options::Arguments::One,
+         [&inputSourceMapFilename](Options* o, const std::string& argument) {
+           inputSourceMapFilename = argument;
+         })
+    .add("--no-legalize-javascript-ffi",
+         "-nj",
+         "Do not fully legalize (i64->i32, "
+         "f32->f64) the imports and exports for interfacing with JS",
+         Options::Arguments::Zero,
+         [&legalizeJavaScriptFFI](Options* o, const std::string&) {
+           legalizeJavaScriptFFI = false;
+         })
+    .add("--bigint",
+         "-bi",
+         "Assume JS will use wasm/JS BigInt integration, so wasm i64s will "
+         "turn into JS BigInts, and there is no need for any legalization at "
+         "all (not even minimal legalization of dynCalls)",
+         Options::Arguments::Zero,
+         [&bigInt](Options* o, const std::string&) { bigInt = true; })
+    .add("--output-source-map",
+         "-osm",
+         "Emit source map to the specified file",
+         Options::Arguments::One,
+         [&outputSourceMapFilename](Options* o, const std::string& argument) {
+           outputSourceMapFilename = argument;
+         })
+    .add("--output-source-map-url",
+         "-osu",
+         "Emit specified string as source map URL",
+         Options::Arguments::One,
+         [&outputSourceMapUrl](Options* o, const std::string& argument) {
+           outputSourceMapUrl = argument;
+         })
+    .add("--separate-data-segments",
+         "",
+         "Separate data segments to a file",
+         Options::Arguments::One,
+         [&dataSegmentFile](Options* o, const std::string& argument) {
+           dataSegmentFile = argument;
+         })
+    .add("--check-stack-overflow",
+         "",
+         "Check for stack overflows every time the stack is extended",
+         Options::Arguments::Zero,
+         [&checkStackOverflow](Options* o, const std::string&) {
+           checkStackOverflow = true;
+         })
+    .add("--standalone-wasm",
+         "",
+         "Emit a wasm file that does not depend on JS, as much as possible,"
+         " using wasi and other standard conventions etc. where possible",
+         Options::Arguments::Zero,
+         [&standaloneWasm](Options* o, const std::string&) {
+           standaloneWasm = true;
+         })
+    .add("--minimize-wasm-changes",
+         "",
+         "Modify the wasm as little as possible. This is useful during "
+         "development as we reduce the number of changes to the wasm, as it "
+         "lets emscripten control how much modifications to do.",
+         Options::Arguments::Zero,
+         [&minimizeWasmChanges](Options* o, const std::string&) {
+           minimizeWasmChanges = true;
+         })
+    .add("--no-dyncalls",
+         "",
+         "",
+         Options::Arguments::Zero,
+         [&noDynCalls](Options* o, const std::string&) { noDynCalls = true; })
+    .add("--dyncalls-i64",
+         "",
+         "",
+         Options::Arguments::Zero,
+         [&onlyI64DynCalls](Options* o, const std::string&) {
+           onlyI64DynCalls = true;
+         })
+    .add_positional("INFILE",
+                    Options::Arguments::One,
+                    [&infile](Options* o, const std::string& argument) {
+                      infile = argument;
+                    });
+  options.parse(argc, argv);
+
+  if (infile == "") {
+    Fatal() << "Need to specify an infile\n";
+  }
+
+  Module wasm;
+  ModuleReader reader;
+  reader.setDWARF(DWARF);
+  try {
+    reader.read(infile, wasm, inputSourceMapFilename);
+  } catch (ParseException& p) {
+    p.dump(std::cerr);
+    std::cerr << '\n';
+    Fatal() << "error in parsing input";
+  } catch (MapParseException& p) {
+    p.dump(std::cerr);
+    std::cerr << '\n';
+    Fatal() << "error in parsing wasm source map";
+  }
+
+  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;
+  }
+
+  EmscriptenGlueGenerator generator(wasm);
+  generator.standalone = standaloneWasm;
+  generator.sideModule = sideModule;
+  generator.minimizeWasmChanges = minimizeWasmChanges;
+  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();
+
+  if (!standaloneWasm) {
+    // This is also not needed in standalone mode since standalone mode uses
+    // crt1.c to invoke the main and is aware of __main_argc_argv mangling.
+    generator.renameMainArgcArgv();
+  }
+
+  PassRunner passRunner(&wasm, options.passOptions);
+  passRunner.setDebug(options.debug);
+  passRunner.setDebugInfo(debugInfo);
+
+  if (checkStackOverflow && !sideModule) {
+    if (!standaloneWasm) {
+      // In standalone mode we don't set a handler at all.. which means
+      // just trap on overflow.
+      passRunner.options.arguments["stack-check-handler"] =
+        "__handle_stack_overflow";
+    }
+    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) {
+      passRunner.add("generate-i64-dyncalls");
+    } else {
+      passRunner.add("generate-dyncalls");
+    }
+  }
+
+  // Legalize the wasm, if BigInts don't make that moot.
+  if (!bigInt) {
+    passRunner.add(ABI::getLegalizationPass(
+      legalizeJavaScriptFFI ? ABI::LegalizationLevel::Full
+                            : ABI::LegalizationLevel::Minimal));
+  }
+
+  // Strip target features section (its information is in the metadata)
+  passRunner.add("strip-target-features");
+
+  // If DWARF is unused, strip it out. This avoids us keeping it alive
+  // until wasm-opt strips it later.
+  if (!DWARF) {
+    passRunner.add("strip-dwarf");
+  }
+
+  passRunner.run();
+
+  if (sideModule) {
+    BYN_TRACE("finalizing as side module\n");
+    generator.generatePostInstantiateFunction();
+  } 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);
+      }
+    }
+  }
+
+  BYN_TRACE("generated metadata\n");
+  // Substantial changes to the wasm are done, enough to create the metadata.
+  std::string metadata =
+    generator.generateEmscriptenMetadata(dataSize, initializerFunctions);
+
+  // Finally, separate out data segments if relevant (they may have been needed
+  // for metadata).
+  if (!dataSegmentFile.empty()) {
+    Output memInitFile(dataSegmentFile, Flags::Binary);
+    if (globalBase == INVALID_BASE) {
+      Fatal() << "globalBase must be set";
+    }
+    generator.separateDataSegments(&memInitFile, globalBase);
+  }
+
+  BYN_TRACE_WITH_TYPE("emscripten-dump", "Module after:\n");
+  BYN_DEBUG_WITH_TYPE("emscripten-dump",
+                      WasmPrinter::printModule(&wasm, std::cerr));
+
+  // 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).
+  if (outfile.size() > 0 || !emitBinary) {
+    Output output(outfile, emitBinary ? Flags::Binary : Flags::Text);
+    ModuleWriter writer;
+    writer.setDebugInfo(debugInfo);
+    // writer.setSymbolMap(symbolMap);
+    writer.setBinary(emitBinary);
+    if (outputSourceMapFilename.size()) {
+      writer.setSourceMapFilename(outputSourceMapFilename);
+      writer.setSourceMapUrl(outputSourceMapUrl);
+    }
+    writer.write(wasm, output);
+    if (!emitBinary) {
+      output << "(;\n";
+      output << "--BEGIN METADATA --\n" << metadata << "-- END METADATA --\n";
+      output << ";)\n";
+    }
+  }
+  // If we emit text then we emitted the metadata together with that text
+  // earlier. Otherwise emit it to stdout.
+  if (emitBinary) {
+    std::cout << metadata;
+  }
+  return 0;
+}
diff --git a/binaryen/src/tools/wasm-metadce.cpp b/binaryen/src/tools/wasm-metadce.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/wasm-metadce.cpp
@@ -0,0 +1,622 @@
+/*
+ * 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.
+ */
+
+//
+// Performs DCE on a graph containing a wasm module. The caller provides
+// the graph, this tool fills in the wasm module's parts. It can then
+// remove exports that are unused, for example, which is impossible
+// otherwise (since we wouldn't know if the outside needs them).
+//
+// TODO: Currently all functions in the table are considered roots,
+//       as the outside may call them. In the future we probably want
+//       to refine that.
+
+#include <memory>
+
+#include "ir/module-utils.h"
+#include "pass.h"
+#include "support/colors.h"
+#include "support/file.h"
+#include "support/json.h"
+#include "tool-options.h"
+#include "wasm-builder.h"
+#include "wasm-io.h"
+#include "wasm-validator.h"
+
+using namespace wasm;
+
+// Generic reachability graph of abstract nodes
+
+struct DCENode {
+  Name name;
+  std::vector<Name> reaches; // the other nodes this one can reach
+  DCENode() = default;
+  DCENode(Name name) : name(name) {}
+};
+
+// A meta DCE graph with wasm integration
+struct MetaDCEGraph {
+  std::unordered_map<Name, DCENode> nodes;
+  std::unordered_set<Name> roots;
+
+  // export exported name => DCE name
+  std::unordered_map<Name, Name> exportToDCENode;
+  std::unordered_map<Name, Name> functionToDCENode; // function name => DCE name
+  std::unordered_map<Name, Name> globalToDCENode;   // global name => DCE name
+  std::unordered_map<Name, Name> eventToDCENode;    // event name => DCE name
+
+  std::unordered_map<Name, Name> DCENodeToExport; // reverse maps
+  std::unordered_map<Name, Name> DCENodeToFunction;
+  std::unordered_map<Name, Name> DCENodeToGlobal;
+  std::unordered_map<Name, Name> DCENodeToEvent;
+
+  // imports are not mapped 1:1 to DCE nodes in the wasm, since env.X might
+  // be imported twice, for example. So we don't map a DCE node to an Import,
+  // but rather the module.base pair ("id") for the import.
+  // TODO: implement this in a safer way, not a string with a magic separator
+  typedef Name ImportId;
+
+  ImportId getImportId(Name module, Name base) {
+    return std::string(module.str) + " (*) " + std::string(base.str);
+  }
+
+  ImportId getFunctionImportId(Name name) {
+    auto* imp = wasm.getFunction(name);
+    return getImportId(imp->module, imp->base);
+  }
+
+  ImportId getGlobalImportId(Name name) {
+    auto* imp = wasm.getGlobal(name);
+    return getImportId(imp->module, imp->base);
+  }
+
+  ImportId getEventImportId(Name name) {
+    auto* imp = wasm.getEvent(name);
+    return getImportId(imp->module, imp->base);
+  }
+
+  // import module.base => DCE name
+  std::unordered_map<Name, Name> importIdToDCENode;
+
+  Module& wasm;
+
+  MetaDCEGraph(Module& wasm) : wasm(wasm) {}
+
+  // populate the graph with info from the wasm, integrating with
+  // potentially-existing nodes for imports and exports that the graph may
+  // already contain.
+  void scanWebAssembly() {
+    // Add an entry for everything we might need ahead of time, so parallel work
+    // does not alter parent state, just adds to things pointed by it,
+    // independently (each thread will add for one function, etc.)
+    ModuleUtils::iterDefinedFunctions(wasm, [&](Function* func) {
+      auto dceName = getName("func", func->name.str);
+      DCENodeToFunction[dceName] = func->name;
+      functionToDCENode[func->name] = dceName;
+      nodes[dceName] = DCENode(dceName);
+    });
+    ModuleUtils::iterDefinedGlobals(wasm, [&](Global* global) {
+      auto dceName = getName("global", global->name.str);
+      DCENodeToGlobal[dceName] = global->name;
+      globalToDCENode[global->name] = dceName;
+      nodes[dceName] = DCENode(dceName);
+    });
+    ModuleUtils::iterDefinedEvents(wasm, [&](Event* event) {
+      auto dceName = getName("event", event->name.str);
+      DCENodeToEvent[dceName] = event->name;
+      eventToDCENode[event->name] = dceName;
+      nodes[dceName] = DCENode(dceName);
+    });
+    // only process function, global, and event imports - the table and memory
+    // are always there
+    ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
+      auto id = getImportId(import->module, import->base);
+      if (importIdToDCENode.find(id) == importIdToDCENode.end()) {
+        auto dceName = getName("importId", import->name.str);
+        importIdToDCENode[id] = dceName;
+      }
+    });
+    ModuleUtils::iterImportedGlobals(wasm, [&](Global* import) {
+      auto id = getImportId(import->module, import->base);
+      if (importIdToDCENode.find(id) == importIdToDCENode.end()) {
+        auto dceName = getName("importId", import->name.str);
+        importIdToDCENode[id] = dceName;
+      }
+    });
+    ModuleUtils::iterImportedEvents(wasm, [&](Event* import) {
+      auto id = getImportId(import->module, import->base);
+      if (importIdToDCENode.find(id) == importIdToDCENode.end()) {
+        auto dceName = getName("importId", import->name.str);
+        importIdToDCENode[id] = dceName;
+      }
+    });
+    for (auto& exp : wasm.exports) {
+      if (exportToDCENode.find(exp->name) == exportToDCENode.end()) {
+        auto dceName = getName("export", exp->name.str);
+        DCENodeToExport[dceName] = exp->name;
+        exportToDCENode[exp->name] = dceName;
+        nodes[dceName] = DCENode(dceName);
+      }
+      // we can also link the export to the thing being exported
+      auto& node = nodes[exportToDCENode[exp->name]];
+      if (exp->kind == ExternalKind::Function) {
+        if (!wasm.getFunction(exp->value)->imported()) {
+          node.reaches.push_back(functionToDCENode[exp->value]);
+        } else {
+          node.reaches.push_back(
+            importIdToDCENode[getFunctionImportId(exp->value)]);
+        }
+      } else if (exp->kind == ExternalKind::Global) {
+        if (!wasm.getGlobal(exp->value)->imported()) {
+          node.reaches.push_back(globalToDCENode[exp->value]);
+        } else {
+          node.reaches.push_back(
+            importIdToDCENode[getGlobalImportId(exp->value)]);
+        }
+      } else if (exp->kind == ExternalKind::Event) {
+        if (!wasm.getEvent(exp->value)->imported()) {
+          node.reaches.push_back(eventToDCENode[exp->value]);
+        } else {
+          node.reaches.push_back(
+            importIdToDCENode[getEventImportId(exp->value)]);
+        }
+      }
+    }
+    // Add initializer dependencies
+    // if we provide a parent DCE name, that is who can reach what we see
+    // if none is provided, then it is something we must root
+    struct InitScanner : public PostWalker<InitScanner> {
+      InitScanner(MetaDCEGraph* parent, Name parentDceName)
+        : parent(parent), parentDceName(parentDceName) {}
+
+      void visitGlobalGet(GlobalGet* curr) { handleGlobal(curr->name); }
+      void visitGlobalSet(GlobalSet* curr) { handleGlobal(curr->name); }
+
+    private:
+      MetaDCEGraph* parent;
+      Name parentDceName;
+
+      void handleGlobal(Name name) {
+        Name dceName;
+        if (!getModule()->getGlobal(name)->imported()) {
+          // its a defined global
+          dceName = parent->globalToDCENode[name];
+        } else {
+          // it's an import.
+          dceName = parent->importIdToDCENode[parent->getGlobalImportId(name)];
+        }
+        if (parentDceName.isNull()) {
+          parent->roots.insert(parentDceName);
+        } else {
+          parent->nodes[parentDceName].reaches.push_back(dceName);
+        }
+      }
+    };
+    ModuleUtils::iterDefinedGlobals(wasm, [&](Global* global) {
+      InitScanner scanner(this, globalToDCENode[global->name]);
+      scanner.setModule(&wasm);
+      scanner.walk(global->init);
+    });
+    // we can't remove segments, so root what they need
+    InitScanner rooter(this, Name());
+    rooter.setModule(&wasm);
+    for (auto& segment : wasm.table.segments) {
+      // TODO: currently, all functions in the table are roots, but we
+      //       should add an option to refine that
+      for (auto& name : segment.data) {
+        if (!wasm.getFunction(name)->imported()) {
+          roots.insert(functionToDCENode[name]);
+        } else {
+          roots.insert(importIdToDCENode[getFunctionImportId(name)]);
+        }
+      }
+      rooter.walk(segment.offset);
+    }
+    for (auto& segment : wasm.memory.segments) {
+      if (!segment.isPassive) {
+        rooter.walk(segment.offset);
+      }
+    }
+
+    // A parallel scanner for function bodies
+    struct Scanner : public WalkerPass<PostWalker<Scanner>> {
+      bool isFunctionParallel() override { return true; }
+
+      Scanner(MetaDCEGraph* parent) : parent(parent) {}
+
+      Scanner* create() override { return new Scanner(parent); }
+
+      void visitCall(Call* curr) {
+        if (!getModule()->getFunction(curr->target)->imported()) {
+          parent->nodes[parent->functionToDCENode[getFunction()->name]]
+            .reaches.push_back(parent->functionToDCENode[curr->target]);
+        } else {
+          assert(parent->functionToDCENode.count(getFunction()->name) > 0);
+          parent->nodes[parent->functionToDCENode[getFunction()->name]]
+            .reaches.push_back(
+              parent
+                ->importIdToDCENode[parent->getFunctionImportId(curr->target)]);
+        }
+      }
+      void visitGlobalGet(GlobalGet* curr) { handleGlobal(curr->name); }
+      void visitGlobalSet(GlobalSet* curr) { handleGlobal(curr->name); }
+
+    private:
+      MetaDCEGraph* parent;
+
+      void handleGlobal(Name name) {
+        if (!getFunction()) {
+          return; // non-function stuff (initializers) are handled separately
+        }
+        Name dceName;
+        if (!getModule()->getGlobal(name)->imported()) {
+          // its a global
+          dceName = parent->globalToDCENode[name];
+        } else {
+          // it's an import.
+          dceName = parent->importIdToDCENode[parent->getGlobalImportId(name)];
+        }
+        parent->nodes[parent->functionToDCENode[getFunction()->name]]
+          .reaches.push_back(dceName);
+      }
+    };
+
+    PassRunner runner(&wasm);
+    Scanner(this).run(&runner, &wasm);
+  }
+
+private:
+  // gets a unique name for the graph
+  Name getName(std::string prefix1, std::string prefix2) {
+    while (1) {
+      auto curr =
+        Name(prefix1 + '$' + prefix2 + '$' + std::to_string(nameIndex++));
+      if (nodes.find(curr) == nodes.end()) {
+        return curr;
+      }
+    }
+  }
+
+  Index nameIndex = 0;
+
+  std::unordered_set<Name> reached;
+
+public:
+  // Perform the DCE: simple marking from the roots
+  void deadCodeElimination() {
+    std::vector<Name> queue;
+    for (auto root : roots) {
+      reached.insert(root);
+      queue.push_back(root);
+    }
+    while (queue.size() > 0) {
+      auto name = queue.back();
+      queue.pop_back();
+      auto& node = nodes[name];
+      for (auto target : node.reaches) {
+        if (reached.find(target) == reached.end()) {
+          reached.insert(target);
+          queue.push_back(target);
+        }
+      }
+    }
+  }
+
+  // Apply to the wasm
+  void apply() {
+    // Remove the unused exports
+    std::vector<Name> toRemove;
+    for (auto& exp : wasm.exports) {
+      auto name = exp->name;
+      auto dceName = exportToDCENode[name];
+      if (reached.find(dceName) == reached.end()) {
+        toRemove.push_back(name);
+      }
+    }
+    for (auto name : toRemove) {
+      wasm.removeExport(name);
+    }
+    // Now they are gone, standard optimization passes can do the rest!
+    PassRunner passRunner(&wasm);
+    passRunner.add("remove-unused-module-elements");
+    // removing functions may alter the optimum order, as # of calls can change
+    passRunner.add("reorder-functions");
+    passRunner.run();
+  }
+
+  // Print out everything we found is not used, and so can be
+  // removed, including on the outside
+  void printAllUnused() {
+    std::set<std::string> unused;
+    for (auto& pair : nodes) {
+      auto name = pair.first;
+      if (reached.find(name) == reached.end()) {
+        unused.insert(name.str);
+      }
+    }
+    for (auto& name : unused) {
+      std::cout << "unused: " << name << '\n';
+    }
+  }
+
+  // A debug utility, prints out the graph
+  void dump() {
+    std::cout << "=== graph ===\n";
+    for (auto root : roots) {
+      std::cout << "root: " << root.str << '\n';
+    }
+    std::map<Name, ImportId> importMap;
+    for (auto& pair : importIdToDCENode) {
+      auto& id = pair.first;
+      auto dceName = pair.second;
+      importMap[dceName] = id;
+    }
+    for (auto& pair : nodes) {
+      auto name = pair.first;
+      auto& node = pair.second;
+      std::cout << "node: " << name.str << '\n';
+      if (importMap.find(name) != importMap.end()) {
+        std::cout << "  is import " << importMap[name] << '\n';
+      }
+      if (DCENodeToExport.find(name) != DCENodeToExport.end()) {
+        std::cout << "  is export " << DCENodeToExport[name].str << ", "
+                  << wasm.getExport(DCENodeToExport[name])->value << '\n';
+      }
+      if (DCENodeToFunction.find(name) != DCENodeToFunction.end()) {
+        std::cout << "  is function " << DCENodeToFunction[name] << '\n';
+      }
+      if (DCENodeToGlobal.find(name) != DCENodeToGlobal.end()) {
+        std::cout << "  is global " << DCENodeToGlobal[name] << '\n';
+      }
+      if (DCENodeToEvent.find(name) != DCENodeToEvent.end()) {
+        std::cout << "  is event " << DCENodeToEvent[name] << '\n';
+      }
+      for (auto target : node.reaches) {
+        std::cout << "  reaches: " << target.str << '\n';
+      }
+    }
+    std::cout << "=============\n";
+  }
+};
+
+//
+// main
+//
+
+int main(int argc, const char* argv[]) {
+  Name entry;
+  std::vector<std::string> passes;
+  bool emitBinary = true;
+  bool debugInfo = false;
+  std::string graphFile;
+  bool dump = false;
+
+  ToolOptions options(
+    "wasm-metadce",
+    "This tool performs dead code elimination (DCE) on a larger space "
+    "that the wasm module is just a part of. For example, if you have "
+    "JS and wasm that are connected, this can DCE the combined graph. "
+    "By doing so, it is able to eliminate wasm module exports, which "
+    "otherwise regular optimizations cannot.\n\n"
+    "This tool receives a representation of the reachability graph "
+    "that the wasm module resides in, which contains abstract nodes "
+    "and connections showing what they reach. Some of those nodes "
+    "can represent the wasm module's imports and exports. The tool "
+    "then completes the graph by adding the internal parts of the "
+    "module, and does DCE on the entire thing.\n\n"
+    "This tool will output a wasm module with dead code eliminated, "
+    "and metadata describing the things in the rest of the graph "
+    "that can be eliminated as well.\n\n"
+    "The graph description file should represent the graph in the following "
+    "JSON-like notation (note, this is not true JSON, things like "
+    "comments, escaping, single-quotes, etc. are not supported):\n\n"
+    "  [\n"
+    "    {\n"
+    "      \"name\": \"entity1\",\n"
+    "      \"reaches\": [\"entity2, \"entity3\"],\n"
+    "      \"root\": true\n"
+    "    },\n"
+    "    {\n"
+    "      \"name\": \"entity2\",\n"
+    "      \"reaches\": [\"entity1, \"entity4\"]\n"
+    "    },\n"
+    "    {\n"
+    "      \"name\": \"entity3\",\n"
+    "      \"reaches\": [\"entity1\"],\n"
+    "      \"export\": \"export1\"\n"
+    "    },\n"
+    "    {\n"
+    "      \"name\": \"entity4\",\n"
+    "      \"import\": [\"module\", \"import1\"]\n"
+    "    },\n"
+    "  ]\n\n"
+    "Each entity has a name and an optional list of the other "
+    "entities it reaches. It can also be marked as a root, "
+    "export (with the export string), or import (with the "
+    "module and import strings). DCE then computes what is "
+    "reachable from the roots.");
+
+  options
+    .add("--output",
+         "-o",
+         "Output file (stdout if not specified)",
+         Options::Arguments::One,
+         [](Options* o, const std::string& argument) {
+           o->extra["output"] = argument;
+           Colors::setEnabled(false);
+         })
+    .add("--emit-text",
+         "-S",
+         "Emit text instead of binary for the output file",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& argument) { emitBinary = false; })
+    .add("--debuginfo",
+         "-g",
+         "Emit names section and debug info",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& arguments) { debugInfo = true; })
+    .add("--graph-file",
+         "-f",
+         "Filename of the graph description file",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) { graphFile = argument; })
+    .add("--dump",
+         "-d",
+         "Dump the combined graph file (useful for debugging)",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& arguments) { dump = true; })
+    .add_positional("INFILE",
+                    Options::Arguments::One,
+                    [](Options* o, const std::string& argument) {
+                      o->extra["infile"] = argument;
+                    });
+  options.parse(argc, argv);
+
+  if (graphFile.size() == 0) {
+    Fatal() << "no graph file provided.";
+  }
+
+  auto input(read_file<std::string>(options.extra["infile"], Flags::Text));
+
+  Module wasm;
+
+  {
+    if (options.debug) {
+      std::cerr << "reading...\n";
+    }
+    ModuleReader reader;
+    reader.setDWARF(debugInfo);
+    try {
+      reader.read(options.extra["infile"], wasm);
+    } catch (ParseException& p) {
+      p.dump(std::cerr);
+      Fatal() << "error in parsing wasm input";
+    }
+  }
+
+  options.applyFeatures(wasm);
+
+  if (options.passOptions.validate) {
+    if (!WasmValidator().validate(wasm)) {
+      WasmPrinter::printModule(&wasm);
+      Fatal() << "error in validating input";
+    }
+  }
+
+  auto graphInput(read_file<std::string>(graphFile, Flags::Text));
+  auto* copy = strdup(graphInput.c_str());
+  json::Value outside;
+  outside.parse(copy);
+
+  // parse the JSON into our graph, doing all the JSON parsing here, leaving
+  // the abstract computation for the class itself
+  const json::IString NAME("name");
+  const json::IString REACHES("reaches");
+  const json::IString ROOT("root");
+  const json::IString EXPORT("export");
+  const json::IString IMPORT("import");
+
+  MetaDCEGraph graph(wasm);
+
+  if (!outside.isArray()) {
+    Fatal()
+      << "input graph must be a JSON array of nodes. see --help for the form";
+  }
+  auto size = outside.size();
+  for (size_t i = 0; i < size; i++) {
+    json::Ref ref = outside[i];
+    if (!ref->isObject()) {
+      Fatal()
+        << "nodes in input graph must be JSON objects. see --help for the form";
+    }
+    if (!ref->has(NAME)) {
+      Fatal()
+        << "nodes in input graph must have a name. see --help for the form";
+    }
+    DCENode node(ref[NAME]->getIString());
+    if (ref->has(REACHES)) {
+      json::Ref reaches = ref[REACHES];
+      if (!reaches->isArray()) {
+        Fatal() << "node.reaches must be an array. see --help for the form";
+      }
+      auto size = reaches->size();
+      for (size_t j = 0; j < size; j++) {
+        json::Ref name = reaches[j];
+        if (!name->isString()) {
+          Fatal()
+            << "node.reaches items must be strings. see --help for the form";
+        }
+        node.reaches.push_back(name->getIString());
+      }
+    }
+    if (ref->has(ROOT)) {
+      json::Ref root = ref[ROOT];
+      if (!root->isBool() || !root->getBool()) {
+        Fatal()
+          << "node.root, if it exists, must be true. see --help for the form";
+      }
+      graph.roots.insert(node.name);
+    }
+    if (ref->has(EXPORT)) {
+      json::Ref exp = ref[EXPORT];
+      if (!exp->isString()) {
+        Fatal() << "node.export, if it exists, must be a string. see --help "
+                   "for the form";
+      }
+      graph.exportToDCENode[exp->getIString()] = node.name;
+      graph.DCENodeToExport[node.name] = exp->getIString();
+    }
+    if (ref->has(IMPORT)) {
+      json::Ref imp = ref[IMPORT];
+      if (!imp->isArray() || imp->size() != 2 || !imp[0]->isString() ||
+          !imp[1]->isString()) {
+        Fatal() << "node.import, if it exists, must be an array of two "
+                   "strings. see --help for the form";
+      }
+      auto id = graph.getImportId(imp[0]->getIString(), imp[1]->getIString());
+      graph.importIdToDCENode[id] = node.name;
+    }
+    // TODO: optimize this copy with a clever move
+    graph.nodes[node.name] = node;
+  }
+
+  // The external graph is now populated. Scan the module
+  graph.scanWebAssembly();
+
+  // Debug dump the graph, if requested
+  if (dump) {
+    graph.dump();
+  }
+
+  // Perform the DCE
+  graph.deadCodeElimination();
+
+  // Apply to the wasm
+  graph.apply();
+
+  if (options.extra.count("output") > 0) {
+    ModuleWriter writer;
+    writer.setBinary(emitBinary);
+    writer.setDebugInfo(debugInfo);
+    writer.write(wasm, options.extra["output"]);
+  }
+
+  // Print out everything that we found is removable, the outside might use that
+  graph.printAllUnused();
+
+  // Clean up
+  free(copy);
+}
diff --git a/binaryen/src/tools/wasm-opt.cpp b/binaryen/src/tools/wasm-opt.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/wasm-opt.cpp
@@ -0,0 +1,384 @@
+/*
+ * 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.
+ */
+
+//
+// A WebAssembly optimizer, loads code, optionally runs passes on it,
+// then writes it.
+//
+
+#include <memory>
+
+#include "execution-results.h"
+#include "fuzzing.h"
+#include "js-wrapper.h"
+#include "optimization-options.h"
+#include "pass.h"
+#include "shell-interface.h"
+#include "spec-wrapper.h"
+#include "support/command-line.h"
+#include "support/debug.h"
+#include "support/file.h"
+#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"
+
+#define DEBUG_TYPE "opt"
+
+using namespace wasm;
+
+// runs a command and returns its output TODO: portability, return code checking
+static std::string runCommand(std::string command) {
+#ifdef __linux__
+  std::string output;
+  const int MAX_BUFFER = 1024;
+  char buffer[MAX_BUFFER];
+  FILE* stream = popen(command.c_str(), "r");
+  while (fgets(buffer, MAX_BUFFER, stream) != NULL) {
+    output.append(buffer);
+  }
+  pclose(stream);
+  return output;
+#else
+  Fatal() << "TODO: portability for wasm-opt runCommand";
+#endif
+}
+
+static bool willRemoveDebugInfo(const std::vector<std::string>& passes) {
+  for (auto& pass : passes) {
+    if (pass == "strip" || pass == "strip-debug" || pass == "strip-dwarf") {
+      return true;
+    }
+  }
+  return false;
+}
+
+//
+// main
+//
+
+int main(int argc, const char* argv[]) {
+  Name entry;
+  bool emitBinary = true;
+  bool converge = false;
+  bool fuzzExecBefore = false;
+  bool fuzzExecAfter = false;
+  std::string extraFuzzCommand;
+  bool translateToFuzz = false;
+  bool fuzzPasses = false;
+  bool fuzzMemory = true;
+  bool fuzzOOB = true;
+  std::string emitJSWrapper;
+  std::string emitSpecWrapper;
+  std::string emitWasm2CWrapper;
+  std::string inputSourceMapFilename;
+  std::string outputSourceMapFilename;
+  std::string outputSourceMapUrl;
+
+  OptimizationOptions options("wasm-opt", "Read, write, and optimize files");
+  options
+    .add("--output",
+         "-o",
+         "Output file (stdout if not specified)",
+         Options::Arguments::One,
+         [](Options* o, const std::string& argument) {
+           o->extra["output"] = argument;
+           Colors::setEnabled(false);
+         })
+    .add("--emit-text",
+         "-S",
+         "Emit text instead of binary for the output file",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& argument) { emitBinary = false; })
+    .add("--converge",
+         "-c",
+         "Run passes to convergence, continuing while binary size decreases",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& arguments) { converge = true; })
+    .add(
+      "--fuzz-exec-before",
+      "-feh",
+      "Execute functions before optimization, helping fuzzing find bugs",
+      Options::Arguments::Zero,
+      [&](Options* o, const std::string& arguments) { fuzzExecBefore = true; })
+    .add("--fuzz-exec",
+         "-fe",
+         "Execute functions before and after optimization, helping fuzzing "
+         "find bugs",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& arguments) {
+           fuzzExecBefore = fuzzExecAfter = true;
+         })
+    .add("--extra-fuzz-command",
+         "-efc",
+         "An extra command to run on the output before and after optimizing. "
+         "The output is compared between the two, and an error occurs if they "
+         "are not equal",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& arguments) {
+           extraFuzzCommand = arguments;
+         })
+    .add(
+      "--translate-to-fuzz",
+      "-ttf",
+      "Translate the input into a valid wasm module *somehow*, useful for "
+      "fuzzing",
+      Options::Arguments::Zero,
+      [&](Options* o, const std::string& arguments) { translateToFuzz = true; })
+    .add("--fuzz-passes",
+         "-fp",
+         "Pick a random set of passes to run, useful for fuzzing. this depends "
+         "on translate-to-fuzz (it picks the passes from the input)",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& arguments) { fuzzPasses = true; })
+    .add("--no-fuzz-memory",
+         "",
+         "don't emit memory ops when fuzzing",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& arguments) { fuzzMemory = false; })
+    .add("--no-fuzz-oob",
+         "",
+         "don't emit out-of-bounds loads/stores/indirect calls when fuzzing",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& arguments) { fuzzOOB = false; })
+    .add("--emit-js-wrapper",
+         "-ejw",
+         "Emit a JavaScript wrapper file that can run the wasm with some test "
+         "values, useful for fuzzing",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& arguments) {
+           emitJSWrapper = arguments;
+         })
+    .add("--emit-spec-wrapper",
+         "-esw",
+         "Emit a wasm spec interpreter wrapper file that can run the wasm with "
+         "some test values, useful for fuzzing",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& arguments) {
+           emitSpecWrapper = arguments;
+         })
+    .add("--emit-wasm2c-wrapper",
+         "-esw",
+         "Emit a C wrapper file that can run the wasm after it is compiled "
+         "with wasm2c, useful for fuzzing",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& arguments) {
+           emitWasm2CWrapper = arguments;
+         })
+    .add("--input-source-map",
+         "-ism",
+         "Consume source map from the specified file",
+         Options::Arguments::One,
+         [&inputSourceMapFilename](Options* o, const std::string& argument) {
+           inputSourceMapFilename = argument;
+         })
+    .add("--output-source-map",
+         "-osm",
+         "Emit source map to the specified file",
+         Options::Arguments::One,
+         [&outputSourceMapFilename](Options* o, const std::string& argument) {
+           outputSourceMapFilename = argument;
+         })
+    .add("--output-source-map-url",
+         "-osu",
+         "Emit specified string as source map URL",
+         Options::Arguments::One,
+         [&outputSourceMapUrl](Options* o, const std::string& argument) {
+           outputSourceMapUrl = argument;
+         })
+    .add_positional("INFILE",
+                    Options::Arguments::One,
+                    [](Options* o, const std::string& argument) {
+                      o->extra["infile"] = argument;
+                    });
+  options.parse(argc, argv);
+
+  Module wasm;
+
+  BYN_TRACE("reading...\n");
+
+  auto exitOnInvalidWasm = [&](const char* message) {
+    // If the user asked to print the module, print it even if invalid,
+    // as otherwise there is no way to print the broken module (the pass
+    // to print would not be reached).
+    if (std::find(options.passes.begin(), options.passes.end(), "print") !=
+        options.passes.end()) {
+      WasmPrinter::printModule(&wasm);
+    }
+    Fatal() << message;
+  };
+
+  if (!translateToFuzz) {
+    ModuleReader reader;
+    // Enable DWARF parsing if we were asked for debug info, and were not
+    // asked to remove it.
+    reader.setDWARF(options.passOptions.debugInfo &&
+                    !willRemoveDebugInfo(options.passes));
+    reader.setProfile(options.profile);
+    try {
+      reader.read(options.extra["infile"], wasm, inputSourceMapFilename);
+    } catch (ParseException& p) {
+      p.dump(std::cerr);
+      std::cerr << '\n';
+      Fatal() << "error parsing wasm";
+    } catch (MapParseException& p) {
+      p.dump(std::cerr);
+      std::cerr << '\n';
+      Fatal() << "error parsing wasm source map";
+    } catch (std::bad_alloc&) {
+      Fatal() << "error building module, std::bad_alloc (possibly invalid "
+                 "request for silly amounts of memory)";
+    }
+
+    options.applyFeatures(wasm);
+
+    if (options.passOptions.validate) {
+      if (!WasmValidator().validate(wasm)) {
+        exitOnInvalidWasm("error validating input");
+      }
+    }
+  } else {
+    // translate-to-fuzz
+    options.applyFeatures(wasm);
+    TranslateToFuzzReader reader(wasm, options.extra["infile"]);
+    if (fuzzPasses) {
+      reader.pickPasses(options);
+    }
+    reader.setAllowMemory(fuzzMemory);
+    reader.setAllowOOB(fuzzOOB);
+    reader.build();
+    if (options.passOptions.validate) {
+      if (!WasmValidator().validate(wasm)) {
+        WasmPrinter::printModule(&wasm);
+        Fatal() << "error after translate-to-fuzz";
+      }
+    }
+  }
+
+  if (emitJSWrapper.size() > 0) {
+    // As the code will run in JS, we must legalize it.
+    PassRunner runner(&wasm);
+    runner.add("legalize-js-interface");
+    runner.run();
+  }
+
+  ExecutionResults results;
+  if (fuzzExecBefore) {
+    results.get(wasm);
+  }
+
+  if (emitJSWrapper.size() > 0) {
+    std::ofstream outfile;
+    outfile.open(emitJSWrapper, std::ofstream::out);
+    outfile << generateJSWrapper(wasm);
+    outfile.close();
+  }
+  if (emitSpecWrapper.size() > 0) {
+    std::ofstream outfile;
+    outfile.open(emitSpecWrapper, std::ofstream::out);
+    outfile << generateSpecWrapper(wasm);
+    outfile.close();
+  }
+  if (emitWasm2CWrapper.size() > 0) {
+    std::ofstream outfile;
+    outfile.open(emitWasm2CWrapper, std::ofstream::out);
+    outfile << generateWasm2CWrapper(wasm);
+    outfile.close();
+  }
+
+  std::string firstOutput;
+
+  if (extraFuzzCommand.size() > 0 && options.extra.count("output") > 0) {
+    BYN_TRACE("writing binary before opts, for extra fuzz command...\n");
+    ModuleWriter writer;
+    writer.setBinary(emitBinary);
+    writer.setDebugInfo(options.passOptions.debugInfo);
+    writer.write(wasm, options.extra["output"]);
+    firstOutput = runCommand(extraFuzzCommand);
+    std::cout << "[extra-fuzz-command first output:]\n" << firstOutput << '\n';
+  }
+
+  if (!options.runningPasses()) {
+    if (!options.quiet) {
+      std::cerr << "warning: no passes specified, not doing any work\n";
+    }
+  } else {
+    BYN_TRACE("running passes...\n");
+    auto runPasses = [&]() {
+      options.runPasses(wasm);
+      if (options.passOptions.validate) {
+        bool valid = WasmValidator().validate(wasm);
+        if (!valid) {
+          exitOnInvalidWasm("error after opts");
+        }
+      }
+    };
+    runPasses();
+    if (converge) {
+      // Keep on running passes to convergence, defined as binary
+      // size no longer decreasing.
+      auto getSize = [&]() {
+        BufferWithRandomAccess buffer;
+        WasmBinaryWriter writer(&wasm, buffer);
+        writer.write();
+        return buffer.size();
+      };
+      auto lastSize = getSize();
+      while (1) {
+        BYN_TRACE("running iteration for convergence (" << lastSize << ")..\n");
+        runPasses();
+        auto currSize = getSize();
+        if (currSize >= lastSize) {
+          break;
+        }
+        lastSize = currSize;
+      }
+    }
+  }
+
+  if (fuzzExecAfter) {
+    results.check(wasm);
+  }
+
+  if (options.extra.count("output") == 0) {
+    if (!options.quiet) {
+      std::cerr << "warning: no output file specified, not emitting output\n";
+    }
+    return 0;
+  }
+
+  BYN_TRACE("writing...\n");
+  ModuleWriter writer;
+  writer.setBinary(emitBinary);
+  writer.setDebugInfo(options.passOptions.debugInfo);
+  if (outputSourceMapFilename.size()) {
+    writer.setSourceMapFilename(outputSourceMapFilename);
+    writer.setSourceMapUrl(outputSourceMapUrl);
+  }
+  writer.write(wasm, options.extra["output"]);
+
+  if (extraFuzzCommand.size() > 0) {
+    auto secondOutput = runCommand(extraFuzzCommand);
+    std::cout << "[extra-fuzz-command second output:]\n" << firstOutput << '\n';
+    if (firstOutput != secondOutput) {
+      Fatal() << "extra fuzz command output differs\n";
+    }
+  }
+  return 0;
+}
diff --git a/binaryen/src/tools/wasm-reduce.cpp b/binaryen/src/tools/wasm-reduce.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/wasm-reduce.cpp
@@ -0,0 +1,1312 @@
+/*
+ * 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.
+ */
+
+//
+// Tries to reduce the input wasm into the smallest possible wasm
+// that still generates the same result on a given command. This is
+// useful to reduce bug testcases, for example, if a file crashes
+// the optimizer, you can reduce it to find the smallest file that
+// also crashes it (which generally will show the same bug, in a
+// much more debuggable manner).
+//
+
+#include <cstdio>
+#include <cstdlib>
+#include <memory>
+
+#include "ir/branch-utils.h"
+#include "ir/iteration.h"
+#include "ir/literal-utils.h"
+#include "ir/properties.h"
+#include "pass.h"
+#include "support/colors.h"
+#include "support/command-line.h"
+#include "support/file.h"
+#include "support/path.h"
+#include "support/timing.h"
+#include "wasm-builder.h"
+#include "wasm-io.h"
+#include "wasm-validator.h"
+#ifdef _WIN32
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include <windows.h>
+// Create a string with last error message
+std::string GetLastErrorStdStr() {
+  DWORD error = GetLastError();
+  if (error) {
+    LPVOID lpMsgBuf;
+    DWORD bufLen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                                   FORMAT_MESSAGE_FROM_SYSTEM |
+                                   FORMAT_MESSAGE_IGNORE_INSERTS,
+                                 NULL,
+                                 error,
+                                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                                 (LPTSTR)&lpMsgBuf,
+                                 0,
+                                 NULL);
+    if (bufLen) {
+      LPCSTR lpMsgStr = (LPCSTR)lpMsgBuf;
+      std::string result(lpMsgStr, lpMsgStr + bufLen);
+      LocalFree(lpMsgBuf);
+      return result;
+    }
+  }
+  return std::string();
+}
+#endif
+using namespace wasm;
+
+// a timeout on every execution of the command
+size_t timeout = 2;
+
+struct ProgramResult {
+  int code;
+  std::string output;
+  double time;
+
+  ProgramResult() = default;
+  ProgramResult(std::string command) { getFromExecution(command); }
+
+#ifdef _WIN32
+  void getFromExecution(std::string command) {
+    Timer timer;
+    timer.start();
+    SECURITY_ATTRIBUTES saAttr;
+    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+    saAttr.bInheritHandle = TRUE;
+    saAttr.lpSecurityDescriptor = NULL;
+
+    HANDLE hChildStd_OUT_Rd;
+    HANDLE hChildStd_OUT_Wr;
+
+    if (
+      // Create a pipe for the child process's STDOUT.
+      !CreatePipe(&hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &saAttr, 0) ||
+      // Ensure the read handle to the pipe for STDOUT is not inherited.
+      !SetHandleInformation(hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) {
+      Fatal() << "CreatePipe \"" << command
+              << "\" failed: " << GetLastErrorStdStr() << ".\n";
+    }
+
+    STARTUPINFO si;
+    PROCESS_INFORMATION pi;
+
+    ZeroMemory(&si, sizeof(si));
+    si.cb = sizeof(si);
+    si.hStdError = hChildStd_OUT_Wr;
+    si.hStdOutput = hChildStd_OUT_Wr;
+    si.dwFlags |= STARTF_USESTDHANDLES;
+    ZeroMemory(&pi, sizeof(pi));
+
+    // Start the child process.
+    if (!CreateProcess(NULL, // No module name (use command line)
+                       (LPSTR)command.c_str(), // Command line
+                       NULL,                   // Process handle not inheritable
+                       NULL,                   // Thread handle not inheritable
+                       TRUE,                   // Set handle inheritance to TRUE
+                       0,                      // No creation flags
+                       NULL,                   // Use parent's environment block
+                       NULL, // Use parent's starting directory
+                       &si,  // Pointer to STARTUPINFO structure
+                       &pi)  // Pointer to PROCESS_INFORMATION structure
+    ) {
+      Fatal() << "CreateProcess \"" << command
+              << "\" failed: " << GetLastErrorStdStr() << ".\n";
+    }
+
+    // Wait until child process exits.
+    DWORD retVal = WaitForSingleObject(pi.hProcess, timeout * 1000);
+    if (retVal == WAIT_TIMEOUT) {
+      printf("Command timeout: %s", command.c_str());
+      TerminateProcess(pi.hProcess, -1);
+    }
+    DWORD dwordExitCode;
+    if (!GetExitCodeProcess(pi.hProcess, &dwordExitCode)) {
+      Fatal() << "GetExitCodeProcess failed: " << GetLastErrorStdStr() << ".\n";
+    }
+    code = (int)dwordExitCode;
+
+    // Close process and thread handles.
+    CloseHandle(pi.hProcess);
+    CloseHandle(pi.hThread);
+
+    // Read output from the child process's pipe for STDOUT
+    // Stop when there is no more data.
+    {
+      const int BUFSIZE = 4096;
+      DWORD dwRead, dwTotal, dwTotalRead = 0;
+      CHAR chBuf[BUFSIZE];
+      BOOL bSuccess = FALSE;
+
+      PeekNamedPipe(hChildStd_OUT_Rd, NULL, 0, NULL, &dwTotal, NULL);
+      while (dwTotalRead < dwTotal) {
+        bSuccess =
+          ReadFile(hChildStd_OUT_Rd, chBuf, BUFSIZE - 1, &dwRead, NULL);
+        if (!bSuccess || dwRead == 0)
+          break;
+        chBuf[dwRead] = 0;
+        dwTotalRead += dwRead;
+        output.append(chBuf);
+      }
+    }
+    timer.stop();
+    time = timer.getTotal();
+  }
+#else  // POSIX
+  // runs the command and notes the output
+  // TODO: also stderr, not just stdout?
+  void getFromExecution(std::string command) {
+    Timer timer;
+    timer.start();
+    // do this using just core stdio.h and stdlib.h, for portability
+    // sadly this requires two invokes
+    code = system(("timeout " + std::to_string(timeout) + "s " + command +
+                   " > /dev/null 2> /dev/null")
+                    .c_str());
+    const int MAX_BUFFER = 1024;
+    char buffer[MAX_BUFFER];
+    FILE* stream = popen(
+      ("timeout " + std::to_string(timeout) + "s " + command + " 2> /dev/null")
+        .c_str(),
+      "r");
+    while (fgets(buffer, MAX_BUFFER, stream) != NULL) {
+      output.append(buffer);
+    }
+    pclose(stream);
+    timer.stop();
+    time = timer.getTotal() / 2;
+  }
+#endif // _WIN32
+
+  bool operator==(ProgramResult& other) {
+    return code == other.code && output == other.output;
+  }
+  bool operator!=(ProgramResult& other) { return !(*this == other); }
+
+  bool failed() { return code != 0; }
+
+  void dump(std::ostream& o) {
+    o << "[ProgramResult] code: " << code << " stdout: \n"
+      << output << "[====]\nin " << time << " seconds\n[/ProgramResult]\n";
+  }
+};
+
+namespace std {
+
+inline std::ostream& operator<<(std::ostream& o, ProgramResult& result) {
+  result.dump(o);
+  return o;
+}
+
+} // namespace std
+
+ProgramResult expected;
+
+// Removing functions is extremely beneficial and efficient. We aggressively
+// try to remove functions, unless we've seen they can't be removed, in which
+// case we may try again but much later.
+static std::unordered_set<Name> functionsWeTriedToRemove;
+
+struct Reducer
+  : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<Reducer>>> {
+  std::string command, test, working;
+  bool binary, deNan, verbose, debugInfo;
+
+  // test is the file we write to that the command will operate on
+  // working is the current temporary state, the reduction so far
+  Reducer(std::string command,
+          std::string test,
+          std::string working,
+          bool binary,
+          bool deNan,
+          bool verbose,
+          bool debugInfo)
+    : command(command), test(test), working(working), binary(binary),
+      deNan(deNan), verbose(verbose), debugInfo(debugInfo) {}
+
+  // runs passes in order to reduce, until we can't reduce any more
+  // the criterion here is wasm binary size
+  void reduceUsingPasses() {
+    // run optimization passes until we can't shrink it any more
+    std::vector<std::string> passes = {
+      "-Oz",
+      "-Os",
+      "-O1",
+      "-O2",
+      "-O3",
+      "-O4",
+      "--flatten -Os",
+      "--flatten -O3",
+      "--flatten --local-cse -Os",
+      "--coalesce-locals --vacuum",
+      "--dce",
+      "--duplicate-function-elimination",
+      "--inlining",
+      "--inlining-optimizing",
+      "--optimize-level=3 --inlining-optimizing",
+      "--memory-packing",
+      "--remove-unused-names --merge-blocks --vacuum",
+      "--optimize-instructions",
+      "--precompute",
+      "--remove-imports",
+      "--remove-memory",
+      "--remove-unused-names --remove-unused-brs",
+      "--remove-unused-module-elements",
+      "--remove-unused-nonfunction-module-elements",
+      "--reorder-functions",
+      "--reorder-locals",
+      "--simplify-locals --vacuum",
+      "--strip",
+      "--vacuum"};
+    auto oldSize = file_size(working);
+    bool more = true;
+    while (more) {
+      // std::cerr << "|    starting passes loop iteration\n";
+      more = false;
+      // try both combining with a generic shrink (so minor pass overhead is
+      // compensated for), and without
+      for (auto pass : passes) {
+        std::string currCommand = Path::getBinaryenBinaryTool("wasm-opt") + " ";
+        currCommand += working + " --detect-features -o " + test + " " + pass;
+        if (debugInfo) {
+          currCommand += " -g ";
+        }
+        if (!binary) {
+          currCommand += " -S ";
+        }
+        if (verbose) {
+          std::cerr << "|    trying pass command: " << currCommand << "\n";
+        }
+        if (!ProgramResult(currCommand).failed()) {
+          auto newSize = file_size(test);
+          if (newSize < oldSize) {
+            // the pass didn't fail, and the size looks smaller, so promising
+            // see if it is still has the property we are preserving
+            if (ProgramResult(command) == expected) {
+              std::cerr << "|    command \"" << currCommand
+                        << "\" succeeded, reduced size to " << newSize
+                        << ", and preserved the property\n";
+              copy_file(test, working);
+              more = true;
+              oldSize = newSize;
+            }
+          }
+        }
+      }
+    }
+    if (verbose) {
+      std::cerr << "|    done with passes for now\n";
+    }
+  }
+
+  // does one pass of slow and destructive reduction. returns whether it
+  // succeeded or not
+  // the criterion here is a logical change in the program. this may actually
+  // increase wasm size in some cases, but it should allow more reduction later.
+  // @param factor how much to ignore. starting with a high factor skips through
+  //               most of the file, which is often faster than going one by one
+  //               from the start
+  size_t reduceDestructively(int factor_) {
+    factor = factor_;
+    // prepare
+    loadWorking();
+    reduced = 0;
+    funcsSeen = 0;
+    // before we do any changes, it should be valid to write out the module:
+    // size should be as expected, and output should be as expected
+    ProgramResult result;
+    if (!writeAndTestReduction(result)) {
+      std::cerr << "\n|! WARNING: writing before destructive reduction fails, "
+                   "very unlikely reduction can work\n"
+                << result << '\n';
+    }
+    // destroy!
+    walkModule(getModule());
+    return reduced;
+  }
+
+  void loadWorking() {
+    module = make_unique<Module>();
+    Module wasm;
+    ModuleReader reader;
+    reader.read(working, *module);
+    wasm.features = FeatureSet::All;
+    builder = make_unique<Builder>(*module);
+    setModule(module.get());
+  }
+
+  // destructive reduction state
+
+  size_t reduced;
+  Expression* beforeReduction;
+  std::unique_ptr<Module> module;
+  std::unique_ptr<Builder> builder;
+  Index funcsSeen;
+  int factor;
+
+  // write the module and see if the command still fails on it as expected
+  bool writeAndTestReduction() {
+    ProgramResult result;
+    return writeAndTestReduction(result);
+  }
+
+  bool writeAndTestReduction(ProgramResult& out) {
+    // write the module out
+    ModuleWriter writer;
+    writer.setBinary(binary);
+    writer.setDebugInfo(debugInfo);
+    writer.write(*getModule(), test);
+    // note that it is ok for the destructively-reduced module to be bigger
+    // than the previous - each destructive reduction removes logical code,
+    // and so is strictly better, even if the wasm binary format happens to
+    // encode things slightly less efficiently.
+    // test it
+    out.getFromExecution(command);
+    return out == expected;
+  }
+
+  bool shouldTryToReduce(size_t bonus = 1) {
+    static size_t counter = 0;
+    counter += bonus;
+    return (counter % factor) <= bonus;
+  }
+
+  bool isOkReplacement(Expression* with) {
+    if (deNan) {
+      if (auto* c = with->dynCast<Const>()) {
+        if (c->value.isNaN()) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  // tests a reduction on the current traversal node, and undos if it failed
+  bool tryToReplaceCurrent(Expression* with) {
+    if (!isOkReplacement(with)) {
+      return false;
+    }
+    auto* curr = getCurrent();
+    // std::cerr << "try " << curr << " => " << with << '\n';
+    if (curr->type != with->type) {
+      return false;
+    }
+    if (!shouldTryToReduce()) {
+      return false;
+    }
+    replaceCurrent(with);
+    if (!writeAndTestReduction()) {
+      replaceCurrent(curr);
+      return false;
+    }
+    std::cerr << "|      tryToReplaceCurrent succeeded (in " << getLocation()
+              << ")\n";
+    noteReduction();
+    return true;
+  }
+
+  void noteReduction(size_t amount = 1) {
+    reduced += amount;
+    copy_file(test, working);
+  }
+
+  // tests a reduction on an arbitrary child
+  bool tryToReplaceChild(Expression*& child, Expression* with) {
+    if (!isOkReplacement(with)) {
+      return false;
+    }
+    if (child->type != with->type) {
+      return false;
+    }
+    if (!shouldTryToReduce()) {
+      return false;
+    }
+    auto* before = child;
+    child = with;
+    if (!writeAndTestReduction()) {
+      child = before;
+      return false;
+    }
+    std::cerr << "|      tryToReplaceChild succeeded (in " << getLocation()
+              << ")\n";
+    // std::cerr << "|      " << before << " => " << with << '\n';
+    noteReduction();
+    return true;
+  }
+
+  std::string getLocation() {
+    if (getFunction()) {
+      return getFunction()->name.str;
+    }
+    return "(non-function context)";
+  }
+
+  // visitors. in each we try to remove code in a destructive and nontrivial
+  // way. "nontrivial" means something that optimization passes can't achieve,
+  // since we don't need to duplicate work that they do
+
+  void visitExpression(Expression* curr) {
+    // type-based reductions
+    if (curr->type == Type::none) {
+      if (tryToReduceCurrentToNop()) {
+        return;
+      }
+    } else if (curr->type.isConcrete()) {
+      if (tryToReduceCurrentToConst()) {
+        return;
+      }
+    } else {
+      assert(curr->type == Type::unreachable);
+      if (tryToReduceCurrentToUnreachable()) {
+        return;
+      }
+    }
+    // specific reductions
+    if (auto* iff = curr->dynCast<If>()) {
+      if (iff->type == Type::none) {
+        // perhaps we need just the condition?
+        if (tryToReplaceCurrent(builder->makeDrop(iff->condition))) {
+          return;
+        }
+      }
+      handleCondition(iff->condition);
+    } else if (auto* br = curr->dynCast<Break>()) {
+      handleCondition(br->condition);
+    } else if (auto* select = curr->dynCast<Select>()) {
+      handleCondition(select->condition);
+    } else if (auto* sw = curr->dynCast<Switch>()) {
+      handleCondition(sw->condition);
+      // Try to replace switch targets with the default
+      for (auto& target : sw->targets) {
+        if (target != sw->default_) {
+          auto old = target;
+          target = sw->default_;
+          if (!tryToReplaceCurrent(curr)) {
+            target = old;
+          }
+        }
+      }
+      // Try to shorten the list of targets.
+      while (sw->targets.size() > 1) {
+        auto last = sw->targets.back();
+        sw->targets.pop_back();
+        if (!tryToReplaceCurrent(curr)) {
+          sw->targets.push_back(last);
+          break;
+        }
+      }
+    } else if (auto* block = curr->dynCast<Block>()) {
+      if (!shouldTryToReduce()) {
+        return;
+      }
+      // replace a singleton
+      auto& list = block->list;
+      if (list.size() == 1 &&
+          !BranchUtils::BranchSeeker::has(block, block->name)) {
+        if (tryToReplaceCurrent(block->list[0])) {
+          return;
+        }
+      }
+      // try to get rid of nops
+      Index i = 0;
+      while (list.size() > 1 && i < list.size()) {
+        auto* curr = list[i];
+        if (curr->is<Nop>() && shouldTryToReduce()) {
+          // try to remove it
+          for (Index j = i; j < list.size() - 1; j++) {
+            list[j] = list[j + 1];
+          }
+          list.pop_back();
+          if (writeAndTestReduction()) {
+            std::cerr << "|      block-nop removed\n";
+            noteReduction();
+            return;
+          }
+          list.push_back(nullptr);
+          // we failed; undo
+          for (Index j = list.size() - 1; j > i; j--) {
+            list[j] = list[j - 1];
+          }
+          list[i] = curr;
+        }
+        i++;
+      }
+      return; // nothing more to do
+    } else if (auto* loop = curr->dynCast<Loop>()) {
+      if (shouldTryToReduce() &&
+          !BranchUtils::BranchSeeker::has(loop, loop->name)) {
+        tryToReplaceCurrent(loop->body);
+      }
+      return; // nothing more to do
+    }
+    // Finally, try to replace with a child.
+    for (auto* child : ChildIterator(curr)) {
+      if (child->type.isConcrete() && curr->type == Type::none) {
+        if (tryToReplaceCurrent(builder->makeDrop(child))) {
+          return;
+        }
+      } else {
+        if (tryToReplaceCurrent(child)) {
+          return;
+        }
+      }
+    }
+    // If that didn't work, try to replace with a child + a unary conversion,
+    // but not if it's already unary
+    if (curr->type.isSingle() && !curr->is<Unary>()) {
+      for (auto* child : ChildIterator(curr)) {
+        if (child->type == curr->type) {
+          continue; // already tried
+        }
+        if (!child->type.isSingle()) {
+          continue; // no conversion
+        }
+        Expression* fixed = nullptr;
+        TODO_SINGLE_COMPOUND(curr->type);
+        switch (curr->type.getBasic()) {
+          case Type::i32: {
+            TODO_SINGLE_COMPOUND(child->type);
+            switch (child->type.getBasic()) {
+              case Type::i32:
+                WASM_UNREACHABLE("invalid type");
+              case Type::i64:
+                fixed = builder->makeUnary(WrapInt64, child);
+                break;
+              case Type::f32:
+                fixed = builder->makeUnary(TruncSFloat32ToInt32, child);
+                break;
+              case Type::f64:
+                fixed = builder->makeUnary(TruncSFloat64ToInt32, child);
+                break;
+              case Type::v128:
+              case Type::funcref:
+              case Type::externref:
+              case Type::exnref:
+              case Type::anyref:
+              case Type::eqref:
+              case Type::i31ref:
+                continue; // not implemented yet
+              case Type::none:
+              case Type::unreachable:
+                WASM_UNREACHABLE("unexpected type");
+            }
+            break;
+          }
+          case Type::i64: {
+            TODO_SINGLE_COMPOUND(child->type);
+            switch (child->type.getBasic()) {
+              case Type::i32:
+                fixed = builder->makeUnary(ExtendSInt32, child);
+                break;
+              case Type::i64:
+                WASM_UNREACHABLE("invalid type");
+              case Type::f32:
+                fixed = builder->makeUnary(TruncSFloat32ToInt64, child);
+                break;
+              case Type::f64:
+                fixed = builder->makeUnary(TruncSFloat64ToInt64, child);
+                break;
+              case Type::v128:
+              case Type::funcref:
+              case Type::externref:
+              case Type::exnref:
+              case Type::anyref:
+              case Type::eqref:
+              case Type::i31ref:
+                continue; // not implemented yet
+              case Type::none:
+              case Type::unreachable:
+                WASM_UNREACHABLE("unexpected type");
+            }
+            break;
+          }
+          case Type::f32: {
+            TODO_SINGLE_COMPOUND(child->type);
+            switch (child->type.getBasic()) {
+              case Type::i32:
+                fixed = builder->makeUnary(ConvertSInt32ToFloat32, child);
+                break;
+              case Type::i64:
+                fixed = builder->makeUnary(ConvertSInt64ToFloat32, child);
+                break;
+              case Type::f32:
+                WASM_UNREACHABLE("unexpected type");
+              case Type::f64:
+                fixed = builder->makeUnary(DemoteFloat64, child);
+                break;
+              case Type::v128:
+              case Type::funcref:
+              case Type::externref:
+              case Type::exnref:
+              case Type::anyref:
+              case Type::eqref:
+              case Type::i31ref:
+                continue; // not implemented yet
+              case Type::none:
+              case Type::unreachable:
+                WASM_UNREACHABLE("unexpected type");
+            }
+            break;
+          }
+          case Type::f64: {
+            TODO_SINGLE_COMPOUND(child->type);
+            switch (child->type.getBasic()) {
+              case Type::i32:
+                fixed = builder->makeUnary(ConvertSInt32ToFloat64, child);
+                break;
+              case Type::i64:
+                fixed = builder->makeUnary(ConvertSInt64ToFloat64, child);
+                break;
+              case Type::f32:
+                fixed = builder->makeUnary(PromoteFloat32, child);
+                break;
+              case Type::f64:
+                WASM_UNREACHABLE("unexpected type");
+              case Type::v128:
+              case Type::funcref:
+              case Type::externref:
+              case Type::exnref:
+              case Type::anyref:
+              case Type::eqref:
+              case Type::i31ref:
+                continue; // not implemented yet
+              case Type::none:
+              case Type::unreachable:
+                WASM_UNREACHABLE("unexpected type");
+            }
+            break;
+          }
+          case Type::v128:
+          case Type::funcref:
+          case Type::externref:
+          case Type::exnref:
+          case Type::anyref:
+          case Type::eqref:
+          case Type::i31ref:
+            continue; // not implemented yet
+          case Type::none:
+          case Type::unreachable:
+            WASM_UNREACHABLE("unexpected type");
+        }
+        assert(fixed->type == curr->type);
+        if (tryToReplaceCurrent(fixed)) {
+          return;
+        }
+      }
+    }
+  }
+
+  void visitFunction(Function* curr) {
+    if (!curr->imported()) {
+      // extra chance to work on the function toplevel element, as if it can
+      // be reduced it's great
+      visitExpression(curr->body);
+    }
+    // finish function
+    funcsSeen++;
+    static int last = 0;
+    int percentage = (100 * funcsSeen) / getModule()->functions.size();
+    if (std::abs(percentage - last) >= 5) {
+      std::cerr << "|    " << percentage << "% of funcs complete\n";
+      last = percentage;
+    }
+  }
+
+  // TODO: bisection on segment shrinking?
+
+  void visitTable(Table* curr) {
+    std::cerr << "|    try to simplify table\n";
+    Name first;
+    for (auto& segment : curr->segments) {
+      for (auto item : segment.data) {
+        first = item;
+        break;
+      }
+      if (!first.isNull()) {
+        break;
+      }
+    }
+    visitSegmented(curr, first, 100);
+  }
+
+  void visitMemory(Memory* curr) {
+    std::cerr << "|    try to simplify memory\n";
+    visitSegmented(curr, 0, 2);
+  }
+
+  template<typename T, typename U>
+  void visitSegmented(T* curr, U zero, size_t bonus) {
+    // try to reduce to first function. first, shrink segment elements.
+    // while we are shrinking successfully, keep going exponentially.
+    bool justShrank = false;
+    bool shrank = false;
+    for (auto& segment : curr->segments) {
+      auto& data = segment.data;
+      // when we succeed, try to shrink by more and more, similar to bisection
+      size_t skip = 1;
+      for (size_t i = 0; i < data.size() && !data.empty(); i++) {
+        if (!justShrank && !shouldTryToReduce(bonus)) {
+          continue;
+        }
+        auto save = data;
+        for (size_t j = 0; j < skip; j++) {
+          if (!data.empty()) {
+            data.pop_back();
+          }
+        }
+        auto justShrank = writeAndTestReduction();
+        if (justShrank) {
+          std::cerr << "|      shrank segment (skip: " << skip << ")\n";
+          shrank = true;
+          noteReduction();
+          skip = std::min(size_t(factor), 2 * skip);
+        } else {
+          data = save;
+          break;
+        }
+      }
+    }
+    // the "opposite" of shrinking: copy a 'zero' element
+    for (auto& segment : curr->segments) {
+      if (segment.data.empty()) {
+        continue;
+      }
+      for (auto& item : segment.data) {
+        if (!shouldTryToReduce(bonus)) {
+          continue;
+        }
+        if (item == zero) {
+          continue;
+        }
+        auto save = item;
+        item = zero;
+        if (writeAndTestReduction()) {
+          std::cerr << "|      zeroed segment\n";
+          noteReduction();
+        } else {
+          item = save;
+        }
+        if (shrank) {
+          // zeroing is fairly inefficient. if we are managing to shrink
+          // (which we do exponentially), just zero one per segment at most
+          break;
+        }
+      }
+    }
+  }
+
+  void visitModule(Module* curr) {
+    assert(curr == module.get());
+    // try to remove functions
+    std::cerr << "|    try to remove functions\n";
+    std::vector<Name> functionNames;
+    for (auto& func : module->functions) {
+      functionNames.push_back(func->name);
+    }
+    size_t skip = 1;
+    // If we just removed some functions in the previous iteration, keep trying
+    // to remove more as this is one of the most efficient ways to reduce.
+    bool justRemoved = false;
+    for (size_t i = 0; i < functionNames.size(); i++) {
+      if (!justRemoved &&
+          functionsWeTriedToRemove.count(functionNames[i]) == 1 &&
+          !shouldTryToReduce(std::max((factor / 100) + 1, 1000))) {
+        continue;
+      }
+      std::vector<Name> names;
+      for (size_t j = 0; names.size() < skip && i + j < functionNames.size();
+           j++) {
+        auto name = functionNames[i + j];
+        if (module->getFunctionOrNull(name)) {
+          names.push_back(name);
+          functionsWeTriedToRemove.insert(name);
+        }
+      }
+      if (names.size() == 0) {
+        continue;
+      }
+      std::cout << "|    try to remove " << names.size()
+                << " functions (skip: " << skip << ")\n";
+      justRemoved = tryToRemoveFunctions(names);
+      if (justRemoved) {
+        noteReduction(names.size());
+        i += skip;
+        skip = std::min(size_t(factor), 2 * skip);
+      } else {
+        skip = std::max(skip / 2, size_t(1)); // or 1?
+      }
+    }
+    // try to remove exports
+    std::cerr << "|    try to remove exports (with factor " << factor << ")\n";
+    std::vector<Export> exports;
+    for (auto& exp : module->exports) {
+      exports.push_back(*exp);
+    }
+    skip = 1;
+    for (size_t i = 0; i < exports.size(); i++) {
+      if (!shouldTryToReduce(std::max((factor / 100) + 1, 1000))) {
+        continue;
+      }
+      std::vector<Export> currExports;
+      for (size_t j = 0; currExports.size() < skip && i + j < exports.size();
+           j++) {
+        auto exp = exports[i + j];
+        if (module->getExportOrNull(exp.name)) {
+          currExports.push_back(exp);
+          module->removeExport(exp.name);
+        }
+      }
+      ProgramResult result;
+      if (!writeAndTestReduction(result)) {
+        for (auto exp : currExports) {
+          module->addExport(new Export(exp));
+        }
+        skip = std::max(skip / 2, size_t(1)); // or 1?
+      } else {
+        std::cerr << "|      removed " << currExports.size() << " exports\n";
+        noteReduction(currExports.size());
+        i += skip;
+        skip = std::min(size_t(factor), 2 * skip);
+      }
+    }
+    // If we are left with a single function that is not exported or used in
+    // a table, that is useful as then we can change the return type.
+    if (module->functions.size() == 1 && module->exports.empty() &&
+        module->table.segments.empty()) {
+      auto* func = module->functions[0].get();
+      // We can't remove something that might have breaks to it.
+      if (!func->imported() && !Properties::isNamedControlFlow(func->body)) {
+        auto funcSig = func->sig;
+        auto* funcBody = func->body;
+        for (auto* child : ChildIterator(func->body)) {
+          if (!(child->type.isConcrete() || child->type == Type::none)) {
+            continue; // not something a function can return
+          }
+          // Try to replace the body with the child, fixing up the function
+          // to accept it.
+          func->sig.results = child->type;
+          func->body = child;
+          if (writeAndTestReduction()) {
+            // great, we succeeded!
+            std::cerr << "|    altered function result type\n";
+            noteReduction(1);
+            break;
+          }
+          // Undo.
+          func->sig = funcSig;
+          func->body = funcBody;
+        }
+      }
+    }
+  }
+
+  bool tryToRemoveFunctions(std::vector<Name> names) {
+    for (auto name : names) {
+      module->removeFunction(name);
+    }
+
+    // remove all references to them
+    struct FunctionReferenceRemover
+      : public PostWalker<FunctionReferenceRemover> {
+      std::unordered_set<Name> names;
+      std::vector<Name> exportsToRemove;
+
+      FunctionReferenceRemover(std::vector<Name>& vec) {
+        for (auto name : vec) {
+          names.insert(name);
+        }
+      }
+      void visitCall(Call* curr) {
+        if (names.count(curr->target)) {
+          replaceCurrent(Builder(*getModule()).replaceWithIdenticalType(curr));
+        }
+      }
+      void visitExport(Export* curr) {
+        if (names.count(curr->value)) {
+          exportsToRemove.push_back(curr->name);
+        }
+      }
+      void visitTable(Table* curr) {
+        Name other;
+        for (auto& segment : curr->segments) {
+          for (auto name : segment.data) {
+            if (!names.count(name)) {
+              other = name;
+              break;
+            }
+          }
+          if (!other.isNull()) {
+            break;
+          }
+        }
+        if (other.isNull()) {
+          return; // we failed to find a replacement
+        }
+        for (auto& segment : curr->segments) {
+          for (auto& name : segment.data) {
+            if (names.count(name)) {
+              name = other;
+            }
+          }
+        }
+      }
+      void doWalkModule(Module* module) {
+        PostWalker<FunctionReferenceRemover>::doWalkModule(module);
+        for (auto name : exportsToRemove) {
+          module->removeExport(name);
+        }
+      }
+    };
+    FunctionReferenceRemover referenceRemover(names);
+    referenceRemover.walkModule(module.get());
+
+    if (WasmValidator().validate(
+          *module, WasmValidator::Globally | WasmValidator::Quiet) &&
+        writeAndTestReduction()) {
+      std::cerr << "|      removed " << names.size() << " functions\n";
+      return true;
+    } else {
+      loadWorking(); // restore it from orbit
+      return false;
+    }
+  }
+
+  // helpers
+
+  // try to replace condition with always true and always false
+  void handleCondition(Expression*& condition) {
+    if (!condition) {
+      return;
+    }
+    if (condition->is<Const>()) {
+      return;
+    }
+    auto* c = builder->makeConst(int32_t(0));
+    if (!tryToReplaceChild(condition, c)) {
+      c->value = Literal(int32_t(1));
+      tryToReplaceChild(condition, c);
+    }
+  }
+
+  bool tryToReduceCurrentToNop() {
+    auto* curr = getCurrent();
+    if (curr->is<Nop>()) {
+      return false;
+    }
+    // try to replace with a trivial value
+    Nop nop;
+    if (tryToReplaceCurrent(&nop)) {
+      replaceCurrent(builder->makeNop());
+      return true;
+    }
+    return false;
+  }
+
+  // try to replace a concrete value with a trivial constant
+  bool tryToReduceCurrentToConst() {
+    auto* curr = getCurrent();
+    if (curr->is<Const>()) {
+      return false;
+    }
+    // try to replace with a trivial value
+    if (curr->type.isNullable()) {
+      RefNull* n = builder->makeRefNull(curr->type);
+      return tryToReplaceCurrent(n);
+    }
+    if (curr->type.isTuple()) {
+      Expression* n =
+        builder->makeConstantExpression(Literal::makeZeros(curr->type));
+      return tryToReplaceCurrent(n);
+    }
+    Const* c = builder->makeConst(int32_t(0));
+    if (tryToReplaceCurrent(c)) {
+      return true;
+    }
+    c->value = Literal::makeOne(curr->type);
+    c->type = curr->type;
+    return tryToReplaceCurrent(c);
+  }
+
+  bool tryToReduceCurrentToUnreachable() {
+    auto* curr = getCurrent();
+    if (curr->is<Unreachable>()) {
+      return false;
+    }
+    // try to replace with a trivial value
+    Unreachable un;
+    if (tryToReplaceCurrent(&un)) {
+      replaceCurrent(builder->makeUnreachable());
+      return true;
+    }
+    // maybe a return? TODO
+    return false;
+  }
+};
+
+//
+// main
+//
+
+int main(int argc, const char* argv[]) {
+  std::string input, test, working, command;
+  // By default, look for binaries alongside our own binary.
+  std::string binDir = Path::getDirName(argv[0]);
+  bool binary = true, deNan = false, verbose = false, debugInfo = false,
+       force = false;
+  Options options("wasm-reduce",
+                  "Reduce a wasm file to a smaller one that has the same "
+                  "behavior on a given command");
+  options
+    .add("--command",
+         "-cmd",
+         "The command to run on the test, that we want to reduce while keeping "
+         "the command's output identical. "
+         "We look at the command's return code and stdout here (TODO: stderr), "
+         "and we reduce while keeping those unchanged.",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) { command = argument; })
+    .add("--test",
+         "-t",
+         "Test file (this will be written to to test, the given command should "
+         "read it when we call it)",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) { test = argument; })
+    .add("--working",
+         "-w",
+         "Working file (this will contain the current good state while doing "
+         "temporary computations, "
+         "and will contain the final best result at the end)",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) { working = argument; })
+    .add("--binaries",
+         "-b",
+         "binaryen binaries location (bin/ directory)",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) {
+           // Add separator just in case
+           binDir = argument + Path::getPathSeparator();
+         })
+    .add("--text",
+         "-S",
+         "Emit intermediate files as text, instead of binary (also make sure "
+         "the test and working files have a .wat or .wast suffix)",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& argument) { binary = false; })
+    .add("--denan",
+         "",
+         "Avoid nans when reducing",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& argument) { deNan = true; })
+    .add("--verbose",
+         "-v",
+         "Verbose output mode",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& argument) { verbose = true; })
+    .add("--debugInfo",
+         "-g",
+         "Keep debug info in binaries",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& argument) { debugInfo = true; })
+    .add("--force",
+         "-f",
+         "Force the reduction attempt, ignoring problems that imply it is "
+         "unlikely to succeed",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& argument) { force = true; })
+    .add("--timeout",
+         "-to",
+         "A timeout to apply to each execution of the command, in seconds "
+         "(default: 2)",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) {
+           timeout = atoi(argument.c_str());
+           std::cout << "|applying timeout: " << timeout << "\n";
+         })
+    .add_positional(
+      "INFILE",
+      Options::Arguments::One,
+      [&](Options* o, const std::string& argument) { input = argument; });
+  options.parse(argc, argv);
+
+  if (test.size() == 0) {
+    Fatal() << "test file not provided\n";
+  }
+  if (working.size() == 0) {
+    Fatal() << "working file not provided\n";
+  }
+
+  if (!binary) {
+    Colors::setEnabled(false);
+  }
+
+  Path::setBinaryenBinDir(binDir);
+
+  std::cerr << "|wasm-reduce\n";
+  std::cerr << "|input: " << input << '\n';
+  std::cerr << "|test: " << test << '\n';
+  std::cerr << "|working: " << working << '\n';
+  std::cerr << "|bin dir: " << binDir << '\n';
+
+  // get the expected output
+  copy_file(input, test);
+  expected.getFromExecution(command);
+
+  std::cerr << "|expected result:\n" << expected << '\n';
+  std::cerr << "|!! Make sure the above is what you expect! !!\n\n";
+
+  auto stopIfNotForced = [&](std::string message, ProgramResult& result) {
+    std::cerr << "|! " << message << '\n' << result << '\n';
+    if (!force) {
+      Fatal() << "|! stopping, as it is very unlikely reduction can succeed "
+                 "(use -f to ignore this check)";
+    }
+  };
+
+  if (expected.time + 1 >= timeout) {
+    stopIfNotForced("execution time is dangerously close to the timeout - you "
+                    "should probably increase the timeout",
+                    expected);
+  }
+
+  std::cerr
+    << "|checking that command has different behavior on invalid binary (this "
+       "verifies that the test file is used by the command)\n";
+  {
+    {
+      std::ofstream dst(test, std::ios::binary);
+      dst << "waka waka\n";
+    }
+    ProgramResult result(command);
+    if (result == expected) {
+      stopIfNotForced(
+        "running command on an invalid module should give different results",
+        result);
+    }
+  }
+
+  std::cerr << "|checking that command has expected behavior on canonicalized "
+               "(read-written) binary\n";
+  {
+    // read and write it
+    auto cmd = Path::getBinaryenBinaryTool("wasm-opt") + " " + input +
+               " --detect-features -o " + test;
+    if (!binary) {
+      cmd += " -S";
+    }
+    ProgramResult readWrite(cmd);
+    if (readWrite.failed()) {
+      stopIfNotForced("failed to read and write the binary", readWrite);
+    } else {
+      ProgramResult result(command);
+      if (result != expected) {
+        stopIfNotForced("running command on the canonicalized module should "
+                        "give the same results",
+                        result);
+      }
+    }
+  }
+
+  copy_file(input, working);
+  auto workingSize = file_size(working);
+  std::cerr << "|input size: " << workingSize << "\n";
+
+  std::cerr << "|starting reduction!\n";
+
+  int factor = workingSize * 2;
+  size_t lastDestructiveReductions = 0;
+  size_t lastPostPassesSize = 0;
+
+  bool stopping = false;
+
+  while (1) {
+    Reducer reducer(command, test, working, binary, deNan, verbose, debugInfo);
+
+    // run binaryen optimization passes to reduce. passes are fast to run
+    // and can often reduce large amounts of code efficiently, as opposed
+    // to detructive reduction (i.e., that doesn't preserve correctness as
+    // passes do) since destrucive must operate one change at a time
+    std::cerr << "|  reduce using passes...\n";
+    auto oldSize = file_size(working);
+    reducer.reduceUsingPasses();
+    auto newSize = file_size(working);
+    auto passProgress = oldSize - newSize;
+    std::cerr << "|  after pass reduction: " << newSize << "\n";
+
+    // always stop after a pass reduction attempt, for final cleanup
+    if (stopping) {
+      break;
+    }
+
+    // check if the full cycle (destructive/passes) has helped or not
+    if (lastPostPassesSize && newSize >= lastPostPassesSize) {
+      std::cerr << "|  progress has stopped, skipping to the end\n";
+      if (factor == 1) {
+        // this is after doing work with factor 1, so after the remaining work,
+        // stop
+        stopping = true;
+      } else {
+        // just try to remove all we can and finish up
+        factor = 1;
+      }
+    }
+    lastPostPassesSize = newSize;
+
+    // if destructive reductions lead to useful proportionate pass reductions,
+    // keep going at the same factor, as pass reductions are far faster
+    std::cerr << "|  pass progress: " << passProgress
+              << ", last destructive: " << lastDestructiveReductions << '\n';
+    if (passProgress >= 4 * lastDestructiveReductions) {
+      // don't change
+      std::cerr << "|  progress is good, do not quickly decrease factor\n";
+    } else {
+      if (factor > 10) {
+        factor = (factor / 3) + 1;
+      } else {
+        factor = (factor + 1) / 2; // stable on 1
+      }
+    }
+
+    // no point in a factor lorger than the size
+    assert(newSize > 4); // wasm modules are >4 bytes anyhow
+    factor = std::min(factor, int(newSize) / 4);
+
+    // try to reduce destructively. if a high factor fails to find anything,
+    // quickly try a lower one (no point in doing passes until we reduce
+    // destructively at least a little)
+    while (1) {
+      std::cerr << "|  reduce destructively... (factor: " << factor << ")\n";
+      lastDestructiveReductions = reducer.reduceDestructively(factor);
+      if (lastDestructiveReductions > 0) {
+        break;
+      }
+      // we failed to reduce destructively
+      if (factor == 1) {
+        stopping = true;
+        break;
+      }
+      factor = std::max(
+        1, factor / 4); // quickly now, try to find *something* we can reduce
+    }
+
+    std::cerr << "|  destructive reduction led to size: " << file_size(working)
+              << '\n';
+  }
+  std::cerr << "|finished, final size: " << file_size(working) << "\n";
+  copy_file(working, test); // just to avoid confusion
+}
diff --git a/binaryen/src/tools/wasm-shell.cpp b/binaryen/src/tools/wasm-shell.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/wasm-shell.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// A WebAssembly shell, loads a .wast file (WebAssembly in S-Expression format)
+// and executes it. This provides similar functionality as the reference
+// interpreter, like assert_* calls, so it can run the spec test suite.
+//
+
+#include <memory>
+
+#include "execution-results.h"
+#include "pass.h"
+#include "shell-interface.h"
+#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"
+
+using namespace cashew;
+using namespace wasm;
+
+Name ASSERT_RETURN("assert_return");
+Name ASSERT_TRAP("assert_trap");
+Name ASSERT_INVALID("assert_invalid");
+Name ASSERT_MALFORMED("assert_malformed");
+Name ASSERT_UNLINKABLE("assert_unlinkable");
+Name INVOKE("invoke");
+Name GET("get");
+
+// Modules named in the file
+
+std::map<Name, std::unique_ptr<Module>> modules;
+std::map<Name, std::unique_ptr<SExpressionWasmBuilder>> builders;
+std::map<Name, std::unique_ptr<ShellExternalInterface>> interfaces;
+std::map<Name, std::unique_ptr<ModuleInstance>> instances;
+
+//
+// An operation on a module
+//
+
+struct Operation {
+  ModuleInstance* instance;
+  Name operation;
+  Name name;
+  LiteralList arguments;
+
+  Operation(Element& element,
+            ModuleInstance* instanceInit,
+            SExpressionWasmBuilder& builder)
+    : instance(instanceInit) {
+    operation = element[0]->str();
+    Index i = 1;
+    if (element.size() >= 3 && element[2]->isStr()) {
+      // module also specified
+      Name moduleName = element[i++]->str();
+      instance = instances[moduleName].get();
+    }
+    name = element[i++]->str();
+    for (size_t j = i; j < element.size(); j++) {
+      Expression* argument = builder.parseExpression(*element[j]);
+      arguments.push_back(getLiteralFromConstExpression(argument));
+    }
+  }
+
+  Literals operate() {
+    if (operation == INVOKE) {
+      return instance->callExport(name, arguments);
+    } else if (operation == GET) {
+      return {instance->getExport(name)};
+    } else {
+      WASM_UNREACHABLE("unknown operation");
+    }
+  }
+};
+
+static void run_asserts(Name moduleName,
+                        size_t* i,
+                        bool* checked,
+                        Module* wasm,
+                        Element* root,
+                        SExpressionWasmBuilder* builder,
+                        Name entry) {
+  ModuleInstance* instance = nullptr;
+  if (wasm) {
+    // prefix make_unique to work around visual studio bugs
+    auto tempInterface = wasm::make_unique<ShellExternalInterface>();
+    auto tempInstance =
+      wasm::make_unique<ModuleInstance>(*wasm, tempInterface.get());
+    interfaces[moduleName].swap(tempInterface);
+    instances[moduleName].swap(tempInstance);
+    instance = instances[moduleName].get();
+    if (entry.is()) {
+      Function* function = wasm->getFunction(entry);
+      if (!function) {
+        std::cerr << "Unknown entry " << entry << std::endl;
+      } else {
+        LiteralList arguments;
+        for (const auto& param : function->sig.params) {
+          arguments.push_back(Literal(param));
+        }
+        try {
+          instance->callExport(entry, arguments);
+        } catch (ExitException&) {
+        }
+      }
+    }
+  }
+  while (*i < root->size()) {
+    Element& curr = *(*root)[*i];
+    IString id = curr[0]->str();
+    if (id == MODULE) {
+      break;
+    }
+    *checked = true;
+    Colors::red(std::cerr);
+    std::cerr << *i << '/' << (root->size() - 1);
+    Colors::green(std::cerr);
+    std::cerr << " CHECKING: ";
+    Colors::normal(std::cerr);
+    std::cerr << curr;
+    Colors::green(std::cerr);
+    std::cerr << " [line: " << curr.line << "]\n";
+    Colors::normal(std::cerr);
+    if (id == ASSERT_INVALID || id == ASSERT_MALFORMED ||
+        id == ASSERT_UNLINKABLE) {
+      // a module invalidity test
+      Module wasm;
+      wasm.features = FeatureSet::All;
+      bool invalid = false;
+      std::unique_ptr<SExpressionWasmBuilder> builder;
+      try {
+        builder = std::unique_ptr<SExpressionWasmBuilder>(
+          new SExpressionWasmBuilder(wasm, *curr[1], IRProfile::Normal));
+      } catch (const ParseException&) {
+        invalid = true;
+      }
+      if (!invalid) {
+        // maybe parsed ok, but otherwise incorrect
+        invalid = !WasmValidator().validate(wasm);
+      }
+      if (!invalid && id == ASSERT_UNLINKABLE) {
+        // validate "instantiating" the mdoule
+        auto reportUnknownImport = [&](Importable* import) {
+          std::cerr << "unknown import: " << import->module << '.'
+                    << import->base << '\n';
+          invalid = true;
+        };
+        ModuleUtils::iterImportedGlobals(wasm, reportUnknownImport);
+        ModuleUtils::iterImportedFunctions(wasm, [&](Importable* import) {
+          if (import->module == SPECTEST && import->base.startsWith(PRINT)) {
+            // We can handle it.
+          } else {
+            reportUnknownImport(import);
+          }
+        });
+        if (wasm.memory.imported()) {
+          reportUnknownImport(&wasm.memory);
+        }
+        if (wasm.table.imported()) {
+          reportUnknownImport(&wasm.table);
+        }
+        for (auto& segment : wasm.table.segments) {
+          for (auto name : segment.data) {
+            // spec tests consider it illegal to use spectest.print in a table
+            if (auto* import = wasm.getFunction(name)) {
+              if (import->imported() && import->module == SPECTEST &&
+                  import->base.startsWith(PRINT)) {
+                std::cerr << "cannot put spectest.print in table\n";
+                invalid = true;
+              }
+            }
+          }
+        }
+      }
+      if (!invalid) {
+        Colors::red(std::cerr);
+        std::cerr << "[should have been invalid]\n";
+        Colors::normal(std::cerr);
+        Fatal() << &wasm << '\n';
+      }
+    } else if (id == INVOKE) {
+      assert(wasm);
+      Operation operation(curr, instance, *builder);
+      operation.operate();
+    } else if (wasm) { // if no wasm, we skipped the module
+      // an invoke test
+      bool trapped = false;
+      WASM_UNUSED(trapped);
+      Literals result;
+      try {
+        Operation operation(*curr[1], instance, *builder);
+        result = operation.operate();
+      } catch (const TrapException&) {
+        trapped = true;
+      } catch (const WasmException& e) {
+        std::cout << "[exception thrown: " << e.exn << "]" << std::endl;
+        trapped = true;
+      }
+      if (id == ASSERT_RETURN) {
+        assert(!trapped);
+        Literals expected;
+        if (curr.size() >= 3) {
+          expected =
+            getLiteralsFromConstExpression(builder->parseExpression(*curr[2]));
+        }
+        std::cerr << "seen " << result << ", expected " << expected << '\n';
+        if (expected != result) {
+          Fatal() << "unexpected, should be identical\n";
+        }
+      }
+      if (id == ASSERT_TRAP) {
+        assert(trapped);
+      }
+    }
+    *i += 1;
+  }
+}
+
+//
+// main
+//
+
+int main(int argc, const char* argv[]) {
+  Name entry;
+  std::set<size_t> skipped;
+
+  Options options("wasm-shell", "Execute .wast files");
+  options
+    .add("--entry",
+         "-e",
+         "Call the entry point after parsing the module",
+         Options::Arguments::One,
+         [&entry](Options*, const std::string& argument) { entry = argument; })
+    .add("--skip",
+         "-s",
+         "Skip input on certain lines (comma-separated-list)",
+         Options::Arguments::One,
+         [&skipped](Options*, const std::string& argument) {
+           size_t i = 0;
+           while (i < argument.size()) {
+             auto ending = argument.find(',', i);
+             if (ending == std::string::npos) {
+               ending = argument.size();
+             }
+             auto sub = argument.substr(i, ending - i);
+             skipped.insert(atoi(sub.c_str()));
+             i = ending + 1;
+           }
+         })
+    .add_positional("INFILE",
+                    Options::Arguments::One,
+                    [](Options* o, const std::string& argument) {
+                      o->extra["infile"] = argument;
+                    });
+  options.parse(argc, argv);
+
+  auto input(
+    read_file<std::vector<char>>(options.extra["infile"], Flags::Text));
+
+  bool checked = false;
+
+  try {
+    if (options.debug) {
+      std::cerr << "parsing text to s-expressions...\n";
+    }
+    SExpressionParser parser(input.data());
+    Element& root = *parser.root;
+
+    // A .wast may have multiple modules, with some asserts after them
+    size_t i = 0;
+    while (i < root.size()) {
+      Element& curr = *root[i];
+      if (skipped.count(curr.line) > 0) {
+        Colors::green(std::cerr);
+        std::cerr << "SKIPPING [line: " << curr.line << "]\n";
+        Colors::normal(std::cerr);
+        i++;
+        continue;
+      }
+      IString id = curr[0]->str();
+      if (id == MODULE) {
+        if (options.debug) {
+          std::cerr << "parsing s-expressions to wasm...\n";
+        }
+        Colors::green(std::cerr);
+        std::cerr << "BUILDING MODULE [line: " << curr.line << "]\n";
+        Colors::normal(std::cerr);
+        auto module = wasm::make_unique<Module>();
+        auto builder = wasm::make_unique<SExpressionWasmBuilder>(
+          *module, *root[i], IRProfile::Normal);
+        auto moduleName = module->name;
+        builders[moduleName].swap(builder);
+        modules[moduleName].swap(module);
+        i++;
+        modules[moduleName]->features = FeatureSet::All;
+        bool valid = WasmValidator().validate(*modules[moduleName]);
+        if (!valid) {
+          WasmPrinter::printModule(modules[moduleName].get());
+          Fatal() << "module failed to validate, see above";
+        }
+        run_asserts(moduleName,
+                    &i,
+                    &checked,
+                    modules[moduleName].get(),
+                    &root,
+                    builders[moduleName].get(),
+                    entry);
+      } else {
+        run_asserts(Name(), &i, &checked, nullptr, &root, nullptr, entry);
+      }
+    }
+  } catch (ParseException& p) {
+    p.dump(std::cerr);
+    exit(1);
+  }
+
+  if (checked) {
+    Colors::green(std::cerr);
+    Colors::bold(std::cerr);
+    std::cerr << "all checks passed.\n";
+    Colors::normal(std::cerr);
+  }
+}
diff --git a/binaryen/src/tools/wasm2c-wrapper.h b/binaryen/src/tools/wasm2c-wrapper.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/wasm2c-wrapper.h
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+//
+// Emit a C  wrapper file that can run the wasm after it is compiled with
+// wasm2c, useful for fuzzing.
+//
+
+#include <string>
+
+#include "wasm.h"
+
+namespace wasm {
+
+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.
+  std::string ret = R"(
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "wasm-rt-impl.h"
+#include "wasm.h"
+
+void _Z_fuzzingZ2DsupportZ_logZ2Di32Z_vi(u32 x) {
+  printf("[LoggingExternalInterface logging %d]\n", x);
+}
+void (*Z_fuzzingZ2DsupportZ_logZ2Di32Z_vi)(u32) = _Z_fuzzingZ2DsupportZ_logZ2Di32Z_vi;
+
+void _Z_fuzzingZ2DsupportZ_logZ2Di64Z_vj(u64 x) {
+  printf("[LoggingExternalInterface logging %" PRId64 "]\n", (int64_t)x);
+}
+void (*Z_fuzzingZ2DsupportZ_logZ2Di64Z_vj)(u64) = _Z_fuzzingZ2DsupportZ_logZ2Di64Z_vj;
+
+void _Z_fuzzingZ2DsupportZ_logZ2Di64Z_vii(u32 x, u32 y) {
+  printf("[LoggingExternalInterface logging %d %d]\n", x, y);
+}
+void (*Z_fuzzingZ2DsupportZ_logZ2Di64Z_vii)(u32, u32) = _Z_fuzzingZ2DsupportZ_logZ2Di64Z_vii;
+
+void _Z_fuzzingZ2DsupportZ_logZ2Df32Z_vf(f32 x) {
+  printf("[LoggingExternalInterface logging %.17e]\n", x);
+}
+void (*Z_fuzzingZ2DsupportZ_logZ2Df32Z_vf)(f32) = _Z_fuzzingZ2DsupportZ_logZ2Df32Z_vf;
+
+void _Z_fuzzingZ2DsupportZ_logZ2Df64Z_vd(f64 x) {
+  printf("[LoggingExternalInterface logging %.17le]\n", x);
+}
+void (*Z_fuzzingZ2DsupportZ_logZ2Df64Z_vd)(f64) = _Z_fuzzingZ2DsupportZ_logZ2Df64Z_vd;
+
+// Miscellaneous imports
+
+u32 tempRet0 = 0;
+
+void _Z_envZ_setTempRet0Z_vi(u32 x) {
+  tempRet0 = x;
+}
+void (*Z_envZ_setTempRet0Z_vi)(u32) = _Z_envZ_setTempRet0Z_vi;
+
+u32 _Z_envZ_getTempRet0Z_iv(void) {
+  return tempRet0;
+}
+u32 (*Z_envZ_getTempRet0Z_iv)(void) = _Z_envZ_getTempRet0Z_iv;
+
+// Main
+
+int main(int argc, char** argv) {
+  init();
+
+  // We go through each export and call it, in turn. Note that we use a loop
+  // so we can do all this with a single setjmp. A setjmp is needed to handle
+  // wasm traps, and emitting a single one helps compilation speed into wasm as
+  // compile times are O(size * num_setjmps).
+  for (size_t curr = 0;; curr++) {
+  )";
+  if (wasm.getExportOrNull("hangLimitInitializer")) {
+    ret += R"(
+    // If present, call the hang limit initializer before each export.
+    (*Z_hangLimitInitializerZ_vv)();
+)";
+  }
+  ret += R"(
+    // Prepare to call the export, so we can catch traps.
+    if (WASM_RT_SETJMP(g_jmp_buf) != 0) {
+      puts("exception!");
+    } else {
+      // Call the proper export.
+      switch(curr) {
+)";
+
+  // For each function export in the wasm, emit code to call it and log its
+  // result, similar to the other wrappers.
+  size_t functionExportIndex = 0;
+
+  for (auto& exp : wasm.exports) {
+    if (exp->kind != ExternalKind::Function) {
+      continue;
+    }
+
+    ret += "        case " + std::to_string(functionExportIndex++) + ":\n";
+
+    auto* func = wasm.getFunction(exp->value);
+
+    ret += std::string("          puts(\"[fuzz-exec] calling ") +
+           exp->name.str + "\");\n";
+    auto result = func->sig.results;
+
+    // Emit the call itself.
+    ret += "            ";
+    if (result != Type::none) {
+      ret += std::string("printf(\"[fuzz-exec] note result: ") + exp->name.str +
+             " => ";
+      TODO_SINGLE_COMPOUND(result);
+      switch (result.getBasic()) {
+        case Type::i32:
+          ret += "%d\\n\", ";
+          break;
+        case Type::i64:
+          ret += "%\" PRId64 \"\\n\", (int64_t)";
+          break;
+        case Type::f32:
+          ret += "%.17e\\n\", ";
+          break;
+        case Type::f64:
+          ret += "%.17le\\n\", ";
+          break;
+        default:
+          Fatal() << "unhandled wasm2c wrapper result type: " << result;
+      }
+    }
+
+    // Emit the callee's name with wasm2c name mangling.
+    ret += std::string("(*Z_") + exp->name.str + "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;
+      }
+    };
+
+    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).
+    bool first = true;
+    for (const auto& param : func->sig.params) {
+      WASM_UNUSED(param);
+      if (!first) {
+        ret += ", ";
+      }
+      ret += "0";
+      first = false;
+    }
+    if (result != Type::none) {
+      ret += ")";
+    }
+    ret += ");\n";
+
+    // Break from the big switch.
+    ret += "          break;\n";
+  }
+
+  ret += R"(        default:
+          return 0; // All done.
+      }
+    }
+  }
+  return 0;
+}
+)";
+
+  return ret;
+}
+
+} // namespace wasm
diff --git a/binaryen/src/tools/wasm2js.cpp b/binaryen/src/tools/wasm2js.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/wasm2js.cpp
@@ -0,0 +1,1005 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// wasm2js console tool
+//
+
+#include "wasm2js.h"
+#include "optimization-options.h"
+#include "pass.h"
+#include "support/colors.h"
+#include "support/command-line.h"
+#include "support/file.h"
+#include "wasm-s-parser.h"
+
+using namespace cashew;
+using namespace wasm;
+
+// helpers
+
+namespace {
+
+static void optimizeWasm(Module& wasm, PassOptions options) {
+  // Perform various optimizations that will be good for JS, but would not be
+  // great for wasm in general
+  struct OptimizeForJS : public WalkerPass<PostWalker<OptimizeForJS>> {
+    bool isFunctionParallel() override { return true; }
+
+    Pass* create() override { return new OptimizeForJS; }
+
+    void visitBinary(Binary* curr) {
+      // x - -c (where c is a constant) is larger than x + c, in js (but not
+      // necessarily in wasm, where LEBs prefer negatives).
+      if (curr->op == SubInt32) {
+        if (auto* c = curr->right->dynCast<Const>()) {
+          if (c->value.geti32() < 0) {
+            curr->op = AddInt32;
+            c->value = c->value.neg();
+          }
+        }
+      }
+    }
+  };
+
+  PassRunner runner(&wasm, options);
+  OptimizeForJS().run(&runner, &wasm);
+}
+
+template<typename T> static void printJS(Ref ast, T& output) {
+  JSPrinter jser(true, true, ast);
+  jser.printAst();
+  output << jser.buffer << '\n';
+}
+
+// Traversals
+
+struct TraverseInfo {
+  TraverseInfo() = default;
+  TraverseInfo(Ref node) : node(node) {
+    assert(node.get());
+    if (node->isArray()) {
+      for (size_t i = 0; i < node->size(); i++) {
+        maybeAdd(node[i]);
+      }
+    } else if (node->isAssign()) {
+      auto assign = node->asAssign();
+      maybeAdd(assign->target());
+      maybeAdd(assign->value());
+    } else if (node->isAssignName()) {
+      auto assign = node->asAssignName();
+      maybeAdd(assign->value());
+    } else {
+      // no children
+    }
+  }
+  Ref node;
+  bool scanned = false;
+  std::vector<Ref> children;
+
+private:
+  void maybeAdd(Ref child) {
+    if (child.get()) {
+      children.push_back(child);
+    }
+  }
+};
+
+// Traverse, calling visit after the children
+static void traversePrePost(Ref node,
+                            std::function<void(Ref)> visitPre,
+                            std::function<void(Ref)> visitPost) {
+  std::vector<TraverseInfo> stack;
+  stack.push_back(TraverseInfo(node));
+  while (!stack.empty()) {
+    TraverseInfo& back = stack.back();
+    if (!back.scanned) {
+      back.scanned = true;
+      // This is the first time we see this.
+      visitPre(back.node);
+      for (auto child : back.children) {
+        stack.emplace_back(child);
+      }
+      continue;
+    }
+    // Time to post-visit the node itself
+    auto node = back.node;
+    stack.pop_back();
+    visitPost(node);
+  }
+}
+
+static void traversePost(Ref node, std::function<void(Ref)> visit) {
+  traversePrePost(
+    node, [](Ref node) {}, visit);
+}
+
+static void replaceInPlace(Ref target, Ref value) {
+  assert(target->isArray() && value->isArray());
+  target->setSize(value->size());
+  for (size_t i = 0; i < value->size(); i++) {
+    target[i] = value[i];
+  }
+}
+
+static void replaceInPlaceIfPossible(Ref target, Ref value) {
+  if (target->isArray() && value->isArray()) {
+    replaceInPlace(target, value);
+  }
+}
+
+static void optimizeJS(Ref ast, Wasm2JSBuilder::Flags flags) {
+  // Helpers
+
+  auto isBinary = [](Ref node, IString op) {
+    return node->isArray() && !node->empty() && node[0] == BINARY &&
+           node[1] == op;
+  };
+
+  auto isConstantBinary = [&](Ref node, IString op, int num) {
+    return isBinary(node, op) && node[3]->isNumber() &&
+           node[3]->getNumber() == num;
+  };
+
+  auto isOrZero = [&](Ref node) { return isConstantBinary(node, OR, 0); };
+
+  auto isTrshiftZero = [&](Ref node) {
+    return isConstantBinary(node, TRSHIFT, 0);
+  };
+
+  auto isPlus = [](Ref node) {
+    return node->isArray() && !node->empty() && node[0] == UNARY_PREFIX &&
+           node[1] == PLUS;
+  };
+
+  auto isFround = [](Ref node) {
+    return node->isArray() && !node->empty() && node[0] == cashew::CALL &&
+           node[1] == MATH_FROUND;
+  };
+
+  auto isBitwise = [](Ref node) {
+    if (node->isArray() && !node->empty() && node[0] == BINARY) {
+      auto op = node[1];
+      return op == OR || op == AND || op == XOR || op == RSHIFT ||
+             op == TRSHIFT || op == LSHIFT;
+    }
+    return false;
+  };
+
+  auto isSignedBitwise = [](Ref node) {
+    if (node->isArray() && !node->empty() && node[0] == BINARY) {
+      auto op = node[1];
+      return op == OR || op == AND || op == XOR || op == RSHIFT || op == LSHIFT;
+    }
+    return false;
+  };
+
+  auto isUnary = [](Ref node, IString op) {
+    return node->isArray() && !node->empty() && node[0] == UNARY_PREFIX &&
+           node[1] == op;
+  };
+
+  auto isWhile = [](Ref node) {
+    return node->isArray() && !node->empty() && node[0] == WHILE;
+  };
+
+  auto isDo = [](Ref node) {
+    return node->isArray() && !node->empty() && node[0] == DO;
+  };
+
+  auto isIf = [](Ref node) {
+    return node->isArray() && !node->empty() && node[0] == IF;
+  };
+
+  auto removeOrZero = [&](Ref node) {
+    while (isOrZero(node)) {
+      node = node[2];
+    }
+    return node;
+  };
+
+  auto removePlus = [&](Ref node) {
+    while (isPlus(node)) {
+      node = node[2];
+    }
+    return node;
+  };
+
+  auto removePlusAndFround = [&](Ref node) {
+    while (1) {
+      if (isFround(node)) {
+        node = node[2][0];
+      } else if (isPlus(node)) {
+        node = node[2];
+      } else {
+        break;
+      }
+    }
+    return node;
+  };
+
+  auto getHeapFromAccess = [](Ref node) { return node[1]->getIString(); };
+
+  auto setHeapOnAccess = [](Ref node, IString heap) {
+    node[1] = ValueBuilder::makeName(heap);
+  };
+
+  auto isIntegerHeap = [](IString heap) {
+    return heap == HEAP8 || heap == HEAPU8 || heap == HEAP16 ||
+           heap == HEAPU16 || heap == HEAP32 || heap == HEAPU32;
+  };
+
+  auto isFloatHeap = [](IString heap) {
+    return heap == HEAPF32 || heap == HEAPF64;
+  };
+
+  auto isHeapAccess = [&](Ref node) {
+    if (node->isArray() && !node->empty() && node[0] == SUB &&
+        node[1]->isString()) {
+      auto heap = getHeapFromAccess(node);
+      return isIntegerHeap(heap) || isFloatHeap(heap);
+    }
+    return false;
+  };
+
+  // Optimize given that the expression is flowing into a boolean context
+  auto optimizeBoolean = [&](Ref node) {
+    // TODO: in some cases it may be possible to turn
+    //
+    //   if (x | 0)
+    //
+    // into
+    //
+    //   if (x)
+    //
+    // In general this is unsafe if e.g. x is -2147483648 + -2147483648 (which
+    // the | 0 turns into 0, but without it is a truthy value).
+    //
+    // Another issue is that in deterministic mode we care about corner cases
+    // that would trap in wasm, like an integer divide by zero:
+    //
+    //  if ((1 / 0) | 0)  =>  condition is Infinity | 0 = 0 which is falsey
+    //
+    // while
+    //
+    //  if (1 / 0)  =>  condition is Infinity which is truthy
+    //
+    // Thankfully this is not common, and does not occur on % (1 % 0 is a NaN
+    // which has the right truthiness), so we could perhaps do
+    //
+    //   if (!(flags.deterministic && isBinary(node[2], DIV))) return node[2];
+    //
+    // (but there is still the first issue).
+    return node;
+  };
+
+  // Optimizations
+
+  // Pre-simplification
+  traversePost(ast, [&](Ref node) {
+    // x >> 0  =>  x | 0
+    if (isConstantBinary(node, RSHIFT, 0)) {
+      node[1]->setString(OR);
+    }
+  });
+
+  traversePost(ast, [&](Ref node) {
+    if (isBitwise(node)) {
+      // x | 0 going into a bitwise op => skip the | 0
+      node[2] = removeOrZero(node[2]);
+      node[3] = removeOrZero(node[3]);
+      // (x | 0 or similar) | 0  =>  (x | 0 or similar)
+      if (isOrZero(node)) {
+        if (isSignedBitwise(node[2])) {
+          replaceInPlace(node, node[2]);
+        }
+      }
+      if (isHeapAccess(node[2])) {
+        auto heap = getHeapFromAccess(node[2]);
+        IString replacementHeap;
+        // We can avoid a cast of a load by using the load to do it instead.
+        if (isOrZero(node)) {
+          if (isIntegerHeap(heap)) {
+            replacementHeap = heap;
+          }
+        } else if (isTrshiftZero(node)) {
+          // For signed or unsigned loads smaller than 32 bits, doing an | 0
+          // was safe either way - they aren't in the range an | 0 can affect.
+          // For >>> 0 however, a negative value would change, so we still
+          // need the cast.
+          if (heap == HEAP32 || heap == HEAPU32) {
+            replacementHeap = HEAPU32;
+          } else if (heap == HEAPU16) {
+            replacementHeap = HEAPU16;
+          } else if (heap == HEAPU8) {
+            replacementHeap = HEAPU8;
+          }
+        }
+        if (!replacementHeap.isNull()) {
+          setHeapOnAccess(node[2], replacementHeap);
+          replaceInPlace(node, node[2]);
+          return;
+        }
+        // A load into an & may allow using a simpler heap, e.g. HEAPU8[..] & 1
+        // (a load of a boolean) may be HEAP8[..] & 1. The signed heaps are more
+        // commonly used, so it compresses better, and also they seem to have
+        // better performance (perhaps since HEAPU32 is at risk of not being a
+        // smallint).
+        if (node[1] == AND) {
+          if (isConstantBinary(node, AND, 1)) {
+            if (heap == HEAPU8) {
+              setHeapOnAccess(node[2], HEAP8);
+            } else if (heap == HEAPU16) {
+              setHeapOnAccess(node[2], HEAP16);
+            }
+          }
+        }
+      }
+      // Pre-compute constant [op] constant, which the lowering can generate
+      // in loads etc.
+      if (node[2]->isNumber() && node[3]->isNumber()) {
+        int32_t left = node[2]->getNumber();
+        int32_t right = node[3]->getNumber();
+        if (node[1] == OR) {
+          node->setNumber(left | right);
+        } else if (node[1] == AND) {
+          node->setNumber(left & right);
+        } else if (node[1] == XOR) {
+          node->setNumber(left ^ right);
+        } else if (node[1] == LSHIFT) {
+          node->setNumber(left << (right & 31));
+        } else if (node[1] == RSHIFT) {
+          node->setNumber(int32_t(left) >> int32_t(right & 31));
+        } else if (node[1] == TRSHIFT) {
+          node->setNumber(uint32_t(left) >> uint32_t(right & 31));
+        }
+        return;
+      }
+    }
+    // +(+x) => +x
+    else if (isPlus(node)) {
+      node[2] = removePlus(node[2]);
+    }
+    // +(+x) => +x
+    else if (isFround(node)) {
+      node[2] = removePlusAndFround(node[2]);
+    } else if (isUnary(node, L_NOT)) {
+      node[2] = optimizeBoolean(node[2]);
+    }
+    // Add/subtract can merge coercions up, except when a child is a division,
+    // which needs to be eagerly truncated to remove fractional results.
+    else if (isBinary(node, PLUS) || isBinary(node, MINUS)) {
+      auto left = node[2];
+      auto right = node[3];
+      if (isOrZero(left) && isOrZero(right) && !isBinary(left[2], DIV) &&
+          !isBinary(right[2], DIV)) {
+        auto op = node[1]->getIString();
+        // Add a coercion on top.
+        node[1]->setString(OR);
+        node[2] = left;
+        node[3] = ValueBuilder::makeNum(0);
+        // Add/subtract the inner uncoerced values.
+        left[1]->setString(op);
+        left[3] = right[2];
+      }
+    }
+    // Assignment into a heap coerces.
+    else if (node->isAssign()) {
+      auto assign = node->asAssign();
+      auto target = assign->target();
+      if (isHeapAccess(target)) {
+        auto heap = getHeapFromAccess(target);
+        if (isIntegerHeap(heap)) {
+          if (heap == HEAP8 || heap == HEAPU8) {
+            while (isOrZero(assign->value()) ||
+                   isConstantBinary(assign->value(), AND, 255)) {
+              assign->value() = assign->value()[2];
+            }
+          } else if (heap == HEAP16 || heap == HEAPU16) {
+            while (isOrZero(assign->value()) ||
+                   isConstantBinary(assign->value(), AND, 65535)) {
+              assign->value() = assign->value()[2];
+            }
+          } else {
+            assert(heap == HEAP32 || heap == HEAPU32);
+            assign->value() = removeOrZero(assign->value());
+          }
+        } else {
+          assert(isFloatHeap(heap));
+          if (heap == HEAPF32) {
+            assign->value() = removePlusAndFround(assign->value());
+          } else {
+            assign->value() = removePlus(assign->value());
+          }
+        }
+      }
+    } else if (isWhile(node) || isDo(node) || isIf(node)) {
+      node[1] = optimizeBoolean(node[1]);
+    }
+  });
+
+  // Remove unnecessary break/continue labels, when the name is that of the
+  // highest target anyhow, which we would reach without the name.
+
+  std::vector<Ref> breakCapturers;
+  std::vector<Ref> continueCapturers;
+  std::unordered_map<IString, Ref>
+    labelToValue;                      // maps the label to the loop/etc.
+  std::unordered_set<Value*> labelled; // all things with a label on them.
+  Value INVALID;
+  traversePrePost(
+    ast,
+    [&](Ref node) {
+      if (node->isArray() && !node->empty()) {
+        if (node[0] == LABEL) {
+          auto label = node[1]->getIString();
+          labelToValue[label] = node[2];
+          labelled.insert(node[2].get());
+        } else if (node[0] == WHILE || node[0] == DO || node[0] == FOR) {
+          breakCapturers.push_back(node);
+          continueCapturers.push_back(node);
+        } else if (node[0] == cashew::BLOCK) {
+          if (labelled.count(node.get())) {
+            // Cannot break to a block without the label.
+            breakCapturers.push_back(Ref(&INVALID));
+          }
+        } else if (node[0] == SWITCH) {
+          breakCapturers.push_back(node);
+        }
+      }
+    },
+    [&](Ref node) {
+      if (node->isArray() && !node->empty()) {
+        if (node[0] == LABEL) {
+          auto label = node[1]->getIString();
+          labelToValue.erase(label);
+          labelled.erase(node[2].get());
+        } else if (node[0] == WHILE || node[0] == DO || node[0] == FOR) {
+          breakCapturers.pop_back();
+          continueCapturers.pop_back();
+        } else if (node[0] == cashew::BLOCK) {
+          if (labelled.count(node.get())) {
+            breakCapturers.pop_back();
+          }
+        } else if (node[0] == SWITCH) {
+          breakCapturers.pop_back();
+        } else if (node[0] == BREAK || node[0] == CONTINUE) {
+          if (!node[1]->isNull()) {
+            auto label = node[1]->getIString();
+            assert(labelToValue.count(label));
+            auto& capturers =
+              node[0] == BREAK ? breakCapturers : continueCapturers;
+            assert(!capturers.empty());
+            if (capturers.back() == labelToValue[label]) {
+              // Success, the break/continue goes exactly where we would if we
+              // didn't have the label!
+              node[1]->setNull();
+            }
+          }
+        }
+      }
+    });
+
+  // Remove unnecessary block/loop labels.
+
+  std::set<IString> usedLabelNames;
+
+  traversePost(ast, [&](Ref node) {
+    if (node->isArray() && !node->empty()) {
+      if (node[0] == BREAK || node[0] == CONTINUE) {
+        if (!node[1]->isNull()) {
+          auto label = node[1]->getIString();
+          usedLabelNames.insert(label);
+        }
+      } else if (node[0] == LABEL) {
+        auto label = node[1]->getIString();
+        if (usedLabelNames.count(label)) {
+          // It's used; just erase it from the data structure.
+          usedLabelNames.erase(label);
+        } else {
+          // It's not used - get rid of it.
+          replaceInPlaceIfPossible(node, node[2]);
+        }
+      }
+    }
+  });
+}
+
+static void emitWasm(Module& wasm,
+                     Output& output,
+                     Wasm2JSBuilder::Flags flags,
+                     PassOptions options,
+                     Name name) {
+  if (options.optimizeLevel > 0) {
+    optimizeWasm(wasm, options);
+  }
+  Wasm2JSBuilder wasm2js(flags, options);
+  auto js = wasm2js.processWasm(&wasm, name);
+  if (options.optimizeLevel >= 2) {
+    optimizeJS(js, flags);
+  }
+  Wasm2JSGlue glue(wasm, output, flags, name);
+  glue.emitPre();
+  printJS(js, output);
+  glue.emitPost();
+}
+
+class AssertionEmitter {
+public:
+  AssertionEmitter(Element& root,
+                   SExpressionWasmBuilder& sexpBuilder,
+                   Output& out,
+                   Wasm2JSBuilder::Flags flags,
+                   const ToolOptions& options)
+    : root(root), sexpBuilder(sexpBuilder), out(out), flags(flags),
+      options(options) {}
+
+  void emit();
+
+private:
+  Element& root;
+  SExpressionWasmBuilder& sexpBuilder;
+  Output& out;
+  Wasm2JSBuilder::Flags flags;
+  ToolOptions options;
+  Module tempAllocationModule;
+
+  Ref emitAssertReturnFunc(Builder& wasmBuilder,
+                           Element& e,
+                           Name testFuncName,
+                           Name asmModule);
+  Ref emitAssertReturnNanFunc(Builder& wasmBuilder,
+                              Element& e,
+                              Name testFuncName,
+                              Name asmModule);
+  Ref emitAssertTrapFunc(Builder& wasmBuilder,
+                         Element& e,
+                         Name testFuncName,
+                         Name asmModule);
+  Ref emitInvokeFunc(Builder& wasmBuilder,
+                     Element& e,
+                     Name testFuncName,
+                     Name asmModule);
+  bool isInvokeHandled(Element& e);
+  bool isAssertHandled(Element& e);
+  void fixCalls(Ref asmjs, Name asmModule);
+
+  Ref processFunction(Function* func) {
+    Wasm2JSBuilder sub(flags, options.passOptions);
+    return sub.processStandaloneFunction(&tempAllocationModule, func);
+  }
+
+  void emitFunction(Ref func) {
+    JSPrinter jser(true, true, func);
+    jser.printAst();
+    out << jser.buffer << std::endl;
+  }
+};
+
+Ref AssertionEmitter::emitAssertReturnFunc(Builder& wasmBuilder,
+                                           Element& e,
+                                           Name testFuncName,
+                                           Name asmModule) {
+  Expression* actual = sexpBuilder.parseExpression(e[1]);
+  Expression* body = nullptr;
+  if (e.size() == 2) {
+    if (actual->type == Type::none) {
+      body = wasmBuilder.blockify(actual, wasmBuilder.makeConst(uint32_t(1)));
+    } else {
+      body = actual;
+    }
+  } else if (e.size() == 3) {
+    Expression* expected = sexpBuilder.parseExpression(e[2]);
+    Type resType = expected->type;
+    actual->type = resType;
+    TODO_SINGLE_COMPOUND(resType);
+    switch (resType.getBasic()) {
+      case Type::i32:
+        body = wasmBuilder.makeBinary(EqInt32, actual, expected);
+        break;
+
+      case Type::i64:
+        body = wasmBuilder.makeCall(
+          "i64Equal",
+          {actual,
+           wasmBuilder.makeCall(WASM_FETCH_HIGH_BITS, {}, Type::i32),
+           expected},
+          Type::i32);
+        break;
+
+      case Type::f32: {
+        body = wasmBuilder.makeCall("f32Equal", {actual, expected}, Type::i32);
+        break;
+      }
+      case Type::f64: {
+        body = wasmBuilder.makeCall("f64Equal", {actual, expected}, Type::i32);
+        break;
+      }
+
+      default: {
+        Fatal() << "Unhandled type in assert: " << resType;
+      }
+    }
+  } else {
+    assert(false && "Unexpected number of parameters in assert_return");
+  }
+  std::unique_ptr<Function> testFunc(
+    wasmBuilder.makeFunction(testFuncName,
+                             std::vector<NameType>{},
+                             body->type,
+                             std::vector<NameType>{},
+                             body));
+  Ref jsFunc = processFunction(testFunc.get());
+  fixCalls(jsFunc, asmModule);
+  emitFunction(jsFunc);
+  return jsFunc;
+}
+
+Ref AssertionEmitter::emitAssertReturnNanFunc(Builder& wasmBuilder,
+                                              Element& e,
+                                              Name testFuncName,
+                                              Name asmModule) {
+  Expression* actual = sexpBuilder.parseExpression(e[1]);
+  Expression* body = wasmBuilder.makeCall("isNaN", {actual}, Type::i32);
+  std::unique_ptr<Function> testFunc(
+    wasmBuilder.makeFunction(testFuncName,
+                             std::vector<NameType>{},
+                             body->type,
+                             std::vector<NameType>{},
+                             body));
+  Ref jsFunc = processFunction(testFunc.get());
+  fixCalls(jsFunc, asmModule);
+  emitFunction(jsFunc);
+  return jsFunc;
+}
+
+Ref AssertionEmitter::emitAssertTrapFunc(Builder& wasmBuilder,
+                                         Element& e,
+                                         Name testFuncName,
+                                         Name asmModule) {
+  Name innerFuncName("f");
+  Expression* expr = sexpBuilder.parseExpression(e[1]);
+  std::unique_ptr<Function> exprFunc(
+    wasmBuilder.makeFunction(innerFuncName,
+                             std::vector<NameType>{},
+                             expr->type,
+                             std::vector<NameType>{},
+                             expr));
+  IString expectedErr = e[2]->str();
+  Ref innerFunc = processFunction(exprFunc.get());
+  fixCalls(innerFunc, asmModule);
+  Ref outerFunc = ValueBuilder::makeFunction(testFuncName);
+  outerFunc[3]->push_back(innerFunc);
+  Ref tryBlock = ValueBuilder::makeBlock();
+  ValueBuilder::appendToBlock(tryBlock, ValueBuilder::makeCall(innerFuncName));
+  Ref catchBlock = ValueBuilder::makeBlock();
+  ValueBuilder::appendToBlock(
+    catchBlock,
+    ValueBuilder::makeReturn(ValueBuilder::makeCall(
+      ValueBuilder::makeDot(ValueBuilder::makeName(IString("e")),
+                            ValueBuilder::makeName(IString("message")),
+                            ValueBuilder::makeName(IString("includes"))),
+      ValueBuilder::makeString(expectedErr))));
+  outerFunc[3]->push_back(ValueBuilder::makeTry(
+    tryBlock, ValueBuilder::makeName((IString("e"))), catchBlock));
+  outerFunc[3]->push_back(ValueBuilder::makeReturn(ValueBuilder::makeInt(0)));
+  emitFunction(outerFunc);
+  return outerFunc;
+}
+
+Ref AssertionEmitter::emitInvokeFunc(Builder& wasmBuilder,
+                                     Element& e,
+                                     Name testFuncName,
+                                     Name asmModule) {
+  Expression* body = sexpBuilder.parseExpression(e);
+  std::unique_ptr<Function> testFunc(
+    wasmBuilder.makeFunction(testFuncName,
+                             std::vector<NameType>{},
+                             body->type,
+                             std::vector<NameType>{},
+                             body));
+  Ref jsFunc = processFunction(testFunc.get());
+  fixCalls(jsFunc, asmModule);
+  emitFunction(jsFunc);
+  return jsFunc;
+}
+
+bool AssertionEmitter::isInvokeHandled(Element& e) {
+  return e.isList() && e.size() >= 2 && e[0]->isStr() &&
+         e[0]->str() == Name("invoke");
+}
+
+bool AssertionEmitter::isAssertHandled(Element& e) {
+  return e.isList() && e.size() >= 2 && e[0]->isStr() &&
+         (e[0]->str() == Name("assert_return") ||
+          e[0]->str() == Name("assert_return_nan") ||
+          (flags.pedantic && e[0]->str() == Name("assert_trap"))) &&
+         e[1]->isList() && e[1]->size() >= 2 && (*e[1])[0]->isStr() &&
+         (*e[1])[0]->str() == Name("invoke");
+}
+
+void AssertionEmitter::fixCalls(Ref asmjs, Name asmModule) {
+  if (asmjs->isArray()) {
+    ArrayStorage& arr = asmjs->getArray();
+    for (Ref& r : arr) {
+      fixCalls(r, asmModule);
+    }
+    if (arr.size() > 0 && arr[0]->isString() &&
+        arr[0]->getIString() == cashew::CALL) {
+      assert(arr.size() >= 2);
+      if (arr[1]->getIString() == "f32Equal" ||
+          arr[1]->getIString() == "f64Equal" ||
+          arr[1]->getIString() == "i64Equal" ||
+          arr[1]->getIString() == "isNaN") {
+        // ...
+      } else if (arr[1]->getIString() == "Math_fround") {
+        arr[1]->setString("Math.fround");
+      } else {
+        Ref fixed = ValueBuilder::makeDot(ValueBuilder::makeName(asmModule),
+                                          arr[1]->getIString());
+        arr[1]->setArray(fixed->getArray());
+      }
+    }
+  }
+
+  if (asmjs->isAssign()) {
+    fixCalls(asmjs->asAssign()->target(), asmModule);
+    fixCalls(asmjs->asAssign()->value(), asmModule);
+  }
+  if (asmjs->isAssignName()) {
+    fixCalls(asmjs->asAssignName()->value(), asmModule);
+  }
+}
+
+void AssertionEmitter::emit() {
+  // TODO: nan and infinity shouldn't be needed once literal asm.js code isn't
+  // generated
+  out << R"(
+    var nan = NaN;
+    var infinity = Infinity;
+  )";
+
+  // When equating floating point values in spec tests we want to use bitwise
+  // equality like wasm does. Unfortunately though NaN makes this tricky. JS
+  // implementations like Spidermonkey and JSC will canonicalize NaN loads from
+  // `Float32Array`, but V8 will not. This means that NaN representations are
+  // kind of all over the place and difficult to bitwise equate.
+  //
+  // To work around this problem we just use a small shim which considers all
+  // NaN representations equivalent and otherwise tests for bitwise equality.
+  out << R"(
+    function f32Equal(a, b) {
+       var i = new Int32Array(1);
+       var f = new Float32Array(i.buffer);
+       f[0] = a;
+       var ai = f[0];
+       f[0] = b;
+       var bi = f[0];
+
+       return (isNaN(a) && isNaN(b)) || a == b;
+    }
+
+    function f64Equal(a, b) {
+       var i = new Int32Array(2);
+       var f = new Float64Array(i.buffer);
+       f[0] = a;
+       var ai1 = i[0];
+       var ai2 = i[1];
+       f[0] = b;
+       var bi1 = i[0];
+       var bi2 = i[1];
+
+       return (isNaN(a) && isNaN(b)) || (ai1 == bi1 && ai2 == bi2);
+    }
+
+    function i64Equal(actual_lo, actual_hi, expected_lo, expected_hi) {
+       return (actual_lo | 0) == (expected_lo | 0) && (actual_hi | 0) == (expected_hi | 0);
+    }
+  )";
+
+  Builder wasmBuilder(sexpBuilder.getModule());
+  Name asmModule = std::string("ret") + ASM_FUNC.str;
+  for (size_t i = 0; i < root.size(); ++i) {
+    Element& e = *root[i];
+    if (e.isList() && e.size() >= 1 && e[0]->isStr() &&
+        e[0]->str() == Name("module")) {
+      std::stringstream funcNameS;
+      funcNameS << ASM_FUNC.c_str() << i;
+      std::stringstream moduleNameS;
+      moduleNameS << "ret" << ASM_FUNC.c_str() << i;
+      Name funcName(funcNameS.str().c_str());
+      asmModule = Name(moduleNameS.str().c_str());
+      Module wasm;
+      options.applyFeatures(wasm);
+      SExpressionWasmBuilder builder(wasm, e, options.profile);
+      emitWasm(wasm, out, flags, options.passOptions, funcName);
+      continue;
+    }
+    if (!isInvokeHandled(e) && !isAssertHandled(e)) {
+      std::cerr << "skipping " << e << std::endl;
+      continue;
+    }
+    Name testFuncName(IString(("check" + std::to_string(i)).c_str(), false));
+    bool isInvoke = (e[0]->str() == Name("invoke"));
+    bool isReturn = (e[0]->str() == Name("assert_return"));
+    bool isReturnNan = (e[0]->str() == Name("assert_return_nan"));
+    Element* assertOp;
+    // An assertion of an invoke has the invoke inside the assert.
+    if (isAssertHandled(e)) {
+      assertOp = e[1];
+    } else {
+      assertOp = &e;
+    }
+    // Replace "invoke" with "call"
+    (*assertOp)[0]->setString(IString("call"), false, false);
+    // Need to claim dollared to get string as function target
+    (*assertOp)[1]->setString((*assertOp)[1]->str(), /*dollared=*/true, false);
+    if (isInvoke) {
+      emitInvokeFunc(wasmBuilder, e, testFuncName, asmModule);
+      out << testFuncName.str << "();\n";
+      continue;
+    }
+    // Otherwise, this is some form of assertion.
+    if (isReturn) {
+      emitAssertReturnFunc(wasmBuilder, e, testFuncName, asmModule);
+    } else if (isReturnNan) {
+      emitAssertReturnNanFunc(wasmBuilder, e, testFuncName, asmModule);
+    } else {
+      emitAssertTrapFunc(wasmBuilder, e, testFuncName, asmModule);
+    }
+
+    out << "if (!" << testFuncName.str << "()) throw 'assertion failed: " << e
+        << "';\n";
+  }
+}
+
+} // anonymous namespace
+
+// Main
+
+int main(int argc, const char* argv[]) {
+  Wasm2JSBuilder::Flags flags;
+  OptimizationOptions options("wasm2js",
+                              "Transform .wasm/.wat files to asm.js");
+  options
+    .add("--output",
+         "-o",
+         "Output file (stdout if not specified)",
+         Options::Arguments::One,
+         [](Options* o, const std::string& argument) {
+           o->extra["output"] = argument;
+           Colors::setEnabled(false);
+         })
+    .add("--allow-asserts",
+         "",
+         "Allow compilation of .wast testing asserts",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& argument) {
+           flags.allowAsserts = true;
+           o->extra["asserts"] = "1";
+         })
+    .add(
+      "--pedantic",
+      "",
+      "Emulate WebAssembly trapping behavior",
+      Options::Arguments::Zero,
+      [&](Options* o, const std::string& argument) { flags.pedantic = true; })
+    .add(
+      "--emscripten",
+      "",
+      "Emulate the glue in emscripten-compatible form (and not ES6 module "
+      "form)",
+      Options::Arguments::Zero,
+      [&](Options* o, const std::string& argument) { flags.emscripten = true; })
+    .add(
+      "--deterministic",
+      "",
+      "Replace WebAssembly trapping behavior deterministically "
+      "(the default is to not care about what would trap in wasm, like a load "
+      "out of bounds or integer divide by zero; with this flag, we try to be "
+      "deterministic at least in what happens, which might or might not be "
+      "to trap like wasm, but at least should not vary)",
+      Options::Arguments::Zero,
+      [&](Options* o, const std::string& argument) {
+        flags.deterministic = true;
+      })
+    .add(
+      "--symbols-file",
+      "",
+      "Emit a symbols file that maps function indexes to their original names",
+      Options::Arguments::One,
+      [&](Options* o, const std::string& argument) {
+        flags.symbolsFile = argument;
+      })
+    .add_positional("INFILE",
+                    Options::Arguments::One,
+                    [](Options* o, const std::string& argument) {
+                      o->extra["infile"] = argument;
+                    });
+  options.parse(argc, argv);
+  if (options.debug) {
+    flags.debug = true;
+  }
+
+  Element* root = nullptr;
+  Module wasm;
+  options.applyFeatures(wasm);
+  Ref js;
+  std::unique_ptr<SExpressionParser> sexprParser;
+  std::unique_ptr<SExpressionWasmBuilder> sexprBuilder;
+
+  auto& input = options.extra["infile"];
+  std::string suffix(".wasm");
+  bool binaryInput =
+    input.size() >= suffix.size() &&
+    input.compare(input.size() - suffix.size(), suffix.size(), suffix) == 0;
+
+  try {
+    // If the input filename ends in `.wasm`, then parse it in binary form,
+    // otherwise assume it's a `*.wat` file and go from there.
+    //
+    // Note that we're not using the built-in `ModuleReader` which will also do
+    // similar logic here because when testing JS files we use the
+    // `--allow-asserts` flag which means we need to parse the extra
+    // s-expressions that come at the end of the `*.wast` file after the module
+    // is defined.
+    if (binaryInput) {
+      ModuleReader reader;
+      reader.read(input, wasm, "");
+    } else {
+      auto input(
+        read_file<std::vector<char>>(options.extra["infile"], Flags::Text));
+      if (options.debug) {
+        std::cerr << "s-parsing..." << std::endl;
+      }
+      sexprParser = make_unique<SExpressionParser>(input.data());
+      root = sexprParser->root;
+
+      if (options.debug) {
+        std::cerr << "w-parsing..." << std::endl;
+      }
+      sexprBuilder =
+        make_unique<SExpressionWasmBuilder>(wasm, *(*root)[0], options.profile);
+    }
+  } catch (ParseException& p) {
+    p.dump(std::cerr);
+    Fatal() << "error in parsing input";
+  } catch (std::bad_alloc&) {
+    Fatal() << "error in building module, std::bad_alloc (possibly invalid "
+               "request for silly amounts of memory)";
+  }
+
+  if (options.passOptions.validate) {
+    if (!WasmValidator().validate(wasm)) {
+      WasmPrinter::printModule(&wasm);
+      Fatal() << "error in validating input";
+    }
+  }
+
+  if (options.debug) {
+    std::cerr << "j-printing..." << std::endl;
+  }
+  Output output(options.extra["output"], Flags::Text);
+  if (!binaryInput && options.extra["asserts"] == "1") {
+    AssertionEmitter(*root, *sexprBuilder, output, flags, options).emit();
+  } else {
+    emitWasm(wasm, output, flags, options.passOptions, "asmFunc");
+  }
+
+  if (options.debug) {
+    std::cerr << "done." << std::endl;
+  }
+}
diff --git a/binaryen/src/wasm-binary.h b/binaryen/src/wasm-binary.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-binary.h
@@ -0,0 +1,1533 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// Parses and emits WebAssembly binary code
+//
+
+#ifndef wasm_wasm_binary_h
+#define wasm_wasm_binary_h
+
+#include <cassert>
+#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"
+#include "support/debug.h"
+#include "wasm-builder.h"
+#include "wasm-traversal.h"
+#include "wasm-validator.h"
+#include "wasm.h"
+
+#define DEBUG_TYPE "binary"
+
+namespace wasm {
+
+enum {
+  // the maximum amount of bytes we emit per LEB
+  MaxLEB32Bytes = 5,
+};
+
+// wasm VMs on the web have decided to impose some limits on what they
+// accept
+enum WebLimitations : uint32_t {
+  MaxDataSegments = 100 * 1000,
+  MaxFunctionBodySize = 128 * 1024,
+  MaxFunctionLocals = 50 * 1000
+};
+
+template<typename T, typename MiniT> struct LEB {
+  static_assert(sizeof(MiniT) == 1, "MiniT must be a byte");
+
+  T value;
+
+  LEB() = default;
+  LEB(T value) : value(value) {}
+
+  bool hasMore(T temp, MiniT byte) {
+    // for signed, we must ensure the last bit has the right sign, as it will
+    // zero extend
+    return std::is_signed<T>::value
+             ? (temp != 0 && temp != T(-1)) || (value >= 0 && (byte & 64)) ||
+                 (value < 0 && !(byte & 64))
+             : (temp != 0);
+  }
+
+  void write(std::vector<uint8_t>* out) {
+    T temp = value;
+    bool more;
+    do {
+      uint8_t byte = temp & 127;
+      temp >>= 7;
+      more = hasMore(temp, byte);
+      if (more) {
+        byte = byte | 128;
+      }
+      out->push_back(byte);
+    } while (more);
+  }
+
+  // @minimum: a minimum number of bytes to write, padding as necessary
+  // returns the number of bytes written
+  size_t writeAt(std::vector<uint8_t>* out, size_t at, size_t minimum = 0) {
+    T temp = value;
+    size_t offset = 0;
+    bool more;
+    do {
+      uint8_t byte = temp & 127;
+      temp >>= 7;
+      more = hasMore(temp, byte) || offset + 1 < minimum;
+      if (more) {
+        byte = byte | 128;
+      }
+      (*out)[at + offset] = byte;
+      offset++;
+    } while (more);
+    return offset;
+  }
+
+  LEB<T, MiniT>& read(std::function<MiniT()> get) {
+    value = 0;
+    T shift = 0;
+    MiniT byte;
+    while (1) {
+      byte = get();
+      bool last = !(byte & 128);
+      T payload = byte & 127;
+      typedef typename std::make_unsigned<T>::type mask_type;
+      auto shift_mask = 0 == shift
+                          ? ~mask_type(0)
+                          : ((mask_type(1) << (sizeof(T) * 8 - shift)) - 1u);
+      T significant_payload = payload & shift_mask;
+      if (significant_payload != payload) {
+        if (!(std::is_signed<T>::value && last)) {
+          throw ParseException("LEB dropped bits only valid for signed LEB");
+        }
+      }
+      value |= significant_payload << shift;
+      if (last) {
+        break;
+      }
+      shift += 7;
+      if (size_t(shift) >= sizeof(T) * 8) {
+        throw ParseException("LEB overflow");
+      }
+    }
+    // If signed LEB, then we might need to sign-extend. (compile should
+    // optimize this out if not needed).
+    if (std::is_signed<T>::value) {
+      shift += 7;
+      if ((byte & 64) && size_t(shift) < 8 * sizeof(T)) {
+        size_t sext_bits = 8 * sizeof(T) - size_t(shift);
+        value <<= sext_bits;
+        value >>= sext_bits;
+        if (value >= 0) {
+          throw ParseException(
+            " LEBsign-extend should produce a negative value");
+        }
+      }
+    }
+    return *this;
+  }
+};
+
+typedef LEB<uint32_t, uint8_t> U32LEB;
+typedef LEB<uint64_t, uint8_t> U64LEB;
+typedef LEB<int32_t, int8_t> S32LEB;
+typedef LEB<int64_t, int8_t> S64LEB;
+
+//
+// We mostly stream into a buffer as we create the binary format, however,
+// sometimes we need to backtrack and write to a location behind us - wasm
+// is optimized for reading, not writing.
+//
+class BufferWithRandomAccess : public std::vector<uint8_t> {
+public:
+  BufferWithRandomAccess() = default;
+
+  BufferWithRandomAccess& operator<<(int8_t x) {
+    BYN_TRACE("writeInt8: " << (int)(uint8_t)x << " (at " << size() << ")\n");
+    push_back(x);
+    return *this;
+  }
+  BufferWithRandomAccess& operator<<(int16_t x) {
+    BYN_TRACE("writeInt16: " << x << " (at " << size() << ")\n");
+    push_back(x & 0xff);
+    push_back(x >> 8);
+    return *this;
+  }
+  BufferWithRandomAccess& operator<<(int32_t x) {
+    BYN_TRACE("writeInt32: " << x << " (at " << size() << ")\n");
+    push_back(x & 0xff);
+    x >>= 8;
+    push_back(x & 0xff);
+    x >>= 8;
+    push_back(x & 0xff);
+    x >>= 8;
+    push_back(x & 0xff);
+    return *this;
+  }
+  BufferWithRandomAccess& operator<<(int64_t x) {
+    BYN_TRACE("writeInt64: " << x << " (at " << size() << ")\n");
+    push_back(x & 0xff);
+    x >>= 8;
+    push_back(x & 0xff);
+    x >>= 8;
+    push_back(x & 0xff);
+    x >>= 8;
+    push_back(x & 0xff);
+    x >>= 8;
+    push_back(x & 0xff);
+    x >>= 8;
+    push_back(x & 0xff);
+    x >>= 8;
+    push_back(x & 0xff);
+    x >>= 8;
+    push_back(x & 0xff);
+    return *this;
+  }
+  BufferWithRandomAccess& operator<<(U32LEB x) {
+    size_t before = -1;
+    WASM_UNUSED(before);
+    BYN_DEBUG(before = size(); std::cerr << "writeU32LEB: " << x.value
+                                         << " (at " << before << ")"
+                                         << std::endl;);
+    x.write(this);
+    BYN_DEBUG(for (size_t i = before; i < size(); i++) {
+      std::cerr << "  " << (int)at(i) << " (at " << i << ")\n";
+    });
+    return *this;
+  }
+  BufferWithRandomAccess& operator<<(U64LEB x) {
+    size_t before = -1;
+    WASM_UNUSED(before);
+    BYN_DEBUG(before = size(); std::cerr << "writeU64LEB: " << x.value
+                                         << " (at " << before << ")"
+                                         << std::endl;);
+    x.write(this);
+    BYN_DEBUG(for (size_t i = before; i < size(); i++) {
+      std::cerr << "  " << (int)at(i) << " (at " << i << ")\n";
+    });
+    return *this;
+  }
+  BufferWithRandomAccess& operator<<(S32LEB x) {
+    size_t before = -1;
+    WASM_UNUSED(before);
+    BYN_DEBUG(before = size(); std::cerr << "writeS32LEB: " << x.value
+                                         << " (at " << before << ")"
+                                         << std::endl;);
+    x.write(this);
+    BYN_DEBUG(for (size_t i = before; i < size(); i++) {
+      std::cerr << "  " << (int)at(i) << " (at " << i << ")\n";
+    });
+    return *this;
+  }
+  BufferWithRandomAccess& operator<<(S64LEB x) {
+    size_t before = -1;
+    WASM_UNUSED(before);
+    BYN_DEBUG(before = size(); std::cerr << "writeS64LEB: " << x.value
+                                         << " (at " << before << ")"
+                                         << std::endl;);
+    x.write(this);
+    BYN_DEBUG(for (size_t i = before; i < size(); i++) {
+      std::cerr << "  " << (int)at(i) << " (at " << i << ")\n";
+    });
+    return *this;
+  }
+
+  BufferWithRandomAccess& operator<<(uint8_t x) { return *this << (int8_t)x; }
+  BufferWithRandomAccess& operator<<(uint16_t x) { return *this << (int16_t)x; }
+  BufferWithRandomAccess& operator<<(uint32_t x) { return *this << (int32_t)x; }
+  BufferWithRandomAccess& operator<<(uint64_t x) { return *this << (int64_t)x; }
+
+  BufferWithRandomAccess& operator<<(float x) {
+    BYN_TRACE("writeFloat32: " << x << " (at " << size() << ")\n");
+    return *this << Literal(x).reinterpreti32();
+  }
+  BufferWithRandomAccess& operator<<(double x) {
+    BYN_TRACE("writeFloat64: " << x << " (at " << size() << ")\n");
+    return *this << Literal(x).reinterpreti64();
+  }
+
+  void writeAt(size_t i, uint16_t x) {
+    BYN_TRACE("backpatchInt16: " << x << " (at " << i << ")\n");
+    (*this)[i] = x & 0xff;
+    (*this)[i + 1] = x >> 8;
+  }
+  void writeAt(size_t i, uint32_t x) {
+    BYN_TRACE("backpatchInt32: " << x << " (at " << i << ")\n");
+    (*this)[i] = x & 0xff;
+    x >>= 8;
+    (*this)[i + 1] = x & 0xff;
+    x >>= 8;
+    (*this)[i + 2] = x & 0xff;
+    x >>= 8;
+    (*this)[i + 3] = x & 0xff;
+  }
+
+  // writes out an LEB to an arbitrary location. this writes the LEB as a full
+  // 5 bytes, the fixed amount that can easily be set aside ahead of time
+  void writeAtFullFixedSize(size_t i, U32LEB x) {
+    BYN_TRACE("backpatchU32LEB: " << x.value << " (at " << i << ")\n");
+    // fill all 5 bytes, we have to do this when backpatching
+    x.writeAt(this, i, MaxLEB32Bytes);
+  }
+  // writes out an LEB of normal size
+  // returns how many bytes were written
+  size_t writeAt(size_t i, U32LEB x) {
+    BYN_TRACE("writeAtU32LEB: " << x.value << " (at " << i << ")\n");
+    return x.writeAt(this, i);
+  }
+
+  template<typename T> void writeTo(T& o) {
+    for (auto c : *this) {
+      o << c;
+    }
+  }
+
+  std::vector<char> getAsChars() {
+    std::vector<char> ret;
+    ret.resize(size());
+    std::copy(begin(), end(), ret.begin());
+    return ret;
+  }
+};
+
+namespace BinaryConsts {
+
+enum Meta { Magic = 0x6d736100, Version = 0x01 };
+
+enum Section {
+  User = 0,
+  Type = 1,
+  Import = 2,
+  Function = 3,
+  Table = 4,
+  Memory = 5,
+  Global = 6,
+  Export = 7,
+  Start = 8,
+  Element = 9,
+  Code = 10,
+  Data = 11,
+  DataCount = 12,
+  Event = 13
+};
+
+enum SegmentFlag { IsPassive = 0x01, HasMemIndex = 0x02 };
+
+enum EncodedType {
+  // value_type
+  i32 = -0x1,  // 0x7f
+  i64 = -0x2,  // 0x7e
+  f32 = -0x3,  // 0x7d
+  f64 = -0x4,  // 0x7c
+  v128 = -0x5, // 0x7b
+  // function reference type
+  funcref = -0x10, // 0x70
+  // opaque host reference type
+  externref = -0x11, // 0x6f
+  // any reference type
+  anyref = -0x12, // 0x6e
+  // comparable reference type
+  eqref = -0x13, // 0x6d
+  // integer reference type
+  i31ref = -0x16, // 0x6a
+  // exception reference type
+  exnref = -0x18, // 0x68
+  // func_type form
+  Func = -0x20, // 0x60
+  // block_type
+  Empty = -0x40 // 0x40
+};
+
+enum EncodedHeapType {
+  func = -0x10,    // 0x70
+  extern_ = -0x11, // 0x6f
+  any = -0x12,     // 0x6e
+  eq = -0x13,      // 0x6d
+  i31 = -0x17,     // 0x69, != i31ref
+  exn = -0x18,     // 0x68
+};
+
+namespace UserSections {
+extern const char* Name;
+extern const char* SourceMapUrl;
+extern const char* Dylink;
+extern const char* Linking;
+extern const char* Producers;
+extern const char* TargetFeatures;
+
+extern const char* AtomicsFeature;
+extern const char* BulkMemoryFeature;
+extern const char* ExceptionHandlingFeature;
+extern const char* MutableGlobalsFeature;
+extern const char* TruncSatFeature;
+extern const char* SignExtFeature;
+extern const char* SIMD128Feature;
+extern const char* ExceptionHandlingFeature;
+extern const char* TailCallFeature;
+extern const char* ReferenceTypesFeature;
+extern const char* MultivalueFeature;
+extern const char* GCFeature;
+extern const char* Memory64Feature;
+
+enum Subsection {
+  NameModule = 0,
+  NameFunction = 1,
+  NameLocal = 2,
+  // see: https://github.com/WebAssembly/extended-name-section
+  NameLabel = 3,
+  NameType = 4,
+  NameTable = 5,
+  NameMemory = 6,
+  NameGlobal = 7,
+  NameElem = 8,
+  NameData = 9
+};
+
+} // namespace UserSections
+
+enum ASTNodes {
+  Unreachable = 0x00,
+  Nop = 0x01,
+  Block = 0x02,
+  Loop = 0x03,
+  If = 0x04,
+  Else = 0x05,
+
+  End = 0x0b,
+  Br = 0x0c,
+  BrIf = 0x0d,
+  BrTable = 0x0e,
+  Return = 0x0f,
+
+  CallFunction = 0x10,
+  CallIndirect = 0x11,
+  RetCallFunction = 0x12,
+  RetCallIndirect = 0x13,
+
+  Drop = 0x1a,
+  Select = 0x1b,
+  SelectWithType = 0x1c, // added in reference types proposal
+
+  LocalGet = 0x20,
+  LocalSet = 0x21,
+  LocalTee = 0x22,
+  GlobalGet = 0x23,
+  GlobalSet = 0x24,
+
+  I32LoadMem = 0x28,
+  I64LoadMem = 0x29,
+  F32LoadMem = 0x2a,
+  F64LoadMem = 0x2b,
+
+  I32LoadMem8S = 0x2c,
+  I32LoadMem8U = 0x2d,
+  I32LoadMem16S = 0x2e,
+  I32LoadMem16U = 0x2f,
+  I64LoadMem8S = 0x30,
+  I64LoadMem8U = 0x31,
+  I64LoadMem16S = 0x32,
+  I64LoadMem16U = 0x33,
+  I64LoadMem32S = 0x34,
+  I64LoadMem32U = 0x35,
+
+  I32StoreMem = 0x36,
+  I64StoreMem = 0x37,
+  F32StoreMem = 0x38,
+  F64StoreMem = 0x39,
+
+  I32StoreMem8 = 0x3a,
+  I32StoreMem16 = 0x3b,
+  I64StoreMem8 = 0x3c,
+  I64StoreMem16 = 0x3d,
+  I64StoreMem32 = 0x3e,
+
+  MemorySize = 0x3f,
+  MemoryGrow = 0x40,
+
+  I32Const = 0x41,
+  I64Const = 0x42,
+  F32Const = 0x43,
+  F64Const = 0x44,
+
+  I32EqZ = 0x45,
+  I32Eq = 0x46,
+  I32Ne = 0x47,
+  I32LtS = 0x48,
+  I32LtU = 0x49,
+  I32GtS = 0x4a,
+  I32GtU = 0x4b,
+  I32LeS = 0x4c,
+  I32LeU = 0x4d,
+  I32GeS = 0x4e,
+  I32GeU = 0x4f,
+  I64EqZ = 0x50,
+  I64Eq = 0x51,
+  I64Ne = 0x52,
+  I64LtS = 0x53,
+  I64LtU = 0x54,
+  I64GtS = 0x55,
+  I64GtU = 0x56,
+  I64LeS = 0x57,
+  I64LeU = 0x58,
+  I64GeS = 0x59,
+  I64GeU = 0x5a,
+  F32Eq = 0x5b,
+  F32Ne = 0x5c,
+  F32Lt = 0x5d,
+  F32Gt = 0x5e,
+  F32Le = 0x5f,
+  F32Ge = 0x60,
+  F64Eq = 0x61,
+  F64Ne = 0x62,
+  F64Lt = 0x63,
+  F64Gt = 0x64,
+  F64Le = 0x65,
+  F64Ge = 0x66,
+
+  I32Clz = 0x67,
+  I32Ctz = 0x68,
+  I32Popcnt = 0x69,
+  I32Add = 0x6a,
+  I32Sub = 0x6b,
+  I32Mul = 0x6c,
+  I32DivS = 0x6d,
+  I32DivU = 0x6e,
+  I32RemS = 0x6f,
+  I32RemU = 0x70,
+  I32And = 0x71,
+  I32Or = 0x72,
+  I32Xor = 0x73,
+  I32Shl = 0x74,
+  I32ShrS = 0x75,
+  I32ShrU = 0x76,
+  I32RotL = 0x77,
+  I32RotR = 0x78,
+
+  I64Clz = 0x79,
+  I64Ctz = 0x7a,
+  I64Popcnt = 0x7b,
+  I64Add = 0x7c,
+  I64Sub = 0x7d,
+  I64Mul = 0x7e,
+  I64DivS = 0x7f,
+  I64DivU = 0x80,
+  I64RemS = 0x81,
+  I64RemU = 0x82,
+  I64And = 0x83,
+  I64Or = 0x84,
+  I64Xor = 0x85,
+  I64Shl = 0x86,
+  I64ShrS = 0x87,
+  I64ShrU = 0x88,
+  I64RotL = 0x89,
+  I64RotR = 0x8a,
+
+  F32Abs = 0x8b,
+  F32Neg = 0x8c,
+  F32Ceil = 0x8d,
+  F32Floor = 0x8e,
+  F32Trunc = 0x8f,
+  F32NearestInt = 0x90,
+  F32Sqrt = 0x91,
+  F32Add = 0x92,
+  F32Sub = 0x93,
+  F32Mul = 0x94,
+  F32Div = 0x95,
+  F32Min = 0x96,
+  F32Max = 0x97,
+  F32CopySign = 0x98,
+
+  F64Abs = 0x99,
+  F64Neg = 0x9a,
+  F64Ceil = 0x9b,
+  F64Floor = 0x9c,
+  F64Trunc = 0x9d,
+  F64NearestInt = 0x9e,
+  F64Sqrt = 0x9f,
+  F64Add = 0xa0,
+  F64Sub = 0xa1,
+  F64Mul = 0xa2,
+  F64Div = 0xa3,
+  F64Min = 0xa4,
+  F64Max = 0xa5,
+  F64CopySign = 0xa6,
+
+  I32WrapI64 = 0xa7,
+  I32STruncF32 = 0xa8,
+  I32UTruncF32 = 0xa9,
+  I32STruncF64 = 0xaa,
+  I32UTruncF64 = 0xab,
+  I64SExtendI32 = 0xac,
+  I64UExtendI32 = 0xad,
+  I64STruncF32 = 0xae,
+  I64UTruncF32 = 0xaf,
+  I64STruncF64 = 0xb0,
+  I64UTruncF64 = 0xb1,
+  F32SConvertI32 = 0xb2,
+  F32UConvertI32 = 0xb3,
+  F32SConvertI64 = 0xb4,
+  F32UConvertI64 = 0xb5,
+  F32DemoteI64 = 0xb6,
+  F64SConvertI32 = 0xb7,
+  F64UConvertI32 = 0xb8,
+  F64SConvertI64 = 0xb9,
+  F64UConvertI64 = 0xba,
+  F64PromoteF32 = 0xbb,
+
+  I32ReinterpretF32 = 0xbc,
+  I64ReinterpretF64 = 0xbd,
+  F32ReinterpretI32 = 0xbe,
+  F64ReinterpretI64 = 0xbf,
+
+  I32ExtendS8 = 0xc0,
+  I32ExtendS16 = 0xc1,
+  I64ExtendS8 = 0xc2,
+  I64ExtendS16 = 0xc3,
+  I64ExtendS32 = 0xc4,
+
+  // prefixes
+
+  GCPrefix = 0xfb,
+  MiscPrefix = 0xfc,
+  SIMDPrefix = 0xfd,
+  AtomicPrefix = 0xfe,
+
+  // atomic opcodes
+
+  AtomicNotify = 0x00,
+  I32AtomicWait = 0x01,
+  I64AtomicWait = 0x02,
+  AtomicFence = 0x03,
+
+  I32AtomicLoad = 0x10,
+  I64AtomicLoad = 0x11,
+  I32AtomicLoad8U = 0x12,
+  I32AtomicLoad16U = 0x13,
+  I64AtomicLoad8U = 0x14,
+  I64AtomicLoad16U = 0x15,
+  I64AtomicLoad32U = 0x16,
+  I32AtomicStore = 0x17,
+  I64AtomicStore = 0x18,
+  I32AtomicStore8 = 0x19,
+  I32AtomicStore16 = 0x1a,
+  I64AtomicStore8 = 0x1b,
+  I64AtomicStore16 = 0x1c,
+  I64AtomicStore32 = 0x1d,
+
+  AtomicRMWOps_Begin = 0x1e,
+  I32AtomicRMWAdd = 0x1e,
+  I64AtomicRMWAdd = 0x1f,
+  I32AtomicRMWAdd8U = 0x20,
+  I32AtomicRMWAdd16U = 0x21,
+  I64AtomicRMWAdd8U = 0x22,
+  I64AtomicRMWAdd16U = 0x23,
+  I64AtomicRMWAdd32U = 0x24,
+  I32AtomicRMWSub = 0x25,
+  I64AtomicRMWSub = 0x26,
+  I32AtomicRMWSub8U = 0x27,
+  I32AtomicRMWSub16U = 0x28,
+  I64AtomicRMWSub8U = 0x29,
+  I64AtomicRMWSub16U = 0x2a,
+  I64AtomicRMWSub32U = 0x2b,
+  I32AtomicRMWAnd = 0x2c,
+  I64AtomicRMWAnd = 0x2d,
+  I32AtomicRMWAnd8U = 0x2e,
+  I32AtomicRMWAnd16U = 0x2f,
+  I64AtomicRMWAnd8U = 0x30,
+  I64AtomicRMWAnd16U = 0x31,
+  I64AtomicRMWAnd32U = 0x32,
+  I32AtomicRMWOr = 0x33,
+  I64AtomicRMWOr = 0x34,
+  I32AtomicRMWOr8U = 0x35,
+  I32AtomicRMWOr16U = 0x36,
+  I64AtomicRMWOr8U = 0x37,
+  I64AtomicRMWOr16U = 0x38,
+  I64AtomicRMWOr32U = 0x39,
+  I32AtomicRMWXor = 0x3a,
+  I64AtomicRMWXor = 0x3b,
+  I32AtomicRMWXor8U = 0x3c,
+  I32AtomicRMWXor16U = 0x3d,
+  I64AtomicRMWXor8U = 0x3e,
+  I64AtomicRMWXor16U = 0x3f,
+  I64AtomicRMWXor32U = 0x40,
+  I32AtomicRMWXchg = 0x41,
+  I64AtomicRMWXchg = 0x42,
+  I32AtomicRMWXchg8U = 0x43,
+  I32AtomicRMWXchg16U = 0x44,
+  I64AtomicRMWXchg8U = 0x45,
+  I64AtomicRMWXchg16U = 0x46,
+  I64AtomicRMWXchg32U = 0x47,
+  AtomicRMWOps_End = 0x47,
+
+  AtomicCmpxchgOps_Begin = 0x48,
+  I32AtomicCmpxchg = 0x48,
+  I64AtomicCmpxchg = 0x49,
+  I32AtomicCmpxchg8U = 0x4a,
+  I32AtomicCmpxchg16U = 0x4b,
+  I64AtomicCmpxchg8U = 0x4c,
+  I64AtomicCmpxchg16U = 0x4d,
+  I64AtomicCmpxchg32U = 0x4e,
+  AtomicCmpxchgOps_End = 0x4e,
+
+  // truncsat opcodes
+
+  I32STruncSatF32 = 0x00,
+  I32UTruncSatF32 = 0x01,
+  I32STruncSatF64 = 0x02,
+  I32UTruncSatF64 = 0x03,
+  I64STruncSatF32 = 0x04,
+  I64UTruncSatF32 = 0x05,
+  I64STruncSatF64 = 0x06,
+  I64UTruncSatF64 = 0x07,
+
+  // SIMD opcodes
+
+  V128Load = 0x00,
+  I16x8LoadExtSVec8x8 = 0x01,
+  I16x8LoadExtUVec8x8 = 0x02,
+  I32x4LoadExtSVec16x4 = 0x03,
+  I32x4LoadExtUVec16x4 = 0x04,
+  I64x2LoadExtSVec32x2 = 0x05,
+  I64x2LoadExtUVec32x2 = 0x06,
+  V8x16LoadSplat = 0x07,
+  V16x8LoadSplat = 0x08,
+  V32x4LoadSplat = 0x09,
+  V64x2LoadSplat = 0x0a,
+  V128Store = 0x0b,
+
+  V128Const = 0x0c,
+  V8x16Shuffle = 0x0d,
+  V8x16Swizzle = 0x0e,
+
+  I8x16Splat = 0x0f,
+  I16x8Splat = 0x10,
+  I32x4Splat = 0x11,
+  I64x2Splat = 0x12,
+  F32x4Splat = 0x13,
+  F64x2Splat = 0x14,
+
+  I8x16ExtractLaneS = 0x15,
+  I8x16ExtractLaneU = 0x16,
+  I8x16ReplaceLane = 0x17,
+  I16x8ExtractLaneS = 0x18,
+  I16x8ExtractLaneU = 0x19,
+  I16x8ReplaceLane = 0x1a,
+  I32x4ExtractLane = 0x1b,
+  I32x4ReplaceLane = 0x1c,
+  I64x2ExtractLane = 0x1d,
+  I64x2ReplaceLane = 0x1e,
+  F32x4ExtractLane = 0x1f,
+  F32x4ReplaceLane = 0x20,
+  F64x2ExtractLane = 0x21,
+  F64x2ReplaceLane = 0x22,
+
+  I8x16Eq = 0x23,
+  I8x16Ne = 0x24,
+  I8x16LtS = 0x25,
+  I8x16LtU = 0x26,
+  I8x16GtS = 0x27,
+  I8x16GtU = 0x28,
+  I8x16LeS = 0x29,
+  I8x16LeU = 0x2a,
+  I8x16GeS = 0x2b,
+  I8x16GeU = 0x2c,
+  I16x8Eq = 0x2d,
+  I16x8Ne = 0x2e,
+  I16x8LtS = 0x2f,
+  I16x8LtU = 0x30,
+  I16x8GtS = 0x31,
+  I16x8GtU = 0x32,
+  I16x8LeS = 0x33,
+  I16x8LeU = 0x34,
+  I16x8GeS = 0x35,
+  I16x8GeU = 0x36,
+  I32x4Eq = 0x37,
+  I32x4Ne = 0x38,
+  I32x4LtS = 0x39,
+  I32x4LtU = 0x3a,
+  I32x4GtS = 0x3b,
+  I32x4GtU = 0x3c,
+  I32x4LeS = 0x3d,
+  I32x4LeU = 0x3e,
+  I32x4GeS = 0x3f,
+  I32x4GeU = 0x40,
+  F32x4Eq = 0x41,
+  F32x4Ne = 0x42,
+  F32x4Lt = 0x43,
+  F32x4Gt = 0x44,
+  F32x4Le = 0x45,
+  F32x4Ge = 0x46,
+  F64x2Eq = 0x47,
+  F64x2Ne = 0x48,
+  F64x2Lt = 0x49,
+  F64x2Gt = 0x4a,
+  F64x2Le = 0x4b,
+  F64x2Ge = 0x4c,
+
+  V128Not = 0x4d,
+  V128And = 0x4e,
+  V128AndNot = 0x4f,
+  V128Or = 0x50,
+  V128Xor = 0x51,
+  V128Bitselect = 0x52,
+
+  I8x16Abs = 0x60,
+  I8x16Neg = 0x61,
+  I8x16AnyTrue = 0x62,
+  I8x16AllTrue = 0x63,
+  I8x16Bitmask = 0x64,
+  I8x16NarrowSI16x8 = 0x65,
+  I8x16NarrowUI16x8 = 0x66,
+  I8x16Shl = 0x6b,
+  I8x16ShrS = 0x6c,
+  I8x16ShrU = 0x6d,
+  I8x16Add = 0x6e,
+  I8x16AddSatS = 0x6f,
+  I8x16AddSatU = 0x70,
+  I8x16Sub = 0x71,
+  I8x16SubSatS = 0x72,
+  I8x16SubSatU = 0x73,
+  I8x16Mul = 0x75,
+  I8x16MinS = 0x76,
+  I8x16MinU = 0x77,
+  I8x16MaxS = 0x78,
+  I8x16MaxU = 0x79,
+  I8x16AvgrU = 0x7b,
+
+  I16x8Abs = 0x80,
+  I16x8Neg = 0x81,
+  I16x8AnyTrue = 0x82,
+  I16x8AllTrue = 0x83,
+  I16x8Bitmask = 0x84,
+  I16x8NarrowSI32x4 = 0x85,
+  I16x8NarrowUI32x4 = 0x86,
+  I16x8WidenLowSI8x16 = 0x87,
+  I16x8WidenHighSI8x16 = 0x88,
+  I16x8WidenLowUI8x16 = 0x89,
+  I16x8WidenHighUI8x16 = 0x8a,
+  I16x8Shl = 0x8b,
+  I16x8ShrS = 0x8c,
+  I16x8ShrU = 0x8d,
+  I16x8Add = 0x8e,
+  I16x8AddSatS = 0x8f,
+  I16x8AddSatU = 0x90,
+  I16x8Sub = 0x91,
+  I16x8SubSatS = 0x92,
+  I16x8SubSatU = 0x93,
+  I16x8Mul = 0x95,
+  I16x8MinS = 0x96,
+  I16x8MinU = 0x97,
+  I16x8MaxS = 0x98,
+  I16x8MaxU = 0x99,
+  I16x8AvgrU = 0x9b,
+
+  I32x4Abs = 0xa0,
+  I32x4Neg = 0xa1,
+  I32x4AnyTrue = 0xa2,
+  I32x4AllTrue = 0xa3,
+  I32x4Bitmask = 0xa4,
+  I32x4WidenLowSI16x8 = 0xa7,
+  I32x4WidenHighSI16x8 = 0xa8,
+  I32x4WidenLowUI16x8 = 0xa9,
+  I32x4WidenHighUI16x8 = 0xaa,
+  I32x4Shl = 0xab,
+  I32x4ShrS = 0xac,
+  I32x4ShrU = 0xad,
+  I32x4Add = 0xae,
+  I32x4Sub = 0xb1,
+  I32x4Mul = 0xb5,
+  I32x4MinS = 0xb6,
+  I32x4MinU = 0xb7,
+  I32x4MaxS = 0xb8,
+  I32x4MaxU = 0xb9,
+  I32x4DotSVecI16x8 = 0xba,
+
+  I64x2Neg = 0xc1,
+  I64x2AnyTrue = 0xc2,
+  I64x2AllTrue = 0xc3,
+  I64x2Shl = 0xcb,
+  I64x2ShrS = 0xcc,
+  I64x2ShrU = 0xcd,
+  I64x2Add = 0xce,
+  I64x2Sub = 0xd1,
+  I64x2Mul = 0xd5,
+
+  F32x4Abs = 0xe0,
+  F32x4Neg = 0xe1,
+  F32x4Sqrt = 0xe3,
+  F32x4Add = 0xe4,
+  F32x4Sub = 0xe5,
+  F32x4Mul = 0xe6,
+  F32x4Div = 0xe7,
+  F32x4Min = 0xe8,
+  F32x4Max = 0xe9,
+  F32x4PMin = 0xea,
+  F32x4PMax = 0xeb,
+
+  F32x4Ceil = 0xd8,
+  F32x4Floor = 0xd9,
+  F32x4Trunc = 0xda,
+  F32x4Nearest = 0xdb,
+  F64x2Ceil = 0xdc,
+  F64x2Floor = 0xdd,
+  F64x2Trunc = 0xde,
+  F64x2Nearest = 0xdf,
+
+  F64x2Abs = 0xec,
+  F64x2Neg = 0xed,
+  F64x2Sqrt = 0xef,
+  F64x2Add = 0xf0,
+  F64x2Sub = 0xf1,
+  F64x2Mul = 0xf2,
+  F64x2Div = 0xf3,
+  F64x2Min = 0xf4,
+  F64x2Max = 0xf5,
+  F64x2PMin = 0xf6,
+  F64x2PMax = 0xf7,
+
+  I32x4TruncSatSF32x4 = 0xf8,
+  I32x4TruncSatUF32x4 = 0xf9,
+  F32x4ConvertSI32x4 = 0xfa,
+  F32x4ConvertUI32x4 = 0xfb,
+
+  V128Load32Zero = 0xfc,
+  V128Load64Zero = 0xfd,
+
+  F32x4QFMA = 0xb4,
+  F32x4QFMS = 0xd4,
+  F64x2QFMA = 0xfe,
+  F64x2QFMS = 0xff,
+
+  I64x2TruncSatSF64x2 = 0x0100,
+  I64x2TruncSatUF64x2 = 0x0101,
+  F64x2ConvertSI64x2 = 0x0102,
+  F64x2ConvertUI64x2 = 0x0103,
+
+  // bulk memory opcodes
+
+  MemoryInit = 0x08,
+  DataDrop = 0x09,
+  MemoryCopy = 0x0a,
+  MemoryFill = 0x0b,
+
+  // reference types opcodes
+
+  RefNull = 0xd0,
+  RefIsNull = 0xd1,
+  RefFunc = 0xd2,
+
+  // exception handling opcodes
+
+  Try = 0x06,
+  Catch = 0x07,
+  Throw = 0x08,
+  Rethrow = 0x09,
+  BrOnExn = 0x0a,
+
+  // gc opcodes
+
+  RefEq = 0xd5,
+  StructNewWithRtt = 0x01,
+  StructNewDefaultWithRtt = 0x02,
+  StructGet = 0x03,
+  StructGetS = 0x04,
+  StructGetU = 0x05,
+  StructSet = 0x06,
+  ArrayNewWithRtt = 0x11,
+  ArrayNewDefaultWithRtt = 0x12,
+  ArrayGet = 0x13,
+  ArrayGetS = 0x14,
+  ArrayGetU = 0x15,
+  ArraySet = 0x16,
+  ArrayLen = 0x17,
+  I31New = 0x20,
+  I31GetS = 0x21,
+  I31GetU = 0x22,
+  RttCanon = 0x30,
+  RttSub = 0x31,
+  RefTest = 0x40,
+  RefCast = 0x41,
+  BrOnCast = 0x42
+};
+
+enum MemoryAccess {
+  Offset = 0x10,    // bit 4
+  Alignment = 0x80, // bit 7
+  NaturalAlignment = 0
+};
+
+enum MemoryFlags { HasMaximum = 1 << 0, IsShared = 1 << 1, Is64 = 1 << 2 };
+
+enum FeaturePrefix {
+  FeatureUsed = '+',
+  FeatureRequired = '=',
+  FeatureDisallowed = '-'
+};
+
+} // 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 {
+  // Computes the indexes in a wasm binary, i.e., with function imports
+  // and function implementations sharing a single index space, etc.,
+  // and with the imports first (the Module's functions and globals
+  // arrays are not assumed to be in a particular order, so we can't
+  // just use them directly).
+  struct BinaryIndexes {
+    std::unordered_map<Name, Index> functionIndexes;
+    std::unordered_map<Name, Index> eventIndexes;
+    std::unordered_map<Name, Index> globalIndexes;
+
+    BinaryIndexes(Module& wasm) {
+      auto addIndexes = [&](auto& source, auto& indexes) {
+        auto addIndex = [&](auto* curr) {
+          auto index = indexes.size();
+          indexes[curr->name] = index;
+        };
+        for (auto& curr : source) {
+          if (curr->imported()) {
+            addIndex(curr.get());
+          }
+        }
+        for (auto& curr : source) {
+          if (!curr->imported()) {
+            addIndex(curr.get());
+          }
+        }
+      };
+      addIndexes(wasm.functions, functionIndexes);
+      addIndexes(wasm.events, eventIndexes);
+
+      // Globals may have tuple types in the IR, in which case they lower to
+      // multiple globals, one for each tuple element, in the binary. Tuple
+      // globals therefore occupy multiple binary indices, and we have to take
+      // that into account when calculating indices.
+      Index globalCount = 0;
+      auto addGlobal = [&](auto* curr) {
+        globalIndexes[curr->name] = globalCount;
+        globalCount += curr->type.size();
+      };
+      for (auto& curr : wasm.globals) {
+        if (curr->imported()) {
+          addGlobal(curr.get());
+        }
+      }
+      for (auto& curr : wasm.globals) {
+        if (!curr->imported()) {
+          addGlobal(curr.get());
+        }
+      }
+    }
+  };
+
+public:
+  WasmBinaryWriter(Module* input, BufferWithRandomAccess& o)
+    : wasm(input), o(o), indexes(*input) {
+    prepare();
+  }
+
+  // locations in the output binary for the various parts of the module
+  struct TableOfContents {
+    struct Entry {
+      Name name;
+      size_t offset; // where the entry starts
+      size_t size;   // the size of the entry
+      Entry(Name name, size_t offset, size_t size)
+        : name(name), offset(offset), size(size) {}
+    };
+    std::vector<Entry> functionBodies;
+  } tableOfContents;
+
+  void setNamesSection(bool set) { debugInfo = set; }
+  void setSourceMap(std::ostream* set, std::string url) {
+    sourceMap = set;
+    sourceMapUrl = url;
+  }
+  void setSymbolMap(std::string set) { symbolMap = set; }
+
+  void write();
+  void writeHeader();
+  int32_t writeU32LEBPlaceholder();
+  void writeResizableLimits(
+    Address initial, Address maximum, bool hasMaximum, bool shared, bool is64);
+  template<typename T> int32_t startSection(T code);
+  void finishSection(int32_t start);
+  int32_t startSubsection(BinaryConsts::UserSections::Subsection code);
+  void finishSubsection(int32_t start);
+  void writeStart();
+  void writeMemory();
+  void writeTypes();
+  void writeImports();
+
+  void writeFunctionSignatures();
+  void writeExpression(Expression* curr);
+  void writeFunctions();
+  void writeGlobals();
+  void writeExports();
+  void writeDataCount();
+  void writeDataSegments();
+  void writeEvents();
+
+  uint32_t getFunctionIndex(Name name) const;
+  uint32_t getGlobalIndex(Name name) const;
+  uint32_t getEventIndex(Name name) const;
+  uint32_t getTypeIndex(Signature sig) const;
+
+  void writeFunctionTableDeclaration();
+  void writeTableElements();
+  void writeNames();
+  void writeSourceMapUrl();
+  void writeSymbolMap();
+  void writeLateUserSections();
+  void writeUserSection(const UserSection& section);
+  void writeFeaturesSection();
+  void writeDylinkSection();
+
+  void initializeDebugInfo();
+  void writeSourceMapProlog();
+  void writeSourceMapEpilog();
+  void writeDebugLocation(const Function::DebugLocation& loc);
+  void writeDebugLocation(Expression* curr, Function* func);
+  void writeDebugLocationEnd(Expression* curr, Function* func);
+  void writeExtraDebugLocation(Expression* curr,
+                               Function* func,
+                               BinaryLocations::DelimiterId id);
+
+  // helpers
+  void writeInlineString(const char* name);
+  void writeEscapedName(const char* name);
+  void writeInlineBuffer(const char* data, size_t size);
+
+  struct Buffer {
+    const char* data;
+    size_t size;
+    size_t pointerLocation;
+    Buffer(const char* data, size_t size, size_t pointerLocation)
+      : data(data), size(size), pointerLocation(pointerLocation) {}
+  };
+
+  std::vector<Buffer> buffersToWrite;
+
+  void emitBuffer(const char* data, size_t size);
+  void emitString(const char* str);
+  void finishUp();
+
+  Module* getModule() { return wasm; }
+
+private:
+  Module* wasm;
+  BufferWithRandomAccess& o;
+  BinaryIndexes indexes;
+  std::unordered_map<Signature, Index> typeIndices;
+  std::vector<Signature> types;
+
+  bool debugInfo = true;
+  std::ostream* sourceMap = nullptr;
+  std::string sourceMapUrl;
+  std::string symbolMap;
+
+  MixedArena allocator;
+
+  // storage of source map locations until the section is placed at its final
+  // location (shrinking LEBs may cause changes there)
+  std::vector<std::pair<size_t, const Function::DebugLocation*>>
+    sourceMapLocations;
+  size_t sourceMapLocationsSizeAtSectionStart;
+  Function::DebugLocation lastDebugLocation;
+
+  std::unique_ptr<ImportInfo> importInfo;
+
+  // General debugging info: track locations as we write.
+  BinaryLocations binaryLocations;
+  size_t binaryLocationsSizeAtSectionStart;
+  // Track the expressions that we added for the current function being
+  // written, so that we can update those specific binary locations when
+  // the function is written out.
+  std::vector<Expression*> binaryLocationTrackedExpressionsForFunc;
+
+  void prepare();
+};
+
+class WasmBinaryBuilder {
+  Module& wasm;
+  MixedArena& allocator;
+  const std::vector<char>& input;
+  std::istream* sourceMap;
+  std::pair<uint32_t, Function::DebugLocation> nextDebugLocation;
+  bool DWARF = false;
+
+  size_t pos = 0;
+  Index startIndex = -1;
+  std::set<Function::DebugLocation> debugLocation;
+  size_t codeSectionLocation;
+
+  std::set<BinaryConsts::Section> seenSections;
+
+  // All signatures present in the type section
+  std::vector<Signature> signatures;
+
+public:
+  WasmBinaryBuilder(Module& wasm, const std::vector<char>& input)
+    : wasm(wasm), allocator(wasm.allocator), input(input), sourceMap(nullptr),
+      nextDebugLocation(0, {0, 0, 0}), debugLocation() {}
+
+  void setDWARF(bool value) { DWARF = value; }
+  void read();
+  void readUserSection(size_t payloadLen);
+
+  bool more() { return pos < input.size(); }
+
+  uint8_t getInt8();
+  uint16_t getInt16();
+  uint32_t getInt32();
+  uint64_t getInt64();
+  uint8_t getLaneIndex(size_t lanes);
+  // it is unsafe to return a float directly, due to ABI issues with the
+  // signalling bit
+  Literal getFloat32Literal();
+  Literal getFloat64Literal();
+  Literal getVec128Literal();
+  uint32_t getU32LEB();
+  uint64_t getU64LEB();
+  int32_t getS32LEB();
+  int64_t getS64LEB();
+  Type getType();
+  HeapType getHeapType();
+  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();
+
+  // gets a name in the combined import+defined space
+  Name getFunctionName(Index index);
+  Name getGlobalName(Index index);
+  Name getEventName(Index index);
+
+  void getResizableLimits(Address& initial,
+                          Address& max,
+                          bool& shared,
+                          Type& indexType,
+                          Address defaultIfNoMax);
+  void readImports();
+
+  // The signatures of each function, given in the function section
+  std::vector<Signature> functionSignatures;
+
+  void readFunctionSignatures();
+  size_t nextLabel;
+
+  Name getNextLabel();
+
+  // We read functions and globals before we know their names, so we need to
+  // backpatch the names later
+
+  // we store functions here before wasm.addFunction after we know their names
+  std::vector<Function*> functions;
+  // we store function imports here before wasm.addFunctionImport after we know
+  // their names
+  std::vector<Function*> functionImports;
+  // at index i we have all refs to the function i
+  std::map<Index, std::vector<Expression*>> functionRefs;
+  Function* currFunction = nullptr;
+  // before we see a function (like global init expressions), there is no end of
+  // function to check
+  Index endOfFunction = -1;
+
+  // we store globals here before wasm.addGlobal after we know their names
+  std::vector<Global*> globals;
+  // we store global imports here before wasm.addGlobalImport after we know
+  // their names
+  std::vector<Global*> globalImports;
+  // at index i we have all refs to the global i
+  std::map<Index, std::vector<Expression*>> globalRefs;
+
+  // Throws a parsing error if we are not in a function context
+  void requireFunctionContext(const char* error);
+
+  void readFunctions();
+
+  std::map<Export*, Index> exportIndices;
+  std::vector<Export*> exportOrder;
+  void readExports();
+
+  Expression* readExpression();
+  void readGlobals();
+
+  struct BreakTarget {
+    Name name;
+    Type type;
+    BreakTarget(Name name, Type type) : name(name), type(type) {}
+  };
+  std::vector<BreakTarget> breakStack;
+  // the names that breaks target. this lets us know if a block has breaks to it
+  // or not.
+  std::unordered_set<Name> breakTargetNames;
+
+  std::vector<Expression*> expressionStack;
+
+  // Control flow structure parsing: these have not just the normal binary
+  // data for an instruction, but also some bytes later on like "end" or "else".
+  // We must be aware of the connection between those things, for debug info.
+  std::vector<Expression*> controlFlowStack;
+
+  // Called when we parse the beginning of a control flow structure.
+  void startControlFlow(Expression* curr);
+
+  // Called when we parse a later part of a control flow structure, like "end"
+  // or "else".
+  void continueControlFlow(BinaryLocations::DelimiterId id, BinaryLocation pos);
+
+  // set when we know code is unreachable in the sense of the wasm spec: we are
+  // in a block and after an unreachable element. this helps parse stacky wasm
+  // code, which can be unsuitable for our IR when unreachable.
+  bool unreachableInTheWasmSense;
+
+  // set when the current code being processed will not be emitted in the
+  // output, which is the case when it is literally unreachable, for example,
+  // (block $a
+  //   (unreachable)
+  //   (block $b
+  //     ;; code here is reachable in the wasm sense, even though $b as a whole
+  //     ;; is not
+  //     (unreachable)
+  //     ;; code here is unreachable in the wasm sense
+  //   )
+  // )
+  bool willBeIgnored;
+
+  BinaryConsts::ASTNodes lastSeparator = BinaryConsts::End;
+
+  // process a block-type scope, until an end or else marker, or the end of the
+  // function
+  void processExpressions();
+  void skipUnreachableCode();
+
+  void pushExpression(Expression* curr);
+  Expression* popExpression();
+  Expression* popNonVoidExpression();
+  Expression* popTuple(size_t numElems);
+  Expression* popTypedExpression(Type type);
+
+  void validateBinary(); // validations that cannot be performed on the Module
+  void processNames();
+
+  size_t dataCount = 0;
+  bool hasDataCount = false;
+
+  void readDataSegments();
+  void readDataCount();
+
+  std::map<Index, std::vector<Index>> functionTable;
+
+  void readFunctionTableDeclaration();
+  void readTableElements();
+
+  void readEvents();
+
+  static Name escape(Name name);
+  void readNames(size_t);
+  void readFeatures(size_t);
+  void readDylink(size_t);
+
+  // Debug information reading helpers
+  void setDebugLocations(std::istream* sourceMap_) { sourceMap = sourceMap_; }
+  std::unordered_map<std::string, Index> debugInfoFileIndices;
+  void readNextDebugLocation();
+  void readSourceMapHeader();
+
+  void handleBrOnExnNotTaken(Expression* curr);
+
+  // AST reading
+  int depth = 0; // only for debugging
+
+  BinaryConsts::ASTNodes readExpression(Expression*& curr);
+  void pushBlockElements(Block* curr, Type type, size_t start);
+  void visitBlock(Block* curr);
+
+  // Gets a block of expressions. If it's just one, return that singleton.
+  Expression* getBlockOrSingleton(Type type);
+
+  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);
+  bool maybeVisitAtomicRMW(Expression*& out, uint8_t code);
+  bool maybeVisitAtomicCmpxchg(Expression*& out, uint8_t code);
+  bool maybeVisitAtomicWait(Expression*& out, uint8_t code);
+  bool maybeVisitAtomicNotify(Expression*& out, uint8_t code);
+  bool maybeVisitAtomicFence(Expression*& out, uint8_t code);
+  bool maybeVisitConst(Expression*& out, uint8_t code);
+  bool maybeVisitUnary(Expression*& out, uint8_t code);
+  bool maybeVisitBinary(Expression*& out, uint8_t code);
+  bool maybeVisitTruncSat(Expression*& out, uint32_t code);
+  bool maybeVisitSIMDBinary(Expression*& out, uint32_t code);
+  bool maybeVisitSIMDUnary(Expression*& out, uint32_t code);
+  bool maybeVisitSIMDConst(Expression*& out, uint32_t code);
+  bool maybeVisitSIMDStore(Expression*& out, uint32_t code);
+  bool maybeVisitSIMDExtract(Expression*& out, uint32_t code);
+  bool maybeVisitSIMDReplace(Expression*& out, uint32_t code);
+  bool maybeVisitSIMDShuffle(Expression*& out, uint32_t code);
+  bool maybeVisitSIMDTernary(Expression*& out, uint32_t code);
+  bool maybeVisitSIMDShift(Expression*& out, uint32_t code);
+  bool maybeVisitSIMDLoad(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);
+  bool maybeVisitMemoryFill(Expression*& out, uint32_t code);
+  bool maybeVisitI31New(Expression*& out, uint32_t code);
+  bool maybeVisitI31Get(Expression*& out, uint32_t code);
+  bool maybeVisitRefTest(Expression*& out, uint32_t code);
+  bool maybeVisitRefCast(Expression*& out, uint32_t code);
+  bool maybeVisitBrOnCast(Expression*& out, uint32_t code);
+  bool maybeVisitRttCanon(Expression*& out, uint32_t code);
+  bool maybeVisitRttSub(Expression*& out, uint32_t code);
+  bool maybeVisitStructNew(Expression*& out, uint32_t code);
+  bool maybeVisitStructGet(Expression*& out, uint32_t code);
+  bool maybeVisitStructSet(Expression*& out, uint32_t code);
+  bool maybeVisitArrayNew(Expression*& out, uint32_t code);
+  bool maybeVisitArrayGet(Expression*& out, uint32_t code);
+  bool maybeVisitArraySet(Expression*& out, uint32_t code);
+  bool maybeVisitArrayLen(Expression*& out, uint32_t code);
+  void visitSelect(Select* curr, uint8_t code);
+  void visitReturn(Return* curr);
+  void visitMemorySize(MemorySize* curr);
+  void visitMemoryGrow(MemoryGrow* curr);
+  void visitNop(Nop* curr);
+  void visitUnreachable(Unreachable* curr);
+  void visitDrop(Drop* curr);
+  void visitRefNull(RefNull* curr);
+  void visitRefIsNull(RefIsNull* curr);
+  void visitRefFunc(RefFunc* curr);
+  void visitRefEq(RefEq* curr);
+  void visitTryOrTryInBlock(Expression*& out);
+  void visitThrow(Throw* curr);
+  void visitRethrow(Rethrow* curr);
+  void visitBrOnExn(BrOnExn* curr);
+
+  void throwError(std::string text);
+
+private:
+  bool hasDWARFSections();
+};
+
+} // namespace wasm
+
+#undef DEBUG_TYPE
+
+#endif // wasm_wasm_binary_h
diff --git a/binaryen/src/wasm-builder.h b/binaryen/src/wasm-builder.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-builder.h
@@ -0,0 +1,972 @@
+/*
+ * 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_builder_h
+#define wasm_wasm_builder_h
+
+#include "ir/manipulation.h"
+#include "wasm.h"
+
+namespace wasm {
+
+// Useful data structures
+
+struct NameType {
+  Name name;
+  Type type;
+  NameType() : name(nullptr), type(Type::none) {}
+  NameType(Name name, Type type) : name(name), type(type) {}
+};
+
+// General AST node builder
+
+class Builder {
+  Module& wasm;
+
+public:
+  Builder(Module& wasm) : wasm(wasm) {}
+
+  // make* functions, other globals
+
+  Function* makeFunction(Name name,
+                         Signature sig,
+                         std::vector<Type>&& vars,
+                         Expression* body = nullptr) {
+    auto* func = new Function;
+    func->name = name;
+    func->sig = sig;
+    func->body = body;
+    func->vars.swap(vars);
+    return func;
+  }
+
+  Function* makeFunction(Name name,
+                         std::vector<NameType>&& params,
+                         Type resultType,
+                         std::vector<NameType>&& vars,
+                         Expression* body = nullptr) {
+    auto* func = new Function;
+    func->name = name;
+    func->body = body;
+    std::vector<Type> paramVec;
+    for (auto& param : params) {
+      paramVec.push_back(param.type);
+      Index index = func->localNames.size();
+      func->localIndices[param.name] = index;
+      func->localNames[index] = param.name;
+    }
+    func->sig = Signature(Type(paramVec), resultType);
+    for (auto& var : vars) {
+      func->vars.push_back(var.type);
+      Index index = func->localNames.size();
+      func->localIndices[var.name] = index;
+      func->localNames[index] = var.name;
+    }
+    return func;
+  }
+
+  Export* makeExport(Name name, Name value, ExternalKind kind) {
+    auto* export_ = new Export();
+    export_->name = name;
+    export_->value = value;
+    export_->kind = kind;
+    return export_;
+  }
+
+  // IR nodes
+
+  Nop* makeNop() { return wasm.allocator.alloc<Nop>(); }
+  Block* makeBlock(Expression* first = nullptr) {
+    auto* ret = wasm.allocator.alloc<Block>();
+    if (first) {
+      ret->list.push_back(first);
+      ret->finalize();
+    }
+    return ret;
+  }
+  Block* makeBlock(Name name, Expression* first = nullptr) {
+    auto* ret = makeBlock(first);
+    ret->name = name;
+    ret->finalize();
+    return ret;
+  }
+  Block* makeBlock(const std::vector<Expression*>& items) {
+    auto* ret = wasm.allocator.alloc<Block>();
+    ret->list.set(items);
+    ret->finalize();
+    return ret;
+  }
+  Block* makeBlock(const std::vector<Expression*>& items, Type type) {
+    auto* ret = wasm.allocator.alloc<Block>();
+    ret->list.set(items);
+    ret->finalize(type);
+    return ret;
+  }
+  Block* makeBlock(const ExpressionList& items) {
+    auto* ret = wasm.allocator.alloc<Block>();
+    ret->list.set(items);
+    ret->finalize();
+    return ret;
+  }
+  Block* makeBlock(const ExpressionList& items, Type type) {
+    auto* ret = wasm.allocator.alloc<Block>();
+    ret->list.set(items);
+    ret->finalize(type);
+    return ret;
+  }
+  Block* makeBlock(Name name, const ExpressionList& items) {
+    auto* ret = wasm.allocator.alloc<Block>();
+    ret->name = name;
+    ret->list.set(items);
+    ret->finalize();
+    return ret;
+  }
+  Block* makeBlock(Name name, const ExpressionList& items, Type type) {
+    auto* ret = wasm.allocator.alloc<Block>();
+    ret->name = name;
+    ret->list.set(items);
+    ret->finalize(type);
+    return ret;
+  }
+  If* makeIf(Expression* condition,
+             Expression* ifTrue,
+             Expression* ifFalse = nullptr) {
+    auto* ret = wasm.allocator.alloc<If>();
+    ret->condition = condition;
+    ret->ifTrue = ifTrue;
+    ret->ifFalse = ifFalse;
+    ret->finalize();
+    return ret;
+  }
+  If* makeIf(Expression* condition,
+             Expression* ifTrue,
+             Expression* ifFalse,
+             Type type) {
+    auto* ret = wasm.allocator.alloc<If>();
+    ret->condition = condition;
+    ret->ifTrue = ifTrue;
+    ret->ifFalse = ifFalse;
+    ret->finalize(type);
+    return ret;
+  }
+  Loop* makeLoop(Name name, Expression* body) {
+    auto* ret = wasm.allocator.alloc<Loop>();
+    ret->name = name;
+    ret->body = body;
+    ret->finalize();
+    return ret;
+  }
+  Loop* makeLoop(Name name, Expression* body, Type type) {
+    auto* ret = wasm.allocator.alloc<Loop>();
+    ret->name = name;
+    ret->body = body;
+    ret->finalize(type);
+    return ret;
+  }
+  Break* makeBreak(Name name,
+                   Expression* value = nullptr,
+                   Expression* condition = nullptr) {
+    auto* ret = wasm.allocator.alloc<Break>();
+    ret->name = name;
+    ret->value = value;
+    ret->condition = condition;
+    ret->finalize();
+    return ret;
+  }
+  template<typename T>
+  Switch* makeSwitch(T& list,
+                     Name default_,
+                     Expression* condition,
+                     Expression* value = nullptr) {
+    auto* ret = wasm.allocator.alloc<Switch>();
+    ret->targets.set(list);
+    ret->default_ = default_;
+    ret->value = value;
+    ret->condition = condition;
+    return ret;
+  }
+  Call* makeCall(Name target,
+                 const std::vector<Expression*>& args,
+                 Type type,
+                 bool isReturn = false) {
+    auto* call = wasm.allocator.alloc<Call>();
+    // not all functions may exist yet, so type must be provided
+    call->type = type;
+    call->target = target;
+    call->operands.set(args);
+    call->isReturn = isReturn;
+    return call;
+  }
+  template<typename T>
+  Call* makeCall(Name target, const T& args, Type type, bool isReturn = false) {
+    auto* call = wasm.allocator.alloc<Call>();
+    // not all functions may exist yet, so type must be provided
+    call->type = type;
+    call->target = target;
+    call->operands.set(args);
+    call->isReturn = isReturn;
+    call->finalize();
+    return call;
+  }
+  CallIndirect* makeCallIndirect(Expression* target,
+                                 const std::vector<Expression*>& args,
+                                 Signature sig,
+                                 bool isReturn = false) {
+    auto* call = wasm.allocator.alloc<CallIndirect>();
+    call->sig = sig;
+    call->type = sig.results;
+    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;
+    ret->type = type;
+    return ret;
+  }
+  LocalSet* makeLocalSet(Index index, Expression* value) {
+    auto* ret = wasm.allocator.alloc<LocalSet>();
+    ret->index = index;
+    ret->value = value;
+    ret->makeSet();
+    ret->finalize();
+    return ret;
+  }
+  LocalSet* makeLocalTee(Index index, Expression* value, Type type) {
+    auto* ret = wasm.allocator.alloc<LocalSet>();
+    ret->index = index;
+    ret->value = value;
+    ret->makeTee(type);
+    return ret;
+  }
+  GlobalGet* makeGlobalGet(Name name, Type type) {
+    auto* ret = wasm.allocator.alloc<GlobalGet>();
+    ret->name = name;
+    ret->type = type;
+    return ret;
+  }
+  GlobalSet* makeGlobalSet(Name name, Expression* value) {
+    auto* ret = wasm.allocator.alloc<GlobalSet>();
+    ret->name = name;
+    ret->value = value;
+    ret->finalize();
+    return ret;
+  }
+  Load* makeLoad(unsigned bytes,
+                 bool signed_,
+                 uint32_t offset,
+                 unsigned align,
+                 Expression* ptr,
+                 Type type) {
+    auto* ret = wasm.allocator.alloc<Load>();
+    ret->isAtomic = false;
+    ret->bytes = bytes;
+    ret->signed_ = signed_;
+    ret->offset = offset;
+    ret->align = align;
+    ret->ptr = ptr;
+    ret->type = type;
+    return ret;
+  }
+  Load*
+  makeAtomicLoad(unsigned bytes, uint32_t offset, Expression* ptr, Type type) {
+    Load* load = makeLoad(bytes, false, offset, bytes, ptr, type);
+    load->isAtomic = true;
+    return load;
+  }
+  AtomicWait* makeAtomicWait(Expression* ptr,
+                             Expression* expected,
+                             Expression* timeout,
+                             Type expectedType,
+                             Address offset) {
+    auto* wait = wasm.allocator.alloc<AtomicWait>();
+    wait->offset = offset;
+    wait->ptr = ptr;
+    wait->expected = expected;
+    wait->timeout = timeout;
+    wait->expectedType = expectedType;
+    wait->finalize();
+    return wait;
+  }
+  AtomicNotify*
+  makeAtomicNotify(Expression* ptr, Expression* notifyCount, Address offset) {
+    auto* notify = wasm.allocator.alloc<AtomicNotify>();
+    notify->offset = offset;
+    notify->ptr = ptr;
+    notify->notifyCount = notifyCount;
+    notify->finalize();
+    return notify;
+  }
+  AtomicFence* makeAtomicFence() { return wasm.allocator.alloc<AtomicFence>(); }
+  Store* makeStore(unsigned bytes,
+                   uint32_t offset,
+                   unsigned align,
+                   Expression* ptr,
+                   Expression* value,
+                   Type type) {
+    auto* ret = wasm.allocator.alloc<Store>();
+    ret->isAtomic = false;
+    ret->bytes = bytes;
+    ret->offset = offset;
+    ret->align = align;
+    ret->ptr = ptr;
+    ret->value = value;
+    ret->valueType = type;
+    ret->finalize();
+    assert(ret->value->type.isConcrete() ? ret->value->type == type : true);
+    return ret;
+  }
+  Store* makeAtomicStore(unsigned bytes,
+                         uint32_t offset,
+                         Expression* ptr,
+                         Expression* value,
+                         Type type) {
+    Store* store = makeStore(bytes, offset, bytes, ptr, value, type);
+    store->isAtomic = true;
+    return store;
+  }
+  AtomicRMW* makeAtomicRMW(AtomicRMWOp op,
+                           unsigned bytes,
+                           uint32_t offset,
+                           Expression* ptr,
+                           Expression* value,
+                           Type type) {
+    auto* ret = wasm.allocator.alloc<AtomicRMW>();
+    ret->op = op;
+    ret->bytes = bytes;
+    ret->offset = offset;
+    ret->ptr = ptr;
+    ret->value = value;
+    ret->type = type;
+    ret->finalize();
+    return ret;
+  }
+  AtomicCmpxchg* makeAtomicCmpxchg(unsigned bytes,
+                                   uint32_t offset,
+                                   Expression* ptr,
+                                   Expression* expected,
+                                   Expression* replacement,
+                                   Type type) {
+    auto* ret = wasm.allocator.alloc<AtomicCmpxchg>();
+    ret->bytes = bytes;
+    ret->offset = offset;
+    ret->ptr = ptr;
+    ret->expected = expected;
+    ret->replacement = replacement;
+    ret->type = type;
+    ret->finalize();
+    return ret;
+  }
+  SIMDExtract*
+  makeSIMDExtract(SIMDExtractOp op, Expression* vec, uint8_t index) {
+    auto* ret = wasm.allocator.alloc<SIMDExtract>();
+    ret->op = op;
+    ret->vec = vec;
+    ret->index = index;
+    ret->finalize();
+    return ret;
+  }
+  SIMDReplace* makeSIMDReplace(SIMDReplaceOp op,
+                               Expression* vec,
+                               uint8_t index,
+                               Expression* value) {
+    auto* ret = wasm.allocator.alloc<SIMDReplace>();
+    ret->op = op;
+    ret->vec = vec;
+    ret->index = index;
+    ret->value = value;
+    ret->finalize();
+    return ret;
+  }
+  SIMDShuffle* makeSIMDShuffle(Expression* left,
+                               Expression* right,
+                               const std::array<uint8_t, 16>& mask) {
+    auto* ret = wasm.allocator.alloc<SIMDShuffle>();
+    ret->left = left;
+    ret->right = right;
+    ret->mask = mask;
+    ret->finalize();
+    return ret;
+  }
+  SIMDTernary* makeSIMDTernary(SIMDTernaryOp op,
+                               Expression* a,
+                               Expression* b,
+                               Expression* c) {
+    auto* ret = wasm.allocator.alloc<SIMDTernary>();
+    ret->op = op;
+    ret->a = a;
+    ret->b = b;
+    ret->c = c;
+    ret->finalize();
+    return ret;
+  }
+  SIMDShift* makeSIMDShift(SIMDShiftOp op, Expression* vec, Expression* shift) {
+    auto* ret = wasm.allocator.alloc<SIMDShift>();
+    ret->op = op;
+    ret->vec = vec;
+    ret->shift = shift;
+    ret->finalize();
+    return ret;
+  }
+  SIMDLoad*
+  makeSIMDLoad(SIMDLoadOp op, Address offset, Address align, Expression* ptr) {
+    auto* ret = wasm.allocator.alloc<SIMDLoad>();
+    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,
+                             Expression* size) {
+    auto* ret = wasm.allocator.alloc<MemoryInit>();
+    ret->segment = segment;
+    ret->dest = dest;
+    ret->offset = offset;
+    ret->size = size;
+    ret->finalize();
+    return ret;
+  }
+  DataDrop* makeDataDrop(uint32_t segment) {
+    auto* ret = wasm.allocator.alloc<DataDrop>();
+    ret->segment = segment;
+    ret->finalize();
+    return ret;
+  }
+  MemoryCopy*
+  makeMemoryCopy(Expression* dest, Expression* source, Expression* size) {
+    auto* ret = wasm.allocator.alloc<MemoryCopy>();
+    ret->dest = dest;
+    ret->source = source;
+    ret->size = size;
+    ret->finalize();
+    return ret;
+  }
+  MemoryFill*
+  makeMemoryFill(Expression* dest, Expression* value, Expression* size) {
+    auto* ret = wasm.allocator.alloc<MemoryFill>();
+    ret->dest = dest;
+    ret->value = value;
+    ret->size = size;
+    ret->finalize();
+    return ret;
+  }
+  Const* makeConst(Literal value) {
+    assert(value.type.isNumber());
+    auto* ret = wasm.allocator.alloc<Const>();
+    ret->value = value;
+    ret->type = value.type;
+    return ret;
+  }
+  template<typename T> Const* makeConst(T x) { return makeConst(Literal(x)); }
+  Unary* makeUnary(UnaryOp op, Expression* value) {
+    auto* ret = wasm.allocator.alloc<Unary>();
+    ret->op = op;
+    ret->value = value;
+    ret->finalize();
+    return ret;
+  }
+  Const* makeConstPtr(uint64_t val) {
+    return makeConst(Literal::makeFromInt64(val, wasm.memory.indexType));
+  }
+  Binary* makeBinary(BinaryOp op, Expression* left, Expression* right) {
+    auto* ret = wasm.allocator.alloc<Binary>();
+    ret->op = op;
+    ret->left = left;
+    ret->right = right;
+    ret->finalize();
+    return ret;
+  }
+  Select*
+  makeSelect(Expression* condition, Expression* ifTrue, Expression* ifFalse) {
+    auto* ret = wasm.allocator.alloc<Select>();
+    ret->condition = condition;
+    ret->ifTrue = ifTrue;
+    ret->ifFalse = ifFalse;
+    ret->finalize();
+    return ret;
+  }
+  Select* makeSelect(Expression* condition,
+                     Expression* ifTrue,
+                     Expression* ifFalse,
+                     Type type) {
+    auto* ret = wasm.allocator.alloc<Select>();
+    ret->condition = condition;
+    ret->ifTrue = ifTrue;
+    ret->ifFalse = ifFalse;
+    ret->finalize(type);
+    return ret;
+  }
+  Return* makeReturn(Expression* value = nullptr) {
+    auto* ret = wasm.allocator.alloc<Return>();
+    ret->value = value;
+    return ret;
+  }
+  MemorySize* makeMemorySize() {
+    auto* ret = wasm.allocator.alloc<MemorySize>();
+    if (wasm.memory.is64()) {
+      ret->make64();
+    }
+    ret->finalize();
+    return ret;
+  }
+  MemoryGrow* makeMemoryGrow(Expression* delta) {
+    auto* ret = wasm.allocator.alloc<MemoryGrow>();
+    if (wasm.memory.is64()) {
+      ret->make64();
+    }
+    ret->delta = delta;
+    ret->finalize();
+    return ret;
+  }
+  RefNull* makeRefNull(Type type) {
+    auto* ret = wasm.allocator.alloc<RefNull>();
+    ret->finalize(type);
+    return ret;
+  }
+  RefIsNull* makeRefIsNull(Expression* value) {
+    auto* ret = wasm.allocator.alloc<RefIsNull>();
+    ret->value = value;
+    ret->finalize();
+    return ret;
+  }
+  RefFunc* makeRefFunc(Name func) {
+    auto* ret = wasm.allocator.alloc<RefFunc>();
+    ret->func = func;
+    ret->finalize();
+    return ret;
+  }
+  RefEq* makeRefEq(Expression* left, Expression* right) {
+    auto* ret = wasm.allocator.alloc<RefEq>();
+    ret->left = left;
+    ret->right = right;
+    ret->finalize();
+    return ret;
+  }
+  Try* makeTry(Expression* body, Expression* catchBody) {
+    auto* ret = wasm.allocator.alloc<Try>();
+    ret->body = body;
+    ret->catchBody = catchBody;
+    ret->finalize();
+    return ret;
+  }
+  Try* makeTry(Expression* body, Expression* catchBody, Type type) {
+    auto* ret = wasm.allocator.alloc<Try>();
+    ret->body = body;
+    ret->catchBody = catchBody;
+    ret->finalize(type);
+    return ret;
+  }
+  Throw* makeThrow(Event* event, const std::vector<Expression*>& args) {
+    return makeThrow(event->name, args);
+  }
+  Throw* makeThrow(Name event, const std::vector<Expression*>& args) {
+    auto* ret = wasm.allocator.alloc<Throw>();
+    ret->event = event;
+    ret->operands.set(args);
+    ret->finalize();
+    return ret;
+  }
+  Rethrow* makeRethrow(Expression* exnref) {
+    auto* ret = wasm.allocator.alloc<Rethrow>();
+    ret->exnref = exnref;
+    ret->finalize();
+    return ret;
+  }
+  BrOnExn* makeBrOnExn(Name name, Event* event, Expression* exnref) {
+    return makeBrOnExn(name, event->name, exnref, event->sig.params);
+  }
+  BrOnExn* makeBrOnExn(Name name, Name event, Expression* exnref, Type sent) {
+    auto* ret = wasm.allocator.alloc<BrOnExn>();
+    ret->name = name;
+    ret->event = event;
+    ret->exnref = exnref;
+    // Copy params info into BrOnExn, because it is necessary when BrOnExn is
+    // refinalized without the module.
+    ret->sent = sent;
+    ret->finalize();
+    return ret;
+  }
+  Unreachable* makeUnreachable() { return wasm.allocator.alloc<Unreachable>(); }
+  Pop* makePop(Type type) {
+    auto* ret = wasm.allocator.alloc<Pop>();
+    ret->type = type;
+    ret->finalize();
+    return ret;
+  }
+  template<typename ListType> TupleMake* makeTupleMake(ListType&& operands) {
+    auto* ret = wasm.allocator.alloc<TupleMake>();
+    ret->operands.set(operands);
+    ret->finalize();
+    return ret;
+  }
+  TupleExtract* makeTupleExtract(Expression* tuple, Index index) {
+    auto* ret = wasm.allocator.alloc<TupleExtract>();
+    ret->tuple = tuple;
+    ret->index = index;
+    ret->finalize();
+    return ret;
+  }
+  I31New* makeI31New(Expression* value) {
+    auto* ret = wasm.allocator.alloc<I31New>();
+    ret->value = value;
+    ret->finalize();
+    return ret;
+  }
+  I31Get* makeI31Get(Expression* i31, bool signed_) {
+    auto* ret = wasm.allocator.alloc<I31Get>();
+    ret->i31 = i31;
+    ret->signed_ = signed_;
+    ret->finalize();
+    return ret;
+  }
+  RefTest* makeRefTest() {
+    auto* ret = wasm.allocator.alloc<RefTest>();
+    WASM_UNREACHABLE("TODO (gc): ref.test");
+    ret->finalize();
+    return ret;
+  }
+  RefCast* makeRefCast() {
+    auto* ret = wasm.allocator.alloc<RefCast>();
+    WASM_UNREACHABLE("TODO (gc): ref.cast");
+    ret->finalize();
+    return ret;
+  }
+  BrOnCast* makeBrOnCast() {
+    auto* ret = wasm.allocator.alloc<BrOnCast>();
+    WASM_UNREACHABLE("TODO (gc): br_on_cast");
+    ret->finalize();
+    return ret;
+  }
+  RttCanon* makeRttCanon() {
+    auto* ret = wasm.allocator.alloc<RttCanon>();
+    WASM_UNREACHABLE("TODO (gc): rtt.canon");
+    ret->finalize();
+    return ret;
+  }
+  RttSub* makeRttSub() {
+    auto* ret = wasm.allocator.alloc<RttSub>();
+    WASM_UNREACHABLE("TODO (gc): rtt.sub");
+    ret->finalize();
+    return ret;
+  }
+  StructNew* makeStructNew() {
+    auto* ret = wasm.allocator.alloc<StructNew>();
+    WASM_UNREACHABLE("TODO (gc): struct.new");
+    ret->finalize();
+    return ret;
+  }
+  StructGet* makeStructGet() {
+    auto* ret = wasm.allocator.alloc<StructGet>();
+    WASM_UNREACHABLE("TODO (gc): struct.get");
+    ret->finalize();
+    return ret;
+  }
+  StructSet* makeStructSet() {
+    auto* ret = wasm.allocator.alloc<StructSet>();
+    WASM_UNREACHABLE("TODO (gc): struct.set");
+    ret->finalize();
+    return ret;
+  }
+  ArrayNew* makeArrayNew() {
+    auto* ret = wasm.allocator.alloc<ArrayNew>();
+    WASM_UNREACHABLE("TODO (gc): array.new");
+    ret->finalize();
+    return ret;
+  }
+  ArrayGet* makeArrayGet() {
+    auto* ret = wasm.allocator.alloc<ArrayGet>();
+    WASM_UNREACHABLE("TODO (gc): array.get");
+    ret->finalize();
+    return ret;
+  }
+  ArraySet* makeArraySet() {
+    auto* ret = wasm.allocator.alloc<ArraySet>();
+    WASM_UNREACHABLE("TODO (gc): array.set");
+    ret->finalize();
+    return ret;
+  }
+  ArrayLen* makeArrayLen() {
+    auto* ret = wasm.allocator.alloc<ArrayLen>();
+    WASM_UNREACHABLE("TODO (gc): array.len");
+    ret->finalize();
+    return ret;
+  }
+
+  // Additional helpers
+
+  Drop* makeDrop(Expression* value) {
+    auto* ret = wasm.allocator.alloc<Drop>();
+    ret->value = value;
+    ret->finalize();
+    return ret;
+  }
+
+  // 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);
+      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);
+      case Type::i31ref:
+        return makeI31New(makeConst(value.geti31()));
+      default:
+        assert(value.type.isNumber());
+        return makeConst(value);
+    }
+  }
+
+  Expression* makeConstantExpression(Literals values) {
+    assert(values.size() > 0);
+    if (values.size() == 1) {
+      return makeConstantExpression(values[0]);
+    } else {
+      std::vector<Expression*> consts;
+      for (auto value : values) {
+        consts.push_back(makeConstantExpression(value));
+      }
+      return makeTupleMake(consts);
+    }
+  }
+
+  // Additional utility functions for building on top of nodes
+  // Convenient to have these on Builder, as it has allocation built in
+
+  static Index addParam(Function* func, Name name, Type type) {
+    // only ok to add a param if no vars, otherwise indices are invalidated
+    assert(func->localIndices.size() == func->sig.params.size());
+    assert(name.is());
+    std::vector<Type> params(func->sig.params.begin(), func->sig.params.end());
+    params.push_back(type);
+    func->sig.params = Type(params);
+    Index index = func->localNames.size();
+    func->localIndices[name] = index;
+    func->localNames[index] = name;
+    return index;
+  }
+
+  static Index addVar(Function* func, Name name, Type type) {
+    // always ok to add a var, it does not affect other indices
+    assert(type.isConcrete());
+    Index index = func->getNumLocals();
+    if (name.is()) {
+      func->localIndices[name] = index;
+      func->localNames[index] = name;
+    }
+    func->vars.emplace_back(type);
+    return index;
+  }
+
+  static Index addVar(Function* func, Type type) {
+    return addVar(func, Name(), type);
+  }
+
+  static void clearLocalNames(Function* func) {
+    func->localNames.clear();
+    func->localIndices.clear();
+  }
+
+  static void clearLocals(Function* func) {
+    func->sig.params = Type::none;
+    func->vars.clear();
+    clearLocalNames(func);
+  }
+
+  // ensure a node is a block, if it isn't already, and optionally append to the
+  // block
+  Block* blockify(Expression* any, Expression* append = nullptr) {
+    Block* block = nullptr;
+    if (any) {
+      block = any->dynCast<Block>();
+    }
+    if (!block) {
+      block = makeBlock(any);
+    }
+    if (append) {
+      block->list.push_back(append);
+      block->finalize();
+    }
+    return block;
+  }
+
+  template<typename... Ts>
+  Block* blockify(Expression* any, Expression* append, Ts... args) {
+    return blockify(blockify(any, append), args...);
+  }
+
+  // ensure a node is a block, if it isn't already, and optionally append to the
+  // block this variant sets a name for the block, so it will not reuse a block
+  // already named
+  Block*
+  blockifyWithName(Expression* any, Name name, Expression* append = nullptr) {
+    Block* block = nullptr;
+    if (any) {
+      block = any->dynCast<Block>();
+    }
+    if (!block || block->name.is()) {
+      block = makeBlock(any);
+    }
+    block->name = name;
+    if (append) {
+      block->list.push_back(append);
+      block->finalize();
+    }
+    return block;
+  }
+
+  // a helper for the common pattern of a sequence of two expressions. Similar
+  // to blockify, but does *not* reuse a block if the first is one.
+  Block* makeSequence(Expression* left, Expression* right) {
+    auto* block = makeBlock(left);
+    block->list.push_back(right);
+    block->finalize();
+    return block;
+  }
+
+  Block* makeSequence(Expression* left, Expression* right, Type type) {
+    auto* block = makeBlock(left);
+    block->list.push_back(right);
+    block->finalize(type);
+    return block;
+  }
+
+  // Grab a slice out of a block, replacing it with nops, and returning
+  // either another block with the contents (if more than 1) or a single
+  // expression
+  Expression* stealSlice(Block* input, Index from, Index to) {
+    Expression* ret;
+    if (to == from + 1) {
+      // just one
+      ret = input->list[from];
+    } else {
+      auto* block = wasm.allocator.alloc<Block>();
+      for (Index i = from; i < to; i++) {
+        block->list.push_back(input->list[i]);
+      }
+      block->finalize();
+      ret = block;
+    }
+    if (to == input->list.size()) {
+      input->list.resize(from);
+    } else {
+      for (Index i = from; i < to; i++) {
+        input->list[i] = wasm.allocator.alloc<Nop>();
+      }
+    }
+    input->finalize();
+    return ret;
+  }
+
+  // Drop an expression if it has a concrete type
+  Expression* dropIfConcretelyTyped(Expression* curr) {
+    if (!curr->type.isConcrete()) {
+      return curr;
+    }
+    return makeDrop(curr);
+  }
+
+  void flip(If* iff) {
+    std::swap(iff->ifTrue, iff->ifFalse);
+    iff->condition = makeUnary(EqZInt32, iff->condition);
+  }
+
+  // returns a replacement with the precise same type, and with
+  // minimal contents. as a replacement, this may reuse the
+  // input node
+  template<typename T> Expression* replaceWithIdenticalType(T* curr) {
+    if (curr->type.isTuple()) {
+      return makeConstantExpression(Literal::makeZeros(curr->type));
+    }
+    Literal value;
+    // TODO: reuse node conditionally when possible for literals
+    TODO_SINGLE_COMPOUND(curr->type);
+    switch (curr->type.getBasic()) {
+      case Type::i32:
+        value = Literal(int32_t(0));
+        break;
+      case Type::i64:
+        value = Literal(int64_t(0));
+        break;
+      case Type::f32:
+        value = Literal(float(0));
+        break;
+      case Type::f64:
+        value = Literal(double(0));
+        break;
+      case Type::v128: {
+        std::array<uint8_t, 16> bytes;
+        bytes.fill(0);
+        value = Literal(bytes.data());
+        break;
+      }
+      case Type::funcref:
+      case Type::externref:
+      case Type::exnref:
+      case Type::anyref:
+      case Type::eqref:
+        return ExpressionManipulator::refNull(curr, curr->type);
+      case Type::i31ref:
+        return makeI31New(makeConst(0));
+      case Type::none:
+        return ExpressionManipulator::nop(curr);
+      case Type::unreachable:
+        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;
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_wasm_builder_h
diff --git a/binaryen/src/wasm-debug.h b/binaryen/src/wasm-debug.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-debug.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 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.
+ */
+
+//
+// Comprehensive debug info support (beyond source maps).
+//
+
+#ifndef wasm_wasm_debug_h
+#define wasm_wasm_debug_h
+
+#include <string>
+
+#include "wasm.h"
+
+namespace wasm {
+
+namespace Debug {
+
+bool isDWARFSection(Name name);
+
+bool hasDWARFSections(const Module& wasm);
+
+// Dump the DWARF sections to stdout.
+void dumpDWARF(const Module& wasm);
+
+// Update the DWARF sections.
+void writeDWARFSections(Module& wasm, const BinaryLocations& newLocations);
+
+} // namespace Debug
+
+} // namespace wasm
+
+#undef DEBUG_TYPE
+
+#endif // wasm_wasm_debug_h
diff --git a/binaryen/src/wasm-emscripten.h b/binaryen/src/wasm-emscripten.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-emscripten.h
@@ -0,0 +1,76 @@
+/*
+ * 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_emscripten_h
+#define wasm_wasm_emscripten_h
+
+#include "support/file.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+Global* getStackPointerGlobal(Module& wasm);
+
+// Class which modifies a wasm module for use with emscripten. Generates
+// runtime functions and emits metadata.
+class EmscriptenGlueGenerator {
+public:
+  EmscriptenGlueGenerator(Module& wasm, Address stackPointerOffset = Address(0))
+    : 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);
+
+  void fixInvokeFunctionNames();
+
+  // clang uses name mangling to rename the argc/argv form of main to
+  // __main_argc_argv.  Emscripten in non-standalone mode expects that function
+  // to be exported as main.  This function renames __main_argc_argv to main
+  // as expected by emscripten.
+  void renameMainArgcArgv();
+
+  // Emits the data segments to a file. The file contains data from address base
+  // onwards (we must pass in base, as we can't tell it from the wasm - the
+  // first segment may start after a run of zeros, but we need those zeros in
+  // the file).
+  void separateDataSegments(Output* outfile, Address base);
+
+  bool standalone = false;
+  bool sideModule = false;
+  bool minimizeWasmChanges = false;
+  bool noDynCalls = false;
+  bool onlyI64DynCalls = false;
+
+private:
+  Module& wasm;
+  Builder builder;
+  Address stackPointerOffset;
+  bool useStackPointerGlobal;
+};
+
+} // namespace wasm
+
+#endif // wasm_wasm_emscripten_h
diff --git a/binaryen/src/wasm-features.h b/binaryen/src/wasm-features.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-features.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2019 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_features_h
+#define wasm_features_h
+
+#include <stdint.h>
+#include <string>
+
+#include "compiler-support.h"
+#include "support/utilities.h"
+
+struct FeatureSet {
+  enum Feature : uint32_t {
+    MVP = 0,
+    Atomics = 1 << 0,
+    MutableGlobals = 1 << 1,
+    TruncSat = 1 << 2,
+    SIMD = 1 << 3,
+    BulkMemory = 1 << 4,
+    SignExt = 1 << 5,
+    ExceptionHandling = 1 << 6,
+    TailCall = 1 << 7,
+    ReferenceTypes = 1 << 8,
+    Multivalue = 1 << 9,
+    GC = 1 << 10,
+    Memory64 = 1 << 11,
+    All = (1 << 12) - 1
+  };
+
+  static std::string toString(Feature f) {
+    switch (f) {
+      case Atomics:
+        return "threads";
+      case MutableGlobals:
+        return "mutable-globals";
+      case TruncSat:
+        return "nontrapping-float-to-int";
+      case SIMD:
+        return "simd";
+      case BulkMemory:
+        return "bulk-memory";
+      case SignExt:
+        return "sign-ext";
+      case ExceptionHandling:
+        return "exception-handling";
+      case TailCall:
+        return "tail-call";
+      case ReferenceTypes:
+        return "reference-types";
+      case Multivalue:
+        return "multivalue";
+      case GC:
+        return "gc";
+      case Memory64:
+        return "memory64";
+      default:
+        WASM_UNREACHABLE("unexpected feature");
+    }
+  }
+
+  FeatureSet() : features(MVP) {}
+  FeatureSet(uint32_t features) : features(features) {}
+  operator uint32_t() const { return features; }
+
+  bool isMVP() const { return features == MVP; }
+  bool has(FeatureSet f) { return (features & f) == f; }
+  bool hasAtomics() const { return (features & Atomics) != 0; }
+  bool hasMutableGlobals() const { return (features & MutableGlobals) != 0; }
+  bool hasTruncSat() const { return (features & TruncSat) != 0; }
+  bool hasSIMD() const { return (features & SIMD) != 0; }
+  bool hasBulkMemory() const { return (features & BulkMemory) != 0; }
+  bool hasSignExt() const { return (features & SignExt) != 0; }
+  bool hasExceptionHandling() const {
+    return (features & ExceptionHandling) != 0;
+  }
+  bool hasTailCall() const { return (features & TailCall) != 0; }
+  bool hasReferenceTypes() const { return (features & ReferenceTypes) != 0; }
+  bool hasMultivalue() const { return (features & Multivalue) != 0; }
+  bool hasGC() const { return (features & GC) != 0; }
+  bool hasMemory64() const { return (features & Memory64) != 0; }
+  bool hasAll() const { return (features & All) != 0; }
+
+  void makeMVP() { features = MVP; }
+  void set(FeatureSet f, bool v = true) {
+    features = v ? (features | f) : (features & ~f);
+  }
+  void setAtomics(bool v = true) { set(Atomics, v); }
+  void setMutableGlobals(bool v = true) { set(MutableGlobals, v); }
+  void setTruncSat(bool v = true) { set(TruncSat, v); }
+  void setSIMD(bool v = true) { set(SIMD, v); }
+  void setBulkMemory(bool v = true) { set(BulkMemory, v); }
+  void setSignExt(bool v = true) { set(SignExt, v); }
+  void setExceptionHandling(bool v = true) { set(ExceptionHandling, v); }
+  void setTailCall(bool v = true) { set(TailCall, v); }
+  void setReferenceTypes(bool v = true) { set(ReferenceTypes, v); }
+  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 setAll(bool v = true) { features = v ? All : MVP; }
+
+  void enable(const FeatureSet& other) { features |= other.features; }
+  void disable(const FeatureSet& other) {
+    features = features & ~other.features & All;
+  }
+
+  template<typename F> void iterFeatures(F f) {
+    for (uint32_t feature = MVP + 1; feature < All; feature <<= 1) {
+      if (has(feature)) {
+        f(static_cast<Feature>(feature));
+      }
+    }
+  }
+
+  bool operator<=(const FeatureSet& other) const {
+    return !(features & ~other.features);
+  }
+
+  bool operator==(const FeatureSet& other) const {
+    return *this <= other && other <= *this;
+  }
+
+  bool operator!=(const FeatureSet& other) const { return !(*this == other); }
+
+  FeatureSet& operator|=(const FeatureSet& other) {
+    features |= other.features;
+    return *this;
+  }
+
+  uint32_t features;
+};
+
+#endif // wasm_features_h
diff --git a/binaryen/src/wasm-interpreter.h b/binaryen/src/wasm-interpreter.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-interpreter.h
@@ -0,0 +1,2765 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// Simple WebAssembly interpreter. This operates directly on the AST,
+// for simplicity and clarity. A goal is for it to be possible for
+// people to read this code and understand WebAssembly semantics.
+//
+
+#ifndef wasm_wasm_interpreter_h
+#define wasm_wasm_interpreter_h
+
+#include <cmath>
+#include <limits.h>
+#include <sstream>
+
+#include "ir/module-utils.h"
+#include "support/bits.h"
+#include "support/safe_integer.h"
+#include "wasm-builder.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
+
+#ifdef WASM_INTERPRETER_DEBUG
+#include "wasm-printing.h"
+#endif
+
+namespace wasm {
+
+struct WasmException {
+  WasmException(Literal exn) : exn(exn) {}
+  Literal exn;
+};
+
+using namespace cashew;
+
+// Utilities
+
+extern Name WASM, RETURN_FLOW, NONCONSTANT_FLOW;
+
+// Stuff that flows around during executing expressions: a literal, or a change
+// in control flow.
+class Flow {
+public:
+  Flow() : values() {}
+  Flow(Literal value) : values{value} { assert(value.type.isConcrete()); }
+  Flow(Literals& values) : values(values) {}
+  Flow(Literals&& values) : values(std::move(values)) {}
+  Flow(Name breakTo) : values(), breakTo(breakTo) {}
+
+  Literals values;
+  Name breakTo; // if non-null, a break is going on
+
+  // A helper function for the common case where there is only one value
+  const Literal& getSingleValue() {
+    assert(values.size() == 1);
+    return values[0];
+  }
+
+  Type getType() { return values.getType(); }
+
+  Expression* getConstExpression(Module& module) {
+    assert(values.size() > 0);
+    Builder builder(module);
+    return builder.makeConstantExpression(values);
+  }
+
+  bool breaking() { return breakTo.is(); }
+
+  void clearIf(Name target) {
+    if (breakTo == target) {
+      breakTo.clear();
+    }
+  }
+
+  friend std::ostream& operator<<(std::ostream& o, const Flow& flow) {
+    o << "(flow " << (flow.breakTo.is() ? flow.breakTo.str : "-") << " : {";
+    for (size_t i = 0; i < flow.values.size(); ++i) {
+      if (i > 0) {
+        o << ", ";
+      }
+      o << flow.values[i];
+    }
+    o << "})";
+    return o;
+  }
+};
+
+// A list of literals, for function calls
+typedef std::vector<Literal> LiteralList;
+
+// Debugging helpers
+#ifdef WASM_INTERPRETER_DEBUG
+class Indenter {
+  static int indentLevel;
+
+  const char* entryName;
+
+public:
+  Indenter(const char* entry);
+  ~Indenter();
+
+  static void print();
+};
+
+#define NOTE_ENTER(x)                                                          \
+  Indenter _int_blah(x);                                                       \
+  {                                                                            \
+    Indenter::print();                                                         \
+    std::cout << "visit " << x << " : " << curr << "\n";                       \
+  }
+#define NOTE_ENTER_(x)                                                         \
+  Indenter _int_blah(x);                                                       \
+  {                                                                            \
+    Indenter::print();                                                         \
+    std::cout << "visit " << x << "\n";                                        \
+  }
+#define NOTE_NAME(p0)                                                          \
+  {                                                                            \
+    Indenter::print();                                                         \
+    std::cout << "name " << '(' << Name(p0) << ")\n";                          \
+  }
+#define NOTE_EVAL1(p0)                                                         \
+  {                                                                            \
+    Indenter::print();                                                         \
+    std::cout << "eval " #p0 " (" << p0 << ")\n";                              \
+  }
+#define NOTE_EVAL2(p0, p1)                                                     \
+  {                                                                            \
+    Indenter::print();                                                         \
+    std::cout << "eval " #p0 " (" << p0 << "), " #p1 " (" << p1 << ")\n";      \
+  }
+#else // WASM_INTERPRETER_DEBUG
+#define NOTE_ENTER(x)
+#define NOTE_ENTER_(x)
+#define NOTE_NAME(p0)
+#define NOTE_EVAL1(p0)
+#define NOTE_EVAL2(p0, p1)
+#endif // WASM_INTERPRETER_DEBUG
+
+// Execute an expression
+template<typename SubType>
+class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
+protected:
+  // Maximum depth before giving up.
+  Index maxDepth;
+  Index depth = 0;
+
+  // Maximum iterations before giving up on a loop.
+  Index maxLoopIterations;
+
+  Flow generateArguments(const ExpressionList& operands,
+                         LiteralList& arguments) {
+    NOTE_ENTER_("generateArguments");
+    arguments.reserve(operands.size());
+    for (auto expression : operands) {
+      Flow flow = this->visit(expression);
+      if (flow.breaking()) {
+        return flow;
+      }
+      NOTE_EVAL1(flow.values);
+      arguments.push_back(flow.getSingleValue());
+    }
+    return Flow();
+  }
+
+public:
+  // Indicates no limit of maxDepth or maxLoopIterations.
+  static const Index NO_LIMIT = 0;
+
+  ExpressionRunner(Index maxDepth = NO_LIMIT,
+                   Index maxLoopIterations = NO_LIMIT)
+    : maxDepth(maxDepth), maxLoopIterations(maxLoopIterations) {}
+
+  Flow visit(Expression* curr) {
+    depth++;
+    if (maxDepth != NO_LIMIT && depth > maxDepth) {
+      trap("interpreter recursion limit");
+    }
+    auto ret = OverriddenVisitor<SubType, Flow>::visit(curr);
+    if (!ret.breaking()) {
+      Type type = ret.getType();
+      if (type.isConcrete() || curr->type.isConcrete()) {
+#if 1 // def WASM_INTERPRETER_DEBUG
+        if (!Type::isSubType(type, curr->type)) {
+          std::cerr << "expected " << curr->type << ", seeing " << type
+                    << " from\n"
+                    << curr << '\n';
+        }
+#endif
+        assert(Type::isSubType(type, curr->type));
+      }
+    }
+    depth--;
+    return ret;
+  }
+
+  Flow visitBlock(Block* curr) {
+    NOTE_ENTER("Block");
+    // special-case Block, because Block nesting (in their first element) can be
+    // incredibly deep
+    std::vector<Block*> stack;
+    stack.push_back(curr);
+    while (curr->list.size() > 0 && curr->list[0]->is<Block>()) {
+      curr = curr->list[0]->cast<Block>();
+      stack.push_back(curr);
+    }
+    Flow flow;
+    auto* top = stack.back();
+    while (stack.size() > 0) {
+      curr = stack.back();
+      stack.pop_back();
+      if (flow.breaking()) {
+        flow.clearIf(curr->name);
+        continue;
+      }
+      auto& list = curr->list;
+      for (size_t i = 0; i < list.size(); i++) {
+        if (curr != top && i == 0) {
+          // one of the block recursions we already handled
+          continue;
+        }
+        flow = visit(list[i]);
+        if (flow.breaking()) {
+          flow.clearIf(curr->name);
+          break;
+        }
+      }
+    }
+    return flow;
+  }
+  Flow visitIf(If* curr) {
+    NOTE_ENTER("If");
+    Flow flow = visit(curr->condition);
+    if (flow.breaking()) {
+      return flow;
+    }
+    NOTE_EVAL1(flow.values);
+    if (flow.getSingleValue().geti32()) {
+      Flow flow = visit(curr->ifTrue);
+      if (!flow.breaking() && !curr->ifFalse) {
+        flow = Flow(); // if_else returns a value, but if does not
+      }
+      return flow;
+    }
+    if (curr->ifFalse) {
+      return visit(curr->ifFalse);
+    }
+    return Flow();
+  }
+  Flow visitLoop(Loop* curr) {
+    NOTE_ENTER("Loop");
+    Index loopCount = 0;
+    while (1) {
+      Flow flow = visit(curr->body);
+      if (flow.breaking()) {
+        if (flow.breakTo == curr->name) {
+          if (maxLoopIterations != NO_LIMIT &&
+              ++loopCount >= maxLoopIterations) {
+            return Flow(NONCONSTANT_FLOW);
+          }
+          continue; // lol
+        }
+      }
+      // loop does not loop automatically, only continue achieves that
+      return flow;
+    }
+  }
+  Flow visitBreak(Break* curr) {
+    NOTE_ENTER("Break");
+    bool condition = true;
+    Flow flow;
+    if (curr->value) {
+      flow = visit(curr->value);
+      if (flow.breaking()) {
+        return flow;
+      }
+    }
+    if (curr->condition) {
+      Flow conditionFlow = visit(curr->condition);
+      if (conditionFlow.breaking()) {
+        return conditionFlow;
+      }
+      condition = conditionFlow.getSingleValue().getInteger() != 0;
+      if (!condition) {
+        return flow;
+      }
+    }
+    flow.breakTo = curr->name;
+    return flow;
+  }
+  Flow visitSwitch(Switch* curr) {
+    NOTE_ENTER("Switch");
+    Flow flow;
+    Literals values;
+    if (curr->value) {
+      flow = visit(curr->value);
+      if (flow.breaking()) {
+        return flow;
+      }
+      values = flow.values;
+    }
+    flow = visit(curr->condition);
+    if (flow.breaking()) {
+      return flow;
+    }
+    int64_t index = flow.getSingleValue().getInteger();
+    Name target = curr->default_;
+    if (index >= 0 && (size_t)index < curr->targets.size()) {
+      target = curr->targets[(size_t)index];
+    }
+    flow.breakTo = target;
+    flow.values = values;
+    return flow;
+  }
+
+  Flow visitConst(Const* curr) {
+    NOTE_ENTER("Const");
+    NOTE_EVAL1(curr->value);
+    return Flow(curr->value); // heh
+  }
+
+  // Unary and Binary nodes, the core math computations. We mostly just
+  // delegate to the Literal::* methods, except we handle traps here.
+
+  Flow visitUnary(Unary* curr) {
+    NOTE_ENTER("Unary");
+    Flow flow = visit(curr->value);
+    if (flow.breaking()) {
+      return flow;
+    }
+    Literal value = flow.getSingleValue();
+    NOTE_EVAL1(value);
+    switch (curr->op) {
+      case ClzInt32:
+      case ClzInt64:
+        return value.countLeadingZeroes();
+      case CtzInt32:
+      case CtzInt64:
+        return value.countTrailingZeroes();
+      case PopcntInt32:
+      case PopcntInt64:
+        return value.popCount();
+      case EqZInt32:
+      case EqZInt64:
+        return value.eqz();
+      case ReinterpretInt32:
+        return value.castToF32();
+      case ReinterpretInt64:
+        return value.castToF64();
+      case ExtendSInt32:
+        return value.extendToSI64();
+      case ExtendUInt32:
+        return value.extendToUI64();
+      case WrapInt64:
+        return value.wrapToI32();
+      case ConvertUInt32ToFloat32:
+      case ConvertUInt64ToFloat32:
+        return value.convertUIToF32();
+      case ConvertUInt32ToFloat64:
+      case ConvertUInt64ToFloat64:
+        return value.convertUIToF64();
+      case ConvertSInt32ToFloat32:
+      case ConvertSInt64ToFloat32:
+        return value.convertSIToF32();
+      case ConvertSInt32ToFloat64:
+      case ConvertSInt64ToFloat64:
+        return value.convertSIToF64();
+      case ExtendS8Int32:
+      case ExtendS8Int64:
+        return value.extendS8();
+      case ExtendS16Int32:
+      case ExtendS16Int64:
+        return value.extendS16();
+      case ExtendS32Int64:
+        return value.extendS32();
+
+      case NegFloat32:
+      case NegFloat64:
+        return value.neg();
+      case AbsFloat32:
+      case AbsFloat64:
+        return value.abs();
+      case CeilFloat32:
+      case CeilFloat64:
+        return value.ceil();
+      case FloorFloat32:
+      case FloorFloat64:
+        return value.floor();
+      case TruncFloat32:
+      case TruncFloat64:
+        return value.trunc();
+      case NearestFloat32:
+      case NearestFloat64:
+        return value.nearbyint();
+      case SqrtFloat32:
+      case SqrtFloat64:
+        return value.sqrt();
+      case TruncSFloat32ToInt32:
+      case TruncSFloat64ToInt32:
+      case TruncSFloat32ToInt64:
+      case TruncSFloat64ToInt64:
+        return truncSFloat(curr, value);
+      case TruncUFloat32ToInt32:
+      case TruncUFloat64ToInt32:
+      case TruncUFloat32ToInt64:
+      case TruncUFloat64ToInt64:
+        return truncUFloat(curr, value);
+      case TruncSatSFloat32ToInt32:
+      case TruncSatSFloat64ToInt32:
+        return value.truncSatToSI32();
+      case TruncSatSFloat32ToInt64:
+      case TruncSatSFloat64ToInt64:
+        return value.truncSatToSI64();
+      case TruncSatUFloat32ToInt32:
+      case TruncSatUFloat64ToInt32:
+        return value.truncSatToUI32();
+      case TruncSatUFloat32ToInt64:
+      case TruncSatUFloat64ToInt64:
+        return value.truncSatToUI64();
+      case ReinterpretFloat32:
+        return value.castToI32();
+      case PromoteFloat32:
+        return value.extendToF64();
+      case ReinterpretFloat64:
+        return value.castToI64();
+      case DemoteFloat64:
+        return value.demote();
+      case SplatVecI8x16:
+        return value.splatI8x16();
+      case SplatVecI16x8:
+        return value.splatI16x8();
+      case SplatVecI32x4:
+        return value.splatI32x4();
+      case SplatVecI64x2:
+        return value.splatI64x2();
+      case SplatVecF32x4:
+        return value.splatF32x4();
+      case SplatVecF64x2:
+        return value.splatF64x2();
+      case NotVec128:
+        return value.notV128();
+      case AbsVecI8x16:
+        return value.absI8x16();
+      case NegVecI8x16:
+        return value.negI8x16();
+      case AnyTrueVecI8x16:
+        return value.anyTrueI8x16();
+      case AllTrueVecI8x16:
+        return value.allTrueI8x16();
+      case BitmaskVecI8x16:
+        return value.bitmaskI8x16();
+      case AbsVecI16x8:
+        return value.absI16x8();
+      case NegVecI16x8:
+        return value.negI16x8();
+      case AnyTrueVecI16x8:
+        return value.anyTrueI16x8();
+      case AllTrueVecI16x8:
+        return value.allTrueI16x8();
+      case BitmaskVecI16x8:
+        return value.bitmaskI16x8();
+      case AbsVecI32x4:
+        return value.absI32x4();
+      case NegVecI32x4:
+        return value.negI32x4();
+      case AnyTrueVecI32x4:
+        return value.anyTrueI32x4();
+      case AllTrueVecI32x4:
+        return value.allTrueI32x4();
+      case BitmaskVecI32x4:
+        return value.bitmaskI32x4();
+      case NegVecI64x2:
+        return value.negI64x2();
+      case AnyTrueVecI64x2:
+        return value.anyTrueI64x2();
+      case AllTrueVecI64x2:
+        return value.allTrueI64x2();
+      case AbsVecF32x4:
+        return value.absF32x4();
+      case NegVecF32x4:
+        return value.negF32x4();
+      case SqrtVecF32x4:
+        return value.sqrtF32x4();
+      case CeilVecF32x4:
+        return value.ceilF32x4();
+      case FloorVecF32x4:
+        return value.floorF32x4();
+      case TruncVecF32x4:
+        return value.truncF32x4();
+      case NearestVecF32x4:
+        return value.nearestF32x4();
+      case AbsVecF64x2:
+        return value.absF64x2();
+      case NegVecF64x2:
+        return value.negF64x2();
+      case SqrtVecF64x2:
+        return value.sqrtF64x2();
+      case CeilVecF64x2:
+        return value.ceilF64x2();
+      case FloorVecF64x2:
+        return value.floorF64x2();
+      case TruncVecF64x2:
+        return value.truncF64x2();
+      case NearestVecF64x2:
+        return value.nearestF64x2();
+      case TruncSatSVecF32x4ToVecI32x4:
+        return value.truncSatToSI32x4();
+      case TruncSatUVecF32x4ToVecI32x4:
+        return value.truncSatToUI32x4();
+      case TruncSatSVecF64x2ToVecI64x2:
+        return value.truncSatToSI64x2();
+      case TruncSatUVecF64x2ToVecI64x2:
+        return value.truncSatToUI64x2();
+      case ConvertSVecI32x4ToVecF32x4:
+        return value.convertSToF32x4();
+      case ConvertUVecI32x4ToVecF32x4:
+        return value.convertUToF32x4();
+      case ConvertSVecI64x2ToVecF64x2:
+        return value.convertSToF64x2();
+      case ConvertUVecI64x2ToVecF64x2:
+        return value.convertUToF64x2();
+      case WidenLowSVecI8x16ToVecI16x8:
+        return value.widenLowSToVecI16x8();
+      case WidenHighSVecI8x16ToVecI16x8:
+        return value.widenHighSToVecI16x8();
+      case WidenLowUVecI8x16ToVecI16x8:
+        return value.widenLowUToVecI16x8();
+      case WidenHighUVecI8x16ToVecI16x8:
+        return value.widenHighUToVecI16x8();
+      case WidenLowSVecI16x8ToVecI32x4:
+        return value.widenLowSToVecI32x4();
+      case WidenHighSVecI16x8ToVecI32x4:
+        return value.widenHighSToVecI32x4();
+      case WidenLowUVecI16x8ToVecI32x4:
+        return value.widenLowUToVecI32x4();
+      case WidenHighUVecI16x8ToVecI32x4:
+        return value.widenHighUToVecI32x4();
+      case InvalidUnary:
+        WASM_UNREACHABLE("invalid unary op");
+    }
+    WASM_UNREACHABLE("invalid op");
+  }
+  Flow visitBinary(Binary* curr) {
+    NOTE_ENTER("Binary");
+    Flow flow = visit(curr->left);
+    if (flow.breaking()) {
+      return flow;
+    }
+    Literal left = flow.getSingleValue();
+    flow = visit(curr->right);
+    if (flow.breaking()) {
+      return flow;
+    }
+    Literal right = flow.getSingleValue();
+    NOTE_EVAL2(left, right);
+    assert(curr->left->type.isConcrete() ? left.type == curr->left->type
+                                         : true);
+    assert(curr->right->type.isConcrete() ? right.type == curr->right->type
+                                          : true);
+    switch (curr->op) {
+      case AddInt32:
+      case AddInt64:
+      case AddFloat32:
+      case AddFloat64:
+        return left.add(right);
+      case SubInt32:
+      case SubInt64:
+      case SubFloat32:
+      case SubFloat64:
+        return left.sub(right);
+      case MulInt32:
+      case MulInt64:
+      case MulFloat32:
+      case MulFloat64:
+        return left.mul(right);
+      case DivSInt32: {
+        if (right.getInteger() == 0) {
+          trap("i32.div_s by 0");
+        }
+        if (left.getInteger() == std::numeric_limits<int32_t>::min() &&
+            right.getInteger() == -1) {
+          trap("i32.div_s overflow"); // signed division overflow
+        }
+        return left.divS(right);
+      }
+      case DivUInt32: {
+        if (right.getInteger() == 0) {
+          trap("i32.div_u by 0");
+        }
+        return left.divU(right);
+      }
+      case RemSInt32: {
+        if (right.getInteger() == 0) {
+          trap("i32.rem_s by 0");
+        }
+        if (left.getInteger() == std::numeric_limits<int32_t>::min() &&
+            right.getInteger() == -1) {
+          return Literal(int32_t(0));
+        }
+        return left.remS(right);
+      }
+      case RemUInt32: {
+        if (right.getInteger() == 0) {
+          trap("i32.rem_u by 0");
+        }
+        return left.remU(right);
+      }
+      case DivSInt64: {
+        if (right.getInteger() == 0) {
+          trap("i64.div_s by 0");
+        }
+        if (left.getInteger() == LLONG_MIN && right.getInteger() == -1LL) {
+          trap("i64.div_s overflow"); // signed division overflow
+        }
+        return left.divS(right);
+      }
+      case DivUInt64: {
+        if (right.getInteger() == 0) {
+          trap("i64.div_u by 0");
+        }
+        return left.divU(right);
+      }
+      case RemSInt64: {
+        if (right.getInteger() == 0) {
+          trap("i64.rem_s by 0");
+        }
+        if (left.getInteger() == LLONG_MIN && right.getInteger() == -1LL) {
+          return Literal(int64_t(0));
+        }
+        return left.remS(right);
+      }
+      case RemUInt64: {
+        if (right.getInteger() == 0) {
+          trap("i64.rem_u by 0");
+        }
+        return left.remU(right);
+      }
+      case DivFloat32:
+      case DivFloat64:
+        return left.div(right);
+      case AndInt32:
+      case AndInt64:
+        return left.and_(right);
+      case OrInt32:
+      case OrInt64:
+        return left.or_(right);
+      case XorInt32:
+      case XorInt64:
+        return left.xor_(right);
+      case ShlInt32:
+      case ShlInt64:
+        return left.shl(right);
+      case ShrUInt32:
+      case ShrUInt64:
+        return left.shrU(right);
+      case ShrSInt32:
+      case ShrSInt64:
+        return left.shrS(right);
+      case RotLInt32:
+      case RotLInt64:
+        return left.rotL(right);
+      case RotRInt32:
+      case RotRInt64:
+        return left.rotR(right);
+
+      case EqInt32:
+      case EqInt64:
+      case EqFloat32:
+      case EqFloat64:
+        return left.eq(right);
+      case NeInt32:
+      case NeInt64:
+      case NeFloat32:
+      case NeFloat64:
+        return left.ne(right);
+      case LtSInt32:
+      case LtSInt64:
+        return left.ltS(right);
+      case LtUInt32:
+      case LtUInt64:
+        return left.ltU(right);
+      case LeSInt32:
+      case LeSInt64:
+        return left.leS(right);
+      case LeUInt32:
+      case LeUInt64:
+        return left.leU(right);
+      case GtSInt32:
+      case GtSInt64:
+        return left.gtS(right);
+      case GtUInt32:
+      case GtUInt64:
+        return left.gtU(right);
+      case GeSInt32:
+      case GeSInt64:
+        return left.geS(right);
+      case GeUInt32:
+      case GeUInt64:
+        return left.geU(right);
+      case LtFloat32:
+      case LtFloat64:
+        return left.lt(right);
+      case LeFloat32:
+      case LeFloat64:
+        return left.le(right);
+      case GtFloat32:
+      case GtFloat64:
+        return left.gt(right);
+      case GeFloat32:
+      case GeFloat64:
+        return left.ge(right);
+
+      case CopySignFloat32:
+      case CopySignFloat64:
+        return left.copysign(right);
+      case MinFloat32:
+      case MinFloat64:
+        return left.min(right);
+      case MaxFloat32:
+      case MaxFloat64:
+        return left.max(right);
+
+      case EqVecI8x16:
+        return left.eqI8x16(right);
+      case NeVecI8x16:
+        return left.neI8x16(right);
+      case LtSVecI8x16:
+        return left.ltSI8x16(right);
+      case LtUVecI8x16:
+        return left.ltUI8x16(right);
+      case GtSVecI8x16:
+        return left.gtSI8x16(right);
+      case GtUVecI8x16:
+        return left.gtUI8x16(right);
+      case LeSVecI8x16:
+        return left.leSI8x16(right);
+      case LeUVecI8x16:
+        return left.leUI8x16(right);
+      case GeSVecI8x16:
+        return left.geSI8x16(right);
+      case GeUVecI8x16:
+        return left.geUI8x16(right);
+      case EqVecI16x8:
+        return left.eqI16x8(right);
+      case NeVecI16x8:
+        return left.neI16x8(right);
+      case LtSVecI16x8:
+        return left.ltSI16x8(right);
+      case LtUVecI16x8:
+        return left.ltUI16x8(right);
+      case GtSVecI16x8:
+        return left.gtSI16x8(right);
+      case GtUVecI16x8:
+        return left.gtUI16x8(right);
+      case LeSVecI16x8:
+        return left.leSI16x8(right);
+      case LeUVecI16x8:
+        return left.leUI16x8(right);
+      case GeSVecI16x8:
+        return left.geSI16x8(right);
+      case GeUVecI16x8:
+        return left.geUI16x8(right);
+      case EqVecI32x4:
+        return left.eqI32x4(right);
+      case NeVecI32x4:
+        return left.neI32x4(right);
+      case LtSVecI32x4:
+        return left.ltSI32x4(right);
+      case LtUVecI32x4:
+        return left.ltUI32x4(right);
+      case GtSVecI32x4:
+        return left.gtSI32x4(right);
+      case GtUVecI32x4:
+        return left.gtUI32x4(right);
+      case LeSVecI32x4:
+        return left.leSI32x4(right);
+      case LeUVecI32x4:
+        return left.leUI32x4(right);
+      case GeSVecI32x4:
+        return left.geSI32x4(right);
+      case GeUVecI32x4:
+        return left.geUI32x4(right);
+      case EqVecF32x4:
+        return left.eqF32x4(right);
+      case NeVecF32x4:
+        return left.neF32x4(right);
+      case LtVecF32x4:
+        return left.ltF32x4(right);
+      case GtVecF32x4:
+        return left.gtF32x4(right);
+      case LeVecF32x4:
+        return left.leF32x4(right);
+      case GeVecF32x4:
+        return left.geF32x4(right);
+      case EqVecF64x2:
+        return left.eqF64x2(right);
+      case NeVecF64x2:
+        return left.neF64x2(right);
+      case LtVecF64x2:
+        return left.ltF64x2(right);
+      case GtVecF64x2:
+        return left.gtF64x2(right);
+      case LeVecF64x2:
+        return left.leF64x2(right);
+      case GeVecF64x2:
+        return left.geF64x2(right);
+
+      case AndVec128:
+        return left.andV128(right);
+      case OrVec128:
+        return left.orV128(right);
+      case XorVec128:
+        return left.xorV128(right);
+      case AndNotVec128:
+        return left.andV128(right.notV128());
+
+      case AddVecI8x16:
+        return left.addI8x16(right);
+      case AddSatSVecI8x16:
+        return left.addSaturateSI8x16(right);
+      case AddSatUVecI8x16:
+        return left.addSaturateUI8x16(right);
+      case SubVecI8x16:
+        return left.subI8x16(right);
+      case SubSatSVecI8x16:
+        return left.subSaturateSI8x16(right);
+      case SubSatUVecI8x16:
+        return left.subSaturateUI8x16(right);
+      case MulVecI8x16:
+        return left.mulI8x16(right);
+      case MinSVecI8x16:
+        return left.minSI8x16(right);
+      case MinUVecI8x16:
+        return left.minUI8x16(right);
+      case MaxSVecI8x16:
+        return left.maxSI8x16(right);
+      case MaxUVecI8x16:
+        return left.maxUI8x16(right);
+      case AvgrUVecI8x16:
+        return left.avgrUI8x16(right);
+      case AddVecI16x8:
+        return left.addI16x8(right);
+      case AddSatSVecI16x8:
+        return left.addSaturateSI16x8(right);
+      case AddSatUVecI16x8:
+        return left.addSaturateUI16x8(right);
+      case SubVecI16x8:
+        return left.subI16x8(right);
+      case SubSatSVecI16x8:
+        return left.subSaturateSI16x8(right);
+      case SubSatUVecI16x8:
+        return left.subSaturateUI16x8(right);
+      case MulVecI16x8:
+        return left.mulI16x8(right);
+      case MinSVecI16x8:
+        return left.minSI16x8(right);
+      case MinUVecI16x8:
+        return left.minUI16x8(right);
+      case MaxSVecI16x8:
+        return left.maxSI16x8(right);
+      case MaxUVecI16x8:
+        return left.maxUI16x8(right);
+      case AvgrUVecI16x8:
+        return left.avgrUI16x8(right);
+      case AddVecI32x4:
+        return left.addI32x4(right);
+      case SubVecI32x4:
+        return left.subI32x4(right);
+      case MulVecI32x4:
+        return left.mulI32x4(right);
+      case MinSVecI32x4:
+        return left.minSI32x4(right);
+      case MinUVecI32x4:
+        return left.minUI32x4(right);
+      case MaxSVecI32x4:
+        return left.maxSI32x4(right);
+      case MaxUVecI32x4:
+        return left.maxUI32x4(right);
+      case DotSVecI16x8ToVecI32x4:
+        return left.dotSI16x8toI32x4(right);
+      case AddVecI64x2:
+        return left.addI64x2(right);
+      case SubVecI64x2:
+        return left.subI64x2(right);
+      case MulVecI64x2:
+        return left.mulI64x2(right);
+
+      case AddVecF32x4:
+        return left.addF32x4(right);
+      case SubVecF32x4:
+        return left.subF32x4(right);
+      case MulVecF32x4:
+        return left.mulF32x4(right);
+      case DivVecF32x4:
+        return left.divF32x4(right);
+      case MinVecF32x4:
+        return left.minF32x4(right);
+      case MaxVecF32x4:
+        return left.maxF32x4(right);
+      case PMinVecF32x4:
+        return left.pminF32x4(right);
+      case PMaxVecF32x4:
+        return left.pmaxF32x4(right);
+      case AddVecF64x2:
+        return left.addF64x2(right);
+      case SubVecF64x2:
+        return left.subF64x2(right);
+      case MulVecF64x2:
+        return left.mulF64x2(right);
+      case DivVecF64x2:
+        return left.divF64x2(right);
+      case MinVecF64x2:
+        return left.minF64x2(right);
+      case MaxVecF64x2:
+        return left.maxF64x2(right);
+      case PMinVecF64x2:
+        return left.pminF64x2(right);
+      case PMaxVecF64x2:
+        return left.pmaxF64x2(right);
+
+      case NarrowSVecI16x8ToVecI8x16:
+        return left.narrowSToVecI8x16(right);
+      case NarrowUVecI16x8ToVecI8x16:
+        return left.narrowUToVecI8x16(right);
+      case NarrowSVecI32x4ToVecI16x8:
+        return left.narrowSToVecI16x8(right);
+      case NarrowUVecI32x4ToVecI16x8:
+        return left.narrowUToVecI16x8(right);
+
+      case SwizzleVec8x16:
+        return left.swizzleVec8x16(right);
+
+      case InvalidBinary:
+        WASM_UNREACHABLE("invalid binary op");
+    }
+    WASM_UNREACHABLE("invalid op");
+  }
+  Flow visitSIMDExtract(SIMDExtract* curr) {
+    NOTE_ENTER("SIMDExtract");
+    Flow flow = this->visit(curr->vec);
+    if (flow.breaking()) {
+      return flow;
+    }
+    Literal vec = flow.getSingleValue();
+    switch (curr->op) {
+      case ExtractLaneSVecI8x16:
+        return vec.extractLaneSI8x16(curr->index);
+      case ExtractLaneUVecI8x16:
+        return vec.extractLaneUI8x16(curr->index);
+      case ExtractLaneSVecI16x8:
+        return vec.extractLaneSI16x8(curr->index);
+      case ExtractLaneUVecI16x8:
+        return vec.extractLaneUI16x8(curr->index);
+      case ExtractLaneVecI32x4:
+        return vec.extractLaneI32x4(curr->index);
+      case ExtractLaneVecI64x2:
+        return vec.extractLaneI64x2(curr->index);
+      case ExtractLaneVecF32x4:
+        return vec.extractLaneF32x4(curr->index);
+      case ExtractLaneVecF64x2:
+        return vec.extractLaneF64x2(curr->index);
+    }
+    WASM_UNREACHABLE("invalid op");
+  }
+  Flow visitSIMDReplace(SIMDReplace* curr) {
+    NOTE_ENTER("SIMDReplace");
+    Flow flow = this->visit(curr->vec);
+    if (flow.breaking()) {
+      return flow;
+    }
+    Literal vec = flow.getSingleValue();
+    flow = this->visit(curr->value);
+    if (flow.breaking()) {
+      return flow;
+    }
+    Literal value = flow.getSingleValue();
+    switch (curr->op) {
+      case ReplaceLaneVecI8x16:
+        return vec.replaceLaneI8x16(value, curr->index);
+      case ReplaceLaneVecI16x8:
+        return vec.replaceLaneI16x8(value, curr->index);
+      case ReplaceLaneVecI32x4:
+        return vec.replaceLaneI32x4(value, curr->index);
+      case ReplaceLaneVecI64x2:
+        return vec.replaceLaneI64x2(value, curr->index);
+      case ReplaceLaneVecF32x4:
+        return vec.replaceLaneF32x4(value, curr->index);
+      case ReplaceLaneVecF64x2:
+        return vec.replaceLaneF64x2(value, curr->index);
+    }
+    WASM_UNREACHABLE("invalid op");
+  }
+  Flow visitSIMDShuffle(SIMDShuffle* curr) {
+    NOTE_ENTER("SIMDShuffle");
+    Flow flow = this->visit(curr->left);
+    if (flow.breaking()) {
+      return flow;
+    }
+    Literal left = flow.getSingleValue();
+    flow = this->visit(curr->right);
+    if (flow.breaking()) {
+      return flow;
+    }
+    Literal right = flow.getSingleValue();
+    return left.shuffleV8x16(right, curr->mask);
+  }
+  Flow visitSIMDTernary(SIMDTernary* curr) {
+    NOTE_ENTER("SIMDBitselect");
+    Flow flow = this->visit(curr->a);
+    if (flow.breaking()) {
+      return flow;
+    }
+    Literal a = flow.getSingleValue();
+    flow = this->visit(curr->b);
+    if (flow.breaking()) {
+      return flow;
+    }
+    Literal b = flow.getSingleValue();
+    flow = this->visit(curr->c);
+    if (flow.breaking()) {
+      return flow;
+    }
+    Literal c = flow.getSingleValue();
+    switch (curr->op) {
+      case Bitselect:
+        return c.bitselectV128(a, b);
+      default:
+        // TODO: implement qfma/qfms
+        WASM_UNREACHABLE("not implemented");
+    }
+  }
+  Flow visitSIMDShift(SIMDShift* curr) {
+    NOTE_ENTER("SIMDShift");
+    Flow flow = this->visit(curr->vec);
+    if (flow.breaking()) {
+      return flow;
+    }
+    Literal vec = flow.getSingleValue();
+    flow = this->visit(curr->shift);
+    if (flow.breaking()) {
+      return flow;
+    }
+    Literal shift = flow.getSingleValue();
+    switch (curr->op) {
+      case ShlVecI8x16:
+        return vec.shlI8x16(shift);
+      case ShrSVecI8x16:
+        return vec.shrSI8x16(shift);
+      case ShrUVecI8x16:
+        return vec.shrUI8x16(shift);
+      case ShlVecI16x8:
+        return vec.shlI16x8(shift);
+      case ShrSVecI16x8:
+        return vec.shrSI16x8(shift);
+      case ShrUVecI16x8:
+        return vec.shrUI16x8(shift);
+      case ShlVecI32x4:
+        return vec.shlI32x4(shift);
+      case ShrSVecI32x4:
+        return vec.shrSI32x4(shift);
+      case ShrUVecI32x4:
+        return vec.shrUI32x4(shift);
+      case ShlVecI64x2:
+        return vec.shlI64x2(shift);
+      case ShrSVecI64x2:
+        return vec.shrSI64x2(shift);
+      case ShrUVecI64x2:
+        return vec.shrUI64x2(shift);
+    }
+    WASM_UNREACHABLE("invalid op");
+  }
+  Flow visitSelect(Select* curr) {
+    NOTE_ENTER("Select");
+    Flow ifTrue = visit(curr->ifTrue);
+    if (ifTrue.breaking()) {
+      return ifTrue;
+    }
+    Flow ifFalse = visit(curr->ifFalse);
+    if (ifFalse.breaking()) {
+      return ifFalse;
+    }
+    Flow condition = visit(curr->condition);
+    if (condition.breaking()) {
+      return condition;
+    }
+    NOTE_EVAL1(condition.getSingleValue());
+    return condition.getSingleValue().geti32() ? ifTrue : ifFalse; // ;-)
+  }
+  Flow visitDrop(Drop* curr) {
+    NOTE_ENTER("Drop");
+    Flow value = visit(curr->value);
+    if (value.breaking()) {
+      return value;
+    }
+    return Flow();
+  }
+  Flow visitReturn(Return* curr) {
+    NOTE_ENTER("Return");
+    Flow flow;
+    if (curr->value) {
+      flow = visit(curr->value);
+      if (flow.breaking()) {
+        return flow;
+      }
+      NOTE_EVAL1(flow.getSingleValue());
+    }
+    flow.breakTo = RETURN_FLOW;
+    return flow;
+  }
+  Flow visitNop(Nop* curr) {
+    NOTE_ENTER("Nop");
+    return Flow();
+  }
+  Flow visitUnreachable(Unreachable* curr) {
+    NOTE_ENTER("Unreachable");
+    trap("unreachable");
+    WASM_UNREACHABLE("unreachable");
+  }
+
+  Literal truncSFloat(Unary* curr, Literal value) {
+    double val = value.getFloat();
+    if (std::isnan(val)) {
+      trap("truncSFloat of nan");
+    }
+    if (curr->type == Type::i32) {
+      if (value.type == Type::f32) {
+        if (!isInRangeI32TruncS(value.reinterpreti32())) {
+          trap("i32.truncSFloat overflow");
+        }
+      } else {
+        if (!isInRangeI32TruncS(value.reinterpreti64())) {
+          trap("i32.truncSFloat overflow");
+        }
+      }
+      return Literal(int32_t(val));
+    } else {
+      if (value.type == Type::f32) {
+        if (!isInRangeI64TruncS(value.reinterpreti32())) {
+          trap("i64.truncSFloat overflow");
+        }
+      } else {
+        if (!isInRangeI64TruncS(value.reinterpreti64())) {
+          trap("i64.truncSFloat overflow");
+        }
+      }
+      return Literal(int64_t(val));
+    }
+  }
+
+  Literal truncUFloat(Unary* curr, Literal value) {
+    double val = value.getFloat();
+    if (std::isnan(val)) {
+      trap("truncUFloat of nan");
+    }
+    if (curr->type == Type::i32) {
+      if (value.type == Type::f32) {
+        if (!isInRangeI32TruncU(value.reinterpreti32())) {
+          trap("i32.truncUFloat overflow");
+        }
+      } else {
+        if (!isInRangeI32TruncU(value.reinterpreti64())) {
+          trap("i32.truncUFloat overflow");
+        }
+      }
+      return Literal(uint32_t(val));
+    } else {
+      if (value.type == Type::f32) {
+        if (!isInRangeI64TruncU(value.reinterpreti32())) {
+          trap("i64.truncUFloat overflow");
+        }
+      } else {
+        if (!isInRangeI64TruncU(value.reinterpreti64())) {
+          trap("i64.truncUFloat overflow");
+        }
+      }
+      return Literal(uint64_t(val));
+    }
+  }
+  Flow visitAtomicFence(AtomicFence* curr) {
+    // Wasm currently supports only sequentially consistent atomics, in which
+    // case atomic_fence can be lowered to nothing.
+    NOTE_ENTER("AtomicFence");
+    return Flow();
+  }
+  Flow visitTupleMake(TupleMake* curr) {
+    NOTE_ENTER("tuple.make");
+    LiteralList arguments;
+    Flow flow = generateArguments(curr->operands, arguments);
+    if (flow.breaking()) {
+      return flow;
+    }
+    for (auto arg : arguments) {
+      assert(arg.type.isConcrete());
+      flow.values.push_back(arg);
+    }
+    return flow;
+  }
+  Flow visitTupleExtract(TupleExtract* curr) {
+    NOTE_ENTER("tuple.extract");
+    Flow flow = visit(curr->tuple);
+    if (flow.breaking()) {
+      return flow;
+    }
+    assert(flow.values.size() > curr->index);
+    return Flow(flow.values[curr->index]);
+  }
+  Flow visitLocalGet(LocalGet* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitLocalSet(LocalSet* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitGlobalGet(GlobalGet* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitGlobalSet(GlobalSet* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitCall(Call* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitCallIndirect(CallIndirect* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitLoad(Load* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitStore(Store* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitMemorySize(MemorySize* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitMemoryGrow(MemoryGrow* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitMemoryInit(MemoryInit* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitDataDrop(DataDrop* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitMemoryCopy(MemoryCopy* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitMemoryFill(MemoryFill* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitAtomicRMW(AtomicRMW* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitAtomicCmpxchg(AtomicCmpxchg* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitAtomicWait(AtomicWait* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitAtomicNotify(AtomicNotify* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitSIMDLoad(SIMDLoad* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitSIMDLoadSplat(SIMDLoad* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitSIMDLoadExtend(SIMDLoad* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitSIMDLoadZero(SIMDLoad* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitPop(Pop* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitRefNull(RefNull* curr) {
+    NOTE_ENTER("RefNull");
+    return Literal::makeNull(curr->type);
+  }
+  Flow visitRefIsNull(RefIsNull* curr) {
+    NOTE_ENTER("RefIsNull");
+    Flow flow = visit(curr->value);
+    if (flow.breaking()) {
+      return flow;
+    }
+    const auto& value = flow.getSingleValue();
+    NOTE_EVAL1(value);
+    return Literal(value.isNull());
+  }
+  Flow visitRefFunc(RefFunc* curr) {
+    NOTE_ENTER("RefFunc");
+    NOTE_NAME(curr->func);
+    return Literal::makeFunc(curr->func);
+  }
+  Flow visitRefEq(RefEq* curr) {
+    NOTE_ENTER("RefEq");
+    Flow flow = visit(curr->left);
+    if (flow.breaking()) {
+      return flow;
+    }
+    auto left = flow.getSingleValue();
+    flow = visit(curr->right);
+    if (flow.breaking()) {
+      return flow;
+    }
+    auto right = flow.getSingleValue();
+    NOTE_EVAL2(left, right);
+    return Literal(int32_t(left == right));
+  }
+  Flow visitTry(Try* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitThrow(Throw* curr) {
+    NOTE_ENTER("Throw");
+    LiteralList arguments;
+    Flow flow = generateArguments(curr->operands, arguments);
+    if (flow.breaking()) {
+      return flow;
+    }
+    NOTE_EVAL1(curr->event);
+    auto exn = std::make_unique<ExceptionPackage>();
+    exn->event = curr->event;
+    for (auto item : arguments) {
+      exn->values.push_back(item);
+    }
+    throwException(Literal::makeExn(std::move(exn)));
+    WASM_UNREACHABLE("throw");
+  }
+  Flow visitRethrow(Rethrow* curr) {
+    NOTE_ENTER("Rethrow");
+    Flow flow = visit(curr->exnref);
+    if (flow.breaking()) {
+      return flow;
+    }
+    const auto& value = flow.getSingleValue();
+    if (value.isNull()) {
+      trap("rethrow: argument is null");
+    }
+    throwException(value);
+    WASM_UNREACHABLE("rethrow");
+  }
+  Flow visitBrOnExn(BrOnExn* curr) {
+    NOTE_ENTER("BrOnExn");
+    Flow flow = this->visit(curr->exnref);
+    if (flow.breaking()) {
+      return flow;
+    }
+    const auto& value = flow.getSingleValue();
+    if (value.isNull()) {
+      trap("br_on_exn: argument is null");
+    }
+    auto ex = value.getExceptionPackage();
+    if (curr->event != ex.event) { // Not taken
+      return flow;
+    }
+    // Taken
+    flow.values = ex.values;
+    flow.breakTo = curr->name;
+    return flow;
+  }
+  Flow visitI31New(I31New* curr) {
+    NOTE_ENTER("I31New");
+    Flow flow = visit(curr->value);
+    if (flow.breaking()) {
+      return flow;
+    }
+    const auto& value = flow.getSingleValue();
+    NOTE_EVAL1(value);
+    return Literal::makeI31(value.geti32());
+  }
+  Flow visitI31Get(I31Get* curr) {
+    NOTE_ENTER("I31Get");
+    Flow flow = visit(curr->i31);
+    if (flow.breaking()) {
+      return flow;
+    }
+    const auto& value = flow.getSingleValue();
+    NOTE_EVAL1(value);
+    return Literal(value.geti31(curr->signed_));
+  }
+  Flow visitRefTest(RefTest* curr) {
+    NOTE_ENTER("RefTest");
+    WASM_UNREACHABLE("TODO (gc): ref.test");
+  }
+  Flow visitRefCast(RefCast* curr) {
+    NOTE_ENTER("RefCast");
+    WASM_UNREACHABLE("TODO (gc): ref.cast");
+  }
+  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");
+  }
+  Flow visitRttSub(RttSub* curr) {
+    NOTE_ENTER("RttSub");
+    WASM_UNREACHABLE("TODO (gc): rtt.sub");
+  }
+  Flow visitStructNew(StructNew* curr) {
+    NOTE_ENTER("StructNew");
+    WASM_UNREACHABLE("TODO (gc): struct.new");
+  }
+  Flow visitStructGet(StructGet* curr) {
+    NOTE_ENTER("StructGet");
+    WASM_UNREACHABLE("TODO (gc): struct.get");
+  }
+  Flow visitStructSet(StructSet* curr) {
+    NOTE_ENTER("StructSet");
+    WASM_UNREACHABLE("TODO (gc): struct.set");
+  }
+  Flow visitArrayNew(ArrayNew* curr) {
+    NOTE_ENTER("ArrayNew");
+    WASM_UNREACHABLE("TODO (gc): array.new");
+  }
+  Flow visitArrayGet(ArrayGet* curr) {
+    NOTE_ENTER("ArrayGet");
+    WASM_UNREACHABLE("TODO (gc): array.get");
+  }
+  Flow visitArraySet(ArraySet* curr) {
+    NOTE_ENTER("ArraySet");
+    WASM_UNREACHABLE("TODO (gc): array.set");
+  }
+  Flow visitArrayLen(ArrayLen* curr) {
+    NOTE_ENTER("ArrayLen");
+    WASM_UNREACHABLE("TODO (gc): array.len");
+  }
+
+  virtual void trap(const char* why) { WASM_UNREACHABLE("unimp"); }
+
+  virtual void throwException(Literal exn) { WASM_UNREACHABLE("unimp"); }
+};
+
+// Execute a suspected constant expression (precompute and C-API).
+template<typename SubType>
+class ConstantExpressionRunner : public ExpressionRunner<SubType> {
+public:
+  enum FlagValues {
+    // By default, just evaluate the expression, i.e. all we want to know is
+    // whether it computes down to a concrete value, where it is not necessary
+    // to preserve side effects like those of a `local.tee`.
+    DEFAULT = 0,
+    // Be very careful to preserve any side effects. For example, if we are
+    // intending to replace the expression with a constant afterwards, even if
+    // we can technically evaluate down to a constant, we still cannot replace
+    // the expression if it also sets a local, which must be preserved in this
+    // scenario so subsequent code keeps functioning.
+    PRESERVE_SIDEEFFECTS = 1 << 0,
+    // Traverse through function calls, attempting to compute their concrete
+    // value. Must not be used in function-parallel scenarios, where the called
+    // function might be concurrently modified, leading to undefined behavior.
+    TRAVERSE_CALLS = 1 << 1
+  };
+
+  // Flags indicating special requirements, for example whether we are just
+  // evaluating (default), also going to replace the expression afterwards or
+  // executing in a function-parallel scenario. See FlagValues.
+  typedef uint32_t Flags;
+
+  // Indicates no limit of maxDepth or maxLoopIterations.
+  static const Index NO_LIMIT = 0;
+
+protected:
+  // Optional module context to search for globals and called functions. NULL if
+  // we are not interested in any context.
+  Module* module = nullptr;
+
+  // Flags indicating special requirements. See FlagValues.
+  Flags flags = FlagValues::DEFAULT;
+
+  // Map remembering concrete local values set in the context of this flow.
+  std::unordered_map<Index, Literals> localValues;
+  // Map remembering concrete global values set in the context of this flow.
+  std::unordered_map<Name, Literals> globalValues;
+
+public:
+  struct NonconstantException {
+  }; // TODO: use a flow with a special name, as this is likely very slow
+
+  ConstantExpressionRunner(Module* module,
+                           Flags flags,
+                           Index maxDepth,
+                           Index maxLoopIterations)
+    : ExpressionRunner<SubType>(maxDepth, maxLoopIterations), module(module),
+      flags(flags) {}
+
+  // Gets the module this runner is operating on.
+  Module* getModule() { return module; }
+
+  // Sets a known local value to use.
+  void setLocalValue(Index index, Literals& values) {
+    assert(values.isConcrete());
+    localValues[index] = values;
+  }
+
+  // Sets a known global value to use.
+  void setGlobalValue(Name name, Literals& values) {
+    assert(values.isConcrete());
+    globalValues[name] = values;
+  }
+
+  Flow visitLocalGet(LocalGet* curr) {
+    NOTE_ENTER("LocalGet");
+    NOTE_EVAL1(curr->index);
+    // Check if a constant value has been set in the context of this runner.
+    auto iter = localValues.find(curr->index);
+    if (iter != localValues.end()) {
+      return Flow(iter->second);
+    }
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitLocalSet(LocalSet* curr) {
+    NOTE_ENTER("LocalSet");
+    NOTE_EVAL1(curr->index);
+    if (!(flags & FlagValues::PRESERVE_SIDEEFFECTS)) {
+      // If we are evaluating and not replacing the expression, remember the
+      // constant value set, if any, and see if there is a value flowing through
+      // a tee.
+      auto setFlow = ExpressionRunner<SubType>::visit(curr->value);
+      if (!setFlow.breaking()) {
+        setLocalValue(curr->index, setFlow.values);
+        if (curr->type.isConcrete()) {
+          assert(curr->isTee());
+          return setFlow;
+        }
+        return Flow();
+      }
+    }
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitGlobalGet(GlobalGet* curr) {
+    NOTE_ENTER("GlobalGet");
+    NOTE_NAME(curr->name);
+    if (module != nullptr) {
+      auto* global = module->getGlobal(curr->name);
+      // Check if the global has an immutable value anyway
+      if (!global->imported() && !global->mutable_) {
+        return ExpressionRunner<SubType>::visit(global->init);
+      }
+    }
+    // Check if a constant value has been set in the context of this runner.
+    auto iter = globalValues.find(curr->name);
+    if (iter != globalValues.end()) {
+      return Flow(iter->second);
+    }
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitGlobalSet(GlobalSet* curr) {
+    NOTE_ENTER("GlobalSet");
+    NOTE_NAME(curr->name);
+    if (!(flags & FlagValues::PRESERVE_SIDEEFFECTS) && module != nullptr) {
+      // If we are evaluating and not replacing the expression, remember the
+      // constant value set, if any, for subsequent gets.
+      auto* global = module->getGlobal(curr->name);
+      assert(global->mutable_);
+      auto setFlow = ExpressionRunner<SubType>::visit(curr->value);
+      if (!setFlow.breaking()) {
+        setGlobalValue(curr->name, setFlow.values);
+        return Flow();
+      }
+    }
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitCall(Call* curr) {
+    NOTE_ENTER("Call");
+    NOTE_NAME(curr->target);
+    // Traverse into functions using the same mode, which we can also do
+    // when replacing as long as the function does not have any side effects.
+    // Might yield something useful for simple functions like `clamp`, sometimes
+    // even if arguments are only partially constant or not constant at all.
+    if ((flags & FlagValues::TRAVERSE_CALLS) != 0 && module != nullptr) {
+      auto* func = module->getFunction(curr->target);
+      if (!func->imported()) {
+        if (func->sig.results.isConcrete()) {
+          auto numOperands = curr->operands.size();
+          assert(numOperands == func->getNumParams());
+          auto prevLocalValues = localValues;
+          localValues.clear();
+          for (Index i = 0; i < numOperands; ++i) {
+            auto argFlow = ExpressionRunner<SubType>::visit(curr->operands[i]);
+            if (!argFlow.breaking()) {
+              assert(argFlow.values.isConcrete());
+              localValues[i] = argFlow.values;
+            }
+          }
+          auto retFlow = ExpressionRunner<SubType>::visit(func->body);
+          localValues = prevLocalValues;
+          if (retFlow.breakTo == RETURN_FLOW) {
+            return Flow(retFlow.values);
+          } else if (!retFlow.breaking()) {
+            return retFlow;
+          }
+        }
+      }
+    }
+    return Flow(NONCONSTANT_FLOW);
+  }
+
+  Flow visitCallIndirect(CallIndirect* curr) {
+    NOTE_ENTER("CallIndirect");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitLoad(Load* curr) {
+    NOTE_ENTER("Load");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitStore(Store* curr) {
+    NOTE_ENTER("Store");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitMemorySize(MemorySize* curr) {
+    NOTE_ENTER("MemorySize");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitMemoryGrow(MemoryGrow* curr) {
+    NOTE_ENTER("MemoryGrow");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitMemoryInit(MemoryInit* curr) {
+    NOTE_ENTER("MemoryInit");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitDataDrop(DataDrop* curr) {
+    NOTE_ENTER("DataDrop");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitMemoryCopy(MemoryCopy* curr) {
+    NOTE_ENTER("MemoryCopy");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitMemoryFill(MemoryFill* curr) {
+    NOTE_ENTER("MemoryFill");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitAtomicRMW(AtomicRMW* curr) {
+    NOTE_ENTER("AtomicRMW");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+    NOTE_ENTER("AtomicCmpxchg");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitAtomicWait(AtomicWait* curr) {
+    NOTE_ENTER("AtomicWait");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitAtomicNotify(AtomicNotify* curr) {
+    NOTE_ENTER("AtomicNotify");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitSIMDLoad(SIMDLoad* curr) {
+    NOTE_ENTER("SIMDLoad");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitSIMDLoadSplat(SIMDLoad* curr) {
+    NOTE_ENTER("SIMDLoadSplat");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitSIMDLoadExtend(SIMDLoad* curr) {
+    NOTE_ENTER("SIMDLoadExtend");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitPop(Pop* curr) {
+    NOTE_ENTER("Pop");
+    return Flow(NONCONSTANT_FLOW);
+  }
+  Flow visitTry(Try* curr) {
+    NOTE_ENTER("Try");
+    return Flow(NONCONSTANT_FLOW);
+  }
+
+  void trap(const char* why) override { throw NonconstantException(); }
+
+  virtual void throwException(Literal exn) override {
+    throw NonconstantException();
+  }
+};
+
+// Execute an initializer expression of a global, data or element segment.
+// see: https://webassembly.org/docs/modules/#initializer-expression
+template<typename GlobalManager>
+class InitializerExpressionRunner
+  : public ExpressionRunner<InitializerExpressionRunner<GlobalManager>> {
+  GlobalManager& globals;
+
+public:
+  InitializerExpressionRunner(GlobalManager& globals, Index maxDepth)
+    : ExpressionRunner<InitializerExpressionRunner<GlobalManager>>(maxDepth),
+      globals(globals) {}
+
+  Flow visitGlobalGet(GlobalGet* curr) { return Flow(globals[curr->name]); }
+};
+
+//
+// An instance of a WebAssembly module, which can execute it via AST
+// interpretation.
+//
+// To embed this interpreter, you need to provide an ExternalInterface instance
+// (see below) which provides the embedding-specific details, that is, how to
+// connect to the embedding implementation.
+//
+// To call into the interpreter, use callExport.
+//
+
+template<typename GlobalManager, typename SubType> class ModuleInstanceBase {
+public:
+  //
+  // You need to implement one of these to create a concrete interpreter. The
+  // ExternalInterface provides embedding-specific functionality like calling
+  // an imported function or accessing memory.
+  //
+  struct ExternalInterface {
+    virtual void init(Module& wasm, SubType& instance) {}
+    virtual void importGlobals(GlobalManager& globals, Module& wasm) = 0;
+    virtual Literals callImport(Function* import, LiteralList& arguments) = 0;
+    virtual Literals callTable(Index index,
+                               Signature sig,
+                               LiteralList& arguments,
+                               Type result,
+                               SubType& instance) = 0;
+    virtual bool growMemory(Address oldSize, Address newSize) = 0;
+    virtual void trap(const char* why) = 0;
+    virtual void throwException(Literal exnref) = 0;
+
+    // the default impls for load and store switch on the sizes. you can either
+    // customize load/store, or the sub-functions which they call
+    virtual Literal load(Load* load, Address addr) {
+      switch (load->type.getBasic()) {
+        case Type::i32: {
+          switch (load->bytes) {
+            case 1:
+              return load->signed_ ? Literal((int32_t)load8s(addr))
+                                   : Literal((int32_t)load8u(addr));
+            case 2:
+              return load->signed_ ? Literal((int32_t)load16s(addr))
+                                   : Literal((int32_t)load16u(addr));
+            case 4:
+              return Literal((int32_t)load32s(addr));
+            default:
+              WASM_UNREACHABLE("invalid size");
+          }
+          break;
+        }
+        case Type::i64: {
+          switch (load->bytes) {
+            case 1:
+              return load->signed_ ? Literal((int64_t)load8s(addr))
+                                   : Literal((int64_t)load8u(addr));
+            case 2:
+              return load->signed_ ? Literal((int64_t)load16s(addr))
+                                   : Literal((int64_t)load16u(addr));
+            case 4:
+              return load->signed_ ? Literal((int64_t)load32s(addr))
+                                   : Literal((int64_t)load32u(addr));
+            case 8:
+              return Literal((int64_t)load64s(addr));
+            default:
+              WASM_UNREACHABLE("invalid size");
+          }
+          break;
+        }
+        case Type::f32:
+          return Literal(load32u(addr)).castToF32();
+        case Type::f64:
+          return Literal(load64u(addr)).castToF64();
+        case Type::v128:
+          return Literal(load128(addr).data());
+        case Type::funcref:
+        case Type::externref:
+        case Type::exnref:
+        case Type::anyref:
+        case Type::eqref:
+        case Type::i31ref:
+        case Type::none:
+        case Type::unreachable:
+          WASM_UNREACHABLE("unexpected type");
+      }
+      WASM_UNREACHABLE("invalid type");
+    }
+    virtual void store(Store* store, Address addr, Literal value) {
+      switch (store->valueType.getBasic()) {
+        case Type::i32: {
+          switch (store->bytes) {
+            case 1:
+              store8(addr, value.geti32());
+              break;
+            case 2:
+              store16(addr, value.geti32());
+              break;
+            case 4:
+              store32(addr, value.geti32());
+              break;
+            default:
+              WASM_UNREACHABLE("invalid store size");
+          }
+          break;
+        }
+        case Type::i64: {
+          switch (store->bytes) {
+            case 1:
+              store8(addr, value.geti64());
+              break;
+            case 2:
+              store16(addr, value.geti64());
+              break;
+            case 4:
+              store32(addr, value.geti64());
+              break;
+            case 8:
+              store64(addr, value.geti64());
+              break;
+            default:
+              WASM_UNREACHABLE("invalid store size");
+          }
+          break;
+        }
+        // write floats carefully, ensuring all bits reach memory
+        case Type::f32:
+          store32(addr, value.reinterpreti32());
+          break;
+        case Type::f64:
+          store64(addr, value.reinterpreti64());
+          break;
+        case Type::v128:
+          store128(addr, value.getv128());
+          break;
+        case Type::funcref:
+        case Type::externref:
+        case Type::exnref:
+        case Type::anyref:
+        case Type::eqref:
+        case Type::i31ref:
+        case Type::none:
+        case Type::unreachable:
+          WASM_UNREACHABLE("unexpected type");
+      }
+    }
+
+    virtual int8_t load8s(Address addr) { WASM_UNREACHABLE("unimp"); }
+    virtual uint8_t load8u(Address addr) { WASM_UNREACHABLE("unimp"); }
+    virtual int16_t load16s(Address addr) { WASM_UNREACHABLE("unimp"); }
+    virtual uint16_t load16u(Address addr) { WASM_UNREACHABLE("unimp"); }
+    virtual int32_t load32s(Address addr) { WASM_UNREACHABLE("unimp"); }
+    virtual uint32_t load32u(Address addr) { WASM_UNREACHABLE("unimp"); }
+    virtual int64_t load64s(Address addr) { WASM_UNREACHABLE("unimp"); }
+    virtual uint64_t load64u(Address addr) { WASM_UNREACHABLE("unimp"); }
+    virtual std::array<uint8_t, 16> load128(Address addr) {
+      WASM_UNREACHABLE("unimp");
+    }
+
+    virtual void store8(Address addr, int8_t value) {
+      WASM_UNREACHABLE("unimp");
+    }
+    virtual void store16(Address addr, int16_t value) {
+      WASM_UNREACHABLE("unimp");
+    }
+    virtual void store32(Address addr, int32_t value) {
+      WASM_UNREACHABLE("unimp");
+    }
+    virtual void store64(Address addr, int64_t value) {
+      WASM_UNREACHABLE("unimp");
+    }
+    virtual void store128(Address addr, const std::array<uint8_t, 16>&) {
+      WASM_UNREACHABLE("unimp");
+    }
+
+    virtual void tableStore(Address addr, Name entry) {
+      WASM_UNREACHABLE("unimp");
+    }
+  };
+
+  SubType* self() { return static_cast<SubType*>(this); }
+
+  Module& wasm;
+
+  // Values of globals
+  GlobalManager globals;
+
+  // Multivalue ABI support (see push/pop).
+  std::vector<Literal> multiValues;
+
+  ModuleInstanceBase(Module& wasm, ExternalInterface* externalInterface)
+    : wasm(wasm), externalInterface(externalInterface) {
+    // import globals from the outside
+    externalInterface->importGlobals(globals, wasm);
+    // prepare memory
+    memorySize = wasm.memory.initial;
+    // generate internal (non-imported) globals
+    ModuleUtils::iterDefinedGlobals(wasm, [&](Global* global) {
+      globals[global->name] =
+        InitializerExpressionRunner<GlobalManager>(globals, maxDepth)
+          .visit(global->init)
+          .values;
+    });
+
+    // initialize the rest of the external interface
+    externalInterface->init(wasm, *self());
+
+    initializeTableContents();
+    initializeMemoryContents();
+
+    // run start, if present
+    if (wasm.start.is()) {
+      LiteralList arguments;
+      callFunction(wasm.start, arguments);
+    }
+  }
+
+  // call an exported function
+  Literals callExport(Name name, const LiteralList& arguments) {
+    Export* export_ = wasm.getExportOrNull(name);
+    if (!export_) {
+      externalInterface->trap("callExport not found");
+    }
+    return callFunction(export_->value, arguments);
+  }
+
+  Literals callExport(Name name) { return callExport(name, LiteralList()); }
+
+  // get an exported global
+  Literals getExport(Name name) {
+    Export* export_ = wasm.getExportOrNull(name);
+    if (!export_) {
+      externalInterface->trap("getExport external not found");
+    }
+    Name internalName = export_->value;
+    auto iter = globals.find(internalName);
+    if (iter == globals.end()) {
+      externalInterface->trap("getExport internal not found");
+    }
+    return iter->second;
+  }
+
+  std::string printFunctionStack() {
+    std::string ret = "/== (binaryen interpreter stack trace)\n";
+    for (int i = int(functionStack.size()) - 1; i >= 0; i--) {
+      ret += std::string("|: ") + functionStack[i].str + "\n";
+    }
+    ret += std::string("\\==\n");
+    return ret;
+  }
+
+private:
+  // Keep a record of call depth, to guard against excessive recursion.
+  size_t callDepth;
+
+  // Function name stack. We maintain this explicitly to allow printing of
+  // stack traces.
+  std::vector<Name> functionStack;
+
+  std::unordered_set<size_t> droppedSegments;
+
+  void initializeTableContents() {
+    for (auto& segment : wasm.table.segments) {
+      Address offset =
+        (uint32_t)InitializerExpressionRunner<GlobalManager>(globals, maxDepth)
+          .visit(segment.offset)
+          .getSingleValue()
+          .geti32();
+      if (offset + segment.data.size() > wasm.table.initial) {
+        externalInterface->trap("invalid offset when initializing table");
+      }
+      for (size_t i = 0; i != segment.data.size(); ++i) {
+        externalInterface->tableStore(offset + i, segment.data[i]);
+      }
+    }
+  }
+
+  void initializeMemoryContents() {
+    Const offset;
+    offset.value = Literal(uint32_t(0));
+    offset.finalize();
+
+    // apply active memory segments
+    for (size_t i = 0, e = wasm.memory.segments.size(); i < e; ++i) {
+      Memory::Segment& segment = wasm.memory.segments[i];
+      if (segment.isPassive) {
+        continue;
+      }
+
+      Const size;
+      size.value = Literal(uint32_t(segment.data.size()));
+      size.finalize();
+
+      MemoryInit init;
+      init.segment = i;
+      init.dest = segment.offset;
+      init.offset = &offset;
+      init.size = &size;
+      init.finalize();
+
+      DataDrop drop;
+      drop.segment = i;
+      drop.finalize();
+
+      // we don't actually have a function, but we need one in order to visit
+      // the memory.init and data.drop instructions.
+      Function dummyFunc;
+      FunctionScope dummyScope(&dummyFunc, {});
+      RuntimeExpressionRunner runner(*this, dummyScope, maxDepth);
+      runner.visit(&init);
+      runner.visit(&drop);
+    }
+  }
+
+  class FunctionScope {
+  public:
+    std::vector<Literals> locals;
+    Function* function;
+
+    FunctionScope(Function* function, const LiteralList& arguments)
+      : function(function) {
+      if (function->sig.params.size() != arguments.size()) {
+        std::cerr << "Function `" << function->name << "` expects "
+                  << function->sig.params.size() << " parameters, got "
+                  << arguments.size() << " arguments." << std::endl;
+        WASM_UNREACHABLE("invalid param count");
+      }
+      locals.resize(function->getNumLocals());
+      for (size_t i = 0; i < function->getNumLocals(); i++) {
+        if (i < arguments.size()) {
+          if (!Type::isSubType(arguments[i].type, function->sig.params[i])) {
+            std::cerr << "Function `" << function->name << "` expects type "
+                      << function->sig.params[i] << " for parameter " << i
+                      << ", got " << arguments[i].type << "." << std::endl;
+            WASM_UNREACHABLE("invalid param count");
+          }
+          locals[i] = {arguments[i]};
+        } else {
+          assert(function->isVar(i));
+          locals[i] = Literal::makeZeros(function->getLocalType(i));
+        }
+      }
+    }
+  };
+
+  // Executes expressions with concrete runtime info, the function and module at
+  // runtime
+  class RuntimeExpressionRunner
+    : public ExpressionRunner<RuntimeExpressionRunner> {
+    ModuleInstanceBase& instance;
+    FunctionScope& scope;
+
+  public:
+    RuntimeExpressionRunner(ModuleInstanceBase& instance,
+                            FunctionScope& scope,
+                            Index maxDepth)
+      : ExpressionRunner<RuntimeExpressionRunner>(maxDepth), instance(instance),
+        scope(scope) {}
+
+    Flow visitCall(Call* curr) {
+      NOTE_ENTER("Call");
+      NOTE_NAME(curr->target);
+      LiteralList arguments;
+      Flow flow = this->generateArguments(curr->operands, arguments);
+      if (flow.breaking()) {
+        return flow;
+      }
+      auto* func = instance.wasm.getFunction(curr->target);
+      Flow ret;
+      if (func->imported()) {
+        ret.values = instance.externalInterface->callImport(func, arguments);
+      } else {
+        ret.values = instance.callFunctionInternal(curr->target, 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 visitCallIndirect(CallIndirect* curr) {
+      NOTE_ENTER("CallIndirect");
+      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;
+      }
+      Index index = target.getSingleValue().geti32();
+      Type type = curr->isReturn ? scope.function->sig.results : curr->type;
+      Flow ret = instance.externalInterface->callTable(
+        index, curr->sig, arguments, type, *instance.self());
+      // 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");
+      auto index = curr->index;
+      NOTE_EVAL1(index);
+      NOTE_EVAL1(scope.locals[index]);
+      return scope.locals[index];
+    }
+    Flow visitLocalSet(LocalSet* curr) {
+      NOTE_ENTER("LocalSet");
+      auto index = curr->index;
+      Flow flow = this->visit(curr->value);
+      if (flow.breaking()) {
+        return flow;
+      }
+      NOTE_EVAL1(index);
+      NOTE_EVAL1(flow.getSingleValue());
+      assert(curr->isTee() ? Type::isSubType(flow.getType(), curr->type)
+                           : true);
+      scope.locals[index] = flow.values;
+      return curr->isTee() ? flow : Flow();
+    }
+
+    Flow visitGlobalGet(GlobalGet* curr) {
+      NOTE_ENTER("GlobalGet");
+      auto name = curr->name;
+      NOTE_EVAL1(name);
+      assert(instance.globals.find(name) != instance.globals.end());
+      NOTE_EVAL1(instance.globals[name]);
+      return instance.globals[name];
+    }
+    Flow visitGlobalSet(GlobalSet* curr) {
+      NOTE_ENTER("GlobalSet");
+      auto name = curr->name;
+      Flow flow = this->visit(curr->value);
+      if (flow.breaking()) {
+        return flow;
+      }
+      NOTE_EVAL1(name);
+      NOTE_EVAL1(flow.getSingleValue());
+      instance.globals[name] = flow.values;
+      return Flow();
+    }
+
+    Flow visitLoad(Load* curr) {
+      NOTE_ENTER("Load");
+      Flow flow = this->visit(curr->ptr);
+      if (flow.breaking()) {
+        return flow;
+      }
+      NOTE_EVAL1(flow);
+      auto addr = instance.getFinalAddress(curr, flow.getSingleValue());
+      if (curr->isAtomic) {
+        instance.checkAtomicAddress(addr, curr->bytes);
+      }
+      auto ret = instance.externalInterface->load(curr, addr);
+      NOTE_EVAL1(addr);
+      NOTE_EVAL1(ret);
+      return ret;
+    }
+    Flow visitStore(Store* curr) {
+      NOTE_ENTER("Store");
+      Flow ptr = this->visit(curr->ptr);
+      if (ptr.breaking()) {
+        return ptr;
+      }
+      Flow value = this->visit(curr->value);
+      if (value.breaking()) {
+        return value;
+      }
+      auto addr = instance.getFinalAddress(curr, ptr.getSingleValue());
+      if (curr->isAtomic) {
+        instance.checkAtomicAddress(addr, curr->bytes);
+      }
+      NOTE_EVAL1(addr);
+      NOTE_EVAL1(value);
+      instance.externalInterface->store(curr, addr, value.getSingleValue());
+      return Flow();
+    }
+
+    Flow visitAtomicRMW(AtomicRMW* curr) {
+      NOTE_ENTER("AtomicRMW");
+      Flow ptr = this->visit(curr->ptr);
+      if (ptr.breaking()) {
+        return ptr;
+      }
+      auto value = this->visit(curr->value);
+      if (value.breaking()) {
+        return value;
+      }
+      NOTE_EVAL1(ptr);
+      auto addr = instance.getFinalAddress(curr, ptr.getSingleValue());
+      NOTE_EVAL1(addr);
+      NOTE_EVAL1(value);
+      auto loaded = instance.doAtomicLoad(addr, curr->bytes, curr->type);
+      NOTE_EVAL1(loaded);
+      auto computed = value.getSingleValue();
+      switch (curr->op) {
+        case Add:
+          computed = loaded.add(computed);
+          break;
+        case Sub:
+          computed = loaded.sub(computed);
+          break;
+        case And:
+          computed = loaded.and_(computed);
+          break;
+        case Or:
+          computed = loaded.or_(computed);
+          break;
+        case Xor:
+          computed = loaded.xor_(computed);
+          break;
+        case Xchg:
+          break;
+      }
+      instance.doAtomicStore(addr, curr->bytes, computed);
+      return loaded;
+    }
+    Flow visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+      NOTE_ENTER("AtomicCmpxchg");
+      Flow ptr = this->visit(curr->ptr);
+      if (ptr.breaking()) {
+        return ptr;
+      }
+      NOTE_EVAL1(ptr);
+      auto expected = this->visit(curr->expected);
+      if (expected.breaking()) {
+        return expected;
+      }
+      auto replacement = this->visit(curr->replacement);
+      if (replacement.breaking()) {
+        return replacement;
+      }
+      auto addr = instance.getFinalAddress(curr, ptr.getSingleValue());
+      expected =
+        Flow(wrapToSmallerSize(expected.getSingleValue(), curr->bytes));
+      NOTE_EVAL1(addr);
+      NOTE_EVAL1(expected);
+      NOTE_EVAL1(replacement);
+      auto loaded = instance.doAtomicLoad(addr, curr->bytes, curr->type);
+      NOTE_EVAL1(loaded);
+      if (loaded == expected.getSingleValue()) {
+        instance.doAtomicStore(addr, curr->bytes, replacement.getSingleValue());
+      }
+      return loaded;
+    }
+    Flow visitAtomicWait(AtomicWait* curr) {
+      NOTE_ENTER("AtomicWait");
+      Flow ptr = this->visit(curr->ptr);
+      if (ptr.breaking()) {
+        return ptr;
+      }
+      NOTE_EVAL1(ptr);
+      auto expected = this->visit(curr->expected);
+      NOTE_EVAL1(expected);
+      if (expected.breaking()) {
+        return expected;
+      }
+      auto timeout = this->visit(curr->timeout);
+      NOTE_EVAL1(timeout);
+      if (timeout.breaking()) {
+        return timeout;
+      }
+      auto bytes = curr->expectedType.getByteSize();
+      auto addr = instance.getFinalAddress(curr, ptr.getSingleValue(), bytes);
+      auto loaded = instance.doAtomicLoad(addr, bytes, curr->expectedType);
+      NOTE_EVAL1(loaded);
+      if (loaded != expected.getSingleValue()) {
+        return Literal(int32_t(1)); // not equal
+      }
+      // TODO: add threads support!
+      //       for now, just assume we are woken up
+      return Literal(int32_t(0)); // woken up
+    }
+    Flow visitAtomicNotify(AtomicNotify* curr) {
+      NOTE_ENTER("AtomicNotify");
+      Flow ptr = this->visit(curr->ptr);
+      if (ptr.breaking()) {
+        return ptr;
+      }
+      NOTE_EVAL1(ptr);
+      auto count = this->visit(curr->notifyCount);
+      NOTE_EVAL1(count);
+      if (count.breaking()) {
+        return count;
+      }
+      auto addr = instance.getFinalAddress(curr, ptr.getSingleValue(), 4);
+      // Just check TODO actual threads support
+      instance.checkAtomicAddress(addr, 4);
+      return Literal(int32_t(0)); // none woken up
+    }
+    Flow visitSIMDLoad(SIMDLoad* curr) {
+      NOTE_ENTER("SIMDLoad");
+      switch (curr->op) {
+        case LoadSplatVec8x16:
+        case LoadSplatVec16x8:
+        case LoadSplatVec32x4:
+        case LoadSplatVec64x2:
+          return visitSIMDLoadSplat(curr);
+        case LoadExtSVec8x8ToVecI16x8:
+        case LoadExtUVec8x8ToVecI16x8:
+        case LoadExtSVec16x4ToVecI32x4:
+        case LoadExtUVec16x4ToVecI32x4:
+        case LoadExtSVec32x2ToVecI64x2:
+        case LoadExtUVec32x2ToVecI64x2:
+          return visitSIMDLoadExtend(curr);
+        case Load32Zero:
+        case Load64Zero:
+          return visitSIMDLoadZero(curr);
+      }
+      WASM_UNREACHABLE("invalid op");
+    }
+    Flow visitSIMDLoadSplat(SIMDLoad* curr) {
+      Load load;
+      load.type = Type::i32;
+      load.bytes = curr->getMemBytes();
+      load.signed_ = false;
+      load.offset = curr->offset;
+      load.align = curr->align;
+      load.isAtomic = false;
+      load.ptr = curr->ptr;
+      Literal (Literal::*splat)() const = nullptr;
+      switch (curr->op) {
+        case LoadSplatVec8x16:
+          splat = &Literal::splatI8x16;
+          break;
+        case LoadSplatVec16x8:
+          splat = &Literal::splatI16x8;
+          break;
+        case LoadSplatVec32x4:
+          splat = &Literal::splatI32x4;
+          break;
+        case LoadSplatVec64x2:
+          load.type = Type::i64;
+          splat = &Literal::splatI64x2;
+          break;
+        default:
+          WASM_UNREACHABLE("invalid op");
+      }
+      load.finalize();
+      Flow flow = this->visit(&load);
+      if (flow.breaking()) {
+        return flow;
+      }
+      return (flow.getSingleValue().*splat)();
+    }
+    Flow visitSIMDLoadExtend(SIMDLoad* curr) {
+      Flow flow = this->visit(curr->ptr);
+      if (flow.breaking()) {
+        return flow;
+      }
+      NOTE_EVAL1(flow);
+      Address src(uint32_t(flow.getSingleValue().geti32()));
+      auto loadLane = [&](Address addr) {
+        switch (curr->op) {
+          case LoadExtSVec8x8ToVecI16x8:
+            return Literal(int32_t(instance.externalInterface->load8s(addr)));
+          case LoadExtUVec8x8ToVecI16x8:
+            return Literal(int32_t(instance.externalInterface->load8u(addr)));
+          case LoadExtSVec16x4ToVecI32x4:
+            return Literal(int32_t(instance.externalInterface->load16s(addr)));
+          case LoadExtUVec16x4ToVecI32x4:
+            return Literal(int32_t(instance.externalInterface->load16u(addr)));
+          case LoadExtSVec32x2ToVecI64x2:
+            return Literal(int64_t(instance.externalInterface->load32s(addr)));
+          case LoadExtUVec32x2ToVecI64x2:
+            return Literal(int64_t(instance.externalInterface->load32u(addr)));
+          default:
+            WASM_UNREACHABLE("unexpected op");
+        }
+        WASM_UNREACHABLE("invalid op");
+      };
+      auto fillLanes = [&](auto lanes, size_t laneBytes) {
+        for (auto& lane : lanes) {
+          lane = loadLane(
+            instance.getFinalAddress(curr, Literal(uint32_t(src)), laneBytes));
+          src = Address(uint32_t(src) + laneBytes);
+        }
+        return Literal(lanes);
+      };
+      switch (curr->op) {
+        case LoadExtSVec8x8ToVecI16x8:
+        case LoadExtUVec8x8ToVecI16x8: {
+          std::array<Literal, 8> lanes;
+          return fillLanes(lanes, 1);
+        }
+        case LoadExtSVec16x4ToVecI32x4:
+        case LoadExtUVec16x4ToVecI32x4: {
+          std::array<Literal, 4> lanes;
+          return fillLanes(lanes, 2);
+        }
+        case LoadExtSVec32x2ToVecI64x2:
+        case LoadExtUVec32x2ToVecI64x2: {
+          std::array<Literal, 2> lanes;
+          return fillLanes(lanes, 4);
+        }
+        default:
+          WASM_UNREACHABLE("unexpected op");
+      }
+      WASM_UNREACHABLE("invalid op");
+    }
+    Flow visitSIMDLoadZero(SIMDLoad* curr) {
+      Flow flow = this->visit(curr->ptr);
+      if (flow.breaking()) {
+        return flow;
+      }
+      NOTE_EVAL1(flow);
+      Address src = instance.getFinalAddress(
+        curr, flow.getSingleValue(), curr->op == Load32Zero ? 32 : 64);
+      auto zero =
+        Literal::makeZero(curr->op == Load32Zero ? Type::i32 : Type::i64);
+      if (curr->op == Load32Zero) {
+        auto val = Literal(instance.externalInterface->load32u(src));
+        return Literal(std::array<Literal, 4>{{val, zero, zero, zero}});
+      } else {
+        auto val = Literal(instance.externalInterface->load64u(src));
+        return Literal(std::array<Literal, 2>{{val, zero}});
+      }
+    }
+    Flow visitMemorySize(MemorySize* curr) {
+      NOTE_ENTER("MemorySize");
+      return Literal::makeFromInt64(instance.memorySize,
+                                    instance.wasm.memory.indexType);
+    }
+    Flow visitMemoryGrow(MemoryGrow* curr) {
+      NOTE_ENTER("MemoryGrow");
+      auto indexType = instance.wasm.memory.indexType;
+      auto fail = Literal::makeFromInt64(-1, indexType);
+      Flow flow = this->visit(curr->delta);
+      if (flow.breaking()) {
+        return flow;
+      }
+      Flow ret = Literal::makeFromInt64(instance.memorySize, indexType);
+      uint64_t delta = flow.getSingleValue().getUnsigned();
+      if (delta > uint32_t(-1) / Memory::kPageSize && indexType == Type::i32) {
+        return fail;
+      }
+      if (instance.memorySize >= uint32_t(-1) - delta &&
+          indexType == Type::i32) {
+        return fail;
+      }
+      auto newSize = instance.memorySize + delta;
+      if (newSize > instance.wasm.memory.max) {
+        return fail;
+      }
+      if (!instance.externalInterface->growMemory(
+            instance.memorySize * Memory::kPageSize,
+            newSize * Memory::kPageSize)) {
+        // We failed to grow the memory in practice, even though it was valid
+        // to try to do so.
+        return fail;
+      }
+      instance.memorySize = newSize;
+      return ret;
+    }
+    Flow visitMemoryInit(MemoryInit* curr) {
+      NOTE_ENTER("MemoryInit");
+      Flow dest = this->visit(curr->dest);
+      if (dest.breaking()) {
+        return dest;
+      }
+      Flow offset = this->visit(curr->offset);
+      if (offset.breaking()) {
+        return offset;
+      }
+      Flow size = this->visit(curr->size);
+      if (size.breaking()) {
+        return size;
+      }
+      NOTE_EVAL1(dest);
+      NOTE_EVAL1(offset);
+      NOTE_EVAL1(size);
+
+      assert(curr->segment < instance.wasm.memory.segments.size());
+      Memory::Segment& segment = instance.wasm.memory.segments[curr->segment];
+
+      Address destVal(dest.getSingleValue().getUnsigned());
+      Address offsetVal(uint32_t(offset.getSingleValue().geti32()));
+      Address sizeVal(uint32_t(size.getSingleValue().geti32()));
+
+      if (offsetVal + sizeVal > 0 &&
+          instance.droppedSegments.count(curr->segment)) {
+        trap("out of bounds segment access in memory.init");
+      }
+      if ((uint64_t)offsetVal + sizeVal > segment.data.size()) {
+        trap("out of bounds segment access in memory.init");
+      }
+      if (destVal + sizeVal > instance.memorySize * Memory::kPageSize) {
+        trap("out of bounds memory access in memory.init");
+      }
+      for (size_t i = 0; i < sizeVal; ++i) {
+        Literal addr(destVal + i);
+        instance.externalInterface->store8(
+          instance.getFinalAddressWithoutOffset(addr, 1),
+          segment.data[offsetVal + i]);
+      }
+      return {};
+    }
+    Flow visitDataDrop(DataDrop* curr) {
+      NOTE_ENTER("DataDrop");
+      instance.droppedSegments.insert(curr->segment);
+      return {};
+    }
+    Flow visitMemoryCopy(MemoryCopy* curr) {
+      NOTE_ENTER("MemoryCopy");
+      Flow dest = this->visit(curr->dest);
+      if (dest.breaking()) {
+        return dest;
+      }
+      Flow source = this->visit(curr->source);
+      if (source.breaking()) {
+        return source;
+      }
+      Flow size = this->visit(curr->size);
+      if (size.breaking()) {
+        return size;
+      }
+      NOTE_EVAL1(dest);
+      NOTE_EVAL1(source);
+      NOTE_EVAL1(size);
+      Address destVal(dest.getSingleValue().getUnsigned());
+      Address sourceVal(source.getSingleValue().getUnsigned());
+      Address sizeVal(size.getSingleValue().getUnsigned());
+
+      if (sourceVal + sizeVal > instance.memorySize * Memory::kPageSize ||
+          destVal + sizeVal > instance.memorySize * Memory::kPageSize ||
+          // FIXME: better/cheaper way to detect wrapping?
+          sourceVal + sizeVal < sourceVal || sourceVal + sizeVal < sizeVal ||
+          destVal + sizeVal < destVal || destVal + sizeVal < sizeVal) {
+        trap("out of bounds segment access in memory.copy");
+      }
+
+      int64_t start = 0;
+      int64_t end = sizeVal;
+      int step = 1;
+      // Reverse direction if source is below dest
+      if (sourceVal < destVal) {
+        start = int64_t(sizeVal) - 1;
+        end = -1;
+        step = -1;
+      }
+      for (int64_t i = start; i != end; i += step) {
+        instance.externalInterface->store8(
+          instance.getFinalAddressWithoutOffset(Literal(destVal + i), 1),
+          instance.externalInterface->load8s(
+            instance.getFinalAddressWithoutOffset(Literal(sourceVal + i), 1)));
+      }
+      return {};
+    }
+    Flow visitMemoryFill(MemoryFill* curr) {
+      NOTE_ENTER("MemoryFill");
+      Flow dest = this->visit(curr->dest);
+      if (dest.breaking()) {
+        return dest;
+      }
+      Flow value = this->visit(curr->value);
+      if (value.breaking()) {
+        return value;
+      }
+      Flow size = this->visit(curr->size);
+      if (size.breaking()) {
+        return size;
+      }
+      NOTE_EVAL1(dest);
+      NOTE_EVAL1(value);
+      NOTE_EVAL1(size);
+      Address destVal(dest.getSingleValue().getUnsigned());
+      Address sizeVal(size.getSingleValue().getUnsigned());
+
+      // FIXME: cheaper wrapping detection?
+      if (destVal > instance.memorySize * Memory::kPageSize ||
+          sizeVal > instance.memorySize * Memory::kPageSize ||
+          destVal + sizeVal > instance.memorySize * Memory::kPageSize) {
+        trap("out of bounds memory access in memory.fill");
+      }
+      uint8_t val(value.getSingleValue().geti32());
+      for (size_t i = 0; i < sizeVal; ++i) {
+        instance.externalInterface->store8(
+          instance.getFinalAddressWithoutOffset(Literal(destVal + i), 1), val);
+      }
+      return {};
+    }
+    Flow visitTry(Try* curr) {
+      NOTE_ENTER("Try");
+      try {
+        return this->visit(curr->body);
+      } catch (const WasmException& e) {
+        instance.multiValues.push_back(e.exn);
+        return this->visit(curr->catchBody);
+      }
+    }
+    Flow visitPop(Pop* curr) {
+      NOTE_ENTER("Pop");
+      assert(!instance.multiValues.empty());
+      auto ret = instance.multiValues.back();
+      instance.multiValues.pop_back();
+      return ret;
+    }
+
+    void trap(const char* why) override {
+      instance.externalInterface->trap(why);
+    }
+
+    void throwException(Literal exn) override {
+      instance.externalInterface->throwException(exn);
+    }
+
+    // Given a value, wrap it to a smaller given number of bytes.
+    Literal wrapToSmallerSize(Literal value, Index bytes) {
+      if (value.type == Type::i32) {
+        switch (bytes) {
+          case 1: {
+            return value.and_(Literal(uint32_t(0xff)));
+          }
+          case 2: {
+            return value.and_(Literal(uint32_t(0xffff)));
+          }
+          case 4: {
+            break;
+          }
+          default:
+            WASM_UNREACHABLE("unexpected bytes");
+        }
+      } else {
+        assert(value.type == Type::i64);
+        switch (bytes) {
+          case 1: {
+            return value.and_(Literal(uint64_t(0xff)));
+          }
+          case 2: {
+            return value.and_(Literal(uint64_t(0xffff)));
+          }
+          case 4: {
+            return value.and_(Literal(uint64_t(0xffffffffUL)));
+          }
+          case 8: {
+            break;
+          }
+          default:
+            WASM_UNREACHABLE("unexpected bytes");
+        }
+      }
+      return value;
+    }
+  };
+
+public:
+  // Call a function, starting an invocation.
+  Literals callFunction(Name name, const LiteralList& arguments) {
+    // if the last call ended in a jump up the stack, it might have left stuff
+    // for us to clean up here
+    callDepth = 0;
+    functionStack.clear();
+    return callFunctionInternal(name, arguments);
+  }
+
+  // Internal function call. Must be public so that callTable implementations
+  // can use it (refactor?)
+  Literals callFunctionInternal(Name name, const LiteralList& arguments) {
+    if (callDepth > maxDepth) {
+      externalInterface->trap("stack limit");
+    }
+    auto previousCallDepth = callDepth;
+    callDepth++;
+    auto previousFunctionStackSize = functionStack.size();
+    functionStack.push_back(name);
+
+    Function* function = wasm.getFunction(name);
+    assert(function);
+    FunctionScope scope(function, arguments);
+
+#ifdef WASM_INTERPRETER_DEBUG
+    std::cout << "entering " << function->name << "\n  with arguments:\n";
+    for (unsigned i = 0; i < arguments.size(); ++i) {
+      std::cout << "    $" << i << ": " << arguments[i] << '\n';
+    }
+#endif
+
+    Flow flow =
+      RuntimeExpressionRunner(*this, scope, maxDepth).visit(function->body);
+    // cannot still be breaking, it means we missed our stop
+    assert(!flow.breaking() || flow.breakTo == RETURN_FLOW);
+    auto type = flow.getType();
+    if (!Type::isSubType(type, function->sig.results)) {
+      std::cerr << "calling " << function->name << " resulted in " << type
+                << " but the function type is " << function->sig.results
+                << '\n';
+      WASM_UNREACHABLE("unexpected result type");
+    }
+    // may decrease more than one, if we jumped up the stack
+    callDepth = previousCallDepth;
+    // if we jumped up the stack, we also need to pop higher frames
+    while (functionStack.size() > previousFunctionStackSize) {
+      functionStack.pop_back();
+    }
+#ifdef WASM_INTERPRETER_DEBUG
+    std::cout << "exiting " << function->name << " with " << flow.values
+              << '\n';
+#endif
+    return flow.values;
+  }
+
+protected:
+  Address memorySize; // in pages
+
+  static const Index maxDepth = 250;
+
+  void trapIfGt(uint64_t lhs, uint64_t rhs, const char* msg) {
+    if (lhs > rhs) {
+      std::stringstream ss;
+      ss << msg << ": " << lhs << " > " << rhs;
+      externalInterface->trap(ss.str().c_str());
+    }
+  }
+
+  template<class LS>
+  Address getFinalAddress(LS* curr, Literal ptr, Index bytes) {
+    Address memorySizeBytes = memorySize * Memory::kPageSize;
+    uint64_t addr = ptr.type == Type::i32 ? ptr.geti32() : ptr.geti64();
+    trapIfGt(curr->offset, memorySizeBytes, "offset > memory");
+    trapIfGt(addr, memorySizeBytes - curr->offset, "final > memory");
+    addr += curr->offset;
+    trapIfGt(bytes, memorySizeBytes, "bytes > memory");
+    checkLoadAddress(addr, bytes);
+    return addr;
+  }
+
+  template<class LS> Address getFinalAddress(LS* curr, Literal ptr) {
+    return getFinalAddress(curr, ptr, curr->bytes);
+  }
+
+  Address getFinalAddressWithoutOffset(Literal ptr, Index bytes) {
+    uint64_t addr = ptr.type == Type::i32 ? ptr.geti32() : ptr.geti64();
+    checkLoadAddress(addr, bytes);
+    return addr;
+  }
+
+  void checkLoadAddress(Address addr, Index bytes) {
+    Address memorySizeBytes = memorySize * Memory::kPageSize;
+    trapIfGt(addr, memorySizeBytes - bytes, "highest > memory");
+  }
+
+  void checkAtomicAddress(Address addr, Index bytes) {
+    checkLoadAddress(addr, bytes);
+    // Unaligned atomics trap.
+    if (bytes > 1) {
+      if (addr & (bytes - 1)) {
+        externalInterface->trap("unaligned atomic operation");
+      }
+    }
+  }
+
+  Literal doAtomicLoad(Address addr, Index bytes, Type type) {
+    checkAtomicAddress(addr, bytes);
+    Const ptr;
+    ptr.value = Literal(int32_t(addr));
+    ptr.type = Type::i32;
+    Load load;
+    load.bytes = bytes;
+    // When an atomic loads a partial number of bytes for the type, it is
+    // always an unsigned extension.
+    load.signed_ = false;
+    load.align = bytes;
+    load.isAtomic = true; // understatement
+    load.ptr = &ptr;
+    load.type = type;
+    return externalInterface->load(&load, addr);
+  }
+
+  void doAtomicStore(Address addr, Index bytes, Literal toStore) {
+    checkAtomicAddress(addr, bytes);
+    Const ptr;
+    ptr.value = Literal(int32_t(addr));
+    ptr.type = Type::i32;
+    Const value;
+    value.value = toStore;
+    value.type = toStore.type;
+    Store store;
+    store.bytes = bytes;
+    store.align = bytes;
+    store.isAtomic = true; // understatement
+    store.ptr = &ptr;
+    store.value = &value;
+    store.valueType = value.type;
+    return externalInterface->store(&store, addr, toStore);
+  }
+
+  ExternalInterface* externalInterface;
+};
+
+// The default ModuleInstance uses a trivial global manager
+using TrivialGlobalManager = std::map<Name, Literals>;
+class ModuleInstance
+  : public ModuleInstanceBase<TrivialGlobalManager, ModuleInstance> {
+public:
+  ModuleInstance(Module& wasm, ExternalInterface* externalInterface)
+    : ModuleInstanceBase(wasm, externalInterface) {}
+};
+
+} // namespace wasm
+
+#endif // wasm_wasm_interpreter_h
diff --git a/binaryen/src/wasm-io.h b/binaryen/src/wasm-io.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-io.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+//
+// Abstracts reading and writing, supporting both text and binary.
+//
+
+#ifndef wasm_wasm_io_h
+#define wasm_wasm_io_h
+
+#include "parsing.h"
+#include "support/file.h"
+#include "wasm.h"
+
+namespace wasm {
+
+class ModuleReader {
+public:
+  // If DWARF support is enabled, we track the locations of all IR nodes in
+  // the binary, so that we can update DWARF sections later when writing.
+  void setDWARF(bool DWARF_) { DWARF = DWARF_; }
+
+  void setProfile(IRProfile profile_) { profile = profile_; }
+
+  // read text
+  void readText(std::string filename, Module& wasm);
+  // read binary
+  void readBinary(std::string filename,
+                  Module& wasm,
+                  std::string sourceMapFilename = "");
+  // read text or binary, checking the contents for what it is. If `filename` is
+  // empty, read from stdin.
+  void
+  read(std::string filename, Module& wasm, std::string sourceMapFilename = "");
+  // check whether a file is a wasm binary
+  bool isBinaryFile(std::string filename);
+
+private:
+  bool DWARF = false;
+
+  IRProfile profile = IRProfile::Normal;
+
+  void readStdin(Module& wasm, std::string sourceMapFilename);
+
+  void readBinaryData(std::vector<char>& input,
+                      Module& wasm,
+                      std::string sourceMapFilename);
+};
+
+class ModuleWriter {
+  bool binary = true;
+  bool debugInfo = false;
+  std::string symbolMap;
+  std::string sourceMapFilename;
+  std::string sourceMapUrl;
+
+public:
+  void setBinary(bool binary_) { binary = binary_; }
+  void setDebugInfo(bool debugInfo_) { debugInfo = debugInfo_; }
+  void setSymbolMap(std::string symbolMap_) { symbolMap = symbolMap_; }
+  void setSourceMapFilename(std::string sourceMapFilename_) {
+    sourceMapFilename = sourceMapFilename_;
+  }
+  void setSourceMapUrl(std::string sourceMapUrl_) {
+    sourceMapUrl = sourceMapUrl_;
+  }
+
+  // write text
+  void writeText(Module& wasm, Output& output);
+  void writeText(Module& wasm, std::string filename);
+  // write binary
+  void writeBinary(Module& wasm, Output& output);
+  void writeBinary(Module& wasm, std::string filename);
+  // write text or binary, defaulting to binary unless setBinary(false),
+  // and unless there is no output file (in which case we write text
+  // to stdout).
+  void write(Module& wasm, Output& output);
+  void write(Module& wasm, std::string filename);
+};
+
+} // namespace wasm
+
+#endif // wasm_wasm_io_h
diff --git a/binaryen/src/wasm-module-building.h b/binaryen/src/wasm-module-building.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-module-building.h
@@ -0,0 +1,324 @@
+/*
+ * 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_module_building_h
+#define wasm_wasm_module_building_h
+
+#include <support/threads.h>
+#include <wasm.h>
+
+namespace wasm {
+
+#ifdef BINARYEN_THREAD_DEBUG
+static std::mutex debug;
+#define DEBUG_THREAD(x)                                                        \
+  {                                                                            \
+    std::lock_guard<std::mutex> lock(debug);                                   \
+    std::cerr << "[OptimizingIncrementalModuleBuilder Threading (thread: "     \
+              << std::this_thread::get_id() << ")] " << x;                     \
+    std::cerr << '\n';                                                         \
+  }
+#else
+#define DEBUG_THREAD(x)
+#endif
+
+//
+// OptimizingIncrementalModuleBuilder
+//
+// Helps build wasm modules efficiently. If you build a module by
+// adding function by function, and you want to optimize them, this class
+// starts optimizing using worker threads *while you are still adding*.
+// It runs function optimization passes at that time. This does not
+// run global optimization after that by default, but you can do that
+// to by calling optimizeGlobally(), which runs the the global post-passes
+// (we can't run the pre-passes, as they must be run before function
+// passes, and no such time is possible here given that we receive
+// functions one by one and optimize them).
+//
+// This might also be faster than normal module optimization since it
+// runs all passes on each function, then goes on to the next function
+// which is better for data locality.
+//
+// Usage: Create an instance, passing it the module and the total
+//        number of functions. Then call addFunction as you have
+//        new functions to add (this also adds it to the module). Finally,
+//        call finish() when all functions have been added.
+//
+// This avoids locking by using atomics. We allocate an array of nullptrs
+// that represent all the functions, and as we add a function, we place it
+// at the next index. Each worker will read from the start to the end,
+// and when a non-nullptr is found, the worker optimizes that function and
+// nulls it. There is also an end marker that is not nullptr nor the address of
+// a valid function, which represents that beyond this point we have not
+// yet filled in. In other words,
+//    * the main thread fills everything with the end marker
+//    * the main thread transforms a marker entry into a function
+//    * workers pause when they see the marker
+//    * workers skip over nullptrs
+//    * workers transform functions into nullptrs, and optimize them
+//    * we keep an atomic count of the number of active workers and
+//      the number of optimized functions.
+//    * after adding a function, the main thread notifys up workers if
+//      it calculates there is work for them.
+//    * a lock is used for going to sleep and waking up.
+// Locking should be rare, as optimization is
+// generally slower than generation; in the optimal case, we never
+// lock beyond the first step, and all further work is lock-free.
+//
+// N.B.: Optimizing functions in parallel with adding functions is possible,
+//       but the rest of the global state of the module should be fixed,
+//       such as globals, imports, etc. Function-parallel optimization passes
+//       may read (but not modify) those fields.
+
+class OptimizingIncrementalModuleBuilder {
+  Module* wasm;
+  uint32_t numFunctions;
+  PassOptions passOptions;
+  std::function<void(PassRunner&)> addPrePasses;
+  Function* endMarker;
+  std::atomic<Function*>* list;
+  uint32_t nextFunction; // only used on main thread
+  uint32_t numWorkers;
+  std::vector<std::unique_ptr<std::thread>> threads;
+  std::atomic<uint32_t> liveWorkers, activeWorkers, availableFuncs,
+    finishedFuncs;
+  std::mutex mutex;
+  std::condition_variable condition;
+  bool finishing;
+  bool debug;
+  bool validateGlobally;
+
+public:
+  // numFunctions must be equal to the number of functions allocated, or higher.
+  // Knowing this bounds helps avoid locking.
+  OptimizingIncrementalModuleBuilder(
+    Module* wasm,
+    Index numFunctions,
+    PassOptions passOptions,
+    std::function<void(PassRunner&)> addPrePasses,
+    bool debug,
+    bool validateGlobally)
+    : wasm(wasm), numFunctions(numFunctions), passOptions(passOptions),
+      addPrePasses(addPrePasses), endMarker(nullptr), list(nullptr),
+      nextFunction(0), numWorkers(0), liveWorkers(0), activeWorkers(0),
+      availableFuncs(0), finishedFuncs(0), finishing(false), debug(debug),
+      validateGlobally(validateGlobally) {
+
+    if (!useWorkers()) {
+      // if we shouldn't use threads, don't
+      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];
+    for (uint32_t i = 0; i < numFunctions; i++) {
+      list[i].store(endMarker);
+    }
+    // create workers
+    DEBUG_THREAD("creating workers");
+    numWorkers = ThreadPool::getNumCores();
+    assert(numWorkers >= 1);
+    // worth it to use threads
+    liveWorkers.store(0);
+    activeWorkers.store(0);
+    // TODO: one less, and add it at the very end, to not compete with main
+    // thread?
+    for (uint32_t i = 0; i < numWorkers; i++) {
+      createWorker();
+    }
+    waitUntilAllReady();
+    DEBUG_THREAD("workers are ready");
+    // prepare the rest of the initial state
+    availableFuncs.store(0);
+    finishedFuncs.store(0);
+  }
+
+  ~OptimizingIncrementalModuleBuilder() {
+    delete[] list;
+    delete endMarker;
+  }
+
+  bool useWorkers() {
+    return numFunctions > 0 && !debug && ThreadPool::getNumCores() > 1 &&
+           !PassRunner::getPassDebug();
+  }
+
+  // Add a function to the module, and to be optimized
+  void addFunction(Function* func) {
+    wasm->addFunction(func);
+    if (!useWorkers()) {
+      return; // we optimize at the end in that case
+    }
+    queueFunction(func);
+    // notify workers if needed
+    auto notify = availableFuncs.load();
+    for (uint32_t i = 0; i < notify; i++) {
+      notifyWorker();
+    }
+  }
+
+  // All functions have been added, block until all are optimized, and then do
+  // global optimizations. When this returns, the module is ready and optimized.
+  void finish() {
+    if (!useWorkers()) {
+      // optimize each function now that we are done adding functions,
+      // then optimize globally
+      PassRunner passRunner(wasm, passOptions);
+      if (debug) {
+        passRunner.setDebug(true);
+        passRunner.setValidateGlobally(validateGlobally);
+      }
+      addPrePasses(passRunner);
+      passRunner.addDefaultFunctionOptimizationPasses();
+      passRunner.run();
+    } else {
+      DEBUG_THREAD("finish()ing");
+      assert(nextFunction == numFunctions);
+      notifyAllWorkers();
+      waitUntilAllFinished();
+    }
+    // TODO: clear side thread allocators from module allocator, as these
+    // threads were transient
+  }
+
+private:
+  void createWorker() {
+    DEBUG_THREAD("create a worker");
+    threads.emplace_back(make_unique<std::thread>(workerMain, this));
+  }
+
+  void notifyWorker() {
+    DEBUG_THREAD("notify a worker");
+    std::lock_guard<std::mutex> lock(mutex);
+    condition.notify_one();
+  }
+
+  void notifyAllWorkers() {
+    DEBUG_THREAD("notify all workers");
+    std::lock_guard<std::mutex> lock(mutex);
+    condition.notify_all();
+  }
+
+  void waitUntilAllReady() {
+    DEBUG_THREAD("wait until all workers are ready");
+    std::unique_lock<std::mutex> lock(mutex);
+    if (liveWorkers.load() < numWorkers) {
+      condition.wait(lock,
+                     [this]() { return liveWorkers.load() == numWorkers; });
+    }
+  }
+
+  void waitUntilAllFinished() {
+    DEBUG_THREAD("wait until all workers are finished");
+    {
+      std::unique_lock<std::mutex> lock(mutex);
+      finishing = true;
+      if (liveWorkers.load() > 0) {
+        condition.wait(lock, [this]() { return liveWorkers.load() == 0; });
+      }
+    }
+    DEBUG_THREAD("joining");
+    for (auto& thread : threads) {
+      thread->join();
+    }
+    DEBUG_THREAD("joined");
+  }
+
+  void queueFunction(Function* func) {
+    DEBUG_THREAD("queue function");
+    // TODO: if we are given more than we expected, use a slower work queue?
+    assert(nextFunction < numFunctions);
+    list[nextFunction++].store(func);
+    availableFuncs++;
+  }
+
+  void optimizeGlobally() {
+    PassRunner passRunner(wasm, passOptions);
+    passRunner.addDefaultGlobalOptimizationPostPasses();
+    passRunner.run();
+  }
+
+  // worker code
+
+  void optimizeFunction(Function* func) {
+    PassRunner passRunner(wasm, passOptions);
+    addPrePasses(passRunner);
+    passRunner.addDefaultFunctionOptimizationPasses();
+    passRunner.runOnFunction(func);
+  }
+
+  static void workerMain(OptimizingIncrementalModuleBuilder* self) {
+    DEBUG_THREAD("workerMain");
+    {
+      std::lock_guard<std::mutex> lock(self->mutex);
+      self->liveWorkers++;
+      self->activeWorkers++;
+      self->condition.notify_all();
+    }
+    for (uint32_t i = 0; i < self->numFunctions; i++) {
+      DEBUG_THREAD("workerMain iteration " << i);
+      if (self->list[i].load() == self->endMarker) {
+        // sleep, this entry isn't ready yet
+        DEBUG_THREAD("workerMain sleep");
+        self->activeWorkers--;
+        {
+          std::unique_lock<std::mutex> lock(self->mutex);
+          // while waiting for the lock, things may have ended
+          if (!self->finishing) {
+            self->condition.wait(lock);
+          }
+        }
+        // continue
+        DEBUG_THREAD("workerMain continue");
+        self->activeWorkers++;
+        i--;
+        continue;
+      }
+      DEBUG_THREAD("workerMain exchange item");
+      auto* func = self->list[i].exchange(nullptr);
+      if (func == nullptr) {
+        DEBUG_THREAD("workerMain sees was already taken");
+        continue; // someone else has taken this one
+      }
+      // we have work to do!
+      DEBUG_THREAD("workerMain work on " << size_t(func));
+      self->availableFuncs--;
+      self->optimizeFunction(func);
+      self->finishedFuncs++;
+    }
+    DEBUG_THREAD("workerMain ready to exit");
+    {
+      std::lock_guard<std::mutex> lock(self->mutex);
+      self->liveWorkers--;
+      self->condition.notify_all();
+    }
+    DEBUG_THREAD("workerMain exiting");
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_wasm_module_building_h
diff --git a/binaryen/src/wasm-printing.h b/binaryen/src/wasm-printing.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-printing.h
@@ -0,0 +1,70 @@
+/*
+ * 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
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-s-parser.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// Parses WebAssembly code in S-Expression format, as in .wast files
+// such as are in the spec test suite.
+//
+
+#ifndef wasm_wasm_s_parser_h
+#define wasm_wasm_s_parser_h
+
+#include "mixed_arena.h"
+#include "parsing.h" // for UniqueNameMapper. TODO: move dependency to cpp file?
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace wasm {
+
+class SourceLocation {
+public:
+  cashew::IString filename;
+  uint32_t line;
+  uint32_t column;
+  SourceLocation(cashew::IString filename_,
+                 uint32_t line_,
+                 uint32_t column_ = 0)
+    : filename(filename_), line(line_), column(column_) {}
+};
+
+//
+// An element in an S-Expression: a list or a string
+//
+class Element {
+  typedef ArenaVector<Element*> List;
+
+  bool isList_ = true;
+  List list_;
+  cashew::IString str_;
+  bool dollared_;
+  bool quoted_;
+
+public:
+  Element(MixedArena& allocator) : list_(allocator) {}
+
+  bool isList() const { return isList_; }
+  bool isStr() const { return !isList_; }
+  bool dollared() const { return isStr() && dollared_; }
+  bool quoted() const { return isStr() && quoted_; }
+
+  size_t line = -1;
+  size_t col = -1;
+  // original locations at the start/end of the S-Expression list
+  SourceLocation* startLoc = nullptr;
+  SourceLocation* endLoc = nullptr;
+
+  // list methods
+  List& list();
+  Element* operator[](unsigned i);
+  size_t size() { return list().size(); }
+
+  // string methods
+  cashew::IString str() const;
+  const char* c_str() const;
+  Element* setString(cashew::IString str__, bool dollared__, bool quoted__);
+  Element* setMetadata(size_t line_, size_t col_, SourceLocation* startLoc_);
+
+  // printing
+  friend std::ostream& operator<<(std::ostream& o, Element& e);
+  void dump();
+};
+
+//
+// Generic S-Expression parsing into lists
+//
+class SExpressionParser {
+  char* input;
+  size_t line;
+  char* lineStart;
+  SourceLocation* loc = nullptr;
+
+  MixedArena allocator;
+
+public:
+  // Assumes control of and modifies the input.
+  SExpressionParser(char* input);
+  Element* root;
+
+private:
+  Element* parse();
+  void skipWhitespace();
+  void parseDebugLocation();
+  Element* parseString();
+};
+
+//
+// SExpressions => WebAssembly module
+//
+class SExpressionWasmBuilder {
+  Module& wasm;
+  MixedArena& allocator;
+  IRProfile profile;
+  std::vector<Signature> signatures;
+  std::unordered_map<std::string, size_t> signatureIndices;
+  std::vector<Name> functionNames;
+  std::vector<Name> globalNames;
+  std::vector<Name> eventNames;
+  int functionCounter = 0;
+  int globalCounter = 0;
+  int eventCounter = 0;
+  // we need to know function return types before we parse their contents
+  std::map<Name, Type> functionTypes;
+  std::unordered_map<cashew::IString, Index> debugInfoFileIndices;
+
+public:
+  // Assumes control of and modifies the input.
+  SExpressionWasmBuilder(Module& wasm, Element& module, IRProfile profile);
+
+private:
+  // pre-parse types and function definitions, so we know function return types
+  // before parsing their contents
+  void preParseFunctionType(Element& s);
+  bool isImport(Element& curr);
+  void preParseImports(Element& curr);
+  void parseModuleElement(Element& curr);
+
+  // function parsing state
+  std::unique_ptr<Function> currFunction;
+  bool brokeToAutoBlock;
+
+  UniqueNameMapper nameMapper;
+
+  Signature getFunctionSignature(Element& s);
+  Name getFunctionName(Element& s);
+  Name getGlobalName(Element& s);
+  Name getEventName(Element& s);
+  void parseStart(Element& s) { wasm.addStart(getFunctionName(*s[1])); }
+
+  // returns the next index in s
+  size_t parseFunctionNames(Element& s, Name& name, Name& exportName);
+  void parseFunction(Element& s, bool preParseImport = false);
+
+  Type stringToType(cashew::IString str,
+                    bool allowError = false,
+                    bool prefix = false) {
+    return stringToType(str.str, allowError, prefix);
+  }
+  Type
+  stringToType(const char* str, bool allowError = false, bool prefix = false);
+  HeapType stringToHeapType(cashew::IString str, bool prefix = false) {
+    return stringToHeapType(str.str, prefix);
+  }
+  HeapType stringToHeapType(const char* str, bool prefix = false);
+  Type elementToType(Element& s);
+  Type stringToLaneType(const char* str);
+  bool isType(cashew::IString str) {
+    return stringToType(str, true) != Type::none;
+  }
+
+public:
+  Expression* parseExpression(Element* s) { return parseExpression(*s); }
+  Expression* parseExpression(Element& s);
+
+  Module& getModule() { return wasm; }
+
+private:
+  Expression* makeExpression(Element& s);
+  Expression* makeUnreachable();
+  Expression* makeNop();
+  Expression* makeBinary(Element& s, BinaryOp op);
+  Expression* makeUnary(Element& s, UnaryOp op);
+  Expression* makeSelect(Element& s);
+  Expression* makeDrop(Element& s);
+  Expression* makeMemorySize(Element& s);
+  Expression* makeMemoryGrow(Element& s);
+  Index getLocalIndex(Element& s);
+  Expression* makeLocalGet(Element& s);
+  Expression* makeLocalTee(Element& s);
+  Expression* makeLocalSet(Element& s);
+  Expression* makeGlobalGet(Element& s);
+  Expression* makeGlobalSet(Element& s);
+  Expression* makeBlock(Element& s);
+  Expression* makeThenOrElse(Element& s);
+  Expression* makeConst(Element& s, Type type);
+  Expression* makeLoad(Element& s, Type type, bool isAtomic);
+  Expression* makeStore(Element& s, Type type, bool isAtomic);
+  Expression* makeAtomicRMWOrCmpxchg(Element& s, Type type);
+  Expression*
+  makeAtomicRMW(Element& s, Type type, uint8_t bytes, const char* extra);
+  Expression*
+  makeAtomicCmpxchg(Element& s, Type type, uint8_t bytes, const char* extra);
+  Expression* makeAtomicWait(Element& s, Type type);
+  Expression* makeAtomicNotify(Element& s);
+  Expression* makeAtomicFence(Element& s);
+  Expression* makeSIMDExtract(Element& s, SIMDExtractOp op, size_t lanes);
+  Expression* makeSIMDReplace(Element& s, SIMDReplaceOp op, size_t lanes);
+  Expression* makeSIMDShuffle(Element& s);
+  Expression* makeSIMDTernary(Element& s, SIMDTernaryOp op);
+  Expression* makeSIMDShift(Element& s, SIMDShiftOp op);
+  Expression* makeSIMDLoad(Element& s, SIMDLoadOp op);
+  Expression* makeMemoryInit(Element& s);
+  Expression* makeDataDrop(Element& s);
+  Expression* makeMemoryCopy(Element& s);
+  Expression* makeMemoryFill(Element& s);
+  Expression* makePush(Element& s);
+  Expression* makePop(Element& s);
+  Expression* makeIf(Element& s);
+  Expression* makeMaybeBlock(Element& s, size_t i, Type type);
+  Expression* makeLoop(Element& s);
+  Expression* makeCall(Element& s, bool isReturn);
+  Expression* makeCallIndirect(Element& s, bool isReturn);
+  template<class T>
+  void parseCallOperands(Element& s, Index i, Index j, T* call) {
+    while (i < j) {
+      call->operands.push_back(parseExpression(s[i]));
+      i++;
+    }
+  }
+  Name getLabel(Element& s);
+  Expression* makeBreak(Element& s);
+  Expression* makeBreakTable(Element& s);
+  Expression* makeReturn(Element& s);
+  Expression* makeRefNull(Element& s);
+  Expression* makeRefIsNull(Element& s);
+  Expression* makeRefFunc(Element& s);
+  Expression* makeRefEq(Element& s);
+  Expression* makeTry(Element& s);
+  Expression* makeTryOrCatchBody(Element& s, Type type, bool isTry);
+  Expression* makeThrow(Element& s);
+  Expression* makeRethrow(Element& s);
+  Expression* makeBrOnExn(Element& s);
+  Expression* makeTupleMake(Element& s);
+  Expression* makeTupleExtract(Element& s);
+  Expression* makeI31New(Element& s);
+  Expression* makeI31Get(Element& s, bool signed_);
+  Expression* makeRefTest(Element& s);
+  Expression* makeRefCast(Element& s);
+  Expression* makeBrOnCast(Element& s);
+  Expression* makeRttCanon(Element& s);
+  Expression* makeRttSub(Element& s);
+  Expression* makeStructNew(Element& s, bool default_);
+  Expression* makeStructGet(Element& s);
+  Expression* makeStructGet(Element& s, bool signed_);
+  Expression* makeStructSet(Element& s);
+  Expression* makeArrayNew(Element& s, bool default_);
+  Expression* makeArrayGet(Element& s);
+  Expression* makeArrayGet(Element& s, bool signed_);
+  Expression* makeArraySet(Element& s);
+  Expression* makeArrayLen(Element& s);
+
+  // Helper functions
+  Type parseOptionalResultType(Element& s, Index& i);
+  Index parseMemoryLimits(Element& s, Index i);
+  Index parseMemoryIndex(Element& s, Index i);
+  std::vector<Type> parseParamOrLocal(Element& s);
+  std::vector<NameType> parseParamOrLocal(Element& s, size_t& localIndex);
+  std::vector<Type> parseResults(Element& s);
+  Signature parseTypeRef(Element& s);
+  size_t parseTypeUse(Element& s,
+                      size_t startPos,
+                      Signature& functionSignature,
+                      std::vector<NameType>& namedParams);
+  size_t
+  parseTypeUse(Element& s, size_t startPos, Signature& functionSignature);
+
+  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 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);
+  void parseType(Element& s);
+  void parseEvent(Element& s, bool preParseImport = false);
+
+  Function::DebugLocation getDebugLocation(const SourceLocation& loc);
+};
+
+} // namespace wasm
+
+#endif // wasm_wasm_s_parser_h
diff --git a/binaryen/src/wasm-stack.h b/binaryen/src/wasm-stack.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-stack.h
@@ -0,0 +1,495 @@
+/*
+ * 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.
+ */
+
+#ifndef wasm_stack_h
+#define wasm_stack_h
+
+#include "ir/branch-utils.h"
+#include "ir/properties.h"
+#include "pass.h"
+#include "wasm-binary.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
+
+namespace wasm {
+
+// Stack IR: an IR that represents code at the wasm binary format level,
+// that is, a stack machine. Binaryen IR is *almost* identical to this,
+// but as documented in README.md, there are a few differences, intended
+// to make Binaryen IR fast and flexible for maximal optimization. Stack
+// IR, on the other hand, is designed to optimize a few final things that
+// can only really be done when modeling the stack machine format precisely.
+
+// Currently the benefits of Stack IR are minor, less than 1% reduction in
+// code size. For that reason it is just a secondary IR, run optionally
+// after the main IR has been optimized. However, if we improve Stack IR
+// optimizations to a point where they have a significant impact, it's
+// possible that could motivate investigating replacing the main IR with Stack
+// IR (so that we have just a single IR).
+
+// A StackIR instance (see wasm.h) contains a linear sequence of
+// stack instructions. This representation is very simple: just a single vector
+// of all instructions, in order.
+//  * nullptr is allowed in the vector, representing something to skip.
+//    This is useful as a common thing optimizations do is remove instructions,
+//    so this way we can do so without compacting the vector all the time.
+
+// Direct writing binaryen IR to binary is fast. Otherwise, StackIRGenerator
+// lets you optimize the Stack IR before emitting stack IR to binary (but the
+// cost is that the extra IR in the middle makes things 20% slower than emitting
+// binaryen IR to binary directly).
+
+// A Stack IR instruction. Most just directly reflect a Binaryen IR node,
+// but we need extra ones for certain things.
+class StackInst {
+public:
+  StackInst(MixedArena&) {}
+
+  enum Op {
+    Basic,      // an instruction directly corresponding to a non-control-flow
+                // Binaryen IR node
+    BlockBegin, // the beginning of a block
+    BlockEnd,   // the ending of a block
+    IfBegin,    // the beginning of a if
+    IfElse,     // the else of a if
+    IfEnd,      // the ending of a if
+    LoopBegin,  // the beginning of a loop
+    LoopEnd,    // the ending of a loop
+    TryBegin,   // the beginning of a try
+    Catch,      // the catch within a try
+    TryEnd      // the ending of a try
+  } op;
+
+  Expression* origin; // the expression this originates from
+
+  // the type - usually identical to the origin type, but e.g. wasm has no
+  // unreachable blocks, they must be none
+  Type type;
+};
+
+class BinaryInstWriter : public OverriddenVisitor<BinaryInstWriter> {
+public:
+  BinaryInstWriter(WasmBinaryWriter& parent,
+                   BufferWithRandomAccess& o,
+                   Function* func,
+                   bool sourceMap,
+                   bool DWARF)
+    : parent(parent), o(o), func(func), sourceMap(sourceMap), DWARF(DWARF) {}
+
+  void visit(Expression* curr) {
+    if (func && !sourceMap) {
+      parent.writeDebugLocation(curr, func);
+    }
+    OverriddenVisitor<BinaryInstWriter>::visit(curr);
+    if (func && !sourceMap) {
+      parent.writeDebugLocationEnd(curr, func);
+    }
+  }
+
+  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);
+
+  void emitResultType(Type type);
+  void emitIfElse(If* curr);
+  void emitCatch(Try* curr);
+  // emit an end at the end of a block/loop/if/try
+  void emitScopeEnd(Expression* curr);
+  // emit an end at the end of a function
+  void emitFunctionEnd();
+  void emitUnreachable();
+  void mapLocalsAndEmitHeader();
+
+private:
+  void emitMemoryAccess(size_t alignment, size_t bytes, uint32_t offset);
+  int32_t getBreakIndex(Name name);
+
+  WasmBinaryWriter& parent;
+  BufferWithRandomAccess& o;
+  Function* func = nullptr;
+  bool sourceMap;
+  bool DWARF;
+
+  std::vector<Name> breakStack;
+
+  // type => number of locals of that type in the compact form
+  std::map<Type, size_t> numLocalsByType;
+  // (local index, tuple index) => binary local index
+  std::map<std::pair<Index, Index>, size_t> mappedLocals;
+
+  // Keeps track of the binary index of the scratch locals used to lower
+  // tuple.extract.
+  std::map<Type, Index> scratchLocals;
+  void countScratchLocals();
+  void setScratchLocals();
+};
+
+// Takes binaryen IR and converts it to something else (binary or stack IR)
+template<typename SubType>
+class BinaryenIRWriter : public Visitor<BinaryenIRWriter<SubType>> {
+public:
+  BinaryenIRWriter(Function* func) : func(func) {}
+
+  void write();
+
+  // visits a node, emitting the proper code for it
+  void visit(Expression* curr);
+
+  void visitBlock(Block* curr);
+  void visitIf(If* curr);
+  void visitLoop(Loop* curr);
+  void visitTry(Try* curr);
+
+protected:
+  Function* func = nullptr;
+
+private:
+  void emit(Expression* curr) { static_cast<SubType*>(this)->emit(curr); }
+  void emitHeader() { static_cast<SubType*>(this)->emitHeader(); }
+  void emitIfElse(If* curr) { static_cast<SubType*>(this)->emitIfElse(curr); }
+  void emitCatch(Try* curr) { static_cast<SubType*>(this)->emitCatch(curr); }
+  void emitScopeEnd(Expression* curr) {
+    static_cast<SubType*>(this)->emitScopeEnd(curr);
+  }
+  void emitFunctionEnd() { static_cast<SubType*>(this)->emitFunctionEnd(); }
+  void emitUnreachable() { static_cast<SubType*>(this)->emitUnreachable(); }
+  void emitDebugLocation(Expression* curr) {
+    static_cast<SubType*>(this)->emitDebugLocation(curr);
+  }
+  void visitPossibleBlockContents(Expression* curr);
+};
+
+template<typename SubType> void BinaryenIRWriter<SubType>::write() {
+  assert(func && "BinaryenIRWriter: function is not set");
+  emitHeader();
+  visitPossibleBlockContents(func->body);
+  emitFunctionEnd();
+}
+
+// emits a node, but if it is a block with no name, emit a list of its contents
+template<typename SubType>
+void BinaryenIRWriter<SubType>::visitPossibleBlockContents(Expression* curr) {
+  auto* block = curr->dynCast<Block>();
+  if (!block || BranchUtils::BranchSeeker::has(block, block->name)) {
+    visit(curr);
+    return;
+  }
+  for (auto* child : block->list) {
+    visit(child);
+    // Since this child was unreachable, either this child or one of its
+    // descendants was a source of unreachability that was actually
+    // emitted. Subsequent children won't be reachable, so skip them.
+    if (child->type == Type::unreachable) {
+      break;
+    }
+  }
+}
+
+template<typename SubType>
+void BinaryenIRWriter<SubType>::visit(Expression* curr) {
+  emitDebugLocation(curr);
+  // We emit unreachable instructions that create unreachability, but not
+  // unreachable instructions that just inherit unreachability from their
+  // children, since the latter won't be reached. This (together with logic in
+  // the control flow visitors) also ensures that the final instruction in each
+  // unreachable block is a source of unreachability, which means we don't need
+  // to emit an extra `unreachable` before the end of the block to prevent type
+  // errors.
+  bool hasUnreachableChild = false;
+  for (auto* child : ValueChildIterator(curr)) {
+    visit(child);
+    if (child->type == Type::unreachable) {
+      hasUnreachableChild = true;
+      break;
+    }
+  }
+  if (hasUnreachableChild) {
+    // `curr` is not reachable, so don't emit it.
+    return;
+  }
+  // Control flow requires special handling, but most instructions can be
+  // emitted directly after their children.
+  if (Properties::isControlFlowStructure(curr)) {
+    Visitor<BinaryenIRWriter>::visit(curr);
+  } else {
+    emit(curr);
+  }
+}
+
+template<typename SubType>
+void BinaryenIRWriter<SubType>::visitBlock(Block* curr) {
+  auto visitChildren = [this](Block* curr, Index from) {
+    auto& list = curr->list;
+    while (from < list.size()) {
+      auto* child = list[from];
+      visit(child);
+      if (child->type == Type::unreachable) {
+        break;
+      }
+      ++from;
+    }
+  };
+
+  auto afterChildren = [this](Block* curr) {
+    emitScopeEnd(curr);
+    if (curr->type == Type::unreachable) {
+      // Since this block is unreachable, no instructions will be emitted after
+      // it in its enclosing scope. That means that this block will be the last
+      // instruction before the end of its parent scope, so its type must match
+      // the type of its parent. But we don't have a concrete type for this
+      // block and we don't know what type its parent expects, so we can't
+      // ensure the types match. To work around this, we insert an `unreachable`
+      // instruction after every unreachable control flow structure and depend
+      // on its polymorphic behavior to paper over any type mismatches.
+      emitUnreachable();
+    }
+  };
+
+  // Handle very deeply nested blocks in the first position efficiently,
+  // avoiding heavy recursion. We only start to do this if we see it will help
+  // us (to avoid allocation of the vector).
+  if (!curr->list.empty() && curr->list[0]->is<Block>()) {
+    std::vector<Block*> parents;
+    Block* child;
+    while (!curr->list.empty() && (child = curr->list[0]->dynCast<Block>())) {
+      parents.push_back(curr);
+      emit(curr);
+      curr = child;
+    }
+    // Emit the current block, which does not have a block as a child in the
+    // first position.
+    emit(curr);
+    visitChildren(curr, 0);
+    afterChildren(curr);
+    bool childUnreachable = curr->type == Type::unreachable;
+    // Finish the later parts of all the parent blocks.
+    while (!parents.empty()) {
+      auto* parent = parents.back();
+      parents.pop_back();
+      if (!childUnreachable) {
+        visitChildren(parent, 1);
+      }
+      afterChildren(parent);
+      childUnreachable = parent->type == Type::unreachable;
+    }
+    return;
+  }
+  // Simple case of not having a nested block in the first position.
+  emit(curr);
+  visitChildren(curr, 0);
+  afterChildren(curr);
+}
+
+template<typename SubType> void BinaryenIRWriter<SubType>::visitIf(If* curr) {
+  emit(curr);
+  visitPossibleBlockContents(curr->ifTrue);
+
+  if (curr->ifFalse) {
+    emitIfElse(curr);
+    visitPossibleBlockContents(curr->ifFalse);
+  }
+
+  emitScopeEnd(curr);
+  if (curr->type == Type::unreachable) {
+    // We already handled the case of the condition being unreachable in
+    // `visit`.  Otherwise, we may still be unreachable, if we are an if-else
+    // with both sides unreachable. Just like with blocks, we emit an extra
+    // `unreachable` to work around potential type mismatches.
+    assert(curr->ifFalse);
+    emitUnreachable();
+  }
+}
+
+template<typename SubType>
+void BinaryenIRWriter<SubType>::visitLoop(Loop* curr) {
+  emit(curr);
+  visitPossibleBlockContents(curr->body);
+  emitScopeEnd(curr);
+  if (curr->type == Type::unreachable) {
+    // we emitted a loop without a return type, so it must not be consumed
+    emitUnreachable();
+  }
+}
+
+template<typename SubType> void BinaryenIRWriter<SubType>::visitTry(Try* curr) {
+  emit(curr);
+  visitPossibleBlockContents(curr->body);
+  emitCatch(curr);
+  visitPossibleBlockContents(curr->catchBody);
+  emitScopeEnd(curr);
+  if (curr->type == Type::unreachable) {
+    emitUnreachable();
+  }
+}
+
+// Binaryen IR to binary writer
+class BinaryenIRToBinaryWriter
+  : public BinaryenIRWriter<BinaryenIRToBinaryWriter> {
+public:
+  BinaryenIRToBinaryWriter(WasmBinaryWriter& parent,
+                           BufferWithRandomAccess& o,
+                           Function* func = nullptr,
+                           bool sourceMap = false,
+                           bool DWARF = false)
+    : BinaryenIRWriter<BinaryenIRToBinaryWriter>(func), parent(parent),
+      writer(parent, o, func, sourceMap, DWARF), sourceMap(sourceMap) {}
+
+  void visit(Expression* curr) {
+    BinaryenIRWriter<BinaryenIRToBinaryWriter>::visit(curr);
+  }
+
+  void emit(Expression* curr) { writer.visit(curr); }
+  void emitHeader() {
+    if (func->prologLocation.size()) {
+      parent.writeDebugLocation(*func->prologLocation.begin());
+    }
+    writer.mapLocalsAndEmitHeader();
+  }
+  void emitIfElse(If* curr) { writer.emitIfElse(curr); }
+  void emitCatch(Try* curr) { writer.emitCatch(curr); }
+  void emitScopeEnd(Expression* curr) { writer.emitScopeEnd(curr); }
+  void emitFunctionEnd() {
+    if (func->epilogLocation.size()) {
+      parent.writeDebugLocation(*func->epilogLocation.begin());
+    }
+    writer.emitFunctionEnd();
+  }
+  void emitUnreachable() { writer.emitUnreachable(); }
+  void emitDebugLocation(Expression* curr) {
+    if (sourceMap) {
+      parent.writeDebugLocation(curr, func);
+    }
+  }
+
+private:
+  WasmBinaryWriter& parent;
+  BinaryInstWriter writer;
+  bool sourceMap;
+};
+
+// Binaryen IR to stack IR converter
+// Queues the expressions linearly in Stack IR (SIR)
+class StackIRGenerator : public BinaryenIRWriter<StackIRGenerator> {
+public:
+  StackIRGenerator(Module& module, Function* func)
+    : BinaryenIRWriter<StackIRGenerator>(func), module(module) {}
+
+  void emit(Expression* curr);
+  void emitScopeEnd(Expression* curr);
+  void emitHeader() {}
+  void emitIfElse(If* curr) {
+    stackIR.push_back(makeStackInst(StackInst::IfElse, curr));
+  }
+  void emitCatch(Try* curr) {
+    stackIR.push_back(makeStackInst(StackInst::Catch, curr));
+  }
+  void emitFunctionEnd() {}
+  void emitUnreachable() {
+    stackIR.push_back(makeStackInst(Builder(module).makeUnreachable()));
+  }
+  void emitDebugLocation(Expression* curr) {}
+
+  StackIR& getStackIR() { return stackIR; }
+
+private:
+  StackInst* makeStackInst(StackInst::Op op, Expression* origin);
+  StackInst* makeStackInst(Expression* origin) {
+    return makeStackInst(StackInst::Basic, origin);
+  }
+
+  Module& module;
+  StackIR stackIR; // filled in write()
+};
+
+// Stack IR to binary writer
+class StackIRToBinaryWriter {
+public:
+  StackIRToBinaryWriter(WasmBinaryWriter& parent,
+                        BufferWithRandomAccess& o,
+                        Function* func)
+    : writer(parent, o, func, false /* sourceMap */, false /* DWARF */),
+      func(func) {}
+
+  void write();
+
+private:
+  BinaryInstWriter writer;
+  Function* func;
+};
+
+} // namespace wasm
+
+#endif // wasm_stack_h
diff --git a/binaryen/src/wasm-traversal.h b/binaryen/src/wasm-traversal.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-traversal.h
@@ -0,0 +1,1669 @@
+/*
+ * 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.
+ */
+
+//
+// WebAssembly AST visitor. Useful for anything that wants to do something
+// different for each AST node type, like printing, interpreting, etc.
+//
+// This class is specifically designed as a template to avoid virtual function
+// call overhead. To write a visitor, derive from this class as follows:
+//
+//   struct MyVisitor : public WasmVisitor<MyVisitor> { .. }
+//
+
+#ifndef wasm_wasm_traversal_h
+#define wasm_wasm_traversal_h
+
+#include "support/small_vector.h"
+#include "support/threads.h"
+#include "wasm.h"
+
+namespace wasm {
+
+// A generic visitor, defaulting to doing nothing on each visit
+
+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");
+    }
+  }
+};
+
+// Stacks of expressions tend to be limited in size (although, sometimes
+// super-nested blocks exist for br_table).
+typedef SmallVector<Expression*, 10> ExpressionStack;
+
+// Traversal with a control-flow stack.
+
+template<typename SubType, typename VisitorType = Visitor<SubType>>
+struct ControlFlowWalker : public PostWalker<SubType, VisitorType> {
+  ControlFlowWalker() = default;
+
+  ExpressionStack controlFlowStack; // contains blocks, loops, and ifs
+
+  // Uses the control flow stack to find the target of a break to a name
+  Expression* findBreakTarget(Name name) {
+    assert(!controlFlowStack.empty());
+    Index i = controlFlowStack.size() - 1;
+    while (true) {
+      auto* curr = controlFlowStack[i];
+      if (Block* block = curr->template dynCast<Block>()) {
+        if (name == block->name) {
+          return curr;
+        }
+      } else if (Loop* loop = curr->template dynCast<Loop>()) {
+        if (name == loop->name) {
+          return curr;
+        }
+      } else {
+        // an if or try, ignorable
+        assert(curr->template is<If>() || curr->template is<Try>());
+      }
+      if (i == 0) {
+        return nullptr;
+      }
+      i--;
+    }
+  }
+
+  static void doPreVisitControlFlow(SubType* self, Expression** currp) {
+    self->controlFlowStack.push_back(*currp);
+  }
+
+  static void doPostVisitControlFlow(SubType* self, Expression** currp) {
+    // note that we might be popping something else, as we may have been
+    // replaced
+    self->controlFlowStack.pop_back();
+  }
+
+  static void scan(SubType* self, Expression** currp) {
+    auto* curr = *currp;
+
+    switch (curr->_id) {
+      case Expression::Id::BlockId:
+      case Expression::Id::IfId:
+      case Expression::Id::LoopId:
+      case Expression::Id::TryId: {
+        self->pushTask(SubType::doPostVisitControlFlow, currp);
+        break;
+      }
+      default: {
+      }
+    }
+
+    PostWalker<SubType, VisitorType>::scan(self, currp);
+
+    switch (curr->_id) {
+      case Expression::Id::BlockId:
+      case Expression::Id::IfId:
+      case Expression::Id::LoopId:
+      case Expression::Id::TryId: {
+        self->pushTask(SubType::doPreVisitControlFlow, currp);
+        break;
+      }
+      default: {
+      }
+    }
+  }
+};
+
+// Traversal with an expression stack.
+
+template<typename SubType, typename VisitorType = Visitor<SubType>>
+struct ExpressionStackWalker : public PostWalker<SubType, VisitorType> {
+  ExpressionStackWalker() = default;
+
+  ExpressionStack expressionStack;
+
+  // Uses the control flow stack to find the target of a break to a name
+  Expression* findBreakTarget(Name name) {
+    assert(!expressionStack.empty());
+    Index i = expressionStack.size() - 1;
+    while (true) {
+      auto* curr = expressionStack[i];
+      if (Block* block = curr->template dynCast<Block>()) {
+        if (name == block->name) {
+          return curr;
+        }
+      } else if (Loop* loop = curr->template dynCast<Loop>()) {
+        if (name == loop->name) {
+          return curr;
+        }
+      }
+      if (i == 0) {
+        return nullptr;
+      }
+      i--;
+    }
+  }
+
+  Expression* getParent() {
+    if (expressionStack.size() == 1) {
+      return nullptr;
+    }
+    assert(expressionStack.size() >= 2);
+    return expressionStack[expressionStack.size() - 2];
+  }
+
+  static void doPreVisit(SubType* self, Expression** currp) {
+    self->expressionStack.push_back(*currp);
+  }
+
+  static void doPostVisit(SubType* self, Expression** currp) {
+    self->expressionStack.pop_back();
+  }
+
+  static void scan(SubType* self, Expression** currp) {
+    self->pushTask(SubType::doPostVisit, currp);
+
+    PostWalker<SubType, VisitorType>::scan(self, currp);
+
+    self->pushTask(SubType::doPreVisit, currp);
+  }
+
+  Expression* replaceCurrent(Expression* expression) {
+    PostWalker<SubType, VisitorType>::replaceCurrent(expression);
+    // also update the stack
+    expressionStack.back() = expression;
+    return expression;
+  }
+};
+
+// Traversal in the order of execution. This is quick and simple, but
+// does not provide the same comprehensive information that a full
+// conversion to basic blocks would. What it does give is a quick
+// way to view straightline execution traces, i.e., that have no
+// branching. This can let optimizations get most of what they
+// want without the cost of creating another AST.
+//
+// When execution is no longer linear, this notifies via a call
+// to noteNonLinear().
+
+template<typename SubType, typename VisitorType = Visitor<SubType>>
+struct LinearExecutionWalker : public PostWalker<SubType, VisitorType> {
+  LinearExecutionWalker() = default;
+
+  // subclasses should implement this
+  void noteNonLinear(Expression* curr) { abort(); }
+
+  static void doNoteNonLinear(SubType* self, Expression** currp) {
+    self->noteNonLinear(*currp);
+  }
+
+  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);
+        if (curr->cast<Block>()->name.is()) {
+          self->pushTask(SubType::doNoteNonLinear, 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->pushTask(SubType::doNoteNonLinear, currp);
+        self->maybePushTask(SubType::scan, &curr->cast<If>()->ifFalse);
+        self->pushTask(SubType::doNoteNonLinear, currp);
+        self->pushTask(SubType::scan, &curr->cast<If>()->ifTrue);
+        self->pushTask(SubType::doNoteNonLinear, currp);
+        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);
+        self->pushTask(SubType::doNoteNonLinear, currp);
+        break;
+      }
+      case Expression::Id::BreakId: {
+        self->pushTask(SubType::doVisitBreak, currp);
+        self->pushTask(SubType::doNoteNonLinear, 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::doNoteNonLinear, currp);
+        self->maybePushTask(SubType::scan, &curr->cast<Switch>()->value);
+        self->pushTask(SubType::scan, &curr->cast<Switch>()->condition);
+        break;
+      }
+      case Expression::Id::ReturnId: {
+        self->pushTask(SubType::doVisitReturn, currp);
+        self->pushTask(SubType::doNoteNonLinear, currp);
+        self->maybePushTask(SubType::scan, &curr->cast<Return>()->value);
+        break;
+      }
+      case Expression::Id::TryId: {
+        self->pushTask(SubType::doVisitTry, currp);
+        self->pushTask(SubType::doNoteNonLinear, currp);
+        self->pushTask(SubType::scan, &curr->cast<Try>()->catchBody);
+        self->pushTask(SubType::doNoteNonLinear, currp);
+        self->pushTask(SubType::scan, &curr->cast<Try>()->body);
+        break;
+      }
+      case Expression::Id::ThrowId: {
+        self->pushTask(SubType::doVisitThrow, currp);
+        self->pushTask(SubType::doNoteNonLinear, 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::doNoteNonLinear, currp);
+        self->pushTask(SubType::scan, &curr->cast<Rethrow>()->exnref);
+        break;
+      }
+      case Expression::Id::BrOnExnId: {
+        self->pushTask(SubType::doVisitBrOnExn, currp);
+        self->pushTask(SubType::doNoteNonLinear, currp);
+        self->pushTask(SubType::scan, &curr->cast<BrOnExn>()->exnref);
+        break;
+      }
+      case Expression::Id::UnreachableId: {
+        self->pushTask(SubType::doVisitUnreachable, currp);
+        self->pushTask(SubType::doNoteNonLinear, currp);
+        break;
+      }
+      default: {
+        // other node types do not have control flow, use regular post-order
+        PostWalker<SubType, VisitorType>::scan(self, currp);
+      }
+    }
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_wasm_traversal_h
diff --git a/binaryen/src/wasm-type.h b/binaryen/src/wasm-type.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-type.h
@@ -0,0 +1,449 @@
+/*
+ * 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_wasm_type_h
+#define wasm_wasm_type_h
+
+#include "wasm-features.h"
+#include <ostream>
+#include <vector>
+
+// TODO: At various code locations we were assuming that single types are basic
+// types, but this is going to change with the introduction of the compound
+// Signature, Struct and Array types that will be single but not basic. To
+// prepare for this change, the following macro marks affected code locations.
+#define TODO_SINGLE_COMPOUND(type)                                             \
+  assert(!type.isTuple() && "Unexpected tuple type");                          \
+  assert(!type.isCompound() && "TODO: handle compound types");
+
+namespace wasm {
+
+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`
+  // 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.
+  uintptr_t id;
+
+public:
+  enum BasicID : uint32_t {
+    none,
+    unreachable,
+    i32,
+    i64,
+    f32,
+    f64,
+    v128,
+    funcref,
+    externref,
+    exnref,
+    anyref,
+    eqref,
+    i31ref,
+    _last_basic_id = i31ref,
+  };
+
+  Type() = default;
+
+  // BasicID can be implicitly upgraded to Type
+  constexpr Type(BasicID id) : id(id){};
+
+  // But converting raw uint32_t is more dangerous, so make it explicit
+  explicit Type(uint64_t 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&);
+
+  // 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);
+
+  // Construct from rtt description
+  explicit Type(const struct Rtt&);
+
+  // Predicates
+  //                 Compound Concrete
+  //   Type        Basic │ Single│
+  // ╒═════════════╦═│═╤═│═╤═│═╤═│═╤═══════╕
+  // │ none        ║ x │   │   │   │       │
+  // │ unreachable ║ x │   │   │   │       │
+  // ├─────────────╫───┼───┼───┼───┤───────┤
+  // │ i32         ║ x │   │ x │ x │ I     │ ┐ Number
+  // │ i64         ║ x │   │ x │ x │ I     │ │  I_nteger
+  // │ f32         ║ x │   │ x │ x │   F   │ │  F_loat
+  // │ f64         ║ x │   │ x │ x │   F   │ │  V_ector
+  // │ v128        ║ x │   │ x │ x │     V │ ┘
+  // ├─ Aliases ───╫───┼───┼───┼───┤───────┤
+  // │ funcref     ║ x │   │ x │ x │ f  n  │ ┐ Ref
+  // │ externref   ║ x │   │ x │ x │ f? n  │ │  f_unc
+  // │ exnref      ║ x │   │ x │ x │    n  │ │  n_ullable
+  // │ anyref      ║ x │   │ x │ x │ f? n  │ │
+  // │ eqref       ║ x │   │ x │ x │    n  │ │ ┐ TODO (GC)
+  // │ i31ref      ║ x │   │ x │ x │       │ │ ┘
+  // ├─ Compound ──╫───┼───┼───┼───┤───────┤ │
+  // │ Ref         ║   │ x │ x │ x │ f? n? │◄┘
+  // │ 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 isConcrete() const { return id >= i32; }
+  constexpr bool isInteger() const { return id == i32 || id == i64; }
+  constexpr bool isFloat() const { return id == f32 || id == f64; }
+  constexpr bool isVector() const { return id == v128; };
+  constexpr bool isNumber() const { return id >= i32 && id <= v128; }
+  bool isTuple() const;
+  bool isSingle() const { return isConcrete() && !isTuple(); }
+  bool isRef() const;
+  bool isFunction() const;
+  bool isException() const;
+  bool isNullable() const;
+  bool isRtt() const;
+
+private:
+  template<bool (Type::*pred)() const> bool hasPredicate() {
+    for (const auto& type : *this) {
+      if ((type.*pred)()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+public:
+  bool hasVector() { return hasPredicate<&Type::isVector>(); }
+  bool hasRef() { return hasPredicate<&Type::isRef>(); }
+
+  constexpr uint64_t getID() const { return id; }
+  constexpr BasicID getBasic() const {
+    assert(isBasic() && "Basic type expected");
+    return static_cast<BasicID>(id);
+  }
+
+  // (In)equality must be defined for both Type and BasicID 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 Type& other) const { return id != other.id; }
+  bool operator!=(const BasicID& otherId) const { return id != otherId; }
+
+  // Order types by some notion of simplicity
+  bool operator<(const Type& other) const;
+
+  // Returns the type size in bytes. Only single types are supported.
+  unsigned getByteSize() const;
+
+  // Reinterpret an integer type to a float type with the same size and vice
+  // versa. Only single integer and float types are supported.
+  Type reinterpret() const;
+
+  // Returns the feature set required to use this type.
+  FeatureSet getFeatures() const;
+
+  // Gets the heap type corresponding to this type
+  HeapType getHeapType() 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_);
+
+  // Returns true if left is a subtype of right. Subtype includes itself.
+  static bool isSubType(Type left, Type right);
+
+  // Computes the least upper bound from the type lattice.
+  // If one of the type is unreachable, the other type becomes the result. If
+  // the common supertype does not exist, returns none, a poison value.
+  static Type getLeastUpperBound(Type a, Type b);
+
+  // Computes the least upper bound for all types in the given list.
+  template<typename T> static Type mergeTypes(const T& types) {
+    Type type = Type::unreachable;
+    for (auto other : types) {
+      type = Type::getLeastUpperBound(type, other);
+    }
+    return type;
+  }
+
+  std::string toString() const;
+
+  struct Iterator
+    : std::iterator<std::random_access_iterator_tag, Type, long, Type*, Type&> {
+    const Type* parent;
+    size_t index;
+    Iterator(const Type* parent, size_t index) : parent(parent), index(index) {}
+    bool operator==(const Iterator& other) const {
+      return index == other.index && parent == other.parent;
+    }
+    bool operator!=(const Iterator& other) const { return !(*this == other); }
+    Iterator& operator++() {
+      ++index;
+      return *this;
+    }
+    Iterator& operator--() {
+      --index;
+      return *this;
+    }
+    Iterator operator++(int) {
+      auto it = *this;
+      index++;
+      return it;
+    }
+    Iterator operator--(int) {
+      auto it = *this;
+      index--;
+      return it;
+    }
+    Iterator& operator+=(difference_type off) {
+      index += off;
+      return *this;
+    }
+    Iterator operator+(difference_type off) const {
+      return Iterator(*this) += off;
+    }
+    Iterator& operator-=(difference_type off) {
+      index -= off;
+      return *this;
+    }
+    Iterator operator-(difference_type off) const {
+      return Iterator(*this) -= off;
+    }
+    difference_type operator-(const Iterator& other) const {
+      assert(parent == other.parent);
+      return index - other.index;
+    }
+    const value_type& operator*() const;
+  };
+
+  Iterator begin() const { return Iterator(this, 0); }
+  Iterator end() const;
+  size_t size() const { return end() - begin(); }
+  const Type& operator[](size_t i) const;
+};
+
+// Wrapper type for formatting types as "(param i32 i64 f32)"
+struct ParamType {
+  Type type;
+  ParamType(Type type) : type(type) {}
+  std::string toString() const;
+};
+
+// Wrapper type for formatting types as "(result i32 i64 f32)"
+struct ResultType {
+  Type type;
+  ResultType(Type type) : type(type) {}
+  std::string toString() const;
+};
+
+typedef std::vector<Type> TypeList;
+
+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)) {}
+  bool operator==(const Tuple& other) const { return types == other.types; }
+  bool operator!=(const Tuple& other) const { return !(*this == other); }
+  std::string toString() const;
+};
+
+struct Signature {
+  Type params;
+  Type results;
+  Signature() : params(Type::none), results(Type::none) {}
+  Signature(Type params, Type results) : params(params), results(results) {}
+  bool operator==(const Signature& other) const {
+    return params == other.params && results == other.results;
+  }
+  bool operator!=(const Signature& other) const { return !(*this == other); }
+  bool operator<(const Signature& other) const;
+  std::string toString() const;
+};
+
+struct Field {
+  Type type;
+  enum PackedType {
+    not_packed,
+    i8,
+    i16,
+  } packedType; // applicable iff type=i32
+  bool mutable_;
+
+  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_) {}
+
+  constexpr bool isPacked() const {
+    if (packedType != not_packed) {
+      assert(type == Type::i32 && "unexpected type");
+      return true;
+    }
+    return false;
+  }
+
+  bool operator==(const Field& other) const {
+    return type == other.type && packedType == other.packedType &&
+           mutable_ == other.mutable_;
+  }
+  bool operator!=(const Field& other) const { return !(*this == other); }
+  std::string toString() const;
+};
+
+typedef std::vector<Field> FieldList;
+
+struct Struct {
+  FieldList fields;
+  Struct(const Struct& other) : fields(other.fields) {}
+  Struct(const FieldList& fields) : fields(fields) {}
+  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); }
+  std::string toString() const;
+};
+
+struct Array {
+  Field element;
+  Array(const Array& other) : element(other.element) {}
+  Array(const Field& element) : element(element) {}
+  Array(Field&& element) : element(std::move(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);
+  std::string toString() const;
+};
+
+struct Rtt {
+  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)) {}
+  bool operator==(const Rtt& other) const {
+    return depth == other.depth && heapType == other.heapType;
+  }
+  bool operator!=(const Rtt& other) const { return !(*this == other); }
+  std::string toString() const;
+};
+
+std::ostream& operator<<(std::ostream&, Type);
+std::ostream& operator<<(std::ostream&, ParamType);
+std::ostream& operator<<(std::ostream&, ResultType);
+std::ostream& operator<<(std::ostream&, Tuple);
+std::ostream& operator<<(std::ostream&, Signature);
+std::ostream& operator<<(std::ostream&, Field);
+std::ostream& operator<<(std::ostream&, Struct);
+std::ostream& operator<<(std::ostream&, Array);
+std::ostream& operator<<(std::ostream&, HeapType);
+std::ostream& operator<<(std::ostream&, Rtt);
+
+} // namespace wasm
+
+namespace std {
+
+template<> class hash<wasm::Type> {
+public:
+  size_t operator()(const wasm::Type&) const;
+};
+template<> class hash<wasm::Tuple> {
+public:
+  size_t operator()(const wasm::Tuple&) const;
+};
+template<> class hash<wasm::Signature> {
+public:
+  size_t operator()(const wasm::Signature&) const;
+};
+template<> class hash<wasm::Field> {
+public:
+  size_t operator()(const wasm::Field&) const;
+};
+template<> class hash<wasm::Struct> {
+public:
+  size_t operator()(const wasm::Struct&) const;
+};
+template<> class hash<wasm::Array> {
+public:
+  size_t operator()(const wasm::Array&) const;
+};
+template<> class hash<wasm::HeapType> {
+public:
+  size_t operator()(const wasm::HeapType&) const;
+};
+template<> class hash<wasm::Rtt> {
+public:
+  size_t operator()(const wasm::Rtt&) const;
+};
+
+} // namespace std
+
+#endif // wasm_wasm_type_h
diff --git a/binaryen/src/wasm-validator.h b/binaryen/src/wasm-validator.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-validator.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// Simple WebAssembly module validator.
+//
+// There are some options regarding how to validate:
+//
+//  * validateWeb: The Web platform doesn't have i64 values, so it is illegal
+//                 to import or export such a value. When this option is set,
+//                 such imports/exports are validation errors.
+//
+//  * validateGlobally: Binaryen supports building modules in parallel, which
+//                      means you can add and optimize a function before the
+//                      module is complete, for example, you can add function A
+//                      with a call to function B before function B exists.
+//                      When validateGlobally is disabled, we don't look at
+//                      global correctness, and instead only check inside
+//                      each function (so in the example above we wouldn't care
+//                      about function B not existing yet, but we would care
+//                      if e.g. inside function A an i32.add receives an i64).
+//
+//  * quiet: Whether to log errors verbosely.
+//
+
+#ifndef wasm_wasm_validator_h
+#define wasm_wasm_validator_h
+
+#include <set>
+#include <sstream>
+#include <unordered_set>
+
+#include "wasm-printing.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct WasmValidator {
+  enum FlagValues {
+    Minimal = 0,
+    Web = 1 << 0,
+    Globally = 1 << 1,
+    Quiet = 1 << 2
+  };
+  typedef uint32_t Flags;
+
+  bool validate(Module& module, Flags flags = Globally);
+};
+
+} // namespace wasm
+
+#endif // wasm_wasm_validator_h
diff --git a/binaryen/src/wasm.h b/binaryen/src/wasm.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm.h
@@ -0,0 +1,1721 @@
+/*
+ * Copyright 2015 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.h: Define Binaryen IR, a representation for WebAssembly, with
+//         all core parts in one simple header file.
+//
+// For more overview, see README.md
+//
+
+#ifndef wasm_wasm_h
+#define wasm_wasm_h
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "literal.h"
+#include "mixed_arena.h"
+#include "support/name.h"
+#include "wasm-features.h"
+#include "wasm-type.h"
+
+namespace wasm {
+
+// An index in a wasm module
+typedef uint32_t Index;
+
+// An address in linear memory.
+struct Address {
+  typedef uint32_t address32_t;
+  typedef uint64_t address64_t;
+  address64_t addr;
+  Address() : addr(0) {}
+  Address(uint64_t a) : addr(a) {}
+  Address& operator=(uint64_t a) {
+    addr = a;
+    return *this;
+  }
+  operator address64_t() const { return addr; }
+  Address& operator++() {
+    ++addr;
+    return *this;
+  }
+};
+
+enum class IRProfile { Normal, Poppy };
+
+// Operators
+
+enum UnaryOp {
+  // int
+  ClzInt32,
+  ClzInt64,
+  CtzInt32,
+  CtzInt64,
+  PopcntInt32,
+  PopcntInt64,
+
+  // float
+  NegFloat32,
+  NegFloat64,
+  AbsFloat32,
+  AbsFloat64,
+  CeilFloat32,
+  CeilFloat64,
+  FloorFloat32,
+  FloorFloat64,
+  TruncFloat32,
+  TruncFloat64,
+  NearestFloat32,
+  NearestFloat64,
+  SqrtFloat32,
+  SqrtFloat64,
+
+  // relational
+  EqZInt32,
+  EqZInt64,
+
+  // conversions
+  // extend i32 to i64
+  ExtendSInt32,
+  ExtendUInt32,
+  // i64 to i32
+  WrapInt64,
+  // float to int
+  TruncSFloat32ToInt32,
+  TruncSFloat32ToInt64,
+  TruncUFloat32ToInt32,
+  TruncUFloat32ToInt64,
+  TruncSFloat64ToInt32,
+  TruncSFloat64ToInt64,
+  TruncUFloat64ToInt32,
+  TruncUFloat64ToInt64,
+  // reintepret bits to int
+  ReinterpretFloat32,
+  ReinterpretFloat64,
+  // int to float
+  ConvertSInt32ToFloat32,
+  ConvertSInt32ToFloat64,
+  ConvertUInt32ToFloat32,
+  ConvertUInt32ToFloat64,
+  ConvertSInt64ToFloat32,
+  ConvertSInt64ToFloat64,
+  ConvertUInt64ToFloat32,
+  ConvertUInt64ToFloat64,
+  // f32 to f64
+  PromoteFloat32,
+  // f64 to f32
+  DemoteFloat64,
+  // reinterpret bits to float
+  ReinterpretInt32,
+  ReinterpretInt64,
+
+  // Extend signed subword-sized integer. This differs from e.g. ExtendSInt32
+  // because the input integer is in an i64 value insetad of an i32 value.
+  ExtendS8Int32,
+  ExtendS16Int32,
+  ExtendS8Int64,
+  ExtendS16Int64,
+  ExtendS32Int64,
+
+  // Saturating float-to-int
+  TruncSatSFloat32ToInt32,
+  TruncSatUFloat32ToInt32,
+  TruncSatSFloat64ToInt32,
+  TruncSatUFloat64ToInt32,
+  TruncSatSFloat32ToInt64,
+  TruncSatUFloat32ToInt64,
+  TruncSatSFloat64ToInt64,
+  TruncSatUFloat64ToInt64,
+
+  // SIMD splats
+  SplatVecI8x16,
+  SplatVecI16x8,
+  SplatVecI32x4,
+  SplatVecI64x2,
+  SplatVecF32x4,
+  SplatVecF64x2,
+
+  // SIMD arithmetic
+  NotVec128,
+  AbsVecI8x16,
+  NegVecI8x16,
+  AnyTrueVecI8x16,
+  AllTrueVecI8x16,
+  BitmaskVecI8x16,
+  AbsVecI16x8,
+  NegVecI16x8,
+  AnyTrueVecI16x8,
+  AllTrueVecI16x8,
+  BitmaskVecI16x8,
+  AbsVecI32x4,
+  NegVecI32x4,
+  AnyTrueVecI32x4,
+  AllTrueVecI32x4,
+  BitmaskVecI32x4,
+  NegVecI64x2,
+  AnyTrueVecI64x2,
+  AllTrueVecI64x2,
+  AbsVecF32x4,
+  NegVecF32x4,
+  SqrtVecF32x4,
+  CeilVecF32x4,
+  FloorVecF32x4,
+  TruncVecF32x4,
+  NearestVecF32x4,
+  AbsVecF64x2,
+  NegVecF64x2,
+  SqrtVecF64x2,
+  CeilVecF64x2,
+  FloorVecF64x2,
+  TruncVecF64x2,
+  NearestVecF64x2,
+
+  // SIMD conversions
+  TruncSatSVecF32x4ToVecI32x4,
+  TruncSatUVecF32x4ToVecI32x4,
+  TruncSatSVecF64x2ToVecI64x2,
+  TruncSatUVecF64x2ToVecI64x2,
+  ConvertSVecI32x4ToVecF32x4,
+  ConvertUVecI32x4ToVecF32x4,
+  ConvertSVecI64x2ToVecF64x2,
+  ConvertUVecI64x2ToVecF64x2,
+  WidenLowSVecI8x16ToVecI16x8,
+  WidenHighSVecI8x16ToVecI16x8,
+  WidenLowUVecI8x16ToVecI16x8,
+  WidenHighUVecI8x16ToVecI16x8,
+  WidenLowSVecI16x8ToVecI32x4,
+  WidenHighSVecI16x8ToVecI32x4,
+  WidenLowUVecI16x8ToVecI32x4,
+  WidenHighUVecI16x8ToVecI32x4,
+
+  InvalidUnary
+};
+
+enum BinaryOp {
+  // int or float
+  AddInt32,
+  SubInt32,
+  MulInt32,
+
+  // int
+  DivSInt32,
+  DivUInt32,
+  RemSInt32,
+  RemUInt32,
+  AndInt32,
+  OrInt32,
+  XorInt32,
+  ShlInt32,
+  ShrSInt32,
+  ShrUInt32,
+  RotLInt32,
+  RotRInt32,
+
+  // relational ops
+  // int or float
+  EqInt32,
+  NeInt32,
+  // int
+  LtSInt32,
+  LtUInt32,
+  LeSInt32,
+  LeUInt32,
+  GtSInt32,
+  GtUInt32,
+  GeSInt32,
+  GeUInt32,
+
+  // int or float
+  AddInt64,
+  SubInt64,
+  MulInt64,
+
+  // int
+  DivSInt64,
+  DivUInt64,
+  RemSInt64,
+  RemUInt64,
+  AndInt64,
+  OrInt64,
+  XorInt64,
+  ShlInt64,
+  ShrSInt64,
+  ShrUInt64,
+  RotLInt64,
+  RotRInt64,
+
+  // relational ops
+  // int or float
+  EqInt64,
+  NeInt64,
+  // int
+  LtSInt64,
+  LtUInt64,
+  LeSInt64,
+  LeUInt64,
+  GtSInt64,
+  GtUInt64,
+  GeSInt64,
+  GeUInt64,
+
+  // int or float
+  AddFloat32,
+  SubFloat32,
+  MulFloat32,
+
+  // float
+  DivFloat32,
+  CopySignFloat32,
+  MinFloat32,
+  MaxFloat32,
+
+  // relational ops
+  // int or float
+  EqFloat32,
+  NeFloat32,
+  // float
+  LtFloat32,
+  LeFloat32,
+  GtFloat32,
+  GeFloat32,
+
+  // int or float
+  AddFloat64,
+  SubFloat64,
+  MulFloat64,
+
+  // float
+  DivFloat64,
+  CopySignFloat64,
+  MinFloat64,
+  MaxFloat64,
+
+  // relational ops
+  // int or float
+  EqFloat64,
+  NeFloat64,
+  // float
+  LtFloat64,
+  LeFloat64,
+  GtFloat64,
+  GeFloat64,
+
+  // SIMD relational ops (return vectors)
+  EqVecI8x16,
+  NeVecI8x16,
+  LtSVecI8x16,
+  LtUVecI8x16,
+  GtSVecI8x16,
+  GtUVecI8x16,
+  LeSVecI8x16,
+  LeUVecI8x16,
+  GeSVecI8x16,
+  GeUVecI8x16,
+  EqVecI16x8,
+  NeVecI16x8,
+  LtSVecI16x8,
+  LtUVecI16x8,
+  GtSVecI16x8,
+  GtUVecI16x8,
+  LeSVecI16x8,
+  LeUVecI16x8,
+  GeSVecI16x8,
+  GeUVecI16x8,
+  EqVecI32x4,
+  NeVecI32x4,
+  LtSVecI32x4,
+  LtUVecI32x4,
+  GtSVecI32x4,
+  GtUVecI32x4,
+  LeSVecI32x4,
+  LeUVecI32x4,
+  GeSVecI32x4,
+  GeUVecI32x4,
+  EqVecF32x4,
+  NeVecF32x4,
+  LtVecF32x4,
+  GtVecF32x4,
+  LeVecF32x4,
+  GeVecF32x4,
+  EqVecF64x2,
+  NeVecF64x2,
+  LtVecF64x2,
+  GtVecF64x2,
+  LeVecF64x2,
+  GeVecF64x2,
+
+  // SIMD arithmetic
+  AndVec128,
+  OrVec128,
+  XorVec128,
+  AndNotVec128,
+  AddVecI8x16,
+  AddSatSVecI8x16,
+  AddSatUVecI8x16,
+  SubVecI8x16,
+  SubSatSVecI8x16,
+  SubSatUVecI8x16,
+  MulVecI8x16,
+  MinSVecI8x16,
+  MinUVecI8x16,
+  MaxSVecI8x16,
+  MaxUVecI8x16,
+  AvgrUVecI8x16,
+  AddVecI16x8,
+  AddSatSVecI16x8,
+  AddSatUVecI16x8,
+  SubVecI16x8,
+  SubSatSVecI16x8,
+  SubSatUVecI16x8,
+  MulVecI16x8,
+  MinSVecI16x8,
+  MinUVecI16x8,
+  MaxSVecI16x8,
+  MaxUVecI16x8,
+  AvgrUVecI16x8,
+  AddVecI32x4,
+  SubVecI32x4,
+  MulVecI32x4,
+  MinSVecI32x4,
+  MinUVecI32x4,
+  MaxSVecI32x4,
+  MaxUVecI32x4,
+  DotSVecI16x8ToVecI32x4,
+  AddVecI64x2,
+  SubVecI64x2,
+  MulVecI64x2,
+  AddVecF32x4,
+  SubVecF32x4,
+  MulVecF32x4,
+  DivVecF32x4,
+  MinVecF32x4,
+  MaxVecF32x4,
+  PMinVecF32x4,
+  PMaxVecF32x4,
+  AddVecF64x2,
+  SubVecF64x2,
+  MulVecF64x2,
+  DivVecF64x2,
+  MinVecF64x2,
+  MaxVecF64x2,
+  PMinVecF64x2,
+  PMaxVecF64x2,
+
+  // SIMD Conversion
+  NarrowSVecI16x8ToVecI8x16,
+  NarrowUVecI16x8ToVecI8x16,
+  NarrowSVecI32x4ToVecI16x8,
+  NarrowUVecI32x4ToVecI16x8,
+
+  // SIMD Swizzle
+  SwizzleVec8x16,
+
+  InvalidBinary
+};
+
+enum AtomicRMWOp { Add, Sub, And, Or, Xor, Xchg };
+
+enum SIMDExtractOp {
+  ExtractLaneSVecI8x16,
+  ExtractLaneUVecI8x16,
+  ExtractLaneSVecI16x8,
+  ExtractLaneUVecI16x8,
+  ExtractLaneVecI32x4,
+  ExtractLaneVecI64x2,
+  ExtractLaneVecF32x4,
+  ExtractLaneVecF64x2
+};
+
+enum SIMDReplaceOp {
+  ReplaceLaneVecI8x16,
+  ReplaceLaneVecI16x8,
+  ReplaceLaneVecI32x4,
+  ReplaceLaneVecI64x2,
+  ReplaceLaneVecF32x4,
+  ReplaceLaneVecF64x2
+};
+
+enum SIMDShiftOp {
+  ShlVecI8x16,
+  ShrSVecI8x16,
+  ShrUVecI8x16,
+  ShlVecI16x8,
+  ShrSVecI16x8,
+  ShrUVecI16x8,
+  ShlVecI32x4,
+  ShrSVecI32x4,
+  ShrUVecI32x4,
+  ShlVecI64x2,
+  ShrSVecI64x2,
+  ShrUVecI64x2
+};
+
+enum SIMDLoadOp {
+  LoadSplatVec8x16,
+  LoadSplatVec16x8,
+  LoadSplatVec32x4,
+  LoadSplatVec64x2,
+  LoadExtSVec8x8ToVecI16x8,
+  LoadExtUVec8x8ToVecI16x8,
+  LoadExtSVec16x4ToVecI32x4,
+  LoadExtUVec16x4ToVecI32x4,
+  LoadExtSVec32x2ToVecI64x2,
+  LoadExtUVec32x2ToVecI64x2,
+  Load32Zero,
+  Load64Zero
+};
+
+enum SIMDTernaryOp { Bitselect, QFMAF32x4, QFMSF32x4, QFMAF64x2, QFMSF64x2 };
+
+//
+// Expressions
+//
+// Note that little is provided in terms of constructors for these. The
+// rationale is that writing  new Something(a, b, c, d, e)  is not the clearest,
+// and it would be better to write   new Something(name=a, leftOperand=b...
+// etc., but C++ lacks named operands, so in asm2wasm etc. you will see things
+// like
+//   auto x = new Something();
+//   x->name = a;
+//   x->leftOperand = b;
+//   ..
+// which is less compact but less ambiguous. See wasm-builder.h for a more
+// friendly API for building nodes.
+//
+// Most nodes have no need of internal allocation, and when arena-allocated
+// they drop the provided arena on the floor. You can create random instances
+// of those that are not in an arena without issue. However, the nodes that
+// have internal allocation will need an allocator provided to them in order
+// to be constructed.
+
+class Expression {
+public:
+  enum Id {
+    InvalidId = 0,
+    BlockId,
+    IfId,
+    LoopId,
+    BreakId,
+    SwitchId,
+    CallId,
+    CallIndirectId,
+    LocalGetId,
+    LocalSetId,
+    GlobalGetId,
+    GlobalSetId,
+    LoadId,
+    StoreId,
+    ConstId,
+    UnaryId,
+    BinaryId,
+    SelectId,
+    DropId,
+    ReturnId,
+    MemorySizeId,
+    MemoryGrowId,
+    NopId,
+    UnreachableId,
+    AtomicRMWId,
+    AtomicCmpxchgId,
+    AtomicWaitId,
+    AtomicNotifyId,
+    AtomicFenceId,
+    SIMDExtractId,
+    SIMDReplaceId,
+    SIMDShuffleId,
+    SIMDTernaryId,
+    SIMDShiftId,
+    SIMDLoadId,
+    MemoryInitId,
+    DataDropId,
+    MemoryCopyId,
+    MemoryFillId,
+    PopId,
+    RefNullId,
+    RefIsNullId,
+    RefFuncId,
+    RefEqId,
+    TryId,
+    ThrowId,
+    RethrowId,
+    BrOnExnId,
+    TupleMakeId,
+    TupleExtractId,
+    I31NewId,
+    I31GetId,
+    RefTestId,
+    RefCastId,
+    BrOnCastId,
+    RttCanonId,
+    RttSubId,
+    StructNewId,
+    StructGetId,
+    StructSetId,
+    ArrayNewId,
+    ArrayGetId,
+    ArraySetId,
+    ArrayLenId,
+    NumExpressionIds
+  };
+  Id _id;
+
+  // the type of the expression: its *output*, not necessarily its input(s)
+  Type type = Type::none;
+
+  Expression(Id id) : _id(id) {}
+
+  void finalize() {}
+
+  template<class T> bool is() const {
+    static_assert(std::is_base_of<Expression, T>::value,
+                  "Expression is not a base of destination type T");
+    return int(_id) == int(T::SpecificId);
+  }
+
+  template<class T> T* dynCast() {
+    static_assert(std::is_base_of<Expression, T>::value,
+                  "Expression is not a base of destination type T");
+    return int(_id) == int(T::SpecificId) ? (T*)this : nullptr;
+  }
+
+  template<class T> const T* dynCast() const {
+    static_assert(std::is_base_of<Expression, T>::value,
+                  "Expression is not a base of destination type T");
+    return int(_id) == int(T::SpecificId) ? (const T*)this : nullptr;
+  }
+
+  template<class T> T* cast() {
+    static_assert(std::is_base_of<Expression, T>::value,
+                  "Expression is not a base of destination type T");
+    assert(int(_id) == int(T::SpecificId));
+    return (T*)this;
+  }
+
+  template<class T> const T* cast() const {
+    static_assert(std::is_base_of<Expression, T>::value,
+                  "Expression is not a base of destination type T");
+    assert(int(_id) == int(T::SpecificId));
+    return (const T*)this;
+  }
+
+  // Print the expression to stderr. Meant for use while debugging.
+  void dump();
+};
+
+const char* getExpressionName(Expression* curr);
+
+Literal getLiteralFromConstExpression(Expression* curr);
+Literals getLiteralsFromConstExpression(Expression* curr);
+
+typedef ArenaVector<Expression*> ExpressionList;
+
+template<Expression::Id SID> class SpecificExpression : public Expression {
+public:
+  enum {
+    SpecificId = SID // compile-time access to the type for the class
+  };
+
+  SpecificExpression() : Expression(SID) {}
+};
+
+class Nop : public SpecificExpression<Expression::NopId> {
+public:
+  Nop() = default;
+  Nop(MixedArena& allocator) {}
+};
+
+class Block : public SpecificExpression<Expression::BlockId> {
+public:
+  Block(MixedArena& allocator) : list(allocator) {}
+
+  Name name;
+  ExpressionList list;
+
+  // set the type purely based on its contents. this scans the block, so it is
+  // not fast.
+  void finalize();
+
+  // set the type given you know its type, which is the case when parsing
+  // s-expression or binary, as explicit types are given. the only additional
+  // work this does is to set the type to unreachable in the cases that is
+  // needed (which may require scanning the block)
+  void finalize(Type type_);
+
+  // 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);
+};
+
+class If : public SpecificExpression<Expression::IfId> {
+public:
+  If() : ifFalse(nullptr) {}
+  If(MixedArena& allocator) : If() {}
+
+  Expression* condition;
+  Expression* ifTrue;
+  Expression* ifFalse;
+
+  // set the type given you know its type, which is the case when parsing
+  // s-expression or binary, as explicit types are given. the only additional
+  // work this does is to set the type to unreachable in the cases that is
+  // needed.
+  void finalize(Type type_);
+
+  // set the type purely based on its contents.
+  void finalize();
+};
+
+class Loop : public SpecificExpression<Expression::LoopId> {
+public:
+  Loop() = default;
+  Loop(MixedArena& allocator) {}
+
+  Name name;
+  Expression* body;
+
+  // set the type given you know its type, which is the case when parsing
+  // s-expression or binary, as explicit types are given. the only additional
+  // work this does is to set the type to unreachable in the cases that is
+  // needed.
+  void finalize(Type type_);
+
+  // set the type purely based on its contents.
+  void finalize();
+};
+
+class Break : public SpecificExpression<Expression::BreakId> {
+public:
+  Break() : value(nullptr), condition(nullptr) {}
+  Break(MixedArena& allocator) : Break() { type = Type::unreachable; }
+
+  Name name;
+  Expression* value;
+  Expression* condition;
+
+  void finalize();
+};
+
+class Switch : public SpecificExpression<Expression::SwitchId> {
+public:
+  Switch(MixedArena& allocator) : targets(allocator) {
+    type = Type::unreachable;
+  }
+
+  ArenaVector<Name> targets;
+  Name default_;
+  Expression* condition = nullptr;
+  Expression* value = nullptr;
+
+  void finalize();
+};
+
+class Call : public SpecificExpression<Expression::CallId> {
+public:
+  Call(MixedArena& allocator) : operands(allocator) {}
+
+  ExpressionList operands;
+  Name target;
+  bool isReturn = false;
+
+  void finalize();
+};
+
+class CallIndirect : public SpecificExpression<Expression::CallIndirectId> {
+public:
+  CallIndirect(MixedArena& allocator) : operands(allocator) {}
+  Signature sig;
+  ExpressionList operands;
+  Expression* target;
+  bool isReturn = false;
+
+  void finalize();
+};
+
+class LocalGet : public SpecificExpression<Expression::LocalGetId> {
+public:
+  LocalGet() = default;
+  LocalGet(MixedArena& allocator) {}
+
+  Index index;
+};
+
+class LocalSet : public SpecificExpression<Expression::LocalSetId> {
+public:
+  LocalSet() = default;
+  LocalSet(MixedArena& allocator) {}
+
+  void finalize();
+
+  Index index;
+  Expression* value;
+
+  bool isTee() const;
+  void makeTee(Type type);
+  void makeSet();
+};
+
+class GlobalGet : public SpecificExpression<Expression::GlobalGetId> {
+public:
+  GlobalGet() = default;
+  GlobalGet(MixedArena& allocator) {}
+
+  Name name;
+};
+
+class GlobalSet : public SpecificExpression<Expression::GlobalSetId> {
+public:
+  GlobalSet() = default;
+  GlobalSet(MixedArena& allocator) {}
+
+  Name name;
+  Expression* value;
+
+  void finalize();
+};
+
+class Load : public SpecificExpression<Expression::LoadId> {
+public:
+  Load() = default;
+  Load(MixedArena& allocator) {}
+
+  uint8_t bytes;
+  bool signed_;
+  Address offset;
+  Address align;
+  bool isAtomic;
+  Expression* ptr;
+
+  // type must be set during creation, cannot be inferred
+
+  void finalize();
+};
+
+class Store : public SpecificExpression<Expression::StoreId> {
+public:
+  Store() = default;
+  Store(MixedArena& allocator) : Store() {}
+
+  uint8_t bytes;
+  Address offset;
+  Address align;
+  bool isAtomic;
+  Expression* ptr;
+  Expression* value;
+  Type valueType;
+
+  void finalize();
+};
+
+class AtomicRMW : public SpecificExpression<Expression::AtomicRMWId> {
+public:
+  AtomicRMW() = default;
+  AtomicRMW(MixedArena& allocator) : AtomicRMW() {}
+
+  AtomicRMWOp op;
+  uint8_t bytes;
+  Address offset;
+  Expression* ptr;
+  Expression* value;
+
+  void finalize();
+};
+
+class AtomicCmpxchg : public SpecificExpression<Expression::AtomicCmpxchgId> {
+public:
+  AtomicCmpxchg() = default;
+  AtomicCmpxchg(MixedArena& allocator) : AtomicCmpxchg() {}
+
+  uint8_t bytes;
+  Address offset;
+  Expression* ptr;
+  Expression* expected;
+  Expression* replacement;
+
+  void finalize();
+};
+
+class AtomicWait : public SpecificExpression<Expression::AtomicWaitId> {
+public:
+  AtomicWait() = default;
+  AtomicWait(MixedArena& allocator) : AtomicWait() {}
+
+  Address offset;
+  Expression* ptr;
+  Expression* expected;
+  Expression* timeout;
+  Type expectedType;
+
+  void finalize();
+};
+
+class AtomicNotify : public SpecificExpression<Expression::AtomicNotifyId> {
+public:
+  AtomicNotify() = default;
+  AtomicNotify(MixedArena& allocator) : AtomicNotify() {}
+
+  Address offset;
+  Expression* ptr;
+  Expression* notifyCount;
+
+  void finalize();
+};
+
+class AtomicFence : public SpecificExpression<Expression::AtomicFenceId> {
+public:
+  AtomicFence() = default;
+  AtomicFence(MixedArena& allocator) : AtomicFence() {}
+
+  // Current wasm threads only supports sequentialy consistent atomics, but
+  // other orderings may be added in the future. This field is reserved for
+  // that, and currently set to 0.
+  uint8_t order = 0;
+
+  void finalize();
+};
+
+class SIMDExtract : public SpecificExpression<Expression::SIMDExtractId> {
+public:
+  SIMDExtract() = default;
+  SIMDExtract(MixedArena& allocator) : SIMDExtract() {}
+
+  SIMDExtractOp op;
+  Expression* vec;
+  uint8_t index;
+
+  void finalize();
+};
+
+class SIMDReplace : public SpecificExpression<Expression::SIMDReplaceId> {
+public:
+  SIMDReplace() = default;
+  SIMDReplace(MixedArena& allocator) : SIMDReplace() {}
+
+  SIMDReplaceOp op;
+  Expression* vec;
+  uint8_t index;
+  Expression* value;
+
+  void finalize();
+};
+
+class SIMDShuffle : public SpecificExpression<Expression::SIMDShuffleId> {
+public:
+  SIMDShuffle() = default;
+  SIMDShuffle(MixedArena& allocator) : SIMDShuffle() {}
+
+  Expression* left;
+  Expression* right;
+  std::array<uint8_t, 16> mask;
+
+  void finalize();
+};
+
+class SIMDTernary : public SpecificExpression<Expression::SIMDTernaryId> {
+public:
+  SIMDTernary() = default;
+  SIMDTernary(MixedArena& allocator) : SIMDTernary() {}
+
+  SIMDTernaryOp op;
+  Expression* a;
+  Expression* b;
+  Expression* c;
+
+  void finalize();
+};
+
+class SIMDShift : public SpecificExpression<Expression::SIMDShiftId> {
+public:
+  SIMDShift() = default;
+  SIMDShift(MixedArena& allocator) : SIMDShift() {}
+
+  SIMDShiftOp op;
+  Expression* vec;
+  Expression* shift;
+
+  void finalize();
+};
+
+class SIMDLoad : public SpecificExpression<Expression::SIMDLoadId> {
+public:
+  SIMDLoad() = default;
+  SIMDLoad(MixedArena& allocator) {}
+
+  SIMDLoadOp op;
+  Address offset;
+  Address align;
+  Expression* ptr;
+
+  Index getMemBytes();
+  void finalize();
+};
+
+class MemoryInit : public SpecificExpression<Expression::MemoryInitId> {
+public:
+  MemoryInit() = default;
+  MemoryInit(MixedArena& allocator) : MemoryInit() {}
+
+  Index segment;
+  Expression* dest;
+  Expression* offset;
+  Expression* size;
+
+  void finalize();
+};
+
+class DataDrop : public SpecificExpression<Expression::DataDropId> {
+public:
+  DataDrop() = default;
+  DataDrop(MixedArena& allocator) : DataDrop() {}
+
+  Index segment;
+
+  void finalize();
+};
+
+class MemoryCopy : public SpecificExpression<Expression::MemoryCopyId> {
+public:
+  MemoryCopy() = default;
+  MemoryCopy(MixedArena& allocator) : MemoryCopy() {}
+
+  Expression* dest;
+  Expression* source;
+  Expression* size;
+
+  void finalize();
+};
+
+class MemoryFill : public SpecificExpression<Expression::MemoryFillId> {
+public:
+  MemoryFill() = default;
+  MemoryFill(MixedArena& allocator) : MemoryFill() {}
+
+  Expression* dest;
+  Expression* value;
+  Expression* size;
+
+  void finalize();
+};
+
+class Const : public SpecificExpression<Expression::ConstId> {
+public:
+  Const() = default;
+  Const(MixedArena& allocator) {}
+
+  Literal value;
+
+  Const* set(Literal value_);
+
+  void finalize();
+};
+
+class Unary : public SpecificExpression<Expression::UnaryId> {
+public:
+  Unary() = default;
+  Unary(MixedArena& allocator) {}
+
+  UnaryOp op;
+  Expression* value;
+
+  bool isRelational();
+
+  void finalize();
+};
+
+class Binary : public SpecificExpression<Expression::BinaryId> {
+public:
+  Binary() = default;
+  Binary(MixedArena& allocator) {}
+
+  BinaryOp op;
+  Expression* left;
+  Expression* right;
+
+  // the type is always the type of the operands,
+  // except for relationals
+
+  bool isRelational();
+
+  void finalize();
+};
+
+class Select : public SpecificExpression<Expression::SelectId> {
+public:
+  Select() = default;
+  Select(MixedArena& allocator) {}
+
+  Expression* ifTrue;
+  Expression* ifFalse;
+  Expression* condition;
+
+  void finalize();
+  void finalize(Type type_);
+};
+
+class Drop : public SpecificExpression<Expression::DropId> {
+public:
+  Drop() = default;
+  Drop(MixedArena& allocator) {}
+
+  Expression* value;
+
+  void finalize();
+};
+
+class Return : public SpecificExpression<Expression::ReturnId> {
+public:
+  Return() { type = Type::unreachable; }
+  Return(MixedArena& allocator) : Return() {}
+
+  Expression* value = nullptr;
+};
+
+class MemorySize : public SpecificExpression<Expression::MemorySizeId> {
+public:
+  MemorySize() { type = Type::i32; }
+  MemorySize(MixedArena& allocator) : MemorySize() {}
+
+  Type ptrType = Type::i32;
+
+  void make64();
+  void finalize();
+};
+
+class MemoryGrow : public SpecificExpression<Expression::MemoryGrowId> {
+public:
+  MemoryGrow() { type = Type::i32; }
+  MemoryGrow(MixedArena& allocator) : MemoryGrow() {}
+
+  Expression* delta = nullptr;
+  Type ptrType = Type::i32;
+
+  void make64();
+  void finalize();
+};
+
+class Unreachable : public SpecificExpression<Expression::UnreachableId> {
+public:
+  Unreachable() { type = Type::unreachable; }
+  Unreachable(MixedArena& allocator) : Unreachable() {}
+};
+
+// Represents a pop of a value that arrives as an implicit argument to the
+// current block. Currently used in exception handling.
+class Pop : public SpecificExpression<Expression::PopId> {
+public:
+  Pop() = default;
+  Pop(MixedArena& allocator) {}
+};
+
+class RefNull : public SpecificExpression<Expression::RefNullId> {
+public:
+  RefNull() = default;
+  RefNull(MixedArena& allocator) {}
+
+  void finalize();
+  void finalize(HeapType heapType);
+  void finalize(Type type);
+};
+
+class RefIsNull : public SpecificExpression<Expression::RefIsNullId> {
+public:
+  RefIsNull(MixedArena& allocator) {}
+
+  Expression* value;
+
+  void finalize();
+};
+
+class RefFunc : public SpecificExpression<Expression::RefFuncId> {
+public:
+  RefFunc(MixedArena& allocator) {}
+
+  Name func;
+
+  void finalize();
+};
+
+class RefEq : public SpecificExpression<Expression::RefEqId> {
+public:
+  RefEq(MixedArena& allocator) {}
+
+  Expression* left;
+  Expression* right;
+
+  void finalize();
+};
+
+class Try : public SpecificExpression<Expression::TryId> {
+public:
+  Try(MixedArena& allocator) {}
+
+  Expression* body;
+  Expression* catchBody;
+
+  void finalize();
+  void finalize(Type type_);
+};
+
+class Throw : public SpecificExpression<Expression::ThrowId> {
+public:
+  Throw(MixedArena& allocator) : operands(allocator) {}
+
+  Name event;
+  ExpressionList operands;
+
+  void finalize();
+};
+
+class Rethrow : public SpecificExpression<Expression::RethrowId> {
+public:
+  Rethrow(MixedArena& allocator) {}
+
+  Expression* exnref;
+
+  void finalize();
+};
+
+class BrOnExn : public SpecificExpression<Expression::BrOnExnId> {
+public:
+  BrOnExn() { type = Type::unreachable; }
+  BrOnExn(MixedArena& allocator) : BrOnExn() {}
+
+  Name name;
+  Name event;
+  Expression* exnref;
+  // This is duplicate info of param types stored in Event, but this is required
+  // for us to know the type of the value sent to the target block.
+  Type sent;
+
+  void finalize();
+};
+
+class TupleMake : public SpecificExpression<Expression::TupleMakeId> {
+public:
+  TupleMake(MixedArena& allocator) : operands(allocator) {}
+
+  ExpressionList operands;
+
+  void finalize();
+};
+
+class TupleExtract : public SpecificExpression<Expression::TupleExtractId> {
+public:
+  TupleExtract(MixedArena& allocator) {}
+
+  Expression* tuple;
+  Index index;
+
+  void finalize();
+};
+
+class I31New : public SpecificExpression<Expression::I31NewId> {
+public:
+  I31New(MixedArena& allocator) {}
+
+  Expression* value;
+
+  void finalize();
+};
+
+class I31Get : public SpecificExpression<Expression::I31GetId> {
+public:
+  I31Get(MixedArena& allocator) {}
+
+  Expression* i31;
+  bool signed_;
+
+  void finalize();
+};
+
+class RefTest : public SpecificExpression<Expression::RefTestId> {
+public:
+  RefTest(MixedArena& allocator) {}
+
+  void finalize() { WASM_UNREACHABLE("TODO (gc): ref.test"); }
+};
+
+class RefCast : public SpecificExpression<Expression::RefCastId> {
+public:
+  RefCast(MixedArena& allocator) {}
+
+  void finalize() { WASM_UNREACHABLE("TODO (gc): ref.cast"); }
+};
+
+class BrOnCast : public SpecificExpression<Expression::BrOnCastId> {
+public:
+  BrOnCast(MixedArena& allocator) {}
+
+  void finalize() { WASM_UNREACHABLE("TODO (gc): br_on_cast"); }
+};
+
+class RttCanon : public SpecificExpression<Expression::RttCanonId> {
+public:
+  RttCanon(MixedArena& allocator) {}
+
+  void finalize() { WASM_UNREACHABLE("TODO (gc): rtt.canon"); }
+};
+
+class RttSub : public SpecificExpression<Expression::RttSubId> {
+public:
+  RttSub(MixedArena& allocator) {}
+
+  void finalize() { WASM_UNREACHABLE("TODO (gc): rtt.sub"); }
+};
+
+class StructNew : public SpecificExpression<Expression::StructNewId> {
+public:
+  StructNew(MixedArena& allocator) {}
+
+  void finalize() { WASM_UNREACHABLE("TODO (gc): struct.new"); }
+};
+
+class StructGet : public SpecificExpression<Expression::StructGetId> {
+public:
+  StructGet(MixedArena& allocator) {}
+
+  void finalize() { WASM_UNREACHABLE("TODO (gc): struct.get"); }
+};
+
+class StructSet : public SpecificExpression<Expression::StructSetId> {
+public:
+  StructSet(MixedArena& allocator) {}
+
+  void finalize() { WASM_UNREACHABLE("TODO (gc): struct.set"); }
+};
+
+class ArrayNew : public SpecificExpression<Expression::ArrayNewId> {
+public:
+  ArrayNew(MixedArena& allocator) {}
+
+  void finalize() { WASM_UNREACHABLE("TODO (gc): array.new"); }
+};
+
+class ArrayGet : public SpecificExpression<Expression::ArrayGetId> {
+public:
+  ArrayGet(MixedArena& allocator) {}
+
+  void finalize() { WASM_UNREACHABLE("TODO (gc): array.get"); }
+};
+
+class ArraySet : public SpecificExpression<Expression::ArraySetId> {
+public:
+  ArraySet(MixedArena& allocator) {}
+
+  void finalize() { WASM_UNREACHABLE("TODO (gc): array.set"); }
+};
+
+class ArrayLen : public SpecificExpression<Expression::ArrayLenId> {
+public:
+  ArrayLen(MixedArena& allocator) {}
+
+  void finalize() { WASM_UNREACHABLE("TODO (gc): array.len"); }
+};
+
+// Globals
+
+struct Importable {
+  // If these are set, then this is an import, as module.base
+  Name module, base;
+
+  bool imported() { return module.is(); }
+};
+
+class Function;
+
+// Represents an offset into a wasm binary file. This is used for debug info.
+// For now, assume this is 32 bits as that's the size limit of wasm files
+// anyhow.
+using BinaryLocation = uint32_t;
+
+// Represents a mapping of wasm module elements to their location in the
+// binary representation. This is used for general debugging info support.
+// Offsets are relative to the beginning of the code section, as in DWARF.
+struct BinaryLocations {
+  struct Span {
+    BinaryLocation start = 0, end = 0;
+  };
+
+  // Track the range of addresses an expressions appears at. This is the
+  // contiguous range that all instructions have - control flow instructions
+  // have additional opcodes later (like an end for a block or loop), see
+  // just after this.
+  std::unordered_map<Expression*, Span> expressions;
+
+  // Track the extra delimiter positions that some instructions, in particular
+  // 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> {
+    DelimiterLocations() {
+      // Ensure zero-initialization.
+      for (auto& item : *this) {
+        item = 0;
+      }
+    }
+  };
+
+  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
+  };
+  std::unordered_map<Expression*, DelimiterLocations> delimiters;
+
+  // DWARF debug info can refer to multiple interesting positions in a function.
+  struct FunctionLocations {
+    // The very start of the function, where the binary has a size LEB.
+    BinaryLocation start = 0;
+    // The area where we declare locals, which is right after the size LEB.
+    BinaryLocation declarations = 0;
+    // The end, which is one past the final "end" instruction byte.
+    BinaryLocation end = 0;
+  };
+
+  std::unordered_map<Function*, FunctionLocations> functions;
+};
+
+// Forward declarations of Stack IR, as functions can contain it, see
+// the stackIR property.
+// Stack IR is a secondary IR to the main IR defined in this file (Binaryen
+// IR). See wasm-stack.h.
+class StackInst;
+
+using StackIR = std::vector<StackInst*>;
+
+class Function : public Importable {
+public:
+  Name name;
+  Signature sig; // parameters and return value
+  IRProfile profile = IRProfile::Normal;
+  std::vector<Type> vars; // non-param locals
+
+  // The body of the function
+  Expression* body = nullptr;
+
+  // If present, this stack IR was generated from the main Binaryen IR body,
+  // and possibly optimized. If it is present when writing to wasm binary,
+  // it will be emitted instead of the main Binaryen IR.
+  //
+  // Note that no special care is taken to synchronize the two IRs - if you
+  // emit stack IR and then optimize the main IR, you need to recompute the
+  // stack IR. The Pass system will throw away Stack IR if a pass is run
+  // that declares it may modify Binaryen IR.
+  std::unique_ptr<StackIR> stackIR;
+
+  // local names. these are optional.
+  std::map<Index, Name> localNames;
+  std::map<Name, Index> localIndices;
+
+  // Source maps debugging info: map expression nodes to their file, line, col.
+  struct DebugLocation {
+    BinaryLocation fileIndex, lineNumber, columnNumber;
+    bool operator==(const DebugLocation& other) const {
+      return fileIndex == other.fileIndex && lineNumber == other.lineNumber &&
+             columnNumber == other.columnNumber;
+    }
+    bool operator!=(const DebugLocation& other) const {
+      return !(*this == other);
+    }
+    bool operator<(const DebugLocation& other) const {
+      return fileIndex != other.fileIndex
+               ? fileIndex < other.fileIndex
+               : lineNumber != other.lineNumber
+                   ? lineNumber < other.lineNumber
+                   : columnNumber < other.columnNumber;
+    }
+  };
+  std::unordered_map<Expression*, DebugLocation> debugLocations;
+  std::set<DebugLocation> prologLocation;
+  std::set<DebugLocation> epilogLocation;
+
+  // General debugging info support: track instructions and the function itself.
+  std::unordered_map<Expression*, BinaryLocations::Span> expressionLocations;
+  std::unordered_map<Expression*, BinaryLocations::DelimiterLocations>
+    delimiterLocations;
+  BinaryLocations::FunctionLocations funcLocation;
+
+  size_t getNumParams();
+  size_t getNumVars();
+  size_t getNumLocals();
+
+  bool isParam(Index index);
+  bool isVar(Index index);
+
+  Name getLocalName(Index index);
+  Index getLocalIndex(Name name);
+  Index getVarIndexBase();
+  Type getLocalType(Index index);
+
+  Name getLocalNameOrDefault(Index index);
+  Name getLocalNameOrGeneric(Index index);
+
+  bool hasLocalName(Index index) const;
+  void setLocalName(Index index, Name name);
+
+  void clearNames();
+  void clearDebugInfo();
+};
+
+// The kind of an import or export.
+enum class ExternalKind {
+  Function = 0,
+  Table = 1,
+  Memory = 2,
+  Global = 3,
+  Event = 4,
+  Invalid = -1
+};
+
+class Export {
+public:
+  // exported name - note that this is the key, as the internal name is
+  // non-unique (can have multiple exports for an internal, also over kinds)
+  Name name;
+  Name value; // internal name
+  ExternalKind kind;
+};
+
+class Table : public Importable {
+public:
+  static const Address::address32_t kPageSize = 1;
+  static const Index kUnlimitedSize = Index(-1);
+  // In wasm32/64, the maximum table size is limited by a 32-bit pointer: 4GB
+  static const Index kMaxSize = Index(-1);
+
+  struct Segment {
+    Expression* offset;
+    std::vector<Name> data;
+    Segment() = default;
+    Segment(Expression* offset) : offset(offset) {}
+    Segment(Expression* offset, std::vector<Name>& init) : offset(offset) {
+      data.swap(init);
+    }
+  };
+
+  // Currently the wasm object always 'has' one Table. It 'exists' if it has
+  // 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;
+
+  Table() { name = Name::fromInt(0); }
+  bool hasMax() { return max != kUnlimitedSize; }
+  void clear() {
+    exists = false;
+    name = "";
+    initial = 0;
+    max = kMaxSize;
+    segments.clear();
+  }
+};
+
+class Memory : public Importable {
+public:
+  static const Address::address32_t kPageSize = 64 * 1024;
+  static const Address::address64_t kUnlimitedSize = Address::address64_t(-1);
+  // In wasm32, the maximum memory size is limited by a 32-bit pointer: 4GB
+  static const Address::address32_t kMaxSize32 =
+    (uint64_t(4) * 1024 * 1024 * 1024) / kPageSize;
+
+  struct Segment {
+    bool isPassive = false;
+    Expression* offset = nullptr;
+    std::vector<char> data; // TODO: optimize
+    Segment() = default;
+    Segment(Expression* offset) : offset(offset) {}
+    Segment(Expression* offset, const char* init, Address size)
+      : offset(offset) {
+      data.resize(size);
+      std::copy_n(init, size, data.begin());
+    }
+    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) {
+      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;
+
+  // See comment in Table.
+  bool shared = false;
+  Type indexType = Type::i32;
+
+  Memory() { name = Name::fromInt(0); }
+  bool hasMax() { return max != kUnlimitedSize; }
+  bool is64() { return indexType == Type::i64; }
+  void clear() {
+    exists = false;
+    name = "";
+    initial = 0;
+    max = kMaxSize32;
+    segments.clear();
+    shared = false;
+    indexType = Type::i32;
+  }
+};
+
+class Global : public Importable {
+public:
+  Name name;
+  Type type;
+  Expression* init = nullptr;
+  bool mutable_ = false;
+};
+
+// Kinds of event attributes.
+enum WasmEventAttribute : unsigned { WASM_EVENT_ATTRIBUTE_EXCEPTION = 0x0 };
+
+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;
+};
+
+// "Opaque" data, not part of the core wasm spec, that is held in binaries.
+// May be parsed/handled by utility code elsewhere, but not in wasm.h
+class UserSection {
+public:
+  std::string name;
+  std::vector<char> data;
+};
+
+// The optional "dylink" section is used in dynamic linking.
+class DylinkSection {
+public:
+  Index memorySize, memoryAlignment, tableSize, tableAlignment;
+  std::vector<Name> neededDynlibs;
+};
+
+class Module {
+public:
+  // wasm contents (generally you shouldn't access these from outside, except
+  // maybe for iterating; use add*() and the get() functions)
+  std::vector<std::unique_ptr<Export>> exports;
+  std::vector<std::unique_ptr<Function>> functions;
+  std::vector<std::unique_ptr<Global>> globals;
+  std::vector<std::unique_ptr<Event>> events;
+
+  Table table;
+  Memory memory;
+  Name start;
+
+  std::vector<UserSection> userSections;
+
+  // Optional user section IR representation.
+  std::unique_ptr<DylinkSection> dylinkSection;
+
+  // Source maps debug info.
+  std::vector<std::string> debugInfoFileNames;
+
+  // `features` are the features allowed to be used in this module and should be
+  // respected regardless of the value of`hasFeaturesSection`.
+  // `hasFeaturesSection` means we read a features section and will emit one
+  // too.
+  FeatureSet features = FeatureSet::MVP;
+  bool hasFeaturesSection = false;
+
+  // Module name, if specified. Serves a documentary role only.
+  Name name;
+
+  MixedArena allocator;
+
+private:
+  // TODO: add a build option where Names are just indices, and then these
+  // methods are not needed
+  // exports map is by the *exported* name, which is unique
+  std::map<Name, Export*> exportsMap;
+  std::map<Name, Function*> functionsMap;
+  std::map<Name, Global*> globalsMap;
+  std::map<Name, Event*> eventsMap;
+
+public:
+  Module() = default;
+
+  Export* getExport(Name name);
+  Function* getFunction(Name name);
+  Global* getGlobal(Name name);
+  Event* getEvent(Name name);
+
+  Export* getExportOrNull(Name name);
+  Function* getFunctionOrNull(Name name);
+  Global* getGlobalOrNull(Name name);
+  Event* getEventOrNull(Name name);
+
+  Export* addExport(Export* curr);
+  Function* addFunction(Function* curr);
+  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);
+
+  void addStart(const Name& s);
+
+  void removeExport(Name name);
+  void removeFunction(Name name);
+  void removeGlobal(Name name);
+  void removeEvent(Name name);
+
+  void removeExports(std::function<bool(Export*)> pred);
+  void removeFunctions(std::function<bool(Function*)> pred);
+  void removeGlobals(std::function<bool(Global*)> pred);
+  void removeEvents(std::function<bool(Event*)> pred);
+
+  void updateMaps();
+
+  void clearDebugInfo();
+};
+
+} // namespace wasm
+
+namespace std {
+template<> struct hash<wasm::Address> {
+  size_t operator()(const wasm::Address a) const {
+    return std::hash<wasm::Address::address64_t>()(a.addr);
+  }
+};
+} // namespace std
+
+#endif // wasm_wasm_h
diff --git a/binaryen/src/wasm/CMakeLists.txt b/binaryen/src/wasm/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm/CMakeLists.txt
@@ -0,0 +1,17 @@
+file(GLOB wasm_HEADERS ../*.h)
+set(wasm_SOURCES
+  literal.cpp
+  wasm.cpp
+  wasm-binary.cpp
+  wasm-debug.cpp
+  wasm-emscripten.cpp
+  wasm-debug.cpp
+  wasm-interpreter.cpp
+  wasm-io.cpp
+  wasm-s-parser.cpp
+  wasm-stack.cpp
+  wasm-type.cpp
+  wasm-validator.cpp
+  ${wasm_HEADERS}
+)
+add_library(wasm OBJECT ${wasm_SOURCES})
diff --git a/binaryen/src/wasm/literal.cpp b/binaryen/src/wasm/literal.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm/literal.cpp
@@ -0,0 +1,2288 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "literal.h"
+
+#include <cassert>
+#include <cmath>
+
+#include "emscripten-optimizer/simple_ast.h"
+#include "ir/bits.h"
+#include "pretty_printing.h"
+#include "support/bits.h"
+#include "support/utilities.h"
+
+namespace wasm {
+
+template<int N> using LaneArray = std::array<Literal, N>;
+
+Literal::Literal(Type type) : type(type) {
+  if (type == Type::i31ref) {
+    // i31ref is special in that it is non-nullable, so we construct with zero
+    i32 = 0;
+  } else {
+    assert(type != Type::unreachable && (!type.isRef() || type.isNullable()));
+    if (type.isException()) {
+      new (&exn) std::unique_ptr<ExceptionPackage>();
+    } else {
+      memset(&v128, 0, 16);
+    }
+  }
+}
+
+Literal::Literal(const uint8_t init[16]) : type(Type::v128) {
+  memcpy(&v128, init, 16);
+}
+
+Literal::Literal(const Literal& other) : type(other.type) {
+  if (type.isException()) {
+    // Avoid calling the destructor on an uninitialized value
+    if (other.exn != nullptr) {
+      new (&exn) auto(std::make_unique<ExceptionPackage>(*other.exn));
+    } else {
+      new (&exn) std::unique_ptr<ExceptionPackage>();
+    }
+  } else if (type.isFunction()) {
+    func = other.func;
+  } else {
+    TODO_SINGLE_COMPOUND(type);
+    switch (type.getBasic()) {
+      case Type::i32:
+      case Type::f32:
+      case Type::i31ref:
+        i32 = other.i32;
+        break;
+      case Type::i64:
+      case Type::f64:
+        i64 = other.i64;
+        break;
+      case Type::v128:
+        memcpy(&v128, other.v128, 16);
+        break;
+      case Type::none:
+        break;
+      case Type::externref:
+      case Type::anyref:
+      case Type::eqref:
+        break; // null
+      case Type::funcref:
+      case Type::exnref:
+      case Type::unreachable:
+        WASM_UNREACHABLE("unexpected type");
+    }
+  }
+}
+
+Literal& Literal::operator=(const Literal& other) {
+  if (this != &other) {
+    this->~Literal();
+    new (this) auto(other);
+  }
+  return *this;
+}
+
+template<typename LaneT, int Lanes>
+static void extractBytes(uint8_t (&dest)[16], const LaneArray<Lanes>& lanes) {
+  std::array<uint8_t, 16> bytes;
+  const size_t lane_width = 16 / Lanes;
+  for (size_t lane_index = 0; lane_index < Lanes; ++lane_index) {
+    uint8_t bits[16];
+    lanes[lane_index].getBits(bits);
+    LaneT lane;
+    memcpy(&lane, bits, sizeof(lane));
+    for (size_t offset = 0; offset < lane_width; ++offset) {
+      bytes.at(lane_index * lane_width + offset) =
+        uint8_t(lane >> (8 * offset));
+    }
+  }
+  memcpy(&dest, bytes.data(), sizeof(bytes));
+}
+
+Literal::Literal(const LaneArray<16>& lanes) : type(Type::v128) {
+  extractBytes<uint8_t, 16>(v128, lanes);
+}
+
+Literal::Literal(const LaneArray<8>& lanes) : type(Type::v128) {
+  extractBytes<uint16_t, 8>(v128, lanes);
+}
+
+Literal::Literal(const LaneArray<4>& lanes) : type(Type::v128) {
+  extractBytes<uint32_t, 4>(v128, lanes);
+}
+
+Literal::Literal(const LaneArray<2>& lanes) : type(Type::v128) {
+  extractBytes<uint64_t, 2>(v128, lanes);
+}
+
+Literals Literal::makeZeros(Type type) {
+  assert(type.isConcrete());
+  Literals zeroes;
+  for (const auto& t : type) {
+    zeroes.push_back(makeZero(t));
+  }
+  return zeroes;
+}
+
+Literals Literal::makeOnes(Type type) {
+  assert(type.isConcrete());
+  Literals units;
+  for (const auto& t : type) {
+    units.push_back(makeOne(t));
+  }
+  return units;
+}
+
+Literals Literal::makeNegOnes(Type type) {
+  assert(type.isConcrete());
+  Literals units;
+  for (const auto& t : type) {
+    units.push_back(makeNegOne(t));
+  }
+  return units;
+}
+
+Literal Literal::makeZero(Type type) {
+  assert(type.isSingle());
+  if (type.isRef()) {
+    if (type == Type::i31ref) {
+      return makeI31(0);
+    } else {
+      return makeNull(type);
+    }
+  } else {
+    return makeFromInt32(0, type);
+  }
+}
+
+Literal Literal::makeOne(Type type) {
+  assert(type.isNumber());
+  return makeFromInt32(1, type);
+}
+
+Literal Literal::makeNegOne(Type type) {
+  assert(type.isNumber());
+  return makeFromInt32(-1, type);
+}
+
+std::array<uint8_t, 16> Literal::getv128() const {
+  assert(type == Type::v128);
+  std::array<uint8_t, 16> ret;
+  memcpy(ret.data(), v128, sizeof(ret));
+  return ret;
+}
+
+ExceptionPackage Literal::getExceptionPackage() const {
+  assert(type.isException() && exn != nullptr);
+  return *exn;
+}
+
+Literal Literal::castToF32() {
+  assert(type == Type::i32);
+  Literal ret(Type::f32);
+  ret.i32 = i32;
+  return ret;
+}
+
+Literal Literal::castToF64() {
+  assert(type == Type::i64);
+  Literal ret(Type::f64);
+  ret.i64 = i64;
+  return ret;
+}
+
+Literal Literal::castToI32() {
+  assert(type == Type::f32);
+  Literal ret(Type::i32);
+  ret.i32 = i32;
+  return ret;
+}
+
+Literal Literal::castToI64() {
+  assert(type == Type::f64);
+  Literal ret(Type::i64);
+  ret.i64 = i64;
+  return ret;
+}
+
+int64_t Literal::getInteger() const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return i32;
+    case Type::i64:
+      return i64;
+    default:
+      abort();
+  }
+}
+
+uint64_t Literal::getUnsigned() const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return static_cast<uint32_t>(i32);
+    case Type::i64:
+      return i64;
+    default:
+      abort();
+  }
+}
+
+double Literal::getFloat() const {
+  switch (type.getBasic()) {
+    case Type::f32:
+      return getf32();
+    case Type::f64:
+      return getf64();
+    default:
+      abort();
+  }
+}
+
+void Literal::getBits(uint8_t (&buf)[16]) const {
+  memset(buf, 0, 16);
+  switch (type.getBasic()) {
+    case Type::i32:
+    case Type::f32:
+      memcpy(buf, &i32, sizeof(i32));
+      break;
+    case Type::i64:
+    case Type::f64:
+      memcpy(buf, &i64, sizeof(i64));
+      break;
+    case Type::v128:
+      memcpy(buf, &v128, sizeof(v128));
+      break;
+    case Type::none:
+    case Type::unreachable:
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+      WASM_UNREACHABLE("invalid type");
+  }
+}
+
+bool Literal::operator==(const Literal& other) const {
+  if (type != other.type) {
+    return false;
+  }
+  auto compareRef = [&]() {
+    assert(type.isRef());
+    if (isNull() || other.isNull()) {
+      return isNull() == other.isNull();
+    }
+    if (type.isFunction()) {
+      assert(func.is() && other.func.is());
+      return func == other.func;
+    }
+    if (type.isException()) {
+      assert(exn != nullptr && other.exn != nullptr);
+      return *exn == *other.exn;
+    }
+    // other non-null reference type literals cannot represent concrete values,
+    // i.e. there is no concrete externref, anyref or eqref other than null.
+    WASM_UNREACHABLE("unexpected type");
+  };
+  if (type.isBasic()) {
+    switch (type.getBasic()) {
+      case Type::none:
+        return true; // special voided literal
+      case Type::i32:
+      case Type::f32:
+      case Type::i31ref:
+        return i32 == other.i32;
+      case Type::i64:
+      case Type::f64:
+        return i64 == other.i64;
+      case Type::v128:
+        return memcmp(v128, other.v128, 16) == 0;
+      case Type::funcref:
+      case Type::externref:
+      case Type::exnref:
+      case Type::anyref:
+      case Type::eqref:
+        return compareRef();
+      case Type::unreachable:
+        break;
+    }
+  } else if (type.isRef()) {
+    return compareRef();
+  } else if (type.isRtt()) {
+    WASM_UNREACHABLE("TODO: rtt literals");
+  }
+  WASM_UNREACHABLE("unexpected type");
+}
+
+bool Literal::operator!=(const Literal& other) const {
+  return !(*this == other);
+}
+
+bool Literal::isNaN() {
+  if (type == Type::f32 && std::isnan(getf32())) {
+    return true;
+  }
+  if (type == Type::f64 && std::isnan(getf64())) {
+    return true;
+  }
+  // TODO: SIMD?
+  return false;
+}
+
+uint32_t Literal::NaNPayload(float f) {
+  assert(std::isnan(f) && "expected a NaN");
+  // SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF
+  // NaN has all-one exponent and non-zero fraction.
+  return ~0xff800000u & bit_cast<uint32_t>(f);
+}
+
+uint64_t Literal::NaNPayload(double f) {
+  assert(std::isnan(f) && "expected a NaN");
+  // SEEEEEEE EEEEFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
+  // NaN has all-one exponent and non-zero fraction.
+  return ~0xfff0000000000000ull & bit_cast<uint64_t>(f);
+}
+
+float Literal::setQuietNaN(float f) {
+  assert(std::isnan(f) && "expected a NaN");
+  // An SNaN is a NaN with the most significant fraction bit clear.
+  return bit_cast<float>(0x00400000u | bit_cast<uint32_t>(f));
+}
+
+double Literal::setQuietNaN(double f) {
+  assert(std::isnan(f) && "expected a NaN");
+  // An SNaN is a NaN with the most significant fraction bit clear.
+  return bit_cast<double>(0x0008000000000000ull | bit_cast<uint64_t>(f));
+}
+
+void Literal::printFloat(std::ostream& o, float f) {
+  if (std::isnan(f)) {
+    const char* sign = std::signbit(f) ? "-" : "";
+    o << sign << "nan";
+    if (uint32_t payload = NaNPayload(f)) {
+      o << ":0x" << std::hex << payload << std::dec;
+    }
+    return;
+  }
+  printDouble(o, f);
+}
+
+void Literal::printDouble(std::ostream& o, double d) {
+  if (d == 0 && std::signbit(d)) {
+    o << "-0";
+    return;
+  }
+  if (std::isnan(d)) {
+    const char* sign = std::signbit(d) ? "-" : "";
+    o << sign << "nan";
+    if (uint64_t payload = NaNPayload(d)) {
+      o << ":0x" << std::hex << payload << std::dec;
+    }
+    return;
+  }
+  if (!std::isfinite(d)) {
+    o << (std::signbit(d) ? "-inf" : "inf");
+    return;
+  }
+  const char* text = cashew::JSPrinter::numToString(d);
+  // spec interpreter hates floats starting with '.'
+  if (text[0] == '.') {
+    o << '0';
+  } else if (text[0] == '-' && text[1] == '.') {
+    o << "-0";
+    text++;
+  }
+  o << text;
+}
+
+void Literal::printVec128(std::ostream& o, const std::array<uint8_t, 16>& v) {
+  o << std::hex;
+  for (auto i = 0; i < 16; i += 4) {
+    if (i) {
+      o << " ";
+    }
+    o << "0x" << std::setfill('0') << std::setw(8)
+      << uint32_t(v[i] | (v[i + 1] << 8) | (v[i + 2] << 16) | (v[i + 3] << 24));
+  }
+  o << std::dec;
+}
+
+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");
+  }
+  restoreNormalColor(o);
+  return o;
+}
+
+std::ostream& operator<<(std::ostream& o, wasm::Literals literals) {
+  if (literals.size() == 1) {
+    return o << literals[0];
+  } else {
+    o << '(';
+    if (literals.size() > 0) {
+      o << literals[0];
+    }
+    for (size_t i = 1; i < literals.size(); ++i) {
+      o << ", " << literals[i];
+    }
+    return o << ')';
+  }
+}
+
+std::ostream& operator<<(std::ostream& o, const ExceptionPackage& exn) {
+  return o << exn.event << " " << exn.values;
+}
+
+Literal Literal::countLeadingZeroes() const {
+  if (type == Type::i32) {
+    return Literal((int32_t)Bits::countLeadingZeroes(i32));
+  }
+  if (type == Type::i64) {
+    return Literal((int64_t)Bits::countLeadingZeroes(i64));
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::countTrailingZeroes() const {
+  if (type == Type::i32) {
+    return Literal((int32_t)Bits::countTrailingZeroes(i32));
+  }
+  if (type == Type::i64) {
+    return Literal((int64_t)Bits::countTrailingZeroes(i64));
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::popCount() const {
+  if (type == Type::i32) {
+    return Literal((int32_t)Bits::popCount(i32));
+  }
+  if (type == Type::i64) {
+    return Literal((int64_t)Bits::popCount(i64));
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::extendToSI64() const {
+  assert(type == Type::i32);
+  return Literal((int64_t)i32);
+}
+
+Literal Literal::extendToUI64() const {
+  assert(type == Type::i32);
+  return Literal((uint64_t)(uint32_t)i32);
+}
+
+Literal Literal::extendToF64() const {
+  assert(type == Type::f32);
+  return Literal(double(getf32()));
+}
+
+Literal Literal::extendS8() const {
+  if (type == Type::i32) {
+    return Literal(int32_t(int8_t(geti32() & 0xFF)));
+  }
+  if (type == Type::i64) {
+    return Literal(int64_t(int8_t(geti64() & 0xFF)));
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::extendS16() const {
+  if (type == Type::i32) {
+    return Literal(int32_t(int16_t(geti32() & 0xFFFF)));
+  }
+  if (type == Type::i64) {
+    return Literal(int64_t(int16_t(geti64() & 0xFFFF)));
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::extendS32() const {
+  if (type == Type::i64) {
+    return Literal(int64_t(int32_t(geti64() & 0xFFFFFFFF)));
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::wrapToI32() const {
+  assert(type == Type::i64);
+  return Literal((int32_t)i64);
+}
+
+Literal Literal::convertSIToF32() const {
+  if (type == Type::i32) {
+    return Literal(float(i32));
+  }
+  if (type == Type::i64) {
+    return Literal(float(i64));
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::convertUIToF32() const {
+  if (type == Type::i32) {
+    return Literal(float(uint32_t(i32)));
+  }
+  if (type == Type::i64) {
+    return Literal(float(uint64_t(i64)));
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::convertSIToF64() const {
+  if (type == Type::i32) {
+    return Literal(double(i32));
+  }
+  if (type == Type::i64) {
+    return Literal(double(i64));
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::convertUIToF64() const {
+  if (type == Type::i32) {
+    return Literal(double(uint32_t(i32)));
+  }
+  if (type == Type::i64) {
+    return Literal(double(uint64_t(i64)));
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+template<typename F> struct AsInt { using type = void; };
+template<> struct AsInt<float> { using type = int32_t; };
+template<> struct AsInt<double> { using type = int64_t; };
+
+template<typename F, typename I, bool (*RangeCheck)(typename AsInt<F>::type)>
+static Literal saturating_trunc(typename AsInt<F>::type val) {
+  if (std::isnan(bit_cast<F>(val))) {
+    return Literal(I(0));
+  }
+  if (!RangeCheck(val)) {
+    if (std::signbit(bit_cast<F>(val))) {
+      return Literal(std::numeric_limits<I>::min());
+    } else {
+      return Literal(std::numeric_limits<I>::max());
+    }
+  }
+  return Literal(I(std::trunc(bit_cast<F>(val))));
+}
+
+Literal Literal::truncSatToSI32() const {
+  if (type == Type::f32) {
+    return saturating_trunc<float, int32_t, isInRangeI32TruncS>(
+      Literal(*this).castToI32().geti32());
+  }
+  if (type == Type::f64) {
+    return saturating_trunc<double, int32_t, isInRangeI32TruncS>(
+      Literal(*this).castToI64().geti64());
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::truncSatToSI64() const {
+  if (type == Type::f32) {
+    return saturating_trunc<float, int64_t, isInRangeI64TruncS>(
+      Literal(*this).castToI32().geti32());
+  }
+  if (type == Type::f64) {
+    return saturating_trunc<double, int64_t, isInRangeI64TruncS>(
+      Literal(*this).castToI64().geti64());
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::truncSatToUI32() const {
+  if (type == Type::f32) {
+    return saturating_trunc<float, uint32_t, isInRangeI32TruncU>(
+      Literal(*this).castToI32().geti32());
+  }
+  if (type == Type::f64) {
+    return saturating_trunc<double, uint32_t, isInRangeI32TruncU>(
+      Literal(*this).castToI64().geti64());
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::truncSatToUI64() const {
+  if (type == Type::f32) {
+    return saturating_trunc<float, uint64_t, isInRangeI64TruncU>(
+      Literal(*this).castToI32().geti32());
+  }
+  if (type == Type::f64) {
+    return saturating_trunc<double, uint64_t, isInRangeI64TruncU>(
+      Literal(*this).castToI64().geti64());
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::eqz() const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return eq(Literal(int32_t(0)));
+    case Type::i64:
+      return eq(Literal(int64_t(0)));
+    case Type::f32:
+      return eq(Literal(float(0)));
+    case Type::f64:
+      return eq(Literal(double(0)));
+    case Type::v128:
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+    case Type::none:
+    case Type::unreachable:
+      WASM_UNREACHABLE("unexpected type");
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::neg() const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(-uint32_t(i32));
+    case Type::i64:
+      return Literal(-uint64_t(i64));
+    case Type::f32:
+      return Literal(i32 ^ 0x80000000).castToF32();
+    case Type::f64:
+      return Literal(int64_t(i64 ^ 0x8000000000000000ULL)).castToF64();
+    case Type::v128:
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+    case Type::none:
+    case Type::unreachable:
+      WASM_UNREACHABLE("unexpected type");
+  }
+  WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::abs() const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(std::abs(i32));
+    case Type::i64:
+      return Literal(std::abs(i64));
+    case Type::f32:
+      return Literal(i32 & 0x7fffffff).castToF32();
+    case Type::f64:
+      return Literal(int64_t(i64 & 0x7fffffffffffffffULL)).castToF64();
+    case Type::v128:
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+    case Type::none:
+    case Type::unreachable:
+      WASM_UNREACHABLE("unexpected type");
+  }
+  WASM_UNREACHABLE("unexpected type");
+}
+
+Literal Literal::ceil() const {
+  switch (type.getBasic()) {
+    case Type::f32:
+      return Literal(std::ceil(getf32()));
+    case Type::f64:
+      return Literal(std::ceil(getf64()));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::floor() const {
+  switch (type.getBasic()) {
+    case Type::f32:
+      return Literal(std::floor(getf32()));
+    case Type::f64:
+      return Literal(std::floor(getf64()));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::trunc() const {
+  switch (type.getBasic()) {
+    case Type::f32:
+      return Literal(std::trunc(getf32()));
+    case Type::f64:
+      return Literal(std::trunc(getf64()));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::nearbyint() const {
+  switch (type.getBasic()) {
+    case Type::f32:
+      return Literal(std::nearbyint(getf32()));
+    case Type::f64:
+      return Literal(std::nearbyint(getf64()));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::sqrt() const {
+  switch (type.getBasic()) {
+    case Type::f32:
+      return Literal(std::sqrt(getf32()));
+    case Type::f64:
+      return Literal(std::sqrt(getf64()));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::demote() const {
+  auto f64 = getf64();
+  if (std::isnan(f64)) {
+    return Literal(float(f64));
+  }
+  if (std::isinf(f64)) {
+    return Literal(float(f64));
+  }
+  // when close to the limit, but still truncatable to a valid value, do that
+  // see
+  // https://github.com/WebAssembly/sexpr-wasm-prototype/blob/2d375e8d502327e814d62a08f22da9d9b6b675dc/src/wasm-interpreter.c#L247
+  uint64_t bits = reinterpreti64();
+  if (bits > 0x47efffffe0000000ULL && bits < 0x47effffff0000000ULL) {
+    return Literal(std::numeric_limits<float>::max());
+  }
+  if (bits > 0xc7efffffe0000000ULL && bits < 0xc7effffff0000000ULL) {
+    return Literal(-std::numeric_limits<float>::max());
+  }
+  // when we must convert to infinity, do that
+  if (f64 < -std::numeric_limits<float>::max()) {
+    return Literal(-std::numeric_limits<float>::infinity());
+  }
+  if (f64 > std::numeric_limits<float>::max()) {
+    return Literal(std::numeric_limits<float>::infinity());
+  }
+  return Literal(float(getf64()));
+}
+
+Literal Literal::add(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(uint32_t(i32) + uint32_t(other.i32));
+    case Type::i64:
+      return Literal(uint64_t(i64) + uint64_t(other.i64));
+    case Type::f32:
+      return Literal(getf32() + other.getf32());
+    case Type::f64:
+      return Literal(getf64() + other.getf64());
+    case Type::v128:
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+    case Type::none:
+    case Type::unreachable:
+      WASM_UNREACHABLE("unexpected type");
+  }
+  WASM_UNREACHABLE("unexpected type");
+}
+
+Literal Literal::sub(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(uint32_t(i32) - uint32_t(other.i32));
+    case Type::i64:
+      return Literal(uint64_t(i64) - uint64_t(other.i64));
+    case Type::f32:
+      return Literal(getf32() - other.getf32());
+    case Type::f64:
+      return Literal(getf64() - other.getf64());
+    case Type::v128:
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+    case Type::none:
+    case Type::unreachable:
+      WASM_UNREACHABLE("unexpected type");
+  }
+  WASM_UNREACHABLE("unexpected type");
+}
+
+template<typename T> static T add_sat_s(T a, T b) {
+  static_assert(std::is_signed<T>::value,
+                "Trying to instantiate add_sat_s with unsigned type");
+  using UT = typename std::make_unsigned<T>::type;
+  UT ua = static_cast<UT>(a);
+  UT ub = static_cast<UT>(b);
+  UT ures = ua + ub;
+  // overflow if sign of result is different from sign of a and b
+  if (static_cast<T>((ures ^ ua) & (ures ^ ub)) < 0) {
+    return (a < 0) ? std::numeric_limits<T>::min()
+                   : std::numeric_limits<T>::max();
+  }
+  return static_cast<T>(ures);
+}
+
+template<typename T> static T sub_sat_s(T a, T b) {
+  static_assert(std::is_signed<T>::value,
+                "Trying to instantiate sub_sat_s with unsigned type");
+  using UT = typename std::make_unsigned<T>::type;
+  UT ua = static_cast<UT>(a);
+  UT ub = static_cast<UT>(b);
+  UT ures = ua - ub;
+  // overflow if a and b have different signs and result and a differ in sign
+  if (static_cast<T>((ua ^ ub) & (ures ^ ua)) < 0) {
+    return (a < 0) ? std::numeric_limits<T>::min()
+                   : std::numeric_limits<T>::max();
+  }
+  return static_cast<T>(ures);
+}
+
+template<typename T> static T add_sat_u(T a, T b) {
+  static_assert(std::is_unsigned<T>::value,
+                "Trying to instantiate add_sat_u with signed type");
+  T res = a + b;
+  // overflow if result is less than arguments
+  return (res < a) ? std::numeric_limits<T>::max() : res;
+}
+
+template<typename T> static T sub_sat_u(T a, T b) {
+  static_assert(std::is_unsigned<T>::value,
+                "Trying to instantiate sub_sat_u with signed type");
+  T res = a - b;
+  // overflow if result is greater than a
+  return (res > a) ? 0 : res;
+}
+
+Literal Literal::addSatSI8(const Literal& other) const {
+  return Literal(add_sat_s<int8_t>(geti32(), other.geti32()));
+}
+Literal Literal::addSatUI8(const Literal& other) const {
+  return Literal(add_sat_u<uint8_t>(geti32(), other.geti32()));
+}
+Literal Literal::addSatSI16(const Literal& other) const {
+  return Literal(add_sat_s<int16_t>(geti32(), other.geti32()));
+}
+Literal Literal::addSatUI16(const Literal& other) const {
+  return Literal(add_sat_u<uint16_t>(geti32(), other.geti32()));
+}
+Literal Literal::subSatSI8(const Literal& other) const {
+  return Literal(sub_sat_s<int8_t>(geti32(), other.geti32()));
+}
+Literal Literal::subSatUI8(const Literal& other) const {
+  return Literal(sub_sat_u<uint8_t>(geti32(), other.geti32()));
+}
+Literal Literal::subSatSI16(const Literal& other) const {
+  return Literal(sub_sat_s<int16_t>(geti32(), other.geti32()));
+}
+Literal Literal::subSatUI16(const Literal& other) const {
+  return Literal(sub_sat_u<uint16_t>(geti32(), other.geti32()));
+}
+
+Literal Literal::mul(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(uint32_t(i32) * uint32_t(other.i32));
+    case Type::i64:
+      return Literal(uint64_t(i64) * uint64_t(other.i64));
+    case Type::f32:
+      return Literal(getf32() * other.getf32());
+    case Type::f64:
+      return Literal(getf64() * other.getf64());
+    case Type::v128:
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+    case Type::none:
+    case Type::unreachable:
+      WASM_UNREACHABLE("unexpected type");
+  }
+  WASM_UNREACHABLE("unexpected type");
+}
+
+Literal Literal::div(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::f32: {
+      float lhs = getf32(), rhs = other.getf32();
+      float sign = std::signbit(lhs) == std::signbit(rhs) ? 0.f : -0.f;
+      switch (std::fpclassify(rhs)) {
+        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));
+            case FP_NORMAL:    // fallthrough
+            case FP_SUBNORMAL: // fallthrough
+            case FP_INFINITE:
+              return Literal(
+                std::copysign(std::numeric_limits<float>::infinity(), sign));
+            default:
+              WASM_UNREACHABLE("invalid fp classification");
+          }
+        case FP_NAN:      // fallthrough
+        case FP_INFINITE: // fallthrough
+        case FP_NORMAL:   // fallthrough
+        case FP_SUBNORMAL:
+          return Literal(lhs / rhs);
+        default:
+          WASM_UNREACHABLE("invalid fp classification");
+      }
+    }
+    case Type::f64: {
+      double lhs = getf64(), rhs = other.getf64();
+      double sign = std::signbit(lhs) == std::signbit(rhs) ? 0. : -0.;
+      switch (std::fpclassify(rhs)) {
+        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));
+            case FP_NORMAL:    // fallthrough
+            case FP_SUBNORMAL: // fallthrough
+            case FP_INFINITE:
+              return Literal(
+                std::copysign(std::numeric_limits<double>::infinity(), sign));
+            default:
+              WASM_UNREACHABLE("invalid fp classification");
+          }
+        case FP_NAN:      // fallthrough
+        case FP_INFINITE: // fallthrough
+        case FP_NORMAL:   // fallthrough
+        case FP_SUBNORMAL:
+          return Literal(lhs / rhs);
+        default:
+          WASM_UNREACHABLE("invalid fp classification");
+      }
+    }
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::divS(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(i32 / other.i32);
+    case Type::i64:
+      return Literal(i64 / other.i64);
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::divU(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(uint32_t(i32) / uint32_t(other.i32));
+    case Type::i64:
+      return Literal(uint64_t(i64) / uint64_t(other.i64));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::remS(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(i32 % other.i32);
+    case Type::i64:
+      return Literal(i64 % other.i64);
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::remU(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(uint32_t(i32) % uint32_t(other.i32));
+    case Type::i64:
+      return Literal(uint64_t(i64) % uint64_t(other.i64));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::minInt(const Literal& other) const {
+  return geti32() < other.geti32() ? *this : other;
+}
+Literal Literal::maxInt(const Literal& other) const {
+  return geti32() > other.geti32() ? *this : other;
+}
+Literal Literal::minUInt(const Literal& other) const {
+  return uint32_t(geti32()) < uint32_t(other.geti32()) ? *this : other;
+}
+Literal Literal::maxUInt(const Literal& other) const {
+  return uint32_t(geti32()) > uint32_t(other.geti32()) ? *this : other;
+}
+
+Literal Literal::avgrUInt(const Literal& other) const {
+  return Literal((geti32() + other.geti32() + 1) / 2);
+}
+
+Literal Literal::and_(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(i32 & other.i32);
+    case Type::i64:
+      return Literal(i64 & other.i64);
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::or_(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(i32 | other.i32);
+    case Type::i64:
+      return Literal(i64 | other.i64);
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::xor_(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(i32 ^ other.i32);
+    case Type::i64:
+      return Literal(i64 ^ other.i64);
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::shl(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(uint32_t(i32)
+                     << Bits::getEffectiveShifts(other.i32, Type::i32));
+    case Type::i64:
+      return Literal(uint64_t(i64)
+                     << Bits::getEffectiveShifts(other.i64, Type::i64));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::shrS(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(i32 >> Bits::getEffectiveShifts(other.i32, Type::i32));
+    case Type::i64:
+      return Literal(i64 >> Bits::getEffectiveShifts(other.i64, Type::i64));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::shrU(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(uint32_t(i32) >>
+                     Bits::getEffectiveShifts(other.i32, Type::i32));
+    case Type::i64:
+      return Literal(uint64_t(i64) >>
+                     Bits::getEffectiveShifts(other.i64, Type::i64));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::rotL(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(Bits::rotateLeft(uint32_t(i32), uint32_t(other.i32)));
+    case Type::i64:
+      return Literal(Bits::rotateLeft(uint64_t(i64), uint64_t(other.i64)));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::rotR(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(Bits::rotateRight(uint32_t(i32), uint32_t(other.i32)));
+    case Type::i64:
+      return Literal(Bits::rotateRight(uint64_t(i64), uint64_t(other.i64)));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::eq(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(i32 == other.i32);
+    case Type::i64:
+      return Literal(i64 == other.i64);
+    case Type::f32:
+      return Literal(getf32() == other.getf32());
+    case Type::f64:
+      return Literal(getf64() == other.getf64());
+    case Type::v128:
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+    case Type::none:
+    case Type::unreachable:
+      WASM_UNREACHABLE("unexpected type");
+  }
+  WASM_UNREACHABLE("unexpected type");
+}
+
+Literal Literal::ne(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(i32 != other.i32);
+    case Type::i64:
+      return Literal(i64 != other.i64);
+    case Type::f32:
+      return Literal(getf32() != other.getf32());
+    case Type::f64:
+      return Literal(getf64() != other.getf64());
+    case Type::v128:
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+    case Type::none:
+    case Type::unreachable:
+      WASM_UNREACHABLE("unexpected type");
+  }
+  WASM_UNREACHABLE("unexpected type");
+}
+
+Literal Literal::ltS(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(i32 < other.i32);
+    case Type::i64:
+      return Literal(i64 < other.i64);
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::ltU(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(uint32_t(i32) < uint32_t(other.i32));
+    case Type::i64:
+      return Literal(uint64_t(i64) < uint64_t(other.i64));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::lt(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::f32:
+      return Literal(getf32() < other.getf32());
+    case Type::f64:
+      return Literal(getf64() < other.getf64());
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::leS(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(i32 <= other.i32);
+    case Type::i64:
+      return Literal(i64 <= other.i64);
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::leU(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(uint32_t(i32) <= uint32_t(other.i32));
+    case Type::i64:
+      return Literal(uint64_t(i64) <= uint64_t(other.i64));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::le(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::f32:
+      return Literal(getf32() <= other.getf32());
+    case Type::f64:
+      return Literal(getf64() <= other.getf64());
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::gtS(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(i32 > other.i32);
+    case Type::i64:
+      return Literal(i64 > other.i64);
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::gtU(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(uint32_t(i32) > uint32_t(other.i32));
+    case Type::i64:
+      return Literal(uint64_t(i64) > uint64_t(other.i64));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::gt(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::f32:
+      return Literal(getf32() > other.getf32());
+    case Type::f64:
+      return Literal(getf64() > other.getf64());
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::geS(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(i32 >= other.i32);
+    case Type::i64:
+      return Literal(i64 >= other.i64);
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::geU(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::i32:
+      return Literal(uint32_t(i32) >= uint32_t(other.i32));
+    case Type::i64:
+      return Literal(uint64_t(i64) >= uint64_t(other.i64));
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::ge(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::f32:
+      return Literal(getf32() >= other.getf32());
+    case Type::f64:
+      return Literal(getf64() >= other.getf64());
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::min(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::f32: {
+      auto l = getf32(), r = other.getf32();
+      if (l == r && l == 0) {
+        return Literal(std::signbit(l) ? l : r);
+      }
+      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 (!lnan && !rnan) {
+        return Literal((int32_t)0x7fc00000).castToF32();
+      }
+      return Literal(lnan ? l : r)
+        .castToI32()
+        .or_(Literal(0xc00000))
+        .castToF32();
+    }
+    case Type::f64: {
+      auto l = getf64(), r = other.getf64();
+      if (l == r && l == 0) {
+        return Literal(std::signbit(l) ? l : r);
+      }
+      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 (!lnan && !rnan) {
+        return Literal((int64_t)0x7ff8000000000000LL).castToF64();
+      }
+      return Literal(lnan ? l : r)
+        .castToI64()
+        .or_(Literal(int64_t(0x8000000000000LL)))
+        .castToF64();
+    }
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::max(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::f32: {
+      auto l = getf32(), r = other.getf32();
+      if (l == r && l == 0) {
+        return Literal(std::signbit(l) ? r : 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 (!lnan && !rnan) {
+        return Literal((int32_t)0x7fc00000).castToF32();
+      }
+      return Literal(lnan ? l : r)
+        .castToI32()
+        .or_(Literal(0xc00000))
+        .castToF32();
+    }
+    case Type::f64: {
+      auto l = getf64(), r = other.getf64();
+      if (l == r && l == 0) {
+        return Literal(std::signbit(l) ? r : 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 (!lnan && !rnan) {
+        return Literal((int64_t)0x7ff8000000000000LL).castToF64();
+      }
+      return Literal(lnan ? l : r)
+        .castToI64()
+        .or_(Literal(int64_t(0x8000000000000LL)))
+        .castToF64();
+    }
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::pmin(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::f32:
+    case Type::f64:
+      return other.lt(*this).geti32() ? other : *this;
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::pmax(const Literal& other) const {
+  switch (type.getBasic()) {
+    case Type::f32:
+    case Type::f64:
+      return this->lt(other).geti32() ? other : *this;
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+Literal Literal::copysign(const Literal& other) const {
+  // operate on bits directly, to avoid signalling bit being set on a float
+  switch (type.getBasic()) {
+    case Type::f32:
+      return Literal((i32 & 0x7fffffff) | (other.i32 & 0x80000000)).castToF32();
+      break;
+    case Type::f64:
+      return Literal((i64 & 0x7fffffffffffffffUL) |
+                     (other.i64 & 0x8000000000000000UL))
+        .castToF64();
+      break;
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+template<typename LaneT, int Lanes>
+static LaneArray<Lanes> getLanes(const Literal& val) {
+  assert(val.type == Type::v128);
+  const size_t lane_width = 16 / Lanes;
+  std::array<uint8_t, 16> bytes = val.getv128();
+  LaneArray<Lanes> lanes;
+  for (size_t lane_index = 0; lane_index < Lanes; ++lane_index) {
+    LaneT lane(0);
+    for (size_t offset = 0; offset < lane_width; ++offset) {
+      lane |= LaneT(bytes.at(lane_index * lane_width + offset))
+              << LaneT(8 * offset);
+    }
+    lanes.at(lane_index) = Literal(lane);
+  }
+  return lanes;
+}
+
+LaneArray<16> Literal::getLanesSI8x16() const {
+  return getLanes<int8_t, 16>(*this);
+}
+LaneArray<16> Literal::getLanesUI8x16() const {
+  return getLanes<uint8_t, 16>(*this);
+}
+LaneArray<8> Literal::getLanesSI16x8() const {
+  return getLanes<int16_t, 8>(*this);
+}
+LaneArray<8> Literal::getLanesUI16x8() const {
+  return getLanes<uint16_t, 8>(*this);
+}
+LaneArray<4> Literal::getLanesI32x4() const {
+  return getLanes<int32_t, 4>(*this);
+}
+LaneArray<2> Literal::getLanesI64x2() const {
+  return getLanes<int64_t, 2>(*this);
+}
+LaneArray<4> Literal::getLanesF32x4() const {
+  auto lanes = getLanesI32x4();
+  for (size_t i = 0; i < lanes.size(); ++i) {
+    lanes[i] = lanes[i].castToF32();
+  }
+  return lanes;
+}
+LaneArray<2> Literal::getLanesF64x2() const {
+  auto lanes = getLanesI64x2();
+  for (size_t i = 0; i < lanes.size(); ++i) {
+    lanes[i] = lanes[i].castToF64();
+  }
+  return lanes;
+}
+
+Literal Literal::shuffleV8x16(const Literal& other,
+                              const std::array<uint8_t, 16>& mask) const {
+  assert(type == Type::v128);
+  uint8_t bytes[16];
+  for (size_t i = 0; i < mask.size(); ++i) {
+    bytes[i] = (mask[i] < 16) ? v128[mask[i]] : other.v128[mask[i] - 16];
+  }
+  return Literal(bytes);
+}
+
+template<Type::BasicID Ty, int Lanes> static Literal splat(const Literal& val) {
+  assert(val.type == Ty);
+  LaneArray<Lanes> lanes;
+  lanes.fill(val);
+  return Literal(lanes);
+}
+
+Literal Literal::splatI8x16() const { return splat<Type::i32, 16>(*this); }
+Literal Literal::splatI16x8() const { return splat<Type::i32, 8>(*this); }
+Literal Literal::splatI32x4() const { return splat<Type::i32, 4>(*this); }
+Literal Literal::splatI64x2() const { return splat<Type::i64, 2>(*this); }
+Literal Literal::splatF32x4() const { return splat<Type::f32, 4>(*this); }
+Literal Literal::splatF64x2() const { return splat<Type::f64, 2>(*this); }
+
+Literal Literal::extractLaneSI8x16(uint8_t index) const {
+  return getLanesSI8x16().at(index);
+}
+Literal Literal::extractLaneUI8x16(uint8_t index) const {
+  return getLanesUI8x16().at(index);
+}
+Literal Literal::extractLaneSI16x8(uint8_t index) const {
+  return getLanesSI16x8().at(index);
+}
+Literal Literal::extractLaneUI16x8(uint8_t index) const {
+  return getLanesUI16x8().at(index);
+}
+Literal Literal::extractLaneI32x4(uint8_t index) const {
+  return getLanesI32x4().at(index);
+}
+Literal Literal::extractLaneI64x2(uint8_t index) const {
+  return getLanesI64x2().at(index);
+}
+Literal Literal::extractLaneF32x4(uint8_t index) const {
+  return getLanesF32x4().at(index);
+}
+Literal Literal::extractLaneF64x2(uint8_t index) const {
+  return getLanesF64x2().at(index);
+}
+
+template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const>
+static Literal
+replace(const Literal& val, const Literal& other, uint8_t index) {
+  LaneArray<Lanes> lanes = (val.*IntoLanes)();
+  lanes.at(index) = other;
+  auto ret = Literal(lanes);
+  return ret;
+}
+
+Literal Literal::replaceLaneI8x16(const Literal& other, uint8_t index) const {
+  return replace<16, &Literal::getLanesUI8x16>(*this, other, index);
+}
+Literal Literal::replaceLaneI16x8(const Literal& other, uint8_t index) const {
+  return replace<8, &Literal::getLanesUI16x8>(*this, other, index);
+}
+Literal Literal::replaceLaneI32x4(const Literal& other, uint8_t index) const {
+  return replace<4, &Literal::getLanesI32x4>(*this, other, index);
+}
+Literal Literal::replaceLaneI64x2(const Literal& other, uint8_t index) const {
+  return replace<2, &Literal::getLanesI64x2>(*this, other, index);
+}
+Literal Literal::replaceLaneF32x4(const Literal& other, uint8_t index) const {
+  return replace<4, &Literal::getLanesF32x4>(*this, other, index);
+}
+Literal Literal::replaceLaneF64x2(const Literal& other, uint8_t index) const {
+  return replace<2, &Literal::getLanesF64x2>(*this, other, index);
+}
+
+template<int Lanes,
+         LaneArray<Lanes> (Literal::*IntoLanes)() const,
+         Literal (Literal::*UnaryOp)(void) const>
+static Literal unary(const Literal& val) {
+  LaneArray<Lanes> lanes = (val.*IntoLanes)();
+  for (size_t i = 0; i < Lanes; ++i) {
+    lanes[i] = (lanes[i].*UnaryOp)();
+  }
+  return Literal(lanes);
+}
+
+Literal Literal::notV128() const {
+  std::array<uint8_t, 16> ones;
+  ones.fill(0xff);
+  return xorV128(Literal(ones.data()));
+}
+Literal Literal::absI8x16() const {
+  return unary<16, &Literal::getLanesSI8x16, &Literal::abs>(*this);
+}
+Literal Literal::absI16x8() const {
+  return unary<8, &Literal::getLanesSI16x8, &Literal::abs>(*this);
+}
+Literal Literal::absI32x4() const {
+  return unary<4, &Literal::getLanesI32x4, &Literal::abs>(*this);
+}
+Literal Literal::negI8x16() const {
+  return unary<16, &Literal::getLanesUI8x16, &Literal::neg>(*this);
+}
+Literal Literal::negI16x8() const {
+  return unary<8, &Literal::getLanesUI16x8, &Literal::neg>(*this);
+}
+Literal Literal::negI32x4() const {
+  return unary<4, &Literal::getLanesI32x4, &Literal::neg>(*this);
+}
+Literal Literal::negI64x2() const {
+  return unary<2, &Literal::getLanesI64x2, &Literal::neg>(*this);
+}
+Literal Literal::absF32x4() const {
+  return unary<4, &Literal::getLanesF32x4, &Literal::abs>(*this);
+}
+Literal Literal::negF32x4() const {
+  return unary<4, &Literal::getLanesF32x4, &Literal::neg>(*this);
+}
+Literal Literal::sqrtF32x4() const {
+  return unary<4, &Literal::getLanesF32x4, &Literal::sqrt>(*this);
+}
+Literal Literal::ceilF32x4() const {
+  return unary<4, &Literal::getLanesF32x4, &Literal::ceil>(*this);
+}
+Literal Literal::floorF32x4() const {
+  return unary<4, &Literal::getLanesF32x4, &Literal::floor>(*this);
+}
+Literal Literal::truncF32x4() const {
+  return unary<4, &Literal::getLanesF32x4, &Literal::trunc>(*this);
+}
+Literal Literal::nearestF32x4() const {
+  return unary<4, &Literal::getLanesF32x4, &Literal::nearbyint>(*this);
+}
+Literal Literal::absF64x2() const {
+  return unary<2, &Literal::getLanesF64x2, &Literal::abs>(*this);
+}
+Literal Literal::negF64x2() const {
+  return unary<2, &Literal::getLanesF64x2, &Literal::neg>(*this);
+}
+Literal Literal::sqrtF64x2() const {
+  return unary<2, &Literal::getLanesF64x2, &Literal::sqrt>(*this);
+}
+Literal Literal::ceilF64x2() const {
+  return unary<2, &Literal::getLanesF64x2, &Literal::ceil>(*this);
+}
+Literal Literal::floorF64x2() const {
+  return unary<2, &Literal::getLanesF64x2, &Literal::floor>(*this);
+}
+Literal Literal::truncF64x2() const {
+  return unary<2, &Literal::getLanesF64x2, &Literal::trunc>(*this);
+}
+Literal Literal::nearestF64x2() const {
+  return unary<2, &Literal::getLanesF64x2, &Literal::nearbyint>(*this);
+}
+Literal Literal::truncSatToSI32x4() const {
+  return unary<4, &Literal::getLanesF32x4, &Literal::truncSatToSI32>(*this);
+}
+Literal Literal::truncSatToUI32x4() const {
+  return unary<4, &Literal::getLanesF32x4, &Literal::truncSatToUI32>(*this);
+}
+Literal Literal::truncSatToSI64x2() const {
+  return unary<2, &Literal::getLanesF64x2, &Literal::truncSatToSI64>(*this);
+}
+Literal Literal::truncSatToUI64x2() const {
+  return unary<2, &Literal::getLanesF64x2, &Literal::truncSatToUI64>(*this);
+}
+Literal Literal::convertSToF32x4() const {
+  return unary<4, &Literal::getLanesI32x4, &Literal::convertSIToF32>(*this);
+}
+Literal Literal::convertUToF32x4() const {
+  return unary<4, &Literal::getLanesI32x4, &Literal::convertUIToF32>(*this);
+}
+Literal Literal::convertSToF64x2() const {
+  return unary<2, &Literal::getLanesI64x2, &Literal::convertSIToF64>(*this);
+}
+Literal Literal::convertUToF64x2() const {
+  return unary<2, &Literal::getLanesI64x2, &Literal::convertUIToF64>(*this);
+}
+
+template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const>
+static Literal any_true(const Literal& val) {
+  LaneArray<Lanes> lanes = (val.*IntoLanes)();
+  for (size_t i = 0; i < Lanes; ++i) {
+    if (lanes[i] != Literal::makeZero(lanes[i].type)) {
+      return Literal(int32_t(1));
+    }
+  }
+  return Literal(int32_t(0));
+}
+
+template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const>
+static Literal all_true(const Literal& val) {
+  LaneArray<Lanes> lanes = (val.*IntoLanes)();
+  for (size_t i = 0; i < Lanes; ++i) {
+    if (lanes[i] == Literal::makeZero(lanes[i].type)) {
+      return Literal(int32_t(0));
+    }
+  }
+  return Literal(int32_t(1));
+}
+
+template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const>
+static Literal bitmask(const Literal& val) {
+  uint32_t result = 0;
+  LaneArray<Lanes> lanes = (val.*IntoLanes)();
+  for (size_t i = 0; i < Lanes; ++i) {
+    if (lanes[i].geti32() & (1 << 31)) {
+      result = result | (1 << i);
+    }
+  }
+  return Literal(result);
+}
+
+Literal Literal::anyTrueI8x16() const {
+  return any_true<16, &Literal::getLanesUI8x16>(*this);
+}
+Literal Literal::allTrueI8x16() const {
+  return all_true<16, &Literal::getLanesUI8x16>(*this);
+}
+Literal Literal::bitmaskI8x16() const {
+  return bitmask<16, &Literal::getLanesSI8x16>(*this);
+}
+Literal Literal::anyTrueI16x8() const {
+  return any_true<8, &Literal::getLanesUI16x8>(*this);
+}
+Literal Literal::allTrueI16x8() const {
+  return all_true<8, &Literal::getLanesUI16x8>(*this);
+}
+Literal Literal::bitmaskI16x8() const {
+  return bitmask<8, &Literal::getLanesSI16x8>(*this);
+}
+Literal Literal::anyTrueI32x4() const {
+  return any_true<4, &Literal::getLanesI32x4>(*this);
+}
+Literal Literal::allTrueI32x4() const {
+  return all_true<4, &Literal::getLanesI32x4>(*this);
+}
+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,
+         Literal (Literal::*ShiftOp)(const Literal&) const>
+static Literal shift(const Literal& vec, const Literal& shift) {
+  assert(shift.type == Type::i32);
+  size_t lane_bits = 128 / Lanes;
+  LaneArray<Lanes> lanes = (vec.*IntoLanes)();
+  for (size_t i = 0; i < Lanes; ++i) {
+    lanes[i] =
+      (lanes[i].*ShiftOp)(Literal(int32_t(shift.geti32() % lane_bits)));
+  }
+  return Literal(lanes);
+}
+
+Literal Literal::shlI8x16(const Literal& other) const {
+  return shift<16, &Literal::getLanesUI8x16, &Literal::shl>(*this, other);
+}
+Literal Literal::shrSI8x16(const Literal& other) const {
+  return shift<16, &Literal::getLanesSI8x16, &Literal::shrS>(*this, other);
+}
+Literal Literal::shrUI8x16(const Literal& other) const {
+  return shift<16, &Literal::getLanesUI8x16, &Literal::shrU>(*this, other);
+}
+Literal Literal::shlI16x8(const Literal& other) const {
+  return shift<8, &Literal::getLanesUI16x8, &Literal::shl>(*this, other);
+}
+Literal Literal::shrSI16x8(const Literal& other) const {
+  return shift<8, &Literal::getLanesSI16x8, &Literal::shrS>(*this, other);
+}
+Literal Literal::shrUI16x8(const Literal& other) const {
+  return shift<8, &Literal::getLanesUI16x8, &Literal::shrU>(*this, other);
+}
+Literal Literal::shlI32x4(const Literal& other) const {
+  return shift<4, &Literal::getLanesI32x4, &Literal::shl>(*this, other);
+}
+Literal Literal::shrSI32x4(const Literal& other) const {
+  return shift<4, &Literal::getLanesI32x4, &Literal::shrS>(*this, other);
+}
+Literal Literal::shrUI32x4(const Literal& other) const {
+  return shift<4, &Literal::getLanesI32x4, &Literal::shrU>(*this, other);
+}
+Literal Literal::shlI64x2(const Literal& other) const {
+  return shift<2, &Literal::getLanesI64x2, &Literal::shl>(*this, other);
+}
+Literal Literal::shrSI64x2(const Literal& other) const {
+  return shift<2, &Literal::getLanesI64x2, &Literal::shrS>(*this, other);
+}
+Literal Literal::shrUI64x2(const Literal& other) const {
+  return shift<2, &Literal::getLanesI64x2, &Literal::shrU>(*this, other);
+}
+
+template<int Lanes,
+         LaneArray<Lanes> (Literal::*IntoLanes)() const,
+         Literal (Literal::*CompareOp)(const Literal&) const,
+         typename LaneT = int32_t>
+static Literal compare(const Literal& val, const Literal& other) {
+  LaneArray<Lanes> lanes = (val.*IntoLanes)();
+  LaneArray<Lanes> other_lanes = (other.*IntoLanes)();
+  for (size_t i = 0; i < Lanes; ++i) {
+    lanes[i] = (lanes[i].*CompareOp)(other_lanes[i]) == Literal(int32_t(1))
+                 ? Literal(LaneT(-1))
+                 : Literal(LaneT(0));
+  }
+  return Literal(lanes);
+}
+
+Literal Literal::eqI8x16(const Literal& other) const {
+  return compare<16, &Literal::getLanesUI8x16, &Literal::eq>(*this, other);
+}
+Literal Literal::neI8x16(const Literal& other) const {
+  return compare<16, &Literal::getLanesUI8x16, &Literal::ne>(*this, other);
+}
+Literal Literal::ltSI8x16(const Literal& other) const {
+  return compare<16, &Literal::getLanesSI8x16, &Literal::ltS>(*this, other);
+}
+Literal Literal::ltUI8x16(const Literal& other) const {
+  return compare<16, &Literal::getLanesUI8x16, &Literal::ltU>(*this, other);
+}
+Literal Literal::gtSI8x16(const Literal& other) const {
+  return compare<16, &Literal::getLanesSI8x16, &Literal::gtS>(*this, other);
+}
+Literal Literal::gtUI8x16(const Literal& other) const {
+  return compare<16, &Literal::getLanesUI8x16, &Literal::gtU>(*this, other);
+}
+Literal Literal::leSI8x16(const Literal& other) const {
+  return compare<16, &Literal::getLanesSI8x16, &Literal::leS>(*this, other);
+}
+Literal Literal::leUI8x16(const Literal& other) const {
+  return compare<16, &Literal::getLanesUI8x16, &Literal::leU>(*this, other);
+}
+Literal Literal::geSI8x16(const Literal& other) const {
+  return compare<16, &Literal::getLanesSI8x16, &Literal::geS>(*this, other);
+}
+Literal Literal::geUI8x16(const Literal& other) const {
+  return compare<16, &Literal::getLanesUI8x16, &Literal::geU>(*this, other);
+}
+Literal Literal::eqI16x8(const Literal& other) const {
+  return compare<8, &Literal::getLanesUI16x8, &Literal::eq>(*this, other);
+}
+Literal Literal::neI16x8(const Literal& other) const {
+  return compare<8, &Literal::getLanesUI16x8, &Literal::ne>(*this, other);
+}
+Literal Literal::ltSI16x8(const Literal& other) const {
+  return compare<8, &Literal::getLanesSI16x8, &Literal::ltS>(*this, other);
+}
+Literal Literal::ltUI16x8(const Literal& other) const {
+  return compare<8, &Literal::getLanesUI16x8, &Literal::ltU>(*this, other);
+}
+Literal Literal::gtSI16x8(const Literal& other) const {
+  return compare<8, &Literal::getLanesSI16x8, &Literal::gtS>(*this, other);
+}
+Literal Literal::gtUI16x8(const Literal& other) const {
+  return compare<8, &Literal::getLanesUI16x8, &Literal::gtU>(*this, other);
+}
+Literal Literal::leSI16x8(const Literal& other) const {
+  return compare<8, &Literal::getLanesSI16x8, &Literal::leS>(*this, other);
+}
+Literal Literal::leUI16x8(const Literal& other) const {
+  return compare<8, &Literal::getLanesUI16x8, &Literal::leU>(*this, other);
+}
+Literal Literal::geSI16x8(const Literal& other) const {
+  return compare<8, &Literal::getLanesSI16x8, &Literal::geS>(*this, other);
+}
+Literal Literal::geUI16x8(const Literal& other) const {
+  return compare<8, &Literal::getLanesUI16x8, &Literal::geU>(*this, other);
+}
+Literal Literal::eqI32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesI32x4, &Literal::eq>(*this, other);
+}
+Literal Literal::neI32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesI32x4, &Literal::ne>(*this, other);
+}
+Literal Literal::ltSI32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesI32x4, &Literal::ltS>(*this, other);
+}
+Literal Literal::ltUI32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesI32x4, &Literal::ltU>(*this, other);
+}
+Literal Literal::gtSI32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesI32x4, &Literal::gtS>(*this, other);
+}
+Literal Literal::gtUI32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesI32x4, &Literal::gtU>(*this, other);
+}
+Literal Literal::leSI32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesI32x4, &Literal::leS>(*this, other);
+}
+Literal Literal::leUI32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesI32x4, &Literal::leU>(*this, other);
+}
+Literal Literal::geSI32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesI32x4, &Literal::geS>(*this, other);
+}
+Literal Literal::geUI32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesI32x4, &Literal::geU>(*this, other);
+}
+Literal Literal::eqF32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesF32x4, &Literal::eq>(*this, other);
+}
+Literal Literal::neF32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesF32x4, &Literal::ne>(*this, other);
+}
+Literal Literal::ltF32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesF32x4, &Literal::lt>(*this, other);
+}
+Literal Literal::gtF32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesF32x4, &Literal::gt>(*this, other);
+}
+Literal Literal::leF32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesF32x4, &Literal::le>(*this, other);
+}
+Literal Literal::geF32x4(const Literal& other) const {
+  return compare<4, &Literal::getLanesF32x4, &Literal::ge>(*this, other);
+}
+Literal Literal::eqF64x2(const Literal& other) const {
+  return compare<2, &Literal::getLanesF64x2, &Literal::eq, int64_t>(*this,
+                                                                    other);
+}
+Literal Literal::neF64x2(const Literal& other) const {
+  return compare<2, &Literal::getLanesF64x2, &Literal::ne, int64_t>(*this,
+                                                                    other);
+}
+Literal Literal::ltF64x2(const Literal& other) const {
+  return compare<2, &Literal::getLanesF64x2, &Literal::lt, int64_t>(*this,
+                                                                    other);
+}
+Literal Literal::gtF64x2(const Literal& other) const {
+  return compare<2, &Literal::getLanesF64x2, &Literal::gt, int64_t>(*this,
+                                                                    other);
+}
+Literal Literal::leF64x2(const Literal& other) const {
+  return compare<2, &Literal::getLanesF64x2, &Literal::le, int64_t>(*this,
+                                                                    other);
+}
+Literal Literal::geF64x2(const Literal& other) const {
+  return compare<2, &Literal::getLanesF64x2, &Literal::ge, int64_t>(*this,
+                                                                    other);
+}
+
+template<int Lanes,
+         LaneArray<Lanes> (Literal::*IntoLanes)() const,
+         Literal (Literal::*BinaryOp)(const Literal&) const>
+static Literal binary(const Literal& val, const Literal& other) {
+  LaneArray<Lanes> lanes = (val.*IntoLanes)();
+  LaneArray<Lanes> other_lanes = (other.*IntoLanes)();
+  for (size_t i = 0; i < Lanes; ++i) {
+    lanes[i] = (lanes[i].*BinaryOp)(other_lanes[i]);
+  }
+  return Literal(lanes);
+}
+
+Literal Literal::andV128(const Literal& other) const {
+  return binary<4, &Literal::getLanesI32x4, &Literal::and_>(*this, other);
+}
+Literal Literal::orV128(const Literal& other) const {
+  return binary<4, &Literal::getLanesI32x4, &Literal::or_>(*this, other);
+}
+Literal Literal::xorV128(const Literal& other) const {
+  return binary<4, &Literal::getLanesI32x4, &Literal::xor_>(*this, other);
+}
+Literal Literal::addI8x16(const Literal& other) const {
+  return binary<16, &Literal::getLanesUI8x16, &Literal::add>(*this, other);
+}
+Literal Literal::addSaturateSI8x16(const Literal& other) const {
+  return binary<16, &Literal::getLanesUI8x16, &Literal::addSatSI8>(*this,
+                                                                   other);
+}
+Literal Literal::addSaturateUI8x16(const Literal& other) const {
+  return binary<16, &Literal::getLanesSI8x16, &Literal::addSatUI8>(*this,
+                                                                   other);
+}
+Literal Literal::subI8x16(const Literal& other) const {
+  return binary<16, &Literal::getLanesUI8x16, &Literal::sub>(*this, other);
+}
+Literal Literal::subSaturateSI8x16(const Literal& other) const {
+  return binary<16, &Literal::getLanesUI8x16, &Literal::subSatSI8>(*this,
+                                                                   other);
+}
+Literal Literal::subSaturateUI8x16(const Literal& other) const {
+  return binary<16, &Literal::getLanesSI8x16, &Literal::subSatUI8>(*this,
+                                                                   other);
+}
+Literal Literal::mulI8x16(const Literal& other) const {
+  return binary<16, &Literal::getLanesUI8x16, &Literal::mul>(*this, other);
+}
+Literal Literal::minSI8x16(const Literal& other) const {
+  return binary<16, &Literal::getLanesSI8x16, &Literal::minInt>(*this, other);
+}
+Literal Literal::minUI8x16(const Literal& other) const {
+  return binary<16, &Literal::getLanesUI8x16, &Literal::minInt>(*this, other);
+}
+Literal Literal::maxSI8x16(const Literal& other) const {
+  return binary<16, &Literal::getLanesSI8x16, &Literal::maxInt>(*this, other);
+}
+Literal Literal::maxUI8x16(const Literal& other) const {
+  return binary<16, &Literal::getLanesUI8x16, &Literal::maxInt>(*this, other);
+}
+Literal Literal::avgrUI8x16(const Literal& other) const {
+  return binary<16, &Literal::getLanesUI8x16, &Literal::avgrUInt>(*this, other);
+}
+Literal Literal::addI16x8(const Literal& other) const {
+  return binary<8, &Literal::getLanesUI16x8, &Literal::add>(*this, other);
+}
+Literal Literal::addSaturateSI16x8(const Literal& other) const {
+  return binary<8, &Literal::getLanesUI16x8, &Literal::addSatSI16>(*this,
+                                                                   other);
+}
+Literal Literal::addSaturateUI16x8(const Literal& other) const {
+  return binary<8, &Literal::getLanesSI16x8, &Literal::addSatUI16>(*this,
+                                                                   other);
+}
+Literal Literal::subI16x8(const Literal& other) const {
+  return binary<8, &Literal::getLanesUI16x8, &Literal::sub>(*this, other);
+}
+Literal Literal::subSaturateSI16x8(const Literal& other) const {
+  return binary<8, &Literal::getLanesUI16x8, &Literal::subSatSI16>(*this,
+                                                                   other);
+}
+Literal Literal::subSaturateUI16x8(const Literal& other) const {
+  return binary<8, &Literal::getLanesSI16x8, &Literal::subSatUI16>(*this,
+                                                                   other);
+}
+Literal Literal::mulI16x8(const Literal& other) const {
+  return binary<8, &Literal::getLanesUI16x8, &Literal::mul>(*this, other);
+}
+Literal Literal::minSI16x8(const Literal& other) const {
+  return binary<8, &Literal::getLanesSI16x8, &Literal::minInt>(*this, other);
+}
+Literal Literal::minUI16x8(const Literal& other) const {
+  return binary<8, &Literal::getLanesUI16x8, &Literal::minInt>(*this, other);
+}
+Literal Literal::maxSI16x8(const Literal& other) const {
+  return binary<8, &Literal::getLanesSI16x8, &Literal::maxInt>(*this, other);
+}
+Literal Literal::maxUI16x8(const Literal& other) const {
+  return binary<8, &Literal::getLanesUI16x8, &Literal::maxInt>(*this, other);
+}
+Literal Literal::avgrUI16x8(const Literal& other) const {
+  return binary<8, &Literal::getLanesUI16x8, &Literal::avgrUInt>(*this, other);
+}
+Literal Literal::addI32x4(const Literal& other) const {
+  return binary<4, &Literal::getLanesI32x4, &Literal::add>(*this, other);
+}
+Literal Literal::subI32x4(const Literal& other) const {
+  return binary<4, &Literal::getLanesI32x4, &Literal::sub>(*this, other);
+}
+Literal Literal::mulI32x4(const Literal& other) const {
+  return binary<4, &Literal::getLanesI32x4, &Literal::mul>(*this, other);
+}
+Literal Literal::minSI32x4(const Literal& other) const {
+  return binary<4, &Literal::getLanesI32x4, &Literal::minInt>(*this, other);
+}
+Literal Literal::minUI32x4(const Literal& other) const {
+  return binary<4, &Literal::getLanesI32x4, &Literal::minUInt>(*this, other);
+}
+Literal Literal::maxSI32x4(const Literal& other) const {
+  return binary<4, &Literal::getLanesI32x4, &Literal::maxInt>(*this, other);
+}
+Literal Literal::maxUI32x4(const Literal& other) const {
+  return binary<4, &Literal::getLanesI32x4, &Literal::maxUInt>(*this, other);
+}
+Literal Literal::addI64x2(const Literal& other) const {
+  return binary<2, &Literal::getLanesI64x2, &Literal::add>(*this, other);
+}
+Literal Literal::subI64x2(const Literal& other) const {
+  return binary<2, &Literal::getLanesI64x2, &Literal::sub>(*this, other);
+}
+Literal Literal::mulI64x2(const Literal& other) const {
+  return binary<2, &Literal::getLanesI64x2, &Literal::mul>(*this, other);
+}
+Literal Literal::addF32x4(const Literal& other) const {
+  return binary<4, &Literal::getLanesF32x4, &Literal::add>(*this, other);
+}
+Literal Literal::subF32x4(const Literal& other) const {
+  return binary<4, &Literal::getLanesF32x4, &Literal::sub>(*this, other);
+}
+Literal Literal::mulF32x4(const Literal& other) const {
+  return binary<4, &Literal::getLanesF32x4, &Literal::mul>(*this, other);
+}
+Literal Literal::divF32x4(const Literal& other) const {
+  return binary<4, &Literal::getLanesF32x4, &Literal::div>(*this, other);
+}
+Literal Literal::minF32x4(const Literal& other) const {
+  return binary<4, &Literal::getLanesF32x4, &Literal::min>(*this, other);
+}
+Literal Literal::maxF32x4(const Literal& other) const {
+  return binary<4, &Literal::getLanesF32x4, &Literal::max>(*this, other);
+}
+Literal Literal::pminF32x4(const Literal& other) const {
+  return binary<4, &Literal::getLanesF32x4, &Literal::pmin>(*this, other);
+}
+Literal Literal::pmaxF32x4(const Literal& other) const {
+  return binary<4, &Literal::getLanesF32x4, &Literal::pmax>(*this, other);
+}
+Literal Literal::addF64x2(const Literal& other) const {
+  return binary<2, &Literal::getLanesF64x2, &Literal::add>(*this, other);
+}
+Literal Literal::subF64x2(const Literal& other) const {
+  return binary<2, &Literal::getLanesF64x2, &Literal::sub>(*this, other);
+}
+Literal Literal::mulF64x2(const Literal& other) const {
+  return binary<2, &Literal::getLanesF64x2, &Literal::mul>(*this, other);
+}
+Literal Literal::divF64x2(const Literal& other) const {
+  return binary<2, &Literal::getLanesF64x2, &Literal::div>(*this, other);
+}
+Literal Literal::minF64x2(const Literal& other) const {
+  return binary<2, &Literal::getLanesF64x2, &Literal::min>(*this, other);
+}
+Literal Literal::maxF64x2(const Literal& other) const {
+  return binary<2, &Literal::getLanesF64x2, &Literal::max>(*this, other);
+}
+Literal Literal::pminF64x2(const Literal& other) const {
+  return binary<2, &Literal::getLanesF64x2, &Literal::pmin>(*this, other);
+}
+Literal Literal::pmaxF64x2(const Literal& other) const {
+  return binary<2, &Literal::getLanesF64x2, &Literal::pmax>(*this, other);
+}
+
+Literal Literal::dotSI16x8toI32x4(const Literal& other) const {
+  LaneArray<8> lhs = getLanesSI16x8();
+  LaneArray<8> rhs = other.getLanesSI16x8();
+  LaneArray<4> result;
+  for (size_t i = 0; i < 4; ++i) {
+    result[i] = Literal(lhs[i * 2].geti32() * rhs[i * 2].geti32() +
+                        lhs[i * 2 + 1].geti32() * rhs[i * 2 + 1].geti32());
+  }
+  return Literal(result);
+}
+
+Literal Literal::bitselectV128(const Literal& left,
+                               const Literal& right) const {
+  return andV128(left).orV128(notV128().andV128(right));
+}
+
+template<typename T> struct TwiceWidth {};
+template<> struct TwiceWidth<int8_t> { using type = int16_t; };
+template<> struct TwiceWidth<int16_t> { using type = int32_t; };
+
+template<typename T>
+Literal saturating_narrow(
+  typename TwiceWidth<typename std::make_signed<T>::type>::type val) {
+  using WideT = typename TwiceWidth<typename std::make_signed<T>::type>::type;
+  if (val > WideT(std::numeric_limits<T>::max())) {
+    val = std::numeric_limits<T>::max();
+  } else if (val < WideT(std::numeric_limits<T>::min())) {
+    val = std::numeric_limits<T>::min();
+  }
+  return Literal(int32_t(val));
+}
+
+template<size_t Lanes,
+         typename T,
+         LaneArray<Lanes / 2> (Literal::*IntoLanes)() const>
+Literal narrow(const Literal& low, const Literal& high) {
+  LaneArray<Lanes / 2> lowLanes = (low.*IntoLanes)();
+  LaneArray<Lanes / 2> highLanes = (high.*IntoLanes)();
+  LaneArray<Lanes> result;
+  for (size_t i = 0; i < Lanes / 2; ++i) {
+    result[i] = saturating_narrow<T>(lowLanes[i].geti32());
+    result[Lanes / 2 + i] = saturating_narrow<T>(highLanes[i].geti32());
+  }
+  return Literal(result);
+}
+
+Literal Literal::narrowSToVecI8x16(const Literal& other) const {
+  return narrow<16, int8_t, &Literal::getLanesSI16x8>(*this, other);
+}
+Literal Literal::narrowUToVecI8x16(const Literal& other) const {
+  return narrow<16, uint8_t, &Literal::getLanesSI16x8>(*this, other);
+}
+Literal Literal::narrowSToVecI16x8(const Literal& other) const {
+  return narrow<8, int16_t, &Literal::getLanesI32x4>(*this, other);
+}
+Literal Literal::narrowUToVecI16x8(const Literal& other) const {
+  return narrow<8, uint16_t, &Literal::getLanesI32x4>(*this, other);
+}
+
+enum class LaneOrder { Low, High };
+
+template<size_t Lanes,
+         LaneArray<Lanes * 2> (Literal::*IntoLanes)() const,
+         LaneOrder Side>
+Literal widen(const Literal& vec) {
+  LaneArray<Lanes* 2> lanes = (vec.*IntoLanes)();
+  LaneArray<Lanes> result;
+  for (size_t i = 0; i < Lanes; ++i) {
+    result[i] = lanes[(Side == LaneOrder::Low) ? i : i + Lanes];
+  }
+  return Literal(result);
+}
+
+Literal Literal::widenLowSToVecI16x8() const {
+  return widen<8, &Literal::getLanesSI8x16, LaneOrder::Low>(*this);
+}
+Literal Literal::widenHighSToVecI16x8() const {
+  return widen<8, &Literal::getLanesSI8x16, LaneOrder::High>(*this);
+}
+Literal Literal::widenLowUToVecI16x8() const {
+  return widen<8, &Literal::getLanesUI8x16, LaneOrder::Low>(*this);
+}
+Literal Literal::widenHighUToVecI16x8() const {
+  return widen<8, &Literal::getLanesUI8x16, LaneOrder::High>(*this);
+}
+Literal Literal::widenLowSToVecI32x4() const {
+  return widen<4, &Literal::getLanesSI16x8, LaneOrder::Low>(*this);
+}
+Literal Literal::widenHighSToVecI32x4() const {
+  return widen<4, &Literal::getLanesSI16x8, LaneOrder::High>(*this);
+}
+Literal Literal::widenLowUToVecI32x4() const {
+  return widen<4, &Literal::getLanesUI16x8, LaneOrder::Low>(*this);
+}
+Literal Literal::widenHighUToVecI32x4() const {
+  return widen<4, &Literal::getLanesUI16x8, LaneOrder::High>(*this);
+}
+
+Literal Literal::swizzleVec8x16(const Literal& other) const {
+  auto lanes = getLanesUI8x16();
+  auto indices = other.getLanesUI8x16();
+  LaneArray<16> result;
+  for (size_t i = 0; i < 16; ++i) {
+    size_t index = indices[i].geti32();
+    result[i] = index >= 16 ? Literal(int32_t(0)) : lanes[index];
+  }
+  return Literal(result);
+}
+
+} // namespace wasm
diff --git a/binaryen/src/wasm/wasm-binary.cpp b/binaryen/src/wasm/wasm-binary.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm/wasm-binary.cpp
@@ -0,0 +1,5409 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <fstream>
+
+#include "ir/module-utils.h"
+#include "support/bits.h"
+#include "support/debug.h"
+#include "wasm-binary.h"
+#include "wasm-debug.h"
+#include "wasm-stack.h"
+
+#define DEBUG_TYPE "binary"
+
+namespace wasm {
+
+void WasmBinaryWriter::prepare() {
+  // Collect function types and their frequencies. Collect information in each
+  // function in parallel, then merge.
+  ModuleUtils::collectSignatures(*wasm, types, typeIndices);
+  importInfo = wasm::make_unique<ImportInfo>(*wasm);
+}
+
+void WasmBinaryWriter::write() {
+  writeHeader();
+
+  writeDylinkSection();
+
+  initializeDebugInfo();
+  if (sourceMap) {
+    writeSourceMapProlog();
+  }
+
+  writeTypes();
+  writeImports();
+  writeFunctionSignatures();
+  writeFunctionTableDeclaration();
+  writeMemory();
+  writeEvents();
+  writeGlobals();
+  writeExports();
+  writeStart();
+  writeTableElements();
+  writeDataCount();
+  writeFunctions();
+  writeDataSegments();
+  if (debugInfo) {
+    writeNames();
+  }
+  if (sourceMap && !sourceMapUrl.empty()) {
+    writeSourceMapUrl();
+  }
+  if (symbolMap.size() > 0) {
+    writeSymbolMap();
+  }
+
+  if (sourceMap) {
+    writeSourceMapEpilog();
+  }
+
+#ifdef BUILD_LLVM_DWARF
+  // Update DWARF user sections after writing the data they refer to
+  // (function bodies), and before writing the user sections themselves.
+  if (Debug::hasDWARFSections(*wasm)) {
+    Debug::writeDWARFSections(*wasm, binaryLocations);
+  }
+#endif
+
+  writeLateUserSections();
+  writeFeaturesSection();
+
+  finishUp();
+}
+
+void WasmBinaryWriter::writeHeader() {
+  BYN_TRACE("== writeHeader\n");
+  o << int32_t(BinaryConsts::Magic); // magic number \0asm
+  o << int32_t(BinaryConsts::Version);
+}
+
+int32_t WasmBinaryWriter::writeU32LEBPlaceholder() {
+  int32_t ret = o.size();
+  o << int32_t(0);
+  o << int8_t(0);
+  return ret;
+}
+
+void WasmBinaryWriter::writeResizableLimits(
+  Address initial, Address maximum, bool hasMaximum, bool shared, bool is64) {
+  uint32_t flags = (hasMaximum ? (uint32_t)BinaryConsts::HasMaximum : 0U) |
+                   (shared ? (uint32_t)BinaryConsts::IsShared : 0U) |
+                   (is64 ? (uint32_t)BinaryConsts::Is64 : 0U);
+  o << U32LEB(flags);
+  o << U32LEB(initial);
+  if (hasMaximum) {
+    o << U32LEB(maximum);
+  }
+}
+
+template<typename T> int32_t WasmBinaryWriter::startSection(T code) {
+  o << uint8_t(code);
+  if (sourceMap) {
+    sourceMapLocationsSizeAtSectionStart = sourceMapLocations.size();
+  }
+  binaryLocationsSizeAtSectionStart = binaryLocations.expressions.size();
+  return writeU32LEBPlaceholder(); // section size to be filled in later
+}
+
+void WasmBinaryWriter::finishSection(int32_t start) {
+  // section size does not include the reserved bytes of the size field itself
+  int32_t size = o.size() - start - MaxLEB32Bytes;
+  auto sizeFieldSize = o.writeAt(start, U32LEB(size));
+  // We can move things back if the actual LEB for the size doesn't use the
+  // maximum 5 bytes. In that case we need to adjust offsets after we move
+  // things backwards.
+  auto adjustmentForLEBShrinking = MaxLEB32Bytes - sizeFieldSize;
+  if (adjustmentForLEBShrinking) {
+    // we can save some room, nice
+    assert(sizeFieldSize < MaxLEB32Bytes);
+    std::move(&o[start] + MaxLEB32Bytes,
+              &o[start] + MaxLEB32Bytes + size,
+              &o[start] + sizeFieldSize);
+    o.resize(o.size() - adjustmentForLEBShrinking);
+    if (sourceMap) {
+      for (auto i = sourceMapLocationsSizeAtSectionStart;
+           i < sourceMapLocations.size();
+           ++i) {
+        sourceMapLocations[i].first -= adjustmentForLEBShrinking;
+      }
+    }
+  }
+
+  if (binaryLocationsSizeAtSectionStart != binaryLocations.expressions.size()) {
+    // We added the binary locations, adjust them: they must be relative
+    // to the code section.
+    assert(binaryLocationsSizeAtSectionStart == 0);
+    // The section type byte is right before the LEB for the size; we want
+    // offsets that are relative to the body, which is after that section type
+    // byte and the the size LEB.
+    auto body = start + sizeFieldSize;
+    // Offsets are relative to the body of the code section: after the
+    // section type byte and the size.
+    // Everything was moved by the adjustment, track that. After this,
+    // we are at the right absolute address.
+    // We are relative to the section start.
+    auto totalAdjustment = adjustmentForLEBShrinking + body;
+    for (auto& pair : binaryLocations.expressions) {
+      pair.second.start -= totalAdjustment;
+      pair.second.end -= totalAdjustment;
+    }
+    for (auto& pair : binaryLocations.functions) {
+      pair.second.start -= totalAdjustment;
+      pair.second.declarations -= totalAdjustment;
+      pair.second.end -= totalAdjustment;
+    }
+    for (auto& pair : binaryLocations.delimiters) {
+      for (auto& item : pair.second) {
+        item -= totalAdjustment;
+      }
+    }
+  }
+}
+
+int32_t
+WasmBinaryWriter::startSubsection(BinaryConsts::UserSections::Subsection code) {
+  return startSection(code);
+}
+
+void WasmBinaryWriter::finishSubsection(int32_t start) { finishSection(start); }
+
+void WasmBinaryWriter::writeStart() {
+  if (!wasm->start.is()) {
+    return;
+  }
+  BYN_TRACE("== writeStart\n");
+  auto start = startSection(BinaryConsts::Section::Start);
+  o << U32LEB(getFunctionIndex(wasm->start.str));
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeMemory() {
+  if (!wasm->memory.exists || wasm->memory.imported()) {
+    return;
+  }
+  BYN_TRACE("== writeMemory\n");
+  auto start = startSection(BinaryConsts::Section::Memory);
+  o << U32LEB(1); // Define 1 memory
+  writeResizableLimits(wasm->memory.initial,
+                       wasm->memory.max,
+                       wasm->memory.hasMax(),
+                       wasm->memory.shared,
+                       wasm->memory.is64());
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeTypes() {
+  if (types.size() == 0) {
+    return;
+  }
+  BYN_TRACE("== writeTypes\n");
+  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);
+      }
+    }
+  }
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeImports() {
+  auto num = importInfo->getNumImports();
+  if (num == 0) {
+    return;
+  }
+  BYN_TRACE("== writeImports\n");
+  auto start = startSection(BinaryConsts::Section::Import);
+  o << U32LEB(num);
+  auto writeImportHeader = [&](Importable* import) {
+    writeInlineString(import->module.str);
+    writeInlineString(import->base.str);
+  };
+  ModuleUtils::iterImportedFunctions(*wasm, [&](Function* func) {
+    BYN_TRACE("write one function\n");
+    writeImportHeader(func);
+    o << U32LEB(int32_t(ExternalKind::Function));
+    o << U32LEB(getTypeIndex(func->sig));
+  });
+  ModuleUtils::iterImportedGlobals(*wasm, [&](Global* global) {
+    BYN_TRACE("write one global\n");
+    writeImportHeader(global);
+    o << U32LEB(int32_t(ExternalKind::Global));
+    o << binaryType(global->type);
+    o << U32LEB(global->mutable_);
+  });
+  ModuleUtils::iterImportedEvents(*wasm, [&](Event* event) {
+    BYN_TRACE("write one event\n");
+    writeImportHeader(event);
+    o << U32LEB(int32_t(ExternalKind::Event));
+    o << U32LEB(event->attribute);
+    o << U32LEB(getTypeIndex(event->sig));
+  });
+  if (wasm->memory.imported()) {
+    BYN_TRACE("write one memory\n");
+    writeImportHeader(&wasm->memory);
+    o << U32LEB(int32_t(ExternalKind::Memory));
+    writeResizableLimits(wasm->memory.initial,
+                         wasm->memory.max,
+                         wasm->memory.hasMax(),
+                         wasm->memory.shared,
+                         wasm->memory.is64());
+  }
+  if (wasm->table.imported()) {
+    BYN_TRACE("write one table\n");
+    writeImportHeader(&wasm->table);
+    o << U32LEB(int32_t(ExternalKind::Table));
+    o << S32LEB(BinaryConsts::EncodedType::funcref);
+    writeResizableLimits(wasm->table.initial,
+                         wasm->table.max,
+                         wasm->table.hasMax(),
+                         /*shared=*/false,
+                         /*is64*/ false);
+  }
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeFunctionSignatures() {
+  if (importInfo->getNumDefinedFunctions() == 0) {
+    return;
+  }
+  BYN_TRACE("== writeFunctionSignatures\n");
+  auto start = startSection(BinaryConsts::Section::Function);
+  o << U32LEB(importInfo->getNumDefinedFunctions());
+  ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) {
+    BYN_TRACE("write one\n");
+    o << U32LEB(getTypeIndex(func->sig));
+  });
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeExpression(Expression* curr) {
+  BinaryenIRToBinaryWriter(*this, o).visit(curr);
+}
+
+void WasmBinaryWriter::writeFunctions() {
+  if (importInfo->getNumDefinedFunctions() == 0) {
+    return;
+  }
+  BYN_TRACE("== writeFunctions\n");
+  auto sectionStart = startSection(BinaryConsts::Section::Code);
+  o << U32LEB(importInfo->getNumDefinedFunctions());
+  bool DWARF = Debug::hasDWARFSections(*getModule());
+  ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) {
+    assert(binaryLocationTrackedExpressionsForFunc.empty());
+    size_t sourceMapLocationsSizeAtFunctionStart = sourceMapLocations.size();
+    BYN_TRACE("write one at" << o.size() << std::endl);
+    size_t sizePos = writeU32LEBPlaceholder();
+    size_t start = o.size();
+    BYN_TRACE("writing" << func->name << std::endl);
+    // Emit Stack IR if present, and if we can
+    if (func->stackIR && !sourceMap && !DWARF) {
+      BYN_TRACE("write Stack IR\n");
+      StackIRToBinaryWriter(*this, o, func).write();
+    } else {
+      BYN_TRACE("write Binaryen IR\n");
+      BinaryenIRToBinaryWriter(*this, o, func, sourceMap, DWARF).write();
+    }
+    size_t size = o.size() - start;
+    assert(size <= std::numeric_limits<uint32_t>::max());
+    BYN_TRACE("body size: " << size << ", writing at " << sizePos
+                            << ", next starts at " << o.size() << "\n");
+    auto sizeFieldSize = o.writeAt(sizePos, U32LEB(size));
+    // We can move things back if the actual LEB for the size doesn't use the
+    // maximum 5 bytes. In that case we need to adjust offsets after we move
+    // things backwards.
+    auto adjustmentForLEBShrinking = MaxLEB32Bytes - sizeFieldSize;
+    if (adjustmentForLEBShrinking) {
+      // we can save some room, nice
+      assert(sizeFieldSize < MaxLEB32Bytes);
+      std::move(&o[start], &o[start] + size, &o[sizePos] + sizeFieldSize);
+      o.resize(o.size() - adjustmentForLEBShrinking);
+      if (sourceMap) {
+        for (auto i = sourceMapLocationsSizeAtFunctionStart;
+             i < sourceMapLocations.size();
+             ++i) {
+          sourceMapLocations[i].first -= adjustmentForLEBShrinking;
+        }
+      }
+      for (auto* curr : binaryLocationTrackedExpressionsForFunc) {
+        // We added the binary locations, adjust them: they must be relative
+        // to the code section.
+        auto& span = binaryLocations.expressions[curr];
+        span.start -= adjustmentForLEBShrinking;
+        span.end -= adjustmentForLEBShrinking;
+        auto iter = binaryLocations.delimiters.find(curr);
+        if (iter != binaryLocations.delimiters.end()) {
+          for (auto& item : iter->second) {
+            item -= adjustmentForLEBShrinking;
+          }
+        }
+      }
+    }
+    if (!binaryLocationTrackedExpressionsForFunc.empty()) {
+      binaryLocations.functions[func] = BinaryLocations::FunctionLocations{
+        BinaryLocation(sizePos),
+        BinaryLocation(start - adjustmentForLEBShrinking),
+        BinaryLocation(o.size())};
+    }
+    tableOfContents.functionBodies.emplace_back(
+      func->name, sizePos + sizeFieldSize, size);
+    binaryLocationTrackedExpressionsForFunc.clear();
+  });
+  finishSection(sectionStart);
+}
+
+void WasmBinaryWriter::writeGlobals() {
+  if (importInfo->getNumDefinedGlobals() == 0) {
+    return;
+  }
+  BYN_TRACE("== writeglobals\n");
+  auto start = startSection(BinaryConsts::Section::Global);
+  // Count and emit the total number of globals after tuple globals have been
+  // expanded into their constituent parts.
+  Index num = 0;
+  ModuleUtils::iterDefinedGlobals(
+    *wasm, [&num](Global* global) { num += global->type.size(); });
+  o << U32LEB(num);
+  ModuleUtils::iterDefinedGlobals(*wasm, [&](Global* global) {
+    BYN_TRACE("write one\n");
+    size_t i = 0;
+    for (const auto& t : global->type) {
+      o << binaryType(t);
+      o << U32LEB(global->mutable_);
+      if (global->type.size() == 1) {
+        writeExpression(global->init);
+      } else {
+        writeExpression(global->init->cast<TupleMake>()->operands[i]);
+      }
+      o << int8_t(BinaryConsts::End);
+      ++i;
+    }
+  });
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeExports() {
+  if (wasm->exports.size() == 0) {
+    return;
+  }
+  BYN_TRACE("== writeexports\n");
+  auto start = startSection(BinaryConsts::Section::Export);
+  o << U32LEB(wasm->exports.size());
+  for (auto& curr : wasm->exports) {
+    BYN_TRACE("write one\n");
+    writeInlineString(curr->name.str);
+    o << U32LEB(int32_t(curr->kind));
+    switch (curr->kind) {
+      case ExternalKind::Function:
+        o << U32LEB(getFunctionIndex(curr->value));
+        break;
+      case ExternalKind::Table:
+        o << U32LEB(0);
+        break;
+      case ExternalKind::Memory:
+        o << U32LEB(0);
+        break;
+      case ExternalKind::Global:
+        o << U32LEB(getGlobalIndex(curr->value));
+        break;
+      case ExternalKind::Event:
+        o << U32LEB(getEventIndex(curr->value));
+        break;
+      default:
+        WASM_UNREACHABLE("unexpected extern kind");
+    }
+  }
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeDataCount() {
+  if (!wasm->features.hasBulkMemory() || !wasm->memory.segments.size()) {
+    return;
+  }
+  auto start = startSection(BinaryConsts::Section::DataCount);
+  o << U32LEB(wasm->memory.segments.size());
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeDataSegments() {
+  if (wasm->memory.segments.size() == 0) {
+    return;
+  }
+  if (wasm->memory.segments.size() > WebLimitations::MaxDataSegments) {
+    std::cerr << "Some VMs may not accept this binary because it has a large "
+              << "number of data segments. Run the limit-segments pass to "
+              << "merge segments.\n";
+  }
+  auto start = startSection(BinaryConsts::Section::Data);
+  o << U32LEB(wasm->memory.segments.size());
+  for (auto& segment : wasm->memory.segments) {
+    uint32_t flags = 0;
+    if (segment.isPassive) {
+      flags |= BinaryConsts::IsPassive;
+    }
+    o << U32LEB(flags);
+    if (!segment.isPassive) {
+      writeExpression(segment.offset);
+      o << int8_t(BinaryConsts::End);
+    }
+    writeInlineBuffer(segment.data.data(), segment.data.size());
+  }
+  finishSection(start);
+}
+
+uint32_t WasmBinaryWriter::getFunctionIndex(Name name) const {
+  auto it = indexes.functionIndexes.find(name);
+  assert(it != indexes.functionIndexes.end());
+  return it->second;
+}
+
+uint32_t WasmBinaryWriter::getGlobalIndex(Name name) const {
+  auto it = indexes.globalIndexes.find(name);
+  assert(it != indexes.globalIndexes.end());
+  return it->second;
+}
+
+uint32_t WasmBinaryWriter::getEventIndex(Name name) const {
+  auto it = indexes.eventIndexes.find(name);
+  assert(it != indexes.eventIndexes.end());
+  return it->second;
+}
+
+uint32_t WasmBinaryWriter::getTypeIndex(Signature sig) const {
+  auto it = typeIndices.find(sig);
+  assert(it != typeIndices.end());
+  return it->second;
+}
+
+void WasmBinaryWriter::writeFunctionTableDeclaration() {
+  if (!wasm->table.exists || wasm->table.imported()) {
+    return;
+  }
+  BYN_TRACE("== writeFunctionTableDeclaration\n");
+  auto start = startSection(BinaryConsts::Section::Table);
+  o << U32LEB(1); // Declare 1 table.
+  o << S32LEB(BinaryConsts::EncodedType::funcref);
+  writeResizableLimits(wasm->table.initial,
+                       wasm->table.max,
+                       wasm->table.hasMax(),
+                       /*shared=*/false,
+                       /*is64*/ false);
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeTableElements() {
+  if (!wasm->table.exists || wasm->table.segments.size() == 0) {
+    return;
+  }
+  BYN_TRACE("== writeTableElements\n");
+  auto start = startSection(BinaryConsts::Section::Element);
+
+  o << U32LEB(wasm->table.segments.size());
+  for (auto& segment : wasm->table.segments) {
+    // Table index; 0 in the MVP (and binaryen IR only has 1 table)
+    o << U32LEB(0);
+    writeExpression(segment.offset);
+    o << int8_t(BinaryConsts::End);
+    o << U32LEB(segment.data.size());
+    for (auto name : segment.data) {
+      o << U32LEB(getFunctionIndex(name));
+    }
+  }
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeEvents() {
+  if (importInfo->getNumDefinedEvents() == 0) {
+    return;
+  }
+  BYN_TRACE("== writeEvents\n");
+  auto start = startSection(BinaryConsts::Section::Event);
+  auto num = importInfo->getNumDefinedEvents();
+  o << U32LEB(num);
+  ModuleUtils::iterDefinedEvents(*wasm, [&](Event* event) {
+    BYN_TRACE("write one\n");
+    o << U32LEB(event->attribute);
+    o << U32LEB(getTypeIndex(event->sig));
+  });
+
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeNames() {
+  BYN_TRACE("== writeNames\n");
+  auto start = startSection(BinaryConsts::Section::User);
+  writeInlineString(BinaryConsts::UserSections::Name);
+
+  // module name
+  if (wasm->name.is()) {
+    auto substart =
+      startSubsection(BinaryConsts::UserSections::Subsection::NameModule);
+    writeEscapedName(wasm->name.str);
+    finishSubsection(substart);
+  }
+
+  // function names
+  {
+    auto substart =
+      startSubsection(BinaryConsts::UserSections::Subsection::NameFunction);
+    o << U32LEB(indexes.functionIndexes.size());
+    Index emitted = 0;
+    auto add = [&](Function* curr) {
+      o << U32LEB(emitted);
+      writeEscapedName(curr->name.str);
+      emitted++;
+    };
+    ModuleUtils::iterImportedFunctions(*wasm, add);
+    ModuleUtils::iterDefinedFunctions(*wasm, add);
+    assert(emitted == indexes.functionIndexes.size());
+    finishSubsection(substart);
+  }
+
+  // local names
+  {
+    // Find all functions with at least one local name and only emit the
+    // subsection if there is at least one.
+    std::vector<std::pair<Index, Function*>> functionsWithLocalNames;
+    Index checked = 0;
+    auto check = [&](Function* curr) {
+      auto numLocals = curr->getNumLocals();
+      for (Index i = 0; i < numLocals; ++i) {
+        if (curr->hasLocalName(i)) {
+          functionsWithLocalNames.push_back({checked, curr});
+          break;
+        }
+      }
+      checked++;
+    };
+    ModuleUtils::iterImportedFunctions(*wasm, check);
+    ModuleUtils::iterDefinedFunctions(*wasm, check);
+    assert(checked == indexes.functionIndexes.size());
+    if (functionsWithLocalNames.size() > 0) {
+      // Otherwise emit those functions but only include locals with a name.
+      auto substart =
+        startSubsection(BinaryConsts::UserSections::Subsection::NameLocal);
+      o << U32LEB(functionsWithLocalNames.size());
+      Index emitted = 0;
+      for (auto& indexedFunc : functionsWithLocalNames) {
+        std::vector<std::pair<Index, Name>> localsWithNames;
+        auto numLocals = indexedFunc.second->getNumLocals();
+        for (Index i = 0; i < numLocals; ++i) {
+          if (indexedFunc.second->hasLocalName(i)) {
+            localsWithNames.push_back({i, indexedFunc.second->getLocalName(i)});
+          }
+        }
+        assert(localsWithNames.size());
+        o << U32LEB(indexedFunc.first);
+        o << U32LEB(localsWithNames.size());
+        for (auto& indexedLocal : localsWithNames) {
+          o << U32LEB(indexedLocal.first);
+          writeEscapedName(indexedLocal.second.str);
+        }
+        emitted++;
+      }
+      assert(emitted == functionsWithLocalNames.size());
+      finishSubsection(substart);
+    }
+  }
+
+  // table names
+  if (wasm->table.exists && wasm->table.name.is()) {
+    auto substart =
+      startSubsection(BinaryConsts::UserSections::Subsection::NameTable);
+    o << U32LEB(1) << U32LEB(0); // currently exactly 1 table at index 0
+    writeEscapedName(wasm->table.name.str);
+    finishSubsection(substart);
+  }
+
+  // memory names
+  if (wasm->memory.exists && wasm->memory.name.is()) {
+    auto substart =
+      startSubsection(BinaryConsts::UserSections::Subsection::NameMemory);
+    o << U32LEB(1) << U32LEB(0); // currently exactly 1 memory at index 0
+    writeEscapedName(wasm->memory.name.str);
+    finishSubsection(substart);
+  }
+
+  // global names
+  {
+    std::vector<std::pair<Index, Global*>> globalsWithNames;
+    Index checked = 0;
+    auto check = [&](Global* curr) {
+      if (curr->name.is()) {
+        globalsWithNames.push_back({checked, curr});
+      }
+      checked++;
+    };
+    ModuleUtils::iterImportedGlobals(*wasm, check);
+    ModuleUtils::iterDefinedGlobals(*wasm, check);
+    assert(checked == indexes.globalIndexes.size());
+    if (globalsWithNames.size() > 0) {
+      auto substart =
+        startSubsection(BinaryConsts::UserSections::Subsection::NameGlobal);
+      o << U32LEB(globalsWithNames.size());
+      for (auto& indexedGlobal : globalsWithNames) {
+        o << U32LEB(indexedGlobal.first);
+        writeEscapedName(indexedGlobal.second->name.str);
+      }
+      finishSubsection(substart);
+    }
+  }
+
+  // TODO: label, type, element and data names
+  // see: https://github.com/WebAssembly/extended-name-section
+
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeSourceMapUrl() {
+  BYN_TRACE("== writeSourceMapUrl\n");
+  auto start = startSection(BinaryConsts::Section::User);
+  writeInlineString(BinaryConsts::UserSections::SourceMapUrl);
+  writeInlineString(sourceMapUrl.c_str());
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeSymbolMap() {
+  std::ofstream file(symbolMap);
+  auto write = [&](Function* func) {
+    file << getFunctionIndex(func->name) << ":" << func->name.str << std::endl;
+  };
+  ModuleUtils::iterImportedFunctions(*wasm, write);
+  ModuleUtils::iterDefinedFunctions(*wasm, write);
+  file.close();
+}
+
+void WasmBinaryWriter::initializeDebugInfo() {
+  lastDebugLocation = {0, /* lineNumber = */ 1, 0};
+}
+
+void WasmBinaryWriter::writeSourceMapProlog() {
+  *sourceMap << "{\"version\":3,\"sources\":[";
+  for (size_t i = 0; i < wasm->debugInfoFileNames.size(); i++) {
+    if (i > 0) {
+      *sourceMap << ",";
+    }
+    // TODO respect JSON string encoding, e.g. quotes and control chars.
+    *sourceMap << "\"" << wasm->debugInfoFileNames[i] << "\"";
+  }
+  *sourceMap << "],\"names\":[],\"mappings\":\"";
+}
+
+static void writeBase64VLQ(std::ostream& out, int32_t n) {
+  uint32_t value = n >= 0 ? n << 1 : ((-n) << 1) | 1;
+  while (1) {
+    uint32_t digit = value & 0x1F;
+    value >>= 5;
+    if (!value) {
+      // last VLQ digit -- base64 codes 'A'..'Z', 'a'..'f'
+      out << char(digit < 26 ? 'A' + digit : 'a' + digit - 26);
+      break;
+    }
+    // more VLG digit will follow -- add continuation bit (0x20),
+    // base64 codes 'g'..'z', '0'..'9', '+', '/'
+    out << char(digit < 20
+                  ? 'g' + digit
+                  : digit < 30 ? '0' + digit - 20 : digit == 30 ? '+' : '/');
+  }
+}
+
+void WasmBinaryWriter::writeSourceMapEpilog() {
+  // write source map entries
+  size_t lastOffset = 0;
+  Function::DebugLocation lastLoc = {0, /* lineNumber = */ 1, 0};
+  for (const auto& offsetAndlocPair : sourceMapLocations) {
+    if (lastOffset > 0) {
+      *sourceMap << ",";
+    }
+    size_t offset = offsetAndlocPair.first;
+    const Function::DebugLocation& loc = *offsetAndlocPair.second;
+    writeBase64VLQ(*sourceMap, int32_t(offset - lastOffset));
+    writeBase64VLQ(*sourceMap, int32_t(loc.fileIndex - lastLoc.fileIndex));
+    writeBase64VLQ(*sourceMap, int32_t(loc.lineNumber - lastLoc.lineNumber));
+    writeBase64VLQ(*sourceMap,
+                   int32_t(loc.columnNumber - lastLoc.columnNumber));
+    lastLoc = loc;
+    lastOffset = offset;
+  }
+  *sourceMap << "\"}";
+}
+
+void WasmBinaryWriter::writeLateUserSections() {
+  for (auto& section : wasm->userSections) {
+    if (section.name != BinaryConsts::UserSections::Dylink) {
+      writeUserSection(section);
+    }
+  }
+}
+
+void WasmBinaryWriter::writeUserSection(const UserSection& section) {
+  auto start = startSection(BinaryConsts::User);
+  writeInlineString(section.name.c_str());
+  for (size_t i = 0; i < section.data.size(); i++) {
+    o << uint8_t(section.data[i]);
+  }
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeFeaturesSection() {
+  if (!wasm->hasFeaturesSection || wasm->features.isMVP()) {
+    return;
+  }
+
+  // TODO(tlively): unify feature names with rest of toolchain and use
+  // FeatureSet::toString()
+  auto toString = [](FeatureSet::Feature f) {
+    switch (f) {
+      case FeatureSet::Atomics:
+        return BinaryConsts::UserSections::AtomicsFeature;
+      case FeatureSet::MutableGlobals:
+        return BinaryConsts::UserSections::MutableGlobalsFeature;
+      case FeatureSet::TruncSat:
+        return BinaryConsts::UserSections::TruncSatFeature;
+      case FeatureSet::SIMD:
+        return BinaryConsts::UserSections::SIMD128Feature;
+      case FeatureSet::BulkMemory:
+        return BinaryConsts::UserSections::BulkMemoryFeature;
+      case FeatureSet::SignExt:
+        return BinaryConsts::UserSections::SignExtFeature;
+      case FeatureSet::ExceptionHandling:
+        return BinaryConsts::UserSections::ExceptionHandlingFeature;
+      case FeatureSet::TailCall:
+        return BinaryConsts::UserSections::TailCallFeature;
+      case FeatureSet::ReferenceTypes:
+        return BinaryConsts::UserSections::ReferenceTypesFeature;
+      case FeatureSet::Multivalue:
+        return BinaryConsts::UserSections::MultivalueFeature;
+      case FeatureSet::GC:
+        return BinaryConsts::UserSections::GCFeature;
+      case FeatureSet::Memory64:
+        return BinaryConsts::UserSections::Memory64Feature;
+      default:
+        WASM_UNREACHABLE("unexpected feature flag");
+    }
+  };
+
+  std::vector<const char*> features;
+  wasm->features.iterFeatures(
+    [&](FeatureSet::Feature f) { features.push_back(toString(f)); });
+
+  auto start = startSection(BinaryConsts::User);
+  writeInlineString(BinaryConsts::UserSections::TargetFeatures);
+  o << U32LEB(features.size());
+  for (auto& f : features) {
+    o << uint8_t(BinaryConsts::FeatureUsed);
+    writeInlineString(f);
+  }
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeDylinkSection() {
+  if (!wasm->dylinkSection) {
+    return;
+  }
+
+  auto start = startSection(BinaryConsts::User);
+  writeInlineString(BinaryConsts::UserSections::Dylink);
+  o << U32LEB(wasm->dylinkSection->memorySize);
+  o << U32LEB(wasm->dylinkSection->memoryAlignment);
+  o << U32LEB(wasm->dylinkSection->tableSize);
+  o << U32LEB(wasm->dylinkSection->tableAlignment);
+  o << U32LEB(wasm->dylinkSection->neededDynlibs.size());
+  for (auto& neededDynlib : wasm->dylinkSection->neededDynlibs) {
+    writeInlineString(neededDynlib.c_str());
+  }
+  finishSection(start);
+}
+
+void WasmBinaryWriter::writeDebugLocation(const Function::DebugLocation& loc) {
+  if (loc == lastDebugLocation) {
+    return;
+  }
+  auto offset = o.size();
+  sourceMapLocations.emplace_back(offset, &loc);
+  lastDebugLocation = loc;
+}
+
+void WasmBinaryWriter::writeDebugLocation(Expression* curr, Function* func) {
+  if (sourceMap) {
+    auto& debugLocations = func->debugLocations;
+    auto iter = debugLocations.find(curr);
+    if (iter != debugLocations.end()) {
+      writeDebugLocation(iter->second);
+    }
+  }
+  // If this is an instruction in a function, and if the original wasm had
+  // binary locations tracked, then track it in the output as well.
+  if (func && !func->expressionLocations.empty()) {
+    binaryLocations.expressions[curr] =
+      BinaryLocations::Span{BinaryLocation(o.size()), 0};
+    binaryLocationTrackedExpressionsForFunc.push_back(curr);
+  }
+}
+
+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();
+  }
+}
+
+void WasmBinaryWriter::writeExtraDebugLocation(
+  Expression* curr, Function* func, BinaryLocations::DelimiterId id) {
+  if (func && !func->expressionLocations.empty()) {
+    binaryLocations.delimiters[curr][id] = o.size();
+  }
+}
+
+void WasmBinaryWriter::writeInlineString(const char* name) {
+  int32_t size = strlen(name);
+  o << U32LEB(size);
+  for (int32_t i = 0; i < size; i++) {
+    o << int8_t(name[i]);
+  }
+}
+
+static bool isHexDigit(char ch) {
+  return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
+         (ch >= 'A' && ch <= 'F');
+}
+
+static int decodeHexNibble(char ch) {
+  return ch <= '9' ? ch & 15 : (ch & 15) + 9;
+}
+
+void WasmBinaryWriter::writeEscapedName(const char* name) {
+  if (!strpbrk(name, "\\")) {
+    writeInlineString(name);
+    return;
+  }
+  // decode escaped by escapeName (see below) function names
+  std::string unescaped;
+  int32_t size = strlen(name);
+  for (int32_t i = 0; i < size;) {
+    char ch = name[i++];
+    // support only `\xx` escapes; ignore invalid or unsupported escapes
+    if (ch != '\\' || i + 1 >= size || !isHexDigit(name[i]) ||
+        !isHexDigit(name[i + 1])) {
+      unescaped.push_back(ch);
+      continue;
+    }
+    unescaped.push_back(
+      char((decodeHexNibble(name[i]) << 4) | decodeHexNibble(name[i + 1])));
+    i += 2;
+  }
+  writeInlineString(unescaped.c_str());
+}
+
+void WasmBinaryWriter::writeInlineBuffer(const char* data, size_t size) {
+  o << U32LEB(size);
+  for (size_t i = 0; i < size; i++) {
+    o << int8_t(data[i]);
+  }
+}
+
+void WasmBinaryWriter::emitBuffer(const char* data, size_t size) {
+  assert(size > 0);
+  buffersToWrite.emplace_back(data, size, o.size());
+  // placeholder, we'll fill in the pointer to the buffer later when we have it
+  o << uint32_t(0);
+}
+
+void WasmBinaryWriter::emitString(const char* str) {
+  BYN_TRACE("emitString " << str << std::endl);
+  emitBuffer(str, strlen(str) + 1);
+}
+
+void WasmBinaryWriter::finishUp() {
+  BYN_TRACE("finishUp\n");
+  // finish buffers
+  for (const auto& buffer : buffersToWrite) {
+    BYN_TRACE("writing buffer"
+              << (int)buffer.data[0] << "," << (int)buffer.data[1] << " at "
+              << o.size() << " and pointer is at " << buffer.pointerLocation
+              << "\n");
+    o.writeAt(buffer.pointerLocation, (uint32_t)o.size());
+    for (size_t i = 0; i < buffer.size; i++) {
+      o << (uint8_t)buffer.data[i];
+    }
+  }
+}
+
+// reader
+
+bool WasmBinaryBuilder::hasDWARFSections() {
+  assert(pos == 0);
+  getInt32(); // magic
+  getInt32(); // version
+  bool has = false;
+  while (more()) {
+    uint8_t sectionCode = getInt8();
+    uint32_t payloadLen = getU32LEB();
+    if (uint64_t(pos) + uint64_t(payloadLen) > input.size()) {
+      throwError("Section extends beyond end of input");
+    }
+    auto oldPos = pos;
+    if (sectionCode == BinaryConsts::Section::User) {
+      auto sectionName = getInlineString();
+      if (Debug::isDWARFSection(sectionName)) {
+        has = true;
+        break;
+      }
+    }
+    pos = oldPos + payloadLen;
+  }
+  pos = 0;
+  return has;
+}
+
+void WasmBinaryBuilder::read() {
+  if (DWARF) {
+    // In order to update dwarf, we must store info about each IR node's
+    // binary position. This has noticeable memory overhead, so we don't do it
+    // by default: the user must request it by setting "DWARF", and even if so
+    // we scan ahead to see that there actually *are* DWARF sections, so that
+    // we don't do unnecessary work.
+    if (!hasDWARFSections()) {
+      DWARF = false;
+    }
+  }
+
+  readHeader();
+  readSourceMapHeader();
+
+  // read sections until the end
+  while (more()) {
+    uint8_t sectionCode = getInt8();
+    uint32_t payloadLen = getU32LEB();
+    if (uint64_t(pos) + uint64_t(payloadLen) > input.size()) {
+      throwError("Section extends beyond end of input");
+    }
+
+    auto oldPos = pos;
+
+    // note the section in the list of seen sections, as almost no sections can
+    // appear more than once, and verify those that shouldn't do not.
+    if (sectionCode != BinaryConsts::Section::User &&
+        sectionCode != BinaryConsts::Section::Code) {
+      if (!seenSections.insert(BinaryConsts::Section(sectionCode)).second) {
+        throwError("section seen more than once: " +
+                   std::to_string(sectionCode));
+      }
+    }
+
+    switch (sectionCode) {
+      case BinaryConsts::Section::Start:
+        readStart();
+        break;
+      case BinaryConsts::Section::Memory:
+        readMemory();
+        break;
+      case BinaryConsts::Section::Type:
+        readSignatures();
+        break;
+      case BinaryConsts::Section::Import:
+        readImports();
+        break;
+      case BinaryConsts::Section::Function:
+        readFunctionSignatures();
+        break;
+      case BinaryConsts::Section::Code:
+        if (DWARF) {
+          codeSectionLocation = pos;
+        }
+        readFunctions();
+        break;
+      case BinaryConsts::Section::Export:
+        readExports();
+        break;
+      case BinaryConsts::Section::Element:
+        readTableElements();
+        break;
+      case BinaryConsts::Section::Global:
+        readGlobals();
+        break;
+      case BinaryConsts::Section::Data:
+        readDataSegments();
+        break;
+      case BinaryConsts::Section::DataCount:
+        readDataCount();
+        break;
+      case BinaryConsts::Section::Table:
+        readFunctionTableDeclaration();
+        break;
+      case BinaryConsts::Section::Event:
+        readEvents();
+        break;
+      default: {
+        readUserSection(payloadLen);
+        if (pos > oldPos + payloadLen) {
+          throwError("bad user section size, started at " +
+                     std::to_string(oldPos) + " plus payload " +
+                     std::to_string(payloadLen) +
+                     " not being equal to new position " + std::to_string(pos));
+        }
+        pos = oldPos + payloadLen;
+      }
+    }
+
+    // make sure we advanced exactly past this section
+    if (pos != oldPos + payloadLen) {
+      throwError("bad section size, started at " + std::to_string(oldPos) +
+                 " plus payload " + std::to_string(payloadLen) +
+                 " not being equal to new position " + std::to_string(pos));
+    }
+  }
+
+  validateBinary();
+  processNames();
+}
+
+void WasmBinaryBuilder::readUserSection(size_t payloadLen) {
+  auto oldPos = pos;
+  Name sectionName = getInlineString();
+  size_t read = pos - oldPos;
+  if (read > payloadLen) {
+    throwError("bad user section size");
+  }
+  payloadLen -= read;
+  if (sectionName.equals(BinaryConsts::UserSections::Name)) {
+    readNames(payloadLen);
+  } else if (sectionName.equals(BinaryConsts::UserSections::TargetFeatures)) {
+    readFeatures(payloadLen);
+  } else if (sectionName.equals(BinaryConsts::UserSections::Dylink)) {
+    readDylink(payloadLen);
+  } else {
+    // an unfamiliar custom section
+    if (sectionName.equals(BinaryConsts::UserSections::Linking)) {
+      std::cerr
+        << "warning: linking section is present, so this is not a standard "
+           "wasm file - binaryen cannot handle this properly!\n";
+    }
+    wasm.userSections.resize(wasm.userSections.size() + 1);
+    auto& section = wasm.userSections.back();
+    section.name = sectionName.str;
+    auto sectionSize = payloadLen;
+    section.data.resize(sectionSize);
+    for (size_t i = 0; i < sectionSize; i++) {
+      section.data[i] = getInt8();
+    }
+  }
+}
+
+uint8_t WasmBinaryBuilder::getInt8() {
+  if (!more()) {
+    throwError("unexpected end of input");
+  }
+  BYN_TRACE("getInt8: " << (int)(uint8_t)input[pos] << " (at " << pos << ")\n");
+  return input[pos++];
+}
+
+uint16_t WasmBinaryBuilder::getInt16() {
+  BYN_TRACE("<==\n");
+  auto ret = uint16_t(getInt8());
+  ret |= uint16_t(getInt8()) << 8;
+  BYN_TRACE("getInt16: " << ret << "/0x" << std::hex << ret << std::dec
+                         << " ==>\n");
+  return ret;
+}
+
+uint32_t WasmBinaryBuilder::getInt32() {
+  BYN_TRACE("<==\n");
+  auto ret = uint32_t(getInt16());
+  ret |= uint32_t(getInt16()) << 16;
+  BYN_TRACE("getInt32: " << ret << "/0x" << std::hex << ret << std::dec
+                         << " ==>\n");
+  return ret;
+}
+
+uint64_t WasmBinaryBuilder::getInt64() {
+  BYN_TRACE("<==\n");
+  auto ret = uint64_t(getInt32());
+  ret |= uint64_t(getInt32()) << 32;
+  BYN_TRACE("getInt64: " << ret << "/0x" << std::hex << ret << std::dec
+                         << " ==>\n");
+  return ret;
+}
+
+uint8_t WasmBinaryBuilder::getLaneIndex(size_t lanes) {
+  BYN_TRACE("<==\n");
+  auto ret = getInt8();
+  if (ret >= lanes) {
+    throwError("Illegal lane index");
+  }
+  BYN_TRACE("getLaneIndex(" << lanes << "): " << ret << " ==>" << std::endl);
+  return ret;
+}
+
+Literal WasmBinaryBuilder::getFloat32Literal() {
+  BYN_TRACE("<==\n");
+  auto ret = Literal(getInt32());
+  ret = ret.castToF32();
+  BYN_TRACE("getFloat32: " << ret << " ==>\n");
+  return ret;
+}
+
+Literal WasmBinaryBuilder::getFloat64Literal() {
+  BYN_TRACE("<==\n");
+  auto ret = Literal(getInt64());
+  ret = ret.castToF64();
+  BYN_TRACE("getFloat64: " << ret << " ==>\n");
+  return ret;
+}
+
+Literal WasmBinaryBuilder::getVec128Literal() {
+  BYN_TRACE("<==\n");
+  std::array<uint8_t, 16> bytes;
+  for (auto i = 0; i < 16; ++i) {
+    bytes[i] = getInt8();
+  }
+  auto ret = Literal(bytes.data());
+  BYN_TRACE("getVec128: " << ret << " ==>\n");
+  return ret;
+}
+
+uint32_t WasmBinaryBuilder::getU32LEB() {
+  BYN_TRACE("<==\n");
+  U32LEB ret;
+  ret.read([&]() { return getInt8(); });
+  BYN_TRACE("getU32LEB: " << ret.value << " ==>\n");
+  return ret.value;
+}
+
+uint64_t WasmBinaryBuilder::getU64LEB() {
+  BYN_TRACE("<==\n");
+  U64LEB ret;
+  ret.read([&]() { return getInt8(); });
+  BYN_TRACE("getU64LEB: " << ret.value << " ==>\n");
+  return ret.value;
+}
+
+int32_t WasmBinaryBuilder::getS32LEB() {
+  BYN_TRACE("<==\n");
+  S32LEB ret;
+  ret.read([&]() { return (int8_t)getInt8(); });
+  BYN_TRACE("getS32LEB: " << ret.value << " ==>\n");
+  return ret.value;
+}
+
+int64_t WasmBinaryBuilder::getS64LEB() {
+  BYN_TRACE("<==\n");
+  S64LEB ret;
+  ret.read([&]() { return (int8_t)getInt8(); });
+  BYN_TRACE("getS64LEB: " << ret.value << " ==>\n");
+  return ret.value;
+}
+
+Type WasmBinaryBuilder::getType() {
+  int type = getS32LEB();
+  // 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;
+  }
+  switch (type) {
+    // None only used for block signatures. TODO: Separate out?
+    case BinaryConsts::EncodedType::Empty:
+      return Type::none;
+    case BinaryConsts::EncodedType::i32:
+      return Type::i32;
+    case BinaryConsts::EncodedType::i64:
+      return Type::i64;
+    case BinaryConsts::EncodedType::f32:
+      return Type::f32;
+    case BinaryConsts::EncodedType::f64:
+      return Type::f64;
+    case BinaryConsts::EncodedType::v128:
+      return Type::v128;
+    case BinaryConsts::EncodedType::funcref:
+      return Type::funcref;
+    case BinaryConsts::EncodedType::externref:
+      return Type::externref;
+    case BinaryConsts::EncodedType::exnref:
+      return Type::exnref;
+    case BinaryConsts::EncodedType::anyref:
+      return Type::anyref;
+    case BinaryConsts::EncodedType::eqref:
+      return Type::eqref;
+    case BinaryConsts::EncodedType::i31ref:
+      return Type::i31ref;
+    default:
+      throwError("invalid wasm type: " + std::to_string(type));
+  }
+  WASM_UNREACHABLE("unexpected type");
+}
+
+HeapType WasmBinaryBuilder::getHeapType() {
+  int type = getS32LEB(); // TODO: Actually encoded as s33
+  // Single heap types are negative; heap type indices are non-negative
+  if (type >= 0) {
+    if (size_t(type) >= signatures.size()) {
+      throwError("invalid signature index: " + std::to_string(type));
+    }
+    return HeapType(signatures[type]);
+  }
+  switch (type) {
+    case BinaryConsts::EncodedHeapType::func:
+      return HeapType::FuncKind;
+    case BinaryConsts::EncodedHeapType::extern_:
+      return HeapType::ExternKind;
+    case BinaryConsts::EncodedHeapType::exn:
+      return HeapType::ExnKind;
+    case BinaryConsts::EncodedHeapType::any:
+      return HeapType::AnyKind;
+    case BinaryConsts::EncodedHeapType::eq:
+      return HeapType::EqKind;
+    case BinaryConsts::EncodedHeapType::i31:
+      return HeapType::I31Kind;
+    default:
+      throwError("invalid wasm heap type: " + std::to_string(type));
+  }
+  WASM_UNREACHABLE("unexpected type");
+}
+
+Type WasmBinaryBuilder::getConcreteType() {
+  auto type = getType();
+  if (!type.isConcrete()) {
+    throw ParseException("non-concrete type when one expected");
+  }
+  return type;
+}
+
+Name WasmBinaryBuilder::getInlineString() {
+  BYN_TRACE("<==\n");
+  auto len = getU32LEB();
+  std::string str;
+  for (size_t i = 0; i < len; i++) {
+    auto curr = char(getInt8());
+    if (curr == 0) {
+      throwError(
+        "inline string contains NULL (0). that is technically valid in wasm, "
+        "but you shouldn't do it, and it's not supported in binaryen");
+    }
+    str = str + curr;
+  }
+  BYN_TRACE("getInlineString: " << str << " ==>\n");
+  return Name(str);
+}
+
+void WasmBinaryBuilder::verifyInt8(int8_t x) {
+  int8_t y = getInt8();
+  if (x != y) {
+    throwError("surprising value");
+  }
+}
+
+void WasmBinaryBuilder::verifyInt16(int16_t x) {
+  int16_t y = getInt16();
+  if (x != y) {
+    throwError("surprising value");
+  }
+}
+
+void WasmBinaryBuilder::verifyInt32(int32_t x) {
+  int32_t y = getInt32();
+  if (x != y) {
+    throwError("surprising value");
+  }
+}
+
+void WasmBinaryBuilder::verifyInt64(int64_t x) {
+  int64_t y = getInt64();
+  if (x != y) {
+    throwError("surprising value");
+  }
+}
+
+void WasmBinaryBuilder::ungetInt8() {
+  assert(pos > 0);
+  BYN_TRACE("ungetInt8 (at " << pos << ")\n");
+  pos--;
+}
+
+void WasmBinaryBuilder::readHeader() {
+  BYN_TRACE("== readHeader\n");
+  verifyInt32(BinaryConsts::Magic);
+  verifyInt32(BinaryConsts::Version);
+}
+
+void WasmBinaryBuilder::readStart() {
+  BYN_TRACE("== readStart\n");
+  startIndex = getU32LEB();
+}
+
+void WasmBinaryBuilder::readMemory() {
+  BYN_TRACE("== readMemory\n");
+  auto numMemories = getU32LEB();
+  if (!numMemories) {
+    return;
+  }
+  if (numMemories != 1) {
+    throwError("Must be exactly 1 memory");
+  }
+  if (wasm.memory.exists) {
+    throwError("Memory cannot be both imported and defined");
+  }
+  wasm.memory.exists = true;
+  getResizableLimits(wasm.memory.initial,
+                     wasm.memory.max,
+                     wasm.memory.shared,
+                     wasm.memory.indexType,
+                     Memory::kUnlimitedSize);
+}
+
+void WasmBinaryBuilder::readSignatures() {
+  BYN_TRACE("== readSignatures\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());
+    }
+    signatures.emplace_back(Type(params), Type(results));
+  }
+}
+
+Name WasmBinaryBuilder::getFunctionName(Index index) {
+  if (index >= wasm.functions.size()) {
+    throwError("invalid function index");
+  }
+  return wasm.functions[index]->name;
+}
+
+Name WasmBinaryBuilder::getGlobalName(Index index) {
+  if (index >= wasm.globals.size()) {
+    throwError("invalid global index");
+  }
+  return wasm.globals[index]->name;
+}
+
+Name WasmBinaryBuilder::getEventName(Index index) {
+  if (index >= wasm.events.size()) {
+    throwError("invalid event index");
+  }
+  return wasm.events[index]->name;
+}
+
+void WasmBinaryBuilder::getResizableLimits(Address& initial,
+                                           Address& max,
+                                           bool& shared,
+                                           Type& indexType,
+                                           Address defaultIfNoMax) {
+  auto flags = getU32LEB();
+  initial = getU32LEB();
+  bool hasMax = (flags & BinaryConsts::HasMaximum) != 0;
+  bool isShared = (flags & BinaryConsts::IsShared) != 0;
+  bool is64 = (flags & BinaryConsts::Is64) != 0;
+  if (isShared && !hasMax) {
+    throwError("shared memory must have max size");
+  }
+  shared = isShared;
+  indexType = is64 ? Type::i64 : Type::i32;
+  if (hasMax) {
+    max = getU32LEB();
+  } else {
+    max = defaultIfNoMax;
+  }
+}
+
+void WasmBinaryBuilder::readImports() {
+  BYN_TRACE("== readImports\n");
+  size_t num = getU32LEB();
+  BYN_TRACE("num: " << num << std::endl);
+  Builder builder(wasm);
+  for (size_t i = 0; i < num; i++) {
+    BYN_TRACE("read one\n");
+    auto module = getInlineString();
+    auto base = getInlineString();
+    auto kind = (ExternalKind)getU32LEB();
+    // We set a unique prefix for the name based on the kind. This ensures no
+    // collisions between them, which can't occur here (due to the index i) but
+    // could occur later due to the names section.
+    switch (kind) {
+      case ExternalKind::Function: {
+        auto name = Name(std::string("fimport$") + std::to_string(i));
+        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], {});
+        curr->module = module;
+        curr->base = base;
+        wasm.addFunction(curr);
+        functionImports.push_back(curr);
+        break;
+      }
+      case ExternalKind::Table: {
+        wasm.table.module = module;
+        wasm.table.base = base;
+        wasm.table.name = Name(std::string("timport$") + std::to_string(i));
+        auto elementType = getS32LEB();
+        WASM_UNUSED(elementType);
+        if (elementType != BinaryConsts::EncodedType::funcref) {
+          throwError("Imported table type is not funcref");
+        }
+        wasm.table.exists = true;
+        bool is_shared;
+        Type indexType;
+        getResizableLimits(wasm.table.initial,
+                           wasm.table.max,
+                           is_shared,
+                           indexType,
+                           Table::kUnlimitedSize);
+        if (is_shared) {
+          throwError("Tables may not be shared");
+        }
+        if (indexType == Type::i64) {
+          throwError("Tables may not be 64-bit");
+        }
+        break;
+      }
+      case ExternalKind::Memory: {
+        wasm.memory.module = module;
+        wasm.memory.base = base;
+        wasm.memory.name = Name(std::string("mimport$") + std::to_string(i));
+        wasm.memory.exists = true;
+        getResizableLimits(wasm.memory.initial,
+                           wasm.memory.max,
+                           wasm.memory.shared,
+                           wasm.memory.indexType,
+                           Memory::kUnlimitedSize);
+        break;
+      }
+      case ExternalKind::Global: {
+        auto name = Name(std::string("gimport$") + std::to_string(i));
+        auto type = getConcreteType();
+        auto mutable_ = getU32LEB();
+        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);
+        break;
+      }
+      case ExternalKind::Event: {
+        auto name = Name(std::string("eimport$") + std::to_string(i));
+        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]);
+        curr->module = module;
+        curr->base = base;
+        wasm.addEvent(curr);
+        break;
+      }
+      default: {
+        throwError("bad import kind");
+      }
+    }
+  }
+}
+
+Name WasmBinaryBuilder::getNextLabel() {
+  requireFunctionContext("getting a label");
+  return Name("label$" + std::to_string(nextLabel++));
+}
+
+void WasmBinaryBuilder::requireFunctionContext(const char* error) {
+  if (!currFunction) {
+    throwError(std::string("in a non-function context: ") + error);
+  }
+}
+
+void WasmBinaryBuilder::readFunctionSignatures() {
+  BYN_TRACE("== readFunctionSignatures\n");
+  size_t num = getU32LEB();
+  BYN_TRACE("num: " << num << std::endl);
+  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]);
+  }
+}
+
+void WasmBinaryBuilder::readFunctions() {
+  BYN_TRACE("== readFunctions\n");
+  size_t total = getU32LEB();
+  if (total != functionSignatures.size()) {
+    throwError("invalid function section size, must equal types");
+  }
+  for (size_t i = 0; i < total; i++) {
+    BYN_TRACE("read one at " << pos << std::endl);
+    auto sizePos = pos;
+    size_t size = getU32LEB();
+    if (size == 0) {
+      throwError("empty function size");
+    }
+    endOfFunction = pos + size;
+
+    auto* func = new Function;
+    func->name = Name::fromInt(i);
+    func->sig = functionSignatures[i];
+    currFunction = func;
+
+    if (DWARF) {
+      func->funcLocation = BinaryLocations::FunctionLocations{
+        BinaryLocation(sizePos - codeSectionLocation),
+        BinaryLocation(pos - codeSectionLocation),
+        BinaryLocation(pos - codeSectionLocation + size)};
+    }
+
+    readNextDebugLocation();
+
+    BYN_TRACE("reading " << i << std::endl);
+    size_t numLocalTypes = getU32LEB();
+    for (size_t t = 0; t < numLocalTypes; t++) {
+      auto num = getU32LEB();
+      auto type = getConcreteType();
+      while (num > 0) {
+        func->vars.push_back(type);
+        num--;
+      }
+    }
+    std::swap(func->prologLocation, debugLocation);
+    {
+      // process the function body
+      BYN_TRACE("processing function: " << i << std::endl);
+      nextLabel = 0;
+      debugLocation.clear();
+      willBeIgnored = false;
+      // process body
+      assert(breakTargetNames.size() == 0);
+      assert(breakStack.empty());
+      assert(expressionStack.empty());
+      assert(controlFlowStack.empty());
+      assert(depth == 0);
+      func->body = getBlockOrSingleton(func->sig.results);
+      assert(depth == 0);
+      assert(breakStack.size() == 0);
+      assert(breakTargetNames.size() == 0);
+      if (!expressionStack.empty()) {
+        throwError("stack not empty on function exit");
+      }
+      assert(controlFlowStack.empty());
+      if (pos != endOfFunction) {
+        throwError("binary offset at function exit not at expected location");
+      }
+    }
+    std::swap(func->epilogLocation, debugLocation);
+    currFunction = nullptr;
+    debugLocation.clear();
+    functions.push_back(func);
+  }
+  BYN_TRACE(" end function bodies\n");
+}
+
+void WasmBinaryBuilder::readExports() {
+  BYN_TRACE("== readExports\n");
+  size_t num = getU32LEB();
+  BYN_TRACE("num: " << num << std::endl);
+  std::set<Name> names;
+  for (size_t i = 0; i < num; i++) {
+    BYN_TRACE("read one\n");
+    auto curr = new Export;
+    curr->name = getInlineString();
+    if (names.count(curr->name) > 0) {
+      throwError("duplicate export name");
+    }
+    names.insert(curr->name);
+    curr->kind = (ExternalKind)getU32LEB();
+    auto index = getU32LEB();
+    exportIndices[curr] = index;
+    exportOrder.push_back(curr);
+  }
+}
+
+static int32_t readBase64VLQ(std::istream& in) {
+  uint32_t value = 0;
+  uint32_t shift = 0;
+  while (1) {
+    auto ch = in.get();
+    if (ch == EOF) {
+      throw MapParseException("unexpected EOF in the middle of VLQ");
+    }
+    if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch < 'g')) {
+      // last number digit
+      uint32_t digit = ch < 'a' ? ch - 'A' : ch - 'a' + 26;
+      value |= digit << shift;
+      break;
+    }
+    if (!(ch >= 'g' && ch <= 'z') && !(ch >= '0' && ch <= '9') && ch != '+' &&
+        ch != '/') {
+      throw MapParseException("invalid VLQ digit");
+    }
+    uint32_t digit =
+      ch > '9' ? ch - 'g' : (ch >= '0' ? ch - '0' + 20 : (ch == '+' ? 30 : 31));
+    value |= digit << shift;
+    shift += 5;
+  }
+  return value & 1 ? -int32_t(value >> 1) : int32_t(value >> 1);
+}
+
+void WasmBinaryBuilder::readSourceMapHeader() {
+  if (!sourceMap) {
+    return;
+  }
+
+  auto skipWhitespace = [&]() {
+    while (sourceMap->peek() == ' ' || sourceMap->peek() == '\n') {
+      sourceMap->get();
+    }
+  };
+
+  auto maybeReadChar = [&](char expected) {
+    if (sourceMap->peek() != expected) {
+      return false;
+    }
+    sourceMap->get();
+    return true;
+  };
+
+  auto mustReadChar = [&](char expected) {
+    char c = sourceMap->get();
+    if (c != expected) {
+      throw MapParseException(std::string("Unexpected char: expected '") +
+                              expected + "' got '" + c + "'");
+    }
+  };
+
+  auto findField = [&](const char* name) {
+    bool matching = false;
+    size_t len = strlen(name);
+    size_t pos;
+    while (1) {
+      int ch = sourceMap->get();
+      if (ch == EOF) {
+        return false;
+      }
+      if (ch == '\"') {
+        if (matching) {
+          // we matched a terminating quote.
+          if (pos == len) {
+            break;
+          }
+          matching = false;
+        } else {
+          matching = true;
+          pos = 0;
+        }
+      } else if (matching && name[pos] == ch) {
+        ++pos;
+      } else if (matching) {
+        matching = false;
+      }
+    }
+    skipWhitespace();
+    mustReadChar(':');
+    skipWhitespace();
+    return true;
+  };
+
+  auto readString = [&](std::string& str) {
+    std::vector<char> vec;
+    skipWhitespace();
+    mustReadChar('\"');
+    if (!maybeReadChar('\"')) {
+      while (1) {
+        int ch = sourceMap->get();
+        if (ch == EOF) {
+          throw MapParseException("unexpected EOF in the middle of string");
+        }
+        if (ch == '\"') {
+          break;
+        }
+        vec.push_back(ch);
+      }
+    }
+    skipWhitespace();
+    str = std::string(vec.begin(), vec.end());
+  };
+
+  if (!findField("sources")) {
+    throw MapParseException("cannot find the 'sources' field in map");
+  }
+
+  skipWhitespace();
+  mustReadChar('[');
+  if (!maybeReadChar(']')) {
+    do {
+      std::string file;
+      readString(file);
+      Index index = wasm.debugInfoFileNames.size();
+      wasm.debugInfoFileNames.push_back(file);
+      debugInfoFileIndices[file] = index;
+    } while (maybeReadChar(','));
+    mustReadChar(']');
+  }
+
+  if (!findField("mappings")) {
+    throw MapParseException("cannot find the 'mappings' field in map");
+  }
+
+  mustReadChar('\"');
+  if (maybeReadChar('\"')) { // empty mappings
+    nextDebugLocation.first = 0;
+    return;
+  }
+  // read first debug location
+  uint32_t position = readBase64VLQ(*sourceMap);
+  uint32_t fileIndex = readBase64VLQ(*sourceMap);
+  uint32_t lineNumber =
+    readBase64VLQ(*sourceMap) + 1; // adjust zero-based line number
+  uint32_t columnNumber = readBase64VLQ(*sourceMap);
+  nextDebugLocation = {position, {fileIndex, lineNumber, columnNumber}};
+}
+
+void WasmBinaryBuilder::readNextDebugLocation() {
+  if (!sourceMap) {
+    return;
+  }
+
+  while (nextDebugLocation.first && nextDebugLocation.first <= pos) {
+    debugLocation.clear();
+    // use debugLocation only for function expressions
+    if (currFunction) {
+      debugLocation.insert(nextDebugLocation.second);
+    }
+
+    char ch;
+    *sourceMap >> ch;
+    if (ch == '\"') { // end of records
+      nextDebugLocation.first = 0;
+      break;
+    }
+    if (ch != ',') {
+      throw MapParseException("Unexpected delimiter");
+    }
+
+    int32_t positionDelta = readBase64VLQ(*sourceMap);
+    uint32_t position = nextDebugLocation.first + positionDelta;
+    int32_t fileIndexDelta = readBase64VLQ(*sourceMap);
+    uint32_t fileIndex = nextDebugLocation.second.fileIndex + fileIndexDelta;
+    int32_t lineNumberDelta = readBase64VLQ(*sourceMap);
+    uint32_t lineNumber = nextDebugLocation.second.lineNumber + lineNumberDelta;
+    int32_t columnNumberDelta = readBase64VLQ(*sourceMap);
+    uint32_t columnNumber =
+      nextDebugLocation.second.columnNumber + columnNumberDelta;
+
+    nextDebugLocation = {position, {fileIndex, lineNumber, columnNumber}};
+  }
+}
+
+Expression* WasmBinaryBuilder::readExpression() {
+  assert(depth == 0);
+  processExpressions();
+  if (expressionStack.size() != 1) {
+    throwError("expected to read a single expression");
+  }
+  auto* ret = popExpression();
+  assert(depth == 0);
+  return ret;
+}
+
+void WasmBinaryBuilder::readGlobals() {
+  BYN_TRACE("== readGlobals\n");
+  size_t num = getU32LEB();
+  BYN_TRACE("num: " << num << std::endl);
+  for (size_t i = 0; i < num; i++) {
+    BYN_TRACE("read one\n");
+    auto type = getConcreteType();
+    auto mutable_ = getU32LEB();
+    if (mutable_ & ~1) {
+      throwError("Global mutability must be 0 or 1");
+    }
+    auto* init = readExpression();
+    globals.push_back(
+      Builder::makeGlobal("global$" + std::to_string(i),
+                          type,
+                          init,
+                          mutable_ ? Builder::Mutable : Builder::Immutable));
+  }
+}
+
+void WasmBinaryBuilder::processExpressions() {
+  BYN_TRACE("== processExpressions\n");
+  unreachableInTheWasmSense = false;
+  while (1) {
+    Expression* curr;
+    auto ret = readExpression(curr);
+    if (!curr) {
+      lastSeparator = ret;
+      BYN_TRACE("== processExpressions finished\n");
+      return;
+    }
+    pushExpression(curr);
+    if (curr->type == Type::unreachable) {
+      // Once we see something unreachable, we don't want to add anything else
+      // to the stack, as it could be stacky code that is non-representable in
+      // our AST. but we do need to skip it.
+      // If there is nothing else here, just stop. Otherwise, go into
+      // unreachable mode. peek to see what to do.
+      if (pos == endOfFunction) {
+        throwError("Reached function end without seeing End opcode");
+      }
+      if (!more()) {
+        throwError("unexpected end of input");
+      }
+      auto peek = input[pos];
+      if (peek == BinaryConsts::End || peek == BinaryConsts::Else ||
+          peek == BinaryConsts::Catch) {
+        BYN_TRACE("== processExpressions finished with unreachable"
+                  << std::endl);
+        lastSeparator = BinaryConsts::ASTNodes(peek);
+        // Read the byte we peeked at. No new instruction is generated for it.
+        Expression* dummy = nullptr;
+        readExpression(dummy);
+        assert(!dummy);
+        return;
+      } else {
+        skipUnreachableCode();
+        return;
+      }
+    }
+  }
+}
+
+void WasmBinaryBuilder::skipUnreachableCode() {
+  BYN_TRACE("== skipUnreachableCode\n");
+  // preserve the stack, and restore it. it contains the instruction that made
+  // us unreachable, and we can ignore anything after it. things after it may
+  // pop, we want to undo that
+  auto savedStack = expressionStack;
+  // note we are entering unreachable code, and note what the state as before so
+  // we can restore it
+  auto before = willBeIgnored;
+  willBeIgnored = true;
+  // clear the stack. nothing should be popped from there anyhow, just stuff
+  // can be pushed and then popped. Popping past the top of the stack will
+  // result in uneachables being returned
+  expressionStack.clear();
+  while (1) {
+    // set the unreachableInTheWasmSense flag each time, as sub-blocks may set
+    // and unset it
+    unreachableInTheWasmSense = true;
+    Expression* curr;
+    auto ret = readExpression(curr);
+    if (!curr) {
+      BYN_TRACE("== skipUnreachableCode finished\n");
+      lastSeparator = ret;
+      unreachableInTheWasmSense = false;
+      willBeIgnored = before;
+      expressionStack = savedStack;
+      return;
+    }
+    pushExpression(curr);
+  }
+}
+
+void WasmBinaryBuilder::pushExpression(Expression* curr) {
+  if (curr->type.isTuple()) {
+    // Store tuple to local and push individual extracted values
+    Builder builder(wasm);
+    Index tuple = builder.addVar(currFunction, curr->type);
+    expressionStack.push_back(builder.makeLocalSet(tuple, curr));
+    for (Index i = 0; i < curr->type.size(); ++i) {
+      expressionStack.push_back(
+        builder.makeTupleExtract(builder.makeLocalGet(tuple, curr->type), i));
+    }
+  } else {
+    expressionStack.push_back(curr);
+  }
+}
+
+Expression* WasmBinaryBuilder::popExpression() {
+  BYN_TRACE("== popExpression\n");
+  if (expressionStack.empty()) {
+    if (unreachableInTheWasmSense) {
+      // in unreachable code, trying to pop past the polymorphic stack
+      // area results in receiving unreachables
+      BYN_TRACE("== popping unreachable from polymorphic stack" << std::endl);
+      return allocator.alloc<Unreachable>();
+    }
+    throwError(
+      "attempted pop from empty stack / beyond block start boundary at " +
+      std::to_string(pos));
+  }
+  // the stack is not empty, and we would not be going out of the current block
+  auto ret = expressionStack.back();
+  assert(!ret->type.isTuple());
+  expressionStack.pop_back();
+  return ret;
+}
+
+Expression* WasmBinaryBuilder::popNonVoidExpression() {
+  auto* ret = popExpression();
+  if (ret->type != Type::none) {
+    return ret;
+  }
+  // we found a void, so this is stacky code that we must handle carefully
+  Builder builder(wasm);
+  // add elements until we find a non-void
+  std::vector<Expression*> expressions;
+  expressions.push_back(ret);
+  while (1) {
+    auto* curr = popExpression();
+    expressions.push_back(curr);
+    if (curr->type != Type::none) {
+      break;
+    }
+  }
+  auto* block = builder.makeBlock();
+  while (!expressions.empty()) {
+    block->list.push_back(expressions.back());
+    expressions.pop_back();
+  }
+  requireFunctionContext("popping void where we need a new local");
+  auto type = block->list[0]->type;
+  if (type.isConcrete()) {
+    auto local = builder.addVar(currFunction, type);
+    block->list[0] = builder.makeLocalSet(local, block->list[0]);
+    block->list.push_back(builder.makeLocalGet(local, type));
+  } else {
+    assert(type == Type::unreachable);
+    // nothing to do here - unreachable anyhow
+  }
+  block->finalize();
+  return block;
+}
+
+Expression* WasmBinaryBuilder::popTuple(size_t numElems) {
+  Builder builder(wasm);
+  std::vector<Expression*> elements;
+  elements.resize(numElems);
+  for (size_t i = 0; i < numElems; i++) {
+    auto* elem = popNonVoidExpression();
+    if (elem->type == Type::unreachable) {
+      // All the previously-popped items cannot be reached, so ignore them. We
+      // cannot continue popping because there might not be enough items on the
+      // expression stack after an unreachable expression. Any remaining
+      // elements can stay unperturbed on the stack and will be explicitly
+      // dropped by some parent call to pushBlockElements.
+      return elem;
+    }
+    elements[numElems - i - 1] = elem;
+  }
+  return Builder(wasm).makeTupleMake(std::move(elements));
+}
+
+Expression* WasmBinaryBuilder::popTypedExpression(Type type) {
+  if (type.isSingle()) {
+    return popNonVoidExpression();
+  } else if (type.isTuple()) {
+    return popTuple(type.size());
+  } else {
+    WASM_UNREACHABLE("Invalid popped type");
+  }
+}
+
+void WasmBinaryBuilder::validateBinary() {
+  if (hasDataCount && wasm.memory.segments.size() != dataCount) {
+    throwError("Number of segments does not agree with DataCount section");
+  }
+}
+
+void WasmBinaryBuilder::processNames() {
+  for (auto* func : functions) {
+    wasm.addFunction(func);
+  }
+  for (auto* global : globals) {
+    wasm.addGlobal(global);
+  }
+
+  // now that we have names, apply things
+
+  if (startIndex != static_cast<Index>(-1)) {
+    wasm.start = getFunctionName(startIndex);
+  }
+
+  for (auto* curr : exportOrder) {
+    auto index = exportIndices[curr];
+    switch (curr->kind) {
+      case ExternalKind::Function: {
+        curr->value = getFunctionName(index);
+        break;
+      }
+      case ExternalKind::Table:
+        curr->value = wasm.table.name;
+        break;
+      case ExternalKind::Memory:
+        curr->value = wasm.memory.name;
+        break;
+      case ExternalKind::Global:
+        curr->value = getGlobalName(index);
+        break;
+      case ExternalKind::Event:
+        curr->value = getEventName(index);
+        break;
+      default:
+        throwError("bad export kind");
+    }
+    wasm.addExport(curr);
+  }
+
+  for (auto& iter : functionRefs) {
+    size_t index = iter.first;
+    auto& refs = iter.second;
+    for (auto* ref : refs) {
+      if (auto* call = ref->dynCast<Call>()) {
+        call->target = getFunctionName(index);
+      } else if (auto* refFunc = ref->dynCast<RefFunc>()) {
+        refFunc->func = getFunctionName(index);
+      } else {
+        WASM_UNREACHABLE("Invalid type in function references");
+      }
+    }
+  }
+
+  for (auto& pair : functionTable) {
+    auto i = pair.first;
+    auto& indices = pair.second;
+    for (auto j : indices) {
+      wasm.table.segments[i].data.push_back(getFunctionName(j));
+    }
+  }
+
+  for (auto& iter : globalRefs) {
+    size_t index = iter.first;
+    auto& refs = iter.second;
+    for (auto* ref : refs) {
+      if (auto* get = ref->dynCast<GlobalGet>()) {
+        get->name = getGlobalName(index);
+      } else if (auto* set = ref->dynCast<GlobalSet>()) {
+        set->name = getGlobalName(index);
+      } else {
+        WASM_UNREACHABLE("Invalid type in global references");
+      }
+    }
+  }
+
+  // Everything now has its proper name.
+
+  wasm.updateMaps();
+}
+
+void WasmBinaryBuilder::readDataCount() {
+  BYN_TRACE("== readDataCount\n");
+  hasDataCount = true;
+  dataCount = getU32LEB();
+}
+
+void WasmBinaryBuilder::readDataSegments() {
+  BYN_TRACE("== readDataSegments\n");
+  auto num = getU32LEB();
+  for (size_t i = 0; i < num; i++) {
+    Memory::Segment curr;
+    uint32_t flags = getU32LEB();
+    if (flags > 2) {
+      throwError("bad segment flags, must be 0, 1, or 2, not " +
+                 std::to_string(flags));
+    }
+    curr.isPassive = flags & BinaryConsts::IsPassive;
+    if (flags & BinaryConsts::HasMemIndex) {
+      auto memIndex = getU32LEB();
+      if (memIndex != 0) {
+        throwError("nonzero memory index");
+      }
+    }
+    if (!curr.isPassive) {
+      curr.offset = readExpression();
+    }
+    auto size = getU32LEB();
+    curr.data.resize(size);
+    for (size_t j = 0; j < size; j++) {
+      curr.data[j] = char(getInt8());
+    }
+    wasm.memory.segments.push_back(curr);
+  }
+}
+
+void WasmBinaryBuilder::readFunctionTableDeclaration() {
+  BYN_TRACE("== readFunctionTableDeclaration\n");
+  auto numTables = getU32LEB();
+  if (numTables != 1) {
+    throwError("Only 1 table definition allowed in MVP");
+  }
+  if (wasm.table.exists) {
+    throwError("Table cannot be both imported and defined");
+  }
+  wasm.table.exists = true;
+  auto elemType = getS32LEB();
+  if (elemType != BinaryConsts::EncodedType::funcref) {
+    throwError("ElementType must be funcref in MVP");
+  }
+  bool is_shared;
+  Type indexType;
+  getResizableLimits(wasm.table.initial,
+                     wasm.table.max,
+                     is_shared,
+                     indexType,
+                     Table::kUnlimitedSize);
+  if (is_shared) {
+    throwError("Tables may not be shared");
+  }
+  if (indexType == Type::i64) {
+    throwError("Tables may not be 64-bit");
+  }
+}
+
+void WasmBinaryBuilder::readTableElements() {
+  BYN_TRACE("== readTableElements\n");
+  auto numSegments = getU32LEB();
+  if (numSegments >= Table::kMaxSize) {
+    throwError("Too many segments");
+  }
+  for (size_t i = 0; i < numSegments; i++) {
+    auto tableIndex = getU32LEB();
+    if (tableIndex != 0) {
+      throwError("Table elements must refer to table 0 in MVP");
+    }
+    wasm.table.segments.emplace_back(readExpression());
+
+    auto& indexSegment = functionTable[i];
+    auto size = getU32LEB();
+    for (Index j = 0; j < size; j++) {
+      indexSegment.push_back(getU32LEB());
+    }
+  }
+}
+
+void WasmBinaryBuilder::readEvents() {
+  BYN_TRACE("== readEvents\n");
+  size_t numEvents = getU32LEB();
+  BYN_TRACE("num: " << numEvents << std::endl);
+  for (size_t i = 0; i < numEvents; i++) {
+    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]));
+  }
+}
+
+static bool isIdChar(char ch) {
+  return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') ||
+         (ch >= 'a' && ch <= 'z') || ch == '!' || ch == '#' || ch == '$' ||
+         ch == '%' || ch == '&' || ch == '\'' || ch == '*' || ch == '+' ||
+         ch == '-' || ch == '.' || ch == '/' || ch == ':' || ch == '<' ||
+         ch == '=' || ch == '>' || ch == '?' || ch == '@' || ch == '^' ||
+         ch == '_' || ch == '`' || ch == '|' || ch == '~';
+}
+
+static char formatNibble(int nibble) {
+  return nibble < 10 ? '0' + nibble : 'a' - 10 + nibble;
+}
+
+Name WasmBinaryBuilder::escape(Name name) {
+  bool allIdChars = true;
+  for (const char* p = name.str; allIdChars && *p; p++) {
+    allIdChars = isIdChar(*p);
+  }
+  if (allIdChars) {
+    return name;
+  }
+  // encode name, if at least one non-idchar (per WebAssembly spec) was found
+  std::string escaped;
+  for (const char* p = name.str; *p; p++) {
+    char ch = *p;
+    if (isIdChar(ch)) {
+      escaped.push_back(ch);
+      continue;
+    }
+    // replace non-idchar with `\xx` escape
+    escaped.push_back('\\');
+    escaped.push_back(formatNibble(ch >> 4));
+    escaped.push_back(formatNibble(ch & 15));
+  }
+  return escaped;
+}
+
+void WasmBinaryBuilder::readNames(size_t payloadLen) {
+  BYN_TRACE("== readNames\n");
+  auto sectionPos = pos;
+  while (pos < sectionPos + payloadLen) {
+    auto nameType = getU32LEB();
+    auto subsectionSize = getU32LEB();
+    auto subsectionPos = pos;
+    if (nameType == BinaryConsts::UserSections::Subsection::NameModule) {
+      wasm.name = getInlineString();
+    } else if (nameType ==
+               BinaryConsts::UserSections::Subsection::NameFunction) {
+      auto num = getU32LEB();
+      std::set<Name> usedNames;
+      for (size_t i = 0; i < num; i++) {
+        auto index = getU32LEB();
+        auto rawName = getInlineString();
+        auto name = escape(rawName);
+        // De-duplicate names by appending .1, .2, etc.
+        for (int i = 1; !usedNames.insert(name).second; ++i) {
+          name = std::string(escape(rawName).str) + std::string(".") +
+                 std::to_string(i);
+        }
+        auto numFunctionImports = functionImports.size();
+        if (index < numFunctionImports) {
+          functionImports[index]->name = name;
+        } else if (index - numFunctionImports < functions.size()) {
+          functions[index - numFunctionImports]->name = name;
+        } else {
+          std::cerr << "warning: function index out of bounds in name section, "
+                       "function subsection: "
+                    << std::string(rawName.str) << " at index "
+                    << std::to_string(index) << std::endl;
+        }
+      }
+    } else if (nameType == BinaryConsts::UserSections::Subsection::NameLocal) {
+      auto numFuncs = getU32LEB();
+      auto numFunctionImports = functionImports.size();
+      for (size_t i = 0; i < numFuncs; i++) {
+        auto funcIndex = getU32LEB();
+        Function* func = nullptr;
+        if (funcIndex < numFunctionImports) {
+          func = functionImports[funcIndex];
+        } else if (funcIndex - numFunctionImports < functions.size()) {
+          func = functions[funcIndex - numFunctionImports];
+        } else {
+          std::cerr
+            << "warning: function index out of bounds in name section, local "
+               "subsection: "
+            << std::to_string(funcIndex) << std::endl;
+        }
+        auto numLocals = getU32LEB();
+        std::set<Name> usedNames;
+        for (size_t j = 0; j < numLocals; j++) {
+          auto localIndex = getU32LEB();
+          auto rawLocalName = getInlineString();
+          if (!func) {
+            continue; // read and discard in case of prior error
+          }
+          auto localName = escape(rawLocalName);
+          // De-duplicate names by appending .1, .2, etc.
+          for (int i = 1; !usedNames.insert(localName).second; ++i) {
+            localName = std::string(escape(rawLocalName).str) +
+                        std::string(".") + std::to_string(i);
+          }
+          if (localIndex < func->getNumLocals()) {
+            func->localNames[localIndex] = localName;
+          } else {
+            std::cerr << "warning: local index out of bounds in name "
+                         "section, local subsection: "
+                      << std::string(rawLocalName.str) << " at index "
+                      << std::to_string(localIndex) << " in function "
+                      << std::string(func->name.str) << std::endl;
+          }
+        }
+      }
+    } else if (nameType == BinaryConsts::UserSections::Subsection::NameTable) {
+      auto num = getU32LEB();
+      for (size_t i = 0; i < num; i++) {
+        auto index = getU32LEB();
+        auto rawName = getInlineString();
+        if (index == 0) {
+          wasm.table.name = escape(rawName);
+        } else {
+          std::cerr << "warning: table index out of bounds in name section, "
+                       "table subsection: "
+                    << std::string(rawName.str) << " at index "
+                    << std::to_string(index) << std::endl;
+        }
+      }
+    } else if (nameType == BinaryConsts::UserSections::Subsection::NameMemory) {
+      auto num = getU32LEB();
+      for (size_t i = 0; i < num; i++) {
+        auto index = getU32LEB();
+        auto rawName = getInlineString();
+        if (index == 0) {
+          wasm.memory.name = escape(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;
+      for (size_t i = 0; i < num; i++) {
+        auto index = getU32LEB();
+        auto rawName = getInlineString();
+        auto name = escape(rawName);
+        // De-duplicate names by appending .1, .2, etc.
+        for (int i = 1; !usedNames.insert(name).second; ++i) {
+          name = std::string(escape(rawName).str) + std::string(".") +
+                 std::to_string(i);
+        }
+        auto numGlobalImports = globalImports.size();
+        if (index < numGlobalImports) {
+          globalImports[index]->name = name;
+        } else if (index - numGlobalImports < globals.size()) {
+          globals[index - numGlobalImports]->name = name;
+        } else {
+          std::cerr << "warning: global index out of bounds in name section, "
+                       "global subsection: "
+                    << std::string(rawName.str) << " at index "
+                    << std::to_string(index) << std::endl;
+        }
+      }
+    } else {
+      std::cerr << "warning: unknown name subsection with id "
+                << std::to_string(nameType) << " at " << pos << std::endl;
+      pos = subsectionPos + subsectionSize;
+    }
+    if (pos != subsectionPos + subsectionSize) {
+      throwError("bad names subsection position change");
+    }
+  }
+  if (pos != sectionPos + payloadLen) {
+    throwError("bad names section position change");
+  }
+}
+
+void WasmBinaryBuilder::readFeatures(size_t payloadLen) {
+  wasm.hasFeaturesSection = true;
+  wasm.features = FeatureSet::MVP;
+
+  auto sectionPos = pos;
+  size_t numFeatures = getU32LEB();
+  for (size_t i = 0; i < numFeatures; ++i) {
+    uint8_t prefix = getInt8();
+    if (prefix != BinaryConsts::FeatureUsed) {
+      if (prefix == BinaryConsts::FeatureRequired) {
+        std::cerr
+          << "warning: required features in feature section are ignored";
+      } else if (prefix == BinaryConsts::FeatureDisallowed) {
+        std::cerr
+          << "warning: disallowed features in feature section are ignored";
+      } else {
+        throwError("Unrecognized feature policy prefix");
+      }
+    }
+
+    Name name = getInlineString();
+    if (pos > sectionPos + payloadLen) {
+      throwError("ill-formed string extends beyond section");
+    }
+
+    if (prefix != BinaryConsts::FeatureDisallowed) {
+      if (name == BinaryConsts::UserSections::AtomicsFeature) {
+        wasm.features.setAtomics();
+      } else if (name == BinaryConsts::UserSections::BulkMemoryFeature) {
+        wasm.features.setBulkMemory();
+      } else if (name == BinaryConsts::UserSections::ExceptionHandlingFeature) {
+        wasm.features.setExceptionHandling();
+      } else if (name == BinaryConsts::UserSections::MutableGlobalsFeature) {
+        wasm.features.setMutableGlobals();
+      } else if (name == BinaryConsts::UserSections::TruncSatFeature) {
+        wasm.features.setTruncSat();
+      } else if (name == BinaryConsts::UserSections::SignExtFeature) {
+        wasm.features.setSignExt();
+      } else if (name == BinaryConsts::UserSections::SIMD128Feature) {
+        wasm.features.setSIMD();
+      } else if (name == BinaryConsts::UserSections::TailCallFeature) {
+        wasm.features.setTailCall();
+      } else if (name == BinaryConsts::UserSections::ReferenceTypesFeature) {
+        wasm.features.setReferenceTypes();
+      } else if (name == BinaryConsts::UserSections::MultivalueFeature) {
+        wasm.features.setMultivalue();
+      } else if (name == BinaryConsts::UserSections::GCFeature) {
+        wasm.features.setGC();
+      } else if (name == BinaryConsts::UserSections::Memory64Feature) {
+        wasm.features.setMemory64();
+      }
+    }
+  }
+  if (pos != sectionPos + payloadLen) {
+    throwError("bad features section size");
+  }
+}
+
+void WasmBinaryBuilder::readDylink(size_t payloadLen) {
+  wasm.dylinkSection = make_unique<DylinkSection>();
+
+  auto sectionPos = pos;
+
+  wasm.dylinkSection->memorySize = getU32LEB();
+  wasm.dylinkSection->memoryAlignment = getU32LEB();
+  wasm.dylinkSection->tableSize = getU32LEB();
+  wasm.dylinkSection->tableAlignment = getU32LEB();
+
+  size_t numNeededDynlibs = getU32LEB();
+  for (size_t i = 0; i < numNeededDynlibs; ++i) {
+    wasm.dylinkSection->neededDynlibs.push_back(getInlineString());
+  }
+
+  if (pos != sectionPos + payloadLen) {
+    throwError("bad features section size");
+  }
+}
+
+BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
+  if (pos == endOfFunction) {
+    throwError("Reached function end without seeing End opcode");
+  }
+  BYN_TRACE("zz recurse into " << ++depth << " at " << pos << std::endl);
+  readNextDebugLocation();
+  std::set<Function::DebugLocation> currDebugLocation;
+  if (debugLocation.size()) {
+    currDebugLocation.insert(*debugLocation.begin());
+  }
+  size_t startPos = pos;
+  uint8_t code = getInt8();
+  BYN_TRACE("readExpression seeing " << (int)code << std::endl);
+  switch (code) {
+    case BinaryConsts::Block:
+      visitBlock((curr = allocator.alloc<Block>())->cast<Block>());
+      break;
+    case BinaryConsts::If:
+      visitIf((curr = allocator.alloc<If>())->cast<If>());
+      break;
+    case BinaryConsts::Loop:
+      visitLoop((curr = allocator.alloc<Loop>())->cast<Loop>());
+      break;
+    case BinaryConsts::Br:
+    case BinaryConsts::BrIf:
+      visitBreak((curr = allocator.alloc<Break>())->cast<Break>(), code);
+      break; // code distinguishes br from br_if
+    case BinaryConsts::BrTable:
+      visitSwitch((curr = allocator.alloc<Switch>())->cast<Switch>());
+      break;
+    case BinaryConsts::CallFunction:
+      visitCall((curr = allocator.alloc<Call>())->cast<Call>());
+      break;
+    case BinaryConsts::CallIndirect:
+      visitCallIndirect(
+        (curr = allocator.alloc<CallIndirect>())->cast<CallIndirect>());
+      break;
+    case BinaryConsts::RetCallFunction: {
+      auto call = allocator.alloc<Call>();
+      call->isReturn = true;
+      curr = call;
+      visitCall(call);
+      break;
+    }
+    case BinaryConsts::RetCallIndirect: {
+      auto call = allocator.alloc<CallIndirect>();
+      call->isReturn = true;
+      curr = call;
+      visitCallIndirect(call);
+      break;
+    }
+    case BinaryConsts::LocalGet:
+      visitLocalGet((curr = allocator.alloc<LocalGet>())->cast<LocalGet>());
+      break;
+    case BinaryConsts::LocalTee:
+    case BinaryConsts::LocalSet:
+      visitLocalSet((curr = allocator.alloc<LocalSet>())->cast<LocalSet>(),
+                    code);
+      break;
+    case BinaryConsts::GlobalGet:
+      visitGlobalGet((curr = allocator.alloc<GlobalGet>())->cast<GlobalGet>());
+      break;
+    case BinaryConsts::GlobalSet:
+      visitGlobalSet((curr = allocator.alloc<GlobalSet>())->cast<GlobalSet>());
+      break;
+    case BinaryConsts::Select:
+    case BinaryConsts::SelectWithType:
+      visitSelect((curr = allocator.alloc<Select>())->cast<Select>(), code);
+      break;
+    case BinaryConsts::Return:
+      visitReturn((curr = allocator.alloc<Return>())->cast<Return>());
+      break;
+    case BinaryConsts::Nop:
+      visitNop((curr = allocator.alloc<Nop>())->cast<Nop>());
+      break;
+    case BinaryConsts::Unreachable:
+      visitUnreachable(
+        (curr = allocator.alloc<Unreachable>())->cast<Unreachable>());
+      break;
+    case BinaryConsts::Drop:
+      visitDrop((curr = allocator.alloc<Drop>())->cast<Drop>());
+      break;
+    case BinaryConsts::End:
+      curr = nullptr;
+      continueControlFlow(BinaryLocations::End, startPos);
+      break;
+    case BinaryConsts::Else:
+      curr = nullptr;
+      continueControlFlow(BinaryLocations::Else, startPos);
+      break;
+    case BinaryConsts::Catch:
+      curr = nullptr;
+      continueControlFlow(BinaryLocations::Catch, startPos);
+      break;
+    case BinaryConsts::RefNull:
+      visitRefNull((curr = allocator.alloc<RefNull>())->cast<RefNull>());
+      break;
+    case BinaryConsts::RefIsNull:
+      visitRefIsNull((curr = allocator.alloc<RefIsNull>())->cast<RefIsNull>());
+      break;
+    case BinaryConsts::RefFunc:
+      visitRefFunc((curr = allocator.alloc<RefFunc>())->cast<RefFunc>());
+      break;
+    case BinaryConsts::RefEq:
+      visitRefEq((curr = allocator.alloc<RefEq>())->cast<RefEq>());
+      break;
+    case BinaryConsts::Try:
+      visitTryOrTryInBlock(curr);
+      break;
+    case BinaryConsts::Throw:
+      visitThrow((curr = allocator.alloc<Throw>())->cast<Throw>());
+      break;
+    case BinaryConsts::Rethrow:
+      visitRethrow((curr = allocator.alloc<Rethrow>())->cast<Rethrow>());
+      break;
+    case BinaryConsts::BrOnExn:
+      visitBrOnExn((curr = allocator.alloc<BrOnExn>())->cast<BrOnExn>());
+      break;
+    case BinaryConsts::MemorySize: {
+      auto size = allocator.alloc<MemorySize>();
+      if (wasm.memory.is64()) {
+        size->make64();
+      }
+      curr = size;
+      visitMemorySize(size);
+      break;
+    }
+    case BinaryConsts::MemoryGrow: {
+      auto grow = allocator.alloc<MemoryGrow>();
+      if (wasm.memory.is64()) {
+        grow->make64();
+      }
+      curr = grow;
+      visitMemoryGrow(grow);
+      break;
+    }
+    case BinaryConsts::AtomicPrefix: {
+      code = static_cast<uint8_t>(getU32LEB());
+      if (maybeVisitLoad(curr, code, /*isAtomic=*/true)) {
+        break;
+      }
+      if (maybeVisitStore(curr, code, /*isAtomic=*/true)) {
+        break;
+      }
+      if (maybeVisitAtomicRMW(curr, code)) {
+        break;
+      }
+      if (maybeVisitAtomicCmpxchg(curr, code)) {
+        break;
+      }
+      if (maybeVisitAtomicWait(curr, code)) {
+        break;
+      }
+      if (maybeVisitAtomicNotify(curr, code)) {
+        break;
+      }
+      if (maybeVisitAtomicFence(curr, code)) {
+        break;
+      }
+      throwError("invalid code after atomic prefix: " + std::to_string(code));
+      break;
+    }
+    case BinaryConsts::MiscPrefix: {
+      auto opcode = getU32LEB();
+      if (maybeVisitTruncSat(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitMemoryInit(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitDataDrop(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitMemoryCopy(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitMemoryFill(curr, opcode)) {
+        break;
+      }
+      throwError("invalid code after nontrapping float-to-int prefix: " +
+                 std::to_string(opcode));
+      break;
+    }
+    case BinaryConsts::SIMDPrefix: {
+      auto opcode = getU32LEB();
+      if (maybeVisitSIMDBinary(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitSIMDUnary(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitSIMDConst(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitSIMDStore(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitSIMDExtract(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitSIMDReplace(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitSIMDShuffle(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitSIMDTernary(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitSIMDShift(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitSIMDLoad(curr, opcode)) {
+        break;
+      }
+      throwError("invalid code after SIMD prefix: " + std::to_string(opcode));
+      break;
+    }
+    case BinaryConsts::GCPrefix: {
+      auto opcode = getU32LEB();
+      if (maybeVisitI31New(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitI31Get(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitRefTest(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitRefCast(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitBrOnCast(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitRttCanon(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitRttSub(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitStructNew(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitStructGet(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitStructSet(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitArrayNew(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitArrayGet(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitArraySet(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitArrayLen(curr, opcode)) {
+        break;
+      }
+      throwError("invalid code after GC prefix: " + std::to_string(opcode));
+      break;
+    }
+    default: {
+      // otherwise, the code is a subcode TODO: optimize
+      if (maybeVisitBinary(curr, code)) {
+        break;
+      }
+      if (maybeVisitUnary(curr, code)) {
+        break;
+      }
+      if (maybeVisitConst(curr, code)) {
+        break;
+      }
+      if (maybeVisitLoad(curr, code, /*isAtomic=*/false)) {
+        break;
+      }
+      if (maybeVisitStore(curr, code, /*isAtomic=*/false)) {
+        break;
+      }
+      throwError("bad node code " + std::to_string(code));
+      break;
+    }
+  }
+  if (curr) {
+    if (currDebugLocation.size()) {
+      currFunction->debugLocations[curr] = *currDebugLocation.begin();
+    }
+    if (DWARF && currFunction) {
+      currFunction->expressionLocations[curr] =
+        BinaryLocations::Span{BinaryLocation(startPos - codeSectionLocation),
+                              BinaryLocation(pos - codeSectionLocation)};
+    }
+  }
+  BYN_TRACE("zz recurse from " << depth-- << " at " << pos << std::endl);
+  return BinaryConsts::ASTNodes(code);
+}
+
+void WasmBinaryBuilder::startControlFlow(Expression* curr) {
+  if (DWARF && currFunction) {
+    controlFlowStack.push_back(curr);
+  }
+}
+
+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();
+    }
+  }
+}
+
+void WasmBinaryBuilder::pushBlockElements(Block* curr,
+                                          Type type,
+                                          size_t start) {
+  assert(start <= expressionStack.size());
+  // The results of this block are the last values pushed to the expressionStack
+  Expression* results = nullptr;
+  if (type.isConcrete()) {
+    results = popTypedExpression(type);
+  }
+  if (expressionStack.size() < start) {
+    throwError("Block requires more values than are available");
+  }
+  // Everything else on the stack after `start` is either a none-type expression
+  // or a concretely-type expression that is implicitly dropped due to
+  // unreachability at the end of the block, like this:
+  //
+  //  block i32
+  //   i32.const 1
+  //   i32.const 2
+  //   i32.const 3
+  //   return
+  //  end
+  //
+  // The first two const elements will be emitted as drops in the block (the
+  // optimizer can remove them, of course, but in general we may need dropped
+  // items here as they may have side effects).
+  //
+  for (size_t i = start; i < expressionStack.size(); ++i) {
+    auto* item = expressionStack[i];
+    if (item->type.isConcrete()) {
+      item = Builder(wasm).makeDrop(item);
+    }
+    curr->list.push_back(item);
+  }
+  expressionStack.resize(start);
+  if (results != nullptr) {
+    curr->list.push_back(results);
+  }
+}
+
+void WasmBinaryBuilder::visitBlock(Block* curr) {
+  BYN_TRACE("zz node: Block\n");
+  startControlFlow(curr);
+  // special-case Block and de-recurse nested blocks in their first position, as
+  // that is a common pattern that can be very highly nested.
+  std::vector<Block*> stack;
+  while (1) {
+    curr->type = getType();
+    curr->name = getNextLabel();
+    breakStack.push_back({curr->name, curr->type});
+    stack.push_back(curr);
+    if (more() && input[pos] == BinaryConsts::Block) {
+      // a recursion
+      readNextDebugLocation();
+      curr = allocator.alloc<Block>();
+      startControlFlow(curr);
+      pos++;
+      if (debugLocation.size()) {
+        currFunction->debugLocations[curr] = *debugLocation.begin();
+      }
+      continue;
+    } else {
+      // end of recursion
+      break;
+    }
+  }
+  Block* last = nullptr;
+  while (stack.size() > 0) {
+    curr = stack.back();
+    stack.pop_back();
+    // everything after this, that is left when we see the marker, is ours
+    size_t start = expressionStack.size();
+    if (last) {
+      // the previous block is our first-position element
+      pushExpression(last);
+    }
+    last = curr;
+    processExpressions();
+    size_t end = expressionStack.size();
+    if (end < start) {
+      throwError("block cannot pop from outside");
+    }
+    pushBlockElements(curr, curr->type, start);
+    curr->finalize(curr->type,
+                   breakTargetNames.find(curr->name) !=
+                     breakTargetNames.end() /* hasBreak */);
+    breakStack.pop_back();
+    breakTargetNames.erase(curr->name);
+  }
+}
+
+// Gets a block of expressions. If it's just one, return that singleton.
+Expression* WasmBinaryBuilder::getBlockOrSingleton(Type type) {
+  Name label = getNextLabel();
+  breakStack.push_back({label, type});
+  auto start = expressionStack.size();
+
+  processExpressions();
+  size_t end = expressionStack.size();
+  if (end < start) {
+    throwError("block cannot pop from outside");
+  }
+  breakStack.pop_back();
+  auto* block = allocator.alloc<Block>();
+  pushBlockElements(block, type, start);
+  block->name = label;
+  block->finalize(type);
+  // maybe we don't need a block here?
+  if (breakTargetNames.find(block->name) == breakTargetNames.end()) {
+    block->name = Name();
+    if (block->list.size() == 1) {
+      return block->list[0];
+    }
+  }
+  breakTargetNames.erase(block->name);
+  return block;
+}
+
+void WasmBinaryBuilder::visitIf(If* curr) {
+  BYN_TRACE("zz node: If\n");
+  startControlFlow(curr);
+  curr->type = getType();
+  curr->condition = popNonVoidExpression();
+  curr->ifTrue = getBlockOrSingleton(curr->type);
+  if (lastSeparator == BinaryConsts::Else) {
+    curr->ifFalse = getBlockOrSingleton(curr->type);
+  }
+  curr->finalize(curr->type);
+  if (lastSeparator != BinaryConsts::End) {
+    throwError("if should end with End");
+  }
+}
+
+void WasmBinaryBuilder::visitLoop(Loop* curr) {
+  BYN_TRACE("zz node: Loop\n");
+  startControlFlow(curr);
+  curr->type = getType();
+  curr->name = getNextLabel();
+  breakStack.push_back({curr->name, Type::none});
+  // find the expressions in the block, and create the body
+  // a loop may have a list of instructions in wasm, much like
+  // a block, but it only has a label at the top of the loop,
+  // so even if we need a block (if there is more than 1
+  // expression) we never need a label on the block.
+  auto start = expressionStack.size();
+  processExpressions();
+  size_t end = expressionStack.size();
+  if (start > end) {
+    throwError("block cannot pop from outside");
+  }
+  if (end - start == 1) {
+    curr->body = popExpression();
+  } else {
+    auto* block = allocator.alloc<Block>();
+    pushBlockElements(block, curr->type, start);
+    block->finalize(curr->type);
+    curr->body = block;
+  }
+  breakStack.pop_back();
+  breakTargetNames.erase(curr->name);
+  curr->finalize(curr->type);
+}
+
+WasmBinaryBuilder::BreakTarget
+WasmBinaryBuilder::getBreakTarget(int32_t offset) {
+  BYN_TRACE("getBreakTarget " << offset << std::endl);
+  if (breakStack.size() < 1 + size_t(offset)) {
+    throwError("bad breakindex (low)");
+  }
+  size_t index = breakStack.size() - 1 - offset;
+  if (index >= breakStack.size()) {
+    throwError("bad breakindex (high)");
+  }
+  BYN_TRACE("breaktarget " << breakStack[index].name << " type "
+                           << breakStack[index].type << std::endl);
+  auto& ret = breakStack[index];
+  // if the break is in literally unreachable code, then we will not emit it
+  // anyhow, so do not note that the target has breaks to it
+  if (!willBeIgnored) {
+    breakTargetNames.insert(ret.name);
+  }
+  return ret;
+}
+
+void WasmBinaryBuilder::visitBreak(Break* curr, uint8_t code) {
+  BYN_TRACE("zz node: Break, code " << int32_t(code) << std::endl);
+  BreakTarget target = getBreakTarget(getU32LEB());
+  curr->name = target.name;
+  if (code == BinaryConsts::BrIf) {
+    curr->condition = popNonVoidExpression();
+  }
+  if (target.type.isConcrete()) {
+    curr->value = popTypedExpression(target.type);
+  }
+  curr->finalize();
+}
+
+void WasmBinaryBuilder::visitSwitch(Switch* curr) {
+  BYN_TRACE("zz node: Switch\n");
+  curr->condition = popNonVoidExpression();
+  auto numTargets = getU32LEB();
+  BYN_TRACE("targets: " << numTargets << std::endl);
+  for (size_t i = 0; i < numTargets; i++) {
+    curr->targets.push_back(getBreakTarget(getU32LEB()).name);
+  }
+  auto defaultTarget = getBreakTarget(getU32LEB());
+  curr->default_ = defaultTarget.name;
+  BYN_TRACE("default: " << curr->default_ << "\n");
+  if (defaultTarget.type.isConcrete()) {
+    curr->value = popTypedExpression(defaultTarget.type);
+  }
+  curr->finalize();
+}
+
+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 num = sig.params.size();
+  curr->operands.resize(num);
+  for (size_t i = 0; i < num; i++) {
+    curr->operands[num - i - 1] = popNonVoidExpression();
+  }
+  curr->type = sig.results;
+  functionRefs[index].push_back(curr); // we don't know function names yet
+  curr->finalize();
+}
+
+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];
+  auto reserved = getU32LEB();
+  if (reserved != 0) {
+    throwError("Invalid flags field in call_indirect");
+  }
+  auto num = curr->sig.params.size();
+  curr->operands.resize(num);
+  curr->target = popNonVoidExpression();
+  for (size_t i = 0; i < num; i++) {
+    curr->operands[num - i - 1] = popNonVoidExpression();
+  }
+  curr->finalize();
+}
+
+void WasmBinaryBuilder::visitLocalGet(LocalGet* curr) {
+  BYN_TRACE("zz node: LocalGet " << pos << std::endl);
+  ;
+  requireFunctionContext("local.get");
+  curr->index = getU32LEB();
+  if (curr->index >= currFunction->getNumLocals()) {
+    throwError("bad local.get index");
+  }
+  curr->type = currFunction->getLocalType(curr->index);
+  curr->finalize();
+}
+
+void WasmBinaryBuilder::visitLocalSet(LocalSet* curr, uint8_t code) {
+  BYN_TRACE("zz node: Set|LocalTee\n");
+  requireFunctionContext("local.set outside of function");
+  curr->index = getU32LEB();
+  if (curr->index >= currFunction->getNumLocals()) {
+    throwError("bad local.set index");
+  }
+  curr->value = popNonVoidExpression();
+  if (code == BinaryConsts::LocalTee) {
+    curr->makeTee(currFunction->getLocalType(curr->index));
+  } else {
+    curr->makeSet();
+  }
+  curr->finalize();
+}
+
+void WasmBinaryBuilder::visitGlobalGet(GlobalGet* curr) {
+  BYN_TRACE("zz node: GlobalGet " << pos << std::endl);
+  auto index = getU32LEB();
+  if (index < globalImports.size()) {
+    auto* import = globalImports[index];
+    curr->name = import->name;
+    curr->type = import->type;
+  } else {
+    Index adjustedIndex = index - globalImports.size();
+    if (adjustedIndex >= globals.size()) {
+      throwError("invalid global index");
+    }
+    auto* glob = globals[adjustedIndex];
+    curr->name = glob->name;
+    curr->type = glob->type;
+  }
+  globalRefs[index].push_back(curr); // we don't know the final name yet
+}
+
+void WasmBinaryBuilder::visitGlobalSet(GlobalSet* curr) {
+  BYN_TRACE("zz node: GlobalSet\n");
+  auto index = getU32LEB();
+  if (index < globalImports.size()) {
+    auto* import = globalImports[index];
+    curr->name = import->name;
+  } else {
+    Index adjustedIndex = index - globalImports.size();
+    if (adjustedIndex >= globals.size()) {
+      throwError("invalid global index");
+    }
+    curr->name = globals[adjustedIndex]->name;
+  }
+  curr->value = popNonVoidExpression();
+  globalRefs[index].push_back(curr); // we don't know the final name yet
+  curr->finalize();
+}
+
+void WasmBinaryBuilder::readMemoryAccess(Address& alignment, Address& offset) {
+  auto rawAlignment = getU32LEB();
+  if (rawAlignment > 4) {
+    throwError("Alignment must be of a reasonable size");
+  }
+  alignment = Bits::pow2(rawAlignment);
+  offset = getU32LEB();
+}
+
+bool WasmBinaryBuilder::maybeVisitLoad(Expression*& out,
+                                       uint8_t code,
+                                       bool isAtomic) {
+  Load* curr;
+  if (!isAtomic) {
+    switch (code) {
+      case BinaryConsts::I32LoadMem8S:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 1;
+        curr->type = Type::i32;
+        curr->signed_ = true;
+        break;
+      case BinaryConsts::I32LoadMem8U:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 1;
+        curr->type = Type::i32;
+        curr->signed_ = false;
+        break;
+      case BinaryConsts::I32LoadMem16S:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 2;
+        curr->type = Type::i32;
+        curr->signed_ = true;
+        break;
+      case BinaryConsts::I32LoadMem16U:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 2;
+        curr->type = Type::i32;
+        curr->signed_ = false;
+        break;
+      case BinaryConsts::I32LoadMem:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 4;
+        curr->type = Type::i32;
+        break;
+      case BinaryConsts::I64LoadMem8S:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 1;
+        curr->type = Type::i64;
+        curr->signed_ = true;
+        break;
+      case BinaryConsts::I64LoadMem8U:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 1;
+        curr->type = Type::i64;
+        curr->signed_ = false;
+        break;
+      case BinaryConsts::I64LoadMem16S:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 2;
+        curr->type = Type::i64;
+        curr->signed_ = true;
+        break;
+      case BinaryConsts::I64LoadMem16U:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 2;
+        curr->type = Type::i64;
+        curr->signed_ = false;
+        break;
+      case BinaryConsts::I64LoadMem32S:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 4;
+        curr->type = Type::i64;
+        curr->signed_ = true;
+        break;
+      case BinaryConsts::I64LoadMem32U:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 4;
+        curr->type = Type::i64;
+        curr->signed_ = false;
+        break;
+      case BinaryConsts::I64LoadMem:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 8;
+        curr->type = Type::i64;
+        break;
+      case BinaryConsts::F32LoadMem:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 4;
+        curr->type = Type::f32;
+        break;
+      case BinaryConsts::F64LoadMem:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 8;
+        curr->type = Type::f64;
+        break;
+      default:
+        return false;
+    }
+    BYN_TRACE("zz node: Load\n");
+  } else {
+    switch (code) {
+      case BinaryConsts::I32AtomicLoad8U:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 1;
+        curr->type = Type::i32;
+        break;
+      case BinaryConsts::I32AtomicLoad16U:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 2;
+        curr->type = Type::i32;
+        break;
+      case BinaryConsts::I32AtomicLoad:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 4;
+        curr->type = Type::i32;
+        break;
+      case BinaryConsts::I64AtomicLoad8U:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 1;
+        curr->type = Type::i64;
+        break;
+      case BinaryConsts::I64AtomicLoad16U:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 2;
+        curr->type = Type::i64;
+        break;
+      case BinaryConsts::I64AtomicLoad32U:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 4;
+        curr->type = Type::i64;
+        break;
+      case BinaryConsts::I64AtomicLoad:
+        curr = allocator.alloc<Load>();
+        curr->bytes = 8;
+        curr->type = Type::i64;
+        break;
+      default:
+        return false;
+    }
+    curr->signed_ = false;
+    BYN_TRACE("zz node: AtomicLoad\n");
+  }
+
+  curr->isAtomic = isAtomic;
+  readMemoryAccess(curr->align, curr->offset);
+  curr->ptr = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitStore(Expression*& out,
+                                        uint8_t code,
+                                        bool isAtomic) {
+  Store* curr;
+  if (!isAtomic) {
+    switch (code) {
+      case BinaryConsts::I32StoreMem8:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 1;
+        curr->valueType = Type::i32;
+        break;
+      case BinaryConsts::I32StoreMem16:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 2;
+        curr->valueType = Type::i32;
+        break;
+      case BinaryConsts::I32StoreMem:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 4;
+        curr->valueType = Type::i32;
+        break;
+      case BinaryConsts::I64StoreMem8:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 1;
+        curr->valueType = Type::i64;
+        break;
+      case BinaryConsts::I64StoreMem16:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 2;
+        curr->valueType = Type::i64;
+        break;
+      case BinaryConsts::I64StoreMem32:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 4;
+        curr->valueType = Type::i64;
+        break;
+      case BinaryConsts::I64StoreMem:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 8;
+        curr->valueType = Type::i64;
+        break;
+      case BinaryConsts::F32StoreMem:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 4;
+        curr->valueType = Type::f32;
+        break;
+      case BinaryConsts::F64StoreMem:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 8;
+        curr->valueType = Type::f64;
+        break;
+      default:
+        return false;
+    }
+  } else {
+    switch (code) {
+      case BinaryConsts::I32AtomicStore8:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 1;
+        curr->valueType = Type::i32;
+        break;
+      case BinaryConsts::I32AtomicStore16:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 2;
+        curr->valueType = Type::i32;
+        break;
+      case BinaryConsts::I32AtomicStore:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 4;
+        curr->valueType = Type::i32;
+        break;
+      case BinaryConsts::I64AtomicStore8:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 1;
+        curr->valueType = Type::i64;
+        break;
+      case BinaryConsts::I64AtomicStore16:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 2;
+        curr->valueType = Type::i64;
+        break;
+      case BinaryConsts::I64AtomicStore32:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 4;
+        curr->valueType = Type::i64;
+        break;
+      case BinaryConsts::I64AtomicStore:
+        curr = allocator.alloc<Store>();
+        curr->bytes = 8;
+        curr->valueType = Type::i64;
+        break;
+      default:
+        return false;
+    }
+  }
+
+  curr->isAtomic = isAtomic;
+  BYN_TRACE("zz node: Store\n");
+  readMemoryAccess(curr->align, curr->offset);
+  curr->value = popNonVoidExpression();
+  curr->ptr = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitAtomicRMW(Expression*& out, uint8_t code) {
+  if (code < BinaryConsts::AtomicRMWOps_Begin ||
+      code > BinaryConsts::AtomicRMWOps_End) {
+    return false;
+  }
+  auto* curr = allocator.alloc<AtomicRMW>();
+
+  // Set curr to the given opcode, type and size.
+#define SET(opcode, optype, size)                                              \
+  curr->op = opcode;                                                           \
+  curr->type = optype;                                                         \
+  curr->bytes = size
+
+  // Handle the cases for all the valid types for a particular opcode
+#define SET_FOR_OP(Op)                                                         \
+  case BinaryConsts::I32AtomicRMW##Op:                                         \
+    SET(Op, Type::i32, 4);                                                     \
+    break;                                                                     \
+  case BinaryConsts::I32AtomicRMW##Op##8U:                                     \
+    SET(Op, Type::i32, 1);                                                     \
+    break;                                                                     \
+  case BinaryConsts::I32AtomicRMW##Op##16U:                                    \
+    SET(Op, Type::i32, 2);                                                     \
+    break;                                                                     \
+  case BinaryConsts::I64AtomicRMW##Op:                                         \
+    SET(Op, Type::i64, 8);                                                     \
+    break;                                                                     \
+  case BinaryConsts::I64AtomicRMW##Op##8U:                                     \
+    SET(Op, Type::i64, 1);                                                     \
+    break;                                                                     \
+  case BinaryConsts::I64AtomicRMW##Op##16U:                                    \
+    SET(Op, Type::i64, 2);                                                     \
+    break;                                                                     \
+  case BinaryConsts::I64AtomicRMW##Op##32U:                                    \
+    SET(Op, Type::i64, 4);                                                     \
+    break;
+
+  switch (code) {
+    SET_FOR_OP(Add);
+    SET_FOR_OP(Sub);
+    SET_FOR_OP(And);
+    SET_FOR_OP(Or);
+    SET_FOR_OP(Xor);
+    SET_FOR_OP(Xchg);
+    default:
+      WASM_UNREACHABLE("unexpected opcode");
+  }
+#undef SET_FOR_OP
+#undef SET
+
+  BYN_TRACE("zz node: AtomicRMW\n");
+  Address readAlign;
+  readMemoryAccess(readAlign, curr->offset);
+  if (readAlign != curr->bytes) {
+    throwError("Align of AtomicRMW must match size");
+  }
+  curr->value = popNonVoidExpression();
+  curr->ptr = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitAtomicCmpxchg(Expression*& out,
+                                                uint8_t code) {
+  if (code < BinaryConsts::AtomicCmpxchgOps_Begin ||
+      code > BinaryConsts::AtomicCmpxchgOps_End) {
+    return false;
+  }
+  auto* curr = allocator.alloc<AtomicCmpxchg>();
+
+  // Set curr to the given type and size.
+#define SET(optype, size)                                                      \
+  curr->type = optype;                                                         \
+  curr->bytes = size
+
+  switch (code) {
+    case BinaryConsts::I32AtomicCmpxchg:
+      SET(Type::i32, 4);
+      break;
+    case BinaryConsts::I64AtomicCmpxchg:
+      SET(Type::i64, 8);
+      break;
+    case BinaryConsts::I32AtomicCmpxchg8U:
+      SET(Type::i32, 1);
+      break;
+    case BinaryConsts::I32AtomicCmpxchg16U:
+      SET(Type::i32, 2);
+      break;
+    case BinaryConsts::I64AtomicCmpxchg8U:
+      SET(Type::i64, 1);
+      break;
+    case BinaryConsts::I64AtomicCmpxchg16U:
+      SET(Type::i64, 2);
+      break;
+    case BinaryConsts::I64AtomicCmpxchg32U:
+      SET(Type::i64, 4);
+      break;
+    default:
+      WASM_UNREACHABLE("unexpected opcode");
+  }
+
+  BYN_TRACE("zz node: AtomicCmpxchg\n");
+  Address readAlign;
+  readMemoryAccess(readAlign, curr->offset);
+  if (readAlign != curr->bytes) {
+    throwError("Align of AtomicCpxchg must match size");
+  }
+  curr->replacement = popNonVoidExpression();
+  curr->expected = popNonVoidExpression();
+  curr->ptr = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitAtomicWait(Expression*& out, uint8_t code) {
+  if (code < BinaryConsts::I32AtomicWait ||
+      code > BinaryConsts::I64AtomicWait) {
+    return false;
+  }
+  auto* curr = allocator.alloc<AtomicWait>();
+
+  switch (code) {
+    case BinaryConsts::I32AtomicWait:
+      curr->expectedType = Type::i32;
+      break;
+    case BinaryConsts::I64AtomicWait:
+      curr->expectedType = Type::i64;
+      break;
+    default:
+      WASM_UNREACHABLE("unexpected opcode");
+  }
+  curr->type = Type::i32;
+  BYN_TRACE("zz node: AtomicWait\n");
+  curr->timeout = popNonVoidExpression();
+  curr->expected = popNonVoidExpression();
+  curr->ptr = popNonVoidExpression();
+  Address readAlign;
+  readMemoryAccess(readAlign, curr->offset);
+  if (readAlign != curr->expectedType.getByteSize()) {
+    throwError("Align of AtomicWait must match size");
+  }
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitAtomicNotify(Expression*& out, uint8_t code) {
+  if (code != BinaryConsts::AtomicNotify) {
+    return false;
+  }
+  auto* curr = allocator.alloc<AtomicNotify>();
+  BYN_TRACE("zz node: AtomicNotify\n");
+
+  curr->type = Type::i32;
+  curr->notifyCount = popNonVoidExpression();
+  curr->ptr = popNonVoidExpression();
+  Address readAlign;
+  readMemoryAccess(readAlign, curr->offset);
+  if (readAlign != curr->type.getByteSize()) {
+    throwError("Align of AtomicNotify must match size");
+  }
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitAtomicFence(Expression*& out, uint8_t code) {
+  if (code != BinaryConsts::AtomicFence) {
+    return false;
+  }
+  auto* curr = allocator.alloc<AtomicFence>();
+  BYN_TRACE("zz node: AtomicFence\n");
+  curr->order = getU32LEB();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitConst(Expression*& out, uint8_t code) {
+  Const* curr;
+  BYN_TRACE("zz node: Const, code " << code << std::endl);
+  switch (code) {
+    case BinaryConsts::I32Const:
+      curr = allocator.alloc<Const>();
+      curr->value = Literal(getS32LEB());
+      break;
+    case BinaryConsts::I64Const:
+      curr = allocator.alloc<Const>();
+      curr->value = Literal(getS64LEB());
+      break;
+    case BinaryConsts::F32Const:
+      curr = allocator.alloc<Const>();
+      curr->value = getFloat32Literal();
+      break;
+    case BinaryConsts::F64Const:
+      curr = allocator.alloc<Const>();
+      curr->value = getFloat64Literal();
+      break;
+    default:
+      return false;
+  }
+  curr->type = curr->value.type;
+  out = curr;
+
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitUnary(Expression*& out, uint8_t code) {
+  Unary* curr;
+  switch (code) {
+    case BinaryConsts::I32Clz:
+      curr = allocator.alloc<Unary>();
+      curr->op = ClzInt32;
+      break;
+    case BinaryConsts::I64Clz:
+      curr = allocator.alloc<Unary>();
+      curr->op = ClzInt64;
+      break;
+    case BinaryConsts::I32Ctz:
+      curr = allocator.alloc<Unary>();
+      curr->op = CtzInt32;
+      break;
+    case BinaryConsts::I64Ctz:
+      curr = allocator.alloc<Unary>();
+      curr->op = CtzInt64;
+      break;
+    case BinaryConsts::I32Popcnt:
+      curr = allocator.alloc<Unary>();
+      curr->op = PopcntInt32;
+      break;
+    case BinaryConsts::I64Popcnt:
+      curr = allocator.alloc<Unary>();
+      curr->op = PopcntInt64;
+      break;
+    case BinaryConsts::I32EqZ:
+      curr = allocator.alloc<Unary>();
+      curr->op = EqZInt32;
+      break;
+    case BinaryConsts::I64EqZ:
+      curr = allocator.alloc<Unary>();
+      curr->op = EqZInt64;
+      break;
+    case BinaryConsts::F32Neg:
+      curr = allocator.alloc<Unary>();
+      curr->op = NegFloat32;
+      break;
+    case BinaryConsts::F64Neg:
+      curr = allocator.alloc<Unary>();
+      curr->op = NegFloat64;
+      break;
+    case BinaryConsts::F32Abs:
+      curr = allocator.alloc<Unary>();
+      curr->op = AbsFloat32;
+      break;
+    case BinaryConsts::F64Abs:
+      curr = allocator.alloc<Unary>();
+      curr->op = AbsFloat64;
+      break;
+    case BinaryConsts::F32Ceil:
+      curr = allocator.alloc<Unary>();
+      curr->op = CeilFloat32;
+      break;
+    case BinaryConsts::F64Ceil:
+      curr = allocator.alloc<Unary>();
+      curr->op = CeilFloat64;
+      break;
+    case BinaryConsts::F32Floor:
+      curr = allocator.alloc<Unary>();
+      curr->op = FloorFloat32;
+      break;
+    case BinaryConsts::F64Floor:
+      curr = allocator.alloc<Unary>();
+      curr->op = FloorFloat64;
+      break;
+    case BinaryConsts::F32NearestInt:
+      curr = allocator.alloc<Unary>();
+      curr->op = NearestFloat32;
+      break;
+    case BinaryConsts::F64NearestInt:
+      curr = allocator.alloc<Unary>();
+      curr->op = NearestFloat64;
+      break;
+    case BinaryConsts::F32Sqrt:
+      curr = allocator.alloc<Unary>();
+      curr->op = SqrtFloat32;
+      break;
+    case BinaryConsts::F64Sqrt:
+      curr = allocator.alloc<Unary>();
+      curr->op = SqrtFloat64;
+      break;
+    case BinaryConsts::F32UConvertI32:
+      curr = allocator.alloc<Unary>();
+      curr->op = ConvertUInt32ToFloat32;
+      break;
+    case BinaryConsts::F64UConvertI32:
+      curr = allocator.alloc<Unary>();
+      curr->op = ConvertUInt32ToFloat64;
+      break;
+    case BinaryConsts::F32SConvertI32:
+      curr = allocator.alloc<Unary>();
+      curr->op = ConvertSInt32ToFloat32;
+      break;
+    case BinaryConsts::F64SConvertI32:
+      curr = allocator.alloc<Unary>();
+      curr->op = ConvertSInt32ToFloat64;
+      break;
+    case BinaryConsts::F32UConvertI64:
+      curr = allocator.alloc<Unary>();
+      curr->op = ConvertUInt64ToFloat32;
+      break;
+    case BinaryConsts::F64UConvertI64:
+      curr = allocator.alloc<Unary>();
+      curr->op = ConvertUInt64ToFloat64;
+      break;
+    case BinaryConsts::F32SConvertI64:
+      curr = allocator.alloc<Unary>();
+      curr->op = ConvertSInt64ToFloat32;
+      break;
+    case BinaryConsts::F64SConvertI64:
+      curr = allocator.alloc<Unary>();
+      curr->op = ConvertSInt64ToFloat64;
+      break;
+
+    case BinaryConsts::I64SExtendI32:
+      curr = allocator.alloc<Unary>();
+      curr->op = ExtendSInt32;
+      break;
+    case BinaryConsts::I64UExtendI32:
+      curr = allocator.alloc<Unary>();
+      curr->op = ExtendUInt32;
+      break;
+    case BinaryConsts::I32WrapI64:
+      curr = allocator.alloc<Unary>();
+      curr->op = WrapInt64;
+      break;
+
+    case BinaryConsts::I32UTruncF32:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncUFloat32ToInt32;
+      break;
+    case BinaryConsts::I32UTruncF64:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncUFloat64ToInt32;
+      break;
+    case BinaryConsts::I32STruncF32:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSFloat32ToInt32;
+      break;
+    case BinaryConsts::I32STruncF64:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSFloat64ToInt32;
+      break;
+    case BinaryConsts::I64UTruncF32:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncUFloat32ToInt64;
+      break;
+    case BinaryConsts::I64UTruncF64:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncUFloat64ToInt64;
+      break;
+    case BinaryConsts::I64STruncF32:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSFloat32ToInt64;
+      break;
+    case BinaryConsts::I64STruncF64:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSFloat64ToInt64;
+      break;
+
+    case BinaryConsts::F32Trunc:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncFloat32;
+      break;
+    case BinaryConsts::F64Trunc:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncFloat64;
+      break;
+
+    case BinaryConsts::F32DemoteI64:
+      curr = allocator.alloc<Unary>();
+      curr->op = DemoteFloat64;
+      break;
+    case BinaryConsts::F64PromoteF32:
+      curr = allocator.alloc<Unary>();
+      curr->op = PromoteFloat32;
+      break;
+    case BinaryConsts::I32ReinterpretF32:
+      curr = allocator.alloc<Unary>();
+      curr->op = ReinterpretFloat32;
+      break;
+    case BinaryConsts::I64ReinterpretF64:
+      curr = allocator.alloc<Unary>();
+      curr->op = ReinterpretFloat64;
+      break;
+    case BinaryConsts::F32ReinterpretI32:
+      curr = allocator.alloc<Unary>();
+      curr->op = ReinterpretInt32;
+      break;
+    case BinaryConsts::F64ReinterpretI64:
+      curr = allocator.alloc<Unary>();
+      curr->op = ReinterpretInt64;
+      break;
+
+    case BinaryConsts::I32ExtendS8:
+      curr = allocator.alloc<Unary>();
+      curr->op = ExtendS8Int32;
+      break;
+    case BinaryConsts::I32ExtendS16:
+      curr = allocator.alloc<Unary>();
+      curr->op = ExtendS16Int32;
+      break;
+    case BinaryConsts::I64ExtendS8:
+      curr = allocator.alloc<Unary>();
+      curr->op = ExtendS8Int64;
+      break;
+    case BinaryConsts::I64ExtendS16:
+      curr = allocator.alloc<Unary>();
+      curr->op = ExtendS16Int64;
+      break;
+    case BinaryConsts::I64ExtendS32:
+      curr = allocator.alloc<Unary>();
+      curr->op = ExtendS32Int64;
+      break;
+
+    default:
+      return false;
+  }
+  BYN_TRACE("zz node: Unary\n");
+  curr->value = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitTruncSat(Expression*& out, uint32_t code) {
+  Unary* curr;
+  switch (code) {
+    case BinaryConsts::I32STruncSatF32:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSatSFloat32ToInt32;
+      break;
+    case BinaryConsts::I32UTruncSatF32:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSatUFloat32ToInt32;
+      break;
+    case BinaryConsts::I32STruncSatF64:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSatSFloat64ToInt32;
+      break;
+    case BinaryConsts::I32UTruncSatF64:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSatUFloat64ToInt32;
+      break;
+    case BinaryConsts::I64STruncSatF32:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSatSFloat32ToInt64;
+      break;
+    case BinaryConsts::I64UTruncSatF32:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSatUFloat32ToInt64;
+      break;
+    case BinaryConsts::I64STruncSatF64:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSatSFloat64ToInt64;
+      break;
+    case BinaryConsts::I64UTruncSatF64:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSatUFloat64ToInt64;
+      break;
+    default:
+      return false;
+  }
+  BYN_TRACE("zz node: Unary (nontrapping float-to-int)\n");
+  curr->value = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitMemoryInit(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::MemoryInit) {
+    return false;
+  }
+  auto* curr = allocator.alloc<MemoryInit>();
+  curr->size = popNonVoidExpression();
+  curr->offset = popNonVoidExpression();
+  curr->dest = popNonVoidExpression();
+  curr->segment = getU32LEB();
+  if (getInt8() != 0) {
+    throwError("Unexpected nonzero memory index");
+  }
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitDataDrop(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::DataDrop) {
+    return false;
+  }
+  auto* curr = allocator.alloc<DataDrop>();
+  curr->segment = getU32LEB();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitMemoryCopy(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::MemoryCopy) {
+    return false;
+  }
+  auto* curr = allocator.alloc<MemoryCopy>();
+  curr->size = popNonVoidExpression();
+  curr->source = popNonVoidExpression();
+  curr->dest = popNonVoidExpression();
+  if (getInt8() != 0 || getInt8() != 0) {
+    throwError("Unexpected nonzero memory index");
+  }
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitMemoryFill(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::MemoryFill) {
+    return false;
+  }
+  auto* curr = allocator.alloc<MemoryFill>();
+  curr->size = popNonVoidExpression();
+  curr->value = popNonVoidExpression();
+  curr->dest = popNonVoidExpression();
+  if (getInt8() != 0) {
+    throwError("Unexpected nonzero memory index");
+  }
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitBinary(Expression*& out, uint8_t code) {
+  Binary* curr;
+#define INT_TYPED_CODE(code)                                                   \
+  {                                                                            \
+    case BinaryConsts::I32##code:                                              \
+      curr = allocator.alloc<Binary>();                                        \
+      curr->op = code##Int32;                                                  \
+      break;                                                                   \
+    case BinaryConsts::I64##code:                                              \
+      curr = allocator.alloc<Binary>();                                        \
+      curr->op = code##Int64;                                                  \
+      break;                                                                   \
+  }
+#define FLOAT_TYPED_CODE(code)                                                 \
+  {                                                                            \
+    case BinaryConsts::F32##code:                                              \
+      curr = allocator.alloc<Binary>();                                        \
+      curr->op = code##Float32;                                                \
+      break;                                                                   \
+    case BinaryConsts::F64##code:                                              \
+      curr = allocator.alloc<Binary>();                                        \
+      curr->op = code##Float64;                                                \
+      break;                                                                   \
+  }
+#define TYPED_CODE(code)                                                       \
+  {                                                                            \
+    INT_TYPED_CODE(code)                                                       \
+    FLOAT_TYPED_CODE(code)                                                     \
+  }
+
+  switch (code) {
+    TYPED_CODE(Add);
+    TYPED_CODE(Sub);
+    TYPED_CODE(Mul);
+    INT_TYPED_CODE(DivS);
+    INT_TYPED_CODE(DivU);
+    INT_TYPED_CODE(RemS);
+    INT_TYPED_CODE(RemU);
+    INT_TYPED_CODE(And);
+    INT_TYPED_CODE(Or);
+    INT_TYPED_CODE(Xor);
+    INT_TYPED_CODE(Shl);
+    INT_TYPED_CODE(ShrU);
+    INT_TYPED_CODE(ShrS);
+    INT_TYPED_CODE(RotL);
+    INT_TYPED_CODE(RotR);
+    FLOAT_TYPED_CODE(Div);
+    FLOAT_TYPED_CODE(CopySign);
+    FLOAT_TYPED_CODE(Min);
+    FLOAT_TYPED_CODE(Max);
+    TYPED_CODE(Eq);
+    TYPED_CODE(Ne);
+    INT_TYPED_CODE(LtS);
+    INT_TYPED_CODE(LtU);
+    INT_TYPED_CODE(LeS);
+    INT_TYPED_CODE(LeU);
+    INT_TYPED_CODE(GtS);
+    INT_TYPED_CODE(GtU);
+    INT_TYPED_CODE(GeS);
+    INT_TYPED_CODE(GeU);
+    FLOAT_TYPED_CODE(Lt);
+    FLOAT_TYPED_CODE(Le);
+    FLOAT_TYPED_CODE(Gt);
+    FLOAT_TYPED_CODE(Ge);
+    default:
+      return false;
+  }
+  BYN_TRACE("zz node: Binary\n");
+  curr->right = popNonVoidExpression();
+  curr->left = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+#undef TYPED_CODE
+#undef INT_TYPED_CODE
+#undef FLOAT_TYPED_CODE
+}
+
+bool WasmBinaryBuilder::maybeVisitSIMDBinary(Expression*& out, uint32_t code) {
+  Binary* curr;
+  switch (code) {
+    case BinaryConsts::I8x16Eq:
+      curr = allocator.alloc<Binary>();
+      curr->op = EqVecI8x16;
+      break;
+    case BinaryConsts::I8x16Ne:
+      curr = allocator.alloc<Binary>();
+      curr->op = NeVecI8x16;
+      break;
+    case BinaryConsts::I8x16LtS:
+      curr = allocator.alloc<Binary>();
+      curr->op = LtSVecI8x16;
+      break;
+    case BinaryConsts::I8x16LtU:
+      curr = allocator.alloc<Binary>();
+      curr->op = LtUVecI8x16;
+      break;
+    case BinaryConsts::I8x16GtS:
+      curr = allocator.alloc<Binary>();
+      curr->op = GtSVecI8x16;
+      break;
+    case BinaryConsts::I8x16GtU:
+      curr = allocator.alloc<Binary>();
+      curr->op = GtUVecI8x16;
+      break;
+    case BinaryConsts::I8x16LeS:
+      curr = allocator.alloc<Binary>();
+      curr->op = LeSVecI8x16;
+      break;
+    case BinaryConsts::I8x16LeU:
+      curr = allocator.alloc<Binary>();
+      curr->op = LeUVecI8x16;
+      break;
+    case BinaryConsts::I8x16GeS:
+      curr = allocator.alloc<Binary>();
+      curr->op = GeSVecI8x16;
+      break;
+    case BinaryConsts::I8x16GeU:
+      curr = allocator.alloc<Binary>();
+      curr->op = GeUVecI8x16;
+      break;
+    case BinaryConsts::I16x8Eq:
+      curr = allocator.alloc<Binary>();
+      curr->op = EqVecI16x8;
+      break;
+    case BinaryConsts::I16x8Ne:
+      curr = allocator.alloc<Binary>();
+      curr->op = NeVecI16x8;
+      break;
+    case BinaryConsts::I16x8LtS:
+      curr = allocator.alloc<Binary>();
+      curr->op = LtSVecI16x8;
+      break;
+    case BinaryConsts::I16x8LtU:
+      curr = allocator.alloc<Binary>();
+      curr->op = LtUVecI16x8;
+      break;
+    case BinaryConsts::I16x8GtS:
+      curr = allocator.alloc<Binary>();
+      curr->op = GtSVecI16x8;
+      break;
+    case BinaryConsts::I16x8GtU:
+      curr = allocator.alloc<Binary>();
+      curr->op = GtUVecI16x8;
+      break;
+    case BinaryConsts::I16x8LeS:
+      curr = allocator.alloc<Binary>();
+      curr->op = LeSVecI16x8;
+      break;
+    case BinaryConsts::I16x8LeU:
+      curr = allocator.alloc<Binary>();
+      curr->op = LeUVecI16x8;
+      break;
+    case BinaryConsts::I16x8GeS:
+      curr = allocator.alloc<Binary>();
+      curr->op = GeSVecI16x8;
+      break;
+    case BinaryConsts::I16x8GeU:
+      curr = allocator.alloc<Binary>();
+      curr->op = GeUVecI16x8;
+      break;
+    case BinaryConsts::I32x4Eq:
+      curr = allocator.alloc<Binary>();
+      curr->op = EqVecI32x4;
+      break;
+    case BinaryConsts::I32x4Ne:
+      curr = allocator.alloc<Binary>();
+      curr->op = NeVecI32x4;
+      break;
+    case BinaryConsts::I32x4LtS:
+      curr = allocator.alloc<Binary>();
+      curr->op = LtSVecI32x4;
+      break;
+    case BinaryConsts::I32x4LtU:
+      curr = allocator.alloc<Binary>();
+      curr->op = LtUVecI32x4;
+      break;
+    case BinaryConsts::I32x4GtS:
+      curr = allocator.alloc<Binary>();
+      curr->op = GtSVecI32x4;
+      break;
+    case BinaryConsts::I32x4GtU:
+      curr = allocator.alloc<Binary>();
+      curr->op = GtUVecI32x4;
+      break;
+    case BinaryConsts::I32x4LeS:
+      curr = allocator.alloc<Binary>();
+      curr->op = LeSVecI32x4;
+      break;
+    case BinaryConsts::I32x4LeU:
+      curr = allocator.alloc<Binary>();
+      curr->op = LeUVecI32x4;
+      break;
+    case BinaryConsts::I32x4GeS:
+      curr = allocator.alloc<Binary>();
+      curr->op = GeSVecI32x4;
+      break;
+    case BinaryConsts::I32x4GeU:
+      curr = allocator.alloc<Binary>();
+      curr->op = GeUVecI32x4;
+      break;
+    case BinaryConsts::F32x4Eq:
+      curr = allocator.alloc<Binary>();
+      curr->op = EqVecF32x4;
+      break;
+    case BinaryConsts::F32x4Ne:
+      curr = allocator.alloc<Binary>();
+      curr->op = NeVecF32x4;
+      break;
+    case BinaryConsts::F32x4Lt:
+      curr = allocator.alloc<Binary>();
+      curr->op = LtVecF32x4;
+      break;
+    case BinaryConsts::F32x4Gt:
+      curr = allocator.alloc<Binary>();
+      curr->op = GtVecF32x4;
+      break;
+    case BinaryConsts::F32x4Le:
+      curr = allocator.alloc<Binary>();
+      curr->op = LeVecF32x4;
+      break;
+    case BinaryConsts::F32x4Ge:
+      curr = allocator.alloc<Binary>();
+      curr->op = GeVecF32x4;
+      break;
+    case BinaryConsts::F64x2Eq:
+      curr = allocator.alloc<Binary>();
+      curr->op = EqVecF64x2;
+      break;
+    case BinaryConsts::F64x2Ne:
+      curr = allocator.alloc<Binary>();
+      curr->op = NeVecF64x2;
+      break;
+    case BinaryConsts::F64x2Lt:
+      curr = allocator.alloc<Binary>();
+      curr->op = LtVecF64x2;
+      break;
+    case BinaryConsts::F64x2Gt:
+      curr = allocator.alloc<Binary>();
+      curr->op = GtVecF64x2;
+      break;
+    case BinaryConsts::F64x2Le:
+      curr = allocator.alloc<Binary>();
+      curr->op = LeVecF64x2;
+      break;
+    case BinaryConsts::F64x2Ge:
+      curr = allocator.alloc<Binary>();
+      curr->op = GeVecF64x2;
+      break;
+    case BinaryConsts::V128And:
+      curr = allocator.alloc<Binary>();
+      curr->op = AndVec128;
+      break;
+    case BinaryConsts::V128Or:
+      curr = allocator.alloc<Binary>();
+      curr->op = OrVec128;
+      break;
+    case BinaryConsts::V128Xor:
+      curr = allocator.alloc<Binary>();
+      curr->op = XorVec128;
+      break;
+    case BinaryConsts::V128AndNot:
+      curr = allocator.alloc<Binary>();
+      curr->op = AndNotVec128;
+      break;
+    case BinaryConsts::I8x16Add:
+      curr = allocator.alloc<Binary>();
+      curr->op = AddVecI8x16;
+      break;
+    case BinaryConsts::I8x16AddSatS:
+      curr = allocator.alloc<Binary>();
+      curr->op = AddSatSVecI8x16;
+      break;
+    case BinaryConsts::I8x16AddSatU:
+      curr = allocator.alloc<Binary>();
+      curr->op = AddSatUVecI8x16;
+      break;
+    case BinaryConsts::I8x16Sub:
+      curr = allocator.alloc<Binary>();
+      curr->op = SubVecI8x16;
+      break;
+    case BinaryConsts::I8x16SubSatS:
+      curr = allocator.alloc<Binary>();
+      curr->op = SubSatSVecI8x16;
+      break;
+    case BinaryConsts::I8x16SubSatU:
+      curr = allocator.alloc<Binary>();
+      curr->op = SubSatUVecI8x16;
+      break;
+    case BinaryConsts::I8x16Mul:
+      curr = allocator.alloc<Binary>();
+      curr->op = MulVecI8x16;
+      break;
+    case BinaryConsts::I8x16MinS:
+      curr = allocator.alloc<Binary>();
+      curr->op = MinSVecI8x16;
+      break;
+    case BinaryConsts::I8x16MinU:
+      curr = allocator.alloc<Binary>();
+      curr->op = MinUVecI8x16;
+      break;
+    case BinaryConsts::I8x16MaxS:
+      curr = allocator.alloc<Binary>();
+      curr->op = MaxSVecI8x16;
+      break;
+    case BinaryConsts::I8x16MaxU:
+      curr = allocator.alloc<Binary>();
+      curr->op = MaxUVecI8x16;
+      break;
+    case BinaryConsts::I8x16AvgrU:
+      curr = allocator.alloc<Binary>();
+      curr->op = AvgrUVecI8x16;
+      break;
+    case BinaryConsts::I16x8Add:
+      curr = allocator.alloc<Binary>();
+      curr->op = AddVecI16x8;
+      break;
+    case BinaryConsts::I16x8AddSatS:
+      curr = allocator.alloc<Binary>();
+      curr->op = AddSatSVecI16x8;
+      break;
+    case BinaryConsts::I16x8AddSatU:
+      curr = allocator.alloc<Binary>();
+      curr->op = AddSatUVecI16x8;
+      break;
+    case BinaryConsts::I16x8Sub:
+      curr = allocator.alloc<Binary>();
+      curr->op = SubVecI16x8;
+      break;
+    case BinaryConsts::I16x8SubSatS:
+      curr = allocator.alloc<Binary>();
+      curr->op = SubSatSVecI16x8;
+      break;
+    case BinaryConsts::I16x8SubSatU:
+      curr = allocator.alloc<Binary>();
+      curr->op = SubSatUVecI16x8;
+      break;
+    case BinaryConsts::I16x8Mul:
+      curr = allocator.alloc<Binary>();
+      curr->op = MulVecI16x8;
+      break;
+    case BinaryConsts::I16x8MinS:
+      curr = allocator.alloc<Binary>();
+      curr->op = MinSVecI16x8;
+      break;
+    case BinaryConsts::I16x8MinU:
+      curr = allocator.alloc<Binary>();
+      curr->op = MinUVecI16x8;
+      break;
+    case BinaryConsts::I16x8MaxS:
+      curr = allocator.alloc<Binary>();
+      curr->op = MaxSVecI16x8;
+      break;
+    case BinaryConsts::I16x8MaxU:
+      curr = allocator.alloc<Binary>();
+      curr->op = MaxUVecI16x8;
+      break;
+    case BinaryConsts::I16x8AvgrU:
+      curr = allocator.alloc<Binary>();
+      curr->op = AvgrUVecI16x8;
+      break;
+    case BinaryConsts::I32x4Add:
+      curr = allocator.alloc<Binary>();
+      curr->op = AddVecI32x4;
+      break;
+    case BinaryConsts::I32x4Sub:
+      curr = allocator.alloc<Binary>();
+      curr->op = SubVecI32x4;
+      break;
+    case BinaryConsts::I32x4Mul:
+      curr = allocator.alloc<Binary>();
+      curr->op = MulVecI32x4;
+      break;
+    case BinaryConsts::I32x4MinS:
+      curr = allocator.alloc<Binary>();
+      curr->op = MinSVecI32x4;
+      break;
+    case BinaryConsts::I32x4MinU:
+      curr = allocator.alloc<Binary>();
+      curr->op = MinUVecI32x4;
+      break;
+    case BinaryConsts::I32x4MaxS:
+      curr = allocator.alloc<Binary>();
+      curr->op = MaxSVecI32x4;
+      break;
+    case BinaryConsts::I32x4MaxU:
+      curr = allocator.alloc<Binary>();
+      curr->op = MaxUVecI32x4;
+      break;
+    case BinaryConsts::I32x4DotSVecI16x8:
+      curr = allocator.alloc<Binary>();
+      curr->op = DotSVecI16x8ToVecI32x4;
+      break;
+    case BinaryConsts::I64x2Add:
+      curr = allocator.alloc<Binary>();
+      curr->op = AddVecI64x2;
+      break;
+    case BinaryConsts::I64x2Sub:
+      curr = allocator.alloc<Binary>();
+      curr->op = SubVecI64x2;
+      break;
+    case BinaryConsts::I64x2Mul:
+      curr = allocator.alloc<Binary>();
+      curr->op = MulVecI64x2;
+      break;
+    case BinaryConsts::F32x4Add:
+      curr = allocator.alloc<Binary>();
+      curr->op = AddVecF32x4;
+      break;
+    case BinaryConsts::F32x4Sub:
+      curr = allocator.alloc<Binary>();
+      curr->op = SubVecF32x4;
+      break;
+    case BinaryConsts::F32x4Mul:
+      curr = allocator.alloc<Binary>();
+      curr->op = MulVecF32x4;
+      break;
+    case BinaryConsts::F32x4Div:
+      curr = allocator.alloc<Binary>();
+      curr->op = DivVecF32x4;
+      break;
+    case BinaryConsts::F32x4Min:
+      curr = allocator.alloc<Binary>();
+      curr->op = MinVecF32x4;
+      break;
+    case BinaryConsts::F32x4Max:
+      curr = allocator.alloc<Binary>();
+      curr->op = MaxVecF32x4;
+      break;
+    case BinaryConsts::F32x4PMin:
+      curr = allocator.alloc<Binary>();
+      curr->op = PMinVecF32x4;
+      break;
+    case BinaryConsts::F32x4PMax:
+      curr = allocator.alloc<Binary>();
+      curr->op = PMaxVecF32x4;
+      break;
+    case BinaryConsts::F64x2Add:
+      curr = allocator.alloc<Binary>();
+      curr->op = AddVecF64x2;
+      break;
+    case BinaryConsts::F64x2Sub:
+      curr = allocator.alloc<Binary>();
+      curr->op = SubVecF64x2;
+      break;
+    case BinaryConsts::F64x2Mul:
+      curr = allocator.alloc<Binary>();
+      curr->op = MulVecF64x2;
+      break;
+    case BinaryConsts::F64x2Div:
+      curr = allocator.alloc<Binary>();
+      curr->op = DivVecF64x2;
+      break;
+    case BinaryConsts::F64x2Min:
+      curr = allocator.alloc<Binary>();
+      curr->op = MinVecF64x2;
+      break;
+    case BinaryConsts::F64x2Max:
+      curr = allocator.alloc<Binary>();
+      curr->op = MaxVecF64x2;
+      break;
+    case BinaryConsts::F64x2PMin:
+      curr = allocator.alloc<Binary>();
+      curr->op = PMinVecF64x2;
+      break;
+    case BinaryConsts::F64x2PMax:
+      curr = allocator.alloc<Binary>();
+      curr->op = PMaxVecF64x2;
+      break;
+    case BinaryConsts::I8x16NarrowSI16x8:
+      curr = allocator.alloc<Binary>();
+      curr->op = NarrowSVecI16x8ToVecI8x16;
+      break;
+    case BinaryConsts::I8x16NarrowUI16x8:
+      curr = allocator.alloc<Binary>();
+      curr->op = NarrowUVecI16x8ToVecI8x16;
+      break;
+    case BinaryConsts::I16x8NarrowSI32x4:
+      curr = allocator.alloc<Binary>();
+      curr->op = NarrowSVecI32x4ToVecI16x8;
+      break;
+    case BinaryConsts::I16x8NarrowUI32x4:
+      curr = allocator.alloc<Binary>();
+      curr->op = NarrowUVecI32x4ToVecI16x8;
+      break;
+    case BinaryConsts::V8x16Swizzle:
+      curr = allocator.alloc<Binary>();
+      curr->op = SwizzleVec8x16;
+      break;
+    default:
+      return false;
+  }
+  BYN_TRACE("zz node: Binary\n");
+  curr->right = popNonVoidExpression();
+  curr->left = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+bool WasmBinaryBuilder::maybeVisitSIMDUnary(Expression*& out, uint32_t code) {
+  Unary* curr;
+  switch (code) {
+    case BinaryConsts::I8x16Splat:
+      curr = allocator.alloc<Unary>();
+      curr->op = SplatVecI8x16;
+      break;
+    case BinaryConsts::I16x8Splat:
+      curr = allocator.alloc<Unary>();
+      curr->op = SplatVecI16x8;
+      break;
+    case BinaryConsts::I32x4Splat:
+      curr = allocator.alloc<Unary>();
+      curr->op = SplatVecI32x4;
+      break;
+    case BinaryConsts::I64x2Splat:
+      curr = allocator.alloc<Unary>();
+      curr->op = SplatVecI64x2;
+      break;
+    case BinaryConsts::F32x4Splat:
+      curr = allocator.alloc<Unary>();
+      curr->op = SplatVecF32x4;
+      break;
+    case BinaryConsts::F64x2Splat:
+      curr = allocator.alloc<Unary>();
+      curr->op = SplatVecF64x2;
+      break;
+    case BinaryConsts::V128Not:
+      curr = allocator.alloc<Unary>();
+      curr->op = NotVec128;
+      break;
+    case BinaryConsts::I8x16Abs:
+      curr = allocator.alloc<Unary>();
+      curr->op = AbsVecI8x16;
+      break;
+    case BinaryConsts::I8x16Neg:
+      curr = allocator.alloc<Unary>();
+      curr->op = NegVecI8x16;
+      break;
+    case BinaryConsts::I8x16AnyTrue:
+      curr = allocator.alloc<Unary>();
+      curr->op = AnyTrueVecI8x16;
+      break;
+    case BinaryConsts::I8x16AllTrue:
+      curr = allocator.alloc<Unary>();
+      curr->op = AllTrueVecI8x16;
+      break;
+    case BinaryConsts::I8x16Bitmask:
+      curr = allocator.alloc<Unary>();
+      curr->op = BitmaskVecI8x16;
+      break;
+    case BinaryConsts::I16x8Abs:
+      curr = allocator.alloc<Unary>();
+      curr->op = AbsVecI16x8;
+      break;
+    case BinaryConsts::I16x8Neg:
+      curr = allocator.alloc<Unary>();
+      curr->op = NegVecI16x8;
+      break;
+    case BinaryConsts::I16x8AnyTrue:
+      curr = allocator.alloc<Unary>();
+      curr->op = AnyTrueVecI16x8;
+      break;
+    case BinaryConsts::I16x8AllTrue:
+      curr = allocator.alloc<Unary>();
+      curr->op = AllTrueVecI16x8;
+      break;
+    case BinaryConsts::I16x8Bitmask:
+      curr = allocator.alloc<Unary>();
+      curr->op = BitmaskVecI16x8;
+      break;
+    case BinaryConsts::I32x4Abs:
+      curr = allocator.alloc<Unary>();
+      curr->op = AbsVecI32x4;
+      break;
+    case BinaryConsts::I32x4Neg:
+      curr = allocator.alloc<Unary>();
+      curr->op = NegVecI32x4;
+      break;
+    case BinaryConsts::I32x4AnyTrue:
+      curr = allocator.alloc<Unary>();
+      curr->op = AnyTrueVecI32x4;
+      break;
+    case BinaryConsts::I32x4AllTrue:
+      curr = allocator.alloc<Unary>();
+      curr->op = AllTrueVecI32x4;
+      break;
+    case BinaryConsts::I32x4Bitmask:
+      curr = allocator.alloc<Unary>();
+      curr->op = BitmaskVecI32x4;
+      break;
+    case BinaryConsts::I64x2Neg:
+      curr = allocator.alloc<Unary>();
+      curr->op = NegVecI64x2;
+      break;
+    case BinaryConsts::I64x2AnyTrue:
+      curr = allocator.alloc<Unary>();
+      curr->op = AnyTrueVecI64x2;
+      break;
+    case BinaryConsts::I64x2AllTrue:
+      curr = allocator.alloc<Unary>();
+      curr->op = AllTrueVecI64x2;
+      break;
+    case BinaryConsts::F32x4Abs:
+      curr = allocator.alloc<Unary>();
+      curr->op = AbsVecF32x4;
+      break;
+    case BinaryConsts::F32x4Neg:
+      curr = allocator.alloc<Unary>();
+      curr->op = NegVecF32x4;
+      break;
+    case BinaryConsts::F32x4Sqrt:
+      curr = allocator.alloc<Unary>();
+      curr->op = SqrtVecF32x4;
+      break;
+    case BinaryConsts::F32x4Ceil:
+      curr = allocator.alloc<Unary>();
+      curr->op = CeilVecF32x4;
+      break;
+    case BinaryConsts::F32x4Floor:
+      curr = allocator.alloc<Unary>();
+      curr->op = FloorVecF32x4;
+      break;
+    case BinaryConsts::F32x4Trunc:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncVecF32x4;
+      break;
+    case BinaryConsts::F32x4Nearest:
+      curr = allocator.alloc<Unary>();
+      curr->op = NearestVecF32x4;
+      break;
+    case BinaryConsts::F64x2Abs:
+      curr = allocator.alloc<Unary>();
+      curr->op = AbsVecF64x2;
+      break;
+    case BinaryConsts::F64x2Neg:
+      curr = allocator.alloc<Unary>();
+      curr->op = NegVecF64x2;
+      break;
+    case BinaryConsts::F64x2Sqrt:
+      curr = allocator.alloc<Unary>();
+      curr->op = SqrtVecF64x2;
+      break;
+    case BinaryConsts::F64x2Ceil:
+      curr = allocator.alloc<Unary>();
+      curr->op = CeilVecF64x2;
+      break;
+    case BinaryConsts::F64x2Floor:
+      curr = allocator.alloc<Unary>();
+      curr->op = FloorVecF64x2;
+      break;
+    case BinaryConsts::F64x2Trunc:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncVecF64x2;
+      break;
+    case BinaryConsts::F64x2Nearest:
+      curr = allocator.alloc<Unary>();
+      curr->op = NearestVecF64x2;
+      break;
+    case BinaryConsts::I32x4TruncSatSF32x4:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSatSVecF32x4ToVecI32x4;
+      break;
+    case BinaryConsts::I32x4TruncSatUF32x4:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSatUVecF32x4ToVecI32x4;
+      break;
+    case BinaryConsts::I64x2TruncSatSF64x2:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSatSVecF64x2ToVecI64x2;
+      break;
+    case BinaryConsts::I64x2TruncSatUF64x2:
+      curr = allocator.alloc<Unary>();
+      curr->op = TruncSatUVecF64x2ToVecI64x2;
+      break;
+    case BinaryConsts::F32x4ConvertSI32x4:
+      curr = allocator.alloc<Unary>();
+      curr->op = ConvertSVecI32x4ToVecF32x4;
+      break;
+    case BinaryConsts::F32x4ConvertUI32x4:
+      curr = allocator.alloc<Unary>();
+      curr->op = ConvertUVecI32x4ToVecF32x4;
+      break;
+    case BinaryConsts::F64x2ConvertSI64x2:
+      curr = allocator.alloc<Unary>();
+      curr->op = ConvertSVecI64x2ToVecF64x2;
+      break;
+    case BinaryConsts::F64x2ConvertUI64x2:
+      curr = allocator.alloc<Unary>();
+      curr->op = ConvertUVecI64x2ToVecF64x2;
+      break;
+    case BinaryConsts::I16x8WidenLowSI8x16:
+      curr = allocator.alloc<Unary>();
+      curr->op = WidenLowSVecI8x16ToVecI16x8;
+      break;
+    case BinaryConsts::I16x8WidenHighSI8x16:
+      curr = allocator.alloc<Unary>();
+      curr->op = WidenHighSVecI8x16ToVecI16x8;
+      break;
+    case BinaryConsts::I16x8WidenLowUI8x16:
+      curr = allocator.alloc<Unary>();
+      curr->op = WidenLowUVecI8x16ToVecI16x8;
+      break;
+    case BinaryConsts::I16x8WidenHighUI8x16:
+      curr = allocator.alloc<Unary>();
+      curr->op = WidenHighUVecI8x16ToVecI16x8;
+      break;
+    case BinaryConsts::I32x4WidenLowSI16x8:
+      curr = allocator.alloc<Unary>();
+      curr->op = WidenLowSVecI16x8ToVecI32x4;
+      break;
+    case BinaryConsts::I32x4WidenHighSI16x8:
+      curr = allocator.alloc<Unary>();
+      curr->op = WidenHighSVecI16x8ToVecI32x4;
+      break;
+    case BinaryConsts::I32x4WidenLowUI16x8:
+      curr = allocator.alloc<Unary>();
+      curr->op = WidenLowUVecI16x8ToVecI32x4;
+      break;
+    case BinaryConsts::I32x4WidenHighUI16x8:
+      curr = allocator.alloc<Unary>();
+      curr->op = WidenHighUVecI16x8ToVecI32x4;
+      break;
+    default:
+      return false;
+  }
+  curr->value = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitSIMDConst(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::V128Const) {
+    return false;
+  }
+  auto* curr = allocator.alloc<Const>();
+  curr->value = getVec128Literal();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitSIMDStore(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::V128Store) {
+    return false;
+  }
+  auto* curr = allocator.alloc<Store>();
+  curr->bytes = 16;
+  curr->valueType = Type::v128;
+  readMemoryAccess(curr->align, curr->offset);
+  curr->isAtomic = false;
+  curr->value = popNonVoidExpression();
+  curr->ptr = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitSIMDExtract(Expression*& out, uint32_t code) {
+  SIMDExtract* curr;
+  switch (code) {
+    case BinaryConsts::I8x16ExtractLaneS:
+      curr = allocator.alloc<SIMDExtract>();
+      curr->op = ExtractLaneSVecI8x16;
+      curr->index = getLaneIndex(16);
+      break;
+    case BinaryConsts::I8x16ExtractLaneU:
+      curr = allocator.alloc<SIMDExtract>();
+      curr->op = ExtractLaneUVecI8x16;
+      curr->index = getLaneIndex(16);
+      break;
+    case BinaryConsts::I16x8ExtractLaneS:
+      curr = allocator.alloc<SIMDExtract>();
+      curr->op = ExtractLaneSVecI16x8;
+      curr->index = getLaneIndex(8);
+      break;
+    case BinaryConsts::I16x8ExtractLaneU:
+      curr = allocator.alloc<SIMDExtract>();
+      curr->op = ExtractLaneUVecI16x8;
+      curr->index = getLaneIndex(8);
+      break;
+    case BinaryConsts::I32x4ExtractLane:
+      curr = allocator.alloc<SIMDExtract>();
+      curr->op = ExtractLaneVecI32x4;
+      curr->index = getLaneIndex(4);
+      break;
+    case BinaryConsts::I64x2ExtractLane:
+      curr = allocator.alloc<SIMDExtract>();
+      curr->op = ExtractLaneVecI64x2;
+      curr->index = getLaneIndex(2);
+      break;
+    case BinaryConsts::F32x4ExtractLane:
+      curr = allocator.alloc<SIMDExtract>();
+      curr->op = ExtractLaneVecF32x4;
+      curr->index = getLaneIndex(4);
+      break;
+    case BinaryConsts::F64x2ExtractLane:
+      curr = allocator.alloc<SIMDExtract>();
+      curr->op = ExtractLaneVecF64x2;
+      curr->index = getLaneIndex(2);
+      break;
+    default:
+      return false;
+  }
+  curr->vec = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitSIMDReplace(Expression*& out, uint32_t code) {
+  SIMDReplace* curr;
+  switch (code) {
+    case BinaryConsts::I8x16ReplaceLane:
+      curr = allocator.alloc<SIMDReplace>();
+      curr->op = ReplaceLaneVecI8x16;
+      curr->index = getLaneIndex(16);
+      break;
+    case BinaryConsts::I16x8ReplaceLane:
+      curr = allocator.alloc<SIMDReplace>();
+      curr->op = ReplaceLaneVecI16x8;
+      curr->index = getLaneIndex(8);
+      break;
+    case BinaryConsts::I32x4ReplaceLane:
+      curr = allocator.alloc<SIMDReplace>();
+      curr->op = ReplaceLaneVecI32x4;
+      curr->index = getLaneIndex(4);
+      break;
+    case BinaryConsts::I64x2ReplaceLane:
+      curr = allocator.alloc<SIMDReplace>();
+      curr->op = ReplaceLaneVecI64x2;
+      curr->index = getLaneIndex(2);
+      break;
+    case BinaryConsts::F32x4ReplaceLane:
+      curr = allocator.alloc<SIMDReplace>();
+      curr->op = ReplaceLaneVecF32x4;
+      curr->index = getLaneIndex(4);
+      break;
+    case BinaryConsts::F64x2ReplaceLane:
+      curr = allocator.alloc<SIMDReplace>();
+      curr->op = ReplaceLaneVecF64x2;
+      curr->index = getLaneIndex(2);
+      break;
+    default:
+      return false;
+  }
+  curr->value = popNonVoidExpression();
+  curr->vec = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitSIMDShuffle(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::V8x16Shuffle) {
+    return false;
+  }
+  auto* curr = allocator.alloc<SIMDShuffle>();
+  for (auto i = 0; i < 16; ++i) {
+    curr->mask[i] = getLaneIndex(32);
+  }
+  curr->right = popNonVoidExpression();
+  curr->left = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitSIMDTernary(Expression*& out, uint32_t code) {
+  SIMDTernary* curr;
+  switch (code) {
+    case BinaryConsts::V128Bitselect:
+      curr = allocator.alloc<SIMDTernary>();
+      curr->op = Bitselect;
+      break;
+    case BinaryConsts::F32x4QFMA:
+      curr = allocator.alloc<SIMDTernary>();
+      curr->op = QFMAF32x4;
+      break;
+    case BinaryConsts::F32x4QFMS:
+      curr = allocator.alloc<SIMDTernary>();
+      curr->op = QFMSF32x4;
+      break;
+    case BinaryConsts::F64x2QFMA:
+      curr = allocator.alloc<SIMDTernary>();
+      curr->op = QFMAF64x2;
+      break;
+    case BinaryConsts::F64x2QFMS:
+      curr = allocator.alloc<SIMDTernary>();
+      curr->op = QFMSF64x2;
+      break;
+    default:
+      return false;
+  }
+  curr->c = popNonVoidExpression();
+  curr->b = popNonVoidExpression();
+  curr->a = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitSIMDShift(Expression*& out, uint32_t code) {
+  SIMDShift* curr;
+  switch (code) {
+    case BinaryConsts::I8x16Shl:
+      curr = allocator.alloc<SIMDShift>();
+      curr->op = ShlVecI8x16;
+      break;
+    case BinaryConsts::I8x16ShrS:
+      curr = allocator.alloc<SIMDShift>();
+      curr->op = ShrSVecI8x16;
+      break;
+    case BinaryConsts::I8x16ShrU:
+      curr = allocator.alloc<SIMDShift>();
+      curr->op = ShrUVecI8x16;
+      break;
+    case BinaryConsts::I16x8Shl:
+      curr = allocator.alloc<SIMDShift>();
+      curr->op = ShlVecI16x8;
+      break;
+    case BinaryConsts::I16x8ShrS:
+      curr = allocator.alloc<SIMDShift>();
+      curr->op = ShrSVecI16x8;
+      break;
+    case BinaryConsts::I16x8ShrU:
+      curr = allocator.alloc<SIMDShift>();
+      curr->op = ShrUVecI16x8;
+      break;
+    case BinaryConsts::I32x4Shl:
+      curr = allocator.alloc<SIMDShift>();
+      curr->op = ShlVecI32x4;
+      break;
+    case BinaryConsts::I32x4ShrS:
+      curr = allocator.alloc<SIMDShift>();
+      curr->op = ShrSVecI32x4;
+      break;
+    case BinaryConsts::I32x4ShrU:
+      curr = allocator.alloc<SIMDShift>();
+      curr->op = ShrUVecI32x4;
+      break;
+    case BinaryConsts::I64x2Shl:
+      curr = allocator.alloc<SIMDShift>();
+      curr->op = ShlVecI64x2;
+      break;
+    case BinaryConsts::I64x2ShrS:
+      curr = allocator.alloc<SIMDShift>();
+      curr->op = ShrSVecI64x2;
+      break;
+    case BinaryConsts::I64x2ShrU:
+      curr = allocator.alloc<SIMDShift>();
+      curr->op = ShrUVecI64x2;
+      break;
+    default:
+      return false;
+  }
+  curr->shift = popNonVoidExpression();
+  curr->vec = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitSIMDLoad(Expression*& out, uint32_t code) {
+  if (code == BinaryConsts::V128Load) {
+    auto* curr = allocator.alloc<Load>();
+    curr->type = Type::v128;
+    curr->bytes = 16;
+    readMemoryAccess(curr->align, curr->offset);
+    curr->isAtomic = false;
+    curr->ptr = popNonVoidExpression();
+    curr->finalize();
+    out = curr;
+    return true;
+  }
+  SIMDLoad* curr;
+  switch (code) {
+    case BinaryConsts::V8x16LoadSplat:
+      curr = allocator.alloc<SIMDLoad>();
+      curr->op = LoadSplatVec8x16;
+      break;
+    case BinaryConsts::V16x8LoadSplat:
+      curr = allocator.alloc<SIMDLoad>();
+      curr->op = LoadSplatVec16x8;
+      break;
+    case BinaryConsts::V32x4LoadSplat:
+      curr = allocator.alloc<SIMDLoad>();
+      curr->op = LoadSplatVec32x4;
+      break;
+    case BinaryConsts::V64x2LoadSplat:
+      curr = allocator.alloc<SIMDLoad>();
+      curr->op = LoadSplatVec64x2;
+      break;
+    case BinaryConsts::I16x8LoadExtSVec8x8:
+      curr = allocator.alloc<SIMDLoad>();
+      curr->op = LoadExtSVec8x8ToVecI16x8;
+      break;
+    case BinaryConsts::I16x8LoadExtUVec8x8:
+      curr = allocator.alloc<SIMDLoad>();
+      curr->op = LoadExtUVec8x8ToVecI16x8;
+      break;
+    case BinaryConsts::I32x4LoadExtSVec16x4:
+      curr = allocator.alloc<SIMDLoad>();
+      curr->op = LoadExtSVec16x4ToVecI32x4;
+      break;
+    case BinaryConsts::I32x4LoadExtUVec16x4:
+      curr = allocator.alloc<SIMDLoad>();
+      curr->op = LoadExtUVec16x4ToVecI32x4;
+      break;
+    case BinaryConsts::I64x2LoadExtSVec32x2:
+      curr = allocator.alloc<SIMDLoad>();
+      curr->op = LoadExtSVec32x2ToVecI64x2;
+      break;
+    case BinaryConsts::I64x2LoadExtUVec32x2:
+      curr = allocator.alloc<SIMDLoad>();
+      curr->op = LoadExtUVec32x2ToVecI64x2;
+      break;
+    case BinaryConsts::V128Load32Zero:
+      curr = allocator.alloc<SIMDLoad>();
+      curr->op = Load32Zero;
+      break;
+    case BinaryConsts::V128Load64Zero:
+      curr = allocator.alloc<SIMDLoad>();
+      curr->op = Load64Zero;
+      break;
+    default:
+      return false;
+  }
+  readMemoryAccess(curr->align, curr->offset);
+  curr->ptr = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  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) {
+    size_t numTypes = getU32LEB();
+    std::vector<Type> types;
+    for (size_t i = 0; i < numTypes; i++) {
+      types.push_back(getType());
+    }
+    curr->type = Type(types);
+  }
+  curr->condition = popNonVoidExpression();
+  curr->ifFalse = popNonVoidExpression();
+  curr->ifTrue = popNonVoidExpression();
+  if (code == BinaryConsts::SelectWithType) {
+    curr->finalize(curr->type);
+  } else {
+    curr->finalize();
+  }
+}
+
+void WasmBinaryBuilder::visitReturn(Return* curr) {
+  BYN_TRACE("zz node: Return\n");
+  requireFunctionContext("return");
+  if (currFunction->sig.results.isConcrete()) {
+    curr->value = popTypedExpression(currFunction->sig.results);
+  }
+  curr->finalize();
+}
+
+void WasmBinaryBuilder::visitMemorySize(MemorySize* curr) {
+  BYN_TRACE("zz node: MemorySize\n");
+  auto reserved = getU32LEB();
+  if (reserved != 0) {
+    throwError("Invalid reserved field on memory.size");
+  }
+  curr->finalize();
+}
+
+void WasmBinaryBuilder::visitMemoryGrow(MemoryGrow* curr) {
+  BYN_TRACE("zz node: MemoryGrow\n");
+  curr->delta = popNonVoidExpression();
+  auto reserved = getU32LEB();
+  if (reserved != 0) {
+    throwError("Invalid reserved field on memory.grow");
+  }
+  curr->finalize();
+}
+
+void WasmBinaryBuilder::visitNop(Nop* curr) { BYN_TRACE("zz node: Nop\n"); }
+
+void WasmBinaryBuilder::visitUnreachable(Unreachable* curr) {
+  BYN_TRACE("zz node: Unreachable\n");
+}
+
+void WasmBinaryBuilder::visitDrop(Drop* curr) {
+  BYN_TRACE("zz node: Drop\n");
+  curr->value = popNonVoidExpression();
+  curr->finalize();
+}
+
+void WasmBinaryBuilder::visitRefNull(RefNull* curr) {
+  BYN_TRACE("zz node: RefNull\n");
+  curr->finalize(getHeapType());
+}
+
+void WasmBinaryBuilder::visitRefIsNull(RefIsNull* curr) {
+  BYN_TRACE("zz node: RefIsNull\n");
+  curr->value = popNonVoidExpression();
+  curr->finalize();
+}
+
+void WasmBinaryBuilder::visitRefFunc(RefFunc* curr) {
+  BYN_TRACE("zz node: RefFunc\n");
+  Index index = getU32LEB();
+  if (index >= functionImports.size() + functionSignatures.size()) {
+    throwError("ref.func: invalid call index");
+  }
+  functionRefs[index].push_back(curr); // we don't know function names yet
+  curr->finalize();
+}
+
+void WasmBinaryBuilder::visitRefEq(RefEq* curr) {
+  BYN_TRACE("zz node: RefEq\n");
+  curr->right = popNonVoidExpression();
+  curr->left = popNonVoidExpression();
+  curr->finalize();
+}
+
+void WasmBinaryBuilder::visitTryOrTryInBlock(Expression*& out) {
+  BYN_TRACE("zz node: Try\n");
+  auto* curr = allocator.alloc<Try>();
+  startControlFlow(curr);
+  // For simplicity of implementation, like if scopes, we create a hidden block
+  // within each try-body and catch-body, and let branches target those inner
+  // blocks instead.
+  curr->type = getType();
+  curr->body = getBlockOrSingleton(curr->type);
+  if (lastSeparator != BinaryConsts::Catch) {
+    throwError("No catch instruction within a try scope");
+  }
+
+  // For simplicity, we create an inner block within the catch body too, but the
+  // one within the 'catch' *must* be omitted when we write out the binary back
+  // later, because the 'catch' instruction pushes a value onto the stack and
+  // the inner block does not support block input parameters without multivalue
+  // support.
+  // try
+  //   ...
+  // catch    ;; Pushes a value onto the stack
+  //   block  ;; Inner block. Should be deleted when writing binary!
+  //     use the pushed value
+  //   end
+  // end
+  //
+  // But when input binary code is like
+  // try
+  //   ...
+  // catch
+  //   br 0
+  // end
+  //
+  // 'br 0' accidentally happens to target the inner block, creating code like
+  // this in Binaryen IR, making the inner block not deletable, resulting in a
+  // validation error:
+  // (try
+  //   ...
+  //   (catch
+  //     (block $label0 ;; Cannot be deleted, because there's a branch to this
+  //       ...
+  //       (br $label0)
+  //     )
+  //   )
+  // )
+  //
+  // When this happens, we fix this by creating a block that wraps the whole
+  // try-catch, and making the branches target that block instead, like this:
+  // (block $label  ;; New enclosing block, new target for the branch
+  //   (try
+  //     ...
+  //     (catch
+  //       (block   ;; Now this can be deleted when writing binary
+  //         ...
+  //         (br $label0)
+  //       )
+  //     )
+  //   )
+  // )
+  Name catchLabel = getNextLabel();
+  breakStack.push_back({catchLabel, curr->type});
+  auto start = expressionStack.size();
+
+  Builder builder(wasm);
+  pushExpression(builder.makePop(Type::exnref));
+
+  processExpressions();
+  size_t end = expressionStack.size();
+  if (start > end) {
+    throwError("block cannot pop from outside");
+  }
+  if (end - start == 1) {
+    curr->catchBody = popExpression();
+  } else {
+    auto* block = allocator.alloc<Block>();
+    pushBlockElements(block, curr->type, start);
+    block->finalize(curr->type);
+    curr->catchBody = block;
+  }
+  curr->finalize(curr->type);
+
+  if (breakTargetNames.find(catchLabel) == breakTargetNames.end()) {
+    out = curr;
+  } else {
+    // Create a new block that encloses the whole try-catch
+    auto* block = builder.makeBlock(catchLabel, curr);
+    out = block;
+  }
+  breakStack.pop_back();
+  breakTargetNames.erase(catchLabel);
+}
+
+void WasmBinaryBuilder::visitThrow(Throw* curr) {
+  BYN_TRACE("zz node: Throw\n");
+  auto index = getU32LEB();
+  if (index >= wasm.events.size()) {
+    throwError("bad event index");
+  }
+  auto* event = wasm.events[index].get();
+  curr->event = event->name;
+  size_t num = event->sig.params.size();
+  curr->operands.resize(num);
+  for (size_t i = 0; i < num; i++) {
+    curr->operands[num - i - 1] = popNonVoidExpression();
+  }
+  curr->finalize();
+}
+
+void WasmBinaryBuilder::visitRethrow(Rethrow* curr) {
+  BYN_TRACE("zz node: Rethrow\n");
+  curr->exnref = popNonVoidExpression();
+  curr->finalize();
+}
+
+void WasmBinaryBuilder::visitBrOnExn(BrOnExn* curr) {
+  BYN_TRACE("zz node: BrOnExn\n");
+  BreakTarget target = getBreakTarget(getU32LEB());
+  curr->name = target.name;
+  auto index = getU32LEB();
+  if (index >= wasm.events.size()) {
+    throwError("bad event index");
+  }
+  curr->event = wasm.events[index]->name;
+  curr->exnref = popNonVoidExpression();
+
+  Event* event = wasm.getEventOrNull(curr->event);
+  assert(event && "br_on_exn's event must exist");
+
+  // Copy params info into BrOnExn, because it is necessary when BrOnExn is
+  // refinalized without the module.
+  curr->sent = event->sig.params;
+  curr->finalize();
+}
+
+bool WasmBinaryBuilder::maybeVisitI31New(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::I31New) {
+    return false;
+  }
+  auto* curr = allocator.alloc<I31New>();
+  curr->value = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitI31Get(Expression*& out, uint32_t code) {
+  I31Get* curr;
+  switch (code) {
+    case BinaryConsts::I31GetS:
+      curr = allocator.alloc<I31Get>();
+      curr->signed_ = true;
+      break;
+    case BinaryConsts::I31GetU:
+      curr = allocator.alloc<I31Get>();
+      curr->signed_ = false;
+      break;
+    default:
+      return false;
+  }
+  curr->i31 = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitRefTest(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::RefTest) {
+    return false;
+  }
+  auto* curr = allocator.alloc<RefTest>();
+  WASM_UNREACHABLE("TODO (gc): ref.test");
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitRefCast(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::RefCast) {
+    return false;
+  }
+  auto* curr = allocator.alloc<RefCast>();
+  WASM_UNREACHABLE("TODO (gc): ref.cast");
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitBrOnCast(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::BrOnCast) {
+    return false;
+  }
+  auto* curr = allocator.alloc<BrOnCast>();
+  WASM_UNREACHABLE("TODO (gc): br_on_cast");
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitRttCanon(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::RttCanon) {
+    return false;
+  }
+  auto* curr = allocator.alloc<RttCanon>();
+  WASM_UNREACHABLE("TODO (gc): rtt.canon");
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitRttSub(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::RttSub) {
+    return false;
+  }
+  auto* curr = allocator.alloc<RttSub>();
+  WASM_UNREACHABLE("TODO (gc): rtt.sub");
+  curr->finalize();
+  out = curr;
+  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;
+  }
+  WASM_UNREACHABLE("TODO (gc): struct.new");
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitStructGet(Expression*& out, uint32_t code) {
+  StructGet* curr;
+  switch (code) {
+    case BinaryConsts::StructGet:
+      curr = allocator.alloc<StructGet>();
+      // ...
+      break;
+    case BinaryConsts::StructGetS:
+      curr = allocator.alloc<StructGet>();
+      // ...
+      break;
+    case BinaryConsts::StructGetU:
+      curr = allocator.alloc<StructGet>();
+      // ...
+      break;
+    default:
+      return false;
+  }
+  WASM_UNREACHABLE("TODO (gc): struct.get");
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitStructSet(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::StructSet) {
+    return false;
+  }
+  auto* curr = allocator.alloc<StructSet>();
+  WASM_UNREACHABLE("TODO (gc): struct.set");
+  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;
+  }
+  WASM_UNREACHABLE("TODO (gc): array.new");
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitArrayGet(Expression*& out, uint32_t code) {
+  ArrayGet* curr;
+  switch (code) {
+    case BinaryConsts::ArrayGet:
+      curr = allocator.alloc<ArrayGet>();
+      // ...
+      break;
+    case BinaryConsts::ArrayGetS:
+      curr = allocator.alloc<ArrayGet>();
+      // ...
+      break;
+    case BinaryConsts::ArrayGetU:
+      curr = allocator.alloc<ArrayGet>();
+      // ...
+      break;
+    default:
+      return false;
+  }
+  WASM_UNREACHABLE("TODO (gc): array.get");
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitArraySet(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::ArraySet) {
+    return false;
+  }
+  auto* curr = allocator.alloc<ArraySet>();
+  WASM_UNREACHABLE("TODO (gc): array.set");
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitArrayLen(Expression*& out, uint32_t code) {
+  if (code != BinaryConsts::ArrayLen) {
+    return false;
+  }
+  auto* curr = allocator.alloc<ArrayLen>();
+  WASM_UNREACHABLE("TODO (gc): array.len");
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+void WasmBinaryBuilder::throwError(std::string text) {
+  throw ParseException(text, 0, pos);
+}
+
+} // namespace wasm
diff --git a/binaryen/src/wasm/wasm-debug.cpp b/binaryen/src/wasm/wasm-debug.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm/wasm-debug.cpp
@@ -0,0 +1,1078 @@
+/*
+ * Copyright 2019 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wasm-debug.h"
+#include "wasm.h"
+
+#ifdef BUILD_LLVM_DWARF
+#include "llvm/ObjectYAML/DWARFEmitter.h"
+#include "llvm/ObjectYAML/DWARFYAML.h"
+#include "llvm/include/llvm/DebugInfo/DWARFContext.h"
+
+std::error_code dwarf2yaml(llvm::DWARFContext& DCtx, llvm::DWARFYAML::Data& Y);
+#endif
+
+#include "wasm-binary.h"
+#include "wasm-debug.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace Debug {
+
+bool isDWARFSection(Name name) { return name.startsWith(".debug_"); }
+
+bool hasDWARFSections(const Module& wasm) {
+  for (auto& section : wasm.userSections) {
+    if (isDWARFSection(section.name)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+#ifdef BUILD_LLVM_DWARF
+
+// In wasm32 the address size is 32 bits.
+static const size_t AddressSize = 4;
+
+struct BinaryenDWARFInfo {
+  llvm::StringMap<std::unique_ptr<llvm::MemoryBuffer>> sections;
+  std::unique_ptr<llvm::DWARFContext> context;
+
+  BinaryenDWARFInfo(const Module& wasm) {
+    // Get debug sections from the wasm.
+    for (auto& section : wasm.userSections) {
+      if (Name(section.name).startsWith(".debug_") && section.data.data()) {
+        // TODO: efficiency
+        sections[section.name.substr(1)] = llvm::MemoryBuffer::getMemBufferCopy(
+          llvm::StringRef(section.data.data(), section.data.size()));
+      }
+    }
+    // Parse debug sections.
+    uint8_t addrSize = AddressSize;
+    bool isLittleEndian = true;
+    context = llvm::DWARFContext::create(sections, addrSize, isLittleEndian);
+  }
+};
+
+void dumpDWARF(const Module& wasm) {
+  BinaryenDWARFInfo info(wasm);
+  std::cout << "DWARF debug info\n";
+  std::cout << "================\n\n";
+  for (auto& section : wasm.userSections) {
+    if (Name(section.name).startsWith(".debug_")) {
+      std::cout << "Contains section " << section.name << " ("
+                << section.data.size() << " bytes)\n";
+    }
+  }
+  llvm::DIDumpOptions options;
+  options.DumpType = llvm::DIDT_All;
+  options.ShowChildren = true;
+  options.Verbose = true;
+  info.context->dump(llvm::outs(), options);
+}
+
+//
+// Big picture: We use a DWARFContext to read data, then DWARFYAML support
+// code to write it. That is not the main LLVM Dwarf code used for writing
+// object files, but it avoids us create a "fake" MC layer, and provides a
+// simple way to write out the debug info. Likely the level of info represented
+// in the DWARFYAML::Data object is sufficient for Binaryen's needs, but if not,
+// we may need a different approach.
+//
+// In more detail:
+//
+// 1. Binary sections => DWARFContext:
+//
+//     llvm::DWARFContext::create(sections..)
+//
+// 2. DWARFContext => DWARFYAML::Data
+//
+//     std::error_code dwarf2yaml(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+//
+// 3. DWARFYAML::Data => binary sections
+//
+//     StringMap<std::unique_ptr<MemoryBuffer>>
+//     EmitDebugSections(llvm::DWARFYAML::Data &DI, bool ApplyFixups);
+//
+
+// Represents the state when parsing a line table.
+struct LineState {
+  uint32_t addr = 0;
+  // TODO sectionIndex?
+  uint32_t line = 1;
+  uint32_t col = 0;
+  uint32_t file = 1;
+  uint32_t isa = 0;
+  uint32_t discriminator = 0;
+  bool isStmt;
+  bool basicBlock = false;
+  bool prologueEnd = false;
+  bool epilogueBegin = false;
+  // Each instruction is part of a sequence, all of which get the same ID. The
+  // order within a sequence may change if binaryen reorders things, which means
+  // that we can't track the end_sequence location and assume it is at the end -
+  // we must track sequences and then emit an end for each one.
+  // -1 is an invalid marker value (note that this assumes we can fit all ids
+  // into just under 32 bits).
+  uint32_t sequenceId = -1;
+
+  LineState(const LineState& other) = default;
+  LineState(const llvm::DWARFYAML::LineTable& table, uint32_t sequenceId)
+    : isStmt(table.DefaultIsStmt), sequenceId(sequenceId) {}
+
+  LineState& operator=(const LineState& other) = default;
+
+  // Updates the state, and returns whether a new row is ready to be emitted.
+  bool update(llvm::DWARFYAML::LineTableOpcode& opcode,
+              const llvm::DWARFYAML::LineTable& table) {
+    switch (opcode.Opcode) {
+      case 0: {
+        // Extended opcodes
+        switch (opcode.SubOpcode) {
+          case llvm::dwarf::DW_LNE_set_address: {
+            addr = opcode.Data;
+            break;
+          }
+          case llvm::dwarf::DW_LNE_end_sequence: {
+            return true;
+          }
+          case llvm::dwarf::DW_LNE_set_discriminator: {
+            discriminator = opcode.Data;
+            break;
+          }
+          case llvm::dwarf::DW_LNE_define_file: {
+            Fatal() << "TODO: DW_LNE_define_file";
+          }
+          default: {
+            // An unknown opcode, ignore.
+            std::cerr << "warning: unknown subopcopde " << opcode.SubOpcode
+                      << '\n';
+          }
+        }
+        break;
+      }
+      case llvm::dwarf::DW_LNS_set_column: {
+        col = opcode.Data;
+        break;
+      }
+      case llvm::dwarf::DW_LNS_set_prologue_end: {
+        prologueEnd = true;
+        break;
+      }
+      case llvm::dwarf::DW_LNS_copy: {
+        return true;
+      }
+      case llvm::dwarf::DW_LNS_advance_pc: {
+        assert(table.MinInstLength == 1);
+        addr += opcode.Data;
+        break;
+      }
+      case llvm::dwarf::DW_LNS_advance_line: {
+        line += opcode.SData;
+        break;
+      }
+      case llvm::dwarf::DW_LNS_set_file: {
+        file = opcode.Data;
+        break;
+      }
+      case llvm::dwarf::DW_LNS_negate_stmt: {
+        isStmt = !isStmt;
+        break;
+      }
+      case llvm::dwarf::DW_LNS_set_basic_block: {
+        basicBlock = true;
+        break;
+      }
+      case llvm::dwarf::DW_LNS_const_add_pc: {
+        uint8_t AdjustOpcode = 255 - table.OpcodeBase;
+        uint64_t AddrOffset =
+          (AdjustOpcode / table.LineRange) * table.MinInstLength;
+        addr += AddrOffset;
+        break;
+      }
+      case llvm::dwarf::DW_LNS_fixed_advance_pc: {
+        addr += opcode.Data;
+        break;
+      }
+      case llvm::dwarf::DW_LNS_set_isa: {
+        isa = opcode.Data;
+        break;
+      }
+      default: {
+        if (opcode.Opcode >= table.OpcodeBase) {
+          // Special opcode: adjust line and addr, using some math.
+          uint8_t AdjustOpcode =
+            opcode.Opcode - table.OpcodeBase; // 20 - 13 = 7
+          uint64_t AddrOffset = (AdjustOpcode / table.LineRange) *
+                                table.MinInstLength; // (7 / 14) * 1 = 0
+          int32_t LineOffset =
+            table.LineBase +
+            (AdjustOpcode % table.LineRange); // -5 + (7 % 14) = 2
+          line += LineOffset;
+          addr += AddrOffset;
+          return true;
+        } else {
+          Fatal() << "unknown debug line opcode: " << std::hex << opcode.Opcode;
+        }
+      }
+    }
+    return false;
+  }
+
+  // Checks if this starts a new range of addresses. Each range is a set of
+  // related addresses, where in particular, if the first has been zeroed out
+  // by the linker, we must omit the entire range. (If we do not, then the
+  // initial range is 0 and the others are offsets relative to it, which will
+  // look like random addresses, perhaps into the middle of instructions, and
+  // perhaps that happen to collide with real ones.)
+  bool startsNewRange(llvm::DWARFYAML::LineTableOpcode& opcode) {
+    return opcode.Opcode == 0 &&
+           opcode.SubOpcode == llvm::dwarf::DW_LNE_set_address;
+  }
+
+  bool needToEmit() {
+    // Zero values imply we can ignore this line.
+    // https://github.com/WebAssembly/debugging/issues/9#issuecomment-567720872
+    return line != 0 && addr != 0;
+  }
+
+  // Given an old state, emit the diff from it to this state into a new line
+  // table entry (that will be emitted in the updated DWARF debug line section).
+  void emitDiff(const LineState& old,
+                std::vector<llvm::DWARFYAML::LineTableOpcode>& newOpcodes,
+                const llvm::DWARFYAML::LineTable& table,
+                bool endSequence) const {
+    bool useSpecial = false;
+    if (addr != old.addr || line != old.line) {
+      // Try to use a special opcode TODO
+    }
+    if (addr != old.addr && !useSpecial) {
+      // len = 1 (subopcode) + 4 (wasm32 address)
+      // FIXME: look at AddrSize on the Unit.
+      auto item = makeItem(llvm::dwarf::DW_LNE_set_address, 5);
+      item.Data = addr;
+      newOpcodes.push_back(item);
+    }
+    if (line != old.line && !useSpecial) {
+      auto item = makeItem(llvm::dwarf::DW_LNS_advance_line);
+      // In wasm32 we have 32-bit addresses, and the delta here might be
+      // negative (note that SData is 64-bit, as LLVM supports 64-bit
+      // addresses too).
+      item.SData = int32_t(line - old.line);
+      newOpcodes.push_back(item);
+    }
+    if (col != old.col) {
+      auto item = makeItem(llvm::dwarf::DW_LNS_set_column);
+      item.Data = col;
+      newOpcodes.push_back(item);
+    }
+    if (file != old.file) {
+      auto item = makeItem(llvm::dwarf::DW_LNS_set_file);
+      item.Data = file;
+      newOpcodes.push_back(item);
+    }
+    if (isa != old.isa) {
+      auto item = makeItem(llvm::dwarf::DW_LNS_set_isa);
+      item.Data = isa;
+      newOpcodes.push_back(item);
+    }
+    if (discriminator != old.discriminator) {
+      // len = 1 (subopcode) + 4 (wasm32 address)
+      auto item = makeItem(llvm::dwarf::DW_LNE_set_discriminator, 5);
+      item.Data = discriminator;
+      newOpcodes.push_back(item);
+    }
+    if (isStmt != old.isStmt) {
+      newOpcodes.push_back(makeItem(llvm::dwarf::DW_LNS_negate_stmt));
+    }
+    if (basicBlock != old.basicBlock) {
+      assert(basicBlock);
+      newOpcodes.push_back(makeItem(llvm::dwarf::DW_LNS_set_basic_block));
+    }
+    if (prologueEnd) {
+      newOpcodes.push_back(makeItem(llvm::dwarf::DW_LNS_set_prologue_end));
+    }
+    if (epilogueBegin != old.epilogueBegin) {
+      Fatal() << "eb";
+    }
+    if (useSpecial) {
+      // Emit a special, which emits a line automatically.
+      // TODO
+    } else {
+      // Emit the line manually.
+      if (endSequence) {
+        // len = 1 (subopcode)
+        newOpcodes.push_back(makeItem(llvm::dwarf::DW_LNE_end_sequence, 1));
+      } else {
+        newOpcodes.push_back(makeItem(llvm::dwarf::DW_LNS_copy));
+      }
+    }
+  }
+
+  // Some flags are automatically reset after each debug line.
+  void resetAfterLine() { prologueEnd = false; }
+
+private:
+  llvm::DWARFYAML::LineTableOpcode
+  makeItem(llvm::dwarf::LineNumberOps opcode) const {
+    llvm::DWARFYAML::LineTableOpcode item = {};
+    item.Opcode = opcode;
+    return item;
+  }
+
+  llvm::DWARFYAML::LineTableOpcode
+  makeItem(llvm::dwarf::LineNumberExtendedOps opcode, uint64_t len) const {
+    auto item = makeItem(llvm::dwarf::LineNumberOps(0));
+    // All the length after the len field itself, including the subopcode
+    // (1 byte).
+    item.ExtLen = len;
+    item.SubOpcode = opcode;
+    return item;
+  }
+};
+
+// Represents a mapping of addresses to expressions. We track beginnings and
+// endings of expressions separately, since the end of one (which is one past
+// the end in DWARF notation) overlaps with the beginning of the next, and also
+// to let us use contextual information (we may know we are looking up the end
+// of an instruction).
+struct AddrExprMap {
+  std::unordered_map<BinaryLocation, Expression*> startMap;
+  std::unordered_map<BinaryLocation, Expression*> endMap;
+
+  // Some instructions have delimiter binary locations, like the else and end in
+  // and if. Track those separately, including their expression and their id
+  // ("else", "end", etc.), as they are rare, and we don't want to
+  // bloat the common case which is represented in the earlier maps.
+  struct DelimiterInfo {
+    Expression* expr;
+    BinaryLocations::DelimiterId id;
+  };
+  std::unordered_map<BinaryLocation, DelimiterInfo> delimiterMap;
+
+  // Construct the map from the binaryLocations loaded from the wasm.
+  AddrExprMap(const Module& wasm) {
+    for (auto& func : wasm.functions) {
+      for (auto pair : func->expressionLocations) {
+        add(pair.first, pair.second);
+      }
+      for (auto pair : func->delimiterLocations) {
+        add(pair.first, pair.second);
+      }
+    }
+  }
+
+  Expression* getStart(BinaryLocation addr) const {
+    auto iter = startMap.find(addr);
+    if (iter != startMap.end()) {
+      return iter->second;
+    }
+    return nullptr;
+  }
+
+  Expression* getEnd(BinaryLocation addr) const {
+    auto iter = endMap.find(addr);
+    if (iter != endMap.end()) {
+      return iter->second;
+    }
+    return nullptr;
+  }
+
+  DelimiterInfo getDelimiter(BinaryLocation addr) const {
+    auto iter = delimiterMap.find(addr);
+    if (iter != delimiterMap.end()) {
+      return iter->second;
+    }
+    return DelimiterInfo{nullptr, BinaryLocations::Invalid};
+  }
+
+private:
+  void add(Expression* expr, const BinaryLocations::Span span) {
+    assert(startMap.count(span.start) == 0);
+    startMap[span.start] = expr;
+    assert(endMap.count(span.end) == 0);
+    endMap[span.end] = expr;
+  }
+
+  void add(Expression* expr,
+           const BinaryLocations::DelimiterLocations& delimiter) {
+    for (Index i = 0; i < delimiter.size(); i++) {
+      if (delimiter[i] != 0) {
+        assert(delimiterMap.count(delimiter[i]) == 0);
+        delimiterMap[delimiter[i]] =
+          DelimiterInfo{expr, BinaryLocations::DelimiterId(i)};
+      }
+    }
+  }
+};
+
+// Represents a mapping of addresses to expressions. As with expressions, we
+// track both start and end; here, however, "start" means the "start" and
+// "declarations" fields in FunctionLocations, and "end" means the two locations
+// of one past the end, and one before it which is the "end" opcode that is
+// emitted.
+struct FuncAddrMap {
+  std::unordered_map<BinaryLocation, Function*> startMap, endMap;
+
+  // Construct the map from the binaryLocations loaded from the wasm.
+  FuncAddrMap(const Module& wasm) {
+    for (auto& func : wasm.functions) {
+      startMap[func->funcLocation.start] = func.get();
+      startMap[func->funcLocation.declarations] = func.get();
+      endMap[func->funcLocation.end - 1] = func.get();
+      endMap[func->funcLocation.end] = func.get();
+    }
+  }
+
+  Function* getStart(BinaryLocation addr) const {
+    auto iter = startMap.find(addr);
+    if (iter != startMap.end()) {
+      return iter->second;
+    }
+    return nullptr;
+  }
+
+  Function* getEnd(BinaryLocation addr) const {
+    auto iter = endMap.find(addr);
+    if (iter != endMap.end()) {
+      return iter->second;
+    }
+    return nullptr;
+  }
+};
+
+// Track locations from the original binary and the new one we wrote, so that
+// we can update debug positions.
+// We track expressions and functions separately, instead of having a single
+// big map of (oldAddr) => (newAddr) because of the potentially ambiguous case
+// of the final expression in a function: it's end might be identical in offset
+// to the end of the function. So we have two different things that map to the
+// same offset. However, if the context is "the end of the function" then the
+// updated address is the new end of the function, even if the function ends
+// with a different instruction now, as the old last instruction might have
+// moved or been optimized out.
+struct LocationUpdater {
+  Module& wasm;
+  const BinaryLocations& newLocations;
+
+  AddrExprMap oldExprAddrMap;
+  FuncAddrMap oldFuncAddrMap;
+
+  // Map offsets of location list entries in the debug_loc section to the index
+  // of their compile unit.
+  std::unordered_map<BinaryLocation, size_t> locToUnitMap;
+
+  // Map start of line tables in the debug_line section to their new locations.
+  std::unordered_map<BinaryLocation, BinaryLocation> debugLineMap;
+
+  typedef std::pair<BinaryLocation, BinaryLocation> OldToNew;
+
+  // Map of compile unit index => old and new base offsets (i.e., in the
+  // original binary and in the new one).
+  std::unordered_map<size_t, OldToNew> compileUnitBases;
+
+  // TODO: for memory efficiency, we may want to do this in a streaming manner,
+  //       binary to binary, without YAML IR.
+
+  LocationUpdater(Module& wasm, const BinaryLocations& newLocations)
+    : wasm(wasm), newLocations(newLocations), oldExprAddrMap(wasm),
+      oldFuncAddrMap(wasm) {}
+
+  // Updates an expression's address. If there was never an instruction at that
+  // address, or if there was but if that instruction no longer exists, return
+  // 0. Otherwise, return the new updated location.
+  BinaryLocation getNewExprStart(BinaryLocation oldAddr) const {
+    if (auto* expr = oldExprAddrMap.getStart(oldAddr)) {
+      auto iter = newLocations.expressions.find(expr);
+      if (iter != newLocations.expressions.end()) {
+        BinaryLocation newAddr = iter->second.start;
+        return newAddr;
+      }
+    }
+    return 0;
+  }
+
+  bool hasOldExprStart(BinaryLocation oldAddr) const {
+    return oldExprAddrMap.getStart(oldAddr);
+  }
+
+  BinaryLocation getNewExprEnd(BinaryLocation oldAddr) const {
+    if (auto* expr = oldExprAddrMap.getEnd(oldAddr)) {
+      auto iter = newLocations.expressions.find(expr);
+      if (iter != newLocations.expressions.end()) {
+        return iter->second.end;
+      }
+    }
+    return 0;
+  }
+
+  bool hasOldExprEnd(BinaryLocation oldAddr) const {
+    return oldExprAddrMap.getEnd(oldAddr);
+  }
+
+  BinaryLocation getNewFuncStart(BinaryLocation oldAddr) const {
+    if (auto* func = oldFuncAddrMap.getStart(oldAddr)) {
+      // The function might have been optimized away, check.
+      auto iter = newLocations.functions.find(func);
+      if (iter != newLocations.functions.end()) {
+        auto oldLocations = func->funcLocation;
+        auto newLocations = iter->second;
+        if (oldAddr == oldLocations.start) {
+          return newLocations.start;
+        } else if (oldAddr == oldLocations.declarations) {
+          return newLocations.declarations;
+        } else {
+          WASM_UNREACHABLE("invalid func start");
+        }
+      }
+    }
+    return 0;
+  }
+
+  bool hasOldFuncStart(BinaryLocation oldAddr) const {
+    return oldFuncAddrMap.getStart(oldAddr);
+  }
+
+  BinaryLocation getNewFuncEnd(BinaryLocation oldAddr) const {
+    if (auto* func = oldFuncAddrMap.getEnd(oldAddr)) {
+      // The function might have been optimized away, check.
+      auto iter = newLocations.functions.find(func);
+      if (iter != newLocations.functions.end()) {
+        auto oldLocations = func->funcLocation;
+        auto newLocations = iter->second;
+        if (oldAddr == oldLocations.end) {
+          return newLocations.end;
+        } else if (oldAddr == oldLocations.end - 1) {
+          return newLocations.end - 1;
+        } else {
+          WASM_UNREACHABLE("invalid func end");
+        }
+      }
+    }
+    return 0;
+  }
+
+  // Check for either the end opcode, or one past the end.
+  bool hasOldFuncEnd(BinaryLocation oldAddr) const {
+    return oldFuncAddrMap.getEnd(oldAddr);
+  }
+
+  // Check specifically for the end opcode.
+  bool hasOldFuncEndOpcode(BinaryLocation oldAddr) const {
+    if (auto* func = oldFuncAddrMap.getEnd(oldAddr)) {
+      return oldAddr == func->funcLocation.end - 1;
+    }
+    return false;
+  }
+
+  BinaryLocation getNewDelimiter(BinaryLocation oldAddr) const {
+    auto info = oldExprAddrMap.getDelimiter(oldAddr);
+    if (info.expr) {
+      auto iter = newLocations.delimiters.find(info.expr);
+      if (iter != newLocations.delimiters.end()) {
+        return iter->second[info.id];
+      }
+    }
+    return 0;
+  }
+
+  bool hasOldDelimiter(BinaryLocation oldAddr) const {
+    return oldExprAddrMap.getDelimiter(oldAddr).expr;
+  }
+
+  // getNewStart|EndAddr utilities.
+  // TODO: should we track the start and end of delimiters, even though they
+  //       are just one byte?
+  BinaryLocation getNewStart(BinaryLocation oldStart) const {
+    if (hasOldExprStart(oldStart)) {
+      return getNewExprStart(oldStart);
+    } else if (hasOldFuncStart(oldStart)) {
+      return getNewFuncStart(oldStart);
+    } else if (hasOldDelimiter(oldStart)) {
+      return getNewDelimiter(oldStart);
+    }
+    return 0;
+  }
+
+  BinaryLocation getNewEnd(BinaryLocation oldEnd) const {
+    if (hasOldExprEnd(oldEnd)) {
+      return getNewExprEnd(oldEnd);
+    } else if (hasOldFuncEnd(oldEnd)) {
+      return getNewFuncEnd(oldEnd);
+    } else if (hasOldDelimiter(oldEnd)) {
+      return getNewDelimiter(oldEnd);
+    }
+    return 0;
+  }
+
+  BinaryLocation getNewDebugLineLocation(BinaryLocation old) const {
+    return debugLineMap.at(old);
+  }
+
+  // Given an offset in .debug_loc, get the old and new compile unit bases.
+  OldToNew getCompileUnitBasesForLoc(size_t offset) const {
+    auto index = locToUnitMap.at(offset);
+    auto iter = compileUnitBases.find(index);
+    if (iter != compileUnitBases.end()) {
+      return iter->second;
+    }
+    return OldToNew{0, 0};
+  }
+};
+
+// 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,
+                             LocationUpdater& locationUpdater) {
+  for (auto& table : data.DebugLines) {
+    uint32_t sequenceId = 0;
+    // Parse the original opcodes and emit new ones.
+    LineState state(table, sequenceId);
+    // All the addresses we need to write out.
+    std::vector<BinaryLocation> newAddrs;
+    std::unordered_map<BinaryLocation, LineState> newAddrInfo;
+    // If the address was zeroed out, we must omit the entire range (we could
+    // also leave it unchanged, so that the debugger ignores it based on the
+    // initial zero; but it's easier and better to just not emit it at all).
+    bool omittingRange = false;
+    for (auto& opcode : table.Opcodes) {
+      // Update the state, and check if we have a new row to emit.
+      if (state.startsNewRange(opcode)) {
+        omittingRange = false;
+      }
+      if (state.update(opcode, table)) {
+        if (state.addr == 0) {
+          omittingRange = true;
+        }
+        if (omittingRange) {
+          state = LineState(table, sequenceId);
+          continue;
+        }
+        // An expression may not exist for this line table item, if we optimized
+        // it away.
+        BinaryLocation oldAddr = state.addr;
+        BinaryLocation newAddr = 0;
+        if (locationUpdater.hasOldExprStart(oldAddr)) {
+          newAddr = locationUpdater.getNewExprStart(oldAddr);
+        }
+        // Test for a function's end address first, as LLVM output appears to
+        // use 1-past-the-end-of-the-function as a location in that function,
+        // and not the next (but the first byte of the next function, which is
+        // ambiguously identical to that value, is used at least in low_pc).
+        else if (locationUpdater.hasOldFuncEnd(oldAddr)) {
+          newAddr = locationUpdater.getNewFuncEnd(oldAddr);
+        } else if (locationUpdater.hasOldFuncStart(oldAddr)) {
+          newAddr = locationUpdater.getNewFuncStart(oldAddr);
+        } else if (locationUpdater.hasOldDelimiter(oldAddr)) {
+          newAddr = locationUpdater.getNewDelimiter(oldAddr);
+        }
+        if (newAddr && state.needToEmit()) {
+          // LLVM sometimes emits the same address more than once. We should
+          // probably investigate that.
+          if (newAddrInfo.count(newAddr)) {
+            continue;
+          }
+          newAddrs.push_back(newAddr);
+          newAddrInfo.emplace(newAddr, state);
+          auto& updatedState = newAddrInfo.at(newAddr);
+          // The only difference is the address TODO other stuff?
+          updatedState.addr = newAddr;
+          // Reset relevant state.
+          state.resetAfterLine();
+        }
+        if (opcode.Opcode == 0 &&
+            opcode.SubOpcode == llvm::dwarf::DW_LNE_end_sequence) {
+          sequenceId++;
+          // We assume the number of sequences can fit in 32 bits, and -1 is
+          // an invalid value.
+          assert(sequenceId != uint32_t(-1));
+          state = LineState(table, sequenceId);
+        }
+      }
+    }
+    // Sort the new addresses (which may be substantially different from the
+    // original layout after optimization).
+    std::sort(newAddrs.begin(), newAddrs.end());
+    // Emit a new line table.
+    {
+      std::vector<llvm::DWARFYAML::LineTableOpcode> newOpcodes;
+      for (size_t i = 0; i < newAddrs.size(); i++) {
+        LineState state = newAddrInfo.at(newAddrs[i]);
+        assert(state.needToEmit());
+        LineState lastState(table, -1);
+        if (i != 0) {
+          lastState = newAddrInfo.at(newAddrs[i - 1]);
+          // If the last line is in another sequence, clear the old state, as
+          // there is nothing to diff to.
+          if (lastState.sequenceId != state.sequenceId) {
+            lastState = LineState(table, -1);
+          }
+        }
+        // This line ends a sequence if there is no next line after it, or if
+        // the next line is in a different sequence.
+        bool endSequence =
+          i + 1 == newAddrs.size() ||
+          newAddrInfo.at(newAddrs[i + 1]).sequenceId != state.sequenceId;
+        state.emitDiff(lastState, newOpcodes, table, endSequence);
+      }
+      table.Opcodes.swap(newOpcodes);
+    }
+  }
+  // After updating the contents, run the emitter in order to update the
+  // lengths of each section. We will use that to update offsets into the
+  // debug_line section.
+  std::vector<size_t> computedLengths;
+  llvm::DWARFYAML::ComputeDebugLine(data, computedLengths);
+  BinaryLocation oldLocation = 0, newLocation = 0;
+  for (size_t i = 0; i < data.DebugLines.size(); i++) {
+    auto& table = data.DebugLines[i];
+    locationUpdater.debugLineMap[oldLocation] = newLocation;
+    oldLocation += table.Length.getLength() + AddressSize;
+    newLocation += computedLengths[i] + AddressSize;
+    table.Length.setLength(computedLengths[i]);
+  }
+}
+
+// Iterate in parallel over a DwarfContext representation element and a
+// YAML element, which parallel each other.
+template<typename T, typename U, typename W>
+static void iterContextAndYAML(const T& contextList, U& yamlList, W func) {
+  auto yamlValue = yamlList.begin();
+  for (const auto& contextValue : contextList) {
+    assert(yamlValue != yamlList.end());
+    func(contextValue, *yamlValue);
+    yamlValue++;
+  }
+  assert(yamlValue == yamlList.end());
+}
+
+// Updates a YAML entry from a DWARF DIE. Also updates LocationUpdater
+// associating each .debug_loc entry with the base address of its corresponding
+// compilation unit.
+static void updateDIE(const llvm::DWARFDebugInfoEntry& DIE,
+                      llvm::DWARFYAML::Entry& yamlEntry,
+                      const llvm::DWARFAbbreviationDeclaration* abbrevDecl,
+                      LocationUpdater& locationUpdater,
+                      size_t compileUnitIndex) {
+  auto tag = DIE.getTag();
+  // Pairs of low/high_pc require some special handling, as the high
+  // may be an offset relative to the low. First, process everything but
+  // the high pcs, so we see the low pcs first.
+  BinaryLocation oldLowPC = 0, newLowPC = 0;
+  iterContextAndYAML(
+    abbrevDecl->attributes(),
+    yamlEntry.Values,
+    [&](const llvm::DWARFAbbreviationDeclaration::AttributeSpec& attrSpec,
+        llvm::DWARFYAML::FormValue& yamlValue) {
+      auto attr = attrSpec.Attr;
+      if (attr == llvm::dwarf::DW_AT_low_pc) {
+        // This is an address.
+        BinaryLocation oldValue = yamlValue.Value, newValue = 0;
+        if (tag == llvm::dwarf::DW_TAG_GNU_call_site ||
+            tag == llvm::dwarf::DW_TAG_inlined_subroutine ||
+            tag == llvm::dwarf::DW_TAG_lexical_block ||
+            tag == llvm::dwarf::DW_TAG_label) {
+          newValue = locationUpdater.getNewStart(oldValue);
+        } else if (tag == llvm::dwarf::DW_TAG_compile_unit) {
+          newValue = locationUpdater.getNewFuncStart(oldValue);
+          // Per the DWARF spec, "The base address of a compile unit is
+          // defined as the value of the DW_AT_low_pc attribute, if present."
+          locationUpdater.compileUnitBases[compileUnitIndex] =
+            LocationUpdater::OldToNew{oldValue, newValue};
+        } else if (tag == llvm::dwarf::DW_TAG_subprogram) {
+          newValue = locationUpdater.getNewFuncStart(oldValue);
+        } else {
+          Fatal() << "unknown tag with low_pc "
+                  << llvm::dwarf::TagString(tag).str();
+        }
+        oldLowPC = oldValue;
+        newLowPC = newValue;
+        yamlValue.Value = newValue;
+      } else if (attr == llvm::dwarf::DW_AT_stmt_list) {
+        // This is an offset into the debug line section.
+        yamlValue.Value =
+          locationUpdater.getNewDebugLineLocation(yamlValue.Value);
+      } else if (attr == llvm::dwarf::DW_AT_location &&
+                 attrSpec.Form == llvm::dwarf::DW_FORM_sec_offset) {
+        BinaryLocation locOffset = yamlValue.Value;
+        locationUpdater.locToUnitMap[locOffset] = compileUnitIndex;
+      }
+    });
+  // Next, process the high_pcs.
+  // TODO: do this more efficiently, without a second traversal (but that's a
+  //       little tricky given the special double-traversal we have).
+  iterContextAndYAML(
+    abbrevDecl->attributes(),
+    yamlEntry.Values,
+    [&](const llvm::DWARFAbbreviationDeclaration::AttributeSpec& attrSpec,
+        llvm::DWARFYAML::FormValue& yamlValue) {
+      auto attr = attrSpec.Attr;
+      if (attr != llvm::dwarf::DW_AT_high_pc) {
+        return;
+      }
+      BinaryLocation oldValue = yamlValue.Value, newValue = 0;
+      bool isRelative = attrSpec.Form == llvm::dwarf::DW_FORM_data4;
+      if (isRelative) {
+        oldValue += oldLowPC;
+      }
+      if (tag == llvm::dwarf::DW_TAG_GNU_call_site ||
+          tag == llvm::dwarf::DW_TAG_inlined_subroutine ||
+          tag == llvm::dwarf::DW_TAG_lexical_block ||
+          tag == llvm::dwarf::DW_TAG_label) {
+        newValue = locationUpdater.getNewExprEnd(oldValue);
+      } else if (tag == llvm::dwarf::DW_TAG_compile_unit ||
+                 tag == llvm::dwarf::DW_TAG_subprogram) {
+        newValue = locationUpdater.getNewFuncEnd(oldValue);
+      } else {
+        Fatal() << "unknown tag with low_pc "
+                << llvm::dwarf::TagString(tag).str();
+      }
+      if (isRelative) {
+        newValue -= newLowPC;
+      }
+      yamlValue.Value = newValue;
+    });
+}
+
+static void updateCompileUnits(const BinaryenDWARFInfo& info,
+                               llvm::DWARFYAML::Data& yaml,
+                               LocationUpdater& locationUpdater) {
+  // 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;
+  iterContextAndYAML(
+    info.context->compile_units(),
+    yaml.CompileUnits,
+    [&](const std::unique_ptr<llvm::DWARFUnit>& CU,
+        llvm::DWARFYAML::Unit& yamlUnit) {
+      // Process the DIEs in each compile unit.
+      iterContextAndYAML(
+        CU->dies(),
+        yamlUnit.Entries,
+        [&](const llvm::DWARFDebugInfoEntry& DIE,
+            llvm::DWARFYAML::Entry& yamlEntry) {
+          // Process the entries in each relevant DIE, looking for attributes to
+          // change.
+          auto abbrevDecl = DIE.getAbbreviationDeclarationPtr();
+          if (abbrevDecl) {
+            // This is relevant; look for things to update.
+            updateDIE(
+              DIE, yamlEntry, abbrevDecl, locationUpdater, compileUnitIndex);
+          }
+        });
+      compileUnitIndex++;
+    });
+}
+
+static void updateRanges(llvm::DWARFYAML::Data& yaml,
+                         const LocationUpdater& locationUpdater) {
+  // In each range section, try to update the start and end. If we no longer
+  // have something to map them to, we must skip that part.
+  size_t skip = 0;
+  for (size_t i = 0; i < yaml.Ranges.size(); i++) {
+    auto& range = yaml.Ranges[i];
+    BinaryLocation oldStart = range.Start, oldEnd = range.End, newStart = 0,
+                   newEnd = 0;
+    // 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) {
+      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) {
+        // 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.
+        newStart = 0;
+        newEnd = 1;
+      }
+      // TODO even if range start and end markers have been preserved,
+      // instructions in the middle may have moved around, making the range no
+      // longer contiguous. We should check that, and possibly split/merge
+      // the range. Or, we may need to have tracking in the IR for this.
+    }
+    auto& writtenRange = yaml.Ranges[i - skip];
+    writtenRange.Start = newStart;
+    writtenRange.End = newEnd;
+  }
+}
+
+// A location that is ignoreable, i.e., not a special value like 0 or -1 (which
+// would indicate an end or a base in .debug_loc).
+static const BinaryLocation IGNOREABLE_LOCATION = 1;
+
+static bool isNewBaseLoc(const llvm::DWARFYAML::Loc& loc) {
+  return loc.Start == BinaryLocation(-1);
+}
+
+static bool isEndMarkerLoc(const llvm::DWARFYAML::Loc& loc) {
+  return loc.Start == 0 && loc.End == 0;
+}
+
+// Update the .debug_loc section.
+static void updateLoc(llvm::DWARFYAML::Data& yaml,
+                      const LocationUpdater& locationUpdater) {
+  // Similar to ranges, try to update the start and end. Note that here we
+  // can't skip since the location description is a variable number of bytes,
+  // so we mark no longer valid addresses as empty.
+  bool atStart = true;
+  // We need to keep positions in the .debug_loc section identical to before
+  // (or else we'd need to update their positions too) and so we need to keep
+  // base entries around (a base entry is added to every entry after it in the
+  // list). However, we may change the base's value as after moving instructions
+  // around the old base may not be smaller than all the values relative to it.
+  BinaryLocation oldBase, newBase;
+  auto& locs = yaml.Locs;
+  for (size_t i = 0; i < locs.size(); i++) {
+    auto& loc = locs[i];
+    if (atStart) {
+      std::tie(oldBase, newBase) =
+        locationUpdater.getCompileUnitBasesForLoc(loc.CompileUnitOffset);
+      atStart = false;
+    }
+    // By default we copy values over, unless we modify them below.
+    BinaryLocation newStart = loc.Start, newEnd = loc.End;
+    if (isNewBaseLoc(loc)) {
+      // This is a new base.
+      // Note that the base is not the address of an instruction, necessarily -
+      // it's just a number (seems like it could always be an instruction, but
+      // that's not what LLVM emits).
+      // We must look forward at everything relative to this base, so that we
+      // can emit a new proper base (as mentioned earlier, the original base may
+      // not be valid if instructions moved to a position before it - they must
+      // be positive offsets from it).
+      oldBase = newBase = newEnd;
+      BinaryLocation smallest = -1;
+      for (size_t j = i + 1; j < locs.size(); j++) {
+        auto& futureLoc = locs[j];
+        if (isNewBaseLoc(futureLoc) || isEndMarkerLoc(futureLoc)) {
+          break;
+        }
+        auto updatedStart =
+          locationUpdater.getNewStart(futureLoc.Start + oldBase);
+        // If we found a valid mapping, this is a relevant value for us. If the
+        // optimizer removed it, it's a 0, and we can ignore it here - we will
+        // emit IGNOREABLE_LOCATION for it later anyhow.
+        if (updatedStart != 0) {
+          smallest = std::min(smallest, updatedStart);
+        }
+      }
+      // If we found no valid values that will be relativized here, just use 0
+      // as the new (never-to-be-used) base, which is less confusing (otherwise
+      // the value looks like it means something).
+      if (smallest == BinaryLocation(-1)) {
+        smallest = 0;
+      }
+      newBase = newEnd = smallest;
+    } else if (isEndMarkerLoc(loc)) {
+      // This is an end marker, this list is done; reset the base.
+      atStart = true;
+    } else {
+      // This is a normal entry, try to find what it should be updated to. First
+      // de-relativize it to the base to get the absolute address, then look for
+      // a new address for it.
+      newStart = locationUpdater.getNewStart(loc.Start + oldBase);
+      newEnd = locationUpdater.getNewEnd(loc.End + oldBase);
+      if (newStart == 0 || newEnd == 0 || newStart > newEnd) {
+        // This part of the loc no longer has a mapping, or after the mapping
+        // it is no longer a proper span, so we must ignore it.
+        newStart = newEnd = IGNOREABLE_LOCATION;
+      } else {
+        // We picked a new base that ensures it is smaller than the values we
+        // will relativize to it.
+        assert(newStart >= newBase && newEnd >= newBase);
+        newStart -= newBase;
+        newEnd -= newBase;
+        if (newStart == 0 && newEnd == 0) {
+          // After mapping to the new positions, and after relativizing to the
+          // base, if we end up with (0, 0) then we must emit something else, as
+          // that would be interpreted as the end of a list. As it is an empty
+          // span, the actual value doesn't matter, it just has to be != 0.
+          // This can happen if the very first span in a compile unit is an
+          // empty span, in which case relative to the base of the compile unit
+          // we would have (0, 0).
+          newStart = newEnd = IGNOREABLE_LOCATION;
+        }
+      }
+      // The loc start and end markers have been preserved. However, TODO
+      // instructions in the middle may have moved around, making the loc no
+      // longer contiguous, we should check that, and possibly split/merge
+      // the loc. Or, we may need to have tracking in the IR for this.
+    }
+    loc.Start = newStart;
+    loc.End = newEnd;
+    // Note how the ".Location" field is unchanged.
+  }
+}
+
+void writeDWARFSections(Module& wasm, const BinaryLocations& newLocations) {
+  BinaryenDWARFInfo info(wasm);
+
+  // Convert to Data representation, which YAML can use to write.
+  llvm::DWARFYAML::Data data;
+  if (dwarf2yaml(*info.context, data)) {
+    Fatal() << "Failed to parse DWARF to YAML";
+  }
+
+  LocationUpdater locationUpdater(wasm, newLocations);
+
+  updateDebugLines(data, locationUpdater);
+
+  updateCompileUnits(info, data, locationUpdater);
+
+  updateRanges(data, locationUpdater);
+
+  updateLoc(data, locationUpdater);
+
+  // Convert to binary sections.
+  auto newSections =
+    EmitDebugSections(data, false /* EmitFixups for debug_info */);
+
+  // Update the custom sections in the wasm.
+  // TODO: efficiency
+  for (auto& section : wasm.userSections) {
+    if (Name(section.name).startsWith(".debug_")) {
+      auto llvmName = section.name.substr(1);
+      if (newSections.count(llvmName)) {
+        auto llvmData = newSections[llvmName]->getBuffer();
+        section.data.resize(llvmData.size());
+        std::copy(llvmData.begin(), llvmData.end(), section.data.data());
+      }
+    }
+  }
+}
+
+#else // BUILD_LLVM_DWARF
+
+void dumpDWARF(const Module& wasm) {
+  std::cerr << "warning: no DWARF dumping support present\n";
+}
+
+void writeDWARFSections(Module& wasm, const BinaryLocations& newLocations) {
+  std::cerr << "warning: no DWARF updating support present\n";
+}
+
+#endif // BUILD_LLVM_DWARF
+
+} // namespace Debug
+
+} // namespace wasm
diff --git a/binaryen/src/wasm/wasm-emscripten.cpp b/binaryen/src/wasm/wasm-emscripten.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm/wasm-emscripten.cpp
@@ -0,0 +1,702 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wasm-emscripten.h"
+
+#include <sstream>
+
+#include "asm_v_wasm.h"
+#include "asmjs/shared-constants.h"
+#include "ir/import-utils.h"
+#include "ir/literal-utils.h"
+#include "ir/module-utils.h"
+#include "ir/table-utils.h"
+#include "shared-constants.h"
+#include "support/debug.h"
+#include "wasm-builder.h"
+#include "wasm-traversal.h"
+#include "wasm.h"
+
+#define DEBUG_TYPE "emscripten"
+
+namespace wasm {
+
+cashew::IString EM_ASM_PREFIX("emscripten_asm_const");
+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);
+  auto export_ = new Export;
+  export_->name = export_->value = function->name;
+  export_->kind = ExternalKind::Function;
+  wasm.addExport(export_);
+}
+
+// TODO(sbc): There should probably be a better way to do this.
+bool isExported(Module& wasm, Name name) {
+  for (auto& ex : wasm.exports) {
+    if (ex->value == name) {
+      return true;
+    }
+  }
+  return false;
+}
+
+Global* getStackPointerGlobal(Module& wasm) {
+  // Assumption: The stack pointer is either imported as __stack_pointer or
+  // its the first non-imported and non-exported global.
+  // TODO(sbc): Find a better way to discover the stack pointer.  Perhaps the
+  // linker could export it by name?
+  for (auto& g : wasm.globals) {
+    if (g->imported()) {
+      if (g->base == STACK_POINTER) {
+        return g.get();
+      }
+    } else if (!isExported(wasm, g->name)) {
+      return g.get();
+    }
+  }
+  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) {
+  std::unordered_map<Index, Address> passiveOffsets;
+  if (wasm.features.hasBulkMemory()) {
+    // Fetch passive segment offsets out of memory.init instructions
+    struct OffsetSearcher : PostWalker<OffsetSearcher> {
+      std::unordered_map<Index, Address>& offsets;
+      OffsetSearcher(std::unordered_map<unsigned, Address>& offsets)
+        : offsets(offsets) {}
+      void visitMemoryInit(MemoryInit* curr) {
+        auto* dest = curr->dest->dynCast<Const>();
+        if (!dest) {
+          return;
+        }
+        auto it = offsets.find(curr->segment);
+        if (it != offsets.end()) {
+          Fatal() << "Cannot get offset of passive segment initialized "
+                     "multiple times";
+        }
+        offsets[curr->segment] = dest->value.geti32();
+      }
+    } searcher(passiveOffsets);
+    searcher.walkModule(&wasm);
+  }
+  std::vector<Address> segmentOffsets;
+  for (unsigned i = 0; i < wasm.memory.segments.size(); ++i) {
+    auto& segment = wasm.memory.segments[i];
+    if (segment.isPassive) {
+      auto it = passiveOffsets.find(i);
+      if (it != passiveOffsets.end()) {
+        segmentOffsets.push_back(it->second);
+      } else {
+        // This was a non-constant offset (perhaps TLS)
+        segmentOffsets.push_back(UNKNOWN_OFFSET);
+      }
+    } else if (auto* addrConst = segment.offset->dynCast<Const>()) {
+      auto address = addrConst->value.geti32();
+      segmentOffsets.push_back(address);
+    } else {
+      // TODO(sbc): Wasm shared libraries have data segments with non-const
+      // offset.
+      segmentOffsets.push_back(0);
+    }
+  }
+  return segmentOffsets;
+}
+
+std::string escape(const char* input) {
+  std::string code = input;
+  // replace newlines quotes with escaped newlines
+  size_t curr = 0;
+  while ((curr = code.find("\\n", curr)) != std::string::npos) {
+    code = code.replace(curr, 2, "\\\\n");
+    curr += 3; // skip this one
+  }
+  // replace double quotes with escaped single quotes
+  curr = 0;
+  while ((curr = code.find('"', curr)) != std::string::npos) {
+    if (curr == 0 || code[curr - 1] != '\\') {
+      code = code.replace(curr,
+                          1,
+                          "\\"
+                          "\"");
+      curr += 2; // skip this one
+    } else {     // already escaped, escape the slash as well
+      code = code.replace(curr,
+                          1,
+                          "\\"
+                          "\\"
+                          "\"");
+      curr += 3; // skip this one
+    }
+  }
+  return code;
+}
+
+const char* stringAtAddr(Module& wasm,
+                         std::vector<Address> const& segmentOffsets,
+                         Address address) {
+  for (unsigned i = 0; i < wasm.memory.segments.size(); ++i) {
+    Memory::Segment& segment = wasm.memory.segments[i];
+    Address offset = segmentOffsets[i];
+    if (offset != UNKNOWN_OFFSET && address >= offset &&
+        address < offset + segment.data.size()) {
+      return &segment.data[address - offset];
+    }
+  }
+  return nullptr;
+}
+
+std::string codeForConstAddr(Module& wasm,
+                             std::vector<Address> const& segmentOffsets,
+                             int32_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("");
+  }
+  return escape(str);
+}
+
+enum class Proxying {
+  None,
+  Sync,
+  Async,
+};
+
+std::string proxyingSuffix(Proxying proxy) {
+  switch (proxy) {
+    case Proxying::None:
+      return "";
+    case Proxying::Sync:
+      return "sync_on_main_thread_";
+    case Proxying::Async:
+      return "async_on_main_thread_";
+  }
+  WASM_UNREACHABLE("invalid prozy type");
+}
+
+struct AsmConstWalker : public LinearExecutionWalker<AsmConstWalker> {
+  Module& wasm;
+  bool minimizeWasmChanges;
+  std::vector<Address> segmentOffsets; // segment index => address offset
+
+  struct AsmConst {
+    std::set<Signature> sigs;
+    Address id;
+    std::string code;
+    Proxying proxy;
+  };
+
+  std::vector<AsmConst> asmConsts;
+  std::set<std::pair<Signature, Proxying>> allSigs;
+  // last sets in the current basic block, per index
+  std::map<Index, LocalSet*> sets;
+
+  AsmConstWalker(Module& _wasm, bool minimizeWasmChanges)
+    : wasm(_wasm), minimizeWasmChanges(minimizeWasmChanges),
+      segmentOffsets(getSegmentOffsets(wasm)) {}
+
+  void noteNonLinear(Expression* curr);
+
+  void visitLocalSet(LocalSet* curr);
+  void visitCall(Call* curr);
+
+  void process();
+
+private:
+  void createAsmConst(uint32_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);
+
+  std::vector<std::unique_ptr<Function>> queuedImports;
+};
+
+void AsmConstWalker::noteNonLinear(Expression* curr) {
+  // End of this basic block; clear sets.
+  sets.clear();
+}
+
+void AsmConstWalker::visitLocalSet(LocalSet* curr) { sets[curr->index] = curr; }
+
+void AsmConstWalker::visitCall(Call* curr) {
+  auto* import = wasm.getFunction(curr->target);
+  // Find calls to emscripten_asm_const* functions whose first argument is
+  // is always a string constant.
+  if (!import->imported()) {
+    return;
+  }
+  auto importName = import->base;
+  if (!importName.hasSubstring(EM_ASM_PREFIX)) {
+    return;
+  }
+
+  auto baseSig = wasm.getFunction(curr->target)->sig;
+  auto sig = asmConstSig(baseSig);
+  auto* arg = curr->operands[0];
+  while (!arg->dynCast<Const>()) {
+    if (auto* get = arg->dynCast<LocalGet>()) {
+      // The argument may be a local.get, in which case, the last set in this
+      // basic block has the value.
+      auto* set = sets[get->index];
+      if (set) {
+        assert(set->index == get->index);
+        arg = set->value;
+      } else {
+        Fatal() << "local.get of unknown in arg0 of call to " << importName
+                << " (used by EM_ASM* macros) in function "
+                << getFunction()->name
+                << ".\nThis might be caused by aggressive compiler "
+                   "transformations. Consider using EM_JS instead.";
+      }
+      continue;
+    }
+
+    if (auto* setlocal = arg->dynCast<LocalSet>()) {
+      // The argument may be a local.tee, in which case we take first child
+      // which is the value being copied into the local.
+      if (setlocal->isTee()) {
+        arg = setlocal->value;
+        continue;
+      }
+    }
+
+    if (auto* bin = arg->dynCast<Binary>()) {
+      if (bin->op == AddInt32) {
+        // 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
+        // the RHS of the addition is just what we want.
+        arg = bin->right;
+        continue;
+      }
+    }
+
+    Fatal() << "Unexpected arg0 type (" << getExpressionName(arg)
+            << ") in call to: " << importName;
+  }
+
+  auto* value = arg->cast<Const>();
+  int32_t address = value->value.geti32();
+  auto code = codeForConstAddr(wasm, segmentOffsets, address);
+  createAsmConst(address, code, sig, importName);
+}
+
+Proxying AsmConstWalker::proxyType(Name name) {
+  if (name.hasSubstring("_sync_on_main_thread")) {
+    return Proxying::Sync;
+  } else if (name.hasSubstring("_async_on_main_thread")) {
+    return Proxying::Async;
+  }
+  return Proxying::None;
+}
+
+void AsmConstWalker::process() {
+  // Find and queue necessary imports
+  walkModule(&wasm);
+  // Add them after the walk, to avoid iterator invalidation on
+  // the list of functions.
+  addImports();
+}
+
+void AsmConstWalker::createAsmConst(uint32_t id,
+                                    std::string code,
+                                    Signature sig,
+                                    Name name) {
+  AsmConst asmConst;
+  asmConst.id = id;
+  asmConst.code = code;
+  asmConst.sigs.insert(sig);
+  asmConst.proxy = proxyType(name);
+  asmConsts.push_back(asmConst);
+}
+
+Signature AsmConstWalker::asmConstSig(Signature baseSig) {
+  assert(baseSig.params.size() >= 1);
+  // Omit the signature of the "code" parameter, taken as a string, as the
+  // first argument
+  return Signature(
+    Type(std::vector<Type>(baseSig.params.begin() + 1, baseSig.params.end())),
+    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());
+  }
+}
+
+static AsmConstWalker fixEmAsmConstsAndReturnWalker(Module& wasm,
+                                                    bool minimizeWasmChanges) {
+  AsmConstWalker walker(wasm, minimizeWasmChanges);
+  walker.process();
+  return walker;
+}
+
+struct EmJsWalker : public PostWalker<EmJsWalker> {
+  Module& wasm;
+  std::vector<Address> segmentOffsets; // segment index => address offset
+
+  std::map<std::string, std::string> codeByName;
+
+  EmJsWalker(Module& _wasm)
+    : wasm(_wasm), segmentOffsets(getSegmentOffsets(wasm)) {}
+
+  void visitExport(Export* curr) {
+    if (curr->kind != ExternalKind::Function) {
+      return;
+    }
+    if (!curr->name.startsWith(EM_JS_PREFIX.str)) {
+      return;
+    }
+    auto* func = wasm.getFunction(curr->value);
+    auto funcName = std::string(curr->name.stripPrefix(EM_JS_PREFIX.str));
+    // An EM_JS has a single const in the body. Typically it is just returned,
+    // but in unoptimized code it might be stored to a local and loaded from
+    // there, and in relocatable code it might get added to __memory_base etc.
+    FindAll<Const> consts(func->body);
+    if (consts.list.size() != 1) {
+      Fatal() << "Unexpected generated __em_js__ function body: " << curr->name;
+    }
+    auto* addrConst = consts.list[0];
+    int32_t address = addrConst->value.geti32();
+    auto code = codeForConstAddr(wasm, segmentOffsets, address);
+    codeByName[funcName] = code;
+  }
+};
+
+EmJsWalker fixEmJsFuncsAndReturnWalker(Module& wasm) {
+  EmJsWalker walker(wasm);
+  walker.walkModule(&wasm);
+
+  std::vector<Name> toRemove;
+  for (auto& func : wasm.functions) {
+    if (func->name.startsWith(EM_JS_PREFIX.str)) {
+      toRemove.push_back(func->name);
+    }
+  }
+  for (auto funcName : toRemove) {
+    wasm.removeFunction(funcName);
+    wasm.removeExport(funcName);
+  }
+  return walker;
+}
+
+void printSignatures(std::ostream& o, const std::set<Signature>& c) {
+  o << "[";
+  bool first = true;
+  for (auto& sig : c) {
+    if (first) {
+      first = false;
+    } else {
+      o << ",";
+    }
+    o << '"' << getSig(sig.results, sig.params) << '"';
+  }
+  o << "]";
+}
+
+std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
+  Address staticBump, std::vector<Name> const& initializerFunctions) {
+  bool commaFirst;
+  auto nextElement = [&commaFirst]() {
+    if (commaFirst) {
+      commaFirst = false;
+      return "\n    ";
+    } else {
+      return ",\n    ";
+    }
+  };
+
+  std::stringstream meta;
+  meta << "{\n";
+
+  AsmConstWalker emAsmWalker =
+    fixEmAsmConstsAndReturnWalker(wasm, minimizeWasmChanges);
+
+  // print
+  commaFirst = true;
+  if (!emAsmWalker.asmConsts.empty()) {
+    meta << "  \"asmConsts\": {";
+    for (auto& asmConst : emAsmWalker.asmConsts) {
+      meta << nextElement();
+      meta << '"' << asmConst.id << "\": [\"" << asmConst.code << "\", ";
+      printSignatures(meta, asmConst.sigs);
+      meta << ", [\"" << proxyingSuffix(asmConst.proxy) << "\"]";
+
+      meta << "]";
+    }
+    meta << "\n  },\n";
+  }
+
+  EmJsWalker emJsWalker = fixEmJsFuncsAndReturnWalker(wasm);
+  if (!emJsWalker.codeByName.empty()) {
+    meta << "  \"emJsFuncs\": {";
+    commaFirst = true;
+    for (auto& pair : emJsWalker.codeByName) {
+      auto& name = pair.first;
+      auto& code = pair.second;
+      meta << nextElement();
+      meta << '"' << name << "\": \"" << code << '"';
+    }
+    meta << "\n  },\n";
+  }
+
+  meta << "  \"staticBump\": " << staticBump << ",\n";
+  meta << "  \"tableSize\": " << wasm.table.initial.addr << ",\n";
+
+  if (!initializerFunctions.empty()) {
+    meta << "  \"initializers\": [";
+    commaFirst = true;
+    for (const auto& func : initializerFunctions) {
+      meta << nextElement();
+      meta << "\"" << func.c_str() << "\"";
+    }
+    meta << "\n  ],\n";
+  }
+
+  // Avoid adding duplicate imports to `declares' or `invokeFuncs`.  Even
+  // though we might import the same function multiple times (i.e. with
+  // different sigs) we only need to list is in the metadata once.
+  std::set<std::string> declares;
+  std::set<std::string> invokeFuncs;
+
+  // We use the `base` rather than the `name` of the imports here and below
+  // becasue this is the externally visible name that the embedder (JS) will
+  // see.
+  meta << "  \"declares\": [";
+  commaFirst = true;
+  ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
+    if (emJsWalker.codeByName.count(import->base.str) == 0 &&
+        !import->base.startsWith("invoke_")) {
+      if (declares.insert(import->base.str).second) {
+        meta << nextElement() << '"' << import->base.str << '"';
+      }
+    }
+  });
+  meta << "\n  ],\n";
+
+  meta << "  \"externs\": [";
+  commaFirst = true;
+  ModuleUtils::iterImportedGlobals(wasm, [&](Global* import) {
+    if (!(import->module == ENV && import->name == STACK_INIT)) {
+      meta << nextElement() << "\"_" << import->base.str << '"';
+    }
+  });
+  meta << "\n  ],\n";
+
+  if (!wasm.exports.empty()) {
+    meta << "  \"exports\": [";
+    commaFirst = true;
+    for (const auto& ex : wasm.exports) {
+      if (ex->kind == ExternalKind::Function) {
+        meta << nextElement() << '"' << ex->name.str << '"';
+      }
+    }
+    meta << "\n  ],\n";
+
+    meta << "  \"namedGlobals\": {";
+    commaFirst = true;
+    for (const auto& ex : wasm.exports) {
+      if (ex->kind == ExternalKind::Global) {
+        const Global* g = wasm.getGlobal(ex->value);
+        assert(g->type == Type::i32);
+        Const* init = g->init->cast<Const>();
+        uint32_t addr = init->value.geti32();
+        meta << nextElement() << '"' << ex->name.str << "\" : \"" << addr
+             << '"';
+      }
+    }
+    meta << "\n  },\n";
+  }
+
+  meta << "  \"invokeFuncs\": [";
+  commaFirst = true;
+  ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
+    if (import->module == ENV && import->base.startsWith("invoke_")) {
+      if (invokeFuncs.insert(import->base.str).second) {
+        meta << nextElement() << '"' << import->base.str << '"';
+      }
+    }
+  });
+  meta << "\n  ],\n";
+
+  // In normal mode we attempt to determine if main takes argumnts or not
+  // In standalone mode we export _start instead and rely on the presence
+  // of the __wasi_args_get and __wasi_args_sizes_get syscalls allow us to
+  // DCE to the argument handling JS code instead.
+  if (!standalone) {
+    auto mainReadsParams = false;
+    auto* exp = wasm.getExportOrNull("main");
+    if (!exp) {
+      exp = wasm.getExportOrNull("__main_argc_argv");
+    }
+    if (exp) {
+      if (exp->kind == ExternalKind::Function) {
+        auto* main = wasm.getFunction(exp->value);
+        mainReadsParams = true;
+        // If main does not read its parameters, it will just be a stub that
+        // calls __original_main (which has no parameters).
+        if (auto* call = main->body->dynCast<Call>()) {
+          if (call->operands.empty()) {
+            mainReadsParams = false;
+          }
+        }
+      }
+    }
+    meta << "  \"mainReadsParams\": " << int(mainReadsParams) << ",\n";
+  }
+
+  meta << "  \"features\": [";
+  commaFirst = true;
+  wasm.features.iterFeatures([&](FeatureSet::Feature f) {
+    meta << nextElement() << "\"--enable-" << FeatureSet::toString(f) << '"';
+  });
+  meta << "\n  ]\n";
+
+  meta << "}\n";
+
+  return meta.str();
+}
+
+void EmscriptenGlueGenerator::separateDataSegments(Output* outfile,
+                                                   Address base) {
+  size_t lastEnd = 0;
+  for (Memory::Segment& seg : wasm.memory.segments) {
+    if (seg.isPassive) {
+      Fatal() << "separating passive segments not implemented";
+    }
+    if (!seg.offset->is<Const>()) {
+      Fatal() << "separating relocatable segments not implemented";
+    }
+    size_t offset = seg.offset->cast<Const>()->value.geti32();
+    offset -= base;
+    size_t fill = offset - lastEnd;
+    if (fill > 0) {
+      std::vector<char> buf(fill);
+      outfile->write(buf.data(), fill);
+    }
+    outfile->write(seg.data.data(), seg.data.size());
+    lastEnd = offset + seg.data.size();
+  }
+  wasm.memory.segments.clear();
+}
+
+void EmscriptenGlueGenerator::renameMainArgcArgv() {
+  // If an export call ed __main_argc_argv exists rename it to main
+  Export* ex = wasm.getExportOrNull("__main_argc_argv");
+  if (!ex) {
+    BYN_TRACE("renameMain: __main_argc_argv not found\n");
+    return;
+  }
+  ex->name = "main";
+  wasm.updateMaps();
+  ModuleUtils::renameFunction(wasm, "__main_argc_argv", "main");
+}
+
+} // namespace wasm
diff --git a/binaryen/src/wasm/wasm-interpreter.cpp b/binaryen/src/wasm/wasm-interpreter.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm/wasm-interpreter.cpp
@@ -0,0 +1,22 @@
+#include "wasm-interpreter.h"
+
+namespace wasm {
+
+#ifdef WASM_INTERPRETER_DEBUG
+int Indenter::indentLevel = 0;
+
+Indenter::Indenter(const char* entry) : entryName(entry) { ++indentLevel; }
+Indenter::~Indenter() {
+  print();
+  std::cout << "exit " << entryName << '\n';
+  --indentLevel;
+}
+void Indenter::print() {
+  std::cout << indentLevel << ':';
+  for (int i = 0; i <= indentLevel; ++i) {
+    std::cout << ' ';
+  }
+}
+#endif // WASM_INTERPRETER_DEBUG
+
+} // namespace wasm
diff --git a/binaryen/src/wasm/wasm-io.cpp b/binaryen/src/wasm/wasm-io.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm/wasm-io.cpp
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+//
+// Abstracts reading and writing, supporting both text and binary
+// depending on the suffix.
+//
+// When the suffix is unclear, writing defaults to text (this
+// allows odd suffixes, which we use in the test suite), while
+// reading will check the magic number and default to text if not
+// binary.
+//
+
+#include "wasm-io.h"
+#include "support/debug.h"
+#include "wasm-binary.h"
+#include "wasm-s-parser.h"
+
+namespace wasm {
+
+#define DEBUG_TYPE "writer"
+
+static void readTextData(std::string& input, Module& wasm, IRProfile profile) {
+  SExpressionParser parser(const_cast<char*>(input.c_str()));
+  Element& root = *parser.root;
+  SExpressionWasmBuilder builder(wasm, *root[0], profile);
+}
+
+void ModuleReader::readText(std::string filename, Module& wasm) {
+  BYN_TRACE("reading text from " << filename << "\n");
+  auto input(read_file<std::string>(filename, Flags::Text));
+  readTextData(input, wasm, profile);
+}
+
+void ModuleReader::readBinaryData(std::vector<char>& input,
+                                  Module& wasm,
+                                  std::string sourceMapFilename) {
+  std::unique_ptr<std::ifstream> sourceMapStream;
+  WasmBinaryBuilder parser(wasm, input);
+  parser.setDWARF(DWARF);
+  if (sourceMapFilename.size()) {
+    sourceMapStream = make_unique<std::ifstream>();
+    sourceMapStream->open(sourceMapFilename);
+    parser.setDebugLocations(sourceMapStream.get());
+  }
+  parser.read();
+  if (sourceMapStream) {
+    sourceMapStream->close();
+  }
+}
+
+void ModuleReader::readBinary(std::string filename,
+                              Module& wasm,
+                              std::string sourceMapFilename) {
+  BYN_TRACE("reading binary from " << filename << "\n");
+  auto input(read_file<std::vector<char>>(filename, Flags::Binary));
+  readBinaryData(input, wasm, sourceMapFilename);
+}
+
+bool ModuleReader::isBinaryFile(std::string filename) {
+  std::ifstream infile;
+  std::ios_base::openmode flags = std::ifstream::in | std::ifstream::binary;
+  infile.open(filename, flags);
+  char buffer[4] = {1, 2, 3, 4};
+  infile.read(buffer, 4);
+  infile.close();
+  return buffer[0] == '\0' && buffer[1] == 'a' && buffer[2] == 's' &&
+         buffer[3] == 'm';
+}
+
+void ModuleReader::read(std::string filename,
+                        Module& wasm,
+                        std::string sourceMapFilename) {
+  // empty filename means read from stdin
+  if (!filename.size()) {
+    readStdin(wasm, sourceMapFilename);
+    return;
+  }
+  if (isBinaryFile(filename)) {
+    readBinary(filename, wasm, sourceMapFilename);
+  } else {
+    // default to text
+    if (sourceMapFilename.size()) {
+      std::cerr << "Binaryen ModuleReader::read() - source map filename "
+                   "provided, but file appears to not be binary\n";
+    }
+    readText(filename, wasm);
+  }
+}
+
+// TODO: reading into a vector<char> then copying into a string is unnecessarily
+// inefficient. It would be better to read just once into a stringstream.
+void ModuleReader::readStdin(Module& wasm, std::string sourceMapFilename) {
+  std::vector<char> input = read_stdin();
+  if (input.size() >= 4 && input[0] == '\0' && input[1] == 'a' &&
+      input[2] == 's' && input[3] == 'm') {
+    readBinaryData(input, wasm, sourceMapFilename);
+  } else {
+    std::ostringstream s;
+    s.write(input.data(), input.size());
+    s << '\0';
+    std::string input_str = s.str();
+    readTextData(input_str, wasm, profile);
+  }
+}
+
+#undef DEBUG_TYPE
+#define DEBUG_TYPE "writer"
+
+void ModuleWriter::writeText(Module& wasm, Output& output) {
+  WasmPrinter::printModule(&wasm, output.getStream());
+}
+
+void ModuleWriter::writeText(Module& wasm, std::string filename) {
+  BYN_TRACE("writing text to " << filename << "\n");
+  Output output(filename, Flags::Text);
+  writeText(wasm, output);
+}
+
+void ModuleWriter::writeBinary(Module& wasm, Output& output) {
+  BufferWithRandomAccess buffer;
+  WasmBinaryWriter writer(&wasm, buffer);
+  // if debug info is used, then we want to emit the names section
+  writer.setNamesSection(debugInfo);
+  std::unique_ptr<std::ofstream> sourceMapStream;
+  if (sourceMapFilename.size()) {
+    sourceMapStream = make_unique<std::ofstream>();
+    sourceMapStream->open(sourceMapFilename);
+    writer.setSourceMap(sourceMapStream.get(), sourceMapUrl);
+  }
+  if (symbolMap.size() > 0) {
+    writer.setSymbolMap(symbolMap);
+  }
+  writer.write();
+  buffer.writeTo(output);
+  if (sourceMapStream) {
+    sourceMapStream->close();
+  }
+}
+
+void ModuleWriter::writeBinary(Module& wasm, std::string filename) {
+  BYN_TRACE("writing binary to " << filename << "\n");
+  Output output(filename, Flags::Binary);
+  writeBinary(wasm, output);
+}
+
+void ModuleWriter::write(Module& wasm, Output& output) {
+  if (binary) {
+    writeBinary(wasm, output);
+  } else {
+    writeText(wasm, output);
+  }
+}
+
+void ModuleWriter::write(Module& wasm, std::string filename) {
+  if (binary && filename.size() > 0) {
+    writeBinary(wasm, filename);
+  } else {
+    writeText(wasm, filename);
+  }
+}
+
+} // namespace wasm
diff --git a/binaryen/src/wasm/wasm-s-parser.cpp b/binaryen/src/wasm/wasm-s-parser.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm/wasm-s-parser.cpp
@@ -0,0 +1,2778 @@
+/*
+ * Copyright 2015 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wasm-s-parser.h"
+
+#include <cctype>
+#include <cmath>
+#include <limits>
+
+#include "asm_v_wasm.h"
+#include "asmjs/shared-constants.h"
+#include "ir/branch-utils.h"
+#include "shared-constants.h"
+#include "wasm-binary.h"
+
+#define abort_on(str)                                                          \
+  { throw ParseException(std::string("abort_on ") + str); }
+#define element_assert(condition)                                              \
+  assert((condition) ? true : (std::cerr << "on: " << *this << '\n' && 0));
+
+using cashew::IString;
+
+namespace {
+int unhex(char c) {
+  if (c >= '0' && c <= '9') {
+    return c - '0';
+  }
+  if (c >= 'a' && c <= 'f') {
+    return c - 'a' + 10;
+  }
+  if (c >= 'A' && c <= 'F') {
+    return c - 'A' + 10;
+  }
+  throw wasm::ParseException("invalid hexadecimal");
+}
+} // namespace
+
+namespace wasm {
+
+static Address getAddress(const Element* s) { return atoll(s->c_str()); }
+
+static void
+checkAddress(Address a, const char* errorText, const Element* errorElem) {
+  if (a > std::numeric_limits<Address::address32_t>::max()) {
+    throw ParseException(errorText, errorElem->line, errorElem->col);
+  }
+}
+
+static bool elementStartsWith(Element& s, IString str) {
+  return s.isList() && s.size() > 0 && s[0]->isStr() && s[0]->str() == str;
+}
+
+Element::List& Element::list() {
+  if (!isList()) {
+    throw ParseException("expected list", line, col);
+  }
+  return list_;
+}
+
+Element* Element::operator[](unsigned i) {
+  if (!isList()) {
+    throw ParseException("expected list", line, col);
+  }
+  if (i >= list().size()) {
+    throw ParseException("expected more elements in list", line, col);
+  }
+  return list()[i];
+}
+
+IString Element::str() const {
+  if (!isStr()) {
+    throw ParseException("expected string", line, col);
+  }
+  return str_;
+}
+
+const char* Element::c_str() const {
+  if (!isStr()) {
+    throw ParseException("expected string", line, col);
+  }
+  return str_.str;
+}
+
+Element* Element::setString(IString str__, bool dollared__, bool quoted__) {
+  isList_ = false;
+  str_ = str__;
+  dollared_ = dollared__;
+  quoted_ = quoted__;
+  return this;
+}
+
+Element*
+Element::setMetadata(size_t line_, size_t col_, SourceLocation* startLoc_) {
+  line = line_;
+  col = col_;
+  startLoc = startLoc_;
+  return this;
+}
+
+std::ostream& operator<<(std::ostream& o, Element& e) {
+  if (e.isList_) {
+    o << '(';
+    for (auto item : e.list_) {
+      o << ' ' << *item;
+    }
+    o << " )";
+  } else {
+    o << e.str_.str;
+  }
+  return o;
+}
+
+void Element::dump() {
+  std::cout << "dumping " << this << " : " << *this << ".\n";
+}
+
+SExpressionParser::SExpressionParser(char* input) : input(input) {
+  root = nullptr;
+  line = 1;
+  lineStart = input;
+  while (!root) { // keep parsing until we pass an initial comment
+    root = parse();
+  }
+}
+
+Element* SExpressionParser::parse() {
+  std::vector<Element*> stack;
+  std::vector<SourceLocation*> stackLocs;
+  Element* curr = allocator.alloc<Element>();
+  while (1) {
+    skipWhitespace();
+    if (input[0] == 0) {
+      break;
+    }
+    if (input[0] == '(') {
+      input++;
+      stack.push_back(curr);
+      curr = allocator.alloc<Element>()->setMetadata(
+        line, input - lineStart - 1, loc);
+      stackLocs.push_back(loc);
+      assert(stack.size() == stackLocs.size());
+    } else if (input[0] == ')') {
+      input++;
+      curr->endLoc = loc;
+      auto last = curr;
+      if (stack.empty()) {
+        throw ParseException("s-expr stack empty");
+      }
+      curr = stack.back();
+      assert(stack.size() == stackLocs.size());
+      stack.pop_back();
+      loc = stackLocs.back();
+      stackLocs.pop_back();
+      curr->list().push_back(last);
+    } else {
+      curr->list().push_back(parseString());
+    }
+  }
+  if (stack.size() != 0) {
+    throw ParseException("stack is not empty", curr->line, curr->col);
+  }
+  return curr;
+}
+
+void SExpressionParser::parseDebugLocation() {
+  // Extracting debug location (if valid)
+  char* debugLoc = input + 3; // skipping ";;@"
+  while (debugLoc[0] && debugLoc[0] == ' ') {
+    debugLoc++;
+  }
+  char* debugLocEnd = debugLoc;
+  while (debugLocEnd[0] && debugLocEnd[0] != '\n') {
+    debugLocEnd++;
+  }
+  char* pos = debugLoc;
+  while (pos < debugLocEnd && pos[0] != ':') {
+    pos++;
+  }
+  if (pos >= debugLocEnd) {
+    return; // no line number
+  }
+  std::string name(debugLoc, pos);
+  char* lineStart = ++pos;
+  while (pos < debugLocEnd && pos[0] != ':') {
+    pos++;
+  }
+  std::string lineStr(lineStart, pos);
+  if (pos >= debugLocEnd) {
+    return; // no column number
+  }
+  std::string colStr(++pos, debugLocEnd);
+  void* buf =
+    allocator.allocSpace(sizeof(SourceLocation), alignof(SourceLocation));
+  loc = new (buf) SourceLocation(
+    IString(name.c_str(), false), atoi(lineStr.c_str()), atoi(colStr.c_str()));
+}
+
+void SExpressionParser::skipWhitespace() {
+  while (1) {
+    while (isspace(input[0])) {
+      if (input[0] == '\n') {
+        line++;
+        lineStart = input + 1;
+      }
+      input++;
+    }
+    if (input[0] == ';' && input[1] == ';') {
+      if (input[2] == '@') {
+        parseDebugLocation();
+      }
+      while (input[0] && input[0] != '\n') {
+        input++;
+      }
+      line++;
+      if (!input[0]) {
+        return;
+      }
+      lineStart = ++input;
+    } else if (input[0] == '(' && input[1] == ';') {
+      // Skip nested block comments.
+      input += 2;
+      int depth = 1;
+      while (1) {
+        if (!input[0]) {
+          return;
+        }
+        if (input[0] == '(' && input[1] == ';') {
+          input += 2;
+          depth++;
+        } else if (input[0] == ';' && input[1] == ')') {
+          input += 2;
+          --depth;
+          if (depth == 0) {
+            break;
+          }
+        } else if (input[0] == '\n') {
+          line++;
+          lineStart = input;
+          input++;
+        } else {
+          input++;
+        }
+      }
+    } else {
+      return;
+    }
+  }
+}
+
+Element* SExpressionParser::parseString() {
+  bool dollared = false;
+  if (input[0] == '$') {
+    input++;
+    dollared = true;
+  }
+  char* start = input;
+  if (input[0] == '"') {
+    // parse escaping \", but leave code escaped - we'll handle escaping in
+    // memory segments specifically
+    input++;
+    std::string str;
+    while (1) {
+      if (input[0] == 0) {
+        throw ParseException("unterminated string", line, start - lineStart);
+      }
+      if (input[0] == '"') {
+        break;
+      }
+      if (input[0] == '\\') {
+        str += input[0];
+        if (input[1] == 0) {
+          throw ParseException(
+            "unterminated string escape", line, start - lineStart);
+        }
+        str += input[1];
+        input += 2;
+        continue;
+      }
+      str += input[0];
+      input++;
+    }
+    input++;
+    return allocator.alloc<Element>()
+      ->setString(IString(str.c_str(), false), dollared, true)
+      ->setMetadata(line, start - lineStart, loc);
+  }
+  while (input[0] && !isspace(input[0]) && input[0] != ')' && input[0] != '(' &&
+         input[0] != ';') {
+    input++;
+  }
+  if (start == input) {
+    throw ParseException("expected string", line, input - lineStart);
+  }
+  char temp = input[0];
+  input[0] = 0;
+  auto ret = allocator.alloc<Element>()
+               ->setString(IString(start, false), dollared, false)
+               ->setMetadata(line, start - lineStart, loc);
+  input[0] = temp;
+  return ret;
+}
+
+SExpressionWasmBuilder::SExpressionWasmBuilder(Module& wasm,
+                                               Element& module,
+                                               IRProfile profile)
+  : wasm(wasm), allocator(wasm.allocator), profile(profile) {
+  if (module.size() == 0) {
+    throw ParseException("empty toplevel, expected module");
+  }
+  if (module[0]->str() != MODULE) {
+    throw ParseException("toplevel does not start with module");
+  }
+  if (module.size() == 1) {
+    return;
+  }
+  Index i = 1;
+  if (module[i]->dollared()) {
+    wasm.name = module[i]->str();
+    i++;
+  }
+  if (i < module.size() && module[i]->isStr()) {
+    // these s-expressions contain a binary module, actually
+    std::vector<char> data;
+    while (i < module.size()) {
+      auto str = module[i++]->c_str();
+      if (auto size = strlen(str)) {
+        stringToBinary(str, size, data);
+      }
+    }
+    WasmBinaryBuilder binaryBuilder(wasm, data);
+    binaryBuilder.read();
+    return;
+  }
+  Index implementedFunctions = 0;
+  functionCounter = 0;
+  for (unsigned j = i; j < module.size(); j++) {
+    auto& s = *module[j];
+    preParseFunctionType(s);
+    preParseImports(s);
+    if (elementStartsWith(s, FUNC) && !isImport(s)) {
+      implementedFunctions++;
+    }
+  }
+  // we go through the functions again, now parsing them, and the counter begins
+  // from where imports ended
+  functionCounter -= implementedFunctions;
+  for (unsigned j = i; j < module.size(); j++) {
+    parseModuleElement(*module[j]);
+  }
+}
+
+bool SExpressionWasmBuilder::isImport(Element& curr) {
+  for (Index i = 0; i < curr.size(); i++) {
+    auto& x = *curr[i];
+    if (elementStartsWith(x, IMPORT)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void SExpressionWasmBuilder::preParseImports(Element& curr) {
+  IString id = curr[0]->str();
+  if (id == IMPORT) {
+    parseImport(curr);
+  }
+  if (isImport(curr)) {
+    if (id == FUNC) {
+      parseFunction(curr, true /* preParseImport */);
+    } else if (id == GLOBAL) {
+      parseGlobal(curr, true /* preParseImport */);
+    } else if (id == TABLE) {
+      parseTable(curr, true /* preParseImport */);
+    } else if (id == MEMORY) {
+      parseMemory(curr, true /* preParseImport */);
+    } else if (id == EVENT) {
+      parseEvent(curr, true /* preParseImport */);
+    } else {
+      throw ParseException(
+        "fancy import we don't support yet", curr.line, curr.col);
+    }
+  }
+}
+
+void SExpressionWasmBuilder::parseModuleElement(Element& curr) {
+  if (isImport(curr)) {
+    return; // already done
+  }
+  IString id = curr[0]->str();
+  if (id == START) {
+    return parseStart(curr);
+  }
+  if (id == FUNC) {
+    return parseFunction(curr);
+  }
+  if (id == MEMORY) {
+    return parseMemory(curr);
+  }
+  if (id == DATA) {
+    return parseData(curr);
+  }
+  if (id == EXPORT) {
+    return parseExport(curr);
+  }
+  if (id == IMPORT) {
+    return; // already done
+  }
+  if (id == GLOBAL) {
+    return parseGlobal(curr);
+  }
+  if (id == TABLE) {
+    return parseTable(curr);
+  }
+  if (id == ELEM) {
+    return parseElem(curr);
+  }
+  if (id == TYPE) {
+    return; // already done
+  }
+  if (id == EVENT) {
+    return parseEvent(curr);
+  }
+  std::cerr << "bad module element " << id.str << '\n';
+  throw ParseException("unknown module element", curr.line, curr.col);
+}
+
+Name SExpressionWasmBuilder::getFunctionName(Element& s) {
+  if (s.dollared()) {
+    return s.str();
+  } else {
+    // index
+    size_t offset = atoi(s.str().c_str());
+    if (offset >= functionNames.size()) {
+      throw ParseException(
+        "unknown function in getFunctionName", s.line, s.col);
+    }
+    return functionNames[offset];
+  }
+}
+
+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();
+  } else {
+    // index
+    size_t offset = atoi(s.str().c_str());
+    if (offset >= globalNames.size()) {
+      throw ParseException("unknown global in getGlobalName", s.line, s.col);
+    }
+    return globalNames[offset];
+  }
+}
+
+Name SExpressionWasmBuilder::getEventName(Element& s) {
+  if (s.dollared()) {
+    return s.str();
+  } else {
+    // index
+    size_t offset = atoi(s.str().c_str());
+    if (offset >= eventNames.size()) {
+      throw ParseException("unknown event in getEventName", s.line, s.col);
+    }
+    return eventNames[offset];
+  }
+}
+
+// Parse various forms of (param ...) or (local ...) element. This ignores all
+// parameter or local names when specified.
+std::vector<Type> SExpressionWasmBuilder::parseParamOrLocal(Element& s) {
+  size_t fakeIndex = 0;
+  std::vector<NameType> namedParams = parseParamOrLocal(s, fakeIndex);
+  std::vector<Type> params;
+  for (auto& p : namedParams) {
+    params.push_back(p.type);
+  }
+  return params;
+}
+
+// Parses various forms of (param ...) or (local ...) element:
+// (param $name type) (e.g. (param $a i32))
+// (param type+)      (e.g. (param i32 f64))
+// (local $name type) (e.g. (local $a i32))
+// (local type+)      (e.g. (local i32 f64))
+// If the name is unspecified, it will create one using localIndex.
+std::vector<NameType>
+SExpressionWasmBuilder::parseParamOrLocal(Element& s, size_t& localIndex) {
+  assert(elementStartsWith(s, PARAM) || elementStartsWith(s, LOCAL));
+  std::vector<NameType> namedParams;
+  if (s.size() == 1) { // (param) or (local)
+    return namedParams;
+  }
+
+  for (size_t i = 1; i < s.size(); i++) {
+    IString name;
+    if (s[i]->dollared()) {
+      if (i != 1) {
+        throw ParseException("invalid wasm type", s[i]->line, s[i]->col);
+      }
+      if (i + 1 >= s.size()) {
+        throw ParseException("invalid param entry", s.line, s.col);
+      }
+      name = s[i]->str();
+      i++;
+    } else {
+      name = Name::fromInt(localIndex);
+    }
+    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]);
+    }
+    namedParams.emplace_back(name, type);
+  }
+  return namedParams;
+}
+
+// Parses (result type) element. (e.g. (result i32))
+std::vector<Type> SExpressionWasmBuilder::parseResults(Element& s) {
+  assert(elementStartsWith(s, RESULT));
+  std::vector<Type> types;
+  for (size_t i = 1; i < s.size(); i++) {
+    types.push_back(stringToType(s[i]->str()));
+  }
+  return types;
+}
+
+// Parses an element that references an entry in the type section. The element
+// should be in the form of (type name) or (type index).
+// (e.g. (type $a), (type 0))
+Signature SExpressionWasmBuilder::parseTypeRef(Element& s) {
+  assert(elementStartsWith(s, TYPE));
+  if (s.size() != 2) {
+    throw ParseException("invalid type reference", s.line, s.col);
+  }
+  return getFunctionSignature(*s[1]);
+}
+
+// Prases typeuse, a reference to a type definition. It is in the form of either
+// (type index) or (type name), possibly augmented by inlined (param) and
+// (result) nodes. (type) node can be omitted as well. Outputs are returned by
+// parameter references.
+// typeuse ::= (type index|name)+ |
+//             (type index|name)+ (param ..)* (result ..)* |
+//             (param ..)* (result ..)*
+size_t
+SExpressionWasmBuilder::parseTypeUse(Element& s,
+                                     size_t startPos,
+                                     Signature& functionSignature,
+                                     std::vector<NameType>& namedParams) {
+  std::vector<Type> params, results;
+  size_t i = startPos;
+
+  bool typeExists = false, paramsOrResultsExist = false;
+  if (i < s.size() && elementStartsWith(*s[i], TYPE)) {
+    typeExists = true;
+    functionSignature = parseTypeRef(*s[i++]);
+  }
+
+  size_t paramPos = i;
+  size_t localIndex = 0;
+
+  while (i < s.size() && elementStartsWith(*s[i], PARAM)) {
+    paramsOrResultsExist = true;
+    auto newParams = parseParamOrLocal(*s[i++], localIndex);
+    namedParams.insert(namedParams.end(), newParams.begin(), newParams.end());
+    for (auto p : newParams) {
+      params.push_back(p.type);
+    }
+  }
+
+  while (i < s.size() && elementStartsWith(*s[i], RESULT)) {
+    paramsOrResultsExist = true;
+    auto newResults = parseResults(*s[i++]);
+    results.insert(results.end(), newResults.begin(), newResults.end());
+  }
+
+  auto inlineSig = Signature(Type(params), Type(results));
+
+  // If none of type/param/result exists, this is equivalent to a type that does
+  // not have parameters and returns nothing.
+  if (!typeExists && !paramsOrResultsExist) {
+    paramsOrResultsExist = true;
+  }
+
+  if (!typeExists) {
+    functionSignature = inlineSig;
+  } else if (paramsOrResultsExist) {
+    // verify that (type) and (params)/(result) match
+    if (inlineSig != functionSignature) {
+      throw ParseException("type and param/result don't match",
+                           s[paramPos]->line,
+                           s[paramPos]->col);
+    }
+  }
+
+  // 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);
+  }
+
+  // If only (type) is specified, populate `namedParams`
+  if (!paramsOrResultsExist) {
+    size_t index = 0;
+    for (const auto& param : functionSignature.params) {
+      namedParams.emplace_back(Name::fromInt(index++), param);
+    }
+  }
+
+  return i;
+}
+
+// Parses a typeuse. Use this when only FunctionType* is needed.
+size_t SExpressionWasmBuilder::parseTypeUse(Element& s,
+                                            size_t startPos,
+                                            Signature& functionSignature) {
+  std::vector<NameType> params;
+  return parseTypeUse(s, startPos, functionSignature, params);
+}
+
+void SExpressionWasmBuilder::preParseFunctionType(Element& s) {
+  IString id = s[0]->str();
+  if (id == TYPE) {
+    return parseType(s);
+  }
+  if (id != FUNC) {
+    return;
+  }
+  size_t i = 1;
+  Name name, exportName;
+  i = parseFunctionNames(s, name, exportName);
+  if (!name.is()) {
+    // unnamed, use an index
+    name = Name::fromInt(functionCounter);
+  }
+  functionNames.push_back(name);
+  functionCounter++;
+  Signature sig;
+  parseTypeUse(s, i, sig);
+  functionTypes[name] = sig.results;
+}
+
+size_t SExpressionWasmBuilder::parseFunctionNames(Element& s,
+                                                  Name& name,
+                                                  Name& exportName) {
+  size_t i = 1;
+  while (i < s.size() && i < 3 && s[i]->isStr()) {
+    if (s[i]->quoted()) {
+      // an export name
+      exportName = s[i]->str();
+      i++;
+    } else if (s[i]->dollared()) {
+      name = s[i]->str();
+      i++;
+    } else {
+      break;
+    }
+  }
+  if (i < s.size() && s[i]->isList()) {
+    auto& inner = *s[i];
+    if (elementStartsWith(inner, EXPORT)) {
+      exportName = inner[1]->str();
+      i++;
+    }
+  }
+#if 0
+  if (exportName.is() && !name.is()) {
+    name = exportName; // useful for debugging
+  }
+#endif
+  return i;
+}
+
+void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) {
+  brokeToAutoBlock = false;
+
+  Name name, exportName;
+  size_t i = parseFunctionNames(s, name, exportName);
+  if (!preParseImport) {
+    if (!name.is()) {
+      // unnamed, use an index
+      name = Name::fromInt(functionCounter);
+    }
+    functionCounter++;
+  } else {
+    // just preparsing, functionCounter was incremented by preParseFunctionType
+    if (!name.is()) {
+      // unnamed, use an index
+      name = functionNames[functionCounter - 1];
+    }
+  }
+  if (exportName.is()) {
+    auto ex = make_unique<Export>();
+    ex->name = exportName;
+    ex->value = name;
+    ex->kind = ExternalKind::Function;
+    if (wasm.getExportOrNull(ex->name)) {
+      throw ParseException("duplicate export", s.line, s.col);
+    }
+    wasm.addExport(ex.release());
+  }
+
+  // parse import
+  Name importModule, importBase;
+  if (i < s.size() && elementStartsWith(*s[i], IMPORT)) {
+    Element& curr = *s[i];
+    importModule = curr[1]->str();
+    importBase = curr[2]->str();
+    i++;
+  }
+
+  // parse typeuse: type/param/result
+  Signature sig;
+  std::vector<NameType> params;
+  i = parseTypeUse(s, i, sig, params);
+
+  // when (import) is inside a (func) element, this is not a function definition
+  // but an import.
+  if (importModule.is()) {
+    if (!importBase.size()) {
+      throw ParseException("module but no base for import", s.line, s.col);
+    }
+    if (!preParseImport) {
+      throw ParseException("!preParseImport in func", s.line, s.col);
+    }
+    auto im = make_unique<Function>();
+    im->name = name;
+    im->module = importModule;
+    im->base = importBase;
+    im->sig = sig;
+    functionTypes[name] = sig.results;
+    if (wasm.getFunctionOrNull(im->name)) {
+      throw ParseException("duplicate import", s.line, s.col);
+    }
+    wasm.addFunction(im.release());
+    if (currFunction) {
+      throw ParseException("import module inside function dec", s.line, s.col);
+    }
+    nameMapper.clear();
+    return;
+  }
+  // at this point this not an import but a real function definition.
+  if (preParseImport) {
+    throw ParseException("preParseImport in func", s.line, s.col);
+  }
+
+  size_t localIndex = params.size(); // local index for params and locals
+
+  // parse locals
+  std::vector<NameType> vars;
+  while (i < s.size() && elementStartsWith(*s[i], LOCAL)) {
+    auto newVars = parseParamOrLocal(*s[i++], localIndex);
+    vars.insert(vars.end(), newVars.begin(), newVars.end());
+  }
+
+  // make a new function
+  currFunction = std::unique_ptr<Function>(Builder(wasm).makeFunction(
+    name, std::move(params), sig.results, std::move(vars)));
+  currFunction->profile = profile;
+
+  // parse body
+  Block* autoBlock = nullptr; // may need to add a block for the very top level
+  auto ensureAutoBlock = [&]() {
+    if (!autoBlock) {
+      autoBlock = allocator.alloc<Block>();
+      autoBlock->list.push_back(currFunction->body);
+      currFunction->body = autoBlock;
+    }
+  };
+  while (i < s.size()) {
+    Expression* ex = parseExpression(*s[i++]);
+    if (!currFunction->body) {
+      currFunction->body = ex;
+    } else {
+      ensureAutoBlock();
+      autoBlock->list.push_back(ex);
+    }
+  }
+
+  if (brokeToAutoBlock) {
+    ensureAutoBlock();
+    autoBlock->name = FAKE_RETURN;
+  }
+  if (autoBlock) {
+    autoBlock->finalize(sig.results);
+  }
+  if (!currFunction->body) {
+    currFunction->body = allocator.alloc<Nop>();
+  }
+  if (s.startLoc) {
+    currFunction->prologLocation.insert(getDebugLocation(*s.startLoc));
+  }
+  if (s.endLoc) {
+    currFunction->epilogLocation.insert(getDebugLocation(*s.endLoc));
+  }
+  if (wasm.getFunctionOrNull(currFunction->name)) {
+    throw ParseException("duplicate function", s.line, s.col);
+  }
+  wasm.addFunction(currFunction.release());
+  nameMapper.clear();
+}
+
+Type SExpressionWasmBuilder::stringToType(const char* str,
+                                          bool allowError,
+                                          bool prefix) {
+  if (str[0] == 'i') {
+    if (str[1] == '3' && str[2] == '2' && (prefix || str[3] == 0)) {
+      return Type::i32;
+    }
+    if (str[1] == '6' && str[2] == '4' && (prefix || str[3] == 0)) {
+      return Type::i64;
+    }
+  }
+  if (str[0] == 'f') {
+    if (str[1] == '3' && str[2] == '2' && (prefix || str[3] == 0)) {
+      return Type::f32;
+    }
+    if (str[1] == '6' && str[2] == '4' && (prefix || str[3] == 0)) {
+      return Type::f64;
+    }
+  }
+  if (str[0] == 'v') {
+    if (str[1] == '1' && str[2] == '2' && str[3] == '8' &&
+        (prefix || str[4] == 0)) {
+      return Type::v128;
+    }
+  }
+  if (strncmp(str, "funcref", 7) == 0 && (prefix || str[7] == 0)) {
+    return Type::funcref;
+  }
+  if (strncmp(str, "externref", 9) == 0 && (prefix || str[9] == 0)) {
+    return Type::externref;
+  }
+  if (strncmp(str, "exnref", 6) == 0 && (prefix || str[6] == 0)) {
+    return Type::exnref;
+  }
+  if (strncmp(str, "anyref", 6) == 0 && (prefix || str[6] == 0)) {
+    return Type::anyref;
+  }
+  if (strncmp(str, "eqref", 5) == 0 && (prefix || str[5] == 0)) {
+    return Type::eqref;
+  }
+  if (strncmp(str, "i31ref", 6) == 0 && (prefix || str[6] == 0)) {
+    return Type::i31ref;
+  }
+  if (allowError) {
+    return Type::none;
+  }
+  throw ParseException(std::string("invalid wasm type: ") + str);
+}
+
+HeapType SExpressionWasmBuilder::stringToHeapType(const char* str,
+                                                  bool prefix) {
+  if (str[0] == 'a') {
+    if (str[1] == 'n' && str[2] == 'y' && (prefix || str[3] == 0)) {
+      return HeapType::AnyKind;
+    }
+  }
+  if (str[0] == 'e') {
+    if (str[1] == 'q' && (prefix || str[2] == 0)) {
+      return HeapType::EqKind;
+    }
+    if (str[1] == 'x') {
+      if (str[2] == 'n' && (prefix || str[3] == 0)) {
+        return HeapType::ExnKind;
+      }
+      if (str[2] == 't' && str[3] == 'e' && str[4] == 'r' && str[5] == 'n' &&
+          (prefix || str[6] == 0)) {
+        return HeapType::ExternKind;
+      }
+    }
+  }
+  if (str[0] == 'i') {
+    if (str[1] == '3' && str[2] == '1' && (prefix || str[3] == 0)) {
+      return HeapType::I31Kind;
+    }
+  }
+  if (str[0] == 'f') {
+    if (str[1] == 'u' && str[2] == 'n' && str[3] == 'c' &&
+        (prefix || str[4] == 0)) {
+      return HeapType::FuncKind;
+    }
+  }
+  throw ParseException(std::string("invalid wasm heap type: ") + str);
+}
+
+Type SExpressionWasmBuilder::elementToType(Element& s) {
+  if (s.isStr()) {
+    return stringToType(s.str(), false, false);
+  }
+  auto& tuple = s.list();
+  std::vector<Type> types;
+  for (size_t i = 0; i < s.size(); ++i) {
+    types.push_back(stringToType(tuple[i]->str()));
+  }
+  return Type(types);
+}
+
+Type SExpressionWasmBuilder::stringToLaneType(const char* str) {
+  if (strcmp(str, "i8x16") == 0) {
+    return Type::i32;
+  }
+  if (strcmp(str, "i16x8") == 0) {
+    return Type::i32;
+  }
+  if (strcmp(str, "i32x4") == 0) {
+    return Type::i32;
+  }
+  if (strcmp(str, "i64x2") == 0) {
+    return Type::i64;
+  }
+  if (strcmp(str, "f32x4") == 0) {
+    return Type::f32;
+  }
+  if (strcmp(str, "f64x2") == 0) {
+    return Type::f64;
+  }
+  return Type::none;
+}
+
+Function::DebugLocation
+SExpressionWasmBuilder::getDebugLocation(const SourceLocation& loc) {
+  IString file = loc.filename;
+  auto& debugInfoFileNames = wasm.debugInfoFileNames;
+  auto iter = debugInfoFileIndices.find(file);
+  if (iter == debugInfoFileIndices.end()) {
+    Index index = debugInfoFileNames.size();
+    debugInfoFileNames.push_back(file.c_str());
+    debugInfoFileIndices[file] = index;
+  }
+  uint32_t fileIndex = debugInfoFileIndices[file];
+  return {fileIndex, loc.line, loc.column};
+}
+
+Expression* SExpressionWasmBuilder::parseExpression(Element& s) {
+  Expression* result = makeExpression(s);
+  if (s.startLoc && currFunction) {
+    currFunction->debugLocations[result] = getDebugLocation(*s.startLoc);
+  }
+  return result;
+}
+
+Expression* SExpressionWasmBuilder::makeExpression(Element& s){
+#define INSTRUCTION_PARSER
+#include "gen-s-parser.inc"
+}
+
+Expression* SExpressionWasmBuilder::makeUnreachable() {
+  return allocator.alloc<Unreachable>();
+}
+
+Expression* SExpressionWasmBuilder::makeNop() { return allocator.alloc<Nop>(); }
+
+Expression* SExpressionWasmBuilder::makeBinary(Element& s, BinaryOp op) {
+  auto ret = allocator.alloc<Binary>();
+  ret->op = op;
+  ret->left = parseExpression(s[1]);
+  ret->right = parseExpression(s[2]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeUnary(Element& s, UnaryOp op) {
+  auto ret = allocator.alloc<Unary>();
+  ret->op = op;
+  ret->value = parseExpression(s[1]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeSelect(Element& s) {
+  auto ret = allocator.alloc<Select>();
+  Index i = 1;
+  Type type = parseOptionalResultType(s, i);
+  ret->ifTrue = parseExpression(s[i++]);
+  ret->ifFalse = parseExpression(s[i++]);
+  ret->condition = parseExpression(s[i]);
+  if (type.isConcrete()) {
+    ret->finalize(type);
+  } else {
+    ret->finalize();
+  }
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeDrop(Element& s) {
+  auto ret = allocator.alloc<Drop>();
+  ret->value = parseExpression(s[1]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeMemorySize(Element& s) {
+  auto ret = allocator.alloc<MemorySize>();
+  if (wasm.memory.is64()) {
+    ret->make64();
+  }
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeMemoryGrow(Element& s) {
+  auto ret = allocator.alloc<MemoryGrow>();
+  if (wasm.memory.is64()) {
+    ret->make64();
+  }
+  ret->delta = parseExpression(s[1]);
+  ret->finalize();
+  return ret;
+}
+
+Index SExpressionWasmBuilder::getLocalIndex(Element& s) {
+  if (!currFunction) {
+    throw ParseException("local access in non-function scope", s.line, s.col);
+  }
+  if (s.dollared()) {
+    auto ret = s.str();
+    if (currFunction->localIndices.count(ret) == 0) {
+      throw ParseException("bad local name", s.line, s.col);
+    }
+    return currFunction->getLocalIndex(ret);
+  }
+  // this is a numeric index
+  Index ret = atoi(s.c_str());
+  if (ret >= currFunction->getNumLocals()) {
+    throw ParseException("bad local index", s.line, s.col);
+  }
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeLocalGet(Element& s) {
+  auto ret = allocator.alloc<LocalGet>();
+  ret->index = getLocalIndex(*s[1]);
+  ret->type = currFunction->getLocalType(ret->index);
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeLocalTee(Element& s) {
+  auto ret = allocator.alloc<LocalSet>();
+  ret->index = getLocalIndex(*s[1]);
+  ret->value = parseExpression(s[2]);
+  ret->makeTee(currFunction->getLocalType(ret->index));
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeLocalSet(Element& s) {
+  auto ret = allocator.alloc<LocalSet>();
+  ret->index = getLocalIndex(*s[1]);
+  ret->value = parseExpression(s[2]);
+  ret->makeSet();
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeGlobalGet(Element& s) {
+  auto ret = allocator.alloc<GlobalGet>();
+  ret->name = getGlobalName(*s[1]);
+  auto* global = wasm.getGlobalOrNull(ret->name);
+  if (!global) {
+    throw ParseException("bad global.get name", s.line, s.col);
+  }
+  ret->type = global->type;
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeGlobalSet(Element& s) {
+  auto ret = allocator.alloc<GlobalSet>();
+  ret->name = getGlobalName(*s[1]);
+  if (wasm.getGlobalOrNull(ret->name) &&
+      !wasm.getGlobalOrNull(ret->name)->mutable_) {
+    throw ParseException("global.set of immutable", s.line, s.col);
+  }
+  ret->value = parseExpression(s[2]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeBlock(Element& s) {
+  if (!currFunction) {
+    throw ParseException(
+      "block is unallowed outside of functions", s.line, s.col);
+  }
+  // special-case Block, because Block nesting (in their first element) can be
+  // incredibly deep
+  auto curr = allocator.alloc<Block>();
+  auto* sp = &s;
+  std::vector<std::pair<Element*, Block*>> stack;
+  while (1) {
+    stack.emplace_back(sp, curr);
+    auto& s = *sp;
+    Index i = 1;
+    Name sName;
+    if (i < s.size() && s[i]->isStr()) {
+      // could be a name or a type
+      if (s[i]->dollared() ||
+          stringToType(s[i]->str(), true /* allowError */) == Type::none) {
+        sName = s[i++]->str();
+      } else {
+        sName = "block";
+      }
+    } else {
+      sName = "block";
+    }
+    curr->name = nameMapper.pushLabelName(sName);
+    // block signature
+    curr->type = parseOptionalResultType(s, i);
+    if (i >= s.size()) {
+      break; // empty block
+    }
+    auto& first = *s[i];
+    if (elementStartsWith(first, BLOCK)) {
+      // recurse
+      curr = allocator.alloc<Block>();
+      if (first.startLoc) {
+        currFunction->debugLocations[curr] = getDebugLocation(*first.startLoc);
+      }
+      sp = &first;
+      continue;
+    }
+    break;
+  }
+  // we now have a stack of Blocks, with their labels, but no contents yet
+  for (int t = int(stack.size()) - 1; t >= 0; t--) {
+    auto* sp = stack[t].first;
+    auto* curr = stack[t].second;
+    auto& s = *sp;
+    size_t i = 1;
+    if (i < s.size()) {
+      while (i < s.size() && s[i]->isStr()) {
+        i++;
+      }
+      if (i < s.size() && elementStartsWith(*s[i], RESULT)) {
+        i++;
+      }
+      if (t < int(stack.size()) - 1) {
+        // first child is one of our recursions
+        curr->list.push_back(stack[t + 1].second);
+        i++;
+      }
+      for (; i < s.size(); i++) {
+        curr->list.push_back(parseExpression(s[i]));
+      }
+    }
+    nameMapper.popLabelName(curr->name);
+    curr->finalize(curr->type);
+  }
+  return stack[0].second;
+}
+
+// Similar to block, but the label is handled by the enclosing if (since there
+// might not be a then or else, ick)
+Expression* SExpressionWasmBuilder::makeThenOrElse(Element& s) {
+  auto ret = allocator.alloc<Block>();
+  size_t i = 1;
+  if (s[1]->isStr()) {
+    i++;
+  }
+  for (; i < s.size(); i++) {
+    ret->list.push_back(parseExpression(s[i]));
+  }
+  ret->finalize();
+  return ret;
+}
+
+template<int Lanes>
+static Literal makeLanes(Element& s, MixedArena& allocator, Type lane_t) {
+  std::array<Literal, Lanes> lanes;
+  for (size_t i = 0; i < Lanes; ++i) {
+    Expression* lane = parseConst(s[i + 2]->str(), lane_t, allocator);
+    if (lane) {
+      lanes[i] = lane->cast<Const>()->value;
+    } else {
+      throw ParseException(
+        "Could not parse v128 lane", s[i + 2]->line, s[i + 2]->col);
+    }
+  }
+  return Literal(lanes);
+}
+
+Expression* SExpressionWasmBuilder::makeConst(Element& s, Type type) {
+  if (type != Type::v128) {
+    auto ret = parseConst(s[1]->str(), type, allocator);
+    if (!ret) {
+      throw ParseException("bad const", s[1]->line, s[1]->col);
+    }
+    return ret;
+  }
+
+  auto ret = allocator.alloc<Const>();
+  Type lane_t = stringToLaneType(s[1]->str().str);
+  size_t lanes = s.size() - 2;
+  switch (lanes) {
+    case 2: {
+      if (lane_t != Type::i64 && lane_t != Type::f64) {
+        throw ParseException(
+          "Unexpected v128 literal lane type", s[1]->line, s[1]->col);
+      }
+      ret->value = makeLanes<2>(s, allocator, lane_t);
+      break;
+    }
+    case 4: {
+      if (lane_t != Type::i32 && lane_t != Type::f32) {
+        throw ParseException(
+          "Unexpected v128 literal lane type", s[1]->line, s[1]->col);
+      }
+      ret->value = makeLanes<4>(s, allocator, lane_t);
+      break;
+    }
+    case 8: {
+      if (lane_t != Type::i32) {
+        throw ParseException(
+          "Unexpected v128 literal lane type", s[1]->line, s[1]->col);
+      }
+      ret->value = makeLanes<8>(s, allocator, lane_t);
+      break;
+    }
+    case 16: {
+      if (lane_t != Type::i32) {
+        throw ParseException(
+          "Unexpected v128 literal lane type", s[1]->line, s[1]->col);
+      }
+      ret->value = makeLanes<16>(s, allocator, lane_t);
+      break;
+    }
+    default:
+      throw ParseException(
+        "Unexpected number of lanes in v128 literal", s[1]->line, s[1]->col);
+  }
+  ret->finalize();
+  return ret;
+}
+
+static uint8_t parseMemBytes(const char*& s, uint8_t fallback) {
+  uint8_t ret;
+  if (s[0] == '8') {
+    ret = 1;
+    s++;
+  } else if (s[0] == '1') {
+    if (s[1] != '6') {
+      throw ParseException(std::string("expected 16 for memop size: ") + s);
+    }
+    ret = 2;
+    s += 2;
+  } else if (s[0] == '3') {
+    if (s[1] != '2') {
+      throw ParseException(std::string("expected 32 for memop size: ") + s);
+    };
+    ret = 4;
+    s += 2;
+  } else {
+    ret = fallback;
+  }
+  return ret;
+}
+
+static size_t parseMemAttributes(Element& s,
+                                 Address& offset,
+                                 Address& align,
+                                 Address fallbackAlign) {
+  size_t i = 1;
+  offset = 0;
+  align = fallbackAlign;
+  while (!s[i]->isList()) {
+    const char* str = s[i]->c_str();
+    const char* eq = strchr(str, '=');
+    if (!eq) {
+      throw ParseException(
+        "missing = in memory attribute", s[i]->line, s[i]->col);
+    }
+    eq++;
+    if (*eq == 0) {
+      throw ParseException(
+        "missing value in memory attribute", s[i]->line, s[i]->col);
+    }
+    char* endptr;
+    uint64_t value = strtoll(eq, &endptr, 10);
+    if (*endptr != 0) {
+      throw ParseException(
+        "bad memory attribute immediate", s[i]->line, s[i]->col);
+    }
+    if (str[0] == 'a') {
+      if (value > std::numeric_limits<uint32_t>::max()) {
+        throw ParseException("bad align", s[i]->line, s[i]->col);
+      }
+      align = value;
+    } else if (str[0] == 'o') {
+      if (value > std::numeric_limits<uint32_t>::max()) {
+        throw ParseException("bad offset", s[i]->line, s[i]->col);
+      }
+      offset = value;
+    } else {
+      throw ParseException("bad memory attribute", s[i]->line, s[i]->col);
+    }
+    i++;
+  }
+  return i;
+}
+
+static const char* findMemExtra(const Element& s, size_t skip, bool isAtomic) {
+  auto* str = s.c_str();
+  auto size = strlen(str);
+  auto* ret = strchr(str, '.');
+  if (!ret) {
+    throw ParseException("missing '.' in memory access", s.line, s.col);
+  }
+  ret += skip;
+  if (isAtomic) {
+    ret += 7; // after "type.atomic.load"
+  }
+  if (ret > str + size) {
+    throw ParseException("memory access ends abruptly", s.line, s.col);
+  }
+  return ret;
+}
+
+Expression*
+SExpressionWasmBuilder::makeLoad(Element& s, Type type, bool isAtomic) {
+  const char* extra = findMemExtra(*s[0], 5 /* after "type.load" */, isAtomic);
+  auto* ret = allocator.alloc<Load>();
+  ret->isAtomic = isAtomic;
+  ret->type = type;
+  ret->bytes = parseMemBytes(extra, type.getByteSize());
+  ret->signed_ = extra[0] && extra[1] == 's';
+  size_t i = parseMemAttributes(s, ret->offset, ret->align, ret->bytes);
+  ret->ptr = parseExpression(s[i]);
+  ret->finalize();
+  return ret;
+}
+
+Expression*
+SExpressionWasmBuilder::makeStore(Element& s, Type type, bool isAtomic) {
+  const char* extra = findMemExtra(*s[0], 6 /* after "type.store" */, isAtomic);
+  auto ret = allocator.alloc<Store>();
+  ret->isAtomic = isAtomic;
+  ret->valueType = type;
+  ret->bytes = parseMemBytes(extra, type.getByteSize());
+  size_t i = parseMemAttributes(s, ret->offset, ret->align, ret->bytes);
+  ret->ptr = parseExpression(s[i]);
+  ret->value = parseExpression(s[i + 1]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeAtomicRMWOrCmpxchg(Element& s,
+                                                           Type type) {
+  const char* extra = findMemExtra(
+    *s[0], 11 /* after "type.atomic.rmw" */, /* isAtomic = */ false);
+  auto bytes = parseMemBytes(extra, type.getByteSize());
+  extra = strchr(extra, '.'); // after the optional '_u' and before the opcode
+  if (!extra) {
+    throw ParseException("malformed atomic rmw instruction", s.line, s.col);
+  }
+  extra++; // after the '.'
+  if (!strncmp(extra, "cmpxchg", 7)) {
+    return makeAtomicCmpxchg(s, type, bytes, extra);
+  }
+  return makeAtomicRMW(s, type, bytes, extra);
+}
+
+Expression* SExpressionWasmBuilder::makeAtomicRMW(Element& s,
+                                                  Type type,
+                                                  uint8_t bytes,
+                                                  const char* extra) {
+  auto ret = allocator.alloc<AtomicRMW>();
+  ret->type = type;
+  ret->bytes = bytes;
+  if (!strncmp(extra, "add", 3)) {
+    ret->op = Add;
+  } else if (!strncmp(extra, "and", 3)) {
+    ret->op = And;
+  } else if (!strncmp(extra, "or", 2)) {
+    ret->op = Or;
+  } else if (!strncmp(extra, "sub", 3)) {
+    ret->op = Sub;
+  } else if (!strncmp(extra, "xor", 3)) {
+    ret->op = Xor;
+  } else if (!strncmp(extra, "xchg", 4)) {
+    ret->op = Xchg;
+  } else {
+    throw ParseException("bad atomic rmw operator", s.line, s.col);
+  }
+  Address align;
+  size_t i = parseMemAttributes(s, ret->offset, align, ret->bytes);
+  if (align != ret->bytes) {
+    throw ParseException("Align of Atomic RMW must match size", s.line, s.col);
+  }
+  ret->ptr = parseExpression(s[i]);
+  ret->value = parseExpression(s[i + 1]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeAtomicCmpxchg(Element& s,
+                                                      Type type,
+                                                      uint8_t bytes,
+                                                      const char* extra) {
+  auto ret = allocator.alloc<AtomicCmpxchg>();
+  ret->type = type;
+  ret->bytes = bytes;
+  Address align;
+  size_t i = parseMemAttributes(s, ret->offset, align, ret->bytes);
+  if (align != ret->bytes) {
+    throw ParseException(
+      "Align of Atomic Cmpxchg must match size", s.line, s.col);
+  }
+  ret->ptr = parseExpression(s[i]);
+  ret->expected = parseExpression(s[i + 1]);
+  ret->replacement = parseExpression(s[i + 2]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeAtomicWait(Element& s, Type type) {
+  auto ret = allocator.alloc<AtomicWait>();
+  ret->type = Type::i32;
+  ret->expectedType = type;
+  Address align;
+  Address expectedAlign;
+  if (type == Type::i32) {
+    expectedAlign = 4;
+  } else if (type == Type::i64) {
+    expectedAlign = 8;
+  } else {
+    WASM_UNREACHABLE("Invalid prefix for 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);
+  }
+  ret->ptr = parseExpression(s[i]);
+  ret->expected = parseExpression(s[i + 1]);
+  ret->timeout = parseExpression(s[i + 2]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeAtomicNotify(Element& s) {
+  auto ret = allocator.alloc<AtomicNotify>();
+  ret->type = Type::i32;
+  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);
+  }
+  ret->ptr = parseExpression(s[i]);
+  ret->notifyCount = parseExpression(s[i + 1]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeAtomicFence(Element& s) {
+  return allocator.alloc<AtomicFence>();
+}
+
+static uint8_t parseLaneIndex(const Element* s, size_t lanes) {
+  const char* str = s->c_str();
+  char* end;
+  auto n = static_cast<unsigned long long>(strtoll(str, &end, 10));
+  if (end == str || *end != '\0') {
+    throw ParseException("Expected lane index", s->line, s->col);
+  }
+  if (n > lanes) {
+    throw ParseException(
+      "lane index must be less than " + std::to_string(lanes), s->line, s->col);
+  }
+  return uint8_t(n);
+}
+
+Expression* SExpressionWasmBuilder::makeSIMDExtract(Element& s,
+                                                    SIMDExtractOp op,
+                                                    size_t lanes) {
+  auto ret = allocator.alloc<SIMDExtract>();
+  ret->op = op;
+  ret->index = parseLaneIndex(s[1], lanes);
+  ret->vec = parseExpression(s[2]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeSIMDReplace(Element& s,
+                                                    SIMDReplaceOp op,
+                                                    size_t lanes) {
+  auto ret = allocator.alloc<SIMDReplace>();
+  ret->op = op;
+  ret->index = parseLaneIndex(s[1], lanes);
+  ret->vec = parseExpression(s[2]);
+  ret->value = parseExpression(s[3]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeSIMDShuffle(Element& s) {
+  auto ret = allocator.alloc<SIMDShuffle>();
+  for (size_t i = 0; i < 16; ++i) {
+    ret->mask[i] = parseLaneIndex(s[i + 1], 32);
+  }
+  ret->left = parseExpression(s[17]);
+  ret->right = parseExpression(s[18]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeSIMDTernary(Element& s,
+                                                    SIMDTernaryOp op) {
+  auto ret = allocator.alloc<SIMDTernary>();
+  ret->op = op;
+  ret->a = parseExpression(s[1]);
+  ret->b = parseExpression(s[2]);
+  ret->c = parseExpression(s[3]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeSIMDShift(Element& s, SIMDShiftOp op) {
+  auto ret = allocator.alloc<SIMDShift>();
+  ret->op = op;
+  ret->vec = parseExpression(s[1]);
+  ret->shift = parseExpression(s[2]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeSIMDLoad(Element& s, SIMDLoadOp op) {
+  auto ret = allocator.alloc<SIMDLoad>();
+  ret->op = op;
+  Address defaultAlign;
+  switch (op) {
+    case LoadSplatVec8x16:
+      defaultAlign = 1;
+      break;
+    case LoadSplatVec16x8:
+      defaultAlign = 2;
+      break;
+    case LoadSplatVec32x4:
+    case Load32Zero:
+      defaultAlign = 4;
+      break;
+    case LoadSplatVec64x2:
+    case LoadExtSVec8x8ToVecI16x8:
+    case LoadExtUVec8x8ToVecI16x8:
+    case LoadExtSVec16x4ToVecI32x4:
+    case LoadExtUVec16x4ToVecI32x4:
+    case LoadExtSVec32x2ToVecI64x2:
+    case LoadExtUVec32x2ToVecI64x2:
+    case Load64Zero:
+      defaultAlign = 8;
+      break;
+  }
+  size_t i = parseMemAttributes(s, ret->offset, ret->align, defaultAlign);
+  ret->ptr = parseExpression(s[i]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeMemoryInit(Element& s) {
+  auto ret = allocator.alloc<MemoryInit>();
+  ret->segment = atoi(s[1]->str().c_str());
+  ret->dest = parseExpression(s[2]);
+  ret->offset = parseExpression(s[3]);
+  ret->size = parseExpression(s[4]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeDataDrop(Element& s) {
+  auto ret = allocator.alloc<DataDrop>();
+  ret->segment = atoi(s[1]->str().c_str());
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeMemoryCopy(Element& s) {
+  auto ret = allocator.alloc<MemoryCopy>();
+  ret->dest = parseExpression(s[1]);
+  ret->source = parseExpression(s[2]);
+  ret->size = parseExpression(s[3]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeMemoryFill(Element& s) {
+  auto ret = allocator.alloc<MemoryFill>();
+  ret->dest = parseExpression(s[1]);
+  ret->value = parseExpression(s[2]);
+  ret->size = parseExpression(s[3]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makePop(Element& s) {
+  auto ret = allocator.alloc<Pop>();
+  std::vector<Type> types;
+  for (size_t i = 1; i < s.size(); ++i) {
+    types.push_back(stringToType(s[i]->str()));
+  }
+  ret->type = Type(types);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeIf(Element& s) {
+  auto ret = allocator.alloc<If>();
+  Index i = 1;
+  Name sName;
+  if (s[i]->dollared()) {
+    // the if is labeled
+    sName = s[i++]->str();
+  } else {
+    sName = "if";
+  }
+  auto label = nameMapper.pushLabelName(sName);
+  // if signature
+  Type type = parseOptionalResultType(s, i);
+  ret->condition = parseExpression(s[i++]);
+  ret->ifTrue = parseExpression(*s[i++]);
+  if (i < s.size()) {
+    ret->ifFalse = parseExpression(*s[i++]);
+  }
+  ret->finalize(type);
+  nameMapper.popLabelName(label);
+  // create a break target if we must
+  if (BranchUtils::BranchSeeker::has(ret, label)) {
+    auto* block = allocator.alloc<Block>();
+    block->name = label;
+    block->list.push_back(ret);
+    block->finalize(type);
+    return block;
+  }
+  return ret;
+}
+
+Expression*
+SExpressionWasmBuilder::makeMaybeBlock(Element& s, size_t i, Type type) {
+  Index stopAt = -1;
+  if (s.size() == i) {
+    return allocator.alloc<Nop>();
+  }
+  if (s.size() == i + 1) {
+    return parseExpression(s[i]);
+  }
+  auto ret = allocator.alloc<Block>();
+  for (; i < s.size() && i < stopAt; i++) {
+    ret->list.push_back(parseExpression(s[i]));
+  }
+  ret->finalize(type);
+  // Note that we do not name these implicit/synthetic blocks. They
+  // are the effects of syntactic sugar, and nothing can branch to
+  // them anyhow.
+  return ret;
+}
+
+Type SExpressionWasmBuilder::parseOptionalResultType(Element& s, Index& i) {
+  if (s.size() == i) {
+    return Type::none;
+  }
+
+  // TODO(sbc): Remove support for old result syntax (bare streing) once the
+  // spec tests are updated.
+  if (s[i]->isStr()) {
+    return stringToType(s[i++]->str());
+  }
+
+  Element& results = *s[i];
+  IString id = results[0]->str();
+  if (id == RESULT) {
+    i++;
+    return Type(parseResults(results));
+  }
+  return Type::none;
+}
+
+Expression* SExpressionWasmBuilder::makeLoop(Element& s) {
+  auto ret = allocator.alloc<Loop>();
+  Index i = 1;
+  Name sName;
+  if (s.size() > i && s[i]->dollared()) {
+    sName = s[i++]->str();
+  } else {
+    sName = "loop-in";
+  }
+  ret->name = nameMapper.pushLabelName(sName);
+  ret->type = parseOptionalResultType(s, i);
+  ret->body = makeMaybeBlock(s, i, ret->type);
+  nameMapper.popLabelName(ret->name);
+  ret->finalize(ret->type);
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeCall(Element& s, bool isReturn) {
+  auto target = getFunctionName(*s[1]);
+  auto ret = allocator.alloc<Call>();
+  ret->target = target;
+  ret->type = functionTypes[ret->target];
+  parseCallOperands(s, 2, s.size(), ret);
+  ret->isReturn = isReturn;
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeCallIndirect(Element& s,
+                                                     bool isReturn) {
+  if (!wasm.table.exists) {
+    throw ParseException("no table", s.line, s.col);
+  }
+  Index i = 1;
+  auto ret = allocator.alloc<CallIndirect>();
+  i = parseTypeUse(s, i, ret->sig);
+  parseCallOperands(s, i, s.size() - 1, ret);
+  ret->target = parseExpression(s[s.size() - 1]);
+  ret->isReturn = isReturn;
+  ret->finalize();
+  return ret;
+}
+
+Name SExpressionWasmBuilder::getLabel(Element& s) {
+  if (s.dollared()) {
+    return nameMapper.sourceToUnique(s.str());
+  } else {
+    // offset, break to nth outside label
+    uint64_t offset;
+    try {
+      offset = std::stoll(s.c_str(), nullptr, 0);
+    } catch (std::invalid_argument&) {
+      throw ParseException("invalid break offset", s.line, s.col);
+    } catch (std::out_of_range&) {
+      throw ParseException("out of range break offset", s.line, s.col);
+    }
+    if (offset > nameMapper.labelStack.size()) {
+      throw ParseException("invalid label", s.line, s.col);
+    }
+    if (offset == nameMapper.labelStack.size()) {
+      // a break to the function's scope. this means we need an automatic block,
+      // with a name
+      brokeToAutoBlock = true;
+      return FAKE_RETURN;
+    }
+    return nameMapper.labelStack[nameMapper.labelStack.size() - 1 - offset];
+  }
+}
+
+Expression* SExpressionWasmBuilder::makeBreak(Element& s) {
+  auto ret = allocator.alloc<Break>();
+  size_t i = 1;
+  ret->name = getLabel(*s[i]);
+  i++;
+  if (i == s.size()) {
+    return ret;
+  }
+  if (elementStartsWith(s, BR_IF)) {
+    if (i + 1 < s.size()) {
+      ret->value = parseExpression(s[i]);
+      i++;
+    }
+    ret->condition = parseExpression(s[i]);
+  } else {
+    ret->value = parseExpression(s[i]);
+  }
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeBreakTable(Element& s) {
+  auto ret = allocator.alloc<Switch>();
+  size_t i = 1;
+  while (!s[i]->isList()) {
+    ret->targets.push_back(getLabel(*s[i++]));
+  }
+  if (ret->targets.size() == 0) {
+    throw ParseException("switch with no targets", s.line, s.col);
+  }
+  ret->default_ = ret->targets.back();
+  ret->targets.pop_back();
+  ret->condition = parseExpression(s[i++]);
+  if (i < s.size()) {
+    ret->value = ret->condition;
+    ret->condition = parseExpression(s[i++]);
+  }
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeReturn(Element& s) {
+  auto ret = allocator.alloc<Return>();
+  if (s.size() >= 2) {
+    ret->value = parseExpression(s[1]);
+  }
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeRefNull(Element& s) {
+  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);
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeRefIsNull(Element& s) {
+  auto ret = allocator.alloc<RefIsNull>();
+  ret->value = parseExpression(s[1]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeRefFunc(Element& s) {
+  auto func = getFunctionName(*s[1]);
+  auto ret = allocator.alloc<RefFunc>();
+  ret->func = func;
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeRefEq(Element& s) {
+  auto ret = allocator.alloc<RefEq>();
+  ret->left = parseExpression(s[1]);
+  ret->right = parseExpression(s[2]);
+  ret->finalize();
+  return ret;
+}
+
+// try-catch-end is written in the folded wast format as
+// (try
+//   ...
+//  (catch
+//    ...
+//  )
+// )
+// The parenthesis wrapping 'catch' is just a syntax and does not affect nested
+// depths of instructions within.
+Expression* SExpressionWasmBuilder::makeTry(Element& s) {
+  auto ret = allocator.alloc<Try>();
+  Index i = 1;
+  Name sName;
+  if (s[i]->dollared()) {
+    // the try is labeled
+    sName = s[i++]->str();
+  } else {
+    sName = "try";
+  }
+  auto label = nameMapper.pushLabelName(sName);
+  Type type = parseOptionalResultType(s, i); // signature
+  if (!elementStartsWith(*s[i], "do")) {
+    throw ParseException(
+      "try body should start with 'do'", s[i]->line, s[i]->col);
+  }
+  ret->body = makeTryOrCatchBody(*s[i++], type, true);
+  if (!elementStartsWith(*s[i], "catch")) {
+    throw ParseException("catch clause does not exist", s[i]->line, s[i]->col);
+  }
+  ret->catchBody = makeTryOrCatchBody(*s[i++], type, false);
+  ret->finalize(type);
+  nameMapper.popLabelName(label);
+  // create a break target if we must
+  if (BranchUtils::BranchSeeker::has(ret, label)) {
+    auto* block = allocator.alloc<Block>();
+    block->name = label;
+    block->list.push_back(ret);
+    block->finalize(type);
+    return block;
+  }
+  return ret;
+}
+
+Expression*
+SExpressionWasmBuilder::makeTryOrCatchBody(Element& s, Type type, bool isTry) {
+  if (isTry && !elementStartsWith(s, "do")) {
+    throw ParseException("invalid try do clause", s.line, s.col);
+  }
+  if (!isTry && !elementStartsWith(s, "catch")) {
+    throw ParseException("invalid catch clause", s.line, s.col);
+  }
+  if (s.size() == 1) { // (do) or (catch) without instructions
+    return makeNop();
+  }
+  auto ret = allocator.alloc<Block>();
+  for (size_t i = 1; i < s.size(); i++) {
+    ret->list.push_back(parseExpression(s[i]));
+  }
+  if (ret->list.size() == 1) {
+    return ret->list[0];
+  }
+  ret->finalize(type);
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeThrow(Element& s) {
+  auto ret = allocator.alloc<Throw>();
+  Index i = 1;
+
+  ret->event = getEventName(*s[i++]);
+  if (!wasm.getEventOrNull(ret->event)) {
+    throw ParseException("bad event name", s[1]->line, s[1]->col);
+  }
+  for (; i < s.size(); i++) {
+    ret->operands.push_back(parseExpression(s[i]));
+  }
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeRethrow(Element& s) {
+  auto ret = allocator.alloc<Rethrow>();
+  ret->exnref = parseExpression(*s[1]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeBrOnExn(Element& s) {
+  auto ret = allocator.alloc<BrOnExn>();
+  size_t i = 1;
+  ret->name = getLabel(*s[i++]);
+  ret->event = getEventName(*s[i++]);
+  if (!wasm.getEventOrNull(ret->event)) {
+    throw ParseException("bad event name", s[1]->line, s[1]->col);
+  }
+  ret->exnref = parseExpression(s[i]);
+
+  Event* event = wasm.getEventOrNull(ret->event);
+  assert(event && "br_on_exn's event must exist");
+  // Copy params info into BrOnExn, because it is necessary when BrOnExn is
+  // refinalized without the module.
+  ret->sent = event->sig.params;
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeTupleMake(Element& s) {
+  auto ret = allocator.alloc<TupleMake>();
+  parseCallOperands(s, 1, s.size(), ret);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeTupleExtract(Element& s) {
+  auto ret = allocator.alloc<TupleExtract>();
+  ret->index = atoi(s[1]->str().c_str());
+  ret->tuple = parseExpression(s[2]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeI31New(Element& s) {
+  auto ret = allocator.alloc<I31New>();
+  ret->value = parseExpression(s[1]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeI31Get(Element& s, bool signed_) {
+  auto ret = allocator.alloc<I31Get>();
+  ret->i31 = parseExpression(s[1]);
+  ret->signed_ = signed_;
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeRefTest(Element& s) {
+  auto ret = allocator.alloc<RefTest>();
+  WASM_UNREACHABLE("TODO (gc): ref.test");
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeRefCast(Element& s) {
+  auto ret = allocator.alloc<RefCast>();
+  WASM_UNREACHABLE("TODO (gc): ref.cast");
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeBrOnCast(Element& s) {
+  auto ret = allocator.alloc<BrOnCast>();
+  WASM_UNREACHABLE("TODO (gc): br_on_cast");
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeRttCanon(Element& s) {
+  auto ret = allocator.alloc<RttCanon>();
+  WASM_UNREACHABLE("TODO (gc): rtt.canon");
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeRttSub(Element& s) {
+  auto ret = allocator.alloc<RttSub>();
+  WASM_UNREACHABLE("TODO (gc): rtt.sub");
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeStructNew(Element& s, bool default_) {
+  auto ret = allocator.alloc<StructNew>();
+  WASM_UNREACHABLE("TODO (gc): struct.new");
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeStructGet(Element& s) {
+  auto ret = allocator.alloc<StructGet>();
+  WASM_UNREACHABLE("TODO (gc): struct.get");
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeStructGet(Element& s, bool signed_) {
+  auto ret = allocator.alloc<StructGet>();
+  WASM_UNREACHABLE("TODO (gc): struct.get_s/u");
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeStructSet(Element& s) {
+  auto ret = allocator.alloc<StructSet>();
+  WASM_UNREACHABLE("TODO (gc): struct.set");
+  ret->finalize();
+  return ret;
+}
+
+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;
+}
+
+Expression* SExpressionWasmBuilder::makeArrayGet(Element& s, bool signed_) {
+  auto ret = allocator.alloc<ArrayGet>();
+  WASM_UNREACHABLE("TODO (gc): array.get_s/u");
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeArraySet(Element& s) {
+  auto ret = allocator.alloc<ArraySet>();
+  WASM_UNREACHABLE("TODO (gc): array.set");
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makeArrayLen(Element& s) {
+  auto ret = allocator.alloc<ArrayLen>();
+  WASM_UNREACHABLE("TODO (gc): array.len");
+  ret->finalize();
+  return ret;
+}
+
+// converts an s-expression string representing binary data into an output
+// sequence of raw bytes this appends to data, which may already contain
+// content.
+void SExpressionWasmBuilder::stringToBinary(const char* input,
+                                            size_t size,
+                                            std::vector<char>& data) {
+  auto originalSize = data.size();
+  data.resize(originalSize + size);
+  char* write = data.data() + originalSize;
+  while (1) {
+    if (input[0] == 0) {
+      break;
+    }
+    if (input[0] == '\\') {
+      if (input[1] == '"') {
+        *write++ = '"';
+        input += 2;
+        continue;
+      } else if (input[1] == '\'') {
+        *write++ = '\'';
+        input += 2;
+        continue;
+      } else if (input[1] == '\\') {
+        *write++ = '\\';
+        input += 2;
+        continue;
+      } else if (input[1] == 'n') {
+        *write++ = '\n';
+        input += 2;
+        continue;
+      } else if (input[1] == 't') {
+        *write++ = '\t';
+        input += 2;
+        continue;
+      } else {
+        *write++ = (char)(unhex(input[1]) * 16 + unhex(input[2]));
+        input += 3;
+        continue;
+      }
+    }
+    *write++ = input[0];
+    input++;
+  }
+  assert(write >= data.data());
+  size_t actual = write - data.data();
+  assert(actual <= data.size());
+  data.resize(actual);
+}
+
+Index SExpressionWasmBuilder::parseMemoryIndex(Element& s, Index i) {
+  if (i < s.size() && s[i]->isStr()) {
+    if (s[i]->str() == "i64") {
+      i++;
+      wasm.memory.indexType = Type::i64;
+    } else if (s[i]->str() == "i32") {
+      i++;
+      wasm.memory.indexType = Type::i32;
+    }
+  }
+  return i;
+}
+
+Index SExpressionWasmBuilder::parseMemoryLimits(Element& s, Index i) {
+  i = parseMemoryIndex(s, i);
+  if (i == s.size()) {
+    throw ParseException("missing memory limits", s.line, s.col);
+  }
+  auto initElem = s[i++];
+  wasm.memory.initial = getAddress(initElem);
+  if (!wasm.memory.is64()) {
+    checkAddress(wasm.memory.initial, "excessive memory init", initElem);
+  }
+  if (i == s.size()) {
+    wasm.memory.max = Memory::kUnlimitedSize;
+  } else {
+    auto maxElem = s[i++];
+    wasm.memory.max = getAddress(maxElem);
+    if (!wasm.memory.is64() && wasm.memory.max > Memory::kMaxSize32) {
+      throw ParseException(
+        "total memory must be <= 4GB", maxElem->line, maxElem->col);
+    }
+  }
+  return i;
+}
+
+void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) {
+  if (wasm.memory.exists) {
+    throw ParseException("too many memories", s.line, s.col);
+  }
+  wasm.memory.exists = true;
+  wasm.memory.shared = false;
+  Index i = 1;
+  if (s[i]->dollared()) {
+    wasm.memory.name = s[i++]->str();
+  }
+  i = parseMemoryIndex(s, i);
+  Name importModule, importBase;
+  if (s[i]->isList()) {
+    auto& inner = *s[i];
+    if (elementStartsWith(inner, EXPORT)) {
+      auto ex = make_unique<Export>();
+      ex->name = inner[1]->str();
+      ex->value = wasm.memory.name;
+      ex->kind = ExternalKind::Memory;
+      if (wasm.getExportOrNull(ex->name)) {
+        throw ParseException("duplicate export", inner.line, inner.col);
+      }
+      wasm.addExport(ex.release());
+      i++;
+    } else if (elementStartsWith(inner, IMPORT)) {
+      wasm.memory.module = inner[1]->str();
+      wasm.memory.base = inner[2]->str();
+      i++;
+    } else if (elementStartsWith(inner, SHARED)) {
+      wasm.memory.shared = true;
+      parseMemoryLimits(inner, 1);
+      i++;
+    } else {
+      if (!(inner.size() > 0 ? inner[0]->str() != IMPORT : true)) {
+        throw ParseException("bad import ending", inner.line, inner.col);
+      }
+      // (memory (data ..)) format
+      auto j = parseMemoryIndex(inner, 1);
+      auto offset = allocator.alloc<Const>()->set(Literal(int32_t(0)));
+      parseInnerData(inner, j, offset, false);
+      wasm.memory.initial = wasm.memory.segments[0].data.size();
+      return;
+    }
+  }
+  if (!wasm.memory.shared) {
+    i = parseMemoryLimits(s, i);
+  }
+
+  // Parse memory initializers.
+  while (i < s.size()) {
+    Element& curr = *s[i];
+    size_t j = 1;
+    Address offsetValue;
+    if (elementStartsWith(curr, DATA)) {
+      offsetValue = 0;
+    } else {
+      auto offsetElem = curr[j++];
+      offsetValue = getAddress(offsetElem);
+      if (!wasm.memory.is64()) {
+        checkAddress(offsetValue, "excessive memory offset", offsetElem);
+      }
+    }
+    const char* input = curr[j]->c_str();
+    auto* offset = allocator.alloc<Const>();
+    offset->type = Type::i32;
+    offset->value = Literal(int32_t(offsetValue));
+    if (auto size = strlen(input)) {
+      std::vector<char> data;
+      stringToBinary(input, size, data);
+      wasm.memory.segments.emplace_back(offset, data.data(), data.size());
+    } else {
+      wasm.memory.segments.emplace_back(offset, "", 0);
+    }
+    i++;
+  }
+}
+
+void SExpressionWasmBuilder::parseData(Element& s) {
+  if (!wasm.memory.exists) {
+    throw ParseException("data but no memory", s.line, s.col);
+  }
+  bool isPassive = false;
+  Expression* offset = nullptr;
+  Index i = 1;
+  if (s[i]->isStr()) {
+    // data is passive or named
+    if (s[i]->str() == PASSIVE) {
+      isPassive = true;
+    }
+    i++;
+  }
+  if (!isPassive) {
+    offset = parseExpression(s[i]);
+  }
+  if (s.size() != 3 && s.size() != 4) {
+    throw ParseException("Unexpected data items", s.line, s.col);
+  }
+  parseInnerData(s, s.size() - 1, offset, isPassive);
+}
+
+void SExpressionWasmBuilder::parseInnerData(Element& s,
+                                            Index i,
+                                            Expression* offset,
+                                            bool isPassive) {
+  std::vector<char> data;
+  while (i < s.size()) {
+    const char* input = s[i++]->c_str();
+    if (auto size = strlen(input)) {
+      stringToBinary(input, size, data);
+    }
+  }
+  wasm.memory.segments.emplace_back(
+    isPassive, offset, data.data(), data.size());
+}
+
+void SExpressionWasmBuilder::parseExport(Element& s) {
+  std::unique_ptr<Export> ex = make_unique<Export>();
+  ex->name = s[1]->str();
+  if (s[2]->isList()) {
+    auto& inner = *s[2];
+    ex->value = inner[1]->str();
+    if (elementStartsWith(inner, FUNC)) {
+      ex->kind = ExternalKind::Function;
+    } else if (elementStartsWith(inner, MEMORY)) {
+      ex->kind = ExternalKind::Memory;
+    } else if (elementStartsWith(inner, TABLE)) {
+      ex->kind = ExternalKind::Table;
+    } else if (elementStartsWith(inner, GLOBAL)) {
+      ex->kind = ExternalKind::Global;
+    } else if (inner[0]->str() == EVENT) {
+      ex->kind = ExternalKind::Event;
+    } else {
+      throw ParseException("invalid export", inner.line, inner.col);
+    }
+  } else {
+    // function
+    ex->value = s[2]->str();
+    ex->kind = ExternalKind::Function;
+  }
+  if (wasm.getExportOrNull(ex->name)) {
+    throw ParseException("duplicate export", s.line, s.col);
+  }
+  wasm.addExport(ex.release());
+}
+
+void SExpressionWasmBuilder::parseImport(Element& s) {
+  size_t i = 1;
+  // (import "env" "STACKTOP" (global $stackTop i32))
+  bool newStyle = s.size() == 4 && s[3]->isList();
+  auto kind = ExternalKind::Invalid;
+  if (newStyle) {
+    if (elementStartsWith(*s[3], FUNC)) {
+      kind = ExternalKind::Function;
+    } else if (elementStartsWith(*s[3], MEMORY)) {
+      kind = ExternalKind::Memory;
+      if (wasm.memory.exists) {
+        throw ParseException("more than one memory", s[3]->line, s[3]->col);
+      }
+      wasm.memory.exists = true;
+    } else if (elementStartsWith(*s[3], TABLE)) {
+      kind = ExternalKind::Table;
+      if (wasm.table.exists) {
+        throw ParseException("more than one table", s[3]->line, s[3]->col);
+      }
+      wasm.table.exists = true;
+    } else if (elementStartsWith(*s[3], GLOBAL)) {
+      kind = ExternalKind::Global;
+    } else if ((*s[3])[0]->str() == EVENT) {
+      kind = ExternalKind::Event;
+    } else {
+      newStyle = false; // either (param..) or (result..)
+    }
+  }
+  Index newStyleInner = 1;
+  Name name;
+  if (s.size() > 3 && s[3]->isStr()) {
+    name = s[i++]->str();
+  } else if (newStyle && newStyleInner < s[3]->size() &&
+             (*s[3])[newStyleInner]->dollared()) {
+    name = (*s[3])[newStyleInner++]->str();
+  }
+  if (!name.is()) {
+    if (kind == ExternalKind::Function) {
+      name = Name("fimport$" + std::to_string(functionCounter++));
+      functionNames.push_back(name);
+    } else if (kind == ExternalKind::Global) {
+      name = Name("gimport$" + std::to_string(globalCounter++));
+      globalNames.push_back(name);
+    } else if (kind == ExternalKind::Memory) {
+      name = Name("mimport$" + std::to_string(0));
+    } else if (kind == ExternalKind::Table) {
+      name = Name("timport$" + std::to_string(0));
+    } else if (kind == ExternalKind::Event) {
+      name = Name("eimport$" + std::to_string(eventCounter++));
+      eventNames.push_back(name);
+    } else {
+      throw ParseException("invalid import", s[3]->line, s[3]->col);
+    }
+  }
+  if (!newStyle) {
+    kind = ExternalKind::Function;
+  }
+  auto module = s[i++]->str();
+  if (!s[i]->isStr()) {
+    throw ParseException("no name for import", s[i]->line, s[i]->col);
+  }
+  auto base = s[i]->str();
+  if (!module.size() || !base.size()) {
+    throw ParseException(
+      "imports must have module and base", s[i]->line, s[i]->col);
+  }
+  i++;
+  // parse internals
+  Element& inner = newStyle ? *s[3] : s;
+  Index j = newStyle ? newStyleInner : i;
+  if (kind == ExternalKind::Function) {
+    auto func = make_unique<Function>();
+
+    j = parseTypeUse(inner, j, func->sig);
+    func->name = name;
+    func->module = module;
+    func->base = base;
+    functionTypes[name] = func->sig.results;
+    wasm.addFunction(func.release());
+  } else if (kind == ExternalKind::Global) {
+    Type type;
+    bool mutable_ = false;
+    if (inner[j]->isStr()) {
+      type = stringToType(inner[j++]->str());
+    } else {
+      auto& inner2 = *inner[j++];
+      if (inner2[0]->str() != MUT) {
+        throw ParseException("expected mut", inner2.line, inner2.col);
+      }
+      type = stringToType(inner2[1]->str());
+      mutable_ = true;
+    }
+    auto global = make_unique<Global>();
+    global->name = name;
+    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.module = module;
+    wasm.table.base = base;
+    if (j < inner.size() - 1) {
+      auto initElem = inner[j++];
+      wasm.table.initial = getAddress(initElem);
+      checkAddress(wasm.table.initial, "excessive table init size", initElem);
+    }
+    if (j < inner.size() - 1) {
+      auto maxElem = inner[j++];
+      wasm.table.max = getAddress(maxElem);
+      checkAddress(wasm.table.max, "excessive table max size", maxElem);
+    } else {
+      wasm.table.max = Table::kUnlimitedSize;
+    }
+    j++; // funcref
+    // ends with the table element type
+  } else if (kind == ExternalKind::Memory) {
+    wasm.memory.name = name;
+    wasm.memory.module = module;
+    wasm.memory.base = base;
+    if (inner[j]->isList()) {
+      auto& limits = *inner[j];
+      if (!elementStartsWith(limits, SHARED)) {
+        throw ParseException(
+          "bad memory limit declaration", inner[j]->line, inner[j]->col);
+      }
+      wasm.memory.shared = true;
+      j = parseMemoryLimits(limits, 1);
+    } else {
+      j = parseMemoryLimits(inner, j);
+    }
+  } else if (kind == ExternalKind::Event) {
+    auto event = make_unique<Event>();
+    if (j >= inner.size()) {
+      throw ParseException("event does not have an attribute", s.line, s.col);
+    }
+    auto& attrElem = *inner[j++];
+    if (!elementStartsWith(attrElem, ATTR) || attrElem.size() != 2) {
+      throw ParseException("invalid attribute", attrElem.line, attrElem.col);
+    }
+    event->attribute = atoi(attrElem[1]->c_str());
+    j = parseTypeUse(inner, j, event->sig);
+    event->name = name;
+    event->module = module;
+    event->base = base;
+    wasm.addEvent(event.release());
+  }
+  // If there are more elements, they are invalid
+  if (j < inner.size()) {
+    throw ParseException("invalid element", inner[j]->line, inner[j]->col);
+  }
+}
+
+void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) {
+  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();
+  } else {
+    global->name = Name::fromInt(globalCounter);
+  }
+  globalCounter++;
+  globalNames.push_back(global->name);
+  bool mutable_ = false;
+  Type type = Type::none;
+  bool exported = false;
+  Name importModule, importBase;
+  while (i < s.size() && s[i]->isList()) {
+    auto& inner = *s[i++];
+    if (elementStartsWith(inner, EXPORT)) {
+      auto ex = make_unique<Export>();
+      ex->name = inner[1]->str();
+      ex->value = global->name;
+      ex->kind = ExternalKind::Global;
+      if (wasm.getExportOrNull(ex->name)) {
+        throw ParseException("duplicate export", s.line, s.col);
+      }
+      wasm.addExport(ex.release());
+      exported = true;
+    } else if (elementStartsWith(inner, IMPORT)) {
+      importModule = inner[1]->str();
+      importBase = inner[2]->str();
+    } else if (elementStartsWith(inner, MUT)) {
+      mutable_ = true;
+      type = elementToType(*inner[1]);
+      break;
+    } else {
+      type = elementToType(inner);
+      break;
+    }
+  }
+  if (exported && mutable_) {
+    throw ParseException("cannot export a mutable global", s.line, s.col);
+  }
+  if (type == Type::none) {
+    type = stringToType(s[i++]->str());
+  }
+  if (importModule.is()) {
+    // this is an import, actually
+    if (!importBase.size()) {
+      throw ParseException("module but no base for import", s.line, s.col);
+    }
+    if (!preParseImport) {
+      throw ParseException("!preParseImport in global", s.line, s.col);
+    }
+    auto im = make_unique<Global>();
+    im->name = global->name;
+    im->module = importModule;
+    im->base = importBase;
+    im->type = type;
+    im->mutable_ = mutable_;
+    if (wasm.getGlobalOrNull(im->name)) {
+      throw ParseException("duplicate import", s.line, s.col);
+    }
+    wasm.addGlobal(im.release());
+    return;
+  }
+  if (preParseImport) {
+    throw ParseException("preParseImport in global", s.line, s.col);
+  }
+  global->type = type;
+  if (i < s.size()) {
+    global->init = parseExpression(s[i++]);
+  } else {
+    throw ParseException("global without init", s.line, s.col);
+  }
+  global->mutable_ = mutable_;
+  if (i != s.size()) {
+    throw ParseException("extra import elements", s.line, s.col);
+  }
+  if (wasm.getGlobalOrNull(global->name)) {
+    throw ParseException("duplicate import", s.line, s.col);
+  }
+  wasm.addGlobal(global.release());
+}
+
+void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) {
+  if (wasm.table.exists) {
+    throw ParseException("more than one table", s.line, s.col);
+  }
+  wasm.table.exists = true;
+  Index i = 1;
+  if (i == s.size()) {
+    return; // empty table in old notation
+  }
+  if (s[i]->dollared()) {
+    wasm.table.name = s[i++]->str();
+  }
+  if (i == s.size()) {
+    return;
+  }
+  Name importModule, importBase;
+  if (s[i]->isList()) {
+    auto& inner = *s[i];
+    if (elementStartsWith(inner, EXPORT)) {
+      auto ex = make_unique<Export>();
+      ex->name = inner[1]->str();
+      ex->value = wasm.table.name;
+      ex->kind = ExternalKind::Table;
+      if (wasm.getExportOrNull(ex->name)) {
+        throw ParseException("duplicate export", inner.line, inner.col);
+      }
+      wasm.addExport(ex.release());
+      i++;
+    } else if (elementStartsWith(inner, IMPORT)) {
+      if (!preParseImport) {
+        throw ParseException("!preParseImport in table", inner.line, inner.col);
+      }
+      wasm.table.module = inner[1]->str();
+      wasm.table.base = inner[2]->str();
+      i++;
+    } else {
+      throw ParseException("invalid table", inner.line, inner.col);
+    }
+  }
+  if (i == s.size()) {
+    return;
+  }
+  if (!s[i]->dollared()) {
+    if (s[i]->str() == FUNCREF) {
+      // (table type (elem ..))
+      parseInnerElem(*s[i + 1]);
+      if (wasm.table.segments.size() > 0) {
+        wasm.table.initial = wasm.table.max =
+          wasm.table.segments[0].data.size();
+      } else {
+        wasm.table.initial = wasm.table.max = 0;
+      }
+      return;
+    }
+    // first element isn't dollared, and isn't funcref. this could be old syntax
+    // for (table 0 1) which means function 0 and 1, or it could be (table
+    // initial max? type), look for type
+    if (s[s.size() - 1]->str() == FUNCREF) {
+      // (table initial max? type)
+      if (i < s.size() - 1) {
+        wasm.table.initial = atoi(s[i++]->c_str());
+      }
+      if (i < s.size() - 1) {
+        wasm.table.max = atoi(s[i++]->c_str());
+      }
+      return;
+    }
+  }
+  // old notation (table func1 func2 ..)
+  parseInnerElem(s, i);
+  if (wasm.table.segments.size() > 0) {
+    wasm.table.initial = wasm.table.max = wasm.table.segments[0].data.size();
+  } else {
+    wasm.table.initial = wasm.table.max = 0;
+  }
+}
+
+void SExpressionWasmBuilder::parseElem(Element& s) {
+  Index i = 1;
+  if (!s[i]->isList()) {
+    // the table is named
+    i++;
+  }
+  auto* offset = parseExpression(s[i++]);
+  parseInnerElem(s, i, offset);
+}
+
+void SExpressionWasmBuilder::parseInnerElem(Element& s,
+                                            Index i,
+                                            Expression* offset) {
+  if (!wasm.table.exists) {
+    throw ParseException("elem without table", s.line, s.col);
+  }
+  if (!offset) {
+    offset = allocator.alloc<Const>()->set(Literal(int32_t(0)));
+  }
+  Table::Segment segment(offset);
+  for (; i < s.size(); i++) {
+    segment.data.push_back(getFunctionName(*s[i]));
+  }
+  wasm.table.segments.push_back(segment);
+}
+
+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()) {
+      throw ParseException("duplicate function type", s.line, s.col);
+    }
+    signatureIndices[name] = signatures.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));
+}
+
+void SExpressionWasmBuilder::parseEvent(Element& s, bool preParseImport) {
+  auto event = make_unique<Event>();
+  size_t i = 1;
+
+  // Parse name
+  if (s[i]->isStr() && s[i]->dollared()) {
+    auto& inner = *s[i++];
+    event->name = inner.str();
+    if (wasm.getEventOrNull(event->name)) {
+      throw ParseException("duplicate event", inner.line, inner.col);
+    }
+  } else {
+    event->name = Name::fromInt(eventCounter);
+    assert(!wasm.getEventOrNull(event->name));
+  }
+  eventCounter++;
+  eventNames.push_back(event->name);
+
+  // Parse import, if any
+  if (i < s.size() && elementStartsWith(*s[i], IMPORT)) {
+    assert(preParseImport && "import element in non-preParseImport mode");
+    auto& importElem = *s[i++];
+    if (importElem.size() != 3) {
+      throw ParseException("invalid import", importElem.line, importElem.col);
+    }
+    if (!importElem[1]->isStr() || importElem[1]->dollared()) {
+      throw ParseException(
+        "invalid import module name", importElem[1]->line, importElem[1]->col);
+    }
+    if (!importElem[2]->isStr() || importElem[2]->dollared()) {
+      throw ParseException(
+        "invalid import base name", importElem[2]->line, importElem[2]->col);
+    }
+    event->module = importElem[1]->str();
+    event->base = importElem[2]->str();
+  }
+
+  // Parse export, if any
+  if (i < s.size() && elementStartsWith(*s[i], EXPORT)) {
+    auto& exportElem = *s[i++];
+    if (event->module.is()) {
+      throw ParseException("import and export cannot be specified together",
+                           exportElem.line,
+                           exportElem.col);
+    }
+    if (exportElem.size() != 2) {
+      throw ParseException("invalid export", exportElem.line, exportElem.col);
+    }
+    if (!exportElem[1]->isStr() || exportElem[1]->dollared()) {
+      throw ParseException(
+        "invalid export name", exportElem[1]->line, exportElem[1]->col);
+    }
+    auto ex = make_unique<Export>();
+    ex->name = exportElem[1]->str();
+    if (wasm.getExportOrNull(ex->name)) {
+      throw ParseException(
+        "duplicate export", exportElem[1]->line, exportElem[1]->col);
+    }
+    ex->value = event->name;
+    ex->kind = ExternalKind::Event;
+  }
+
+  // Parse attribute
+  if (i >= s.size()) {
+    throw ParseException("event does not have an attribute", s.line, s.col);
+  }
+  auto& attrElem = *s[i++];
+  if (!elementStartsWith(attrElem, ATTR) || attrElem.size() != 2) {
+    throw ParseException("invalid attribute", attrElem.line, attrElem.col);
+  }
+  if (!attrElem[1]->isStr()) {
+    throw ParseException(
+      "invalid attribute", attrElem[1]->line, attrElem[1]->col);
+  }
+  event->attribute = atoi(attrElem[1]->c_str());
+
+  // Parse typeuse
+  i = parseTypeUse(s, i, event->sig);
+
+  // If there are more elements, they are invalid
+  if (i < s.size()) {
+    throw ParseException("invalid element", s[i]->line, s[i]->col);
+  }
+
+  wasm.addEvent(event.release());
+}
+
+} // namespace wasm
diff --git a/binaryen/src/wasm/wasm-stack.cpp b/binaryen/src/wasm/wasm-stack.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm/wasm-stack.cpp
@@ -0,0 +1,2045 @@
+/*
+ * Copyright 2019 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wasm-stack.h"
+#include "ir/find_all.h"
+#include "wasm-debug.h"
+
+namespace wasm {
+
+void BinaryInstWriter::emitResultType(Type type) {
+  if (type == Type::unreachable) {
+    o << binaryType(Type::none);
+  } else if (type.isTuple()) {
+    o << S32LEB(parent.getTypeIndex(Signature(Type::none, type)));
+  } else {
+    o << binaryType(type);
+  }
+}
+
+void BinaryInstWriter::visitBlock(Block* curr) {
+  breakStack.push_back(curr->name);
+  o << int8_t(BinaryConsts::Block);
+  emitResultType(curr->type);
+}
+
+void BinaryInstWriter::visitIf(If* curr) {
+  // the binary format requires this; we have a block if we need one
+  // TODO: optimize this in Stack IR (if child is a block, we may break to this
+  // instead)
+  breakStack.emplace_back(IMPOSSIBLE_CONTINUE);
+  o << int8_t(BinaryConsts::If);
+  emitResultType(curr->type);
+}
+
+void BinaryInstWriter::emitIfElse(If* curr) {
+  assert(!breakStack.empty());
+  breakStack.pop_back();
+  breakStack.emplace_back(IMPOSSIBLE_CONTINUE); // TODO same as If
+  if (func && !sourceMap) {
+    parent.writeExtraDebugLocation(curr, func, BinaryLocations::Else);
+  }
+  o << int8_t(BinaryConsts::Else);
+}
+
+void BinaryInstWriter::visitLoop(Loop* curr) {
+  breakStack.push_back(curr->name);
+  o << int8_t(BinaryConsts::Loop);
+  emitResultType(curr->type);
+}
+
+void BinaryInstWriter::visitBreak(Break* curr) {
+  o << int8_t(curr->condition ? BinaryConsts::BrIf : BinaryConsts::Br)
+    << U32LEB(getBreakIndex(curr->name));
+}
+
+void BinaryInstWriter::visitSwitch(Switch* curr) {
+  o << int8_t(BinaryConsts::BrTable) << U32LEB(curr->targets.size());
+  for (auto target : curr->targets) {
+    o << U32LEB(getBreakIndex(target));
+  }
+  o << U32LEB(getBreakIndex(curr->default_));
+}
+
+void BinaryInstWriter::visitCall(Call* curr) {
+  int8_t op =
+    curr->isReturn ? BinaryConsts::RetCallFunction : BinaryConsts::CallFunction;
+  o << op << U32LEB(parent.getFunctionIndex(curr->target));
+}
+
+void BinaryInstWriter::visitCallIndirect(CallIndirect* curr) {
+  int8_t op =
+    curr->isReturn ? BinaryConsts::RetCallIndirect : BinaryConsts::CallIndirect;
+  o << op << U32LEB(parent.getTypeIndex(curr->sig))
+    << U32LEB(0); // Reserved flags field
+}
+
+void BinaryInstWriter::visitLocalGet(LocalGet* curr) {
+  size_t numValues = func->getLocalType(curr->index).size();
+  for (Index i = 0; i < numValues; ++i) {
+    o << int8_t(BinaryConsts::LocalGet)
+      << U32LEB(mappedLocals[std::make_pair(curr->index, i)]);
+  }
+}
+
+void BinaryInstWriter::visitLocalSet(LocalSet* curr) {
+  size_t numValues = func->getLocalType(curr->index).size();
+  for (Index i = numValues - 1; i >= 1; --i) {
+    o << int8_t(BinaryConsts::LocalSet)
+      << U32LEB(mappedLocals[std::make_pair(curr->index, i)]);
+  }
+  if (!curr->isTee()) {
+    o << int8_t(BinaryConsts::LocalSet)
+      << U32LEB(mappedLocals[std::make_pair(curr->index, 0)]);
+  } else {
+    o << int8_t(BinaryConsts::LocalTee)
+      << U32LEB(mappedLocals[std::make_pair(curr->index, 0)]);
+    for (Index i = 1; i < numValues; ++i) {
+      o << int8_t(BinaryConsts::LocalGet)
+        << U32LEB(mappedLocals[std::make_pair(curr->index, i)]);
+    }
+  }
+}
+
+void BinaryInstWriter::visitGlobalGet(GlobalGet* curr) {
+  // Emit a global.get for each element if this is a tuple global
+  Index index = parent.getGlobalIndex(curr->name);
+  size_t numValues = curr->type.size();
+  for (Index i = 0; i < numValues; ++i) {
+    o << int8_t(BinaryConsts::GlobalGet) << U32LEB(index + i);
+  }
+}
+
+void BinaryInstWriter::visitGlobalSet(GlobalSet* curr) {
+  // Emit a global.set for each element if this is a tuple global
+  Index index = parent.getGlobalIndex(curr->name);
+  size_t numValues = parent.getModule()->getGlobal(curr->name)->type.size();
+  for (int i = numValues - 1; i >= 0; --i) {
+    o << int8_t(BinaryConsts::GlobalSet) << U32LEB(index + i);
+  }
+}
+
+void BinaryInstWriter::visitLoad(Load* curr) {
+  if (!curr->isAtomic) {
+    switch (curr->type.getBasic()) {
+      case Type::i32: {
+        switch (curr->bytes) {
+          case 1:
+            o << int8_t(curr->signed_ ? BinaryConsts::I32LoadMem8S
+                                      : BinaryConsts::I32LoadMem8U);
+            break;
+          case 2:
+            o << int8_t(curr->signed_ ? BinaryConsts::I32LoadMem16S
+                                      : BinaryConsts::I32LoadMem16U);
+            break;
+          case 4:
+            o << int8_t(BinaryConsts::I32LoadMem);
+            break;
+          default:
+            abort();
+        }
+        break;
+      }
+      case Type::i64: {
+        switch (curr->bytes) {
+          case 1:
+            o << int8_t(curr->signed_ ? BinaryConsts::I64LoadMem8S
+                                      : BinaryConsts::I64LoadMem8U);
+            break;
+          case 2:
+            o << int8_t(curr->signed_ ? BinaryConsts::I64LoadMem16S
+                                      : BinaryConsts::I64LoadMem16U);
+            break;
+          case 4:
+            o << int8_t(curr->signed_ ? BinaryConsts::I64LoadMem32S
+                                      : BinaryConsts::I64LoadMem32U);
+            break;
+          case 8:
+            o << int8_t(BinaryConsts::I64LoadMem);
+            break;
+          default:
+            abort();
+        }
+        break;
+      }
+      case Type::f32:
+        o << int8_t(BinaryConsts::F32LoadMem);
+        break;
+      case Type::f64:
+        o << int8_t(BinaryConsts::F64LoadMem);
+        break;
+      case Type::v128:
+        o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Load);
+        break;
+      case Type::unreachable:
+        // the pointer is unreachable, so we are never reached; just don't emit
+        // a load
+        return;
+      case Type::funcref:
+      case Type::externref:
+      case Type::exnref:
+      case Type::anyref:
+      case Type::eqref:
+      case Type::i31ref:
+      case Type::none:
+        WASM_UNREACHABLE("unexpected type");
+    }
+  } else {
+    o << int8_t(BinaryConsts::AtomicPrefix);
+    switch (curr->type.getBasic()) {
+      case Type::i32: {
+        switch (curr->bytes) {
+          case 1:
+            o << int8_t(BinaryConsts::I32AtomicLoad8U);
+            break;
+          case 2:
+            o << int8_t(BinaryConsts::I32AtomicLoad16U);
+            break;
+          case 4:
+            o << int8_t(BinaryConsts::I32AtomicLoad);
+            break;
+          default:
+            WASM_UNREACHABLE("invalid load size");
+        }
+        break;
+      }
+      case Type::i64: {
+        switch (curr->bytes) {
+          case 1:
+            o << int8_t(BinaryConsts::I64AtomicLoad8U);
+            break;
+          case 2:
+            o << int8_t(BinaryConsts::I64AtomicLoad16U);
+            break;
+          case 4:
+            o << int8_t(BinaryConsts::I64AtomicLoad32U);
+            break;
+          case 8:
+            o << int8_t(BinaryConsts::I64AtomicLoad);
+            break;
+          default:
+            WASM_UNREACHABLE("invalid load size");
+        }
+        break;
+      }
+      case Type::unreachable:
+        return;
+      default:
+        WASM_UNREACHABLE("unexpected type");
+    }
+  }
+  emitMemoryAccess(curr->align, curr->bytes, curr->offset);
+}
+
+void BinaryInstWriter::visitStore(Store* curr) {
+  if (!curr->isAtomic) {
+    switch (curr->valueType.getBasic()) {
+      case Type::i32: {
+        switch (curr->bytes) {
+          case 1:
+            o << int8_t(BinaryConsts::I32StoreMem8);
+            break;
+          case 2:
+            o << int8_t(BinaryConsts::I32StoreMem16);
+            break;
+          case 4:
+            o << int8_t(BinaryConsts::I32StoreMem);
+            break;
+          default:
+            abort();
+        }
+        break;
+      }
+      case Type::i64: {
+        switch (curr->bytes) {
+          case 1:
+            o << int8_t(BinaryConsts::I64StoreMem8);
+            break;
+          case 2:
+            o << int8_t(BinaryConsts::I64StoreMem16);
+            break;
+          case 4:
+            o << int8_t(BinaryConsts::I64StoreMem32);
+            break;
+          case 8:
+            o << int8_t(BinaryConsts::I64StoreMem);
+            break;
+          default:
+            abort();
+        }
+        break;
+      }
+      case Type::f32:
+        o << int8_t(BinaryConsts::F32StoreMem);
+        break;
+      case Type::f64:
+        o << int8_t(BinaryConsts::F64StoreMem);
+        break;
+      case Type::v128:
+        o << int8_t(BinaryConsts::SIMDPrefix)
+          << U32LEB(BinaryConsts::V128Store);
+        break;
+      case Type::funcref:
+      case Type::externref:
+      case Type::exnref:
+      case Type::anyref:
+      case Type::eqref:
+      case Type::i31ref:
+      case Type::none:
+      case Type::unreachable:
+        WASM_UNREACHABLE("unexpected type");
+    }
+  } else {
+    o << int8_t(BinaryConsts::AtomicPrefix);
+    switch (curr->valueType.getBasic()) {
+      case Type::i32: {
+        switch (curr->bytes) {
+          case 1:
+            o << int8_t(BinaryConsts::I32AtomicStore8);
+            break;
+          case 2:
+            o << int8_t(BinaryConsts::I32AtomicStore16);
+            break;
+          case 4:
+            o << int8_t(BinaryConsts::I32AtomicStore);
+            break;
+          default:
+            WASM_UNREACHABLE("invalid store size");
+        }
+        break;
+      }
+      case Type::i64: {
+        switch (curr->bytes) {
+          case 1:
+            o << int8_t(BinaryConsts::I64AtomicStore8);
+            break;
+          case 2:
+            o << int8_t(BinaryConsts::I64AtomicStore16);
+            break;
+          case 4:
+            o << int8_t(BinaryConsts::I64AtomicStore32);
+            break;
+          case 8:
+            o << int8_t(BinaryConsts::I64AtomicStore);
+            break;
+          default:
+            WASM_UNREACHABLE("invalid store size");
+        }
+        break;
+      }
+      default:
+        WASM_UNREACHABLE("unexpected type");
+    }
+  }
+  emitMemoryAccess(curr->align, curr->bytes, curr->offset);
+}
+
+void BinaryInstWriter::visitAtomicRMW(AtomicRMW* curr) {
+  o << int8_t(BinaryConsts::AtomicPrefix);
+
+#define CASE_FOR_OP(Op)                                                        \
+  case Op:                                                                     \
+    switch (curr->type.getBasic()) {                                           \
+      case Type::i32:                                                          \
+        switch (curr->bytes) {                                                 \
+          case 1:                                                              \
+            o << int8_t(BinaryConsts::I32AtomicRMW##Op##8U);                   \
+            break;                                                             \
+          case 2:                                                              \
+            o << int8_t(BinaryConsts::I32AtomicRMW##Op##16U);                  \
+            break;                                                             \
+          case 4:                                                              \
+            o << int8_t(BinaryConsts::I32AtomicRMW##Op);                       \
+            break;                                                             \
+          default:                                                             \
+            WASM_UNREACHABLE("invalid rmw size");                              \
+        }                                                                      \
+        break;                                                                 \
+      case Type::i64:                                                          \
+        switch (curr->bytes) {                                                 \
+          case 1:                                                              \
+            o << int8_t(BinaryConsts::I64AtomicRMW##Op##8U);                   \
+            break;                                                             \
+          case 2:                                                              \
+            o << int8_t(BinaryConsts::I64AtomicRMW##Op##16U);                  \
+            break;                                                             \
+          case 4:                                                              \
+            o << int8_t(BinaryConsts::I64AtomicRMW##Op##32U);                  \
+            break;                                                             \
+          case 8:                                                              \
+            o << int8_t(BinaryConsts::I64AtomicRMW##Op);                       \
+            break;                                                             \
+          default:                                                             \
+            WASM_UNREACHABLE("invalid rmw size");                              \
+        }                                                                      \
+        break;                                                                 \
+      default:                                                                 \
+        WASM_UNREACHABLE("unexpected type");                                   \
+    }                                                                          \
+    break
+
+  switch (curr->op) {
+    CASE_FOR_OP(Add);
+    CASE_FOR_OP(Sub);
+    CASE_FOR_OP(And);
+    CASE_FOR_OP(Or);
+    CASE_FOR_OP(Xor);
+    CASE_FOR_OP(Xchg);
+    default:
+      WASM_UNREACHABLE("unexpected op");
+  }
+#undef CASE_FOR_OP
+
+  emitMemoryAccess(curr->bytes, curr->bytes, curr->offset);
+}
+
+void BinaryInstWriter::visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+  o << int8_t(BinaryConsts::AtomicPrefix);
+  switch (curr->type.getBasic()) {
+    case Type::i32:
+      switch (curr->bytes) {
+        case 1:
+          o << int8_t(BinaryConsts::I32AtomicCmpxchg8U);
+          break;
+        case 2:
+          o << int8_t(BinaryConsts::I32AtomicCmpxchg16U);
+          break;
+        case 4:
+          o << int8_t(BinaryConsts::I32AtomicCmpxchg);
+          break;
+        default:
+          WASM_UNREACHABLE("invalid size");
+      }
+      break;
+    case Type::i64:
+      switch (curr->bytes) {
+        case 1:
+          o << int8_t(BinaryConsts::I64AtomicCmpxchg8U);
+          break;
+        case 2:
+          o << int8_t(BinaryConsts::I64AtomicCmpxchg16U);
+          break;
+        case 4:
+          o << int8_t(BinaryConsts::I64AtomicCmpxchg32U);
+          break;
+        case 8:
+          o << int8_t(BinaryConsts::I64AtomicCmpxchg);
+          break;
+        default:
+          WASM_UNREACHABLE("invalid size");
+      }
+      break;
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+  emitMemoryAccess(curr->bytes, curr->bytes, curr->offset);
+}
+
+void BinaryInstWriter::visitAtomicWait(AtomicWait* curr) {
+  o << int8_t(BinaryConsts::AtomicPrefix);
+  switch (curr->expectedType.getBasic()) {
+    case Type::i32: {
+      o << int8_t(BinaryConsts::I32AtomicWait);
+      emitMemoryAccess(4, 4, curr->offset);
+      break;
+    }
+    case Type::i64: {
+      o << int8_t(BinaryConsts::I64AtomicWait);
+      emitMemoryAccess(8, 8, curr->offset);
+      break;
+    }
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+void BinaryInstWriter::visitAtomicNotify(AtomicNotify* curr) {
+  o << int8_t(BinaryConsts::AtomicPrefix) << int8_t(BinaryConsts::AtomicNotify);
+  emitMemoryAccess(4, 4, curr->offset);
+}
+
+void BinaryInstWriter::visitAtomicFence(AtomicFence* curr) {
+  o << int8_t(BinaryConsts::AtomicPrefix) << int8_t(BinaryConsts::AtomicFence)
+    << int8_t(curr->order);
+}
+
+void BinaryInstWriter::visitSIMDExtract(SIMDExtract* curr) {
+  o << int8_t(BinaryConsts::SIMDPrefix);
+  switch (curr->op) {
+    case ExtractLaneSVecI8x16:
+      o << U32LEB(BinaryConsts::I8x16ExtractLaneS);
+      break;
+    case ExtractLaneUVecI8x16:
+      o << U32LEB(BinaryConsts::I8x16ExtractLaneU);
+      break;
+    case ExtractLaneSVecI16x8:
+      o << U32LEB(BinaryConsts::I16x8ExtractLaneS);
+      break;
+    case ExtractLaneUVecI16x8:
+      o << U32LEB(BinaryConsts::I16x8ExtractLaneU);
+      break;
+    case ExtractLaneVecI32x4:
+      o << U32LEB(BinaryConsts::I32x4ExtractLane);
+      break;
+    case ExtractLaneVecI64x2:
+      o << U32LEB(BinaryConsts::I64x2ExtractLane);
+      break;
+    case ExtractLaneVecF32x4:
+      o << U32LEB(BinaryConsts::F32x4ExtractLane);
+      break;
+    case ExtractLaneVecF64x2:
+      o << U32LEB(BinaryConsts::F64x2ExtractLane);
+      break;
+  }
+  o << uint8_t(curr->index);
+}
+
+void BinaryInstWriter::visitSIMDReplace(SIMDReplace* curr) {
+  o << int8_t(BinaryConsts::SIMDPrefix);
+  switch (curr->op) {
+    case ReplaceLaneVecI8x16:
+      o << U32LEB(BinaryConsts::I8x16ReplaceLane);
+      break;
+    case ReplaceLaneVecI16x8:
+      o << U32LEB(BinaryConsts::I16x8ReplaceLane);
+      break;
+    case ReplaceLaneVecI32x4:
+      o << U32LEB(BinaryConsts::I32x4ReplaceLane);
+      break;
+    case ReplaceLaneVecI64x2:
+      o << U32LEB(BinaryConsts::I64x2ReplaceLane);
+      break;
+    case ReplaceLaneVecF32x4:
+      o << U32LEB(BinaryConsts::F32x4ReplaceLane);
+      break;
+    case ReplaceLaneVecF64x2:
+      o << U32LEB(BinaryConsts::F64x2ReplaceLane);
+      break;
+  }
+  assert(curr->index < 16);
+  o << uint8_t(curr->index);
+}
+
+void BinaryInstWriter::visitSIMDShuffle(SIMDShuffle* curr) {
+  o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V8x16Shuffle);
+  for (uint8_t m : curr->mask) {
+    o << m;
+  }
+}
+
+void BinaryInstWriter::visitSIMDTernary(SIMDTernary* curr) {
+  o << int8_t(BinaryConsts::SIMDPrefix);
+  switch (curr->op) {
+    case Bitselect:
+      o << U32LEB(BinaryConsts::V128Bitselect);
+      break;
+    case QFMAF32x4:
+      o << U32LEB(BinaryConsts::F32x4QFMA);
+      break;
+    case QFMSF32x4:
+      o << U32LEB(BinaryConsts::F32x4QFMS);
+      break;
+    case QFMAF64x2:
+      o << U32LEB(BinaryConsts::F64x2QFMA);
+      break;
+    case QFMSF64x2:
+      o << U32LEB(BinaryConsts::F64x2QFMS);
+      break;
+  }
+}
+
+void BinaryInstWriter::visitSIMDShift(SIMDShift* curr) {
+  o << int8_t(BinaryConsts::SIMDPrefix);
+  switch (curr->op) {
+    case ShlVecI8x16:
+      o << U32LEB(BinaryConsts::I8x16Shl);
+      break;
+    case ShrSVecI8x16:
+      o << U32LEB(BinaryConsts::I8x16ShrS);
+      break;
+    case ShrUVecI8x16:
+      o << U32LEB(BinaryConsts::I8x16ShrU);
+      break;
+    case ShlVecI16x8:
+      o << U32LEB(BinaryConsts::I16x8Shl);
+      break;
+    case ShrSVecI16x8:
+      o << U32LEB(BinaryConsts::I16x8ShrS);
+      break;
+    case ShrUVecI16x8:
+      o << U32LEB(BinaryConsts::I16x8ShrU);
+      break;
+    case ShlVecI32x4:
+      o << U32LEB(BinaryConsts::I32x4Shl);
+      break;
+    case ShrSVecI32x4:
+      o << U32LEB(BinaryConsts::I32x4ShrS);
+      break;
+    case ShrUVecI32x4:
+      o << U32LEB(BinaryConsts::I32x4ShrU);
+      break;
+    case ShlVecI64x2:
+      o << U32LEB(BinaryConsts::I64x2Shl);
+      break;
+    case ShrSVecI64x2:
+      o << U32LEB(BinaryConsts::I64x2ShrS);
+      break;
+    case ShrUVecI64x2:
+      o << U32LEB(BinaryConsts::I64x2ShrU);
+      break;
+  }
+}
+
+void BinaryInstWriter::visitSIMDLoad(SIMDLoad* curr) {
+  o << int8_t(BinaryConsts::SIMDPrefix);
+  switch (curr->op) {
+    case LoadSplatVec8x16:
+      o << U32LEB(BinaryConsts::V8x16LoadSplat);
+      break;
+    case LoadSplatVec16x8:
+      o << U32LEB(BinaryConsts::V16x8LoadSplat);
+      break;
+    case LoadSplatVec32x4:
+      o << U32LEB(BinaryConsts::V32x4LoadSplat);
+      break;
+    case LoadSplatVec64x2:
+      o << U32LEB(BinaryConsts::V64x2LoadSplat);
+      break;
+    case LoadExtSVec8x8ToVecI16x8:
+      o << U32LEB(BinaryConsts::I16x8LoadExtSVec8x8);
+      break;
+    case LoadExtUVec8x8ToVecI16x8:
+      o << U32LEB(BinaryConsts::I16x8LoadExtUVec8x8);
+      break;
+    case LoadExtSVec16x4ToVecI32x4:
+      o << U32LEB(BinaryConsts::I32x4LoadExtSVec16x4);
+      break;
+    case LoadExtUVec16x4ToVecI32x4:
+      o << U32LEB(BinaryConsts::I32x4LoadExtUVec16x4);
+      break;
+    case LoadExtSVec32x2ToVecI64x2:
+      o << U32LEB(BinaryConsts::I64x2LoadExtSVec32x2);
+      break;
+    case LoadExtUVec32x2ToVecI64x2:
+      o << U32LEB(BinaryConsts::I64x2LoadExtUVec32x2);
+      break;
+    case Load32Zero:
+      o << U32LEB(BinaryConsts::V128Load32Zero);
+      break;
+    case Load64Zero:
+      o << U32LEB(BinaryConsts::V128Load64Zero);
+      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);
+  o << U32LEB(curr->segment) << int8_t(0);
+}
+
+void BinaryInstWriter::visitDataDrop(DataDrop* curr) {
+  o << int8_t(BinaryConsts::MiscPrefix);
+  o << U32LEB(BinaryConsts::DataDrop);
+  o << U32LEB(curr->segment);
+}
+
+void BinaryInstWriter::visitMemoryCopy(MemoryCopy* curr) {
+  o << int8_t(BinaryConsts::MiscPrefix);
+  o << U32LEB(BinaryConsts::MemoryCopy);
+  o << int8_t(0) << int8_t(0);
+}
+
+void BinaryInstWriter::visitMemoryFill(MemoryFill* curr) {
+  o << int8_t(BinaryConsts::MiscPrefix);
+  o << U32LEB(BinaryConsts::MemoryFill);
+  o << int8_t(0);
+}
+
+void BinaryInstWriter::visitConst(Const* curr) {
+  switch (curr->type.getBasic()) {
+    case Type::i32: {
+      o << int8_t(BinaryConsts::I32Const) << S32LEB(curr->value.geti32());
+      break;
+    }
+    case Type::i64: {
+      o << int8_t(BinaryConsts::I64Const) << S64LEB(curr->value.geti64());
+      break;
+    }
+    case Type::f32: {
+      o << int8_t(BinaryConsts::F32Const) << curr->value.reinterpreti32();
+      break;
+    }
+    case Type::f64: {
+      o << int8_t(BinaryConsts::F64Const) << curr->value.reinterpreti64();
+      break;
+    }
+    case Type::v128: {
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Const);
+      std::array<uint8_t, 16> v = curr->value.getv128();
+      for (size_t i = 0; i < 16; ++i) {
+        o << uint8_t(v[i]);
+      }
+      break;
+    }
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+    case Type::none:
+    case Type::unreachable:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+void BinaryInstWriter::visitUnary(Unary* curr) {
+  switch (curr->op) {
+    case ClzInt32:
+      o << int8_t(BinaryConsts::I32Clz);
+      break;
+    case CtzInt32:
+      o << int8_t(BinaryConsts::I32Ctz);
+      break;
+    case PopcntInt32:
+      o << int8_t(BinaryConsts::I32Popcnt);
+      break;
+    case EqZInt32:
+      o << int8_t(BinaryConsts::I32EqZ);
+      break;
+    case ClzInt64:
+      o << int8_t(BinaryConsts::I64Clz);
+      break;
+    case CtzInt64:
+      o << int8_t(BinaryConsts::I64Ctz);
+      break;
+    case PopcntInt64:
+      o << int8_t(BinaryConsts::I64Popcnt);
+      break;
+    case EqZInt64:
+      o << int8_t(BinaryConsts::I64EqZ);
+      break;
+    case NegFloat32:
+      o << int8_t(BinaryConsts::F32Neg);
+      break;
+    case AbsFloat32:
+      o << int8_t(BinaryConsts::F32Abs);
+      break;
+    case CeilFloat32:
+      o << int8_t(BinaryConsts::F32Ceil);
+      break;
+    case FloorFloat32:
+      o << int8_t(BinaryConsts::F32Floor);
+      break;
+    case TruncFloat32:
+      o << int8_t(BinaryConsts::F32Trunc);
+      break;
+    case NearestFloat32:
+      o << int8_t(BinaryConsts::F32NearestInt);
+      break;
+    case SqrtFloat32:
+      o << int8_t(BinaryConsts::F32Sqrt);
+      break;
+    case NegFloat64:
+      o << int8_t(BinaryConsts::F64Neg);
+      break;
+    case AbsFloat64:
+      o << int8_t(BinaryConsts::F64Abs);
+      break;
+    case CeilFloat64:
+      o << int8_t(BinaryConsts::F64Ceil);
+      break;
+    case FloorFloat64:
+      o << int8_t(BinaryConsts::F64Floor);
+      break;
+    case TruncFloat64:
+      o << int8_t(BinaryConsts::F64Trunc);
+      break;
+    case NearestFloat64:
+      o << int8_t(BinaryConsts::F64NearestInt);
+      break;
+    case SqrtFloat64:
+      o << int8_t(BinaryConsts::F64Sqrt);
+      break;
+    case ExtendSInt32:
+      o << int8_t(BinaryConsts::I64SExtendI32);
+      break;
+    case ExtendUInt32:
+      o << int8_t(BinaryConsts::I64UExtendI32);
+      break;
+    case WrapInt64:
+      o << int8_t(BinaryConsts::I32WrapI64);
+      break;
+    case TruncUFloat32ToInt32:
+      o << int8_t(BinaryConsts::I32UTruncF32);
+      break;
+    case TruncUFloat32ToInt64:
+      o << int8_t(BinaryConsts::I64UTruncF32);
+      break;
+    case TruncSFloat32ToInt32:
+      o << int8_t(BinaryConsts::I32STruncF32);
+      break;
+    case TruncSFloat32ToInt64:
+      o << int8_t(BinaryConsts::I64STruncF32);
+      break;
+    case TruncUFloat64ToInt32:
+      o << int8_t(BinaryConsts::I32UTruncF64);
+      break;
+    case TruncUFloat64ToInt64:
+      o << int8_t(BinaryConsts::I64UTruncF64);
+      break;
+    case TruncSFloat64ToInt32:
+      o << int8_t(BinaryConsts::I32STruncF64);
+      break;
+    case TruncSFloat64ToInt64:
+      o << int8_t(BinaryConsts::I64STruncF64);
+      break;
+    case ConvertUInt32ToFloat32:
+      o << int8_t(BinaryConsts::F32UConvertI32);
+      break;
+    case ConvertUInt32ToFloat64:
+      o << int8_t(BinaryConsts::F64UConvertI32);
+      break;
+    case ConvertSInt32ToFloat32:
+      o << int8_t(BinaryConsts::F32SConvertI32);
+      break;
+    case ConvertSInt32ToFloat64:
+      o << int8_t(BinaryConsts::F64SConvertI32);
+      break;
+    case ConvertUInt64ToFloat32:
+      o << int8_t(BinaryConsts::F32UConvertI64);
+      break;
+    case ConvertUInt64ToFloat64:
+      o << int8_t(BinaryConsts::F64UConvertI64);
+      break;
+    case ConvertSInt64ToFloat32:
+      o << int8_t(BinaryConsts::F32SConvertI64);
+      break;
+    case ConvertSInt64ToFloat64:
+      o << int8_t(BinaryConsts::F64SConvertI64);
+      break;
+    case DemoteFloat64:
+      o << int8_t(BinaryConsts::F32DemoteI64);
+      break;
+    case PromoteFloat32:
+      o << int8_t(BinaryConsts::F64PromoteF32);
+      break;
+    case ReinterpretFloat32:
+      o << int8_t(BinaryConsts::I32ReinterpretF32);
+      break;
+    case ReinterpretFloat64:
+      o << int8_t(BinaryConsts::I64ReinterpretF64);
+      break;
+    case ReinterpretInt32:
+      o << int8_t(BinaryConsts::F32ReinterpretI32);
+      break;
+    case ReinterpretInt64:
+      o << int8_t(BinaryConsts::F64ReinterpretI64);
+      break;
+    case ExtendS8Int32:
+      o << int8_t(BinaryConsts::I32ExtendS8);
+      break;
+    case ExtendS16Int32:
+      o << int8_t(BinaryConsts::I32ExtendS16);
+      break;
+    case ExtendS8Int64:
+      o << int8_t(BinaryConsts::I64ExtendS8);
+      break;
+    case ExtendS16Int64:
+      o << int8_t(BinaryConsts::I64ExtendS16);
+      break;
+    case ExtendS32Int64:
+      o << int8_t(BinaryConsts::I64ExtendS32);
+      break;
+    case TruncSatSFloat32ToInt32:
+      o << int8_t(BinaryConsts::MiscPrefix)
+        << U32LEB(BinaryConsts::I32STruncSatF32);
+      break;
+    case TruncSatUFloat32ToInt32:
+      o << int8_t(BinaryConsts::MiscPrefix)
+        << U32LEB(BinaryConsts::I32UTruncSatF32);
+      break;
+    case TruncSatSFloat64ToInt32:
+      o << int8_t(BinaryConsts::MiscPrefix)
+        << U32LEB(BinaryConsts::I32STruncSatF64);
+      break;
+    case TruncSatUFloat64ToInt32:
+      o << int8_t(BinaryConsts::MiscPrefix)
+        << U32LEB(BinaryConsts::I32UTruncSatF64);
+      break;
+    case TruncSatSFloat32ToInt64:
+      o << int8_t(BinaryConsts::MiscPrefix)
+        << U32LEB(BinaryConsts::I64STruncSatF32);
+      break;
+    case TruncSatUFloat32ToInt64:
+      o << int8_t(BinaryConsts::MiscPrefix)
+        << U32LEB(BinaryConsts::I64UTruncSatF32);
+      break;
+    case TruncSatSFloat64ToInt64:
+      o << int8_t(BinaryConsts::MiscPrefix)
+        << U32LEB(BinaryConsts::I64STruncSatF64);
+      break;
+    case TruncSatUFloat64ToInt64:
+      o << int8_t(BinaryConsts::MiscPrefix)
+        << U32LEB(BinaryConsts::I64UTruncSatF64);
+      break;
+    case SplatVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Splat);
+      break;
+    case SplatVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Splat);
+      break;
+    case SplatVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Splat);
+      break;
+    case SplatVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Splat);
+      break;
+    case SplatVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Splat);
+      break;
+    case SplatVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Splat);
+      break;
+    case NotVec128:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Not);
+      break;
+    case AbsVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Abs);
+      break;
+    case NegVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Neg);
+      break;
+    case AnyTrueVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I8x16AnyTrue);
+      break;
+    case AllTrueVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I8x16AllTrue);
+      break;
+    case BitmaskVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I8x16Bitmask);
+      break;
+    case AbsVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Abs);
+      break;
+    case NegVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Neg);
+      break;
+    case AnyTrueVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8AnyTrue);
+      break;
+    case AllTrueVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8AllTrue);
+      break;
+    case BitmaskVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8Bitmask);
+      break;
+    case AbsVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Abs);
+      break;
+    case NegVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Neg);
+      break;
+    case AnyTrueVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4AnyTrue);
+      break;
+    case AllTrueVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4AllTrue);
+      break;
+    case BitmaskVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4Bitmask);
+      break;
+    case NegVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Neg);
+      break;
+    case AnyTrueVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I64x2AnyTrue);
+      break;
+    case AllTrueVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I64x2AllTrue);
+      break;
+    case AbsVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Abs);
+      break;
+    case NegVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Neg);
+      break;
+    case SqrtVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Sqrt);
+      break;
+    case CeilVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Ceil);
+      break;
+    case FloorVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Floor);
+      break;
+    case TruncVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Trunc);
+      break;
+    case NearestVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::F32x4Nearest);
+      break;
+    case AbsVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Abs);
+      break;
+    case NegVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Neg);
+      break;
+    case SqrtVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Sqrt);
+      break;
+    case CeilVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Ceil);
+      break;
+    case FloorVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Floor);
+      break;
+    case TruncVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Trunc);
+      break;
+    case NearestVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::F64x2Nearest);
+      break;
+    case TruncSatSVecF32x4ToVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4TruncSatSF32x4);
+      break;
+    case TruncSatUVecF32x4ToVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4TruncSatUF32x4);
+      break;
+    case TruncSatSVecF64x2ToVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I64x2TruncSatSF64x2);
+      break;
+    case TruncSatUVecF64x2ToVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I64x2TruncSatUF64x2);
+      break;
+    case ConvertSVecI32x4ToVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::F32x4ConvertSI32x4);
+      break;
+    case ConvertUVecI32x4ToVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::F32x4ConvertUI32x4);
+      break;
+    case ConvertSVecI64x2ToVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::F64x2ConvertSI64x2);
+      break;
+    case ConvertUVecI64x2ToVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::F64x2ConvertUI64x2);
+      break;
+    case WidenLowSVecI8x16ToVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8WidenLowSI8x16);
+      break;
+    case WidenHighSVecI8x16ToVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8WidenHighSI8x16);
+      break;
+    case WidenLowUVecI8x16ToVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8WidenLowUI8x16);
+      break;
+    case WidenHighUVecI8x16ToVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8WidenHighUI8x16);
+      break;
+    case WidenLowSVecI16x8ToVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4WidenLowSI16x8);
+      break;
+    case WidenHighSVecI16x8ToVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4WidenHighSI16x8);
+      break;
+    case WidenLowUVecI16x8ToVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4WidenLowUI16x8);
+      break;
+    case WidenHighUVecI16x8ToVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4WidenHighUI16x8);
+      break;
+    case InvalidUnary:
+      WASM_UNREACHABLE("invalid unary op");
+  }
+}
+
+void BinaryInstWriter::visitBinary(Binary* curr) {
+  switch (curr->op) {
+    case AddInt32:
+      o << int8_t(BinaryConsts::I32Add);
+      break;
+    case SubInt32:
+      o << int8_t(BinaryConsts::I32Sub);
+      break;
+    case MulInt32:
+      o << int8_t(BinaryConsts::I32Mul);
+      break;
+    case DivSInt32:
+      o << int8_t(BinaryConsts::I32DivS);
+      break;
+    case DivUInt32:
+      o << int8_t(BinaryConsts::I32DivU);
+      break;
+    case RemSInt32:
+      o << int8_t(BinaryConsts::I32RemS);
+      break;
+    case RemUInt32:
+      o << int8_t(BinaryConsts::I32RemU);
+      break;
+    case AndInt32:
+      o << int8_t(BinaryConsts::I32And);
+      break;
+    case OrInt32:
+      o << int8_t(BinaryConsts::I32Or);
+      break;
+    case XorInt32:
+      o << int8_t(BinaryConsts::I32Xor);
+      break;
+    case ShlInt32:
+      o << int8_t(BinaryConsts::I32Shl);
+      break;
+    case ShrUInt32:
+      o << int8_t(BinaryConsts::I32ShrU);
+      break;
+    case ShrSInt32:
+      o << int8_t(BinaryConsts::I32ShrS);
+      break;
+    case RotLInt32:
+      o << int8_t(BinaryConsts::I32RotL);
+      break;
+    case RotRInt32:
+      o << int8_t(BinaryConsts::I32RotR);
+      break;
+    case EqInt32:
+      o << int8_t(BinaryConsts::I32Eq);
+      break;
+    case NeInt32:
+      o << int8_t(BinaryConsts::I32Ne);
+      break;
+    case LtSInt32:
+      o << int8_t(BinaryConsts::I32LtS);
+      break;
+    case LtUInt32:
+      o << int8_t(BinaryConsts::I32LtU);
+      break;
+    case LeSInt32:
+      o << int8_t(BinaryConsts::I32LeS);
+      break;
+    case LeUInt32:
+      o << int8_t(BinaryConsts::I32LeU);
+      break;
+    case GtSInt32:
+      o << int8_t(BinaryConsts::I32GtS);
+      break;
+    case GtUInt32:
+      o << int8_t(BinaryConsts::I32GtU);
+      break;
+    case GeSInt32:
+      o << int8_t(BinaryConsts::I32GeS);
+      break;
+    case GeUInt32:
+      o << int8_t(BinaryConsts::I32GeU);
+      break;
+
+    case AddInt64:
+      o << int8_t(BinaryConsts::I64Add);
+      break;
+    case SubInt64:
+      o << int8_t(BinaryConsts::I64Sub);
+      break;
+    case MulInt64:
+      o << int8_t(BinaryConsts::I64Mul);
+      break;
+    case DivSInt64:
+      o << int8_t(BinaryConsts::I64DivS);
+      break;
+    case DivUInt64:
+      o << int8_t(BinaryConsts::I64DivU);
+      break;
+    case RemSInt64:
+      o << int8_t(BinaryConsts::I64RemS);
+      break;
+    case RemUInt64:
+      o << int8_t(BinaryConsts::I64RemU);
+      break;
+    case AndInt64:
+      o << int8_t(BinaryConsts::I64And);
+      break;
+    case OrInt64:
+      o << int8_t(BinaryConsts::I64Or);
+      break;
+    case XorInt64:
+      o << int8_t(BinaryConsts::I64Xor);
+      break;
+    case ShlInt64:
+      o << int8_t(BinaryConsts::I64Shl);
+      break;
+    case ShrUInt64:
+      o << int8_t(BinaryConsts::I64ShrU);
+      break;
+    case ShrSInt64:
+      o << int8_t(BinaryConsts::I64ShrS);
+      break;
+    case RotLInt64:
+      o << int8_t(BinaryConsts::I64RotL);
+      break;
+    case RotRInt64:
+      o << int8_t(BinaryConsts::I64RotR);
+      break;
+    case EqInt64:
+      o << int8_t(BinaryConsts::I64Eq);
+      break;
+    case NeInt64:
+      o << int8_t(BinaryConsts::I64Ne);
+      break;
+    case LtSInt64:
+      o << int8_t(BinaryConsts::I64LtS);
+      break;
+    case LtUInt64:
+      o << int8_t(BinaryConsts::I64LtU);
+      break;
+    case LeSInt64:
+      o << int8_t(BinaryConsts::I64LeS);
+      break;
+    case LeUInt64:
+      o << int8_t(BinaryConsts::I64LeU);
+      break;
+    case GtSInt64:
+      o << int8_t(BinaryConsts::I64GtS);
+      break;
+    case GtUInt64:
+      o << int8_t(BinaryConsts::I64GtU);
+      break;
+    case GeSInt64:
+      o << int8_t(BinaryConsts::I64GeS);
+      break;
+    case GeUInt64:
+      o << int8_t(BinaryConsts::I64GeU);
+      break;
+
+    case AddFloat32:
+      o << int8_t(BinaryConsts::F32Add);
+      break;
+    case SubFloat32:
+      o << int8_t(BinaryConsts::F32Sub);
+      break;
+    case MulFloat32:
+      o << int8_t(BinaryConsts::F32Mul);
+      break;
+    case DivFloat32:
+      o << int8_t(BinaryConsts::F32Div);
+      break;
+    case CopySignFloat32:
+      o << int8_t(BinaryConsts::F32CopySign);
+      break;
+    case MinFloat32:
+      o << int8_t(BinaryConsts::F32Min);
+      break;
+    case MaxFloat32:
+      o << int8_t(BinaryConsts::F32Max);
+      break;
+    case EqFloat32:
+      o << int8_t(BinaryConsts::F32Eq);
+      break;
+    case NeFloat32:
+      o << int8_t(BinaryConsts::F32Ne);
+      break;
+    case LtFloat32:
+      o << int8_t(BinaryConsts::F32Lt);
+      break;
+    case LeFloat32:
+      o << int8_t(BinaryConsts::F32Le);
+      break;
+    case GtFloat32:
+      o << int8_t(BinaryConsts::F32Gt);
+      break;
+    case GeFloat32:
+      o << int8_t(BinaryConsts::F32Ge);
+      break;
+
+    case AddFloat64:
+      o << int8_t(BinaryConsts::F64Add);
+      break;
+    case SubFloat64:
+      o << int8_t(BinaryConsts::F64Sub);
+      break;
+    case MulFloat64:
+      o << int8_t(BinaryConsts::F64Mul);
+      break;
+    case DivFloat64:
+      o << int8_t(BinaryConsts::F64Div);
+      break;
+    case CopySignFloat64:
+      o << int8_t(BinaryConsts::F64CopySign);
+      break;
+    case MinFloat64:
+      o << int8_t(BinaryConsts::F64Min);
+      break;
+    case MaxFloat64:
+      o << int8_t(BinaryConsts::F64Max);
+      break;
+    case EqFloat64:
+      o << int8_t(BinaryConsts::F64Eq);
+      break;
+    case NeFloat64:
+      o << int8_t(BinaryConsts::F64Ne);
+      break;
+    case LtFloat64:
+      o << int8_t(BinaryConsts::F64Lt);
+      break;
+    case LeFloat64:
+      o << int8_t(BinaryConsts::F64Le);
+      break;
+    case GtFloat64:
+      o << int8_t(BinaryConsts::F64Gt);
+      break;
+    case GeFloat64:
+      o << int8_t(BinaryConsts::F64Ge);
+      break;
+
+    case EqVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Eq);
+      break;
+    case NeVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Ne);
+      break;
+    case LtSVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16LtS);
+      break;
+    case LtUVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16LtU);
+      break;
+    case GtSVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16GtS);
+      break;
+    case GtUVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16GtU);
+      break;
+    case LeSVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16LeS);
+      break;
+    case LeUVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16LeU);
+      break;
+    case GeSVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16GeS);
+      break;
+    case GeUVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16GeU);
+      break;
+    case EqVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Eq);
+      break;
+    case NeVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Ne);
+      break;
+    case LtSVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8LtS);
+      break;
+    case LtUVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8LtU);
+      break;
+    case GtSVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8GtS);
+      break;
+    case GtUVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8GtU);
+      break;
+    case LeSVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8LeS);
+      break;
+    case LeUVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8LeU);
+      break;
+    case GeSVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8GeS);
+      break;
+    case GeUVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8GeU);
+      break;
+    case EqVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Eq);
+      break;
+    case NeVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Ne);
+      break;
+    case LtSVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4LtS);
+      break;
+    case LtUVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4LtU);
+      break;
+    case GtSVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4GtS);
+      break;
+    case GtUVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4GtU);
+      break;
+    case LeSVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4LeS);
+      break;
+    case LeUVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4LeU);
+      break;
+    case GeSVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4GeS);
+      break;
+    case GeUVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4GeU);
+      break;
+    case EqVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Eq);
+      break;
+    case NeVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Ne);
+      break;
+    case LtVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Lt);
+      break;
+    case GtVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Gt);
+      break;
+    case LeVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Le);
+      break;
+    case GeVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Ge);
+      break;
+    case EqVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Eq);
+      break;
+    case NeVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Ne);
+      break;
+    case LtVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Lt);
+      break;
+    case GtVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Gt);
+      break;
+    case LeVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Le);
+      break;
+    case GeVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Ge);
+      break;
+    case AndVec128:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128And);
+      break;
+    case OrVec128:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Or);
+      break;
+    case XorVec128:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Xor);
+      break;
+    case AndNotVec128:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128AndNot);
+      break;
+    case AddVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Add);
+      break;
+    case AddSatSVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I8x16AddSatS);
+      break;
+    case AddSatUVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I8x16AddSatU);
+      break;
+    case SubVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Sub);
+      break;
+    case SubSatSVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I8x16SubSatS);
+      break;
+    case SubSatUVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I8x16SubSatU);
+      break;
+    case MulVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16Mul);
+      break;
+    case MinSVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16MinS);
+      break;
+    case MinUVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16MinU);
+      break;
+    case MaxSVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16MaxS);
+      break;
+    case MaxUVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16MaxU);
+      break;
+    case AvgrUVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I8x16AvgrU);
+      break;
+    case AddVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Add);
+      break;
+    case AddSatSVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8AddSatS);
+      break;
+    case AddSatUVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8AddSatU);
+      break;
+    case SubVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Sub);
+      break;
+    case SubSatSVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8SubSatS);
+      break;
+    case SubSatUVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8SubSatU);
+      break;
+    case MulVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Mul);
+      break;
+    case MinSVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8MinS);
+      break;
+    case MinUVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8MinU);
+      break;
+    case MaxSVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8MaxS);
+      break;
+    case MaxUVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8MaxU);
+      break;
+    case AvgrUVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8AvgrU);
+      break;
+    case AddVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Add);
+      break;
+    case SubVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Sub);
+      break;
+    case MulVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Mul);
+      break;
+    case MinSVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4MinS);
+      break;
+    case MinUVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4MinU);
+      break;
+    case MaxSVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4MaxS);
+      break;
+    case MaxUVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4MaxU);
+      break;
+    case DotSVecI16x8ToVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4DotSVecI16x8);
+      break;
+    case AddVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Add);
+      break;
+    case SubVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Sub);
+      break;
+    case MulVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Mul);
+      break;
+
+    case AddVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Add);
+      break;
+    case SubVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Sub);
+      break;
+    case MulVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Mul);
+      break;
+    case DivVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Div);
+      break;
+    case MinVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Min);
+      break;
+    case MaxVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Max);
+      break;
+    case PMinVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4PMin);
+      break;
+    case PMaxVecF32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4PMax);
+      break;
+    case AddVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Add);
+      break;
+    case SubVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Sub);
+      break;
+    case MulVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Mul);
+      break;
+    case DivVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Div);
+      break;
+    case MinVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Min);
+      break;
+    case MaxVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Max);
+      break;
+    case PMinVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2PMin);
+      break;
+    case PMaxVecF64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2PMax);
+      break;
+
+    case NarrowSVecI16x8ToVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I8x16NarrowSI16x8);
+      break;
+    case NarrowUVecI16x8ToVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I8x16NarrowUI16x8);
+      break;
+    case NarrowSVecI32x4ToVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8NarrowSI32x4);
+      break;
+    case NarrowUVecI32x4ToVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8NarrowUI32x4);
+      break;
+
+    case SwizzleVec8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::V8x16Swizzle);
+      break;
+
+    case InvalidBinary:
+      WASM_UNREACHABLE("invalid binary op");
+  }
+}
+
+void BinaryInstWriter::visitSelect(Select* curr) {
+  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);
+    }
+  } else {
+    o << int8_t(BinaryConsts::Select);
+  }
+}
+
+void BinaryInstWriter::visitReturn(Return* curr) {
+  o << int8_t(BinaryConsts::Return);
+}
+
+void BinaryInstWriter::visitMemorySize(MemorySize* curr) {
+  o << int8_t(BinaryConsts::MemorySize);
+  o << U32LEB(0); // Reserved flags field
+}
+
+void BinaryInstWriter::visitMemoryGrow(MemoryGrow* curr) {
+  o << int8_t(BinaryConsts::MemoryGrow);
+  o << U32LEB(0); // Reserved flags field
+}
+
+void BinaryInstWriter::visitRefNull(RefNull* curr) {
+  o << int8_t(BinaryConsts::RefNull)
+    << binaryHeapType(curr->type.getHeapType());
+}
+
+void BinaryInstWriter::visitRefIsNull(RefIsNull* curr) {
+  o << int8_t(BinaryConsts::RefIsNull);
+}
+
+void BinaryInstWriter::visitRefFunc(RefFunc* curr) {
+  o << int8_t(BinaryConsts::RefFunc)
+    << U32LEB(parent.getFunctionIndex(curr->func));
+}
+
+void BinaryInstWriter::visitRefEq(RefEq* curr) {
+  o << int8_t(BinaryConsts::RefEq);
+}
+
+void BinaryInstWriter::visitTry(Try* curr) {
+  breakStack.emplace_back(IMPOSSIBLE_CONTINUE);
+  o << int8_t(BinaryConsts::Try);
+  emitResultType(curr->type);
+}
+
+void BinaryInstWriter::emitCatch(Try* curr) {
+  assert(!breakStack.empty());
+  breakStack.pop_back();
+  breakStack.emplace_back(IMPOSSIBLE_CONTINUE);
+  if (func && !sourceMap) {
+    parent.writeExtraDebugLocation(curr, func, BinaryLocations::Catch);
+  }
+  o << int8_t(BinaryConsts::Catch);
+}
+
+void BinaryInstWriter::visitThrow(Throw* curr) {
+  o << int8_t(BinaryConsts::Throw) << U32LEB(parent.getEventIndex(curr->event));
+}
+
+void BinaryInstWriter::visitRethrow(Rethrow* curr) {
+  o << int8_t(BinaryConsts::Rethrow);
+}
+
+void BinaryInstWriter::visitBrOnExn(BrOnExn* curr) {
+  o << int8_t(BinaryConsts::BrOnExn) << U32LEB(getBreakIndex(curr->name))
+    << U32LEB(parent.getEventIndex(curr->event));
+}
+
+void BinaryInstWriter::visitNop(Nop* curr) { o << int8_t(BinaryConsts::Nop); }
+
+void BinaryInstWriter::visitUnreachable(Unreachable* curr) {
+  o << int8_t(BinaryConsts::Unreachable);
+}
+
+void BinaryInstWriter::visitDrop(Drop* curr) {
+  size_t numValues = curr->value->type.size();
+  for (size_t i = 0; i < numValues; i++) {
+    o << int8_t(BinaryConsts::Drop);
+  }
+}
+
+void BinaryInstWriter::visitPop(Pop* curr) {
+  // Turns into nothing in the binary format
+}
+
+void BinaryInstWriter::visitTupleMake(TupleMake* curr) {
+  // Turns into nothing in the binary format
+}
+
+void BinaryInstWriter::visitTupleExtract(TupleExtract* curr) {
+  size_t numVals = curr->tuple->type.size();
+  // Drop all values after the one we want
+  for (size_t i = curr->index + 1; i < numVals; ++i) {
+    o << int8_t(BinaryConsts::Drop);
+  }
+  // If the extracted value is the only one left, we're done
+  if (curr->index == 0) {
+    return;
+  }
+  // Otherwise, save it to a scratch local, drop the others, then retrieve it
+  assert(scratchLocals.find(curr->type) != scratchLocals.end());
+  auto scratch = scratchLocals[curr->type];
+  o << int8_t(BinaryConsts::LocalSet) << U32LEB(scratch);
+  for (size_t i = 0; i < curr->index; ++i) {
+    o << int8_t(BinaryConsts::Drop);
+  }
+  o << int8_t(BinaryConsts::LocalGet) << U32LEB(scratch);
+}
+
+void BinaryInstWriter::visitI31New(I31New* curr) {
+  o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::I31New);
+}
+
+void BinaryInstWriter::visitI31Get(I31Get* curr) {
+  o << int8_t(BinaryConsts::GCPrefix)
+    << U32LEB(curr->signed_ ? BinaryConsts::I31GetS : BinaryConsts::I31GetU);
+}
+
+void BinaryInstWriter::visitRefTest(RefTest* curr) {
+  o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RefTest);
+  WASM_UNREACHABLE("TODO (gc): ref.test");
+}
+
+void BinaryInstWriter::visitRefCast(RefCast* curr) {
+  o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RefCast);
+  WASM_UNREACHABLE("TODO (gc): ref.cast");
+}
+
+void BinaryInstWriter::visitBrOnCast(BrOnCast* curr) {
+  o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnCast);
+  WASM_UNREACHABLE("TODO (gc): br_on_cast");
+}
+
+void BinaryInstWriter::visitRttCanon(RttCanon* curr) {
+  o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RttCanon);
+  WASM_UNREACHABLE("TODO (gc): rtt.canon");
+}
+
+void BinaryInstWriter::visitRttSub(RttSub* curr) {
+  o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RttSub);
+  WASM_UNREACHABLE("TODO (gc): rtt.sub");
+}
+
+void BinaryInstWriter::visitStructNew(StructNew* curr) {
+  WASM_UNREACHABLE("TODO (gc): struct.new");
+}
+
+void BinaryInstWriter::visitStructGet(StructGet* curr) {
+  WASM_UNREACHABLE("TODO (gc): struct.get");
+}
+
+void BinaryInstWriter::visitStructSet(StructSet* curr) {
+  o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::StructSet);
+  WASM_UNREACHABLE("TODO (gc): struct.set");
+}
+
+void BinaryInstWriter::visitArrayNew(ArrayNew* curr) {
+  WASM_UNREACHABLE("TODO (gc): array.new");
+}
+
+void BinaryInstWriter::visitArrayGet(ArrayGet* curr) {
+  WASM_UNREACHABLE("TODO (gc): array.get");
+}
+
+void BinaryInstWriter::visitArraySet(ArraySet* curr) {
+  o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::ArraySet);
+  WASM_UNREACHABLE("TODO (gc): array.set");
+}
+
+void BinaryInstWriter::visitArrayLen(ArrayLen* curr) {
+  o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::ArrayLen);
+  WASM_UNREACHABLE("TODO (gc): array.len");
+}
+
+void BinaryInstWriter::emitScopeEnd(Expression* curr) {
+  assert(!breakStack.empty());
+  breakStack.pop_back();
+  if (func && !sourceMap) {
+    parent.writeExtraDebugLocation(curr, func, BinaryLocations::End);
+  }
+  o << int8_t(BinaryConsts::End);
+}
+
+void BinaryInstWriter::emitFunctionEnd() { o << int8_t(BinaryConsts::End); }
+
+void BinaryInstWriter::emitUnreachable() {
+  o << int8_t(BinaryConsts::Unreachable);
+}
+
+void BinaryInstWriter::mapLocalsAndEmitHeader() {
+  assert(func && "BinaryInstWriter: function is not set");
+  // Map params
+  for (Index i = 0; i < func->getNumParams(); i++) {
+    mappedLocals[std::make_pair(i, 0)] = i;
+  }
+  // Normally we map all locals of the same type into a range of adjacent
+  // addresses, which is more compact. However, if we need to keep DWARF valid,
+  // do not do any reordering at all - instead, do a trivial mapping that
+  // keeps everything unmoved.
+  if (DWARF) {
+    FindAll<TupleExtract> extracts(func->body);
+    if (!extracts.list.empty()) {
+      Fatal() << "DWARF + multivalue is not yet complete";
+    }
+    Index varStart = func->getVarIndexBase();
+    Index varEnd = varStart + func->getNumVars();
+    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));
+    }
+    return;
+  }
+  for (auto type : func->vars) {
+    for (const auto& t : type) {
+      numLocalsByType[t]++;
+    }
+  }
+  countScratchLocals();
+  std::map<Type, size_t> currLocalsByType;
+  for (Index i = func->getVarIndexBase(); i < func->getNumLocals(); i++) {
+    Index j = 0;
+    for (const auto& type : func->getLocalType(i)) {
+      auto fullIndex = std::make_pair(i, j++);
+      Index index = func->getVarIndexBase();
+      for (auto& typeCount : numLocalsByType) {
+        if (type == typeCount.first) {
+          mappedLocals[fullIndex] = index + currLocalsByType[typeCount.first];
+          currLocalsByType[type]++;
+          break;
+        }
+        index += typeCount.second;
+      }
+    }
+  }
+  setScratchLocals();
+  o << U32LEB(numLocalsByType.size());
+  for (auto& typeCount : numLocalsByType) {
+    o << U32LEB(typeCount.second) << binaryType(typeCount.first);
+  }
+}
+
+void BinaryInstWriter::countScratchLocals() {
+  // Add a scratch register in `numLocalsByType` for each type of
+  // tuple.extract with nonzero index present.
+  FindAll<TupleExtract> extracts(func->body);
+  for (auto* extract : extracts.list) {
+    if (extract->type != Type::unreachable && extract->index != 0) {
+      scratchLocals[extract->type] = 0;
+    }
+  }
+  for (auto t : scratchLocals) {
+    numLocalsByType[t.first]++;
+  }
+}
+
+void BinaryInstWriter::setScratchLocals() {
+  Index index = func->getVarIndexBase();
+  for (auto& typeCount : numLocalsByType) {
+    index += typeCount.second;
+    if (scratchLocals.find(typeCount.first) != scratchLocals.end()) {
+      scratchLocals[typeCount.first] = index - 1;
+    }
+  }
+}
+
+void BinaryInstWriter::emitMemoryAccess(size_t alignment,
+                                        size_t bytes,
+                                        uint32_t offset) {
+  o << U32LEB(Bits::log2(alignment ? alignment : bytes));
+  o << U32LEB(offset);
+}
+
+int32_t BinaryInstWriter::getBreakIndex(Name name) { // -1 if not found
+  for (int i = breakStack.size() - 1; i >= 0; i--) {
+    if (breakStack[i] == name) {
+      return breakStack.size() - 1 - i;
+    }
+  }
+  WASM_UNREACHABLE("break index not found");
+}
+
+void StackIRGenerator::emit(Expression* curr) {
+  StackInst* stackInst = nullptr;
+  if (curr->is<Block>()) {
+    stackInst = makeStackInst(StackInst::BlockBegin, curr);
+  } else if (curr->is<If>()) {
+    stackInst = makeStackInst(StackInst::IfBegin, curr);
+  } else if (curr->is<Loop>()) {
+    stackInst = makeStackInst(StackInst::LoopBegin, curr);
+  } else if (curr->is<Try>()) {
+    stackInst = makeStackInst(StackInst::TryBegin, curr);
+  } else {
+    stackInst = makeStackInst(curr);
+  }
+  stackIR.push_back(stackInst);
+}
+
+void StackIRGenerator::emitScopeEnd(Expression* curr) {
+  StackInst* stackInst = nullptr;
+  if (curr->is<Block>()) {
+    stackInst = makeStackInst(StackInst::BlockEnd, curr);
+  } else if (curr->is<If>()) {
+    stackInst = makeStackInst(StackInst::IfEnd, curr);
+  } else if (curr->is<Loop>()) {
+    stackInst = makeStackInst(StackInst::LoopEnd, curr);
+  } else if (curr->is<Try>()) {
+    stackInst = makeStackInst(StackInst::TryEnd, curr);
+  } else {
+    WASM_UNREACHABLE("unexpected expr type");
+  }
+  stackIR.push_back(stackInst);
+}
+
+StackInst* StackIRGenerator::makeStackInst(StackInst::Op op,
+                                           Expression* origin) {
+  auto* ret = module.allocator.alloc<StackInst>();
+  ret->op = op;
+  ret->origin = origin;
+  auto stackType = origin->type;
+  if (origin->is<Block>() || origin->is<Loop>() || origin->is<If>() ||
+      origin->is<Try>()) {
+    if (stackType == Type::unreachable) {
+      // There are no unreachable blocks, loops, or ifs. we emit extra
+      // unreachables to fix that up, so that they are valid as having none
+      // type.
+      stackType = Type::none;
+    } else if (op != StackInst::BlockEnd && op != StackInst::IfEnd &&
+               op != StackInst::LoopEnd && op != StackInst::TryEnd) {
+      // If a concrete type is returned, we mark the end of the construct has
+      // having that type (as it is pushed to the value stack at that point),
+      // other parts are marked as none).
+      stackType = Type::none;
+    }
+  }
+  ret->type = stackType;
+  return ret;
+}
+
+void StackIRToBinaryWriter::write() {
+  writer.mapLocalsAndEmitHeader();
+  for (auto* inst : *func->stackIR) {
+    if (!inst) {
+      continue; // a nullptr is just something we can skip
+    }
+    switch (inst->op) {
+      case StackInst::Basic:
+      case StackInst::BlockBegin:
+      case StackInst::IfBegin:
+      case StackInst::LoopBegin:
+      case StackInst::TryBegin: {
+        writer.visit(inst->origin);
+        break;
+      }
+      case StackInst::BlockEnd:
+      case StackInst::IfEnd:
+      case StackInst::LoopEnd:
+      case StackInst::TryEnd: {
+        writer.emitScopeEnd(inst->origin);
+        break;
+      }
+      case StackInst::IfElse: {
+        writer.emitIfElse(inst->origin->cast<If>());
+        break;
+      }
+      case StackInst::Catch: {
+        writer.emitCatch(inst->origin->cast<Try>());
+        break;
+      }
+      default:
+        WASM_UNREACHABLE("unexpected op");
+    }
+  }
+  writer.emitFunctionEnd();
+}
+
+} // namespace wasm
diff --git a/binaryen/src/wasm/wasm-type.cpp b/binaryen/src/wasm/wasm-type.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm/wasm-type.cpp
@@ -0,0 +1,903 @@
+/*
+ * 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.
+ */
+
+#include <array>
+#include <cassert>
+#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
diff --git a/binaryen/src/wasm/wasm-validator.cpp b/binaryen/src/wasm/wasm-validator.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm/wasm-validator.cpp
@@ -0,0 +1,2697 @@
+/*
+ * 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.
+ */
+
+#include <mutex>
+#include <set>
+#include <sstream>
+#include <unordered_set>
+
+#include "ir/features.h"
+#include "ir/global-utils.h"
+#include "ir/module-utils.h"
+#include "ir/stack-utils.h"
+#include "ir/utils.h"
+#include "support/colors.h"
+#include "wasm-printing.h"
+#include "wasm-validator.h"
+#include "wasm.h"
+
+namespace wasm {
+
+// Print anything that can be streamed to an ostream
+template<typename T,
+         typename std::enable_if<!std::is_base_of<
+           Expression,
+           typename std::remove_pointer<T>::type>::value>::type* = nullptr>
+inline std::ostream& printModuleComponent(T curr, std::ostream& stream) {
+  stream << curr << std::endl;
+  return stream;
+}
+
+// Extra overload for Expressions, to print type info too
+inline std::ostream& printModuleComponent(Expression* curr,
+                                          std::ostream& stream) {
+  WasmPrinter::printExpression(curr, stream, false, true) << std::endl;
+  return stream;
+}
+
+// For parallel validation, we have a helper struct for coordination
+struct ValidationInfo {
+  bool validateWeb;
+  bool validateGlobally;
+  bool quiet;
+
+  std::atomic<bool> valid;
+
+  // a stream of error test for each function. we print in the right order at
+  // the end, for deterministic output
+  // note errors are rare/unexpected, so it's ok to use a slow mutex here
+  std::mutex mutex;
+  std::unordered_map<Function*, std::unique_ptr<std::ostringstream>> outputs;
+
+  ValidationInfo() { valid.store(true); }
+
+  std::ostringstream& getStream(Function* func) {
+    std::unique_lock<std::mutex> lock(mutex);
+    auto iter = outputs.find(func);
+    if (iter != outputs.end()) {
+      return *(iter->second.get());
+    }
+    auto& ret = outputs[func] = make_unique<std::ostringstream>();
+    return *ret.get();
+  }
+
+  // printing and error handling support
+
+  template<typename T, typename S>
+  std::ostream& fail(S text, T curr, Function* func) {
+    valid.store(false);
+    auto& stream = getStream(func);
+    if (quiet) {
+      return stream;
+    }
+    auto& ret = printFailureHeader(func);
+    ret << text << ", on \n";
+    return printModuleComponent(curr, ret);
+  }
+
+  std::ostream& printFailureHeader(Function* func) {
+    auto& stream = getStream(func);
+    if (quiet) {
+      return stream;
+    }
+    Colors::red(stream);
+    if (func) {
+      stream << "[wasm-validator error in function ";
+      Colors::green(stream);
+      stream << func->name;
+      Colors::red(stream);
+      stream << "] ";
+    } else {
+      stream << "[wasm-validator error in module] ";
+    }
+    Colors::normal(stream);
+    return stream;
+  }
+
+  // checking utilities
+
+  template<typename T>
+  bool shouldBeTrue(bool result,
+                    T curr,
+                    const char* text,
+                    Function* func = nullptr) {
+    if (!result) {
+      fail("unexpected false: " + std::string(text), curr, func);
+      return false;
+    }
+    return result;
+  }
+  template<typename T>
+  bool shouldBeFalse(bool result,
+                     T curr,
+                     const char* text,
+                     Function* func = nullptr) {
+    if (result) {
+      fail("unexpected true: " + std::string(text), curr, func);
+      return false;
+    }
+    return result;
+  }
+
+  template<typename T, typename S>
+  bool shouldBeEqual(
+    S left, S right, T curr, const char* text, Function* func = nullptr) {
+    if (left != right) {
+      std::ostringstream ss;
+      ss << left << " != " << right << ": " << text;
+      fail(ss.str(), curr, func);
+      return false;
+    }
+    return true;
+  }
+
+  template<typename T, typename S>
+  bool shouldBeEqualOrFirstIsUnreachable(
+    S left, S right, T curr, const char* text, Function* func = nullptr) {
+    if (left != Type::unreachable && left != right) {
+      std::ostringstream ss;
+      ss << left << " != " << right << ": " << text;
+      fail(ss.str(), curr, func);
+      return false;
+    }
+    return true;
+  }
+
+  template<typename T, typename S>
+  bool shouldBeUnequal(
+    S left, S right, T curr, const char* text, Function* func = nullptr) {
+    if (left == right) {
+      std::ostringstream ss;
+      ss << left << " == " << right << ": " << text;
+      fail(ss.str(), curr, func);
+      return false;
+    }
+    return true;
+  }
+
+  void shouldBeIntOrUnreachable(Type ty,
+                                Expression* curr,
+                                const char* text,
+                                Function* func = nullptr) {
+    switch (ty.getBasic()) {
+      case Type::i32:
+      case Type::i64:
+      case Type::unreachable: {
+        break;
+      }
+      default:
+        fail(text, curr, func);
+    }
+  }
+
+  // Type 'left' should be a subtype of 'right'.
+  bool shouldBeSubType(Type left,
+                       Type right,
+                       Expression* curr,
+                       const char* text,
+                       Function* func = nullptr) {
+    if (Type::isSubType(left, right)) {
+      return true;
+    }
+    fail(text, curr, func);
+    return false;
+  }
+
+  // Type 'left' should be a subtype of 'right', or unreachable.
+  bool shouldBeSubTypeOrFirstIsUnreachable(Type left,
+                                           Type right,
+                                           Expression* curr,
+                                           const char* text,
+                                           Function* func = nullptr) {
+    if (left == Type::unreachable) {
+      return true;
+    }
+    return shouldBeSubType(left, right, curr, text, func);
+  }
+};
+
+struct FunctionValidator : public WalkerPass<PostWalker<FunctionValidator>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new FunctionValidator(&info); }
+
+  bool modifiesBinaryenIR() override { return false; }
+
+  ValidationInfo& info;
+
+  FunctionValidator(ValidationInfo* info) : info(*info) {}
+
+  struct BreakInfo {
+    enum { UnsetArity = Index(-1), PoisonArity = Index(-2) };
+
+    Type type;
+    Index arity;
+    BreakInfo() : arity(UnsetArity) {}
+    BreakInfo(Type type, Index arity) : type(type), arity(arity) {}
+
+    bool hasBeenSet() {
+      // Compare to the impossible value.
+      return arity != UnsetArity;
+    }
+  };
+
+  std::unordered_map<Name, BreakInfo> breakInfos;
+
+  std::set<Type> returnTypes; // types used in returns
+
+  // Binaryen IR requires that label names must be unique - IR generators must
+  // ensure that
+  std::unordered_set<Name> labelNames;
+
+  void noteLabelName(Name name);
+
+public:
+  // visitors
+
+  void validatePoppyExpression(Expression* curr);
+
+  static void visitPoppyExpression(FunctionValidator* self,
+                                   Expression** currp) {
+    self->validatePoppyExpression(*currp);
+  }
+
+  static void visitPreBlock(FunctionValidator* self, Expression** currp) {
+    auto* curr = (*currp)->cast<Block>();
+    if (curr->name.is()) {
+      self->breakInfos[curr->name];
+    }
+  }
+
+  void visitBlock(Block* curr);
+  void validateNormalBlockElements(Block* curr);
+  void validatePoppyBlockElements(Block* curr);
+
+  static void visitPreLoop(FunctionValidator* self, Expression** currp) {
+    auto* curr = (*currp)->cast<Loop>();
+    if (curr->name.is()) {
+      self->breakInfos[curr->name];
+    }
+  }
+
+  void visitLoop(Loop* curr);
+  void visitIf(If* curr);
+
+  // override scan to add a pre and a post check task to all nodes
+  static void scan(FunctionValidator* self, Expression** currp) {
+    PostWalker<FunctionValidator>::scan(self, currp);
+
+    auto* curr = *currp;
+    if (curr->is<Block>()) {
+      self->pushTask(visitPreBlock, currp);
+    }
+    if (curr->is<Loop>()) {
+      self->pushTask(visitPreLoop, currp);
+    }
+    if (auto* func = self->getFunction()) {
+      if (func->profile == IRProfile::Poppy) {
+        self->pushTask(visitPoppyExpression, currp);
+      }
+    }
+  }
+
+  void noteBreak(Name name, Expression* value, Expression* curr);
+  void noteBreak(Name name, Type valueType, Expression* curr);
+  void visitBreak(Break* curr);
+  void visitSwitch(Switch* curr);
+  void visitCall(Call* curr);
+  void visitCallIndirect(CallIndirect* curr);
+  void visitConst(Const* 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 visitBinary(Binary* curr);
+  void visitUnary(Unary* 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 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);
+  void visitFunction(Function* curr);
+
+  // helpers
+private:
+  std::ostream& getStream() { return info.getStream(getFunction()); }
+
+  template<typename T>
+  bool shouldBeTrue(bool result, T curr, const char* text) {
+    return info.shouldBeTrue(result, curr, text, getFunction());
+  }
+  template<typename T>
+  bool shouldBeFalse(bool result, T curr, const char* text) {
+    return info.shouldBeFalse(result, curr, text, getFunction());
+  }
+
+  template<typename T, typename S>
+  bool shouldBeEqual(S left, S right, T curr, const char* text) {
+    return info.shouldBeEqual(left, right, curr, text, getFunction());
+  }
+
+  template<typename T, typename S>
+  bool
+  shouldBeEqualOrFirstIsUnreachable(S left, S right, T curr, const char* text) {
+    return info.shouldBeEqualOrFirstIsUnreachable(
+      left, right, curr, text, getFunction());
+  }
+
+  template<typename T, typename S>
+  bool shouldBeUnequal(S left, S right, T curr, const char* text) {
+    return info.shouldBeUnequal(left, right, curr, text, getFunction());
+  }
+
+  void shouldBeIntOrUnreachable(Type ty, Expression* curr, const char* text) {
+    return info.shouldBeIntOrUnreachable(ty, curr, text, getFunction());
+  }
+
+  bool
+  shouldBeSubType(Type left, Type right, Expression* curr, const char* text) {
+    return info.shouldBeSubType(left, right, curr, text, getFunction());
+  }
+
+  bool shouldBeSubTypeOrFirstIsUnreachable(Type left,
+                                           Type right,
+                                           Expression* curr,
+                                           const char* text) {
+    return info.shouldBeSubTypeOrFirstIsUnreachable(
+      left, right, curr, text, getFunction());
+  }
+
+  void validateAlignment(
+    size_t align, Type type, Index bytes, bool isAtomic, Expression* curr);
+  void validateMemBytes(uint8_t bytes, Type type, Expression* curr);
+
+  Type indexType() { return getModule()->memory.indexType; }
+};
+
+void FunctionValidator::noteLabelName(Name name) {
+  if (!name.is()) {
+    return;
+  }
+  bool inserted;
+  std::tie(std::ignore, inserted) = labelNames.insert(name);
+  shouldBeTrue(
+    inserted,
+    name,
+    "names in Binaryen IR must be unique - IR generators must ensure that");
+}
+
+void FunctionValidator::validatePoppyExpression(Expression* curr) {
+  if (curr->type == Type::unreachable) {
+    shouldBeTrue(StackUtils::mayBeUnreachable(curr),
+                 curr,
+                 "Only control flow structures and unreachable polymorphic"
+                 " instructions may be unreachable in Poppy IR");
+  }
+  if (Properties::isControlFlowStructure(curr)) {
+    // Check that control flow children (except If conditions) are blocks
+    if (auto* if_ = curr->dynCast<If>()) {
+      shouldBeTrue(
+        if_->condition->is<Pop>(), curr, "Expected condition to be a Pop");
+      shouldBeTrue(if_->ifTrue->is<Block>(),
+                   curr,
+                   "Expected control flow child to be a block");
+      shouldBeTrue(!if_->ifFalse || if_->ifFalse->is<Block>(),
+                   curr,
+                   "Expected control flow child to be a block");
+    } else if (!curr->is<Block>()) {
+      for (auto* child : ChildIterator(curr)) {
+        shouldBeTrue(child->is<Block>(),
+                     curr,
+                     "Expected control flow child to be a block");
+      }
+    }
+  } else {
+    // Check that all children are Pops
+    for (auto* child : ChildIterator(curr)) {
+      shouldBeTrue(child->is<Pop>(), curr, "Unexpected non-Pop child");
+    }
+  }
+}
+
+void FunctionValidator::visitBlock(Block* curr) {
+  if (!getModule()->features.hasMultivalue()) {
+    shouldBeTrue(!curr->type.isTuple(),
+                 curr,
+                 "Multivalue block type (multivalue is not enabled)");
+  }
+  // if we are break'ed to, then the value must be right for us
+  if (curr->name.is()) {
+    noteLabelName(curr->name);
+    auto iter = breakInfos.find(curr->name);
+    assert(iter != breakInfos.end()); // we set it ourselves
+    auto& info = iter->second;
+    if (info.hasBeenSet()) {
+      if (curr->type.isConcrete()) {
+        shouldBeTrue(info.arity != 0,
+                     curr,
+                     "break arities must be > 0 if block has a value");
+      } else {
+        shouldBeTrue(info.arity == 0,
+                     curr,
+                     "break arities must be 0 if block has no value");
+      }
+      // none or unreachable means a poison value that we should ignore - if
+      // consumed, it will error
+      if (info.type.isConcrete() && curr->type.isConcrete()) {
+        shouldBeSubType(
+          info.type,
+          curr->type,
+          curr,
+          "block+breaks must have right type if breaks return a value");
+      }
+      if (curr->type.isConcrete() && info.arity &&
+          info.type != Type::unreachable) {
+        shouldBeSubType(
+          info.type,
+          curr->type,
+          curr,
+          "block+breaks must have right type if breaks have arity");
+      }
+      shouldBeTrue(
+        info.arity != BreakInfo::PoisonArity, curr, "break arities must match");
+      if (curr->list.size() > 0) {
+        auto last = curr->list.back()->type;
+        if (last == Type::none) {
+          shouldBeTrue(info.arity == Index(0),
+                       curr,
+                       "if block ends with a none, breaks cannot send a value "
+                       "of any type");
+        }
+      }
+    }
+    breakInfos.erase(iter);
+  }
+  switch (getFunction()->profile) {
+    case IRProfile::Normal:
+      validateNormalBlockElements(curr);
+      break;
+    case IRProfile::Poppy:
+      validatePoppyBlockElements(curr);
+      break;
+  }
+}
+
+void FunctionValidator::validateNormalBlockElements(Block* curr) {
+  if (curr->list.size() > 1) {
+    for (Index i = 0; i < curr->list.size() - 1; i++) {
+      if (!shouldBeTrue(
+            !curr->list[i]->type.isConcrete(),
+            curr,
+            "non-final block elements returning a value must be drop()ed "
+            "(binaryen's autodrop option might help you)") &&
+          !info.quiet) {
+        getStream() << "(on index " << i << ":\n"
+                    << curr->list[i] << "\n), type: " << curr->list[i]->type
+                    << "\n";
+      }
+    }
+  }
+  if (curr->list.size() > 0) {
+    auto backType = curr->list.back()->type;
+    if (!curr->type.isConcrete()) {
+      shouldBeFalse(backType.isConcrete(),
+                    curr,
+                    "if block is not returning a value, final element should "
+                    "not flow out a value");
+    } else {
+      if (backType.isConcrete()) {
+        shouldBeSubType(
+          backType,
+          curr->type,
+          curr,
+          "block with value and last element with value must match types");
+      } else {
+        shouldBeUnequal(
+          backType,
+          Type(Type::none),
+          curr,
+          "block with value must not have last element that is none");
+      }
+    }
+  }
+  if (curr->type.isConcrete()) {
+    shouldBeTrue(
+      curr->list.size() > 0, curr, "block with a value must not be empty");
+  }
+}
+
+void FunctionValidator::validatePoppyBlockElements(Block* curr) {
+  StackSignature blockSig;
+  for (size_t i = 0; i < curr->list.size(); ++i) {
+    Expression* expr = curr->list[i];
+    if (!shouldBeTrue(
+          !expr->is<Pop>(), expr, "Unexpected top-level pop in block")) {
+      return;
+    }
+    StackSignature sig(expr);
+    if (!shouldBeTrue(blockSig.composes(sig),
+                      curr,
+                      "block element has incompatible type") &&
+        !info.quiet) {
+      getStream() << "(on index " << i << ":\n"
+                  << expr << "\n), required: " << sig.params << ", available: ";
+      if (blockSig.unreachable) {
+        getStream() << "unreachable, ";
+      }
+      getStream() << blockSig.results << "\n";
+      return;
+    }
+    blockSig += sig;
+  }
+  if (curr->type == Type::unreachable) {
+    shouldBeTrue(blockSig.unreachable,
+                 curr,
+                 "unreachable block should have unreachable element");
+  } else {
+    if (!shouldBeTrue(blockSig.satisfies(Signature(Type::none, curr->type)),
+                      curr,
+                      "block contents should satisfy block type") &&
+        !info.quiet) {
+      getStream() << "contents: " << blockSig.results
+                  << (blockSig.unreachable ? " [unreachable]" : "") << "\n"
+                  << "expected: " << curr->type << "\n";
+    }
+  }
+}
+
+void FunctionValidator::visitLoop(Loop* curr) {
+  if (curr->name.is()) {
+    noteLabelName(curr->name);
+    auto iter = breakInfos.find(curr->name);
+    assert(iter != breakInfos.end()); // we set it ourselves
+    auto& info = iter->second;
+    if (info.hasBeenSet()) {
+      shouldBeEqual(
+        info.arity, Index(0), curr, "breaks to a loop cannot pass a value");
+    }
+    breakInfos.erase(iter);
+  }
+  if (curr->type == Type::none) {
+    shouldBeFalse(curr->body->type.isConcrete(),
+                  curr,
+                  "bad body for a loop that has no value");
+  }
+
+  // When there are multiple instructions within a loop, they are wrapped in a
+  // Block internally, so visitBlock can take care of verification. Here we
+  // check cases when there is only one instruction in a Loop.
+  if (!curr->body->is<Block>()) {
+    if (!curr->type.isConcrete()) {
+      shouldBeFalse(curr->body->type.isConcrete(),
+                    curr,
+                    "if loop is not returning a value, final element should "
+                    "not flow out a value");
+    } else {
+      shouldBeSubTypeOrFirstIsUnreachable(
+        curr->body->type,
+        curr->type,
+        curr,
+        "loop with value and body must match types");
+    }
+  }
+}
+
+void FunctionValidator::visitIf(If* curr) {
+  shouldBeTrue(curr->condition->type == Type::unreachable ||
+                 curr->condition->type == Type::i32,
+               curr,
+               "if condition must be valid");
+  if (!curr->ifFalse) {
+    shouldBeFalse(curr->ifTrue->type.isConcrete(),
+                  curr,
+                  "if without else must not return a value in body");
+    if (curr->condition->type != Type::unreachable) {
+      shouldBeEqual(curr->type,
+                    Type(Type::none),
+                    curr,
+                    "if without else and reachable condition must be none");
+    }
+  } else {
+    if (curr->type != Type::unreachable) {
+      shouldBeSubTypeOrFirstIsUnreachable(
+        curr->ifTrue->type,
+        curr->type,
+        curr,
+        "returning if-else's true must have right type");
+      shouldBeSubTypeOrFirstIsUnreachable(
+        curr->ifFalse->type,
+        curr->type,
+        curr,
+        "returning if-else's false must have right type");
+    } else {
+      if (curr->condition->type != Type::unreachable) {
+        shouldBeEqual(curr->ifTrue->type,
+                      Type(Type::unreachable),
+                      curr,
+                      "unreachable if-else must have unreachable true");
+        shouldBeEqual(curr->ifFalse->type,
+                      Type(Type::unreachable),
+                      curr,
+                      "unreachable if-else must have unreachable false");
+      }
+    }
+    if (curr->ifTrue->type.isConcrete()) {
+      shouldBeSubType(curr->ifTrue->type,
+                      curr->type,
+                      curr,
+                      "if type must match concrete ifTrue");
+    }
+    if (curr->ifFalse->type.isConcrete()) {
+      shouldBeSubType(curr->ifFalse->type,
+                      curr->type,
+                      curr,
+                      "if type must match concrete ifFalse");
+    }
+  }
+}
+
+void FunctionValidator::noteBreak(Name name,
+                                  Expression* value,
+                                  Expression* curr) {
+  if (value) {
+    shouldBeUnequal(
+      value->type, Type(Type::none), curr, "breaks must have a valid value");
+  }
+  noteBreak(name, value ? value->type : Type::none, curr);
+}
+
+void FunctionValidator::noteBreak(Name name, Type valueType, Expression* curr) {
+  Index arity = 0;
+  if (valueType != Type::none) {
+    arity = 1;
+  }
+  auto iter = breakInfos.find(name);
+  if (!shouldBeTrue(
+        iter != breakInfos.end(), curr, "all break targets must be valid")) {
+    return;
+  }
+  auto& info = iter->second;
+  if (!info.hasBeenSet()) {
+    info = BreakInfo(valueType, arity);
+  } else {
+    info.type = Type::getLeastUpperBound(info.type, valueType);
+    if (arity != info.arity) {
+      info.arity = BreakInfo::PoisonArity;
+    }
+  }
+}
+void FunctionValidator::visitBreak(Break* curr) {
+  noteBreak(curr->name, curr->value, curr);
+  if (curr->value) {
+    shouldBeTrue(curr->value->type != Type::none,
+                 curr,
+                 "break value must not have none type");
+  }
+  if (curr->condition) {
+    shouldBeTrue(curr->condition->type == Type::unreachable ||
+                   curr->condition->type == Type::i32,
+                 curr,
+                 "break condition must be i32");
+  }
+}
+
+void FunctionValidator::visitSwitch(Switch* curr) {
+  for (auto& target : curr->targets) {
+    noteBreak(target, curr->value, curr);
+  }
+  noteBreak(curr->default_, curr->value, curr);
+  shouldBeTrue(curr->condition->type == Type::unreachable ||
+                 curr->condition->type == Type::i32,
+               curr,
+               "br_table condition must be i32");
+}
+
+void FunctionValidator::visitCall(Call* curr) {
+  shouldBeTrue(!curr->isReturn || getModule()->features.hasTailCall(),
+               curr,
+               "return_call requires tail calls to be enabled");
+  if (!info.validateGlobally) {
+    return;
+  }
+  auto* target = getModule()->getFunctionOrNull(curr->target);
+  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");
+    }
+  }
+}
+
+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;
+  }
+  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");
+    }
+  }
+}
+
+void FunctionValidator::visitConst(Const* curr) {
+  shouldBeTrue(curr->type.getFeatures() <= getModule()->features,
+               curr,
+               "all used features should be allowed");
+}
+
+void FunctionValidator::visitLocalGet(LocalGet* curr) {
+  shouldBeTrue(curr->type.isConcrete(),
+               curr,
+               "local.get must have a valid type - check what you provided "
+               "when you constructed the node");
+  if (shouldBeTrue(curr->index < getFunction()->getNumLocals(),
+                   curr,
+                   "local.get index must be small enough")) {
+    shouldBeTrue(curr->type == getFunction()->getLocalType(curr->index),
+                 curr,
+                 "local.get must have proper type");
+  }
+}
+
+void FunctionValidator::visitLocalSet(LocalSet* curr) {
+  if (shouldBeTrue(curr->index < getFunction()->getNumLocals(),
+                   curr,
+                   "local.set index must be small enough")) {
+    if (curr->value->type != Type::unreachable) {
+      if (curr->type != Type::none) { // tee is ok anyhow
+        shouldBeEqual(getFunction()->getLocalType(curr->index),
+                      curr->type,
+                      curr,
+                      "local.set type must be correct");
+      }
+      shouldBeSubType(curr->value->type,
+                      getFunction()->getLocalType(curr->index),
+                      curr,
+                      "local.set's value type must be correct");
+    }
+  }
+}
+
+void FunctionValidator::visitGlobalGet(GlobalGet* curr) {
+  if (!info.validateGlobally) {
+    return;
+  }
+  shouldBeTrue(getModule()->getGlobalOrNull(curr->name),
+               curr,
+               "global.get name must be valid");
+}
+
+void FunctionValidator::visitGlobalSet(GlobalSet* curr) {
+  if (!info.validateGlobally) {
+    return;
+  }
+  auto* global = getModule()->getGlobalOrNull(curr->name);
+  if (shouldBeTrue(global,
+                   curr,
+                   "global.set name must be valid (and not an import; imports "
+                   "can't be modified)")) {
+    shouldBeTrue(global->mutable_, curr, "global.set global must be mutable");
+    shouldBeSubTypeOrFirstIsUnreachable(
+      curr->value->type,
+      global->type,
+      curr,
+      "global.set value must have right type");
+  }
+}
+
+void FunctionValidator::visitLoad(Load* curr) {
+  shouldBeTrue(
+    getModule()->memory.exists, curr, "Memory operations require a memory");
+  if (curr->isAtomic) {
+    shouldBeTrue(getModule()->features.hasAtomics(),
+                 curr,
+                 "Atomic operation (atomics are disabled)");
+    shouldBeTrue(curr->type == Type::i32 || curr->type == Type::i64 ||
+                   curr->type == Type::unreachable,
+                 curr,
+                 "Atomic load should be i32 or i64");
+  }
+  if (curr->type == Type::v128) {
+    shouldBeTrue(getModule()->features.hasSIMD(),
+                 curr,
+                 "SIMD operation (SIMD is disabled)");
+  }
+  validateMemBytes(curr->bytes, curr->type, curr);
+  validateAlignment(curr->align, curr->type, curr->bytes, curr->isAtomic, curr);
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->ptr->type,
+    indexType(),
+    curr,
+    "load pointer type must match memory index type");
+  if (curr->isAtomic) {
+    shouldBeFalse(curr->signed_, curr, "atomic loads must be unsigned");
+    shouldBeIntOrUnreachable(
+      curr->type, curr, "atomic loads must be of integers");
+  }
+}
+
+void FunctionValidator::visitStore(Store* curr) {
+  shouldBeTrue(
+    getModule()->memory.exists, curr, "Memory operations require a memory");
+  if (curr->isAtomic) {
+    shouldBeTrue(getModule()->features.hasAtomics(),
+                 curr,
+                 "Atomic operation (atomics are disabled)");
+    shouldBeTrue(curr->valueType == Type::i32 || curr->valueType == Type::i64 ||
+                   curr->valueType == Type::unreachable,
+                 curr,
+                 "Atomic store should be i32 or i64");
+  }
+  if (curr->valueType == Type::v128) {
+    shouldBeTrue(getModule()->features.hasSIMD(),
+                 curr,
+                 "SIMD operation (SIMD is disabled)");
+  }
+  validateMemBytes(curr->bytes, curr->valueType, curr);
+  validateAlignment(
+    curr->align, curr->valueType, curr->bytes, curr->isAtomic, curr);
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->ptr->type,
+    indexType(),
+    curr,
+    "store pointer must match memory index type");
+  shouldBeUnequal(curr->value->type,
+                  Type(Type::none),
+                  curr,
+                  "store value type must not be none");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->value->type, curr->valueType, curr, "store value type must match");
+  if (curr->isAtomic) {
+    shouldBeIntOrUnreachable(
+      curr->valueType, curr, "atomic stores must be of integers");
+  }
+}
+
+void FunctionValidator::visitAtomicRMW(AtomicRMW* curr) {
+  shouldBeTrue(
+    getModule()->memory.exists, curr, "Memory operations require a memory");
+  shouldBeTrue(getModule()->features.hasAtomics(),
+               curr,
+               "Atomic operation (atomics are disabled)");
+  validateMemBytes(curr->bytes, curr->type, curr);
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->ptr->type,
+    indexType(),
+    curr,
+    "AtomicRMW pointer type must match memory index type");
+  shouldBeEqualOrFirstIsUnreachable(curr->type,
+                                    curr->value->type,
+                                    curr,
+                                    "AtomicRMW result type must match operand");
+  shouldBeIntOrUnreachable(
+    curr->type, curr, "Atomic operations are only valid on int types");
+}
+
+void FunctionValidator::visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+  shouldBeTrue(
+    getModule()->memory.exists, curr, "Memory operations require a memory");
+  shouldBeTrue(getModule()->features.hasAtomics(),
+               curr,
+               "Atomic operation (atomics are disabled)");
+  validateMemBytes(curr->bytes, curr->type, curr);
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->ptr->type,
+    indexType(),
+    curr,
+    "cmpxchg pointer must match memory index type");
+  if (curr->expected->type != Type::unreachable &&
+      curr->replacement->type != Type::unreachable) {
+    shouldBeEqual(curr->expected->type,
+                  curr->replacement->type,
+                  curr,
+                  "cmpxchg operand types must match");
+  }
+  shouldBeEqualOrFirstIsUnreachable(curr->type,
+                                    curr->expected->type,
+                                    curr,
+                                    "Cmpxchg result type must match expected");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->type,
+    curr->replacement->type,
+    curr,
+    "Cmpxchg result type must match replacement");
+  shouldBeIntOrUnreachable(curr->expected->type,
+                           curr,
+                           "Atomic operations are only valid on int types");
+}
+
+void FunctionValidator::visitAtomicWait(AtomicWait* curr) {
+  shouldBeTrue(
+    getModule()->memory.exists, curr, "Memory operations require a memory");
+  shouldBeTrue(getModule()->features.hasAtomics(),
+               curr,
+               "Atomic operation (atomics are disabled)");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->type, Type(Type::i32), curr, "AtomicWait must have type i32");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->ptr->type,
+    indexType(),
+    curr,
+    "AtomicWait pointer must match memory index type");
+  shouldBeIntOrUnreachable(
+    curr->expected->type, curr, "AtomicWait expected type must be int");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->expected->type,
+    curr->expectedType,
+    curr,
+    "AtomicWait expected type must match operand");
+  shouldBeEqualOrFirstIsUnreachable(curr->timeout->type,
+                                    Type(Type::i64),
+                                    curr,
+                                    "AtomicWait timeout type must be i64");
+}
+
+void FunctionValidator::visitAtomicNotify(AtomicNotify* curr) {
+  shouldBeTrue(
+    getModule()->memory.exists, curr, "Memory operations require a memory");
+  shouldBeTrue(getModule()->features.hasAtomics(),
+               curr,
+               "Atomic operation (atomics are disabled)");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->type, Type(Type::i32), curr, "AtomicNotify must have type i32");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->ptr->type,
+    indexType(),
+    curr,
+    "AtomicNotify pointer must match memory index type");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->notifyCount->type,
+    Type(Type::i32),
+    curr,
+    "AtomicNotify notifyCount type must be i32");
+}
+
+void FunctionValidator::visitAtomicFence(AtomicFence* curr) {
+  shouldBeTrue(
+    getModule()->memory.exists, curr, "Memory operations require a memory");
+  shouldBeTrue(getModule()->features.hasAtomics(),
+               curr,
+               "Atomic operation (atomics are disabled)");
+  shouldBeTrue(curr->order == 0,
+               curr,
+               "Currently only sequentially consistent atomics are supported, "
+               "so AtomicFence's order should be 0");
+}
+
+void FunctionValidator::visitSIMDExtract(SIMDExtract* curr) {
+  shouldBeTrue(
+    getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
+  shouldBeEqualOrFirstIsUnreachable(curr->vec->type,
+                                    Type(Type::v128),
+                                    curr,
+                                    "extract_lane must operate on a v128");
+  Type lane_t = Type::none;
+  size_t lanes = 0;
+  switch (curr->op) {
+    case ExtractLaneSVecI8x16:
+    case ExtractLaneUVecI8x16:
+      lane_t = Type::i32;
+      lanes = 16;
+      break;
+    case ExtractLaneSVecI16x8:
+    case ExtractLaneUVecI16x8:
+      lane_t = Type::i32;
+      lanes = 8;
+      break;
+    case ExtractLaneVecI32x4:
+      lane_t = Type::i32;
+      lanes = 4;
+      break;
+    case ExtractLaneVecI64x2:
+      lane_t = Type::i64;
+      lanes = 2;
+      break;
+    case ExtractLaneVecF32x4:
+      lane_t = Type::f32;
+      lanes = 4;
+      break;
+    case ExtractLaneVecF64x2:
+      lane_t = Type::f64;
+      lanes = 2;
+      break;
+  }
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->type,
+    lane_t,
+    curr,
+    "extract_lane must have same type as vector lane");
+  shouldBeTrue(curr->index < lanes, curr, "invalid lane index");
+}
+
+void FunctionValidator::visitSIMDReplace(SIMDReplace* curr) {
+  shouldBeTrue(
+    getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->type, Type(Type::v128), curr, "replace_lane must have type v128");
+  shouldBeEqualOrFirstIsUnreachable(curr->vec->type,
+                                    Type(Type::v128),
+                                    curr,
+                                    "replace_lane must operate on a v128");
+  Type lane_t = Type::none;
+  size_t lanes = 0;
+  switch (curr->op) {
+    case ReplaceLaneVecI8x16:
+      lane_t = Type::i32;
+      lanes = 16;
+      break;
+    case ReplaceLaneVecI16x8:
+      lane_t = Type::i32;
+      lanes = 8;
+      break;
+    case ReplaceLaneVecI32x4:
+      lane_t = Type::i32;
+      lanes = 4;
+      break;
+    case ReplaceLaneVecI64x2:
+      lane_t = Type::i64;
+      lanes = 2;
+      break;
+    case ReplaceLaneVecF32x4:
+      lane_t = Type::f32;
+      lanes = 4;
+      break;
+    case ReplaceLaneVecF64x2:
+      lane_t = Type::f64;
+      lanes = 2;
+      break;
+  }
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->value->type, lane_t, curr, "unexpected value type");
+  shouldBeTrue(curr->index < lanes, curr, "invalid lane index");
+}
+
+void FunctionValidator::visitSIMDShuffle(SIMDShuffle* curr) {
+  shouldBeTrue(
+    getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->type, Type(Type::v128), curr, "v128.shuffle must have type v128");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->left->type, Type(Type::v128), curr, "expected operand of type v128");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->right->type, Type(Type::v128), curr, "expected operand of type v128");
+  for (uint8_t index : curr->mask) {
+    shouldBeTrue(index < 32, curr, "Invalid lane index in mask");
+  }
+}
+
+void FunctionValidator::visitSIMDTernary(SIMDTernary* curr) {
+  shouldBeTrue(
+    getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->type, Type(Type::v128), curr, "SIMD ternary must have type v128");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->a->type, Type(Type::v128), curr, "expected operand of type v128");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->b->type, Type(Type::v128), curr, "expected operand of type v128");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->c->type, Type(Type::v128), curr, "expected operand of type v128");
+}
+
+void FunctionValidator::visitSIMDShift(SIMDShift* curr) {
+  shouldBeTrue(
+    getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->type, Type(Type::v128), curr, "vector shift must have type v128");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->vec->type, Type(Type::v128), curr, "expected operand of type v128");
+  shouldBeEqualOrFirstIsUnreachable(curr->shift->type,
+                                    Type(Type::i32),
+                                    curr,
+                                    "expected shift amount to have type i32");
+}
+
+void FunctionValidator::visitSIMDLoad(SIMDLoad* curr) {
+  shouldBeTrue(
+    getModule()->memory.exists, curr, "Memory operations require a memory");
+  shouldBeTrue(
+    getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->type, Type(Type::v128), curr, "load_splat must have type v128");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->ptr->type,
+    indexType(),
+    curr,
+    "load_splat address must match memory index type");
+  Type memAlignType = Type::none;
+  switch (curr->op) {
+    case LoadSplatVec8x16:
+    case LoadSplatVec16x8:
+    case LoadSplatVec32x4:
+    case Load32Zero:
+      memAlignType = Type::i32;
+      break;
+    case LoadSplatVec64x2:
+    case LoadExtSVec8x8ToVecI16x8:
+    case LoadExtUVec8x8ToVecI16x8:
+    case LoadExtSVec16x4ToVecI32x4:
+    case LoadExtUVec16x4ToVecI32x4:
+    case LoadExtSVec32x2ToVecI64x2:
+    case LoadExtUVec32x2ToVecI64x2:
+    case Load64Zero:
+      memAlignType = Type::i64;
+      break;
+  }
+  Index bytes = curr->getMemBytes();
+  validateAlignment(curr->align, memAlignType, bytes, /*isAtomic=*/false, curr);
+}
+
+void FunctionValidator::visitMemoryInit(MemoryInit* curr) {
+  shouldBeTrue(getModule()->features.hasBulkMemory(),
+               curr,
+               "Bulk memory operation (bulk memory is disabled)");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->type, Type(Type::none), curr, "memory.init must have type none");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->dest->type,
+    indexType(),
+    curr,
+    "memory.init dest must match memory index type");
+  shouldBeEqualOrFirstIsUnreachable(curr->offset->type,
+                                    Type(Type::i32),
+                                    curr,
+                                    "memory.init offset must be an i32");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->size->type, Type(Type::i32), curr, "memory.init size must be an i32");
+  if (!shouldBeTrue(getModule()->memory.exists,
+                    curr,
+                    "Memory operations require a memory")) {
+    return;
+  }
+  shouldBeTrue(curr->segment < getModule()->memory.segments.size(),
+               curr,
+               "memory.init segment index out of bounds");
+}
+
+void FunctionValidator::visitDataDrop(DataDrop* curr) {
+  shouldBeTrue(getModule()->features.hasBulkMemory(),
+               curr,
+               "Bulk memory operation (bulk memory is disabled)");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->type, Type(Type::none), curr, "data.drop must have type none");
+  if (!shouldBeTrue(getModule()->memory.exists,
+                    curr,
+                    "Memory operations require a memory")) {
+    return;
+  }
+  shouldBeTrue(curr->segment < getModule()->memory.segments.size(),
+               curr,
+               "data.drop segment index out of bounds");
+}
+
+void FunctionValidator::visitMemoryCopy(MemoryCopy* curr) {
+  shouldBeTrue(getModule()->features.hasBulkMemory(),
+               curr,
+               "Bulk memory operation (bulk memory is disabled)");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->type, Type(Type::none), curr, "memory.copy must have type none");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->dest->type,
+    indexType(),
+    curr,
+    "memory.copy dest must match memory index type");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->source->type,
+    indexType(),
+    curr,
+    "memory.copy source must match memory index type");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->size->type,
+    indexType(),
+    curr,
+    "memory.copy size must match memory index type");
+  shouldBeTrue(
+    getModule()->memory.exists, curr, "Memory operations require a memory");
+}
+
+void FunctionValidator::visitMemoryFill(MemoryFill* curr) {
+  shouldBeTrue(getModule()->features.hasBulkMemory(),
+               curr,
+               "Bulk memory operation (bulk memory is disabled)");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->type, Type(Type::none), curr, "memory.fill must have type none");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->dest->type,
+    indexType(),
+    curr,
+    "memory.fill dest must match memory index type");
+  shouldBeEqualOrFirstIsUnreachable(curr->value->type,
+                                    Type(Type::i32),
+                                    curr,
+                                    "memory.fill value must be an i32");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->size->type,
+    indexType(),
+    curr,
+    "memory.fill size must match memory index type");
+  shouldBeTrue(
+    getModule()->memory.exists, curr, "Memory operations require a memory");
+}
+
+void FunctionValidator::validateMemBytes(uint8_t bytes,
+                                         Type type,
+                                         Expression* curr) {
+  switch (type.getBasic()) {
+    case Type::i32:
+      shouldBeTrue(bytes == 1 || bytes == 2 || bytes == 4,
+                   curr,
+                   "expected i32 operation to touch 1, 2, or 4 bytes");
+      break;
+    case Type::i64:
+      shouldBeTrue(bytes == 1 || bytes == 2 || bytes == 4 || bytes == 8,
+                   curr,
+                   "expected i64 operation to touch 1, 2, 4, or 8 bytes");
+      break;
+    case Type::f32:
+      shouldBeEqual(
+        bytes, uint8_t(4), curr, "expected f32 operation to touch 4 bytes");
+      break;
+    case Type::f64:
+      shouldBeEqual(
+        bytes, uint8_t(8), curr, "expected f64 operation to touch 8 bytes");
+      break;
+    case Type::v128:
+      shouldBeEqual(
+        bytes, uint8_t(16), curr, "expected v128 operation to touch 16 bytes");
+      break;
+    case Type::unreachable:
+      break;
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+    case Type::none:
+      WASM_UNREACHABLE("unexpected type");
+  }
+}
+
+void FunctionValidator::visitBinary(Binary* curr) {
+  if (curr->left->type != Type::unreachable &&
+      curr->right->type != Type::unreachable) {
+    shouldBeEqual(curr->left->type,
+                  curr->right->type,
+                  curr,
+                  "binary child types must be equal");
+  }
+  switch (curr->op) {
+    case AddInt32:
+    case SubInt32:
+    case MulInt32:
+    case DivSInt32:
+    case DivUInt32:
+    case RemSInt32:
+    case RemUInt32:
+    case AndInt32:
+    case OrInt32:
+    case XorInt32:
+    case ShlInt32:
+    case ShrUInt32:
+    case ShrSInt32:
+    case RotLInt32:
+    case RotRInt32:
+    case EqInt32:
+    case NeInt32:
+    case LtSInt32:
+    case LtUInt32:
+    case LeSInt32:
+    case LeUInt32:
+    case GtSInt32:
+    case GtUInt32:
+    case GeSInt32:
+    case GeUInt32: {
+      shouldBeEqualOrFirstIsUnreachable(
+        curr->left->type, Type(Type::i32), curr, "i32 op");
+      break;
+    }
+    case AddInt64:
+    case SubInt64:
+    case MulInt64:
+    case DivSInt64:
+    case DivUInt64:
+    case RemSInt64:
+    case RemUInt64:
+    case AndInt64:
+    case OrInt64:
+    case XorInt64:
+    case ShlInt64:
+    case ShrUInt64:
+    case ShrSInt64:
+    case RotLInt64:
+    case RotRInt64:
+    case EqInt64:
+    case NeInt64:
+    case LtSInt64:
+    case LtUInt64:
+    case LeSInt64:
+    case LeUInt64:
+    case GtSInt64:
+    case GtUInt64:
+    case GeSInt64:
+    case GeUInt64: {
+      shouldBeEqualOrFirstIsUnreachable(
+        curr->left->type, Type(Type::i64), curr, "i64 op");
+      break;
+    }
+    case AddFloat32:
+    case SubFloat32:
+    case MulFloat32:
+    case DivFloat32:
+    case CopySignFloat32:
+    case MinFloat32:
+    case MaxFloat32:
+    case EqFloat32:
+    case NeFloat32:
+    case LtFloat32:
+    case LeFloat32:
+    case GtFloat32:
+    case GeFloat32: {
+      shouldBeEqualOrFirstIsUnreachable(
+        curr->left->type, Type(Type::f32), curr, "f32 op");
+      break;
+    }
+    case AddFloat64:
+    case SubFloat64:
+    case MulFloat64:
+    case DivFloat64:
+    case CopySignFloat64:
+    case MinFloat64:
+    case MaxFloat64:
+    case EqFloat64:
+    case NeFloat64:
+    case LtFloat64:
+    case LeFloat64:
+    case GtFloat64:
+    case GeFloat64: {
+      shouldBeEqualOrFirstIsUnreachable(
+        curr->left->type, Type(Type::f64), curr, "f64 op");
+      break;
+    }
+    case EqVecI8x16:
+    case NeVecI8x16:
+    case LtSVecI8x16:
+    case LtUVecI8x16:
+    case LeSVecI8x16:
+    case LeUVecI8x16:
+    case GtSVecI8x16:
+    case GtUVecI8x16:
+    case GeSVecI8x16:
+    case GeUVecI8x16:
+    case EqVecI16x8:
+    case NeVecI16x8:
+    case LtSVecI16x8:
+    case LtUVecI16x8:
+    case LeSVecI16x8:
+    case LeUVecI16x8:
+    case GtSVecI16x8:
+    case GtUVecI16x8:
+    case GeSVecI16x8:
+    case GeUVecI16x8:
+    case EqVecI32x4:
+    case NeVecI32x4:
+    case LtSVecI32x4:
+    case LtUVecI32x4:
+    case LeSVecI32x4:
+    case LeUVecI32x4:
+    case GtSVecI32x4:
+    case GtUVecI32x4:
+    case GeSVecI32x4:
+    case GeUVecI32x4:
+    case EqVecF32x4:
+    case NeVecF32x4:
+    case LtVecF32x4:
+    case LeVecF32x4:
+    case GtVecF32x4:
+    case GeVecF32x4:
+    case EqVecF64x2:
+    case NeVecF64x2:
+    case LtVecF64x2:
+    case LeVecF64x2:
+    case GtVecF64x2:
+    case GeVecF64x2:
+    case AndVec128:
+    case OrVec128:
+    case XorVec128:
+    case AndNotVec128:
+    case AddVecI8x16:
+    case AddSatSVecI8x16:
+    case AddSatUVecI8x16:
+    case SubVecI8x16:
+    case SubSatSVecI8x16:
+    case SubSatUVecI8x16:
+    case MulVecI8x16:
+    case MinSVecI8x16:
+    case MinUVecI8x16:
+    case MaxSVecI8x16:
+    case MaxUVecI8x16:
+    case AvgrUVecI8x16:
+    case AddVecI16x8:
+    case AddSatSVecI16x8:
+    case AddSatUVecI16x8:
+    case SubVecI16x8:
+    case SubSatSVecI16x8:
+    case SubSatUVecI16x8:
+    case MulVecI16x8:
+    case MinSVecI16x8:
+    case MinUVecI16x8:
+    case MaxSVecI16x8:
+    case MaxUVecI16x8:
+    case AvgrUVecI16x8:
+    case AddVecI32x4:
+    case SubVecI32x4:
+    case MulVecI32x4:
+    case MinSVecI32x4:
+    case MinUVecI32x4:
+    case MaxSVecI32x4:
+    case MaxUVecI32x4:
+    case DotSVecI16x8ToVecI32x4:
+    case AddVecI64x2:
+    case SubVecI64x2:
+    case MulVecI64x2:
+    case AddVecF32x4:
+    case SubVecF32x4:
+    case MulVecF32x4:
+    case DivVecF32x4:
+    case MinVecF32x4:
+    case MaxVecF32x4:
+    case PMinVecF32x4:
+    case PMaxVecF32x4:
+    case AddVecF64x2:
+    case SubVecF64x2:
+    case MulVecF64x2:
+    case DivVecF64x2:
+    case MinVecF64x2:
+    case MaxVecF64x2:
+    case PMinVecF64x2:
+    case PMaxVecF64x2:
+    case NarrowSVecI16x8ToVecI8x16:
+    case NarrowUVecI16x8ToVecI8x16:
+    case NarrowSVecI32x4ToVecI16x8:
+    case NarrowUVecI32x4ToVecI16x8:
+    case SwizzleVec8x16: {
+      shouldBeEqualOrFirstIsUnreachable(
+        curr->left->type, Type(Type::v128), curr, "v128 op");
+      shouldBeEqualOrFirstIsUnreachable(
+        curr->right->type, Type(Type::v128), curr, "v128 op");
+      break;
+    }
+    case InvalidBinary:
+      WASM_UNREACHABLE("invliad binary op");
+  }
+  shouldBeTrue(Features::get(curr->op) <= getModule()->features,
+               curr,
+               "all used features should be allowed");
+}
+
+void FunctionValidator::visitUnary(Unary* curr) {
+  shouldBeUnequal(curr->value->type,
+                  Type(Type::none),
+                  curr,
+                  "unaries must not receive a none as their input");
+  if (curr->value->type == Type::unreachable) {
+    return; // nothing to check
+  }
+  switch (curr->op) {
+    case ClzInt32:
+    case CtzInt32:
+    case PopcntInt32: {
+      shouldBeEqual(curr->value->type,
+                    Type(Type::i32),
+                    curr,
+                    "i32 unary value type must be correct");
+      break;
+    }
+    case ClzInt64:
+    case CtzInt64:
+    case PopcntInt64: {
+      shouldBeEqual(curr->value->type,
+                    Type(Type::i64),
+                    curr,
+                    "i64 unary value type must be correct");
+      break;
+    }
+    case NegFloat32:
+    case AbsFloat32:
+    case CeilFloat32:
+    case FloorFloat32:
+    case TruncFloat32:
+    case NearestFloat32:
+    case SqrtFloat32: {
+      shouldBeEqual(curr->value->type,
+                    Type(Type::f32),
+                    curr,
+                    "f32 unary value type must be correct");
+      break;
+    }
+    case NegFloat64:
+    case AbsFloat64:
+    case CeilFloat64:
+    case FloorFloat64:
+    case TruncFloat64:
+    case NearestFloat64:
+    case SqrtFloat64: {
+      shouldBeEqual(curr->value->type,
+                    Type(Type::f64),
+                    curr,
+                    "f64 unary value type must be correct");
+      break;
+    }
+    case EqZInt32: {
+      shouldBeTrue(
+        curr->value->type == Type::i32, curr, "i32.eqz input must be i32");
+      break;
+    }
+    case EqZInt64: {
+      shouldBeTrue(curr->value->type == Type(Type::i64),
+                   curr,
+                   "i64.eqz input must be i64");
+      break;
+    }
+    case ExtendSInt32:
+    case ExtendUInt32:
+    case ExtendS8Int32:
+    case ExtendS16Int32: {
+      shouldBeEqual(curr->value->type,
+                    Type(Type::i32),
+                    curr,
+                    "extend type must be correct");
+      break;
+    }
+    case ExtendS8Int64:
+    case ExtendS16Int64:
+    case ExtendS32Int64: {
+      shouldBeEqual(curr->value->type,
+                    Type(Type::i64),
+                    curr,
+                    "extend type must be correct");
+      break;
+    }
+    case WrapInt64: {
+      shouldBeEqual(
+        curr->value->type, Type(Type::i64), curr, "wrap type must be correct");
+      break;
+    }
+    case TruncSFloat32ToInt32:
+    case TruncSFloat32ToInt64:
+    case TruncUFloat32ToInt32:
+    case TruncUFloat32ToInt64: {
+      shouldBeEqual(
+        curr->value->type, Type(Type::f32), curr, "trunc type must be correct");
+      break;
+    }
+    case TruncSatSFloat32ToInt32:
+    case TruncSatSFloat32ToInt64:
+    case TruncSatUFloat32ToInt32:
+    case TruncSatUFloat32ToInt64: {
+      shouldBeEqual(
+        curr->value->type, Type(Type::f32), curr, "trunc type must be correct");
+      break;
+    }
+    case TruncSFloat64ToInt32:
+    case TruncSFloat64ToInt64:
+    case TruncUFloat64ToInt32:
+    case TruncUFloat64ToInt64: {
+      shouldBeEqual(
+        curr->value->type, Type(Type::f64), curr, "trunc type must be correct");
+      break;
+    }
+    case TruncSatSFloat64ToInt32:
+    case TruncSatSFloat64ToInt64:
+    case TruncSatUFloat64ToInt32:
+    case TruncSatUFloat64ToInt64: {
+      shouldBeEqual(
+        curr->value->type, Type(Type::f64), curr, "trunc type must be correct");
+      break;
+    }
+    case ReinterpretFloat32: {
+      shouldBeEqual(curr->value->type,
+                    Type(Type::f32),
+                    curr,
+                    "reinterpret/f32 type must be correct");
+      break;
+    }
+    case ReinterpretFloat64: {
+      shouldBeEqual(curr->value->type,
+                    Type(Type::f64),
+                    curr,
+                    "reinterpret/f64 type must be correct");
+      break;
+    }
+    case ConvertUInt32ToFloat32:
+    case ConvertUInt32ToFloat64:
+    case ConvertSInt32ToFloat32:
+    case ConvertSInt32ToFloat64: {
+      shouldBeEqual(curr->value->type,
+                    Type(Type::i32),
+                    curr,
+                    "convert type must be correct");
+      break;
+    }
+    case ConvertUInt64ToFloat32:
+    case ConvertUInt64ToFloat64:
+    case ConvertSInt64ToFloat32:
+    case ConvertSInt64ToFloat64: {
+      shouldBeEqual(curr->value->type,
+                    Type(Type::i64),
+                    curr,
+                    "convert type must be correct");
+      break;
+    }
+    case PromoteFloat32: {
+      shouldBeEqual(curr->value->type,
+                    Type(Type::f32),
+                    curr,
+                    "promote type must be correct");
+      break;
+    }
+    case DemoteFloat64: {
+      shouldBeEqual(curr->value->type,
+                    Type(Type::f64),
+                    curr,
+                    "demote type must be correct");
+      break;
+    }
+    case ReinterpretInt32: {
+      shouldBeEqual(curr->value->type,
+                    Type(Type::i32),
+                    curr,
+                    "reinterpret/i32 type must be correct");
+      break;
+    }
+    case ReinterpretInt64: {
+      shouldBeEqual(curr->value->type,
+                    Type(Type::i64),
+                    curr,
+                    "reinterpret/i64 type must be correct");
+      break;
+    }
+    case SplatVecI8x16:
+    case SplatVecI16x8:
+    case SplatVecI32x4:
+      shouldBeEqual(
+        curr->type, Type(Type::v128), curr, "expected splat to have v128 type");
+      shouldBeEqual(
+        curr->value->type, Type(Type::i32), curr, "expected i32 splat value");
+      break;
+    case SplatVecI64x2:
+      shouldBeEqual(
+        curr->type, Type(Type::v128), curr, "expected splat to have v128 type");
+      shouldBeEqual(
+        curr->value->type, Type(Type::i64), curr, "expected i64 splat value");
+      break;
+    case SplatVecF32x4:
+      shouldBeEqual(
+        curr->type, Type(Type::v128), curr, "expected splat to have v128 type");
+      shouldBeEqual(
+        curr->value->type, Type(Type::f32), curr, "expected f32 splat value");
+      break;
+    case SplatVecF64x2:
+      shouldBeEqual(
+        curr->type, Type(Type::v128), curr, "expected splat to have v128 type");
+      shouldBeEqual(
+        curr->value->type, Type(Type::f64), curr, "expected f64 splat value");
+      break;
+    case NotVec128:
+    case AbsVecI8x16:
+    case AbsVecI16x8:
+    case AbsVecI32x4:
+    case NegVecI8x16:
+    case NegVecI16x8:
+    case NegVecI32x4:
+    case NegVecI64x2:
+    case AbsVecF32x4:
+    case NegVecF32x4:
+    case SqrtVecF32x4:
+    case CeilVecF32x4:
+    case FloorVecF32x4:
+    case TruncVecF32x4:
+    case NearestVecF32x4:
+    case AbsVecF64x2:
+    case NegVecF64x2:
+    case SqrtVecF64x2:
+    case CeilVecF64x2:
+    case FloorVecF64x2:
+    case TruncVecF64x2:
+    case NearestVecF64x2:
+    case TruncSatSVecF32x4ToVecI32x4:
+    case TruncSatUVecF32x4ToVecI32x4:
+    case TruncSatSVecF64x2ToVecI64x2:
+    case TruncSatUVecF64x2ToVecI64x2:
+    case ConvertSVecI32x4ToVecF32x4:
+    case ConvertUVecI32x4ToVecF32x4:
+    case ConvertSVecI64x2ToVecF64x2:
+    case ConvertUVecI64x2ToVecF64x2:
+    case WidenLowSVecI8x16ToVecI16x8:
+    case WidenHighSVecI8x16ToVecI16x8:
+    case WidenLowUVecI8x16ToVecI16x8:
+    case WidenHighUVecI8x16ToVecI16x8:
+    case WidenLowSVecI16x8ToVecI32x4:
+    case WidenHighSVecI16x8ToVecI32x4:
+    case WidenLowUVecI16x8ToVecI32x4:
+    case WidenHighUVecI16x8ToVecI32x4:
+      shouldBeEqual(curr->type, Type(Type::v128), curr, "expected v128 type");
+      shouldBeEqual(
+        curr->value->type, Type(Type::v128), curr, "expected v128 operand");
+      break;
+    case AnyTrueVecI8x16:
+    case AnyTrueVecI16x8:
+    case AnyTrueVecI32x4:
+    case AnyTrueVecI64x2:
+    case AllTrueVecI8x16:
+    case AllTrueVecI16x8:
+    case AllTrueVecI32x4:
+    case AllTrueVecI64x2:
+    case BitmaskVecI8x16:
+    case BitmaskVecI16x8:
+    case BitmaskVecI32x4:
+      shouldBeEqual(curr->type, Type(Type::i32), curr, "expected i32 type");
+      shouldBeEqual(
+        curr->value->type, Type(Type::v128), curr, "expected v128 operand");
+      break;
+    case InvalidUnary:
+      WASM_UNREACHABLE("invalid unary op");
+  }
+  shouldBeTrue(Features::get(curr->op) <= getModule()->features,
+               curr,
+               "all used features should be allowed");
+}
+
+void FunctionValidator::visitSelect(Select* curr) {
+  shouldBeUnequal(
+    curr->ifFalse->type, Type(Type::none), curr, "select right must be valid");
+  shouldBeUnequal(
+    curr->type, Type(Type::none), curr, "select type must be valid");
+  shouldBeTrue(curr->condition->type == Type::unreachable ||
+                 curr->condition->type == Type::i32,
+               curr,
+               "select condition must be valid");
+  if (curr->ifTrue->type != Type::unreachable) {
+    shouldBeFalse(
+      curr->ifTrue->type.isTuple(), curr, "select value may not be a tuple");
+  }
+  if (curr->ifFalse->type != Type::unreachable) {
+    shouldBeFalse(
+      curr->ifFalse->type.isTuple(), curr, "select value may not be a tuple");
+  }
+  if (curr->type != Type::unreachable) {
+    shouldBeTrue(Type::isSubType(curr->ifTrue->type, curr->type),
+                 curr,
+                 "select's left expression must be subtype of select's type");
+    shouldBeTrue(Type::isSubType(curr->ifFalse->type, curr->type),
+                 curr,
+                 "select's right expression must be subtype of select's type");
+  }
+}
+
+void FunctionValidator::visitDrop(Drop* curr) {
+  shouldBeTrue(curr->value->type.isConcrete() ||
+                 curr->value->type == Type::unreachable,
+               curr,
+               "can only drop a valid value");
+}
+
+void FunctionValidator::visitReturn(Return* curr) {
+  returnTypes.insert(curr->value ? curr->value->type : Type::none);
+}
+
+void FunctionValidator::visitMemorySize(MemorySize* curr) {
+  shouldBeTrue(
+    getModule()->memory.exists, curr, "Memory operations require a memory");
+}
+
+void FunctionValidator::visitMemoryGrow(MemoryGrow* curr) {
+  shouldBeTrue(
+    getModule()->memory.exists, curr, "Memory operations require a memory");
+  shouldBeEqualOrFirstIsUnreachable(curr->delta->type,
+                                    indexType(),
+                                    curr,
+                                    "memory.grow must match memory index type");
+}
+
+void FunctionValidator::visitRefNull(RefNull* curr) {
+  shouldBeTrue(getModule()->features.hasReferenceTypes(),
+               curr,
+               "ref.null requires reference-types to be enabled");
+}
+
+void FunctionValidator::visitRefIsNull(RefIsNull* curr) {
+  shouldBeTrue(getModule()->features.hasReferenceTypes(),
+               curr,
+               "ref.is_null requires reference-types to be enabled");
+  shouldBeTrue(curr->value->type == Type::unreachable ||
+                 curr->value->type.isRef(),
+               curr->value,
+               "ref.is_null's argument should be a reference type");
+}
+
+void FunctionValidator::visitRefFunc(RefFunc* curr) {
+  shouldBeTrue(getModule()->features.hasReferenceTypes(),
+               curr,
+               "ref.func requires reference-types to be enabled");
+  auto* func = getModule()->getFunctionOrNull(curr->func);
+  shouldBeTrue(!!func, curr, "function argument of ref.func must exist");
+}
+
+void FunctionValidator::visitRefEq(RefEq* curr) {
+  shouldBeTrue(
+    getModule()->features.hasGC(), curr, "ref.eq requires gc to be enabled");
+  shouldBeSubTypeOrFirstIsUnreachable(
+    curr->left->type,
+    Type::eqref,
+    curr->left,
+    "ref.eq's left argument should be a subtype of eqref");
+  shouldBeSubTypeOrFirstIsUnreachable(
+    curr->right->type,
+    Type::eqref,
+    curr->right,
+    "ref.eq's right argument should be a subtype of eqref");
+}
+
+void FunctionValidator::visitTry(Try* curr) {
+  shouldBeTrue(getModule()->features.hasExceptionHandling(),
+               curr,
+               "try requires exception-handling to be enabled");
+  if (curr->type != Type::unreachable) {
+    shouldBeSubTypeOrFirstIsUnreachable(
+      curr->body->type,
+      curr->type,
+      curr->body,
+      "try's type does not match try body's type");
+    shouldBeSubTypeOrFirstIsUnreachable(
+      curr->catchBody->type,
+      curr->type,
+      curr->catchBody,
+      "try's type does not match catch's body type");
+  } else {
+    shouldBeEqual(curr->body->type,
+                  Type(Type::unreachable),
+                  curr,
+                  "unreachable try-catch must have unreachable try body");
+    shouldBeEqual(curr->catchBody->type,
+                  Type(Type::unreachable),
+                  curr,
+                  "unreachable try-catch must have unreachable catch body");
+  }
+}
+
+void FunctionValidator::visitThrow(Throw* curr) {
+  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");
+  auto* event = getModule()->getEventOrNull(curr->event);
+  if (!shouldBeTrue(!!event, curr, "throw's event must exist")) {
+    return;
+  }
+  if (!shouldBeTrue(curr->operands.size() == event->sig.params.size(),
+                    curr,
+                    "event's param numbers must match")) {
+    return;
+  }
+  size_t i = 0;
+  for (const auto& param : event->sig.params) {
+    if (!shouldBeSubTypeOrFirstIsUnreachable(curr->operands[i]->type,
+                                             param,
+                                             curr->operands[i],
+                                             "event param types must match") &&
+        !info.quiet) {
+      getStream() << "(on argument " << i << ")\n";
+    }
+    ++i;
+  }
+}
+
+void FunctionValidator::visitRethrow(Rethrow* curr) {
+  shouldBeTrue(getModule()->features.hasExceptionHandling(),
+               curr,
+               "rethrow requires exception-handling to be enabled");
+  shouldBeEqual(curr->type,
+                Type(Type::unreachable),
+                curr,
+                "rethrow's type must be unreachable");
+  shouldBeSubTypeOrFirstIsUnreachable(
+    curr->exnref->type,
+    Type::exnref,
+    curr->exnref,
+    "rethrow's argument must be exnref type or its subtype");
+}
+
+void FunctionValidator::visitBrOnExn(BrOnExn* curr) {
+  shouldBeTrue(getModule()->features.hasExceptionHandling(),
+               curr,
+               "br_on_exn requires exception-handling to be enabled");
+  Event* event = getModule()->getEventOrNull(curr->event);
+  shouldBeTrue(event != nullptr, curr, "br_on_exn's event must exist");
+  shouldBeTrue(event->sig.params == curr->sent,
+               curr,
+               "br_on_exn's event params and event's params are different");
+  noteBreak(curr->name, curr->sent, curr);
+  shouldBeSubTypeOrFirstIsUnreachable(
+    curr->exnref->type,
+    Type::exnref,
+    curr,
+    "br_on_exn's argument must be unreachable or exnref type or its subtype");
+  if (curr->exnref->type == Type::unreachable) {
+    shouldBeTrue(curr->type == Type::unreachable,
+                 curr,
+                 "If exnref argument's type is unreachable, br_on_exn should "
+                 "be unreachable too");
+  } else {
+    shouldBeTrue(curr->type == Type::exnref,
+                 curr,
+                 "br_on_exn's type should be exnref unless its exnref argument "
+                 "is unreachable");
+  }
+}
+
+void FunctionValidator::visitTupleMake(TupleMake* curr) {
+  shouldBeTrue(getModule()->features.hasMultivalue(),
+               curr,
+               "Tuples are not allowed unless multivalue is enabled");
+  shouldBeTrue(
+    curr->operands.size() > 1, curr, "tuple.make must have multiple operands");
+  std::vector<Type> types;
+  for (auto* op : curr->operands) {
+    if (op->type == Type::unreachable) {
+      shouldBeTrue(
+        curr->type == Type::unreachable,
+        curr,
+        "If tuple.make has an unreachable operand, it must be unreachable");
+      return;
+    }
+    types.push_back(op->type);
+  }
+  shouldBeSubType(Type(types),
+                  curr->type,
+                  curr,
+                  "Type of tuple.make does not match types of its operands");
+}
+
+void FunctionValidator::visitTupleExtract(TupleExtract* curr) {
+  shouldBeTrue(getModule()->features.hasMultivalue(),
+               curr,
+               "Tuples are not allowed unless multivalue is enabled");
+  if (curr->tuple->type == Type::unreachable) {
+    shouldBeTrue(
+      curr->type == Type::unreachable,
+      curr,
+      "If tuple.extract has an unreachable operand, it must be unreachable");
+  } else {
+    bool inBounds = curr->index < curr->tuple->type.size();
+    shouldBeTrue(inBounds, curr, "tuple.extract index out of bounds");
+    if (inBounds) {
+      shouldBeSubType(
+        curr->tuple->type[curr->index],
+        curr->type,
+        curr,
+        "tuple.extract type does not match the type of the extracted element");
+    }
+  }
+}
+
+void FunctionValidator::visitI31New(I31New* curr) {
+  shouldBeTrue(
+    getModule()->features.hasGC(), curr, "i31.new requires gc to be enabled");
+  shouldBeSubTypeOrFirstIsUnreachable(curr->value->type,
+                                      Type::i32,
+                                      curr->value,
+                                      "i31.new's argument should be i32");
+}
+
+void FunctionValidator::visitI31Get(I31Get* curr) {
+  shouldBeTrue(getModule()->features.hasGC(),
+               curr,
+               "i31.get_s/u requires gc to be enabled");
+  shouldBeSubTypeOrFirstIsUnreachable(
+    curr->i31->type,
+    Type::i31ref,
+    curr->i31,
+    "i31.get_s/u's argument should be i31ref");
+}
+
+void FunctionValidator::visitRefTest(RefTest* curr) {
+  shouldBeTrue(
+    getModule()->features.hasGC(), curr, "ref.test requires gc to be enabled");
+  WASM_UNREACHABLE("TODO (gc): ref.test");
+}
+
+void FunctionValidator::visitRefCast(RefCast* curr) {
+  shouldBeTrue(
+    getModule()->features.hasGC(), curr, "ref.cast requires gc to be enabled");
+  WASM_UNREACHABLE("TODO (gc): ref.cast");
+}
+
+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");
+}
+
+void FunctionValidator::visitRttCanon(RttCanon* curr) {
+  shouldBeTrue(
+    getModule()->features.hasGC(), curr, "rtt.canon requires gc to be enabled");
+  WASM_UNREACHABLE("TODO (gc): rtt.canon");
+}
+
+void FunctionValidator::visitRttSub(RttSub* curr) {
+  shouldBeTrue(
+    getModule()->features.hasGC(), curr, "rtt.sub requires gc to be enabled");
+  WASM_UNREACHABLE("TODO (gc): rtt.sub");
+}
+
+void FunctionValidator::visitStructNew(StructNew* curr) {
+  shouldBeTrue(getModule()->features.hasGC(),
+               curr,
+               "struct.new requires gc to be enabled");
+  WASM_UNREACHABLE("TODO (gc): struct.new");
+}
+
+void FunctionValidator::visitStructGet(StructGet* curr) {
+  shouldBeTrue(getModule()->features.hasGC(),
+               curr,
+               "struct.get requires gc to be enabled");
+  WASM_UNREACHABLE("TODO (gc): struct.get");
+}
+
+void FunctionValidator::visitStructSet(StructSet* curr) {
+  shouldBeTrue(getModule()->features.hasGC(),
+               curr,
+               "struct.set requires gc to be enabled");
+  WASM_UNREACHABLE("TODO (gc): struct.set");
+}
+
+void FunctionValidator::visitArrayNew(ArrayNew* curr) {
+  shouldBeTrue(
+    getModule()->features.hasGC(), curr, "array.new requires gc to be enabled");
+  WASM_UNREACHABLE("TODO (gc): array.new");
+}
+
+void FunctionValidator::visitArrayGet(ArrayGet* curr) {
+  shouldBeTrue(
+    getModule()->features.hasGC(), curr, "array.get requires gc to be enabled");
+  WASM_UNREACHABLE("TODO (gc): array.get");
+}
+
+void FunctionValidator::visitArraySet(ArraySet* curr) {
+  shouldBeTrue(
+    getModule()->features.hasGC(), curr, "array.set requires gc to be enabled");
+  WASM_UNREACHABLE("TODO (gc): array.set");
+}
+
+void FunctionValidator::visitArrayLen(ArrayLen* curr) {
+  shouldBeTrue(
+    getModule()->features.hasGC(), curr, "array.len requires gc to be enabled");
+  WASM_UNREACHABLE("TODO (gc): array.len");
+}
+
+void FunctionValidator::visitFunction(Function* curr) {
+  if (curr->sig.results.isTuple()) {
+    shouldBeTrue(getModule()->features.hasMultivalue(),
+                 curr->body,
+                 "Multivalue function results (multivalue is not enabled)");
+  }
+  FeatureSet features;
+  for (const auto& param : curr->sig.params) {
+    features |= param.getFeatures();
+    shouldBeTrue(param.isConcrete(), curr, "params must be concretely typed");
+  }
+  for (const auto& result : curr->sig.results) {
+    features |= result.getFeatures();
+    shouldBeTrue(result.isConcrete(), curr, "results must be concretely typed");
+  }
+  for (const auto& var : curr->vars) {
+    features |= var.getFeatures();
+    shouldBeTrue(var.isConcrete(), curr, "vars must be concretely typed");
+  }
+  shouldBeTrue(features <= getModule()->features,
+               curr,
+               "all used types should be allowed");
+  if (curr->profile == IRProfile::Poppy) {
+    shouldBeTrue(
+      curr->body->is<Block>(), curr->body, "Function body must be a block");
+  }
+  // if function has no result, it is ignored
+  // if body is unreachable, it might be e.g. a return
+  shouldBeSubTypeOrFirstIsUnreachable(
+    curr->body->type,
+    curr->sig.results,
+    curr->body,
+    "function body type must match, if function returns");
+  for (Type returnType : returnTypes) {
+    shouldBeSubTypeOrFirstIsUnreachable(
+      returnType,
+      curr->sig.results,
+      curr->body,
+      "function result must match, if function has returns");
+  }
+
+  shouldBeTrue(
+    breakInfos.empty(), curr->body, "all named break targets must exist");
+  returnTypes.clear();
+  labelNames.clear();
+  // validate optional local names
+  std::set<Name> seen;
+  for (auto& pair : curr->localNames) {
+    Name name = pair.second;
+    shouldBeTrue(seen.insert(name).second, name, "local names must be unique");
+  }
+}
+
+static bool checkSegmentOffset(Expression* curr, Address add, Address max) {
+  if (curr->is<GlobalGet>()) {
+    return true;
+  }
+  auto* c = curr->dynCast<Const>();
+  if (!c) {
+    return false;
+  }
+  uint64_t raw = c->value.getInteger();
+  if (raw > std::numeric_limits<Address::address32_t>::max()) {
+    return false;
+  }
+  if (raw + uint64_t(add) > std::numeric_limits<Address::address32_t>::max()) {
+    return false;
+  }
+  Address offset = raw;
+  return offset + add <= max;
+}
+
+void FunctionValidator::validateAlignment(
+  size_t align, Type type, Index bytes, bool isAtomic, Expression* curr) {
+  if (isAtomic) {
+    shouldBeEqual(align,
+                  (size_t)bytes,
+                  curr,
+                  "atomic accesses must have natural alignment");
+    return;
+  }
+  switch (align) {
+    case 1:
+    case 2:
+    case 4:
+    case 8:
+    case 16:
+      break;
+    default: {
+      info.fail("bad alignment: " + std::to_string(align), curr, getFunction());
+      break;
+    }
+  }
+  shouldBeTrue(align <= bytes, curr, "alignment must not exceed natural");
+  TODO_SINGLE_COMPOUND(type);
+  switch (type.getBasic()) {
+    case Type::i32:
+    case Type::f32: {
+      shouldBeTrue(align <= 4, curr, "alignment must not exceed natural");
+      break;
+    }
+    case Type::i64:
+    case Type::f64: {
+      shouldBeTrue(align <= 8, curr, "alignment must not exceed natural");
+      break;
+    }
+    case Type::v128:
+    case Type::unreachable:
+      break;
+    case Type::funcref:
+    case Type::externref:
+    case Type::exnref:
+    case Type::anyref:
+    case Type::eqref:
+    case Type::i31ref:
+    case Type::none:
+      WASM_UNREACHABLE("invalid type");
+  }
+}
+
+static void validateBinaryenIR(Module& wasm, ValidationInfo& info) {
+  struct BinaryenIRValidator
+    : public PostWalker<BinaryenIRValidator,
+                        UnifiedExpressionVisitor<BinaryenIRValidator>> {
+    ValidationInfo& info;
+
+    std::unordered_set<Expression*> seen;
+
+    BinaryenIRValidator(ValidationInfo& info) : info(info) {}
+
+    void visitExpression(Expression* curr) {
+      auto scope = getFunction() ? getFunction()->name : Name("(global scope)");
+      // check if a node type is 'stale', i.e., we forgot to finalize() the
+      // node.
+      auto oldType = curr->type;
+      ReFinalizeNode().visit(curr);
+      auto newType = curr->type;
+      if (newType != oldType) {
+        // We accept concrete => undefined,
+        // e.g.
+        //
+        //  (drop (block (result i32) (unreachable)))
+        //
+        // The block has an added type, not derived from the ast itself, so it
+        // is ok for it to be either i32 or unreachable.
+        if (!Type::isSubType(newType, oldType) &&
+            !(oldType.isConcrete() && newType == Type::unreachable)) {
+          std::ostringstream ss;
+          ss << "stale type found in " << scope << " on " << curr
+             << "\n(marked as " << oldType << ", should be " << newType
+             << ")\n";
+          info.fail(ss.str(), curr, getFunction());
+        }
+        curr->type = oldType;
+      }
+      // check if a node is a duplicate - expressions must not be seen more than
+      // once
+      bool inserted;
+      std::tie(std::ignore, inserted) = seen.insert(curr);
+      if (!inserted) {
+        std::ostringstream ss;
+        ss << "expression seen more than once in the tree in " << scope
+           << " on " << curr << '\n';
+        info.fail(ss.str(), curr, getFunction());
+      }
+    }
+  };
+  BinaryenIRValidator binaryenIRValidator(info);
+  binaryenIRValidator.walkModule(&wasm);
+}
+
+// Main validator class
+
+static void validateImports(Module& module, ValidationInfo& info) {
+  ModuleUtils::iterImportedFunctions(module, [&](Function* curr) {
+    if (curr->sig.results.isTuple()) {
+      info.shouldBeTrue(module.features.hasMultivalue(),
+                        curr->name,
+                        "Imported multivalue function "
+                        "(multivalue is not enabled)");
+    }
+    if (info.validateWeb) {
+      for (const auto& param : curr->sig.params) {
+        info.shouldBeUnequal(param,
+                             Type(Type::i64),
+                             curr->name,
+                             "Imported function must not have i64 parameters");
+      }
+      for (const auto& result : curr->sig.results) {
+        info.shouldBeUnequal(result,
+                             Type(Type::i64),
+                             curr->name,
+                             "Imported function must not have i64 results");
+      }
+    }
+  });
+  ModuleUtils::iterImportedGlobals(module, [&](Global* curr) {
+    if (!module.features.hasMutableGlobals()) {
+      info.shouldBeFalse(
+        curr->mutable_, curr->name, "Imported global cannot be mutable");
+    }
+    info.shouldBeFalse(
+      curr->type.isTuple(), curr->name, "Imported global cannot be tuple");
+  });
+}
+
+static void validateExports(Module& module, ValidationInfo& info) {
+  for (auto& curr : module.exports) {
+    if (curr->kind == ExternalKind::Function) {
+      if (info.validateWeb) {
+        Function* f = module.getFunction(curr->value);
+        for (const auto& param : f->sig.params) {
+          info.shouldBeUnequal(
+            param,
+            Type(Type::i64),
+            f->name,
+            "Exported function must not have i64 parameters");
+        }
+        for (const auto& result : f->sig.results) {
+          info.shouldBeUnequal(result,
+                               Type(Type::i64),
+                               f->name,
+                               "Exported function must not have i64 results");
+        }
+      }
+    } else if (curr->kind == ExternalKind::Global) {
+      if (Global* g = module.getGlobalOrNull(curr->value)) {
+        if (!module.features.hasMutableGlobals()) {
+          info.shouldBeFalse(
+            g->mutable_, g->name, "Exported global cannot be mutable");
+        }
+        info.shouldBeFalse(
+          g->type.isTuple(), g->name, "Exported global cannot be tuple");
+      }
+    }
+  }
+  std::unordered_set<Name> exportNames;
+  for (auto& exp : module.exports) {
+    Name name = exp->value;
+    if (exp->kind == ExternalKind::Function) {
+      info.shouldBeTrue(module.getFunctionOrNull(name),
+                        name,
+                        "module function exports must be found");
+    } else if (exp->kind == ExternalKind::Global) {
+      info.shouldBeTrue(module.getGlobalOrNull(name),
+                        name,
+                        "module global exports must be found");
+    } else if (exp->kind == ExternalKind::Table) {
+      info.shouldBeTrue(name == Name("0") || name == module.table.name,
+                        name,
+                        "module table exports must be found");
+    } else if (exp->kind == ExternalKind::Memory) {
+      info.shouldBeTrue(name == Name("0") || name == module.memory.name,
+                        name,
+                        "module memory exports must be found");
+    } else if (exp->kind == ExternalKind::Event) {
+      info.shouldBeTrue(module.getEventOrNull(name),
+                        name,
+                        "module event exports must be found");
+    } else {
+      WASM_UNREACHABLE("invalid ExternalKind");
+    }
+    Name exportName = exp->name;
+    info.shouldBeFalse(exportNames.count(exportName) > 0,
+                       exportName,
+                       "module exports must be unique");
+    exportNames.insert(exportName);
+  }
+}
+
+static void validateGlobals(Module& module, ValidationInfo& info) {
+  ModuleUtils::iterDefinedGlobals(module, [&](Global* curr) {
+    info.shouldBeTrue(curr->type.getFeatures() <= module.features,
+                      curr->name,
+                      "all used types should be allowed");
+    info.shouldBeTrue(
+      curr->init != nullptr, curr->name, "global init must be non-null");
+    assert(curr->init);
+    info.shouldBeTrue(GlobalUtils::canInitializeGlobal(curr->init),
+                      curr->name,
+                      "global init must be valid");
+
+    if (!info.shouldBeSubType(curr->init->type,
+                              curr->type,
+                              curr->init,
+                              "global init must have correct type") &&
+        !info.quiet) {
+      info.getStream(nullptr) << "(on global " << curr->name << ")\n";
+    }
+  });
+}
+
+static void validateMemory(Module& module, ValidationInfo& info) {
+  auto& curr = module.memory;
+  info.shouldBeFalse(
+    curr.initial > curr.max, "memory", "memory max >= initial");
+  if (curr.is64()) {
+    info.shouldBeTrue(module.features.hasMemory64(),
+                      "memory",
+                      "memory is 64-bit, but memory64 is disabled");
+  } else {
+    info.shouldBeTrue(curr.initial <= Memory::kMaxSize32,
+                      "memory",
+                      "initial memory must be <= 4GB");
+    info.shouldBeTrue(!curr.hasMax() || curr.max <= Memory::kMaxSize32,
+                      "memory",
+                      "max memory must be <= 4GB, or unlimited");
+  }
+  info.shouldBeTrue(!curr.shared || curr.hasMax(),
+                    "memory",
+                    "shared memory must have max size");
+  if (curr.shared) {
+    info.shouldBeTrue(module.features.hasAtomics(),
+                      "memory",
+                      "memory is shared, but atomics are disabled");
+  }
+  for (auto& segment : curr.segments) {
+    Index size = segment.data.size();
+    if (segment.isPassive) {
+      info.shouldBeTrue(module.features.hasBulkMemory(),
+                        segment.offset,
+                        "nonzero segment flags (bulk memory is disabled)");
+      info.shouldBeEqual(segment.offset,
+                         (Expression*)nullptr,
+                         segment.offset,
+                         "passive segment should not have an offset");
+    } else {
+      if (!info.shouldBeEqual(segment.offset->type,
+                              Type(Type::i32),
+                              segment.offset,
+                              "segment offset should be i32")) {
+        continue;
+      }
+      info.shouldBeTrue(checkSegmentOffset(segment.offset,
+                                           segment.data.size(),
+                                           curr.initial * Memory::kPageSize),
+                        segment.offset,
+                        "memory segment offset should be reasonable");
+      if (segment.offset->is<Const>()) {
+        Index start = segment.offset->cast<Const>()->value.geti32();
+        Index end = start + size;
+        info.shouldBeTrue(end <= curr.initial * Memory::kPageSize,
+                          segment.data.size(),
+                          "segment size should fit in memory (end)");
+      }
+    }
+    // If the memory is imported we don't actually know its initial size.
+    // Specifically wasm dll's import a zero sized memory which is perfectly
+    // valid.
+    if (!curr.imported()) {
+      info.shouldBeTrue(size <= curr.initial * Memory::kPageSize,
+                        segment.data.size(),
+                        "segment size should fit in memory (initial)");
+    }
+  }
+}
+
+static void validateTable(Module& module, ValidationInfo& info) {
+  auto& curr = module.table;
+  for (auto& segment : curr.segments) {
+    info.shouldBeEqual(segment.offset->type,
+                       Type(Type::i32),
+                       segment.offset,
+                       "segment offset should be i32");
+    info.shouldBeTrue(
+      checkSegmentOffset(segment.offset,
+                         segment.data.size(),
+                         module.table.initial * Table::kPageSize),
+      segment.offset,
+      "table segment offset should be reasonable");
+    for (auto name : segment.data) {
+      info.shouldBeTrue(
+        module.getFunctionOrNull(name), name, "segment name should be valid");
+    }
+  }
+}
+
+static void validateEvents(Module& module, ValidationInfo& info) {
+  if (!module.events.empty()) {
+    info.shouldBeTrue(module.features.hasExceptionHandling(),
+                      module.events[0]->name,
+                      "Module has events (event-handling is disabled)");
+  }
+  for (auto& curr : module.events) {
+    info.shouldBeEqual(curr->attribute,
+                       (unsigned)0,
+                       curr->attribute,
+                       "Currently only attribute 0 is supported");
+    info.shouldBeEqual(curr->sig.results,
+                       Type(Type::none),
+                       curr->name,
+                       "Event type's result type should be none");
+    if (curr->sig.params.isTuple()) {
+      info.shouldBeTrue(module.features.hasMultivalue(),
+                        curr->name,
+                        "Multivalue event type (multivalue is not enabled)");
+    }
+    for (const auto& param : curr->sig.params) {
+      info.shouldBeTrue(param.isConcrete(),
+                        curr->name,
+                        "Values in an event should have concrete types");
+    }
+  }
+}
+
+static void validateModule(Module& module, ValidationInfo& info) {
+  // start
+  if (module.start.is()) {
+    auto func = module.getFunctionOrNull(module.start);
+    if (info.shouldBeTrue(
+          func != nullptr, module.start, "start must be found")) {
+      info.shouldBeTrue(func->sig.params == Type::none,
+                        module.start,
+                        "start must have 0 params");
+      info.shouldBeTrue(func->sig.results == Type::none,
+                        module.start,
+                        "start must not return a value");
+    }
+  }
+}
+
+static void validateFeatures(Module& module, ValidationInfo& info) {
+  if (module.features.hasGC()) {
+    info.shouldBeTrue(module.features.hasReferenceTypes(),
+                      module.features,
+                      "--enable-gc requires --enable-reference-types");
+  }
+  if (module.features.hasExceptionHandling()) { // implies exnref
+    info.shouldBeTrue(
+      module.features.hasReferenceTypes(),
+      module.features,
+      "--enable-exception-handling requires --enable-reference-types");
+  }
+}
+
+// TODO: If we want the validator to be part of libwasm rather than libpasses,
+// then Using PassRunner::getPassDebug causes a circular dependence. We should
+// fix that, perhaps by moving some of the pass infrastructure into libsupport.
+bool WasmValidator::validate(Module& module, Flags flags) {
+  ValidationInfo info;
+  info.validateWeb = (flags & Web) != 0;
+  info.validateGlobally = (flags & Globally) != 0;
+  info.quiet = (flags & Quiet) != 0;
+  // parallel wasm logic validation
+  PassRunner runner(&module);
+  FunctionValidator(&info).run(&runner, &module);
+  // validate globally
+  if (info.validateGlobally) {
+    validateImports(module, info);
+    validateExports(module, info);
+    validateGlobals(module, info);
+    validateMemory(module, info);
+    validateTable(module, info);
+    validateEvents(module, info);
+    validateModule(module, info);
+    validateFeatures(module, info);
+  }
+  // validate additional internal IR details when in pass-debug mode
+  if (PassRunner::getPassDebug()) {
+    validateBinaryenIR(module, info);
+  }
+  // print all the data
+  if (!info.valid.load() && !info.quiet) {
+    for (auto& func : module.functions) {
+      std::cerr << info.getStream(func.get()).str();
+    }
+    std::cerr << info.getStream(nullptr).str();
+  }
+  return info.valid.load();
+}
+
+} // namespace wasm
diff --git a/binaryen/src/wasm/wasm.cpp b/binaryen/src/wasm/wasm.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm/wasm.cpp
@@ -0,0 +1,1293 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wasm.h"
+#include "ir/branch-utils.h"
+#include "wasm-printing.h"
+#include "wasm-traversal.h"
+
+namespace wasm {
+
+// shared constants
+
+Name WASM("wasm");
+Name RETURN_FLOW("*return:)*");
+Name NONCONSTANT_FLOW("*nonconstant:)*");
+
+namespace BinaryConsts {
+namespace UserSections {
+const char* Name = "name";
+const char* SourceMapUrl = "sourceMappingURL";
+const char* Dylink = "dylink";
+const char* Linking = "linking";
+const char* Producers = "producers";
+const char* TargetFeatures = "target_features";
+const char* AtomicsFeature = "atomics";
+const char* BulkMemoryFeature = "bulk-memory";
+const char* ExceptionHandlingFeature = "exception-handling";
+const char* MutableGlobalsFeature = "mutable-globals";
+const char* TruncSatFeature = "nontrapping-fptoint";
+const char* SignExtFeature = "sign-ext";
+const char* SIMD128Feature = "simd128";
+const char* TailCallFeature = "tail-call";
+const char* ReferenceTypesFeature = "reference-types";
+const char* MultivalueFeature = "multivalue";
+const char* GCFeature = "gc";
+const char* Memory64Feature = "memory64";
+} // namespace UserSections
+} // namespace BinaryConsts
+
+Name WASM_CALL_CTORS("__wasm_call_ctors");
+Name MEMORY_BASE("__memory_base");
+Name TABLE_BASE("__table_base");
+Name STACK_POINTER("__stack_pointer");
+Name GET_TEMP_RET0("getTempRet0");
+Name SET_TEMP_RET0("setTempRet0");
+Name NEW_SIZE("newSize");
+Name MODULE("module");
+Name START("start");
+Name FUNC("func");
+Name PARAM("param");
+Name RESULT("result");
+Name MEMORY("memory");
+Name DATA("data");
+Name PASSIVE("passive");
+Name EXPORT("export");
+Name IMPORT("import");
+Name TABLE("table");
+Name ELEM("elem");
+Name LOCAL("local");
+Name TYPE("type");
+Name CALL("call");
+Name CALL_INDIRECT("call_indirect");
+Name BLOCK("block");
+Name BR_IF("br_if");
+Name THEN("then");
+Name ELSE("else");
+Name _NAN("NaN");
+Name _INFINITY("Infinity");
+Name NEG_INFINITY("-infinity");
+Name NEG_NAN("-nan");
+Name CASE("case");
+Name BR("br");
+Name FUNCREF("funcref");
+Name FAKE_RETURN("fake_return_waka123");
+Name MUT("mut");
+Name SPECTEST("spectest");
+Name PRINT("print");
+Name EXIT("exit");
+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);
+}
+
+const char* getExpressionName(Expression* curr) {
+  switch (curr->_id) {
+    case Expression::Id::InvalidId:
+      WASM_UNREACHABLE("invalid expr id");
+    case Expression::Id::BlockId:
+      return "block";
+    case Expression::Id::IfId:
+      return "if";
+    case Expression::Id::LoopId:
+      return "loop";
+    case Expression::Id::BreakId:
+      return "break";
+    case Expression::Id::SwitchId:
+      return "switch";
+    case Expression::Id::CallId:
+      return "call";
+    case Expression::Id::CallIndirectId:
+      return "call_indirect";
+    case Expression::Id::LocalGetId:
+      return "local.get";
+    case Expression::Id::LocalSetId:
+      return "local.set";
+    case Expression::Id::GlobalGetId:
+      return "global.get";
+    case Expression::Id::GlobalSetId:
+      return "global.set";
+    case Expression::Id::LoadId:
+      return "load";
+    case Expression::Id::StoreId:
+      return "store";
+    case Expression::Id::ConstId:
+      return "const";
+    case Expression::Id::UnaryId:
+      return "unary";
+    case Expression::Id::BinaryId:
+      return "binary";
+    case Expression::Id::SelectId:
+      return "select";
+    case Expression::Id::DropId:
+      return "drop";
+    case Expression::Id::ReturnId:
+      return "return";
+    case Expression::Id::MemorySizeId:
+      return "memory.size";
+    case Expression::Id::MemoryGrowId:
+      return "memory.grow";
+    case Expression::Id::NopId:
+      return "nop";
+    case Expression::Id::UnreachableId:
+      return "unreachable";
+    case Expression::Id::AtomicCmpxchgId:
+      return "atomic_cmpxchg";
+    case Expression::Id::AtomicRMWId:
+      return "atomic_rmw";
+    case Expression::Id::AtomicWaitId:
+      return "atomic_wait";
+    case Expression::Id::AtomicNotifyId:
+      return "atomic_notify";
+    case Expression::Id::AtomicFenceId:
+      return "atomic_fence";
+    case Expression::Id::SIMDExtractId:
+      return "simd_extract";
+    case Expression::Id::SIMDReplaceId:
+      return "simd_replace";
+    case Expression::Id::SIMDShuffleId:
+      return "simd_shuffle";
+    case Expression::Id::SIMDTernaryId:
+      return "simd_ternary";
+    case Expression::Id::SIMDShiftId:
+      return "simd_shift";
+    case Expression::Id::SIMDLoadId:
+      return "simd_load";
+    case Expression::Id::MemoryInitId:
+      return "memory_init";
+    case Expression::Id::DataDropId:
+      return "data_drop";
+    case Expression::Id::MemoryCopyId:
+      return "memory_copy";
+    case Expression::Id::MemoryFillId:
+      return "memory_fill";
+    case Expression::Id::PopId:
+      return "pop";
+    case Expression::Id::RefNullId:
+      return "ref.null";
+    case Expression::Id::RefIsNullId:
+      return "ref.is_null";
+    case Expression::Id::RefFuncId:
+      return "ref.func";
+    case Expression::Id::RefEqId:
+      return "ref.eq";
+    case Expression::Id::TryId:
+      return "try";
+    case Expression::Id::ThrowId:
+      return "throw";
+    case Expression::Id::RethrowId:
+      return "rethrow";
+    case Expression::Id::BrOnExnId:
+      return "br_on_exn";
+    case Expression::Id::TupleMakeId:
+      return "tuple.make";
+    case Expression::Id::TupleExtractId:
+      return "tuple.extract";
+    case Expression::Id::I31NewId:
+      return "i31.new";
+    case Expression::Id::I31GetId:
+      return "i31.get";
+    case Expression::Id::RefTestId:
+      return "ref.test";
+    case Expression::Id::RefCastId:
+      return "ref.cast";
+    case Expression::Id::BrOnCastId:
+      return "br_on_cast";
+    case Expression::Id::RttCanonId:
+      return "rtt.canon";
+    case Expression::Id::RttSubId:
+      return "rtt.sub";
+    case Expression::Id::StructNewId:
+      return "struct.new";
+    case Expression::Id::StructGetId:
+      return "struct.get";
+    case Expression::Id::StructSetId:
+      return "struct.set";
+    case Expression::Id::ArrayNewId:
+      return "array.new";
+    case Expression::Id::ArrayGetId:
+      return "array.get";
+    case Expression::Id::ArraySetId:
+      return "array.set";
+    case Expression::Id::ArrayLenId:
+      return "array.len";
+    case Expression::Id::NumExpressionIds:
+      WASM_UNREACHABLE("invalid expr id");
+  }
+  WASM_UNREACHABLE("invalid expr id");
+}
+
+Literal getLiteralFromConstExpression(Expression* curr) {
+  // TODO: Do we need this function given that Properties::getLiteral
+  // (currently) does the same?
+  assert(Properties::isConstantExpression(curr));
+  return Properties::getLiteral(curr);
+}
+
+Literals getLiteralsFromConstExpression(Expression* curr) {
+  // TODO: Do we need this function given that Properties::getLiterals
+  // (currently) does the same?
+  if (auto* t = curr->dynCast<TupleMake>()) {
+    Literals values;
+    for (auto* operand : t->operands) {
+      values.push_back(getLiteralFromConstExpression(operand));
+    }
+    return values;
+  } else {
+    return {getLiteralFromConstExpression(curr)};
+  }
+}
+
+// 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) {
+  if (block->type == Type::unreachable) {
+    return; // nothing to do
+  }
+  if (block->list.size() == 0) {
+    return; // nothing to do
+  }
+  // if we are concrete, stop - even an unreachable child
+  // won't change that (since we have a break with a value,
+  // or the final child flows out a value)
+  if (block->type.isConcrete()) {
+    return;
+  }
+  // look for an unreachable child
+  for (auto* child : block->list) {
+    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 (!hasBreak) {
+        block->type = Type::unreachable;
+      }
+      return;
+    }
+  }
+}
+
+void Block::finalize() {
+  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;
+        }
+      }
+    } else {
+      type = Type::none;
+    }
+    return;
+  }
+
+  TypeSeeker seeker(this, this->name);
+  type = Type::mergeTypes(seeker.types);
+  handleUnreachable(this);
+}
+
+void Block::finalize(Type type_) {
+  type = type_;
+  if (type == Type::none && list.size() > 0) {
+    handleUnreachable(this);
+  }
+}
+
+void Block::finalize(Type type_, bool hasBreak) {
+  type = type_;
+  if (type == Type::none && list.size() > 0) {
+    handleUnreachable(this, true, hasBreak);
+  }
+}
+
+void If::finalize(Type type_) {
+  type = type_;
+  if (type == Type::none && (condition->type == Type::unreachable ||
+                             (ifFalse && ifTrue->type == Type::unreachable &&
+                              ifFalse->type == Type::unreachable))) {
+    type = Type::unreachable;
+  }
+}
+
+void If::finalize() {
+  type = ifFalse ? Type::getLeastUpperBound(ifTrue->type, ifFalse->type)
+                 : Type::none;
+  // if the arms return a value, leave it even if the condition
+  // is unreachable, we still mark ourselves as having that type, e.g.
+  // (if (result i32)
+  //  (unreachable)
+  //  (i32.const 10)
+  //  (i32.const 20
+  // )
+  // otherwise, if the condition is unreachable, so is the if
+  if (type == Type::none && condition->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void Loop::finalize(Type type_) {
+  type = type_;
+  if (type == Type::none && body->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void Loop::finalize() { type = body->type; }
+
+void Break::finalize() {
+  if (condition) {
+    if (condition->type == Type::unreachable) {
+      type = Type::unreachable;
+    } else if (value) {
+      type = value->type;
+    } else {
+      type = Type::none;
+    }
+  } else {
+    type = Type::unreachable;
+  }
+}
+
+void Switch::finalize() { type = Type::unreachable; }
+
+template<typename T> void handleUnreachableOperands(T* curr) {
+  for (auto* child : curr->operands) {
+    if (child->type == Type::unreachable) {
+      curr->type = Type::unreachable;
+      break;
+    }
+  }
+}
+
+void Call::finalize() {
+  handleUnreachableOperands(this);
+  if (isReturn) {
+    type = Type::unreachable;
+  }
+}
+
+void CallIndirect::finalize() {
+  type = sig.results;
+  handleUnreachableOperands(this);
+  if (isReturn) {
+    type = Type::unreachable;
+  }
+  if (target->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+bool LocalSet::isTee() const { return type != Type::none; }
+
+// Changes to local.tee. The type of the local should be given.
+void LocalSet::makeTee(Type type_) {
+  type = type_;
+  finalize(); // type may need to be unreachable
+}
+
+// Changes to local.set.
+void LocalSet::makeSet() {
+  type = Type::none;
+  finalize(); // type may need to be unreachable
+}
+
+void LocalSet::finalize() {
+  if (value->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void GlobalSet::finalize() {
+  if (value->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void Load::finalize() {
+  if (ptr->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void Store::finalize() {
+  assert(valueType != Type::none); // must be set
+  if (ptr->type == Type::unreachable || value->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = Type::none;
+  }
+}
+
+void AtomicRMW::finalize() {
+  if (ptr->type == Type::unreachable || value->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void AtomicCmpxchg::finalize() {
+  if (ptr->type == Type::unreachable || expected->type == Type::unreachable ||
+      replacement->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void AtomicWait::finalize() {
+  type = Type::i32;
+  if (ptr->type == Type::unreachable || expected->type == Type::unreachable ||
+      timeout->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void AtomicNotify::finalize() {
+  type = Type::i32;
+  if (ptr->type == Type::unreachable ||
+      notifyCount->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void AtomicFence::finalize() { type = Type::none; }
+
+void SIMDExtract::finalize() {
+  assert(vec);
+  switch (op) {
+    case ExtractLaneSVecI8x16:
+    case ExtractLaneUVecI8x16:
+    case ExtractLaneSVecI16x8:
+    case ExtractLaneUVecI16x8:
+    case ExtractLaneVecI32x4:
+      type = Type::i32;
+      break;
+    case ExtractLaneVecI64x2:
+      type = Type::i64;
+      break;
+    case ExtractLaneVecF32x4:
+      type = Type::f32;
+      break;
+    case ExtractLaneVecF64x2:
+      type = Type::f64;
+      break;
+    default:
+      WASM_UNREACHABLE("unexpected op");
+  }
+  if (vec->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void SIMDReplace::finalize() {
+  assert(vec && value);
+  type = Type::v128;
+  if (vec->type == Type::unreachable || value->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void SIMDShuffle::finalize() {
+  assert(left && right);
+  type = Type::v128;
+  if (left->type == Type::unreachable || right->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void SIMDTernary::finalize() {
+  assert(a && b && c);
+  type = Type::v128;
+  if (a->type == Type::unreachable || b->type == Type::unreachable ||
+      c->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void MemoryInit::finalize() {
+  assert(dest && offset && size);
+  type = Type::none;
+  if (dest->type == Type::unreachable || offset->type == Type::unreachable ||
+      size->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void DataDrop::finalize() { type = Type::none; }
+
+void MemoryCopy::finalize() {
+  assert(dest && source && size);
+  type = Type::none;
+  if (dest->type == Type::unreachable || source->type == Type::unreachable ||
+      size->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void MemoryFill::finalize() {
+  assert(dest && value && size);
+  type = Type::none;
+  if (dest->type == Type::unreachable || value->type == Type::unreachable ||
+      size->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void SIMDShift::finalize() {
+  assert(vec && shift);
+  type = Type::v128;
+  if (vec->type == Type::unreachable || shift->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void SIMDLoad::finalize() {
+  assert(ptr);
+  type = Type::v128;
+  if (ptr->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+Index SIMDLoad::getMemBytes() {
+  switch (op) {
+    case LoadSplatVec8x16:
+      return 1;
+    case LoadSplatVec16x8:
+      return 2;
+    case LoadSplatVec32x4:
+    case Load32Zero:
+      return 4;
+    case LoadSplatVec64x2:
+    case LoadExtSVec8x8ToVecI16x8:
+    case LoadExtUVec8x8ToVecI16x8:
+    case LoadExtSVec16x4ToVecI32x4:
+    case LoadExtUVec16x4ToVecI32x4:
+    case LoadExtSVec32x2ToVecI64x2:
+    case LoadExtUVec32x2ToVecI64x2:
+    case Load64Zero:
+      return 8;
+  }
+  WASM_UNREACHABLE("unexpected op");
+}
+
+Const* Const::set(Literal value_) {
+  value = value_;
+  type = value.type;
+  return this;
+}
+
+void Const::finalize() { type = value.type; }
+
+bool Unary::isRelational() { return op == EqZInt32 || op == EqZInt64; }
+
+void Unary::finalize() {
+  if (value->type == Type::unreachable) {
+    type = Type::unreachable;
+    return;
+  }
+  switch (op) {
+    case ClzInt32:
+    case CtzInt32:
+    case PopcntInt32:
+    case NegFloat32:
+    case AbsFloat32:
+    case CeilFloat32:
+    case FloorFloat32:
+    case TruncFloat32:
+    case NearestFloat32:
+    case SqrtFloat32:
+    case ClzInt64:
+    case CtzInt64:
+    case PopcntInt64:
+    case NegFloat64:
+    case AbsFloat64:
+    case CeilFloat64:
+    case FloorFloat64:
+    case TruncFloat64:
+    case NearestFloat64:
+    case SqrtFloat64:
+      type = value->type;
+      break;
+    case EqZInt32:
+    case EqZInt64:
+      type = Type::i32;
+      break;
+    case ExtendS8Int32:
+    case ExtendS16Int32:
+      type = Type::i32;
+      break;
+    case ExtendSInt32:
+    case ExtendUInt32:
+    case ExtendS8Int64:
+    case ExtendS16Int64:
+    case ExtendS32Int64:
+      type = Type::i64;
+      break;
+    case WrapInt64:
+      type = Type::i32;
+      break;
+    case PromoteFloat32:
+      type = Type::f64;
+      break;
+    case DemoteFloat64:
+      type = Type::f32;
+      break;
+    case TruncSFloat32ToInt32:
+    case TruncUFloat32ToInt32:
+    case TruncSFloat64ToInt32:
+    case TruncUFloat64ToInt32:
+    case TruncSatSFloat32ToInt32:
+    case TruncSatUFloat32ToInt32:
+    case TruncSatSFloat64ToInt32:
+    case TruncSatUFloat64ToInt32:
+    case ReinterpretFloat32:
+      type = Type::i32;
+      break;
+    case TruncSFloat32ToInt64:
+    case TruncUFloat32ToInt64:
+    case TruncSFloat64ToInt64:
+    case TruncUFloat64ToInt64:
+    case TruncSatSFloat32ToInt64:
+    case TruncSatUFloat32ToInt64:
+    case TruncSatSFloat64ToInt64:
+    case TruncSatUFloat64ToInt64:
+    case ReinterpretFloat64:
+      type = Type::i64;
+      break;
+    case ReinterpretInt32:
+    case ConvertSInt32ToFloat32:
+    case ConvertUInt32ToFloat32:
+    case ConvertSInt64ToFloat32:
+    case ConvertUInt64ToFloat32:
+      type = Type::f32;
+      break;
+    case ReinterpretInt64:
+    case ConvertSInt32ToFloat64:
+    case ConvertUInt32ToFloat64:
+    case ConvertSInt64ToFloat64:
+    case ConvertUInt64ToFloat64:
+      type = Type::f64;
+      break;
+    case SplatVecI8x16:
+    case SplatVecI16x8:
+    case SplatVecI32x4:
+    case SplatVecI64x2:
+    case SplatVecF32x4:
+    case SplatVecF64x2:
+    case NotVec128:
+    case AbsVecI8x16:
+    case AbsVecI16x8:
+    case AbsVecI32x4:
+    case NegVecI8x16:
+    case NegVecI16x8:
+    case NegVecI32x4:
+    case NegVecI64x2:
+    case AbsVecF32x4:
+    case NegVecF32x4:
+    case SqrtVecF32x4:
+    case CeilVecF32x4:
+    case FloorVecF32x4:
+    case TruncVecF32x4:
+    case NearestVecF32x4:
+    case AbsVecF64x2:
+    case NegVecF64x2:
+    case SqrtVecF64x2:
+    case CeilVecF64x2:
+    case FloorVecF64x2:
+    case TruncVecF64x2:
+    case NearestVecF64x2:
+    case TruncSatSVecF32x4ToVecI32x4:
+    case TruncSatUVecF32x4ToVecI32x4:
+    case TruncSatSVecF64x2ToVecI64x2:
+    case TruncSatUVecF64x2ToVecI64x2:
+    case ConvertSVecI32x4ToVecF32x4:
+    case ConvertUVecI32x4ToVecF32x4:
+    case ConvertSVecI64x2ToVecF64x2:
+    case ConvertUVecI64x2ToVecF64x2:
+    case WidenLowSVecI8x16ToVecI16x8:
+    case WidenHighSVecI8x16ToVecI16x8:
+    case WidenLowUVecI8x16ToVecI16x8:
+    case WidenHighUVecI8x16ToVecI16x8:
+    case WidenLowSVecI16x8ToVecI32x4:
+    case WidenHighSVecI16x8ToVecI32x4:
+    case WidenLowUVecI16x8ToVecI32x4:
+    case WidenHighUVecI16x8ToVecI32x4:
+      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:
+      type = Type::i32;
+      break;
+
+    case InvalidUnary:
+      WASM_UNREACHABLE("invalid unary op");
+  }
+}
+
+bool Binary::isRelational() {
+  switch (op) {
+    case EqInt32:
+    case NeInt32:
+    case LtSInt32:
+    case LtUInt32:
+    case LeSInt32:
+    case LeUInt32:
+    case GtSInt32:
+    case GtUInt32:
+    case GeSInt32:
+    case GeUInt32:
+    case EqInt64:
+    case NeInt64:
+    case LtSInt64:
+    case LtUInt64:
+    case LeSInt64:
+    case LeUInt64:
+    case GtSInt64:
+    case GtUInt64:
+    case GeSInt64:
+    case GeUInt64:
+    case EqFloat32:
+    case NeFloat32:
+    case LtFloat32:
+    case LeFloat32:
+    case GtFloat32:
+    case GeFloat32:
+    case EqFloat64:
+    case NeFloat64:
+    case LtFloat64:
+    case LeFloat64:
+    case GtFloat64:
+    case GeFloat64:
+      return true;
+    default:
+      return false;
+  }
+}
+
+void Binary::finalize() {
+  assert(left && right);
+  if (left->type == Type::unreachable || right->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else if (isRelational()) {
+    type = Type::i32;
+  } else {
+    type = left->type;
+  }
+}
+
+void Select::finalize(Type type_) { type = type_; }
+
+void Select::finalize() {
+  assert(ifTrue && ifFalse);
+  if (ifTrue->type == Type::unreachable || ifFalse->type == Type::unreachable ||
+      condition->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = Type::getLeastUpperBound(ifTrue->type, ifFalse->type);
+  }
+}
+
+void Drop::finalize() {
+  if (value->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = Type::none;
+  }
+}
+
+void MemorySize::make64() { type = ptrType = Type::i64; }
+void MemorySize::finalize() { type = ptrType; }
+
+void MemoryGrow::make64() { type = ptrType = Type::i64; }
+void MemoryGrow::finalize() {
+  if (delta->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = ptrType;
+  }
+}
+
+void RefNull::finalize(HeapType heapType) { type = Type(heapType, true); }
+
+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() {
+  if (value->type == Type::unreachable) {
+    type = Type::unreachable;
+    return;
+  }
+  type = Type::i32;
+}
+
+void RefFunc::finalize() { type = Type::funcref; }
+
+void RefEq::finalize() {
+  if (left->type == Type::unreachable || right->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = Type::i32;
+  }
+}
+
+void Try::finalize() {
+  type = Type::getLeastUpperBound(body->type, catchBody->type);
+}
+
+void Try::finalize(Type type_) {
+  type = type_;
+  if (type == Type::none && body->type == Type::unreachable &&
+      catchBody->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+void Throw::finalize() { type = Type::unreachable; }
+
+void Rethrow::finalize() { type = Type::unreachable; }
+
+void BrOnExn::finalize() {
+  if (exnref->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = Type::exnref;
+  }
+}
+
+void TupleMake::finalize() {
+  std::vector<Type> types;
+  for (auto* op : operands) {
+    if (op->type == Type::unreachable) {
+      type = Type::unreachable;
+      return;
+    }
+    types.push_back(op->type);
+  }
+  type = Type(types);
+}
+
+void TupleExtract::finalize() {
+  if (tuple->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = tuple->type[index];
+  }
+}
+
+void I31New::finalize() {
+  if (value->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = Type::i31ref;
+  }
+}
+
+void I31Get::finalize() {
+  if (i31->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = Type::i32;
+  }
+}
+
+// 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
+
+size_t Function::getNumParams() { return sig.params.size(); }
+
+size_t Function::getNumVars() { return vars.size(); }
+
+size_t Function::getNumLocals() { return sig.params.size() + vars.size(); }
+
+bool Function::isParam(Index index) {
+  size_t size = sig.params.size();
+  assert(index < size + vars.size());
+  return index < size;
+}
+
+bool Function::isVar(Index index) {
+  auto base = getVarIndexBase();
+  assert(index < base + vars.size());
+  return index >= base;
+}
+
+bool Function::hasLocalName(Index index) const {
+  return localNames.find(index) != localNames.end();
+}
+
+Name Function::getLocalName(Index index) { return localNames.at(index); }
+
+void Function::setLocalName(Index index, Name name) {
+  assert(index < getNumLocals());
+  localNames[index] = name;
+}
+
+Name Function::getLocalNameOrDefault(Index index) {
+  auto nameIt = localNames.find(index);
+  if (nameIt != localNames.end()) {
+    return nameIt->second;
+  }
+  // this is an unnamed local
+  return Name();
+}
+
+Name Function::getLocalNameOrGeneric(Index index) {
+  auto nameIt = localNames.find(index);
+  if (nameIt != localNames.end()) {
+    return nameIt->second;
+  }
+  return Name::fromInt(index);
+}
+
+Index Function::getLocalIndex(Name name) {
+  auto iter = localIndices.find(name);
+  if (iter == localIndices.end()) {
+    Fatal() << "Function::getLocalIndex: " << name << " does not exist";
+  }
+  return iter->second;
+}
+
+Index Function::getVarIndexBase() { return sig.params.size(); }
+
+Type Function::getLocalType(Index index) {
+  auto numParams = sig.params.size();
+  if (index < numParams) {
+    return sig.params[index];
+  } else if (isVar(index)) {
+    return vars[index - numParams];
+  } else {
+    WASM_UNREACHABLE("invalid local index");
+  }
+}
+
+void Function::clearNames() { localNames.clear(); }
+
+void Function::clearDebugInfo() {
+  localIndices.clear();
+  debugLocations.clear();
+  prologLocation.clear();
+  epilogLocation.clear();
+}
+
+template<typename Map>
+typename Map::mapped_type&
+getModuleElement(Map& m, Name name, const std::string& funcName) {
+  auto iter = m.find(name);
+  if (iter == m.end()) {
+    Fatal() << "Module::" << funcName << ": " << name << " does not exist";
+  }
+  return iter->second;
+}
+
+Export* Module::getExport(Name name) {
+  return getModuleElement(exportsMap, name, "getExport");
+}
+
+Function* Module::getFunction(Name name) {
+  return getModuleElement(functionsMap, name, "getFunction");
+}
+
+Global* Module::getGlobal(Name name) {
+  return getModuleElement(globalsMap, name, "getGlobal");
+}
+
+Event* Module::getEvent(Name name) {
+  return getModuleElement(eventsMap, name, "getEvent");
+}
+
+template<typename Map>
+typename Map::mapped_type getModuleElementOrNull(Map& m, Name name) {
+  auto iter = m.find(name);
+  if (iter == m.end()) {
+    return nullptr;
+  }
+  return iter->second;
+}
+
+Export* Module::getExportOrNull(Name name) {
+  return getModuleElementOrNull(exportsMap, name);
+}
+
+Function* Module::getFunctionOrNull(Name name) {
+  return getModuleElementOrNull(functionsMap, name);
+}
+
+Global* Module::getGlobalOrNull(Name name) {
+  return getModuleElementOrNull(globalsMap, name);
+}
+
+Event* Module::getEventOrNull(Name name) {
+  return getModuleElementOrNull(eventsMap, name);
+}
+
+// TODO(@warchant): refactor all usages to use variant with unique_ptr
+template<typename Vector, typename Map, typename Elem>
+Elem* addModuleElement(Vector& v, Map& m, Elem* curr, std::string funcName) {
+  if (!curr->name.is()) {
+    Fatal() << "Module::" << funcName << ": empty name";
+  }
+  if (getModuleElementOrNull(m, curr->name)) {
+    Fatal() << "Module::" << funcName << ": " << curr->name
+            << " already exists";
+  }
+  v.push_back(std::unique_ptr<Elem>(curr));
+  m[curr->name] = curr;
+  return curr;
+}
+
+template<typename Vector, typename Map, typename Elem>
+Elem* addModuleElement(Vector& v,
+                       Map& m,
+                       std::unique_ptr<Elem> curr,
+                       std::string funcName) {
+  if (!curr->name.is()) {
+    Fatal() << "Module::" << funcName << ": empty name";
+  }
+  if (getModuleElementOrNull(m, curr->name)) {
+    Fatal() << "Module::" << funcName << ": " << curr->name
+            << " already exists";
+  }
+  auto* ret = m[curr->name] = curr.get();
+  v.push_back(std::move(curr));
+  return ret;
+}
+
+Export* Module::addExport(Export* curr) {
+  return addModuleElement(exports, exportsMap, curr, "addExport");
+}
+
+Function* Module::addFunction(Function* curr) {
+  return addModuleElement(functions, functionsMap, curr, "addFunction");
+}
+
+Global* Module::addGlobal(Global* curr) {
+  return addModuleElement(globals, globalsMap, curr, "addGlobal");
+}
+
+Event* Module::addEvent(Event* curr) {
+  return addModuleElement(events, eventsMap, curr, "addEvent");
+}
+
+Export* Module::addExport(std::unique_ptr<Export> curr) {
+  return addModuleElement(exports, exportsMap, std::move(curr), "addExport");
+}
+
+Function* Module::addFunction(std::unique_ptr<Function> curr) {
+  return addModuleElement(
+    functions, functionsMap, std::move(curr), "addFunction");
+}
+
+Global* Module::addGlobal(std::unique_ptr<Global> curr) {
+  return addModuleElement(globals, globalsMap, std::move(curr), "addGlobal");
+}
+
+Event* Module::addEvent(std::unique_ptr<Event> curr) {
+  return addModuleElement(events, eventsMap, std::move(curr), "addEvent");
+}
+
+void Module::addStart(const Name& s) { start = s; }
+
+template<typename Vector, typename Map>
+void removeModuleElement(Vector& v, Map& m, Name name) {
+  m.erase(name);
+  for (size_t i = 0; i < v.size(); i++) {
+    if (v[i]->name == name) {
+      v.erase(v.begin() + i);
+      break;
+    }
+  }
+}
+
+void Module::removeExport(Name name) {
+  removeModuleElement(exports, exportsMap, name);
+}
+void Module::removeFunction(Name name) {
+  removeModuleElement(functions, functionsMap, name);
+}
+void Module::removeGlobal(Name name) {
+  removeModuleElement(globals, globalsMap, name);
+}
+void Module::removeEvent(Name name) {
+  removeModuleElement(events, eventsMap, name);
+}
+
+template<typename Vector, typename Map, typename Elem>
+void removeModuleElements(Vector& v,
+                          Map& m,
+                          std::function<bool(Elem* elem)> pred) {
+  for (auto it = m.begin(); it != m.end();) {
+    if (pred(it->second)) {
+      it = m.erase(it);
+    } else {
+      it++;
+    }
+  }
+  v.erase(
+    std::remove_if(v.begin(), v.end(), [&](auto& e) { return pred(e.get()); }),
+    v.end());
+}
+
+void Module::removeExports(std::function<bool(Export*)> pred) {
+  removeModuleElements(exports, exportsMap, pred);
+}
+void Module::removeFunctions(std::function<bool(Function*)> pred) {
+  removeModuleElements(functions, functionsMap, pred);
+}
+void Module::removeGlobals(std::function<bool(Global*)> pred) {
+  removeModuleElements(globals, globalsMap, pred);
+}
+void Module::removeEvents(std::function<bool(Event*)> pred) {
+  removeModuleElements(events, eventsMap, pred);
+}
+
+void Module::updateMaps() {
+  functionsMap.clear();
+  for (auto& curr : functions) {
+    functionsMap[curr->name] = curr.get();
+  }
+  exportsMap.clear();
+  for (auto& curr : exports) {
+    exportsMap[curr->name] = curr.get();
+  }
+  globalsMap.clear();
+  for (auto& curr : globals) {
+    globalsMap[curr->name] = curr.get();
+  }
+  eventsMap.clear();
+  for (auto& curr : events) {
+    eventsMap[curr->name] = curr.get();
+  }
+}
+
+void Module::clearDebugInfo() { debugInfoFileNames.clear(); }
+
+} // namespace wasm
diff --git a/binaryen/src/wasm2js.h b/binaryen/src/wasm2js.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm2js.h
@@ -0,0 +1,2889 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// WebAssembly-to-JS code translator. Converts wasm functions into
+// valid JavaScript (with a somewhat asm.js-ish flavor).
+//
+
+#ifndef wasm_wasm2js_h
+#define wasm_wasm2js_h
+
+#include <cmath>
+#include <numeric>
+
+#include "abi/js.h"
+#include "asm_v_wasm.h"
+#include "asmjs/asmangle.h"
+#include "asmjs/shared-constants.h"
+#include "emscripten-optimizer/optimizer.h"
+#include "ir/branch-utils.h"
+#include "ir/effects.h"
+#include "ir/find_all.h"
+#include "ir/import-utils.h"
+#include "ir/load-utils.h"
+#include "ir/module-utils.h"
+#include "ir/names.h"
+#include "ir/table-utils.h"
+#include "ir/utils.h"
+#include "mixed_arena.h"
+#include "passes/passes.h"
+#include "support/base64.h"
+#include "support/file.h"
+#include "wasm-builder.h"
+#include "wasm-io.h"
+#include "wasm-validator.h"
+#include "wasm.h"
+
+namespace wasm {
+
+using namespace cashew;
+
+// Appends extra to block, flattening out if extra is a block as well
+void flattenAppend(Ref ast, Ref extra) {
+  int index;
+  if (ast[0] == BLOCK || ast[0] == TOPLEVEL) {
+    index = 1;
+  } else if (ast[0] == DEFUN) {
+    index = 3;
+  } else {
+    abort();
+  }
+  if (extra->isArray() && extra[0] == BLOCK) {
+    for (size_t i = 0; i < extra[1]->size(); i++) {
+      ast[index]->push_back(extra[1][i]);
+    }
+  } else {
+    ast[index]->push_back(extra);
+  }
+}
+
+// Appends extra to a chain of sequence elements
+void sequenceAppend(Ref& ast, Ref extra) {
+  if (!ast.get()) {
+    ast = extra;
+    return;
+  }
+  ast = ValueBuilder::makeSeq(ast, extra);
+}
+
+bool isTableExported(Module& wasm) {
+  if (!wasm.table.exists || wasm.table.imported()) {
+    return false;
+  }
+  for (auto& ex : wasm.exports) {
+    if (ex->kind == ExternalKind::Table && ex->value == wasm.table.name) {
+      return true;
+    }
+  }
+  return false;
+}
+
+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
+// is used to ensure that all names have a unique name but the same wasm name
+// within a scope always resolves to the same symbol.
+//
+// Export: Export names
+// Top: The main scope which contains functions and globals
+// Local: Local variables in a function.
+// Label: Label identifiers in a function
+enum class NameScope {
+  Export,
+  Top,
+  Local,
+  Label,
+  Max,
+};
+
+//
+// Wasm2JSBuilder - converts a WebAssembly module's functions into JS
+//
+// In general, JS (asm.js) => wasm is very straightforward, as can
+// be seen in asm2wasm.h. Just a single pass, plus a little
+// state bookkeeping (breakStack, etc.), and a few after-the
+// fact corrections for imports, etc. However, wasm => JS
+// is tricky because wasm has statements == expressions, or in
+// other words, things like `break` and `if` can show up
+// in places where JS can't handle them, like inside an
+// a loop's condition check. For that reason we use flat IR here.
+// We do optimize it later, to allow some nesting, but we avoid
+// non-JS-compatible nesting like block return values control
+// flow in an if condition, etc.
+//
+
+class Wasm2JSBuilder {
+public:
+  struct Flags {
+    // see wasm2js.cpp for details
+    bool debug = false;
+    bool pedantic = false;
+    bool allowAsserts = false;
+    bool emscripten = false;
+    bool deterministic = false;
+    std::string symbolsFile;
+  };
+
+  Wasm2JSBuilder(Flags f, PassOptions options_) : flags(f), options(options_) {
+    // We don't try to model wasm's trapping precisely - if we did, each load
+    // and store would need to do a check. Given that, we can just ignore
+    // implicit traps like those when optimizing. (When not optimizing, it's
+    // nice to see codegen that matches wasm more precisely.)
+    if (options.optimizeLevel > 0) {
+      options.ignoreImplicitTraps = true;
+    }
+  }
+
+  Ref processWasm(Module* wasm, Name funcName = ASM_FUNC);
+  Ref processFunction(Module* wasm, Function* func, bool standalone = false);
+  Ref processStandaloneFunction(Module* wasm, Function* func) {
+    return processFunction(wasm, func, true);
+  }
+
+  // The second pass on an expression: process it fully, generating
+  // JS
+  Ref processFunctionBody(Module* m, Function* func, bool standalone);
+
+  // Get a temp var.
+  IString getTemp(Type type, Function* func) {
+    IString ret;
+    TODO_SINGLE_COMPOUND(type);
+    if (frees[type.getBasic()].size() > 0) {
+      ret = frees[type.getBasic()].back();
+      frees[type.getBasic()].pop_back();
+    } else {
+      size_t index = temps[type.getBasic()]++;
+      ret = IString((std::string("wasm2js_") + type.toString() + "$" +
+                     std::to_string(index))
+                      .c_str(),
+                    false);
+    }
+    if (func->localIndices.find(ret) == func->localIndices.end()) {
+      Builder::addVar(func, ret, type);
+    }
+    return ret;
+  }
+
+  // Free a temp var.
+  void freeTemp(Type type, IString temp) {
+    TODO_SINGLE_COMPOUND(type);
+    frees[type.getBasic()].push_back(temp);
+  }
+
+  // Generates a mangled name from `name` within the specified scope.
+  //
+  // The goal of this function is to ensure that all identifiers in JS ar
+  // unique. Otherwise there can be clashes with locals and functions and cause
+  // unwanted name shadowing.
+  //
+  // The returned string from this function is constant for a particular `name`
+  // within a `scope`. Or in other words, the same `name` and `scope` pair will
+  // always return the same result. If `scope` changes, however, the return
+  // value may differ even if the same `name` is passed in.
+  IString fromName(Name name, NameScope scope) {
+    // TODO: checking names do not collide after mangling
+
+    // First up check our cached of mangled names to avoid doing extra work
+    // below
+    auto& map = wasmNameToMangledName[(int)scope];
+    auto it = map.find(name.c_str());
+    if (it != map.end()) {
+      return it->second;
+    }
+    // The mangled names in our scope.
+    auto& scopeMangledNames = mangledNames[(int)scope];
+    // In some cases (see below) we need to also check the Top scope.
+    auto& topMangledNames = mangledNames[int(NameScope::Top)];
+
+    // This is the first time we've seen the `name` and `scope` pair. Generate a
+    // globally unique name based on `name` and then register that in our cache
+    // and return it.
+    //
+    // Identifiers here generated are of the form `${name}_${n}` where `_${n}`
+    // is omitted if `n==0` and otherwise `n` is just looped over to find the
+    // next unused identifier.
+    IString ret;
+    for (int i = 0;; i++) {
+      std::ostringstream out;
+      out << name.c_str();
+      if (i > 0) {
+        out << "_" << i;
+      }
+      auto mangled = asmangle(out.str());
+      ret = stringToIString(mangled);
+      if (scopeMangledNames.count(ret)) {
+        // When export names collide things may be confusing, as this is
+        // observable externally by the person using the JS. Report a warning.
+        if (scope == NameScope::Export) {
+          std::cerr << "wasm2js: warning: export names colliding: " << mangled
+                    << '\n';
+        }
+        continue;
+      }
+      // The Local scope is special: a Local name must not collide with a Top
+      // name, as they are in a single namespace in JS and can conflict:
+      //
+      // function foo(bar) {
+      //   var bar = 0;
+      // }
+      // function bar() { ..
+      if (scope == NameScope::Local && topMangledNames.count(ret)) {
+        continue;
+      }
+      // We found a good name, use it.
+      scopeMangledNames.insert(ret);
+      map[name.c_str()] = ret;
+      return ret;
+    }
+  }
+
+private:
+  Flags flags;
+  PassOptions options;
+
+  // How many temp vars we need
+  std::vector<size_t> temps; // type => num temps
+  // Which are currently free to use
+  std::vector<std::vector<IString>> frees; // type => list of free names
+
+  // Mangled names cache by interned names.
+  // Utilizes the usually reused underlying cstring's pointer as the key.
+  std::unordered_map<const char*, IString>
+    wasmNameToMangledName[(int)NameScope::Max];
+  // Set of all mangled names in each scope.
+  std::unordered_set<IString> mangledNames[(int)NameScope::Max];
+
+  // If a function is callable from outside, we'll need to cast the inputs
+  // and our return value. Otherwise, internally, casts are only needed
+  // on operations.
+  std::unordered_set<Name> functionsCallableFromOutside;
+
+  void addBasics(Ref ast, Module* wasm);
+  void addFunctionImport(Ref ast, Function* import);
+  void addGlobalImport(Ref ast, Global* import);
+  void addTable(Ref ast, Module* wasm);
+  void addStart(Ref ast, Module* wasm);
+  void addExports(Ref ast, Module* wasm);
+  void addGlobal(Ref ast, Global* global);
+  void addMemoryFuncs(Ref ast, Module* wasm);
+  void addMemoryGrowFunc(Ref ast, Module* wasm);
+
+  Wasm2JSBuilder() = delete;
+  Wasm2JSBuilder(const Wasm2JSBuilder&) = delete;
+  Wasm2JSBuilder& operator=(const Wasm2JSBuilder&) = delete;
+};
+
+Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) {
+  // Scan the wasm for important things.
+  for (auto& exp : wasm->exports) {
+    if (exp->kind == ExternalKind::Function) {
+      functionsCallableFromOutside.insert(exp->value);
+    }
+  }
+  for (auto& segment : wasm->table.segments) {
+    for (auto name : segment.data) {
+      functionsCallableFromOutside.insert(name);
+    }
+  }
+
+  // Ensure the scratch memory helpers.
+  // If later on they aren't needed, we'll clean them up.
+  ABI::wasm2js::ensureHelpers(wasm);
+
+  // Process the code, and optimize if relevant.
+  // First, do the lowering to a JS-friendly subset.
+  {
+    PassRunner runner(wasm, options);
+    runner.add(make_unique<AutoDrop>());
+    // TODO: only legalize if necessary - emscripten would already do so, and
+    //       likely other toolchains. but spec test suite needs that.
+    runner.add("legalize-js-interface");
+    // First up remove as many non-JS operations we can, including things like
+    // 64-bit integer multiplication/division, `f32.nearest` instructions, etc.
+    // This may inject intrinsics which use i64 so it needs to be run before the
+    // i64-to-i32 lowering pass.
+    runner.add("remove-non-js-ops");
+    // Currently the i64-to-32 lowering pass requires that `flatten` be run
+    // before it to produce correct code. For some more details about this see
+    // #1480
+    runner.add("flatten");
+    runner.add("i64-to-i32-lowering");
+    runner.add("alignment-lowering");
+    // Next, optimize that as best we can. This should not generate
+    // non-JS-friendly things.
+    if (options.optimizeLevel > 0) {
+      // It is especially import to propagate constants after the lowering.
+      // However, this can be a slow operation, especially after flattening;
+      // some local simplification helps.
+      if (options.optimizeLevel >= 3 || options.shrinkLevel >= 1) {
+        runner.add("simplify-locals-nonesting");
+        runner.add("precompute-propagate");
+        // Avoiding reinterpretation is helped by propagation. We also run
+        // it later down as default optimizations help as well.
+        runner.add("avoid-reinterprets");
+      }
+      runner.addDefaultOptimizationPasses();
+      runner.add("avoid-reinterprets");
+    }
+    // Finally, get the code into the flat form we need for wasm2js itself, and
+    // optimize that a little in a way that keeps that property.
+    runner.add("flatten");
+    // Regardless of optimization level, run some simple optimizations to undo
+    // some of the effects of flattening.
+    runner.add("simplify-locals-notee-nostructure");
+    // Some operations can be very slow if we didn't run full optimizations
+    // earlier, so don't run them automatically.
+    if (options.optimizeLevel > 0) {
+      runner.add("remove-unused-names");
+      runner.add("merge-blocks");
+      runner.add("reorder-locals");
+      runner.add("coalesce-locals");
+    }
+    runner.add("reorder-locals");
+    runner.add("vacuum");
+    runner.add("remove-unused-module-elements");
+    // DCE at the end to make sure all IR nodes have valid types for conversion
+    // to JS, and not unreachable.
+    runner.add("dce");
+    runner.setDebug(flags.debug);
+    runner.run();
+  }
+
+  if (flags.symbolsFile.size() > 0) {
+    Output out(flags.symbolsFile, wasm::Flags::Text);
+    Index i = 0;
+    for (auto& func : wasm->functions) {
+      out.getStream() << i++ << ':' << func->name.str << '\n';
+    }
+  }
+
+#ifndef NDEBUG
+  if (!WasmValidator().validate(*wasm)) {
+    WasmPrinter::printModule(wasm);
+    Fatal() << "error in validating wasm2js output";
+  }
+#endif
+
+  Ref ret = ValueBuilder::makeToplevel();
+  Ref asmFunc = ValueBuilder::makeFunction(funcName);
+  ret[1]->push_back(asmFunc);
+  ValueBuilder::appendArgumentToFunction(asmFunc, GLOBAL);
+  ValueBuilder::appendArgumentToFunction(asmFunc, ENV);
+
+  if (wasm->memory.exists) {
+    if (wasm->memory.imported()) {
+      // find memory and buffer in imports
+      Ref theVar = ValueBuilder::makeVar();
+      asmFunc[3]->push_back(theVar);
+      ValueBuilder::appendToVar(
+        theVar,
+        "memory",
+        ValueBuilder::makeDot(ValueBuilder::makeName(ENV),
+                              ValueBuilder::makeName(wasm->memory.base)));
+
+      // Assign `buffer = memory.buffer`
+      Ref buf = ValueBuilder::makeVar();
+      asmFunc[3]->push_back(buf);
+      ValueBuilder::appendToVar(
+        buf,
+        BUFFER,
+        ValueBuilder::makeDot(ValueBuilder::makeName("memory"),
+                              ValueBuilder::makeName("buffer")));
+
+      // If memory is growable, override the imported memory's grow method to
+      // ensure so that when grow is called from the output it works as expected
+      if (wasm->memory.max > wasm->memory.initial) {
+        asmFunc[3]->push_back(
+          ValueBuilder::makeStatement(ValueBuilder::makeBinary(
+            ValueBuilder::makeDot(ValueBuilder::makeName("memory"),
+                                  ValueBuilder::makeName("grow")),
+            SET,
+            ValueBuilder::makeName(WASM_MEMORY_GROW))));
+      }
+    } else {
+      // find memory as third argument
+      ValueBuilder::appendArgumentToFunction(asmFunc, BUFFER);
+    }
+  }
+
+  // add table import
+  if (wasm->table.exists && wasm->table.imported()) {
+    Ref theVar = ValueBuilder::makeVar();
+    asmFunc[3]->push_back(theVar);
+    ValueBuilder::appendToVar(
+      theVar,
+      FUNCTION_TABLE,
+      ValueBuilder::makeDot(ValueBuilder::makeName(ENV), wasm->table.base));
+  }
+  // create heaps, etc
+  addBasics(asmFunc[3], wasm);
+  ModuleUtils::iterImportedFunctions(
+    *wasm, [&](Function* import) { addFunctionImport(asmFunc[3], import); });
+  ModuleUtils::iterImportedGlobals(
+    *wasm, [&](Global* import) { addGlobalImport(asmFunc[3], import); });
+
+  // Note the names of functions. We need to do this here as when generating
+  // mangled local names we need them not to conflict with these (see fromName)
+  // so we can't wait until we parse each function to note its name.
+  for (auto& f : wasm->functions) {
+    fromName(f->name, NameScope::Top);
+  }
+
+  // globals
+  bool generateFetchHighBits = false;
+  ModuleUtils::iterDefinedGlobals(*wasm, [&](Global* global) {
+    addGlobal(asmFunc[3], global);
+    if (flags.allowAsserts && global->name == INT64_TO_32_HIGH_BITS) {
+      generateFetchHighBits = true;
+    }
+  });
+  if (flags.emscripten) {
+    asmFunc[3]->push_back(
+      ValueBuilder::makeName("// EMSCRIPTEN_START_FUNCS\n"));
+  }
+  // functions
+  ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) {
+    asmFunc[3]->push_back(processFunction(wasm, func));
+  });
+  if (generateFetchHighBits) {
+    Builder builder(*wasm);
+    asmFunc[3]->push_back(
+      processFunction(wasm,
+                      wasm->addFunction(builder.makeFunction(
+                        WASM_FETCH_HIGH_BITS,
+                        Signature(Type::none, Type::i32),
+                        {},
+                        builder.makeReturn(builder.makeGlobalGet(
+                          INT64_TO_32_HIGH_BITS, Type::i32))))));
+    auto e = new Export();
+    e->name = WASM_FETCH_HIGH_BITS;
+    e->value = WASM_FETCH_HIGH_BITS;
+    e->kind = ExternalKind::Function;
+    wasm->addExport(e);
+  }
+  if (flags.emscripten) {
+    asmFunc[3]->push_back(ValueBuilder::makeName("// EMSCRIPTEN_END_FUNCS\n"));
+  }
+
+  addTable(asmFunc[3], wasm);
+  addStart(asmFunc[3], wasm);
+  addExports(asmFunc[3], wasm);
+  return ret;
+}
+
+void Wasm2JSBuilder::addBasics(Ref ast, Module* wasm) {
+  if (wasm->memory.exists) {
+    // heaps, var HEAP8 = new global.Int8Array(buffer); etc
+    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))));
+    };
+    addHeap(HEAP8, INT8ARRAY);
+    addHeap(HEAP16, INT16ARRAY);
+    addHeap(HEAP32, INT32ARRAY);
+    addHeap(HEAPU8, UINT8ARRAY);
+    addHeap(HEAPU16, UINT16ARRAY);
+    addHeap(HEAPU32, UINT32ARRAY);
+    addHeap(HEAPF32, FLOAT32ARRAY);
+    addHeap(HEAPF64, FLOAT64ARRAY);
+  }
+  // core asm.js imports
+  auto addMath = [&](IString name, IString base) {
+    Ref theVar = ValueBuilder::makeVar();
+    ast->push_back(theVar);
+    ValueBuilder::appendToVar(
+      theVar,
+      name,
+      ValueBuilder::makeDot(
+        ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), MATH), base));
+  };
+  addMath(MATH_IMUL, IMUL);
+  addMath(MATH_FROUND, FROUND);
+  addMath(MATH_ABS, ABS);
+  addMath(MATH_CLZ32, CLZ32);
+  addMath(MATH_MIN, MIN);
+  addMath(MATH_MAX, MAX);
+  addMath(MATH_FLOOR, FLOOR);
+  addMath(MATH_CEIL, CEIL);
+  addMath(MATH_SQRT, SQRT);
+  // abort function
+  Ref abortVar = ValueBuilder::makeVar();
+  ast->push_back(abortVar);
+  ValueBuilder::appendToVar(
+    abortVar,
+    "abort",
+    ValueBuilder::makeDot(ValueBuilder::makeName(ENV), ABORT_FUNC));
+  // TODO: this shouldn't be needed once we stop generating literal asm.js code
+  // NaN and Infinity variables
+  Ref nanVar = ValueBuilder::makeVar();
+  ast->push_back(nanVar);
+  ValueBuilder::appendToVar(
+    nanVar,
+    "nan",
+    ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), "NaN"));
+  Ref infinityVar = ValueBuilder::makeVar();
+  ast->push_back(infinityVar);
+  ValueBuilder::appendToVar(
+    infinityVar,
+    "infinity",
+    ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), "Infinity"));
+}
+
+void Wasm2JSBuilder::addFunctionImport(Ref ast, Function* import) {
+  // The scratch memory helpers are emitted in the glue, see code and comments
+  // below.
+  if (ABI::wasm2js::isHelper(import->base)) {
+    return;
+  }
+  Ref theVar = ValueBuilder::makeVar();
+  ast->push_back(theVar);
+  // TODO: handle nested module imports
+  Ref module = ValueBuilder::makeName(ENV);
+  ValueBuilder::appendToVar(
+    theVar,
+    fromName(import->name, NameScope::Top),
+    ValueBuilder::makeDot(module, fromName(import->base, NameScope::Top)));
+}
+
+void Wasm2JSBuilder::addGlobalImport(Ref ast, Global* import) {
+  Ref theVar = ValueBuilder::makeVar();
+  ast->push_back(theVar);
+  // TODO: handle nested module imports
+  Ref module = ValueBuilder::makeName(ENV);
+  Ref value =
+    ValueBuilder::makeDot(module, fromName(import->base, NameScope::Top));
+  if (import->type == Type::i32) {
+    value = makeAsmCoercion(value, ASM_INT);
+  }
+  ValueBuilder::appendToVar(
+    theVar, fromName(import->name, NameScope::Top), value);
+}
+
+void Wasm2JSBuilder::addTable(Ref ast, Module* wasm) {
+  if (!wasm->table.exists) {
+    return;
+  }
+
+  bool perElementInit = false;
+
+  // Emit a simple flat table as a JS array literal. Otherwise,
+  // emit assignments separately for each index.
+  Ref theArray = ValueBuilder::makeArray();
+  if (!wasm->table.imported()) {
+    TableUtils::FlatTable flat(wasm->table);
+    if (flat.valid) {
+      Name null("null");
+      for (auto& name : flat.names) {
+        if (name.is()) {
+          name = fromName(name, NameScope::Top);
+        } else {
+          name = null;
+        }
+        ValueBuilder::appendToArray(theArray, ValueBuilder::makeName(name));
+      }
+    } else {
+      perElementInit = true;
+      Ref initial =
+        ValueBuilder::makeInt(Address::address32_t(wasm->table.initial.addr));
+      theArray = ValueBuilder::makeNew(
+        ValueBuilder::makeCall(IString("Array"), initial));
+    }
+  } else {
+    perElementInit = true;
+  }
+
+  if (isTableExported(*wasm)) {
+    // If the table is exported use a fake WebAssembly.Table object
+    // We don't handle the case where a table is both imported and exported.
+    if (wasm->table.imported()) {
+      Fatal() << "wasm2js doesn't support a table that is both imported and "
+                 "exported\n";
+    }
+    Ref theVar = ValueBuilder::makeVar();
+    ast->push_back(theVar);
+
+    Ref table = ValueBuilder::makeCall(IString("Table"), theArray);
+    ValueBuilder::appendToVar(theVar, FUNCTION_TABLE, table);
+  } else if (!wasm->table.imported()) {
+    // Otherwise if the table is internal (neither imported not exported).
+    // Just use a plain array in this case, avoiding the Table.
+    Ref theVar = ValueBuilder::makeVar();
+    ast->push_back(theVar);
+    ValueBuilder::appendToVar(theVar, FUNCTION_TABLE, theArray);
+  }
+
+  if (perElementInit) {
+    // TODO: optimize for size
+    for (auto& segment : wasm->table.segments) {
+      auto offset = segment.offset;
+      for (Index i = 0; i < segment.data.size(); i++) {
+        Ref index;
+        if (auto* c = offset->dynCast<Const>()) {
+          index = ValueBuilder::makeInt(c->value.geti32() + i);
+        } else if (auto* get = offset->dynCast<GlobalGet>()) {
+          index = ValueBuilder::makeBinary(
+            ValueBuilder::makeName(stringToIString(asmangle(get->name.str))),
+            PLUS,
+            ValueBuilder::makeNum(i));
+        } else {
+          WASM_UNREACHABLE("unexpected expr type");
+        }
+        ast->push_back(ValueBuilder::makeStatement(ValueBuilder::makeBinary(
+          ValueBuilder::makeSub(ValueBuilder::makeName(FUNCTION_TABLE), index),
+          SET,
+          ValueBuilder::makeName(fromName(segment.data[i], NameScope::Top)))));
+      }
+    }
+  }
+}
+
+void Wasm2JSBuilder::addStart(Ref ast, Module* wasm) {
+  if (wasm->start.is()) {
+    ast->push_back(
+      ValueBuilder::makeCall(fromName(wasm->start, NameScope::Top)));
+  }
+}
+
+void Wasm2JSBuilder::addExports(Ref ast, Module* wasm) {
+  Ref exports = ValueBuilder::makeObject();
+  for (auto& export_ : wasm->exports) {
+    switch (export_->kind) {
+      case ExternalKind::Function: {
+        ValueBuilder::appendToObjectWithQuotes(
+          exports,
+          fromName(export_->name, NameScope::Export),
+          ValueBuilder::makeName(fromName(export_->value, NameScope::Top)));
+        break;
+      }
+      case ExternalKind::Memory: {
+        Ref descs = ValueBuilder::makeObject();
+        Ref growDesc = ValueBuilder::makeObject();
+        ValueBuilder::appendToObjectWithQuotes(
+          descs, IString("grow"), growDesc);
+        if (wasm->memory.max > wasm->memory.initial) {
+          ValueBuilder::appendToObjectWithQuotes(
+            growDesc,
+            IString("value"),
+            ValueBuilder::makeName(WASM_MEMORY_GROW));
+        }
+        Ref bufferDesc = ValueBuilder::makeObject();
+        Ref bufferGetter = ValueBuilder::makeFunction(IString(""));
+        bufferGetter[3]->push_back(
+          ValueBuilder::makeReturn(ValueBuilder::makeName(BUFFER)));
+        ValueBuilder::appendToObjectWithQuotes(
+          bufferDesc, IString("get"), bufferGetter);
+        ValueBuilder::appendToObjectWithQuotes(
+          descs, IString("buffer"), bufferDesc);
+        Ref memory = ValueBuilder::makeCall(
+          ValueBuilder::makeDot(ValueBuilder::makeName(IString("Object")),
+                                IString("create")),
+          ValueBuilder::makeDot(ValueBuilder::makeName(IString("Object")),
+                                IString("prototype")));
+        ValueBuilder::appendToCall(memory, descs);
+        ValueBuilder::appendToObjectWithQuotes(
+          exports, fromName(export_->name, NameScope::Export), memory);
+        break;
+      }
+      case ExternalKind::Table: {
+        ValueBuilder::appendToObjectWithQuotes(
+          exports,
+          fromName(export_->name, NameScope::Export),
+          ValueBuilder::makeName(FUNCTION_TABLE));
+        break;
+      }
+      case ExternalKind::Global: {
+        ValueBuilder::appendToObjectWithQuotes(
+          exports,
+          fromName(export_->name, NameScope::Export),
+          ValueBuilder::makeName(fromName(export_->value, NameScope::Top)));
+        break;
+      }
+      case ExternalKind::Event:
+      case ExternalKind::Invalid:
+        Fatal() << "unsupported export type: " << export_->name << "\n";
+    }
+  }
+  if (wasm->memory.exists) {
+    addMemoryFuncs(ast, wasm);
+  }
+  ast->push_back(
+    ValueBuilder::makeStatement(ValueBuilder::makeReturn(exports)));
+}
+
+void Wasm2JSBuilder::addGlobal(Ref ast, Global* global) {
+  if (auto* const_ = global->init->dynCast<Const>()) {
+    Ref theValue;
+    TODO_SINGLE_COMPOUND(const_->type);
+    switch (const_->type.getBasic()) {
+      case Type::i32: {
+        theValue = ValueBuilder::makeInt(const_->value.geti32());
+        break;
+      }
+      case Type::f32: {
+        theValue = ValueBuilder::makeCall(
+          MATH_FROUND,
+          makeAsmCoercion(ValueBuilder::makeDouble(const_->value.getf32()),
+                          ASM_DOUBLE));
+        break;
+      }
+      case Type::f64: {
+        theValue = makeAsmCoercion(
+          ValueBuilder::makeDouble(const_->value.getf64()), ASM_DOUBLE);
+        break;
+      }
+      default: {
+        assert(false && "Top const type not supported");
+      }
+    }
+    Ref theVar = ValueBuilder::makeVar();
+    ast->push_back(theVar);
+    ValueBuilder::appendToVar(
+      theVar, fromName(global->name, NameScope::Top), theValue);
+  } else if (auto* get = global->init->dynCast<GlobalGet>()) {
+    Ref theVar = ValueBuilder::makeVar();
+    ast->push_back(theVar);
+    ValueBuilder::appendToVar(
+      theVar,
+      fromName(global->name, NameScope::Top),
+      ValueBuilder::makeName(fromName(get->name, NameScope::Top)));
+  } else {
+    assert(false && "Top init type not supported");
+  }
+}
+
+Ref Wasm2JSBuilder::processFunction(Module* m,
+                                    Function* func,
+                                    bool standaloneFunction) {
+  if (standaloneFunction) {
+    // We are only printing a function, not a whole module. Prepare it for
+    // translation now (if there were a module, we'd have done this for all
+    // functions in parallel, earlier).
+    PassRunner runner(m);
+    // We only run a subset of all passes here. TODO: create a full valid module
+    // for each assertion body.
+    runner.add("flatten");
+    runner.add("simplify-locals-notee-nostructure");
+    runner.add("reorder-locals");
+    runner.add("remove-unused-names");
+    runner.add("vacuum");
+    runner.runOnFunction(func);
+  }
+
+  // We will be symbolically referring to all variables in the function, so make
+  // sure that everything has a name and it's unique.
+  Names::ensureNames(func);
+  Ref ret = ValueBuilder::makeFunction(fromName(func->name, NameScope::Top));
+  frees.clear();
+  frees.resize(std::max(Type::i32, std::max(Type::f32, Type::f64)) + 1);
+  temps.clear();
+  temps.resize(std::max(Type::i32, std::max(Type::f32, Type::f64)) + 1);
+  temps[Type::i32] = temps[Type::f32] = temps[Type::f64] = 0;
+  // arguments
+  bool needCoercions = options.optimizeLevel == 0 || standaloneFunction ||
+                       functionsCallableFromOutside.count(func->name);
+  for (Index i = 0; i < func->getNumParams(); i++) {
+    IString name = fromName(func->getLocalNameOrGeneric(i), NameScope::Local);
+    ValueBuilder::appendArgumentToFunction(ret, name);
+    if (needCoercions) {
+      ret[3]->push_back(ValueBuilder::makeStatement(ValueBuilder::makeBinary(
+        ValueBuilder::makeName(name),
+        SET,
+        makeAsmCoercion(ValueBuilder::makeName(name),
+                        wasmToAsmType(func->getLocalType(i))))));
+    }
+  }
+  Ref theVar = ValueBuilder::makeVar();
+  size_t theVarIndex = ret[3]->size();
+  ret[3]->push_back(theVar);
+  // body
+  flattenAppend(ret, processFunctionBody(m, func, standaloneFunction));
+  // vars, including new temp vars
+  for (Index i = func->getVarIndexBase(); i < func->getNumLocals(); i++) {
+    ValueBuilder::appendToVar(
+      theVar,
+      fromName(func->getLocalNameOrGeneric(i), NameScope::Local),
+      makeAsmCoercedZero(wasmToAsmType(func->getLocalType(i))));
+  }
+  if (theVar[1]->size() == 0) {
+    ret[3]->splice(theVarIndex, 1);
+  }
+  // checks: all temp vars should be free at the end
+  assert(frees[Type::i32].size() == temps[Type::i32]);
+  assert(frees[Type::f32].size() == temps[Type::f32]);
+  assert(frees[Type::f64].size() == temps[Type::f64]);
+  return ret;
+}
+
+Ref Wasm2JSBuilder::processFunctionBody(Module* m,
+                                        Function* func,
+                                        bool standaloneFunction) {
+  // Switches are tricky to handle - in wasm they often come with
+  // massively-nested "towers" of blocks, which if naively translated
+  // to JS may exceed parse recursion limits of VMs. Therefore even when
+  // not optimizing we work hard to emit minimal and minimally-nested
+  // switches.
+  // We do so by pre-scanning for br_tables and noting which of their
+  // targets can be hoisted up into them, e.g.
+  //
+  // (block $a
+  //  (block $b
+  //   (block $c
+  //    (block $d
+  //     (block $e
+  //      (br_table $a $b $c $d $e (..))
+  //     )
+  //     ;; code X (for block $e)
+  //     ;; implicit fallthrough - can be done in the switch too
+  //    )
+  //    ;; code Y
+  //    (br $c) ;; branch which is identical to a fallthrough
+  //   )
+  //   ;; code Z
+  //   (br $a) ;; skip some blocks - can't do this in a switch!
+  //  )
+  //  ;; code W
+  // )
+  //
+  // Every branch we see is a potential hazard - all targets must not
+  // be optimized into the switch, since they must be reached normally,
+  // unless they happen to be right after us, in which case it's just
+  // a fallthrough anyhow.
+  struct SwitchProcessor : public ExpressionStackWalker<SwitchProcessor> {
+    // A list of expressions we don't need to emit, as we are handling them
+    // in another way.
+    std::set<Expression*> unneededExpressions;
+
+    struct SwitchCase {
+      Name target;
+      std::vector<Expression*> code;
+      SwitchCase(Name target) : target(target) {}
+    };
+
+    // The switch cases we found that we can hoist up.
+    std::map<Switch*, std::vector<SwitchCase>> hoistedSwitchCases;
+
+    void visitSwitch(Switch* brTable) {
+      Index i = expressionStack.size() - 1;
+      assert(expressionStack[i] == brTable);
+      // A set of names we must stop at, since we've seen branches to them.
+      std::set<Name> namesBranchedTo;
+      while (1) {
+        // Stop if we are at the top level.
+        if (i == 0) {
+          break;
+        }
+        i--;
+        auto* child = expressionStack[i + 1];
+        auto* curr = expressionStack[i];
+        // Stop if the current node is not a block with the child in the
+        // first position, i.e., the classic switch pattern.
+        auto* block = curr->dynCast<Block>();
+        if (!block || block->list[0] != child) {
+          break;
+        }
+        // Ignore the case of a name-less block for simplicity (merge-blocks
+        // would have removed it).
+        if (!block->name.is()) {
+          break;
+        }
+        // If we have already seen this block, stop here.
+        if (unneededExpressions.count(block)) {
+          // XXX FIXME we should probably abort the entire optimization
+          break;
+        }
+        auto& list = block->list;
+        if (child == brTable) {
+          // Nothing more to do here (we can in fact skip any code til
+          // the parent block).
+          continue;
+        }
+        // Ok, we are a block and our child in the first position is a
+        // block, and the neither is branched to - unless maybe the child
+        // branches to the parent, check that. Note how we treat the
+        // final element which may be a break that is a fallthrough.
+        Expression* unneededBr = nullptr;
+        for (Index j = 1; j < list.size(); j++) {
+          auto* item = list[j];
+          auto newBranches = BranchUtils::getExitingBranches(item);
+          if (auto* br = item->dynCast<Break>()) {
+            if (j == list.size() - 1) {
+              if (!br->condition && br->name == block->name) {
+                // This is a natural, unnecessary-to-emit fallthrough.
+                unneededBr = br;
+                break;
+              }
+            }
+          }
+          namesBranchedTo.insert(newBranches.begin(), newBranches.end());
+        }
+        if (namesBranchedTo.count(block->name)) {
+          break;
+        }
+        // We can move code after the child (reached by branching on the
+        // child) into the switch.
+        auto* childBlock = child->cast<Block>();
+        hoistedSwitchCases[brTable].emplace_back(childBlock->name);
+        SwitchCase& case_ = hoistedSwitchCases[brTable].back();
+        for (Index j = 1; j < list.size(); j++) {
+          auto* item = list[j];
+          if (item != unneededBr) {
+            case_.code.push_back(item);
+          }
+        }
+        list.resize(1);
+        // Finally, mark the block as unneeded outside the switch.
+        unneededExpressions.insert(childBlock);
+      }
+    }
+  };
+
+  struct ExpressionProcessor
+    : public OverriddenVisitor<ExpressionProcessor, Ref> {
+    Wasm2JSBuilder* parent;
+    IString result; // TODO: remove
+    Function* func;
+    Module* module;
+    bool standaloneFunction;
+
+    SwitchProcessor switchProcessor;
+
+    ExpressionProcessor(Wasm2JSBuilder* parent,
+                        Module* m,
+                        Function* func,
+                        bool standaloneFunction)
+      : parent(parent), func(func), module(m),
+        standaloneFunction(standaloneFunction) {}
+
+    Ref process() {
+      switchProcessor.walk(func->body);
+      return visit(func->body, NO_RESULT);
+    }
+
+    // A scoped temporary variable.
+    struct ScopedTemp {
+      Wasm2JSBuilder* parent;
+      Type type;
+      IString temp; // TODO: switch to indexes; avoid names
+      bool needFree;
+      // @param possible if provided, this is a variable we can use as our temp.
+      //                 it has already been allocated in a higher scope, and we
+      //                 can just assign to it as our result is going there
+      //                 anyhow.
+      ScopedTemp(Type type,
+                 Wasm2JSBuilder* parent,
+                 Function* func,
+                 IString possible = NO_RESULT)
+        : parent(parent), type(type) {
+        assert(possible != EXPRESSION_RESULT);
+        if (possible == NO_RESULT) {
+          temp = parent->getTemp(type, func);
+          needFree = true;
+        } else {
+          temp = possible;
+          needFree = false;
+        }
+      }
+      ~ScopedTemp() {
+        if (needFree) {
+          parent->freeTemp(type, temp);
+        }
+      }
+
+      IString getName() { return temp; }
+      Ref getAstName() { return ValueBuilder::makeName(temp); }
+    };
+
+    Ref visit(Expression* curr, IString nextResult) {
+      IString old = result;
+      result = nextResult;
+      Ref ret = OverriddenVisitor::visit(curr);
+      // keep it consistent for the rest of this frame, which may call visit on
+      // multiple children
+      result = old;
+      return ret;
+    }
+
+    Ref visit(Expression* curr, ScopedTemp& temp) {
+      return visit(curr, temp.temp);
+    }
+
+    Ref visitAndAssign(Expression* curr, IString result) {
+      assert(result != NO_RESULT);
+      Ref ret = visit(curr, result);
+      return ValueBuilder::makeStatement(
+        ValueBuilder::makeBinary(ValueBuilder::makeName(result), SET, ret));
+    }
+
+    Ref visitAndAssign(Expression* curr, ScopedTemp& temp) {
+      return visitAndAssign(curr, temp.getName());
+    }
+
+    // Expressions with control flow turn into a block, which we must
+    // then handle, even if we are an expression.
+    bool isBlock(Ref ast) { return !!ast && ast->isArray() && ast[0] == BLOCK; }
+
+    Ref blockify(Ref ast) {
+      if (isBlock(ast)) {
+        return ast;
+      }
+      Ref ret = ValueBuilder::makeBlock();
+      ret[1]->push_back(ValueBuilder::makeStatement(ast));
+      return ret;
+    }
+
+    // Breaks to the top of a loop should be emitted as continues, to that
+    // loop's main label
+    std::unordered_set<Name> continueLabels;
+
+    IString fromName(Name name, NameScope scope) {
+      return parent->fromName(name, scope);
+    }
+
+    // Visitors
+
+    Ref visitBlock(Block* curr) {
+      if (switchProcessor.unneededExpressions.count(curr)) {
+        // We have had our tail hoisted into a switch that is nested in our
+        // first position, so we don't need to emit that code again, or
+        // ourselves in fact.
+        return visit(curr->list[0], NO_RESULT);
+      }
+      Ref ret = ValueBuilder::makeBlock();
+      size_t size = curr->list.size();
+      for (size_t i = 0; i < size; i++) {
+        flattenAppend(
+          ret, ValueBuilder::makeStatement(visit(curr->list[i], NO_RESULT)));
+      }
+      if (curr->name.is()) {
+        ret =
+          ValueBuilder::makeLabel(fromName(curr->name, NameScope::Label), ret);
+      }
+      return ret;
+    }
+
+    Ref visitIf(If* curr) {
+      Ref condition = visit(curr->condition, EXPRESSION_RESULT);
+      Ref ifTrue = visit(curr->ifTrue, NO_RESULT);
+      Ref ifFalse;
+      if (curr->ifFalse) {
+        ifFalse = visit(curr->ifFalse, NO_RESULT);
+      }
+      return ValueBuilder::makeIf(condition, ifTrue, ifFalse); // simple if
+    }
+
+    Ref visitLoop(Loop* curr) {
+      Name asmLabel = curr->name;
+      continueLabels.insert(asmLabel);
+      Ref body = visit(curr->body, result);
+      // if we can reach the end of the block, we must leave the while (1) loop
+      if (curr->body->type != Type::unreachable) {
+        assert(curr->body->type == Type::none); // flat IR
+        body = blockify(body);
+        flattenAppend(
+          body, ValueBuilder::makeBreak(fromName(asmLabel, NameScope::Label)));
+      }
+      Ref ret = ValueBuilder::makeWhile(ValueBuilder::makeInt(1), body);
+      return ValueBuilder::makeLabel(fromName(asmLabel, NameScope::Label), ret);
+    }
+
+    Ref makeBreakOrContinue(Name name) {
+      if (continueLabels.count(name)) {
+        return ValueBuilder::makeContinue(fromName(name, NameScope::Label));
+      } else {
+        return ValueBuilder::makeBreak(fromName(name, NameScope::Label));
+      }
+    }
+
+    Ref visitBreak(Break* curr) {
+      if (curr->condition) {
+        // we need an equivalent to an if here, so use that code
+        Break fakeBreak = *curr;
+        fakeBreak.condition = nullptr;
+        If fakeIf;
+        fakeIf.condition = curr->condition;
+        fakeIf.ifTrue = &fakeBreak;
+        return visit(&fakeIf, result);
+      }
+      return makeBreakOrContinue(curr->name);
+    }
+
+    Expression* defaultBody = nullptr; // default must be last in asm.js
+
+    Ref visitSwitch(Switch* curr) {
+      // Even without optimizations, we work hard here to emit minimal and
+      // especially minimally-nested code, since otherwise we may get block
+      // nesting of a size that JS engines can't handle.
+      Ref condition = visit(curr->condition, EXPRESSION_RESULT);
+      Ref theSwitch =
+        ValueBuilder::makeSwitch(makeAsmCoercion(condition, ASM_INT));
+      // First, group the switch targets.
+      std::map<Name, std::vector<Index>> targetIndexes;
+      for (size_t i = 0; i < curr->targets.size(); i++) {
+        targetIndexes[curr->targets[i]].push_back(i);
+      }
+      // Emit first any hoisted groups.
+      auto& hoistedCases = switchProcessor.hoistedSwitchCases[curr];
+      std::set<Name> emittedTargets;
+      bool hoistedEndsWithUnreachable = false;
+      for (auto& case_ : hoistedCases) {
+        auto target = case_.target;
+        auto& code = case_.code;
+        emittedTargets.insert(target);
+        if (target != curr->default_) {
+          auto& indexes = targetIndexes[target];
+          for (auto i : indexes) {
+            ValueBuilder::appendCaseToSwitch(theSwitch,
+                                             ValueBuilder::makeNum(i));
+          }
+        } else {
+          ValueBuilder::appendDefaultToSwitch(theSwitch);
+        }
+        for (auto* c : code) {
+          ValueBuilder::appendCodeToSwitch(
+            theSwitch, blockify(visit(c, NO_RESULT)), false);
+          hoistedEndsWithUnreachable = c->type == Type::unreachable;
+        }
+      }
+      // After the hoisted cases, if any remain we must make sure not to
+      // fall through into them. If no code was hoisted, this is unnecessary,
+      // and if the hoisted code ended with an unreachable it also is not
+      // necessary.
+      bool stoppedFurtherFallthrough = false;
+      auto stopFurtherFallthrough = [&]() {
+        if (!stoppedFurtherFallthrough && !hoistedCases.empty() &&
+            !hoistedEndsWithUnreachable) {
+          stoppedFurtherFallthrough = true;
+          ValueBuilder::appendCodeToSwitch(
+            theSwitch, blockify(ValueBuilder::makeBreak(IString())), false);
+        }
+      };
+
+      // Emit any remaining groups by just emitting branches to their code,
+      // which will appear outside the switch.
+      for (auto& pair : targetIndexes) {
+        auto target = pair.first;
+        auto& indexes = pair.second;
+        if (emittedTargets.count(target)) {
+          continue;
+        }
+        stopFurtherFallthrough();
+        if (target != curr->default_) {
+          for (auto i : indexes) {
+            ValueBuilder::appendCaseToSwitch(theSwitch,
+                                             ValueBuilder::makeNum(i));
+          }
+          ValueBuilder::appendCodeToSwitch(
+            theSwitch, blockify(makeBreakOrContinue(target)), false);
+        } else {
+          // For the group going to the same place as the default, we can just
+          // emit the default itself, which we do at the end.
+        }
+      }
+      // TODO: if the group the default is in is not the largest, we can turn
+      // the largest into
+      //       the default by using a local and a check on the range
+      if (!emittedTargets.count(curr->default_)) {
+        stopFurtherFallthrough();
+        ValueBuilder::appendDefaultToSwitch(theSwitch);
+        ValueBuilder::appendCodeToSwitch(
+          theSwitch, blockify(makeBreakOrContinue(curr->default_)), false);
+      }
+      return theSwitch;
+    }
+
+    Ref visitCall(Call* curr) {
+      if (curr->isReturn) {
+        Fatal() << "tail calls not yet supported in wasm2js";
+      }
+      Ref theCall =
+        ValueBuilder::makeCall(fromName(curr->target, NameScope::Top));
+      // For wasm => wasm calls, we don't need coercions. TODO: even imports
+      // might be safe?
+      bool needCoercions = parent->options.optimizeLevel == 0 ||
+                           standaloneFunction ||
+                           module->getFunction(curr->target)->imported();
+      for (auto operand : curr->operands) {
+        auto value = visit(operand, EXPRESSION_RESULT);
+        if (needCoercions) {
+          value = makeAsmCoercion(value, wasmToAsmType(operand->type));
+        }
+        theCall[2]->push_back(value);
+      }
+      if (needCoercions) {
+        theCall = makeAsmCoercion(theCall, wasmToAsmType(curr->type));
+      }
+      return theCall;
+    }
+
+    Ref visitCallIndirect(CallIndirect* curr) {
+      if (curr->isReturn) {
+        Fatal() << "tail calls not yet supported in wasm2js";
+      }
+      // If the target has effects that interact with the operands, we must
+      // reorder it to the start.
+      bool mustReorder = false;
+      EffectAnalyzer targetEffects(
+        parent->options, module->features, curr->target);
+      if (targetEffects.hasAnything()) {
+        for (auto* operand : curr->operands) {
+          if (targetEffects.invalidates(
+                EffectAnalyzer(parent->options, module->features, operand))) {
+            mustReorder = true;
+            break;
+          }
+        }
+      }
+      // Ensure the function pointer is a number. In general in wasm2js we are
+      // ok with true/false being present, as they are immediately cast to a
+      // number anyhow on their use. However, FUNCTION_TABLE[true] is *not* the
+      // same as FUNCTION_TABLE[1], so we must cast. This is a rare exception
+      // because FUNCTION_TABLE is just a normal JS object, not a typed array
+      // or a mathematical operation (all of which coerce to a number for us).
+      auto target = visit(curr->target, EXPRESSION_RESULT);
+      target = makeAsmCoercion(target, ASM_INT);
+      if (mustReorder) {
+        Ref ret;
+        ScopedTemp idx(Type::i32, parent, func);
+        std::vector<ScopedTemp*> temps; // TODO: utility class, with destructor?
+        for (auto* operand : curr->operands) {
+          temps.push_back(new ScopedTemp(operand->type, parent, func));
+          IString temp = temps.back()->temp;
+          sequenceAppend(ret, visitAndAssign(operand, temp));
+        }
+        sequenceAppend(ret,
+                       ValueBuilder::makeBinary(
+                         ValueBuilder::makeName(idx.getName()), SET, target));
+        Ref theCall = ValueBuilder::makeCall(ValueBuilder::makeSub(
+          ValueBuilder::makeName(FUNCTION_TABLE), idx.getAstName()));
+        for (size_t i = 0; i < temps.size(); i++) {
+          IString temp = temps[i]->temp;
+          auto& operand = curr->operands[i];
+          theCall[2]->push_back(makeAsmCoercion(ValueBuilder::makeName(temp),
+                                                wasmToAsmType(operand->type)));
+        }
+        theCall = makeAsmCoercion(theCall, wasmToAsmType(curr->type));
+        sequenceAppend(ret, theCall);
+        for (auto temp : temps) {
+          delete temp;
+        }
+        return ret;
+      } else {
+        // Target has no side effects, emit simple code
+        Ref theCall = ValueBuilder::makeCall(ValueBuilder::makeSub(
+          ValueBuilder::makeName(FUNCTION_TABLE), target));
+        for (auto* operand : curr->operands) {
+          theCall[2]->push_back(visit(operand, EXPRESSION_RESULT));
+        }
+        theCall = makeAsmCoercion(theCall, wasmToAsmType(curr->type));
+        return theCall;
+      }
+    }
+
+    // TODO: remove
+    Ref makeSetVar(Expression* curr,
+                   Expression* value,
+                   Name name,
+                   NameScope scope) {
+      return ValueBuilder::makeBinary(
+        ValueBuilder::makeName(fromName(name, scope)),
+        SET,
+        visit(value, EXPRESSION_RESULT));
+    }
+
+    Ref visitLocalGet(LocalGet* curr) {
+      return ValueBuilder::makeName(
+        fromName(func->getLocalNameOrGeneric(curr->index), NameScope::Local));
+    }
+
+    Ref visitLocalSet(LocalSet* curr) {
+      return makeSetVar(curr,
+                        curr->value,
+                        func->getLocalNameOrGeneric(curr->index),
+                        NameScope::Local);
+    }
+
+    Ref visitGlobalGet(GlobalGet* curr) {
+      return ValueBuilder::makeName(fromName(curr->name, NameScope::Top));
+    }
+
+    Ref visitGlobalSet(GlobalSet* curr) {
+      return makeSetVar(curr, curr->value, curr->name, NameScope::Top);
+    }
+
+    Ref visitLoad(Load* curr) {
+      // Unaligned loads and stores must have been fixed up already.
+      assert(curr->align == 0 || curr->align == curr->bytes);
+      // normal load
+      Ref ptr = makePointer(curr->ptr, curr->offset);
+      Ref ret;
+      switch (curr->type.getBasic()) {
+        case Type::i32: {
+          switch (curr->bytes) {
+            case 1:
+              ret = ValueBuilder::makeSub(
+                ValueBuilder::makeName(
+                  LoadUtils::isSignRelevant(curr) && curr->signed_ ? HEAP8
+                                                                   : HEAPU8),
+                ValueBuilder::makePtrShift(ptr, 0));
+              break;
+            case 2:
+              ret = ValueBuilder::makeSub(
+                ValueBuilder::makeName(
+                  LoadUtils::isSignRelevant(curr) && curr->signed_ ? HEAP16
+                                                                   : HEAPU16),
+                ValueBuilder::makePtrShift(ptr, 1));
+              break;
+            case 4:
+              ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAP32),
+                                          ValueBuilder::makePtrShift(ptr, 2));
+              break;
+            default: {
+              Fatal() << "Unhandled number of bytes in i32 load: "
+                      << curr->bytes;
+            }
+          }
+          break;
+        }
+        case Type::f32:
+          ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAPF32),
+                                      ValueBuilder::makePtrShift(ptr, 2));
+          break;
+        case Type::f64:
+          ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAPF64),
+                                      ValueBuilder::makePtrShift(ptr, 3));
+          break;
+        default: {
+          Fatal() << "Unhandled type in load: " << curr->type;
+        }
+      }
+      if (curr->isAtomic) {
+        Ref call = ValueBuilder::makeCall(
+          ValueBuilder::makeDot(ValueBuilder::makeName(ATOMICS), LOAD));
+        ValueBuilder::appendToCall(call, ret[1]);
+        ValueBuilder::appendToCall(call, ret[2]);
+        ret = call;
+      }
+      // Coercions are not actually needed, as if the user reads beyond valid
+      // memory, it's undefined behavior anyhow, and so we don't care much about
+      // slowness of undefined values etc.
+      bool needCoercions =
+        parent->options.optimizeLevel == 0 || standaloneFunction;
+      if (needCoercions) {
+        ret = makeAsmCoercion(ret, wasmToAsmType(curr->type));
+      }
+      return ret;
+    }
+
+    Ref visitStore(Store* curr) {
+      if (module->memory.initial < module->memory.max &&
+          curr->type != Type::unreachable) {
+        // In JS, if memory grows then it is dangerous to write
+        //  HEAP[f()] = ..
+        // or
+        //  HEAP[..] = f()
+        // since if the call swaps HEAP (in a growth operation) then
+        // we will not actually write to the new version (since the
+        // semantics of JS mean we already looked at HEAP and have
+        // decided where to assign to).
+        if (!FindAll<Call>(curr->ptr).list.empty() ||
+            !FindAll<Call>(curr->value).list.empty() ||
+            !FindAll<CallIndirect>(curr->ptr).list.empty() ||
+            !FindAll<CallIndirect>(curr->value).list.empty() ||
+            !FindAll<MemoryGrow>(curr->ptr).list.empty() ||
+            !FindAll<MemoryGrow>(curr->value).list.empty()) {
+          Ref ret;
+          ScopedTemp ptr(Type::i32, parent, func);
+          sequenceAppend(ret, visitAndAssign(curr->ptr, ptr));
+          ScopedTemp value(curr->value->type, parent, func);
+          sequenceAppend(ret, visitAndAssign(curr->value, value));
+          LocalGet getPtr;
+          getPtr.index = func->getLocalIndex(ptr.getName());
+          getPtr.type = Type::i32;
+          LocalGet getValue;
+          getValue.index = func->getLocalIndex(value.getName());
+          getValue.type = curr->value->type;
+          Store fakeStore = *curr;
+          fakeStore.ptr = &getPtr;
+          fakeStore.value = &getValue;
+          sequenceAppend(ret, visitStore(&fakeStore));
+          return ret;
+        }
+      }
+      // FIXME if memory growth, store ptr cannot contain a function call
+      //       also other stores to memory, check them, all makeSub's
+      // Unaligned loads and stores must have been fixed up already.
+      assert(curr->align == 0 || curr->align == curr->bytes);
+      // normal store
+      Ref ptr = makePointer(curr->ptr, curr->offset);
+      Ref value = visit(curr->value, EXPRESSION_RESULT);
+      Ref ret;
+      switch (curr->valueType.getBasic()) {
+        case Type::i32: {
+          switch (curr->bytes) {
+            case 1:
+              ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAP8),
+                                          ValueBuilder::makePtrShift(ptr, 0));
+              break;
+            case 2:
+              ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAP16),
+                                          ValueBuilder::makePtrShift(ptr, 1));
+              break;
+            case 4:
+              ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAP32),
+                                          ValueBuilder::makePtrShift(ptr, 2));
+              break;
+            default:
+              abort();
+          }
+          break;
+        }
+        case Type::f32:
+          ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAPF32),
+                                      ValueBuilder::makePtrShift(ptr, 2));
+          break;
+        case Type::f64:
+          ret = ValueBuilder::makeSub(ValueBuilder::makeName(HEAPF64),
+                                      ValueBuilder::makePtrShift(ptr, 3));
+          break;
+        default: {
+          Fatal() << "Unhandled type in store: " << curr->valueType;
+        }
+      }
+      if (curr->isAtomic) {
+        Ref call = ValueBuilder::makeCall(
+          ValueBuilder::makeDot(ValueBuilder::makeName(ATOMICS), STORE));
+        ValueBuilder::appendToCall(call, ret[1]);
+        ValueBuilder::appendToCall(call, ret[2]);
+        ValueBuilder::appendToCall(call, value);
+        return call;
+      }
+      return ValueBuilder::makeBinary(ret, SET, value);
+    }
+
+    Ref visitDrop(Drop* curr) { return visit(curr->value, NO_RESULT); }
+
+    Ref visitConst(Const* curr) {
+      switch (curr->type.getBasic()) {
+        case Type::i32:
+          return ValueBuilder::makeInt(curr->value.geti32());
+        // An i64 argument translates to two actual arguments to asm.js
+        // functions, so we do a bit of a hack here to get our one `Ref` to look
+        // like two function arguments.
+        case Type::i64: {
+          auto lo = (unsigned)curr->value.geti64();
+          auto hi = (unsigned)(curr->value.geti64() >> 32);
+          std::ostringstream out;
+          out << lo << "," << hi;
+          std::string os = out.str();
+          IString name(os.c_str(), false);
+          return ValueBuilder::makeName(name);
+        }
+        case Type::f32: {
+          Ref ret = ValueBuilder::makeCall(MATH_FROUND);
+          Const fake;
+          fake.value = Literal(double(curr->value.getf32()));
+          fake.type = Type::f64;
+          ret[2]->push_back(visitConst(&fake));
+          return ret;
+        }
+        case Type::f64: {
+          double d = curr->value.getf64();
+          if (d == 0 && std::signbit(d)) { // negative zero
+            return ValueBuilder::makeUnary(
+              PLUS,
+              ValueBuilder::makeUnary(MINUS, ValueBuilder::makeDouble(0)));
+          }
+          return ValueBuilder::makeUnary(
+            PLUS, ValueBuilder::makeDouble(curr->value.getf64()));
+        }
+        default:
+          Fatal() << "unknown const type";
+      }
+    }
+
+    Ref visitUnary(Unary* curr) {
+      // normal unary
+      switch (curr->type.getBasic()) {
+        case Type::i32: {
+          switch (curr->op) {
+            case ClzInt32: {
+              return ValueBuilder::makeCall(
+                MATH_CLZ32, visit(curr->value, EXPRESSION_RESULT));
+            }
+            case CtzInt32:
+            case PopcntInt32: {
+              WASM_UNREACHABLE("i32 unary should have been removed");
+            }
+            case EqZInt32: {
+              // XXX !x does change the type to bool, which is correct, but may
+              // be slower?
+              return ValueBuilder::makeUnary(
+                L_NOT, visit(curr->value, EXPRESSION_RESULT));
+            }
+            case ReinterpretFloat32: {
+              ABI::wasm2js::ensureHelpers(module,
+                                          ABI::wasm2js::SCRATCH_STORE_F32);
+              ABI::wasm2js::ensureHelpers(module,
+                                          ABI::wasm2js::SCRATCH_LOAD_I32);
+
+              Ref store =
+                ValueBuilder::makeCall(ABI::wasm2js::SCRATCH_STORE_F32,
+                                       visit(curr->value, EXPRESSION_RESULT));
+              // 32-bit scratch memory uses index 2, so that it does not
+              // conflict with indexes 0, 1 which are used for 64-bit, see
+              // comment where |scratchBuffer| is defined.
+              Ref load = ValueBuilder::makeCall(ABI::wasm2js::SCRATCH_LOAD_I32,
+                                                ValueBuilder::makeInt(2));
+              return ValueBuilder::makeSeq(store, load);
+            }
+            // generate (~~expr), what Emscripten does
+            case TruncSFloat32ToInt32:
+            case TruncSFloat64ToInt32:
+            case TruncSatSFloat32ToInt32:
+            case TruncSatSFloat64ToInt32: {
+              return ValueBuilder::makeUnary(
+                B_NOT,
+                ValueBuilder::makeUnary(B_NOT,
+                                        visit(curr->value, EXPRESSION_RESULT)));
+            }
+            // generate (~~expr >>> 0), what Emscripten does
+            case TruncUFloat32ToInt32:
+            case TruncUFloat64ToInt32:
+            case TruncSatUFloat32ToInt32:
+            case TruncSatUFloat64ToInt32: {
+              return ValueBuilder::makeBinary(
+                ValueBuilder::makeUnary(
+                  B_NOT,
+                  ValueBuilder::makeUnary(
+                    B_NOT, visit(curr->value, EXPRESSION_RESULT))),
+                TRSHIFT,
+                ValueBuilder::makeNum(0));
+            }
+            case ExtendS8Int32: {
+              return ValueBuilder::makeBinary(
+                ValueBuilder::makeBinary(visit(curr->value, EXPRESSION_RESULT),
+                                         LSHIFT,
+                                         ValueBuilder::makeNum(24)),
+                RSHIFT,
+                ValueBuilder::makeNum(24));
+            }
+            case ExtendS16Int32: {
+              return ValueBuilder::makeBinary(
+                ValueBuilder::makeBinary(visit(curr->value, EXPRESSION_RESULT),
+                                         LSHIFT,
+                                         ValueBuilder::makeNum(16)),
+                RSHIFT,
+                ValueBuilder::makeNum(16));
+            }
+            default: {
+              Fatal() << "Unhandled unary i32 operator: " << curr;
+            }
+          }
+        }
+        case Type::f32:
+        case Type::f64: {
+          Ref ret;
+          switch (curr->op) {
+            case NegFloat32:
+            case NegFloat64:
+              ret = ValueBuilder::makeUnary(
+                MINUS, visit(curr->value, EXPRESSION_RESULT));
+              break;
+            case AbsFloat32:
+            case AbsFloat64:
+              ret = ValueBuilder::makeCall(
+                MATH_ABS, visit(curr->value, EXPRESSION_RESULT));
+              break;
+            case CeilFloat32:
+            case CeilFloat64:
+              ret = ValueBuilder::makeCall(
+                MATH_CEIL, visit(curr->value, EXPRESSION_RESULT));
+              break;
+            case FloorFloat32:
+            case FloorFloat64:
+              ret = ValueBuilder::makeCall(
+                MATH_FLOOR, visit(curr->value, EXPRESSION_RESULT));
+              break;
+            case SqrtFloat32:
+            case SqrtFloat64:
+              ret = ValueBuilder::makeCall(
+                MATH_SQRT, visit(curr->value, EXPRESSION_RESULT));
+              break;
+            case PromoteFloat32:
+              return makeAsmCoercion(visit(curr->value, EXPRESSION_RESULT),
+                                     ASM_DOUBLE);
+            case DemoteFloat64:
+              return makeAsmCoercion(visit(curr->value, EXPRESSION_RESULT),
+                                     ASM_FLOAT);
+            case ReinterpretInt32: {
+              ABI::wasm2js::ensureHelpers(module,
+                                          ABI::wasm2js::SCRATCH_STORE_I32);
+              ABI::wasm2js::ensureHelpers(module,
+                                          ABI::wasm2js::SCRATCH_LOAD_F32);
+
+              // 32-bit scratch memory uses index 2, so that it does not
+              // conflict with indexes 0, 1 which are used for 64-bit, see
+              // comment where |scratchBuffer| is defined.
+              Ref store =
+                ValueBuilder::makeCall(ABI::wasm2js::SCRATCH_STORE_I32,
+                                       ValueBuilder::makeNum(2),
+                                       visit(curr->value, EXPRESSION_RESULT));
+              Ref load = ValueBuilder::makeCall(ABI::wasm2js::SCRATCH_LOAD_F32);
+              return ValueBuilder::makeSeq(store, load);
+            }
+            // Coerce the integer to a float as emscripten does
+            case ConvertSInt32ToFloat32:
+              return makeAsmCoercion(
+                makeAsmCoercion(visit(curr->value, EXPRESSION_RESULT), ASM_INT),
+                ASM_FLOAT);
+            case ConvertSInt32ToFloat64:
+              return makeAsmCoercion(
+                makeAsmCoercion(visit(curr->value, EXPRESSION_RESULT), ASM_INT),
+                ASM_DOUBLE);
+
+            // Generate (expr >>> 0), followed by a coercion
+            case ConvertUInt32ToFloat32:
+              return makeAsmCoercion(
+                ValueBuilder::makeBinary(visit(curr->value, EXPRESSION_RESULT),
+                                         TRSHIFT,
+                                         ValueBuilder::makeInt(0)),
+                ASM_FLOAT);
+            case ConvertUInt32ToFloat64:
+              return makeAsmCoercion(
+                ValueBuilder::makeBinary(visit(curr->value, EXPRESSION_RESULT),
+                                         TRSHIFT,
+                                         ValueBuilder::makeInt(0)),
+                ASM_DOUBLE);
+            // TODO: more complex unary conversions
+            case NearestFloat32:
+            case NearestFloat64:
+            case TruncFloat32:
+            case TruncFloat64:
+              WASM_UNREACHABLE(
+                "operation should have been removed in previous passes");
+
+            default:
+              WASM_UNREACHABLE("unhandled unary float operator");
+          }
+          if (curr->type == Type::f32) { // doubles need much less coercing
+            return makeAsmCoercion(ret, ASM_FLOAT);
+          }
+          return ret;
+        }
+        default: {
+          Fatal() << "Unhandled type in unary: " << curr;
+        }
+      }
+    }
+
+    Ref visitBinary(Binary* curr) {
+      // normal binary
+      Ref left = visit(curr->left, EXPRESSION_RESULT);
+      Ref right = visit(curr->right, EXPRESSION_RESULT);
+      Ref ret;
+      switch (curr->type.getBasic()) {
+        case Type::i32: {
+          switch (curr->op) {
+            case AddInt32:
+              ret = ValueBuilder::makeBinary(left, PLUS, right);
+              break;
+            case SubInt32:
+              ret = ValueBuilder::makeBinary(left, MINUS, right);
+              break;
+            case MulInt32: {
+              if (curr->type == Type::i32) {
+                // TODO: when one operand is a small int, emit a multiply
+                return ValueBuilder::makeCall(MATH_IMUL, left, right);
+              } else {
+                return ValueBuilder::makeBinary(left, MUL, right);
+              }
+            }
+            case DivSInt32:
+              ret = ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+                                             DIV,
+                                             makeSigning(right, ASM_SIGNED));
+              break;
+            case DivUInt32:
+              ret = ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED),
+                                             DIV,
+                                             makeSigning(right, ASM_UNSIGNED));
+              break;
+            case RemSInt32:
+              ret = ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+                                             MOD,
+                                             makeSigning(right, ASM_SIGNED));
+              break;
+            case RemUInt32:
+              ret = ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED),
+                                             MOD,
+                                             makeSigning(right, ASM_UNSIGNED));
+              break;
+            case AndInt32:
+              ret = ValueBuilder::makeBinary(left, AND, right);
+              break;
+            case OrInt32:
+              ret = ValueBuilder::makeBinary(left, OR, right);
+              break;
+            case XorInt32:
+              ret = ValueBuilder::makeBinary(left, XOR, right);
+              break;
+            case ShlInt32:
+              ret = ValueBuilder::makeBinary(left, LSHIFT, right);
+              break;
+            case ShrUInt32:
+              ret = ValueBuilder::makeBinary(left, TRSHIFT, right);
+              break;
+            case ShrSInt32:
+              ret = ValueBuilder::makeBinary(left, RSHIFT, right);
+              break;
+            case EqInt32: {
+              return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+                                              EQ,
+                                              makeSigning(right, ASM_SIGNED));
+            }
+            case NeInt32: {
+              return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+                                              NE,
+                                              makeSigning(right, ASM_SIGNED));
+            }
+            case LtSInt32:
+              return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+                                              LT,
+                                              makeSigning(right, ASM_SIGNED));
+            case LtUInt32:
+              return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED),
+                                              LT,
+                                              makeSigning(right, ASM_UNSIGNED));
+            case LeSInt32:
+              return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+                                              LE,
+                                              makeSigning(right, ASM_SIGNED));
+            case LeUInt32:
+              return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED),
+                                              LE,
+                                              makeSigning(right, ASM_UNSIGNED));
+            case GtSInt32:
+              return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+                                              GT,
+                                              makeSigning(right, ASM_SIGNED));
+            case GtUInt32:
+              return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED),
+                                              GT,
+                                              makeSigning(right, ASM_UNSIGNED));
+            case GeSInt32:
+              return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED),
+                                              GE,
+                                              makeSigning(right, ASM_SIGNED));
+            case GeUInt32:
+              return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED),
+                                              GE,
+                                              makeSigning(right, ASM_UNSIGNED));
+            case EqFloat32:
+            case EqFloat64:
+              return ValueBuilder::makeBinary(left, EQ, right);
+            case NeFloat32:
+            case NeFloat64:
+              return ValueBuilder::makeBinary(left, NE, right);
+            case GeFloat32:
+            case GeFloat64:
+              return ValueBuilder::makeBinary(left, GE, right);
+            case GtFloat32:
+            case GtFloat64:
+              return ValueBuilder::makeBinary(left, GT, right);
+            case LeFloat32:
+            case LeFloat64:
+              return ValueBuilder::makeBinary(left, LE, right);
+            case LtFloat32:
+            case LtFloat64:
+              return ValueBuilder::makeBinary(left, LT, right);
+            case RotLInt32:
+            case RotRInt32:
+              WASM_UNREACHABLE("should be removed already");
+            default:
+              WASM_UNREACHABLE("unhandled i32 binary operator");
+          }
+          break;
+        }
+        case Type::f32:
+        case Type::f64:
+          switch (curr->op) {
+            case AddFloat32:
+            case AddFloat64:
+              ret = ValueBuilder::makeBinary(left, PLUS, right);
+              break;
+            case SubFloat32:
+            case SubFloat64:
+              ret = ValueBuilder::makeBinary(left, MINUS, right);
+              break;
+            case MulFloat32:
+            case MulFloat64:
+              ret = ValueBuilder::makeBinary(left, MUL, right);
+              break;
+            case DivFloat32:
+            case DivFloat64:
+              ret = ValueBuilder::makeBinary(left, DIV, right);
+              break;
+            case MinFloat32:
+            case MinFloat64:
+              ret = ValueBuilder::makeCall(MATH_MIN, left, right);
+              break;
+            case MaxFloat32:
+            case MaxFloat64:
+              ret = ValueBuilder::makeCall(MATH_MAX, left, right);
+              break;
+            case CopySignFloat32:
+            case CopySignFloat64:
+            default:
+              Fatal() << "Unhandled binary float operator: ";
+          }
+          if (curr->type == Type::f32) {
+            return makeAsmCoercion(ret, ASM_FLOAT);
+          }
+          return ret;
+        default:
+          Fatal() << "Unhandled type in binary: " << curr;
+      }
+      return makeAsmCoercion(ret, wasmToAsmType(curr->type));
+    }
+
+    Ref visitSelect(Select* curr) {
+      // If the condition has effects that interact with the operands, we must
+      // reorder it to the start. We must also use locals if the values have
+      // side effects, as a JS conditional does not visit both sides.
+      bool useLocals = false;
+      EffectAnalyzer conditionEffects(
+        parent->options, module->features, curr->condition);
+      EffectAnalyzer ifTrueEffects(
+        parent->options, module->features, curr->ifTrue);
+      EffectAnalyzer ifFalseEffects(
+        parent->options, module->features, curr->ifFalse);
+      if (conditionEffects.invalidates(ifTrueEffects) ||
+          conditionEffects.invalidates(ifFalseEffects) ||
+          ifTrueEffects.hasSideEffects() || ifFalseEffects.hasSideEffects()) {
+        useLocals = true;
+      }
+      if (useLocals) {
+        ScopedTemp tempIfTrue(curr->type, parent, func),
+          tempIfFalse(curr->type, parent, func),
+          tempCondition(Type::i32, parent, func);
+        Ref ifTrue = visit(curr->ifTrue, EXPRESSION_RESULT);
+        Ref ifFalse = visit(curr->ifFalse, EXPRESSION_RESULT);
+        Ref condition = visit(curr->condition, EXPRESSION_RESULT);
+        return ValueBuilder::makeSeq(
+          ValueBuilder::makeBinary(tempIfTrue.getAstName(), SET, ifTrue),
+          ValueBuilder::makeSeq(
+            ValueBuilder::makeBinary(tempIfFalse.getAstName(), SET, ifFalse),
+            ValueBuilder::makeSeq(
+              ValueBuilder::makeBinary(
+                tempCondition.getAstName(), SET, condition),
+              ValueBuilder::makeConditional(tempCondition.getAstName(),
+                                            tempIfTrue.getAstName(),
+                                            tempIfFalse.getAstName()))));
+      } else {
+        // Simple case without reordering.
+        return ValueBuilder::makeConditional(
+          visit(curr->condition, EXPRESSION_RESULT),
+          visit(curr->ifTrue, EXPRESSION_RESULT),
+          visit(curr->ifFalse, EXPRESSION_RESULT));
+      }
+    }
+
+    Ref visitReturn(Return* curr) {
+      if (!curr->value) {
+        return ValueBuilder::makeReturn(Ref());
+      }
+      Ref val = visit(curr->value, EXPRESSION_RESULT);
+      bool needCoercion =
+        parent->options.optimizeLevel == 0 || standaloneFunction ||
+        parent->functionsCallableFromOutside.count(func->name);
+      if (needCoercion) {
+        val = makeAsmCoercion(val, wasmToAsmType(curr->value->type));
+      }
+      return ValueBuilder::makeReturn(val);
+    }
+
+    Ref visitMemorySize(MemorySize* curr) {
+      return ValueBuilder::makeCall(WASM_MEMORY_SIZE);
+    }
+
+    Ref visitMemoryGrow(MemoryGrow* curr) {
+      if (module->memory.exists &&
+          module->memory.max > module->memory.initial) {
+        return ValueBuilder::makeCall(
+          WASM_MEMORY_GROW,
+          makeAsmCoercion(visit(curr->delta, EXPRESSION_RESULT),
+                          wasmToAsmType(curr->delta->type)));
+      } else {
+        return ValueBuilder::makeCall(ABORT_FUNC);
+      }
+    }
+
+    Ref visitNop(Nop* curr) { return ValueBuilder::makeToplevel(); }
+
+    Ref visitUnreachable(Unreachable* curr) {
+      return ValueBuilder::makeCall(ABORT_FUNC);
+    }
+
+    // Atomics
+
+    struct HeapAndPointer {
+      Ref heap;
+      Ref ptr;
+    };
+
+    HeapAndPointer
+    getHeapAndAdjustedPointer(Index bytes, Expression* ptr, Index offset) {
+      IString heap;
+      Ref adjustedPtr = makePointer(ptr, offset);
+      switch (bytes) {
+        case 1:
+          heap = HEAP8;
+          break;
+        case 2:
+          heap = HEAP16;
+          adjustedPtr = ValueBuilder::makePtrShift(adjustedPtr, 1);
+          break;
+        case 4:
+          heap = HEAP32;
+          adjustedPtr = ValueBuilder::makePtrShift(adjustedPtr, 2);
+          break;
+        default: {
+          WASM_UNREACHABLE("unimp");
+        }
+      }
+      return {ValueBuilder::makeName(heap), adjustedPtr};
+    }
+
+    Ref visitAtomicRMW(AtomicRMW* curr) {
+      auto hap =
+        getHeapAndAdjustedPointer(curr->bytes, curr->ptr, curr->offset);
+      IString target;
+      switch (curr->op) {
+        case AtomicRMWOp::Add:
+          target = IString("add");
+          break;
+        case AtomicRMWOp::Sub:
+          target = IString("sub");
+          break;
+        case AtomicRMWOp::And:
+          target = IString("and");
+          break;
+        case AtomicRMWOp::Or:
+          target = IString("or");
+          break;
+        case AtomicRMWOp::Xor:
+          target = IString("xor");
+          break;
+        case AtomicRMWOp::Xchg:
+          target = IString("exchange");
+          break;
+        default:
+          WASM_UNREACHABLE("unimp");
+      }
+      Ref call = ValueBuilder::makeCall(
+        ValueBuilder::makeDot(ValueBuilder::makeName(ATOMICS), target));
+      ValueBuilder::appendToCall(call, hap.heap);
+      ValueBuilder::appendToCall(call, hap.ptr);
+      ValueBuilder::appendToCall(call, visit(curr->value, EXPRESSION_RESULT));
+      return call;
+    }
+
+    Ref visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+      auto hap =
+        getHeapAndAdjustedPointer(curr->bytes, curr->ptr, curr->offset);
+      Ref expected = visit(curr->expected, EXPRESSION_RESULT);
+      Ref replacement = visit(curr->replacement, EXPRESSION_RESULT);
+      Ref call = ValueBuilder::makeCall(ValueBuilder::makeDot(
+        ValueBuilder::makeName(ATOMICS), COMPARE_EXCHANGE));
+      ValueBuilder::appendToCall(call, hap.heap);
+      ValueBuilder::appendToCall(call, hap.ptr);
+      ValueBuilder::appendToCall(call, expected);
+      ValueBuilder::appendToCall(call, replacement);
+      return makeAsmCoercion(call, wasmToAsmType(curr->type));
+    }
+
+    Ref visitAtomicWait(AtomicWait* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+
+    Ref visitAtomicNotify(AtomicNotify* curr) {
+      Ref call = ValueBuilder::makeCall(ValueBuilder::makeDot(
+        ValueBuilder::makeName(ATOMICS), IString("notify")));
+      ValueBuilder::appendToCall(call, ValueBuilder::makeName(HEAP32));
+      ValueBuilder::appendToCall(
+        call,
+        ValueBuilder::makePtrShift(makePointer(curr->ptr, curr->offset), 2));
+      ValueBuilder::appendToCall(call,
+                                 visit(curr->notifyCount, EXPRESSION_RESULT));
+      return call;
+    }
+
+    Ref visitAtomicFence(AtomicFence* curr) {
+      // Sequentially consistent fences can be lowered to no operation
+      return ValueBuilder::makeToplevel();
+    }
+
+    // TODOs
+
+    Ref visitSIMDExtract(SIMDExtract* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitSIMDReplace(SIMDReplace* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitSIMDShuffle(SIMDShuffle* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitSIMDTernary(SIMDTernary* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitSIMDShift(SIMDShift* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitSIMDLoad(SIMDLoad* 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,
+                                    ValueBuilder::makeNum(curr->segment),
+                                    visit(curr->dest, EXPRESSION_RESULT),
+                                    visit(curr->offset, EXPRESSION_RESULT),
+                                    visit(curr->size, EXPRESSION_RESULT));
+    }
+    Ref visitDataDrop(DataDrop* curr) {
+      ABI::wasm2js::ensureHelpers(module, ABI::wasm2js::DATA_DROP);
+      return ValueBuilder::makeCall(ABI::wasm2js::DATA_DROP,
+                                    ValueBuilder::makeNum(curr->segment));
+    }
+    Ref visitMemoryCopy(MemoryCopy* curr) {
+      ABI::wasm2js::ensureHelpers(module, ABI::wasm2js::MEMORY_COPY);
+      return ValueBuilder::makeCall(ABI::wasm2js::MEMORY_COPY,
+                                    visit(curr->dest, EXPRESSION_RESULT),
+                                    visit(curr->source, EXPRESSION_RESULT),
+                                    visit(curr->size, EXPRESSION_RESULT));
+    }
+    Ref visitMemoryFill(MemoryFill* curr) {
+      ABI::wasm2js::ensureHelpers(module, ABI::wasm2js::MEMORY_FILL);
+      return ValueBuilder::makeCall(ABI::wasm2js::MEMORY_FILL,
+                                    visit(curr->dest, EXPRESSION_RESULT),
+                                    visit(curr->value, EXPRESSION_RESULT),
+                                    visit(curr->size, EXPRESSION_RESULT));
+    }
+    Ref visitRefNull(RefNull* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitRefIsNull(RefIsNull* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitRefFunc(RefFunc* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitRefEq(RefEq* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitTry(Try* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitThrow(Throw* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitRethrow(Rethrow* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitBrOnExn(BrOnExn* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitPop(Pop* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitTupleMake(TupleMake* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitTupleExtract(TupleExtract* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitI31New(I31New* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitI31Get(I31Get* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitRefTest(RefTest* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitRefCast(RefCast* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitBrOnCast(BrOnCast* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitRttCanon(RttCanon* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitRttSub(RttSub* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitStructNew(StructNew* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitStructGet(StructGet* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitStructSet(StructSet* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitArrayNew(ArrayNew* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitArrayGet(ArrayGet* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitArraySet(ArraySet* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+    Ref visitArrayLen(ArrayLen* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
+
+  private:
+    Ref makePointer(Expression* ptr, Address offset) {
+      auto ret = visit(ptr, EXPRESSION_RESULT);
+      if (offset) {
+        ret = makeAsmCoercion(
+          ValueBuilder::makeBinary(ret, PLUS, ValueBuilder::makeNum(offset)),
+          ASM_INT);
+      }
+      return ret;
+    }
+
+    void unimplemented(Expression* curr) {
+      Fatal() << "wasm2js cannot convert " << getExpressionName(curr);
+    }
+  };
+
+  return ExpressionProcessor(this, m, func, standaloneFunction).process();
+}
+
+void Wasm2JSBuilder::addMemoryFuncs(Ref ast, Module* wasm) {
+  Ref memorySizeFunc = ValueBuilder::makeFunction(WASM_MEMORY_SIZE);
+  memorySizeFunc[3]->push_back(ValueBuilder::makeReturn(
+    makeAsmCoercion(ValueBuilder::makeBinary(
+                      ValueBuilder::makeDot(ValueBuilder::makeName(BUFFER),
+                                            IString("byteLength")),
+                      DIV,
+                      ValueBuilder::makeInt(Memory::kPageSize)),
+                    AsmType::ASM_INT)));
+  ast->push_back(memorySizeFunc);
+
+  if (wasm->memory.max > wasm->memory.initial) {
+    addMemoryGrowFunc(ast, wasm);
+  }
+}
+
+void Wasm2JSBuilder::addMemoryGrowFunc(Ref ast, Module* wasm) {
+  Ref memoryGrowFunc = ValueBuilder::makeFunction(WASM_MEMORY_GROW);
+  ValueBuilder::appendArgumentToFunction(memoryGrowFunc, IString("pagesToAdd"));
+
+  memoryGrowFunc[3]->push_back(
+    ValueBuilder::makeStatement(ValueBuilder::makeBinary(
+      ValueBuilder::makeName(IString("pagesToAdd")),
+      SET,
+      makeAsmCoercion(ValueBuilder::makeName(IString("pagesToAdd")),
+                      AsmType::ASM_INT))));
+
+  Ref oldPages = ValueBuilder::makeVar();
+  memoryGrowFunc[3]->push_back(oldPages);
+  ValueBuilder::appendToVar(
+    oldPages,
+    IString("oldPages"),
+    makeAsmCoercion(ValueBuilder::makeCall(WASM_MEMORY_SIZE),
+                    AsmType::ASM_INT));
+
+  Ref newPages = ValueBuilder::makeVar();
+  memoryGrowFunc[3]->push_back(newPages);
+  ValueBuilder::appendToVar(
+    newPages,
+    IString("newPages"),
+    makeAsmCoercion(
+      ValueBuilder::makeBinary(ValueBuilder::makeName(IString("oldPages")),
+                               PLUS,
+                               ValueBuilder::makeName(IString("pagesToAdd"))),
+      AsmType::ASM_INT));
+
+  Ref block = ValueBuilder::makeBlock();
+  memoryGrowFunc[3]->push_back(ValueBuilder::makeIf(
+    ValueBuilder::makeBinary(
+      ValueBuilder::makeBinary(ValueBuilder::makeName(IString("oldPages")),
+                               LT,
+                               ValueBuilder::makeName(IString("newPages"))),
+      IString("&&"),
+      ValueBuilder::makeBinary(ValueBuilder::makeName(IString("newPages")),
+                               LT,
+                               ValueBuilder::makeInt(Memory::kMaxSize32))),
+    block,
+    NULL));
+
+  Ref newBuffer = ValueBuilder::makeVar();
+  ValueBuilder::appendToBlock(block, newBuffer);
+  ValueBuilder::appendToVar(
+    newBuffer,
+    IString("newBuffer"),
+    ValueBuilder::makeNew(ValueBuilder::makeCall(
+      ARRAY_BUFFER,
+      ValueBuilder::makeCall(MATH_IMUL,
+                             ValueBuilder::makeName(IString("newPages")),
+                             ValueBuilder::makeInt(Memory::kPageSize)))));
+
+  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::appendToBlock(
+    block,
+    ValueBuilder::makeCall(
+      ValueBuilder::makeDot(ValueBuilder::makeName(IString("newHEAP8")),
+                            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,
+      ValueBuilder::makeBinary(
+        ValueBuilder::makeName(name),
+        SET,
+        ValueBuilder::makeNew(ValueBuilder::makeCall(
+          ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), view),
+          ValueBuilder::makeName(IString("newBuffer"))))));
+  };
+
+  setHeap(HEAP8, INT8ARRAY);
+  setHeap(HEAP16, INT16ARRAY);
+  setHeap(HEAP32, INT32ARRAY);
+  setHeap(HEAPU8, UINT8ARRAY);
+  setHeap(HEAPU16, UINT16ARRAY);
+  setHeap(HEAPU32, UINT32ARRAY);
+  setHeap(HEAPF32, FLOAT32ARRAY);
+  setHeap(HEAPF64, FLOAT64ARRAY);
+
+  ValueBuilder::appendToBlock(
+    block,
+    ValueBuilder::makeBinary(ValueBuilder::makeName(BUFFER),
+                             SET,
+                             ValueBuilder::makeName(IString("newBuffer"))));
+
+  // apply the changes to the memory import
+  if (wasm->memory.imported()) {
+    ValueBuilder::appendToBlock(
+      block,
+      ValueBuilder::makeBinary(
+        ValueBuilder::makeDot(ValueBuilder::makeName("memory"),
+                              ValueBuilder::makeName(BUFFER)),
+        SET,
+        ValueBuilder::makeName(IString("newBuffer"))));
+  }
+
+  memoryGrowFunc[3]->push_back(
+    ValueBuilder::makeReturn(ValueBuilder::makeName(IString("oldPages"))));
+
+  ast->push_back(memoryGrowFunc);
+}
+
+// Wasm2JSGlue emits the core of the module - the functions etc. that would
+// be the asm.js function in an asm.js world. This class emits the rest of the
+// "glue" around that.
+class Wasm2JSGlue {
+public:
+  Wasm2JSGlue(Module& wasm,
+              Output& out,
+              Wasm2JSBuilder::Flags flags,
+              Name moduleName)
+    : wasm(wasm), out(out), flags(flags), moduleName(moduleName) {}
+
+  void emitPre();
+  void emitPost();
+
+private:
+  Module& wasm;
+  Output& out;
+  Wasm2JSBuilder::Flags flags;
+  Name moduleName;
+
+  void emitPreEmscripten();
+  void emitPreES6();
+  void emitPostEmscripten();
+  void emitPostES6();
+
+  void emitMemory(std::string buffer,
+                  std::string segmentWriter,
+                  std::function<std::string(std::string)> accessGlobal);
+  void emitSpecialSupport();
+};
+
+void Wasm2JSGlue::emitPre() {
+  if (flags.emscripten) {
+    emitPreEmscripten();
+  } else {
+    emitPreES6();
+  }
+
+  if (isTableExported(wasm)) {
+    out << "function Table(ret) {\n";
+    if (wasm.table.initial == wasm.table.max) {
+      out << "  // grow method not included; table is not growable\n";
+    } else {
+      out << "  ret.grow = function(by) {\n"
+          << "    var old = this.length;\n"
+          << "    this.length = this.length + by;\n"
+          << "    return old;\n"
+          << "  };\n";
+    }
+    out << "  ret.set = function(i, func) {\n"
+        << "    this[i] = func;\n"
+        << "  };\n"
+        << "  ret.get = function(i) {\n"
+        << "    return this[i];\n"
+        << "  };\n"
+        << "  return ret;\n"
+        << "}\n\n";
+  }
+
+  emitSpecialSupport();
+}
+
+void Wasm2JSGlue::emitPreEmscripten() {
+  out << "function instantiate(asmLibraryArg, wasmMemory) {\n";
+}
+
+void Wasm2JSGlue::emitPreES6() {
+  std::unordered_map<Name, Name> baseModuleMap;
+
+  auto noteImport = [&](Name module, Name base) {
+    // Right now codegen requires a flat namespace going into the module,
+    // meaning we don't support importing the same name from multiple namespaces
+    // yet.
+    if (baseModuleMap.count(base) && baseModuleMap[base] != module) {
+      Fatal() << "the name " << base << " cannot be imported from "
+              << "two different modules yet";
+    }
+    baseModuleMap[base] = module;
+
+    out << "import { " << asmangle(base.str) << " } from '" << module.str
+        << "';\n";
+  };
+
+  ImportInfo imports(wasm);
+
+  ModuleUtils::iterImportedGlobals(
+    wasm, [&](Global* import) { noteImport(import->module, import->base); });
+  ModuleUtils::iterImportedTables(
+    wasm, [&](Table* import) { noteImport(import->module, import->base); });
+  ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
+    // The special helpers are emitted in the glue, see code and comments
+    // below.
+    if (ABI::wasm2js::isHelper(import->base)) {
+      return;
+    }
+    noteImport(import->module, import->base);
+  });
+
+  out << '\n';
+}
+
+void Wasm2JSGlue::emitPost() {
+  if (flags.emscripten) {
+    emitPostEmscripten();
+  } else {
+    emitPostES6();
+  }
+}
+
+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"
+      << "}";
+}
+
+void Wasm2JSGlue::emitPostES6() {
+  // Create an initial `ArrayBuffer` and populate it with static data.
+  // Currently we use base64 encoding to encode static data and we decode it at
+  // instantiation time.
+  //
+  // 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) {
+    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'); }";
+
+  ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
+    // The special helpers are emitted in the glue, see code and comments
+    // below.
+    if (ABI::wasm2js::isHelper(import->base)) {
+      return;
+    }
+    out << ",\n    " << asmangle(import->base.str);
+  });
+
+  ModuleUtils::iterImportedMemories(wasm, [&](Memory* import) {
+    // The special helpers are emitted in the glue, see code and comments
+    // below.
+    if (ABI::wasm2js::isHelper(import->base)) {
+      return;
+    }
+    out << ",\n    " << asmangle(import->base.str) << ": { buffer : mem"
+        << moduleName.str << " }";
+  });
+
+  ModuleUtils::iterImportedTables(wasm, [&](Table* import) {
+    // The special helpers are emitted in the glue, see code and comments
+    // below.
+    if (ABI::wasm2js::isHelper(import->base)) {
+      return;
+    }
+    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";
+  }
+
+  if (flags.allowAsserts) {
+    return;
+  }
+
+  // And now that we have our returned instance, export all our functions
+  // that are hanging off it.
+  for (auto& exp : wasm.exports) {
+    switch (exp->kind) {
+      case ExternalKind::Function:
+      case ExternalKind::Memory:
+        break;
+
+      // Exported globals and function tables aren't supported yet
+      default:
+        continue;
+    }
+    std::ostringstream export_name;
+    for (auto* ptr = exp->name.str; *ptr; ptr++) {
+      if (*ptr == '-') {
+        export_name << '_';
+      } else {
+        export_name << *ptr;
+      }
+    }
+    out << "export var " << asmangle(exp->name.str) << " = ret"
+        << moduleName.str << "." << asmangle(exp->name.str) << ";\n";
+  }
+}
+
+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";
+  }
+  // If there are no memory segments, we don't need to emit any support code for
+  // segment creation.
+  if (wasm.memory.segments.empty()) {
+    return;
+  }
+
+  out <<
+    R"(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)];
+    })";
+  if (wasm.features.hasBulkMemory()) {
+    // Passive segments in bulk memory are initialized into new arrays that are
+    // passed into here, and we need to return them.
+    out << R"(
+    return uint8Array;)";
+  }
+  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 {
+      // Fancy passive segments are decoded into typed arrays on the side, for
+      // later copying.
+      out << "memorySegments[" << i
+          << "] = base64DecodeToExistingUint8Array(new Uint8Array("
+          << seg.data.size() << ")"
+          << ", 0, \"" << base64Encode(seg.data) << "\");\n";
+    }
+  }
+}
+
+void Wasm2JSGlue::emitSpecialSupport() {
+  // 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;
+    }
+  });
+  if (!need) {
+    return;
+  }
+
+  // Scratch memory uses 3 indexes, each referring to 4 bytes. Indexes 0, 1 are
+  // used for 64-bit operations, while 2 is for 32-bit. These operations need
+  // separate indexes because we need to handle the case where the optimizer
+  // reorders a 32-bit reinterpret in between a 64-bit's split-out parts.
+  // That situation can occur because the 64-bit reinterpret was split up into
+  // pieces early, in the 64-bit lowering pass, while the 32-bit reinterprets
+  // are lowered only at the very end, and until then the optimizer sees wasm
+  // reinterprets which have no side effects (but they will have the side effect
+  // of altering scratch memory). That is, conceptual code like this:
+  //
+  //   a = reinterpret_64(b)
+  //   x = reinterpret_32(y)
+  //
+  // turns into
+  //
+  //   scratch_write(b)
+  //   a_low = scratch_read(0)
+  //   a_high = scratch_read(1)
+  //   x = reinterpret_32(y)
+  //
+  // (Note how the single wasm instruction for a 64-bit reinterpret turns into
+  // multiple operations. We have to do such splitting, because in JS we will
+  // have to have separate operations to receive each 32-bit chunk anyhow. A
+  // *32*-bit reinterpret *could* be a single function, but given we have the
+  // separate functions anyhow for the 64-bit case, it's more compact to reuse
+  // those.)
+  // At this point, the scratch_* functions look like they have side effects to
+  // the optimizer (which is true, as they modify scratch memory), but the
+  // reinterpret_32 is still a normal wasm instruction without side effects, so
+  // the optimizer might do this:
+  //
+  //   scratch_write(b)
+  //   a_low = scratch_read(0)
+  //   x = reinterpret_32(y)    ;; this moved one line up
+  //   a_high = scratch_read(1)
+  //
+  // When we do lower the reinterpret_32 into JS, we get:
+  //
+  //   scratch_write(b)
+  //   a_low = scratch_read(0)
+  //   scratch_write(y)
+  //   x = scratch_read()
+  //   a_high = scratch_read(1)
+  //
+  // The second write occurs before the first's values have been read, so they
+  // interfere.
+  //
+  // There isn't a problem with reordering 32-bit reinterprets with each other
+  // as each is lowered into a pair of write+read in JS (after the wasm
+  // optimizer runs), so they are guaranteed to be adjacent (and a JS optimizer
+  // that runs later will handle that ok since they are calls, which can always
+  // have side effects).
+  out << R"(
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  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"(
+  function wasm2js_scratch_store_i32(index, value) {
+    i32ScratchView[index] = value;
+  }
+      )";
+    } else if (import->base == ABI::wasm2js::SCRATCH_LOAD_I32) {
+      out << R"(
+  function wasm2js_scratch_load_i32(index) {
+    return i32ScratchView[index];
+  }
+      )";
+    } else if (import->base == ABI::wasm2js::SCRATCH_STORE_F32) {
+      out << R"(
+  function wasm2js_scratch_store_f32(value) {
+    f32ScratchView[2] = value;
+  }
+      )";
+    } else if (import->base == ABI::wasm2js::SCRATCH_LOAD_F32) {
+      out << R"(
+  function wasm2js_scratch_load_f32() {
+    return f32ScratchView[2];
+  }
+      )";
+    } else if (import->base == ABI::wasm2js::SCRATCH_STORE_F64) {
+      out << R"(
+  function wasm2js_scratch_store_f64(value) {
+    f64ScratchView[0] = value;
+  }
+      )";
+    } else if (import->base == ABI::wasm2js::SCRATCH_LOAD_F64) {
+      out << R"(
+  function wasm2js_scratch_load_f64() {
+    return f64ScratchView[0];
+  }
+      )";
+    } 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
+    bufferView.set(memorySegments[segment].subarray(offset, offset + size), dest);
+  }
+      )";
+    } else if (import->base == ABI::wasm2js::MEMORY_FILL) {
+      out << R"(
+  function wasm2js_memory_fill(dest, value, size) {
+    dest = dest >>> 0;
+    size = size >>> 0;
+    if (dest + size > bufferView.length) throw "trap: invalid memory.fill";
+    bufferView.fill(value, dest, dest + size);
+  }
+      )";
+    } else if (import->base == ABI::wasm2js::MEMORY_COPY) {
+      out << R"(
+  function wasm2js_memory_copy(dest, source, size) {
+    // TODO: traps on invalid things
+    bufferView.copyWithin(dest, source, source + size);
+  }
+      )";
+    } else if (import->base == ABI::wasm2js::DATA_DROP) {
+      needMemorySegmentsList = true;
+      out << R"(
+  function wasm2js_data_drop(segment) {
+    // TODO: traps on invalid things
+    memorySegments[segment] = new Uint8Array(0);
+  }
+      )";
+    } else if (import->base == ABI::wasm2js::ATOMIC_WAIT_I32) {
+      out << R"(
+  function wasm2js_atomic_wait_i32(ptr, expected, timeoutLow, timeoutHigh) {
+    if (timeoutLow != -1 || timeoutHigh != -1) throw 'unsupported timeout';
+    var view = new Int32Array(bufferView.buffer); // TODO cache
+    var result = Atomics.wait(view, ptr, expected);
+    if (result == 'ok') return 0;
+    if (result == 'not-equal') return 1;
+    if (result == 'timed-out') return 2;
+    throw 'bad result ' + result;
+  }
+      )";
+    } else if (import->base == ABI::wasm2js::ATOMIC_RMW_I64) {
+      out << R"(
+  function wasm2js_atomic_rmw_i64(op, bytes, offset, ptr, valueLow, valueHigh) {
+    assert(bytes == 8); // TODO: support 1, 2, 4 as well
+    var view = new BigInt64Array(bufferView.buffer); // TODO cache
+    ptr = (ptr + offset) >> 3;
+    var value = BigInt(valueLow >>> 0) | (BigInt(valueHigh >>> 0) << BigInt(32));
+    var result;
+    switch (op) {
+      case 0: { // Add
+        result = Atomics.add(view, ptr, value);
+        break;
+      }
+      case 1: { // Sub
+        result = Atomics.sub(view, ptr, value);
+        break;
+      }
+      case 2: { // And
+        result = Atomics.and(view, ptr, value);
+        break;
+      }
+      case 3: { // Or
+        result = Atomics.or(view, ptr, value);
+        break;
+      }
+      case 4: { // Xor
+        result = Atomics.xor(view, ptr, value);
+        break;
+      }
+      case 5: { // Xchg
+        result = Atomics.exchange(view, ptr, value);
+        break;
+      }
+      default: throw 'bad op';
+    }
+    var low = Number(result & BigInt(0xffffffff)) | 0;
+    var high = Number((result >> BigInt(32)) & BigInt(0xffffffff)) | 0;
+    stashedBits = high;
+    return low;
+  }
+      )";
+    } else if (import->base == ABI::wasm2js::GET_STASHED_BITS) {
+      out << R"(
+  var stashedBits = 0;
+
+  function wasm2js_get_stashed_bits() {
+    return stashedBits;
+  }
+      )";
+    }
+  });
+
+  if (needMemorySegmentsList) {
+    out << R"(
+  var memorySegments = {};
+    )";
+  }
+
+  out << '\n';
+}
+
+} // namespace wasm
+
+#endif // wasm_wasm2js_h
diff --git a/binaryen/test/__init__.py b/binaryen/test/__init__.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/__init__.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python3
+#
+# Copyright 2015 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.
+
+# Empty __init__.py file: Python treats the directory as containing a package.
diff --git a/binaryen/test/atomics-unshared.wast b/binaryen/test/atomics-unshared.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/atomics-unshared.wast
@@ -0,0 +1,10 @@
+(module
+ (memory $0 1 1)
+ (func $foo
+  (drop (i32.atomic.rmw.cmpxchg
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 0)
+  ))
+ )
+)
diff --git a/binaryen/test/atomics-unshared.wast.from-wast b/binaryen/test/atomics-unshared.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/atomics-unshared.wast.from-wast
@@ -0,0 +1,13 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 1 1)
+ (func $foo
+  (drop
+   (i32.atomic.rmw.cmpxchg
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/atomics-unshared.wast.fromBinary b/binaryen/test/atomics-unshared.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/atomics-unshared.wast.fromBinary
@@ -0,0 +1,14 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 1 1)
+ (func $foo
+  (drop
+   (i32.atomic.rmw.cmpxchg
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/atomics-unshared.wast.fromBinary.noDebugInfo b/binaryen/test/atomics-unshared.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/atomics-unshared.wast.fromBinary.noDebugInfo
@@ -0,0 +1,14 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 1 1)
+ (func $0
+  (drop
+   (i32.atomic.rmw.cmpxchg
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/atomics.wast b/binaryen/test/atomics.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/atomics.wast
@@ -0,0 +1,184 @@
+(module
+ (type $0 (func))
+ (memory $0 (shared 23 256))
+ (func $atomic-loadstore (type $0)
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.load8_u offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.load16_u offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.load offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load8_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load16_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load32_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load
+    (local.get $0)
+   )
+  )
+  (i32.atomic.store offset=4 align=4
+   (local.get $0)
+   (local.get $0)
+  )
+  (i32.atomic.store8 offset=4 align=1
+   (local.get $0)
+   (local.get $0)
+  )
+  (i32.atomic.store16 offset=4
+   (local.get $0)
+   (local.get $0)
+  )
+  (i64.atomic.store offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store8 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store16 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store32 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $atomic-rmw (type $0)
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.rmw.add offset=4
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.add_u offset=4
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw16.and_u align=2
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.or_u
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.xchg_u align=1
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+ )
+ (func $atomic-cmpxchg (type $0)
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.rmw.cmpxchg offset=4
+    (local.get $0)
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.cmpxchg_u
+    (local.get $0)
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.rmw.cmpxchg offset=4
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.cmpxchg_u align=4
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $atomic-wait-notify (type $0)
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.wait
+    (local.get $0)
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.wait offset=4 align=4
+    (local.get $0)
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (drop
+   (atomic.notify
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (atomic.notify offset=24 align=4
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.wait
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.wait align=8 offset=16
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $atomic-fence (type $0)
+  (atomic.fence)
+ )
+)
diff --git a/binaryen/test/atomics.wast.from-wast b/binaryen/test/atomics.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/atomics.wast.from-wast
@@ -0,0 +1,184 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 (shared 23 256))
+ (func $atomic-loadstore
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.load8_u offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.load16_u offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.load offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load8_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load16_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load32_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load
+    (local.get $0)
+   )
+  )
+  (i32.atomic.store offset=4
+   (local.get $0)
+   (local.get $0)
+  )
+  (i32.atomic.store8 offset=4
+   (local.get $0)
+   (local.get $0)
+  )
+  (i32.atomic.store16 offset=4
+   (local.get $0)
+   (local.get $0)
+  )
+  (i64.atomic.store offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store8 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store16 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store32 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $atomic-rmw
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.rmw.add offset=4
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.add_u offset=4
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw16.and_u
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.or_u
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.xchg_u
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+ )
+ (func $atomic-cmpxchg
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.rmw.cmpxchg offset=4
+    (local.get $0)
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.cmpxchg_u
+    (local.get $0)
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.rmw.cmpxchg offset=4
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.cmpxchg_u
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $atomic-wait-notify
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.wait
+    (local.get $0)
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.wait offset=4
+    (local.get $0)
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (drop
+   (atomic.notify
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (atomic.notify offset=24
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.wait
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.wait offset=16
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $atomic-fence
+  (atomic.fence)
+ )
+)
diff --git a/binaryen/test/atomics.wast.fromBinary b/binaryen/test/atomics.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/atomics.wast.fromBinary
@@ -0,0 +1,185 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 (shared 23 256))
+ (func $atomic-loadstore
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.load8_u offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.load16_u offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.load offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load8_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load16_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load32_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load
+    (local.get $0)
+   )
+  )
+  (i32.atomic.store offset=4
+   (local.get $0)
+   (local.get $0)
+  )
+  (i32.atomic.store8 offset=4
+   (local.get $0)
+   (local.get $0)
+  )
+  (i32.atomic.store16 offset=4
+   (local.get $0)
+   (local.get $0)
+  )
+  (i64.atomic.store offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store8 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store16 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store32 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $atomic-rmw
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.rmw.add offset=4
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.add_u offset=4
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw16.and_u
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.or_u
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.xchg_u
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+ )
+ (func $atomic-cmpxchg
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.rmw.cmpxchg offset=4
+    (local.get $0)
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.cmpxchg_u
+    (local.get $0)
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.rmw.cmpxchg offset=4
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.cmpxchg_u
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $atomic-wait-notify
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.wait
+    (local.get $0)
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.wait offset=4
+    (local.get $0)
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (drop
+   (atomic.notify
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (atomic.notify offset=24
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.wait
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.wait offset=16
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $atomic-fence
+  (atomic.fence)
+ )
+)
+
diff --git a/binaryen/test/atomics.wast.fromBinary.noDebugInfo b/binaryen/test/atomics.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/atomics.wast.fromBinary.noDebugInfo
@@ -0,0 +1,185 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 (shared 23 256))
+ (func $0
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.load8_u offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.load16_u offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.load offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load8_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load16_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load32_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load
+    (local.get $0)
+   )
+  )
+  (i32.atomic.store offset=4
+   (local.get $0)
+   (local.get $0)
+  )
+  (i32.atomic.store8 offset=4
+   (local.get $0)
+   (local.get $0)
+  )
+  (i32.atomic.store16 offset=4
+   (local.get $0)
+   (local.get $0)
+  )
+  (i64.atomic.store offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store8 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store16 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store32 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $1
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.rmw.add offset=4
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.add_u offset=4
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw16.and_u
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.or_u
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.xchg_u
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+ )
+ (func $2
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.rmw.cmpxchg offset=4
+    (local.get $0)
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.cmpxchg_u
+    (local.get $0)
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.rmw.cmpxchg offset=4
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.cmpxchg_u
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $3
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.wait
+    (local.get $0)
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.wait offset=4
+    (local.get $0)
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (drop
+   (atomic.notify
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (atomic.notify offset=24
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.wait
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.wait offset=16
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $4
+  (atomic.fence)
+ )
+)
+
diff --git a/binaryen/test/atomics64.wast b/binaryen/test/atomics64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/atomics64.wast
@@ -0,0 +1,188 @@
+(module
+ (type $0 (func))
+ (memory $0 (shared i64 23 256))
+ (func $atomic-loadstore (type $0)
+  (local $0 i64)
+  (local $1 i64)
+  (local $2 i32)
+  (drop
+   (i32.atomic.load8_u offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.load16_u offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.load offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load8_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load16_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load32_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load
+    (local.get $0)
+   )
+  )
+  (i32.atomic.store offset=4 align=4
+   (local.get $0)
+   (local.get $2)
+  )
+  (i32.atomic.store8 offset=4 align=1
+   (local.get $0)
+   (local.get $2)
+  )
+  (i32.atomic.store16 offset=4
+   (local.get $0)
+   (local.get $2)
+  )
+  (i64.atomic.store offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store8 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store16 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store32 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $atomic-rmw (type $0)
+  (local $0 i64)
+  (local $1 i64)
+  (local $2 i32)
+  (drop
+   (i32.atomic.rmw.add offset=4
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.add_u offset=4
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i32.atomic.rmw16.and_u align=2
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.or_u
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.xchg_u align=1
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+ )
+ (func $atomic-cmpxchg (type $0)
+  (local $0 i64)
+  (local $1 i64)
+  (local $2 i32)
+  (drop
+   (i32.atomic.rmw.cmpxchg offset=4
+    (local.get $0)
+    (local.get $2)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.cmpxchg_u
+    (local.get $0)
+    (local.get $2)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i64.atomic.rmw.cmpxchg offset=4
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.cmpxchg_u align=4
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $atomic-wait-notify (type $0)
+  (local $0 i64)
+  (local $1 i64)
+  (local $2 i32)
+  (drop
+   (i32.atomic.wait
+    (local.get $0)
+    (local.get $2)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.wait offset=4 align=4
+    (local.get $0)
+    (local.get $2)
+    (local.get $1)
+   )
+  )
+  (drop
+   (atomic.notify
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (drop
+   (atomic.notify offset=24 align=4
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i64.atomic.wait
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.wait align=8 offset=16
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $atomic-fence (type $0)
+  (atomic.fence)
+ )
+)
diff --git a/binaryen/test/atomics64.wast.from-wast b/binaryen/test/atomics64.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/atomics64.wast.from-wast
@@ -0,0 +1,188 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 (shared i64 23 256))
+ (func $atomic-loadstore
+  (local $0 i64)
+  (local $1 i64)
+  (local $2 i32)
+  (drop
+   (i32.atomic.load8_u offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.load16_u offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.load offset=4
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load8_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load16_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load32_u
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.load
+    (local.get $0)
+   )
+  )
+  (i32.atomic.store offset=4
+   (local.get $0)
+   (local.get $2)
+  )
+  (i32.atomic.store8 offset=4
+   (local.get $0)
+   (local.get $2)
+  )
+  (i32.atomic.store16 offset=4
+   (local.get $0)
+   (local.get $2)
+  )
+  (i64.atomic.store offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store8 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store16 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (i64.atomic.store32 offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $atomic-rmw
+  (local $0 i64)
+  (local $1 i64)
+  (local $2 i32)
+  (drop
+   (i32.atomic.rmw.add offset=4
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.add_u offset=4
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i32.atomic.rmw16.and_u
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.or_u
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.xchg_u
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+ )
+ (func $atomic-cmpxchg
+  (local $0 i64)
+  (local $1 i64)
+  (local $2 i32)
+  (drop
+   (i32.atomic.rmw.cmpxchg offset=4
+    (local.get $0)
+    (local.get $2)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.cmpxchg_u
+    (local.get $0)
+    (local.get $2)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i64.atomic.rmw.cmpxchg offset=4
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.cmpxchg_u
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $atomic-wait-notify
+  (local $0 i64)
+  (local $1 i64)
+  (local $2 i32)
+  (drop
+   (i32.atomic.wait
+    (local.get $0)
+    (local.get $2)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.wait offset=4
+    (local.get $0)
+    (local.get $2)
+    (local.get $1)
+   )
+  )
+  (drop
+   (atomic.notify
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (drop
+   (atomic.notify offset=24
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i64.atomic.wait
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.wait offset=16
+    (local.get $0)
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $atomic-fence
+  (atomic.fence)
+ )
+)
diff --git a/binaryen/test/atomics64.wast.fromBinary b/binaryen/test/atomics64.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/atomics64.wast.fromBinary
@@ -0,0 +1,189 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 (shared i64 23 256))
+ (func $atomic-loadstore
+  (local $0 i32)
+  (local $1 i64)
+  (local $2 i64)
+  (drop
+   (i32.atomic.load8_u offset=4
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.load16_u offset=4
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.load offset=4
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.load8_u
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.load16_u
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.load32_u
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.load
+    (local.get $1)
+   )
+  )
+  (i32.atomic.store offset=4
+   (local.get $1)
+   (local.get $0)
+  )
+  (i32.atomic.store8 offset=4
+   (local.get $1)
+   (local.get $0)
+  )
+  (i32.atomic.store16 offset=4
+   (local.get $1)
+   (local.get $0)
+  )
+  (i64.atomic.store offset=4
+   (local.get $1)
+   (local.get $2)
+  )
+  (i64.atomic.store8 offset=4
+   (local.get $1)
+   (local.get $2)
+  )
+  (i64.atomic.store16 offset=4
+   (local.get $1)
+   (local.get $2)
+  )
+  (i64.atomic.store32 offset=4
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $atomic-rmw
+  (local $0 i32)
+  (local $1 i64)
+  (local $2 i64)
+  (drop
+   (i32.atomic.rmw.add offset=4
+    (local.get $1)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.add_u offset=4
+    (local.get $1)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw16.and_u
+    (local.get $1)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.or_u
+    (local.get $1)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.xchg_u
+    (local.get $1)
+    (local.get $0)
+   )
+  )
+ )
+ (func $atomic-cmpxchg
+  (local $0 i32)
+  (local $1 i64)
+  (local $2 i64)
+  (drop
+   (i32.atomic.rmw.cmpxchg offset=4
+    (local.get $1)
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.cmpxchg_u
+    (local.get $1)
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.rmw.cmpxchg offset=4
+    (local.get $1)
+    (local.get $2)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.cmpxchg_u
+    (local.get $1)
+    (local.get $2)
+    (local.get $2)
+   )
+  )
+ )
+ (func $atomic-wait-notify
+  (local $0 i32)
+  (local $1 i64)
+  (local $2 i64)
+  (drop
+   (i32.atomic.wait
+    (local.get $1)
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i32.atomic.wait offset=4
+    (local.get $1)
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (drop
+   (atomic.notify
+    (local.get $1)
+    (local.get $0)
+   )
+  )
+  (drop
+   (atomic.notify offset=24
+    (local.get $1)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.wait
+    (local.get $1)
+    (local.get $2)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i64.atomic.wait offset=16
+    (local.get $1)
+    (local.get $2)
+    (local.get $2)
+   )
+  )
+ )
+ (func $atomic-fence
+  (atomic.fence)
+ )
+)
+
diff --git a/binaryen/test/atomics64.wast.fromBinary.noDebugInfo b/binaryen/test/atomics64.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/atomics64.wast.fromBinary.noDebugInfo
@@ -0,0 +1,189 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 (shared i64 23 256))
+ (func $0
+  (local $0 i32)
+  (local $1 i64)
+  (local $2 i64)
+  (drop
+   (i32.atomic.load8_u offset=4
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.load16_u offset=4
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.atomic.load offset=4
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.load8_u
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.load16_u
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.load32_u
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.atomic.load
+    (local.get $1)
+   )
+  )
+  (i32.atomic.store offset=4
+   (local.get $1)
+   (local.get $0)
+  )
+  (i32.atomic.store8 offset=4
+   (local.get $1)
+   (local.get $0)
+  )
+  (i32.atomic.store16 offset=4
+   (local.get $1)
+   (local.get $0)
+  )
+  (i64.atomic.store offset=4
+   (local.get $1)
+   (local.get $2)
+  )
+  (i64.atomic.store8 offset=4
+   (local.get $1)
+   (local.get $2)
+  )
+  (i64.atomic.store16 offset=4
+   (local.get $1)
+   (local.get $2)
+  )
+  (i64.atomic.store32 offset=4
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $1
+  (local $0 i32)
+  (local $1 i64)
+  (local $2 i64)
+  (drop
+   (i32.atomic.rmw.add offset=4
+    (local.get $1)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.add_u offset=4
+    (local.get $1)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw16.and_u
+    (local.get $1)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.or_u
+    (local.get $1)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.xchg_u
+    (local.get $1)
+    (local.get $0)
+   )
+  )
+ )
+ (func $2
+  (local $0 i32)
+  (local $1 i64)
+  (local $2 i64)
+  (drop
+   (i32.atomic.rmw.cmpxchg offset=4
+    (local.get $1)
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.atomic.rmw8.cmpxchg_u
+    (local.get $1)
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.rmw.cmpxchg offset=4
+    (local.get $1)
+    (local.get $2)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i64.atomic.rmw32.cmpxchg_u
+    (local.get $1)
+    (local.get $2)
+    (local.get $2)
+   )
+  )
+ )
+ (func $3
+  (local $0 i32)
+  (local $1 i64)
+  (local $2 i64)
+  (drop
+   (i32.atomic.wait
+    (local.get $1)
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i32.atomic.wait offset=4
+    (local.get $1)
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (drop
+   (atomic.notify
+    (local.get $1)
+    (local.get $0)
+   )
+  )
+  (drop
+   (atomic.notify offset=24
+    (local.get $1)
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.atomic.wait
+    (local.get $1)
+    (local.get $2)
+    (local.get $2)
+   )
+  )
+  (drop
+   (i64.atomic.wait offset=16
+    (local.get $1)
+    (local.get $2)
+    (local.get $2)
+   )
+  )
+ )
+ (func $4
+  (atomic.fence)
+ )
+)
+
diff --git a/binaryen/test/bad_params.asm.js b/binaryen/test/bad_params.asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/bad_params.asm.js
@@ -0,0 +1,30 @@
+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/bigswitch.cpp b/binaryen/test/bigswitch.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/bigswitch.cpp
@@ -0,0 +1,7946 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <SDL.h>
+#include "SDL/SDL_opengl.h"
+
+const char *WWWGLEnumToString(GLenum e)
+{
+switch(e)
+{
+case 0x0000 /* GL_POINTS */: return "GL_POINTS (0x0000)";
+case 0x00000001 /* GL_CURRENT_BIT */: return "GL_LINES/GL_CURRENT_BIT/GL_CLIENT_PIXEL_STORE_BIT (0x00000001)";
+case 0x0002 /* GL_LINE_LOOP */: return "GL_LINE_LOOP/GL_POINT_BIT/GL_CLIENT_VERTEX_ARRAY_BIT (0x0002)";
+case 0x0003 /* GL_LINE_STRIP */: return "GL_LINE_STRIP (0x0003)";
+case 0x00000004 /* GL_LINE_BIT */: return "GL_TRIANGLES/GL_LINE_BIT (0x00000004)";
+case 0x0005 /* GL_TRIANGLE_STRIP */: return "GL_TRIANGLE_STRIP (0x0005)";
+case 0x0006 /* GL_TRIANGLE_FAN */: return "GL_TRIANGLE_FAN (0x0006)";
+case 0x0007 /* GL_QUADS */: return "GL_QUADS (0x0007)";
+case 0x0008 /* GL_QUAD_STRIP */: return "GL_QUAD_STRIP/GL_POLYGON_BIT (0x0008)";
+case 0x0009 /* GL_POLYGON */: return "GL_POLYGON (0x0009)";
+case 0x00000010 /* GL_POLYGON_STIPPLE_BIT */: return "GL_POLYGON_STIPPLE_BIT (0x00000010)";
+case 0x00000020 /* GL_PIXEL_MODE_BIT */: return "GL_PIXEL_MODE_BIT (0x00000020)";
+case 0x00000040 /* GL_LIGHTING_BIT */: return "GL_LIGHTING_BIT (0x00000040)";
+case 0x00000080 /* GL_FOG_BIT */: return "GL_FOG_BIT (0x00000080)";
+case 0x00000100 /* GL_DEPTH_BUFFER_BIT */: return "GL_DEPTH_BUFFER_BIT/GL_ACCUM (0x00000100)";
+case 0x0101 /* GL_LOAD */: return "GL_LOAD (0x0101)";
+case 0x0102 /* GL_RETURN */: return "GL_RETURN (0x0102)";
+case 0x0103 /* GL_MULT */: return "GL_MULT (0x0103)";
+case 0x0104 /* GL_ADD */: return "GL_ADD (0x0104)";
+case 0x0200 /* GL_NEVER */: return "GL_NEVER/GL_ACCUM_BUFFER_BIT (0x0200)";
+case 0x0201 /* GL_LESS */: return "GL_LESS (0x0201)";
+case 0x0202 /* GL_EQUAL */: return "GL_EQUAL (0x0202)";
+case 0x0203 /* GL_LEQUAL */: return "GL_LEQUAL (0x0203)";
+case 0x0204 /* GL_GREATER */: return "GL_GREATER (0x0204)";
+case 0x0205 /* GL_NOTEQUAL */: return "GL_NOTEQUAL (0x0205)";
+case 0x0206 /* GL_GEQUAL */: return "GL_GEQUAL (0x0206)";
+case 0x0207 /* GL_ALWAYS */: return "GL_ALWAYS (0x0207)";
+case 0x0300 /* GL_SRC_COLOR */: return "GL_SRC_COLOR (0x0300)";
+case 0x0301 /* GL_ONE_MINUS_SRC_COLOR */: return "GL_ONE_MINUS_SRC_COLOR (0x0301)";
+case 0x0302 /* GL_SRC_ALPHA */: return "GL_SRC_ALPHA (0x0302)";
+case 0x0303 /* GL_ONE_MINUS_SRC_ALPHA */: return "GL_ONE_MINUS_SRC_ALPHA (0x0303)";
+case 0x0304 /* GL_DST_ALPHA */: return "GL_DST_ALPHA (0x0304)";
+case 0x0305 /* GL_ONE_MINUS_DST_ALPHA */: return "GL_ONE_MINUS_DST_ALPHA (0x0305)";
+case 0x0306 /* GL_DST_COLOR */: return "GL_DST_COLOR (0x0306)";
+case 0x0307 /* GL_ONE_MINUS_DST_COLOR */: return "GL_ONE_MINUS_DST_COLOR (0x0307)";
+case 0x0308 /* GL_SRC_ALPHA_SATURATE */: return "GL_SRC_ALPHA_SATURATE (0x0308)";
+case 0x00000400 /* GL_STENCIL_BUFFER_BIT */: return "GL_STENCIL_BUFFER_BIT/GL_FRONT_LEFT (0x00000400)";
+case 0x0401 /* GL_FRONT_RIGHT */: return "GL_FRONT_RIGHT (0x0401)";
+case 0x0402 /* GL_BACK_LEFT */: return "GL_BACK_LEFT (0x0402)";
+case 0x0403 /* GL_BACK_RIGHT */: return "GL_BACK_RIGHT (0x0403)";
+case 0x0404 /* GL_FRONT */: return "GL_FRONT (0x0404)";
+case 0x0405 /* GL_BACK */: return "GL_BACK (0x0405)";
+case 0x0406 /* GL_LEFT */: return "GL_LEFT (0x0406)";
+case 0x0407 /* GL_RIGHT */: return "GL_RIGHT (0x0407)";
+case 0x0408 /* GL_FRONT_AND_BACK */: return "GL_FRONT_AND_BACK (0x0408)";
+case 0x0409 /* GL_AUX0 */: return "GL_AUX0 (0x0409)";
+case 0x040A /* GL_AUX1 */: return "GL_AUX1 (0x040A)";
+case 0x040B /* GL_AUX2 */: return "GL_AUX2 (0x040B)";
+case 0x040C /* GL_AUX3 */: return "GL_AUX3 (0x040C)";
+case 0x0500 /* GL_INVALID_ENUM */: return "GL_INVALID_ENUM (0x0500)";
+case 0x0501 /* GL_INVALID_VALUE */: return "GL_INVALID_VALUE (0x0501)";
+case 0x0502 /* GL_INVALID_OPERATION */: return "GL_INVALID_OPERATION (0x0502)";
+case 0x0503 /* GL_STACK_OVERFLOW */: return "GL_STACK_OVERFLOW (0x0503)";
+case 0x0504 /* GL_STACK_UNDERFLOW */: return "GL_STACK_UNDERFLOW (0x0504)";
+case 0x0505 /* GL_OUT_OF_MEMORY */: return "GL_OUT_OF_MEMORY (0x0505)";
+case 0x0600 /* GL_2D */: return "GL_2D (0x0600)";
+case 0x0601 /* GL_3D */: return "GL_3D (0x0601)";
+case 0x0602 /* GL_3D_COLOR */: return "GL_3D_COLOR (0x0602)";
+case 0x0603 /* GL_3D_COLOR_TEXTURE */: return "GL_3D_COLOR_TEXTURE (0x0603)";
+case 0x0604 /* GL_4D_COLOR_TEXTURE */: return "GL_4D_COLOR_TEXTURE (0x0604)";
+case 0x0700 /* GL_PASS_THROUGH_TOKEN */: return "GL_PASS_THROUGH_TOKEN (0x0700)";
+case 0x0701 /* GL_POINT_TOKEN */: return "GL_POINT_TOKEN (0x0701)";
+case 0x0702 /* GL_LINE_TOKEN */: return "GL_LINE_TOKEN (0x0702)";
+case 0x0703 /* GL_POLYGON_TOKEN */: return "GL_POLYGON_TOKEN (0x0703)";
+case 0x0704 /* GL_BITMAP_TOKEN */: return "GL_BITMAP_TOKEN (0x0704)";
+case 0x0705 /* GL_DRAW_PIXEL_TOKEN */: return "GL_DRAW_PIXEL_TOKEN (0x0705)";
+case 0x0706 /* GL_COPY_PIXEL_TOKEN */: return "GL_COPY_PIXEL_TOKEN (0x0706)";
+case 0x0707 /* GL_LINE_RESET_TOKEN */: return "GL_LINE_RESET_TOKEN (0x0707)";
+case 0x0800 /* GL_EXP */: return "GL_EXP/GL_VIEWPORT_BIT (0x0800)";
+case 0x0801 /* GL_EXP2 */: return "GL_EXP2 (0x0801)";
+case 0x0900 /* GL_CW */: return "GL_CW (0x0900)";
+case 0x0901 /* GL_CCW */: return "GL_CCW (0x0901)";
+case 0x0A00 /* GL_COEFF */: return "GL_COEFF (0x0A00)";
+case 0x0A01 /* GL_ORDER */: return "GL_ORDER (0x0A01)";
+case 0x0A02 /* GL_DOMAIN */: return "GL_DOMAIN (0x0A02)";
+case 0x0B00 /* GL_CURRENT_COLOR */: return "GL_CURRENT_COLOR (0x0B00)";
+case 0x0B01 /* GL_CURRENT_INDEX */: return "GL_CURRENT_INDEX (0x0B01)";
+case 0x0B02 /* GL_CURRENT_NORMAL */: return "GL_CURRENT_NORMAL (0x0B02)";
+case 0x0B03 /* GL_CURRENT_TEXTURE_COORDS */: return "GL_CURRENT_TEXTURE_COORDS (0x0B03)";
+case 0x0B04 /* GL_CURRENT_RASTER_COLOR */: return "GL_CURRENT_RASTER_COLOR (0x0B04)";
+case 0x0B05 /* GL_CURRENT_RASTER_INDEX */: return "GL_CURRENT_RASTER_INDEX (0x0B05)";
+case 0x0B06 /* GL_CURRENT_RASTER_TEXTURE_COORDS */: return "GL_CURRENT_RASTER_TEXTURE_COORDS (0x0B06)";
+case 0x0B07 /* GL_CURRENT_RASTER_POSITION */: return "GL_CURRENT_RASTER_POSITION (0x0B07)";
+case 0x0B08 /* GL_CURRENT_RASTER_POSITION_VALID */: return "GL_CURRENT_RASTER_POSITION_VALID (0x0B08)";
+case 0x0B09 /* GL_CURRENT_RASTER_DISTANCE */: return "GL_CURRENT_RASTER_DISTANCE (0x0B09)";
+case 0x0B10 /* GL_POINT_SMOOTH */: return "GL_POINT_SMOOTH (0x0B10)";
+case 0x0B11 /* GL_POINT_SIZE */: return "GL_POINT_SIZE (0x0B11)";
+case 0x0B20 /* GL_LINE_SMOOTH */: return "GL_LINE_SMOOTH (0x0B20)";
+case 0x0B21 /* GL_LINE_WIDTH */: return "GL_LINE_WIDTH (0x0B21)";
+case 0x0B24 /* GL_LINE_STIPPLE */: return "GL_LINE_STIPPLE (0x0B24)";
+case 0x0B25 /* GL_LINE_STIPPLE_PATTERN */: return "GL_LINE_STIPPLE_PATTERN (0x0B25)";
+case 0x0B26 /* GL_LINE_STIPPLE_REPEAT */: return "GL_LINE_STIPPLE_REPEAT (0x0B26)";
+case 0x0B30 /* GL_LIST_MODE */: return "GL_LIST_MODE (0x0B30)";
+case 0x0B31 /* GL_MAX_LIST_NESTING */: return "GL_MAX_LIST_NESTING (0x0B31)";
+case 0x0B32 /* GL_LIST_BASE */: return "GL_LIST_BASE (0x0B32)";
+case 0x0B33 /* GL_LIST_INDEX */: return "GL_LIST_INDEX (0x0B33)";
+case 0x0B40 /* GL_POLYGON_MODE */: return "GL_POLYGON_MODE (0x0B40)";
+case 0x0B41 /* GL_POLYGON_SMOOTH */: return "GL_POLYGON_SMOOTH (0x0B41)";
+case 0x0B42 /* GL_POLYGON_STIPPLE */: return "GL_POLYGON_STIPPLE (0x0B42)";
+case 0x0B43 /* GL_EDGE_FLAG */: return "GL_EDGE_FLAG (0x0B43)";
+case 0x0B44 /* GL_CULL_FACE */: return "GL_CULL_FACE (0x0B44)";
+case 0x0B45 /* GL_CULL_FACE_MODE */: return "GL_CULL_FACE_MODE (0x0B45)";
+case 0x0B46 /* GL_FRONT_FACE */: return "GL_FRONT_FACE (0x0B46)";
+case 0x0B50 /* GL_LIGHTING */: return "GL_LIGHTING (0x0B50)";
+case 0x0B51 /* GL_LIGHT_MODEL_LOCAL_VIEWER */: return "GL_LIGHT_MODEL_LOCAL_VIEWER (0x0B51)";
+case 0x0B52 /* GL_LIGHT_MODEL_TWO_SIDE */: return "GL_LIGHT_MODEL_TWO_SIDE (0x0B52)";
+case 0x0B53 /* GL_LIGHT_MODEL_AMBIENT */: return "GL_LIGHT_MODEL_AMBIENT (0x0B53)";
+case 0x0B54 /* GL_SHADE_MODEL */: return "GL_SHADE_MODEL (0x0B54)";
+case 0x0B55 /* GL_COLOR_MATERIAL_FACE */: return "GL_COLOR_MATERIAL_FACE (0x0B55)";
+case 0x0B56 /* GL_COLOR_MATERIAL_PARAMETER */: return "GL_COLOR_MATERIAL_PARAMETER (0x0B56)";
+case 0x0B57 /* GL_COLOR_MATERIAL */: return "GL_COLOR_MATERIAL (0x0B57)";
+case 0x0B60 /* GL_FOG */: return "GL_FOG (0x0B60)";
+case 0x0B61 /* GL_FOG_INDEX */: return "GL_FOG_INDEX (0x0B61)";
+case 0x0B62 /* GL_FOG_DENSITY */: return "GL_FOG_DENSITY (0x0B62)";
+case 0x0B63 /* GL_FOG_START */: return "GL_FOG_START (0x0B63)";
+case 0x0B64 /* GL_FOG_END */: return "GL_FOG_END (0x0B64)";
+case 0x0B65 /* GL_FOG_MODE */: return "GL_FOG_MODE (0x0B65)";
+case 0x0B66 /* GL_FOG_COLOR */: return "GL_FOG_COLOR (0x0B66)";
+case 0x0B70 /* GL_DEPTH_RANGE */: return "GL_DEPTH_RANGE (0x0B70)";
+case 0x0B71 /* GL_DEPTH_TEST */: return "GL_DEPTH_TEST (0x0B71)";
+case 0x0B72 /* GL_DEPTH_WRITEMASK */: return "GL_DEPTH_WRITEMASK (0x0B72)";
+case 0x0B73 /* GL_DEPTH_CLEAR_VALUE */: return "GL_DEPTH_CLEAR_VALUE (0x0B73)";
+case 0x0B74 /* GL_DEPTH_FUNC */: return "GL_DEPTH_FUNC (0x0B74)";
+case 0x0B80 /* GL_ACCUM_CLEAR_VALUE */: return "GL_ACCUM_CLEAR_VALUE (0x0B80)";
+case 0x0B90 /* GL_STENCIL_TEST */: return "GL_STENCIL_TEST (0x0B90)";
+case 0x0B91 /* GL_STENCIL_CLEAR_VALUE */: return "GL_STENCIL_CLEAR_VALUE (0x0B91)";
+case 0x0B92 /* GL_STENCIL_FUNC */: return "GL_STENCIL_FUNC (0x0B92)";
+case 0x0B93 /* GL_STENCIL_VALUE_MASK */: return "GL_STENCIL_VALUE_MASK (0x0B93)";
+case 0x0B94 /* GL_STENCIL_FAIL */: return "GL_STENCIL_FAIL (0x0B94)";
+case 0x0B95 /* GL_STENCIL_PASS_DEPTH_FAIL */: return "GL_STENCIL_PASS_DEPTH_FAIL (0x0B95)";
+case 0x0B96 /* GL_STENCIL_PASS_DEPTH_PASS */: return "GL_STENCIL_PASS_DEPTH_PASS (0x0B96)";
+case 0x0B97 /* GL_STENCIL_REF */: return "GL_STENCIL_REF (0x0B97)";
+case 0x0B98 /* GL_STENCIL_WRITEMASK */: return "GL_STENCIL_WRITEMASK (0x0B98)";
+case 0x0BA0 /* GL_MATRIX_MODE */: return "GL_MATRIX_MODE (0x0BA0)";
+case 0x0BA1 /* GL_NORMALIZE */: return "GL_NORMALIZE (0x0BA1)";
+case 0x0BA2 /* GL_VIEWPORT */: return "GL_VIEWPORT (0x0BA2)";
+case 0x0BA3 /* GL_MODELVIEW_STACK_DEPTH */: return "GL_MODELVIEW_STACK_DEPTH (0x0BA3)";
+case 0x0BA4 /* GL_PROJECTION_STACK_DEPTH */: return "GL_PROJECTION_STACK_DEPTH (0x0BA4)";
+case 0x0BA5 /* GL_TEXTURE_STACK_DEPTH */: return "GL_TEXTURE_STACK_DEPTH (0x0BA5)";
+case 0x0BA6 /* GL_MODELVIEW_MATRIX */: return "GL_MODELVIEW_MATRIX (0x0BA6)";
+case 0x0BA7 /* GL_PROJECTION_MATRIX */: return "GL_PROJECTION_MATRIX (0x0BA7)";
+case 0x0BA8 /* GL_TEXTURE_MATRIX */: return "GL_TEXTURE_MATRIX (0x0BA8)";
+case 0x0BB0 /* GL_ATTRIB_STACK_DEPTH */: return "GL_ATTRIB_STACK_DEPTH (0x0BB0)";
+case 0x0BB1 /* GL_CLIENT_ATTRIB_STACK_DEPTH */: return "GL_CLIENT_ATTRIB_STACK_DEPTH (0x0BB1)";
+case 0x0BC0 /* GL_ALPHA_TEST */: return "GL_ALPHA_TEST (0x0BC0)";
+case 0x0BC1 /* GL_ALPHA_TEST_FUNC */: return "GL_ALPHA_TEST_FUNC (0x0BC1)";
+case 0x0BC2 /* GL_ALPHA_TEST_REF */: return "GL_ALPHA_TEST_REF (0x0BC2)";
+case 0x0BD0 /* GL_DITHER */: return "GL_DITHER (0x0BD0)";
+case 0x0BE0 /* GL_BLEND_DST */: return "GL_BLEND_DST (0x0BE0)";
+case 0x0BE1 /* GL_BLEND_SRC */: return "GL_BLEND_SRC (0x0BE1)";
+case 0x0BE2 /* GL_BLEND */: return "GL_BLEND (0x0BE2)";
+case 0x0BF0 /* GL_LOGIC_OP_MODE */: return "GL_LOGIC_OP_MODE (0x0BF0)";
+case 0x0BF1 /* GL_LOGIC_OP */: return "GL_LOGIC_OP/GL_INDEX_LOGIC_OP (0x0BF1)";
+//case 0x0BF1 /* GL_INDEX_LOGIC_OP */: return "GL_INDEX_LOGIC_OP (0x0BF1)";
+case 0x0BF2 /* GL_COLOR_LOGIC_OP */: return "GL_COLOR_LOGIC_OP (0x0BF2)";
+case 0x0C00 /* GL_AUX_BUFFERS */: return "GL_AUX_BUFFERS (0x0C00)";
+case 0x0C01 /* GL_DRAW_BUFFER */: return "GL_DRAW_BUFFER (0x0C01)";
+case 0x0C02 /* GL_READ_BUFFER */: return "GL_READ_BUFFER (0x0C02)";
+case 0x0C10 /* GL_SCISSOR_BOX */: return "GL_SCISSOR_BOX (0x0C10)";
+case 0x0C11 /* GL_SCISSOR_TEST */: return "GL_SCISSOR_TEST (0x0C11)";
+case 0x0C20 /* GL_INDEX_CLEAR_VALUE */: return "GL_INDEX_CLEAR_VALUE (0x0C20)";
+case 0x0C21 /* GL_INDEX_WRITEMASK */: return "GL_INDEX_WRITEMASK (0x0C21)";
+case 0x0C22 /* GL_COLOR_CLEAR_VALUE */: return "GL_COLOR_CLEAR_VALUE (0x0C22)";
+case 0x0C23 /* GL_COLOR_WRITEMASK */: return "GL_COLOR_WRITEMASK (0x0C23)";
+case 0x0C30 /* GL_INDEX_MODE */: return "GL_INDEX_MODE (0x0C30)";
+case 0x0C31 /* GL_RGBA_MODE */: return "GL_RGBA_MODE (0x0C31)";
+case 0x0C32 /* GL_DOUBLEBUFFER */: return "GL_DOUBLEBUFFER (0x0C32)";
+case 0x0C33 /* GL_STEREO */: return "GL_STEREO (0x0C33)";
+case 0x0C40 /* GL_RENDER_MODE */: return "GL_RENDER_MODE (0x0C40)";
+case 0x0C50 /* GL_PERSPECTIVE_CORRECTION_HINT */: return "GL_PERSPECTIVE_CORRECTION_HINT (0x0C50)";
+case 0x0C51 /* GL_POINT_SMOOTH_HINT */: return "GL_POINT_SMOOTH_HINT (0x0C51)";
+case 0x0C52 /* GL_LINE_SMOOTH_HINT */: return "GL_LINE_SMOOTH_HINT (0x0C52)";
+case 0x0C53 /* GL_POLYGON_SMOOTH_HINT */: return "GL_POLYGON_SMOOTH_HINT (0x0C53)";
+case 0x0C54 /* GL_FOG_HINT */: return "GL_FOG_HINT (0x0C54)";
+case 0x0C60 /* GL_TEXTURE_GEN_S */: return "GL_TEXTURE_GEN_S (0x0C60)";
+case 0x0C61 /* GL_TEXTURE_GEN_T */: return "GL_TEXTURE_GEN_T (0x0C61)";
+case 0x0C62 /* GL_TEXTURE_GEN_R */: return "GL_TEXTURE_GEN_R (0x0C62)";
+case 0x0C63 /* GL_TEXTURE_GEN_Q */: return "GL_TEXTURE_GEN_Q (0x0C63)";
+case 0x0C70 /* GL_PIXEL_MAP_I_TO_I */: return "GL_PIXEL_MAP_I_TO_I (0x0C70)";
+case 0x0C71 /* GL_PIXEL_MAP_S_TO_S */: return "GL_PIXEL_MAP_S_TO_S (0x0C71)";
+case 0x0C72 /* GL_PIXEL_MAP_I_TO_R */: return "GL_PIXEL_MAP_I_TO_R (0x0C72)";
+case 0x0C73 /* GL_PIXEL_MAP_I_TO_G */: return "GL_PIXEL_MAP_I_TO_G (0x0C73)";
+case 0x0C74 /* GL_PIXEL_MAP_I_TO_B */: return "GL_PIXEL_MAP_I_TO_B (0x0C74)";
+case 0x0C75 /* GL_PIXEL_MAP_I_TO_A */: return "GL_PIXEL_MAP_I_TO_A (0x0C75)";
+case 0x0C76 /* GL_PIXEL_MAP_R_TO_R */: return "GL_PIXEL_MAP_R_TO_R (0x0C76)";
+case 0x0C77 /* GL_PIXEL_MAP_G_TO_G */: return "GL_PIXEL_MAP_G_TO_G (0x0C77)";
+case 0x0C78 /* GL_PIXEL_MAP_B_TO_B */: return "GL_PIXEL_MAP_B_TO_B (0x0C78)";
+case 0x0C79 /* GL_PIXEL_MAP_A_TO_A */: return "GL_PIXEL_MAP_A_TO_A (0x0C79)";
+case 0x0CB0 /* GL_PIXEL_MAP_I_TO_I_SIZE */: return "GL_PIXEL_MAP_I_TO_I_SIZE (0x0CB0)";
+case 0x0CB1 /* GL_PIXEL_MAP_S_TO_S_SIZE */: return "GL_PIXEL_MAP_S_TO_S_SIZE (0x0CB1)";
+case 0x0CB2 /* GL_PIXEL_MAP_I_TO_R_SIZE */: return "GL_PIXEL_MAP_I_TO_R_SIZE (0x0CB2)";
+case 0x0CB3 /* GL_PIXEL_MAP_I_TO_G_SIZE */: return "GL_PIXEL_MAP_I_TO_G_SIZE (0x0CB3)";
+case 0x0CB4 /* GL_PIXEL_MAP_I_TO_B_SIZE */: return "GL_PIXEL_MAP_I_TO_B_SIZE (0x0CB4)";
+case 0x0CB5 /* GL_PIXEL_MAP_I_TO_A_SIZE */: return "GL_PIXEL_MAP_I_TO_A_SIZE (0x0CB5)";
+case 0x0CB6 /* GL_PIXEL_MAP_R_TO_R_SIZE */: return "GL_PIXEL_MAP_R_TO_R_SIZE (0x0CB6)";
+case 0x0CB7 /* GL_PIXEL_MAP_G_TO_G_SIZE */: return "GL_PIXEL_MAP_G_TO_G_SIZE (0x0CB7)";
+case 0x0CB8 /* GL_PIXEL_MAP_B_TO_B_SIZE */: return "GL_PIXEL_MAP_B_TO_B_SIZE (0x0CB8)";
+case 0x0CB9 /* GL_PIXEL_MAP_A_TO_A_SIZE */: return "GL_PIXEL_MAP_A_TO_A_SIZE (0x0CB9)";
+case 0x0CF0 /* GL_UNPACK_SWAP_BYTES */: return "GL_UNPACK_SWAP_BYTES (0x0CF0)";
+case 0x0CF1 /* GL_UNPACK_LSB_FIRST */: return "GL_UNPACK_LSB_FIRST (0x0CF1)";
+case 0x0CF2 /* GL_UNPACK_ROW_LENGTH */: return "GL_UNPACK_ROW_LENGTH (0x0CF2)";
+case 0x0CF3 /* GL_UNPACK_SKIP_ROWS */: return "GL_UNPACK_SKIP_ROWS (0x0CF3)";
+case 0x0CF4 /* GL_UNPACK_SKIP_PIXELS */: return "GL_UNPACK_SKIP_PIXELS (0x0CF4)";
+case 0x0CF5 /* GL_UNPACK_ALIGNMENT */: return "GL_UNPACK_ALIGNMENT (0x0CF5)";
+case 0x0D00 /* GL_PACK_SWAP_BYTES */: return "GL_PACK_SWAP_BYTES (0x0D00)";
+case 0x0D01 /* GL_PACK_LSB_FIRST */: return "GL_PACK_LSB_FIRST (0x0D01)";
+case 0x0D02 /* GL_PACK_ROW_LENGTH */: return "GL_PACK_ROW_LENGTH (0x0D02)";
+case 0x0D03 /* GL_PACK_SKIP_ROWS */: return "GL_PACK_SKIP_ROWS (0x0D03)";
+case 0x0D04 /* GL_PACK_SKIP_PIXELS */: return "GL_PACK_SKIP_PIXELS (0x0D04)";
+case 0x0D05 /* GL_PACK_ALIGNMENT */: return "GL_PACK_ALIGNMENT (0x0D05)";
+case 0x0D10 /* GL_MAP_COLOR */: return "GL_MAP_COLOR (0x0D10)";
+case 0x0D11 /* GL_MAP_STENCIL */: return "GL_MAP_STENCIL (0x0D11)";
+case 0x0D12 /* GL_INDEX_SHIFT */: return "GL_INDEX_SHIFT (0x0D12)";
+case 0x0D13 /* GL_INDEX_OFFSET */: return "GL_INDEX_OFFSET (0x0D13)";
+case 0x0D14 /* GL_RED_SCALE */: return "GL_RED_SCALE (0x0D14)";
+case 0x0D15 /* GL_RED_BIAS */: return "GL_RED_BIAS (0x0D15)";
+case 0x0D16 /* GL_ZOOM_X */: return "GL_ZOOM_X (0x0D16)";
+case 0x0D17 /* GL_ZOOM_Y */: return "GL_ZOOM_Y (0x0D17)";
+case 0x0D18 /* GL_GREEN_SCALE */: return "GL_GREEN_SCALE (0x0D18)";
+case 0x0D19 /* GL_GREEN_BIAS */: return "GL_GREEN_BIAS (0x0D19)";
+case 0x0D1A /* GL_BLUE_SCALE */: return "GL_BLUE_SCALE (0x0D1A)";
+case 0x0D1B /* GL_BLUE_BIAS */: return "GL_BLUE_BIAS (0x0D1B)";
+case 0x0D1C /* GL_ALPHA_SCALE */: return "GL_ALPHA_SCALE (0x0D1C)";
+case 0x0D1D /* GL_ALPHA_BIAS */: return "GL_ALPHA_BIAS (0x0D1D)";
+case 0x0D1E /* GL_DEPTH_SCALE */: return "GL_DEPTH_SCALE (0x0D1E)";
+case 0x0D1F /* GL_DEPTH_BIAS */: return "GL_DEPTH_BIAS (0x0D1F)";
+case 0x0D30 /* GL_MAX_EVAL_ORDER */: return "GL_MAX_EVAL_ORDER (0x0D30)";
+case 0x0D31 /* GL_MAX_LIGHTS */: return "GL_MAX_LIGHTS (0x0D31)";
+case 0x0D32 /* GL_MAX_CLIP_PLANES */: return "GL_MAX_CLIP_PLANES (0x0D32)";
+case 0x0D33 /* GL_MAX_TEXTURE_SIZE */: return "GL_MAX_TEXTURE_SIZE (0x0D33)";
+case 0x0D34 /* GL_MAX_PIXEL_MAP_TABLE */: return "GL_MAX_PIXEL_MAP_TABLE (0x0D34)";
+case 0x0D35 /* GL_MAX_ATTRIB_STACK_DEPTH */: return "GL_MAX_ATTRIB_STACK_DEPTH (0x0D35)";
+case 0x0D36 /* GL_MAX_MODELVIEW_STACK_DEPTH */: return "GL_MAX_MODELVIEW_STACK_DEPTH (0x0D36)";
+case 0x0D37 /* GL_MAX_NAME_STACK_DEPTH */: return "GL_MAX_NAME_STACK_DEPTH (0x0D37)";
+case 0x0D38 /* GL_MAX_PROJECTION_STACK_DEPTH */: return "GL_MAX_PROJECTION_STACK_DEPTH (0x0D38)";
+case 0x0D39 /* GL_MAX_TEXTURE_STACK_DEPTH */: return "GL_MAX_TEXTURE_STACK_DEPTH (0x0D39)";
+case 0x0D3A /* GL_MAX_VIEWPORT_DIMS */: return "GL_MAX_VIEWPORT_DIMS (0x0D3A)";
+case 0x0D3B /* GL_MAX_CLIENT_ATTRIB_STACK_DEPTH */: return "GL_MAX_CLIENT_ATTRIB_STACK_DEPTH (0x0D3B)";
+case 0x0D50 /* GL_SUBPIXEL_BITS */: return "GL_SUBPIXEL_BITS (0x0D50)";
+case 0x0D51 /* GL_INDEX_BITS */: return "GL_INDEX_BITS (0x0D51)";
+case 0x0D52 /* GL_RED_BITS */: return "GL_RED_BITS (0x0D52)";
+case 0x0D53 /* GL_GREEN_BITS */: return "GL_GREEN_BITS (0x0D53)";
+case 0x0D54 /* GL_BLUE_BITS */: return "GL_BLUE_BITS (0x0D54)";
+case 0x0D55 /* GL_ALPHA_BITS */: return "GL_ALPHA_BITS (0x0D55)";
+case 0x0D56 /* GL_DEPTH_BITS */: return "GL_DEPTH_BITS (0x0D56)";
+case 0x0D57 /* GL_STENCIL_BITS */: return "GL_STENCIL_BITS (0x0D57)";
+case 0x0D58 /* GL_ACCUM_RED_BITS */: return "GL_ACCUM_RED_BITS (0x0D58)";
+case 0x0D59 /* GL_ACCUM_GREEN_BITS */: return "GL_ACCUM_GREEN_BITS (0x0D59)";
+case 0x0D5A /* GL_ACCUM_BLUE_BITS */: return "GL_ACCUM_BLUE_BITS (0x0D5A)";
+case 0x0D5B /* GL_ACCUM_ALPHA_BITS */: return "GL_ACCUM_ALPHA_BITS (0x0D5B)";
+case 0x0D70 /* GL_NAME_STACK_DEPTH */: return "GL_NAME_STACK_DEPTH (0x0D70)";
+case 0x0D80 /* GL_AUTO_NORMAL */: return "GL_AUTO_NORMAL (0x0D80)";
+case 0x0D90 /* GL_MAP1_COLOR_4 */: return "GL_MAP1_COLOR_4 (0x0D90)";
+case 0x0D91 /* GL_MAP1_INDEX */: return "GL_MAP1_INDEX (0x0D91)";
+case 0x0D92 /* GL_MAP1_NORMAL */: return "GL_MAP1_NORMAL (0x0D92)";
+case 0x0D93 /* GL_MAP1_TEXTURE_COORD_1 */: return "GL_MAP1_TEXTURE_COORD_1 (0x0D93)";
+case 0x0D94 /* GL_MAP1_TEXTURE_COORD_2 */: return "GL_MAP1_TEXTURE_COORD_2 (0x0D94)";
+case 0x0D95 /* GL_MAP1_TEXTURE_COORD_3 */: return "GL_MAP1_TEXTURE_COORD_3 (0x0D95)";
+case 0x0D96 /* GL_MAP1_TEXTURE_COORD_4 */: return "GL_MAP1_TEXTURE_COORD_4 (0x0D96)";
+case 0x0D97 /* GL_MAP1_VERTEX_3 */: return "GL_MAP1_VERTEX_3 (0x0D97)";
+case 0x0D98 /* GL_MAP1_VERTEX_4 */: return "GL_MAP1_VERTEX_4 (0x0D98)";
+case 0x0DB0 /* GL_MAP2_COLOR_4 */: return "GL_MAP2_COLOR_4 (0x0DB0)";
+case 0x0DB1 /* GL_MAP2_INDEX */: return "GL_MAP2_INDEX (0x0DB1)";
+case 0x0DB2 /* GL_MAP2_NORMAL */: return "GL_MAP2_NORMAL (0x0DB2)";
+case 0x0DB3 /* GL_MAP2_TEXTURE_COORD_1 */: return "GL_MAP2_TEXTURE_COORD_1 (0x0DB3)";
+case 0x0DB4 /* GL_MAP2_TEXTURE_COORD_2 */: return "GL_MAP2_TEXTURE_COORD_2 (0x0DB4)";
+case 0x0DB5 /* GL_MAP2_TEXTURE_COORD_3 */: return "GL_MAP2_TEXTURE_COORD_3 (0x0DB5)";
+case 0x0DB6 /* GL_MAP2_TEXTURE_COORD_4 */: return "GL_MAP2_TEXTURE_COORD_4 (0x0DB6)";
+case 0x0DB7 /* GL_MAP2_VERTEX_3 */: return "GL_MAP2_VERTEX_3 (0x0DB7)";
+case 0x0DB8 /* GL_MAP2_VERTEX_4 */: return "GL_MAP2_VERTEX_4 (0x0DB8)";
+case 0x0DD0 /* GL_MAP1_GRID_DOMAIN */: return "GL_MAP1_GRID_DOMAIN (0x0DD0)";
+case 0x0DD1 /* GL_MAP1_GRID_SEGMENTS */: return "GL_MAP1_GRID_SEGMENTS (0x0DD1)";
+case 0x0DD2 /* GL_MAP2_GRID_DOMAIN */: return "GL_MAP2_GRID_DOMAIN (0x0DD2)";
+case 0x0DD3 /* GL_MAP2_GRID_SEGMENTS */: return "GL_MAP2_GRID_SEGMENTS (0x0DD3)";
+case 0x0DE0 /* GL_TEXTURE_1D */: return "GL_TEXTURE_1D (0x0DE0)";
+case 0x0DE1 /* GL_TEXTURE_2D */: return "GL_TEXTURE_2D (0x0DE1)";
+case 0x0DF0 /* GL_FEEDBACK_BUFFER_POINTER */: return "GL_FEEDBACK_BUFFER_POINTER (0x0DF0)";
+case 0x0DF1 /* GL_FEEDBACK_BUFFER_SIZE */: return "GL_FEEDBACK_BUFFER_SIZE (0x0DF1)";
+case 0x0DF2 /* GL_FEEDBACK_BUFFER_TYPE */: return "GL_FEEDBACK_BUFFER_TYPE (0x0DF2)";
+case 0x0DF3 /* GL_SELECTION_BUFFER_POINTER */: return "GL_SELECTION_BUFFER_POINTER (0x0DF3)";
+case 0x0DF4 /* GL_SELECTION_BUFFER_SIZE */: return "GL_SELECTION_BUFFER_SIZE (0x0DF4)";
+case 0x1000 /* GL_TEXTURE_WIDTH */: return "GL_TEXTURE_WIDTH/GL_TRANSFORM_BIT (0x1000)";
+case 0x1001 /* GL_TEXTURE_HEIGHT */: return "GL_TEXTURE_HEIGHT (0x1001)";
+//case 0x1003 /* GL_TEXTURE_COMPONENTS */: return "GL_TEXTURE_COMPONENTS (0x1003)";
+case 0x1003 /* GL_TEXTURE_INTERNAL_FORMAT */: return "GL_TEXTURE_INTERNAL_FORMAT/GL_TEXTURE_COMPONENTS (0x1003)";
+case 0x1004 /* GL_TEXTURE_BORDER_COLOR */: return "GL_TEXTURE_BORDER_COLOR (0x1004)";
+case 0x1005 /* GL_TEXTURE_BORDER */: return "GL_TEXTURE_BORDER (0x1005)";
+case 0x1100 /* GL_DONT_CARE */: return "GL_DONT_CARE (0x1100)";
+case 0x1101 /* GL_FASTEST */: return "GL_FASTEST (0x1101)";
+case 0x1102 /* GL_NICEST */: return "GL_NICEST (0x1102)";
+case 0x1200 /* GL_AMBIENT */: return "GL_AMBIENT (0x1200)";
+case 0x1201 /* GL_DIFFUSE */: return "GL_DIFFUSE (0x1201)";
+case 0x1202 /* GL_SPECULAR */: return "GL_SPECULAR (0x1202)";
+case 0x1203 /* GL_POSITION */: return "GL_POSITION (0x1203)";
+case 0x1204 /* GL_SPOT_DIRECTION */: return "GL_SPOT_DIRECTION (0x1204)";
+case 0x1205 /* GL_SPOT_EXPONENT */: return "GL_SPOT_EXPONENT (0x1205)";
+case 0x1206 /* GL_SPOT_CUTOFF */: return "GL_SPOT_CUTOFF (0x1206)";
+case 0x1207 /* GL_CONSTANT_ATTENUATION */: return "GL_CONSTANT_ATTENUATION (0x1207)";
+case 0x1208 /* GL_LINEAR_ATTENUATION */: return "GL_LINEAR_ATTENUATION (0x1208)";
+case 0x1209 /* GL_QUADRATIC_ATTENUATION */: return "GL_QUADRATIC_ATTENUATION (0x1209)";
+case 0x1300 /* GL_COMPILE */: return "GL_COMPILE (0x1300)";
+case 0x1301 /* GL_COMPILE_AND_EXECUTE */: return "GL_COMPILE_AND_EXECUTE (0x1301)";
+case 0x1400 /* GL_BYTE */: return "GL_BYTE (0x1400)";
+case 0x1401 /* GL_UNSIGNED_BYTE */: return "GL_UNSIGNED_BYTE (0x1401)";
+case 0x1402 /* GL_SHORT */: return "GL_SHORT (0x1402)";
+case 0x1403 /* GL_UNSIGNED_SHORT */: return "GL_UNSIGNED_SHORT (0x1403)";
+case 0x1404 /* GL_INT */: return "GL_INT (0x1404)";
+case 0x1405 /* GL_UNSIGNED_INT */: return "GL_UNSIGNED_INT (0x1405)";
+case 0x1406 /* GL_FLOAT */: return "GL_FLOAT (0x1406)";
+case 0x1407 /* GL_2_BYTES */: return "GL_2_BYTES (0x1407)";
+case 0x1408 /* GL_3_BYTES */: return "GL_3_BYTES (0x1408)";
+case 0x1409 /* GL_4_BYTES */: return "GL_4_BYTES (0x1409)";
+case 0x140A /* GL_DOUBLE */: return "GL_DOUBLE (0x140A)";
+case 0x1500 /* GL_CLEAR */: return "GL_CLEAR (0x1500)";
+case 0x1501 /* GL_AND */: return "GL_AND (0x1501)";
+case 0x1502 /* GL_AND_REVERSE */: return "GL_AND_REVERSE (0x1502)";
+case 0x1503 /* GL_COPY */: return "GL_COPY (0x1503)";
+case 0x1504 /* GL_AND_INVERTED */: return "GL_AND_INVERTED (0x1504)";
+case 0x1505 /* GL_NOOP */: return "GL_NOOP (0x1505)";
+case 0x1506 /* GL_XOR */: return "GL_XOR (0x1506)";
+case 0x1507 /* GL_OR */: return "GL_OR (0x1507)";
+case 0x1508 /* GL_NOR */: return "GL_NOR (0x1508)";
+case 0x1509 /* GL_EQUIV */: return "GL_EQUIV (0x1509)";
+case 0x150A /* GL_INVERT */: return "GL_INVERT (0x150A)";
+case 0x150B /* GL_OR_REVERSE */: return "GL_OR_REVERSE (0x150B)";
+case 0x150C /* GL_COPY_INVERTED */: return "GL_COPY_INVERTED (0x150C)";
+case 0x150D /* GL_OR_INVERTED */: return "GL_OR_INVERTED (0x150D)";
+case 0x150E /* GL_NAND */: return "GL_NAND (0x150E)";
+case 0x150F /* GL_SET */: return "GL_SET (0x150F)";
+case 0x1600 /* GL_EMISSION */: return "GL_EMISSION (0x1600)";
+case 0x1601 /* GL_SHININESS */: return "GL_SHININESS (0x1601)";
+case 0x1602 /* GL_AMBIENT_AND_DIFFUSE */: return "GL_AMBIENT_AND_DIFFUSE (0x1602)";
+case 0x1603 /* GL_COLOR_INDEXES */: return "GL_COLOR_INDEXES (0x1603)";
+case 0x1700 /* GL_MODELVIEW */: return "GL_MODELVIEW (0x1700)";
+case 0x1701 /* GL_PROJECTION */: return "GL_PROJECTION (0x1701)";
+case 0x1702 /* GL_TEXTURE */: return "GL_TEXTURE (0x1702)";
+case 0x1800 /* GL_COLOR */: return "GL_COLOR (0x1800)";
+case 0x1801 /* GL_DEPTH */: return "GL_DEPTH (0x1801)";
+case 0x1802 /* GL_STENCIL */: return "GL_STENCIL (0x1802)";
+case 0x1900 /* GL_COLOR_INDEX */: return "GL_COLOR_INDEX (0x1900)";
+case 0x1901 /* GL_STENCIL_INDEX */: return "GL_STENCIL_INDEX (0x1901)";
+case 0x1902 /* GL_DEPTH_COMPONENT */: return "GL_DEPTH_COMPONENT (0x1902)";
+case 0x1903 /* GL_RED */: return "GL_RED (0x1903)";
+case 0x1904 /* GL_GREEN */: return "GL_GREEN (0x1904)";
+case 0x1905 /* GL_BLUE */: return "GL_BLUE (0x1905)";
+case 0x1906 /* GL_ALPHA */: return "GL_ALPHA (0x1906)";
+case 0x1907 /* GL_RGB */: return "GL_RGB (0x1907)";
+case 0x1908 /* GL_RGBA */: return "GL_RGBA (0x1908)";
+case 0x1909 /* GL_LUMINANCE */: return "GL_LUMINANCE (0x1909)";
+case 0x190A /* GL_LUMINANCE_ALPHA */: return "GL_LUMINANCE_ALPHA (0x190A)";
+case 0x1A00 /* GL_BITMAP */: return "GL_BITMAP (0x1A00)";
+case 0x1B00 /* GL_POINT */: return "GL_POINT (0x1B00)";
+case 0x1B01 /* GL_LINE */: return "GL_LINE (0x1B01)";
+case 0x1B02 /* GL_FILL */: return "GL_FILL (0x1B02)";
+case 0x1C00 /* GL_RENDER */: return "GL_RENDER (0x1C00)";
+case 0x1C01 /* GL_FEEDBACK */: return "GL_FEEDBACK (0x1C01)";
+case 0x1C02 /* GL_SELECT */: return "GL_SELECT (0x1C02)";
+case 0x1D00 /* GL_FLAT */: return "GL_FLAT (0x1D00)";
+case 0x1D01 /* GL_SMOOTH */: return "GL_SMOOTH (0x1D01)";
+case 0x1E00 /* GL_KEEP */: return "GL_KEEP (0x1E00)";
+case 0x1E01 /* GL_REPLACE */: return "GL_REPLACE (0x1E01)";
+case 0x1E02 /* GL_INCR */: return "GL_INCR (0x1E02)";
+case 0x1E03 /* GL_DECR */: return "GL_DECR (0x1E03)";
+case 0x1F00 /* GL_VENDOR */: return "GL_VENDOR (0x1F00)";
+case 0x1F01 /* GL_RENDERER */: return "GL_RENDERER (0x1F01)";
+case 0x1F02 /* GL_VERSION */: return "GL_VERSION (0x1F02)";
+case 0x1F03 /* GL_EXTENSIONS */: return "GL_EXTENSIONS (0x1F03)";
+case 0x2000 /* GL_S */: return "GL_S/GL_ENABLE_BIT (0x2000)";
+case 0x2001 /* GL_T */: return "GL_T (0x2001)";
+case 0x2002 /* GL_R */: return "GL_R (0x2002)";
+case 0x2003 /* GL_Q */: return "GL_Q (0x2003)";
+case 0x2100 /* GL_MODULATE */: return "GL_MODULATE (0x2100)";
+case 0x2101 /* GL_DECAL */: return "GL_DECAL (0x2101)";
+case 0x2200 /* GL_TEXTURE_ENV_MODE */: return "GL_TEXTURE_ENV_MODE (0x2200)";
+case 0x2201 /* GL_TEXTURE_ENV_COLOR */: return "GL_TEXTURE_ENV_COLOR (0x2201)";
+case 0x2300 /* GL_TEXTURE_ENV */: return "GL_TEXTURE_ENV (0x2300)";
+case 0x2400 /* GL_EYE_LINEAR */: return "GL_EYE_LINEAR (0x2400)";
+case 0x2401 /* GL_OBJECT_LINEAR */: return "GL_OBJECT_LINEAR (0x2401)";
+case 0x2402 /* GL_SPHERE_MAP */: return "GL_SPHERE_MAP (0x2402)";
+case 0x2500 /* GL_TEXTURE_GEN_MODE */: return "GL_TEXTURE_GEN_MODE (0x2500)";
+case 0x2501 /* GL_OBJECT_PLANE */: return "GL_OBJECT_PLANE (0x2501)";
+case 0x2502 /* GL_EYE_PLANE */: return "GL_EYE_PLANE (0x2502)";
+case 0x2600 /* GL_NEAREST */: return "GL_NEAREST (0x2600)";
+case 0x2601 /* GL_LINEAR */: return "GL_LINEAR (0x2601)";
+case 0x2700 /* GL_NEAREST_MIPMAP_NEAREST */: return "GL_NEAREST_MIPMAP_NEAREST (0x2700)";
+case 0x2701 /* GL_LINEAR_MIPMAP_NEAREST */: return "GL_LINEAR_MIPMAP_NEAREST (0x2701)";
+case 0x2702 /* GL_NEAREST_MIPMAP_LINEAR */: return "GL_NEAREST_MIPMAP_LINEAR (0x2702)";
+case 0x2703 /* GL_LINEAR_MIPMAP_LINEAR */: return "GL_LINEAR_MIPMAP_LINEAR (0x2703)";
+case 0x2800 /* GL_TEXTURE_MAG_FILTER */: return "GL_TEXTURE_MAG_FILTER (0x2800)";
+case 0x2801 /* GL_TEXTURE_MIN_FILTER */: return "GL_TEXTURE_MIN_FILTER (0x2801)";
+case 0x2802 /* GL_TEXTURE_WRAP_S */: return "GL_TEXTURE_WRAP_S (0x2802)";
+case 0x2803 /* GL_TEXTURE_WRAP_T */: return "GL_TEXTURE_WRAP_T (0x2803)";
+case 0x2900 /* GL_CLAMP */: return "GL_CLAMP (0x2900)";
+case 0x2901 /* GL_REPEAT */: return "GL_REPEAT (0x2901)";
+case 0x2A00 /* GL_POLYGON_OFFSET_UNITS */: return "GL_POLYGON_OFFSET_UNITS (0x2A00)";
+case 0x2A01 /* GL_POLYGON_OFFSET_POINT */: return "GL_POLYGON_OFFSET_POINT (0x2A01)";
+case 0x2A02 /* GL_POLYGON_OFFSET_LINE */: return "GL_POLYGON_OFFSET_LINE (0x2A02)";
+case 0x2A10 /* GL_R3_G3_B2 */: return "GL_R3_G3_B2 (0x2A10)";
+case 0x2A20 /* GL_V2F */: return "GL_V2F (0x2A20)";
+case 0x2A21 /* GL_V3F */: return "GL_V3F (0x2A21)";
+case 0x2A22 /* GL_C4UB_V2F */: return "GL_C4UB_V2F (0x2A22)";
+case 0x2A23 /* GL_C4UB_V3F */: return "GL_C4UB_V3F (0x2A23)";
+case 0x2A24 /* GL_C3F_V3F */: return "GL_C3F_V3F (0x2A24)";
+case 0x2A25 /* GL_N3F_V3F */: return "GL_N3F_V3F (0x2A25)";
+case 0x2A26 /* GL_C4F_N3F_V3F */: return "GL_C4F_N3F_V3F (0x2A26)";
+case 0x2A27 /* GL_T2F_V3F */: return "GL_T2F_V3F (0x2A27)";
+case 0x2A28 /* GL_T4F_V4F */: return "GL_T4F_V4F (0x2A28)";
+case 0x2A29 /* GL_T2F_C4UB_V3F */: return "GL_T2F_C4UB_V3F (0x2A29)";
+case 0x2A2A /* GL_T2F_C3F_V3F */: return "GL_T2F_C3F_V3F (0x2A2A)";
+case 0x2A2B /* GL_T2F_N3F_V3F */: return "GL_T2F_N3F_V3F (0x2A2B)";
+case 0x2A2C /* GL_T2F_C4F_N3F_V3F */: return "GL_T2F_C4F_N3F_V3F (0x2A2C)";
+case 0x2A2D /* GL_T4F_C4F_N3F_V4F */: return "GL_T4F_C4F_N3F_V4F (0x2A2D)";
+case 0x3000 /* GL_CLIP_PLANE0 */: return "GL_CLIP_PLANE0 (0x3000)";
+case 0x3001 /* GL_CLIP_PLANE1 */: return "GL_CLIP_PLANE1 (0x3001)";
+case 0x3002 /* GL_CLIP_PLANE2 */: return "GL_CLIP_PLANE2 (0x3002)";
+case 0x3003 /* GL_CLIP_PLANE3 */: return "GL_CLIP_PLANE3 (0x3003)";
+case 0x3004 /* GL_CLIP_PLANE4 */: return "GL_CLIP_PLANE4 (0x3004)";
+case 0x3005 /* GL_CLIP_PLANE5 */: return "GL_CLIP_PLANE5 (0x3005)";
+case 0x4000 /* GL_LIGHT0 */: return "GL_LIGHT0/GL_COLOR_BUFFER_BIT (0x4000)";
+case 0x4001 /* GL_LIGHT1 */: return "GL_LIGHT1 (0x4001)";
+case 0x4002 /* GL_LIGHT2 */: return "GL_LIGHT2 (0x4002)";
+case 0x4003 /* GL_LIGHT3 */: return "GL_LIGHT3 (0x4003)";
+case 0x4004 /* GL_LIGHT4 */: return "GL_LIGHT4 (0x4004)";
+case 0x4005 /* GL_LIGHT5 */: return "GL_LIGHT5 (0x4005)";
+case 0x4006 /* GL_LIGHT6 */: return "GL_LIGHT6 (0x4006)";
+case 0x4007 /* GL_LIGHT7 */: return "GL_LIGHT7 (0x4007)";
+case 0x00008000 /* GL_HINT_BIT */: return "GL_HINT_BIT (0x00008000)";
+case 0x8037 /* GL_POLYGON_OFFSET_FILL */: return "GL_POLYGON_OFFSET_FILL (0x8037)";
+case 0x8038 /* GL_POLYGON_OFFSET_FACTOR */: return "GL_POLYGON_OFFSET_FACTOR (0x8038)";
+case 0x803B /* GL_ALPHA4 */: return "GL_ALPHA4 (0x803B)";
+case 0x803C /* GL_ALPHA8 */: return "GL_ALPHA8 (0x803C)";
+case 0x803D /* GL_ALPHA12 */: return "GL_ALPHA12 (0x803D)";
+case 0x803E /* GL_ALPHA16 */: return "GL_ALPHA16 (0x803E)";
+case 0x803F /* GL_LUMINANCE4 */: return "GL_LUMINANCE4 (0x803F)";
+case 0x8040 /* GL_LUMINANCE8 */: return "GL_LUMINANCE8 (0x8040)";
+case 0x8041 /* GL_LUMINANCE12 */: return "GL_LUMINANCE12 (0x8041)";
+case 0x8042 /* GL_LUMINANCE16 */: return "GL_LUMINANCE16 (0x8042)";
+case 0x8043 /* GL_LUMINANCE4_ALPHA4 */: return "GL_LUMINANCE4_ALPHA4 (0x8043)";
+case 0x8044 /* GL_LUMINANCE6_ALPHA2 */: return "GL_LUMINANCE6_ALPHA2 (0x8044)";
+case 0x8045 /* GL_LUMINANCE8_ALPHA8 */: return "GL_LUMINANCE8_ALPHA8 (0x8045)";
+case 0x8046 /* GL_LUMINANCE12_ALPHA4 */: return "GL_LUMINANCE12_ALPHA4 (0x8046)";
+case 0x8047 /* GL_LUMINANCE12_ALPHA12 */: return "GL_LUMINANCE12_ALPHA12 (0x8047)";
+case 0x8048 /* GL_LUMINANCE16_ALPHA16 */: return "GL_LUMINANCE16_ALPHA16 (0x8048)";
+case 0x8049 /* GL_INTENSITY */: return "GL_INTENSITY (0x8049)";
+case 0x804A /* GL_INTENSITY4 */: return "GL_INTENSITY4 (0x804A)";
+case 0x804B /* GL_INTENSITY8 */: return "GL_INTENSITY8 (0x804B)";
+case 0x804C /* GL_INTENSITY12 */: return "GL_INTENSITY12 (0x804C)";
+case 0x804D /* GL_INTENSITY16 */: return "GL_INTENSITY16 (0x804D)";
+case 0x804F /* GL_RGB4 */: return "GL_RGB4 (0x804F)";
+case 0x8050 /* GL_RGB5 */: return "GL_RGB5 (0x8050)";
+case 0x8051 /* GL_RGB8 */: return "GL_RGB8 (0x8051)";
+case 0x8052 /* GL_RGB10 */: return "GL_RGB10 (0x8052)";
+case 0x8053 /* GL_RGB12 */: return "GL_RGB12 (0x8053)";
+case 0x8054 /* GL_RGB16 */: return "GL_RGB16 (0x8054)";
+case 0x8055 /* GL_RGBA2 */: return "GL_RGBA2 (0x8055)";
+case 0x8056 /* GL_RGBA4 */: return "GL_RGBA4 (0x8056)";
+case 0x8057 /* GL_RGB5_A1 */: return "GL_RGB5_A1 (0x8057)";
+case 0x8058 /* GL_RGBA8 */: return "GL_RGBA8 (0x8058)";
+case 0x8059 /* GL_RGB10_A2 */: return "GL_RGB10_A2 (0x8059)";
+case 0x805A /* GL_RGBA12 */: return "GL_RGBA12 (0x805A)";
+case 0x805B /* GL_RGBA16 */: return "GL_RGBA16 (0x805B)";
+case 0x805C /* GL_TEXTURE_RED_SIZE */: return "GL_TEXTURE_RED_SIZE (0x805C)";
+case 0x805D /* GL_TEXTURE_GREEN_SIZE */: return "GL_TEXTURE_GREEN_SIZE (0x805D)";
+case 0x805E /* GL_TEXTURE_BLUE_SIZE */: return "GL_TEXTURE_BLUE_SIZE (0x805E)";
+case 0x805F /* GL_TEXTURE_ALPHA_SIZE */: return "GL_TEXTURE_ALPHA_SIZE (0x805F)";
+case 0x8060 /* GL_TEXTURE_LUMINANCE_SIZE */: return "GL_TEXTURE_LUMINANCE_SIZE (0x8060)";
+case 0x8061 /* GL_TEXTURE_INTENSITY_SIZE */: return "GL_TEXTURE_INTENSITY_SIZE (0x8061)";
+case 0x8063 /* GL_PROXY_TEXTURE_1D */: return "GL_PROXY_TEXTURE_1D (0x8063)";
+case 0x8064 /* GL_PROXY_TEXTURE_2D */: return "GL_PROXY_TEXTURE_2D (0x8064)";
+case 0x8066 /* GL_TEXTURE_PRIORITY */: return "GL_TEXTURE_PRIORITY (0x8066)";
+case 0x8067 /* GL_TEXTURE_RESIDENT */: return "GL_TEXTURE_RESIDENT (0x8067)";
+case 0x8068 /* GL_TEXTURE_BINDING_1D */: return "GL_TEXTURE_BINDING_1D (0x8068)";
+case 0x8069 /* GL_TEXTURE_BINDING_2D */: return "GL_TEXTURE_BINDING_2D (0x8069)";
+case 0x8074 /* GL_VERTEX_ARRAY */: return "GL_VERTEX_ARRAY (0x8074)";
+case 0x8075 /* GL_NORMAL_ARRAY */: return "GL_NORMAL_ARRAY (0x8075)";
+case 0x8076 /* GL_COLOR_ARRAY */: return "GL_COLOR_ARRAY (0x8076)";
+case 0x8077 /* GL_INDEX_ARRAY */: return "GL_INDEX_ARRAY (0x8077)";
+case 0x8078 /* GL_TEXTURE_COORD_ARRAY */: return "GL_TEXTURE_COORD_ARRAY (0x8078)";
+case 0x8079 /* GL_EDGE_FLAG_ARRAY */: return "GL_EDGE_FLAG_ARRAY (0x8079)";
+case 0x807A /* GL_VERTEX_ARRAY_SIZE */: return "GL_VERTEX_ARRAY_SIZE (0x807A)";
+case 0x807B /* GL_VERTEX_ARRAY_TYPE */: return "GL_VERTEX_ARRAY_TYPE (0x807B)";
+case 0x807C /* GL_VERTEX_ARRAY_STRIDE */: return "GL_VERTEX_ARRAY_STRIDE (0x807C)";
+case 0x807E /* GL_NORMAL_ARRAY_TYPE */: return "GL_NORMAL_ARRAY_TYPE (0x807E)";
+case 0x807F /* GL_NORMAL_ARRAY_STRIDE */: return "GL_NORMAL_ARRAY_STRIDE (0x807F)";
+case 0x8081 /* GL_COLOR_ARRAY_SIZE */: return "GL_COLOR_ARRAY_SIZE (0x8081)";
+case 0x8082 /* GL_COLOR_ARRAY_TYPE */: return "GL_COLOR_ARRAY_TYPE (0x8082)";
+case 0x8083 /* GL_COLOR_ARRAY_STRIDE */: return "GL_COLOR_ARRAY_STRIDE (0x8083)";
+case 0x8085 /* GL_INDEX_ARRAY_TYPE */: return "GL_INDEX_ARRAY_TYPE (0x8085)";
+case 0x8086 /* GL_INDEX_ARRAY_STRIDE */: return "GL_INDEX_ARRAY_STRIDE (0x8086)";
+case 0x8088 /* GL_TEXTURE_COORD_ARRAY_SIZE */: return "GL_TEXTURE_COORD_ARRAY_SIZE (0x8088)";
+case 0x8089 /* GL_TEXTURE_COORD_ARRAY_TYPE */: return "GL_TEXTURE_COORD_ARRAY_TYPE (0x8089)";
+case 0x808A /* GL_TEXTURE_COORD_ARRAY_STRIDE */: return "GL_TEXTURE_COORD_ARRAY_STRIDE (0x808A)";
+case 0x808C /* GL_EDGE_FLAG_ARRAY_STRIDE */: return "GL_EDGE_FLAG_ARRAY_STRIDE (0x808C)";
+case 0x808E /* GL_VERTEX_ARRAY_POINTER */: return "GL_VERTEX_ARRAY_POINTER (0x808E)";
+case 0x808F /* GL_NORMAL_ARRAY_POINTER */: return "GL_NORMAL_ARRAY_POINTER (0x808F)";
+case 0x8090 /* GL_COLOR_ARRAY_POINTER */: return "GL_COLOR_ARRAY_POINTER (0x8090)";
+case 0x8091 /* GL_INDEX_ARRAY_POINTER */: return "GL_INDEX_ARRAY_POINTER (0x8091)";
+case 0x8092 /* GL_TEXTURE_COORD_ARRAY_POINTER */: return "GL_TEXTURE_COORD_ARRAY_POINTER (0x8092)";
+case 0x8093 /* GL_EDGE_FLAG_ARRAY_POINTER */: return "GL_EDGE_FLAG_ARRAY_POINTER (0x8093)";
+case 0x80E2 /* GL_COLOR_INDEX1_EXT */: return "GL_COLOR_INDEX1_EXT (0x80E2)";
+case 0x80E3 /* GL_COLOR_INDEX2_EXT */: return "GL_COLOR_INDEX2_EXT (0x80E3)";
+case 0x80E4 /* GL_COLOR_INDEX4_EXT */: return "GL_COLOR_INDEX4_EXT (0x80E4)";
+case 0x80E5 /* GL_COLOR_INDEX8_EXT */: return "GL_COLOR_INDEX8_EXT (0x80E5)";
+case 0x80E6 /* GL_COLOR_INDEX12_EXT */: return "GL_COLOR_INDEX12_EXT (0x80E6)";
+case 0x80E7 /* GL_COLOR_INDEX16_EXT */: return "GL_COLOR_INDEX16_EXT (0x80E7)";
+case 0x00010000 /* GL_EVAL_BIT */: return "GL_EVAL_BIT (0x00010000)";
+case 0x00020000 /* GL_LIST_BIT */: return "GL_LIST_BIT (0x00020000)";
+case 0x00040000 /* GL_TEXTURE_BIT */: return "GL_TEXTURE_BIT (0x00040000)";
+case 0x00080000 /* GL_SCISSOR_BIT */: return "GL_SCISSOR_BIT (0x00080000)";
+case 0x000fffff /* GL_ALL_ATTRIB_BITS */: return "GL_ALL_ATTRIB_BITS (0x000fffff)";
+case 0xffffffff /* GL_CLIENT_ALL_ATTRIB_BITS */: return "GL_CLIENT_ALL_ATTRIB_BITS (0xffffffff)";
+
+//case 0x0B12 /* GL_SMOOTH_POINT_SIZE_RANGE */: return "GL_SMOOTH_POINT_SIZE_RANGE (0x0B12)";
+case 0x0B12 /* GL_POINT_SIZE_RANGE */: return "GL_POINT_SIZE_RANGE/GL_SMOOTH_POINT_SIZE_RANGE (0x0B12)";
+//case 0x0B13 /* GL_SMOOTH_POINT_SIZE_GRANULARITY */: return "GL_SMOOTH_POINT_SIZE_GRANULARITY (0x0B13)";
+case 0x0B13 /* GL_POINT_SIZE_GRANULARITY */: return "GL_POINT_SIZE_GRANULARITY/GL_SMOOTH_POINT_SIZE_GRANULARITY (0x0B13)";
+case 0x0B22 /* GL_LINE_WIDTH_RANGE */: return "GL_LINE_WIDTH_RANGE/GL_SMOOTH_LINE_WIDTH_RANGE (0x0B22)";
+//case 0x0B22 /* GL_SMOOTH_LINE_WIDTH_RANGE */: return "GL_SMOOTH_LINE_WIDTH_RANGE (0x0B22)";
+//case 0x0B23 /* GL_SMOOTH_LINE_WIDTH_GRANULARITY */: return "GL_SMOOTH_LINE_WIDTH_GRANULARITY (0x0B23)";
+case 0x0B23 /* GL_LINE_WIDTH_GRANULARITY */: return "GL_LINE_WIDTH_GRANULARITY/GL_SMOOTH_LINE_WIDTH_GRANULARITY (0x0B23)";
+case 0x8032 /* GL_UNSIGNED_BYTE_3_3_2 */: return "GL_UNSIGNED_BYTE_3_3_2 (0x8032)";
+case 0x8033 /* GL_UNSIGNED_SHORT_4_4_4_4 */: return "GL_UNSIGNED_SHORT_4_4_4_4 (0x8033)";
+case 0x8034 /* GL_UNSIGNED_SHORT_5_5_5_1 */: return "GL_UNSIGNED_SHORT_5_5_5_1 (0x8034)";
+case 0x8035 /* GL_UNSIGNED_INT_8_8_8_8 */: return "GL_UNSIGNED_INT_8_8_8_8 (0x8035)";
+case 0x8036 /* GL_UNSIGNED_INT_10_10_10_2 */: return "GL_UNSIGNED_INT_10_10_10_2 (0x8036)";
+case 0x803A /* GL_RESCALE_NORMAL */: return "GL_RESCALE_NORMAL (0x803A)";
+case 0x806A /* GL_TEXTURE_BINDING_3D */: return "GL_TEXTURE_BINDING_3D (0x806A)";
+case 0x806B /* GL_PACK_SKIP_IMAGES */: return "GL_PACK_SKIP_IMAGES (0x806B)";
+case 0x806C /* GL_PACK_IMAGE_HEIGHT */: return "GL_PACK_IMAGE_HEIGHT (0x806C)";
+case 0x806D /* GL_UNPACK_SKIP_IMAGES */: return "GL_UNPACK_SKIP_IMAGES (0x806D)";
+case 0x806E /* GL_UNPACK_IMAGE_HEIGHT */: return "GL_UNPACK_IMAGE_HEIGHT (0x806E)";
+case 0x806F /* GL_TEXTURE_3D */: return "GL_TEXTURE_3D (0x806F)";
+case 0x8070 /* GL_PROXY_TEXTURE_3D */: return "GL_PROXY_TEXTURE_3D (0x8070)";
+case 0x8071 /* GL_TEXTURE_DEPTH */: return "GL_TEXTURE_DEPTH (0x8071)";
+case 0x8072 /* GL_TEXTURE_WRAP_R */: return "GL_TEXTURE_WRAP_R (0x8072)";
+case 0x8073 /* GL_MAX_3D_TEXTURE_SIZE */: return "GL_MAX_3D_TEXTURE_SIZE (0x8073)";
+case 0x80E0 /* GL_BGR */: return "GL_BGR (0x80E0)";
+case 0x80E1 /* GL_BGRA */: return "GL_BGRA (0x80E1)";
+case 0x80E8 /* GL_MAX_ELEMENTS_VERTICES */: return "GL_MAX_ELEMENTS_VERTICES (0x80E8)";
+case 0x80E9 /* GL_MAX_ELEMENTS_INDICES */: return "GL_MAX_ELEMENTS_INDICES (0x80E9)";
+case 0x812F /* GL_CLAMP_TO_EDGE */: return "GL_CLAMP_TO_EDGE (0x812F)";
+case 0x813A /* GL_TEXTURE_MIN_LOD */: return "GL_TEXTURE_MIN_LOD (0x813A)";
+case 0x813B /* GL_TEXTURE_MAX_LOD */: return "GL_TEXTURE_MAX_LOD (0x813B)";
+case 0x813C /* GL_TEXTURE_BASE_LEVEL */: return "GL_TEXTURE_BASE_LEVEL (0x813C)";
+case 0x813D /* GL_TEXTURE_MAX_LEVEL */: return "GL_TEXTURE_MAX_LEVEL (0x813D)";
+case 0x81F8 /* GL_LIGHT_MODEL_COLOR_CONTROL */: return "GL_LIGHT_MODEL_COLOR_CONTROL (0x81F8)";
+case 0x81F9 /* GL_SINGLE_COLOR */: return "GL_SINGLE_COLOR (0x81F9)";
+case 0x81FA /* GL_SEPARATE_SPECULAR_COLOR */: return "GL_SEPARATE_SPECULAR_COLOR (0x81FA)";
+case 0x8362 /* GL_UNSIGNED_BYTE_2_3_3_REV */: return "GL_UNSIGNED_BYTE_2_3_3_REV (0x8362)";
+case 0x8363 /* GL_UNSIGNED_SHORT_5_6_5 */: return "GL_UNSIGNED_SHORT_5_6_5 (0x8363)";
+case 0x8364 /* GL_UNSIGNED_SHORT_5_6_5_REV */: return "GL_UNSIGNED_SHORT_5_6_5_REV (0x8364)";
+case 0x8365 /* GL_UNSIGNED_SHORT_4_4_4_4_REV */: return "GL_UNSIGNED_SHORT_4_4_4_4_REV (0x8365)";
+case 0x8366 /* GL_UNSIGNED_SHORT_1_5_5_5_REV */: return "GL_UNSIGNED_SHORT_1_5_5_5_REV (0x8366)";
+case 0x8367 /* GL_UNSIGNED_INT_8_8_8_8_REV */: return "GL_UNSIGNED_INT_8_8_8_8_REV (0x8367)";
+case 0x8368 /* GL_UNSIGNED_INT_2_10_10_10_REV */: return "GL_UNSIGNED_INT_2_10_10_10_REV (0x8368)";
+case 0x846D /* GL_ALIASED_POINT_SIZE_RANGE */: return "GL_ALIASED_POINT_SIZE_RANGE (0x846D)";
+case 0x846E /* GL_ALIASED_LINE_WIDTH_RANGE */: return "GL_ALIASED_LINE_WIDTH_RANGE (0x846E)";
+
+case 0x809D /* GL_MULTISAMPLE */: return "GL_MULTISAMPLE (0x809D)";
+case 0x809E /* GL_SAMPLE_ALPHA_TO_COVERAGE */: return "GL_SAMPLE_ALPHA_TO_COVERAGE (0x809E)";
+case 0x809F /* GL_SAMPLE_ALPHA_TO_ONE */: return "GL_SAMPLE_ALPHA_TO_ONE (0x809F)";
+case 0x80A0 /* GL_SAMPLE_COVERAGE */: return "GL_SAMPLE_COVERAGE (0x80A0)";
+case 0x80A8 /* GL_SAMPLE_BUFFERS */: return "GL_SAMPLE_BUFFERS (0x80A8)";
+case 0x80A9 /* GL_SAMPLES */: return "GL_SAMPLES (0x80A9)";
+case 0x80AA /* GL_SAMPLE_COVERAGE_VALUE */: return "GL_SAMPLE_COVERAGE_VALUE (0x80AA)";
+case 0x80AB /* GL_SAMPLE_COVERAGE_INVERT */: return "GL_SAMPLE_COVERAGE_INVERT (0x80AB)";
+case 0x812D /* GL_CLAMP_TO_BORDER */: return "GL_CLAMP_TO_BORDER (0x812D)";
+case 0x84C0 /* GL_TEXTURE0 */: return "GL_TEXTURE0 (0x84C0)";
+case 0x84C1 /* GL_TEXTURE1 */: return "GL_TEXTURE1 (0x84C1)";
+case 0x84C2 /* GL_TEXTURE2 */: return "GL_TEXTURE2 (0x84C2)";
+case 0x84C3 /* GL_TEXTURE3 */: return "GL_TEXTURE3 (0x84C3)";
+case 0x84C4 /* GL_TEXTURE4 */: return "GL_TEXTURE4 (0x84C4)";
+case 0x84C5 /* GL_TEXTURE5 */: return "GL_TEXTURE5 (0x84C5)";
+case 0x84C6 /* GL_TEXTURE6 */: return "GL_TEXTURE6 (0x84C6)";
+case 0x84C7 /* GL_TEXTURE7 */: return "GL_TEXTURE7 (0x84C7)";
+case 0x84C8 /* GL_TEXTURE8 */: return "GL_TEXTURE8 (0x84C8)";
+case 0x84C9 /* GL_TEXTURE9 */: return "GL_TEXTURE9 (0x84C9)";
+case 0x84CA /* GL_TEXTURE10 */: return "GL_TEXTURE10 (0x84CA)";
+case 0x84CB /* GL_TEXTURE11 */: return "GL_TEXTURE11 (0x84CB)";
+case 0x84CC /* GL_TEXTURE12 */: return "GL_TEXTURE12 (0x84CC)";
+case 0x84CD /* GL_TEXTURE13 */: return "GL_TEXTURE13 (0x84CD)";
+case 0x84CE /* GL_TEXTURE14 */: return "GL_TEXTURE14 (0x84CE)";
+case 0x84CF /* GL_TEXTURE15 */: return "GL_TEXTURE15 (0x84CF)";
+case 0x84D0 /* GL_TEXTURE16 */: return "GL_TEXTURE16 (0x84D0)";
+case 0x84D1 /* GL_TEXTURE17 */: return "GL_TEXTURE17 (0x84D1)";
+case 0x84D2 /* GL_TEXTURE18 */: return "GL_TEXTURE18 (0x84D2)";
+case 0x84D3 /* GL_TEXTURE19 */: return "GL_TEXTURE19 (0x84D3)";
+case 0x84D4 /* GL_TEXTURE20 */: return "GL_TEXTURE20 (0x84D4)";
+case 0x84D5 /* GL_TEXTURE21 */: return "GL_TEXTURE21 (0x84D5)";
+case 0x84D6 /* GL_TEXTURE22 */: return "GL_TEXTURE22 (0x84D6)";
+case 0x84D7 /* GL_TEXTURE23 */: return "GL_TEXTURE23 (0x84D7)";
+case 0x84D8 /* GL_TEXTURE24 */: return "GL_TEXTURE24 (0x84D8)";
+case 0x84D9 /* GL_TEXTURE25 */: return "GL_TEXTURE25 (0x84D9)";
+case 0x84DA /* GL_TEXTURE26 */: return "GL_TEXTURE26 (0x84DA)";
+case 0x84DB /* GL_TEXTURE27 */: return "GL_TEXTURE27 (0x84DB)";
+case 0x84DC /* GL_TEXTURE28 */: return "GL_TEXTURE28 (0x84DC)";
+case 0x84DD /* GL_TEXTURE29 */: return "GL_TEXTURE29 (0x84DD)";
+case 0x84DE /* GL_TEXTURE30 */: return "GL_TEXTURE30 (0x84DE)";
+case 0x84DF /* GL_TEXTURE31 */: return "GL_TEXTURE31 (0x84DF)";
+case 0x84E0 /* GL_ACTIVE_TEXTURE */: return "GL_ACTIVE_TEXTURE (0x84E0)";
+case 0x84E1 /* GL_CLIENT_ACTIVE_TEXTURE */: return "GL_CLIENT_ACTIVE_TEXTURE (0x84E1)";
+case 0x84E2 /* GL_MAX_TEXTURE_UNITS */: return "GL_MAX_TEXTURE_UNITS (0x84E2)";
+case 0x84E3 /* GL_TRANSPOSE_MODELVIEW_MATRIX */: return "GL_TRANSPOSE_MODELVIEW_MATRIX (0x84E3)";
+case 0x84E4 /* GL_TRANSPOSE_PROJECTION_MATRIX */: return "GL_TRANSPOSE_PROJECTION_MATRIX (0x84E4)";
+case 0x84E5 /* GL_TRANSPOSE_TEXTURE_MATRIX */: return "GL_TRANSPOSE_TEXTURE_MATRIX (0x84E5)";
+case 0x84E6 /* GL_TRANSPOSE_COLOR_MATRIX */: return "GL_TRANSPOSE_COLOR_MATRIX (0x84E6)";
+case 0x84E7 /* GL_SUBTRACT */: return "GL_SUBTRACT (0x84E7)";
+case 0x84E9 /* GL_COMPRESSED_ALPHA */: return "GL_COMPRESSED_ALPHA (0x84E9)";
+case 0x84EA /* GL_COMPRESSED_LUMINANCE */: return "GL_COMPRESSED_LUMINANCE (0x84EA)";
+case 0x84EB /* GL_COMPRESSED_LUMINANCE_ALPHA */: return "GL_COMPRESSED_LUMINANCE_ALPHA (0x84EB)";
+case 0x84EC /* GL_COMPRESSED_INTENSITY */: return "GL_COMPRESSED_INTENSITY (0x84EC)";
+case 0x84ED /* GL_COMPRESSED_RGB */: return "GL_COMPRESSED_RGB (0x84ED)";
+case 0x84EE /* GL_COMPRESSED_RGBA */: return "GL_COMPRESSED_RGBA (0x84EE)";
+case 0x84EF /* GL_TEXTURE_COMPRESSION_HINT */: return "GL_TEXTURE_COMPRESSION_HINT (0x84EF)";
+case 0x8511 /* GL_NORMAL_MAP */: return "GL_NORMAL_MAP (0x8511)";
+case 0x8512 /* GL_REFLECTION_MAP */: return "GL_REFLECTION_MAP (0x8512)";
+case 0x8513 /* GL_TEXTURE_CUBE_MAP */: return "GL_TEXTURE_CUBE_MAP (0x8513)";
+case 0x8514 /* GL_TEXTURE_BINDING_CUBE_MAP */: return "GL_TEXTURE_BINDING_CUBE_MAP (0x8514)";
+case 0x8515 /* GL_TEXTURE_CUBE_MAP_POSITIVE_X */: return "GL_TEXTURE_CUBE_MAP_POSITIVE_X (0x8515)";
+case 0x8516 /* GL_TEXTURE_CUBE_MAP_NEGATIVE_X */: return "GL_TEXTURE_CUBE_MAP_NEGATIVE_X (0x8516)";
+case 0x8517 /* GL_TEXTURE_CUBE_MAP_POSITIVE_Y */: return "GL_TEXTURE_CUBE_MAP_POSITIVE_Y (0x8517)";
+case 0x8518 /* GL_TEXTURE_CUBE_MAP_NEGATIVE_Y */: return "GL_TEXTURE_CUBE_MAP_NEGATIVE_Y (0x8518)";
+case 0x8519 /* GL_TEXTURE_CUBE_MAP_POSITIVE_Z */: return "GL_TEXTURE_CUBE_MAP_POSITIVE_Z (0x8519)";
+case 0x851A /* GL_TEXTURE_CUBE_MAP_NEGATIVE_Z */: return "GL_TEXTURE_CUBE_MAP_NEGATIVE_Z (0x851A)";
+case 0x851B /* GL_PROXY_TEXTURE_CUBE_MAP */: return "GL_PROXY_TEXTURE_CUBE_MAP (0x851B)";
+case 0x851C /* GL_MAX_CUBE_MAP_TEXTURE_SIZE */: return "GL_MAX_CUBE_MAP_TEXTURE_SIZE (0x851C)";
+case 0x8570 /* GL_COMBINE */: return "GL_COMBINE (0x8570)";
+case 0x8571 /* GL_COMBINE_RGB */: return "GL_COMBINE_RGB (0x8571)";
+case 0x8572 /* GL_COMBINE_ALPHA */: return "GL_COMBINE_ALPHA (0x8572)";
+case 0x8573 /* GL_RGB_SCALE */: return "GL_RGB_SCALE (0x8573)";
+case 0x8574 /* GL_ADD_SIGNED */: return "GL_ADD_SIGNED (0x8574)";
+case 0x8575 /* GL_INTERPOLATE */: return "GL_INTERPOLATE (0x8575)";
+case 0x8576 /* GL_CONSTANT */: return "GL_CONSTANT (0x8576)";
+case 0x8577 /* GL_PRIMARY_COLOR */: return "GL_PRIMARY_COLOR (0x8577)";
+case 0x8578 /* GL_PREVIOUS */: return "GL_PREVIOUS (0x8578)";
+case 0x8580 /* GL_SOURCE0_RGB */: return "GL_SOURCE0_RGB (0x8580)";
+case 0x8581 /* GL_SOURCE1_RGB */: return "GL_SOURCE1_RGB (0x8581)";
+case 0x8582 /* GL_SOURCE2_RGB */: return "GL_SOURCE2_RGB (0x8582)";
+case 0x8588 /* GL_SOURCE0_ALPHA */: return "GL_SOURCE0_ALPHA (0x8588)";
+case 0x8589 /* GL_SOURCE1_ALPHA */: return "GL_SOURCE1_ALPHA (0x8589)";
+case 0x858A /* GL_SOURCE2_ALPHA */: return "GL_SOURCE2_ALPHA (0x858A)";
+case 0x8590 /* GL_OPERAND0_RGB */: return "GL_OPERAND0_RGB (0x8590)";
+case 0x8591 /* GL_OPERAND1_RGB */: return "GL_OPERAND1_RGB (0x8591)";
+case 0x8592 /* GL_OPERAND2_RGB */: return "GL_OPERAND2_RGB (0x8592)";
+case 0x8598 /* GL_OPERAND0_ALPHA */: return "GL_OPERAND0_ALPHA (0x8598)";
+case 0x8599 /* GL_OPERAND1_ALPHA */: return "GL_OPERAND1_ALPHA (0x8599)";
+case 0x859A /* GL_OPERAND2_ALPHA */: return "GL_OPERAND2_ALPHA (0x859A)";
+case 0x86A0 /* GL_TEXTURE_COMPRESSED_IMAGE_SIZE */: return "GL_TEXTURE_COMPRESSED_IMAGE_SIZE (0x86A0)";
+case 0x86A1 /* GL_TEXTURE_COMPRESSED */: return "GL_TEXTURE_COMPRESSED (0x86A1)";
+case 0x86A2 /* GL_NUM_COMPRESSED_TEXTURE_FORMATS */: return "GL_NUM_COMPRESSED_TEXTURE_FORMATS (0x86A2)";
+case 0x86A3 /* GL_COMPRESSED_TEXTURE_FORMATS */: return "GL_COMPRESSED_TEXTURE_FORMATS (0x86A3)";
+case 0x86AE /* GL_DOT3_RGB */: return "GL_DOT3_RGB (0x86AE)";
+case 0x86AF /* GL_DOT3_RGBA */: return "GL_DOT3_RGBA (0x86AF)";
+case 0x20000000 /* GL_MULTISAMPLE_BIT */: return "GL_MULTISAMPLE_BIT (0x20000000)";
+
+case 0x80C8 /* GL_BLEND_DST_RGB */: return "GL_BLEND_DST_RGB (0x80C8)";
+case 0x80C9 /* GL_BLEND_SRC_RGB */: return "GL_BLEND_SRC_RGB (0x80C9)";
+case 0x80CA /* GL_BLEND_DST_ALPHA */: return "GL_BLEND_DST_ALPHA (0x80CA)";
+case 0x80CB /* GL_BLEND_SRC_ALPHA */: return "GL_BLEND_SRC_ALPHA (0x80CB)";
+case 0x8126 /* GL_POINT_SIZE_MIN */: return "GL_POINT_SIZE_MIN (0x8126)";
+case 0x8127 /* GL_POINT_SIZE_MAX */: return "GL_POINT_SIZE_MAX (0x8127)";
+case 0x8128 /* GL_POINT_FADE_THRESHOLD_SIZE */: return "GL_POINT_FADE_THRESHOLD_SIZE (0x8128)";
+case 0x8129 /* GL_POINT_DISTANCE_ATTENUATION */: return "GL_POINT_DISTANCE_ATTENUATION (0x8129)";
+case 0x8191 /* GL_GENERATE_MIPMAP */: return "GL_GENERATE_MIPMAP (0x8191)";
+case 0x8192 /* GL_GENERATE_MIPMAP_HINT */: return "GL_GENERATE_MIPMAP_HINT (0x8192)";
+case 0x81A5 /* GL_DEPTH_COMPONENT16 */: return "GL_DEPTH_COMPONENT16 (0x81A5)";
+case 0x81A6 /* GL_DEPTH_COMPONENT24 */: return "GL_DEPTH_COMPONENT24 (0x81A6)";
+case 0x81A7 /* GL_DEPTH_COMPONENT32 */: return "GL_DEPTH_COMPONENT32 (0x81A7)";
+case 0x8370 /* GL_MIRRORED_REPEAT */: return "GL_MIRRORED_REPEAT (0x8370)";
+case 0x8450 /* GL_FOG_COORDINATE_SOURCE */: return "GL_FOG_COORDINATE_SOURCE (0x8450)";
+case 0x8451 /* GL_FOG_COORDINATE */: return "GL_FOG_COORDINATE (0x8451)";
+case 0x8452 /* GL_FRAGMENT_DEPTH */: return "GL_FRAGMENT_DEPTH (0x8452)";
+case 0x8453 /* GL_CURRENT_FOG_COORDINATE */: return "GL_CURRENT_FOG_COORDINATE (0x8453)";
+case 0x8454 /* GL_FOG_COORDINATE_ARRAY_TYPE */: return "GL_FOG_COORDINATE_ARRAY_TYPE (0x8454)";
+case 0x8455 /* GL_FOG_COORDINATE_ARRAY_STRIDE */: return "GL_FOG_COORDINATE_ARRAY_STRIDE (0x8455)";
+case 0x8456 /* GL_FOG_COORDINATE_ARRAY_POINTER */: return "GL_FOG_COORDINATE_ARRAY_POINTER (0x8456)";
+case 0x8457 /* GL_FOG_COORDINATE_ARRAY */: return "GL_FOG_COORDINATE_ARRAY (0x8457)";
+case 0x8458 /* GL_COLOR_SUM */: return "GL_COLOR_SUM (0x8458)";
+case 0x8459 /* GL_CURRENT_SECONDARY_COLOR */: return "GL_CURRENT_SECONDARY_COLOR (0x8459)";
+case 0x845A /* GL_SECONDARY_COLOR_ARRAY_SIZE */: return "GL_SECONDARY_COLOR_ARRAY_SIZE (0x845A)";
+case 0x845B /* GL_SECONDARY_COLOR_ARRAY_TYPE */: return "GL_SECONDARY_COLOR_ARRAY_TYPE (0x845B)";
+case 0x845C /* GL_SECONDARY_COLOR_ARRAY_STRIDE */: return "GL_SECONDARY_COLOR_ARRAY_STRIDE (0x845C)";
+case 0x845D /* GL_SECONDARY_COLOR_ARRAY_POINTER */: return "GL_SECONDARY_COLOR_ARRAY_POINTER (0x845D)";
+case 0x845E /* GL_SECONDARY_COLOR_ARRAY */: return "GL_SECONDARY_COLOR_ARRAY (0x845E)";
+case 0x84FD /* GL_MAX_TEXTURE_LOD_BIAS */: return "GL_MAX_TEXTURE_LOD_BIAS (0x84FD)";
+case 0x8500 /* GL_TEXTURE_FILTER_CONTROL */: return "GL_TEXTURE_FILTER_CONTROL (0x8500)";
+case 0x8501 /* GL_TEXTURE_LOD_BIAS */: return "GL_TEXTURE_LOD_BIAS (0x8501)";
+case 0x8507 /* GL_INCR_WRAP */: return "GL_INCR_WRAP (0x8507)";
+case 0x8508 /* GL_DECR_WRAP */: return "GL_DECR_WRAP (0x8508)";
+case 0x884A /* GL_TEXTURE_DEPTH_SIZE */: return "GL_TEXTURE_DEPTH_SIZE (0x884A)";
+case 0x884B /* GL_DEPTH_TEXTURE_MODE */: return "GL_DEPTH_TEXTURE_MODE (0x884B)";
+case 0x884C /* GL_TEXTURE_COMPARE_MODE */: return "GL_TEXTURE_COMPARE_MODE (0x884C)";
+case 0x884D /* GL_TEXTURE_COMPARE_FUNC */: return "GL_TEXTURE_COMPARE_FUNC (0x884D)";
+case 0x884E /* GL_COMPARE_R_TO_TEXTURE */: return "GL_COMPARE_R_TO_TEXTURE (0x884E)";
+
+/* ----------------------------- GL_VERSION_1_5 ---------------------------- */
+
+case 0x8764 /* GL_BUFFER_SIZE */: return "GL_BUFFER_SIZE (0x8764)";
+case 0x8765 /* GL_BUFFER_USAGE */: return "GL_BUFFER_USAGE (0x8765)";
+case 0x8864 /* GL_QUERY_COUNTER_BITS */: return "GL_QUERY_COUNTER_BITS (0x8864)";
+case 0x8865 /* GL_CURRENT_QUERY */: return "GL_CURRENT_QUERY (0x8865)";
+case 0x8866 /* GL_QUERY_RESULT */: return "GL_QUERY_RESULT (0x8866)";
+case 0x8867 /* GL_QUERY_RESULT_AVAILABLE */: return "GL_QUERY_RESULT_AVAILABLE (0x8867)";
+case 0x8892 /* GL_ARRAY_BUFFER */: return "GL_ARRAY_BUFFER (0x8892)";
+case 0x8893 /* GL_ELEMENT_ARRAY_BUFFER */: return "GL_ELEMENT_ARRAY_BUFFER (0x8893)";
+case 0x8894 /* GL_ARRAY_BUFFER_BINDING */: return "GL_ARRAY_BUFFER_BINDING (0x8894)";
+case 0x8895 /* GL_ELEMENT_ARRAY_BUFFER_BINDING */: return "GL_ELEMENT_ARRAY_BUFFER_BINDING (0x8895)";
+case 0x8896 /* GL_VERTEX_ARRAY_BUFFER_BINDING */: return "GL_VERTEX_ARRAY_BUFFER_BINDING (0x8896)";
+case 0x8897 /* GL_NORMAL_ARRAY_BUFFER_BINDING */: return "GL_NORMAL_ARRAY_BUFFER_BINDING (0x8897)";
+case 0x8898 /* GL_COLOR_ARRAY_BUFFER_BINDING */: return "GL_COLOR_ARRAY_BUFFER_BINDING (0x8898)";
+case 0x8899 /* GL_INDEX_ARRAY_BUFFER_BINDING */: return "GL_INDEX_ARRAY_BUFFER_BINDING (0x8899)";
+case 0x889A /* GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING */: return "GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING (0x889A)";
+case 0x889B /* GL_EDGE_FLAG_ARRAY_BUFFER_BINDING */: return "GL_EDGE_FLAG_ARRAY_BUFFER_BINDING (0x889B)";
+case 0x889C /* GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING */: return "GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING (0x889C)";
+case 0x889D /* GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING */: return "GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING (0x889D)";
+case 0x889E /* GL_WEIGHT_ARRAY_BUFFER_BINDING */: return "GL_WEIGHT_ARRAY_BUFFER_BINDING (0x889E)";
+case 0x889F /* GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING */: return "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING (0x889F)";
+case 0x88B8 /* GL_READ_ONLY */: return "GL_READ_ONLY (0x88B8)";
+case 0x88B9 /* GL_WRITE_ONLY */: return "GL_WRITE_ONLY (0x88B9)";
+case 0x88BA /* GL_READ_WRITE */: return "GL_READ_WRITE (0x88BA)";
+case 0x88BB /* GL_BUFFER_ACCESS */: return "GL_BUFFER_ACCESS (0x88BB)";
+case 0x88BC /* GL_BUFFER_MAPPED */: return "GL_BUFFER_MAPPED (0x88BC)";
+case 0x88BD /* GL_BUFFER_MAP_POINTER */: return "GL_BUFFER_MAP_POINTER (0x88BD)";
+case 0x88E0 /* GL_STREAM_DRAW */: return "GL_STREAM_DRAW (0x88E0)";
+case 0x88E1 /* GL_STREAM_READ */: return "GL_STREAM_READ (0x88E1)";
+case 0x88E2 /* GL_STREAM_COPY */: return "GL_STREAM_COPY (0x88E2)";
+case 0x88E4 /* GL_STATIC_DRAW */: return "GL_STATIC_DRAW (0x88E4)";
+case 0x88E5 /* GL_STATIC_READ */: return "GL_STATIC_READ (0x88E5)";
+case 0x88E6 /* GL_STATIC_COPY */: return "GL_STATIC_COPY (0x88E6)";
+case 0x88E8 /* GL_DYNAMIC_DRAW */: return "GL_DYNAMIC_DRAW (0x88E8)";
+case 0x88E9 /* GL_DYNAMIC_READ */: return "GL_DYNAMIC_READ (0x88E9)";
+case 0x88EA /* GL_DYNAMIC_COPY */: return "GL_DYNAMIC_COPY (0x88EA)";
+case 0x8914 /* GL_SAMPLES_PASSED */: return "GL_SAMPLES_PASSED (0x8914)";
+
+/* ----------------------------- GL_VERSION_2_0 ---------------------------- */
+
+case 0x8622 /* GL_VERTEX_ATTRIB_ARRAY_ENABLED */: return "GL_VERTEX_ATTRIB_ARRAY_ENABLED (0x8622)";
+case 0x8623 /* GL_VERTEX_ATTRIB_ARRAY_SIZE */: return "GL_VERTEX_ATTRIB_ARRAY_SIZE (0x8623)";
+case 0x8624 /* GL_VERTEX_ATTRIB_ARRAY_STRIDE */: return "GL_VERTEX_ATTRIB_ARRAY_STRIDE (0x8624)";
+case 0x8625 /* GL_VERTEX_ATTRIB_ARRAY_TYPE */: return "GL_VERTEX_ATTRIB_ARRAY_TYPE (0x8625)";
+case 0x8626 /* GL_CURRENT_VERTEX_ATTRIB */: return "GL_CURRENT_VERTEX_ATTRIB (0x8626)";
+//case 0x8642 /* GL_VERTEX_PROGRAM_POINT_SIZE */: return "GL_VERTEX_PROGRAM_POINT_SIZE (0x8642)";
+case 0x8643 /* GL_VERTEX_PROGRAM_TWO_SIDE */: return "GL_VERTEX_PROGRAM_TWO_SIDE (0x8643)";
+case 0x8645 /* GL_VERTEX_ATTRIB_ARRAY_POINTER */: return "GL_VERTEX_ATTRIB_ARRAY_POINTER (0x8645)";
+case 0x8800 /* GL_STENCIL_BACK_FUNC */: return "GL_STENCIL_BACK_FUNC (0x8800)";
+case 0x8801 /* GL_STENCIL_BACK_FAIL */: return "GL_STENCIL_BACK_FAIL (0x8801)";
+case 0x8802 /* GL_STENCIL_BACK_PASS_DEPTH_FAIL */: return "GL_STENCIL_BACK_PASS_DEPTH_FAIL (0x8802)";
+case 0x8803 /* GL_STENCIL_BACK_PASS_DEPTH_PASS */: return "GL_STENCIL_BACK_PASS_DEPTH_PASS (0x8803)";
+case 0x8824 /* GL_MAX_DRAW_BUFFERS */: return "GL_MAX_DRAW_BUFFERS (0x8824)";
+case 0x8825 /* GL_DRAW_BUFFER0 */: return "GL_DRAW_BUFFER0 (0x8825)";
+case 0x8826 /* GL_DRAW_BUFFER1 */: return "GL_DRAW_BUFFER1 (0x8826)";
+case 0x8827 /* GL_DRAW_BUFFER2 */: return "GL_DRAW_BUFFER2 (0x8827)";
+case 0x8828 /* GL_DRAW_BUFFER3 */: return "GL_DRAW_BUFFER3 (0x8828)";
+case 0x8829 /* GL_DRAW_BUFFER4 */: return "GL_DRAW_BUFFER4 (0x8829)";
+case 0x882A /* GL_DRAW_BUFFER5 */: return "GL_DRAW_BUFFER5 (0x882A)";
+case 0x882B /* GL_DRAW_BUFFER6 */: return "GL_DRAW_BUFFER6 (0x882B)";
+case 0x882C /* GL_DRAW_BUFFER7 */: return "GL_DRAW_BUFFER7 (0x882C)";
+case 0x882D /* GL_DRAW_BUFFER8 */: return "GL_DRAW_BUFFER8 (0x882D)";
+case 0x882E /* GL_DRAW_BUFFER9 */: return "GL_DRAW_BUFFER9 (0x882E)";
+case 0x882F /* GL_DRAW_BUFFER10 */: return "GL_DRAW_BUFFER10 (0x882F)";
+case 0x8830 /* GL_DRAW_BUFFER11 */: return "GL_DRAW_BUFFER11 (0x8830)";
+case 0x8831 /* GL_DRAW_BUFFER12 */: return "GL_DRAW_BUFFER12 (0x8831)";
+case 0x8832 /* GL_DRAW_BUFFER13 */: return "GL_DRAW_BUFFER13 (0x8832)";
+case 0x8833 /* GL_DRAW_BUFFER14 */: return "GL_DRAW_BUFFER14 (0x8833)";
+case 0x8834 /* GL_DRAW_BUFFER15 */: return "GL_DRAW_BUFFER15 (0x8834)";
+case 0x883D /* GL_BLEND_EQUATION_ALPHA */: return "GL_BLEND_EQUATION_ALPHA (0x883D)";
+case 0x8861 /* GL_POINT_SPRITE */: return "GL_POINT_SPRITE (0x8861)";
+case 0x8862 /* GL_COORD_REPLACE */: return "GL_COORD_REPLACE (0x8862)";
+case 0x8869 /* GL_MAX_VERTEX_ATTRIBS */: return "GL_MAX_VERTEX_ATTRIBS (0x8869)";
+case 0x886A /* GL_VERTEX_ATTRIB_ARRAY_NORMALIZED */: return "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED (0x886A)";
+case 0x8871 /* GL_MAX_TEXTURE_COORDS */: return "GL_MAX_TEXTURE_COORDS (0x8871)";
+case 0x8872 /* GL_MAX_TEXTURE_IMAGE_UNITS */: return "GL_MAX_TEXTURE_IMAGE_UNITS (0x8872)";
+case 0x8B30 /* GL_FRAGMENT_SHADER */: return "GL_FRAGMENT_SHADER (0x8B30)";
+case 0x8B31 /* GL_VERTEX_SHADER */: return "GL_VERTEX_SHADER (0x8B31)";
+case 0x8B49 /* GL_MAX_FRAGMENT_UNIFORM_COMPONENTS */: return "GL_MAX_FRAGMENT_UNIFORM_COMPONENTS (0x8B49)";
+case 0x8B4A /* GL_MAX_VERTEX_UNIFORM_COMPONENTS */: return "GL_MAX_VERTEX_UNIFORM_COMPONENTS (0x8B4A)";
+case 0x8B4B /* GL_MAX_VARYING_FLOATS */: return "GL_MAX_VARYING_FLOATS (0x8B4B)";
+case 0x8B4C /* GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS */: return "GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS (0x8B4C)";
+case 0x8B4D /* GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS */: return "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (0x8B4D)";
+case 0x8B4F /* GL_SHADER_TYPE */: return "GL_SHADER_TYPE (0x8B4F)";
+case 0x8B50 /* GL_FLOAT_VEC2 */: return "GL_FLOAT_VEC2 (0x8B50)";
+case 0x8B51 /* GL_FLOAT_VEC3 */: return "GL_FLOAT_VEC3 (0x8B51)";
+case 0x8B52 /* GL_FLOAT_VEC4 */: return "GL_FLOAT_VEC4 (0x8B52)";
+case 0x8B53 /* GL_INT_VEC2 */: return "GL_INT_VEC2 (0x8B53)";
+case 0x8B54 /* GL_INT_VEC3 */: return "GL_INT_VEC3 (0x8B54)";
+case 0x8B55 /* GL_INT_VEC4 */: return "GL_INT_VEC4 (0x8B55)";
+case 0x8B56 /* GL_BOOL */: return "GL_BOOL (0x8B56)";
+case 0x8B57 /* GL_BOOL_VEC2 */: return "GL_BOOL_VEC2 (0x8B57)";
+case 0x8B58 /* GL_BOOL_VEC3 */: return "GL_BOOL_VEC3 (0x8B58)";
+case 0x8B59 /* GL_BOOL_VEC4 */: return "GL_BOOL_VEC4 (0x8B59)";
+case 0x8B5A /* GL_FLOAT_MAT2 */: return "GL_FLOAT_MAT2 (0x8B5A)";
+case 0x8B5B /* GL_FLOAT_MAT3 */: return "GL_FLOAT_MAT3 (0x8B5B)";
+case 0x8B5C /* GL_FLOAT_MAT4 */: return "GL_FLOAT_MAT4 (0x8B5C)";
+case 0x8B5D /* GL_SAMPLER_1D */: return "GL_SAMPLER_1D (0x8B5D)";
+case 0x8B5E /* GL_SAMPLER_2D */: return "GL_SAMPLER_2D (0x8B5E)";
+case 0x8B5F /* GL_SAMPLER_3D */: return "GL_SAMPLER_3D (0x8B5F)";
+case 0x8B60 /* GL_SAMPLER_CUBE */: return "GL_SAMPLER_CUBE (0x8B60)";
+case 0x8B61 /* GL_SAMPLER_1D_SHADOW */: return "GL_SAMPLER_1D_SHADOW (0x8B61)";
+case 0x8B62 /* GL_SAMPLER_2D_SHADOW */: return "GL_SAMPLER_2D_SHADOW (0x8B62)";
+case 0x8B80 /* GL_DELETE_STATUS */: return "GL_DELETE_STATUS (0x8B80)";
+case 0x8B81 /* GL_COMPILE_STATUS */: return "GL_COMPILE_STATUS (0x8B81)";
+case 0x8B82 /* GL_LINK_STATUS */: return "GL_LINK_STATUS (0x8B82)";
+case 0x8B83 /* GL_VALIDATE_STATUS */: return "GL_VALIDATE_STATUS (0x8B83)";
+case 0x8B84 /* GL_INFO_LOG_LENGTH */: return "GL_INFO_LOG_LENGTH (0x8B84)";
+case 0x8B85 /* GL_ATTACHED_SHADERS */: return "GL_ATTACHED_SHADERS (0x8B85)";
+case 0x8B86 /* GL_ACTIVE_UNIFORMS */: return "GL_ACTIVE_UNIFORMS (0x8B86)";
+case 0x8B87 /* GL_ACTIVE_UNIFORM_MAX_LENGTH */: return "GL_ACTIVE_UNIFORM_MAX_LENGTH (0x8B87)";
+case 0x8B88 /* GL_SHADER_SOURCE_LENGTH */: return "GL_SHADER_SOURCE_LENGTH (0x8B88)";
+case 0x8B89 /* GL_ACTIVE_ATTRIBUTES */: return "GL_ACTIVE_ATTRIBUTES (0x8B89)";
+case 0x8B8A /* GL_ACTIVE_ATTRIBUTE_MAX_LENGTH */: return "GL_ACTIVE_ATTRIBUTE_MAX_LENGTH (0x8B8A)";
+case 0x8B8B /* GL_FRAGMENT_SHADER_DERIVATIVE_HINT */: return "GL_FRAGMENT_SHADER_DERIVATIVE_HINT (0x8B8B)";
+case 0x8B8C /* GL_SHADING_LANGUAGE_VERSION */: return "GL_SHADING_LANGUAGE_VERSION (0x8B8C)";
+case 0x8B8D /* GL_CURRENT_PROGRAM */: return "GL_CURRENT_PROGRAM (0x8B8D)";
+case 0x8CA0 /* GL_POINT_SPRITE_COORD_ORIGIN */: return "GL_POINT_SPRITE_COORD_ORIGIN (0x8CA0)";
+case 0x8CA1 /* GL_LOWER_LEFT */: return "GL_LOWER_LEFT (0x8CA1)";
+case 0x8CA2 /* GL_UPPER_LEFT */: return "GL_UPPER_LEFT (0x8CA2)";
+case 0x8CA3 /* GL_STENCIL_BACK_REF */: return "GL_STENCIL_BACK_REF (0x8CA3)";
+case 0x8CA4 /* GL_STENCIL_BACK_VALUE_MASK */: return "GL_STENCIL_BACK_VALUE_MASK (0x8CA4)";
+case 0x8CA5 /* GL_STENCIL_BACK_WRITEMASK */: return "GL_STENCIL_BACK_WRITEMASK (0x8CA5)";
+
+/* ----------------------------- GL_VERSION_2_1 ---------------------------- */
+
+case 0x845F /* GL_CURRENT_RASTER_SECONDARY_COLOR */: return "GL_CURRENT_RASTER_SECONDARY_COLOR (0x845F)";
+case 0x88EB /* GL_PIXEL_PACK_BUFFER */: return "GL_PIXEL_PACK_BUFFER (0x88EB)";
+case 0x88EC /* GL_PIXEL_UNPACK_BUFFER */: return "GL_PIXEL_UNPACK_BUFFER (0x88EC)";
+case 0x88ED /* GL_PIXEL_PACK_BUFFER_BINDING */: return "GL_PIXEL_PACK_BUFFER_BINDING (0x88ED)";
+case 0x88EF /* GL_PIXEL_UNPACK_BUFFER_BINDING */: return "GL_PIXEL_UNPACK_BUFFER_BINDING (0x88EF)";
+case 0x8B65 /* GL_FLOAT_MAT2x3 */: return "GL_FLOAT_MAT2x3 (0x8B65)";
+case 0x8B66 /* GL_FLOAT_MAT2x4 */: return "GL_FLOAT_MAT2x4 (0x8B66)";
+case 0x8B67 /* GL_FLOAT_MAT3x2 */: return "GL_FLOAT_MAT3x2 (0x8B67)";
+case 0x8B68 /* GL_FLOAT_MAT3x4 */: return "GL_FLOAT_MAT3x4 (0x8B68)";
+case 0x8B69 /* GL_FLOAT_MAT4x2 */: return "GL_FLOAT_MAT4x2 (0x8B69)";
+case 0x8B6A /* GL_FLOAT_MAT4x3 */: return "GL_FLOAT_MAT4x3 (0x8B6A)";
+case 0x8C40 /* GL_SRGB */: return "GL_SRGB (0x8C40)";
+case 0x8C41 /* GL_SRGB8 */: return "GL_SRGB8 (0x8C41)";
+case 0x8C42 /* GL_SRGB_ALPHA */: return "GL_SRGB_ALPHA (0x8C42)";
+case 0x8C43 /* GL_SRGB8_ALPHA8 */: return "GL_SRGB8_ALPHA8 (0x8C43)";
+case 0x8C44 /* GL_SLUMINANCE_ALPHA */: return "GL_SLUMINANCE_ALPHA (0x8C44)";
+case 0x8C45 /* GL_SLUMINANCE8_ALPHA8 */: return "GL_SLUMINANCE8_ALPHA8 (0x8C45)";
+case 0x8C46 /* GL_SLUMINANCE */: return "GL_SLUMINANCE (0x8C46)";
+case 0x8C47 /* GL_SLUMINANCE8 */: return "GL_SLUMINANCE8 (0x8C47)";
+case 0x8C48 /* GL_COMPRESSED_SRGB */: return "GL_COMPRESSED_SRGB (0x8C48)";
+case 0x8C49 /* GL_COMPRESSED_SRGB_ALPHA */: return "GL_COMPRESSED_SRGB_ALPHA (0x8C49)";
+case 0x8C4A /* GL_COMPRESSED_SLUMINANCE */: return "GL_COMPRESSED_SLUMINANCE (0x8C4A)";
+case 0x8C4B /* GL_COMPRESSED_SLUMINANCE_ALPHA */: return "GL_COMPRESSED_SLUMINANCE_ALPHA (0x8C4B)";
+
+/* ----------------------------- GL_VERSION_3_0 ---------------------------- */
+
+//case 0x0001 /* GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT */: return "GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT (0x0001)";
+case 0x821B /* GL_MAJOR_VERSION */: return "GL_MAJOR_VERSION (0x821B)";
+case 0x821C /* GL_MINOR_VERSION */: return "GL_MINOR_VERSION (0x821C)";
+case 0x821D /* GL_NUM_EXTENSIONS */: return "GL_NUM_EXTENSIONS (0x821D)";
+case 0x821E /* GL_CONTEXT_FLAGS */: return "GL_CONTEXT_FLAGS (0x821E)";
+case 0x8223 /* GL_DEPTH_BUFFER */: return "GL_DEPTH_BUFFER (0x8223)";
+case 0x8224 /* GL_STENCIL_BUFFER */: return "GL_STENCIL_BUFFER (0x8224)";
+case 0x8225 /* GL_COMPRESSED_RED */: return "GL_COMPRESSED_RED (0x8225)";
+case 0x8226 /* GL_COMPRESSED_RG */: return "GL_COMPRESSED_RG (0x8226)";
+case 0x8814 /* GL_RGBA32F */: return "GL_RGBA32F (0x8814)";
+//case 0x8814 /* GL_RGBA_FLOAT32_APPLE */: return "GL_RGBA_FLOAT32_APPLE (0x8814)";
+//case 0x8814 /* GL_RGBA32F_ARB */: return "GL_RGBA32F_ARB (0x8814)";
+case 0x8815 /* GL_RGB32F */: return "GL_RGB32F (0x8815)";
+case 0x881A /* GL_RGBA16F */: return "GL_RGBA16F (0x881A)";
+case 0x881B /* GL_RGB16F */: return "GL_RGB16F (0x881B)";
+case 0x88FD /* GL_VERTEX_ATTRIB_ARRAY_INTEGER */: return "GL_VERTEX_ATTRIB_ARRAY_INTEGER (0x88FD)";
+case 0x88FF /* GL_MAX_ARRAY_TEXTURE_LAYERS */: return "GL_MAX_ARRAY_TEXTURE_LAYERS (0x88FF)";
+case 0x8904 /* GL_MIN_PROGRAM_TEXEL_OFFSET */: return "GL_MIN_PROGRAM_TEXEL_OFFSET (0x8904)";
+case 0x8905 /* GL_MAX_PROGRAM_TEXEL_OFFSET */: return "GL_MAX_PROGRAM_TEXEL_OFFSET (0x8905)";
+case 0x891A /* GL_CLAMP_VERTEX_COLOR */: return "GL_CLAMP_VERTEX_COLOR (0x891A)";
+case 0x891B /* GL_CLAMP_FRAGMENT_COLOR */: return "GL_CLAMP_FRAGMENT_COLOR (0x891B)";
+case 0x891C /* GL_CLAMP_READ_COLOR */: return "GL_CLAMP_READ_COLOR (0x891C)";
+case 0x891D /* GL_FIXED_ONLY */: return "GL_FIXED_ONLY (0x891D)";
+case 0x8C10 /* GL_TEXTURE_RED_TYPE */: return "GL_TEXTURE_RED_TYPE (0x8C10)";
+case 0x8C11 /* GL_TEXTURE_GREEN_TYPE */: return "GL_TEXTURE_GREEN_TYPE (0x8C11)";
+case 0x8C12 /* GL_TEXTURE_BLUE_TYPE */: return "GL_TEXTURE_BLUE_TYPE (0x8C12)";
+case 0x8C13 /* GL_TEXTURE_ALPHA_TYPE */: return "GL_TEXTURE_ALPHA_TYPE (0x8C13)";
+case 0x8C14 /* GL_TEXTURE_LUMINANCE_TYPE */: return "GL_TEXTURE_LUMINANCE_TYPE (0x8C14)";
+case 0x8C15 /* GL_TEXTURE_INTENSITY_TYPE */: return "GL_TEXTURE_INTENSITY_TYPE (0x8C15)";
+case 0x8C16 /* GL_TEXTURE_DEPTH_TYPE */: return "GL_TEXTURE_DEPTH_TYPE (0x8C16)";
+case 0x8C18 /* GL_TEXTURE_1D_ARRAY */: return "GL_TEXTURE_1D_ARRAY (0x8C18)";
+case 0x8C19 /* GL_PROXY_TEXTURE_1D_ARRAY */: return "GL_PROXY_TEXTURE_1D_ARRAY (0x8C19)";
+case 0x8C1A /* GL_TEXTURE_2D_ARRAY */: return "GL_TEXTURE_2D_ARRAY (0x8C1A)";
+case 0x8C1B /* GL_PROXY_TEXTURE_2D_ARRAY */: return "GL_PROXY_TEXTURE_2D_ARRAY (0x8C1B)";
+case 0x8C1C /* GL_TEXTURE_BINDING_1D_ARRAY */: return "GL_TEXTURE_BINDING_1D_ARRAY (0x8C1C)";
+case 0x8C1D /* GL_TEXTURE_BINDING_2D_ARRAY */: return "GL_TEXTURE_BINDING_2D_ARRAY (0x8C1D)";
+case 0x8C3A /* GL_R11F_G11F_B10F */: return "GL_R11F_G11F_B10F (0x8C3A)";
+case 0x8C3B /* GL_UNSIGNED_INT_10F_11F_11F_REV */: return "GL_UNSIGNED_INT_10F_11F_11F_REV (0x8C3B)";
+case 0x8C3D /* GL_RGB9_E5 */: return "GL_RGB9_E5 (0x8C3D)";
+case 0x8C3E /* GL_UNSIGNED_INT_5_9_9_9_REV */: return "GL_UNSIGNED_INT_5_9_9_9_REV (0x8C3E)";
+case 0x8C3F /* GL_TEXTURE_SHARED_SIZE */: return "GL_TEXTURE_SHARED_SIZE (0x8C3F)";
+case 0x8C76 /* GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH */: return "GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH (0x8C76)";
+case 0x8C7F /* GL_TRANSFORM_FEEDBACK_BUFFER_MODE */: return "GL_TRANSFORM_FEEDBACK_BUFFER_MODE (0x8C7F)";
+case 0x8C80 /* GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS */: return "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS (0x8C80)";
+case 0x8C83 /* GL_TRANSFORM_FEEDBACK_VARYINGS */: return "GL_TRANSFORM_FEEDBACK_VARYINGS (0x8C83)";
+case 0x8C84 /* GL_TRANSFORM_FEEDBACK_BUFFER_START */: return "GL_TRANSFORM_FEEDBACK_BUFFER_START (0x8C84)";
+case 0x8C85 /* GL_TRANSFORM_FEEDBACK_BUFFER_SIZE */: return "GL_TRANSFORM_FEEDBACK_BUFFER_SIZE (0x8C85)";
+case 0x8C87 /* GL_PRIMITIVES_GENERATED */: return "GL_PRIMITIVES_GENERATED (0x8C87)";
+case 0x8C88 /* GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN */: return "GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN (0x8C88)";
+case 0x8C89 /* GL_RASTERIZER_DISCARD */: return "GL_RASTERIZER_DISCARD (0x8C89)";
+case 0x8C8A /* GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS */: return "GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS (0x8C8A)";
+case 0x8C8B /* GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS */: return "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS (0x8C8B)";
+case 0x8C8C /* GL_INTERLEAVED_ATTRIBS */: return "GL_INTERLEAVED_ATTRIBS (0x8C8C)";
+case 0x8C8D /* GL_SEPARATE_ATTRIBS */: return "GL_SEPARATE_ATTRIBS (0x8C8D)";
+case 0x8C8E /* GL_TRANSFORM_FEEDBACK_BUFFER */: return "GL_TRANSFORM_FEEDBACK_BUFFER (0x8C8E)";
+case 0x8C8F /* GL_TRANSFORM_FEEDBACK_BUFFER_BINDING */: return "GL_TRANSFORM_FEEDBACK_BUFFER_BINDING (0x8C8F)";
+case 0x8D70 /* GL_RGBA32UI */: return "GL_RGBA32UI (0x8D70)";
+case 0x8D71 /* GL_RGB32UI */: return "GL_RGB32UI (0x8D71)";
+case 0x8D76 /* GL_RGBA16UI */: return "GL_RGBA16UI (0x8D76)";
+case 0x8D77 /* GL_RGB16UI */: return "GL_RGB16UI (0x8D77)";
+case 0x8D7C /* GL_RGBA8UI */: return "GL_RGBA8UI (0x8D7C)";
+case 0x8D7D /* GL_RGB8UI */: return "GL_RGB8UI (0x8D7D)";
+case 0x8D82 /* GL_RGBA32I */: return "GL_RGBA32I (0x8D82)";
+case 0x8D83 /* GL_RGB32I */: return "GL_RGB32I (0x8D83)";
+case 0x8D88 /* GL_RGBA16I */: return "GL_RGBA16I (0x8D88)";
+case 0x8D89 /* GL_RGB16I */: return "GL_RGB16I (0x8D89)";
+case 0x8D8E /* GL_RGBA8I */: return "GL_RGBA8I (0x8D8E)";
+case 0x8D8F /* GL_RGB8I */: return "GL_RGB8I (0x8D8F)";
+case 0x8D94 /* GL_RED_INTEGER */: return "GL_RED_INTEGER (0x8D94)";
+case 0x8D95 /* GL_GREEN_INTEGER */: return "GL_GREEN_INTEGER (0x8D95)";
+case 0x8D96 /* GL_BLUE_INTEGER */: return "GL_BLUE_INTEGER (0x8D96)";
+case 0x8D97 /* GL_ALPHA_INTEGER */: return "GL_ALPHA_INTEGER (0x8D97)";
+case 0x8D98 /* GL_RGB_INTEGER */: return "GL_RGB_INTEGER (0x8D98)";
+case 0x8D99 /* GL_RGBA_INTEGER */: return "GL_RGBA_INTEGER (0x8D99)";
+case 0x8D9A /* GL_BGR_INTEGER */: return "GL_BGR_INTEGER (0x8D9A)";
+case 0x8D9B /* GL_BGRA_INTEGER */: return "GL_BGRA_INTEGER (0x8D9B)";
+case 0x8DC0 /* GL_SAMPLER_1D_ARRAY */: return "GL_SAMPLER_1D_ARRAY (0x8DC0)";
+case 0x8DC1 /* GL_SAMPLER_2D_ARRAY */: return "GL_SAMPLER_2D_ARRAY (0x8DC1)";
+case 0x8DC3 /* GL_SAMPLER_1D_ARRAY_SHADOW */: return "GL_SAMPLER_1D_ARRAY_SHADOW (0x8DC3)";
+case 0x8DC4 /* GL_SAMPLER_2D_ARRAY_SHADOW */: return "GL_SAMPLER_2D_ARRAY_SHADOW (0x8DC4)";
+case 0x8DC5 /* GL_SAMPLER_CUBE_SHADOW */: return "GL_SAMPLER_CUBE_SHADOW (0x8DC5)";
+case 0x8DC6 /* GL_UNSIGNED_INT_VEC2 */: return "GL_UNSIGNED_INT_VEC2 (0x8DC6)";
+case 0x8DC7 /* GL_UNSIGNED_INT_VEC3 */: return "GL_UNSIGNED_INT_VEC3 (0x8DC7)";
+case 0x8DC8 /* GL_UNSIGNED_INT_VEC4 */: return "GL_UNSIGNED_INT_VEC4 (0x8DC8)";
+case 0x8DC9 /* GL_INT_SAMPLER_1D */: return "GL_INT_SAMPLER_1D (0x8DC9)";
+case 0x8DCA /* GL_INT_SAMPLER_2D */: return "GL_INT_SAMPLER_2D (0x8DCA)";
+case 0x8DCB /* GL_INT_SAMPLER_3D */: return "GL_INT_SAMPLER_3D (0x8DCB)";
+case 0x8DCC /* GL_INT_SAMPLER_CUBE */: return "GL_INT_SAMPLER_CUBE (0x8DCC)";
+case 0x8DCE /* GL_INT_SAMPLER_1D_ARRAY */: return "GL_INT_SAMPLER_1D_ARRAY (0x8DCE)";
+case 0x8DCF /* GL_INT_SAMPLER_2D_ARRAY */: return "GL_INT_SAMPLER_2D_ARRAY (0x8DCF)";
+case 0x8DD1 /* GL_UNSIGNED_INT_SAMPLER_1D */: return "GL_UNSIGNED_INT_SAMPLER_1D (0x8DD1)";
+case 0x8DD2 /* GL_UNSIGNED_INT_SAMPLER_2D */: return "GL_UNSIGNED_INT_SAMPLER_2D (0x8DD2)";
+case 0x8DD3 /* GL_UNSIGNED_INT_SAMPLER_3D */: return "GL_UNSIGNED_INT_SAMPLER_3D (0x8DD3)";
+case 0x8DD4 /* GL_UNSIGNED_INT_SAMPLER_CUBE */: return "GL_UNSIGNED_INT_SAMPLER_CUBE (0x8DD4)";
+case 0x8DD6 /* GL_UNSIGNED_INT_SAMPLER_1D_ARRAY */: return "GL_UNSIGNED_INT_SAMPLER_1D_ARRAY (0x8DD6)";
+case 0x8DD7 /* GL_UNSIGNED_INT_SAMPLER_2D_ARRAY */: return "GL_UNSIGNED_INT_SAMPLER_2D_ARRAY (0x8DD7)";
+case 0x8E13 /* GL_QUERY_WAIT */: return "GL_QUERY_WAIT (0x8E13)";
+case 0x8E14 /* GL_QUERY_NO_WAIT */: return "GL_QUERY_NO_WAIT (0x8E14)";
+case 0x8E15 /* GL_QUERY_BY_REGION_WAIT */: return "GL_QUERY_BY_REGION_WAIT (0x8E15)";
+case 0x8E16 /* GL_QUERY_BY_REGION_NO_WAIT */: return "GL_QUERY_BY_REGION_NO_WAIT (0x8E16)";
+
+/* ----------------------------- GL_VERSION_3_1 ---------------------------- */
+
+case 0x84F5 /* GL_TEXTURE_RECTANGLE */: return "GL_TEXTURE_RECTANGLE (0x84F5)";
+case 0x84F6 /* GL_TEXTURE_BINDING_RECTANGLE */: return "GL_TEXTURE_BINDING_RECTANGLE (0x84F6)";
+case 0x84F7 /* GL_PROXY_TEXTURE_RECTANGLE */: return "GL_PROXY_TEXTURE_RECTANGLE (0x84F7)";
+case 0x84F8 /* GL_MAX_RECTANGLE_TEXTURE_SIZE */: return "GL_MAX_RECTANGLE_TEXTURE_SIZE (0x84F8)";
+case 0x8B63 /* GL_SAMPLER_2D_RECT */: return "GL_SAMPLER_2D_RECT (0x8B63)";
+case 0x8B64 /* GL_SAMPLER_2D_RECT_SHADOW */: return "GL_SAMPLER_2D_RECT_SHADOW (0x8B64)";
+case 0x8C2A /* GL_TEXTURE_BUFFER */: return "GL_TEXTURE_BUFFER (0x8C2A)";
+case 0x8C2B /* GL_MAX_TEXTURE_BUFFER_SIZE */: return "GL_MAX_TEXTURE_BUFFER_SIZE (0x8C2B)";
+case 0x8C2C /* GL_TEXTURE_BINDING_BUFFER */: return "GL_TEXTURE_BINDING_BUFFER (0x8C2C)";
+case 0x8C2D /* GL_TEXTURE_BUFFER_DATA_STORE_BINDING */: return "GL_TEXTURE_BUFFER_DATA_STORE_BINDING (0x8C2D)";
+case 0x8C2E /* GL_TEXTURE_BUFFER_FORMAT */: return "GL_TEXTURE_BUFFER_FORMAT (0x8C2E)";
+case 0x8DC2 /* GL_SAMPLER_BUFFER */: return "GL_SAMPLER_BUFFER (0x8DC2)";
+case 0x8DCD /* GL_INT_SAMPLER_2D_RECT */: return "GL_INT_SAMPLER_2D_RECT (0x8DCD)";
+case 0x8DD0 /* GL_INT_SAMPLER_BUFFER */: return "GL_INT_SAMPLER_BUFFER (0x8DD0)";
+case 0x8DD5 /* GL_UNSIGNED_INT_SAMPLER_2D_RECT */: return "GL_UNSIGNED_INT_SAMPLER_2D_RECT (0x8DD5)";
+case 0x8DD8 /* GL_UNSIGNED_INT_SAMPLER_BUFFER */: return "GL_UNSIGNED_INT_SAMPLER_BUFFER (0x8DD8)";
+case 0x8F90 /* GL_RED_SNORM */: return "GL_RED_SNORM (0x8F90)";
+case 0x8F91 /* GL_RG_SNORM */: return "GL_RG_SNORM (0x8F91)";
+case 0x8F92 /* GL_RGB_SNORM */: return "GL_RGB_SNORM (0x8F92)";
+case 0x8F93 /* GL_RGBA_SNORM */: return "GL_RGBA_SNORM (0x8F93)";
+case 0x8F94 /* GL_R8_SNORM */: return "GL_R8_SNORM (0x8F94)";
+case 0x8F95 /* GL_RG8_SNORM */: return "GL_RG8_SNORM (0x8F95)";
+case 0x8F96 /* GL_RGB8_SNORM */: return "GL_RGB8_SNORM (0x8F96)";
+case 0x8F97 /* GL_RGBA8_SNORM */: return "GL_RGBA8_SNORM (0x8F97)";
+case 0x8F98 /* GL_R16_SNORM */: return "GL_R16_SNORM (0x8F98)";
+case 0x8F99 /* GL_RG16_SNORM */: return "GL_RG16_SNORM (0x8F99)";
+case 0x8F9A /* GL_RGB16_SNORM */: return "GL_RGB16_SNORM (0x8F9A)";
+case 0x8F9B /* GL_RGBA16_SNORM */: return "GL_RGBA16_SNORM (0x8F9B)";
+case 0x8F9C /* GL_SIGNED_NORMALIZED */: return "GL_SIGNED_NORMALIZED (0x8F9C)";
+case 0x8F9D /* GL_PRIMITIVE_RESTART */: return "GL_PRIMITIVE_RESTART (0x8F9D)";
+case 0x8F9E /* GL_PRIMITIVE_RESTART_INDEX */: return "GL_PRIMITIVE_RESTART_INDEX (0x8F9E)";
+case 0x911F /* GL_BUFFER_ACCESS_FLAGS */: return "GL_BUFFER_ACCESS_FLAGS (0x911F)";
+case 0x9120 /* GL_BUFFER_MAP_LENGTH */: return "GL_BUFFER_MAP_LENGTH (0x9120)";
+case 0x9121 /* GL_BUFFER_MAP_OFFSET */: return "GL_BUFFER_MAP_OFFSET (0x9121)";
+
+/* ----------------------------- GL_VERSION_3_2 ---------------------------- */
+
+//case 0x00000001 /* GL_CONTEXT_CORE_PROFILE_BIT */: return "GL_CONTEXT_CORE_PROFILE_BIT (0x00000001)";
+//case 0x00000002 /* GL_CONTEXT_COMPATIBILITY_PROFILE_BIT */: return "GL_CONTEXT_COMPATIBILITY_PROFILE_BIT (0x00000002)";
+case 0x000A /* GL_LINES_ADJACENCY */: return "GL_LINES_ADJACENCY (0x000A)";
+case 0x000B /* GL_LINE_STRIP_ADJACENCY */: return "GL_LINE_STRIP_ADJACENCY (0x000B)";
+case 0x000C /* GL_TRIANGLES_ADJACENCY */: return "GL_TRIANGLES_ADJACENCY (0x000C)";
+case 0x000D /* GL_TRIANGLE_STRIP_ADJACENCY */: return "GL_TRIANGLE_STRIP_ADJACENCY (0x000D)";
+case 0x8642 /* GL_PROGRAM_POINT_SIZE */: return "GL_PROGRAM_POINT_SIZE (0x8642)";
+//case 0x8642 /* GL_PROGRAM_POINT_SIZE_ARB */: return "GL_PROGRAM_POINT_SIZE_ARB (0x8642)";
+case 0x8916 /* GL_GEOMETRY_VERTICES_OUT */: return "GL_GEOMETRY_VERTICES_OUT (0x8916)";
+case 0x8917 /* GL_GEOMETRY_INPUT_TYPE */: return "GL_GEOMETRY_INPUT_TYPE (0x8917)";
+case 0x8918 /* GL_GEOMETRY_OUTPUT_TYPE */: return "GL_GEOMETRY_OUTPUT_TYPE (0x8918)";
+case 0x8C29 /* GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS */: return "GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS (0x8C29)";
+case 0x8DA7 /* GL_FRAMEBUFFER_ATTACHMENT_LAYERED */: return "GL_FRAMEBUFFER_ATTACHMENT_LAYERED (0x8DA7)";
+case 0x8DA8 /* GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS */: return "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS (0x8DA8)";
+case 0x8DD9 /* GL_GEOMETRY_SHADER */: return "GL_GEOMETRY_SHADER (0x8DD9)";
+case 0x8DDF /* GL_MAX_GEOMETRY_UNIFORM_COMPONENTS */: return "GL_MAX_GEOMETRY_UNIFORM_COMPONENTS (0x8DDF)";
+case 0x8DE0 /* GL_MAX_GEOMETRY_OUTPUT_VERTICES */: return "GL_MAX_GEOMETRY_OUTPUT_VERTICES (0x8DE0)";
+case 0x8DE1 /* GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS */: return "GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS (0x8DE1)";
+case 0x9122 /* GL_MAX_VERTEX_OUTPUT_COMPONENTS */: return "GL_MAX_VERTEX_OUTPUT_COMPONENTS (0x9122)";
+case 0x9123 /* GL_MAX_GEOMETRY_INPUT_COMPONENTS */: return "GL_MAX_GEOMETRY_INPUT_COMPONENTS (0x9123)";
+case 0x9124 /* GL_MAX_GEOMETRY_OUTPUT_COMPONENTS */: return "GL_MAX_GEOMETRY_OUTPUT_COMPONENTS (0x9124)";
+case 0x9125 /* GL_MAX_FRAGMENT_INPUT_COMPONENTS */: return "GL_MAX_FRAGMENT_INPUT_COMPONENTS (0x9125)";
+case 0x9126 /* GL_CONTEXT_PROFILE_MASK */: return "GL_CONTEXT_PROFILE_MASK (0x9126)";
+
+/* ----------------------------- GL_VERSION_3_3 ---------------------------- */
+
+case 0x88FE /* GL_VERTEX_ATTRIB_ARRAY_DIVISOR */: return "GL_VERTEX_ATTRIB_ARRAY_DIVISOR (0x88FE)";
+case 0x8E42 /* GL_TEXTURE_SWIZZLE_R */: return "GL_TEXTURE_SWIZZLE_R (0x8E42)";
+case 0x8E43 /* GL_TEXTURE_SWIZZLE_G */: return "GL_TEXTURE_SWIZZLE_G (0x8E43)";
+case 0x8E44 /* GL_TEXTURE_SWIZZLE_B */: return "GL_TEXTURE_SWIZZLE_B (0x8E44)";
+case 0x8E45 /* GL_TEXTURE_SWIZZLE_A */: return "GL_TEXTURE_SWIZZLE_A (0x8E45)";
+case 0x8E46 /* GL_TEXTURE_SWIZZLE_RGBA */: return "GL_TEXTURE_SWIZZLE_RGBA (0x8E46)";
+case 0x906F /* GL_RGB10_A2UI */: return "GL_RGB10_A2UI (0x906F)";
+
+/* ----------------------------- GL_VERSION_4_0 ---------------------------- */
+
+case 0x887F /* GL_GEOMETRY_SHADER_INVOCATIONS */: return "GL_GEOMETRY_SHADER_INVOCATIONS (0x887F)";
+case 0x8C36 /* GL_SAMPLE_SHADING */: return "GL_SAMPLE_SHADING (0x8C36)";
+case 0x8C37 /* GL_MIN_SAMPLE_SHADING_VALUE */: return "GL_MIN_SAMPLE_SHADING_VALUE (0x8C37)";
+case 0x8E5A /* GL_MAX_GEOMETRY_SHADER_INVOCATIONS */: return "GL_MAX_GEOMETRY_SHADER_INVOCATIONS (0x8E5A)";
+case 0x8E5B /* GL_MIN_FRAGMENT_INTERPOLATION_OFFSET */: return "GL_MIN_FRAGMENT_INTERPOLATION_OFFSET (0x8E5B)";
+case 0x8E5C /* GL_MAX_FRAGMENT_INTERPOLATION_OFFSET */: return "GL_MAX_FRAGMENT_INTERPOLATION_OFFSET (0x8E5C)";
+case 0x8E5D /* GL_FRAGMENT_INTERPOLATION_OFFSET_BITS */: return "GL_FRAGMENT_INTERPOLATION_OFFSET_BITS (0x8E5D)";
+case 0x8E5E /* GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET */: return "GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET (0x8E5E)";
+case 0x8E5F /* GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET */: return "GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET (0x8E5F)";
+case 0x8F9F /* GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS */: return "GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS (0x8F9F)";
+case 0x9009 /* GL_TEXTURE_CUBE_MAP_ARRAY */: return "GL_TEXTURE_CUBE_MAP_ARRAY (0x9009)";
+case 0x900A /* GL_TEXTURE_BINDING_CUBE_MAP_ARRAY */: return "GL_TEXTURE_BINDING_CUBE_MAP_ARRAY (0x900A)";
+case 0x900B /* GL_PROXY_TEXTURE_CUBE_MAP_ARRAY */: return "GL_PROXY_TEXTURE_CUBE_MAP_ARRAY (0x900B)";
+case 0x900C /* GL_SAMPLER_CUBE_MAP_ARRAY */: return "GL_SAMPLER_CUBE_MAP_ARRAY (0x900C)";
+case 0x900D /* GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW */: return "GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW (0x900D)";
+case 0x900E /* GL_INT_SAMPLER_CUBE_MAP_ARRAY */: return "GL_INT_SAMPLER_CUBE_MAP_ARRAY (0x900E)";
+case 0x900F /* GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY */: return "GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY (0x900F)";
+
+/* ----------------------------- GL_VERSION_4_2 ---------------------------- */
+
+case 0x8E8C /* GL_COMPRESSED_RGBA_BPTC_UNORM */: return "GL_COMPRESSED_RGBA_BPTC_UNORM (0x8E8C)";
+case 0x8E8D /* GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM */: return "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM (0x8E8D)";
+case 0x8E8E /* GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT */: return "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT (0x8E8E)";
+case 0x8E8F /* GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT */: return "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT (0x8E8F)";
+
+/* ----------------------------- GL_VERSION_4_3 ---------------------------- */
+
+case 0x82E9 /* GL_NUM_SHADING_LANGUAGE_VERSIONS */: return "GL_NUM_SHADING_LANGUAGE_VERSIONS (0x82E9)";
+case 0x874E /* GL_VERTEX_ATTRIB_ARRAY_LONG */: return "GL_VERTEX_ATTRIB_ARRAY_LONG (0x874E)";
+
+/* -------------------------- GL_3DFX_multisample -------------------------- */
+
+case 0x86B2 /* GL_MULTISAMPLE_3DFX */: return "GL_MULTISAMPLE_3DFX (0x86B2)";
+case 0x86B3 /* GL_SAMPLE_BUFFERS_3DFX */: return "GL_SAMPLE_BUFFERS_3DFX (0x86B3)";
+case 0x86B4 /* GL_SAMPLES_3DFX */: return "GL_SAMPLES_3DFX (0x86B4)";
+//case 0x20000000 /* GL_MULTISAMPLE_BIT_3DFX */: return "GL_MULTISAMPLE_BIT_3DFX (0x20000000)";
+
+/* ---------------------------- GL_3DFX_tbuffer ---------------------------- */
+
+
+/* -------------------- GL_3DFX_texture_compression_FXT1 ------------------- */
+
+
+
+
+case 0x86B0 /* GL_COMPRESSED_RGB_FXT1_3DFX */: return "GL_COMPRESSED_RGB_FXT1_3DFX (0x86B0)";
+case 0x86B1 /* GL_COMPRESSED_RGBA_FXT1_3DFX */: return "GL_COMPRESSED_RGBA_FXT1_3DFX (0x86B1)";
+
+
+
+
+
+/* ----------------------- GL_AMD_blend_minmax_factor ---------------------- */
+
+
+
+
+case 0x901C /* GL_FACTOR_MIN_AMD */: return "GL_FACTOR_MIN_AMD (0x901C)";
+case 0x901D /* GL_FACTOR_MAX_AMD */: return "GL_FACTOR_MAX_AMD (0x901D)";
+
+
+
+
+
+/* ----------------------- GL_AMD_conservative_depth ----------------------- */
+
+
+
+
+
+
+
+
+/* -------------------------- GL_AMD_debug_output -------------------------- */
+
+
+
+
+case 0x9143 /* GL_MAX_DEBUG_MESSAGE_LENGTH_AMD */: return "GL_MAX_DEBUG_MESSAGE_LENGTH_AMD (0x9143)";
+case 0x9144 /* GL_MAX_DEBUG_LOGGED_MESSAGES_AMD */: return "GL_MAX_DEBUG_LOGGED_MESSAGES_AMD (0x9144)";
+case 0x9145 /* GL_DEBUG_LOGGED_MESSAGES_AMD */: return "GL_DEBUG_LOGGED_MESSAGES_AMD (0x9145)";
+case 0x9146 /* GL_DEBUG_SEVERITY_HIGH_AMD */: return "GL_DEBUG_SEVERITY_HIGH_AMD (0x9146)";
+case 0x9147 /* GL_DEBUG_SEVERITY_MEDIUM_AMD */: return "GL_DEBUG_SEVERITY_MEDIUM_AMD (0x9147)";
+case 0x9148 /* GL_DEBUG_SEVERITY_LOW_AMD */: return "GL_DEBUG_SEVERITY_LOW_AMD (0x9148)";
+case 0x9149 /* GL_DEBUG_CATEGORY_API_ERROR_AMD */: return "GL_DEBUG_CATEGORY_API_ERROR_AMD (0x9149)";
+case 0x914A /* GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD */: return "GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD (0x914A)";
+case 0x914B /* GL_DEBUG_CATEGORY_DEPRECATION_AMD */: return "GL_DEBUG_CATEGORY_DEPRECATION_AMD (0x914B)";
+case 0x914C /* GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD */: return "GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD (0x914C)";
+case 0x914D /* GL_DEBUG_CATEGORY_PERFORMANCE_AMD */: return "GL_DEBUG_CATEGORY_PERFORMANCE_AMD (0x914D)";
+case 0x914E /* GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD */: return "GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD (0x914E)";
+case 0x914F /* GL_DEBUG_CATEGORY_APPLICATION_AMD */: return "GL_DEBUG_CATEGORY_APPLICATION_AMD (0x914F)";
+case 0x9150 /* GL_DEBUG_CATEGORY_OTHER_AMD */: return "GL_DEBUG_CATEGORY_OTHER_AMD (0x9150)";
+
+
+
+
+
+
+
+/* ---------------------- GL_AMD_depth_clamp_separate ---------------------- */
+
+
+
+
+case 0x901E /* GL_DEPTH_CLAMP_NEAR_AMD */: return "GL_DEPTH_CLAMP_NEAR_AMD (0x901E)";
+case 0x901F /* GL_DEPTH_CLAMP_FAR_AMD */: return "GL_DEPTH_CLAMP_FAR_AMD (0x901F)";
+
+
+
+
+
+/* ----------------------- GL_AMD_draw_buffers_blend ----------------------- */
+
+
+
+
+
+
+
+
+/* ----------------------- GL_AMD_multi_draw_indirect ---------------------- */
+
+
+
+
+/* ------------------------- GL_AMD_name_gen_delete ------------------------ */
+
+
+
+
+case 0x9151 /* GL_DATA_BUFFER_AMD */: return "GL_DATA_BUFFER_AMD (0x9151)";
+case 0x9152 /* GL_PERFORMANCE_MONITOR_AMD */: return "GL_PERFORMANCE_MONITOR_AMD (0x9152)";
+case 0x9153 /* GL_QUERY_OBJECT_AMD */: return "GL_QUERY_OBJECT_AMD (0x9153)";
+case 0x9154 /* GL_VERTEX_ARRAY_OBJECT_AMD */: return "GL_VERTEX_ARRAY_OBJECT_AMD (0x9154)";
+case 0x9155 /* GL_SAMPLER_OBJECT_AMD */: return "GL_SAMPLER_OBJECT_AMD (0x9155)";
+
+
+
+/* ----------------------- GL_AMD_performance_monitor ---------------------- */
+
+
+
+
+case 0x8BC0 /* GL_COUNTER_TYPE_AMD */: return "GL_COUNTER_TYPE_AMD (0x8BC0)";
+case 0x8BC1 /* GL_COUNTER_RANGE_AMD */: return "GL_COUNTER_RANGE_AMD (0x8BC1)";
+case 0x8BC2 /* GL_UNSIGNED_INT64_AMD */: return "GL_UNSIGNED_INT64_AMD (0x8BC2)";
+case 0x8BC3 /* GL_PERCENTAGE_AMD */: return "GL_PERCENTAGE_AMD (0x8BC3)";
+case 0x8BC4 /* GL_PERFMON_RESULT_AVAILABLE_AMD */: return "GL_PERFMON_RESULT_AVAILABLE_AMD (0x8BC4)";
+case 0x8BC5 /* GL_PERFMON_RESULT_SIZE_AMD */: return "GL_PERFMON_RESULT_SIZE_AMD (0x8BC5)";
+case 0x8BC6 /* GL_PERFMON_RESULT_AMD */: return "GL_PERFMON_RESULT_AMD (0x8BC6)";/* -------------------------- GL_AMD_pinned_memory ------------------------- */
+
+
+
+
+case 0x9160 /* GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD */: return "GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD (0x9160)";
+
+
+
+
+
+/* ----------------------- GL_AMD_query_buffer_object ---------------------- */
+
+
+
+
+case 0x9192 /* GL_QUERY_BUFFER_AMD */: return "GL_QUERY_BUFFER_AMD (0x9192)";
+case 0x9193 /* GL_QUERY_BUFFER_BINDING_AMD */: return "GL_QUERY_BUFFER_BINDING_AMD (0x9193)";
+case 0x9194 /* GL_QUERY_RESULT_NO_WAIT_AMD */: return "GL_QUERY_RESULT_NO_WAIT_AMD (0x9194)";
+
+
+
+
+
+/* ------------------------ GL_AMD_sample_positions ------------------------ */
+
+
+
+
+case 0x883F /* GL_SUBSAMPLE_DISTANCE_AMD */: return "GL_SUBSAMPLE_DISTANCE_AMD (0x883F)";/* ------------------ GL_AMD_seamless_cubemap_per_texture ------------------ */
+
+
+
+
+case 0x884F /* GL_TEXTURE_CUBE_MAP_SEAMLESS_ARB */: return "GL_TEXTURE_CUBE_MAP_SEAMLESS_ARB (0x884F)";
+
+
+
+
+
+/* ---------------------- GL_AMD_shader_stencil_export --------------------- */
+
+
+
+
+
+
+
+
+/* ------------------- GL_AMD_stencil_operation_extended ------------------- */
+
+
+
+
+case 0x874A /* GL_SET_AMD */: return "GL_SET_AMD (0x874A)";
+case 0x874B /* GL_REPLACE_VALUE_AMD */: return "GL_REPLACE_VALUE_AMD (0x874B)";
+case 0x874C /* GL_STENCIL_OP_VALUE_AMD */: return "GL_STENCIL_OP_VALUE_AMD (0x874C)";
+case 0x874D /* GL_STENCIL_BACK_OP_VALUE_AMD */: return "GL_STENCIL_BACK_OP_VALUE_AMD (0x874D)";/* ------------------------ GL_AMD_texture_texture4 ------------------------ */
+
+
+
+
+
+
+
+
+/* --------------- GL_AMD_transform_feedback3_lines_triangles -------------- */
+
+
+
+
+
+
+
+
+/* ----------------------- GL_AMD_vertex_shader_layer ---------------------- */
+
+
+
+
+
+
+
+
+/* -------------------- GL_AMD_vertex_shader_tessellator ------------------- */
+
+
+
+
+case 0x9001 /* GL_SAMPLER_BUFFER_AMD */: return "GL_SAMPLER_BUFFER_AMD (0x9001)";
+case 0x9002 /* GL_INT_SAMPLER_BUFFER_AMD */: return "GL_INT_SAMPLER_BUFFER_AMD (0x9002)";
+case 0x9003 /* GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD */: return "GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD (0x9003)";
+case 0x9004 /* GL_TESSELLATION_MODE_AMD */: return "GL_TESSELLATION_MODE_AMD (0x9004)";
+case 0x9005 /* GL_TESSELLATION_FACTOR_AMD */: return "GL_TESSELLATION_FACTOR_AMD (0x9005)";
+case 0x9006 /* GL_DISCRETE_AMD */: return "GL_DISCRETE_AMD (0x9006)";
+case 0x9007 /* GL_CONTINUOUS_AMD */: return "GL_CONTINUOUS_AMD (0x9007)";
+
+/* ------------------ GL_AMD_vertex_shader_viewport_index ------------------ */
+
+
+
+
+
+
+
+
+/* ----------------------- GL_APPLE_aux_depth_stencil ---------------------- */
+
+
+
+
+case 0x8A14 /* GL_AUX_DEPTH_STENCIL_APPLE */: return "GL_AUX_DEPTH_STENCIL_APPLE (0x8A14)";
+
+
+
+
+
+/* ------------------------ GL_APPLE_client_storage ------------------------ */
+
+
+
+
+case 0x85B2 /* GL_UNPACK_CLIENT_STORAGE_APPLE */: return "GL_UNPACK_CLIENT_STORAGE_APPLE (0x85B2)";
+
+
+
+
+
+/* ------------------------- GL_APPLE_element_array ------------------------ */
+
+
+
+
+case 0x8A0C /* GL_ELEMENT_ARRAY_APPLE */: return "GL_ELEMENT_ARRAY_APPLE (0x8A0C)";
+case 0x8A0D /* GL_ELEMENT_ARRAY_TYPE_APPLE */: return "GL_ELEMENT_ARRAY_TYPE_APPLE (0x8A0D)";
+case 0x8A0E /* GL_ELEMENT_ARRAY_POINTER_APPLE */: return "GL_ELEMENT_ARRAY_POINTER_APPLE (0x8A0E)";
+
+
+
+
+
+
+
+/* ----------------------------- GL_APPLE_fence ---------------------------- */
+
+
+
+
+case 0x8A0A /* GL_DRAW_PIXELS_APPLE */: return "GL_DRAW_PIXELS_APPLE (0x8A0A)";
+case 0x8A0B /* GL_FENCE_APPLE */: return "GL_FENCE_APPLE (0x8A0B)";
+
+
+
+/* ------------------------- GL_APPLE_float_pixels ------------------------- */
+
+
+
+
+//case 0x140B /* GL_HALF_APPLE */: return "GL_HALF_APPLE (0x140B)";
+//case 0x8815 /* GL_RGB_FLOAT32_APPLE */: return "GL_RGB_FLOAT32_APPLE (0x8815)";
+case 0x8816 /* GL_ALPHA_FLOAT32_APPLE */: return "GL_ALPHA_FLOAT32_APPLE (0x8816)";
+case 0x8817 /* GL_INTENSITY_FLOAT32_APPLE */: return "GL_INTENSITY_FLOAT32_APPLE (0x8817)";
+case 0x8818 /* GL_LUMINANCE_FLOAT32_APPLE */: return "GL_LUMINANCE_FLOAT32_APPLE (0x8818)";
+case 0x8819 /* GL_LUMINANCE_ALPHA_FLOAT32_APPLE */: return "GL_LUMINANCE_ALPHA_FLOAT32_APPLE (0x8819)";
+//case 0x881A /* GL_RGBA_FLOAT16_APPLE */: return "GL_RGBA_FLOAT16_APPLE (0x881A)";
+//case 0x881B /* GL_RGB_FLOAT16_APPLE */: return "GL_RGB_FLOAT16_APPLE (0x881B)";
+case 0x881C /* GL_ALPHA_FLOAT16_APPLE */: return "GL_ALPHA_FLOAT16_APPLE (0x881C)";
+case 0x881D /* GL_INTENSITY_FLOAT16_APPLE */: return "GL_INTENSITY_FLOAT16_APPLE (0x881D)";
+case 0x881E /* GL_LUMINANCE_FLOAT16_APPLE */: return "GL_LUMINANCE_FLOAT16_APPLE (0x881E)";
+case 0x881F /* GL_LUMINANCE_ALPHA_FLOAT16_APPLE */: return "GL_LUMINANCE_ALPHA_FLOAT16_APPLE (0x881F)";
+case 0x8A0F /* GL_COLOR_FLOAT_APPLE */: return "GL_COLOR_FLOAT_APPLE (0x8A0F)";
+
+
+
+
+
+/* ---------------------- GL_APPLE_flush_buffer_range ---------------------- */
+
+
+
+
+case 0x8A12 /* GL_BUFFER_SERIALIZED_MODIFY_APPLE */: return "GL_BUFFER_SERIALIZED_MODIFY_APPLE (0x8A12)";
+case 0x8A13 /* GL_BUFFER_FLUSHING_UNMAP_APPLE */: return "GL_BUFFER_FLUSHING_UNMAP_APPLE (0x8A13)";
+
+/* ----------------------- GL_APPLE_object_purgeable ----------------------- */
+
+
+
+
+case 0x85B3 /* GL_BUFFER_OBJECT_APPLE */: return "GL_BUFFER_OBJECT_APPLE (0x85B3)";
+case 0x8A19 /* GL_RELEASED_APPLE */: return "GL_RELEASED_APPLE (0x8A19)";
+case 0x8A1A /* GL_VOLATILE_APPLE */: return "GL_VOLATILE_APPLE (0x8A1A)";
+case 0x8A1B /* GL_RETAINED_APPLE */: return "GL_RETAINED_APPLE (0x8A1B)";
+case 0x8A1C /* GL_UNDEFINED_APPLE */: return "GL_UNDEFINED_APPLE (0x8A1C)";
+case 0x8A1D /* GL_PURGEABLE_APPLE */: return "GL_PURGEABLE_APPLE (0x8A1D)";
+
+
+
+/* ------------------------- GL_APPLE_pixel_buffer ------------------------- */
+
+
+
+
+case 0x8A10 /* GL_MIN_PBUFFER_VIEWPORT_DIMS_APPLE */: return "GL_MIN_PBUFFER_VIEWPORT_DIMS_APPLE (0x8A10)";
+
+
+
+
+
+/* ---------------------------- GL_APPLE_rgb_422 --------------------------- */
+
+
+
+
+case 0x85BA /* GL_UNSIGNED_SHORT_8_8_APPLE */: return "GL_UNSIGNED_SHORT_8_8_APPLE (0x85BA)";
+case 0x85BB /* GL_UNSIGNED_SHORT_8_8_REV_APPLE */: return "GL_UNSIGNED_SHORT_8_8_REV_APPLE (0x85BB)";
+case 0x8A1F /* GL_RGB_422_APPLE */: return "GL_RGB_422_APPLE (0x8A1F)";
+
+
+
+
+
+/* --------------------------- GL_APPLE_row_bytes -------------------------- */
+
+
+
+
+case 0x8A15 /* GL_PACK_ROW_BYTES_APPLE */: return "GL_PACK_ROW_BYTES_APPLE (0x8A15)";
+case 0x8A16 /* GL_UNPACK_ROW_BYTES_APPLE */: return "GL_UNPACK_ROW_BYTES_APPLE (0x8A16)";
+
+
+
+
+
+/* ------------------------ GL_APPLE_specular_vector ----------------------- */
+
+
+
+
+case 0x85B0 /* GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE */: return "GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE (0x85B0)";
+
+
+
+
+
+/* ------------------------- GL_APPLE_texture_range ------------------------ */
+
+
+
+
+case 0x85B7 /* GL_TEXTURE_RANGE_LENGTH_APPLE */: return "GL_TEXTURE_RANGE_LENGTH_APPLE (0x85B7)";
+case 0x85B8 /* GL_TEXTURE_RANGE_POINTER_APPLE */: return "GL_TEXTURE_RANGE_POINTER_APPLE (0x85B8)";
+case 0x85BC /* GL_TEXTURE_STORAGE_HINT_APPLE */: return "GL_TEXTURE_STORAGE_HINT_APPLE (0x85BC)";
+case 0x85BD /* GL_STORAGE_PRIVATE_APPLE */: return "GL_STORAGE_PRIVATE_APPLE (0x85BD)";
+//case 0x85BE /* GL_STORAGE_CACHED_APPLE */: return "GL_STORAGE_CACHED_APPLE (0x85BE)";
+//case 0x85BF /* GL_STORAGE_SHARED_APPLE */: return "GL_STORAGE_SHARED_APPLE (0x85BF)";
+
+/* ------------------------ GL_APPLE_transform_hint ------------------------ */
+
+
+
+
+case 0x85B1 /* GL_TRANSFORM_HINT_APPLE */: return "GL_TRANSFORM_HINT_APPLE (0x85B1)";
+
+
+
+
+
+/* ---------------------- GL_APPLE_vertex_array_object --------------------- */
+
+
+
+
+case 0x85B5 /* GL_VERTEX_ARRAY_BINDING_APPLE */: return "GL_VERTEX_ARRAY_BINDING_APPLE (0x85B5)";
+
+
+
+
+
+/* ---------------------- GL_APPLE_vertex_array_range ---------------------- */
+
+
+
+
+case 0x851D /* GL_VERTEX_ARRAY_RANGE_APPLE */: return "GL_VERTEX_ARRAY_RANGE_APPLE (0x851D)";
+case 0x851E /* GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE */: return "GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE (0x851E)";
+case 0x851F /* GL_VERTEX_ARRAY_STORAGE_HINT_APPLE */: return "GL_VERTEX_ARRAY_STORAGE_HINT_APPLE (0x851F)";
+case 0x8520 /* GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_APPLE */: return "GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_APPLE (0x8520)";
+case 0x8521 /* GL_VERTEX_ARRAY_RANGE_POINTER_APPLE */: return "GL_VERTEX_ARRAY_RANGE_POINTER_APPLE (0x8521)";
+case 0x85B4 /* GL_STORAGE_CLIENT_APPLE */: return "GL_STORAGE_CLIENT_APPLE (0x85B4)";
+case 0x85BE /* GL_STORAGE_CACHED_APPLE */: return "GL_STORAGE_CACHED_APPLE (0x85BE)";
+case 0x85BF /* GL_STORAGE_SHARED_APPLE */: return "GL_STORAGE_SHARED_APPLE (0x85BF)";
+
+
+
+/* ------------------- GL_APPLE_vertex_program_evaluators ------------------ */
+
+
+
+
+case 0x8A00 /* GL_VERTEX_ATTRIB_MAP1_APPLE */: return "GL_VERTEX_ATTRIB_MAP1_APPLE (0x8A00)";
+case 0x8A01 /* GL_VERTEX_ATTRIB_MAP2_APPLE */: return "GL_VERTEX_ATTRIB_MAP2_APPLE (0x8A01)";
+case 0x8A02 /* GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE */: return "GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE (0x8A02)";
+case 0x8A03 /* GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE */: return "GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE (0x8A03)";
+case 0x8A04 /* GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE */: return "GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE (0x8A04)";
+case 0x8A05 /* GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE */: return "GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE (0x8A05)";
+case 0x8A06 /* GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE */: return "GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE (0x8A06)";
+case 0x8A07 /* GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE */: return "GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE (0x8A07)";
+case 0x8A08 /* GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE */: return "GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE (0x8A08)";
+case 0x8A09 /* GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE */: return "GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE (0x8A09)";
+
+/* --------------------------- GL_APPLE_ycbcr_422 -------------------------- */
+
+
+
+
+case 0x85B9 /* GL_YCBCR_422_APPLE */: return "GL_YCBCR_422_APPLE (0x85B9)";
+
+
+
+
+
+/* ------------------------ GL_ARB_ES2_compatibility ----------------------- */
+
+
+
+
+case 0x140C /* GL_FIXED */: return "GL_FIXED (0x140C)";
+case 0x8B9A /* GL_IMPLEMENTATION_COLOR_READ_TYPE */: return "GL_IMPLEMENTATION_COLOR_READ_TYPE (0x8B9A)";
+case 0x8B9B /* GL_IMPLEMENTATION_COLOR_READ_FORMAT */: return "GL_IMPLEMENTATION_COLOR_READ_FORMAT (0x8B9B)";
+case 0x8D62 /* GL_RGB565 */: return "GL_RGB565 (0x8D62)";
+case 0x8DF0 /* GL_LOW_FLOAT */: return "GL_LOW_FLOAT (0x8DF0)";
+case 0x8DF1 /* GL_MEDIUM_FLOAT */: return "GL_MEDIUM_FLOAT (0x8DF1)";
+case 0x8DF2 /* GL_HIGH_FLOAT */: return "GL_HIGH_FLOAT (0x8DF2)";
+case 0x8DF3 /* GL_LOW_INT */: return "GL_LOW_INT (0x8DF3)";
+case 0x8DF4 /* GL_MEDIUM_INT */: return "GL_MEDIUM_INT (0x8DF4)";
+case 0x8DF5 /* GL_HIGH_INT */: return "GL_HIGH_INT (0x8DF5)";
+case 0x8DF8 /* GL_SHADER_BINARY_FORMATS */: return "GL_SHADER_BINARY_FORMATS (0x8DF8)";
+case 0x8DF9 /* GL_NUM_SHADER_BINARY_FORMATS */: return "GL_NUM_SHADER_BINARY_FORMATS (0x8DF9)";
+case 0x8DFA /* GL_SHADER_COMPILER */: return "GL_SHADER_COMPILER (0x8DFA)";
+case 0x8DFB /* GL_MAX_VERTEX_UNIFORM_VECTORS */: return "GL_MAX_VERTEX_UNIFORM_VECTORS (0x8DFB)";
+case 0x8DFC /* GL_MAX_VARYING_VECTORS */: return "GL_MAX_VARYING_VECTORS (0x8DFC)";
+case 0x8DFD /* GL_MAX_FRAGMENT_UNIFORM_VECTORS */: return "GL_MAX_FRAGMENT_UNIFORM_VECTORS (0x8DFD)";
+
+
+
+
+
+
+
+/* ------------------------ GL_ARB_ES3_compatibility ----------------------- */
+
+
+
+
+case 0x8D69 /* GL_PRIMITIVE_RESTART_FIXED_INDEX */: return "GL_PRIMITIVE_RESTART_FIXED_INDEX (0x8D69)";
+case 0x8D6A /* GL_ANY_SAMPLES_PASSED_CONSERVATIVE */: return "GL_ANY_SAMPLES_PASSED_CONSERVATIVE (0x8D6A)";
+case 0x8D6B /* GL_MAX_ELEMENT_INDEX */: return "GL_MAX_ELEMENT_INDEX (0x8D6B)";
+case 0x9270 /* GL_COMPRESSED_R11_EAC */: return "GL_COMPRESSED_R11_EAC (0x9270)";
+case 0x9271 /* GL_COMPRESSED_SIGNED_R11_EAC */: return "GL_COMPRESSED_SIGNED_R11_EAC (0x9271)";
+case 0x9272 /* GL_COMPRESSED_RG11_EAC */: return "GL_COMPRESSED_RG11_EAC (0x9272)";
+case 0x9273 /* GL_COMPRESSED_SIGNED_RG11_EAC */: return "GL_COMPRESSED_SIGNED_RG11_EAC (0x9273)";
+case 0x9274 /* GL_COMPRESSED_RGB8_ETC2 */: return "GL_COMPRESSED_RGB8_ETC2 (0x9274)";
+case 0x9275 /* GL_COMPRESSED_SRGB8_ETC2 */: return "GL_COMPRESSED_SRGB8_ETC2 (0x9275)";
+case 0x9276 /* GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 */: return "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 (0x9276)";
+case 0x9277 /* GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 */: return "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 (0x9277)";
+case 0x9278 /* GL_COMPRESSED_RGBA8_ETC2_EAC */: return "GL_COMPRESSED_RGBA8_ETC2_EAC (0x9278)";
+case 0x9279 /* GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC */: return "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC (0x9279)";
+
+
+
+
+
+/* ------------------------ GL_ARB_arrays_of_arrays ------------------------ */
+
+
+
+
+
+
+
+
+/* -------------------------- GL_ARB_base_instance ------------------------- */
+
+
+
+
+
+
+/* ----------------------- GL_ARB_blend_func_extended ---------------------- */
+
+
+
+
+case 0x88F9 /* GL_SRC1_COLOR */: return "GL_SRC1_COLOR (0x88F9)";
+case 0x88FA /* GL_ONE_MINUS_SRC1_COLOR */: return "GL_ONE_MINUS_SRC1_COLOR (0x88FA)";
+case 0x88FB /* GL_ONE_MINUS_SRC1_ALPHA */: return "GL_ONE_MINUS_SRC1_ALPHA (0x88FB)";
+case 0x88FC /* GL_MAX_DUAL_SOURCE_DRAW_BUFFERS */: return "GL_MAX_DUAL_SOURCE_DRAW_BUFFERS (0x88FC)";
+
+/* ---------------------------- GL_ARB_cl_event ---------------------------- */
+
+
+
+
+case 0x8240 /* GL_SYNC_CL_EVENT_ARB */: return "GL_SYNC_CL_EVENT_ARB (0x8240)";
+case 0x8241 /* GL_SYNC_CL_EVENT_COMPLETE_ARB */: return "GL_SYNC_CL_EVENT_COMPLETE_ARB (0x8241)";
+
+
+/* ----------------------- GL_ARB_clear_buffer_object ---------------------- */
+
+
+
+
+
+
+
+
+/* ----------------------- GL_ARB_color_buffer_float ----------------------- */
+
+
+
+
+case 0x8820 /* GL_RGBA_FLOAT_MODE_ARB */: return "GL_RGBA_FLOAT_MODE_ARB (0x8820)";
+//case 0x891A /* GL_CLAMP_VERTEX_COLOR_ARB */: return "GL_CLAMP_VERTEX_COLOR_ARB (0x891A)";
+//case 0x891B /* GL_CLAMP_FRAGMENT_COLOR_ARB */: return "GL_CLAMP_FRAGMENT_COLOR_ARB (0x891B)";
+//case 0x891C /* GL_CLAMP_READ_COLOR_ARB */: return "GL_CLAMP_READ_COLOR_ARB (0x891C)";
+//case 0x891D /* GL_FIXED_ONLY_ARB */: return "GL_FIXED_ONLY_ARB (0x891D)";
+	
+	/* -------------------------- GL_ARB_compatibility ------------------------- */
+
+
+
+
+
+
+
+
+/* ---------------- GL_ARB_compressed_texture_pixel_storage ---------------- */
+
+
+
+
+case 0x9127 /* GL_UNPACK_COMPRESSED_BLOCK_WIDTH */: return "GL_UNPACK_COMPRESSED_BLOCK_WIDTH (0x9127)";
+case 0x9128 /* GL_UNPACK_COMPRESSED_BLOCK_HEIGHT */: return "GL_UNPACK_COMPRESSED_BLOCK_HEIGHT (0x9128)";
+case 0x9129 /* GL_UNPACK_COMPRESSED_BLOCK_DEPTH */: return "GL_UNPACK_COMPRESSED_BLOCK_DEPTH (0x9129)";
+case 0x912A /* GL_UNPACK_COMPRESSED_BLOCK_SIZE */: return "GL_UNPACK_COMPRESSED_BLOCK_SIZE (0x912A)";
+case 0x912B /* GL_PACK_COMPRESSED_BLOCK_WIDTH */: return "GL_PACK_COMPRESSED_BLOCK_WIDTH (0x912B)";
+case 0x912C /* GL_PACK_COMPRESSED_BLOCK_HEIGHT */: return "GL_PACK_COMPRESSED_BLOCK_HEIGHT (0x912C)";
+case 0x912D /* GL_PACK_COMPRESSED_BLOCK_DEPTH */: return "GL_PACK_COMPRESSED_BLOCK_DEPTH (0x912D)";
+case 0x912E /* GL_PACK_COMPRESSED_BLOCK_SIZE */: return "GL_PACK_COMPRESSED_BLOCK_SIZE (0x912E)";
+
+
+
+
+
+/* ------------------------- GL_ARB_compute_shader ------------------------- */
+
+
+
+
+//case 0x00000020 /* GL_COMPUTE_SHADER_BIT */: return "GL_COMPUTE_SHADER_BIT (0x00000020)";
+case 0x8262 /* GL_MAX_COMPUTE_SHARED_MEMORY_SIZE */: return "GL_MAX_COMPUTE_SHARED_MEMORY_SIZE (0x8262)";
+case 0x8263 /* GL_MAX_COMPUTE_UNIFORM_COMPONENTS */: return "GL_MAX_COMPUTE_UNIFORM_COMPONENTS (0x8263)";
+case 0x8264 /* GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS */: return "GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS (0x8264)";
+case 0x8265 /* GL_MAX_COMPUTE_ATOMIC_COUNTERS */: return "GL_MAX_COMPUTE_ATOMIC_COUNTERS (0x8265)";
+case 0x8266 /* GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS */: return "GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS (0x8266)";
+case 0x8267 /* GL_COMPUTE_WORK_GROUP_SIZE */: return "GL_COMPUTE_WORK_GROUP_SIZE (0x8267)";
+case 0x90EB /* GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS */: return "GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS (0x90EB)";
+case 0x90EC /* GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER */: return "GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER (0x90EC)";
+case 0x90ED /* GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER */: return "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER (0x90ED)";
+case 0x90EE /* GL_DISPATCH_INDIRECT_BUFFER */: return "GL_DISPATCH_INDIRECT_BUFFER (0x90EE)";
+case 0x90EF /* GL_DISPATCH_INDIRECT_BUFFER_BINDING */: return "GL_DISPATCH_INDIRECT_BUFFER_BINDING (0x90EF)";
+case 0x91B9 /* GL_COMPUTE_SHADER */: return "GL_COMPUTE_SHADER (0x91B9)";
+case 0x91BB /* GL_MAX_COMPUTE_UNIFORM_BLOCKS */: return "GL_MAX_COMPUTE_UNIFORM_BLOCKS (0x91BB)";
+case 0x91BC /* GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS */: return "GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS (0x91BC)";
+case 0x91BD /* GL_MAX_COMPUTE_IMAGE_UNIFORMS */: return "GL_MAX_COMPUTE_IMAGE_UNIFORMS (0x91BD)";
+case 0x91BE /* GL_MAX_COMPUTE_WORK_GROUP_COUNT */: return "GL_MAX_COMPUTE_WORK_GROUP_COUNT (0x91BE)";
+case 0x91BF /* GL_MAX_COMPUTE_WORK_GROUP_SIZE */: return "GL_MAX_COMPUTE_WORK_GROUP_SIZE (0x91BF)";
+
+/* ----------------------- GL_ARB_conservative_depth ----------------------- */
+
+
+
+
+
+
+
+
+/* --------------------------- GL_ARB_copy_buffer -------------------------- */
+
+
+
+
+case 0x8F36 /* GL_COPY_READ_BUFFER */: return "GL_COPY_READ_BUFFER (0x8F36)";
+case 0x8F37 /* GL_COPY_WRITE_BUFFER */: return "GL_COPY_WRITE_BUFFER (0x8F37)";/* --------------------------- GL_ARB_copy_image --------------------------- */
+
+
+/* -------------------------- GL_ARB_debug_output -------------------------- */
+
+
+
+
+case 0x8242 /* GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB */: return "GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB (0x8242)";
+case 0x8243 /* GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB */: return "GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB (0x8243)";
+case 0x8244 /* GL_DEBUG_CALLBACK_FUNCTION_ARB */: return "GL_DEBUG_CALLBACK_FUNCTION_ARB (0x8244)";
+case 0x8245 /* GL_DEBUG_CALLBACK_USER_PARAM_ARB */: return "GL_DEBUG_CALLBACK_USER_PARAM_ARB (0x8245)";
+case 0x8246 /* GL_DEBUG_SOURCE_API_ARB */: return "GL_DEBUG_SOURCE_API_ARB (0x8246)";
+case 0x8247 /* GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB */: return "GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB (0x8247)";
+case 0x8248 /* GL_DEBUG_SOURCE_SHADER_COMPILER_ARB */: return "GL_DEBUG_SOURCE_SHADER_COMPILER_ARB (0x8248)";
+case 0x8249 /* GL_DEBUG_SOURCE_THIRD_PARTY_ARB */: return "GL_DEBUG_SOURCE_THIRD_PARTY_ARB (0x8249)";
+case 0x824A /* GL_DEBUG_SOURCE_APPLICATION_ARB */: return "GL_DEBUG_SOURCE_APPLICATION_ARB (0x824A)";
+case 0x824B /* GL_DEBUG_SOURCE_OTHER_ARB */: return "GL_DEBUG_SOURCE_OTHER_ARB (0x824B)";
+case 0x824C /* GL_DEBUG_TYPE_ERROR_ARB */: return "GL_DEBUG_TYPE_ERROR_ARB (0x824C)";
+case 0x824D /* GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB */: return "GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB (0x824D)";
+case 0x824E /* GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB */: return "GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB (0x824E)";
+case 0x824F /* GL_DEBUG_TYPE_PORTABILITY_ARB */: return "GL_DEBUG_TYPE_PORTABILITY_ARB (0x824F)";
+case 0x8250 /* GL_DEBUG_TYPE_PERFORMANCE_ARB */: return "GL_DEBUG_TYPE_PERFORMANCE_ARB (0x8250)";
+case 0x8251 /* GL_DEBUG_TYPE_OTHER_ARB */: return "GL_DEBUG_TYPE_OTHER_ARB (0x8251)";
+//case 0x9143 /* GL_MAX_DEBUG_MESSAGE_LENGTH_ARB */: return "GL_MAX_DEBUG_MESSAGE_LENGTH_ARB (0x9143)";
+//case 0x9144 /* GL_MAX_DEBUG_LOGGED_MESSAGES_ARB */: return "GL_MAX_DEBUG_LOGGED_MESSAGES_ARB (0x9144)";
+//case 0x9145 /* GL_DEBUG_LOGGED_MESSAGES_ARB */: return "GL_DEBUG_LOGGED_MESSAGES_ARB (0x9145)";
+//case 0x9146 /* GL_DEBUG_SEVERITY_HIGH_ARB */: return "GL_DEBUG_SEVERITY_HIGH_ARB (0x9146)";
+//case 0x9147 /* GL_DEBUG_SEVERITY_MEDIUM_ARB */: return "GL_DEBUG_SEVERITY_MEDIUM_ARB (0x9147)";
+//case 0x9148 /* GL_DEBUG_SEVERITY_LOW_ARB */: return "GL_DEBUG_SEVERITY_LOW_ARB (0x9148)";
+
+
+
+
+
+
+
+/* ----------------------- GL_ARB_depth_buffer_float ----------------------- */
+
+
+
+
+case 0x8CAC /* GL_DEPTH_COMPONENT32F */: return "GL_DEPTH_COMPONENT32F (0x8CAC)";
+case 0x8CAD /* GL_DEPTH32F_STENCIL8 */: return "GL_DEPTH32F_STENCIL8 (0x8CAD)";
+case 0x8DAD /* GL_FLOAT_32_UNSIGNED_INT_24_8_REV */: return "GL_FLOAT_32_UNSIGNED_INT_24_8_REV (0x8DAD)";
+
+
+
+
+
+/* --------------------------- GL_ARB_depth_clamp -------------------------- */
+
+
+
+
+case 0x864F /* GL_DEPTH_CLAMP */: return "GL_DEPTH_CLAMP (0x864F)";
+
+
+
+
+
+/* -------------------------- GL_ARB_depth_texture ------------------------- */
+
+
+
+
+//case 0x81A5 /* GL_DEPTH_COMPONENT16_ARB */: return "GL_DEPTH_COMPONENT16_ARB (0x81A5)";
+//case 0x81A6 /* GL_DEPTH_COMPONENT24_ARB */: return "GL_DEPTH_COMPONENT24_ARB (0x81A6)";
+//case 0x81A7 /* GL_DEPTH_COMPONENT32_ARB */: return "GL_DEPTH_COMPONENT32_ARB (0x81A7)";
+//case 0x884A /* GL_TEXTURE_DEPTH_SIZE_ARB */: return "GL_TEXTURE_DEPTH_SIZE_ARB (0x884A)";
+//case 0x884B /* GL_DEPTH_TEXTURE_MODE_ARB */: return "GL_DEPTH_TEXTURE_MODE_ARB (0x884B)";
+
+
+
+
+
+/* -------------------------- GL_ARB_draw_buffers -------------------------- */
+
+
+
+
+//case 0x8824 /* GL_MAX_DRAW_BUFFERS_ARB */: return "GL_MAX_DRAW_BUFFERS_ARB (0x8824)";
+//case 0x8825 /* GL_DRAW_BUFFER0_ARB */: return "GL_DRAW_BUFFER0_ARB (0x8825)";
+//case 0x8826 /* GL_DRAW_BUFFER1_ARB */: return "GL_DRAW_BUFFER1_ARB (0x8826)";
+//case 0x8827 /* GL_DRAW_BUFFER2_ARB */: return "GL_DRAW_BUFFER2_ARB (0x8827)";
+//case 0x8828 /* GL_DRAW_BUFFER3_ARB */: return "GL_DRAW_BUFFER3_ARB (0x8828)";
+//case 0x8829 /* GL_DRAW_BUFFER4_ARB */: return "GL_DRAW_BUFFER4_ARB (0x8829)";
+//case 0x882A /* GL_DRAW_BUFFER5_ARB */: return "GL_DRAW_BUFFER5_ARB (0x882A)";
+//case 0x882B /* GL_DRAW_BUFFER6_ARB */: return "GL_DRAW_BUFFER6_ARB (0x882B)";
+//case 0x882C /* GL_DRAW_BUFFER7_ARB */: return "GL_DRAW_BUFFER7_ARB (0x882C)";
+//case 0x882D /* GL_DRAW_BUFFER8_ARB */: return "GL_DRAW_BUFFER8_ARB (0x882D)";
+//case 0x882E /* GL_DRAW_BUFFER9_ARB */: return "GL_DRAW_BUFFER9_ARB (0x882E)";
+//case 0x882F /* GL_DRAW_BUFFER10_ARB */: return "GL_DRAW_BUFFER10_ARB (0x882F)";
+//case 0x8830 /* GL_DRAW_BUFFER11_ARB */: return "GL_DRAW_BUFFER11_ARB (0x8830)";
+//case 0x8831 /* GL_DRAW_BUFFER12_ARB */: return "GL_DRAW_BUFFER12_ARB (0x8831)";
+//case 0x8832 /* GL_DRAW_BUFFER13_ARB */: return "GL_DRAW_BUFFER13_ARB (0x8832)";
+//case 0x8833 /* GL_DRAW_BUFFER14_ARB */: return "GL_DRAW_BUFFER14_ARB (0x8833)";
+//case 0x8834 /* GL_DRAW_BUFFER15_ARB */: return "GL_DRAW_BUFFER15_ARB (0x8834)";
+	/* ----------------------- GL_ARB_draw_buffers_blend ----------------------- */
+
+
+
+
+
+
+
+
+/* -------------------- GL_ARB_draw_elements_base_vertex ------------------- */
+
+
+
+
+
+
+
+
+/* -------------------------- GL_ARB_draw_indirect ------------------------- */
+
+
+
+
+case 0x8F3F /* GL_DRAW_INDIRECT_BUFFER */: return "GL_DRAW_INDIRECT_BUFFER (0x8F3F)";
+case 0x8F43 /* GL_DRAW_INDIRECT_BUFFER_BINDING */: return "GL_DRAW_INDIRECT_BUFFER_BINDING (0x8F43)";
+
+/* ------------------------- GL_ARB_draw_instanced ------------------------- */
+
+
+
+
+
+
+
+
+/* -------------------- GL_ARB_explicit_attrib_location -------------------- */
+
+
+
+
+
+
+
+
+/* -------------------- GL_ARB_explicit_uniform_location ------------------- */
+
+
+
+
+case 0x826E /* GL_MAX_UNIFORM_LOCATIONS */: return "GL_MAX_UNIFORM_LOCATIONS (0x826E)";
+
+
+
+
+
+/* ------------------- GL_ARB_fragment_coord_conventions ------------------- */
+
+
+
+
+
+
+
+
+/* --------------------- GL_ARB_fragment_layer_viewport -------------------- */
+
+
+
+
+
+
+
+
+/* ------------------------ GL_ARB_fragment_program ------------------------ */
+
+
+
+
+case 0x8804 /* GL_FRAGMENT_PROGRAM_ARB */: return "GL_FRAGMENT_PROGRAM_ARB (0x8804)";
+case 0x8807 /* GL_PROGRAM_TEX_INDIRECTIONS_ARB */: return "GL_PROGRAM_TEX_INDIRECTIONS_ARB (0x8807)";
+case 0x880A /* GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB */: return "GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB (0x880A)";
+case 0x880D /* GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB */: return "GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB (0x880D)";
+case 0x8810 /* GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB */: return "GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB (0x8810)";
+//case 0x8871 /* GL_MAX_TEXTURE_COORDS_ARB */: return "GL_MAX_TEXTURE_COORDS_ARB (0x8871)";
+//case 0x8872 /* GL_MAX_TEXTURE_IMAGE_UNITS_ARB */: return "GL_MAX_TEXTURE_IMAGE_UNITS_ARB (0x8872)";
+
+
+
+
+
+/* --------------------- GL_ARB_fragment_program_shadow -------------------- */
+
+
+
+
+
+
+
+
+/* ------------------------- GL_ARB_fragment_shader ------------------------ */
+
+
+
+
+//case 0x8B30 /* GL_FRAGMENT_SHADER_ARB */: return "GL_FRAGMENT_SHADER_ARB (0x8B30)";
+//case 0x8B49 /* GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB */: return "GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB (0x8B49)";
+//case 0x8B8B /* GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB */: return "GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB (0x8B8B)";
+
+
+
+
+
+/* ------------------- GL_ARB_framebuffer_no_attachments ------------------- */
+
+
+
+
+case 0x9310 /* GL_FRAMEBUFFER_DEFAULT_WIDTH */: return "GL_FRAMEBUFFER_DEFAULT_WIDTH (0x9310)";
+case 0x9311 /* GL_FRAMEBUFFER_DEFAULT_HEIGHT */: return "GL_FRAMEBUFFER_DEFAULT_HEIGHT (0x9311)";
+case 0x9312 /* GL_FRAMEBUFFER_DEFAULT_LAYERS */: return "GL_FRAMEBUFFER_DEFAULT_LAYERS (0x9312)";
+case 0x9313 /* GL_FRAMEBUFFER_DEFAULT_SAMPLES */: return "GL_FRAMEBUFFER_DEFAULT_SAMPLES (0x9313)";
+case 0x9314 /* GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS */: return "GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS (0x9314)";
+case 0x9315 /* GL_MAX_FRAMEBUFFER_WIDTH */: return "GL_MAX_FRAMEBUFFER_WIDTH (0x9315)";
+case 0x9316 /* GL_MAX_FRAMEBUFFER_HEIGHT */: return "GL_MAX_FRAMEBUFFER_HEIGHT (0x9316)";
+case 0x9317 /* GL_MAX_FRAMEBUFFER_LAYERS */: return "GL_MAX_FRAMEBUFFER_LAYERS (0x9317)";
+case 0x9318 /* GL_MAX_FRAMEBUFFER_SAMPLES */: return "GL_MAX_FRAMEBUFFER_SAMPLES (0x9318)";
+
+
+
+
+
+/* ----------------------- GL_ARB_framebuffer_object ----------------------- */
+
+
+
+
+case 0x0506 /* GL_INVALID_FRAMEBUFFER_OPERATION */: return "GL_INVALID_FRAMEBUFFER_OPERATION (0x0506)";
+case 0x8210 /* GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING */: return "GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING (0x8210)";
+case 0x8211 /* GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE */: return "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE (0x8211)";
+case 0x8212 /* GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE */: return "GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE (0x8212)";
+case 0x8213 /* GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE */: return "GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE (0x8213)";
+case 0x8214 /* GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE */: return "GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE (0x8214)";
+case 0x8215 /* GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE */: return "GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE (0x8215)";
+case 0x8216 /* GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE */: return "GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE (0x8216)";
+case 0x8217 /* GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE */: return "GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE (0x8217)";
+case 0x8218 /* GL_FRAMEBUFFER_DEFAULT */: return "GL_FRAMEBUFFER_DEFAULT (0x8218)";
+case 0x8219 /* GL_FRAMEBUFFER_UNDEFINED */: return "GL_FRAMEBUFFER_UNDEFINED (0x8219)";
+case 0x821A /* GL_DEPTH_STENCIL_ATTACHMENT */: return "GL_DEPTH_STENCIL_ATTACHMENT (0x821A)";
+case 0x8222 /* GL_INDEX */: return "GL_INDEX (0x8222)";
+case 0x84E8 /* GL_MAX_RENDERBUFFER_SIZE */: return "GL_MAX_RENDERBUFFER_SIZE (0x84E8)";
+case 0x84F9 /* GL_DEPTH_STENCIL */: return "GL_DEPTH_STENCIL (0x84F9)";
+case 0x84FA /* GL_UNSIGNED_INT_24_8 */: return "GL_UNSIGNED_INT_24_8 (0x84FA)";
+case 0x88F0 /* GL_DEPTH24_STENCIL8 */: return "GL_DEPTH24_STENCIL8 (0x88F0)";
+case 0x88F1 /* GL_TEXTURE_STENCIL_SIZE */: return "GL_TEXTURE_STENCIL_SIZE (0x88F1)";
+case 0x8C17 /* GL_UNSIGNED_NORMALIZED */: return "GL_UNSIGNED_NORMALIZED (0x8C17)";
+//case 0x8C40 /* GL_SRGB */: return "GL_SRGB (0x8C40)";
+//case 0x8CA6 /* GL_DRAW_FRAMEBUFFER_BINDING */: return "GL_DRAW_FRAMEBUFFER_BINDING (0x8CA6)";
+case 0x8CA6 /* GL_FRAMEBUFFER_BINDING */: return "GL_FRAMEBUFFER_BINDING (0x8CA6)";
+case 0x8CA7 /* GL_RENDERBUFFER_BINDING */: return "GL_RENDERBUFFER_BINDING (0x8CA7)";
+case 0x8CA8 /* GL_READ_FRAMEBUFFER */: return "GL_READ_FRAMEBUFFER (0x8CA8)";
+case 0x8CA9 /* GL_DRAW_FRAMEBUFFER */: return "GL_DRAW_FRAMEBUFFER (0x8CA9)";
+case 0x8CAA /* GL_READ_FRAMEBUFFER_BINDING */: return "GL_READ_FRAMEBUFFER_BINDING (0x8CAA)";
+case 0x8CAB /* GL_RENDERBUFFER_SAMPLES */: return "GL_RENDERBUFFER_SAMPLES (0x8CAB)";
+case 0x8CD0 /* GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE */: return "GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE (0x8CD0)";
+case 0x8CD1 /* GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME */: return "GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME (0x8CD1)";
+case 0x8CD2 /* GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL */: return "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL (0x8CD2)";
+case 0x8CD3 /* GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE */: return "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE (0x8CD3)";
+case 0x8CD4 /* GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */: return "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER (0x8CD4)";
+case 0x8CD5 /* GL_FRAMEBUFFER_COMPLETE */: return "GL_FRAMEBUFFER_COMPLETE (0x8CD5)";
+case 0x8CD6 /* GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT */: return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT (0x8CD6)";
+case 0x8CD7 /* GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT */: return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT (0x8CD7)";
+case 0x8CDB /* GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER */: return "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER (0x8CDB)";
+case 0x8CDC /* GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER */: return "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER (0x8CDC)";
+case 0x8CDD /* GL_FRAMEBUFFER_UNSUPPORTED */: return "GL_FRAMEBUFFER_UNSUPPORTED (0x8CDD)";
+case 0x8CDF /* GL_MAX_COLOR_ATTACHMENTS */: return "GL_MAX_COLOR_ATTACHMENTS (0x8CDF)";
+case 0x8CE0 /* GL_COLOR_ATTACHMENT0 */: return "GL_COLOR_ATTACHMENT0 (0x8CE0)";
+case 0x8CE1 /* GL_COLOR_ATTACHMENT1 */: return "GL_COLOR_ATTACHMENT1 (0x8CE1)";
+case 0x8CE2 /* GL_COLOR_ATTACHMENT2 */: return "GL_COLOR_ATTACHMENT2 (0x8CE2)";
+case 0x8CE3 /* GL_COLOR_ATTACHMENT3 */: return "GL_COLOR_ATTACHMENT3 (0x8CE3)";
+case 0x8CE4 /* GL_COLOR_ATTACHMENT4 */: return "GL_COLOR_ATTACHMENT4 (0x8CE4)";
+case 0x8CE5 /* GL_COLOR_ATTACHMENT5 */: return "GL_COLOR_ATTACHMENT5 (0x8CE5)";
+case 0x8CE6 /* GL_COLOR_ATTACHMENT6 */: return "GL_COLOR_ATTACHMENT6 (0x8CE6)";
+case 0x8CE7 /* GL_COLOR_ATTACHMENT7 */: return "GL_COLOR_ATTACHMENT7 (0x8CE7)";
+case 0x8CE8 /* GL_COLOR_ATTACHMENT8 */: return "GL_COLOR_ATTACHMENT8 (0x8CE8)";
+case 0x8CE9 /* GL_COLOR_ATTACHMENT9 */: return "GL_COLOR_ATTACHMENT9 (0x8CE9)";
+case 0x8CEA /* GL_COLOR_ATTACHMENT10 */: return "GL_COLOR_ATTACHMENT10 (0x8CEA)";
+case 0x8CEB /* GL_COLOR_ATTACHMENT11 */: return "GL_COLOR_ATTACHMENT11 (0x8CEB)";
+case 0x8CEC /* GL_COLOR_ATTACHMENT12 */: return "GL_COLOR_ATTACHMENT12 (0x8CEC)";
+case 0x8CED /* GL_COLOR_ATTACHMENT13 */: return "GL_COLOR_ATTACHMENT13 (0x8CED)";
+case 0x8CEE /* GL_COLOR_ATTACHMENT14 */: return "GL_COLOR_ATTACHMENT14 (0x8CEE)";
+case 0x8CEF /* GL_COLOR_ATTACHMENT15 */: return "GL_COLOR_ATTACHMENT15 (0x8CEF)";
+case 0x8D00 /* GL_DEPTH_ATTACHMENT */: return "GL_DEPTH_ATTACHMENT (0x8D00)";
+case 0x8D20 /* GL_STENCIL_ATTACHMENT */: return "GL_STENCIL_ATTACHMENT (0x8D20)";
+case 0x8D40 /* GL_FRAMEBUFFER */: return "GL_FRAMEBUFFER (0x8D40)";
+case 0x8D41 /* GL_RENDERBUFFER */: return "GL_RENDERBUFFER (0x8D41)";
+case 0x8D42 /* GL_RENDERBUFFER_WIDTH */: return "GL_RENDERBUFFER_WIDTH (0x8D42)";
+case 0x8D43 /* GL_RENDERBUFFER_HEIGHT */: return "GL_RENDERBUFFER_HEIGHT (0x8D43)";
+case 0x8D44 /* GL_RENDERBUFFER_INTERNAL_FORMAT */: return "GL_RENDERBUFFER_INTERNAL_FORMAT (0x8D44)";
+case 0x8D46 /* GL_STENCIL_INDEX1 */: return "GL_STENCIL_INDEX1 (0x8D46)";
+case 0x8D47 /* GL_STENCIL_INDEX4 */: return "GL_STENCIL_INDEX4 (0x8D47)";
+case 0x8D48 /* GL_STENCIL_INDEX8 */: return "GL_STENCIL_INDEX8 (0x8D48)";
+case 0x8D49 /* GL_STENCIL_INDEX16 */: return "GL_STENCIL_INDEX16 (0x8D49)";
+case 0x8D50 /* GL_RENDERBUFFER_RED_SIZE */: return "GL_RENDERBUFFER_RED_SIZE (0x8D50)";
+case 0x8D51 /* GL_RENDERBUFFER_GREEN_SIZE */: return "GL_RENDERBUFFER_GREEN_SIZE (0x8D51)";
+case 0x8D52 /* GL_RENDERBUFFER_BLUE_SIZE */: return "GL_RENDERBUFFER_BLUE_SIZE (0x8D52)";
+case 0x8D53 /* GL_RENDERBUFFER_ALPHA_SIZE */: return "GL_RENDERBUFFER_ALPHA_SIZE (0x8D53)";
+case 0x8D54 /* GL_RENDERBUFFER_DEPTH_SIZE */: return "GL_RENDERBUFFER_DEPTH_SIZE (0x8D54)";
+case 0x8D55 /* GL_RENDERBUFFER_STENCIL_SIZE */: return "GL_RENDERBUFFER_STENCIL_SIZE (0x8D55)";
+case 0x8D56 /* GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE */: return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE (0x8D56)";
+case 0x8D57 /* GL_MAX_SAMPLES */: return "GL_MAX_SAMPLES (0x8D57)";
+
+
+
+
+
+
+
+/* ------------------------ GL_ARB_framebuffer_sRGB ------------------------ */
+
+
+
+
+case 0x8DB9 /* GL_FRAMEBUFFER_SRGB */: return "GL_FRAMEBUFFER_SRGB (0x8DB9)";
+
+
+
+
+
+/* ------------------------ GL_ARB_geometry_shader4 ------------------------ */
+
+
+
+
+//case 0xA /* GL_LINES_ADJACENCY_ARB */: return "GL_LINES_ADJACENCY_ARB (0xA)";
+//case 0xB /* GL_LINE_STRIP_ADJACENCY_ARB */: return "GL_LINE_STRIP_ADJACENCY_ARB (0xB)";
+//case 0xC /* GL_TRIANGLES_ADJACENCY_ARB */: return "GL_TRIANGLES_ADJACENCY_ARB (0xC)";
+//case 0xD /* GL_TRIANGLE_STRIP_ADJACENCY_ARB */: return "GL_TRIANGLE_STRIP_ADJACENCY_ARB (0xD)";
+//case 0x8C29 /* GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB */: return "GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB (0x8C29)";
+//case 0x8CD4 /* GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */: return "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER (0x8CD4)";
+//case 0x8DA7 /* GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB */: return "GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB (0x8DA7)";
+//case 0x8DA8 /* GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB */: return "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB (0x8DA8)";
+case 0x8DA9 /* GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB */: return "GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB (0x8DA9)";
+//case 0x8DD9 /* GL_GEOMETRY_SHADER_ARB */: return "GL_GEOMETRY_SHADER_ARB (0x8DD9)";
+case 0x8DDA /* GL_GEOMETRY_VERTICES_OUT_ARB */: return "GL_GEOMETRY_VERTICES_OUT_ARB (0x8DDA)";
+case 0x8DDB /* GL_GEOMETRY_INPUT_TYPE_ARB */: return "GL_GEOMETRY_INPUT_TYPE_ARB (0x8DDB)";
+case 0x8DDC /* GL_GEOMETRY_OUTPUT_TYPE_ARB */: return "GL_GEOMETRY_OUTPUT_TYPE_ARB (0x8DDC)";
+case 0x8DDD /* GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB */: return "GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB (0x8DDD)";
+case 0x8DDE /* GL_MAX_VERTEX_VARYING_COMPONENTS_ARB */: return "GL_MAX_VERTEX_VARYING_COMPONENTS_ARB (0x8DDE)";
+//case 0x8DDF /* GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB */: return "GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB (0x8DDF)";
+//case 0x8DE0 /* GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB */: return "GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB (0x8DE0)";
+//case 0x8DE1 /* GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB */: return "GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB (0x8DE1)";
+
+
+
+
+
+/* ----------------------- GL_ARB_get_program_binary ----------------------- */
+
+
+
+
+case 0x8257 /* GL_PROGRAM_BINARY_RETRIEVABLE_HINT */: return "GL_PROGRAM_BINARY_RETRIEVABLE_HINT (0x8257)";
+case 0x8741 /* GL_PROGRAM_BINARY_LENGTH */: return "GL_PROGRAM_BINARY_LENGTH (0x8741)";
+case 0x87FE /* GL_NUM_PROGRAM_BINARY_FORMATS */: return "GL_NUM_PROGRAM_BINARY_FORMATS (0x87FE)";
+case 0x87FF /* GL_PROGRAM_BINARY_FORMATS */: return "GL_PROGRAM_BINARY_FORMATS (0x87FF)";
+
+
+
+/* --------------------------- GL_ARB_gpu_shader5 -------------------------- */
+
+
+
+
+//case 0x887F /* GL_GEOMETRY_SHADER_INVOCATIONS */: return "GL_GEOMETRY_SHADER_INVOCATIONS (0x887F)";
+//case 0x8E5A /* GL_MAX_GEOMETRY_SHADER_INVOCATIONS */: return "GL_MAX_GEOMETRY_SHADER_INVOCATIONS (0x8E5A)";
+//case 0x8E5B /* GL_MIN_FRAGMENT_INTERPOLATION_OFFSET */: return "GL_MIN_FRAGMENT_INTERPOLATION_OFFSET (0x8E5B)";
+//case 0x8E5C /* GL_MAX_FRAGMENT_INTERPOLATION_OFFSET */: return "GL_MAX_FRAGMENT_INTERPOLATION_OFFSET (0x8E5C)";
+//case 0x8E5D /* GL_FRAGMENT_INTERPOLATION_OFFSET_BITS */: return "GL_FRAGMENT_INTERPOLATION_OFFSET_BITS (0x8E5D)";
+case 0x8E71 /* GL_MAX_VERTEX_STREAMS */: return "GL_MAX_VERTEX_STREAMS (0x8E71)";
+
+
+
+
+
+/* ------------------------- GL_ARB_gpu_shader_fp64 ------------------------ */
+
+
+
+
+case 0x8F46 /* GL_DOUBLE_MAT2 */: return "GL_DOUBLE_MAT2 (0x8F46)";
+case 0x8F47 /* GL_DOUBLE_MAT3 */: return "GL_DOUBLE_MAT3 (0x8F47)";
+case 0x8F48 /* GL_DOUBLE_MAT4 */: return "GL_DOUBLE_MAT4 (0x8F48)";
+case 0x8F49 /* GL_DOUBLE_MAT2x3 */: return "GL_DOUBLE_MAT2x3 (0x8F49)";
+case 0x8F4A /* GL_DOUBLE_MAT2x4 */: return "GL_DOUBLE_MAT2x4 (0x8F4A)";
+case 0x8F4B /* GL_DOUBLE_MAT3x2 */: return "GL_DOUBLE_MAT3x2 (0x8F4B)";
+case 0x8F4C /* GL_DOUBLE_MAT3x4 */: return "GL_DOUBLE_MAT3x4 (0x8F4C)";
+case 0x8F4D /* GL_DOUBLE_MAT4x2 */: return "GL_DOUBLE_MAT4x2 (0x8F4D)";
+case 0x8F4E /* GL_DOUBLE_MAT4x3 */: return "GL_DOUBLE_MAT4x3 (0x8F4E)";
+case 0x8FFC /* GL_DOUBLE_VEC2 */: return "GL_DOUBLE_VEC2 (0x8FFC)";
+case 0x8FFD /* GL_DOUBLE_VEC3 */: return "GL_DOUBLE_VEC3 (0x8FFD)";
+case 0x8FFE /* GL_DOUBLE_VEC4 */: return "GL_DOUBLE_VEC4 (0x8FFE)";
+
+
+
+/* ------------------------ GL_ARB_half_float_pixel ------------------------ */
+
+
+
+
+//case 0x140B /* GL_HALF_FLOAT_ARB */: return "GL_HALF_FLOAT_ARB (0x140B)";
+
+
+
+
+
+/* ------------------------ GL_ARB_half_float_vertex ----------------------- */
+
+
+
+
+case 0x140B /* GL_HALF_FLOAT */: return "GL_HALF_FLOAT (0x140B)";
+
+
+
+
+
+/* ----------------------------- GL_ARB_imaging ---------------------------- */
+
+
+
+
+case 0x8001 /* GL_CONSTANT_COLOR */: return "GL_CONSTANT_COLOR (0x8001)";
+case 0x8002 /* GL_ONE_MINUS_CONSTANT_COLOR */: return "GL_ONE_MINUS_CONSTANT_COLOR (0x8002)";
+case 0x8003 /* GL_CONSTANT_ALPHA */: return "GL_CONSTANT_ALPHA (0x8003)";
+case 0x8004 /* GL_ONE_MINUS_CONSTANT_ALPHA */: return "GL_ONE_MINUS_CONSTANT_ALPHA (0x8004)";
+case 0x8005 /* GL_BLEND_COLOR */: return "GL_BLEND_COLOR (0x8005)";
+case 0x8006 /* GL_FUNC_ADD */: return "GL_FUNC_ADD (0x8006)";
+case 0x8007 /* GL_MIN */: return "GL_MIN (0x8007)";
+case 0x8008 /* GL_MAX */: return "GL_MAX (0x8008)";
+case 0x8009 /* GL_BLEND_EQUATION */: return "GL_BLEND_EQUATION (0x8009)";
+case 0x800A /* GL_FUNC_SUBTRACT */: return "GL_FUNC_SUBTRACT (0x800A)";
+case 0x800B /* GL_FUNC_REVERSE_SUBTRACT */: return "GL_FUNC_REVERSE_SUBTRACT (0x800B)";
+case 0x8010 /* GL_CONVOLUTION_1D */: return "GL_CONVOLUTION_1D (0x8010)";
+case 0x8011 /* GL_CONVOLUTION_2D */: return "GL_CONVOLUTION_2D (0x8011)";
+case 0x8012 /* GL_SEPARABLE_2D */: return "GL_SEPARABLE_2D (0x8012)";
+case 0x8013 /* GL_CONVOLUTION_BORDER_MODE */: return "GL_CONVOLUTION_BORDER_MODE (0x8013)";
+case 0x8014 /* GL_CONVOLUTION_FILTER_SCALE */: return "GL_CONVOLUTION_FILTER_SCALE (0x8014)";
+case 0x8015 /* GL_CONVOLUTION_FILTER_BIAS */: return "GL_CONVOLUTION_FILTER_BIAS (0x8015)";
+case 0x8016 /* GL_REDUCE */: return "GL_REDUCE (0x8016)";
+case 0x8017 /* GL_CONVOLUTION_FORMAT */: return "GL_CONVOLUTION_FORMAT (0x8017)";
+case 0x8018 /* GL_CONVOLUTION_WIDTH */: return "GL_CONVOLUTION_WIDTH (0x8018)";
+case 0x8019 /* GL_CONVOLUTION_HEIGHT */: return "GL_CONVOLUTION_HEIGHT (0x8019)";
+case 0x801A /* GL_MAX_CONVOLUTION_WIDTH */: return "GL_MAX_CONVOLUTION_WIDTH (0x801A)";
+case 0x801B /* GL_MAX_CONVOLUTION_HEIGHT */: return "GL_MAX_CONVOLUTION_HEIGHT (0x801B)";
+case 0x801C /* GL_POST_CONVOLUTION_RED_SCALE */: return "GL_POST_CONVOLUTION_RED_SCALE (0x801C)";
+case 0x801D /* GL_POST_CONVOLUTION_GREEN_SCALE */: return "GL_POST_CONVOLUTION_GREEN_SCALE (0x801D)";
+case 0x801E /* GL_POST_CONVOLUTION_BLUE_SCALE */: return "GL_POST_CONVOLUTION_BLUE_SCALE (0x801E)";
+case 0x801F /* GL_POST_CONVOLUTION_ALPHA_SCALE */: return "GL_POST_CONVOLUTION_ALPHA_SCALE (0x801F)";
+case 0x8020 /* GL_POST_CONVOLUTION_RED_BIAS */: return "GL_POST_CONVOLUTION_RED_BIAS (0x8020)";
+case 0x8021 /* GL_POST_CONVOLUTION_GREEN_BIAS */: return "GL_POST_CONVOLUTION_GREEN_BIAS (0x8021)";
+case 0x8022 /* GL_POST_CONVOLUTION_BLUE_BIAS */: return "GL_POST_CONVOLUTION_BLUE_BIAS (0x8022)";
+case 0x8023 /* GL_POST_CONVOLUTION_ALPHA_BIAS */: return "GL_POST_CONVOLUTION_ALPHA_BIAS (0x8023)";
+case 0x8024 /* GL_HISTOGRAM */: return "GL_HISTOGRAM (0x8024)";
+case 0x8025 /* GL_PROXY_HISTOGRAM */: return "GL_PROXY_HISTOGRAM (0x8025)";
+case 0x8026 /* GL_HISTOGRAM_WIDTH */: return "GL_HISTOGRAM_WIDTH (0x8026)";
+case 0x8027 /* GL_HISTOGRAM_FORMAT */: return "GL_HISTOGRAM_FORMAT (0x8027)";
+case 0x8028 /* GL_HISTOGRAM_RED_SIZE */: return "GL_HISTOGRAM_RED_SIZE (0x8028)";
+case 0x8029 /* GL_HISTOGRAM_GREEN_SIZE */: return "GL_HISTOGRAM_GREEN_SIZE (0x8029)";
+case 0x802A /* GL_HISTOGRAM_BLUE_SIZE */: return "GL_HISTOGRAM_BLUE_SIZE (0x802A)";
+case 0x802B /* GL_HISTOGRAM_ALPHA_SIZE */: return "GL_HISTOGRAM_ALPHA_SIZE (0x802B)";
+case 0x802C /* GL_HISTOGRAM_LUMINANCE_SIZE */: return "GL_HISTOGRAM_LUMINANCE_SIZE (0x802C)";
+case 0x802D /* GL_HISTOGRAM_SINK */: return "GL_HISTOGRAM_SINK (0x802D)";
+case 0x802E /* GL_MINMAX */: return "GL_MINMAX (0x802E)";
+case 0x802F /* GL_MINMAX_FORMAT */: return "GL_MINMAX_FORMAT (0x802F)";
+case 0x8030 /* GL_MINMAX_SINK */: return "GL_MINMAX_SINK (0x8030)";
+case 0x8031 /* GL_TABLE_TOO_LARGE */: return "GL_TABLE_TOO_LARGE (0x8031)";
+case 0x80B1 /* GL_COLOR_MATRIX */: return "GL_COLOR_MATRIX (0x80B1)";
+case 0x80B2 /* GL_COLOR_MATRIX_STACK_DEPTH */: return "GL_COLOR_MATRIX_STACK_DEPTH (0x80B2)";
+case 0x80B3 /* GL_MAX_COLOR_MATRIX_STACK_DEPTH */: return "GL_MAX_COLOR_MATRIX_STACK_DEPTH (0x80B3)";
+case 0x80B4 /* GL_POST_COLOR_MATRIX_RED_SCALE */: return "GL_POST_COLOR_MATRIX_RED_SCALE (0x80B4)";
+case 0x80B5 /* GL_POST_COLOR_MATRIX_GREEN_SCALE */: return "GL_POST_COLOR_MATRIX_GREEN_SCALE (0x80B5)";
+case 0x80B6 /* GL_POST_COLOR_MATRIX_BLUE_SCALE */: return "GL_POST_COLOR_MATRIX_BLUE_SCALE (0x80B6)";
+case 0x80B7 /* GL_POST_COLOR_MATRIX_ALPHA_SCALE */: return "GL_POST_COLOR_MATRIX_ALPHA_SCALE (0x80B7)";
+case 0x80B8 /* GL_POST_COLOR_MATRIX_RED_BIAS */: return "GL_POST_COLOR_MATRIX_RED_BIAS (0x80B8)";
+case 0x80B9 /* GL_POST_COLOR_MATRIX_GREEN_BIAS */: return "GL_POST_COLOR_MATRIX_GREEN_BIAS (0x80B9)";
+case 0x80BA /* GL_POST_COLOR_MATRIX_BLUE_BIAS */: return "GL_POST_COLOR_MATRIX_BLUE_BIAS (0x80BA)";
+case 0x80BB /* GL_POST_COLOR_MATRIX_ALPHA_BIAS */: return "GL_POST_COLOR_MATRIX_ALPHA_BIAS (0x80BB)";
+case 0x80D0 /* GL_COLOR_TABLE */: return "GL_COLOR_TABLE (0x80D0)";
+case 0x80D1 /* GL_POST_CONVOLUTION_COLOR_TABLE */: return "GL_POST_CONVOLUTION_COLOR_TABLE (0x80D1)";
+case 0x80D2 /* GL_POST_COLOR_MATRIX_COLOR_TABLE */: return "GL_POST_COLOR_MATRIX_COLOR_TABLE (0x80D2)";
+case 0x80D3 /* GL_PROXY_COLOR_TABLE */: return "GL_PROXY_COLOR_TABLE (0x80D3)";
+case 0x80D4 /* GL_PROXY_POST_CONVOLUTION_COLOR_TABLE */: return "GL_PROXY_POST_CONVOLUTION_COLOR_TABLE (0x80D4)";
+case 0x80D5 /* GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE */: return "GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE (0x80D5)";
+case 0x80D6 /* GL_COLOR_TABLE_SCALE */: return "GL_COLOR_TABLE_SCALE (0x80D6)";
+case 0x80D7 /* GL_COLOR_TABLE_BIAS */: return "GL_COLOR_TABLE_BIAS (0x80D7)";
+case 0x80D8 /* GL_COLOR_TABLE_FORMAT */: return "GL_COLOR_TABLE_FORMAT (0x80D8)";
+case 0x80D9 /* GL_COLOR_TABLE_WIDTH */: return "GL_COLOR_TABLE_WIDTH (0x80D9)";
+case 0x80DA /* GL_COLOR_TABLE_RED_SIZE */: return "GL_COLOR_TABLE_RED_SIZE (0x80DA)";
+case 0x80DB /* GL_COLOR_TABLE_GREEN_SIZE */: return "GL_COLOR_TABLE_GREEN_SIZE (0x80DB)";
+case 0x80DC /* GL_COLOR_TABLE_BLUE_SIZE */: return "GL_COLOR_TABLE_BLUE_SIZE (0x80DC)";
+case 0x80DD /* GL_COLOR_TABLE_ALPHA_SIZE */: return "GL_COLOR_TABLE_ALPHA_SIZE (0x80DD)";
+case 0x80DE /* GL_COLOR_TABLE_LUMINANCE_SIZE */: return "GL_COLOR_TABLE_LUMINANCE_SIZE (0x80DE)";
+case 0x80DF /* GL_COLOR_TABLE_INTENSITY_SIZE */: return "GL_COLOR_TABLE_INTENSITY_SIZE (0x80DF)";
+case 0x8150 /* GL_IGNORE_BORDER */: return "GL_IGNORE_BORDER (0x8150)";
+case 0x8151 /* GL_CONSTANT_BORDER */: return "GL_CONSTANT_BORDER (0x8151)";
+case 0x8152 /* GL_WRAP_BORDER */: return "GL_WRAP_BORDER (0x8152)";
+case 0x8153 /* GL_REPLICATE_BORDER */: return "GL_REPLICATE_BORDER (0x8153)";
+case 0x8154 /* GL_CONVOLUTION_BORDER_COLOR */: return "GL_CONVOLUTION_BORDER_COLOR (0x8154)";
+
+/* ------------------------ GL_ARB_instanced_arrays ------------------------ */
+
+
+
+
+//case 0x88FE /* GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB */: return "GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB (0x88FE)";
+
+
+
+/* ---------------------- GL_ARB_internalformat_query ---------------------- */
+
+
+
+
+case 0x9380 /* GL_NUM_SAMPLE_COUNTS */: return "GL_NUM_SAMPLE_COUNTS (0x9380)";/* ---------------------- GL_ARB_internalformat_query2 --------------------- */
+
+
+
+
+//case 0x0DE0 /* GL_TEXTURE_1D */: return "GL_TEXTURE_1D (0x0DE0)";
+//case 0x0DE1 /* GL_TEXTURE_2D */: return "GL_TEXTURE_2D (0x0DE1)";
+//case 0x806F /* GL_TEXTURE_3D */: return "GL_TEXTURE_3D (0x806F)";
+//case 0x80A9 /* GL_SAMPLES */: return "GL_SAMPLES (0x80A9)";
+case 0x826F /* GL_INTERNALFORMAT_SUPPORTED */: return "GL_INTERNALFORMAT_SUPPORTED (0x826F)";
+case 0x8270 /* GL_INTERNALFORMAT_PREFERRED */: return "GL_INTERNALFORMAT_PREFERRED (0x8270)";
+case 0x8271 /* GL_INTERNALFORMAT_RED_SIZE */: return "GL_INTERNALFORMAT_RED_SIZE (0x8271)";
+case 0x8272 /* GL_INTERNALFORMAT_GREEN_SIZE */: return "GL_INTERNALFORMAT_GREEN_SIZE (0x8272)";
+case 0x8273 /* GL_INTERNALFORMAT_BLUE_SIZE */: return "GL_INTERNALFORMAT_BLUE_SIZE (0x8273)";
+case 0x8274 /* GL_INTERNALFORMAT_ALPHA_SIZE */: return "GL_INTERNALFORMAT_ALPHA_SIZE (0x8274)";
+case 0x8275 /* GL_INTERNALFORMAT_DEPTH_SIZE */: return "GL_INTERNALFORMAT_DEPTH_SIZE (0x8275)";
+case 0x8276 /* GL_INTERNALFORMAT_STENCIL_SIZE */: return "GL_INTERNALFORMAT_STENCIL_SIZE (0x8276)";
+case 0x8277 /* GL_INTERNALFORMAT_SHARED_SIZE */: return "GL_INTERNALFORMAT_SHARED_SIZE (0x8277)";
+case 0x8278 /* GL_INTERNALFORMAT_RED_TYPE */: return "GL_INTERNALFORMAT_RED_TYPE (0x8278)";
+case 0x8279 /* GL_INTERNALFORMAT_GREEN_TYPE */: return "GL_INTERNALFORMAT_GREEN_TYPE (0x8279)";
+case 0x827A /* GL_INTERNALFORMAT_BLUE_TYPE */: return "GL_INTERNALFORMAT_BLUE_TYPE (0x827A)";
+case 0x827B /* GL_INTERNALFORMAT_ALPHA_TYPE */: return "GL_INTERNALFORMAT_ALPHA_TYPE (0x827B)";
+case 0x827C /* GL_INTERNALFORMAT_DEPTH_TYPE */: return "GL_INTERNALFORMAT_DEPTH_TYPE (0x827C)";
+case 0x827D /* GL_INTERNALFORMAT_STENCIL_TYPE */: return "GL_INTERNALFORMAT_STENCIL_TYPE (0x827D)";
+case 0x827E /* GL_MAX_WIDTH */: return "GL_MAX_WIDTH (0x827E)";
+case 0x827F /* GL_MAX_HEIGHT */: return "GL_MAX_HEIGHT (0x827F)";
+case 0x8280 /* GL_MAX_DEPTH */: return "GL_MAX_DEPTH (0x8280)";
+case 0x8281 /* GL_MAX_LAYERS */: return "GL_MAX_LAYERS (0x8281)";
+case 0x8282 /* GL_MAX_COMBINED_DIMENSIONS */: return "GL_MAX_COMBINED_DIMENSIONS (0x8282)";
+case 0x8283 /* GL_COLOR_COMPONENTS */: return "GL_COLOR_COMPONENTS (0x8283)";
+case 0x8284 /* GL_DEPTH_COMPONENTS */: return "GL_DEPTH_COMPONENTS (0x8284)";
+case 0x8285 /* GL_STENCIL_COMPONENTS */: return "GL_STENCIL_COMPONENTS (0x8285)";
+case 0x8286 /* GL_COLOR_RENDERABLE */: return "GL_COLOR_RENDERABLE (0x8286)";
+case 0x8287 /* GL_DEPTH_RENDERABLE */: return "GL_DEPTH_RENDERABLE (0x8287)";
+case 0x8288 /* GL_STENCIL_RENDERABLE */: return "GL_STENCIL_RENDERABLE (0x8288)";
+case 0x8289 /* GL_FRAMEBUFFER_RENDERABLE */: return "GL_FRAMEBUFFER_RENDERABLE (0x8289)";
+case 0x828A /* GL_FRAMEBUFFER_RENDERABLE_LAYERED */: return "GL_FRAMEBUFFER_RENDERABLE_LAYERED (0x828A)";
+case 0x828B /* GL_FRAMEBUFFER_BLEND */: return "GL_FRAMEBUFFER_BLEND (0x828B)";
+case 0x828C /* GL_READ_PIXELS */: return "GL_READ_PIXELS (0x828C)";
+case 0x828D /* GL_READ_PIXELS_FORMAT */: return "GL_READ_PIXELS_FORMAT (0x828D)";
+case 0x828E /* GL_READ_PIXELS_TYPE */: return "GL_READ_PIXELS_TYPE (0x828E)";
+case 0x828F /* GL_TEXTURE_IMAGE_FORMAT */: return "GL_TEXTURE_IMAGE_FORMAT (0x828F)";
+case 0x8290 /* GL_TEXTURE_IMAGE_TYPE */: return "GL_TEXTURE_IMAGE_TYPE (0x8290)";
+case 0x8291 /* GL_GET_TEXTURE_IMAGE_FORMAT */: return "GL_GET_TEXTURE_IMAGE_FORMAT (0x8291)";
+case 0x8292 /* GL_GET_TEXTURE_IMAGE_TYPE */: return "GL_GET_TEXTURE_IMAGE_TYPE (0x8292)";
+case 0x8293 /* GL_MIPMAP */: return "GL_MIPMAP (0x8293)";
+case 0x8294 /* GL_MANUAL_GENERATE_MIPMAP */: return "GL_MANUAL_GENERATE_MIPMAP (0x8294)";
+case 0x8295 /* GL_AUTO_GENERATE_MIPMAP */: return "GL_AUTO_GENERATE_MIPMAP (0x8295)";
+case 0x8296 /* GL_COLOR_ENCODING */: return "GL_COLOR_ENCODING (0x8296)";
+case 0x8297 /* GL_SRGB_READ */: return "GL_SRGB_READ (0x8297)";
+case 0x8298 /* GL_SRGB_WRITE */: return "GL_SRGB_WRITE (0x8298)";
+case 0x8299 /* GL_SRGB_DECODE_ARB */: return "GL_SRGB_DECODE_ARB (0x8299)";
+case 0x829A /* GL_FILTER */: return "GL_FILTER (0x829A)";
+case 0x829B /* GL_VERTEX_TEXTURE */: return "GL_VERTEX_TEXTURE (0x829B)";
+case 0x829C /* GL_TESS_CONTROL_TEXTURE */: return "GL_TESS_CONTROL_TEXTURE (0x829C)";
+case 0x829D /* GL_TESS_EVALUATION_TEXTURE */: return "GL_TESS_EVALUATION_TEXTURE (0x829D)";
+case 0x829E /* GL_GEOMETRY_TEXTURE */: return "GL_GEOMETRY_TEXTURE (0x829E)";
+case 0x829F /* GL_FRAGMENT_TEXTURE */: return "GL_FRAGMENT_TEXTURE (0x829F)";
+case 0x82A0 /* GL_COMPUTE_TEXTURE */: return "GL_COMPUTE_TEXTURE (0x82A0)";
+case 0x82A1 /* GL_TEXTURE_SHADOW */: return "GL_TEXTURE_SHADOW (0x82A1)";
+case 0x82A2 /* GL_TEXTURE_GATHER */: return "GL_TEXTURE_GATHER (0x82A2)";
+case 0x82A3 /* GL_TEXTURE_GATHER_SHADOW */: return "GL_TEXTURE_GATHER_SHADOW (0x82A3)";
+case 0x82A4 /* GL_SHADER_IMAGE_LOAD */: return "GL_SHADER_IMAGE_LOAD (0x82A4)";
+case 0x82A5 /* GL_SHADER_IMAGE_STORE */: return "GL_SHADER_IMAGE_STORE (0x82A5)";
+case 0x82A6 /* GL_SHADER_IMAGE_ATOMIC */: return "GL_SHADER_IMAGE_ATOMIC (0x82A6)";
+case 0x82A7 /* GL_IMAGE_TEXEL_SIZE */: return "GL_IMAGE_TEXEL_SIZE (0x82A7)";
+case 0x82A8 /* GL_IMAGE_COMPATIBILITY_CLASS */: return "GL_IMAGE_COMPATIBILITY_CLASS (0x82A8)";
+case 0x82A9 /* GL_IMAGE_PIXEL_FORMAT */: return "GL_IMAGE_PIXEL_FORMAT (0x82A9)";
+case 0x82AA /* GL_IMAGE_PIXEL_TYPE */: return "GL_IMAGE_PIXEL_TYPE (0x82AA)";
+case 0x82AC /* GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST */: return "GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST (0x82AC)";
+case 0x82AD /* GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST */: return "GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST (0x82AD)";
+case 0x82AE /* GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE */: return "GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE (0x82AE)";
+case 0x82AF /* GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE */: return "GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE (0x82AF)";
+case 0x82B1 /* GL_TEXTURE_COMPRESSED_BLOCK_WIDTH */: return "GL_TEXTURE_COMPRESSED_BLOCK_WIDTH (0x82B1)";
+case 0x82B2 /* GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT */: return "GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT (0x82B2)";
+case 0x82B3 /* GL_TEXTURE_COMPRESSED_BLOCK_SIZE */: return "GL_TEXTURE_COMPRESSED_BLOCK_SIZE (0x82B3)";
+case 0x82B4 /* GL_CLEAR_BUFFER */: return "GL_CLEAR_BUFFER (0x82B4)";
+case 0x82B5 /* GL_TEXTURE_VIEW */: return "GL_TEXTURE_VIEW (0x82B5)";
+case 0x82B6 /* GL_VIEW_COMPATIBILITY_CLASS */: return "GL_VIEW_COMPATIBILITY_CLASS (0x82B6)";
+case 0x82B7 /* GL_FULL_SUPPORT */: return "GL_FULL_SUPPORT (0x82B7)";
+case 0x82B8 /* GL_CAVEAT_SUPPORT */: return "GL_CAVEAT_SUPPORT (0x82B8)";
+case 0x82B9 /* GL_IMAGE_CLASS_4_X_32 */: return "GL_IMAGE_CLASS_4_X_32 (0x82B9)";
+case 0x82BA /* GL_IMAGE_CLASS_2_X_32 */: return "GL_IMAGE_CLASS_2_X_32 (0x82BA)";
+case 0x82BB /* GL_IMAGE_CLASS_1_X_32 */: return "GL_IMAGE_CLASS_1_X_32 (0x82BB)";
+case 0x82BC /* GL_IMAGE_CLASS_4_X_16 */: return "GL_IMAGE_CLASS_4_X_16 (0x82BC)";
+case 0x82BD /* GL_IMAGE_CLASS_2_X_16 */: return "GL_IMAGE_CLASS_2_X_16 (0x82BD)";
+case 0x82BE /* GL_IMAGE_CLASS_1_X_16 */: return "GL_IMAGE_CLASS_1_X_16 (0x82BE)";
+case 0x82BF /* GL_IMAGE_CLASS_4_X_8 */: return "GL_IMAGE_CLASS_4_X_8 (0x82BF)";
+case 0x82C0 /* GL_IMAGE_CLASS_2_X_8 */: return "GL_IMAGE_CLASS_2_X_8 (0x82C0)";
+case 0x82C1 /* GL_IMAGE_CLASS_1_X_8 */: return "GL_IMAGE_CLASS_1_X_8 (0x82C1)";
+case 0x82C2 /* GL_IMAGE_CLASS_11_11_10 */: return "GL_IMAGE_CLASS_11_11_10 (0x82C2)";
+case 0x82C3 /* GL_IMAGE_CLASS_10_10_10_2 */: return "GL_IMAGE_CLASS_10_10_10_2 (0x82C3)";
+case 0x82C4 /* GL_VIEW_CLASS_128_BITS */: return "GL_VIEW_CLASS_128_BITS (0x82C4)";
+case 0x82C5 /* GL_VIEW_CLASS_96_BITS */: return "GL_VIEW_CLASS_96_BITS (0x82C5)";
+case 0x82C6 /* GL_VIEW_CLASS_64_BITS */: return "GL_VIEW_CLASS_64_BITS (0x82C6)";
+case 0x82C7 /* GL_VIEW_CLASS_48_BITS */: return "GL_VIEW_CLASS_48_BITS (0x82C7)";
+case 0x82C8 /* GL_VIEW_CLASS_32_BITS */: return "GL_VIEW_CLASS_32_BITS (0x82C8)";
+case 0x82C9 /* GL_VIEW_CLASS_24_BITS */: return "GL_VIEW_CLASS_24_BITS (0x82C9)";
+case 0x82CA /* GL_VIEW_CLASS_16_BITS */: return "GL_VIEW_CLASS_16_BITS (0x82CA)";
+case 0x82CB /* GL_VIEW_CLASS_8_BITS */: return "GL_VIEW_CLASS_8_BITS (0x82CB)";
+case 0x82CC /* GL_VIEW_CLASS_S3TC_DXT1_RGB */: return "GL_VIEW_CLASS_S3TC_DXT1_RGB (0x82CC)";
+case 0x82CD /* GL_VIEW_CLASS_S3TC_DXT1_RGBA */: return "GL_VIEW_CLASS_S3TC_DXT1_RGBA (0x82CD)";
+case 0x82CE /* GL_VIEW_CLASS_S3TC_DXT3_RGBA */: return "GL_VIEW_CLASS_S3TC_DXT3_RGBA (0x82CE)";
+case 0x82CF /* GL_VIEW_CLASS_S3TC_DXT5_RGBA */: return "GL_VIEW_CLASS_S3TC_DXT5_RGBA (0x82CF)";
+case 0x82D0 /* GL_VIEW_CLASS_RGTC1_RED */: return "GL_VIEW_CLASS_RGTC1_RED (0x82D0)";
+case 0x82D1 /* GL_VIEW_CLASS_RGTC2_RG */: return "GL_VIEW_CLASS_RGTC2_RG (0x82D1)";
+case 0x82D2 /* GL_VIEW_CLASS_BPTC_UNORM */: return "GL_VIEW_CLASS_BPTC_UNORM (0x82D2)";
+case 0x82D3 /* GL_VIEW_CLASS_BPTC_FLOAT */: return "GL_VIEW_CLASS_BPTC_FLOAT (0x82D3)";
+//case 0x84F5 /* GL_TEXTURE_RECTANGLE */: return "GL_TEXTURE_RECTANGLE (0x84F5)";
+//case 0x8C18 /* GL_TEXTURE_1D_ARRAY */: return "GL_TEXTURE_1D_ARRAY (0x8C18)";
+//case 0x8C1A /* GL_TEXTURE_2D_ARRAY */: return "GL_TEXTURE_2D_ARRAY (0x8C1A)";
+//case 0x8C2A /* GL_TEXTURE_BUFFER */: return "GL_TEXTURE_BUFFER (0x8C2A)";
+//case 0x8D41 /* GL_RENDERBUFFER */: return "GL_RENDERBUFFER (0x8D41)";
+//case 0x9009 /* GL_TEXTURE_CUBE_MAP_ARRAY */: return "GL_TEXTURE_CUBE_MAP_ARRAY (0x9009)";
+case 0x9100 /* GL_TEXTURE_2D_MULTISAMPLE */: return "GL_TEXTURE_2D_MULTISAMPLE (0x9100)";
+case 0x9102 /* GL_TEXTURE_2D_MULTISAMPLE_ARRAY */: return "GL_TEXTURE_2D_MULTISAMPLE_ARRAY (0x9102)";
+//case 0x9380 /* GL_NUM_SAMPLE_COUNTS */: return "GL_NUM_SAMPLE_COUNTS (0x9380)";
+	/* ----------------------- GL_ARB_invalidate_subdata ----------------------- */
+
+
+/* ---------------------- GL_ARB_map_buffer_alignment ---------------------- */
+
+
+
+
+case 0x90BC /* GL_MIN_MAP_BUFFER_ALIGNMENT */: return "GL_MIN_MAP_BUFFER_ALIGNMENT (0x90BC)";
+
+
+
+
+
+/* ------------------------ GL_ARB_map_buffer_range ------------------------ */
+
+
+
+
+//case 0x0001 /* GL_MAP_READ_BIT */: return "GL_MAP_READ_BIT (0x0001)";
+//case 0x0002 /* GL_MAP_WRITE_BIT */: return "GL_MAP_WRITE_BIT (0x0002)";
+//case 0x0004 /* GL_MAP_INVALIDATE_RANGE_BIT */: return "GL_MAP_INVALIDATE_RANGE_BIT (0x0004)";
+//case 0x0008 /* GL_MAP_INVALIDATE_BUFFER_BIT */: return "GL_MAP_INVALIDATE_BUFFER_BIT (0x0008)";
+//case 0x0010 /* GL_MAP_FLUSH_EXPLICIT_BIT */: return "GL_MAP_FLUSH_EXPLICIT_BIT (0x0010)";
+//case 0x0020 /* GL_MAP_UNSYNCHRONIZED_BIT */: return "GL_MAP_UNSYNCHRONIZED_BIT (0x0020)";
+
+/* ------------------------- GL_ARB_matrix_palette ------------------------- */
+
+
+
+
+case 0x8840 /* GL_MATRIX_PALETTE_ARB */: return "GL_MATRIX_PALETTE_ARB (0x8840)";
+case 0x8841 /* GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB */: return "GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB (0x8841)";
+case 0x8842 /* GL_MAX_PALETTE_MATRICES_ARB */: return "GL_MAX_PALETTE_MATRICES_ARB (0x8842)";
+case 0x8843 /* GL_CURRENT_PALETTE_MATRIX_ARB */: return "GL_CURRENT_PALETTE_MATRIX_ARB (0x8843)";
+case 0x8844 /* GL_MATRIX_INDEX_ARRAY_ARB */: return "GL_MATRIX_INDEX_ARRAY_ARB (0x8844)";
+case 0x8845 /* GL_CURRENT_MATRIX_INDEX_ARB */: return "GL_CURRENT_MATRIX_INDEX_ARB (0x8845)";
+case 0x8846 /* GL_MATRIX_INDEX_ARRAY_SIZE_ARB */: return "GL_MATRIX_INDEX_ARRAY_SIZE_ARB (0x8846)";
+case 0x8847 /* GL_MATRIX_INDEX_ARRAY_TYPE_ARB */: return "GL_MATRIX_INDEX_ARRAY_TYPE_ARB (0x8847)";
+case 0x8848 /* GL_MATRIX_INDEX_ARRAY_STRIDE_ARB */: return "GL_MATRIX_INDEX_ARRAY_STRIDE_ARB (0x8848)";
+case 0x8849 /* GL_MATRIX_INDEX_ARRAY_POINTER_ARB */: return "GL_MATRIX_INDEX_ARRAY_POINTER_ARB (0x8849)";
+
+
+
+
+
+
+
+/* ----------------------- GL_ARB_multi_draw_indirect ---------------------- */
+
+
+
+
+/* --------------------------- GL_ARB_multisample -------------------------- */
+
+
+
+
+//case 0x809D /* GL_MULTISAMPLE_ARB */: return "GL_MULTISAMPLE_ARB (0x809D)";
+//case 0x809E /* GL_SAMPLE_ALPHA_TO_COVERAGE_ARB */: return "GL_SAMPLE_ALPHA_TO_COVERAGE_ARB (0x809E)";
+//case 0x809F /* GL_SAMPLE_ALPHA_TO_ONE_ARB */: return "GL_SAMPLE_ALPHA_TO_ONE_ARB (0x809F)";
+//case 0x80A0 /* GL_SAMPLE_COVERAGE_ARB */: return "GL_SAMPLE_COVERAGE_ARB (0x80A0)";
+//case 0x80A8 /* GL_SAMPLE_BUFFERS_ARB */: return "GL_SAMPLE_BUFFERS_ARB (0x80A8)";
+//case 0x80A9 /* GL_SAMPLES_ARB */: return "GL_SAMPLES_ARB (0x80A9)";
+//case 0x80AA /* GL_SAMPLE_COVERAGE_VALUE_ARB */: return "GL_SAMPLE_COVERAGE_VALUE_ARB (0x80AA)";
+//case 0x80AB /* GL_SAMPLE_COVERAGE_INVERT_ARB */: return "GL_SAMPLE_COVERAGE_INVERT_ARB (0x80AB)";
+//case 0x20000000 /* GL_MULTISAMPLE_BIT_ARB */: return "GL_MULTISAMPLE_BIT_ARB (0x20000000)";/* -------------------------- GL_ARB_multitexture -------------------------- */
+
+
+
+
+//case 0x84C0 /* GL_TEXTURE0_ARB */: return "GL_TEXTURE0_ARB (0x84C0)";
+//case 0x84C1 /* GL_TEXTURE1_ARB */: return "GL_TEXTURE1_ARB (0x84C1)";
+//case 0x84C2 /* GL_TEXTURE2_ARB */: return "GL_TEXTURE2_ARB (0x84C2)";
+//case 0x84C3 /* GL_TEXTURE3_ARB */: return "GL_TEXTURE3_ARB (0x84C3)";
+//case 0x84C4 /* GL_TEXTURE4_ARB */: return "GL_TEXTURE4_ARB (0x84C4)";
+//case 0x84C5 /* GL_TEXTURE5_ARB */: return "GL_TEXTURE5_ARB (0x84C5)";
+//case 0x84C6 /* GL_TEXTURE6_ARB */: return "GL_TEXTURE6_ARB (0x84C6)";
+//case 0x84C7 /* GL_TEXTURE7_ARB */: return "GL_TEXTURE7_ARB (0x84C7)";
+//case 0x84C8 /* GL_TEXTURE8_ARB */: return "GL_TEXTURE8_ARB (0x84C8)";
+//case 0x84C9 /* GL_TEXTURE9_ARB */: return "GL_TEXTURE9_ARB (0x84C9)";
+//case 0x84CA /* GL_TEXTURE10_ARB */: return "GL_TEXTURE10_ARB (0x84CA)";
+//case 0x84CB /* GL_TEXTURE11_ARB */: return "GL_TEXTURE11_ARB (0x84CB)";
+//case 0x84CC /* GL_TEXTURE12_ARB */: return "GL_TEXTURE12_ARB (0x84CC)";
+//case 0x84CD /* GL_TEXTURE13_ARB */: return "GL_TEXTURE13_ARB (0x84CD)";
+//case 0x84CE /* GL_TEXTURE14_ARB */: return "GL_TEXTURE14_ARB (0x84CE)";
+//case 0x84CF /* GL_TEXTURE15_ARB */: return "GL_TEXTURE15_ARB (0x84CF)";
+//case 0x84D0 /* GL_TEXTURE16_ARB */: return "GL_TEXTURE16_ARB (0x84D0)";
+//case 0x84D1 /* GL_TEXTURE17_ARB */: return "GL_TEXTURE17_ARB (0x84D1)";
+//case 0x84D2 /* GL_TEXTURE18_ARB */: return "GL_TEXTURE18_ARB (0x84D2)";
+//case 0x84D3 /* GL_TEXTURE19_ARB */: return "GL_TEXTURE19_ARB (0x84D3)";
+//case 0x84D4 /* GL_TEXTURE20_ARB */: return "GL_TEXTURE20_ARB (0x84D4)";
+//case 0x84D5 /* GL_TEXTURE21_ARB */: return "GL_TEXTURE21_ARB (0x84D5)";
+//case 0x84D6 /* GL_TEXTURE22_ARB */: return "GL_TEXTURE22_ARB (0x84D6)";
+//case 0x84D7 /* GL_TEXTURE23_ARB */: return "GL_TEXTURE23_ARB (0x84D7)";
+//case 0x84D8 /* GL_TEXTURE24_ARB */: return "GL_TEXTURE24_ARB (0x84D8)";
+//case 0x84D9 /* GL_TEXTURE25_ARB */: return "GL_TEXTURE25_ARB (0x84D9)";
+//case 0x84DA /* GL_TEXTURE26_ARB */: return "GL_TEXTURE26_ARB (0x84DA)";
+//case 0x84DB /* GL_TEXTURE27_ARB */: return "GL_TEXTURE27_ARB (0x84DB)";
+//case 0x84DC /* GL_TEXTURE28_ARB */: return "GL_TEXTURE28_ARB (0x84DC)";
+//case 0x84DD /* GL_TEXTURE29_ARB */: return "GL_TEXTURE29_ARB (0x84DD)";
+//case 0x84DE /* GL_TEXTURE30_ARB */: return "GL_TEXTURE30_ARB (0x84DE)";
+//case 0x84DF /* GL_TEXTURE31_ARB */: return "GL_TEXTURE31_ARB (0x84DF)";
+//case 0x84E0 /* GL_ACTIVE_TEXTURE_ARB */: return "GL_ACTIVE_TEXTURE_ARB (0x84E0)";
+//case 0x84E1 /* GL_CLIENT_ACTIVE_TEXTURE_ARB */: return "GL_CLIENT_ACTIVE_TEXTURE_ARB (0x84E1)";
+//case 0x84E2 /* GL_MAX_TEXTURE_UNITS_ARB */: return "GL_MAX_TEXTURE_UNITS_ARB (0x84E2)";
+
+
+
+
+
+/* ------------------------- GL_ARB_occlusion_query ------------------------ */
+
+
+
+
+//case 0x8864 /* GL_QUERY_COUNTER_BITS_ARB */: return "GL_QUERY_COUNTER_BITS_ARB (0x8864)";
+//case 0x8865 /* GL_CURRENT_QUERY_ARB */: return "GL_CURRENT_QUERY_ARB (0x8865)";
+//case 0x8866 /* GL_QUERY_RESULT_ARB */: return "GL_QUERY_RESULT_ARB (0x8866)";
+//case 0x8867 /* GL_QUERY_RESULT_AVAILABLE_ARB */: return "GL_QUERY_RESULT_AVAILABLE_ARB (0x8867)";
+//case 0x8914 /* GL_SAMPLES_PASSED_ARB */: return "GL_SAMPLES_PASSED_ARB (0x8914)";
+
+
+
+/* ------------------------ GL_ARB_occlusion_query2 ------------------------ */
+
+
+
+
+case 0x8C2F /* GL_ANY_SAMPLES_PASSED */: return "GL_ANY_SAMPLES_PASSED (0x8C2F)";
+
+
+
+
+
+/* ----------------------- GL_ARB_pixel_buffer_object ---------------------- */
+
+
+
+
+//case 0x88EB /* GL_PIXEL_PACK_BUFFER_ARB */: return "GL_PIXEL_PACK_BUFFER_ARB (0x88EB)";
+//case 0x88EC /* GL_PIXEL_UNPACK_BUFFER_ARB */: return "GL_PIXEL_UNPACK_BUFFER_ARB (0x88EC)";
+//case 0x88ED /* GL_PIXEL_PACK_BUFFER_BINDING_ARB */: return "GL_PIXEL_PACK_BUFFER_BINDING_ARB (0x88ED)";
+//case 0x88EF /* GL_PIXEL_UNPACK_BUFFER_BINDING_ARB */: return "GL_PIXEL_UNPACK_BUFFER_BINDING_ARB (0x88EF)";
+
+
+
+
+
+/* ------------------------ GL_ARB_point_parameters ------------------------ */
+
+
+
+
+//case 0x8126 /* GL_POINT_SIZE_MIN_ARB */: return "GL_POINT_SIZE_MIN_ARB (0x8126)";
+//case 0x8127 /* GL_POINT_SIZE_MAX_ARB */: return "GL_POINT_SIZE_MAX_ARB (0x8127)";
+//case 0x8128 /* GL_POINT_FADE_THRESHOLD_SIZE_ARB */: return "GL_POINT_FADE_THRESHOLD_SIZE_ARB (0x8128)";
+//case 0x8129 /* GL_POINT_DISTANCE_ATTENUATION_ARB */: return "GL_POINT_DISTANCE_ATTENUATION_ARB (0x8129)";
+
+/* -------------------------- GL_ARB_point_sprite -------------------------- */
+
+
+
+
+//case 0x8861 /* GL_POINT_SPRITE_ARB */: return "GL_POINT_SPRITE_ARB (0x8861)";
+//case 0x8862 /* GL_COORD_REPLACE_ARB */: return "GL_COORD_REPLACE_ARB (0x8862)";
+
+
+
+
+
+/* --------------------- GL_ARB_program_interface_query -------------------- */
+
+
+
+
+case 0x92E1 /* GL_UNIFORM */: return "GL_UNIFORM (0x92E1)";
+case 0x92E2 /* GL_UNIFORM_BLOCK */: return "GL_UNIFORM_BLOCK (0x92E2)";
+case 0x92E3 /* GL_PROGRAM_INPUT */: return "GL_PROGRAM_INPUT (0x92E3)";
+case 0x92E4 /* GL_PROGRAM_OUTPUT */: return "GL_PROGRAM_OUTPUT (0x92E4)";
+case 0x92E5 /* GL_BUFFER_VARIABLE */: return "GL_BUFFER_VARIABLE (0x92E5)";
+case 0x92E6 /* GL_SHADER_STORAGE_BLOCK */: return "GL_SHADER_STORAGE_BLOCK (0x92E6)";
+case 0x92E7 /* GL_IS_PER_PATCH */: return "GL_IS_PER_PATCH (0x92E7)";
+case 0x92E8 /* GL_VERTEX_SUBROUTINE */: return "GL_VERTEX_SUBROUTINE (0x92E8)";
+case 0x92E9 /* GL_TESS_CONTROL_SUBROUTINE */: return "GL_TESS_CONTROL_SUBROUTINE (0x92E9)";
+case 0x92EA /* GL_TESS_EVALUATION_SUBROUTINE */: return "GL_TESS_EVALUATION_SUBROUTINE (0x92EA)";
+case 0x92EB /* GL_GEOMETRY_SUBROUTINE */: return "GL_GEOMETRY_SUBROUTINE (0x92EB)";
+case 0x92EC /* GL_FRAGMENT_SUBROUTINE */: return "GL_FRAGMENT_SUBROUTINE (0x92EC)";
+case 0x92ED /* GL_COMPUTE_SUBROUTINE */: return "GL_COMPUTE_SUBROUTINE (0x92ED)";
+case 0x92EE /* GL_VERTEX_SUBROUTINE_UNIFORM */: return "GL_VERTEX_SUBROUTINE_UNIFORM (0x92EE)";
+case 0x92EF /* GL_TESS_CONTROL_SUBROUTINE_UNIFORM */: return "GL_TESS_CONTROL_SUBROUTINE_UNIFORM (0x92EF)";
+case 0x92F0 /* GL_TESS_EVALUATION_SUBROUTINE_UNIFORM */: return "GL_TESS_EVALUATION_SUBROUTINE_UNIFORM (0x92F0)";
+case 0x92F1 /* GL_GEOMETRY_SUBROUTINE_UNIFORM */: return "GL_GEOMETRY_SUBROUTINE_UNIFORM (0x92F1)";
+case 0x92F2 /* GL_FRAGMENT_SUBROUTINE_UNIFORM */: return "GL_FRAGMENT_SUBROUTINE_UNIFORM (0x92F2)";
+case 0x92F3 /* GL_COMPUTE_SUBROUTINE_UNIFORM */: return "GL_COMPUTE_SUBROUTINE_UNIFORM (0x92F3)";
+case 0x92F4 /* GL_TRANSFORM_FEEDBACK_VARYING */: return "GL_TRANSFORM_FEEDBACK_VARYING (0x92F4)";
+case 0x92F5 /* GL_ACTIVE_RESOURCES */: return "GL_ACTIVE_RESOURCES (0x92F5)";
+case 0x92F6 /* GL_MAX_NAME_LENGTH */: return "GL_MAX_NAME_LENGTH (0x92F6)";
+case 0x92F7 /* GL_MAX_NUM_ACTIVE_VARIABLES */: return "GL_MAX_NUM_ACTIVE_VARIABLES (0x92F7)";
+case 0x92F8 /* GL_MAX_NUM_COMPATIBLE_SUBROUTINES */: return "GL_MAX_NUM_COMPATIBLE_SUBROUTINES (0x92F8)";
+case 0x92F9 /* GL_NAME_LENGTH */: return "GL_NAME_LENGTH (0x92F9)";
+case 0x92FA /* GL_TYPE */: return "GL_TYPE (0x92FA)";
+case 0x92FB /* GL_ARRAY_SIZE */: return "GL_ARRAY_SIZE (0x92FB)";
+case 0x92FC /* GL_OFFSET */: return "GL_OFFSET (0x92FC)";
+case 0x92FD /* GL_BLOCK_INDEX */: return "GL_BLOCK_INDEX (0x92FD)";
+case 0x92FE /* GL_ARRAY_STRIDE */: return "GL_ARRAY_STRIDE (0x92FE)";
+case 0x92FF /* GL_MATRIX_STRIDE */: return "GL_MATRIX_STRIDE (0x92FF)";
+case 0x9300 /* GL_IS_ROW_MAJOR */: return "GL_IS_ROW_MAJOR (0x9300)";
+case 0x9301 /* GL_ATOMIC_COUNTER_BUFFER_INDEX */: return "GL_ATOMIC_COUNTER_BUFFER_INDEX (0x9301)";
+case 0x9302 /* GL_BUFFER_BINDING */: return "GL_BUFFER_BINDING (0x9302)";
+case 0x9303 /* GL_BUFFER_DATA_SIZE */: return "GL_BUFFER_DATA_SIZE (0x9303)";
+case 0x9304 /* GL_NUM_ACTIVE_VARIABLES */: return "GL_NUM_ACTIVE_VARIABLES (0x9304)";
+case 0x9305 /* GL_ACTIVE_VARIABLES */: return "GL_ACTIVE_VARIABLES (0x9305)";
+case 0x9306 /* GL_REFERENCED_BY_VERTEX_SHADER */: return "GL_REFERENCED_BY_VERTEX_SHADER (0x9306)";
+case 0x9307 /* GL_REFERENCED_BY_TESS_CONTROL_SHADER */: return "GL_REFERENCED_BY_TESS_CONTROL_SHADER (0x9307)";
+case 0x9308 /* GL_REFERENCED_BY_TESS_EVALUATION_SHADER */: return "GL_REFERENCED_BY_TESS_EVALUATION_SHADER (0x9308)";
+case 0x9309 /* GL_REFERENCED_BY_GEOMETRY_SHADER */: return "GL_REFERENCED_BY_GEOMETRY_SHADER (0x9309)";
+case 0x930A /* GL_REFERENCED_BY_FRAGMENT_SHADER */: return "GL_REFERENCED_BY_FRAGMENT_SHADER (0x930A)";
+case 0x930B /* GL_REFERENCED_BY_COMPUTE_SHADER */: return "GL_REFERENCED_BY_COMPUTE_SHADER (0x930B)";
+case 0x930C /* GL_TOP_LEVEL_ARRAY_SIZE */: return "GL_TOP_LEVEL_ARRAY_SIZE (0x930C)";
+case 0x930D /* GL_TOP_LEVEL_ARRAY_STRIDE */: return "GL_TOP_LEVEL_ARRAY_STRIDE (0x930D)";
+case 0x930E /* GL_LOCATION */: return "GL_LOCATION (0x930E)";
+case 0x930F /* GL_LOCATION_INDEX */: return "GL_LOCATION_INDEX (0x930F)";/* ------------------------ GL_ARB_provoking_vertex ------------------------ */
+
+
+
+
+case 0x8E4C /* GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION */: return "GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION (0x8E4C)";
+case 0x8E4D /* GL_FIRST_VERTEX_CONVENTION */: return "GL_FIRST_VERTEX_CONVENTION (0x8E4D)";
+case 0x8E4E /* GL_LAST_VERTEX_CONVENTION */: return "GL_LAST_VERTEX_CONVENTION (0x8E4E)";
+case 0x8E4F /* GL_PROVOKING_VERTEX */: return "GL_PROVOKING_VERTEX (0x8E4F)";/* ------------------ GL_ARB_robust_buffer_access_behavior ----------------- */
+
+
+
+
+
+
+
+
+/* --------------------------- GL_ARB_robustness --------------------------- */
+
+
+
+
+//case 0x00000004 /* GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB */: return "GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB (0x00000004)";
+case 0x8252 /* GL_LOSE_CONTEXT_ON_RESET_ARB */: return "GL_LOSE_CONTEXT_ON_RESET_ARB (0x8252)";
+case 0x8253 /* GL_GUILTY_CONTEXT_RESET_ARB */: return "GL_GUILTY_CONTEXT_RESET_ARB (0x8253)";
+case 0x8254 /* GL_INNOCENT_CONTEXT_RESET_ARB */: return "GL_INNOCENT_CONTEXT_RESET_ARB (0x8254)";
+case 0x8255 /* GL_UNKNOWN_CONTEXT_RESET_ARB */: return "GL_UNKNOWN_CONTEXT_RESET_ARB (0x8255)";
+case 0x8256 /* GL_RESET_NOTIFICATION_STRATEGY_ARB */: return "GL_RESET_NOTIFICATION_STRATEGY_ARB (0x8256)";
+case 0x8261 /* GL_NO_RESET_NOTIFICATION_ARB */: return "GL_NO_RESET_NOTIFICATION_ARB (0x8261)";
+
+
+
+
+
+
+
+/* ---------------- GL_ARB_robustness_application_isolation ---------------- */
+
+
+
+
+
+
+
+
+/* ---------------- GL_ARB_robustness_share_group_isolation ---------------- */
+
+
+
+
+
+
+
+
+/* ------------------------- GL_ARB_sample_shading ------------------------- */
+
+
+
+
+//case 0x8C36 /* GL_SAMPLE_SHADING_ARB */: return "GL_SAMPLE_SHADING_ARB (0x8C36)";
+//case 0x8C37 /* GL_MIN_SAMPLE_SHADING_VALUE_ARB */: return "GL_MIN_SAMPLE_SHADING_VALUE_ARB (0x8C37)";
+	/* ------------------------- GL_ARB_sampler_objects ------------------------ */
+
+
+
+
+case 0x8919 /* GL_SAMPLER_BINDING */: return "GL_SAMPLER_BINDING (0x8919)";
+
+
+
+
+
+/* ------------------------ GL_ARB_seamless_cube_map ----------------------- */
+
+
+
+
+//case 0x884F /* GL_TEXTURE_CUBE_MAP_SEAMLESS */: return "GL_TEXTURE_CUBE_MAP_SEAMLESS (0x884F)";
+
+
+
+
+
+/* --------------------- GL_ARB_separate_shader_objects -------------------- */
+
+
+
+
+//case 0x00000001 /* GL_VERTEX_SHADER_BIT */: return "GL_VERTEX_SHADER_BIT (0x00000001)";
+//case 0x00000002 /* GL_FRAGMENT_SHADER_BIT */: return "GL_FRAGMENT_SHADER_BIT (0x00000002)";
+//case 0x00000004 /* GL_GEOMETRY_SHADER_BIT */: return "GL_GEOMETRY_SHADER_BIT (0x00000004)";
+//case 0x00000008 /* GL_TESS_CONTROL_SHADER_BIT */: return "GL_TESS_CONTROL_SHADER_BIT (0x00000008)";
+//case 0x00000010 /* GL_TESS_EVALUATION_SHADER_BIT */: return "GL_TESS_EVALUATION_SHADER_BIT (0x00000010)";
+case 0x8258 /* GL_PROGRAM_SEPARABLE */: return "GL_PROGRAM_SEPARABLE (0x8258)";
+case 0x8259 /* GL_ACTIVE_PROGRAM */: return "GL_ACTIVE_PROGRAM (0x8259)";
+case 0x825A /* GL_PROGRAM_PIPELINE_BINDING */: return "GL_PROGRAM_PIPELINE_BINDING (0x825A)";
+//case 0xFFFFFFFF /* GL_ALL_SHADER_BITS */: return "GL_ALL_SHADER_BITS (0xFFFFFFFF)";
+
+
+
+
+
+
+
+/* --------------------- GL_ARB_shader_atomic_counters --------------------- */
+
+
+
+
+case 0x92C0 /* GL_ATOMIC_COUNTER_BUFFER */: return "GL_ATOMIC_COUNTER_BUFFER (0x92C0)";
+case 0x92C1 /* GL_ATOMIC_COUNTER_BUFFER_BINDING */: return "GL_ATOMIC_COUNTER_BUFFER_BINDING (0x92C1)";
+case 0x92C2 /* GL_ATOMIC_COUNTER_BUFFER_START */: return "GL_ATOMIC_COUNTER_BUFFER_START (0x92C2)";
+case 0x92C3 /* GL_ATOMIC_COUNTER_BUFFER_SIZE */: return "GL_ATOMIC_COUNTER_BUFFER_SIZE (0x92C3)";
+case 0x92C4 /* GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE */: return "GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE (0x92C4)";
+case 0x92C5 /* GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS */: return "GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS (0x92C5)";
+case 0x92C6 /* GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES */: return "GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES (0x92C6)";
+case 0x92C7 /* GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER */: return "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER (0x92C7)";
+case 0x92C8 /* GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER */: return "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER (0x92C8)";
+case 0x92C9 /* GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER */: return "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER (0x92C9)";
+case 0x92CA /* GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER */: return "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER (0x92CA)";
+case 0x92CB /* GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER */: return "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER (0x92CB)";
+case 0x92CC /* GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS */: return "GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS (0x92CC)";
+case 0x92CD /* GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS */: return "GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS (0x92CD)";
+case 0x92CE /* GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS */: return "GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS (0x92CE)";
+case 0x92CF /* GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS */: return "GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS (0x92CF)";
+case 0x92D0 /* GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS */: return "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS (0x92D0)";
+case 0x92D1 /* GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS */: return "GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS (0x92D1)";
+case 0x92D2 /* GL_MAX_VERTEX_ATOMIC_COUNTERS */: return "GL_MAX_VERTEX_ATOMIC_COUNTERS (0x92D2)";
+case 0x92D3 /* GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS */: return "GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS (0x92D3)";
+case 0x92D4 /* GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS */: return "GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS (0x92D4)";
+case 0x92D5 /* GL_MAX_GEOMETRY_ATOMIC_COUNTERS */: return "GL_MAX_GEOMETRY_ATOMIC_COUNTERS (0x92D5)";
+case 0x92D6 /* GL_MAX_FRAGMENT_ATOMIC_COUNTERS */: return "GL_MAX_FRAGMENT_ATOMIC_COUNTERS (0x92D6)";
+case 0x92D7 /* GL_MAX_COMBINED_ATOMIC_COUNTERS */: return "GL_MAX_COMBINED_ATOMIC_COUNTERS (0x92D7)";
+case 0x92D8 /* GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE */: return "GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE (0x92D8)";
+case 0x92D9 /* GL_ACTIVE_ATOMIC_COUNTER_BUFFERS */: return "GL_ACTIVE_ATOMIC_COUNTER_BUFFERS (0x92D9)";
+case 0x92DA /* GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX */: return "GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX (0x92DA)";
+case 0x92DB /* GL_UNSIGNED_INT_ATOMIC_COUNTER */: return "GL_UNSIGNED_INT_ATOMIC_COUNTER (0x92DB)";
+case 0x92DC /* GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS */: return "GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS (0x92DC)";/* ----------------------- GL_ARB_shader_bit_encoding ---------------------- */
+
+
+
+
+
+
+
+
+/* --------------------- GL_ARB_shader_image_load_store -------------------- */
+
+
+
+
+//case 0x00000001 /* GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT */: return "GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT (0x00000001)";
+//case 0x00000002 /* GL_ELEMENT_ARRAY_BARRIER_BIT */: return "GL_ELEMENT_ARRAY_BARRIER_BIT (0x00000002)";
+//case 0x00000004 /* GL_UNIFORM_BARRIER_BIT */: return "GL_UNIFORM_BARRIER_BIT (0x00000004)";
+//case 0x00000008 /* GL_TEXTURE_FETCH_BARRIER_BIT */: return "GL_TEXTURE_FETCH_BARRIER_BIT (0x00000008)";
+//case 0x00000020 /* GL_SHADER_IMAGE_ACCESS_BARRIER_BIT */: return "GL_SHADER_IMAGE_ACCESS_BARRIER_BIT (0x00000020)";
+//case 0x00000040 /* GL_COMMAND_BARRIER_BIT */: return "GL_COMMAND_BARRIER_BIT (0x00000040)";
+//case 0x00000080 /* GL_PIXEL_BUFFER_BARRIER_BIT */: return "GL_PIXEL_BUFFER_BARRIER_BIT (0x00000080)";
+//case 0x00000100 /* GL_TEXTURE_UPDATE_BARRIER_BIT */: return "GL_TEXTURE_UPDATE_BARRIER_BIT (0x00000100)";
+//case 0x00000200 /* GL_BUFFER_UPDATE_BARRIER_BIT */: return "GL_BUFFER_UPDATE_BARRIER_BIT (0x00000200)";
+//case 0x00000400 /* GL_FRAMEBUFFER_BARRIER_BIT */: return "GL_FRAMEBUFFER_BARRIER_BIT (0x00000400)";
+//case 0x00000800 /* GL_TRANSFORM_FEEDBACK_BARRIER_BIT */: return "GL_TRANSFORM_FEEDBACK_BARRIER_BIT (0x00000800)";
+//case 0x00001000 /* GL_ATOMIC_COUNTER_BARRIER_BIT */: return "GL_ATOMIC_COUNTER_BARRIER_BIT (0x00001000)";
+case 0x8F38 /* GL_MAX_IMAGE_UNITS */: return "GL_MAX_IMAGE_UNITS (0x8F38)";
+case 0x8F39 /* GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS */: return "GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS (0x8F39)";
+case 0x8F3A /* GL_IMAGE_BINDING_NAME */: return "GL_IMAGE_BINDING_NAME (0x8F3A)";
+case 0x8F3B /* GL_IMAGE_BINDING_LEVEL */: return "GL_IMAGE_BINDING_LEVEL (0x8F3B)";
+case 0x8F3C /* GL_IMAGE_BINDING_LAYERED */: return "GL_IMAGE_BINDING_LAYERED (0x8F3C)";
+case 0x8F3D /* GL_IMAGE_BINDING_LAYER */: return "GL_IMAGE_BINDING_LAYER (0x8F3D)";
+case 0x8F3E /* GL_IMAGE_BINDING_ACCESS */: return "GL_IMAGE_BINDING_ACCESS (0x8F3E)";
+case 0x904C /* GL_IMAGE_1D */: return "GL_IMAGE_1D (0x904C)";
+case 0x904D /* GL_IMAGE_2D */: return "GL_IMAGE_2D (0x904D)";
+case 0x904E /* GL_IMAGE_3D */: return "GL_IMAGE_3D (0x904E)";
+case 0x904F /* GL_IMAGE_2D_RECT */: return "GL_IMAGE_2D_RECT (0x904F)";
+case 0x9050 /* GL_IMAGE_CUBE */: return "GL_IMAGE_CUBE (0x9050)";
+case 0x9051 /* GL_IMAGE_BUFFER */: return "GL_IMAGE_BUFFER (0x9051)";
+case 0x9052 /* GL_IMAGE_1D_ARRAY */: return "GL_IMAGE_1D_ARRAY (0x9052)";
+case 0x9053 /* GL_IMAGE_2D_ARRAY */: return "GL_IMAGE_2D_ARRAY (0x9053)";
+case 0x9054 /* GL_IMAGE_CUBE_MAP_ARRAY */: return "GL_IMAGE_CUBE_MAP_ARRAY (0x9054)";
+case 0x9055 /* GL_IMAGE_2D_MULTISAMPLE */: return "GL_IMAGE_2D_MULTISAMPLE (0x9055)";
+case 0x9056 /* GL_IMAGE_2D_MULTISAMPLE_ARRAY */: return "GL_IMAGE_2D_MULTISAMPLE_ARRAY (0x9056)";
+case 0x9057 /* GL_INT_IMAGE_1D */: return "GL_INT_IMAGE_1D (0x9057)";
+case 0x9058 /* GL_INT_IMAGE_2D */: return "GL_INT_IMAGE_2D (0x9058)";
+case 0x9059 /* GL_INT_IMAGE_3D */: return "GL_INT_IMAGE_3D (0x9059)";
+case 0x905A /* GL_INT_IMAGE_2D_RECT */: return "GL_INT_IMAGE_2D_RECT (0x905A)";
+case 0x905B /* GL_INT_IMAGE_CUBE */: return "GL_INT_IMAGE_CUBE (0x905B)";
+case 0x905C /* GL_INT_IMAGE_BUFFER */: return "GL_INT_IMAGE_BUFFER (0x905C)";
+case 0x905D /* GL_INT_IMAGE_1D_ARRAY */: return "GL_INT_IMAGE_1D_ARRAY (0x905D)";
+case 0x905E /* GL_INT_IMAGE_2D_ARRAY */: return "GL_INT_IMAGE_2D_ARRAY (0x905E)";
+case 0x905F /* GL_INT_IMAGE_CUBE_MAP_ARRAY */: return "GL_INT_IMAGE_CUBE_MAP_ARRAY (0x905F)";
+case 0x9060 /* GL_INT_IMAGE_2D_MULTISAMPLE */: return "GL_INT_IMAGE_2D_MULTISAMPLE (0x9060)";
+case 0x9061 /* GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY */: return "GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY (0x9061)";
+case 0x9062 /* GL_UNSIGNED_INT_IMAGE_1D */: return "GL_UNSIGNED_INT_IMAGE_1D (0x9062)";
+case 0x9063 /* GL_UNSIGNED_INT_IMAGE_2D */: return "GL_UNSIGNED_INT_IMAGE_2D (0x9063)";
+case 0x9064 /* GL_UNSIGNED_INT_IMAGE_3D */: return "GL_UNSIGNED_INT_IMAGE_3D (0x9064)";
+case 0x9065 /* GL_UNSIGNED_INT_IMAGE_2D_RECT */: return "GL_UNSIGNED_INT_IMAGE_2D_RECT (0x9065)";
+case 0x9066 /* GL_UNSIGNED_INT_IMAGE_CUBE */: return "GL_UNSIGNED_INT_IMAGE_CUBE (0x9066)";
+case 0x9067 /* GL_UNSIGNED_INT_IMAGE_BUFFER */: return "GL_UNSIGNED_INT_IMAGE_BUFFER (0x9067)";
+case 0x9068 /* GL_UNSIGNED_INT_IMAGE_1D_ARRAY */: return "GL_UNSIGNED_INT_IMAGE_1D_ARRAY (0x9068)";
+case 0x9069 /* GL_UNSIGNED_INT_IMAGE_2D_ARRAY */: return "GL_UNSIGNED_INT_IMAGE_2D_ARRAY (0x9069)";
+case 0x906A /* GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY */: return "GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY (0x906A)";
+case 0x906B /* GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE */: return "GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE (0x906B)";
+case 0x906C /* GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY */: return "GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY (0x906C)";
+case 0x906D /* GL_MAX_IMAGE_SAMPLES */: return "GL_MAX_IMAGE_SAMPLES (0x906D)";
+case 0x906E /* GL_IMAGE_BINDING_FORMAT */: return "GL_IMAGE_BINDING_FORMAT (0x906E)";
+case 0x90C7 /* GL_IMAGE_FORMAT_COMPATIBILITY_TYPE */: return "GL_IMAGE_FORMAT_COMPATIBILITY_TYPE (0x90C7)";
+case 0x90C8 /* GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE */: return "GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE (0x90C8)";
+case 0x90C9 /* GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS */: return "GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS (0x90C9)";
+case 0x90CA /* GL_MAX_VERTEX_IMAGE_UNIFORMS */: return "GL_MAX_VERTEX_IMAGE_UNIFORMS (0x90CA)";
+case 0x90CB /* GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS */: return "GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS (0x90CB)";
+case 0x90CC /* GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS */: return "GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS (0x90CC)";
+case 0x90CD /* GL_MAX_GEOMETRY_IMAGE_UNIFORMS */: return "GL_MAX_GEOMETRY_IMAGE_UNIFORMS (0x90CD)";
+case 0x90CE /* GL_MAX_FRAGMENT_IMAGE_UNIFORMS */: return "GL_MAX_FRAGMENT_IMAGE_UNIFORMS (0x90CE)";
+case 0x90CF /* GL_MAX_COMBINED_IMAGE_UNIFORMS */: return "GL_MAX_COMBINED_IMAGE_UNIFORMS (0x90CF)";
+//case 0xFFFFFFFF /* GL_ALL_BARRIER_BITS */: return "GL_ALL_BARRIER_BITS (0xFFFFFFFF)";
+
+/* ------------------------ GL_ARB_shader_image_size ----------------------- */
+
+
+
+
+
+
+
+
+/* ------------------------- GL_ARB_shader_objects ------------------------- */
+
+
+
+
+case 0x8B40 /* GL_PROGRAM_OBJECT_ARB */: return "GL_PROGRAM_OBJECT_ARB (0x8B40)";
+case 0x8B48 /* GL_SHADER_OBJECT_ARB */: return "GL_SHADER_OBJECT_ARB (0x8B48)";
+case 0x8B4E /* GL_OBJECT_TYPE_ARB */: return "GL_OBJECT_TYPE_ARB (0x8B4E)";
+//case 0x8B4F /* GL_OBJECT_SUBTYPE_ARB */: return "GL_OBJECT_SUBTYPE_ARB (0x8B4F)";
+//case 0x8B50 /* GL_FLOAT_VEC2_ARB */: return "GL_FLOAT_VEC2_ARB (0x8B50)";
+//case 0x8B51 /* GL_FLOAT_VEC3_ARB */: return "GL_FLOAT_VEC3_ARB (0x8B51)";
+//case 0x8B52 /* GL_FLOAT_VEC4_ARB */: return "GL_FLOAT_VEC4_ARB (0x8B52)";
+//case 0x8B53 /* GL_INT_VEC2_ARB */: return "GL_INT_VEC2_ARB (0x8B53)";
+//case 0x8B54 /* GL_INT_VEC3_ARB */: return "GL_INT_VEC3_ARB (0x8B54)";
+//case 0x8B55 /* GL_INT_VEC4_ARB */: return "GL_INT_VEC4_ARB (0x8B55)";
+//case 0x8B56 /* GL_BOOL_ARB */: return "GL_BOOL_ARB (0x8B56)";
+//case 0x8B57 /* GL_BOOL_VEC2_ARB */: return "GL_BOOL_VEC2_ARB (0x8B57)";
+//case 0x8B58 /* GL_BOOL_VEC3_ARB */: return "GL_BOOL_VEC3_ARB (0x8B58)";
+//case 0x8B59 /* GL_BOOL_VEC4_ARB */: return "GL_BOOL_VEC4_ARB (0x8B59)";
+//case 0x8B5A /* GL_FLOAT_MAT2_ARB */: return "GL_FLOAT_MAT2_ARB (0x8B5A)";
+//case 0x8B5B /* GL_FLOAT_MAT3_ARB */: return "GL_FLOAT_MAT3_ARB (0x8B5B)";
+//case 0x8B5C /* GL_FLOAT_MAT4_ARB */: return "GL_FLOAT_MAT4_ARB (0x8B5C)";
+//case 0x8B5D /* GL_SAMPLER_1D_ARB */: return "GL_SAMPLER_1D_ARB (0x8B5D)";
+//case 0x8B5E /* GL_SAMPLER_2D_ARB */: return "GL_SAMPLER_2D_ARB (0x8B5E)";
+//case 0x8B5F /* GL_SAMPLER_3D_ARB */: return "GL_SAMPLER_3D_ARB (0x8B5F)";
+//case 0x8B60 /* GL_SAMPLER_CUBE_ARB */: return "GL_SAMPLER_CUBE_ARB (0x8B60)";
+//case 0x8B61 /* GL_SAMPLER_1D_SHADOW_ARB */: return "GL_SAMPLER_1D_SHADOW_ARB (0x8B61)";
+//case 0x8B62 /* GL_SAMPLER_2D_SHADOW_ARB */: return "GL_SAMPLER_2D_SHADOW_ARB (0x8B62)";
+//case 0x8B63 /* GL_SAMPLER_2D_RECT_ARB */: return "GL_SAMPLER_2D_RECT_ARB (0x8B63)";
+//case 0x8B64 /* GL_SAMPLER_2D_RECT_SHADOW_ARB */: return "GL_SAMPLER_2D_RECT_SHADOW_ARB (0x8B64)";
+//case 0x8B80 /* GL_OBJECT_DELETE_STATUS_ARB */: return "GL_OBJECT_DELETE_STATUS_ARB (0x8B80)";
+//case 0x8B81 /* GL_OBJECT_COMPILE_STATUS_ARB */: return "GL_OBJECT_COMPILE_STATUS_ARB (0x8B81)";
+//case 0x8B82 /* GL_OBJECT_LINK_STATUS_ARB */: return "GL_OBJECT_LINK_STATUS_ARB (0x8B82)";
+//case 0x8B83 /* GL_OBJECT_VALIDATE_STATUS_ARB */: return "GL_OBJECT_VALIDATE_STATUS_ARB (0x8B83)";
+//case 0x8B84 /* GL_OBJECT_INFO_LOG_LENGTH_ARB */: return "GL_OBJECT_INFO_LOG_LENGTH_ARB (0x8B84)";
+//case 0x8B85 /* GL_OBJECT_ATTACHED_OBJECTS_ARB */: return "GL_OBJECT_ATTACHED_OBJECTS_ARB (0x8B85)";
+//case 0x8B86 /* GL_OBJECT_ACTIVE_UNIFORMS_ARB */: return "GL_OBJECT_ACTIVE_UNIFORMS_ARB (0x8B86)";
+//case 0x8B87 /* GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB */: return "GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB (0x8B87)";
+//case 0x8B88 /* GL_OBJECT_SHADER_SOURCE_LENGTH_ARB */: return "GL_OBJECT_SHADER_SOURCE_LENGTH_ARB (0x8B88)";
+
+
+
+
+
+
+
+
+/* ------------------------ GL_ARB_shader_precision ------------------------ */
+
+
+
+
+
+
+
+
+/* ---------------------- GL_ARB_shader_stencil_export --------------------- */
+
+
+
+
+
+
+
+
+/* ------------------ GL_ARB_shader_storage_buffer_object ------------------ */
+
+
+
+
+//case 0x2000 /* GL_SHADER_STORAGE_BARRIER_BIT */: return "GL_SHADER_STORAGE_BARRIER_BIT (0x2000)";
+//case 0x8F39 /* GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES */: return "GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES (0x8F39)";
+case 0x90D2 /* GL_SHADER_STORAGE_BUFFER */: return "GL_SHADER_STORAGE_BUFFER (0x90D2)";
+case 0x90D3 /* GL_SHADER_STORAGE_BUFFER_BINDING */: return "GL_SHADER_STORAGE_BUFFER_BINDING (0x90D3)";
+case 0x90D4 /* GL_SHADER_STORAGE_BUFFER_START */: return "GL_SHADER_STORAGE_BUFFER_START (0x90D4)";
+case 0x90D5 /* GL_SHADER_STORAGE_BUFFER_SIZE */: return "GL_SHADER_STORAGE_BUFFER_SIZE (0x90D5)";
+case 0x90D6 /* GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS */: return "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS (0x90D6)";
+case 0x90D7 /* GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS */: return "GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS (0x90D7)";
+case 0x90D8 /* GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS */: return "GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS (0x90D8)";
+case 0x90D9 /* GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS */: return "GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS (0x90D9)";
+case 0x90DA /* GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS */: return "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS (0x90DA)";
+case 0x90DB /* GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS */: return "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS (0x90DB)";
+case 0x90DC /* GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS */: return "GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS (0x90DC)";
+case 0x90DD /* GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS */: return "GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS (0x90DD)";
+case 0x90DE /* GL_MAX_SHADER_STORAGE_BLOCK_SIZE */: return "GL_MAX_SHADER_STORAGE_BLOCK_SIZE (0x90DE)";
+case 0x90DF /* GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT */: return "GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT (0x90DF)";/* ------------------------ GL_ARB_shader_subroutine ----------------------- */
+
+
+
+
+case 0x8DE5 /* GL_ACTIVE_SUBROUTINES */: return "GL_ACTIVE_SUBROUTINES (0x8DE5)";
+case 0x8DE6 /* GL_ACTIVE_SUBROUTINE_UNIFORMS */: return "GL_ACTIVE_SUBROUTINE_UNIFORMS (0x8DE6)";
+case 0x8DE7 /* GL_MAX_SUBROUTINES */: return "GL_MAX_SUBROUTINES (0x8DE7)";
+case 0x8DE8 /* GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS */: return "GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS (0x8DE8)";
+case 0x8E47 /* GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS */: return "GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS (0x8E47)";
+case 0x8E48 /* GL_ACTIVE_SUBROUTINE_MAX_LENGTH */: return "GL_ACTIVE_SUBROUTINE_MAX_LENGTH (0x8E48)";
+case 0x8E49 /* GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH */: return "GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH (0x8E49)";
+case 0x8E4A /* GL_NUM_COMPATIBLE_SUBROUTINES */: return "GL_NUM_COMPATIBLE_SUBROUTINES (0x8E4A)";
+case 0x8E4B /* GL_COMPATIBLE_SUBROUTINES */: return "GL_COMPATIBLE_SUBROUTINES (0x8E4B)";
+
+
+
+/* ----------------------- GL_ARB_shader_texture_lod ----------------------- */
+
+
+
+
+
+
+
+
+/* ---------------------- GL_ARB_shading_language_100 ---------------------- */
+
+
+
+
+//case 0x8B8C /* GL_SHADING_LANGUAGE_VERSION_ARB */: return "GL_SHADING_LANGUAGE_VERSION_ARB (0x8B8C)";
+
+
+
+
+
+/* -------------------- GL_ARB_shading_language_420pack -------------------- */
+
+
+
+
+
+
+
+
+/* -------------------- GL_ARB_shading_language_include -------------------- */
+
+
+
+
+case 0x8DAE /* GL_SHADER_INCLUDE_ARB */: return "GL_SHADER_INCLUDE_ARB (0x8DAE)";
+case 0x8DE9 /* GL_NAMED_STRING_LENGTH_ARB */: return "GL_NAMED_STRING_LENGTH_ARB (0x8DE9)";
+case 0x8DEA /* GL_NAMED_STRING_TYPE_ARB */: return "GL_NAMED_STRING_TYPE_ARB (0x8DEA)";/* -------------------- GL_ARB_shading_language_packing -------------------- */
+
+
+
+
+
+
+
+
+/* ----------------------------- GL_ARB_shadow ----------------------------- */
+
+
+
+
+//case 0x884C /* GL_TEXTURE_COMPARE_MODE_ARB */: return "GL_TEXTURE_COMPARE_MODE_ARB (0x884C)";
+//case 0x884D /* GL_TEXTURE_COMPARE_FUNC_ARB */: return "GL_TEXTURE_COMPARE_FUNC_ARB (0x884D)";
+//case 0x884E /* GL_COMPARE_R_TO_TEXTURE_ARB */: return "GL_COMPARE_R_TO_TEXTURE_ARB (0x884E)";
+
+
+
+
+
+/* ------------------------- GL_ARB_shadow_ambient ------------------------- */
+
+
+
+
+case 0x80BF /* GL_TEXTURE_COMPARE_FAIL_VALUE_ARB */: return "GL_TEXTURE_COMPARE_FAIL_VALUE_ARB (0x80BF)";
+
+
+
+
+
+/* ------------------------ GL_ARB_stencil_texturing ----------------------- */
+
+
+
+
+case 0x90EA /* GL_DEPTH_STENCIL_TEXTURE_MODE */: return "GL_DEPTH_STENCIL_TEXTURE_MODE (0x90EA)";
+
+
+
+
+
+/* ------------------------------ GL_ARB_sync ------------------------------ */
+
+
+
+
+//case 0x00000001 /* GL_SYNC_FLUSH_COMMANDS_BIT */: return "GL_SYNC_FLUSH_COMMANDS_BIT (0x00000001)";
+case 0x9111 /* GL_MAX_SERVER_WAIT_TIMEOUT */: return "GL_MAX_SERVER_WAIT_TIMEOUT (0x9111)";
+case 0x9112 /* GL_OBJECT_TYPE */: return "GL_OBJECT_TYPE (0x9112)";
+case 0x9113 /* GL_SYNC_CONDITION */: return "GL_SYNC_CONDITION (0x9113)";
+case 0x9114 /* GL_SYNC_STATUS */: return "GL_SYNC_STATUS (0x9114)";
+case 0x9115 /* GL_SYNC_FLAGS */: return "GL_SYNC_FLAGS (0x9115)";
+case 0x9116 /* GL_SYNC_FENCE */: return "GL_SYNC_FENCE (0x9116)";
+case 0x9117 /* GL_SYNC_GPU_COMMANDS_COMPLETE */: return "GL_SYNC_GPU_COMMANDS_COMPLETE (0x9117)";
+case 0x9118 /* GL_UNSIGNALED */: return "GL_UNSIGNALED (0x9118)";
+case 0x9119 /* GL_SIGNALED */: return "GL_SIGNALED (0x9119)";
+case 0x911A /* GL_ALREADY_SIGNALED */: return "GL_ALREADY_SIGNALED (0x911A)";
+case 0x911B /* GL_TIMEOUT_EXPIRED */: return "GL_TIMEOUT_EXPIRED (0x911B)";
+case 0x911C /* GL_CONDITION_SATISFIED */: return "GL_CONDITION_SATISFIED (0x911C)";
+case 0x911D /* GL_WAIT_FAILED */: return "GL_WAIT_FAILED (0x911D)";
+//case 0xFFFFFFFFFFFFFFFF /* GL_TIMEOUT_IGNORED */: return "GL_TIMEOUT_IGNORED (0xFFFFFFFFFFFFFFFF)";
+
+/* ----------------------- GL_ARB_tessellation_shader ---------------------- */
+
+
+
+
+case 0xE /* GL_PATCHES */: return "GL_PATCHES (0xE)";
+case 0x84F0 /* GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER */: return "GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER (0x84F0)";
+case 0x84F1 /* GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER */: return "GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER (0x84F1)";
+case 0x886C /* GL_MAX_TESS_CONTROL_INPUT_COMPONENTS */: return "GL_MAX_TESS_CONTROL_INPUT_COMPONENTS (0x886C)";
+case 0x886D /* GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS */: return "GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS (0x886D)";
+case 0x8E1E /* GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS */: return "GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS (0x8E1E)";
+case 0x8E1F /* GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS */: return "GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS (0x8E1F)";
+case 0x8E72 /* GL_PATCH_VERTICES */: return "GL_PATCH_VERTICES (0x8E72)";
+case 0x8E73 /* GL_PATCH_DEFAULT_INNER_LEVEL */: return "GL_PATCH_DEFAULT_INNER_LEVEL (0x8E73)";
+case 0x8E74 /* GL_PATCH_DEFAULT_OUTER_LEVEL */: return "GL_PATCH_DEFAULT_OUTER_LEVEL (0x8E74)";
+case 0x8E75 /* GL_TESS_CONTROL_OUTPUT_VERTICES */: return "GL_TESS_CONTROL_OUTPUT_VERTICES (0x8E75)";
+case 0x8E76 /* GL_TESS_GEN_MODE */: return "GL_TESS_GEN_MODE (0x8E76)";
+case 0x8E77 /* GL_TESS_GEN_SPACING */: return "GL_TESS_GEN_SPACING (0x8E77)";
+case 0x8E78 /* GL_TESS_GEN_VERTEX_ORDER */: return "GL_TESS_GEN_VERTEX_ORDER (0x8E78)";
+case 0x8E79 /* GL_TESS_GEN_POINT_MODE */: return "GL_TESS_GEN_POINT_MODE (0x8E79)";
+case 0x8E7A /* GL_ISOLINES */: return "GL_ISOLINES (0x8E7A)";
+case 0x8E7B /* GL_FRACTIONAL_ODD */: return "GL_FRACTIONAL_ODD (0x8E7B)";
+case 0x8E7C /* GL_FRACTIONAL_EVEN */: return "GL_FRACTIONAL_EVEN (0x8E7C)";
+case 0x8E7D /* GL_MAX_PATCH_VERTICES */: return "GL_MAX_PATCH_VERTICES (0x8E7D)";
+case 0x8E7E /* GL_MAX_TESS_GEN_LEVEL */: return "GL_MAX_TESS_GEN_LEVEL (0x8E7E)";
+case 0x8E7F /* GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS */: return "GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS (0x8E7F)";
+case 0x8E80 /* GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS */: return "GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS (0x8E80)";
+case 0x8E81 /* GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS */: return "GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS (0x8E81)";
+case 0x8E82 /* GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS */: return "GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS (0x8E82)";
+case 0x8E83 /* GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS */: return "GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS (0x8E83)";
+case 0x8E84 /* GL_MAX_TESS_PATCH_COMPONENTS */: return "GL_MAX_TESS_PATCH_COMPONENTS (0x8E84)";
+case 0x8E85 /* GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS */: return "GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS (0x8E85)";
+case 0x8E86 /* GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS */: return "GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS (0x8E86)";
+case 0x8E87 /* GL_TESS_EVALUATION_SHADER */: return "GL_TESS_EVALUATION_SHADER (0x8E87)";
+case 0x8E88 /* GL_TESS_CONTROL_SHADER */: return "GL_TESS_CONTROL_SHADER (0x8E88)";
+case 0x8E89 /* GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS */: return "GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS (0x8E89)";
+case 0x8E8A /* GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS */: return "GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS (0x8E8A)";
+
+/* ---------------------- GL_ARB_texture_border_clamp ---------------------- */
+
+
+
+
+//case 0x812D /* GL_CLAMP_TO_BORDER_ARB */: return "GL_CLAMP_TO_BORDER_ARB (0x812D)";
+
+
+
+
+
+/* ---------------------- GL_ARB_texture_buffer_object --------------------- */
+
+
+
+
+//case 0x8C2A /* GL_TEXTURE_BUFFER_ARB */: return "GL_TEXTURE_BUFFER_ARB (0x8C2A)";
+//case 0x8C2B /* GL_MAX_TEXTURE_BUFFER_SIZE_ARB */: return "GL_MAX_TEXTURE_BUFFER_SIZE_ARB (0x8C2B)";
+//case 0x8C2C /* GL_TEXTURE_BINDING_BUFFER_ARB */: return "GL_TEXTURE_BINDING_BUFFER_ARB (0x8C2C)";
+//case 0x8C2D /* GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB */: return "GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB (0x8C2D)";
+//case 0x8C2E /* GL_TEXTURE_BUFFER_FORMAT_ARB */: return "GL_TEXTURE_BUFFER_FORMAT_ARB (0x8C2E)";/* ------------------- GL_ARB_texture_buffer_object_rgb32 ------------------ */
+
+
+
+
+
+
+
+
+/* ---------------------- GL_ARB_texture_buffer_range ---------------------- */
+
+
+
+
+case 0x919D /* GL_TEXTURE_BUFFER_OFFSET */: return "GL_TEXTURE_BUFFER_OFFSET (0x919D)";
+case 0x919E /* GL_TEXTURE_BUFFER_SIZE */: return "GL_TEXTURE_BUFFER_SIZE (0x919E)";
+case 0x919F /* GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT */: return "GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT (0x919F)";
+
+/* ----------------------- GL_ARB_texture_compression ---------------------- */
+
+
+
+
+//case 0x84E9 /* GL_COMPRESSED_ALPHA_ARB */: return "GL_COMPRESSED_ALPHA_ARB (0x84E9)";
+//case 0x84EA /* GL_COMPRESSED_LUMINANCE_ARB */: return "GL_COMPRESSED_LUMINANCE_ARB (0x84EA)";
+//case 0x84EB /* GL_COMPRESSED_LUMINANCE_ALPHA_ARB */: return "GL_COMPRESSED_LUMINANCE_ALPHA_ARB (0x84EB)";
+//case 0x84EC /* GL_COMPRESSED_INTENSITY_ARB */: return "GL_COMPRESSED_INTENSITY_ARB (0x84EC)";
+//case 0x84ED /* GL_COMPRESSED_RGB_ARB */: return "GL_COMPRESSED_RGB_ARB (0x84ED)";
+//case 0x84EE /* GL_COMPRESSED_RGBA_ARB */: return "GL_COMPRESSED_RGBA_ARB (0x84EE)";
+//case 0x84EF /* GL_TEXTURE_COMPRESSION_HINT_ARB */: return "GL_TEXTURE_COMPRESSION_HINT_ARB (0x84EF)";
+//case 0x86A0 /* GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB */: return "GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB (0x86A0)";
+//case 0x86A1 /* GL_TEXTURE_COMPRESSED_ARB */: return "GL_TEXTURE_COMPRESSED_ARB (0x86A1)";
+//case 0x86A2 /* GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB */: return "GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB (0x86A2)";
+//case 0x86A3 /* GL_COMPRESSED_TEXTURE_FORMATS_ARB */: return "GL_COMPRESSED_TEXTURE_FORMATS_ARB (0x86A3)";
+
+/* -------------------- GL_ARB_texture_compression_bptc -------------------- */
+
+
+
+
+//case 0x8E8C /* GL_COMPRESSED_RGBA_BPTC_UNORM_ARB */: return "GL_COMPRESSED_RGBA_BPTC_UNORM_ARB (0x8E8C)";
+//case 0x8E8D /* GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB */: return "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB (0x8E8D)";
+//case 0x8E8E /* GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB */: return "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB (0x8E8E)";
+//case 0x8E8F /* GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB */: return "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB (0x8E8F)";
+
+
+
+
+
+/* -------------------- GL_ARB_texture_compression_rgtc -------------------- */
+
+
+
+
+case 0x8DBB /* GL_COMPRESSED_RED_RGTC1 */: return "GL_COMPRESSED_RED_RGTC1 (0x8DBB)";
+case 0x8DBC /* GL_COMPRESSED_SIGNED_RED_RGTC1 */: return "GL_COMPRESSED_SIGNED_RED_RGTC1 (0x8DBC)";
+case 0x8DBD /* GL_COMPRESSED_RG_RGTC2 */: return "GL_COMPRESSED_RG_RGTC2 (0x8DBD)";
+case 0x8DBE /* GL_COMPRESSED_SIGNED_RG_RGTC2 */: return "GL_COMPRESSED_SIGNED_RG_RGTC2 (0x8DBE)";
+
+
+
+
+
+/* ------------------------ GL_ARB_texture_cube_map ------------------------ */
+
+
+
+
+//case 0x8511 /* GL_NORMAL_MAP_ARB */: return "GL_NORMAL_MAP_ARB (0x8511)";
+//case 0x8512 /* GL_REFLECTION_MAP_ARB */: return "GL_REFLECTION_MAP_ARB (0x8512)";
+//case 0x8513 /* GL_TEXTURE_CUBE_MAP_ARB */: return "GL_TEXTURE_CUBE_MAP_ARB (0x8513)";
+//case 0x8514 /* GL_TEXTURE_BINDING_CUBE_MAP_ARB */: return "GL_TEXTURE_BINDING_CUBE_MAP_ARB (0x8514)";
+//case 0x8515 /* GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB */: return "GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB (0x8515)";
+//case 0x8516 /* GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB */: return "GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB (0x8516)";
+//case 0x8517 /* GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB */: return "GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB (0x8517)";
+//case 0x8518 /* GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB */: return "GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB (0x8518)";
+//case 0x8519 /* GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB */: return "GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB (0x8519)";
+//case 0x851A /* GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB */: return "GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB (0x851A)";
+//case 0x851B /* GL_PROXY_TEXTURE_CUBE_MAP_ARB */: return "GL_PROXY_TEXTURE_CUBE_MAP_ARB (0x851B)";
+//case 0x851C /* GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB */: return "GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB (0x851C)";
+
+
+
+
+
+/* --------------------- GL_ARB_texture_cube_map_array --------------------- */
+
+
+
+
+//case 0x9009 /* GL_TEXTURE_CUBE_MAP_ARRAY_ARB */: return "GL_TEXTURE_CUBE_MAP_ARRAY_ARB (0x9009)";
+//case 0x900A /* GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB */: return "GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB (0x900A)";
+//case 0x900B /* GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB */: return "GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB (0x900B)";
+//case 0x900C /* GL_SAMPLER_CUBE_MAP_ARRAY_ARB */: return "GL_SAMPLER_CUBE_MAP_ARRAY_ARB (0x900C)";
+//case 0x900D /* GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB */: return "GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB (0x900D)";
+//case 0x900E /* GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB */: return "GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB (0x900E)";
+//case 0x900F /* GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB */: return "GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB (0x900F)";
+
+
+
+
+
+/* ------------------------- GL_ARB_texture_env_add ------------------------ */
+
+
+
+
+
+
+
+
+/* ----------------------- GL_ARB_texture_env_combine ---------------------- */
+
+
+
+
+//case 0x84E7 /* GL_SUBTRACT_ARB */: return "GL_SUBTRACT_ARB (0x84E7)";
+//case 0x8570 /* GL_COMBINE_ARB */: return "GL_COMBINE_ARB (0x8570)";
+//case 0x8571 /* GL_COMBINE_RGB_ARB */: return "GL_COMBINE_RGB_ARB (0x8571)";
+//case 0x8572 /* GL_COMBINE_ALPHA_ARB */: return "GL_COMBINE_ALPHA_ARB (0x8572)";
+//case 0x8573 /* GL_RGB_SCALE_ARB */: return "GL_RGB_SCALE_ARB (0x8573)";
+//case 0x8574 /* GL_ADD_SIGNED_ARB */: return "GL_ADD_SIGNED_ARB (0x8574)";
+//case 0x8575 /* GL_INTERPOLATE_ARB */: return "GL_INTERPOLATE_ARB (0x8575)";
+//case 0x8576 /* GL_CONSTANT_ARB */: return "GL_CONSTANT_ARB (0x8576)";
+//case 0x8577 /* GL_PRIMARY_COLOR_ARB */: return "GL_PRIMARY_COLOR_ARB (0x8577)";
+//case 0x8578 /* GL_PREVIOUS_ARB */: return "GL_PREVIOUS_ARB (0x8578)";
+//case 0x8580 /* GL_SOURCE0_RGB_ARB */: return "GL_SOURCE0_RGB_ARB (0x8580)";
+//case 0x8581 /* GL_SOURCE1_RGB_ARB */: return "GL_SOURCE1_RGB_ARB (0x8581)";
+//case 0x8582 /* GL_SOURCE2_RGB_ARB */: return "GL_SOURCE2_RGB_ARB (0x8582)";
+//case 0x8588 /* GL_SOURCE0_ALPHA_ARB */: return "GL_SOURCE0_ALPHA_ARB (0x8588)";
+//case 0x8589 /* GL_SOURCE1_ALPHA_ARB */: return "GL_SOURCE1_ALPHA_ARB (0x8589)";
+//case 0x858A /* GL_SOURCE2_ALPHA_ARB */: return "GL_SOURCE2_ALPHA_ARB (0x858A)";
+//case 0x8590 /* GL_OPERAND0_RGB_ARB */: return "GL_OPERAND0_RGB_ARB (0x8590)";
+//case 0x8591 /* GL_OPERAND1_RGB_ARB */: return "GL_OPERAND1_RGB_ARB (0x8591)";
+//case 0x8592 /* GL_OPERAND2_RGB_ARB */: return "GL_OPERAND2_RGB_ARB (0x8592)";
+//case 0x8598 /* GL_OPERAND0_ALPHA_ARB */: return "GL_OPERAND0_ALPHA_ARB (0x8598)";
+//case 0x8599 /* GL_OPERAND1_ALPHA_ARB */: return "GL_OPERAND1_ALPHA_ARB (0x8599)";
+//case 0x859A /* GL_OPERAND2_ALPHA_ARB */: return "GL_OPERAND2_ALPHA_ARB (0x859A)";
+
+
+
+
+
+/* ---------------------- GL_ARB_texture_env_crossbar ---------------------- */
+
+
+
+
+
+
+
+
+/* ------------------------ GL_ARB_texture_env_dot3 ------------------------ */
+
+
+
+
+//case 0x86AE /* GL_DOT3_RGB_ARB */: return "GL_DOT3_RGB_ARB (0x86AE)";
+//case 0x86AF /* GL_DOT3_RGBA_ARB */: return "GL_DOT3_RGBA_ARB (0x86AF)";
+
+
+
+
+
+/* -------------------------- GL_ARB_texture_float ------------------------- */
+
+
+
+
+//case 0x8815 /* GL_RGB32F_ARB */: return "GL_RGB32F_ARB (0x8815)";
+//case 0x8816 /* GL_ALPHA32F_ARB */: return "GL_ALPHA32F_ARB (0x8816)";
+//case 0x8817 /* GL_INTENSITY32F_ARB */: return "GL_INTENSITY32F_ARB (0x8817)";
+//case 0x8818 /* GL_LUMINANCE32F_ARB */: return "GL_LUMINANCE32F_ARB (0x8818)";
+//case 0x8819 /* GL_LUMINANCE_ALPHA32F_ARB */: return "GL_LUMINANCE_ALPHA32F_ARB (0x8819)";
+//case 0x881A /* GL_RGBA16F_ARB */: return "GL_RGBA16F_ARB (0x881A)";
+//case 0x881B /* GL_RGB16F_ARB */: return "GL_RGB16F_ARB (0x881B)";
+//case 0x881C /* GL_ALPHA16F_ARB */: return "GL_ALPHA16F_ARB (0x881C)";
+//case 0x881D /* GL_INTENSITY16F_ARB */: return "GL_INTENSITY16F_ARB (0x881D)";
+//case 0x881E /* GL_LUMINANCE16F_ARB */: return "GL_LUMINANCE16F_ARB (0x881E)";
+//case 0x881F /* GL_LUMINANCE_ALPHA16F_ARB */: return "GL_LUMINANCE_ALPHA16F_ARB (0x881F)";
+//case 0x8C10 /* GL_TEXTURE_RED_TYPE_ARB */: return "GL_TEXTURE_RED_TYPE_ARB (0x8C10)";
+//case 0x8C11 /* GL_TEXTURE_GREEN_TYPE_ARB */: return "GL_TEXTURE_GREEN_TYPE_ARB (0x8C11)";
+//case 0x8C12 /* GL_TEXTURE_BLUE_TYPE_ARB */: return "GL_TEXTURE_BLUE_TYPE_ARB (0x8C12)";
+//case 0x8C13 /* GL_TEXTURE_ALPHA_TYPE_ARB */: return "GL_TEXTURE_ALPHA_TYPE_ARB (0x8C13)";
+//case 0x8C14 /* GL_TEXTURE_LUMINANCE_TYPE_ARB */: return "GL_TEXTURE_LUMINANCE_TYPE_ARB (0x8C14)";
+//case 0x8C15 /* GL_TEXTURE_INTENSITY_TYPE_ARB */: return "GL_TEXTURE_INTENSITY_TYPE_ARB (0x8C15)";
+//case 0x8C16 /* GL_TEXTURE_DEPTH_TYPE_ARB */: return "GL_TEXTURE_DEPTH_TYPE_ARB (0x8C16)";
+//case 0x8C17 /* GL_UNSIGNED_NORMALIZED_ARB */: return "GL_UNSIGNED_NORMALIZED_ARB (0x8C17)";
+
+
+
+
+
+/* ------------------------- GL_ARB_texture_gather ------------------------- */
+
+
+
+
+//case 0x8E5E /* GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB */: return "GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB (0x8E5E)";
+//case 0x8E5F /* GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB */: return "GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB (0x8E5F)";
+//case 0x8F9F /* GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB */: return "GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB (0x8F9F)";
+
+
+
+
+
+/* --------------------- GL_ARB_texture_mirrored_repeat -------------------- */
+
+
+
+
+//case 0x8370 /* GL_MIRRORED_REPEAT_ARB */: return "GL_MIRRORED_REPEAT_ARB (0x8370)";
+
+
+
+
+
+/* ----------------------- GL_ARB_texture_multisample ---------------------- */
+
+
+
+
+case 0x8E50 /* GL_SAMPLE_POSITION */: return "GL_SAMPLE_POSITION (0x8E50)";
+case 0x8E51 /* GL_SAMPLE_MASK */: return "GL_SAMPLE_MASK (0x8E51)";
+case 0x8E52 /* GL_SAMPLE_MASK_VALUE */: return "GL_SAMPLE_MASK_VALUE (0x8E52)";
+case 0x8E59 /* GL_MAX_SAMPLE_MASK_WORDS */: return "GL_MAX_SAMPLE_MASK_WORDS (0x8E59)";
+//case 0x9100 /* GL_TEXTURE_2D_MULTISAMPLE */: return "GL_TEXTURE_2D_MULTISAMPLE (0x9100)";
+case 0x9101 /* GL_PROXY_TEXTURE_2D_MULTISAMPLE */: return "GL_PROXY_TEXTURE_2D_MULTISAMPLE (0x9101)";
+//case 0x9102 /* GL_TEXTURE_2D_MULTISAMPLE_ARRAY */: return "GL_TEXTURE_2D_MULTISAMPLE_ARRAY (0x9102)";
+case 0x9103 /* GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY */: return "GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY (0x9103)";
+case 0x9104 /* GL_TEXTURE_BINDING_2D_MULTISAMPLE */: return "GL_TEXTURE_BINDING_2D_MULTISAMPLE (0x9104)";
+case 0x9105 /* GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY */: return "GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY (0x9105)";
+case 0x9106 /* GL_TEXTURE_SAMPLES */: return "GL_TEXTURE_SAMPLES (0x9106)";
+case 0x9107 /* GL_TEXTURE_FIXED_SAMPLE_LOCATIONS */: return "GL_TEXTURE_FIXED_SAMPLE_LOCATIONS (0x9107)";
+case 0x9108 /* GL_SAMPLER_2D_MULTISAMPLE */: return "GL_SAMPLER_2D_MULTISAMPLE (0x9108)";
+case 0x9109 /* GL_INT_SAMPLER_2D_MULTISAMPLE */: return "GL_INT_SAMPLER_2D_MULTISAMPLE (0x9109)";
+case 0x910A /* GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE */: return "GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE (0x910A)";
+case 0x910B /* GL_SAMPLER_2D_MULTISAMPLE_ARRAY */: return "GL_SAMPLER_2D_MULTISAMPLE_ARRAY (0x910B)";
+case 0x910C /* GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY */: return "GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY (0x910C)";
+case 0x910D /* GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY */: return "GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY (0x910D)";
+case 0x910E /* GL_MAX_COLOR_TEXTURE_SAMPLES */: return "GL_MAX_COLOR_TEXTURE_SAMPLES (0x910E)";
+case 0x910F /* GL_MAX_DEPTH_TEXTURE_SAMPLES */: return "GL_MAX_DEPTH_TEXTURE_SAMPLES (0x910F)";
+case 0x9110 /* GL_MAX_INTEGER_SAMPLES */: return "GL_MAX_INTEGER_SAMPLES (0x9110)";
+
+
+
+
+
+/* -------------------- GL_ARB_texture_non_power_of_two -------------------- */
+
+
+
+
+
+
+
+
+/* ---------------------- GL_ARB_texture_query_levels ---------------------- */
+
+
+
+
+
+
+
+
+/* ------------------------ GL_ARB_texture_query_lod ----------------------- */
+
+
+
+
+
+
+
+
+/* ------------------------ GL_ARB_texture_rectangle ----------------------- */
+
+
+
+
+//case 0x84F5 /* GL_TEXTURE_RECTANGLE_ARB */: return "GL_TEXTURE_RECTANGLE_ARB (0x84F5)";
+//case 0x84F6 /* GL_TEXTURE_BINDING_RECTANGLE_ARB */: return "GL_TEXTURE_BINDING_RECTANGLE_ARB (0x84F6)";
+//case 0x84F7 /* GL_PROXY_TEXTURE_RECTANGLE_ARB */: return "GL_PROXY_TEXTURE_RECTANGLE_ARB (0x84F7)";
+//case 0x84F8 /* GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB */: return "GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB (0x84F8)";
+//case 0x8B63 /* GL_SAMPLER_2D_RECT_ARB */: return "GL_SAMPLER_2D_RECT_ARB (0x8B63)";
+//case 0x8B64 /* GL_SAMPLER_2D_RECT_SHADOW_ARB */: return "GL_SAMPLER_2D_RECT_SHADOW_ARB (0x8B64)";
+
+
+
+
+
+/* --------------------------- GL_ARB_texture_rg --------------------------- */
+
+
+
+
+//case 0x8225 /* GL_COMPRESSED_RED */: return "GL_COMPRESSED_RED (0x8225)";
+//case 0x8226 /* GL_COMPRESSED_RG */: return "GL_COMPRESSED_RG (0x8226)";
+case 0x8227 /* GL_RG */: return "GL_RG (0x8227)";
+case 0x8228 /* GL_RG_INTEGER */: return "GL_RG_INTEGER (0x8228)";
+case 0x8229 /* GL_R8 */: return "GL_R8 (0x8229)";
+case 0x822A /* GL_R16 */: return "GL_R16 (0x822A)";
+case 0x822B /* GL_RG8 */: return "GL_RG8 (0x822B)";
+case 0x822C /* GL_RG16 */: return "GL_RG16 (0x822C)";
+case 0x822D /* GL_R16F */: return "GL_R16F (0x822D)";
+case 0x822E /* GL_R32F */: return "GL_R32F (0x822E)";
+case 0x822F /* GL_RG16F */: return "GL_RG16F (0x822F)";
+case 0x8230 /* GL_RG32F */: return "GL_RG32F (0x8230)";
+case 0x8231 /* GL_R8I */: return "GL_R8I (0x8231)";
+case 0x8232 /* GL_R8UI */: return "GL_R8UI (0x8232)";
+case 0x8233 /* GL_R16I */: return "GL_R16I (0x8233)";
+case 0x8234 /* GL_R16UI */: return "GL_R16UI (0x8234)";
+case 0x8235 /* GL_R32I */: return "GL_R32I (0x8235)";
+case 0x8236 /* GL_R32UI */: return "GL_R32UI (0x8236)";
+case 0x8237 /* GL_RG8I */: return "GL_RG8I (0x8237)";
+case 0x8238 /* GL_RG8UI */: return "GL_RG8UI (0x8238)";
+case 0x8239 /* GL_RG16I */: return "GL_RG16I (0x8239)";
+case 0x823A /* GL_RG16UI */: return "GL_RG16UI (0x823A)";
+case 0x823B /* GL_RG32I */: return "GL_RG32I (0x823B)";
+case 0x823C /* GL_RG32UI */: return "GL_RG32UI (0x823C)";
+
+
+
+
+
+/* ----------------------- GL_ARB_texture_rgb10_a2ui ----------------------- */
+
+
+
+
+//case 0x906F /* GL_RGB10_A2UI */: return "GL_RGB10_A2UI (0x906F)";
+
+
+
+
+
+/* ------------------------- GL_ARB_texture_storage ------------------------ */
+
+
+
+
+case 0x912F /* GL_TEXTURE_IMMUTABLE_FORMAT */: return "GL_TEXTURE_IMMUTABLE_FORMAT (0x912F)";/* ------------------- GL_ARB_texture_storage_multisample ------------------ */
+
+
+
+
+
+
+
+
+/* ------------------------- GL_ARB_texture_swizzle ------------------------ */
+
+
+
+
+//case 0x8E42 /* GL_TEXTURE_SWIZZLE_R */: return "GL_TEXTURE_SWIZZLE_R (0x8E42)";
+//case 0x8E43 /* GL_TEXTURE_SWIZZLE_G */: return "GL_TEXTURE_SWIZZLE_G (0x8E43)";
+//case 0x8E44 /* GL_TEXTURE_SWIZZLE_B */: return "GL_TEXTURE_SWIZZLE_B (0x8E44)";
+//case 0x8E45 /* GL_TEXTURE_SWIZZLE_A */: return "GL_TEXTURE_SWIZZLE_A (0x8E45)";
+//case 0x8E46 /* GL_TEXTURE_SWIZZLE_RGBA */: return "GL_TEXTURE_SWIZZLE_RGBA (0x8E46)";
+
+
+
+
+
+/* -------------------------- GL_ARB_texture_view -------------------------- */
+
+
+
+
+case 0x82DB /* GL_TEXTURE_VIEW_MIN_LEVEL */: return "GL_TEXTURE_VIEW_MIN_LEVEL (0x82DB)";
+case 0x82DC /* GL_TEXTURE_VIEW_NUM_LEVELS */: return "GL_TEXTURE_VIEW_NUM_LEVELS (0x82DC)";
+case 0x82DD /* GL_TEXTURE_VIEW_MIN_LAYER */: return "GL_TEXTURE_VIEW_MIN_LAYER (0x82DD)";
+case 0x82DE /* GL_TEXTURE_VIEW_NUM_LAYERS */: return "GL_TEXTURE_VIEW_NUM_LAYERS (0x82DE)";
+case 0x82DF /* GL_TEXTURE_IMMUTABLE_LEVELS */: return "GL_TEXTURE_IMMUTABLE_LEVELS (0x82DF)";/* --------------------------- GL_ARB_timer_query -------------------------- */
+
+
+
+
+case 0x88BF /* GL_TIME_ELAPSED */: return "GL_TIME_ELAPSED (0x88BF)";
+case 0x8E28 /* GL_TIMESTAMP */: return "GL_TIMESTAMP (0x8E28)";
+
+
+
+/* ----------------------- GL_ARB_transform_feedback2 ---------------------- */
+
+
+
+
+case 0x8E22 /* GL_TRANSFORM_FEEDBACK */: return "GL_TRANSFORM_FEEDBACK (0x8E22)";
+case 0x8E23 /* GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED */: return "GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED (0x8E23)";
+case 0x8E24 /* GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE */: return "GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE (0x8E24)";
+case 0x8E25 /* GL_TRANSFORM_FEEDBACK_BINDING */: return "GL_TRANSFORM_FEEDBACK_BINDING (0x8E25)";
+
+/* ----------------------- GL_ARB_transform_feedback3 ---------------------- */
+
+
+
+
+case 0x8E70 /* GL_MAX_TRANSFORM_FEEDBACK_BUFFERS */: return "GL_MAX_TRANSFORM_FEEDBACK_BUFFERS (0x8E70)";
+//case 0x8E71 /* GL_MAX_VERTEX_STREAMS */: return "GL_MAX_VERTEX_STREAMS (0x8E71)";
+
+
+
+
+
+/* ------------------ GL_ARB_transform_feedback_instanced ------------------ */
+
+
+
+
+/* ------------------------ GL_ARB_transpose_matrix ------------------------ */
+
+
+
+
+//case 0x84E3 /* GL_TRANSPOSE_MODELVIEW_MATRIX_ARB */: return "GL_TRANSPOSE_MODELVIEW_MATRIX_ARB (0x84E3)";
+//case 0x84E4 /* GL_TRANSPOSE_PROJECTION_MATRIX_ARB */: return "GL_TRANSPOSE_PROJECTION_MATRIX_ARB (0x84E4)";
+//case 0x84E5 /* GL_TRANSPOSE_TEXTURE_MATRIX_ARB */: return "GL_TRANSPOSE_TEXTURE_MATRIX_ARB (0x84E5)";
+//case 0x84E6 /* GL_TRANSPOSE_COLOR_MATRIX_ARB */: return "GL_TRANSPOSE_COLOR_MATRIX_ARB (0x84E6)";
+
+
+
+
+
+/* ---------------------- GL_ARB_uniform_buffer_object --------------------- */
+
+
+
+
+case 0x8A11 /* GL_UNIFORM_BUFFER */: return "GL_UNIFORM_BUFFER (0x8A11)";
+case 0x8A28 /* GL_UNIFORM_BUFFER_BINDING */: return "GL_UNIFORM_BUFFER_BINDING (0x8A28)";
+case 0x8A29 /* GL_UNIFORM_BUFFER_START */: return "GL_UNIFORM_BUFFER_START (0x8A29)";
+case 0x8A2A /* GL_UNIFORM_BUFFER_SIZE */: return "GL_UNIFORM_BUFFER_SIZE (0x8A2A)";
+case 0x8A2B /* GL_MAX_VERTEX_UNIFORM_BLOCKS */: return "GL_MAX_VERTEX_UNIFORM_BLOCKS (0x8A2B)";
+case 0x8A2C /* GL_MAX_GEOMETRY_UNIFORM_BLOCKS */: return "GL_MAX_GEOMETRY_UNIFORM_BLOCKS (0x8A2C)";
+case 0x8A2D /* GL_MAX_FRAGMENT_UNIFORM_BLOCKS */: return "GL_MAX_FRAGMENT_UNIFORM_BLOCKS (0x8A2D)";
+case 0x8A2E /* GL_MAX_COMBINED_UNIFORM_BLOCKS */: return "GL_MAX_COMBINED_UNIFORM_BLOCKS (0x8A2E)";
+case 0x8A2F /* GL_MAX_UNIFORM_BUFFER_BINDINGS */: return "GL_MAX_UNIFORM_BUFFER_BINDINGS (0x8A2F)";
+case 0x8A30 /* GL_MAX_UNIFORM_BLOCK_SIZE */: return "GL_MAX_UNIFORM_BLOCK_SIZE (0x8A30)";
+case 0x8A31 /* GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS */: return "GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS (0x8A31)";
+case 0x8A32 /* GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS */: return "GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS (0x8A32)";
+case 0x8A33 /* GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS */: return "GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS (0x8A33)";
+case 0x8A34 /* GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT */: return "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT (0x8A34)";
+case 0x8A35 /* GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH */: return "GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH (0x8A35)";
+case 0x8A36 /* GL_ACTIVE_UNIFORM_BLOCKS */: return "GL_ACTIVE_UNIFORM_BLOCKS (0x8A36)";
+case 0x8A37 /* GL_UNIFORM_TYPE */: return "GL_UNIFORM_TYPE (0x8A37)";
+case 0x8A38 /* GL_UNIFORM_SIZE */: return "GL_UNIFORM_SIZE (0x8A38)";
+case 0x8A39 /* GL_UNIFORM_NAME_LENGTH */: return "GL_UNIFORM_NAME_LENGTH (0x8A39)";
+case 0x8A3A /* GL_UNIFORM_BLOCK_INDEX */: return "GL_UNIFORM_BLOCK_INDEX (0x8A3A)";
+case 0x8A3B /* GL_UNIFORM_OFFSET */: return "GL_UNIFORM_OFFSET (0x8A3B)";
+case 0x8A3C /* GL_UNIFORM_ARRAY_STRIDE */: return "GL_UNIFORM_ARRAY_STRIDE (0x8A3C)";
+case 0x8A3D /* GL_UNIFORM_MATRIX_STRIDE */: return "GL_UNIFORM_MATRIX_STRIDE (0x8A3D)";
+case 0x8A3E /* GL_UNIFORM_IS_ROW_MAJOR */: return "GL_UNIFORM_IS_ROW_MAJOR (0x8A3E)";
+case 0x8A3F /* GL_UNIFORM_BLOCK_BINDING */: return "GL_UNIFORM_BLOCK_BINDING (0x8A3F)";
+case 0x8A40 /* GL_UNIFORM_BLOCK_DATA_SIZE */: return "GL_UNIFORM_BLOCK_DATA_SIZE (0x8A40)";
+case 0x8A41 /* GL_UNIFORM_BLOCK_NAME_LENGTH */: return "GL_UNIFORM_BLOCK_NAME_LENGTH (0x8A41)";
+case 0x8A42 /* GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS */: return "GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS (0x8A42)";
+case 0x8A43 /* GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES */: return "GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES (0x8A43)";
+case 0x8A44 /* GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER */: return "GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER (0x8A44)";
+case 0x8A45 /* GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER */: return "GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER (0x8A45)";
+case 0x8A46 /* GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER */: return "GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER (0x8A46)";
+//case 0xFFFFFFFF /* GL_INVALID_INDEX */: return "GL_INVALID_INDEX (0xFFFFFFFF)";
+
+
+
+
+
+
+
+/* ------------------------ GL_ARB_vertex_array_bgra ----------------------- */
+
+
+
+
+//case 0x80E1 /* GL_BGRA */: return "GL_BGRA (0x80E1)";
+
+
+
+
+
+/* ----------------------- GL_ARB_vertex_array_object ---------------------- */
+
+
+
+
+//case 0x85B5 /* GL_VERTEX_ARRAY_BINDING */: return "GL_VERTEX_ARRAY_BINDING (0x85B5)";
+
+
+
+
+
+/* ----------------------- GL_ARB_vertex_attrib_64bit ---------------------- */
+
+
+
+
+//case 0x8F46 /* GL_DOUBLE_MAT2 */: return "GL_DOUBLE_MAT2 (0x8F46)";
+//case 0x8F47 /* GL_DOUBLE_MAT3 */: return "GL_DOUBLE_MAT3 (0x8F47)";
+//case 0x8F48 /* GL_DOUBLE_MAT4 */: return "GL_DOUBLE_MAT4 (0x8F48)";
+//case 0x8FFC /* GL_DOUBLE_VEC2 */: return "GL_DOUBLE_VEC2 (0x8FFC)";
+//case 0x8FFD /* GL_DOUBLE_VEC3 */: return "GL_DOUBLE_VEC3 (0x8FFD)";
+//case 0x8FFE /* GL_DOUBLE_VEC4 */: return "GL_DOUBLE_VEC4 (0x8FFE)";
+
+
+
+
+
+
+
+/* ---------------------- GL_ARB_vertex_attrib_binding --------------------- */
+
+
+
+
+case 0x82D4 /* GL_VERTEX_ATTRIB_BINDING */: return "GL_VERTEX_ATTRIB_BINDING (0x82D4)";
+case 0x82D5 /* GL_VERTEX_ATTRIB_RELATIVE_OFFSET */: return "GL_VERTEX_ATTRIB_RELATIVE_OFFSET (0x82D5)";
+case 0x82D6 /* GL_VERTEX_BINDING_DIVISOR */: return "GL_VERTEX_BINDING_DIVISOR (0x82D6)";
+case 0x82D7 /* GL_VERTEX_BINDING_OFFSET */: return "GL_VERTEX_BINDING_OFFSET (0x82D7)";
+case 0x82D8 /* GL_VERTEX_BINDING_STRIDE */: return "GL_VERTEX_BINDING_STRIDE (0x82D8)";
+case 0x82D9 /* GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET */: return "GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET (0x82D9)";
+case 0x82DA /* GL_MAX_VERTEX_ATTRIB_BINDINGS */: return "GL_MAX_VERTEX_ATTRIB_BINDINGS (0x82DA)";/* -------------------------- GL_ARB_vertex_blend -------------------------- */
+
+
+
+
+//case 0x1700 /* GL_MODELVIEW0_ARB */: return "GL_MODELVIEW0_ARB (0x1700)";
+case 0x850A /* GL_MODELVIEW1_ARB */: return "GL_MODELVIEW1_ARB (0x850A)";
+case 0x86A4 /* GL_MAX_VERTEX_UNITS_ARB */: return "GL_MAX_VERTEX_UNITS_ARB (0x86A4)";
+case 0x86A5 /* GL_ACTIVE_VERTEX_UNITS_ARB */: return "GL_ACTIVE_VERTEX_UNITS_ARB (0x86A5)";
+case 0x86A6 /* GL_WEIGHT_SUM_UNITY_ARB */: return "GL_WEIGHT_SUM_UNITY_ARB (0x86A6)";
+case 0x86A7 /* GL_VERTEX_BLEND_ARB */: return "GL_VERTEX_BLEND_ARB (0x86A7)";
+case 0x86A8 /* GL_CURRENT_WEIGHT_ARB */: return "GL_CURRENT_WEIGHT_ARB (0x86A8)";
+case 0x86A9 /* GL_WEIGHT_ARRAY_TYPE_ARB */: return "GL_WEIGHT_ARRAY_TYPE_ARB (0x86A9)";
+case 0x86AA /* GL_WEIGHT_ARRAY_STRIDE_ARB */: return "GL_WEIGHT_ARRAY_STRIDE_ARB (0x86AA)";
+case 0x86AB /* GL_WEIGHT_ARRAY_SIZE_ARB */: return "GL_WEIGHT_ARRAY_SIZE_ARB (0x86AB)";
+case 0x86AC /* GL_WEIGHT_ARRAY_POINTER_ARB */: return "GL_WEIGHT_ARRAY_POINTER_ARB (0x86AC)";
+case 0x86AD /* GL_WEIGHT_ARRAY_ARB */: return "GL_WEIGHT_ARRAY_ARB (0x86AD)";
+case 0x8722 /* GL_MODELVIEW2_ARB */: return "GL_MODELVIEW2_ARB (0x8722)";
+case 0x8723 /* GL_MODELVIEW3_ARB */: return "GL_MODELVIEW3_ARB (0x8723)";
+case 0x8724 /* GL_MODELVIEW4_ARB */: return "GL_MODELVIEW4_ARB (0x8724)";
+case 0x8725 /* GL_MODELVIEW5_ARB */: return "GL_MODELVIEW5_ARB (0x8725)";
+case 0x8726 /* GL_MODELVIEW6_ARB */: return "GL_MODELVIEW6_ARB (0x8726)";
+case 0x8727 /* GL_MODELVIEW7_ARB */: return "GL_MODELVIEW7_ARB (0x8727)";
+case 0x8728 /* GL_MODELVIEW8_ARB */: return "GL_MODELVIEW8_ARB (0x8728)";
+case 0x8729 /* GL_MODELVIEW9_ARB */: return "GL_MODELVIEW9_ARB (0x8729)";
+case 0x872A /* GL_MODELVIEW10_ARB */: return "GL_MODELVIEW10_ARB (0x872A)";
+case 0x872B /* GL_MODELVIEW11_ARB */: return "GL_MODELVIEW11_ARB (0x872B)";
+case 0x872C /* GL_MODELVIEW12_ARB */: return "GL_MODELVIEW12_ARB (0x872C)";
+case 0x872D /* GL_MODELVIEW13_ARB */: return "GL_MODELVIEW13_ARB (0x872D)";
+case 0x872E /* GL_MODELVIEW14_ARB */: return "GL_MODELVIEW14_ARB (0x872E)";
+case 0x872F /* GL_MODELVIEW15_ARB */: return "GL_MODELVIEW15_ARB (0x872F)";
+case 0x8730 /* GL_MODELVIEW16_ARB */: return "GL_MODELVIEW16_ARB (0x8730)";
+case 0x8731 /* GL_MODELVIEW17_ARB */: return "GL_MODELVIEW17_ARB (0x8731)";
+case 0x8732 /* GL_MODELVIEW18_ARB */: return "GL_MODELVIEW18_ARB (0x8732)";
+case 0x8733 /* GL_MODELVIEW19_ARB */: return "GL_MODELVIEW19_ARB (0x8733)";
+case 0x8734 /* GL_MODELVIEW20_ARB */: return "GL_MODELVIEW20_ARB (0x8734)";
+case 0x8735 /* GL_MODELVIEW21_ARB */: return "GL_MODELVIEW21_ARB (0x8735)";
+case 0x8736 /* GL_MODELVIEW22_ARB */: return "GL_MODELVIEW22_ARB (0x8736)";
+case 0x8737 /* GL_MODELVIEW23_ARB */: return "GL_MODELVIEW23_ARB (0x8737)";
+case 0x8738 /* GL_MODELVIEW24_ARB */: return "GL_MODELVIEW24_ARB (0x8738)";
+case 0x8739 /* GL_MODELVIEW25_ARB */: return "GL_MODELVIEW25_ARB (0x8739)";
+case 0x873A /* GL_MODELVIEW26_ARB */: return "GL_MODELVIEW26_ARB (0x873A)";
+case 0x873B /* GL_MODELVIEW27_ARB */: return "GL_MODELVIEW27_ARB (0x873B)";
+case 0x873C /* GL_MODELVIEW28_ARB */: return "GL_MODELVIEW28_ARB (0x873C)";
+case 0x873D /* GL_MODELVIEW29_ARB */: return "GL_MODELVIEW29_ARB (0x873D)";
+case 0x873E /* GL_MODELVIEW30_ARB */: return "GL_MODELVIEW30_ARB (0x873E)";
+case 0x873F /* GL_MODELVIEW31_ARB */: return "GL_MODELVIEW31_ARB (0x873F)";
+
+
+
+
+
+
+
+/* ---------------------- GL_ARB_vertex_buffer_object ---------------------- */
+
+
+
+
+//case 0x8764 /* GL_BUFFER_SIZE_ARB */: return "GL_BUFFER_SIZE_ARB (0x8764)";
+//case 0x8765 /* GL_BUFFER_USAGE_ARB */: return "GL_BUFFER_USAGE_ARB (0x8765)";
+//case 0x8892 /* GL_ARRAY_BUFFER_ARB */: return "GL_ARRAY_BUFFER_ARB (0x8892)";
+//case 0x8893 /* GL_ELEMENT_ARRAY_BUFFER_ARB */: return "GL_ELEMENT_ARRAY_BUFFER_ARB (0x8893)";
+//case 0x8894 /* GL_ARRAY_BUFFER_BINDING_ARB */: return "GL_ARRAY_BUFFER_BINDING_ARB (0x8894)";
+//case 0x8895 /* GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB */: return "GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB (0x8895)";
+//case 0x8896 /* GL_VERTEX_ARRAY_BUFFER_BINDING_ARB */: return "GL_VERTEX_ARRAY_BUFFER_BINDING_ARB (0x8896)";
+//case 0x8897 /* GL_NORMAL_ARRAY_BUFFER_BINDING_ARB */: return "GL_NORMAL_ARRAY_BUFFER_BINDING_ARB (0x8897)";
+//case 0x8898 /* GL_COLOR_ARRAY_BUFFER_BINDING_ARB */: return "GL_COLOR_ARRAY_BUFFER_BINDING_ARB (0x8898)";
+//case 0x8899 /* GL_INDEX_ARRAY_BUFFER_BINDING_ARB */: return "GL_INDEX_ARRAY_BUFFER_BINDING_ARB (0x8899)";
+//case 0x889A /* GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB */: return "GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB (0x889A)";
+//case 0x889B /* GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB */: return "GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB (0x889B)";
+//case 0x889C /* GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB */: return "GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB (0x889C)";
+//case 0x889D /* GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB */: return "GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB (0x889D)";
+//case 0x889E /* GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB */: return "GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB (0x889E)";
+//case 0x889F /* GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB */: return "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB (0x889F)";
+//case 0x88B8 /* GL_READ_ONLY_ARB */: return "GL_READ_ONLY_ARB (0x88B8)";
+//case 0x88B9 /* GL_WRITE_ONLY_ARB */: return "GL_WRITE_ONLY_ARB (0x88B9)";
+//case 0x88BA /* GL_READ_WRITE_ARB */: return "GL_READ_WRITE_ARB (0x88BA)";
+//case 0x88BB /* GL_BUFFER_ACCESS_ARB */: return "GL_BUFFER_ACCESS_ARB (0x88BB)";
+//case 0x88BC /* GL_BUFFER_MAPPED_ARB */: return "GL_BUFFER_MAPPED_ARB (0x88BC)";
+//case 0x88BD /* GL_BUFFER_MAP_POINTER_ARB */: return "GL_BUFFER_MAP_POINTER_ARB (0x88BD)";
+//case 0x88E0 /* GL_STREAM_DRAW_ARB */: return "GL_STREAM_DRAW_ARB (0x88E0)";
+//case 0x88E1 /* GL_STREAM_READ_ARB */: return "GL_STREAM_READ_ARB (0x88E1)";
+//case 0x88E2 /* GL_STREAM_COPY_ARB */: return "GL_STREAM_COPY_ARB (0x88E2)";
+//case 0x88E4 /* GL_STATIC_DRAW_ARB */: return "GL_STATIC_DRAW_ARB (0x88E4)";
+//case 0x88E5 /* GL_STATIC_READ_ARB */: return "GL_STATIC_READ_ARB (0x88E5)";
+//case 0x88E6 /* GL_STATIC_COPY_ARB */: return "GL_STATIC_COPY_ARB (0x88E6)";
+//case 0x88E8 /* GL_DYNAMIC_DRAW_ARB */: return "GL_DYNAMIC_DRAW_ARB (0x88E8)";
+//case 0x88E9 /* GL_DYNAMIC_READ_ARB */: return "GL_DYNAMIC_READ_ARB (0x88E9)";
+//case 0x88EA /* GL_DYNAMIC_COPY_ARB */: return "GL_DYNAMIC_COPY_ARB (0x88EA)";
+
+
+/* ------------------------- GL_ARB_vertex_program ------------------------- */
+
+
+
+
+//case 0x8458 /* GL_COLOR_SUM_ARB */: return "GL_COLOR_SUM_ARB (0x8458)";
+case 0x8620 /* GL_VERTEX_PROGRAM_ARB */: return "GL_VERTEX_PROGRAM_ARB (0x8620)";
+//case 0x8622 /* GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB */: return "GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB (0x8622)";
+//case 0x8623 /* GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB */: return "GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB (0x8623)";
+//case 0x8624 /* GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB */: return "GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB (0x8624)";
+//case 0x8625 /* GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB */: return "GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB (0x8625)";
+//case 0x8626 /* GL_CURRENT_VERTEX_ATTRIB_ARB */: return "GL_CURRENT_VERTEX_ATTRIB_ARB (0x8626)";
+case 0x8627 /* GL_PROGRAM_LENGTH_ARB */: return "GL_PROGRAM_LENGTH_ARB (0x8627)";
+case 0x8628 /* GL_PROGRAM_STRING_ARB */: return "GL_PROGRAM_STRING_ARB (0x8628)";
+case 0x862E /* GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB */: return "GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB (0x862E)";
+case 0x862F /* GL_MAX_PROGRAM_MATRICES_ARB */: return "GL_MAX_PROGRAM_MATRICES_ARB (0x862F)";
+case 0x8640 /* GL_CURRENT_MATRIX_STACK_DEPTH_ARB */: return "GL_CURRENT_MATRIX_STACK_DEPTH_ARB (0x8640)";
+case 0x8641 /* GL_CURRENT_MATRIX_ARB */: return "GL_CURRENT_MATRIX_ARB (0x8641)";
+//case 0x8642 /* GL_VERTEX_PROGRAM_POINT_SIZE_ARB */: return "GL_VERTEX_PROGRAM_POINT_SIZE_ARB (0x8642)";
+//case 0x8643 /* GL_VERTEX_PROGRAM_TWO_SIDE_ARB */: return "GL_VERTEX_PROGRAM_TWO_SIDE_ARB (0x8643)";
+//case 0x8645 /* GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB */: return "GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB (0x8645)";
+case 0x864B /* GL_PROGRAM_ERROR_POSITION_ARB */: return "GL_PROGRAM_ERROR_POSITION_ARB (0x864B)";
+case 0x8677 /* GL_PROGRAM_BINDING_ARB */: return "GL_PROGRAM_BINDING_ARB (0x8677)";
+//case 0x8869 /* GL_MAX_VERTEX_ATTRIBS_ARB */: return "GL_MAX_VERTEX_ATTRIBS_ARB (0x8869)";
+//case 0x886A /* GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB */: return "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB (0x886A)";
+case 0x8874 /* GL_PROGRAM_ERROR_STRING_ARB */: return "GL_PROGRAM_ERROR_STRING_ARB (0x8874)";
+case 0x8875 /* GL_PROGRAM_FORMAT_ASCII_ARB */: return "GL_PROGRAM_FORMAT_ASCII_ARB (0x8875)";
+case 0x8876 /* GL_PROGRAM_FORMAT_ARB */: return "GL_PROGRAM_FORMAT_ARB (0x8876)";
+case 0x88A4 /* GL_PROGRAM_TEMPORARIES_ARB */: return "GL_PROGRAM_TEMPORARIES_ARB (0x88A4)";
+case 0x88A5 /* GL_MAX_PROGRAM_TEMPORARIES_ARB */: return "GL_MAX_PROGRAM_TEMPORARIES_ARB (0x88A5)";
+case 0x88A6 /* GL_PROGRAM_NATIVE_TEMPORARIES_ARB */: return "GL_PROGRAM_NATIVE_TEMPORARIES_ARB (0x88A6)";
+case 0x88A7 /* GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB */: return "GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB (0x88A7)";
+case 0x88A8 /* GL_PROGRAM_PARAMETERS_ARB */: return "GL_PROGRAM_PARAMETERS_ARB (0x88A8)";
+case 0x88A9 /* GL_MAX_PROGRAM_PARAMETERS_ARB */: return "GL_MAX_PROGRAM_PARAMETERS_ARB (0x88A9)";
+case 0x88AA /* GL_PROGRAM_NATIVE_PARAMETERS_ARB */: return "GL_PROGRAM_NATIVE_PARAMETERS_ARB (0x88AA)";
+case 0x88AB /* GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB */: return "GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB (0x88AB)";
+case 0x88AC /* GL_PROGRAM_ATTRIBS_ARB */: return "GL_PROGRAM_ATTRIBS_ARB (0x88AC)";
+case 0x88AD /* GL_MAX_PROGRAM_ATTRIBS_ARB */: return "GL_MAX_PROGRAM_ATTRIBS_ARB (0x88AD)";
+case 0x88AE /* GL_PROGRAM_NATIVE_ATTRIBS_ARB */: return "GL_PROGRAM_NATIVE_ATTRIBS_ARB (0x88AE)";
+case 0x88AF /* GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB */: return "GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB (0x88AF)";
+case 0x88B0 /* GL_PROGRAM_ADDRESS_REGISTERS_ARB */: return "GL_PROGRAM_ADDRESS_REGISTERS_ARB (0x88B0)";
+case 0x88B1 /* GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB */: return "GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB (0x88B1)";
+case 0x88B2 /* GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB */: return "GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB (0x88B2)";
+case 0x88B3 /* GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB */: return "GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB (0x88B3)";
+case 0x88B4 /* GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB */: return "GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB (0x88B4)";
+case 0x88B5 /* GL_MAX_PROGRAM_ENV_PARAMETERS_ARB */: return "GL_MAX_PROGRAM_ENV_PARAMETERS_ARB (0x88B5)";
+case 0x88B6 /* GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB */: return "GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB (0x88B6)";
+case 0x88B7 /* GL_TRANSPOSE_CURRENT_MATRIX_ARB */: return "GL_TRANSPOSE_CURRENT_MATRIX_ARB (0x88B7)";
+case 0x88C0 /* GL_MATRIX0_ARB */: return "GL_MATRIX0_ARB (0x88C0)";
+case 0x88C1 /* GL_MATRIX1_ARB */: return "GL_MATRIX1_ARB (0x88C1)";
+case 0x88C2 /* GL_MATRIX2_ARB */: return "GL_MATRIX2_ARB (0x88C2)";
+case 0x88C3 /* GL_MATRIX3_ARB */: return "GL_MATRIX3_ARB (0x88C3)";
+case 0x88C4 /* GL_MATRIX4_ARB */: return "GL_MATRIX4_ARB (0x88C4)";
+case 0x88C5 /* GL_MATRIX5_ARB */: return "GL_MATRIX5_ARB (0x88C5)";
+case 0x88C6 /* GL_MATRIX6_ARB */: return "GL_MATRIX6_ARB (0x88C6)";
+case 0x88C7 /* GL_MATRIX7_ARB */: return "GL_MATRIX7_ARB (0x88C7)";
+case 0x88C8 /* GL_MATRIX8_ARB */: return "GL_MATRIX8_ARB (0x88C8)";
+case 0x88C9 /* GL_MATRIX9_ARB */: return "GL_MATRIX9_ARB (0x88C9)";
+case 0x88CA /* GL_MATRIX10_ARB */: return "GL_MATRIX10_ARB (0x88CA)";
+case 0x88CB /* GL_MATRIX11_ARB */: return "GL_MATRIX11_ARB (0x88CB)";
+case 0x88CC /* GL_MATRIX12_ARB */: return "GL_MATRIX12_ARB (0x88CC)";
+case 0x88CD /* GL_MATRIX13_ARB */: return "GL_MATRIX13_ARB (0x88CD)";
+case 0x88CE /* GL_MATRIX14_ARB */: return "GL_MATRIX14_ARB (0x88CE)";
+case 0x88CF /* GL_MATRIX15_ARB */: return "GL_MATRIX15_ARB (0x88CF)";
+case 0x88D0 /* GL_MATRIX16_ARB */: return "GL_MATRIX16_ARB (0x88D0)";
+case 0x88D1 /* GL_MATRIX17_ARB */: return "GL_MATRIX17_ARB (0x88D1)";
+case 0x88D2 /* GL_MATRIX18_ARB */: return "GL_MATRIX18_ARB (0x88D2)";
+case 0x88D3 /* GL_MATRIX19_ARB */: return "GL_MATRIX19_ARB (0x88D3)";
+case 0x88D4 /* GL_MATRIX20_ARB */: return "GL_MATRIX20_ARB (0x88D4)";
+case 0x88D5 /* GL_MATRIX21_ARB */: return "GL_MATRIX21_ARB (0x88D5)";
+case 0x88D6 /* GL_MATRIX22_ARB */: return "GL_MATRIX22_ARB (0x88D6)";
+case 0x88D7 /* GL_MATRIX23_ARB */: return "GL_MATRIX23_ARB (0x88D7)";
+case 0x88D8 /* GL_MATRIX24_ARB */: return "GL_MATRIX24_ARB (0x88D8)";
+case 0x88D9 /* GL_MATRIX25_ARB */: return "GL_MATRIX25_ARB (0x88D9)";
+case 0x88DA /* GL_MATRIX26_ARB */: return "GL_MATRIX26_ARB (0x88DA)";
+case 0x88DB /* GL_MATRIX27_ARB */: return "GL_MATRIX27_ARB (0x88DB)";
+case 0x88DC /* GL_MATRIX28_ARB */: return "GL_MATRIX28_ARB (0x88DC)";
+case 0x88DD /* GL_MATRIX29_ARB */: return "GL_MATRIX29_ARB (0x88DD)";
+case 0x88DE /* GL_MATRIX30_ARB */: return "GL_MATRIX30_ARB (0x88DE)";
+case 0x88DF /* GL_MATRIX31_ARB */: return "GL_MATRIX31_ARB (0x88DF)";
+
+/* -------------------------- GL_ARB_vertex_shader ------------------------- */
+
+
+
+
+//case 0x8B31 /* GL_VERTEX_SHADER_ARB */: return "GL_VERTEX_SHADER_ARB (0x8B31)";
+//case 0x8B4A /* GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB */: return "GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB (0x8B4A)";
+//case 0x8B4B /* GL_MAX_VARYING_FLOATS_ARB */: return "GL_MAX_VARYING_FLOATS_ARB (0x8B4B)";
+//case 0x8B4C /* GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB */: return "GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB (0x8B4C)";
+//case 0x8B4D /* GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB */: return "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB (0x8B4D)";
+//case 0x8B89 /* GL_OBJECT_ACTIVE_ATTRIBUTES_ARB */: return "GL_OBJECT_ACTIVE_ATTRIBUTES_ARB (0x8B89)";
+//case 0x8B8A /* GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB */: return "GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB (0x8B8A)";
+
+
+
+/* ------------------- GL_ARB_vertex_type_2_10_10_10_rev ------------------- */
+
+
+
+
+//case 0x8368 /* GL_UNSIGNED_INT_2_10_10_10_REV */: return "GL_UNSIGNED_INT_2_10_10_10_REV (0x8368)";
+case 0x8D9F /* GL_INT_2_10_10_10_REV */: return "GL_INT_2_10_10_10_REV (0x8D9F)";
+
+
+
+/* ------------------------- GL_ARB_viewport_array ------------------------- */
+
+
+
+
+//case 0x0B70 /* GL_DEPTH_RANGE */: return "GL_DEPTH_RANGE (0x0B70)";
+//case 0x0BA2 /* GL_VIEWPORT */: return "GL_VIEWPORT (0x0BA2)";
+//case 0x0C10 /* GL_SCISSOR_BOX */: return "GL_SCISSOR_BOX (0x0C10)";
+//case 0x0C11 /* GL_SCISSOR_TEST */: return "GL_SCISSOR_TEST (0x0C11)";
+case 0x825B /* GL_MAX_VIEWPORTS */: return "GL_MAX_VIEWPORTS (0x825B)";
+case 0x825C /* GL_VIEWPORT_SUBPIXEL_BITS */: return "GL_VIEWPORT_SUBPIXEL_BITS (0x825C)";
+case 0x825D /* GL_VIEWPORT_BOUNDS_RANGE */: return "GL_VIEWPORT_BOUNDS_RANGE (0x825D)";
+case 0x825E /* GL_LAYER_PROVOKING_VERTEX */: return "GL_LAYER_PROVOKING_VERTEX (0x825E)";
+case 0x825F /* GL_VIEWPORT_INDEX_PROVOKING_VERTEX */: return "GL_VIEWPORT_INDEX_PROVOKING_VERTEX (0x825F)";
+case 0x8260 /* GL_UNDEFINED_VERTEX */: return "GL_UNDEFINED_VERTEX (0x8260)";
+//case 0x8E4D /* GL_FIRST_VERTEX_CONVENTION */: return "GL_FIRST_VERTEX_CONVENTION (0x8E4D)";
+//case 0x8E4E /* GL_LAST_VERTEX_CONVENTION */: return "GL_LAST_VERTEX_CONVENTION (0x8E4E)";
+//case 0x8E4F /* GL_PROVOKING_VERTEX */: return "GL_PROVOKING_VERTEX (0x8E4F)";
+
+
+
+
+
+
+
+/* --------------------------- GL_ARB_window_pos --------------------------- */
+
+
+/* ------------------------- GL_ATIX_point_sprites ------------------------- */
+
+
+
+
+case 0x60B0 /* GL_TEXTURE_POINT_MODE_ATIX */: return "GL_TEXTURE_POINT_MODE_ATIX (0x60B0)";
+case 0x60B1 /* GL_TEXTURE_POINT_ONE_COORD_ATIX */: return "GL_TEXTURE_POINT_ONE_COORD_ATIX (0x60B1)";
+case 0x60B2 /* GL_TEXTURE_POINT_SPRITE_ATIX */: return "GL_TEXTURE_POINT_SPRITE_ATIX (0x60B2)";
+case 0x60B3 /* GL_POINT_SPRITE_CULL_MODE_ATIX */: return "GL_POINT_SPRITE_CULL_MODE_ATIX (0x60B3)";
+case 0x60B4 /* GL_POINT_SPRITE_CULL_CENTER_ATIX */: return "GL_POINT_SPRITE_CULL_CENTER_ATIX (0x60B4)";
+case 0x60B5 /* GL_POINT_SPRITE_CULL_CLIP_ATIX */: return "GL_POINT_SPRITE_CULL_CLIP_ATIX (0x60B5)";
+
+
+
+
+
+/* ---------------------- GL_ATIX_texture_env_combine3 --------------------- */
+
+
+
+
+case 0x8744 /* GL_MODULATE_ADD_ATIX */: return "GL_MODULATE_ADD_ATIX (0x8744)";
+case 0x8745 /* GL_MODULATE_SIGNED_ADD_ATIX */: return "GL_MODULATE_SIGNED_ADD_ATIX (0x8745)";
+case 0x8746 /* GL_MODULATE_SUBTRACT_ATIX */: return "GL_MODULATE_SUBTRACT_ATIX (0x8746)";
+
+
+
+
+
+/* ----------------------- GL_ATIX_texture_env_route ----------------------- */
+
+
+
+
+case 0x8747 /* GL_SECONDARY_COLOR_ATIX */: return "GL_SECONDARY_COLOR_ATIX (0x8747)";
+case 0x8748 /* GL_TEXTURE_OUTPUT_RGB_ATIX */: return "GL_TEXTURE_OUTPUT_RGB_ATIX (0x8748)";
+case 0x8749 /* GL_TEXTURE_OUTPUT_ALPHA_ATIX */: return "GL_TEXTURE_OUTPUT_ALPHA_ATIX (0x8749)";
+
+
+
+
+
+/* ---------------- GL_ATIX_vertex_shader_output_point_size ---------------- */
+
+
+
+
+case 0x610E /* GL_OUTPUT_POINT_SIZE_ATIX */: return "GL_OUTPUT_POINT_SIZE_ATIX (0x610E)";
+
+
+
+
+
+/* -------------------------- GL_ATI_draw_buffers -------------------------- */
+
+
+
+
+//case 0x8824 /* GL_MAX_DRAW_BUFFERS_ATI */: return "GL_MAX_DRAW_BUFFERS_ATI (0x8824)";
+//case 0x8825 /* GL_DRAW_BUFFER0_ATI */: return "GL_DRAW_BUFFER0_ATI (0x8825)";
+//case 0x8826 /* GL_DRAW_BUFFER1_ATI */: return "GL_DRAW_BUFFER1_ATI (0x8826)";
+//case 0x8827 /* GL_DRAW_BUFFER2_ATI */: return "GL_DRAW_BUFFER2_ATI (0x8827)";
+//case 0x8828 /* GL_DRAW_BUFFER3_ATI */: return "GL_DRAW_BUFFER3_ATI (0x8828)";
+//case 0x8829 /* GL_DRAW_BUFFER4_ATI */: return "GL_DRAW_BUFFER4_ATI (0x8829)";
+//case 0x882A /* GL_DRAW_BUFFER5_ATI */: return "GL_DRAW_BUFFER5_ATI (0x882A)";
+//case 0x882B /* GL_DRAW_BUFFER6_ATI */: return "GL_DRAW_BUFFER6_ATI (0x882B)";
+//case 0x882C /* GL_DRAW_BUFFER7_ATI */: return "GL_DRAW_BUFFER7_ATI (0x882C)";
+//case 0x882D /* GL_DRAW_BUFFER8_ATI */: return "GL_DRAW_BUFFER8_ATI (0x882D)";
+//case 0x882E /* GL_DRAW_BUFFER9_ATI */: return "GL_DRAW_BUFFER9_ATI (0x882E)";
+//case 0x882F /* GL_DRAW_BUFFER10_ATI */: return "GL_DRAW_BUFFER10_ATI (0x882F)";
+//case 0x8830 /* GL_DRAW_BUFFER11_ATI */: return "GL_DRAW_BUFFER11_ATI (0x8830)";
+//case 0x8831 /* GL_DRAW_BUFFER12_ATI */: return "GL_DRAW_BUFFER12_ATI (0x8831)";
+//case 0x8832 /* GL_DRAW_BUFFER13_ATI */: return "GL_DRAW_BUFFER13_ATI (0x8832)";
+//case 0x8833 /* GL_DRAW_BUFFER14_ATI */: return "GL_DRAW_BUFFER14_ATI (0x8833)";
+//case 0x8834 /* GL_DRAW_BUFFER15_ATI */: return "GL_DRAW_BUFFER15_ATI (0x8834)";/* -------------------------- GL_ATI_element_array ------------------------- */
+
+
+
+
+case 0x8768 /* GL_ELEMENT_ARRAY_ATI */: return "GL_ELEMENT_ARRAY_ATI (0x8768)";
+case 0x8769 /* GL_ELEMENT_ARRAY_TYPE_ATI */: return "GL_ELEMENT_ARRAY_TYPE_ATI (0x8769)";
+case 0x876A /* GL_ELEMENT_ARRAY_POINTER_ATI */: return "GL_ELEMENT_ARRAY_POINTER_ATI (0x876A)";
+
+
+
+/* ------------------------- GL_ATI_envmap_bumpmap ------------------------- */
+
+
+
+
+case 0x8775 /* GL_BUMP_ROT_MATRIX_ATI */: return "GL_BUMP_ROT_MATRIX_ATI (0x8775)";
+case 0x8776 /* GL_BUMP_ROT_MATRIX_SIZE_ATI */: return "GL_BUMP_ROT_MATRIX_SIZE_ATI (0x8776)";
+case 0x8777 /* GL_BUMP_NUM_TEX_UNITS_ATI */: return "GL_BUMP_NUM_TEX_UNITS_ATI (0x8777)";
+case 0x8778 /* GL_BUMP_TEX_UNITS_ATI */: return "GL_BUMP_TEX_UNITS_ATI (0x8778)";
+case 0x8779 /* GL_DUDV_ATI */: return "GL_DUDV_ATI (0x8779)";
+case 0x877A /* GL_DU8DV8_ATI */: return "GL_DU8DV8_ATI (0x877A)";
+case 0x877B /* GL_BUMP_ENVMAP_ATI */: return "GL_BUMP_ENVMAP_ATI (0x877B)";
+case 0x877C /* GL_BUMP_TARGET_ATI */: return "GL_BUMP_TARGET_ATI (0x877C)";
+
+
+
+
+
+/* ------------------------- GL_ATI_fragment_shader ------------------------ */
+
+
+
+
+//case 0x00000001 /* GL_RED_BIT_ATI */: return "GL_RED_BIT_ATI (0x00000001)";
+//case 0x00000001 /* GL_2X_BIT_ATI */: return "GL_2X_BIT_ATI (0x00000001)";
+//case 0x00000002 /* GL_4X_BIT_ATI */: return "GL_4X_BIT_ATI (0x00000002)";
+//case 0x00000002 /* GL_GREEN_BIT_ATI */: return "GL_GREEN_BIT_ATI (0x00000002)";
+//case 0x00000002 /* GL_COMP_BIT_ATI */: return "GL_COMP_BIT_ATI (0x00000002)";
+//case 0x00000004 /* GL_BLUE_BIT_ATI */: return "GL_BLUE_BIT_ATI (0x00000004)";
+//case 0x00000004 /* GL_8X_BIT_ATI */: return "GL_8X_BIT_ATI (0x00000004)";
+//case 0x00000004 /* GL_NEGATE_BIT_ATI */: return "GL_NEGATE_BIT_ATI (0x00000004)";
+//case 0x00000008 /* GL_BIAS_BIT_ATI */: return "GL_BIAS_BIT_ATI (0x00000008)";
+//case 0x00000008 /* GL_HALF_BIT_ATI */: return "GL_HALF_BIT_ATI (0x00000008)";
+//case 0x00000010 /* GL_QUARTER_BIT_ATI */: return "GL_QUARTER_BIT_ATI (0x00000010)";
+//case 0x00000020 /* GL_EIGHTH_BIT_ATI */: return "GL_EIGHTH_BIT_ATI (0x00000020)";
+//case 0x00000040 /* GL_SATURATE_BIT_ATI */: return "GL_SATURATE_BIT_ATI (0x00000040)";
+case 0x8920 /* GL_FRAGMENT_SHADER_ATI */: return "GL_FRAGMENT_SHADER_ATI (0x8920)";
+case 0x8921 /* GL_REG_0_ATI */: return "GL_REG_0_ATI (0x8921)";
+case 0x8922 /* GL_REG_1_ATI */: return "GL_REG_1_ATI (0x8922)";
+case 0x8923 /* GL_REG_2_ATI */: return "GL_REG_2_ATI (0x8923)";
+case 0x8924 /* GL_REG_3_ATI */: return "GL_REG_3_ATI (0x8924)";
+case 0x8925 /* GL_REG_4_ATI */: return "GL_REG_4_ATI (0x8925)";
+case 0x8926 /* GL_REG_5_ATI */: return "GL_REG_5_ATI (0x8926)";
+case 0x8941 /* GL_CON_0_ATI */: return "GL_CON_0_ATI (0x8941)";
+case 0x8942 /* GL_CON_1_ATI */: return "GL_CON_1_ATI (0x8942)";
+case 0x8943 /* GL_CON_2_ATI */: return "GL_CON_2_ATI (0x8943)";
+case 0x8944 /* GL_CON_3_ATI */: return "GL_CON_3_ATI (0x8944)";
+case 0x8945 /* GL_CON_4_ATI */: return "GL_CON_4_ATI (0x8945)";
+case 0x8946 /* GL_CON_5_ATI */: return "GL_CON_5_ATI (0x8946)";
+case 0x8947 /* GL_CON_6_ATI */: return "GL_CON_6_ATI (0x8947)";
+case 0x8948 /* GL_CON_7_ATI */: return "GL_CON_7_ATI (0x8948)";
+case 0x8961 /* GL_MOV_ATI */: return "GL_MOV_ATI (0x8961)";
+case 0x8963 /* GL_ADD_ATI */: return "GL_ADD_ATI (0x8963)";
+case 0x8964 /* GL_MUL_ATI */: return "GL_MUL_ATI (0x8964)";
+case 0x8965 /* GL_SUB_ATI */: return "GL_SUB_ATI (0x8965)";
+case 0x8966 /* GL_DOT3_ATI */: return "GL_DOT3_ATI (0x8966)";
+case 0x8967 /* GL_DOT4_ATI */: return "GL_DOT4_ATI (0x8967)";
+case 0x8968 /* GL_MAD_ATI */: return "GL_MAD_ATI (0x8968)";
+case 0x8969 /* GL_LERP_ATI */: return "GL_LERP_ATI (0x8969)";
+case 0x896A /* GL_CND_ATI */: return "GL_CND_ATI (0x896A)";
+case 0x896B /* GL_CND0_ATI */: return "GL_CND0_ATI (0x896B)";
+case 0x896C /* GL_DOT2_ADD_ATI */: return "GL_DOT2_ADD_ATI (0x896C)";
+case 0x896D /* GL_SECONDARY_INTERPOLATOR_ATI */: return "GL_SECONDARY_INTERPOLATOR_ATI (0x896D)";
+case 0x896E /* GL_NUM_FRAGMENT_REGISTERS_ATI */: return "GL_NUM_FRAGMENT_REGISTERS_ATI (0x896E)";
+case 0x896F /* GL_NUM_FRAGMENT_CONSTANTS_ATI */: return "GL_NUM_FRAGMENT_CONSTANTS_ATI (0x896F)";
+case 0x8970 /* GL_NUM_PASSES_ATI */: return "GL_NUM_PASSES_ATI (0x8970)";
+case 0x8973 /* GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI */: return "GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI (0x8973)";
+case 0x8974 /* GL_NUM_LOOPBACK_COMPONENTS_ATI */: return "GL_NUM_LOOPBACK_COMPONENTS_ATI (0x8974)";
+case 0x8975 /* GL_COLOR_ALPHA_PAIRING_ATI */: return "GL_COLOR_ALPHA_PAIRING_ATI (0x8975)";
+case 0x8976 /* GL_SWIZZLE_STR_ATI */: return "GL_SWIZZLE_STR_ATI (0x8976)";
+case 0x8977 /* GL_SWIZZLE_STQ_ATI */: return "GL_SWIZZLE_STQ_ATI (0x8977)";
+case 0x8978 /* GL_SWIZZLE_STR_DR_ATI */: return "GL_SWIZZLE_STR_DR_ATI (0x8978)";
+case 0x8979 /* GL_SWIZZLE_STQ_DQ_ATI */: return "GL_SWIZZLE_STQ_DQ_ATI (0x8979)";
+case 0x897A /* GL_SWIZZLE_STRQ_ATI */: return "GL_SWIZZLE_STRQ_ATI (0x897A)";
+case 0x897B /* GL_SWIZZLE_STRQ_DQ_ATI */: return "GL_SWIZZLE_STRQ_DQ_ATI (0x897B)";
+
+
+
+
+
+/* ------------------------ GL_ATI_map_object_buffer ----------------------- */
+
+
+
+
+/* ----------------------------- GL_ATI_meminfo ---------------------------- */
+
+
+
+
+case 0x87FB /* GL_VBO_FREE_MEMORY_ATI */: return "GL_VBO_FREE_MEMORY_ATI (0x87FB)";
+case 0x87FC /* GL_TEXTURE_FREE_MEMORY_ATI */: return "GL_TEXTURE_FREE_MEMORY_ATI (0x87FC)";
+case 0x87FD /* GL_RENDERBUFFER_FREE_MEMORY_ATI */: return "GL_RENDERBUFFER_FREE_MEMORY_ATI (0x87FD)";
+
+
+
+
+
+/* -------------------------- GL_ATI_pn_triangles -------------------------- */
+
+
+
+
+case 0x87F0 /* GL_PN_TRIANGLES_ATI */: return "GL_PN_TRIANGLES_ATI (0x87F0)";
+case 0x87F1 /* GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI */: return "GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI (0x87F1)";
+case 0x87F2 /* GL_PN_TRIANGLES_POINT_MODE_ATI */: return "GL_PN_TRIANGLES_POINT_MODE_ATI (0x87F2)";
+case 0x87F3 /* GL_PN_TRIANGLES_NORMAL_MODE_ATI */: return "GL_PN_TRIANGLES_NORMAL_MODE_ATI (0x87F3)";
+case 0x87F4 /* GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI */: return "GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI (0x87F4)";
+case 0x87F5 /* GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI */: return "GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI (0x87F5)";
+case 0x87F6 /* GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI */: return "GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI (0x87F6)";
+case 0x87F7 /* GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI */: return "GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI (0x87F7)";
+case 0x87F8 /* GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI */: return "GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI (0x87F8)";
+
+/* ------------------------ GL_ATI_separate_stencil ------------------------ */
+
+
+
+
+//case 0x8800 /* GL_STENCIL_BACK_FUNC_ATI */: return "GL_STENCIL_BACK_FUNC_ATI (0x8800)";
+//case 0x8801 /* GL_STENCIL_BACK_FAIL_ATI */: return "GL_STENCIL_BACK_FAIL_ATI (0x8801)";
+//case 0x8802 /* GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI */: return "GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI (0x8802)";
+//case 0x8803 /* GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI */: return "GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI (0x8803)";
+
+/* ----------------------- GL_ATI_shader_texture_lod ----------------------- */
+
+
+
+
+
+
+
+
+/* ---------------------- GL_ATI_text_fragment_shader ---------------------- */
+
+
+
+
+case 0x8200 /* GL_TEXT_FRAGMENT_SHADER_ATI */: return "GL_TEXT_FRAGMENT_SHADER_ATI (0x8200)";
+
+
+
+
+
+/* --------------------- GL_ATI_texture_compression_3dc -------------------- */
+
+
+
+
+case 0x8837 /* GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI */: return "GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI (0x8837)";
+
+
+
+
+
+/* ---------------------- GL_ATI_texture_env_combine3 ---------------------- */
+
+
+
+
+//case 0x8744 /* GL_MODULATE_ADD_ATI */: return "GL_MODULATE_ADD_ATI (0x8744)";
+//case 0x8745 /* GL_MODULATE_SIGNED_ADD_ATI */: return "GL_MODULATE_SIGNED_ADD_ATI (0x8745)";
+//case 0x8746 /* GL_MODULATE_SUBTRACT_ATI */: return "GL_MODULATE_SUBTRACT_ATI (0x8746)";
+
+
+
+
+
+/* -------------------------- GL_ATI_texture_float ------------------------- */
+
+
+
+
+//case 0x8814 /* GL_RGBA_FLOAT32_ATI */: return "GL_RGBA_FLOAT32_ATI (0x8814)";
+//case 0x8815 /* GL_RGB_FLOAT32_ATI */: return "GL_RGB_FLOAT32_ATI (0x8815)";
+//case 0x8816 /* GL_ALPHA_FLOAT32_ATI */: return "GL_ALPHA_FLOAT32_ATI (0x8816)";
+//case 0x8817 /* GL_INTENSITY_FLOAT32_ATI */: return "GL_INTENSITY_FLOAT32_ATI (0x8817)";
+//case 0x8818 /* GL_LUMINANCE_FLOAT32_ATI */: return "GL_LUMINANCE_FLOAT32_ATI (0x8818)";
+//case 0x8819 /* GL_LUMINANCE_ALPHA_FLOAT32_ATI */: return "GL_LUMINANCE_ALPHA_FLOAT32_ATI (0x8819)";
+//case 0x881A /* GL_RGBA_FLOAT16_ATI */: return "GL_RGBA_FLOAT16_ATI (0x881A)";
+//case 0x881B /* GL_RGB_FLOAT16_ATI */: return "GL_RGB_FLOAT16_ATI (0x881B)";
+//case 0x881C /* GL_ALPHA_FLOAT16_ATI */: return "GL_ALPHA_FLOAT16_ATI (0x881C)";
+//case 0x881D /* GL_INTENSITY_FLOAT16_ATI */: return "GL_INTENSITY_FLOAT16_ATI (0x881D)";
+//case 0x881E /* GL_LUMINANCE_FLOAT16_ATI */: return "GL_LUMINANCE_FLOAT16_ATI (0x881E)";
+//case 0x881F /* GL_LUMINANCE_ALPHA_FLOAT16_ATI */: return "GL_LUMINANCE_ALPHA_FLOAT16_ATI (0x881F)";
+
+
+
+
+
+/* ----------------------- GL_ATI_texture_mirror_once ---------------------- */
+
+
+
+
+case 0x8742 /* GL_MIRROR_CLAMP_ATI */: return "GL_MIRROR_CLAMP_ATI (0x8742)";
+case 0x8743 /* GL_MIRROR_CLAMP_TO_EDGE_ATI */: return "GL_MIRROR_CLAMP_TO_EDGE_ATI (0x8743)";
+
+
+
+
+
+/* ----------------------- GL_ATI_vertex_array_object ---------------------- */
+
+
+
+
+case 0x8760 /* GL_STATIC_ATI */: return "GL_STATIC_ATI (0x8760)";
+case 0x8761 /* GL_DYNAMIC_ATI */: return "GL_DYNAMIC_ATI (0x8761)";
+case 0x8762 /* GL_PRESERVE_ATI */: return "GL_PRESERVE_ATI (0x8762)";
+case 0x8763 /* GL_DISCARD_ATI */: return "GL_DISCARD_ATI (0x8763)";
+//case 0x8764 /* GL_OBJECT_BUFFER_SIZE_ATI */: return "GL_OBJECT_BUFFER_SIZE_ATI (0x8764)";
+//case 0x8765 /* GL_OBJECT_BUFFER_USAGE_ATI */: return "GL_OBJECT_BUFFER_USAGE_ATI (0x8765)";
+case 0x8766 /* GL_ARRAY_OBJECT_BUFFER_ATI */: return "GL_ARRAY_OBJECT_BUFFER_ATI (0x8766)";
+case 0x8767 /* GL_ARRAY_OBJECT_OFFSET_ATI */: return "GL_ARRAY_OBJECT_OFFSET_ATI (0x8767)";
+
+/* ------------------- GL_ATI_vertex_attrib_array_object ------------------- */
+
+
+
+
+
+
+/* ------------------------- GL_ATI_vertex_streams ------------------------- */
+
+
+
+
+case 0x876B /* GL_MAX_VERTEX_STREAMS_ATI */: return "GL_MAX_VERTEX_STREAMS_ATI (0x876B)";
+case 0x876C /* GL_VERTEX_SOURCE_ATI */: return "GL_VERTEX_SOURCE_ATI (0x876C)";
+case 0x876D /* GL_VERTEX_STREAM0_ATI */: return "GL_VERTEX_STREAM0_ATI (0x876D)";
+case 0x876E /* GL_VERTEX_STREAM1_ATI */: return "GL_VERTEX_STREAM1_ATI (0x876E)";
+case 0x876F /* GL_VERTEX_STREAM2_ATI */: return "GL_VERTEX_STREAM2_ATI (0x876F)";
+case 0x8770 /* GL_VERTEX_STREAM3_ATI */: return "GL_VERTEX_STREAM3_ATI (0x8770)";
+case 0x8771 /* GL_VERTEX_STREAM4_ATI */: return "GL_VERTEX_STREAM4_ATI (0x8771)";
+case 0x8772 /* GL_VERTEX_STREAM5_ATI */: return "GL_VERTEX_STREAM5_ATI (0x8772)";
+case 0x8773 /* GL_VERTEX_STREAM6_ATI */: return "GL_VERTEX_STREAM6_ATI (0x8773)";
+case 0x8774 /* GL_VERTEX_STREAM7_ATI */: return "GL_VERTEX_STREAM7_ATI (0x8774)";
+
+
+
+
+
+
+
+/* --------------------------- GL_EXT_422_pixels --------------------------- */
+
+
+
+
+case 0x80CC /* GL_422_EXT */: return "GL_422_EXT (0x80CC)";
+case 0x80CD /* GL_422_REV_EXT */: return "GL_422_REV_EXT (0x80CD)";
+case 0x80CE /* GL_422_AVERAGE_EXT */: return "GL_422_AVERAGE_EXT (0x80CE)";
+case 0x80CF /* GL_422_REV_AVERAGE_EXT */: return "GL_422_REV_AVERAGE_EXT (0x80CF)";
+
+
+
+
+
+/* ---------------------------- GL_EXT_Cg_shader --------------------------- */
+
+
+
+
+case 0x890E /* GL_CG_VERTEX_SHADER_EXT */: return "GL_CG_VERTEX_SHADER_EXT (0x890E)";
+case 0x890F /* GL_CG_FRAGMENT_SHADER_EXT */: return "GL_CG_FRAGMENT_SHADER_EXT (0x890F)";
+
+
+
+
+
+/* ------------------------------ GL_EXT_abgr ------------------------------ */
+
+
+
+
+//case 0x8000 /* GL_ABGR_EXT */: return "GL_ABGR_EXT (0x8000)";
+
+
+
+
+
+/* ------------------------------ GL_EXT_bgra ------------------------------ */
+
+
+
+
+//case 0x80E0 /* GL_BGR_EXT */: return "GL_BGR_EXT (0x80E0)";
+//case 0x80E1 /* GL_BGRA_EXT */: return "GL_BGRA_EXT (0x80E1)";
+
+
+
+
+
+/* ------------------------ GL_EXT_bindable_uniform ------------------------ */
+
+
+
+
+case 0x8DE2 /* GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT */: return "GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT (0x8DE2)";
+case 0x8DE3 /* GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT */: return "GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT (0x8DE3)";
+case 0x8DE4 /* GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT */: return "GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT (0x8DE4)";
+case 0x8DED /* GL_MAX_BINDABLE_UNIFORM_SIZE_EXT */: return "GL_MAX_BINDABLE_UNIFORM_SIZE_EXT (0x8DED)";
+case 0x8DEE /* GL_UNIFORM_BUFFER_EXT */: return "GL_UNIFORM_BUFFER_EXT (0x8DEE)";
+case 0x8DEF /* GL_UNIFORM_BUFFER_BINDING_EXT */: return "GL_UNIFORM_BUFFER_BINDING_EXT (0x8DEF)";
+
+
+
+/* --------------------------- GL_EXT_blend_color -------------------------- */
+
+
+
+
+//case 0x8001 /* GL_CONSTANT_COLOR_EXT */: return "GL_CONSTANT_COLOR_EXT (0x8001)";
+//case 0x8002 /* GL_ONE_MINUS_CONSTANT_COLOR_EXT */: return "GL_ONE_MINUS_CONSTANT_COLOR_EXT (0x8002)";
+//case 0x8003 /* GL_CONSTANT_ALPHA_EXT */: return "GL_CONSTANT_ALPHA_EXT (0x8003)";
+//case 0x8004 /* GL_ONE_MINUS_CONSTANT_ALPHA_EXT */: return "GL_ONE_MINUS_CONSTANT_ALPHA_EXT (0x8004)";
+//case 0x8005 /* GL_BLEND_COLOR_EXT */: return "GL_BLEND_COLOR_EXT (0x8005)";/* --------------------- GL_EXT_blend_equation_separate -------------------- */
+
+
+
+
+//case 0x8009 /* GL_BLEND_EQUATION_RGB_EXT */: return "GL_BLEND_EQUATION_RGB_EXT (0x8009)";
+//case 0x883D /* GL_BLEND_EQUATION_ALPHA_EXT */: return "GL_BLEND_EQUATION_ALPHA_EXT (0x883D)";/* ----------------------- GL_EXT_blend_func_separate ---------------------- */
+
+
+
+
+//case 0x80C8 /* GL_BLEND_DST_RGB_EXT */: return "GL_BLEND_DST_RGB_EXT (0x80C8)";
+//case 0x80C9 /* GL_BLEND_SRC_RGB_EXT */: return "GL_BLEND_SRC_RGB_EXT (0x80C9)";
+//case 0x80CA /* GL_BLEND_DST_ALPHA_EXT */: return "GL_BLEND_DST_ALPHA_EXT (0x80CA)";
+//case 0x80CB /* GL_BLEND_SRC_ALPHA_EXT */: return "GL_BLEND_SRC_ALPHA_EXT (0x80CB)";/* ------------------------- GL_EXT_blend_logic_op ------------------------- */
+
+
+
+
+
+
+
+
+/* -------------------------- GL_EXT_blend_minmax -------------------------- */
+
+
+
+
+//case 0x8006 /* GL_FUNC_ADD_EXT */: return "GL_FUNC_ADD_EXT (0x8006)";
+//case 0x8007 /* GL_MIN_EXT */: return "GL_MIN_EXT (0x8007)";
+//case 0x8008 /* GL_MAX_EXT */: return "GL_MAX_EXT (0x8008)";
+//case 0x8009 /* GL_BLEND_EQUATION_EXT */: return "GL_BLEND_EQUATION_EXT (0x8009)";/* ------------------------- GL_EXT_blend_subtract ------------------------- */
+
+
+
+
+//case 0x800A /* GL_FUNC_SUBTRACT_EXT */: return "GL_FUNC_SUBTRACT_EXT (0x800A)";
+//case 0x800B /* GL_FUNC_REVERSE_SUBTRACT_EXT */: return "GL_FUNC_REVERSE_SUBTRACT_EXT (0x800B)";
+
+
+
+
+
+/* ------------------------ GL_EXT_clip_volume_hint ------------------------ */
+
+
+
+
+case 0x80F0 /* GL_CLIP_VOLUME_CLIPPING_HINT_EXT */: return "GL_CLIP_VOLUME_CLIPPING_HINT_EXT (0x80F0)";
+
+
+
+
+
+/* ------------------------------ GL_EXT_cmyka ----------------------------- */
+
+
+
+
+case 0x800C /* GL_CMYK_EXT */: return "GL_CMYK_EXT (0x800C)";
+case 0x800D /* GL_CMYKA_EXT */: return "GL_CMYKA_EXT (0x800D)";
+case 0x800E /* GL_PACK_CMYK_HINT_EXT */: return "GL_PACK_CMYK_HINT_EXT (0x800E)";
+case 0x800F /* GL_UNPACK_CMYK_HINT_EXT */: return "GL_UNPACK_CMYK_HINT_EXT (0x800F)";
+
+
+
+
+
+/* ------------------------- GL_EXT_color_subtable ------------------------- */
+
+
+
+
+/* ---------------------- GL_EXT_compiled_vertex_array --------------------- */
+
+
+
+
+case 0x81A8 /* GL_ARRAY_ELEMENT_LOCK_FIRST_EXT */: return "GL_ARRAY_ELEMENT_LOCK_FIRST_EXT (0x81A8)";
+case 0x81A9 /* GL_ARRAY_ELEMENT_LOCK_COUNT_EXT */: return "GL_ARRAY_ELEMENT_LOCK_COUNT_EXT (0x81A9)";
+
+/* --------------------------- GL_EXT_convolution -------------------------- */
+
+
+
+
+//case 0x8010 /* GL_CONVOLUTION_1D_EXT */: return "GL_CONVOLUTION_1D_EXT (0x8010)";
+//case 0x8011 /* GL_CONVOLUTION_2D_EXT */: return "GL_CONVOLUTION_2D_EXT (0x8011)";
+//case 0x8012 /* GL_SEPARABLE_2D_EXT */: return "GL_SEPARABLE_2D_EXT (0x8012)";
+//case 0x8013 /* GL_CONVOLUTION_BORDER_MODE_EXT */: return "GL_CONVOLUTION_BORDER_MODE_EXT (0x8013)";
+//case 0x8014 /* GL_CONVOLUTION_FILTER_SCALE_EXT */: return "GL_CONVOLUTION_FILTER_SCALE_EXT (0x8014)";
+//case 0x8015 /* GL_CONVOLUTION_FILTER_BIAS_EXT */: return "GL_CONVOLUTION_FILTER_BIAS_EXT (0x8015)";
+//case 0x8016 /* GL_REDUCE_EXT */: return "GL_REDUCE_EXT (0x8016)";
+//case 0x8017 /* GL_CONVOLUTION_FORMAT_EXT */: return "GL_CONVOLUTION_FORMAT_EXT (0x8017)";
+//case 0x8018 /* GL_CONVOLUTION_WIDTH_EXT */: return "GL_CONVOLUTION_WIDTH_EXT (0x8018)";
+//case 0x8019 /* GL_CONVOLUTION_HEIGHT_EXT */: return "GL_CONVOLUTION_HEIGHT_EXT (0x8019)";
+//case 0x801A /* GL_MAX_CONVOLUTION_WIDTH_EXT */: return "GL_MAX_CONVOLUTION_WIDTH_EXT (0x801A)";
+//case 0x801B /* GL_MAX_CONVOLUTION_HEIGHT_EXT */: return "GL_MAX_CONVOLUTION_HEIGHT_EXT (0x801B)";
+//case 0x801C /* GL_POST_CONVOLUTION_RED_SCALE_EXT */: return "GL_POST_CONVOLUTION_RED_SCALE_EXT (0x801C)";
+//case 0x801D /* GL_POST_CONVOLUTION_GREEN_SCALE_EXT */: return "GL_POST_CONVOLUTION_GREEN_SCALE_EXT (0x801D)";
+//case 0x801E /* GL_POST_CONVOLUTION_BLUE_SCALE_EXT */: return "GL_POST_CONVOLUTION_BLUE_SCALE_EXT (0x801E)";
+//case 0x801F /* GL_POST_CONVOLUTION_ALPHA_SCALE_EXT */: return "GL_POST_CONVOLUTION_ALPHA_SCALE_EXT (0x801F)";
+//case 0x8020 /* GL_POST_CONVOLUTION_RED_BIAS_EXT */: return "GL_POST_CONVOLUTION_RED_BIAS_EXT (0x8020)";
+//case 0x8021 /* GL_POST_CONVOLUTION_GREEN_BIAS_EXT */: return "GL_POST_CONVOLUTION_GREEN_BIAS_EXT (0x8021)";
+//case 0x8022 /* GL_POST_CONVOLUTION_BLUE_BIAS_EXT */: return "GL_POST_CONVOLUTION_BLUE_BIAS_EXT (0x8022)";
+//case 0x8023 /* GL_POST_CONVOLUTION_ALPHA_BIAS_EXT */: return "GL_POST_CONVOLUTION_ALPHA_BIAS_EXT (0x8023)";
+
+
+
+/* ------------------------ GL_EXT_coordinate_frame ------------------------ */
+
+
+
+
+case 0x8439 /* GL_TANGENT_ARRAY_EXT */: return "GL_TANGENT_ARRAY_EXT (0x8439)";
+case 0x843A /* GL_BINORMAL_ARRAY_EXT */: return "GL_BINORMAL_ARRAY_EXT (0x843A)";
+case 0x843B /* GL_CURRENT_TANGENT_EXT */: return "GL_CURRENT_TANGENT_EXT (0x843B)";
+case 0x843C /* GL_CURRENT_BINORMAL_EXT */: return "GL_CURRENT_BINORMAL_EXT (0x843C)";
+case 0x843E /* GL_TANGENT_ARRAY_TYPE_EXT */: return "GL_TANGENT_ARRAY_TYPE_EXT (0x843E)";
+case 0x843F /* GL_TANGENT_ARRAY_STRIDE_EXT */: return "GL_TANGENT_ARRAY_STRIDE_EXT (0x843F)";
+case 0x8440 /* GL_BINORMAL_ARRAY_TYPE_EXT */: return "GL_BINORMAL_ARRAY_TYPE_EXT (0x8440)";
+case 0x8441 /* GL_BINORMAL_ARRAY_STRIDE_EXT */: return "GL_BINORMAL_ARRAY_STRIDE_EXT (0x8441)";
+case 0x8442 /* GL_TANGENT_ARRAY_POINTER_EXT */: return "GL_TANGENT_ARRAY_POINTER_EXT (0x8442)";
+case 0x8443 /* GL_BINORMAL_ARRAY_POINTER_EXT */: return "GL_BINORMAL_ARRAY_POINTER_EXT (0x8443)";
+case 0x8444 /* GL_MAP1_TANGENT_EXT */: return "GL_MAP1_TANGENT_EXT (0x8444)";
+case 0x8445 /* GL_MAP2_TANGENT_EXT */: return "GL_MAP2_TANGENT_EXT (0x8445)";
+case 0x8446 /* GL_MAP1_BINORMAL_EXT */: return "GL_MAP1_BINORMAL_EXT (0x8446)";
+case 0x8447 /* GL_MAP2_BINORMAL_EXT */: return "GL_MAP2_BINORMAL_EXT (0x8447)";
+
+/* -------------------------- GL_EXT_copy_texture -------------------------- */
+/* --------------------------- GL_EXT_cull_vertex -------------------------- */
+
+
+
+
+case 0x81AA /* GL_CULL_VERTEX_EXT */: return "GL_CULL_VERTEX_EXT (0x81AA)";
+case 0x81AB /* GL_CULL_VERTEX_EYE_POSITION_EXT */: return "GL_CULL_VERTEX_EYE_POSITION_EXT (0x81AB)";
+case 0x81AC /* GL_CULL_VERTEX_OBJECT_POSITION_EXT */: return "GL_CULL_VERTEX_OBJECT_POSITION_EXT (0x81AC)";
+
+/* -------------------------- GL_EXT_debug_marker -------------------------- */
+
+
+
+
+
+
+/* ------------------------ GL_EXT_depth_bounds_test ----------------------- */
+
+
+
+
+case 0x8890 /* GL_DEPTH_BOUNDS_TEST_EXT */: return "GL_DEPTH_BOUNDS_TEST_EXT (0x8890)";
+case 0x8891 /* GL_DEPTH_BOUNDS_EXT */: return "GL_DEPTH_BOUNDS_EXT (0x8891)";/* ----------------------- GL_EXT_direct_state_access ---------------------- */
+
+
+
+
+case 0x8E2D /* GL_PROGRAM_MATRIX_EXT */: return "GL_PROGRAM_MATRIX_EXT (0x8E2D)";
+case 0x8E2E /* GL_TRANSPOSE_PROGRAM_MATRIX_EXT */: return "GL_TRANSPOSE_PROGRAM_MATRIX_EXT (0x8E2E)";
+case 0x8E2F /* GL_PROGRAM_MATRIX_STACK_DEPTH_EXT */: return "GL_PROGRAM_MATRIX_STACK_DEPTH_EXT (0x8E2F)";
+
+
+
+
+
+
+
+/* -------------------------- GL_EXT_draw_buffers2 ------------------------- */
+
+
+/* ------------------------- GL_EXT_draw_instanced ------------------------- */
+
+
+
+
+/* ----------------------- GL_EXT_draw_range_elements ---------------------- */
+
+
+
+
+//case 0x80E8 /* GL_MAX_ELEMENTS_VERTICES_EXT */: return "GL_MAX_ELEMENTS_VERTICES_EXT (0x80E8)";
+//case 0x80E9 /* GL_MAX_ELEMENTS_INDICES_EXT */: return "GL_MAX_ELEMENTS_INDICES_EXT (0x80E9)";/* ---------------------------- GL_EXT_fog_coord --------------------------- */
+
+
+
+
+//case 0x8450 /* GL_FOG_COORDINATE_SOURCE_EXT */: return "GL_FOG_COORDINATE_SOURCE_EXT (0x8450)";
+//case 0x8451 /* GL_FOG_COORDINATE_EXT */: return "GL_FOG_COORDINATE_EXT (0x8451)";
+//case 0x8452 /* GL_FRAGMENT_DEPTH_EXT */: return "GL_FRAGMENT_DEPTH_EXT (0x8452)";
+//case 0x8453 /* GL_CURRENT_FOG_COORDINATE_EXT */: return "GL_CURRENT_FOG_COORDINATE_EXT (0x8453)";
+//case 0x8454 /* GL_FOG_COORDINATE_ARRAY_TYPE_EXT */: return "GL_FOG_COORDINATE_ARRAY_TYPE_EXT (0x8454)";
+//case 0x8455 /* GL_FOG_COORDINATE_ARRAY_STRIDE_EXT */: return "GL_FOG_COORDINATE_ARRAY_STRIDE_EXT (0x8455)";
+//case 0x8456 /* GL_FOG_COORDINATE_ARRAY_POINTER_EXT */: return "GL_FOG_COORDINATE_ARRAY_POINTER_EXT (0x8456)";
+//case 0x8457 /* GL_FOG_COORDINATE_ARRAY_EXT */: return "GL_FOG_COORDINATE_ARRAY_EXT (0x8457)";
+
+
+
+
+
+
+
+/* ------------------------ GL_EXT_fragment_lighting ----------------------- */
+
+
+
+
+case 0x8400 /* GL_FRAGMENT_LIGHTING_EXT */: return "GL_FRAGMENT_LIGHTING_EXT (0x8400)";
+case 0x8401 /* GL_FRAGMENT_COLOR_MATERIAL_EXT */: return "GL_FRAGMENT_COLOR_MATERIAL_EXT (0x8401)";
+case 0x8402 /* GL_FRAGMENT_COLOR_MATERIAL_FACE_EXT */: return "GL_FRAGMENT_COLOR_MATERIAL_FACE_EXT (0x8402)";
+case 0x8403 /* GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_EXT */: return "GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_EXT (0x8403)";
+case 0x8404 /* GL_MAX_FRAGMENT_LIGHTS_EXT */: return "GL_MAX_FRAGMENT_LIGHTS_EXT (0x8404)";
+case 0x8405 /* GL_MAX_ACTIVE_LIGHTS_EXT */: return "GL_MAX_ACTIVE_LIGHTS_EXT (0x8405)";
+case 0x8406 /* GL_CURRENT_RASTER_NORMAL_EXT */: return "GL_CURRENT_RASTER_NORMAL_EXT (0x8406)";
+case 0x8407 /* GL_LIGHT_ENV_MODE_EXT */: return "GL_LIGHT_ENV_MODE_EXT (0x8407)";
+case 0x8408 /* GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_EXT */: return "GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_EXT (0x8408)";
+case 0x8409 /* GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_EXT */: return "GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_EXT (0x8409)";
+case 0x840A /* GL_FRAGMENT_LIGHT_MODEL_AMBIENT_EXT */: return "GL_FRAGMENT_LIGHT_MODEL_AMBIENT_EXT (0x840A)";
+case 0x840B /* GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_EXT */: return "GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_EXT (0x840B)";
+case 0x840C /* GL_FRAGMENT_LIGHT0_EXT */: return "GL_FRAGMENT_LIGHT0_EXT (0x840C)";
+case 0x8413 /* GL_FRAGMENT_LIGHT7_EXT */: return "GL_FRAGMENT_LIGHT7_EXT (0x8413)";
+
+
+
+/* ------------------------ GL_EXT_framebuffer_blit ------------------------ */
+
+
+
+
+//case 0x8CA6 /* GL_DRAW_FRAMEBUFFER_BINDING_EXT */: return "GL_DRAW_FRAMEBUFFER_BINDING_EXT (0x8CA6)";
+//case 0x8CA8 /* GL_READ_FRAMEBUFFER_EXT */: return "GL_READ_FRAMEBUFFER_EXT (0x8CA8)";
+//case 0x8CA9 /* GL_DRAW_FRAMEBUFFER_EXT */: return "GL_DRAW_FRAMEBUFFER_EXT (0x8CA9)";
+//case 0x8CAA /* GL_READ_FRAMEBUFFER_BINDING_EXT */: return "GL_READ_FRAMEBUFFER_BINDING_EXT (0x8CAA)";/* --------------------- GL_EXT_framebuffer_multisample -------------------- */
+
+
+
+
+//case 0x8CAB /* GL_RENDERBUFFER_SAMPLES_EXT */: return "GL_RENDERBUFFER_SAMPLES_EXT (0x8CAB)";
+//case 0x8D56 /* GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT */: return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT (0x8D56)";
+//case 0x8D57 /* GL_MAX_SAMPLES_EXT */: return "GL_MAX_SAMPLES_EXT (0x8D57)";/* --------------- GL_EXT_framebuffer_multisample_blit_scaled -------------- */
+
+
+
+
+case 0x90BA /* GL_SCALED_RESOLVE_FASTEST_EXT */: return "GL_SCALED_RESOLVE_FASTEST_EXT (0x90BA)";
+case 0x90BB /* GL_SCALED_RESOLVE_NICEST_EXT */: return "GL_SCALED_RESOLVE_NICEST_EXT (0x90BB)";
+
+
+
+
+
+/* ----------------------- GL_EXT_framebuffer_object ----------------------- */
+
+
+
+
+//case 0x0506 /* GL_INVALID_FRAMEBUFFER_OPERATION_EXT */: return "GL_INVALID_FRAMEBUFFER_OPERATION_EXT (0x0506)";
+//case 0x84E8 /* GL_MAX_RENDERBUFFER_SIZE_EXT */: return "GL_MAX_RENDERBUFFER_SIZE_EXT (0x84E8)";
+//case 0x8CA6 /* GL_FRAMEBUFFER_BINDING_EXT */: return "GL_FRAMEBUFFER_BINDING_EXT (0x8CA6)";
+//case 0x8CA7 /* GL_RENDERBUFFER_BINDING_EXT */: return "GL_RENDERBUFFER_BINDING_EXT (0x8CA7)";
+//case 0x8CD0 /* GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT */: return "GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT (0x8CD0)";
+//case 0x8CD1 /* GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT */: return "GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT (0x8CD1)";
+//case 0x8CD2 /* GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT */: return "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT (0x8CD2)";
+//case 0x8CD3 /* GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT */: return "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT (0x8CD3)";
+//case 0x8CD4 /* GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT */: return "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT (0x8CD4)";
+//case 0x8CD5 /* GL_FRAMEBUFFER_COMPLETE_EXT */: return "GL_FRAMEBUFFER_COMPLETE_EXT (0x8CD5)";
+//case 0x8CD6 /* GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT */: return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT (0x8CD6)";
+//case 0x8CD7 /* GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT */: return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT (0x8CD7)";
+case 0x8CD9 /* GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT */: return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT (0x8CD9)";
+case 0x8CDA /* GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT */: return "GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT (0x8CDA)";
+//case 0x8CDB /* GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT */: return "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT (0x8CDB)";
+//case 0x8CDC /* GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT */: return "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT (0x8CDC)";
+//case 0x8CDD /* GL_FRAMEBUFFER_UNSUPPORTED_EXT */: return "GL_FRAMEBUFFER_UNSUPPORTED_EXT (0x8CDD)";
+//case 0x8CDF /* GL_MAX_COLOR_ATTACHMENTS_EXT */: return "GL_MAX_COLOR_ATTACHMENTS_EXT (0x8CDF)";
+//case 0x8CE0 /* GL_COLOR_ATTACHMENT0_EXT */: return "GL_COLOR_ATTACHMENT0_EXT (0x8CE0)";
+//case 0x8CE1 /* GL_COLOR_ATTACHMENT1_EXT */: return "GL_COLOR_ATTACHMENT1_EXT (0x8CE1)";
+//case 0x8CE2 /* GL_COLOR_ATTACHMENT2_EXT */: return "GL_COLOR_ATTACHMENT2_EXT (0x8CE2)";
+//case 0x8CE3 /* GL_COLOR_ATTACHMENT3_EXT */: return "GL_COLOR_ATTACHMENT3_EXT (0x8CE3)";
+//case 0x8CE4 /* GL_COLOR_ATTACHMENT4_EXT */: return "GL_COLOR_ATTACHMENT4_EXT (0x8CE4)";
+//case 0x8CE5 /* GL_COLOR_ATTACHMENT5_EXT */: return "GL_COLOR_ATTACHMENT5_EXT (0x8CE5)";
+//case 0x8CE6 /* GL_COLOR_ATTACHMENT6_EXT */: return "GL_COLOR_ATTACHMENT6_EXT (0x8CE6)";
+//case 0x8CE7 /* GL_COLOR_ATTACHMENT7_EXT */: return "GL_COLOR_ATTACHMENT7_EXT (0x8CE7)";
+//case 0x8CE8 /* GL_COLOR_ATTACHMENT8_EXT */: return "GL_COLOR_ATTACHMENT8_EXT (0x8CE8)";
+//case 0x8CE9 /* GL_COLOR_ATTACHMENT9_EXT */: return "GL_COLOR_ATTACHMENT9_EXT (0x8CE9)";
+//case 0x8CEA /* GL_COLOR_ATTACHMENT10_EXT */: return "GL_COLOR_ATTACHMENT10_EXT (0x8CEA)";
+//case 0x8CEB /* GL_COLOR_ATTACHMENT11_EXT */: return "GL_COLOR_ATTACHMENT11_EXT (0x8CEB)";
+//case 0x8CEC /* GL_COLOR_ATTACHMENT12_EXT */: return "GL_COLOR_ATTACHMENT12_EXT (0x8CEC)";
+//case 0x8CED /* GL_COLOR_ATTACHMENT13_EXT */: return "GL_COLOR_ATTACHMENT13_EXT (0x8CED)";
+//case 0x8CEE /* GL_COLOR_ATTACHMENT14_EXT */: return "GL_COLOR_ATTACHMENT14_EXT (0x8CEE)";
+//case 0x8CEF /* GL_COLOR_ATTACHMENT15_EXT */: return "GL_COLOR_ATTACHMENT15_EXT (0x8CEF)";
+//case 0x8D00 /* GL_DEPTH_ATTACHMENT_EXT */: return "GL_DEPTH_ATTACHMENT_EXT (0x8D00)";
+//case 0x8D20 /* GL_STENCIL_ATTACHMENT_EXT */: return "GL_STENCIL_ATTACHMENT_EXT (0x8D20)";
+//case 0x8D40 /* GL_FRAMEBUFFER_EXT */: return "GL_FRAMEBUFFER_EXT (0x8D40)";
+//case 0x8D41 /* GL_RENDERBUFFER_EXT */: return "GL_RENDERBUFFER_EXT (0x8D41)";
+//case 0x8D42 /* GL_RENDERBUFFER_WIDTH_EXT */: return "GL_RENDERBUFFER_WIDTH_EXT (0x8D42)";
+//case 0x8D43 /* GL_RENDERBUFFER_HEIGHT_EXT */: return "GL_RENDERBUFFER_HEIGHT_EXT (0x8D43)";
+//case 0x8D44 /* GL_RENDERBUFFER_INTERNAL_FORMAT_EXT */: return "GL_RENDERBUFFER_INTERNAL_FORMAT_EXT (0x8D44)";
+//case 0x8D46 /* GL_STENCIL_INDEX1_EXT */: return "GL_STENCIL_INDEX1_EXT (0x8D46)";
+//case 0x8D47 /* GL_STENCIL_INDEX4_EXT */: return "GL_STENCIL_INDEX4_EXT (0x8D47)";
+//case 0x8D48 /* GL_STENCIL_INDEX8_EXT */: return "GL_STENCIL_INDEX8_EXT (0x8D48)";
+//case 0x8D49 /* GL_STENCIL_INDEX16_EXT */: return "GL_STENCIL_INDEX16_EXT (0x8D49)";
+//case 0x8D50 /* GL_RENDERBUFFER_RED_SIZE_EXT */: return "GL_RENDERBUFFER_RED_SIZE_EXT (0x8D50)";
+//case 0x8D51 /* GL_RENDERBUFFER_GREEN_SIZE_EXT */: return "GL_RENDERBUFFER_GREEN_SIZE_EXT (0x8D51)";
+//case 0x8D52 /* GL_RENDERBUFFER_BLUE_SIZE_EXT */: return "GL_RENDERBUFFER_BLUE_SIZE_EXT (0x8D52)";
+//case 0x8D53 /* GL_RENDERBUFFER_ALPHA_SIZE_EXT */: return "GL_RENDERBUFFER_ALPHA_SIZE_EXT (0x8D53)";
+//case 0x8D54 /* GL_RENDERBUFFER_DEPTH_SIZE_EXT */: return "GL_RENDERBUFFER_DEPTH_SIZE_EXT (0x8D54)";
+//case 0x8D55 /* GL_RENDERBUFFER_STENCIL_SIZE_EXT */: return "GL_RENDERBUFFER_STENCIL_SIZE_EXT (0x8D55)";
+
+/* ------------------------ GL_EXT_framebuffer_sRGB ------------------------ */
+
+
+
+
+//case 0x8DB9 /* GL_FRAMEBUFFER_SRGB_EXT */: return "GL_FRAMEBUFFER_SRGB_EXT (0x8DB9)";
+case 0x8DBA /* GL_FRAMEBUFFER_SRGB_CAPABLE_EXT */: return "GL_FRAMEBUFFER_SRGB_CAPABLE_EXT (0x8DBA)";
+
+
+
+
+
+/* ------------------------ GL_EXT_geometry_shader4 ------------------------ */
+
+
+
+
+//case 0xA /* GL_LINES_ADJACENCY_EXT */: return "GL_LINES_ADJACENCY_EXT (0xA)";
+//case 0xB /* GL_LINE_STRIP_ADJACENCY_EXT */: return "GL_LINE_STRIP_ADJACENCY_EXT (0xB)";
+//case 0xC /* GL_TRIANGLES_ADJACENCY_EXT */: return "GL_TRIANGLES_ADJACENCY_EXT (0xC)";
+//case 0xD /* GL_TRIANGLE_STRIP_ADJACENCY_EXT */: return "GL_TRIANGLE_STRIP_ADJACENCY_EXT (0xD)";
+//case 0x8642 /* GL_PROGRAM_POINT_SIZE_EXT */: return "GL_PROGRAM_POINT_SIZE_EXT (0x8642)";
+//case 0x8B4B /* GL_MAX_VARYING_COMPONENTS_EXT */: return "GL_MAX_VARYING_COMPONENTS_EXT (0x8B4B)";
+//case 0x8C29 /* GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT */: return "GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT (0x8C29)";
+//case 0x8CD4 /* GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT */: return "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT (0x8CD4)";
+//case 0x8DA7 /* GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT */: return "GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT (0x8DA7)";
+//case 0x8DA8 /* GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT */: return "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT (0x8DA8)";
+//case 0x8DA9 /* GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT */: return "GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT (0x8DA9)";
+//case 0x8DD9 /* GL_GEOMETRY_SHADER_EXT */: return "GL_GEOMETRY_SHADER_EXT (0x8DD9)";
+//case 0x8DDA /* GL_GEOMETRY_VERTICES_OUT_EXT */: return "GL_GEOMETRY_VERTICES_OUT_EXT (0x8DDA)";
+//case 0x8DDB /* GL_GEOMETRY_INPUT_TYPE_EXT */: return "GL_GEOMETRY_INPUT_TYPE_EXT (0x8DDB)";
+//case 0x8DDC /* GL_GEOMETRY_OUTPUT_TYPE_EXT */: return "GL_GEOMETRY_OUTPUT_TYPE_EXT (0x8DDC)";
+//case 0x8DDD /* GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT */: return "GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT (0x8DDD)";
+//case 0x8DDE /* GL_MAX_VERTEX_VARYING_COMPONENTS_EXT */: return "GL_MAX_VERTEX_VARYING_COMPONENTS_EXT (0x8DDE)";
+//case 0x8DDF /* GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT */: return "GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT (0x8DDF)";
+//case 0x8DE0 /* GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT */: return "GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT (0x8DE0)";
+//case 0x8DE1 /* GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT */: return "GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT (0x8DE1)";
+
+
+
+/* --------------------- GL_EXT_gpu_program_parameters --------------------- */
+
+
+
+
+/* --------------------------- GL_EXT_gpu_shader4 -------------------------- */
+
+
+
+
+//case 0x88FD /* GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT */: return "GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT (0x88FD)";
+//case 0x8DC0 /* GL_SAMPLER_1D_ARRAY_EXT */: return "GL_SAMPLER_1D_ARRAY_EXT (0x8DC0)";
+//case 0x8DC1 /* GL_SAMPLER_2D_ARRAY_EXT */: return "GL_SAMPLER_2D_ARRAY_EXT (0x8DC1)";
+//case 0x8DC2 /* GL_SAMPLER_BUFFER_EXT */: return "GL_SAMPLER_BUFFER_EXT (0x8DC2)";
+//case 0x8DC3 /* GL_SAMPLER_1D_ARRAY_SHADOW_EXT */: return "GL_SAMPLER_1D_ARRAY_SHADOW_EXT (0x8DC3)";
+//case 0x8DC4 /* GL_SAMPLER_2D_ARRAY_SHADOW_EXT */: return "GL_SAMPLER_2D_ARRAY_SHADOW_EXT (0x8DC4)";
+//case 0x8DC5 /* GL_SAMPLER_CUBE_SHADOW_EXT */: return "GL_SAMPLER_CUBE_SHADOW_EXT (0x8DC5)";
+//case 0x8DC6 /* GL_UNSIGNED_INT_VEC2_EXT */: return "GL_UNSIGNED_INT_VEC2_EXT (0x8DC6)";
+//case 0x8DC7 /* GL_UNSIGNED_INT_VEC3_EXT */: return "GL_UNSIGNED_INT_VEC3_EXT (0x8DC7)";
+//case 0x8DC8 /* GL_UNSIGNED_INT_VEC4_EXT */: return "GL_UNSIGNED_INT_VEC4_EXT (0x8DC8)";
+//case 0x8DC9 /* GL_INT_SAMPLER_1D_EXT */: return "GL_INT_SAMPLER_1D_EXT (0x8DC9)";
+//case 0x8DCA /* GL_INT_SAMPLER_2D_EXT */: return "GL_INT_SAMPLER_2D_EXT (0x8DCA)";
+//case 0x8DCB /* GL_INT_SAMPLER_3D_EXT */: return "GL_INT_SAMPLER_3D_EXT (0x8DCB)";
+//case 0x8DCC /* GL_INT_SAMPLER_CUBE_EXT */: return "GL_INT_SAMPLER_CUBE_EXT (0x8DCC)";
+//case 0x8DCD /* GL_INT_SAMPLER_2D_RECT_EXT */: return "GL_INT_SAMPLER_2D_RECT_EXT (0x8DCD)";
+//case 0x8DCE /* GL_INT_SAMPLER_1D_ARRAY_EXT */: return "GL_INT_SAMPLER_1D_ARRAY_EXT (0x8DCE)";
+//case 0x8DCF /* GL_INT_SAMPLER_2D_ARRAY_EXT */: return "GL_INT_SAMPLER_2D_ARRAY_EXT (0x8DCF)";
+//case 0x8DD0 /* GL_INT_SAMPLER_BUFFER_EXT */: return "GL_INT_SAMPLER_BUFFER_EXT (0x8DD0)";
+//case 0x8DD1 /* GL_UNSIGNED_INT_SAMPLER_1D_EXT */: return "GL_UNSIGNED_INT_SAMPLER_1D_EXT (0x8DD1)";
+//case 0x8DD2 /* GL_UNSIGNED_INT_SAMPLER_2D_EXT */: return "GL_UNSIGNED_INT_SAMPLER_2D_EXT (0x8DD2)";
+//case 0x8DD3 /* GL_UNSIGNED_INT_SAMPLER_3D_EXT */: return "GL_UNSIGNED_INT_SAMPLER_3D_EXT (0x8DD3)";
+//case 0x8DD4 /* GL_UNSIGNED_INT_SAMPLER_CUBE_EXT */: return "GL_UNSIGNED_INT_SAMPLER_CUBE_EXT (0x8DD4)";
+//case 0x8DD5 /* GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT */: return "GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT (0x8DD5)";
+//case 0x8DD6 /* GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT */: return "GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT (0x8DD6)";
+//case 0x8DD7 /* GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT */: return "GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT (0x8DD7)";
+//case 0x8DD8 /* GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT */: return "GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT (0x8DD8)";
+
+
+
+
+
+/* ---------------------------- GL_EXT_histogram --------------------------- */
+
+
+
+
+//case 0x8024 /* GL_HISTOGRAM_EXT */: return "GL_HISTOGRAM_EXT (0x8024)";
+//case 0x8025 /* GL_PROXY_HISTOGRAM_EXT */: return "GL_PROXY_HISTOGRAM_EXT (0x8025)";
+//case 0x8026 /* GL_HISTOGRAM_WIDTH_EXT */: return "GL_HISTOGRAM_WIDTH_EXT (0x8026)";
+//case 0x8027 /* GL_HISTOGRAM_FORMAT_EXT */: return "GL_HISTOGRAM_FORMAT_EXT (0x8027)";
+//case 0x8028 /* GL_HISTOGRAM_RED_SIZE_EXT */: return "GL_HISTOGRAM_RED_SIZE_EXT (0x8028)";
+//case 0x8029 /* GL_HISTOGRAM_GREEN_SIZE_EXT */: return "GL_HISTOGRAM_GREEN_SIZE_EXT (0x8029)";
+//case 0x802A /* GL_HISTOGRAM_BLUE_SIZE_EXT */: return "GL_HISTOGRAM_BLUE_SIZE_EXT (0x802A)";
+//case 0x802B /* GL_HISTOGRAM_ALPHA_SIZE_EXT */: return "GL_HISTOGRAM_ALPHA_SIZE_EXT (0x802B)";
+//case 0x802C /* GL_HISTOGRAM_LUMINANCE_SIZE_EXT */: return "GL_HISTOGRAM_LUMINANCE_SIZE_EXT (0x802C)";
+//case 0x802D /* GL_HISTOGRAM_SINK_EXT */: return "GL_HISTOGRAM_SINK_EXT (0x802D)";
+//case 0x802E /* GL_MINMAX_EXT */: return "GL_MINMAX_EXT (0x802E)";
+//case 0x802F /* GL_MINMAX_FORMAT_EXT */: return "GL_MINMAX_FORMAT_EXT (0x802F)";
+//case 0x8030 /* GL_MINMAX_SINK_EXT */: return "GL_MINMAX_SINK_EXT (0x8030)";
+
+
+
+
+
+
+
+/* ----------------------- GL_EXT_index_array_formats ---------------------- */
+
+
+
+
+
+
+
+
+/* --------------------------- GL_EXT_index_func --------------------------- */
+
+
+/* ------------------------- GL_EXT_index_material ------------------------- */
+
+
+/* -------------------------- GL_EXT_index_texture ------------------------- */
+
+
+
+
+
+
+
+
+/* -------------------------- GL_EXT_light_texture ------------------------- */
+
+
+
+
+case 0x8349 /* GL_FRAGMENT_MATERIAL_EXT */: return "GL_FRAGMENT_MATERIAL_EXT (0x8349)";
+case 0x834A /* GL_FRAGMENT_NORMAL_EXT */: return "GL_FRAGMENT_NORMAL_EXT (0x834A)";
+case 0x834C /* GL_FRAGMENT_COLOR_EXT */: return "GL_FRAGMENT_COLOR_EXT (0x834C)";
+case 0x834D /* GL_ATTENUATION_EXT */: return "GL_ATTENUATION_EXT (0x834D)";
+case 0x834E /* GL_SHADOW_ATTENUATION_EXT */: return "GL_SHADOW_ATTENUATION_EXT (0x834E)";
+case 0x834F /* GL_TEXTURE_APPLICATION_MODE_EXT */: return "GL_TEXTURE_APPLICATION_MODE_EXT (0x834F)";
+case 0x8350 /* GL_TEXTURE_LIGHT_EXT */: return "GL_TEXTURE_LIGHT_EXT (0x8350)";
+case 0x8351 /* GL_TEXTURE_MATERIAL_FACE_EXT */: return "GL_TEXTURE_MATERIAL_FACE_EXT (0x8351)";
+case 0x8352 /* GL_TEXTURE_MATERIAL_PARAMETER_EXT */: return "GL_TEXTURE_MATERIAL_PARAMETER_EXT (0x8352)";
+
+
+
+/* ------------------------- GL_EXT_misc_attribute ------------------------- */
+
+
+
+
+
+
+
+
+/* ------------------------ GL_EXT_multi_draw_arrays ----------------------- */
+
+
+
+
+/* --------------------------- GL_EXT_multisample -------------------------- */
+
+
+
+
+//case 0x809D /* GL_MULTISAMPLE_EXT */: return "GL_MULTISAMPLE_EXT (0x809D)";
+//case 0x809E /* GL_SAMPLE_ALPHA_TO_MASK_EXT */: return "GL_SAMPLE_ALPHA_TO_MASK_EXT (0x809E)";
+//case 0x809F /* GL_SAMPLE_ALPHA_TO_ONE_EXT */: return "GL_SAMPLE_ALPHA_TO_ONE_EXT (0x809F)";
+//case 0x80A0 /* GL_SAMPLE_MASK_EXT */: return "GL_SAMPLE_MASK_EXT (0x80A0)";
+case 0x80A1 /* GL_1PASS_EXT */: return "GL_1PASS_EXT (0x80A1)";
+case 0x80A2 /* GL_2PASS_0_EXT */: return "GL_2PASS_0_EXT (0x80A2)";
+case 0x80A3 /* GL_2PASS_1_EXT */: return "GL_2PASS_1_EXT (0x80A3)";
+case 0x80A4 /* GL_4PASS_0_EXT */: return "GL_4PASS_0_EXT (0x80A4)";
+case 0x80A5 /* GL_4PASS_1_EXT */: return "GL_4PASS_1_EXT (0x80A5)";
+case 0x80A6 /* GL_4PASS_2_EXT */: return "GL_4PASS_2_EXT (0x80A6)";
+case 0x80A7 /* GL_4PASS_3_EXT */: return "GL_4PASS_3_EXT (0x80A7)";
+//case 0x80A8 /* GL_SAMPLE_BUFFERS_EXT */: return "GL_SAMPLE_BUFFERS_EXT (0x80A8)";
+//case 0x80A9 /* GL_SAMPLES_EXT */: return "GL_SAMPLES_EXT (0x80A9)";
+//case 0x80AA /* GL_SAMPLE_MASK_VALUE_EXT */: return "GL_SAMPLE_MASK_VALUE_EXT (0x80AA)";
+//case 0x80AB /* GL_SAMPLE_MASK_INVERT_EXT */: return "GL_SAMPLE_MASK_INVERT_EXT (0x80AB)";
+case 0x80AC /* GL_SAMPLE_PATTERN_EXT */: return "GL_SAMPLE_PATTERN_EXT (0x80AC)";
+//case 0x20000000 /* GL_MULTISAMPLE_BIT_EXT */: return "GL_MULTISAMPLE_BIT_EXT (0x20000000)";
+
+/* ---------------------- GL_EXT_packed_depth_stencil ---------------------- */
+
+
+
+
+//case 0x84F9 /* GL_DEPTH_STENCIL_EXT */: return "GL_DEPTH_STENCIL_EXT (0x84F9)";
+//case 0x84FA /* GL_UNSIGNED_INT_24_8_EXT */: return "GL_UNSIGNED_INT_24_8_EXT (0x84FA)";
+//case 0x88F0 /* GL_DEPTH24_STENCIL8_EXT */: return "GL_DEPTH24_STENCIL8_EXT (0x88F0)";
+//case 0x88F1 /* GL_TEXTURE_STENCIL_SIZE_EXT */: return "GL_TEXTURE_STENCIL_SIZE_EXT (0x88F1)";
+
+
+
+
+
+/* -------------------------- GL_EXT_packed_float -------------------------- */
+
+
+
+
+//case 0x8C3A /* GL_R11F_G11F_B10F_EXT */: return "GL_R11F_G11F_B10F_EXT (0x8C3A)";
+//case 0x8C3B /* GL_UNSIGNED_INT_10F_11F_11F_REV_EXT */: return "GL_UNSIGNED_INT_10F_11F_11F_REV_EXT (0x8C3B)";
+case 0x8C3C /* GL_RGBA_SIGNED_COMPONENTS_EXT */: return "GL_RGBA_SIGNED_COMPONENTS_EXT (0x8C3C)";
+
+
+
+
+
+/* -------------------------- GL_EXT_packed_pixels ------------------------- */
+
+
+
+
+///case 0x8032 /* GL_UNSIGNED_BYTE_3_3_2_EXT */: return "GL_UNSIGNED_BYTE_3_3_2_EXT (0x8032)";
+//case 0x8033 /* GL_UNSIGNED_SHORT_4_4_4_4_EXT */: return "GL_UNSIGNED_SHORT_4_4_4_4_EXT (0x8033)";
+//case 0x8034 /* GL_UNSIGNED_SHORT_5_5_5_1_EXT */: return "GL_UNSIGNED_SHORT_5_5_5_1_EXT (0x8034)";
+//case 0x8035 /* GL_UNSIGNED_INT_8_8_8_8_EXT */: return "GL_UNSIGNED_INT_8_8_8_8_EXT (0x8035)";
+//case 0x8036 /* GL_UNSIGNED_INT_10_10_10_2_EXT */: return "GL_UNSIGNED_INT_10_10_10_2_EXT (0x8036)";
+
+
+
+
+
+/* ------------------------ GL_EXT_paletted_texture ------------------------ */
+
+
+
+
+//case 0x0DE0 /* GL_TEXTURE_1D */: return "GL_TEXTURE_1D (0x0DE0)";
+//case 0x0DE1 /* GL_TEXTURE_2D */: return "GL_TEXTURE_2D (0x0DE1)";
+//case 0x8063 /* GL_PROXY_TEXTURE_1D */: return "GL_PROXY_TEXTURE_1D (0x8063)";
+//case 0x8064 /* GL_PROXY_TEXTURE_2D */: return "GL_PROXY_TEXTURE_2D (0x8064)";
+//case 0x80D8 /* GL_COLOR_TABLE_FORMAT_EXT */: return "GL_COLOR_TABLE_FORMAT_EXT (0x80D8)";
+//case 0x80D9 /* GL_COLOR_TABLE_WIDTH_EXT */: return "GL_COLOR_TABLE_WIDTH_EXT (0x80D9)";
+//case 0x80DA /* GL_COLOR_TABLE_RED_SIZE_EXT */: return "GL_COLOR_TABLE_RED_SIZE_EXT (0x80DA)";
+//case 0x80DB /* GL_COLOR_TABLE_GREEN_SIZE_EXT */: return "GL_COLOR_TABLE_GREEN_SIZE_EXT (0x80DB)";
+//case 0x80DC /* GL_COLOR_TABLE_BLUE_SIZE_EXT */: return "GL_COLOR_TABLE_BLUE_SIZE_EXT (0x80DC)";
+//case 0x80DD /* GL_COLOR_TABLE_ALPHA_SIZE_EXT */: return "GL_COLOR_TABLE_ALPHA_SIZE_EXT (0x80DD)";
+//case 0x80DE /* GL_COLOR_TABLE_LUMINANCE_SIZE_EXT */: return "GL_COLOR_TABLE_LUMINANCE_SIZE_EXT (0x80DE)";
+//case 0x80DF /* GL_COLOR_TABLE_INTENSITY_SIZE_EXT */: return "GL_COLOR_TABLE_INTENSITY_SIZE_EXT (0x80DF)";
+//case 0x80E2 /* GL_COLOR_INDEX1_EXT */: return "GL_COLOR_INDEX1_EXT (0x80E2)";
+//case 0x80E3 /* GL_COLOR_INDEX2_EXT */: return "GL_COLOR_INDEX2_EXT (0x80E3)";
+//case 0x80E4 /* GL_COLOR_INDEX4_EXT */: return "GL_COLOR_INDEX4_EXT (0x80E4)";
+//case 0x80E5 /* GL_COLOR_INDEX8_EXT */: return "GL_COLOR_INDEX8_EXT (0x80E5)";
+//case 0x80E6 /* GL_COLOR_INDEX12_EXT */: return "GL_COLOR_INDEX12_EXT (0x80E6)";
+//case 0x80E7 /* GL_COLOR_INDEX16_EXT */: return "GL_COLOR_INDEX16_EXT (0x80E7)";
+case 0x80ED /* GL_TEXTURE_INDEX_SIZE_EXT */: return "GL_TEXTURE_INDEX_SIZE_EXT (0x80ED)";
+//case 0x8513 /* GL_TEXTURE_CUBE_MAP_ARB */: return "GL_TEXTURE_CUBE_MAP_ARB (0x8513)";
+//case 0x851B /* GL_PROXY_TEXTURE_CUBE_MAP_ARB */: return "GL_PROXY_TEXTURE_CUBE_MAP_ARB (0x851B)";
+
+
+
+
+
+/* ----------------------- GL_EXT_pixel_buffer_object ---------------------- */
+
+
+
+
+//case 0x88EB /* GL_PIXEL_PACK_BUFFER_EXT */: return "GL_PIXEL_PACK_BUFFER_EXT (0x88EB)";
+//case 0x88EC /* GL_PIXEL_UNPACK_BUFFER_EXT */: return "GL_PIXEL_UNPACK_BUFFER_EXT (0x88EC)";
+//case 0x88ED /* GL_PIXEL_PACK_BUFFER_BINDING_EXT */: return "GL_PIXEL_PACK_BUFFER_BINDING_EXT (0x88ED)";
+//case 0x88EF /* GL_PIXEL_UNPACK_BUFFER_BINDING_EXT */: return "GL_PIXEL_UNPACK_BUFFER_BINDING_EXT (0x88EF)";
+
+
+
+
+
+/* ------------------------- GL_EXT_pixel_transform ------------------------ */
+
+
+
+
+case 0x8330 /* GL_PIXEL_TRANSFORM_2D_EXT */: return "GL_PIXEL_TRANSFORM_2D_EXT (0x8330)";
+case 0x8331 /* GL_PIXEL_MAG_FILTER_EXT */: return "GL_PIXEL_MAG_FILTER_EXT (0x8331)";
+case 0x8332 /* GL_PIXEL_MIN_FILTER_EXT */: return "GL_PIXEL_MIN_FILTER_EXT (0x8332)";
+case 0x8333 /* GL_PIXEL_CUBIC_WEIGHT_EXT */: return "GL_PIXEL_CUBIC_WEIGHT_EXT (0x8333)";
+case 0x8334 /* GL_CUBIC_EXT */: return "GL_CUBIC_EXT (0x8334)";
+case 0x8335 /* GL_AVERAGE_EXT */: return "GL_AVERAGE_EXT (0x8335)";
+case 0x8336 /* GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT */: return "GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT (0x8336)";
+case 0x8337 /* GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT */: return "GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT (0x8337)";
+case 0x8338 /* GL_PIXEL_TRANSFORM_2D_MATRIX_EXT */: return "GL_PIXEL_TRANSFORM_2D_MATRIX_EXT (0x8338)";/* ------------------- GL_EXT_pixel_transform_color_table ------------------ */
+
+
+
+
+
+
+
+
+/* ------------------------ GL_EXT_point_parameters ------------------------ */
+
+
+
+
+//case 0x8126 /* GL_POINT_SIZE_MIN_EXT */: return "GL_POINT_SIZE_MIN_EXT (0x8126)";
+//case 0x8127 /* GL_POINT_SIZE_MAX_EXT */: return "GL_POINT_SIZE_MAX_EXT (0x8127)";
+//case 0x8128 /* GL_POINT_FADE_THRESHOLD_SIZE_EXT */: return "GL_POINT_FADE_THRESHOLD_SIZE_EXT (0x8128)";
+//case 0x8129 /* GL_DISTANCE_ATTENUATION_EXT */: return "GL_DISTANCE_ATTENUATION_EXT (0x8129)";
+
+/* ------------------------- GL_EXT_polygon_offset ------------------------- */
+
+
+
+
+//case 0x8037 /* GL_POLYGON_OFFSET_EXT */: return "GL_POLYGON_OFFSET_EXT (0x8037)";
+//case 0x8038 /* GL_POLYGON_OFFSET_FACTOR_EXT */: return "GL_POLYGON_OFFSET_FACTOR_EXT (0x8038)";
+case 0x8039 /* GL_POLYGON_OFFSET_BIAS_EXT */: return "GL_POLYGON_OFFSET_BIAS_EXT (0x8039)";/* ------------------------ GL_EXT_provoking_vertex ------------------------ */
+
+
+
+
+//case 0x8E4C /* GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT */: return "GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT (0x8E4C)";
+//case 0x8E4D /* GL_FIRST_VERTEX_CONVENTION_EXT */: return "GL_FIRST_VERTEX_CONVENTION_EXT (0x8E4D)";
+//case 0x8E4E /* GL_LAST_VERTEX_CONVENTION_EXT */: return "GL_LAST_VERTEX_CONVENTION_EXT (0x8E4E)";
+//case 0x8E4F /* GL_PROVOKING_VERTEX_EXT */: return "GL_PROVOKING_VERTEX_EXT (0x8E4F)";/* ------------------------- GL_EXT_rescale_normal ------------------------- */
+
+
+
+
+//case 0x803A /* GL_RESCALE_NORMAL_EXT */: return "GL_RESCALE_NORMAL_EXT (0x803A)";
+
+
+
+
+
+/* -------------------------- GL_EXT_scene_marker -------------------------- */
+
+
+
+
+/* ------------------------- GL_EXT_secondary_color ------------------------ */
+
+
+
+
+//case 0x8458 /* GL_COLOR_SUM_EXT */: return "GL_COLOR_SUM_EXT (0x8458)";
+//case 0x8459 /* GL_CURRENT_SECONDARY_COLOR_EXT */: return "GL_CURRENT_SECONDARY_COLOR_EXT (0x8459)";
+//case 0x845A /* GL_SECONDARY_COLOR_ARRAY_SIZE_EXT */: return "GL_SECONDARY_COLOR_ARRAY_SIZE_EXT (0x845A)";
+//case 0x845B /* GL_SECONDARY_COLOR_ARRAY_TYPE_EXT */: return "GL_SECONDARY_COLOR_ARRAY_TYPE_EXT (0x845B)";
+//case 0x845C /* GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT */: return "GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT (0x845C)";
+//case 0x845D /* GL_SECONDARY_COLOR_ARRAY_POINTER_EXT */: return "GL_SECONDARY_COLOR_ARRAY_POINTER_EXT (0x845D)";
+//case 0x845E /* GL_SECONDARY_COLOR_ARRAY_EXT */: return "GL_SECONDARY_COLOR_ARRAY_EXT (0x845E)";
+
+/* --------------------- GL_EXT_separate_shader_objects -------------------- */
+
+
+
+
+//case 0x8B8D /* GL_ACTIVE_PROGRAM_EXT */: return "GL_ACTIVE_PROGRAM_EXT (0x8B8D)";
+
+
+
+/* --------------------- GL_EXT_separate_specular_color -------------------- */
+
+
+
+
+//case 0x81F8 /* GL_LIGHT_MODEL_COLOR_CONTROL_EXT */: return "GL_LIGHT_MODEL_COLOR_CONTROL_EXT (0x81F8)";
+//case 0x81F9 /* GL_SINGLE_COLOR_EXT */: return "GL_SINGLE_COLOR_EXT (0x81F9)";
+//case 0x81FA /* GL_SEPARATE_SPECULAR_COLOR_EXT */: return "GL_SEPARATE_SPECULAR_COLOR_EXT (0x81FA)";
+
+
+
+
+
+/* --------------------- GL_EXT_shader_image_load_store -------------------- */
+
+
+
+
+//case 0x00000001 /* GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT */: return "GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT (0x00000001)";
+//case 0x00000002 /* GL_ELEMENT_ARRAY_BARRIER_BIT_EXT */: return "GL_ELEMENT_ARRAY_BARRIER_BIT_EXT (0x00000002)";
+//case 0x00000004 /* GL_UNIFORM_BARRIER_BIT_EXT */: return "GL_UNIFORM_BARRIER_BIT_EXT (0x00000004)";
+//case 0x00000008 /* GL_TEXTURE_FETCH_BARRIER_BIT_EXT */: return "GL_TEXTURE_FETCH_BARRIER_BIT_EXT (0x00000008)";
+//case 0x00000020 /* GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT */: return "GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT (0x00000020)";
+//case 0x00000040 /* GL_COMMAND_BARRIER_BIT_EXT */: return "GL_COMMAND_BARRIER_BIT_EXT (0x00000040)";
+//case 0x00000080 /* GL_PIXEL_BUFFER_BARRIER_BIT_EXT */: return "GL_PIXEL_BUFFER_BARRIER_BIT_EXT (0x00000080)";
+//case 0x00000100 /* GL_TEXTURE_UPDATE_BARRIER_BIT_EXT */: return "GL_TEXTURE_UPDATE_BARRIER_BIT_EXT (0x00000100)";
+//case 0x00000200 /* GL_BUFFER_UPDATE_BARRIER_BIT_EXT */: return "GL_BUFFER_UPDATE_BARRIER_BIT_EXT (0x00000200)";
+//case 0x00000400 /* GL_FRAMEBUFFER_BARRIER_BIT_EXT */: return "GL_FRAMEBUFFER_BARRIER_BIT_EXT (0x00000400)";
+//case 0x00000800 /* GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT */: return "GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT (0x00000800)";
+//case 0x00001000 /* GL_ATOMIC_COUNTER_BARRIER_BIT_EXT */: return "GL_ATOMIC_COUNTER_BARRIER_BIT_EXT (0x00001000)";
+//case 0x8F38 /* GL_MAX_IMAGE_UNITS_EXT */: return "GL_MAX_IMAGE_UNITS_EXT (0x8F38)";
+//case 0x8F39 /* GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT */: return "GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT (0x8F39)";
+//case 0x8F3A /* GL_IMAGE_BINDING_NAME_EXT */: return "GL_IMAGE_BINDING_NAME_EXT (0x8F3A)";
+//case 0x8F3B /* GL_IMAGE_BINDING_LEVEL_EXT */: return "GL_IMAGE_BINDING_LEVEL_EXT (0x8F3B)";
+//case 0x8F3C /* GL_IMAGE_BINDING_LAYERED_EXT */: return "GL_IMAGE_BINDING_LAYERED_EXT (0x8F3C)";
+//case 0x8F3D /* GL_IMAGE_BINDING_LAYER_EXT */: return "GL_IMAGE_BINDING_LAYER_EXT (0x8F3D)";
+//case 0x8F3E /* GL_IMAGE_BINDING_ACCESS_EXT */: return "GL_IMAGE_BINDING_ACCESS_EXT (0x8F3E)";
+//case 0x904C /* GL_IMAGE_1D_EXT */: return "GL_IMAGE_1D_EXT (0x904C)";
+//case 0x904D /* GL_IMAGE_2D_EXT */: return "GL_IMAGE_2D_EXT (0x904D)";
+//case 0x904E /* GL_IMAGE_3D_EXT */: return "GL_IMAGE_3D_EXT (0x904E)";
+//case 0x904F /* GL_IMAGE_2D_RECT_EXT */: return "GL_IMAGE_2D_RECT_EXT (0x904F)";
+//case 0x9050 /* GL_IMAGE_CUBE_EXT */: return "GL_IMAGE_CUBE_EXT (0x9050)";
+//case 0x9051 /* GL_IMAGE_BUFFER_EXT */: return "GL_IMAGE_BUFFER_EXT (0x9051)";
+//case 0x9052 /* GL_IMAGE_1D_ARRAY_EXT */: return "GL_IMAGE_1D_ARRAY_EXT (0x9052)";
+//case 0x9053 /* GL_IMAGE_2D_ARRAY_EXT */: return "GL_IMAGE_2D_ARRAY_EXT (0x9053)";
+//case 0x9054 /* GL_IMAGE_CUBE_MAP_ARRAY_EXT */: return "GL_IMAGE_CUBE_MAP_ARRAY_EXT (0x9054)";
+//case 0x9055 /* GL_IMAGE_2D_MULTISAMPLE_EXT */: return "GL_IMAGE_2D_MULTISAMPLE_EXT (0x9055)";
+//case 0x9056 /* GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT */: return "GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT (0x9056)";
+//case 0x9057 /* GL_INT_IMAGE_1D_EXT */: return "GL_INT_IMAGE_1D_EXT (0x9057)";
+//case 0x9058 /* GL_INT_IMAGE_2D_EXT */: return "GL_INT_IMAGE_2D_EXT (0x9058)";
+//case 0x9059 /* GL_INT_IMAGE_3D_EXT */: return "GL_INT_IMAGE_3D_EXT (0x9059)";
+//case 0x905A /* GL_INT_IMAGE_2D_RECT_EXT */: return "GL_INT_IMAGE_2D_RECT_EXT (0x905A)";
+//case 0x905B /* GL_INT_IMAGE_CUBE_EXT */: return "GL_INT_IMAGE_CUBE_EXT (0x905B)";
+//case 0x905C /* GL_INT_IMAGE_BUFFER_EXT */: return "GL_INT_IMAGE_BUFFER_EXT (0x905C)";
+//case 0x905D /* GL_INT_IMAGE_1D_ARRAY_EXT */: return "GL_INT_IMAGE_1D_ARRAY_EXT (0x905D)";
+//case 0x905E /* GL_INT_IMAGE_2D_ARRAY_EXT */: return "GL_INT_IMAGE_2D_ARRAY_EXT (0x905E)";
+//case 0x905F /* GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT */: return "GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT (0x905F)";
+//case 0x9060 /* GL_INT_IMAGE_2D_MULTISAMPLE_EXT */: return "GL_INT_IMAGE_2D_MULTISAMPLE_EXT (0x9060)";
+//case 0x9061 /* GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT */: return "GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT (0x9061)";
+//case 0x9062 /* GL_UNSIGNED_INT_IMAGE_1D_EXT */: return "GL_UNSIGNED_INT_IMAGE_1D_EXT (0x9062)";
+//case 0x9063 /* GL_UNSIGNED_INT_IMAGE_2D_EXT */: return "GL_UNSIGNED_INT_IMAGE_2D_EXT (0x9063)";
+//case 0x9064 /* GL_UNSIGNED_INT_IMAGE_3D_EXT */: return "GL_UNSIGNED_INT_IMAGE_3D_EXT (0x9064)";
+//case 0x9065 /* GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT */: return "GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT (0x9065)";
+//case 0x9066 /* GL_UNSIGNED_INT_IMAGE_CUBE_EXT */: return "GL_UNSIGNED_INT_IMAGE_CUBE_EXT (0x9066)";
+//case 0x9067 /* GL_UNSIGNED_INT_IMAGE_BUFFER_EXT */: return "GL_UNSIGNED_INT_IMAGE_BUFFER_EXT (0x9067)";
+//case 0x9068 /* GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT */: return "GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT (0x9068)";
+//case 0x9069 /* GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT */: return "GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT (0x9069)";
+///case 0x906A /* GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT */: return "GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT (0x906A)";
+//case 0x906B /* GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT */: return "GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT (0x906B)";
+//case 0x906C /* GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT */: return "GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT (0x906C)";
+//case 0x906D /* GL_MAX_IMAGE_SAMPLES_EXT */: return "GL_MAX_IMAGE_SAMPLES_EXT (0x906D)";
+//case 0x906E /* GL_IMAGE_BINDING_FORMAT_EXT */: return "GL_IMAGE_BINDING_FORMAT_EXT (0x906E)";
+//case 0xFFFFFFFF /* GL_ALL_BARRIER_BITS_EXT */: return "GL_ALL_BARRIER_BITS_EXT (0xFFFFFFFF)";
+
+/* -------------------------- GL_EXT_shadow_funcs -------------------------- */
+
+
+
+
+
+
+
+
+/* --------------------- GL_EXT_shared_texture_palette --------------------- */
+
+
+
+
+case 0x81FB /* GL_SHARED_TEXTURE_PALETTE_EXT */: return "GL_SHARED_TEXTURE_PALETTE_EXT (0x81FB)";
+
+
+
+
+
+/* ------------------------ GL_EXT_stencil_clear_tag ----------------------- */
+
+
+
+
+case 0x88F2 /* GL_STENCIL_TAG_BITS_EXT */: return "GL_STENCIL_TAG_BITS_EXT (0x88F2)";
+case 0x88F3 /* GL_STENCIL_CLEAR_TAG_VALUE_EXT */: return "GL_STENCIL_CLEAR_TAG_VALUE_EXT (0x88F3)";
+
+
+
+
+
+/* ------------------------ GL_EXT_stencil_two_side ------------------------ */
+
+
+
+
+case 0x8910 /* GL_STENCIL_TEST_TWO_SIDE_EXT */: return "GL_STENCIL_TEST_TWO_SIDE_EXT (0x8910)";
+case 0x8911 /* GL_ACTIVE_STENCIL_FACE_EXT */: return "GL_ACTIVE_STENCIL_FACE_EXT (0x8911)";/* -------------------------- GL_EXT_stencil_wrap -------------------------- */
+
+
+
+
+//case 0x8507 /* GL_INCR_WRAP_EXT */: return "GL_INCR_WRAP_EXT (0x8507)";
+//case 0x8508 /* GL_DECR_WRAP_EXT */: return "GL_DECR_WRAP_EXT (0x8508)";
+
+
+
+
+
+/* --------------------------- GL_EXT_subtexture --------------------------- */
+
+
+
+
+
+
+/* ----------------------------- GL_EXT_texture ---------------------------- */
+
+
+
+
+//case 0x803B /* GL_ALPHA4_EXT */: return "GL_ALPHA4_EXT (0x803B)";
+//case 0x803C /* GL_ALPHA8_EXT */: return "GL_ALPHA8_EXT (0x803C)";
+//case 0x803D /* GL_ALPHA12_EXT */: return "GL_ALPHA12_EXT (0x803D)";
+//case 0x803E /* GL_ALPHA16_EXT */: return "GL_ALPHA16_EXT (0x803E)";
+//case 0x803F /* GL_LUMINANCE4_EXT */: return "GL_LUMINANCE4_EXT (0x803F)";
+//case 0x8040 /* GL_LUMINANCE8_EXT */: return "GL_LUMINANCE8_EXT (0x8040)";
+//case 0x8041 /* GL_LUMINANCE12_EXT */: return "GL_LUMINANCE12_EXT (0x8041)";
+//case 0x8042 /* GL_LUMINANCE16_EXT */: return "GL_LUMINANCE16_EXT (0x8042)";
+//case 0x8043 /* GL_LUMINANCE4_ALPHA4_EXT */: return "GL_LUMINANCE4_ALPHA4_EXT (0x8043)";
+//case 0x8044 /* GL_LUMINANCE6_ALPHA2_EXT */: return "GL_LUMINANCE6_ALPHA2_EXT (0x8044)";
+//case 0x8045 /* GL_LUMINANCE8_ALPHA8_EXT */: return "GL_LUMINANCE8_ALPHA8_EXT (0x8045)";
+//case 0x8046 /* GL_LUMINANCE12_ALPHA4_EXT */: return "GL_LUMINANCE12_ALPHA4_EXT (0x8046)";
+//case 0x8047 /* GL_LUMINANCE12_ALPHA12_EXT */: return "GL_LUMINANCE12_ALPHA12_EXT (0x8047)";
+//case 0x8048 /* GL_LUMINANCE16_ALPHA16_EXT */: return "GL_LUMINANCE16_ALPHA16_EXT (0x8048)";
+//case 0x8049 /* GL_INTENSITY_EXT */: return "GL_INTENSITY_EXT (0x8049)";
+//case 0x804A /* GL_INTENSITY4_EXT */: return "GL_INTENSITY4_EXT (0x804A)";
+//case 0x804B /* GL_INTENSITY8_EXT */: return "GL_INTENSITY8_EXT (0x804B)";
+//case 0x804C /* GL_INTENSITY12_EXT */: return "GL_INTENSITY12_EXT (0x804C)";
+//case 0x804D /* GL_INTENSITY16_EXT */: return "GL_INTENSITY16_EXT (0x804D)";
+case 0x804E /* GL_RGB2_EXT */: return "GL_RGB2_EXT (0x804E)";
+//case 0x804F /* GL_RGB4_EXT */: return "GL_RGB4_EXT (0x804F)";
+//case 0x8050 /* GL_RGB5_EXT */: return "GL_RGB5_EXT (0x8050)";
+//case 0x8051 /* GL_RGB8_EXT */: return "GL_RGB8_EXT (0x8051)";
+//case 0x8052 /* GL_RGB10_EXT */: return "GL_RGB10_EXT (0x8052)";
+//case 0x8053 /* GL_RGB12_EXT */: return "GL_RGB12_EXT (0x8053)";
+//case 0x8054 /* GL_RGB16_EXT */: return "GL_RGB16_EXT (0x8054)";
+//case 0x8055 /* GL_RGBA2_EXT */: return "GL_RGBA2_EXT (0x8055)";
+//case 0x8056 /* GL_RGBA4_EXT */: return "GL_RGBA4_EXT (0x8056)";
+//case 0x8057 /* GL_RGB5_A1_EXT */: return "GL_RGB5_A1_EXT (0x8057)";
+//case 0x8058 /* GL_RGBA8_EXT */: return "GL_RGBA8_EXT (0x8058)";
+//case 0x8059 /* GL_RGB10_A2_EXT */: return "GL_RGB10_A2_EXT (0x8059)";
+//case 0x805A /* GL_RGBA12_EXT */: return "GL_RGBA12_EXT (0x805A)";
+//case 0x805B /* GL_RGBA16_EXT */: return "GL_RGBA16_EXT (0x805B)";
+//case 0x805C /* GL_TEXTURE_RED_SIZE_EXT */: return "GL_TEXTURE_RED_SIZE_EXT (0x805C)";
+//case 0x805D /* GL_TEXTURE_GREEN_SIZE_EXT */: return "GL_TEXTURE_GREEN_SIZE_EXT (0x805D)";
+//case 0x805E /* GL_TEXTURE_BLUE_SIZE_EXT */: return "GL_TEXTURE_BLUE_SIZE_EXT (0x805E)";
+//case 0x805F /* GL_TEXTURE_ALPHA_SIZE_EXT */: return "GL_TEXTURE_ALPHA_SIZE_EXT (0x805F)";
+//case 0x8060 /* GL_TEXTURE_LUMINANCE_SIZE_EXT */: return "GL_TEXTURE_LUMINANCE_SIZE_EXT (0x8060)";
+//case 0x8061 /* GL_TEXTURE_INTENSITY_SIZE_EXT */: return "GL_TEXTURE_INTENSITY_SIZE_EXT (0x8061)";
+case 0x8062 /* GL_REPLACE_EXT */: return "GL_REPLACE_EXT (0x8062)";
+//case 0x8063 /* GL_PROXY_TEXTURE_1D_EXT */: return "GL_PROXY_TEXTURE_1D_EXT (0x8063)";
+//case 0x8064 /* GL_PROXY_TEXTURE_2D_EXT */: return "GL_PROXY_TEXTURE_2D_EXT (0x8064)";
+
+
+
+
+
+/* ---------------------------- GL_EXT_texture3D --------------------------- */
+
+
+
+
+//case 0x806B /* GL_PACK_SKIP_IMAGES_EXT */: return "GL_PACK_SKIP_IMAGES_EXT (0x806B)";
+//case 0x806C /* GL_PACK_IMAGE_HEIGHT_EXT */: return "GL_PACK_IMAGE_HEIGHT_EXT (0x806C)";
+//case 0x806D /* GL_UNPACK_SKIP_IMAGES_EXT */: return "GL_UNPACK_SKIP_IMAGES_EXT (0x806D)";
+//case 0x806E /* GL_UNPACK_IMAGE_HEIGHT_EXT */: return "GL_UNPACK_IMAGE_HEIGHT_EXT (0x806E)";
+//case 0x806F /* GL_TEXTURE_3D_EXT */: return "GL_TEXTURE_3D_EXT (0x806F)";
+//case 0x8070 /* GL_PROXY_TEXTURE_3D_EXT */: return "GL_PROXY_TEXTURE_3D_EXT (0x8070)";
+//case 0x8071 /* GL_TEXTURE_DEPTH_EXT */: return "GL_TEXTURE_DEPTH_EXT (0x8071)";
+//case 0x8072 /* GL_TEXTURE_WRAP_R_EXT */: return "GL_TEXTURE_WRAP_R_EXT (0x8072)";
+//case 0x8073 /* GL_MAX_3D_TEXTURE_SIZE_EXT */: return "GL_MAX_3D_TEXTURE_SIZE_EXT (0x8073)";/* -------------------------- GL_EXT_texture_array ------------------------- */
+
+
+
+
+//case 0x884E /* GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT */: return "GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT (0x884E)";
+//case 0x88FF /* GL_MAX_ARRAY_TEXTURE_LAYERS_EXT */: return "GL_MAX_ARRAY_TEXTURE_LAYERS_EXT (0x88FF)";
+//case 0x8C18 /* GL_TEXTURE_1D_ARRAY_EXT */: return "GL_TEXTURE_1D_ARRAY_EXT (0x8C18)";
+//case 0x8C19 /* GL_PROXY_TEXTURE_1D_ARRAY_EXT */: return "GL_PROXY_TEXTURE_1D_ARRAY_EXT (0x8C19)";
+//case 0x8C1A /* GL_TEXTURE_2D_ARRAY_EXT */: return "GL_TEXTURE_2D_ARRAY_EXT (0x8C1A)";
+//case 0x8C1B /* GL_PROXY_TEXTURE_2D_ARRAY_EXT */: return "GL_PROXY_TEXTURE_2D_ARRAY_EXT (0x8C1B)";
+//case 0x8C1C /* GL_TEXTURE_BINDING_1D_ARRAY_EXT */: return "GL_TEXTURE_BINDING_1D_ARRAY_EXT (0x8C1C)";
+//case 0x8C1D /* GL_TEXTURE_BINDING_2D_ARRAY_EXT */: return "GL_TEXTURE_BINDING_2D_ARRAY_EXT (0x8C1D)";/* ---------------------- GL_EXT_texture_buffer_object --------------------- */
+
+
+
+
+//case 0x8C2A /* GL_TEXTURE_BUFFER_EXT */: return "GL_TEXTURE_BUFFER_EXT (0x8C2A)";
+//case 0x8C2B /* GL_MAX_TEXTURE_BUFFER_SIZE_EXT */: return "GL_MAX_TEXTURE_BUFFER_SIZE_EXT (0x8C2B)";
+//case 0x8C2C /* GL_TEXTURE_BINDING_BUFFER_EXT */: return "GL_TEXTURE_BINDING_BUFFER_EXT (0x8C2C)";
+//case 0x8C2D /* GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT */: return "GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT (0x8C2D)";
+//case 0x8C2E /* GL_TEXTURE_BUFFER_FORMAT_EXT */: return "GL_TEXTURE_BUFFER_FORMAT_EXT (0x8C2E)";/* -------------------- GL_EXT_texture_compression_dxt1 -------------------- */
+
+
+
+
+
+
+
+
+/* -------------------- GL_EXT_texture_compression_latc -------------------- */
+
+
+
+
+case 0x8C70 /* GL_COMPRESSED_LUMINANCE_LATC1_EXT */: return "GL_COMPRESSED_LUMINANCE_LATC1_EXT (0x8C70)";
+case 0x8C71 /* GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT */: return "GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT (0x8C71)";
+case 0x8C72 /* GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT */: return "GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT (0x8C72)";
+case 0x8C73 /* GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT */: return "GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT (0x8C73)";
+
+
+
+
+
+/* -------------------- GL_EXT_texture_compression_rgtc -------------------- */
+
+
+
+
+//case 0x8DBB /* GL_COMPRESSED_RED_RGTC1_EXT */: return "GL_COMPRESSED_RED_RGTC1_EXT (0x8DBB)";
+//case 0x8DBC /* GL_COMPRESSED_SIGNED_RED_RGTC1_EXT */: return "GL_COMPRESSED_SIGNED_RED_RGTC1_EXT (0x8DBC)";
+//case 0x8DBD /* GL_COMPRESSED_RED_GREEN_RGTC2_EXT */: return "GL_COMPRESSED_RED_GREEN_RGTC2_EXT (0x8DBD)";
+//case 0x8DBE /* GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT */: return "GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT (0x8DBE)";
+
+
+
+
+
+/* -------------------- GL_EXT_texture_compression_s3tc -------------------- */
+
+
+
+
+case 0x83F0 /* GL_COMPRESSED_RGB_S3TC_DXT1_EXT */: return "GL_COMPRESSED_RGB_S3TC_DXT1_EXT (0x83F0)";
+case 0x83F1 /* GL_COMPRESSED_RGBA_S3TC_DXT1_EXT */: return "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT (0x83F1)";
+case 0x83F2 /* GL_COMPRESSED_RGBA_S3TC_DXT3_EXT */: return "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT (0x83F2)";
+case 0x83F3 /* GL_COMPRESSED_RGBA_S3TC_DXT5_EXT */: return "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT (0x83F3)";
+
+
+
+
+
+/* ------------------------ GL_EXT_texture_cube_map ------------------------ */
+
+
+
+
+//case 0x8511 /* GL_NORMAL_MAP_EXT */: return "GL_NORMAL_MAP_EXT (0x8511)";
+//case 0x8512 /* GL_REFLECTION_MAP_EXT */: return "GL_REFLECTION_MAP_EXT (0x8512)";
+//case 0x8513 /* GL_TEXTURE_CUBE_MAP_EXT */: return "GL_TEXTURE_CUBE_MAP_EXT (0x8513)";
+//case 0x8514 /* GL_TEXTURE_BINDING_CUBE_MAP_EXT */: return "GL_TEXTURE_BINDING_CUBE_MAP_EXT (0x8514)";
+//case 0x8515 /* GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT */: return "GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT (0x8515)";
+//case 0x8516 /* GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT */: return "GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT (0x8516)";
+//case 0x8517 /* GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT */: return "GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT (0x8517)";
+//case 0x8518 /* GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT */: return "GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT (0x8518)";
+//case 0x8519 /* GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT */: return "GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT (0x8519)";
+//case 0x851A /* GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT */: return "GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT (0x851A)";
+//case 0x851B /* GL_PROXY_TEXTURE_CUBE_MAP_EXT */: return "GL_PROXY_TEXTURE_CUBE_MAP_EXT (0x851B)";
+//case 0x851C /* GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT */: return "GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT (0x851C)";
+
+
+
+
+
+/* ----------------------- GL_EXT_texture_edge_clamp ----------------------- */
+
+
+
+
+//case 0x812F /* GL_CLAMP_TO_EDGE_EXT */: return "GL_CLAMP_TO_EDGE_EXT (0x812F)";
+
+
+
+
+
+/* --------------------------- GL_EXT_texture_env -------------------------- */
+/* ------------------------- GL_EXT_texture_env_add ------------------------ */
+
+
+
+
+
+
+
+
+/* ----------------------- GL_EXT_texture_env_combine ---------------------- */
+
+
+
+
+//case 0x8570 /* GL_COMBINE_EXT */: return "GL_COMBINE_EXT (0x8570)";
+//case 0x8571 /* GL_COMBINE_RGB_EXT */: return "GL_COMBINE_RGB_EXT (0x8571)";
+//case 0x8572 /* GL_COMBINE_ALPHA_EXT */: return "GL_COMBINE_ALPHA_EXT (0x8572)";
+//case 0x8573 /* GL_RGB_SCALE_EXT */: return "GL_RGB_SCALE_EXT (0x8573)";
+//case 0x8574 /* GL_ADD_SIGNED_EXT */: return "GL_ADD_SIGNED_EXT (0x8574)";
+///case 0x8575 /* GL_INTERPOLATE_EXT */: return "GL_INTERPOLATE_EXT (0x8575)";
+//case 0x8576 /* GL_CONSTANT_EXT */: return "GL_CONSTANT_EXT (0x8576)";
+//case 0x8577 /* GL_PRIMARY_COLOR_EXT */: return "GL_PRIMARY_COLOR_EXT (0x8577)";
+//case 0x8578 /* GL_PREVIOUS_EXT */: return "GL_PREVIOUS_EXT (0x8578)";
+//case 0x8580 /* GL_SOURCE0_RGB_EXT */: return "GL_SOURCE0_RGB_EXT (0x8580)";
+//case 0x8581 /* GL_SOURCE1_RGB_EXT */: return "GL_SOURCE1_RGB_EXT (0x8581)";
+//case 0x8582 /* GL_SOURCE2_RGB_EXT */: return "GL_SOURCE2_RGB_EXT (0x8582)";
+//case 0x8588 /* GL_SOURCE0_ALPHA_EXT */: return "GL_SOURCE0_ALPHA_EXT (0x8588)";
+//case 0x8589 /* GL_SOURCE1_ALPHA_EXT */: return "GL_SOURCE1_ALPHA_EXT (0x8589)";
+//case 0x858A /* GL_SOURCE2_ALPHA_EXT */: return "GL_SOURCE2_ALPHA_EXT (0x858A)";
+//case 0x8590 /* GL_OPERAND0_RGB_EXT */: return "GL_OPERAND0_RGB_EXT (0x8590)";
+//case 0x8591 /* GL_OPERAND1_RGB_EXT */: return "GL_OPERAND1_RGB_EXT (0x8591)";
+//case 0x8592 /* GL_OPERAND2_RGB_EXT */: return "GL_OPERAND2_RGB_EXT (0x8592)";
+//case 0x8598 /* GL_OPERAND0_ALPHA_EXT */: return "GL_OPERAND0_ALPHA_EXT (0x8598)";
+//case 0x8599 /* GL_OPERAND1_ALPHA_EXT */: return "GL_OPERAND1_ALPHA_EXT (0x8599)";
+//case 0x859A /* GL_OPERAND2_ALPHA_EXT */: return "GL_OPERAND2_ALPHA_EXT (0x859A)";
+
+
+
+
+
+/* ------------------------ GL_EXT_texture_env_dot3 ------------------------ */
+
+
+
+
+case 0x8740 /* GL_DOT3_RGB_EXT */: return "GL_DOT3_RGB_EXT (0x8740)";
+//case 0x8741 /* GL_DOT3_RGBA_EXT */: return "GL_DOT3_RGBA_EXT (0x8741)";
+
+
+
+
+
+/* ------------------- GL_EXT_texture_filter_anisotropic ------------------- */
+
+
+
+
+case 0x84FE /* GL_TEXTURE_MAX_ANISOTROPY_EXT */: return "GL_TEXTURE_MAX_ANISOTROPY_EXT (0x84FE)";
+case 0x84FF /* GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT */: return "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT (0x84FF)";
+
+
+
+
+
+/* ------------------------- GL_EXT_texture_integer ------------------------ */
+
+
+
+
+//case 0x8D70 /* GL_RGBA32UI_EXT */: return "GL_RGBA32UI_EXT (0x8D70)";
+//case 0x8D71 /* GL_RGB32UI_EXT */: return "GL_RGB32UI_EXT (0x8D71)";
+case 0x8D72 /* GL_ALPHA32UI_EXT */: return "GL_ALPHA32UI_EXT (0x8D72)";
+case 0x8D73 /* GL_INTENSITY32UI_EXT */: return "GL_INTENSITY32UI_EXT (0x8D73)";
+case 0x8D74 /* GL_LUMINANCE32UI_EXT */: return "GL_LUMINANCE32UI_EXT (0x8D74)";
+case 0x8D75 /* GL_LUMINANCE_ALPHA32UI_EXT */: return "GL_LUMINANCE_ALPHA32UI_EXT (0x8D75)";
+//case 0x8D76 /* GL_RGBA16UI_EXT */: return "GL_RGBA16UI_EXT (0x8D76)";
+//case 0x8D77 /* GL_RGB16UI_EXT */: return "GL_RGB16UI_EXT (0x8D77)";
+case 0x8D78 /* GL_ALPHA16UI_EXT */: return "GL_ALPHA16UI_EXT (0x8D78)";
+case 0x8D79 /* GL_INTENSITY16UI_EXT */: return "GL_INTENSITY16UI_EXT (0x8D79)";
+case 0x8D7A /* GL_LUMINANCE16UI_EXT */: return "GL_LUMINANCE16UI_EXT (0x8D7A)";
+case 0x8D7B /* GL_LUMINANCE_ALPHA16UI_EXT */: return "GL_LUMINANCE_ALPHA16UI_EXT (0x8D7B)";
+//case 0x8D7C /* GL_RGBA8UI_EXT */: return "GL_RGBA8UI_EXT (0x8D7C)";
+//case 0x8D7D /* GL_RGB8UI_EXT */: return "GL_RGB8UI_EXT (0x8D7D)";
+case 0x8D7E /* GL_ALPHA8UI_EXT */: return "GL_ALPHA8UI_EXT (0x8D7E)";
+case 0x8D7F /* GL_INTENSITY8UI_EXT */: return "GL_INTENSITY8UI_EXT (0x8D7F)";
+case 0x8D80 /* GL_LUMINANCE8UI_EXT */: return "GL_LUMINANCE8UI_EXT (0x8D80)";
+case 0x8D81 /* GL_LUMINANCE_ALPHA8UI_EXT */: return "GL_LUMINANCE_ALPHA8UI_EXT (0x8D81)";
+//case 0x8D82 /* GL_RGBA32I_EXT */: return "GL_RGBA32I_EXT (0x8D82)";
+//case 0x8D83 /* GL_RGB32I_EXT */: return "GL_RGB32I_EXT (0x8D83)";
+case 0x8D84 /* GL_ALPHA32I_EXT */: return "GL_ALPHA32I_EXT (0x8D84)";
+case 0x8D85 /* GL_INTENSITY32I_EXT */: return "GL_INTENSITY32I_EXT (0x8D85)";
+case 0x8D86 /* GL_LUMINANCE32I_EXT */: return "GL_LUMINANCE32I_EXT (0x8D86)";
+case 0x8D87 /* GL_LUMINANCE_ALPHA32I_EXT */: return "GL_LUMINANCE_ALPHA32I_EXT (0x8D87)";
+//case 0x8D88 /* GL_RGBA16I_EXT */: return "GL_RGBA16I_EXT (0x8D88)";
+//case 0x8D89 /* GL_RGB16I_EXT */: return "GL_RGB16I_EXT (0x8D89)";
+case 0x8D8A /* GL_ALPHA16I_EXT */: return "GL_ALPHA16I_EXT (0x8D8A)";
+case 0x8D8B /* GL_INTENSITY16I_EXT */: return "GL_INTENSITY16I_EXT (0x8D8B)";
+case 0x8D8C /* GL_LUMINANCE16I_EXT */: return "GL_LUMINANCE16I_EXT (0x8D8C)";
+case 0x8D8D /* GL_LUMINANCE_ALPHA16I_EXT */: return "GL_LUMINANCE_ALPHA16I_EXT (0x8D8D)";
+//case 0x8D8E /* GL_RGBA8I_EXT */: return "GL_RGBA8I_EXT (0x8D8E)";
+//case 0x8D8F /* GL_RGB8I_EXT */: return "GL_RGB8I_EXT (0x8D8F)";
+case 0x8D90 /* GL_ALPHA8I_EXT */: return "GL_ALPHA8I_EXT (0x8D90)";
+case 0x8D91 /* GL_INTENSITY8I_EXT */: return "GL_INTENSITY8I_EXT (0x8D91)";
+case 0x8D92 /* GL_LUMINANCE8I_EXT */: return "GL_LUMINANCE8I_EXT (0x8D92)";
+case 0x8D93 /* GL_LUMINANCE_ALPHA8I_EXT */: return "GL_LUMINANCE_ALPHA8I_EXT (0x8D93)";
+//case 0x8D94 /* GL_RED_INTEGER_EXT */: return "GL_RED_INTEGER_EXT (0x8D94)";
+//case 0x8D95 /* GL_GREEN_INTEGER_EXT */: return "GL_GREEN_INTEGER_EXT (0x8D95)";
+//case 0x8D96 /* GL_BLUE_INTEGER_EXT */: return "GL_BLUE_INTEGER_EXT (0x8D96)";
+//case 0x8D97 /* GL_ALPHA_INTEGER_EXT */: return "GL_ALPHA_INTEGER_EXT (0x8D97)";
+//case 0x8D98 /* GL_RGB_INTEGER_EXT */: return "GL_RGB_INTEGER_EXT (0x8D98)";
+//case 0x8D99 /* GL_RGBA_INTEGER_EXT */: return "GL_RGBA_INTEGER_EXT (0x8D99)";
+//case 0x8D9A /* GL_BGR_INTEGER_EXT */: return "GL_BGR_INTEGER_EXT (0x8D9A)";
+//case 0x8D9B /* GL_BGRA_INTEGER_EXT */: return "GL_BGRA_INTEGER_EXT (0x8D9B)";
+case 0x8D9C /* GL_LUMINANCE_INTEGER_EXT */: return "GL_LUMINANCE_INTEGER_EXT (0x8D9C)";
+case 0x8D9D /* GL_LUMINANCE_ALPHA_INTEGER_EXT */: return "GL_LUMINANCE_ALPHA_INTEGER_EXT (0x8D9D)";
+case 0x8D9E /* GL_RGBA_INTEGER_MODE_EXT */: return "GL_RGBA_INTEGER_MODE_EXT (0x8D9E)";/* ------------------------ GL_EXT_texture_lod_bias ------------------------ */
+
+
+
+
+//case 0x84FD /* GL_MAX_TEXTURE_LOD_BIAS_EXT */: return "GL_MAX_TEXTURE_LOD_BIAS_EXT (0x84FD)";
+//case 0x8500 /* GL_TEXTURE_FILTER_CONTROL_EXT */: return "GL_TEXTURE_FILTER_CONTROL_EXT (0x8500)";
+//case 0x8501 /* GL_TEXTURE_LOD_BIAS_EXT */: return "GL_TEXTURE_LOD_BIAS_EXT (0x8501)";
+
+
+
+
+
+/* ---------------------- GL_EXT_texture_mirror_clamp ---------------------- */
+
+
+
+
+//case 0x8742 /* GL_MIRROR_CLAMP_EXT */: return "GL_MIRROR_CLAMP_EXT (0x8742)";
+//case 0x8743 /* GL_MIRROR_CLAMP_TO_EDGE_EXT */: return "GL_MIRROR_CLAMP_TO_EDGE_EXT (0x8743)";
+case 0x8912 /* GL_MIRROR_CLAMP_TO_BORDER_EXT */: return "GL_MIRROR_CLAMP_TO_BORDER_EXT (0x8912)";
+
+
+
+
+
+/* ------------------------- GL_EXT_texture_object ------------------------- */
+
+
+
+
+//case 0x8066 /* GL_TEXTURE_PRIORITY_EXT */: return "GL_TEXTURE_PRIORITY_EXT (0x8066)";
+//case 0x8067 /* GL_TEXTURE_RESIDENT_EXT */: return "GL_TEXTURE_RESIDENT_EXT (0x8067)";
+//case 0x8068 /* GL_TEXTURE_1D_BINDING_EXT */: return "GL_TEXTURE_1D_BINDING_EXT (0x8068)";
+//case 0x8069 /* GL_TEXTURE_2D_BINDING_EXT */: return "GL_TEXTURE_2D_BINDING_EXT (0x8069)";
+//case 0x806A /* GL_TEXTURE_3D_BINDING_EXT */: return "GL_TEXTURE_3D_BINDING_EXT (0x806A)";/* --------------------- GL_EXT_texture_perturb_normal --------------------- */
+
+
+
+
+case 0x85AE /* GL_PERTURB_EXT */: return "GL_PERTURB_EXT (0x85AE)";
+case 0x85AF /* GL_TEXTURE_NORMAL_EXT */: return "GL_TEXTURE_NORMAL_EXT (0x85AF)";/* ------------------------ GL_EXT_texture_rectangle ----------------------- */
+
+
+
+
+//case 0x84F5 /* GL_TEXTURE_RECTANGLE_EXT */: return "GL_TEXTURE_RECTANGLE_EXT (0x84F5)";
+//case 0x84F6 /* GL_TEXTURE_BINDING_RECTANGLE_EXT */: return "GL_TEXTURE_BINDING_RECTANGLE_EXT (0x84F6)";
+//case 0x84F7 /* GL_PROXY_TEXTURE_RECTANGLE_EXT */: return "GL_PROXY_TEXTURE_RECTANGLE_EXT (0x84F7)";
+//case 0x84F8 /* GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT */: return "GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT (0x84F8)";
+
+
+
+
+
+/* -------------------------- GL_EXT_texture_sRGB -------------------------- */
+
+
+
+
+//case 0x8C40 /* GL_SRGB_EXT */: return "GL_SRGB_EXT (0x8C40)";
+//case 0x8C41 /* GL_SRGB8_EXT */: return "GL_SRGB8_EXT (0x8C41)";
+//case 0x8C42 /* GL_SRGB_ALPHA_EXT */: return "GL_SRGB_ALPHA_EXT (0x8C42)";
+//case 0x8C43 /* GL_SRGB8_ALPHA8_EXT */: return "GL_SRGB8_ALPHA8_EXT (0x8C43)";
+//case 0x8C44 /* GL_SLUMINANCE_ALPHA_EXT */: return "GL_SLUMINANCE_ALPHA_EXT (0x8C44)";
+//case 0x8C45 /* GL_SLUMINANCE8_ALPHA8_EXT */: return "GL_SLUMINANCE8_ALPHA8_EXT (0x8C45)";
+//case 0x8C46 /* GL_SLUMINANCE_EXT */: return "GL_SLUMINANCE_EXT (0x8C46)";
+//case 0x8C47 /* GL_SLUMINANCE8_EXT */: return "GL_SLUMINANCE8_EXT (0x8C47)";
+//case 0x8C48 /* GL_COMPRESSED_SRGB_EXT */: return "GL_COMPRESSED_SRGB_EXT (0x8C48)";
+//case 0x8C49 /* GL_COMPRESSED_SRGB_ALPHA_EXT */: return "GL_COMPRESSED_SRGB_ALPHA_EXT (0x8C49)";
+//case 0x8C4A /* GL_COMPRESSED_SLUMINANCE_EXT */: return "GL_COMPRESSED_SLUMINANCE_EXT (0x8C4A)";
+//case 0x8C4B /* GL_COMPRESSED_SLUMINANCE_ALPHA_EXT */: return "GL_COMPRESSED_SLUMINANCE_ALPHA_EXT (0x8C4B)";
+case 0x8C4C /* GL_COMPRESSED_SRGB_S3TC_DXT1_EXT */: return "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT (0x8C4C)";
+case 0x8C4D /* GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT */: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT (0x8C4D)";
+case 0x8C4E /* GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT */: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT (0x8C4E)";
+case 0x8C4F /* GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT */: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT (0x8C4F)";
+
+
+
+
+
+/* ----------------------- GL_EXT_texture_sRGB_decode ---------------------- */
+
+
+
+
+case 0x8A48 /* GL_TEXTURE_SRGB_DECODE_EXT */: return "GL_TEXTURE_SRGB_DECODE_EXT (0x8A48)";
+case 0x8A49 /* GL_DECODE_EXT */: return "GL_DECODE_EXT (0x8A49)";
+case 0x8A4A /* GL_SKIP_DECODE_EXT */: return "GL_SKIP_DECODE_EXT (0x8A4A)";
+
+
+
+
+
+/* --------------------- GL_EXT_texture_shared_exponent -------------------- */
+
+
+
+
+//case 0x8C3D /* GL_RGB9_E5_EXT */: return "GL_RGB9_E5_EXT (0x8C3D)";
+//case 0x8C3E /* GL_UNSIGNED_INT_5_9_9_9_REV_EXT */: return "GL_UNSIGNED_INT_5_9_9_9_REV_EXT (0x8C3E)";
+//case 0x8C3F /* GL_TEXTURE_SHARED_SIZE_EXT */: return "GL_TEXTURE_SHARED_SIZE_EXT (0x8C3F)";
+
+
+
+
+
+/* -------------------------- GL_EXT_texture_snorm ------------------------- */
+
+
+
+
+//case 0x8F90 /* GL_RED_SNORM */: return "GL_RED_SNORM (0x8F90)";
+//case 0x8F91 /* GL_RG_SNORM */: return "GL_RG_SNORM (0x8F91)";
+//case 0x8F92 /* GL_RGB_SNORM */: return "GL_RGB_SNORM (0x8F92)";
+//case 0x8F93 /* GL_RGBA_SNORM */: return "GL_RGBA_SNORM (0x8F93)";
+//case 0x8F94 /* GL_R8_SNORM */: return "GL_R8_SNORM (0x8F94)";
+//case 0x8F95 /* GL_RG8_SNORM */: return "GL_RG8_SNORM (0x8F95)";
+//case 0x8F96 /* GL_RGB8_SNORM */: return "GL_RGB8_SNORM (0x8F96)";
+//case 0x8F97 /* GL_RGBA8_SNORM */: return "GL_RGBA8_SNORM (0x8F97)";
+//case 0x8F98 /* GL_R16_SNORM */: return "GL_R16_SNORM (0x8F98)";
+//case 0x8F99 /* GL_RG16_SNORM */: return "GL_RG16_SNORM (0x8F99)";
+//case 0x8F9A /* GL_RGB16_SNORM */: return "GL_RGB16_SNORM (0x8F9A)";
+//case 0x8F9B /* GL_RGBA16_SNORM */: return "GL_RGBA16_SNORM (0x8F9B)";
+//case 0x8F9C /* GL_SIGNED_NORMALIZED */: return "GL_SIGNED_NORMALIZED (0x8F9C)";
+case 0x9010 /* GL_ALPHA_SNORM */: return "GL_ALPHA_SNORM (0x9010)";
+case 0x9011 /* GL_LUMINANCE_SNORM */: return "GL_LUMINANCE_SNORM (0x9011)";
+case 0x9012 /* GL_LUMINANCE_ALPHA_SNORM */: return "GL_LUMINANCE_ALPHA_SNORM (0x9012)";
+case 0x9013 /* GL_INTENSITY_SNORM */: return "GL_INTENSITY_SNORM (0x9013)";
+case 0x9014 /* GL_ALPHA8_SNORM */: return "GL_ALPHA8_SNORM (0x9014)";
+case 0x9015 /* GL_LUMINANCE8_SNORM */: return "GL_LUMINANCE8_SNORM (0x9015)";
+case 0x9016 /* GL_LUMINANCE8_ALPHA8_SNORM */: return "GL_LUMINANCE8_ALPHA8_SNORM (0x9016)";
+case 0x9017 /* GL_INTENSITY8_SNORM */: return "GL_INTENSITY8_SNORM (0x9017)";
+case 0x9018 /* GL_ALPHA16_SNORM */: return "GL_ALPHA16_SNORM (0x9018)";
+case 0x9019 /* GL_LUMINANCE16_SNORM */: return "GL_LUMINANCE16_SNORM (0x9019)";
+case 0x901A /* GL_LUMINANCE16_ALPHA16_SNORM */: return "GL_LUMINANCE16_ALPHA16_SNORM (0x901A)";
+case 0x901B /* GL_INTENSITY16_SNORM */: return "GL_INTENSITY16_SNORM (0x901B)";
+
+
+
+
+
+/* ------------------------- GL_EXT_texture_swizzle ------------------------ */
+
+
+
+
+//case 0x8E42 /* GL_TEXTURE_SWIZZLE_R_EXT */: return "GL_TEXTURE_SWIZZLE_R_EXT (0x8E42)";
+//case 0x8E43 /* GL_TEXTURE_SWIZZLE_G_EXT */: return "GL_TEXTURE_SWIZZLE_G_EXT (0x8E43)";
+//case 0x8E44 /* GL_TEXTURE_SWIZZLE_B_EXT */: return "GL_TEXTURE_SWIZZLE_B_EXT (0x8E44)";
+//case 0x8E45 /* GL_TEXTURE_SWIZZLE_A_EXT */: return "GL_TEXTURE_SWIZZLE_A_EXT (0x8E45)";
+//case 0x8E46 /* GL_TEXTURE_SWIZZLE_RGBA_EXT */: return "GL_TEXTURE_SWIZZLE_RGBA_EXT (0x8E46)";
+
+
+
+
+
+/* --------------------------- GL_EXT_timer_query -------------------------- */
+
+
+
+
+//case 0x88BF /* GL_TIME_ELAPSED_EXT */: return "GL_TIME_ELAPSED_EXT (0x88BF)";
+
+/* ----------------------- GL_EXT_transform_feedback ----------------------- */
+
+
+
+
+//case 0x8C76 /* GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT */: return "GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT (0x8C76)";
+//case 0x8C7F /* GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT */: return "GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT (0x8C7F)";
+///case 0x8C80 /* GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT */: return "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT (0x8C80)";
+//case 0x8C83 /* GL_TRANSFORM_FEEDBACK_VARYINGS_EXT */: return "GL_TRANSFORM_FEEDBACK_VARYINGS_EXT (0x8C83)";
+//case 0x8C84 /* GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT */: return "GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT (0x8C84)";
+//case 0x8C85 /* GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT */: return "GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT (0x8C85)";
+//case 0x8C87 /* GL_PRIMITIVES_GENERATED_EXT */: return "GL_PRIMITIVES_GENERATED_EXT (0x8C87)";
+//case 0x8C88 /* GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT */: return "GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT (0x8C88)";
+//case 0x8C89 /* GL_RASTERIZER_DISCARD_EXT */: return "GL_RASTERIZER_DISCARD_EXT (0x8C89)";
+//case 0x8C8A /* GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT */: return "GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT (0x8C8A)";
+//case 0x8C8B /* GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT */: return "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT (0x8C8B)";
+//case 0x8C8C /* GL_INTERLEAVED_ATTRIBS_EXT */: return "GL_INTERLEAVED_ATTRIBS_EXT (0x8C8C)";
+//case 0x8C8D /* GL_SEPARATE_ATTRIBS_EXT */: return "GL_SEPARATE_ATTRIBS_EXT (0x8C8D)";
+//case 0x8C8E /* GL_TRANSFORM_FEEDBACK_BUFFER_EXT */: return "GL_TRANSFORM_FEEDBACK_BUFFER_EXT (0x8C8E)";
+//case 0x8C8F /* GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT */: return "GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT (0x8C8F)";
+
+/* -------------------------- GL_EXT_vertex_array -------------------------- */
+
+
+
+
+//case 0x140A /* GL_DOUBLE_EXT */: return "GL_DOUBLE_EXT (0x140A)";
+//case 0x8074 /* GL_VERTEX_ARRAY_EXT */: return "GL_VERTEX_ARRAY_EXT (0x8074)";
+//case 0x8075 /* GL_NORMAL_ARRAY_EXT */: return "GL_NORMAL_ARRAY_EXT (0x8075)";
+//case 0x8076 /* GL_COLOR_ARRAY_EXT */: return "GL_COLOR_ARRAY_EXT (0x8076)";
+//case 0x8077 /* GL_INDEX_ARRAY_EXT */: return "GL_INDEX_ARRAY_EXT (0x8077)";
+//case 0x8078 /* GL_TEXTURE_COORD_ARRAY_EXT */: return "GL_TEXTURE_COORD_ARRAY_EXT (0x8078)";
+//case 0x8079 /* GL_EDGE_FLAG_ARRAY_EXT */: return "GL_EDGE_FLAG_ARRAY_EXT (0x8079)";
+//case 0x807A /* GL_VERTEX_ARRAY_SIZE_EXT */: return "GL_VERTEX_ARRAY_SIZE_EXT (0x807A)";
+//case 0x807B /* GL_VERTEX_ARRAY_TYPE_EXT */: return "GL_VERTEX_ARRAY_TYPE_EXT (0x807B)";
+//case 0x807C /* GL_VERTEX_ARRAY_STRIDE_EXT */: return "GL_VERTEX_ARRAY_STRIDE_EXT (0x807C)";
+case 0x807D /* GL_VERTEX_ARRAY_COUNT_EXT */: return "GL_VERTEX_ARRAY_COUNT_EXT (0x807D)";
+//case 0x807E /* GL_NORMAL_ARRAY_TYPE_EXT */: return "GL_NORMAL_ARRAY_TYPE_EXT (0x807E)";
+//case 0x807F /* GL_NORMAL_ARRAY_STRIDE_EXT */: return "GL_NORMAL_ARRAY_STRIDE_EXT (0x807F)";
+case 0x8080 /* GL_NORMAL_ARRAY_COUNT_EXT */: return "GL_NORMAL_ARRAY_COUNT_EXT (0x8080)";
+//case 0x8081 /* GL_COLOR_ARRAY_SIZE_EXT */: return "GL_COLOR_ARRAY_SIZE_EXT (0x8081)";
+//case 0x8082 /* GL_COLOR_ARRAY_TYPE_EXT */: return "GL_COLOR_ARRAY_TYPE_EXT (0x8082)";
+//case 0x8083 /* GL_COLOR_ARRAY_STRIDE_EXT */: return "GL_COLOR_ARRAY_STRIDE_EXT (0x8083)";
+case 0x8084 /* GL_COLOR_ARRAY_COUNT_EXT */: return "GL_COLOR_ARRAY_COUNT_EXT (0x8084)";
+//case 0x8085 /* GL_INDEX_ARRAY_TYPE_EXT */: return "GL_INDEX_ARRAY_TYPE_EXT (0x8085)";
+//case 0x8086 /* GL_INDEX_ARRAY_STRIDE_EXT */: return "GL_INDEX_ARRAY_STRIDE_EXT (0x8086)";
+case 0x8087 /* GL_INDEX_ARRAY_COUNT_EXT */: return "GL_INDEX_ARRAY_COUNT_EXT (0x8087)";
+//case 0x8088 /* GL_TEXTURE_COORD_ARRAY_SIZE_EXT */: return "GL_TEXTURE_COORD_ARRAY_SIZE_EXT (0x8088)";
+//case 0x8089 /* GL_TEXTURE_COORD_ARRAY_TYPE_EXT */: return "GL_TEXTURE_COORD_ARRAY_TYPE_EXT (0x8089)";
+//case 0x808A /* GL_TEXTURE_COORD_ARRAY_STRIDE_EXT */: return "GL_TEXTURE_COORD_ARRAY_STRIDE_EXT (0x808A)";
+case 0x808B /* GL_TEXTURE_COORD_ARRAY_COUNT_EXT */: return "GL_TEXTURE_COORD_ARRAY_COUNT_EXT (0x808B)";
+//case 0x808C /* GL_EDGE_FLAG_ARRAY_STRIDE_EXT */: return "GL_EDGE_FLAG_ARRAY_STRIDE_EXT (0x808C)";
+case 0x808D /* GL_EDGE_FLAG_ARRAY_COUNT_EXT */: return "GL_EDGE_FLAG_ARRAY_COUNT_EXT (0x808D)";
+//case 0x808E /* GL_VERTEX_ARRAY_POINTER_EXT */: return "GL_VERTEX_ARRAY_POINTER_EXT (0x808E)";
+//case 0x808F /* GL_NORMAL_ARRAY_POINTER_EXT */: return "GL_NORMAL_ARRAY_POINTER_EXT (0x808F)";
+//case 0x8090 /* GL_COLOR_ARRAY_POINTER_EXT */: return "GL_COLOR_ARRAY_POINTER_EXT (0x8090)";
+///case 0x8091 /* GL_INDEX_ARRAY_POINTER_EXT */: return "GL_INDEX_ARRAY_POINTER_EXT (0x8091)";
+///case 0x8092 /* GL_TEXTURE_COORD_ARRAY_POINTER_EXT */: return "GL_TEXTURE_COORD_ARRAY_POINTER_EXT (0x8092)";
+//case 0x8093 /* GL_EDGE_FLAG_ARRAY_POINTER_EXT */: return "GL_EDGE_FLAG_ARRAY_POINTER_EXT (0x8093)";
+
+
+
+/* ------------------------ GL_EXT_vertex_array_bgra ----------------------- */
+
+
+
+
+//case 0x80E1 /* GL_BGRA */: return "GL_BGRA (0x80E1)";
+
+
+
+
+
+/* ----------------------- GL_EXT_vertex_attrib_64bit ---------------------- */
+
+
+
+
+//case 0x8F46 /* GL_DOUBLE_MAT2_EXT */: return "GL_DOUBLE_MAT2_EXT (0x8F46)";
+//case 0x8F47 /* GL_DOUBLE_MAT3_EXT */: return "GL_DOUBLE_MAT3_EXT (0x8F47)";
+//case 0x8F48 /* GL_DOUBLE_MAT4_EXT */: return "GL_DOUBLE_MAT4_EXT (0x8F48)";
+//case 0x8F49 /* GL_DOUBLE_MAT2x3_EXT */: return "GL_DOUBLE_MAT2x3_EXT (0x8F49)";
+//case 0x8F4A /* GL_DOUBLE_MAT2x4_EXT */: return "GL_DOUBLE_MAT2x4_EXT (0x8F4A)";
+//case 0x8F4B /* GL_DOUBLE_MAT3x2_EXT */: return "GL_DOUBLE_MAT3x2_EXT (0x8F4B)";
+//case 0x8F4C /* GL_DOUBLE_MAT3x4_EXT */: return "GL_DOUBLE_MAT3x4_EXT (0x8F4C)";
+//case 0x8F4D /* GL_DOUBLE_MAT4x2_EXT */: return "GL_DOUBLE_MAT4x2_EXT (0x8F4D)";
+//case 0x8F4E /* GL_DOUBLE_MAT4x3_EXT */: return "GL_DOUBLE_MAT4x3_EXT (0x8F4E)";
+//case 0x8FFC /* GL_DOUBLE_VEC2_EXT */: return "GL_DOUBLE_VEC2_EXT (0x8FFC)";
+//case 0x8FFD /* GL_DOUBLE_VEC3_EXT */: return "GL_DOUBLE_VEC3_EXT (0x8FFD)";
+//case 0x8FFE /* GL_DOUBLE_VEC4_EXT */: return "GL_DOUBLE_VEC4_EXT (0x8FFE)";/* -------------------------- GL_EXT_vertex_shader ------------------------- */
+
+
+
+
+case 0x8780 /* GL_VERTEX_SHADER_EXT */: return "GL_VERTEX_SHADER_EXT (0x8780)";
+case 0x8781 /* GL_VERTEX_SHADER_BINDING_EXT */: return "GL_VERTEX_SHADER_BINDING_EXT (0x8781)";
+case 0x8782 /* GL_OP_INDEX_EXT */: return "GL_OP_INDEX_EXT (0x8782)";
+case 0x8783 /* GL_OP_NEGATE_EXT */: return "GL_OP_NEGATE_EXT (0x8783)";
+case 0x8784 /* GL_OP_DOT3_EXT */: return "GL_OP_DOT3_EXT (0x8784)";
+case 0x8785 /* GL_OP_DOT4_EXT */: return "GL_OP_DOT4_EXT (0x8785)";
+case 0x8786 /* GL_OP_MUL_EXT */: return "GL_OP_MUL_EXT (0x8786)";
+case 0x8787 /* GL_OP_ADD_EXT */: return "GL_OP_ADD_EXT (0x8787)";
+case 0x8788 /* GL_OP_MADD_EXT */: return "GL_OP_MADD_EXT (0x8788)";
+case 0x8789 /* GL_OP_FRAC_EXT */: return "GL_OP_FRAC_EXT (0x8789)";
+case 0x878A /* GL_OP_MAX_EXT */: return "GL_OP_MAX_EXT (0x878A)";
+case 0x878B /* GL_OP_MIN_EXT */: return "GL_OP_MIN_EXT (0x878B)";
+case 0x878C /* GL_OP_SET_GE_EXT */: return "GL_OP_SET_GE_EXT (0x878C)";
+case 0x878D /* GL_OP_SET_LT_EXT */: return "GL_OP_SET_LT_EXT (0x878D)";
+case 0x878E /* GL_OP_CLAMP_EXT */: return "GL_OP_CLAMP_EXT (0x878E)";
+case 0x878F /* GL_OP_FLOOR_EXT */: return "GL_OP_FLOOR_EXT (0x878F)";
+case 0x8790 /* GL_OP_ROUND_EXT */: return "GL_OP_ROUND_EXT (0x8790)";
+case 0x8791 /* GL_OP_EXP_BASE_2_EXT */: return "GL_OP_EXP_BASE_2_EXT (0x8791)";
+case 0x8792 /* GL_OP_LOG_BASE_2_EXT */: return "GL_OP_LOG_BASE_2_EXT (0x8792)";
+case 0x8793 /* GL_OP_POWER_EXT */: return "GL_OP_POWER_EXT (0x8793)";
+case 0x8794 /* GL_OP_RECIP_EXT */: return "GL_OP_RECIP_EXT (0x8794)";
+case 0x8795 /* GL_OP_RECIP_SQRT_EXT */: return "GL_OP_RECIP_SQRT_EXT (0x8795)";
+case 0x8796 /* GL_OP_SUB_EXT */: return "GL_OP_SUB_EXT (0x8796)";
+case 0x8797 /* GL_OP_CROSS_PRODUCT_EXT */: return "GL_OP_CROSS_PRODUCT_EXT (0x8797)";
+case 0x8798 /* GL_OP_MULTIPLY_MATRIX_EXT */: return "GL_OP_MULTIPLY_MATRIX_EXT (0x8798)";
+case 0x8799 /* GL_OP_MOV_EXT */: return "GL_OP_MOV_EXT (0x8799)";
+case 0x879A /* GL_OUTPUT_VERTEX_EXT */: return "GL_OUTPUT_VERTEX_EXT (0x879A)";
+case 0x879B /* GL_OUTPUT_COLOR0_EXT */: return "GL_OUTPUT_COLOR0_EXT (0x879B)";
+case 0x879C /* GL_OUTPUT_COLOR1_EXT */: return "GL_OUTPUT_COLOR1_EXT (0x879C)";
+case 0x879D /* GL_OUTPUT_TEXTURE_COORD0_EXT */: return "GL_OUTPUT_TEXTURE_COORD0_EXT (0x879D)";
+case 0x879E /* GL_OUTPUT_TEXTURE_COORD1_EXT */: return "GL_OUTPUT_TEXTURE_COORD1_EXT (0x879E)";
+case 0x879F /* GL_OUTPUT_TEXTURE_COORD2_EXT */: return "GL_OUTPUT_TEXTURE_COORD2_EXT (0x879F)";
+case 0x87A0 /* GL_OUTPUT_TEXTURE_COORD3_EXT */: return "GL_OUTPUT_TEXTURE_COORD3_EXT (0x87A0)";
+case 0x87A1 /* GL_OUTPUT_TEXTURE_COORD4_EXT */: return "GL_OUTPUT_TEXTURE_COORD4_EXT (0x87A1)";
+case 0x87A2 /* GL_OUTPUT_TEXTURE_COORD5_EXT */: return "GL_OUTPUT_TEXTURE_COORD5_EXT (0x87A2)";
+case 0x87A3 /* GL_OUTPUT_TEXTURE_COORD6_EXT */: return "GL_OUTPUT_TEXTURE_COORD6_EXT (0x87A3)";
+case 0x87A4 /* GL_OUTPUT_TEXTURE_COORD7_EXT */: return "GL_OUTPUT_TEXTURE_COORD7_EXT (0x87A4)";
+case 0x87A5 /* GL_OUTPUT_TEXTURE_COORD8_EXT */: return "GL_OUTPUT_TEXTURE_COORD8_EXT (0x87A5)";
+case 0x87A6 /* GL_OUTPUT_TEXTURE_COORD9_EXT */: return "GL_OUTPUT_TEXTURE_COORD9_EXT (0x87A6)";
+case 0x87A7 /* GL_OUTPUT_TEXTURE_COORD10_EXT */: return "GL_OUTPUT_TEXTURE_COORD10_EXT (0x87A7)";
+case 0x87A8 /* GL_OUTPUT_TEXTURE_COORD11_EXT */: return "GL_OUTPUT_TEXTURE_COORD11_EXT (0x87A8)";
+case 0x87A9 /* GL_OUTPUT_TEXTURE_COORD12_EXT */: return "GL_OUTPUT_TEXTURE_COORD12_EXT (0x87A9)";
+case 0x87AA /* GL_OUTPUT_TEXTURE_COORD13_EXT */: return "GL_OUTPUT_TEXTURE_COORD13_EXT (0x87AA)";
+case 0x87AB /* GL_OUTPUT_TEXTURE_COORD14_EXT */: return "GL_OUTPUT_TEXTURE_COORD14_EXT (0x87AB)";
+case 0x87AC /* GL_OUTPUT_TEXTURE_COORD15_EXT */: return "GL_OUTPUT_TEXTURE_COORD15_EXT (0x87AC)";
+case 0x87AD /* GL_OUTPUT_TEXTURE_COORD16_EXT */: return "GL_OUTPUT_TEXTURE_COORD16_EXT (0x87AD)";
+case 0x87AE /* GL_OUTPUT_TEXTURE_COORD17_EXT */: return "GL_OUTPUT_TEXTURE_COORD17_EXT (0x87AE)";
+case 0x87AF /* GL_OUTPUT_TEXTURE_COORD18_EXT */: return "GL_OUTPUT_TEXTURE_COORD18_EXT (0x87AF)";
+case 0x87B0 /* GL_OUTPUT_TEXTURE_COORD19_EXT */: return "GL_OUTPUT_TEXTURE_COORD19_EXT (0x87B0)";
+case 0x87B1 /* GL_OUTPUT_TEXTURE_COORD20_EXT */: return "GL_OUTPUT_TEXTURE_COORD20_EXT (0x87B1)";
+case 0x87B2 /* GL_OUTPUT_TEXTURE_COORD21_EXT */: return "GL_OUTPUT_TEXTURE_COORD21_EXT (0x87B2)";
+case 0x87B3 /* GL_OUTPUT_TEXTURE_COORD22_EXT */: return "GL_OUTPUT_TEXTURE_COORD22_EXT (0x87B3)";
+case 0x87B4 /* GL_OUTPUT_TEXTURE_COORD23_EXT */: return "GL_OUTPUT_TEXTURE_COORD23_EXT (0x87B4)";
+case 0x87B5 /* GL_OUTPUT_TEXTURE_COORD24_EXT */: return "GL_OUTPUT_TEXTURE_COORD24_EXT (0x87B5)";
+case 0x87B6 /* GL_OUTPUT_TEXTURE_COORD25_EXT */: return "GL_OUTPUT_TEXTURE_COORD25_EXT (0x87B6)";
+case 0x87B7 /* GL_OUTPUT_TEXTURE_COORD26_EXT */: return "GL_OUTPUT_TEXTURE_COORD26_EXT (0x87B7)";
+case 0x87B8 /* GL_OUTPUT_TEXTURE_COORD27_EXT */: return "GL_OUTPUT_TEXTURE_COORD27_EXT (0x87B8)";
+case 0x87B9 /* GL_OUTPUT_TEXTURE_COORD28_EXT */: return "GL_OUTPUT_TEXTURE_COORD28_EXT (0x87B9)";
+case 0x87BA /* GL_OUTPUT_TEXTURE_COORD29_EXT */: return "GL_OUTPUT_TEXTURE_COORD29_EXT (0x87BA)";
+case 0x87BB /* GL_OUTPUT_TEXTURE_COORD30_EXT */: return "GL_OUTPUT_TEXTURE_COORD30_EXT (0x87BB)";
+case 0x87BC /* GL_OUTPUT_TEXTURE_COORD31_EXT */: return "GL_OUTPUT_TEXTURE_COORD31_EXT (0x87BC)";
+case 0x87BD /* GL_OUTPUT_FOG_EXT */: return "GL_OUTPUT_FOG_EXT (0x87BD)";
+case 0x87BE /* GL_SCALAR_EXT */: return "GL_SCALAR_EXT (0x87BE)";
+case 0x87BF /* GL_VECTOR_EXT */: return "GL_VECTOR_EXT (0x87BF)";
+case 0x87C0 /* GL_MATRIX_EXT */: return "GL_MATRIX_EXT (0x87C0)";
+case 0x87C1 /* GL_VARIANT_EXT */: return "GL_VARIANT_EXT (0x87C1)";
+case 0x87C2 /* GL_INVARIANT_EXT */: return "GL_INVARIANT_EXT (0x87C2)";
+case 0x87C3 /* GL_LOCAL_CONSTANT_EXT */: return "GL_LOCAL_CONSTANT_EXT (0x87C3)";
+case 0x87C4 /* GL_LOCAL_EXT */: return "GL_LOCAL_EXT (0x87C4)";
+case 0x87C6 /* GL_MAX_VERTEX_SHADER_VARIANTS_EXT */: return "GL_MAX_VERTEX_SHADER_VARIANTS_EXT (0x87C6)";
+case 0x87C7 /* GL_MAX_VERTEX_SHADER_INVARIANTS_EXT */: return "GL_MAX_VERTEX_SHADER_INVARIANTS_EXT (0x87C7)";
+case 0x87C8 /* GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT */: return "GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT (0x87C8)";
+case 0x87C9 /* GL_MAX_VERTEX_SHADER_LOCALS_EXT */: return "GL_MAX_VERTEX_SHADER_LOCALS_EXT (0x87C9)";
+case 0x87CB /* GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT */: return "GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT (0x87CB)";
+case 0x87CC /* GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT */: return "GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT (0x87CC)";
+case 0x87CD /* GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT */: return "GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT (0x87CD)";
+case 0x87CE /* GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT */: return "GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT (0x87CE)";
+case 0x87D0 /* GL_VERTEX_SHADER_VARIANTS_EXT */: return "GL_VERTEX_SHADER_VARIANTS_EXT (0x87D0)";
+case 0x87D1 /* GL_VERTEX_SHADER_INVARIANTS_EXT */: return "GL_VERTEX_SHADER_INVARIANTS_EXT (0x87D1)";
+case 0x87D2 /* GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT */: return "GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT (0x87D2)";
+case 0x87D3 /* GL_VERTEX_SHADER_LOCALS_EXT */: return "GL_VERTEX_SHADER_LOCALS_EXT (0x87D3)";
+case 0x87D4 /* GL_VERTEX_SHADER_OPTIMIZED_EXT */: return "GL_VERTEX_SHADER_OPTIMIZED_EXT (0x87D4)";
+case 0x87D5 /* GL_X_EXT */: return "GL_X_EXT (0x87D5)";
+case 0x87D6 /* GL_Y_EXT */: return "GL_Y_EXT (0x87D6)";
+case 0x87D7 /* GL_Z_EXT */: return "GL_Z_EXT (0x87D7)";
+case 0x87D8 /* GL_W_EXT */: return "GL_W_EXT (0x87D8)";
+case 0x87D9 /* GL_NEGATIVE_X_EXT */: return "GL_NEGATIVE_X_EXT (0x87D9)";
+case 0x87DA /* GL_NEGATIVE_Y_EXT */: return "GL_NEGATIVE_Y_EXT (0x87DA)";
+case 0x87DB /* GL_NEGATIVE_Z_EXT */: return "GL_NEGATIVE_Z_EXT (0x87DB)";
+case 0x87DC /* GL_NEGATIVE_W_EXT */: return "GL_NEGATIVE_W_EXT (0x87DC)";
+case 0x87DD /* GL_ZERO_EXT */: return "GL_ZERO_EXT (0x87DD)";
+case 0x87DE /* GL_ONE_EXT */: return "GL_ONE_EXT (0x87DE)";
+case 0x87DF /* GL_NEGATIVE_ONE_EXT */: return "GL_NEGATIVE_ONE_EXT (0x87DF)";
+case 0x87E0 /* GL_NORMALIZED_RANGE_EXT */: return "GL_NORMALIZED_RANGE_EXT (0x87E0)";
+case 0x87E1 /* GL_FULL_RANGE_EXT */: return "GL_FULL_RANGE_EXT (0x87E1)";
+case 0x87E2 /* GL_CURRENT_VERTEX_EXT */: return "GL_CURRENT_VERTEX_EXT (0x87E2)";
+case 0x87E3 /* GL_MVP_MATRIX_EXT */: return "GL_MVP_MATRIX_EXT (0x87E3)";
+case 0x87E4 /* GL_VARIANT_VALUE_EXT */: return "GL_VARIANT_VALUE_EXT (0x87E4)";
+case 0x87E5 /* GL_VARIANT_DATATYPE_EXT */: return "GL_VARIANT_DATATYPE_EXT (0x87E5)";
+case 0x87E6 /* GL_VARIANT_ARRAY_STRIDE_EXT */: return "GL_VARIANT_ARRAY_STRIDE_EXT (0x87E6)";
+case 0x87E7 /* GL_VARIANT_ARRAY_TYPE_EXT */: return "GL_VARIANT_ARRAY_TYPE_EXT (0x87E7)";
+case 0x87E8 /* GL_VARIANT_ARRAY_EXT */: return "GL_VARIANT_ARRAY_EXT (0x87E8)";
+case 0x87E9 /* GL_VARIANT_ARRAY_POINTER_EXT */: return "GL_VARIANT_ARRAY_POINTER_EXT (0x87E9)";
+case 0x87EA /* GL_INVARIANT_VALUE_EXT */: return "GL_INVARIANT_VALUE_EXT (0x87EA)";
+case 0x87EB /* GL_INVARIANT_DATATYPE_EXT */: return "GL_INVARIANT_DATATYPE_EXT (0x87EB)";
+case 0x87EC /* GL_LOCAL_CONSTANT_VALUE_EXT */: return "GL_LOCAL_CONSTANT_VALUE_EXT (0x87EC)";
+case 0x87ED /* GL_LOCAL_CONSTANT_DATATYPE_EXT */: return "GL_LOCAL_CONSTANT_DATATYPE_EXT (0x87ED)";
+
+/* ------------------------ GL_EXT_vertex_weighting ------------------------ */
+
+
+
+
+//case 0x0BA3 /* GL_MODELVIEW0_STACK_DEPTH_EXT */: return "GL_MODELVIEW0_STACK_DEPTH_EXT (0x0BA3)";
+//case 0x0BA6 /* GL_MODELVIEW0_MATRIX_EXT */: return "GL_MODELVIEW0_MATRIX_EXT (0x0BA6)";
+//case 0x1700 /* GL_MODELVIEW0_EXT */: return "GL_MODELVIEW0_EXT (0x1700)";
+case 0x8502 /* GL_MODELVIEW1_STACK_DEPTH_EXT */: return "GL_MODELVIEW1_STACK_DEPTH_EXT (0x8502)";
+case 0x8506 /* GL_MODELVIEW1_MATRIX_EXT */: return "GL_MODELVIEW1_MATRIX_EXT (0x8506)";
+case 0x8509 /* GL_VERTEX_WEIGHTING_EXT */: return "GL_VERTEX_WEIGHTING_EXT (0x8509)";
+//case 0x850A /* GL_MODELVIEW1_EXT */: return "GL_MODELVIEW1_EXT (0x850A)";
+case 0x850B /* GL_CURRENT_VERTEX_WEIGHT_EXT */: return "GL_CURRENT_VERTEX_WEIGHT_EXT (0x850B)";
+case 0x850C /* GL_VERTEX_WEIGHT_ARRAY_EXT */: return "GL_VERTEX_WEIGHT_ARRAY_EXT (0x850C)";
+case 0x850D /* GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT */: return "GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT (0x850D)";
+case 0x850E /* GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT */: return "GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT (0x850E)";
+case 0x850F /* GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT */: return "GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT (0x850F)";
+case 0x8510 /* GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT */: return "GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT (0x8510)";
+
+
+
+/* ------------------------- GL_EXT_x11_sync_object ------------------------ */
+
+
+
+
+case 0x90E1 /* GL_SYNC_X11_FENCE_EXT */: return "GL_SYNC_X11_FENCE_EXT (0x90E1)";/* ---------------------- GL_GREMEDY_frame_terminator ---------------------- */
+
+
+/* ------------------------ GL_GREMEDY_string_marker ----------------------- */
+
+
+/* --------------------- GL_HP_convolution_border_modes -------------------- */
+
+
+
+
+
+
+
+
+/* ------------------------- GL_HP_image_transform ------------------------- */
+
+
+/* -------------------------- GL_HP_occlusion_test ------------------------- */
+
+
+
+
+case 0x8165 /* GL_OCCLUSION_TEST_HP */: return "GL_OCCLUSION_TEST_HP (0x8165)";
+case 0x8166 /* GL_OCCLUSION_TEST_RESULT_HP */: return "GL_OCCLUSION_TEST_RESULT_HP (0x8166)";
+
+
+
+
+
+/* ------------------------- GL_HP_texture_lighting ------------------------ */
+
+
+
+
+
+
+
+
+/* --------------------------- GL_IBM_cull_vertex -------------------------- */
+/* ---------------------- GL_IBM_multimode_draw_arrays --------------------- */
+
+
+
+
+/* ------------------------- GL_IBM_rasterpos_clip ------------------------- */
+/* --------------------------- GL_IBM_static_data -------------------------- */
+
+/* --------------------- GL_IBM_texture_mirrored_repeat -------------------- */
+
+
+
+
+//case 0x8370 /* GL_MIRRORED_REPEAT_IBM */: return "GL_MIRRORED_REPEAT_IBM (0x8370)";
+
+
+
+
+
+/* ----------------------- GL_IBM_vertex_array_lists ----------------------- */
+
+
+
+/* -------------------------- GL_INGR_color_clamp -------------------------- */
+
+
+
+
+case 0x8560 /* GL_RED_MIN_CLAMP_INGR */: return "GL_RED_MIN_CLAMP_INGR (0x8560)";
+case 0x8561 /* GL_GREEN_MIN_CLAMP_INGR */: return "GL_GREEN_MIN_CLAMP_INGR (0x8561)";
+case 0x8562 /* GL_BLUE_MIN_CLAMP_INGR */: return "GL_BLUE_MIN_CLAMP_INGR (0x8562)";
+case 0x8563 /* GL_ALPHA_MIN_CLAMP_INGR */: return "GL_ALPHA_MIN_CLAMP_INGR (0x8563)";
+case 0x8564 /* GL_RED_MAX_CLAMP_INGR */: return "GL_RED_MAX_CLAMP_INGR (0x8564)";
+case 0x8565 /* GL_GREEN_MAX_CLAMP_INGR */: return "GL_GREEN_MAX_CLAMP_INGR (0x8565)";
+case 0x8566 /* GL_BLUE_MAX_CLAMP_INGR */: return "GL_BLUE_MAX_CLAMP_INGR (0x8566)";
+case 0x8567 /* GL_ALPHA_MAX_CLAMP_INGR */: return "GL_ALPHA_MAX_CLAMP_INGR (0x8567)";
+
+
+
+
+
+/* ------------------------- GL_INGR_interlace_read ------------------------ */
+
+
+
+
+case 0x8568 /* GL_INTERLACE_READ_INGR */: return "GL_INTERLACE_READ_INGR (0x8568)";
+
+
+
+
+
+/* ------------------------ GL_INTEL_parallel_arrays ----------------------- */
+
+
+
+
+case 0x83F4 /* GL_PARALLEL_ARRAYS_INTEL */: return "GL_PARALLEL_ARRAYS_INTEL (0x83F4)";
+case 0x83F5 /* GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL */: return "GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL (0x83F5)";
+case 0x83F6 /* GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL */: return "GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL (0x83F6)";
+case 0x83F7 /* GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL */: return "GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL (0x83F7)";
+case 0x83F8 /* GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL */: return "GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL (0x83F8)";
+
+
+
+
+
+/* ------------------------ GL_INTEL_texture_scissor ----------------------- */
+
+
+
+
+/* ------------------------------ GL_KHR_debug ----------------------------- */
+
+
+
+
+//case 0x00000002 /* GL_CONTEXT_FLAG_DEBUG_BIT */: return "GL_CONTEXT_FLAG_DEBUG_BIT (0x00000002)";
+//case 0x0503 /* GL_STACK_OVERFLOW */: return "GL_STACK_OVERFLOW (0x0503)";
+//case 0x0504 /* GL_STACK_UNDERFLOW */: return "GL_STACK_UNDERFLOW (0x0504)";
+//case 0x8242 /* GL_DEBUG_OUTPUT_SYNCHRONOUS */: return "GL_DEBUG_OUTPUT_SYNCHRONOUS (0x8242)";
+//case 0x8243 /* GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH */: return "GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH (0x8243)";
+//case 0x8244 /* GL_DEBUG_CALLBACK_FUNCTION */: return "GL_DEBUG_CALLBACK_FUNCTION (0x8244)";
+//case 0x8245 /* GL_DEBUG_CALLBACK_USER_PARAM */: return "GL_DEBUG_CALLBACK_USER_PARAM (0x8245)";
+//case 0x8246 /* GL_DEBUG_SOURCE_API */: return "GL_DEBUG_SOURCE_API (0x8246)";
+//case 0x8247 /* GL_DEBUG_SOURCE_WINDOW_SYSTEM */: return "GL_DEBUG_SOURCE_WINDOW_SYSTEM (0x8247)";
+//case 0x8248 /* GL_DEBUG_SOURCE_SHADER_COMPILER */: return "GL_DEBUG_SOURCE_SHADER_COMPILER (0x8248)";
+//case 0x8249 /* GL_DEBUG_SOURCE_THIRD_PARTY */: return "GL_DEBUG_SOURCE_THIRD_PARTY (0x8249)";
+//case 0x824A /* GL_DEBUG_SOURCE_APPLICATION */: return "GL_DEBUG_SOURCE_APPLICATION (0x824A)";
+//case 0x824B /* GL_DEBUG_SOURCE_OTHER */: return "GL_DEBUG_SOURCE_OTHER (0x824B)";
+//case 0x824C /* GL_DEBUG_TYPE_ERROR */: return "GL_DEBUG_TYPE_ERROR (0x824C)";
+//case 0x824D /* GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR */: return "GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR (0x824D)";
+//case 0x824E /* GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR */: return "GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR (0x824E)";
+//case 0x824F /* GL_DEBUG_TYPE_PORTABILITY */: return "GL_DEBUG_TYPE_PORTABILITY (0x824F)";
+//case 0x8250 /* GL_DEBUG_TYPE_PERFORMANCE */: return "GL_DEBUG_TYPE_PERFORMANCE (0x8250)";
+//case 0x8251 /* GL_DEBUG_TYPE_OTHER */: return "GL_DEBUG_TYPE_OTHER (0x8251)";
+case 0x8268 /* GL_DEBUG_TYPE_MARKER */: return "GL_DEBUG_TYPE_MARKER (0x8268)";
+case 0x8269 /* GL_DEBUG_TYPE_PUSH_GROUP */: return "GL_DEBUG_TYPE_PUSH_GROUP (0x8269)";
+case 0x826A /* GL_DEBUG_TYPE_POP_GROUP */: return "GL_DEBUG_TYPE_POP_GROUP (0x826A)";
+case 0x826B /* GL_DEBUG_SEVERITY_NOTIFICATION */: return "GL_DEBUG_SEVERITY_NOTIFICATION (0x826B)";
+case 0x826C /* GL_MAX_DEBUG_GROUP_STACK_DEPTH */: return "GL_MAX_DEBUG_GROUP_STACK_DEPTH (0x826C)";
+case 0x826D /* GL_DEBUG_GROUP_STACK_DEPTH */: return "GL_DEBUG_GROUP_STACK_DEPTH (0x826D)";
+case 0x82E0 /* GL_BUFFER */: return "GL_BUFFER (0x82E0)";
+case 0x82E1 /* GL_SHADER */: return "GL_SHADER (0x82E1)";
+case 0x82E2 /* GL_PROGRAM */: return "GL_PROGRAM (0x82E2)";
+case 0x82E3 /* GL_QUERY */: return "GL_QUERY (0x82E3)";
+case 0x82E4 /* GL_PROGRAM_PIPELINE */: return "GL_PROGRAM_PIPELINE (0x82E4)";
+case 0x82E6 /* GL_SAMPLER */: return "GL_SAMPLER (0x82E6)";
+case 0x82E7 /* GL_DISPLAY_LIST */: return "GL_DISPLAY_LIST (0x82E7)";
+case 0x82E8 /* GL_MAX_LABEL_LENGTH */: return "GL_MAX_LABEL_LENGTH (0x82E8)";
+//case 0x9143 /* GL_MAX_DEBUG_MESSAGE_LENGTH */: return "GL_MAX_DEBUG_MESSAGE_LENGTH (0x9143)";
+//case 0x9144 /* GL_MAX_DEBUG_LOGGED_MESSAGES */: return "GL_MAX_DEBUG_LOGGED_MESSAGES (0x9144)";
+//case 0x9145 /* GL_DEBUG_LOGGED_MESSAGES */: return "GL_DEBUG_LOGGED_MESSAGES (0x9145)";
+//case 0x9146 /* GL_DEBUG_SEVERITY_HIGH */: return "GL_DEBUG_SEVERITY_HIGH (0x9146)";
+//case 0x9147 /* GL_DEBUG_SEVERITY_MEDIUM */: return "GL_DEBUG_SEVERITY_MEDIUM (0x9147)";
+//case 0x9148 /* GL_DEBUG_SEVERITY_LOW */: return "GL_DEBUG_SEVERITY_LOW (0x9148)";
+case 0x92E0 /* GL_DEBUG_OUTPUT */: return "GL_DEBUG_OUTPUT (0x92E0)";/* ------------------ GL_KHR_texture_compression_astc_ldr ------------------ */
+
+
+
+
+case 0x93B0 /* GL_COMPRESSED_RGBA_ASTC_4x4_KHR */: return "GL_COMPRESSED_RGBA_ASTC_4x4_KHR (0x93B0)";
+case 0x93B1 /* GL_COMPRESSED_RGBA_ASTC_5x4_KHR */: return "GL_COMPRESSED_RGBA_ASTC_5x4_KHR (0x93B1)";
+case 0x93B2 /* GL_COMPRESSED_RGBA_ASTC_5x5_KHR */: return "GL_COMPRESSED_RGBA_ASTC_5x5_KHR (0x93B2)";
+case 0x93B3 /* GL_COMPRESSED_RGBA_ASTC_6x5_KHR */: return "GL_COMPRESSED_RGBA_ASTC_6x5_KHR (0x93B3)";
+case 0x93B4 /* GL_COMPRESSED_RGBA_ASTC_6x6_KHR */: return "GL_COMPRESSED_RGBA_ASTC_6x6_KHR (0x93B4)";
+case 0x93B5 /* GL_COMPRESSED_RGBA_ASTC_8x5_KHR */: return "GL_COMPRESSED_RGBA_ASTC_8x5_KHR (0x93B5)";
+case 0x93B6 /* GL_COMPRESSED_RGBA_ASTC_8x6_KHR */: return "GL_COMPRESSED_RGBA_ASTC_8x6_KHR (0x93B6)";
+case 0x93B7 /* GL_COMPRESSED_RGBA_ASTC_8x8_KHR */: return "GL_COMPRESSED_RGBA_ASTC_8x8_KHR (0x93B7)";
+case 0x93B8 /* GL_COMPRESSED_RGBA_ASTC_10x5_KHR */: return "GL_COMPRESSED_RGBA_ASTC_10x5_KHR (0x93B8)";
+case 0x93B9 /* GL_COMPRESSED_RGBA_ASTC_10x6_KHR */: return "GL_COMPRESSED_RGBA_ASTC_10x6_KHR (0x93B9)";
+case 0x93BA /* GL_COMPRESSED_RGBA_ASTC_10x8_KHR */: return "GL_COMPRESSED_RGBA_ASTC_10x8_KHR (0x93BA)";
+case 0x93BB /* GL_COMPRESSED_RGBA_ASTC_10x10_KHR */: return "GL_COMPRESSED_RGBA_ASTC_10x10_KHR (0x93BB)";
+case 0x93BC /* GL_COMPRESSED_RGBA_ASTC_12x10_KHR */: return "GL_COMPRESSED_RGBA_ASTC_12x10_KHR (0x93BC)";
+case 0x93BD /* GL_COMPRESSED_RGBA_ASTC_12x12_KHR */: return "GL_COMPRESSED_RGBA_ASTC_12x12_KHR (0x93BD)";
+case 0x93D0 /* GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR */: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR (0x93D0)";
+case 0x93D1 /* GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR */: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR (0x93D1)";
+case 0x93D2 /* GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR */: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR (0x93D2)";
+case 0x93D3 /* GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR */: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR (0x93D3)";
+case 0x93D4 /* GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR */: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR (0x93D4)";
+case 0x93D5 /* GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR */: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR (0x93D5)";
+case 0x93D6 /* GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR */: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR (0x93D6)";
+case 0x93D7 /* GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR */: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR (0x93D7)";
+case 0x93D8 /* GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR */: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR (0x93D8)";
+case 0x93D9 /* GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR */: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR (0x93D9)";
+case 0x93DA /* GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR */: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR (0x93DA)";
+case 0x93DB /* GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR */: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR (0x93DB)";
+case 0x93DC /* GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR */: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR (0x93DC)";
+case 0x93DD /* GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR */: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR (0x93DD)";
+
+
+
+
+
+/* -------------------------- GL_KTX_buffer_region ------------------------- */
+
+
+
+
+//case 0x0 /* GL_KTX_FRONT_REGION */: return "GL_KTX_FRONT_REGION (0x0)";
+//case 0x1 /* GL_KTX_BACK_REGION */: return "GL_KTX_BACK_REGION (0x1)";
+//case 0x2 /* GL_KTX_Z_REGION */: return "GL_KTX_Z_REGION (0x2)";
+//case 0x3 /* GL_KTX_STENCIL_REGION */: return "GL_KTX_STENCIL_REGION (0x3)";
+
+
+
+
+
+
+
+/* ------------------------- GL_MESAX_texture_stack ------------------------ */
+
+
+
+
+case 0x8759 /* GL_TEXTURE_1D_STACK_MESAX */: return "GL_TEXTURE_1D_STACK_MESAX (0x8759)";
+case 0x875A /* GL_TEXTURE_2D_STACK_MESAX */: return "GL_TEXTURE_2D_STACK_MESAX (0x875A)";
+case 0x875B /* GL_PROXY_TEXTURE_1D_STACK_MESAX */: return "GL_PROXY_TEXTURE_1D_STACK_MESAX (0x875B)";
+case 0x875C /* GL_PROXY_TEXTURE_2D_STACK_MESAX */: return "GL_PROXY_TEXTURE_2D_STACK_MESAX (0x875C)";
+case 0x875D /* GL_TEXTURE_1D_STACK_BINDING_MESAX */: return "GL_TEXTURE_1D_STACK_BINDING_MESAX (0x875D)";
+case 0x875E /* GL_TEXTURE_2D_STACK_BINDING_MESAX */: return "GL_TEXTURE_2D_STACK_BINDING_MESAX (0x875E)";
+
+
+
+
+
+/* -------------------------- GL_MESA_pack_invert -------------------------- */
+
+
+
+
+case 0x8758 /* GL_PACK_INVERT_MESA */: return "GL_PACK_INVERT_MESA (0x8758)";
+
+
+
+
+
+/* ------------------------- GL_MESA_resize_buffers ------------------------ */
+
+
+/* --------------------------- GL_MESA_window_pos -------------------------- */
+
+
+
+
+
+
+
+
+/* ------------------------- GL_MESA_ycbcr_texture ------------------------- */
+
+
+
+
+//case 0x85BA /* GL_UNSIGNED_SHORT_8_8_MESA */: return "GL_UNSIGNED_SHORT_8_8_MESA (0x85BA)";
+//case 0x85BB /* GL_UNSIGNED_SHORT_8_8_REV_MESA */: return "GL_UNSIGNED_SHORT_8_8_REV_MESA (0x85BB)";
+case 0x8757 /* GL_YCBCR_MESA */: return "GL_YCBCR_MESA (0x8757)";
+
+
+
+
+
+/* ------------------------- GL_NVX_gpu_memory_info ------------------------ */
+
+
+
+
+case 0x9047 /* GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX */: return "GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX (0x9047)";
+case 0x9048 /* GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX */: return "GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX (0x9048)";
+case 0x9049 /* GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX */: return "GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX (0x9049)";
+case 0x904A /* GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX */: return "GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX (0x904A)";
+case 0x904B /* GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX */: return "GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX (0x904B)";
+
+
+
+
+
+/* ------------------------- GL_NV_bindless_texture ------------------------ */
+
+
+
+
+
+
+/* --------------------------- GL_NV_blend_square -------------------------- */
+
+
+
+
+
+
+
+
+/* ------------------------ GL_NV_conditional_render ----------------------- */
+
+
+
+
+//case 0x8E13 /* GL_QUERY_WAIT_NV */: return "GL_QUERY_WAIT_NV (0x8E13)";
+//case 0x8E14 /* GL_QUERY_NO_WAIT_NV */: return "GL_QUERY_NO_WAIT_NV (0x8E14)";
+//case 0x8E15 /* GL_QUERY_BY_REGION_WAIT_NV */: return "GL_QUERY_BY_REGION_WAIT_NV (0x8E15)";
+//case 0x8E16 /* GL_QUERY_BY_REGION_NO_WAIT_NV */: return "GL_QUERY_BY_REGION_NO_WAIT_NV (0x8E16)";
+
+/* ----------------------- GL_NV_copy_depth_to_color ----------------------- */
+
+
+
+
+case 0x886E /* GL_DEPTH_STENCIL_TO_RGBA_NV */: return "GL_DEPTH_STENCIL_TO_RGBA_NV (0x886E)";
+case 0x886F /* GL_DEPTH_STENCIL_TO_BGRA_NV */: return "GL_DEPTH_STENCIL_TO_BGRA_NV (0x886F)";
+
+
+
+
+
+/* ---------------------------- GL_NV_copy_image --------------------------- */
+
+
+/* ------------------------ GL_NV_depth_buffer_float ----------------------- */
+
+
+
+
+case 0x8DAB /* GL_DEPTH_COMPONENT32F_NV */: return "GL_DEPTH_COMPONENT32F_NV (0x8DAB)";
+case 0x8DAC /* GL_DEPTH32F_STENCIL8_NV */: return "GL_DEPTH32F_STENCIL8_NV (0x8DAC)";
+//case 0x8DAD /* GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV */: return "GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV (0x8DAD)";
+case 0x8DAF /* GL_DEPTH_BUFFER_FLOAT_MODE_NV */: return "GL_DEPTH_BUFFER_FLOAT_MODE_NV (0x8DAF)";
+
+
+
+/* --------------------------- GL_NV_depth_clamp --------------------------- */
+
+
+
+
+//case 0x864F /* GL_DEPTH_CLAMP_NV */: return "GL_DEPTH_CLAMP_NV (0x864F)";
+
+
+
+
+
+/* ---------------------- GL_NV_depth_range_unclamped ---------------------- */
+
+
+
+
+//case 0x8864 /* GL_SAMPLE_COUNT_BITS_NV */: return "GL_SAMPLE_COUNT_BITS_NV (0x8864)";
+//case 0x8865 /* GL_CURRENT_SAMPLE_COUNT_QUERY_NV */: return "GL_CURRENT_SAMPLE_COUNT_QUERY_NV (0x8865)";
+//case 0x8866 /* GL_QUERY_RESULT_NV */: return "GL_QUERY_RESULT_NV (0x8866)";
+//case 0x8867 /* GL_QUERY_RESULT_AVAILABLE_NV */: return "GL_QUERY_RESULT_AVAILABLE_NV (0x8867)";
+//case 0x8914 /* GL_SAMPLE_COUNT_NV */: return "GL_SAMPLE_COUNT_NV (0x8914)";
+
+
+
+
+
+/* ---------------------------- GL_NV_evaluators --------------------------- */
+
+
+
+
+case 0x86C0 /* GL_EVAL_2D_NV */: return "GL_EVAL_2D_NV (0x86C0)";
+case 0x86C1 /* GL_EVAL_TRIANGULAR_2D_NV */: return "GL_EVAL_TRIANGULAR_2D_NV (0x86C1)";
+case 0x86C2 /* GL_MAP_TESSELLATION_NV */: return "GL_MAP_TESSELLATION_NV (0x86C2)";
+case 0x86C3 /* GL_MAP_ATTRIB_U_ORDER_NV */: return "GL_MAP_ATTRIB_U_ORDER_NV (0x86C3)";
+case 0x86C4 /* GL_MAP_ATTRIB_V_ORDER_NV */: return "GL_MAP_ATTRIB_V_ORDER_NV (0x86C4)";
+case 0x86C5 /* GL_EVAL_FRACTIONAL_TESSELLATION_NV */: return "GL_EVAL_FRACTIONAL_TESSELLATION_NV (0x86C5)";
+case 0x86C6 /* GL_EVAL_VERTEX_ATTRIB0_NV */: return "GL_EVAL_VERTEX_ATTRIB0_NV (0x86C6)";
+case 0x86C7 /* GL_EVAL_VERTEX_ATTRIB1_NV */: return "GL_EVAL_VERTEX_ATTRIB1_NV (0x86C7)";
+case 0x86C8 /* GL_EVAL_VERTEX_ATTRIB2_NV */: return "GL_EVAL_VERTEX_ATTRIB2_NV (0x86C8)";
+case 0x86C9 /* GL_EVAL_VERTEX_ATTRIB3_NV */: return "GL_EVAL_VERTEX_ATTRIB3_NV (0x86C9)";
+case 0x86CA /* GL_EVAL_VERTEX_ATTRIB4_NV */: return "GL_EVAL_VERTEX_ATTRIB4_NV (0x86CA)";
+case 0x86CB /* GL_EVAL_VERTEX_ATTRIB5_NV */: return "GL_EVAL_VERTEX_ATTRIB5_NV (0x86CB)";
+case 0x86CC /* GL_EVAL_VERTEX_ATTRIB6_NV */: return "GL_EVAL_VERTEX_ATTRIB6_NV (0x86CC)";
+case 0x86CD /* GL_EVAL_VERTEX_ATTRIB7_NV */: return "GL_EVAL_VERTEX_ATTRIB7_NV (0x86CD)";
+case 0x86CE /* GL_EVAL_VERTEX_ATTRIB8_NV */: return "GL_EVAL_VERTEX_ATTRIB8_NV (0x86CE)";
+case 0x86CF /* GL_EVAL_VERTEX_ATTRIB9_NV */: return "GL_EVAL_VERTEX_ATTRIB9_NV (0x86CF)";
+case 0x86D0 /* GL_EVAL_VERTEX_ATTRIB10_NV */: return "GL_EVAL_VERTEX_ATTRIB10_NV (0x86D0)";
+case 0x86D1 /* GL_EVAL_VERTEX_ATTRIB11_NV */: return "GL_EVAL_VERTEX_ATTRIB11_NV (0x86D1)";
+case 0x86D2 /* GL_EVAL_VERTEX_ATTRIB12_NV */: return "GL_EVAL_VERTEX_ATTRIB12_NV (0x86D2)";
+case 0x86D3 /* GL_EVAL_VERTEX_ATTRIB13_NV */: return "GL_EVAL_VERTEX_ATTRIB13_NV (0x86D3)";
+case 0x86D4 /* GL_EVAL_VERTEX_ATTRIB14_NV */: return "GL_EVAL_VERTEX_ATTRIB14_NV (0x86D4)";
+case 0x86D5 /* GL_EVAL_VERTEX_ATTRIB15_NV */: return "GL_EVAL_VERTEX_ATTRIB15_NV (0x86D5)";
+case 0x86D6 /* GL_MAX_MAP_TESSELLATION_NV */: return "GL_MAX_MAP_TESSELLATION_NV (0x86D6)";
+case 0x86D7 /* GL_MAX_RATIONAL_EVAL_ORDER_NV */: return "GL_MAX_RATIONAL_EVAL_ORDER_NV (0x86D7)";
+
+
+
+
+
+/* ----------------------- GL_NV_explicit_multisample ---------------------- */
+
+
+
+
+//case 0x8E50 /* GL_SAMPLE_POSITION_NV */: return "GL_SAMPLE_POSITION_NV (0x8E50)";
+//case 0x8E51 /* GL_SAMPLE_MASK_NV */: return "GL_SAMPLE_MASK_NV (0x8E51)";
+//case 0x8E52 /* GL_SAMPLE_MASK_VALUE_NV */: return "GL_SAMPLE_MASK_VALUE_NV (0x8E52)";
+case 0x8E53 /* GL_TEXTURE_BINDING_RENDERBUFFER_NV */: return "GL_TEXTURE_BINDING_RENDERBUFFER_NV (0x8E53)";
+case 0x8E54 /* GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV */: return "GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV (0x8E54)";
+case 0x8E55 /* GL_TEXTURE_RENDERBUFFER_NV */: return "GL_TEXTURE_RENDERBUFFER_NV (0x8E55)";
+case 0x8E56 /* GL_SAMPLER_RENDERBUFFER_NV */: return "GL_SAMPLER_RENDERBUFFER_NV (0x8E56)";
+case 0x8E57 /* GL_INT_SAMPLER_RENDERBUFFER_NV */: return "GL_INT_SAMPLER_RENDERBUFFER_NV (0x8E57)";
+case 0x8E58 /* GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV */: return "GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV (0x8E58)";
+//case 0x8E59 /* GL_MAX_SAMPLE_MASK_WORDS_NV */: return "GL_MAX_SAMPLE_MASK_WORDS_NV (0x8E59)";
+
+
+
+/* ------------------------------ GL_NV_fence ------------------------------ */
+
+
+
+
+case 0x84F2 /* GL_ALL_COMPLETED_NV */: return "GL_ALL_COMPLETED_NV (0x84F2)";
+case 0x84F3 /* GL_FENCE_STATUS_NV */: return "GL_FENCE_STATUS_NV (0x84F3)";
+case 0x84F4 /* GL_FENCE_CONDITION_NV */: return "GL_FENCE_CONDITION_NV (0x84F4)";
+
+/* --------------------------- GL_NV_float_buffer -------------------------- */
+
+
+
+
+case 0x8880 /* GL_FLOAT_R_NV */: return "GL_FLOAT_R_NV (0x8880)";
+case 0x8881 /* GL_FLOAT_RG_NV */: return "GL_FLOAT_RG_NV (0x8881)";
+case 0x8882 /* GL_FLOAT_RGB_NV */: return "GL_FLOAT_RGB_NV (0x8882)";
+case 0x8883 /* GL_FLOAT_RGBA_NV */: return "GL_FLOAT_RGBA_NV (0x8883)";
+case 0x8884 /* GL_FLOAT_R16_NV */: return "GL_FLOAT_R16_NV (0x8884)";
+case 0x8885 /* GL_FLOAT_R32_NV */: return "GL_FLOAT_R32_NV (0x8885)";
+case 0x8886 /* GL_FLOAT_RG16_NV */: return "GL_FLOAT_RG16_NV (0x8886)";
+case 0x8887 /* GL_FLOAT_RG32_NV */: return "GL_FLOAT_RG32_NV (0x8887)";
+case 0x8888 /* GL_FLOAT_RGB16_NV */: return "GL_FLOAT_RGB16_NV (0x8888)";
+case 0x8889 /* GL_FLOAT_RGB32_NV */: return "GL_FLOAT_RGB32_NV (0x8889)";
+case 0x888A /* GL_FLOAT_RGBA16_NV */: return "GL_FLOAT_RGBA16_NV (0x888A)";
+case 0x888B /* GL_FLOAT_RGBA32_NV */: return "GL_FLOAT_RGBA32_NV (0x888B)";
+case 0x888C /* GL_TEXTURE_FLOAT_COMPONENTS_NV */: return "GL_TEXTURE_FLOAT_COMPONENTS_NV (0x888C)";
+case 0x888D /* GL_FLOAT_CLEAR_COLOR_VALUE_NV */: return "GL_FLOAT_CLEAR_COLOR_VALUE_NV (0x888D)";
+case 0x888E /* GL_FLOAT_RGBA_MODE_NV */: return "GL_FLOAT_RGBA_MODE_NV (0x888E)";
+
+
+
+
+
+/* --------------------------- GL_NV_fog_distance -------------------------- */
+
+
+
+
+case 0x855A /* GL_FOG_DISTANCE_MODE_NV */: return "GL_FOG_DISTANCE_MODE_NV (0x855A)";
+case 0x855B /* GL_EYE_RADIAL_NV */: return "GL_EYE_RADIAL_NV (0x855B)";
+case 0x855C /* GL_EYE_PLANE_ABSOLUTE_NV */: return "GL_EYE_PLANE_ABSOLUTE_NV (0x855C)";
+
+
+
+
+
+/* ------------------------- GL_NV_fragment_program ------------------------ */
+
+
+
+
+case 0x8868 /* GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV */: return "GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV (0x8868)";
+case 0x8870 /* GL_FRAGMENT_PROGRAM_NV */: return "GL_FRAGMENT_PROGRAM_NV (0x8870)";
+//case 0x8871 /* GL_MAX_TEXTURE_COORDS_NV */: return "GL_MAX_TEXTURE_COORDS_NV (0x8871)";
+//case 0x8872 /* GL_MAX_TEXTURE_IMAGE_UNITS_NV */: return "GL_MAX_TEXTURE_IMAGE_UNITS_NV (0x8872)";
+case 0x8873 /* GL_FRAGMENT_PROGRAM_BINDING_NV */: return "GL_FRAGMENT_PROGRAM_BINDING_NV (0x8873)";
+//case 0x8874 /* GL_PROGRAM_ERROR_STRING_NV */: return "GL_PROGRAM_ERROR_STRING_NV (0x8874)";/* ------------------------ GL_NV_fragment_program2 ------------------------ */
+
+
+
+
+case 0x88F5 /* GL_MAX_PROGRAM_CALL_DEPTH_NV */: return "GL_MAX_PROGRAM_CALL_DEPTH_NV (0x88F5)";
+case 0x88F6 /* GL_MAX_PROGRAM_IF_DEPTH_NV */: return "GL_MAX_PROGRAM_IF_DEPTH_NV (0x88F6)";
+case 0x88F7 /* GL_MAX_PROGRAM_LOOP_DEPTH_NV */: return "GL_MAX_PROGRAM_LOOP_DEPTH_NV (0x88F7)";
+case 0x88F8 /* GL_MAX_PROGRAM_LOOP_COUNT_NV */: return "GL_MAX_PROGRAM_LOOP_COUNT_NV (0x88F8)";
+
+
+
+
+
+/* ------------------------ GL_NV_fragment_program4 ------------------------ */
+
+
+
+
+
+
+
+
+/* --------------------- GL_NV_fragment_program_option --------------------- */
+
+
+
+
+
+
+
+
+/* ----------------- GL_NV_framebuffer_multisample_coverage ---------------- */
+
+
+
+
+//case 0x8CAB /* GL_RENDERBUFFER_COVERAGE_SAMPLES_NV */: return "GL_RENDERBUFFER_COVERAGE_SAMPLES_NV (0x8CAB)";
+case 0x8E10 /* GL_RENDERBUFFER_COLOR_SAMPLES_NV */: return "GL_RENDERBUFFER_COLOR_SAMPLES_NV (0x8E10)";
+case 0x8E11 /* GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV */: return "GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV (0x8E11)";
+case 0x8E12 /* GL_MULTISAMPLE_COVERAGE_MODES_NV */: return "GL_MULTISAMPLE_COVERAGE_MODES_NV (0x8E12)";/* ------------------------ GL_NV_geometry_program4 ------------------------ */
+
+
+
+
+case 0x8C26 /* GL_GEOMETRY_PROGRAM_NV */: return "GL_GEOMETRY_PROGRAM_NV (0x8C26)";
+case 0x8C27 /* GL_MAX_PROGRAM_OUTPUT_VERTICES_NV */: return "GL_MAX_PROGRAM_OUTPUT_VERTICES_NV (0x8C27)";
+case 0x8C28 /* GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV */: return "GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV (0x8C28)";/* ------------------------- GL_NV_geometry_shader4 ------------------------ */
+
+
+
+
+
+
+
+
+/* --------------------------- GL_NV_gpu_program4 -------------------------- */
+
+
+
+
+//case 0x8904 /* GL_MIN_PROGRAM_TEXEL_OFFSET_NV */: return "GL_MIN_PROGRAM_TEXEL_OFFSET_NV (0x8904)";
+//case 0x8905 /* GL_MAX_PROGRAM_TEXEL_OFFSET_NV */: return "GL_MAX_PROGRAM_TEXEL_OFFSET_NV (0x8905)";
+case 0x8906 /* GL_PROGRAM_ATTRIB_COMPONENTS_NV */: return "GL_PROGRAM_ATTRIB_COMPONENTS_NV (0x8906)";
+case 0x8907 /* GL_PROGRAM_RESULT_COMPONENTS_NV */: return "GL_PROGRAM_RESULT_COMPONENTS_NV (0x8907)";
+case 0x8908 /* GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV */: return "GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV (0x8908)";
+case 0x8909 /* GL_MAX_PROGRAM_RESULT_COMPONENTS_NV */: return "GL_MAX_PROGRAM_RESULT_COMPONENTS_NV (0x8909)";
+case 0x8DA5 /* GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV */: return "GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV (0x8DA5)";
+case 0x8DA6 /* GL_MAX_PROGRAM_GENERIC_RESULTS_NV */: return "GL_MAX_PROGRAM_GENERIC_RESULTS_NV (0x8DA6)";
+
+/* --------------------------- GL_NV_gpu_program5 -------------------------- */
+
+
+
+
+//case 0x8E5A /* GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV */: return "GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV (0x8E5A)";
+//case 0x8E5B /* GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV */: return "GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV (0x8E5B)";
+//case 0x8E5C /* GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV */: return "GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV (0x8E5C)";
+//case 0x8E5D /* GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV */: return "GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV (0x8E5D)";
+//case 0x8E5E /* GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV */: return "GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV (0x8E5E)";
+//case 0x8E5F /* GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV */: return "GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV (0x8E5F)";
+
+
+
+
+
+/* ------------------------- GL_NV_gpu_program_fp64 ------------------------ */
+
+
+
+
+
+
+
+
+/* --------------------------- GL_NV_gpu_shader5 --------------------------- */
+
+
+
+
+case 0x140E /* GL_INT64_NV */: return "GL_INT64_NV (0x140E)";
+case 0x140F /* GL_UNSIGNED_INT64_NV */: return "GL_UNSIGNED_INT64_NV (0x140F)";
+case 0x8FE0 /* GL_INT8_NV */: return "GL_INT8_NV (0x8FE0)";
+case 0x8FE1 /* GL_INT8_VEC2_NV */: return "GL_INT8_VEC2_NV (0x8FE1)";
+case 0x8FE2 /* GL_INT8_VEC3_NV */: return "GL_INT8_VEC3_NV (0x8FE2)";
+case 0x8FE3 /* GL_INT8_VEC4_NV */: return "GL_INT8_VEC4_NV (0x8FE3)";
+case 0x8FE4 /* GL_INT16_NV */: return "GL_INT16_NV (0x8FE4)";
+case 0x8FE5 /* GL_INT16_VEC2_NV */: return "GL_INT16_VEC2_NV (0x8FE5)";
+case 0x8FE6 /* GL_INT16_VEC3_NV */: return "GL_INT16_VEC3_NV (0x8FE6)";
+case 0x8FE7 /* GL_INT16_VEC4_NV */: return "GL_INT16_VEC4_NV (0x8FE7)";
+case 0x8FE9 /* GL_INT64_VEC2_NV */: return "GL_INT64_VEC2_NV (0x8FE9)";
+case 0x8FEA /* GL_INT64_VEC3_NV */: return "GL_INT64_VEC3_NV (0x8FEA)";
+case 0x8FEB /* GL_INT64_VEC4_NV */: return "GL_INT64_VEC4_NV (0x8FEB)";
+case 0x8FEC /* GL_UNSIGNED_INT8_NV */: return "GL_UNSIGNED_INT8_NV (0x8FEC)";
+case 0x8FED /* GL_UNSIGNED_INT8_VEC2_NV */: return "GL_UNSIGNED_INT8_VEC2_NV (0x8FED)";
+case 0x8FEE /* GL_UNSIGNED_INT8_VEC3_NV */: return "GL_UNSIGNED_INT8_VEC3_NV (0x8FEE)";
+case 0x8FEF /* GL_UNSIGNED_INT8_VEC4_NV */: return "GL_UNSIGNED_INT8_VEC4_NV (0x8FEF)";
+case 0x8FF0 /* GL_UNSIGNED_INT16_NV */: return "GL_UNSIGNED_INT16_NV (0x8FF0)";
+case 0x8FF1 /* GL_UNSIGNED_INT16_VEC2_NV */: return "GL_UNSIGNED_INT16_VEC2_NV (0x8FF1)";
+case 0x8FF2 /* GL_UNSIGNED_INT16_VEC3_NV */: return "GL_UNSIGNED_INT16_VEC3_NV (0x8FF2)";
+case 0x8FF3 /* GL_UNSIGNED_INT16_VEC4_NV */: return "GL_UNSIGNED_INT16_VEC4_NV (0x8FF3)";
+case 0x8FF5 /* GL_UNSIGNED_INT64_VEC2_NV */: return "GL_UNSIGNED_INT64_VEC2_NV (0x8FF5)";
+case 0x8FF6 /* GL_UNSIGNED_INT64_VEC3_NV */: return "GL_UNSIGNED_INT64_VEC3_NV (0x8FF6)";
+case 0x8FF7 /* GL_UNSIGNED_INT64_VEC4_NV */: return "GL_UNSIGNED_INT64_VEC4_NV (0x8FF7)";
+case 0x8FF8 /* GL_FLOAT16_NV */: return "GL_FLOAT16_NV (0x8FF8)";
+case 0x8FF9 /* GL_FLOAT16_VEC2_NV */: return "GL_FLOAT16_VEC2_NV (0x8FF9)";
+case 0x8FFA /* GL_FLOAT16_VEC3_NV */: return "GL_FLOAT16_VEC3_NV (0x8FFA)";
+case 0x8FFB /* GL_FLOAT16_VEC4_NV */: return "GL_FLOAT16_VEC4_NV (0x8FFB)";
+
+
+
+
+
+/* ---------------------------- GL_NV_half_float --------------------------- */
+
+
+
+
+//case 0x140B /* GL_HALF_FLOAT_NV */: return "GL_HALF_FLOAT_NV (0x140B)";
+
+/* ------------------------ GL_NV_light_max_exponent ----------------------- */
+
+
+
+
+case 0x8504 /* GL_MAX_SHININESS_NV */: return "GL_MAX_SHININESS_NV (0x8504)";
+case 0x8505 /* GL_MAX_SPOT_EXPONENT_NV */: return "GL_MAX_SPOT_EXPONENT_NV (0x8505)";
+
+
+
+
+
+/* ----------------------- GL_NV_multisample_coverage ---------------------- */
+
+
+
+
+//case 0x80A9 /* GL_COVERAGE_SAMPLES_NV */: return "GL_COVERAGE_SAMPLES_NV (0x80A9)";
+case 0x8E20 /* GL_COLOR_SAMPLES_NV */: return "GL_COLOR_SAMPLES_NV (0x8E20)";
+
+
+
+
+
+/* --------------------- GL_NV_multisample_filter_hint --------------------- */
+
+
+
+
+case 0x8534 /* GL_MULTISAMPLE_FILTER_HINT_NV */: return "GL_MULTISAMPLE_FILTER_HINT_NV (0x8534)";
+
+
+
+
+
+/* ------------------------- GL_NV_occlusion_query ------------------------- */
+
+
+
+
+//case 0x8864 /* GL_PIXEL_COUNTER_BITS_NV */: return "GL_PIXEL_COUNTER_BITS_NV (0x8864)";
+//case 0x8865 /* GL_CURRENT_OCCLUSION_QUERY_ID_NV */: return "GL_CURRENT_OCCLUSION_QUERY_ID_NV (0x8865)";
+//case 0x8866 /* GL_PIXEL_COUNT_NV */: return "GL_PIXEL_COUNT_NV (0x8866)";
+//case 0x8867 /* GL_PIXEL_COUNT_AVAILABLE_NV */: return "GL_PIXEL_COUNT_AVAILABLE_NV (0x8867)";
+
+/* ----------------------- GL_NV_packed_depth_stencil ---------------------- */
+
+
+
+
+//case 0x84F9 /* GL_DEPTH_STENCIL_NV */: return "GL_DEPTH_STENCIL_NV (0x84F9)";
+//case 0x84FA /* GL_UNSIGNED_INT_24_8_NV */: return "GL_UNSIGNED_INT_24_8_NV (0x84FA)";
+
+
+
+
+
+/* --------------------- GL_NV_parameter_buffer_object --------------------- */
+
+
+
+
+case 0x8DA0 /* GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV */: return "GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV (0x8DA0)";
+case 0x8DA1 /* GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV */: return "GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV (0x8DA1)";
+case 0x8DA2 /* GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV */: return "GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV (0x8DA2)";
+case 0x8DA3 /* GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV */: return "GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV (0x8DA3)";
+case 0x8DA4 /* GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV */: return "GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV (0x8DA4)";
+
+
+
+/* --------------------- GL_NV_parameter_buffer_object2 -------------------- */
+
+
+
+
+
+
+
+
+/* -------------------------- GL_NV_path_rendering ------------------------- */
+
+
+
+
+//case 0x00 /* GL_CLOSE_PATH_NV */: return "GL_CLOSE_PATH_NV (0x00)";
+//case 0x01 /* GL_BOLD_BIT_NV */: return "GL_BOLD_BIT_NV (0x01)";
+//case 0x01 /* GL_GLYPH_WIDTH_BIT_NV */: return "GL_GLYPH_WIDTH_BIT_NV (0x01)";
+//case 0x02 /* GL_GLYPH_HEIGHT_BIT_NV */: return "GL_GLYPH_HEIGHT_BIT_NV (0x02)";
+//case 0x02 /* GL_ITALIC_BIT_NV */: return "GL_ITALIC_BIT_NV (0x02)";
+//case 0x02 /* GL_MOVE_TO_NV */: return "GL_MOVE_TO_NV (0x02)";
+//case 0x03 /* GL_RELATIVE_MOVE_TO_NV */: return "GL_RELATIVE_MOVE_TO_NV (0x03)";
+//case 0x04 /* GL_LINE_TO_NV */: return "GL_LINE_TO_NV (0x04)";
+//case 0x04 /* GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV */: return "GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV (0x04)";
+//case 0x05 /* GL_RELATIVE_LINE_TO_NV */: return "GL_RELATIVE_LINE_TO_NV (0x05)";
+//case 0x06 /* GL_HORIZONTAL_LINE_TO_NV */: return "GL_HORIZONTAL_LINE_TO_NV (0x06)";
+//case 0x07 /* GL_RELATIVE_HORIZONTAL_LINE_TO_NV */: return "GL_RELATIVE_HORIZONTAL_LINE_TO_NV (0x07)";
+//case 0x08 /* GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV */: return "GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV (0x08)";
+//case 0x08 /* GL_VERTICAL_LINE_TO_NV */: return "GL_VERTICAL_LINE_TO_NV (0x08)";
+//case 0x09 /* GL_RELATIVE_VERTICAL_LINE_TO_NV */: return "GL_RELATIVE_VERTICAL_LINE_TO_NV (0x09)";
+//case 0x0A /* GL_QUADRATIC_CURVE_TO_NV */: return "GL_QUADRATIC_CURVE_TO_NV (0x0A)";
+//case 0x0B /* GL_RELATIVE_QUADRATIC_CURVE_TO_NV */: return "GL_RELATIVE_QUADRATIC_CURVE_TO_NV (0x0B)";
+//case 0x0C /* GL_CUBIC_CURVE_TO_NV */: return "GL_CUBIC_CURVE_TO_NV (0x0C)";
+//case 0x0D /* GL_RELATIVE_CUBIC_CURVE_TO_NV */: return "GL_RELATIVE_CUBIC_CURVE_TO_NV (0x0D)";
+//case 0x0E /* GL_SMOOTH_QUADRATIC_CURVE_TO_NV */: return "GL_SMOOTH_QUADRATIC_CURVE_TO_NV (0x0E)";
+case 0x0F /* GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV */: return "GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV (0x0F)";
+//case 0x10 /* GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV */: return "GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV (0x10)";
+//case 0x10 /* GL_SMOOTH_CUBIC_CURVE_TO_NV */: return "GL_SMOOTH_CUBIC_CURVE_TO_NV (0x10)";
+case 0x11 /* GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV */: return "GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV (0x11)";
+case 0x12 /* GL_SMALL_CCW_ARC_TO_NV */: return "GL_SMALL_CCW_ARC_TO_NV (0x12)";
+case 0x13 /* GL_RELATIVE_SMALL_CCW_ARC_TO_NV */: return "GL_RELATIVE_SMALL_CCW_ARC_TO_NV (0x13)";
+case 0x14 /* GL_SMALL_CW_ARC_TO_NV */: return "GL_SMALL_CW_ARC_TO_NV (0x14)";
+case 0x15 /* GL_RELATIVE_SMALL_CW_ARC_TO_NV */: return "GL_RELATIVE_SMALL_CW_ARC_TO_NV (0x15)";
+case 0x16 /* GL_LARGE_CCW_ARC_TO_NV */: return "GL_LARGE_CCW_ARC_TO_NV (0x16)";
+case 0x17 /* GL_RELATIVE_LARGE_CCW_ARC_TO_NV */: return "GL_RELATIVE_LARGE_CCW_ARC_TO_NV (0x17)";
+case 0x18 /* GL_LARGE_CW_ARC_TO_NV */: return "GL_LARGE_CW_ARC_TO_NV (0x18)";
+case 0x19 /* GL_RELATIVE_LARGE_CW_ARC_TO_NV */: return "GL_RELATIVE_LARGE_CW_ARC_TO_NV (0x19)";
+//case 0x20 /* GL_GLYPH_VERTICAL_BEARING_X_BIT_NV */: return "GL_GLYPH_VERTICAL_BEARING_X_BIT_NV (0x20)";
+//case 0x40 /* GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV */: return "GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV (0x40)";
+//case 0x80 /* GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV */: return "GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV (0x80)";
+case 0xF0 /* GL_RESTART_PATH_NV */: return "GL_RESTART_PATH_NV (0xF0)";
+case 0xF2 /* GL_DUP_FIRST_CUBIC_CURVE_TO_NV */: return "GL_DUP_FIRST_CUBIC_CURVE_TO_NV (0xF2)";
+case 0xF4 /* GL_DUP_LAST_CUBIC_CURVE_TO_NV */: return "GL_DUP_LAST_CUBIC_CURVE_TO_NV (0xF4)";
+case 0xF6 /* GL_RECT_NV */: return "GL_RECT_NV (0xF6)";
+case 0xF8 /* GL_CIRCULAR_CCW_ARC_TO_NV */: return "GL_CIRCULAR_CCW_ARC_TO_NV (0xF8)";
+case 0xFA /* GL_CIRCULAR_CW_ARC_TO_NV */: return "GL_CIRCULAR_CW_ARC_TO_NV (0xFA)";
+case 0xFC /* GL_CIRCULAR_TANGENT_ARC_TO_NV */: return "GL_CIRCULAR_TANGENT_ARC_TO_NV (0xFC)";
+case 0xFE /* GL_ARC_TO_NV */: return "GL_ARC_TO_NV (0xFE)";
+case 0xFF /* GL_RELATIVE_ARC_TO_NV */: return "GL_RELATIVE_ARC_TO_NV (0xFF)";
+//case 0x100 /* GL_GLYPH_HAS_KERNING_BIT_NV */: return "GL_GLYPH_HAS_KERNING_BIT_NV (0x100)";
+case 0x852C /* GL_PRIMARY_COLOR_NV */: return "GL_PRIMARY_COLOR_NV (0x852C)";
+case 0x852D /* GL_SECONDARY_COLOR_NV */: return "GL_SECONDARY_COLOR_NV (0x852D)";
+//case 0x8577 /* GL_PRIMARY_COLOR */: return "GL_PRIMARY_COLOR (0x8577)";
+case 0x9070 /* GL_PATH_FORMAT_SVG_NV */: return "GL_PATH_FORMAT_SVG_NV (0x9070)";
+case 0x9071 /* GL_PATH_FORMAT_PS_NV */: return "GL_PATH_FORMAT_PS_NV (0x9071)";
+case 0x9072 /* GL_STANDARD_FONT_NAME_NV */: return "GL_STANDARD_FONT_NAME_NV (0x9072)";
+case 0x9073 /* GL_SYSTEM_FONT_NAME_NV */: return "GL_SYSTEM_FONT_NAME_NV (0x9073)";
+case 0x9074 /* GL_FILE_NAME_NV */: return "GL_FILE_NAME_NV (0x9074)";
+case 0x9075 /* GL_PATH_STROKE_WIDTH_NV */: return "GL_PATH_STROKE_WIDTH_NV (0x9075)";
+case 0x9076 /* GL_PATH_END_CAPS_NV */: return "GL_PATH_END_CAPS_NV (0x9076)";
+case 0x9077 /* GL_PATH_INITIAL_END_CAP_NV */: return "GL_PATH_INITIAL_END_CAP_NV (0x9077)";
+case 0x9078 /* GL_PATH_TERMINAL_END_CAP_NV */: return "GL_PATH_TERMINAL_END_CAP_NV (0x9078)";
+case 0x9079 /* GL_PATH_JOIN_STYLE_NV */: return "GL_PATH_JOIN_STYLE_NV (0x9079)";
+case 0x907A /* GL_PATH_MITER_LIMIT_NV */: return "GL_PATH_MITER_LIMIT_NV (0x907A)";
+case 0x907B /* GL_PATH_DASH_CAPS_NV */: return "GL_PATH_DASH_CAPS_NV (0x907B)";
+case 0x907C /* GL_PATH_INITIAL_DASH_CAP_NV */: return "GL_PATH_INITIAL_DASH_CAP_NV (0x907C)";
+case 0x907D /* GL_PATH_TERMINAL_DASH_CAP_NV */: return "GL_PATH_TERMINAL_DASH_CAP_NV (0x907D)";
+case 0x907E /* GL_PATH_DASH_OFFSET_NV */: return "GL_PATH_DASH_OFFSET_NV (0x907E)";
+case 0x907F /* GL_PATH_CLIENT_LENGTH_NV */: return "GL_PATH_CLIENT_LENGTH_NV (0x907F)";
+case 0x9080 /* GL_PATH_FILL_MODE_NV */: return "GL_PATH_FILL_MODE_NV (0x9080)";
+case 0x9081 /* GL_PATH_FILL_MASK_NV */: return "GL_PATH_FILL_MASK_NV (0x9081)";
+case 0x9082 /* GL_PATH_FILL_COVER_MODE_NV */: return "GL_PATH_FILL_COVER_MODE_NV (0x9082)";
+case 0x9083 /* GL_PATH_STROKE_COVER_MODE_NV */: return "GL_PATH_STROKE_COVER_MODE_NV (0x9083)";
+case 0x9084 /* GL_PATH_STROKE_MASK_NV */: return "GL_PATH_STROKE_MASK_NV (0x9084)";
+case 0x9088 /* GL_COUNT_UP_NV */: return "GL_COUNT_UP_NV (0x9088)";
+case 0x9089 /* GL_COUNT_DOWN_NV */: return "GL_COUNT_DOWN_NV (0x9089)";
+case 0x908A /* GL_PATH_OBJECT_BOUNDING_BOX_NV */: return "GL_PATH_OBJECT_BOUNDING_BOX_NV (0x908A)";
+case 0x908B /* GL_CONVEX_HULL_NV */: return "GL_CONVEX_HULL_NV (0x908B)";
+case 0x908D /* GL_BOUNDING_BOX_NV */: return "GL_BOUNDING_BOX_NV (0x908D)";
+case 0x908E /* GL_TRANSLATE_X_NV */: return "GL_TRANSLATE_X_NV (0x908E)";
+case 0x908F /* GL_TRANSLATE_Y_NV */: return "GL_TRANSLATE_Y_NV (0x908F)";
+case 0x9090 /* GL_TRANSLATE_2D_NV */: return "GL_TRANSLATE_2D_NV (0x9090)";
+case 0x9091 /* GL_TRANSLATE_3D_NV */: return "GL_TRANSLATE_3D_NV (0x9091)";
+case 0x9092 /* GL_AFFINE_2D_NV */: return "GL_AFFINE_2D_NV (0x9092)";
+case 0x9094 /* GL_AFFINE_3D_NV */: return "GL_AFFINE_3D_NV (0x9094)";
+case 0x9096 /* GL_TRANSPOSE_AFFINE_2D_NV */: return "GL_TRANSPOSE_AFFINE_2D_NV (0x9096)";
+case 0x9098 /* GL_TRANSPOSE_AFFINE_3D_NV */: return "GL_TRANSPOSE_AFFINE_3D_NV (0x9098)";
+case 0x909A /* GL_UTF8_NV */: return "GL_UTF8_NV (0x909A)";
+case 0x909B /* GL_UTF16_NV */: return "GL_UTF16_NV (0x909B)";
+case 0x909C /* GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV */: return "GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV (0x909C)";
+case 0x909D /* GL_PATH_COMMAND_COUNT_NV */: return "GL_PATH_COMMAND_COUNT_NV (0x909D)";
+case 0x909E /* GL_PATH_COORD_COUNT_NV */: return "GL_PATH_COORD_COUNT_NV (0x909E)";
+case 0x909F /* GL_PATH_DASH_ARRAY_COUNT_NV */: return "GL_PATH_DASH_ARRAY_COUNT_NV (0x909F)";
+case 0x90A0 /* GL_PATH_COMPUTED_LENGTH_NV */: return "GL_PATH_COMPUTED_LENGTH_NV (0x90A0)";
+case 0x90A1 /* GL_PATH_FILL_BOUNDING_BOX_NV */: return "GL_PATH_FILL_BOUNDING_BOX_NV (0x90A1)";
+case 0x90A2 /* GL_PATH_STROKE_BOUNDING_BOX_NV */: return "GL_PATH_STROKE_BOUNDING_BOX_NV (0x90A2)";
+case 0x90A3 /* GL_SQUARE_NV */: return "GL_SQUARE_NV (0x90A3)";
+case 0x90A4 /* GL_ROUND_NV */: return "GL_ROUND_NV (0x90A4)";
+case 0x90A5 /* GL_TRIANGULAR_NV */: return "GL_TRIANGULAR_NV (0x90A5)";
+case 0x90A6 /* GL_BEVEL_NV */: return "GL_BEVEL_NV (0x90A6)";
+case 0x90A7 /* GL_MITER_REVERT_NV */: return "GL_MITER_REVERT_NV (0x90A7)";
+case 0x90A8 /* GL_MITER_TRUNCATE_NV */: return "GL_MITER_TRUNCATE_NV (0x90A8)";
+case 0x90A9 /* GL_SKIP_MISSING_GLYPH_NV */: return "GL_SKIP_MISSING_GLYPH_NV (0x90A9)";
+case 0x90AA /* GL_USE_MISSING_GLYPH_NV */: return "GL_USE_MISSING_GLYPH_NV (0x90AA)";
+case 0x90AB /* GL_PATH_ERROR_POSITION_NV */: return "GL_PATH_ERROR_POSITION_NV (0x90AB)";
+case 0x90AC /* GL_PATH_FOG_GEN_MODE_NV */: return "GL_PATH_FOG_GEN_MODE_NV (0x90AC)";
+case 0x90AD /* GL_ACCUM_ADJACENT_PAIRS_NV */: return "GL_ACCUM_ADJACENT_PAIRS_NV (0x90AD)";
+case 0x90AE /* GL_ADJACENT_PAIRS_NV */: return "GL_ADJACENT_PAIRS_NV (0x90AE)";
+case 0x90AF /* GL_FIRST_TO_REST_NV */: return "GL_FIRST_TO_REST_NV (0x90AF)";
+case 0x90B0 /* GL_PATH_GEN_MODE_NV */: return "GL_PATH_GEN_MODE_NV (0x90B0)";
+case 0x90B1 /* GL_PATH_GEN_COEFF_NV */: return "GL_PATH_GEN_COEFF_NV (0x90B1)";
+case 0x90B2 /* GL_PATH_GEN_COLOR_FORMAT_NV */: return "GL_PATH_GEN_COLOR_FORMAT_NV (0x90B2)";
+case 0x90B3 /* GL_PATH_GEN_COMPONENTS_NV */: return "GL_PATH_GEN_COMPONENTS_NV (0x90B3)";
+case 0x90B4 /* GL_PATH_DASH_OFFSET_RESET_NV */: return "GL_PATH_DASH_OFFSET_RESET_NV (0x90B4)";
+case 0x90B5 /* GL_MOVE_TO_RESETS_NV */: return "GL_MOVE_TO_RESETS_NV (0x90B5)";
+case 0x90B6 /* GL_MOVE_TO_CONTINUES_NV */: return "GL_MOVE_TO_CONTINUES_NV (0x90B6)";
+case 0x90B7 /* GL_PATH_STENCIL_FUNC_NV */: return "GL_PATH_STENCIL_FUNC_NV (0x90B7)";
+case 0x90B8 /* GL_PATH_STENCIL_REF_NV */: return "GL_PATH_STENCIL_REF_NV (0x90B8)";
+case 0x90B9 /* GL_PATH_STENCIL_VALUE_MASK_NV */: return "GL_PATH_STENCIL_VALUE_MASK_NV (0x90B9)";
+case 0x90BD /* GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV */: return "GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV (0x90BD)";
+case 0x90BE /* GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV */: return "GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV (0x90BE)";
+case 0x90BF /* GL_PATH_COVER_DEPTH_FUNC_NV */: return "GL_PATH_COVER_DEPTH_FUNC_NV (0x90BF)";
+//case 0x00010000 /* GL_FONT_X_MIN_BOUNDS_BIT_NV */: return "GL_FONT_X_MIN_BOUNDS_BIT_NV (0x00010000)";
+//case 0x00020000 /* GL_FONT_Y_MIN_BOUNDS_BIT_NV */: return "GL_FONT_Y_MIN_BOUNDS_BIT_NV (0x00020000)";
+//case 0x00040000 /* GL_FONT_X_MAX_BOUNDS_BIT_NV */: return "GL_FONT_X_MAX_BOUNDS_BIT_NV (0x00040000)";
+//case 0x00080000 /* GL_FONT_Y_MAX_BOUNDS_BIT_NV */: return "GL_FONT_Y_MAX_BOUNDS_BIT_NV (0x00080000)";
+case 0x00100000 /* GL_FONT_UNITS_PER_EM_BIT_NV */: return "GL_FONT_UNITS_PER_EM_BIT_NV (0x00100000)";
+case 0x00200000 /* GL_FONT_ASCENDER_BIT_NV */: return "GL_FONT_ASCENDER_BIT_NV (0x00200000)";
+case 0x00400000 /* GL_FONT_DESCENDER_BIT_NV */: return "GL_FONT_DESCENDER_BIT_NV (0x00400000)";
+case 0x00800000 /* GL_FONT_HEIGHT_BIT_NV */: return "GL_FONT_HEIGHT_BIT_NV (0x00800000)";
+case 0x01000000 /* GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV */: return "GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV (0x01000000)";
+case 0x02000000 /* GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV */: return "GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV (0x02000000)";
+case 0x04000000 /* GL_FONT_UNDERLINE_POSITION_BIT_NV */: return "GL_FONT_UNDERLINE_POSITION_BIT_NV (0x04000000)";
+case 0x08000000 /* GL_FONT_UNDERLINE_THICKNESS_BIT_NV */: return "GL_FONT_UNDERLINE_THICKNESS_BIT_NV (0x08000000)";
+case 0x10000000 /* GL_FONT_HAS_KERNING_BIT_NV */: return "GL_FONT_HAS_KERNING_BIT_NV (0x10000000)";
+
+
+
+
+
+/* ------------------------- GL_NV_pixel_data_range ------------------------ */
+
+
+
+
+case 0x8878 /* GL_WRITE_PIXEL_DATA_RANGE_NV */: return "GL_WRITE_PIXEL_DATA_RANGE_NV (0x8878)";
+case 0x8879 /* GL_READ_PIXEL_DATA_RANGE_NV */: return "GL_READ_PIXEL_DATA_RANGE_NV (0x8879)";
+case 0x887A /* GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV */: return "GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV (0x887A)";
+case 0x887B /* GL_READ_PIXEL_DATA_RANGE_LENGTH_NV */: return "GL_READ_PIXEL_DATA_RANGE_LENGTH_NV (0x887B)";
+case 0x887C /* GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV */: return "GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV (0x887C)";
+case 0x887D /* GL_READ_PIXEL_DATA_RANGE_POINTER_NV */: return "GL_READ_PIXEL_DATA_RANGE_POINTER_NV (0x887D)";
+
+/* --------------------------- GL_NV_point_sprite -------------------------- */
+
+
+
+
+//case 0x8861 /* GL_POINT_SPRITE_NV */: return "GL_POINT_SPRITE_NV (0x8861)";
+//case 0x8862 /* GL_COORD_REPLACE_NV */: return "GL_COORD_REPLACE_NV (0x8862)";
+case 0x8863 /* GL_POINT_SPRITE_R_MODE_NV */: return "GL_POINT_SPRITE_R_MODE_NV (0x8863)";
+
+/* -------------------------- GL_NV_present_video -------------------------- */
+
+
+
+
+case 0x8E26 /* GL_FRAME_NV */: return "GL_FRAME_NV (0x8E26)";
+case 0x8E27 /* GL_FIELDS_NV */: return "GL_FIELDS_NV (0x8E27)";
+//case 0x8E28 /* GL_CURRENT_TIME_NV */: return "GL_CURRENT_TIME_NV (0x8E28)";
+case 0x8E29 /* GL_NUM_FILL_STREAMS_NV */: return "GL_NUM_FILL_STREAMS_NV (0x8E29)";
+case 0x8E2A /* GL_PRESENT_TIME_NV */: return "GL_PRESENT_TIME_NV (0x8E2A)";
+case 0x8E2B /* GL_PRESENT_DURATION_NV */: return "GL_PRESENT_DURATION_NV (0x8E2B)";/* ------------------------ GL_NV_primitive_restart ------------------------ */
+
+
+
+
+case 0x8558 /* GL_PRIMITIVE_RESTART_NV */: return "GL_PRIMITIVE_RESTART_NV (0x8558)";
+case 0x8559 /* GL_PRIMITIVE_RESTART_INDEX_NV */: return "GL_PRIMITIVE_RESTART_INDEX_NV (0x8559)";
+
+/* ------------------------ GL_NV_register_combiners ----------------------- */
+
+
+
+
+case 0x8522 /* GL_REGISTER_COMBINERS_NV */: return "GL_REGISTER_COMBINERS_NV (0x8522)";
+case 0x8523 /* GL_VARIABLE_A_NV */: return "GL_VARIABLE_A_NV (0x8523)";
+case 0x8524 /* GL_VARIABLE_B_NV */: return "GL_VARIABLE_B_NV (0x8524)";
+case 0x8525 /* GL_VARIABLE_C_NV */: return "GL_VARIABLE_C_NV (0x8525)";
+case 0x8526 /* GL_VARIABLE_D_NV */: return "GL_VARIABLE_D_NV (0x8526)";
+case 0x8527 /* GL_VARIABLE_E_NV */: return "GL_VARIABLE_E_NV (0x8527)";
+case 0x8528 /* GL_VARIABLE_F_NV */: return "GL_VARIABLE_F_NV (0x8528)";
+case 0x8529 /* GL_VARIABLE_G_NV */: return "GL_VARIABLE_G_NV (0x8529)";
+case 0x852A /* GL_CONSTANT_COLOR0_NV */: return "GL_CONSTANT_COLOR0_NV (0x852A)";
+case 0x852B /* GL_CONSTANT_COLOR1_NV */: return "GL_CONSTANT_COLOR1_NV (0x852B)";
+//case 0x852C /* GL_PRIMARY_COLOR_NV */: return "GL_PRIMARY_COLOR_NV (0x852C)";
+//case 0x852D /* GL_SECONDARY_COLOR_NV */: return "GL_SECONDARY_COLOR_NV (0x852D)";
+case 0x852E /* GL_SPARE0_NV */: return "GL_SPARE0_NV (0x852E)";
+case 0x852F /* GL_SPARE1_NV */: return "GL_SPARE1_NV (0x852F)";
+case 0x8530 /* GL_DISCARD_NV */: return "GL_DISCARD_NV (0x8530)";
+case 0x8531 /* GL_E_TIMES_F_NV */: return "GL_E_TIMES_F_NV (0x8531)";
+case 0x8532 /* GL_SPARE0_PLUS_SECONDARY_COLOR_NV */: return "GL_SPARE0_PLUS_SECONDARY_COLOR_NV (0x8532)";
+case 0x8536 /* GL_UNSIGNED_IDENTITY_NV */: return "GL_UNSIGNED_IDENTITY_NV (0x8536)";
+case 0x8537 /* GL_UNSIGNED_INVERT_NV */: return "GL_UNSIGNED_INVERT_NV (0x8537)";
+case 0x8538 /* GL_EXPAND_NORMAL_NV */: return "GL_EXPAND_NORMAL_NV (0x8538)";
+case 0x8539 /* GL_EXPAND_NEGATE_NV */: return "GL_EXPAND_NEGATE_NV (0x8539)";
+case 0x853A /* GL_HALF_BIAS_NORMAL_NV */: return "GL_HALF_BIAS_NORMAL_NV (0x853A)";
+case 0x853B /* GL_HALF_BIAS_NEGATE_NV */: return "GL_HALF_BIAS_NEGATE_NV (0x853B)";
+case 0x853C /* GL_SIGNED_IDENTITY_NV */: return "GL_SIGNED_IDENTITY_NV (0x853C)";
+case 0x853D /* GL_SIGNED_NEGATE_NV */: return "GL_SIGNED_NEGATE_NV (0x853D)";
+case 0x853E /* GL_SCALE_BY_TWO_NV */: return "GL_SCALE_BY_TWO_NV (0x853E)";
+case 0x853F /* GL_SCALE_BY_FOUR_NV */: return "GL_SCALE_BY_FOUR_NV (0x853F)";
+case 0x8540 /* GL_SCALE_BY_ONE_HALF_NV */: return "GL_SCALE_BY_ONE_HALF_NV (0x8540)";
+case 0x8541 /* GL_BIAS_BY_NEGATIVE_ONE_HALF_NV */: return "GL_BIAS_BY_NEGATIVE_ONE_HALF_NV (0x8541)";
+case 0x8542 /* GL_COMBINER_INPUT_NV */: return "GL_COMBINER_INPUT_NV (0x8542)";
+case 0x8543 /* GL_COMBINER_MAPPING_NV */: return "GL_COMBINER_MAPPING_NV (0x8543)";
+case 0x8544 /* GL_COMBINER_COMPONENT_USAGE_NV */: return "GL_COMBINER_COMPONENT_USAGE_NV (0x8544)";
+case 0x8545 /* GL_COMBINER_AB_DOT_PRODUCT_NV */: return "GL_COMBINER_AB_DOT_PRODUCT_NV (0x8545)";
+case 0x8546 /* GL_COMBINER_CD_DOT_PRODUCT_NV */: return "GL_COMBINER_CD_DOT_PRODUCT_NV (0x8546)";
+case 0x8547 /* GL_COMBINER_MUX_SUM_NV */: return "GL_COMBINER_MUX_SUM_NV (0x8547)";
+case 0x8548 /* GL_COMBINER_SCALE_NV */: return "GL_COMBINER_SCALE_NV (0x8548)";
+case 0x8549 /* GL_COMBINER_BIAS_NV */: return "GL_COMBINER_BIAS_NV (0x8549)";
+case 0x854A /* GL_COMBINER_AB_OUTPUT_NV */: return "GL_COMBINER_AB_OUTPUT_NV (0x854A)";
+case 0x854B /* GL_COMBINER_CD_OUTPUT_NV */: return "GL_COMBINER_CD_OUTPUT_NV (0x854B)";
+case 0x854C /* GL_COMBINER_SUM_OUTPUT_NV */: return "GL_COMBINER_SUM_OUTPUT_NV (0x854C)";
+case 0x854D /* GL_MAX_GENERAL_COMBINERS_NV */: return "GL_MAX_GENERAL_COMBINERS_NV (0x854D)";
+case 0x854E /* GL_NUM_GENERAL_COMBINERS_NV */: return "GL_NUM_GENERAL_COMBINERS_NV (0x854E)";
+case 0x854F /* GL_COLOR_SUM_CLAMP_NV */: return "GL_COLOR_SUM_CLAMP_NV (0x854F)";
+case 0x8550 /* GL_COMBINER0_NV */: return "GL_COMBINER0_NV (0x8550)";
+case 0x8551 /* GL_COMBINER1_NV */: return "GL_COMBINER1_NV (0x8551)";
+case 0x8552 /* GL_COMBINER2_NV */: return "GL_COMBINER2_NV (0x8552)";
+case 0x8553 /* GL_COMBINER3_NV */: return "GL_COMBINER3_NV (0x8553)";
+case 0x8554 /* GL_COMBINER4_NV */: return "GL_COMBINER4_NV (0x8554)";
+case 0x8555 /* GL_COMBINER5_NV */: return "GL_COMBINER5_NV (0x8555)";
+case 0x8556 /* GL_COMBINER6_NV */: return "GL_COMBINER6_NV (0x8556)";
+case 0x8557 /* GL_COMBINER7_NV */: return "GL_COMBINER7_NV (0x8557)";
+
+
+
+/* ----------------------- GL_NV_register_combiners2 ----------------------- */
+
+
+
+
+case 0x8535 /* GL_PER_STAGE_CONSTANTS_NV */: return "GL_PER_STAGE_CONSTANTS_NV (0x8535)";
+
+/* ----------------------- GL_NV_shader_atomic_float ----------------------- */
+
+
+
+
+
+
+
+
+/* ------------------------ GL_NV_shader_buffer_load ----------------------- */
+
+
+
+
+case 0x8F1D /* GL_BUFFER_GPU_ADDRESS_NV */: return "GL_BUFFER_GPU_ADDRESS_NV (0x8F1D)";
+case 0x8F34 /* GL_GPU_ADDRESS_NV */: return "GL_GPU_ADDRESS_NV (0x8F34)";
+case 0x8F35 /* GL_MAX_SHADER_BUFFER_ADDRESS_NV */: return "GL_MAX_SHADER_BUFFER_ADDRESS_NV (0x8F35)";
+
+
+
+/* ---------------------- GL_NV_tessellation_program5 ---------------------- */
+
+
+
+
+case 0x86D8 /* GL_MAX_PROGRAM_PATCH_ATTRIBS_NV */: return "GL_MAX_PROGRAM_PATCH_ATTRIBS_NV (0x86D8)";
+case 0x891E /* GL_TESS_CONTROL_PROGRAM_NV */: return "GL_TESS_CONTROL_PROGRAM_NV (0x891E)";
+case 0x891F /* GL_TESS_EVALUATION_PROGRAM_NV */: return "GL_TESS_EVALUATION_PROGRAM_NV (0x891F)";
+case 0x8C74 /* GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV */: return "GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV (0x8C74)";
+case 0x8C75 /* GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV */: return "GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV (0x8C75)";
+
+
+
+
+
+/* -------------------------- GL_NV_texgen_emboss -------------------------- */
+
+
+
+
+case 0x855D /* GL_EMBOSS_LIGHT_NV */: return "GL_EMBOSS_LIGHT_NV (0x855D)";
+case 0x855E /* GL_EMBOSS_CONSTANT_NV */: return "GL_EMBOSS_CONSTANT_NV (0x855E)";
+case 0x855F /* GL_EMBOSS_MAP_NV */: return "GL_EMBOSS_MAP_NV (0x855F)";
+
+
+
+
+
+/* ------------------------ GL_NV_texgen_reflection ------------------------ */
+
+
+
+
+//case 0x8511 /* GL_NORMAL_MAP_NV */: return "GL_NORMAL_MAP_NV (0x8511)";
+//case 0x8512 /* GL_REFLECTION_MAP_NV */: return "GL_REFLECTION_MAP_NV (0x8512)";
+
+
+
+
+
+/* ------------------------- GL_NV_texture_barrier ------------------------- */
+
+
+/* --------------------- GL_NV_texture_compression_vtc --------------------- */
+
+
+
+
+
+
+
+
+/* ----------------------- GL_NV_texture_env_combine4 ---------------------- */
+
+
+
+
+case 0x8503 /* GL_COMBINE4_NV */: return "GL_COMBINE4_NV (0x8503)";
+case 0x8583 /* GL_SOURCE3_RGB_NV */: return "GL_SOURCE3_RGB_NV (0x8583)";
+case 0x858B /* GL_SOURCE3_ALPHA_NV */: return "GL_SOURCE3_ALPHA_NV (0x858B)";
+case 0x8593 /* GL_OPERAND3_RGB_NV */: return "GL_OPERAND3_RGB_NV (0x8593)";
+case 0x859B /* GL_OPERAND3_ALPHA_NV */: return "GL_OPERAND3_ALPHA_NV (0x859B)";
+
+
+
+
+
+/* ---------------------- GL_NV_texture_expand_normal ---------------------- */
+
+
+
+
+case 0x888F /* GL_TEXTURE_UNSIGNED_REMAP_MODE_NV */: return "GL_TEXTURE_UNSIGNED_REMAP_MODE_NV (0x888F)";
+
+
+
+
+
+/* ----------------------- GL_NV_texture_multisample ----------------------- */
+
+
+
+
+case 0x9045 /* GL_TEXTURE_COVERAGE_SAMPLES_NV */: return "GL_TEXTURE_COVERAGE_SAMPLES_NV (0x9045)";
+case 0x9046 /* GL_TEXTURE_COLOR_SAMPLES_NV */: return "GL_TEXTURE_COLOR_SAMPLES_NV (0x9046)";/* ------------------------ GL_NV_texture_rectangle ------------------------ */
+
+
+
+
+//case 0x84F5 /* GL_TEXTURE_RECTANGLE_NV */: return "GL_TEXTURE_RECTANGLE_NV (0x84F5)";
+//case 0x84F6 /* GL_TEXTURE_BINDING_RECTANGLE_NV */: return "GL_TEXTURE_BINDING_RECTANGLE_NV (0x84F6)";
+//case 0x84F7 /* GL_PROXY_TEXTURE_RECTANGLE_NV */: return "GL_PROXY_TEXTURE_RECTANGLE_NV (0x84F7)";
+//case 0x84F8 /* GL_MAX_RECTANGLE_TEXTURE_SIZE_NV */: return "GL_MAX_RECTANGLE_TEXTURE_SIZE_NV (0x84F8)";
+
+
+
+
+
+/* -------------------------- GL_NV_texture_shader ------------------------- */
+
+
+
+
+case 0x864C /* GL_OFFSET_TEXTURE_RECTANGLE_NV */: return "GL_OFFSET_TEXTURE_RECTANGLE_NV (0x864C)";
+case 0x864D /* GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV */: return "GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV (0x864D)";
+case 0x864E /* GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV */: return "GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV (0x864E)";
+case 0x86D9 /* GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV */: return "GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV (0x86D9)";
+case 0x86DA /* GL_UNSIGNED_INT_S8_S8_8_8_NV */: return "GL_UNSIGNED_INT_S8_S8_8_8_NV (0x86DA)";
+case 0x86DB /* GL_UNSIGNED_INT_8_8_S8_S8_REV_NV */: return "GL_UNSIGNED_INT_8_8_S8_S8_REV_NV (0x86DB)";
+case 0x86DC /* GL_DSDT_MAG_INTENSITY_NV */: return "GL_DSDT_MAG_INTENSITY_NV (0x86DC)";
+case 0x86DD /* GL_SHADER_CONSISTENT_NV */: return "GL_SHADER_CONSISTENT_NV (0x86DD)";
+case 0x86DE /* GL_TEXTURE_SHADER_NV */: return "GL_TEXTURE_SHADER_NV (0x86DE)";
+case 0x86DF /* GL_SHADER_OPERATION_NV */: return "GL_SHADER_OPERATION_NV (0x86DF)";
+case 0x86E0 /* GL_CULL_MODES_NV */: return "GL_CULL_MODES_NV (0x86E0)";
+case 0x86E1 /* GL_OFFSET_TEXTURE_2D_MATRIX_NV */: return "GL_OFFSET_TEXTURE_2D_MATRIX_NV (0x86E1)";
+//case 0x86E1 /* GL_OFFSET_TEXTURE_MATRIX_NV */: return "GL_OFFSET_TEXTURE_MATRIX_NV (0x86E1)";
+case 0x86E2 /* GL_OFFSET_TEXTURE_2D_SCALE_NV */: return "GL_OFFSET_TEXTURE_2D_SCALE_NV (0x86E2)";
+//case 0x86E2 /* GL_OFFSET_TEXTURE_SCALE_NV */: return "GL_OFFSET_TEXTURE_SCALE_NV (0x86E2)";
+case 0x86E3 /* GL_OFFSET_TEXTURE_BIAS_NV */: return "GL_OFFSET_TEXTURE_BIAS_NV (0x86E3)";
+//case 0x86E3 /* GL_OFFSET_TEXTURE_2D_BIAS_NV */: return "GL_OFFSET_TEXTURE_2D_BIAS_NV (0x86E3)";
+case 0x86E4 /* GL_PREVIOUS_TEXTURE_INPUT_NV */: return "GL_PREVIOUS_TEXTURE_INPUT_NV (0x86E4)";
+case 0x86E5 /* GL_CONST_EYE_NV */: return "GL_CONST_EYE_NV (0x86E5)";
+case 0x86E6 /* GL_PASS_THROUGH_NV */: return "GL_PASS_THROUGH_NV (0x86E6)";
+case 0x86E7 /* GL_CULL_FRAGMENT_NV */: return "GL_CULL_FRAGMENT_NV (0x86E7)";
+case 0x86E8 /* GL_OFFSET_TEXTURE_2D_NV */: return "GL_OFFSET_TEXTURE_2D_NV (0x86E8)";
+case 0x86E9 /* GL_DEPENDENT_AR_TEXTURE_2D_NV */: return "GL_DEPENDENT_AR_TEXTURE_2D_NV (0x86E9)";
+case 0x86EA /* GL_DEPENDENT_GB_TEXTURE_2D_NV */: return "GL_DEPENDENT_GB_TEXTURE_2D_NV (0x86EA)";
+case 0x86EC /* GL_DOT_PRODUCT_NV */: return "GL_DOT_PRODUCT_NV (0x86EC)";
+case 0x86ED /* GL_DOT_PRODUCT_DEPTH_REPLACE_NV */: return "GL_DOT_PRODUCT_DEPTH_REPLACE_NV (0x86ED)";
+case 0x86EE /* GL_DOT_PRODUCT_TEXTURE_2D_NV */: return "GL_DOT_PRODUCT_TEXTURE_2D_NV (0x86EE)";
+case 0x86F0 /* GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV */: return "GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV (0x86F0)";
+case 0x86F1 /* GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV */: return "GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV (0x86F1)";
+case 0x86F2 /* GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV */: return "GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV (0x86F2)";
+case 0x86F3 /* GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV */: return "GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV (0x86F3)";
+case 0x86F4 /* GL_HILO_NV */: return "GL_HILO_NV (0x86F4)";
+case 0x86F5 /* GL_DSDT_NV */: return "GL_DSDT_NV (0x86F5)";
+case 0x86F6 /* GL_DSDT_MAG_NV */: return "GL_DSDT_MAG_NV (0x86F6)";
+case 0x86F7 /* GL_DSDT_MAG_VIB_NV */: return "GL_DSDT_MAG_VIB_NV (0x86F7)";
+case 0x86F8 /* GL_HILO16_NV */: return "GL_HILO16_NV (0x86F8)";
+case 0x86F9 /* GL_SIGNED_HILO_NV */: return "GL_SIGNED_HILO_NV (0x86F9)";
+case 0x86FA /* GL_SIGNED_HILO16_NV */: return "GL_SIGNED_HILO16_NV (0x86FA)";
+case 0x86FB /* GL_SIGNED_RGBA_NV */: return "GL_SIGNED_RGBA_NV (0x86FB)";
+case 0x86FC /* GL_SIGNED_RGBA8_NV */: return "GL_SIGNED_RGBA8_NV (0x86FC)";
+case 0x86FE /* GL_SIGNED_RGB_NV */: return "GL_SIGNED_RGB_NV (0x86FE)";
+case 0x86FF /* GL_SIGNED_RGB8_NV */: return "GL_SIGNED_RGB8_NV (0x86FF)";
+case 0x8701 /* GL_SIGNED_LUMINANCE_NV */: return "GL_SIGNED_LUMINANCE_NV (0x8701)";
+case 0x8702 /* GL_SIGNED_LUMINANCE8_NV */: return "GL_SIGNED_LUMINANCE8_NV (0x8702)";
+case 0x8703 /* GL_SIGNED_LUMINANCE_ALPHA_NV */: return "GL_SIGNED_LUMINANCE_ALPHA_NV (0x8703)";
+case 0x8704 /* GL_SIGNED_LUMINANCE8_ALPHA8_NV */: return "GL_SIGNED_LUMINANCE8_ALPHA8_NV (0x8704)";
+case 0x8705 /* GL_SIGNED_ALPHA_NV */: return "GL_SIGNED_ALPHA_NV (0x8705)";
+case 0x8706 /* GL_SIGNED_ALPHA8_NV */: return "GL_SIGNED_ALPHA8_NV (0x8706)";
+case 0x8707 /* GL_SIGNED_INTENSITY_NV */: return "GL_SIGNED_INTENSITY_NV (0x8707)";
+case 0x8708 /* GL_SIGNED_INTENSITY8_NV */: return "GL_SIGNED_INTENSITY8_NV (0x8708)";
+case 0x8709 /* GL_DSDT8_NV */: return "GL_DSDT8_NV (0x8709)";
+case 0x870A /* GL_DSDT8_MAG8_NV */: return "GL_DSDT8_MAG8_NV (0x870A)";
+case 0x870B /* GL_DSDT8_MAG8_INTENSITY8_NV */: return "GL_DSDT8_MAG8_INTENSITY8_NV (0x870B)";
+case 0x870C /* GL_SIGNED_RGB_UNSIGNED_ALPHA_NV */: return "GL_SIGNED_RGB_UNSIGNED_ALPHA_NV (0x870C)";
+case 0x870D /* GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV */: return "GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV (0x870D)";
+case 0x870E /* GL_HI_SCALE_NV */: return "GL_HI_SCALE_NV (0x870E)";
+case 0x870F /* GL_LO_SCALE_NV */: return "GL_LO_SCALE_NV (0x870F)";
+case 0x8710 /* GL_DS_SCALE_NV */: return "GL_DS_SCALE_NV (0x8710)";
+case 0x8711 /* GL_DT_SCALE_NV */: return "GL_DT_SCALE_NV (0x8711)";
+case 0x8712 /* GL_MAGNITUDE_SCALE_NV */: return "GL_MAGNITUDE_SCALE_NV (0x8712)";
+case 0x8713 /* GL_VIBRANCE_SCALE_NV */: return "GL_VIBRANCE_SCALE_NV (0x8713)";
+case 0x8714 /* GL_HI_BIAS_NV */: return "GL_HI_BIAS_NV (0x8714)";
+case 0x8715 /* GL_LO_BIAS_NV */: return "GL_LO_BIAS_NV (0x8715)";
+case 0x8716 /* GL_DS_BIAS_NV */: return "GL_DS_BIAS_NV (0x8716)";
+case 0x8717 /* GL_DT_BIAS_NV */: return "GL_DT_BIAS_NV (0x8717)";
+case 0x8718 /* GL_MAGNITUDE_BIAS_NV */: return "GL_MAGNITUDE_BIAS_NV (0x8718)";
+case 0x8719 /* GL_VIBRANCE_BIAS_NV */: return "GL_VIBRANCE_BIAS_NV (0x8719)";
+case 0x871A /* GL_TEXTURE_BORDER_VALUES_NV */: return "GL_TEXTURE_BORDER_VALUES_NV (0x871A)";
+case 0x871B /* GL_TEXTURE_HI_SIZE_NV */: return "GL_TEXTURE_HI_SIZE_NV (0x871B)";
+case 0x871C /* GL_TEXTURE_LO_SIZE_NV */: return "GL_TEXTURE_LO_SIZE_NV (0x871C)";
+case 0x871D /* GL_TEXTURE_DS_SIZE_NV */: return "GL_TEXTURE_DS_SIZE_NV (0x871D)";
+case 0x871E /* GL_TEXTURE_DT_SIZE_NV */: return "GL_TEXTURE_DT_SIZE_NV (0x871E)";
+case 0x871F /* GL_TEXTURE_MAG_SIZE_NV */: return "GL_TEXTURE_MAG_SIZE_NV (0x871F)";
+
+
+
+
+
+/* ------------------------- GL_NV_texture_shader2 ------------------------- */
+
+
+
+
+//case 0x86DA /* GL_UNSIGNED_INT_S8_S8_8_8_NV */: return "GL_UNSIGNED_INT_S8_S8_8_8_NV (0x86DA)";
+//case 0x86DB /* GL_UNSIGNED_INT_8_8_S8_S8_REV_NV */: return "GL_UNSIGNED_INT_8_8_S8_S8_REV_NV (0x86DB)";
+//case 0x86DC /* GL_DSDT_MAG_INTENSITY_NV */: return "GL_DSDT_MAG_INTENSITY_NV (0x86DC)";
+case 0x86EF /* GL_DOT_PRODUCT_TEXTURE_3D_NV */: return "GL_DOT_PRODUCT_TEXTURE_3D_NV (0x86EF)";
+//case 0x86F4 /* GL_HILO_NV */: return "GL_HILO_NV (0x86F4)";
+//case 0x86F5 /* GL_DSDT_NV */: return "GL_DSDT_NV (0x86F5)";
+//case 0x86F6 /* GL_DSDT_MAG_NV */: return "GL_DSDT_MAG_NV (0x86F6)";
+//case 0x86F7 /* GL_DSDT_MAG_VIB_NV */: return "GL_DSDT_MAG_VIB_NV (0x86F7)";
+//case 0x86F8 /* GL_HILO16_NV */: return "GL_HILO16_NV (0x86F8)";
+//case 0x86F9 /* GL_SIGNED_HILO_NV */: return "GL_SIGNED_HILO_NV (0x86F9)";
+//case 0x86FA /* GL_SIGNED_HILO16_NV */: return "GL_SIGNED_HILO16_NV (0x86FA)";
+//case 0x86FB /* GL_SIGNED_RGBA_NV */: return "GL_SIGNED_RGBA_NV (0x86FB)";
+//case 0x86FC /* GL_SIGNED_RGBA8_NV */: return "GL_SIGNED_RGBA8_NV (0x86FC)";
+//case 0x86FE /* GL_SIGNED_RGB_NV */: return "GL_SIGNED_RGB_NV (0x86FE)";
+//case 0x86FF /* GL_SIGNED_RGB8_NV */: return "GL_SIGNED_RGB8_NV (0x86FF)";
+//case 0x8701 /* GL_SIGNED_LUMINANCE_NV */: return "GL_SIGNED_LUMINANCE_NV (0x8701)";
+//case 0x8702 /* GL_SIGNED_LUMINANCE8_NV */: return "GL_SIGNED_LUMINANCE8_NV (0x8702)";
+//case 0x8703 /* GL_SIGNED_LUMINANCE_ALPHA_NV */: return "GL_SIGNED_LUMINANCE_ALPHA_NV (0x8703)";
+//case 0x8704 /* GL_SIGNED_LUMINANCE8_ALPHA8_NV */: return "GL_SIGNED_LUMINANCE8_ALPHA8_NV (0x8704)";
+//case 0x8705 /* GL_SIGNED_ALPHA_NV */: return "GL_SIGNED_ALPHA_NV (0x8705)";
+//case 0x8706 /* GL_SIGNED_ALPHA8_NV */: return "GL_SIGNED_ALPHA8_NV (0x8706)";
+//case 0x8707 /* GL_SIGNED_INTENSITY_NV */: return "GL_SIGNED_INTENSITY_NV (0x8707)";
+//case 0x8708 /* GL_SIGNED_INTENSITY8_NV */: return "GL_SIGNED_INTENSITY8_NV (0x8708)";
+//case 0x8709 /* GL_DSDT8_NV */: return "GL_DSDT8_NV (0x8709)";
+//case 0x870A /* GL_DSDT8_MAG8_NV */: return "GL_DSDT8_MAG8_NV (0x870A)";
+//case 0x870B /* GL_DSDT8_MAG8_INTENSITY8_NV */: return "GL_DSDT8_MAG8_INTENSITY8_NV (0x870B)";
+//case 0x870C /* GL_SIGNED_RGB_UNSIGNED_ALPHA_NV */: return "GL_SIGNED_RGB_UNSIGNED_ALPHA_NV (0x870C)";
+//case 0x870D /* GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV */: return "GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV (0x870D)";
+
+
+
+
+
+/* ------------------------- GL_NV_texture_shader3 ------------------------- */
+
+
+
+
+case 0x8850 /* GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV */: return "GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV (0x8850)";
+case 0x8851 /* GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV */: return "GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV (0x8851)";
+case 0x8852 /* GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV */: return "GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV (0x8852)";
+case 0x8853 /* GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV */: return "GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV (0x8853)";
+case 0x8854 /* GL_OFFSET_HILO_TEXTURE_2D_NV */: return "GL_OFFSET_HILO_TEXTURE_2D_NV (0x8854)";
+case 0x8855 /* GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV */: return "GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV (0x8855)";
+case 0x8856 /* GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV */: return "GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV (0x8856)";
+case 0x8857 /* GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV */: return "GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV (0x8857)";
+case 0x8858 /* GL_DEPENDENT_HILO_TEXTURE_2D_NV */: return "GL_DEPENDENT_HILO_TEXTURE_2D_NV (0x8858)";
+case 0x8859 /* GL_DEPENDENT_RGB_TEXTURE_3D_NV */: return "GL_DEPENDENT_RGB_TEXTURE_3D_NV (0x8859)";
+case 0x885A /* GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV */: return "GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV (0x885A)";
+case 0x885B /* GL_DOT_PRODUCT_PASS_THROUGH_NV */: return "GL_DOT_PRODUCT_PASS_THROUGH_NV (0x885B)";
+case 0x885C /* GL_DOT_PRODUCT_TEXTURE_1D_NV */: return "GL_DOT_PRODUCT_TEXTURE_1D_NV (0x885C)";
+case 0x885D /* GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV */: return "GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV (0x885D)";
+case 0x885E /* GL_HILO8_NV */: return "GL_HILO8_NV (0x885E)";
+case 0x885F /* GL_SIGNED_HILO8_NV */: return "GL_SIGNED_HILO8_NV (0x885F)";
+case 0x8860 /* GL_FORCE_BLUE_TO_ONE_NV */: return "GL_FORCE_BLUE_TO_ONE_NV (0x8860)";
+
+
+
+
+
+/* ------------------------ GL_NV_transform_feedback ----------------------- */
+
+
+
+
+case 0x8C77 /* GL_BACK_PRIMARY_COLOR_NV */: return "GL_BACK_PRIMARY_COLOR_NV (0x8C77)";
+case 0x8C78 /* GL_BACK_SECONDARY_COLOR_NV */: return "GL_BACK_SECONDARY_COLOR_NV (0x8C78)";
+case 0x8C79 /* GL_TEXTURE_COORD_NV */: return "GL_TEXTURE_COORD_NV (0x8C79)";
+case 0x8C7A /* GL_CLIP_DISTANCE_NV */: return "GL_CLIP_DISTANCE_NV (0x8C7A)";
+case 0x8C7B /* GL_VERTEX_ID_NV */: return "GL_VERTEX_ID_NV (0x8C7B)";
+case 0x8C7C /* GL_PRIMITIVE_ID_NV */: return "GL_PRIMITIVE_ID_NV (0x8C7C)";
+case 0x8C7D /* GL_GENERIC_ATTRIB_NV */: return "GL_GENERIC_ATTRIB_NV (0x8C7D)";
+case 0x8C7E /* GL_TRANSFORM_FEEDBACK_ATTRIBS_NV */: return "GL_TRANSFORM_FEEDBACK_ATTRIBS_NV (0x8C7E)";
+//case 0x8C7F /* GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV */: return "GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV (0x8C7F)";
+//case 0x8C80 /* GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV */: return "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV (0x8C80)";
+case 0x8C81 /* GL_ACTIVE_VARYINGS_NV */: return "GL_ACTIVE_VARYINGS_NV (0x8C81)";
+case 0x8C82 /* GL_ACTIVE_VARYING_MAX_LENGTH_NV */: return "GL_ACTIVE_VARYING_MAX_LENGTH_NV (0x8C82)";
+//case 0x8C83 /* GL_TRANSFORM_FEEDBACK_VARYINGS_NV */: return "GL_TRANSFORM_FEEDBACK_VARYINGS_NV (0x8C83)";
+//case 0x8C84 /* GL_TRANSFORM_FEEDBACK_BUFFER_START_NV */: return "GL_TRANSFORM_FEEDBACK_BUFFER_START_NV (0x8C84)";
+//case 0x8C85 /* GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV */: return "GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV (0x8C85)";
+case 0x8C86 /* GL_TRANSFORM_FEEDBACK_RECORD_NV */: return "GL_TRANSFORM_FEEDBACK_RECORD_NV (0x8C86)";
+//case 0x8C87 /* GL_PRIMITIVES_GENERATED_NV */: return "GL_PRIMITIVES_GENERATED_NV (0x8C87)";
+//case 0x8C88 /* GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV */: return "GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV (0x8C88)";
+//case 0x8C89 /* GL_RASTERIZER_DISCARD_NV */: return "GL_RASTERIZER_DISCARD_NV (0x8C89)";
+//case 0x8C8A /* GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV */: return "GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV (0x8C8A)";
+//case 0x8C8B /* GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV */: return "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV (0x8C8B)";
+//case 0x8C8C /* GL_INTERLEAVED_ATTRIBS_NV */: return "GL_INTERLEAVED_ATTRIBS_NV (0x8C8C)";
+//case 0x8C8D /* GL_SEPARATE_ATTRIBS_NV */: return "GL_SEPARATE_ATTRIBS_NV (0x8C8D)";
+//case 0x8C8E /* GL_TRANSFORM_FEEDBACK_BUFFER_NV */: return "GL_TRANSFORM_FEEDBACK_BUFFER_NV (0x8C8E)";
+//case 0x8C8F /* GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV */: return "GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV (0x8C8F)";/* ----------------------- GL_NV_transform_feedback2 ----------------------- */
+
+
+
+
+//case 0x8E22 /* GL_TRANSFORM_FEEDBACK_NV */: return "GL_TRANSFORM_FEEDBACK_NV (0x8E22)";
+//case 0x8E23 /* GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV */: return "GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV (0x8E23)";
+//case 0x8E24 /* GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV */: return "GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV (0x8E24)";
+//case 0x8E25 /* GL_TRANSFORM_FEEDBACK_BINDING_NV */: return "GL_TRANSFORM_FEEDBACK_BINDING_NV (0x8E25)";
+
+/* -------------------------- GL_NV_vdpau_interop -------------------------- */
+
+
+
+
+case 0x86EB /* GL_SURFACE_STATE_NV */: return "GL_SURFACE_STATE_NV (0x86EB)";
+case 0x86FD /* GL_SURFACE_REGISTERED_NV */: return "GL_SURFACE_REGISTERED_NV (0x86FD)";
+case 0x8700 /* GL_SURFACE_MAPPED_NV */: return "GL_SURFACE_MAPPED_NV (0x8700)";
+case 0x88BE /* GL_WRITE_DISCARD_NV */: return "GL_WRITE_DISCARD_NV (0x88BE)";/* ------------------------ GL_NV_vertex_array_range ----------------------- */
+
+
+
+
+//case 0x851D /* GL_VERTEX_ARRAY_RANGE_NV */: return "GL_VERTEX_ARRAY_RANGE_NV (0x851D)";
+//case 0x851E /* GL_VERTEX_ARRAY_RANGE_LENGTH_NV */: return "GL_VERTEX_ARRAY_RANGE_LENGTH_NV (0x851E)";
+//case 0x851F /* GL_VERTEX_ARRAY_RANGE_VALID_NV */: return "GL_VERTEX_ARRAY_RANGE_VALID_NV (0x851F)";
+//case 0x8520 /* GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV */: return "GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV (0x8520)";
+//case 0x8521 /* GL_VERTEX_ARRAY_RANGE_POINTER_NV */: return "GL_VERTEX_ARRAY_RANGE_POINTER_NV (0x8521)";
+
+/* ----------------------- GL_NV_vertex_array_range2 ----------------------- */
+
+
+
+
+case 0x8533 /* GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV */: return "GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV (0x8533)";
+
+
+
+
+
+/* ------------------- GL_NV_vertex_attrib_integer_64bit ------------------- */
+
+
+
+
+//case 0x140E /* GL_INT64_NV */: return "GL_INT64_NV (0x140E)";
+//case 0x140F /* GL_UNSIGNED_INT64_NV */: return "GL_UNSIGNED_INT64_NV (0x140F)";
+
+
+
+
+
+/* ------------------- GL_NV_vertex_buffer_unified_memory ------------------ */
+
+
+
+
+case 0x8F1E /* GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV */: return "GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV (0x8F1E)";
+case 0x8F1F /* GL_ELEMENT_ARRAY_UNIFIED_NV */: return "GL_ELEMENT_ARRAY_UNIFIED_NV (0x8F1F)";
+case 0x8F20 /* GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV */: return "GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV (0x8F20)";
+case 0x8F21 /* GL_VERTEX_ARRAY_ADDRESS_NV */: return "GL_VERTEX_ARRAY_ADDRESS_NV (0x8F21)";
+case 0x8F22 /* GL_NORMAL_ARRAY_ADDRESS_NV */: return "GL_NORMAL_ARRAY_ADDRESS_NV (0x8F22)";
+case 0x8F23 /* GL_COLOR_ARRAY_ADDRESS_NV */: return "GL_COLOR_ARRAY_ADDRESS_NV (0x8F23)";
+case 0x8F24 /* GL_INDEX_ARRAY_ADDRESS_NV */: return "GL_INDEX_ARRAY_ADDRESS_NV (0x8F24)";
+case 0x8F25 /* GL_TEXTURE_COORD_ARRAY_ADDRESS_NV */: return "GL_TEXTURE_COORD_ARRAY_ADDRESS_NV (0x8F25)";
+case 0x8F26 /* GL_EDGE_FLAG_ARRAY_ADDRESS_NV */: return "GL_EDGE_FLAG_ARRAY_ADDRESS_NV (0x8F26)";
+case 0x8F27 /* GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV */: return "GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV (0x8F27)";
+case 0x8F28 /* GL_FOG_COORD_ARRAY_ADDRESS_NV */: return "GL_FOG_COORD_ARRAY_ADDRESS_NV (0x8F28)";
+case 0x8F29 /* GL_ELEMENT_ARRAY_ADDRESS_NV */: return "GL_ELEMENT_ARRAY_ADDRESS_NV (0x8F29)";
+case 0x8F2A /* GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV */: return "GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV (0x8F2A)";
+case 0x8F2B /* GL_VERTEX_ARRAY_LENGTH_NV */: return "GL_VERTEX_ARRAY_LENGTH_NV (0x8F2B)";
+case 0x8F2C /* GL_NORMAL_ARRAY_LENGTH_NV */: return "GL_NORMAL_ARRAY_LENGTH_NV (0x8F2C)";
+case 0x8F2D /* GL_COLOR_ARRAY_LENGTH_NV */: return "GL_COLOR_ARRAY_LENGTH_NV (0x8F2D)";
+case 0x8F2E /* GL_INDEX_ARRAY_LENGTH_NV */: return "GL_INDEX_ARRAY_LENGTH_NV (0x8F2E)";
+case 0x8F2F /* GL_TEXTURE_COORD_ARRAY_LENGTH_NV */: return "GL_TEXTURE_COORD_ARRAY_LENGTH_NV (0x8F2F)";
+case 0x8F30 /* GL_EDGE_FLAG_ARRAY_LENGTH_NV */: return "GL_EDGE_FLAG_ARRAY_LENGTH_NV (0x8F30)";
+case 0x8F31 /* GL_SECONDARY_COLOR_ARRAY_LENGTH_NV */: return "GL_SECONDARY_COLOR_ARRAY_LENGTH_NV (0x8F31)";
+case 0x8F32 /* GL_FOG_COORD_ARRAY_LENGTH_NV */: return "GL_FOG_COORD_ARRAY_LENGTH_NV (0x8F32)";
+case 0x8F33 /* GL_ELEMENT_ARRAY_LENGTH_NV */: return "GL_ELEMENT_ARRAY_LENGTH_NV (0x8F33)";
+case 0x8F40 /* GL_DRAW_INDIRECT_UNIFIED_NV */: return "GL_DRAW_INDIRECT_UNIFIED_NV (0x8F40)";
+case 0x8F41 /* GL_DRAW_INDIRECT_ADDRESS_NV */: return "GL_DRAW_INDIRECT_ADDRESS_NV (0x8F41)";
+case 0x8F42 /* GL_DRAW_INDIRECT_LENGTH_NV */: return "GL_DRAW_INDIRECT_LENGTH_NV (0x8F42)";
+
+/* -------------------------- GL_NV_vertex_program ------------------------- */
+
+
+
+
+//case 0x8620 /* GL_VERTEX_PROGRAM_NV */: return "GL_VERTEX_PROGRAM_NV (0x8620)";
+case 0x8621 /* GL_VERTEX_STATE_PROGRAM_NV */: return "GL_VERTEX_STATE_PROGRAM_NV (0x8621)";
+//case 0x8623 /* GL_ATTRIB_ARRAY_SIZE_NV */: return "GL_ATTRIB_ARRAY_SIZE_NV (0x8623)";
+//case 0x8624 /* GL_ATTRIB_ARRAY_STRIDE_NV */: return "GL_ATTRIB_ARRAY_STRIDE_NV (0x8624)";
+//case 0x8625 /* GL_ATTRIB_ARRAY_TYPE_NV */: return "GL_ATTRIB_ARRAY_TYPE_NV (0x8625)";
+//case 0x8626 /* GL_CURRENT_ATTRIB_NV */: return "GL_CURRENT_ATTRIB_NV (0x8626)";
+//case 0x8627 /* GL_PROGRAM_LENGTH_NV */: return "GL_PROGRAM_LENGTH_NV (0x8627)";
+//case 0x8628 /* GL_PROGRAM_STRING_NV */: return "GL_PROGRAM_STRING_NV (0x8628)";
+case 0x8629 /* GL_MODELVIEW_PROJECTION_NV */: return "GL_MODELVIEW_PROJECTION_NV (0x8629)";
+case 0x862A /* GL_IDENTITY_NV */: return "GL_IDENTITY_NV (0x862A)";
+case 0x862B /* GL_INVERSE_NV */: return "GL_INVERSE_NV (0x862B)";
+case 0x862C /* GL_TRANSPOSE_NV */: return "GL_TRANSPOSE_NV (0x862C)";
+case 0x862D /* GL_INVERSE_TRANSPOSE_NV */: return "GL_INVERSE_TRANSPOSE_NV (0x862D)";
+//case 0x862E /* GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV */: return "GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV (0x862E)";
+//case 0x862F /* GL_MAX_TRACK_MATRICES_NV */: return "GL_MAX_TRACK_MATRICES_NV (0x862F)";
+case 0x8630 /* GL_MATRIX0_NV */: return "GL_MATRIX0_NV (0x8630)";
+case 0x8631 /* GL_MATRIX1_NV */: return "GL_MATRIX1_NV (0x8631)";
+case 0x8632 /* GL_MATRIX2_NV */: return "GL_MATRIX2_NV (0x8632)";
+case 0x8633 /* GL_MATRIX3_NV */: return "GL_MATRIX3_NV (0x8633)";
+case 0x8634 /* GL_MATRIX4_NV */: return "GL_MATRIX4_NV (0x8634)";
+case 0x8635 /* GL_MATRIX5_NV */: return "GL_MATRIX5_NV (0x8635)";
+case 0x8636 /* GL_MATRIX6_NV */: return "GL_MATRIX6_NV (0x8636)";
+case 0x8637 /* GL_MATRIX7_NV */: return "GL_MATRIX7_NV (0x8637)";
+//case 0x8640 /* GL_CURRENT_MATRIX_STACK_DEPTH_NV */: return "GL_CURRENT_MATRIX_STACK_DEPTH_NV (0x8640)";
+//case 0x8641 /* GL_CURRENT_MATRIX_NV */: return "GL_CURRENT_MATRIX_NV (0x8641)";
+//case 0x8642 /* GL_VERTEX_PROGRAM_POINT_SIZE_NV */: return "GL_VERTEX_PROGRAM_POINT_SIZE_NV (0x8642)";
+//case 0x8643 /* GL_VERTEX_PROGRAM_TWO_SIDE_NV */: return "GL_VERTEX_PROGRAM_TWO_SIDE_NV (0x8643)";
+case 0x8644 /* GL_PROGRAM_PARAMETER_NV */: return "GL_PROGRAM_PARAMETER_NV (0x8644)";
+//case 0x8645 /* GL_ATTRIB_ARRAY_POINTER_NV */: return "GL_ATTRIB_ARRAY_POINTER_NV (0x8645)";
+case 0x8646 /* GL_PROGRAM_TARGET_NV */: return "GL_PROGRAM_TARGET_NV (0x8646)";
+case 0x8647 /* GL_PROGRAM_RESIDENT_NV */: return "GL_PROGRAM_RESIDENT_NV (0x8647)";
+case 0x8648 /* GL_TRACK_MATRIX_NV */: return "GL_TRACK_MATRIX_NV (0x8648)";
+case 0x8649 /* GL_TRACK_MATRIX_TRANSFORM_NV */: return "GL_TRACK_MATRIX_TRANSFORM_NV (0x8649)";
+case 0x864A /* GL_VERTEX_PROGRAM_BINDING_NV */: return "GL_VERTEX_PROGRAM_BINDING_NV (0x864A)";
+//case 0x864B /* GL_PROGRAM_ERROR_POSITION_NV */: return "GL_PROGRAM_ERROR_POSITION_NV (0x864B)";
+case 0x8650 /* GL_VERTEX_ATTRIB_ARRAY0_NV */: return "GL_VERTEX_ATTRIB_ARRAY0_NV (0x8650)";
+case 0x8651 /* GL_VERTEX_ATTRIB_ARRAY1_NV */: return "GL_VERTEX_ATTRIB_ARRAY1_NV (0x8651)";
+case 0x8652 /* GL_VERTEX_ATTRIB_ARRAY2_NV */: return "GL_VERTEX_ATTRIB_ARRAY2_NV (0x8652)";
+case 0x8653 /* GL_VERTEX_ATTRIB_ARRAY3_NV */: return "GL_VERTEX_ATTRIB_ARRAY3_NV (0x8653)";
+case 0x8654 /* GL_VERTEX_ATTRIB_ARRAY4_NV */: return "GL_VERTEX_ATTRIB_ARRAY4_NV (0x8654)";
+case 0x8655 /* GL_VERTEX_ATTRIB_ARRAY5_NV */: return "GL_VERTEX_ATTRIB_ARRAY5_NV (0x8655)";
+case 0x8656 /* GL_VERTEX_ATTRIB_ARRAY6_NV */: return "GL_VERTEX_ATTRIB_ARRAY6_NV (0x8656)";
+case 0x8657 /* GL_VERTEX_ATTRIB_ARRAY7_NV */: return "GL_VERTEX_ATTRIB_ARRAY7_NV (0x8657)";
+case 0x8658 /* GL_VERTEX_ATTRIB_ARRAY8_NV */: return "GL_VERTEX_ATTRIB_ARRAY8_NV (0x8658)";
+case 0x8659 /* GL_VERTEX_ATTRIB_ARRAY9_NV */: return "GL_VERTEX_ATTRIB_ARRAY9_NV (0x8659)";
+case 0x865A /* GL_VERTEX_ATTRIB_ARRAY10_NV */: return "GL_VERTEX_ATTRIB_ARRAY10_NV (0x865A)";
+case 0x865B /* GL_VERTEX_ATTRIB_ARRAY11_NV */: return "GL_VERTEX_ATTRIB_ARRAY11_NV (0x865B)";
+case 0x865C /* GL_VERTEX_ATTRIB_ARRAY12_NV */: return "GL_VERTEX_ATTRIB_ARRAY12_NV (0x865C)";
+case 0x865D /* GL_VERTEX_ATTRIB_ARRAY13_NV */: return "GL_VERTEX_ATTRIB_ARRAY13_NV (0x865D)";
+case 0x865E /* GL_VERTEX_ATTRIB_ARRAY14_NV */: return "GL_VERTEX_ATTRIB_ARRAY14_NV (0x865E)";
+case 0x865F /* GL_VERTEX_ATTRIB_ARRAY15_NV */: return "GL_VERTEX_ATTRIB_ARRAY15_NV (0x865F)";
+case 0x8660 /* GL_MAP1_VERTEX_ATTRIB0_4_NV */: return "GL_MAP1_VERTEX_ATTRIB0_4_NV (0x8660)";
+case 0x8661 /* GL_MAP1_VERTEX_ATTRIB1_4_NV */: return "GL_MAP1_VERTEX_ATTRIB1_4_NV (0x8661)";
+case 0x8662 /* GL_MAP1_VERTEX_ATTRIB2_4_NV */: return "GL_MAP1_VERTEX_ATTRIB2_4_NV (0x8662)";
+case 0x8663 /* GL_MAP1_VERTEX_ATTRIB3_4_NV */: return "GL_MAP1_VERTEX_ATTRIB3_4_NV (0x8663)";
+case 0x8664 /* GL_MAP1_VERTEX_ATTRIB4_4_NV */: return "GL_MAP1_VERTEX_ATTRIB4_4_NV (0x8664)";
+case 0x8665 /* GL_MAP1_VERTEX_ATTRIB5_4_NV */: return "GL_MAP1_VERTEX_ATTRIB5_4_NV (0x8665)";
+case 0x8666 /* GL_MAP1_VERTEX_ATTRIB6_4_NV */: return "GL_MAP1_VERTEX_ATTRIB6_4_NV (0x8666)";
+case 0x8667 /* GL_MAP1_VERTEX_ATTRIB7_4_NV */: return "GL_MAP1_VERTEX_ATTRIB7_4_NV (0x8667)";
+case 0x8668 /* GL_MAP1_VERTEX_ATTRIB8_4_NV */: return "GL_MAP1_VERTEX_ATTRIB8_4_NV (0x8668)";
+case 0x8669 /* GL_MAP1_VERTEX_ATTRIB9_4_NV */: return "GL_MAP1_VERTEX_ATTRIB9_4_NV (0x8669)";
+case 0x866A /* GL_MAP1_VERTEX_ATTRIB10_4_NV */: return "GL_MAP1_VERTEX_ATTRIB10_4_NV (0x866A)";
+case 0x866B /* GL_MAP1_VERTEX_ATTRIB11_4_NV */: return "GL_MAP1_VERTEX_ATTRIB11_4_NV (0x866B)";
+case 0x866C /* GL_MAP1_VERTEX_ATTRIB12_4_NV */: return "GL_MAP1_VERTEX_ATTRIB12_4_NV (0x866C)";
+case 0x866D /* GL_MAP1_VERTEX_ATTRIB13_4_NV */: return "GL_MAP1_VERTEX_ATTRIB13_4_NV (0x866D)";
+case 0x866E /* GL_MAP1_VERTEX_ATTRIB14_4_NV */: return "GL_MAP1_VERTEX_ATTRIB14_4_NV (0x866E)";
+case 0x866F /* GL_MAP1_VERTEX_ATTRIB15_4_NV */: return "GL_MAP1_VERTEX_ATTRIB15_4_NV (0x866F)";
+case 0x8670 /* GL_MAP2_VERTEX_ATTRIB0_4_NV */: return "GL_MAP2_VERTEX_ATTRIB0_4_NV (0x8670)";
+case 0x8671 /* GL_MAP2_VERTEX_ATTRIB1_4_NV */: return "GL_MAP2_VERTEX_ATTRIB1_4_NV (0x8671)";
+case 0x8672 /* GL_MAP2_VERTEX_ATTRIB2_4_NV */: return "GL_MAP2_VERTEX_ATTRIB2_4_NV (0x8672)";
+case 0x8673 /* GL_MAP2_VERTEX_ATTRIB3_4_NV */: return "GL_MAP2_VERTEX_ATTRIB3_4_NV (0x8673)";
+case 0x8674 /* GL_MAP2_VERTEX_ATTRIB4_4_NV */: return "GL_MAP2_VERTEX_ATTRIB4_4_NV (0x8674)";
+case 0x8675 /* GL_MAP2_VERTEX_ATTRIB5_4_NV */: return "GL_MAP2_VERTEX_ATTRIB5_4_NV (0x8675)";
+case 0x8676 /* GL_MAP2_VERTEX_ATTRIB6_4_NV */: return "GL_MAP2_VERTEX_ATTRIB6_4_NV (0x8676)";
+//case 0x8677 /* GL_MAP2_VERTEX_ATTRIB7_4_NV */: return "GL_MAP2_VERTEX_ATTRIB7_4_NV (0x8677)";
+case 0x8678 /* GL_MAP2_VERTEX_ATTRIB8_4_NV */: return "GL_MAP2_VERTEX_ATTRIB8_4_NV (0x8678)";
+case 0x8679 /* GL_MAP2_VERTEX_ATTRIB9_4_NV */: return "GL_MAP2_VERTEX_ATTRIB9_4_NV (0x8679)";
+case 0x867A /* GL_MAP2_VERTEX_ATTRIB10_4_NV */: return "GL_MAP2_VERTEX_ATTRIB10_4_NV (0x867A)";
+case 0x867B /* GL_MAP2_VERTEX_ATTRIB11_4_NV */: return "GL_MAP2_VERTEX_ATTRIB11_4_NV (0x867B)";
+case 0x867C /* GL_MAP2_VERTEX_ATTRIB12_4_NV */: return "GL_MAP2_VERTEX_ATTRIB12_4_NV (0x867C)";
+case 0x867D /* GL_MAP2_VERTEX_ATTRIB13_4_NV */: return "GL_MAP2_VERTEX_ATTRIB13_4_NV (0x867D)";
+case 0x867E /* GL_MAP2_VERTEX_ATTRIB14_4_NV */: return "GL_MAP2_VERTEX_ATTRIB14_4_NV (0x867E)";
+case 0x867F /* GL_MAP2_VERTEX_ATTRIB15_4_NV */: return "GL_MAP2_VERTEX_ATTRIB15_4_NV (0x867F)";
+
+
+
+
+
+/* ------------------------ GL_NV_vertex_program1_1 ------------------------ */
+
+
+
+
+
+
+
+
+/* ------------------------- GL_NV_vertex_program2 ------------------------- */
+
+
+
+
+
+
+
+
+/* ---------------------- GL_NV_vertex_program2_option --------------------- */
+
+
+
+
+//case 0x88F5 /* GL_MAX_PROGRAM_CALL_DEPTH_NV */: return "GL_MAX_PROGRAM_CALL_DEPTH_NV (0x88F5)";
+
+
+
+
+
+/* ------------------------- GL_NV_vertex_program3 ------------------------- */
+/* ------------------------- GL_NV_vertex_program4 ------------------------- */
+
+
+
+
+//case 0x88FD /* GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV */: return "GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV (0x88FD)";
+
+
+
+
+
+/* -------------------------- GL_NV_video_capture -------------------------- */
+
+
+
+
+case 0x9020 /* GL_VIDEO_BUFFER_NV */: return "GL_VIDEO_BUFFER_NV (0x9020)";
+case 0x9021 /* GL_VIDEO_BUFFER_BINDING_NV */: return "GL_VIDEO_BUFFER_BINDING_NV (0x9021)";
+case 0x9022 /* GL_FIELD_UPPER_NV */: return "GL_FIELD_UPPER_NV (0x9022)";
+case 0x9023 /* GL_FIELD_LOWER_NV */: return "GL_FIELD_LOWER_NV (0x9023)";
+case 0x9024 /* GL_NUM_VIDEO_CAPTURE_STREAMS_NV */: return "GL_NUM_VIDEO_CAPTURE_STREAMS_NV (0x9024)";
+case 0x9025 /* GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV */: return "GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV (0x9025)";
+case 0x9026 /* GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV */: return "GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV (0x9026)";
+case 0x9027 /* GL_LAST_VIDEO_CAPTURE_STATUS_NV */: return "GL_LAST_VIDEO_CAPTURE_STATUS_NV (0x9027)";
+case 0x9028 /* GL_VIDEO_BUFFER_PITCH_NV */: return "GL_VIDEO_BUFFER_PITCH_NV (0x9028)";
+case 0x9029 /* GL_VIDEO_COLOR_CONVERSION_MATRIX_NV */: return "GL_VIDEO_COLOR_CONVERSION_MATRIX_NV (0x9029)";
+case 0x902A /* GL_VIDEO_COLOR_CONVERSION_MAX_NV */: return "GL_VIDEO_COLOR_CONVERSION_MAX_NV (0x902A)";
+case 0x902B /* GL_VIDEO_COLOR_CONVERSION_MIN_NV */: return "GL_VIDEO_COLOR_CONVERSION_MIN_NV (0x902B)";
+case 0x902C /* GL_VIDEO_COLOR_CONVERSION_OFFSET_NV */: return "GL_VIDEO_COLOR_CONVERSION_OFFSET_NV (0x902C)";
+case 0x902D /* GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV */: return "GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV (0x902D)";
+case 0x902E /* GL_PARTIAL_SUCCESS_NV */: return "GL_PARTIAL_SUCCESS_NV (0x902E)";
+case 0x902F /* GL_SUCCESS_NV */: return "GL_SUCCESS_NV (0x902F)";
+case 0x9030 /* GL_FAILURE_NV */: return "GL_FAILURE_NV (0x9030)";
+case 0x9031 /* GL_YCBYCR8_422_NV */: return "GL_YCBYCR8_422_NV (0x9031)";
+case 0x9032 /* GL_YCBAYCR8A_4224_NV */: return "GL_YCBAYCR8A_4224_NV (0x9032)";
+case 0x9033 /* GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV */: return "GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV (0x9033)";
+case 0x9034 /* GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV */: return "GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV (0x9034)";
+case 0x9035 /* GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV */: return "GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV (0x9035)";
+case 0x9036 /* GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV */: return "GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV (0x9036)";
+case 0x9037 /* GL_Z4Y12Z4CB12Z4CR12_444_NV */: return "GL_Z4Y12Z4CB12Z4CR12_444_NV (0x9037)";
+case 0x9038 /* GL_VIDEO_CAPTURE_FRAME_WIDTH_NV */: return "GL_VIDEO_CAPTURE_FRAME_WIDTH_NV (0x9038)";
+case 0x9039 /* GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV */: return "GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV (0x9039)";
+case 0x903A /* GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV */: return "GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV (0x903A)";
+case 0x903B /* GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV */: return "GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV (0x903B)";
+case 0x903C /* GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV */: return "GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV (0x903C)";
+
+/* ------------------------ GL_OES_byte_coordinates ------------------------ */
+
+
+
+
+//case 0x1400 /* GL_BYTE */: return "GL_BYTE (0x1400)";
+
+
+
+
+
+/* ------------------- GL_OES_compressed_paletted_texture ------------------ */
+
+
+
+
+case 0x8B90 /* GL_PALETTE4_RGB8_OES */: return "GL_PALETTE4_RGB8_OES (0x8B90)";
+case 0x8B91 /* GL_PALETTE4_RGBA8_OES */: return "GL_PALETTE4_RGBA8_OES (0x8B91)";
+case 0x8B92 /* GL_PALETTE4_R5_G6_B5_OES */: return "GL_PALETTE4_R5_G6_B5_OES (0x8B92)";
+case 0x8B93 /* GL_PALETTE4_RGBA4_OES */: return "GL_PALETTE4_RGBA4_OES (0x8B93)";
+case 0x8B94 /* GL_PALETTE4_RGB5_A1_OES */: return "GL_PALETTE4_RGB5_A1_OES (0x8B94)";
+case 0x8B95 /* GL_PALETTE8_RGB8_OES */: return "GL_PALETTE8_RGB8_OES (0x8B95)";
+case 0x8B96 /* GL_PALETTE8_RGBA8_OES */: return "GL_PALETTE8_RGBA8_OES (0x8B96)";
+case 0x8B97 /* GL_PALETTE8_R5_G6_B5_OES */: return "GL_PALETTE8_R5_G6_B5_OES (0x8B97)";
+case 0x8B98 /* GL_PALETTE8_RGBA4_OES */: return "GL_PALETTE8_RGBA4_OES (0x8B98)";
+case 0x8B99 /* GL_PALETTE8_RGB5_A1_OES */: return "GL_PALETTE8_RGB5_A1_OES (0x8B99)";
+
+
+
+
+
+/* --------------------------- GL_OES_read_format -------------------------- */
+
+
+
+
+//case 0x8B9A /* GL_IMPLEMENTATION_COLOR_READ_TYPE_OES */: return "GL_IMPLEMENTATION_COLOR_READ_TYPE_OES (0x8B9A)";
+//case 0x8B9B /* GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES */: return "GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES (0x8B9B)";
+
+
+
+
+
+/* ------------------------ GL_OES_single_precision ------------------------ */
+
+
+/* ---------------------------- GL_OML_interlace --------------------------- */
+
+
+
+
+case 0x8980 /* GL_INTERLACE_OML */: return "GL_INTERLACE_OML (0x8980)";
+case 0x8981 /* GL_INTERLACE_READ_OML */: return "GL_INTERLACE_READ_OML (0x8981)";
+
+
+
+
+
+/* ---------------------------- GL_OML_resample ---------------------------- */
+
+
+
+
+case 0x8984 /* GL_PACK_RESAMPLE_OML */: return "GL_PACK_RESAMPLE_OML (0x8984)";
+case 0x8985 /* GL_UNPACK_RESAMPLE_OML */: return "GL_UNPACK_RESAMPLE_OML (0x8985)";
+case 0x8986 /* GL_RESAMPLE_REPLICATE_OML */: return "GL_RESAMPLE_REPLICATE_OML (0x8986)";
+case 0x8987 /* GL_RESAMPLE_ZERO_FILL_OML */: return "GL_RESAMPLE_ZERO_FILL_OML (0x8987)";
+case 0x8988 /* GL_RESAMPLE_AVERAGE_OML */: return "GL_RESAMPLE_AVERAGE_OML (0x8988)";
+case 0x8989 /* GL_RESAMPLE_DECIMATE_OML */: return "GL_RESAMPLE_DECIMATE_OML (0x8989)";
+
+
+
+
+
+/* ---------------------------- GL_OML_subsample --------------------------- */
+
+
+
+
+case 0x8982 /* GL_FORMAT_SUBSAMPLE_24_24_OML */: return "GL_FORMAT_SUBSAMPLE_24_24_OML (0x8982)";
+case 0x8983 /* GL_FORMAT_SUBSAMPLE_244_244_OML */: return "GL_FORMAT_SUBSAMPLE_244_244_OML (0x8983)";
+
+
+
+
+
+/* --------------------------- GL_PGI_misc_hints --------------------------- *//* -------------------------- GL_PGI_vertex_hints -------------------------- */
+
+
+
+
+//case 0x00000004 /* GL_VERTEX23_BIT_PGI */: return "GL_VERTEX23_BIT_PGI (0x00000004)";
+//case 0x00000008 /* GL_VERTEX4_BIT_PGI */: return "GL_VERTEX4_BIT_PGI (0x00000008)";
+//case 0x00010000 /* GL_COLOR3_BIT_PGI */: return "GL_COLOR3_BIT_PGI (0x00010000)";
+//case 0x00020000 /* GL_COLOR4_BIT_PGI */: return "GL_COLOR4_BIT_PGI (0x00020000)";
+//case 0x00040000 /* GL_EDGEFLAG_BIT_PGI */: return "GL_EDGEFLAG_BIT_PGI (0x00040000)";
+//case 0x00080000 /* GL_INDEX_BIT_PGI */: return "GL_INDEX_BIT_PGI (0x00080000)";
+//case 0x00100000 /* GL_MAT_AMBIENT_BIT_PGI */: return "GL_MAT_AMBIENT_BIT_PGI (0x00100000)";
+
+
+
+
+//case 0x00200000 /* GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI */: return "GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI (0x00200000)";
+//case 0x00400000 /* GL_MAT_DIFFUSE_BIT_PGI */: return "GL_MAT_DIFFUSE_BIT_PGI (0x00400000)";
+//case 0x00800000 /* GL_MAT_EMISSION_BIT_PGI */: return "GL_MAT_EMISSION_BIT_PGI (0x00800000)";
+//case 0x01000000 /* GL_MAT_COLOR_INDEXES_BIT_PGI */: return "GL_MAT_COLOR_INDEXES_BIT_PGI (0x01000000)";
+//case 0x02000000 /* GL_MAT_SHININESS_BIT_PGI */: return "GL_MAT_SHININESS_BIT_PGI (0x02000000)";
+//case 0x04000000 /* GL_MAT_SPECULAR_BIT_PGI */: return "GL_MAT_SPECULAR_BIT_PGI (0x04000000)";
+//case 0x08000000 /* GL_NORMAL_BIT_PGI */: return "GL_NORMAL_BIT_PGI (0x08000000)";
+//case 0x10000000 /* GL_TEXCOORD1_BIT_PGI */: return "GL_TEXCOORD1_BIT_PGI (0x10000000)";
+//case 0x20000000 /* GL_TEXCOORD2_BIT_PGI */: return "GL_TEXCOORD2_BIT_PGI (0x20000000)";
+case 0x40000000 /* GL_TEXCOORD3_BIT_PGI */: return "GL_TEXCOORD3_BIT_PGI (0x40000000)";
+case 0x80000000 /* GL_TEXCOORD4_BIT_PGI */: return "GL_TEXCOORD4_BIT_PGI (0x80000000)";
+
+
+
+
+
+/* ------------------------- GL_REGAL_error_string ------------------------- */
+
+
+/* ------------------------ GL_REGAL_extension_query ----------------------- */
+
+
+
+
+/* ------------------------------ GL_REGAL_log ----------------------------- */
+
+
+
+
+case 0x9319 /* GL_LOG_ERROR_REGAL */: return "GL_LOG_ERROR_REGAL (0x9319)";
+case 0x931A /* GL_LOG_WARNING_REGAL */: return "GL_LOG_WARNING_REGAL (0x931A)";
+case 0x931B /* GL_LOG_INFO_REGAL */: return "GL_LOG_INFO_REGAL (0x931B)";
+case 0x931C /* GL_LOG_APP_REGAL */: return "GL_LOG_APP_REGAL (0x931C)";
+case 0x931D /* GL_LOG_DRIVER_REGAL */: return "GL_LOG_DRIVER_REGAL (0x931D)";
+case 0x931E /* GL_LOG_INTERNAL_REGAL */: return "GL_LOG_INTERNAL_REGAL (0x931E)";
+case 0x931F /* GL_LOG_DEBUG_REGAL */: return "GL_LOG_DEBUG_REGAL (0x931F)";
+case 0x9320 /* GL_LOG_STATUS_REGAL */: return "GL_LOG_STATUS_REGAL (0x9320)";
+case 0x9321 /* GL_LOG_HTTP_REGAL */: return "GL_LOG_HTTP_REGAL (0x9321)";
+
+
+
+
+
+/* ----------------------- GL_REND_screen_coordinates ---------------------- */
+
+
+
+
+case 0x8490 /* GL_SCREEN_COORDINATES_REND */: return "GL_SCREEN_COORDINATES_REND (0x8490)";
+case 0x8491 /* GL_INVERTED_SCREEN_W_REND */: return "GL_INVERTED_SCREEN_W_REND (0x8491)";
+
+
+
+
+
+/* ------------------------------- GL_S3_s3tc ------------------------------ */
+
+
+
+
+case 0x83A0 /* GL_RGB_S3TC */: return "GL_RGB_S3TC (0x83A0)";
+case 0x83A1 /* GL_RGB4_S3TC */: return "GL_RGB4_S3TC (0x83A1)";
+case 0x83A2 /* GL_RGBA_S3TC */: return "GL_RGBA_S3TC (0x83A2)";
+case 0x83A3 /* GL_RGBA4_S3TC */: return "GL_RGBA4_S3TC (0x83A3)";
+case 0x83A4 /* GL_RGBA_DXT5_S3TC */: return "GL_RGBA_DXT5_S3TC (0x83A4)";
+case 0x83A5 /* GL_RGBA4_DXT5_S3TC */: return "GL_RGBA4_DXT5_S3TC (0x83A5)";
+
+
+
+
+
+/* -------------------------- GL_SGIS_color_range -------------------------- */
+
+
+
+
+case 0x85A5 /* GL_EXTENDED_RANGE_SGIS */: return "GL_EXTENDED_RANGE_SGIS (0x85A5)";
+case 0x85A6 /* GL_MIN_RED_SGIS */: return "GL_MIN_RED_SGIS (0x85A6)";
+case 0x85A7 /* GL_MAX_RED_SGIS */: return "GL_MAX_RED_SGIS (0x85A7)";
+case 0x85A8 /* GL_MIN_GREEN_SGIS */: return "GL_MIN_GREEN_SGIS (0x85A8)";
+case 0x85A9 /* GL_MAX_GREEN_SGIS */: return "GL_MAX_GREEN_SGIS (0x85A9)";
+case 0x85AA /* GL_MIN_BLUE_SGIS */: return "GL_MIN_BLUE_SGIS (0x85AA)";
+case 0x85AB /* GL_MAX_BLUE_SGIS */: return "GL_MAX_BLUE_SGIS (0x85AB)";
+case 0x85AC /* GL_MIN_ALPHA_SGIS */: return "GL_MIN_ALPHA_SGIS (0x85AC)";
+case 0x85AD /* GL_MAX_ALPHA_SGIS */: return "GL_MAX_ALPHA_SGIS (0x85AD)";
+
+
+
+
+
+/* ------------------------- GL_SGIS_detail_texture ------------------------ */
+
+
+
+
+/* -------------------------- GL_SGIS_fog_function ------------------------- */
+
+
+
+
+/* ------------------------ GL_SGIS_generate_mipmap ------------------------ */
+
+
+
+
+//case 0x8191 /* GL_GENERATE_MIPMAP_SGIS */: return "GL_GENERATE_MIPMAP_SGIS (0x8191)";
+//case 0x8192 /* GL_GENERATE_MIPMAP_HINT_SGIS */: return "GL_GENERATE_MIPMAP_HINT_SGIS (0x8192)";
+
+
+
+
+
+/* -------------------------- GL_SGIS_multisample -------------------------- */
+
+
+
+
+//case 0x809D /* GL_MULTISAMPLE_SGIS */: return "GL_MULTISAMPLE_SGIS (0x809D)";
+//case 0x809E /* GL_SAMPLE_ALPHA_TO_MASK_SGIS */: return "GL_SAMPLE_ALPHA_TO_MASK_SGIS (0x809E)";
+//case 0x809F /* GL_SAMPLE_ALPHA_TO_ONE_SGIS */: return "GL_SAMPLE_ALPHA_TO_ONE_SGIS (0x809F)";
+//case 0x80A0 /* GL_SAMPLE_MASK_SGIS */: return "GL_SAMPLE_MASK_SGIS (0x80A0)";
+//case 0x80A1 /* GL_1PASS_SGIS */: return "GL_1PASS_SGIS (0x80A1)";
+//case 0x80A2 /* GL_2PASS_0_SGIS */: return "GL_2PASS_0_SGIS (0x80A2)";
+//case 0x80A3 /* GL_2PASS_1_SGIS */: return "GL_2PASS_1_SGIS (0x80A3)";
+//case 0x80A4 /* GL_4PASS_0_SGIS */: return "GL_4PASS_0_SGIS (0x80A4)";
+//case 0x80A5 /* GL_4PASS_1_SGIS */: return "GL_4PASS_1_SGIS (0x80A5)";
+//case 0x80A6 /* GL_4PASS_2_SGIS */: return "GL_4PASS_2_SGIS (0x80A6)";
+//case 0x80A7 /* GL_4PASS_3_SGIS */: return "GL_4PASS_3_SGIS (0x80A7)";
+//case 0x80A8 /* GL_SAMPLE_BUFFERS_SGIS */: return "GL_SAMPLE_BUFFERS_SGIS (0x80A8)";
+//case 0x80A9 /* GL_SAMPLES_SGIS */: return "GL_SAMPLES_SGIS (0x80A9)";
+//case 0x80AA /* GL_SAMPLE_MASK_VALUE_SGIS */: return "GL_SAMPLE_MASK_VALUE_SGIS (0x80AA)";
+//case 0x80AB /* GL_SAMPLE_MASK_INVERT_SGIS */: return "GL_SAMPLE_MASK_INVERT_SGIS (0x80AB)";
+//case 0x80AC /* GL_SAMPLE_PATTERN_SGIS */: return "GL_SAMPLE_PATTERN_SGIS (0x80AC)";
+
+/* ------------------------- GL_SGIS_pixel_texture ------------------------- */
+
+
+
+
+
+
+
+
+/* ----------------------- GL_SGIS_point_line_texgen ----------------------- */
+
+
+
+
+case 0x81F0 /* GL_EYE_DISTANCE_TO_POINT_SGIS */: return "GL_EYE_DISTANCE_TO_POINT_SGIS (0x81F0)";
+case 0x81F1 /* GL_OBJECT_DISTANCE_TO_POINT_SGIS */: return "GL_OBJECT_DISTANCE_TO_POINT_SGIS (0x81F1)";
+case 0x81F2 /* GL_EYE_DISTANCE_TO_LINE_SGIS */: return "GL_EYE_DISTANCE_TO_LINE_SGIS (0x81F2)";
+case 0x81F3 /* GL_OBJECT_DISTANCE_TO_LINE_SGIS */: return "GL_OBJECT_DISTANCE_TO_LINE_SGIS (0x81F3)";
+case 0x81F4 /* GL_EYE_POINT_SGIS */: return "GL_EYE_POINT_SGIS (0x81F4)";
+case 0x81F5 /* GL_OBJECT_POINT_SGIS */: return "GL_OBJECT_POINT_SGIS (0x81F5)";
+case 0x81F6 /* GL_EYE_LINE_SGIS */: return "GL_EYE_LINE_SGIS (0x81F6)";
+case 0x81F7 /* GL_OBJECT_LINE_SGIS */: return "GL_OBJECT_LINE_SGIS (0x81F7)";
+
+
+
+
+
+/* ------------------------ GL_SGIS_sharpen_texture ------------------------ */
+
+
+
+
+/* --------------------------- GL_SGIS_texture4D --------------------------- */
+
+
+
+
+/* ---------------------- GL_SGIS_texture_border_clamp --------------------- */
+
+
+
+
+//case 0x812D /* GL_CLAMP_TO_BORDER_SGIS */: return "GL_CLAMP_TO_BORDER_SGIS (0x812D)";
+
+
+
+
+
+/* ----------------------- GL_SGIS_texture_edge_clamp ---------------------- */
+
+
+
+
+//case 0x812F /* GL_CLAMP_TO_EDGE_SGIS */: return "GL_CLAMP_TO_EDGE_SGIS (0x812F)";
+
+
+
+
+
+/* ------------------------ GL_SGIS_texture_filter4 ------------------------ */
+
+
+
+
+/* -------------------------- GL_SGIS_texture_lod -------------------------- */
+
+
+
+
+//case 0x813A /* GL_TEXTURE_MIN_LOD_SGIS */: return "GL_TEXTURE_MIN_LOD_SGIS (0x813A)";
+//case 0x813B /* GL_TEXTURE_MAX_LOD_SGIS */: return "GL_TEXTURE_MAX_LOD_SGIS (0x813B)";
+//case 0x813C /* GL_TEXTURE_BASE_LEVEL_SGIS */: return "GL_TEXTURE_BASE_LEVEL_SGIS (0x813C)";
+//case 0x813D /* GL_TEXTURE_MAX_LEVEL_SGIS */: return "GL_TEXTURE_MAX_LEVEL_SGIS (0x813D)";
+
+
+
+
+
+/* ------------------------- GL_SGIS_texture_select ------------------------ */
+
+
+
+
+
+
+
+
+/* ----------------------------- GL_SGIX_async ----------------------------- */
+
+
+
+
+case 0x8329 /* GL_ASYNC_MARKER_SGIX */: return "GL_ASYNC_MARKER_SGIX (0x8329)";
+
+/* ------------------------ GL_SGIX_async_histogram ------------------------ */
+
+
+
+
+case 0x832C /* GL_ASYNC_HISTOGRAM_SGIX */: return "GL_ASYNC_HISTOGRAM_SGIX (0x832C)";
+case 0x832D /* GL_MAX_ASYNC_HISTOGRAM_SGIX */: return "GL_MAX_ASYNC_HISTOGRAM_SGIX (0x832D)";
+
+
+
+
+
+/* -------------------------- GL_SGIX_async_pixel -------------------------- */
+
+
+
+
+case 0x835C /* GL_ASYNC_TEX_IMAGE_SGIX */: return "GL_ASYNC_TEX_IMAGE_SGIX (0x835C)";
+case 0x835D /* GL_ASYNC_DRAW_PIXELS_SGIX */: return "GL_ASYNC_DRAW_PIXELS_SGIX (0x835D)";
+case 0x835E /* GL_ASYNC_READ_PIXELS_SGIX */: return "GL_ASYNC_READ_PIXELS_SGIX (0x835E)";
+case 0x835F /* GL_MAX_ASYNC_TEX_IMAGE_SGIX */: return "GL_MAX_ASYNC_TEX_IMAGE_SGIX (0x835F)";
+case 0x8360 /* GL_MAX_ASYNC_DRAW_PIXELS_SGIX */: return "GL_MAX_ASYNC_DRAW_PIXELS_SGIX (0x8360)";
+case 0x8361 /* GL_MAX_ASYNC_READ_PIXELS_SGIX */: return "GL_MAX_ASYNC_READ_PIXELS_SGIX (0x8361)";
+
+
+
+
+
+/* ----------------------- GL_SGIX_blend_alpha_minmax ---------------------- */
+
+
+
+
+case 0x8320 /* GL_ALPHA_MIN_SGIX */: return "GL_ALPHA_MIN_SGIX (0x8320)";
+case 0x8321 /* GL_ALPHA_MAX_SGIX */: return "GL_ALPHA_MAX_SGIX (0x8321)";
+
+
+
+
+
+/* ---------------------------- GL_SGIX_clipmap ---------------------------- */
+
+
+
+
+
+
+
+
+/* ---------------------- GL_SGIX_convolution_accuracy --------------------- */
+
+
+
+
+case 0x8316 /* GL_CONVOLUTION_HINT_SGIX */: return "GL_CONVOLUTION_HINT_SGIX (0x8316)";
+
+
+
+
+
+/* ------------------------- GL_SGIX_depth_texture ------------------------- */
+
+
+
+
+//case 0x81A5 /* GL_DEPTH_COMPONENT16_SGIX */: return "GL_DEPTH_COMPONENT16_SGIX (0x81A5)";
+//case 0x81A6 /* GL_DEPTH_COMPONENT24_SGIX */: return "GL_DEPTH_COMPONENT24_SGIX (0x81A6)";
+//case 0x81A7 /* GL_DEPTH_COMPONENT32_SGIX */: return "GL_DEPTH_COMPONENT32_SGIX (0x81A7)";
+
+
+
+
+
+/* -------------------------- GL_SGIX_flush_raster ------------------------- */
+
+
+/* --------------------------- GL_SGIX_fog_offset -------------------------- */
+
+
+
+
+case 0x8198 /* GL_FOG_OFFSET_SGIX */: return "GL_FOG_OFFSET_SGIX (0x8198)";
+case 0x8199 /* GL_FOG_OFFSET_VALUE_SGIX */: return "GL_FOG_OFFSET_VALUE_SGIX (0x8199)";
+
+
+
+
+
+/* -------------------------- GL_SGIX_fog_texture -------------------------- */
+
+
+
+
+
+
+/* ------------------- GL_SGIX_fragment_specular_lighting ------------------ */
+
+
+
+
+/* --------------------------- GL_SGIX_framezoom --------------------------- */
+
+
+/* --------------------------- GL_SGIX_interlace --------------------------- */
+
+
+
+
+case 0x8094 /* GL_INTERLACE_SGIX */: return "GL_INTERLACE_SGIX (0x8094)";
+
+
+
+
+
+/* ------------------------- GL_SGIX_ir_instrument1 ------------------------ */
+
+
+
+
+
+
+
+
+/* ------------------------- GL_SGIX_list_priority ------------------------- */
+
+
+
+
+
+
+
+
+/* ------------------------- GL_SGIX_pixel_texture ------------------------- */
+
+
+/* ----------------------- GL_SGIX_pixel_texture_bits ---------------------- */
+
+
+
+
+
+
+
+
+/* ------------------------ GL_SGIX_reference_plane ------------------------ */
+
+
+/* ---------------------------- GL_SGIX_resample --------------------------- */
+
+
+
+
+case 0x842E /* GL_PACK_RESAMPLE_SGIX */: return "GL_PACK_RESAMPLE_SGIX (0x842E)";
+case 0x842F /* GL_UNPACK_RESAMPLE_SGIX */: return "GL_UNPACK_RESAMPLE_SGIX (0x842F)";
+case 0x8430 /* GL_RESAMPLE_DECIMATE_SGIX */: return "GL_RESAMPLE_DECIMATE_SGIX (0x8430)";
+case 0x8433 /* GL_RESAMPLE_REPLICATE_SGIX */: return "GL_RESAMPLE_REPLICATE_SGIX (0x8433)";
+case 0x8434 /* GL_RESAMPLE_ZERO_FILL_SGIX */: return "GL_RESAMPLE_ZERO_FILL_SGIX (0x8434)";
+
+
+
+
+
+/* ----------------------------- GL_SGIX_shadow ---------------------------- */
+
+
+
+
+case 0x819A /* GL_TEXTURE_COMPARE_SGIX */: return "GL_TEXTURE_COMPARE_SGIX (0x819A)";
+case 0x819B /* GL_TEXTURE_COMPARE_OPERATOR_SGIX */: return "GL_TEXTURE_COMPARE_OPERATOR_SGIX (0x819B)";
+case 0x819C /* GL_TEXTURE_LEQUAL_R_SGIX */: return "GL_TEXTURE_LEQUAL_R_SGIX (0x819C)";
+case 0x819D /* GL_TEXTURE_GEQUAL_R_SGIX */: return "GL_TEXTURE_GEQUAL_R_SGIX (0x819D)";
+
+
+
+
+
+/* ------------------------- GL_SGIX_shadow_ambient ------------------------ */
+
+
+
+
+//case 0x80BF /* GL_SHADOW_AMBIENT_SGIX */: return "GL_SHADOW_AMBIENT_SGIX (0x80BF)";
+
+
+
+
+
+/* ----------------------------- GL_SGIX_sprite ---------------------------- */
+
+
+
+
+
+
+
+
+/* ----------------------- GL_SGIX_tag_sample_buffer ----------------------- */
+
+
+/* ------------------------ GL_SGIX_texture_add_env ------------------------ */
+
+
+
+
+
+
+
+
+/* -------------------- GL_SGIX_texture_coordinate_clamp ------------------- */
+
+
+
+
+case 0x8369 /* GL_TEXTURE_MAX_CLAMP_S_SGIX */: return "GL_TEXTURE_MAX_CLAMP_S_SGIX (0x8369)";
+case 0x836A /* GL_TEXTURE_MAX_CLAMP_T_SGIX */: return "GL_TEXTURE_MAX_CLAMP_T_SGIX (0x836A)";
+case 0x836B /* GL_TEXTURE_MAX_CLAMP_R_SGIX */: return "GL_TEXTURE_MAX_CLAMP_R_SGIX (0x836B)";
+
+
+
+
+
+/* ------------------------ GL_SGIX_texture_lod_bias ----------------------- */
+
+
+
+
+
+
+
+
+/* ---------------------- GL_SGIX_texture_multi_buffer --------------------- */
+
+
+
+
+case 0x812E /* GL_TEXTURE_MULTI_BUFFER_HINT_SGIX */: return "GL_TEXTURE_MULTI_BUFFER_HINT_SGIX (0x812E)";
+
+
+
+
+
+/* ------------------------- GL_SGIX_texture_range ------------------------- */
+
+
+
+
+case 0x85E0 /* GL_RGB_SIGNED_SGIX */: return "GL_RGB_SIGNED_SGIX (0x85E0)";
+case 0x85E1 /* GL_RGBA_SIGNED_SGIX */: return "GL_RGBA_SIGNED_SGIX (0x85E1)";
+case 0x85E2 /* GL_ALPHA_SIGNED_SGIX */: return "GL_ALPHA_SIGNED_SGIX (0x85E2)";
+case 0x85E3 /* GL_LUMINANCE_SIGNED_SGIX */: return "GL_LUMINANCE_SIGNED_SGIX (0x85E3)";
+case 0x85E4 /* GL_INTENSITY_SIGNED_SGIX */: return "GL_INTENSITY_SIGNED_SGIX (0x85E4)";
+case 0x85E5 /* GL_LUMINANCE_ALPHA_SIGNED_SGIX */: return "GL_LUMINANCE_ALPHA_SIGNED_SGIX (0x85E5)";
+case 0x85E6 /* GL_RGB16_SIGNED_SGIX */: return "GL_RGB16_SIGNED_SGIX (0x85E6)";
+case 0x85E7 /* GL_RGBA16_SIGNED_SGIX */: return "GL_RGBA16_SIGNED_SGIX (0x85E7)";
+case 0x85E8 /* GL_ALPHA16_SIGNED_SGIX */: return "GL_ALPHA16_SIGNED_SGIX (0x85E8)";
+case 0x85E9 /* GL_LUMINANCE16_SIGNED_SGIX */: return "GL_LUMINANCE16_SIGNED_SGIX (0x85E9)";
+case 0x85EA /* GL_INTENSITY16_SIGNED_SGIX */: return "GL_INTENSITY16_SIGNED_SGIX (0x85EA)";
+case 0x85EB /* GL_LUMINANCE16_ALPHA16_SIGNED_SGIX */: return "GL_LUMINANCE16_ALPHA16_SIGNED_SGIX (0x85EB)";
+case 0x85EC /* GL_RGB_EXTENDED_RANGE_SGIX */: return "GL_RGB_EXTENDED_RANGE_SGIX (0x85EC)";
+case 0x85ED /* GL_RGBA_EXTENDED_RANGE_SGIX */: return "GL_RGBA_EXTENDED_RANGE_SGIX (0x85ED)";
+case 0x85EE /* GL_ALPHA_EXTENDED_RANGE_SGIX */: return "GL_ALPHA_EXTENDED_RANGE_SGIX (0x85EE)";
+case 0x85EF /* GL_LUMINANCE_EXTENDED_RANGE_SGIX */: return "GL_LUMINANCE_EXTENDED_RANGE_SGIX (0x85EF)";
+case 0x85F0 /* GL_INTENSITY_EXTENDED_RANGE_SGIX */: return "GL_INTENSITY_EXTENDED_RANGE_SGIX (0x85F0)";
+case 0x85F1 /* GL_LUMINANCE_ALPHA_EXTENDED_RANGE_SGIX */: return "GL_LUMINANCE_ALPHA_EXTENDED_RANGE_SGIX (0x85F1)";
+case 0x85F2 /* GL_RGB16_EXTENDED_RANGE_SGIX */: return "GL_RGB16_EXTENDED_RANGE_SGIX (0x85F2)";
+case 0x85F3 /* GL_RGBA16_EXTENDED_RANGE_SGIX */: return "GL_RGBA16_EXTENDED_RANGE_SGIX (0x85F3)";
+case 0x85F4 /* GL_ALPHA16_EXTENDED_RANGE_SGIX */: return "GL_ALPHA16_EXTENDED_RANGE_SGIX (0x85F4)";
+case 0x85F5 /* GL_LUMINANCE16_EXTENDED_RANGE_SGIX */: return "GL_LUMINANCE16_EXTENDED_RANGE_SGIX (0x85F5)";
+case 0x85F6 /* GL_INTENSITY16_EXTENDED_RANGE_SGIX */: return "GL_INTENSITY16_EXTENDED_RANGE_SGIX (0x85F6)";
+case 0x85F7 /* GL_LUMINANCE16_ALPHA16_EXTENDED_RANGE_SGIX */: return "GL_LUMINANCE16_ALPHA16_EXTENDED_RANGE_SGIX (0x85F7)";
+case 0x85F8 /* GL_MIN_LUMINANCE_SGIS */: return "GL_MIN_LUMINANCE_SGIS (0x85F8)";
+case 0x85F9 /* GL_MAX_LUMINANCE_SGIS */: return "GL_MAX_LUMINANCE_SGIS (0x85F9)";
+case 0x85FA /* GL_MIN_INTENSITY_SGIS */: return "GL_MIN_INTENSITY_SGIS (0x85FA)";
+case 0x85FB /* GL_MAX_INTENSITY_SGIS */: return "GL_MAX_INTENSITY_SGIS (0x85FB)";
+
+
+
+
+
+/* ----------------------- GL_SGIX_texture_scale_bias ---------------------- */
+
+
+
+
+case 0x8179 /* GL_POST_TEXTURE_FILTER_BIAS_SGIX */: return "GL_POST_TEXTURE_FILTER_BIAS_SGIX (0x8179)";
+case 0x817A /* GL_POST_TEXTURE_FILTER_SCALE_SGIX */: return "GL_POST_TEXTURE_FILTER_SCALE_SGIX (0x817A)";
+case 0x817B /* GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX */: return "GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX (0x817B)";
+case 0x817C /* GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX */: return "GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX (0x817C)";
+
+
+
+
+
+/* ------------------------- GL_SGIX_vertex_preclip ------------------------ */
+
+
+
+
+case 0x83EE /* GL_VERTEX_PRECLIP_SGIX */: return "GL_VERTEX_PRECLIP_SGIX (0x83EE)";
+case 0x83EF /* GL_VERTEX_PRECLIP_HINT_SGIX */: return "GL_VERTEX_PRECLIP_HINT_SGIX (0x83EF)";
+
+
+
+
+
+/* ---------------------- GL_SGIX_vertex_preclip_hint ---------------------- */
+
+
+
+
+//case 0x83EE /* GL_VERTEX_PRECLIP_SGIX */: return "GL_VERTEX_PRECLIP_SGIX (0x83EE)";
+//case 0x83EF /* GL_VERTEX_PRECLIP_HINT_SGIX */: return "GL_VERTEX_PRECLIP_HINT_SGIX (0x83EF)";
+
+
+
+
+
+/* ----------------------------- GL_SGIX_ycrcb ----------------------------- */
+
+
+
+
+
+
+
+
+/* -------------------------- GL_SGI_color_matrix -------------------------- */
+
+
+
+
+//case 0x80B1 /* GL_COLOR_MATRIX_SGI */: return "GL_COLOR_MATRIX_SGI (0x80B1)";
+//case 0x80B2 /* GL_COLOR_MATRIX_STACK_DEPTH_SGI */: return "GL_COLOR_MATRIX_STACK_DEPTH_SGI (0x80B2)";
+//case 0x80B3 /* GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI */: return "GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI (0x80B3)";
+//case 0x80B4 /* GL_POST_COLOR_MATRIX_RED_SCALE_SGI */: return "GL_POST_COLOR_MATRIX_RED_SCALE_SGI (0x80B4)";
+//case 0x80B5 /* GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI */: return "GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI (0x80B5)";
+//case 0x80B6 /* GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI */: return "GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI (0x80B6)";
+//case 0x80B7 /* GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI */: return "GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI (0x80B7)";
+//case 0x80B8 /* GL_POST_COLOR_MATRIX_RED_BIAS_SGI */: return "GL_POST_COLOR_MATRIX_RED_BIAS_SGI (0x80B8)";
+//case 0x80B9 /* GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI */: return "GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI (0x80B9)";
+//case 0x80BA /* GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI */: return "GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI (0x80BA)";
+//case 0x80BB /* GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI */: return "GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI (0x80BB)";
+
+
+
+
+
+/* --------------------------- GL_SGI_color_table -------------------------- */
+
+
+
+
+//case 0x80D0 /* GL_COLOR_TABLE_SGI */: return "GL_COLOR_TABLE_SGI (0x80D0)";
+//case 0x80D1 /* GL_POST_CONVOLUTION_COLOR_TABLE_SGI */: return "GL_POST_CONVOLUTION_COLOR_TABLE_SGI (0x80D1)";
+//case 0x80D2 /* GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI */: return "GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI (0x80D2)";
+//case 0x80D3 /* GL_PROXY_COLOR_TABLE_SGI */: return "GL_PROXY_COLOR_TABLE_SGI (0x80D3)";
+//case 0x80D4 /* GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI */: return "GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI (0x80D4)";
+//case 0x80D5 /* GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI */: return "GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI (0x80D5)";
+//case 0x80D6 /* GL_COLOR_TABLE_SCALE_SGI */: return "GL_COLOR_TABLE_SCALE_SGI (0x80D6)";
+//case 0x80D7 /* GL_COLOR_TABLE_BIAS_SGI */: return "GL_COLOR_TABLE_BIAS_SGI (0x80D7)";
+//case 0x80D8 /* GL_COLOR_TABLE_FORMAT_SGI */: return "GL_COLOR_TABLE_FORMAT_SGI (0x80D8)";
+//case 0x80D9 /* GL_COLOR_TABLE_WIDTH_SGI */: return "GL_COLOR_TABLE_WIDTH_SGI (0x80D9)";
+//case 0x80DA /* GL_COLOR_TABLE_RED_SIZE_SGI */: return "GL_COLOR_TABLE_RED_SIZE_SGI (0x80DA)";
+//case 0x80DB /* GL_COLOR_TABLE_GREEN_SIZE_SGI */: return "GL_COLOR_TABLE_GREEN_SIZE_SGI (0x80DB)";
+//case 0x80DC /* GL_COLOR_TABLE_BLUE_SIZE_SGI */: return "GL_COLOR_TABLE_BLUE_SIZE_SGI (0x80DC)";
+//case 0x80DD /* GL_COLOR_TABLE_ALPHA_SIZE_SGI */: return "GL_COLOR_TABLE_ALPHA_SIZE_SGI (0x80DD)";
+//case 0x80DE /* GL_COLOR_TABLE_LUMINANCE_SIZE_SGI */: return "GL_COLOR_TABLE_LUMINANCE_SIZE_SGI (0x80DE)";
+//case 0x80DF /* GL_COLOR_TABLE_INTENSITY_SIZE_SGI */: return "GL_COLOR_TABLE_INTENSITY_SIZE_SGI (0x80DF)";
+
+/* ----------------------- GL_SGI_texture_color_table ---------------------- */
+
+
+
+
+case 0x80BC /* GL_TEXTURE_COLOR_TABLE_SGI */: return "GL_TEXTURE_COLOR_TABLE_SGI (0x80BC)";
+case 0x80BD /* GL_PROXY_TEXTURE_COLOR_TABLE_SGI */: return "GL_PROXY_TEXTURE_COLOR_TABLE_SGI (0x80BD)";
+
+
+
+
+
+/* ------------------------- GL_SUNX_constant_data ------------------------- */
+
+
+
+
+case 0x81D5 /* GL_UNPACK_CONSTANT_DATA_SUNX */: return "GL_UNPACK_CONSTANT_DATA_SUNX (0x81D5)";
+case 0x81D6 /* GL_TEXTURE_CONSTANT_DATA_SUNX */: return "GL_TEXTURE_CONSTANT_DATA_SUNX (0x81D6)";/* -------------------- GL_SUN_convolution_border_modes -------------------- */
+
+
+
+
+case 0x81D4 /* GL_WRAP_BORDER_SUN */: return "GL_WRAP_BORDER_SUN (0x81D4)";
+
+
+
+
+
+/* -------------------------- GL_SUN_global_alpha -------------------------- */
+
+
+
+
+case 0x81D9 /* GL_GLOBAL_ALPHA_SUN */: return "GL_GLOBAL_ALPHA_SUN (0x81D9)";
+case 0x81DA /* GL_GLOBAL_ALPHA_FACTOR_SUN */: return "GL_GLOBAL_ALPHA_FACTOR_SUN (0x81DA)";
+
+
+
+/* --------------------------- GL_SUN_mesh_array --------------------------- */
+
+
+
+
+case 0x8614 /* GL_QUAD_MESH_SUN */: return "GL_QUAD_MESH_SUN (0x8614)";
+case 0x8615 /* GL_TRIANGLE_MESH_SUN */: return "GL_TRIANGLE_MESH_SUN (0x8615)";
+
+
+
+
+
+/* ------------------------ GL_SUN_read_video_pixels ----------------------- */
+
+
+/* --------------------------- GL_SUN_slice_accum -------------------------- */
+
+
+
+
+case 0x85CC /* GL_SLICE_ACCUM_SUN */: return "GL_SLICE_ACCUM_SUN (0x85CC)";
+
+
+
+
+
+/* -------------------------- GL_SUN_triangle_list ------------------------- */
+
+
+
+
+//case 0x01 /* GL_RESTART_SUN */: return "GL_RESTART_SUN (0x01)";
+//case 0x02 /* GL_REPLACE_MIDDLE_SUN */: return "GL_REPLACE_MIDDLE_SUN (0x02)";
+//case 0x03 /* GL_REPLACE_OLDEST_SUN */: return "GL_REPLACE_OLDEST_SUN (0x03)";
+case 0x81D7 /* GL_TRIANGLE_LIST_SUN */: return "GL_TRIANGLE_LIST_SUN (0x81D7)";
+case 0x81D8 /* GL_REPLACEMENT_CODE_SUN */: return "GL_REPLACEMENT_CODE_SUN (0x81D8)";
+case 0x85C0 /* GL_REPLACEMENT_CODE_ARRAY_SUN */: return "GL_REPLACEMENT_CODE_ARRAY_SUN (0x85C0)";
+case 0x85C1 /* GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN */: return "GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN (0x85C1)";
+case 0x85C2 /* GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN */: return "GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN (0x85C2)";
+case 0x85C3 /* GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN */: return "GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN (0x85C3)";
+case 0x85C4 /* GL_R1UI_V3F_SUN */: return "GL_R1UI_V3F_SUN (0x85C4)";
+case 0x85C5 /* GL_R1UI_C4UB_V3F_SUN */: return "GL_R1UI_C4UB_V3F_SUN (0x85C5)";
+case 0x85C6 /* GL_R1UI_C3F_V3F_SUN */: return "GL_R1UI_C3F_V3F_SUN (0x85C6)";
+case 0x85C7 /* GL_R1UI_N3F_V3F_SUN */: return "GL_R1UI_N3F_V3F_SUN (0x85C7)";
+case 0x85C8 /* GL_R1UI_C4F_N3F_V3F_SUN */: return "GL_R1UI_C4F_N3F_V3F_SUN (0x85C8)";
+case 0x85C9 /* GL_R1UI_T2F_V3F_SUN */: return "GL_R1UI_T2F_V3F_SUN (0x85C9)";
+case 0x85CA /* GL_R1UI_T2F_N3F_V3F_SUN */: return "GL_R1UI_T2F_N3F_V3F_SUN (0x85CA)";
+case 0x85CB /* GL_R1UI_T2F_C4F_N3F_V3F_SUN */: return "GL_R1UI_T2F_C4F_N3F_V3F_SUN (0x85CB)";
+
+/* ----------------------------- GL_SUN_vertex ----------------------------- */
+/* -------------------------- GL_WIN_phong_shading ------------------------- */
+
+
+
+
+case 0x80EA /* GL_PHONG_WIN */: return "GL_PHONG_WIN (0x80EA)";
+case 0x80EB /* GL_PHONG_HINT_WIN */: return "GL_PHONG_HINT_WIN (0x80EB)";
+
+
+
+
+
+/* -------------------------- GL_WIN_specular_fog -------------------------- */
+
+
+
+
+case 0x80EC /* GL_FOG_SPECULAR_TEXTURE_WIN */: return "GL_FOG_SPECULAR_TEXTURE_WIN (0x80EC)";
+
+
+default:
+	{
+		return "what?";
+	}
+} // ~switch
+
+} // ~WWWGLEnumToString
+
+int main() {
+  volatile int i;
+  i = 34962;
+  printf("%d: %s\n", i, WWWGLEnumToString(i));
+  i = 26214;
+  printf("%d: %s\n", i, WWWGLEnumToString(i));
+  i = 35040;
+  printf("%d: %s\n", i, WWWGLEnumToString(i));
+  i = 3060;
+  printf("%d: %s\n", i, WWWGLEnumToString(i));
+}
+
diff --git a/binaryen/test/bigswitch.txt b/binaryen/test/bigswitch.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/bigswitch.txt
@@ -0,0 +1,5 @@
+34962: GL_ARRAY_BUFFER (0x8892)
+26214: what?
+35040: GL_STREAM_DRAW (0x88E0)
+3060: what?
+
diff --git a/binaryen/test/binaryen.js/atomics.js b/binaryen/test/binaryen.js/atomics.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/atomics.js
@@ -0,0 +1,87 @@
+var wast = `
+(module
+  (memory $0 (shared 1 1))
+)
+`;
+
+var module = binaryen.parseText(wast);
+
+// i32/i64.atomic.load/store
+module.addFunction("main", binaryen.none, binaryen.none, [], module.block("", [
+  // i32
+  module.i32.atomic.store(0,
+    module.i32.const(0),
+    module.i32.atomic.load(0,
+      module.i32.const(0)
+    )
+  ),
+  // i32 as u8
+  module.i32.atomic.store8(0,
+    module.i32.const(0),
+    module.i32.atomic.load8_u(0,
+      module.i32.const(0)
+    )
+  ),
+  // i32 as u16
+  module.i32.atomic.store16(0,
+    module.i32.const(0),
+    module.i32.atomic.load16_u(0,
+      module.i32.const(0)
+    )
+  ),
+  // i64
+  module.i64.atomic.store(0,
+    module.i32.const(0),
+    module.i64.atomic.load(0,
+      module.i32.const(0)
+    )
+  ),
+  // i64 as u8
+  module.i64.atomic.store8(0,
+    module.i32.const(0),
+    module.i64.atomic.load8_u(0,
+      module.i32.const(0)
+    )
+  ),
+  // i64 as u16
+  module.i64.atomic.store16(0,
+    module.i32.const(0),
+    module.i64.atomic.load16_u(0,
+      module.i32.const(0)
+    )
+  ),
+  // i64 as u32
+  module.i64.atomic.store32(0,
+    module.i32.const(0),
+    module.i64.atomic.load32_u(0,
+      module.i32.const(0)
+    )
+  ),
+  // wait and notify
+  module.drop(
+    module.i32.atomic.wait(
+      module.i32.const(0),
+      module.i32.const(0),
+      module.i64.const(0)
+    )
+  ),
+  module.drop(
+    module.i64.atomic.wait(
+      module.i32.const(0),
+      module.i64.const(0),
+      module.i64.const(0)
+    )
+  ),
+  module.drop(
+    module.atomic.notify(
+      module.i32.const(0),
+      module.i32.const(0)
+    )
+  ),
+  // fence
+  module.atomic.fence()
+]));
+
+module.setFeatures(binaryen.Features.Atomics);
+assert(module.validate());
+console.log(module.emitText());
diff --git a/binaryen/test/binaryen.js/atomics.js.txt b/binaryen/test/binaryen.js/atomics.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/atomics.js.txt
@@ -0,0 +1,70 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 (shared 1 1))
+ (func $main
+  (i32.atomic.store
+   (i32.const 0)
+   (i32.atomic.load
+    (i32.const 0)
+   )
+  )
+  (i32.atomic.store8
+   (i32.const 0)
+   (i32.atomic.load8_u
+    (i32.const 0)
+   )
+  )
+  (i32.atomic.store16
+   (i32.const 0)
+   (i32.atomic.load16_u
+    (i32.const 0)
+   )
+  )
+  (i64.atomic.store
+   (i32.const 0)
+   (i64.atomic.load
+    (i32.const 0)
+   )
+  )
+  (i64.atomic.store8
+   (i32.const 0)
+   (i64.atomic.load8_u
+    (i32.const 0)
+   )
+  )
+  (i64.atomic.store16
+   (i32.const 0)
+   (i64.atomic.load16_u
+    (i32.const 0)
+   )
+  )
+  (i64.atomic.store32
+   (i32.const 0)
+   (i64.atomic.load32_u
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.atomic.wait
+    (i32.const 0)
+    (i32.const 0)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (i64.atomic.wait
+    (i32.const 0)
+    (i64.const 0)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (atomic.notify
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+  (atomic.fence)
+ )
+)
+
diff --git a/binaryen/test/binaryen.js/copy-expression.js b/binaryen/test/binaryen.js/copy-expression.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/copy-expression.js
@@ -0,0 +1,31 @@
+var module = new binaryen.Module();
+
+// Create an expression and copy it
+var original = module.block(null, [
+  module.if(
+    module.local.get(0, binaryen.i32),
+    module.i32.const(1),
+    module.i32.const(2)
+  )
+], binaryen.i32);
+var copy = module.copyExpression(original);
+
+// Check that the expression incl. sub-expressions are copies
+assert(original !== copy);
+
+var originalInfo = binaryen.getExpressionInfo(original);
+assert(originalInfo.children.length === 1);
+
+var copyInfo = binaryen.getExpressionInfo(copy);
+assert(originalInfo.children.length === copyInfo.children.length);
+assert(originalInfo.children[0] !== copyInfo.children[0]);
+
+var originalIfInfo = binaryen.getExpressionInfo(originalInfo.children[0]);
+var copyIfInfo = binaryen.getExpressionInfo(copyInfo.children[0]);
+
+assert(originalIfInfo.condition !== copyIfInfo.condition);
+assert(originalIfInfo.ifTrue !== copyIfInfo.ifTrue);
+assert(originalIfInfo.ifFalse !== copyIfInfo.ifFalse);
+
+// Check that both are otherwise identical
+assert(binaryen.emitText(original) === binaryen.emitText(copy));
diff --git a/binaryen/test/binaryen.js/copy-expression.js.txt b/binaryen/test/binaryen.js/copy-expression.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/copy-expression.js.txt
diff --git a/binaryen/test/binaryen.js/custom-section.js b/binaryen/test/binaryen.js/custom-section.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/custom-section.js
@@ -0,0 +1,6 @@
+var module = new binaryen.Module();
+
+module.addCustomSection("hello", [119, 111, 114, 108, 100]);
+
+assert(module.validate());
+console.log(module.emitText());
diff --git a/binaryen/test/binaryen.js/custom-section.js.txt b/binaryen/test/binaryen.js/custom-section.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/custom-section.js.txt
@@ -0,0 +1,4 @@
+(module
+ ;; custom section "hello", size 5, contents: "world"
+)
+
diff --git a/binaryen/test/binaryen.js/debug-info.js b/binaryen/test/binaryen.js/debug-info.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/debug-info.js
@@ -0,0 +1,43 @@
+var wast = `
+(module
+ (type $v (func))
+ (memory $0 0)
+ (export "test" (func $test))
+ (func $test (; 0 ;) (type $v))
+)
+`;
+
+// Use defaults (should not emit debug info)
+console.log("=== default ===");
+console.log("debugInfo=" + binaryen.getDebugInfo());
+var module = binaryen.parseText(wast);
+var binary = module.emitBinary();
+module.dispose();
+module = binaryen.readBinary(binary);
+console.log(module.emitText());
+assert(module.validate());
+module.dispose();
+
+// With debug info
+console.log("=== with debug info ===");
+binaryen.setDebugInfo(true);
+console.log("debugInfo=" + binaryen.getDebugInfo());
+module = binaryen.parseText(wast);
+binary = module.emitBinary();
+module.dispose();
+module = binaryen.readBinary(binary);
+console.log(module.emitText());
+assert(module.validate());
+module.dispose();
+
+// Without debug info
+console.log("=== without debug info ===");
+binaryen.setDebugInfo(false);
+console.log("debugInfo=" + binaryen.getDebugInfo());
+module = binaryen.parseText(wast);
+binary = module.emitBinary();
+module.dispose();
+module = binaryen.readBinary(binary);
+console.log(module.emitText());
+assert(module.validate());
+module.dispose();
diff --git a/binaryen/test/binaryen.js/debug-info.js.txt b/binaryen/test/binaryen.js/debug-info.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/debug-info.js.txt
@@ -0,0 +1,33 @@
+=== default ===
+debugInfo=false
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (export "test" (func $0))
+ (func $0
+  (nop)
+ )
+)
+
+=== with debug info ===
+debugInfo=true
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (export "test" (func $test))
+ (func $test
+  (nop)
+ )
+)
+
+=== without debug info ===
+debugInfo=false
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (export "test" (func $0))
+ (func $0
+  (nop)
+ )
+)
+
diff --git a/binaryen/test/binaryen.js/debug-names.js b/binaryen/test/binaryen.js/debug-names.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/debug-names.js
@@ -0,0 +1,42 @@
+var wast = `
+(module $hel
+ (memory $lo 0 0)
+ (table $wor 0 0 funcref)
+ (global $ld i32 (i32.const 0))
+ (func $of (param $wasm i32)
+  (local $!#$%&'*+-./:<=>?@\\^_\`|~ f64)
+ )
+)
+`;
+
+console.log("=== input wast ===" + wast);
+
+var module = binaryen.parseText(wast);
+
+console.log("=== parsed wast ===\n" + module.emitText());
+
+var func = binaryen.Function(module.getFunction("of"));
+assert(func.numLocals === 2);
+assert(func.hasLocalName(0) === true);
+assert(func.getLocalName(0) === "wasm");
+assert(func.hasLocalName(1) === true);
+assert(func.getLocalName(1) === "!#$%&'*+-./:<=>?@\\^_\`|~");
+assert(func.hasLocalName(2) === false);
+func.setLocalName(0, "js");
+assert(func.getLocalName(0) === "js");
+
+binaryen.setDebugInfo(true);
+
+var module2 = binaryen.readBinary(module.emitBinary());
+
+module.dispose();
+
+console.log("=== roundtripped ===\n" + module2.emitText());
+
+var module3 = binaryen.readBinary(module2.emitBinary());
+
+module2.dispose();
+
+console.log("=== roundtripped again ===\n" + module3.emitText());
+
+module3.dispose();
diff --git a/binaryen/test/binaryen.js/debug-names.js.txt b/binaryen/test/binaryen.js/debug-names.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/debug-names.js.txt
@@ -0,0 +1,46 @@
+=== input wast ===
+(module $hel
+ (memory $lo 0 0)
+ (table $wor 0 0 funcref)
+ (global $ld i32 (i32.const 0))
+ (func $of (param $wasm i32)
+  (local $!#$%&'*+-./:<=>?@\^_`|~ f64)
+ )
+)
+
+=== parsed wast ===
+(module $hel
+ (type $i32_=>_none (func (param i32)))
+ (memory $lo 0 0)
+ (table $wor 0 0 funcref)
+ (global $ld i32 (i32.const 0))
+ (func $of (param $wasm i32)
+  (local $!#$%&'*+-./:<=>?@\^_`|~ f64)
+  (nop)
+ )
+)
+
+=== roundtripped ===
+(module $hel
+ (type $i32_=>_none (func (param i32)))
+ (memory $lo 0 0)
+ (table $wor 0 0 funcref)
+ (global $ld i32 (i32.const 0))
+ (func $of (param $js i32)
+  (local $!#$%&'*+-./:<=>?@\5c^_`|~ f64)
+  (nop)
+ )
+)
+
+=== roundtripped again ===
+(module $hel
+ (type $i32_=>_none (func (param i32)))
+ (memory $lo 0 0)
+ (table $wor 0 0 funcref)
+ (global $ld i32 (i32.const 0))
+ (func $of (param $js i32)
+  (local $!#$%&'*+-./:<=>?@\5c^_`|~ f64)
+  (nop)
+ )
+)
+
diff --git a/binaryen/test/binaryen.js/emit_asmjs.js b/binaryen/test/binaryen.js/emit_asmjs.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/emit_asmjs.js
@@ -0,0 +1,9 @@
+var module = new binaryen.Module();
+
+module.addFunction("main", binaryen.i32, binaryen.i32, [], module.local.get(0, binaryen.i32));
+
+module.addFunctionExport("main", "main");
+
+assert(module.validate()); // should validate before calling emitAsmjs
+
+console.log(module.emitAsmjs());
diff --git a/binaryen/test/binaryen.js/emit_asmjs.js.txt b/binaryen/test/binaryen.js/emit_asmjs.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/emit_asmjs.js.txt
@@ -0,0 +1,41 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function main($0) {
+  $0 = $0 | 0;
+  return $0 | 0;
+ }
+ 
+ return {
+  "main": main
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var main = retasmFunc.main;
+
diff --git a/binaryen/test/binaryen.js/event.js b/binaryen/test/binaryen.js/event.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/event.js
@@ -0,0 +1,33 @@
+function cleanInfo(info) {
+  var ret = {};
+  for (var x in info) {
+    ret[x] = info[x];
+  }
+  return ret;
+}
+
+var module = new binaryen.Module();
+module.setFeatures(binaryen.Features.ReferenceTypes |
+                   binaryen.Features.ExceptionHandling |
+                   binaryen.Features.Multivalue);
+
+var pairType = binaryen.createType([binaryen.i32, binaryen.f32]);
+
+var event_ = module.addEvent("a-event", 0, binaryen.i32, binaryen.none);
+
+console.log("GetEvent is equal: " + (event_ === module.getEvent("a-event")));
+
+var eventInfo = binaryen.getEventInfo(event_);
+console.log("getEventInfo=" + JSON.stringify(cleanInfo(eventInfo)));
+
+module.addEventExport("a-event", "a-event-exp");
+module.addEventImport("a-event-imp", "module", "base", 0, pairType, binaryen.none);
+
+assert(module.validate());
+console.log(module.emitText());
+
+module.removeExport("a-event-exp");
+module.removeEvent("a-event");
+
+assert(module.validate());
+console.log(module.emitText());
diff --git a/binaryen/test/binaryen.js/event.js.txt b/binaryen/test/binaryen.js/event.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/event.js.txt
@@ -0,0 +1,15 @@
+GetEvent is equal: true
+getEventInfo={"name":"a-event","module":"","base":"","attribute":0,"params":2,"results":0}
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_f32_=>_none (func (param i32 f32)))
+ (import "module" "base" (event $a-event-imp (attr 0) (param i32 f32)))
+ (event $a-event (attr 0) (param i32))
+ (export "a-event-exp" (event $a-event))
+)
+
+(module
+ (type $i32_f32_=>_none (func (param i32 f32)))
+ (import "module" "base" (event $a-event-imp (attr 0) (param i32 f32)))
+)
+
diff --git a/binaryen/test/binaryen.js/exception-handling.js b/binaryen/test/binaryen.js/exception-handling.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/exception-handling.js
@@ -0,0 +1,58 @@
+function cleanInfo(info) {
+  var ret = {};
+  for (var x in info) {
+    if (x == 'id' || x == 'type' || x == 'name' || x == 'event') {
+      ret[x] = info[x];
+    }
+  }
+  return ret;
+}
+
+function stringify(expr) {
+  return JSON.stringify(cleanInfo(binaryen.getExpressionInfo(expr)));
+}
+
+var module = new binaryen.Module();
+module.setFeatures(binaryen.Features.ReferenceTypes |
+                   binaryen.Features.ExceptionHandling);
+
+var event_ = module.addEvent("e", 0, binaryen.i32, binaryen.none);
+
+// (try
+//   (do
+//     (throw $e (i32.const 0))
+//   )
+//   (catch
+//     ;; We don't support multi-value yet. Use locals instead.
+//     (local.set 0 (exnref.pop))
+//     (drop
+//       (block $l (result i32)
+//         (rethrow
+//           (br_on_exn $l $e (local.get 0))
+//         )
+//       )
+//     )
+//   )
+// )
+var throw_ = module.throw("e", [module.i32.const(0)]);
+var br_on_exn = module.br_on_exn("l", "e", module.local.get(0, binaryen.exnref));
+var rethrow = module.rethrow(br_on_exn);
+var try_ = module.try(
+  throw_,
+  module.block(null, [
+    module.local.set(0, module.exnref.pop()),
+    module.drop(
+      module.block("l", [rethrow], binaryen.i32)
+    )
+  ]
+  )
+);
+var func = module.addFunction("test", binaryen.none, binaryen.none, [binaryen.exnref], try_);
+
+console.log(module.emitText());
+assert(module.validate());
+
+console.log("getExpressionInfo(throw) = " + stringify(throw_));
+console.log("getExpressionInfo(br_on_exn) = " + stringify(br_on_exn));
+console.log("getExpressionInfo(rethrow) = " + stringify(rethrow));
+console.log("getExpressionInfo(try) = " + stringify(try_));
diff --git a/binaryen/test/binaryen.js/exception-handling.js.txt b/binaryen/test/binaryen.js/exception-handling.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/exception-handling.js.txt
@@ -0,0 +1,34 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (event $e (attr 0) (param i32))
+ (func $test
+  (local $0 exnref)
+  (try
+   (do
+    (throw $e
+     (i32.const 0)
+    )
+   )
+   (catch
+    (local.set $0
+     (pop exnref)
+    )
+    (drop
+     (block $l (result i32)
+      (rethrow
+       (br_on_exn $l $e
+        (local.get $0)
+       )
+      )
+     )
+    )
+   )
+  )
+ )
+)
+
+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}
diff --git a/binaryen/test/binaryen.js/expressionrunner.js b/binaryen/test/binaryen.js/expressionrunner.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/expressionrunner.js
@@ -0,0 +1,205 @@
+var Flags = binaryen.ExpressionRunner.Flags;
+console.log("// ExpressionRunner.Flags.Default = " + Flags.Default);
+console.log("// ExpressionRunner.Flags.PreserveSideeffects = " + Flags.PreserveSideeffects);
+console.log("// ExpressionRunner.Flags.TraverseCalls = " + Flags.TraverseCalls);
+
+function assertDeepEqual(x, y) {
+  if (typeof x === "object") {
+    for (let i in x) assertDeepEqual(x[i], y[i]);
+    for (let i in y) assertDeepEqual(x[i], y[i]);
+  } else {
+    assert(x === y);
+  }
+}
+
+var module = new binaryen.Module();
+module.addGlobal("aGlobal", binaryen.i32, true, module.i32.const(0));
+
+// Should evaluate down to a constant
+var runner = new binaryen.ExpressionRunner(module);
+var expr = runner.runAndDispose(
+  module.i32.add(
+    module.i32.const(1),
+    module.i32.const(2)
+  )
+);
+assertDeepEqual(
+  binaryen.getExpressionInfo(expr),
+  {
+    id: binaryen.ExpressionIds.Const,
+    type: binaryen.i32,
+    value: 3
+  }
+);
+
+// Should traverse control structures
+runner = new binaryen.ExpressionRunner(module);
+expr = runner.runAndDispose(
+  module.i32.add(
+    module.i32.const(1),
+    module.if(
+      module.i32.const(0),
+      module.i32.const(0),
+      module.i32.const(3)
+    )
+  ),
+);
+assertDeepEqual(
+  binaryen.getExpressionInfo(expr),
+  {
+    id: binaryen.ExpressionIds.Const,
+    type: binaryen.i32,
+    value: 4
+  }
+);
+
+// Should be unable to evaluate a local if not explicitly specified
+runner = new binaryen.ExpressionRunner(module);
+expr = runner.runAndDispose(
+  module.i32.add(
+    module.local.get(0, binaryen.i32),
+    module.i32.const(1)
+  )
+);
+assert(expr === 0);
+
+// Should handle traps properly
+runner = new binaryen.ExpressionRunner(module);
+expr = runner.runAndDispose(
+  module.unreachable()
+);
+assert(expr === 0);
+
+// Should ignore `local.tee` side-effects if just evaluating the expression
+runner = new binaryen.ExpressionRunner(module);
+expr = runner.runAndDispose(
+  module.i32.add(
+    module.local.tee(0, module.i32.const(4), binaryen.i32),
+    module.i32.const(1)
+  )
+);
+assertDeepEqual(
+  binaryen.getExpressionInfo(expr),
+  {
+    id: binaryen.ExpressionIds.Const,
+    type: binaryen.i32,
+    value: 5
+  }
+);
+
+// Should preserve any side-effects if explicitly requested
+runner = new binaryen.ExpressionRunner(module, Flags.PreserveSideeffects);
+expr = runner.runAndDispose(
+  module.i32.add(
+    module.local.tee(0, module.i32.const(4), binaryen.i32),
+    module.i32.const(1)
+  )
+);
+assert(expr === 0);
+
+// Should work with temporary values if just evaluating the expression
+runner = new binaryen.ExpressionRunner(module);
+expr = runner.runAndDispose(
+  module.i32.add(
+    module.block(null, [
+      module.local.set(0, module.i32.const(2)),
+      module.local.get(0, binaryen.i32)
+    ], binaryen.i32),
+    module.block(null, [
+      module.global.set("aGlobal", module.i32.const(4)),
+      module.global.get("aGlobal", binaryen.i32)
+    ], binaryen.i32)
+  )
+);
+assertDeepEqual(
+  binaryen.getExpressionInfo(expr),
+  {
+    id: binaryen.ExpressionIds.Const,
+    type: binaryen.i32,
+    value: 6
+  }
+);
+
+// Should pick up explicitly preset values
+runner = new binaryen.ExpressionRunner(module, Flags.PreserveSideeffects);
+assert(runner.setLocalValue(0, module.i32.const(3)));
+assert(runner.setGlobalValue("aGlobal", module.i32.const(4)));
+expr = runner.runAndDispose(
+  module.i32.add(
+    module.local.get(0, binaryen.i32),
+    module.global.get("aGlobal", binaryen.i32)
+  )
+);
+assertDeepEqual(
+  binaryen.getExpressionInfo(expr),
+  {
+    id: binaryen.ExpressionIds.Const,
+    type: binaryen.i32,
+    value: 7
+  }
+);
+
+// Should traverse into (simple) functions if requested
+runner = new binaryen.ExpressionRunner(module, Flags.TraverseCalls);
+module.addFunction("add", binaryen.createType([ binaryen.i32, binaryen.i32 ]), binaryen.i32, [],
+  module.block(null, [
+    module.i32.add(
+      module.local.get(0, binaryen.i32),
+      module.local.get(1, binaryen.i32)
+    )
+  ], binaryen.i32)
+);
+assert(runner.setLocalValue(0, module.i32.const(1)));
+expr = runner.runAndDispose(
+  module.i32.add(
+    module.i32.add(
+      module.local.get(0, binaryen.i32),
+      module.call("add", [
+        module.i32.const(2),
+        module.i32.const(4)
+      ], binaryen.i32)
+    ),
+    module.local.get(0, binaryen.i32)
+  )
+);
+assertDeepEqual(
+  binaryen.getExpressionInfo(expr),
+  {
+    id: binaryen.ExpressionIds.Const,
+    type: binaryen.i32,
+    value: 8
+  }
+);
+
+// Should not attempt to traverse into functions if not explicitly set
+runner = new binaryen.ExpressionRunner(module);
+expr = runner.runAndDispose(
+  module.i32.add(
+    module.i32.const(1),
+    module.call("add", [
+      module.i32.const(3),
+      module.i32.const(4)
+    ], binaryen.i32)
+  )
+);
+assert(expr === 0);
+
+// Should stop on maxDepth
+runner = new binaryen.ExpressionRunner(module, Flags.Default, 1);
+expr = runner.runAndDispose(
+  module.block(null, [
+    module.i32.const(1),
+  ], binaryen.i32)
+);
+assert(expr === 0);
+
+// Should not loop infinitely
+runner = new binaryen.ExpressionRunner(module, Flags.Default, 50, 3);
+expr = runner.runAndDispose(
+  module.loop("theLoop",
+    module.br("theLoop")
+  )
+);
+assert(expr === 0);
+
+module.dispose();
diff --git a/binaryen/test/binaryen.js/expressionrunner.js.txt b/binaryen/test/binaryen.js/expressionrunner.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/expressionrunner.js.txt
@@ -0,0 +1,3 @@
+// ExpressionRunner.Flags.Default = 0
+// ExpressionRunner.Flags.PreserveSideeffects = 1
+// ExpressionRunner.Flags.TraverseCalls = 2
diff --git a/binaryen/test/binaryen.js/expressions.js b/binaryen/test/binaryen.js/expressions.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/expressions.js
@@ -0,0 +1,1708 @@
+function assertDeepEqual(x, y) {
+  if (typeof x === "object") {
+    for (let i in x) assertDeepEqual(x[i], y[i]);
+    for (let i in y) assertDeepEqual(x[i], y[i]);
+  } else {
+    assert(x === y);
+  }
+}
+
+console.log("# Expression");
+(function testWrapper() {
+  var theExpression = binaryen.Block(42); // works without new
+  assert(theExpression instanceof binaryen.Block);
+  assert(theExpression instanceof binaryen.Expression);
+  assert(theExpression.constructor === binaryen.Block);
+  assert(typeof binaryen.Block.getId === "function"); // proto
+  assert(typeof binaryen.Block.getName === "function"); // own
+  assert(typeof theExpression.getId === "function"); // proto
+  assert(typeof theExpression.getName === "function"); // own
+  assert((theExpression | 0) === 42); // via valueOf
+})();
+
+console.log("# Block");
+(function testBlock() {
+  const module = new binaryen.Module();
+
+  const theBlock = binaryen.Block(module.block(null, []));
+  assert(theBlock instanceof binaryen.Block);
+  assert(theBlock instanceof binaryen.Expression);
+  assert(theBlock.id === binaryen.BlockId);
+  assert(theBlock.name === null);
+  assert(theBlock.type === binaryen.none);
+
+  theBlock.name ="theName";
+  assert(theBlock.name === "theName");
+  theBlock.type = binaryen.i32;
+  assert(theBlock.type === binaryen.i32);
+  assert(theBlock.numChildren === 0);
+  assertDeepEqual(theBlock.children, []);
+
+  var child1 = module.i32.const(1);
+  theBlock.appendChild(child1);
+  assert(theBlock.numChildren === 1);
+  assert(theBlock.getChildAt(0) === child1);
+  var child2 = module.i32.const(2);
+  theBlock.insertChildAt(1, child2);
+  assert(theBlock.numChildren === 2);
+  assert(theBlock.getChildAt(0) === child1);
+  assert(theBlock.getChildAt(1) === child2);
+  var child0 = module.i32.const(0);
+  theBlock.insertChildAt(0, child0);
+  assert(theBlock.numChildren === 3);
+  assert(theBlock.getChildAt(0) === child0);
+  assert(theBlock.getChildAt(1) === child1);
+  assert(theBlock.getChildAt(2) === child2);
+  var newChild1 = module.i32.const(11);
+  theBlock.setChildAt(1, newChild1);
+  assert(theBlock.numChildren === 3);
+  assert(theBlock.getChildAt(0) === child0);
+  assert(theBlock.getChildAt(1) === newChild1);
+  assert(theBlock.getChildAt(2) === child2);
+  theBlock.removeChildAt(1);
+  assert(theBlock.numChildren === 2);
+  assert(theBlock.getChildAt(0) === child0);
+  assert(theBlock.getChildAt(1) === child2);
+  theBlock.removeChildAt(1);
+  assert(theBlock.numChildren === 1);
+  assert(theBlock.getChildAt(0) === child0);
+  theBlock.finalize();
+
+  console.log(theBlock.toText());
+  assert(
+    theBlock.toText()
+    ==
+    "(block $theName (result i32)\n (i32.const 0)\n)\n"
+  );
+  theBlock.removeChildAt(0);
+  assert(theBlock.numChildren === 0);
+
+  module.dispose();
+})();
+
+console.log("# If");
+(function testIf() {
+  const module = new binaryen.Module();
+
+  var condition = module.i32.const(1);
+  var ifTrue = module.i32.const(2);
+  var ifFalse = module.i32.const(3);
+  const theIf = binaryen.If(module.if(condition, ifTrue, ifFalse));
+  assert(theIf instanceof binaryen.If);
+  assert(theIf instanceof binaryen.Expression);
+  assert(theIf.id === binaryen.IfId);
+  assert(theIf.condition === condition);
+  assert(theIf.ifTrue === ifTrue);
+  assert(theIf.ifFalse === ifFalse);
+  assert(theIf.type == binaryen.i32);
+
+  theIf.condition = condition = module.i32.const(4);
+  assert(theIf.condition === condition);
+  theIf.ifTrue = ifTrue = module.i32.const(5);
+  assert(theIf.ifTrue === ifTrue);
+  theIf.ifFalse = ifFalse = module.i32.const(6);
+  assert(theIf.ifFalse === ifFalse);
+  theIf.finalize();
+
+  console.log(theIf.toText());
+  assert(
+    theIf.toText()
+    ==
+    "(if (result i32)\n (i32.const 4)\n (i32.const 5)\n (i32.const 6)\n)\n"
+  );
+
+  theIf.ifFalse = null;
+  assert(!theIf.ifFalse);
+  console.log(theIf.toText());
+  assert(
+    theIf.toText()
+    ==
+    "(if (result i32)\n (i32.const 4)\n (i32.const 5)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# Loop");
+(function testLoop() {
+  const module = new binaryen.Module();
+
+  var name = null;
+  var body = module.i32.const(1);
+  const theLoop = binaryen.Loop(module.loop(name, body));
+  assert(theLoop instanceof binaryen.Loop);
+  assert(theLoop instanceof binaryen.Expression);
+  assert(theLoop.id === binaryen.LoopId);
+  assert(theLoop.name === name);
+  assert(theLoop.body === body);
+  assert(theLoop.type === binaryen.i32);
+
+  theLoop.name = name = "theName";
+  assert(theLoop.name === name);
+  theLoop.body = body = module.drop(body);
+  assert(theLoop.body === body);
+  theLoop.finalize();
+  assert(theLoop.type === binaryen.none);
+
+  console.log(theLoop.toText());
+  assert(
+    theLoop.toText()
+    ==
+    "(loop $theName\n (drop\n  (i32.const 1)\n )\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# Break");
+(function testBreak() {
+  const module = new binaryen.Module();
+
+  var name = "theName";
+  var condition = module.i32.const(1);
+  var value = module.i32.const(2);
+  const theBreak = binaryen.Break(module.br(name, condition, value));
+  assert(theBreak instanceof binaryen.Break);
+  assert(theBreak instanceof binaryen.Expression);
+  assert(theBreak.name === name);
+  assert(theBreak.condition === condition);
+  assert(theBreak.value === value);
+  assert(theBreak.type === binaryen.i32);
+
+  theBreak.name = name = "theNewName";
+  assert(theBreak.name === "theNewName");
+  theBreak.condition = condition = module.i32.const(3);
+  assert(theBreak.condition === condition);
+  theBreak.value = value = module.i32.const(4);
+  assert(theBreak.value === value);
+  theBreak.finalize();
+
+  console.log(theBreak.toText());
+  assert(
+    theBreak.toText()
+    ==
+    "(br_if $theNewName\n (i32.const 4)\n (i32.const 3)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# Switch");
+(function testSwitch() {
+  const module = new binaryen.Module();
+
+  var names = ["a", "b"];
+  var defaultName = "c";
+  var condition = module.i32.const(1);
+  var value = module.i32.const(2);
+  const theSwitch = binaryen.Switch(module.switch(names, defaultName, condition, value));
+  assert(theSwitch instanceof binaryen.Switch);
+  assert(theSwitch instanceof binaryen.Expression);
+  assert(theSwitch.numNames === 2);
+  assertDeepEqual(theSwitch.names, names);
+  assert(theSwitch.defaultName === defaultName);
+  assert(theSwitch.condition === condition);
+  assert(theSwitch.value === value);
+  assert(theSwitch.type === binaryen.unreachable);
+
+  theSwitch.names = names = [
+    "1", // set
+    "2", // set
+    "3"  // append
+  ];
+  assertDeepEqual(theSwitch.names, names);
+  theSwitch.names = names = [
+    "x", // set
+    // remove
+    // remove
+  ];
+  assertDeepEqual(theSwitch.names, names);
+  theSwitch.insertNameAt(1, "y");
+  theSwitch.condition = condition = module.i32.const(3);
+  assert(theSwitch.condition === condition);
+  theSwitch.value = value = module.i32.const(4);
+  assert(theSwitch.value === value);
+  theSwitch.finalize();
+
+  console.log(theSwitch.toText());
+  assert(
+    theSwitch.toText()
+    ==
+    "(br_table $x $y $c\n (i32.const 4)\n (i32.const 3)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# Call");
+(function testCall() {
+  const module = new binaryen.Module();
+
+  var target = "foo";
+  var operands = [
+    module.i32.const(1),
+    module.i32.const(2)
+  ];
+  const theCall = binaryen.Call(module.call(target, operands, binaryen.i32));
+  assert(theCall instanceof binaryen.Call);
+  assert(theCall instanceof binaryen.Expression);
+  assert(theCall.target === target);
+  assertDeepEqual(theCall.operands, operands);
+  assert(theCall.return === false);
+  assert(theCall.type === binaryen.i32);
+
+  theCall.target = "bar";
+  assert(theCall.target === "bar");
+  theCall.operands = operands = [
+    module.i32.const(3), // set
+    module.i32.const(4), // set
+    module.i32.const(5)  // append
+  ];
+  assertDeepEqual(theCall.operands, operands);
+  theCall.operands = operands = [
+    module.i32.const(6) // set
+    // remove
+    // remove
+  ];
+  assertDeepEqual(theCall.operands, operands);
+  theCall.insertOperandAt(0, module.i32.const(7));
+  theCall.return = true;
+  assert(theCall.return === true);
+  theCall.finalize();
+  assert(theCall.type === binaryen.unreachable); // finalized tail call
+
+  theCall.return = false;
+  theCall.type = binaryen.i32;
+  theCall.finalize();
+  assert(theCall.type === binaryen.i32); // finalized call
+
+  console.log(theCall.toText());
+  assert(
+    theCall.toText()
+    ==
+    "(call $bar\n (i32.const 7)\n (i32.const 6)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# CallIndirect");
+(function testCallIndirect() {
+  const module = new binaryen.Module();
+
+  var target = module.i32.const(42);
+  var params = binaryen.none;
+  var results = binaryen.none;
+  var operands = [
+    module.i32.const(1),
+    module.i32.const(2)
+  ];
+  const theCallIndirect = binaryen.CallIndirect(module.call_indirect(target, operands, params, results));
+  assert(theCallIndirect instanceof binaryen.CallIndirect);
+  assert(theCallIndirect instanceof binaryen.Expression);
+  assert(theCallIndirect.target === target);
+  assertDeepEqual(theCallIndirect.operands, operands);
+  assert(theCallIndirect.params === params);
+  assert(theCallIndirect.results === results);
+  assert(theCallIndirect.return === false);
+  assert(theCallIndirect.type === theCallIndirect.results);
+
+  theCallIndirect.target = target = module.i32.const(9000);
+  assert(theCallIndirect.target === target);
+  theCallIndirect.operands = operands = [
+    module.i32.const(3), // set
+    module.i32.const(4), // set
+    module.i32.const(5)  // append
+  ];
+  assertDeepEqual(theCallIndirect.operands, operands);
+  theCallIndirect.operands = operands = [
+    module.i32.const(6) // set
+    // remove
+    // remove
+  ];
+  assertDeepEqual(theCallIndirect.operands, operands);
+  theCallIndirect.insertOperandAt(0, module.i32.const(7));
+  theCallIndirect.return = true;
+  assert(theCallIndirect.return === true);
+  theCallIndirect.params = params = binaryen.createType([ binaryen.i32, binaryen.i32 ]);
+  assert(theCallIndirect.params === params);
+  theCallIndirect.results = results = binaryen.i32;
+  assert(theCallIndirect.results === results);
+  theCallIndirect.finalize();
+  assert(theCallIndirect.type === binaryen.unreachable); // finalized tail call
+
+  theCallIndirect.return = false;
+  theCallIndirect.finalize();
+  assert(theCallIndirect.type === results); // finalized call
+
+  console.log(theCallIndirect.toText());
+  assert(
+    theCallIndirect.toText()
+    ==
+    "(call_indirect (type $i32_i32_=>_i32)\n (i32.const 7)\n (i32.const 6)\n (i32.const 9000)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# LocalGet");
+(function testLocalGet() {
+  const module = new binaryen.Module();
+
+  var index = 1;
+  var type = binaryen.i32;
+  const theLocalGet = binaryen.LocalGet(module.local.get(index, type));
+  assert(theLocalGet instanceof binaryen.LocalGet);
+  assert(theLocalGet instanceof binaryen.Expression);
+  assert(theLocalGet.index === index);
+  assert(theLocalGet.type === type);
+
+  theLocalGet.index = index = 2;
+  assert(theLocalGet.index === index);
+  theLocalGet.type = type = binaryen.f64;
+  assert(theLocalGet.type === type);
+  theLocalGet.finalize();
+
+  console.log(theLocalGet.toText());
+  assert(
+    theLocalGet.toText()
+    ==
+    "(local.get $2)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# LocalSet");
+(function testLocalSet() {
+  const module = new binaryen.Module();
+
+  var index = 1;
+  var value = module.i32.const(1);
+  const theLocalSet = binaryen.LocalSet(module.local.set(index, value));
+  assert(theLocalSet instanceof binaryen.LocalSet);
+  assert(theLocalSet instanceof binaryen.Expression);
+  assert(theLocalSet.index === index);
+  assert(theLocalSet.value === value);
+  assert(theLocalSet.tee === false);
+  assert(theLocalSet.type == binaryen.none);
+
+  theLocalSet.index = index = 2;
+  assert(theLocalSet.index === index);
+  theLocalSet.value = value = module.i32.const(3);
+  assert(theLocalSet.value === value);
+  theLocalSet.type = binaryen.i32;
+  assert(theLocalSet.type === binaryen.i32);
+  assert(theLocalSet.tee === true);
+  theLocalSet.type = binaryen.none;
+  theLocalSet.finalize();
+
+  console.log(theLocalSet.toText());
+  assert(
+    theLocalSet.toText()
+    ==
+    "(local.set $2\n (i32.const 3)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# GlobalGet");
+(function testGlobalGet() {
+  const module = new binaryen.Module();
+
+  var name = "a";
+  var type = binaryen.i32;
+  const theGlobalGet = binaryen.GlobalGet(module.global.get(name, type));
+  assert(theGlobalGet instanceof binaryen.GlobalGet);
+  assert(theGlobalGet instanceof binaryen.Expression);
+  assert(theGlobalGet.name === name);
+  assert(theGlobalGet.type === type);
+
+  theGlobalGet.name = name = "b";
+  assert(theGlobalGet.name === name);
+  theGlobalGet.type = type = binaryen.f64;
+  assert(theGlobalGet.type === type);
+  theGlobalGet.finalize();
+
+  console.log(theGlobalGet.toText());
+  assert(
+    theGlobalGet.toText()
+    ==
+    "(global.get $b)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# GlobalSet");
+(function testGlobalSet() {
+  const module = new binaryen.Module();
+
+  var name = "a";
+  var value = module.i32.const(1);
+  const theGlobalSet = binaryen.GlobalSet(module.global.set(name, value));
+  assert(theGlobalSet instanceof binaryen.GlobalSet);
+  assert(theGlobalSet instanceof binaryen.Expression);
+  assert(theGlobalSet.name === name);
+  assert(theGlobalSet.value === value);
+  assert(theGlobalSet.type == binaryen.none);
+
+  theGlobalSet.name = name = "b";
+  assert(theGlobalSet.name === name);
+  theGlobalSet.value = value = module.f64.const(3);
+  assert(theGlobalSet.value === value);
+  theGlobalSet.finalize();
+
+  console.log(theGlobalSet.toText());
+  assert(
+    theGlobalSet.toText()
+    ==
+    "(global.set $b\n (f64.const 3)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# MemorySize");
+(function testMemorySize() {
+  const module = new binaryen.Module();
+
+  var type = binaryen.i32;
+  const theMemorySize = binaryen.MemorySize(module.memory.size());
+  assert(theMemorySize instanceof binaryen.MemorySize);
+  assert(theMemorySize instanceof binaryen.Expression);
+  assert(theMemorySize.type === type);
+
+  theMemorySize.type = type = binaryen.f64;
+  assert(theMemorySize.type === type);
+  theMemorySize.finalize();
+  assert(theMemorySize.type === binaryen.i32);
+
+  console.log(theMemorySize.toText());
+  assert(
+    theMemorySize.toText()
+    ==
+    "(memory.size)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# MemoryGrow");
+(function testMemoryGrow() {
+  const module = new binaryen.Module();
+
+  var type = binaryen.i32;
+  var delta = module.i32.const(1);
+  const theMemoryGrow = binaryen.MemoryGrow(module.memory.grow(delta));
+  assert(theMemoryGrow instanceof binaryen.MemoryGrow);
+  assert(theMemoryGrow instanceof binaryen.Expression);
+  assert(theMemoryGrow.delta === delta);
+  assert(theMemoryGrow.type === type);
+
+  theMemoryGrow.delta = delta = module.i32.const(2);
+  assert(theMemoryGrow.delta === delta);
+  theMemoryGrow.type = type = binaryen.f64;
+  assert(theMemoryGrow.type === type);
+  theMemoryGrow.finalize();
+  assert(theMemoryGrow.type === binaryen.i32);
+
+  console.log(theMemoryGrow.toText());
+  assert(
+    theMemoryGrow.toText()
+    ==
+    "(memory.grow\n (i32.const 2)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# Load");
+(function testLoad() {
+  const module = new binaryen.Module();
+
+  var offset = 16;
+  var align = 2;
+  var ptr = module.i32.const(64);
+  const theLoad = binaryen.Load(module.i32.load(offset, align, ptr));
+  assert(theLoad instanceof binaryen.Load);
+  assert(theLoad instanceof binaryen.Expression);
+  assert(theLoad.offset === offset);
+  assert(theLoad.align === align);
+  assert(theLoad.ptr === ptr);
+  assert(theLoad.bytes === 4);
+  assert(theLoad.signed === true);
+  assert(theLoad.atomic === false);
+  assert(theLoad.type == binaryen.i32);
+
+  theLoad.offset = offset = 32;
+  assert(theLoad.offset === offset);
+  theLoad.align = align = 4;
+  assert(theLoad.align === align);
+  theLoad.ptr = ptr = module.i32.const(128);
+  assert(theLoad.ptr === ptr);
+  theLoad.type = binaryen.i64;
+  assert(theLoad.type === binaryen.i64);
+  theLoad.signed = false;
+  assert(theLoad.signed === false);
+  theLoad.bytes = 8;
+  assert(theLoad.bytes === 8);
+  theLoad.atomic = true;
+  assert(theLoad.atomic === true);
+  theLoad.finalize();
+  assert(theLoad.align === 4);
+
+  console.log(theLoad.toText());
+  assert(
+    theLoad.toText()
+    ==
+    "(i64.atomic.load offset=32 align=4\n (i32.const 128)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# Store");
+(function testStore() {
+  const module = new binaryen.Module();
+
+  var offset = 16;
+  var align = 2;
+  var ptr = module.i32.const(64);
+  var value = module.i32.const(1);
+  const theStore = binaryen.Store(module.i32.store(offset, align, ptr, value));
+  assert(theStore instanceof binaryen.Store);
+  assert(theStore instanceof binaryen.Expression);
+  assert(theStore.offset === offset);
+  assert(theStore.align === align);
+  assert(theStore.ptr === ptr);
+  assert(theStore.value === value);
+  assert(theStore.bytes === 4);
+  assert(theStore.atomic === false);
+  assert(theStore.valueType === binaryen.i32);
+  assert(theStore.type === binaryen.none);
+
+  theStore.offset = offset = 32;
+  assert(theStore.offset === offset);
+  theStore.align = align = 4;
+  assert(theStore.align === align);
+  theStore.ptr = ptr = module.i32.const(128);
+  assert(theStore.ptr === ptr);
+  theStore.value = value = module.i32.const(2);
+  assert(theStore.value === value);
+  theStore.signed = false;
+  assert(theStore.signed === false);
+  theStore.valueType = binaryen.i64;
+  assert(theStore.valueType === binaryen.i64);
+  theStore.bytes = 8;
+  assert(theStore.bytes === 8);
+  theStore.atomic = true;
+  assert(theStore.atomic === true);
+  theStore.finalize();
+  assert(theStore.align === 4);
+
+  console.log(theStore.toText());
+  assert(
+    theStore.toText()
+    ==
+    "(i64.atomic.store offset=32 align=4\n (i32.const 128)\n (i32.const 2)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# Const");
+(function testConst() {
+  const module = new binaryen.Module();
+
+  const theConst = binaryen.Const(module.i32.const(1));
+  assert(theConst instanceof binaryen.Const);
+  assert(theConst instanceof binaryen.Expression);
+  assert(theConst.valueI32 === 1);
+  theConst.valueI32 = 2;
+  assert(theConst.valueI32 === 2);
+  assert(theConst.type === binaryen.i32);
+
+  theConst.valueI64Low = 3;
+  assert(theConst.valueI64Low === 3);
+  theConst.valueI64High = 4;
+  assert(theConst.valueI64High === 4);
+  theConst.finalize();
+  assert(theConst.type == binaryen.i64);
+
+  theConst.valueF32 = 5;
+  assert(theConst.valueF32 === 5);
+  theConst.finalize();
+  assert(theConst.type === binaryen.f32);
+
+  theConst.valueF64 = 6;
+  assert(theConst.valueF64 === 6);
+  theConst.finalize();
+  assert(theConst.type === binaryen.f64);
+
+  theConst.valueV128 = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];
+  assertDeepEqual(theConst.valueV128, [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]);
+  theConst.finalize();
+  assert(theConst.type === binaryen.v128);
+
+  console.log(theConst.toText());
+  assert(
+    theConst.toText()
+    ==
+    "(v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# Unary");
+(function testUnary() {
+  const module = new binaryen.Module();
+
+  var op = binaryen.Operations.EqZInt32;
+  var value = module.i32.const(1);
+  const theUnary = binaryen.Unary(module.i32.eqz(value));
+  assert(theUnary instanceof binaryen.Unary);
+  assert(theUnary instanceof binaryen.Expression);
+  assert(theUnary.op === op);
+  assert(theUnary.value === value);
+  assert(theUnary.type === binaryen.i32);
+
+  theUnary.op = op = binaryen.Operations.EqZInt64;
+  assert(theUnary.op === op);
+  theUnary.value = value = module.i64.const(2);
+  assert(theUnary.value === value);
+  theUnary.type = binaryen.f32;
+  theUnary.finalize();
+  assert(theUnary.type === binaryen.i32);
+
+  console.log(theUnary.toText());
+  assert(
+    theUnary.toText()
+    ==
+    "(i64.eqz\n (i64.const 2)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# Binary");
+(function testBinary() {
+  const module = new binaryen.Module();
+
+  var op = binaryen.Operations.AddInt32;
+  var left = module.i32.const(1);
+  var right = module.i32.const(2);
+  const theBinary = binaryen.Binary(module.i32.add(left, right));
+  assert(theBinary instanceof binaryen.Binary);
+  assert(theBinary instanceof binaryen.Expression);
+  assert(theBinary.op === op);
+  assert(theBinary.left === left);
+  assert(theBinary.right === right);
+  assert(theBinary.type === binaryen.i32);
+
+  theBinary.op = op = binaryen.Operations.AddInt64;
+  assert(theBinary.op === op);
+  theBinary.left = left = module.i64.const(3);
+  assert(theBinary.left === left);
+  theBinary.right = right = module.i64.const(4);
+  assert(theBinary.right === right);
+  theBinary.type = binaryen.f32;
+  theBinary.finalize();
+  assert(theBinary.type === binaryen.i64);
+
+  console.log(theBinary.toText());
+  assert(
+    theBinary.toText()
+    ==
+    "(i64.add\n (i64.const 3)\n (i64.const 4)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# Select");
+(function testSelect() {
+  const module = new binaryen.Module();
+
+  var condition = module.i32.const(1);
+  var ifTrue = module.i32.const(2);
+  var ifFalse = module.i32.const(3);
+  const theSelect = binaryen.Select(module.select(condition, ifTrue, ifFalse));  assert(theSelect.ifTrue === ifTrue);
+  assert(theSelect instanceof binaryen.Select);
+  assert(theSelect instanceof binaryen.Expression);
+  assert(theSelect.condition === condition);
+  assert(theSelect.ifTrue === ifTrue);
+  assert(theSelect.ifFalse === ifFalse);
+  assert(theSelect.type === binaryen.i32);
+
+  theSelect.condition = condition = module.i32.const(4);
+  assert(theSelect.condition === condition);
+  theSelect.ifTrue = ifTrue = module.i64.const(5);
+  assert(theSelect.ifTrue === ifTrue);
+  theSelect.ifFalse = ifFalse = module.i64.const(6);
+  assert(theSelect.ifFalse === ifFalse);
+  theSelect.finalize();
+  assert(theSelect.type === binaryen.i64);
+
+  console.log(theSelect.toText());
+  assert(
+    theSelect.toText()
+    ==
+    "(select\n (i64.const 5)\n (i64.const 6)\n (i32.const 4)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# Drop");
+(function testDrop() {
+  const module = new binaryen.Module();
+
+  var value = module.i32.const(1);
+  const theDrop = binaryen.Drop(module.drop(value));
+  assert(theDrop instanceof binaryen.Drop);
+  assert(theDrop instanceof binaryen.Expression);
+  assert(theDrop.value === value);
+  assert(theDrop.type === binaryen.none);
+
+  theDrop.value = value = module.i32.const(2);
+  assert(theDrop.value === value);
+
+  theDrop.finalize();
+  assert(theDrop.type === binaryen.none);
+
+  console.log(theDrop.toText());
+  assert(
+    theDrop.toText()
+    ==
+    "(drop\n (i32.const 2)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# Return");
+(function testReturn() {
+  const module = new binaryen.Module();
+
+  var value = module.i32.const(1);
+  const theReturn = binaryen.Return(module.return(value));
+  assert(theReturn instanceof binaryen.Return);
+  assert(theReturn instanceof binaryen.Expression);
+  assert(theReturn.value === value);
+  assert(theReturn.type === binaryen.unreachable);
+
+  theReturn.value = value = module.i32.const(2);
+  assert(theReturn.value === value);
+
+  theReturn.finalize();
+  assert(theReturn.type === binaryen.unreachable);
+
+  console.log(theReturn.toText());
+  assert(
+    theReturn.toText()
+    ==
+    "(return\n (i32.const 2)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# AtomicRMW");
+(function testAtomicRMW() {
+  const module = new binaryen.Module();
+
+  var op = binaryen.Operations.AtomicRMWAdd;
+  var offset = 8;
+  var ptr = module.i32.const(2);
+  var value = module.i32.const(3);
+  const theAtomicRMW = binaryen.AtomicRMW(module.i32.atomic.rmw.add(offset, ptr, value));
+  assert(theAtomicRMW instanceof binaryen.AtomicRMW);
+  assert(theAtomicRMW instanceof binaryen.Expression);
+  assert(theAtomicRMW.op === op);
+  assert(theAtomicRMW.bytes === 4);
+  assert(theAtomicRMW.offset === offset);
+  assert(theAtomicRMW.ptr === ptr);
+  assert(theAtomicRMW.value === value);
+  assert(theAtomicRMW.type === binaryen.i32);
+
+  theAtomicRMW.op = op = binaryen.Operations.AtomicRMWSub;
+  assert(theAtomicRMW.op === op);
+  theAtomicRMW.bytes = 2;
+  assert(theAtomicRMW.bytes === 2);
+  theAtomicRMW.offset = offset = 16;
+  assert(theAtomicRMW.offset === offset);
+  theAtomicRMW.ptr = ptr = module.i32.const(4);
+  assert(theAtomicRMW.ptr === ptr);
+  theAtomicRMW.value = value = module.i64.const(5);
+  assert(theAtomicRMW.value === value);
+  theAtomicRMW.type = binaryen.i64;
+  theAtomicRMW.finalize();
+  assert(theAtomicRMW.type === binaryen.i64);
+
+  console.log(theAtomicRMW.toText());
+  assert(
+    theAtomicRMW.toText()
+    ==
+    "(i64.atomic.rmw16.sub_u offset=16\n (i32.const 4)\n (i64.const 5)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# AtomicCmpxchg");
+(function testAtomicCmpxchg() {
+  const module = new binaryen.Module();
+
+  var offset = 8;
+  var ptr = module.i32.const(2);
+  var expected = module.i32.const(3);
+  var replacement = module.i32.const(4);
+  const theAtomicCmpxchg = binaryen.AtomicCmpxchg(module.i32.atomic.rmw.cmpxchg(offset, ptr, expected, replacement));
+  assert(theAtomicCmpxchg instanceof binaryen.AtomicCmpxchg);
+  assert(theAtomicCmpxchg instanceof binaryen.Expression);
+  assert(theAtomicCmpxchg.bytes === 4);
+  assert(theAtomicCmpxchg.offset === offset);
+  assert(theAtomicCmpxchg.ptr === ptr);
+  assert(theAtomicCmpxchg.expected === expected);
+  assert(theAtomicCmpxchg.replacement === replacement);
+  assert(theAtomicCmpxchg.type === binaryen.i32);
+
+  theAtomicCmpxchg.bytes = 2;
+  assert(theAtomicCmpxchg.bytes === 2);
+  theAtomicCmpxchg.offset = offset = 16;
+  assert(theAtomicCmpxchg.offset === offset);
+  theAtomicCmpxchg.ptr = ptr = module.i32.const(5);
+  assert(theAtomicCmpxchg.ptr === ptr);
+  theAtomicCmpxchg.expected = expected = module.i64.const(6);
+  assert(theAtomicCmpxchg.expected === expected);
+  theAtomicCmpxchg.replacement = replacement = module.i64.const(7);
+  assert(theAtomicCmpxchg.replacement === replacement);
+  theAtomicCmpxchg.type = binaryen.i64;
+  theAtomicCmpxchg.finalize();
+  assert(theAtomicCmpxchg.type === binaryen.i64);
+
+  console.log(theAtomicCmpxchg.toText());
+  assert(
+    theAtomicCmpxchg.toText()
+    ==
+    "(i64.atomic.rmw16.cmpxchg_u offset=16\n (i32.const 5)\n (i64.const 6)\n (i64.const 7)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# AtomicWait");
+(function testAtomicWait() {
+  const module = new binaryen.Module();
+
+  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));
+  assert(theAtomicWait instanceof binaryen.AtomicWait);
+  assert(theAtomicWait instanceof binaryen.Expression);
+  assert(theAtomicWait.ptr === ptr);
+  assert(theAtomicWait.expected === expected);
+  assert(theAtomicWait.expectedType === binaryen.i32);
+  assert(theAtomicWait.timeout === timeout);
+  assert(theAtomicWait.type === binaryen.i32);
+
+  theAtomicWait.ptr = ptr = module.i32.const(5);
+  assert(theAtomicWait.ptr === ptr);
+  theAtomicWait.expected = expected = module.i32.const(6);
+  assert(theAtomicWait.expected === expected);
+  theAtomicWait.expectedType = binaryen.i64;
+  assert(theAtomicWait.expectedType === binaryen.i64);
+  theAtomicWait.timeout = timeout = module.i64.const(7);
+  assert(theAtomicWait.timeout === timeout);
+  theAtomicWait.type = binaryen.f64;
+  theAtomicWait.finalize();
+  assert(theAtomicWait.type === binaryen.i32);
+
+  console.log(theAtomicWait.toText());
+  assert(
+    theAtomicWait.toText()
+    ==
+    "(i64.atomic.wait\n (i32.const 5)\n (i32.const 6)\n (i64.const 7)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# AtomicNotify");
+(function testAtomicNotify() {
+  const module = new binaryen.Module();
+
+  var ptr = module.i32.const(1);
+  var notifyCount = module.i32.const(2);
+  const theAtomicNotify = binaryen.AtomicNotify(module.atomic.notify(ptr, notifyCount));
+  assert(theAtomicNotify instanceof binaryen.AtomicNotify);
+  assert(theAtomicNotify instanceof binaryen.Expression);
+  assert(theAtomicNotify.ptr === ptr);
+  assert(theAtomicNotify.notifyCount === notifyCount);
+  assert(theAtomicNotify.type === binaryen.i32);
+
+  theAtomicNotify.ptr = ptr = module.i32.const(3);
+  assert(theAtomicNotify.ptr === ptr);
+  theAtomicNotify.notifyCount = notifyCount = module.i32.const(4);
+  assert(theAtomicNotify.notifyCount === notifyCount);
+  theAtomicNotify.type = binaryen.f64;
+  theAtomicNotify.finalize();
+  assert(theAtomicNotify.type === binaryen.i32);
+
+  console.log(theAtomicNotify.toText());
+  assert(
+    theAtomicNotify.toText()
+    ==
+    "(atomic.notify\n (i32.const 3)\n (i32.const 4)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# AtomicFence");
+(function testAtomicFence() {
+  const module = new binaryen.Module();
+
+  const theAtomicFence = binaryen.AtomicFence(module.atomic.fence());
+  assert(theAtomicFence instanceof binaryen.AtomicFence);
+  assert(theAtomicFence instanceof binaryen.Expression);
+  assert(theAtomicFence.order === 0); // reserved, not yet used
+  assert(theAtomicFence.type === binaryen.none);
+
+  theAtomicFence.order = 1;
+  assert(theAtomicFence.order === 1);
+  theAtomicFence.type = binaryen.f64;
+  theAtomicFence.finalize();
+  assert(theAtomicFence.type === binaryen.none);
+
+  console.log(theAtomicFence.toText());
+  assert(
+    theAtomicFence.toText()
+    ==
+    "(atomic.fence)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# SIMDExtract");
+(function testSIMDExtract() {
+  const module = new binaryen.Module();
+
+  var op = binaryen.Operations.ExtractLaneSVecI8x16;
+  var vec = module.v128.const([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]);
+  var index = 0;
+  const theSIMDExtract = binaryen.SIMDExtract(module.i8x16.extract_lane_s(vec, index));
+  assert(theSIMDExtract instanceof binaryen.SIMDExtract);
+  assert(theSIMDExtract instanceof binaryen.Expression);
+  assert(theSIMDExtract.op === op);
+  assert(theSIMDExtract.vec === vec);
+  assert(theSIMDExtract.index === index);
+  assert(theSIMDExtract.type === binaryen.i32);
+
+  theSIMDExtract.op = op = binaryen.Operations.ExtractLaneSVecI16x8;
+  assert(theSIMDExtract.op === op);
+  theSIMDExtract.vec = vec = module.v128.const([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]);
+  assert(theSIMDExtract.vec === vec);
+  theSIMDExtract.index = index = 1;
+  assert(theSIMDExtract.index === index);
+  theSIMDExtract.type = binaryen.f64;
+  theSIMDExtract.finalize();
+  assert(theSIMDExtract.type === binaryen.i32);
+
+  console.log(theSIMDExtract.toText());
+  assert(
+    theSIMDExtract.toText()
+    ==
+    "(i16x8.extract_lane_s 1\n (v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# SIMDReplace");
+(function testSIMDReplace() {
+  const module = new binaryen.Module();
+
+  var op = binaryen.Operations.ReplaceLaneVecI8x16;
+  var vec = module.v128.const([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]);
+  var index = 0;
+  var value = module.i32.const(1);
+  const theSIMDReplace = binaryen.SIMDReplace(module.i8x16.replace_lane(vec, index, value));
+  assert(theSIMDReplace instanceof binaryen.SIMDReplace);
+  assert(theSIMDReplace instanceof binaryen.Expression);
+  assert(theSIMDReplace.op === op);
+  assert(theSIMDReplace.vec === vec);
+  assert(theSIMDReplace.index === index);
+  assert(theSIMDReplace.value === value);
+  assert(theSIMDReplace.type === binaryen.v128);
+
+  theSIMDReplace.op = op = binaryen.Operations.ReplaceLaneVecI16x8;
+  assert(theSIMDReplace.op === op);
+  theSIMDReplace.vec = vec = module.v128.const([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]);
+  assert(theSIMDReplace.vec === vec);
+  theSIMDReplace.index = index = 1;
+  assert(theSIMDReplace.index === index);
+  theSIMDReplace.value = value = module.i32.const(2);
+  assert(theSIMDReplace.value === value);
+  theSIMDReplace.type = binaryen.f64;
+  theSIMDReplace.finalize();
+  assert(theSIMDReplace.type === binaryen.v128);
+
+  console.log(theSIMDReplace.toText());
+  assert(
+    theSIMDReplace.toText()
+    ==
+    "(i16x8.replace_lane 1\n (v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)\n (i32.const 2)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# SIMDShuffle");
+(function testSIMDShuffle() {
+  const module = new binaryen.Module();
+
+  var left = module.v128.const([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]);
+  var right = module.v128.const([2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]);
+  var mask = [3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18];
+  const theSIMDShuffle = binaryen.SIMDShuffle(module.v8x16.shuffle(left, right, mask));
+  assert(theSIMDShuffle instanceof binaryen.SIMDShuffle);
+  assert(theSIMDShuffle instanceof binaryen.Expression);
+  assert(theSIMDShuffle.left === left);
+  assert(theSIMDShuffle.right === right);
+  assertDeepEqual(theSIMDShuffle.mask, mask);
+  assert(theSIMDShuffle.type === binaryen.v128);
+
+  theSIMDShuffle.left = left = module.v128.const([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]);
+  assert(theSIMDShuffle.left === left);
+  theSIMDShuffle.right = right = module.v128.const([2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]);
+  assert(theSIMDShuffle.right === right);
+  theSIMDShuffle.mask = mask = [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3];
+  assertDeepEqual(theSIMDShuffle.mask, mask);
+  theSIMDShuffle.type = binaryen.f64;
+  theSIMDShuffle.finalize();
+  assert(theSIMDShuffle.type === binaryen.v128);
+
+  console.log(theSIMDShuffle.toText());
+  assert(
+    theSIMDShuffle.toText()
+    ==
+    "(v8x16.shuffle 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3\n (v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)\n (v128.const i32x4 0x02020202 0x02020202 0x02020202 0x02020202)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# SIMDTernary");
+(function testSIMDTernary() {
+  const module = new binaryen.Module();
+
+  var op = binaryen.Operations.BitselectVec128;
+  var a = module.v128.const([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]);
+  var b = module.v128.const([2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]);
+  var c = module.v128.const([3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]);
+  const theSIMDTernary = binaryen.SIMDTernary(module.v128.bitselect(a, b, c));
+  assert(theSIMDTernary instanceof binaryen.SIMDTernary);
+  assert(theSIMDTernary instanceof binaryen.Expression);
+  assert(theSIMDTernary.op === op);
+  assert(theSIMDTernary.a === a);
+  assert(theSIMDTernary.b === b);
+  assert(theSIMDTernary.c === c);
+  assert(theSIMDTernary.type === binaryen.v128);
+
+  theSIMDTernary.op = op = binaryen.Operations.QFMAVecF64x2;
+  assert(theSIMDTernary.op === op);
+  theSIMDTernary.a = a = module.v128.const([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]);
+  assert(theSIMDTernary.a === a);
+  theSIMDTernary.b = b = module.v128.const([2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]);
+  assert(theSIMDTernary.b === b);
+  theSIMDTernary.c = c = module.v128.const([3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]);
+  assert(theSIMDTernary.c === c);
+  theSIMDTernary.type = binaryen.f64;
+  theSIMDTernary.finalize();
+  assert(theSIMDTernary.type === binaryen.v128);
+
+  console.log(theSIMDTernary.toText());
+  assert(
+    theSIMDTernary.toText()
+    ==
+    "(f64x2.qfma\n (v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)\n (v128.const i32x4 0x02020202 0x02020202 0x02020202 0x02020202)\n (v128.const i32x4 0x03030303 0x03030303 0x03030303 0x03030303)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# SIMDShift");
+(function testSIMDShift() {
+  const module = new binaryen.Module();
+
+  var op = binaryen.Operations.BitselectVec128;
+  var vec = module.v128.const([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]);
+  var shift = module.i32.const(1);
+  const theSIMDShift = binaryen.SIMDShift(module.i8x16.shl(vec, shift));
+  assert(theSIMDShift instanceof binaryen.SIMDShift);
+  assert(theSIMDShift instanceof binaryen.Expression);
+  assert(theSIMDShift.op === op);
+  assert(theSIMDShift.vec === vec);
+  assert(theSIMDShift.shift === shift);
+  assert(theSIMDShift.type === binaryen.v128);
+
+  theSIMDShift.op = op = binaryen.Operations.ShrSVecI8x16;
+  assert(theSIMDShift.op === op);
+  theSIMDShift.vec = vec = module.v128.const([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]);
+  assert(theSIMDShift.vec === vec);
+  theSIMDShift.shift = shift = module.i32.const(2);
+  assert(theSIMDShift.shift === shift);
+  theSIMDShift.type = binaryen.f64;
+  theSIMDShift.finalize();
+  assert(theSIMDShift.type === binaryen.v128);
+
+  console.log(theSIMDShift.toText());
+  assert(
+    theSIMDShift.toText()
+    ==
+    "(i8x16.shr_s\n (v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)\n (i32.const 2)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# SIMDLoad");
+(function testSIMDLoad() {
+  const module = new binaryen.Module();
+
+  var op = binaryen.Operations.LoadExtSVec8x8ToVecI16x8;
+  var offset = 16;
+  var align = 2;
+  var ptr = module.i32.const(1);
+  const theSIMDLoad = binaryen.SIMDLoad(module.i16x8.load8x8_s(offset, align, ptr));
+  assert(theSIMDLoad instanceof binaryen.SIMDLoad);
+  assert(theSIMDLoad instanceof binaryen.Expression);
+  assert(theSIMDLoad.offset === offset);
+  assert(theSIMDLoad.align === align);
+  assert(theSIMDLoad.ptr === ptr);
+  assert(theSIMDLoad.type === binaryen.v128);
+
+  theSIMDLoad.op = op = binaryen.Operations.LoadSplatVec8x16;
+  assert(theSIMDLoad.op === op);
+  theSIMDLoad.offset = offset = 32;
+  assert(theSIMDLoad.offset === offset);
+  theSIMDLoad.align = align = 4;
+  assert(theSIMDLoad.align === align);
+  theSIMDLoad.ptr = ptr = module.i32.const(2);
+  assert(theSIMDLoad.ptr === ptr);
+  theSIMDLoad.type = binaryen.f64;
+  theSIMDLoad.finalize();
+  assert(theSIMDLoad.type === binaryen.v128);
+
+  console.log(theSIMDLoad.toText());
+  assert(
+    theSIMDLoad.toText()
+    ==
+    "(v8x16.load_splat offset=32 align=4\n (i32.const 2)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# MemoryInit");
+(function testMemoryInit() {
+  const module = new binaryen.Module();
+
+  var segment = 1;
+  var dest = module.i32.const(2);
+  var offset = module.i32.const(3);
+  var size = module.i32.const(4);
+  const theMemoryInit = binaryen.MemoryInit(module.memory.init(segment, dest, offset, size));
+  assert(theMemoryInit instanceof binaryen.MemoryInit);
+  assert(theMemoryInit instanceof binaryen.Expression);
+  assert(theMemoryInit.segment === segment);
+  assert(theMemoryInit.dest === dest);
+  assert(theMemoryInit.offset === offset);
+  assert(theMemoryInit.size === size);
+  assert(theMemoryInit.type === binaryen.none);
+
+  theMemoryInit.segment = segment = 5;
+  assert(theMemoryInit.segment === 5);
+  theMemoryInit.dest = dest = module.i32.const(6);
+  assert(theMemoryInit.dest === dest);
+  theMemoryInit.offset = offset = module.i32.const(7);
+  assert(theMemoryInit.offset === offset);
+  theMemoryInit.size = size = module.i32.const(8);
+  assert(theMemoryInit.size === size);
+  theMemoryInit.type = binaryen.f64;
+  theMemoryInit.finalize();
+  assert(theMemoryInit.type === binaryen.none);
+
+  console.log(theMemoryInit.toText());
+  assert(
+    theMemoryInit.toText()
+    ==
+    "(memory.init 5\n (i32.const 6)\n (i32.const 7)\n (i32.const 8)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# DataDrop");
+(function testDataDrop() {
+  const module = new binaryen.Module();
+
+  var segment = 1;
+  const theDataDrop = binaryen.DataDrop(module.data.drop(segment));
+  assert(theDataDrop instanceof binaryen.DataDrop);
+  assert(theDataDrop instanceof binaryen.Expression);
+  assert(theDataDrop.segment === segment);
+  assert(theDataDrop.type === binaryen.none);
+
+  theDataDrop.segment = segment = 2;
+  assert(theDataDrop.segment === 2);
+  theDataDrop.type = binaryen.f64;
+  theDataDrop.finalize();
+  assert(theDataDrop.type === binaryen.none);
+
+  console.log(theDataDrop.toText());
+  assert(
+    theDataDrop.toText()
+    ==
+    "(data.drop 2)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# MemoryCopy");
+(function testMemoryCopy() {
+  const module = new binaryen.Module();
+
+  var dest = module.i32.const(1);
+  var source = module.i32.const(2);
+  var size = module.i32.const(3);
+  const theMemoryCopy = binaryen.MemoryCopy(module.memory.copy(dest, source, size));
+  assert(theMemoryCopy instanceof binaryen.MemoryCopy);
+  assert(theMemoryCopy instanceof binaryen.Expression);
+  assert(theMemoryCopy.dest === dest);
+  assert(theMemoryCopy.source === source);
+  assert(theMemoryCopy.size === size);
+  assert(theMemoryCopy.type === binaryen.none);
+
+  theMemoryCopy.dest = dest = module.i32.const(4);
+  assert(theMemoryCopy.dest === dest);
+  theMemoryCopy.source = source = module.i32.const(5);
+  assert(theMemoryCopy.source === source);
+  theMemoryCopy.size = size = module.i32.const(6);
+  assert(theMemoryCopy.size === size);
+  theMemoryCopy.type = binaryen.f64;
+  theMemoryCopy.finalize();
+  assert(theMemoryCopy.type === binaryen.none);
+
+  console.log(theMemoryCopy.toText());
+  assert(
+    theMemoryCopy.toText()
+    ==
+    "(memory.copy\n (i32.const 4)\n (i32.const 5)\n (i32.const 6)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# MemoryFill");
+(function testMemoryFill() {
+  const module = new binaryen.Module();
+
+  var dest = module.i32.const(1);
+  var value = module.i32.const(2);
+  var size = module.i32.const(3);
+  const theMemoryFill = binaryen.MemoryFill(module.memory.fill(dest, value, size));
+  assert(theMemoryFill instanceof binaryen.MemoryFill);
+  assert(theMemoryFill instanceof binaryen.Expression);
+  assert(theMemoryFill.dest === dest);
+  assert(theMemoryFill.value === value);
+  assert(theMemoryFill.size === size);
+  assert(theMemoryFill.type === binaryen.none);
+
+  theMemoryFill.dest = dest = module.i32.const(4);
+  assert(theMemoryFill.dest === dest);
+  theMemoryFill.value = value = module.i32.const(5);
+  assert(theMemoryFill.value === value);
+  theMemoryFill.size = size = module.i32.const(6);
+  assert(theMemoryFill.size === size);
+  theMemoryFill.type = binaryen.f64;
+  theMemoryFill.finalize();
+  assert(theMemoryFill.type === binaryen.none);
+
+  console.log(theMemoryFill.toText());
+  assert(
+    theMemoryFill.toText()
+    ==
+    "(memory.fill\n (i32.const 4)\n (i32.const 5)\n (i32.const 6)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# RefIsNull");
+(function testRefIsNull() {
+  const module = new binaryen.Module();
+
+  var value = module.local.get(1, binaryen.externref);
+  const theRefIsNull = binaryen.RefIsNull(module.ref.is_null(value));
+  assert(theRefIsNull instanceof binaryen.RefIsNull);
+  assert(theRefIsNull instanceof binaryen.Expression);
+  assert(theRefIsNull.value === value);
+  assert(theRefIsNull.type === binaryen.i32);
+
+  theRefIsNull.value = value = module.local.get(2, binaryen.externref);
+  assert(theRefIsNull.value === value);
+  theRefIsNull.type = binaryen.f64;
+  theRefIsNull.finalize();
+  assert(theRefIsNull.type === binaryen.i32);
+
+  console.log(theRefIsNull.toText());
+  assert(
+    theRefIsNull.toText()
+    ==
+    "(ref.is_null\n (local.get $2)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# RefFunc");
+(function testRefFunc() {
+  const module = new binaryen.Module();
+
+  var func = "a";
+  const theRefFunc = binaryen.RefFunc(module.ref.func(func));
+  assert(theRefFunc instanceof binaryen.RefFunc);
+  assert(theRefFunc instanceof binaryen.Expression);
+  assert(theRefFunc.func === func);
+  assert(theRefFunc.type === binaryen.funcref);
+
+  theRefFunc.func = func = "b";
+  assert(theRefFunc.func === func);
+  theRefFunc.type = binaryen.f64;
+  theRefFunc.finalize();
+  assert(theRefFunc.type === binaryen.funcref);
+
+  console.log(theRefFunc.toText());
+  assert(
+    theRefFunc.toText()
+    ==
+    "(ref.func $b)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# RefEq");
+(function testRefEq() {
+  const module = new binaryen.Module();
+
+  var left = module.local.get(0, binaryen.eqref);
+  var right = module.local.get(1, binaryen.eqref);
+  const theRefEq = binaryen.RefEq(module.ref.eq(left, right));
+  assert(theRefEq instanceof binaryen.RefEq);
+  assert(theRefEq instanceof binaryen.Expression);
+  assert(theRefEq.left === left);
+  assert(theRefEq.right === right);
+  assert(theRefEq.type === binaryen.i32);
+
+  theRefEq.left = left = module.local.get(2, binaryen.eqref);
+  assert(theRefEq.left === left);
+  theRefEq.right = right = module.local.get(3, binaryen.eqref);
+  assert(theRefEq.right === right);
+  theRefEq.type = binaryen.f64;
+  theRefEq.finalize();
+  assert(theRefEq.type === binaryen.i32);
+
+  console.log(theRefEq.toText());
+  assert(
+    theRefEq.toText()
+    ==
+    "(ref.eq\n (local.get $2)\n (local.get $3)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# Try");
+(function testTry() {
+  const module = new binaryen.Module();
+
+  var body = module.i32.const(1);
+  var catchBody = module.i32.const(2);
+  const theTry = binaryen.Try(module.try(body, catchBody));
+  assert(theTry instanceof binaryen.Try);
+  assert(theTry instanceof binaryen.Expression);
+  assert(theTry.body === body);
+  assert(theTry.catchBody === catchBody);
+  assert(theTry.type === binaryen.i32);
+
+  theTry.body = body = module.i32.const(3);
+  assert(theTry.body === body);
+  theTry.catchBody = catchBody = module.i32.const(4);
+  assert(theTry.catchBody === catchBody);
+  theTry.type = binaryen.f64;
+  theTry.finalize();
+  assert(theTry.type === binaryen.i32);
+
+  console.log(theTry.toText());
+  assert(
+    theTry.toText()
+    ==
+    "(try (result i32)\n (do\n  (i32.const 3)\n )\n (catch\n  (i32.const 4)\n )\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# Throw");
+(function testThrow() {
+  const module = new binaryen.Module();
+
+  var event = "foo";
+  var operands = [
+    module.i32.const(1),
+    module.i32.const(2)
+  ];
+  const theThrow = binaryen.Throw(module.throw(event, operands));
+  assert(theThrow instanceof binaryen.Throw);
+  assert(theThrow instanceof binaryen.Expression);
+  assert(theThrow.event === event);
+  assertDeepEqual(theThrow.operands, operands);
+  assert(theThrow.type === binaryen.unreachable);
+
+  theThrow.event = "bar";
+  assert(theThrow.event === "bar");
+  theThrow.operands = operands = [
+    module.i32.const(3), // set
+    module.i32.const(4), // set
+    module.i32.const(5)  // append
+  ];
+  assertDeepEqual(theThrow.operands, operands);
+  theThrow.operands = operands = [
+    module.i32.const(6) // set
+    // remove
+    // remove
+  ];
+  assertDeepEqual(theThrow.operands, operands);
+  theThrow.insertOperandAt(1, module.i32.const(7));
+  theThrow.type = binaryen.f64;
+  theThrow.finalize();
+  assert(theThrow.type === binaryen.unreachable);
+
+  console.log(theThrow.toText());
+  assert(
+    theThrow.toText()
+    ==
+    "(throw $bar\n (i32.const 6)\n (i32.const 7)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# Rethrow");
+(function testRethrow() {
+  const module = new binaryen.Module();
+
+  var exnref = module.local.get(1, binaryen.exnref);
+  const theRethrow = binaryen.Rethrow(module.rethrow(exnref));
+  assert(theRethrow instanceof binaryen.Rethrow);
+  assert(theRethrow instanceof binaryen.Expression);
+  assert(theRethrow.exnref === exnref);
+  assert(theRethrow.type === binaryen.unreachable);
+
+  theRethrow.exnref = exnref = module.local.get(2, binaryen.exnref);
+  assert(theRethrow.exnref === exnref);
+  theRethrow.type = binaryen.f64;
+  theRethrow.finalize();
+  assert(theRethrow.type === binaryen.unreachable);
+
+  console.log(theRethrow.toText());
+  assert(
+    theRethrow.toText()
+    ==
+    "(rethrow\n (local.get $2)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# BrOnExn");
+(function testBrOnExn() {
+  const module = new binaryen.Module();
+  module.addEvent("event1", 0, binaryen.none, binaryen.none);
+  module.addEvent("event2", 0, binaryen.none, binaryen.none);
+
+  var name = "foo";
+  var event = "event1";
+  var exnref = module.local.get(1, binaryen.exnref);
+  const theBrOnExn = binaryen.BrOnExn(module.br_on_exn(name, event, exnref));
+  assert(theBrOnExn instanceof binaryen.BrOnExn);
+  assert(theBrOnExn instanceof binaryen.Expression);
+  assert(theBrOnExn.name === name);
+  assert(theBrOnExn.event === event);
+  assert(theBrOnExn.exnref === exnref);
+  assert(theBrOnExn.type === binaryen.exnref);
+
+  theBrOnExn.name = name = "bar";
+  assert(theBrOnExn.name === name);
+  theBrOnExn.event = event = "event2";
+  assert(theBrOnExn.event === event);
+  theBrOnExn.exnref = exnref = module.local.get(2, binaryen.exnref);
+  assert(theBrOnExn.exnref === exnref);
+  theBrOnExn.type = binaryen.f64;
+  theBrOnExn.finalize();
+  assert(theBrOnExn.type === binaryen.exnref);
+
+  console.log(theBrOnExn.toText());
+  assert(
+    theBrOnExn.toText()
+    ==
+    "(br_on_exn $bar $event2\n (local.get $2)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# TupleMake");
+(function testTupleMake() {
+  const module = new binaryen.Module();
+
+  var operands = [
+    module.i32.const(1),
+    module.i32.const(2)
+  ];
+  var type = binaryen.createType([ binaryen.i32, binaryen.i32 ]);
+  const theTupleMake = binaryen.TupleMake(module.tuple.make(operands));
+  assert(theTupleMake instanceof binaryen.TupleMake);
+  assert(theTupleMake instanceof binaryen.Expression);
+  assertDeepEqual(theTupleMake.operands, operands);
+  assert(theTupleMake.type === type);
+
+  theTupleMake.operands = operands = [
+    module.i32.const(3), // set
+    module.i32.const(4), // set
+    module.i32.const(5)  // append
+  ];
+  assertDeepEqual(theTupleMake.operands, operands);
+  theTupleMake.operands = operands = [
+    module.i32.const(6) // set
+    // remove
+    // remove
+  ];
+  assertDeepEqual(theTupleMake.operands, operands);
+  theTupleMake.insertOperandAt(1, module.i32.const(7));
+  theTupleMake.type = binaryen.f64;
+  theTupleMake.finalize();
+  assert(theTupleMake.type === type);
+
+  console.log(theTupleMake.toText());
+  assert(
+    theTupleMake.toText()
+    ==
+    "(tuple.make\n (i32.const 6)\n (i32.const 7)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# TupleExtract");
+(function testTupleExtract() {
+  const module = new binaryen.Module();
+
+  var tuple = module.tuple.make([
+    module.i32.const(1),
+    module.i32.const(2)
+  ]);
+  var index = 1;
+  const theTupleExtract = binaryen.TupleExtract(module.tuple.extract(tuple, index));
+  assert(theTupleExtract instanceof binaryen.TupleExtract);
+  assert(theTupleExtract instanceof binaryen.Expression);
+  assert(theTupleExtract.tuple === tuple);
+  assert(theTupleExtract.index === index);
+  assert(theTupleExtract.type === binaryen.i32);
+
+  theTupleExtract.tuple = tuple = module.tuple.make([
+    module.f64.const(3),
+    module.f64.const(4)
+  ]);
+  assert(theTupleExtract.tuple === tuple);
+  theTupleExtract.index = index = 0;
+  assert(theTupleExtract.index === index);
+  theTupleExtract.type = binaryen.i32;
+  theTupleExtract.finalize();
+  assert(theTupleExtract.type === binaryen.f64);
+
+  console.log(theTupleExtract.toText());
+  assert(
+    theTupleExtract.toText()
+    ==
+    "(tuple.extract 0\n (tuple.make\n  (f64.const 3)\n  (f64.const 4)\n )\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# I31New");
+(function testI31New() {
+  const module = new binaryen.Module();
+
+  var value = module.local.get(1, binaryen.i32);
+  const theI31New = binaryen.I31New(module.i31.new(value));
+  assert(theI31New instanceof binaryen.I31New);
+  assert(theI31New instanceof binaryen.Expression);
+  assert(theI31New.value === value);
+  assert(theI31New.type === binaryen.i31ref);
+
+  theI31New.value = value = module.local.get(2, binaryen.i32);
+  assert(theI31New.value === value);
+  theI31New.type = binaryen.f64;
+  theI31New.finalize();
+  assert(theI31New.type === binaryen.i31ref);
+
+  console.log(theI31New.toText());
+  assert(
+    theI31New.toText()
+    ==
+    "(i31.new\n (local.get $2)\n)\n"
+  );
+
+  module.dispose();
+})();
+
+console.log("# I31Get");
+(function testI31Get() {
+  const module = new binaryen.Module();
+
+  var i31 = module.local.get(1, binaryen.i31ref);
+  const theI31Get = binaryen.I31Get(module.i31.get_s(i31));
+  assert(theI31Get instanceof binaryen.I31Get);
+  assert(theI31Get instanceof binaryen.Expression);
+  assert(theI31Get.i31 === i31);
+  assert(theI31Get.signed === true);
+  assert(theI31Get.type === binaryen.i32);
+
+  theI31Get.i31 = i31 = module.local.get(2, binaryen.i31ref);
+  assert(theI31Get.i31 === i31);
+  theI31Get.signed = false;
+  assert(theI31Get.signed === false);
+  theI31Get.type = binaryen.f64;
+  theI31Get.finalize();
+  assert(theI31Get.type === binaryen.i32);
+
+  console.log(theI31Get.toText());
+  assert(
+    theI31Get.toText()
+    ==
+    "(i31.get_u\n (local.get $2)\n)\n"
+  );
+
+  module.dispose();
+})();
diff --git a/binaryen/test/binaryen.js/expressions.js.txt b/binaryen/test/binaryen.js/expressions.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/expressions.js.txt
@@ -0,0 +1,268 @@
+# Expression
+# Block
+(block $theName (result i32)
+ (i32.const 0)
+)
+
+# If
+(if (result i32)
+ (i32.const 4)
+ (i32.const 5)
+ (i32.const 6)
+)
+
+(if (result i32)
+ (i32.const 4)
+ (i32.const 5)
+)
+
+# Loop
+(loop $theName
+ (drop
+  (i32.const 1)
+ )
+)
+
+# Break
+(br_if $theNewName
+ (i32.const 4)
+ (i32.const 3)
+)
+
+# Switch
+(br_table $x $y $c
+ (i32.const 4)
+ (i32.const 3)
+)
+
+# Call
+(call $bar
+ (i32.const 7)
+ (i32.const 6)
+)
+
+# CallIndirect
+(call_indirect (type $i32_i32_=>_i32)
+ (i32.const 7)
+ (i32.const 6)
+ (i32.const 9000)
+)
+
+# LocalGet
+(local.get $2)
+
+# LocalSet
+(local.set $2
+ (i32.const 3)
+)
+
+# GlobalGet
+(global.get $b)
+
+# GlobalSet
+(global.set $b
+ (f64.const 3)
+)
+
+# MemorySize
+(memory.size)
+
+# MemoryGrow
+(memory.grow
+ (i32.const 2)
+)
+
+# Load
+(i64.atomic.load offset=32 align=4
+ (i32.const 128)
+)
+
+# Store
+(i64.atomic.store offset=32 align=4
+ (i32.const 128)
+ (i32.const 2)
+)
+
+# Const
+(v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+
+# Unary
+(i64.eqz
+ (i64.const 2)
+)
+
+# Binary
+(i64.add
+ (i64.const 3)
+ (i64.const 4)
+)
+
+# Select
+(select
+ (i64.const 5)
+ (i64.const 6)
+ (i32.const 4)
+)
+
+# Drop
+(drop
+ (i32.const 2)
+)
+
+# Return
+(return
+ (i32.const 2)
+)
+
+# AtomicRMW
+(i64.atomic.rmw16.sub_u offset=16
+ (i32.const 4)
+ (i64.const 5)
+)
+
+# AtomicCmpxchg
+(i64.atomic.rmw16.cmpxchg_u offset=16
+ (i32.const 5)
+ (i64.const 6)
+ (i64.const 7)
+)
+
+# AtomicWait
+(i64.atomic.wait
+ (i32.const 5)
+ (i32.const 6)
+ (i64.const 7)
+)
+
+# AtomicNotify
+(atomic.notify
+ (i32.const 3)
+ (i32.const 4)
+)
+
+# AtomicFence
+(atomic.fence)
+
+# SIMDExtract
+(i16x8.extract_lane_s 1
+ (v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)
+)
+
+# SIMDReplace
+(i16x8.replace_lane 1
+ (v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)
+ (i32.const 2)
+)
+
+# SIMDShuffle
+(v8x16.shuffle 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
+ (v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)
+ (v128.const i32x4 0x02020202 0x02020202 0x02020202 0x02020202)
+)
+
+# SIMDTernary
+(f64x2.qfma
+ (v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)
+ (v128.const i32x4 0x02020202 0x02020202 0x02020202 0x02020202)
+ (v128.const i32x4 0x03030303 0x03030303 0x03030303 0x03030303)
+)
+
+# SIMDShift
+(i8x16.shr_s
+ (v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)
+ (i32.const 2)
+)
+
+# SIMDLoad
+(v8x16.load_splat offset=32 align=4
+ (i32.const 2)
+)
+
+# MemoryInit
+(memory.init 5
+ (i32.const 6)
+ (i32.const 7)
+ (i32.const 8)
+)
+
+# DataDrop
+(data.drop 2)
+
+# MemoryCopy
+(memory.copy
+ (i32.const 4)
+ (i32.const 5)
+ (i32.const 6)
+)
+
+# MemoryFill
+(memory.fill
+ (i32.const 4)
+ (i32.const 5)
+ (i32.const 6)
+)
+
+# RefIsNull
+(ref.is_null
+ (local.get $2)
+)
+
+# RefFunc
+(ref.func $b)
+
+# RefEq
+(ref.eq
+ (local.get $2)
+ (local.get $3)
+)
+
+# Try
+(try (result i32)
+ (do
+  (i32.const 3)
+ )
+ (catch
+  (i32.const 4)
+ )
+)
+
+# Throw
+(throw $bar
+ (i32.const 6)
+ (i32.const 7)
+)
+
+# Rethrow
+(rethrow
+ (local.get $2)
+)
+
+# BrOnExn
+(br_on_exn $bar $event2
+ (local.get $2)
+)
+
+# TupleMake
+(tuple.make
+ (i32.const 6)
+ (i32.const 7)
+)
+
+# TupleExtract
+(tuple.extract 0
+ (tuple.make
+  (f64.const 3)
+  (f64.const 4)
+ )
+)
+
+# I31New
+(i31.new
+ (local.get $2)
+)
+
+# I31Get
+(i31.get_u
+ (local.get $2)
+)
+
diff --git a/binaryen/test/binaryen.js/fast-math.js b/binaryen/test/binaryen.js/fast-math.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/fast-math.js
@@ -0,0 +1,3 @@
+console.log("// fastMath=" + binaryen.getFastMath());
+binaryen.setFastMath(true);
+assert(binaryen.getFastMath() == true);
diff --git a/binaryen/test/binaryen.js/fast-math.js.txt b/binaryen/test/binaryen.js/fast-math.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/fast-math.js.txt
@@ -0,0 +1,1 @@
+// fastMath=false
diff --git a/binaryen/test/binaryen.js/functions.js b/binaryen/test/binaryen.js/functions.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/functions.js
@@ -0,0 +1,75 @@
+function cleanInfo(info) {
+  var ret = {};
+  for (var x in info) {
+    if (x !== 'name' && x !== 'body' && x !== 'type') {
+      ret[x] = info[x];
+    }
+  }
+  return ret;
+}
+
+var module = new binaryen.Module();
+
+var func = module.addFunction("a-function", binaryen.none, binaryen.i32, [],
+  module.i32.add(
+    module.i32.const(1),
+    module.i32.const(2)
+  )
+);
+
+console.log("GetFunction is equal: " + (func === module.getFunction("a-function")));
+
+module.runPassesOnFunction(func, ["precompute"]);
+
+var funcInfo = binaryen.getFunctionInfo(func);
+console.log("getFunctionInfo=" + JSON.stringify(cleanInfo(funcInfo)));
+var expInfo = binaryen.getExpressionInfo(funcInfo.body);
+console.log("getExpressionInfo(body)=" + JSON.stringify(cleanInfo(expInfo)));
+console.log(binaryen.emitText(funcInfo.body));
+
+module.removeFunction("a-function");
+
+assert(module.validate());
+
+console.log(module.emitText());
+
+// Test wrapper
+
+func = module.addFunction("b-function",
+  binaryen.createType([binaryen.i32, binaryen.i32]),
+  binaryen.i32,
+  [ binaryen.i32, binaryen.f64 ],
+  module.local.tee(2,
+    module.i32.add(
+      module.local.get(0, binaryen.i32),
+      module.local.get(1, binaryen.i32)
+    ),
+    binaryen.i32
+  )
+);
+binaryen.Function.setLocalName(func, 0, "a");
+binaryen.Function.setLocalName(func, 1, "b");
+binaryen.Function.setLocalName(func, 2, "ret");
+binaryen.Function.setLocalName(func, 3, "unused");
+
+var theFunc = binaryen.Function(func);
+assert(theFunc.name === "b-function");
+assert(theFunc.params === binaryen.createType([binaryen.i32, binaryen.i32]));
+assert(theFunc.results === binaryen.i32);
+assert(theFunc.numVars === 2);
+assert(theFunc.getVar(0) === binaryen.i32);
+assert(theFunc.getVar(1) === binaryen.f64);
+assert(theFunc.numLocals === 4);
+assert(theFunc.getLocalName(0) === "a");
+assert(theFunc.getLocalName(1) === "b");
+assert(theFunc.getLocalName(2) === "ret");
+assert(theFunc.getLocalName(3) === "unused");
+theFunc.setLocalName(2, "res");
+assert(theFunc.getLocalName(2) === "res");
+assert((theFunc | 0) === func);
+
+assert(module.validate());
+
+console.log(module.emitText());
+
+module.dispose();
diff --git a/binaryen/test/binaryen.js/functions.js.txt b/binaryen/test/binaryen.js/functions.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/functions.js.txt
@@ -0,0 +1,22 @@
+GetFunction is equal: true
+getFunctionInfo={"module":"","base":"","params":0,"results":2,"vars":[]}
+getExpressionInfo(body)={"id":14,"value":3}
+(i32.const 3)
+
+(module
+)
+
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (func $b-function (param $a i32) (param $b i32) (result i32)
+  (local $res i32)
+  (local $unused f64)
+  (local.tee $res
+   (i32.add
+    (local.get $a)
+    (local.get $b)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/binaryen.js/global.js b/binaryen/test/binaryen.js/global.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/global.js
@@ -0,0 +1,37 @@
+function cleanInfo(info) {
+  var ret = {};
+  for (var x in info) {
+    if (x !== 'name' && x !== 'body' && x !== 'type' && x !== 'init') {
+      ret[x] = info[x];
+    }
+  }
+  return ret;
+}
+
+var module = new binaryen.Module();
+module.setFeatures(binaryen.Features.MVP | binaryen.Features.MutableGlobals);
+
+var initExpr = module.i32.const(1);
+var global = module.addGlobal("a-global", binaryen.i32, false, initExpr);
+
+console.log("GetGlobal is equal: " + (global === module.getGlobal("a-global")));
+
+var globalInfo = binaryen.getGlobalInfo(global);
+console.log("getGlobalInfo=" + JSON.stringify(cleanInfo(globalInfo)));
+
+var initExpInfo = binaryen.getExpressionInfo(globalInfo.init);
+console.log("getExpressionInfo(init)=" + JSON.stringify(cleanInfo(initExpInfo)));
+console.log(binaryen.emitText(globalInfo.init));
+
+module.addGlobalExport("a-global", "a-global-exp");
+module.addGlobalImport("a-global-imp", "module", "base", binaryen.i32, false);
+module.addGlobalImport("a-mut-global-imp", "module", "base", binaryen.i32, true);
+
+assert(module.validate());
+console.log(module.emitText());
+
+module.removeGlobal("a-global");
+module.removeExport("a-global-exp");
+
+assert(module.validate());
+console.log(module.emitText());
diff --git a/binaryen/test/binaryen.js/global.js.txt b/binaryen/test/binaryen.js/global.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/global.js.txt
@@ -0,0 +1,17 @@
+GetGlobal is equal: true
+getGlobalInfo={"module":"","base":"","mutable":false}
+getExpressionInfo(init)={"id":14,"value":1}
+(i32.const 1)
+
+(module
+ (import "module" "base" (global $a-global-imp i32))
+ (import "module" "base" (global $a-mut-global-imp (mut i32)))
+ (global $a-global i32 (i32.const 1))
+ (export "a-global-exp" (global $a-global))
+)
+
+(module
+ (import "module" "base" (global $a-global-imp i32))
+ (import "module" "base" (global $a-mut-global-imp (mut i32)))
+)
+
diff --git a/binaryen/test/binaryen.js/hello-world.js b/binaryen/test/binaryen.js/hello-world.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/hello-world.js
@@ -0,0 +1,49 @@
+// "hello world" type example: create a function that adds two i32s and
+// returns the result
+
+// Create a module to work on
+var module = new binaryen.Module();
+
+// Start to create the function, starting with the contents: Get the 0 and
+// 1 arguments, and add them, then return them
+var left = module.local.get(0, binaryen.i32);
+var right = module.local.get(1, binaryen.i32);
+var add = module.i32.add(left, right);
+var ret = module.return(add);
+
+// Create the add function
+// Note: no additional local variables (that's the [])
+var ii = binaryen.createType([binaryen.i32, binaryen.i32])
+module.addFunction('adder', ii, binaryen.i32, [], ret);
+
+// Export the function, so we can call it later (for simplicity we
+// export it as the same name as it has internally)
+module.addFunctionExport('adder', 'adder');
+
+// Print out the text
+console.log(module.emitText());
+
+// Optimize the module! This removes the 'return', since the
+// output of the add can just fall through
+module.optimize();
+
+// Print out the optimized module's text
+console.log('optimized:\n\n' + module.emitText());
+
+// Get the binary in typed array form
+var binary = module.emitBinary();
+console.log('binary size: ' + binary.length);
+console.log();
+assert(module.validate());
+
+// We don't need the Binaryen module anymore, so we can tell it to
+// clean itself up
+module.dispose();
+
+// Compile the binary and create an instance
+var wasm = new WebAssembly.Instance(new WebAssembly.Module(binary), {})
+console.log("exports: " + Object.keys(wasm.exports).sort().join(","));
+console.log();
+
+// Call the code!
+console.log('an addition: ' + wasm.exports.adder(40, 2));
diff --git a/binaryen/test/binaryen.js/hello-world.js.txt b/binaryen/test/binaryen.js/hello-world.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/hello-world.js.txt
@@ -0,0 +1,31 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (export "adder" (func $adder))
+ (func $adder (param $0 i32) (param $1 i32) (result i32)
+  (return
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+)
+
+optimized:
+
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (export "adder" (func $adder))
+ (func $adder (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
+
+binary size: 43
+
+exports: adder
+
+an addition: 42
diff --git a/binaryen/test/binaryen.js/inlining-options.js b/binaryen/test/binaryen.js/inlining-options.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/inlining-options.js
@@ -0,0 +1,15 @@
+console.log("// alwaysInlineMaxSize=" + binaryen.getAlwaysInlineMaxSize());
+binaryen.setAlwaysInlineMaxSize(11);
+assert(binaryen.getAlwaysInlineMaxSize() == 11);
+
+console.log("// flexibleInlineMaxSize=" + binaryen.getFlexibleInlineMaxSize());
+binaryen.setFlexibleInlineMaxSize(22);
+assert(binaryen.getFlexibleInlineMaxSize() == 22);
+
+console.log("// oneCallerInlineMaxSize=" + binaryen.getOneCallerInlineMaxSize());
+binaryen.setOneCallerInlineMaxSize(33);
+assert(binaryen.getOneCallerInlineMaxSize() == 33);
+
+console.log("// allowInliningFunctionsWithLoops=" + binaryen.getAllowInliningFunctionsWithLoops());
+binaryen.setAllowInliningFunctionsWithLoops(true);
+assert(binaryen.getAllowInliningFunctionsWithLoops() == true);
diff --git a/binaryen/test/binaryen.js/inlining-options.js.txt b/binaryen/test/binaryen.js/inlining-options.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/inlining-options.js.txt
@@ -0,0 +1,4 @@
+// alwaysInlineMaxSize=2
+// flexibleInlineMaxSize=20
+// oneCallerInlineMaxSize=15
+// allowInliningFunctionsWithLoops=false
diff --git a/binaryen/test/binaryen.js/kitchen-sink.js b/binaryen/test/binaryen.js/kitchen-sink.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/kitchen-sink.js
@@ -0,0 +1,1098 @@
+// kitchen sink, tests the full API
+
+function cleanInfo(info) {
+  var ret = {};
+  for (var x in info) {
+    if (x !== 'value') {
+      ret[x] = info[x];
+    }
+  }
+  return ret;
+}
+
+var module;
+
+// helpers
+
+var v128_bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
+
+function makeInt32(x) {
+  return module.i32.const(x);
+}
+
+function makeFloat32(x) {
+  return module.f32.const(x);
+}
+
+function makeInt64(l, h) {
+  return module.i64.const(l, h);
+}
+
+function makeFloat64(x) {
+  return module.f64.const(x);
+}
+
+function makeVec128(i8s) {
+  return module.v128.const(i8s)
+}
+
+function makeSomething() {
+  return makeInt32(1337);
+}
+
+function makeDroppedInt32(x) {
+  return module.drop(module.i32.const(x));
+}
+
+// tests
+
+function test_types() {
+  console.log("  // BinaryenTypeNone: " + binaryen.none);
+  console.log("  //", binaryen.expandType(binaryen.none).join(","));
+
+  console.log("  // BinaryenTypeUnreachable: " + binaryen.unreachable);
+  console.log("  //", binaryen.expandType(binaryen.unreachable).join(","));
+
+  console.log("  // BinaryenTypeInt32: " + binaryen.i32);
+  console.log("  //", binaryen.expandType(binaryen.i32).join(","));
+
+  console.log("  // BinaryenTypeInt64: " + binaryen.i64);
+  console.log("  //", binaryen.expandType(binaryen.i64).join(","));
+
+  console.log("  // BinaryenTypeFloat32: " + binaryen.f32);
+  console.log("  //", binaryen.expandType(binaryen.f32).join(","));
+
+  console.log("  // BinaryenTypeFloat64: " + binaryen.f64);
+  console.log("  //", binaryen.expandType(binaryen.f64).join(","));
+
+  console.log("  // BinaryenTypeVec128: " + binaryen.v128);
+  console.log("  //", binaryen.expandType(binaryen.v128).join(","));
+
+  console.log("  // BinaryenTypeFuncref: " + binaryen.funcref);
+  console.log("  //", binaryen.expandType(binaryen.funcref).join(","));
+
+  console.log("  // BinaryenTypeExternref: " + binaryen.externref);
+  console.log("  //", binaryen.expandType(binaryen.externref).join(","));
+
+  console.log("  // BinaryenTypeExnref: " + binaryen.exnref);
+  console.log("  //", binaryen.expandType(binaryen.exnref).join(","));
+
+  console.log("  // BinaryenTypeAnyref: " + binaryen.anyref);
+  console.log("  //", binaryen.expandType(binaryen.anyref).join(","));
+
+  console.log("  // BinaryenTypeEqref: " + binaryen.eqref);
+  console.log("  //", binaryen.expandType(binaryen.eqref).join(","));
+
+  console.log("  // BinaryenTypeI31ref: " + binaryen.i31ref);
+  console.log("  //", binaryen.expandType(binaryen.i31ref).join(","));
+
+  console.log("  // BinaryenTypeAuto: " + binaryen.auto);
+
+  var i32_pair = binaryen.createType([binaryen.i32, binaryen.i32]);
+  console.log("  //", binaryen.expandType(i32_pair).join(","));
+
+  var duplicate_pair = binaryen.createType([binaryen.i32, binaryen.i32]);
+  console.log("  //", binaryen.expandType(duplicate_pair).join(","));
+
+  assert(i32_pair == duplicate_pair);
+
+  var f32_pair = binaryen.createType([binaryen.f32, binaryen.f32]);
+  console.log("  //", binaryen.expandType(f32_pair).join(","));
+}
+
+function test_features() {
+  console.log("Features.MVP: " + binaryen.Features.MVP);
+  console.log("Features.Atomics: " + binaryen.Features.Atomics);
+  console.log("Features.BulkMemory: " + binaryen.Features.BulkMemory);
+  console.log("Features.MutableGlobals: " + binaryen.Features.MutableGlobals);
+  console.log("Features.NontrappingFPToInt: " + binaryen.Features.NontrappingFPToInt);
+  console.log("Features.SignExt: " + binaryen.Features.SignExt);
+  console.log("Features.SIMD128: " + binaryen.Features.SIMD128);
+  console.log("Features.ExceptionHandling: " + binaryen.Features.ExceptionHandling);
+  console.log("Features.TailCall: " + binaryen.Features.TailCall);
+  console.log("Features.ReferenceTypes: " + binaryen.Features.ReferenceTypes);
+  console.log("Features.Multivalue: " + binaryen.Features.Multivalue);
+  console.log("Features.GC: " + binaryen.Features.GC);
+  console.log("Features.Memory64: " + binaryen.Features.Memory64);
+  console.log("Features.All: " + binaryen.Features.All);
+}
+
+function test_ids() {
+  console.log("InvalidId: " + binaryen.InvalidId);
+  console.log("BlockId: " + binaryen.BlockId);
+  console.log("IfId: " + binaryen.IfId);
+  console.log("LoopId: " + binaryen.LoopId);
+  console.log("BreakId: " + binaryen.BreakId);
+  console.log("SwitchId: " + binaryen.SwitchId);
+  console.log("CallId: " + binaryen.CallId);
+  console.log("CallIndirectId: " + binaryen.CallIndirectId);
+  console.log("LocalGetId: " + binaryen.LocalGetId);
+  console.log("LocalSetId: " + binaryen.LocalSetId);
+  console.log("GlobalGetId: " + binaryen.GlobalGetId);
+  console.log("GlobalSetId: " + binaryen.GlobalSetId);
+  console.log("LoadId: " + binaryen.LoadId);
+  console.log("StoreId: " + binaryen.StoreId);
+  console.log("ConstId: " + binaryen.ConstId);
+  console.log("UnaryId: " + binaryen.UnaryId);
+  console.log("BinaryId: " + binaryen.BinaryId);
+  console.log("SelectId: " + binaryen.SelectId);
+  console.log("DropId: " + binaryen.DropId);
+  console.log("ReturnId: " + binaryen.ReturnId);
+  console.log("MemorySizeId: " + binaryen.MemorySizeId);
+  console.log("MemoryGrowId: " + binaryen.MemoryGrowId);
+  console.log("NopId: " + binaryen.NopId);
+  console.log("UnreachableId: " + binaryen.UnreachableId);
+  console.log("AtomicCmpxchgId: " + binaryen.AtomicCmpxchgId);
+  console.log("AtomicRMWId: " + binaryen.AtomicRMWId);
+  console.log("AtomicWaitId: " + binaryen.AtomicWaitId);
+  console.log("AtomicNotifyId: " + binaryen.AtomicNotifyId);
+  console.log("SIMDExtractId: " + binaryen.SIMDExtractId);
+  console.log("SIMDReplaceId: " + binaryen.SIMDReplaceId);
+  console.log("SIMDShuffleId: " + binaryen.SIMDShuffleId);
+  console.log("SIMDTernaryId: " + binaryen.SIMDTernaryId);
+  console.log("SIMDShiftId: " + binaryen.SIMDShiftId);
+  console.log("SIMDLoadId: " + binaryen.SIMDLoadId);
+  console.log("MemoryInitId: " + binaryen.MemoryInitId);
+  console.log("DataDropId: " + binaryen.DataDropId);
+  console.log("MemoryCopyId: " + binaryen.MemoryCopyId);
+  console.log("MemoryFillId: " + binaryen.MemoryFillId);
+  console.log("PopId: " + binaryen.PopId);
+  console.log("RefNullId: " + binaryen.RefNullId);
+  console.log("RefIsNullId: " + binaryen.RefIsNullId);
+  console.log("RefFuncId: " + binaryen.RefFuncId);
+  console.log("RefEqId: " + binaryen.RefEqId);
+  console.log("TryId: " + binaryen.TryId);
+  console.log("ThrowId: " + binaryen.ThrowId);
+  console.log("RethrowId: " + binaryen.RethrowId);
+  console.log("BrOnExnId: " + binaryen.BrOnExnId);
+  console.log("TupleMakeId: " + binaryen.TupleMakeId);
+  console.log("TupleExtractId: " + binaryen.TupleExtractId);
+  console.log("I31NewId: " + binaryen.I31NewId);
+  console.log("I31GetId: " + binaryen.I31GetId);
+  console.log("RefTestId: " + binaryen.RefTestId);
+  console.log("RefCastId: " + binaryen.RefCastId);
+  console.log("BrOnCastId: " + binaryen.BrOnCastId);
+  console.log("RttCanonId: " + binaryen.RttCanonId);
+  console.log("RttSubId: " + binaryen.RttSubId);
+  console.log("StructNewId: " + binaryen.StructNewId);
+  console.log("StructGetId: " + binaryen.StructGetId);
+  console.log("StructSetId: " + binaryen.StructSetId);
+  console.log("ArrayNewId: " + binaryen.ArrayNewId);
+  console.log("ArrayGetId: " + binaryen.ArrayGetId);
+  console.log("ArraySetId: " + binaryen.ArraySetId);
+  console.log("ArrayLenId: " + binaryen.ArrayLenId);
+}
+
+function test_core() {
+
+  // Module creation
+
+  module = new binaryen.Module();
+
+  // Create an event
+  var event_ = module.addEvent("a-event", 0, binaryen.i32, binaryen.none);
+
+  // Literals and consts
+
+  var constI32 = module.i32.const(1),
+      constI64 = module.i64.const(2),
+      constF32 = module.f32.const(3.14),
+      constF64 = module.f64.const(2.1828),
+      constF32Bits = module.f32.const_bits(0xffff1234),
+      constF64Bits = module.f64.const_bits(0x5678abcd, 0xffff1234);
+
+  var iIfF = binaryen.createType([binaryen.i32, binaryen.i64, binaryen.f32, binaryen.f64])
+
+  var temp1 = makeInt32(1), temp2 = makeInt32(2), temp3 = makeInt32(3),
+      temp4 = makeInt32(4), temp5 = makeInt32(5),
+      temp6 = makeInt32(0), temp7 = makeInt32(1),
+      temp8 = makeInt32(0), temp9 = makeInt32(1),
+      temp10 = makeInt32(1), temp11 = makeInt32(3), temp12 = makeInt32(5),
+      temp13 = makeInt32(10), temp14 = makeInt32(11),
+      temp15 = makeInt32(110), temp16 = makeInt64(111);
+
+  var valueList = [
+    // Unary
+    module.i32.clz(module.i32.const(-10)),
+    module.i64.ctz(module.i64.const(-22, -1)),
+    module.i32.popcnt(module.i32.const(-10)),
+    module.f32.neg(module.f32.const(-33.612)),
+    module.f64.abs(module.f64.const(-9005.841)),
+    module.f32.ceil(module.f32.const(-33.612)),
+    module.f64.floor(module.f64.const(-9005.841)),
+    module.f32.trunc(module.f32.const(-33.612)),
+    module.f32.nearest(module.f32.const(-33.612)),
+    module.f64.sqrt(module.f64.const(-9005.841)),
+    module.i32.eqz(module.i32.const(-10)),
+    module.i64.extend_s(module.i32.const(-10)),
+    module.i64.extend_u(module.i32.const(-10)),
+    module.i32.wrap(module.i64.const(-22, -1)),
+    module.i32.trunc_s.f32(module.f32.const(-33.612)),
+    module.i64.trunc_s.f32(module.f32.const(-33.612)),
+    module.i32.trunc_u.f32(module.f32.const(-33.612)),
+    module.i64.trunc_u.f32(module.f32.const(-33.612)),
+    module.i32.trunc_s.f64(module.f64.const(-9005.841)),
+    module.i64.trunc_s.f64(module.f64.const(-9005.841)),
+    module.i32.trunc_u.f64(module.f64.const(-9005.841)),
+    module.i64.trunc_u.f64(module.f64.const(-9005.841)),
+    module.i32.trunc_s_sat.f32(module.f32.const(-33.612)),
+    module.i64.trunc_s_sat.f32(module.f32.const(-33.612)),
+    module.i32.trunc_u_sat.f32(module.f32.const(-33.612)),
+    module.i64.trunc_u_sat.f32(module.f32.const(-33.612)),
+    module.i32.trunc_s_sat.f64(module.f64.const(-9005.841)),
+    module.i64.trunc_s_sat.f64(module.f64.const(-9005.841)),
+    module.i32.trunc_u_sat.f64(module.f64.const(-9005.841)),
+    module.i64.trunc_u_sat.f64(module.f64.const(-9005.841)),
+    module.i32.reinterpret(module.f32.const(-33.612)),
+    module.i64.reinterpret(module.f64.const(-9005.841)),
+    module.f32.convert_s.i32(module.i32.const(-10)),
+    module.f64.convert_s.i32(module.i32.const(-10)),
+    module.f32.convert_u.i32(module.i32.const(-10)),
+    module.f64.convert_u.i32(module.i32.const(-10)),
+    module.f32.convert_s.i64(module.i64.const(-22, -1)),
+    module.f64.convert_s.i64(module.i64.const(-22, -1)),
+    module.f32.convert_u.i64(module.i64.const(-22, -1)),
+    module.f64.convert_u.i64(module.i64.const(-22, -1)),
+    module.f64.promote(module.f32.const(-33.612)),
+    module.f32.demote(module.f64.const(-9005.841)),
+    module.f32.reinterpret(module.i32.const(-10)),
+    module.f64.reinterpret(module.i64.const(-22, -1)),
+    module.i8x16.splat(module.i32.const(42)),
+    module.i16x8.splat(module.i32.const(42)),
+    module.i32x4.splat(module.i32.const(42)),
+    module.i64x2.splat(module.i64.const(123, 456)),
+    module.f32x4.splat(module.f32.const(42.0)),
+    module.f64x2.splat(module.f64.const(42.0)),
+    module.v128.not(module.v128.const(v128_bytes)),
+    module.i8x16.abs(module.v128.const(v128_bytes)),
+    module.i8x16.neg(module.v128.const(v128_bytes)),
+    module.i8x16.any_true(module.v128.const(v128_bytes)),
+    module.i8x16.all_true(module.v128.const(v128_bytes)),
+    module.i8x16.bitmask(module.v128.const(v128_bytes)),
+    module.i16x8.abs(module.v128.const(v128_bytes)),
+    module.i16x8.neg(module.v128.const(v128_bytes)),
+    module.i16x8.any_true(module.v128.const(v128_bytes)),
+    module.i16x8.all_true(module.v128.const(v128_bytes)),
+    module.i16x8.bitmask(module.v128.const(v128_bytes)),
+    module.i32x4.abs(module.v128.const(v128_bytes)),
+    module.i32x4.neg(module.v128.const(v128_bytes)),
+    module.i32x4.any_true(module.v128.const(v128_bytes)),
+    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)),
+    module.f64x2.abs(module.v128.const(v128_bytes)),
+    module.f64x2.neg(module.v128.const(v128_bytes)),
+    module.f64x2.sqrt(module.v128.const(v128_bytes)),
+    module.i32x4.trunc_sat_f32x4_s(module.v128.const(v128_bytes)),
+    module.i32x4.trunc_sat_f32x4_u(module.v128.const(v128_bytes)),
+    module.i64x2.trunc_sat_f64x2_s(module.v128.const(v128_bytes)),
+    module.i64x2.trunc_sat_f64x2_u(module.v128.const(v128_bytes)),
+    module.f32x4.convert_i32x4_s(module.v128.const(v128_bytes)),
+    module.f32x4.convert_i32x4_u(module.v128.const(v128_bytes)),
+    module.f64x2.convert_i64x2_s(module.v128.const(v128_bytes)),
+    module.f64x2.convert_i64x2_u(module.v128.const(v128_bytes)),
+    module.i16x8.widen_low_i8x16_s(module.v128.const(v128_bytes)),
+    module.i16x8.widen_high_i8x16_s(module.v128.const(v128_bytes)),
+    module.i16x8.widen_low_i8x16_u(module.v128.const(v128_bytes)),
+    module.i16x8.widen_high_i8x16_u(module.v128.const(v128_bytes)),
+    module.i32x4.widen_low_i16x8_s(module.v128.const(v128_bytes)),
+    module.i32x4.widen_high_i16x8_s(module.v128.const(v128_bytes)),
+    module.i32x4.widen_low_i16x8_u(module.v128.const(v128_bytes)),
+    module.i32x4.widen_high_i16x8_u(module.v128.const(v128_bytes)),
+    // Binary
+    module.i32.add(module.i32.const(-10), module.i32.const(-11)),
+    module.f64.sub(module.f64.const(-9005.841), module.f64.const(-9007.333)),
+    module.i32.div_s(module.i32.const(-10), module.i32.const(-11)),
+    module.i64.div_u(module.i64.const(-22, 0), module.i64.const(-23, 0)),
+    module.i64.rem_s(module.i64.const(-22, 0), module.i64.const(-23, 0)),
+    module.i32.rem_u(module.i32.const(-10), module.i32.const(-11)),
+    module.i32.and(module.i32.const(-10), module.i32.const(-11)),
+    module.i64.or(module.i64.const(-22, 0), module.i64.const(-23, 0)),
+    module.i32.xor(module.i32.const(-10), module.i32.const(-11)),
+    module.i64.shl(module.i64.const(-22, 0), module.i64.const(-23, 0)),
+    module.i64.shr_u(module.i64.const(-22, 0), module.i64.const(-23, 0)),
+    module.i32.shr_s(module.i32.const(-10), module.i32.const(-11)),
+    module.i32.rotl(module.i32.const(-10), module.i32.const(-11)),
+    module.i64.rotr(module.i64.const(-22, 0), module.i64.const(-23, 0)),
+    module.f32.div(module.f32.const(-33.612), module.f32.const(-62.5)),
+    module.f64.copysign(module.f64.const(-9005.841), module.f64.const(-9007.333)),
+    module.f32.min(module.f32.const(-33.612), module.f32.const(-62.5)),
+    module.f64.max(module.f64.const(-9005.841), module.f64.const(-9007.333)),
+    module.i32.eq(module.i32.const(-10), module.i32.const(-11)),
+    module.f32.ne(module.f32.const(-33.612), module.f32.const(-62.5)),
+    module.i32.lt_s(module.i32.const(-10), module.i32.const(-11)),
+    module.i64.lt_u(module.i64.const(-22, 0), module.i64.const(-23, 0)),
+    module.i64.le_s(module.i64.const(-22, 0), module.i64.const(-23, 0)),
+    module.i32.le_u(module.i32.const(-10), module.i32.const(-11)),
+    module.i64.gt_s(module.i64.const(-22, 0), module.i64.const(-23, 0)),
+    module.i32.gt_u(module.i32.const(-10), module.i32.const(-11)),
+    module.i32.ge_s(module.i32.const(-10), module.i32.const(-11)),
+    module.i64.ge_u(module.i64.const(-22, 0), module.i64.const(-23, 0)),
+    module.f32.lt(module.f32.const(-33.612), module.f32.const(-62.5)),
+    module.f64.le(module.f64.const(-9005.841), module.f64.const(-9007.333)),
+    module.f64.gt(module.f64.const(-9005.841), module.f64.const(-9007.333)),
+    module.f32.ge(module.f32.const(-33.612), module.f32.const(-62.5)),
+    module.i8x16.eq(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.ne(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.lt_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.lt_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.gt_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.gt_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.le_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.le_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.ge_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.ge_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.eq(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.ne(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.lt_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.lt_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.gt_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.gt_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.le_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.le_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.ge_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.ge_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.eq(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.ne(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.lt_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.lt_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.gt_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.gt_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.le_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.le_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.ge_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.ge_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.eq(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.ne(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.lt(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.gt(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.le(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.ge(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.eq(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.ne(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.lt(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.gt(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.le(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.ge(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.v128.and(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.v128.or(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.v128.xor(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.v128.andnot(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.add(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.add_saturate_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.add_saturate_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.sub(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.sub_saturate_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.sub_saturate_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.mul(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.min_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.min_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.max_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.max_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.avgr_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.add(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.add_saturate_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.add_saturate_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.sub(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.sub_saturate_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.sub_saturate_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.mul(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.min_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.min_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.max_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.max_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.avgr_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.add(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.sub(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.mul(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.min_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.min_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.max_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.max_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i32x4.dot_i16x8_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i64x2.add(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i64x2.sub(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i64x2.mul(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.add(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.sub(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.mul(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.div(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.min(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.max(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.pmin(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.pmax(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.ceil(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.floor(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.trunc(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.nearest(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.add(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.sub(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.mul(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.div(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.min(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.max(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.pmin(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.pmax(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.ceil(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.floor(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.trunc(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.nearest(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.narrow_i16x8_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i8x16.narrow_i16x8_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.narrow_i32x4_s(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.i16x8.narrow_i32x4_u(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.v8x16.swizzle(module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    // SIMD lane manipulation
+    module.i8x16.extract_lane_s(module.v128.const(v128_bytes), 1),
+    module.i8x16.extract_lane_u(module.v128.const(v128_bytes), 1),
+    module.i16x8.extract_lane_s(module.v128.const(v128_bytes), 1),
+    module.i16x8.extract_lane_u(module.v128.const(v128_bytes), 1),
+    module.i32x4.extract_lane(module.v128.const(v128_bytes), 1),
+    module.i64x2.extract_lane(module.v128.const(v128_bytes), 1),
+    module.f32x4.extract_lane(module.v128.const(v128_bytes), 1),
+    module.f64x2.extract_lane(module.v128.const(v128_bytes), 1),
+    module.i16x8.replace_lane(module.v128.const(v128_bytes), 1, module.i32.const(42)),
+    module.i8x16.replace_lane(module.v128.const(v128_bytes), 1, module.i32.const(42)),
+    module.i32x4.replace_lane(module.v128.const(v128_bytes), 1, module.i32.const(42)),
+    module.i64x2.replace_lane(module.v128.const(v128_bytes), 1, module.i64.const(42, 43)),
+    module.f32x4.replace_lane(module.v128.const(v128_bytes), 1, module.f32.const(42)),
+    module.f64x2.replace_lane(module.v128.const(v128_bytes), 1, module.f64.const(42)),
+    // SIMD shift
+    module.i8x16.shl(module.v128.const(v128_bytes), module.i32.const(1)),
+    module.i8x16.shr_s(module.v128.const(v128_bytes), module.i32.const(1)),
+    module.i8x16.shr_u(module.v128.const(v128_bytes), module.i32.const(1)),
+    module.i16x8.shl(module.v128.const(v128_bytes), module.i32.const(1)),
+    module.i16x8.shr_s(module.v128.const(v128_bytes), module.i32.const(1)),
+    module.i16x8.shr_u(module.v128.const(v128_bytes), module.i32.const(1)),
+    module.i32x4.shl(module.v128.const(v128_bytes), module.i32.const(1)),
+    module.i32x4.shr_s(module.v128.const(v128_bytes), module.i32.const(1)),
+    module.i32x4.shr_u(module.v128.const(v128_bytes), module.i32.const(1)),
+    module.i64x2.shl(module.v128.const(v128_bytes), module.i32.const(1)),
+    module.i64x2.shr_s(module.v128.const(v128_bytes), module.i32.const(1)),
+    module.i64x2.shr_u(module.v128.const(v128_bytes), module.i32.const(1)),
+    // SIMD load
+    module.v8x16.load_splat(0, 1, module.i32.const(128)),
+    module.v16x8.load_splat(16, 1, module.i32.const(128)),
+    module.v32x4.load_splat(16, 4, module.i32.const(128)),
+    module.v64x2.load_splat(0, 4, module.i32.const(128)),
+    module.i16x8.load8x8_s(0, 8, module.i32.const(128)),
+    module.i16x8.load8x8_u(0, 8, module.i32.const(128)),
+    module.i32x4.load16x4_s(0, 8, module.i32.const(128)),
+    module.i32x4.load16x4_u(0, 8, module.i32.const(128)),
+    module.i64x2.load32x2_s(0, 8, module.i32.const(128)),
+    module.i64x2.load32x2_u(0, 8, module.i32.const(128)),
+    // Other SIMD
+    module.v8x16.shuffle(module.v128.const(v128_bytes), module.v128.const(v128_bytes), v128_bytes),
+    module.v128.bitselect(module.v128.const(v128_bytes), module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.qfma(module.v128.const(v128_bytes), module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f32x4.qfms(module.v128.const(v128_bytes), module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.qfma(module.v128.const(v128_bytes), module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    module.f64x2.qfms(module.v128.const(v128_bytes), module.v128.const(v128_bytes), module.v128.const(v128_bytes)),
+    // Bulk memory
+    module.memory.init(0, makeInt32(1024), makeInt32(0), makeInt32(12)),
+    module.data.drop(0),
+    module.memory.copy(makeInt32(2048), makeInt32(1024), makeInt32(12)),
+    module.memory.fill(makeInt32(0), makeInt32(42), makeInt32(1024)),
+    // All the rest
+    module.block('', []), // block with no name
+    module.if(temp1, temp2, temp3),
+    module.if(temp4, temp5),
+    module.loop("in", makeInt32(0)),
+    module.loop(null, makeInt32(0)),
+    module.break("the-value", temp6, temp7),
+    module.break("the-nothing", makeInt32(2)),
+    module.break("the-value", null, makeInt32(3)),
+    module.break("the-nothing"),
+    module.switch([ "the-value" ], "the-value", temp8, temp9),
+    module.switch([ "the-nothing" ], "the-nothing", makeInt32(2)),
+    module.i32.eqz( // check the output type of the call node
+      module.call("kitchen()sinker", [ makeInt32(13), makeInt64(37, 0), makeFloat32(1.3), makeFloat64(3.7) ], binaryen.i32)
+    ),
+    module.i32.eqz( // check the output type of the call node
+      module.i32.trunc_s.f32(
+        module.call("an-imported", [ makeInt32(13), makeFloat64(3.7) ], binaryen.f32)
+      )
+    ),
+    module.i32.eqz( // check the output type of the call node
+      module.call_indirect(makeInt32(2449), [ makeInt32(13), makeInt64(37, 0), makeFloat32(1.3), makeFloat64(3.7) ], iIfF, binaryen.i32)
+    ),
+    module.drop(module.local.get(0, binaryen.i32)),
+    module.local.set(0, makeInt32(101)),
+    module.drop(module.local.tee(0, makeInt32(102), binaryen.i32)),
+    module.i32.load(0, 0, makeInt32(1)),
+    module.i64.load16_s(2, 1, makeInt32(8)),
+    module.f32.load(0, 0, makeInt32(2)),
+    module.f64.load(2, 8, makeInt32(9)),
+    module.i32.store(0, 0, temp13, temp14),
+    module.i64.store(2, 4, temp15, temp16),
+    module.select(temp10, temp11, temp12),
+    module.return(makeInt32(1337)),
+    // Tail Call
+    module.return_call("kitchen()sinker", [ makeInt32(13), makeInt64(37, 0), makeFloat32(1.3), makeFloat64(3.7) ], binaryen.i32),
+    module.return_call_indirect(makeInt32(2449), [ makeInt32(13), makeInt64(37, 0), makeFloat32(1.3), makeFloat64(3.7) ], iIfF, binaryen.i32),
+
+    // 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),
+
+    // GC
+    module.ref.eq(module.ref.null(binaryen.eqref), module.ref.null(binaryen.eqref)),
+
+    // Exception handling
+    module.try(
+      module.throw("a-event", [module.i32.const(0)]),
+      module.block(null, [
+        module.local.set(5, module.exnref.pop()),
+        module.drop(
+          module.block("try-block", [
+            module.rethrow(
+              module.br_on_exn("try-block", "a-event",
+                module.local.get(5, binaryen.exnref)),
+            )
+          ], binaryen.i32)
+        )
+      ]
+      )
+    ),
+
+    // Atomics
+    module.i32.atomic.store(0,
+      module.i32.const(0),
+      module.i32.atomic.load(0,
+        module.i32.const(0)
+      )
+    ),
+    module.drop(
+      module.i32.atomic.wait(
+        module.i32.const(0),
+        module.i32.const(0),
+        module.i64.const(0)
+      )
+    ),
+    module.drop(
+      module.atomic.notify(
+        module.i32.const(0),
+        module.i32.const(0)
+      )
+    ),
+    module.atomic.fence(),
+
+    // Tuples
+    module.tuple.make(
+      [ makeInt32(13), makeInt64(37, 0), makeFloat32(1.3), makeFloat64(3.7) ]
+    ),
+    module.tuple.extract(
+      module.tuple.make(
+        [ makeInt32(13), makeInt64(37, 0), makeFloat32(1.3), makeFloat64(3.7) ]
+      ), 2
+    ),
+
+    // Pop
+    module.i32.pop(),
+    module.i64.pop(),
+    module.f32.pop(),
+    module.f64.pop(),
+    module.v128.pop(),
+    module.funcref.pop(),
+    module.externref.pop(),
+    module.exnref.pop(),
+    module.anyref.pop(),
+    module.eqref.pop(),
+    module.i31ref.pop(),
+
+    // Memory
+    module.memory.size(),
+    module.memory.grow(makeInt32(0)),
+
+    // GC
+    module.i31.new(
+      module.i32.const(0)
+    ),
+    module.i31.get_s(
+      module.i31.new(
+        module.i32.const(1)
+      )
+    ),
+    module.i31.get_u(
+      module.i31.new(
+        module.i32.const(2)
+      )
+    ),
+
+    // Other
+    module.nop(),
+    module.unreachable(),
+  ];
+
+  // Test expression utility
+  console.log("getExpressionInfo=" + JSON.stringify(cleanInfo(binaryen.getExpressionInfo(valueList[3]))));
+  console.log(binaryen.emitText(valueList[3])); // test printing a standalone expression
+
+  console.log("getExpressionInfo(i32.const)=" + JSON.stringify(binaryen.getExpressionInfo(module.i32.const(5))));
+  console.log("getExpressionInfo(i64.const)=" + JSON.stringify(binaryen.getExpressionInfo(module.i64.const(6, 7))));
+  console.log("getExpressionInfo(f32.const)=" + JSON.stringify(binaryen.getExpressionInfo(module.f32.const(8.5))));
+  console.log("getExpressionInfo(f64.const)=" + JSON.stringify(binaryen.getExpressionInfo(module.f64.const(9.5))));
+  var elements = binaryen.getExpressionInfo(
+    module.tuple.make([ makeInt32(13), makeInt64(37, 0), makeFloat32(1.3), makeFloat64(3.7) ])
+  ).operands;
+  for (var i = 0; i < elements.length; i++) {
+    console.log("getExpressionInfo(tuple[" + i + "])=" + JSON.stringify(binaryen.getExpressionInfo(elements[i])));
+  }
+
+  // Make the main body of the function. and one block with a return value, one without
+  var value = module.block("the-value", valueList);
+  var droppedValue = module.drop(value);
+  var nothing = module.block("the-nothing", [ droppedValue ]);
+  var body = module.block("the-body", [ nothing, makeInt32(42) ]);
+
+  // Create the function
+  var sinker = module.addFunction("kitchen()sinker", iIfF, binaryen.i32, [ binaryen.i32, binaryen.exnref ], body);
+
+  // Create a global
+  var initExpr = module.i32.const(1);
+  var global = module.addGlobal("a-global", binaryen.i32, false, initExpr)
+
+  // Imports
+
+  var iF = binaryen.createType([binaryen.i32, binaryen.f64]);
+  module.addFunctionImport("an-imported", "module", "base", iF, binaryen.f32);
+  module.addGlobalImport("a-global-imp", "module", "base", binaryen.i32, false);
+  module.addGlobalImport("a-mut-global-imp", "module", "base", binaryen.i32, true);
+  module.addEventImport("a-event-imp", "module", "base", 0, binaryen.i32, binaryen.none);
+
+  // Exports
+
+  module.addFunctionExport("kitchen()sinker", "kitchen_sinker");
+  module.addGlobalExport("a-global", "a-global-exp");
+  module.addEventExport("a-event", "a-event-exp");
+
+  // Function table. One per module
+
+  module.setFunctionTable(1, 0xffffffff, [ binaryen.getFunctionInfo(sinker).name ]);
+
+  // Memory. One per module
+
+  module.setMemory(1, 256, "mem", [
+    {
+      passive: false,
+      offset: module.i32.const(10),
+      data: "hello, world".split('').map(function(x) { return x.charCodeAt(0) })
+    },
+    {
+      passive: true,
+      offset: null,
+      data: "I am passive".split('').map(function(x) { return x.charCodeAt(0) })
+    }
+  ], true);
+
+  // Start function. One per module
+  var starter = module.addFunction("starter", binaryen.none, binaryen.none, [], module.nop());
+  module.setStart(starter);
+
+  // A bunch of our code needs drop, auto-add it
+  module.autoDrop();
+
+  var features = binaryen.Features.All;
+  module.setFeatures(features);
+  assert(module.getFeatures() == features);
+  console.log(module.emitText());
+
+  // Verify it validates
+  assert(module.validate());
+
+  // Print it out
+  console.log(module.emitText());
+
+  // Clean up the module, which owns all the objects we created above
+  module.dispose();
+}
+
+function makeCallCheck(x) {
+  return module.call("check", [ makeInt32(x) ], binaryen.None);
+}
+
+function test_relooper() {
+  module = new binaryen.Module();
+  var localTypes = [ binaryen.i32 ];
+
+  module.addFunctionImport("check", "module", "check", binaryen.i32, binaryen.none);
+
+  { // trivial: just one block
+    var relooper = new binaryen.Relooper(module);
+    var block = relooper.addBlock(makeCallCheck(1337));
+    var body = relooper.renderAndDispose(block, 0, module);
+    module.addFunction("just-one-block", binaryen.none, binaryen.none, localTypes, body);
+  }
+  { // two blocks
+    var relooper = new binaryen.Relooper(module);
+    var block0 = relooper.addBlock(makeCallCheck(0));
+    var block1 = relooper.addBlock(makeCallCheck(1));
+    relooper.addBranch(block0, block1); // no condition, no code on branch
+    var body = relooper.renderAndDispose(block0, 0, module);
+    module.addFunction("two-blocks", binaryen.none, binaryen.none, localTypes, body);
+  }
+  { // two blocks with code between them
+    var relooper = new binaryen.Relooper(module);
+    var block0 = relooper.addBlock(makeCallCheck(0));
+    var block1 = relooper.addBlock(makeCallCheck(1));
+    relooper.addBranch(block0, block1, null, makeDroppedInt32(77)); // code on branch
+    var body = relooper.renderAndDispose(block0, 0, module);
+    module.addFunction("two-blocks-plus-code", binaryen.none, binaryen.none, localTypes, body);
+  }
+  { // two blocks in a loop
+    var relooper = new binaryen.Relooper(module);
+    var block0 = relooper.addBlock(makeCallCheck(0));
+    var block1 = relooper.addBlock(makeCallCheck(1));
+    relooper.addBranch(block0, block1, null, null);
+    relooper.addBranch(block1, block0, null, null);
+    var body = relooper.renderAndDispose(block0, 0, module);
+    module.addFunction("loop", binaryen.none, binaryen.none, localTypes, body);
+  }
+  { // two blocks in a loop with codes
+    var relooper = new binaryen.Relooper(module);
+    var block0 = relooper.addBlock(makeCallCheck(0));
+    var block1 = relooper.addBlock(makeCallCheck(1));
+    relooper.addBranch(block0, block1, null, makeDroppedInt32(33));
+    relooper.addBranch(block1, block0, null, makeDroppedInt32(-66));
+    var body = relooper.renderAndDispose(block0, 0, module);
+    module.addFunction("loop-plus-code", binaryen.none, binaryen.none, localTypes, body);
+  }
+  { // split
+    var relooper = new binaryen.Relooper(module);
+    var block0 = relooper.addBlock(makeCallCheck(0));
+    var block1 = relooper.addBlock(makeCallCheck(1));
+    var block2 = relooper.addBlock(makeCallCheck(2));
+    relooper.addBranch(block0, block1, makeInt32(55), null);
+    relooper.addBranch(block0, block2, null, null);
+    var body = relooper.renderAndDispose(block0, 0, module);
+    module.addFunction("split", binaryen.none, binaryen.none, localTypes, body);
+  }
+  { // split + code
+    var relooper = new binaryen.Relooper(module);
+    var block0 = relooper.addBlock(makeCallCheck(0));
+    var block1 = relooper.addBlock(makeCallCheck(1));
+    var block2 = relooper.addBlock(makeCallCheck(2));
+    temp = makeDroppedInt32(10);
+    relooper.addBranch(block0, block1, makeInt32(55), temp);
+    relooper.addBranch(block0, block2, null, makeDroppedInt32(20));
+    var body = relooper.renderAndDispose(block0, 0, module);
+    module.addFunction("split-plus-code", binaryen.none, binaryen.none, localTypes, body);
+  }
+  { // if
+    var relooper = new binaryen.Relooper(module);
+    var block0 = relooper.addBlock(makeCallCheck(0));
+    var block1 = relooper.addBlock(makeCallCheck(1));
+    var block2 = relooper.addBlock(makeCallCheck(2));
+    relooper.addBranch(block0, block1, makeInt32(55), null);
+    relooper.addBranch(block0, block2, null, null);
+    relooper.addBranch(block1, block2, null, null);
+    var body = relooper.renderAndDispose(block0, 0, module);
+    module.addFunction("if", binaryen.none, binaryen.none, localTypes, body);
+  }
+  { // if + code
+    var relooper = new binaryen.Relooper(module);
+    var block0 = relooper.addBlock(makeCallCheck(0));
+    var block1 = relooper.addBlock(makeCallCheck(1));
+    var block2 = relooper.addBlock(makeCallCheck(2));
+    temp = makeDroppedInt32(-1);
+    relooper.addBranch(block0, block1, makeInt32(55), temp);
+    relooper.addBranch(block0, block2, null, makeDroppedInt32(-2));
+    relooper.addBranch(block1, block2, null, makeDroppedInt32(-3));
+    var body = relooper.renderAndDispose(block0, 0, module);
+    module.addFunction("if-plus-code", binaryen.none, binaryen.none, localTypes, body);
+  }
+  { // if-else
+    var relooper = new binaryen.Relooper(module);
+    var block0 = relooper.addBlock(makeCallCheck(0));
+    var block1 = relooper.addBlock(makeCallCheck(1));
+    var block2 = relooper.addBlock(makeCallCheck(2));
+    var block3 = relooper.addBlock(makeCallCheck(3));
+    relooper.addBranch(block0, block1, makeInt32(55), null);
+    relooper.addBranch(block0, block2, null, null);
+    relooper.addBranch(block1, block3, null, null);
+    relooper.addBranch(block2, block3, null, null);
+    var body = relooper.renderAndDispose(block0, 0, module);
+    module.addFunction("if-else", binaryen.none, binaryen.none, localTypes, body);
+  }
+  { // loop+tail
+    var relooper = new binaryen.Relooper(module);
+    var block0 = relooper.addBlock(makeCallCheck(0));
+    var block1 = relooper.addBlock(makeCallCheck(1));
+    var block2 = relooper.addBlock(makeCallCheck(2));
+    relooper.addBranch(block0, block1, null, null);
+    relooper.addBranch(block1, block0, makeInt32(10), null);
+    relooper.addBranch(block1, block2, null, null);
+    var body = relooper.renderAndDispose(block0, 0, module);
+    module.addFunction("loop-tail", binaryen.none, binaryen.none, localTypes, body);
+  }
+  { // nontrivial loop + phi to head
+    var relooper = new binaryen.Relooper(module);
+    var block0 = relooper.addBlock(makeCallCheck(0));
+    var block1 = relooper.addBlock(makeCallCheck(1));
+    var block2 = relooper.addBlock(makeCallCheck(2));
+    var block3 = relooper.addBlock(makeCallCheck(3));
+    var block4 = relooper.addBlock(makeCallCheck(4));
+    var block5 = relooper.addBlock(makeCallCheck(5));
+    var block6 = relooper.addBlock(makeCallCheck(6));
+    relooper.addBranch(block0, block1, null, makeDroppedInt32(10));
+    relooper.addBranch(block1, block2, makeInt32(-2), null);
+    relooper.addBranch(block1, block6, null, makeDroppedInt32(20));
+    relooper.addBranch(block2, block3, makeInt32(-6), null);
+    relooper.addBranch(block2, block1, null, makeDroppedInt32(30));
+    relooper.addBranch(block3, block4, makeInt32(-10), null);
+    relooper.addBranch(block3, block5, null, null);
+    relooper.addBranch(block4, block5, null, null);
+    relooper.addBranch(block5, block6, null, makeDroppedInt32(40));
+    var body = relooper.renderAndDispose(block0, 0, module);
+    module.addFunction("nontrivial-loop-plus-phi-to-head", binaryen.none, binaryen.none, localTypes, body);
+  }
+  { // switch
+    var relooper = new binaryen.Relooper(module);
+    temp = makeInt32(-99);
+    var block0 = relooper.addBlockWithSwitch(makeCallCheck(0), temp);
+    var block1 = relooper.addBlock(makeCallCheck(1));
+    var block2 = relooper.addBlock(makeCallCheck(2));
+    var block3 = relooper.addBlock(makeCallCheck(3));
+    relooper.addBranchForSwitch(block0, block1, [ 2, 5 ]);
+    relooper.addBranchForSwitch(block0, block2, [4], makeDroppedInt32(55));
+    relooper.addBranchForSwitch(block0, block3, [], null);
+    var body = relooper.renderAndDispose(block0, 0, module);
+    module.addFunction("switch", binaryen.none, binaryen.none, localTypes, body);
+  }
+  { // duff's device
+    var relooper = new binaryen.Relooper(module);
+    var block0 = relooper.addBlock(makeCallCheck(0));
+    var block1 = relooper.addBlock(makeCallCheck(1));
+    var block2 = relooper.addBlock(makeCallCheck(2));
+    relooper.addBranch(block0, block1, makeInt32(10), null);
+    relooper.addBranch(block0, block2, null, null);
+    relooper.addBranch(block1, block2, null, null);
+    relooper.addBranch(block2, block1, null, null);
+    var body = relooper.renderAndDispose(block0, 3, module); // use $3 as the helper var
+    module.addFunction("duffs-device", binaryen.none, binaryen.none, [ binaryen.i32, binaryen.i32, binaryen.i64, binaryen.i32, binaryen.f32, binaryen.f64, binaryen.i32 ], body);
+  }
+
+  { // return in a block
+    var relooper = new binaryen.Relooper(module);
+    var list = module.block("the-list", [ makeCallCheck(42), module.return(makeInt32(1337)) ]);
+    var block = relooper.addBlock(list);
+    var body = relooper.renderAndDispose(block, 0, module);
+    module.addFunction("return", binaryen.none, binaryen.i32, localTypes, body);
+  }
+
+  console.log("raw:");
+  console.log(module.emitText());
+
+  assert(module.validate());
+
+  module.runPasses(["precompute"]);
+
+  assert(module.validate());
+
+  module.optimize();
+
+  assert(module.validate());
+
+  console.log("optimized:");
+  console.log(module.emitText());
+
+  module.dispose();
+}
+
+function test_binaries() {
+  var buffer, size;
+
+  { // create a module and write it to binary
+    module = new binaryen.Module();
+    module.setFeatures(binaryen.Features.All);
+    var ii = binaryen.createType([binaryen.i32, binaryen.i32]);
+    var x = module.local.get(0, binaryen.i32),
+        y = module.local.get(1, binaryen.i32);
+    var add = module.i32.add(x, y);
+    var adder = module.addFunction("adder", ii, binaryen.i32, [], add);
+    var initExpr = module.i32.const(3);
+    var global = module.addGlobal("a-global", binaryen.i32, false, initExpr)
+    var event_ = module.addEvent("a-event", 0, binaryen.createType([binaryen.i32, binaryen.i32]), binaryen.none);
+    binaryen.setDebugInfo(true); // include names section
+    buffer = module.emitBinary();
+    binaryen.setDebugInfo(false);
+    size = buffer.length; // write out the module
+    module.dispose();
+  }
+
+  assert(size > 0);
+  assert(size < 512); // this is a tiny module
+
+  // read the module from the binary
+  module = binaryen.readBinary(buffer);
+  module.setFeatures(binaryen.Features.All);
+
+  // validate, print, and free
+  assert(module.validate());
+  console.log("module loaded from binary form:");
+  console.log(module.emitText());
+  module.dispose();
+}
+
+function test_interpret() {
+  // create a simple module with a start method that prints a number, and interpret it, printing that number.
+  module = new binaryen.Module();
+
+  module.addFunctionImport("print-i32", "spectest", "print", binaryen.i32, binaryen.none);
+  call = module.call("print-i32", [ makeInt32(1234) ], binaryen.None);
+  var starter = module.addFunction("starter", binaryen.none, binaryen.none, [], call);
+  module.setStart(starter);
+
+  console.log(module.emitText());
+  assert(module.validate());
+  module.interpret();
+  module.dispose();
+}
+
+function test_nonvalid() {
+  // create a module that fails to validate
+  module = new binaryen.Module();
+
+  var func = module.addFunction("func", binaryen.none, binaryen.none, [ binaryen.i32 ],
+    module.local.set(0, makeInt64(1234, 0)) // wrong type!
+  );
+
+  console.log(module.emitText());
+  console.log("validation: " + module.validate());
+
+  module.dispose();
+}
+
+function test_parsing() {
+  var text;
+
+  // create a module and write it to text
+  module = new binaryen.Module();
+  module.setFeatures(binaryen.Features.All);
+
+  var ii = binaryen.createType([binaryen.i32, binaryen.i32]);
+  var x = module.local.get(0, binaryen.i32),
+      y = module.local.get(1, binaryen.i32);
+  var add = module.i32.add(x, y);
+  var adder = module.addFunction("adder", ii, binaryen.i32, [], add);
+  var initExpr = module.i32.const(3);
+  var global = module.addGlobal("a-global", binaryen.i32, false, initExpr)
+  var event_ = module.addEvent("a-event", 0, binaryen.i32, binaryen.none);
+  text = module.emitText();
+  module.dispose();
+  module = null;
+  console.log('test_parsing text:\n' + text);
+
+  text = text.replace('adder', 'ADD_ER');
+
+  var module2 = binaryen.parseText(text);
+  module2.setFeatures(binaryen.Features.All);
+  assert(module2.validate());
+  console.log("module loaded from text form:");
+  console.log(module2.emitText());
+  module2.dispose();
+}
+
+function test_internals() {
+  console.log('sizeof Literal: ' + binaryen['_BinaryenSizeofLiteral']());
+}
+
+function test_for_each() {
+  module = new binaryen.Module();
+
+  var funcNames = [ "fn0", "fn1", "fn2" ];
+
+  var fns = [
+    module.addFunction(funcNames[0], binaryen.none, binaryen.none, [], module.nop()),
+    module.addFunction(funcNames[1], binaryen.none, binaryen.none, [], module.nop()),
+    module.addFunction(funcNames[2], binaryen.none, binaryen.none, [], module.nop())
+  ];
+
+  var i;
+  for (i = 0; i < module.getNumFunctions(); i++) {
+    assert(module.getFunctionByIndex(i) === fns[i]);
+  }
+
+  var exps = [
+    module.addFunctionExport(funcNames[0], "export0"),
+    module.addFunctionExport(funcNames[1], "export1"),
+    module.addFunctionExport(funcNames[2], "export2")
+  ];
+
+  for (i = 0; i < module.getNumExports(); i++) {
+    assert(module.getExportByIndex(i) === exps[i]);
+  }
+
+  var expected_offsets = [10, 125];
+  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]))
+  module.setMemory(1, 256, "mem", [
+    {
+      passive: expected_passive[0],
+      offset: module.i32.const(expected_offsets[0]),
+      data: expected_data[0].split('').map(function(x) { return x.charCodeAt(0) })
+    },
+    {
+      passive: expected_passive[1],
+      offset: module.global.get("a-global"),
+      data: expected_data[1].split('').map(function(x) { return x.charCodeAt(0) })
+    }
+  ], false);
+  for (i = 0; i < module.getNumMemorySegments(); i++) {
+    var segment = module.getMemorySegmentInfoByIndex(i);
+    assert(expected_offsets[i] === segment.offset);
+    var data8 = new Uint8Array(segment.data);
+    var str = String.fromCharCode.apply(null, data8);
+    assert(expected_data[i] === str);
+    assert(expected_passive[i] === segment.passive);
+  }
+
+  var constExprRef = module.i32.const(0);
+  module.setFunctionTable(1, 0xffffffff, funcNames, constExprRef);
+
+  var ftable = module.getFunctionTable();
+  assert(false === ftable.imported);
+  assert(1 === ftable.segments.length);
+  assert(constExprRef === ftable.segments[0].offset);
+  assert(3 === ftable.segments[0].names.length);
+  for (i = 0; i < ftable.segments[0].names.length; i++) {
+    assert(funcNames[i] === ftable.segments[0].names[i]);
+  }
+
+  console.log(module.emitText());
+  module.dispose();
+}
+
+function test_expression_info() {
+  module = new binaryen.Module();
+
+  // Issue #2392
+  console.log("getExpressionInfo(memory.grow)=" + JSON.stringify(binaryen.getExpressionInfo(module.memory.grow(1))));
+
+  // Issue #2396
+  console.log("getExpressionInfo(switch)=" + JSON.stringify(binaryen.getExpressionInfo(module.switch([ "label" ], "label", 0))));
+
+  module.dispose();
+}
+
+test_types();
+test_features();
+test_ids();
+test_core();
+test_relooper();
+test_binaries();
+test_interpret();
+test_nonvalid();
+test_parsing();
+test_internals();
+test_for_each();
+test_expression_info();
diff --git a/binaryen/test/binaryen.js/kitchen-sink.js.txt b/binaryen/test/binaryen.js/kitchen-sink.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/kitchen-sink.js.txt
@@ -0,0 +1,4450 @@
+  // BinaryenTypeNone: 0
+  // 
+  // BinaryenTypeUnreachable: 1
+  // 1
+  // BinaryenTypeInt32: 2
+  // 2
+  // BinaryenTypeInt64: 3
+  // 3
+  // BinaryenTypeFloat32: 4
+  // 4
+  // BinaryenTypeFloat64: 5
+  // 5
+  // BinaryenTypeVec128: 6
+  // 6
+  // BinaryenTypeFuncref: 7
+  // 7
+  // BinaryenTypeExternref: 8
+  // 8
+  // BinaryenTypeExnref: 9
+  // 9
+  // BinaryenTypeAnyref: 10
+  // 10
+  // BinaryenTypeEqref: 11
+  // 11
+  // BinaryenTypeI31ref: 12
+  // 12
+  // BinaryenTypeAuto: -1
+  // 2,2
+  // 2,2
+  // 4,4
+Features.MVP: 0
+Features.Atomics: 1
+Features.BulkMemory: 16
+Features.MutableGlobals: 2
+Features.NontrappingFPToInt: 4
+Features.SignExt: 32
+Features.SIMD128: 8
+Features.ExceptionHandling: 64
+Features.TailCall: 128
+Features.ReferenceTypes: 256
+Features.Multivalue: 512
+Features.GC: 1024
+Features.Memory64: 2048
+Features.All: 4095
+InvalidId: 0
+BlockId: 1
+IfId: 2
+LoopId: 3
+BreakId: 4
+SwitchId: 5
+CallId: 6
+CallIndirectId: 7
+LocalGetId: 8
+LocalSetId: 9
+GlobalGetId: 10
+GlobalSetId: 11
+LoadId: 12
+StoreId: 13
+ConstId: 14
+UnaryId: 15
+BinaryId: 16
+SelectId: 17
+DropId: 18
+ReturnId: 19
+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
+getExpressionInfo={"id":15,"type":4,"op":6}
+(f32.neg
+ (f32.const -33.61199951171875)
+)
+
+getExpressionInfo(i32.const)={"id":14,"type":2,"value":5}
+getExpressionInfo(i64.const)={"id":14,"type":3,"value":{"low":6,"high":7}}
+getExpressionInfo(f32.const)={"id":14,"type":4,"value":8.5}
+getExpressionInfo(f64.const)={"id":14,"type":5,"value":9.5}
+getExpressionInfo(tuple[0])={"id":14,"type":2,"value":13}
+getExpressionInfo(tuple[1])={"id":14,"type":3,"value":{"low":37,"high":0}}
+getExpressionInfo(tuple[2])={"id":14,"type":4,"value":1.2999999523162842}
+getExpressionInfo(tuple[3])={"id":14,"type":5,"value":3.7}
+(module
+ (type $i32_i64_f32_f64_=>_i32 (func (param i32 i64 f32 f64) (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_none (func))
+ (type $i32_f64_=>_f32 (func (param i32 f64) (result f32)))
+ (import "module" "base" (global $a-global-imp i32))
+ (import "module" "base" (global $a-mut-global-imp (mut i32)))
+ (import "module" "base" (func $an-imported (param i32 f64) (result f32)))
+ (import "module" "base" (event $a-event-imp (attr 0) (param i32)))
+ (memory $0 (shared 1 256))
+ (data (i32.const 10) "hello, world")
+ (data passive "I am passive")
+ (table $0 1 funcref)
+ (elem (i32.const 0) "$kitchen()sinker")
+ (global $a-global i32 (i32.const 1))
+ (event $a-event (attr 0) (param i32))
+ (export "kitchen_sinker" (func "$kitchen()sinker"))
+ (export "a-global-exp" (global $a-global))
+ (export "a-event-exp" (event $a-event))
+ (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.841)
+       )
+      )
+      (drop
+       (f32.ceil
+        (f32.const -33.61199951171875)
+       )
+      )
+      (drop
+       (f64.floor
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (f32.trunc
+        (f32.const -33.61199951171875)
+       )
+      )
+      (drop
+       (f32.nearest
+        (f32.const -33.61199951171875)
+       )
+      )
+      (drop
+       (f64.sqrt
+        (f64.const -9005.841)
+       )
+      )
+      (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.841)
+       )
+      )
+      (drop
+       (i64.trunc_f64_s
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (i32.trunc_f64_u
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (i64.trunc_f64_u
+        (f64.const -9005.841)
+       )
+      )
+      (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.841)
+       )
+      )
+      (drop
+       (i64.trunc_sat_f64_s
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (i32.trunc_sat_f64_u
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (i64.trunc_sat_f64_u
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (i32.reinterpret_f32
+        (f32.const -33.61199951171875)
+       )
+      )
+      (drop
+       (i64.reinterpret_f64
+        (f64.const -9005.841)
+       )
+      )
+      (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.841)
+       )
+      )
+      (drop
+       (f32.reinterpret_i32
+        (i32.const -10)
+       )
+      )
+      (drop
+       (f64.reinterpret_i64
+        (i64.const -22)
+       )
+      )
+      (drop
+       (i8x16.splat
+        (i32.const 42)
+       )
+      )
+      (drop
+       (i16x8.splat
+        (i32.const 42)
+       )
+      )
+      (drop
+       (i32x4.splat
+        (i32.const 42)
+       )
+      )
+      (drop
+       (i64x2.splat
+        (i64.const 1958505087099)
+       )
+      )
+      (drop
+       (f32x4.splat
+        (f32.const 42)
+       )
+      )
+      (drop
+       (f64x2.splat
+        (f64.const 42)
+       )
+      )
+      (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.841)
+        (f64.const -9007.333)
+       )
+      )
+      (drop
+       (i32.div_s
+        (i32.const -10)
+        (i32.const -11)
+       )
+      )
+      (drop
+       (i64.div_u
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (i64.rem_s
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (i32.rem_u
+        (i32.const -10)
+        (i32.const -11)
+       )
+      )
+      (drop
+       (i32.and
+        (i32.const -10)
+        (i32.const -11)
+       )
+      )
+      (drop
+       (i64.or
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (i32.xor
+        (i32.const -10)
+        (i32.const -11)
+       )
+      )
+      (drop
+       (i64.shl
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (i64.shr_u
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (i32.shr_s
+        (i32.const -10)
+        (i32.const -11)
+       )
+      )
+      (drop
+       (i32.rotl
+        (i32.const -10)
+        (i32.const -11)
+       )
+      )
+      (drop
+       (i64.rotr
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (f32.div
+        (f32.const -33.61199951171875)
+        (f32.const -62.5)
+       )
+      )
+      (drop
+       (f64.copysign
+        (f64.const -9005.841)
+        (f64.const -9007.333)
+       )
+      )
+      (drop
+       (f32.min
+        (f32.const -33.61199951171875)
+        (f32.const -62.5)
+       )
+      )
+      (drop
+       (f64.max
+        (f64.const -9005.841)
+        (f64.const -9007.333)
+       )
+      )
+      (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 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (i64.le_s
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (i32.le_u
+        (i32.const -10)
+        (i32.const -11)
+       )
+      )
+      (drop
+       (i64.gt_s
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (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 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (f32.lt
+        (f32.const -33.61199951171875)
+        (f32.const -62.5)
+       )
+      )
+      (drop
+       (f64.le
+        (f64.const -9005.841)
+        (f64.const -9007.333)
+       )
+      )
+      (drop
+       (f64.gt
+        (f64.const -9005.841)
+        (f64.const -9007.333)
+       )
+      )
+      (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
+       (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
+       (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
+       (i64x2.mul
+        (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
+       (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
+       (f32x4.pmin
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f32x4.pmax
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f32x4.ceil
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f32x4.floor
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f32x4.trunc
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f32x4.nearest
+        (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
+       (f64x2.pmin
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f64x2.pmax
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f64x2.ceil
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f64x2.floor
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f64x2.trunc
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f64x2.nearest
+        (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 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (i8x16.extract_lane_u 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (i16x8.extract_lane_s 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (i16x8.extract_lane_u 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (i32x4.extract_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (i64x2.extract_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f32x4.extract_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f64x2.extract_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (i16x8.replace_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (i32.const 42)
+       )
+      )
+      (drop
+       (i8x16.replace_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (i32.const 42)
+       )
+      )
+      (drop
+       (i32x4.replace_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (i32.const 42)
+       )
+      )
+      (drop
+       (i64x2.replace_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (i64.const 184683593770)
+       )
+      )
+      (drop
+       (f32x4.replace_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (f32.const 42)
+       )
+      )
+      (drop
+       (f64x2.replace_lane 1
+        (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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+        (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 extern)
+       )
+      )
+      (drop
+       (ref.is_null
+        (ref.null func)
+       )
+      )
+      (drop
+       (ref.is_null
+        (ref.func "$kitchen()sinker")
+       )
+      )
+      (drop
+       (select (result funcref)
+        (ref.null func)
+        (ref.func "$kitchen()sinker")
+        (i32.const 1)
+       )
+      )
+      (drop
+       (ref.eq
+        (ref.null eq)
+        (ref.null eq)
+       )
+      )
+      (try
+       (do
+        (throw $a-event
+         (i32.const 0)
+        )
+       )
+       (catch
+        (local.set $5
+         (pop exnref)
+        )
+        (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 0)
+       )
+      )
+      (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)
+        )
+       )
+      )
+      (drop
+       (pop i32)
+      )
+      (drop
+       (pop i64)
+      )
+      (drop
+       (pop f32)
+      )
+      (drop
+       (pop f64)
+      )
+      (drop
+       (pop v128)
+      )
+      (drop
+       (pop funcref)
+      )
+      (drop
+       (pop externref)
+      )
+      (drop
+       (pop exnref)
+      )
+      (drop
+       (pop anyref)
+      )
+      (drop
+       (pop eqref)
+      )
+      (drop
+       (pop i31ref)
+      )
+      (drop
+       (memory.size)
+      )
+      (drop
+       (memory.grow
+        (i32.const 0)
+       )
+      )
+      (drop
+       (i31.new
+        (i32.const 0)
+       )
+      )
+      (drop
+       (i31.get_s
+        (i31.new
+         (i32.const 1)
+        )
+       )
+      )
+      (drop
+       (i31.get_u
+        (i31.new
+         (i32.const 2)
+        )
+       )
+      )
+      (nop)
+      (unreachable)
+     )
+    )
+   )
+   (i32.const 42)
+  )
+ )
+ (func $starter
+  (nop)
+ )
+)
+
+(module
+ (type $i32_i64_f32_f64_=>_i32 (func (param i32 i64 f32 f64) (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_none (func))
+ (type $i32_f64_=>_f32 (func (param i32 f64) (result f32)))
+ (import "module" "base" (global $a-global-imp i32))
+ (import "module" "base" (global $a-mut-global-imp (mut i32)))
+ (import "module" "base" (func $an-imported (param i32 f64) (result f32)))
+ (import "module" "base" (event $a-event-imp (attr 0) (param i32)))
+ (memory $0 (shared 1 256))
+ (data (i32.const 10) "hello, world")
+ (data passive "I am passive")
+ (table $0 1 funcref)
+ (elem (i32.const 0) "$kitchen()sinker")
+ (global $a-global i32 (i32.const 1))
+ (event $a-event (attr 0) (param i32))
+ (export "kitchen_sinker" (func "$kitchen()sinker"))
+ (export "a-global-exp" (global $a-global))
+ (export "a-event-exp" (event $a-event))
+ (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.841)
+       )
+      )
+      (drop
+       (f32.ceil
+        (f32.const -33.61199951171875)
+       )
+      )
+      (drop
+       (f64.floor
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (f32.trunc
+        (f32.const -33.61199951171875)
+       )
+      )
+      (drop
+       (f32.nearest
+        (f32.const -33.61199951171875)
+       )
+      )
+      (drop
+       (f64.sqrt
+        (f64.const -9005.841)
+       )
+      )
+      (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.841)
+       )
+      )
+      (drop
+       (i64.trunc_f64_s
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (i32.trunc_f64_u
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (i64.trunc_f64_u
+        (f64.const -9005.841)
+       )
+      )
+      (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.841)
+       )
+      )
+      (drop
+       (i64.trunc_sat_f64_s
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (i32.trunc_sat_f64_u
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (i64.trunc_sat_f64_u
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (i32.reinterpret_f32
+        (f32.const -33.61199951171875)
+       )
+      )
+      (drop
+       (i64.reinterpret_f64
+        (f64.const -9005.841)
+       )
+      )
+      (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.841)
+       )
+      )
+      (drop
+       (f32.reinterpret_i32
+        (i32.const -10)
+       )
+      )
+      (drop
+       (f64.reinterpret_i64
+        (i64.const -22)
+       )
+      )
+      (drop
+       (i8x16.splat
+        (i32.const 42)
+       )
+      )
+      (drop
+       (i16x8.splat
+        (i32.const 42)
+       )
+      )
+      (drop
+       (i32x4.splat
+        (i32.const 42)
+       )
+      )
+      (drop
+       (i64x2.splat
+        (i64.const 1958505087099)
+       )
+      )
+      (drop
+       (f32x4.splat
+        (f32.const 42)
+       )
+      )
+      (drop
+       (f64x2.splat
+        (f64.const 42)
+       )
+      )
+      (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.841)
+        (f64.const -9007.333)
+       )
+      )
+      (drop
+       (i32.div_s
+        (i32.const -10)
+        (i32.const -11)
+       )
+      )
+      (drop
+       (i64.div_u
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (i64.rem_s
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (i32.rem_u
+        (i32.const -10)
+        (i32.const -11)
+       )
+      )
+      (drop
+       (i32.and
+        (i32.const -10)
+        (i32.const -11)
+       )
+      )
+      (drop
+       (i64.or
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (i32.xor
+        (i32.const -10)
+        (i32.const -11)
+       )
+      )
+      (drop
+       (i64.shl
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (i64.shr_u
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (i32.shr_s
+        (i32.const -10)
+        (i32.const -11)
+       )
+      )
+      (drop
+       (i32.rotl
+        (i32.const -10)
+        (i32.const -11)
+       )
+      )
+      (drop
+       (i64.rotr
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (f32.div
+        (f32.const -33.61199951171875)
+        (f32.const -62.5)
+       )
+      )
+      (drop
+       (f64.copysign
+        (f64.const -9005.841)
+        (f64.const -9007.333)
+       )
+      )
+      (drop
+       (f32.min
+        (f32.const -33.61199951171875)
+        (f32.const -62.5)
+       )
+      )
+      (drop
+       (f64.max
+        (f64.const -9005.841)
+        (f64.const -9007.333)
+       )
+      )
+      (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 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (i64.le_s
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (i32.le_u
+        (i32.const -10)
+        (i32.const -11)
+       )
+      )
+      (drop
+       (i64.gt_s
+        (i64.const 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (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 4294967274)
+        (i64.const 4294967273)
+       )
+      )
+      (drop
+       (f32.lt
+        (f32.const -33.61199951171875)
+        (f32.const -62.5)
+       )
+      )
+      (drop
+       (f64.le
+        (f64.const -9005.841)
+        (f64.const -9007.333)
+       )
+      )
+      (drop
+       (f64.gt
+        (f64.const -9005.841)
+        (f64.const -9007.333)
+       )
+      )
+      (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
+       (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
+       (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
+       (i64x2.mul
+        (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
+       (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
+       (f32x4.pmin
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f32x4.pmax
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f32x4.ceil
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f32x4.floor
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f32x4.trunc
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f32x4.nearest
+        (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
+       (f64x2.pmin
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f64x2.pmax
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f64x2.ceil
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f64x2.floor
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f64x2.trunc
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f64x2.nearest
+        (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 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (i8x16.extract_lane_u 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (i16x8.extract_lane_s 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (i16x8.extract_lane_u 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (i32x4.extract_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (i64x2.extract_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f32x4.extract_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f64x2.extract_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (i16x8.replace_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (i32.const 42)
+       )
+      )
+      (drop
+       (i8x16.replace_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (i32.const 42)
+       )
+      )
+      (drop
+       (i32x4.replace_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (i32.const 42)
+       )
+      )
+      (drop
+       (i64x2.replace_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (i64.const 184683593770)
+       )
+      )
+      (drop
+       (f32x4.replace_lane 1
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (f32.const 42)
+       )
+      )
+      (drop
+       (f64x2.replace_lane 1
+        (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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+        (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 extern)
+       )
+      )
+      (drop
+       (ref.is_null
+        (ref.null func)
+       )
+      )
+      (drop
+       (ref.is_null
+        (ref.func "$kitchen()sinker")
+       )
+      )
+      (drop
+       (select (result funcref)
+        (ref.null func)
+        (ref.func "$kitchen()sinker")
+        (i32.const 1)
+       )
+      )
+      (drop
+       (ref.eq
+        (ref.null eq)
+        (ref.null eq)
+       )
+      )
+      (try
+       (do
+        (throw $a-event
+         (i32.const 0)
+        )
+       )
+       (catch
+        (local.set $5
+         (pop exnref)
+        )
+        (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 0)
+       )
+      )
+      (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)
+        )
+       )
+      )
+      (drop
+       (pop i32)
+      )
+      (drop
+       (pop i64)
+      )
+      (drop
+       (pop f32)
+      )
+      (drop
+       (pop f64)
+      )
+      (drop
+       (pop v128)
+      )
+      (drop
+       (pop funcref)
+      )
+      (drop
+       (pop externref)
+      )
+      (drop
+       (pop exnref)
+      )
+      (drop
+       (pop anyref)
+      )
+      (drop
+       (pop eqref)
+      )
+      (drop
+       (pop i31ref)
+      )
+      (drop
+       (memory.size)
+      )
+      (drop
+       (memory.grow
+        (i32.const 0)
+       )
+      )
+      (drop
+       (i31.new
+        (i32.const 0)
+       )
+      )
+      (drop
+       (i31.get_s
+        (i31.new
+         (i32.const 1)
+        )
+       )
+      )
+      (drop
+       (i31.get_u
+        (i31.new
+         (i32.const 2)
+        )
+       )
+      )
+      (nop)
+      (unreachable)
+     )
+    )
+   )
+   (i32.const 42)
+  )
+ )
+ (func $starter
+  (nop)
+ )
+)
+
+raw:
+(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)
+   )
+  )
+ )
+)
+
+optimized:
+(module
+)
+
+module loaded from binary form:
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (global $a-global i32 (i32.const 3))
+ (event $event$0 (attr 0) (param i32 i32))
+ (func $adder (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
+
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (import "spectest" "print" (func $print-i32 (param i32)))
+ (start $starter)
+ (func $starter
+  (call $print-i32
+   (i32.const 1234)
+  )
+ )
+)
+
+1234 : i32
+(module
+ (type $none_=>_none (func))
+ (func $func
+  (local $0 i32)
+  (local.set $0
+   (i64.const 1234)
+  )
+ )
+)
+
+[wasm-validator error in function func] local.set's value type must be correct, on 
+[none] (local.set $0
+ [i64] (i64.const 1234)
+)
+validation: 0
+test_parsing text:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (global $a-global i32 (i32.const 3))
+ (event $a-event (attr 0) (param i32))
+ (func $adder (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
+
+module loaded from text form:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (global $a-global i32 (i32.const 3))
+ (event $a-event (attr 0) (param i32))
+ (func $ADD_ER (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
+
+sizeof Literal: 24
+(module
+ (type $none_=>_none (func))
+ (memory $0 1 256)
+ (data (i32.const 10) "hello, world")
+ (data (global.get $a-global) "segment data 2")
+ (table $0 1 funcref)
+ (elem (i32.const 0) $fn0 $fn1 $fn2)
+ (global $a-global i32 (i32.const 125))
+ (export "export0" (func $fn0))
+ (export "export1" (func $fn1))
+ (export "export2" (func $fn2))
+ (export "mem" (memory $0))
+ (func $fn0
+  (nop)
+ )
+ (func $fn1
+  (nop)
+ )
+ (func $fn2
+  (nop)
+ )
+)
+
+getExpressionInfo(memory.grow)={"id":21,"type":2,"delta":1}
+getExpressionInfo(switch)={"id":5,"type":1,"names":["label"],"defaultName":"label","condition":0,"value":0}
diff --git a/binaryen/test/binaryen.js/low-memory-unused.js b/binaryen/test/binaryen.js/low-memory-unused.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/low-memory-unused.js
@@ -0,0 +1,38 @@
+var wast = `
+(module
+ (memory $0 1)
+ (export "test" (func $test))
+ (func $test (param $0 i32) (result i32)
+  (i32.load
+    (i32.add
+      (local.get $0)
+      (i32.const 128)
+    )
+  )
+ )
+)
+`;
+
+console.log("=== input wast ===" + wast);
+
+var module = binaryen.parseText(wast);
+
+console.log("=== unoptimized ===");
+assert(module.validate());
+console.log(module.emitText());
+
+console.log("=== optimized, lowMemoryUnused=" + binaryen.getLowMemoryUnused() + " ===");
+module.optimize();
+assert(module.validate());
+console.log(module.emitText());
+
+binaryen.setLowMemoryUnused(true);
+assert(binaryen.getLowMemoryUnused());
+console.log();
+
+console.log("=== optimized, lowMemoryUnused=" + binaryen.getLowMemoryUnused() + " ===");
+module.optimize();
+assert(module.validate());
+console.log(module.emitText());
+
+module.dispose();
diff --git a/binaryen/test/binaryen.js/low-memory-unused.js.txt b/binaryen/test/binaryen.js/low-memory-unused.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/low-memory-unused.js.txt
@@ -0,0 +1,57 @@
+=== input wast ===
+(module
+ (memory $0 1)
+ (export "test" (func $test))
+ (func $test (param $0 i32) (result i32)
+  (i32.load
+    (i32.add
+      (local.get $0)
+      (i32.const 128)
+    )
+  )
+ )
+)
+
+=== unoptimized ===
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 1)
+ (export "test" (func $test))
+ (func $test (param $0 i32) (result i32)
+  (i32.load
+   (i32.add
+    (local.get $0)
+    (i32.const 128)
+   )
+  )
+ )
+)
+
+=== optimized, lowMemoryUnused=false ===
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 1)
+ (export "test" (func $test))
+ (func $test (; has Stack IR ;) (param $0 i32) (result i32)
+  (i32.load
+   (i32.add
+    (local.get $0)
+    (i32.const 128)
+   )
+  )
+ )
+)
+
+
+=== optimized, lowMemoryUnused=true ===
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 1)
+ (export "test" (func $test))
+ (func $test (; has Stack IR ;) (param $0 i32) (result i32)
+  (i32.load offset=128
+   (local.get $0)
+  )
+ )
+)
+
diff --git a/binaryen/test/binaryen.js/optimize-levels.js b/binaryen/test/binaryen.js/optimize-levels.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/optimize-levels.js
@@ -0,0 +1,61 @@
+var wast = `
+(module
+ (type $i (func (param i32) (result i32)))
+ (memory $0 0)
+ (export "test" (func $test))
+ (func $test (; 0 ;) (type $i) (param $0 i32) (result i32)
+  (block (result i32)
+   (if (result i32)
+    (local.get $0)
+    (local.get $0)
+    (i32.const 0)
+   )
+  )
+ )
+)
+`;
+
+console.log("=== input wast ===" + wast);
+
+function printOptions() {
+  console.log("optimizeLevel=" + binaryen.getOptimizeLevel());
+  console.log("shrinkLevel=" + binaryen.getShrinkLevel());
+}
+
+// Use defaults (should be equal to -Os below)
+var module = binaryen.parseText(wast);
+
+console.log("=== unoptimized ===");
+assert(module.validate());
+console.log(module.emitText());
+
+module.optimize();
+console.log("=== optimized using defaults ===");
+printOptions();
+assert(module.validate());
+console.log(module.emitText());
+module.dispose();
+
+// Use -O0 (should remove the block)
+module = binaryen.parseText(wast);
+
+binaryen.setOptimizeLevel(0);
+binaryen.setShrinkLevel(0);
+module.optimize();
+console.log("=== optimized with -O0 ===");
+printOptions();
+assert(module.validate());
+console.log(module.emitText());
+module.dispose();
+
+// Use -Os (should remove the block and convert to a select)
+module = binaryen.parseText(wast);
+
+binaryen.setOptimizeLevel(2);
+binaryen.setShrinkLevel(1);
+module.optimize();
+console.log("=== optimized with -Os ===");
+printOptions();
+assert(module.validate());
+console.log(module.emitText());
+module.dispose();
diff --git a/binaryen/test/binaryen.js/optimize-levels.js.txt b/binaryen/test/binaryen.js/optimize-levels.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/optimize-levels.js.txt
@@ -0,0 +1,77 @@
+=== input wast ===
+(module
+ (type $i (func (param i32) (result i32)))
+ (memory $0 0)
+ (export "test" (func $test))
+ (func $test (; 0 ;) (type $i) (param $0 i32) (result i32)
+  (block (result i32)
+   (if (result i32)
+    (local.get $0)
+    (local.get $0)
+    (i32.const 0)
+   )
+  )
+ )
+)
+
+=== unoptimized ===
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 0)
+ (export "test" (func $test))
+ (func $test (param $0 i32) (result i32)
+  (block $block (result i32)
+   (if (result i32)
+    (local.get $0)
+    (local.get $0)
+    (i32.const 0)
+   )
+  )
+ )
+)
+
+=== optimized using defaults ===
+optimizeLevel=2
+shrinkLevel=1
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "test" (func $test))
+ (func $test (; has Stack IR ;) (param $0 i32) (result i32)
+  (select
+   (local.get $0)
+   (i32.const 0)
+   (local.get $0)
+  )
+ )
+)
+
+=== optimized with -O0 ===
+optimizeLevel=0
+shrinkLevel=0
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "test" (func $test))
+ (func $test (param $0 i32) (result i32)
+  (select
+   (local.get $0)
+   (i32.const 0)
+   (local.get $0)
+  )
+ )
+)
+
+=== optimized with -Os ===
+optimizeLevel=2
+shrinkLevel=1
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "test" (func $test))
+ (func $test (; has Stack IR ;) (param $0 i32) (result i32)
+  (select
+   (local.get $0)
+   (i32.const 0)
+   (local.get $0)
+  )
+ )
+)
+
diff --git a/binaryen/test/binaryen.js/pass-arguments.js b/binaryen/test/binaryen.js/pass-arguments.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/pass-arguments.js
@@ -0,0 +1,13 @@
+assert(binaryen.getPassArgument("theKey") === null);
+
+binaryen.setPassArgument("theKey", "theValue");
+assert(binaryen.getPassArgument("theKey") === "theValue");
+
+binaryen.setPassArgument("theKey", null);
+assert(binaryen.getPassArgument("theKey") === null);
+
+binaryen.setPassArgument("theKey", "theValue2");
+assert(binaryen.getPassArgument("theKey") === "theValue2");
+
+binaryen.clearPassArguments();
+assert(binaryen.getPassArgument("theKey") === null);
diff --git a/binaryen/test/binaryen.js/pass-arguments.js.txt b/binaryen/test/binaryen.js/pass-arguments.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/pass-arguments.js.txt
diff --git a/binaryen/test/binaryen.js/reloc.js b/binaryen/test/binaryen.js/reloc.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/reloc.js
@@ -0,0 +1,21 @@
+var module = new binaryen.Module();
+
+// memory with offset
+
+module.addGlobalImport("memory_base", "env", "memory_base", binaryen.i32, false);
+module.setMemory(1, -1, null, [
+  {
+    offset: module.global.get("memory_base", binaryen.i32),
+    data: "data data".split('').map(function(x) { return x.charCodeAt(0) })
+  }
+]);
+
+// table with offset
+
+var func = module.addFunction("func", binaryen.none, binaryen.none, [], module.nop());
+
+module.addGlobalImport("table_base", "env", "table_base", binaryen.i32, false);
+module.setFunctionTable(1, -1, [ "func", "func" ], module.global.get("table_base", binaryen.i32));
+
+assert(module.validate());
+console.log(module.emitText());
diff --git a/binaryen/test/binaryen.js/reloc.js.txt b/binaryen/test/binaryen.js/reloc.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/reloc.js.txt
@@ -0,0 +1,13 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "memory_base" (global $memory_base i32))
+ (import "env" "table_base" (global $table_base i32))
+ (memory $0 1)
+ (data (global.get $memory_base) "data data")
+ (table $0 1 funcref)
+ (elem (global.get $table_base) $func $func)
+ (func $func
+  (nop)
+ )
+)
+
diff --git a/binaryen/test/binaryen.js/sideffects.js b/binaryen/test/binaryen.js/sideffects.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/sideffects.js
@@ -0,0 +1,116 @@
+console.log("SideEffects.None=" + binaryen.SideEffects.None);
+console.log("SideEffects.Branches=" + binaryen.SideEffects.Branches);
+console.log("SideEffects.Calls=" + binaryen.SideEffects.Calls);
+console.log("SideEffects.ReadsLocal=" + binaryen.SideEffects.ReadsLocal);
+console.log("SideEffects.WritesLocal=" + binaryen.SideEffects.WritesLocal);
+console.log("SideEffects.ReadsGlobal=" + binaryen.SideEffects.ReadsGlobal);
+console.log("SideEffects.WritesGlobal=" + binaryen.SideEffects.WritesGlobal);
+console.log("SideEffects.ReadsMemory=" + binaryen.SideEffects.ReadsMemory);
+console.log("SideEffects.WritesMemory=" + binaryen.SideEffects.WritesMemory);
+console.log("SideEffects.ImplicitTrap=" + binaryen.SideEffects.ImplicitTrap);
+console.log("SideEffects.IsAtomic=" + binaryen.SideEffects.IsAtomic);
+console.log("SideEffects.Throws=" + binaryen.SideEffects.Throws);
+console.log("SideEffects.DanglingPop=" + binaryen.SideEffects.DanglingPop);
+console.log("SideEffects.Any=" + binaryen.SideEffects.Any);
+
+var module = new binaryen.Module();
+assert(
+  binaryen.getSideEffects(
+    module.i32.const(1)
+  )
+  ==
+  binaryen.SideEffects.None
+);
+assert(
+  binaryen.getSideEffects(
+    module.br("test")
+  )
+  ==
+  binaryen.SideEffects.Branches
+);
+assert(
+  binaryen.getSideEffects(
+    module.call("test", [], binaryen.i32)
+  )
+  ==
+  binaryen.SideEffects.Calls
+);
+assert(
+  binaryen.getSideEffects(
+    module.local.get("test", binaryen.i32)
+  )
+  ==
+  binaryen.SideEffects.ReadsLocal
+);
+assert(
+  binaryen.getSideEffects(
+    module.local.set("test",
+      module.i32.const(1)
+    )
+  )
+  ==
+  binaryen.SideEffects.WritesLocal
+);
+assert(
+  binaryen.getSideEffects(
+    module.global.get("test", binaryen.i32)
+  )
+  ==
+  binaryen.SideEffects.ReadsGlobal
+);
+assert(
+  binaryen.getSideEffects(
+    module.global.set("test", module.i32.const(1))
+  )
+  ==
+  binaryen.SideEffects.WritesGlobal
+);
+assert(
+  binaryen.getSideEffects(
+    module.i32.load(0, 0,
+      module.i32.const(0)
+    )
+  )
+  ==
+  binaryen.SideEffects.ReadsMemory | binaryen.SideEffects.ImplicitTrap
+);
+assert(
+  binaryen.getSideEffects(
+    module.i32.store(0, 0,
+      module.i32.const(0),
+      module.i32.const(1)
+    )
+  )
+  ==
+  binaryen.SideEffects.WritesMemory | binaryen.SideEffects.ImplicitTrap
+);
+assert(
+  binaryen.getSideEffects(
+    module.i32.div_s(
+      module.i32.const(1),
+      module.i32.const(0)
+    )
+  )
+  ==
+  binaryen.SideEffects.ImplicitTrap
+);
+
+// If exception handling feature is enabled, calls can throw
+module.setFeatures(binaryen.Features.All);
+assert(
+  binaryen.getSideEffects(
+    module.call("test", [], binaryen.i32),
+    module.getFeatures()
+  )
+  ==
+  binaryen.SideEffects.Calls | binaryen.SideEffects.Throws
+);
+
+assert(
+  binaryen.getSideEffects(
+    module.drop(module.exnref.pop()),
+    module.getFeatures()
+  )
+  ==
+  binaryen.SideEffects.DanglingPop
+);
diff --git a/binaryen/test/binaryen.js/sideffects.js.txt b/binaryen/test/binaryen.js/sideffects.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/sideffects.js.txt
@@ -0,0 +1,14 @@
+SideEffects.None=0
+SideEffects.Branches=1
+SideEffects.Calls=2
+SideEffects.ReadsLocal=4
+SideEffects.WritesLocal=8
+SideEffects.ReadsGlobal=16
+SideEffects.WritesGlobal=32
+SideEffects.ReadsMemory=64
+SideEffects.WritesMemory=128
+SideEffects.ImplicitTrap=256
+SideEffects.IsAtomic=512
+SideEffects.Throws=1024
+SideEffects.DanglingPop=2048
+SideEffects.Any=4095
diff --git a/binaryen/test/binaryen.js/sieve.js b/binaryen/test/binaryen.js/sieve.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/sieve.js
@@ -0,0 +1,75 @@
+// Create a module to work on
+var module = new binaryen.Module();
+
+// Set a memory of initially one page, maximum 100 pages
+module.setMemory(1, 100);
+
+var body = module.block(
+  null,
+  [
+    // if the current memory size is too small, grow it
+    module.if(
+      module.i32.lt_u(
+        module.i32.mul(
+          module.memory.size(),
+          module.i32.const(65536)
+        ),
+        module.local.get(0, binaryen.i32)
+      ),
+      module.drop(
+        module.memory.grow(
+          module.i32.sub(
+            module.i32.div_u(
+              module.i32.add(
+                module.local.get(0, binaryen.i32),
+                module.i32.const(65535)
+              ),
+              module.i32.const(65536)
+            ),
+            module.memory.size()
+          )
+        )
+      )
+    ),
+    // first, clear memory
+    module.local.set(1, module.i32.const(0)),
+    module.loop('clear', module.block(null, [
+      module.i32.store8(0, 1,
+        module.local.get(1, binaryen.i32),
+        module.i32.const(0)
+      ),
+      module.local.set(1, module.i32.add(
+        module.local.get(1, binaryen.i32),
+        module.i32.const(1)
+      )),
+      module.br_if('clear', module.i32.eq(
+        module.local.get(1, binaryen.i32),
+        module.local.get(0, binaryen.i32)
+      ))
+    ])),
+    // perform the sieve TODO
+    // calculate how many primes there are
+    module.return(module.local.get(0, binaryen.i32))
+  ],
+  binaryen.none
+);
+
+// Create the add function
+// Note: no additional local variables (that's the [])
+module.addFunction('sieve', binaryen.i32, binaryen.i32, [binaryen.i32], body);
+
+// Export the function, so we can call it later (for simplicity we
+// export it as the same name as it has internally)
+module.addFunctionExport('sieve', 'sieve');
+
+if (!module.validate()) throw 'did not validate :(';
+
+// Print out the text
+console.log(module.emitText());
+
+// Optimize the module! This removes the 'return', since the
+// output of the add can just fall through
+module.optimize();
+
+// Print out the optimized module's text
+console.log('optimized:\n\n' + module.emitText());
diff --git a/binaryen/test/binaryen.js/sieve.js.txt b/binaryen/test/binaryen.js/sieve.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/sieve.js.txt
@@ -0,0 +1,108 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 1 100)
+ (export "sieve" (func $sieve))
+ (func $sieve (param $0 i32) (result i32)
+  (local $1 i32)
+  (if
+   (i32.lt_u
+    (i32.mul
+     (memory.size)
+     (i32.const 65536)
+    )
+    (local.get $0)
+   )
+   (drop
+    (memory.grow
+     (i32.sub
+      (i32.div_u
+       (i32.add
+        (local.get $0)
+        (i32.const 65535)
+       )
+       (i32.const 65536)
+      )
+      (memory.size)
+     )
+    )
+   )
+  )
+  (local.set $1
+   (i32.const 0)
+  )
+  (loop $clear
+   (i32.store8
+    (local.get $1)
+    (i32.const 0)
+   )
+   (local.set $1
+    (i32.add
+     (local.get $1)
+     (i32.const 1)
+    )
+   )
+   (br_if $clear
+    (i32.eq
+     (local.get $1)
+     (local.get $0)
+    )
+   )
+  )
+  (return
+   (local.get $0)
+  )
+ )
+)
+
+optimized:
+
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 1 100)
+ (export "sieve" (func $sieve))
+ (func $sieve (; has Stack IR ;) (param $0 i32) (result i32)
+  (local $1 i32)
+  (if
+   (i32.lt_u
+    (i32.shl
+     (memory.size)
+     (i32.const 16)
+    )
+    (local.get $0)
+   )
+   (drop
+    (memory.grow
+     (i32.sub
+      (i32.shr_u
+       (i32.add
+        (local.get $0)
+        (i32.const 65535)
+       )
+       (i32.const 16)
+      )
+      (memory.size)
+     )
+    )
+   )
+  )
+  (loop $clear
+   (i32.store8
+    (local.get $1)
+    (i32.const 0)
+   )
+   (br_if $clear
+    (i32.eq
+     (local.tee $1
+      (i32.add
+       (local.get $1)
+       (i32.const 1)
+      )
+     )
+     (local.get $0)
+    )
+   )
+  )
+  (local.get $0)
+ )
+)
+
diff --git a/binaryen/test/binaryen.js/simd.js b/binaryen/test/binaryen.js/simd.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/simd.js
@@ -0,0 +1,5 @@
+var module = new binaryen.Module();
+
+var expr = module.v128.const([1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]);
+var info = binaryen.getExpressionInfo(expr);
+console.log("v128.const i8x16 0x" + info.value.map(b => b.toString(16)).join(" 0x"));
diff --git a/binaryen/test/binaryen.js/simd.js.txt b/binaryen/test/binaryen.js/simd.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/simd.js.txt
@@ -0,0 +1,1 @@
+v128.const i8x16 0x1 0x0 0x0 0x0 0x2 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0x4 0x0 0x0 0x0
diff --git a/binaryen/test/binaryen.js/sourcemap.js b/binaryen/test/binaryen.js/sourcemap.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/sourcemap.js
@@ -0,0 +1,38 @@
+var module = new binaryen.Module();
+
+var fileIndex = module.addDebugInfoFileName("module.c");
+
+console.log(module.getDebugInfoFileName(fileIndex));
+console.log();
+
+var expr = module.i32.const(1);
+var body = module.block("", [
+  expr
+], binaryen.i32);
+
+var func = module.addFunction("main", binaryen.none, binaryen.i32, [], body);
+
+module.setDebugLocation(func, expr, fileIndex, 1, 2);
+module.setDebugLocation(func, body, fileIndex, 0, 3);
+
+var output = module.emitBinary("module.wasm.map");
+assert(module.validate());
+
+function dumpBinary(buffer) {
+  var hex = [], o, b, h;
+  for (var i = 0; i < buffer.length; ++i) {
+    o = i.toString(16);
+    while (o.length < 3) o = "0" + o;
+    if ((i & 15) === 0) hex.push((i ? "\n" : "") + o + ":");
+    if ((b = buffer[i]) >= 0x21 && b <= 0x7e)
+      h = String.fromCharCode(b) + ' ';
+    else if ((h = b.toString(16)).length < 2)
+      h = "0" + h;
+    hex.push(h);
+  }
+  console.log(hex.join(" "));
+}
+
+dumpBinary(output.binary);
+console.log();
+console.log(output.sourceMap);
diff --git a/binaryen/test/binaryen.js/sourcemap.js.txt b/binaryen/test/binaryen.js/sourcemap.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/sourcemap.js.txt
@@ -0,0 +1,8 @@
+module.c
+
+000: 00 a  s  m  01 00 00 00 01 05 01 `  00 01 7f 03 
+010: 02 01 00 0a 06 01 04 00 A  01 0b 00 !  10 s  o  
+020: u  r  c  e  M  a  p  p  i  n  g  U  R  L  0f m  
+030: o  d  u  l  e  .  w  a  s  m  .  m  a  p 
+
+{"version":3,"sources":["module.c"],"names":[],"mappings":"wBAAE"}
diff --git a/binaryen/test/binaryen.js/stackir.js b/binaryen/test/binaryen.js/stackir.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/stackir.js
@@ -0,0 +1,29 @@
+var wast = `
+(module
+ (type $i (func (param i32) (result i32)))
+ (memory $0 0)
+ (export "test" (func $test))
+ (func $test (; 0 ;) (type $i) (param $0 i32) (result i32)
+  (block (result i32)
+   (block (result i32)
+    (if (result i32)
+     (local.get $0)
+     (local.get $0)
+     (i32.const 0)
+    )
+   )
+  )
+ )
+)
+`;
+
+console.log("=== input wast ===" + wast);
+
+var module = binaryen.parseText(wast);
+assert(module.validate());
+
+console.log("=== default ===");
+console.log(module.emitStackIR());
+
+console.log("=== optimize ==="); // should omit the second block
+console.log(module.emitStackIR(true));
diff --git a/binaryen/test/binaryen.js/stackir.js.txt b/binaryen/test/binaryen.js/stackir.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/stackir.js.txt
@@ -0,0 +1,50 @@
+=== input wast ===
+(module
+ (type $i (func (param i32) (result i32)))
+ (memory $0 0)
+ (export "test" (func $test))
+ (func $test (; 0 ;) (type $i) (param $0 i32) (result i32)
+  (block (result i32)
+   (block (result i32)
+    (if (result i32)
+     (local.get $0)
+     (local.get $0)
+     (i32.const 0)
+    )
+   )
+  )
+ )
+)
+
+=== default ===
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 0)
+ (export "test" (func $test))
+ (func $test (param $0 i32) (result i32)
+  block $block0 (result i32)
+   local.get $0
+   if (result i32)
+    local.get $0
+   else
+    i32.const 0
+   end
+  end
+ )
+)
+
+=== optimize ===
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 0)
+ (export "test" (func $test))
+ (func $test (param $0 i32) (result i32)
+  local.get $0
+  if (result i32)
+   local.get $0
+  else
+   i32.const 0
+  end
+ )
+)
+
diff --git a/binaryen/test/binaryen.js/tail_calls.js b/binaryen/test/binaryen.js/tail_calls.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/tail_calls.js
@@ -0,0 +1,36 @@
+var module = new binaryen.Module();
+
+module.setFeatures(binaryen.Features.TailCall);
+
+module.addTableImport("0", "env", "table");
+
+var foo = module.addFunction(
+  "foo",
+  binaryen.none,
+  binaryen.none,
+  [],
+  module.return_call("foo", [], binaryen.none, binaryen.none)
+);
+
+var bar = module.addFunction(
+  "bar",
+  binaryen.none,
+  binaryen.none,
+  [],
+  module.return_call_indirect(
+    module.i32.const(0),
+    [],
+    binaryen.none,
+    binaryen.none
+  )
+);
+
+assert(module.validate());
+
+console.log(
+  binaryen.getExpressionInfo(binaryen.getFunctionInfo(foo).body).isReturn
+);
+
+console.log(
+  binaryen.getExpressionInfo(binaryen.getFunctionInfo(bar).body).isReturn
+);
diff --git a/binaryen/test/binaryen.js/tail_calls.js.txt b/binaryen/test/binaryen.js/tail_calls.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/tail_calls.js.txt
@@ -0,0 +1,2 @@
+true
+true
diff --git a/binaryen/test/binaryen.js/validation_errors.js b/binaryen/test/binaryen.js/validation_errors.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/validation_errors.js
@@ -0,0 +1,25 @@
+(function() {
+  var mod = new binaryen.Module();
+  var func = mod.addFunction("test", binaryen.none, binaryen.none, [],
+    mod.block("", [
+      mod.drop(
+        mod.global.get("missing", binaryen.i32)
+      )
+    ])
+  );
+  mod.addExport("test", func);
+  console.log(mod.validate())
+})();
+
+(function() {
+  var mod = new binaryen.Module();
+  var func = mod.addFunction("test", binaryen.none, binaryen.none, [],
+    mod.block("", [
+      mod.drop(
+        mod.local.get(0, binaryen.i32)
+      )
+    ])
+  );
+  mod.addFunctionExport("test", "test", func);
+  console.log(mod.validate())
+})();
diff --git a/binaryen/test/binaryen.js/validation_errors.js.txt b/binaryen/test/binaryen.js/validation_errors.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/binaryen.js/validation_errors.js.txt
@@ -0,0 +1,6 @@
+[wasm-validator error in function test] unexpected false: global.get name must be valid, on 
+[i32] (global.get $missing)
+0
+[wasm-validator error in function test] unexpected false: local.get index must be small enough, on 
+[i32] (local.get $0)
+0
diff --git a/binaryen/test/br_to_exit.wasm b/binaryen/test/br_to_exit.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/br_to_exit.wasm differ
diff --git a/binaryen/test/br_to_exit.wasm.fromBinary b/binaryen/test/br_to_exit.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/br_to_exit.wasm.fromBinary
@@ -0,0 +1,9 @@
+(module
+ (type $none_=>_none (func))
+ (func $0
+  (block $label$0
+   (br $label$0)
+  )
+ )
+)
+
diff --git a/binaryen/test/break-to-return.wasm b/binaryen/test/break-to-return.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/break-to-return.wasm differ
diff --git a/binaryen/test/break-to-return.wasm.fromBinary b/binaryen/test/break-to-return.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/break-to-return.wasm.fromBinary
@@ -0,0 +1,16 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (memory $0 256 256)
+ (export "add" (func $0))
+ (func $0 (param $0 i32) (param $1 i32) (result i32)
+  (block $label$0 (result i32)
+   (br $label$0
+    (i32.add
+     (local.get $0)
+     (local.get $1)
+    )
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/break-within-catch.wasm b/binaryen/test/break-within-catch.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/break-within-catch.wasm differ
diff --git a/binaryen/test/break-within-catch.wasm.fromBinary b/binaryen/test/break-within-catch.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/break-within-catch.wasm.fromBinary
@@ -0,0 +1,19 @@
+(module
+ (type $none_=>_none (func))
+ (func $0
+  (block $label$2
+   (try
+    (do
+     (nop)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (br $label$2)
+    )
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/calls.cpp b/binaryen/test/calls.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/calls.cpp
@@ -0,0 +1,24 @@
+#include <emscripten.h>
+
+extern "C" {
+
+int inner(int x) {
+  return x*x + 2;
+}
+
+int EMSCRIPTEN_KEEPALIVE simple(int x) {
+  return inner(x);
+}
+
+int EMSCRIPTEN_KEEPALIVE fibo(int x) {
+  if (x == 0 || x == 1) return 1;
+  return fibo(x-1) + fibo(x-2);
+}
+
+int EMSCRIPTEN_KEEPALIVE run_script() {
+  emscripten_run_script("Module.print('hello from called script')");
+  return emscripten_run_script_int("1+2+3+4-1");
+}
+
+}
+
diff --git a/binaryen/test/calls.emcc b/binaryen/test/calls.emcc
new file mode 100644
--- /dev/null
+++ b/binaryen/test/calls.emcc
@@ -0,0 +1,1 @@
+["-s", "ASSERTIONS=0"]
diff --git a/binaryen/test/calls.post.js b/binaryen/test/calls.post.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/calls.post.js
@@ -0,0 +1,23 @@
+
+function test(name) {
+  Module.print(name);
+  function doTest(x) {
+    Module.print('  ' + [x] + ' ==> ' + Module['_' + name](x));
+  }
+  doTest(1);
+  doTest(2);
+  doTest(3);
+  doTest(4);
+  doTest(7);
+}
+
+test('simple');
+test('fibo');
+
+Module.print('run_script');
+Module.print(Module['_run_script']());
+
+Module.print('too many/few arguments');
+Module.print(Module['_simple']());
+Module.print(Module['_simple'](10, 20));
+
diff --git a/binaryen/test/calls.txt b/binaryen/test/calls.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/calls.txt
@@ -0,0 +1,18 @@
+simple
+  1 ==> 3
+  2 ==> 6
+  3 ==> 11
+  4 ==> 18
+  7 ==> 51
+fibo
+  1 ==> 1
+  2 ==> 2
+  3 ==> 3
+  4 ==> 5
+  7 ==> 21
+run_script
+hello from called script
+9
+too many/few arguments
+2
+102
diff --git a/binaryen/test/complexBinaryNames.wasm b/binaryen/test/complexBinaryNames.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/complexBinaryNames.wasm differ
diff --git a/binaryen/test/complexBinaryNames.wasm.fromBinary b/binaryen/test/complexBinaryNames.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/complexBinaryNames.wasm.fromBinary
@@ -0,0 +1,11 @@
+(module
+ (type $none_=>_none (func))
+ (export "$zoo (.bar)" (func $1))
+ (func $foo\20\28.bar\29
+  (nop)
+ )
+ (func $1
+  (call $foo\20\28.bar\29)
+ )
+)
+
diff --git a/binaryen/test/complexTextNames.wast b/binaryen/test/complexTextNames.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/complexTextNames.wast
@@ -0,0 +1,4 @@
+(module
+  (func $foo\20\28.bar\29)
+  (func "$zoo (.bar)" (call $foo\20\28.bar\29))
+)
diff --git a/binaryen/test/complexTextNames.wast.from-wast b/binaryen/test/complexTextNames.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/complexTextNames.wast.from-wast
@@ -0,0 +1,10 @@
+(module
+ (type $none_=>_none (func))
+ (export "$zoo (.bar)" (func $1))
+ (func $foo\20\28.bar\29
+  (nop)
+ )
+ (func $1
+  (call $foo\20\28.bar\29)
+ )
+)
diff --git a/binaryen/test/complexTextNames.wast.fromBinary b/binaryen/test/complexTextNames.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/complexTextNames.wast.fromBinary
@@ -0,0 +1,11 @@
+(module
+ (type $none_=>_none (func))
+ (export "$zoo (.bar)" (func $1))
+ (func $foo\20\28.bar\29
+  (nop)
+ )
+ (func $1
+  (call $foo\20\28.bar\29)
+ )
+)
+
diff --git a/binaryen/test/complexTextNames.wast.fromBinary.noDebugInfo b/binaryen/test/complexTextNames.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/complexTextNames.wast.fromBinary.noDebugInfo
@@ -0,0 +1,11 @@
+(module
+ (type $none_=>_none (func))
+ (export "$zoo (.bar)" (func $1))
+ (func $0
+  (nop)
+ )
+ (func $1
+  (call $0)
+ )
+)
+
diff --git a/binaryen/test/consume-stacky.wasm b/binaryen/test/consume-stacky.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/consume-stacky.wasm differ
diff --git a/binaryen/test/consume-stacky.wasm.fromBinary b/binaryen/test/consume-stacky.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/consume-stacky.wasm.fromBinary
@@ -0,0 +1,16 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 1 1)
+ (func $0 (result i32)
+  (local $0 i32)
+  (local.set $0
+   (i32.const 1)
+  )
+  (i32.store
+   (i32.const 2)
+   (i32.const 3)
+  )
+  (local.get $0)
+ )
+)
+
diff --git a/binaryen/test/control_flow.cpp b/binaryen/test/control_flow.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/control_flow.cpp
@@ -0,0 +1,117 @@
+#include <cmath>
+#include <algorithm>
+#include <emscripten.h>
+
+extern "C" {
+
+int EMSCRIPTEN_KEEPALIVE check_if(int x) {
+  if (x < 10) x++;
+  return x;
+}
+
+int EMSCRIPTEN_KEEPALIVE check_loop(int x) {
+  while (x < 100) x *= 2;
+  return x;
+}
+
+int EMSCRIPTEN_KEEPALIVE check_loop_break(int x) {
+  while (x < 100) {
+    x *= 2;
+    if (x > 30) break;
+    x++;
+  }
+  return x;
+}
+
+int EMSCRIPTEN_KEEPALIVE check_loop_continue(int x) {
+  while (x < 100) {
+    x *= 2;
+    if (x > 30) continue;
+    x++;
+  }
+  return x;
+}
+
+int EMSCRIPTEN_KEEPALIVE check_do_loop(int x) {
+  do {
+    x *= 2;
+    if (x > 1000) break;
+    x--;
+    if (x > 30) continue;
+    x++;
+  } while (x < 100);
+  return x;
+}
+
+int EMSCRIPTEN_KEEPALIVE check_do_once(int x) {
+  do {
+    x *= 2;
+    if (x > 1000) break;
+    x--;
+    if (x > 30) continue;
+    x++;
+  } while (0);
+  return x;
+}
+
+int EMSCRIPTEN_KEEPALIVE check_while_forever(int x) {
+  while (1) {
+    x *= 2;
+    if (x > 1000) break;
+    x--;
+    if (x > 30) continue;
+    x++;
+  }
+  return x;
+}
+
+int EMSCRIPTEN_KEEPALIVE check_switch(int x) {
+  switch (x) {
+    case 1: return 10;
+    case 3: return 20;
+    case 5: return 30;
+    case 10: return 40;
+    case 11: return 50;
+    default: return 60;
+  }
+  return 70;
+}
+
+int EMSCRIPTEN_KEEPALIVE check_switch_nodefault(int x) {
+  switch (x) {
+    case 1: return 10;
+    case 3: return 20;
+    case 5: return 30;
+    case 10: return 40;
+    case 11: return 50;
+  }
+  return 70;
+}
+
+int EMSCRIPTEN_KEEPALIVE check_switch_rdefault(int x) {
+  switch (x) {
+    default: return -60;
+    case 1: return 10;
+    case 3: return 20;
+    case 5: return 30;
+    case 10: return 40;
+    case 11: return 50;
+  }
+  return 70;
+}
+
+int EMSCRIPTEN_KEEPALIVE check_switch_fallthrough(int x) {
+  switch (x) {
+    case 1: return 10;
+    case 2:
+    case 3: x++;
+    case 5: return x;
+    case 10: return 40;
+    case 11: return 50;
+    default: return 60;
+  }
+  return 70;
+}
+
+}
+
diff --git a/binaryen/test/control_flow.emcc b/binaryen/test/control_flow.emcc
new file mode 100644
--- /dev/null
+++ b/binaryen/test/control_flow.emcc
@@ -0,0 +1,1 @@
+["-s", "ASSERTIONS=0"]
diff --git a/binaryen/test/control_flow.post.js b/binaryen/test/control_flow.post.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/control_flow.post.js
@@ -0,0 +1,26 @@
+
+function test(name) {
+  Module.print(name);
+  function doTest(x) {
+    Module.print('  ' + [x] + ' ==> ' + Module['_check_' + name](x));
+  }
+  doTest(1);
+  doTest(2);
+  doTest(3);
+  doTest(4);
+  doTest(11);
+  doTest(90);
+}
+
+test('if');
+test('loop');
+test('loop_break');
+test('loop_continue');
+test('do_loop');
+test('do_once');
+test('while_forever');
+test('switch');
+test('switch_nodefault');
+test('switch_rdefault');
+test('switch_fallthrough');
+
diff --git a/binaryen/test/control_flow.txt b/binaryen/test/control_flow.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/control_flow.txt
@@ -0,0 +1,77 @@
+if
+  1 ==> 2
+  2 ==> 3
+  3 ==> 4
+  4 ==> 5
+  11 ==> 11
+  90 ==> 90
+loop
+  1 ==> 128
+  2 ==> 128
+  3 ==> 192
+  4 ==> 128
+  11 ==> 176
+  90 ==> 180
+loop_break
+  1 ==> 62
+  2 ==> 46
+  3 ==> 62
+  4 ==> 38
+  11 ==> 46
+  90 ==> 180
+loop_continue
+  1 ==> 124
+  2 ==> 184
+  3 ==> 124
+  4 ==> 152
+  11 ==> 184
+  90 ==> 180
+do_loop
+  1 ==> 121
+  2 ==> 121
+  3 ==> 185
+  4 ==> 121
+  11 ==> 169
+  90 ==> 179
+do_once
+  1 ==> 2
+  2 ==> 4
+  3 ==> 6
+  4 ==> 8
+  11 ==> 22
+  90 ==> 179
+while_forever
+  1 ==> 1922
+  2 ==> 1922
+  3 ==> 1474
+  4 ==> 1922
+  11 ==> 1346
+  90 ==> 1426
+switch
+  1 ==> 10
+  2 ==> 60
+  3 ==> 20
+  4 ==> 60
+  11 ==> 50
+  90 ==> 60
+switch_nodefault
+  1 ==> 10
+  2 ==> 70
+  3 ==> 20
+  4 ==> 70
+  11 ==> 50
+  90 ==> 70
+switch_rdefault
+  1 ==> 10
+  2 ==> -60
+  3 ==> 20
+  4 ==> -60
+  11 ==> 50
+  90 ==> -60
+switch_fallthrough
+  1 ==> 10
+  2 ==> 3
+  3 ==> 4
+  4 ==> 60
+  11 ==> 50
+  90 ==> 60
diff --git a/binaryen/test/crash/expression-past-end-of-input.wasm b/binaryen/test/crash/expression-past-end-of-input.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/crash/expression-past-end-of-input.wasm differ
diff --git a/binaryen/test/crash/outside.wasm b/binaryen/test/crash/outside.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/crash/outside.wasm differ
diff --git a/binaryen/test/crash/use_var_outside_func.wasm b/binaryen/test/crash/use_var_outside_func.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/crash/use_var_outside_func.wasm differ
diff --git a/binaryen/test/ctor-eval/bad-indirect-call.wast b/binaryen/test/ctor-eval/bad-indirect-call.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/bad-indirect-call.wast
@@ -0,0 +1,15 @@
+(module
+  (type $v (func))
+  (memory 256 256)
+  (data (i32.const 10) "waka waka waka waka waka")
+  (table 1 1 funcref)
+  (elem (i32.const 0) $call-indirect)
+  (export "test1" $test1)
+  (func $test1
+    (call_indirect (type $v) (i32.const 1)) ;; unsafe to call, out of range
+    (i32.store8 (i32.const 20) (i32.const 120))
+  )
+  (func $call-indirect
+    (i32.store8 (i32.const 40) (i32.const 67))
+  )
+)
diff --git a/binaryen/test/ctor-eval/bad-indirect-call.wast.ctors b/binaryen/test/ctor-eval/bad-indirect-call.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/bad-indirect-call.wast.ctors
@@ -0,0 +1,1 @@
+test1
diff --git a/binaryen/test/ctor-eval/bad-indirect-call.wast.out b/binaryen/test/ctor-eval/bad-indirect-call.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/bad-indirect-call.wast.out
@@ -0,0 +1,23 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 256 256)
+ (data (i32.const 10) "waka waka waka waka waka")
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $call-indirect)
+ (export "test1" (func $test1))
+ (func $test1
+  (call_indirect (type $none_=>_none)
+   (i32.const 1)
+  )
+  (i32.store8
+   (i32.const 20)
+   (i32.const 120)
+  )
+ )
+ (func $call-indirect
+  (i32.store8
+   (i32.const 40)
+   (i32.const 67)
+  )
+ )
+)
diff --git a/binaryen/test/ctor-eval/bad-indirect-call2.wast b/binaryen/test/ctor-eval/bad-indirect-call2.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/bad-indirect-call2.wast
@@ -0,0 +1,16 @@
+(module
+  (type $v (func))
+  (memory 256 256)
+  (data (i32.const 10) "waka waka waka waka waka")
+  (import "env" "_abort" (func $_abort))
+  (table 2 2 funcref)
+  (elem (i32.const 0) $_abort $call-indirect)
+  (export "test1" $test1)
+  (func $test1
+    (call_indirect (type $v) (i32.const 0)) ;; unsafe to call, imported
+    (i32.store8 (i32.const 20) (i32.const 120))
+  )
+  (func $call-indirect
+    (i32.store8 (i32.const 40) (i32.const 67))
+  )
+)
diff --git a/binaryen/test/ctor-eval/bad-indirect-call2.wast.ctors b/binaryen/test/ctor-eval/bad-indirect-call2.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/bad-indirect-call2.wast.ctors
@@ -0,0 +1,1 @@
+test1
diff --git a/binaryen/test/ctor-eval/bad-indirect-call2.wast.out b/binaryen/test/ctor-eval/bad-indirect-call2.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/bad-indirect-call2.wast.out
@@ -0,0 +1,24 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "_abort" (func $_abort))
+ (memory $0 256 256)
+ (data (i32.const 10) "waka waka waka waka waka")
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $_abort $call-indirect)
+ (export "test1" (func $test1))
+ (func $test1
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+  (i32.store8
+   (i32.const 20)
+   (i32.const 120)
+  )
+ )
+ (func $call-indirect
+  (i32.store8
+   (i32.const 40)
+   (i32.const 67)
+  )
+ )
+)
diff --git a/binaryen/test/ctor-eval/bad-indirect-call3.wast b/binaryen/test/ctor-eval/bad-indirect-call3.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/bad-indirect-call3.wast
@@ -0,0 +1,16 @@
+(module
+  (type $funcref_=>_none (func (param funcref)))
+  (memory 256 256)
+  (data (i32.const 10) "waka waka waka waka waka")
+  (table funcref (elem $callee))
+  (export "sig_mismatch" (func $sig_mismatch))
+  (func $callee (param $0 exnref)
+    (i32.store8 (i32.const 40) (i32.const 67))
+  )
+  (func $sig_mismatch
+    (call_indirect (type $funcref_=>_none) ;; unsafe to call, signature mismatch
+      (ref.null func)
+      (i32.const 0)
+    )
+  )
+)
diff --git a/binaryen/test/ctor-eval/bad-indirect-call3.wast.ctors b/binaryen/test/ctor-eval/bad-indirect-call3.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/bad-indirect-call3.wast.ctors
@@ -0,0 +1,1 @@
+sig_mismatch
diff --git a/binaryen/test/ctor-eval/bad-indirect-call3.wast.out b/binaryen/test/ctor-eval/bad-indirect-call3.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/bad-indirect-call3.wast.out
@@ -0,0 +1,22 @@
+(module
+ (type $none_=>_none (func))
+ (type $funcref_=>_none (func (param funcref)))
+ (type $exnref_=>_none (func (param exnref)))
+ (memory $0 256 256)
+ (data (i32.const 10) "waka waka waka waka waka")
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $callee)
+ (export "sig_mismatch" (func $sig_mismatch))
+ (func $callee (param $0 exnref)
+  (i32.store8
+   (i32.const 40)
+   (i32.const 67)
+  )
+ )
+ (func $sig_mismatch
+  (call_indirect (type $funcref_=>_none)
+   (ref.null func)
+   (i32.const 0)
+  )
+ )
+)
diff --git a/binaryen/test/ctor-eval/basics-flatten.wast b/binaryen/test/ctor-eval/basics-flatten.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/basics-flatten.wast
@@ -0,0 +1,38 @@
+(module
+  (type $v (func))
+  (memory 256 256)
+  ;; test flattening of multiple segments
+  (data (i32.const 10) "waka ")
+  (data (i32.const 15) "waka") ;; skip a byte here
+  (data (i32.const 20) "waka waka waka")
+  (table 1 1 funcref)
+  (elem (i32.const 0) $call-indirect)
+  (export "test1" $test1)
+  (export "test2" $test2)
+  (export "test3" $test3)
+  (func $test1
+    (drop (i32.const 0)) ;; no work at all, really
+    (call $safe-to-call) ;; safe to call
+    (call_indirect (type $v) (i32.const 0)) ;; safe to call
+  )
+  (func $test2
+    (drop (i32.load (i32.const 12))) ;; a safe load
+    (drop (i32.load16_s (i32.const 12)))
+    (drop (i32.load8_s (i32.const 12)))
+    (drop (i32.load16_u (i32.const 12)))
+    (drop (i32.load8_u (i32.const 12)))
+  )
+  (func $test3
+    (i32.store (i32.const 12) (i32.const 115)) ;; a safe store, should alter memory
+    (i32.store16 (i32.const 20) (i32.const 31353))
+    (i32.store8 (i32.const 23) (i32.const 120))
+  )
+  (func $safe-to-call
+    (drop (i32.const 1))
+    (i32.store8 (i32.const 10) (i32.const 110)) ;; safe write too (lowest possible)
+    (i32.store8 (i32.const 33) (i32.const 109)) ;; safe write too (highest possible)
+  )
+  (func $call-indirect
+    (i32.store8 (i32.const 40) (i32.const 67))
+  )
+)
diff --git a/binaryen/test/ctor-eval/basics-flatten.wast.ctors b/binaryen/test/ctor-eval/basics-flatten.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/basics-flatten.wast.ctors
@@ -0,0 +1,1 @@
+test1,test2,test3
diff --git a/binaryen/test/ctor-eval/basics-flatten.wast.out b/binaryen/test/ctor-eval/basics-flatten.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/basics-flatten.wast.out
@@ -0,0 +1,11 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 256 256)
+ (data (i32.const 10) "nas\00\00\00aka\00yzkx waka wakm\00\00\00\00\00\00C")
+ (func $call-indirect
+  (i32.store8
+   (i32.const 40)
+   (i32.const 67)
+  )
+ )
+)
diff --git a/binaryen/test/ctor-eval/basics.wast b/binaryen/test/ctor-eval/basics.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/basics.wast
@@ -0,0 +1,35 @@
+(module
+  (type $v (func))
+  (memory 256 256)
+  (data (i32.const 10) "waka waka waka waka waka")
+  (table 1 1 funcref)
+  (elem (i32.const 0) $call-indirect)
+  (export "test1" $test1)
+  (export "test2" $test2)
+  (export "test3" $test3)
+  (func $test1
+    (drop (i32.const 0)) ;; no work at all, really
+    (call $safe-to-call) ;; safe to call
+    (call_indirect (type $v) (i32.const 0)) ;; safe to call
+  )
+  (func $test2
+    (drop (i32.load (i32.const 12))) ;; a safe load
+    (drop (i32.load16_s (i32.const 12)))
+    (drop (i32.load8_s (i32.const 12)))
+    (drop (i32.load16_u (i32.const 12)))
+    (drop (i32.load8_u (i32.const 12)))
+  )
+  (func $test3
+    (i32.store (i32.const 12) (i32.const 115)) ;; a safe store, should alter memory
+    (i32.store16 (i32.const 20) (i32.const 31353))
+    (i32.store8 (i32.const 23) (i32.const 120))
+  )
+  (func $safe-to-call
+    (drop (i32.const 1))
+    (i32.store8 (i32.const 10) (i32.const 110)) ;; safe write too (lowest possible)
+    (i32.store8 (i32.const 33) (i32.const 109)) ;; safe write too (highest possible)
+  )
+  (func $call-indirect
+    (i32.store8 (i32.const 40) (i32.const 67))
+  )
+)
diff --git a/binaryen/test/ctor-eval/basics.wast.ctors b/binaryen/test/ctor-eval/basics.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/basics.wast.ctors
@@ -0,0 +1,1 @@
+test1,test2,test3
diff --git a/binaryen/test/ctor-eval/basics.wast.out b/binaryen/test/ctor-eval/basics.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/basics.wast.out
@@ -0,0 +1,11 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 256 256)
+ (data (i32.const 10) "nas\00\00\00aka yzkx waka wakm\00\00\00\00\00\00C")
+ (func $call-indirect
+  (i32.store8
+   (i32.const 40)
+   (i32.const 67)
+  )
+ )
+)
diff --git a/binaryen/test/ctor-eval/imported-min.wast b/binaryen/test/ctor-eval/imported-min.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/imported-min.wast
@@ -0,0 +1,47 @@
+(module
+  (memory 256 256)
+  (data (i32.const 10) "waka waka waka waka waka")
+  ;; stack imports are special
+  (import "env" "STACKTOP" (global $STACKTOP$asm2wasm$import i32))
+  (import "env" "STACK_MAX" (global $STACK_MAX$asm2wasm$import i32))
+  (import "env" "tempDoublePtr" (global $tempDoublePtr i32))
+  (global $tempDoublePtrMut (mut i32) (global.get $tempDoublePtr))
+  (export "test1" $test1)
+  (export "test2" $test2)
+  (export "test3" $test3)
+  ;; ok to modify a global, if we keep it the same value
+  (global $mine (mut i32) (i32.const 1))
+  ;; stack imports are ok to use. their uses are the same as other
+  ;; globals - must keep the same value (which means, unwind the stack)
+  ;; here the global names are "minified"
+  (global $global0 (mut i32) (global.get $STACKTOP$asm2wasm$import))
+  (global $global1 (mut i32) (global.get $STACK_MAX$asm2wasm$import))
+  ;; a global initialized by an import, so bad, but ok if not used
+  (global $do-not-use (mut i32) (global.get $tempDoublePtr))
+  (func $test1
+    (local $temp i32)
+    (global.set $mine (i32.const 1))
+    (local.set $temp (global.get $global0))
+    (global.set $global0 (i32.const 1337)) ;; bad
+    (global.set $global0 (local.get $temp)) ;; save us
+    (global.set $global1 (i32.const 913370)) ;; bad
+    (global.set $global1 (local.get $temp)) ;; save us
+    ;; use the stack memory
+    (i32.store (local.get $temp) (i32.const 1337))
+    (if
+      (i32.ne
+        (i32.load (local.get $temp))
+        (i32.const 1337)
+      )
+      (unreachable) ;; they should be equal, never get here
+    )
+    ;; finally, do a valid store
+    (i32.store8 (i32.const 12) (i32.const 115))
+  )
+  (func $test2
+    (i32.store8 (i32.const 13) (i32.const 115))
+  )
+  (func $test3
+    (i32.store8 (i32.const 14) (i32.const 115))
+  )
+)
diff --git a/binaryen/test/ctor-eval/imported-min.wast.ctors b/binaryen/test/ctor-eval/imported-min.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/imported-min.wast.ctors
@@ -0,0 +1,1 @@
+test1,test2,test3
diff --git a/binaryen/test/ctor-eval/imported-min.wast.out b/binaryen/test/ctor-eval/imported-min.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/imported-min.wast.out
@@ -0,0 +1,2 @@
+(module
+)
diff --git a/binaryen/test/ctor-eval/imported.wast b/binaryen/test/ctor-eval/imported.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/imported.wast
@@ -0,0 +1,45 @@
+(module
+  (memory 256 256)
+  (data (i32.const 10) "waka waka waka waka waka")
+  ;; stack imports are special
+  (import "env" "STACKTOP" (global $STACKTOP$asm2wasm$import i32))
+  (import "env" "STACK_MAX" (global $STACK_MAX$asm2wasm$import i32))
+  ;; other imports must not be touched!
+  (import "env" "tempDoublePtr" (global $tempDoublePtr i32))
+  (global $tempDoublePtrMut (mut i32) (global.get $tempDoublePtr))
+  (export "test1" $test1)
+  (export "test2" $test2)
+  (export "test3" $test3)
+  ;; ok to modify a global, if we keep it the same value
+  (global $mine (mut i32) (i32.const 1))
+  ;; stack imports are ok to use. their uses are the same as other
+  ;; globals - must keep the same value (which means, unwind the stack)
+  (global $STACKTOP (mut i32) (global.get $STACKTOP$asm2wasm$import))
+  (global $STACK_MAX (mut i32) (global.get $STACK_MAX$asm2wasm$import))
+  ;; a global initialized by an import, so bad, but ok if not used
+  (global $do-not-use (mut i32) (global.get $tempDoublePtr))
+  (func $test1
+    (local $temp i32)
+    (global.set $mine (i32.const 1))
+    (local.set $temp (global.get $STACKTOP))
+    (global.set $STACKTOP (i32.const 1337)) ;; bad
+    (global.set $STACKTOP (local.get $temp)) ;; save us
+    ;; use the stack memory
+    (i32.store (local.get $temp) (i32.const 1337))
+    (if
+      (i32.ne
+        (i32.load (local.get $temp))
+        (i32.const 1337)
+      )
+      (unreachable) ;; they should be equal, never get here
+    )
+    ;; finally, do a valid store
+    (i32.store8 (i32.const 12) (i32.const 115))
+  )
+  (func $test2
+    (i32.store8 (i32.const 13) (i32.const 115))
+  )
+  (func $test3
+    (i32.store8 (i32.const 14) (i32.const 115))
+  )
+)
diff --git a/binaryen/test/ctor-eval/imported.wast.ctors b/binaryen/test/ctor-eval/imported.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/imported.wast.ctors
@@ -0,0 +1,1 @@
+test1,test2,test3
diff --git a/binaryen/test/ctor-eval/imported.wast.out b/binaryen/test/ctor-eval/imported.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/imported.wast.out
@@ -0,0 +1,2 @@
+(module
+)
diff --git a/binaryen/test/ctor-eval/imported2.wast b/binaryen/test/ctor-eval/imported2.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/imported2.wast
@@ -0,0 +1,26 @@
+(module
+  (memory 256 256)
+  (data (i32.const 10) "waka waka waka waka waka")
+  ;; stack imports are special-cased
+  (import "env" "STACKTOP" (global $STACKTOP i32))
+  (import "env" "STACK_MAX" (global $STACK_MAX i32))
+  ;; other imports must not be touched!
+  (import "env" "tempDoublePtr" (global $tempDoublePtr i32))
+  (export "test1" $test1)
+  (export "test2" $test2)
+  (export "test3" $test3)
+  ;; ok to modify a global, if we keep it the same value
+  (global $mine (mut i32) (i32.const 1))
+  (func $test1
+    (global.set $mine (i32.const 2))
+    (global.set $mine (i32.const 1)) ;; restore!
+    (i32.store8 (i32.const 12) (i32.const 115))
+  )
+  (func $test2
+    (global.set $mine (i32.const 2)) ;; embadden
+    (i32.store8 (i32.const 13) (i32.const 115))
+  )
+  (func $test3
+    (i32.store8 (i32.const 14) (i32.const 115))
+  )
+)
diff --git a/binaryen/test/ctor-eval/imported2.wast.ctors b/binaryen/test/ctor-eval/imported2.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/imported2.wast.ctors
@@ -0,0 +1,1 @@
+test1,test2,test3
diff --git a/binaryen/test/ctor-eval/imported2.wast.out b/binaryen/test/ctor-eval/imported2.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/imported2.wast.out
@@ -0,0 +1,23 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 256 256)
+ (data (i32.const 10) "wasa waka waka waka waka")
+ (global $mine (mut i32) (i32.const 1))
+ (export "test2" (func $test2))
+ (export "test3" (func $test3))
+ (func $test2
+  (global.set $mine
+   (i32.const 2)
+  )
+  (i32.store8
+   (i32.const 13)
+   (i32.const 115)
+  )
+ )
+ (func $test3
+  (i32.store8
+   (i32.const 14)
+   (i32.const 115)
+  )
+ )
+)
diff --git a/binaryen/test/ctor-eval/imported3.wast b/binaryen/test/ctor-eval/imported3.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/imported3.wast
@@ -0,0 +1,12 @@
+(module
+  (memory 256 256)
+  (data (i32.const 10) "waka waka waka waka waka")
+  ;; imports must not be used
+  (import "env" "tempDoublePtr" (global $tempDoublePtr i32))
+  (export "test1" $test1)
+  (global $mine (mut i32) (global.get $tempDoublePtr)) ;; BAD, if used
+  (func $test1
+    (drop (global.get $mine))
+    (i32.store8 (i32.const 13) (i32.const 115)) ;; we never get here.
+  )
+)
diff --git a/binaryen/test/ctor-eval/imported3.wast.ctors b/binaryen/test/ctor-eval/imported3.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/imported3.wast.ctors
@@ -0,0 +1,1 @@
+test1
diff --git a/binaryen/test/ctor-eval/imported3.wast.out b/binaryen/test/ctor-eval/imported3.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/imported3.wast.out
@@ -0,0 +1,12 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 256 256)
+ (data (i32.const 10) "waka waka waka waka waka")
+ (export "test1" (func $test1))
+ (func $test1
+  (i32.store8
+   (i32.const 13)
+   (i32.const 115)
+  )
+ )
+)
diff --git a/binaryen/test/ctor-eval/indirect-call3.wast b/binaryen/test/ctor-eval/indirect-call3.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/indirect-call3.wast
@@ -0,0 +1,17 @@
+(module
+  (type $v (func))
+  (memory 256 256)
+  (data (i32.const 10) "waka waka waka waka waka")
+  (import "env" "tableBase" (global $tableBase i32))
+  (import "env" "_abort" (func $_abort))
+  (table 2 2 funcref)
+  (elem (global.get $tableBase) $_abort $call-indirect)
+  (export "test1" $test1)
+  (func $test1
+    (call_indirect (type $v) (i32.const 1)) ;; safe to call
+    (i32.store8 (i32.const 20) (i32.const 120))
+  )
+  (func $call-indirect
+    (i32.store8 (i32.const 40) (i32.const 67))
+  )
+)
diff --git a/binaryen/test/ctor-eval/indirect-call3.wast.ctors b/binaryen/test/ctor-eval/indirect-call3.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/indirect-call3.wast.ctors
@@ -0,0 +1,1 @@
+test1
diff --git a/binaryen/test/ctor-eval/indirect-call3.wast.out b/binaryen/test/ctor-eval/indirect-call3.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/indirect-call3.wast.out
@@ -0,0 +1,13 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "_abort" (func $_abort))
+ (memory $0 256 256)
+ (data (i32.const 10) "waka waka xaka waka waka\00\00\00\00\00\00C")
+ (func $call-indirect
+  (i32.store8
+   (i32.const 40)
+   (i32.const 67)
+  )
+ )
+)
diff --git a/binaryen/test/ctor-eval/just_some.wast b/binaryen/test/ctor-eval/just_some.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/just_some.wast
@@ -0,0 +1,17 @@
+(module
+  (memory 256 256)
+  (data (i32.const 10) "waka waka waka waka waka")
+  (export "test1" $test1)
+  (export "test2" $test2)
+  (export "test3" $test3)
+  (func $test1
+    (i32.store8 (i32.const 12) (i32.const 115)) ;; a safe store, should alter memory
+  )
+  (func $test2
+    (unreachable)
+    (i32.store8 (i32.const 13) (i32.const 114)) ;; a safe store, should alter memory, but we trapped already
+  )
+  (func $test3
+    (i32.store8 (i32.const 13) (i32.const 113)) ;; a safe store, should alter memory, but we trapped already
+  )
+)
diff --git a/binaryen/test/ctor-eval/just_some.wast.ctors b/binaryen/test/ctor-eval/just_some.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/just_some.wast.ctors
@@ -0,0 +1,1 @@
+test1,test2,test3
diff --git a/binaryen/test/ctor-eval/just_some.wast.out b/binaryen/test/ctor-eval/just_some.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/just_some.wast.out
@@ -0,0 +1,16 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 256 256)
+ (data (i32.const 10) "wasa waka waka waka waka")
+ (export "test2" (func $test2))
+ (export "test3" (func $test3))
+ (func $test2
+  (unreachable)
+ )
+ (func $test3
+  (i32.store8
+   (i32.const 13)
+   (i32.const 113)
+  )
+ )
+)
diff --git a/binaryen/test/ctor-eval/no_partial.wast b/binaryen/test/ctor-eval/no_partial.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/no_partial.wast
@@ -0,0 +1,10 @@
+(module
+  (memory 256 256)
+  (data (i32.const 10) "waka waka waka waka waka")
+  (export "test1" $test1)
+  (func $test1
+    (i32.store8 (i32.const 12) (i32.const 115)) ;; a safe store, should alter memory
+    (unreachable)
+    (i32.store8 (i32.const 13) (i32.const 114)) ;; a safe store, should alter memory, but we trapped already, and so must roll back the first one too
+  )
+)
diff --git a/binaryen/test/ctor-eval/no_partial.wast.ctors b/binaryen/test/ctor-eval/no_partial.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/no_partial.wast.ctors
@@ -0,0 +1,1 @@
+test1
diff --git a/binaryen/test/ctor-eval/no_partial.wast.out b/binaryen/test/ctor-eval/no_partial.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/no_partial.wast.out
@@ -0,0 +1,13 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 256 256)
+ (data (i32.const 10) "waka waka waka waka waka")
+ (export "test1" (func $test1))
+ (func $test1
+  (i32.store8
+   (i32.const 12)
+   (i32.const 115)
+  )
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/ctor-eval/stack-direction.wast b/binaryen/test/ctor-eval/stack-direction.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/stack-direction.wast
@@ -0,0 +1,30 @@
+(module
+ (type $0 (func))
+ (import "env" "memory" (memory $1 256 256))
+ (import "env" "STACKTOP" (global $gimport$0 i32))
+ (global $global$0 (mut i32) (global.get $gimport$0))
+ (export "__post_instantiate" (func $0))
+ ;; if the stack goes **down**, this may seem to write to memory we care about
+ (func $0 (; 0 ;) (type $0)
+  (local $0 i32)
+  (i32.store offset=12
+   (local.tee $0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 16)
+    )
+   )
+   (i32.const 10)
+  )
+  (i32.store offset=12
+   (local.get $0)
+   (i32.add
+    (i32.load offset=12
+     (local.get $0)
+    )
+    (i32.const 1)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/ctor-eval/stack-direction.wast.ctors b/binaryen/test/ctor-eval/stack-direction.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/stack-direction.wast.ctors
@@ -0,0 +1,1 @@
+__post_instantiate
diff --git a/binaryen/test/ctor-eval/stack-direction.wast.out b/binaryen/test/ctor-eval/stack-direction.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/stack-direction.wast.out
@@ -0,0 +1,2 @@
+(module
+)
diff --git a/binaryen/test/ctor-eval/unsafe_call.wast b/binaryen/test/ctor-eval/unsafe_call.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/unsafe_call.wast
@@ -0,0 +1,14 @@
+(module
+  (memory 256 256)
+  (data (i32.const 10) "waka waka waka waka waka")
+  (export "test1" $test1)
+  (func $test1
+    (call $unsafe-to-call) ;; unsafe to call
+    (i32.store (i32.const 12) (i32.const 115)) ;; a safe store, should alter memory
+    (i32.store16 (i32.const 20) (i32.const 31353))
+    (i32.store8 (i32.const 23) (i32.const 120))
+  )
+  (func $unsafe-to-call
+    (unreachable)
+  )
+)
diff --git a/binaryen/test/ctor-eval/unsafe_call.wast.ctors b/binaryen/test/ctor-eval/unsafe_call.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/unsafe_call.wast.ctors
@@ -0,0 +1,1 @@
+test1
diff --git a/binaryen/test/ctor-eval/unsafe_call.wast.out b/binaryen/test/ctor-eval/unsafe_call.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/unsafe_call.wast.out
@@ -0,0 +1,24 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 256 256)
+ (data (i32.const 10) "waka waka waka waka waka")
+ (export "test1" (func $test1))
+ (func $test1
+  (call $unsafe-to-call)
+  (i32.store
+   (i32.const 12)
+   (i32.const 115)
+  )
+  (i32.store16
+   (i32.const 20)
+   (i32.const 31353)
+  )
+  (i32.store8
+   (i32.const 23)
+   (i32.const 120)
+  )
+ )
+ (func $unsafe-to-call
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/ctor-eval/unsafe_store.wast b/binaryen/test/ctor-eval/unsafe_store.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/unsafe_store.wast
@@ -0,0 +1,8 @@
+(module
+  (memory 256 256)
+  (data (i32.const 10) "waka waka waka waka waka")
+  (export "test1" $test1)
+  (func $test1
+    (i32.store8 (i32.const 9) (i32.const 109)) ;; before first segment
+  )
+)
diff --git a/binaryen/test/ctor-eval/unsafe_store.wast.ctors b/binaryen/test/ctor-eval/unsafe_store.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/unsafe_store.wast.ctors
@@ -0,0 +1,1 @@
+test1
diff --git a/binaryen/test/ctor-eval/unsafe_store.wast.out b/binaryen/test/ctor-eval/unsafe_store.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/unsafe_store.wast.out
@@ -0,0 +1,2 @@
+(module
+)
diff --git a/binaryen/test/ctor-eval/unsafe_store2.wast b/binaryen/test/ctor-eval/unsafe_store2.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/unsafe_store2.wast
@@ -0,0 +1,8 @@
+(module
+  (memory 256 256)
+  (data (i32.const 10) "waka waka waka waka waka")
+  (export "test1" $test1)
+  (func $test1
+    (i32.store8 (i32.const 34) (i32.const 109)) ;; after last segment
+  )
+)
diff --git a/binaryen/test/ctor-eval/unsafe_store2.wast.ctors b/binaryen/test/ctor-eval/unsafe_store2.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/unsafe_store2.wast.ctors
@@ -0,0 +1,1 @@
+test1
diff --git a/binaryen/test/ctor-eval/unsafe_store2.wast.out b/binaryen/test/ctor-eval/unsafe_store2.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/unsafe_store2.wast.out
@@ -0,0 +1,2 @@
+(module
+)
diff --git a/binaryen/test/ctor-eval/unsafe_store3.wast b/binaryen/test/ctor-eval/unsafe_store3.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/unsafe_store3.wast
@@ -0,0 +1,8 @@
+(module
+  (memory 256 256)
+  (data (i32.const 10) "waka waka waka waka waka")
+  (export "test1" $test1)
+  (func $test1
+    (i32.store16 (i32.const 33) (i32.const 109)) ;; after last segment due to size of type
+  )
+)
diff --git a/binaryen/test/ctor-eval/unsafe_store3.wast.ctors b/binaryen/test/ctor-eval/unsafe_store3.wast.ctors
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/unsafe_store3.wast.ctors
@@ -0,0 +1,1 @@
+test1
diff --git a/binaryen/test/ctor-eval/unsafe_store3.wast.out b/binaryen/test/ctor-eval/unsafe_store3.wast.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/ctor-eval/unsafe_store3.wast.out
@@ -0,0 +1,2 @@
+(module
+)
diff --git a/binaryen/test/debugInfo.asm.js b/binaryen/test/debugInfo.asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/debugInfo.asm.js
@@ -0,0 +1,102 @@
+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/duplicate_types.wast b/binaryen/test/duplicate_types.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/duplicate_types.wast
@@ -0,0 +1,15 @@
+(module ;; tests duplicate types are named properly
+ (type (func))
+ (type (func))
+ (type (func))
+ (type (func (param i32)))
+ (type $0 (func (param i32)))
+ (type (func (param i32)))
+ (type $b (func (param i32) (result f32)))
+ (type (func (param i32) (result f32)))
+
+ (func $f0 (param i32))
+ (func $f1 (param i32) (result i32)
+  (i32.const 0)
+ )
+)
diff --git a/binaryen/test/duplicate_types.wast.from-wast b/binaryen/test/duplicate_types.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/duplicate_types.wast.from-wast
@@ -0,0 +1,10 @@
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $f0 (param $0 i32)
+  (nop)
+ )
+ (func $f1 (param $0 i32) (result i32)
+  (i32.const 0)
+ )
+)
diff --git a/binaryen/test/duplicate_types.wast.fromBinary b/binaryen/test/duplicate_types.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/duplicate_types.wast.fromBinary
@@ -0,0 +1,11 @@
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $f0 (param $0 i32)
+  (nop)
+ )
+ (func $f1 (param $0 i32) (result i32)
+  (i32.const 0)
+ )
+)
+
diff --git a/binaryen/test/duplicate_types.wast.fromBinary.noDebugInfo b/binaryen/test/duplicate_types.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/duplicate_types.wast.fromBinary.noDebugInfo
@@ -0,0 +1,11 @@
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $0 (param $0 i32)
+  (nop)
+ )
+ (func $1 (param $0 i32) (result i32)
+  (i32.const 0)
+ )
+)
+
diff --git a/binaryen/test/duplicated_names.wasm b/binaryen/test/duplicated_names.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/duplicated_names.wasm differ
diff --git a/binaryen/test/duplicated_names.wasm.fromBinary b/binaryen/test/duplicated_names.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/duplicated_names.wasm.fromBinary
@@ -0,0 +1,13 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (func $foo (result i32)
+  (i32.const 0)
+ )
+ (func $foo.1 (result i32)
+  (i32.const 1)
+ )
+ (func $foo.2 (result i32)
+  (i32.const 2)
+ )
+)
+
diff --git a/binaryen/test/duplicated_names_collision.wasm b/binaryen/test/duplicated_names_collision.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/duplicated_names_collision.wasm differ
diff --git a/binaryen/test/duplicated_names_collision.wasm.fromBinary b/binaryen/test/duplicated_names_collision.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/duplicated_names_collision.wasm.fromBinary
@@ -0,0 +1,13 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (func $foo (result i32)
+  (i32.const 0)
+ )
+ (func $foo.1 (result i32)
+  (i32.const 1)
+ )
+ (func $foo.1.1 (result i32)
+  (i32.const 2)
+ )
+)
+
diff --git a/binaryen/test/dylib.wasm b/binaryen/test/dylib.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/dylib.wasm differ
diff --git a/binaryen/test/dylib.wasm.fromBinary b/binaryen/test/dylib.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/dylib.wasm.fromBinary
@@ -0,0 +1,87 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (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" "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)))
+ (import "env" "fp$_Z14waka_func_minei$ii" (func $fimport$3 (result i32)))
+ (global $global$0 (mut i32) (i32.const 0))
+ (global $global$1 (mut i32) (i32.const 0))
+ (global $global$2 (mut i32) (i32.const 0))
+ (global $global$3 (mut i32) (i32.const 0))
+ (global $global$4 i32 (i32.const 0))
+ (global $global$5 i32 (i32.const 0))
+ (export "__wasm_apply_relocs" (func $0))
+ (export "_Z14waka_func_minei" (func $1))
+ (export "__original_main" (func $2))
+ (export "waka_mine" (global $global$4))
+ (export "main" (func $3))
+ (export "__dso_handle" (global $global$5))
+ (export "__post_instantiate" (func $4))
+ (func $0
+  (nop)
+ )
+ (func $1 (param $0 i32) (result i32)
+  (i32.add
+   (local.get $0)
+   (i32.const 1)
+  )
+ )
+ (func $2 (result i32)
+  (i32.add
+   (i32.load
+    (global.get $global$3)
+   )
+   (i32.add
+    (i32.load
+     (global.get $global$2)
+    )
+    (i32.add
+     (global.get $global$0)
+     (global.get $global$1)
+    )
+   )
+  )
+ )
+ (func $3 (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (i32.load
+    (global.get $global$3)
+   )
+   (i32.add
+    (i32.load
+     (global.get $global$2)
+    )
+    (i32.add
+     (global.get $global$0)
+     (global.get $global$1)
+    )
+   )
+  )
+ )
+ (func $4
+  (global.set $global$2
+   (call $fimport$0)
+  )
+  (global.set $global$3
+   (call $fimport$1)
+  )
+  (global.set $global$0
+   (call $fimport$2)
+  )
+  (global.set $global$1
+   (call $fimport$3)
+  )
+ )
+ ;; dylink section
+ ;;   memorysize: 4
+ ;;   memoryalignment: 2
+ ;;   tablesize: 0
+ ;;   tablealignment: 0
+)
+
diff --git a/binaryen/test/dynamicLibrary.asm.js b/binaryen/test/dynamicLibrary.asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/dynamicLibrary.asm.js
@@ -0,0 +1,136 @@
+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/elided-br.wasm b/binaryen/test/elided-br.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/elided-br.wasm differ
diff --git a/binaryen/test/elided-br.wasm.fromBinary b/binaryen/test/elided-br.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/elided-br.wasm.fromBinary
@@ -0,0 +1,9 @@
+(module
+ (type $none_=>_none (func))
+ (func $0
+  (block $label$1
+   (unreachable)
+  )
+ )
+)
+
diff --git a/binaryen/test/emcc_O2_hello_world.asm.js b/binaryen/test/emcc_O2_hello_world.asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/emcc_O2_hello_world.asm.js
@@ -0,0 +1,2293 @@
+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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/emcc_hello_world.asm.js
@@ -0,0 +1,7101 @@
+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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/empty.asm.js
@@ -0,0 +1,4 @@
+function EmptyModule() {
+    'use asm';
+    return {};
+}
diff --git a/binaryen/test/empty_4GB.asm.js b/binaryen/test/empty_4GB.asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/empty_4GB.asm.js
@@ -0,0 +1,4 @@
+function EmptyModule() {
+    'use asm';
+    return {};
+}
diff --git a/binaryen/test/empty_imported_table.wast b/binaryen/test/empty_imported_table.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/empty_imported_table.wast
@@ -0,0 +1,4 @@
+(module
+  (import "env" "table" (table 0 0 funcref))
+  (memory $0 0)
+)
diff --git a/binaryen/test/empty_imported_table.wast.from-wast b/binaryen/test/empty_imported_table.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/empty_imported_table.wast.from-wast
@@ -0,0 +1,4 @@
+(module
+ (import "env" "table" (table $timport$0 0 0 funcref))
+ (memory $0 0)
+)
diff --git a/binaryen/test/empty_imported_table.wast.fromBinary b/binaryen/test/empty_imported_table.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/empty_imported_table.wast.fromBinary
@@ -0,0 +1,5 @@
+(module
+ (import "env" "table" (table $timport$0 0 0 funcref))
+ (memory $0 0)
+)
+
diff --git a/binaryen/test/empty_imported_table.wast.fromBinary.noDebugInfo b/binaryen/test/empty_imported_table.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/empty_imported_table.wast.fromBinary.noDebugInfo
@@ -0,0 +1,5 @@
+(module
+ (import "env" "table" (table $timport$0 0 0 funcref))
+ (memory $0 0)
+)
+
diff --git a/binaryen/test/empty_table.wast b/binaryen/test/empty_table.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/empty_table.wast
@@ -0,0 +1,4 @@
+(module
+  (table 0 0 funcref)
+  (memory $0 0)
+)
diff --git a/binaryen/test/empty_table.wast.from-wast b/binaryen/test/empty_table.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/empty_table.wast.from-wast
@@ -0,0 +1,4 @@
+(module
+ (memory $0 0)
+ (table $0 0 0 funcref)
+)
diff --git a/binaryen/test/empty_table.wast.fromBinary b/binaryen/test/empty_table.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/empty_table.wast.fromBinary
@@ -0,0 +1,5 @@
+(module
+ (memory $0 0)
+ (table $0 0 0 funcref)
+)
+
diff --git a/binaryen/test/empty_table.wast.fromBinary.noDebugInfo b/binaryen/test/empty_table.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/empty_table.wast.fromBinary.noDebugInfo
@@ -0,0 +1,5 @@
+(module
+ (memory $0 0)
+ (table $0 0 0 funcref)
+)
+
diff --git a/binaryen/test/events.wast b/binaryen/test/events.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/events.wast
@@ -0,0 +1,16 @@
+;; Test events
+
+(module
+  (event (attr 0) (param i32))
+  (event $e (attr 0) (param i32 f32))
+  (event $empty (attr 0))
+
+  (event $e-params0 (attr 0) (param i32 f32))
+  (event $e-params1 (attr 0) (param i32) (param f32))
+
+  (event $e-export (export "ex0") (attr 0) (param i32))
+  (event $e-import (import "env" "im0") (attr 0) (param i32))
+
+  (import "env" "im1" (event (attr 0) (param i32 f32)))
+  (export "ex1" (event $e))
+)
diff --git a/binaryen/test/events.wast.from-wast b/binaryen/test/events.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/events.wast.from-wast
@@ -0,0 +1,14 @@
+(module
+ (type $i32_f32_=>_none (func (param i32 f32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_none (func))
+ (import "env" "im0" (event $e-import (attr 0) (param i32)))
+ (import "env" "im1" (event $eimport$1 (attr 0) (param i32 f32)))
+ (event $2 (attr 0) (param i32))
+ (event $e (attr 0) (param i32 f32))
+ (event $empty (attr 0) (param))
+ (event $e-params0 (attr 0) (param i32 f32))
+ (event $e-params1 (attr 0) (param i32 f32))
+ (event $e-export (attr 0) (param i32))
+ (export "ex1" (event $e))
+)
diff --git a/binaryen/test/events.wast.fromBinary b/binaryen/test/events.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/events.wast.fromBinary
@@ -0,0 +1,15 @@
+(module
+ (type $i32_f32_=>_none (func (param i32 f32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_none (func))
+ (import "env" "im0" (event $eimport$0 (attr 0) (param i32)))
+ (import "env" "im1" (event $eimport$1 (attr 0) (param i32 f32)))
+ (event $event$0 (attr 0) (param i32))
+ (event $event$1 (attr 0) (param i32 f32))
+ (event $event$2 (attr 0) (param))
+ (event $event$3 (attr 0) (param i32 f32))
+ (event $event$4 (attr 0) (param i32 f32))
+ (event $event$5 (attr 0) (param i32))
+ (export "ex1" (event $event$1))
+)
+
diff --git a/binaryen/test/events.wast.fromBinary.noDebugInfo b/binaryen/test/events.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/events.wast.fromBinary.noDebugInfo
@@ -0,0 +1,15 @@
+(module
+ (type $i32_f32_=>_none (func (param i32 f32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_none (func))
+ (import "env" "im0" (event $eimport$0 (attr 0) (param i32)))
+ (import "env" "im1" (event $eimport$1 (attr 0) (param i32 f32)))
+ (event $event$0 (attr 0) (param i32))
+ (event $event$1 (attr 0) (param i32 f32))
+ (event $event$2 (attr 0) (param))
+ (event $event$3 (attr 0) (param i32 f32))
+ (event $event$4 (attr 0) (param i32 f32))
+ (event $event$5 (attr 0) (param i32))
+ (export "ex1" (event $event$1))
+)
+
diff --git a/binaryen/test/example/c-api-hello-world.c b/binaryen/test/example/c-api-hello-world.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/c-api-hello-world.c
@@ -0,0 +1,33 @@
+#include <binaryen-c.h>
+
+// "hello world" type example: create a function that adds two i32s and returns
+// the result
+
+int main() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+
+  // Create a function type for  i32 (i32, i32)
+  BinaryenType ii[2] = {BinaryenTypeInt32(), BinaryenTypeInt32()};
+  BinaryenType params = BinaryenTypeCreate(ii, 2);
+  BinaryenType results = BinaryenTypeInt32();
+
+  // Get the 0 and 1 arguments, and add them
+  BinaryenExpressionRef x = BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+                        y = BinaryenLocalGet(module, 1, BinaryenTypeInt32());
+  BinaryenExpressionRef add = BinaryenBinary(module, BinaryenAddInt32(), x, y);
+
+  // Create the add function
+  // Note: no additional local variables
+  // Note: no basic blocks here, we are an AST. The function body is just an
+  // expression node.
+  BinaryenFunctionRef adder =
+    BinaryenAddFunction(module, "adder", params, results, NULL, 0, add);
+
+  // Print it out
+  BinaryenModulePrint(module);
+
+  // Clean up the module, which owns all the objects we created above
+  BinaryenModuleDispose(module);
+
+  return 0;
+}
diff --git a/binaryen/test/example/c-api-hello-world.txt b/binaryen/test/example/c-api-hello-world.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/c-api-hello-world.txt
@@ -0,0 +1,9 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (func $adder (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
diff --git a/binaryen/test/example/c-api-kitchen-sink.c b/binaryen/test/example/c-api-kitchen-sink.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/c-api-kitchen-sink.c
@@ -0,0 +1,1381 @@
+// We always need asserts here
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <binaryen-c.h>
+
+// kitchen sink, tests the full API
+
+
+// helpers
+
+static const uint8_t v128_bytes[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+
+BinaryenExpressionRef makeUnary(BinaryenModuleRef module, BinaryenOp op, BinaryenType inputType) {
+  if (inputType == BinaryenTypeInt32()) return BinaryenUnary(module, op, BinaryenConst(module, BinaryenLiteralInt32(-10)));
+  if (inputType == BinaryenTypeInt64()) return BinaryenUnary(module, op, BinaryenConst(module, BinaryenLiteralInt64(-22)));
+  if (inputType == BinaryenTypeFloat32()) return BinaryenUnary(module, op, BinaryenConst(module, BinaryenLiteralFloat32(-33.612f)));
+  if (inputType == BinaryenTypeFloat64()) return BinaryenUnary(module, op, BinaryenConst(module, BinaryenLiteralFloat64(-9005.841)));
+  if (inputType == BinaryenTypeVec128()) return BinaryenUnary(module, op, BinaryenConst(module, BinaryenLiteralVec128(v128_bytes)));
+  abort();
+}
+
+BinaryenExpressionRef makeBinary(BinaryenModuleRef module, BinaryenOp op, BinaryenType type) {
+  if (type == BinaryenTypeInt32()) {
+    // use temp vars to ensure optimization doesn't change the order of operation in our trace recording
+    BinaryenExpressionRef temp = BinaryenConst(module, BinaryenLiteralInt32(-11));
+    return BinaryenBinary(module, op, BinaryenConst(module, BinaryenLiteralInt32(-10)), temp);
+  }
+  if (type == BinaryenTypeInt64()) {
+    BinaryenExpressionRef temp = BinaryenConst(module, BinaryenLiteralInt64(-23));
+    return BinaryenBinary(module, op, BinaryenConst(module, BinaryenLiteralInt64(-22)), temp);
+  }
+  if (type == BinaryenTypeFloat32()) {
+    BinaryenExpressionRef temp = BinaryenConst(module, BinaryenLiteralFloat32(-62.5f));
+    return BinaryenBinary(module, op, BinaryenConst(module, BinaryenLiteralFloat32(-33.612f)), temp);
+  }
+  if (type == BinaryenTypeFloat64()) {
+    BinaryenExpressionRef temp = BinaryenConst(module, BinaryenLiteralFloat64(-9007.333));
+    return BinaryenBinary(module, op, BinaryenConst(module, BinaryenLiteralFloat64(-9005.841)), temp);
+  }
+  if (type == BinaryenTypeVec128()) {
+    BinaryenExpressionRef temp = BinaryenConst(module, BinaryenLiteralVec128(v128_bytes));
+    return BinaryenBinary(module, op, BinaryenConst(module, BinaryenLiteralVec128(v128_bytes)), temp);
+  }
+  abort();
+}
+
+BinaryenExpressionRef makeInt32(BinaryenModuleRef module, int x) {
+  return BinaryenConst(module, BinaryenLiteralInt32(x));
+}
+
+BinaryenExpressionRef makeFloat32(BinaryenModuleRef module, float x) {
+  return BinaryenConst(module, BinaryenLiteralFloat32(x));
+}
+
+BinaryenExpressionRef makeInt64(BinaryenModuleRef module, int64_t x) {
+  return BinaryenConst(module, BinaryenLiteralInt64(x));
+}
+
+BinaryenExpressionRef makeFloat64(BinaryenModuleRef module, double x) {
+  return BinaryenConst(module, BinaryenLiteralFloat64(x));
+}
+
+BinaryenExpressionRef makeVec128(BinaryenModuleRef module, uint8_t const *bytes) {
+  return BinaryenConst(module, BinaryenLiteralVec128(bytes));
+}
+
+BinaryenExpressionRef makeSomething(BinaryenModuleRef module) {
+  return makeInt32(module, 1337);
+}
+
+BinaryenExpressionRef makeDroppedInt32(BinaryenModuleRef module, int x) {
+  return BinaryenDrop(module, BinaryenConst(module, BinaryenLiteralInt32(x)));
+}
+
+BinaryenExpressionRef makeSIMDExtract(BinaryenModuleRef module, BinaryenOp op) {
+  return BinaryenSIMDExtract(module, op, makeVec128(module, v128_bytes), 0);
+}
+
+BinaryenExpressionRef makeSIMDReplace(BinaryenModuleRef module, BinaryenOp op, BinaryenType type) {
+  BinaryenExpressionRef val;
+  if (type == BinaryenTypeInt32()) {
+    val = makeInt32(module, 42);
+  }
+  if (type == BinaryenTypeInt64()) {
+    val = makeInt64(module, 42);
+  }
+  if (type == BinaryenTypeFloat32()) {
+    val = makeFloat32(module, 42.);
+  }
+  if (type == BinaryenTypeFloat64()) {
+    val = makeFloat64(module, 42.);
+  }
+  if (!val) {
+    abort();
+  }
+  return BinaryenSIMDReplace(module, op, makeVec128(module, v128_bytes), 0, val);
+}
+
+BinaryenExpressionRef makeSIMDShuffle(BinaryenModuleRef module) {
+  BinaryenExpressionRef left = makeVec128(module, v128_bytes);
+  BinaryenExpressionRef right = makeVec128(module, v128_bytes);
+  return BinaryenSIMDShuffle(module, left, right, (uint8_t[16]) {});
+}
+
+BinaryenExpressionRef makeSIMDTernary(BinaryenModuleRef module, BinaryenOp op) {
+  BinaryenExpressionRef a = makeVec128(module, v128_bytes);
+  BinaryenExpressionRef b = makeVec128(module, v128_bytes);
+  BinaryenExpressionRef c = makeVec128(module, v128_bytes);
+  return BinaryenSIMDTernary(module, op, a, b, c);
+}
+
+BinaryenExpressionRef makeSIMDShift(BinaryenModuleRef module, BinaryenOp op) {
+  BinaryenExpressionRef vec = makeVec128(module, v128_bytes);
+  return BinaryenSIMDShift(module, op, vec, makeInt32(module, 1));
+}
+
+BinaryenExpressionRef makeMemoryInit(BinaryenModuleRef module) {
+  BinaryenExpressionRef dest = makeInt32(module, 1024);
+  BinaryenExpressionRef offset = makeInt32(module, 0);
+  BinaryenExpressionRef size = makeInt32(module, 12);
+  return BinaryenMemoryInit(module, 0, dest, offset, size);
+};
+
+BinaryenExpressionRef makeDataDrop(BinaryenModuleRef module) {
+  return BinaryenDataDrop(module, 0);
+};
+
+BinaryenExpressionRef makeMemoryCopy(BinaryenModuleRef module) {
+  BinaryenExpressionRef dest = makeInt32(module, 2048);
+  BinaryenExpressionRef source = makeInt32(module, 1024);
+  BinaryenExpressionRef size = makeInt32(module, 12);
+  return BinaryenMemoryCopy(module, dest, source, size);
+};
+
+BinaryenExpressionRef makeMemoryFill(BinaryenModuleRef module) {
+  BinaryenExpressionRef dest = makeInt32(module, 0);
+  BinaryenExpressionRef value = makeInt32(module, 42);
+  BinaryenExpressionRef size = makeInt32(module, 1024);
+  return BinaryenMemoryFill(module, dest, value, size);
+};
+
+// tests
+
+void test_types() {
+  BinaryenType valueType = 0xdeadbeef;
+
+  BinaryenType none = BinaryenTypeNone();
+  printf("  // BinaryenTypeNone: %d\n", none);
+  assert(BinaryenTypeArity(none) == 0);
+  BinaryenTypeExpand(none, &valueType);
+  assert(valueType == 0xdeadbeef);
+
+  BinaryenType unreachable = BinaryenTypeUnreachable();
+  printf("  // BinaryenTypeUnreachable: %d\n", unreachable);
+  assert(BinaryenTypeArity(unreachable) == 1);
+  BinaryenTypeExpand(unreachable, &valueType);
+  assert(valueType == unreachable);
+
+  BinaryenType i32 = BinaryenTypeInt32();
+  printf("  // BinaryenTypeInt32: %d\n", i32);
+  assert(BinaryenTypeArity(i32) == 1);
+  BinaryenTypeExpand(i32, &valueType);
+  assert(valueType == i32);
+
+  BinaryenType i64 = BinaryenTypeInt64();
+  printf("  // BinaryenTypeInt64: %d\n", i64);
+  assert(BinaryenTypeArity(i64) == 1);
+  BinaryenTypeExpand(i64, &valueType);
+  assert(valueType == i64);
+
+  BinaryenType f32 = BinaryenTypeFloat32();
+  printf("  // BinaryenTypeFloat32: %d\n", f32);
+  assert(BinaryenTypeArity(f32) == 1);
+  BinaryenTypeExpand(f32, &valueType);
+  assert(valueType == f32);
+
+  BinaryenType f64 = BinaryenTypeFloat64();
+  printf("  // BinaryenTypeFloat64: %d\n", f64);
+  assert(BinaryenTypeArity(f64) == 1);
+  BinaryenTypeExpand(f64, &valueType);
+  assert(valueType == f64);
+
+  BinaryenType v128 = BinaryenTypeVec128();
+  printf("  // BinaryenTypeVec128: %d\n", v128);
+  assert(BinaryenTypeArity(v128) == 1);
+  BinaryenTypeExpand(v128, &valueType);
+  assert(valueType == v128);
+
+  BinaryenType funcref = BinaryenTypeFuncref();
+  printf("  // BinaryenTypeFuncref: %d\n", funcref);
+  assert(BinaryenTypeArity(funcref) == 1);
+  BinaryenTypeExpand(funcref, &valueType);
+  assert(valueType == funcref);
+
+  BinaryenType externref = BinaryenTypeExternref();
+  printf("  // BinaryenTypeExternref: %d\n", externref);
+  assert(BinaryenTypeArity(externref) == 1);
+  BinaryenTypeExpand(externref, &valueType);
+  assert(valueType == externref);
+
+  BinaryenType exnref = BinaryenTypeExnref();
+  printf("  // BinaryenTypeExnref: %d\n", exnref);
+  assert(BinaryenTypeArity(exnref) == 1);
+  BinaryenTypeExpand(exnref, &valueType);
+  assert(valueType == exnref);
+
+  BinaryenType anyref = BinaryenTypeAnyref();
+  printf("  // BinaryenTypeAnyref: %d\n", anyref);
+  assert(BinaryenTypeArity(anyref) == 1);
+  BinaryenTypeExpand(anyref, &valueType);
+  assert(valueType == anyref);
+
+  BinaryenType eqref = BinaryenTypeEqref();
+  printf("  // BinaryenTypeEqref: %d\n", eqref);
+  assert(BinaryenTypeArity(eqref) == 1);
+  BinaryenTypeExpand(eqref, &valueType);
+  assert(valueType == eqref);
+
+  BinaryenType i31ref = BinaryenTypeI31ref();
+  printf("  // BinaryenTypeI31ref: %d\n", i31ref);
+  assert(BinaryenTypeArity(i31ref) == 1);
+  BinaryenTypeExpand(i31ref, &valueType);
+  assert(valueType == i31ref);
+
+  printf("  // BinaryenTypeAuto: %d\n", BinaryenTypeAuto());
+
+  BinaryenType pair[] = {i32, i32};
+
+  BinaryenType i32_pair = BinaryenTypeCreate(pair, 2);
+  assert(BinaryenTypeArity(i32_pair) == 2);
+  pair[0] = pair[1] = none;
+  BinaryenTypeExpand(i32_pair, pair);
+  assert(pair[0] == i32 && pair[1] == i32);
+
+  BinaryenType duplicate_pair = BinaryenTypeCreate(pair, 2);
+  assert(duplicate_pair == i32_pair);
+
+  pair[0] = pair[1] = f32;
+  BinaryenType float_pair = BinaryenTypeCreate(pair, 2);
+  assert(float_pair != i32_pair);
+}
+
+void test_features() {
+  printf("BinaryenFeatureMVP: %d\n", BinaryenFeatureMVP());
+  printf("BinaryenFeatureAtomics: %d\n", BinaryenFeatureAtomics());
+  printf("BinaryenFeatureBulkMemory: %d\n", BinaryenFeatureBulkMemory());
+  printf("BinaryenFeatureMutableGlobals: %d\n", BinaryenFeatureMutableGlobals());
+  printf("BinaryenFeatureNontrappingFPToInt: %d\n", BinaryenFeatureNontrappingFPToInt());
+  printf("BinaryenFeatureSignExt: %d\n", BinaryenFeatureSignExt());
+  printf("BinaryenFeatureSIMD128: %d\n", BinaryenFeatureSIMD128());
+  printf("BinaryenFeatureExceptionHandling: %d\n", BinaryenFeatureExceptionHandling());
+  printf("BinaryenFeatureTailCall: %d\n", BinaryenFeatureTailCall());
+  printf("BinaryenFeatureReferenceTypes: %d\n", BinaryenFeatureReferenceTypes());
+  printf("BinaryenFeatureMultivalue: %d\n", BinaryenFeatureMultivalue());
+  printf("BinaryenFeatureGC: %d\n", BinaryenFeatureGC());
+  printf("BinaryenFeatureMemory64: %d\n", BinaryenFeatureMemory64());
+  printf("BinaryenFeatureAll: %d\n", BinaryenFeatureAll());
+}
+
+void test_core() {
+
+  // Module creation
+
+  BinaryenModuleRef module = BinaryenModuleCreate();
+
+  // Literals and consts
+
+  BinaryenExpressionRef constI32 = BinaryenConst(module, BinaryenLiteralInt32(1)),
+                        constI64 = BinaryenConst(module, BinaryenLiteralInt64(2)),
+                        constF32 = BinaryenConst(module, BinaryenLiteralFloat32(3.14f)),
+                        constF64 = BinaryenConst(module, BinaryenLiteralFloat64(2.1828)),
+                        constF32Bits = BinaryenConst(module, BinaryenLiteralFloat32Bits(0xffff1234)),
+                        constF64Bits = BinaryenConst(module, BinaryenLiteralFloat64Bits(0xffff12345678abcdLL)),
+                        constV128 = BinaryenConst(module, BinaryenLiteralVec128(v128_bytes));
+
+  const char* switchValueNames[] = { "the-value" };
+  const char* switchBodyNames[] = { "the-nothing" };
+
+  BinaryenExpressionRef callOperands2[] = { makeInt32(module, 13), makeFloat64(module, 3.7) };
+  BinaryenExpressionRef callOperands4[] = { makeInt32(module, 13), makeInt64(module, 37), makeFloat32(module, 1.3f), makeFloat64(module, 3.7) };
+  BinaryenExpressionRef callOperands4b[] = { makeInt32(module, 13), makeInt64(module, 37), makeFloat32(module, 1.3f), makeFloat64(module, 3.7) };
+  BinaryenExpressionRef tupleElements4a[] = {makeInt32(module, 13),
+                                             makeInt64(module, 37),
+                                             makeFloat32(module, 1.3f),
+                                             makeFloat64(module, 3.7)};
+  BinaryenExpressionRef tupleElements4b[] = {makeInt32(module, 13),
+                                             makeInt64(module, 37),
+                                             makeFloat32(module, 1.3f),
+                                             makeFloat64(module, 3.7)};
+
+  BinaryenType iIfF_[4] = {BinaryenTypeInt32(),
+                           BinaryenTypeInt64(),
+                           BinaryenTypeFloat32(),
+                           BinaryenTypeFloat64()};
+  BinaryenType iIfF = BinaryenTypeCreate(iIfF_, 4);
+
+  BinaryenExpressionRef temp1 = makeInt32(module, 1), temp2 = makeInt32(module, 2), temp3 = makeInt32(module, 3),
+                        temp4 = makeInt32(module, 4), temp5 = makeInt32(module, 5),
+                        temp6 = makeInt32(module, 0), temp7 = makeInt32(module, 1),
+                        temp8 = makeInt32(module, 0), temp9 = makeInt32(module, 1),
+                        temp10 = makeInt32(module, 1), temp11 = makeInt32(module, 3), temp12 = makeInt32(module, 5),
+                        temp13 = makeInt32(module, 10), temp14 = makeInt32(module, 11),
+                        temp15 = makeInt32(module, 110), temp16 = makeInt64(module, 111);
+  BinaryenExpressionRef externrefExpr = BinaryenRefNull(module, BinaryenTypeExternref());
+  BinaryenExpressionRef funcrefExpr = BinaryenRefNull(module, BinaryenTypeFuncref());
+  funcrefExpr = BinaryenRefFunc(module, "kitchen()sinker");
+  BinaryenExpressionRef exnrefExpr = BinaryenRefNull(module, BinaryenTypeExnref());
+  BinaryenExpressionRef i31refExpr = BinaryenI31New(module, makeInt32(module, 1));
+
+  // Events
+  BinaryenAddEvent(
+    module, "a-event", 0, BinaryenTypeInt32(), BinaryenTypeNone());
+
+  // Exception handling
+
+  // (try
+  //   (do
+  //     (throw $a-event (i32.const 0))
+  //   )
+  //   (catch
+  //     ;; We don't support multi-value yet. Use locals instead.
+  //     (local.set 0 (exnref.pop))
+  //     (drop
+  //       (block $try-block (result i32)
+  //         (rethrow
+  //           (br_on_exn $try-block $a-event (local.get 5))
+  //         )
+  //       )
+  //     )
+  //   )
+  // )
+  BinaryenExpressionRef tryBody = BinaryenThrow(
+    module, "a-event", (BinaryenExpressionRef[]){makeInt32(module, 0)}, 1);
+  BinaryenExpressionRef catchBody = BinaryenBlock(
+    module,
+    NULL,
+    (BinaryenExpressionRef[]){
+      BinaryenLocalSet(module, 5, BinaryenPop(module, BinaryenTypeExnref())),
+      BinaryenDrop(
+        module,
+        BinaryenBlock(module,
+                      "try-block",
+                      (BinaryenExpressionRef[]){BinaryenRethrow(
+                        module,
+                        BinaryenBrOnExn(
+                          module,
+                          "try-block",
+                          "a-event",
+                          BinaryenLocalGet(module, 5, BinaryenTypeExnref())))},
+                      1,
+                      BinaryenTypeInt32()))},
+    2,
+    BinaryenTypeNone());
+
+  BinaryenType i32 = BinaryenTypeInt32();
+  BinaryenType i64 = BinaryenTypeInt64();
+  BinaryenType f32 = BinaryenTypeFloat32();
+  BinaryenType f64 = BinaryenTypeFloat64();
+  BinaryenType v128 = BinaryenTypeVec128();
+
+  BinaryenExpressionRef valueList[] = {
+    // Unary
+    makeUnary(module, BinaryenClzInt32(), i32),
+    makeUnary(module, BinaryenCtzInt64(), i64),
+    makeUnary(module, BinaryenPopcntInt32(), i32),
+    makeUnary(module, BinaryenNegFloat32(), f32),
+    makeUnary(module, BinaryenAbsFloat64(), f64),
+    makeUnary(module, BinaryenCeilFloat32(), f32),
+    makeUnary(module, BinaryenFloorFloat64(), f64),
+    makeUnary(module, BinaryenTruncFloat32(), f32),
+    makeUnary(module, BinaryenNearestFloat32(), f32),
+    makeUnary(module, BinaryenSqrtFloat64(), f64),
+    makeUnary(module, BinaryenEqZInt32(), i32),
+    makeUnary(module, BinaryenExtendSInt32(), i32),
+    makeUnary(module, BinaryenExtendUInt32(), i32),
+    makeUnary(module, BinaryenWrapInt64(), i64),
+    makeUnary(module, BinaryenTruncSFloat32ToInt32(), f32),
+    makeUnary(module, BinaryenTruncSFloat32ToInt64(), f32),
+    makeUnary(module, BinaryenTruncUFloat32ToInt32(), f32),
+    makeUnary(module, BinaryenTruncUFloat32ToInt64(), f32),
+    makeUnary(module, BinaryenTruncSFloat64ToInt32(), f64),
+    makeUnary(module, BinaryenTruncSFloat64ToInt64(), f64),
+    makeUnary(module, BinaryenTruncUFloat64ToInt32(), f64),
+    makeUnary(module, BinaryenTruncUFloat64ToInt64(), f64),
+    makeUnary(module, BinaryenTruncSatSFloat32ToInt32(), f32),
+    makeUnary(module, BinaryenTruncSatSFloat32ToInt64(), f32),
+    makeUnary(module, BinaryenTruncSatUFloat32ToInt32(), f32),
+    makeUnary(module, BinaryenTruncSatUFloat32ToInt64(), f32),
+    makeUnary(module, BinaryenTruncSatSFloat64ToInt32(), f64),
+    makeUnary(module, BinaryenTruncSatSFloat64ToInt64(), f64),
+    makeUnary(module, BinaryenTruncSatUFloat64ToInt32(), f64),
+    makeUnary(module, BinaryenTruncSatUFloat64ToInt64(), f64),
+    makeUnary(module, BinaryenReinterpretFloat32(), f32),
+    makeUnary(module, BinaryenReinterpretFloat64(), f64),
+    makeUnary(module, BinaryenConvertSInt32ToFloat32(), i32),
+    makeUnary(module, BinaryenConvertSInt32ToFloat64(), i32),
+    makeUnary(module, BinaryenConvertUInt32ToFloat32(), i32),
+    makeUnary(module, BinaryenConvertUInt32ToFloat64(), i32),
+    makeUnary(module, BinaryenConvertSInt64ToFloat32(), i64),
+    makeUnary(module, BinaryenConvertSInt64ToFloat64(), i64),
+    makeUnary(module, BinaryenConvertUInt64ToFloat32(), i64),
+    makeUnary(module, BinaryenConvertUInt64ToFloat64(), i64),
+    makeUnary(module, BinaryenPromoteFloat32(), f32),
+    makeUnary(module, BinaryenDemoteFloat64(), f64),
+    makeUnary(module, BinaryenReinterpretInt32(), i32),
+    makeUnary(module, BinaryenReinterpretInt64(), i64),
+    makeUnary(module, BinaryenSplatVecI8x16(), i32),
+    makeUnary(module, BinaryenSplatVecI16x8(), i32),
+    makeUnary(module, BinaryenSplatVecI32x4(), i32),
+    makeUnary(module, BinaryenSplatVecI64x2(), i64),
+    makeUnary(module, BinaryenSplatVecF32x4(), f32),
+    makeUnary(module, BinaryenSplatVecF64x2(), f64),
+    makeUnary(module, BinaryenNotVec128(), v128),
+    makeUnary(module, BinaryenAbsVecI8x16(), v128),
+    makeUnary(module, BinaryenNegVecI8x16(), v128),
+    makeUnary(module, BinaryenAnyTrueVecI8x16(), v128),
+    makeUnary(module, BinaryenAllTrueVecI8x16(), v128),
+    makeUnary(module, BinaryenBitmaskVecI8x16(), v128),
+    makeUnary(module, BinaryenAbsVecI16x8(), v128),
+    makeUnary(module, BinaryenNegVecI16x8(), v128),
+    makeUnary(module, BinaryenAnyTrueVecI16x8(), v128),
+    makeUnary(module, BinaryenAllTrueVecI16x8(), v128),
+    makeUnary(module, BinaryenBitmaskVecI16x8(), v128),
+    makeUnary(module, BinaryenAbsVecI32x4(), v128),
+    makeUnary(module, BinaryenNegVecI32x4(), v128),
+    makeUnary(module, BinaryenAnyTrueVecI32x4(), v128),
+    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),
+    makeUnary(module, BinaryenAbsVecF64x2(), v128),
+    makeUnary(module, BinaryenNegVecF64x2(), v128),
+    makeUnary(module, BinaryenSqrtVecF64x2(), v128),
+    makeUnary(module, BinaryenTruncSatSVecF32x4ToVecI32x4(), v128),
+    makeUnary(module, BinaryenTruncSatUVecF32x4ToVecI32x4(), v128),
+    makeUnary(module, BinaryenTruncSatSVecF64x2ToVecI64x2(), v128),
+    makeUnary(module, BinaryenTruncSatUVecF64x2ToVecI64x2(), v128),
+    makeUnary(module, BinaryenConvertSVecI32x4ToVecF32x4(), v128),
+    makeUnary(module, BinaryenConvertUVecI32x4ToVecF32x4(), v128),
+    makeUnary(module, BinaryenConvertSVecI64x2ToVecF64x2(), v128),
+    makeUnary(module, BinaryenConvertUVecI64x2ToVecF64x2(), v128),
+    makeUnary(module, BinaryenWidenLowSVecI8x16ToVecI16x8(), v128),
+    makeUnary(module, BinaryenWidenHighSVecI8x16ToVecI16x8(), v128),
+    makeUnary(module, BinaryenWidenLowUVecI8x16ToVecI16x8(), v128),
+    makeUnary(module, BinaryenWidenHighUVecI8x16ToVecI16x8(), v128),
+    makeUnary(module, BinaryenWidenLowSVecI16x8ToVecI32x4(), v128),
+    makeUnary(module, BinaryenWidenHighSVecI16x8ToVecI32x4(), v128),
+    makeUnary(module, BinaryenWidenLowUVecI16x8ToVecI32x4(), v128),
+    makeUnary(module, BinaryenWidenHighUVecI16x8ToVecI32x4(), v128),
+    // Binary
+    makeBinary(module, BinaryenAddInt32(), i32),
+    makeBinary(module, BinaryenSubFloat64(), f64),
+    makeBinary(module, BinaryenDivSInt32(), i32),
+    makeBinary(module, BinaryenDivUInt64(), i64),
+    makeBinary(module, BinaryenRemSInt64(), i64),
+    makeBinary(module, BinaryenRemUInt32(), i32),
+    makeBinary(module, BinaryenAndInt32(), i32),
+    makeBinary(module, BinaryenOrInt64(), i64),
+    makeBinary(module, BinaryenXorInt32(), i32),
+    makeBinary(module, BinaryenShlInt64(), i64),
+    makeBinary(module, BinaryenShrUInt64(), i64),
+    makeBinary(module, BinaryenShrSInt32(), i32),
+    makeBinary(module, BinaryenRotLInt32(), i32),
+    makeBinary(module, BinaryenRotRInt64(), i64),
+    makeBinary(module, BinaryenDivFloat32(), f32),
+    makeBinary(module, BinaryenCopySignFloat64(), f64),
+    makeBinary(module, BinaryenMinFloat32(), f32),
+    makeBinary(module, BinaryenMaxFloat64(), f64),
+    makeBinary(module, BinaryenEqInt32(), i32),
+    makeBinary(module, BinaryenNeFloat32(), f32),
+    makeBinary(module, BinaryenLtSInt32(), i32),
+    makeBinary(module, BinaryenLtUInt64(), i64),
+    makeBinary(module, BinaryenLeSInt64(), i64),
+    makeBinary(module, BinaryenLeUInt32(), i32),
+    makeBinary(module, BinaryenGtSInt64(), i64),
+    makeBinary(module, BinaryenGtUInt32(), i32),
+    makeBinary(module, BinaryenGeSInt32(), i32),
+    makeBinary(module, BinaryenGeUInt64(), i64),
+    makeBinary(module, BinaryenLtFloat32(), f32),
+    makeBinary(module, BinaryenLeFloat64(), f64),
+    makeBinary(module, BinaryenGtFloat64(), f64),
+    makeBinary(module, BinaryenGeFloat32(), f32),
+    makeBinary(module, BinaryenEqVecI8x16(), v128),
+    makeBinary(module, BinaryenNeVecI8x16(), v128),
+    makeBinary(module, BinaryenLtSVecI8x16(), v128),
+    makeBinary(module, BinaryenLtUVecI8x16(), v128),
+    makeBinary(module, BinaryenGtSVecI8x16(), v128),
+    makeBinary(module, BinaryenGtUVecI8x16(), v128),
+    makeBinary(module, BinaryenLeSVecI8x16(), v128),
+    makeBinary(module, BinaryenLeUVecI8x16(), v128),
+    makeBinary(module, BinaryenGeSVecI8x16(), v128),
+    makeBinary(module, BinaryenGeUVecI8x16(), v128),
+    makeBinary(module, BinaryenEqVecI16x8(), v128),
+    makeBinary(module, BinaryenNeVecI16x8(), v128),
+    makeBinary(module, BinaryenLtSVecI16x8(), v128),
+    makeBinary(module, BinaryenLtUVecI16x8(), v128),
+    makeBinary(module, BinaryenGtSVecI16x8(), v128),
+    makeBinary(module, BinaryenGtUVecI16x8(), v128),
+    makeBinary(module, BinaryenLeSVecI16x8(), v128),
+    makeBinary(module, BinaryenLeUVecI16x8(), v128),
+    makeBinary(module, BinaryenGeSVecI16x8(), v128),
+    makeBinary(module, BinaryenGeUVecI16x8(), v128),
+    makeBinary(module, BinaryenEqVecI32x4(), v128),
+    makeBinary(module, BinaryenNeVecI32x4(), v128),
+    makeBinary(module, BinaryenLtSVecI32x4(), v128),
+    makeBinary(module, BinaryenLtUVecI32x4(), v128),
+    makeBinary(module, BinaryenGtSVecI32x4(), v128),
+    makeBinary(module, BinaryenGtUVecI32x4(), v128),
+    makeBinary(module, BinaryenLeSVecI32x4(), v128),
+    makeBinary(module, BinaryenLeUVecI32x4(), v128),
+    makeBinary(module, BinaryenGeSVecI32x4(), v128),
+    makeBinary(module, BinaryenGeUVecI32x4(), v128),
+    makeBinary(module, BinaryenEqVecF32x4(), v128),
+    makeBinary(module, BinaryenNeVecF32x4(), v128),
+    makeBinary(module, BinaryenLtVecF32x4(), v128),
+    makeBinary(module, BinaryenGtVecF32x4(), v128),
+    makeBinary(module, BinaryenLeVecF32x4(), v128),
+    makeBinary(module, BinaryenGeVecF32x4(), v128),
+    makeBinary(module, BinaryenEqVecF64x2(), v128),
+    makeBinary(module, BinaryenNeVecF64x2(), v128),
+    makeBinary(module, BinaryenLtVecF64x2(), v128),
+    makeBinary(module, BinaryenGtVecF64x2(), v128),
+    makeBinary(module, BinaryenLeVecF64x2(), v128),
+    makeBinary(module, BinaryenGeVecF64x2(), v128),
+    makeBinary(module, BinaryenAndVec128(), v128),
+    makeBinary(module, BinaryenOrVec128(), v128),
+    makeBinary(module, BinaryenXorVec128(), v128),
+    makeBinary(module, BinaryenAndNotVec128(), v128),
+    makeBinary(module, BinaryenAddVecI8x16(), v128),
+    makeBinary(module, BinaryenAddSatSVecI8x16(), v128),
+    makeBinary(module, BinaryenAddSatUVecI8x16(), v128),
+    makeBinary(module, BinaryenSubVecI8x16(), v128),
+    makeBinary(module, BinaryenSubSatSVecI8x16(), v128),
+    makeBinary(module, BinaryenSubSatUVecI8x16(), v128),
+    makeBinary(module, BinaryenMulVecI8x16(), v128),
+    makeBinary(module, BinaryenMinSVecI8x16(), v128),
+    makeBinary(module, BinaryenMinUVecI8x16(), v128),
+    makeBinary(module, BinaryenMaxSVecI8x16(), v128),
+    makeBinary(module, BinaryenMaxUVecI8x16(), v128),
+    makeBinary(module, BinaryenAvgrUVecI8x16(), v128),
+    makeBinary(module, BinaryenAddVecI16x8(), v128),
+    makeBinary(module, BinaryenAddSatSVecI16x8(), v128),
+    makeBinary(module, BinaryenAddSatUVecI16x8(), v128),
+    makeBinary(module, BinaryenSubVecI16x8(), v128),
+    makeBinary(module, BinaryenSubSatSVecI16x8(), v128),
+    makeBinary(module, BinaryenSubSatUVecI16x8(), v128),
+    makeBinary(module, BinaryenMulVecI16x8(), v128),
+    makeBinary(module, BinaryenMinSVecI16x8(), v128),
+    makeBinary(module, BinaryenMinUVecI16x8(), v128),
+    makeBinary(module, BinaryenMaxSVecI16x8(), v128),
+    makeBinary(module, BinaryenMaxUVecI16x8(), v128),
+    makeBinary(module, BinaryenAvgrUVecI16x8(), v128),
+    makeBinary(module, BinaryenAddVecI32x4(), v128),
+    makeBinary(module, BinaryenSubVecI32x4(), v128),
+    makeBinary(module, BinaryenMulVecI32x4(), v128),
+    makeBinary(module, BinaryenAddVecI64x2(), v128),
+    makeBinary(module, BinaryenSubVecI64x2(), v128),
+    makeBinary(module, BinaryenMulVecI64x2(), v128),
+    makeBinary(module, BinaryenAddVecF32x4(), v128),
+    makeBinary(module, BinaryenSubVecF32x4(), v128),
+    makeBinary(module, BinaryenMulVecF32x4(), v128),
+    makeBinary(module, BinaryenMinSVecI32x4(), v128),
+    makeBinary(module, BinaryenMinUVecI32x4(), v128),
+    makeBinary(module, BinaryenMaxSVecI32x4(), v128),
+    makeBinary(module, BinaryenMaxUVecI32x4(), v128),
+    makeBinary(module, BinaryenDotSVecI16x8ToVecI32x4(), v128),
+    makeBinary(module, BinaryenDivVecF32x4(), v128),
+    makeBinary(module, BinaryenMinVecF32x4(), v128),
+    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),
+    makeBinary(module, BinaryenAddVecF64x2(), v128),
+    makeBinary(module, BinaryenSubVecF64x2(), v128),
+    makeBinary(module, BinaryenMulVecF64x2(), v128),
+    makeBinary(module, BinaryenDivVecF64x2(), v128),
+    makeBinary(module, BinaryenMinVecF64x2(), v128),
+    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),
+    makeBinary(module, BinaryenNarrowSVecI16x8ToVecI8x16(), v128),
+    makeBinary(module, BinaryenNarrowUVecI16x8ToVecI8x16(), v128),
+    makeBinary(module, BinaryenNarrowSVecI32x4ToVecI16x8(), v128),
+    makeBinary(module, BinaryenNarrowUVecI32x4ToVecI16x8(), v128),
+    makeBinary(module, BinaryenSwizzleVec8x16(), v128),
+    // SIMD lane manipulation
+    makeSIMDExtract(module, BinaryenExtractLaneSVecI8x16()),
+    makeSIMDExtract(module, BinaryenExtractLaneUVecI8x16()),
+    makeSIMDExtract(module, BinaryenExtractLaneSVecI16x8()),
+    makeSIMDExtract(module, BinaryenExtractLaneUVecI16x8()),
+    makeSIMDExtract(module, BinaryenExtractLaneVecI32x4()),
+    makeSIMDExtract(module, BinaryenExtractLaneVecI64x2()),
+    makeSIMDExtract(module, BinaryenExtractLaneVecF32x4()),
+    makeSIMDExtract(module, BinaryenExtractLaneVecF64x2()),
+    makeSIMDReplace(module, BinaryenReplaceLaneVecI8x16(), i32),
+    makeSIMDReplace(module, BinaryenReplaceLaneVecI16x8(), i32),
+    makeSIMDReplace(module, BinaryenReplaceLaneVecI32x4(), i32),
+    makeSIMDReplace(module, BinaryenReplaceLaneVecI64x2(), i64),
+    makeSIMDReplace(module, BinaryenReplaceLaneVecF32x4(), f32),
+    makeSIMDReplace(module, BinaryenReplaceLaneVecF64x2(), f64),
+    // SIMD shift
+    makeSIMDShift(module, BinaryenShlVecI8x16()),
+    makeSIMDShift(module, BinaryenShrSVecI8x16()),
+    makeSIMDShift(module, BinaryenShrUVecI8x16()),
+    makeSIMDShift(module, BinaryenShlVecI16x8()),
+    makeSIMDShift(module, BinaryenShrSVecI16x8()),
+    makeSIMDShift(module, BinaryenShrUVecI16x8()),
+    makeSIMDShift(module, BinaryenShlVecI32x4()),
+    makeSIMDShift(module, BinaryenShrSVecI32x4()),
+    makeSIMDShift(module, BinaryenShrUVecI32x4()),
+    makeSIMDShift(module, BinaryenShlVecI64x2()),
+    makeSIMDShift(module, BinaryenShrSVecI64x2()),
+    makeSIMDShift(module, BinaryenShrUVecI64x2()),
+    // SIMD load
+    BinaryenSIMDLoad(
+      module, BinaryenLoadSplatVec8x16(), 0, 1, makeInt32(module, 128)),
+    BinaryenSIMDLoad(
+      module, BinaryenLoadSplatVec16x8(), 16, 1, makeInt32(module, 128)),
+    BinaryenSIMDLoad(
+      module, BinaryenLoadSplatVec32x4(), 16, 4, makeInt32(module, 128)),
+    BinaryenSIMDLoad(
+      module, BinaryenLoadSplatVec64x2(), 0, 4, makeInt32(module, 128)),
+    BinaryenSIMDLoad(
+      module, BinaryenLoadExtSVec8x8ToVecI16x8(), 0, 8, makeInt32(module, 128)),
+    BinaryenSIMDLoad(
+      module, BinaryenLoadExtUVec8x8ToVecI16x8(), 0, 8, makeInt32(module, 128)),
+    BinaryenSIMDLoad(module,
+                     BinaryenLoadExtSVec16x4ToVecI32x4(),
+                     0,
+                     8,
+                     makeInt32(module, 128)),
+    BinaryenSIMDLoad(module,
+                     BinaryenLoadExtUVec16x4ToVecI32x4(),
+                     0,
+                     8,
+                     makeInt32(module, 128)),
+    BinaryenSIMDLoad(module,
+                     BinaryenLoadExtSVec32x2ToVecI64x2(),
+                     0,
+                     8,
+                     makeInt32(module, 128)),
+    BinaryenSIMDLoad(module,
+                     BinaryenLoadExtUVec32x2ToVecI64x2(),
+                     0,
+                     8,
+                     makeInt32(module, 128)),
+    // Other SIMD
+    makeSIMDShuffle(module),
+    makeSIMDTernary(module, BinaryenBitselectVec128()),
+    makeSIMDTernary(module, BinaryenQFMAVecF32x4()),
+    makeSIMDTernary(module, BinaryenQFMSVecF32x4()),
+    makeSIMDTernary(module, BinaryenQFMAVecF64x2()),
+    makeSIMDTernary(module, BinaryenQFMSVecF64x2()),
+    // Bulk memory
+    makeMemoryInit(module),
+    makeDataDrop(module),
+    makeMemoryCopy(module),
+    makeMemoryFill(module),
+    // All the rest
+    BinaryenBlock(module, NULL, NULL, 0, -1), // block with no name and no type
+    BinaryenIf(module, temp1, temp2, temp3),
+    BinaryenIf(module, temp4, temp5, NULL),
+    BinaryenLoop(module, "in", makeInt32(module, 0)),
+    BinaryenLoop(module, NULL, makeInt32(module, 0)),
+    BinaryenBreak(module, "the-value", temp6, temp7),
+    BinaryenBreak(module, "the-nothing", makeInt32(module, 2), NULL),
+    BinaryenBreak(module, "the-value", NULL, makeInt32(module, 3)),
+    BinaryenBreak(module, "the-nothing", NULL, NULL),
+    BinaryenSwitch(module, switchValueNames, 1, "the-value", temp8, temp9),
+    BinaryenSwitch(
+      module, switchBodyNames, 1, "the-nothing", makeInt32(module, 2), NULL),
+    BinaryenUnary(
+      module,
+      BinaryenEqZInt32(), // check the output type of the call node
+      BinaryenCall(
+        module, "kitchen()sinker", callOperands4, 4, BinaryenTypeInt32())),
+    BinaryenUnary(module,
+                  BinaryenEqZInt32(), // check the output type of the call node
+                  BinaryenUnary(module,
+                                BinaryenTruncSFloat32ToInt32(),
+                                BinaryenCall(module,
+                                             "an-imported",
+                                             callOperands2,
+                                             2,
+                                             BinaryenTypeFloat32()))),
+    BinaryenUnary(module,
+                  BinaryenEqZInt32(), // check the output type of the call node
+                  BinaryenCallIndirect(module,
+                                       makeInt32(module, 2449),
+                                       callOperands4b,
+                                       4,
+                                       iIfF,
+                                       BinaryenTypeInt32())),
+    BinaryenDrop(module, BinaryenLocalGet(module, 0, BinaryenTypeInt32())),
+    BinaryenLocalSet(module, 0, makeInt32(module, 101)),
+    BinaryenDrop(
+      module,
+      BinaryenLocalTee(module, 0, makeInt32(module, 102), BinaryenTypeInt32())),
+    BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), makeInt32(module, 1)),
+    BinaryenLoad(module, 2, 1, 2, 1, BinaryenTypeInt64(), makeInt32(module, 8)),
+    BinaryenLoad(
+      module, 4, 0, 0, 0, BinaryenTypeFloat32(), makeInt32(module, 2)),
+    BinaryenLoad(
+      module, 8, 0, 2, 8, BinaryenTypeFloat64(), makeInt32(module, 9)),
+    BinaryenStore(module, 4, 0, 0, temp13, temp14, BinaryenTypeInt32()),
+    BinaryenStore(module, 8, 2, 4, temp15, temp16, BinaryenTypeInt64()),
+    BinaryenSelect(module, temp10, temp11, temp12, BinaryenTypeAuto()),
+    BinaryenReturn(module, makeInt32(module, 1337)),
+    // Tail call
+    BinaryenReturnCall(
+      module, "kitchen()sinker", callOperands4, 4, BinaryenTypeInt32()),
+    BinaryenReturnCallIndirect(module,
+                               makeInt32(module, 2449),
+                               callOperands4b,
+                               4,
+                               iIfF,
+                               BinaryenTypeInt32()),
+    // Reference types
+    BinaryenRefIsNull(module, externrefExpr),
+    BinaryenRefIsNull(module, funcrefExpr),
+    BinaryenRefIsNull(module, exnrefExpr),
+    BinaryenSelect(module,
+                   temp10,
+                   BinaryenRefNull(module, BinaryenTypeFuncref()),
+                   BinaryenRefFunc(module, "kitchen()sinker"),
+                   BinaryenTypeFuncref()),
+    // GC
+    BinaryenRefEq(module,
+      BinaryenRefNull(module, BinaryenTypeEqref()),
+      BinaryenRefNull(module, BinaryenTypeEqref())),
+    // Exception handling
+    BinaryenTry(module, tryBody, catchBody),
+    // Atomics
+    BinaryenAtomicStore(
+      module,
+      4,
+      0,
+      temp6,
+      BinaryenAtomicLoad(module, 4, 0, BinaryenTypeInt32(), temp6),
+      BinaryenTypeInt32()),
+    BinaryenDrop(
+      module,
+      BinaryenAtomicWait(module, temp6, temp6, temp16, BinaryenTypeInt32())),
+    BinaryenDrop(module, BinaryenAtomicNotify(module, temp6, temp6)),
+    BinaryenAtomicFence(module),
+    // Tuples
+    BinaryenTupleMake(module, tupleElements4a, 4),
+    BinaryenTupleExtract(
+      module, BinaryenTupleMake(module, tupleElements4b, 4), 2),
+    // Pop
+    BinaryenPop(module, BinaryenTypeInt32()),
+    BinaryenPop(module, BinaryenTypeInt64()),
+    BinaryenPop(module, BinaryenTypeFloat32()),
+    BinaryenPop(module, BinaryenTypeFloat64()),
+    BinaryenPop(module, BinaryenTypeFuncref()),
+    BinaryenPop(module, BinaryenTypeExternref()),
+    BinaryenPop(module, BinaryenTypeExnref()),
+    BinaryenPop(module, iIfF),
+    // Memory
+    BinaryenMemorySize(module),
+    BinaryenMemoryGrow(module, makeInt32(module, 0)),
+    // GC
+    BinaryenI31New(module, makeInt32(module, 0)),
+    BinaryenI31Get(module, i31refExpr, 1),
+    BinaryenI31Get(module, BinaryenI31New(module, makeInt32(module, 2)), 0),
+    // Other
+    BinaryenNop(module),
+    BinaryenUnreachable(module),
+  };
+
+  BinaryenExpressionPrint(valueList[3]); // test printing a standalone expression
+
+  // Make the main body of the function. and one block with a return value, one without
+  BinaryenExpressionRef value =
+    BinaryenBlock(module,
+                  "the-value",
+                  valueList,
+                  sizeof(valueList) / sizeof(BinaryenExpressionRef),
+                  BinaryenTypeAuto());
+  BinaryenExpressionRef droppedValue = BinaryenDrop(module, value);
+  BinaryenExpressionRef nothing = BinaryenBlock(module, "the-nothing", &droppedValue, 1, -1);
+  BinaryenExpressionRef bodyList[] = { nothing, makeInt32(module, 42) };
+  BinaryenExpressionRef body =
+    BinaryenBlock(module, "the-body", bodyList, 2, BinaryenTypeAuto());
+
+  // Create the function
+  BinaryenType localTypes[] = {BinaryenTypeInt32(), BinaryenTypeExnref()};
+  BinaryenFunctionRef sinker = BinaryenAddFunction(
+    module, "kitchen()sinker", iIfF, BinaryenTypeInt32(), localTypes, 2, body);
+
+  // Globals
+
+  BinaryenAddGlobal(module, "a-global", BinaryenTypeInt32(), 0, makeInt32(module, 7));
+  BinaryenAddGlobal(module, "a-mutable-global", BinaryenTypeFloat32(), 1, makeFloat32(module, 7.5));
+
+  // Imports
+
+  BinaryenType iF_[2] = {BinaryenTypeInt32(), BinaryenTypeFloat64()};
+  BinaryenType iF = BinaryenTypeCreate(iF_, 2);
+  BinaryenAddFunctionImport(
+    module, "an-imported", "module", "base", iF, BinaryenTypeFloat32());
+
+  // Exports
+
+  BinaryenAddFunctionExport(module, "kitchen()sinker", "kitchen_sinker");
+
+  // Function table. One per module
+  const char* funcNames[] = { BinaryenFunctionGetName(sinker) };
+  BinaryenSetFunctionTable(module, 1, 1, funcNames, 1, BinaryenConst(module, BinaryenLiteralInt32(0)));
+
+  // Memory. One per module
+
+  const char* segments[] = { "hello, world", "I am passive" };
+  int8_t segmentPassive[] = { 0, 1 };
+  BinaryenExpressionRef segmentOffsets[] = { BinaryenConst(module, BinaryenLiteralInt32(10)), NULL };
+  BinaryenIndex segmentSizes[] = { 12, 12 };
+  BinaryenSetMemory(module, 1, 256, "mem", segments, segmentPassive, segmentOffsets, segmentSizes, 2, 1);
+
+  // Start function. One per module
+
+  BinaryenFunctionRef starter = BinaryenAddFunction(module,
+                                                    "starter",
+                                                    BinaryenTypeNone(),
+                                                    BinaryenTypeNone(),
+                                                    NULL,
+                                                    0,
+                                                    BinaryenNop(module));
+  BinaryenSetStart(module, starter);
+
+  // A bunch of our code needs drop(), auto-add it
+  BinaryenModuleAutoDrop(module);
+
+  BinaryenFeatures features = BinaryenFeatureAll();
+  BinaryenModuleSetFeatures(module, features);
+  assert(BinaryenModuleGetFeatures(module) == features);
+
+  // Verify it validates
+  assert(BinaryenModuleValidate(module));
+
+  // Print it out
+  BinaryenModulePrint(module);
+
+  // Clean up the module, which owns all the objects we created above
+  BinaryenModuleDispose(module);
+}
+
+void test_unreachable() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+  BinaryenExpressionRef body = BinaryenCallIndirect(module,
+                                                    BinaryenUnreachable(module),
+                                                    NULL,
+                                                    0,
+                                                    BinaryenTypeNone(),
+                                                    BinaryenTypeInt64());
+  BinaryenFunctionRef fn = BinaryenAddFunction(module,
+                                               "unreachable-fn",
+                                               BinaryenTypeNone(),
+                                               BinaryenTypeInt32(),
+                                               NULL,
+                                               0,
+                                               body);
+
+  assert(BinaryenModuleValidate(module));
+  BinaryenModulePrint(module);
+  BinaryenModuleDispose(module);
+}
+
+BinaryenExpressionRef makeCallCheck(BinaryenModuleRef module, int x) {
+  BinaryenExpressionRef callOperands[] = { makeInt32(module, x) };
+  return BinaryenCall(module, "check", callOperands, 1, BinaryenTypeNone());
+}
+
+void test_relooper() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+  BinaryenType localTypes[] = { BinaryenTypeInt32() };
+
+  BinaryenAddFunctionImport(module,
+                            "check",
+                            "module",
+                            "check",
+                            BinaryenTypeInt32(),
+                            BinaryenTypeNone());
+
+  { // trivial: just one block
+    RelooperRef relooper = RelooperCreate(module);
+    RelooperBlockRef block = RelooperAddBlock(relooper, makeCallCheck(module, 1337));
+    BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, block, 0);
+    BinaryenFunctionRef sinker = BinaryenAddFunction(module,
+                                                     "just-one-block",
+                                                     BinaryenTypeNone(),
+                                                     BinaryenTypeNone(),
+                                                     localTypes,
+                                                     1,
+                                                     body);
+  }
+  { // two blocks
+    RelooperRef relooper = RelooperCreate(module);
+    RelooperBlockRef block0 = RelooperAddBlock(relooper, makeCallCheck(module, 0));
+    RelooperBlockRef block1 = RelooperAddBlock(relooper, makeCallCheck(module,  1));
+    RelooperAddBranch(block0, block1, NULL, NULL); // no condition, no code on branch
+    BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, block0, 0);
+    BinaryenFunctionRef sinker = BinaryenAddFunction(module,
+                                                     "two-blocks",
+                                                     BinaryenTypeNone(),
+                                                     BinaryenTypeNone(),
+                                                     localTypes,
+                                                     1,
+                                                     body);
+  }
+  { // two blocks with code between them
+    RelooperRef relooper = RelooperCreate(module);
+    RelooperBlockRef block0 = RelooperAddBlock(relooper, makeCallCheck(module,  0));
+    RelooperBlockRef block1 = RelooperAddBlock(relooper, makeCallCheck(module,  1));
+    RelooperAddBranch(block0, block1, NULL, makeDroppedInt32(module, 77)); // code on branch
+    BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, block0, 0);
+    BinaryenFunctionRef sinker = BinaryenAddFunction(module,
+                                                     "two-blocks-plus-code",
+                                                     BinaryenTypeNone(),
+                                                     BinaryenTypeNone(),
+                                                     localTypes,
+                                                     1,
+                                                     body);
+  }
+  { // two blocks in a loop
+    RelooperRef relooper = RelooperCreate(module);
+    RelooperBlockRef block0 = RelooperAddBlock(relooper, makeCallCheck(module,  0));
+    RelooperBlockRef block1 = RelooperAddBlock(relooper, makeCallCheck(module,  1));
+    RelooperAddBranch(block0, block1, NULL, NULL);
+    RelooperAddBranch(block1, block0, NULL, NULL);
+    BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, block0, 0);
+    BinaryenFunctionRef sinker = BinaryenAddFunction(module,
+                                                     "loop",
+                                                     BinaryenTypeNone(),
+                                                     BinaryenTypeNone(),
+                                                     localTypes,
+                                                     1,
+                                                     body);
+  }
+  { // two blocks in a loop with codes
+    RelooperRef relooper = RelooperCreate(module);
+    RelooperBlockRef block0 = RelooperAddBlock(relooper, makeCallCheck(module,  0));
+    RelooperBlockRef block1 = RelooperAddBlock(relooper, makeCallCheck(module,  1));
+    RelooperAddBranch(block0, block1, NULL, makeDroppedInt32(module, 33));
+    RelooperAddBranch(block1, block0, NULL, makeDroppedInt32(module, -66));
+    BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, block0, 0);
+    BinaryenFunctionRef sinker = BinaryenAddFunction(module,
+                                                     "loop-plus-code",
+                                                     BinaryenTypeNone(),
+                                                     BinaryenTypeNone(),
+                                                     localTypes,
+                                                     1,
+                                                     body);
+  }
+  { // split
+    RelooperRef relooper = RelooperCreate(module);
+    RelooperBlockRef block0 = RelooperAddBlock(relooper, makeCallCheck(module,  0));
+    RelooperBlockRef block1 = RelooperAddBlock(relooper, makeCallCheck(module,  1));
+    RelooperBlockRef block2 = RelooperAddBlock(relooper, makeCallCheck(module,  2));
+    RelooperAddBranch(block0, block1, makeInt32(module, 55), NULL);
+    RelooperAddBranch(block0, block2, NULL, NULL);
+    BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, block0, 0);
+    BinaryenFunctionRef sinker = BinaryenAddFunction(module,
+                                                     "split",
+                                                     BinaryenTypeNone(),
+                                                     BinaryenTypeNone(),
+                                                     localTypes,
+                                                     1,
+                                                     body);
+  }
+  { // split + code
+    RelooperRef relooper = RelooperCreate(module);
+    RelooperBlockRef block0 = RelooperAddBlock(relooper, makeCallCheck(module,  0));
+    RelooperBlockRef block1 = RelooperAddBlock(relooper, makeCallCheck(module,  1));
+    RelooperBlockRef block2 = RelooperAddBlock(relooper, makeCallCheck(module,  2));
+    BinaryenExpressionRef temp = makeDroppedInt32(module, 10);
+    RelooperAddBranch(block0, block1, makeInt32(module, 55), temp);
+    RelooperAddBranch(block0, block2, NULL, makeDroppedInt32(module, 20));
+    BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, block0, 0);
+    BinaryenFunctionRef sinker = BinaryenAddFunction(module,
+                                                     "split-plus-code",
+                                                     BinaryenTypeNone(),
+                                                     BinaryenTypeNone(),
+                                                     localTypes,
+                                                     1,
+                                                     body);
+  }
+  { // if
+    RelooperRef relooper = RelooperCreate(module);
+    RelooperBlockRef block0 = RelooperAddBlock(relooper, makeCallCheck(module,  0));
+    RelooperBlockRef block1 = RelooperAddBlock(relooper, makeCallCheck(module,  1));
+    RelooperBlockRef block2 = RelooperAddBlock(relooper, makeCallCheck(module,  2));
+    RelooperAddBranch(block0, block1, makeInt32(module, 55), NULL);
+    RelooperAddBranch(block0, block2, NULL, NULL);
+    RelooperAddBranch(block1, block2, NULL, NULL);
+    BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, block0, 0);
+    BinaryenFunctionRef sinker = BinaryenAddFunction(module,
+                                                     "if",
+                                                     BinaryenTypeNone(),
+                                                     BinaryenTypeNone(),
+                                                     localTypes,
+                                                     1,
+                                                     body);
+  }
+  { // if + code
+    RelooperRef relooper = RelooperCreate(module);
+    RelooperBlockRef block0 = RelooperAddBlock(relooper, makeCallCheck(module,  0));
+    RelooperBlockRef block1 = RelooperAddBlock(relooper, makeCallCheck(module,  1));
+    RelooperBlockRef block2 = RelooperAddBlock(relooper, makeCallCheck(module,  2));
+    BinaryenExpressionRef temp = makeDroppedInt32(module, -1);
+    RelooperAddBranch(block0, block1, makeInt32(module, 55), temp);
+    RelooperAddBranch(block0, block2, NULL, makeDroppedInt32(module, -2));
+    RelooperAddBranch(block1, block2, NULL, makeDroppedInt32(module, -3));
+    BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, block0, 0);
+    BinaryenFunctionRef sinker = BinaryenAddFunction(module,
+                                                     "if-plus-code",
+                                                     BinaryenTypeNone(),
+                                                     BinaryenTypeNone(),
+                                                     localTypes,
+                                                     1,
+                                                     body);
+  }
+  { // if-else
+    RelooperRef relooper = RelooperCreate(module);
+    RelooperBlockRef block0 = RelooperAddBlock(relooper, makeCallCheck(module,  0));
+    RelooperBlockRef block1 = RelooperAddBlock(relooper, makeCallCheck(module,  1));
+    RelooperBlockRef block2 = RelooperAddBlock(relooper, makeCallCheck(module,  2));
+    RelooperBlockRef block3 = RelooperAddBlock(relooper, makeCallCheck(module,  3));
+    RelooperAddBranch(block0, block1, makeInt32(module, 55), NULL);
+    RelooperAddBranch(block0, block2, NULL, NULL);
+    RelooperAddBranch(block1, block3, NULL, NULL);
+    RelooperAddBranch(block2, block3, NULL, NULL);
+    BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, block0, 0);
+    BinaryenFunctionRef sinker = BinaryenAddFunction(module,
+                                                     "if-else",
+                                                     BinaryenTypeNone(),
+                                                     BinaryenTypeNone(),
+                                                     localTypes,
+                                                     1,
+                                                     body);
+  }
+  { // loop+tail
+    RelooperRef relooper = RelooperCreate(module);
+    RelooperBlockRef block0 = RelooperAddBlock(relooper, makeCallCheck(module,  0));
+    RelooperBlockRef block1 = RelooperAddBlock(relooper, makeCallCheck(module,  1));
+    RelooperBlockRef block2 = RelooperAddBlock(relooper, makeCallCheck(module,  2));
+    RelooperAddBranch(block0, block1, NULL, NULL);
+    RelooperAddBranch(block1, block0, makeInt32(module, 10), NULL);
+    RelooperAddBranch(block1, block2, NULL, NULL);
+    BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, block0, 0);
+    BinaryenFunctionRef sinker = BinaryenAddFunction(module,
+                                                     "loop-tail",
+                                                     BinaryenTypeNone(),
+                                                     BinaryenTypeNone(),
+                                                     localTypes,
+                                                     1,
+                                                     body);
+  }
+  { // nontrivial loop + phi to head
+    RelooperRef relooper = RelooperCreate(module);
+    RelooperBlockRef block0 = RelooperAddBlock(relooper, makeCallCheck(module,  0));
+    RelooperBlockRef block1 = RelooperAddBlock(relooper, makeCallCheck(module,  1));
+    RelooperBlockRef block2 = RelooperAddBlock(relooper, makeCallCheck(module,  2));
+    RelooperBlockRef block3 = RelooperAddBlock(relooper, makeCallCheck(module,  3));
+    RelooperBlockRef block4 = RelooperAddBlock(relooper, makeCallCheck(module,  4));
+    RelooperBlockRef block5 = RelooperAddBlock(relooper, makeCallCheck(module,  5));
+    RelooperBlockRef block6 = RelooperAddBlock(relooper, makeCallCheck(module,  6));
+    RelooperAddBranch(block0, block1, NULL, makeDroppedInt32(module, 10));
+    RelooperAddBranch(block1, block2, makeInt32(module, -2), NULL);
+    RelooperAddBranch(block1, block6, NULL, makeDroppedInt32(module, 20));
+    RelooperAddBranch(block2, block3, makeInt32(module, -6), NULL);
+    RelooperAddBranch(block2, block1, NULL, makeDroppedInt32(module, 30));
+    RelooperAddBranch(block3, block4, makeInt32(module, -10), NULL);
+    RelooperAddBranch(block3, block5, NULL, NULL);
+    RelooperAddBranch(block4, block5, NULL, NULL);
+    RelooperAddBranch(block5, block6, NULL, makeDroppedInt32(module, 40));
+    BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, block0, 0);
+    BinaryenFunctionRef sinker =
+      BinaryenAddFunction(module,
+                          "nontrivial-loop-plus-phi-to-head",
+                          BinaryenTypeNone(),
+                          BinaryenTypeNone(),
+                          localTypes,
+                          1,
+                          body);
+  }
+  { // switch
+    RelooperRef relooper = RelooperCreate(module);
+    BinaryenExpressionRef temp = makeInt32(module, -99);
+    RelooperBlockRef block0 = RelooperAddBlockWithSwitch(relooper, makeCallCheck(module,  0), temp);
+    // TODO: this example is not very good, the blocks should end in a |return| as otherwise they
+    //       fall through to each other. A relooper block should end in something that stops control
+    //       flow, if it doesn't have branches going out
+    RelooperBlockRef block1 = RelooperAddBlock(relooper, makeCallCheck(module,  1));
+    RelooperBlockRef block2 = RelooperAddBlock(relooper, makeCallCheck(module,  2));
+    RelooperBlockRef block3 = RelooperAddBlock(relooper, makeCallCheck(module,  3));
+    BinaryenIndex to_block1[] = { 2, 5 };
+    RelooperAddBranchForSwitch(block0, block1, to_block1, 2, NULL);
+    BinaryenIndex to_block2[] = { 4 };
+    RelooperAddBranchForSwitch(block0, block2, to_block2, 1, makeDroppedInt32(module, 55));
+    RelooperAddBranchForSwitch(block0, block3, NULL, 0, NULL);
+    BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, block0, 0);
+    BinaryenFunctionRef sinker = BinaryenAddFunction(module,
+                                                     "switch",
+                                                     BinaryenTypeNone(),
+                                                     BinaryenTypeNone(),
+                                                     localTypes,
+                                                     1,
+                                                     body);
+  }
+  { // duff's device
+    RelooperRef relooper = RelooperCreate(module);
+    RelooperBlockRef block0 = RelooperAddBlock(relooper, makeCallCheck(module,  0));
+    RelooperBlockRef block1 = RelooperAddBlock(relooper, makeCallCheck(module,  1));
+    RelooperBlockRef block2 = RelooperAddBlock(relooper, makeCallCheck(module,  2));
+    RelooperAddBranch(block0, block1, makeInt32(module, 10), NULL);
+    RelooperAddBranch(block0, block2, NULL, NULL);
+    RelooperAddBranch(block1, block2, NULL, NULL);
+    RelooperAddBranch(block2, block1, NULL, NULL);
+    BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, block0, 3); // use $3 as the helper var
+    BinaryenType localTypes[] = { BinaryenTypeInt32(), BinaryenTypeInt32(), BinaryenTypeInt64(), BinaryenTypeInt32(), BinaryenTypeFloat32(), BinaryenTypeFloat64(), BinaryenTypeInt32() };
+    BinaryenFunctionRef sinker =
+      BinaryenAddFunction(module,
+                          "duffs-device",
+                          BinaryenTypeNone(),
+                          BinaryenTypeNone(),
+                          localTypes,
+                          sizeof(localTypes) / sizeof(BinaryenType),
+                          body);
+  }
+
+  { // return in a block
+    RelooperRef relooper = RelooperCreate(module);
+    BinaryenExpressionRef listList[] = { makeCallCheck(module,  42), BinaryenReturn(module, makeInt32(module, 1337)) };
+    BinaryenExpressionRef list = BinaryenBlock(module, "the-list", listList, 2, -1);
+    RelooperBlockRef block = RelooperAddBlock(relooper, list);
+    BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, block, 0);
+    BinaryenFunctionRef sinker = BinaryenAddFunction(module,
+                                                     "return",
+                                                     BinaryenTypeNone(),
+                                                     BinaryenTypeInt32(),
+                                                     localTypes,
+                                                     1,
+                                                     body);
+  }
+
+  printf("raw:\n");
+  BinaryenModulePrint(module);
+
+  assert(BinaryenModuleValidate(module));
+
+  BinaryenModuleOptimize(module);
+
+  assert(BinaryenModuleValidate(module));
+
+  printf("optimized:\n");
+  BinaryenModulePrint(module);
+
+  BinaryenModuleDispose(module);
+}
+
+void test_binaries() {
+  char buffer[1024];
+  size_t size;
+
+  { // create a module and write it to binary
+    BinaryenModuleRef module = BinaryenModuleCreate();
+    BinaryenType ii_[2] = {BinaryenTypeInt32(), BinaryenTypeInt32()};
+    BinaryenType ii = BinaryenTypeCreate(ii_, 2);
+    BinaryenExpressionRef x = BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+                          y = BinaryenLocalGet(module, 1, BinaryenTypeInt32());
+    BinaryenExpressionRef add = BinaryenBinary(module, BinaryenAddInt32(), x, y);
+    BinaryenFunctionRef adder = BinaryenAddFunction(
+      module, "adder", ii, BinaryenTypeInt32(), NULL, 0, add);
+    BinaryenSetDebugInfo(1); // include names section
+    size = BinaryenModuleWrite(module, buffer, 1024); // write out the module
+    BinaryenSetDebugInfo(0);
+    BinaryenModuleDispose(module);
+  }
+
+  assert(size > 0);
+  assert(size < 512); // this is a tiny module
+
+  // read the module from the binary
+  BinaryenModuleRef module = BinaryenModuleRead(buffer, size);
+
+  // validate, print, and free
+  assert(BinaryenModuleValidate(module));
+  printf("module loaded from binary form:\n");
+  BinaryenModulePrint(module);
+
+  // write the s-expr representation of the module.
+  BinaryenModuleWriteText(module, buffer, 1024);
+  printf("module s-expr printed (in memory):\n%s\n", buffer);
+
+
+  // writ the s-expr representation to a pointer which is managed by the
+  // caller
+  char *text = BinaryenModuleAllocateAndWriteText(module);
+  printf("module s-expr printed (in memory, caller-owned):\n%s\n", text);
+  free(text);
+
+
+  BinaryenModuleDispose(module);
+}
+
+void test_interpret() {
+  // create a simple module with a start method that prints a number, and interpret it, printing that number.
+  BinaryenModuleRef module = BinaryenModuleCreate();
+
+  BinaryenType iparams[2] = { BinaryenTypeInt32() };
+  BinaryenAddFunctionImport(module,
+                            "print-i32",
+                            "spectest",
+                            "print",
+                            BinaryenTypeInt32(),
+                            BinaryenTypeNone());
+
+  BinaryenExpressionRef callOperands[] = { makeInt32(module, 1234) };
+  BinaryenExpressionRef call = BinaryenCall(module, "print-i32", callOperands, 1, BinaryenTypeNone());
+  BinaryenFunctionRef starter = BinaryenAddFunction(
+    module, "starter", BinaryenTypeNone(), BinaryenTypeNone(), NULL, 0, call);
+  BinaryenSetStart(module, starter);
+
+  BinaryenModulePrint(module);
+  assert(BinaryenModuleValidate(module));
+  BinaryenModuleInterpret(module);
+  BinaryenModuleDispose(module);
+}
+
+void test_nonvalid() {
+  // create a module that fails to validate
+  {
+    BinaryenModuleRef module = BinaryenModuleCreate();
+
+    BinaryenType localTypes[] = { BinaryenTypeInt32() };
+    BinaryenFunctionRef func = BinaryenAddFunction(
+      module,
+      "func",
+      BinaryenTypeNone(),
+      BinaryenTypeNone(),
+      localTypes,
+      1,
+      BinaryenLocalSet(module, 0, makeInt64(module, 1234)) // wrong type!
+    );
+
+    BinaryenModulePrint(module);
+    printf("validation: %d\n", BinaryenModuleValidate(module));
+
+    BinaryenModuleDispose(module);
+  }
+}
+
+void test_color_status() {
+    int i;
+
+    // save old state
+    const int old_state = BinaryenAreColorsEnabled();
+
+    // Check that we can set the state to both {0, 1}
+    for(i = 0; i <= 1; i++){
+        BinaryenSetColorsEnabled(i);
+        assert(BinaryenAreColorsEnabled() == i);
+    }
+
+    BinaryenSetColorsEnabled(old_state);
+}
+
+void test_for_each() {
+  BinaryenIndex i;
+
+  BinaryenModuleRef module = BinaryenModuleCreate();
+  BinaryenFunctionRef fns[3] = {};
+  fns[0] = BinaryenAddFunction(module,
+                               "fn0",
+                               BinaryenTypeNone(),
+                               BinaryenTypeNone(),
+                               NULL,
+                               0,
+                               BinaryenNop(module));
+  fns[1] = BinaryenAddFunction(module,
+                               "fn1",
+                               BinaryenTypeNone(),
+                               BinaryenTypeNone(),
+                               NULL,
+                               0,
+                               BinaryenNop(module));
+  fns[2] = BinaryenAddFunction(module,
+                               "fn2",
+                               BinaryenTypeNone(),
+                               BinaryenTypeNone(),
+                               NULL,
+                               0,
+                               BinaryenNop(module));
+  {
+    for (i = 0; i < BinaryenGetNumFunctions(module) ; i++) {
+      assert(BinaryenGetFunctionByIndex(module, i) == fns[i]);
+    }
+
+    BinaryenExportRef exps[3] = {0};
+    exps[0] = BinaryenAddFunctionExport(module, "fn0", "export0");
+    exps[1] = BinaryenAddFunctionExport(module, "fn1", "export1");
+    exps[2] = BinaryenAddFunctionExport(module, "fn2", "export2");
+
+    for (i = 0; i < BinaryenGetNumExports(module) ; i++) {
+      assert(BinaryenGetExportByIndex(module, i) == exps[i]);
+    }
+
+    const char* segments[] = { "hello, world", "segment data 2" };
+    const uint32_t expected_offsets[] = { 10, 125 };
+    int8_t segmentPassive[] = { 0, 0 };
+    BinaryenIndex segmentSizes[] = { 12, 14 };
+
+    BinaryenExpressionRef segmentOffsets[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(expected_offsets[0])),
+      BinaryenGlobalGet(module, "a-global", BinaryenTypeInt32())
+    };
+    BinaryenSetMemory(module, 1, 256, "mem", segments, segmentPassive, segmentOffsets, segmentSizes, 2, 0);
+    BinaryenAddGlobal(module, "a-global", BinaryenTypeInt32(), 0, makeInt32(module, expected_offsets[1]));
+
+    for (i = 0; i < BinaryenGetNumMemorySegments(module) ; i++) {
+      char out[15] = {};
+      assert(BinaryenGetMemorySegmentByteOffset(module, i) == expected_offsets[i]);
+      assert(BinaryenGetMemorySegmentByteLength(module, i) == segmentSizes[i]);
+      BinaryenCopyMemorySegmentData(module, i, out);
+      assert(0 == strcmp(segments[i], out));
+    }
+  }
+  {
+    const char* funcNames[] = {
+      BinaryenFunctionGetName(fns[0]),
+      BinaryenFunctionGetName(fns[1]),
+      BinaryenFunctionGetName(fns[2])
+    };
+    BinaryenExpressionRef constExprRef = BinaryenConst(module, BinaryenLiteralInt32(0));
+    BinaryenSetFunctionTable(module, 1, 1, funcNames, 3, constExprRef);
+    assert(0 == BinaryenIsFunctionTableImported(module));
+    assert(1 == BinaryenGetNumFunctionTableSegments(module));
+    assert(constExprRef == BinaryenGetFunctionTableSegmentOffset(module, 0));
+    assert(3 == BinaryenGetFunctionTableSegmentLength(module, 0));
+    for (i = 0; i != BinaryenGetFunctionTableSegmentLength(module, 0); ++i)
+    {
+      const char * str = BinaryenGetFunctionTableSegmentData(module, 0, i);
+      assert(0 == strcmp(funcNames[i], str));
+    }
+  }
+  BinaryenModulePrint(module);
+  BinaryenModuleDispose(module);
+}
+
+int main() {
+  test_types();
+  test_features();
+  test_core();
+  test_unreachable();
+  test_relooper();
+  test_binaries();
+  test_interpret();
+  test_nonvalid();
+  test_color_status();
+  test_for_each();
+
+  return 0;
+}
diff --git a/binaryen/test/example/c-api-kitchen-sink.txt b/binaryen/test/example/c-api-kitchen-sink.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/c-api-kitchen-sink.txt
@@ -0,0 +1,2460 @@
+  // BinaryenTypeNone: 0
+  // BinaryenTypeUnreachable: 1
+  // BinaryenTypeInt32: 2
+  // BinaryenTypeInt64: 3
+  // BinaryenTypeFloat32: 4
+  // BinaryenTypeFloat64: 5
+  // BinaryenTypeVec128: 6
+  // BinaryenTypeFuncref: 7
+  // BinaryenTypeExternref: 8
+  // BinaryenTypeExnref: 9
+  // BinaryenTypeAnyref: 10
+  // BinaryenTypeEqref: 11
+  // BinaryenTypeI31ref: 12
+  // BinaryenTypeAuto: -1
+BinaryenFeatureMVP: 0
+BinaryenFeatureAtomics: 1
+BinaryenFeatureBulkMemory: 16
+BinaryenFeatureMutableGlobals: 2
+BinaryenFeatureNontrappingFPToInt: 4
+BinaryenFeatureSignExt: 32
+BinaryenFeatureSIMD128: 8
+BinaryenFeatureExceptionHandling: 64
+BinaryenFeatureTailCall: 128
+BinaryenFeatureReferenceTypes: 256
+BinaryenFeatureMultivalue: 512
+BinaryenFeatureGC: 1024
+BinaryenFeatureMemory64: 2048
+BinaryenFeatureAll: 4095
+(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.841)
+       )
+      )
+      (drop
+       (f32.ceil
+        (f32.const -33.61199951171875)
+       )
+      )
+      (drop
+       (f64.floor
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (f32.trunc
+        (f32.const -33.61199951171875)
+       )
+      )
+      (drop
+       (f32.nearest
+        (f32.const -33.61199951171875)
+       )
+      )
+      (drop
+       (f64.sqrt
+        (f64.const -9005.841)
+       )
+      )
+      (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.841)
+       )
+      )
+      (drop
+       (i64.trunc_f64_s
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (i32.trunc_f64_u
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (i64.trunc_f64_u
+        (f64.const -9005.841)
+       )
+      )
+      (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.841)
+       )
+      )
+      (drop
+       (i64.trunc_sat_f64_s
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (i32.trunc_sat_f64_u
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (i64.trunc_sat_f64_u
+        (f64.const -9005.841)
+       )
+      )
+      (drop
+       (i32.reinterpret_f32
+        (f32.const -33.61199951171875)
+       )
+      )
+      (drop
+       (i64.reinterpret_f64
+        (f64.const -9005.841)
+       )
+      )
+      (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.841)
+       )
+      )
+      (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.841)
+       )
+      )
+      (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.841)
+        (f64.const -9007.333)
+       )
+      )
+      (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.841)
+        (f64.const -9007.333)
+       )
+      )
+      (drop
+       (f32.min
+        (f32.const -33.61199951171875)
+        (f32.const -62.5)
+       )
+      )
+      (drop
+       (f64.max
+        (f64.const -9005.841)
+        (f64.const -9007.333)
+       )
+      )
+      (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.841)
+        (f64.const -9007.333)
+       )
+      )
+      (drop
+       (f64.gt
+        (f64.const -9005.841)
+        (f64.const -9007.333)
+       )
+      )
+      (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
+       (i64x2.mul
+        (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
+       (f32x4.pmin
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f32x4.pmax
+        (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
+       (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
+       (f64x2.pmin
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       )
+      )
+      (drop
+       (f64x2.pmax
+        (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
+       (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 extern)
+       )
+      )
+      (drop
+       (ref.is_null
+        (ref.func "$kitchen()sinker")
+       )
+      )
+      (drop
+       (ref.is_null
+        (ref.null exn)
+       )
+      )
+      (drop
+       (select (result funcref)
+        (ref.null func)
+        (ref.func "$kitchen()sinker")
+        (i32.const 1)
+       )
+      )
+      (drop
+       (ref.eq
+        (ref.null eq)
+        (ref.null eq)
+       )
+      )
+      (try
+       (do
+        (throw $a-event
+         (i32.const 0)
+        )
+       )
+       (catch
+        (local.set $5
+         (pop exnref)
+        )
+        (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)
+        )
+       )
+      )
+      (drop
+       (pop i32)
+      )
+      (drop
+       (pop i64)
+      )
+      (drop
+       (pop f32)
+      )
+      (drop
+       (pop f64)
+      )
+      (drop
+       (pop funcref)
+      )
+      (drop
+       (pop externref)
+      )
+      (drop
+       (pop exnref)
+      )
+      (drop
+       (pop i32 i64 f32 f64)
+      )
+      (drop
+       (memory.size)
+      )
+      (drop
+       (memory.grow
+        (i32.const 0)
+       )
+      )
+      (drop
+       (i31.new
+        (i32.const 0)
+       )
+      )
+      (drop
+       (i31.get_s
+        (i31.new
+         (i32.const 1)
+        )
+       )
+      )
+      (drop
+       (i31.get_u
+        (i31.new
+         (i32.const 2)
+        )
+       )
+      )
+      (nop)
+      (unreachable)
+     )
+    )
+   )
+   (i32.const 42)
+  )
+ )
+ (func $starter
+  (nop)
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_i64 (func (result i64)))
+ (func $unreachable-fn (result i32)
+  (call_indirect (type $none_=>_i64)
+   (unreachable)
+  )
+ )
+)
+raw:
+(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)
+   )
+  )
+ )
+)
+optimized:
+(module
+)
+module loaded from binary form:
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (func $adder (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
+module s-expr printed (in memory):
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (func $adder (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
+
+module s-expr printed (in memory, caller-owned):
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (func $adder (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
+
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (import "spectest" "print" (func $print-i32 (param i32)))
+ (start $starter)
+ (func $starter
+  (call $print-i32
+   (i32.const 1234)
+  )
+ )
+)
+1234 : i32
+(module
+ (type $none_=>_none (func))
+ (func $func
+  (local $0 i32)
+  (local.set $0
+   (i64.const 1234)
+  )
+ )
+)
+validation: 0
+(module
+ (type $none_=>_none (func))
+ (memory $0 1 256)
+ (data (i32.const 10) "hello, world")
+ (data (global.get $a-global) "segment data 2")
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $fn0 $fn1 $fn2)
+ (global $a-global i32 (i32.const 125))
+ (export "export0" (func $fn0))
+ (export "export1" (func $fn1))
+ (export "export2" (func $fn2))
+ (export "mem" (memory $0))
+ (func $fn0
+  (nop)
+ )
+ (func $fn1
+  (nop)
+ )
+ (func $fn2
+  (nop)
+ )
+)
diff --git a/binaryen/test/example/c-api-kitchen-sink.txt.txt b/binaryen/test/example/c-api-kitchen-sink.txt.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/c-api-kitchen-sink.txt.txt
@@ -0,0 +1,2236 @@
+(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-relooper-unreachable-if.cpp b/binaryen/test/example/c-api-relooper-unreachable-if.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/c-api-relooper-unreachable-if.cpp
@@ -0,0 +1,744 @@
+// beginning a Binaryen API trace
+
+#include <cassert>
+#include <math.h>
+#include <map>
+#include "binaryen-c.h"
+
+int main() {
+  std::map<size_t, BinaryenExpressionRef> expressions;
+  std::map<size_t, BinaryenFunctionRef> functions;
+  std::map<size_t, RelooperBlockRef> relooperBlocks;
+  BinaryenModuleRef the_module = NULL;
+  RelooperRef the_relooper = NULL;
+  the_module = BinaryenModuleCreate();
+  expressions[size_t(NULL)] = BinaryenExpressionRef(NULL);
+  BinaryenModuleAutoDrop(the_module);
+  {
+    const char* segments[] = { 0 };
+    int8_t segmentPassive[] = { 0 };
+    BinaryenExpressionRef segmentOffsets[] = { 0 };
+    BinaryenIndex segmentSizes[] = { 0 };
+    BinaryenSetMemory(the_module, 256, 256, "memory", segments, segmentPassive, segmentOffsets, segmentSizes, 0, 0);
+  }
+  the_relooper = RelooperCreate(the_module);
+  expressions[1] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
+  expressions[2] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[3] = BinaryenStore(
+    the_module, 4, 0, 0, expressions[2], expressions[1], BinaryenTypeInt32());
+  expressions[4] = BinaryenReturn(the_module, expressions[0]);
+  {
+    BinaryenExpressionRef children[] = { expressions[3], expressions[4] };
+    expressions[5] = BinaryenBlock(the_module, "bb0", children, 2, BinaryenTypeAuto());
+  }
+  relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[5]);
+  expressions[6] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[7] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[6]);
+  expressions[8] = BinaryenLocalSet(the_module, 0, expressions[7]);
+  relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[8]);
+  RelooperAddBranch(relooperBlocks[1], relooperBlocks[0], expressions[0], expressions[0]);
+  expressions[9] = RelooperRenderAndDispose(the_relooper, relooperBlocks[1], 1);
+  {
+    BinaryenType varTypes[] = {
+      BinaryenTypeInt32(), BinaryenTypeInt32(), BinaryenTypeInt64()};
+    functions[0] = BinaryenAddFunction(the_module,
+                                       "tinycore::eh_personality",
+                                       BinaryenTypeNone(),
+                                       BinaryenTypeNone(),
+                                       varTypes,
+                                       3,
+                                       expressions[9]);
+  }
+  BinaryenAddFunctionExport(the_module, "tinycore::eh_personality", "tinycore::eh_personality");
+  the_relooper = RelooperCreate(the_module);
+  expressions[10] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
+  expressions[11] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[12] = BinaryenStore(
+    the_module, 4, 0, 0, expressions[11], expressions[10], BinaryenTypeInt32());
+  expressions[13] = BinaryenReturn(the_module, expressions[0]);
+  {
+    BinaryenExpressionRef children[] = { expressions[12], expressions[13] };
+    expressions[14] = BinaryenBlock(the_module, "bb0", children, 2, BinaryenTypeAuto());
+  }
+  relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[14]);
+  expressions[15] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[16] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[15]);
+  expressions[17] = BinaryenLocalSet(the_module, 0, expressions[16]);
+  relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[17]);
+  RelooperAddBranch(relooperBlocks[1], relooperBlocks[0], expressions[0], expressions[0]);
+  expressions[18] = RelooperRenderAndDispose(the_relooper, relooperBlocks[1], 1);
+  {
+    BinaryenType varTypes[] = {
+      BinaryenTypeInt32(), BinaryenTypeInt32(), BinaryenTypeInt64()};
+    functions[1] = BinaryenAddFunction(the_module,
+                                       "tinycore::eh_unwind_resume",
+                                       BinaryenTypeNone(),
+                                       BinaryenTypeNone(),
+                                       varTypes,
+                                       3,
+                                       expressions[18]);
+  }
+  BinaryenAddFunctionExport(the_module, "tinycore::eh_unwind_resume", "tinycore::eh_unwind_resume");
+  the_relooper = RelooperCreate(the_module);
+  {
+    BinaryenExpressionRef children[] = { 0 };
+    expressions[19] = BinaryenBlock(the_module, "bb0", children, 0, BinaryenTypeAuto());
+  }
+  relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[19]);
+  {
+    BinaryenExpressionRef children[] = { 0 };
+    expressions[20] = BinaryenBlock(the_module, "bb1", children, 0, BinaryenTypeAuto());
+  }
+  relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[20]);
+  RelooperAddBranch(relooperBlocks[0], relooperBlocks[1], expressions[0], expressions[0]);
+  RelooperAddBranch(relooperBlocks[1], relooperBlocks[1], expressions[0], expressions[0]);
+  expressions[21] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[22] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[21]);
+  expressions[23] = BinaryenLocalSet(the_module, 0, expressions[22]);
+  relooperBlocks[2] = RelooperAddBlock(the_relooper, expressions[23]);
+  RelooperAddBranch(relooperBlocks[2], relooperBlocks[0], expressions[0], expressions[0]);
+  expressions[24] = RelooperRenderAndDispose(the_relooper, relooperBlocks[2], 1);
+  {
+    BinaryenType varTypes[] = {
+      BinaryenTypeInt32(), BinaryenTypeInt32(), BinaryenTypeInt64()};
+    functions[2] = BinaryenAddFunction(the_module,
+                                       "tinycore::panic_fmt",
+                                       BinaryenTypeNone(),
+                                       BinaryenTypeNone(),
+                                       varTypes,
+                                       3,
+                                       expressions[24]);
+  }
+  BinaryenAddFunctionExport(the_module, "tinycore::panic_fmt", "tinycore::panic_fmt");
+  the_relooper = RelooperCreate(the_module);
+  expressions[25] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
+  expressions[26] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[27] = BinaryenStore(
+    the_module, 4, 0, 0, expressions[26], expressions[25], BinaryenTypeInt32());
+  expressions[28] = BinaryenReturn(the_module, expressions[0]);
+  {
+    BinaryenExpressionRef children[] = { expressions[27], expressions[28] };
+    expressions[29] = BinaryenBlock(the_module, "bb0", children, 2, BinaryenTypeAuto());
+  }
+  relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[29]);
+  expressions[30] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[31] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[30]);
+  expressions[32] = BinaryenLocalSet(the_module, 0, expressions[31]);
+  relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[32]);
+  RelooperAddBranch(relooperBlocks[1], relooperBlocks[0], expressions[0], expressions[0]);
+  expressions[33] = RelooperRenderAndDispose(the_relooper, relooperBlocks[1], 1);
+  {
+    BinaryenType varTypes[] = {
+      BinaryenTypeInt32(), BinaryenTypeInt32(), BinaryenTypeInt64()};
+    functions[3] = BinaryenAddFunction(the_module,
+                                       "tinycore::rust_eh_register_frames",
+                                       BinaryenTypeNone(),
+                                       BinaryenTypeNone(),
+                                       varTypes,
+                                       3,
+                                       expressions[33]);
+  }
+  BinaryenAddFunctionExport(the_module, "tinycore::rust_eh_register_frames", "tinycore::rust_eh_register_frames");
+  the_relooper = RelooperCreate(the_module);
+  expressions[34] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
+  expressions[35] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[36] = BinaryenStore(
+    the_module, 4, 0, 0, expressions[35], expressions[34], BinaryenTypeInt32());
+  expressions[37] = BinaryenReturn(the_module, expressions[0]);
+  {
+    BinaryenExpressionRef children[] = { expressions[36], expressions[37] };
+    expressions[38] = BinaryenBlock(the_module, "bb0", children, 2, BinaryenTypeAuto());
+  }
+  relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[38]);
+  expressions[39] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[40] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[39]);
+  expressions[41] = BinaryenLocalSet(the_module, 0, expressions[40]);
+  relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[41]);
+  RelooperAddBranch(relooperBlocks[1], relooperBlocks[0], expressions[0], expressions[0]);
+  expressions[42] = RelooperRenderAndDispose(the_relooper, relooperBlocks[1], 1);
+  {
+    BinaryenType varTypes[] = {
+      BinaryenTypeInt32(), BinaryenTypeInt32(), BinaryenTypeInt64()};
+    functions[4] = BinaryenAddFunction(the_module,
+                                       "tinycore::rust_eh_unregister_frames",
+                                       BinaryenTypeNone(),
+                                       BinaryenTypeNone(),
+                                       varTypes,
+                                       3,
+                                       expressions[42]);
+  }
+  BinaryenAddFunctionExport(the_module, "tinycore::rust_eh_unregister_frames", "tinycore::rust_eh_unregister_frames");
+  the_relooper = RelooperCreate(the_module);
+  expressions[43] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
+  expressions[44] = BinaryenLocalSet(the_module, 1, expressions[43]);
+  expressions[45] = BinaryenLocalGet(the_module, 1, BinaryenTypeInt32());
+  expressions[46] = BinaryenLocalSet(the_module, 2, expressions[45]);
+  BinaryenAddFunctionImport(the_module,
+                            "print_i32",
+                            "spectest",
+                            "print",
+                            BinaryenTypeInt32(),
+                            BinaryenTypeNone());
+  expressions[47] = BinaryenLocalGet(the_module, 2, BinaryenTypeInt32());
+  {
+    BinaryenExpressionRef operands[] = { expressions[47] };
+    expressions[48] = BinaryenCall(the_module, "print_i32", operands, 1, BinaryenTypeNone());
+  }
+  {
+    BinaryenExpressionRef children[] = { expressions[44], expressions[46], expressions[48] };
+    expressions[49] = BinaryenBlock(the_module, "bb0", children, 3, BinaryenTypeAuto());
+  }
+  relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[49]);
+  expressions[50] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt32());
+  expressions[51] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[52] = BinaryenStore(
+    the_module, 4, 0, 0, expressions[51], expressions[50], BinaryenTypeInt32());
+  expressions[53] = BinaryenReturn(the_module, expressions[0]);
+  {
+    BinaryenExpressionRef children[] = { expressions[52], expressions[53] };
+    expressions[54] = BinaryenBlock(the_module, "bb1", children, 2, BinaryenTypeAuto());
+  }
+  relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[54]);
+  RelooperAddBranch(relooperBlocks[0], relooperBlocks[1], expressions[0], expressions[0]);
+  expressions[55] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[56] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[55]);
+  expressions[57] = BinaryenLocalSet(the_module, 3, expressions[56]);
+  relooperBlocks[2] = RelooperAddBlock(the_relooper, expressions[57]);
+  RelooperAddBranch(relooperBlocks[2], relooperBlocks[0], expressions[0], expressions[0]);
+  expressions[58] = RelooperRenderAndDispose(the_relooper, relooperBlocks[2], 4);
+  {
+    BinaryenType varTypes[] = {BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt64()};
+    functions[5] = BinaryenAddFunction(the_module,
+                                       "wasm::print_i32",
+                                       BinaryenTypeInt32(),
+                                       BinaryenTypeNone(),
+                                       varTypes,
+                                       5,
+                                       expressions[58]);
+  }
+  BinaryenAddFunctionExport(the_module, "wasm::print_i32", "wasm::print_i32");
+  the_relooper = RelooperCreate(the_module);
+  expressions[59] = BinaryenConst(the_module, BinaryenLiteralInt32(1));
+  expressions[60] = BinaryenLocalSet(the_module, 0, expressions[59]);
+  expressions[61] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
+  expressions[62] = BinaryenLocalSet(the_module, 2, expressions[61]);
+  expressions[63] = BinaryenLocalGet(the_module, 2, BinaryenTypeInt32());
+  expressions[64] = BinaryenConst(the_module, BinaryenLiteralInt32(2));
+  expressions[65] = BinaryenUnary(the_module, 22, expressions[63]);
+  expressions[66] = BinaryenUnary(the_module, 22, expressions[64]);
+  expressions[67] = BinaryenBinary(the_module, 25, expressions[65], expressions[66]);
+  expressions[68] = BinaryenLocalSet(the_module, 8, expressions[67]);
+  expressions[69] = BinaryenLocalGet(the_module, 8, BinaryenTypeInt64());
+  expressions[70] = BinaryenUnary(the_module, 24, expressions[69]);
+  expressions[71] = BinaryenConst(the_module, BinaryenLiteralInt64(32));
+  expressions[72] = BinaryenLocalGet(the_module, 8, BinaryenTypeInt64());
+  expressions[73] = BinaryenBinary(the_module, 36, expressions[72], expressions[71]);
+  expressions[74] = BinaryenUnary(the_module, 24, expressions[73]);
+  expressions[75] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[76] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[75]);
+  expressions[77] = BinaryenConst(the_module, BinaryenLiteralInt32(128));
+  expressions[78] = BinaryenBinary(the_module, 1, expressions[76], expressions[77]);
+  expressions[79] =
+    BinaryenLocalTee(the_module, 3, expressions[78], BinaryenTypeInt32());
+  expressions[80] = BinaryenStore(
+    the_module, 4, 0, 0, expressions[75], expressions[79], BinaryenTypeInt32());
+  expressions[81] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt32());
+  expressions[82] = BinaryenStore(
+    the_module, 4, 0, 0, expressions[81], expressions[70], BinaryenTypeInt32());
+  expressions[83] = BinaryenStore(
+    the_module, 4, 4, 0, expressions[81], expressions[74], BinaryenTypeInt32());
+  {
+    BinaryenExpressionRef children[] = { expressions[60], expressions[62], expressions[68], expressions[80], expressions[82], expressions[83] };
+    expressions[84] = BinaryenBlock(the_module, "bb0", children, 6, BinaryenTypeAuto());
+  }
+  relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[84]);
+  expressions[85] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt32());
+  expressions[86] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[85]);
+  expressions[87] = BinaryenLocalSet(the_module, 1, expressions[86]);
+  expressions[88] = BinaryenLocalGet(the_module, 1, BinaryenTypeInt32());
+  expressions[89] = BinaryenLocalSet(the_module, 4, expressions[88]);
+  expressions[90] = BinaryenLocalGet(the_module, 4, BinaryenTypeInt32());
+  expressions[91] = BinaryenLocalSet(the_module, 5, expressions[90]);
+  expressions[92] = BinaryenLocalGet(the_module, 6, BinaryenTypeInt32());
+  expressions[93] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[94] = BinaryenStore(
+    the_module, 4, 0, 0, expressions[93], expressions[92], BinaryenTypeInt32());
+  expressions[95] = BinaryenLocalGet(the_module, 5, BinaryenTypeInt32());
+  expressions[96] = BinaryenReturn(the_module, expressions[95]);
+  {
+    BinaryenExpressionRef children[] = { expressions[87], expressions[89], expressions[91], expressions[94], expressions[96] };
+    expressions[97] = BinaryenBlock(the_module, "bb1", children, 5, BinaryenTypeAuto());
+  }
+  relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[97]);
+  expressions[98] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt32());
+  expressions[99] = BinaryenLoad(the_module, 4, 0, 8, 0, BinaryenTypeInt32(), expressions[98]);
+  RelooperAddBranch(relooperBlocks[0], relooperBlocks[1], expressions[99], expressions[0]);
+  expressions[100] = BinaryenUnreachable(the_module);
+  relooperBlocks[2] = RelooperAddBlock(the_relooper, expressions[100]);
+  RelooperAddBranch(relooperBlocks[0], relooperBlocks[2], expressions[0], expressions[0]);
+  expressions[101] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[102] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[101]);
+  expressions[103] = BinaryenLocalSet(the_module, 6, expressions[102]);
+  relooperBlocks[3] = RelooperAddBlock(the_relooper, expressions[103]);
+  RelooperAddBranch(relooperBlocks[3], relooperBlocks[0], expressions[0], expressions[0]);
+  expressions[104] = RelooperRenderAndDispose(the_relooper, relooperBlocks[3], 7);
+  {
+    BinaryenType varTypes[] = {BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt64()};
+    functions[6] = BinaryenAddFunction(the_module,
+                                       "real_main",
+                                       BinaryenTypeNone(),
+                                       BinaryenTypeInt32(),
+                                       varTypes,
+                                       9,
+                                       expressions[104]);
+  }
+  BinaryenAddFunctionExport(the_module, "real_main", "real_main");
+  the_relooper = RelooperCreate(the_module);
+  expressions[105] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
+  expressions[106] = BinaryenLocalSet(the_module, 2, expressions[105]);
+  {
+    BinaryenExpressionRef operands[] = { 0 };
+    expressions[107] = BinaryenCall(the_module, "real_main", operands, 0, BinaryenTypeInt32());
+  }
+  expressions[108] = BinaryenLocalSet(the_module, 4, expressions[107]);
+  {
+    BinaryenExpressionRef children[] = { expressions[106], expressions[108] };
+    expressions[109] = BinaryenBlock(the_module, "bb0", children, 2, BinaryenTypeAuto());
+  }
+  relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[109]);
+  expressions[110] = BinaryenLocalGet(the_module, 4, BinaryenTypeInt32());
+  expressions[111] = BinaryenConst(the_module, BinaryenLiteralInt32(3));
+  expressions[112] = BinaryenUnary(the_module, 22, expressions[110]);
+  expressions[113] = BinaryenUnary(the_module, 22, expressions[111]);
+  expressions[114] = BinaryenBinary(the_module, 25, expressions[112], expressions[113]);
+  expressions[115] = BinaryenLocalSet(the_module, 11, expressions[114]);
+  expressions[116] = BinaryenLocalGet(the_module, 11, BinaryenTypeInt64());
+  expressions[117] = BinaryenUnary(the_module, 24, expressions[116]);
+  expressions[118] = BinaryenConst(the_module, BinaryenLiteralInt64(32));
+  expressions[119] = BinaryenLocalGet(the_module, 11, BinaryenTypeInt64());
+  expressions[120] = BinaryenBinary(the_module, 36, expressions[119], expressions[118]);
+  expressions[121] = BinaryenUnary(the_module, 24, expressions[120]);
+  expressions[122] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[123] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[122]);
+  expressions[124] = BinaryenConst(the_module, BinaryenLiteralInt32(128));
+  expressions[125] = BinaryenBinary(the_module, 1, expressions[123], expressions[124]);
+  expressions[126] =
+    BinaryenLocalTee(the_module, 5, expressions[125], BinaryenTypeInt32());
+  expressions[127] = BinaryenStore(the_module,
+                                   4,
+                                   0,
+                                   0,
+                                   expressions[122],
+                                   expressions[126],
+                                   BinaryenTypeInt32());
+  expressions[128] = BinaryenLocalGet(the_module, 5, BinaryenTypeInt32());
+  expressions[129] = BinaryenStore(the_module,
+                                   4,
+                                   0,
+                                   0,
+                                   expressions[128],
+                                   expressions[117],
+                                   BinaryenTypeInt32());
+  expressions[130] = BinaryenStore(the_module,
+                                   4,
+                                   4,
+                                   0,
+                                   expressions[128],
+                                   expressions[121],
+                                   BinaryenTypeInt32());
+  {
+    BinaryenExpressionRef children[] = { expressions[115], expressions[127], expressions[129], expressions[130] };
+    expressions[131] = BinaryenBlock(the_module, "bb1", children, 4, BinaryenTypeAuto());
+  }
+  relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[131]);
+  expressions[132] = BinaryenLocalGet(the_module, 5, BinaryenTypeInt32());
+  expressions[133] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[132]);
+  expressions[134] = BinaryenLocalSet(the_module, 3, expressions[133]);
+  expressions[135] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt32());
+  expressions[136] = BinaryenLocalSet(the_module, 6, expressions[135]);
+  expressions[137] = BinaryenLocalGet(the_module, 6, BinaryenTypeInt32());
+  {
+    BinaryenExpressionRef operands[] = { expressions[137] };
+    expressions[138] = BinaryenCall(the_module, "wasm::print_i32", operands, 1, BinaryenTypeNone());
+  }
+  {
+    BinaryenExpressionRef children[] = { expressions[134], expressions[136], expressions[138] };
+    expressions[139] = BinaryenBlock(the_module, "bb2", children, 3, BinaryenTypeAuto());
+  }
+  relooperBlocks[2] = RelooperAddBlock(the_relooper, expressions[139]);
+  expressions[140] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt32());
+  expressions[141] = BinaryenLocalSet(the_module, 7, expressions[140]);
+  expressions[142] = BinaryenLocalGet(the_module, 7, BinaryenTypeInt32());
+  expressions[143] = BinaryenLocalSet(the_module, 8, expressions[142]);
+  expressions[144] = BinaryenLocalGet(the_module, 9, BinaryenTypeInt32());
+  expressions[145] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[146] = BinaryenStore(the_module,
+                                   4,
+                                   0,
+                                   0,
+                                   expressions[145],
+                                   expressions[144],
+                                   BinaryenTypeInt32());
+  expressions[147] = BinaryenLocalGet(the_module, 8, BinaryenTypeInt32());
+  expressions[148] = BinaryenReturn(the_module, expressions[147]);
+  {
+    BinaryenExpressionRef children[] = { expressions[141], expressions[143], expressions[146], expressions[148] };
+    expressions[149] = BinaryenBlock(the_module, "bb3", children, 4, BinaryenTypeAuto());
+  }
+  relooperBlocks[3] = RelooperAddBlock(the_relooper, expressions[149]);
+  RelooperAddBranch(relooperBlocks[0], relooperBlocks[1], expressions[0], expressions[0]);
+  expressions[150] = BinaryenLocalGet(the_module, 5, BinaryenTypeInt32());
+  expressions[151] = BinaryenLoad(the_module, 4, 0, 8, 0, BinaryenTypeInt32(), expressions[150]);
+  RelooperAddBranch(relooperBlocks[1], relooperBlocks[2], expressions[151], expressions[0]);
+  expressions[152] = BinaryenUnreachable(the_module);
+  relooperBlocks[4] = RelooperAddBlock(the_relooper, expressions[152]);
+  RelooperAddBranch(relooperBlocks[1], relooperBlocks[4], expressions[0], expressions[0]);
+  RelooperAddBranch(relooperBlocks[2], relooperBlocks[3], expressions[0], expressions[0]);
+  expressions[153] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[154] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[153]);
+  expressions[155] = BinaryenLocalSet(the_module, 9, expressions[154]);
+  relooperBlocks[5] = RelooperAddBlock(the_relooper, expressions[155]);
+  RelooperAddBranch(relooperBlocks[5], relooperBlocks[0], expressions[0], expressions[0]);
+  expressions[156] = RelooperRenderAndDispose(the_relooper, relooperBlocks[5], 10);
+  {
+    BinaryenType varTypes[] = {BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt64()};
+    BinaryenType ii_[2] = {BinaryenTypeInt32(), BinaryenTypeInt32()};
+    BinaryenType ii = BinaryenTypeCreate(ii_, 2);
+    functions[7] = BinaryenAddFunction(the_module,
+                                       "main",
+                                       ii,
+                                       BinaryenTypeInt32(),
+                                       varTypes,
+                                       10,
+                                       expressions[156]);
+  }
+  BinaryenAddFunctionExport(the_module, "main", "main");
+  {
+    const char* segments[] = { 0 };
+    BinaryenExpressionRef segmentOffsets[] = { 0 };
+    int8_t segmentPassive[] = { 0 };
+    BinaryenIndex segmentSizes[] = { 0 };
+    BinaryenSetMemory(the_module, 1, 1, NULL, segments, segmentPassive, segmentOffsets, segmentSizes, 0, 0);
+  }
+  expressions[157] = BinaryenConst(the_module, BinaryenLiteralInt32(65535));
+  expressions[158] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[159] = BinaryenStore(the_module,
+                                   4,
+                                   0,
+                                   0,
+                                   expressions[158],
+                                   expressions[157],
+                                   BinaryenTypeInt32());
+  expressions[160] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[161] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  {
+    BinaryenExpressionRef operands[] = { expressions[160], expressions[161] };
+    expressions[162] =
+      BinaryenCall(the_module, "main", operands, 2, BinaryenTypeInt32());
+  }
+  expressions[163] = BinaryenDrop(the_module, expressions[162]);
+  {
+    BinaryenExpressionRef children[] = { expressions[159], expressions[163] };
+    expressions[164] = BinaryenBlock(the_module, NULL, children, 2, BinaryenTypeAuto());
+  }
+  BinaryenAddFunctionExport(the_module, "__wasm_start", "rust_entry");
+  {
+    BinaryenType varTypes[] = {BinaryenTypeNone()};
+    functions[8] = BinaryenAddFunction(the_module,
+                                       "__wasm_start",
+                                       BinaryenTypeNone(),
+                                       BinaryenTypeNone(),
+                                       varTypes,
+                                       0,
+                                       expressions[164]);
+  }
+  BinaryenSetStart(the_module, functions[8]);
+  the_relooper = RelooperCreate(the_module);
+  expressions[165] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
+  expressions[166] = BinaryenLocalSet(the_module, 2, expressions[165]);
+  expressions[167] = BinaryenLocalGet(the_module, 1, BinaryenTypeInt32());
+  expressions[168] = BinaryenLocalSet(the_module, 3, expressions[167]);
+  expressions[169] = BinaryenLocalGet(the_module, 2, BinaryenTypeInt32());
+  expressions[170] = BinaryenLocalSet(the_module, 4, expressions[169]);
+  expressions[171] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt32());
+  expressions[172] = BinaryenLocalSet(the_module, 5, expressions[171]);
+  expressions[173] = BinaryenLocalGet(the_module, 4, BinaryenTypeInt32());
+  expressions[174] = BinaryenLocalGet(the_module, 5, BinaryenTypeInt32());
+  expressions[175] = BinaryenUnary(the_module, 22, expressions[173]);
+  expressions[176] = BinaryenUnary(the_module, 22, expressions[174]);
+  expressions[177] = BinaryenBinary(the_module, 25, expressions[175], expressions[176]);
+  expressions[178] = BinaryenLocalSet(the_module, 10, expressions[177]);
+  expressions[179] = BinaryenLocalGet(the_module, 10, BinaryenTypeInt64());
+  expressions[180] = BinaryenUnary(the_module, 24, expressions[179]);
+  expressions[181] = BinaryenConst(the_module, BinaryenLiteralInt64(32));
+  expressions[182] = BinaryenLocalGet(the_module, 10, BinaryenTypeInt64());
+  expressions[183] = BinaryenBinary(the_module, 36, expressions[182], expressions[181]);
+  expressions[184] = BinaryenUnary(the_module, 24, expressions[183]);
+  expressions[185] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[186] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[185]);
+  expressions[187] = BinaryenConst(the_module, BinaryenLiteralInt32(128));
+  expressions[188] = BinaryenBinary(the_module, 1, expressions[186], expressions[187]);
+  expressions[189] =
+    BinaryenLocalTee(the_module, 6, expressions[188], BinaryenTypeInt32());
+  expressions[190] = BinaryenStore(the_module,
+                                   4,
+                                   0,
+                                   0,
+                                   expressions[185],
+                                   expressions[189],
+                                   BinaryenTypeInt32());
+  expressions[191] = BinaryenLocalGet(the_module, 6, BinaryenTypeInt32());
+  expressions[192] = BinaryenStore(the_module,
+                                   4,
+                                   0,
+                                   0,
+                                   expressions[191],
+                                   expressions[180],
+                                   BinaryenTypeInt32());
+  expressions[193] = BinaryenStore(the_module,
+                                   4,
+                                   4,
+                                   0,
+                                   expressions[191],
+                                   expressions[184],
+                                   BinaryenTypeInt32());
+  {
+    BinaryenExpressionRef children[] = { expressions[166], expressions[168], expressions[170], expressions[172], expressions[178], expressions[190], expressions[192], expressions[193] };
+    expressions[194] = BinaryenBlock(the_module, "bb0", children, 8, BinaryenTypeAuto());
+  }
+  relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[194]);
+  expressions[195] = BinaryenLocalGet(the_module, 6, BinaryenTypeInt32());
+  expressions[196] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[195]);
+  expressions[197] = BinaryenLocalSet(the_module, 7, expressions[196]);
+  expressions[198] = BinaryenLocalGet(the_module, 8, BinaryenTypeInt32());
+  expressions[199] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[200] = BinaryenStore(the_module,
+                                   4,
+                                   0,
+                                   0,
+                                   expressions[199],
+                                   expressions[198],
+                                   BinaryenTypeInt32());
+  expressions[201] = BinaryenLocalGet(the_module, 7, BinaryenTypeInt32());
+  expressions[202] = BinaryenReturn(the_module, expressions[201]);
+  {
+    BinaryenExpressionRef children[] = { expressions[197], expressions[200], expressions[202] };
+    expressions[203] = BinaryenBlock(the_module, "bb1", children, 3, BinaryenTypeAuto());
+  }
+  relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[203]);
+  expressions[204] = BinaryenLocalGet(the_module, 6, BinaryenTypeInt32());
+  expressions[205] = BinaryenLoad(the_module, 4, 0, 8, 0, BinaryenTypeInt32(), expressions[204]);
+  RelooperAddBranch(relooperBlocks[0], relooperBlocks[1], expressions[205], expressions[0]);
+  expressions[206] = BinaryenUnreachable(the_module);
+  relooperBlocks[2] = RelooperAddBlock(the_relooper, expressions[206]);
+  RelooperAddBranch(relooperBlocks[0], relooperBlocks[2], expressions[0], expressions[0]);
+  expressions[207] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[208] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[207]);
+  expressions[209] = BinaryenLocalSet(the_module, 8, expressions[208]);
+  relooperBlocks[3] = RelooperAddBlock(the_relooper, expressions[209]);
+  RelooperAddBranch(relooperBlocks[3], relooperBlocks[0], expressions[0], expressions[0]);
+  expressions[210] = RelooperRenderAndDispose(the_relooper, relooperBlocks[3], 9);
+  {
+    BinaryenType varTypes[] = {BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt64()};
+    BinaryenType ii_[2] = {BinaryenTypeInt32(), BinaryenTypeInt32()};
+    BinaryenType ii = BinaryenTypeCreate(ii_, 2);
+    functions[9] = BinaryenAddFunction(the_module,
+                                       "_isize_as_tinycore::Add_::add",
+                                       ii,
+                                       BinaryenTypeInt32(),
+                                       varTypes,
+                                       9,
+                                       expressions[210]);
+  }
+  BinaryenAddFunctionExport(the_module, "_isize_as_tinycore::Add_::add", "_isize_as_tinycore::Add_::add");
+  the_relooper = RelooperCreate(the_module);
+  expressions[211] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
+  expressions[212] = BinaryenLocalSet(the_module, 1, expressions[211]);
+  expressions[213] = BinaryenLocalGet(the_module, 1, BinaryenTypeInt32());
+  expressions[214] = BinaryenLocalSet(the_module, 2, expressions[213]);
+  expressions[215] = BinaryenLocalGet(the_module, 2, BinaryenTypeInt32());
+  expressions[216] = BinaryenUnary(the_module, 20, expressions[215]);
+  expressions[217] = BinaryenLocalSet(the_module, 3, expressions[216]);
+  expressions[218] = BinaryenLocalGet(the_module, 4, BinaryenTypeInt32());
+  expressions[219] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[220] = BinaryenStore(the_module,
+                                   4,
+                                   0,
+                                   0,
+                                   expressions[219],
+                                   expressions[218],
+                                   BinaryenTypeInt32());
+  expressions[221] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt32());
+  expressions[222] = BinaryenReturn(the_module, expressions[221]);
+  {
+    BinaryenExpressionRef children[] = { expressions[212], expressions[214], expressions[217], expressions[220], expressions[222] };
+    expressions[223] = BinaryenBlock(the_module, "bb0", children, 5, BinaryenTypeAuto());
+  }
+  relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[223]);
+  expressions[224] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[225] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[224]);
+  expressions[226] = BinaryenLocalSet(the_module, 4, expressions[225]);
+  relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[226]);
+  RelooperAddBranch(relooperBlocks[1], relooperBlocks[0], expressions[0], expressions[0]);
+  expressions[227] = RelooperRenderAndDispose(the_relooper, relooperBlocks[1], 5);
+  {
+    BinaryenType varTypes[] = {BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt64()};
+    functions[10] = BinaryenAddFunction(the_module,
+                                        "_bool_as_tinycore::Not_::not",
+                                        BinaryenTypeInt32(),
+                                        BinaryenTypeInt32(),
+                                        varTypes,
+                                        6,
+                                        expressions[227]);
+  }
+  BinaryenAddFunctionExport(the_module, "_bool_as_tinycore::Not_::not", "_bool_as_tinycore::Not_::not");
+  the_relooper = RelooperCreate(the_module);
+  expressions[228] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
+  expressions[229] = BinaryenLocalSet(the_module, 2, expressions[228]);
+  expressions[230] = BinaryenLocalGet(the_module, 1, BinaryenTypeInt32());
+  expressions[231] = BinaryenLocalSet(the_module, 3, expressions[230]);
+  expressions[232] = BinaryenLocalGet(the_module, 2, BinaryenTypeInt32());
+  expressions[233] = BinaryenLocalSet(the_module, 4, expressions[232]);
+  expressions[234] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt32());
+  expressions[235] = BinaryenLocalSet(the_module, 5, expressions[234]);
+  expressions[236] = BinaryenLocalGet(the_module, 4, BinaryenTypeInt32());
+  expressions[237] = BinaryenLocalGet(the_module, 5, BinaryenTypeInt32());
+  expressions[238] = BinaryenBinary(the_module, 15, expressions[236], expressions[237]);
+  expressions[239] = BinaryenLocalSet(the_module, 6, expressions[238]);
+  expressions[240] = BinaryenLocalGet(the_module, 7, BinaryenTypeInt32());
+  expressions[241] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[242] = BinaryenStore(the_module,
+                                   4,
+                                   0,
+                                   0,
+                                   expressions[241],
+                                   expressions[240],
+                                   BinaryenTypeInt32());
+  expressions[243] = BinaryenLocalGet(the_module, 6, BinaryenTypeInt32());
+  expressions[244] = BinaryenReturn(the_module, expressions[243]);
+  {
+    BinaryenExpressionRef children[] = { expressions[229], expressions[231], expressions[233], expressions[235], expressions[239], expressions[242], expressions[244] };
+    expressions[245] = BinaryenBlock(the_module, "bb0", children, 7, BinaryenTypeAuto());
+  }
+  relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[245]);
+  expressions[246] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[247] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[246]);
+  expressions[248] = BinaryenLocalSet(the_module, 7, expressions[247]);
+  relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[248]);
+  RelooperAddBranch(relooperBlocks[1], relooperBlocks[0], expressions[0], expressions[0]);
+  expressions[249] = RelooperRenderAndDispose(the_relooper, relooperBlocks[1], 8);
+  {
+    BinaryenType varTypes[] = {BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt64()};
+    BinaryenType ii_[2] = {BinaryenTypeInt32(), BinaryenTypeInt32()};
+    BinaryenType ii = BinaryenTypeCreate(ii_, 2);
+    functions[11] = BinaryenAddFunction(the_module,
+                                        "_i16_as_tinycore::PartialEq_::eq",
+                                        ii,
+                                        BinaryenTypeInt32(),
+                                        varTypes,
+                                        8,
+                                        expressions[249]);
+  }
+  BinaryenAddFunctionExport(the_module, "_i16_as_tinycore::PartialEq_::eq", "_i16_as_tinycore::PartialEq_::eq");
+  the_relooper = RelooperCreate(the_module);
+  expressions[250] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt64());
+  expressions[251] = BinaryenLocalSet(the_module, 2, expressions[250]);
+  expressions[252] = BinaryenLocalGet(the_module, 1, BinaryenTypeInt64());
+  expressions[253] = BinaryenLocalSet(the_module, 3, expressions[252]);
+  expressions[254] = BinaryenLocalGet(the_module, 2, BinaryenTypeInt64());
+  expressions[255] = BinaryenLocalSet(the_module, 4, expressions[254]);
+  expressions[256] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt64());
+  expressions[257] = BinaryenLocalSet(the_module, 5, expressions[256]);
+  expressions[258] = BinaryenLocalGet(the_module, 4, BinaryenTypeInt64());
+  expressions[259] = BinaryenLocalGet(the_module, 5, BinaryenTypeInt64());
+  expressions[260] = BinaryenBinary(the_module, 40, expressions[258], expressions[259]);
+  expressions[261] = BinaryenLocalSet(the_module, 6, expressions[260]);
+  expressions[262] = BinaryenLocalGet(the_module, 7, BinaryenTypeInt64());
+  expressions[263] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[264] = BinaryenStore(the_module,
+                                   4,
+                                   0,
+                                   0,
+                                   expressions[263],
+                                   expressions[262],
+                                   BinaryenTypeInt64());
+  expressions[265] = BinaryenLocalGet(the_module, 6, BinaryenTypeInt32());
+  expressions[266] = BinaryenReturn(the_module, expressions[265]);
+  {
+    BinaryenExpressionRef children[] = { expressions[251], expressions[253], expressions[255], expressions[257], expressions[261], expressions[264], expressions[266] };
+    expressions[267] = BinaryenBlock(the_module, "bb0", children, 7, BinaryenTypeAuto());
+  }
+  relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[267]);
+  expressions[268] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[269] = BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt64(), expressions[268]);
+  expressions[270] = BinaryenLocalSet(the_module, 7, expressions[269]);
+  relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[270]);
+  RelooperAddBranch(relooperBlocks[1], relooperBlocks[0], expressions[0], expressions[0]);
+  expressions[271] = RelooperRenderAndDispose(the_relooper, relooperBlocks[1], 8);
+  {
+    BinaryenType varTypes[] = {BinaryenTypeInt64(),
+                               BinaryenTypeInt64(),
+                               BinaryenTypeInt64(),
+                               BinaryenTypeInt64(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt64(),
+                               BinaryenTypeInt32(),
+                               BinaryenTypeInt64()};
+    BinaryenType ii_[2] = {BinaryenTypeInt64(), BinaryenTypeInt64()};
+    BinaryenType ii = BinaryenTypeCreate(ii_, 2);
+    functions[12] = BinaryenAddFunction(the_module,
+                                        "_i64_as_tinycore::PartialEq_::eq",
+                                        ii,
+                                        BinaryenTypeInt32(),
+                                        varTypes,
+                                        8,
+                                        expressions[271]);
+  }
+  BinaryenAddFunctionExport(the_module, "_i64_as_tinycore::PartialEq_::eq", "_i64_as_tinycore::PartialEq_::eq");
+  assert(BinaryenModuleValidate(the_module));
+  BinaryenModuleDispose(the_module);
+  expressions.clear();
+  functions.clear();
+  relooperBlocks.clear();
+}
diff --git a/binaryen/test/example/c-api-relooper-unreachable-if.txt b/binaryen/test/example/c-api-relooper-unreachable-if.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/c-api-relooper-unreachable-if.txt
diff --git a/binaryen/test/example/c-api-unused-mem.cpp b/binaryen/test/example/c-api-unused-mem.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/c-api-unused-mem.cpp
@@ -0,0 +1,105 @@
+// beginning a Binaryen API trace
+
+#include <cassert>
+#include <stdio.h>
+#include <math.h>
+#include <map>
+#include "binaryen-c.h"
+
+int main() {
+  std::map<size_t, BinaryenExpressionRef> expressions;
+  std::map<size_t, BinaryenFunctionRef> functions;
+  std::map<size_t, RelooperBlockRef> relooperBlocks;
+  BinaryenModuleRef the_module = NULL;
+  RelooperRef the_relooper = NULL;
+  the_module = BinaryenModuleCreate();
+  expressions[size_t(NULL)] = BinaryenExpressionRef(NULL);
+  BinaryenModuleAutoDrop(the_module);
+  {
+    const char* segments[] = { 0 };
+    int8_t segmentPassive[] = { 0 };
+    BinaryenExpressionRef segmentOffsets[] = { 0 };
+    BinaryenIndex segmentSizes[] = { 0 };
+    BinaryenSetMemory(the_module, 256, 256, "memory", segments, segmentPassive, segmentOffsets, segmentSizes, 0, 0);
+  }
+  the_relooper = RelooperCreate(the_module);
+  {
+    BinaryenExpressionRef children[] = { 0 };
+    expressions[1] = BinaryenBlock(the_module, "bb0", children, 0, BinaryenTypeAuto());
+  }
+  relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[1]);
+  expressions[2] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
+  expressions[3] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[4] = BinaryenStore(
+    the_module, 4, 0, 0, expressions[3], expressions[2], BinaryenTypeInt32());
+  expressions[5] = BinaryenReturn(the_module, expressions[0]);
+  {
+    BinaryenExpressionRef children[] = { expressions[4], expressions[5] };
+    expressions[6] = BinaryenBlock(the_module, "bb1", children, 2, BinaryenTypeAuto());
+  }
+  relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[6]);
+  RelooperAddBranch(relooperBlocks[0], relooperBlocks[1], expressions[0], expressions[0]);
+  expressions[7] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[8] =
+    BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[7]);
+  expressions[9] = BinaryenLocalSet(the_module, 0, expressions[8]);
+  relooperBlocks[2] = RelooperAddBlock(the_relooper, expressions[9]);
+  RelooperAddBranch(relooperBlocks[2], relooperBlocks[0], expressions[0], expressions[0]);
+  expressions[10] = RelooperRenderAndDispose(the_relooper, relooperBlocks[2], 1);
+  {
+    BinaryenType varTypes[] = {
+      BinaryenTypeInt32(), BinaryenTypeInt32(), BinaryenTypeInt64()};
+    functions[0] = BinaryenAddFunction(the_module,
+                                       "main",
+                                       BinaryenTypeNone(),
+                                       BinaryenTypeNone(),
+                                       varTypes,
+                                       3,
+                                       expressions[10]);
+  }
+  BinaryenAddFunctionExport(the_module, "main", "main");
+  {
+    const char* segments[] = { 0 };
+    int8_t segmentPassive[] = { 0 };
+    BinaryenExpressionRef segmentOffsets[] = { 0 };
+    BinaryenIndex segmentSizes[] = { 0 };
+    BinaryenSetMemory(the_module, 1024, 1024, NULL, segments, segmentPassive, segmentOffsets, segmentSizes, 0, 0);
+  }
+  expressions[11] = BinaryenConst(the_module, BinaryenLiteralInt32(65535));
+  expressions[12] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
+  expressions[13] = BinaryenStore(
+    the_module, 4, 0, 0, expressions[12], expressions[11], BinaryenTypeInt32());
+  {
+    BinaryenExpressionRef operands[] = { 0 };
+    expressions[14] = BinaryenCall(the_module, "main", operands, 0, BinaryenTypeNone());
+  }
+  {
+    BinaryenExpressionRef children[] = { expressions[13], expressions[14] };
+    expressions[15] = BinaryenBlock(the_module, NULL, children, 2, BinaryenTypeAuto());
+  }
+  BinaryenAddFunctionExport(the_module, "__wasm_start", "rust_entry");
+  {
+    BinaryenType varTypes[] = {BinaryenTypeNone()};
+    functions[1] = BinaryenAddFunction(the_module,
+                                       "__wasm_start",
+                                       BinaryenTypeNone(),
+                                       BinaryenTypeNone(),
+                                       varTypes,
+                                       0,
+                                       expressions[15]);
+  }
+  assert(BinaryenModuleValidate(the_module));
+  BinaryenModulePrint(the_module);
+  // check that binary read-write works
+  {
+    char buffer[1024];
+    BinaryenSetDebugInfo(1);
+    size_t size = BinaryenModuleWrite(the_module, buffer, 1024);
+    printf("%d\n", size);
+    BinaryenModuleRef copy = BinaryenModuleRead(buffer, size);
+    BinaryenModulePrint(copy);
+    BinaryenModuleDispose(copy);
+  }
+  BinaryenModuleDispose(the_module);
+  return 0;
+}
diff --git a/binaryen/test/example/c-api-unused-mem.txt b/binaryen/test/example/c-api-unused-mem.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/c-api-unused-mem.txt
@@ -0,0 +1,78 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 1024 1024)
+ (export "memory" (memory $0))
+ (export "main" (func $main))
+ (export "rust_entry" (func $__wasm_start))
+ (func $main
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i64)
+  (block $block$2$break
+   (local.set $0
+    (i32.load
+     (i32.const 0)
+    )
+   )
+   (block
+    (br $block$2$break)
+   )
+  )
+  (block
+   (block
+    (i32.store
+     (i32.const 0)
+     (local.get $0)
+    )
+    (return)
+   )
+  )
+ )
+ (func $__wasm_start
+  (i32.store
+   (i32.const 0)
+   (i32.const 65535)
+  )
+  (call $main)
+ )
+)
+151
+(module
+ (type $none_=>_none (func))
+ (memory $0 1024 1024)
+ (export "memory" (memory $0))
+ (export "main" (func $main))
+ (export "rust_entry" (func $__wasm_start))
+ (func $main
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i64)
+  (block $label$1
+   (local.set $0
+    (i32.load
+     (i32.const 0)
+    )
+   )
+   (block $label$2
+    (br $label$1)
+   )
+  )
+  (block $label$3
+   (block $label$4
+    (i32.store
+     (i32.const 0)
+     (local.get $0)
+    )
+    (return)
+   )
+   (unreachable)
+  )
+ )
+ (func $__wasm_start
+  (i32.store
+   (i32.const 0)
+   (i32.const 65535)
+  )
+  (call $main)
+ )
+)
diff --git a/binaryen/test/example/cpp-threads.cpp b/binaryen/test/example/cpp-threads.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/cpp-threads.cpp
@@ -0,0 +1,59 @@
+// test multiple uses of the threadPool
+
+#include <cassert>
+#include <iostream>
+#include <thread>
+#include <vector>
+
+#include <binaryen-c.h>
+
+int NUM_THREADS = 33;
+
+void worker() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+
+  // Create a function type for  i32 (i32, i32)
+  BinaryenType ii_[2] = {BinaryenTypeInt32(), BinaryenTypeInt32()};
+  BinaryenType ii = BinaryenTypeCreate(ii_, 2);
+
+  // Get the 0 and 1 arguments, and add them
+  BinaryenExpressionRef x = BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+                        y = BinaryenLocalGet(module, 1, BinaryenTypeInt32());
+  BinaryenExpressionRef add = BinaryenBinary(module, BinaryenAddInt32(), x, y);
+  BinaryenExpressionRef ret = BinaryenReturn(module, add);
+
+  // Create the add function
+  // Note: no additional local variables
+  // Note: no basic blocks here, we are an AST. The function body is just an expression node.
+  BinaryenFunctionRef adder =
+    BinaryenAddFunction(module, "adder", ii, BinaryenTypeInt32(), NULL, 0, ret);
+
+  // validate it
+  assert(BinaryenModuleValidate(module));
+
+  // optimize it
+  BinaryenModuleOptimize(module);
+  assert(BinaryenModuleValidate(module));
+
+  // Clean up the module, which owns all the objects we created above
+  BinaryenModuleDispose(module);
+}
+
+int main() {
+  std::vector<std::thread> threads;
+
+  std::cout << "create threads...\n";
+  for (int i = 0; i < NUM_THREADS; i++) {
+    threads.emplace_back(worker);
+  }
+  std::cout << "threads running in parallel...\n";
+
+  std::cout << "waiting for threads to join...\n";
+  for (auto& thread : threads) {
+    thread.join();
+  }
+
+  std::cout << "all done.\n";
+
+  return 0;
+}
diff --git a/binaryen/test/example/cpp-threads.txt b/binaryen/test/example/cpp-threads.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/cpp-threads.txt
@@ -0,0 +1,4 @@
+create threads...
+threads running in parallel...
+waiting for threads to join...
+all done.
diff --git a/binaryen/test/example/cpp-unit.cpp b/binaryen/test/example/cpp-unit.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/cpp-unit.cpp
@@ -0,0 +1,556 @@
+// test multiple uses of the threadPool
+
+#include <iostream>
+
+#include <ir/bits.h>
+#include <ir/cost.h>
+#include <wasm.h>
+
+using namespace wasm;
+using namespace Bits;
+
+#define RESET     "\x1b[0m"
+
+#define FG_BLACK  "\x1b[30m"
+#define FG_RED    "\x1b[31m"
+#define FG_GREEN  "\x1b[32m"
+#define FG_YELLOW "\x1b[33m"
+
+#define BG_BLACK  "\x1b[40m"
+#define BG_RED    "\x1b[41m"
+
+static int failsCount = 0;
+
+template<typename T, typename U>
+void assert_equal_(T a, U b, int line, const char* file) {
+  if (a != b) {
+    std::cerr << '\n'
+              << BG_RED FG_BLACK << "  ASSERTION ERROR    "
+              << ++failsCount    << "    "
+              << RESET FG_RED    << "\n"
+              << FG_RED          << "   Actual:   " << a << '\n'
+              << FG_GREEN        << "   Expected: " << b << "\n\n"
+              << FG_YELLOW       << "   Line: "     << line << '\n'
+              << FG_YELLOW       << "   File: "     << file << '\n'
+              << RESET           << std::endl;
+
+    std::cout << "actual: "     << a
+              << ", expected: " << b
+              << ", line "      << line
+              << ", file "      << file
+              << std::endl;
+  }
+}
+
+#define assert_equal(a, b) assert_equal_((a), (b), __LINE__, __FILE__)
+
+void test_bits() {
+  Const c0, c1;
+  Binary b;
+
+  b.left = &c0;
+  b.right = &c1;
+
+  // --- //
+  // i32 //
+  // --- //
+
+  c0.type = Type::i32;
+  c1.type = Type::i32;
+  b.type  = Type::i32;
+
+  c0.value = Literal(int32_t(0));
+  assert_equal(getMaxBits(&c0), 0);
+  c0.value = Literal(int32_t(1));
+  assert_equal(getMaxBits(&c0), 1);
+  c0.value = Literal(int32_t(2));
+  assert_equal(getMaxBits(&c0), 2);
+  c0.value = Literal(int32_t(0x80000));
+  assert_equal(getMaxBits(&c0), 20);
+  c0.value = Literal(int32_t(-1));
+  assert_equal(getMaxBits(&c0), 32);
+
+  b.op = AddInt32;
+  c0.value = Literal(int32_t(0xFFFF));
+  c1.value = Literal(int32_t(0x11));
+  assert_equal(getMaxBits(&b), 17);
+  c0.value = Literal(int32_t(-1));
+  c1.value = Literal(int32_t(2));
+  assert_equal(getMaxBits(&b), 32);
+  c0.value = Literal(int32_t(-1));
+  c1.value = Literal(int32_t(-1));
+  assert_equal(getMaxBits(&b), 32);
+
+  b.op = SubInt32;
+  c0.value = Literal(int32_t(0xFFFF));
+  c1.value = Literal(int32_t(0x11));
+  assert_equal(getMaxBits(&b), 32);
+  c0.value = Literal(int32_t(-1));
+  c1.value = Literal(int32_t(2));
+  assert_equal(getMaxBits(&b), 32);
+  c0.value = Literal(int32_t(2));
+  c1.value = Literal(int32_t(-1));
+  assert_equal(getMaxBits(&b), 32);
+  c0.value = Literal(int32_t(0));
+  c1.value = Literal(int32_t(1));
+  assert_equal(getMaxBits(&b), 32);
+  c0.value = Literal(int32_t(0x7FFFFFF0));
+  c1.value = Literal(int32_t(0x7FFFFFFF));
+  assert_equal(getMaxBits(&b), 32);
+  c0.value = Literal(int32_t(1));
+  c1.value = Literal(int32_t(1));
+  assert_equal(getMaxBits(&b), 32);
+  c0.value = Literal(int32_t(0));
+  c1.value = Literal(int32_t(0x7FFFFFFF));
+  assert_equal(getMaxBits(&b), 32);
+
+  b.op = MulInt32;
+  c0.value = Literal(int32_t(0xFFFF));
+  c1.value = Literal(int32_t(0x11));
+  assert_equal(getMaxBits(&b), 21);
+  c0.value = Literal(int32_t(0));
+  c1.value = Literal(int32_t(1));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(int32_t(1));
+  c1.value = Literal(int32_t(0));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(int32_t(3));
+  c1.value = Literal(int32_t(3));
+  assert_equal(getMaxBits(&b), 4);
+  c0.value = Literal(int32_t(2));
+  c1.value = Literal(int32_t(-2));
+  assert_equal(getMaxBits(&b), 32);
+
+  b.op = DivSInt32;
+  c0.value = Literal(int32_t(0));
+  c1.value = Literal(int32_t(0xF));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(int32_t( 1));
+  c1.value = Literal(int32_t( 2));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(int32_t(0xFF));
+  c1.value = Literal(int32_t(0xFF));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(int32_t(-1));
+  c1.value = Literal(int32_t( 1));
+  assert_equal(getMaxBits(&b), 32);
+  c0.value = Literal(int32_t(-1));
+  c1.value = Literal(int32_t( 2));
+  assert_equal(getMaxBits(&b), 32);
+  c0.value = Literal(int32_t(0x7FFFFFFF));
+  c1.value = Literal(int32_t(3));
+  assert_equal(getMaxBits(&b), 30);
+  c0.value = Literal(int32_t(0x0000FFFF));
+  c1.value = Literal(int32_t(0xFF));
+  assert_equal(getMaxBits(&b), 9);
+  c0.value = Literal(int32_t(0x00001000));
+  c1.value = Literal(int32_t(0x00000FFF));
+  assert_equal(getMaxBits(&b), 2);
+  c0.value = Literal(int32_t(0x80000000));
+  c1.value = Literal(int32_t(-1));
+  assert_equal(getMaxBits(&b), 32);
+  c0.value = Literal(int32_t(2));
+  c1.value = Literal(int32_t(-2));
+  assert_equal(getMaxBits(&b), 32);
+
+
+  b.op = DivUInt32;
+  c0.value = Literal(uint32_t(0));
+  c1.value = Literal(uint32_t(0xF));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(uint32_t( 1));
+  c1.value = Literal(uint32_t( 2));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(uint32_t(0xFF));
+  c1.value = Literal(uint32_t(0xFF));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(uint32_t(-1));
+  c1.value = Literal(uint32_t( 1));
+  assert_equal(getMaxBits(&b), 32);
+  c0.value = Literal(uint32_t(-1));
+  c1.value = Literal(uint32_t( 2));
+  assert_equal(getMaxBits(&b), 31);
+  c0.value = Literal(uint32_t(0x7FFFFFFF));
+  c1.value = Literal(uint32_t(3));
+  assert_equal(getMaxBits(&b), 30);
+  c0.value = Literal(int32_t(0x0000FFFF));
+  c1.value = Literal(int32_t(0xFF));
+  assert_equal(getMaxBits(&b), 9);
+  c0.value = Literal(int32_t(0x00001000));
+  c1.value = Literal(int32_t(0x00000FFF));
+  assert_equal(getMaxBits(&b), 2);
+  c0.value = Literal(uint32_t(0x80000000));
+  c1.value = Literal(uint32_t(-1));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(uint32_t(2));
+  c1.value = Literal(uint32_t(-2));
+  assert_equal(getMaxBits(&b), 0);
+
+  b.op = RemSInt32;
+  c0.value = Literal(int32_t(0));
+  c1.value = Literal(int32_t(0xF));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(int32_t(0));
+  c1.value = Literal(int32_t(-1));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(int32_t( 1));
+  c1.value = Literal(int32_t( 2));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(int32_t(-1));
+  c1.value = Literal(int32_t( 2));
+  assert_equal(getMaxBits(&b), 32);
+  c0.value = Literal(int32_t(3));
+  c1.value = Literal(int32_t(-1));
+  assert_equal(getMaxBits(&b), 2);
+  c0.value = Literal(int32_t(0x7FFFFFFF));
+  c1.value = Literal(int32_t(0x7FFFFFFF));
+  assert_equal(getMaxBits(&b), 31);
+
+  b.op = RemUInt32;
+  c0.value = Literal(uint32_t(0));
+  c1.value = Literal(uint32_t(0xF));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(uint32_t(0));
+  c1.value = Literal(uint32_t(-1));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(uint32_t( 1));
+  c1.value = Literal(uint32_t( 2));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(uint32_t(-1));
+  c1.value = Literal(uint32_t( 2));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(uint32_t(3));
+  c1.value = Literal(uint32_t(-1));
+  assert_equal(getMaxBits(&b), 2);
+  c0.value = Literal(uint32_t(0x7FFFFFFF));
+  c1.value = Literal(uint32_t(0x7FFFFFFF));
+  assert_equal(getMaxBits(&b), 31);
+
+  b.op = AndInt32;
+  c0.value = Literal(int32_t(0));
+  c1.value = Literal(int32_t(0xF));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(int32_t(0xF));
+  c1.value = Literal(int32_t(0));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(int32_t(3));
+  c1.value = Literal(int32_t(3));
+  assert_equal(getMaxBits(&b), 2);
+  c0.value = Literal(int32_t(-1));
+  c1.value = Literal(int32_t(3));
+  assert_equal(getMaxBits(&b), 2);
+  c0.value = Literal(int32_t(3));
+  c1.value = Literal(int32_t(-1));
+  assert_equal(getMaxBits(&b), 2);
+
+  b.op = OrInt32;
+  c0.value = Literal(int32_t(0));
+  c1.value = Literal(int32_t(0xF));
+  assert_equal(getMaxBits(&b), 4);
+  c0.value = Literal(int32_t(0xF));
+  c1.value = Literal(int32_t(0));
+  assert_equal(getMaxBits(&b), 4);
+  c0.value = Literal(int32_t(3));
+  c1.value = Literal(int32_t(3));
+  assert_equal(getMaxBits(&b), 2);
+  c0.value = Literal(int32_t(-1));
+  c1.value = Literal(int32_t(3));
+  assert_equal(getMaxBits(&b), 32);
+  c0.value = Literal(int32_t(3));
+  c1.value = Literal(int32_t(-1));
+  assert_equal(getMaxBits(&b), 32);
+
+  b.op = XorInt32;
+  c0.value = Literal(int32_t(0));
+  c1.value = Literal(int32_t(0xF));
+  assert_equal(getMaxBits(&b), 4);
+  c0.value = Literal(int32_t(0xF));
+  c1.value = Literal(int32_t(0));
+  assert_equal(getMaxBits(&b), 4);
+  c0.value = Literal(int32_t(3));
+  c1.value = Literal(int32_t(3));
+  assert_equal(getMaxBits(&b), 2);
+  c0.value = Literal(int32_t(-1));
+  c1.value = Literal(int32_t(3));
+  assert_equal(getMaxBits(&b), 32);
+  c0.value = Literal(int32_t(3));
+  c1.value = Literal(int32_t(-1));
+  assert_equal(getMaxBits(&b), 32);
+
+  // --- //
+  // i64 //
+  // --- //
+
+  c0.type = Type::i64;
+  c1.type = Type::i64;
+  b.type  = Type::i64;
+
+  c0.value = Literal(int64_t(0));
+  assert_equal(getMaxBits(&c0), 0);
+  c0.value = Literal(int64_t(1));
+  assert_equal(getMaxBits(&c0), 1);
+  c0.value = Literal(int64_t(2));
+  assert_equal(getMaxBits(&c0), 2);
+  c0.value = Literal(int64_t(0x80000));
+  assert_equal(getMaxBits(&c0), 20);
+  c0.value = Literal(int64_t(-1));
+  assert_equal(getMaxBits(&c0), 64);
+
+  b.op = AddInt64;
+  c0.value = Literal(int64_t(0xFFFF));
+  c1.value = Literal(int64_t(0x11));
+  assert_equal(getMaxBits(&b), 17);
+  c0.value = Literal(int64_t(-1));
+  c1.value = Literal(int64_t(2));
+  assert_equal(getMaxBits(&b), 64);
+  c0.value = Literal(int64_t(-1));
+  c1.value = Literal(int64_t(-1));
+  assert_equal(getMaxBits(&b), 64);
+
+  b.op = SubInt64;
+  c0.value = Literal(int64_t(0xFFFF));
+  c1.value = Literal(int64_t(0x11));
+  assert_equal(getMaxBits(&b), 64);
+  c0.value = Literal(int64_t(-1));
+  c1.value = Literal(int64_t(2));
+  assert_equal(getMaxBits(&b), 64);
+  c0.value = Literal(int64_t(2));
+  c1.value = Literal(int64_t(-1));
+  assert_equal(getMaxBits(&b), 64);
+  c0.value = Literal(int64_t(0));
+  c1.value = Literal(int64_t(1));
+  assert_equal(getMaxBits(&b), 64);
+  c0.value = Literal(int64_t(0x7FFFFFFFFFFFFFF0));
+  c1.value = Literal(int64_t(0x7FFFFFFFFFFFFFFF));
+  assert_equal(getMaxBits(&b), 64);
+  c0.value = Literal(int64_t(1));
+  c1.value = Literal(int64_t(1));
+  assert_equal(getMaxBits(&b), 64);
+  c0.value = Literal(int64_t(0));
+  c1.value = Literal(int64_t(0x7FFFFFFFFFFFFFFF));
+  assert_equal(getMaxBits(&b), 64);
+
+  b.op = MulInt64;
+  c0.value = Literal(int64_t(0xFFFF));
+  c1.value = Literal(int64_t(0x11));
+  assert_equal(getMaxBits(&b), 21);
+  c0.value = Literal(int64_t(0));
+  c1.value = Literal(int64_t(1));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(int64_t(1));
+  c1.value = Literal(int64_t(0));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(int64_t(3));
+  c1.value = Literal(int64_t(3));
+  assert_equal(getMaxBits(&b), 4);
+  c0.value = Literal(int64_t(2));
+  c1.value = Literal(int64_t(-2));
+  assert_equal(getMaxBits(&b), 64);
+
+  b.op = DivSInt64;
+  c0.value = Literal(int64_t(0));
+  c1.value = Literal(int64_t(0xF));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(int64_t( 1));
+  c1.value = Literal(int64_t( 2));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(int64_t(0xFF));
+  c1.value = Literal(int64_t(0xFF));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(int64_t(-1));
+  c1.value = Literal(int64_t( 1));
+  assert_equal(getMaxBits(&b), 64);
+  c0.value = Literal(int64_t(-1));
+  c1.value = Literal(int64_t( 2));
+  assert_equal(getMaxBits(&b), 64);
+  c0.value = Literal(int64_t(0x7FFFFFFFFFFFFFFF));
+  c1.value = Literal(int64_t(3));
+  assert_equal(getMaxBits(&b), 62);
+  c0.value = Literal(int64_t(0x8000000000000000));
+  c1.value = Literal(int64_t(-1));
+  assert_equal(getMaxBits(&b), 64);
+  c0.value = Literal(int64_t(2));
+  c1.value = Literal(int64_t(-2));
+  assert_equal(getMaxBits(&b), 64);
+
+  b.op = DivUInt64;
+  c0.value = Literal(uint64_t(0));
+  c1.value = Literal(uint64_t(0xF));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(uint64_t( 1));
+  c1.value = Literal(uint64_t( 2));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(uint64_t(0xFF));
+  c1.value = Literal(uint64_t(0xFF));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(uint64_t(-1));
+  c1.value = Literal(uint64_t( 1));
+  assert_equal(getMaxBits(&b), 64);
+  c0.value = Literal(uint64_t(-1));
+  c1.value = Literal(uint64_t( 2));
+  assert_equal(getMaxBits(&b), 63);
+  c0.value = Literal(uint64_t(0x7FFFFFFFFFFFFFFF));
+  c1.value = Literal(uint64_t(3));
+  assert_equal(getMaxBits(&b), 62);
+  c0.value = Literal(uint64_t(0x8000000000000000));
+  c1.value = Literal(uint64_t(-1));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(uint64_t(2));
+  c1.value = Literal(uint64_t(-2));
+  assert_equal(getMaxBits(&b), 0);
+
+  b.op = RemSInt64;
+  c0.value = Literal(int64_t(0));
+  c1.value = Literal(int64_t(0xF));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(int64_t(0));
+  c1.value = Literal(int64_t(-1));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(int64_t( 1));
+  c1.value = Literal(int64_t( 2));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(int64_t(-1));
+  c1.value = Literal(int64_t( 2));
+  assert_equal(getMaxBits(&b), 64);
+  c0.value = Literal(int64_t(3));
+  c1.value = Literal(int64_t(-1));
+  assert_equal(getMaxBits(&b), 2);
+  c0.value = Literal(int64_t(0x7FFFFFFFFFFFFFFF));
+  c1.value = Literal(int64_t(0x7FFFFFFFFFFFFFFF));
+  assert_equal(getMaxBits(&b), 63);
+
+  b.op = RemUInt64;
+  c0.value = Literal(uint64_t(0));
+  c1.value = Literal(uint64_t(0xF));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(uint64_t(0));
+  c1.value = Literal(uint64_t(-1));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(uint64_t( 1));
+  c1.value = Literal(uint64_t( 2));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(uint64_t(-1));
+  c1.value = Literal(uint64_t( 2));
+  assert_equal(getMaxBits(&b), 1);
+  c0.value = Literal(uint64_t(3));
+  c1.value = Literal(uint64_t(-1));
+  assert_equal(getMaxBits(&b), 2);
+  c0.value = Literal(uint64_t(0x7FFFFFFFFFFFFFFF));
+  c1.value = Literal(uint64_t(0x7FFFFFFFFFFFFFFF));
+  assert_equal(getMaxBits(&b), 63);
+
+  b.op = AndInt64;
+  c0.value = Literal(int64_t(0));
+  c1.value = Literal(int64_t(0xF));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(int64_t(0xF));
+  c1.value = Literal(int64_t(0));
+  assert_equal(getMaxBits(&b), 0);
+  c0.value = Literal(int64_t(3));
+  c1.value = Literal(int64_t(3));
+  assert_equal(getMaxBits(&b), 2);
+  c0.value = Literal(int64_t(-1));
+  c1.value = Literal(int64_t(3));
+  assert_equal(getMaxBits(&b), 2);
+  c0.value = Literal(int64_t(3));
+  c1.value = Literal(int64_t(-1));
+  assert_equal(getMaxBits(&b), 2);
+
+  b.op = OrInt64;
+  c0.value = Literal(int64_t(0));
+  c1.value = Literal(int64_t(0xF));
+  assert_equal(getMaxBits(&b), 4);
+  c0.value = Literal(int64_t(0xF));
+  c1.value = Literal(int64_t(0));
+  assert_equal(getMaxBits(&b), 4);
+  c0.value = Literal(int64_t(3));
+  c1.value = Literal(int64_t(3));
+  assert_equal(getMaxBits(&b), 2);
+  c0.value = Literal(int64_t(-1));
+  c1.value = Literal(int64_t(3));
+  assert_equal(getMaxBits(&b), 64);
+  c0.value = Literal(int64_t(3));
+  c1.value = Literal(int64_t(-1));
+  assert_equal(getMaxBits(&b), 64);
+
+  b.op = XorInt64;
+  c0.value = Literal(int64_t(0));
+  c1.value = Literal(int64_t(0xF));
+  assert_equal(getMaxBits(&b), 4);
+  c0.value = Literal(int64_t(0xF));
+  c1.value = Literal(int64_t(0));
+  assert_equal(getMaxBits(&b), 4);
+  c0.value = Literal(int64_t(3));
+  c1.value = Literal(int64_t(3));
+  assert_equal(getMaxBits(&b), 2);
+  c0.value = Literal(int64_t(-1));
+  c1.value = Literal(int64_t(3));
+  assert_equal(getMaxBits(&b), 64);
+  c0.value = Literal(int64_t(3));
+  c1.value = Literal(int64_t(-1));
+  assert_equal(getMaxBits(&b), 64);
+
+  Unary u;
+  c0.type = Type::i32;
+  u.value = &c0;
+
+  u.type = Type::i64;
+
+  u.op = ExtendUInt32;
+  c0.value = Literal(int32_t(0));
+  assert_equal(getMaxBits(&u), 0);
+  c0.value = Literal(int32_t(1));
+  assert_equal(getMaxBits(&u), 1);
+  c0.value = Literal(int32_t(0xF));
+  assert_equal(getMaxBits(&u), 4);
+  c0.value = Literal(int32_t(-1));
+  assert_equal(getMaxBits(&u), 32);
+
+  u.op = ExtendSInt32;
+  c0.value = Literal(int32_t(0));
+  assert_equal(getMaxBits(&u), 0);
+  c0.value = Literal(int32_t(1));
+  assert_equal(getMaxBits(&u), 1);
+  c0.value = Literal(int32_t(0xF));
+  assert_equal(getMaxBits(&u), 4);
+  c0.value = Literal(int32_t(0x7FFFFFFF));
+  assert_equal(getMaxBits(&u), 31);
+  c0.value = Literal(int32_t(0x80000000));
+  assert_equal(getMaxBits(&u), 64);
+  c0.value = Literal(int32_t(-1));
+  assert_equal(getMaxBits(&u), 64);
+
+  u.type = Type::i32;
+  c0.type = Type::i64;
+
+  u.op = WrapInt64;
+  c0.value = Literal(int64_t(0));
+  assert_equal(getMaxBits(&u), 0);
+  c0.value = Literal(int64_t(0x7FFFFFFF));
+  assert_equal(getMaxBits(&u), 31);
+  c0.value = Literal(int64_t(0xFFFFFFFF));
+  assert_equal(getMaxBits(&u), 32);
+  c0.value = Literal(int64_t(0xFFFFFFFFFF));
+  assert_equal(getMaxBits(&u), 32);
+  c0.value = Literal(int64_t(-1));
+  assert_equal(getMaxBits(&u), 32);
+
+}
+
+void test_cost() {
+  // Some optimizations assume that the cost of a get is zero, e.g. local-cse.
+  LocalGet get;
+  assert_equal(CostAnalyzer(&get).cost, 0);
+}
+
+int main() {
+  test_bits();
+  test_cost();
+
+  if (failsCount > 0) {
+    abort();
+  } else {
+    std::cout << "Success" << std::endl;
+  }
+  return 0;
+}
diff --git a/binaryen/test/example/cpp-unit.txt b/binaryen/test/example/cpp-unit.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/cpp-unit.txt
@@ -0,0 +1,1 @@
+Success
diff --git a/binaryen/test/example/match.cpp b/binaryen/test/example/match.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/match.cpp
@@ -0,0 +1,499 @@
+#include <cassert>
+#include <iostream>
+
+#include "literal.h"
+#include "wasm-builder.h"
+#include <ir/match.h>
+
+using namespace wasm;
+using namespace wasm::Match;
+
+Module module;
+Builder builder(module);
+
+void test_internal_any() {
+  std::cout << "Testing Internal::Any\n";
+
+  assert(Internal::Any<int32_t>(nullptr).matches(0));
+  assert(Internal::Any<int32_t>(nullptr).matches(1));
+  assert(Internal::Any<int32_t>(nullptr).matches(-1));
+  assert(Internal::Any<int32_t>(nullptr).matches(42LL));
+  assert(Internal::Any<int32_t>(nullptr).matches(4.2f));
+
+  assert(Internal::Any<int64_t>(nullptr).matches(0));
+  assert(Internal::Any<int64_t>(nullptr).matches(1));
+  assert(Internal::Any<int64_t>(nullptr).matches(-1));
+  assert(Internal::Any<int64_t>(nullptr).matches(42LL));
+  assert(Internal::Any<int64_t>(nullptr).matches(4.2f));
+
+  assert(Internal::Any<float>(nullptr).matches(0));
+  assert(Internal::Any<float>(nullptr).matches(1));
+  assert(Internal::Any<float>(nullptr).matches(-1));
+  assert(Internal::Any<float>(nullptr).matches(42LL));
+  assert(Internal::Any<float>(nullptr).matches(4.2f));
+
+  assert(Internal::Any<double>(nullptr).matches(0));
+  assert(Internal::Any<double>(nullptr).matches(1));
+  assert(Internal::Any<double>(nullptr).matches(-1));
+  assert(Internal::Any<double>(nullptr).matches(42LL));
+  assert(Internal::Any<double>(nullptr).matches(4.2f));
+
+  // Working as intended: cannot convert `const char [6]' to double
+  // assert(Internal::Any<double>(nullptr).matches("hello"));
+
+  {
+    int32_t val = 0xffffffff;
+    assert(Internal::Any<int32_t>(&val).matches(0));
+    assert(val == 0);
+    assert(Internal::Any<int32_t>(&val).matches(1));
+    assert(val == 1);
+    assert(Internal::Any<int32_t>(&val).matches(-1));
+    assert(val == -1);
+    assert(Internal::Any<int32_t>(&val).matches(42LL));
+    assert(val == 42);
+    assert(Internal::Any<int32_t>(&val).matches(4.2f));
+    assert(val == 4);
+  }
+
+  {
+    Expression* expr = nullptr;
+    Nop* nop = nullptr;
+
+    Expression* builtExpr = builder.makeNop();
+    Nop* builtNop = builder.makeNop();
+    AtomicFence* builtFence = builder.makeAtomicFence();
+
+    assert(Internal::Any(&expr).matches(builtExpr));
+    assert(expr == builtExpr);
+
+    assert(Internal::Any(&expr).matches(builtNop));
+    assert(expr == builtNop);
+
+    assert(Internal::Any(&expr).matches(builtFence));
+    assert(expr == builtFence);
+
+    assert(Internal::Any(&nop).matches(builtExpr));
+    assert(nop == builtExpr);
+
+    assert(Internal::Any(&nop).matches(builtNop));
+    assert(nop == builtNop);
+
+    // Does NOT match sibling expression types. Bound variable unchanged.
+    assert(!Internal::Any(&nop).matches(builtFence));
+    assert(nop == builtNop);
+
+    // Working as intended: invalid conversion from Expression** to Nop**
+    // assert(Internal::Any<Nop*>(&expr).matches(builtExpr));
+  }
+}
+
+void test_internal_exact() {
+  std::cout << "Testing Internal::Exact\n";
+
+  assert(Internal::Exact<int32_t>(nullptr, 0).matches(0));
+  assert(Internal::Exact<int32_t>(nullptr, 1).matches(1));
+  assert(Internal::Exact<int32_t>(nullptr, -1).matches(-1));
+  assert(Internal::Exact<int32_t>(nullptr, 42).matches(42LL));
+  assert(Internal::Exact<int32_t>(nullptr, 4).matches(4.2f));
+
+  assert(!Internal::Exact<int32_t>(nullptr, 1).matches(0));
+  assert(!Internal::Exact<int32_t>(nullptr, -1).matches(1));
+  assert(!Internal::Exact<int32_t>(nullptr, 42).matches(-1));
+  assert(!Internal::Exact<int32_t>(nullptr, 4).matches(42LL));
+  assert(!Internal::Exact<int32_t>(nullptr, 0).matches(4.2f));
+
+  {
+    Expression* expr = nullptr;
+    Nop* nop = nullptr;
+
+    Nop* builtNop = builder.makeNop();
+    Expression* builtExpr = builtNop;
+
+    assert(!Internal::Exact(&expr, expr).matches(builtExpr));
+    assert(Internal::Exact(&expr, builtExpr).matches(builtExpr));
+    assert(expr == builtExpr);
+
+    assert(!Internal::Exact(&nop, nop).matches(builtNop));
+    assert(Internal::Exact(&nop, builtNop).matches(builtNop));
+    assert(nop == builtNop);
+    nop = nullptr;
+    assert(Internal::Exact(&nop, builtNop).matches(builtExpr));
+    assert(nop == builtNop);
+  }
+}
+
+void test_internal_literal() {
+  std::cout << "Testing Internal::{I32,I64,Int,F32,F64,Float}Lit\n";
+
+  Literal i32Zero(int32_t(0));
+  Literal i32One(int32_t(1));
+  Literal f32Zero(float(0));
+  Literal f32One(float(1));
+  Literal i64Zero(int64_t(0));
+  Literal i64One(int64_t(1));
+  Literal f64Zero(double(0));
+  Literal f64One(double(1));
+
+  auto anyi32 = Internal::I32Lit(nullptr, Internal::Any<int32_t>(nullptr));
+  assert(anyi32.matches(i32Zero));
+  assert(anyi32.matches(i32One));
+  assert(!anyi32.matches(f32Zero));
+  assert(!anyi32.matches(f32One));
+  assert(!anyi32.matches(i64Zero));
+  assert(!anyi32.matches(i64One));
+  assert(!anyi32.matches(f64Zero));
+  assert(!anyi32.matches(f64One));
+
+  auto onei32 = Internal::I32Lit(nullptr, Internal::Exact<int32_t>(nullptr, 1));
+  assert(!onei32.matches(i32Zero));
+  assert(onei32.matches(i32One));
+  assert(!onei32.matches(f32Zero));
+  assert(!onei32.matches(f32One));
+  assert(!onei32.matches(i64Zero));
+  assert(!onei32.matches(i64One));
+  assert(!onei32.matches(f64Zero));
+  assert(!onei32.matches(f64One));
+
+  auto anyi64 = Internal::I64Lit(nullptr, Internal::Any<int64_t>(nullptr));
+  assert(!anyi64.matches(i32Zero));
+  assert(!anyi64.matches(i32One));
+  assert(!anyi64.matches(f32Zero));
+  assert(!anyi64.matches(f32One));
+  assert(anyi64.matches(i64Zero));
+  assert(anyi64.matches(i64One));
+  assert(!anyi64.matches(f64Zero));
+  assert(!anyi64.matches(f64One));
+
+  auto onei64 = Internal::I64Lit(nullptr, Internal::Exact<int64_t>(nullptr, 1));
+  assert(!onei64.matches(i32Zero));
+  assert(!onei64.matches(i32One));
+  assert(!onei64.matches(f32Zero));
+  assert(!onei64.matches(f32One));
+  assert(!onei64.matches(i64Zero));
+  assert(onei64.matches(i64One));
+  assert(!onei64.matches(f64Zero));
+  assert(!onei64.matches(f64One));
+
+  auto anyint = Internal::IntLit(nullptr, Internal::Any<int64_t>(nullptr));
+  assert(anyint.matches(i32Zero));
+  assert(anyint.matches(i32One));
+  assert(!anyint.matches(f32Zero));
+  assert(!anyint.matches(f32One));
+  assert(anyint.matches(i64Zero));
+  assert(anyint.matches(i64One));
+  assert(!anyint.matches(f64Zero));
+  assert(!anyint.matches(f64One));
+
+  auto oneint = Internal::IntLit(nullptr, Internal::Exact<int64_t>(nullptr, 1));
+  assert(!oneint.matches(i32Zero));
+  assert(oneint.matches(i32One));
+  assert(!oneint.matches(f32Zero));
+  assert(!oneint.matches(f32One));
+  assert(!oneint.matches(i64Zero));
+  assert(oneint.matches(i64One));
+  assert(!oneint.matches(f64Zero));
+  assert(!oneint.matches(f64One));
+
+  auto anyf32 = Internal::F32Lit(nullptr, Internal::Any<float>(nullptr));
+  assert(!anyf32.matches(i32Zero));
+  assert(!anyf32.matches(i32One));
+  assert(anyf32.matches(f32Zero));
+  assert(anyf32.matches(f32One));
+  assert(!anyf32.matches(i64Zero));
+  assert(!anyf32.matches(i64One));
+  assert(!anyf32.matches(f64Zero));
+  assert(!anyf32.matches(f64One));
+
+  auto onef32 = Internal::F32Lit(nullptr, Internal::Exact<float>(nullptr, 1));
+  assert(!onef32.matches(i32Zero));
+  assert(!onef32.matches(i32One));
+  assert(!onef32.matches(f32Zero));
+  assert(onef32.matches(f32One));
+  assert(!onef32.matches(i64Zero));
+  assert(!onef32.matches(i64One));
+  assert(!onef32.matches(f64Zero));
+  assert(!onef32.matches(f64One));
+
+  auto anyf64 = Internal::F64Lit(nullptr, Internal::Any<double>(nullptr));
+  assert(!anyf64.matches(i32Zero));
+  assert(!anyf64.matches(i32One));
+  assert(!anyf64.matches(f32Zero));
+  assert(!anyf64.matches(f32One));
+  assert(!anyf64.matches(i64Zero));
+  assert(!anyf64.matches(i64One));
+  assert(anyf64.matches(f64Zero));
+  assert(anyf64.matches(f64One));
+
+  auto onef64 = Internal::F64Lit(nullptr, Internal::Exact<double>(nullptr, 1));
+  assert(!onef64.matches(i32Zero));
+  assert(!onef64.matches(i32One));
+  assert(!onef64.matches(f32Zero));
+  assert(!onef64.matches(f32One));
+  assert(!onef64.matches(i64Zero));
+  assert(!onef64.matches(i64One));
+  assert(!onef64.matches(f64Zero));
+  assert(onef64.matches(f64One));
+
+  auto anyfp = Internal::FloatLit(nullptr, Internal::Any<double>(nullptr));
+  assert(!anyfp.matches(i32Zero));
+  assert(!anyfp.matches(i32One));
+  assert(anyfp.matches(f32Zero));
+  assert(anyfp.matches(f32One));
+  assert(!anyfp.matches(i64Zero));
+  assert(!anyfp.matches(i64One));
+  assert(anyfp.matches(f64Zero));
+  assert(anyfp.matches(f64One));
+
+  auto onefp = Internal::FloatLit(nullptr, Internal::Exact<double>(nullptr, 1));
+  assert(!onefp.matches(i32Zero));
+  assert(!onefp.matches(i32One));
+  assert(!onefp.matches(f32Zero));
+  assert(onefp.matches(f32One));
+  assert(!onefp.matches(i64Zero));
+  assert(!onefp.matches(i64One));
+  assert(!onefp.matches(f64Zero));
+  assert(onefp.matches(f64One));
+
+  auto number = Internal::NumberLit(nullptr, 1);
+  assert(!number.matches(i32Zero));
+  assert(number.matches(i32One));
+  assert(!number.matches(f32Zero));
+  assert(number.matches(f32One));
+  assert(!number.matches(i64Zero));
+  assert(number.matches(i64One));
+  assert(!number.matches(f64Zero));
+  assert(number.matches(f64One));
+
+  int64_t x = 0;
+  Literal xLit;
+  Literal imatched(int32_t(42));
+  assert(Internal::IntLit(&xLit, Internal::Any(&x)).matches(imatched));
+  assert(xLit == imatched);
+  assert(x == 42);
+
+  double f = 0;
+  Literal fLit;
+  Literal fmatched(double(42));
+  assert(Internal::FloatLit(&fLit, Internal::Any(&f)).matches(fmatched));
+  assert(fLit == fmatched);
+  assert(f == 42.0);
+
+  Literal numLit;
+  Literal numMatched(1.0f);
+  assert(Internal::NumberLit(&numLit, 1).matches(numMatched));
+  assert(numLit == numMatched);
+}
+
+void test_internal_const() {
+  std::cout << "Testing Internal::ConstantMatcher\n";
+
+  Const* c = builder.makeConst(Literal(int32_t(42)));
+  Expression* constExpr = builder.makeConst(Literal(int32_t(43)));
+  Expression* nop = builder.makeNop();
+
+  Const* extractedConst = nullptr;
+  Literal extractedLit;
+  int32_t extractedInt = 0;
+
+  auto matcher = Internal::ConstMatcher(
+    &extractedConst,
+    Internal::I32Lit(&extractedLit, Internal::Any(&extractedInt)));
+
+  assert(matcher.matches(c));
+  assert(extractedConst == c);
+  assert(extractedLit == Literal(int32_t(42)));
+  assert(extractedInt == 42);
+
+  assert(matcher.matches(constExpr));
+  assert(extractedConst == constExpr);
+  assert(extractedLit == Literal(int32_t(43)));
+  assert(extractedInt == 43);
+
+  assert(!matcher.matches(nop));
+}
+
+void test_internal_unary() {
+  Expression* eqz32 =
+    builder.makeUnary(EqZInt32, builder.makeConst(Literal(int32_t(0))));
+  Expression* eqz64 =
+    builder.makeUnary(EqZInt64, builder.makeConst(Literal(int64_t(0))));
+  Expression* clz =
+    builder.makeUnary(ClzInt32, builder.makeConst(Literal(int32_t(0))));
+  Expression* nop = builder.makeNop();
+
+  std::cout << "Testing Internal::UnaryMatcher\n";
+
+  Unary* out = nullptr;
+  UnaryOp op;
+
+  auto unMatcher = Internal::UnaryMatcher(
+    &out, Internal::Any<UnaryOp>(&op), Internal::Any<Expression*>(nullptr));
+  assert(unMatcher.matches(eqz32));
+  assert(out == eqz32);
+  assert(op == EqZInt32);
+  assert(unMatcher.matches(eqz64));
+  assert(out == eqz64);
+  assert(op == EqZInt64);
+  assert(unMatcher.matches(clz));
+  assert(out == clz);
+  assert(op == ClzInt32);
+  assert(!unMatcher.matches(nop));
+
+  assert(matches(clz, unary(any())));
+  assert(matches(eqz64, unary(&out, any())));
+  assert(out == eqz64);
+  assert(matches(eqz32, unary(&op, any())));
+  assert(op == EqZInt32);
+
+  std::cout << "Testing Internal::UnaryOpMatcher\n";
+
+  out = nullptr;
+
+  auto eqz32Matcher = Internal::UnaryOpMatcher(
+    &out, EqZInt32, Internal::Any<Expression*>(nullptr));
+  assert(eqz32Matcher.matches(eqz32));
+  assert(out == eqz32);
+  assert(!eqz32Matcher.matches(eqz64));
+  assert(!eqz32Matcher.matches(clz));
+  assert(!eqz32Matcher.matches(nop));
+
+  std::cout << "Testing Internal::AbstractUnaryOpMatcher\n";
+
+  out = nullptr;
+
+  auto eqzMatcher = Internal::AbstractUnaryOpMatcher(
+    &out, Abstract::EqZ, Internal::Any<Expression*>(nullptr));
+  assert(eqzMatcher.matches(eqz32));
+  assert(out == eqz32);
+  assert(eqzMatcher.matches(eqz64));
+  assert(out == eqz64);
+  assert(!eqzMatcher.matches(clz));
+  assert(!eqzMatcher.matches(nop));
+}
+
+void test_internal_binary() {
+  Expression* eq32 = builder.makeBinary(EqInt32,
+                                        builder.makeConst(Literal(int32_t(0))),
+                                        builder.makeConst(Literal(int32_t(0))));
+  Expression* eq64 = builder.makeBinary(EqInt64,
+                                        builder.makeConst(Literal(int64_t(0))),
+                                        builder.makeConst(Literal(int64_t(0))));
+  Expression* add = builder.makeBinary(AddInt32,
+                                       builder.makeConst(Literal(int32_t(0))),
+                                       builder.makeConst(Literal(int32_t(0))));
+  Expression* nop = builder.makeNop();
+
+  std::cout << "Testing Internal::BinaryMatcher\n";
+
+  Binary* out = nullptr;
+  BinaryOp op;
+
+  auto binMatcher =
+    Internal::BinaryMatcher(&out,
+                            Internal::Any<BinaryOp>(&op),
+                            Internal::Any<Expression*>(nullptr),
+                            Internal::Any<Expression*>(nullptr));
+  assert(binMatcher.matches(eq32));
+  assert(out == eq32);
+  assert(op == EqInt32);
+  assert(binMatcher.matches(eq64));
+  assert(out == eq64);
+  assert(op == EqInt64);
+  assert(binMatcher.matches(add));
+  assert(out == add);
+  assert(op == AddInt32);
+  assert(!binMatcher.matches(nop));
+
+  assert(matches(add, binary(any(), any())));
+  assert(matches(eq64, binary(&out, any(), any())));
+  assert(out == eq64);
+  assert(matches(eq32, binary(&op, any(), any())));
+  assert(op == EqInt32);
+
+  std::cout << "Testing Internal::BinaryOpMatcher\n";
+
+  out = nullptr;
+
+  auto eq32Matcher =
+    Internal::BinaryOpMatcher(&out,
+                              EqInt32,
+                              Internal::Any<Expression*>(nullptr),
+                              Internal::Any<Expression*>(nullptr));
+  assert(eq32Matcher.matches(eq32));
+  assert(out == eq32);
+  assert(!eq32Matcher.matches(eq64));
+  assert(!eq32Matcher.matches(add));
+  assert(!eq32Matcher.matches(nop));
+
+  std::cout << "Testing Internal::AbstractBinaryOpMatcher\n";
+
+  out = nullptr;
+
+  auto eqMatcher =
+    Internal::AbstractBinaryOpMatcher(&out,
+                                      Abstract::Eq,
+                                      Internal::Any<Expression*>(nullptr),
+                                      Internal::Any<Expression*>(nullptr));
+  assert(eqMatcher.matches(eq32));
+  assert(out == eq32);
+  assert(eqMatcher.matches(eq64));
+  assert(out == eq64);
+  assert(!eqMatcher.matches(add));
+  assert(!eqMatcher.matches(nop));
+}
+
+void test_internal_select() {
+  std::cout << "Testing Internal::SelectMatcher\n";
+
+  auto zero = [&]() { return builder.makeConst(Literal(int32_t(0))); };
+  auto one = [&]() { return builder.makeConst(Literal(int32_t(1))); };
+
+  auto constMatcher = [](int32_t c) {
+    return Internal::ConstMatcher(
+      nullptr, Internal::I32Lit(nullptr, Internal::Exact<int32_t>(nullptr, c)));
+  };
+
+  // NB: `makeSelect` takes the condition first for some reason
+  Expression* leftOne = builder.makeSelect(zero(), one(), zero());
+  Expression* rightOne = builder.makeSelect(zero(), zero(), one());
+  Expression* condOne = builder.makeSelect(one(), zero(), zero());
+
+  Select* out = nullptr;
+
+  auto zeroesMatcher = Internal::SelectMatcher(
+    &out, constMatcher(0), constMatcher(0), constMatcher(0));
+  assert(!zeroesMatcher.matches(leftOne));
+  assert(!zeroesMatcher.matches(rightOne));
+  assert(!zeroesMatcher.matches(condOne));
+
+  auto leftMatcher = Internal::SelectMatcher(
+    &out, constMatcher(1), constMatcher(0), constMatcher(0));
+  assert(leftMatcher.matches(leftOne));
+  assert(out == leftOne);
+  assert(!leftMatcher.matches(rightOne));
+  assert(!leftMatcher.matches(condOne));
+
+  auto rightMatcher = Internal::SelectMatcher(
+    &out, constMatcher(0), constMatcher(1), constMatcher(0));
+  assert(!rightMatcher.matches(leftOne));
+  assert(rightMatcher.matches(rightOne));
+  assert(out == rightOne);
+  assert(!rightMatcher.matches(condOne));
+
+  auto condMatcher = Internal::SelectMatcher(
+    &out, constMatcher(0), constMatcher(0), constMatcher(1));
+  assert(!condMatcher.matches(leftOne));
+  assert(!condMatcher.matches(rightOne));
+  assert(condMatcher.matches(condOne));
+  assert(out == condOne);
+}
+
+int main() {
+  test_internal_any();
+  test_internal_exact();
+  test_internal_literal();
+  test_internal_const();
+  test_internal_unary();
+  test_internal_binary();
+  test_internal_select();
+}
diff --git a/binaryen/test/example/match.txt b/binaryen/test/example/match.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/match.txt
@@ -0,0 +1,11 @@
+Testing Internal::Any
+Testing Internal::Exact
+Testing Internal::{I32,I64,Int,F32,F64,Float}Lit
+Testing Internal::ConstantMatcher
+Testing Internal::UnaryMatcher
+Testing Internal::UnaryOpMatcher
+Testing Internal::AbstractUnaryOpMatcher
+Testing Internal::BinaryMatcher
+Testing Internal::BinaryOpMatcher
+Testing Internal::AbstractBinaryOpMatcher
+Testing Internal::SelectMatcher
diff --git a/binaryen/test/example/relooper-fuzz.c b/binaryen/test/example/relooper-fuzz.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-fuzz.c
@@ -0,0 +1,283 @@
+
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "binaryen-c.h"
+
+// globals: address 4 is index
+// decisions are at address 8+
+
+int main() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+
+  // check()
+
+  // if the end, halt
+  BinaryenExpressionRef halter = BinaryenIf(module,
+    BinaryenBinary(module,
+      BinaryenEqInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4 * 27)) // jumps of 4 bytes
+    ),
+    BinaryenUnreachable(module),
+    NULL
+  );
+  // increment index
+  BinaryenExpressionRef incer = BinaryenStore(module,
+    4, 0, 0,
+    BinaryenConst(module, BinaryenLiteralInt32(4)),
+    BinaryenBinary(module,
+      BinaryenAddInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4))
+    ),
+    BinaryenTypeInt32()
+  );
+
+  // optionally, print the return value
+  BinaryenExpressionRef args[] = {
+    BinaryenBinary(module,
+      BinaryenSubInt32(),
+      BinaryenConst(module, BinaryenLiteralInt32(0)),
+      BinaryenLoad(module,
+        4, 0, 4, 0, BinaryenTypeInt32(),
+        BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), BinaryenConst(module, BinaryenLiteralInt32(4)))
+      )
+    )
+  };
+  BinaryenExpressionRef debugger;
+  if (1) debugger = BinaryenCall(module, "print", args, 1, BinaryenTypeNone());
+  else debugger = BinaryenNop(module);
+
+  // return the decision. need to subtract 4 that we just added, and add 8 since that's where we start, so overall offset 4
+  BinaryenExpressionRef returner = BinaryenLoad(module,
+    4, 0, 4, 0, BinaryenTypeInt32(),
+    BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), BinaryenConst(module, BinaryenLiteralInt32(4)))
+  );
+  BinaryenExpressionRef checkBodyList[] = { halter, incer, debugger, returner };
+  BinaryenExpressionRef checkBody = BinaryenBlock(module, NULL, checkBodyList, sizeof(checkBodyList) / sizeof(BinaryenExpressionRef), BinaryenTypeAuto());
+  BinaryenAddFunction(module,
+                      "check",
+                      BinaryenTypeNone(),
+                      BinaryenTypeInt32(),
+                      NULL,
+                      0,
+                      checkBody);
+
+  // contents of main() begin here
+
+  RelooperRef relooper = RelooperCreate(module);
+
+
+  RelooperBlockRef b0;
+  {
+    BinaryenExpressionRef args[] = { BinaryenConst(module, BinaryenLiteralInt32(0)) };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0, BinaryenTypeInt32()))
+    };
+    b0 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeAuto()));
+  }
+
+  RelooperBlockRef b1;
+  {
+    BinaryenExpressionRef args[] = { BinaryenConst(module, BinaryenLiteralInt32(1)) };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0, BinaryenTypeInt32()))
+    };
+    b1 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeAuto()));
+  }
+
+  RelooperBlockRef b2;
+  {
+    BinaryenExpressionRef args[] = { BinaryenConst(module, BinaryenLiteralInt32(2)) };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0, BinaryenTypeInt32()))
+    };
+    b2 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeAuto()));
+  }
+
+  RelooperBlockRef b3;
+  {
+    BinaryenExpressionRef args[] = { BinaryenConst(module, BinaryenLiteralInt32(3)) };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0, BinaryenTypeInt32()))
+    };
+    b3 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeAuto()));
+  }
+
+  RelooperBlockRef b4;
+  {
+    BinaryenExpressionRef args[] = { BinaryenConst(module, BinaryenLiteralInt32(4)) };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0, BinaryenTypeInt32()))
+    };
+    b4 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeAuto()));
+  }
+
+  RelooperBlockRef b5;
+  {
+    BinaryenExpressionRef args[] = { BinaryenConst(module, BinaryenLiteralInt32(5)) };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0, BinaryenTypeInt32()))
+    };
+    b5 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeAuto()));
+  }
+
+  RelooperBlockRef b6;
+  {
+    BinaryenExpressionRef args[] = { BinaryenConst(module, BinaryenLiteralInt32(6)) };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0, BinaryenTypeInt32()))
+    };
+    b6 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeAuto()));
+  }
+
+  RelooperBlockRef b7;
+  {
+    BinaryenExpressionRef args[] = { BinaryenConst(module, BinaryenLiteralInt32(7)) };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0, BinaryenTypeInt32()))
+    };
+    b7 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeAuto()));
+  }
+
+  RelooperBlockRef b8;
+  {
+    BinaryenExpressionRef args[] = { BinaryenConst(module, BinaryenLiteralInt32(8)) };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0, BinaryenTypeInt32()))
+    };
+    b8 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeAuto()));
+  }
+
+  RelooperAddBranch(b0, b5, BinaryenBinary(module,
+    BinaryenEqInt32(),
+    BinaryenBinary(module,
+      BinaryenRemUInt32(),
+      BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+      BinaryenConst(module, BinaryenLiteralInt32(2))
+    ),
+    BinaryenConst(module, BinaryenLiteralInt32(0))
+  ), NULL);
+
+  RelooperAddBranch(b0, b8, NULL, NULL);
+
+  RelooperAddBranch(b1, b5, NULL, NULL);
+
+  RelooperAddBranch(b2, b5, NULL, NULL);
+
+  RelooperAddBranch(b3, b5, BinaryenBinary(module,
+    BinaryenEqInt32(),
+    BinaryenBinary(module,
+      BinaryenRemUInt32(),
+      BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+      BinaryenConst(module, BinaryenLiteralInt32(2))
+    ),
+    BinaryenConst(module, BinaryenLiteralInt32(0))
+  ), NULL);
+
+  RelooperAddBranch(b3, b8, NULL, NULL);
+
+  RelooperAddBranch(b4, b4, BinaryenBinary(module,
+    BinaryenEqInt32(),
+    BinaryenBinary(module,
+      BinaryenRemUInt32(),
+      BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+      BinaryenConst(module, BinaryenLiteralInt32(3))
+    ),
+    BinaryenConst(module, BinaryenLiteralInt32(0))
+  ), NULL);
+
+  RelooperAddBranch(b4, b5, BinaryenBinary(module,
+    BinaryenEqInt32(),
+    BinaryenBinary(module,
+      BinaryenRemUInt32(),
+      BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+      BinaryenConst(module, BinaryenLiteralInt32(3))
+    ),
+    BinaryenConst(module, BinaryenLiteralInt32(1))
+  ), NULL);
+
+  RelooperAddBranch(b4, b2, NULL, NULL);
+
+  RelooperAddBranch(b5, b4, BinaryenBinary(module,
+    BinaryenEqInt32(),
+    BinaryenBinary(module,
+      BinaryenRemUInt32(),
+      BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+      BinaryenConst(module, BinaryenLiteralInt32(2))
+    ),
+    BinaryenConst(module, BinaryenLiteralInt32(0))
+  ), NULL);
+
+  RelooperAddBranch(b5, b5, NULL, NULL);
+
+  RelooperAddBranch(b6, b6, NULL, NULL);
+
+  RelooperAddBranch(b7, b8, NULL, NULL);
+
+  RelooperAddBranch(b8, b4, NULL, NULL);
+
+  BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, b0, 1);
+
+  int decisions[] = { 89, 12, 78, 149, 118, 179, 127, 80, 21, 34, 119, 98, 38, 29, 36, 147, 13, 55, 166, 16, 143, 52, 130, 150, 176, 91, 34 };
+  int numDecisions = sizeof(decisions)/sizeof(int);
+
+  BinaryenExpressionRef full[numDecisions + 1]; // write out all the decisions, then the body of the function
+
+  {
+    int i;
+    for (i = 0; i < numDecisions; i++) {
+      full[i] = BinaryenStore(module,
+        4, 0, 0,
+        BinaryenConst(module, BinaryenLiteralInt32(8 + 4 * i)),
+        BinaryenConst(module, BinaryenLiteralInt32(decisions[i])),
+        BinaryenTypeInt32()
+      );
+    }
+  }
+  full[numDecisions] = body;
+  BinaryenExpressionRef all = BinaryenBlock(module, NULL, full, numDecisions + 1, BinaryenTypeAuto());
+
+  BinaryenType localTypes[] = { BinaryenTypeInt32(), BinaryenTypeInt32() }; // state, free-for-label
+  BinaryenFunctionRef theMain = BinaryenAddFunction(
+    module, "main", BinaryenTypeNone(), BinaryenTypeNone(), localTypes, 2, all);
+  BinaryenSetStart(module, theMain);
+
+  // import
+
+  BinaryenType iparams[] = { BinaryenTypeInt32() };
+  BinaryenAddFunctionImport(module,
+                            "print",
+                            "spectest",
+                            "print",
+                            BinaryenTypeInt32(),
+                            BinaryenTypeNone());
+
+  // memory
+  BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+
+  assert(BinaryenModuleValidate(module));
+
+  BinaryenModulePrint(module);
+
+  BinaryenModuleOptimize(module);
+
+  assert(BinaryenModuleValidate(module));
+
+  BinaryenModulePrint(module);
+
+  BinaryenModuleDispose(module);
+
+  return 0;
+}
diff --git a/binaryen/test/example/relooper-fuzz.txt b/binaryen/test/example/relooper-fuzz.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-fuzz.txt
@@ -0,0 +1,537 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "spectest" "print" (func $print (param i32)))
+ (memory $0 1 1)
+ (export "mem" (memory $0))
+ (start $main)
+ (func $check (result i32)
+  (if
+   (i32.eq
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 108)
+   )
+   (unreachable)
+  )
+  (i32.store
+   (i32.const 4)
+   (i32.add
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 4)
+   )
+  )
+  (call $print
+   (i32.sub
+    (i32.const 0)
+    (i32.load offset=4
+     (i32.load
+      (i32.const 4)
+     )
+    )
+   )
+  )
+  (i32.load offset=4
+   (i32.load
+    (i32.const 4)
+   )
+  )
+ )
+ (func $main
+  (local $0 i32)
+  (local $1 i32)
+  (i32.store
+   (i32.const 8)
+   (i32.const 89)
+  )
+  (i32.store
+   (i32.const 12)
+   (i32.const 12)
+  )
+  (i32.store
+   (i32.const 16)
+   (i32.const 78)
+  )
+  (i32.store
+   (i32.const 20)
+   (i32.const 149)
+  )
+  (i32.store
+   (i32.const 24)
+   (i32.const 118)
+  )
+  (i32.store
+   (i32.const 28)
+   (i32.const 179)
+  )
+  (i32.store
+   (i32.const 32)
+   (i32.const 127)
+  )
+  (i32.store
+   (i32.const 36)
+   (i32.const 80)
+  )
+  (i32.store
+   (i32.const 40)
+   (i32.const 21)
+  )
+  (i32.store
+   (i32.const 44)
+   (i32.const 34)
+  )
+  (i32.store
+   (i32.const 48)
+   (i32.const 119)
+  )
+  (i32.store
+   (i32.const 52)
+   (i32.const 98)
+  )
+  (i32.store
+   (i32.const 56)
+   (i32.const 38)
+  )
+  (i32.store
+   (i32.const 60)
+   (i32.const 29)
+  )
+  (i32.store
+   (i32.const 64)
+   (i32.const 36)
+  )
+  (i32.store
+   (i32.const 68)
+   (i32.const 147)
+  )
+  (i32.store
+   (i32.const 72)
+   (i32.const 13)
+  )
+  (i32.store
+   (i32.const 76)
+   (i32.const 55)
+  )
+  (i32.store
+   (i32.const 80)
+   (i32.const 166)
+  )
+  (i32.store
+   (i32.const 84)
+   (i32.const 16)
+  )
+  (i32.store
+   (i32.const 88)
+   (i32.const 143)
+  )
+  (i32.store
+   (i32.const 92)
+   (i32.const 52)
+  )
+  (i32.store
+   (i32.const 96)
+   (i32.const 130)
+  )
+  (i32.store
+   (i32.const 100)
+   (i32.const 150)
+  )
+  (i32.store
+   (i32.const 104)
+   (i32.const 176)
+  )
+  (i32.store
+   (i32.const 108)
+   (i32.const 91)
+  )
+  (i32.store
+   (i32.const 112)
+   (i32.const 34)
+  )
+  (block
+   (block
+    (block $block$6$break
+     (block $block$5$break
+      (block
+       (call $print
+        (i32.const 0)
+       )
+       (local.set $0
+        (call $check)
+       )
+      )
+      (if
+       (i32.eq
+        (i32.rem_u
+         (local.get $0)
+         (i32.const 2)
+        )
+        (i32.const 0)
+       )
+       (block
+        (local.set $1
+         (i32.const 6)
+        )
+        (br $block$6$break)
+       )
+       (block
+        (block
+         (call $print
+          (i32.const 8)
+         )
+         (local.set $0
+          (call $check)
+         )
+        )
+        (block
+         (br $block$5$break)
+        )
+       )
+      )
+     )
+    )
+   )
+   (loop $shape$3$continue
+    (block $block$5$break0
+     (if
+      (i32.eq
+       (local.get $1)
+       (i32.const 6)
+      )
+      (block
+       (local.set $1
+        (i32.const 0)
+       )
+       (block
+        (call $print
+         (i32.const 5)
+        )
+        (local.set $0
+         (call $check)
+        )
+       )
+       (if
+        (i32.eq
+         (i32.rem_u
+          (local.get $0)
+          (i32.const 2)
+         )
+         (i32.const 0)
+        )
+        (br $shape$3$continue)
+        (block
+         (local.set $1
+          (i32.const 6)
+         )
+         (br $shape$3$continue)
+        )
+       )
+      )
+     )
+    )
+    (block
+     (block $block$3$break
+      (block
+       (call $print
+        (i32.const 4)
+       )
+       (local.set $0
+        (call $check)
+       )
+      )
+      (if
+       (i32.eq
+        (i32.rem_u
+         (local.get $0)
+         (i32.const 3)
+        )
+        (i32.const 0)
+       )
+       (br $shape$3$continue)
+       (if
+        (i32.eq
+         (i32.rem_u
+          (local.get $0)
+          (i32.const 3)
+         )
+         (i32.const 1)
+        )
+        (block
+         (local.set $1
+          (i32.const 6)
+         )
+         (br $shape$3$continue)
+        )
+        (br $block$3$break)
+       )
+      )
+     )
+     (block
+      (block
+       (call $print
+        (i32.const 2)
+       )
+       (local.set $0
+        (call $check)
+       )
+      )
+      (block
+       (local.set $1
+        (i32.const 6)
+       )
+       (br $shape$3$continue)
+      )
+     )
+    )
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "spectest" "print" (func $print (param i32)))
+ (memory $0 1 1)
+ (export "mem" (memory $0))
+ (start $main)
+ (func $check (; has Stack IR ;) (result i32)
+  (if
+   (i32.eq
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 108)
+   )
+   (unreachable)
+  )
+  (i32.store
+   (i32.const 4)
+   (i32.add
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 4)
+   )
+  )
+  (call $print
+   (i32.sub
+    (i32.const 0)
+    (i32.load offset=4
+     (i32.load
+      (i32.const 4)
+     )
+    )
+   )
+  )
+  (i32.load offset=4
+   (i32.load
+    (i32.const 4)
+   )
+  )
+ )
+ (func $main (; has Stack IR ;)
+  (local $0 i32)
+  (local $1 i32)
+  (i32.store
+   (i32.const 8)
+   (i32.const 89)
+  )
+  (i32.store
+   (i32.const 12)
+   (i32.const 12)
+  )
+  (i32.store
+   (i32.const 16)
+   (i32.const 78)
+  )
+  (i32.store
+   (i32.const 20)
+   (i32.const 149)
+  )
+  (i32.store
+   (i32.const 24)
+   (i32.const 118)
+  )
+  (i32.store
+   (i32.const 28)
+   (i32.const 179)
+  )
+  (i32.store
+   (i32.const 32)
+   (i32.const 127)
+  )
+  (i32.store
+   (i32.const 36)
+   (i32.const 80)
+  )
+  (i32.store
+   (i32.const 40)
+   (i32.const 21)
+  )
+  (i32.store
+   (i32.const 44)
+   (i32.const 34)
+  )
+  (i32.store
+   (i32.const 48)
+   (i32.const 119)
+  )
+  (i32.store
+   (i32.const 52)
+   (i32.const 98)
+  )
+  (i32.store
+   (i32.const 56)
+   (i32.const 38)
+  )
+  (i32.store
+   (i32.const 60)
+   (i32.const 29)
+  )
+  (i32.store
+   (i32.const 64)
+   (i32.const 36)
+  )
+  (i32.store
+   (i32.const 68)
+   (i32.const 147)
+  )
+  (i32.store
+   (i32.const 72)
+   (i32.const 13)
+  )
+  (i32.store
+   (i32.const 76)
+   (i32.const 55)
+  )
+  (i32.store
+   (i32.const 80)
+   (i32.const 166)
+  )
+  (i32.store
+   (i32.const 84)
+   (i32.const 16)
+  )
+  (i32.store
+   (i32.const 88)
+   (i32.const 143)
+  )
+  (i32.store
+   (i32.const 92)
+   (i32.const 52)
+  )
+  (i32.store
+   (i32.const 96)
+   (i32.const 130)
+  )
+  (i32.store
+   (i32.const 100)
+   (i32.const 150)
+  )
+  (i32.store
+   (i32.const 104)
+   (i32.const 176)
+  )
+  (i32.store
+   (i32.const 108)
+   (i32.const 91)
+  )
+  (i32.store
+   (i32.const 112)
+   (i32.const 34)
+  )
+  (call $print
+   (i32.const 0)
+  )
+  (if
+   (i32.and
+    (call $check)
+    (i32.const 1)
+   )
+   (block
+    (call $print
+     (i32.const 8)
+    )
+    (drop
+     (call $check)
+    )
+   )
+   (local.set $0
+    (i32.const 6)
+   )
+  )
+  (loop $shape$3$continue
+   (if
+    (i32.eq
+     (local.get $0)
+     (i32.const 6)
+    )
+    (block
+     (local.set $0
+      (i32.const 0)
+     )
+     (call $print
+      (i32.const 5)
+     )
+     (br_if $shape$3$continue
+      (i32.eqz
+       (i32.and
+        (call $check)
+        (i32.const 1)
+       )
+      )
+     )
+     (local.set $0
+      (i32.const 6)
+     )
+     (br $shape$3$continue)
+    )
+   )
+   (call $print
+    (i32.const 4)
+   )
+   (br_if $shape$3$continue
+    (i32.eqz
+     (i32.rem_u
+      (local.tee $1
+       (call $check)
+      )
+      (i32.const 3)
+     )
+    )
+   )
+   (if
+    (i32.eq
+     (i32.rem_u
+      (local.get $1)
+      (i32.const 3)
+     )
+     (i32.const 1)
+    )
+    (block
+     (local.set $0
+      (i32.const 6)
+     )
+     (br $shape$3$continue)
+    )
+    (block
+     (call $print
+      (i32.const 2)
+     )
+     (drop
+      (call $check)
+     )
+     (local.set $0
+      (i32.const 6)
+     )
+     (br $shape$3$continue)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/example/relooper-fuzz1.c b/binaryen/test/example/relooper-fuzz1.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-fuzz1.c
@@ -0,0 +1,343 @@
+#include <assert.h>
+#include <stdio.h>
+
+#include "binaryen-c.h"
+
+// globals: address 4 is index
+// decisions are at address 8+
+
+int main() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+
+  // check()
+
+  // if the end, halt
+  BinaryenExpressionRef halter = BinaryenIf(module,
+    BinaryenBinary(module,
+      BinaryenEqInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4 * 30)) // jumps of 4 bytes
+    ),
+    BinaryenUnreachable(module),
+    NULL
+  );
+  // increment index
+  BinaryenExpressionRef incer = BinaryenStore(module,
+    4, 0, 0,
+    BinaryenConst(module, BinaryenLiteralInt32(4)),
+    BinaryenBinary(module,
+      BinaryenAddInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4))
+    ),
+    BinaryenTypeInt32()
+  );
+
+  // optionally, print the return value
+  BinaryenExpressionRef args[] = {
+    BinaryenBinary(module,
+      BinaryenSubInt32(),
+      BinaryenConst(module, BinaryenLiteralInt32(0)),
+      BinaryenLoad(module,
+        4, 0, 4, 0, BinaryenTypeInt32(),
+        BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4)))
+      )
+    )
+  };
+  BinaryenExpressionRef debugger;
+  if (1) debugger = BinaryenCall(module, "print", args, 1,
+                                       BinaryenTypeNone());
+  else debugger = BinaryenNop(module);
+
+  // return the decision. need to subtract 4 that we just added,
+  // and add 8 since that's where we start, so overall offset 4
+  BinaryenExpressionRef returner = BinaryenLoad(module,
+    4, 0, 4, 0, BinaryenTypeInt32(),
+    BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+    BinaryenConst(module, BinaryenLiteralInt32(4)))
+  );
+  BinaryenExpressionRef checkBodyList[] = { halter, incer, debugger,
+                                            returner };
+  BinaryenExpressionRef checkBody = BinaryenBlock(module,
+    NULL, checkBodyList, sizeof(checkBodyList) / sizeof(BinaryenExpressionRef),
+    BinaryenTypeAuto()
+  );
+  BinaryenAddFunction(module,
+                      "check",
+                      BinaryenTypeNone(),
+                      BinaryenTypeInt32(),
+                      NULL,
+                      0,
+                      checkBody);
+
+  // contents of main() begin here
+
+  RelooperRef relooper = RelooperCreate(module);
+
+
+  RelooperBlockRef b0;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(0))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b0 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2,
+                                                  BinaryenTypeAuto()));
+
+  }
+
+  RelooperBlockRef b1;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b1 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2,
+                                                  BinaryenTypeAuto()));
+
+  }
+
+  RelooperBlockRef b2;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(2))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b2 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2,
+                                                  BinaryenTypeAuto()));
+
+  }
+
+  RelooperBlockRef b3;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(3))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b3 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2,
+                                                  BinaryenTypeAuto()));
+
+  }
+
+  RelooperBlockRef b4;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(4))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b4 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2,
+                                                  BinaryenTypeAuto()));
+
+  }
+
+  RelooperBlockRef b5;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(5))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b5 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2,
+                                                  BinaryenTypeAuto()));
+
+  }
+
+  RelooperBlockRef b6;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(6))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b6 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2,
+                                                  BinaryenTypeAuto()));
+
+  }
+
+  RelooperBlockRef b7;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(7))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b7 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2,
+                                                  BinaryenTypeAuto()));
+
+  }
+
+  RelooperBlockRef b8;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(8))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b8 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2,
+                                                  BinaryenTypeAuto()));
+
+  }
+
+  RelooperBlockRef b9;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(9))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b9 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2,
+                                                  BinaryenTypeAuto()));
+
+  }
+
+  RelooperAddBranch(b0, b2, BinaryenBinary(module,
+    BinaryenEqInt32(),
+    BinaryenBinary(module,
+      BinaryenRemUInt32(),
+      BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+      BinaryenConst(module, BinaryenLiteralInt32(4))
+    ),
+    BinaryenConst(module, BinaryenLiteralInt32(0))
+  ), NULL);
+
+  RelooperAddBranch(b0, b7, BinaryenBinary(module,
+    BinaryenEqInt32(),
+    BinaryenBinary(module,
+      BinaryenRemUInt32(),
+      BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+      BinaryenConst(module, BinaryenLiteralInt32(4))
+    ),
+    BinaryenConst(module, BinaryenLiteralInt32(2))
+  ), NULL);
+
+  RelooperAddBranch(b0, b3, NULL, NULL);
+
+  RelooperAddBranch(b2, b3, BinaryenBinary(module,
+    BinaryenEqInt32(),
+    BinaryenBinary(module,
+      BinaryenRemUInt32(),
+      BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+      BinaryenConst(module, BinaryenLiteralInt32(2))
+    ),
+    BinaryenConst(module, BinaryenLiteralInt32(0))
+  ), NULL);
+
+  RelooperAddBranch(b2, b9, NULL, NULL);
+
+  RelooperAddBranch(b3, b3, NULL, NULL);
+
+  RelooperAddBranch(b7, b2, BinaryenBinary(module,
+    BinaryenEqInt32(),
+    BinaryenBinary(module,
+      BinaryenRemUInt32(),
+      BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+      BinaryenConst(module, BinaryenLiteralInt32(3))
+    ),
+    BinaryenConst(module, BinaryenLiteralInt32(0))
+  ), NULL);
+
+  RelooperAddBranch(b7, b9, NULL, NULL);
+
+  BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, b0, 1);
+
+  int decisions[] = { 67, 131, 49, 36, 112, 161, 62, 166, 16, 88, 176, 152, 161, 194, 117, 180, 60, 166, 55, 183, 150, 73, 196, 143, 76, 182, 97, 140, 126, 3 };
+  int numDecisions = sizeof(decisions)/sizeof(int);
+
+  // write out all the decisions, then the body of the function
+  BinaryenExpressionRef full[numDecisions + 1];
+
+  {
+    int i;
+    for (i = 0; i < numDecisions; i++) {
+      full[i] = BinaryenStore(module,
+        4, 0, 0,
+        BinaryenConst(module, BinaryenLiteralInt32(8 + 4 * i)),
+        BinaryenConst(module, BinaryenLiteralInt32(decisions[i])),
+        BinaryenTypeInt32()
+      );
+    }
+  }
+  full[numDecisions] = body;
+  BinaryenExpressionRef all = BinaryenBlock(module, NULL, full,
+                                            numDecisions + 1,
+                                            BinaryenTypeAuto());
+
+  // locals: state, free-for-label
+  BinaryenType localTypes[] = { BinaryenTypeInt32(), BinaryenTypeInt32() };
+  BinaryenFunctionRef theMain = BinaryenAddFunction(
+    module, "main", BinaryenTypeNone(), BinaryenTypeNone(), localTypes, 2, all);
+  BinaryenSetStart(module, theMain);
+
+  // import
+  BinaryenAddFunctionImport(module,
+                            "print",
+                            "spectest",
+                            "print",
+                            BinaryenTypeInt32(),
+                            BinaryenTypeNone());
+
+  // memory
+  BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+
+  assert(BinaryenModuleValidate(module));
+
+  BinaryenModulePrint(module);
+
+  BinaryenModuleOptimize(module);
+
+  assert(BinaryenModuleValidate(module));
+
+  BinaryenModulePrint(module);
+
+  BinaryenModuleDispose(module);
+
+  return 0;
+}
diff --git a/binaryen/test/example/relooper-fuzz1.txt b/binaryen/test/example/relooper-fuzz1.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-fuzz1.txt
@@ -0,0 +1,496 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "spectest" "print" (func $print (param i32)))
+ (memory $0 1 1)
+ (export "mem" (memory $0))
+ (start $main)
+ (func $check (result i32)
+  (if
+   (i32.eq
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 120)
+   )
+   (unreachable)
+  )
+  (i32.store
+   (i32.const 4)
+   (i32.add
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 4)
+   )
+  )
+  (call $print
+   (i32.sub
+    (i32.const 0)
+    (i32.load offset=4
+     (i32.load
+      (i32.const 4)
+     )
+    )
+   )
+  )
+  (i32.load offset=4
+   (i32.load
+    (i32.const 4)
+   )
+  )
+ )
+ (func $main
+  (local $0 i32)
+  (local $1 i32)
+  (i32.store
+   (i32.const 8)
+   (i32.const 67)
+  )
+  (i32.store
+   (i32.const 12)
+   (i32.const 131)
+  )
+  (i32.store
+   (i32.const 16)
+   (i32.const 49)
+  )
+  (i32.store
+   (i32.const 20)
+   (i32.const 36)
+  )
+  (i32.store
+   (i32.const 24)
+   (i32.const 112)
+  )
+  (i32.store
+   (i32.const 28)
+   (i32.const 161)
+  )
+  (i32.store
+   (i32.const 32)
+   (i32.const 62)
+  )
+  (i32.store
+   (i32.const 36)
+   (i32.const 166)
+  )
+  (i32.store
+   (i32.const 40)
+   (i32.const 16)
+  )
+  (i32.store
+   (i32.const 44)
+   (i32.const 88)
+  )
+  (i32.store
+   (i32.const 48)
+   (i32.const 176)
+  )
+  (i32.store
+   (i32.const 52)
+   (i32.const 152)
+  )
+  (i32.store
+   (i32.const 56)
+   (i32.const 161)
+  )
+  (i32.store
+   (i32.const 60)
+   (i32.const 194)
+  )
+  (i32.store
+   (i32.const 64)
+   (i32.const 117)
+  )
+  (i32.store
+   (i32.const 68)
+   (i32.const 180)
+  )
+  (i32.store
+   (i32.const 72)
+   (i32.const 60)
+  )
+  (i32.store
+   (i32.const 76)
+   (i32.const 166)
+  )
+  (i32.store
+   (i32.const 80)
+   (i32.const 55)
+  )
+  (i32.store
+   (i32.const 84)
+   (i32.const 183)
+  )
+  (i32.store
+   (i32.const 88)
+   (i32.const 150)
+  )
+  (i32.store
+   (i32.const 92)
+   (i32.const 73)
+  )
+  (i32.store
+   (i32.const 96)
+   (i32.const 196)
+  )
+  (i32.store
+   (i32.const 100)
+   (i32.const 143)
+  )
+  (i32.store
+   (i32.const 104)
+   (i32.const 76)
+  )
+  (i32.store
+   (i32.const 108)
+   (i32.const 182)
+  )
+  (i32.store
+   (i32.const 112)
+   (i32.const 97)
+  )
+  (i32.store
+   (i32.const 116)
+   (i32.const 140)
+  )
+  (i32.store
+   (i32.const 120)
+   (i32.const 126)
+  )
+  (i32.store
+   (i32.const 124)
+   (i32.const 3)
+  )
+  (block
+   (block $block$10$break
+    (block $block$4$break
+     (block $block$3$break
+      (block
+       (call $print
+        (i32.const 0)
+       )
+       (local.set $0
+        (call $check)
+       )
+      )
+      (if
+       (i32.eq
+        (i32.rem_u
+         (local.get $0)
+         (i32.const 4)
+        )
+        (i32.const 0)
+       )
+       (br $block$3$break)
+       (if
+        (i32.eq
+         (i32.rem_u
+          (local.get $0)
+          (i32.const 4)
+         )
+         (i32.const 2)
+        )
+        (block
+         (block
+          (call $print
+           (i32.const 7)
+          )
+          (local.set $0
+           (call $check)
+          )
+         )
+         (if
+          (i32.eq
+           (i32.rem_u
+            (local.get $0)
+            (i32.const 3)
+           )
+           (i32.const 0)
+          )
+          (br $block$3$break)
+          (br $block$10$break)
+         )
+        )
+        (br $block$4$break)
+       )
+      )
+     )
+     (block
+      (block
+       (call $print
+        (i32.const 2)
+       )
+       (local.set $0
+        (call $check)
+       )
+      )
+      (if
+       (i32.eq
+        (i32.rem_u
+         (local.get $0)
+         (i32.const 2)
+        )
+        (i32.const 0)
+       )
+       (br $block$4$break)
+       (br $block$10$break)
+      )
+     )
+    )
+    (loop $shape$6$continue
+     (block
+      (call $print
+       (i32.const 3)
+      )
+      (local.set $0
+       (call $check)
+      )
+     )
+     (block
+      (br $shape$6$continue)
+     )
+    )
+   )
+   (block
+    (block
+     (call $print
+      (i32.const 9)
+     )
+     (local.set $0
+      (call $check)
+     )
+    )
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "spectest" "print" (func $print (param i32)))
+ (memory $0 1 1)
+ (export "mem" (memory $0))
+ (start $main)
+ (func $check (; has Stack IR ;) (result i32)
+  (if
+   (i32.eq
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 120)
+   )
+   (unreachable)
+  )
+  (i32.store
+   (i32.const 4)
+   (i32.add
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 4)
+   )
+  )
+  (call $print
+   (i32.sub
+    (i32.const 0)
+    (i32.load offset=4
+     (i32.load
+      (i32.const 4)
+     )
+    )
+   )
+  )
+  (i32.load offset=4
+   (i32.load
+    (i32.const 4)
+   )
+  )
+ )
+ (func $main (; has Stack IR ;)
+  (local $0 i32)
+  (i32.store
+   (i32.const 8)
+   (i32.const 67)
+  )
+  (i32.store
+   (i32.const 12)
+   (i32.const 131)
+  )
+  (i32.store
+   (i32.const 16)
+   (i32.const 49)
+  )
+  (i32.store
+   (i32.const 20)
+   (i32.const 36)
+  )
+  (i32.store
+   (i32.const 24)
+   (i32.const 112)
+  )
+  (i32.store
+   (i32.const 28)
+   (i32.const 161)
+  )
+  (i32.store
+   (i32.const 32)
+   (i32.const 62)
+  )
+  (i32.store
+   (i32.const 36)
+   (i32.const 166)
+  )
+  (i32.store
+   (i32.const 40)
+   (i32.const 16)
+  )
+  (i32.store
+   (i32.const 44)
+   (i32.const 88)
+  )
+  (i32.store
+   (i32.const 48)
+   (i32.const 176)
+  )
+  (i32.store
+   (i32.const 52)
+   (i32.const 152)
+  )
+  (i32.store
+   (i32.const 56)
+   (i32.const 161)
+  )
+  (i32.store
+   (i32.const 60)
+   (i32.const 194)
+  )
+  (i32.store
+   (i32.const 64)
+   (i32.const 117)
+  )
+  (i32.store
+   (i32.const 68)
+   (i32.const 180)
+  )
+  (i32.store
+   (i32.const 72)
+   (i32.const 60)
+  )
+  (i32.store
+   (i32.const 76)
+   (i32.const 166)
+  )
+  (i32.store
+   (i32.const 80)
+   (i32.const 55)
+  )
+  (i32.store
+   (i32.const 84)
+   (i32.const 183)
+  )
+  (i32.store
+   (i32.const 88)
+   (i32.const 150)
+  )
+  (i32.store
+   (i32.const 92)
+   (i32.const 73)
+  )
+  (i32.store
+   (i32.const 96)
+   (i32.const 196)
+  )
+  (i32.store
+   (i32.const 100)
+   (i32.const 143)
+  )
+  (i32.store
+   (i32.const 104)
+   (i32.const 76)
+  )
+  (i32.store
+   (i32.const 108)
+   (i32.const 182)
+  )
+  (i32.store
+   (i32.const 112)
+   (i32.const 97)
+  )
+  (i32.store
+   (i32.const 116)
+   (i32.const 140)
+  )
+  (i32.store
+   (i32.const 120)
+   (i32.const 126)
+  )
+  (i32.store
+   (i32.const 124)
+   (i32.const 3)
+  )
+  (call $print
+   (i32.const 0)
+  )
+  (block $block$10$break
+   (block $block$4$break
+    (if
+     (i32.and
+      (local.tee $0
+       (call $check)
+      )
+      (i32.const 3)
+     )
+     (if
+      (i32.eq
+       (i32.and
+        (local.get $0)
+        (i32.const 3)
+       )
+       (i32.const 2)
+      )
+      (block
+       (call $print
+        (i32.const 7)
+       )
+       (br_if $block$10$break
+        (i32.rem_u
+         (call $check)
+         (i32.const 3)
+        )
+       )
+      )
+      (br $block$4$break)
+     )
+    )
+    (call $print
+     (i32.const 2)
+    )
+    (br_if $block$10$break
+     (i32.and
+      (call $check)
+      (i32.const 1)
+     )
+    )
+   )
+   (loop $shape$6$continue
+    (call $print
+     (i32.const 3)
+    )
+    (drop
+     (call $check)
+    )
+    (br $shape$6$continue)
+   )
+  )
+  (call $print
+   (i32.const 9)
+  )
+  (drop
+   (call $check)
+  )
+ )
+)
diff --git a/binaryen/test/example/relooper-fuzz2.c b/binaryen/test/example/relooper-fuzz2.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-fuzz2.c
@@ -0,0 +1,649 @@
+#include <assert.h>
+#include <stdio.h>
+
+#include "binaryen-c.h"
+
+// globals: address 4 is index
+// decisions are at address 8+
+
+int main() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+
+  // check()
+
+  // if the end, halt
+  BinaryenExpressionRef halter = BinaryenIf(module,
+    BinaryenBinary(module,
+      BinaryenGeUInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4 * 27)) // jumps of 4 bytes
+    ),
+    BinaryenUnreachable(module),
+    NULL
+  );
+  // increment index
+  BinaryenExpressionRef incer = BinaryenStore(module,
+    4, 0, 0,
+    BinaryenConst(module, BinaryenLiteralInt32(4)),
+    BinaryenBinary(module,
+      BinaryenAddInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4))
+    ),
+    BinaryenTypeInt32()
+  );
+
+  // optionally, print the return value
+  BinaryenExpressionRef args[] = {
+    BinaryenBinary(module,
+      BinaryenSubInt32(),
+      BinaryenConst(module, BinaryenLiteralInt32(0)),
+      BinaryenLoad(module,
+        4, 0, 4, 0, BinaryenTypeInt32(),
+        BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4)))
+      )
+    )
+  };
+  BinaryenExpressionRef debugger;
+  if (1) debugger = BinaryenCall(module, "print", args, 1,
+                                 BinaryenTypeNone());
+  else debugger = BinaryenNop(module);
+
+  // return the decision. need to subtract 4 that we just added,
+  // and add 8 since that's where we start, so overall offset 4
+  BinaryenExpressionRef returner = BinaryenLoad(module,
+    4, 0, 4, 0, BinaryenTypeInt32(),
+    BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+    BinaryenConst(module, BinaryenLiteralInt32(4)))
+  );
+  BinaryenExpressionRef checkBodyList[] = { halter, incer, debugger,
+                                            returner };
+  BinaryenExpressionRef checkBody = BinaryenBlock(module,
+    NULL, checkBodyList, sizeof(checkBodyList) / sizeof(BinaryenExpressionRef),
+    BinaryenTypeInt32()
+  );
+  BinaryenAddFunction(module,
+                      "check",
+                      BinaryenTypeNone(),
+                      BinaryenTypeInt32(),
+                      NULL,
+                      0,
+                      checkBody);
+
+  // contents of main() begin here
+
+  RelooperRef relooper = RelooperCreate(module);
+
+
+  RelooperBlockRef b0;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(0))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b0 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b1;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(0))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b1 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b2;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(0))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b2 = RelooperAddBlockWithSwitch(relooper,
+      BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()),
+      BinaryenBinary(module,
+        BinaryenRemUInt32(),
+        BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+        BinaryenConst(module, BinaryenLiteralInt32(2))
+      )
+    );
+
+  }
+
+  RelooperBlockRef b3;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(0))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b3 = RelooperAddBlockWithSwitch(relooper,
+      BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()),
+      BinaryenBinary(module,
+        BinaryenRemUInt32(),
+        BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+        BinaryenConst(module, BinaryenLiteralInt32(1))
+      )
+    );
+
+  }
+
+  RelooperBlockRef b4;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(4))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b4 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b5;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(0))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b5 = RelooperAddBlockWithSwitch(relooper,
+      BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()),
+      BinaryenBinary(module,
+        BinaryenRemUInt32(),
+        BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+        BinaryenConst(module, BinaryenLiteralInt32(1))
+      )
+    );
+
+  }
+
+  RelooperBlockRef b6;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(6))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b6 = RelooperAddBlockWithSwitch(relooper,
+      BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()),
+      BinaryenBinary(module,
+        BinaryenRemUInt32(),
+        BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+        BinaryenConst(module, BinaryenLiteralInt32(3))
+      )
+    );
+
+  }
+
+  RelooperBlockRef b7;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(0))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b7 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b8;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(0))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b8 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperAddBranch(
+    b0,
+    b1,
+    NULL,
+    BinaryenStore(
+      module,
+      4,
+      0,
+      0,
+      BinaryenConst(module, BinaryenLiteralInt32(4)),
+      BinaryenBinary(
+        module,
+        BinaryenAddInt32(),
+        BinaryenLoad(module,
+                     4,
+                     0,
+                     0,
+                     0,
+                     BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4))),
+        BinaryenConst(module, BinaryenLiteralInt32(4 * 4))),
+      BinaryenTypeInt32()));
+
+  RelooperAddBranch(
+    b1,
+    b1,
+    NULL,
+    BinaryenStore(
+      module,
+      4,
+      0,
+      0,
+      BinaryenConst(module, BinaryenLiteralInt32(4)),
+      BinaryenBinary(
+        module,
+        BinaryenAddInt32(),
+        BinaryenLoad(module,
+                     4,
+                     0,
+                     0,
+                     0,
+                     BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4))),
+        BinaryenConst(module, BinaryenLiteralInt32(4 * 4))),
+      BinaryenTypeInt32()));
+
+  {
+    BinaryenIndex values[] = { 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86 };
+    RelooperAddBranchForSwitch(
+      b2,
+      b7,
+      values,
+      sizeof(values) / sizeof(BinaryenIndex),
+      BinaryenStore(
+        module,
+        4,
+        0,
+        0,
+        BinaryenConst(module, BinaryenLiteralInt32(4)),
+        BinaryenBinary(
+          module,
+          BinaryenAddInt32(),
+          BinaryenLoad(module,
+                       4,
+                       0,
+                       0,
+                       0,
+                       BinaryenTypeInt32(),
+                       BinaryenConst(module, BinaryenLiteralInt32(4))),
+          BinaryenConst(module, BinaryenLiteralInt32(4 * 6))),
+        BinaryenTypeInt32()));
+  }
+
+  RelooperAddBranchForSwitch(
+    b2,
+    b4,
+    NULL,
+    0,
+    BinaryenStore(
+      module,
+      4,
+      0,
+      0,
+      BinaryenConst(module, BinaryenLiteralInt32(4)),
+      BinaryenBinary(
+        module,
+        BinaryenAddInt32(),
+        BinaryenLoad(module,
+                     4,
+                     0,
+                     0,
+                     0,
+                     BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4))),
+        BinaryenConst(module, BinaryenLiteralInt32(4 * 4))),
+      BinaryenTypeInt32()));
+
+  RelooperAddBranchForSwitch(
+    b3,
+    b6,
+    NULL,
+    0,
+    BinaryenStore(
+      module,
+      4,
+      0,
+      0,
+      BinaryenConst(module, BinaryenLiteralInt32(4)),
+      BinaryenBinary(
+        module,
+        BinaryenAddInt32(),
+        BinaryenLoad(module,
+                     4,
+                     0,
+                     0,
+                     0,
+                     BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4))),
+        BinaryenConst(module, BinaryenLiteralInt32(4 * 5))),
+      BinaryenTypeInt32()));
+
+  RelooperAddBranch(
+    b4,
+    b7,
+    BinaryenBinary(
+      module,
+      BinaryenEqInt32(),
+      BinaryenBinary(module,
+                     BinaryenRemUInt32(),
+                     BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+                     BinaryenConst(module, BinaryenLiteralInt32(2))),
+      BinaryenConst(module, BinaryenLiteralInt32(0))),
+    BinaryenStore(
+      module,
+      4,
+      0,
+      0,
+      BinaryenConst(module, BinaryenLiteralInt32(4)),
+      BinaryenBinary(
+        module,
+        BinaryenAddInt32(),
+        BinaryenLoad(module,
+                     4,
+                     0,
+                     0,
+                     0,
+                     BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4))),
+        BinaryenConst(module, BinaryenLiteralInt32(4 * 5))),
+      BinaryenTypeInt32()));
+
+  RelooperAddBranch(
+    b4,
+    b3,
+    NULL,
+    BinaryenStore(
+      module,
+      4,
+      0,
+      0,
+      BinaryenConst(module, BinaryenLiteralInt32(4)),
+      BinaryenBinary(
+        module,
+        BinaryenAddInt32(),
+        BinaryenLoad(module,
+                     4,
+                     0,
+                     0,
+                     0,
+                     BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4))),
+        BinaryenConst(module, BinaryenLiteralInt32(4 * 3))),
+      BinaryenTypeInt32()));
+
+  RelooperAddBranchForSwitch(
+    b5,
+    b1,
+    NULL,
+    0,
+    BinaryenStore(
+      module,
+      4,
+      0,
+      0,
+      BinaryenConst(module, BinaryenLiteralInt32(4)),
+      BinaryenBinary(
+        module,
+        BinaryenAddInt32(),
+        BinaryenLoad(module,
+                     4,
+                     0,
+                     0,
+                     0,
+                     BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4))),
+        BinaryenConst(module, BinaryenLiteralInt32(4 * 4))),
+      BinaryenTypeInt32()));
+
+  {
+    BinaryenIndex values[] = { 0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60,63,66,69,72,75,78,81,84,87,90,93,96,99,102,105,108 };
+    RelooperAddBranchForSwitch(
+      b6,
+      b1,
+      values,
+      sizeof(values) / sizeof(BinaryenIndex),
+      BinaryenStore(
+        module,
+        4,
+        0,
+        0,
+        BinaryenConst(module, BinaryenLiteralInt32(4)),
+        BinaryenBinary(
+          module,
+          BinaryenAddInt32(),
+          BinaryenLoad(module,
+                       4,
+                       0,
+                       0,
+                       0,
+                       BinaryenTypeInt32(),
+                       BinaryenConst(module, BinaryenLiteralInt32(4))),
+          BinaryenConst(module, BinaryenLiteralInt32(4 * 2))),
+        BinaryenTypeInt32()));
+  }
+
+  {
+    BinaryenIndex values[] = { 1,4,7,10,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58,61,64,67,70,73,76,79,82,85,88,91,94,97,100,103,106,109,112,115,118,121,124,127,130,133,136,139,142,145,148,151,154,157,160 };
+    RelooperAddBranchForSwitch(
+      b6,
+      b7,
+      values,
+      sizeof(values) / sizeof(BinaryenIndex),
+      BinaryenStore(
+        module,
+        4,
+        0,
+        0,
+        BinaryenConst(module, BinaryenLiteralInt32(4)),
+        BinaryenBinary(
+          module,
+          BinaryenAddInt32(),
+          BinaryenLoad(module,
+                       4,
+                       0,
+                       0,
+                       0,
+                       BinaryenTypeInt32(),
+                       BinaryenConst(module, BinaryenLiteralInt32(4))),
+          BinaryenConst(module, BinaryenLiteralInt32(4 * 3))),
+        BinaryenTypeInt32()));
+  }
+
+  RelooperAddBranchForSwitch(
+    b6,
+    b2,
+    NULL,
+    0,
+    BinaryenStore(
+      module,
+      4,
+      0,
+      0,
+      BinaryenConst(module, BinaryenLiteralInt32(4)),
+      BinaryenBinary(
+        module,
+        BinaryenAddInt32(),
+        BinaryenLoad(module,
+                     4,
+                     0,
+                     0,
+                     0,
+                     BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4))),
+        BinaryenConst(module, BinaryenLiteralInt32(4 * 3))),
+      BinaryenTypeInt32()));
+
+  RelooperAddBranch(
+    b7,
+    b5,
+    BinaryenBinary(
+      module,
+      BinaryenEqInt32(),
+      BinaryenBinary(module,
+                     BinaryenRemUInt32(),
+                     BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+                     BinaryenConst(module, BinaryenLiteralInt32(2))),
+      BinaryenConst(module, BinaryenLiteralInt32(0))),
+    BinaryenStore(
+      module,
+      4,
+      0,
+      0,
+      BinaryenConst(module, BinaryenLiteralInt32(4)),
+      BinaryenBinary(
+        module,
+        BinaryenAddInt32(),
+        BinaryenLoad(module,
+                     4,
+                     0,
+                     0,
+                     0,
+                     BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4))),
+        BinaryenConst(module, BinaryenLiteralInt32(4 * 1))),
+      BinaryenTypeInt32()));
+
+  RelooperAddBranch(
+    b7,
+    b1,
+    NULL,
+    BinaryenStore(
+      module,
+      4,
+      0,
+      0,
+      BinaryenConst(module, BinaryenLiteralInt32(4)),
+      BinaryenBinary(
+        module,
+        BinaryenAddInt32(),
+        BinaryenLoad(module,
+                     4,
+                     0,
+                     0,
+                     0,
+                     BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4))),
+        BinaryenConst(module, BinaryenLiteralInt32(4 * 4))),
+      BinaryenTypeInt32()));
+
+  RelooperAddBranch(
+    b8,
+    b8,
+    NULL,
+    BinaryenStore(
+      module,
+      4,
+      0,
+      0,
+      BinaryenConst(module, BinaryenLiteralInt32(4)),
+      BinaryenBinary(
+        module,
+        BinaryenAddInt32(),
+        BinaryenLoad(module,
+                     4,
+                     0,
+                     0,
+                     0,
+                     BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4))),
+        BinaryenConst(module, BinaryenLiteralInt32(4 * 2))),
+      BinaryenTypeInt32()));
+
+  BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, b0, 1);
+
+  int decisions[] = { 5, 111, 119, 17, 179, 41, 32, 3, 171, 126, 13, 95, 70, 91, 9, 140, 99, 161, 38, 87, 153, 117, 140, 11, 157, 48, 4 };
+  int numDecisions = sizeof(decisions)/sizeof(int);
+
+  // write out all the decisions, then the body of the function
+  BinaryenExpressionRef full[numDecisions + 1];
+
+  {
+    int i;
+    for (i = 0; i < numDecisions; i++) {
+      full[i] = BinaryenStore(module,
+        4, 0, 0,
+        BinaryenConst(module, BinaryenLiteralInt32(8 + 4 * i)),
+        BinaryenConst(module, BinaryenLiteralInt32(decisions[i])),
+        BinaryenTypeInt32()
+      );
+    }
+  }
+  full[numDecisions] = body;
+  BinaryenExpressionRef all = BinaryenBlock(module, NULL, full,
+                                            numDecisions + 1,
+                                            BinaryenTypeNone());
+
+  // locals: state, free-for-label
+  BinaryenType localTypes[] = { BinaryenTypeInt32(), BinaryenTypeInt32() };
+  BinaryenFunctionRef theMain = BinaryenAddFunction(
+    module, "main", BinaryenTypeNone(), BinaryenTypeNone(), localTypes, 2, all);
+  BinaryenSetStart(module, theMain);
+
+  // import
+  BinaryenAddFunctionImport(module,
+                            "print",
+                            "spectest",
+                            "print",
+                            BinaryenTypeInt32(),
+                            BinaryenTypeNone());
+
+  // memory
+  BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+
+  // optionally, optimize
+  if (0) BinaryenModuleOptimize(module);
+
+  assert(BinaryenModuleValidate(module));
+
+  // write it out
+
+  BinaryenModulePrint(module);
+
+  BinaryenModuleDispose(module);
+
+  return 0;
+}
diff --git a/binaryen/test/example/relooper-fuzz2.txt b/binaryen/test/example/relooper-fuzz2.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-fuzz2.txt
@@ -0,0 +1,202 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "spectest" "print" (func $print (param i32)))
+ (memory $0 1 1)
+ (export "mem" (memory $0))
+ (start $main)
+ (func $check (result i32)
+  (if
+   (i32.ge_u
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 108)
+   )
+   (unreachable)
+  )
+  (i32.store
+   (i32.const 4)
+   (i32.add
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 4)
+   )
+  )
+  (call $print
+   (i32.sub
+    (i32.const 0)
+    (i32.load offset=4
+     (i32.load
+      (i32.const 4)
+     )
+    )
+   )
+  )
+  (i32.load offset=4
+   (i32.load
+    (i32.const 4)
+   )
+  )
+ )
+ (func $main
+  (local $0 i32)
+  (local $1 i32)
+  (i32.store
+   (i32.const 8)
+   (i32.const 5)
+  )
+  (i32.store
+   (i32.const 12)
+   (i32.const 111)
+  )
+  (i32.store
+   (i32.const 16)
+   (i32.const 119)
+  )
+  (i32.store
+   (i32.const 20)
+   (i32.const 17)
+  )
+  (i32.store
+   (i32.const 24)
+   (i32.const 179)
+  )
+  (i32.store
+   (i32.const 28)
+   (i32.const 41)
+  )
+  (i32.store
+   (i32.const 32)
+   (i32.const 32)
+  )
+  (i32.store
+   (i32.const 36)
+   (i32.const 3)
+  )
+  (i32.store
+   (i32.const 40)
+   (i32.const 171)
+  )
+  (i32.store
+   (i32.const 44)
+   (i32.const 126)
+  )
+  (i32.store
+   (i32.const 48)
+   (i32.const 13)
+  )
+  (i32.store
+   (i32.const 52)
+   (i32.const 95)
+  )
+  (i32.store
+   (i32.const 56)
+   (i32.const 70)
+  )
+  (i32.store
+   (i32.const 60)
+   (i32.const 91)
+  )
+  (i32.store
+   (i32.const 64)
+   (i32.const 9)
+  )
+  (i32.store
+   (i32.const 68)
+   (i32.const 140)
+  )
+  (i32.store
+   (i32.const 72)
+   (i32.const 99)
+  )
+  (i32.store
+   (i32.const 76)
+   (i32.const 161)
+  )
+  (i32.store
+   (i32.const 80)
+   (i32.const 38)
+  )
+  (i32.store
+   (i32.const 84)
+   (i32.const 87)
+  )
+  (i32.store
+   (i32.const 88)
+   (i32.const 153)
+  )
+  (i32.store
+   (i32.const 92)
+   (i32.const 117)
+  )
+  (i32.store
+   (i32.const 96)
+   (i32.const 140)
+  )
+  (i32.store
+   (i32.const 100)
+   (i32.const 11)
+  )
+  (i32.store
+   (i32.const 104)
+   (i32.const 157)
+  )
+  (i32.store
+   (i32.const 108)
+   (i32.const 48)
+  )
+  (i32.store
+   (i32.const 112)
+   (i32.const 4)
+  )
+  (block
+   (block $block$2$break
+    (block
+     (call $print
+      (i32.const 0)
+     )
+     (local.set $0
+      (call $check)
+     )
+    )
+    (block
+     (i32.store
+      (i32.const 4)
+      (i32.add
+       (i32.load
+        (i32.const 4)
+       )
+       (i32.const 16)
+      )
+     )
+     (br $block$2$break)
+    )
+   )
+   (loop $shape$1$continue
+    (block
+     (call $print
+      (i32.const 0)
+     )
+     (local.set $0
+      (call $check)
+     )
+    )
+    (block
+     (i32.store
+      (i32.const 4)
+      (i32.add
+       (i32.load
+        (i32.const 4)
+       )
+       (i32.const 16)
+      )
+     )
+     (br $shape$1$continue)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/example/relooper-merge1.c b/binaryen/test/example/relooper-merge1.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-merge1.c
@@ -0,0 +1,214 @@
+#include <assert.h>
+#include <stdio.h>
+
+#include "binaryen-c.h"
+
+// globals: address 4 is index
+// decisions are at address 8+
+
+int main() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+
+  // check()
+
+  // if the end, halt
+  BinaryenExpressionRef halter = BinaryenIf(module,
+    BinaryenBinary(module,
+      BinaryenGeUInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4 * 12)) // jumps of 4 bytes
+    ),
+    BinaryenUnreachable(module),
+    NULL
+  );
+  // increment index
+  BinaryenExpressionRef incer = BinaryenStore(module,
+    4, 0, 0,
+    BinaryenConst(module, BinaryenLiteralInt32(4)),
+    BinaryenBinary(module,
+      BinaryenAddInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4))
+    ),
+    BinaryenTypeInt32()
+  );
+
+  // optionally, print the return value
+  BinaryenExpressionRef args[] = {
+    BinaryenBinary(module,
+      BinaryenSubInt32(),
+      BinaryenConst(module, BinaryenLiteralInt32(0)),
+      BinaryenLoad(module,
+        4, 0, 4, 0, BinaryenTypeInt32(),
+        BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4)))
+      )
+    )
+  };
+  BinaryenExpressionRef debugger;
+  if (1) debugger = BinaryenCall(module, "print", args, 1,
+                                 BinaryenTypeNone());
+  else debugger = BinaryenNop(module);
+
+  // return the decision. need to subtract 4 that we just added,
+  // and add 8 since that's where we start, so overall offset 4
+  BinaryenExpressionRef returner = BinaryenLoad(module,
+    4, 0, 4, 0, BinaryenTypeInt32(),
+    BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+    BinaryenConst(module, BinaryenLiteralInt32(4)))
+  );
+  BinaryenExpressionRef checkBodyList[] = { halter, incer, debugger,
+                                            returner };
+  BinaryenExpressionRef checkBody = BinaryenBlock(module,
+    NULL, checkBodyList, sizeof(checkBodyList) / sizeof(BinaryenExpressionRef),
+    BinaryenTypeInt32()
+  );
+  BinaryenAddFunction(module,
+                      "check",
+                      BinaryenTypeNone(),
+                      BinaryenTypeInt32(),
+                      NULL,
+                      0,
+                      checkBody);
+
+  // contents of main() begin here
+
+  RelooperRef relooper = RelooperCreate(module);
+
+
+  RelooperBlockRef b0;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(0))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b0 = RelooperAddBlockWithSwitch(relooper,
+      BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()),
+      BinaryenBinary(module,
+        BinaryenRemUInt32(),
+        BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+        BinaryenConst(module, BinaryenLiteralInt32(1))
+      )
+    );
+
+  }
+
+  RelooperBlockRef b1;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b1 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b2;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b2 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b3;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b3 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+  }
+
+  RelooperBlockRef b4;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b4 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+  }
+
+  // Separate branch for each.
+  // In this testcase, target blocks have identical contents (print 1),
+  // and branches have no phi codes, and no loops.
+  {
+    BinaryenIndex indexes[] = { 1, 4, 9 };
+    RelooperAddBranchForSwitch(b0, b1, indexes, 3, NULL);
+  }
+  {
+    BinaryenIndex indexes[] = { 3, 6 };
+    RelooperAddBranchForSwitch(b0, b2, indexes, 2, NULL);
+  }
+  {
+    BinaryenIndex indexes[] = { 5, 25, 125 };
+    RelooperAddBranchForSwitch(b0, b3, indexes, 3, NULL);
+  }
+  RelooperAddBranchForSwitch(b0, b4, NULL, 0, NULL);
+
+  BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, b0, 1);
+
+  // locals: state, free-for-label
+  BinaryenType localTypes[] = { BinaryenTypeInt32(), BinaryenTypeInt32() };
+  BinaryenFunctionRef theMain = BinaryenAddFunction(module,
+                                                    "main",
+                                                    BinaryenTypeNone(),
+                                                    BinaryenTypeNone(),
+                                                    localTypes,
+                                                    2,
+                                                    body);
+  BinaryenSetStart(module, theMain);
+
+  // import
+  BinaryenAddFunctionImport(module,
+                            "print",
+                            "spectest",
+                            "print",
+                            BinaryenTypeInt32(),
+                            BinaryenTypeNone());
+
+  // memory
+  BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL,  NULL, NULL, 0, 0);
+
+  // optionally, optimize
+  if (0) BinaryenModuleOptimize(module);
+
+  assert(BinaryenModuleValidate(module));
+
+  // write it out
+
+  BinaryenModulePrint(module);
+
+  BinaryenModuleDispose(module);
+
+  return 0;
+}
diff --git a/binaryen/test/example/relooper-merge1.txt b/binaryen/test/example/relooper-merge1.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-merge1.txt
@@ -0,0 +1,66 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "spectest" "print" (func $print (param i32)))
+ (memory $0 1 1)
+ (export "mem" (memory $0))
+ (start $main)
+ (func $check (result i32)
+  (if
+   (i32.ge_u
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 48)
+   )
+   (unreachable)
+  )
+  (i32.store
+   (i32.const 4)
+   (i32.add
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 4)
+   )
+  )
+  (call $print
+   (i32.sub
+    (i32.const 0)
+    (i32.load offset=4
+     (i32.load
+      (i32.const 4)
+     )
+    )
+   )
+  )
+  (i32.load offset=4
+   (i32.load
+    (i32.const 4)
+   )
+  )
+ )
+ (func $main
+  (local $0 i32)
+  (local $1 i32)
+  (block
+   (block
+    (call $print
+     (i32.const 0)
+    )
+    (local.set $0
+     (call $check)
+    )
+   )
+   (block
+    (call $print
+     (i32.const 1)
+    )
+    (local.set $0
+     (call $check)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/example/relooper-merge2.c b/binaryen/test/example/relooper-merge2.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-merge2.c
@@ -0,0 +1,226 @@
+#include <assert.h>
+#include <stdio.h>
+
+#include "binaryen-c.h"
+
+// globals: address 4 is index
+// decisions are at address 8+
+
+int main() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+
+  // check()
+
+  // if the end, halt
+  BinaryenExpressionRef halter = BinaryenIf(module,
+    BinaryenBinary(module,
+      BinaryenGeUInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4 * 12)) // jumps of 4 bytes
+    ),
+    BinaryenUnreachable(module),
+    NULL
+  );
+  // increment index
+  BinaryenExpressionRef incer = BinaryenStore(module,
+    4, 0, 0,
+    BinaryenConst(module, BinaryenLiteralInt32(4)),
+    BinaryenBinary(module,
+      BinaryenAddInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4))
+    ),
+    BinaryenTypeInt32()
+  );
+
+  // optionally, print the return value
+  BinaryenExpressionRef args[] = {
+    BinaryenBinary(module,
+      BinaryenSubInt32(),
+      BinaryenConst(module, BinaryenLiteralInt32(0)),
+      BinaryenLoad(module,
+        4, 0, 4, 0, BinaryenTypeInt32(),
+        BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4)))
+      )
+    )
+  };
+  BinaryenExpressionRef debugger;
+  if (1) debugger = BinaryenCall(module, "print", args, 1,
+                                 BinaryenTypeNone());
+  else debugger = BinaryenNop(module);
+
+  // return the decision. need to subtract 4 that we just added,
+  // and add 8 since that's where we start, so overall offset 4
+  BinaryenExpressionRef returner = BinaryenLoad(module,
+    4, 0, 4, 0, BinaryenTypeInt32(),
+    BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+    BinaryenConst(module, BinaryenLiteralInt32(4)))
+  );
+  BinaryenExpressionRef checkBodyList[] = { halter, incer, debugger,
+                                            returner };
+  BinaryenExpressionRef checkBody = BinaryenBlock(module,
+    NULL, checkBodyList, sizeof(checkBodyList) / sizeof(BinaryenExpressionRef),
+    BinaryenTypeInt32()
+  );
+  BinaryenAddFunction(module,
+                      "check",
+                      BinaryenTypeNone(),
+                      BinaryenTypeInt32(),
+                      NULL,
+                      0,
+                      checkBody);
+
+  // contents of main() begin here
+
+  RelooperRef relooper = RelooperCreate(module);
+
+
+  RelooperBlockRef b0;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(0))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b0 = RelooperAddBlockWithSwitch(relooper,
+      BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()),
+      BinaryenBinary(module,
+        BinaryenRemUInt32(),
+        BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+        BinaryenConst(module, BinaryenLiteralInt32(1))
+      )
+    );
+
+  }
+
+  RelooperBlockRef b1;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b1 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b2;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b2 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b3;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b3 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+  }
+
+  RelooperBlockRef b4;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b4 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+  }
+
+  // Separate branch for each.
+  // In this testcase, target blocks have identical contents (print 1),
+  // and branches have identical phis.
+  {
+    BinaryenIndex indexes[] = { 1, 4, 9 };
+    RelooperAddBranchForSwitch(b0, b1, indexes, 3,
+      BinaryenDrop(module,
+        BinaryenConst(module, BinaryenLiteralInt32(4))
+      )
+    );
+  }
+  {
+    BinaryenIndex indexes[] = { 3, 6 };
+    RelooperAddBranchForSwitch(b0, b2, indexes, 2,
+      BinaryenDrop(module,
+        BinaryenConst(module, BinaryenLiteralInt32(4))
+      )
+    );
+  }
+  {
+    BinaryenIndex indexes[] = { 5, 25, 125 };
+    RelooperAddBranchForSwitch(b0, b3, indexes, 3,
+      BinaryenDrop(module,
+        BinaryenConst(module, BinaryenLiteralInt32(4))
+      )
+    );
+  }
+  RelooperAddBranchForSwitch(b0, b4, NULL, 0, NULL);
+
+  BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, b0, 1);
+
+  // locals: state, free-for-label
+  BinaryenType localTypes[] = { BinaryenTypeInt32(), BinaryenTypeInt32() };
+  BinaryenFunctionRef theMain = BinaryenAddFunction(module,
+                                                    "main",
+                                                    BinaryenTypeNone(),
+                                                    BinaryenTypeNone(),
+                                                    localTypes,
+                                                    2,
+                                                    body);
+  BinaryenSetStart(module, theMain);
+
+  // import
+  BinaryenAddFunctionImport(module,
+                            "print",
+                            "spectest",
+                            "print",
+                            BinaryenTypeInt32(),
+                            BinaryenTypeNone());
+
+  // memory
+  BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+
+  // optionally, optimize
+  if (0) BinaryenModuleOptimize(module);
+
+  assert(BinaryenModuleValidate(module));
+
+  // write it out
+
+  BinaryenModulePrint(module);
+
+  BinaryenModuleDispose(module);
+
+  return 0;
+}
diff --git a/binaryen/test/example/relooper-merge2.txt b/binaryen/test/example/relooper-merge2.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-merge2.txt
@@ -0,0 +1,133 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "spectest" "print" (func $print (param i32)))
+ (memory $0 1 1)
+ (export "mem" (memory $0))
+ (start $main)
+ (func $check (result i32)
+  (if
+   (i32.ge_u
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 48)
+   )
+   (unreachable)
+  )
+  (i32.store
+   (i32.const 4)
+   (i32.add
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 4)
+   )
+  )
+  (call $print
+   (i32.sub
+    (i32.const 0)
+    (i32.load offset=4
+     (i32.load
+      (i32.const 4)
+     )
+    )
+   )
+  )
+  (i32.load offset=4
+   (i32.load
+    (i32.const 4)
+   )
+  )
+ )
+ (func $main
+  (local $0 i32)
+  (local $1 i32)
+  (block
+   (call $print
+    (i32.const 0)
+   )
+   (local.set $0
+    (call $check)
+   )
+  )
+  (block $switch$1$leave
+   (block $switch$1$default
+    (block $switch$1$case$4
+     (block $switch$1$case$3
+      (block $switch$1$case$2
+       (br_table $switch$1$default $switch$1$case$2 $switch$1$default $switch$1$case$3 $switch$1$case$2 $switch$1$case$4 $switch$1$case$3 $switch$1$default $switch$1$default $switch$1$case$2 $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$case$4 $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$default $switch$1$case$4 $switch$1$default
+        (i32.rem_u
+         (local.get $0)
+         (i32.const 1)
+        )
+       )
+      )
+      (block
+       (drop
+        (i32.const 4)
+       )
+       (block
+        (block
+         (call $print
+          (i32.const 1)
+         )
+         (local.set $0
+          (call $check)
+         )
+        )
+       )
+      )
+      (br $switch$1$leave)
+     )
+     (block
+      (drop
+       (i32.const 4)
+      )
+      (block
+       (block
+        (call $print
+         (i32.const 1)
+        )
+        (local.set $0
+         (call $check)
+        )
+       )
+      )
+     )
+     (br $switch$1$leave)
+    )
+    (block
+     (drop
+      (i32.const 4)
+     )
+     (block
+      (block
+       (call $print
+        (i32.const 1)
+       )
+       (local.set $0
+        (call $check)
+       )
+      )
+     )
+    )
+    (br $switch$1$leave)
+   )
+   (block
+    (block
+     (block
+      (call $print
+       (i32.const 1)
+      )
+      (local.set $0
+       (call $check)
+      )
+     )
+    )
+   )
+   (br $switch$1$leave)
+  )
+ )
+)
diff --git a/binaryen/test/example/relooper-merge3.c b/binaryen/test/example/relooper-merge3.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-merge3.c
@@ -0,0 +1,213 @@
+#include <assert.h>
+#include <stdio.h>
+
+#include "binaryen-c.h"
+
+// globals: address 4 is index
+// decisions are at address 8+
+
+int main() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+
+  // check()
+
+  // if the end, halt
+  BinaryenExpressionRef halter = BinaryenIf(module,
+    BinaryenBinary(module,
+      BinaryenGeUInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4 * 12)) // jumps of 4 bytes
+    ),
+    BinaryenUnreachable(module),
+    NULL
+  );
+  // increment index
+  BinaryenExpressionRef incer = BinaryenStore(module,
+    4, 0, 0,
+    BinaryenConst(module, BinaryenLiteralInt32(4)),
+    BinaryenBinary(module,
+      BinaryenAddInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4))
+    ),
+    BinaryenTypeInt32()
+  );
+
+  // optionally, print the return value
+  BinaryenExpressionRef args[] = {
+    BinaryenBinary(module,
+      BinaryenSubInt32(),
+      BinaryenConst(module, BinaryenLiteralInt32(0)),
+      BinaryenLoad(module,
+        4, 0, 4, 0, BinaryenTypeInt32(),
+        BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4)))
+      )
+    )
+  };
+  BinaryenExpressionRef debugger;
+  if (1) debugger = BinaryenCall(module, "print", args, 1,
+                                 BinaryenTypeNone());
+  else debugger = BinaryenNop(module);
+
+  // return the decision. need to subtract 4 that we just added,
+  // and add 8 since that's where we start, so overall offset 4
+  BinaryenExpressionRef returner = BinaryenLoad(module,
+    4, 0, 4, 0, BinaryenTypeInt32(),
+    BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+    BinaryenConst(module, BinaryenLiteralInt32(4)))
+  );
+  BinaryenExpressionRef checkBodyList[] = { halter, incer, debugger,
+                                            returner };
+  BinaryenExpressionRef checkBody = BinaryenBlock(module,
+    NULL, checkBodyList, sizeof(checkBodyList) / sizeof(BinaryenExpressionRef),
+    BinaryenTypeInt32()
+  );
+  BinaryenAddFunction(module,
+                      "check",
+                      BinaryenTypeNone(),
+                      BinaryenTypeInt32(),
+                      NULL,
+                      0,
+                      checkBody);
+
+  // contents of main() begin here
+
+  RelooperRef relooper = RelooperCreate(module);
+
+
+  RelooperBlockRef b0;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(0))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b0 = RelooperAddBlockWithSwitch(relooper,
+      BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()),
+      BinaryenBinary(module,
+        BinaryenRemUInt32(),
+        BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+        BinaryenConst(module, BinaryenLiteralInt32(1))
+      )
+    );
+
+  }
+
+  RelooperBlockRef b1;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b1 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b2;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b2 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b3;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(2))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b3 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+  }
+
+  RelooperBlockRef b4;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(3))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b4 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+  }
+
+  // Separate branch for each.
+  // In this testcase, two blocks out of 4 can be merged.
+  {
+    BinaryenIndex indexes[] = { 1, 4, 9 };
+    RelooperAddBranchForSwitch(b0, b1, indexes, 3, NULL);
+  }
+  {
+    BinaryenIndex indexes[] = { 3, 6 };
+    RelooperAddBranchForSwitch(b0, b2, indexes, 2, NULL);
+  }
+  {
+    BinaryenIndex indexes[] = { 5 };
+    RelooperAddBranchForSwitch(b0, b3, indexes, 1, NULL);
+  }
+  RelooperAddBranchForSwitch(b0, b4, NULL, 0, NULL);
+
+  BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, b0, 1);
+
+  // locals: state, free-for-label
+  BinaryenType localTypes[] = { BinaryenTypeInt32(), BinaryenTypeInt32() };
+  BinaryenFunctionRef theMain = BinaryenAddFunction(module,
+                                                    "main",
+                                                    BinaryenTypeNone(),
+                                                    BinaryenTypeNone(),
+                                                    localTypes,
+                                                    2,
+                                                    body);
+  BinaryenSetStart(module, theMain);
+
+  // import
+  BinaryenAddFunctionImport(module,
+                            "print",
+                            "spectest",
+                            "print",
+                            BinaryenTypeInt32(),
+                            BinaryenTypeNone());
+
+  // memory
+  BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+
+  // optionally, optimize
+  if (0) BinaryenModuleOptimize(module);
+
+  assert(BinaryenModuleValidate(module));
+
+  // write it out
+
+  BinaryenModulePrint(module);
+
+  BinaryenModuleDispose(module);
+
+  return 0;
+}
diff --git a/binaryen/test/example/relooper-merge3.txt b/binaryen/test/example/relooper-merge3.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-merge3.txt
@@ -0,0 +1,109 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "spectest" "print" (func $print (param i32)))
+ (memory $0 1 1)
+ (export "mem" (memory $0))
+ (start $main)
+ (func $check (result i32)
+  (if
+   (i32.ge_u
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 48)
+   )
+   (unreachable)
+  )
+  (i32.store
+   (i32.const 4)
+   (i32.add
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 4)
+   )
+  )
+  (call $print
+   (i32.sub
+    (i32.const 0)
+    (i32.load offset=4
+     (i32.load
+      (i32.const 4)
+     )
+    )
+   )
+  )
+  (i32.load offset=4
+   (i32.load
+    (i32.const 4)
+   )
+  )
+ )
+ (func $main
+  (local $0 i32)
+  (local $1 i32)
+  (block
+   (call $print
+    (i32.const 0)
+   )
+   (local.set $0
+    (call $check)
+   )
+  )
+  (block $switch$1$leave
+   (block $switch$1$default
+    (block $switch$1$case$4
+     (block $switch$1$case$2
+      (br_table $switch$1$default $switch$1$case$2 $switch$1$default $switch$1$case$2 $switch$1$case$2 $switch$1$case$4 $switch$1$case$2 $switch$1$default $switch$1$default $switch$1$case$2 $switch$1$default
+       (i32.rem_u
+        (local.get $0)
+        (i32.const 1)
+       )
+      )
+     )
+     (block
+      (block
+       (block
+        (call $print
+         (i32.const 1)
+        )
+        (local.set $0
+         (call $check)
+        )
+       )
+      )
+     )
+     (br $switch$1$leave)
+    )
+    (block
+     (block
+      (block
+       (call $print
+        (i32.const 2)
+       )
+       (local.set $0
+        (call $check)
+       )
+      )
+     )
+    )
+    (br $switch$1$leave)
+   )
+   (block
+    (block
+     (block
+      (call $print
+       (i32.const 3)
+      )
+      (local.set $0
+       (call $check)
+      )
+     )
+    )
+   )
+   (br $switch$1$leave)
+  )
+ )
+)
diff --git a/binaryen/test/example/relooper-merge4.c b/binaryen/test/example/relooper-merge4.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-merge4.c
@@ -0,0 +1,213 @@
+#include <assert.h>
+#include <stdio.h>
+
+#include "binaryen-c.h"
+
+// globals: address 4 is index
+// decisions are at address 8+
+
+int main() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+
+  // check()
+
+  // if the end, halt
+  BinaryenExpressionRef halter = BinaryenIf(module,
+    BinaryenBinary(module,
+      BinaryenGeUInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4 * 12)) // jumps of 4 bytes
+    ),
+    BinaryenUnreachable(module),
+    NULL
+  );
+  // increment index
+  BinaryenExpressionRef incer = BinaryenStore(module,
+    4, 0, 0,
+    BinaryenConst(module, BinaryenLiteralInt32(4)),
+    BinaryenBinary(module,
+      BinaryenAddInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4))
+    ),
+    BinaryenTypeInt32()
+  );
+
+  // optionally, print the return value
+  BinaryenExpressionRef args[] = {
+    BinaryenBinary(module,
+      BinaryenSubInt32(),
+      BinaryenConst(module, BinaryenLiteralInt32(0)),
+      BinaryenLoad(module,
+        4, 0, 4, 0, BinaryenTypeInt32(),
+        BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4)))
+      )
+    )
+  };
+  BinaryenExpressionRef debugger;
+  if (1) debugger = BinaryenCall(module, "print", args, 1,
+                                 BinaryenTypeNone());
+  else debugger = BinaryenNop(module);
+
+  // return the decision. need to subtract 4 that we just added,
+  // and add 8 since that's where we start, so overall offset 4
+  BinaryenExpressionRef returner = BinaryenLoad(module,
+    4, 0, 4, 0, BinaryenTypeInt32(),
+    BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+    BinaryenConst(module, BinaryenLiteralInt32(4)))
+  );
+  BinaryenExpressionRef checkBodyList[] = { halter, incer, debugger,
+                                            returner };
+  BinaryenExpressionRef checkBody = BinaryenBlock(module,
+    NULL, checkBodyList, sizeof(checkBodyList) / sizeof(BinaryenExpressionRef),
+    BinaryenTypeInt32()
+  );
+  BinaryenAddFunction(module,
+                      "check",
+                      BinaryenTypeNone(),
+                      BinaryenTypeInt32(),
+                      NULL,
+                      0,
+                      checkBody);
+
+  // contents of main() begin here
+
+  RelooperRef relooper = RelooperCreate(module);
+
+
+  RelooperBlockRef b0;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(0))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b0 = RelooperAddBlockWithSwitch(relooper,
+      BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()),
+      BinaryenBinary(module,
+        BinaryenRemUInt32(),
+        BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+        BinaryenConst(module, BinaryenLiteralInt32(1))
+      )
+    );
+
+  }
+
+  RelooperBlockRef b1;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b1 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b2;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b2 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b3;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(2))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b3 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+  }
+
+  RelooperBlockRef b4;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(3))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b4 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+  }
+
+  // Separate branch for each.
+  // In this testcase, two blocks out of 4 can be merged.
+  {
+    BinaryenIndex indexes[] = { 1, 4, 9 };
+    RelooperAddBranchForSwitch(b0, b4, indexes, 3, NULL);
+  }
+  {
+    BinaryenIndex indexes[] = { 3, 6 };
+    RelooperAddBranchForSwitch(b0, b2, indexes, 2, NULL);
+  }
+  {
+    BinaryenIndex indexes[] = { 5 };
+    RelooperAddBranchForSwitch(b0, b3, indexes, 1, NULL);
+  }
+  RelooperAddBranchForSwitch(b0, b1, NULL, 0, NULL);
+
+  BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, b0, 1);
+
+  // locals: state, free-for-label
+  BinaryenType localTypes[] = { BinaryenTypeInt32(), BinaryenTypeInt32() };
+  BinaryenFunctionRef theMain = BinaryenAddFunction(module,
+                                                    "main",
+                                                    BinaryenTypeNone(),
+                                                    BinaryenTypeNone(),
+                                                    localTypes,
+                                                    2,
+                                                    body);
+  BinaryenSetStart(module, theMain);
+
+  // import
+  BinaryenAddFunctionImport(module,
+                            "print",
+                            "spectest",
+                            "print",
+                            BinaryenTypeInt32(),
+                            BinaryenTypeNone());
+
+  // memory
+  BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+
+  // optionally, optimize
+  if (0) BinaryenModuleOptimize(module);
+
+  assert(BinaryenModuleValidate(module));
+
+  // write it out
+
+  BinaryenModulePrint(module);
+
+  BinaryenModuleDispose(module);
+
+  return 0;
+}
diff --git a/binaryen/test/example/relooper-merge4.txt b/binaryen/test/example/relooper-merge4.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-merge4.txt
@@ -0,0 +1,109 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "spectest" "print" (func $print (param i32)))
+ (memory $0 1 1)
+ (export "mem" (memory $0))
+ (start $main)
+ (func $check (result i32)
+  (if
+   (i32.ge_u
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 48)
+   )
+   (unreachable)
+  )
+  (i32.store
+   (i32.const 4)
+   (i32.add
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 4)
+   )
+  )
+  (call $print
+   (i32.sub
+    (i32.const 0)
+    (i32.load offset=4
+     (i32.load
+      (i32.const 4)
+     )
+    )
+   )
+  )
+  (i32.load offset=4
+   (i32.load
+    (i32.const 4)
+   )
+  )
+ )
+ (func $main
+  (local $0 i32)
+  (local $1 i32)
+  (block
+   (call $print
+    (i32.const 0)
+   )
+   (local.set $0
+    (call $check)
+   )
+  )
+  (block $switch$1$leave
+   (block $switch$1$case$4
+    (block $switch$1$default
+     (block $switch$1$case$5
+      (br_table $switch$1$default $switch$1$case$5 $switch$1$default $switch$1$default $switch$1$case$5 $switch$1$case$4 $switch$1$default $switch$1$default $switch$1$default $switch$1$case$5 $switch$1$default
+       (i32.rem_u
+        (local.get $0)
+        (i32.const 1)
+       )
+      )
+     )
+     (block
+      (block
+       (block
+        (call $print
+         (i32.const 3)
+        )
+        (local.set $0
+         (call $check)
+        )
+       )
+      )
+     )
+     (br $switch$1$leave)
+    )
+    (block
+     (block
+      (block
+       (call $print
+        (i32.const 1)
+       )
+       (local.set $0
+        (call $check)
+       )
+      )
+     )
+    )
+    (br $switch$1$leave)
+   )
+   (block
+    (block
+     (block
+      (call $print
+       (i32.const 2)
+      )
+      (local.set $0
+       (call $check)
+      )
+     )
+    )
+   )
+   (br $switch$1$leave)
+  )
+ )
+)
diff --git a/binaryen/test/example/relooper-merge5.c b/binaryen/test/example/relooper-merge5.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-merge5.c
@@ -0,0 +1,213 @@
+#include <assert.h>
+#include <stdio.h>
+
+#include "binaryen-c.h"
+
+// globals: address 4 is index
+// decisions are at address 8+
+
+int main() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+
+  // check()
+
+  // if the end, halt
+  BinaryenExpressionRef halter = BinaryenIf(module,
+    BinaryenBinary(module,
+      BinaryenGeUInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4 * 12)) // jumps of 4 bytes
+    ),
+    BinaryenUnreachable(module),
+    NULL
+  );
+  // increment index
+  BinaryenExpressionRef incer = BinaryenStore(module,
+    4, 0, 0,
+    BinaryenConst(module, BinaryenLiteralInt32(4)),
+    BinaryenBinary(module,
+      BinaryenAddInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4))
+    ),
+    BinaryenTypeInt32()
+  );
+
+  // optionally, print the return value
+  BinaryenExpressionRef args[] = {
+    BinaryenBinary(module,
+      BinaryenSubInt32(),
+      BinaryenConst(module, BinaryenLiteralInt32(0)),
+      BinaryenLoad(module,
+        4, 0, 4, 0, BinaryenTypeInt32(),
+        BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4)))
+      )
+    )
+  };
+  BinaryenExpressionRef debugger;
+  if (1) debugger = BinaryenCall(module, "print", args, 1,
+                                 BinaryenTypeNone());
+  else debugger = BinaryenNop(module);
+
+  // return the decision. need to subtract 4 that we just added,
+  // and add 8 since that's where we start, so overall offset 4
+  BinaryenExpressionRef returner = BinaryenLoad(module,
+    4, 0, 4, 0, BinaryenTypeInt32(),
+    BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+    BinaryenConst(module, BinaryenLiteralInt32(4)))
+  );
+  BinaryenExpressionRef checkBodyList[] = { halter, incer, debugger,
+                                            returner };
+  BinaryenExpressionRef checkBody = BinaryenBlock(module,
+    NULL, checkBodyList, sizeof(checkBodyList) / sizeof(BinaryenExpressionRef),
+    BinaryenTypeInt32()
+  );
+  BinaryenAddFunction(module,
+                      "check",
+                      BinaryenTypeNone(),
+                      BinaryenTypeInt32(),
+                      NULL,
+                      0,
+                      checkBody);
+
+  // contents of main() begin here
+
+  RelooperRef relooper = RelooperCreate(module);
+
+
+  RelooperBlockRef b0;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(0))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b0 = RelooperAddBlockWithSwitch(relooper,
+      BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()),
+      BinaryenBinary(module,
+        BinaryenRemUInt32(),
+        BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+        BinaryenConst(module, BinaryenLiteralInt32(1))
+      )
+    );
+
+  }
+
+  RelooperBlockRef b1;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b1 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b2;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b2 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b3;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(2))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b3 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+  }
+
+  RelooperBlockRef b4;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(3))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b4 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+  }
+
+  // Separate branch for each.
+  // In this testcase, two blocks out of 4 can be merged.
+  RelooperAddBranchForSwitch(b0, b1, NULL, 0, NULL);
+  {
+    BinaryenIndex indexes[] = { 1, 4, 9 };
+    RelooperAddBranchForSwitch(b0, b4, indexes, 3, NULL);
+  }
+  {
+    BinaryenIndex indexes[] = { 3, 6 };
+    RelooperAddBranchForSwitch(b0, b2, indexes, 2, NULL);
+  }
+  {
+    BinaryenIndex indexes[] = { 5 };
+    RelooperAddBranchForSwitch(b0, b3, indexes, 1, NULL);
+  }
+
+  BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, b0, 1);
+
+  // locals: state, free-for-label
+  BinaryenType localTypes[] = { BinaryenTypeInt32(), BinaryenTypeInt32() };
+  BinaryenFunctionRef theMain = BinaryenAddFunction(module,
+                                                    "main",
+                                                    BinaryenTypeNone(),
+                                                    BinaryenTypeNone(),
+                                                    localTypes,
+                                                    2,
+                                                    body);
+  BinaryenSetStart(module, theMain);
+
+  // import
+  BinaryenAddFunctionImport(module,
+                            "print",
+                            "spectest",
+                            "print",
+                            BinaryenTypeInt32(),
+                            BinaryenTypeNone());
+
+  // memory
+  BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+
+  // optionally, optimize
+  if (0) BinaryenModuleOptimize(module);
+
+  assert(BinaryenModuleValidate(module));
+
+  // write it out
+
+  BinaryenModulePrint(module);
+
+  BinaryenModuleDispose(module);
+
+  return 0;
+}
diff --git a/binaryen/test/example/relooper-merge5.txt b/binaryen/test/example/relooper-merge5.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-merge5.txt
@@ -0,0 +1,109 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "spectest" "print" (func $print (param i32)))
+ (memory $0 1 1)
+ (export "mem" (memory $0))
+ (start $main)
+ (func $check (result i32)
+  (if
+   (i32.ge_u
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 48)
+   )
+   (unreachable)
+  )
+  (i32.store
+   (i32.const 4)
+   (i32.add
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 4)
+   )
+  )
+  (call $print
+   (i32.sub
+    (i32.const 0)
+    (i32.load offset=4
+     (i32.load
+      (i32.const 4)
+     )
+    )
+   )
+  )
+  (i32.load offset=4
+   (i32.load
+    (i32.const 4)
+   )
+  )
+ )
+ (func $main
+  (local $0 i32)
+  (local $1 i32)
+  (block
+   (call $print
+    (i32.const 0)
+   )
+   (local.set $0
+    (call $check)
+   )
+  )
+  (block $switch$1$leave
+   (block $switch$1$case$4
+    (block $switch$1$case$5
+     (block $switch$1$default
+      (br_table $switch$1$default $switch$1$case$5 $switch$1$default $switch$1$default $switch$1$case$5 $switch$1$case$4 $switch$1$default $switch$1$default $switch$1$default $switch$1$case$5 $switch$1$default
+       (i32.rem_u
+        (local.get $0)
+        (i32.const 1)
+       )
+      )
+     )
+     (block
+      (block
+       (block
+        (call $print
+         (i32.const 1)
+        )
+        (local.set $0
+         (call $check)
+        )
+       )
+      )
+     )
+     (br $switch$1$leave)
+    )
+    (block
+     (block
+      (block
+       (call $print
+        (i32.const 3)
+       )
+       (local.set $0
+        (call $check)
+       )
+      )
+     )
+    )
+    (br $switch$1$leave)
+   )
+   (block
+    (block
+     (block
+      (call $print
+       (i32.const 2)
+      )
+      (local.set $0
+       (call $check)
+      )
+     )
+    )
+   )
+   (br $switch$1$leave)
+  )
+ )
+)
diff --git a/binaryen/test/example/relooper-merge6.c b/binaryen/test/example/relooper-merge6.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-merge6.c
@@ -0,0 +1,204 @@
+#include <assert.h>
+#include <stdio.h>
+
+#include "binaryen-c.h"
+
+// globals: address 4 is index
+// decisions are at address 8+
+
+int main() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+
+  // check()
+
+  // if the end, halt
+  BinaryenExpressionRef halter = BinaryenIf(module,
+    BinaryenBinary(module,
+      BinaryenGeUInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4 * 12)) // jumps of 4 bytes
+    ),
+    BinaryenUnreachable(module),
+    NULL
+  );
+  // increment index
+  BinaryenExpressionRef incer = BinaryenStore(module,
+    4, 0, 0,
+    BinaryenConst(module, BinaryenLiteralInt32(4)),
+    BinaryenBinary(module,
+      BinaryenAddInt32(),
+      BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                   BinaryenConst(module, BinaryenLiteralInt32(4))),
+      BinaryenConst(module, BinaryenLiteralInt32(4))
+    ),
+    BinaryenTypeInt32()
+  );
+
+  // optionally, print the return value
+  BinaryenExpressionRef args[] = {
+    BinaryenBinary(module,
+      BinaryenSubInt32(),
+      BinaryenConst(module, BinaryenLiteralInt32(0)),
+      BinaryenLoad(module,
+        4, 0, 4, 0, BinaryenTypeInt32(),
+        BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+                     BinaryenConst(module, BinaryenLiteralInt32(4)))
+      )
+    )
+  };
+  BinaryenExpressionRef debugger;
+  if (1) debugger = BinaryenCall(module, "print", args, 1,
+                                 BinaryenTypeNone());
+  else debugger = BinaryenNop(module);
+
+  // return the decision. need to subtract 4 that we just added,
+  // and add 8 since that's where we start, so overall offset 4
+  BinaryenExpressionRef returner = BinaryenLoad(module,
+    4, 0, 4, 0, BinaryenTypeInt32(),
+    BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(),
+    BinaryenConst(module, BinaryenLiteralInt32(4)))
+  );
+  BinaryenExpressionRef checkBodyList[] = { halter, incer, debugger,
+                                            returner };
+  BinaryenExpressionRef checkBody = BinaryenBlock(module,
+    NULL, checkBodyList, sizeof(checkBodyList) / sizeof(BinaryenExpressionRef),
+    BinaryenTypeInt32()
+  );
+  BinaryenAddFunction(module,
+                      "check",
+                      BinaryenTypeNone(),
+                      BinaryenTypeInt32(),
+                      NULL,
+                      0,
+                      checkBody);
+
+  // contents of main() begin here
+
+  RelooperRef relooper = RelooperCreate(module);
+
+
+  RelooperBlockRef b0;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(0))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b0 = RelooperAddBlockWithSwitch(relooper,
+      BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()),
+      BinaryenBinary(module,
+        BinaryenRemUInt32(),
+        BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
+        BinaryenConst(module, BinaryenLiteralInt32(1))
+      )
+    );
+
+  }
+
+  RelooperBlockRef b1;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b1 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b2;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b2 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+
+  }
+
+  RelooperBlockRef b3;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b3 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+  }
+
+  RelooperBlockRef b4;
+  {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(1))
+    };
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenLocalSet(module, 0, BinaryenCall(module, "check", NULL, 0,
+                                               BinaryenTypeInt32()))
+    };
+
+    b4 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
+  }
+
+  // Separate branch for each.
+  // In this testcase, we can merge multiple consecutive blocks with phis.
+  RelooperAddBranch(b0, b1, NULL, BinaryenDrop(module, BinaryenConst(module, BinaryenLiteralInt32(10))));
+  RelooperAddBranch(b1, b2, NULL, BinaryenDrop(module, BinaryenConst(module, BinaryenLiteralInt32(11))));
+  RelooperAddBranch(b2, b3, NULL, NULL);
+  RelooperAddBranch(b3, b4, NULL, BinaryenDrop(module, BinaryenConst(module, BinaryenLiteralInt32(12))));
+
+  BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, b0, 1);
+
+  // locals: state, free-for-label
+  BinaryenType localTypes[] = { BinaryenTypeInt32(), BinaryenTypeInt32() };
+  BinaryenFunctionRef theMain = BinaryenAddFunction(module,
+                                                    "main",
+                                                    BinaryenTypeNone(),
+                                                    BinaryenTypeNone(),
+                                                    localTypes,
+                                                    2,
+                                                    body);
+  BinaryenSetStart(module, theMain);
+
+  // import
+  BinaryenAddFunctionImport(module,
+                            "print",
+                            "spectest",
+                            "print",
+                            BinaryenTypeInt32(),
+                            BinaryenTypeNone());
+
+  // memory
+  BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+
+  // optionally, optimize
+  if (0) BinaryenModuleOptimize(module);
+
+  assert(BinaryenModuleValidate(module));
+
+  // write it out
+
+  BinaryenModulePrint(module);
+
+  BinaryenModuleDispose(module);
+
+  return 0;
+}
diff --git a/binaryen/test/example/relooper-merge6.txt b/binaryen/test/example/relooper-merge6.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-merge6.txt
@@ -0,0 +1,111 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "spectest" "print" (func $print (param i32)))
+ (memory $0 1 1)
+ (export "mem" (memory $0))
+ (start $main)
+ (func $check (result i32)
+  (if
+   (i32.ge_u
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 48)
+   )
+   (unreachable)
+  )
+  (i32.store
+   (i32.const 4)
+   (i32.add
+    (i32.load
+     (i32.const 4)
+    )
+    (i32.const 4)
+   )
+  )
+  (call $print
+   (i32.sub
+    (i32.const 0)
+    (i32.load offset=4
+     (i32.load
+      (i32.const 4)
+     )
+    )
+   )
+  )
+  (i32.load offset=4
+   (i32.load
+    (i32.const 4)
+   )
+  )
+ )
+ (func $main
+  (local $0 i32)
+  (local $1 i32)
+  (block
+   (block
+    (block
+     (block
+      (block
+       (block
+        (block
+         (call $print
+          (i32.const 0)
+         )
+         (local.set $0
+          (call $check)
+         )
+        )
+        (drop
+         (i32.const 10)
+        )
+       )
+       (block
+        (call $print
+         (i32.const 1)
+        )
+        (local.set $0
+         (call $check)
+        )
+       )
+      )
+      (drop
+       (i32.const 11)
+      )
+     )
+     (block
+      (block
+       (call $print
+        (i32.const 1)
+       )
+       (local.set $0
+        (call $check)
+       )
+      )
+      (block
+       (call $print
+        (i32.const 1)
+       )
+       (local.set $0
+        (call $check)
+       )
+      )
+     )
+    )
+    (drop
+     (i32.const 12)
+    )
+   )
+   (block
+    (call $print
+     (i32.const 1)
+    )
+    (local.set $0
+     (call $check)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/example/relooper-merge7.c b/binaryen/test/example/relooper-merge7.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-merge7.c
@@ -0,0 +1,49 @@
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "binaryen-c.h"
+
+int main() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+
+  RelooperRef relooper = RelooperCreate(module);
+
+  // Create the basic blocks
+  RelooperBlockRef b[4];
+  int hasTerminator[4] = {0, 0, 0, 1};
+
+  int numBlocks = sizeof(b) / sizeof(RelooperBlockRef);
+  assert(sizeof(hasTerminator) / sizeof(int) == numBlocks);
+  int i;
+  for (i = 0; i < numBlocks; i++) {
+    BinaryenExpressionRef args[] = {
+      BinaryenConst(module, BinaryenLiteralInt32(i))};
+    BinaryenExpressionRef list[] = {
+      BinaryenCall(module, "print", args, 1, BinaryenTypeNone()),
+      BinaryenReturn(module, NULL) // relevant only if hasTerminator[i]
+    };
+    b[i] = RelooperAddBlock(
+      relooper,
+      BinaryenBlock(
+        module, NULL, list, 1 + hasTerminator[i], BinaryenTypeNone()));
+  }
+
+  // Create the branches.
+  // In this testcase, only b[2] and b[3] can be merged.
+  RelooperAddBranch(b[0], b[1], NULL, NULL);
+  RelooperAddBranch(
+    b[0], b[2], BinaryenConst(module, BinaryenLiteralInt32(-10)), NULL);
+  RelooperAddBranch(b[1], b[0], NULL, NULL);
+  RelooperAddBranch(b[2], b[3], NULL, NULL);
+
+  BinaryenExpressionRef all = RelooperRenderAndDispose(relooper, b[0], 1);
+
+  // Print it out
+  BinaryenExpressionPrint(all);
+
+  // Clean up the module, which owns all the objects we created above
+  BinaryenModuleDispose(module);
+
+  return 0;
+}
diff --git a/binaryen/test/example/relooper-merge7.txt b/binaryen/test/example/relooper-merge7.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/relooper-merge7.txt
@@ -0,0 +1,37 @@
+(block
+ (block $block$3$break
+  (loop $shape$0$continue
+   (block $block$2$break
+    (call $print
+     (i32.const 0)
+    )
+    (if
+     (i32.const -10)
+     (br $block$3$break)
+     (br $block$2$break)
+    )
+   )
+   (block
+    (call $print
+     (i32.const 1)
+    )
+    (block
+     (br $shape$0$continue)
+    )
+   )
+  )
+ )
+ (block
+  (block
+   (call $print
+    (i32.const 2)
+   )
+   (block
+    (call $print
+     (i32.const 3)
+    )
+    (return)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/example/small_vector.cpp b/binaryen/test/example/small_vector.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/small_vector.cpp
@@ -0,0 +1,68 @@
+#include <iostream>
+#include <cassert>
+
+#include "support/small_vector.h"
+
+using namespace wasm;
+
+template<typename T>
+void test() {
+  {
+    T t;
+    // build up
+    assert(t.empty());
+    assert(t.size() == 0);
+    t.push_back(1);
+    assert(!t.empty());
+    assert(t.size() == 1);
+    t.push_back(2);
+    assert(!t.empty());
+    assert(t.size() == 2);
+    t.push_back(3);
+    assert(!t.empty());
+    // unwind
+    assert(t.size() == 3);
+    assert(t.back() == 3);
+    t.pop_back();
+    assert(t.size() == 2);
+    assert(t.back() == 2);
+    t.pop_back();
+    assert(t.size() == 1);
+    assert(t.back() == 1);
+    t.pop_back();
+    assert(t.size() == 0);
+    assert(t.empty());
+  }
+  {
+    T t;
+    // build up
+    t.push_back(1);
+    t.push_back(2);
+    t.push_back(3);
+    // unwind
+    t.clear();
+    assert(t.size() == 0);
+    assert(t.empty());
+  }
+  {
+    T t, u;
+    assert(t == u);
+    t.push_back(1);
+    assert(t != u);
+    u.push_back(1);
+    assert(t == u);
+    u.pop_back();
+    assert(t != u);
+    u.push_back(2);
+    assert(t != u);
+  }
+}
+
+int main() {
+  test<SmallVector<int, 0>>();
+  test<SmallVector<int, 1>>();
+  test<SmallVector<int, 2>>();
+  test<SmallVector<int, 10>>();
+  std::cout << "ok.\n";
+}
+
diff --git a/binaryen/test/example/small_vector.txt b/binaryen/test/example/small_vector.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/small_vector.txt
@@ -0,0 +1,1 @@
+ok.
diff --git a/binaryen/test/example/stack-utils.cpp b/binaryen/test/example/stack-utils.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/stack-utils.cpp
@@ -0,0 +1,443 @@
+#include <cassert>
+#include <iostream>
+
+#include "ir/stack-utils.h"
+#include "literal.h"
+#include "mixed_arena.h"
+#include "wasm-builder.h"
+#include "wasm-printing.h"
+#include "wasm-type.h"
+#include "wasm.h"
+
+using namespace wasm;
+
+Module module;
+Builder builder(module);
+
+void test_remove_nops() {
+  std::cout << ";; Test removeNops\n";
+  auto* block = builder.makeBlock(
+    {
+      builder.makeNop(),
+      builder.makeConst(Literal(int32_t(0))),
+      builder.makeNop(),
+      builder.makeConst(Literal(int64_t(0))),
+      builder.makeNop(),
+      builder.makeNop(),
+    },
+    {Type::i32, Type::i64});
+  WasmPrinter::printExpression(block, std::cout);
+  std::cout << "\n";
+  StackUtils::removeNops(block);
+  WasmPrinter::printExpression(block, std::cout);
+  std::cout << "\n";
+}
+
+void test_stack_signatures() {
+  std::cout << ";; Test stack signatures\n";
+  // Typed block
+  auto* block = builder.makeBlock({builder.makeUnreachable()}, Type::f32);
+  assert(StackSignature(block) ==
+         (StackSignature{Type::none, Type::f32, false}));
+  // Unreachable block
+  auto* unreachable =
+    builder.makeBlock({builder.makeUnreachable()}, Type::unreachable);
+  assert(StackSignature(unreachable) ==
+         (StackSignature{Type::none, Type::none, true}));
+  {
+    // Typed loop
+    auto* loop = builder.makeLoop("loop", unreachable, Type::f32);
+    assert(StackSignature(loop) ==
+           (StackSignature{Type::none, Type::f32, false}));
+  }
+  {
+    // Unreachable loop
+    auto* loop = builder.makeLoop("loop", unreachable, Type::unreachable);
+    assert(StackSignature(loop) ==
+           (StackSignature{Type::none, Type::none, true}));
+  }
+  {
+    // If (no else)
+    auto* if_ = builder.makeIf(
+      builder.makePop(Type::i32), unreachable, nullptr, Type::none);
+    assert(StackSignature(if_) ==
+           (StackSignature{Type::i32, Type::none, false}));
+  }
+  {
+    // If (with else)
+    auto* if_ =
+      builder.makeIf(builder.makePop(Type::i32), block, block, Type::f32);
+    assert(StackSignature(if_) ==
+           (StackSignature{Type::i32, Type::f32, false}));
+  }
+  {
+    // Call
+    auto* call =
+      builder.makeCall("foo",
+                       {builder.makePop(Type::i32), builder.makePop(Type::f32)},
+                       {Type::i64, Type::f64});
+    assert(
+      StackSignature(call) ==
+      (StackSignature{{Type::i32, Type::f32}, {Type::i64, Type::f64}, false}));
+  }
+  {
+    // Return Call
+    auto* call =
+      builder.makeCall("bar",
+                       {builder.makePop(Type::i32), builder.makePop(Type::f32)},
+                       Type::unreachable,
+                       true);
+    assert(StackSignature(call) ==
+           (StackSignature{{Type::i32, Type::f32}, Type::none, true}));
+  }
+  {
+    // Return
+    auto* ret = builder.makeReturn(builder.makePop(Type::i32));
+    assert(StackSignature(ret) ==
+           (StackSignature{Type::i32, Type::none, true}));
+  }
+  {
+    // Multivalue return
+    auto* ret = builder.makeReturn(builder.makePop({Type::i32, Type::f32}));
+    assert(StackSignature(ret) ==
+           (StackSignature{{Type::i32, Type::f32}, Type::none, true}));
+  }
+}
+
+void test_signature_composition() {
+  std::cout << ";; Test stack signature composition\n";
+  // No unreachables
+  {
+    StackSignature a{Type::none, {Type::f32, Type::i32}, false};
+    StackSignature b{{Type::f32, Type::i32}, Type::none, false};
+    assert(a.composes(b));
+    assert(a + b == (StackSignature{Type::none, Type::none, false}));
+  }
+  {
+    StackSignature a{Type::none, Type::i32, false};
+    StackSignature b{{Type::f32, Type::i32}, Type::none, false};
+    assert(a.composes(b));
+    assert(a + b == StackSignature(Type::f32, Type::none, false));
+  }
+  {
+    StackSignature a{Type::none, {Type::f32, Type::i32}, false};
+    StackSignature b{Type::i32, Type::none, false};
+    assert(a.composes(b));
+    assert(a + b == (StackSignature{Type::none, Type::f32, false}));
+  }
+  {
+    StackSignature a{Type::none, Type::f32, false};
+    StackSignature b{{Type::f32, Type::i32}, Type::none, false};
+    assert(!a.composes(b));
+  }
+  {
+    StackSignature a{Type::none, {Type::f32, Type::i32}, false};
+    StackSignature b{Type::f32, Type::none, false};
+    assert(!a.composes(b));
+  }
+  // First unreachable
+  {
+    StackSignature a{Type::none, {Type::f32, Type::i32}, true};
+    StackSignature b{{Type::f32, Type::i32}, Type::none, false};
+    assert(a.composes(b));
+    assert(a + b == (StackSignature{Type::none, Type::none, true}));
+  }
+  {
+    StackSignature a{Type::none, Type::i32, true};
+    StackSignature b{{Type::f32, Type::i32}, Type::none, false};
+    assert(a.composes(b));
+    assert(a + b == StackSignature(Type::none, Type::none, true));
+  }
+  {
+    StackSignature a{Type::none, {Type::f32, Type::i32}, true};
+    StackSignature b{Type::i32, Type::none, false};
+    assert(a.composes(b));
+    assert(a + b == (StackSignature{Type::none, Type::f32, true}));
+  }
+  {
+    StackSignature a{Type::none, Type::f32, true};
+    StackSignature b{{Type::f32, Type::i32}, Type::none, false};
+    assert(!a.composes(b));
+  }
+  {
+    StackSignature a{Type::none, {Type::f32, Type::i32}, true};
+    StackSignature b{Type::f32, Type::none, false};
+    assert(!a.composes(b));
+  }
+  // Second unreachable
+  {
+    StackSignature a{Type::none, {Type::f32, Type::i32}, false};
+    StackSignature b{{Type::f32, Type::i32}, Type::none, true};
+    assert(a.composes(b));
+    assert(a + b == (StackSignature{Type::none, Type::none, true}));
+  }
+  {
+    StackSignature a{Type::none, Type::i32, false};
+    StackSignature b{{Type::f32, Type::i32}, Type::none, true};
+    assert(a.composes(b));
+    assert(a + b == StackSignature(Type::f32, Type::none, true));
+  }
+  {
+    StackSignature a{Type::none, {Type::f32, Type::i32}, false};
+    StackSignature b{Type::i32, Type::none, true};
+    assert(a.composes(b));
+    assert(a + b == (StackSignature{Type::none, Type::none, true}));
+  }
+  {
+    StackSignature a{Type::none, Type::f32, false};
+    StackSignature b{{Type::f32, Type::i32}, Type::none, true};
+    assert(!a.composes(b));
+  }
+  {
+    StackSignature a{Type::none, {Type::f32, Type::i32}, false};
+    StackSignature b{Type::f32, Type::none, true};
+    assert(!a.composes(b));
+  }
+  // Both unreachable
+  {
+    StackSignature a{Type::none, {Type::f32, Type::i32}, true};
+    StackSignature b{{Type::f32, Type::i32}, Type::none, true};
+    assert(a.composes(b));
+    assert(a + b == (StackSignature{Type::none, Type::none, true}));
+  }
+  {
+    StackSignature a{Type::none, Type::i32, true};
+    StackSignature b{{Type::f32, Type::i32}, Type::none, true};
+    assert(a.composes(b));
+    assert(a + b == StackSignature(Type::none, Type::none, true));
+  }
+  {
+    StackSignature a{Type::none, {Type::f32, Type::i32}, true};
+    StackSignature b{Type::i32, Type::none, true};
+    assert(a.composes(b));
+    assert(a + b == (StackSignature{Type::none, Type::none, true}));
+  }
+  {
+    StackSignature a{Type::none, Type::f32, true};
+    StackSignature b{{Type::f32, Type::i32}, Type::none, true};
+    assert(!a.composes(b));
+  }
+  {
+    StackSignature a{Type::none, {Type::f32, Type::i32}, true};
+    StackSignature b{Type::f32, Type::none, true};
+    assert(!a.composes(b));
+  }
+}
+
+void test_signature_satisfaction() {
+  std::cout << ";; Test stack signature satisfaction\n";
+  // No unreachable
+  {
+    StackSignature a{Type::i32, Type::f32, false};
+    Signature b(Type::i32, Type::f32);
+    assert(a.satisfies(b));
+  }
+  {
+    StackSignature a{Type::i32, Type::f32, false};
+    Signature b({Type::i64, Type::i32}, {Type::i64, Type::f32});
+    assert(a.satisfies(b));
+  }
+  {
+    StackSignature a{Type::i32, Type::f32, false};
+    Signature b({Type::i64, Type::i32}, {Type::i64, Type::i64, Type::f32});
+    assert(!a.satisfies(b));
+  }
+  {
+    StackSignature a{Type::i32, Type::f32, false};
+    Signature b({Type::i64, Type::i32}, {Type::f64, Type::f32});
+    assert(!a.satisfies(b));
+  }
+  {
+    StackSignature a{Type::i32, Type::f32, false};
+    Signature b(Type::none, Type::f32);
+    assert(!a.satisfies(b));
+  }
+  {
+    StackSignature a{Type::i32, Type::f32, false};
+    Signature b(Type::i32, Type::none);
+    assert(!a.satisfies(b));
+  }
+  {
+    StackSignature a{Type::i32, Type::f32, false};
+    Signature b(Type::f32, Type::i32);
+    assert(!a.satisfies(b));
+  }
+  // With unreachable
+  {
+    StackSignature a{Type::i32, Type::f32, true};
+    Signature b(Type::i32, Type::f32);
+    assert(a.satisfies(b));
+  }
+  {
+    StackSignature a{Type::i32, Type::f32, true};
+    Signature b({Type::i64, Type::i32}, {Type::i64, Type::f32});
+    assert(a.satisfies(b));
+  }
+  {
+    StackSignature a{Type::i32, Type::f32, true};
+    Signature b({Type::i64, Type::i32}, {Type::i64, Type::i64, Type::f32});
+    assert(a.satisfies(b));
+  }
+  {
+    StackSignature a{Type::i32, Type::f32, true};
+    Signature b({Type::i64, Type::i32}, {Type::f64, Type::f32});
+    assert(a.satisfies(b));
+  }
+  {
+    StackSignature a{Type::i32, Type::f32, true};
+    Signature b(Type::none, Type::f32);
+    assert(!a.satisfies(b));
+  }
+  {
+    StackSignature a{Type::i32, Type::f32, true};
+    Signature b(Type::i32, Type::none);
+    assert(!a.satisfies(b));
+  }
+  {
+    StackSignature a{Type::i32, Type::f32, true};
+    Signature b(Type::f32, Type::i32);
+    assert(!a.satisfies(b));
+  }
+}
+
+void test_stack_flow() {
+  std::cout << ";; Test stack flow\n";
+  {
+    // Simple case:
+    // foo
+    //  │i32
+    // bar
+    //  │f32
+    // end
+    auto* foo = builder.makeCall("foo", {}, Type::i32);
+    auto* bar =
+      builder.makeCall("bar", {builder.makePop(Type::i32)}, Type::f32);
+    auto* block = builder.makeBlock({foo, bar}, Type::f32);
+    StackFlow flow(block);
+
+    auto fooSrcs = flow.srcs.find(foo);
+    assert(fooSrcs != flow.srcs.end());
+    assert(fooSrcs->second.size() == 0);
+
+    auto fooDests = flow.dests.find(foo);
+    assert(fooDests != flow.dests.end());
+    assert(fooDests->second.size() == 1);
+    assert(fooDests->second[0] ==
+           (StackFlow::Location{bar, 0, Type::i32, false}));
+
+    auto barSrcs = flow.srcs.find(bar);
+    assert(barSrcs != flow.dests.end());
+    assert(barSrcs->second.size() == 1);
+    assert(barSrcs->second[0] ==
+           (StackFlow::Location{foo, 0, Type::i32, false}));
+
+    auto barDests = flow.dests.find(bar);
+    assert(barDests != flow.dests.end());
+    assert(barDests->second.size() == 1);
+    assert(barDests->second[0] ==
+           (StackFlow::Location{block, 0, Type::f32, false}));
+
+    auto blockSrcs = flow.srcs.find(block);
+    assert(blockSrcs != flow.srcs.end());
+    assert(blockSrcs->second.size() == 1);
+    assert(blockSrcs->second[0] ==
+           (StackFlow::Location{bar, 0, Type::f32, false}));
+  }
+  {
+    // Interesting case:
+    // foo
+    //  ├─────┬─────┐
+    //  │i32  │f32  │i64
+    //  │     │    bar
+    //  │     │     │f64
+    //  │    baz╶───┘
+    //  │     ├─────┐
+    //  ╵     ╵i64  │f32
+    // ret╶─────────┘
+    //  ╷     ╷     ╷
+    //  │i64  │f64  │i32
+    //  │    quux╶──┘
+    // end
+    auto* foo = builder.makeCall("foo", {}, {Type::i32, Type::f32, Type::i64});
+    auto* bar =
+      builder.makeCall("bar", {builder.makePop(Type::i64)}, Type::f64);
+    auto* baz =
+      builder.makeCall("baz",
+                       {builder.makePop(Type::f32), builder.makePop(Type::f64)},
+                       {Type::i64, Type::f32});
+    auto* ret = builder.makeReturn(builder.makePop(Type::f32));
+    auto* quux =
+      builder.makeCall("quux",
+                       {builder.makePop(Type::f64), builder.makePop(Type::i32)},
+                       Type::none);
+    auto* block = builder.makeBlock({foo, bar, baz, ret, quux}, Type::i64);
+    StackFlow flow(block);
+
+    assert(flow.srcs.find(foo)->second.size() == 0);
+
+    const auto& fooDests = flow.dests[foo];
+    assert(fooDests.size() == 3);
+    assert(fooDests[0] == (StackFlow::Location{ret, 0, Type::i32, true}));
+    assert(fooDests[1] == (StackFlow::Location{baz, 0, Type::f32, false}));
+    assert(fooDests[2] == (StackFlow::Location{bar, 0, Type::i64, false}));
+
+    const auto& barSrcs = flow.srcs[bar];
+    assert(barSrcs.size() == 1);
+    assert(barSrcs[0] == (StackFlow::Location{foo, 2, Type::i64, false}));
+
+    const auto& barDests = flow.dests[bar];
+    assert(barDests.size() == 1);
+    assert(barDests[0] == (StackFlow::Location{baz, 1, Type::f64, false}));
+
+    const auto& bazSrcs = flow.srcs[baz];
+    assert(bazSrcs.size() == 2);
+    assert(bazSrcs[0] == (StackFlow::Location{foo, 1, Type::f32, false}));
+    assert(bazSrcs[1] == (StackFlow::Location{bar, 0, Type::f64, false}));
+
+    const auto& bazDests = flow.dests[baz];
+    assert(bazDests.size() == 2);
+    assert(bazDests[0] == (StackFlow::Location{ret, 1, Type::i64, true}));
+    assert(bazDests[1] == (StackFlow::Location{ret, 2, Type::f32, false}));
+
+    const auto& retSrcs = flow.srcs[ret];
+    assert(retSrcs.size() == 3);
+    assert(retSrcs[0] == (StackFlow::Location{foo, 0, Type::i32, false}));
+    assert(retSrcs[1] == (StackFlow::Location{baz, 0, Type::i64, false}));
+    assert(retSrcs[2] == (StackFlow::Location{baz, 1, Type::f32, false}));
+
+    const auto& retDests = flow.dests[ret];
+    assert(retDests.size() == 3);
+    assert(retDests[0] == (StackFlow::Location{block, 0, Type::i64, false}));
+    assert(retDests[1] == (StackFlow::Location{quux, 0, Type::f64, false}));
+    assert(retDests[2] == (StackFlow::Location{quux, 1, Type::i32, false}));
+
+    const auto& quuxSrcs = flow.srcs[quux];
+    assert(quuxSrcs.size() == 2);
+    assert(quuxSrcs[0] == (StackFlow::Location{ret, 1, Type::f64, true}));
+    assert(quuxSrcs[1] == (StackFlow::Location{ret, 2, Type::i32, true}));
+
+    const auto& quuxDests = flow.dests[quux];
+    assert(quuxDests.size() == 0);
+
+    const auto& blockSrcs = flow.srcs[block];
+    assert(blockSrcs.size() == 1);
+    assert(blockSrcs[0] == (StackFlow::Location{ret, 0, Type::i64, true}));
+
+    assert(flow.getSignature(foo) == StackSignature(foo));
+    assert(flow.getSignature(bar) == StackSignature(bar));
+    assert(flow.getSignature(baz) == StackSignature(baz));
+    assert(flow.getSignature(ret) ==
+           (StackSignature{{Type::i32, Type::i64, Type::f32},
+                           {Type::i64, Type::f64, Type::i32},
+                           true}));
+    assert(flow.getSignature(quux) == StackSignature(quux));
+  }
+}
+
+int main() {
+  test_remove_nops();
+  test_stack_signatures();
+  test_signature_composition();
+  test_signature_satisfaction();
+  test_stack_flow();
+}
diff --git a/binaryen/test/example/stack-utils.txt b/binaryen/test/example/stack-utils.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/stack-utils.txt
@@ -0,0 +1,17 @@
+;; Test removeNops
+(block (result i32 i64)
+ (nop)
+ (i32.const 0)
+ (nop)
+ (i64.const 0)
+ (nop)
+ (nop)
+)
+(block (result i32 i64)
+ (i32.const 0)
+ (i64.const 0)
+)
+;; Test stack signatures
+;; Test stack signature composition
+;; Test stack signature satisfaction
+;; Test stack flow
diff --git a/binaryen/test/example/typeinfo.cpp b/binaryen/test/example/typeinfo.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/typeinfo.cpp
@@ -0,0 +1,336 @@
+#include <cassert>
+#include <iostream>
+
+#include "wasm-type.h"
+
+using namespace wasm;
+
+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 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 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 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 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 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());
+  }
+  {
+    Signature signature(Type::i32, Type::none);
+    assert(Type(signature, false).getID() == Type(signature, false).getID());
+    assert(Type(signature, false).getID() != Type(signature, true).getID());
+
+    Signature sameSignature(Type::i32, Type::none);
+    assert(Type(signature, false).getID() ==
+           Type(sameSignature, false).getID());
+
+    Signature otherSignature(Type::f64, Type::none);
+    assert(Type(signature, false).getID() !=
+           Type(otherSignature, false).getID());
+  }
+  {
+    Struct struct_({});
+    assert(Type(struct_, false).getID() == Type(struct_, false).getID());
+    assert(Type(struct_, false).getID() != Type(struct_, true).getID());
+
+    Struct sameStruct({});
+    assert(Type(struct_, false).getID() == Type(sameStruct, false).getID());
+
+    Struct otherStruct({{Type::i32, false}});
+    assert(Type(struct_, false).getID() != Type(otherStruct, false).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 sameArray({Type::i32, false});
+    assert(Type(array, false).getID() == Type(sameArray, false).getID());
+
+    Array otherArray({Type::f64, true});
+    assert(Type(array, false).getID() != Type(otherArray, false).getID());
+  }
+  {
+    Tuple singleTuple({Type::i32});
+    assert(Type(singleTuple).getID() == Type::i32);
+
+    Tuple tuple({Type::i32, Type::f64});
+    assert(Type(tuple).getID() == Type(tuple).getID());
+
+    Tuple sameTuple({Type::i32, Type::f64});
+    assert(Type(tuple).getID() == Type(sameTuple).getID());
+
+    Tuple otherTuple({Type::f64, Type::externref});
+    assert(Type(tuple).getID() != Type(otherTuple).getID());
+  }
+  {
+    Rtt rtt(0, HeapType::FuncKind);
+    assert(Type(rtt).getID() == Type(rtt).getID());
+
+    Rtt sameRtt(0, HeapType::FuncKind);
+    assert(rtt == sameRtt);
+    assert(Type(rtt).getID() == Type(sameRtt).getID());
+
+    Rtt otherDepthRtt(1, HeapType::FuncKind);
+    assert(rtt != otherDepthRtt);
+    assert(Type(rtt).getID() != Type(otherDepthRtt).getID());
+
+    Rtt otherHeapTypeRtt(0, HeapType::AnyKind);
+    assert(rtt != otherHeapTypeRtt);
+    assert(Type(rtt).getID() != Type(otherHeapTypeRtt).getID());
+
+    Rtt structRtt(0, Struct({}));
+    assert(Type(structRtt).getID() == Type(structRtt).getID());
+
+    Rtt sameStructRtt(0, Struct({}));
+    assert(structRtt == sameStructRtt);
+    assert(Type(structRtt).getID() == Type(sameStructRtt).getID());
+
+    Rtt otherStructRtt(0, Struct({{Type::i32, false}}));
+    assert(structRtt != otherStructRtt);
+    assert(Type(structRtt).getID() != Type(otherStructRtt).getID());
+  }
+}
+
+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(Signature(Type::none, Type::none)) << "\n";
+    std::cout << HeapType(Struct({})) << "\n";
+    std::cout << HeapType(Array({Type::i32, false})) << "\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";
+    Signature signature(Type::i32, Type::f64);
+    std::cout << signature << "\n";
+    std::cout << Type(signature, false) << "\n";
+    std::cout << Type(signature, true) << "\n";
+  }
+  {
+    std::cout << "\n;; Struct\n";
+    Struct emptyStruct({});
+    std::cout << emptyStruct << "\n";
+    std::cout << Type(emptyStruct, false) << "\n";
+    std::cout << Type(emptyStruct, true) << "\n";
+    Struct struct_({
+      {Type::i32, false},
+      {Type::i64, false},
+      {Type::f32, true},
+      {Type::f64, true},
+      {Type::externref, false},
+    });
+    std::cout << struct_ << "\n";
+    std::cout << Type(struct_, false) << "\n";
+    std::cout << Type(struct_, true) << "\n";
+  }
+  {
+    std::cout << "\n;; Array\n";
+    Array array({Type::i32, false});
+    std::cout << array << "\n";
+    std::cout << Type(array, false) << "\n";
+    std::cout << Type(array, true) << "\n";
+    Array arrayMut({Type::externref, true});
+    std::cout << arrayMut << "\n";
+    std::cout << Type(arrayMut, false) << "\n";
+    std::cout << Type(arrayMut, true) << "\n";
+  }
+  {
+    std::cout << "\n;; Tuple\n";
+    Tuple emptyTuple({});
+    std::cout << emptyTuple << "\n";
+    std::cout << Type(emptyTuple) << "\n";
+    Tuple tuple({
+      Type::i32,
+      Type::f64,
+      Type::externref,
+    });
+    std::cout << tuple << "\n";
+    std::cout << Type(tuple) << "\n";
+  }
+  {
+    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";
+    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}));
+    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));
+    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({
+                          Type(Struct({}), false),
+                          Type(Array({Type::i32, false}), true),
+                        }));
+    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},
+    });
+    std::cout << structOfSignature << "\n";
+    std::cout << Type(structOfSignature, false) << "\n";
+    std::cout << Type(structOfSignature, true) << "\n";
+    Struct structOfStruct({
+      {Type(Struct({}), false), false},
+      {Type(Struct({}), false), true},
+      {Type(Struct({}), true), false},
+      {Type(Struct({}), true), true},
+    });
+    std::cout << structOfStruct << "\n";
+    std::cout << Type(structOfStruct, false) << "\n";
+    std::cout << Type(structOfStruct, true) << "\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},
+    });
+    std::cout << structOfArray << "\n";
+    std::cout << Type(structOfArray, false) << "\n";
+    std::cout << Type(structOfArray, true) << "\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},
+    });
+    std::cout << structOfEverything << "\n";
+    std::cout << Type(structOfEverything, false) << "\n";
+    std::cout << Type(structOfEverything, true) << "\n";
+  }
+  {
+    std::cout << "\n;; Array of references\n";
+    Array arrayOfSignature(
+      {Type(Signature(Type::none, Type::none), true), false});
+    std::cout << arrayOfSignature << "\n";
+    std::cout << Type(arrayOfSignature, false) << "\n";
+    std::cout << Type(arrayOfSignature, true) << "\n";
+    Array arrayOfStruct({Type(Struct({}), true), true});
+    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 << arrayOfArray << "\n";
+    std::cout << Type(arrayOfArray, false) << "\n";
+    std::cout << Type(arrayOfArray, true) << "\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),
+    });
+    std::cout << tuple << "\n";
+    std::cout << Type(tuple) << "\n";
+  }
+  // TODO: Think about recursive types. Currently impossible to construct.
+  {
+    std::cout << "\n;; Recursive (not really)\n";
+    Signature signatureSignature(Type::none, Type::none);
+    signatureSignature.params = Type(signatureSignature, false);
+    //                                ^ copies
+    std::cout << signatureSignature << "\n";
+    std::cout << Type(signatureSignature, false) << "\n";
+    Signature signatureArraySignature(Type::none, Type::none);
+    signatureArraySignature.params =
+      Type(Array({Type(signatureArraySignature, false), false}), false);
+    //                 ^ copies
+    std::cout << signatureArraySignature << "\n";
+    std::cout << Type(signatureArraySignature, false) << "\n";
+  }
+}
+
+int main() {
+  test_compound();
+  test_printing();
+}
diff --git a/binaryen/test/example/typeinfo.txt b/binaryen/test/example/typeinfo.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/typeinfo.txt
@@ -0,0 +1,113 @@
+;; Heap types
+func
+funcref
+(ref func)
+extern
+externref
+(ref extern)
+any
+anyref
+(ref any)
+eq
+eqref
+(ref eq)
+i31
+(ref null i31)
+i31ref
+exn
+exnref
+(ref exn)
+(func)
+(struct)
+(array i32)
+
+;; Signature
+(func)
+(ref (func))
+(ref null (func))
+(func (param i32) (result f64))
+(ref (func (param i32) (result f64)))
+(ref null (func (param i32) (result f64)))
+
+;; Struct
+(struct)
+(ref (struct))
+(ref null (struct))
+(struct (field i32 i64 (mut f32) (mut f64) externref))
+(ref (struct (field i32 i64 (mut f32) (mut f64) externref)))
+(ref null (struct (field i32 i64 (mut f32) (mut f64) externref)))
+
+;; Array
+(array i32)
+(ref (array i32))
+(ref null (array i32))
+(array (mut externref))
+(ref (array (mut externref)))
+(ref null (array (mut externref)))
+
+;; Tuple
+()
+none
+(i32 f64 externref)
+(i32 f64 externref)
+
+;; Rtt
+(rtt 0 func)
+(rtt 0 func)
+(rtt 1 extern)
+(rtt 1 extern)
+(rtt 2 any)
+(rtt 2 any)
+(rtt 3 eq)
+(rtt 3 eq)
+(rtt 4 i31)
+(rtt 4 i31)
+(rtt 5 exn)
+(rtt 5 exn)
+(rtt 6 (func))
+(rtt 6 (func))
+(rtt 7 (struct))
+(rtt 7 (struct))
+(rtt 8 (array i32))
+(rtt 8 (array i32))
+
+;; Signature of references (param/result)
+(func (param (ref null (struct))) (result (ref (array (mut i32)))))
+
+;; Signature of references (params/results)
+(func (param (ref null (struct)) (ref (array (mut i32)))) (result (ref (struct)) (ref null (array i32))))
+
+;; Struct of references
+(struct (field (ref (func)) (mut (ref (func))) (ref null (func)) (mut (ref null (func)))))
+(ref (struct (field (ref (func)) (mut (ref (func))) (ref null (func)) (mut (ref null (func))))))
+(ref null (struct (field (ref (func)) (mut (ref (func))) (ref null (func)) (mut (ref null (func))))))
+(struct (field (ref (struct)) (mut (ref (struct))) (ref null (struct)) (mut (ref null (struct)))))
+(ref (struct (field (ref (struct)) (mut (ref (struct))) (ref null (struct)) (mut (ref null (struct))))))
+(ref null (struct (field (ref (struct)) (mut (ref (struct))) (ref null (struct)) (mut (ref null (struct))))))
+(struct (field (ref (array i32)) (mut (ref (array i32))) (ref null (array i32)) (mut (ref null (array i32)))))
+(ref (struct (field (ref (array i32)) (mut (ref (array i32))) (ref null (array i32)) (mut (ref null (array i32))))))
+(ref null (struct (field (ref (array i32)) (mut (ref (array i32))) (ref null (array i32)) (mut (ref null (array i32))))))
+(struct (field (mut i32) (mut (ref null (func))) (mut (ref null (struct))) (mut (ref null (array (mut i32))))))
+(ref (struct (field (mut i32) (mut (ref null (func))) (mut (ref null (struct))) (mut (ref null (array (mut i32)))))))
+(ref null (struct (field (mut i32) (mut (ref null (func))) (mut (ref null (struct))) (mut (ref null (array (mut i32)))))))
+
+;; Array of references
+(array (ref null (func)))
+(ref (array (ref null (func))))
+(ref null (array (ref null (func))))
+(array (mut (ref null (struct))))
+(ref (array (mut (ref null (struct)))))
+(ref null (array (mut (ref null (struct)))))
+(array (ref null (array i32)))
+(ref (array (ref null (array i32))))
+(ref null (array (ref null (array i32))))
+
+;; Tuple of references
+((ref (func)) (ref null (func)) (ref (struct)) (ref null (struct)) (ref (array i32)) (ref null (array i32)))
+((ref (func)) (ref null (func)) (ref (struct)) (ref null (struct)) (ref (array i32)) (ref null (array i32)))
+
+;; Recursive (not really)
+(func (param (ref (func))))
+(ref (func (param (ref (func)))))
+(func (param (ref (array (ref (func))))))
+(ref (func (param (ref (array (ref (func)))))))
diff --git a/binaryen/test/exception-handling.wast b/binaryen/test/exception-handling.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/exception-handling.wast
@@ -0,0 +1,62 @@
+(module
+  (event $e0 (attr 0) (param i32))
+  (event $e1 (attr 0) (param externref))
+
+  (func $exnref_test (param $0 exnref) (result exnref)
+    (local.get $0)
+  )
+
+  (func $foo)
+  (func $bar)
+
+  (func $eh_test (local $exn exnref)
+    (try
+      (do
+        (throw $e0 (i32.const 0))
+      )
+      (catch
+        ;; Multi-value is not available yet, so block can't take a value from
+        ;; stack. So this uses locals for now.
+        (local.set $exn (pop exnref))
+        (drop
+          (block $l0 (result i32)
+            (rethrow
+              (br_on_exn $l0 $e0 (local.get $exn))
+            )
+          )
+        )
+      )
+    )
+
+    ;; Try with a block label
+    (try $l1
+      (do
+        (br $l1)
+      )
+      (catch
+        (br $l1)
+      )
+    )
+
+    ;; Empty try body
+    (try
+      (do)
+      (catch
+        (drop (pop exnref))
+      )
+    )
+
+    ;; Multiple instructions within try and catch bodies
+    (try
+      (do
+        (call $foo)
+        (call $bar)
+      )
+      (catch
+        (drop (pop exnref))
+        (call $foo)
+        (call $bar)
+      )
+    )
+  )
+)
diff --git a/binaryen/test/exception-handling.wast.from-wast b/binaryen/test/exception-handling.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/exception-handling.wast.from-wast
@@ -0,0 +1,74 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $externref_=>_none (func (param externref)))
+ (type $exnref_=>_exnref (func (param exnref) (result exnref)))
+ (event $e0 (attr 0) (param i32))
+ (event $e1 (attr 0) (param externref))
+ (func $exnref_test (param $0 exnref) (result exnref)
+  (local.get $0)
+ )
+ (func $foo
+  (nop)
+ )
+ (func $bar
+  (nop)
+ )
+ (func $eh_test
+  (local $exn exnref)
+  (try
+   (do
+    (throw $e0
+     (i32.const 0)
+    )
+   )
+   (catch
+    (local.set $exn
+     (pop exnref)
+    )
+    (drop
+     (block $l0 (result i32)
+      (rethrow
+       (br_on_exn $l0 $e0
+        (local.get $exn)
+       )
+      )
+     )
+    )
+   )
+  )
+  (block $l1
+   (try
+    (do
+     (br $l1)
+    )
+    (catch
+     (br $l1)
+    )
+   )
+  )
+  (try
+   (do
+    (nop)
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+   )
+  )
+  (try
+   (do
+    (call $foo)
+    (call $bar)
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+    (call $foo)
+    (call $bar)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/exception-handling.wast.fromBinary b/binaryen/test/exception-handling.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/exception-handling.wast.fromBinary
@@ -0,0 +1,78 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $externref_=>_none (func (param externref)))
+ (type $exnref_=>_exnref (func (param exnref) (result exnref)))
+ (event $event$0 (attr 0) (param i32))
+ (event $event$1 (attr 0) (param externref))
+ (func $exnref_test (param $0 exnref) (result exnref)
+  (local.get $0)
+ )
+ (func $foo
+  (nop)
+ )
+ (func $bar
+  (nop)
+ )
+ (func $eh_test
+  (local $exn exnref)
+  (try
+   (do
+    (throw $event$0
+     (i32.const 0)
+    )
+   )
+   (catch
+    (local.set $exn
+     (pop exnref)
+    )
+    (drop
+     (block $label$3 (result i32)
+      (rethrow
+       (br_on_exn $label$3 $event$0
+        (local.get $exn)
+       )
+      )
+     )
+    )
+   )
+  )
+  (block $label$4
+   (try
+    (do
+     (br $label$4)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (br $label$4)
+    )
+   )
+  )
+  (try
+   (do
+    (nop)
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+   )
+  )
+  (try
+   (do
+    (call $foo)
+    (call $bar)
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+    (call $foo)
+    (call $bar)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/exception-handling.wast.fromBinary.noDebugInfo b/binaryen/test/exception-handling.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/exception-handling.wast.fromBinary.noDebugInfo
@@ -0,0 +1,78 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $externref_=>_none (func (param externref)))
+ (type $exnref_=>_exnref (func (param exnref) (result exnref)))
+ (event $event$0 (attr 0) (param i32))
+ (event $event$1 (attr 0) (param externref))
+ (func $0 (param $0 exnref) (result exnref)
+  (local.get $0)
+ )
+ (func $1
+  (nop)
+ )
+ (func $2
+  (nop)
+ )
+ (func $3
+  (local $0 exnref)
+  (try
+   (do
+    (throw $event$0
+     (i32.const 0)
+    )
+   )
+   (catch
+    (local.set $0
+     (pop exnref)
+    )
+    (drop
+     (block $label$3 (result i32)
+      (rethrow
+       (br_on_exn $label$3 $event$0
+        (local.get $0)
+       )
+      )
+     )
+    )
+   )
+  )
+  (block $label$4
+   (try
+    (do
+     (br $label$4)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (br $label$4)
+    )
+   )
+  )
+  (try
+   (do
+    (nop)
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+   )
+  )
+  (try
+   (do
+    (call $1)
+    (call $2)
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+    (call $1)
+    (call $2)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/export-import.wast b/binaryen/test/export-import.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/export-import.wast
@@ -0,0 +1,8 @@
+(module
+ (type $v (func))
+ (import "env" "test1" (func $test1))
+ (import "env" "test2" (global $test2 i32))
+ (export "test1" (func $test1))
+ (export "test2" (global $test2))
+)
+
diff --git a/binaryen/test/export-import.wast.from-wast b/binaryen/test/export-import.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/export-import.wast.from-wast
@@ -0,0 +1,7 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "test2" (global $test2 i32))
+ (import "env" "test1" (func $test1))
+ (export "test1" (func $test1))
+ (export "test2" (global $test2))
+)
diff --git a/binaryen/test/export-import.wast.fromBinary b/binaryen/test/export-import.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/export-import.wast.fromBinary
@@ -0,0 +1,8 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "test2" (global $test2 i32))
+ (import "env" "test1" (func $test1))
+ (export "test1" (func $test1))
+ (export "test2" (global $test2))
+)
+
diff --git a/binaryen/test/export-import.wast.fromBinary.noDebugInfo b/binaryen/test/export-import.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/export-import.wast.fromBinary.noDebugInfo
@@ -0,0 +1,8 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "test2" (global $gimport$1 i32))
+ (import "env" "test1" (func $fimport$0))
+ (export "test1" (func $fimport$0))
+ (export "test2" (global $gimport$1))
+)
+
diff --git a/binaryen/test/externref.wast.from-wast b/binaryen/test/externref.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/externref.wast.from-wast
@@ -0,0 +1,19 @@
+(module
+ (type $externref_=>_externref (func (param externref) (result externref)))
+ (import "env" "test2" (global $test2 externref))
+ (import "env" "test1" (func $test1 (param externref) (result externref)))
+ (memory $0 1 1)
+ (export "test1" (func $test1))
+ (export "test2" (global $test2))
+ (func $externref_test (; 1 ;) (param $0 externref) (result externref)
+  (local $1 externref)
+  (local.set $1
+   (call $test1
+    (local.get $0)
+   )
+  )
+  (return
+   (local.get $1)
+  )
+ )
+)
diff --git a/binaryen/test/externref.wast.fromBinary b/binaryen/test/externref.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/externref.wast.fromBinary
@@ -0,0 +1,20 @@
+(module
+ (type $externref_=>_externref (func (param externref) (result externref)))
+ (import "env" "test2" (global $gimport$1 externref))
+ (import "env" "test1" (func $test1 (param externref) (result externref)))
+ (memory $0 1 1)
+ (export "test1" (func $test1))
+ (export "test2" (global $gimport$1))
+ (func $externref_test (; 1 ;) (param $0 externref) (result externref)
+  (local $1 externref)
+  (local.set $1
+   (call $test1
+    (local.get $0)
+   )
+  )
+  (return
+   (local.get $1)
+  )
+ )
+)
+
diff --git a/binaryen/test/externref.wast.fromBinary.noDebugInfo b/binaryen/test/externref.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/externref.wast.fromBinary.noDebugInfo
@@ -0,0 +1,20 @@
+(module
+ (type $externref_=>_externref (func (param externref) (result externref)))
+ (import "env" "test2" (global $gimport$1 externref))
+ (import "env" "test1" (func $fimport$0 (param externref) (result externref)))
+ (memory $0 1 1)
+ (export "test1" (func $fimport$0))
+ (export "test2" (global $gimport$1))
+ (func $0 (; 1 ;) (param $0 externref) (result externref)
+  (local $1 externref)
+  (local.set $1
+   (call $fimport$0
+    (local.get $0)
+   )
+  )
+  (return
+   (local.get $1)
+  )
+ )
+)
+
diff --git a/binaryen/test/extra-unreachable.wast b/binaryen/test/extra-unreachable.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/extra-unreachable.wast
@@ -0,0 +1,196 @@
+(module
+  (type $ii (param i32) (result i32))
+  (memory (shared 1 1))
+  (table 0 funcref)
+  (global $g (mut f32) (f32.const 0))
+  (event $e (attr 0) (param i32))
+
+  (func $foo (param i32) (result i32) (i32.const 0))
+
+  (func $test_function_block
+    ;; block, which has unreachable type, can be omitted here because it is the
+    ;; only expression within a function. We emit an extra unreachable at the
+    ;; end.
+    (block
+      (unreachable)
+      (nop)
+    )
+  )
+
+  (func $test
+    ;; block has unreachable type. We emit an unreachable at the end of the
+    ;; block and also outside the block too.
+    (block
+      (i32.eqz (unreachable))
+    )
+
+    ;; If an if's condition is unreachable, don't emit the if and emit an
+    ;; unreachable instead.
+    (if
+      (unreachable)
+      (nop)
+      (nop)
+    )
+
+    ;; If an if is unreachable, i.e., the both sides are unreachable, we emit
+    ;; an extra unreachable after the if.
+    (if
+      (i32.const 1)
+      (unreachable)
+      (unreachable)
+    )
+
+    ;; If a try is unreachable, i.e., both the 'try' and 'catch' bodies are
+    ;; unreachable, we emit an extra unreachable after the try.
+    (try
+      (do
+        (unreachable)
+      )
+      (catch
+        (unreachable)
+      )
+    )
+
+    ;; If a br_if/br_on_exn's type is unreachable, emit an extra unreachable
+    ;; after it
+    (block
+      (br_if 0 (unreachable))
+    )
+    (drop
+      (block (result i32)
+        (br_on_exn 0 $e (unreachable))
+      )
+    )
+
+    ;; If a br_table is not reachable, emit an unreachable instead
+    (block $l
+      (block $default
+        (br_table $l $default
+          (unreachable)
+        )
+      )
+    )
+
+    ;; For all tests below, when a value-returning expression is unreachable,
+    ;; emit an unreachable instead of the operation, to prevent it from being
+    ;; consumed by the next operation.
+    ;;
+    ;; Here global.set is used to consume the value. If an unreachable is not
+    ;; emitted, the instruction itself will be consumed by global.set and will
+    ;; result in a type validation failure, because it expects a f32 but gets an
+    ;; i32. The reason we use global.set is the instruction does not return a
+    ;; value, so it will be emitted even if its argument is unreachable.
+
+    ;; call / call_indirect
+    (global.set $g
+      (call $foo (unreachable))
+    )
+    (global.set $g
+      (call_indirect (type $ii) (unreachable))
+    )
+
+    ;; unary
+    (global.set $g
+      (i32.eqz (unreachable))
+    )
+
+    ;; binary
+    (global.set $g
+      (i32.add
+        (unreachable)
+        (i32.const 0)
+      )
+    )
+
+    ;; select
+    (global.set $g
+      (select
+        (unreachable)
+        (i32.const 0)
+        (i32.const 0)
+      )
+    )
+
+    ;; load
+    (global.set $g
+      (i32.load (unreachable))
+    )
+    (global.set $g
+      (i32.atomic.load (unreachable))
+    )
+
+    ;; atomic.rmw
+    (global.set $g
+      (i32.atomic.rmw.add
+        (unreachable)
+        (i32.const 0)
+      )
+    )
+
+    ;; atomic.cmpxchg
+    (global.set $g
+      (i32.atomic.rmw.cmpxchg
+        (unreachable)
+        (i32.const 0)
+        (i32.const 0)
+      )
+    )
+
+    ;; atomic.wait
+    (global.set $g
+      (i32.atomic.wait
+        (unreachable)
+        (i32.const 0)
+        (i64.const 0)
+      )
+    )
+
+    ;; atomic.notify
+    (global.set $g
+      (atomic.notify
+        (unreachable)
+        (i32.const 0)
+      )
+    )
+
+    ;; SIMD extract
+    (global.set $g
+      (i32x4.extract_lane 0
+        (unreachable)
+      )
+    )
+
+    ;; SIMD replace
+    (global.set $g
+      (i32x4.replace_lane 0
+        (unreachable)
+        (i32.const 0)
+      )
+    )
+
+    ;; SIMD shuffle
+    (global.set $g
+      (v8x16.shuffle 0 17 2 19 4 21 6 23 8 25 10 27 12 29 14 31
+        (unreachable)
+        (unreachable)
+      )
+    )
+
+    ;; SIMD bitselect
+    (global.set $g
+      (v128.bitselect
+        (unreachable)
+        (unreachable)
+        (unreachable)
+      )
+    )
+
+    ;; SIMD shift
+    (global.set $g
+      (i32x4.shl
+        (unreachable)
+        (i32.const 0)
+      )
+    )
+  )
+)
diff --git a/binaryen/test/extra-unreachable.wast.from-wast b/binaryen/test/extra-unreachable.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/extra-unreachable.wast.from-wast
@@ -0,0 +1,156 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 (shared 1 1))
+ (table $0 0 funcref)
+ (global $g (mut f32) (f32.const 0))
+ (event $e (attr 0) (param i32))
+ (func $foo (param $0 i32) (result i32)
+  (i32.const 0)
+ )
+ (func $test_function_block
+  (block $block
+   (unreachable)
+   (nop)
+  )
+ )
+ (func $test
+  (block $block
+   (i32.eqz
+    (unreachable)
+   )
+  )
+  (if
+   (unreachable)
+   (nop)
+   (nop)
+  )
+  (if
+   (i32.const 1)
+   (unreachable)
+   (unreachable)
+  )
+  (try
+   (do
+    (unreachable)
+   )
+   (catch
+    (unreachable)
+   )
+  )
+  (block $block1
+   (br_if $block1
+    (unreachable)
+   )
+  )
+  (drop
+   (block $block2 (result i32)
+    (br_on_exn $block2 $e
+     (unreachable)
+    )
+   )
+  )
+  (block $l
+   (block $default
+    (br_table $l $default
+     (unreachable)
+    )
+   )
+  )
+  (global.set $g
+   (call $foo
+    (unreachable)
+   )
+  )
+  (global.set $g
+   (call_indirect (type $none_=>_none)
+    (unreachable)
+   )
+  )
+  (global.set $g
+   (i32.eqz
+    (unreachable)
+   )
+  )
+  (global.set $g
+   (i32.add
+    (unreachable)
+    (i32.const 0)
+   )
+  )
+  (global.set $g
+   (select
+    (unreachable)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+  (global.set $g
+   (i32.load
+    (unreachable)
+   )
+  )
+  (global.set $g
+   (i32.atomic.load
+    (unreachable)
+   )
+  )
+  (global.set $g
+   (i32.atomic.rmw.add
+    (unreachable)
+    (i32.const 0)
+   )
+  )
+  (global.set $g
+   (i32.atomic.rmw.cmpxchg
+    (unreachable)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+  (global.set $g
+   (i32.atomic.wait
+    (unreachable)
+    (i32.const 0)
+    (i64.const 0)
+   )
+  )
+  (global.set $g
+   (atomic.notify
+    (unreachable)
+    (i32.const 0)
+   )
+  )
+  (global.set $g
+   (i32x4.extract_lane 0
+    (unreachable)
+   )
+  )
+  (global.set $g
+   (i32x4.replace_lane 0
+    (unreachable)
+    (i32.const 0)
+   )
+  )
+  (global.set $g
+   (v8x16.shuffle 0 17 2 19 4 21 6 23 8 25 10 27 12 29 14 31
+    (unreachable)
+    (unreachable)
+   )
+  )
+  (global.set $g
+   (v128.bitselect
+    (unreachable)
+    (unreachable)
+    (unreachable)
+   )
+  )
+  (global.set $g
+   (i32x4.shl
+    (unreachable)
+    (i32.const 0)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/extra-unreachable.wast.fromBinary b/binaryen/test/extra-unreachable.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/extra-unreachable.wast.fromBinary
@@ -0,0 +1,21 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 (shared 1 1))
+ (table $0 0 funcref)
+ (global $g (mut f32) (f32.const 0))
+ (event $event$0 (attr 0) (param i32))
+ (func $foo (param $0 i32) (result i32)
+  (i32.const 0)
+ )
+ (func $test_function_block
+  (unreachable)
+ )
+ (func $test
+  (block $label$1
+   (unreachable)
+  )
+ )
+)
+
diff --git a/binaryen/test/extra-unreachable.wast.fromBinary.noDebugInfo b/binaryen/test/extra-unreachable.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/extra-unreachable.wast.fromBinary.noDebugInfo
@@ -0,0 +1,21 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 (shared 1 1))
+ (table $0 0 funcref)
+ (global $global$0 (mut f32) (f32.const 0))
+ (event $event$0 (attr 0) (param i32))
+ (func $0 (param $0 i32) (result i32)
+  (i32.const 0)
+ )
+ (func $1
+  (unreachable)
+ )
+ (func $2
+  (block $label$1
+   (unreachable)
+  )
+ )
+)
+
diff --git a/binaryen/test/fannkuch.args b/binaryen/test/fannkuch.args
new file mode 100644
--- /dev/null
+++ b/binaryen/test/fannkuch.args
@@ -0,0 +1,1 @@
+["5"]
diff --git a/binaryen/test/fannkuch.cpp b/binaryen/test/fannkuch.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/fannkuch.cpp
@@ -0,0 +1,159 @@
+/*
+ * The Computer Language Benchmarks Game
+ * http://shootout.alioth.debian.org/
+ *
+ * Contributed by Eckehard Berns
+ * Based on code by Heiner Marxen
+ * and the ATS version by Hongwei Xi
+ *
+ * Modified for emscripten by azakai
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+struct worker_args {
+   int i, n;
+   struct worker_args *next;
+};
+
+int
+fannkuch_worker(void *_arg)
+{
+   struct worker_args *args = (worker_args*)_arg;
+   int *perm1, *count, *perm;
+   int maxflips, flips, i, n, r, j, k, tmp;
+
+   maxflips = 0;
+   n = args->n;
+   perm1 = (int*)malloc(n * sizeof(int));
+   perm = (int*)malloc(n * sizeof(int));
+   count = (int*)malloc(n * sizeof(int));
+   for (i = 0; i < n; i++)
+      perm1[i] = i;
+   perm1[args->i] = n - 1;
+   perm1[n - 1] = args->i;
+   r = n;
+
+   for (;;) {
+      for (; r > 1; r--)
+         count[r - 1] = r;
+      if (perm1[0] != 0 && perm1[n - 1] != n - 1) {
+         for (i = 0; i < n; i++)
+            perm[i] = perm1[i];
+         flips = 0;
+         k = perm[0];
+         do {
+            for (i = 1, j = k - 1; i < j; i++, j--) {
+               tmp = perm[i];
+               perm[i] = perm[j];
+               perm[j] = tmp;
+            }
+            flips++;
+            tmp = perm[k];
+            perm[k] = k;
+            k = tmp;
+         } while (k);
+         if (maxflips < flips)
+            maxflips = flips;
+      }
+      for (;;) {
+         if (r >= n - 1) {
+            free(perm1);
+            free(perm);
+            free(count);
+            return maxflips;
+         }
+
+         {
+            int p0 = perm1[0];
+            for (i = 0; i < r; i++)
+               perm1[i] = perm1[i + 1];
+            perm1[i] = p0;
+         }
+         if (--count[r] > 0)
+            break;
+         r++;
+      }
+   }
+}
+
+static int
+fannkuch(int n)
+{
+   struct worker_args *args, *targs;
+   int showmax = 30;
+   int *perm1, *count, i, r, maxflips, flips;
+
+   args = NULL;
+   for (i = 0; i < n - 1; i++) {
+      targs = (worker_args*)malloc(sizeof(struct worker_args));
+      targs->i = i;
+      targs->n = n;
+      targs->next = args;
+      args = targs;
+   }
+
+   perm1 = (int*)malloc(n * sizeof(int));
+   count = (int*)malloc(n * sizeof(int));
+
+   for (i = 0; i < n; i++)
+      perm1[i] = i;
+
+   r = n;
+   for (;;) {
+      if (showmax) {
+         for (i = 0; i < n; i++)
+            printf("%d", perm1[i] + 1);
+         printf("\n");
+         showmax--;
+      } else
+         goto cleanup;
+
+      for (; r > 1; r--)
+         count[r - 1] = r;
+
+      for (;;) {
+         if (r == n)
+            goto cleanup;
+         {
+            int p0 = perm1[0];
+            for (i = 0; i < r; i++)
+               perm1[i] = perm1[i + 1];
+            perm1[i] = p0;
+         }
+         if (--count[r] > 0)
+            break;
+
+         r++;
+      }
+   }
+
+    cleanup:
+   free(perm1);
+   free(count);
+   maxflips = 0;
+   while (args != NULL) {
+      flips = (int)fannkuch_worker(args);
+      if (maxflips < flips)
+         maxflips = flips;
+      targs = args;
+      args = args->next;
+      free(targs);
+   }
+   return maxflips;
+}
+
+int
+main(int argc, char **argv)
+{
+   int n = argc > 1 ? atoi(argv[1]) : 0;
+
+   if (n < 1) {
+      printf("Wrong argument.\n");
+      return 1;
+   }
+   printf("Pfannkuchen(%d) = %d.\n", n, fannkuch(n));
+   return 0;
+}
+
diff --git a/binaryen/test/fannkuch.txt b/binaryen/test/fannkuch.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/fannkuch.txt
@@ -0,0 +1,31 @@
+12345
+21345
+23145
+32145
+31245
+13245
+23415
+32415
+34215
+43215
+42315
+24315
+34125
+43125
+41325
+14325
+13425
+31425
+41235
+14235
+12435
+21435
+24135
+42135
+23451
+32451
+34251
+43251
+42351
+24351
+Pfannkuchen(5) = 7.
diff --git a/binaryen/test/fasta.args b/binaryen/test/fasta.args
new file mode 100644
--- /dev/null
+++ b/binaryen/test/fasta.args
@@ -0,0 +1,1 @@
+["10"]
diff --git a/binaryen/test/fasta.cpp b/binaryen/test/fasta.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/fasta.cpp
@@ -0,0 +1,198 @@
+/* The Computer Language Benchmarks Game
+   http://shootout.alioth.debian.org/
+   contributed by Andrew Moon
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// limit output, so we do not benchmark speed of printing
+void puts_limited(char *x)
+{
+  static int left = 550;
+  int len = strlen(x);
+  if (len <= left) {
+    puts(x);
+    left -= len;
+    return;
+  }
+  if (left > 0) {
+    x[left] = '\0';
+    puts(x);
+    x[left] = 'z';
+    left = 0;
+  }
+}
+
+struct Random {
+   enum { IM = 139968, IA = 3877, IC = 29573 };
+   Random() : last(42) {}
+   float get( float max = 1.0f ) {
+      last = ( last * IA + IC ) % IM;
+      return max * last / IM;
+   }
+protected:
+   unsigned int last;
+} rng;
+
+struct IUB {
+   int c;
+   double p;
+   unsigned int pi;
+};
+
+struct Cumulative {
+   enum { slots = 512, };
+
+   Cumulative( IUB *start ) {
+      double p = 0;
+      for ( IUB *iter = start; iter->c; ++iter ) {
+         p += iter->p;
+         iter->p = p < 1.0 ? p : 1.0;
+         iter->pi = (unsigned int )( iter->p * slots );
+      }
+
+      for ( unsigned int i = 0; i <= slots; i++ ) {
+         while ( i > start->pi && start->pi != 0) {
+            ++start;
+          }
+
+         table[i] = start;
+      }
+   }
+
+   const char operator[] ( float pct ) const {
+      IUB *iter = table[(unsigned int )( pct * slots )];
+      while ( iter->p < pct )
+         ++iter;
+      return iter->c;
+   }
+
+protected:
+   IUB *table[slots + 1];
+};
+
+static const size_t lineLength = 60;
+
+struct LineBuffer {
+   LineBuffer() : lastN(0) {}
+   LineBuffer &genrand( Cumulative &table, size_t N ) {
+      //assert(N <= lineLength);
+      for ( size_t i = 0; i < N; i++ )
+         buffer[i] = table[rng.get()];
+      buffer[N] = '\n';
+      buffer[N+1] = '\0';
+      lastN = N + 1;
+      return *this;
+   }
+   void writeline() { puts_limited(buffer); }
+protected:
+   char buffer[lineLength + 2];
+   size_t lastN;
+};
+
+struct RotatingString {
+   RotatingString( const char *in ) : pos(0) {
+      size = strlen( in );
+      buffer = new char[size + lineLength];
+      memcpy( buffer, in, size );
+      memcpy( buffer + size, in, lineLength );
+   }
+   ~RotatingString() { delete[] buffer; }
+   void write( size_t bytes ) {
+      char* temp = new char[bytes+2];
+      memcpy(temp, buffer + pos, bytes);
+      temp[bytes] = '\n';
+      temp[bytes] = '\0';
+      puts_limited(temp);
+      delete temp;
+      pos += bytes;
+      if ( pos > size )
+         pos -= size;
+   }
+protected:
+   char *buffer;
+   size_t size, pos;
+};
+
+template< class Output >
+void makeFasta( const char *id, const char *desc, size_t N, Output &output ) {
+   while ( N ) {
+      const size_t bytes = N < lineLength ? N : lineLength;
+      output.writeline( bytes );
+      N -= bytes;
+   }
+}
+
+struct Repeater {
+   Repeater( const char *alu ) : rot(alu) {}
+   void writeline( size_t bytes ) { rot.write( bytes ); }
+   void run( const char *id, const char *desc, size_t N ) {
+      makeFasta( id, desc, N, *this );
+   }
+protected:
+   RotatingString rot;
+};
+
+struct Randomized {
+   Randomized( IUB *start ) : table(start) {}
+   void writeline( size_t bytes ) { line.genrand(table, bytes).writeline(); }
+   void run( const char *id, const char *desc, size_t N ) {
+      makeFasta( id, desc, N, *this );
+   }
+protected:
+   Cumulative table;
+   LineBuffer line;
+};
+
+IUB iub[] = {
+   { 'a', 0.27, 0 },
+   { 'c', 0.12, 0 },
+   { 'g', 0.12, 0 },
+   { 't', 0.27, 0 },
+
+   { 'B', 0.02, 0 },
+   { 'D', 0.02, 0 },
+   { 'H', 0.02, 0 },
+   { 'K', 0.02, 0 },
+   { 'M', 0.02, 0 },
+   { 'N', 0.02, 0 },
+   { 'R', 0.02, 0 },
+   { 'S', 0.02, 0 },
+   { 'V', 0.02, 0 },
+   { 'W', 0.02, 0 },
+   { 'Y', 0.02, 0 },
+   {   0,    0, 0 },
+};
+
+IUB homosapiens[] = {
+   { 'a', 0.3029549426680, 0 },
+   { 'c', 0.1979883004921, 0 },
+   { 'g', 0.1975473066391, 0 },
+   { 't', 0.3015094502008, 0 },
+   {   0,               0, 0 },
+};
+
+static const char alu[] =
+   "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTG"
+   "GGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGA"
+   "GACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAA"
+   "AATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT"
+   "CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAAC"
+   "CCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTG"
+   "CACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
+
+int main( int argc, const char *argv[] ) {
+   const size_t n = ( argc > 1 ) ? atoi( argv[1] ) : 512;
+
+   Repeater(alu)
+      .run( "ONE", "Homo sapiens alu", n*2 );
+   Randomized(iub)
+      .run( "TWO", "IUB ambiguity codes", n*3 );
+   Randomized(homosapiens)
+      .run( "THREE", "Homo sapiens frequency", n*5 );
+
+   return 0;
+}
+
diff --git a/binaryen/test/fasta.txt b/binaryen/test/fasta.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/fasta.txt
@@ -0,0 +1,5 @@
+GGCCGGGCGCGGTGGCTCAC
+cttBtatcatatgctaKggNcataaaSatg
+
+taaatcttgtgcttcgttagaagtctcgactacgtgtagcctagtgtttg
+
diff --git a/binaryen/test/fib-dbg.wasm b/binaryen/test/fib-dbg.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/fib-dbg.wasm differ
diff --git a/binaryen/test/fib-dbg.wasm.fromBinary b/binaryen/test/fib-dbg.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/fib-dbg.wasm.fromBinary
@@ -0,0 +1,219 @@
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (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" "DYNAMICTOP_PTR" (global $gimport$0 i32))
+ (import "env" "tempDoublePtr" (global $gimport$1 i32))
+ (import "env" "ABORT" (global $gimport$2 i32))
+ (import "env" "STACKTOP" (global $gimport$3 i32))
+ (import "env" "STACK_MAX" (global $gimport$4 i32))
+ (import "env" "gb" (global $gimport$5 i32))
+ (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))
+ (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))
+ (global $global$3 (mut i32) (global.get $gimport$3))
+ (global $global$4 (mut i32) (global.get $gimport$4))
+ (global $global$5 (mut i32) (global.get $gimport$5))
+ (global $global$6 (mut i32) (global.get $gimport$6))
+ (global $global$7 (mut i32) (i32.const 0))
+ (global $global$8 (mut i32) (i32.const 0))
+ (global $global$9 (mut i32) (i32.const 0))
+ (global $global$10 (mut i32) (i32.const 0))
+ (global $global$11 (mut f64) (global.get $gimport$7))
+ (global $global$12 (mut f64) (global.get $gimport$8))
+ (global $global$13 (mut i32) (i32.const 0))
+ (global $global$14 (mut i32) (i32.const 0))
+ (global $global$15 (mut i32) (i32.const 0))
+ (global $global$16 (mut i32) (i32.const 0))
+ (global $global$17 (mut f64) (f64.const 0))
+ (global $global$18 (mut i32) (i32.const 0))
+ (global $global$19 (mut i32) (i32.const 0))
+ (global $global$20 (mut i32) (i32.const 0))
+ (global $global$21 (mut f64) (f64.const 0))
+ (global $global$22 (mut i32) (i32.const 0))
+ (global $global$23 (mut f64) (f64.const 0))
+ (export "setThrew" (func $setThrew))
+ (export "runPostSets" (func $runPostSets))
+ (export "establishStackSpace" (func $establishStackSpace))
+ (export "stackSave" (func $stackSave))
+ (export "stackRestore" (func $stackRestore))
+ (export "_fib" (func $_fib))
+ (export "stackAlloc" (func $stackAlloc))
+ (func $stackAlloc (param $0 i32) (result i32)
+  (local $1 i32)
+  (block $label$1
+   (local.set $1
+    (global.get $global$3)
+   )
+   (global.set $global$3
+    (i32.add
+     (global.get $global$3)
+     (local.get $0)
+    )
+   )
+   (global.set $global$3
+    (i32.and
+     (i32.add
+      (global.get $global$3)
+      (i32.const 15)
+     )
+     (i32.const -16)
+    )
+   )
+   (return
+    (local.get $1)
+   )
+  )
+ )
+ (func $stackSave (result i32)
+  (return
+   (global.get $global$3)
+  )
+ )
+ (func $stackRestore (param $0 i32)
+  (global.set $global$3
+   (local.get $0)
+  )
+ )
+ (func $establishStackSpace (param $0 i32) (param $1 i32)
+  (block $label$1
+   (global.set $global$3
+    (local.get $0)
+   )
+   (global.set $global$4
+    (local.get $1)
+   )
+  )
+ )
+ (func $setThrew (param $0 i32) (param $1 i32)
+  (if
+   (i32.eq
+    (global.get $global$7)
+    (i32.const 0)
+   )
+   (block
+    (global.set $global$7
+     (local.get $0)
+    )
+    (global.set $global$8
+     (local.get $1)
+    )
+   )
+  )
+ )
+ (func $_fib (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (block $label$1
+   (local.set $11
+    (global.get $global$3)
+   )
+   ;;@ fib.c:3:0
+   (local.set $6
+    (i32.gt_s
+     (local.get $0)
+     (i32.const 0)
+    )
+   )
+   (if
+    (local.get $6)
+    (block
+     (local.set $1
+      (i32.const 0)
+     )
+     (local.set $5
+      (i32.const 1)
+     )
+     (local.set $8
+      (i32.const 0)
+     )
+    )
+    (block
+     (local.set $4
+      (i32.const 1)
+     )
+     ;;@ fib.c:8:0
+     (return
+      (local.get $4)
+     )
+    )
+   )
+   (loop $label$4
+    (block $label$5
+     ;;@ fib.c:4:0
+     (local.set $3
+      (i32.add
+       (local.get $5)
+       (local.get $1)
+      )
+     )
+     ;;@ fib.c:3:0
+     (local.set $9
+      (i32.add
+       (local.get $8)
+       (i32.const 1)
+      )
+     )
+     (local.set $7
+      (i32.eq
+       (local.get $9)
+       (local.get $0)
+      )
+     )
+     (if
+      (local.get $7)
+      (block
+       (local.set $4
+        (local.get $3)
+       )
+       (br $label$5)
+      )
+      (block
+       (local.set $2
+        (local.get $5)
+       )
+       (local.set $5
+        (local.get $3)
+       )
+       (local.set $8
+        (local.get $9)
+       )
+       (local.set $1
+        (local.get $2)
+       )
+      )
+     )
+     (br $label$4)
+    )
+   )
+   ;;@ fib.c:8:0
+   (return
+    (local.get $4)
+   )
+  )
+ )
+ (func $runPostSets
+  (local $0 i32)
+  (nop)
+ )
+ ;; custom section "sourceMappingURL", size 35, contents: "\"http://localhost:8000/fib.wasm.map"
+)
+
diff --git a/binaryen/test/fib-dbg.wasm.map b/binaryen/test/fib-dbg.wasm.map
new file mode 100644
--- /dev/null
+++ b/binaryen/test/fib-dbg.wasm.map
@@ -0,0 +1,1 @@
+{"version":3,"sources":["fib.c"],"names":[],"mappings":"moBAEA,4BAKA,QAJA,OADA,OAAA,uCAKA"}
diff --git a/binaryen/test/float_ops.cpp b/binaryen/test/float_ops.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/float_ops.cpp
@@ -0,0 +1,73 @@
+#include <cmath>
+#include <algorithm>
+#include <emscripten.h>
+
+extern "C" {
+
+// unary
+double EMSCRIPTEN_KEEPALIVE dneg(double x) { return -x; }
+double EMSCRIPTEN_KEEPALIVE dfloor(double x) { return floor(x); }
+
+// binary
+double EMSCRIPTEN_KEEPALIVE dadd(double x, double y) { return x + y; }
+double EMSCRIPTEN_KEEPALIVE dsub(double x, double y) { return x - y; }
+double EMSCRIPTEN_KEEPALIVE dmul(double x, double y) { return x * y; }
+double EMSCRIPTEN_KEEPALIVE ddiv(double x, double y) { return x / y; }
+double EMSCRIPTEN_KEEPALIVE dcopysign(double x, double y) { return std::copysign(x, y); }
+double EMSCRIPTEN_KEEPALIVE dmin(double x, double y) { return std::min(x, y); }
+double EMSCRIPTEN_KEEPALIVE dmax(double x, double y) { return std::max(x, y); }
+
+// comparisons
+int EMSCRIPTEN_KEEPALIVE deq(double x, double y) { return x == y; }
+int EMSCRIPTEN_KEEPALIVE dne(double x, double y) { return x != y; }
+int EMSCRIPTEN_KEEPALIVE dlt(double x, double y) { return x < y; }
+int EMSCRIPTEN_KEEPALIVE dle(double x, double y) { return x <= y; }
+int EMSCRIPTEN_KEEPALIVE dgt(double x, double y) { return x > y; }
+int EMSCRIPTEN_KEEPALIVE dge(double x, double y) { return x >= y; }
+
+double EMSCRIPTEN_KEEPALIVE int_to_double(int x) {
+  double d = x;
+  return d + 1.23;
+}
+
+double EMSCRIPTEN_KEEPALIVE uint_to_double(unsigned x) {
+  double d = x;
+  return d + 1.23;
+}
+
+int EMSCRIPTEN_KEEPALIVE double_to_int(double d) {
+  d += 1.23;
+  int x = d;
+  return x;
+}
+
+int EMSCRIPTEN_KEEPALIVE double_to_uint(double d) {
+  d += 1.23;
+  unsigned x = d;
+  return x;
+}
+
+float EMSCRIPTEN_KEEPALIVE int_to_float(int x) {
+  float d = x;
+  return d + 1.23;
+}
+
+float EMSCRIPTEN_KEEPALIVE uint_to_float(unsigned x) {
+  float d = x;
+  return d + 1.23;
+}
+
+int EMSCRIPTEN_KEEPALIVE float_to_int(float d) {
+  d += 1.23;
+  int x = d;
+  return x;
+}
+
+int EMSCRIPTEN_KEEPALIVE float_to_uint(float d) {
+  d += 1.23;
+  unsigned x = d;
+  return x;
+}
+
+}
+
diff --git a/binaryen/test/float_ops.emcc b/binaryen/test/float_ops.emcc
new file mode 100644
--- /dev/null
+++ b/binaryen/test/float_ops.emcc
@@ -0,0 +1,1 @@
+["-s", "ASSERTIONS=0"]
diff --git a/binaryen/test/float_ops.post.js b/binaryen/test/float_ops.post.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/float_ops.post.js
@@ -0,0 +1,89 @@
+
+// unary
+function testUnary(name) {
+  Module.print(name);
+  function doTest(x) {
+    Module.print('  ' + [x] + ' ==> ' + Module['_' + name](x));
+  }
+  doTest(0);
+  doTest(1);
+  doTest(-1);
+  doTest(0.5);
+  doTest(-0.5);
+  doTest(1.4);
+  doTest(-1.4);
+  doTest(1.6);
+  doTest(-1.6);
+  doTest(5.1);
+  doTest(5.3);
+  doTest(5.7);
+  doTest(5.9);
+  doTest(-1 | 0);
+  doTest((-1 | 0) + 1);
+  doTest((-1 | 0) - 1);
+  doTest((-1 >>> 0) + 1);
+  doTest((-1 >>> 0) - 1);
+  doTest((-1 | 0) + 2);
+  doTest((-1 | 0) - 2);
+  doTest((-1 >>> 0) + 2);
+  doTest((-1 >>> 0) - 2);
+}
+testUnary('dfloor');
+
+// binary
+function testBinary(name) {
+  Module.print(name);
+  function doTest(x, y) {
+    Module.print('  ' + [x, y] + ' ==> ' + Module['_' + name](x, y));
+  }
+  doTest(0, 0);
+  doTest(0, 1);
+  doTest(1, 0);
+  doTest(1, 1);
+  doTest(5, 6);
+  doTest(6, 5);
+  doTest(101, -12);
+  doTest(-12, 101);
+  doTest(-1, 5);
+  doTest(5, -1);
+  doTest(-1, -1);
+  doTest(0.12, 0.12);
+  doTest(0.812, 1);
+  doTest(1.821, 0);
+  doTest(1, 1.212);
+  doTest(5.543, 6);
+  doTest(6, 5.121);
+  doTest(101.001, -12);
+  doTest(-12.001, 101);
+  doTest(-1, 5.123);
+  doTest(5, -1.123);
+  doTest(-1, -1.123);
+}
+testBinary('dadd');
+testBinary('dsub');
+testBinary('dmul');
+testBinary('ddiv');
+//testBinary('dcopysign'); // TODO this uses tempDoublePtr, a global, which is not yet functional
+testBinary('dmin');
+testBinary('dmax');
+
+// comparisons
+testBinary('deq');
+testBinary('dne');
+testBinary('dlt');
+testBinary('dle');
+testBinary('dgt');
+testBinary('dge');
+
+// conversions
+testUnary('int_to_double');
+testUnary('uint_to_double');
+testUnary('double_to_int');
+testUnary('double_to_uint');
+testUnary('int_to_float');
+testUnary('uint_to_float');
+testUnary('float_to_int');
+testUnary('float_to_uint');
+
+Module.print('done.');
+
diff --git a/binaryen/test/float_ops.txt b/binaryen/test/float_ops.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/float_ops.txt
@@ -0,0 +1,484 @@
+dfloor
+  0 ==> 0
+  1 ==> 1
+  -1 ==> -1
+  0.5 ==> 0
+  -0.5 ==> -1
+  1.4 ==> 1
+  -1.4 ==> -2
+  1.6 ==> 1
+  -1.6 ==> -2
+  5.1 ==> 5
+  5.3 ==> 5
+  5.7 ==> 5
+  5.9 ==> 5
+  -1 ==> -1
+  0 ==> 0
+  -2 ==> -2
+  4294967296 ==> 4294967296
+  4294967294 ==> 4294967294
+  1 ==> 1
+  -3 ==> -3
+  4294967297 ==> 4294967297
+  4294967293 ==> 4294967293
+dadd
+  0,0 ==> 0
+  0,1 ==> 1
+  1,0 ==> 1
+  1,1 ==> 2
+  5,6 ==> 11
+  6,5 ==> 11
+  101,-12 ==> 89
+  -12,101 ==> 89
+  -1,5 ==> 4
+  5,-1 ==> 4
+  -1,-1 ==> -2
+  0.12,0.12 ==> 0.24
+  0.812,1 ==> 1.812
+  1.821,0 ==> 1.821
+  1,1.212 ==> 2.2119999999999997
+  5.543,6 ==> 11.543
+  6,5.121 ==> 11.121
+  101.001,-12 ==> 89.001
+  -12.001,101 ==> 88.999
+  -1,5.123 ==> 4.123
+  5,-1.123 ==> 3.877
+  -1,-1.123 ==> -2.123
+dsub
+  0,0 ==> 0
+  0,1 ==> -1
+  1,0 ==> 1
+  1,1 ==> 0
+  5,6 ==> -1
+  6,5 ==> 1
+  101,-12 ==> 113
+  -12,101 ==> -113
+  -1,5 ==> -6
+  5,-1 ==> 6
+  -1,-1 ==> 0
+  0.12,0.12 ==> 0
+  0.812,1 ==> -0.18799999999999994
+  1.821,0 ==> 1.821
+  1,1.212 ==> -0.21199999999999997
+  5.543,6 ==> -0.45699999999999985
+  6,5.121 ==> 0.8789999999999996
+  101.001,-12 ==> 113.001
+  -12.001,101 ==> -113.001
+  -1,5.123 ==> -6.123
+  5,-1.123 ==> 6.123
+  -1,-1.123 ==> 0.123
+dmul
+  0,0 ==> 0
+  0,1 ==> 0
+  1,0 ==> 0
+  1,1 ==> 1
+  5,6 ==> 30
+  6,5 ==> 30
+  101,-12 ==> -1212
+  -12,101 ==> -1212
+  -1,5 ==> -5
+  5,-1 ==> -5
+  -1,-1 ==> 1
+  0.12,0.12 ==> 0.0144
+  0.812,1 ==> 0.812
+  1.821,0 ==> 0
+  1,1.212 ==> 1.212
+  5.543,6 ==> 33.258
+  6,5.121 ==> 30.726000000000003
+  101.001,-12 ==> -1212.0120000000002
+  -12.001,101 ==> -1212.1009999999999
+  -1,5.123 ==> -5.123
+  5,-1.123 ==> -5.615
+  -1,-1.123 ==> 1.123
+ddiv
+  0,0 ==> NaN
+  0,1 ==> 0
+  1,0 ==> Infinity
+  1,1 ==> 1
+  5,6 ==> 0.8333333333333334
+  6,5 ==> 1.2
+  101,-12 ==> -8.416666666666666
+  -12,101 ==> -0.1188118811881188
+  -1,5 ==> -0.2
+  5,-1 ==> -5
+  -1,-1 ==> 1
+  0.12,0.12 ==> 1
+  0.812,1 ==> 0.812
+  1.821,0 ==> Infinity
+  1,1.212 ==> 0.8250825082508251
+  5.543,6 ==> 0.9238333333333334
+  6,5.121 ==> 1.1716461628588166
+  101.001,-12 ==> -8.41675
+  -12.001,101 ==> -0.11882178217821782
+  -1,5.123 ==> -0.19519812609798945
+  5,-1.123 ==> -4.452359750667854
+  -1,-1.123 ==> 0.8904719501335708
+dmin
+  0,0 ==> 0
+  0,1 ==> 0
+  1,0 ==> 0
+  1,1 ==> 1
+  5,6 ==> 5
+  6,5 ==> 5
+  101,-12 ==> -12
+  -12,101 ==> -12
+  -1,5 ==> -1
+  5,-1 ==> -1
+  -1,-1 ==> -1
+  0.12,0.12 ==> 0.12
+  0.812,1 ==> 0.812
+  1.821,0 ==> 0
+  1,1.212 ==> 1
+  5.543,6 ==> 5.543
+  6,5.121 ==> 5.121
+  101.001,-12 ==> -12
+  -12.001,101 ==> -12.001
+  -1,5.123 ==> -1
+  5,-1.123 ==> -1.123
+  -1,-1.123 ==> -1.123
+dmax
+  0,0 ==> 0
+  0,1 ==> 1
+  1,0 ==> 1
+  1,1 ==> 1
+  5,6 ==> 6
+  6,5 ==> 6
+  101,-12 ==> 101
+  -12,101 ==> 101
+  -1,5 ==> 5
+  5,-1 ==> 5
+  -1,-1 ==> -1
+  0.12,0.12 ==> 0.12
+  0.812,1 ==> 1
+  1.821,0 ==> 1.821
+  1,1.212 ==> 1.212
+  5.543,6 ==> 6
+  6,5.121 ==> 6
+  101.001,-12 ==> 101.001
+  -12.001,101 ==> 101
+  -1,5.123 ==> 5.123
+  5,-1.123 ==> 5
+  -1,-1.123 ==> -1
+deq
+  0,0 ==> 1
+  0,1 ==> 0
+  1,0 ==> 0
+  1,1 ==> 1
+  5,6 ==> 0
+  6,5 ==> 0
+  101,-12 ==> 0
+  -12,101 ==> 0
+  -1,5 ==> 0
+  5,-1 ==> 0
+  -1,-1 ==> 1
+  0.12,0.12 ==> 1
+  0.812,1 ==> 0
+  1.821,0 ==> 0
+  1,1.212 ==> 0
+  5.543,6 ==> 0
+  6,5.121 ==> 0
+  101.001,-12 ==> 0
+  -12.001,101 ==> 0
+  -1,5.123 ==> 0
+  5,-1.123 ==> 0
+  -1,-1.123 ==> 0
+dne
+  0,0 ==> 0
+  0,1 ==> 1
+  1,0 ==> 1
+  1,1 ==> 0
+  5,6 ==> 1
+  6,5 ==> 1
+  101,-12 ==> 1
+  -12,101 ==> 1
+  -1,5 ==> 1
+  5,-1 ==> 1
+  -1,-1 ==> 0
+  0.12,0.12 ==> 0
+  0.812,1 ==> 1
+  1.821,0 ==> 1
+  1,1.212 ==> 1
+  5.543,6 ==> 1
+  6,5.121 ==> 1
+  101.001,-12 ==> 1
+  -12.001,101 ==> 1
+  -1,5.123 ==> 1
+  5,-1.123 ==> 1
+  -1,-1.123 ==> 1
+dlt
+  0,0 ==> 0
+  0,1 ==> 1
+  1,0 ==> 0
+  1,1 ==> 0
+  5,6 ==> 1
+  6,5 ==> 0
+  101,-12 ==> 0
+  -12,101 ==> 1
+  -1,5 ==> 1
+  5,-1 ==> 0
+  -1,-1 ==> 0
+  0.12,0.12 ==> 0
+  0.812,1 ==> 1
+  1.821,0 ==> 0
+  1,1.212 ==> 1
+  5.543,6 ==> 1
+  6,5.121 ==> 0
+  101.001,-12 ==> 0
+  -12.001,101 ==> 1
+  -1,5.123 ==> 1
+  5,-1.123 ==> 0
+  -1,-1.123 ==> 0
+dle
+  0,0 ==> 1
+  0,1 ==> 1
+  1,0 ==> 0
+  1,1 ==> 1
+  5,6 ==> 1
+  6,5 ==> 0
+  101,-12 ==> 0
+  -12,101 ==> 1
+  -1,5 ==> 1
+  5,-1 ==> 0
+  -1,-1 ==> 1
+  0.12,0.12 ==> 1
+  0.812,1 ==> 1
+  1.821,0 ==> 0
+  1,1.212 ==> 1
+  5.543,6 ==> 1
+  6,5.121 ==> 0
+  101.001,-12 ==> 0
+  -12.001,101 ==> 1
+  -1,5.123 ==> 1
+  5,-1.123 ==> 0
+  -1,-1.123 ==> 0
+dgt
+  0,0 ==> 0
+  0,1 ==> 0
+  1,0 ==> 1
+  1,1 ==> 0
+  5,6 ==> 0
+  6,5 ==> 1
+  101,-12 ==> 1
+  -12,101 ==> 0
+  -1,5 ==> 0
+  5,-1 ==> 1
+  -1,-1 ==> 0
+  0.12,0.12 ==> 0
+  0.812,1 ==> 0
+  1.821,0 ==> 1
+  1,1.212 ==> 0
+  5.543,6 ==> 0
+  6,5.121 ==> 1
+  101.001,-12 ==> 1
+  -12.001,101 ==> 0
+  -1,5.123 ==> 0
+  5,-1.123 ==> 1
+  -1,-1.123 ==> 1
+dge
+  0,0 ==> 1
+  0,1 ==> 0
+  1,0 ==> 1
+  1,1 ==> 1
+  5,6 ==> 0
+  6,5 ==> 1
+  101,-12 ==> 1
+  -12,101 ==> 0
+  -1,5 ==> 0
+  5,-1 ==> 1
+  -1,-1 ==> 1
+  0.12,0.12 ==> 1
+  0.812,1 ==> 0
+  1.821,0 ==> 1
+  1,1.212 ==> 0
+  5.543,6 ==> 0
+  6,5.121 ==> 1
+  101.001,-12 ==> 1
+  -12.001,101 ==> 0
+  -1,5.123 ==> 0
+  5,-1.123 ==> 1
+  -1,-1.123 ==> 1
+int_to_double
+  0 ==> 1.23
+  1 ==> 2.23
+  -1 ==> 0.22999999999999998
+  0.5 ==> 1.23
+  -0.5 ==> 1.23
+  1.4 ==> 2.23
+  -1.4 ==> 0.22999999999999998
+  1.6 ==> 2.23
+  -1.6 ==> 0.22999999999999998
+  5.1 ==> 6.23
+  5.3 ==> 6.23
+  5.7 ==> 6.23
+  5.9 ==> 6.23
+  -1 ==> 0.22999999999999998
+  0 ==> 1.23
+  -2 ==> -0.77
+  4294967296 ==> 1.23
+  4294967294 ==> -0.77
+  1 ==> 2.23
+  -3 ==> -1.77
+  4294967297 ==> 2.23
+  4294967293 ==> -1.77
+uint_to_double
+  0 ==> 1.23
+  1 ==> 2.23
+  -1 ==> 4294967296.23
+  0.5 ==> 1.23
+  -0.5 ==> 1.23
+  1.4 ==> 2.23
+  -1.4 ==> 4294967296.23
+  1.6 ==> 2.23
+  -1.6 ==> 4294967296.23
+  5.1 ==> 6.23
+  5.3 ==> 6.23
+  5.7 ==> 6.23
+  5.9 ==> 6.23
+  -1 ==> 4294967296.23
+  0 ==> 1.23
+  -2 ==> 4294967295.23
+  4294967296 ==> 1.23
+  4294967294 ==> 4294967295.23
+  1 ==> 2.23
+  -3 ==> 4294967294.23
+  4294967297 ==> 2.23
+  4294967293 ==> 4294967294.23
+double_to_int
+  0 ==> 1
+  1 ==> 2
+  -1 ==> 0
+  0.5 ==> 1
+  -0.5 ==> 0
+  1.4 ==> 2
+  -1.4 ==> 0
+  1.6 ==> 2
+  -1.6 ==> 0
+  5.1 ==> 6
+  5.3 ==> 6
+  5.7 ==> 6
+  5.9 ==> 7
+  -1 ==> 0
+  0 ==> 1
+  -2 ==> 0
+  4294967296 ==> 1
+  4294967294 ==> -1
+  1 ==> 2
+  -3 ==> -1
+  4294967297 ==> 2
+  4294967293 ==> -2
+double_to_uint
+  0 ==> 1
+  1 ==> 2
+  -1 ==> 0
+  0.5 ==> 1
+  -0.5 ==> 0
+  1.4 ==> 2
+  -1.4 ==> 0
+  1.6 ==> 2
+  -1.6 ==> 0
+  5.1 ==> 6
+  5.3 ==> 6
+  5.7 ==> 6
+  5.9 ==> 7
+  -1 ==> 0
+  0 ==> 1
+  -2 ==> 0
+  4294967296 ==> 1
+  4294967294 ==> -1
+  1 ==> 2
+  -3 ==> -1
+  4294967297 ==> 2
+  4294967293 ==> -2
+int_to_float
+  0 ==> 1.2300000190734863
+  1 ==> 2.2300000190734863
+  -1 ==> 0.23000000417232513
+  0.5 ==> 1.2300000190734863
+  -0.5 ==> 1.2300000190734863
+  1.4 ==> 2.2300000190734863
+  -1.4 ==> 0.23000000417232513
+  1.6 ==> 2.2300000190734863
+  -1.6 ==> 0.23000000417232513
+  5.1 ==> 6.230000019073486
+  5.3 ==> 6.230000019073486
+  5.7 ==> 6.230000019073486
+  5.9 ==> 6.230000019073486
+  -1 ==> 0.23000000417232513
+  0 ==> 1.2300000190734863
+  -2 ==> -0.7699999809265137
+  4294967296 ==> 1.2300000190734863
+  4294967294 ==> -0.7699999809265137
+  1 ==> 2.2300000190734863
+  -3 ==> -1.7699999809265137
+  4294967297 ==> 2.2300000190734863
+  4294967293 ==> -1.7699999809265137
+uint_to_float
+  0 ==> 1.2300000190734863
+  1 ==> 2.2300000190734863
+  -1 ==> 4294967296
+  0.5 ==> 1.2300000190734863
+  -0.5 ==> 1.2300000190734863
+  1.4 ==> 2.2300000190734863
+  -1.4 ==> 4294967296
+  1.6 ==> 2.2300000190734863
+  -1.6 ==> 4294967296
+  5.1 ==> 6.230000019073486
+  5.3 ==> 6.230000019073486
+  5.7 ==> 6.230000019073486
+  5.9 ==> 6.230000019073486
+  -1 ==> 4294967296
+  0 ==> 1.2300000190734863
+  -2 ==> 4294967296
+  4294967296 ==> 1.2300000190734863
+  4294967294 ==> 4294967296
+  1 ==> 2.2300000190734863
+  -3 ==> 4294967296
+  4294967297 ==> 2.2300000190734863
+  4294967293 ==> 4294967296
+float_to_int
+  0 ==> 1
+  1 ==> 2
+  -1 ==> 0
+  0.5 ==> 1
+  -0.5 ==> 0
+  1.4 ==> 2
+  -1.4 ==> 0
+  1.6 ==> 2
+  -1.6 ==> 0
+  5.1 ==> 6
+  5.3 ==> 6
+  5.7 ==> 6
+  5.9 ==> 7
+  -1 ==> 0
+  0 ==> 1
+  -2 ==> 0
+  4294967296 ==> 0
+  4294967294 ==> 0
+  1 ==> 2
+  -3 ==> -1
+  4294967297 ==> 0
+  4294967293 ==> 0
+float_to_uint
+  0 ==> 1
+  1 ==> 2
+  -1 ==> 0
+  0.5 ==> 1
+  -0.5 ==> 0
+  1.4 ==> 2
+  -1.4 ==> 0
+  1.6 ==> 2
+  -1.6 ==> 0
+  5.1 ==> 6
+  5.3 ==> 6
+  5.7 ==> 6
+  5.9 ==> 7
+  -1 ==> 0
+  0 ==> 1
+  -2 ==> 0
+  4294967296 ==> 0
+  4294967294 ==> 0
+  1 ==> 2
+  -3 ==> -1
+  4294967297 ==> 0
+  4294967293 ==> 0
+done.
diff --git a/binaryen/test/fn_prolog_epilog.debugInfo.wasm b/binaryen/test/fn_prolog_epilog.debugInfo.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/fn_prolog_epilog.debugInfo.wasm differ
diff --git a/binaryen/test/fn_prolog_epilog.debugInfo.wasm.fromBinary b/binaryen/test/fn_prolog_epilog.debugInfo.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/fn_prolog_epilog.debugInfo.wasm.fromBinary
@@ -0,0 +1,18 @@
+(module
+ (type $none_=>_none (func))
+ ;;@ src.cpp:1:1
+ (func $0
+  (nop)
+  ;;@ src.cpp:2:1
+  (block $label$1
+   ;;@ src.cpp:2:2
+   (block $label$2
+    (br $label$2)
+   )
+  )
+  ;;@ src.cpp:3:1
+  (return)
+  ;;@ src.cpp:3:2
+ )
+)
+
diff --git a/binaryen/test/fn_prolog_epilog.debugInfo.wasm.map b/binaryen/test/fn_prolog_epilog.debugInfo.wasm.map
new file mode 100644
--- /dev/null
+++ b/binaryen/test/fn_prolog_epilog.debugInfo.wasm.map
@@ -0,0 +1,1 @@
+{"version":3,"sources":["src.cpp"],"names":[],"mappings":"sBAAC,EACA,EAAC,MACD,CAAC"}
diff --git a/binaryen/test/fn_prolog_epilog.debugInfo.wast b/binaryen/test/fn_prolog_epilog.debugInfo.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/fn_prolog_epilog.debugInfo.wast
@@ -0,0 +1,16 @@
+(module
+  ;;@ src.cpp:1:1
+  (func
+    (nop)
+    ;;@ src.cpp:2:1
+    (block $l0
+      ;;@ src.cpp:2:2
+      (block $l1
+        (br $l1)
+      )
+    )
+    ;;@ src.cpp:3:1
+    (return)
+    ;;@ src.cpp:3:2
+  )
+)
diff --git a/binaryen/test/fn_prolog_epilog.debugInfo.wast.from-wast b/binaryen/test/fn_prolog_epilog.debugInfo.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/fn_prolog_epilog.debugInfo.wast.from-wast
@@ -0,0 +1,17 @@
+(module
+ (type $none_=>_none (func))
+ ;;@ src.cpp:1:1
+ (func $0
+  (nop)
+  ;;@ src.cpp:2:1
+  (block $l0
+   ;;@ src.cpp:2:2
+   (block $l1
+    (br $l1)
+   )
+  )
+  ;;@ src.cpp:3:1
+  (return)
+  ;;@ src.cpp:3:2
+ )
+)
diff --git a/binaryen/test/fn_prolog_epilog.debugInfo.wast.fromBinary b/binaryen/test/fn_prolog_epilog.debugInfo.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/fn_prolog_epilog.debugInfo.wast.fromBinary
@@ -0,0 +1,13 @@
+(module
+ (type $none_=>_none (func))
+ (func $0
+  (nop)
+  (block $label$1
+   (block $label$2
+    (br $label$2)
+   )
+  )
+  (return)
+ )
+)
+
diff --git a/binaryen/test/fn_prolog_epilog.debugInfo.wast.fromBinary.noDebugInfo b/binaryen/test/fn_prolog_epilog.debugInfo.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/fn_prolog_epilog.debugInfo.wast.fromBinary.noDebugInfo
@@ -0,0 +1,13 @@
+(module
+ (type $none_=>_none (func))
+ (func $0
+  (nop)
+  (block $label$1
+   (block $label$2
+    (br $label$2)
+   )
+  )
+  (return)
+ )
+)
+
diff --git a/binaryen/test/gc.wast b/binaryen/test/gc.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/gc.wast
@@ -0,0 +1,71 @@
+;; A preliminary test for prototype GC types and instructions.
+;; TODO: Move subtype tests from reference-types.wast here?
+;; TODO: The test assumes that `(i31.new (i32.const N))` is a valid constant
+;; initializer for i31ref types globals, which isn't yet specified.
+
+(module
+  ;; Test global initializer expressions
+  (global $global_anyref (mut anyref) (ref.null any))
+  (global $global_eqref (mut eqref) (ref.null eq))
+  (global $global_i31ref (mut i31ref) (i31.new (i32.const 0)))
+
+  ;; Test subtype relationship in global initializer expressions
+  (global $global_anyref2 (mut anyref) (ref.null eq))
+  (global $global_anyref3 (mut anyref) (i31.new (i32.const 0)))
+  (global $global_eqref2 (mut eqref) (i31.new (i32.const 0)))
+
+  (func $test
+    (local $local_i32 i32)
+    (local $local_anyref anyref)
+    (local $local_eqref eqref)
+    (local $local_i31ref i31ref)
+
+    ;; Test types for local.get/set
+    (local.set $local_anyref (local.get $local_anyref))
+    (local.set $local_anyref (global.get $global_anyref))
+    (local.set $local_anyref (ref.null any))
+    (local.set $local_eqref (local.get $local_eqref))
+    (local.set $local_eqref (global.get $global_eqref))
+    (local.set $local_eqref (ref.null eq))
+    (local.set $local_i31ref (local.get $local_i31ref))
+    (local.set $local_i31ref (global.get $global_i31ref))
+    (local.set $local_i31ref (i31.new (i32.const 0)))
+
+    ;; Test subtype relationship for local.set
+    (local.set $local_anyref (local.get $local_eqref))
+    (local.set $local_anyref (global.get $global_eqref))
+    (local.set $local_anyref (ref.null eq))
+    (local.set $local_anyref (local.get $local_i31ref))
+    (local.set $local_anyref (global.get $global_i31ref))
+    (local.set $local_anyref (i31.new (i32.const 0)))
+    (local.set $local_eqref (local.get $local_i31ref))
+    (local.set $local_eqref (global.get $global_i31ref))
+    (local.set $local_eqref (i31.new (i32.const 0)))
+
+    ;; Test types for global.get/set
+    (global.set $global_anyref (local.get $local_anyref))
+    (global.set $global_anyref (global.get $global_anyref))
+    (global.set $global_anyref (ref.null any))
+    (global.set $global_eqref (local.get $local_eqref))
+    (global.set $global_eqref (global.get $global_eqref))
+    (global.set $global_eqref (ref.null eq))
+    (global.set $global_i31ref (local.get $local_i31ref))
+    (global.set $global_i31ref (global.get $global_i31ref))
+    (global.set $global_i31ref (i31.new (i32.const 0)))
+
+    ;; Test subtype relationship for global.set
+    (global.set $global_anyref (local.get $local_eqref))
+    (global.set $global_anyref (global.get $global_eqref))
+    (global.set $global_anyref (ref.null eq))
+    (global.set $global_anyref (local.get $local_i31ref))
+    (global.set $global_anyref (global.get $global_i31ref))
+    (global.set $global_anyref (i31.new (i32.const 0)))
+    (global.set $global_eqref (local.get $local_i31ref))
+    (global.set $global_eqref (global.get $global_i31ref))
+    (global.set $global_eqref (i31.new (i32.const 0)))
+
+    ;; Test i31.get_s/u
+    (local.set $local_i32 (i31.get_s (local.get $local_i31ref)))
+    (local.set $local_i32 (i31.get_u (local.get $local_i31ref)))
+  )
+)
diff --git a/binaryen/test/gc.wast.from-wast b/binaryen/test/gc.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/gc.wast.from-wast
@@ -0,0 +1,151 @@
+(module
+ (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
+  (i32.const 0)
+ ))
+ (global $global_anyref2 (mut anyref) (ref.null eq))
+ (global $global_anyref3 (mut anyref) (i31.new
+  (i32.const 0)
+ ))
+ (global $global_eqref2 (mut eqref) (i31.new
+  (i32.const 0)
+ ))
+ (func $test
+  (local $local_i32 i32)
+  (local $local_anyref anyref)
+  (local $local_eqref eqref)
+  (local $local_i31ref i31ref)
+  (local.set $local_anyref
+   (local.get $local_anyref)
+  )
+  (local.set $local_anyref
+   (global.get $global_anyref)
+  )
+  (local.set $local_anyref
+   (ref.null any)
+  )
+  (local.set $local_eqref
+   (local.get $local_eqref)
+  )
+  (local.set $local_eqref
+   (global.get $global_eqref)
+  )
+  (local.set $local_eqref
+   (ref.null eq)
+  )
+  (local.set $local_i31ref
+   (local.get $local_i31ref)
+  )
+  (local.set $local_i31ref
+   (global.get $global_i31ref)
+  )
+  (local.set $local_i31ref
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (local.set $local_anyref
+   (local.get $local_eqref)
+  )
+  (local.set $local_anyref
+   (global.get $global_eqref)
+  )
+  (local.set $local_anyref
+   (ref.null eq)
+  )
+  (local.set $local_anyref
+   (local.get $local_i31ref)
+  )
+  (local.set $local_anyref
+   (global.get $global_i31ref)
+  )
+  (local.set $local_anyref
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (local.set $local_eqref
+   (local.get $local_i31ref)
+  )
+  (local.set $local_eqref
+   (global.get $global_i31ref)
+  )
+  (local.set $local_eqref
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (global.set $global_anyref
+   (local.get $local_anyref)
+  )
+  (global.set $global_anyref
+   (global.get $global_anyref)
+  )
+  (global.set $global_anyref
+   (ref.null any)
+  )
+  (global.set $global_eqref
+   (local.get $local_eqref)
+  )
+  (global.set $global_eqref
+   (global.get $global_eqref)
+  )
+  (global.set $global_eqref
+   (ref.null eq)
+  )
+  (global.set $global_i31ref
+   (local.get $local_i31ref)
+  )
+  (global.set $global_i31ref
+   (global.get $global_i31ref)
+  )
+  (global.set $global_i31ref
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (global.set $global_anyref
+   (local.get $local_eqref)
+  )
+  (global.set $global_anyref
+   (global.get $global_eqref)
+  )
+  (global.set $global_anyref
+   (ref.null eq)
+  )
+  (global.set $global_anyref
+   (local.get $local_i31ref)
+  )
+  (global.set $global_anyref
+   (global.get $global_i31ref)
+  )
+  (global.set $global_anyref
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (global.set $global_eqref
+   (local.get $local_i31ref)
+  )
+  (global.set $global_eqref
+   (global.get $global_i31ref)
+  )
+  (global.set $global_eqref
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (local.set $local_i32
+   (i31.get_s
+    (local.get $local_i31ref)
+   )
+  )
+  (local.set $local_i32
+   (i31.get_u
+    (local.get $local_i31ref)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/gc.wast.fromBinary b/binaryen/test/gc.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/gc.wast.fromBinary
@@ -0,0 +1,152 @@
+(module
+ (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
+  (i32.const 0)
+ ))
+ (global $global_anyref2 (mut anyref) (ref.null eq))
+ (global $global_anyref3 (mut anyref) (i31.new
+  (i32.const 0)
+ ))
+ (global $global_eqref2 (mut eqref) (i31.new
+  (i32.const 0)
+ ))
+ (func $test
+  (local $local_i32 i32)
+  (local $local_anyref anyref)
+  (local $local_eqref eqref)
+  (local $local_i31ref i31ref)
+  (local.set $local_anyref
+   (local.get $local_anyref)
+  )
+  (local.set $local_anyref
+   (global.get $global_anyref)
+  )
+  (local.set $local_anyref
+   (ref.null any)
+  )
+  (local.set $local_eqref
+   (local.get $local_eqref)
+  )
+  (local.set $local_eqref
+   (global.get $global_eqref)
+  )
+  (local.set $local_eqref
+   (ref.null eq)
+  )
+  (local.set $local_i31ref
+   (local.get $local_i31ref)
+  )
+  (local.set $local_i31ref
+   (global.get $global_i31ref)
+  )
+  (local.set $local_i31ref
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (local.set $local_anyref
+   (local.get $local_eqref)
+  )
+  (local.set $local_anyref
+   (global.get $global_eqref)
+  )
+  (local.set $local_anyref
+   (ref.null eq)
+  )
+  (local.set $local_anyref
+   (local.get $local_i31ref)
+  )
+  (local.set $local_anyref
+   (global.get $global_i31ref)
+  )
+  (local.set $local_anyref
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (local.set $local_eqref
+   (local.get $local_i31ref)
+  )
+  (local.set $local_eqref
+   (global.get $global_i31ref)
+  )
+  (local.set $local_eqref
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (global.set $global_anyref
+   (local.get $local_anyref)
+  )
+  (global.set $global_anyref
+   (global.get $global_anyref)
+  )
+  (global.set $global_anyref
+   (ref.null any)
+  )
+  (global.set $global_eqref
+   (local.get $local_eqref)
+  )
+  (global.set $global_eqref
+   (global.get $global_eqref)
+  )
+  (global.set $global_eqref
+   (ref.null eq)
+  )
+  (global.set $global_i31ref
+   (local.get $local_i31ref)
+  )
+  (global.set $global_i31ref
+   (global.get $global_i31ref)
+  )
+  (global.set $global_i31ref
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (global.set $global_anyref
+   (local.get $local_eqref)
+  )
+  (global.set $global_anyref
+   (global.get $global_eqref)
+  )
+  (global.set $global_anyref
+   (ref.null eq)
+  )
+  (global.set $global_anyref
+   (local.get $local_i31ref)
+  )
+  (global.set $global_anyref
+   (global.get $global_i31ref)
+  )
+  (global.set $global_anyref
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (global.set $global_eqref
+   (local.get $local_i31ref)
+  )
+  (global.set $global_eqref
+   (global.get $global_i31ref)
+  )
+  (global.set $global_eqref
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (local.set $local_i32
+   (i31.get_s
+    (local.get $local_i31ref)
+   )
+  )
+  (local.set $local_i32
+   (i31.get_u
+    (local.get $local_i31ref)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/gc.wast.fromBinary.noDebugInfo b/binaryen/test/gc.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/gc.wast.fromBinary.noDebugInfo
@@ -0,0 +1,152 @@
+(module
+ (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
+  (i32.const 0)
+ ))
+ (global $global$3 (mut anyref) (ref.null eq))
+ (global $global$4 (mut anyref) (i31.new
+  (i32.const 0)
+ ))
+ (global $global$5 (mut eqref) (i31.new
+  (i32.const 0)
+ ))
+ (func $0
+  (local $0 i32)
+  (local $1 anyref)
+  (local $2 eqref)
+  (local $3 i31ref)
+  (local.set $1
+   (local.get $1)
+  )
+  (local.set $1
+   (global.get $global$0)
+  )
+  (local.set $1
+   (ref.null any)
+  )
+  (local.set $2
+   (local.get $2)
+  )
+  (local.set $2
+   (global.get $global$1)
+  )
+  (local.set $2
+   (ref.null eq)
+  )
+  (local.set $3
+   (local.get $3)
+  )
+  (local.set $3
+   (global.get $global$2)
+  )
+  (local.set $3
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (local.set $1
+   (local.get $2)
+  )
+  (local.set $1
+   (global.get $global$1)
+  )
+  (local.set $1
+   (ref.null eq)
+  )
+  (local.set $1
+   (local.get $3)
+  )
+  (local.set $1
+   (global.get $global$2)
+  )
+  (local.set $1
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (local.set $2
+   (local.get $3)
+  )
+  (local.set $2
+   (global.get $global$2)
+  )
+  (local.set $2
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (global.set $global$0
+   (local.get $1)
+  )
+  (global.set $global$0
+   (global.get $global$0)
+  )
+  (global.set $global$0
+   (ref.null any)
+  )
+  (global.set $global$1
+   (local.get $2)
+  )
+  (global.set $global$1
+   (global.get $global$1)
+  )
+  (global.set $global$1
+   (ref.null eq)
+  )
+  (global.set $global$2
+   (local.get $3)
+  )
+  (global.set $global$2
+   (global.get $global$2)
+  )
+  (global.set $global$2
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (global.set $global$0
+   (local.get $2)
+  )
+  (global.set $global$0
+   (global.get $global$1)
+  )
+  (global.set $global$0
+   (ref.null eq)
+  )
+  (global.set $global$0
+   (local.get $3)
+  )
+  (global.set $global$0
+   (global.get $global$2)
+  )
+  (global.set $global$0
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (global.set $global$1
+   (local.get $3)
+  )
+  (global.set $global$1
+   (global.get $global$2)
+  )
+  (global.set $global$1
+   (i31.new
+    (i32.const 0)
+   )
+  )
+  (local.set $0
+   (i31.get_s
+    (local.get $3)
+   )
+  )
+  (local.set $0
+   (i31.get_u
+    (local.get $3)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/grow_memory.cpp b/binaryen/test/grow_memory.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/grow_memory.cpp
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <emscripten.h>
+
+volatile int writeOnly;
+
+int main() {
+  EM_ASM({
+    assert(HEAPU8.length === 16*1024*1024);
+  });
+  for (int i = 0; i < 20; i++) {
+    printf("alloc 1MB: %d\n", i);
+    writeOnly = (int)malloc(1024*1024);
+  }
+  EM_ASM({
+    assert(HEAPU8.length > 16*1024*1024);
+  });
+  printf("ok.\n");
+}
+
diff --git a/binaryen/test/grow_memory.emcc b/binaryen/test/grow_memory.emcc
new file mode 100644
--- /dev/null
+++ b/binaryen/test/grow_memory.emcc
@@ -0,0 +1,1 @@
+["-s", "ALLOW_MEMORY_GROWTH=1"]
diff --git a/binaryen/test/grow_memory.txt b/binaryen/test/grow_memory.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/grow_memory.txt
@@ -0,0 +1,22 @@
+alloc 1MB: 0
+alloc 1MB: 1
+alloc 1MB: 2
+alloc 1MB: 3
+alloc 1MB: 4
+alloc 1MB: 5
+alloc 1MB: 6
+alloc 1MB: 7
+alloc 1MB: 8
+alloc 1MB: 9
+alloc 1MB: 10
+alloc 1MB: 11
+alloc 1MB: 12
+alloc 1MB: 13
+alloc 1MB: 14
+alloc 1MB: 15
+alloc 1MB: 16
+alloc 1MB: 17
+alloc 1MB: 18
+alloc 1MB: 19
+ok.
+
diff --git a/binaryen/test/grow_memory.wast b/binaryen/test/grow_memory.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/grow_memory.wast
@@ -0,0 +1,17 @@
+(module
+ (type $0 (func (param i32) (result i32)))
+ (type $1 (func (result i32)))
+ (memory $0 1)
+ (export "memory" (memory $0))
+ (export "grow" (func $0))
+ (export "current" (func $1))
+ (func $0 (; 0 ;) (type $0) (param $var$0 i32) (result i32)
+  (memory.grow
+   (local.get $var$0)
+  )
+ )
+ (func $1 (; 1 ;) (type $1) (result i32)
+  (memory.size)
+ )
+)
+
diff --git a/binaryen/test/grow_memory.wast.from-wast b/binaryen/test/grow_memory.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/grow_memory.wast.from-wast
@@ -0,0 +1,16 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 1)
+ (export "memory" (memory $0))
+ (export "grow" (func $0))
+ (export "current" (func $1))
+ (func $0 (param $var$0 i32) (result i32)
+  (memory.grow
+   (local.get $var$0)
+  )
+ )
+ (func $1 (result i32)
+  (memory.size)
+ )
+)
diff --git a/binaryen/test/grow_memory.wast.fromBinary b/binaryen/test/grow_memory.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/grow_memory.wast.fromBinary
@@ -0,0 +1,17 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 1)
+ (export "memory" (memory $0))
+ (export "grow" (func $0))
+ (export "current" (func $1))
+ (func $0 (param $var$0 i32) (result i32)
+  (memory.grow
+   (local.get $var$0)
+  )
+ )
+ (func $1 (result i32)
+  (memory.size)
+ )
+)
+
diff --git a/binaryen/test/grow_memory.wast.fromBinary.noDebugInfo b/binaryen/test/grow_memory.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/grow_memory.wast.fromBinary.noDebugInfo
@@ -0,0 +1,17 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 1)
+ (export "memory" (memory $0))
+ (export "grow" (func $0))
+ (export "current" (func $1))
+ (func $0 (param $0 i32) (result i32)
+  (memory.grow
+   (local.get $0)
+  )
+ )
+ (func $1 (result i32)
+  (memory.size)
+ )
+)
+
diff --git a/binaryen/test/hello_libcxx.cpp b/binaryen/test/hello_libcxx.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/hello_libcxx.cpp
@@ -0,0 +1,8 @@
+#include <iostream>
+
+int main()
+{
+  std::cout << "hello, world!" << std::endl;
+  return 0;
+}
+
diff --git a/binaryen/test/hello_libcxx.txt b/binaryen/test/hello_libcxx.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/hello_libcxx.txt
@@ -0,0 +1,2 @@
+hello, world!
+
diff --git a/binaryen/test/hello_world.asm.js b/binaryen/test/hello_world.asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/hello_world.asm.js
@@ -0,0 +1,10 @@
+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/hello_world.c b/binaryen/test/hello_world.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/hello_world.c
@@ -0,0 +1,7 @@
+#include<stdio.h>
+
+int main() {
+  printf("hello, world!\n");
+  return 0;
+}
+
diff --git a/binaryen/test/hello_world.txt b/binaryen/test/hello_world.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/hello_world.txt
@@ -0,0 +1,2 @@
+hello, world!
+
diff --git a/binaryen/test/hello_world.wast.from-wast b/binaryen/test/hello_world.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/hello_world.wast.from-wast
@@ -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 (; 0 ;) (param $x i32) (param $y i32) (result i32)
+  (i32.add
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+)
diff --git a/binaryen/test/hello_world.wast.fromBinary b/binaryen/test/hello_world.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/hello_world.wast.fromBinary
@@ -0,0 +1,12 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (memory $0 256 256)
+ (export "add" (func $add))
+ (func $add (; 0 ;) (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
+
diff --git a/binaryen/test/hello_world.wast.fromBinary.noDebugInfo b/binaryen/test/hello_world.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/hello_world.wast.fromBinary.noDebugInfo
@@ -0,0 +1,12 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (memory $0 256 256)
+ (export "add" (func $0))
+ (func $0 (; 0 ;) (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
+
diff --git a/binaryen/test/hello_world.wat b/binaryen/test/hello_world.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/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/i64-setTempRet0.asm.js b/binaryen/test/i64-setTempRet0.asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/i64-setTempRet0.asm.js
@@ -0,0 +1,24 @@
+//
+// 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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/importedSignCast.asm.js
@@ -0,0 +1,14 @@
+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 b/binaryen/test/imported_memory.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/imported_memory.wast
@@ -0,0 +1,4 @@
+(module
+  (import "env" "memory" (memory $0 256 256))
+  (import "env" "table" (table 256 256 funcref))
+)
diff --git a/binaryen/test/imported_memory.wast.from-wast b/binaryen/test/imported_memory.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/imported_memory.wast.from-wast
@@ -0,0 +1,4 @@
+(module
+ (import "env" "memory" (memory $0 256 256))
+ (import "env" "table" (table $timport$0 256 256 funcref))
+)
diff --git a/binaryen/test/imported_memory.wast.fromBinary b/binaryen/test/imported_memory.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/imported_memory.wast.fromBinary
@@ -0,0 +1,5 @@
+(module
+ (import "env" "memory" (memory $0 256 256))
+ (import "env" "table" (table $timport$0 256 256 funcref))
+)
+
diff --git a/binaryen/test/imported_memory.wast.fromBinary.noDebugInfo b/binaryen/test/imported_memory.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/imported_memory.wast.fromBinary.noDebugInfo
@@ -0,0 +1,5 @@
+(module
+ (import "env" "memory" (memory $mimport$0 256 256))
+ (import "env" "table" (table $timport$1 256 256 funcref))
+)
+
diff --git a/binaryen/test/imported_memory_growth.wast b/binaryen/test/imported_memory_growth.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/imported_memory_growth.wast
@@ -0,0 +1,4 @@
+(module
+  (import "env" "memory" (memory $0 256))
+  (import "env" "table" (table 256 funcref))
+)
diff --git a/binaryen/test/imported_memory_growth.wast.from-wast b/binaryen/test/imported_memory_growth.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/imported_memory_growth.wast.from-wast
@@ -0,0 +1,4 @@
+(module
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table $timport$0 256 funcref))
+)
diff --git a/binaryen/test/imported_memory_growth.wast.fromBinary b/binaryen/test/imported_memory_growth.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/imported_memory_growth.wast.fromBinary
@@ -0,0 +1,5 @@
+(module
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table $timport$0 256 funcref))
+)
+
diff --git a/binaryen/test/imported_memory_growth.wast.fromBinary.noDebugInfo b/binaryen/test/imported_memory_growth.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/imported_memory_growth.wast.fromBinary.noDebugInfo
@@ -0,0 +1,5 @@
+(module
+ (import "env" "memory" (memory $mimport$0 256))
+ (import "env" "table" (table $timport$1 256 funcref))
+)
+
diff --git a/binaryen/test/int_ops.c b/binaryen/test/int_ops.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/int_ops.c
@@ -0,0 +1,32 @@
+#include <emscripten.h>
+
+// unary
+int EMSCRIPTEN_KEEPALIVE clz(int x) { return __builtin_clz(x); }
+
+// binary
+int EMSCRIPTEN_KEEPALIVE add(int x, int y) { return x + y; }
+int EMSCRIPTEN_KEEPALIVE sub(int x, int y) { return x - y; }
+int EMSCRIPTEN_KEEPALIVE mul(int x, int y) { return x * y; }
+int EMSCRIPTEN_KEEPALIVE sdiv(int x, int y) { return x / y; }
+unsigned EMSCRIPTEN_KEEPALIVE udiv(unsigned x, unsigned y) { return x / y; }
+int EMSCRIPTEN_KEEPALIVE srem(int x, int y) { return x % y; }
+unsigned EMSCRIPTEN_KEEPALIVE urem(unsigned x, unsigned y) { return x % y; }
+int EMSCRIPTEN_KEEPALIVE and(int x, int y) { return x & y; }
+int EMSCRIPTEN_KEEPALIVE or(int x, int y) { return x | y; }
+int EMSCRIPTEN_KEEPALIVE xor(int x, int y) { return x ^ y; }
+int EMSCRIPTEN_KEEPALIVE shl(int x, int y) { return x << y; }
+int EMSCRIPTEN_KEEPALIVE sshr(int x, int y) { return x >> y; }
+unsigned EMSCRIPTEN_KEEPALIVE ushr(unsigned x, unsigned y) { return x >> y; }
+
+// comparisons
+int EMSCRIPTEN_KEEPALIVE eq(int x, int y) { return x == y; }
+int EMSCRIPTEN_KEEPALIVE ne(int x, int y) { return x != y; }
+int EMSCRIPTEN_KEEPALIVE lts(int x, int y) { return x < y; }
+int EMSCRIPTEN_KEEPALIVE ltu(unsigned x, unsigned y) { return x < y; }
+int EMSCRIPTEN_KEEPALIVE les(int x, int y) { return x <= y; }
+int EMSCRIPTEN_KEEPALIVE leu(unsigned x, unsigned y) { return x <= y; }
+int EMSCRIPTEN_KEEPALIVE gts(int x, int y) { return x > y; }
+int EMSCRIPTEN_KEEPALIVE gtu(unsigned x, unsigned y) { return x > y; }
+int EMSCRIPTEN_KEEPALIVE ges(int x, int y) { return x >= y; }
+int EMSCRIPTEN_KEEPALIVE geu(unsigned x, unsigned y) { return x >= y; }
+
diff --git a/binaryen/test/int_ops.emcc b/binaryen/test/int_ops.emcc
new file mode 100644
--- /dev/null
+++ b/binaryen/test/int_ops.emcc
@@ -0,0 +1,1 @@
+["-s", "ASSERTIONS=0"]
diff --git a/binaryen/test/int_ops.post.js b/binaryen/test/int_ops.post.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/int_ops.post.js
@@ -0,0 +1,53 @@
+
+// unary
+Module.print('clz');
+Module.print(Module._clz(1));
+Module.print(Module._clz(-1));
+Module.print(Module._clz(8));
+
+// binary
+function testBinary(name, noSecondZero, noSecondBig) {
+  Module.print(name);
+  function doTest(x, y) {
+    Module.print('  ' + [x, y] + ' ==> ' + Module['_' + name](x, y));
+  }
+  if (!noSecondZero) doTest(0, 0);
+  doTest(0, 1);
+  if (!noSecondZero) doTest(1, 0);
+  doTest(1, 1);
+  doTest(5, 6);
+  doTest(6, 5);
+  if (!noSecondBig) doTest(101, -12);
+  if (!noSecondBig) doTest(-12, 101);
+  doTest(-1, 5);
+  if (!noSecondBig) doTest(5, -1);
+  if (!noSecondBig) doTest(-1, -1);
+}
+testBinary('add');
+testBinary('sub');
+testBinary('mul');
+testBinary('sdiv', true);
+testBinary('udiv', true);
+testBinary('srem', true);
+testBinary('urem', true);
+testBinary('and');
+testBinary('or');
+testBinary('xor');
+testBinary('shl', false, true);
+testBinary('sshr', false, true);
+testBinary('ushr', false, true);
+
+// comparisons
+testBinary('eq');
+testBinary('ne');
+testBinary('lts');
+testBinary('ltu');
+testBinary('les');
+testBinary('leu');
+testBinary('gts');
+testBinary('gtu');
+testBinary('ges');
+testBinary('geu');
+
+Module.print('done.');
+
diff --git a/binaryen/test/int_ops.txt b/binaryen/test/int_ops.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/int_ops.txt
@@ -0,0 +1,261 @@
+clz
+31
+0
+28
+add
+  0,0 ==> 0
+  0,1 ==> 1
+  1,0 ==> 1
+  1,1 ==> 2
+  5,6 ==> 11
+  6,5 ==> 11
+  101,-12 ==> 89
+  -12,101 ==> 89
+  -1,5 ==> 4
+  5,-1 ==> 4
+  -1,-1 ==> -2
+sub
+  0,0 ==> 0
+  0,1 ==> -1
+  1,0 ==> 1
+  1,1 ==> 0
+  5,6 ==> -1
+  6,5 ==> 1
+  101,-12 ==> 113
+  -12,101 ==> -113
+  -1,5 ==> -6
+  5,-1 ==> 6
+  -1,-1 ==> 0
+mul
+  0,0 ==> 0
+  0,1 ==> 0
+  1,0 ==> 0
+  1,1 ==> 1
+  5,6 ==> 30
+  6,5 ==> 30
+  101,-12 ==> -1212
+  -12,101 ==> -1212
+  -1,5 ==> -5
+  5,-1 ==> -5
+  -1,-1 ==> 1
+sdiv
+  0,1 ==> 0
+  1,1 ==> 1
+  5,6 ==> 0
+  6,5 ==> 1
+  101,-12 ==> -8
+  -12,101 ==> 0
+  -1,5 ==> 0
+  5,-1 ==> -5
+  -1,-1 ==> 1
+udiv
+  0,1 ==> 0
+  1,1 ==> 1
+  5,6 ==> 0
+  6,5 ==> 1
+  101,-12 ==> 0
+  -12,101 ==> 42524428
+  -1,5 ==> 858993459
+  5,-1 ==> 0
+  -1,-1 ==> 1
+srem
+  0,1 ==> 0
+  1,1 ==> 0
+  5,6 ==> 5
+  6,5 ==> 1
+  101,-12 ==> 5
+  -12,101 ==> -12
+  -1,5 ==> -1
+  5,-1 ==> 0
+  -1,-1 ==> 0
+urem
+  0,1 ==> 0
+  1,1 ==> 0
+  5,6 ==> 5
+  6,5 ==> 1
+  101,-12 ==> 101
+  -12,101 ==> 56
+  -1,5 ==> 0
+  5,-1 ==> 5
+  -1,-1 ==> 0
+and
+  0,0 ==> 0
+  0,1 ==> 0
+  1,0 ==> 0
+  1,1 ==> 1
+  5,6 ==> 4
+  6,5 ==> 4
+  101,-12 ==> 100
+  -12,101 ==> 100
+  -1,5 ==> 5
+  5,-1 ==> 5
+  -1,-1 ==> -1
+or
+  0,0 ==> 0
+  0,1 ==> 1
+  1,0 ==> 1
+  1,1 ==> 1
+  5,6 ==> 7
+  6,5 ==> 7
+  101,-12 ==> -11
+  -12,101 ==> -11
+  -1,5 ==> -1
+  5,-1 ==> -1
+  -1,-1 ==> -1
+xor
+  0,0 ==> 0
+  0,1 ==> 1
+  1,0 ==> 1
+  1,1 ==> 0
+  5,6 ==> 3
+  6,5 ==> 3
+  101,-12 ==> -111
+  -12,101 ==> -111
+  -1,5 ==> -6
+  5,-1 ==> -6
+  -1,-1 ==> 0
+shl
+  0,0 ==> 0
+  0,1 ==> 0
+  1,0 ==> 1
+  1,1 ==> 2
+  5,6 ==> 320
+  6,5 ==> 192
+  -1,5 ==> -32
+sshr
+  0,0 ==> 0
+  0,1 ==> 0
+  1,0 ==> 1
+  1,1 ==> 0
+  5,6 ==> 0
+  6,5 ==> 0
+  -1,5 ==> -1
+ushr
+  0,0 ==> 0
+  0,1 ==> 0
+  1,0 ==> 1
+  1,1 ==> 0
+  5,6 ==> 0
+  6,5 ==> 0
+  -1,5 ==> 134217727
+eq
+  0,0 ==> 1
+  0,1 ==> 0
+  1,0 ==> 0
+  1,1 ==> 1
+  5,6 ==> 0
+  6,5 ==> 0
+  101,-12 ==> 0
+  -12,101 ==> 0
+  -1,5 ==> 0
+  5,-1 ==> 0
+  -1,-1 ==> 1
+ne
+  0,0 ==> 0
+  0,1 ==> 1
+  1,0 ==> 1
+  1,1 ==> 0
+  5,6 ==> 1
+  6,5 ==> 1
+  101,-12 ==> 1
+  -12,101 ==> 1
+  -1,5 ==> 1
+  5,-1 ==> 1
+  -1,-1 ==> 0
+lts
+  0,0 ==> 0
+  0,1 ==> 1
+  1,0 ==> 0
+  1,1 ==> 0
+  5,6 ==> 1
+  6,5 ==> 0
+  101,-12 ==> 0
+  -12,101 ==> 1
+  -1,5 ==> 1
+  5,-1 ==> 0
+  -1,-1 ==> 0
+ltu
+  0,0 ==> 0
+  0,1 ==> 1
+  1,0 ==> 0
+  1,1 ==> 0
+  5,6 ==> 1
+  6,5 ==> 0
+  101,-12 ==> 1
+  -12,101 ==> 0
+  -1,5 ==> 0
+  5,-1 ==> 1
+  -1,-1 ==> 0
+les
+  0,0 ==> 1
+  0,1 ==> 1
+  1,0 ==> 0
+  1,1 ==> 1
+  5,6 ==> 1
+  6,5 ==> 0
+  101,-12 ==> 0
+  -12,101 ==> 1
+  -1,5 ==> 1
+  5,-1 ==> 0
+  -1,-1 ==> 1
+leu
+  0,0 ==> 1
+  0,1 ==> 1
+  1,0 ==> 0
+  1,1 ==> 1
+  5,6 ==> 1
+  6,5 ==> 0
+  101,-12 ==> 1
+  -12,101 ==> 0
+  -1,5 ==> 0
+  5,-1 ==> 1
+  -1,-1 ==> 1
+gts
+  0,0 ==> 0
+  0,1 ==> 0
+  1,0 ==> 1
+  1,1 ==> 0
+  5,6 ==> 0
+  6,5 ==> 1
+  101,-12 ==> 1
+  -12,101 ==> 0
+  -1,5 ==> 0
+  5,-1 ==> 1
+  -1,-1 ==> 0
+gtu
+  0,0 ==> 0
+  0,1 ==> 0
+  1,0 ==> 1
+  1,1 ==> 0
+  5,6 ==> 0
+  6,5 ==> 1
+  101,-12 ==> 0
+  -12,101 ==> 1
+  -1,5 ==> 1
+  5,-1 ==> 0
+  -1,-1 ==> 0
+ges
+  0,0 ==> 1
+  0,1 ==> 0
+  1,0 ==> 1
+  1,1 ==> 1
+  5,6 ==> 0
+  6,5 ==> 1
+  101,-12 ==> 1
+  -12,101 ==> 0
+  -1,5 ==> 0
+  5,-1 ==> 1
+  -1,-1 ==> 1
+geu
+  0,0 ==> 1
+  0,1 ==> 0
+  1,0 ==> 1
+  1,1 ==> 1
+  5,6 ==> 0
+  6,5 ==> 1
+  101,-12 ==> 0
+  -12,101 ==> 1
+  -1,5 ==> 1
+  5,-1 ==> 0
+  -1,-1 ==> 1
+done.
diff --git a/binaryen/test/kitchen_sink.wast b/binaryen/test/kitchen_sink.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/kitchen_sink.wast
@@ -0,0 +1,707 @@
+(module
+  (type $0 (func (result i32)))
+  (memory $0 4096 4096)
+  (data (i32.const 1026) "\14\00")
+  (func $kitchensink (type $0) (result i32)
+    (block $block0 (result i32)
+      (drop
+        (i32.add
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.sub
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.mul
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.div_s
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.div_u
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.rem_s
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.rem_u
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.and
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.or
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.xor
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.shl
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.shr_u
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.shr_s
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.eq
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.ne
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.lt_s
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.le_s
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.lt_u
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.le_u
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.gt_s
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.ge_s
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.gt_u
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.ge_u
+          (i32.const 10)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.clz
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.ctz
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.popcnt
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i64.add
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.sub
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.mul
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.div_s
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.div_u
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.rem_s
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.rem_u
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.and
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.or
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.xor
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.shl
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.shr_u
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.shr_s
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.eq
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.ne
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.lt_s
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.le_s
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.lt_u
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.le_u
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.gt_s
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.ge_s
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.gt_u
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.ge_u
+          (i64.const 100)
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.clz
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.ctz
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.popcnt
+          (i64.const 100)
+        )
+      )
+      (drop
+        (f32.add
+          (f32.const 10)
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.sub
+          (f32.const 10)
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.mul
+          (f32.const 10)
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.div
+          (f32.const 10)
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.min
+          (f32.const 10)
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.max
+          (f32.const 10)
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.abs
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.neg
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.copysign
+          (f32.const 10)
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.ceil
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.floor
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.trunc
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.nearest
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.sqrt
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.eq
+          (f32.const 10)
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.ne
+          (f32.const 10)
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.lt
+          (f32.const 10)
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.le
+          (f32.const 10)
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.gt
+          (f32.const 10)
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f32.ge
+          (f32.const 10)
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f64.add
+          (f64.const 10)
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.sub
+          (f64.const 10)
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.mul
+          (f64.const 10)
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.div
+          (f64.const 10)
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.min
+          (f64.const 10)
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.max
+          (f64.const 10)
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.abs
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.neg
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.copysign
+          (f64.const 10)
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.ceil
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.floor
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.trunc
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.nearest
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.sqrt
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.eq
+          (f64.const 10)
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.ne
+          (f64.const 10)
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.lt
+          (f64.const 10)
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.le
+          (f64.const 10)
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.gt
+          (f64.const 10)
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f64.ge
+          (f64.const 10)
+          (f64.const 10)
+        )
+      )
+      (drop
+        (i32.trunc_f32_s
+          (f32.const 10)
+        )
+      )
+      (drop
+        (i32.trunc_f64_s
+          (f64.const 10)
+        )
+      )
+      (drop
+        (i32.trunc_f32_u
+          (f32.const 10)
+        )
+      )
+      (drop
+        (i32.trunc_f64_u
+          (f64.const 10)
+        )
+      )
+      (drop
+        (i32.trunc_sat_f32_s
+          (f32.const 10)
+        )
+      )
+      (drop
+        (i32.trunc_sat_f32_u
+          (f32.const 10)
+        )
+      )
+      (drop
+        (i32.trunc_sat_f64_s
+          (f64.const 10)
+        )
+      )
+      (drop
+        (i32.trunc_sat_f64_u
+          (f64.const 10)
+        )
+      )
+      (drop
+        (i32.wrap_i64
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i64.trunc_f32_s
+          (f32.const 10)
+        )
+      )
+      (drop
+        (i64.trunc_f64_s
+          (f64.const 10)
+        )
+      )
+      (drop
+        (i64.trunc_f32_u
+          (f32.const 10)
+        )
+      )
+      (drop
+        (i64.trunc_f64_u
+          (f64.const 10)
+        )
+      )
+      (drop
+        (i64.trunc_sat_f32_s
+          (f32.const 10)
+        )
+      )
+      (drop
+        (i64.trunc_sat_f32_u
+          (f32.const 10)
+        )
+      )
+      (drop
+        (i64.trunc_sat_f64_s
+          (f64.const 10)
+        )
+      )
+      (drop
+        (i64.trunc_sat_f64_u
+          (f64.const 10)
+        )
+      )
+      (drop
+        (i64.extend_i32_s
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i64.extend_i32_u
+          (i32.const 10)
+        )
+      )
+      (drop
+        (f32.convert_i32_s
+          (i32.const 10)
+        )
+      )
+      (drop
+        (f32.convert_i32_u
+          (i32.const 10)
+        )
+      )
+      (drop
+        (f32.convert_i64_s
+          (i64.const 100)
+        )
+      )
+      (drop
+        (f32.convert_i64_u
+          (i64.const 100)
+        )
+      )
+      (drop
+        (f32.demote_f64
+          (f64.const 10)
+        )
+      )
+      (drop
+        (f32.reinterpret_i32
+          (i32.const 10)
+        )
+      )
+      (drop
+        (f64.convert_i32_s
+          (i32.const 10)
+        )
+      )
+      (drop
+        (f64.convert_i32_u
+          (i32.const 10)
+        )
+      )
+      (drop
+        (f64.convert_i64_s
+          (i64.const 100)
+        )
+      )
+      (drop
+        (f64.convert_i64_u
+          (i64.const 100)
+        )
+      )
+      (drop
+        (f64.promote_f32
+          (f32.const 10)
+        )
+      )
+      (drop
+        (f64.reinterpret_i64
+          (i64.const 100)
+        )
+      )
+      (drop
+        (i32.reinterpret_f32
+          (f32.const 10)
+        )
+      )
+      (drop
+        (i64.reinterpret_f64
+          (f64.const 10)
+        )
+      )
+      (i32.const 0)
+    )
+  )
+)
diff --git a/binaryen/test/kitchen_sink.wast.from-wast b/binaryen/test/kitchen_sink.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/kitchen_sink.wast.from-wast
@@ -0,0 +1,707 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 4096 4096)
+ (data (i32.const 1026) "\14\00")
+ (func $kitchensink (result i32)
+  (block $block0 (result i32)
+   (drop
+    (i32.add
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.sub
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.mul
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.div_s
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.div_u
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.rem_s
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.rem_u
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.and
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.or
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.xor
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.shl
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.shr_u
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.shr_s
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.eq
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.ne
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.lt_s
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.le_s
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.lt_u
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.le_u
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.gt_s
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.ge_s
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.gt_u
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.ge_u
+     (i32.const 10)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.clz
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.ctz
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.popcnt
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i64.add
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.sub
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.mul
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.div_s
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.div_u
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.rem_s
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.rem_u
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.and
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.or
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.xor
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.shl
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.shr_u
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.shr_s
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.eq
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.ne
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.lt_s
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.le_s
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.lt_u
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.le_u
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.gt_s
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.ge_s
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.gt_u
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.ge_u
+     (i64.const 100)
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.clz
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.ctz
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.popcnt
+     (i64.const 100)
+    )
+   )
+   (drop
+    (f32.add
+     (f32.const 10)
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.sub
+     (f32.const 10)
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.mul
+     (f32.const 10)
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.div
+     (f32.const 10)
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.min
+     (f32.const 10)
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.max
+     (f32.const 10)
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.abs
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.neg
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.copysign
+     (f32.const 10)
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.ceil
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.floor
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.trunc
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.nearest
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.sqrt
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.eq
+     (f32.const 10)
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.ne
+     (f32.const 10)
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.lt
+     (f32.const 10)
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.le
+     (f32.const 10)
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.gt
+     (f32.const 10)
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f32.ge
+     (f32.const 10)
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f64.add
+     (f64.const 10)
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.sub
+     (f64.const 10)
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.mul
+     (f64.const 10)
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.div
+     (f64.const 10)
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.min
+     (f64.const 10)
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.max
+     (f64.const 10)
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.abs
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.neg
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.copysign
+     (f64.const 10)
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.ceil
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.floor
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.trunc
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.nearest
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.sqrt
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.eq
+     (f64.const 10)
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.ne
+     (f64.const 10)
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.lt
+     (f64.const 10)
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.le
+     (f64.const 10)
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.gt
+     (f64.const 10)
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f64.ge
+     (f64.const 10)
+     (f64.const 10)
+    )
+   )
+   (drop
+    (i32.trunc_f32_s
+     (f32.const 10)
+    )
+   )
+   (drop
+    (i32.trunc_f64_s
+     (f64.const 10)
+    )
+   )
+   (drop
+    (i32.trunc_f32_u
+     (f32.const 10)
+    )
+   )
+   (drop
+    (i32.trunc_f64_u
+     (f64.const 10)
+    )
+   )
+   (drop
+    (i32.trunc_sat_f32_s
+     (f32.const 10)
+    )
+   )
+   (drop
+    (i32.trunc_sat_f32_u
+     (f32.const 10)
+    )
+   )
+   (drop
+    (i32.trunc_sat_f64_s
+     (f64.const 10)
+    )
+   )
+   (drop
+    (i32.trunc_sat_f64_u
+     (f64.const 10)
+    )
+   )
+   (drop
+    (i32.wrap_i64
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i64.trunc_f32_s
+     (f32.const 10)
+    )
+   )
+   (drop
+    (i64.trunc_f64_s
+     (f64.const 10)
+    )
+   )
+   (drop
+    (i64.trunc_f32_u
+     (f32.const 10)
+    )
+   )
+   (drop
+    (i64.trunc_f64_u
+     (f64.const 10)
+    )
+   )
+   (drop
+    (i64.trunc_sat_f32_s
+     (f32.const 10)
+    )
+   )
+   (drop
+    (i64.trunc_sat_f32_u
+     (f32.const 10)
+    )
+   )
+   (drop
+    (i64.trunc_sat_f64_s
+     (f64.const 10)
+    )
+   )
+   (drop
+    (i64.trunc_sat_f64_u
+     (f64.const 10)
+    )
+   )
+   (drop
+    (i64.extend_i32_s
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i64.extend_i32_u
+     (i32.const 10)
+    )
+   )
+   (drop
+    (f32.convert_i32_s
+     (i32.const 10)
+    )
+   )
+   (drop
+    (f32.convert_i32_u
+     (i32.const 10)
+    )
+   )
+   (drop
+    (f32.convert_i64_s
+     (i64.const 100)
+    )
+   )
+   (drop
+    (f32.convert_i64_u
+     (i64.const 100)
+    )
+   )
+   (drop
+    (f32.demote_f64
+     (f64.const 10)
+    )
+   )
+   (drop
+    (f32.reinterpret_i32
+     (i32.const 10)
+    )
+   )
+   (drop
+    (f64.convert_i32_s
+     (i32.const 10)
+    )
+   )
+   (drop
+    (f64.convert_i32_u
+     (i32.const 10)
+    )
+   )
+   (drop
+    (f64.convert_i64_s
+     (i64.const 100)
+    )
+   )
+   (drop
+    (f64.convert_i64_u
+     (i64.const 100)
+    )
+   )
+   (drop
+    (f64.promote_f32
+     (f32.const 10)
+    )
+   )
+   (drop
+    (f64.reinterpret_i64
+     (i64.const 100)
+    )
+   )
+   (drop
+    (i32.reinterpret_f32
+     (f32.const 10)
+    )
+   )
+   (drop
+    (i64.reinterpret_f64
+     (f64.const 10)
+    )
+   )
+   (i32.const 0)
+  )
+ )
+)
diff --git a/binaryen/test/kitchen_sink.wast.fromBinary b/binaryen/test/kitchen_sink.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/kitchen_sink.wast.fromBinary
@@ -0,0 +1,706 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 4096 4096)
+ (data (i32.const 1026) "\14\00")
+ (func $kitchensink (result i32)
+  (drop
+   (i32.add
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.sub
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.mul
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.div_s
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.div_u
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.rem_s
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.rem_u
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.and
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.or
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.xor
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.shl
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.ne
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.lt_s
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.le_s
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.lt_u
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.le_u
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.gt_s
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.ge_s
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.gt_u
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.ge_u
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.clz
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.ctz
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.popcnt
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i64.add
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.sub
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.mul
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.div_s
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.div_u
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.rem_s
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.rem_u
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.and
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.or
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.xor
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.shl
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.shr_u
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.shr_s
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.eq
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.ne
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.lt_s
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.le_s
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.lt_u
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.le_u
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.gt_s
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.ge_s
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.gt_u
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.ge_u
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.clz
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.ctz
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.popcnt
+    (i64.const 100)
+   )
+  )
+  (drop
+   (f32.add
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.sub
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.mul
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.div
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.min
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.max
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.abs
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.neg
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.copysign
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.ceil
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.floor
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.trunc
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.nearest
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.sqrt
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.eq
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.ne
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.lt
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.le
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.gt
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.ge
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f64.add
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.sub
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.mul
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.div
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.min
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.max
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.abs
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.neg
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.copysign
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.ceil
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.floor
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.trunc
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.nearest
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.sqrt
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.eq
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.ne
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.lt
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.le
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.gt
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.ge
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_f32_s
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_f64_s
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_f32_u
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_f64_u
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_sat_f32_s
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_sat_f32_u
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_sat_f64_s
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_sat_f64_u
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i32.wrap_i64
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.trunc_f32_s
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i64.trunc_f64_s
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i64.trunc_f32_u
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i64.trunc_f64_u
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i64.trunc_sat_f32_s
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i64.trunc_sat_f32_u
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i64.trunc_sat_f64_s
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i64.trunc_sat_f64_u
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i64.extend_i32_s
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (i32.const 10)
+   )
+  )
+  (drop
+   (f32.convert_i32_s
+    (i32.const 10)
+   )
+  )
+  (drop
+   (f32.convert_i32_u
+    (i32.const 10)
+   )
+  )
+  (drop
+   (f32.convert_i64_s
+    (i64.const 100)
+   )
+  )
+  (drop
+   (f32.convert_i64_u
+    (i64.const 100)
+   )
+  )
+  (drop
+   (f32.demote_f64
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f32.reinterpret_i32
+    (i32.const 10)
+   )
+  )
+  (drop
+   (f64.convert_i32_s
+    (i32.const 10)
+   )
+  )
+  (drop
+   (f64.convert_i32_u
+    (i32.const 10)
+   )
+  )
+  (drop
+   (f64.convert_i64_s
+    (i64.const 100)
+   )
+  )
+  (drop
+   (f64.convert_i64_u
+    (i64.const 100)
+   )
+  )
+  (drop
+   (f64.promote_f32
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f64.reinterpret_i64
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i32.reinterpret_f32
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i64.reinterpret_f64
+    (f64.const 10)
+   )
+  )
+  (i32.const 0)
+ )
+)
+
diff --git a/binaryen/test/kitchen_sink.wast.fromBinary.noDebugInfo b/binaryen/test/kitchen_sink.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/kitchen_sink.wast.fromBinary.noDebugInfo
@@ -0,0 +1,706 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 4096 4096)
+ (data (i32.const 1026) "\14\00")
+ (func $0 (result i32)
+  (drop
+   (i32.add
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.sub
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.mul
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.div_s
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.div_u
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.rem_s
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.rem_u
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.and
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.or
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.xor
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.shl
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.ne
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.lt_s
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.le_s
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.lt_u
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.le_u
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.gt_s
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.ge_s
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.gt_u
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.ge_u
+    (i32.const 10)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.clz
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.ctz
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.popcnt
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i64.add
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.sub
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.mul
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.div_s
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.div_u
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.rem_s
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.rem_u
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.and
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.or
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.xor
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.shl
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.shr_u
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.shr_s
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.eq
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.ne
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.lt_s
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.le_s
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.lt_u
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.le_u
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.gt_s
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.ge_s
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.gt_u
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.ge_u
+    (i64.const 100)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.clz
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.ctz
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.popcnt
+    (i64.const 100)
+   )
+  )
+  (drop
+   (f32.add
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.sub
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.mul
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.div
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.min
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.max
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.abs
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.neg
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.copysign
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.ceil
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.floor
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.trunc
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.nearest
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.sqrt
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.eq
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.ne
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.lt
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.le
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.gt
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f32.ge
+    (f32.const 10)
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f64.add
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.sub
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.mul
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.div
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.min
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.max
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.abs
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.neg
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.copysign
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.ceil
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.floor
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.trunc
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.nearest
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.sqrt
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.eq
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.ne
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.lt
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.le
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.gt
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f64.ge
+    (f64.const 10)
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_f32_s
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_f64_s
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_f32_u
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_f64_u
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_sat_f32_s
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_sat_f32_u
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_sat_f64_s
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i32.trunc_sat_f64_u
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i32.wrap_i64
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.trunc_f32_s
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i64.trunc_f64_s
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i64.trunc_f32_u
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i64.trunc_f64_u
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i64.trunc_sat_f32_s
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i64.trunc_sat_f32_u
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i64.trunc_sat_f64_s
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i64.trunc_sat_f64_u
+    (f64.const 10)
+   )
+  )
+  (drop
+   (i64.extend_i32_s
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (i32.const 10)
+   )
+  )
+  (drop
+   (f32.convert_i32_s
+    (i32.const 10)
+   )
+  )
+  (drop
+   (f32.convert_i32_u
+    (i32.const 10)
+   )
+  )
+  (drop
+   (f32.convert_i64_s
+    (i64.const 100)
+   )
+  )
+  (drop
+   (f32.convert_i64_u
+    (i64.const 100)
+   )
+  )
+  (drop
+   (f32.demote_f64
+    (f64.const 10)
+   )
+  )
+  (drop
+   (f32.reinterpret_i32
+    (i32.const 10)
+   )
+  )
+  (drop
+   (f64.convert_i32_s
+    (i32.const 10)
+   )
+  )
+  (drop
+   (f64.convert_i32_u
+    (i32.const 10)
+   )
+  )
+  (drop
+   (f64.convert_i64_s
+    (i64.const 100)
+   )
+  )
+  (drop
+   (f64.convert_i64_u
+    (i64.const 100)
+   )
+  )
+  (drop
+   (f64.promote_f32
+    (f32.const 10)
+   )
+  )
+  (drop
+   (f64.reinterpret_i64
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i32.reinterpret_f32
+    (f32.const 10)
+   )
+  )
+  (drop
+   (i64.reinterpret_f64
+    (f64.const 10)
+   )
+  )
+  (i32.const 0)
+ )
+)
+
diff --git a/binaryen/test/linker/archive/barlong.a b/binaryen/test/linker/archive/barlong.a
new file mode 100644
--- /dev/null
+++ b/binaryen/test/linker/archive/barlong.a
@@ -0,0 +1,21 @@
+!<arch>
+//                                              32        `
+bar_with_very_long_filename.s/
+
+/0              0           0     0     644     363       `
+	.text
+	.file	"src/work/binaryen/test/linker/archive/bar.c"
+	.section	.text.bar,"ax",@progbits
+	.hidden	bar
+	.globl	bar
+	.type	bar,@function
+bar:                                    # @bar
+# BB#0:                                 # %entry
+	return
+	.endfunc
+.Lfunc_end0:
+	.size	bar, .Lfunc_end0-bar
+
+
+	.ident	"clang version 3.9.0 (trunk 267883) (llvm/trunk 267901)"
+
diff --git a/binaryen/test/linker/archive/foobar.a b/binaryen/test/linker/archive/foobar.a
new file mode 100644
--- /dev/null
+++ b/binaryen/test/linker/archive/foobar.a
@@ -0,0 +1,73 @@
+!<arch>
+quux.s/         0           0     0     644     345       `
+	.text
+	.file	"test/linker/quux.c"
+	.section	.text.quux,"ax",@progbits
+	.hidden	quux
+	.globl	quux
+	.type	quux,@function
+quux:                                   # @quux
+# BB#0:                                 # %entry
+	return
+	.endfunc
+.Lfunc_end0:
+	.size	quux, .Lfunc_end0-quux
+
+
+	.ident	"clang version 3.9.0 (trunk 268553) (llvm/trunk 268561)"
+
+foo.s/          0           0     0     644     407       `
+	.text
+	.file	"src/work/binaryen/test/linker/foo.c"
+	.section	.text.foo,"ax",@progbits
+	.hidden	foo
+	.globl	foo
+	.type	foo,@function
+foo:                                    # @foo
+	.result 	i32
+	.local  	i32
+# BB#0:                                 # %entry
+	i32.const	$0=, 43
+	return  	$0
+	.endfunc
+.Lfunc_end0:
+	.size	foo, .Lfunc_end0-foo
+
+
+	.ident	"clang version 3.9.0 (trunk 267883) (llvm/trunk 267901)"
+
+bar.s/          0           0     0     644     361       `
+	.text
+	.file	"test/linker/bar.c"
+	.section	.text.bar,"ax",@progbits
+	.hidden	bar
+	.globl	bar
+	.type	bar,@function
+bar:                                    # @bar
+# BB#0:                                 # %entry
+	call    	quux@FUNCTION
+	return
+	.endfunc
+.Lfunc_end0:
+	.size	bar, .Lfunc_end0-bar
+
+
+	.ident	"clang version 3.9.0 (trunk 268553) (llvm/trunk 268561)"
+
+baz.s/          0           0     0     644     355       `
+	.text
+	.file	"src/work/binaryen/test/linker/baz.c"
+	.section	.text.baz,"ax",@progbits
+	.hidden	baz
+	.globl	baz
+	.type	baz,@function
+baz:                                    # @baz
+# BB#0:                                 # %entry
+	return
+	.endfunc
+.Lfunc_end0:
+	.size	baz, .Lfunc_end0-baz
+
+
+	.ident	"clang version 3.9.0 (trunk 267883) (llvm/trunk 267901)"
+
diff --git a/binaryen/test/linker/bar.c b/binaryen/test/linker/bar.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/linker/bar.c
@@ -0,0 +1,2 @@
+void quux();
+void bar() { quux(); }
diff --git a/binaryen/test/linker/baz.c b/binaryen/test/linker/baz.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/linker/baz.c
@@ -0,0 +1,2 @@
+void baz() {
+}
diff --git a/binaryen/test/linker/foo.c b/binaryen/test/linker/foo.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/linker/foo.c
@@ -0,0 +1,3 @@
+int foo() {
+  return 43;
+}
diff --git a/binaryen/test/linker/main.c b/binaryen/test/linker/main.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/linker/main.c
@@ -0,0 +1,10 @@
+int foo() {
+  return 42;
+}
+
+void bar();
+
+int main() {
+  foo();
+  bar();
+}
diff --git a/binaryen/test/linker/quux.c b/binaryen/test/linker/quux.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/linker/quux.c
@@ -0,0 +1,1 @@
+void quux() {}
diff --git a/binaryen/test/lld/basic_safe_stack.s b/binaryen/test/lld/basic_safe_stack.s
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/basic_safe_stack.s
@@ -0,0 +1,38 @@
+# Test that wasm-binaryen-finalize --check-stack-overflow correctly
+# inserts stack chekc handlers.
+
+.globl stackRestore
+.globl stackAlloc
+
+.globaltype __stack_pointer, i32
+
+stackRestore:
+  .functype stackRestore(i32) -> ()
+  local.get 0
+  global.set __stack_pointer
+  end_function
+
+stackAlloc:
+  .functype stackAlloc(i32) -> (i32)
+  .local i32, i32
+  global.get __stack_pointer
+  # Get arg 0 -> number of bytes to allocate
+  local.get 0
+  # Stack grows down.  Subtract arg0 from __stack_pointer
+  i32.sub
+  # Align result by anding with ~15
+  i32.const 0xfffffff0
+  i32.and
+  local.tee 1
+  global.set __stack_pointer
+  local.get 1
+  end_function
+
+.globl main
+main:
+  .functype main () -> ()
+  end_function
+
+.export_name stackAlloc, stackAlloc
+.export_name stackSave, stackSave
+.export_name stackRestore, stackRestore
diff --git a/binaryen/test/lld/basic_safe_stack.wat b/binaryen/test/lld/basic_safe_stack.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/basic_safe_stack.wat
@@ -0,0 +1,41 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (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)
+  (global.set $global$0
+   (local.get $0)
+  )
+ )
+ (func $stackAlloc (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (global.set $global$0
+   (local.tee $1
+    (i32.and
+     (i32.sub
+      (global.get $global$0)
+      (local.get $0)
+     )
+     (i32.const -16)
+    )
+   )
+  )
+  (local.get $1)
+ )
+ (func $main
+ )
+)
+
diff --git a/binaryen/test/lld/basic_safe_stack.wat.out b/binaryen/test/lld/basic_safe_stack.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/basic_safe_stack.wat.out
@@ -0,0 +1,120 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "__handle_stack_overflow" (func $__handle_stack_overflow))
+ (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))
+ (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))
+ (export "__set_stack_limits" (func $__set_stack_limits))
+ (func $__wasm_call_ctors
+  (nop)
+ )
+ (func $stackRestore (param $0 i32)
+  (local $1 i32)
+  (if
+   (i32.or
+    (i32.gt_u
+     (local.tee $1
+      (local.get $0)
+     )
+     (global.get $__stack_base)
+    )
+    (i32.lt_u
+     (local.get $1)
+     (global.get $__stack_limit)
+    )
+   )
+   (call $__handle_stack_overflow)
+  )
+  (global.set $global$0
+   (local.get $1)
+  )
+ )
+ (func $stackAlloc (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (block
+   (if
+    (i32.or
+     (i32.gt_u
+      (local.tee $3
+       (local.tee $1
+        (i32.and
+         (i32.sub
+          (global.get $global$0)
+          (local.get $0)
+         )
+         (i32.const -16)
+        )
+       )
+      )
+      (global.get $__stack_base)
+     )
+     (i32.lt_u
+      (local.get $3)
+      (global.get $__stack_limit)
+     )
+    )
+    (call $__handle_stack_overflow)
+   )
+   (global.set $global$0
+    (local.get $3)
+   )
+  )
+  (local.get $1)
+ )
+ (func $main
+  (nop)
+ )
+ (func $__set_stack_limits (param $0 i32) (param $1 i32)
+  (global.set $__stack_base
+   (local.get $0)
+  )
+  (global.set $__stack_limit
+   (local.get $1)
+  )
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 0,
+  "tableSize": 1,
+  "initializers": [
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+    "__handle_stack_overflow"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "stackRestore",
+    "stackAlloc",
+    "main",
+    "__set_stack_limits"
+  ],
+  "namedGlobals": {
+    "__data_end" : "568"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 1,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/bigint.wat b/binaryen/test/lld/bigint.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/bigint.wat
@@ -0,0 +1,10 @@
+(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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/bigint.wat.out
@@ -0,0 +1,42 @@
+(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 b/binaryen/test/lld/duplicate_imports.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/duplicate_imports.wat
@@ -0,0 +1,32 @@
+(module
+ (type $0 (func (param i32) (result i32)))
+ (type $1 (func (result i32)))
+ (type $2 (func))
+ (import "env" "puts" (func $puts1 (param i32) (result i32)))
+ (import "env" "puts" (func $puts2 (param i64) (result i32)))
+ (import "env" "invoke_ffd" (func $invoke_ffd (param i32 f32 f64) (result f32)))
+ (import "env" "invoke_ffd" (func $invoke_ffd2 (param i32 f64 f64) (result f32)))
+ (global $global$0 (mut i32) (i32.const 66128))
+ (global $global$1 i32 (i32.const 66128))
+ (global $global$2 i32 (i32.const 581))
+ (table 1 1 funcref)
+ (memory $0 2)
+ (data (i32.const 568) "Hello, world\00")
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (func $main (; 1 ;) (type $1) (result i32)
+  (drop
+   (call $puts1
+    (i32.const 568)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $__wasm_call_ctors (; 2 ;) (type $2)
+ )
+ ;; custom section "linking", size 3
+)
+
diff --git a/binaryen/test/lld/duplicate_imports.wat.out b/binaryen/test/lld/duplicate_imports.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/duplicate_imports.wat.out
@@ -0,0 +1,98 @@
+(module
+ (type $i32_f32_f64_=>_f32 (func (param i32 f32 f64) (result f32)))
+ (type $i32_f64_f64_=>_f32 (func (param i32 f64 f64) (result f32)))
+ (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 $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)))
+ (import "env" "invoke_ffd" (func $invoke_ffd (param i32 f32 f64) (result f32)))
+ (import "env" "invoke_ffd" (func $invoke_ffd2 (param i32 f64 f64) (result f32)))
+ (import "env" "puts" (func $legalimport$puts2 (param i32 i32) (result i32)))
+ (memory $0 2)
+ (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 66128))
+ (global $global$2 i32 (i32.const 581))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (export "dynCall_ffd" (func $dynCall_ffd))
+ (export "dynCall_fdd" (func $dynCall_fdd))
+ (func $main (result i32)
+  (drop
+   (call $puts1
+    (i32.const 568)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $__wasm_call_ctors
+  (nop)
+ )
+ (func $dynCall_ffd (param $fptr i32) (param $0 f32) (param $1 f64) (result f32)
+  (call_indirect (type $f32_f64_=>_f32)
+   (local.get $0)
+   (local.get $1)
+   (local.get $fptr)
+  )
+ )
+ (func $dynCall_fdd (param $fptr i32) (param $0 f64) (param $1 f64) (result f32)
+  (call_indirect (type $f64_f64_=>_f32)
+   (local.get $0)
+   (local.get $1)
+   (local.get $fptr)
+  )
+ )
+ (func $legalfunc$puts2 (param $0 i64) (result i32)
+  (call $legalimport$puts2
+   (i32.wrap_i64
+    (local.get $0)
+   )
+   (i32.wrap_i64
+    (i64.shr_u
+     (local.get $0)
+     (i64.const 32)
+    )
+   )
+  )
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 13,
+  "tableSize": 1,
+  "initializers": [
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+    "puts"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "main",
+    "dynCall_ffd",
+    "dynCall_fdd"
+  ],
+  "namedGlobals": {
+    "__heap_base" : "66128",
+    "__data_end" : "581"
+  },
+  "invokeFuncs": [
+    "invoke_ffd"
+  ],
+  "mainReadsParams": 1,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/em_asm.cpp b/binaryen/test/lld/em_asm.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm.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_asm.wat b/binaryen/test/lld/em_asm.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm.wat
@@ -0,0 +1,70 @@
+(module
+ (type $none_=>_none (func))
+ (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" "emscripten_asm_const_int" (func $emscripten_asm_const_int (param i32 i32 i32) (result i32)))
+ (memory $0 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 $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)
+  (local $0 i32)
+  (global.set $global$0
+   (local.tee $0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 32)
+    )
+   )
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i32.const 568)
+    (i32.const 601)
+    (i32.const 0)
+   )
+  )
+  (i64.store offset=16
+   (local.get $0)
+   (i64.const 115964117005)
+  )
+  (i32.store
+   (local.get $0)
+   (call $emscripten_asm_const_int
+    (i32.const 602)
+    (i32.const 622)
+    (i32.add
+     (local.get $0)
+     (i32.const 16)
+    )
+   )
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i32.const 625)
+    (i32.const 656)
+    (local.get $0)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $0)
+    (i32.const 32)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+ ;; custom section "producers", size 112
+)
+
diff --git a/binaryen/test/lld/em_asm.wat.mem.mem b/binaryen/test/lld/em_asm.wat.mem.mem
new file mode 100644
Binary files /dev/null and b/binaryen/test/lld/em_asm.wat.mem.mem differ
diff --git a/binaryen/test/lld/em_asm.wat.mem.out b/binaryen/test/lld/em_asm.wat.mem.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm.wat.mem.out
@@ -0,0 +1,101 @@
+(module
+ (type $none_=>_none (func))
+ (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" "emscripten_asm_const_int" (func $emscripten_asm_const_int (param i32 i32 i32) (result i32)))
+ (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)
+ )
+ (func $__original_main (result i32)
+  (local $0 i32)
+  (global.set $global$0
+   (local.tee $0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 32)
+    )
+   )
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i32.const 568)
+    (i32.const 601)
+    (i32.const 0)
+   )
+  )
+  (i64.store offset=16
+   (local.get $0)
+   (i64.const 115964117005)
+  )
+  (i32.store
+   (local.get $0)
+   (call $emscripten_asm_const_int
+    (i32.const 602)
+    (i32.const 622)
+    (i32.add
+     (local.get $0)
+     (i32.const 16)
+    )
+   )
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i32.const 625)
+    (i32.const 656)
+    (local.get $0)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $0)
+    (i32.const 32)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "asmConsts": {
+    "568": ["{ Module.print(\"Hello world\"); }", ["iii"], [""]],
+    "602": ["{ return $0 + $1; }", ["iii"], [""]],
+    "625": ["{ Module.print(\"Got \" + $0); }", ["iii"], [""]]
+  },
+  "staticBump": 90,
+  "tableSize": 1,
+  "initializers": [
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+    "emscripten_asm_const_int"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "main"
+  ],
+  "namedGlobals": {
+    "__data_end" : "658"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/em_asm.wat.out b/binaryen/test/lld/em_asm.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm.wat.out
@@ -0,0 +1,102 @@
+(module
+ (type $none_=>_none (func))
+ (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" "emscripten_asm_const_int" (func $emscripten_asm_const_int (param i32 i32 i32) (result i32)))
+ (memory $0 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 $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)
+ )
+ (func $__original_main (result i32)
+  (local $0 i32)
+  (global.set $global$0
+   (local.tee $0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 32)
+    )
+   )
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i32.const 568)
+    (i32.const 601)
+    (i32.const 0)
+   )
+  )
+  (i64.store offset=16
+   (local.get $0)
+   (i64.const 115964117005)
+  )
+  (i32.store
+   (local.get $0)
+   (call $emscripten_asm_const_int
+    (i32.const 602)
+    (i32.const 622)
+    (i32.add
+     (local.get $0)
+     (i32.const 16)
+    )
+   )
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i32.const 625)
+    (i32.const 656)
+    (local.get $0)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $0)
+    (i32.const 32)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "asmConsts": {
+    "568": ["{ Module.print(\"Hello world\"); }", ["iii"], [""]],
+    "602": ["{ return $0 + $1; }", ["iii"], [""]],
+    "625": ["{ Module.print(\"Got \" + $0); }", ["iii"], [""]]
+  },
+  "staticBump": 90,
+  "tableSize": 1,
+  "initializers": [
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+    "emscripten_asm_const_int"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "main"
+  ],
+  "namedGlobals": {
+    "__data_end" : "658"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/em_asm_O0.c b/binaryen/test/lld/em_asm_O0.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm_O0.c
@@ -0,0 +1,8 @@
+#include <emscripten.h>
+
+int main(int argc, char **argv) {
+  EM_ASM({ Module.print("Hello world"); });
+  int ret = EM_ASM_INT({ return $0 + $1; }, 20, 30);
+  EM_ASM({ Module.print("Got " + $0); }, 42);
+  return ret;
+}
diff --git a/binaryen/test/lld/em_asm_O0.wat b/binaryen/test/lld/em_asm_O0.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm_O0.wat
@@ -0,0 +1,95 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (import "env" "emscripten_asm_const_int" (func $emscripten_asm_const_int (param i32 i32 i32) (result i32)))
+ (memory $0 2)
+ (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)
+  (local $2 i32)
+  (local $3 i32)
+  (global.set $global$0
+   (local.tee $2
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 32)
+    )
+   )
+  )
+  (i32.store8 offset=31
+   (local.get $2)
+   (i32.const 0)
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i32.const 568)
+    (i32.add
+     (local.get $2)
+     (i32.const 31)
+    )
+    (i32.const 0)
+   )
+  )
+  (i32.store8 offset=30
+   (local.get $2)
+   (i32.const 0)
+  )
+  (i32.store16 offset=28 align=1
+   (local.get $2)
+   (i32.const 26985)
+  )
+  (i64.store offset=16
+   (local.get $2)
+   (i64.const 128849018900)
+  )
+  (local.set $3
+   (call $emscripten_asm_const_int
+    (i32.const 601)
+    (i32.add
+     (local.get $2)
+     (i32.const 28)
+    )
+    (i32.add
+     (local.get $2)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store16 offset=26 align=1
+   (local.get $2)
+   (i32.const 105)
+  )
+  (i32.store
+   (local.get $2)
+   (i32.const 42)
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i32.const 621)
+    (i32.add
+     (local.get $2)
+     (i32.const 26)
+    )
+    (local.get $2)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $2)
+    (i32.const 32)
+   )
+  )
+  (local.get $3)
+ )
+ ;; custom section "producers", size 112
+)
+
diff --git a/binaryen/test/lld/em_asm_O0.wat.out b/binaryen/test/lld/em_asm_O0.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm_O0.wat.out
@@ -0,0 +1,127 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (import "env" "emscripten_asm_const_int" (func $emscripten_asm_const_int (param i32 i32 i32) (result i32)))
+ (memory $0 2)
+ (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)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (global.set $global$0
+   (local.tee $2
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 32)
+    )
+   )
+  )
+  (i32.store8 offset=31
+   (local.get $2)
+   (i32.const 0)
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i32.const 568)
+    (i32.add
+     (local.get $2)
+     (i32.const 31)
+    )
+    (i32.const 0)
+   )
+  )
+  (i32.store8 offset=30
+   (local.get $2)
+   (i32.const 0)
+  )
+  (i32.store16 offset=28 align=1
+   (local.get $2)
+   (i32.const 26985)
+  )
+  (i64.store offset=16
+   (local.get $2)
+   (i64.const 128849018900)
+  )
+  (local.set $3
+   (call $emscripten_asm_const_int
+    (i32.const 601)
+    (i32.add
+     (local.get $2)
+     (i32.const 28)
+    )
+    (i32.add
+     (local.get $2)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store16 offset=26 align=1
+   (local.get $2)
+   (i32.const 105)
+  )
+  (i32.store
+   (local.get $2)
+   (i32.const 42)
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i32.const 621)
+    (i32.add
+     (local.get $2)
+     (i32.const 26)
+    )
+    (local.get $2)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $2)
+    (i32.const 32)
+   )
+  )
+  (local.get $3)
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "asmConsts": {
+    "568": ["{ Module.print(\"Hello world\"); }", ["iii"], [""]],
+    "601": ["{ return $0 + $1; }", ["iii"], [""]],
+    "621": ["{ Module.print(\"Got \" + $0); }", ["iii"], [""]]
+  },
+  "staticBump": 84,
+  "tableSize": 1,
+  "initializers": [
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+    "emscripten_asm_const_int"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "main"
+  ],
+  "namedGlobals": {
+    "__data_end" : "652"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 1,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/em_asm_main_thread.wat b/binaryen/test/lld/em_asm_main_thread.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm_main_thread.wat
@@ -0,0 +1,196 @@
+(; Copied from em_asm.wat
+  s/emscripten_asm_const_int/emscripten_asm_const_int_sync_on_main_thread/g
+;)
+(module
+ (type $0 (func (param i32 i32 i32) (result i32)))
+ (type $1 (func))
+ (type $2 (func (result i32)))
+ (type $3 (func (param i32 i32 i32)))
+ (type $4 (func (param i32 i32)))
+ (type $5 (func (param i32) (result i32)))
+ (type $6 (func (param i32 i32) (result i32)))
+ (import "env" "emscripten_asm_const_int_sync_on_main_thread" (func $emscripten_asm_const_int_sync_on_main_thread (param i32 i32 i32) (result i32)))
+ (memory $0 2)
+ (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 66192))
+ (global $global$2 i32 (i32.const 652))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (export "main" (func $main))
+ (func $__wasm_call_ctors (; 1 ;) (type $1)
+ )
+ (func $__original_main (; 2 ;) (type $2) (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (global.set $global$0
+   (local.tee $0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 32)
+    )
+   )
+  )
+  (i32.store8 offset=24
+   (local.get $0)
+   (call $__em_asm_sig_builder::inner<>\20const\20__em_asm_sig_builder::__em_asm_sig<>\28\29)
+  )
+  (drop
+   (call $emscripten_asm_const_int_sync_on_main_thread
+    (i32.const 568)
+    (i32.add
+     (local.get $0)
+     (i32.const 24)
+    )
+    (i32.const 0)
+   )
+  )
+  (call $__em_asm_sig_builder::inner<int\2c\20int>\20const\20__em_asm_sig_builder::__em_asm_sig<int\2c\20int>\28int\2c\20int\29
+   (i32.add
+    (local.get $0)
+    (i32.const 24)
+   )
+   (i32.const 13)
+   (i32.const 27)
+  )
+  (i64.store offset=16
+   (local.get $0)
+   (i64.const 115964117005)
+  )
+  (call $__em_asm_sig_builder::inner<int>\20const\20__em_asm_sig_builder::__em_asm_sig<int>\28int\29
+   (i32.add
+    (local.get $0)
+    (i32.const 24)
+   )
+   (local.tee $1
+    (call $emscripten_asm_const_int_sync_on_main_thread
+     (i32.const 601)
+     (i32.add
+      (local.get $0)
+      (i32.const 24)
+     )
+     (i32.add
+      (local.get $0)
+      (i32.const 16)
+     )
+    )
+   )
+  )
+  (i32.store
+   (local.get $0)
+   (local.get $1)
+  )
+  (drop
+   (call $emscripten_asm_const_int_sync_on_main_thread
+    (i32.const 621)
+    (i32.add
+     (local.get $0)
+     (i32.const 24)
+    )
+    (local.get $0)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $0)
+    (i32.const 32)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $__em_asm_sig_builder::inner<>\20const\20__em_asm_sig_builder::__em_asm_sig<>\28\29 (; 3 ;) (type $2) (result i32)
+  (i32.const 0)
+ )
+ (func $__em_asm_sig_builder::inner<int\2c\20int>\20const\20__em_asm_sig_builder::__em_asm_sig<int\2c\20int>\28int\2c\20int\29 (; 4 ;) (type $3) (param $0 i32) (param $1 i32) (param $2 i32)
+  (local $3 i32)
+  (global.set $global$0
+   (local.tee $3
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store8 offset=13
+   (local.get $3)
+   (call $__em_asm_sig_builder::sig_char\28int\29
+    (local.get $1)
+   )
+  )
+  (local.set $2
+   (call $__em_asm_sig_builder::sig_char\28int\29
+    (local.get $2)
+   )
+  )
+  (i32.store8
+   (i32.add
+    (local.get $0)
+    (i32.const 2)
+   )
+   (i32.const 0)
+  )
+  (i32.store8 offset=14
+   (local.get $3)
+   (local.get $2)
+  )
+  (i32.store16 align=1
+   (local.get $0)
+   (i32.load16_u offset=13 align=1
+    (local.get $3)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $3)
+    (i32.const 16)
+   )
+  )
+ )
+ (func $__em_asm_sig_builder::inner<int>\20const\20__em_asm_sig_builder::__em_asm_sig<int>\28int\29 (; 5 ;) (type $4) (param $0 i32) (param $1 i32)
+  (local $2 i32)
+  (global.set $global$0
+   (local.tee $2
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 16)
+    )
+   )
+  )
+  (local.set $1
+   (call $__em_asm_sig_builder::sig_char\28int\29
+    (local.get $1)
+   )
+  )
+  (i32.store8 offset=15
+   (local.get $2)
+   (i32.const 0)
+  )
+  (i32.store8 offset=14
+   (local.get $2)
+   (local.get $1)
+  )
+  (i32.store16 align=1
+   (local.get $0)
+   (i32.load16_u offset=14
+    (local.get $2)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $2)
+    (i32.const 16)
+   )
+  )
+ )
+ (func $__em_asm_sig_builder::sig_char\28int\29 (; 6 ;) (type $5) (param $0 i32) (result i32)
+  (i32.const 105)
+ )
+ (func $main (; 7 ;) (type $6) (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+ ;; custom section "producers", size 111
+)
+
diff --git a/binaryen/test/lld/em_asm_main_thread.wat.out b/binaryen/test/lld/em_asm_main_thread.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm_main_thread.wat.out
@@ -0,0 +1,226 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (type $i32_=>_i32 (func (param i32) (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" "emscripten_asm_const_int_sync_on_main_thread" (func $emscripten_asm_const_int_sync_on_main_thread (param i32 i32 i32) (result i32)))
+ (memory $0 2)
+ (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 66192))
+ (global $global$2 i32 (i32.const 652))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (export "main" (func $main))
+ (func $__wasm_call_ctors
+  (nop)
+ )
+ (func $__original_main (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (global.set $global$0
+   (local.tee $0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 32)
+    )
+   )
+  )
+  (i32.store8 offset=24
+   (local.get $0)
+   (call $__em_asm_sig_builder::inner<>\20const\20__em_asm_sig_builder::__em_asm_sig<>\28\29)
+  )
+  (drop
+   (call $emscripten_asm_const_int_sync_on_main_thread
+    (i32.const 568)
+    (i32.add
+     (local.get $0)
+     (i32.const 24)
+    )
+    (i32.const 0)
+   )
+  )
+  (call $__em_asm_sig_builder::inner<int\2c\20int>\20const\20__em_asm_sig_builder::__em_asm_sig<int\2c\20int>\28int\2c\20int\29
+   (i32.add
+    (local.get $0)
+    (i32.const 24)
+   )
+   (i32.const 13)
+   (i32.const 27)
+  )
+  (i64.store offset=16
+   (local.get $0)
+   (i64.const 115964117005)
+  )
+  (call $__em_asm_sig_builder::inner<int>\20const\20__em_asm_sig_builder::__em_asm_sig<int>\28int\29
+   (i32.add
+    (local.get $0)
+    (i32.const 24)
+   )
+   (local.tee $1
+    (call $emscripten_asm_const_int_sync_on_main_thread
+     (i32.const 601)
+     (i32.add
+      (local.get $0)
+      (i32.const 24)
+     )
+     (i32.add
+      (local.get $0)
+      (i32.const 16)
+     )
+    )
+   )
+  )
+  (i32.store
+   (local.get $0)
+   (local.get $1)
+  )
+  (drop
+   (call $emscripten_asm_const_int_sync_on_main_thread
+    (i32.const 621)
+    (i32.add
+     (local.get $0)
+     (i32.const 24)
+    )
+    (local.get $0)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $0)
+    (i32.const 32)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $__em_asm_sig_builder::inner<>\20const\20__em_asm_sig_builder::__em_asm_sig<>\28\29 (result i32)
+  (i32.const 0)
+ )
+ (func $__em_asm_sig_builder::inner<int\2c\20int>\20const\20__em_asm_sig_builder::__em_asm_sig<int\2c\20int>\28int\2c\20int\29 (param $0 i32) (param $1 i32) (param $2 i32)
+  (local $3 i32)
+  (global.set $global$0
+   (local.tee $3
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store8 offset=13
+   (local.get $3)
+   (call $__em_asm_sig_builder::sig_char\28int\29
+    (local.get $1)
+   )
+  )
+  (local.set $2
+   (call $__em_asm_sig_builder::sig_char\28int\29
+    (local.get $2)
+   )
+  )
+  (i32.store8
+   (i32.add
+    (local.get $0)
+    (i32.const 2)
+   )
+   (i32.const 0)
+  )
+  (i32.store8 offset=14
+   (local.get $3)
+   (local.get $2)
+  )
+  (i32.store16 align=1
+   (local.get $0)
+   (i32.load16_u offset=13 align=1
+    (local.get $3)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $3)
+    (i32.const 16)
+   )
+  )
+ )
+ (func $__em_asm_sig_builder::inner<int>\20const\20__em_asm_sig_builder::__em_asm_sig<int>\28int\29 (param $0 i32) (param $1 i32)
+  (local $2 i32)
+  (global.set $global$0
+   (local.tee $2
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 16)
+    )
+   )
+  )
+  (local.set $1
+   (call $__em_asm_sig_builder::sig_char\28int\29
+    (local.get $1)
+   )
+  )
+  (i32.store8 offset=15
+   (local.get $2)
+   (i32.const 0)
+  )
+  (i32.store8 offset=14
+   (local.get $2)
+   (local.get $1)
+  )
+  (i32.store16 align=1
+   (local.get $0)
+   (i32.load16_u offset=14
+    (local.get $2)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $2)
+    (i32.const 16)
+   )
+  )
+ )
+ (func $__em_asm_sig_builder::sig_char\28int\29 (param $0 i32) (result i32)
+  (i32.const 105)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "asmConsts": {
+    "568": ["{ Module.print(\"Hello world\"); }", ["iii"], ["sync_on_main_thread_"]],
+    "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"
+  ],
+  "declares": [
+    "emscripten_asm_const_int_sync_on_main_thread"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "main"
+  ],
+  "namedGlobals": {
+    "__heap_base" : "66192",
+    "__data_end" : "652"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/em_asm_shared.cpp b/binaryen/test/lld/em_asm_shared.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm_shared.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_asm_shared.wat b/binaryen/test/lld/em_asm_shared.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm_shared.wat
@@ -0,0 +1,99 @@
+(module
+ (type $none_=>_none (func))
+ (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" "__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)))
+ (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))
+ (global $global$2 i32 (i32.const 88))
+ (export "__wasm_call_ctors" (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))
+ (func $__wasm_call_ctors
+  (call $__wasm_apply_relocs)
+ )
+ (func $__wasm_apply_relocs
+ )
+ (func $__original_main (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (global.set $gimport$2
+   (local.tee $0
+    (i32.sub
+     (global.get $gimport$2)
+     (i32.const 32)
+    )
+   )
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i32.add
+     (local.tee $1
+      (global.get $gimport$3)
+     )
+     (i32.const 0)
+    )
+    (global.get $gimport$6)
+    (i32.const 0)
+   )
+  )
+  (i64.store offset=16
+   (local.get $0)
+   (i64.const 115964117005)
+  )
+  (i32.store
+   (local.get $0)
+   (call $emscripten_asm_const_int
+    (i32.add
+     (local.get $1)
+     (i32.const 34)
+    )
+    (global.get $gimport$7)
+    (i32.add
+     (local.get $0)
+     (i32.const 16)
+    )
+   )
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i32.add
+     (local.get $1)
+     (i32.const 57)
+    )
+    (global.get $gimport$8)
+    (local.get $0)
+   )
+  )
+  (global.set $gimport$2
+   (i32.add
+    (local.get $0)
+    (i32.const 32)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+ ;; dylink section
+ ;;   memorysize: 90
+ ;;   memoryalignment: 0
+ ;;   tablesize: 0
+ ;;   tablealignment: 0
+ ;; custom section "producers", size 112
+)
+
diff --git a/binaryen/test/lld/em_asm_shared.wat.out b/binaryen/test/lld/em_asm_shared.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm_shared.wat.out
@@ -0,0 +1,153 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param 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))
+ (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 "__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)
+ )
+ (func $__wasm_apply_relocs
+  (nop)
+ )
+ (func $__original_main (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (call $stackRestore
+   (local.tee $0
+    (i32.sub
+     (call $stackSave)
+     (i32.const 32)
+    )
+   )
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i32.add
+     (local.tee $1
+      (global.get $gimport$3)
+     )
+     (i32.const 0)
+    )
+    (global.get $gimport$6)
+    (i32.const 0)
+   )
+  )
+  (i64.store offset=16
+   (local.get $0)
+   (i64.const 115964117005)
+  )
+  (i32.store
+   (local.get $0)
+   (call $emscripten_asm_const_int
+    (i32.add
+     (local.get $1)
+     (i32.const 34)
+    )
+    (global.get $gimport$7)
+    (i32.add
+     (local.get $0)
+     (i32.const 16)
+    )
+   )
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i32.add
+     (local.get $1)
+     (i32.const 57)
+    )
+    (global.get $gimport$8)
+    (local.get $0)
+   )
+  )
+  (call $stackRestore
+   (i32.add
+    (local.get $0)
+    (i32.const 32)
+   )
+  )
+  (i32.const 0)
+ )
+ (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 --
+{
+  "asmConsts": {
+    "0": ["{ Module.print(\"Hello world\"); }", ["iii"], [""]],
+    "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"
+  ],
+  "externs": [
+    "___memory_base",
+    "___table_base"
+  ],
+  "exports": [
+    "__original_main",
+    "main",
+    "__post_instantiate"
+  ],
+  "namedGlobals": {
+    "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJEEE6bufferE" : "33",
+    "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiiEEE6bufferE" : "54",
+    "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiEEE6bufferE" : "88"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/em_asm_table.wat b/binaryen/test/lld/em_asm_table.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm_table.wat
@@ -0,0 +1,13 @@
+(module
+ (type $0 (func (param i32 i32)))
+ (type $1 (func (param i32 i32 i32) (result i32)))
+ (import "env" "memory" (memory $2 8192))
+ (import "env" "emscripten_log" (func $fimport$0 (param i32 i32)))
+ (import "env" "emscripten_asm_const_int" (func $fimport$1 (param i32 i32 i32) (result i32)))
+ (table $0 159609 funcref)
+ (elem (i32.const 1) $fimport$0 $fimport$1)
+ (global $global$0 (mut i32) (i32.const 1024))
+ (global $global$1 i32 (i32.const 1048))
+ (export "__data_end" (global $global$1))
+)
+
diff --git a/binaryen/test/lld/em_asm_table.wat.out b/binaryen/test/lld/em_asm_table.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm_table.wat.out
@@ -0,0 +1,57 @@
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (type $i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32) (result i32)))
+ (import "env" "memory" (memory $2 8192))
+ (import "env" "emscripten_log" (func $fimport$0 (param i32 i32)))
+ (import "env" "emscripten_asm_const_int" (func $fimport$1 (param i32 i32 i32) (result i32)))
+ (table $0 159609 funcref)
+ (elem (i32.const 1) $fimport$0 $fimport$1)
+ (global $global$0 (mut i32) (i32.const 1024))
+ (global $global$1 i32 (i32.const 1048))
+ (export "__data_end" (global $global$1))
+ (export "dynCall_vii" (func $dynCall_vii))
+ (export "dynCall_iiii" (func $dynCall_iiii))
+ (func $dynCall_vii (param $fptr i32) (param $0 i32) (param $1 i32)
+  (call_indirect (type $i32_i32_=>_none)
+   (local.get $0)
+   (local.get $1)
+   (local.get $fptr)
+  )
+ )
+ (func $dynCall_iiii (param $fptr i32) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (call_indirect (type $i32_i32_i32_=>_i32)
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+   (local.get $fptr)
+  )
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 480,
+  "tableSize": 159609,
+  "declares": [
+    "emscripten_log",
+    "emscripten_asm_const_int"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "dynCall_vii",
+    "dynCall_iiii"
+  ],
+  "namedGlobals": {
+    "__data_end" : "1048"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/em_js_O0.wat b/binaryen/test/lld/em_js_O0.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_js_O0.wat
@@ -0,0 +1,22 @@
+(module
+ (import "env" "memory" (memory $0 256 256))
+ (data (i32.const 1024) "(void)<::>{ out(\"no args works\"); }\00(void)<::>{ out(\"no args returning int\"); return 12; }\00(void)<::>{ out(\"no args returning double\"); return 12.25; }\00(int x)<::>{ out(\"  takes ints: \" + x);}\00(double d)<::>{ out(\"  takes doubles: \" + d);}\00(char* str)<::>{ out(\"  takes strings: \" + UTF8ToString(str)); return 7.75; }\00(int x, int y)<::>{ out(\"  takes multiple ints: \" + x + \", \" + y); return 6; }\00(int x, const char* str, double d)<::>{ out(\"  mixed arg types: \" + x + \", \" + UTF8ToString(str) + \", \" + d); return 8.125; }\00(int unused)<::>{ out(\"  ignores unused args\"); return 5.5; }\00(int x, int y)<::>{ out(\"  skips unused args: \" + y); return 6; }\00(double x, double y, double z)<::>{ out(\"  \" + x + \" + \" + z); return x + z; }\00(void)<::>{ out(\"  can use <::> separator in user code\"); return 15; }\00(void)<::>{ var x, y; x = {}; y = 3; x[y] = [1, 2, 3]; out(\"  can have commas in user code: \" + x[y]); return x[y][1]; }\00(void)<::>{ var jsString = \'\e3\81\93\e3\82\93\e3\81\ab\e3\81\a1\e3\81\af\'; var lengthBytes = lengthBytesUTF8(jsString); var stringOnWasmHeap = _malloc(lengthBytes); stringToUTF8(jsString, stringOnWasmHeap, lengthBytes+1); return stringOnWasmHeap; }\00(void)<::>{ var jsString = \'hello from js\'; var lengthBytes = jsString.length+1; var stringOnWasmHeap = _malloc(lengthBytes); stringToUTF8(jsString, stringOnWasmHeap, lengthBytes+1); return stringOnWasmHeap; }\00BEGIN\n\00    noarg_int returned: %d\n\00    noarg_double returned: %f\n\00    stringarg returned: %f\n\00string arg\00    multi_intarg returned: %d\n\00    multi_mixedarg returned: %f\n\00hello\00    unused_args returned: %d\n\00    skip_args returned: %f\n\00    add_outer returned: %f\n\00    user_separator returned: %d\n\00    user_comma returned: %d\n\00    return_str returned: %s\n\00    return_utf8_str returned: %s\n\00END\n\00\00\cc\1a\00\00\00\00\00\00\00\00\00\00\00\00\00\00T!\"\19\0d\01\02\03\11K\1c\0c\10\04\0b\1d\12\1e\'hnopqb \05\06\0f\13\14\15\1a\08\16\07($\17\18\t\n\0e\1b\1f%#\83\82}&*+<=>?CGJMXYZ[\\]^_`acdefgijklrstyz{|\00\00\00\00\00\00\00\00\00Illegal byte sequence\00Domain error\00Result not representable\00Not a tty\00Permission denied\00Operation not permitted\00No such file or directory\00No such process\00File exists\00Value too large for data type\00No space left on device\00Out of memory\00Resource busy\00Interrupted system call\00Resource temporarily unavailable\00Invalid seek\00Cross-device link\00Read-only file system\00Directory not empty\00Connection reset by peer\00Operation timed out\00Connection refused\00Host is down\00Host is unreachable\00Address in use\00Broken pipe\00I/O error\00No such device or address\00Block device required\00No such device\00Not a directory\00Is a directory\00Text file busy\00Exec format error\00Invalid argument\00Argument list too long\00Symbolic link loop\00Filename too long\00Too many open files in system\00No file descriptors available\00Bad file descriptor\00No child process\00Bad address\00File too large\00Too many links\00No locks available\00Resource deadlock would occur\00State not recoverable\00Previous owner died\00Operation canceled\00Function not implemented\00No message of desired type\00Identifier removed\00Device not a stream\00No data available\00Device timeout\00Out of streams resources\00Link has been severed\00Protocol error\00Bad message\00File descriptor in bad state\00Not a socket\00Destination address required\00Message too large\00Protocol wrong type for socket\00Protocol not available\00Protocol not supported\00Socket type not supported\00Not supported\00Protocol family not supported\00Address family not supported by protocol\00Address not available\00Network is down\00Network unreachable\00Connection reset by network\00Connection aborted\00No buffer space available\00Socket is connected\00Socket not connected\00Cannot send after socket shutdown\00Operation already in progress\00Operation in progress\00Stale file handle\00Remote I/O error\00Quota exceeded\00No medium found\00Wrong medium type\00No error information\00\00-+   0X0x\00(null)\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 5232) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00")
+ (data (i32.const 6860) "\05\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\03\00\00\00\04\00\00\00\88\14\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\00\00\00\00\00\00\00\00\00\00\00\cc\1a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\b0\18\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00")
+ (global $global$0 (mut i32) (i32.const 5250112))
+ (global $global$1 i32 (i32.const 5250112))
+ (global $global$2 i32 (i32.const 7232))
+ (export "__em_js__noarg" (func $__em_js__noarg))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (func $__em_js__noarg (result i32)
+  (local $0 i32)
+  (local.set $0
+   (i32.const 1024)
+  )
+  (return
+   (local.get $0)
+  )
+ )
+)
+
diff --git a/binaryen/test/lld/em_js_O0.wat.out b/binaryen/test/lld/em_js_O0.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_js_O0.wat.out
@@ -0,0 +1,37 @@
+(module
+ (import "env" "memory" (memory $0 256 256))
+ (data (i32.const 1024) "(void)<::>{ out(\"no args works\"); }\00(void)<::>{ out(\"no args returning int\"); return 12; }\00(void)<::>{ out(\"no args returning double\"); return 12.25; }\00(int x)<::>{ out(\"  takes ints: \" + x);}\00(double d)<::>{ out(\"  takes doubles: \" + d);}\00(char* str)<::>{ out(\"  takes strings: \" + UTF8ToString(str)); return 7.75; }\00(int x, int y)<::>{ out(\"  takes multiple ints: \" + x + \", \" + y); return 6; }\00(int x, const char* str, double d)<::>{ out(\"  mixed arg types: \" + x + \", \" + UTF8ToString(str) + \", \" + d); return 8.125; }\00(int unused)<::>{ out(\"  ignores unused args\"); return 5.5; }\00(int x, int y)<::>{ out(\"  skips unused args: \" + y); return 6; }\00(double x, double y, double z)<::>{ out(\"  \" + x + \" + \" + z); return x + z; }\00(void)<::>{ out(\"  can use <::> separator in user code\"); return 15; }\00(void)<::>{ var x, y; x = {}; y = 3; x[y] = [1, 2, 3]; out(\"  can have commas in user code: \" + x[y]); return x[y][1]; }\00(void)<::>{ var jsString = \'\e3\81\93\e3\82\93\e3\81\ab\e3\81\a1\e3\81\af\'; var lengthBytes = lengthBytesUTF8(jsString); var stringOnWasmHeap = _malloc(lengthBytes); stringToUTF8(jsString, stringOnWasmHeap, lengthBytes+1); return stringOnWasmHeap; }\00(void)<::>{ var jsString = \'hello from js\'; var lengthBytes = jsString.length+1; var stringOnWasmHeap = _malloc(lengthBytes); stringToUTF8(jsString, stringOnWasmHeap, lengthBytes+1); return stringOnWasmHeap; }\00BEGIN\n\00    noarg_int returned: %d\n\00    noarg_double returned: %f\n\00    stringarg returned: %f\n\00string arg\00    multi_intarg returned: %d\n\00    multi_mixedarg returned: %f\n\00hello\00    unused_args returned: %d\n\00    skip_args returned: %f\n\00    add_outer returned: %f\n\00    user_separator returned: %d\n\00    user_comma returned: %d\n\00    return_str returned: %s\n\00    return_utf8_str returned: %s\n\00END\n\00\00\cc\1a\00\00\00\00\00\00\00\00\00\00\00\00\00\00T!\"\19\0d\01\02\03\11K\1c\0c\10\04\0b\1d\12\1e\'hnopqb \05\06\0f\13\14\15\1a\08\16\07($\17\18\t\n\0e\1b\1f%#\83\82}&*+<=>?CGJMXYZ[\\]^_`acdefgijklrstyz{|\00\00\00\00\00\00\00\00\00Illegal byte sequence\00Domain error\00Result not representable\00Not a tty\00Permission denied\00Operation not permitted\00No such file or directory\00No such process\00File exists\00Value too large for data type\00No space left on device\00Out of memory\00Resource busy\00Interrupted system call\00Resource temporarily unavailable\00Invalid seek\00Cross-device link\00Read-only file system\00Directory not empty\00Connection reset by peer\00Operation timed out\00Connection refused\00Host is down\00Host is unreachable\00Address in use\00Broken pipe\00I/O error\00No such device or address\00Block device required\00No such device\00Not a directory\00Is a directory\00Text file busy\00Exec format error\00Invalid argument\00Argument list too long\00Symbolic link loop\00Filename too long\00Too many open files in system\00No file descriptors available\00Bad file descriptor\00No child process\00Bad address\00File too large\00Too many links\00No locks available\00Resource deadlock would occur\00State not recoverable\00Previous owner died\00Operation canceled\00Function not implemented\00No message of desired type\00Identifier removed\00Device not a stream\00No data available\00Device timeout\00Out of streams resources\00Link has been severed\00Protocol error\00Bad message\00File descriptor in bad state\00Not a socket\00Destination address required\00Message too large\00Protocol wrong type for socket\00Protocol not available\00Protocol not supported\00Socket type not supported\00Not supported\00Protocol family not supported\00Address family not supported by protocol\00Address not available\00Network is down\00Network unreachable\00Connection reset by network\00Connection aborted\00No buffer space available\00Socket is connected\00Socket not connected\00Cannot send after socket shutdown\00Operation already in progress\00Operation in progress\00Stale file handle\00Remote I/O error\00Quota exceeded\00No medium found\00Wrong medium type\00No error information\00\00-+   0X0x\00(null)\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 5232) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00")
+ (data (i32.const 6860) "\05\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\03\00\00\00\04\00\00\00\88\14\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\00\00\00\00\00\00\00\00\00\00\00\cc\1a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\b0\18\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00")
+ (global $global$0 (mut i32) (i32.const 5250112))
+ (global $global$1 i32 (i32.const 5250112))
+ (global $global$2 i32 (i32.const 7232))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+)
+(;
+--BEGIN METADATA --
+{
+  "emJsFuncs": {
+    "noarg": "(void)<::>{ out(\"no args works\"); }"
+  },
+  "staticBump": 6664,
+  "tableSize": 0,
+  "declares": [
+  ],
+  "externs": [
+  ],
+  "exports": [
+  ],
+  "namedGlobals": {
+    "__heap_base" : "5250112",
+    "__data_end" : "7232"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/gdollar_mainmodule.wat b/binaryen/test/lld/gdollar_mainmodule.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/gdollar_mainmodule.wat
@@ -0,0 +1,20 @@
+(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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/gdollar_mainmodule.wat.out
@@ -0,0 +1,73 @@
+(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.c b/binaryen/test/lld/hello_world.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/hello_world.c
@@ -0,0 +1,6 @@
+int puts(const char* str);
+
+int main() {
+  puts("Hello, world");
+  return 0;
+}
diff --git a/binaryen/test/lld/hello_world.passive.wat b/binaryen/test/lld/hello_world.passive.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/hello_world.passive.wat
@@ -0,0 +1,40 @@
+(module
+ (type $0 (func (param i32) (result i32)))
+ (type $1 (func))
+ (type $2 (func (result i32)))
+ (type $3 (func (param i32 i32) (result i32)))
+ (import "env" "puts" (func $puts (param i32) (result i32)))
+ (memory $0 2)
+ (data passive "Hello, world\00")
+ (table $0 1 1 funcref)
+ (global $global$0 (mut i32) (i32.const 66128))
+ (global $global$1 i32 (i32.const 66128))
+ (global $global$2 i32 (i32.const 581))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (export "main" (func $main))
+ (func $__wasm_call_ctors (; 1 ;) (type $1)
+  (call $__wasm_init_memory)
+ )
+ (func $__wasm_init_memory (; 2 ;) (type $1)
+  (memory.init 0
+   (i32.const 568)
+   (i32.const 0)
+   (i32.const 14)
+  )
+ )
+ (func $__original_main (; 3 ;) (type $2) (result i32)
+  (drop
+   (call $puts
+    (i32.const 568)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (; 3 ;) (type $3) (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+ ;; custom section "producers", size 111
+)
diff --git a/binaryen/test/lld/hello_world.passive.wat.out b/binaryen/test/lld/hello_world.passive.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/hello_world.passive.wat.out
@@ -0,0 +1,68 @@
+(module
+ (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)))
+ (import "env" "puts" (func $puts (param i32) (result i32)))
+ (memory $0 2)
+ (data passive "Hello, world\00")
+ (table $0 1 1 funcref)
+ (global $global$0 (mut i32) (i32.const 66128))
+ (global $global$1 i32 (i32.const 66128))
+ (global $global$2 i32 (i32.const 581))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (export "main" (func $main))
+ (func $__wasm_call_ctors
+  (call $__wasm_init_memory)
+ )
+ (func $__wasm_init_memory
+  (memory.init 0
+   (i32.const 568)
+   (i32.const 0)
+   (i32.const 14)
+  )
+ )
+ (func $__original_main (result i32)
+  (drop
+   (call $puts
+    (i32.const 568)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 13,
+  "tableSize": 1,
+  "initializers": [
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+    "puts"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "main"
+  ],
+  "namedGlobals": {
+    "__heap_base" : "66128",
+    "__data_end" : "581"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/hello_world.wat b/binaryen/test/lld/hello_world.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/hello_world.wat
@@ -0,0 +1,31 @@
+(module
+ (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)))
+ (import "env" "puts" (func $puts (param i32) (result i32)))
+ (memory $0 2)
+ (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)
+  (drop
+   (call $puts
+    (i32.const 568)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+ ;; custom section "producers", size 112
+)
+
diff --git a/binaryen/test/lld/hello_world.wat.mem.mem b/binaryen/test/lld/hello_world.wat.mem.mem
new file mode 100644
Binary files /dev/null and b/binaryen/test/lld/hello_world.wat.mem.mem differ
diff --git a/binaryen/test/lld/hello_world.wat.mem.out b/binaryen/test/lld/hello_world.wat.mem.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/hello_world.wat.mem.out
@@ -0,0 +1,57 @@
+(module
+ (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)))
+ (import "env" "puts" (func $puts (param i32) (result i32)))
+ (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)
+ )
+ (func $__original_main (result i32)
+  (drop
+   (call $puts
+    (i32.const 568)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 13,
+  "tableSize": 1,
+  "initializers": [
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+    "puts"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "main"
+  ],
+  "namedGlobals": {
+    "__data_end" : "581"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/hello_world.wat.out b/binaryen/test/lld/hello_world.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/hello_world.wat.out
@@ -0,0 +1,58 @@
+(module
+ (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)))
+ (import "env" "puts" (func $puts (param i32) (result i32)))
+ (memory $0 2)
+ (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)
+ )
+ (func $__original_main (result i32)
+  (drop
+   (call $puts
+    (i32.const 568)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 13,
+  "tableSize": 1,
+  "initializers": [
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+    "puts"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "main"
+  ],
+  "namedGlobals": {
+    "__data_end" : "581"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/init.c b/binaryen/test/lld/init.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/init.c
@@ -0,0 +1,15 @@
+volatile int x, y;
+
+__attribute__((constructor))
+void init_x() {
+    x = 14;
+}
+
+__attribute__((constructor))
+void init_y() {
+    y = 144;
+}
+
+int main() {
+    return x + y;
+}
diff --git a/binaryen/test/lld/init.wat b/binaryen/test/lld/init.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/init.wat
@@ -0,0 +1,44 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (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)
+ )
+ (func $init_x
+  (i32.store offset=568
+   (i32.const 0)
+   (i32.const 14)
+  )
+ )
+ (func $init_y
+  (i32.store offset=572
+   (i32.const 0)
+   (i32.const 144)
+  )
+ )
+ (func $__original_main (result i32)
+  (i32.add
+   (i32.load offset=568
+    (i32.const 0)
+   )
+   (i32.load offset=572
+    (i32.const 0)
+   )
+  )
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+ ;; custom section "producers", size 112
+)
+
diff --git a/binaryen/test/lld/init.wat.out b/binaryen/test/lld/init.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/init.wat.out
@@ -0,0 +1,69 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (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)
+ )
+ (func $init_x
+  (i32.store offset=568
+   (i32.const 0)
+   (i32.const 14)
+  )
+ )
+ (func $init_y
+  (i32.store offset=572
+   (i32.const 0)
+   (i32.const 144)
+  )
+ )
+ (func $__original_main (result i32)
+  (i32.add
+   (i32.load offset=568
+    (i32.const 0)
+   )
+   (i32.load offset=572
+    (i32.const 0)
+   )
+  )
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 8,
+  "tableSize": 1,
+  "initializers": [
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "main"
+  ],
+  "namedGlobals": {
+    "__data_end" : "576"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/longjmp.c b/binaryen/test/lld/longjmp.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/longjmp.c
@@ -0,0 +1,17 @@
+typedef struct jmp_buf_buf {
+  int thing;
+} jmp_buf;
+
+void longjmp(jmp_buf env, int val);
+int setjmp(jmp_buf env);
+
+int __THREW__;
+int __threwValue;
+
+int main() {
+  jmp_buf jmp;
+  if (setjmp(jmp) == 0) {
+    longjmp(jmp, 1);
+  }
+  return 0;
+}
diff --git a/binaryen/test/lld/longjmp.wat b/binaryen/test/lld/longjmp.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/longjmp.wat
@@ -0,0 +1,135 @@
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 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" "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)))
+ (memory $0 2)
+ (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)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (i32.store
+   (local.tee $0
+    (call $fimport$0
+     (i32.const 40)
+    )
+   )
+   (i32.const 0)
+  )
+  (local.set $1
+   (call $fimport$1
+    (local.get $0)
+    (i32.const 1)
+    (local.get $0)
+    (i32.const 4)
+   )
+  )
+  (local.set $2
+   (call $fimport$2)
+  )
+  (local.set $0
+   (i32.const 0)
+  )
+  (block $label$1
+   (block $label$2
+    (loop $label$3
+     (br_if $label$2
+      (local.get $0)
+     )
+     (i32.store offset=568
+      (i32.const 0)
+      (i32.const 0)
+     )
+     (call $fimport$4
+      (i32.const 1)
+      (local.get $0)
+      (i32.const 1)
+     )
+     (local.set $0
+      (i32.load offset=568
+       (i32.const 0)
+      )
+     )
+     (i32.store offset=568
+      (i32.const 0)
+      (i32.const 0)
+     )
+     (block $label$4
+      (br_if $label$4
+       (i32.eqz
+        (local.get $0)
+       )
+      )
+      (br_if $label$4
+       (i32.eqz
+        (local.tee $3
+         (i32.load offset=572
+          (i32.const 0)
+         )
+        )
+       )
+      )
+      (br_if $label$1
+       (i32.eqz
+        (call $fimport$5
+         (i32.load
+          (local.get $0)
+         )
+         (local.get $1)
+         (local.get $2)
+        )
+       )
+      )
+      (call $fimport$6
+       (local.get $3)
+      )
+     )
+     (local.set $0
+      (call $fimport$2)
+     )
+     (br $label$3)
+    )
+   )
+   (call $fimport$7
+    (local.get $1)
+   )
+   (return
+    (i32.const 0)
+   )
+  )
+  (call $fimport$3
+   (local.get $0)
+   (local.get $3)
+  )
+  (unreachable)
+ )
+ (func $2 (param $0 i32) (param $1 i32) (result i32)
+  (call $1)
+ )
+ ;; custom section "producers", size 112
+)
+
diff --git a/binaryen/test/lld/longjmp.wat.out b/binaryen/test/lld/longjmp.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/longjmp.wat.out
@@ -0,0 +1,178 @@
+(module
+ (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 $none_=>_none (func))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 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" "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)))
+ (memory $0 2)
+ (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)
+ )
+ (func $1 (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (i32.store
+   (local.tee $0
+    (call $fimport$0
+     (i32.const 40)
+    )
+   )
+   (i32.const 0)
+  )
+  (local.set $1
+   (call $fimport$1
+    (local.get $0)
+    (i32.const 1)
+    (local.get $0)
+    (i32.const 4)
+   )
+  )
+  (local.set $2
+   (call $fimport$2)
+  )
+  (local.set $0
+   (i32.const 0)
+  )
+  (block $label$1
+   (block $label$2
+    (loop $label$3
+     (br_if $label$2
+      (local.get $0)
+     )
+     (i32.store offset=568
+      (i32.const 0)
+      (i32.const 0)
+     )
+     (call $fimport$4
+      (i32.const 1)
+      (local.get $0)
+      (i32.const 1)
+     )
+     (local.set $0
+      (i32.load offset=568
+       (i32.const 0)
+      )
+     )
+     (i32.store offset=568
+      (i32.const 0)
+      (i32.const 0)
+     )
+     (block $label$4
+      (br_if $label$4
+       (i32.eqz
+        (local.get $0)
+       )
+      )
+      (br_if $label$4
+       (i32.eqz
+        (local.tee $3
+         (i32.load offset=572
+          (i32.const 0)
+         )
+        )
+       )
+      )
+      (br_if $label$1
+       (i32.eqz
+        (call $fimport$5
+         (i32.load
+          (local.get $0)
+         )
+         (local.get $1)
+         (local.get $2)
+        )
+       )
+      )
+      (call $fimport$6
+       (local.get $3)
+      )
+     )
+     (local.set $0
+      (call $fimport$2)
+     )
+     (br $label$3)
+    )
+   )
+   (call $fimport$7
+    (local.get $1)
+   )
+   (return
+    (i32.const 0)
+   )
+  )
+  (call $fimport$3
+   (local.get $0)
+   (local.get $3)
+  )
+  (unreachable)
+ )
+ (func $2 (param $0 i32) (param $1 i32) (result i32)
+  (call $1)
+ )
+ (func $dynCall_vii (param $fptr i32) (param $0 i32) (param $1 i32)
+  (call_indirect (type $i32_i32_=>_none)
+   (local.get $0)
+   (local.get $1)
+   (local.get $fptr)
+  )
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 8,
+  "tableSize": 2,
+  "initializers": [
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+    "malloc",
+    "saveSetjmp",
+    "getTempRet0",
+    "emscripten_longjmp",
+    "testSetjmp",
+    "setTempRet0",
+    "free"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "main",
+    "dynCall_vii"
+  ],
+  "namedGlobals": {
+    "__data_end" : "576"
+  },
+  "invokeFuncs": [
+    "invoke_vii"
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/main_module.wat b/binaryen/test/lld/main_module.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/main_module.wat
@@ -0,0 +1,58 @@
+(module
+ (type $0 (func (param i32) (result i32)))
+ (type $1 (func))
+ (type $2 (func (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" "__stack_pointer" (global $sp (mut i32)))
+ (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)))
+ (import "env" "puts" (func $puts (param i32) (result i32)))
+ (global $global$0 i32 (i32.const 16))
+ (global $global$1 i32 (i32.const 20))
+ (global $global i32 (i32.const 42))
+ (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))
+ (func $__wasm_call_ctors (; 1 ;) (type $1)
+  (call $__wasm_apply_relocs)
+ )
+ (func $__wasm_apply_relocs (; 2 ;) (type $1)
+  (i32.store
+   (i32.add
+    (global.get $gimport$2)
+    (i32.const 16)
+   )
+   (global.get $gimport$6)
+  )
+  (i32.store
+   (i32.add
+    (global.get $gimport$2)
+    (i32.const 20)
+   )
+   (global.get $gimport$7)
+  )
+ )
+ (func $print_message\28\29 (; 3 ;) (type $2) (result i32)
+  (drop
+   (call $puts
+    (i32.add
+     (global.get $gimport$2)
+     (i32.const 0)
+    )
+   )
+  )
+  (i32.load
+   (global.get $gimport$5)
+  )
+ )
+ ;; custom section "dylink", size 5
+ ;; custom section "producers", size 112
+)
+
diff --git a/binaryen/test/lld/main_module.wat.out b/binaryen/test/lld/main_module.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/main_module.wat.out
@@ -0,0 +1,118 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (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" "__memory_base" (global $gimport$2 i32))
+ (import "env" "__table_base" (global $gimport$3 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)
+ )
+ (func $__wasm_apply_relocs
+  (i32.store
+   (i32.add
+    (global.get $gimport$2)
+    (i32.const 16)
+   )
+   (global.get $gimport$6)
+  )
+  (i32.store
+   (i32.add
+    (global.get $gimport$2)
+    (i32.const 20)
+   )
+   (global.get $gimport$7)
+  )
+ )
+ (func $print_message\28\29 (result i32)
+  (drop
+   (call $puts
+    (i32.add
+     (global.get $gimport$2)
+     (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
+   (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,
+  "initializers": [
+    "__assign_got_enties",
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+    "puts",
+    "g$external_var",
+    "fp$puts$ii"
+  ],
+  "externs": [
+    "___stack_pointer",
+    "___memory_base",
+    "___table_base"
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "_Z13print_messagev",
+    "dynCall_i",
+    "__assign_got_enties"
+  ],
+  "namedGlobals": {
+    "ptr_puts" : "16",
+    "ptr_local_func" : "20",
+    "__data_end" : "42"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/main_module_table.wat b/binaryen/test/lld/main_module_table.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/main_module_table.wat
@@ -0,0 +1,9 @@
+(module
+ (import "env" "__stack_pointer" (global $sp (mut i32)))
+ (import "GOT.func" "__stdio_write" (global $gimport$9 (mut i32)))
+ (global $global i32 (i32.const 42))
+ (export "__stdio_write" (func $__stdio_write))
+ (export "__data_end" (global $global))
+ (func $__stdio_write
+ )
+)
diff --git a/binaryen/test/lld/main_module_table.wat.out b/binaryen/test/lld/main_module_table.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/main_module_table.wat.out
@@ -0,0 +1,61 @@
+(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))
+ (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"
+  ],
+  "declares": [
+  ],
+  "externs": [
+    "___stack_pointer",
+    "___table_base"
+  ],
+  "exports": [
+    "__stdio_write",
+    "dynCall_v",
+    "__assign_got_enties"
+  ],
+  "namedGlobals": {
+    "__data_end" : "42"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/main_module_table_2.wat b/binaryen/test/lld/main_module_table_2.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/main_module_table_2.wat
@@ -0,0 +1,10 @@
+(module
+ (import "env" "__stack_pointer" (global $sp (mut i32)))
+ (import "GOT.func" "__stdio_write" (global $gimport$9 (mut i32)))
+ (import "env" "table" (table $timport$9 1 funcref))
+ (global $global i32 (i32.const 42))
+ (export "__stdio_write" (func $__stdio_write))
+ (export "__data_end" (global $global))
+ (func $__stdio_write
+ )
+)
diff --git a/binaryen/test/lld/main_module_table_2.wat.out b/binaryen/test/lld/main_module_table_2.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/main_module_table_2.wat.out
@@ -0,0 +1,61 @@
+(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))
+ (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"
+  ],
+  "declares": [
+  ],
+  "externs": [
+    "___stack_pointer",
+    "___table_base"
+  ],
+  "exports": [
+    "__stdio_write",
+    "dynCall_v",
+    "__assign_got_enties"
+  ],
+  "namedGlobals": {
+    "__data_end" : "42"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/main_module_table_3.wat b/binaryen/test/lld/main_module_table_3.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/main_module_table_3.wat
@@ -0,0 +1,11 @@
+(module
+ (import "env" "__stack_pointer" (global $sp (mut i32)))
+ (import "GOT.func" "__stdio_write" (global $gimport$9 (mut i32)))
+ (import "env" "table" (table $timport$9 1 funcref))
+ (elem (i32.const 0))
+ (global $global i32 (i32.const 42))
+ (export "__stdio_write" (func $__stdio_write))
+ (export "__data_end" (global $global))
+ (func $__stdio_write
+ )
+)
diff --git a/binaryen/test/lld/main_module_table_3.wat.out b/binaryen/test/lld/main_module_table_3.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/main_module_table_3.wat.out
@@ -0,0 +1,61 @@
+(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))
+ (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"
+  ],
+  "declares": [
+  ],
+  "externs": [
+    "___stack_pointer",
+    "___table_base"
+  ],
+  "exports": [
+    "__stdio_write",
+    "dynCall_v",
+    "__assign_got_enties"
+  ],
+  "namedGlobals": {
+    "__data_end" : "42"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/main_module_table_4.wat b/binaryen/test/lld/main_module_table_4.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/main_module_table_4.wat
@@ -0,0 +1,12 @@
+(module
+ (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))
+ (import "env" "table" (table $timport$9 1 funcref))
+ (elem (global.get $tb))
+ (global $global i32 (i32.const 42))
+ (export "__stdio_write" (func $__stdio_write))
+ (export "__data_end" (global $global))
+ (func $__stdio_write
+ )
+)
diff --git a/binaryen/test/lld/main_module_table_4.wat.out b/binaryen/test/lld/main_module_table_4.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/main_module_table_4.wat.out
@@ -0,0 +1,61 @@
+(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_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"
+  ],
+  "declares": [
+  ],
+  "externs": [
+    "___stack_pointer",
+    "___table_base"
+  ],
+  "exports": [
+    "__stdio_write",
+    "dynCall_v",
+    "__assign_got_enties"
+  ],
+  "namedGlobals": {
+    "__data_end" : "42"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/main_module_table_5.wat b/binaryen/test/lld/main_module_table_5.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/main_module_table_5.wat
@@ -0,0 +1,16 @@
+(module
+ (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))
+ (import "env" "table" (table $timport$9 1 funcref))
+ (elem (global.get $tb) $other $stuff)
+ (global $global i32 (i32.const 42))
+ (export "__stdio_write" (func $__stdio_write))
+ (export "__data_end" (global $global))
+ (func $__stdio_write
+ )
+ (func $other
+ )
+ (func $stuff
+ )
+)
diff --git a/binaryen/test/lld/main_module_table_5.wat.out b/binaryen/test/lld/main_module_table_5.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/main_module_table_5.wat.out
@@ -0,0 +1,67 @@
+(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_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 $other
+  (nop)
+ )
+ (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)
+  )
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 4294966770,
+  "tableSize": 2,
+  "initializers": [
+    "__assign_got_enties"
+  ],
+  "declares": [
+  ],
+  "externs": [
+    "___stack_pointer",
+    "___table_base"
+  ],
+  "exports": [
+    "__stdio_write",
+    "dynCall_v",
+    "__assign_got_enties"
+  ],
+  "namedGlobals": {
+    "__data_end" : "42"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/recursive.c b/binaryen/test/lld/recursive.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/recursive.c
@@ -0,0 +1,15 @@
+// This test emits a stack pointer, which tests global importing in object files
+// (which are mutable and not normally allowed).
+
+int printf(const char* fmt, ...);
+
+__attribute__((noinline))
+int foo(int a, int b) {
+    printf("%d:%d\n", a, b);
+    return a + b;
+}
+
+int main() {
+  printf("Result: %d\n", foo(1, 2));
+  return 0;
+}
diff --git a/binaryen/test/lld/recursive.wat b/binaryen/test/lld/recursive.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/recursive.wat
@@ -0,0 +1,88 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "iprintf" (func $iprintf (param i32 i32) (result i32)))
+ (memory $0 2)
+ (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)
+  (local $2 i32)
+  (global.set $global$0
+   (local.tee $2
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store offset=4
+   (local.get $2)
+   (local.get $1)
+  )
+  (i32.store
+   (local.get $2)
+   (local.get $0)
+  )
+  (drop
+   (call $iprintf
+    (i32.const 568)
+    (local.get $2)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $2)
+    (i32.const 16)
+   )
+  )
+  (i32.add
+   (local.get $1)
+   (local.get $0)
+  )
+ )
+ (func $__original_main (result i32)
+  (local $0 i32)
+  (global.set $global$0
+   (local.tee $0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store
+   (local.get $0)
+   (call $foo
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (call $iprintf
+    (i32.const 575)
+    (local.get $0)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $0)
+    (i32.const 16)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+ ;; custom section "producers", size 112
+)
+
diff --git a/binaryen/test/lld/recursive.wat.out b/binaryen/test/lld/recursive.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/recursive.wat.out
@@ -0,0 +1,115 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "iprintf" (func $iprintf (param i32 i32) (result i32)))
+ (memory $0 2)
+ (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)
+ )
+ (func $foo (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (global.set $global$0
+   (local.tee $2
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store offset=4
+   (local.get $2)
+   (local.get $1)
+  )
+  (i32.store
+   (local.get $2)
+   (local.get $0)
+  )
+  (drop
+   (call $iprintf
+    (i32.const 568)
+    (local.get $2)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $2)
+    (i32.const 16)
+   )
+  )
+  (i32.add
+   (local.get $1)
+   (local.get $0)
+  )
+ )
+ (func $__original_main (result i32)
+  (local $0 i32)
+  (global.set $global$0
+   (local.tee $0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store
+   (local.get $0)
+   (call $foo
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (call $iprintf
+    (i32.const 575)
+    (local.get $0)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $0)
+    (i32.const 16)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 19,
+  "tableSize": 1,
+  "initializers": [
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+    "iprintf"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "main"
+  ],
+  "namedGlobals": {
+    "__data_end" : "587"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/recursive_safe_stack.wat b/binaryen/test/lld/recursive_safe_stack.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/recursive_safe_stack.wat
@@ -0,0 +1,90 @@
+(module
+ (type $0 (func (param i32 i32) (result i32)))
+ (type $1 (func))
+ (type $2 (func (result i32)))
+ (import "env" "printf" (func $printf (param i32 i32) (result i32)))
+ (memory $0 2)
+ (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 66128))
+ (global $global$2 i32 (i32.const 587))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (export "main" (func $main))
+ (func $__wasm_call_ctors (; 1 ;) (type $1)
+ )
+ (func $foo (; 2 ;) (type $0) (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (global.set $global$0
+   (local.tee $2
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store offset=4
+   (local.get $2)
+   (local.get $1)
+  )
+  (i32.store
+   (local.get $2)
+   (local.get $0)
+  )
+  (drop
+   (call $printf
+    (i32.const 568)
+    (local.get $2)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $2)
+    (i32.const 16)
+   )
+  )
+  (i32.add
+   (local.get $1)
+   (local.get $0)
+  )
+ )
+ (func $__original_main (; 3 ;) (type $2) (result i32)
+  (local $0 i32)
+  (global.set $global$0
+   (local.tee $0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store
+   (local.get $0)
+   (call $foo
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (call $printf
+    (i32.const 575)
+    (local.get $0)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $0)
+    (i32.const 16)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (; 4 ;) (type $0) (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+ ;; custom section "producers", size 111
+)
+
diff --git a/binaryen/test/lld/recursive_safe_stack.wat.out b/binaryen/test/lld/recursive_safe_stack.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/recursive_safe_stack.wat.out
@@ -0,0 +1,205 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "printf" (func $printf (param i32 i32) (result i32)))
+ (import "env" "__handle_stack_overflow" (func $__handle_stack_overflow))
+ (memory $0 2)
+ (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 66128))
+ (global $global$2 i32 (i32.const 587))
+ (global $__stack_base (mut i32) (i32.const 0))
+ (global $__stack_limit (mut i32) (i32.const 0))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (export "main" (func $main))
+ (export "__set_stack_limits" (func $__set_stack_limits))
+ (func $__wasm_call_ctors
+  (nop)
+ )
+ (func $foo (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (block
+   (if
+    (i32.or
+     (i32.gt_u
+      (local.tee $3
+       (local.tee $2
+        (i32.sub
+         (global.get $global$0)
+         (i32.const 16)
+        )
+       )
+      )
+      (global.get $__stack_base)
+     )
+     (i32.lt_u
+      (local.get $3)
+      (global.get $__stack_limit)
+     )
+    )
+    (call $__handle_stack_overflow)
+   )
+   (global.set $global$0
+    (local.get $3)
+   )
+  )
+  (i32.store offset=4
+   (local.get $2)
+   (local.get $1)
+  )
+  (i32.store
+   (local.get $2)
+   (local.get $0)
+  )
+  (drop
+   (call $printf
+    (i32.const 568)
+    (local.get $2)
+   )
+  )
+  (block
+   (if
+    (i32.or
+     (i32.gt_u
+      (local.tee $4
+       (i32.add
+        (local.get $2)
+        (i32.const 16)
+       )
+      )
+      (global.get $__stack_base)
+     )
+     (i32.lt_u
+      (local.get $4)
+      (global.get $__stack_limit)
+     )
+    )
+    (call $__handle_stack_overflow)
+   )
+   (global.set $global$0
+    (local.get $4)
+   )
+  )
+  (i32.add
+   (local.get $1)
+   (local.get $0)
+  )
+ )
+ (func $__original_main (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block
+   (if
+    (i32.or
+     (i32.gt_u
+      (local.tee $1
+       (local.tee $0
+        (i32.sub
+         (global.get $global$0)
+         (i32.const 16)
+        )
+       )
+      )
+      (global.get $__stack_base)
+     )
+     (i32.lt_u
+      (local.get $1)
+      (global.get $__stack_limit)
+     )
+    )
+    (call $__handle_stack_overflow)
+   )
+   (global.set $global$0
+    (local.get $1)
+   )
+  )
+  (i32.store
+   (local.get $0)
+   (call $foo
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (call $printf
+    (i32.const 575)
+    (local.get $0)
+   )
+  )
+  (block
+   (if
+    (i32.or
+     (i32.gt_u
+      (local.tee $2
+       (i32.add
+        (local.get $0)
+        (i32.const 16)
+       )
+      )
+      (global.get $__stack_base)
+     )
+     (i32.lt_u
+      (local.get $2)
+      (global.get $__stack_limit)
+     )
+    )
+    (call $__handle_stack_overflow)
+   )
+   (global.set $global$0
+    (local.get $2)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+ (func $__set_stack_limits (param $0 i32) (param $1 i32)
+  (global.set $__stack_base
+   (local.get $0)
+  )
+  (global.set $__stack_limit
+   (local.get $1)
+  )
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 19,
+  "tableSize": 1,
+  "initializers": [
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+    "printf",
+    "__handle_stack_overflow"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "main",
+    "__set_stack_limits"
+  ],
+  "namedGlobals": {
+    "__heap_base" : "66128",
+    "__data_end" : "587"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/reserved_func_ptr.cpp b/binaryen/test/lld/reserved_func_ptr.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/reserved_func_ptr.cpp
@@ -0,0 +1,34 @@
+int atoi(const char *nptr);
+
+void address_taken_func(int a, int b, int c) {}
+void address_taken_func2(int a, int b, int c) {}
+
+int main(int argc, char **argv) {
+  int fp_v = atoi(argv[1]);
+  int fp_vi = atoi(argv[2]);
+  int fp_iii = atoi(argv[3]);
+  int fp_fffi = atoi(argv[4]);
+  int fp_ddi = atoi(argv[5]);
+
+  void (*f_viiii)(int, int, int) = 0;
+  if (argc > 3)
+    f_viiii = address_taken_func;
+  else
+    f_viiii = address_taken_func2;
+
+  void (*f_v)() = reinterpret_cast<void (*)()>(fp_v);
+  void (*f_vi)(int) = reinterpret_cast<void (*)(int)>(fp_vi);
+  int (*f_iii)(int, int) = reinterpret_cast<int (*)(int, int)>(fp_iii);
+  float (*f_fffi)(float, float, int) =
+      reinterpret_cast<float (*)(float, float, int)>(fp_fffi);
+  double (*f_ddi)(double, int) =
+      reinterpret_cast<double (*)(double, int)>(fp_ddi);
+
+  f_v();
+  f_vi(3);
+  f_iii(4, 5);
+  f_fffi(3.1f, 4.2f, 5);
+  f_ddi(4.2, 5);
+  f_viiii(1, 2, 3);
+  return 0;
+}
diff --git a/binaryen/test/lld/reserved_func_ptr.wat b/binaryen/test/lld/reserved_func_ptr.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/reserved_func_ptr.wat
@@ -0,0 +1,111 @@
+(module
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $f32_f32_i32_=>_f32 (func (param f32 f32 i32) (result f32)))
+ (type $f64_i32_=>_f64 (func (param f64 i32) (result f64)))
+ (import "env" "_Z4atoiPKc" (func $atoi\28char\20const*\29 (param i32) (result i32)))
+ (memory $0 2)
+ (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)
+ )
+ (func $address_taken_func2\28int\2c\20int\2c\20int\29 (param $0 i32) (param $1 i32) (param $2 i32)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $2
+   (call $atoi\28char\20const*\29
+    (i32.load offset=4
+     (local.get $1)
+    )
+   )
+  )
+  (local.set $3
+   (call $atoi\28char\20const*\29
+    (i32.load offset=8
+     (local.get $1)
+    )
+   )
+  )
+  (local.set $4
+   (call $atoi\28char\20const*\29
+    (i32.load offset=12
+     (local.get $1)
+    )
+   )
+  )
+  (local.set $5
+   (call $atoi\28char\20const*\29
+    (i32.load offset=16
+     (local.get $1)
+    )
+   )
+  )
+  (local.set $1
+   (call $atoi\28char\20const*\29
+    (i32.load offset=20
+     (local.get $1)
+    )
+   )
+  )
+  (call_indirect (type $none_=>_none)
+   (local.get $2)
+  )
+  (call_indirect (type $i32_=>_none)
+   (i32.const 3)
+   (local.get $3)
+  )
+  (drop
+   (call_indirect (type $i32_i32_=>_i32)
+    (i32.const 4)
+    (i32.const 5)
+    (local.get $4)
+   )
+  )
+  (drop
+   (call_indirect (type $f32_f32_i32_=>_f32)
+    (f32.const 3.0999999046325684)
+    (f32.const 4.199999809265137)
+    (i32.const 5)
+    (local.get $5)
+   )
+  )
+  (drop
+   (call_indirect (type $f64_i32_=>_f64)
+    (f64.const 4.2)
+    (i32.const 5)
+    (local.get $1)
+   )
+  )
+  (call_indirect (type $i32_i32_i32_=>_none)
+   (i32.const 1)
+   (i32.const 2)
+   (i32.const 3)
+   (select
+    (i32.const 1)
+    (i32.const 2)
+    (i32.gt_s
+     (local.get $0)
+     (i32.const 3)
+    )
+   )
+  )
+  (i32.const 0)
+ )
+ ;; custom section "producers", size 112
+)
+
diff --git a/binaryen/test/lld/reserved_func_ptr.wat.out b/binaryen/test/lld/reserved_func_ptr.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/reserved_func_ptr.wat.out
@@ -0,0 +1,151 @@
+(module
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $f32_f32_i32_=>_f32 (func (param f32 f32 i32) (result f32)))
+ (type $f64_i32_=>_f64 (func (param f64 i32) (result f64)))
+ (import "env" "_Z4atoiPKc" (func $atoi\28char\20const*\29 (param i32) (result i32)))
+ (memory $0 2)
+ (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)
+ )
+ (func $address_taken_func\28int\2c\20int\2c\20int\29 (param $0 i32) (param $1 i32) (param $2 i32)
+  (nop)
+ )
+ (func $address_taken_func2\28int\2c\20int\2c\20int\29 (param $0 i32) (param $1 i32) (param $2 i32)
+  (nop)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $2
+   (call $atoi\28char\20const*\29
+    (i32.load offset=4
+     (local.get $1)
+    )
+   )
+  )
+  (local.set $3
+   (call $atoi\28char\20const*\29
+    (i32.load offset=8
+     (local.get $1)
+    )
+   )
+  )
+  (local.set $4
+   (call $atoi\28char\20const*\29
+    (i32.load offset=12
+     (local.get $1)
+    )
+   )
+  )
+  (local.set $5
+   (call $atoi\28char\20const*\29
+    (i32.load offset=16
+     (local.get $1)
+    )
+   )
+  )
+  (local.set $1
+   (call $atoi\28char\20const*\29
+    (i32.load offset=20
+     (local.get $1)
+    )
+   )
+  )
+  (call_indirect (type $none_=>_none)
+   (local.get $2)
+  )
+  (call_indirect (type $i32_=>_none)
+   (i32.const 3)
+   (local.get $3)
+  )
+  (drop
+   (call_indirect (type $i32_i32_=>_i32)
+    (i32.const 4)
+    (i32.const 5)
+    (local.get $4)
+   )
+  )
+  (drop
+   (call_indirect (type $f32_f32_i32_=>_f32)
+    (f32.const 3.0999999046325684)
+    (f32.const 4.199999809265137)
+    (i32.const 5)
+    (local.get $5)
+   )
+  )
+  (drop
+   (call_indirect (type $f64_i32_=>_f64)
+    (f64.const 4.2)
+    (i32.const 5)
+    (local.get $1)
+   )
+  )
+  (call_indirect (type $i32_i32_i32_=>_none)
+   (i32.const 1)
+   (i32.const 2)
+   (i32.const 3)
+   (select
+    (i32.const 1)
+    (i32.const 2)
+    (i32.gt_s
+     (local.get $0)
+     (i32.const 3)
+    )
+   )
+  )
+  (i32.const 0)
+ )
+ (func $dynCall_viii (param $fptr i32) (param $0 i32) (param $1 i32) (param $2 i32)
+  (call_indirect (type $i32_i32_i32_=>_none)
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+   (local.get $fptr)
+  )
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 0,
+  "tableSize": 3,
+  "initializers": [
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+    "_Z4atoiPKc"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "main",
+    "dynCall_viii"
+  ],
+  "namedGlobals": {
+    "__data_end" : "568"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 1,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/safe_stack_standalone-wasm.wat b/binaryen/test/lld/safe_stack_standalone-wasm.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/safe_stack_standalone-wasm.wat
@@ -0,0 +1,89 @@
+(module
+ (type $0 (func (param i32 i32) (result i32)))
+ (type $1 (func))
+ (type $2 (func (result i32)))
+ (import "env" "printf" (func $printf (param i32 i32) (result i32)))
+ (memory $0 2)
+ (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 66128))
+ (global $global$2 i32 (i32.const 587))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (export "main" (func $main))
+ (func $__wasm_call_ctors (; 1 ;) (type $1)
+ )
+ (func $foo (; 2 ;) (type $0) (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (global.set $global$0
+   (local.tee $2
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store offset=4
+   (local.get $2)
+   (local.get $1)
+  )
+  (i32.store
+   (local.get $2)
+   (local.get $0)
+  )
+  (drop
+   (call $printf
+    (i32.const 568)
+    (local.get $2)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $2)
+    (i32.const 16)
+   )
+  )
+  (i32.add
+   (local.get $1)
+   (local.get $0)
+  )
+ )
+ (func $__original_main (; 3 ;) (type $2) (result i32)
+  (local $0 i32)
+  (global.set $global$0
+   (local.tee $0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store
+   (local.get $0)
+   (call $foo
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (call $printf
+    (i32.const 575)
+    (local.get $0)
+   )
+  )
+  (global.set $global$0
+   (i32.add
+    (local.get $0)
+    (i32.const 16)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (; 4 ;) (type $0) (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+)
+
diff --git a/binaryen/test/lld/safe_stack_standalone-wasm.wat.out b/binaryen/test/lld/safe_stack_standalone-wasm.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/safe_stack_standalone-wasm.wat.out
@@ -0,0 +1,202 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "printf" (func $printf (param i32 i32) (result i32)))
+ (memory $0 2)
+ (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 66128))
+ (global $global$2 i32 (i32.const 587))
+ (global $__stack_base (mut i32) (i32.const 0))
+ (global $__stack_limit (mut i32) (i32.const 0))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (export "main" (func $main))
+ (export "__set_stack_limits" (func $__set_stack_limits))
+ (func $__wasm_call_ctors
+  (nop)
+ )
+ (func $foo (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (block
+   (if
+    (i32.or
+     (i32.gt_u
+      (local.tee $3
+       (local.tee $2
+        (i32.sub
+         (global.get $global$0)
+         (i32.const 16)
+        )
+       )
+      )
+      (global.get $__stack_base)
+     )
+     (i32.lt_u
+      (local.get $3)
+      (global.get $__stack_limit)
+     )
+    )
+    (unreachable)
+   )
+   (global.set $global$0
+    (local.get $3)
+   )
+  )
+  (i32.store offset=4
+   (local.get $2)
+   (local.get $1)
+  )
+  (i32.store
+   (local.get $2)
+   (local.get $0)
+  )
+  (drop
+   (call $printf
+    (i32.const 568)
+    (local.get $2)
+   )
+  )
+  (block
+   (if
+    (i32.or
+     (i32.gt_u
+      (local.tee $4
+       (i32.add
+        (local.get $2)
+        (i32.const 16)
+       )
+      )
+      (global.get $__stack_base)
+     )
+     (i32.lt_u
+      (local.get $4)
+      (global.get $__stack_limit)
+     )
+    )
+    (unreachable)
+   )
+   (global.set $global$0
+    (local.get $4)
+   )
+  )
+  (i32.add
+   (local.get $1)
+   (local.get $0)
+  )
+ )
+ (func $__original_main (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block
+   (if
+    (i32.or
+     (i32.gt_u
+      (local.tee $1
+       (local.tee $0
+        (i32.sub
+         (global.get $global$0)
+         (i32.const 16)
+        )
+       )
+      )
+      (global.get $__stack_base)
+     )
+     (i32.lt_u
+      (local.get $1)
+      (global.get $__stack_limit)
+     )
+    )
+    (unreachable)
+   )
+   (global.set $global$0
+    (local.get $1)
+   )
+  )
+  (i32.store
+   (local.get $0)
+   (call $foo
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (call $printf
+    (i32.const 575)
+    (local.get $0)
+   )
+  )
+  (block
+   (if
+    (i32.or
+     (i32.gt_u
+      (local.tee $2
+       (i32.add
+        (local.get $0)
+        (i32.const 16)
+       )
+      )
+      (global.get $__stack_base)
+     )
+     (i32.lt_u
+      (local.get $2)
+      (global.get $__stack_limit)
+     )
+    )
+    (unreachable)
+   )
+   (global.set $global$0
+    (local.get $2)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+ (func $__set_stack_limits (param $0 i32) (param $1 i32)
+  (global.set $__stack_base
+   (local.get $0)
+  )
+  (global.set $__stack_limit
+   (local.get $1)
+  )
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 19,
+  "tableSize": 1,
+  "initializers": [
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+    "printf"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "main",
+    "__set_stack_limits"
+  ],
+  "namedGlobals": {
+    "__heap_base" : "66128",
+    "__data_end" : "587"
+  },
+  "invokeFuncs": [
+  ],
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/shared.cpp b/binaryen/test/lld/shared.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/shared.cpp
@@ -0,0 +1,10 @@
+extern "C" int puts(const char* str);
+extern "C" int external_var;
+
+int print_message() {
+  puts("Hello, world");
+  return external_var;
+}
+
+void* ptr_puts = (void*)&puts;
+void* ptr_local_func = (void*)&print_message;
diff --git a/binaryen/test/lld/shared.wat b/binaryen/test/lld/shared.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/shared.wat
@@ -0,0 +1,59 @@
+(module
+ (type $none_=>_none (func))
+ (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)))
+ (import "env" "puts" (func $puts (param i32) (result i32)))
+ (global $global$0 i32 (i32.const 16))
+ (global $global$1 i32 (i32.const 20))
+ (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))
+ (func $__wasm_call_ctors
+  (call $__wasm_apply_relocs)
+ )
+ (func $__wasm_apply_relocs
+  (i32.store
+   (i32.add
+    (global.get $gimport$2)
+    (i32.const 16)
+   )
+   (global.get $gimport$6)
+  )
+  (i32.store
+   (i32.add
+    (global.get $gimport$2)
+    (i32.const 20)
+   )
+   (global.get $gimport$7)
+  )
+ )
+ (func $print_message\28\29 (result i32)
+  (drop
+   (call $puts
+    (i32.add
+     (global.get $gimport$2)
+     (i32.const 0)
+    )
+   )
+  )
+  (i32.load
+   (global.get $gimport$5)
+  )
+ )
+ ;; dylink section
+ ;;   memorysize: 24
+ ;;   memoryalignment: 2
+ ;;   tablesize: 0
+ ;;   tablealignment: 0
+ ;; custom section "producers", size 112
+)
+
diff --git a/binaryen/test/lld/shared.wat.out b/binaryen/test/lld/shared.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/shared.wat.out
@@ -0,0 +1,101 @@
+(module
+ (type $none_=>_none (func))
+ (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))
+ (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 "_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)
+    (i32.const 16)
+   )
+   (global.get $gimport$6)
+  )
+  (i32.store
+   (i32.add
+    (global.get $gimport$2)
+    (i32.const 20)
+   )
+   (global.get $gimport$7)
+  )
+ )
+ (func $print_message\28\29 (result i32)
+  (drop
+   (call $puts
+    (i32.add
+     (global.get $gimport$2)
+     (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)
+  )
+ )
+ (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"
+  ],
+  "externs": [
+    "___memory_base",
+    "___table_base"
+  ],
+  "exports": [
+    "_Z13print_messagev",
+    "__post_instantiate"
+  ],
+  "namedGlobals": {
+    "ptr_puts" : "16",
+    "ptr_local_func" : "20"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/shared_add_to_table.wasm b/binaryen/test/lld/shared_add_to_table.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/lld/shared_add_to_table.wasm differ
diff --git a/binaryen/test/lld/shared_add_to_table.wasm.out b/binaryen/test/lld/shared_add_to_table.wasm.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/shared_add_to_table.wasm.out
@@ -0,0 +1,126 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (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$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))
+ (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 "__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)
+ )
+ (func $__wasm_apply_relocs
+ )
+ (func $waka_func_mine\28int\29 (param $0 i32) (result i32)
+  (i32.add
+   (local.get $0)
+   (i32.const 1)
+  )
+ )
+ (func $__original_main (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (global.get $gimport$6)
+  )
+  (local.set $1
+   (global.get $gimport$7)
+  )
+  (i32.add
+   (i32.add
+    (i32.load
+     (global.get $gimport$8)
+    )
+    (i32.add
+     (local.get $1)
+     (local.get $0)
+    )
+   )
+   (i32.load
+    (global.get $gimport$9)
+   )
+  )
+ )
+ (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
+ ;;   tablesize: 0
+ ;;   tablealignment: 0
+ ;; custom section "producers", size 157
+)
+(;
+--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"
+  ],
+  "externs": [
+    "___memory_base",
+    "___table_base"
+  ],
+  "exports": [
+    "__wasm_apply_relocs",
+    "_Z14waka_func_minei",
+    "__original_main",
+    "main",
+    "__post_instantiate"
+  ],
+  "namedGlobals": {
+    "waka_mine" : "0",
+    "__dso_handle" : "0"
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/shared_longjmp.c b/binaryen/test/lld/shared_longjmp.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/shared_longjmp.c
@@ -0,0 +1,16 @@
+typedef struct jmp_buf_buf {
+  int thing;
+} jmp_buf;
+
+void longjmp(jmp_buf env, int val);
+int setjmp(jmp_buf env);
+
+int __THREW__;
+int __threwValue;
+
+void _start() {
+  jmp_buf jmp;
+  if (setjmp(jmp) == 0) {
+    longjmp(jmp, 1);
+  }
+}
diff --git a/binaryen/test/lld/shared_longjmp.wat b/binaryen/test/lld/shared_longjmp.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/shared_longjmp.wat
@@ -0,0 +1,147 @@
+(module
+ (type $none_=>_none (func))
+ (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" "__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)))
+ (global $global$0 i32 (i32.const 0))
+ (global $global$1 i32 (i32.const 4))
+ (export "__wasm_call_ctors" (func $0))
+ (export "_start" (func $2))
+ (export "__THREW__" (global $global$0))
+ (export "__threwValue" (global $global$1))
+ (func $0
+  (call $1)
+ )
+ (func $1
+ )
+ (func $2
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (i32.store
+   (local.tee $0
+    (call $fimport$4
+     (i32.const 40)
+    )
+   )
+   (i32.const 0)
+  )
+  (local.set $1
+   (call $fimport$5
+    (local.get $0)
+    (i32.const 1)
+    (local.get $0)
+    (i32.const 4)
+   )
+  )
+  (local.set $2
+   (call $fimport$6)
+  )
+  (local.set $0
+   (i32.const 0)
+  )
+  (block $label$1
+   (block $label$2
+    (loop $label$3
+     (br_if $label$2
+      (local.get $0)
+     )
+     (i32.store
+      (local.tee $0
+       (global.get $gimport$12)
+      )
+      (i32.const 0)
+     )
+     (call $fimport$8
+      (global.get $gimport$13)
+      (local.get $0)
+      (i32.const 1)
+     )
+     (local.set $3
+      (i32.load
+       (local.get $0)
+      )
+     )
+     (i32.store
+      (local.get $0)
+      (i32.const 0)
+     )
+     (local.set $0
+      (global.get $gimport$14)
+     )
+     (block $label$4
+      (br_if $label$4
+       (i32.eqz
+        (local.get $3)
+       )
+      )
+      (br_if $label$4
+       (i32.eqz
+        (local.tee $0
+         (i32.load
+          (local.get $0)
+         )
+        )
+       )
+      )
+      (br_if $label$1
+       (i32.eqz
+        (call $fimport$9
+         (i32.load
+          (local.get $3)
+         )
+         (local.get $1)
+         (local.get $2)
+        )
+       )
+      )
+      (call $fimport$10
+       (local.get $0)
+      )
+     )
+     (local.set $0
+      (call $fimport$6)
+     )
+     (br $label$3)
+    )
+   )
+   (call $fimport$11
+    (local.get $1)
+   )
+   (return)
+  )
+  (call $fimport$7
+   (local.get $3)
+   (local.get $0)
+  )
+  (unreachable)
+ )
+ ;; dylink section
+ ;;   memorysize: 8
+ ;;   memoryalignment: 2
+ ;;   tablesize: 0
+ ;;   tablealignment: 0
+ ;; custom section "producers", size 112
+)
+
diff --git a/binaryen/test/lld/shared_longjmp.wat.out b/binaryen/test/lld/shared_longjmp.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/shared_longjmp.wat.out
@@ -0,0 +1,206 @@
+(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 $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))
+ (global $global$0 i32 (i32.const 0))
+ (global $global$1 i32 (i32.const 4))
+ (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)
+ )
+ (func $1
+  (nop)
+ )
+ (func $2
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (i32.store
+   (local.tee $0
+    (call $fimport$4
+     (i32.const 40)
+    )
+   )
+   (i32.const 0)
+  )
+  (local.set $1
+   (call $fimport$5
+    (local.get $0)
+    (i32.const 1)
+    (local.get $0)
+    (i32.const 4)
+   )
+  )
+  (local.set $2
+   (call $fimport$6)
+  )
+  (local.set $0
+   (i32.const 0)
+  )
+  (block $label$1
+   (block $label$2
+    (loop $label$3
+     (br_if $label$2
+      (local.get $0)
+     )
+     (i32.store
+      (local.tee $0
+       (global.get $gimport$12)
+      )
+      (i32.const 0)
+     )
+     (call $fimport$8
+      (global.get $gimport$13)
+      (local.get $0)
+      (i32.const 1)
+     )
+     (local.set $3
+      (i32.load
+       (local.get $0)
+      )
+     )
+     (i32.store
+      (local.get $0)
+      (i32.const 0)
+     )
+     (local.set $0
+      (global.get $gimport$14)
+     )
+     (block $label$4
+      (br_if $label$4
+       (i32.eqz
+        (local.get $3)
+       )
+      )
+      (br_if $label$4
+       (i32.eqz
+        (local.tee $0
+         (i32.load
+          (local.get $0)
+         )
+        )
+       )
+      )
+      (br_if $label$1
+       (i32.eqz
+        (call $fimport$9
+         (i32.load
+          (local.get $3)
+         )
+         (local.get $1)
+         (local.get $2)
+        )
+       )
+      )
+      (call $fimport$10
+       (local.get $0)
+      )
+     )
+     (local.set $0
+      (call $fimport$6)
+     )
+     (br $label$3)
+    )
+   )
+   (call $fimport$11
+    (local.get $1)
+   )
+   (return)
+  )
+  (call $fimport$7
+   (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)
+   (local.get $1)
+   (local.get $fptr)
+  )
+ )
+ (func $__post_instantiate
+  (call $__assign_got_enties)
+  (call $0)
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 0,
+  "tableSize": 0,
+  "declares": [
+    "malloc",
+    "saveSetjmp",
+    "getTempRet0",
+    "emscripten_longjmp",
+    "testSetjmp",
+    "setTempRet0",
+    "free",
+    "g$__THREW__",
+    "g$__threwValue",
+    "fp$emscripten_longjmp$vii"
+  ],
+  "externs": [
+    "___memory_base",
+    "___table_base"
+  ],
+  "exports": [
+    "_start",
+    "dynCall_vii",
+    "__post_instantiate"
+  ],
+  "namedGlobals": {
+    "__THREW__" : "0",
+    "__threwValue" : "4"
+  },
+  "invokeFuncs": [
+    "invoke_vii"
+  ],
+  "mainReadsParams": 0,
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/standalone-wasm-with-start.wat b/binaryen/test/lld/standalone-wasm-with-start.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/standalone-wasm-with-start.wat
@@ -0,0 +1,17 @@
+(module
+ (memory $0 2)
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $foo)
+ (global $global$0 (mut i32) (i32.const 66112))
+ (global $global$1 i32 (i32.const 66112))
+ (global $global$2 i32 (i32.const 576))
+ (export "memory" (memory $0))
+ (export "_start" (func $_start))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (func $_start (result i32)
+  (nop)
+ )
+ (func $foo (result i32))
+)
+
diff --git a/binaryen/test/lld/standalone-wasm-with-start.wat.out b/binaryen/test/lld/standalone-wasm-with-start.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/standalone-wasm-with-start.wat.out
@@ -0,0 +1,42 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 2)
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $foo)
+ (global $global$0 (mut i32) (i32.const 66112))
+ (global $global$1 i32 (i32.const 66112))
+ (global $global$2 i32 (i32.const 576))
+ (export "memory" (memory $0))
+ (export "_start" (func $_start))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (func $_start (result i32)
+  (nop)
+ )
+ (func $foo (result i32)
+  (nop)
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 8,
+  "tableSize": 1,
+  "declares": [
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "_start"
+  ],
+  "namedGlobals": {
+    "__heap_base" : "66112",
+    "__data_end" : "576"
+  },
+  "invokeFuncs": [
+  ],
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/standalone-wasm.wat b/binaryen/test/lld/standalone-wasm.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/standalone-wasm.wat
@@ -0,0 +1,20 @@
+(module
+ (memory $0 2)
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $foo)
+ (global $global$0 (mut i32) (i32.const 66112))
+ (global $global$1 i32 (i32.const 66112))
+ (global $global$2 i32 (i32.const 576))
+ (export "memory" (memory $0))
+ (export "main" (func $main))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (func $__original_main (result i32)
+  (nop)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+ (func $foo (result i32))
+)
+
diff --git a/binaryen/test/lld/standalone-wasm.wat.out b/binaryen/test/lld/standalone-wasm.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/standalone-wasm.wat.out
@@ -0,0 +1,46 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (memory $0 2)
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $foo)
+ (global $global$0 (mut i32) (i32.const 66112))
+ (global $global$1 i32 (i32.const 66112))
+ (global $global$2 i32 (i32.const 576))
+ (export "memory" (memory $0))
+ (export "main" (func $main))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (func $__original_main (result i32)
+  (nop)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+ (func $foo (result i32)
+  (nop)
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 8,
+  "tableSize": 1,
+  "declares": [
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "main"
+  ],
+  "namedGlobals": {
+    "__heap_base" : "66112",
+    "__data_end" : "576"
+  },
+  "invokeFuncs": [
+  ],
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/standalone-wasm2.wat b/binaryen/test/lld/standalone-wasm2.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/standalone-wasm2.wat
@@ -0,0 +1,17 @@
+(module
+ (memory $0 2)
+ (global $global$0 (mut i32) (i32.const 66112))
+ (global $global$1 i32 (i32.const 66112))
+ (global $global$2 i32 (i32.const 576))
+ (export "memory" (memory $0))
+ (export "main" (func $main))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (func $__original_main (param $0 i32) (param $1 i32) (result i32)
+  (nop)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main (local.get $0) (local.get $1))
+ )
+)
+
diff --git a/binaryen/test/lld/standalone-wasm2.wat.out b/binaryen/test/lld/standalone-wasm2.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/standalone-wasm2.wat.out
@@ -0,0 +1,43 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (memory $0 2)
+ (global $global$0 (mut i32) (i32.const 66112))
+ (global $global$1 i32 (i32.const 66112))
+ (global $global$2 i32 (i32.const 576))
+ (export "memory" (memory $0))
+ (export "main" (func $main))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (func $__original_main (param $0 i32) (param $1 i32) (result i32)
+  (nop)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 8,
+  "tableSize": 0,
+  "declares": [
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "main"
+  ],
+  "namedGlobals": {
+    "__heap_base" : "66112",
+    "__data_end" : "576"
+  },
+  "invokeFuncs": [
+  ],
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/standalone-wasm3.wat b/binaryen/test/lld/standalone-wasm3.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/standalone-wasm3.wat
@@ -0,0 +1,13 @@
+(module
+ (memory $0 2)
+ (global $global$0 (mut i32) (i32.const 66112))
+ (global $global$1 i32 (i32.const 66112))
+ (global $global$2 i32 (i32.const 576))
+ (export "memory" (memory $0))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (func $__original_main (param $0 i32) (param $1 i32) (result i32)
+  (nop)
+ )
+)
+
diff --git a/binaryen/test/lld/standalone-wasm3.wat.out b/binaryen/test/lld/standalone-wasm3.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/standalone-wasm3.wat.out
@@ -0,0 +1,35 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (memory $0 2)
+ (global $global$0 (mut i32) (i32.const 66112))
+ (global $global$1 i32 (i32.const 66112))
+ (global $global$2 i32 (i32.const 576))
+ (export "memory" (memory $0))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (func $__original_main (param $0 i32) (param $1 i32) (result i32)
+  (nop)
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "staticBump": 8,
+  "tableSize": 0,
+  "declares": [
+  ],
+  "externs": [
+  ],
+  "exports": [
+  ],
+  "namedGlobals": {
+    "__heap_base" : "66112",
+    "__data_end" : "576"
+  },
+  "invokeFuncs": [
+  ],
+  "features": [
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/mem.cpp b/binaryen/test/mem.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/mem.cpp
@@ -0,0 +1,34 @@
+#include <stdint.h>
+#include <emscripten.h>
+
+extern "C" {
+
+int EMSCRIPTEN_KEEPALIVE loadi8(size_t addr) { return ((int8_t*)addr)[0]; }
+int EMSCRIPTEN_KEEPALIVE loadi16(size_t addr) { return ((int16_t*)addr)[0]; }
+int EMSCRIPTEN_KEEPALIVE loadi32(size_t addr) { return ((int32_t*)addr)[0]; }
+
+int EMSCRIPTEN_KEEPALIVE loadu8(size_t addr) { return ((uint8_t*)addr)[0]; }
+int EMSCRIPTEN_KEEPALIVE loadu16(size_t addr) { return ((uint16_t*)addr)[0]; }
+int EMSCRIPTEN_KEEPALIVE loadu32(size_t addr) { return ((uint32_t*)addr)[0]; }
+
+double EMSCRIPTEN_KEEPALIVE loadf32(size_t addr) { return ((float*)addr)[0]; }
+double EMSCRIPTEN_KEEPALIVE loadf64(size_t addr) { return ((double*)addr)[0]; }
+
+void EMSCRIPTEN_KEEPALIVE storei8(size_t addr, int8_t v) { ((int8_t*)addr)[0] = v; }
+void EMSCRIPTEN_KEEPALIVE storei16(size_t addr, int16_t v) { ((int16_t*)addr)[0] = v; }
+void EMSCRIPTEN_KEEPALIVE storei32(size_t addr, int32_t v) { ((int32_t*)addr)[0] = v; }
+
+void EMSCRIPTEN_KEEPALIVE storeu8(size_t addr, uint8_t v) { ((uint8_t*)addr)[0] = v; }
+void EMSCRIPTEN_KEEPALIVE storeu16(size_t addr, uint16_t v) { ((uint16_t*)addr)[0] = v; }
+void EMSCRIPTEN_KEEPALIVE storeu32(size_t addr, uint32_t v) { ((uint32_t*)addr)[0] = v; }
+
+void EMSCRIPTEN_KEEPALIVE storef32(size_t addr, float v) { ((float*)addr)[0] = v; }
+void EMSCRIPTEN_KEEPALIVE storef64(size_t addr, double v) { ((double*)addr)[0] = v; }
+
+int* EMSCRIPTEN_KEEPALIVE get_stack() {
+  int t;
+  return &t;
+}
+
+}
+
diff --git a/binaryen/test/mem.emcc b/binaryen/test/mem.emcc
new file mode 100644
--- /dev/null
+++ b/binaryen/test/mem.emcc
@@ -0,0 +1,1 @@
+["-s", "ASSERTIONS=0"]
diff --git a/binaryen/test/mem.post.js b/binaryen/test/mem.post.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/mem.post.js
@@ -0,0 +1,53 @@
+
+function test(name) {
+  Module.print(name);
+  function doTest(x) {
+    // write to 0, as 0-8 is normally unused anyhow
+    Module['_store' + name](0, x);
+    Module.print('  ' + [x] + ' ==> ' + Module['_load' + name](0));
+  }
+  doTest(0);
+  doTest(1);
+  doTest(-1);
+  doTest(0.5);
+  doTest(-0.5);
+  doTest(1.4);
+  doTest(-1.4);
+  doTest(1.6);
+  doTest(-1.6);
+  doTest(5.1);
+  doTest(5.3);
+  doTest(5.7);
+  doTest(5.9);
+  doTest(1 << 10);
+  doTest(1 << 20);
+  doTest(-1 | 0);
+  doTest((-1 | 0) + 1);
+  doTest((-1 | 0) - 1);
+  doTest(-1 >>> 0);
+  doTest((-1 >>> 0) + 1);
+  doTest((-1 >>> 0) - 1);
+
+  Module.print('  pre  ==> ' + Module['_load' + name](0));
+  HEAPU8[0] = 10;
+  HEAPU8[1] = 20;
+  HEAPU8[2] = 30;
+  HEAPU8[3] = 40;
+  HEAPU8[4] = 50;
+  HEAPU8[5] = 99;
+  HEAPU8[6] = 125;
+  HEAPU8[7] = 250;
+  Module.print('  post ==> ' + Module['_load' + name](0));
+}
+
+test('i8');
+test('i16');
+test('i32');
+test('u8');
+test('u16');
+test('u32');
+test('f32');
+test('f64');
+
+Module.print('stack: ' + (Module['_get_stack']() > 8));
+
diff --git a/binaryen/test/mem.txt b/binaryen/test/mem.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/mem.txt
@@ -0,0 +1,193 @@
+i8
+  0 ==> 0
+  1 ==> 1
+  -1 ==> -1
+  0.5 ==> 0
+  -0.5 ==> 0
+  1.4 ==> 1
+  -1.4 ==> -1
+  1.6 ==> 1
+  -1.6 ==> -1
+  5.1 ==> 5
+  5.3 ==> 5
+  5.7 ==> 5
+  5.9 ==> 5
+  1024 ==> 0
+  1048576 ==> 0
+  -1 ==> -1
+  0 ==> 0
+  -2 ==> -2
+  4294967295 ==> -1
+  4294967296 ==> 0
+  4294967294 ==> -2
+  pre  ==> -2
+  post ==> 10
+i16
+  0 ==> 0
+  1 ==> 1
+  -1 ==> -1
+  0.5 ==> 0
+  -0.5 ==> 0
+  1.4 ==> 1
+  -1.4 ==> -1
+  1.6 ==> 1
+  -1.6 ==> -1
+  5.1 ==> 5
+  5.3 ==> 5
+  5.7 ==> 5
+  5.9 ==> 5
+  1024 ==> 1024
+  1048576 ==> 0
+  -1 ==> -1
+  0 ==> 0
+  -2 ==> -2
+  4294967295 ==> -1
+  4294967296 ==> 0
+  4294967294 ==> -2
+  pre  ==> -2
+  post ==> 5130
+i32
+  0 ==> 0
+  1 ==> 1
+  -1 ==> -1
+  0.5 ==> 0
+  -0.5 ==> 0
+  1.4 ==> 1
+  -1.4 ==> -1
+  1.6 ==> 1
+  -1.6 ==> -1
+  5.1 ==> 5
+  5.3 ==> 5
+  5.7 ==> 5
+  5.9 ==> 5
+  1024 ==> 1024
+  1048576 ==> 1048576
+  -1 ==> -1
+  0 ==> 0
+  -2 ==> -2
+  4294967295 ==> -1
+  4294967296 ==> 0
+  4294967294 ==> -2
+  pre  ==> -2
+  post ==> 673059850
+u8
+  0 ==> 0
+  1 ==> 1
+  -1 ==> 255
+  0.5 ==> 0
+  -0.5 ==> 0
+  1.4 ==> 1
+  -1.4 ==> 255
+  1.6 ==> 1
+  -1.6 ==> 255
+  5.1 ==> 5
+  5.3 ==> 5
+  5.7 ==> 5
+  5.9 ==> 5
+  1024 ==> 0
+  1048576 ==> 0
+  -1 ==> 255
+  0 ==> 0
+  -2 ==> 254
+  4294967295 ==> 255
+  4294967296 ==> 0
+  4294967294 ==> 254
+  pre  ==> 254
+  post ==> 10
+u16
+  0 ==> 0
+  1 ==> 1
+  -1 ==> 65535
+  0.5 ==> 0
+  -0.5 ==> 0
+  1.4 ==> 1
+  -1.4 ==> 65535
+  1.6 ==> 1
+  -1.6 ==> 65535
+  5.1 ==> 5
+  5.3 ==> 5
+  5.7 ==> 5
+  5.9 ==> 5
+  1024 ==> 1024
+  1048576 ==> 0
+  -1 ==> 65535
+  0 ==> 0
+  -2 ==> 65534
+  4294967295 ==> 65535
+  4294967296 ==> 0
+  4294967294 ==> 65534
+  pre  ==> 65534
+  post ==> 5130
+u32
+  0 ==> 0
+  1 ==> 1
+  -1 ==> -1
+  0.5 ==> 0
+  -0.5 ==> 0
+  1.4 ==> 1
+  -1.4 ==> -1
+  1.6 ==> 1
+  -1.6 ==> -1
+  5.1 ==> 5
+  5.3 ==> 5
+  5.7 ==> 5
+  5.9 ==> 5
+  1024 ==> 1024
+  1048576 ==> 1048576
+  -1 ==> -1
+  0 ==> 0
+  -2 ==> -2
+  4294967295 ==> -1
+  4294967296 ==> 0
+  4294967294 ==> -2
+  pre  ==> -2
+  post ==> 673059850
+f32
+  0 ==> 0
+  1 ==> 1
+  -1 ==> -1
+  0.5 ==> 0.5
+  -0.5 ==> -0.5
+  1.4 ==> 1.399999976158142
+  -1.4 ==> -1.399999976158142
+  1.6 ==> 1.600000023841858
+  -1.6 ==> -1.600000023841858
+  5.1 ==> 5.099999904632568
+  5.3 ==> 5.300000190734863
+  5.7 ==> 5.699999809265137
+  5.9 ==> 5.900000095367432
+  1024 ==> 1024
+  1048576 ==> 1048576
+  -1 ==> -1
+  0 ==> 0
+  -2 ==> -2
+  4294967295 ==> 4294967296
+  4294967296 ==> 4294967296
+  4294967294 ==> 4294967296
+  pre  ==> 4294967296
+  post ==> 8.775107173558151e-15
+f64
+  0 ==> 0
+  1 ==> 1
+  -1 ==> -1
+  0.5 ==> 0.5
+  -0.5 ==> -0.5
+  1.4 ==> 1.4
+  -1.4 ==> -1.4
+  1.6 ==> 1.6
+  -1.6 ==> -1.6
+  5.1 ==> 5.1
+  5.3 ==> 5.3
+  5.7 ==> 5.7
+  5.9 ==> 5.9
+  1024 ==> 1024
+  1048576 ==> 1048576
+  -1 ==> -1
+  0 ==> 0
+  -2 ==> -2
+  4294967295 ==> 4294967295
+  4294967296 ==> 4294967296
+  4294967294 ==> 4294967294
+  pre  ==> 4294967294
+  post ==> -1.066886858533604e+282
+stack: true
diff --git a/binaryen/test/memory-import.wast b/binaryen/test/memory-import.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/memory-import.wast
@@ -0,0 +1,9 @@
+(module
+  (type $0 (func (result i32)))
+  (import "env" "memory" (memory $0 1 1))
+  (func $foo (type $0) (result i32)
+    (i32.load offset=13
+      (i32.const 37)
+    )
+  )
+)
diff --git a/binaryen/test/memory-import.wast.from-wast b/binaryen/test/memory-import.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/memory-import.wast.from-wast
@@ -0,0 +1,9 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "memory" (memory $0 1 1))
+ (func $foo (result i32)
+  (i32.load offset=13
+   (i32.const 37)
+  )
+ )
+)
diff --git a/binaryen/test/memory-import.wast.fromBinary b/binaryen/test/memory-import.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/memory-import.wast.fromBinary
@@ -0,0 +1,10 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "memory" (memory $0 1 1))
+ (func $foo (result i32)
+  (i32.load offset=13
+   (i32.const 37)
+  )
+ )
+)
+
diff --git a/binaryen/test/memory-import.wast.fromBinary.noDebugInfo b/binaryen/test/memory-import.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/memory-import.wast.fromBinary.noDebugInfo
@@ -0,0 +1,10 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "memory" (memory $mimport$0 1 1))
+ (func $0 (result i32)
+  (i32.load offset=13
+   (i32.const 37)
+  )
+ )
+)
+
diff --git a/binaryen/test/memory-import64.wast b/binaryen/test/memory-import64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/memory-import64.wast
@@ -0,0 +1,9 @@
+(module
+  (type $0 (func (result i32)))
+  (import "env" "memory" (memory $0 i64 1 1))
+  (func $foo (type $0) (result i32)
+    (i32.load offset=13
+      (i64.const 37)
+    )
+  )
+)
diff --git a/binaryen/test/memory-import64.wast.from-wast b/binaryen/test/memory-import64.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/memory-import64.wast.from-wast
@@ -0,0 +1,9 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "memory" (memory $0 i64 1 1))
+ (func $foo (result i32)
+  (i32.load offset=13
+   (i64.const 37)
+  )
+ )
+)
diff --git a/binaryen/test/memory-import64.wast.fromBinary b/binaryen/test/memory-import64.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/memory-import64.wast.fromBinary
@@ -0,0 +1,10 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "memory" (memory $0 i64 1 1))
+ (func $foo (result i32)
+  (i32.load offset=13
+   (i64.const 37)
+  )
+ )
+)
+
diff --git a/binaryen/test/memory-import64.wast.fromBinary.noDebugInfo b/binaryen/test/memory-import64.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/memory-import64.wast.fromBinary.noDebugInfo
@@ -0,0 +1,10 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "memory" (memory $mimport$0 i64 1 1))
+ (func $0 (result i32)
+  (i32.load offset=13
+   (i64.const 37)
+  )
+ )
+)
+
diff --git a/binaryen/test/memory-import64.wast.wasm.fromBinary b/binaryen/test/memory-import64.wast.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/memory-import64.wast.wasm.fromBinary
@@ -0,0 +1,10 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "memory" (memory $0 1 1 i64))
+ (func $0 (result i32)
+  (i32.load offset=13
+   (i64.const 37)
+  )
+ )
+)
+
diff --git a/binaryen/test/memory-shared.wast b/binaryen/test/memory-shared.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/memory-shared.wast
@@ -0,0 +1,3 @@
+(module
+ (memory $0 (shared 23 256))
+)
diff --git a/binaryen/test/memory-shared.wast.from-wast b/binaryen/test/memory-shared.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/memory-shared.wast.from-wast
@@ -0,0 +1,3 @@
+(module
+ (memory $0 (shared 23 256))
+)
diff --git a/binaryen/test/memory-shared.wast.fromBinary b/binaryen/test/memory-shared.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/memory-shared.wast.fromBinary
@@ -0,0 +1,4 @@
+(module
+ (memory $0 (shared 23 256))
+)
+
diff --git a/binaryen/test/memory-shared.wast.fromBinary.noDebugInfo b/binaryen/test/memory-shared.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/memory-shared.wast.fromBinary.noDebugInfo
@@ -0,0 +1,4 @@
+(module
+ (memory $0 (shared 23 256))
+)
+
diff --git a/binaryen/test/memorygrowth-minimal.asm.js b/binaryen/test/memorygrowth-minimal.asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/memorygrowth-minimal.asm.js
@@ -0,0 +1,41 @@
+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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/memorygrowth.asm.js
@@ -0,0 +1,2387 @@
+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/metadatas.wasm b/binaryen/test/metadatas.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/metadatas.wasm differ
diff --git a/binaryen/test/metadatas.wasm.fromBinary b/binaryen/test/metadatas.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadatas.wasm.fromBinary
@@ -0,0 +1,10 @@
+(module
+ (type $none_=>_none (func))
+ (export "a" (func $0))
+ (func $0
+  (nop)
+ )
+ ;; custom section "emscripten_metadata", size 7
+ ;; custom section "producers", size 187
+)
+
diff --git a/binaryen/test/metadce/all-outside.wast b/binaryen/test/metadce/all-outside.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/all-outside.wast
@@ -0,0 +1,1 @@
+(module)
diff --git a/binaryen/test/metadce/all-outside.wast.dced b/binaryen/test/metadce/all-outside.wast.dced
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/all-outside.wast.dced
@@ -0,0 +1,2 @@
+(module
+)
diff --git a/binaryen/test/metadce/all-outside.wast.dced.stdout b/binaryen/test/metadce/all-outside.wast.dced.stdout
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/all-outside.wast.dced.stdout
@@ -0,0 +1,5 @@
+unused: island
+unused: lonely
+unused: loop1
+unused: loop2
+unused: reverse
diff --git a/binaryen/test/metadce/all-outside.wast.graph.txt b/binaryen/test/metadce/all-outside.wast.graph.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/all-outside.wast.graph.txt
@@ -0,0 +1,39 @@
+[
+  {
+    "name": "root1",
+    "reaches": ["two", "three"],
+    "root": true
+  },
+  {
+    "name": "root2",
+    "reaches": ["three"],
+    "root": true
+  },
+  {
+    "name": "two",
+    "reaches": ["two"],
+  },
+  {
+    "name": "three",
+  },
+  {
+    "name": "island",
+    "reaches": ["island"],
+  },
+  {
+    "name": "loop1",
+    "reaches": ["loop2"],
+  },
+  {
+    "name": "loop2",
+    "reaches": ["loop1"],
+  },
+  {
+    "name": "lonely",
+  },
+  {
+    "name": "reverse",
+    "reaches": ["root1"],
+  },
+]
+
diff --git a/binaryen/test/metadce/corners.wast b/binaryen/test/metadce/corners.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/corners.wast
@@ -0,0 +1,23 @@
+(module
+ (import "env" "STACKTOP" (global $STACKTOP$asm2wasm$import i32))
+ (global $STACKTOP (mut i32) (global.get $STACKTOP$asm2wasm$import))
+
+ (import "env" "UNUSEDTOP" (global $UNUSEDTOP$asm2wasm$import i32))
+ (global $UNUSEDTOP (mut i32) (global.get $UNUSEDTOP$asm2wasm$import))
+
+ (import "env" "imported_twice" (func $imported_twice_a)) ;; and used just once,
+ (import "env" "imported_twice" (func $imported_twice_b)) ;; but the other should not kill the import for both!
+
+ (import "env" "an-imported-table-func" (func $imported_table_func))
+
+ (import "env" "table" (table 10 10 funcref))
+ (elem (i32.const 0) $imported_table_func)
+
+ (export "stackAlloc" (func $stackAlloc))
+
+ (func $stackAlloc
+  (drop (global.get $STACKTOP))
+  (call $imported_twice_a)
+ )
+)
+
diff --git a/binaryen/test/metadce/corners.wast.dced b/binaryen/test/metadce/corners.wast.dced
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/corners.wast.dced
@@ -0,0 +1,16 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "table" (table $timport$0 10 10 funcref))
+ (elem (i32.const 0) $imported_table_func)
+ (import "env" "STACKTOP" (global $STACKTOP$asm2wasm$import i32))
+ (import "env" "imported_twice" (func $imported_twice_a))
+ (import "env" "an-imported-table-func" (func $imported_table_func))
+ (global $STACKTOP (mut i32) (global.get $STACKTOP$asm2wasm$import))
+ (export "stackAlloc" (func $stackAlloc))
+ (func $stackAlloc
+  (drop
+   (global.get $STACKTOP)
+  )
+  (call $imported_twice_a)
+ )
+)
diff --git a/binaryen/test/metadce/corners.wast.dced.stdout b/binaryen/test/metadce/corners.wast.dced.stdout
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/corners.wast.dced.stdout
@@ -0,0 +1,2 @@
+unused: global$UNUSEDTOP$2
+unused: ignorable import
diff --git a/binaryen/test/metadce/corners.wast.graph.txt b/binaryen/test/metadce/corners.wast.graph.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/corners.wast.graph.txt
@@ -0,0 +1,16 @@
+[
+  {
+    "name": "ignorable import",
+    "import": ["non", "existent"]
+  },
+  {
+    "name": "imported_twice",
+    "import": ["env", "imported_twice"]
+  },
+  {
+    "name": "stackAllocGood",
+    "export": "stackAlloc",
+    "root": true
+  }
+]
+
diff --git a/binaryen/test/metadce/no-outside.wast b/binaryen/test/metadce/no-outside.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/no-outside.wast
@@ -0,0 +1,12 @@
+(module
+ (import "env" "js_func" (func $a_js_func))
+ (import "env" "js_func_unused" (func $an_unused_js_func))
+ (export "wasm_func" (func $a_wasm_func))
+ (export "wasm_func_unused" (func $an_unused_wasm_func))
+ (func $a_wasm_func
+  (call $a_js_func)
+ )
+ (func $an_unused_wasm_func
+ )
+)
+
diff --git a/binaryen/test/metadce/no-outside.wast.dced b/binaryen/test/metadce/no-outside.wast.dced
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/no-outside.wast.dced
@@ -0,0 +1,2 @@
+(module
+)
diff --git a/binaryen/test/metadce/no-outside.wast.dced.stdout b/binaryen/test/metadce/no-outside.wast.dced.stdout
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/no-outside.wast.dced.stdout
@@ -0,0 +1,4 @@
+unused: export$wasm_func$4
+unused: export$wasm_func_unused$5
+unused: func$a_wasm_func$0
+unused: func$an_unused_wasm_func$1
diff --git a/binaryen/test/metadce/no-outside.wast.graph.txt b/binaryen/test/metadce/no-outside.wast.graph.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/no-outside.wast.graph.txt
@@ -0,0 +1,4 @@
+[
+]
+
+
diff --git a/binaryen/test/metadce/outside.wast b/binaryen/test/metadce/outside.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/outside.wast
@@ -0,0 +1,34 @@
+(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))
+
+ (export "wasm_func" (func $a_wasm_func))
+ (export "wasm_func_unused" (func $an_unused_wasm_func))
+
+ (global $__THREW__ (mut i32) (i32.const 0))
+ (global $__THREW__unused (mut i32) (i32.const 0))
+ (global $from_segment (mut i32) (i32.const 0))
+ (global $from_segment_2 (mut i32) (i32.const 0))
+ (global $from_segment_never_used (mut i32) (i32.const 0))
+
+ (data (i32.const 1024) "abcd")
+ (data (global.get $from_segment) "abcd")
+ (elem (global.get $from_segment_2) $table_func)
+
+ (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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/outside.wast.dced
@@ -0,0 +1,26 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "memory" (memory $0 256 256))
+ (data (i32.const 1024) "abcd")
+ (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))
+ (global $from_segment_2 (mut i32) (i32.const 0))
+ (export "wasm_func" (func $a_wasm_func))
+ (func $table_func
+  (nop)
+ )
+ (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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/outside.wast.dced.stdout
@@ -0,0 +1,6 @@
+unused: export$wasm_func_unused$12
+unused: func$an_unused_wasm_func$1
+unused: global$__THREW__unused$4
+unused: global$from_segment$5
+unused: global$from_segment_2$6
+unused: global$from_segment_never_used$7
diff --git a/binaryen/test/metadce/outside.wast.graph.txt b/binaryen/test/metadce/outside.wast.graph.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/outside.wast.graph.txt
@@ -0,0 +1,12 @@
+[
+  {
+    "name": "outside-entity",
+    "reaches": ["inside-wasm-func"],
+    "root": true
+  },
+  {
+    "name": "inside-wasm-func",
+    "export": "wasm_func"
+  }
+]
+
diff --git a/binaryen/test/metadce/rooted-export.wast b/binaryen/test/metadce/rooted-export.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/rooted-export.wast
@@ -0,0 +1,18 @@
+(module
+ (export "wasm_func_a" (func $a_wasm_func))
+ (export "wasm_func_b" (func $b_wasm_func))
+
+ (func $a_wasm_func
+  (unreachable)
+ )
+ (func $b_wasm_func
+  (unreachable)
+ )
+
+ (export "wasm_event_a" (event $a_wasm_event))
+ (export "wasm_event_b" (event $b_wasm_event))
+
+ (event $a_wasm_event (attr 0) (param i32))
+ (event $b_wasm_event (attr 0) (param i32))
+)
+
diff --git a/binaryen/test/metadce/rooted-export.wast.dced b/binaryen/test/metadce/rooted-export.wast.dced
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/rooted-export.wast.dced
@@ -0,0 +1,10 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (event $b_wasm_event (attr 0) (param i32))
+ (export "wasm_func_b" (func $b_wasm_func))
+ (export "wasm_event_b" (event $b_wasm_event))
+ (func $b_wasm_func
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/metadce/rooted-export.wast.dced.stdout b/binaryen/test/metadce/rooted-export.wast.dced.stdout
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/rooted-export.wast.dced.stdout
@@ -0,0 +1,4 @@
+unused: event$a_wasm_event$2
+unused: export$wasm_event_a$5
+unused: export$wasm_func_a$4
+unused: func$a_wasm_func$0
diff --git a/binaryen/test/metadce/rooted-export.wast.graph.txt b/binaryen/test/metadce/rooted-export.wast.graph.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/rooted-export.wast.graph.txt
@@ -0,0 +1,13 @@
+[
+  {
+    "name": "rooted-export-func",
+    "root": true,
+    "export": "wasm_func_b"
+  },
+  {
+    "name": "rooted-export-event",
+    "root": true,
+    "export": "wasm_event_b"
+  }
+]
+
diff --git a/binaryen/test/metadce/spanning_cycle.wast b/binaryen/test/metadce/spanning_cycle.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/spanning_cycle.wast
@@ -0,0 +1,18 @@
+(module
+ (memory 1 1)
+ (data passive "Hello, datacount section!")
+
+ (import "env" "js_func" (func $a_js_func))
+
+ (export "wasm_func_a" (func $a_wasm_func))
+
+ (func $a_wasm_func
+  ;; refer to the data segment to keep it around
+  (memory.init 0
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 25)
+  )
+  (call $a_js_func)
+ )
+)
diff --git a/binaryen/test/metadce/spanning_cycle.wast.dced b/binaryen/test/metadce/spanning_cycle.wast.dced
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/spanning_cycle.wast.dced
@@ -0,0 +1,15 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "js_func" (func $a_js_func))
+ (memory $0 1 1)
+ (data passive "Hello, datacount section!")
+ (export "wasm_func_a" (func $a_wasm_func))
+ (func $a_wasm_func
+  (memory.init 0
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 25)
+  )
+  (call $a_js_func)
+ )
+)
diff --git a/binaryen/test/metadce/spanning_cycle.wast.dced.stdout b/binaryen/test/metadce/spanning_cycle.wast.dced.stdout
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/spanning_cycle.wast.dced.stdout
diff --git a/binaryen/test/metadce/spanning_cycle.wast.graph.txt b/binaryen/test/metadce/spanning_cycle.wast.graph.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/spanning_cycle.wast.graph.txt
@@ -0,0 +1,17 @@
+[
+  {
+    "name": "root",
+    "root": true,
+    "reaches": ["wasm_export"],
+  },
+  {
+    "name": "wasm_export",
+    "export": "wasm_func_a"
+  },
+  {
+    "name": "outside_js_function",
+    "reaches": ["wasm_export"],
+    "import": ["env", "js_func"]
+  }
+]
+
diff --git a/binaryen/test/metadce/spanning_cycle_unrooted.wast b/binaryen/test/metadce/spanning_cycle_unrooted.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/spanning_cycle_unrooted.wast
@@ -0,0 +1,10 @@
+(module
+ (import "env" "js_func" (func $a_js_func))
+
+ (export "wasm_func_a" (func $a_wasm_func))
+
+ (func $a_wasm_func
+  (call $a_js_func)
+ )
+)
+
diff --git a/binaryen/test/metadce/spanning_cycle_unrooted.wast.dced b/binaryen/test/metadce/spanning_cycle_unrooted.wast.dced
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/spanning_cycle_unrooted.wast.dced
@@ -0,0 +1,2 @@
+(module
+)
diff --git a/binaryen/test/metadce/spanning_cycle_unrooted.wast.dced.stdout b/binaryen/test/metadce/spanning_cycle_unrooted.wast.dced.stdout
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/spanning_cycle_unrooted.wast.dced.stdout
@@ -0,0 +1,3 @@
+unused: func$a_wasm_func$0
+unused: outside_js_function
+unused: wasm_export
diff --git a/binaryen/test/metadce/spanning_cycle_unrooted.wast.graph.txt b/binaryen/test/metadce/spanning_cycle_unrooted.wast.graph.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/spanning_cycle_unrooted.wast.graph.txt
@@ -0,0 +1,12 @@
+[
+  {
+    "name": "wasm_export",
+    "export": "wasm_func_a"
+  },
+  {
+    "name": "outside_js_function",
+    "reaches": ["wasm_export"],
+    "import": ["env", "js_func"]
+  }
+]
+
diff --git a/binaryen/test/metadce/threaded.wast b/binaryen/test/metadce/threaded.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded.wast
@@ -0,0 +1,25 @@
+(module
+ (import "env" "js_func1" (func $js_func_1))
+ (import "env" "js_func2" (func $js_func_2))
+ (import "env" "js_func3" (func $js_func_3))
+ (import "env" "js_func4" (func $js_func_4))
+
+ (export "wasm_func1" (func $wasm_func_1))
+ (export "wasm_func2" (func $wasm_func_2))
+ (export "wasm_func3" (func $wasm_func_3))
+ (export "wasm_func4" (func $wasm_func_4))
+
+ (func $wasm_func_1
+  (call $js_func_2)
+ )
+ (func $wasm_func_2
+  (call $js_func_3)
+ )
+ (func $wasm_func_3
+  (call $js_func_4)
+ )
+ (func $wasm_func_4
+  (nop)
+ )
+)
+
diff --git a/binaryen/test/metadce/threaded.wast.dced b/binaryen/test/metadce/threaded.wast.dced
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded.wast.dced
@@ -0,0 +1,22 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "js_func4" (func $js_func_4))
+ (import "env" "js_func3" (func $js_func_3))
+ (import "env" "js_func2" (func $js_func_2))
+ (export "wasm_func1" (func $wasm_func_1))
+ (export "wasm_func2" (func $wasm_func_2))
+ (export "wasm_func3" (func $wasm_func_3))
+ (export "wasm_func4" (func $wasm_func_4))
+ (func $wasm_func_4
+  (nop)
+ )
+ (func $wasm_func_3
+  (call $js_func_4)
+ )
+ (func $wasm_func_2
+  (call $js_func_3)
+ )
+ (func $wasm_func_1
+  (call $js_func_2)
+ )
+)
diff --git a/binaryen/test/metadce/threaded.wast.dced.stdout b/binaryen/test/metadce/threaded.wast.dced.stdout
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded.wast.dced.stdout
@@ -0,0 +1,1 @@
+unused: outside_js_function1
diff --git a/binaryen/test/metadce/threaded.wast.graph.txt b/binaryen/test/metadce/threaded.wast.graph.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded.wast.graph.txt
@@ -0,0 +1,40 @@
+[
+  {
+    "name": "wasm_export1",
+    "export": "wasm_func1",
+    "root": true
+  },
+  {
+    "name": "wasm_export2",
+    "export": "wasm_func2"
+  },
+  {
+    "name": "wasm_export3",
+    "export": "wasm_func3"
+  },
+  {
+    "name": "wasm_export4",
+    "export": "wasm_func4"
+  },
+  {
+    "name": "outside_js_function1",
+    "reaches": ["wasm_export1"],
+    "import": ["env", "js_func1"]
+  },
+  {
+    "name": "outside_js_function2",
+    "reaches": ["wasm_export2"],
+    "import": ["env", "js_func2"]
+  },
+  {
+    "name": "outside_js_function3",
+    "reaches": ["wasm_export3"],
+    "import": ["env", "js_func3"]
+  },
+  {
+    "name": "outside_js_function4",
+    "reaches": ["wasm_export4"],
+    "import": ["env", "js_func4"]
+  }
+]
+
diff --git a/binaryen/test/metadce/threaded_cycle.wast b/binaryen/test/metadce/threaded_cycle.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded_cycle.wast
@@ -0,0 +1,25 @@
+(module
+ (import "env" "js_func1" (func $js_func_1))
+ (import "env" "js_func2" (func $js_func_2))
+ (import "env" "js_func3" (func $js_func_3))
+ (import "env" "js_func4" (func $js_func_4))
+
+ (export "wasm_func1" (func $wasm_func_1))
+ (export "wasm_func2" (func $wasm_func_2))
+ (export "wasm_func3" (func $wasm_func_3))
+ (export "wasm_func4" (func $wasm_func_4))
+
+ (func $wasm_func_1
+  (call $js_func_2)
+ )
+ (func $wasm_func_2
+  (call $js_func_3)
+ )
+ (func $wasm_func_3
+  (call $js_func_4)
+ )
+ (func $wasm_func_4
+  (call $js_func_1)
+ )
+)
+
diff --git a/binaryen/test/metadce/threaded_cycle.wast.dced b/binaryen/test/metadce/threaded_cycle.wast.dced
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded_cycle.wast.dced
@@ -0,0 +1,23 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "js_func4" (func $js_func_4))
+ (import "env" "js_func3" (func $js_func_3))
+ (import "env" "js_func2" (func $js_func_2))
+ (import "env" "js_func1" (func $js_func_1))
+ (export "wasm_func1" (func $wasm_func_1))
+ (export "wasm_func2" (func $wasm_func_2))
+ (export "wasm_func3" (func $wasm_func_3))
+ (export "wasm_func4" (func $wasm_func_4))
+ (func $wasm_func_4
+  (call $js_func_1)
+ )
+ (func $wasm_func_3
+  (call $js_func_4)
+ )
+ (func $wasm_func_2
+  (call $js_func_3)
+ )
+ (func $wasm_func_1
+  (call $js_func_2)
+ )
+)
diff --git a/binaryen/test/metadce/threaded_cycle.wast.dced.stdout b/binaryen/test/metadce/threaded_cycle.wast.dced.stdout
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded_cycle.wast.dced.stdout
diff --git a/binaryen/test/metadce/threaded_cycle.wast.graph.txt b/binaryen/test/metadce/threaded_cycle.wast.graph.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded_cycle.wast.graph.txt
@@ -0,0 +1,40 @@
+[
+  {
+    "name": "wasm_export1",
+    "export": "wasm_func1",
+  },
+  {
+    "name": "wasm_export2",
+    "export": "wasm_func2"
+  },
+  {
+    "name": "wasm_export3",
+    "export": "wasm_func3",
+    "root": true
+  },
+  {
+    "name": "wasm_export4",
+    "export": "wasm_func4"
+  },
+  {
+    "name": "outside_js_function1",
+    "reaches": ["wasm_export1"],
+    "import": ["env", "js_func1"]
+  },
+  {
+    "name": "outside_js_function2",
+    "reaches": ["wasm_export2"],
+    "import": ["env", "js_func2"]
+  },
+  {
+    "name": "outside_js_function3",
+    "reaches": ["wasm_export3"],
+    "import": ["env", "js_func3"]
+  },
+  {
+    "name": "outside_js_function4",
+    "reaches": ["wasm_export4"],
+    "import": ["env", "js_func4"]
+  }
+]
+
diff --git a/binaryen/test/metadce/threaded_unrooted.wast b/binaryen/test/metadce/threaded_unrooted.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded_unrooted.wast
@@ -0,0 +1,25 @@
+(module
+ (import "env" "js_func1" (func $js_func_1))
+ (import "env" "js_func2" (func $js_func_2))
+ (import "env" "js_func3" (func $js_func_3))
+ (import "env" "js_func4" (func $js_func_4))
+
+ (export "wasm_func1" (func $wasm_func_1))
+ (export "wasm_func2" (func $wasm_func_2))
+ (export "wasm_func3" (func $wasm_func_3))
+ (export "wasm_func4" (func $wasm_func_4))
+
+ (func $wasm_func_1
+  (call $js_func_2)
+ )
+ (func $wasm_func_2
+  (call $js_func_3)
+ )
+ (func $wasm_func_3
+  (call $js_func_4)
+ )
+ (func $wasm_func_4
+  (nop)
+ )
+)
+
diff --git a/binaryen/test/metadce/threaded_unrooted.wast.dced b/binaryen/test/metadce/threaded_unrooted.wast.dced
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded_unrooted.wast.dced
@@ -0,0 +1,2 @@
+(module
+)
diff --git a/binaryen/test/metadce/threaded_unrooted.wast.dced.stdout b/binaryen/test/metadce/threaded_unrooted.wast.dced.stdout
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded_unrooted.wast.dced.stdout
@@ -0,0 +1,12 @@
+unused: func$wasm_func_1$0
+unused: func$wasm_func_2$1
+unused: func$wasm_func_3$2
+unused: func$wasm_func_4$3
+unused: outside_js_function1
+unused: outside_js_function2
+unused: outside_js_function3
+unused: outside_js_function4
+unused: wasm_export1
+unused: wasm_export2
+unused: wasm_export3
+unused: wasm_export4
diff --git a/binaryen/test/metadce/threaded_unrooted.wast.graph.txt b/binaryen/test/metadce/threaded_unrooted.wast.graph.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded_unrooted.wast.graph.txt
@@ -0,0 +1,39 @@
+[
+  {
+    "name": "wasm_export1",
+    "export": "wasm_func1",
+  },
+  {
+    "name": "wasm_export2",
+    "export": "wasm_func2"
+  },
+  {
+    "name": "wasm_export3",
+    "export": "wasm_func3"
+  },
+  {
+    "name": "wasm_export4",
+    "export": "wasm_func4"
+  },
+  {
+    "name": "outside_js_function1",
+    "reaches": ["wasm_export1"],
+    "import": ["env", "js_func1"]
+  },
+  {
+    "name": "outside_js_function2",
+    "reaches": ["wasm_export2"],
+    "import": ["env", "js_func2"]
+  },
+  {
+    "name": "outside_js_function3",
+    "reaches": ["wasm_export3"],
+    "import": ["env", "js_func3"]
+  },
+  {
+    "name": "outside_js_function4",
+    "reaches": ["wasm_export4"],
+    "import": ["env", "js_func4"]
+  }
+]
+
diff --git a/binaryen/test/metadce/threaded_unrooted_cycle.wast b/binaryen/test/metadce/threaded_unrooted_cycle.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded_unrooted_cycle.wast
@@ -0,0 +1,25 @@
+(module
+ (import "env" "js_func1" (func $js_func_1))
+ (import "env" "js_func2" (func $js_func_2))
+ (import "env" "js_func3" (func $js_func_3))
+ (import "env" "js_func4" (func $js_func_4))
+
+ (export "wasm_func1" (func $wasm_func_1))
+ (export "wasm_func2" (func $wasm_func_2))
+ (export "wasm_func3" (func $wasm_func_3))
+ (export "wasm_func4" (func $wasm_func_4))
+
+ (func $wasm_func_1
+  (call $js_func_2)
+ )
+ (func $wasm_func_2
+  (call $js_func_3)
+ )
+ (func $wasm_func_3
+  (call $js_func_4)
+ )
+ (func $wasm_func_4
+  (call $js_func_1)
+ )
+)
+
diff --git a/binaryen/test/metadce/threaded_unrooted_cycle.wast.dced b/binaryen/test/metadce/threaded_unrooted_cycle.wast.dced
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded_unrooted_cycle.wast.dced
@@ -0,0 +1,2 @@
+(module
+)
diff --git a/binaryen/test/metadce/threaded_unrooted_cycle.wast.dced.stdout b/binaryen/test/metadce/threaded_unrooted_cycle.wast.dced.stdout
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded_unrooted_cycle.wast.dced.stdout
@@ -0,0 +1,12 @@
+unused: func$wasm_func_1$0
+unused: func$wasm_func_2$1
+unused: func$wasm_func_3$2
+unused: func$wasm_func_4$3
+unused: outside_js_function1
+unused: outside_js_function2
+unused: outside_js_function3
+unused: outside_js_function4
+unused: wasm_export1
+unused: wasm_export2
+unused: wasm_export3
+unused: wasm_export4
diff --git a/binaryen/test/metadce/threaded_unrooted_cycle.wast.graph.txt b/binaryen/test/metadce/threaded_unrooted_cycle.wast.graph.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/metadce/threaded_unrooted_cycle.wast.graph.txt
@@ -0,0 +1,39 @@
+[
+  {
+    "name": "wasm_export1",
+    "export": "wasm_func1",
+  },
+  {
+    "name": "wasm_export2",
+    "export": "wasm_func2"
+  },
+  {
+    "name": "wasm_export3",
+    "export": "wasm_func3"
+  },
+  {
+    "name": "wasm_export4",
+    "export": "wasm_func4"
+  },
+  {
+    "name": "outside_js_function1",
+    "reaches": ["wasm_export1"],
+    "import": ["env", "js_func1"]
+  },
+  {
+    "name": "outside_js_function2",
+    "reaches": ["wasm_export2"],
+    "import": ["env", "js_func2"]
+  },
+  {
+    "name": "outside_js_function3",
+    "reaches": ["wasm_export3"],
+    "import": ["env", "js_func3"]
+  },
+  {
+    "name": "outside_js_function4",
+    "reaches": ["wasm_export4"],
+    "import": ["env", "js_func4"]
+  }
+]
+
diff --git a/binaryen/test/min.asm.js b/binaryen/test/min.asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/min.asm.js
@@ -0,0 +1,52 @@
+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 b/binaryen/test/min.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/min.wast
@@ -0,0 +1,57 @@
+(module
+  (type $0 (func (param f32) (result f32)))
+  (type $1 (func (param i32 i32) (result f32)))
+  (type $2 (func (param i32) (result i32)))
+  (type $3 (func (param i32 i32 i32) (result i32)))
+  (memory $0 256 256)
+  (export "floats" (func $floats))
+  (func $floats (type $0) (param $f f32) (result f32)
+    (local $t f32)
+    (f32.add
+      (local.get $t)
+      (local.get $f)
+    )
+  )
+  (func $neg (type $1) (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 (type $2) (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 (type $3) (param $i1 i32) (param $i2 i32) (param $i3 i32) (result i32)
+    (block $topmost (result i32)
+      (local.get $i3)
+    )
+  )
+)
diff --git a/binaryen/test/min.wast.from-wast b/binaryen/test/min.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/min.wast.from-wast
@@ -0,0 +1,57 @@
+(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)
+ (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/min.wast.fromBinary b/binaryen/test/min.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/min.wast.fromBinary
@@ -0,0 +1,55 @@
+(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)
+ (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 $label$1 (result f32)
+     (i32.store
+      (local.get $k)
+      (local.get $p)
+     )
+     (f32.load
+      (local.get $k)
+     )
+    )
+   )
+  )
+ )
+ (func $littleswitch (param $x i32) (result i32)
+  (block $label$1 (result i32)
+   (block $label$2
+    (block $label$3
+     (br_table $label$3 $label$2 $label$3
+      (i32.sub
+       (local.get $x)
+       (i32.const 1)
+      )
+     )
+    )
+    (br $label$1
+     (i32.const 1)
+    )
+   )
+   (br $label$1
+    (i32.const 2)
+   )
+  )
+ )
+ (func $f1 (param $i1 i32) (param $i2 i32) (param $i3 i32) (result i32)
+  (local.get $i3)
+ )
+)
+
diff --git a/binaryen/test/min.wast.fromBinary.noDebugInfo b/binaryen/test/min.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/min.wast.fromBinary.noDebugInfo
@@ -0,0 +1,55 @@
+(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)
+ (export "floats" (func $0))
+ (func $0 (param $0 f32) (result f32)
+  (local $1 f32)
+  (f32.add
+   (local.get $1)
+   (local.get $0)
+  )
+ )
+ (func $1 (param $0 i32) (param $1 i32) (result f32)
+  (local $2 f32)
+  (local.tee $2
+   (f32.neg
+    (block $label$1 (result f32)
+     (i32.store
+      (local.get $0)
+      (local.get $1)
+     )
+     (f32.load
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $2 (param $0 i32) (result i32)
+  (block $label$1 (result i32)
+   (block $label$2
+    (block $label$3
+     (br_table $label$3 $label$2 $label$3
+      (i32.sub
+       (local.get $0)
+       (i32.const 1)
+      )
+     )
+    )
+    (br $label$1
+     (i32.const 1)
+    )
+   )
+   (br $label$1
+    (i32.const 2)
+   )
+  )
+ )
+ (func $3 (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local.get $2)
+ )
+)
+
diff --git a/binaryen/test/multivalue.wast b/binaryen/test/multivalue.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/multivalue.wast
@@ -0,0 +1,167 @@
+(module
+ (import "env" "pair" (func $pair (result i32 i64)))
+ (global $g1 (mut (i32 i64)) (tuple.make (i32.const 0) (i64.const 0)))
+ (global $g2 (i32 i64) (tuple.make (i32.const 0) (i64.const 0)))
+ ;; Test basic lowering of tuple.make, tuple.extract, and tuple variables
+ (func $triple (result i32 i64 f32)
+  (tuple.make
+   (i32.const 42)
+   (i64.const 7)
+   (f32.const 13)
+  )
+ )
+ (func $get-first (result i32)
+  (tuple.extract 0
+   (call $triple)
+  )
+ )
+ (func $get-second (result i64)
+  (tuple.extract 1
+   (call $triple)
+  )
+ )
+ (func $get-third (result f32)
+  (tuple.extract 2
+   (call $triple)
+  )
+ )
+ (func $reverse (result f32 i64 i32)
+  (local $x (i32 i64 f32))
+  (local.set $x
+   (call $triple)
+  )
+  (tuple.make
+   (tuple.extract 2
+    (local.get $x)
+   )
+   (tuple.extract 1
+    (local.get $x)
+   )
+   (tuple.extract 0
+    (local.get $x)
+   )
+  )
+ )
+ (func $unreachable (result i64)
+  (tuple.extract 1
+   (tuple.make
+    (i32.const 42)
+    (i64.const 7)
+    (unreachable)
+   )
+  )
+ )
+
+ ;; Test multivalue globals
+ (func $global (result i32 i64)
+  (global.set $g1
+   (tuple.make
+    (i32.const 42)
+    (i64.const 7)
+   )
+  )
+  (global.get $g2)
+ )
+
+ ;; Test lowering of multivalue drops
+ (func $drop-call
+  (drop
+   (call $pair)
+  )
+ )
+ (func $drop-tuple-make
+  (drop
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+   )
+  )
+ )
+ (func $drop-block
+  (drop
+   (block (result i32 i64)
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+    )
+   )
+  )
+ )
+
+ ;; Test multivalue control structures
+ (func $mv-return (result i32 i64)
+  (return
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+   )
+  )
+ )
+ (func $mv-return-in-block (result i32 i64)
+  (block (result i32 i64)
+   (return
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+    )
+   )
+  )
+ )
+ (func $mv-block-break (result i32 i64)
+  (block $l (result i32 i64)
+   (br $l
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+    )
+   )
+  )
+ )
+ (func $mv-block-br-if (result i32 i64)
+  (block $l (result i32 i64)
+   (br_if $l
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+    )
+    (i32.const 1)
+   )
+  )
+ )
+ (func $mv-if (result i32 i64 externref)
+  (if (result i32 i64 externref)
+   (i32.const 1)
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+    (ref.null extern)
+   )
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+    (ref.null extern)
+   )
+  )
+ )
+ (func $mv-loop (result i32 i64)
+  (loop (result i32 i64)
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+   )
+  )
+ )
+ (func $mv-switch (result i32 i64)
+  (block $a (result i32 i64)
+   (block $b (result i32 i64)
+    (br_table $a $b
+     (tuple.make
+      (i32.const 42)
+      (i64.const 42)
+     )
+     (i32.const 0)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/multivalue.wast.from-wast b/binaryen/test/multivalue.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/multivalue.wast.from-wast
@@ -0,0 +1,174 @@
+(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_=>_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)))
+ (import "env" "pair" (func $pair (result i32 i64)))
+ (global $g1 (mut (i32 i64)) (tuple.make
+  (i32.const 0)
+  (i64.const 0)
+ ))
+ (global $g2 (i32 i64) (tuple.make
+  (i32.const 0)
+  (i64.const 0)
+ ))
+ (func $triple (result i32 i64 f32)
+  (tuple.make
+   (i32.const 42)
+   (i64.const 7)
+   (f32.const 13)
+  )
+ )
+ (func $get-first (result i32)
+  (tuple.extract 0
+   (call $triple)
+  )
+ )
+ (func $get-second (result i64)
+  (tuple.extract 1
+   (call $triple)
+  )
+ )
+ (func $get-third (result f32)
+  (tuple.extract 2
+   (call $triple)
+  )
+ )
+ (func $reverse (result f32 i64 i32)
+  (local $x (i32 i64 f32))
+  (local.set $x
+   (call $triple)
+  )
+  (tuple.make
+   (tuple.extract 2
+    (local.get $x)
+   )
+   (tuple.extract 1
+    (local.get $x)
+   )
+   (tuple.extract 0
+    (local.get $x)
+   )
+  )
+ )
+ (func $unreachable (result i64)
+  (tuple.extract 1
+   (tuple.make
+    (i32.const 42)
+    (i64.const 7)
+    (unreachable)
+   )
+  )
+ )
+ (func $global (result i32 i64)
+  (global.set $g1
+   (tuple.make
+    (i32.const 42)
+    (i64.const 7)
+   )
+  )
+  (global.get $g2)
+ )
+ (func $drop-call
+  (drop
+   (call $pair)
+  )
+ )
+ (func $drop-tuple-make
+  (drop
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+   )
+  )
+ )
+ (func $drop-block
+  (drop
+   (block $block (result i32 i64)
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+    )
+   )
+  )
+ )
+ (func $mv-return (result i32 i64)
+  (return
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+   )
+  )
+ )
+ (func $mv-return-in-block (result i32 i64)
+  (block $block (result i32 i64)
+   (return
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+    )
+   )
+  )
+ )
+ (func $mv-block-break (result i32 i64)
+  (block $l (result i32 i64)
+   (br $l
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+    )
+   )
+  )
+ )
+ (func $mv-block-br-if (result i32 i64)
+  (block $l (result i32 i64)
+   (br_if $l
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+    )
+    (i32.const 1)
+   )
+  )
+ )
+ (func $mv-if (result i32 i64 externref)
+  (if (result i32 i64 externref)
+   (i32.const 1)
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+    (ref.null extern)
+   )
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+    (ref.null extern)
+   )
+  )
+ )
+ (func $mv-loop (result i32 i64)
+  (loop $loop-in (result i32 i64)
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+   )
+  )
+ )
+ (func $mv-switch (result i32 i64)
+  (block $a (result i32 i64)
+   (block $b (result i32 i64)
+    (br_table $a $b
+     (tuple.make
+      (i32.const 42)
+      (i64.const 42)
+     )
+     (i32.const 0)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/multivalue.wast.fromBinary b/binaryen/test/multivalue.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/multivalue.wast.fromBinary
@@ -0,0 +1,476 @@
+(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_=>_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)))
+ (import "env" "pair" (func $pair (result i32 i64)))
+ (global $g1 (mut i32) (i32.const 0))
+ (global $g2 (mut i64) (i64.const 0))
+ (global $global$2 i32 (i32.const 0))
+ (global $global$3 i64 (i64.const 0))
+ (func $triple (result i32 i64 f32)
+  (tuple.make
+   (i32.const 42)
+   (i64.const 7)
+   (f32.const 13)
+  )
+ )
+ (func $get-first (result i32)
+  (local $0 (i32 i64 f32))
+  (local $1 i64)
+  (local $2 i32)
+  (local.set $0
+   (call $triple)
+  )
+  (block (result i32)
+   (local.set $2
+    (tuple.extract 0
+     (local.get $0)
+    )
+   )
+   (drop
+    (block (result i64)
+     (local.set $1
+      (tuple.extract 1
+       (local.get $0)
+      )
+     )
+     (drop
+      (tuple.extract 2
+       (local.get $0)
+      )
+     )
+     (local.get $1)
+    )
+   )
+   (local.get $2)
+  )
+ )
+ (func $get-second (result i64)
+  (local $0 i64)
+  (local $1 (i32 i64 f32))
+  (local $2 i64)
+  (local $3 i32)
+  (local.set $1
+   (call $triple)
+  )
+  (drop
+   (block (result i32)
+    (local.set $3
+     (tuple.extract 0
+      (local.get $1)
+     )
+    )
+    (local.set $0
+     (block (result i64)
+      (local.set $2
+       (tuple.extract 1
+        (local.get $1)
+       )
+      )
+      (drop
+       (tuple.extract 2
+        (local.get $1)
+       )
+      )
+      (local.get $2)
+     )
+    )
+    (local.get $3)
+   )
+  )
+  (local.get $0)
+ )
+ (func $get-third (result f32)
+  (local $0 f32)
+  (local $1 (i32 i64 f32))
+  (local $2 i64)
+  (local $3 i32)
+  (local.set $1
+   (call $triple)
+  )
+  (drop
+   (block (result i32)
+    (local.set $3
+     (tuple.extract 0
+      (local.get $1)
+     )
+    )
+    (drop
+     (block (result i64)
+      (local.set $2
+       (tuple.extract 1
+        (local.get $1)
+       )
+      )
+      (local.set $0
+       (tuple.extract 2
+        (local.get $1)
+       )
+      )
+      (local.get $2)
+     )
+    )
+    (local.get $3)
+   )
+  )
+  (local.get $0)
+ )
+ (func $reverse (result f32 i64 i32)
+  (local $x i32)
+  (local $1 i64)
+  (local $2 i64)
+  (local $3 f32)
+  (local $4 f32)
+  (local $5 (i32 i64 f32))
+  (local $6 i64)
+  (local $7 i32)
+  (local $8 i64)
+  (local $9 i32)
+  (local $10 i64)
+  (local $11 i32)
+  (local $12 i64)
+  (local $13 i32)
+  (local $14 f32)
+  (local.set $5
+   (call $triple)
+  )
+  (local.set $x
+   (block (result i32)
+    (local.set $7
+     (tuple.extract 0
+      (local.get $5)
+     )
+    )
+    (local.set $1
+     (block (result i64)
+      (local.set $6
+       (tuple.extract 1
+        (local.get $5)
+       )
+      )
+      (local.set $3
+       (tuple.extract 2
+        (local.get $5)
+       )
+      )
+      (local.get $6)
+     )
+    )
+    (local.get $7)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $9
+     (local.get $x)
+    )
+    (drop
+     (block (result i64)
+      (local.set $8
+       (local.get $1)
+      )
+      (local.set $4
+       (local.get $3)
+      )
+      (local.get $8)
+     )
+    )
+    (local.get $9)
+   )
+  )
+  (tuple.make
+   (block (result f32)
+    (local.set $14
+     (local.get $4)
+    )
+    (drop
+     (block (result i32)
+      (local.set $11
+       (local.get $x)
+      )
+      (local.set $2
+       (block (result i64)
+        (local.set $10
+         (local.get $1)
+        )
+        (drop
+         (local.get $3)
+        )
+        (local.get $10)
+       )
+      )
+      (local.get $11)
+     )
+    )
+    (local.get $14)
+   )
+   (local.get $2)
+   (block (result i32)
+    (local.set $13
+     (local.get $x)
+    )
+    (drop
+     (block (result i64)
+      (local.set $12
+       (local.get $1)
+      )
+      (drop
+       (local.get $3)
+      )
+      (local.get $12)
+     )
+    )
+    (local.get $13)
+   )
+  )
+ )
+ (func $unreachable (result i64)
+  (drop
+   (i32.const 42)
+  )
+  (drop
+   (i64.const 7)
+  )
+  (unreachable)
+ )
+ (func $global (result i32 i64)
+  (local $0 i32)
+  (global.set $g1
+   (block (result i32)
+    (local.set $0
+     (i32.const 42)
+    )
+    (global.set $g2
+     (i64.const 7)
+    )
+    (local.get $0)
+   )
+  )
+  (tuple.make
+   (global.get $global$2)
+   (global.get $global$3)
+  )
+ )
+ (func $drop-call
+  (local $0 (i32 i64))
+  (local $1 i32)
+  (local.set $0
+   (call $pair)
+  )
+  (drop
+   (block (result i32)
+    (local.set $1
+     (tuple.extract 0
+      (local.get $0)
+     )
+    )
+    (drop
+     (tuple.extract 1
+      (local.get $0)
+     )
+    )
+    (local.get $1)
+   )
+  )
+ )
+ (func $drop-tuple-make
+  (local $0 i32)
+  (drop
+   (block (result i32)
+    (local.set $0
+     (i32.const 42)
+    )
+    (drop
+     (i64.const 42)
+    )
+    (local.get $0)
+   )
+  )
+ )
+ (func $drop-block
+  (local $0 (i32 i64))
+  (local $1 i32)
+  (local.set $0
+   (block $label$1 (result i32 i64)
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $1
+     (tuple.extract 0
+      (local.get $0)
+     )
+    )
+    (drop
+     (tuple.extract 1
+      (local.get $0)
+     )
+    )
+    (local.get $1)
+   )
+  )
+ )
+ (func $mv-return (result i32 i64)
+  (return
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+   )
+  )
+ )
+ (func $mv-return-in-block (result i32 i64)
+  (return
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+   )
+  )
+ )
+ (func $mv-block-break (result i32 i64)
+  (local $0 (i32 i64))
+  (local.set $0
+   (block $label$1 (result i32 i64)
+    (br $label$1
+     (tuple.make
+      (i32.const 42)
+      (i64.const 42)
+     )
+    )
+   )
+  )
+  (tuple.make
+   (tuple.extract 0
+    (local.get $0)
+   )
+   (tuple.extract 1
+    (local.get $0)
+   )
+  )
+ )
+ (func $mv-block-br-if (result i32 i64)
+  (local $0 (i32 i64))
+  (local $1 (i32 i64))
+  (local.set $1
+   (block $label$1 (result i32 i64)
+    (local.set $0
+     (br_if $label$1
+      (tuple.make
+       (i32.const 42)
+       (i64.const 42)
+      )
+      (i32.const 1)
+     )
+    )
+    (tuple.make
+     (tuple.extract 0
+      (local.get $0)
+     )
+     (tuple.extract 1
+      (local.get $0)
+     )
+    )
+   )
+  )
+  (tuple.make
+   (tuple.extract 0
+    (local.get $1)
+   )
+   (tuple.extract 1
+    (local.get $1)
+   )
+  )
+ )
+ (func $mv-if (result i32 i64 externref)
+  (local $0 (i32 i64 externref))
+  (local.set $0
+   (if (result i32 i64 externref)
+    (i32.const 1)
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+     (ref.null extern)
+    )
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+     (ref.null extern)
+    )
+   )
+  )
+  (tuple.make
+   (tuple.extract 0
+    (local.get $0)
+   )
+   (tuple.extract 1
+    (local.get $0)
+   )
+   (tuple.extract 2
+    (local.get $0)
+   )
+  )
+ )
+ (func $mv-loop (result i32 i64)
+  (local $0 (i32 i64))
+  (local.set $0
+   (loop $label$1 (result i32 i64)
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+    )
+   )
+  )
+  (tuple.make
+   (tuple.extract 0
+    (local.get $0)
+   )
+   (tuple.extract 1
+    (local.get $0)
+   )
+  )
+ )
+ (func $mv-switch (result i32 i64)
+  (local $0 (i32 i64))
+  (local $1 (i32 i64))
+  (local.set $1
+   (block $label$1 (result i32 i64)
+    (local.set $0
+     (block $label$2 (result i32 i64)
+      (br_table $label$1 $label$2
+       (tuple.make
+        (i32.const 42)
+        (i64.const 42)
+       )
+       (i32.const 0)
+      )
+     )
+    )
+    (tuple.make
+     (tuple.extract 0
+      (local.get $0)
+     )
+     (tuple.extract 1
+      (local.get $0)
+     )
+    )
+   )
+  )
+  (tuple.make
+   (tuple.extract 0
+    (local.get $1)
+   )
+   (tuple.extract 1
+    (local.get $1)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/multivalue.wast.fromBinary.noDebugInfo b/binaryen/test/multivalue.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/multivalue.wast.fromBinary.noDebugInfo
@@ -0,0 +1,476 @@
+(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_=>_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)))
+ (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))
+ (global $global$2 i32 (i32.const 0))
+ (global $global$3 i64 (i64.const 0))
+ (func $0 (result i32 i64 f32)
+  (tuple.make
+   (i32.const 42)
+   (i64.const 7)
+   (f32.const 13)
+  )
+ )
+ (func $1 (result i32)
+  (local $0 (i32 i64 f32))
+  (local $1 i64)
+  (local $2 i32)
+  (local.set $0
+   (call $0)
+  )
+  (block (result i32)
+   (local.set $2
+    (tuple.extract 0
+     (local.get $0)
+    )
+   )
+   (drop
+    (block (result i64)
+     (local.set $1
+      (tuple.extract 1
+       (local.get $0)
+      )
+     )
+     (drop
+      (tuple.extract 2
+       (local.get $0)
+      )
+     )
+     (local.get $1)
+    )
+   )
+   (local.get $2)
+  )
+ )
+ (func $2 (result i64)
+  (local $0 i64)
+  (local $1 (i32 i64 f32))
+  (local $2 i64)
+  (local $3 i32)
+  (local.set $1
+   (call $0)
+  )
+  (drop
+   (block (result i32)
+    (local.set $3
+     (tuple.extract 0
+      (local.get $1)
+     )
+    )
+    (local.set $0
+     (block (result i64)
+      (local.set $2
+       (tuple.extract 1
+        (local.get $1)
+       )
+      )
+      (drop
+       (tuple.extract 2
+        (local.get $1)
+       )
+      )
+      (local.get $2)
+     )
+    )
+    (local.get $3)
+   )
+  )
+  (local.get $0)
+ )
+ (func $3 (result f32)
+  (local $0 f32)
+  (local $1 (i32 i64 f32))
+  (local $2 i64)
+  (local $3 i32)
+  (local.set $1
+   (call $0)
+  )
+  (drop
+   (block (result i32)
+    (local.set $3
+     (tuple.extract 0
+      (local.get $1)
+     )
+    )
+    (drop
+     (block (result i64)
+      (local.set $2
+       (tuple.extract 1
+        (local.get $1)
+       )
+      )
+      (local.set $0
+       (tuple.extract 2
+        (local.get $1)
+       )
+      )
+      (local.get $2)
+     )
+    )
+    (local.get $3)
+   )
+  )
+  (local.get $0)
+ )
+ (func $4 (result f32 i64 i32)
+  (local $0 i32)
+  (local $1 i64)
+  (local $2 i64)
+  (local $3 f32)
+  (local $4 f32)
+  (local $5 (i32 i64 f32))
+  (local $6 i64)
+  (local $7 i32)
+  (local $8 i64)
+  (local $9 i32)
+  (local $10 i64)
+  (local $11 i32)
+  (local $12 i64)
+  (local $13 i32)
+  (local $14 f32)
+  (local.set $5
+   (call $0)
+  )
+  (local.set $0
+   (block (result i32)
+    (local.set $7
+     (tuple.extract 0
+      (local.get $5)
+     )
+    )
+    (local.set $1
+     (block (result i64)
+      (local.set $6
+       (tuple.extract 1
+        (local.get $5)
+       )
+      )
+      (local.set $3
+       (tuple.extract 2
+        (local.get $5)
+       )
+      )
+      (local.get $6)
+     )
+    )
+    (local.get $7)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $9
+     (local.get $0)
+    )
+    (drop
+     (block (result i64)
+      (local.set $8
+       (local.get $1)
+      )
+      (local.set $4
+       (local.get $3)
+      )
+      (local.get $8)
+     )
+    )
+    (local.get $9)
+   )
+  )
+  (tuple.make
+   (block (result f32)
+    (local.set $14
+     (local.get $4)
+    )
+    (drop
+     (block (result i32)
+      (local.set $11
+       (local.get $0)
+      )
+      (local.set $2
+       (block (result i64)
+        (local.set $10
+         (local.get $1)
+        )
+        (drop
+         (local.get $3)
+        )
+        (local.get $10)
+       )
+      )
+      (local.get $11)
+     )
+    )
+    (local.get $14)
+   )
+   (local.get $2)
+   (block (result i32)
+    (local.set $13
+     (local.get $0)
+    )
+    (drop
+     (block (result i64)
+      (local.set $12
+       (local.get $1)
+      )
+      (drop
+       (local.get $3)
+      )
+      (local.get $12)
+     )
+    )
+    (local.get $13)
+   )
+  )
+ )
+ (func $5 (result i64)
+  (drop
+   (i32.const 42)
+  )
+  (drop
+   (i64.const 7)
+  )
+  (unreachable)
+ )
+ (func $6 (result i32 i64)
+  (local $0 i32)
+  (global.set $global$0
+   (block (result i32)
+    (local.set $0
+     (i32.const 42)
+    )
+    (global.set $global$1
+     (i64.const 7)
+    )
+    (local.get $0)
+   )
+  )
+  (tuple.make
+   (global.get $global$2)
+   (global.get $global$3)
+  )
+ )
+ (func $7
+  (local $0 (i32 i64))
+  (local $1 i32)
+  (local.set $0
+   (call $fimport$0)
+  )
+  (drop
+   (block (result i32)
+    (local.set $1
+     (tuple.extract 0
+      (local.get $0)
+     )
+    )
+    (drop
+     (tuple.extract 1
+      (local.get $0)
+     )
+    )
+    (local.get $1)
+   )
+  )
+ )
+ (func $8
+  (local $0 i32)
+  (drop
+   (block (result i32)
+    (local.set $0
+     (i32.const 42)
+    )
+    (drop
+     (i64.const 42)
+    )
+    (local.get $0)
+   )
+  )
+ )
+ (func $9
+  (local $0 (i32 i64))
+  (local $1 i32)
+  (local.set $0
+   (block $label$1 (result i32 i64)
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $1
+     (tuple.extract 0
+      (local.get $0)
+     )
+    )
+    (drop
+     (tuple.extract 1
+      (local.get $0)
+     )
+    )
+    (local.get $1)
+   )
+  )
+ )
+ (func $10 (result i32 i64)
+  (return
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+   )
+  )
+ )
+ (func $11 (result i32 i64)
+  (return
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+   )
+  )
+ )
+ (func $12 (result i32 i64)
+  (local $0 (i32 i64))
+  (local.set $0
+   (block $label$1 (result i32 i64)
+    (br $label$1
+     (tuple.make
+      (i32.const 42)
+      (i64.const 42)
+     )
+    )
+   )
+  )
+  (tuple.make
+   (tuple.extract 0
+    (local.get $0)
+   )
+   (tuple.extract 1
+    (local.get $0)
+   )
+  )
+ )
+ (func $13 (result i32 i64)
+  (local $0 (i32 i64))
+  (local $1 (i32 i64))
+  (local.set $1
+   (block $label$1 (result i32 i64)
+    (local.set $0
+     (br_if $label$1
+      (tuple.make
+       (i32.const 42)
+       (i64.const 42)
+      )
+      (i32.const 1)
+     )
+    )
+    (tuple.make
+     (tuple.extract 0
+      (local.get $0)
+     )
+     (tuple.extract 1
+      (local.get $0)
+     )
+    )
+   )
+  )
+  (tuple.make
+   (tuple.extract 0
+    (local.get $1)
+   )
+   (tuple.extract 1
+    (local.get $1)
+   )
+  )
+ )
+ (func $14 (result i32 i64 externref)
+  (local $0 (i32 i64 externref))
+  (local.set $0
+   (if (result i32 i64 externref)
+    (i32.const 1)
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+     (ref.null extern)
+    )
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+     (ref.null extern)
+    )
+   )
+  )
+  (tuple.make
+   (tuple.extract 0
+    (local.get $0)
+   )
+   (tuple.extract 1
+    (local.get $0)
+   )
+   (tuple.extract 2
+    (local.get $0)
+   )
+  )
+ )
+ (func $15 (result i32 i64)
+  (local $0 (i32 i64))
+  (local.set $0
+   (loop $label$1 (result i32 i64)
+    (tuple.make
+     (i32.const 42)
+     (i64.const 42)
+    )
+   )
+  )
+  (tuple.make
+   (tuple.extract 0
+    (local.get $0)
+   )
+   (tuple.extract 1
+    (local.get $0)
+   )
+  )
+ )
+ (func $16 (result i32 i64)
+  (local $0 (i32 i64))
+  (local $1 (i32 i64))
+  (local.set $1
+   (block $label$1 (result i32 i64)
+    (local.set $0
+     (block $label$2 (result i32 i64)
+      (br_table $label$1 $label$2
+       (tuple.make
+        (i32.const 42)
+        (i64.const 42)
+       )
+       (i32.const 0)
+      )
+     )
+    )
+    (tuple.make
+     (tuple.extract 0
+      (local.get $0)
+     )
+     (tuple.extract 1
+      (local.get $0)
+     )
+    )
+   )
+  )
+  (tuple.make
+   (tuple.extract 0
+    (local.get $1)
+   )
+   (tuple.extract 1
+    (local.get $1)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/mutable-global.wasm b/binaryen/test/mutable-global.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/mutable-global.wasm differ
diff --git a/binaryen/test/mutable-global.wasm.fromBinary b/binaryen/test/mutable-global.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/mutable-global.wasm.fromBinary
@@ -0,0 +1,13 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "global-mut" (global $gimport$0 (mut i32)))
+ (func $0
+  (global.set $gimport$0
+   (i32.add
+    (global.get $gimport$0)
+    (i32.const 1)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/mutable-global.wast b/binaryen/test/mutable-global.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/mutable-global.wast
@@ -0,0 +1,12 @@
+(module
+  (type $0 (func))
+  (import "env" "global-mut" (global $global-mut (mut i32)))
+  (func $foo (type $0)
+    (global.set $global-mut
+      (i32.add
+        (global.get $global-mut)
+        (i32.const 1)
+      )
+    )
+  )
+)
diff --git a/binaryen/test/mutable-global.wast.from-wast b/binaryen/test/mutable-global.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/mutable-global.wast.from-wast
@@ -0,0 +1,12 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "global-mut" (global $global-mut (mut i32)))
+ (func $foo
+  (global.set $global-mut
+   (i32.add
+    (global.get $global-mut)
+    (i32.const 1)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/mutable-global.wast.fromBinary b/binaryen/test/mutable-global.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/mutable-global.wast.fromBinary
@@ -0,0 +1,13 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "global-mut" (global $global-mut (mut i32)))
+ (func $foo
+  (global.set $global-mut
+   (i32.add
+    (global.get $global-mut)
+    (i32.const 1)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/mutable-global.wast.fromBinary.noDebugInfo b/binaryen/test/mutable-global.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/mutable-global.wast.fromBinary.noDebugInfo
@@ -0,0 +1,13 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "global-mut" (global $gimport$0 (mut i32)))
+ (func $0
+  (global.set $gimport$0
+   (i32.add
+    (global.get $gimport$0)
+    (i32.const 1)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/newsyntax.wast b/binaryen/test/newsyntax.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/newsyntax.wast
@@ -0,0 +1,10 @@
+(module
+  (import "env" "table" (table 9 9 funcref))
+  (func "call_indirect"
+    (drop
+      (call_indirect (param i32) (param f64) (result i32) (i32.const 10) (f64.const 20) (i32.const 30))
+    )
+    (call_indirect (i32.const 1))
+  )
+)
+
diff --git a/binaryen/test/newsyntax.wast.from-wast b/binaryen/test/newsyntax.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/newsyntax.wast.from-wast
@@ -0,0 +1,18 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_f64_=>_i32 (func (param i32 f64) (result i32)))
+ (import "env" "table" (table $timport$0 9 9 funcref))
+ (export "call_indirect" (func $0))
+ (func $0
+  (drop
+   (call_indirect (type $i32_f64_=>_i32)
+    (i32.const 10)
+    (f64.const 20)
+    (i32.const 30)
+   )
+  )
+  (call_indirect (type $none_=>_none)
+   (i32.const 1)
+  )
+ )
+)
diff --git a/binaryen/test/newsyntax.wast.fromBinary b/binaryen/test/newsyntax.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/newsyntax.wast.fromBinary
@@ -0,0 +1,19 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_f64_=>_i32 (func (param i32 f64) (result i32)))
+ (import "env" "table" (table $timport$0 9 9 funcref))
+ (export "call_indirect" (func $0))
+ (func $0
+  (drop
+   (call_indirect (type $i32_f64_=>_i32)
+    (i32.const 10)
+    (f64.const 20)
+    (i32.const 30)
+   )
+  )
+  (call_indirect (type $none_=>_none)
+   (i32.const 1)
+  )
+ )
+)
+
diff --git a/binaryen/test/newsyntax.wast.fromBinary.noDebugInfo b/binaryen/test/newsyntax.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/newsyntax.wast.fromBinary.noDebugInfo
@@ -0,0 +1,19 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_f64_=>_i32 (func (param i32 f64) (result i32)))
+ (import "env" "table" (table $timport$0 9 9 funcref))
+ (export "call_indirect" (func $0))
+ (func $0
+  (drop
+   (call_indirect (type $i32_f64_=>_i32)
+    (i32.const 10)
+    (f64.const 20)
+    (i32.const 30)
+   )
+  )
+  (call_indirect (type $none_=>_none)
+   (i32.const 1)
+  )
+ )
+)
+
diff --git a/binaryen/test/noffi_f32.asm.js b/binaryen/test/noffi_f32.asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/noffi_f32.asm.js
@@ -0,0 +1,21 @@
+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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/noffi_i64.asm.js
@@ -0,0 +1,21 @@
+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/nonspec-bulk-memory.wast b/binaryen/test/nonspec-bulk-memory.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/nonspec-bulk-memory.wast
@@ -0,0 +1,29 @@
+(module
+ (memory 1024 1024
+  (segment 0 "hello, world")
+ )
+ (func $memory.init
+  (memory.init 0
+   (i32.const 512)
+   (i32.const 0)
+   (i32.const 12)
+  )
+ )
+ (func $data.drop
+  (data.drop 0)
+ )
+ (func $memory.copy
+  (memory.copy
+   (i32.const 512)
+   (i32.const 0)
+   (i32.const 12)
+  )
+ )
+ (func $memory.fill
+  (memory.fill
+   (i32.const 0)
+   (i32.const 42)
+   (i32.const 1024)
+  )
+ )
+)
diff --git a/binaryen/test/nonspec-bulk-memory.wast.from-wast b/binaryen/test/nonspec-bulk-memory.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/nonspec-bulk-memory.wast.from-wast
@@ -0,0 +1,29 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 1024 1024)
+ (data (i32.const 0) "hello, world")
+ (func $memory.init
+  (memory.init 0
+   (i32.const 512)
+   (i32.const 0)
+   (i32.const 12)
+  )
+ )
+ (func $data.drop
+  (data.drop 0)
+ )
+ (func $memory.copy
+  (memory.copy
+   (i32.const 512)
+   (i32.const 0)
+   (i32.const 12)
+  )
+ )
+ (func $memory.fill
+  (memory.fill
+   (i32.const 0)
+   (i32.const 42)
+   (i32.const 1024)
+  )
+ )
+)
diff --git a/binaryen/test/nonspec-bulk-memory.wast.fromBinary b/binaryen/test/nonspec-bulk-memory.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/nonspec-bulk-memory.wast.fromBinary
@@ -0,0 +1,30 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 1024 1024)
+ (data (i32.const 0) "hello, world")
+ (func $memory.init
+  (memory.init 0
+   (i32.const 512)
+   (i32.const 0)
+   (i32.const 12)
+  )
+ )
+ (func $data.drop
+  (data.drop 0)
+ )
+ (func $memory.copy
+  (memory.copy
+   (i32.const 512)
+   (i32.const 0)
+   (i32.const 12)
+  )
+ )
+ (func $memory.fill
+  (memory.fill
+   (i32.const 0)
+   (i32.const 42)
+   (i32.const 1024)
+  )
+ )
+)
+
diff --git a/binaryen/test/nonspec-bulk-memory.wast.fromBinary.noDebugInfo b/binaryen/test/nonspec-bulk-memory.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/nonspec-bulk-memory.wast.fromBinary.noDebugInfo
@@ -0,0 +1,30 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 1024 1024)
+ (data (i32.const 0) "hello, world")
+ (func $0
+  (memory.init 0
+   (i32.const 512)
+   (i32.const 0)
+   (i32.const 12)
+  )
+ )
+ (func $1
+  (data.drop 0)
+ )
+ (func $2
+  (memory.copy
+   (i32.const 512)
+   (i32.const 0)
+   (i32.const 12)
+  )
+ )
+ (func $3
+  (memory.fill
+   (i32.const 0)
+   (i32.const 42)
+   (i32.const 1024)
+  )
+ )
+)
+
diff --git a/binaryen/test/passes/O.bin.txt b/binaryen/test/passes/O.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O.bin.txt
@@ -0,0 +1,108 @@
+(module
+ (type $i64_=>_i64 (func (param i64) (result i64)))
+ (export "fac-rec" (func $0))
+ (export "fac-rec-named" (func $1))
+ (export "fac-iter" (func $2))
+ (export "fac-iter-named" (func $3))
+ (export "fac-opt" (func $4))
+ (func $0 (; has Stack IR ;) (param $0 i64) (result i64)
+  (if (result i64)
+   (i64.eqz
+    (local.get $0)
+   )
+   (i64.const 1)
+   (i64.mul
+    (call $0
+     (i64.sub
+      (local.get $0)
+      (i64.const 1)
+     )
+    )
+    (local.get $0)
+   )
+  )
+ )
+ (func $1 (; has Stack IR ;) (param $0 i64) (result i64)
+  (if (result i64)
+   (i64.eqz
+    (local.get $0)
+   )
+   (i64.const 1)
+   (i64.mul
+    (call $1
+     (i64.sub
+      (local.get $0)
+      (i64.const 1)
+     )
+    )
+    (local.get $0)
+   )
+  )
+ )
+ (func $2 (; has Stack IR ;) (param $0 i64) (result i64)
+  (unreachable)
+ )
+ (func $3 (; has Stack IR ;) (param $0 i64) (result i64)
+  (local $1 i64)
+  (local.set $1
+   (i64.const 1)
+  )
+  (loop $label$3
+   (if
+    (i32.eqz
+     (i64.eqz
+      (local.get $0)
+     )
+    )
+    (block
+     (local.set $1
+      (i64.mul
+       (local.get $0)
+       (local.get $1)
+      )
+     )
+     (local.set $0
+      (i64.sub
+       (local.get $0)
+       (i64.const 1)
+      )
+     )
+     (br $label$3)
+    )
+   )
+  )
+  (local.get $1)
+ )
+ (func $4 (; has Stack IR ;) (param $0 i64) (result i64)
+  (local $1 i64)
+  (local.set $1
+   (i64.const 1)
+  )
+  (if
+   (i64.ge_s
+    (local.get $0)
+    (i64.const 2)
+   )
+   (loop $label$3
+    (local.set $1
+     (i64.mul
+      (local.get $0)
+      (local.get $1)
+     )
+    )
+    (br_if $label$3
+     (i64.gt_s
+      (local.tee $0
+       (i64.add
+        (local.get $0)
+        (i64.const -1)
+       )
+      )
+      (i64.const 1)
+     )
+    )
+   )
+  )
+  (local.get $1)
+ )
+)
diff --git a/binaryen/test/passes/O.txt b/binaryen/test/passes/O.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O.txt
@@ -0,0 +1,56 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i64_=>_none (func (param i64)))
+ (type $none_=>_i32 (func (result i32)))
+ (export "ret" (func $ret))
+ (export "waka" (func $if-0-unreachable-to-none))
+ (export "many-selects" (func $many-selects))
+ (export "end-if-else" (func $end-if-else))
+ (export "end-if-else-call" (func $end-if-else-call))
+ (func $ret (; has Stack IR ;) (result i32)
+  (drop
+   (call $ret)
+  )
+  (if
+   (call $ret)
+   (return
+    (i32.const 1)
+   )
+  )
+  (i32.const 999)
+ )
+ (func $if-0-unreachable-to-none (; has Stack IR ;) (param $0 i64)
+  (unreachable)
+ )
+ (func $many-selects (; has Stack IR ;) (param $0 i32) (result i32)
+  (select
+   (i32.const -1073741824)
+   (select
+    (i32.const 1073741823)
+    (local.get $0)
+    (i32.gt_s
+     (local.get $0)
+     (i32.const 1073741823)
+    )
+   )
+   (i32.lt_s
+    (local.get $0)
+    (i32.const -1073741824)
+   )
+  )
+ )
+ (func $end-if-else (; has Stack IR ;) (param $0 i32) (result i32)
+  (select
+   (i32.const 1)
+   (local.get $0)
+   (local.get $0)
+  )
+ )
+ (func $end-if-else-call (; has Stack IR ;) (param $0 i32) (result i32)
+  (if (result i32)
+   (local.get $0)
+   (call $ret)
+   (local.get $0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/O.wasm b/binaryen/test/passes/O.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/O.wasm differ
diff --git a/binaryen/test/passes/O.wast b/binaryen/test/passes/O.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O.wast
@@ -0,0 +1,67 @@
+(module
+  (func $ret (export "ret") (result i32)
+    (block $out (result i32)
+      (drop (call $ret))
+      (if (call $ret)
+        (return
+          (return
+            (i32.const 1)
+          )
+        )
+      )
+      (drop (br_if $out (i32.const 999) (i32.const 1)))
+      (unreachable)
+    )
+  )
+  (func $if-0-unreachable-to-none (export "waka") (param $var$0 i64)
+   (local $var$1 i64)
+   (local $var$2 i64)
+   (block $label$1
+    (if
+     (i32.const 0)
+     (br $label$1)
+     (unreachable)
+    )
+   )
+  )
+  (func $many-selects (export "many-selects") (param $0 i32) (result i32)
+   (if
+    (i32.lt_s
+     (local.get $0)
+     (i32.const -1073741824)
+    )
+    (local.set $0
+     (i32.const -1073741824)
+    )
+    (if
+     (i32.gt_s
+      (local.get $0)
+      (i32.const 1073741823)
+     )
+     (local.set $0
+      (i32.const 1073741823)
+     )
+    )
+   )
+   (local.get $0)
+  )
+  (func $end-if-else (export "end-if-else") (param $x i32) (result i32)
+    (if
+      (local.get $x)
+      (local.set $x
+        (i32.const 1)
+      )
+    )
+    (local.get $x)
+  )
+  (func $end-if-else-call (export "end-if-else-call") (param $x i32) (result i32)
+    (if
+      (local.get $x)
+      (local.set $x
+        (call $ret)
+      )
+    )
+    (local.get $x)
+  )
+)
+
diff --git a/binaryen/test/passes/O1.txt b/binaryen/test/passes/O1.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O1.txt
@@ -0,0 +1,13 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 1 1)
+ (export "foo" (func $0))
+ (func $0 (result i32)
+  (drop
+   (i32.const 0)
+  )
+  (i32.load align=1
+   (i32.const 4)
+  )
+ )
+)
diff --git a/binaryen/test/passes/O1.wast b/binaryen/test/passes/O1.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O1.wast
@@ -0,0 +1,25 @@
+(module
+ (memory $0 1 1)
+ (global $global$0 (mut i32) (i32.const 10))
+ (func "foo" (result i32)
+  (i32.load offset=4 align=1
+   (i32.and
+    (block $label$1 (result i32)
+     (global.set $global$0
+      (i32.const 0)
+     )
+     (i32.const -64)
+    )
+    (i32.const 15)
+   )
+  )
+ )
+ (func $signed-overflow (param $0 f32) (result i32)
+  (i32.sub
+   (i32.const 268435456)
+   (i32.const -2147483648)
+  )
+ )
+)
+
+
diff --git a/binaryen/test/passes/O1_print-stack-ir.txt b/binaryen/test/passes/O1_print-stack-ir.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O1_print-stack-ir.txt
@@ -0,0 +1,52 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "stacky-help" (func $stacky-help))
+ (func $stacky-help (param $0 i32) (result i32)
+  (i32.add
+   (call $stacky-help
+    (i32.const 0)
+   )
+   (block (result i32)
+    (local.set $0
+     (call $stacky-help
+      (i32.const 1)
+     )
+    )
+    (drop
+     (call $stacky-help
+      (i32.const 2)
+     )
+    )
+    (i32.eqz
+     (local.get $0)
+    )
+   )
+  )
+ )
+)
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "stacky-help" (func $stacky-help))
+ (func $stacky-help (param $0 i32) (result i32)
+  (i32.add
+   (call $stacky-help
+    (i32.const 0)
+   )
+   (block (result i32)
+    (local.set $0
+     (call $stacky-help
+      (i32.const 1)
+     )
+    )
+    (drop
+     (call $stacky-help
+      (i32.const 2)
+     )
+    )
+    (i32.eqz
+     (local.get $0)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/O1_print-stack-ir.wast b/binaryen/test/passes/O1_print-stack-ir.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O1_print-stack-ir.wast
@@ -0,0 +1,16 @@
+(module
+ (export "stacky-help" (func $stacky-help))
+ (func $stacky-help (param $x i32) (result i32)
+  (local $temp i32)
+  (i32.add
+   (call $stacky-help (i32.const 0))
+   (i32.eqz
+    (block (result i32) ;; after we use the stack instead of the local, we can remove this block
+     (local.set $temp (call $stacky-help (i32.const 1)))
+     (drop (call $stacky-help (i32.const 2)))
+     (local.get $temp)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/O2_precompute-propagate_print-stack-ir.txt b/binaryen/test/passes/O2_precompute-propagate_print-stack-ir.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O2_precompute-propagate_print-stack-ir.txt
@@ -0,0 +1,24 @@
+(module
+ (type $i32_i32_i32_i64_=>_i64 (func (param i32 i32 i32 i64) (result i64)))
+ (export "func" (func $0))
+ (func $0 (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i64) (result i64)
+  (local $4 i32)
+  (local.set $3
+   (i64.const 2147483647)
+  )
+  (nop)
+  (i64.const 2147483647)
+ )
+)
+(module
+ (type $i32_i32_i32_i64_=>_i64 (func (param i32 i32 i32 i64) (result i64)))
+ (export "func" (func $0))
+ (func $0 (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i64) (result i64)
+  (local $4 i32)
+  (local.set $3
+   (i64.const 2147483647)
+  )
+  (nop)
+  (i64.const 2147483647)
+ )
+)
diff --git a/binaryen/test/passes/O2_precompute-propagate_print-stack-ir.wast b/binaryen/test/passes/O2_precompute-propagate_print-stack-ir.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O2_precompute-propagate_print-stack-ir.wast
@@ -0,0 +1,18 @@
+(module
+ (func "func" (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (param $var$3 i64) (result i64)
+  (local $var$4 i32)
+  (block $label$1
+   (local.set $var$3
+    (i64.const 2147483647)
+   )
+   (br_if $label$1
+    (local.get $var$4) ;; precompute-propagate will optimize this into 0, then the br_if is nopped
+                       ;; in place. if stack ir is not regenerated, that means we have the get
+                       ;; on the stack from before, and the br_if is now a nop, which means no one
+                       ;; pops the get
+   )
+  )
+  (local.get $var$3)
+ )
+)
+
diff --git a/binaryen/test/passes/O2_print-stack-ir.txt b/binaryen/test/passes/O2_print-stack-ir.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O2_print-stack-ir.txt
@@ -0,0 +1,43 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "stacky-help" (func $stacky-help))
+ (func $stacky-help (param $0 i32) (result i32)
+  i32.const 0
+  call $stacky-help
+  i32.const 1
+  call $stacky-help
+  local.set $0
+  i32.const 2
+  call $stacky-help
+  drop
+  local.get $0
+  i32.eqz
+  i32.add
+ )
+)
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "stacky-help" (func $stacky-help))
+ (func $stacky-help (; has Stack IR ;) (param $0 i32) (result i32)
+  (i32.add
+   (call $stacky-help
+    (i32.const 0)
+   )
+   (block (result i32)
+    (local.set $0
+     (call $stacky-help
+      (i32.const 1)
+     )
+    )
+    (drop
+     (call $stacky-help
+      (i32.const 2)
+     )
+    )
+    (i32.eqz
+     (local.get $0)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/O2_print-stack-ir.wast b/binaryen/test/passes/O2_print-stack-ir.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O2_print-stack-ir.wast
@@ -0,0 +1,16 @@
+(module
+ (export "stacky-help" (func $stacky-help))
+ (func $stacky-help (param $x i32) (result i32)
+  (local $temp i32)
+  (i32.add
+   (call $stacky-help (i32.const 0))
+   (i32.eqz
+    (block (result i32) ;; after we use the stack instead of the local, we can remove this block
+     (local.set $temp (call $stacky-help (i32.const 1)))
+     (drop (call $stacky-help (i32.const 2)))
+     (local.get $temp)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/O3_inline-functions-with-loops_flexible-inline-max-function-size=30.txt b/binaryen/test/passes/O3_inline-functions-with-loops_flexible-inline-max-function-size=30.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O3_inline-functions-with-loops_flexible-inline-max-function-size=30.txt
@@ -0,0 +1,95 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $memory 0)
+ (export "fib" (func $fib))
+ (export "looped" (func $looped))
+ (export "t0" (func $looped))
+ (export "t1" (func $t1))
+ (export "t2" (func $t2))
+ (export "t3" (func $t3))
+ (export "memory" (memory $memory))
+ (func $fib (; has Stack IR ;) (param $0 i32) (result i32)
+  (if
+   (i32.le_s
+    (local.get $0)
+    (i32.const 2)
+   )
+   (return
+    (local.get $0)
+   )
+  )
+  (i32.add
+   (call $fib
+    (i32.sub
+     (local.get $0)
+     (i32.const 1)
+    )
+   )
+   (call $fib
+    (i32.sub
+     (local.get $0)
+     (i32.const 2)
+    )
+   )
+  )
+ )
+ (func $looped (; has Stack IR ;) (param $0 i32) (result i32)
+  (loop $L0
+   (if
+    (i32.ge_s
+     (local.get $0)
+     (i32.const 0)
+    )
+    (block
+     (local.set $0
+      (i32.sub
+       (local.get $0)
+       (i32.const 1)
+      )
+     )
+     (br $L0)
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $t1 (; has Stack IR ;) (param $0 i32) (result i32)
+  (local.set $0
+   (i32.add
+    (local.get $0)
+    (i32.const 1)
+   )
+  )
+  (loop $L0
+   (if
+    (i32.ge_s
+     (local.get $0)
+     (i32.const 0)
+    )
+    (block
+     (local.set $0
+      (i32.sub
+       (local.get $0)
+       (i32.const 1)
+      )
+     )
+     (br $L0)
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $t2 (; has Stack IR ;) (param $0 i32) (result i32)
+  (call $fib
+   (local.get $0)
+  )
+ )
+ (func $t3 (; has Stack IR ;) (param $0 i32) (result i32)
+  (call $fib
+   (i32.add
+    (local.get $0)
+    (i32.const 1)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/O3_inline-functions-with-loops_flexible-inline-max-function-size=30.wast b/binaryen/test/passes/O3_inline-functions-with-loops_flexible-inline-max-function-size=30.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O3_inline-functions-with-loops_flexible-inline-max-function-size=30.wast
@@ -0,0 +1,80 @@
+(module
+  (type $t0 (func (param i32) (result i32)))
+  (func $fib (export "fib") (type $t0) (param $p0 i32) (result i32)
+    (if $I0
+      (i32.le_s
+        (local.get $p0)
+        (i32.const 2)
+      )
+      (then
+        (return
+          (local.get $p0)
+        )
+      )
+    )
+    (i32.add
+      (call $fib
+        (i32.sub
+          (local.get $p0)
+          (i32.const 1)
+        )
+      )
+      (call $fib
+        (i32.sub
+          (local.get $p0)
+          (i32.const 2)
+        )
+      )
+    )
+  )
+  (func $looped (export "looped") (type $t0) (param $p0 i32) (result i32)
+    (loop $L0
+      (if $I1
+        (i32.ge_s
+          (local.get $p0)
+          (i32.const 0)
+        )
+        (then
+          (local.set $p0
+            (i32.sub
+              (local.get $p0)
+              (i32.const 1)
+            )
+          )
+          (br $L0)
+        )
+      )
+    )
+    (local.get $p0)
+  )
+
+  (func $t0 (export "t0") (type $t0) (param $p0 i32) (result i32)
+    (call $looped
+      (local.get $p0)
+    )
+  )
+
+  (func $t1 (export "t1") (type $t0) (param $p0 i32) (result i32)
+    (call $looped
+      (i32.add
+        (local.get $p0)
+        (i32.const 1)
+      )
+    )
+  )
+  (func $t2 (export "t2") (type $t0) (param $p0 i32) (result i32)
+    (call $fib
+      (local.get $p0)
+    )
+  )
+
+  (func $t3 (export "t3") (type $t0) (param $p0 i32) (result i32)
+    (call $fib
+      (i32.add
+        (local.get $p0)
+        (i32.const 1)
+      )
+    )
+  )
+  (memory $memory (export "memory") 0)
+)
diff --git a/binaryen/test/passes/O3_inlining.txt b/binaryen/test/passes/O3_inlining.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O3_inlining.txt
@@ -0,0 +1,27 @@
+(module
+ (type $i32_=>_none (func (param i32)))
+ (memory $0 1 1)
+ (global $global$1 (mut i32) (i32.const 100))
+ (export "func_217" (func $1))
+ (func $1 (param $0 i32)
+  (if
+   (global.get $global$1)
+   (unreachable)
+  )
+  (global.set $global$1
+   (i32.const 0)
+  )
+  (if
+   (i32.eqz
+    (if (result i32)
+     (i32.load16_u
+      (i32.const 3)
+     )
+     (i32.const 1)
+     (i32.const 0)
+    )
+   )
+   (unreachable)
+  )
+ )
+)
diff --git a/binaryen/test/passes/O3_inlining.wast b/binaryen/test/passes/O3_inlining.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O3_inlining.wast
@@ -0,0 +1,44 @@
+(module
+ (global $global$0 (mut f64) (f64.const -32768))
+ (global $global$1 (mut i32) (i32.const 100))
+ (memory $0 1 1)
+ (export "func_217" (func $1))
+ (func $0
+  (if
+   (global.get $global$1)
+   (unreachable)
+  )
+  (global.set $global$1
+   (i32.const 0)
+  )
+  (block $label$2
+   (global.set $global$0
+    (block $label$3 (result f64)
+     (br_if $label$2
+      (if (result i32)
+       (i32.load16_u offset=3
+        (i32.const 0)
+       )
+       (i32.const 1)
+       (i32.const 0)
+      )
+     )
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $1 (param $var$0 i32)
+  (drop
+   (call $2
+    (f32.const 1)
+    (i32.const 1)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $2 (param $var$0 f32) (param $var$1 i32) (param $var$2 i32) (result i32)
+  (call $0)
+  (i32.const 0)
+ )
+)
diff --git a/binaryen/test/passes/O3_low-memory-unused_metrics.txt b/binaryen/test/passes/O3_low-memory-unused_metrics.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O3_low-memory-unused_metrics.txt
@@ -0,0 +1,3152 @@
+total
+ [events]       : 0       
+ [exports]      : 1       
+ [funcs]        : 1       
+ [globals]      : 0       
+ [imports]      : 10      
+ [memory-data]  : 0       
+ [table-data]   : 0       
+ [total]        : 1964    
+ [vars]         : 9       
+ binary         : 240     
+ block          : 68      
+ break          : 90      
+ call           : 22      
+ call_indirect  : 1       
+ const          : 175     
+ drop           : 8       
+ if             : 27      
+ load           : 313     
+ local.get      : 633     
+ local.set      : 181     
+ loop           : 3       
+ return         : 3       
+ select         : 11      
+ store          : 160     
+ unary          : 29      
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32)))
+ (import "env" "memory" (memory $108 4096 4096))
+ (import "env" "table" (table $timport$109 10 funcref))
+ (import "env" "crc32" (func $fimport$14 (param i32 i32 i32) (result i32)))
+ (import "env" "adler32" (func $fimport$15 (param i32 i32 i32) (result i32)))
+ (import "env" "deflate_huff" (func $fimport$20 (param i32 i32) (result i32)))
+ (import "env" "deflate_rle" (func $fimport$21 (param i32 i32) (result i32)))
+ (import "env" "_tr_stored_block" (func $fimport$29 (param i32 i32 i32 i32)))
+ (import "env" "_tr_align" (func $fimport$30 (param i32)))
+ (import "env" "memset" (func $fimport$97 (param i32 i32 i32) (result i32)))
+ (import "env" "memcpy" (func $fimport$98 (param i32 i32 i32) (result i32)))
+ (export "deflate" (func $0))
+ (func $0 (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local.set $3
+   (i32.const -2)
+  )
+  (block $folding-inner1
+   (block $folding-inner0
+    (block $label$1
+     (br_if $label$1
+      (i32.eqz
+       (local.get $0)
+      )
+     )
+     (br_if $label$1
+      (i32.gt_u
+       (local.get $1)
+       (i32.const 5)
+      )
+     )
+     (br_if $label$1
+      (i32.eqz
+       (local.tee $2
+        (i32.load offset=28
+         (local.get $0)
+        )
+       )
+      )
+     )
+     (block $label$2
+      (block $label$3
+       (br_if $label$3
+        (i32.eqz
+         (i32.load offset=12
+          (local.get $0)
+         )
+        )
+       )
+       (if
+        (i32.eqz
+         (i32.load
+          (local.get $0)
+         )
+        )
+        (br_if $label$3
+         (i32.load offset=4
+          (local.get $0)
+         )
+        )
+       )
+       (local.set $3
+        (i32.load offset=4
+         (local.get $2)
+        )
+       )
+       (br_if $label$2
+        (i32.eq
+         (local.get $1)
+         (i32.const 4)
+        )
+       )
+       (br_if $label$2
+        (i32.ne
+         (local.get $3)
+         (i32.const 666)
+        )
+       )
+      )
+      (i32.store offset=24
+       (local.get $0)
+       (i32.load
+        (i32.const 16992)
+       )
+      )
+      (return
+       (i32.const -2)
+      )
+     )
+     (if
+      (i32.eqz
+       (i32.load offset=16
+        (local.get $0)
+       )
+      )
+      (br $folding-inner0)
+     )
+     (i32.store
+      (local.get $2)
+      (local.get $0)
+     )
+     (local.set $7
+      (i32.load offset=40
+       (local.get $2)
+      )
+     )
+     (i32.store offset=40
+      (local.get $2)
+      (local.get $1)
+     )
+     (block $label$6
+      (block $label$7
+       (block $label$8
+        (block $label$9
+         (block $label$10
+          (block $label$11
+           (block $label$12
+            (block $label$13
+             (block $label$14
+              (block $label$15
+               (block $label$16
+                (if
+                 (i32.eq
+                  (local.get $3)
+                  (i32.const 42)
+                 )
+                 (block
+                  (if
+                   (i32.eq
+                    (i32.load offset=24
+                     (local.get $2)
+                    )
+                    (i32.const 2)
+                   )
+                   (block
+                    (i32.store offset=48
+                     (local.get $0)
+                     (call $fimport$14
+                      (i32.const 0)
+                      (i32.const 0)
+                      (i32.const 0)
+                     )
+                    )
+                    (i32.store offset=20
+                     (local.get $2)
+                     (i32.add
+                      (local.tee $3
+                       (i32.load offset=20
+                        (local.get $2)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                    )
+                    (i32.store8
+                     (i32.add
+                      (local.get $3)
+                      (i32.load offset=8
+                       (local.get $2)
+                      )
+                     )
+                     (i32.const 31)
+                    )
+                    (i32.store offset=20
+                     (local.get $2)
+                     (i32.add
+                      (local.tee $3
+                       (i32.load offset=20
+                        (local.get $2)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                    )
+                    (i32.store8
+                     (i32.add
+                      (local.get $3)
+                      (i32.load offset=8
+                       (local.get $2)
+                      )
+                     )
+                     (i32.const 139)
+                    )
+                    (i32.store offset=20
+                     (local.get $2)
+                     (i32.add
+                      (local.tee $3
+                       (i32.load offset=20
+                        (local.get $2)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                    )
+                    (i32.store8
+                     (i32.add
+                      (local.get $3)
+                      (i32.load offset=8
+                       (local.get $2)
+                      )
+                     )
+                     (i32.const 8)
+                    )
+                    (if
+                     (i32.eqz
+                      (local.tee $3
+                       (i32.load offset=28
+                        (local.get $2)
+                       )
+                      )
+                     )
+                     (block
+                      (i32.store offset=20
+                       (local.get $2)
+                       (i32.add
+                        (local.tee $3
+                         (i32.load offset=20
+                          (local.get $2)
+                         )
+                        )
+                        (i32.const 1)
+                       )
+                      )
+                      (i32.store8
+                       (i32.add
+                        (local.get $3)
+                        (i32.load offset=8
+                         (local.get $2)
+                        )
+                       )
+                       (i32.const 0)
+                      )
+                      (i32.store offset=20
+                       (local.get $2)
+                       (i32.add
+                        (local.tee $3
+                         (i32.load offset=20
+                          (local.get $2)
+                         )
+                        )
+                        (i32.const 1)
+                       )
+                      )
+                      (i32.store8
+                       (i32.add
+                        (local.get $3)
+                        (i32.load offset=8
+                         (local.get $2)
+                        )
+                       )
+                       (i32.const 0)
+                      )
+                      (i32.store offset=20
+                       (local.get $2)
+                       (i32.add
+                        (local.tee $3
+                         (i32.load offset=20
+                          (local.get $2)
+                         )
+                        )
+                        (i32.const 1)
+                       )
+                      )
+                      (i32.store8
+                       (i32.add
+                        (local.get $3)
+                        (i32.load offset=8
+                         (local.get $2)
+                        )
+                       )
+                       (i32.const 0)
+                      )
+                      (i32.store offset=20
+                       (local.get $2)
+                       (i32.add
+                        (local.tee $3
+                         (i32.load offset=20
+                          (local.get $2)
+                         )
+                        )
+                        (i32.const 1)
+                       )
+                      )
+                      (i32.store8
+                       (i32.add
+                        (local.get $3)
+                        (i32.load offset=8
+                         (local.get $2)
+                        )
+                       )
+                       (i32.const 0)
+                      )
+                      (i32.store offset=20
+                       (local.get $2)
+                       (i32.add
+                        (local.tee $3
+                         (i32.load offset=20
+                          (local.get $2)
+                         )
+                        )
+                        (i32.const 1)
+                       )
+                      )
+                      (i32.store8
+                       (i32.add
+                        (local.get $3)
+                        (i32.load offset=8
+                         (local.get $2)
+                        )
+                       )
+                       (i32.const 0)
+                      )
+                      (local.set $3
+                       (i32.const 2)
+                      )
+                      (if
+                       (i32.ne
+                        (local.tee $4
+                         (i32.load offset=132
+                          (local.get $2)
+                         )
+                        )
+                        (i32.const 9)
+                       )
+                       (local.set $3
+                        (select
+                         (i32.const 4)
+                         (i32.shl
+                          (i32.gt_s
+                           (i32.load offset=136
+                            (local.get $2)
+                           )
+                           (i32.const 1)
+                          )
+                          (i32.const 2)
+                         )
+                         (i32.lt_s
+                          (local.get $4)
+                          (i32.const 2)
+                         )
+                        )
+                       )
+                      )
+                      (i32.store offset=20
+                       (local.get $2)
+                       (i32.add
+                        (local.tee $4
+                         (i32.load offset=20
+                          (local.get $2)
+                         )
+                        )
+                        (i32.const 1)
+                       )
+                      )
+                      (i32.store8
+                       (i32.add
+                        (local.get $4)
+                        (i32.load offset=8
+                         (local.get $2)
+                        )
+                       )
+                       (local.get $3)
+                      )
+                      (i32.store offset=20
+                       (local.get $2)
+                       (i32.add
+                        (local.tee $3
+                         (i32.load offset=20
+                          (local.get $2)
+                         )
+                        )
+                        (i32.const 1)
+                       )
+                      )
+                      (i32.store8
+                       (i32.add
+                        (local.get $3)
+                        (i32.load offset=8
+                         (local.get $2)
+                        )
+                       )
+                       (i32.const 3)
+                      )
+                      (i32.store offset=4
+                       (local.get $2)
+                       (i32.const 113)
+                      )
+                      (br $label$6)
+                     )
+                    )
+                    (local.set $4
+                     (i32.load offset=36
+                      (local.get $3)
+                     )
+                    )
+                    (local.set $5
+                     (i32.load offset=28
+                      (local.get $3)
+                     )
+                    )
+                    (local.set $6
+                     (i32.load offset=16
+                      (local.get $3)
+                     )
+                    )
+                    (local.set $8
+                     (i32.load offset=44
+                      (local.get $3)
+                     )
+                    )
+                    (local.set $9
+                     (i32.load
+                      (local.get $3)
+                     )
+                    )
+                    (i32.store offset=20
+                     (local.get $2)
+                     (i32.add
+                      (local.tee $10
+                       (i32.load offset=20
+                        (local.get $2)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                    )
+                    (local.set $3
+                     (i32.const 2)
+                    )
+                    (i32.store8
+                     (i32.add
+                      (local.get $10)
+                      (i32.load offset=8
+                       (local.get $2)
+                      )
+                     )
+                     (i32.or
+                      (i32.or
+                       (i32.or
+                        (i32.or
+                         (i32.shl
+                          (i32.ne
+                           (local.get $8)
+                           (i32.const 0)
+                          )
+                          (i32.const 1)
+                         )
+                         (i32.ne
+                          (local.get $9)
+                          (i32.const 0)
+                         )
+                        )
+                        (i32.shl
+                         (i32.ne
+                          (local.get $6)
+                          (i32.const 0)
+                         )
+                         (i32.const 2)
+                        )
+                       )
+                       (i32.shl
+                        (i32.ne
+                         (local.get $5)
+                         (i32.const 0)
+                        )
+                        (i32.const 3)
+                       )
+                      )
+                      (i32.shl
+                       (i32.ne
+                        (local.get $4)
+                        (i32.const 0)
+                       )
+                       (i32.const 4)
+                      )
+                     )
+                    )
+                    (local.set $4
+                     (i32.load offset=4
+                      (i32.load offset=28
+                       (local.get $2)
+                      )
+                     )
+                    )
+                    (i32.store offset=20
+                     (local.get $2)
+                     (i32.add
+                      (local.tee $5
+                       (i32.load offset=20
+                        (local.get $2)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                    )
+                    (i32.store8
+                     (i32.add
+                      (local.get $5)
+                      (i32.load offset=8
+                       (local.get $2)
+                      )
+                     )
+                     (local.get $4)
+                    )
+                    (local.set $4
+                     (i32.load offset=4
+                      (i32.load offset=28
+                       (local.get $2)
+                      )
+                     )
+                    )
+                    (i32.store offset=20
+                     (local.get $2)
+                     (i32.add
+                      (local.tee $5
+                       (i32.load offset=20
+                        (local.get $2)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                    )
+                    (i32.store8
+                     (i32.add
+                      (local.get $5)
+                      (i32.load offset=8
+                       (local.get $2)
+                      )
+                     )
+                     (i32.shr_u
+                      (local.get $4)
+                      (i32.const 8)
+                     )
+                    )
+                    (local.set $4
+                     (i32.load16_u offset=6
+                      (i32.load offset=28
+                       (local.get $2)
+                      )
+                     )
+                    )
+                    (i32.store offset=20
+                     (local.get $2)
+                     (i32.add
+                      (local.tee $5
+                       (i32.load offset=20
+                        (local.get $2)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                    )
+                    (i32.store8
+                     (i32.add
+                      (local.get $5)
+                      (i32.load offset=8
+                       (local.get $2)
+                      )
+                     )
+                     (local.get $4)
+                    )
+                    (local.set $4
+                     (i32.load8_u offset=7
+                      (i32.load offset=28
+                       (local.get $2)
+                      )
+                     )
+                    )
+                    (i32.store offset=20
+                     (local.get $2)
+                     (i32.add
+                      (local.tee $5
+                       (i32.load offset=20
+                        (local.get $2)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                    )
+                    (i32.store8
+                     (i32.add
+                      (local.get $5)
+                      (i32.load offset=8
+                       (local.get $2)
+                      )
+                     )
+                     (local.get $4)
+                    )
+                    (if
+                     (i32.ne
+                      (local.tee $4
+                       (i32.load offset=132
+                        (local.get $2)
+                       )
+                      )
+                      (i32.const 9)
+                     )
+                     (local.set $3
+                      (select
+                       (i32.const 4)
+                       (i32.shl
+                        (i32.gt_s
+                         (i32.load offset=136
+                          (local.get $2)
+                         )
+                         (i32.const 1)
+                        )
+                        (i32.const 2)
+                       )
+                       (i32.lt_s
+                        (local.get $4)
+                        (i32.const 2)
+                       )
+                      )
+                     )
+                    )
+                    (i32.store offset=20
+                     (local.get $2)
+                     (i32.add
+                      (local.tee $4
+                       (i32.load offset=20
+                        (local.get $2)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                    )
+                    (i32.store8
+                     (i32.add
+                      (local.get $4)
+                      (i32.load offset=8
+                       (local.get $2)
+                      )
+                     )
+                     (local.get $3)
+                    )
+                    (local.set $3
+                     (i32.load offset=12
+                      (i32.load offset=28
+                       (local.get $2)
+                      )
+                     )
+                    )
+                    (i32.store offset=20
+                     (local.get $2)
+                     (i32.add
+                      (local.tee $4
+                       (i32.load offset=20
+                        (local.get $2)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                    )
+                    (i32.store8
+                     (i32.add
+                      (local.get $4)
+                      (i32.load offset=8
+                       (local.get $2)
+                      )
+                     )
+                     (local.get $3)
+                    )
+                    (if
+                     (i32.load offset=44
+                      (if (result i32)
+                       (i32.load offset=16
+                        (local.tee $3
+                         (i32.load offset=28
+                          (local.get $2)
+                         )
+                        )
+                       )
+                       (block (result i32)
+                        (local.set $3
+                         (i32.load offset=20
+                          (local.get $3)
+                         )
+                        )
+                        (i32.store offset=20
+                         (local.get $2)
+                         (i32.add
+                          (local.tee $4
+                           (i32.load offset=20
+                            (local.get $2)
+                           )
+                          )
+                          (i32.const 1)
+                         )
+                        )
+                        (i32.store8
+                         (i32.add
+                          (local.get $4)
+                          (i32.load offset=8
+                           (local.get $2)
+                          )
+                         )
+                         (local.get $3)
+                        )
+                        (local.set $3
+                         (i32.load offset=20
+                          (i32.load offset=28
+                           (local.get $2)
+                          )
+                         )
+                        )
+                        (i32.store offset=20
+                         (local.get $2)
+                         (i32.add
+                          (local.tee $4
+                           (i32.load offset=20
+                            (local.get $2)
+                           )
+                          )
+                          (i32.const 1)
+                         )
+                        )
+                        (i32.store8
+                         (i32.add
+                          (local.get $4)
+                          (i32.load offset=8
+                           (local.get $2)
+                          )
+                         )
+                         (i32.shr_u
+                          (local.get $3)
+                          (i32.const 8)
+                         )
+                        )
+                        (i32.load offset=28
+                         (local.get $2)
+                        )
+                       )
+                       (local.get $3)
+                      )
+                     )
+                     (i32.store offset=48
+                      (local.get $0)
+                      (call $fimport$14
+                       (i32.load offset=48
+                        (local.get $0)
+                       )
+                       (i32.load offset=8
+                        (local.get $2)
+                       )
+                       (i32.load offset=20
+                        (local.get $2)
+                       )
+                      )
+                     )
+                    )
+                    (i32.store offset=4
+                     (local.get $2)
+                     (i32.const 69)
+                    )
+                    (i32.store offset=32
+                     (local.get $2)
+                     (i32.const 0)
+                    )
+                    (br $label$16)
+                   )
+                  )
+                  (local.set $5
+                   (i32.add
+                    (i32.shl
+                     (i32.load offset=48
+                      (local.get $2)
+                     )
+                     (i32.const 12)
+                    )
+                    (i32.const -30720)
+                   )
+                  )
+                  (local.set $3
+                   (i32.const 0)
+                  )
+                  (block $label$24
+                   (br_if $label$24
+                    (i32.gt_s
+                     (i32.load offset=136
+                      (local.get $2)
+                     )
+                     (i32.const 1)
+                    )
+                   )
+                   (br_if $label$24
+                    (i32.lt_s
+                     (local.tee $4
+                      (i32.load offset=132
+                       (local.get $2)
+                      )
+                     )
+                     (i32.const 2)
+                    )
+                   )
+                   (local.set $3
+                    (i32.const 64)
+                   )
+                   (br_if $label$24
+                    (i32.lt_s
+                     (local.get $4)
+                     (i32.const 6)
+                    )
+                   )
+                   (local.set $3
+                    (select
+                     (i32.const 128)
+                     (i32.const 192)
+                     (i32.eq
+                      (local.get $4)
+                      (i32.const 6)
+                     )
+                    )
+                   )
+                  )
+                  (i32.store offset=4
+                   (local.get $2)
+                   (i32.const 113)
+                  )
+                  (i32.store offset=20
+                   (local.get $2)
+                   (i32.add
+                    (local.tee $4
+                     (i32.load offset=20
+                      (local.get $2)
+                     )
+                    )
+                    (i32.const 1)
+                   )
+                  )
+                  (i32.store8
+                   (i32.add
+                    (local.get $4)
+                    (i32.load offset=8
+                     (local.get $2)
+                    )
+                   )
+                   (i32.shr_u
+                    (local.tee $3
+                     (select
+                      (i32.or
+                       (local.tee $3
+                        (i32.or
+                         (local.get $3)
+                         (local.get $5)
+                        )
+                       )
+                       (i32.const 32)
+                      )
+                      (local.get $3)
+                      (i32.load offset=108
+                       (local.get $2)
+                      )
+                     )
+                    )
+                    (i32.const 8)
+                   )
+                  )
+                  (i32.store offset=20
+                   (local.get $2)
+                   (i32.add
+                    (local.tee $4
+                     (i32.load offset=20
+                      (local.get $2)
+                     )
+                    )
+                    (i32.const 1)
+                   )
+                  )
+                  (i32.store8
+                   (i32.add
+                    (local.get $4)
+                    (i32.load offset=8
+                     (local.get $2)
+                    )
+                   )
+                   (i32.xor
+                    (i32.or
+                     (i32.rem_u
+                      (local.get $3)
+                      (i32.const 31)
+                     )
+                     (local.get $3)
+                    )
+                    (i32.const 31)
+                   )
+                  )
+                  (if
+                   (i32.load offset=108
+                    (local.get $2)
+                   )
+                   (block
+                    (local.set $3
+                     (i32.load offset=48
+                      (local.get $0)
+                     )
+                    )
+                    (i32.store offset=20
+                     (local.get $2)
+                     (i32.add
+                      (local.tee $4
+                       (i32.load offset=20
+                        (local.get $2)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                    )
+                    (i32.store8
+                     (i32.add
+                      (local.get $4)
+                      (i32.load offset=8
+                       (local.get $2)
+                      )
+                     )
+                     (i32.shr_u
+                      (local.get $3)
+                      (i32.const 24)
+                     )
+                    )
+                    (i32.store offset=20
+                     (local.get $2)
+                     (i32.add
+                      (local.tee $4
+                       (i32.load offset=20
+                        (local.get $2)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                    )
+                    (i32.store8
+                     (i32.add
+                      (local.get $4)
+                      (i32.load offset=8
+                       (local.get $2)
+                      )
+                     )
+                     (i32.shr_u
+                      (local.get $3)
+                      (i32.const 16)
+                     )
+                    )
+                    (local.set $3
+                     (i32.load offset=48
+                      (local.get $0)
+                     )
+                    )
+                    (i32.store offset=20
+                     (local.get $2)
+                     (i32.add
+                      (local.tee $4
+                       (i32.load offset=20
+                        (local.get $2)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                    )
+                    (i32.store8
+                     (i32.add
+                      (local.get $4)
+                      (i32.load offset=8
+                       (local.get $2)
+                      )
+                     )
+                     (i32.shr_u
+                      (local.get $3)
+                      (i32.const 8)
+                     )
+                    )
+                    (i32.store offset=20
+                     (local.get $2)
+                     (i32.add
+                      (local.tee $4
+                       (i32.load offset=20
+                        (local.get $2)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                    )
+                    (i32.store8
+                     (i32.add
+                      (local.get $4)
+                      (i32.load offset=8
+                       (local.get $2)
+                      )
+                     )
+                     (local.get $3)
+                    )
+                   )
+                  )
+                  (i32.store offset=48
+                   (local.get $0)
+                   (call $fimport$15
+                    (i32.const 0)
+                    (i32.const 0)
+                    (i32.const 0)
+                   )
+                  )
+                  (local.set $3
+                   (i32.load offset=4
+                    (local.get $2)
+                   )
+                  )
+                 )
+                )
+                (br_if $label$15
+                 (i32.ne
+                  (local.get $3)
+                  (i32.const 69)
+                 )
+                )
+               )
+               (block $label$26
+                (if
+                 (i32.load offset=16
+                  (local.tee $5
+                   (i32.load offset=28
+                    (local.get $2)
+                   )
+                  )
+                 )
+                 (block
+                  (local.set $3
+                   (i32.load offset=20
+                    (local.get $2)
+                   )
+                  )
+                  (br_if $label$26
+                   (i32.ge_u
+                    (local.tee $6
+                     (i32.load offset=32
+                      (local.get $2)
+                     )
+                    )
+                    (i32.load16_u offset=20
+                     (local.get $5)
+                    )
+                   )
+                  )
+                  (local.set $4
+                   (local.get $3)
+                  )
+                  (loop $label$28
+                   (if
+                    (i32.eq
+                     (i32.load offset=12
+                      (local.get $2)
+                     )
+                     (local.get $3)
+                    )
+                    (block
+                     (block $label$30
+                      (br_if $label$30
+                       (i32.le_u
+                        (local.get $3)
+                        (local.get $4)
+                       )
+                      )
+                      (br_if $label$30
+                       (i32.eqz
+                        (i32.load offset=44
+                         (local.get $5)
+                        )
+                       )
+                      )
+                      (i32.store offset=48
+                       (local.get $0)
+                       (call $fimport$14
+                        (i32.load offset=48
+                         (local.get $0)
+                        )
+                        (i32.add
+                         (i32.load offset=8
+                          (local.get $2)
+                         )
+                         (local.get $4)
+                        )
+                        (i32.sub
+                         (local.get $3)
+                         (local.get $4)
+                        )
+                       )
+                      )
+                     )
+                     (block $label$31
+                      (br_if $label$31
+                       (i32.eqz
+                        (local.tee $3
+                         (select
+                          (local.tee $3
+                           (i32.load offset=16
+                            (local.get $0)
+                           )
+                          )
+                          (local.tee $5
+                           (i32.load offset=20
+                            (local.tee $4
+                             (i32.load offset=28
+                              (local.get $0)
+                             )
+                            )
+                           )
+                          )
+                          (i32.gt_u
+                           (local.get $5)
+                           (local.get $3)
+                          )
+                         )
+                        )
+                       )
+                      )
+                      (drop
+                       (call $fimport$98
+                        (i32.load offset=12
+                         (local.get $0)
+                        )
+                        (i32.load offset=16
+                         (local.get $4)
+                        )
+                        (local.get $3)
+                       )
+                      )
+                      (i32.store offset=12
+                       (local.get $0)
+                       (i32.add
+                        (i32.load offset=12
+                         (local.get $0)
+                        )
+                        (local.get $3)
+                       )
+                      )
+                      (i32.store offset=16
+                       (local.tee $4
+                        (i32.load offset=28
+                         (local.get $0)
+                        )
+                       )
+                       (i32.add
+                        (i32.load offset=16
+                         (local.get $4)
+                        )
+                        (local.get $3)
+                       )
+                      )
+                      (i32.store offset=20
+                       (local.get $0)
+                       (i32.add
+                        (i32.load offset=20
+                         (local.get $0)
+                        )
+                        (local.get $3)
+                       )
+                      )
+                      (i32.store offset=16
+                       (local.get $0)
+                       (i32.sub
+                        (i32.load offset=16
+                         (local.get $0)
+                        )
+                        (local.get $3)
+                       )
+                      )
+                      (i32.store offset=20
+                       (local.get $4)
+                       (local.tee $3
+                        (i32.sub
+                         (i32.load offset=20
+                          (local.get $4)
+                         )
+                         (local.get $3)
+                        )
+                       )
+                      )
+                      (br_if $label$31
+                       (local.get $3)
+                      )
+                      (i32.store offset=16
+                       (local.get $4)
+                       (i32.load offset=8
+                        (local.get $4)
+                       )
+                      )
+                     )
+                     (local.set $5
+                      (i32.load offset=28
+                       (local.get $2)
+                      )
+                     )
+                     (br_if $label$26
+                      (i32.eq
+                       (local.tee $3
+                        (i32.load offset=20
+                         (local.get $2)
+                        )
+                       )
+                       (i32.load offset=12
+                        (local.get $2)
+                       )
+                      )
+                     )
+                     (local.set $6
+                      (i32.load offset=32
+                       (local.get $2)
+                      )
+                     )
+                     (local.set $4
+                      (local.get $3)
+                     )
+                    )
+                   )
+                   (local.set $5
+                    (i32.load8_u
+                     (i32.add
+                      (i32.load offset=16
+                       (local.get $5)
+                      )
+                      (local.get $6)
+                     )
+                    )
+                   )
+                   (i32.store offset=20
+                    (local.get $2)
+                    (i32.add
+                     (local.get $3)
+                     (i32.const 1)
+                    )
+                   )
+                   (i32.store8
+                    (i32.add
+                     (i32.load offset=8
+                      (local.get $2)
+                     )
+                     (local.get $3)
+                    )
+                    (local.get $5)
+                   )
+                   (i32.store offset=32
+                    (local.get $2)
+                    (local.tee $6
+                     (i32.add
+                      (i32.load offset=32
+                       (local.get $2)
+                      )
+                      (i32.const 1)
+                     )
+                    )
+                   )
+                   (if
+                    (i32.ge_u
+                     (local.get $6)
+                     (i32.load16_u offset=20
+                      (local.tee $5
+                       (i32.load offset=28
+                        (local.get $2)
+                       )
+                      )
+                     )
+                    )
+                    (block
+                     (local.set $3
+                      (local.get $4)
+                     )
+                     (br $label$26)
+                    )
+                    (block
+                     (local.set $3
+                      (i32.load offset=20
+                       (local.get $2)
+                      )
+                     )
+                     (br $label$28)
+                    )
+                   )
+                  )
+                 )
+                )
+                (i32.store offset=4
+                 (local.get $2)
+                 (i32.const 73)
+                )
+                (br $label$14)
+               )
+               (block $label$33
+                (br_if $label$33
+                 (i32.eqz
+                  (i32.load offset=44
+                   (local.get $5)
+                  )
+                 )
+                )
+                (br_if $label$33
+                 (i32.le_u
+                  (local.tee $4
+                   (i32.load offset=20
+                    (local.get $2)
+                   )
+                  )
+                  (local.get $3)
+                 )
+                )
+                (i32.store offset=48
+                 (local.get $0)
+                 (call $fimport$14
+                  (i32.load offset=48
+                   (local.get $0)
+                  )
+                  (i32.add
+                   (i32.load offset=8
+                    (local.get $2)
+                   )
+                   (local.get $3)
+                  )
+                  (i32.sub
+                   (local.get $4)
+                   (local.get $3)
+                  )
+                 )
+                )
+                (local.set $5
+                 (i32.load offset=28
+                  (local.get $2)
+                 )
+                )
+               )
+               (if
+                (i32.eq
+                 (i32.load offset=32
+                  (local.get $2)
+                 )
+                 (i32.load offset=20
+                  (local.get $5)
+                 )
+                )
+                (block
+                 (i32.store offset=4
+                  (local.get $2)
+                  (i32.const 73)
+                 )
+                 (i32.store offset=32
+                  (local.get $2)
+                  (i32.const 0)
+                 )
+                 (br $label$14)
+                )
+               )
+               (local.set $3
+                (i32.load offset=4
+                 (local.get $2)
+                )
+               )
+              )
+              (br_if $label$13
+               (i32.ne
+                (local.get $3)
+                (i32.const 73)
+               )
+              )
+              (local.set $5
+               (i32.load offset=28
+                (local.get $2)
+               )
+              )
+             )
+             (br_if $label$11
+              (i32.eqz
+               (i32.load offset=28
+                (local.get $5)
+               )
+              )
+             )
+             (local.set $4
+              (local.tee $3
+               (i32.load offset=20
+                (local.get $2)
+               )
+              )
+             )
+             (local.set $5
+              (block $label$35 (result i32)
+               (loop $label$37
+                (block $label$36
+                 (if
+                  (i32.eq
+                   (i32.load offset=12
+                    (local.get $2)
+                   )
+                   (local.get $3)
+                  )
+                  (block
+                   (block $label$39
+                    (br_if $label$39
+                     (i32.le_u
+                      (local.get $3)
+                      (local.get $4)
+                     )
+                    )
+                    (br_if $label$39
+                     (i32.eqz
+                      (i32.load offset=44
+                       (i32.load offset=28
+                        (local.get $2)
+                       )
+                      )
+                     )
+                    )
+                    (i32.store offset=48
+                     (local.get $0)
+                     (call $fimport$14
+                      (i32.load offset=48
+                       (local.get $0)
+                      )
+                      (i32.add
+                       (i32.load offset=8
+                        (local.get $2)
+                       )
+                       (local.get $4)
+                      )
+                      (i32.sub
+                       (local.get $3)
+                       (local.get $4)
+                      )
+                     )
+                    )
+                   )
+                   (block $label$40
+                    (br_if $label$40
+                     (i32.eqz
+                      (local.tee $3
+                       (select
+                        (local.tee $3
+                         (i32.load offset=16
+                          (local.get $0)
+                         )
+                        )
+                        (local.tee $5
+                         (i32.load offset=20
+                          (local.tee $4
+                           (i32.load offset=28
+                            (local.get $0)
+                           )
+                          )
+                         )
+                        )
+                        (i32.gt_u
+                         (local.get $5)
+                         (local.get $3)
+                        )
+                       )
+                      )
+                     )
+                    )
+                    (drop
+                     (call $fimport$98
+                      (i32.load offset=12
+                       (local.get $0)
+                      )
+                      (i32.load offset=16
+                       (local.get $4)
+                      )
+                      (local.get $3)
+                     )
+                    )
+                    (i32.store offset=12
+                     (local.get $0)
+                     (i32.add
+                      (i32.load offset=12
+                       (local.get $0)
+                      )
+                      (local.get $3)
+                     )
+                    )
+                    (i32.store offset=16
+                     (local.tee $4
+                      (i32.load offset=28
+                       (local.get $0)
+                      )
+                     )
+                     (i32.add
+                      (i32.load offset=16
+                       (local.get $4)
+                      )
+                      (local.get $3)
+                     )
+                    )
+                    (i32.store offset=20
+                     (local.get $0)
+                     (i32.add
+                      (i32.load offset=20
+                       (local.get $0)
+                      )
+                      (local.get $3)
+                     )
+                    )
+                    (i32.store offset=16
+                     (local.get $0)
+                     (i32.sub
+                      (i32.load offset=16
+                       (local.get $0)
+                      )
+                      (local.get $3)
+                     )
+                    )
+                    (i32.store offset=20
+                     (local.get $4)
+                     (local.tee $3
+                      (i32.sub
+                       (i32.load offset=20
+                        (local.get $4)
+                       )
+                       (local.get $3)
+                      )
+                     )
+                    )
+                    (br_if $label$40
+                     (local.get $3)
+                    )
+                    (i32.store offset=16
+                     (local.get $4)
+                     (i32.load offset=8
+                      (local.get $4)
+                     )
+                    )
+                   )
+                   (br_if $label$36
+                    (i32.eq
+                     (local.tee $3
+                      (i32.load offset=20
+                       (local.get $2)
+                      )
+                     )
+                     (i32.load offset=12
+                      (local.get $2)
+                     )
+                    )
+                   )
+                   (local.set $4
+                    (local.get $3)
+                   )
+                  )
+                 )
+                 (local.set $5
+                  (i32.load offset=28
+                   (i32.load offset=28
+                    (local.get $2)
+                   )
+                  )
+                 )
+                 (i32.store offset=32
+                  (local.get $2)
+                  (i32.add
+                   (local.tee $6
+                    (i32.load offset=32
+                     (local.get $2)
+                    )
+                   )
+                   (i32.const 1)
+                  )
+                 )
+                 (local.set $5
+                  (i32.load8_u
+                   (i32.add
+                    (local.get $5)
+                    (local.get $6)
+                   )
+                  )
+                 )
+                 (i32.store offset=20
+                  (local.get $2)
+                  (i32.add
+                   (local.get $3)
+                   (i32.const 1)
+                  )
+                 )
+                 (i32.store8
+                  (i32.add
+                   (i32.load offset=8
+                    (local.get $2)
+                   )
+                   (local.get $3)
+                  )
+                  (local.get $5)
+                 )
+                 (if
+                  (local.get $5)
+                  (block
+                   (local.set $3
+                    (i32.load offset=20
+                     (local.get $2)
+                    )
+                   )
+                   (br $label$37)
+                  )
+                  (block
+                   (local.set $3
+                    (local.get $4)
+                   )
+                   (br $label$35
+                    (i32.const 0)
+                   )
+                  )
+                 )
+                )
+               )
+               (i32.const 1)
+              )
+             )
+             (block $label$42
+              (br_if $label$42
+               (i32.eqz
+                (i32.load offset=44
+                 (i32.load offset=28
+                  (local.get $2)
+                 )
+                )
+               )
+              )
+              (br_if $label$42
+               (i32.le_u
+                (local.tee $4
+                 (i32.load offset=20
+                  (local.get $2)
+                 )
+                )
+                (local.get $3)
+               )
+              )
+              (i32.store offset=48
+               (local.get $0)
+               (call $fimport$14
+                (i32.load offset=48
+                 (local.get $0)
+                )
+                (i32.add
+                 (i32.load offset=8
+                  (local.get $2)
+                 )
+                 (local.get $3)
+                )
+                (i32.sub
+                 (local.get $4)
+                 (local.get $3)
+                )
+               )
+              )
+             )
+             (br_if $label$12
+              (i32.eqz
+               (local.get $5)
+              )
+             )
+             (local.set $3
+              (i32.load offset=4
+               (local.get $2)
+              )
+             )
+            )
+            (br_if $label$10
+             (i32.eq
+              (local.get $3)
+              (i32.const 91)
+             )
+            )
+            (br $label$9)
+           )
+           (i32.store offset=32
+            (local.get $2)
+            (i32.const 0)
+           )
+          )
+          (i32.store offset=4
+           (local.get $2)
+           (i32.const 91)
+          )
+         )
+         (br_if $label$8
+          (i32.eqz
+           (i32.load offset=36
+            (i32.load offset=28
+             (local.get $2)
+            )
+           )
+          )
+         )
+         (local.set $4
+          (local.tee $3
+           (i32.load offset=20
+            (local.get $2)
+           )
+          )
+         )
+         (local.set $5
+          (block $label$43 (result i32)
+           (loop $label$45
+            (block $label$44
+             (if
+              (i32.eq
+               (i32.load offset=12
+                (local.get $2)
+               )
+               (local.get $3)
+              )
+              (block
+               (block $label$47
+                (br_if $label$47
+                 (i32.le_u
+                  (local.get $3)
+                  (local.get $4)
+                 )
+                )
+                (br_if $label$47
+                 (i32.eqz
+                  (i32.load offset=44
+                   (i32.load offset=28
+                    (local.get $2)
+                   )
+                  )
+                 )
+                )
+                (i32.store offset=48
+                 (local.get $0)
+                 (call $fimport$14
+                  (i32.load offset=48
+                   (local.get $0)
+                  )
+                  (i32.add
+                   (i32.load offset=8
+                    (local.get $2)
+                   )
+                   (local.get $4)
+                  )
+                  (i32.sub
+                   (local.get $3)
+                   (local.get $4)
+                  )
+                 )
+                )
+               )
+               (block $label$48
+                (br_if $label$48
+                 (i32.eqz
+                  (local.tee $3
+                   (select
+                    (local.tee $3
+                     (i32.load offset=16
+                      (local.get $0)
+                     )
+                    )
+                    (local.tee $5
+                     (i32.load offset=20
+                      (local.tee $4
+                       (i32.load offset=28
+                        (local.get $0)
+                       )
+                      )
+                     )
+                    )
+                    (i32.gt_u
+                     (local.get $5)
+                     (local.get $3)
+                    )
+                   )
+                  )
+                 )
+                )
+                (drop
+                 (call $fimport$98
+                  (i32.load offset=12
+                   (local.get $0)
+                  )
+                  (i32.load offset=16
+                   (local.get $4)
+                  )
+                  (local.get $3)
+                 )
+                )
+                (i32.store offset=12
+                 (local.get $0)
+                 (i32.add
+                  (i32.load offset=12
+                   (local.get $0)
+                  )
+                  (local.get $3)
+                 )
+                )
+                (i32.store offset=16
+                 (local.tee $4
+                  (i32.load offset=28
+                   (local.get $0)
+                  )
+                 )
+                 (i32.add
+                  (i32.load offset=16
+                   (local.get $4)
+                  )
+                  (local.get $3)
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $0)
+                 (i32.add
+                  (i32.load offset=20
+                   (local.get $0)
+                  )
+                  (local.get $3)
+                 )
+                )
+                (i32.store offset=16
+                 (local.get $0)
+                 (i32.sub
+                  (i32.load offset=16
+                   (local.get $0)
+                  )
+                  (local.get $3)
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $4)
+                 (local.tee $3
+                  (i32.sub
+                   (i32.load offset=20
+                    (local.get $4)
+                   )
+                   (local.get $3)
+                  )
+                 )
+                )
+                (br_if $label$48
+                 (local.get $3)
+                )
+                (i32.store offset=16
+                 (local.get $4)
+                 (i32.load offset=8
+                  (local.get $4)
+                 )
+                )
+               )
+               (br_if $label$44
+                (i32.eq
+                 (local.tee $3
+                  (i32.load offset=20
+                   (local.get $2)
+                  )
+                 )
+                 (i32.load offset=12
+                  (local.get $2)
+                 )
+                )
+               )
+               (local.set $4
+                (local.get $3)
+               )
+              )
+             )
+             (local.set $5
+              (i32.load offset=36
+               (i32.load offset=28
+                (local.get $2)
+               )
+              )
+             )
+             (i32.store offset=32
+              (local.get $2)
+              (i32.add
+               (local.tee $6
+                (i32.load offset=32
+                 (local.get $2)
+                )
+               )
+               (i32.const 1)
+              )
+             )
+             (local.set $5
+              (i32.load8_u
+               (i32.add
+                (local.get $5)
+                (local.get $6)
+               )
+              )
+             )
+             (i32.store offset=20
+              (local.get $2)
+              (i32.add
+               (local.get $3)
+               (i32.const 1)
+              )
+             )
+             (i32.store8
+              (i32.add
+               (i32.load offset=8
+                (local.get $2)
+               )
+               (local.get $3)
+              )
+              (local.get $5)
+             )
+             (if
+              (local.get $5)
+              (block
+               (local.set $3
+                (i32.load offset=20
+                 (local.get $2)
+                )
+               )
+               (br $label$45)
+              )
+              (block
+               (local.set $3
+                (local.get $4)
+               )
+               (br $label$43
+                (i32.const 0)
+               )
+              )
+             )
+            )
+           )
+           (i32.const 1)
+          )
+         )
+         (block $label$50
+          (br_if $label$50
+           (i32.eqz
+            (i32.load offset=44
+             (i32.load offset=28
+              (local.get $2)
+             )
+            )
+           )
+          )
+          (br_if $label$50
+           (i32.le_u
+            (local.tee $4
+             (i32.load offset=20
+              (local.get $2)
+             )
+            )
+            (local.get $3)
+           )
+          )
+          (i32.store offset=48
+           (local.get $0)
+           (call $fimport$14
+            (i32.load offset=48
+             (local.get $0)
+            )
+            (i32.add
+             (i32.load offset=8
+              (local.get $2)
+             )
+             (local.get $3)
+            )
+            (i32.sub
+             (local.get $4)
+             (local.get $3)
+            )
+           )
+          )
+         )
+         (br_if $label$8
+          (i32.eqz
+           (local.get $5)
+          )
+         )
+         (local.set $3
+          (i32.load offset=4
+           (local.get $2)
+          )
+         )
+        )
+        (br_if $label$7
+         (i32.eq
+          (local.get $3)
+          (i32.const 103)
+         )
+        )
+        (br $label$6)
+       )
+       (i32.store offset=4
+        (local.get $2)
+        (i32.const 103)
+       )
+      )
+      (if
+       (i32.load offset=44
+        (i32.load offset=28
+         (local.get $2)
+        )
+       )
+       (block
+        (block $label$52
+         (br_if $label$52
+          (i32.le_u
+           (i32.add
+            (i32.load offset=20
+             (local.get $2)
+            )
+            (i32.const 2)
+           )
+           (i32.load offset=12
+            (local.get $2)
+           )
+          )
+         )
+         (br_if $label$52
+          (i32.eqz
+           (local.tee $3
+            (select
+             (local.tee $3
+              (i32.load offset=16
+               (local.get $0)
+              )
+             )
+             (local.tee $5
+              (i32.load offset=20
+               (local.tee $4
+                (i32.load offset=28
+                 (local.get $0)
+                )
+               )
+              )
+             )
+             (i32.gt_u
+              (local.get $5)
+              (local.get $3)
+             )
+            )
+           )
+          )
+         )
+         (drop
+          (call $fimport$98
+           (i32.load offset=12
+            (local.get $0)
+           )
+           (i32.load offset=16
+            (local.get $4)
+           )
+           (local.get $3)
+          )
+         )
+         (i32.store offset=12
+          (local.get $0)
+          (i32.add
+           (i32.load offset=12
+            (local.get $0)
+           )
+           (local.get $3)
+          )
+         )
+         (i32.store offset=16
+          (local.tee $4
+           (i32.load offset=28
+            (local.get $0)
+           )
+          )
+          (i32.add
+           (i32.load offset=16
+            (local.get $4)
+           )
+           (local.get $3)
+          )
+         )
+         (i32.store offset=20
+          (local.get $0)
+          (i32.add
+           (i32.load offset=20
+            (local.get $0)
+           )
+           (local.get $3)
+          )
+         )
+         (i32.store offset=16
+          (local.get $0)
+          (i32.sub
+           (i32.load offset=16
+            (local.get $0)
+           )
+           (local.get $3)
+          )
+         )
+         (i32.store offset=20
+          (local.get $4)
+          (local.tee $3
+           (i32.sub
+            (i32.load offset=20
+             (local.get $4)
+            )
+            (local.get $3)
+           )
+          )
+         )
+         (br_if $label$52
+          (local.get $3)
+         )
+         (i32.store offset=16
+          (local.get $4)
+          (i32.load offset=8
+           (local.get $4)
+          )
+         )
+        )
+        (br_if $label$6
+         (i32.gt_u
+          (i32.add
+           (local.tee $3
+            (i32.load offset=20
+             (local.get $2)
+            )
+           )
+           (i32.const 2)
+          )
+          (i32.load offset=12
+           (local.get $2)
+          )
+         )
+        )
+        (local.set $4
+         (i32.load offset=48
+          (local.get $0)
+         )
+        )
+        (i32.store offset=20
+         (local.get $2)
+         (i32.add
+          (local.get $3)
+          (i32.const 1)
+         )
+        )
+        (i32.store8
+         (i32.add
+          (i32.load offset=8
+           (local.get $2)
+          )
+          (local.get $3)
+         )
+         (local.get $4)
+        )
+        (local.set $3
+         (i32.load offset=48
+          (local.get $0)
+         )
+        )
+        (i32.store offset=20
+         (local.get $2)
+         (i32.add
+          (local.tee $4
+           (i32.load offset=20
+            (local.get $2)
+           )
+          )
+          (i32.const 1)
+         )
+        )
+        (i32.store8
+         (i32.add
+          (local.get $4)
+          (i32.load offset=8
+           (local.get $2)
+          )
+         )
+         (i32.shr_u
+          (local.get $3)
+          (i32.const 8)
+         )
+        )
+        (i32.store offset=48
+         (local.get $0)
+         (call $fimport$14
+          (i32.const 0)
+          (i32.const 0)
+          (i32.const 0)
+         )
+        )
+        (i32.store offset=4
+         (local.get $2)
+         (i32.const 113)
+        )
+        (br $label$6)
+       )
+      )
+      (i32.store offset=4
+       (local.get $2)
+       (i32.const 113)
+      )
+     )
+     (block $label$53
+      (if
+       (i32.load offset=20
+        (local.get $2)
+       )
+       (block
+        (block $label$55
+         (br_if $label$55
+          (i32.eqz
+           (local.tee $3
+            (select
+             (local.tee $5
+              (i32.load offset=16
+               (local.get $0)
+              )
+             )
+             (local.tee $3
+              (i32.load offset=20
+               (local.tee $4
+                (i32.load offset=28
+                 (local.get $0)
+                )
+               )
+              )
+             )
+             (i32.gt_u
+              (local.get $3)
+              (local.get $5)
+             )
+            )
+           )
+          )
+         )
+         (drop
+          (call $fimport$98
+           (i32.load offset=12
+            (local.get $0)
+           )
+           (i32.load offset=16
+            (local.get $4)
+           )
+           (local.get $3)
+          )
+         )
+         (i32.store offset=12
+          (local.get $0)
+          (i32.add
+           (i32.load offset=12
+            (local.get $0)
+           )
+           (local.get $3)
+          )
+         )
+         (i32.store offset=16
+          (local.tee $4
+           (i32.load offset=28
+            (local.get $0)
+           )
+          )
+          (i32.add
+           (i32.load offset=16
+            (local.get $4)
+           )
+           (local.get $3)
+          )
+         )
+         (i32.store offset=20
+          (local.get $0)
+          (i32.add
+           (i32.load offset=20
+            (local.get $0)
+           )
+           (local.get $3)
+          )
+         )
+         (i32.store offset=16
+          (local.get $0)
+          (local.tee $5
+           (i32.sub
+            (i32.load offset=16
+             (local.get $0)
+            )
+            (local.get $3)
+           )
+          )
+         )
+         (i32.store offset=20
+          (local.get $4)
+          (local.tee $3
+           (i32.sub
+            (i32.load offset=20
+             (local.get $4)
+            )
+            (local.get $3)
+           )
+          )
+         )
+         (br_if $label$55
+          (local.get $3)
+         )
+         (i32.store offset=16
+          (local.get $4)
+          (i32.load offset=8
+           (local.get $4)
+          )
+         )
+        )
+        (br_if $label$53
+         (local.get $5)
+        )
+        (br $folding-inner1)
+       )
+      )
+      (br_if $label$53
+       (i32.eq
+        (local.get $1)
+        (i32.const 4)
+       )
+      )
+      (br_if $label$53
+       (i32.lt_s
+        (local.get $7)
+        (local.get $1)
+       )
+      )
+      (br_if $label$53
+       (i32.load offset=4
+        (local.get $0)
+       )
+      )
+      (br $folding-inner0)
+     )
+     (local.set $3
+      (i32.load offset=4
+       (local.get $0)
+      )
+     )
+     (block $label$56
+      (block $label$57
+       (block $label$58
+        (if
+         (i32.eq
+          (local.tee $4
+           (i32.load offset=4
+            (local.get $2)
+           )
+          )
+          (i32.const 666)
+         )
+         (block
+          (br_if $label$58
+           (i32.eqz
+            (local.get $3)
+           )
+          )
+          (br $folding-inner0)
+         )
+        )
+        (br_if $label$57
+         (local.get $3)
+        )
+       )
+       (br_if $label$57
+        (i32.eqz
+         (i32.or
+          (i32.eqz
+           (local.get $1)
+          )
+          (i32.eq
+           (local.get $4)
+           (i32.const 666)
+          )
+         )
+        )
+       )
+       (br_if $label$56
+        (i32.eqz
+         (i32.load offset=116
+          (local.get $2)
+         )
+        )
+       )
+      )
+      (if
+       (i32.eq
+        (i32.or
+         (local.tee $3
+          (block $label$60 (result i32)
+           (block $label$61
+            (if
+             (i32.ne
+              (local.tee $3
+               (i32.load offset=136
+                (local.get $2)
+               )
+              )
+              (i32.const 3)
+             )
+             (block
+              (br_if $label$61
+               (i32.ne
+                (local.get $3)
+                (i32.const 2)
+               )
+              )
+              (br $label$60
+               (call $fimport$20
+                (local.get $2)
+                (local.get $1)
+               )
+              )
+             )
+            )
+            (br $label$60
+             (call $fimport$21
+              (local.get $2)
+              (local.get $1)
+             )
+            )
+           )
+           (call_indirect (type $i32_i32_=>_i32)
+            (local.get $2)
+            (local.get $1)
+            (i32.load
+             (i32.add
+              (i32.mul
+               (i32.load offset=132
+                (local.get $2)
+               )
+               (i32.const 12)
+              )
+              (i32.const 11032)
+             )
+            )
+           )
+          )
+         )
+         (i32.const 1)
+        )
+        (i32.const 3)
+       )
+       (i32.store offset=4
+        (local.get $2)
+        (i32.const 666)
+       )
+      )
+      (if
+       (i32.eqz
+        (i32.and
+         (local.get $3)
+         (i32.const -3)
+        )
+       )
+       (block
+        (local.set $3
+         (i32.const 0)
+        )
+        (br_if $label$1
+         (i32.load offset=16
+          (local.get $0)
+         )
+        )
+        (br $folding-inner1)
+       )
+      )
+      (br_if $label$56
+       (i32.ne
+        (local.get $3)
+        (i32.const 1)
+       )
+      )
+      (block $label$65
+       (br_if $label$65
+        (i32.eq
+         (local.get $1)
+         (i32.const 5)
+        )
+       )
+       (if
+        (i32.eq
+         (local.get $1)
+         (i32.const 1)
+        )
+        (block
+         (call $fimport$30
+          (local.get $2)
+         )
+         (br $label$65)
+        )
+       )
+       (call $fimport$29
+        (local.get $2)
+        (i32.const 0)
+        (i32.const 0)
+        (i32.const 0)
+       )
+       (br_if $label$65
+        (i32.ne
+         (local.get $1)
+         (i32.const 3)
+        )
+       )
+       (i32.store16
+        (i32.add
+         (local.tee $3
+          (i32.load offset=68
+           (local.get $2)
+          )
+         )
+         (local.tee $4
+          (i32.add
+           (i32.shl
+            (i32.load offset=76
+             (local.get $2)
+            )
+            (i32.const 1)
+           )
+           (i32.const -2)
+          )
+         )
+        )
+        (i32.const 0)
+       )
+       (drop
+        (call $fimport$97
+         (local.get $3)
+         (i32.const 0)
+         (local.get $4)
+        )
+       )
+       (br_if $label$65
+        (i32.load offset=116
+         (local.get $2)
+        )
+       )
+       (i32.store offset=92
+        (local.get $2)
+        (i32.const 0)
+       )
+       (i32.store offset=108
+        (local.get $2)
+        (i32.const 0)
+       )
+      )
+      (block $label$67
+       (br_if $label$67
+        (i32.eqz
+         (local.tee $3
+          (select
+           (local.tee $5
+            (i32.load offset=16
+             (local.get $0)
+            )
+           )
+           (local.tee $3
+            (i32.load offset=20
+             (local.tee $4
+              (i32.load offset=28
+               (local.get $0)
+              )
+             )
+            )
+           )
+           (i32.gt_u
+            (local.get $3)
+            (local.get $5)
+           )
+          )
+         )
+        )
+       )
+       (drop
+        (call $fimport$98
+         (i32.load offset=12
+          (local.get $0)
+         )
+         (i32.load offset=16
+          (local.get $4)
+         )
+         (local.get $3)
+        )
+       )
+       (i32.store offset=12
+        (local.get $0)
+        (i32.add
+         (i32.load offset=12
+          (local.get $0)
+         )
+         (local.get $3)
+        )
+       )
+       (i32.store offset=16
+        (local.tee $4
+         (i32.load offset=28
+          (local.get $0)
+         )
+        )
+        (i32.add
+         (i32.load offset=16
+          (local.get $4)
+         )
+         (local.get $3)
+        )
+       )
+       (i32.store offset=20
+        (local.get $0)
+        (i32.add
+         (i32.load offset=20
+          (local.get $0)
+         )
+         (local.get $3)
+        )
+       )
+       (i32.store offset=16
+        (local.get $0)
+        (local.tee $5
+         (i32.sub
+          (i32.load offset=16
+           (local.get $0)
+          )
+          (local.get $3)
+         )
+        )
+       )
+       (i32.store offset=20
+        (local.get $4)
+        (local.tee $3
+         (i32.sub
+          (i32.load offset=20
+           (local.get $4)
+          )
+          (local.get $3)
+         )
+        )
+       )
+       (br_if $label$67
+        (local.get $3)
+       )
+       (i32.store offset=16
+        (local.get $4)
+        (i32.load offset=8
+         (local.get $4)
+        )
+       )
+      )
+      (br_if $label$56
+       (local.get $5)
+      )
+      (br $folding-inner1)
+     )
+     (local.set $3
+      (i32.const 0)
+     )
+     (br_if $label$1
+      (i32.ne
+       (local.get $1)
+       (i32.const 4)
+      )
+     )
+     (local.set $3
+      (i32.const 1)
+     )
+     (br_if $label$1
+      (i32.lt_s
+       (local.tee $4
+        (i32.load offset=24
+         (local.get $2)
+        )
+       )
+       (i32.const 1)
+      )
+     )
+     (local.set $1
+      (i32.load offset=48
+       (local.get $0)
+      )
+     )
+     (i32.store8
+      (block $label$68 (result i32)
+       (if
+        (i32.eq
+         (local.get $4)
+         (i32.const 2)
+        )
+        (block
+         (i32.store offset=20
+          (local.get $2)
+          (i32.add
+           (local.tee $3
+            (i32.load offset=20
+             (local.get $2)
+            )
+           )
+           (i32.const 1)
+          )
+         )
+         (i32.store8
+          (i32.add
+           (local.get $3)
+           (i32.load offset=8
+            (local.get $2)
+           )
+          )
+          (local.get $1)
+         )
+         (local.set $1
+          (i32.load offset=48
+           (local.get $0)
+          )
+         )
+         (i32.store offset=20
+          (local.get $2)
+          (i32.add
+           (local.tee $3
+            (i32.load offset=20
+             (local.get $2)
+            )
+           )
+           (i32.const 1)
+          )
+         )
+         (i32.store8
+          (i32.add
+           (local.get $3)
+           (i32.load offset=8
+            (local.get $2)
+           )
+          )
+          (i32.shr_u
+           (local.get $1)
+           (i32.const 8)
+          )
+         )
+         (local.set $1
+          (i32.load16_u offset=50
+           (local.get $0)
+          )
+         )
+         (i32.store offset=20
+          (local.get $2)
+          (i32.add
+           (local.tee $3
+            (i32.load offset=20
+             (local.get $2)
+            )
+           )
+           (i32.const 1)
+          )
+         )
+         (i32.store8
+          (i32.add
+           (local.get $3)
+           (i32.load offset=8
+            (local.get $2)
+           )
+          )
+          (local.get $1)
+         )
+         (local.set $1
+          (i32.load8_u offset=51
+           (local.get $0)
+          )
+         )
+         (i32.store offset=20
+          (local.get $2)
+          (i32.add
+           (local.tee $3
+            (i32.load offset=20
+             (local.get $2)
+            )
+           )
+           (i32.const 1)
+          )
+         )
+         (i32.store8
+          (i32.add
+           (local.get $3)
+           (i32.load offset=8
+            (local.get $2)
+           )
+          )
+          (local.get $1)
+         )
+         (local.set $1
+          (i32.load offset=8
+           (local.get $0)
+          )
+         )
+         (i32.store offset=20
+          (local.get $2)
+          (i32.add
+           (local.tee $3
+            (i32.load offset=20
+             (local.get $2)
+            )
+           )
+           (i32.const 1)
+          )
+         )
+         (i32.store8
+          (i32.add
+           (local.get $3)
+           (i32.load offset=8
+            (local.get $2)
+           )
+          )
+          (local.get $1)
+         )
+         (local.set $1
+          (i32.load offset=8
+           (local.get $0)
+          )
+         )
+         (i32.store offset=20
+          (local.get $2)
+          (i32.add
+           (local.tee $3
+            (i32.load offset=20
+             (local.get $2)
+            )
+           )
+           (i32.const 1)
+          )
+         )
+         (i32.store8
+          (i32.add
+           (local.get $3)
+           (i32.load offset=8
+            (local.get $2)
+           )
+          )
+          (i32.shr_u
+           (local.get $1)
+           (i32.const 8)
+          )
+         )
+         (local.set $1
+          (i32.load16_u offset=10
+           (local.get $0)
+          )
+         )
+         (i32.store offset=20
+          (local.get $2)
+          (i32.add
+           (local.tee $3
+            (i32.load offset=20
+             (local.get $2)
+            )
+           )
+           (i32.const 1)
+          )
+         )
+         (i32.store8
+          (i32.add
+           (local.get $3)
+           (i32.load offset=8
+            (local.get $2)
+           )
+          )
+          (local.get $1)
+         )
+         (local.set $3
+          (i32.load8_u offset=11
+           (local.get $0)
+          )
+         )
+         (i32.store offset=20
+          (local.get $2)
+          (i32.add
+           (local.tee $1
+            (i32.load offset=20
+             (local.get $2)
+            )
+           )
+           (i32.const 1)
+          )
+         )
+         (br $label$68
+          (i32.add
+           (local.get $1)
+           (i32.load offset=8
+            (local.get $2)
+           )
+          )
+         )
+        )
+       )
+       (i32.store offset=20
+        (local.get $2)
+        (i32.add
+         (local.tee $3
+          (i32.load offset=20
+           (local.get $2)
+          )
+         )
+         (i32.const 1)
+        )
+       )
+       (i32.store8
+        (i32.add
+         (local.get $3)
+         (i32.load offset=8
+          (local.get $2)
+         )
+        )
+        (i32.shr_u
+         (local.get $1)
+         (i32.const 24)
+        )
+       )
+       (i32.store offset=20
+        (local.get $2)
+        (i32.add
+         (local.tee $3
+          (i32.load offset=20
+           (local.get $2)
+          )
+         )
+         (i32.const 1)
+        )
+       )
+       (i32.store8
+        (i32.add
+         (local.get $3)
+         (i32.load offset=8
+          (local.get $2)
+         )
+        )
+        (i32.shr_u
+         (local.get $1)
+         (i32.const 16)
+        )
+       )
+       (local.set $3
+        (i32.load offset=48
+         (local.get $0)
+        )
+       )
+       (i32.store offset=20
+        (local.get $2)
+        (i32.add
+         (local.tee $1
+          (i32.load offset=20
+           (local.get $2)
+          )
+         )
+         (i32.const 1)
+        )
+       )
+       (i32.store8
+        (i32.add
+         (local.get $1)
+         (i32.load offset=8
+          (local.get $2)
+         )
+        )
+        (i32.shr_u
+         (local.get $3)
+         (i32.const 8)
+        )
+       )
+       (i32.store offset=20
+        (local.get $2)
+        (i32.add
+         (local.tee $1
+          (i32.load offset=20
+           (local.get $2)
+          )
+         )
+         (i32.const 1)
+        )
+       )
+       (i32.add
+        (local.get $1)
+        (i32.load offset=8
+         (local.get $2)
+        )
+       )
+      )
+      (local.get $3)
+     )
+     (block $label$70
+      (br_if $label$70
+       (i32.eqz
+        (local.tee $1
+         (select
+          (local.tee $1
+           (i32.load offset=16
+            (local.get $0)
+           )
+          )
+          (local.tee $4
+           (i32.load offset=20
+            (local.tee $3
+             (i32.load offset=28
+              (local.get $0)
+             )
+            )
+           )
+          )
+          (i32.gt_u
+           (local.get $4)
+           (local.get $1)
+          )
+         )
+        )
+       )
+      )
+      (drop
+       (call $fimport$98
+        (i32.load offset=12
+         (local.get $0)
+        )
+        (i32.load offset=16
+         (local.get $3)
+        )
+        (local.get $1)
+       )
+      )
+      (i32.store offset=12
+       (local.get $0)
+       (i32.add
+        (i32.load offset=12
+         (local.get $0)
+        )
+        (local.get $1)
+       )
+      )
+      (i32.store offset=16
+       (local.tee $3
+        (i32.load offset=28
+         (local.get $0)
+        )
+       )
+       (i32.add
+        (i32.load offset=16
+         (local.get $3)
+        )
+        (local.get $1)
+       )
+      )
+      (i32.store offset=20
+       (local.get $0)
+       (i32.add
+        (i32.load offset=20
+         (local.get $0)
+        )
+        (local.get $1)
+       )
+      )
+      (i32.store offset=16
+       (local.get $0)
+       (i32.sub
+        (i32.load offset=16
+         (local.get $0)
+        )
+        (local.get $1)
+       )
+      )
+      (i32.store offset=20
+       (local.get $3)
+       (local.tee $0
+        (i32.sub
+         (i32.load offset=20
+          (local.get $3)
+         )
+         (local.get $1)
+        )
+       )
+      )
+      (br_if $label$70
+       (local.get $0)
+      )
+      (i32.store offset=16
+       (local.get $3)
+       (i32.load offset=8
+        (local.get $3)
+       )
+      )
+     )
+     (if
+      (i32.ge_s
+       (local.tee $0
+        (i32.load offset=24
+         (local.get $2)
+        )
+       )
+       (i32.const 1)
+      )
+      (i32.store offset=24
+       (local.get $2)
+       (i32.sub
+        (i32.const 0)
+        (local.get $0)
+       )
+      )
+     )
+     (local.set $3
+      (i32.eqz
+       (i32.load offset=20
+        (local.get $2)
+       )
+      )
+     )
+    )
+    (return
+     (local.get $3)
+    )
+   )
+   (i32.store offset=24
+    (local.get $0)
+    (i32.load
+     (i32.const 17004)
+    )
+   )
+   (return
+    (i32.const -5)
+   )
+  )
+  (i32.store offset=40
+   (local.get $2)
+   (i32.const -1)
+  )
+  (i32.const 0)
+ )
+)
diff --git a/binaryen/test/passes/O3_low-memory-unused_metrics.wast b/binaryen/test/passes/O3_low-memory-unused_metrics.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O3_low-memory-unused_metrics.wast
@@ -0,0 +1,3322 @@
+;; zlib key deflate() function, with deflate_rle/deflate_huff inlining disabled
+(module
+ (type $0 (func (param i32 i32 i32) (result i32)))
+ (type $1 (func (param i32 i32)))
+ (type $2 (func (param i32 i32) (result i32)))
+ (type $3 (func (param i32 i32 i32 i32)))
+ (type $4 (func (param i32) (result i32)))
+ (type $5 (func))
+ (type $6 (func (param i32 i32 i32)))
+ (type $7 (func (result i32)))
+ (type $8 (func (param i32 i32 i32 i32) (result i32)))
+ (type $9 (func (param i32 i32 i32 i32 i32 i32 i32 i32) (result i32)))
+ (type $10 (func (param i32)))
+ (type $11 (func (param i32 i32 i32 i32 i32 i32) (result i32)))
+ (type $12 (func (param i64 i64) (result i32)))
+ (type $13 (func (param i32 i64 i64 i32)))
+ (type $14 (func (param i32 i32 i32 i32 i32) (result i32)))
+ (type $15 (func (param i64 i32 i32) (result i32)))
+ (type $16 (func (param i64 i32) (result i32)))
+ (type $17 (func (param i32 i32 i32 i32 i32)))
+ (type $18 (func (param i32 i64 i64 i32 i32 i32 i32) (result i32)))
+ (type $19 (func (param i32 i64 i64 i64 i64)))
+ (type $20 (func (param i64 i64 i64 i64) (result i32)))
+ (type $21 (func (param i32 f64)))
+ (type $22 (func (param i32 i32 i32) (result i32)))
+ (type $23 (func (param i32 i32)))
+ (type $24 (func (param i32 i32) (result i32)))
+ (type $25 (func (param i32) (result i32)))
+ (type $26 (func (result i32)))
+ (type $27 (func (param i32)))
+ (type $28 (func (param i32 i32 i32 i32) (result i32)))
+ (type $29 (func (param i32 i32 i32)))
+ (import "env" "memory" (memory $108 4096 4096))
+ (import "env" "table" (table $timport$109 10 funcref))
+ (import "env" "__assert_fail" (func $fimport$0 (param i32 i32 i32 i32)))
+ (import "env" "__syscall54" (func $fimport$1 (param i32 i32) (result i32)))
+ (import "env" "__syscall6" (func $fimport$2 (param i32 i32) (result i32)))
+ (import "env" "__syscall140" (func $fimport$3 (param i32 i32) (result i32)))
+ (import "env" "__syscall146" (func $fimport$4 (param i32 i32) (result i32)))
+ (import "env" "sbrk" (func $fimport$5 (param i32) (result i32)))
+ (import "env" "emscripten_memcpy_big" (func $fimport$6 (param i32 i32 i32) (result i32)))
+ (import "env" "__wasm_call_ctors" (func $fimport$7))
+ (import "env" "doit" (func $fimport$8 (param i32 i32 i32)))
+ (import "env" "benchmark_main" (func $fimport$9 (param i32 i32) (result i32)))
+ (import "env" "__original_main" (func $fimport$10 (result i32)))
+ (import "env" "main" (func $fimport$11 (param i32 i32) (result i32)))
+ (import "env" "compress" (func $fimport$12 (param i32 i32 i32 i32) (result i32)))
+ (import "env" "compressBound" (func $fimport$13 (param i32) (result i32)))
+ (import "env" "crc32" (func $fimport$14 (param i32 i32 i32) (result i32)))
+ (import "env" "adler32" (func $fimport$15 (param i32 i32 i32) (result i32)))
+ (import "env" "deflateInit_" (func $fimport$16 (param i32 i32 i32 i32) (result i32)))
+ (import "env" "deflateInit2_" (func $fimport$17 (param i32 i32 i32 i32 i32 i32 i32 i32) (result i32)))
+ (import "env" "deflateEnd" (func $fimport$18 (param i32) (result i32)))
+ (import "env" "deflateReset" (func $fimport$19 (param i32) (result i32)))
+ (import "env" "deflate_huff" (func $fimport$20 (param i32 i32) (result i32)))
+ (import "env" "deflate_rle" (func $fimport$21 (param i32 i32) (result i32)))
+ (import "env" "fill_window" (func $fimport$22 (param i32)))
+ (import "env" "deflate_stored" (func $fimport$23 (param i32 i32) (result i32)))
+ (import "env" "deflate_fast" (func $fimport$24 (param i32 i32) (result i32)))
+ (import "env" "longest_match" (func $fimport$25 (param i32 i32) (result i32)))
+ (import "env" "deflate_slow" (func $fimport$26 (param i32 i32) (result i32)))
+ (import "env" "_tr_init" (func $fimport$27 (param i32)))
+ (import "env" "init_block" (func $fimport$28 (param i32)))
+ (import "env" "_tr_stored_block" (func $fimport$29 (param i32 i32 i32 i32)))
+ (import "env" "_tr_align" (func $fimport$30 (param i32)))
+ (import "env" "_tr_flush_block" (func $fimport$31 (param i32 i32 i32 i32)))
+ (import "env" "build_tree" (func $fimport$32 (param i32 i32)))
+ (import "env" "compress_block" (func $fimport$33 (param i32 i32 i32)))
+ (import "env" "send_tree" (func $fimport$34 (param i32 i32 i32)))
+ (import "env" "inflate_table" (func $fimport$35 (param i32 i32 i32 i32 i32 i32) (result i32)))
+ (import "env" "inflate_fast" (func $fimport$36 (param i32 i32)))
+ (import "env" "inflateInit2_" (func $fimport$37 (param i32 i32 i32 i32) (result i32)))
+ (import "env" "inflateInit_" (func $fimport$38 (param i32 i32 i32) (result i32)))
+ (import "env" "inflate" (func $fimport$39 (param i32 i32) (result i32)))
+ (import "env" "updatewindow" (func $fimport$40 (param i32 i32) (result i32)))
+ (import "env" "inflateEnd" (func $fimport$41 (param i32) (result i32)))
+ (import "env" "uncompress" (func $fimport$42 (param i32 i32 i32 i32) (result i32)))
+ (import "env" "zcalloc" (func $fimport$43 (param i32 i32 i32) (result i32)))
+ (import "env" "zcfree" (func $fimport$44 (param i32 i32)))
+ (import "env" "strcmp" (func $fimport$45 (param i32 i32) (result i32)))
+ (import "env" "puts" (func $fimport$46 (param i32) (result i32)))
+ (import "env" "strlen" (func $fimport$47 (param i32) (result i32)))
+ (import "env" "fputs" (func $fimport$48 (param i32 i32) (result i32)))
+ (import "env" "__towrite" (func $fimport$49 (param i32) (result i32)))
+ (import "env" "__fwritex" (func $fimport$50 (param i32 i32 i32) (result i32)))
+ (import "env" "fwrite" (func $fimport$51 (param i32 i32 i32 i32) (result i32)))
+ (import "env" "__lockfile" (func $fimport$52 (param i32) (result i32)))
+ (import "env" "__unlockfile" (func $fimport$53 (param i32)))
+ (import "env" "__stdout_write" (func $fimport$54 (param i32 i32 i32) (result i32)))
+ (import "env" "__errno_location" (func $fimport$55 (result i32)))
+ (import "env" "__syscall_ret" (func $fimport$56 (param i32) (result i32)))
+ (import "env" "dummy" (func $fimport$57 (param i32) (result i32)))
+ (import "env" "__stdio_close" (func $fimport$58 (param i32) (result i32)))
+ (import "env" "printf" (func $fimport$59 (param i32 i32) (result i32)))
+ (import "env" "__overflow" (func $fimport$60 (param i32 i32) (result i32)))
+ (import "env" "isdigit" (func $fimport$61 (param i32) (result i32)))
+ (import "env" "memchr" (func $fimport$62 (param i32 i32 i32) (result i32)))
+ (import "env" "pthread_self" (func $fimport$63 (result i32)))
+ (import "env" "wcrtomb" (func $fimport$64 (param i32 i32 i32) (result i32)))
+ (import "env" "__pthread_self" (func $fimport$65 (result i32)))
+ (import "env" "wctomb" (func $fimport$66 (param i32 i32) (result i32)))
+ (import "env" "__signbitl" (func $fimport$67 (param i64 i64) (result i32)))
+ (import "env" "frexpl" (func $fimport$68 (param i32 i64 i64 i32)))
+ (import "env" "vfprintf" (func $fimport$69 (param i32 i32 i32) (result i32)))
+ (import "env" "printf_core" (func $fimport$70 (param i32 i32 i32 i32 i32) (result i32)))
+ (import "env" "out" (func $fimport$71 (param i32 i32 i32)))
+ (import "env" "getint" (func $fimport$72 (param i32) (result i32)))
+ (import "env" "pop_arg" (func $fimport$73 (param i32 i32 i32)))
+ (import "env" "fmt_x" (func $fimport$74 (param i64 i32 i32) (result i32)))
+ (import "env" "fmt_o" (func $fimport$75 (param i64 i32) (result i32)))
+ (import "env" "fmt_u" (func $fimport$76 (param i64 i32) (result i32)))
+ (import "env" "pad" (func $fimport$77 (param i32 i32 i32 i32 i32)))
+ (import "env" "fmt_fp" (func $fimport$78 (param i32 i64 i64 i32 i32 i32 i32) (result i32)))
+ (import "env" "__stdio_seek" (func $fimport$79 (param i32 i32 i32) (result i32)))
+ (import "env" "__stdio_write" (func $fimport$80 (param i32 i32 i32) (result i32)))
+ (import "env" "malloc" (func $fimport$81 (param i32) (result i32)))
+ (import "env" "free" (func $fimport$82 (param i32)))
+ (import "env" "__addtf3" (func $fimport$83 (param i32 i64 i64 i64 i64)))
+ (import "env" "__ashlti3" (func $fimport$84 (param i32 i64 i64 i32)))
+ (import "env" "__unordtf2" (func $fimport$85 (param i64 i64 i64 i64) (result i32)))
+ (import "env" "__eqtf2" (func $fimport$86 (param i64 i64 i64 i64) (result i32)))
+ (import "env" "__netf2" (func $fimport$87 (param i64 i64 i64 i64) (result i32)))
+ (import "env" "__extenddftf2" (func $fimport$88 (param i32 f64)))
+ (import "env" "__fixtfsi" (func $fimport$89 (param i64 i64) (result i32)))
+ (import "env" "__fixunstfsi" (func $fimport$90 (param i64 i64) (result i32)))
+ (import "env" "__floatsitf" (func $fimport$91 (param i32 i32)))
+ (import "env" "__floatunsitf" (func $fimport$92 (param i32 i32)))
+ (import "env" "__lshrti3" (func $fimport$93 (param i32 i64 i64 i32)))
+ (import "env" "__multf3" (func $fimport$94 (param i32 i64 i64 i64 i64)))
+ (import "env" "__subtf3" (func $fimport$95 (param i32 i64 i64 i64 i64)))
+ (import "env" "__fpclassifyl" (func $fimport$96 (param i64 i64) (result i32)))
+ (import "env" "memset" (func $fimport$97 (param i32 i32 i32) (result i32)))
+ (import "env" "memcpy" (func $fimport$98 (param i32 i32 i32) (result i32)))
+ (import "env" "setThrew" (func $fimport$99 (param i32 i32)))
+ (import "env" "stackSave" (func $fimport$100 (result i32)))
+ (import "env" "stackAlloc" (func $fimport$101 (param i32) (result i32)))
+ (import "env" "stackRestore" (func $fimport$102 (param i32)))
+ (import "env" "__growWasmMemory" (func $fimport$103 (param i32) (result i32)))
+ (import "env" "dynCall_iiii" (func $fimport$104 (param i32 i32 i32 i32) (result i32)))
+ (import "env" "dynCall_vii" (func $fimport$105 (param i32 i32 i32)))
+ (import "env" "dynCall_iii" (func $fimport$106 (param i32 i32 i32) (result i32)))
+ (import "env" "dynCall_ii" (func $fimport$107 (param i32 i32) (result i32)))
+ (global $global$0 (mut i32) (i32.const 5243904))
+ (global $global$1 i32 (i32.const 5260880))
+ (global $global$2 i32 (i32.const 17988))
+ (export "deflate" (func $0))
+ (func $0 (; 108 ;) (type $2) (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local.set $2
+   (i32.const -2)
+  )
+  (block $label$1
+   (br_if $label$1
+    (i32.eqz
+     (local.get $0)
+    )
+   )
+   (br_if $label$1
+    (i32.gt_u
+     (local.get $1)
+     (i32.const 5)
+    )
+   )
+   (br_if $label$1
+    (i32.eqz
+     (local.tee $3
+      (i32.load offset=28
+       (local.get $0)
+      )
+     )
+    )
+   )
+   (block $label$2
+    (block $label$3
+     (br_if $label$3
+      (i32.eqz
+       (i32.load offset=12
+        (local.get $0)
+       )
+      )
+     )
+     (block $label$4
+      (br_if $label$4
+       (i32.load
+        (local.get $0)
+       )
+      )
+      (br_if $label$3
+       (i32.load offset=4
+        (local.get $0)
+       )
+      )
+     )
+     (local.set $2
+      (i32.load offset=4
+       (local.get $3)
+      )
+     )
+     (br_if $label$2
+      (i32.eq
+       (local.get $1)
+       (i32.const 4)
+      )
+     )
+     (br_if $label$2
+      (i32.ne
+       (local.get $2)
+       (i32.const 666)
+      )
+     )
+    )
+    (i32.store offset=24
+     (local.get $0)
+     (i32.load offset=16992
+      (i32.const 0)
+     )
+    )
+    (return
+     (i32.const -2)
+    )
+   )
+   (block $label$5
+    (br_if $label$5
+     (i32.load offset=16
+      (local.get $0)
+     )
+    )
+    (i32.store offset=24
+     (local.get $0)
+     (i32.load offset=17004
+      (i32.const 0)
+     )
+    )
+    (return
+     (i32.const -5)
+    )
+   )
+   (i32.store
+    (local.get $3)
+    (local.get $0)
+   )
+   (local.set $4
+    (i32.load offset=40
+     (local.get $3)
+    )
+   )
+   (i32.store offset=40
+    (local.get $3)
+    (local.get $1)
+   )
+   (block $label$6
+    (block $label$7
+     (block $label$8
+      (block $label$9
+       (block $label$10
+        (block $label$11
+         (block $label$12
+          (block $label$13
+           (block $label$14
+            (block $label$15
+             (block $label$16
+              (block $label$17
+               (br_if $label$17
+                (i32.ne
+                 (local.get $2)
+                 (i32.const 42)
+                )
+               )
+               (block $label$18
+                (br_if $label$18
+                 (i32.ne
+                  (i32.load offset=24
+                   (local.get $3)
+                  )
+                  (i32.const 2)
+                 )
+                )
+                (i32.store offset=48
+                 (local.get $0)
+                 (call $fimport$14
+                  (i32.const 0)
+                  (i32.const 0)
+                  (i32.const 0)
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $3)
+                 (i32.add
+                  (local.tee $2
+                   (i32.load offset=20
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 1)
+                 )
+                )
+                (i32.store8
+                 (i32.add
+                  (local.get $2)
+                  (i32.load offset=8
+                   (local.get $3)
+                  )
+                 )
+                 (i32.const 31)
+                )
+                (i32.store offset=20
+                 (local.get $3)
+                 (i32.add
+                  (local.tee $2
+                   (i32.load offset=20
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 1)
+                 )
+                )
+                (i32.store8
+                 (i32.add
+                  (local.get $2)
+                  (i32.load offset=8
+                   (local.get $3)
+                  )
+                 )
+                 (i32.const 139)
+                )
+                (i32.store offset=20
+                 (local.get $3)
+                 (i32.add
+                  (local.tee $2
+                   (i32.load offset=20
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 1)
+                 )
+                )
+                (i32.store8
+                 (i32.add
+                  (local.get $2)
+                  (i32.load offset=8
+                   (local.get $3)
+                  )
+                 )
+                 (i32.const 8)
+                )
+                (block $label$19
+                 (br_if $label$19
+                  (local.tee $2
+                   (i32.load offset=28
+                    (local.get $3)
+                   )
+                  )
+                 )
+                 (i32.store offset=20
+                  (local.get $3)
+                  (i32.add
+                   (local.tee $2
+                    (i32.load offset=20
+                     (local.get $3)
+                    )
+                   )
+                   (i32.const 1)
+                  )
+                 )
+                 (i32.store8
+                  (i32.add
+                   (local.get $2)
+                   (i32.load offset=8
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 0)
+                 )
+                 (i32.store offset=20
+                  (local.get $3)
+                  (i32.add
+                   (local.tee $2
+                    (i32.load offset=20
+                     (local.get $3)
+                    )
+                   )
+                   (i32.const 1)
+                  )
+                 )
+                 (i32.store8
+                  (i32.add
+                   (local.get $2)
+                   (i32.load offset=8
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 0)
+                 )
+                 (i32.store offset=20
+                  (local.get $3)
+                  (i32.add
+                   (local.tee $2
+                    (i32.load offset=20
+                     (local.get $3)
+                    )
+                   )
+                   (i32.const 1)
+                  )
+                 )
+                 (i32.store8
+                  (i32.add
+                   (local.get $2)
+                   (i32.load offset=8
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 0)
+                 )
+                 (i32.store offset=20
+                  (local.get $3)
+                  (i32.add
+                   (local.tee $2
+                    (i32.load offset=20
+                     (local.get $3)
+                    )
+                   )
+                   (i32.const 1)
+                  )
+                 )
+                 (i32.store8
+                  (i32.add
+                   (local.get $2)
+                   (i32.load offset=8
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 0)
+                 )
+                 (i32.store offset=20
+                  (local.get $3)
+                  (i32.add
+                   (local.tee $2
+                    (i32.load offset=20
+                     (local.get $3)
+                    )
+                   )
+                   (i32.const 1)
+                  )
+                 )
+                 (i32.store8
+                  (i32.add
+                   (local.get $2)
+                   (i32.load offset=8
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 0)
+                 )
+                 (local.set $2
+                  (i32.const 2)
+                 )
+                 (block $label$20
+                  (br_if $label$20
+                   (i32.eq
+                    (local.tee $5
+                     (i32.load offset=132
+                      (local.get $3)
+                     )
+                    )
+                    (i32.const 9)
+                   )
+                  )
+                  (local.set $2
+                   (select
+                    (i32.const 4)
+                    (i32.shl
+                     (i32.gt_s
+                      (i32.load offset=136
+                       (local.get $3)
+                      )
+                      (i32.const 1)
+                     )
+                     (i32.const 2)
+                    )
+                    (i32.lt_s
+                     (local.get $5)
+                     (i32.const 2)
+                    )
+                   )
+                  )
+                 )
+                 (i32.store offset=20
+                  (local.get $3)
+                  (i32.add
+                   (local.tee $5
+                    (i32.load offset=20
+                     (local.get $3)
+                    )
+                   )
+                   (i32.const 1)
+                  )
+                 )
+                 (i32.store8
+                  (i32.add
+                   (local.get $5)
+                   (i32.load offset=8
+                    (local.get $3)
+                   )
+                  )
+                  (local.get $2)
+                 )
+                 (i32.store offset=20
+                  (local.get $3)
+                  (i32.add
+                   (local.tee $2
+                    (i32.load offset=20
+                     (local.get $3)
+                    )
+                   )
+                   (i32.const 1)
+                  )
+                 )
+                 (i32.store8
+                  (i32.add
+                   (local.get $2)
+                   (i32.load offset=8
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 3)
+                 )
+                 (i32.store offset=4
+                  (local.get $3)
+                  (i32.const 113)
+                 )
+                 (br $label$6)
+                )
+                (local.set $5
+                 (i32.load offset=36
+                  (local.get $2)
+                 )
+                )
+                (local.set $6
+                 (i32.load offset=28
+                  (local.get $2)
+                 )
+                )
+                (local.set $7
+                 (i32.load offset=16
+                  (local.get $2)
+                 )
+                )
+                (local.set $8
+                 (i32.load offset=44
+                  (local.get $2)
+                 )
+                )
+                (local.set $9
+                 (i32.load
+                  (local.get $2)
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $3)
+                 (i32.add
+                  (local.tee $10
+                   (i32.load offset=20
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 1)
+                 )
+                )
+                (local.set $2
+                 (i32.const 2)
+                )
+                (i32.store8
+                 (i32.add
+                  (local.get $10)
+                  (i32.load offset=8
+                   (local.get $3)
+                  )
+                 )
+                 (i32.or
+                  (i32.or
+                   (i32.or
+                    (i32.or
+                     (i32.shl
+                      (i32.ne
+                       (local.get $8)
+                       (i32.const 0)
+                      )
+                      (i32.const 1)
+                     )
+                     (i32.ne
+                      (local.get $9)
+                      (i32.const 0)
+                     )
+                    )
+                    (i32.shl
+                     (i32.ne
+                      (local.get $7)
+                      (i32.const 0)
+                     )
+                     (i32.const 2)
+                    )
+                   )
+                   (i32.shl
+                    (i32.ne
+                     (local.get $6)
+                     (i32.const 0)
+                    )
+                    (i32.const 3)
+                   )
+                  )
+                  (i32.shl
+                   (i32.ne
+                    (local.get $5)
+                    (i32.const 0)
+                   )
+                   (i32.const 4)
+                  )
+                 )
+                )
+                (local.set $5
+                 (i32.load offset=4
+                  (i32.load offset=28
+                   (local.get $3)
+                  )
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $3)
+                 (i32.add
+                  (local.tee $6
+                   (i32.load offset=20
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 1)
+                 )
+                )
+                (i32.store8
+                 (i32.add
+                  (local.get $6)
+                  (i32.load offset=8
+                   (local.get $3)
+                  )
+                 )
+                 (local.get $5)
+                )
+                (local.set $5
+                 (i32.load offset=4
+                  (i32.load offset=28
+                   (local.get $3)
+                  )
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $3)
+                 (i32.add
+                  (local.tee $6
+                   (i32.load offset=20
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 1)
+                 )
+                )
+                (i32.store8
+                 (i32.add
+                  (local.get $6)
+                  (i32.load offset=8
+                   (local.get $3)
+                  )
+                 )
+                 (i32.shr_u
+                  (local.get $5)
+                  (i32.const 8)
+                 )
+                )
+                (local.set $5
+                 (i32.load16_u
+                  (i32.add
+                   (i32.load offset=28
+                    (local.get $3)
+                   )
+                   (i32.const 6)
+                  )
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $3)
+                 (i32.add
+                  (local.tee $6
+                   (i32.load offset=20
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 1)
+                 )
+                )
+                (i32.store8
+                 (i32.add
+                  (local.get $6)
+                  (i32.load offset=8
+                   (local.get $3)
+                  )
+                 )
+                 (local.get $5)
+                )
+                (local.set $5
+                 (i32.load8_u
+                  (i32.add
+                   (i32.load offset=28
+                    (local.get $3)
+                   )
+                   (i32.const 7)
+                  )
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $3)
+                 (i32.add
+                  (local.tee $6
+                   (i32.load offset=20
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 1)
+                 )
+                )
+                (i32.store8
+                 (i32.add
+                  (local.get $6)
+                  (i32.load offset=8
+                   (local.get $3)
+                  )
+                 )
+                 (local.get $5)
+                )
+                (block $label$21
+                 (br_if $label$21
+                  (i32.eq
+                   (local.tee $5
+                    (i32.load offset=132
+                     (local.get $3)
+                    )
+                   )
+                   (i32.const 9)
+                  )
+                 )
+                 (local.set $2
+                  (select
+                   (i32.const 4)
+                   (i32.shl
+                    (i32.gt_s
+                     (i32.load offset=136
+                      (local.get $3)
+                     )
+                     (i32.const 1)
+                    )
+                    (i32.const 2)
+                   )
+                   (i32.lt_s
+                    (local.get $5)
+                    (i32.const 2)
+                   )
+                  )
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $3)
+                 (i32.add
+                  (local.tee $5
+                   (i32.load offset=20
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 1)
+                 )
+                )
+                (i32.store8
+                 (i32.add
+                  (local.get $5)
+                  (i32.load offset=8
+                   (local.get $3)
+                  )
+                 )
+                 (local.get $2)
+                )
+                (local.set $2
+                 (i32.load offset=12
+                  (i32.load offset=28
+                   (local.get $3)
+                  )
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $3)
+                 (i32.add
+                  (local.tee $5
+                   (i32.load offset=20
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 1)
+                 )
+                )
+                (i32.store8
+                 (i32.add
+                  (local.get $5)
+                  (i32.load offset=8
+                   (local.get $3)
+                  )
+                 )
+                 (local.get $2)
+                )
+                (block $label$22
+                 (br_if $label$22
+                  (i32.eqz
+                   (i32.load offset=16
+                    (local.tee $2
+                     (i32.load offset=28
+                      (local.get $3)
+                     )
+                    )
+                   )
+                  )
+                 )
+                 (local.set $2
+                  (i32.load offset=20
+                   (local.get $2)
+                  )
+                 )
+                 (i32.store offset=20
+                  (local.get $3)
+                  (i32.add
+                   (local.tee $5
+                    (i32.load offset=20
+                     (local.get $3)
+                    )
+                   )
+                   (i32.const 1)
+                  )
+                 )
+                 (i32.store8
+                  (i32.add
+                   (local.get $5)
+                   (i32.load offset=8
+                    (local.get $3)
+                   )
+                  )
+                  (local.get $2)
+                 )
+                 (local.set $2
+                  (i32.load offset=20
+                   (i32.load offset=28
+                    (local.get $3)
+                   )
+                  )
+                 )
+                 (i32.store offset=20
+                  (local.get $3)
+                  (i32.add
+                   (local.tee $5
+                    (i32.load offset=20
+                     (local.get $3)
+                    )
+                   )
+                   (i32.const 1)
+                  )
+                 )
+                 (i32.store8
+                  (i32.add
+                   (local.get $5)
+                   (i32.load offset=8
+                    (local.get $3)
+                   )
+                  )
+                  (i32.shr_u
+                   (local.get $2)
+                   (i32.const 8)
+                  )
+                 )
+                 (local.set $2
+                  (i32.load offset=28
+                   (local.get $3)
+                  )
+                 )
+                )
+                (block $label$23
+                 (br_if $label$23
+                  (i32.eqz
+                   (i32.load offset=44
+                    (local.get $2)
+                   )
+                  )
+                 )
+                 (i32.store offset=48
+                  (local.get $0)
+                  (call $fimport$14
+                   (i32.load offset=48
+                    (local.get $0)
+                   )
+                   (i32.load offset=8
+                    (local.get $3)
+                   )
+                   (i32.load offset=20
+                    (local.get $3)
+                   )
+                  )
+                 )
+                )
+                (i32.store offset=4
+                 (local.get $3)
+                 (i32.const 69)
+                )
+                (i32.store offset=32
+                 (local.get $3)
+                 (i32.const 0)
+                )
+                (br $label$16)
+               )
+               (local.set $5
+                (i32.add
+                 (i32.shl
+                  (i32.load offset=48
+                   (local.get $3)
+                  )
+                  (i32.const 12)
+                 )
+                 (i32.const -30720)
+                )
+               )
+               (local.set $2
+                (i32.const 0)
+               )
+               (block $label$24
+                (br_if $label$24
+                 (i32.gt_s
+                  (i32.load offset=136
+                   (local.get $3)
+                  )
+                  (i32.const 1)
+                 )
+                )
+                (br_if $label$24
+                 (i32.lt_s
+                  (local.tee $6
+                   (i32.load offset=132
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 2)
+                 )
+                )
+                (local.set $2
+                 (i32.const 64)
+                )
+                (br_if $label$24
+                 (i32.lt_s
+                  (local.get $6)
+                  (i32.const 6)
+                 )
+                )
+                (local.set $2
+                 (select
+                  (i32.const 128)
+                  (i32.const 192)
+                  (i32.eq
+                   (local.get $6)
+                   (i32.const 6)
+                  )
+                 )
+                )
+               )
+               (i32.store offset=4
+                (local.get $3)
+                (i32.const 113)
+               )
+               (i32.store offset=20
+                (local.get $3)
+                (i32.add
+                 (local.tee $6
+                  (i32.load offset=20
+                   (local.get $3)
+                  )
+                 )
+                 (i32.const 1)
+                )
+               )
+               (i32.store8
+                (i32.add
+                 (local.get $6)
+                 (i32.load offset=8
+                  (local.get $3)
+                 )
+                )
+                (i32.shr_u
+                 (local.tee $2
+                  (select
+                   (i32.or
+                    (local.tee $2
+                     (i32.or
+                      (local.get $2)
+                      (local.get $5)
+                     )
+                    )
+                    (i32.const 32)
+                   )
+                   (local.get $2)
+                   (i32.load offset=108
+                    (local.get $3)
+                   )
+                  )
+                 )
+                 (i32.const 8)
+                )
+               )
+               (i32.store offset=20
+                (local.get $3)
+                (i32.add
+                 (local.tee $5
+                  (i32.load offset=20
+                   (local.get $3)
+                  )
+                 )
+                 (i32.const 1)
+                )
+               )
+               (i32.store8
+                (i32.add
+                 (local.get $5)
+                 (i32.load offset=8
+                  (local.get $3)
+                 )
+                )
+                (i32.xor
+                 (i32.or
+                  (i32.rem_u
+                   (local.get $2)
+                   (i32.const 31)
+                  )
+                  (local.get $2)
+                 )
+                 (i32.const 31)
+                )
+               )
+               (block $label$25
+                (br_if $label$25
+                 (i32.eqz
+                  (i32.load offset=108
+                   (local.get $3)
+                  )
+                 )
+                )
+                (local.set $2
+                 (i32.load offset=48
+                  (local.get $0)
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $3)
+                 (i32.add
+                  (local.tee $5
+                   (i32.load offset=20
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 1)
+                 )
+                )
+                (i32.store8
+                 (i32.add
+                  (local.get $5)
+                  (i32.load offset=8
+                   (local.get $3)
+                  )
+                 )
+                 (i32.shr_u
+                  (local.get $2)
+                  (i32.const 24)
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $3)
+                 (i32.add
+                  (local.tee $5
+                   (i32.load offset=20
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 1)
+                 )
+                )
+                (i32.store8
+                 (i32.add
+                  (local.get $5)
+                  (i32.load offset=8
+                   (local.get $3)
+                  )
+                 )
+                 (i32.shr_u
+                  (local.get $2)
+                  (i32.const 16)
+                 )
+                )
+                (local.set $2
+                 (i32.load offset=48
+                  (local.get $0)
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $3)
+                 (i32.add
+                  (local.tee $5
+                   (i32.load offset=20
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 1)
+                 )
+                )
+                (i32.store8
+                 (i32.add
+                  (local.get $5)
+                  (i32.load offset=8
+                   (local.get $3)
+                  )
+                 )
+                 (i32.shr_u
+                  (local.get $2)
+                  (i32.const 8)
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $3)
+                 (i32.add
+                  (local.tee $5
+                   (i32.load offset=20
+                    (local.get $3)
+                   )
+                  )
+                  (i32.const 1)
+                 )
+                )
+                (i32.store8
+                 (i32.add
+                  (local.get $5)
+                  (i32.load offset=8
+                   (local.get $3)
+                  )
+                 )
+                 (local.get $2)
+                )
+               )
+               (i32.store offset=48
+                (local.get $0)
+                (call $fimport$15
+                 (i32.const 0)
+                 (i32.const 0)
+                 (i32.const 0)
+                )
+               )
+               (local.set $2
+                (i32.load offset=4
+                 (local.get $3)
+                )
+               )
+              )
+              (br_if $label$15
+               (i32.ne
+                (local.get $2)
+                (i32.const 69)
+               )
+              )
+             )
+             (block $label$26
+              (block $label$27
+               (br_if $label$27
+                (i32.eqz
+                 (i32.load offset=16
+                  (local.tee $5
+                   (i32.load offset=28
+                    (local.get $3)
+                   )
+                  )
+                 )
+                )
+               )
+               (local.set $2
+                (i32.load offset=20
+                 (local.get $3)
+                )
+               )
+               (br_if $label$26
+                (i32.ge_u
+                 (local.tee $6
+                  (i32.load offset=32
+                   (local.get $3)
+                  )
+                 )
+                 (i32.load16_u offset=20
+                  (local.get $5)
+                 )
+                )
+               )
+               (local.set $7
+                (local.get $2)
+               )
+               (loop $label$28
+                (block $label$29
+                 (br_if $label$29
+                  (i32.ne
+                   (local.get $2)
+                   (i32.load offset=12
+                    (local.get $3)
+                   )
+                  )
+                 )
+                 (block $label$30
+                  (br_if $label$30
+                   (i32.le_u
+                    (local.get $2)
+                    (local.get $7)
+                   )
+                  )
+                  (br_if $label$30
+                   (i32.eqz
+                    (i32.load offset=44
+                     (local.get $5)
+                    )
+                   )
+                  )
+                  (i32.store offset=48
+                   (local.get $0)
+                   (call $fimport$14
+                    (i32.load offset=48
+                     (local.get $0)
+                    )
+                    (i32.add
+                     (i32.load offset=8
+                      (local.get $3)
+                     )
+                     (local.get $7)
+                    )
+                    (i32.sub
+                     (local.get $2)
+                     (local.get $7)
+                    )
+                   )
+                  )
+                 )
+                 (block $label$31
+                  (br_if $label$31
+                   (i32.eqz
+                    (local.tee $2
+                     (select
+                      (local.tee $2
+                       (i32.load offset=16
+                        (local.get $0)
+                       )
+                      )
+                      (local.tee $5
+                       (i32.load offset=20
+                        (local.tee $6
+                         (i32.load offset=28
+                          (local.get $0)
+                         )
+                        )
+                       )
+                      )
+                      (i32.gt_u
+                       (local.get $5)
+                       (local.get $2)
+                      )
+                     )
+                    )
+                   )
+                  )
+                  (drop
+                   (call $fimport$98
+                    (i32.load offset=12
+                     (local.get $0)
+                    )
+                    (i32.load offset=16
+                     (local.get $6)
+                    )
+                    (local.get $2)
+                   )
+                  )
+                  (i32.store offset=12
+                   (local.get $0)
+                   (i32.add
+                    (i32.load offset=12
+                     (local.get $0)
+                    )
+                    (local.get $2)
+                   )
+                  )
+                  (i32.store offset=16
+                   (local.tee $5
+                    (i32.load offset=28
+                     (local.get $0)
+                    )
+                   )
+                   (i32.add
+                    (i32.load offset=16
+                     (local.get $5)
+                    )
+                    (local.get $2)
+                   )
+                  )
+                  (i32.store offset=20
+                   (local.get $0)
+                   (i32.add
+                    (i32.load offset=20
+                     (local.get $0)
+                    )
+                    (local.get $2)
+                   )
+                  )
+                  (i32.store offset=16
+                   (local.get $0)
+                   (i32.sub
+                    (i32.load offset=16
+                     (local.get $0)
+                    )
+                    (local.get $2)
+                   )
+                  )
+                  (i32.store offset=20
+                   (local.get $5)
+                   (local.tee $2
+                    (i32.sub
+                     (i32.load offset=20
+                      (local.get $5)
+                     )
+                     (local.get $2)
+                    )
+                   )
+                  )
+                  (br_if $label$31
+                   (local.get $2)
+                  )
+                  (i32.store offset=16
+                   (local.get $5)
+                   (i32.load offset=8
+                    (local.get $5)
+                   )
+                  )
+                 )
+                 (local.set $5
+                  (i32.load offset=28
+                   (local.get $3)
+                  )
+                 )
+                 (br_if $label$26
+                  (i32.eq
+                   (local.tee $2
+                    (i32.load offset=20
+                     (local.get $3)
+                    )
+                   )
+                   (i32.load offset=12
+                    (local.get $3)
+                   )
+                  )
+                 )
+                 (local.set $6
+                  (i32.load offset=32
+                   (local.get $3)
+                  )
+                 )
+                 (local.set $7
+                  (local.get $2)
+                 )
+                )
+                (local.set $5
+                 (i32.load8_u
+                  (i32.add
+                   (i32.load offset=16
+                    (local.get $5)
+                   )
+                   (local.get $6)
+                  )
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $3)
+                 (i32.add
+                  (local.get $2)
+                  (i32.const 1)
+                 )
+                )
+                (i32.store8
+                 (i32.add
+                  (i32.load offset=8
+                   (local.get $3)
+                  )
+                  (local.get $2)
+                 )
+                 (local.get $5)
+                )
+                (i32.store offset=32
+                 (local.get $3)
+                 (local.tee $6
+                  (i32.add
+                   (i32.load offset=32
+                    (local.get $3)
+                   )
+                   (i32.const 1)
+                  )
+                 )
+                )
+                (block $label$32
+                 (br_if $label$32
+                  (i32.lt_u
+                   (local.get $6)
+                   (i32.load16_u offset=20
+                    (local.tee $5
+                     (i32.load offset=28
+                      (local.get $3)
+                     )
+                    )
+                   )
+                  )
+                 )
+                 (local.set $2
+                  (local.get $7)
+                 )
+                 (br $label$26)
+                )
+                (local.set $2
+                 (i32.load offset=20
+                  (local.get $3)
+                 )
+                )
+                (br $label$28)
+               )
+              )
+              (i32.store offset=4
+               (local.get $3)
+               (i32.const 73)
+              )
+              (br $label$14)
+             )
+             (block $label$33
+              (br_if $label$33
+               (i32.eqz
+                (i32.load offset=44
+                 (local.get $5)
+                )
+               )
+              )
+              (br_if $label$33
+               (i32.le_u
+                (local.tee $6
+                 (i32.load offset=20
+                  (local.get $3)
+                 )
+                )
+                (local.get $2)
+               )
+              )
+              (i32.store offset=48
+               (local.get $0)
+               (call $fimport$14
+                (i32.load offset=48
+                 (local.get $0)
+                )
+                (i32.add
+                 (i32.load offset=8
+                  (local.get $3)
+                 )
+                 (local.get $2)
+                )
+                (i32.sub
+                 (local.get $6)
+                 (local.get $2)
+                )
+               )
+              )
+              (local.set $5
+               (i32.load offset=28
+                (local.get $3)
+               )
+              )
+             )
+             (block $label$34
+              (br_if $label$34
+               (i32.ne
+                (i32.load offset=32
+                 (local.get $3)
+                )
+                (i32.load offset=20
+                 (local.get $5)
+                )
+               )
+              )
+              (i32.store offset=4
+               (local.get $3)
+               (i32.const 73)
+              )
+              (i32.store offset=32
+               (local.get $3)
+               (i32.const 0)
+              )
+              (br $label$14)
+             )
+             (local.set $2
+              (i32.load offset=4
+               (local.get $3)
+              )
+             )
+            )
+            (br_if $label$13
+             (i32.ne
+              (local.get $2)
+              (i32.const 73)
+             )
+            )
+            (local.set $5
+             (i32.load offset=28
+              (local.get $3)
+             )
+            )
+           )
+           (br_if $label$11
+            (i32.eqz
+             (i32.load offset=28
+              (local.get $5)
+             )
+            )
+           )
+           (local.set $7
+            (local.tee $2
+             (i32.load offset=20
+              (local.get $3)
+             )
+            )
+           )
+           (block $label$35
+            (block $label$36
+             (loop $label$37
+              (block $label$38
+               (br_if $label$38
+                (i32.ne
+                 (local.get $2)
+                 (i32.load offset=12
+                  (local.get $3)
+                 )
+                )
+               )
+               (block $label$39
+                (br_if $label$39
+                 (i32.le_u
+                  (local.get $2)
+                  (local.get $7)
+                 )
+                )
+                (br_if $label$39
+                 (i32.eqz
+                  (i32.load offset=44
+                   (i32.load offset=28
+                    (local.get $3)
+                   )
+                  )
+                 )
+                )
+                (i32.store offset=48
+                 (local.get $0)
+                 (call $fimport$14
+                  (i32.load offset=48
+                   (local.get $0)
+                  )
+                  (i32.add
+                   (i32.load offset=8
+                    (local.get $3)
+                   )
+                   (local.get $7)
+                  )
+                  (i32.sub
+                   (local.get $2)
+                   (local.get $7)
+                  )
+                 )
+                )
+               )
+               (block $label$40
+                (br_if $label$40
+                 (i32.eqz
+                  (local.tee $2
+                   (select
+                    (local.tee $2
+                     (i32.load offset=16
+                      (local.get $0)
+                     )
+                    )
+                    (local.tee $5
+                     (i32.load offset=20
+                      (local.tee $6
+                       (i32.load offset=28
+                        (local.get $0)
+                       )
+                      )
+                     )
+                    )
+                    (i32.gt_u
+                     (local.get $5)
+                     (local.get $2)
+                    )
+                   )
+                  )
+                 )
+                )
+                (drop
+                 (call $fimport$98
+                  (i32.load offset=12
+                   (local.get $0)
+                  )
+                  (i32.load offset=16
+                   (local.get $6)
+                  )
+                  (local.get $2)
+                 )
+                )
+                (i32.store offset=12
+                 (local.get $0)
+                 (i32.add
+                  (i32.load offset=12
+                   (local.get $0)
+                  )
+                  (local.get $2)
+                 )
+                )
+                (i32.store offset=16
+                 (local.tee $5
+                  (i32.load offset=28
+                   (local.get $0)
+                  )
+                 )
+                 (i32.add
+                  (i32.load offset=16
+                   (local.get $5)
+                  )
+                  (local.get $2)
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $0)
+                 (i32.add
+                  (i32.load offset=20
+                   (local.get $0)
+                  )
+                  (local.get $2)
+                 )
+                )
+                (i32.store offset=16
+                 (local.get $0)
+                 (i32.sub
+                  (i32.load offset=16
+                   (local.get $0)
+                  )
+                  (local.get $2)
+                 )
+                )
+                (i32.store offset=20
+                 (local.get $5)
+                 (local.tee $2
+                  (i32.sub
+                   (i32.load offset=20
+                    (local.get $5)
+                   )
+                   (local.get $2)
+                  )
+                 )
+                )
+                (br_if $label$40
+                 (local.get $2)
+                )
+                (i32.store offset=16
+                 (local.get $5)
+                 (i32.load offset=8
+                  (local.get $5)
+                 )
+                )
+               )
+               (br_if $label$36
+                (i32.eq
+                 (local.tee $2
+                  (i32.load offset=20
+                   (local.get $3)
+                  )
+                 )
+                 (i32.load offset=12
+                  (local.get $3)
+                 )
+                )
+               )
+               (local.set $7
+                (local.get $2)
+               )
+              )
+              (local.set $5
+               (i32.load offset=28
+                (i32.load offset=28
+                 (local.get $3)
+                )
+               )
+              )
+              (i32.store offset=32
+               (local.get $3)
+               (i32.add
+                (local.tee $6
+                 (i32.load offset=32
+                  (local.get $3)
+                 )
+                )
+                (i32.const 1)
+               )
+              )
+              (local.set $5
+               (i32.load8_u
+                (i32.add
+                 (local.get $5)
+                 (local.get $6)
+                )
+               )
+              )
+              (i32.store offset=20
+               (local.get $3)
+               (i32.add
+                (local.get $2)
+                (i32.const 1)
+               )
+              )
+              (i32.store8
+               (i32.add
+                (i32.load offset=8
+                 (local.get $3)
+                )
+                (local.get $2)
+               )
+               (local.get $5)
+              )
+              (block $label$41
+               (br_if $label$41
+                (local.get $5)
+               )
+               (local.set $5
+                (i32.const 0)
+               )
+               (local.set $2
+                (local.get $7)
+               )
+               (br $label$35)
+              )
+              (local.set $2
+               (i32.load offset=20
+                (local.get $3)
+               )
+              )
+              (br $label$37)
+             )
+            )
+            (local.set $5
+             (i32.const 1)
+            )
+           )
+           (block $label$42
+            (br_if $label$42
+             (i32.eqz
+              (i32.load offset=44
+               (i32.load offset=28
+                (local.get $3)
+               )
+              )
+             )
+            )
+            (br_if $label$42
+             (i32.le_u
+              (local.tee $6
+               (i32.load offset=20
+                (local.get $3)
+               )
+              )
+              (local.get $2)
+             )
+            )
+            (i32.store offset=48
+             (local.get $0)
+             (call $fimport$14
+              (i32.load offset=48
+               (local.get $0)
+              )
+              (i32.add
+               (i32.load offset=8
+                (local.get $3)
+               )
+               (local.get $2)
+              )
+              (i32.sub
+               (local.get $6)
+               (local.get $2)
+              )
+             )
+            )
+           )
+           (br_if $label$12
+            (i32.eqz
+             (local.get $5)
+            )
+           )
+           (local.set $2
+            (i32.load offset=4
+             (local.get $3)
+            )
+           )
+          )
+          (br_if $label$10
+           (i32.eq
+            (local.get $2)
+            (i32.const 91)
+           )
+          )
+          (br $label$9)
+         )
+         (i32.store offset=32
+          (local.get $3)
+          (i32.const 0)
+         )
+        )
+        (i32.store offset=4
+         (local.get $3)
+         (i32.const 91)
+        )
+       )
+       (br_if $label$8
+        (i32.eqz
+         (i32.load offset=36
+          (i32.load offset=28
+           (local.get $3)
+          )
+         )
+        )
+       )
+       (local.set $7
+        (local.tee $2
+         (i32.load offset=20
+          (local.get $3)
+         )
+        )
+       )
+       (block $label$43
+        (block $label$44
+         (loop $label$45
+          (block $label$46
+           (br_if $label$46
+            (i32.ne
+             (local.get $2)
+             (i32.load offset=12
+              (local.get $3)
+             )
+            )
+           )
+           (block $label$47
+            (br_if $label$47
+             (i32.le_u
+              (local.get $2)
+              (local.get $7)
+             )
+            )
+            (br_if $label$47
+             (i32.eqz
+              (i32.load offset=44
+               (i32.load offset=28
+                (local.get $3)
+               )
+              )
+             )
+            )
+            (i32.store offset=48
+             (local.get $0)
+             (call $fimport$14
+              (i32.load offset=48
+               (local.get $0)
+              )
+              (i32.add
+               (i32.load offset=8
+                (local.get $3)
+               )
+               (local.get $7)
+              )
+              (i32.sub
+               (local.get $2)
+               (local.get $7)
+              )
+             )
+            )
+           )
+           (block $label$48
+            (br_if $label$48
+             (i32.eqz
+              (local.tee $2
+               (select
+                (local.tee $2
+                 (i32.load offset=16
+                  (local.get $0)
+                 )
+                )
+                (local.tee $5
+                 (i32.load offset=20
+                  (local.tee $6
+                   (i32.load offset=28
+                    (local.get $0)
+                   )
+                  )
+                 )
+                )
+                (i32.gt_u
+                 (local.get $5)
+                 (local.get $2)
+                )
+               )
+              )
+             )
+            )
+            (drop
+             (call $fimport$98
+              (i32.load offset=12
+               (local.get $0)
+              )
+              (i32.load offset=16
+               (local.get $6)
+              )
+              (local.get $2)
+             )
+            )
+            (i32.store offset=12
+             (local.get $0)
+             (i32.add
+              (i32.load offset=12
+               (local.get $0)
+              )
+              (local.get $2)
+             )
+            )
+            (i32.store offset=16
+             (local.tee $5
+              (i32.load offset=28
+               (local.get $0)
+              )
+             )
+             (i32.add
+              (i32.load offset=16
+               (local.get $5)
+              )
+              (local.get $2)
+             )
+            )
+            (i32.store offset=20
+             (local.get $0)
+             (i32.add
+              (i32.load offset=20
+               (local.get $0)
+              )
+              (local.get $2)
+             )
+            )
+            (i32.store offset=16
+             (local.get $0)
+             (i32.sub
+              (i32.load offset=16
+               (local.get $0)
+              )
+              (local.get $2)
+             )
+            )
+            (i32.store offset=20
+             (local.get $5)
+             (local.tee $2
+              (i32.sub
+               (i32.load offset=20
+                (local.get $5)
+               )
+               (local.get $2)
+              )
+             )
+            )
+            (br_if $label$48
+             (local.get $2)
+            )
+            (i32.store offset=16
+             (local.get $5)
+             (i32.load offset=8
+              (local.get $5)
+             )
+            )
+           )
+           (br_if $label$44
+            (i32.eq
+             (local.tee $2
+              (i32.load offset=20
+               (local.get $3)
+              )
+             )
+             (i32.load offset=12
+              (local.get $3)
+             )
+            )
+           )
+           (local.set $7
+            (local.get $2)
+           )
+          )
+          (local.set $5
+           (i32.load offset=36
+            (i32.load offset=28
+             (local.get $3)
+            )
+           )
+          )
+          (i32.store offset=32
+           (local.get $3)
+           (i32.add
+            (local.tee $6
+             (i32.load offset=32
+              (local.get $3)
+             )
+            )
+            (i32.const 1)
+           )
+          )
+          (local.set $5
+           (i32.load8_u
+            (i32.add
+             (local.get $5)
+             (local.get $6)
+            )
+           )
+          )
+          (i32.store offset=20
+           (local.get $3)
+           (i32.add
+            (local.get $2)
+            (i32.const 1)
+           )
+          )
+          (i32.store8
+           (i32.add
+            (i32.load offset=8
+             (local.get $3)
+            )
+            (local.get $2)
+           )
+           (local.get $5)
+          )
+          (block $label$49
+           (br_if $label$49
+            (local.get $5)
+           )
+           (local.set $5
+            (i32.const 0)
+           )
+           (local.set $2
+            (local.get $7)
+           )
+           (br $label$43)
+          )
+          (local.set $2
+           (i32.load offset=20
+            (local.get $3)
+           )
+          )
+          (br $label$45)
+         )
+        )
+        (local.set $5
+         (i32.const 1)
+        )
+       )
+       (block $label$50
+        (br_if $label$50
+         (i32.eqz
+          (i32.load offset=44
+           (i32.load offset=28
+            (local.get $3)
+           )
+          )
+         )
+        )
+        (br_if $label$50
+         (i32.le_u
+          (local.tee $6
+           (i32.load offset=20
+            (local.get $3)
+           )
+          )
+          (local.get $2)
+         )
+        )
+        (i32.store offset=48
+         (local.get $0)
+         (call $fimport$14
+          (i32.load offset=48
+           (local.get $0)
+          )
+          (i32.add
+           (i32.load offset=8
+            (local.get $3)
+           )
+           (local.get $2)
+          )
+          (i32.sub
+           (local.get $6)
+           (local.get $2)
+          )
+         )
+        )
+       )
+       (br_if $label$8
+        (i32.eqz
+         (local.get $5)
+        )
+       )
+       (local.set $2
+        (i32.load offset=4
+         (local.get $3)
+        )
+       )
+      )
+      (br_if $label$7
+       (i32.eq
+        (local.get $2)
+        (i32.const 103)
+       )
+      )
+      (br $label$6)
+     )
+     (i32.store offset=4
+      (local.get $3)
+      (i32.const 103)
+     )
+    )
+    (block $label$51
+     (br_if $label$51
+      (i32.eqz
+       (i32.load offset=44
+        (i32.load offset=28
+         (local.get $3)
+        )
+       )
+      )
+     )
+     (block $label$52
+      (br_if $label$52
+       (i32.le_u
+        (i32.add
+         (i32.load offset=20
+          (local.get $3)
+         )
+         (i32.const 2)
+        )
+        (i32.load offset=12
+         (local.get $3)
+        )
+       )
+      )
+      (br_if $label$52
+       (i32.eqz
+        (local.tee $2
+         (select
+          (local.tee $2
+           (i32.load offset=16
+            (local.get $0)
+           )
+          )
+          (local.tee $5
+           (i32.load offset=20
+            (local.tee $6
+             (i32.load offset=28
+              (local.get $0)
+             )
+            )
+           )
+          )
+          (i32.gt_u
+           (local.get $5)
+           (local.get $2)
+          )
+         )
+        )
+       )
+      )
+      (drop
+       (call $fimport$98
+        (i32.load offset=12
+         (local.get $0)
+        )
+        (i32.load offset=16
+         (local.get $6)
+        )
+        (local.get $2)
+       )
+      )
+      (i32.store offset=12
+       (local.get $0)
+       (i32.add
+        (i32.load offset=12
+         (local.get $0)
+        )
+        (local.get $2)
+       )
+      )
+      (i32.store offset=16
+       (local.tee $5
+        (i32.load offset=28
+         (local.get $0)
+        )
+       )
+       (i32.add
+        (i32.load offset=16
+         (local.get $5)
+        )
+        (local.get $2)
+       )
+      )
+      (i32.store offset=20
+       (local.get $0)
+       (i32.add
+        (i32.load offset=20
+         (local.get $0)
+        )
+        (local.get $2)
+       )
+      )
+      (i32.store offset=16
+       (local.get $0)
+       (i32.sub
+        (i32.load offset=16
+         (local.get $0)
+        )
+        (local.get $2)
+       )
+      )
+      (i32.store offset=20
+       (local.get $5)
+       (local.tee $2
+        (i32.sub
+         (i32.load offset=20
+          (local.get $5)
+         )
+         (local.get $2)
+        )
+       )
+      )
+      (br_if $label$52
+       (local.get $2)
+      )
+      (i32.store offset=16
+       (local.get $5)
+       (i32.load offset=8
+        (local.get $5)
+       )
+      )
+     )
+     (br_if $label$6
+      (i32.gt_u
+       (i32.add
+        (local.tee $2
+         (i32.load offset=20
+          (local.get $3)
+         )
+        )
+        (i32.const 2)
+       )
+       (i32.load offset=12
+        (local.get $3)
+       )
+      )
+     )
+     (local.set $5
+      (i32.load offset=48
+       (local.get $0)
+      )
+     )
+     (i32.store offset=20
+      (local.get $3)
+      (i32.add
+       (local.get $2)
+       (i32.const 1)
+      )
+     )
+     (i32.store8
+      (i32.add
+       (i32.load offset=8
+        (local.get $3)
+       )
+       (local.get $2)
+      )
+      (local.get $5)
+     )
+     (local.set $2
+      (i32.load offset=48
+       (local.get $0)
+      )
+     )
+     (i32.store offset=20
+      (local.get $3)
+      (i32.add
+       (local.tee $5
+        (i32.load offset=20
+         (local.get $3)
+        )
+       )
+       (i32.const 1)
+      )
+     )
+     (i32.store8
+      (i32.add
+       (local.get $5)
+       (i32.load offset=8
+        (local.get $3)
+       )
+      )
+      (i32.shr_u
+       (local.get $2)
+       (i32.const 8)
+      )
+     )
+     (i32.store offset=48
+      (local.get $0)
+      (call $fimport$14
+       (i32.const 0)
+       (i32.const 0)
+       (i32.const 0)
+      )
+     )
+     (i32.store offset=4
+      (local.get $3)
+      (i32.const 113)
+     )
+     (br $label$6)
+    )
+    (i32.store offset=4
+     (local.get $3)
+     (i32.const 113)
+    )
+   )
+   (block $label$53
+    (block $label$54
+     (br_if $label$54
+      (i32.eqz
+       (i32.load offset=20
+        (local.get $3)
+       )
+      )
+     )
+     (block $label$55
+      (br_if $label$55
+       (i32.eqz
+        (local.tee $2
+         (select
+          (local.tee $5
+           (i32.load offset=16
+            (local.get $0)
+           )
+          )
+          (local.tee $2
+           (i32.load offset=20
+            (local.tee $6
+             (i32.load offset=28
+              (local.get $0)
+             )
+            )
+           )
+          )
+          (i32.gt_u
+           (local.get $2)
+           (local.get $5)
+          )
+         )
+        )
+       )
+      )
+      (drop
+       (call $fimport$98
+        (i32.load offset=12
+         (local.get $0)
+        )
+        (i32.load offset=16
+         (local.get $6)
+        )
+        (local.get $2)
+       )
+      )
+      (i32.store offset=12
+       (local.get $0)
+       (i32.add
+        (i32.load offset=12
+         (local.get $0)
+        )
+        (local.get $2)
+       )
+      )
+      (i32.store offset=16
+       (local.tee $6
+        (i32.load offset=28
+         (local.get $0)
+        )
+       )
+       (i32.add
+        (i32.load offset=16
+         (local.get $6)
+        )
+        (local.get $2)
+       )
+      )
+      (i32.store offset=20
+       (local.get $0)
+       (i32.add
+        (i32.load offset=20
+         (local.get $0)
+        )
+        (local.get $2)
+       )
+      )
+      (i32.store offset=16
+       (local.get $0)
+       (local.tee $5
+        (i32.sub
+         (i32.load offset=16
+          (local.get $0)
+         )
+         (local.get $2)
+        )
+       )
+      )
+      (i32.store offset=20
+       (local.get $6)
+       (local.tee $2
+        (i32.sub
+         (i32.load offset=20
+          (local.get $6)
+         )
+         (local.get $2)
+        )
+       )
+      )
+      (br_if $label$55
+       (local.get $2)
+      )
+      (i32.store offset=16
+       (local.get $6)
+       (i32.load offset=8
+        (local.get $6)
+       )
+      )
+     )
+     (br_if $label$53
+      (local.get $5)
+     )
+     (i32.store offset=40
+      (local.get $3)
+      (i32.const -1)
+     )
+     (return
+      (i32.const 0)
+     )
+    )
+    (br_if $label$53
+     (i32.eq
+      (local.get $1)
+      (i32.const 4)
+     )
+    )
+    (br_if $label$53
+     (i32.lt_s
+      (local.get $4)
+      (local.get $1)
+     )
+    )
+    (br_if $label$53
+     (i32.load offset=4
+      (local.get $0)
+     )
+    )
+    (i32.store offset=24
+     (local.get $0)
+     (i32.load offset=17004
+      (i32.const 0)
+     )
+    )
+    (return
+     (i32.const -5)
+    )
+   )
+   (local.set $2
+    (i32.load offset=4
+     (local.get $0)
+    )
+   )
+   (block $label$56
+    (block $label$57
+     (block $label$58
+      (block $label$59
+       (br_if $label$59
+        (i32.ne
+         (local.tee $5
+          (i32.load offset=4
+           (local.get $3)
+          )
+         )
+         (i32.const 666)
+        )
+       )
+       (br_if $label$58
+        (i32.eqz
+         (local.get $2)
+        )
+       )
+       (i32.store offset=24
+        (local.get $0)
+        (i32.load offset=17004
+         (i32.const 0)
+        )
+       )
+       (return
+        (i32.const -5)
+       )
+      )
+      (br_if $label$57
+       (local.get $2)
+      )
+     )
+     (br_if $label$57
+      (i32.ne
+       (i32.or
+        (i32.eqz
+         (local.get $1)
+        )
+        (i32.eq
+         (local.get $5)
+         (i32.const 666)
+        )
+       )
+       (i32.const 1)
+      )
+     )
+     (br_if $label$56
+      (i32.eqz
+       (i32.load offset=116
+        (local.get $3)
+       )
+      )
+     )
+    )
+    (block $label$60
+     (block $label$61
+      (block $label$62
+       (br_if $label$62
+        (i32.eq
+         (local.tee $2
+          (i32.load offset=136
+           (local.get $3)
+          )
+         )
+         (i32.const 3)
+        )
+       )
+       (br_if $label$61
+        (i32.ne
+         (local.get $2)
+         (i32.const 2)
+        )
+       )
+       (local.set $2
+        (call $fimport$20
+         (local.get $3)
+         (local.get $1)
+        )
+       )
+       (br $label$60)
+      )
+      (local.set $2
+       (call $fimport$21
+        (local.get $3)
+        (local.get $1)
+       )
+      )
+      (br $label$60)
+     )
+     (local.set $2
+      (call_indirect (type $2)
+       (local.get $3)
+       (local.get $1)
+       (i32.load
+        (i32.add
+         (i32.mul
+          (i32.load offset=132
+           (local.get $3)
+          )
+          (i32.const 12)
+         )
+         (i32.const 11032)
+        )
+       )
+      )
+     )
+    )
+    (block $label$63
+     (br_if $label$63
+      (i32.ne
+       (i32.or
+        (local.get $2)
+        (i32.const 1)
+       )
+       (i32.const 3)
+      )
+     )
+     (i32.store offset=4
+      (local.get $3)
+      (i32.const 666)
+     )
+    )
+    (block $label$64
+     (br_if $label$64
+      (i32.and
+       (local.get $2)
+       (i32.const -3)
+      )
+     )
+     (local.set $2
+      (i32.const 0)
+     )
+     (br_if $label$1
+      (i32.load offset=16
+       (local.get $0)
+      )
+     )
+     (i32.store offset=40
+      (local.get $3)
+      (i32.const -1)
+     )
+     (return
+      (i32.const 0)
+     )
+    )
+    (br_if $label$56
+     (i32.ne
+      (local.get $2)
+      (i32.const 1)
+     )
+    )
+    (block $label$65
+     (br_if $label$65
+      (i32.eq
+       (local.get $1)
+       (i32.const 5)
+      )
+     )
+     (block $label$66
+      (br_if $label$66
+       (i32.ne
+        (local.get $1)
+        (i32.const 1)
+       )
+      )
+      (call $fimport$30
+       (local.get $3)
+      )
+      (br $label$65)
+     )
+     (call $fimport$29
+      (local.get $3)
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 0)
+     )
+     (br_if $label$65
+      (i32.ne
+       (local.get $1)
+       (i32.const 3)
+      )
+     )
+     (i32.store16
+      (i32.add
+       (local.tee $2
+        (i32.load offset=68
+         (local.get $3)
+        )
+       )
+       (local.tee $5
+        (i32.add
+         (i32.shl
+          (i32.load offset=76
+           (local.get $3)
+          )
+          (i32.const 1)
+         )
+         (i32.const -2)
+        )
+       )
+      )
+      (i32.const 0)
+     )
+     (drop
+      (call $fimport$97
+       (local.get $2)
+       (i32.const 0)
+       (local.get $5)
+      )
+     )
+     (br_if $label$65
+      (i32.load offset=116
+       (local.get $3)
+      )
+     )
+     (i32.store offset=92
+      (local.get $3)
+      (i32.const 0)
+     )
+     (i32.store offset=108
+      (local.get $3)
+      (i32.const 0)
+     )
+    )
+    (block $label$67
+     (br_if $label$67
+      (i32.eqz
+       (local.tee $2
+        (select
+         (local.tee $5
+          (i32.load offset=16
+           (local.get $0)
+          )
+         )
+         (local.tee $2
+          (i32.load offset=20
+           (local.tee $6
+            (i32.load offset=28
+             (local.get $0)
+            )
+           )
+          )
+         )
+         (i32.gt_u
+          (local.get $2)
+          (local.get $5)
+         )
+        )
+       )
+      )
+     )
+     (drop
+      (call $fimport$98
+       (i32.load offset=12
+        (local.get $0)
+       )
+       (i32.load offset=16
+        (local.get $6)
+       )
+       (local.get $2)
+      )
+     )
+     (i32.store offset=12
+      (local.get $0)
+      (i32.add
+       (i32.load offset=12
+        (local.get $0)
+       )
+       (local.get $2)
+      )
+     )
+     (i32.store offset=16
+      (local.tee $6
+       (i32.load offset=28
+        (local.get $0)
+       )
+      )
+      (i32.add
+       (i32.load offset=16
+        (local.get $6)
+       )
+       (local.get $2)
+      )
+     )
+     (i32.store offset=20
+      (local.get $0)
+      (i32.add
+       (i32.load offset=20
+        (local.get $0)
+       )
+       (local.get $2)
+      )
+     )
+     (i32.store offset=16
+      (local.get $0)
+      (local.tee $5
+       (i32.sub
+        (i32.load offset=16
+         (local.get $0)
+        )
+        (local.get $2)
+       )
+      )
+     )
+     (i32.store offset=20
+      (local.get $6)
+      (local.tee $2
+       (i32.sub
+        (i32.load offset=20
+         (local.get $6)
+        )
+        (local.get $2)
+       )
+      )
+     )
+     (br_if $label$67
+      (local.get $2)
+     )
+     (i32.store offset=16
+      (local.get $6)
+      (i32.load offset=8
+       (local.get $6)
+      )
+     )
+    )
+    (br_if $label$56
+     (local.get $5)
+    )
+    (i32.store offset=40
+     (local.get $3)
+     (i32.const -1)
+    )
+    (return
+     (i32.const 0)
+    )
+   )
+   (local.set $2
+    (i32.const 0)
+   )
+   (br_if $label$1
+    (i32.ne
+     (local.get $1)
+     (i32.const 4)
+    )
+   )
+   (local.set $2
+    (i32.const 1)
+   )
+   (br_if $label$1
+    (i32.lt_s
+     (local.tee $1
+      (i32.load offset=24
+       (local.get $3)
+      )
+     )
+     (i32.const 1)
+    )
+   )
+   (local.set $2
+    (i32.load offset=48
+     (local.get $0)
+    )
+   )
+   (block $label$68
+    (block $label$69
+     (br_if $label$69
+      (i32.ne
+       (local.get $1)
+       (i32.const 2)
+      )
+     )
+     (i32.store offset=20
+      (local.get $3)
+      (i32.add
+       (local.tee $1
+        (i32.load offset=20
+         (local.get $3)
+        )
+       )
+       (i32.const 1)
+      )
+     )
+     (i32.store8
+      (i32.add
+       (local.get $1)
+       (i32.load offset=8
+        (local.get $3)
+       )
+      )
+      (local.get $2)
+     )
+     (local.set $2
+      (i32.load offset=48
+       (local.get $0)
+      )
+     )
+     (i32.store offset=20
+      (local.get $3)
+      (i32.add
+       (local.tee $1
+        (i32.load offset=20
+         (local.get $3)
+        )
+       )
+       (i32.const 1)
+      )
+     )
+     (i32.store8
+      (i32.add
+       (local.get $1)
+       (i32.load offset=8
+        (local.get $3)
+       )
+      )
+      (i32.shr_u
+       (local.get $2)
+       (i32.const 8)
+      )
+     )
+     (local.set $2
+      (i32.load16_u
+       (i32.add
+        (local.get $0)
+        (i32.const 50)
+       )
+      )
+     )
+     (i32.store offset=20
+      (local.get $3)
+      (i32.add
+       (local.tee $1
+        (i32.load offset=20
+         (local.get $3)
+        )
+       )
+       (i32.const 1)
+      )
+     )
+     (i32.store8
+      (i32.add
+       (local.get $1)
+       (i32.load offset=8
+        (local.get $3)
+       )
+      )
+      (local.get $2)
+     )
+     (local.set $2
+      (i32.load8_u
+       (i32.add
+        (local.get $0)
+        (i32.const 51)
+       )
+      )
+     )
+     (i32.store offset=20
+      (local.get $3)
+      (i32.add
+       (local.tee $1
+        (i32.load offset=20
+         (local.get $3)
+        )
+       )
+       (i32.const 1)
+      )
+     )
+     (i32.store8
+      (i32.add
+       (local.get $1)
+       (i32.load offset=8
+        (local.get $3)
+       )
+      )
+      (local.get $2)
+     )
+     (local.set $2
+      (i32.load offset=8
+       (local.get $0)
+      )
+     )
+     (i32.store offset=20
+      (local.get $3)
+      (i32.add
+       (local.tee $1
+        (i32.load offset=20
+         (local.get $3)
+        )
+       )
+       (i32.const 1)
+      )
+     )
+     (i32.store8
+      (i32.add
+       (local.get $1)
+       (i32.load offset=8
+        (local.get $3)
+       )
+      )
+      (local.get $2)
+     )
+     (local.set $2
+      (i32.load offset=8
+       (local.get $0)
+      )
+     )
+     (i32.store offset=20
+      (local.get $3)
+      (i32.add
+       (local.tee $1
+        (i32.load offset=20
+         (local.get $3)
+        )
+       )
+       (i32.const 1)
+      )
+     )
+     (i32.store8
+      (i32.add
+       (local.get $1)
+       (i32.load offset=8
+        (local.get $3)
+       )
+      )
+      (i32.shr_u
+       (local.get $2)
+       (i32.const 8)
+      )
+     )
+     (local.set $2
+      (i32.load16_u
+       (i32.add
+        (local.get $0)
+        (i32.const 10)
+       )
+      )
+     )
+     (i32.store offset=20
+      (local.get $3)
+      (i32.add
+       (local.tee $1
+        (i32.load offset=20
+         (local.get $3)
+        )
+       )
+       (i32.const 1)
+      )
+     )
+     (i32.store8
+      (i32.add
+       (local.get $1)
+       (i32.load offset=8
+        (local.get $3)
+       )
+      )
+      (local.get $2)
+     )
+     (local.set $2
+      (i32.load8_u
+       (i32.add
+        (local.get $0)
+        (i32.const 11)
+       )
+      )
+     )
+     (i32.store offset=20
+      (local.get $3)
+      (i32.add
+       (local.tee $1
+        (i32.load offset=20
+         (local.get $3)
+        )
+       )
+       (i32.const 1)
+      )
+     )
+     (local.set $1
+      (i32.add
+       (local.get $1)
+       (i32.load offset=8
+        (local.get $3)
+       )
+      )
+     )
+     (br $label$68)
+    )
+    (i32.store offset=20
+     (local.get $3)
+     (i32.add
+      (local.tee $1
+       (i32.load offset=20
+        (local.get $3)
+       )
+      )
+      (i32.const 1)
+     )
+    )
+    (i32.store8
+     (i32.add
+      (local.get $1)
+      (i32.load offset=8
+       (local.get $3)
+      )
+     )
+     (i32.shr_u
+      (local.get $2)
+      (i32.const 24)
+     )
+    )
+    (i32.store offset=20
+     (local.get $3)
+     (i32.add
+      (local.tee $1
+       (i32.load offset=20
+        (local.get $3)
+       )
+      )
+      (i32.const 1)
+     )
+    )
+    (i32.store8
+     (i32.add
+      (local.get $1)
+      (i32.load offset=8
+       (local.get $3)
+      )
+     )
+     (i32.shr_u
+      (local.get $2)
+      (i32.const 16)
+     )
+    )
+    (local.set $2
+     (i32.load offset=48
+      (local.get $0)
+     )
+    )
+    (i32.store offset=20
+     (local.get $3)
+     (i32.add
+      (local.tee $1
+       (i32.load offset=20
+        (local.get $3)
+       )
+      )
+      (i32.const 1)
+     )
+    )
+    (i32.store8
+     (i32.add
+      (local.get $1)
+      (i32.load offset=8
+       (local.get $3)
+      )
+     )
+     (i32.shr_u
+      (local.get $2)
+      (i32.const 8)
+     )
+    )
+    (i32.store offset=20
+     (local.get $3)
+     (i32.add
+      (local.tee $1
+       (i32.load offset=20
+        (local.get $3)
+       )
+      )
+      (i32.const 1)
+     )
+    )
+    (local.set $1
+     (i32.add
+      (local.get $1)
+      (i32.load offset=8
+       (local.get $3)
+      )
+     )
+    )
+   )
+   (i32.store8
+    (local.get $1)
+    (local.get $2)
+   )
+   (block $label$70
+    (br_if $label$70
+     (i32.eqz
+      (local.tee $2
+       (select
+        (local.tee $2
+         (i32.load offset=16
+          (local.get $0)
+         )
+        )
+        (local.tee $1
+         (i32.load offset=20
+          (local.tee $5
+           (i32.load offset=28
+            (local.get $0)
+           )
+          )
+         )
+        )
+        (i32.gt_u
+         (local.get $1)
+         (local.get $2)
+        )
+       )
+      )
+     )
+    )
+    (drop
+     (call $fimport$98
+      (i32.load offset=12
+       (local.get $0)
+      )
+      (i32.load offset=16
+       (local.get $5)
+      )
+      (local.get $2)
+     )
+    )
+    (i32.store offset=12
+     (local.get $0)
+     (i32.add
+      (i32.load offset=12
+       (local.get $0)
+      )
+      (local.get $2)
+     )
+    )
+    (i32.store offset=16
+     (local.tee $1
+      (i32.load offset=28
+       (local.get $0)
+      )
+     )
+     (i32.add
+      (i32.load offset=16
+       (local.get $1)
+      )
+      (local.get $2)
+     )
+    )
+    (i32.store offset=20
+     (local.get $0)
+     (i32.add
+      (i32.load offset=20
+       (local.get $0)
+      )
+      (local.get $2)
+     )
+    )
+    (i32.store offset=16
+     (local.get $0)
+     (i32.sub
+      (i32.load offset=16
+       (local.get $0)
+      )
+      (local.get $2)
+     )
+    )
+    (i32.store offset=20
+     (local.get $1)
+     (local.tee $0
+      (i32.sub
+       (i32.load offset=20
+        (local.get $1)
+       )
+       (local.get $2)
+      )
+     )
+    )
+    (br_if $label$70
+     (local.get $0)
+    )
+    (i32.store offset=16
+     (local.get $1)
+     (i32.load offset=8
+      (local.get $1)
+     )
+    )
+   )
+   (block $label$71
+    (br_if $label$71
+     (i32.lt_s
+      (local.tee $0
+       (i32.load offset=24
+        (local.get $3)
+       )
+      )
+      (i32.const 1)
+     )
+    )
+    (i32.store offset=24
+     (local.get $3)
+     (i32.sub
+      (i32.const 0)
+      (local.get $0)
+     )
+    )
+   )
+   (local.set $2
+    (i32.eqz
+     (i32.load offset=20
+      (local.get $3)
+     )
+    )
+   )
+  )
+  (local.get $2)
+ )
+ ;; custom section "producers", size 183
+)
+
diff --git a/binaryen/test/passes/O3_print-stack-ir.txt b/binaryen/test/passes/O3_print-stack-ir.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O3_print-stack-ir.txt
@@ -0,0 +1,41 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "stacky-help" (func $stacky-help))
+ (func $stacky-help (param $0 i32) (result i32)
+  i32.const 0
+  call $stacky-help
+  i32.const 1
+  call $stacky-help
+  i32.const 2
+  call $stacky-help
+  drop
+  i32.eqz
+  i32.add
+ )
+)
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "stacky-help" (func $stacky-help))
+ (func $stacky-help (; has Stack IR ;) (param $0 i32) (result i32)
+  (i32.add
+   (call $stacky-help
+    (i32.const 0)
+   )
+   (block (result i32)
+    (local.set $0
+     (call $stacky-help
+      (i32.const 1)
+     )
+    )
+    (drop
+     (call $stacky-help
+      (i32.const 2)
+     )
+    )
+    (i32.eqz
+     (local.get $0)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/O3_print-stack-ir.wast b/binaryen/test/passes/O3_print-stack-ir.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O3_print-stack-ir.wast
@@ -0,0 +1,16 @@
+(module
+ (export "stacky-help" (func $stacky-help))
+ (func $stacky-help (param $x i32) (result i32)
+  (local $temp i32)
+  (i32.add
+   (call $stacky-help (i32.const 0))
+   (i32.eqz
+    (block (result i32) ;; after we use the stack instead of the local, we can remove this block
+     (local.set $temp (call $stacky-help (i32.const 1)))
+     (drop (call $stacky-help (i32.const 2)))
+     (local.get $temp)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/O4_disable-bulk-memory.txt b/binaryen/test/passes/O4_disable-bulk-memory.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O4_disable-bulk-memory.txt
@@ -0,0 +1,1291 @@
+(module
+ (type $none_=>_none (func))
+ (export "func_59_invoker" (func $0))
+ (func $0 (; has Stack IR ;)
+  (unreachable)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $f64_f64_f64_f64_f64_f64_f64_=>_i32 (func (param f64 f64 f64 f64 f64 f64 f64) (result i32)))
+ (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")
+ (table $0 1 funcref)
+ (elem (i32.const 0) $null)
+ (global $global$0 (mut i32) (i32.const 0))
+ (global $global$1 (mut i32) (i32.const 0))
+ (global $global$5 (mut i32) (i32.const 0))
+ (export "memory" (memory $0))
+ (export "table" (table $0))
+ (export "init" (func $assembly/index/init))
+ (export "step" (func $assembly/index/step))
+ (export "bench" (func $assembly/index/bench))
+ (export "getBody" (func $assembly/index/getBody))
+ (start $start)
+ (func $~lib/allocator/arena/__memory_allocate (; has Stack IR ;) (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (if
+   (i32.gt_u
+    (local.get $0)
+    (i32.const 1073741824)
+   )
+   (unreachable)
+  )
+  (if
+   (i32.gt_u
+    (local.tee $0
+     (i32.and
+      (i32.add
+       (i32.add
+        (local.tee $1
+         (global.get $global$1)
+        )
+        (select
+         (local.get $0)
+         (i32.const 1)
+         (i32.gt_u
+          (local.get $0)
+          (i32.const 1)
+         )
+        )
+       )
+       (i32.const 7)
+      )
+      (i32.const -8)
+     )
+    )
+    (i32.shl
+     (local.tee $2
+      (memory.size)
+     )
+     (i32.const 16)
+    )
+   )
+   (if
+    (i32.lt_s
+     (memory.grow
+      (select
+       (local.get $2)
+       (local.tee $3
+        (i32.shr_u
+         (i32.and
+          (i32.add
+           (i32.sub
+            (local.get $0)
+            (local.get $1)
+           )
+           (i32.const 65535)
+          )
+          (i32.const -65536)
+         )
+         (i32.const 16)
+        )
+       )
+       (i32.gt_s
+        (local.get $2)
+        (local.get $3)
+       )
+      )
+     )
+     (i32.const 0)
+    )
+    (if
+     (i32.lt_s
+      (memory.grow
+       (local.get $3)
+      )
+      (i32.const 0)
+     )
+     (unreachable)
+    )
+   )
+  )
+  (global.set $global$1
+   (local.get $0)
+  )
+  (local.get $1)
+ )
+ (func $assembly/index/NBodySystem#constructor (; has Stack IR ;) (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 f64)
+  (local $4 f64)
+  (local $5 f64)
+  (local $6 f64)
+  (local $7 i32)
+  (local.set $7
+   (i32.load offset=4
+    (local.get $0)
+   )
+  )
+  (loop $label$3
+   (if
+    (i32.lt_s
+     (local.get $1)
+     (local.get $7)
+    )
+    (block
+     (local.set $3
+      (f64.load offset=48
+       (local.tee $2
+        (i32.load offset=8
+         (i32.add
+          (i32.load
+           (local.get $0)
+          )
+          (i32.shl
+           (local.get $1)
+           (i32.const 2)
+          )
+         )
+        )
+       )
+      )
+     )
+     (local.set $4
+      (f64.add
+       (local.get $4)
+       (f64.mul
+        (f64.load offset=24
+         (local.get $2)
+        )
+        (local.get $3)
+       )
+      )
+     )
+     (local.set $5
+      (f64.add
+       (local.get $5)
+       (f64.mul
+        (f64.load offset=32
+         (local.get $2)
+        )
+        (local.get $3)
+       )
+      )
+     )
+     (local.set $6
+      (f64.add
+       (local.get $6)
+       (f64.mul
+        (f64.load offset=40
+         (local.get $2)
+        )
+        (local.get $3)
+       )
+      )
+     )
+     (local.set $1
+      (i32.add
+       (local.get $1)
+       (i32.const 1)
+      )
+     )
+     (br $label$3)
+    )
+   )
+  )
+  (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.const 2)
+      )
+     )
+     (i32.load offset=8
+      (local.get $1)
+     )
+     (unreachable)
+    )
+   )
+   (f64.div
+    (f64.neg
+     (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)
+   )
+  )
+  (f64.store offset=40
+   (local.get $1)
+   (f64.div
+    (f64.neg
+     (local.get $6)
+    )
+    (f64.const 39.47841760435743)
+   )
+  )
+  (i32.store
+   (local.tee $1
+    (call $~lib/allocator/arena/__memory_allocate
+     (i32.const 4)
+    )
+   )
+   (local.get $0)
+  )
+  (local.get $1)
+ )
+ (func $assembly/index/Body#constructor (; has Stack IR ;) (param $0 f64) (param $1 f64) (param $2 f64) (param $3 f64) (param $4 f64) (param $5 f64) (param $6 f64) (result i32)
+  (local $7 i32)
+  (f64.store
+   (local.tee $7
+    (call $~lib/allocator/arena/__memory_allocate
+     (i32.const 56)
+    )
+   )
+   (local.get $0)
+  )
+  (f64.store offset=8
+   (local.get $7)
+   (local.get $1)
+  )
+  (f64.store offset=16
+   (local.get $7)
+   (local.get $2)
+  )
+  (f64.store offset=24
+   (local.get $7)
+   (local.get $3)
+  )
+  (f64.store offset=32
+   (local.get $7)
+   (local.get $4)
+  )
+  (f64.store offset=40
+   (local.get $7)
+   (local.get $5)
+  )
+  (f64.store offset=48
+   (local.get $7)
+   (local.get $6)
+  )
+  (local.get $7)
+ )
+ (func $~lib/internal/memory/memset (; has Stack IR ;) (param $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (i32.store8
+   (local.get $0)
+   (i32.const 0)
+  )
+  (i32.store8
+   (i32.sub
+    (local.tee $1
+     (i32.add
+      (local.get $0)
+      (i32.const 20)
+     )
+    )
+    (i32.const 1)
+   )
+   (i32.const 0)
+  )
+  (i32.store8
+   (i32.add
+    (local.get $0)
+    (i32.const 1)
+   )
+   (i32.const 0)
+  )
+  (i32.store8
+   (i32.add
+    (local.get $0)
+    (i32.const 2)
+   )
+   (i32.const 0)
+  )
+  (i32.store8
+   (i32.sub
+    (local.get $1)
+    (i32.const 2)
+   )
+   (i32.const 0)
+  )
+  (i32.store8
+   (i32.sub
+    (local.get $1)
+    (i32.const 3)
+   )
+   (i32.const 0)
+  )
+  (i32.store8
+   (i32.add
+    (local.get $0)
+    (i32.const 3)
+   )
+   (i32.const 0)
+  )
+  (i32.store8
+   (i32.sub
+    (local.get $1)
+    (i32.const 4)
+   )
+   (i32.const 0)
+  )
+  (i32.store
+   (local.tee $0
+    (i32.add
+     (local.tee $1
+      (i32.and
+       (i32.sub
+        (i32.const 0)
+        (local.get $0)
+       )
+       (i32.const 3)
+      )
+     )
+     (local.get $0)
+    )
+   )
+   (i32.const 0)
+  )
+  (i32.store
+   (i32.sub
+    (i32.add
+     (local.tee $1
+      (i32.and
+       (i32.sub
+        (i32.const 20)
+        (local.get $1)
+       )
+       (i32.const -4)
+      )
+     )
+     (local.get $0)
+    )
+    (i32.const 4)
+   )
+   (i32.const 0)
+  )
+  (if
+   (i32.le_u
+    (local.get $1)
+    (i32.const 8)
+   )
+   (return)
+  )
+  (i32.store
+   (i32.add
+    (local.get $0)
+    (i32.const 4)
+   )
+   (i32.const 0)
+  )
+  (i32.store
+   (i32.add
+    (local.get $0)
+    (i32.const 8)
+   )
+   (i32.const 0)
+  )
+  (i32.store
+   (i32.sub
+    (local.tee $2
+     (i32.add
+      (local.get $0)
+      (local.get $1)
+     )
+    )
+    (i32.const 12)
+   )
+   (i32.const 0)
+  )
+  (i32.store
+   (i32.sub
+    (local.get $2)
+    (i32.const 8)
+   )
+   (i32.const 0)
+  )
+  (if
+   (i32.le_u
+    (local.get $1)
+    (i32.const 24)
+   )
+   (return)
+  )
+  (i32.store
+   (i32.add
+    (local.get $0)
+    (i32.const 12)
+   )
+   (i32.const 0)
+  )
+  (i32.store
+   (i32.add
+    (local.get $0)
+    (i32.const 16)
+   )
+   (i32.const 0)
+  )
+  (i32.store
+   (i32.add
+    (local.get $0)
+    (i32.const 20)
+   )
+   (i32.const 0)
+  )
+  (i32.store
+   (i32.add
+    (local.get $0)
+    (i32.const 24)
+   )
+   (i32.const 0)
+  )
+  (i32.store
+   (i32.sub
+    (local.tee $2
+     (i32.add
+      (local.get $0)
+      (local.get $1)
+     )
+    )
+    (i32.const 28)
+   )
+   (i32.const 0)
+  )
+  (i32.store
+   (i32.sub
+    (local.get $2)
+    (i32.const 24)
+   )
+   (i32.const 0)
+  )
+  (i32.store
+   (i32.sub
+    (local.get $2)
+    (i32.const 20)
+   )
+   (i32.const 0)
+  )
+  (i32.store
+   (i32.sub
+    (local.get $2)
+    (i32.const 16)
+   )
+   (i32.const 0)
+  )
+  (local.set $0
+   (i32.add
+    (local.tee $2
+     (i32.add
+      (i32.and
+       (local.get $0)
+       (i32.const 4)
+      )
+      (i32.const 24)
+     )
+    )
+    (local.get $0)
+   )
+  )
+  (local.set $1
+   (i32.sub
+    (local.get $1)
+    (local.get $2)
+   )
+  )
+  (loop $label$8
+   (if
+    (i32.ge_u
+     (local.get $1)
+     (i32.const 32)
+    )
+    (block
+     (i64.store
+      (local.get $0)
+      (i64.const 0)
+     )
+     (i64.store
+      (i32.add
+       (local.get $0)
+       (i32.const 8)
+      )
+      (i64.const 0)
+     )
+     (i64.store
+      (i32.add
+       (local.get $0)
+       (i32.const 16)
+      )
+      (i64.const 0)
+     )
+     (i64.store
+      (i32.add
+       (local.get $0)
+       (i32.const 24)
+      )
+      (i64.const 0)
+     )
+     (local.set $1
+      (i32.sub
+       (local.get $1)
+       (i32.const 32)
+      )
+     )
+     (local.set $0
+      (i32.add
+       (local.get $0)
+       (i32.const 32)
+      )
+     )
+     (br $label$8)
+    )
+   )
+  )
+ )
+ (func $~lib/array/Array<Body>#constructor (; has Stack IR ;) (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (i32.store
+   (local.tee $1
+    (call $~lib/allocator/arena/__memory_allocate
+     (i32.const 32)
+    )
+   )
+   (i32.const 20)
+  )
+  (i32.store
+   (local.tee $0
+    (call $~lib/allocator/arena/__memory_allocate
+     (i32.const 8)
+    )
+   )
+   (i32.const 0)
+  )
+  (i32.store offset=4
+   (local.get $0)
+   (i32.const 0)
+  )
+  (i32.store
+   (local.get $0)
+   (local.get $1)
+  )
+  (i32.store offset=4
+   (local.get $0)
+   (i32.const 5)
+  )
+  (call $~lib/internal/memory/memset
+   (i32.add
+    (local.get $1)
+    (i32.const 8)
+   )
+  )
+  (local.get $0)
+ )
+ (func $assembly/index/init (; has Stack IR ;)
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $1
+   (call $~lib/array/Array<Body>#constructor)
+  )
+  (local.set $0
+   (call $assembly/index/Body#constructor
+    (f64.const 0)
+    (f64.const 0)
+    (f64.const 0)
+    (f64.const 0)
+    (f64.const 0)
+    (f64.const 0)
+    (f64.const 39.47841760435743)
+   )
+  )
+  (i32.store offset=8
+   (i32.load
+    (local.get $1)
+   )
+   (local.get $0)
+  )
+  (local.set $0
+   (call $assembly/index/Body#constructor
+    (f64.const 4.841431442464721)
+    (f64.const -1.1603200440274284)
+    (f64.const -0.10362204447112311)
+    (f64.const 0.606326392995832)
+    (f64.const 2.81198684491626)
+    (f64.const -0.02521836165988763)
+    (f64.const 0.03769367487038949)
+   )
+  )
+  (i32.store offset=8
+   (i32.add
+    (i32.load
+     (local.get $1)
+    )
+    (i32.const 4)
+   )
+   (local.get $0)
+  )
+  (local.set $0
+   (call $assembly/index/Body#constructor
+    (f64.const 8.34336671824458)
+    (f64.const 4.124798564124305)
+    (f64.const -0.4035234171143214)
+    (f64.const -1.0107743461787924)
+    (f64.const 1.8256623712304119)
+    (f64.const 0.008415761376584154)
+    (f64.const 0.011286326131968767)
+   )
+  )
+  (i32.store offset=8
+   (i32.add
+    (i32.load
+     (local.get $1)
+    )
+    (i32.const 8)
+   )
+   (local.get $0)
+  )
+  (local.set $0
+   (call $assembly/index/Body#constructor
+    (f64.const 12.894369562139131)
+    (f64.const -15.111151401698631)
+    (f64.const -0.22330757889265573)
+    (f64.const 1.0827910064415354)
+    (f64.const 0.8687130181696082)
+    (f64.const -0.010832637401363636)
+    (f64.const 1.7237240570597112e-03)
+   )
+  )
+  (i32.store offset=8
+   (i32.add
+    (i32.load
+     (local.get $1)
+    )
+    (i32.const 12)
+   )
+   (local.get $0)
+  )
+  (local.set $0
+   (call $assembly/index/Body#constructor
+    (f64.const 15.379697114850917)
+    (f64.const -25.919314609987964)
+    (f64.const 0.17925877295037118)
+    (f64.const 0.979090732243898)
+    (f64.const 0.5946989986476762)
+    (f64.const -0.034755955504078104)
+    (f64.const 2.0336868699246304e-03)
+   )
+  )
+  (i32.store offset=8
+   (i32.add
+    (i32.load
+     (local.get $1)
+    )
+    (i32.const 16)
+   )
+   (local.get $0)
+  )
+  (global.set $global$5
+   (call $assembly/index/NBodySystem#constructor
+    (local.get $1)
+   )
+  )
+ )
+ (func $assembly/index/NBodySystem#advance (; has Stack IR ;) (param $0 i32)
+  (local $1 i32)
+  (local $2 f64)
+  (local $3 i32)
+  (local $4 f64)
+  (local $5 f64)
+  (local $6 f64)
+  (local $7 i32)
+  (local $8 f64)
+  (local $9 f64)
+  (local $10 f64)
+  (local $11 f64)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 f64)
+  (local $15 f64)
+  (local $16 f64)
+  (local $17 f64)
+  (local.set $13
+   (i32.load offset=4
+    (local.tee $12
+     (i32.load
+      (local.get $0)
+     )
+    )
+   )
+  )
+  (loop $label$3
+   (if
+    (i32.lt_u
+     (local.get $3)
+     (local.get $13)
+    )
+    (block
+     (local.set $14
+      (f64.load
+       (local.tee $0
+        (i32.load offset=8
+         (i32.add
+          (i32.load
+           (local.get $12)
+          )
+          (i32.shl
+           (local.get $3)
+           (i32.const 2)
+          )
+         )
+        )
+       )
+      )
+     )
+     (local.set $15
+      (f64.load offset=8
+       (local.get $0)
+      )
+     )
+     (local.set $16
+      (f64.load offset=16
+       (local.get $0)
+      )
+     )
+     (local.set $4
+      (f64.load offset=24
+       (local.get $0)
+      )
+     )
+     (local.set $5
+      (f64.load offset=32
+       (local.get $0)
+      )
+     )
+     (local.set $6
+      (f64.load offset=40
+       (local.get $0)
+      )
+     )
+     (local.set $17
+      (f64.load offset=48
+       (local.get $0)
+      )
+     )
+     (local.set $7
+      (i32.add
+       (local.get $3)
+       (i32.const 1)
+      )
+     )
+     (loop $label$6
+      (if
+       (i32.lt_u
+        (local.get $7)
+        (local.get $13)
+       )
+       (block
+        (local.set $11
+         (f64.sqrt
+          (local.tee $8
+           (f64.add
+            (f64.add
+             (f64.mul
+              (local.tee $2
+               (f64.sub
+                (local.get $14)
+                (f64.load
+                 (local.tee $1
+                  (i32.load offset=8
+                   (i32.add
+                    (i32.load
+                     (local.get $12)
+                    )
+                    (i32.shl
+                     (local.get $7)
+                     (i32.const 2)
+                    )
+                   )
+                  )
+                 )
+                )
+               )
+              )
+              (local.get $2)
+             )
+             (f64.mul
+              (local.tee $9
+               (f64.sub
+                (local.get $15)
+                (f64.load offset=8
+                 (local.get $1)
+                )
+               )
+              )
+              (local.get $9)
+             )
+            )
+            (f64.mul
+             (local.tee $10
+              (f64.sub
+               (local.get $16)
+               (f64.load offset=16
+                (local.get $1)
+               )
+              )
+             )
+             (local.get $10)
+            )
+           )
+          )
+         )
+        )
+        (local.set $4
+         (f64.sub
+          (local.get $4)
+          (f64.mul
+           (local.get $2)
+           (local.tee $8
+            (f64.mul
+             (f64.load offset=48
+              (local.get $1)
+             )
+             (local.tee $11
+              (f64.div
+               (f64.const 0.01)
+               (f64.mul
+                (local.get $8)
+                (local.get $11)
+               )
+              )
+             )
+            )
+           )
+          )
+         )
+        )
+        (local.set $5
+         (f64.sub
+          (local.get $5)
+          (f64.mul
+           (local.get $9)
+           (local.get $8)
+          )
+         )
+        )
+        (local.set $6
+         (f64.sub
+          (local.get $6)
+          (f64.mul
+           (local.get $10)
+           (local.get $8)
+          )
+         )
+        )
+        (f64.store offset=24
+         (local.get $1)
+         (f64.add
+          (f64.load offset=24
+           (local.get $1)
+          )
+          (f64.mul
+           (local.get $2)
+           (local.tee $2
+            (f64.mul
+             (local.get $17)
+             (local.get $11)
+            )
+           )
+          )
+         )
+        )
+        (f64.store offset=32
+         (local.get $1)
+         (f64.add
+          (f64.load offset=32
+           (local.get $1)
+          )
+          (f64.mul
+           (local.get $9)
+           (local.get $2)
+          )
+         )
+        )
+        (f64.store offset=40
+         (local.get $1)
+         (f64.add
+          (f64.load offset=40
+           (local.get $1)
+          )
+          (f64.mul
+           (local.get $10)
+           (local.get $2)
+          )
+         )
+        )
+        (local.set $7
+         (i32.add
+          (local.get $7)
+          (i32.const 1)
+         )
+        )
+        (br $label$6)
+       )
+      )
+     )
+     (f64.store offset=24
+      (local.get $0)
+      (local.get $4)
+     )
+     (f64.store offset=32
+      (local.get $0)
+      (local.get $5)
+     )
+     (f64.store offset=40
+      (local.get $0)
+      (local.get $6)
+     )
+     (f64.store
+      (local.get $0)
+      (f64.add
+       (f64.load
+        (local.get $0)
+       )
+       (f64.mul
+        (local.get $4)
+        (f64.const 0.01)
+       )
+      )
+     )
+     (f64.store offset=8
+      (local.get $0)
+      (f64.add
+       (f64.load offset=8
+        (local.get $0)
+       )
+       (f64.mul
+        (local.get $5)
+        (f64.const 0.01)
+       )
+      )
+     )
+     (f64.store offset=16
+      (local.get $0)
+      (f64.add
+       (f64.load offset=16
+        (local.get $0)
+       )
+       (f64.mul
+        (local.get $6)
+        (f64.const 0.01)
+       )
+      )
+     )
+     (local.set $3
+      (i32.add
+       (local.get $3)
+       (i32.const 1)
+      )
+     )
+     (br $label$3)
+    )
+   )
+  )
+ )
+ (func $assembly/index/NBodySystem#energy (; has Stack IR ;) (param $0 i32) (result f64)
+  (local $1 f64)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 f64)
+  (local $7 f64)
+  (local $8 f64)
+  (local $9 f64)
+  (local $10 f64)
+  (local.set $5
+   (i32.load offset=4
+    (local.tee $4
+     (i32.load
+      (local.get $0)
+     )
+    )
+   )
+  )
+  (loop $label$4
+   (if
+    (i32.lt_u
+     (local.get $2)
+     (local.get $5)
+    )
+    (block
+     (local.set $7
+      (f64.load
+       (local.tee $0
+        (i32.load offset=8
+         (i32.add
+          (i32.load
+           (local.get $4)
+          )
+          (i32.shl
+           (local.get $2)
+           (i32.const 2)
+          )
+         )
+        )
+       )
+      )
+     )
+     (local.set $8
+      (f64.load offset=8
+       (local.get $0)
+      )
+     )
+     (local.set $9
+      (f64.load offset=16
+       (local.get $0)
+      )
+     )
+     (local.set $1
+      (f64.add
+       (local.get $1)
+       (f64.mul
+        (f64.mul
+         (local.tee $10
+          (f64.load offset=48
+           (local.get $0)
+          )
+         )
+         (f64.const 0.5)
+        )
+        (f64.add
+         (f64.add
+          (f64.mul
+           (local.tee $1
+            (f64.load offset=24
+             (local.get $0)
+            )
+           )
+           (local.get $1)
+          )
+          (f64.mul
+           (local.tee $1
+            (f64.load offset=32
+             (local.get $0)
+            )
+           )
+           (local.get $1)
+          )
+         )
+         (f64.mul
+          (local.tee $1
+           (f64.load offset=40
+            (local.get $0)
+           )
+          )
+          (local.get $1)
+         )
+        )
+       )
+      )
+     )
+     (local.set $0
+      (i32.add
+       (local.get $2)
+       (i32.const 1)
+      )
+     )
+     (loop $label$7
+      (if
+       (i32.lt_u
+        (local.get $0)
+        (local.get $5)
+       )
+       (block
+        (local.set $6
+         (f64.sub
+          (local.get $7)
+          (f64.load
+           (local.tee $3
+            (i32.load offset=8
+             (i32.add
+              (i32.load
+               (local.get $4)
+              )
+              (i32.shl
+               (local.get $0)
+               (i32.const 2)
+              )
+             )
+            )
+           )
+          )
+         )
+        )
+        (local.set $1
+         (f64.sub
+          (local.get $1)
+          (f64.div
+           (f64.mul
+            (local.get $10)
+            (f64.load offset=48
+             (local.get $3)
+            )
+           )
+           (f64.sqrt
+            (f64.add
+             (f64.add
+              (f64.mul
+               (local.get $6)
+               (local.get $6)
+              )
+              (f64.mul
+               (local.tee $1
+                (f64.sub
+                 (local.get $8)
+                 (f64.load offset=8
+                  (local.get $3)
+                 )
+                )
+               )
+               (local.get $1)
+              )
+             )
+             (f64.mul
+              (local.tee $1
+               (f64.sub
+                (local.get $9)
+                (f64.load offset=16
+                 (local.get $3)
+                )
+               )
+              )
+              (local.get $1)
+             )
+            )
+           )
+          )
+         )
+        )
+        (local.set $0
+         (i32.add
+          (local.get $0)
+          (i32.const 1)
+         )
+        )
+        (br $label$7)
+       )
+      )
+     )
+     (local.set $2
+      (i32.add
+       (local.get $2)
+       (i32.const 1)
+      )
+     )
+     (br $label$4)
+    )
+   )
+  )
+  (local.get $1)
+ )
+ (func $assembly/index/step (; has Stack IR ;) (result f64)
+  (call $assembly/index/NBodySystem#advance
+   (global.get $global$5)
+  )
+  (call $assembly/index/NBodySystem#energy
+   (global.get $global$5)
+  )
+ )
+ (func $assembly/index/bench (; has Stack IR ;) (param $0 i32)
+  (local $1 i32)
+  (block $label$1
+   (loop $label$2
+    (br_if $label$1
+     (i32.ge_u
+      (local.get $1)
+      (local.get $0)
+     )
+    )
+    (call $assembly/index/NBodySystem#advance
+     (global.get $global$5)
+    )
+    (local.set $1
+     (i32.add
+      (local.get $1)
+      (i32.const 1)
+     )
+    )
+    (br $label$2)
+   )
+  )
+ )
+ (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.load offset=4
+     (local.tee $1
+      (i32.load
+       (global.get $global$5)
+      )
+     )
+    )
+   )
+   (if (result i32)
+    (i32.lt_u
+     (local.get $0)
+     (i32.shr_u
+      (i32.load
+       (local.tee $1
+        (i32.load
+         (local.get $1)
+        )
+       )
+      )
+      (i32.const 2)
+     )
+    )
+    (i32.load offset=8
+     (i32.add
+      (i32.shl
+       (local.get $0)
+       (i32.const 2)
+      )
+      (local.get $1)
+     )
+    )
+    (unreachable)
+   )
+   (i32.const 0)
+  )
+ )
+ (func $start (; has Stack IR ;)
+  (global.set $global$0
+   (i32.const 104)
+  )
+  (global.set $global$1
+   (i32.const 104)
+  )
+ )
+ (func $null (; has Stack IR ;)
+  (nop)
+ )
+)
diff --git a/binaryen/test/passes/O4_disable-bulk-memory.wast b/binaryen/test/passes/O4_disable-bulk-memory.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O4_disable-bulk-memory.wast
@@ -0,0 +1,1759 @@
+(module
+ (type $0 (func))
+ (global $global$0 (mut i32) (i32.const 10))
+ (export "func_59_invoker" (func $0))
+ (func $0 (; 0 ;) (type $0)
+  (if
+   (block $label$1 (result i32)
+    (global.set $global$0
+     (i32.const 0)
+    )
+    (i32.const 127)
+   )
+   (unreachable)
+  )
+  (global.set $global$0
+   (i32.const -1)
+  )
+  (if
+   (global.get $global$0)
+   (unreachable)
+  )
+  (unreachable)
+ )
+)
+;; AssemblyScript n-body benchmark
+(module
+ (type $0 (func))
+ (type $1 (func (param i32 i32) (result i32)))
+ (type $2 (func (param i32 f64 f64 f64) (result i32)))
+ (type $3 (func (param i32) (result i32)))
+ (type $4 (func (result i32)))
+ (type $5 (func (param i32 f64 f64 f64 f64 f64 f64 f64) (result i32)))
+ (type $6 (func (param i32 i32 i32 i32)))
+ (type $7 (func (param i32 i32 i32)))
+ (type $8 (func (result f64)))
+ (type $9 (func (param i32 f64)))
+ (type $10 (func (param i32) (result f64)))
+ (type $11 (func (param i32)))
+ (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\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")
+ (import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32)))
+ (table $0 1 funcref)
+ (elem (i32.const 0) $null)
+ (global $global$0 (mut i32) (i32.const 0))
+ (global $global$1 (mut i32) (i32.const 0))
+ (global $global$2 f64 (f64.const 3.141592653589793))
+ (global $global$3 f64 (f64.const 39.47841760435743))
+ (global $global$4 f64 (f64.const 365.24))
+ (global $global$5 (mut i32) (i32.const 0))
+ (global $global$6 i32 (i32.const 100))
+ (export "memory" (memory $0))
+ (export "table" (table $0))
+ (export "init" (func $assembly/index/init))
+ (export "step" (func $assembly/index/step))
+ (export "bench" (func $assembly/index/bench))
+ (export "getBody" (func $assembly/index/getBody))
+ (start $start)
+ (func $start:~lib/allocator/arena (; 1 ;) (type $0)
+  (global.set $global$0
+   (i32.and
+    (i32.add
+     (global.get $global$6)
+     (i32.const 7)
+    )
+    (i32.xor
+     (i32.const 7)
+     (i32.const -1)
+    )
+   )
+  )
+  (global.set $global$1
+   (global.get $global$0)
+  )
+ )
+ (func $start:assembly/index (; 2 ;) (type $0)
+  (call $start:~lib/allocator/arena)
+ )
+ (func $~lib/array/Array<Body>#__unchecked_get (; 3 ;) (type $1) (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local.set $2
+   (i32.load
+    (local.get $0)
+   )
+  )
+  (local.set $3
+   (local.get $1)
+  )
+  (local.set $4
+   (i32.const 0)
+  )
+  (i32.load offset=8
+   (i32.add
+    (i32.add
+     (local.get $2)
+     (i32.shl
+      (local.get $3)
+      (i32.const 2)
+     )
+    )
+    (local.get $4)
+   )
+  )
+ )
+ (func $~lib/array/Array<Body>#__get (; 4 ;) (type $1) (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $2
+   (i32.load
+    (local.get $0)
+   )
+  )
+  (if (result i32)
+   (i32.lt_u
+    (local.get $1)
+    (i32.shr_u
+     (i32.load
+      (local.get $2)
+     )
+     (i32.const 2)
+    )
+   )
+   (block (result i32)
+    (local.set $3
+     (local.get $2)
+    )
+    (local.set $4
+     (local.get $1)
+    )
+    (local.set $5
+     (i32.const 0)
+    )
+    (i32.load offset=8
+     (i32.add
+      (i32.add
+       (local.get $3)
+       (i32.shl
+        (local.get $4)
+        (i32.const 2)
+       )
+      )
+      (local.get $5)
+     )
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $assembly/index/Body#offsetMomentum (; 5 ;) (type $2) (param $0 i32) (param $1 f64) (param $2 f64) (param $3 f64) (result i32)
+  (f64.store offset=24
+   (local.get $0)
+   (f64.div
+    (f64.neg
+     (local.get $1)
+    )
+    (global.get $global$3)
+   )
+  )
+  (f64.store offset=32
+   (local.get $0)
+   (f64.div
+    (f64.neg
+     (local.get $2)
+    )
+    (global.get $global$3)
+   )
+  )
+  (f64.store offset=40
+   (local.get $0)
+   (f64.div
+    (f64.neg
+     (local.get $3)
+    )
+    (global.get $global$3)
+   )
+  )
+  (local.get $0)
+ )
+ (func $~lib/allocator/arena/__memory_allocate (; 6 ;) (type $3) (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (if
+   (i32.gt_u
+    (local.get $0)
+    (i32.const 1073741824)
+   )
+   (unreachable)
+  )
+  (local.set $1
+   (global.get $global$1)
+  )
+  (local.set $4
+   (i32.and
+    (i32.add
+     (i32.add
+      (local.get $1)
+      (select
+       (local.tee $2
+        (local.get $0)
+       )
+       (local.tee $3
+        (i32.const 1)
+       )
+       (i32.gt_u
+        (local.get $2)
+        (local.get $3)
+       )
+      )
+     )
+     (i32.const 7)
+    )
+    (i32.xor
+     (i32.const 7)
+     (i32.const -1)
+    )
+   )
+  )
+  (local.set $5
+   (memory.size)
+  )
+  (if
+   (i32.gt_u
+    (local.get $4)
+    (i32.shl
+     (local.get $5)
+     (i32.const 16)
+    )
+   )
+   (block
+    (local.set $2
+     (i32.shr_u
+      (i32.and
+       (i32.add
+        (i32.sub
+         (local.get $4)
+         (local.get $1)
+        )
+        (i32.const 65535)
+       )
+       (i32.xor
+        (i32.const 65535)
+        (i32.const -1)
+       )
+      )
+      (i32.const 16)
+     )
+    )
+    (local.set $3
+     (select
+      (local.tee $3
+       (local.get $5)
+      )
+      (local.tee $6
+       (local.get $2)
+      )
+      (i32.gt_s
+       (local.get $3)
+       (local.get $6)
+      )
+     )
+    )
+    (if
+     (i32.lt_s
+      (memory.grow
+       (local.get $3)
+      )
+      (i32.const 0)
+     )
+     (if
+      (i32.lt_s
+       (memory.grow
+        (local.get $2)
+       )
+       (i32.const 0)
+      )
+      (unreachable)
+     )
+    )
+   )
+  )
+  (global.set $global$1
+   (local.get $4)
+  )
+  (local.get $1)
+ )
+ (func $~lib/memory/memory.allocate (; 7 ;) (type $3) (param $0 i32) (result i32)
+  (return
+   (call $~lib/allocator/arena/__memory_allocate
+    (local.get $0)
+   )
+  )
+ )
+ (func $assembly/index/NBodySystem#constructor (; 8 ;) (type $1) (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 f64)
+  (local $6 f64)
+  (local $7 f64)
+  (local $8 f64)
+  (local.set $5
+   (f64.const 0)
+  )
+  (local.set $6
+   (f64.const 0)
+  )
+  (local.set $7
+   (f64.const 0)
+  )
+  (local.set $3
+   (block $label$1 (result i32)
+    (local.set $2
+     (local.get $1)
+    )
+    (i32.load offset=4
+     (local.get $2)
+    )
+   )
+  )
+  (block $label$2
+   (local.set $2
+    (i32.const 0)
+   )
+   (loop $label$3
+    (br_if $label$2
+     (i32.eqz
+      (i32.lt_s
+       (local.get $2)
+       (local.get $3)
+      )
+     )
+    )
+    (block $label$4
+     (local.set $4
+      (call $~lib/array/Array<Body>#__unchecked_get
+       (local.get $1)
+       (local.get $2)
+      )
+     )
+     (local.set $8
+      (f64.load offset=48
+       (local.get $4)
+      )
+     )
+     (local.set $5
+      (f64.add
+       (local.get $5)
+       (f64.mul
+        (f64.load offset=24
+         (local.get $4)
+        )
+        (local.get $8)
+       )
+      )
+     )
+     (local.set $6
+      (f64.add
+       (local.get $6)
+       (f64.mul
+        (f64.load offset=32
+         (local.get $4)
+        )
+        (local.get $8)
+       )
+      )
+     )
+     (local.set $7
+      (f64.add
+       (local.get $7)
+       (f64.mul
+        (f64.load offset=40
+         (local.get $4)
+        )
+        (local.get $8)
+       )
+      )
+     )
+    )
+    (local.set $2
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+    )
+    (br $label$3)
+   )
+  )
+  (drop
+   (call $assembly/index/Body#offsetMomentum
+    (call $~lib/array/Array<Body>#__get
+     (local.get $1)
+     (i32.const 0)
+    )
+    (local.get $5)
+    (local.get $6)
+    (local.get $7)
+   )
+  )
+  (if
+   (i32.eqz
+    (local.get $0)
+   )
+   (local.set $0
+    (call $~lib/memory/memory.allocate
+     (i32.const 4)
+    )
+   )
+  )
+  (i32.store
+   (local.get $0)
+   (local.get $1)
+  )
+  (local.get $0)
+ )
+ (func $assembly/index/Body#constructor (; 9 ;) (type $5) (param $0 i32) (param $1 f64) (param $2 f64) (param $3 f64) (param $4 f64) (param $5 f64) (param $6 f64) (param $7 f64) (result i32)
+  (if
+   (i32.eqz
+    (local.get $0)
+   )
+   (local.set $0
+    (call $~lib/memory/memory.allocate
+     (i32.const 56)
+    )
+   )
+  )
+  (f64.store
+   (local.get $0)
+   (local.get $1)
+  )
+  (f64.store offset=8
+   (local.get $0)
+   (local.get $2)
+  )
+  (f64.store offset=16
+   (local.get $0)
+   (local.get $3)
+  )
+  (f64.store offset=24
+   (local.get $0)
+   (local.get $4)
+  )
+  (f64.store offset=32
+   (local.get $0)
+   (local.get $5)
+  )
+  (f64.store offset=40
+   (local.get $0)
+   (local.get $6)
+  )
+  (f64.store offset=48
+   (local.get $0)
+   (local.get $7)
+  )
+  (local.get $0)
+ )
+ (func $assembly/index/Sun (; 10 ;) (type $4) (result i32)
+  (call $assembly/index/Body#constructor
+   (i32.const 0)
+   (f64.const 0)
+   (f64.const 0)
+   (f64.const 0)
+   (f64.const 0)
+   (f64.const 0)
+   (f64.const 0)
+   (global.get $global$3)
+  )
+ )
+ (func $assembly/index/Jupiter (; 11 ;) (type $4) (result i32)
+  (call $assembly/index/Body#constructor
+   (i32.const 0)
+   (f64.const 4.841431442464721)
+   (f64.const -1.1603200440274284)
+   (f64.const -0.10362204447112311)
+   (f64.mul
+    (f64.const 0.001660076642744037)
+    (global.get $global$4)
+   )
+   (f64.mul
+    (f64.const 0.007699011184197404)
+    (global.get $global$4)
+   )
+   (f64.mul
+    (f64.const -6.90460016972063e-05)
+    (global.get $global$4)
+   )
+   (f64.mul
+    (f64.const 9.547919384243266e-04)
+    (global.get $global$3)
+   )
+  )
+ )
+ (func $assembly/index/Saturn (; 12 ;) (type $4) (result i32)
+  (call $assembly/index/Body#constructor
+   (i32.const 0)
+   (f64.const 8.34336671824458)
+   (f64.const 4.124798564124305)
+   (f64.const -0.4035234171143214)
+   (f64.mul
+    (f64.const -0.002767425107268624)
+    (global.get $global$4)
+   )
+   (f64.mul
+    (f64.const 0.004998528012349172)
+    (global.get $global$4)
+   )
+   (f64.mul
+    (f64.const 2.3041729757376393e-05)
+    (global.get $global$4)
+   )
+   (f64.mul
+    (f64.const 2.858859806661308e-04)
+    (global.get $global$3)
+   )
+  )
+ )
+ (func $assembly/index/Uranus (; 13 ;) (type $4) (result i32)
+  (call $assembly/index/Body#constructor
+   (i32.const 0)
+   (f64.const 12.894369562139131)
+   (f64.const -15.111151401698631)
+   (f64.const -0.22330757889265573)
+   (f64.mul
+    (f64.const 0.002964601375647616)
+    (global.get $global$4)
+   )
+   (f64.mul
+    (f64.const 2.3784717395948095e-03)
+    (global.get $global$4)
+   )
+   (f64.mul
+    (f64.const -2.9658956854023756e-05)
+    (global.get $global$4)
+   )
+   (f64.mul
+    (f64.const 4.366244043351563e-05)
+    (global.get $global$3)
+   )
+  )
+ )
+ (func $assembly/index/Neptune (; 14 ;) (type $4) (result i32)
+  (call $assembly/index/Body#constructor
+   (i32.const 0)
+   (f64.const 15.379697114850917)
+   (f64.const -25.919314609987964)
+   (f64.const 0.17925877295037118)
+   (f64.mul
+    (f64.const 2.6806777249038932e-03)
+    (global.get $global$4)
+   )
+   (f64.mul
+    (f64.const 0.001628241700382423)
+    (global.get $global$4)
+   )
+   (f64.mul
+    (f64.const -9.515922545197159e-05)
+    (global.get $global$4)
+   )
+   (f64.mul
+    (f64.const 5.1513890204661145e-05)
+    (global.get $global$3)
+   )
+  )
+ )
+ (func $~lib/internal/arraybuffer/computeSize (; 15 ;) (type $3) (param $0 i32) (result i32)
+  (i32.shl
+   (i32.const 1)
+   (i32.sub
+    (i32.const 32)
+    (i32.clz
+     (i32.sub
+      (i32.add
+       (local.get $0)
+       (i32.const 8)
+      )
+      (i32.const 1)
+     )
+    )
+   )
+  )
+ )
+ (func $~lib/internal/arraybuffer/allocateUnsafe (; 16 ;) (type $3) (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (if
+   (i32.eqz
+    (i32.le_u
+     (local.get $0)
+     (i32.const 1073741816)
+    )
+   )
+   (block
+    (call $~lib/env/abort
+     (i32.const 0)
+     (i32.const 40)
+     (i32.const 26)
+     (i32.const 2)
+    )
+    (unreachable)
+   )
+  )
+  (local.set $1
+   (block $label$2 (result i32)
+    (local.set $2
+     (call $~lib/internal/arraybuffer/computeSize
+      (local.get $0)
+     )
+    )
+    (br $label$2
+     (call $~lib/allocator/arena/__memory_allocate
+      (local.get $2)
+     )
+    )
+   )
+  )
+  (i32.store
+   (local.get $1)
+   (local.get $0)
+  )
+  (local.get $1)
+ )
+ (func $~lib/internal/memory/memset (; 17 ;) (type $7) (param $0 i32) (param $1 i32) (param $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i64)
+  (if
+   (i32.eqz
+    (local.get $2)
+   )
+   (return)
+  )
+  (i32.store8
+   (local.get $0)
+   (local.get $1)
+  )
+  (i32.store8
+   (i32.sub
+    (i32.add
+     (local.get $0)
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (local.get $1)
+  )
+  (if
+   (i32.le_u
+    (local.get $2)
+    (i32.const 2)
+   )
+   (return)
+  )
+  (i32.store8
+   (i32.add
+    (local.get $0)
+    (i32.const 1)
+   )
+   (local.get $1)
+  )
+  (i32.store8
+   (i32.add
+    (local.get $0)
+    (i32.const 2)
+   )
+   (local.get $1)
+  )
+  (i32.store8
+   (i32.sub
+    (i32.add
+     (local.get $0)
+     (local.get $2)
+    )
+    (i32.const 2)
+   )
+   (local.get $1)
+  )
+  (i32.store8
+   (i32.sub
+    (i32.add
+     (local.get $0)
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (local.get $1)
+  )
+  (if
+   (i32.le_u
+    (local.get $2)
+    (i32.const 6)
+   )
+   (return)
+  )
+  (i32.store8
+   (i32.add
+    (local.get $0)
+    (i32.const 3)
+   )
+   (local.get $1)
+  )
+  (i32.store8
+   (i32.sub
+    (i32.add
+     (local.get $0)
+     (local.get $2)
+    )
+    (i32.const 4)
+   )
+   (local.get $1)
+  )
+  (if
+   (i32.le_u
+    (local.get $2)
+    (i32.const 8)
+   )
+   (return)
+  )
+  (local.set $3
+   (i32.and
+    (i32.sub
+     (i32.const 0)
+     (local.get $0)
+    )
+    (i32.const 3)
+   )
+  )
+  (local.set $0
+   (i32.add
+    (local.get $0)
+    (local.get $3)
+   )
+  )
+  (local.set $2
+   (i32.sub
+    (local.get $2)
+    (local.get $3)
+   )
+  )
+  (local.set $2
+   (i32.and
+    (local.get $2)
+    (i32.const -4)
+   )
+  )
+  (local.set $4
+   (i32.mul
+    (i32.div_u
+     (i32.const -1)
+     (i32.const 255)
+    )
+    (i32.and
+     (local.get $1)
+     (i32.const 255)
+    )
+   )
+  )
+  (i32.store
+   (local.get $0)
+   (local.get $4)
+  )
+  (i32.store
+   (i32.sub
+    (i32.add
+     (local.get $0)
+     (local.get $2)
+    )
+    (i32.const 4)
+   )
+   (local.get $4)
+  )
+  (if
+   (i32.le_u
+    (local.get $2)
+    (i32.const 8)
+   )
+   (return)
+  )
+  (i32.store
+   (i32.add
+    (local.get $0)
+    (i32.const 4)
+   )
+   (local.get $4)
+  )
+  (i32.store
+   (i32.add
+    (local.get $0)
+    (i32.const 8)
+   )
+   (local.get $4)
+  )
+  (i32.store
+   (i32.sub
+    (i32.add
+     (local.get $0)
+     (local.get $2)
+    )
+    (i32.const 12)
+   )
+   (local.get $4)
+  )
+  (i32.store
+   (i32.sub
+    (i32.add
+     (local.get $0)
+     (local.get $2)
+    )
+    (i32.const 8)
+   )
+   (local.get $4)
+  )
+  (if
+   (i32.le_u
+    (local.get $2)
+    (i32.const 24)
+   )
+   (return)
+  )
+  (i32.store
+   (i32.add
+    (local.get $0)
+    (i32.const 12)
+   )
+   (local.get $4)
+  )
+  (i32.store
+   (i32.add
+    (local.get $0)
+    (i32.const 16)
+   )
+   (local.get $4)
+  )
+  (i32.store
+   (i32.add
+    (local.get $0)
+    (i32.const 20)
+   )
+   (local.get $4)
+  )
+  (i32.store
+   (i32.add
+    (local.get $0)
+    (i32.const 24)
+   )
+   (local.get $4)
+  )
+  (i32.store
+   (i32.sub
+    (i32.add
+     (local.get $0)
+     (local.get $2)
+    )
+    (i32.const 28)
+   )
+   (local.get $4)
+  )
+  (i32.store
+   (i32.sub
+    (i32.add
+     (local.get $0)
+     (local.get $2)
+    )
+    (i32.const 24)
+   )
+   (local.get $4)
+  )
+  (i32.store
+   (i32.sub
+    (i32.add
+     (local.get $0)
+     (local.get $2)
+    )
+    (i32.const 20)
+   )
+   (local.get $4)
+  )
+  (i32.store
+   (i32.sub
+    (i32.add
+     (local.get $0)
+     (local.get $2)
+    )
+    (i32.const 16)
+   )
+   (local.get $4)
+  )
+  (local.set $3
+   (i32.add
+    (i32.const 24)
+    (i32.and
+     (local.get $0)
+     (i32.const 4)
+    )
+   )
+  )
+  (local.set $0
+   (i32.add
+    (local.get $0)
+    (local.get $3)
+   )
+  )
+  (local.set $2
+   (i32.sub
+    (local.get $2)
+    (local.get $3)
+   )
+  )
+  (local.set $5
+   (i64.or
+    (i64.extend_i32_u
+     (local.get $4)
+    )
+    (i64.shl
+     (i64.extend_i32_u
+      (local.get $4)
+     )
+     (i64.const 32)
+    )
+   )
+  )
+  (block $label$7
+   (loop $label$8
+    (if
+     (i32.ge_u
+      (local.get $2)
+      (i32.const 32)
+     )
+     (block
+      (block $label$10
+       (i64.store
+        (local.get $0)
+        (local.get $5)
+       )
+       (i64.store
+        (i32.add
+         (local.get $0)
+         (i32.const 8)
+        )
+        (local.get $5)
+       )
+       (i64.store
+        (i32.add
+         (local.get $0)
+         (i32.const 16)
+        )
+        (local.get $5)
+       )
+       (i64.store
+        (i32.add
+         (local.get $0)
+         (i32.const 24)
+        )
+        (local.get $5)
+       )
+       (local.set $2
+        (i32.sub
+         (local.get $2)
+         (i32.const 32)
+        )
+       )
+       (local.set $0
+        (i32.add
+         (local.get $0)
+         (i32.const 32)
+        )
+       )
+      )
+      (br $label$8)
+     )
+    )
+   )
+  )
+ )
+ (func $~lib/array/Array<Body>#constructor (; 18 ;) (type $1) (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (if
+   (i32.gt_u
+    (local.get $1)
+    (i32.const 268435454)
+   )
+   (block
+    (call $~lib/env/abort
+     (i32.const 0)
+     (i32.const 8)
+     (i32.const 45)
+     (i32.const 39)
+    )
+    (unreachable)
+   )
+  )
+  (local.set $2
+   (i32.shl
+    (local.get $1)
+    (i32.const 2)
+   )
+  )
+  (local.set $3
+   (call $~lib/internal/arraybuffer/allocateUnsafe
+    (local.get $2)
+   )
+  )
+  (i32.store
+   (block $label$2 (result i32)
+    (if
+     (i32.eqz
+      (local.get $0)
+     )
+     (local.set $0
+      (call $~lib/memory/memory.allocate
+       (i32.const 8)
+      )
+     )
+    )
+    (i32.store
+     (local.get $0)
+     (i32.const 0)
+    )
+    (i32.store offset=4
+     (local.get $0)
+     (i32.const 0)
+    )
+    (local.get $0)
+   )
+   (local.get $3)
+  )
+  (i32.store offset=4
+   (local.get $0)
+   (local.get $1)
+  )
+  (block $label$4
+   (local.set $4
+    (i32.add
+     (local.get $3)
+     (i32.const 8)
+    )
+   )
+   (local.set $5
+    (i32.const 0)
+   )
+   (local.set $6
+    (local.get $2)
+   )
+   (call $~lib/internal/memory/memset
+    (local.get $4)
+    (local.get $5)
+    (local.get $6)
+   )
+  )
+  (local.get $0)
+ )
+ (func $~lib/array/Array<Body>#__unchecked_set (; 19 ;) (type $7) (param $0 i32) (param $1 i32) (param $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local.set $3
+   (i32.load
+    (local.get $0)
+   )
+  )
+  (local.set $4
+   (local.get $1)
+  )
+  (local.set $5
+   (local.get $2)
+  )
+  (local.set $6
+   (i32.const 0)
+  )
+  (i32.store offset=8
+   (i32.add
+    (i32.add
+     (local.get $3)
+     (i32.shl
+      (local.get $4)
+      (i32.const 2)
+     )
+    )
+    (local.get $6)
+   )
+   (local.get $5)
+  )
+ )
+ (func $assembly/index/init (; 20 ;) (type $0)
+  (local $0 i32)
+  (global.set $global$5
+   (call $assembly/index/NBodySystem#constructor
+    (i32.const 0)
+    (block $label$1 (result i32)
+     (local.set $0
+      (call $~lib/array/Array<Body>#constructor
+       (i32.const 0)
+       (i32.const 5)
+      )
+     )
+     (call $~lib/array/Array<Body>#__unchecked_set
+      (local.get $0)
+      (i32.const 0)
+      (call $assembly/index/Sun)
+     )
+     (call $~lib/array/Array<Body>#__unchecked_set
+      (local.get $0)
+      (i32.const 1)
+      (call $assembly/index/Jupiter)
+     )
+     (call $~lib/array/Array<Body>#__unchecked_set
+      (local.get $0)
+      (i32.const 2)
+      (call $assembly/index/Saturn)
+     )
+     (call $~lib/array/Array<Body>#__unchecked_set
+      (local.get $0)
+      (i32.const 3)
+      (call $assembly/index/Uranus)
+     )
+     (call $~lib/array/Array<Body>#__unchecked_set
+      (local.get $0)
+      (i32.const 4)
+      (call $assembly/index/Neptune)
+     )
+     (local.get $0)
+    )
+   )
+  )
+ )
+ (func $assembly/index/NBodySystem#advance (; 21 ;) (type $9) (param $0 i32) (param $1 f64)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 f64)
+  (local $9 f64)
+  (local $10 f64)
+  (local $11 f64)
+  (local $12 f64)
+  (local $13 f64)
+  (local $14 f64)
+  (local $15 f64)
+  (local $16 f64)
+  (local $17 f64)
+  (local $18 f64)
+  (local $19 f64)
+  (local $20 f64)
+  (local $21 f64)
+  (local $22 f64)
+  (local.set $2
+   (i32.load
+    (local.get $0)
+   )
+  )
+  (local.set $4
+   (block $label$1 (result i32)
+    (local.set $3
+     (local.get $2)
+    )
+    (i32.load offset=4
+     (local.get $3)
+    )
+   )
+  )
+  (block $label$2
+   (local.set $3
+    (i32.const 0)
+   )
+   (loop $label$3
+    (br_if $label$2
+     (i32.eqz
+      (i32.lt_u
+       (local.get $3)
+       (local.get $4)
+      )
+     )
+    )
+    (block $label$4
+     (local.set $5
+      (call $~lib/array/Array<Body>#__unchecked_get
+       (local.get $2)
+       (local.get $3)
+      )
+     )
+     (local.set $8
+      (f64.load
+       (local.get $5)
+      )
+     )
+     (local.set $9
+      (f64.load offset=8
+       (local.get $5)
+      )
+     )
+     (local.set $10
+      (f64.load offset=16
+       (local.get $5)
+      )
+     )
+     (local.set $11
+      (f64.load offset=24
+       (local.get $5)
+      )
+     )
+     (local.set $12
+      (f64.load offset=32
+       (local.get $5)
+      )
+     )
+     (local.set $13
+      (f64.load offset=40
+       (local.get $5)
+      )
+     )
+     (local.set $14
+      (f64.load offset=48
+       (local.get $5)
+      )
+     )
+     (block $label$5
+      (local.set $6
+       (i32.add
+        (local.get $3)
+        (i32.const 1)
+       )
+      )
+      (loop $label$6
+       (br_if $label$5
+        (i32.eqz
+         (i32.lt_u
+          (local.get $6)
+          (local.get $4)
+         )
+        )
+       )
+       (block $label$7
+        (local.set $7
+         (call $~lib/array/Array<Body>#__unchecked_get
+          (local.get $2)
+          (local.get $6)
+         )
+        )
+        (local.set $15
+         (f64.sub
+          (local.get $8)
+          (f64.load
+           (local.get $7)
+          )
+         )
+        )
+        (local.set $16
+         (f64.sub
+          (local.get $9)
+          (f64.load offset=8
+           (local.get $7)
+          )
+         )
+        )
+        (local.set $17
+         (f64.sub
+          (local.get $10)
+          (f64.load offset=16
+           (local.get $7)
+          )
+         )
+        )
+        (local.set $18
+         (f64.add
+          (f64.add
+           (f64.mul
+            (local.get $15)
+            (local.get $15)
+           )
+           (f64.mul
+            (local.get $16)
+            (local.get $16)
+           )
+          )
+          (f64.mul
+           (local.get $17)
+           (local.get $17)
+          )
+         )
+        )
+        (local.set $19
+         (block $label$8 (result f64)
+          (local.set $19
+           (local.get $18)
+          )
+          (f64.sqrt
+           (local.get $19)
+          )
+         )
+        )
+        (local.set $20
+         (f64.div
+          (local.get $1)
+          (f64.mul
+           (local.get $18)
+           (local.get $19)
+          )
+         )
+        )
+        (local.set $21
+         (f64.mul
+          (local.get $14)
+          (local.get $20)
+         )
+        )
+        (local.set $22
+         (f64.mul
+          (f64.load offset=48
+           (local.get $7)
+          )
+          (local.get $20)
+         )
+        )
+        (local.set $11
+         (f64.sub
+          (local.get $11)
+          (f64.mul
+           (local.get $15)
+           (local.get $22)
+          )
+         )
+        )
+        (local.set $12
+         (f64.sub
+          (local.get $12)
+          (f64.mul
+           (local.get $16)
+           (local.get $22)
+          )
+         )
+        )
+        (local.set $13
+         (f64.sub
+          (local.get $13)
+          (f64.mul
+           (local.get $17)
+           (local.get $22)
+          )
+         )
+        )
+        (f64.store offset=24
+         (local.get $7)
+         (f64.add
+          (f64.load offset=24
+           (local.get $7)
+          )
+          (f64.mul
+           (local.get $15)
+           (local.get $21)
+          )
+         )
+        )
+        (f64.store offset=32
+         (local.get $7)
+         (f64.add
+          (f64.load offset=32
+           (local.get $7)
+          )
+          (f64.mul
+           (local.get $16)
+           (local.get $21)
+          )
+         )
+        )
+        (f64.store offset=40
+         (local.get $7)
+         (f64.add
+          (f64.load offset=40
+           (local.get $7)
+          )
+          (f64.mul
+           (local.get $17)
+           (local.get $21)
+          )
+         )
+        )
+       )
+       (local.set $6
+        (i32.add
+         (local.get $6)
+         (i32.const 1)
+        )
+       )
+       (br $label$6)
+      )
+     )
+     (f64.store offset=24
+      (local.get $5)
+      (local.get $11)
+     )
+     (f64.store offset=32
+      (local.get $5)
+      (local.get $12)
+     )
+     (f64.store offset=40
+      (local.get $5)
+      (local.get $13)
+     )
+     (f64.store
+      (local.get $5)
+      (f64.add
+       (f64.load
+        (local.get $5)
+       )
+       (f64.mul
+        (local.get $1)
+        (local.get $11)
+       )
+      )
+     )
+     (f64.store offset=8
+      (local.get $5)
+      (f64.add
+       (f64.load offset=8
+        (local.get $5)
+       )
+       (f64.mul
+        (local.get $1)
+        (local.get $12)
+       )
+      )
+     )
+     (f64.store offset=16
+      (local.get $5)
+      (f64.add
+       (f64.load offset=16
+        (local.get $5)
+       )
+       (f64.mul
+        (local.get $1)
+        (local.get $13)
+       )
+      )
+     )
+    )
+    (local.set $3
+     (i32.add
+      (local.get $3)
+      (i32.const 1)
+     )
+    )
+    (br $label$3)
+   )
+  )
+ )
+ (func $assembly/index/NBodySystem#energy (; 22 ;) (type $10) (param $0 i32) (result f64)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 f64)
+  (local $8 f64)
+  (local $9 f64)
+  (local $10 f64)
+  (local $11 f64)
+  (local $12 f64)
+  (local $13 f64)
+  (local $14 f64)
+  (local $15 f64)
+  (local $16 f64)
+  (local $17 f64)
+  (local $18 f64)
+  (local.set $7
+   (f64.const 0)
+  )
+  (local.set $1
+   (i32.load
+    (local.get $0)
+   )
+  )
+  (block $label$1
+   (block $label$2
+    (local.set $2
+     (i32.const 0)
+    )
+    (local.set $3
+     (block $label$3 (result i32)
+      (local.set $3
+       (local.get $1)
+      )
+      (i32.load offset=4
+       (local.get $3)
+      )
+     )
+    )
+   )
+   (loop $label$4
+    (br_if $label$1
+     (i32.eqz
+      (i32.lt_u
+       (local.get $2)
+       (local.get $3)
+      )
+     )
+    )
+    (block $label$5
+     (local.set $4
+      (call $~lib/array/Array<Body>#__unchecked_get
+       (local.get $1)
+       (local.get $2)
+      )
+     )
+     (local.set $8
+      (f64.load
+       (local.get $4)
+      )
+     )
+     (local.set $9
+      (f64.load offset=8
+       (local.get $4)
+      )
+     )
+     (local.set $10
+      (f64.load offset=16
+       (local.get $4)
+      )
+     )
+     (local.set $11
+      (f64.load offset=24
+       (local.get $4)
+      )
+     )
+     (local.set $12
+      (f64.load offset=32
+       (local.get $4)
+      )
+     )
+     (local.set $13
+      (f64.load offset=40
+       (local.get $4)
+      )
+     )
+     (local.set $14
+      (f64.load offset=48
+       (local.get $4)
+      )
+     )
+     (local.set $7
+      (f64.add
+       (local.get $7)
+       (f64.mul
+        (f64.mul
+         (f64.const 0.5)
+         (local.get $14)
+        )
+        (f64.add
+         (f64.add
+          (f64.mul
+           (local.get $11)
+           (local.get $11)
+          )
+          (f64.mul
+           (local.get $12)
+           (local.get $12)
+          )
+         )
+         (f64.mul
+          (local.get $13)
+          (local.get $13)
+         )
+        )
+       )
+      )
+     )
+     (block $label$6
+      (local.set $5
+       (i32.add
+        (local.get $2)
+        (i32.const 1)
+       )
+      )
+      (loop $label$7
+       (br_if $label$6
+        (i32.eqz
+         (i32.lt_u
+          (local.get $5)
+          (local.get $3)
+         )
+        )
+       )
+       (block $label$8
+        (local.set $6
+         (call $~lib/array/Array<Body>#__unchecked_get
+          (local.get $1)
+          (local.get $5)
+         )
+        )
+        (local.set $15
+         (f64.sub
+          (local.get $8)
+          (f64.load
+           (local.get $6)
+          )
+         )
+        )
+        (local.set $16
+         (f64.sub
+          (local.get $9)
+          (f64.load offset=8
+           (local.get $6)
+          )
+         )
+        )
+        (local.set $17
+         (f64.sub
+          (local.get $10)
+          (f64.load offset=16
+           (local.get $6)
+          )
+         )
+        )
+        (local.set $18
+         (block $label$9 (result f64)
+          (local.set $18
+           (f64.add
+            (f64.add
+             (f64.mul
+              (local.get $15)
+              (local.get $15)
+             )
+             (f64.mul
+              (local.get $16)
+              (local.get $16)
+             )
+            )
+            (f64.mul
+             (local.get $17)
+             (local.get $17)
+            )
+           )
+          )
+          (f64.sqrt
+           (local.get $18)
+          )
+         )
+        )
+        (local.set $7
+         (f64.sub
+          (local.get $7)
+          (f64.div
+           (f64.mul
+            (local.get $14)
+            (f64.load offset=48
+             (local.get $6)
+            )
+           )
+           (local.get $18)
+          )
+         )
+        )
+       )
+       (local.set $5
+        (i32.add
+         (local.get $5)
+         (i32.const 1)
+        )
+       )
+       (br $label$7)
+      )
+     )
+    )
+    (local.set $2
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+    )
+    (br $label$4)
+   )
+  )
+  (local.get $7)
+ )
+ (func $assembly/index/step (; 23 ;) (type $8) (result f64)
+  (call $assembly/index/NBodySystem#advance
+   (global.get $global$5)
+   (f64.const 0.01)
+  )
+  (call $assembly/index/NBodySystem#energy
+   (global.get $global$5)
+  )
+ )
+ (func $assembly/index/bench (; 24 ;) (type $11) (param $0 i32)
+  (local $1 i32)
+  (block $label$1
+   (local.set $1
+    (i32.const 0)
+   )
+   (loop $label$2
+    (br_if $label$1
+     (i32.eqz
+      (i32.lt_u
+       (local.get $1)
+       (local.get $0)
+      )
+     )
+    )
+    (call $assembly/index/NBodySystem#advance
+     (global.get $global$5)
+     (f64.const 0.01)
+    )
+    (local.set $1
+     (i32.add
+      (local.get $1)
+      (i32.const 1)
+     )
+    )
+    (br $label$2)
+   )
+  )
+ )
+ (func $assembly/index/getBody (; 25 ;) (type $3) (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $1
+   (i32.load
+    (global.get $global$5)
+   )
+  )
+  (if (result i32)
+   (i32.lt_u
+    (local.get $0)
+    (block $label$1 (result i32)
+     (local.set $2
+      (local.get $1)
+     )
+     (i32.load offset=4
+      (local.get $2)
+     )
+    )
+   )
+   (call $~lib/array/Array<Body>#__get
+    (local.get $1)
+    (local.get $0)
+   )
+   (i32.const 0)
+  )
+ )
+ (func $start (; 26 ;) (type $0)
+  (call $start:assembly/index)
+ )
+ (func $null (; 27 ;) (type $0)
+ )
+)
+
diff --git a/binaryen/test/passes/O_fast-math.txt b/binaryen/test/passes/O_fast-math.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O_fast-math.txt
@@ -0,0 +1,35 @@
+(module
+ (type $none_=>_f32 (func (result f32)))
+ (type $f32_=>_f32 (func (param f32) (result f32)))
+ (type $f64_=>_f64 (func (param f64) (result f64)))
+ (export "div" (func $0))
+ (export "mul1" (func $1))
+ (export "mul2" (func $2))
+ (export "add1" (func $1))
+ (export "add2" (func $2))
+ (export "add3" (func $2))
+ (export "add4" (func $2))
+ (export "sub1" (func $1))
+ (export "sub2" (func $2))
+ (export "mul_neg_one1" (func $9))
+ (export "mul_neg_one2" (func $10))
+ (func $0 (; has Stack IR ;) (result f32)
+  (f32.const -nan:0x23017a)
+ )
+ (func $1 (; has Stack IR ;) (result f32)
+  (f32.const -nan:0x34546d)
+ )
+ (func $2 (; has Stack IR ;) (result f32)
+  (f32.const -nan:0x74546d)
+ )
+ (func $9 (; has Stack IR ;) (param $0 f32) (result f32)
+  (f32.neg
+   (local.get $0)
+  )
+ )
+ (func $10 (; has Stack IR ;) (param $0 f64) (result f64)
+  (f64.neg
+   (local.get $0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/O_fast-math.wast b/binaryen/test/passes/O_fast-math.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O_fast-math.wast
@@ -0,0 +1,69 @@
+;; with fast-math we can optimize some of these patterns
+(module
+ (func "div" (result f32)
+  (f32.div
+   (f32.const -nan:0x23017a)
+   (f32.const 1)
+  )
+ )
+ (func "mul1" (result f32)
+  (f32.mul
+   (f32.const -nan:0x34546d)
+   (f32.const 1)
+  )
+ )
+ (func "mul2" (result f32)
+  (f32.mul
+   (f32.const 1)
+   (f32.const -nan:0x34546d)
+  )
+ )
+ (func "add1" (result f32)
+  (f32.add
+   (f32.const -nan:0x34546d)
+   (f32.const -0)
+  )
+ )
+ (func "add2" (result f32)
+  (f32.add
+   (f32.const -0)
+   (f32.const -nan:0x34546d)
+  )
+ )
+ (func "add3" (result f32)
+  (f32.add
+   (f32.const -nan:0x34546d)
+   (f32.const 0)
+  )
+ )
+ (func "add4" (result f32)
+  (f32.add
+   (f32.const 0)
+   (f32.const -nan:0x34546d)
+  )
+ )
+ (func "sub1" (result f32)
+  (f32.sub
+   (f32.const -nan:0x34546d)
+   (f32.const 0)
+  )
+ )
+ (func "sub2" (result f32)
+  (f32.sub
+   (f32.const -nan:0x34546d)
+   (f32.const -0)
+  )
+ )
+ (func "mul_neg_one1" (param $x f32) (result f32)
+  (f32.mul
+   (local.get $x)
+   (f32.const -1)
+  )
+ )
+ (func "mul_neg_one2" (param $x f64) (result f64)
+  (f64.mul
+   (local.get $x)
+   (f64.const -1)
+  )
+ )
+)
diff --git a/binaryen/test/passes/Os_print-stack-ir_all-features.txt b/binaryen/test/passes/Os_print-stack-ir_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/Os_print-stack-ir_all-features.txt
@@ -0,0 +1,95 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "stacky-help" (func $stacky-help))
+ (func $stacky-help (param $0 i32) (result i32)
+  i32.const 0
+  call $stacky-help
+  i32.const 1
+  call $stacky-help
+  i32.const 2
+  call $stacky-help
+  drop
+  i32.eqz
+  i32.add
+ )
+)
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "stacky-help" (func $stacky-help))
+ (func $stacky-help (; has Stack IR ;) (param $0 i32) (result i32)
+  (i32.add
+   (call $stacky-help
+    (i32.const 0)
+   )
+   (block (result i32)
+    (local.set $0
+     (call $stacky-help
+      (i32.const 1)
+     )
+    )
+    (drop
+     (call $stacky-help
+      (i32.const 2)
+     )
+    )
+    (i32.eqz
+     (local.get $0)
+    )
+   )
+  )
+ )
+)
+(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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/Os_print-stack-ir_all-features.wast
@@ -0,0 +1,36 @@
+(module
+ (export "stacky-help" (func $stacky-help))
+ (func $stacky-help (param $x i32) (result i32)
+  (local $temp i32)
+  (i32.add
+   (call $stacky-help (i32.const 0))
+   (i32.eqz
+    (block (result i32) ;; after we use the stack instead of the local, we can remove this block
+     (local.set $temp (call $stacky-help (i32.const 1)))
+     (drop (call $stacky-help (i32.const 2)))
+     (local.get $temp)
+    )
+   )
+  )
+ )
+)
+(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.txt b/binaryen/test/passes/Oz.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/Oz.txt
@@ -0,0 +1,50 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32) (result i32)))
+ (memory $0 100 100)
+ (export "localcse" (func $basics))
+ (export "localcse-2" (func $8))
+ (func $basics (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+ (func $8 (; has Stack IR ;) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
+  (i32.store
+   (local.tee $0
+    (i32.add
+     (local.get $1)
+     (i32.const 4)
+    )
+   )
+   (i32.and
+    (i32.load
+     (local.get $0)
+    )
+    (i32.const -75)
+   )
+  )
+  (i32.store
+   (local.tee $0
+    (i32.add
+     (local.get $1)
+     (i32.const 4)
+    )
+   )
+   (i32.or
+    (i32.load
+     (local.get $0)
+    )
+    (i32.const 8)
+   )
+  )
+  (i32.const 0)
+ )
+)
diff --git a/binaryen/test/passes/Oz.wast b/binaryen/test/passes/Oz.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/Oz.wast
@@ -0,0 +1,59 @@
+(module
+  (memory 100 100)
+  (func $basics (export "localcse") (param $x i32) ($param $y i32) (result i32) ;; -O3 does localcse
+    (local $x2 i32)
+    (local $y2 i32)
+    (local.set $x2
+      (i32.add (local.get $x) (local.get $y))
+    )
+    (local.set $y2
+      (i32.add (local.get $x) (local.get $y))
+    )
+    (i32.add (local.get $x2) (local.get $y2))
+  )
+  (func $8 (export "localcse-2") (param $var$0 i32)
+    (param $var$1 i32)
+    (param $var$2 i32)
+    (param $var$3 i32)
+    (result i32)
+    (block $label$0 (result i32)
+      (i32.store
+        (local.tee $var$2
+          (i32.add
+            (local.get $var$1)
+            (i32.const 4)
+          )
+        )
+        (i32.and
+          (i32.load
+            (local.get $var$2)
+          )
+          (i32.xor
+            (local.tee $var$2
+              (i32.const 74)
+            )
+            (i32.const -1)
+          )
+        )
+      )
+      (i32.store
+        (local.tee $var$1
+          (i32.add
+            (local.get $var$1)
+            (i32.const 4)
+          )
+        )
+        (i32.or
+          (i32.load
+            (local.get $var$1)
+          )
+          (i32.and
+            (local.get $var$2)
+            (i32.const 8)
+          )
+        )
+      )
+      (i32.const 0)
+    )
+  )
+)
diff --git a/binaryen/test/passes/alignment-lowering.txt b/binaryen/test/passes/alignment-lowering.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/alignment-lowering.txt
@@ -0,0 +1,1948 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 1 1)
+ (func $func_4
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (drop
+   (i32.load
+    (i32.const 4)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $0
+     (i32.const 4)
+    )
+    (i32.or
+     (i32.or
+      (i32.load8_u
+       (local.get $0)
+      )
+      (i32.shl
+       (i32.load8_u offset=1
+        (local.get $0)
+       )
+       (i32.const 8)
+      )
+     )
+     (i32.or
+      (i32.shl
+       (i32.load8_u offset=2
+        (local.get $0)
+       )
+       (i32.const 16)
+      )
+      (i32.shl
+       (i32.load8_u offset=3
+        (local.get $0)
+       )
+       (i32.const 24)
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $1
+     (i32.const 4)
+    )
+    (i32.or
+     (i32.load16_u
+      (local.get $1)
+     )
+     (i32.shl
+      (i32.load16_u offset=2
+       (local.get $1)
+      )
+      (i32.const 16)
+     )
+    )
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 4)
+   )
+  )
+  (drop
+   (i32.load offset=100
+    (i32.const 4)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $2
+     (i32.const 4)
+    )
+    (i32.or
+     (i32.or
+      (i32.load8_u offset=100
+       (local.get $2)
+      )
+      (i32.shl
+       (i32.load8_u offset=101
+        (local.get $2)
+       )
+       (i32.const 8)
+      )
+     )
+     (i32.or
+      (i32.shl
+       (i32.load8_u offset=102
+        (local.get $2)
+       )
+       (i32.const 16)
+      )
+      (i32.shl
+       (i32.load8_u offset=103
+        (local.get $2)
+       )
+       (i32.const 24)
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $3
+     (i32.const 4)
+    )
+    (i32.or
+     (i32.load16_u offset=100
+      (local.get $3)
+     )
+     (i32.shl
+      (i32.load16_u offset=102
+       (local.get $3)
+      )
+      (i32.const 16)
+     )
+    )
+   )
+  )
+  (drop
+   (i32.load offset=100
+    (i32.const 4)
+   )
+  )
+  (drop
+   (unreachable)
+  )
+  (i32.store
+   (i32.const 4)
+   (i32.const 8)
+  )
+  (block
+   (local.set $4
+    (i32.const 4)
+   )
+   (local.set $5
+    (i32.const 8)
+   )
+   (i32.store8
+    (local.get $4)
+    (local.get $5)
+   )
+   (i32.store8 offset=1
+    (local.get $4)
+    (i32.shr_u
+     (local.get $5)
+     (i32.const 8)
+    )
+   )
+   (i32.store8 offset=2
+    (local.get $4)
+    (i32.shr_u
+     (local.get $5)
+     (i32.const 16)
+    )
+   )
+   (i32.store8 offset=3
+    (local.get $4)
+    (i32.shr_u
+     (local.get $5)
+     (i32.const 24)
+    )
+   )
+  )
+  (block
+   (local.set $6
+    (i32.const 4)
+   )
+   (local.set $7
+    (i32.const 8)
+   )
+   (i32.store16
+    (local.get $6)
+    (local.get $7)
+   )
+   (i32.store16 offset=2
+    (local.get $6)
+    (i32.shr_u
+     (local.get $7)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store
+   (i32.const 4)
+   (i32.const 8)
+  )
+  (i32.store offset=100
+   (i32.const 4)
+   (i32.const 8)
+  )
+  (block
+   (local.set $8
+    (i32.const 4)
+   )
+   (local.set $9
+    (i32.const 8)
+   )
+   (i32.store8 offset=100
+    (local.get $8)
+    (local.get $9)
+   )
+   (i32.store8 offset=101
+    (local.get $8)
+    (i32.shr_u
+     (local.get $9)
+     (i32.const 8)
+    )
+   )
+   (i32.store8 offset=102
+    (local.get $8)
+    (i32.shr_u
+     (local.get $9)
+     (i32.const 16)
+    )
+   )
+   (i32.store8 offset=103
+    (local.get $8)
+    (i32.shr_u
+     (local.get $9)
+     (i32.const 24)
+    )
+   )
+  )
+  (block
+   (local.set $10
+    (i32.const 4)
+   )
+   (local.set $11
+    (i32.const 8)
+   )
+   (i32.store16 offset=100
+    (local.get $10)
+    (local.get $11)
+   )
+   (i32.store16 offset=102
+    (local.get $10)
+    (i32.shr_u
+     (local.get $11)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store offset=100
+   (i32.const 4)
+   (i32.const 8)
+  )
+  (block
+   (drop
+    (unreachable)
+   )
+   (drop
+    (i32.const 8)
+   )
+  )
+  (block
+   (drop
+    (i32.const 4)
+   )
+   (drop
+    (unreachable)
+   )
+  )
+ )
+ (func $func_2
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (drop
+   (i32.load16_u
+    (i32.const 4)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $0
+     (i32.const 4)
+    )
+    (i32.or
+     (i32.load8_u
+      (local.get $0)
+     )
+     (i32.shl
+      (i32.load8_u offset=1
+       (local.get $0)
+      )
+      (i32.const 8)
+     )
+    )
+   )
+  )
+  (drop
+   (i32.load16_u
+    (i32.const 4)
+   )
+  )
+  (drop
+   (i32.load16_u offset=100
+    (i32.const 4)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $1
+     (i32.const 4)
+    )
+    (i32.or
+     (i32.load8_u offset=100
+      (local.get $1)
+     )
+     (i32.shl
+      (i32.load8_u offset=101
+       (local.get $1)
+      )
+      (i32.const 8)
+     )
+    )
+   )
+  )
+  (drop
+   (i32.load16_u offset=100
+    (i32.const 4)
+   )
+  )
+  (drop
+   (unreachable)
+  )
+  (i32.store16
+   (i32.const 4)
+   (i32.const 8)
+  )
+  (block
+   (local.set $2
+    (i32.const 4)
+   )
+   (local.set $3
+    (i32.const 8)
+   )
+   (i32.store8
+    (local.get $2)
+    (local.get $3)
+   )
+   (i32.store8 offset=1
+    (local.get $2)
+    (i32.shr_u
+     (local.get $3)
+     (i32.const 8)
+    )
+   )
+  )
+  (i32.store16
+   (i32.const 4)
+   (i32.const 8)
+  )
+  (i32.store16 offset=100
+   (i32.const 4)
+   (i32.const 8)
+  )
+  (block
+   (local.set $4
+    (i32.const 4)
+   )
+   (local.set $5
+    (i32.const 8)
+   )
+   (i32.store8 offset=100
+    (local.get $4)
+    (local.get $5)
+   )
+   (i32.store8 offset=101
+    (local.get $4)
+    (i32.shr_u
+     (local.get $5)
+     (i32.const 8)
+    )
+   )
+  )
+  (i32.store16 offset=100
+   (i32.const 4)
+   (i32.const 8)
+  )
+  (block
+   (drop
+    (unreachable)
+   )
+   (drop
+    (i32.const 8)
+   )
+  )
+  (block
+   (drop
+    (i32.const 4)
+   )
+   (drop
+    (unreachable)
+   )
+  )
+ )
+ (func $func_1
+  (drop
+   (i32.load8_u
+    (i32.const 4)
+   )
+  )
+  (drop
+   (i32.load8_u
+    (i32.const 4)
+   )
+  )
+  (drop
+   (i32.load8_u offset=100
+    (i32.const 4)
+   )
+  )
+  (drop
+   (i32.load8_u offset=100
+    (i32.const 4)
+   )
+  )
+  (drop
+   (unreachable)
+  )
+  (i32.store8
+   (i32.const 4)
+   (i32.const 8)
+  )
+  (i32.store8
+   (i32.const 4)
+   (i32.const 8)
+  )
+  (i32.store8 offset=100
+   (i32.const 4)
+   (i32.const 8)
+  )
+  (i32.store8 offset=100
+   (i32.const 4)
+   (i32.const 8)
+  )
+  (block
+   (drop
+    (unreachable)
+   )
+   (drop
+    (i32.const 8)
+   )
+  )
+  (block
+   (drop
+    (i32.const 4)
+   )
+   (drop
+    (unreachable)
+   )
+  )
+ )
+ (func $func_signed
+  (local $0 i32)
+  (local $1 i32)
+  (drop
+   (i32.load16_s
+    (i32.const 4)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $0
+     (i32.const 4)
+    )
+    (i32.shr_s
+     (i32.shl
+      (i32.or
+       (i32.load8_u
+        (local.get $0)
+       )
+       (i32.shl
+        (i32.load8_u offset=1
+         (local.get $0)
+        )
+        (i32.const 8)
+       )
+      )
+      (i32.const 16)
+     )
+     (i32.const 16)
+    )
+   )
+  )
+  (drop
+   (i32.load16_s
+    (i32.const 4)
+   )
+  )
+  (drop
+   (i32.load16_s offset=100
+    (i32.const 4)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $1
+     (i32.const 4)
+    )
+    (i32.shr_s
+     (i32.shl
+      (i32.or
+       (i32.load8_u offset=100
+        (local.get $1)
+       )
+       (i32.shl
+        (i32.load8_u offset=101
+         (local.get $1)
+        )
+        (i32.const 8)
+       )
+      )
+      (i32.const 16)
+     )
+     (i32.const 16)
+    )
+   )
+  )
+  (drop
+   (i32.load16_s offset=100
+    (i32.const 4)
+   )
+  )
+  (drop
+   (unreachable)
+  )
+ )
+ (func $i64-load
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (drop
+   (block (result i64)
+    (local.set $0
+     (i32.const 12)
+    )
+    (i64.or
+     (i64.extend_i32_u
+      (block (result i32)
+       (local.set $1
+        (local.get $0)
+       )
+       (i32.or
+        (i32.or
+         (i32.load8_u
+          (local.get $1)
+         )
+         (i32.shl
+          (i32.load8_u offset=1
+           (local.get $1)
+          )
+          (i32.const 8)
+         )
+        )
+        (i32.or
+         (i32.shl
+          (i32.load8_u offset=2
+           (local.get $1)
+          )
+          (i32.const 16)
+         )
+         (i32.shl
+          (i32.load8_u offset=3
+           (local.get $1)
+          )
+          (i32.const 24)
+         )
+        )
+       )
+      )
+     )
+     (i64.shl
+      (i64.extend_i32_u
+       (block (result i32)
+        (local.set $2
+         (local.get $0)
+        )
+        (i32.or
+         (i32.or
+          (i32.load8_u offset=4
+           (local.get $2)
+          )
+          (i32.shl
+           (i32.load8_u offset=5
+            (local.get $2)
+           )
+           (i32.const 8)
+          )
+         )
+         (i32.or
+          (i32.shl
+           (i32.load8_u offset=6
+            (local.get $2)
+           )
+           (i32.const 16)
+          )
+          (i32.shl
+           (i32.load8_u offset=7
+            (local.get $2)
+           )
+           (i32.const 24)
+          )
+         )
+        )
+       )
+      )
+      (i64.const 32)
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i64)
+    (local.set $3
+     (i32.const 16)
+    )
+    (i64.or
+     (i64.extend_i32_u
+      (block (result i32)
+       (local.set $4
+        (local.get $3)
+       )
+       (i32.or
+        (i32.load16_u
+         (local.get $4)
+        )
+        (i32.shl
+         (i32.load16_u offset=2
+          (local.get $4)
+         )
+         (i32.const 16)
+        )
+       )
+      )
+     )
+     (i64.shl
+      (i64.extend_i32_u
+       (block (result i32)
+        (local.set $5
+         (local.get $3)
+        )
+        (i32.or
+         (i32.load16_u offset=4
+          (local.get $5)
+         )
+         (i32.shl
+          (i32.load16_u offset=6
+           (local.get $5)
+          )
+          (i32.const 16)
+         )
+        )
+       )
+      )
+      (i64.const 32)
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i64)
+    (local.set $6
+     (i32.const 20)
+    )
+    (i64.or
+     (i64.extend_i32_u
+      (i32.load
+       (local.get $6)
+      )
+     )
+     (i64.shl
+      (i64.extend_i32_u
+       (i32.load offset=4
+        (local.get $6)
+       )
+      )
+      (i64.const 32)
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i64)
+    (local.set $7
+     (i32.const 20)
+    )
+    (i64.or
+     (i64.extend_i32_u
+      (block (result i32)
+       (local.set $8
+        (local.get $7)
+       )
+       (i32.or
+        (i32.or
+         (i32.load8_u offset=3
+          (local.get $8)
+         )
+         (i32.shl
+          (i32.load8_u offset=4
+           (local.get $8)
+          )
+          (i32.const 8)
+         )
+        )
+        (i32.or
+         (i32.shl
+          (i32.load8_u offset=5
+           (local.get $8)
+          )
+          (i32.const 16)
+         )
+         (i32.shl
+          (i32.load8_u offset=6
+           (local.get $8)
+          )
+          (i32.const 24)
+         )
+        )
+       )
+      )
+     )
+     (i64.shl
+      (i64.extend_i32_u
+       (block (result i32)
+        (local.set $9
+         (local.get $7)
+        )
+        (i32.or
+         (i32.or
+          (i32.load8_u offset=7
+           (local.get $9)
+          )
+          (i32.shl
+           (i32.load8_u offset=8
+            (local.get $9)
+           )
+           (i32.const 8)
+          )
+         )
+         (i32.or
+          (i32.shl
+           (i32.load8_u offset=9
+            (local.get $9)
+           )
+           (i32.const 16)
+          )
+          (i32.shl
+           (i32.load8_u offset=10
+            (local.get $9)
+           )
+           (i32.const 24)
+          )
+         )
+        )
+       )
+      )
+      (i64.const 32)
+     )
+    )
+   )
+  )
+  (drop
+   (i64.extend_i32_s
+    (block (result i32)
+     (local.set $10
+      (i32.const 28)
+     )
+     (i32.shr_s
+      (i32.shl
+       (i32.or
+        (i32.load8_u
+         (local.get $10)
+        )
+        (i32.shl
+         (i32.load8_u offset=1
+          (local.get $10)
+         )
+         (i32.const 8)
+        )
+       )
+       (i32.const 16)
+      )
+      (i32.const 16)
+     )
+    )
+   )
+  )
+  (drop
+   (i64.extend_i32_s
+    (block (result i32)
+     (local.set $11
+      (i32.const 32)
+     )
+     (i32.or
+      (i32.or
+       (i32.load8_u
+        (local.get $11)
+       )
+       (i32.shl
+        (i32.load8_u offset=1
+         (local.get $11)
+        )
+        (i32.const 8)
+       )
+      )
+      (i32.or
+       (i32.shl
+        (i32.load8_u offset=2
+         (local.get $11)
+        )
+        (i32.const 16)
+       )
+       (i32.shl
+        (i32.load8_u offset=3
+         (local.get $11)
+        )
+        (i32.const 24)
+       )
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (block (result i32)
+     (local.set $12
+      (i32.const 40)
+     )
+     (i32.or
+      (i32.load8_u
+       (local.get $12)
+      )
+      (i32.shl
+       (i32.load8_u offset=1
+        (local.get $12)
+       )
+       (i32.const 8)
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (block (result i32)
+     (local.set $13
+      (i32.const 44)
+     )
+     (i32.or
+      (i32.or
+       (i32.load8_u
+        (local.get $13)
+       )
+       (i32.shl
+        (i32.load8_u offset=1
+         (local.get $13)
+        )
+        (i32.const 8)
+       )
+      )
+      (i32.or
+       (i32.shl
+        (i32.load8_u offset=2
+         (local.get $13)
+        )
+        (i32.const 16)
+       )
+       (i32.shl
+        (i32.load8_u offset=3
+         (local.get $13)
+        )
+        (i32.const 24)
+       )
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $f32-load
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (drop
+   (f32.reinterpret_i32
+    (block (result i32)
+     (local.set $0
+      (i32.const 12)
+     )
+     (i32.or
+      (i32.or
+       (i32.load8_u
+        (local.get $0)
+       )
+       (i32.shl
+        (i32.load8_u offset=1
+         (local.get $0)
+        )
+        (i32.const 8)
+       )
+      )
+      (i32.or
+       (i32.shl
+        (i32.load8_u offset=2
+         (local.get $0)
+        )
+        (i32.const 16)
+       )
+       (i32.shl
+        (i32.load8_u offset=3
+         (local.get $0)
+        )
+        (i32.const 24)
+       )
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (f32.reinterpret_i32
+    (block (result i32)
+     (local.set $1
+      (i32.const 16)
+     )
+     (i32.or
+      (i32.load16_u
+       (local.get $1)
+      )
+      (i32.shl
+       (i32.load16_u offset=2
+        (local.get $1)
+       )
+       (i32.const 16)
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (f32.reinterpret_i32
+    (block (result i32)
+     (local.set $2
+      (i32.const 20)
+     )
+     (i32.or
+      (i32.or
+       (i32.load8_u offset=3
+        (local.get $2)
+       )
+       (i32.shl
+        (i32.load8_u offset=4
+         (local.get $2)
+        )
+        (i32.const 8)
+       )
+      )
+      (i32.or
+       (i32.shl
+        (i32.load8_u offset=5
+         (local.get $2)
+        )
+        (i32.const 16)
+       )
+       (i32.shl
+        (i32.load8_u offset=6
+         (local.get $2)
+        )
+        (i32.const 24)
+       )
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $f64-load
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (drop
+   (f64.reinterpret_i64
+    (block (result i64)
+     (local.set $0
+      (i32.const 12)
+     )
+     (i64.or
+      (i64.extend_i32_u
+       (block (result i32)
+        (local.set $1
+         (local.get $0)
+        )
+        (i32.or
+         (i32.or
+          (i32.load8_u
+           (local.get $1)
+          )
+          (i32.shl
+           (i32.load8_u offset=1
+            (local.get $1)
+           )
+           (i32.const 8)
+          )
+         )
+         (i32.or
+          (i32.shl
+           (i32.load8_u offset=2
+            (local.get $1)
+           )
+           (i32.const 16)
+          )
+          (i32.shl
+           (i32.load8_u offset=3
+            (local.get $1)
+           )
+           (i32.const 24)
+          )
+         )
+        )
+       )
+      )
+      (i64.shl
+       (i64.extend_i32_u
+        (block (result i32)
+         (local.set $2
+          (local.get $0)
+         )
+         (i32.or
+          (i32.or
+           (i32.load8_u offset=4
+            (local.get $2)
+           )
+           (i32.shl
+            (i32.load8_u offset=5
+             (local.get $2)
+            )
+            (i32.const 8)
+           )
+          )
+          (i32.or
+           (i32.shl
+            (i32.load8_u offset=6
+             (local.get $2)
+            )
+            (i32.const 16)
+           )
+           (i32.shl
+            (i32.load8_u offset=7
+             (local.get $2)
+            )
+            (i32.const 24)
+           )
+          )
+         )
+        )
+       )
+       (i64.const 32)
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (f64.reinterpret_i64
+    (block (result i64)
+     (local.set $3
+      (i32.const 16)
+     )
+     (i64.or
+      (i64.extend_i32_u
+       (block (result i32)
+        (local.set $4
+         (local.get $3)
+        )
+        (i32.or
+         (i32.load16_u
+          (local.get $4)
+         )
+         (i32.shl
+          (i32.load16_u offset=2
+           (local.get $4)
+          )
+          (i32.const 16)
+         )
+        )
+       )
+      )
+      (i64.shl
+       (i64.extend_i32_u
+        (block (result i32)
+         (local.set $5
+          (local.get $3)
+         )
+         (i32.or
+          (i32.load16_u offset=4
+           (local.get $5)
+          )
+          (i32.shl
+           (i32.load16_u offset=6
+            (local.get $5)
+           )
+           (i32.const 16)
+          )
+         )
+        )
+       )
+       (i64.const 32)
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (f64.reinterpret_i64
+    (block (result i64)
+     (local.set $6
+      (i32.const 20)
+     )
+     (i64.or
+      (i64.extend_i32_u
+       (i32.load
+        (local.get $6)
+       )
+      )
+      (i64.shl
+       (i64.extend_i32_u
+        (i32.load offset=4
+         (local.get $6)
+        )
+       )
+       (i64.const 32)
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (f64.reinterpret_i64
+    (block (result i64)
+     (local.set $7
+      (i32.const 20)
+     )
+     (i64.or
+      (i64.extend_i32_u
+       (block (result i32)
+        (local.set $8
+         (local.get $7)
+        )
+        (i32.or
+         (i32.or
+          (i32.load8_u offset=3
+           (local.get $8)
+          )
+          (i32.shl
+           (i32.load8_u offset=4
+            (local.get $8)
+           )
+           (i32.const 8)
+          )
+         )
+         (i32.or
+          (i32.shl
+           (i32.load8_u offset=5
+            (local.get $8)
+           )
+           (i32.const 16)
+          )
+          (i32.shl
+           (i32.load8_u offset=6
+            (local.get $8)
+           )
+           (i32.const 24)
+          )
+         )
+        )
+       )
+      )
+      (i64.shl
+       (i64.extend_i32_u
+        (block (result i32)
+         (local.set $9
+          (local.get $7)
+         )
+         (i32.or
+          (i32.or
+           (i32.load8_u offset=7
+            (local.get $9)
+           )
+           (i32.shl
+            (i32.load8_u offset=8
+             (local.get $9)
+            )
+            (i32.const 8)
+           )
+          )
+          (i32.or
+           (i32.shl
+            (i32.load8_u offset=9
+             (local.get $9)
+            )
+            (i32.const 16)
+           )
+           (i32.shl
+            (i32.load8_u offset=10
+             (local.get $9)
+            )
+            (i32.const 24)
+           )
+          )
+         )
+        )
+       )
+       (i64.const 32)
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $i64-store
+  (local $0 i32)
+  (local $1 i64)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i64)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i64)
+  (local $14 i32)
+  (local $15 i64)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (local $19 i32)
+  (local $20 i32)
+  (local $21 i32)
+  (local $22 i32)
+  (local $23 i32)
+  (block
+   (local.set $0
+    (i32.const 12)
+   )
+   (local.set $1
+    (i64.const 100)
+   )
+   (block
+    (local.set $2
+     (local.get $0)
+    )
+    (local.set $3
+     (i32.wrap_i64
+      (local.get $1)
+     )
+    )
+    (i32.store8
+     (local.get $2)
+     (local.get $3)
+    )
+    (i32.store8 offset=1
+     (local.get $2)
+     (i32.shr_u
+      (local.get $3)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=2
+     (local.get $2)
+     (i32.shr_u
+      (local.get $3)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=3
+     (local.get $2)
+     (i32.shr_u
+      (local.get $3)
+      (i32.const 24)
+     )
+    )
+   )
+   (block
+    (local.set $4
+     (local.get $0)
+    )
+    (local.set $5
+     (i32.wrap_i64
+      (i64.shr_u
+       (local.get $1)
+       (i64.const 32)
+      )
+     )
+    )
+    (i32.store8 offset=4
+     (local.get $4)
+     (local.get $5)
+    )
+    (i32.store8 offset=5
+     (local.get $4)
+     (i32.shr_u
+      (local.get $5)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=6
+     (local.get $4)
+     (i32.shr_u
+      (local.get $5)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=7
+     (local.get $4)
+     (i32.shr_u
+      (local.get $5)
+      (i32.const 24)
+     )
+    )
+   )
+  )
+  (block
+   (local.set $6
+    (i32.const 16)
+   )
+   (local.set $7
+    (i64.const 200)
+   )
+   (block
+    (local.set $8
+     (local.get $6)
+    )
+    (local.set $9
+     (i32.wrap_i64
+      (local.get $7)
+     )
+    )
+    (i32.store16
+     (local.get $8)
+     (local.get $9)
+    )
+    (i32.store16 offset=2
+     (local.get $8)
+     (i32.shr_u
+      (local.get $9)
+      (i32.const 16)
+     )
+    )
+   )
+   (block
+    (local.set $10
+     (local.get $6)
+    )
+    (local.set $11
+     (i32.wrap_i64
+      (i64.shr_u
+       (local.get $7)
+       (i64.const 32)
+      )
+     )
+    )
+    (i32.store16 offset=4
+     (local.get $10)
+     (local.get $11)
+    )
+    (i32.store16 offset=6
+     (local.get $10)
+     (i32.shr_u
+      (local.get $11)
+      (i32.const 16)
+     )
+    )
+   )
+  )
+  (block
+   (local.set $12
+    (i32.const 20)
+   )
+   (local.set $13
+    (i64.const 300)
+   )
+   (i32.store
+    (local.get $12)
+    (i32.wrap_i64
+     (local.get $13)
+    )
+   )
+   (i32.store offset=4
+    (local.get $12)
+    (i32.wrap_i64
+     (i64.shr_u
+      (local.get $13)
+      (i64.const 32)
+     )
+    )
+   )
+  )
+  (block
+   (local.set $14
+    (i32.const 24)
+   )
+   (local.set $15
+    (i64.const 400)
+   )
+   (block
+    (local.set $16
+     (local.get $14)
+    )
+    (local.set $17
+     (i32.wrap_i64
+      (local.get $15)
+     )
+    )
+    (i32.store8 offset=3
+     (local.get $16)
+     (local.get $17)
+    )
+    (i32.store8 offset=4
+     (local.get $16)
+     (i32.shr_u
+      (local.get $17)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=5
+     (local.get $16)
+     (i32.shr_u
+      (local.get $17)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=6
+     (local.get $16)
+     (i32.shr_u
+      (local.get $17)
+      (i32.const 24)
+     )
+    )
+   )
+   (block
+    (local.set $18
+     (local.get $14)
+    )
+    (local.set $19
+     (i32.wrap_i64
+      (i64.shr_u
+       (local.get $15)
+       (i64.const 32)
+      )
+     )
+    )
+    (i32.store8 offset=7
+     (local.get $18)
+     (local.get $19)
+    )
+    (i32.store8 offset=8
+     (local.get $18)
+     (i32.shr_u
+      (local.get $19)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=9
+     (local.get $18)
+     (i32.shr_u
+      (local.get $19)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=10
+     (local.get $18)
+     (i32.shr_u
+      (local.get $19)
+      (i32.const 24)
+     )
+    )
+   )
+  )
+  (block
+   (local.set $20
+    (i32.const 20)
+   )
+   (local.set $21
+    (i32.wrap_i64
+     (i64.const 600)
+    )
+   )
+   (i32.store8
+    (local.get $20)
+    (local.get $21)
+   )
+   (i32.store8 offset=1
+    (local.get $20)
+    (i32.shr_u
+     (local.get $21)
+     (i32.const 8)
+    )
+   )
+  )
+  (block
+   (local.set $22
+    (i32.const 20)
+   )
+   (local.set $23
+    (i32.wrap_i64
+     (i64.const 700)
+    )
+   )
+   (i32.store8
+    (local.get $22)
+    (local.get $23)
+   )
+   (i32.store8 offset=1
+    (local.get $22)
+    (i32.shr_u
+     (local.get $23)
+     (i32.const 8)
+    )
+   )
+   (i32.store8 offset=2
+    (local.get $22)
+    (i32.shr_u
+     (local.get $23)
+     (i32.const 16)
+    )
+   )
+   (i32.store8 offset=3
+    (local.get $22)
+    (i32.shr_u
+     (local.get $23)
+     (i32.const 24)
+    )
+   )
+  )
+ )
+ (func $f32-store
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (block
+   (local.set $0
+    (i32.const 12)
+   )
+   (local.set $1
+    (i32.reinterpret_f32
+     (f32.const 100)
+    )
+   )
+   (i32.store8
+    (local.get $0)
+    (local.get $1)
+   )
+   (i32.store8 offset=1
+    (local.get $0)
+    (i32.shr_u
+     (local.get $1)
+     (i32.const 8)
+    )
+   )
+   (i32.store8 offset=2
+    (local.get $0)
+    (i32.shr_u
+     (local.get $1)
+     (i32.const 16)
+    )
+   )
+   (i32.store8 offset=3
+    (local.get $0)
+    (i32.shr_u
+     (local.get $1)
+     (i32.const 24)
+    )
+   )
+  )
+  (block
+   (local.set $2
+    (i32.const 16)
+   )
+   (local.set $3
+    (i32.reinterpret_f32
+     (f32.const 200)
+    )
+   )
+   (i32.store16
+    (local.get $2)
+    (local.get $3)
+   )
+   (i32.store16 offset=2
+    (local.get $2)
+    (i32.shr_u
+     (local.get $3)
+     (i32.const 16)
+    )
+   )
+  )
+  (block
+   (local.set $4
+    (i32.const 24)
+   )
+   (local.set $5
+    (i32.reinterpret_f32
+     (f32.const 400)
+    )
+   )
+   (i32.store8 offset=3
+    (local.get $4)
+    (local.get $5)
+   )
+   (i32.store8 offset=4
+    (local.get $4)
+    (i32.shr_u
+     (local.get $5)
+     (i32.const 8)
+    )
+   )
+   (i32.store8 offset=5
+    (local.get $4)
+    (i32.shr_u
+     (local.get $5)
+     (i32.const 16)
+    )
+   )
+   (i32.store8 offset=6
+    (local.get $4)
+    (i32.shr_u
+     (local.get $5)
+     (i32.const 24)
+    )
+   )
+  )
+ )
+ (func $f64-store
+  (local $0 i32)
+  (local $1 i64)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i64)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i64)
+  (local $14 i32)
+  (local $15 i64)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (local $19 i32)
+  (block
+   (local.set $0
+    (i32.const 12)
+   )
+   (local.set $1
+    (i64.reinterpret_f64
+     (f64.const 100)
+    )
+   )
+   (block
+    (local.set $2
+     (local.get $0)
+    )
+    (local.set $3
+     (i32.wrap_i64
+      (local.get $1)
+     )
+    )
+    (i32.store8
+     (local.get $2)
+     (local.get $3)
+    )
+    (i32.store8 offset=1
+     (local.get $2)
+     (i32.shr_u
+      (local.get $3)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=2
+     (local.get $2)
+     (i32.shr_u
+      (local.get $3)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=3
+     (local.get $2)
+     (i32.shr_u
+      (local.get $3)
+      (i32.const 24)
+     )
+    )
+   )
+   (block
+    (local.set $4
+     (local.get $0)
+    )
+    (local.set $5
+     (i32.wrap_i64
+      (i64.shr_u
+       (local.get $1)
+       (i64.const 32)
+      )
+     )
+    )
+    (i32.store8 offset=4
+     (local.get $4)
+     (local.get $5)
+    )
+    (i32.store8 offset=5
+     (local.get $4)
+     (i32.shr_u
+      (local.get $5)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=6
+     (local.get $4)
+     (i32.shr_u
+      (local.get $5)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=7
+     (local.get $4)
+     (i32.shr_u
+      (local.get $5)
+      (i32.const 24)
+     )
+    )
+   )
+  )
+  (block
+   (local.set $6
+    (i32.const 16)
+   )
+   (local.set $7
+    (i64.reinterpret_f64
+     (f64.const 200)
+    )
+   )
+   (block
+    (local.set $8
+     (local.get $6)
+    )
+    (local.set $9
+     (i32.wrap_i64
+      (local.get $7)
+     )
+    )
+    (i32.store16
+     (local.get $8)
+     (local.get $9)
+    )
+    (i32.store16 offset=2
+     (local.get $8)
+     (i32.shr_u
+      (local.get $9)
+      (i32.const 16)
+     )
+    )
+   )
+   (block
+    (local.set $10
+     (local.get $6)
+    )
+    (local.set $11
+     (i32.wrap_i64
+      (i64.shr_u
+       (local.get $7)
+       (i64.const 32)
+      )
+     )
+    )
+    (i32.store16 offset=4
+     (local.get $10)
+     (local.get $11)
+    )
+    (i32.store16 offset=6
+     (local.get $10)
+     (i32.shr_u
+      (local.get $11)
+      (i32.const 16)
+     )
+    )
+   )
+  )
+  (block
+   (local.set $12
+    (i32.const 20)
+   )
+   (local.set $13
+    (i64.reinterpret_f64
+     (f64.const 300)
+    )
+   )
+   (i32.store
+    (local.get $12)
+    (i32.wrap_i64
+     (local.get $13)
+    )
+   )
+   (i32.store offset=4
+    (local.get $12)
+    (i32.wrap_i64
+     (i64.shr_u
+      (local.get $13)
+      (i64.const 32)
+     )
+    )
+   )
+  )
+  (block
+   (local.set $14
+    (i32.const 24)
+   )
+   (local.set $15
+    (i64.reinterpret_f64
+     (f64.const 400)
+    )
+   )
+   (block
+    (local.set $16
+     (local.get $14)
+    )
+    (local.set $17
+     (i32.wrap_i64
+      (local.get $15)
+     )
+    )
+    (i32.store8 offset=3
+     (local.get $16)
+     (local.get $17)
+    )
+    (i32.store8 offset=4
+     (local.get $16)
+     (i32.shr_u
+      (local.get $17)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=5
+     (local.get $16)
+     (i32.shr_u
+      (local.get $17)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=6
+     (local.get $16)
+     (i32.shr_u
+      (local.get $17)
+      (i32.const 24)
+     )
+    )
+   )
+   (block
+    (local.set $18
+     (local.get $14)
+    )
+    (local.set $19
+     (i32.wrap_i64
+      (i64.shr_u
+       (local.get $15)
+       (i64.const 32)
+      )
+     )
+    )
+    (i32.store8 offset=7
+     (local.get $18)
+     (local.get $19)
+    )
+    (i32.store8 offset=8
+     (local.get $18)
+     (i32.shr_u
+      (local.get $19)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=9
+     (local.get $18)
+     (i32.shr_u
+      (local.get $19)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=10
+     (local.get $18)
+     (i32.shr_u
+      (local.get $19)
+      (i32.const 24)
+     )
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/alignment-lowering.wast b/binaryen/test/passes/alignment-lowering.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/alignment-lowering.wast
@@ -0,0 +1,103 @@
+(module
+ (memory $0 1 1)
+ (func $func_4
+  (drop (i32.load (i32.const 4)))
+  (drop (i32.load align=1 (i32.const 4)))
+  (drop (i32.load align=2 (i32.const 4)))
+  (drop (i32.load align=4 (i32.const 4)))
+  (drop (i32.load offset=100 (i32.const 4)))
+  (drop (i32.load offset=100 align=1 (i32.const 4)))
+  (drop (i32.load offset=100 align=2 (i32.const 4)))
+  (drop (i32.load offset=100 align=4 (i32.const 4)))
+  (drop (i32.load offset=100 align=1 (unreachable)))
+  (i32.store (i32.const 4) (i32.const 8))
+  (i32.store align=1 (i32.const 4) (i32.const 8))
+  (i32.store align=2 (i32.const 4) (i32.const 8))
+  (i32.store align=4 (i32.const 4) (i32.const 8))
+  (i32.store offset=100 (i32.const 4) (i32.const 8))
+  (i32.store offset=100 align=1 (i32.const 4) (i32.const 8))
+  (i32.store offset=100 align=2 (i32.const 4) (i32.const 8))
+  (i32.store offset=100 align=4 (i32.const 4) (i32.const 8))
+  (i32.store offset=100 align=1 (unreachable) (i32.const 8))
+  (i32.store offset=100 align=1 (i32.const 4) (unreachable))
+ )
+ (func $func_2
+  (drop (i32.load16_u (i32.const 4)))
+  (drop (i32.load16_u align=1 (i32.const 4)))
+  (drop (i32.load16_u align=2 (i32.const 4)))
+  (drop (i32.load16_u offset=100 (i32.const 4)))
+  (drop (i32.load16_u offset=100 align=1 (i32.const 4)))
+  (drop (i32.load16_u offset=100 align=2 (i32.const 4)))
+  (drop (i32.load16_u offset=100 align=1 (unreachable)))
+  (i32.store16 (i32.const 4) (i32.const 8))
+  (i32.store16 align=1 (i32.const 4) (i32.const 8))
+  (i32.store16 align=2 (i32.const 4) (i32.const 8))
+  (i32.store16 offset=100 (i32.const 4) (i32.const 8))
+  (i32.store16 offset=100 align=1 (i32.const 4) (i32.const 8))
+  (i32.store16 offset=100 align=2 (i32.const 4) (i32.const 8))
+  (i32.store16 offset=100 align=1 (unreachable) (i32.const 8))
+  (i32.store16 offset=100 align=1 (i32.const 4) (unreachable))
+ )
+ (func $func_1
+  (drop (i32.load8_u (i32.const 4)))
+  (drop (i32.load8_u align=1 (i32.const 4)))
+  (drop (i32.load8_u offset=100 (i32.const 4)))
+  (drop (i32.load8_u offset=100 align=1 (i32.const 4)))
+  (drop (i32.load8_u offset=100 align=1 (unreachable)))
+  (i32.store8 (i32.const 4) (i32.const 8))
+  (i32.store8 align=1 (i32.const 4) (i32.const 8))
+  (i32.store8 offset=100 (i32.const 4) (i32.const 8))
+  (i32.store8 offset=100 align=1 (i32.const 4) (i32.const 8))
+  (i32.store8 offset=100 align=1 (unreachable) (i32.const 8))
+  (i32.store8 offset=100 align=1 (i32.const 4) (unreachable))
+ )
+ (func $func_signed
+  (drop (i32.load16_s (i32.const 4)))
+  (drop (i32.load16_s align=1 (i32.const 4)))
+  (drop (i32.load16_s align=2 (i32.const 4)))
+  (drop (i32.load16_s offset=100 (i32.const 4)))
+  (drop (i32.load16_s offset=100 align=1 (i32.const 4)))
+  (drop (i32.load16_s offset=100 align=2 (i32.const 4)))
+  (drop (i32.load16_s offset=100 align=1 (unreachable)))
+ )
+ (func $i64-load
+  (drop (i64.load align=1 (i32.const 12)))
+  (drop (i64.load align=2 (i32.const 16)))
+  (drop (i64.load align=4 (i32.const 20)))
+  (drop (i64.load align=1 offset=3 (i32.const 20)))
+  (drop (i64.load16_s align=1 (i32.const 28)))
+  (drop (i64.load32_s align=1 (i32.const 32)))
+  (drop (i64.load16_u align=1 (i32.const 40)))
+  (drop (i64.load32_u align=1 (i32.const 44)))
+ )
+ (func $f32-load
+  (drop (f32.load align=1 (i32.const 12)))
+  (drop (f32.load align=2 (i32.const 16)))
+  (drop (f32.load align=1 offset=3 (i32.const 20)))
+ )
+ (func $f64-load
+  (drop (f64.load align=1 (i32.const 12)))
+  (drop (f64.load align=2 (i32.const 16)))
+  (drop (f64.load align=4 (i32.const 20)))
+  (drop (f64.load align=1 offset=3 (i32.const 20)))
+ )
+ (func $i64-store
+  (i64.store align=1 (i32.const 12) (i64.const 100))
+  (i64.store align=2 (i32.const 16) (i64.const 200))
+  (i64.store align=4 (i32.const 20) (i64.const 300))
+  (i64.store align=1 offset=3 (i32.const 24) (i64.const 400))
+  (i64.store16 align=1 (i32.const 20) (i64.const 600))
+  (i64.store32 align=1 (i32.const 20) (i64.const 700))
+ )
+ (func $f32-store
+  (f32.store align=1 (i32.const 12) (f32.const 100))
+  (f32.store align=2 (i32.const 16) (f32.const 200))
+  (f32.store align=1 offset=3 (i32.const 24) (f32.const 400))
+ )
+ (func $f64-store
+  (f64.store align=1 (i32.const 12) (f64.const 100))
+  (f64.store align=2 (i32.const 16) (f64.const 200))
+  (f64.store align=4 (i32.const 20) (f64.const 300))
+  (f64.store align=1 offset=3 (i32.const 24) (f64.const 400))
+ )
+)
diff --git a/binaryen/test/passes/alignment-lowering64.passes b/binaryen/test/passes/alignment-lowering64.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/alignment-lowering64.passes
@@ -0,0 +1,1 @@
+alignment-lowering_enable-memory64
diff --git a/binaryen/test/passes/alignment-lowering64.txt b/binaryen/test/passes/alignment-lowering64.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/alignment-lowering64.txt
@@ -0,0 +1,1948 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 i64 1 1)
+ (func $func_4
+  (local $0 i64)
+  (local $1 i64)
+  (local $2 i64)
+  (local $3 i64)
+  (local $4 i64)
+  (local $5 i32)
+  (local $6 i64)
+  (local $7 i32)
+  (local $8 i64)
+  (local $9 i32)
+  (local $10 i64)
+  (local $11 i32)
+  (drop
+   (i32.load
+    (i64.const 4)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $0
+     (i64.const 4)
+    )
+    (i32.or
+     (i32.or
+      (i32.load8_u
+       (local.get $0)
+      )
+      (i32.shl
+       (i32.load8_u offset=1
+        (local.get $0)
+       )
+       (i32.const 8)
+      )
+     )
+     (i32.or
+      (i32.shl
+       (i32.load8_u offset=2
+        (local.get $0)
+       )
+       (i32.const 16)
+      )
+      (i32.shl
+       (i32.load8_u offset=3
+        (local.get $0)
+       )
+       (i32.const 24)
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $1
+     (i64.const 4)
+    )
+    (i32.or
+     (i32.load16_u
+      (local.get $1)
+     )
+     (i32.shl
+      (i32.load16_u offset=2
+       (local.get $1)
+      )
+      (i32.const 16)
+     )
+    )
+   )
+  )
+  (drop
+   (i32.load
+    (i64.const 4)
+   )
+  )
+  (drop
+   (i32.load offset=100
+    (i64.const 4)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $2
+     (i64.const 4)
+    )
+    (i32.or
+     (i32.or
+      (i32.load8_u offset=100
+       (local.get $2)
+      )
+      (i32.shl
+       (i32.load8_u offset=101
+        (local.get $2)
+       )
+       (i32.const 8)
+      )
+     )
+     (i32.or
+      (i32.shl
+       (i32.load8_u offset=102
+        (local.get $2)
+       )
+       (i32.const 16)
+      )
+      (i32.shl
+       (i32.load8_u offset=103
+        (local.get $2)
+       )
+       (i32.const 24)
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $3
+     (i64.const 4)
+    )
+    (i32.or
+     (i32.load16_u offset=100
+      (local.get $3)
+     )
+     (i32.shl
+      (i32.load16_u offset=102
+       (local.get $3)
+      )
+      (i32.const 16)
+     )
+    )
+   )
+  )
+  (drop
+   (i32.load offset=100
+    (i64.const 4)
+   )
+  )
+  (drop
+   (unreachable)
+  )
+  (i32.store
+   (i64.const 4)
+   (i32.const 8)
+  )
+  (block
+   (local.set $4
+    (i64.const 4)
+   )
+   (local.set $5
+    (i32.const 8)
+   )
+   (i32.store8
+    (local.get $4)
+    (local.get $5)
+   )
+   (i32.store8 offset=1
+    (local.get $4)
+    (i32.shr_u
+     (local.get $5)
+     (i32.const 8)
+    )
+   )
+   (i32.store8 offset=2
+    (local.get $4)
+    (i32.shr_u
+     (local.get $5)
+     (i32.const 16)
+    )
+   )
+   (i32.store8 offset=3
+    (local.get $4)
+    (i32.shr_u
+     (local.get $5)
+     (i32.const 24)
+    )
+   )
+  )
+  (block
+   (local.set $6
+    (i64.const 4)
+   )
+   (local.set $7
+    (i32.const 8)
+   )
+   (i32.store16
+    (local.get $6)
+    (local.get $7)
+   )
+   (i32.store16 offset=2
+    (local.get $6)
+    (i32.shr_u
+     (local.get $7)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store
+   (i64.const 4)
+   (i32.const 8)
+  )
+  (i32.store offset=100
+   (i64.const 4)
+   (i32.const 8)
+  )
+  (block
+   (local.set $8
+    (i64.const 4)
+   )
+   (local.set $9
+    (i32.const 8)
+   )
+   (i32.store8 offset=100
+    (local.get $8)
+    (local.get $9)
+   )
+   (i32.store8 offset=101
+    (local.get $8)
+    (i32.shr_u
+     (local.get $9)
+     (i32.const 8)
+    )
+   )
+   (i32.store8 offset=102
+    (local.get $8)
+    (i32.shr_u
+     (local.get $9)
+     (i32.const 16)
+    )
+   )
+   (i32.store8 offset=103
+    (local.get $8)
+    (i32.shr_u
+     (local.get $9)
+     (i32.const 24)
+    )
+   )
+  )
+  (block
+   (local.set $10
+    (i64.const 4)
+   )
+   (local.set $11
+    (i32.const 8)
+   )
+   (i32.store16 offset=100
+    (local.get $10)
+    (local.get $11)
+   )
+   (i32.store16 offset=102
+    (local.get $10)
+    (i32.shr_u
+     (local.get $11)
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.store offset=100
+   (i64.const 4)
+   (i32.const 8)
+  )
+  (block
+   (drop
+    (unreachable)
+   )
+   (drop
+    (i32.const 8)
+   )
+  )
+  (block
+   (drop
+    (i64.const 4)
+   )
+   (drop
+    (unreachable)
+   )
+  )
+ )
+ (func $func_2
+  (local $0 i64)
+  (local $1 i64)
+  (local $2 i64)
+  (local $3 i32)
+  (local $4 i64)
+  (local $5 i32)
+  (drop
+   (i32.load16_u
+    (i64.const 4)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $0
+     (i64.const 4)
+    )
+    (i32.or
+     (i32.load8_u
+      (local.get $0)
+     )
+     (i32.shl
+      (i32.load8_u offset=1
+       (local.get $0)
+      )
+      (i32.const 8)
+     )
+    )
+   )
+  )
+  (drop
+   (i32.load16_u
+    (i64.const 4)
+   )
+  )
+  (drop
+   (i32.load16_u offset=100
+    (i64.const 4)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $1
+     (i64.const 4)
+    )
+    (i32.or
+     (i32.load8_u offset=100
+      (local.get $1)
+     )
+     (i32.shl
+      (i32.load8_u offset=101
+       (local.get $1)
+      )
+      (i32.const 8)
+     )
+    )
+   )
+  )
+  (drop
+   (i32.load16_u offset=100
+    (i64.const 4)
+   )
+  )
+  (drop
+   (unreachable)
+  )
+  (i32.store16
+   (i64.const 4)
+   (i32.const 8)
+  )
+  (block
+   (local.set $2
+    (i64.const 4)
+   )
+   (local.set $3
+    (i32.const 8)
+   )
+   (i32.store8
+    (local.get $2)
+    (local.get $3)
+   )
+   (i32.store8 offset=1
+    (local.get $2)
+    (i32.shr_u
+     (local.get $3)
+     (i32.const 8)
+    )
+   )
+  )
+  (i32.store16
+   (i64.const 4)
+   (i32.const 8)
+  )
+  (i32.store16 offset=100
+   (i64.const 4)
+   (i32.const 8)
+  )
+  (block
+   (local.set $4
+    (i64.const 4)
+   )
+   (local.set $5
+    (i32.const 8)
+   )
+   (i32.store8 offset=100
+    (local.get $4)
+    (local.get $5)
+   )
+   (i32.store8 offset=101
+    (local.get $4)
+    (i32.shr_u
+     (local.get $5)
+     (i32.const 8)
+    )
+   )
+  )
+  (i32.store16 offset=100
+   (i64.const 4)
+   (i32.const 8)
+  )
+  (block
+   (drop
+    (unreachable)
+   )
+   (drop
+    (i32.const 8)
+   )
+  )
+  (block
+   (drop
+    (i64.const 4)
+   )
+   (drop
+    (unreachable)
+   )
+  )
+ )
+ (func $func_1
+  (drop
+   (i32.load8_u
+    (i64.const 4)
+   )
+  )
+  (drop
+   (i32.load8_u
+    (i64.const 4)
+   )
+  )
+  (drop
+   (i32.load8_u offset=100
+    (i64.const 4)
+   )
+  )
+  (drop
+   (i32.load8_u offset=100
+    (i64.const 4)
+   )
+  )
+  (drop
+   (unreachable)
+  )
+  (i32.store8
+   (i64.const 4)
+   (i32.const 8)
+  )
+  (i32.store8
+   (i64.const 4)
+   (i32.const 8)
+  )
+  (i32.store8 offset=100
+   (i64.const 4)
+   (i32.const 8)
+  )
+  (i32.store8 offset=100
+   (i64.const 4)
+   (i32.const 8)
+  )
+  (block
+   (drop
+    (unreachable)
+   )
+   (drop
+    (i32.const 8)
+   )
+  )
+  (block
+   (drop
+    (i64.const 4)
+   )
+   (drop
+    (unreachable)
+   )
+  )
+ )
+ (func $func_signed
+  (local $0 i64)
+  (local $1 i64)
+  (drop
+   (i32.load16_s
+    (i64.const 4)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $0
+     (i64.const 4)
+    )
+    (i32.shr_s
+     (i32.shl
+      (i32.or
+       (i32.load8_u
+        (local.get $0)
+       )
+       (i32.shl
+        (i32.load8_u offset=1
+         (local.get $0)
+        )
+        (i32.const 8)
+       )
+      )
+      (i32.const 16)
+     )
+     (i32.const 16)
+    )
+   )
+  )
+  (drop
+   (i32.load16_s
+    (i64.const 4)
+   )
+  )
+  (drop
+   (i32.load16_s offset=100
+    (i64.const 4)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $1
+     (i64.const 4)
+    )
+    (i32.shr_s
+     (i32.shl
+      (i32.or
+       (i32.load8_u offset=100
+        (local.get $1)
+       )
+       (i32.shl
+        (i32.load8_u offset=101
+         (local.get $1)
+        )
+        (i32.const 8)
+       )
+      )
+      (i32.const 16)
+     )
+     (i32.const 16)
+    )
+   )
+  )
+  (drop
+   (i32.load16_s offset=100
+    (i64.const 4)
+   )
+  )
+  (drop
+   (unreachable)
+  )
+ )
+ (func $i64-load
+  (local $0 i64)
+  (local $1 i64)
+  (local $2 i64)
+  (local $3 i64)
+  (local $4 i64)
+  (local $5 i64)
+  (local $6 i64)
+  (local $7 i64)
+  (local $8 i64)
+  (local $9 i64)
+  (local $10 i64)
+  (local $11 i64)
+  (local $12 i64)
+  (local $13 i64)
+  (drop
+   (block (result i64)
+    (local.set $0
+     (i64.const 12)
+    )
+    (i64.or
+     (i64.extend_i32_u
+      (block (result i32)
+       (local.set $1
+        (local.get $0)
+       )
+       (i32.or
+        (i32.or
+         (i32.load8_u
+          (local.get $1)
+         )
+         (i32.shl
+          (i32.load8_u offset=1
+           (local.get $1)
+          )
+          (i32.const 8)
+         )
+        )
+        (i32.or
+         (i32.shl
+          (i32.load8_u offset=2
+           (local.get $1)
+          )
+          (i32.const 16)
+         )
+         (i32.shl
+          (i32.load8_u offset=3
+           (local.get $1)
+          )
+          (i32.const 24)
+         )
+        )
+       )
+      )
+     )
+     (i64.shl
+      (i64.extend_i32_u
+       (block (result i32)
+        (local.set $2
+         (local.get $0)
+        )
+        (i32.or
+         (i32.or
+          (i32.load8_u offset=4
+           (local.get $2)
+          )
+          (i32.shl
+           (i32.load8_u offset=5
+            (local.get $2)
+           )
+           (i32.const 8)
+          )
+         )
+         (i32.or
+          (i32.shl
+           (i32.load8_u offset=6
+            (local.get $2)
+           )
+           (i32.const 16)
+          )
+          (i32.shl
+           (i32.load8_u offset=7
+            (local.get $2)
+           )
+           (i32.const 24)
+          )
+         )
+        )
+       )
+      )
+      (i64.const 32)
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i64)
+    (local.set $3
+     (i64.const 16)
+    )
+    (i64.or
+     (i64.extend_i32_u
+      (block (result i32)
+       (local.set $4
+        (local.get $3)
+       )
+       (i32.or
+        (i32.load16_u
+         (local.get $4)
+        )
+        (i32.shl
+         (i32.load16_u offset=2
+          (local.get $4)
+         )
+         (i32.const 16)
+        )
+       )
+      )
+     )
+     (i64.shl
+      (i64.extend_i32_u
+       (block (result i32)
+        (local.set $5
+         (local.get $3)
+        )
+        (i32.or
+         (i32.load16_u offset=4
+          (local.get $5)
+         )
+         (i32.shl
+          (i32.load16_u offset=6
+           (local.get $5)
+          )
+          (i32.const 16)
+         )
+        )
+       )
+      )
+      (i64.const 32)
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i64)
+    (local.set $6
+     (i64.const 20)
+    )
+    (i64.or
+     (i64.extend_i32_u
+      (i32.load
+       (local.get $6)
+      )
+     )
+     (i64.shl
+      (i64.extend_i32_u
+       (i32.load offset=4
+        (local.get $6)
+       )
+      )
+      (i64.const 32)
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i64)
+    (local.set $7
+     (i64.const 20)
+    )
+    (i64.or
+     (i64.extend_i32_u
+      (block (result i32)
+       (local.set $8
+        (local.get $7)
+       )
+       (i32.or
+        (i32.or
+         (i32.load8_u offset=3
+          (local.get $8)
+         )
+         (i32.shl
+          (i32.load8_u offset=4
+           (local.get $8)
+          )
+          (i32.const 8)
+         )
+        )
+        (i32.or
+         (i32.shl
+          (i32.load8_u offset=5
+           (local.get $8)
+          )
+          (i32.const 16)
+         )
+         (i32.shl
+          (i32.load8_u offset=6
+           (local.get $8)
+          )
+          (i32.const 24)
+         )
+        )
+       )
+      )
+     )
+     (i64.shl
+      (i64.extend_i32_u
+       (block (result i32)
+        (local.set $9
+         (local.get $7)
+        )
+        (i32.or
+         (i32.or
+          (i32.load8_u offset=7
+           (local.get $9)
+          )
+          (i32.shl
+           (i32.load8_u offset=8
+            (local.get $9)
+           )
+           (i32.const 8)
+          )
+         )
+         (i32.or
+          (i32.shl
+           (i32.load8_u offset=9
+            (local.get $9)
+           )
+           (i32.const 16)
+          )
+          (i32.shl
+           (i32.load8_u offset=10
+            (local.get $9)
+           )
+           (i32.const 24)
+          )
+         )
+        )
+       )
+      )
+      (i64.const 32)
+     )
+    )
+   )
+  )
+  (drop
+   (i64.extend_i32_s
+    (block (result i32)
+     (local.set $10
+      (i64.const 28)
+     )
+     (i32.shr_s
+      (i32.shl
+       (i32.or
+        (i32.load8_u
+         (local.get $10)
+        )
+        (i32.shl
+         (i32.load8_u offset=1
+          (local.get $10)
+         )
+         (i32.const 8)
+        )
+       )
+       (i32.const 16)
+      )
+      (i32.const 16)
+     )
+    )
+   )
+  )
+  (drop
+   (i64.extend_i32_s
+    (block (result i32)
+     (local.set $11
+      (i64.const 32)
+     )
+     (i32.or
+      (i32.or
+       (i32.load8_u
+        (local.get $11)
+       )
+       (i32.shl
+        (i32.load8_u offset=1
+         (local.get $11)
+        )
+        (i32.const 8)
+       )
+      )
+      (i32.or
+       (i32.shl
+        (i32.load8_u offset=2
+         (local.get $11)
+        )
+        (i32.const 16)
+       )
+       (i32.shl
+        (i32.load8_u offset=3
+         (local.get $11)
+        )
+        (i32.const 24)
+       )
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (block (result i32)
+     (local.set $12
+      (i64.const 40)
+     )
+     (i32.or
+      (i32.load8_u
+       (local.get $12)
+      )
+      (i32.shl
+       (i32.load8_u offset=1
+        (local.get $12)
+       )
+       (i32.const 8)
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (block (result i32)
+     (local.set $13
+      (i64.const 44)
+     )
+     (i32.or
+      (i32.or
+       (i32.load8_u
+        (local.get $13)
+       )
+       (i32.shl
+        (i32.load8_u offset=1
+         (local.get $13)
+        )
+        (i32.const 8)
+       )
+      )
+      (i32.or
+       (i32.shl
+        (i32.load8_u offset=2
+         (local.get $13)
+        )
+        (i32.const 16)
+       )
+       (i32.shl
+        (i32.load8_u offset=3
+         (local.get $13)
+        )
+        (i32.const 24)
+       )
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $f32-load
+  (local $0 i64)
+  (local $1 i64)
+  (local $2 i64)
+  (drop
+   (f32.reinterpret_i32
+    (block (result i32)
+     (local.set $0
+      (i64.const 12)
+     )
+     (i32.or
+      (i32.or
+       (i32.load8_u
+        (local.get $0)
+       )
+       (i32.shl
+        (i32.load8_u offset=1
+         (local.get $0)
+        )
+        (i32.const 8)
+       )
+      )
+      (i32.or
+       (i32.shl
+        (i32.load8_u offset=2
+         (local.get $0)
+        )
+        (i32.const 16)
+       )
+       (i32.shl
+        (i32.load8_u offset=3
+         (local.get $0)
+        )
+        (i32.const 24)
+       )
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (f32.reinterpret_i32
+    (block (result i32)
+     (local.set $1
+      (i64.const 16)
+     )
+     (i32.or
+      (i32.load16_u
+       (local.get $1)
+      )
+      (i32.shl
+       (i32.load16_u offset=2
+        (local.get $1)
+       )
+       (i32.const 16)
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (f32.reinterpret_i32
+    (block (result i32)
+     (local.set $2
+      (i64.const 20)
+     )
+     (i32.or
+      (i32.or
+       (i32.load8_u offset=3
+        (local.get $2)
+       )
+       (i32.shl
+        (i32.load8_u offset=4
+         (local.get $2)
+        )
+        (i32.const 8)
+       )
+      )
+      (i32.or
+       (i32.shl
+        (i32.load8_u offset=5
+         (local.get $2)
+        )
+        (i32.const 16)
+       )
+       (i32.shl
+        (i32.load8_u offset=6
+         (local.get $2)
+        )
+        (i32.const 24)
+       )
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $f64-load
+  (local $0 i64)
+  (local $1 i64)
+  (local $2 i64)
+  (local $3 i64)
+  (local $4 i64)
+  (local $5 i64)
+  (local $6 i64)
+  (local $7 i64)
+  (local $8 i64)
+  (local $9 i64)
+  (drop
+   (f64.reinterpret_i64
+    (block (result i64)
+     (local.set $0
+      (i64.const 12)
+     )
+     (i64.or
+      (i64.extend_i32_u
+       (block (result i32)
+        (local.set $1
+         (local.get $0)
+        )
+        (i32.or
+         (i32.or
+          (i32.load8_u
+           (local.get $1)
+          )
+          (i32.shl
+           (i32.load8_u offset=1
+            (local.get $1)
+           )
+           (i32.const 8)
+          )
+         )
+         (i32.or
+          (i32.shl
+           (i32.load8_u offset=2
+            (local.get $1)
+           )
+           (i32.const 16)
+          )
+          (i32.shl
+           (i32.load8_u offset=3
+            (local.get $1)
+           )
+           (i32.const 24)
+          )
+         )
+        )
+       )
+      )
+      (i64.shl
+       (i64.extend_i32_u
+        (block (result i32)
+         (local.set $2
+          (local.get $0)
+         )
+         (i32.or
+          (i32.or
+           (i32.load8_u offset=4
+            (local.get $2)
+           )
+           (i32.shl
+            (i32.load8_u offset=5
+             (local.get $2)
+            )
+            (i32.const 8)
+           )
+          )
+          (i32.or
+           (i32.shl
+            (i32.load8_u offset=6
+             (local.get $2)
+            )
+            (i32.const 16)
+           )
+           (i32.shl
+            (i32.load8_u offset=7
+             (local.get $2)
+            )
+            (i32.const 24)
+           )
+          )
+         )
+        )
+       )
+       (i64.const 32)
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (f64.reinterpret_i64
+    (block (result i64)
+     (local.set $3
+      (i64.const 16)
+     )
+     (i64.or
+      (i64.extend_i32_u
+       (block (result i32)
+        (local.set $4
+         (local.get $3)
+        )
+        (i32.or
+         (i32.load16_u
+          (local.get $4)
+         )
+         (i32.shl
+          (i32.load16_u offset=2
+           (local.get $4)
+          )
+          (i32.const 16)
+         )
+        )
+       )
+      )
+      (i64.shl
+       (i64.extend_i32_u
+        (block (result i32)
+         (local.set $5
+          (local.get $3)
+         )
+         (i32.or
+          (i32.load16_u offset=4
+           (local.get $5)
+          )
+          (i32.shl
+           (i32.load16_u offset=6
+            (local.get $5)
+           )
+           (i32.const 16)
+          )
+         )
+        )
+       )
+       (i64.const 32)
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (f64.reinterpret_i64
+    (block (result i64)
+     (local.set $6
+      (i64.const 20)
+     )
+     (i64.or
+      (i64.extend_i32_u
+       (i32.load
+        (local.get $6)
+       )
+      )
+      (i64.shl
+       (i64.extend_i32_u
+        (i32.load offset=4
+         (local.get $6)
+        )
+       )
+       (i64.const 32)
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (f64.reinterpret_i64
+    (block (result i64)
+     (local.set $7
+      (i64.const 20)
+     )
+     (i64.or
+      (i64.extend_i32_u
+       (block (result i32)
+        (local.set $8
+         (local.get $7)
+        )
+        (i32.or
+         (i32.or
+          (i32.load8_u offset=3
+           (local.get $8)
+          )
+          (i32.shl
+           (i32.load8_u offset=4
+            (local.get $8)
+           )
+           (i32.const 8)
+          )
+         )
+         (i32.or
+          (i32.shl
+           (i32.load8_u offset=5
+            (local.get $8)
+           )
+           (i32.const 16)
+          )
+          (i32.shl
+           (i32.load8_u offset=6
+            (local.get $8)
+           )
+           (i32.const 24)
+          )
+         )
+        )
+       )
+      )
+      (i64.shl
+       (i64.extend_i32_u
+        (block (result i32)
+         (local.set $9
+          (local.get $7)
+         )
+         (i32.or
+          (i32.or
+           (i32.load8_u offset=7
+            (local.get $9)
+           )
+           (i32.shl
+            (i32.load8_u offset=8
+             (local.get $9)
+            )
+            (i32.const 8)
+           )
+          )
+          (i32.or
+           (i32.shl
+            (i32.load8_u offset=9
+             (local.get $9)
+            )
+            (i32.const 16)
+           )
+           (i32.shl
+            (i32.load8_u offset=10
+             (local.get $9)
+            )
+            (i32.const 24)
+           )
+          )
+         )
+        )
+       )
+       (i64.const 32)
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $i64-store
+  (local $0 i64)
+  (local $1 i64)
+  (local $2 i64)
+  (local $3 i32)
+  (local $4 i64)
+  (local $5 i32)
+  (local $6 i64)
+  (local $7 i64)
+  (local $8 i64)
+  (local $9 i32)
+  (local $10 i64)
+  (local $11 i32)
+  (local $12 i64)
+  (local $13 i64)
+  (local $14 i64)
+  (local $15 i64)
+  (local $16 i64)
+  (local $17 i32)
+  (local $18 i64)
+  (local $19 i32)
+  (local $20 i64)
+  (local $21 i32)
+  (local $22 i64)
+  (local $23 i32)
+  (block
+   (local.set $0
+    (i64.const 12)
+   )
+   (local.set $1
+    (i64.const 100)
+   )
+   (block
+    (local.set $2
+     (local.get $0)
+    )
+    (local.set $3
+     (i32.wrap_i64
+      (local.get $1)
+     )
+    )
+    (i32.store8
+     (local.get $2)
+     (local.get $3)
+    )
+    (i32.store8 offset=1
+     (local.get $2)
+     (i32.shr_u
+      (local.get $3)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=2
+     (local.get $2)
+     (i32.shr_u
+      (local.get $3)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=3
+     (local.get $2)
+     (i32.shr_u
+      (local.get $3)
+      (i32.const 24)
+     )
+    )
+   )
+   (block
+    (local.set $4
+     (local.get $0)
+    )
+    (local.set $5
+     (i32.wrap_i64
+      (i64.shr_u
+       (local.get $1)
+       (i64.const 32)
+      )
+     )
+    )
+    (i32.store8 offset=4
+     (local.get $4)
+     (local.get $5)
+    )
+    (i32.store8 offset=5
+     (local.get $4)
+     (i32.shr_u
+      (local.get $5)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=6
+     (local.get $4)
+     (i32.shr_u
+      (local.get $5)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=7
+     (local.get $4)
+     (i32.shr_u
+      (local.get $5)
+      (i32.const 24)
+     )
+    )
+   )
+  )
+  (block
+   (local.set $6
+    (i64.const 16)
+   )
+   (local.set $7
+    (i64.const 200)
+   )
+   (block
+    (local.set $8
+     (local.get $6)
+    )
+    (local.set $9
+     (i32.wrap_i64
+      (local.get $7)
+     )
+    )
+    (i32.store16
+     (local.get $8)
+     (local.get $9)
+    )
+    (i32.store16 offset=2
+     (local.get $8)
+     (i32.shr_u
+      (local.get $9)
+      (i32.const 16)
+     )
+    )
+   )
+   (block
+    (local.set $10
+     (local.get $6)
+    )
+    (local.set $11
+     (i32.wrap_i64
+      (i64.shr_u
+       (local.get $7)
+       (i64.const 32)
+      )
+     )
+    )
+    (i32.store16 offset=4
+     (local.get $10)
+     (local.get $11)
+    )
+    (i32.store16 offset=6
+     (local.get $10)
+     (i32.shr_u
+      (local.get $11)
+      (i32.const 16)
+     )
+    )
+   )
+  )
+  (block
+   (local.set $12
+    (i64.const 20)
+   )
+   (local.set $13
+    (i64.const 300)
+   )
+   (i32.store
+    (local.get $12)
+    (i32.wrap_i64
+     (local.get $13)
+    )
+   )
+   (i32.store offset=4
+    (local.get $12)
+    (i32.wrap_i64
+     (i64.shr_u
+      (local.get $13)
+      (i64.const 32)
+     )
+    )
+   )
+  )
+  (block
+   (local.set $14
+    (i64.const 24)
+   )
+   (local.set $15
+    (i64.const 400)
+   )
+   (block
+    (local.set $16
+     (local.get $14)
+    )
+    (local.set $17
+     (i32.wrap_i64
+      (local.get $15)
+     )
+    )
+    (i32.store8 offset=3
+     (local.get $16)
+     (local.get $17)
+    )
+    (i32.store8 offset=4
+     (local.get $16)
+     (i32.shr_u
+      (local.get $17)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=5
+     (local.get $16)
+     (i32.shr_u
+      (local.get $17)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=6
+     (local.get $16)
+     (i32.shr_u
+      (local.get $17)
+      (i32.const 24)
+     )
+    )
+   )
+   (block
+    (local.set $18
+     (local.get $14)
+    )
+    (local.set $19
+     (i32.wrap_i64
+      (i64.shr_u
+       (local.get $15)
+       (i64.const 32)
+      )
+     )
+    )
+    (i32.store8 offset=7
+     (local.get $18)
+     (local.get $19)
+    )
+    (i32.store8 offset=8
+     (local.get $18)
+     (i32.shr_u
+      (local.get $19)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=9
+     (local.get $18)
+     (i32.shr_u
+      (local.get $19)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=10
+     (local.get $18)
+     (i32.shr_u
+      (local.get $19)
+      (i32.const 24)
+     )
+    )
+   )
+  )
+  (block
+   (local.set $20
+    (i64.const 20)
+   )
+   (local.set $21
+    (i32.wrap_i64
+     (i64.const 600)
+    )
+   )
+   (i32.store8
+    (local.get $20)
+    (local.get $21)
+   )
+   (i32.store8 offset=1
+    (local.get $20)
+    (i32.shr_u
+     (local.get $21)
+     (i32.const 8)
+    )
+   )
+  )
+  (block
+   (local.set $22
+    (i64.const 20)
+   )
+   (local.set $23
+    (i32.wrap_i64
+     (i64.const 700)
+    )
+   )
+   (i32.store8
+    (local.get $22)
+    (local.get $23)
+   )
+   (i32.store8 offset=1
+    (local.get $22)
+    (i32.shr_u
+     (local.get $23)
+     (i32.const 8)
+    )
+   )
+   (i32.store8 offset=2
+    (local.get $22)
+    (i32.shr_u
+     (local.get $23)
+     (i32.const 16)
+    )
+   )
+   (i32.store8 offset=3
+    (local.get $22)
+    (i32.shr_u
+     (local.get $23)
+     (i32.const 24)
+    )
+   )
+  )
+ )
+ (func $f32-store
+  (local $0 i64)
+  (local $1 i32)
+  (local $2 i64)
+  (local $3 i32)
+  (local $4 i64)
+  (local $5 i32)
+  (block
+   (local.set $0
+    (i64.const 12)
+   )
+   (local.set $1
+    (i32.reinterpret_f32
+     (f32.const 100)
+    )
+   )
+   (i32.store8
+    (local.get $0)
+    (local.get $1)
+   )
+   (i32.store8 offset=1
+    (local.get $0)
+    (i32.shr_u
+     (local.get $1)
+     (i32.const 8)
+    )
+   )
+   (i32.store8 offset=2
+    (local.get $0)
+    (i32.shr_u
+     (local.get $1)
+     (i32.const 16)
+    )
+   )
+   (i32.store8 offset=3
+    (local.get $0)
+    (i32.shr_u
+     (local.get $1)
+     (i32.const 24)
+    )
+   )
+  )
+  (block
+   (local.set $2
+    (i64.const 16)
+   )
+   (local.set $3
+    (i32.reinterpret_f32
+     (f32.const 200)
+    )
+   )
+   (i32.store16
+    (local.get $2)
+    (local.get $3)
+   )
+   (i32.store16 offset=2
+    (local.get $2)
+    (i32.shr_u
+     (local.get $3)
+     (i32.const 16)
+    )
+   )
+  )
+  (block
+   (local.set $4
+    (i64.const 24)
+   )
+   (local.set $5
+    (i32.reinterpret_f32
+     (f32.const 400)
+    )
+   )
+   (i32.store8 offset=3
+    (local.get $4)
+    (local.get $5)
+   )
+   (i32.store8 offset=4
+    (local.get $4)
+    (i32.shr_u
+     (local.get $5)
+     (i32.const 8)
+    )
+   )
+   (i32.store8 offset=5
+    (local.get $4)
+    (i32.shr_u
+     (local.get $5)
+     (i32.const 16)
+    )
+   )
+   (i32.store8 offset=6
+    (local.get $4)
+    (i32.shr_u
+     (local.get $5)
+     (i32.const 24)
+    )
+   )
+  )
+ )
+ (func $f64-store
+  (local $0 i64)
+  (local $1 i64)
+  (local $2 i64)
+  (local $3 i32)
+  (local $4 i64)
+  (local $5 i32)
+  (local $6 i64)
+  (local $7 i64)
+  (local $8 i64)
+  (local $9 i32)
+  (local $10 i64)
+  (local $11 i32)
+  (local $12 i64)
+  (local $13 i64)
+  (local $14 i64)
+  (local $15 i64)
+  (local $16 i64)
+  (local $17 i32)
+  (local $18 i64)
+  (local $19 i32)
+  (block
+   (local.set $0
+    (i64.const 12)
+   )
+   (local.set $1
+    (i64.reinterpret_f64
+     (f64.const 100)
+    )
+   )
+   (block
+    (local.set $2
+     (local.get $0)
+    )
+    (local.set $3
+     (i32.wrap_i64
+      (local.get $1)
+     )
+    )
+    (i32.store8
+     (local.get $2)
+     (local.get $3)
+    )
+    (i32.store8 offset=1
+     (local.get $2)
+     (i32.shr_u
+      (local.get $3)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=2
+     (local.get $2)
+     (i32.shr_u
+      (local.get $3)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=3
+     (local.get $2)
+     (i32.shr_u
+      (local.get $3)
+      (i32.const 24)
+     )
+    )
+   )
+   (block
+    (local.set $4
+     (local.get $0)
+    )
+    (local.set $5
+     (i32.wrap_i64
+      (i64.shr_u
+       (local.get $1)
+       (i64.const 32)
+      )
+     )
+    )
+    (i32.store8 offset=4
+     (local.get $4)
+     (local.get $5)
+    )
+    (i32.store8 offset=5
+     (local.get $4)
+     (i32.shr_u
+      (local.get $5)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=6
+     (local.get $4)
+     (i32.shr_u
+      (local.get $5)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=7
+     (local.get $4)
+     (i32.shr_u
+      (local.get $5)
+      (i32.const 24)
+     )
+    )
+   )
+  )
+  (block
+   (local.set $6
+    (i64.const 16)
+   )
+   (local.set $7
+    (i64.reinterpret_f64
+     (f64.const 200)
+    )
+   )
+   (block
+    (local.set $8
+     (local.get $6)
+    )
+    (local.set $9
+     (i32.wrap_i64
+      (local.get $7)
+     )
+    )
+    (i32.store16
+     (local.get $8)
+     (local.get $9)
+    )
+    (i32.store16 offset=2
+     (local.get $8)
+     (i32.shr_u
+      (local.get $9)
+      (i32.const 16)
+     )
+    )
+   )
+   (block
+    (local.set $10
+     (local.get $6)
+    )
+    (local.set $11
+     (i32.wrap_i64
+      (i64.shr_u
+       (local.get $7)
+       (i64.const 32)
+      )
+     )
+    )
+    (i32.store16 offset=4
+     (local.get $10)
+     (local.get $11)
+    )
+    (i32.store16 offset=6
+     (local.get $10)
+     (i32.shr_u
+      (local.get $11)
+      (i32.const 16)
+     )
+    )
+   )
+  )
+  (block
+   (local.set $12
+    (i64.const 20)
+   )
+   (local.set $13
+    (i64.reinterpret_f64
+     (f64.const 300)
+    )
+   )
+   (i32.store
+    (local.get $12)
+    (i32.wrap_i64
+     (local.get $13)
+    )
+   )
+   (i32.store offset=4
+    (local.get $12)
+    (i32.wrap_i64
+     (i64.shr_u
+      (local.get $13)
+      (i64.const 32)
+     )
+    )
+   )
+  )
+  (block
+   (local.set $14
+    (i64.const 24)
+   )
+   (local.set $15
+    (i64.reinterpret_f64
+     (f64.const 400)
+    )
+   )
+   (block
+    (local.set $16
+     (local.get $14)
+    )
+    (local.set $17
+     (i32.wrap_i64
+      (local.get $15)
+     )
+    )
+    (i32.store8 offset=3
+     (local.get $16)
+     (local.get $17)
+    )
+    (i32.store8 offset=4
+     (local.get $16)
+     (i32.shr_u
+      (local.get $17)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=5
+     (local.get $16)
+     (i32.shr_u
+      (local.get $17)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=6
+     (local.get $16)
+     (i32.shr_u
+      (local.get $17)
+      (i32.const 24)
+     )
+    )
+   )
+   (block
+    (local.set $18
+     (local.get $14)
+    )
+    (local.set $19
+     (i32.wrap_i64
+      (i64.shr_u
+       (local.get $15)
+       (i64.const 32)
+      )
+     )
+    )
+    (i32.store8 offset=7
+     (local.get $18)
+     (local.get $19)
+    )
+    (i32.store8 offset=8
+     (local.get $18)
+     (i32.shr_u
+      (local.get $19)
+      (i32.const 8)
+     )
+    )
+    (i32.store8 offset=9
+     (local.get $18)
+     (i32.shr_u
+      (local.get $19)
+      (i32.const 16)
+     )
+    )
+    (i32.store8 offset=10
+     (local.get $18)
+     (i32.shr_u
+      (local.get $19)
+      (i32.const 24)
+     )
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/alignment-lowering64.wast b/binaryen/test/passes/alignment-lowering64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/alignment-lowering64.wast
@@ -0,0 +1,103 @@
+(module
+ (memory $0 i64 1 1)
+ (func $func_4
+  (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))
+ )
+ (func $func_2
+  (drop (i32.load16_u (i64.const 4)))
+  (drop (i32.load16_u align=1 (i64.const 4)))
+  (drop (i32.load16_u align=2 (i64.const 4)))
+  (drop (i32.load16_u offset=100 (i64.const 4)))
+  (drop (i32.load16_u offset=100 align=1 (i64.const 4)))
+  (drop (i32.load16_u offset=100 align=2 (i64.const 4)))
+  (drop (i32.load16_u offset=100 align=1 (unreachable)))
+  (i32.store16 (i64.const 4) (i32.const 8))
+  (i32.store16 align=1 (i64.const 4) (i32.const 8))
+  (i32.store16 align=2 (i64.const 4) (i32.const 8))
+  (i32.store16 offset=100 (i64.const 4) (i32.const 8))
+  (i32.store16 offset=100 align=1 (i64.const 4) (i32.const 8))
+  (i32.store16 offset=100 align=2 (i64.const 4) (i32.const 8))
+  (i32.store16 offset=100 align=1 (unreachable) (i32.const 8))
+  (i32.store16 offset=100 align=1 (i64.const 4) (unreachable))
+ )
+ (func $func_1
+  (drop (i32.load8_u (i64.const 4)))
+  (drop (i32.load8_u align=1 (i64.const 4)))
+  (drop (i32.load8_u offset=100 (i64.const 4)))
+  (drop (i32.load8_u offset=100 align=1 (i64.const 4)))
+  (drop (i32.load8_u offset=100 align=1 (unreachable)))
+  (i32.store8 (i64.const 4) (i32.const 8))
+  (i32.store8 align=1 (i64.const 4) (i32.const 8))
+  (i32.store8 offset=100 (i64.const 4) (i32.const 8))
+  (i32.store8 offset=100 align=1 (i64.const 4) (i32.const 8))
+  (i32.store8 offset=100 align=1 (unreachable) (i32.const 8))
+  (i32.store8 offset=100 align=1 (i64.const 4) (unreachable))
+ )
+ (func $func_signed
+  (drop (i32.load16_s (i64.const 4)))
+  (drop (i32.load16_s align=1 (i64.const 4)))
+  (drop (i32.load16_s align=2 (i64.const 4)))
+  (drop (i32.load16_s offset=100 (i64.const 4)))
+  (drop (i32.load16_s offset=100 align=1 (i64.const 4)))
+  (drop (i32.load16_s offset=100 align=2 (i64.const 4)))
+  (drop (i32.load16_s offset=100 align=1 (unreachable)))
+ )
+ (func $i64-load
+  (drop (i64.load align=1 (i64.const 12)))
+  (drop (i64.load align=2 (i64.const 16)))
+  (drop (i64.load align=4 (i64.const 20)))
+  (drop (i64.load align=1 offset=3 (i64.const 20)))
+  (drop (i64.load16_s align=1 (i64.const 28)))
+  (drop (i64.load32_s align=1 (i64.const 32)))
+  (drop (i64.load16_u align=1 (i64.const 40)))
+  (drop (i64.load32_u align=1 (i64.const 44)))
+ )
+ (func $f32-load
+  (drop (f32.load align=1 (i64.const 12)))
+  (drop (f32.load align=2 (i64.const 16)))
+  (drop (f32.load align=1 offset=3 (i64.const 20)))
+ )
+ (func $f64-load
+  (drop (f64.load align=1 (i64.const 12)))
+  (drop (f64.load align=2 (i64.const 16)))
+  (drop (f64.load align=4 (i64.const 20)))
+  (drop (f64.load align=1 offset=3 (i64.const 20)))
+ )
+ (func $i64-store
+  (i64.store align=1 (i64.const 12) (i64.const 100))
+  (i64.store align=2 (i64.const 16) (i64.const 200))
+  (i64.store align=4 (i64.const 20) (i64.const 300))
+  (i64.store align=1 offset=3 (i64.const 24) (i64.const 400))
+  (i64.store16 align=1 (i64.const 20) (i64.const 600))
+  (i64.store32 align=1 (i64.const 20) (i64.const 700))
+ )
+ (func $f32-store
+  (f32.store align=1 (i64.const 12) (f32.const 100))
+  (f32.store align=2 (i64.const 16) (f32.const 200))
+  (f32.store align=1 offset=3 (i64.const 24) (f32.const 400))
+ )
+ (func $f64-store
+  (f64.store align=1 (i64.const 12) (f64.const 100))
+  (f64.store align=2 (i64.const 16) (f64.const 200))
+  (f64.store align=4 (i64.const 20) (f64.const 300))
+  (f64.store align=1 offset=3 (i64.const 24) (f64.const 400))
+ )
+)
diff --git a/binaryen/test/passes/asyncify.txt b/binaryen/test/passes/asyncify.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify.txt
@@ -0,0 +1,1261 @@
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "import" (func $import))
+ (import "env" "import2" (func $import2 (param i32)))
+ (memory $0 1 2)
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $liveness2 $liveness2)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $liveness1 (param $live0 i32) (param $dead0 i32)
+  (local $live1 i32)
+  (local $dead1 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -8)
+     )
+    )
+    (local.set $10
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $live0
+     (i32.load
+      (local.get $10)
+     )
+    )
+    (local.set $live1
+     (i32.load offset=4
+      (local.get $10)
+     )
+    )
+   )
+  )
+  (local.set $8
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $9
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (block
+         (local.set $4
+          (local.get $dead0)
+         )
+         (drop
+          (local.get $4)
+         )
+         (local.set $5
+          (local.get $dead1)
+         )
+         (drop
+          (local.get $5)
+         )
+        )
+       )
+       (nop)
+       (nop)
+       (nop)
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $9)
+          (i32.const 0)
+         )
+        )
+        (block
+         (call $import)
+         (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)
+        )
+        (block
+         (local.set $6
+          (local.get $live0)
+         )
+         (drop
+          (local.get $6)
+         )
+         (local.set $7
+          (local.get $live1)
+         )
+         (drop
+          (local.get $7)
+         )
+        )
+       )
+       (nop)
+       (nop)
+       (nop)
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $8)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $11
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $11)
+    (local.get $live0)
+   )
+   (i32.store offset=4
+    (local.get $11)
+    (local.get $live1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 8)
+    )
+   )
+  )
+ )
+ (func $liveness2 (param $live0 i32) (param $dead0 i32)
+  (local $live1 i32)
+  (local $dead1 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -8)
+     )
+    )
+    (local.set $10
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $live0
+     (i32.load
+      (local.get $10)
+     )
+    )
+    (local.set $live1
+     (i32.load offset=4
+      (local.get $10)
+     )
+    )
+   )
+  )
+  (local.set $8
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $9
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (block
+         (local.set $4
+          (local.get $dead0)
+         )
+         (drop
+          (local.get $4)
+         )
+         (local.set $5
+          (local.get $dead1)
+         )
+         (drop
+          (local.get $5)
+         )
+        )
+       )
+       (nop)
+       (nop)
+       (nop)
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $9)
+          (i32.const 0)
+         )
+        )
+        (block
+         (call $import)
+         (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)
+        )
+        (block
+         (local.set $6
+          (local.get $live0)
+         )
+         (drop
+          (local.get $6)
+         )
+         (local.set $7
+          (local.get $live1)
+         )
+         (drop
+          (local.get $7)
+         )
+        )
+       )
+       (nop)
+       (nop)
+       (nop)
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $8)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $11
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $11)
+    (local.get $live0)
+   )
+   (i32.store offset=4
+    (local.get $11)
+    (local.get $live1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 8)
+    )
+   )
+  )
+ )
+ (func $liveness3 (param $live0 i32) (param $dead0 i32)
+  (local $live1 i32)
+  (local $dead1 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -8)
+     )
+    )
+    (local.set $8
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $live0
+     (i32.load
+      (local.get $8)
+     )
+    )
+    (local.set $live1
+     (i32.load offset=4
+      (local.get $8)
+     )
+    )
+   )
+  )
+  (local.set $6
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $7
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $7)
+          (i32.const 0)
+         )
+        )
+        (block
+         (call $import)
+         (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)
+        )
+        (block
+         (local.set $4
+          (local.get $live0)
+         )
+         (drop
+          (local.get $4)
+         )
+        )
+       )
+       (nop)
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $7)
+          (i32.const 1)
+         )
+        )
+        (block
+         (call $import)
+         (if
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 1)
+          )
+          (br $__asyncify_unwind
+           (i32.const 1)
+          )
+         )
+        )
+       )
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (block
+         (local.set $5
+          (local.get $live1)
+         )
+         (drop
+          (local.get $5)
+         )
+        )
+       )
+       (nop)
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $6)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $9
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $9)
+    (local.get $live0)
+   )
+   (i32.store offset=4
+    (local.get $9)
+    (local.get $live1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 8)
+    )
+   )
+  )
+ )
+ (func $liveness4 (param $live0 i32) (param $dead0 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $5
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $live0
+     (i32.load
+      (local.get $5)
+     )
+    )
+   )
+  )
+  (local.set $3
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $4
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.or
+         (i32.const 0)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 2)
+         )
+        )
+        (if
+         (if (result i32)
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 0)
+          )
+          (i32.const 1)
+          (i32.eq
+           (local.get $4)
+           (i32.const 0)
+          )
+         )
+         (block
+          (call $import)
+          (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)
+        )
+        (block
+         (local.set $2
+          (local.get $live0)
+         )
+         (drop
+          (local.get $2)
+         )
+        )
+       )
+       (nop)
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $3)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $6
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $6)
+    (local.get $live0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+ )
+ (func $liveness5 (param $dead0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $3
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $4
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (block
+         (local.set $1
+          (local.get $dead0)
+         )
+         (drop
+          (local.get $1)
+         )
+        )
+       )
+       (nop)
+       (if
+        (i32.or
+         (i32.const 0)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 2)
+         )
+        )
+        (if
+         (if (result i32)
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 0)
+          )
+          (i32.const 1)
+          (i32.eq
+           (local.get $4)
+           (i32.const 0)
+          )
+         )
+         (block
+          (call $import)
+          (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)
+        )
+        (block
+         (local.set $dead0
+          (i32.const 1)
+         )
+         (local.set $2
+          (local.get $dead0)
+         )
+         (drop
+          (local.get $2)
+         )
+        )
+       )
+       (nop)
+       (nop)
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $3)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $liveness-call-kills (param $live i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $4
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $1
+     (i32.load
+      (local.get $4)
+     )
+    )
+   )
+  )
+  (local.set $2
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $3
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (local.set $1
+         (local.get $live)
+        )
+       )
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $3)
+          (i32.const 0)
+         )
+        )
+        (block
+         (call $import2
+          (local.get $1)
+         )
+         (if
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 1)
+          )
+          (br $__asyncify_unwind
+           (i32.const 0)
+          )
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $2)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $5
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $5)
+    (local.get $1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+ )
+ (func $liveness-indirect-kills (param $live0 i32) (param $live1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -8)
+     )
+    )
+    (local.set $6
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $2
+     (i32.load
+      (local.get $6)
+     )
+    )
+    (local.set $3
+     (i32.load offset=4
+      (local.get $6)
+     )
+    )
+   )
+  )
+  (local.set $4
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $5
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (block
+         (local.set $2
+          (local.get $live0)
+         )
+         (local.set $3
+          (local.get $live1)
+         )
+        )
+       )
+       (nop)
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $5)
+          (i32.const 0)
+         )
+        )
+        (block
+         (call_indirect (type $i32_=>_none)
+          (local.get $2)
+          (local.get $3)
+         )
+         (if
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 1)
+          )
+          (br $__asyncify_unwind
+           (i32.const 0)
+          )
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $4)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $7
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $7)
+    (local.get $2)
+   )
+   (i32.store offset=4
+    (local.get $7)
+    (local.get $3)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 8)
+    )
+   )
+  )
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify.wast b/binaryen/test/passes/asyncify.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify.wast
@@ -0,0 +1,53 @@
+(module
+  (type $f (func (param i32)))
+  (memory 1 2)
+  (import "env" "import" (func $import))
+  (import "env" "import2" (func $import2 (param i32)))
+  (table 1 1)
+  (func $liveness1 (param $live0 i32) (param $dead0 i32)
+    (local $live1 i32)
+    (local $dead1 i32)
+    (drop (local.get $dead0))
+    (drop (local.get $dead1))
+    (call $import)
+    (drop (local.get $live0))
+    (drop (local.get $live1))
+  )
+  (func $liveness2 (param $live0 i32) (param $dead0 i32)
+    (local $live1 i32)
+    (local $dead1 i32)
+    (drop (local.get $dead0))
+    (drop (local.get $dead1))
+    (call $import)
+    (drop (local.get $live0))
+    (drop (local.get $live1))
+  )
+  (func $liveness3 (param $live0 i32) (param $dead0 i32)
+    (local $live1 i32)
+    (local $dead1 i32)
+    (call $import)
+    (drop (local.get $live0))
+    (call $import)
+    (drop (local.get $live1))
+  )
+  (func $liveness4 (param $live0 i32) (param $dead0 i32)
+    (if (i32.const 0)
+      (call $import)
+    )
+    (drop (local.get $live0))
+  )
+  (func $liveness5 (param $dead0 i32)
+    (drop (local.get $dead0))
+    (if (i32.const 0)
+      (call $import) ;; live before and after call, but not during
+    )
+    (local.set $dead0 (i32.const 1))
+    (drop (local.get $dead0))
+  )
+  (func $liveness-call-kills (param $live i32)
+    (call $import2 (local.get $live))
+  )
+  (func $liveness-indirect-kills (param $live0 i32) (param $live1 i32)
+    (call_indirect (type $f) (local.get $live0) (local.get $live1))
+  )
+)
diff --git a/binaryen/test/passes/asyncify_enable-multivalue.txt b/binaryen/test/passes/asyncify_enable-multivalue.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_enable-multivalue.txt
@@ -0,0 +1,2584 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 1 2)
+ (global $sleeping (mut i32) (i32.const 0))
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $do_sleep
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (global.get $sleeping)
+  )
+  (local.set $1
+   (i32.eqz
+    (local.get $0)
+   )
+  )
+  (if
+   (local.get $1)
+   (block $block
+    (global.set $sleeping
+     (i32.const 1)
+    )
+    (call $asyncify_start_unwind
+     (i32.const 4)
+    )
+   )
+   (block $block0
+    (global.set $sleeping
+     (i32.const 0)
+    )
+    (call $asyncify_stop_rewind)
+   )
+  )
+ )
+ (func $work
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (call $stuff)
+       )
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $1)
+          (i32.const 0)
+         )
+        )
+        (block
+         (call $do_sleep)
+         (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)
+        )
+        (call $stuff)
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $stuff
+  (nop)
+ )
+ (func $first_event
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $work)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $second_event
+  (call $asyncify_stop_unwind)
+  (call $asyncify_start_rewind
+   (i32.const 4)
+  )
+  (call $work)
+ )
+ (func $never_sleep
+  (call $stuff)
+  (call $stuff)
+  (call $stuff)
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_i32_i64 (func (result i32 i64)))
+ (import "env" "import" (func $import))
+ (import "env" "import2" (func $import2 (result i32)))
+ (import "env" "import3" (func $import3 (param i32)))
+ (import "env" "import-mv" (func $import-mv (result i32 i64)))
+ (memory $0 1 2)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $calls-import
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $import)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $calls-import2 (result i32)
+  (local $temp i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $8
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $1
+     (i32.load
+      (local.get $8)
+     )
+    )
+   )
+  )
+  (local.set $5
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $6
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (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.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)
+         )
+         (return
+          (local.get $2)
+         )
+        )
+       )
+       (nop)
+       (nop)
+      )
+      (unreachable)
+     )
+     (unreachable)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $5)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $9
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $9)
+    (local.get $1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (i32.const 0)
+ )
+ (func $calls-import2-drop
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $4
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $0
+     (i32.load
+      (local.get $4)
+     )
+    )
+   )
+  )
+  (local.set $1
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $2
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $2)
+          (i32.const 0)
+         )
+        )
+        (block
+         (local.set $3
+          (call $import2)
+         )
+         (if
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 1)
+          )
+          (br $__asyncify_unwind
+           (i32.const 0)
+          )
+          (local.set $0
+           (local.get $3)
+          )
+         )
+        )
+       )
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (drop
+         (local.get $0)
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $5
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $5)
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+ )
+ (func $calls-nothing
+  (local $0 i32)
+  (local.set $0
+   (i32.eqz
+    (i32.const 17)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $many-locals (param $x i32) (result i32)
+  (local $y i32)
+  (local $z (f32 i64))
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $13
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $y
+     (i32.load
+      (local.get $13)
+     )
+    )
+   )
+  )
+  (local.set $11
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $12
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (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)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $12)
+          (i32.const 0)
+         )
+        )
+        (block
+         (call $import)
+         (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)
+        )
+        (block
+         (local.set $8
+          (local.get $y)
+         )
+         (return
+          (local.get $8)
+         )
+        )
+       )
+       (nop)
+      )
+      (unreachable)
+     )
+     (unreachable)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $11)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $14
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $14)
+    (local.get $y)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (i32.const 0)
+ )
+ (func $calls-import2-if (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $2
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $3
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (local.set $1
+         (local.get $x)
+        )
+       )
+       (if
+        (i32.or
+         (local.get $1)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 2)
+         )
+        )
+        (if
+         (if (result i32)
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 0)
+          )
+          (i32.const 1)
+          (i32.eq
+           (local.get $3)
+           (i32.const 0)
+          )
+         )
+         (block
+          (call $import)
+          (if
+           (i32.eq
+            (global.get $__asyncify_state)
+            (i32.const 1)
+           )
+           (br $__asyncify_unwind
+            (i32.const 0)
+           )
+          )
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $2)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $calls-import2-if-else (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $5
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $2
+     (i32.load
+      (local.get $5)
+     )
+    )
+   )
+  )
+  (local.set $3
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $4
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (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 $2
+          (local.get $1)
+         )
+        )
+        (if
+         (i32.or
+          (local.get $2)
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 2)
+          )
+         )
+         (if
+          (if (result i32)
+           (i32.eq
+            (global.get $__asyncify_state)
+            (i32.const 0)
+           )
+           (i32.const 1)
+           (i32.eq
+            (local.get $4)
+            (i32.const 0)
+           )
+          )
+          (block
+           (call $import3
+            (i32.const 1)
+           )
+           (if
+            (i32.eq
+             (global.get $__asyncify_state)
+             (i32.const 1)
+            )
+            (br $__asyncify_unwind
+             (i32.const 0)
+            )
+           )
+          )
+         )
+        )
+        (if
+         (i32.or
+          (i32.eqz
+           (local.get $2)
+          )
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 2)
+          )
+         )
+         (if
+          (if (result i32)
+           (i32.eq
+            (global.get $__asyncify_state)
+            (i32.const 0)
+           )
+           (i32.const 1)
+           (i32.eq
+            (local.get $4)
+            (i32.const 1)
+           )
+          )
+          (block
+           (call $import3
+            (i32.const 2)
+           )
+           (if
+            (i32.eq
+             (global.get $__asyncify_state)
+             (i32.const 1)
+            )
+            (br $__asyncify_unwind
+             (i32.const 1)
+            )
+           )
+          )
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $3)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $6
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $6)
+    (local.get $2)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+ )
+ (func $calls-import2-if-else-oneside (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $5
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $6
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (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)
+          )
+         )
+         (if
+          (i32.or
+           (local.get $4)
+           (i32.eq
+            (global.get $__asyncify_state)
+            (i32.const 2)
+           )
+          )
+          (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)
+           )
+          )
+          (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
+            (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)
+        )
+       )
+      )
+      (unreachable)
+     )
+     (unreachable)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $5)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+  (i32.const 0)
+ )
+ (func $calls-import2-if-else-oneside2 (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $7
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $4
+     (i32.load
+      (local.get $7)
+     )
+    )
+   )
+  )
+  (local.set $5
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $6
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (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)
+          )
+         )
+         (if
+          (i32.or
+           (local.get $4)
+           (i32.eq
+            (global.get $__asyncify_state)
+            (i32.const 2)
+           )
+          )
+          (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
+            (call $import3
+             (i32.const 1)
+            )
+            (if
+             (i32.eq
+              (global.get $__asyncify_state)
+              (i32.const 1)
+             )
+             (br $__asyncify_unwind
+              (i32.const 0)
+             )
+            )
+           )
+          )
+         )
+         (if
+          (i32.or
+           (i32.eqz
+            (local.get $4)
+           )
+           (i32.eq
+            (global.get $__asyncify_state)
+            (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)
+        )
+       )
+      )
+      (unreachable)
+     )
+     (unreachable)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $5)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $8
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $8)
+    (local.get $4)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (i32.const 0)
+ )
+ (func $calls-mv
+  (local $x (i32 i64))
+  (local $1 (i32 i64))
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 (i32 i64))
+  (local $5 i32)
+  (local $6 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -12)
+     )
+    )
+    (local.set $5
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $1
+     (tuple.make
+      (i32.load
+       (local.get $5)
+      )
+      (i64.load offset=4 align=4
+       (local.get $5)
+      )
+     )
+    )
+   )
+  )
+  (local.set $2
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $3
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $3)
+          (i32.const 0)
+         )
+        )
+        (block
+         (local.set $4
+          (call $import-mv)
+         )
+         (if
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 1)
+          )
+          (br $__asyncify_unwind
+           (i32.const 0)
+          )
+          (local.set $1
+           (local.get $4)
+          )
+         )
+        )
+       )
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (local.set $x
+         (local.get $1)
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $2)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $6
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $6)
+    (tuple.extract 0
+     (local.get $1)
+    )
+   )
+   (i64.store offset=4 align=4
+    (local.get $6)
+    (tuple.extract 1
+     (local.get $1)
+    )
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 12)
+    )
+   )
+  )
+ )
+ (func $calls-loop (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $6
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $x
+     (i32.load
+      (local.get $6)
+     )
+    )
+   )
+  )
+  (local.set $4
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $5
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (loop $l
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $5)
+          (i32.const 0)
+         )
+        )
+        (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)
+        )
+        (block
+         (local.set $1
+          (local.get $x)
+         )
+         (local.set $2
+          (i32.add
+           (local.get $1)
+           (i32.const 1)
+          )
+         )
+         (local.set $x
+          (local.get $2)
+         )
+         (local.set $3
+          (local.get $x)
+         )
+         (br_if $l
+          (local.get $3)
+         )
+        )
+       )
+       (nop)
+       (nop)
+       (nop)
+       (nop)
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $4)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $7
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $7)
+    (local.get $x)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+ )
+ (func $calls-loop2
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $4
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $0
+     (i32.load
+      (local.get $4)
+     )
+    )
+   )
+  )
+  (local.set $1
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $2
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (loop $l
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $2)
+          (i32.const 0)
+         )
+        )
+        (block
+         (local.set $3
+          (call $import2)
+         )
+         (if
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 1)
+          )
+          (br $__asyncify_unwind
+           (i32.const 0)
+          )
+          (local.set $0
+           (local.get $3)
+          )
+         )
+        )
+       )
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (br_if $l
+         (local.get $0)
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $5
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $5)
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+ )
+ (func $calls-mix
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (call $boring)
+       )
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $1)
+          (i32.const 0)
+         )
+        )
+        (block
+         (call $import)
+         (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)
+        )
+        (call $boring)
+       )
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $1)
+          (i32.const 1)
+         )
+        )
+        (block
+         (call $import)
+         (if
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 1)
+          )
+          (br $__asyncify_unwind
+           (i32.const 1)
+          )
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $boring
+  (nop)
+ )
+ (func $calls-mix-deep
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (call $boring-deep)
+       )
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $1)
+          (i32.const 0)
+         )
+        )
+        (block
+         (call $import-deep)
+         (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)
+        )
+        (call $boring)
+       )
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $1)
+          (i32.const 1)
+         )
+        )
+        (block
+         (call $import)
+         (if
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 1)
+          )
+          (br $__asyncify_unwind
+           (i32.const 1)
+          )
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $boring-deep
+  (call $boring)
+ )
+ (func $import-deep
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $import)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 1 1)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify_enable-multivalue.wast b/binaryen/test/passes/asyncify_enable-multivalue.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_enable-multivalue.wast
@@ -0,0 +1,157 @@
+;; Pre-existing imports that the pass turns into the implementations.
+(module
+  (memory 1 2)
+  (import "asyncify" "start_unwind" (func $asyncify_start_unwind (param i32)))
+  (import "asyncify" "stop_unwind" (func $asyncify_stop_unwind))
+  (import "asyncify" "start_rewind" (func $asyncify_start_rewind (param i32)))
+  (import "asyncify" "stop_rewind" (func $asyncify_stop_rewind))
+  (global $sleeping (mut i32) (i32.const 0))
+  ;; do a sleep operation: start a sleep if running, or resume after a sleep
+  ;; if we just rewound.
+  (func $do_sleep
+    (if
+      (i32.eqz (global.get $sleeping))
+      (block
+        (global.set $sleeping (i32.const 1))
+        ;; we should set up the data at address 4 around here
+        (call $asyncify_start_unwind (i32.const 4))
+      )
+      (block
+        (global.set $sleeping (i32.const 0))
+        (call $asyncify_stop_rewind)
+      )
+    )
+  )
+  ;; a function that does some work and has a sleep (async pause/resume) in the middle
+  (func $work
+    (call $stuff) ;; do some work
+    (call $do_sleep) ;; take a break
+    (call $stuff) ;; do some more work
+  )
+  (func  $stuff)
+  ;; the first event called from the main event loop: just call into $work
+  (func $first_event
+    (call $work)
+    ;; work will sleep, so we exit through here while it is paused
+  )
+  ;; the second event called from the main event loop: to resume $work,
+  ;; stop the unwind, then prepare a rewind, and initiate it by doing
+  ;; the call to rewind the call stack back up to where it was
+  (func $second_event
+    (call $asyncify_stop_unwind)
+    (call $asyncify_start_rewind (i32.const 4))
+    (call $work)
+  )
+  ;; a function that can't do a sleep
+  (func $never_sleep
+    (call $stuff)
+    (call $stuff)
+    (call $stuff)
+  )
+)
+;; Calls to imports that will call into asyncify themselves.
+(module
+  (memory 1 2)
+  (import "env" "import" (func $import))
+  (import "env" "import2" (func $import2 (result i32)))
+  (import "env" "import3" (func $import3 (param i32)))
+  (import "env" "import-mv" (func $import-mv (result i32 i64)))
+  (func $calls-import
+    (call $import)
+  )
+  (func $calls-import2 (result i32)
+    (local $temp i32)
+    (local.set $temp (call $import2))
+    (return (local.get $temp))
+  )
+  (func $calls-import2-drop
+    (drop (call $import2))
+  )
+  (func $calls-nothing
+    (drop (i32.eqz (i32.const 17)))
+  )
+  (func $many-locals (param $x i32) (result i32)
+    (local $y i32)
+    (local $z (f32 i64))
+    (loop $l
+      (local.set $x
+        (i32.add (local.get $y) (i32.const 1))
+      )
+      (local.set $y
+        (i32.div_s (local.get $x) (i32.const 3))
+      )
+      (br_if $l (local.get $y))
+    )
+    (call $import)
+    (return (local.get $y))
+  )
+  (func $calls-import2-if (param $x i32)
+    (if (local.get $x)
+      (call $import)
+    )
+  )
+  (func $calls-import2-if-else (param $x i32)
+    (if (local.get $x)
+      (call $import3 (i32.const 1))
+      (call $import3 (i32.const 2))
+    )
+  )
+  (func $calls-import2-if-else-oneside (param $x i32) (result i32)
+    (if (local.get $x)
+      (return (i32.const 1))
+      (call $import3 (i32.const 2))
+    )
+    (return (i32.const 3))
+  )
+  (func $calls-import2-if-else-oneside2 (param $x i32) (result i32)
+    (if (local.get $x)
+      (call $import3 (i32.const 1))
+      (return (i32.const 2))
+    )
+    (return (i32.const 3))
+  )
+  (func $calls-mv
+    (local $x (i32 i64))
+    (local.set $x (call $import-mv))
+  )
+  (func $calls-loop (param $x i32)
+    (loop $l
+      (call $import3 (i32.const 1))
+      (local.set $x
+        (i32.add (local.get $x) (i32.const 1))
+      )
+      (br_if $l
+        (local.get $x)
+      )
+    )
+  )
+  (func $calls-loop2
+    (loop $l
+      (br_if $l
+        (call $import2)
+      )
+    )
+  )
+  (func $calls-mix
+    (call $boring)
+    (call $import)
+    (call $boring)
+    (call $import)
+  )
+  (func $boring)
+  (func $calls-mix-deep
+    (call $boring-deep)
+    (call $import-deep)
+    (call $boring)
+    (call $import)
+  )
+  (func $boring-deep
+    (call $boring)
+  )
+  (func $import-deep
+    (call $import)
+  )
+)
+;; empty module, in particular with no memory
+(module
+)
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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind.txt
@@ -0,0 +1,468 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "import" (func $import))
+ (import "env" "import2" (func $import2 (result i32)))
+ (import "env" "import3" (func $import3 (param i32)))
+ (memory $0 1 2)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $calls-import
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.const 0)
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.const 0)
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $import)
+        (if
+         (i32.const 1)
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $calls-import2 (result i32)
+  (local $temp i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (if
+   (i32.const 0)
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $8
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $1
+     (i32.load
+      (local.get $8)
+     )
+    )
+   )
+  )
+  (local.set $5
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.const 0)
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $6
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (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 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)
+         )
+         (return
+          (local.get $2)
+         )
+        )
+       )
+       (nop)
+       (nop)
+      )
+      (unreachable)
+     )
+     (unreachable)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $5)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $9
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $9)
+    (local.get $1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (i32.const 0)
+ )
+ (func $calls-import2-drop
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (if
+   (i32.const 0)
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $4
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $0
+     (i32.load
+      (local.get $4)
+     )
+    )
+   )
+  )
+  (local.set $1
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.const 0)
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $2
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $2)
+          (i32.const 0)
+         )
+        )
+        (block
+         (local.set $3
+          (call $import2)
+         )
+         (if
+          (i32.const 1)
+          (br $__asyncify_unwind
+           (i32.const 0)
+          )
+          (local.set $0
+           (local.get $3)
+          )
+         )
+        )
+       )
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (drop
+         (local.get $0)
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $5
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $5)
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+ )
+ (func $calls-nothing
+  (local $0 i32)
+  (local.set $0
+   (i32.eqz
+    (i32.const 17)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind.wast b/binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind.wast
@@ -0,0 +1,20 @@
+(module
+  (memory 1 2)
+  (import "env" "import" (func $import))
+  (import "env" "import2" (func $import2 (result i32)))
+  (import "env" "import3" (func $import3 (param i32)))
+  (func $calls-import
+    (call $import)
+  )
+  (func $calls-import2 (result i32)
+    (local $temp i32)
+    (local.set $temp (call $import2))
+    (return (local.get $temp))
+  )
+  (func $calls-import2-drop
+    (drop (call $import2))
+  )
+  (func $calls-nothing
+    (drop (i32.eqz (i32.const 17)))
+  )
+)
diff --git a/binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.txt b/binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.txt
@@ -0,0 +1,94 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "import" (func $import))
+ (memory $0 1 2)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "calls-import" (func $calls-import))
+ (export "calls-import2" (func $calls-import))
+ (export "calls-import2-drop" (func $calls-import))
+ (export "calls-nothing" (func $calls-import))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_unwind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $calls-import (; has Stack IR ;)
+  (local $0 i32)
+  (call $import)
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $0)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+ )
+ (func $asyncify_start_unwind (; has Stack IR ;) (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind (; has Stack IR ;)
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (; has Stack IR ;) (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (; has Stack IR ;) (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.wast b/binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.wast
@@ -0,0 +1,24 @@
+(module
+  (memory 1 2)
+  (import "env" "import" (func $import))
+  (import "env" "import2" (func $import2 (result i32)))
+  (import "env" "import3" (func $import3 (param i32)))
+  (export "calls-import" (func $calls-import))
+  (export "calls-import2" (func $calls-import))
+  (export "calls-import2-drop" (func $calls-import))
+  (export "calls-nothing" (func $calls-import))
+  (func $calls-import
+    (call $import)
+  )
+  (func $calls-import2 (result i32)
+    (local $temp i32)
+    (local.set $temp (call $import2))
+    (return (local.get $temp))
+  )
+  (func $calls-import2-drop
+    (drop (call $import2))
+  )
+  (func $calls-nothing
+    (drop (i32.eqz (i32.const 17)))
+  )
+)
diff --git a/binaryen/test/passes/asyncify_mod-asyncify-never-unwind.txt b/binaryen/test/passes/asyncify_mod-asyncify-never-unwind.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_mod-asyncify-never-unwind.txt
@@ -0,0 +1,486 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "import" (func $import))
+ (import "env" "import2" (func $import2 (result i32)))
+ (import "env" "import3" (func $import3 (param i32)))
+ (memory $0 1 2)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $calls-import
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $import)
+        (if
+         (i32.const 0)
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $calls-import2 (result i32)
+  (local $temp i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $8
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $1
+     (i32.load
+      (local.get $8)
+     )
+    )
+   )
+  )
+  (local.set $5
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $6
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (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
+           (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)
+         )
+         (return
+          (local.get $2)
+         )
+        )
+       )
+       (nop)
+       (nop)
+      )
+      (unreachable)
+     )
+     (unreachable)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $5)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $9
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $9)
+    (local.get $1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (i32.const 0)
+ )
+ (func $calls-import2-drop
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $4
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $0
+     (i32.load
+      (local.get $4)
+     )
+    )
+   )
+  )
+  (local.set $1
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $2
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $2)
+          (i32.const 0)
+         )
+        )
+        (block
+         (local.set $3
+          (call $import2)
+         )
+         (if
+          (i32.const 0)
+          (br $__asyncify_unwind
+           (i32.const 0)
+          )
+          (local.set $0
+           (local.get $3)
+          )
+         )
+        )
+       )
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (drop
+         (local.get $0)
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $5
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $5)
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+ )
+ (func $calls-nothing
+  (local $0 i32)
+  (local.set $0
+   (i32.eqz
+    (i32.const 17)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify_mod-asyncify-never-unwind.wast b/binaryen/test/passes/asyncify_mod-asyncify-never-unwind.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_mod-asyncify-never-unwind.wast
@@ -0,0 +1,20 @@
+(module
+  (memory 1 2)
+  (import "env" "import" (func $import))
+  (import "env" "import2" (func $import2 (result i32)))
+  (import "env" "import3" (func $import3 (param i32)))
+  (func $calls-import
+    (call $import)
+  )
+  (func $calls-import2 (result i32)
+    (local $temp i32)
+    (local.set $temp (call $import2))
+    (return (local.get $temp))
+  )
+  (func $calls-import2-drop
+    (drop (call $import2))
+  )
+  (func $calls-nothing
+    (drop (i32.eqz (i32.const 17)))
+  )
+)
diff --git a/binaryen/test/passes/asyncify_mod-asyncify-never-unwind_O.txt b/binaryen/test/passes/asyncify_mod-asyncify-never-unwind_O.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_mod-asyncify-never-unwind_O.txt
@@ -0,0 +1,109 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "import" (func $import))
+ (memory $0 1 2)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "calls-import" (func $calls-import))
+ (export "calls-import2" (func $calls-import))
+ (export "calls-import2-drop" (func $calls-import))
+ (export "calls-nothing" (func $calls-import))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_unwind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $calls-import (; has Stack IR ;)
+  (if
+   (select
+    (i32.eqz
+     (if (result i32)
+      (i32.eq
+       (global.get $__asyncify_state)
+       (i32.const 2)
+      )
+      (block (result i32)
+       (i32.store
+        (global.get $__asyncify_data)
+        (i32.add
+         (i32.load
+          (global.get $__asyncify_data)
+         )
+         (i32.const -4)
+        )
+       )
+       (i32.load
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+       )
+      )
+      (i32.const 0)
+     )
+    )
+    (i32.const 1)
+    (global.get $__asyncify_state)
+   )
+   (call $import)
+  )
+ )
+ (func $asyncify_start_unwind (; has Stack IR ;) (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind (; has Stack IR ;)
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (; has Stack IR ;) (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (; has Stack IR ;) (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify_mod-asyncify-never-unwind_O.wast b/binaryen/test/passes/asyncify_mod-asyncify-never-unwind_O.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_mod-asyncify-never-unwind_O.wast
@@ -0,0 +1,24 @@
+(module
+  (memory 1 2)
+  (import "env" "import" (func $import))
+  (import "env" "import2" (func $import2 (result i32)))
+  (import "env" "import3" (func $import3 (param i32)))
+  (export "calls-import" (func $calls-import))
+  (export "calls-import2" (func $calls-import))
+  (export "calls-import2-drop" (func $calls-import))
+  (export "calls-nothing" (func $calls-import))
+  (func $calls-import
+    (call $import)
+  )
+  (func $calls-import2 (result i32)
+    (local $temp i32)
+    (local.set $temp (call $import2))
+    (return (local.get $temp))
+  )
+  (func $calls-import2-drop
+    (drop (call $import2))
+  )
+  (func $calls-nothing
+    (drop (i32.eqz (i32.const 17)))
+  )
+)
diff --git a/binaryen/test/passes/asyncify_optimize-level=1.txt b/binaryen/test/passes/asyncify_optimize-level=1.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_optimize-level=1.txt
@@ -0,0 +1,1511 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "import" (func $import))
+ (import "env" "import2" (func $import2 (result i32)))
+ (import "env" "import3" (func $import3 (param i32)))
+ (memory $0 1 2)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $calls-import
+  (local $0 i32)
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (if
+     (select
+      (i32.eqz
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 2)
+        )
+        (block (result i32)
+         (i32.store
+          (global.get $__asyncify_data)
+          (i32.add
+           (i32.load
+            (global.get $__asyncify_data)
+           )
+           (i32.const -4)
+          )
+         )
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+        (local.get $0)
+       )
+      )
+      (i32.const 1)
+      (global.get $__asyncify_state)
+     )
+     (block
+      (call $import)
+      (drop
+       (br_if $__asyncify_unwind
+        (i32.const 0)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 1)
+        )
+       )
+      )
+     )
+    )
+    (return)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $0)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+ )
+ (func $calls-import2 (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $0
+     (i32.load
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+     )
+    )
+   )
+  )
+  (local.set $1
+   (block $__asyncify_unwind (result i32)
+    (if
+     (select
+      (i32.eqz
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 2)
+        )
+        (block (result i32)
+         (i32.store
+          (global.get $__asyncify_data)
+          (i32.add
+           (i32.load
+            (global.get $__asyncify_data)
+           )
+           (i32.const -4)
+          )
+         )
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+        (local.get $1)
+       )
+      )
+      (i32.const 1)
+      (global.get $__asyncify_state)
+     )
+     (block
+      (local.set $1
+       (call $import2)
+      )
+      (drop
+       (br_if $__asyncify_unwind
+        (i32.const 0)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 1)
+        )
+       )
+      )
+      (local.set $0
+       (local.get $1)
+      )
+     )
+    )
+    (if
+     (i32.eqz
+      (global.get $__asyncify_state)
+     )
+     (return
+      (local.get $0)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $1)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $0)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $calls-import2-drop
+  (local $0 i32)
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (if
+     (select
+      (i32.eqz
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 2)
+        )
+        (block (result i32)
+         (i32.store
+          (global.get $__asyncify_data)
+          (i32.add
+           (i32.load
+            (global.get $__asyncify_data)
+           )
+           (i32.const -4)
+          )
+         )
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+        (local.get $0)
+       )
+      )
+      (i32.const 1)
+      (global.get $__asyncify_state)
+     )
+     (block
+      (drop
+       (call $import2)
+      )
+      (drop
+       (br_if $__asyncify_unwind
+        (i32.const 0)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 1)
+        )
+       )
+      )
+     )
+    )
+    (return)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $0)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+ )
+ (func $calls-nothing
+  (nop)
+ )
+ (func $many-locals (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $1
+     (i32.load
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+     )
+    )
+   )
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (if
+     (i32.eq
+      (global.get $__asyncify_state)
+      (i32.const 2)
+     )
+     (block
+      (i32.store
+       (global.get $__asyncify_data)
+       (i32.add
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+        (i32.const -4)
+       )
+      )
+      (local.set $2
+       (i32.load
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+       )
+      )
+     )
+    )
+    (if
+     (i32.eqz
+      (global.get $__asyncify_state)
+     )
+     (loop $l
+      (br_if $l
+       (local.tee $1
+        (i32.div_s
+         (i32.add
+          (local.get $1)
+          (i32.const 1)
+         )
+         (i32.const 3)
+        )
+       )
+      )
+     )
+    )
+    (if
+     (select
+      (i32.eqz
+       (local.get $2)
+      )
+      (i32.const 1)
+      (global.get $__asyncify_state)
+     )
+     (block
+      (call $import)
+      (drop
+       (br_if $__asyncify_unwind
+        (i32.const 0)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 1)
+        )
+       )
+      )
+     )
+    )
+    (if
+     (i32.eqz
+      (global.get $__asyncify_state)
+     )
+     (return
+      (local.get $1)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $0)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $1)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $calls-import2-if (param $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (if
+     (i32.eq
+      (global.get $__asyncify_state)
+      (i32.const 2)
+     )
+     (block
+      (i32.store
+       (global.get $__asyncify_data)
+       (i32.add
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+        (i32.const -4)
+       )
+      )
+      (local.set $1
+       (i32.load
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+       )
+      )
+     )
+    )
+    (if
+     (i32.or
+      (local.get $0)
+      (i32.eq
+       (global.get $__asyncify_state)
+       (i32.const 2)
+      )
+     )
+     (if
+      (select
+       (i32.eqz
+        (local.get $1)
+       )
+       (i32.const 1)
+       (global.get $__asyncify_state)
+      )
+      (block
+       (call $import)
+       (drop
+        (br_if $__asyncify_unwind
+         (i32.const 0)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+        )
+       )
+      )
+     )
+    )
+    (return)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $0)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+ )
+ (func $calls-import2-if-else (param $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $1
+     (i32.load
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+     )
+    )
+   )
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (if
+     (i32.eq
+      (global.get $__asyncify_state)
+      (i32.const 2)
+     )
+     (block
+      (i32.store
+       (global.get $__asyncify_data)
+       (i32.add
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+        (i32.const -4)
+       )
+      )
+      (local.set $2
+       (i32.load
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+       )
+      )
+     )
+    )
+    (if
+     (i32.or
+      (local.tee $1
+       (select
+        (local.get $1)
+        (local.get $0)
+        (global.get $__asyncify_state)
+       )
+      )
+      (i32.eq
+       (global.get $__asyncify_state)
+       (i32.const 2)
+      )
+     )
+     (if
+      (select
+       (i32.eqz
+        (local.get $2)
+       )
+       (i32.const 1)
+       (global.get $__asyncify_state)
+      )
+      (block
+       (call $import3
+        (i32.const 1)
+       )
+       (drop
+        (br_if $__asyncify_unwind
+         (i32.const 0)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+        )
+       )
+      )
+     )
+    )
+    (if
+     (i32.or
+      (i32.eqz
+       (local.get $1)
+      )
+      (i32.eq
+       (global.get $__asyncify_state)
+       (i32.const 2)
+      )
+     )
+     (if
+      (select
+       (i32.eq
+        (local.get $2)
+        (i32.const 1)
+       )
+       (i32.const 1)
+       (global.get $__asyncify_state)
+      )
+      (block
+       (call $import3
+        (i32.const 2)
+       )
+       (drop
+        (br_if $__asyncify_unwind
+         (i32.const 1)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+        )
+       )
+      )
+     )
+    )
+    (return)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $0)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $1)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+ )
+ (func $calls-import2-if-else-oneside (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (if
+     (i32.eq
+      (global.get $__asyncify_state)
+      (i32.const 2)
+     )
+     (block
+      (i32.store
+       (global.get $__asyncify_data)
+       (i32.add
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+        (i32.const -4)
+       )
+      )
+      (local.set $1
+       (i32.load
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+       )
+      )
+     )
+    )
+    (if
+     (i32.or
+      (local.tee $2
+       (select
+        (local.get $2)
+        (local.get $0)
+        (global.get $__asyncify_state)
+       )
+      )
+      (i32.eq
+       (global.get $__asyncify_state)
+       (i32.const 2)
+      )
+     )
+     (if
+      (i32.eqz
+       (global.get $__asyncify_state)
+      )
+      (return
+       (i32.const 1)
+      )
+     )
+    )
+    (if
+     (i32.or
+      (i32.eqz
+       (local.get $2)
+      )
+      (i32.eq
+       (global.get $__asyncify_state)
+       (i32.const 2)
+      )
+     )
+     (if
+      (select
+       (i32.eqz
+        (local.get $1)
+       )
+       (i32.const 1)
+       (global.get $__asyncify_state)
+      )
+      (block
+       (call $import3
+        (i32.const 2)
+       )
+       (drop
+        (br_if $__asyncify_unwind
+         (i32.const 0)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+        )
+       )
+      )
+     )
+    )
+    (if
+     (i32.eqz
+      (global.get $__asyncify_state)
+     )
+     (return
+      (i32.const 3)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $0)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $calls-import2-if-else-oneside2 (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $1
+     (i32.load
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+     )
+    )
+   )
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (if
+     (i32.eq
+      (global.get $__asyncify_state)
+      (i32.const 2)
+     )
+     (block
+      (i32.store
+       (global.get $__asyncify_data)
+       (i32.add
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+        (i32.const -4)
+       )
+      )
+      (local.set $2
+       (i32.load
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+       )
+      )
+     )
+    )
+    (if
+     (i32.or
+      (local.tee $1
+       (select
+        (local.get $1)
+        (local.get $0)
+        (global.get $__asyncify_state)
+       )
+      )
+      (i32.eq
+       (global.get $__asyncify_state)
+       (i32.const 2)
+      )
+     )
+     (if
+      (select
+       (i32.eqz
+        (local.get $2)
+       )
+       (i32.const 1)
+       (global.get $__asyncify_state)
+      )
+      (block
+       (call $import3
+        (i32.const 1)
+       )
+       (drop
+        (br_if $__asyncify_unwind
+         (i32.const 0)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+        )
+       )
+      )
+     )
+    )
+    (if
+     (i32.or
+      (i32.eqz
+       (local.get $1)
+      )
+      (i32.eq
+       (global.get $__asyncify_state)
+       (i32.const 2)
+      )
+     )
+     (if
+      (i32.eqz
+       (global.get $__asyncify_state)
+      )
+      (return
+       (i32.const 2)
+      )
+     )
+    )
+    (if
+     (i32.eqz
+      (global.get $__asyncify_state)
+     )
+     (return
+      (i32.const 3)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $0)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $1)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $calls-loop (param $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $0
+     (i32.load
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+     )
+    )
+   )
+  )
+  (local.set $1
+   (block $__asyncify_unwind (result i32)
+    (if
+     (i32.eq
+      (global.get $__asyncify_state)
+      (i32.const 2)
+     )
+     (block
+      (i32.store
+       (global.get $__asyncify_data)
+       (i32.add
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+        (i32.const -4)
+       )
+      )
+      (local.set $1
+       (i32.load
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+       )
+      )
+     )
+    )
+    (loop $l
+     (if
+      (select
+       (i32.eqz
+        (local.get $1)
+       )
+       (i32.const 1)
+       (global.get $__asyncify_state)
+      )
+      (block
+       (call $import3
+        (i32.const 1)
+       )
+       (drop
+        (br_if $__asyncify_unwind
+         (i32.const 0)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+        )
+       )
+      )
+     )
+     (if
+      (i32.eqz
+       (global.get $__asyncify_state)
+      )
+      (br_if $l
+       (local.tee $0
+        (i32.add
+         (local.get $0)
+         (i32.const 1)
+        )
+       )
+      )
+     )
+    )
+    (return)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $1)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $0)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+ )
+ (func $calls-loop2
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $0
+     (i32.load
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+     )
+    )
+   )
+  )
+  (local.set $1
+   (block $__asyncify_unwind (result i32)
+    (if
+     (i32.eq
+      (global.get $__asyncify_state)
+      (i32.const 2)
+     )
+     (block
+      (i32.store
+       (global.get $__asyncify_data)
+       (i32.add
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+        (i32.const -4)
+       )
+      )
+      (local.set $2
+       (i32.load
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+       )
+      )
+     )
+    )
+    (loop $l
+     (if
+      (select
+       (i32.eqz
+        (local.get $2)
+       )
+       (i32.const 1)
+       (global.get $__asyncify_state)
+      )
+      (block
+       (local.set $1
+        (call $import2)
+       )
+       (drop
+        (br_if $__asyncify_unwind
+         (i32.const 0)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+        )
+       )
+       (local.set $0
+        (local.get $1)
+       )
+      )
+     )
+     (br_if $l
+      (select
+       (i32.eqz
+        (global.get $__asyncify_state)
+       )
+       (i32.const 0)
+       (local.get $0)
+      )
+     )
+    )
+    (return)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $1)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $0)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+ )
+ (func $calls-mix
+  (local $0 i32)
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (if
+     (i32.eq
+      (global.get $__asyncify_state)
+      (i32.const 2)
+     )
+     (block
+      (i32.store
+       (global.get $__asyncify_data)
+       (i32.add
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+        (i32.const -4)
+       )
+      )
+      (local.set $0
+       (i32.load
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+       )
+      )
+     )
+    )
+    (if
+     (i32.eqz
+      (global.get $__asyncify_state)
+     )
+     (call $boring)
+    )
+    (if
+     (select
+      (i32.eqz
+       (local.get $0)
+      )
+      (i32.const 1)
+      (global.get $__asyncify_state)
+     )
+     (block
+      (call $import)
+      (drop
+       (br_if $__asyncify_unwind
+        (i32.const 0)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 1)
+        )
+       )
+      )
+     )
+    )
+    (if
+     (i32.eqz
+      (global.get $__asyncify_state)
+     )
+     (call $boring)
+    )
+    (if
+     (select
+      (i32.eq
+       (local.get $0)
+       (i32.const 1)
+      )
+      (i32.const 1)
+      (global.get $__asyncify_state)
+     )
+     (block
+      (call $import)
+      (drop
+       (br_if $__asyncify_unwind
+        (i32.const 1)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 1)
+        )
+       )
+      )
+     )
+    )
+    (return)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $0)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+ )
+ (func $boring
+  (nop)
+ )
+ (func $calls-mix-deep
+  (local $0 i32)
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (if
+     (i32.eq
+      (global.get $__asyncify_state)
+      (i32.const 2)
+     )
+     (block
+      (i32.store
+       (global.get $__asyncify_data)
+       (i32.add
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+        (i32.const -4)
+       )
+      )
+      (local.set $0
+       (i32.load
+        (i32.load
+         (global.get $__asyncify_data)
+        )
+       )
+      )
+     )
+    )
+    (if
+     (i32.eqz
+      (global.get $__asyncify_state)
+     )
+     (call $boring-deep)
+    )
+    (if
+     (select
+      (i32.eqz
+       (local.get $0)
+      )
+      (i32.const 1)
+      (global.get $__asyncify_state)
+     )
+     (block
+      (call $import-deep)
+      (drop
+       (br_if $__asyncify_unwind
+        (i32.const 0)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 1)
+        )
+       )
+      )
+     )
+    )
+    (if
+     (i32.eqz
+      (global.get $__asyncify_state)
+     )
+     (call $boring)
+    )
+    (if
+     (select
+      (i32.eq
+       (local.get $0)
+       (i32.const 1)
+      )
+      (i32.const 1)
+      (global.get $__asyncify_state)
+     )
+     (block
+      (call $import)
+      (drop
+       (br_if $__asyncify_unwind
+        (i32.const 1)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 1)
+        )
+       )
+      )
+     )
+    )
+    (return)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $0)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+ )
+ (func $boring-deep
+  (call $boring)
+ )
+ (func $import-deep
+  (local $0 i32)
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (if
+     (select
+      (i32.eqz
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 2)
+        )
+        (block (result i32)
+         (i32.store
+          (global.get $__asyncify_data)
+          (i32.add
+           (i32.load
+            (global.get $__asyncify_data)
+           )
+           (i32.const -4)
+          )
+         )
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+        (local.get $0)
+       )
+      )
+      (i32.const 1)
+      (global.get $__asyncify_state)
+     )
+     (block
+      (call $import)
+      (drop
+       (br_if $__asyncify_unwind
+        (i32.const 0)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 1)
+        )
+       )
+      )
+     )
+    )
+    (return)
+   )
+  )
+  (i32.store
+   (i32.load
+    (global.get $__asyncify_data)
+   )
+   (local.get $0)
+  )
+  (i32.store
+   (global.get $__asyncify_data)
+   (i32.add
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.const 4)
+   )
+  )
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify_optimize-level=1.wast b/binaryen/test/passes/asyncify_optimize-level=1.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_optimize-level=1.wast
@@ -0,0 +1,97 @@
+(module
+  (memory 1 2)
+  (import "env" "import" (func $import))
+  (import "env" "import2" (func $import2 (result i32)))
+  (import "env" "import3" (func $import3 (param i32)))
+  (func $calls-import
+    (call $import)
+  )
+  (func $calls-import2 (result i32)
+    (local $temp i32)
+    (local.set $temp (call $import2))
+    (return (local.get $temp))
+  )
+  (func $calls-import2-drop
+    (drop (call $import2))
+  )
+  (func $calls-nothing
+    (drop (i32.eqz (i32.const 17)))
+  )
+  (func $many-locals (param $x i32) (result i32)
+    (local $y i32)
+    (loop $l
+      (local.set $x
+        (i32.add (local.get $y) (i32.const 1))
+      )
+      (local.set $y
+        (i32.div_s (local.get $x) (i32.const 3))
+      )
+      (br_if $l (local.get $y))
+    )
+    (call $import)
+    (return (local.get $y))
+  )
+  (func $calls-import2-if (param $x i32)
+    (if (local.get $x)
+      (call $import)
+    )
+  )
+  (func $calls-import2-if-else (param $x i32)
+    (if (local.get $x)
+      (call $import3 (i32.const 1))
+      (call $import3 (i32.const 2))
+    )
+  )
+  (func $calls-import2-if-else-oneside (param $x i32) (result i32)
+    (if (local.get $x)
+      (return (i32.const 1))
+      (call $import3 (i32.const 2))
+    )
+    (return (i32.const 3))
+  )
+  (func $calls-import2-if-else-oneside2 (param $x i32) (result i32)
+    (if (local.get $x)
+      (call $import3 (i32.const 1))
+      (return (i32.const 2))
+    )
+    (return (i32.const 3))
+  )
+  (func $calls-loop (param $x i32)
+    (loop $l
+      (call $import3 (i32.const 1))
+      (local.set $x
+        (i32.add (local.get $x) (i32.const 1))
+      )
+      (br_if $l
+        (local.get $x)
+      )
+    )
+  )
+  (func $calls-loop2
+    (loop $l
+      (br_if $l
+        (call $import2)
+      )
+    )
+  )
+  (func $calls-mix
+    (call $boring)
+    (call $import)
+    (call $boring)
+    (call $import)
+  )
+  (func $boring)
+  (func $calls-mix-deep
+    (call $boring-deep)
+    (call $import-deep)
+    (call $boring)
+    (call $import)
+  )
+  (func $boring-deep
+    (call $boring)
+  )
+  (func $import-deep
+    (call $import)
+  )
+)
+
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo.txt b/binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo.txt
@@ -0,0 +1,162 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "import" (func $import))
+ (memory $0 1 2)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $foo
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.tee $0
+   (block $__asyncify_unwind
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 0)
+       )
+       (call $nothing)
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $bar
+  (call $nothing)
+ )
+ (func $nothing
+  (nop)
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo.wast b/binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo.wast
@@ -0,0 +1,13 @@
+(module
+  (memory 1 2)
+  (import "env" "import" (func $import))
+  (func $foo ;; doesn't look like it needs instrumentation, but in add list
+    (call $nothing)
+  )
+  (func $bar ;; doesn't look like it needs instrumentation, and not in add list
+    (call $nothing)
+  )
+  (func $nothing
+  )
+)
+
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo_pass-arg=asyncify-ignore-indirect.txt b/binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo_pass-arg=asyncify-ignore-indirect.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo_pass-arg=asyncify-ignore-indirect.txt
@@ -0,0 +1,195 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "import" (func $import))
+ (memory $0 1 2)
+ (table $0 1 funcref)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $foo
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (call $nothing)
+       )
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $1)
+          (i32.const 0)
+         )
+        )
+        (block
+         (call_indirect (type $none_=>_none)
+          (i32.const 0)
+         )
+         (if
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 1)
+          )
+          (br $__asyncify_unwind
+           (i32.const 0)
+          )
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $bar
+  (call $nothing)
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+ (func $nothing
+  (nop)
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo_pass-arg=asyncify-ignore-indirect.wast b/binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo_pass-arg=asyncify-ignore-indirect.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-addlist@foo_pass-arg=asyncify-ignore-indirect.wast
@@ -0,0 +1,18 @@
+(module
+  (type $t (func))
+  (memory 1 2)
+  (table 1 funcref)
+  (elem (i32.const 0))
+  (import "env" "import" (func $import))
+  (func $foo ;; doesn't look like it needs instrumentation, but in add list
+    (call $nothing)
+    (call_indirect (type $t) (i32.const 0))
+  )
+  (func $bar ;; doesn't look like it needs instrumentation, and not in add list
+    (call $nothing)
+    (call_indirect (type $t) (i32.const 0))
+  )
+  (func $nothing
+  )
+)
+
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-asserts_pass-arg=asyncify-onlylist@waka.txt b/binaryen/test/passes/asyncify_pass-arg=asyncify-asserts_pass-arg=asyncify-onlylist@waka.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-asserts_pass-arg=asyncify-onlylist@waka.txt
@@ -0,0 +1,205 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "import" (func $import))
+ (import "env" "import2" (func $import2 (result i32)))
+ (import "env" "import3" (func $import3 (param i32)))
+ (memory $0 1 2)
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $calls-import2-drop $calls-import2-drop)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $calls-import
+  (local $0 i32)
+  (local.set $0
+   (global.get $__asyncify_state)
+  )
+  (block
+   (call $import)
+   (if
+    (i32.ne
+     (global.get $__asyncify_state)
+     (local.get $0)
+    )
+    (unreachable)
+   )
+  )
+ )
+ (func $calls-import2-drop
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $1
+   (global.get $__asyncify_state)
+  )
+  (block
+   (local.set $0
+    (block (result i32)
+     (local.set $2
+      (call $import2)
+     )
+     (if
+      (i32.ne
+       (global.get $__asyncify_state)
+       (local.get $1)
+      )
+      (unreachable)
+     )
+     (local.get $2)
+    )
+   )
+   (drop
+    (local.get $0)
+   )
+  )
+ )
+ (func $returns (result i32)
+  (local $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local.set $5
+   (global.get $__asyncify_state)
+  )
+  (block
+   (block
+    (local.set $1
+     (block (result i32)
+      (local.set $6
+       (call $import2)
+      )
+      (if
+       (i32.ne
+        (global.get $__asyncify_state)
+        (local.get $5)
+       )
+       (unreachable)
+      )
+      (local.get $6)
+     )
+    )
+    (local.set $x
+     (local.get $1)
+    )
+    (local.set $2
+     (local.get $x)
+    )
+    (local.set $3
+     (local.get $2)
+    )
+   )
+   (local.set $4
+    (local.get $3)
+   )
+   (return
+    (local.get $4)
+   )
+  )
+ )
+ (func $calls-indirect (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $2
+   (global.get $__asyncify_state)
+  )
+  (block
+   (local.set $1
+    (local.get $x)
+   )
+   (block
+    (call_indirect (type $none_=>_none)
+     (local.get $1)
+    )
+    (if
+     (i32.ne
+      (global.get $__asyncify_state)
+      (local.get $2)
+     )
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-asserts_pass-arg=asyncify-onlylist@waka.wast b/binaryen/test/passes/asyncify_pass-arg=asyncify-asserts_pass-arg=asyncify-onlylist@waka.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-asserts_pass-arg=asyncify-onlylist@waka.wast
@@ -0,0 +1,25 @@
+(module
+  (memory 1 2)
+  (type $f (func))
+  (import "env" "import" (func $import))
+  (import "env" "import2" (func $import2 (result i32)))
+  (import "env" "import3" (func $import3 (param i32)))
+  (table 1 1)
+  (func $calls-import
+    (call $import)
+  )
+  (func $calls-import2-drop
+    (drop (call $import2))
+  )
+  (func $returns (result i32)
+    (local $x i32)
+    (local.set $x (call $import2))
+    (local.get $x)
+  )
+  (func $calls-indirect (param $x i32)
+    (call_indirect (type $f)
+      (local.get $x)
+    )
+  )
+)
+
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-blacklist@foo,bar.txt b/binaryen/test/passes/asyncify_pass-arg=asyncify-blacklist@foo,bar.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-blacklist@foo,bar.txt
@@ -0,0 +1,270 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "import" (func $import))
+ (memory $0 1 2)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $foo
+  (call $import)
+ )
+ (func $bar
+  (call $import)
+ )
+ (func $baz
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $import)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $other1
+  (call $foo)
+ )
+ (func $other2
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $baz)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-blacklist@foo,bar.wast b/binaryen/test/passes/asyncify_pass-arg=asyncify-blacklist@foo,bar.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-blacklist@foo,bar.wast
@@ -0,0 +1,20 @@
+(module
+  (memory 1 2)
+  (import "env" "import" (func $import))
+  (func $foo
+    (call $import)
+  )
+  (func $bar
+    (call $import)
+  )
+  (func $baz
+    (call $import)
+  )
+  (func $other1
+    (call $foo)
+  )
+  (func $other2
+    (call $baz)
+  )
+)
+
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-imports.txt b/binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-imports.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-imports.txt
@@ -0,0 +1,260 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "import" (func $import))
+ (import "env" "import2" (func $import2 (result i32)))
+ (import "env" "import3" (func $import3 (param i32)))
+ (memory $0 1 2)
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $calls-import2-drop $calls-import2-drop)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $calls-import
+  (call $import)
+ )
+ (func $calls-import2-drop
+  (local $0 i32)
+  (local.set $0
+   (call $import2)
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $calls-import2-if-else (param $x i32)
+  (local $1 i32)
+  (local.set $1
+   (local.get $x)
+  )
+  (if
+   (local.get $1)
+   (call $import3
+    (i32.const 1)
+   )
+   (call $import3
+    (i32.const 2)
+   )
+  )
+ )
+ (func $calls-indirect (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $4
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $1
+     (i32.load
+      (local.get $4)
+     )
+    )
+   )
+  )
+  (local.set $2
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $3
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (local.set $1
+         (local.get $x)
+        )
+       )
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $3)
+          (i32.const 0)
+         )
+        )
+        (block
+         (call_indirect (type $none_=>_none)
+          (local.get $1)
+         )
+         (if
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 1)
+          )
+          (br $__asyncify_unwind
+           (i32.const 0)
+          )
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $2)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $5
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $5)
+    (local.get $1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-imports.wast b/binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-imports.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-imports.wast
@@ -0,0 +1,26 @@
+(module
+  (memory 1 2)
+  (type $f (func))
+  (import "env" "import" (func $import))
+  (import "env" "import2" (func $import2 (result i32)))
+  (import "env" "import3" (func $import3 (param i32)))
+  (table 1 1)
+  (func $calls-import
+    (call $import)
+  )
+  (func $calls-import2-drop
+    (drop (call $import2))
+  )
+  (func $calls-import2-if-else (param $x i32)
+    (if (local.get $x)
+      (call $import3 (i32.const 1))
+      (call $import3 (i32.const 2))
+    )
+  )
+  (func $calls-indirect (param $x i32)
+    (call_indirect (type $f)
+      (local.get $x)
+    )
+  )
+)
+
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-indirect.txt b/binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-indirect.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-indirect.txt
@@ -0,0 +1,534 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "import" (func $import))
+ (import "env" "import2" (func $import2 (result i32)))
+ (import "env" "import3" (func $import3 (param i32)))
+ (memory $0 1 2)
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $calls-import2-drop $calls-import2-drop)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $calls-import
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $import)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $calls-import2-drop
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $4
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $0
+     (i32.load
+      (local.get $4)
+     )
+    )
+   )
+  )
+  (local.set $1
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $2
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $2)
+          (i32.const 0)
+         )
+        )
+        (block
+         (local.set $3
+          (call $import2)
+         )
+         (if
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 1)
+          )
+          (br $__asyncify_unwind
+           (i32.const 0)
+          )
+          (local.set $0
+           (local.get $3)
+          )
+         )
+        )
+       )
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (drop
+         (local.get $0)
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $5
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $5)
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+ )
+ (func $calls-import2-if-else (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $5
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $2
+     (i32.load
+      (local.get $5)
+     )
+    )
+   )
+  )
+  (local.set $3
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $4
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (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 $2
+          (local.get $1)
+         )
+        )
+        (if
+         (i32.or
+          (local.get $2)
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 2)
+          )
+         )
+         (if
+          (if (result i32)
+           (i32.eq
+            (global.get $__asyncify_state)
+            (i32.const 0)
+           )
+           (i32.const 1)
+           (i32.eq
+            (local.get $4)
+            (i32.const 0)
+           )
+          )
+          (block
+           (call $import3
+            (i32.const 1)
+           )
+           (if
+            (i32.eq
+             (global.get $__asyncify_state)
+             (i32.const 1)
+            )
+            (br $__asyncify_unwind
+             (i32.const 0)
+            )
+           )
+          )
+         )
+        )
+        (if
+         (i32.or
+          (i32.eqz
+           (local.get $2)
+          )
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 2)
+          )
+         )
+         (if
+          (if (result i32)
+           (i32.eq
+            (global.get $__asyncify_state)
+            (i32.const 0)
+           )
+           (i32.const 1)
+           (i32.eq
+            (local.get $4)
+            (i32.const 1)
+           )
+          )
+          (block
+           (call $import3
+            (i32.const 2)
+           )
+           (if
+            (i32.eq
+             (global.get $__asyncify_state)
+             (i32.const 1)
+            )
+            (br $__asyncify_unwind
+             (i32.const 1)
+            )
+           )
+          )
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $3)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $6
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $6)
+    (local.get $2)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+ )
+ (func $calls-indirect (param $x i32)
+  (local $1 i32)
+  (local.set $1
+   (local.get $x)
+  )
+  (call_indirect (type $none_=>_none)
+   (local.get $1)
+  )
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-indirect.wast b/binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-indirect.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-ignore-indirect.wast
@@ -0,0 +1,26 @@
+(module
+  (memory 1 2)
+  (type $f (func))
+  (import "env" "import" (func $import))
+  (import "env" "import2" (func $import2 (result i32)))
+  (import "env" "import3" (func $import3 (param i32)))
+  (table 1 1)
+  (func $calls-import
+    (call $import)
+  )
+  (func $calls-import2-drop
+    (drop (call $import2))
+  )
+  (func $calls-import2-if-else (param $x i32)
+    (if (local.get $x)
+      (call $import3 (i32.const 1))
+      (call $import3 (i32.const 2))
+    )
+  )
+  (func $calls-indirect (param $x i32)
+    (call_indirect (type $f)
+      (local.get $x)
+    )
+  )
+)
+
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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-imports@env.import,env.import2.txt
@@ -0,0 +1,1700 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 1 2)
+ (global $sleeping (mut i32) (i32.const 0))
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $do_sleep
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (global.get $sleeping)
+  )
+  (local.set $1
+   (i32.eqz
+    (local.get $0)
+   )
+  )
+  (if
+   (local.get $1)
+   (block $block
+    (global.set $sleeping
+     (i32.const 1)
+    )
+    (call $asyncify_start_unwind
+     (i32.const 4)
+    )
+   )
+   (block $block0
+    (global.set $sleeping
+     (i32.const 0)
+    )
+    (call $asyncify_stop_rewind)
+   )
+  )
+ )
+ (func $work
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (call $stuff)
+       )
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $1)
+          (i32.const 0)
+         )
+        )
+        (block
+         (call $do_sleep)
+         (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)
+        )
+        (call $stuff)
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $stuff
+  (nop)
+ )
+ (func $first_event
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $work)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $second_event
+  (call $asyncify_start_rewind
+   (i32.const 4)
+  )
+  (call $work)
+ )
+ (func $never_sleep
+  (call $stuff)
+  (call $stuff)
+  (call $stuff)
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "import" (func $import))
+ (import "env" "import2" (func $import2 (result i32)))
+ (import "env" "import3" (func $import3 (param i32)))
+ (memory $0 1 2)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $calls-import
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $import)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $calls-import2 (result i32)
+  (local $temp i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $8
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $1
+     (i32.load
+      (local.get $8)
+     )
+    )
+   )
+  )
+  (local.set $5
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $6
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (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.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)
+         )
+         (return
+          (local.get $2)
+         )
+        )
+       )
+       (nop)
+       (nop)
+      )
+      (unreachable)
+     )
+     (unreachable)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $5)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $9
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $9)
+    (local.get $1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (i32.const 0)
+ )
+ (func $calls-import2-drop
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $4
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $0
+     (i32.load
+      (local.get $4)
+     )
+    )
+   )
+  )
+  (local.set $1
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $2
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $2)
+          (i32.const 0)
+         )
+        )
+        (block
+         (local.set $3
+          (call $import2)
+         )
+         (if
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 1)
+          )
+          (br $__asyncify_unwind
+           (i32.const 0)
+          )
+          (local.set $0
+           (local.get $3)
+          )
+         )
+        )
+       )
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (drop
+         (local.get $0)
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $5
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $5)
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+ )
+ (func $calls-nothing
+  (local $0 i32)
+  (local.set $0
+   (i32.eqz
+    (i32.const 17)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $many-locals (param $x i32) (result i32)
+  (local $y i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $12
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $y
+     (i32.load
+      (local.get $12)
+     )
+    )
+   )
+  )
+  (local.set $10
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $11
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (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)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $11)
+          (i32.const 0)
+         )
+        )
+        (block
+         (call $import)
+         (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)
+        )
+        (block
+         (local.set $7
+          (local.get $y)
+         )
+         (return
+          (local.get $7)
+         )
+        )
+       )
+       (nop)
+      )
+      (unreachable)
+     )
+     (unreachable)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $10)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $13
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $13)
+    (local.get $y)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (i32.const 0)
+ )
+ (func $calls-import2-if (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $2
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $3
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (local.set $1
+         (local.get $x)
+        )
+       )
+       (if
+        (i32.or
+         (local.get $1)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 2)
+         )
+        )
+        (if
+         (if (result i32)
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 0)
+          )
+          (i32.const 1)
+          (i32.eq
+           (local.get $3)
+           (i32.const 0)
+          )
+         )
+         (block
+          (call $import)
+          (if
+           (i32.eq
+            (global.get $__asyncify_state)
+            (i32.const 1)
+           )
+           (br $__asyncify_unwind
+            (i32.const 0)
+           )
+          )
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $2)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $calls-import2-if-else (param $x i32)
+  (local $1 i32)
+  (local.set $1
+   (local.get $x)
+  )
+  (if
+   (local.get $1)
+   (call $import3
+    (i32.const 1)
+   )
+   (call $import3
+    (i32.const 2)
+   )
+  )
+ )
+ (func $calls-import2-if-else-oneside (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (block
+   (local.set $1
+    (local.get $x)
+   )
+   (if
+    (local.get $1)
+    (return
+     (i32.const 1)
+    )
+    (call $import3
+     (i32.const 2)
+    )
+   )
+  )
+  (return
+   (i32.const 3)
+  )
+ )
+ (func $calls-import2-if-else-oneside2 (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (block
+   (local.set $1
+    (local.get $x)
+   )
+   (if
+    (local.get $1)
+    (call $import3
+     (i32.const 1)
+    )
+    (return
+     (i32.const 2)
+    )
+   )
+  )
+  (return
+   (i32.const 3)
+  )
+ )
+ (func $calls-loop (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (loop $l
+   (call $import3
+    (i32.const 1)
+   )
+   (local.set $1
+    (local.get $x)
+   )
+   (local.set $2
+    (i32.add
+     (local.get $1)
+     (i32.const 1)
+    )
+   )
+   (local.set $x
+    (local.get $2)
+   )
+   (local.set $3
+    (local.get $x)
+   )
+   (br_if $l
+    (local.get $3)
+   )
+  )
+ )
+ (func $calls-loop2
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (global.get $__asyncify_data)
+     (i32.add
+      (i32.load
+       (global.get $__asyncify_data)
+      )
+      (i32.const -4)
+     )
+    )
+    (local.set $4
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+    )
+    (local.set $0
+     (i32.load
+      (local.get $4)
+     )
+    )
+   )
+  )
+  (local.set $1
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $2
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (loop $l
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $2)
+          (i32.const 0)
+         )
+        )
+        (block
+         (local.set $3
+          (call $import2)
+         )
+         (if
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 1)
+          )
+          (br $__asyncify_unwind
+           (i32.const 0)
+          )
+          (local.set $0
+           (local.get $3)
+          )
+         )
+        )
+       )
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (br_if $l
+         (local.get $0)
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $1)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block
+   (local.set $5
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+   )
+   (i32.store
+    (local.get $5)
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+ )
+ (func $calls-mix
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (call $boring)
+       )
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $1)
+          (i32.const 0)
+         )
+        )
+        (block
+         (call $import)
+         (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)
+        )
+        (call $boring)
+       )
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $1)
+          (i32.const 1)
+         )
+        )
+        (block
+         (call $import)
+         (if
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 1)
+          )
+          (br $__asyncify_unwind
+           (i32.const 1)
+          )
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $boring
+  (nop)
+ )
+ (func $calls-mix-deep
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (call $boring-deep)
+       )
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $1)
+          (i32.const 0)
+         )
+        )
+        (block
+         (call $import-deep)
+         (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)
+        )
+        (call $boring)
+       )
+       (if
+        (if (result i32)
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (i32.const 1)
+         (i32.eq
+          (local.get $1)
+          (i32.const 1)
+         )
+        )
+        (block
+         (call $import)
+         (if
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 1)
+          )
+          (br $__asyncify_unwind
+           (i32.const 1)
+          )
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $boring-deep
+  (call $boring)
+ )
+ (func $import-deep
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $import)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-imports@env.import,env.import2.wast b/binaryen/test/passes/asyncify_pass-arg=asyncify-imports@env.import,env.import2.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-imports@env.import,env.import2.wast
@@ -0,0 +1,146 @@
+;; Pre-existing imports that the pass turns into the implementations.
+(module
+  (memory 1 2)
+  (import "asyncify" "start_unwind" (func $asyncify_start_unwind (param i32)))
+  (import "asyncify" "start_rewind" (func $asyncify_start_rewind (param i32)))
+  (import "asyncify" "stop_rewind" (func $asyncify_stop_rewind))
+  (global $sleeping (mut i32) (i32.const 0))
+  ;; do a sleep operation: start a sleep if running, or resume after a sleep
+  ;; if we just rewound.
+  (func $do_sleep
+    (if
+      (i32.eqz (global.get $sleeping))
+      (block
+        (global.set $sleeping (i32.const 1))
+        ;; we should set up the data at address 4 around here
+        (call $asyncify_start_unwind (i32.const 4))
+      )
+      (block
+        (global.set $sleeping (i32.const 0))
+        (call $asyncify_stop_rewind)
+      )
+    )
+  )
+  ;; a function that does some work and has a sleep (async pause/resume) in the middle
+  (func $work
+    (call $stuff) ;; do some work
+    (call $do_sleep) ;; take a break
+    (call $stuff) ;; do some more work
+  )
+  (func  $stuff)
+  ;; the first event called from the main event loop: just call into $work
+  (func $first_event
+    (call $work)
+    ;; work will sleep, so we exit through here while it is paused
+  )
+  ;; the second event called from the main event loop: to resume $work,
+  ;; initiate a rewind, and then do the call to start things back up
+  (func $second_event
+    (call $asyncify_start_rewind (i32.const 4))
+    (call $work)
+  )
+  ;; a function that can't do a sleep
+  (func $never_sleep
+    (call $stuff)
+    (call $stuff)
+    (call $stuff)
+  )
+)
+;; Calls to imports that will call into asyncify themselves.
+(module
+  (memory 1 2)
+  (import "env" "import" (func $import))
+  (import "env" "import2" (func $import2 (result i32)))
+  (import "env" "import3" (func $import3 (param i32)))
+  (func $calls-import
+    (call $import)
+  )
+  (func $calls-import2 (result i32)
+    (local $temp i32)
+    (local.set $temp (call $import2))
+    (return (local.get $temp))
+  )
+  (func $calls-import2-drop
+    (drop (call $import2))
+  )
+  (func $calls-nothing
+    (drop (i32.eqz (i32.const 17)))
+  )
+  (func $many-locals (param $x i32) (result i32)
+    (local $y i32)
+    (loop $l
+      (local.set $x
+        (i32.add (local.get $y) (i32.const 1))
+      )
+      (local.set $y
+        (i32.div_s (local.get $x) (i32.const 3))
+      )
+      (br_if $l (local.get $y))
+    )
+    (call $import)
+    (return (local.get $y))
+  )
+  (func $calls-import2-if (param $x i32)
+    (if (local.get $x)
+      (call $import)
+    )
+  )
+  (func $calls-import2-if-else (param $x i32)
+    (if (local.get $x)
+      (call $import3 (i32.const 1))
+      (call $import3 (i32.const 2))
+    )
+  )
+  (func $calls-import2-if-else-oneside (param $x i32) (result i32)
+    (if (local.get $x)
+      (return (i32.const 1))
+      (call $import3 (i32.const 2))
+    )
+    (return (i32.const 3))
+  )
+  (func $calls-import2-if-else-oneside2 (param $x i32) (result i32)
+    (if (local.get $x)
+      (call $import3 (i32.const 1))
+      (return (i32.const 2))
+    )
+    (return (i32.const 3))
+  )
+  (func $calls-loop (param $x i32)
+    (loop $l
+      (call $import3 (i32.const 1))
+      (local.set $x
+        (i32.add (local.get $x) (i32.const 1))
+      )
+      (br_if $l
+        (local.get $x)
+      )
+    )
+  )
+  (func $calls-loop2
+    (loop $l
+      (br_if $l
+        (call $import2)
+      )
+    )
+  )
+  (func $calls-mix
+    (call $boring)
+    (call $import)
+    (call $boring)
+    (call $import)
+  )
+  (func $boring)
+  (func $calls-mix-deep
+    (call $boring-deep)
+    (call $import-deep)
+    (call $boring)
+    (call $import)
+  )
+  (func $boring-deep
+    (call $boring)
+  )
+  (func $import-deep
+    (call $import)
+  )
+)
+
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-onlylist@foo,bar.txt b/binaryen/test/passes/asyncify_pass-arg=asyncify-onlylist@foo,bar.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-onlylist@foo,bar.txt
@@ -0,0 +1,270 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "import" (func $import))
+ (memory $0 1 2)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $foo
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $import)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $bar
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $import)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $baz
+  (call $import)
+ )
+ (func $other1
+  (call $foo)
+ )
+ (func $other2
+  (call $baz)
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-onlylist@foo,bar.wast b/binaryen/test/passes/asyncify_pass-arg=asyncify-onlylist@foo,bar.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-onlylist@foo,bar.wast
@@ -0,0 +1,20 @@
+(module
+  (memory 1 2)
+  (import "env" "import" (func $import))
+  (func $foo
+    (call $import)
+  )
+  (func $bar
+    (call $import)
+  )
+  (func $baz
+    (call $import)
+  )
+  (func $other1
+    (call $foo) ;; even though we call foo, we are not in the only list, so do not instrument us
+  )
+  (func $other2
+    (call $baz)
+  )
+)
+
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-verbose.txt b/binaryen/test/passes/asyncify_pass-arg=asyncify-verbose.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-verbose.txt
@@ -0,0 +1,355 @@
+[asyncify] import is an import that can change the state
+[asyncify] calls-import can change the state due to import
+[asyncify] calls-calls-import can change the state due to calls-import
+[asyncify] calls-calls-calls-import can change the state due to calls-calls-import
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "import" (func $import))
+ (memory $0 1 2)
+ (global $__asyncify_state (mut i32) (i32.const 0))
+ (global $__asyncify_data (mut i32) (i32.const 0))
+ (export "asyncify_start_unwind" (func $asyncify_start_unwind))
+ (export "asyncify_stop_unwind" (func $asyncify_stop_unwind))
+ (export "asyncify_start_rewind" (func $asyncify_start_rewind))
+ (export "asyncify_stop_rewind" (func $asyncify_stop_rewind))
+ (export "asyncify_get_state" (func $asyncify_get_state))
+ (func $calls-import
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $import)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $calls-calls-import
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $calls-import)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $calls-calls-calls-import
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.eq
+    (global.get $__asyncify_state)
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (block $__asyncify_unwind (result i32)
+    (block
+     (block
+      (if
+       (i32.eq
+        (global.get $__asyncify_state)
+        (i32.const 2)
+       )
+       (block
+        (i32.store
+         (global.get $__asyncify_data)
+         (i32.add
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+          (i32.const -4)
+         )
+        )
+        (local.set $1
+         (i32.load
+          (i32.load
+           (global.get $__asyncify_data)
+          )
+         )
+        )
+       )
+      )
+      (if
+       (if (result i32)
+        (i32.eq
+         (global.get $__asyncify_state)
+         (i32.const 0)
+        )
+        (i32.const 1)
+        (i32.eq
+         (local.get $1)
+         (i32.const 0)
+        )
+       )
+       (block
+        (call $calls-calls-import)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 1)
+         )
+         (br $__asyncify_unwind
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+  (block
+   (i32.store
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (local.get $0)
+   )
+   (i32.store
+    (global.get $__asyncify_data)
+    (i32.add
+     (i32.load
+      (global.get $__asyncify_data)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+ )
+ (func $nothing
+  (nop)
+ )
+ (func $asyncify_start_unwind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 1)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_unwind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_start_rewind (param $0 i32)
+  (global.set $__asyncify_state
+   (i32.const 2)
+  )
+  (global.set $__asyncify_data
+   (local.get $0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_stop_rewind
+  (global.set $__asyncify_state
+   (i32.const 0)
+  )
+  (if
+   (i32.gt_u
+    (i32.load
+     (global.get $__asyncify_data)
+    )
+    (i32.load offset=4
+     (global.get $__asyncify_data)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $asyncify_get_state (result i32)
+  (global.get $__asyncify_state)
+ )
+)
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-verbose.wast b/binaryen/test/passes/asyncify_pass-arg=asyncify-verbose.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-verbose.wast
@@ -0,0 +1,17 @@
+(module
+  (memory 1 2)
+  (import "env" "import" (func $import))
+  (func $calls-import
+    (call $import)
+  )
+  (func $calls-calls-import
+    (call $calls-import)
+  )
+  (func $calls-calls-calls-import
+    (call $calls-calls-import)
+  )
+  (func $nothing
+    (nop)
+  )
+)
+
diff --git a/binaryen/test/passes/avoid-reinterprets.txt b/binaryen/test/passes/avoid-reinterprets.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/avoid-reinterprets.txt
@@ -0,0 +1,182 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_f32 (func (result f32)))
+ (memory $0 1)
+ (func $simple
+  (drop
+   (f32.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (f64.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i64.load
+    (i32.const 1024)
+   )
+  )
+ )
+ (func $one
+  (local $x i32)
+  (local $1 i32)
+  (local $2 f32)
+  (local.set $x
+   (block (result i32)
+    (local.set $1
+     (i32.const 1024)
+    )
+    (local.set $2
+     (f32.load
+      (local.get $1)
+     )
+    )
+    (i32.load
+     (local.get $1)
+    )
+   )
+  )
+  (drop
+   (local.get $2)
+  )
+ )
+ (func $one-b
+  (local $x f32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $x
+   (block (result f32)
+    (local.set $1
+     (i32.const 1024)
+    )
+    (local.set $2
+     (i32.load
+      (local.get $1)
+     )
+    )
+    (f32.load
+     (local.get $1)
+    )
+   )
+  )
+  (drop
+   (local.get $2)
+  )
+ )
+ (func $both
+  (local $x i32)
+  (local $1 i32)
+  (local $2 f32)
+  (local.set $x
+   (block (result i32)
+    (local.set $1
+     (i32.const 1024)
+    )
+    (local.set $2
+     (f32.load
+      (local.get $1)
+     )
+    )
+    (i32.load
+     (local.get $1)
+    )
+   )
+  )
+  (drop
+   (local.get $2)
+  )
+  (drop
+   (local.get $2)
+  )
+ )
+ (func $half
+  (local $x i32)
+  (local $1 i32)
+  (local $2 f32)
+  (local.set $x
+   (block (result i32)
+    (local.set $1
+     (i32.const 1024)
+    )
+    (local.set $2
+     (f32.load
+      (local.get $1)
+     )
+    )
+    (i32.load
+     (local.get $1)
+    )
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (local.get $2)
+  )
+ )
+ (func $copy
+  (local $x i32)
+  (local $y i32)
+  (local $2 i32)
+  (local $3 f32)
+  (local.set $x
+   (block (result i32)
+    (local.set $2
+     (i32.const 1024)
+    )
+    (local.set $3
+     (f32.load
+      (local.get $2)
+     )
+    )
+    (i32.load
+     (local.get $2)
+    )
+   )
+  )
+  (local.set $y
+   (local.get $x)
+  )
+  (drop
+   (local.get $3)
+  )
+ )
+ (func $partial1 (result f32)
+  (f32.reinterpret_i32
+   (i32.load16_u
+    (i32.const 3)
+   )
+  )
+ )
+ (func $partial2 (result f32)
+  (f32.reinterpret_i32
+   (i32.load8_u
+    (i32.const 3)
+   )
+  )
+ )
+ (func $nofallthrough
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (f32.reinterpret_i32
+    (block $block (result i32)
+     (nop)
+     (local.get $x)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/avoid-reinterprets.wast b/binaryen/test/passes/avoid-reinterprets.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/avoid-reinterprets.wast
@@ -0,0 +1,69 @@
+(module
+  (memory 1)
+  (func $simple
+    (drop (f32.reinterpret_i32 (i32.load (i32.const 1024))))
+    (drop (i32.reinterpret_f32 (f32.load (i32.const 1024))))
+    (drop (f64.reinterpret_i64 (i64.load (i32.const 1024))))
+    (drop (i64.reinterpret_f64 (f64.load (i32.const 1024))))
+  )
+  (func $one
+    (local $x i32)
+    (local.set $x (i32.load (i32.const 1024)))
+    (drop (f32.reinterpret_i32 (local.get $x)))
+  )
+  (func $one-b
+    (local $x f32)
+    (local.set $x (f32.load (i32.const 1024)))
+    (drop (i32.reinterpret_f32 (local.get $x)))
+  )
+  (func $both
+    (local $x i32)
+    (local.set $x (i32.load (i32.const 1024)))
+    (drop (f32.reinterpret_i32 (local.get $x)))
+    (drop (f32.reinterpret_i32 (local.get $x)))
+  )
+  (func $half
+    (local $x i32)
+    (local.set $x (i32.load (i32.const 1024)))
+    (drop (local.get $x))
+    (drop (f32.reinterpret_i32 (local.get $x)))
+  )
+  (func $copy
+    (local $x i32)
+    (local $y i32)
+    (local.set $x (i32.load (i32.const 1024)))
+    (local.set $y (local.get $x))
+    (drop (f32.reinterpret_i32 (local.get $y)))
+  )
+  (func $partial1 (result f32)
+   (f32.reinterpret_i32
+    (i32.load16_u
+     (i32.const 3)
+    )
+   )
+  )
+  (func $partial2 (result f32)
+   (f32.reinterpret_i32
+    (i32.load8_u
+     (i32.const 3)
+    )
+   )
+  )
+  (func $nofallthrough
+    (local $x i32)
+    (local.set $x
+     (i32.load
+      (i32.const 1024)
+     )
+    )
+    (drop
+     (f32.reinterpret_i32
+      (block (result i32)
+       (nop) ;; this would be removed by other opts, but in general, we can't
+             ;; just look at the fallthrough, as we can't just remove code here
+       (local.get $x)
+      )
+     )
+    )
+  )
+)
diff --git a/binaryen/test/passes/avoid-reinterprets64.passes b/binaryen/test/passes/avoid-reinterprets64.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/avoid-reinterprets64.passes
@@ -0,0 +1,1 @@
+avoid-reinterprets_enable-memory64
diff --git a/binaryen/test/passes/avoid-reinterprets64.txt b/binaryen/test/passes/avoid-reinterprets64.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/avoid-reinterprets64.txt
@@ -0,0 +1,182 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_f32 (func (result f32)))
+ (memory $0 i64 1)
+ (func $simple
+  (drop
+   (f32.load
+    (i64.const 1024)
+   )
+  )
+  (drop
+   (i32.load
+    (i64.const 1024)
+   )
+  )
+  (drop
+   (f64.load
+    (i64.const 1024)
+   )
+  )
+  (drop
+   (i64.load
+    (i64.const 1024)
+   )
+  )
+ )
+ (func $one
+  (local $x i32)
+  (local $1 i64)
+  (local $2 f32)
+  (local.set $x
+   (block (result i32)
+    (local.set $1
+     (i64.const 1024)
+    )
+    (local.set $2
+     (f32.load
+      (local.get $1)
+     )
+    )
+    (i32.load
+     (local.get $1)
+    )
+   )
+  )
+  (drop
+   (local.get $2)
+  )
+ )
+ (func $one-b
+  (local $x f32)
+  (local $1 i64)
+  (local $2 i32)
+  (local.set $x
+   (block (result f32)
+    (local.set $1
+     (i64.const 1024)
+    )
+    (local.set $2
+     (i32.load
+      (local.get $1)
+     )
+    )
+    (f32.load
+     (local.get $1)
+    )
+   )
+  )
+  (drop
+   (local.get $2)
+  )
+ )
+ (func $both
+  (local $x i32)
+  (local $1 i64)
+  (local $2 f32)
+  (local.set $x
+   (block (result i32)
+    (local.set $1
+     (i64.const 1024)
+    )
+    (local.set $2
+     (f32.load
+      (local.get $1)
+     )
+    )
+    (i32.load
+     (local.get $1)
+    )
+   )
+  )
+  (drop
+   (local.get $2)
+  )
+  (drop
+   (local.get $2)
+  )
+ )
+ (func $half
+  (local $x i32)
+  (local $1 i64)
+  (local $2 f32)
+  (local.set $x
+   (block (result i32)
+    (local.set $1
+     (i64.const 1024)
+    )
+    (local.set $2
+     (f32.load
+      (local.get $1)
+     )
+    )
+    (i32.load
+     (local.get $1)
+    )
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (local.get $2)
+  )
+ )
+ (func $copy
+  (local $x i32)
+  (local $y i32)
+  (local $2 i64)
+  (local $3 f32)
+  (local.set $x
+   (block (result i32)
+    (local.set $2
+     (i64.const 1024)
+    )
+    (local.set $3
+     (f32.load
+      (local.get $2)
+     )
+    )
+    (i32.load
+     (local.get $2)
+    )
+   )
+  )
+  (local.set $y
+   (local.get $x)
+  )
+  (drop
+   (local.get $3)
+  )
+ )
+ (func $partial1 (result f32)
+  (f32.reinterpret_i32
+   (i32.load16_u
+    (i64.const 3)
+   )
+  )
+ )
+ (func $partial2 (result f32)
+  (f32.reinterpret_i32
+   (i32.load8_u
+    (i64.const 3)
+   )
+  )
+ )
+ (func $nofallthrough
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (i64.const 1024)
+   )
+  )
+  (drop
+   (f32.reinterpret_i32
+    (block $block (result i32)
+     (nop)
+     (local.get $x)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/avoid-reinterprets64.wast b/binaryen/test/passes/avoid-reinterprets64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/avoid-reinterprets64.wast
@@ -0,0 +1,69 @@
+(module
+  (memory i64 1)
+  (func $simple
+    (drop (f32.reinterpret_i32 (i32.load (i64.const 1024))))
+    (drop (i32.reinterpret_f32 (f32.load (i64.const 1024))))
+    (drop (f64.reinterpret_i64 (i64.load (i64.const 1024))))
+    (drop (i64.reinterpret_f64 (f64.load (i64.const 1024))))
+  )
+  (func $one
+    (local $x i32)
+    (local.set $x (i32.load (i64.const 1024)))
+    (drop (f32.reinterpret_i32 (local.get $x)))
+  )
+  (func $one-b
+    (local $x f32)
+    (local.set $x (f32.load (i64.const 1024)))
+    (drop (i32.reinterpret_f32 (local.get $x)))
+  )
+  (func $both
+    (local $x i32)
+    (local.set $x (i32.load (i64.const 1024)))
+    (drop (f32.reinterpret_i32 (local.get $x)))
+    (drop (f32.reinterpret_i32 (local.get $x)))
+  )
+  (func $half
+    (local $x i32)
+    (local.set $x (i32.load (i64.const 1024)))
+    (drop (local.get $x))
+    (drop (f32.reinterpret_i32 (local.get $x)))
+  )
+  (func $copy
+    (local $x i32)
+    (local $y i32)
+    (local.set $x (i32.load (i64.const 1024)))
+    (local.set $y (local.get $x))
+    (drop (f32.reinterpret_i32 (local.get $y)))
+  )
+  (func $partial1 (result f32)
+   (f32.reinterpret_i32
+    (i32.load16_u
+     (i64.const 3)
+    )
+   )
+  )
+  (func $partial2 (result f32)
+   (f32.reinterpret_i32
+    (i32.load8_u
+     (i64.const 3)
+    )
+   )
+  )
+  (func $nofallthrough
+    (local $x i32)
+    (local.set $x
+     (i32.load
+      (i64.const 1024)
+     )
+    )
+    (drop
+     (f32.reinterpret_i32
+      (block (result i32)
+       (nop) ;; this would be removed by other opts, but in general, we can't
+             ;; just look at the fallthrough, as we can't just remove code here
+       (local.get $x)
+      )
+     )
+    )
+  )
+)
diff --git a/binaryen/test/passes/class_with_dwarf_noprint.bin.txt b/binaryen/test/passes/class_with_dwarf_noprint.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/class_with_dwarf_noprint.bin.txt
@@ -0,0 +1,708 @@
+DWARF debug info
+================
+
+Contains section .debug_info (429 bytes)
+Contains section .debug_loc (199 bytes)
+Contains section .debug_ranges (24 bytes)
+Contains section .debug_abbrev (337 bytes)
+Contains section .debug_line (438 bytes)
+Contains section .debug_str (364 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+[2] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_location	DW_FORM_exprloc
+
+[3] DW_TAG_structure_type	DW_CHILDREN_yes
+	DW_AT_calling_convention	DW_FORM_data1
+	DW_AT_name	DW_FORM_strp
+	DW_AT_byte_size	DW_FORM_data1
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[4] DW_TAG_member	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_data_member_location	DW_FORM_data1
+	DW_AT_accessibility	DW_FORM_data1
+
+[5] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_declaration	DW_FORM_flag_present
+	DW_AT_external	DW_FORM_flag_present
+
+[6] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_artificial	DW_FORM_flag_present
+
+[7] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_declaration	DW_FORM_flag_present
+	DW_AT_external	DW_FORM_flag_present
+
+[8] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[9] DW_TAG_enumeration_type	DW_CHILDREN_yes
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_byte_size	DW_FORM_data1
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[10] DW_TAG_enumerator	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_const_value	DW_FORM_udata
+
+[11] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+[12] DW_TAG_pointer_type	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[13] DW_TAG_namespace	DW_CHILDREN_yes
+	DW_AT_name	DW_FORM_strp
+
+[14] DW_TAG_typedef	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[15] DW_TAG_unspecified_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+
+[16] DW_TAG_imported_declaration	DW_CHILDREN_no
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_import	DW_FORM_ref4
+
+[17] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_specification	DW_FORM_ref4
+	DW_AT_inline	DW_FORM_data1
+	DW_AT_object_pointer	DW_FORM_ref4
+
+[18] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_artificial	DW_FORM_flag_present
+
+[19] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[20] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[21] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[22] DW_TAG_lexical_block	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+[23] DW_TAG_inlined_subroutine	DW_CHILDREN_yes
+	DW_AT_abstract_origin	DW_FORM_ref4
+	DW_AT_ranges	DW_FORM_sec_offset
+	DW_AT_call_file	DW_FORM_data1
+	DW_AT_call_line	DW_FORM_data1
+	DW_AT_call_column	DW_FORM_data1
+
+[24] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[25] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[26] DW_TAG_inlined_subroutine	DW_CHILDREN_yes
+	DW_AT_abstract_origin	DW_FORM_ref4
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_call_file	DW_FORM_data1
+	DW_AT_call_line	DW_FORM_data1
+	DW_AT_call_column	DW_FORM_data1
+
+[27] DW_TAG_GNU_call_site	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x000001a9 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x000001ad)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 11.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project d6fe253653b7e760f94ca21d0a7ebbfeeee28777)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000095] = "/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x000000c1] = "/tmp/emscripten_test_wasm3_2u9tontv")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000006)
+              DW_AT_high_pc [DW_FORM_data4]	(0x000000b0)
+
+0x00000026:   DW_TAG_variable [2]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000e5] = "rng1")
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0037 => {0x00000037} "Random")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+                DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(23)
+                DW_AT_location [DW_FORM_exprloc]	(DW_OP_addr 0x638)
+
+0x00000037:   DW_TAG_structure_type [3] *
+                DW_AT_calling_convention [DW_FORM_data1]	(DW_CC_pass_by_value)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000fc] = "Random")
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+                DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(9)
+
+0x00000040:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ea] = "last")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0095 => {0x00000095} "unsigned int")
+                  DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(22)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x00)
+                  DW_AT_accessibility [DW_FORM_data1]	(DW_ACCESS_protected)
+
+0x0000004d:     DW_TAG_subprogram [5] *
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000fc] = "Random")
+                  DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(15)
+                  DW_AT_declaration [DW_FORM_flag_present]	(true)
+                  DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000054:       DW_TAG_formal_parameter [6]  
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x009c => {0x0000009c} "Random*")
+                    DW_AT_artificial [DW_FORM_flag_present]	(true)
+
+0x00000059:       NULL
+
+0x0000005a:     DW_TAG_subprogram [7] *
+                  DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x00000103] = "_ZN6Random3getEf")
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000114] = "get")
+                  DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(16)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a1 => {0x000000a1} "float")
+                  DW_AT_declaration [DW_FORM_flag_present]	(true)
+                  DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000069:       DW_TAG_formal_parameter [6]  
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x009c => {0x0000009c} "Random*")
+                    DW_AT_artificial [DW_FORM_flag_present]	(true)
+
+0x0000006e:       DW_TAG_formal_parameter [8]  
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x00a1 => {0x000000a1} "float")
+
+0x00000073:       NULL
+
+0x00000074:     DW_TAG_enumeration_type [9] *
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0095 => {0x00000095} "unsigned int")
+                  DW_AT_byte_size [DW_FORM_data1]	(0x04)
+                  DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(10)
+
+0x0000007c:       DW_TAG_enumerator [10]  
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000011e] = "IM")
+                    DW_AT_const_value [DW_FORM_udata]	(139968)
+
+0x00000084:       DW_TAG_enumerator [10]  
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000121] = "IA")
+                    DW_AT_const_value [DW_FORM_udata]	(3877)
+
+0x0000008b:       DW_TAG_enumerator [10]  
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000124] = "IC")
+                    DW_AT_const_value [DW_FORM_udata]	(29573)
+
+0x00000093:       NULL
+
+0x00000094:     NULL
+
+0x00000095:   DW_TAG_base_type [11]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ef] = "unsigned int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_unsigned)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x0000009c:   DW_TAG_pointer_type [12]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0037 => {0x00000037} "Random")
+
+0x000000a1:   DW_TAG_base_type [11]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000118] = "float")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_float)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x000000a8:   DW_TAG_namespace [13] *
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000127] = "std")
+
+0x000000ad:     DW_TAG_typedef [14]  
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00b9 => {0x000000b9} "decltype(nullptr)")
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000013d] = "nullptr_t")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/system/include/libcxx/__nullptr")
+                  DW_AT_decl_line [DW_FORM_data1]	(57)
+
+0x000000b8:     NULL
+
+0x000000b9:   DW_TAG_unspecified_type [15]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000012b] = "decltype(nullptr)")
+
+0x000000be:   DW_TAG_imported_declaration [16]  
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/system/include/libcxx/stddef.h")
+                DW_AT_decl_line [DW_FORM_data1]	(52)
+                DW_AT_import [DW_FORM_ref4]	(cu + 0x00ad => {0x000000ad})
+
+0x000000c5:   DW_TAG_subprogram [17] *
+                DW_AT_specification [DW_FORM_ref4]	(cu + 0x005a => {0x0000005a} "_ZN6Random3getEf")
+                DW_AT_inline [DW_FORM_data1]	(DW_INL_inlined)
+                DW_AT_object_pointer [DW_FORM_ref4]	(cu + 0x00cf => {0x000000cf})
+
+0x000000cf:     DW_TAG_formal_parameter [18]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000147] = "this")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00e4 => {0x000000e4} "Random*")
+                  DW_AT_artificial [DW_FORM_flag_present]	(true)
+
+0x000000d8:     DW_TAG_formal_parameter [19]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014c] = "max")
+                  DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(16)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a1 => {0x000000a1} "float")
+
+0x000000e3:     NULL
+
+0x000000e4:   DW_TAG_pointer_type [12]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0037 => {0x00000037} "Random")
+
+0x000000e9:   DW_TAG_subprogram [20] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000006)
+                DW_AT_high_pc [DW_FORM_data4]	(0x000000b0)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x0 +0, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000150] = "main")
+                DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(24)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x01a5 => {0x000001a5} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000101:     DW_TAG_variable [21]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000000: 
+                     [0x00000022,  0x0000002a): DW_OP_constu 0x2a, DW_OP_stack_value
+                     [0x00000007,  0x00000007): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000159] = "rng2")
+                  DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(25)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0037 => {0x00000037} "Random")
+
+0x00000110:     DW_TAG_variable [21]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000023: 
+                     [0x00000022,  0x0000002a): DW_OP_consts +0, DW_OP_stack_value
+                     [0x0000008f,  0x0000009c): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000015e] = "count")
+                  DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(26)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x01a5 => {0x000001a5} "int")
+
+0x0000011f:     DW_TAG_lexical_block [22] *
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000030)
+                  DW_AT_high_pc [DW_FORM_data4]	(0xffffffd0)
+
+0x00000128:       DW_TAG_variable [21]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000046: 
+                       [0x00000022,  0x0000002a): DW_OP_consts +0, DW_OP_stack_value
+                       [0x00000007,  0x00000007): DW_OP_WASM_location 0x0 +3, DW_OP_stack_value)
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000164] = "i")
+                    DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+                    DW_AT_decl_line [DW_FORM_data1]	(27)
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x01a5 => {0x000001a5} "int")
+
+0x00000137:       DW_TAG_lexical_block [22] *
+                    DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000030)
+                    DW_AT_high_pc [DW_FORM_data4]	(0x0000005f)
+
+0x00000140:         DW_TAG_variable [21]  
+                      DW_AT_location [DW_FORM_sec_offset]	(0x0000009b: 
+                         [0x00000007,  0x00000007): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value)
+                      DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000166] = "x2")
+                      DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+                      DW_AT_decl_line [DW_FORM_data1]	(29)
+                      DW_AT_type [DW_FORM_ref4]	(cu + 0x00a1 => {0x000000a1} "float")
+
+0x0000014f:         DW_TAG_variable [21]  
+                      DW_AT_location [DW_FORM_sec_offset]	(0x000000b1: 
+                         [0x00000007,  0x00000007): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value)
+                      DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000169] = "x1")
+                      DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+                      DW_AT_decl_line [DW_FORM_data1]	(28)
+                      DW_AT_type [DW_FORM_ref4]	(cu + 0x00a1 => {0x000000a1} "float")
+
+0x0000015e:         DW_TAG_inlined_subroutine [23] *
+                      DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x00c5 => {0x000000c5} "_ZN6Random3getEf")
+                      DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
+                         [0x00000006, 0x00000007)
+                         [0x0000006b, 0x00000074))
+                      DW_AT_call_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+                      DW_AT_call_line [DW_FORM_data1]	(28)
+                      DW_AT_call_column [DW_FORM_data1]	(0x15)
+
+0x0000016a:           DW_TAG_formal_parameter [24]  
+                        DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x00cf => {0x000000cf} "this")
+
+0x0000016f:           DW_TAG_formal_parameter [25]  
+                        DW_AT_location [DW_FORM_sec_offset]	(0x00000069: 
+                           [0x0000002c,  0x0000009c): DW_OP_constu 0x3f800000, DW_OP_stack_value)
+                        DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x00d8 => {0x000000d8} "max")
+
+0x00000178:           NULL
+
+0x00000179:         DW_TAG_inlined_subroutine [26] *
+                      DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x00c5 => {0x000000c5} "_ZN6Random3getEf")
+                      DW_AT_low_pc [DW_FORM_addr]	(0x000000000000004a)
+                      DW_AT_high_pc [DW_FORM_data4]	(0x00000019)
+                      DW_AT_call_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm3_2u9tontv/src.cpp")
+                      DW_AT_call_line [DW_FORM_data1]	(29)
+                      DW_AT_call_column [DW_FORM_data1]	(0x15)
+
+0x00000189:           DW_TAG_formal_parameter [24]  
+                        DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x00cf => {0x000000cf} "this")
+
+0x0000018e:           DW_TAG_formal_parameter [25]  
+                        DW_AT_location [DW_FORM_sec_offset]	(0x00000082: 
+                           [0x00000007,  0x00000007): DW_OP_constu 0x3f800000, DW_OP_stack_value)
+                        DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x00d8 => {0x000000d8} "max")
+
+0x00000197:           NULL
+
+0x00000198:         NULL
+
+0x00000199:       NULL
+
+0x0000019a:     DW_TAG_GNU_call_site [27]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000084)
+
+0x0000019f:     DW_TAG_GNU_call_site [27]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000000ab)
+
+0x000001a4:     NULL
+
+0x000001a5:   DW_TAG_base_type [11]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000155] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x000001ac:   NULL
+
+.debug_loc contents:
+0x00000000: 
+            [0x0000001c,  0x00000024): DW_OP_constu 0x2a, DW_OP_stack_value
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000023: 
+            [0x0000001c,  0x00000024): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000089,  0x00000096): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+
+0x00000046: 
+            [0x0000001c,  0x00000024): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +3, DW_OP_stack_value
+
+0x00000069: 
+            [0x00000026,  0x00000096): DW_OP_constu 0x3f800000, DW_OP_stack_value
+
+0x00000082: 
+            [0x00000001,  0x00000001): DW_OP_constu 0x3f800000, DW_OP_stack_value
+
+0x0000009b: 
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value
+
+0x000000b1: 
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x000001b2
+         version: 4
+ prologue_length: 0x0000007b
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+include_directories[  1] = "/usr/local/google/home/azakai/Dev/emscripten/system/include/libcxx"
+file_names[  1]:
+           name: "src.cpp"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  2]:
+           name: "__nullptr"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  3]:
+           name: "stddef.h"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000085: 00 DW_LNE_set_address (0x0000000000000006)
+0x0000008c: 03 DW_LNS_advance_line (24)
+0x0000008e: 01 DW_LNS_copy
+            0x0000000000000006     24      0      1   0             0  is_stmt
+
+
+0x0000008f: 00 DW_LNE_set_address (0x0000000000000030)
+0x00000096: 03 DW_LNS_advance_line (17)
+0x00000098: 05 DW_LNS_set_column (13)
+0x0000009a: 0a DW_LNS_set_prologue_end
+0x0000009b: 01 DW_LNS_copy
+            0x0000000000000030     17     13      1   0             0  is_stmt prologue_end
+
+
+0x0000009c: 00 DW_LNE_set_address (0x0000000000000037)
+0x000000a3: 05 DW_LNS_set_column (18)
+0x000000a5: 06 DW_LNS_negate_stmt
+0x000000a6: 01 DW_LNS_copy
+            0x0000000000000037     17     18      1   0             0 
+
+
+0x000000a7: 00 DW_LNE_set_address (0x000000000000003c)
+0x000000ae: 05 DW_LNS_set_column (23)
+0x000000b0: 01 DW_LNS_copy
+            0x000000000000003c     17     23      1   0             0 
+
+
+0x000000b1: 00 DW_LNE_set_address (0x0000000000000041)
+0x000000b8: 05 DW_LNS_set_column (29)
+0x000000ba: 01 DW_LNS_copy
+            0x0000000000000041     17     29      1   0             0 
+
+
+0x000000bb: 00 DW_LNE_set_address (0x0000000000000042)
+0x000000c2: 05 DW_LNS_set_column (10)
+0x000000c4: 01 DW_LNS_copy
+            0x0000000000000042     17     10      1   0             0 
+
+
+0x000000c5: 00 DW_LNE_set_address (0x0000000000000048)
+0x000000cc: 03 DW_LNS_advance_line (30)
+0x000000ce: 05 DW_LNS_set_column (5)
+0x000000d0: 06 DW_LNS_negate_stmt
+0x000000d1: 01 DW_LNS_copy
+            0x0000000000000048     30      5      1   0             0  is_stmt
+
+
+0x000000d2: 00 DW_LNE_set_address (0x000000000000004a)
+0x000000d9: 03 DW_LNS_advance_line (17)
+0x000000db: 05 DW_LNS_set_column (18)
+0x000000dd: 01 DW_LNS_copy
+            0x000000000000004a     17     18      1   0             0  is_stmt
+
+
+0x000000de: 00 DW_LNE_set_address (0x0000000000000054)
+0x000000e5: 05 DW_LNS_set_column (23)
+0x000000e7: 06 DW_LNS_negate_stmt
+0x000000e8: 01 DW_LNS_copy
+            0x0000000000000054     17     23      1   0             0 
+
+
+0x000000e9: 00 DW_LNE_set_address (0x0000000000000059)
+0x000000f0: 05 DW_LNS_set_column (29)
+0x000000f2: 01 DW_LNS_copy
+            0x0000000000000059     17     29      1   0             0 
+
+
+0x000000f3: 00 DW_LNE_set_address (0x000000000000005a)
+0x000000fa: 03 DW_LNS_advance_line (18)
+0x000000fc: 05 DW_LNS_set_column (18)
+0x000000fe: 06 DW_LNS_negate_stmt
+0x000000ff: 01 DW_LNS_copy
+            0x000000000000005a     18     18      1   0             0  is_stmt
+
+
+0x00000100: 00 DW_LNE_set_address (0x0000000000000062)
+0x00000107: 05 DW_LNS_set_column (23)
+0x00000109: 06 DW_LNS_negate_stmt
+0x0000010a: 01 DW_LNS_copy
+            0x0000000000000062     18     23      1   0             0 
+
+
+0x0000010b: 00 DW_LNE_set_address (0x0000000000000063)
+0x00000112: 03 DW_LNS_advance_line (30)
+0x00000114: 05 DW_LNS_set_column (28)
+0x00000116: 06 DW_LNS_negate_stmt
+0x00000117: 01 DW_LNS_copy
+            0x0000000000000063     30     28      1   0             0  is_stmt
+
+
+0x00000118: 00 DW_LNE_set_address (0x0000000000000066)
+0x0000011f: 05 DW_LNS_set_column (5)
+0x00000121: 06 DW_LNS_negate_stmt
+0x00000122: 01 DW_LNS_copy
+            0x0000000000000066     30      5      1   0             0 
+
+
+0x00000123: 00 DW_LNE_set_address (0x000000000000006b)
+0x0000012a: 03 DW_LNS_advance_line (18)
+0x0000012c: 05 DW_LNS_set_column (18)
+0x0000012e: 06 DW_LNS_negate_stmt
+0x0000012f: 01 DW_LNS_copy
+            0x000000000000006b     18     18      1   0             0  is_stmt
+
+
+0x00000130: 00 DW_LNE_set_address (0x0000000000000073)
+0x00000137: 05 DW_LNS_set_column (23)
+0x00000139: 06 DW_LNS_negate_stmt
+0x0000013a: 01 DW_LNS_copy
+            0x0000000000000073     18     23      1   0             0 
+
+
+0x0000013b: 00 DW_LNE_set_address (0x0000000000000074)
+0x00000142: 03 DW_LNS_advance_line (30)
+0x00000144: 05 DW_LNS_set_column (24)
+0x00000146: 06 DW_LNS_negate_stmt
+0x00000147: 01 DW_LNS_copy
+            0x0000000000000074     30     24      1   0             0  is_stmt
+
+
+0x00000148: 00 DW_LNE_set_address (0x0000000000000077)
+0x0000014f: 05 DW_LNS_set_column (5)
+0x00000151: 06 DW_LNS_negate_stmt
+0x00000152: 01 DW_LNS_copy
+            0x0000000000000077     30      5      1   0             0 
+
+
+0x00000153: 00 DW_LNE_set_address (0x0000000000000085)
+0x0000015a: 03 DW_LNS_advance_line (31)
+0x0000015c: 05 DW_LNS_set_column (9)
+0x0000015e: 06 DW_LNS_negate_stmt
+0x0000015f: 01 DW_LNS_copy
+            0x0000000000000085     31      9      1   0             0  is_stmt
+
+
+0x00000160: 00 DW_LNE_set_address (0x0000000000000087)
+0x00000167: 05 DW_LNS_set_column (12)
+0x00000169: 06 DW_LNS_negate_stmt
+0x0000016a: 01 DW_LNS_copy
+            0x0000000000000087     31     12      1   0             0 
+
+
+0x0000016b: 00 DW_LNE_set_address (0x000000000000008c)
+0x00000172: 05 DW_LNS_set_column (9)
+0x00000174: 01 DW_LNS_copy
+            0x000000000000008c     31      9      1   0             0 
+
+
+0x00000175: 00 DW_LNE_set_address (0x000000000000008f)
+0x0000017c: 03 DW_LNS_advance_line (27)
+0x0000017e: 05 DW_LNS_set_column (29)
+0x00000180: 06 DW_LNS_negate_stmt
+0x00000181: 01 DW_LNS_copy
+            0x000000000000008f     27     29      1   0             0  is_stmt
+
+
+0x00000182: 00 DW_LNE_set_address (0x0000000000000099)
+0x00000189: 05 DW_LNS_set_column (21)
+0x0000018b: 06 DW_LNS_negate_stmt
+0x0000018c: 01 DW_LNS_copy
+            0x0000000000000099     27     21      1   0             0 
+
+
+0x0000018d: 00 DW_LNE_set_address (0x000000000000009a)
+0x00000194: 05 DW_LNS_set_column (3)
+0x00000196: 01 DW_LNS_copy
+            0x000000000000009a     27      3      1   0             0 
+
+
+0x00000197: 00 DW_LNE_set_address (0x000000000000009d)
+0x0000019e: 03 DW_LNS_advance_line (33)
+0x000001a0: 06 DW_LNS_negate_stmt
+0x000001a1: 01 DW_LNS_copy
+            0x000000000000009d     33      3      1   0             0  is_stmt
+
+
+0x000001a2: 00 DW_LNE_set_address (0x00000000000000ac)
+0x000001a9: 03 DW_LNS_advance_line (34)
+0x000001ab: 01 DW_LNS_copy
+            0x00000000000000ac     34      3      1   0             0  is_stmt
+
+
+0x000001ac: 00 DW_LNE_set_address (0x00000000000000b6)
+0x000001b3: 00 DW_LNE_end_sequence
+            0x00000000000000b6     34      3      1   0             0  is_stmt end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 11.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project d6fe253653b7e760f94ca21d0a7ebbfeeee28777)"
+0x00000095: "/tmp/emscripten_test_wasm3_2u9tontv/src.cpp"
+0x000000c1: "/tmp/emscripten_test_wasm3_2u9tontv"
+0x000000e5: "rng1"
+0x000000ea: "last"
+0x000000ef: "unsigned int"
+0x000000fc: "Random"
+0x00000103: "_ZN6Random3getEf"
+0x00000114: "get"
+0x00000118: "float"
+0x0000011e: "IM"
+0x00000121: "IA"
+0x00000124: "IC"
+0x00000127: "std"
+0x0000012b: "decltype(nullptr)"
+0x0000013d: "nullptr_t"
+0x00000147: "this"
+0x0000014c: "max"
+0x00000150: "main"
+0x00000155: "int"
+0x00000159: "rng2"
+0x0000015e: "count"
+0x00000164: "i"
+0x00000166: "x2"
+0x00000169: "x1"
+
+.debug_ranges contents:
+00000000 00000000 00000001
+00000000 00000065 0000006e
+00000000 <End of list>
diff --git a/binaryen/test/passes/class_with_dwarf_noprint.passes b/binaryen/test/passes/class_with_dwarf_noprint.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/class_with_dwarf_noprint.passes
@@ -0,0 +1,1 @@
+roundtrip_dwarfdump_g
diff --git a/binaryen/test/passes/class_with_dwarf_noprint.wasm b/binaryen/test/passes/class_with_dwarf_noprint.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/class_with_dwarf_noprint.wasm differ
diff --git a/binaryen/test/passes/coalesce-locals-learning.txt b/binaryen/test/passes/coalesce-locals-learning.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/coalesce-locals-learning.txt
@@ -0,0 +1,868 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_f32_=>_none (func (param i32 f32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (import "env" "_emscripten_autodebug_i32" (func $_emscripten_autodebug_i32 (param i32 i32) (result i32)))
+ (memory $0 10)
+ (func $nothing-to-do
+  (local $0 i32)
+  (nop)
+ )
+ (func $merge
+  (local $0 i32)
+  (nop)
+ )
+ (func $leave-type
+  (local $0 i32)
+  (local $1 f32)
+  (nop)
+ )
+ (func $leave-interfere
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (local.set $1
+   (i32.const 0)
+  )
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $almost-interfere
+  (local $0 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (drop
+   (local.get $0)
+  )
+  (local.set $0
+   (i32.const 0)
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $redundant-copy
+  (local $0 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (nop)
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $ineffective-store
+  (local $0 i32)
+  (drop
+   (i32.const 0)
+  )
+  (local.set $0
+   (i32.const 0)
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $block
+  (local $0 i32)
+  (block $block0
+   (local.set $0
+    (i32.const 0)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $see-both-sides
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (block $block0
+   (local.set $1
+    (i32.const 0)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $see-br-and-ignore-dead
+  (local $0 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (block $block
+   (br $block)
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const -1)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $see-block-body
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (block $block
+   (local.set $1
+    (i32.const 0)
+   )
+   (drop
+    (local.get $1)
+   )
+   (br $block)
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $zero-init
+  (local $0 i32)
+  (local $1 i32)
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $multi
+  (local $0 i32)
+  (local $1 i32)
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $if-else
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.const 0)
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+  )
+ )
+ (func $if-else-parallel
+  (local $0 i32)
+  (if
+   (i32.const 0)
+   (block $block1
+    (local.set $0
+     (i32.const 0)
+    )
+    (drop
+     (local.get $0)
+    )
+   )
+   (block $block3
+    (local.set $0
+     (i32.const 1)
+    )
+    (drop
+     (local.get $0)
+    )
+   )
+  )
+ )
+ (func $if-else-after
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.const 0)
+   (local.set $0
+    (i32.const 0)
+   )
+   (local.set $1
+    (i32.const 1)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $if-else-through
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (local.set $1
+   (i32.const 1)
+  )
+  (if
+   (i32.const 0)
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 2)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $if-through
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (local.set $1
+   (i32.const 1)
+  )
+  (if
+   (i32.const 0)
+   (drop
+    (i32.const 1)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $if-through2
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (if
+   (i32.const 0)
+   (local.set $1
+    (i32.const 1)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $if-through3
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (if
+   (i32.const 0)
+   (block $block1
+    (drop
+     (local.get $0)
+    )
+    (drop
+     (local.get $1)
+    )
+   )
+  )
+ )
+ (func $if2
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (local.tee $0
+    (i32.const 0)
+   )
+   (block $block1
+    (drop
+     (local.get $0)
+    )
+    (drop
+     (local.get $1)
+    )
+   )
+  )
+ )
+ (func $if3
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.const 0)
+   (block $block1
+    (local.set $0
+     (i32.const 0)
+    )
+    (drop
+     (local.get $0)
+    )
+   )
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $if4
+  (local $0 i32)
+  (if
+   (i32.const 0)
+   (block $block1
+    (local.set $0
+     (i32.const 0)
+    )
+    (drop
+     (local.get $0)
+    )
+    (local.set $0
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $if5
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.const 0)
+   (block $block1
+    (drop
+     (local.get $0)
+    )
+    (local.set $1
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $loop
+  (local $0 i32)
+  (local $1 i32)
+  (block $out
+   (loop $in
+    (drop
+     (local.get $0)
+    )
+    (local.set $0
+     (i32.const 0)
+    )
+    (drop
+     (local.get $1)
+    )
+    (br $in)
+   )
+  )
+ )
+ (func $interfere-in-dead
+  (local $0 i32)
+  (block $block
+   (br $block)
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 0)
+   )
+  )
+ )
+ (func $interfere-in-dead2
+  (local $0 i32)
+  (block $block
+   (unreachable)
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 0)
+   )
+  )
+ )
+ (func $interfere-in-dead3
+  (local $0 i32)
+  (block $block
+   (return)
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 0)
+   )
+  )
+ )
+ (func $params (param $0 i32) (param $1 f32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (drop
+   (local.get $2)
+  )
+  (drop
+   (local.get $3)
+  )
+  (drop
+   (local.get $4)
+  )
+ )
+ (func $interfere-in-dead4
+  (local $0 i32)
+  (local $1 i32)
+  (block $block
+   (br_if $block
+    (i32.const 0)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+  )
+ )
+ (func $switch
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block $switch$def
+   (block $switch-case$1
+    (block $switch-case$2
+     (br_table $switch-case$1 $switch-case$2 $switch-case$1 $switch-case$1 $switch$def
+      (i32.const 100)
+     )
+     (drop
+      (i32.const 0)
+     )
+    )
+    (drop
+     (local.get $0)
+    )
+   )
+   (drop
+    (local.get $1)
+   )
+  )
+  (drop
+   (local.get $2)
+  )
+ )
+ (func $greedy-can-be-happy
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.const 0)
+   (if
+    (i32.const 1)
+    (if
+     (i32.const 2)
+     (block $block3
+      (local.set $0
+       (i32.const 100)
+      )
+      (local.set $1
+       (i32.const 101)
+      )
+      (drop
+       (local.get $0)
+      )
+      (drop
+       (local.get $1)
+      )
+     )
+     (block $block5
+      (local.set $0
+       (i32.const 102)
+      )
+      (local.set $1
+       (i32.const 103)
+      )
+      (drop
+       (local.get $0)
+      )
+      (drop
+       (local.get $1)
+      )
+     )
+    )
+    (if
+     (i32.const 3)
+     (block $block8
+      (local.set $0
+       (i32.const 104)
+      )
+      (local.set $1
+       (i32.const 105)
+      )
+      (drop
+       (local.get $0)
+      )
+      (drop
+       (local.get $1)
+      )
+     )
+     (block $block10
+      (local.set $0
+       (i32.const 106)
+      )
+      (local.set $1
+       (i32.const 107)
+      )
+      (drop
+       (local.get $0)
+      )
+      (drop
+       (local.get $1)
+      )
+     )
+    )
+   )
+   (if
+    (i32.const 4)
+    (block $block13
+     (local.set $0
+      (i32.const 108)
+     )
+     (local.set $1
+      (i32.const 109)
+     )
+     (drop
+      (local.get $0)
+     )
+     (drop
+      (local.get $1)
+     )
+    )
+    (block $block15
+     (local.set $0
+      (i32.const 110)
+     )
+     (local.set $1
+      (i32.const 111)
+     )
+     (drop
+      (local.get $0)
+     )
+     (drop
+      (local.get $1)
+     )
+    )
+   )
+  )
+ )
+ (func $greedy-can-be-sad
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.const 0)
+   (if
+    (i32.const 1)
+    (if
+     (i32.const 2)
+     (block $block3
+      (local.set $0
+       (i32.const 100)
+      )
+      (local.set $1
+       (i32.const 101)
+      )
+      (drop
+       (local.get $0)
+      )
+      (drop
+       (local.get $1)
+      )
+     )
+     (block $block5
+      (local.set $0
+       (i32.const 102)
+      )
+      (local.set $1
+       (i32.const 103)
+      )
+      (drop
+       (local.get $0)
+      )
+      (drop
+       (local.get $1)
+      )
+     )
+    )
+    (if
+     (i32.const 3)
+     (block $block8
+      (local.set $0
+       (i32.const 104)
+      )
+      (local.set $1
+       (i32.const 105)
+      )
+      (drop
+       (local.get $0)
+      )
+      (drop
+       (local.get $1)
+      )
+     )
+     (block $block10
+      (local.set $0
+       (i32.const 106)
+      )
+      (local.set $1
+       (i32.const 107)
+      )
+      (drop
+       (local.get $0)
+      )
+      (drop
+       (local.get $1)
+      )
+     )
+    )
+   )
+   (if
+    (i32.const 4)
+    (block $block13
+     (local.set $0
+      (i32.const 108)
+     )
+     (local.set $1
+      (i32.const 109)
+     )
+     (drop
+      (local.get $0)
+     )
+     (drop
+      (local.get $1)
+     )
+    )
+    (block $block15
+     (local.set $0
+      (i32.const 110)
+     )
+     (local.set $1
+      (i32.const 111)
+     )
+     (drop
+      (local.get $0)
+     )
+     (drop
+      (local.get $1)
+     )
+    )
+   )
+  )
+ )
+ (func $_memcpy (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (if
+   (i32.ge_s
+    (local.get $2)
+    (i32.const 4096)
+   )
+   (drop
+    (local.get $0)
+   )
+  )
+  (local.set $3
+   (local.get $0)
+  )
+  (if
+   (i32.eq
+    (i32.and
+     (local.get $0)
+     (i32.const 3)
+    )
+    (i32.and
+     (local.get $1)
+     (i32.const 3)
+    )
+   )
+   (block $block2
+    (block $while-out$0
+     (loop $while-in$1
+      (if
+       (i32.eqz
+        (i32.and
+         (local.get $0)
+         (i32.const 3)
+        )
+       )
+       (br $while-out$0)
+      )
+      (block $block4
+       (if
+        (i32.eqz
+         (local.get $2)
+        )
+        (return
+         (local.get $3)
+        )
+       )
+       (i32.store8
+        (local.get $0)
+        (i32.load8_s
+         (local.get $1)
+        )
+       )
+       (local.set $0
+        (i32.add
+         (local.get $0)
+         (i32.const 1)
+        )
+       )
+       (local.set $1
+        (i32.add
+         (local.get $1)
+         (i32.const 1)
+        )
+       )
+       (local.set $2
+        (i32.sub
+         (local.get $2)
+         (i32.const 1)
+        )
+       )
+      )
+      (br $while-in$1)
+     )
+    )
+    (block $while-out$2
+     (loop $while-in$3
+      (if
+       (i32.eqz
+        (i32.ge_s
+         (local.get $2)
+         (i32.const 4)
+        )
+       )
+       (br $while-out$2)
+      )
+      (block $block7
+       (i32.store
+        (local.get $0)
+        (i32.load
+         (local.get $1)
+        )
+       )
+       (local.set $0
+        (i32.add
+         (local.get $0)
+         (i32.const 4)
+        )
+       )
+       (local.set $1
+        (i32.add
+         (local.get $1)
+         (i32.const 4)
+        )
+       )
+       (local.set $2
+        (i32.sub
+         (local.get $2)
+         (i32.const 4)
+        )
+       )
+      )
+      (br $while-in$3)
+     )
+    )
+   )
+  )
+  (block $while-out$4
+   (loop $while-in$5
+    (if
+     (i32.eqz
+      (i32.gt_s
+       (local.get $2)
+       (i32.const 0)
+      )
+     )
+     (br $while-out$4)
+    )
+    (block $block9
+     (i32.store8
+      (local.get $0)
+      (i32.load8_s
+       (local.get $1)
+      )
+     )
+     (local.set $0
+      (i32.add
+       (local.get $0)
+       (i32.const 1)
+      )
+     )
+     (local.set $1
+      (i32.add
+       (local.get $1)
+       (i32.const 1)
+      )
+     )
+     (local.set $2
+      (i32.sub
+       (local.get $2)
+       (i32.const 1)
+      )
+     )
+    )
+    (br $while-in$5)
+   )
+  )
+  (return
+   (local.get $3)
+  )
+ )
+ (func $this-is-effective-i-tell-you (param $0 i32)
+  (if
+   (i32.const -1)
+   (block $block1
+    (if
+     (i32.const 0)
+     (nop)
+    )
+    (local.set $0
+     (i32.const 1)
+    )
+   )
+   (nop)
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/coalesce-locals-learning.wast b/binaryen/test/passes/coalesce-locals-learning.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/coalesce-locals-learning.wast
@@ -0,0 +1,890 @@
+(module
+  (memory 10)
+  (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32)))
+  (type $FUNCSIG$iii (func (param i32 i32) (result i32)))
+  (type $2 (func))
+  (type $3 (func (param i32 f32)))
+  (type $4 (func (param i32)))
+  (import $_emscripten_autodebug_i32 "env" "_emscripten_autodebug_i32" (param i32 i32) (result i32))
+  (func $nothing-to-do (type $2)
+    (local $x i32)
+    (nop)
+  )
+  (func $merge (type $2)
+    (local $x i32)
+    (local $y i32)
+    (nop)
+  )
+  (func $leave-type (type $2)
+    (local $x i32)
+    (local $y f32)
+    (nop)
+  )
+  (func $leave-interfere (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (local.set $y
+      (i32.const 0)
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $almost-interfere (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (drop
+      (local.get $x)
+    )
+    (local.set $y
+      (i32.const 0)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $redundant-copy (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (local.set $y
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $ineffective-store (type $2)
+    (local $x i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (local.set $x
+      (i32.const 0)
+    )
+    (drop
+      (local.get $x)
+    )
+  )
+  (func $block (type $2)
+    (local $x i32)
+    (block $block0
+      (local.set $x
+        (i32.const 0)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+  )
+  (func $see-both-sides (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (block $block0
+      (local.set $y
+        (i32.const 0)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $see-br-and-ignore-dead (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (block $block
+      (br $block)
+      (local.set $y
+        (i32.const 0)
+      )
+      (drop
+        (local.get $y)
+      )
+      (local.set $x
+        (i32.const -1)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+  )
+  (func $see-block-body (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (block $block
+      (local.set $y
+        (i32.const 0)
+      )
+      (drop
+        (local.get $y)
+      )
+      (br $block)
+    )
+    (drop
+      (local.get $x)
+    )
+  )
+  (func $zero-init (type $2)
+    (local $x i32)
+    (local $y i32)
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $multi (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (drop
+      (local.get $y)
+    )
+    (drop
+      (local.get $z)
+    )
+  )
+  (func $if-else (type $2)
+    (local $x i32)
+    (local $y i32)
+    (if
+      (i32.const 0)
+      (drop
+        (local.get $x)
+      )
+      (drop
+        (local.get $y)
+      )
+    )
+  )
+  (func $if-else-parallel (type $2)
+    (local $x i32)
+    (local $y i32)
+    (if
+      (i32.const 0)
+      (block $block1
+        (local.set $x
+          (i32.const 0)
+        )
+        (drop
+          (local.get $x)
+        )
+      )
+      (block $block3
+        (local.set $y
+          (i32.const 1)
+        )
+        (drop
+          (local.get $y)
+        )
+      )
+    )
+  )
+  (func $if-else-after (type $2)
+    (local $x i32)
+    (local $y i32)
+    (if
+      (i32.const 0)
+      (local.set $x
+        (i32.const 0)
+      )
+      (local.set $y
+        (i32.const 1)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $if-else-through (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (local.set $y
+      (i32.const 1)
+    )
+    (if
+      (i32.const 0)
+      (drop
+        (i32.const 1)
+      )
+      (drop
+        (i32.const 2)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $if-through (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (local.set $y
+      (i32.const 1)
+    )
+    (if
+      (i32.const 0)
+      (drop
+        (i32.const 1)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $if-through2 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (if
+      (i32.const 0)
+      (local.set $y
+        (i32.const 1)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $if-through3 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (if
+      (i32.const 0)
+      (block $block1
+        (drop
+          (local.get $x)
+        )
+        (drop
+          (local.get $y)
+        )
+      )
+    )
+  )
+  (func $if2 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (if
+      (local.tee $x
+        (i32.const 0)
+      )
+      (block $block1
+        (drop
+          (local.get $x)
+        )
+        (drop
+          (local.get $y)
+        )
+      )
+    )
+  )
+  (func $if3 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (if
+      (i32.const 0)
+      (block $block1
+        (local.set $x
+          (i32.const 0)
+        )
+        (drop
+          (local.get $x)
+        )
+      )
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $if4 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (if
+      (i32.const 0)
+      (block $block1
+        (local.set $x
+          (i32.const 0)
+        )
+        (drop
+          (local.get $x)
+        )
+        (local.set $y
+          (i32.const 1)
+        )
+      )
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $if5 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (if
+      (i32.const 0)
+      (block $block1
+        (drop
+          (local.get $x)
+        )
+        (local.set $y
+          (i32.const 1)
+        )
+      )
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $loop (type $2)
+    (local $x i32)
+    (local $y i32)
+    (block $out
+      (loop $in
+        (drop
+          (local.get $x)
+        )
+        (local.set $x
+          (i32.const 0)
+        )
+        (drop
+          (local.get $y)
+        )
+        (br $in)
+      )
+    )
+  )
+  (func $interfere-in-dead (type $2)
+    (local $x i32)
+    (local $y i32)
+    (block $block
+      (br $block)
+      (drop
+        (local.get $x)
+      )
+      (drop
+        (local.get $y)
+      )
+    )
+  )
+  (func $interfere-in-dead2 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (block $block
+      (unreachable)
+      (drop
+        (local.get $x)
+      )
+      (drop
+        (local.get $y)
+      )
+    )
+  )
+  (func $interfere-in-dead3 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (block $block
+      (return)
+      (drop
+        (local.get $x)
+      )
+      (drop
+        (local.get $y)
+      )
+    )
+  )
+  (func $params (type $3) (param $p i32) (param $q f32)
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local $w i32)
+    (drop
+      (local.get $y)
+    )
+    (drop
+      (local.get $z)
+    )
+    (drop
+      (local.get $w)
+    )
+  )
+  (func $interfere-in-dead4 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (block $block
+      (br_if $block
+        (i32.const 0)
+      )
+      (drop
+        (local.get $x)
+      )
+      (drop
+        (local.get $y)
+      )
+    )
+  )
+  (func $switch (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local $w i32)
+    (block $switch$def
+      (block $switch-case$1
+        (block $switch-case$2
+          (br_table $switch-case$1 $switch-case$2 $switch-case$1 $switch-case$1 $switch$def
+            (i32.const 100)
+          )
+          (drop
+            (local.get $x)
+          )
+        )
+        (drop
+          (local.get $y)
+        )
+      )
+      (drop
+        (local.get $z)
+      )
+    )
+    (drop
+      (local.get $w)
+    )
+  )
+  (func $greedy-can-be-happy (type $2)
+    (local $x1 i32)
+    (local $x2 i32)
+    (local $x3 i32)
+    (local $y1 i32)
+    (local $y2 i32)
+    (local $y3 i32)
+    (if
+      (i32.const 0)
+      (if
+        (i32.const 1)
+        (if
+          (i32.const 2)
+          (block $block3
+            (local.set $x1
+              (i32.const 100)
+            )
+            (local.set $y2
+              (i32.const 101)
+            )
+            (drop
+              (local.get $x1)
+            )
+            (drop
+              (local.get $y2)
+            )
+          )
+          (block $block5
+            (local.set $x1
+              (i32.const 102)
+            )
+            (local.set $y3
+              (i32.const 103)
+            )
+            (drop
+              (local.get $x1)
+            )
+            (drop
+              (local.get $y3)
+            )
+          )
+        )
+        (if
+          (i32.const 3)
+          (block $block8
+            (local.set $x2
+              (i32.const 104)
+            )
+            (local.set $y1
+              (i32.const 105)
+            )
+            (drop
+              (local.get $x2)
+            )
+            (drop
+              (local.get $y1)
+            )
+          )
+          (block $block10
+            (local.set $x2
+              (i32.const 106)
+            )
+            (local.set $y3
+              (i32.const 107)
+            )
+            (drop
+              (local.get $x2)
+            )
+            (drop
+              (local.get $y3)
+            )
+          )
+        )
+      )
+      (if
+        (i32.const 4)
+        (block $block13
+          (local.set $x3
+            (i32.const 108)
+          )
+          (local.set $y1
+            (i32.const 109)
+          )
+          (drop
+            (local.get $x3)
+          )
+          (drop
+            (local.get $y1)
+          )
+        )
+        (block $block15
+          (local.set $x3
+            (i32.const 110)
+          )
+          (local.set $y2
+            (i32.const 111)
+          )
+          (drop
+            (local.get $x3)
+          )
+          (drop
+            (local.get $y2)
+          )
+        )
+      )
+    )
+  )
+  (func $greedy-can-be-sad (type $2)
+    (local $x1 i32)
+    (local $y1 i32)
+    (local $x2 i32)
+    (local $y2 i32)
+    (local $x3 i32)
+    (local $y3 i32)
+    (if
+      (i32.const 0)
+      (if
+        (i32.const 1)
+        (if
+          (i32.const 2)
+          (block $block3
+            (local.set $x1
+              (i32.const 100)
+            )
+            (local.set $y2
+              (i32.const 101)
+            )
+            (drop
+              (local.get $x1)
+            )
+            (drop
+              (local.get $y2)
+            )
+          )
+          (block $block5
+            (local.set $x1
+              (i32.const 102)
+            )
+            (local.set $y3
+              (i32.const 103)
+            )
+            (drop
+              (local.get $x1)
+            )
+            (drop
+              (local.get $y3)
+            )
+          )
+        )
+        (if
+          (i32.const 3)
+          (block $block8
+            (local.set $x2
+              (i32.const 104)
+            )
+            (local.set $y1
+              (i32.const 105)
+            )
+            (drop
+              (local.get $x2)
+            )
+            (drop
+              (local.get $y1)
+            )
+          )
+          (block $block10
+            (local.set $x2
+              (i32.const 106)
+            )
+            (local.set $y3
+              (i32.const 107)
+            )
+            (drop
+              (local.get $x2)
+            )
+            (drop
+              (local.get $y3)
+            )
+          )
+        )
+      )
+      (if
+        (i32.const 4)
+        (block $block13
+          (local.set $x3
+            (i32.const 108)
+          )
+          (local.set $y1
+            (i32.const 109)
+          )
+          (drop
+            (local.get $x3)
+          )
+          (drop
+            (local.get $y1)
+          )
+        )
+        (block $block15
+          (local.set $x3
+            (i32.const 110)
+          )
+          (local.set $y2
+            (i32.const 111)
+          )
+          (drop
+            (local.get $x3)
+          )
+          (drop
+            (local.get $y2)
+          )
+        )
+      )
+    )
+  )
+  (func $_memcpy (type $FUNCSIG$iiii) (param $i1 i32) (param $i2 i32) (param $i3 i32) (result i32)
+    (local $i4 i32)
+    (if
+      (i32.ge_s
+        (local.get $i3)
+        (i32.const 4096)
+      )
+      (drop
+        (local.get $i1)
+      )
+    )
+    (local.set $i4
+      (local.get $i1)
+    )
+    (if
+      (i32.eq
+        (i32.and
+          (local.get $i1)
+          (i32.const 3)
+        )
+        (i32.and
+          (local.get $i2)
+          (i32.const 3)
+        )
+      )
+      (block $block2
+        (block $while-out$0
+          (loop $while-in$1
+            (if
+              (i32.eqz
+                (i32.and
+                  (local.get $i1)
+                  (i32.const 3)
+                )
+              )
+              (br $while-out$0)
+            )
+            (block $block4
+              (if
+                (i32.eqz
+                  (local.get $i3)
+                )
+                (return
+                  (local.get $i4)
+                )
+              )
+              (i32.store8
+                (local.get $i1)
+                (i32.load8_s
+                  (local.get $i2)
+                )
+              )
+              (local.set $i1
+                (i32.add
+                  (local.get $i1)
+                  (i32.const 1)
+                )
+              )
+              (local.set $i2
+                (i32.add
+                  (local.get $i2)
+                  (i32.const 1)
+                )
+              )
+              (local.set $i3
+                (i32.sub
+                  (local.get $i3)
+                  (i32.const 1)
+                )
+              )
+            )
+            (br $while-in$1)
+          )
+        )
+        (block $while-out$2
+          (loop $while-in$3
+            (if
+              (i32.eqz
+                (i32.ge_s
+                  (local.get $i3)
+                  (i32.const 4)
+                )
+              )
+              (br $while-out$2)
+            )
+            (block $block7
+              (i32.store
+                (local.get $i1)
+                (i32.load
+                  (local.get $i2)
+                )
+              )
+              (local.set $i1
+                (i32.add
+                  (local.get $i1)
+                  (i32.const 4)
+                )
+              )
+              (local.set $i2
+                (i32.add
+                  (local.get $i2)
+                  (i32.const 4)
+                )
+              )
+              (local.set $i3
+                (i32.sub
+                  (local.get $i3)
+                  (i32.const 4)
+                )
+              )
+            )
+            (br $while-in$3)
+          )
+        )
+      )
+    )
+    (block $while-out$4
+      (loop $while-in$5
+        (if
+          (i32.eqz
+            (i32.gt_s
+              (local.get $i3)
+              (i32.const 0)
+            )
+          )
+          (br $while-out$4)
+        )
+        (block $block9
+          (i32.store8
+            (local.get $i1)
+            (i32.load8_s
+              (local.get $i2)
+            )
+          )
+          (local.set $i1
+            (i32.add
+              (local.get $i1)
+              (i32.const 1)
+            )
+          )
+          (local.set $i2
+            (i32.add
+              (local.get $i2)
+              (i32.const 1)
+            )
+          )
+          (local.set $i3
+            (i32.sub
+              (local.get $i3)
+              (i32.const 1)
+            )
+          )
+        )
+        (br $while-in$5)
+      )
+    )
+    (return
+      (local.get $i4)
+    )
+  )
+  (func $this-is-effective-i-tell-you (type $4) (param $x i32)
+    (if
+      (i32.const -1)
+      (block $block1
+        (if
+          (i32.const 0)
+          (nop)
+        )
+        (local.set $x
+          (i32.const 1)
+        )
+      )
+      (nop)
+    )
+    (drop
+      (local.get $x)
+    )
+  )
+)
diff --git a/binaryen/test/passes/coalesce-locals.txt b/binaryen/test/passes/coalesce-locals.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/coalesce-locals.txt
@@ -0,0 +1,1270 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $f64_i32_=>_i64 (func (param f64 i32) (result i64)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_f32_=>_none (func (param i32 f32)))
+ (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 $none_=>_f64 (func (result f64)))
+ (import "env" "_emscripten_autodebug_i32" (func $_emscripten_autodebug_i32 (param i32 i32) (result i32)))
+ (import "env" "get" (func $get (result i32)))
+ (import "env" "set" (func $set (param i32)))
+ (memory $0 10)
+ (func $nothing-to-do
+  (local $0 i32)
+  (nop)
+ )
+ (func $merge
+  (local $0 i32)
+  (nop)
+ )
+ (func $leave-type
+  (local $0 i32)
+  (local $1 f32)
+  (nop)
+ )
+ (func $leave-interfere
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (local.set $1
+   (i32.const 0)
+  )
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $almost-interfere
+  (local $0 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (drop
+   (local.get $0)
+  )
+  (local.set $0
+   (i32.const 0)
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $redundant-copy
+  (local $0 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (nop)
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $ineffective-store
+  (local $0 i32)
+  (drop
+   (i32.const 0)
+  )
+  (local.set $0
+   (i32.const 0)
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $block
+  (local $0 i32)
+  (block $block0
+   (local.set $0
+    (i32.const 0)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $see-both-sides
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (block $block0
+   (local.set $1
+    (i32.const 0)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $see-br-and-ignore-dead
+  (local $0 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (block $block
+   (br $block)
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const -1)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $see-block-body
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (block $block
+   (local.set $1
+    (i32.const 0)
+   )
+   (drop
+    (local.get $1)
+   )
+   (br $block)
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $zero-init
+  (local $0 i32)
+  (local $1 i32)
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $multi
+  (local $0 i32)
+  (local $1 i32)
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $if-else
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.const 0)
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+  )
+ )
+ (func $if-else-parallel
+  (local $0 i32)
+  (if
+   (i32.const 0)
+   (block $block1
+    (local.set $0
+     (i32.const 0)
+    )
+    (drop
+     (local.get $0)
+    )
+   )
+   (block $block3
+    (local.set $0
+     (i32.const 1)
+    )
+    (drop
+     (local.get $0)
+    )
+   )
+  )
+ )
+ (func $if-else-after
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.const 0)
+   (local.set $0
+    (i32.const 0)
+   )
+   (local.set $1
+    (i32.const 1)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $if-else-through
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (local.set $1
+   (i32.const 1)
+  )
+  (if
+   (i32.const 0)
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 2)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $if-through
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (local.set $1
+   (i32.const 1)
+  )
+  (if
+   (i32.const 0)
+   (drop
+    (i32.const 1)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $if-through2
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (if
+   (i32.const 0)
+   (local.set $1
+    (i32.const 1)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $if-through3
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (if
+   (i32.const 0)
+   (block $block1
+    (drop
+     (local.get $0)
+    )
+    (drop
+     (local.get $1)
+    )
+   )
+  )
+ )
+ (func $if2
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (local.tee $0
+    (i32.const 0)
+   )
+   (block $block1
+    (drop
+     (local.get $0)
+    )
+    (drop
+     (local.get $1)
+    )
+   )
+  )
+ )
+ (func $if3
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.const 0)
+   (block $block1
+    (local.set $0
+     (i32.const 0)
+    )
+    (drop
+     (local.get $0)
+    )
+   )
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $if4
+  (local $0 i32)
+  (if
+   (i32.const 0)
+   (block $block1
+    (local.set $0
+     (i32.const 0)
+    )
+    (drop
+     (local.get $0)
+    )
+    (local.set $0
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $if5
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.const 0)
+   (block $block1
+    (drop
+     (local.get $0)
+    )
+    (local.set $1
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $loop
+  (local $0 i32)
+  (local $1 i32)
+  (loop $in
+   (drop
+    (local.get $0)
+   )
+   (local.set $0
+    (i32.const 0)
+   )
+   (drop
+    (local.get $1)
+   )
+   (br $in)
+  )
+ )
+ (func $interfere-in-dead
+  (local $0 i32)
+  (block $block
+   (br $block)
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 0)
+   )
+  )
+ )
+ (func $interfere-in-dead2
+  (local $0 i32)
+  (block $block
+   (unreachable)
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 0)
+   )
+  )
+ )
+ (func $interfere-in-dead3
+  (local $0 i32)
+  (block $block
+   (return)
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 0)
+   )
+  )
+ )
+ (func $params (param $0 i32) (param $1 f32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (drop
+   (local.get $2)
+  )
+  (drop
+   (local.get $3)
+  )
+  (drop
+   (local.get $4)
+  )
+ )
+ (func $interfere-in-dead4
+  (local $0 i32)
+  (local $1 i32)
+  (block $block
+   (br_if $block
+    (i32.const 0)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+  )
+ )
+ (func $switch
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block $switch$def
+   (block $switch-case$1
+    (block $switch-case$2
+     (br_table $switch-case$1 $switch-case$2 $switch-case$1 $switch-case$1 $switch$def
+      (i32.const 100)
+     )
+     (drop
+      (i32.const 0)
+     )
+    )
+    (drop
+     (local.get $0)
+    )
+   )
+   (drop
+    (local.get $1)
+   )
+  )
+  (drop
+   (local.get $2)
+  )
+ )
+ (func $greedy-can-be-happy
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.const 0)
+   (if
+    (i32.const 1)
+    (if
+     (i32.const 2)
+     (block $block3
+      (local.set $0
+       (i32.const 100)
+      )
+      (local.set $1
+       (i32.const 101)
+      )
+      (drop
+       (local.get $0)
+      )
+      (drop
+       (local.get $1)
+      )
+     )
+     (block $block5
+      (local.set $0
+       (i32.const 102)
+      )
+      (local.set $1
+       (i32.const 103)
+      )
+      (drop
+       (local.get $0)
+      )
+      (drop
+       (local.get $1)
+      )
+     )
+    )
+    (if
+     (i32.const 3)
+     (block $block8
+      (local.set $0
+       (i32.const 104)
+      )
+      (local.set $1
+       (i32.const 105)
+      )
+      (drop
+       (local.get $0)
+      )
+      (drop
+       (local.get $1)
+      )
+     )
+     (block $block10
+      (local.set $0
+       (i32.const 106)
+      )
+      (local.set $1
+       (i32.const 107)
+      )
+      (drop
+       (local.get $0)
+      )
+      (drop
+       (local.get $1)
+      )
+     )
+    )
+   )
+   (if
+    (i32.const 4)
+    (block $block13
+     (local.set $0
+      (i32.const 108)
+     )
+     (local.set $1
+      (i32.const 109)
+     )
+     (drop
+      (local.get $0)
+     )
+     (drop
+      (local.get $1)
+     )
+    )
+    (block $block15
+     (local.set $0
+      (i32.const 110)
+     )
+     (local.set $1
+      (i32.const 111)
+     )
+     (drop
+      (local.get $0)
+     )
+     (drop
+      (local.get $1)
+     )
+    )
+   )
+  )
+ )
+ (func $greedy-can-be-sad
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (if
+   (i32.const 0)
+   (if
+    (i32.const 1)
+    (if
+     (i32.const 2)
+     (block $block3
+      (local.set $0
+       (i32.const 100)
+      )
+      (local.set $1
+       (i32.const 101)
+      )
+      (drop
+       (local.get $0)
+      )
+      (drop
+       (local.get $1)
+      )
+     )
+     (block $block5
+      (local.set $0
+       (i32.const 102)
+      )
+      (local.set $2
+       (i32.const 103)
+      )
+      (drop
+       (local.get $0)
+      )
+      (drop
+       (local.get $2)
+      )
+     )
+    )
+    (if
+     (i32.const 3)
+     (block $block8
+      (local.set $1
+       (i32.const 104)
+      )
+      (local.set $0
+       (i32.const 105)
+      )
+      (drop
+       (local.get $1)
+      )
+      (drop
+       (local.get $0)
+      )
+     )
+     (block $block10
+      (local.set $1
+       (i32.const 106)
+      )
+      (local.set $2
+       (i32.const 107)
+      )
+      (drop
+       (local.get $1)
+      )
+      (drop
+       (local.get $2)
+      )
+     )
+    )
+   )
+   (if
+    (i32.const 4)
+    (block $block13
+     (local.set $2
+      (i32.const 108)
+     )
+     (local.set $0
+      (i32.const 109)
+     )
+     (drop
+      (local.get $2)
+     )
+     (drop
+      (local.get $0)
+     )
+    )
+    (block $block15
+     (local.set $2
+      (i32.const 110)
+     )
+     (local.set $1
+      (i32.const 111)
+     )
+     (drop
+      (local.get $2)
+     )
+     (drop
+      (local.get $1)
+     )
+    )
+   )
+  )
+ )
+ (func $_memcpy (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (if
+   (i32.ge_s
+    (local.get $2)
+    (i32.const 4096)
+   )
+   (drop
+    (local.get $0)
+   )
+  )
+  (local.set $3
+   (local.get $0)
+  )
+  (if
+   (i32.eq
+    (i32.and
+     (local.get $0)
+     (i32.const 3)
+    )
+    (i32.and
+     (local.get $1)
+     (i32.const 3)
+    )
+   )
+   (block $block2
+    (block $while-out$0
+     (loop $while-in$1
+      (if
+       (i32.eqz
+        (i32.and
+         (local.get $0)
+         (i32.const 3)
+        )
+       )
+       (br $while-out$0)
+      )
+      (block $block4
+       (if
+        (i32.eqz
+         (local.get $2)
+        )
+        (return
+         (local.get $3)
+        )
+       )
+       (i32.store8
+        (local.get $0)
+        (i32.load8_s
+         (local.get $1)
+        )
+       )
+       (local.set $0
+        (i32.add
+         (local.get $0)
+         (i32.const 1)
+        )
+       )
+       (local.set $1
+        (i32.add
+         (local.get $1)
+         (i32.const 1)
+        )
+       )
+       (local.set $2
+        (i32.sub
+         (local.get $2)
+         (i32.const 1)
+        )
+       )
+      )
+      (br $while-in$1)
+     )
+    )
+    (block $while-out$2
+     (loop $while-in$3
+      (if
+       (i32.eqz
+        (i32.ge_s
+         (local.get $2)
+         (i32.const 4)
+        )
+       )
+       (br $while-out$2)
+      )
+      (block $block7
+       (i32.store
+        (local.get $0)
+        (i32.load
+         (local.get $1)
+        )
+       )
+       (local.set $0
+        (i32.add
+         (local.get $0)
+         (i32.const 4)
+        )
+       )
+       (local.set $1
+        (i32.add
+         (local.get $1)
+         (i32.const 4)
+        )
+       )
+       (local.set $2
+        (i32.sub
+         (local.get $2)
+         (i32.const 4)
+        )
+       )
+      )
+      (br $while-in$3)
+     )
+    )
+   )
+  )
+  (block $while-out$4
+   (loop $while-in$5
+    (if
+     (i32.eqz
+      (i32.gt_s
+       (local.get $2)
+       (i32.const 0)
+      )
+     )
+     (br $while-out$4)
+    )
+    (block $block9
+     (i32.store8
+      (local.get $0)
+      (i32.load8_s
+       (local.get $1)
+      )
+     )
+     (local.set $0
+      (i32.add
+       (local.get $0)
+       (i32.const 1)
+      )
+     )
+     (local.set $1
+      (i32.add
+       (local.get $1)
+       (i32.const 1)
+      )
+     )
+     (local.set $2
+      (i32.sub
+       (local.get $2)
+       (i32.const 1)
+      )
+     )
+    )
+    (br $while-in$5)
+   )
+  )
+  (return
+   (local.get $3)
+  )
+ )
+ (func $this-is-effective-i-tell-you (param $0 i32)
+  (if
+   (i32.const -1)
+   (block $block1
+    (if
+     (i32.const 0)
+     (nop)
+    )
+    (local.set $0
+     (i32.const 1)
+    )
+   )
+   (nop)
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $prefer-remove-copies1
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (nop)
+  (local.set $1
+   (i32.const 1)
+  )
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $prefer-remove-copies2
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (nop)
+  (local.set $1
+   (i32.const 1)
+  )
+  (drop
+   (local.get $1)
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $in-unreachable
+  (local $0 i32)
+  (block $x
+   (return)
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 0)
+   )
+  )
+  (block $y
+   (unreachable)
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 0)
+   )
+  )
+  (block $z
+   (br $z)
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 0)
+   )
+  )
+  (block $z14
+   (br_table $z14 $z14
+    (i32.const 100)
+   )
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 0)
+   )
+  )
+ )
+ (func $nop-in-unreachable
+  (local $0 i32)
+  (block $block
+   (unreachable)
+   (i32.store
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $loop-backedge
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.const 2)
+  )
+  (block $out
+   (loop $while-in7
+    (local.set $1
+     (i32.const 0)
+    )
+    (call $set
+     (local.get $1)
+    )
+    (local.set $0
+     (i32.add
+      (local.get $0)
+      (i32.const 1)
+     )
+    )
+    (if
+     (call $get)
+     (local.set $1
+      (local.get $0)
+     )
+    )
+    (br_if $out
+     (local.get $1)
+    )
+    (local.set $0
+     (i32.const 100)
+    )
+    (nop)
+    (br $while-in7)
+   )
+  )
+ )
+ (func $if-copy1
+  (local $0 i32)
+  (local $1 i32)
+  (loop $top
+   (local.set $0
+    (if (result i32)
+     (i32.const 1)
+     (local.get $0)
+     (local.get $1)
+    )
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+   (br $top)
+  )
+ )
+ (func $if-copy2
+  (local $0 i32)
+  (local $1 i32)
+  (loop $top
+   (local.set $1
+    (if (result i32)
+     (i32.const 1)
+     (local.get $0)
+     (local.get $1)
+    )
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (br $top)
+  )
+ )
+ (func $if-copy3
+  (local $0 i32)
+  (local $1 i32)
+  (loop $top
+   (local.set $0
+    (if (result i32)
+     (i32.const 1)
+     (unreachable)
+     (local.get $0)
+    )
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+   (br $top)
+  )
+ )
+ (func $if-copy4
+  (local $0 i32)
+  (local $1 i32)
+  (loop $top
+   (local.set $1
+    (if (result i32)
+     (i32.const 1)
+     (unreachable)
+     (local.get $0)
+    )
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (br $top)
+  )
+ )
+ (func $if-copy-tee
+  (local $0 i32)
+  (local $1 i32)
+  (loop $top
+   (drop
+    (local.tee $0
+     (if (result i32)
+      (i32.const 1)
+      (local.get $0)
+      (i32.const 2)
+     )
+    )
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+   (br $top)
+  )
+ )
+ (func $tee_br (param $0 i32) (result i32)
+  (block $b
+   (return
+    (br $b)
+   )
+  )
+  (i32.const 1)
+ )
+ (func $unused-tee-with-child-if-no-else (param $0 i32)
+  (loop $label$0
+   (drop
+    (if
+     (br $label$0)
+     (nop)
+    )
+   )
+  )
+ )
+ (func $tee_if_with_unreachable_else (param $0 f64) (param $1 i32) (result i64)
+  (call $tee_if_with_unreachable_else
+   (local.tee $0
+    (if (result f64)
+     (local.get $1)
+     (local.get $0)
+     (unreachable)
+    )
+   )
+   (f64.lt
+    (f64.const -128)
+    (local.get $0)
+   )
+  )
+ )
+ (func $tee_if_with_unreachable_true (param $0 f64) (param $1 i32) (result i64)
+  (call $tee_if_with_unreachable_else
+   (local.tee $0
+    (if (result f64)
+     (local.get $1)
+     (unreachable)
+     (local.get $0)
+    )
+   )
+   (f64.lt
+    (f64.const -128)
+    (local.get $0)
+   )
+  )
+ )
+ (func $pick
+  (local $0 i32)
+  (nop)
+  (if
+   (i32.const 1)
+   (drop
+    (i32.const 1)
+   )
+  )
+  (nop)
+  (nop)
+ )
+ (func $pick-2
+  (local $0 i32)
+  (nop)
+  (if
+   (i32.const 1)
+   (drop
+    (i32.const 1)
+   )
+  )
+  (nop)
+  (nop)
+ )
+ (func $many
+  (local $0 i32)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (if
+   (i32.const 1)
+   (drop
+    (i32.const 1)
+   )
+  )
+  (nop)
+  (if
+   (i32.const 1)
+   (drop
+    (i32.const 1)
+   )
+  )
+  (nop)
+  (nop)
+  (nop)
+  (local.set $0
+   (i32.const 2)
+  )
+  (nop)
+  (if
+   (i32.const 1)
+   (drop
+    (i32.const 1)
+   )
+  )
+  (nop)
+  (nop)
+  (nop)
+  (drop
+   (i32.const 2)
+  )
+  (nop)
+ )
+ (func $loop-copies (param $0 i32) (param $1 i32)
+  (loop $loop
+   (local.set $0
+    (local.get $1)
+   )
+   (local.set $1
+    (local.get $0)
+   )
+   (br_if $loop
+    (local.get $0)
+   )
+  )
+ )
+ (func $proper-type (result f64)
+  (local $0 f64)
+  (local $1 i32)
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 1)
+    (local.get $1)
+   )
+  )
+  (local.get $0)
+ )
+ (func $reuse-param (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (local.tee $0
+    (i32.xor
+     (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)
+     )
+    )
+   )
+   (local.get $0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/coalesce-locals.wast b/binaryen/test/passes/coalesce-locals.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/coalesce-locals.wast
@@ -0,0 +1,1225 @@
+(module
+  (memory 10)
+  (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32)))
+  (type $FUNCSIG$iii (func (param i32 i32) (result i32)))
+  (type $2 (func))
+  (type $3 (func (param i32 f32)))
+  (type $4 (func (param i32)))
+  (import $_emscripten_autodebug_i32 "env" "_emscripten_autodebug_i32" (param i32 i32) (result i32))
+  (import $get "env" "get" (result i32))
+  (import $set "env" "set" (param i32))
+  (func $nothing-to-do (type $2)
+    (local $x i32)
+    (nop)
+  )
+  (func $merge (type $2)
+    (local $x i32)
+    (local $y i32)
+    (nop)
+  )
+  (func $leave-type (type $2)
+    (local $x i32)
+    (local $y f32)
+    (nop)
+  )
+  (func $leave-interfere (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (local.set $y
+      (i32.const 0)
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $almost-interfere (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (drop
+      (local.get $x)
+    )
+    (local.set $y
+      (i32.const 0)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $redundant-copy (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (local.set $y
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $ineffective-store (type $2)
+    (local $x i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (local.set $x
+      (i32.const 0)
+    )
+    (drop
+      (local.get $x)
+    )
+  )
+  (func $block (type $2)
+    (local $x i32)
+    (block $block0
+      (local.set $x
+        (i32.const 0)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+  )
+  (func $see-both-sides (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (block $block0
+      (local.set $y
+        (i32.const 0)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $see-br-and-ignore-dead (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (block $block
+      (br $block)
+      (local.set $y
+        (i32.const 0)
+      )
+      (drop
+        (local.get $y)
+      )
+      (local.set $x
+        (i32.const -1)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+  )
+  (func $see-block-body (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (block $block
+      (local.set $y
+        (i32.const 0)
+      )
+      (drop
+        (local.get $y)
+      )
+      (br $block)
+    )
+    (drop
+      (local.get $x)
+    )
+  )
+  (func $zero-init (type $2)
+    (local $x i32)
+    (local $y i32)
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $multi (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (drop
+      (local.get $y)
+    )
+    (drop
+      (local.get $z)
+    )
+  )
+  (func $if-else (type $2)
+    (local $x i32)
+    (local $y i32)
+    (if
+      (i32.const 0)
+      (drop
+        (local.get $x)
+      )
+      (drop
+        (local.get $y)
+      )
+    )
+  )
+  (func $if-else-parallel (type $2)
+    (local $x i32)
+    (local $y i32)
+    (if
+      (i32.const 0)
+      (block $block1
+        (local.set $x
+          (i32.const 0)
+        )
+        (drop
+          (local.get $x)
+        )
+      )
+      (block $block3
+        (local.set $y
+          (i32.const 1)
+        )
+        (drop
+          (local.get $y)
+        )
+      )
+    )
+  )
+  (func $if-else-after (type $2)
+    (local $x i32)
+    (local $y i32)
+    (if
+      (i32.const 0)
+      (local.set $x
+        (i32.const 0)
+      )
+      (local.set $y
+        (i32.const 1)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $if-else-through (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (local.set $y
+      (i32.const 1)
+    )
+    (if
+      (i32.const 0)
+      (drop
+        (i32.const 1)
+      )
+      (drop
+        (i32.const 2)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $if-through (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (local.set $y
+      (i32.const 1)
+    )
+    (if
+      (i32.const 0)
+      (drop
+        (i32.const 1)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $if-through2 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (if
+      (i32.const 0)
+      (local.set $y
+        (i32.const 1)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $if-through3 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (if
+      (i32.const 0)
+      (block $block1
+        (drop
+          (local.get $x)
+        )
+        (drop
+          (local.get $y)
+        )
+      )
+    )
+  )
+  (func $if2 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (if
+      (local.tee $x
+        (i32.const 0)
+      )
+      (block $block1
+        (drop
+          (local.get $x)
+        )
+        (drop
+          (local.get $y)
+        )
+      )
+    )
+  )
+  (func $if3 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (if
+      (i32.const 0)
+      (block $block1
+        (local.set $x
+          (i32.const 0)
+        )
+        (drop
+          (local.get $x)
+        )
+      )
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $if4 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (if
+      (i32.const 0)
+      (block $block1
+        (local.set $x
+          (i32.const 0)
+        )
+        (drop
+          (local.get $x)
+        )
+        (local.set $y
+          (i32.const 1)
+        )
+      )
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $if5 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (if
+      (i32.const 0)
+      (block $block1
+        (drop
+          (local.get $x)
+        )
+        (local.set $y
+          (i32.const 1)
+        )
+      )
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $loop (type $2)
+    (local $x i32)
+    (local $y i32)
+    (loop $in
+      (drop
+        (local.get $x)
+      )
+      (local.set $x
+        (i32.const 0)
+      )
+      (drop
+        (local.get $y)
+      )
+      (br $in)
+    )
+  )
+  (func $interfere-in-dead (type $2)
+    (local $x i32)
+    (local $y i32)
+    (block $block
+      (br $block)
+      (drop
+        (local.get $x)
+      )
+      (drop
+        (local.get $y)
+      )
+    )
+  )
+  (func $interfere-in-dead2 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (block $block
+      (unreachable)
+      (drop
+        (local.get $x)
+      )
+      (drop
+        (local.get $y)
+      )
+    )
+  )
+  (func $interfere-in-dead3 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (block $block
+      (return)
+      (drop
+        (local.get $x)
+      )
+      (drop
+        (local.get $y)
+      )
+    )
+  )
+  (func $params (type $3) (param $p i32) (param $q f32)
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local $w i32)
+    (drop
+      (local.get $y)
+    )
+    (drop
+      (local.get $z)
+    )
+    (drop
+      (local.get $w)
+    )
+  )
+  (func $interfere-in-dead4 (type $2)
+    (local $x i32)
+    (local $y i32)
+    (block $block
+      (br_if $block
+        (i32.const 0)
+      )
+      (drop
+        (local.get $x)
+      )
+      (drop
+        (local.get $y)
+      )
+    )
+  )
+  (func $switch (type $2)
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local $w i32)
+    (block $switch$def
+      (block $switch-case$1
+        (block $switch-case$2
+          (br_table $switch-case$1 $switch-case$2 $switch-case$1 $switch-case$1 $switch$def
+            (i32.const 100)
+          )
+          (drop
+            (local.get $x)
+          )
+        )
+        (drop
+          (local.get $y)
+        )
+      )
+      (drop
+        (local.get $z)
+      )
+    )
+    (drop
+      (local.get $w)
+    )
+  )
+  (func $greedy-can-be-happy (type $2)
+    (local $x1 i32)
+    (local $x2 i32)
+    (local $x3 i32)
+    (local $y1 i32)
+    (local $y2 i32)
+    (local $y3 i32)
+    (if
+      (i32.const 0)
+      (if
+        (i32.const 1)
+        (if
+          (i32.const 2)
+          (block $block3
+            (local.set $x1
+              (i32.const 100)
+            )
+            (local.set $y2
+              (i32.const 101)
+            )
+            (drop
+              (local.get $x1)
+            )
+            (drop
+              (local.get $y2)
+            )
+          )
+          (block $block5
+            (local.set $x1
+              (i32.const 102)
+            )
+            (local.set $y3
+              (i32.const 103)
+            )
+            (drop
+              (local.get $x1)
+            )
+            (drop
+              (local.get $y3)
+            )
+          )
+        )
+        (if
+          (i32.const 3)
+          (block $block8
+            (local.set $x2
+              (i32.const 104)
+            )
+            (local.set $y1
+              (i32.const 105)
+            )
+            (drop
+              (local.get $x2)
+            )
+            (drop
+              (local.get $y1)
+            )
+          )
+          (block $block10
+            (local.set $x2
+              (i32.const 106)
+            )
+            (local.set $y3
+              (i32.const 107)
+            )
+            (drop
+              (local.get $x2)
+            )
+            (drop
+              (local.get $y3)
+            )
+          )
+        )
+      )
+      (if
+        (i32.const 4)
+        (block $block13
+          (local.set $x3
+            (i32.const 108)
+          )
+          (local.set $y1
+            (i32.const 109)
+          )
+          (drop
+            (local.get $x3)
+          )
+          (drop
+            (local.get $y1)
+          )
+        )
+        (block $block15
+          (local.set $x3
+            (i32.const 110)
+          )
+          (local.set $y2
+            (i32.const 111)
+          )
+          (drop
+            (local.get $x3)
+          )
+          (drop
+            (local.get $y2)
+          )
+        )
+      )
+    )
+  )
+  (func $greedy-can-be-sad (type $2)
+    (local $x1 i32)
+    (local $y1 i32)
+    (local $x2 i32)
+    (local $y2 i32)
+    (local $x3 i32)
+    (local $y3 i32)
+    (if
+      (i32.const 0)
+      (if
+        (i32.const 1)
+        (if
+          (i32.const 2)
+          (block $block3
+            (local.set $x1
+              (i32.const 100)
+            )
+            (local.set $y2
+              (i32.const 101)
+            )
+            (drop
+              (local.get $x1)
+            )
+            (drop
+              (local.get $y2)
+            )
+          )
+          (block $block5
+            (local.set $x1
+              (i32.const 102)
+            )
+            (local.set $y3
+              (i32.const 103)
+            )
+            (drop
+              (local.get $x1)
+            )
+            (drop
+              (local.get $y3)
+            )
+          )
+        )
+        (if
+          (i32.const 3)
+          (block $block8
+            (local.set $x2
+              (i32.const 104)
+            )
+            (local.set $y1
+              (i32.const 105)
+            )
+            (drop
+              (local.get $x2)
+            )
+            (drop
+              (local.get $y1)
+            )
+          )
+          (block $block10
+            (local.set $x2
+              (i32.const 106)
+            )
+            (local.set $y3
+              (i32.const 107)
+            )
+            (drop
+              (local.get $x2)
+            )
+            (drop
+              (local.get $y3)
+            )
+          )
+        )
+      )
+      (if
+        (i32.const 4)
+        (block $block13
+          (local.set $x3
+            (i32.const 108)
+          )
+          (local.set $y1
+            (i32.const 109)
+          )
+          (drop
+            (local.get $x3)
+          )
+          (drop
+            (local.get $y1)
+          )
+        )
+        (block $block15
+          (local.set $x3
+            (i32.const 110)
+          )
+          (local.set $y2
+            (i32.const 111)
+          )
+          (drop
+            (local.get $x3)
+          )
+          (drop
+            (local.get $y2)
+          )
+        )
+      )
+    )
+  )
+  (func $_memcpy (type $FUNCSIG$iiii) (param $i1 i32) (param $i2 i32) (param $i3 i32) (result i32)
+    (local $i4 i32)
+    (if
+      (i32.ge_s
+        (local.get $i3)
+        (i32.const 4096)
+      )
+      (drop
+        (local.get $i1)
+      )
+    )
+    (local.set $i4
+      (local.get $i1)
+    )
+    (if
+      (i32.eq
+        (i32.and
+          (local.get $i1)
+          (i32.const 3)
+        )
+        (i32.and
+          (local.get $i2)
+          (i32.const 3)
+        )
+      )
+      (block $block2
+        (block $while-out$0
+          (loop $while-in$1
+            (if
+              (i32.eqz
+                (i32.and
+                  (local.get $i1)
+                  (i32.const 3)
+                )
+              )
+              (br $while-out$0)
+            )
+            (block $block4
+              (if
+                (i32.eqz
+                  (local.get $i3)
+                )
+                (return
+                  (local.get $i4)
+                )
+              )
+              (i32.store8
+                (local.get $i1)
+                (i32.load8_s
+                  (local.get $i2)
+                )
+              )
+              (local.set $i1
+                (i32.add
+                  (local.get $i1)
+                  (i32.const 1)
+                )
+              )
+              (local.set $i2
+                (i32.add
+                  (local.get $i2)
+                  (i32.const 1)
+                )
+              )
+              (local.set $i3
+                (i32.sub
+                  (local.get $i3)
+                  (i32.const 1)
+                )
+              )
+            )
+            (br $while-in$1)
+          )
+        )
+        (block $while-out$2
+          (loop $while-in$3
+            (if
+              (i32.eqz
+                (i32.ge_s
+                  (local.get $i3)
+                  (i32.const 4)
+                )
+              )
+              (br $while-out$2)
+            )
+            (block $block7
+              (i32.store
+                (local.get $i1)
+                (i32.load
+                  (local.get $i2)
+                )
+              )
+              (local.set $i1
+                (i32.add
+                  (local.get $i1)
+                  (i32.const 4)
+                )
+              )
+              (local.set $i2
+                (i32.add
+                  (local.get $i2)
+                  (i32.const 4)
+                )
+              )
+              (local.set $i3
+                (i32.sub
+                  (local.get $i3)
+                  (i32.const 4)
+                )
+              )
+            )
+            (br $while-in$3)
+          )
+        )
+      )
+    )
+    (block $while-out$4
+      (loop $while-in$5
+        (if
+          (i32.eqz
+            (i32.gt_s
+              (local.get $i3)
+              (i32.const 0)
+            )
+          )
+          (br $while-out$4)
+        )
+        (block $block9
+          (i32.store8
+            (local.get $i1)
+            (i32.load8_s
+              (local.get $i2)
+            )
+          )
+          (local.set $i1
+            (i32.add
+              (local.get $i1)
+              (i32.const 1)
+            )
+          )
+          (local.set $i2
+            (i32.add
+              (local.get $i2)
+              (i32.const 1)
+            )
+          )
+          (local.set $i3
+            (i32.sub
+              (local.get $i3)
+              (i32.const 1)
+            )
+          )
+        )
+        (br $while-in$5)
+      )
+    )
+    (return
+      (local.get $i4)
+    )
+  )
+  (func $this-is-effective-i-tell-you (type $4) (param $x i32)
+    (if
+      (i32.const -1)
+      (block $block1
+        (if
+          (i32.const 0)
+          (nop)
+        )
+        (local.set $x
+          (i32.const 1)
+        )
+      )
+      (nop)
+    )
+    (drop
+      (local.get $x)
+    )
+  )
+  (func $prefer-remove-copies1 (type $2)
+    (local $y i32)
+    (local $z i32)
+    (local $x i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (local.set $y
+      (local.get $x)
+    )
+    (local.set $z
+      (i32.const 1)
+    )
+    (drop
+      (local.get $y)
+    )
+    (drop
+      (local.get $z)
+    )
+  )
+  (func $prefer-remove-copies2 (type $2)
+    (local $y i32)
+    (local $z i32)
+    (local $x i32)
+    (local.set $x
+      (i32.const 0)
+    )
+    (local.set $z
+      (local.get $x)
+    )
+    (local.set $y
+      (i32.const 1)
+    )
+    (drop
+      (local.get $y)
+    )
+    (drop
+      (local.get $z)
+    )
+  )
+  (func $in-unreachable
+    (local $a i32)
+    (block $x
+      (return)
+      (local.set $a (i32.const 1))
+      (drop (local.get $a))
+      (local.set $a (local.get $a))
+    )
+    (block $y
+      (unreachable)
+      (local.set $a (i32.const 1))
+      (drop (local.get $a))
+      (local.set $a (local.get $a))
+    )
+    (block $z
+      (br $z)
+      (local.set $a (i32.const 1))
+      (drop (local.get $a))
+      (local.set $a (local.get $a))
+    )
+    (block $z
+      (br_table $z $z
+        (i32.const 100)
+      )
+      (local.set $a (i32.const 1))
+      (drop (local.get $a))
+      (local.set $a (local.get $a))
+    )
+  )
+  (func $nop-in-unreachable
+    (local $x i32)
+    (block
+      (unreachable)
+      (i32.store
+        (local.get $x)
+        (local.tee $x (i32.const 0))
+      )
+    )
+  )
+  (func $loop-backedge
+    (local $0 i32) ;; loop phi
+    (local $1 i32) ;; value for next loop iteration
+    (local $2 i32) ;; a local that might be merged with with $1, perhaps making us prefer it to removing a backedge copy
+    (local.set $0
+      (i32.const 2)
+    )
+    (block $out
+      (loop $while-in7
+        (local.set $2 (i32.const 0)) ;; 2 interferes with 0
+        (call $set (local.get $2))
+        (local.set $1
+          (i32.add
+            (local.get $0)
+            (i32.const 1)
+          )
+        )
+        (if (call $get)
+          (local.set $2 (local.get $1)) ;; copy for 1/2
+        )
+        (br_if $out (local.get $2))
+        (local.set $1 (i32.const 100))
+        (local.set $0 (local.get $1)) ;; copy for 1/0, with extra weight should win the tie
+        (br $while-in7)
+      )
+    )
+  )
+  (func $if-copy1
+    (local $x i32)
+    (local $y i32)
+    (loop $top
+      (local.set $x
+        (if (result i32)
+          (i32.const 1)
+          (local.get $x)
+          (local.get $y)
+        )
+      )
+      (drop (local.get $x))
+      (drop (local.get $y))
+      (br $top)
+    )
+  )
+  (func $if-copy2
+    (local $x i32)
+    (local $y i32)
+    (loop $top
+      (local.set $x
+        (if (result i32)
+          (i32.const 1)
+          (local.get $y)
+          (local.get $x)
+        )
+      )
+      (drop (local.get $x))
+      (drop (local.get $y))
+      (br $top)
+    )
+  )
+  (func $if-copy3
+    (local $x i32)
+    (local $y i32)
+    (loop $top
+      (local.set $x
+        (if (result i32)
+          (i32.const 1)
+          (unreachable)
+          (local.get $x)
+        )
+      )
+      (drop (local.get $x))
+      (drop (local.get $y))
+      (br $top)
+    )
+  )
+  (func $if-copy4
+    (local $x i32)
+    (local $y i32)
+    (loop $top
+      (local.set $x
+        (if (result i32)
+          (i32.const 1)
+          (unreachable)
+          (local.get $y)
+        )
+      )
+      (drop (local.get $x))
+      (drop (local.get $y))
+      (br $top)
+    )
+  )
+  (func $if-copy-tee
+    (local $x i32)
+    (local $y i32)
+    (loop $top
+      (drop
+        (local.tee $x
+          (if (result i32)
+            (i32.const 1)
+            (local.get $x)
+            (i32.const 2)
+          )
+        )
+      )
+      (drop (local.get $x))
+      (drop (local.get $y))
+      (br $top)
+    )
+  )
+  (func $tee_br (param $x i32) (result i32)
+    (block $b
+      (return
+        (local.tee $x
+          (br $b)
+        )
+      )
+    )
+    (i32.const 1)
+  )
+  (func $unused-tee-with-child-if-no-else (param $0 i32)
+   (loop $label$0
+    (drop
+     (local.tee $0
+      (if
+       (br $label$0)
+       (nop)
+      )
+     )
+    )
+   )
+  )
+  (func $tee_if_with_unreachable_else (param $0 f64) (param $1 i32) (result i64)
+    (call $tee_if_with_unreachable_else
+     (local.tee $0
+      (if (result f64)
+       (local.get $1)
+       (local.get $0)
+       (unreachable)
+      )
+     )
+     (f64.lt
+      (f64.const -128)
+      (local.get $0)
+     )
+    )
+  )
+  (func $tee_if_with_unreachable_true (param $0 f64) (param $1 i32) (result i64)
+    (call $tee_if_with_unreachable_else
+     (local.tee $0
+      (if (result f64)
+       (local.get $1)
+       (unreachable)
+       (local.get $0)
+      )
+     )
+     (f64.lt
+      (f64.const -128)
+      (local.get $0)
+     )
+    )
+  )
+  (func $pick
+   (local $x i32)
+   (local $y i32)
+   (local.set $x (local.get $y))
+   (if (i32.const 1)
+    (local.set $x (i32.const 1))
+   )
+   (local.set $x (local.get $y))
+   (local.set $x (local.get $y))
+  )
+  (func $pick-2
+   (local $x i32)
+   (local $y i32)
+   (local.set $y (local.get $x))
+   (if (i32.const 1)
+    (local.set $y (i32.const 1))
+   )
+   (local.set $y (local.get $x))
+   (local.set $y (local.get $x))
+  )
+  (func $many
+   (local $x i32)
+   (local $y i32)
+   (local $z i32)
+   (local $w i32)
+   (local.set $y (local.get $x))
+   (local.set $z (local.get $y))
+   (local.set $w (local.get $z))
+   (local.set $x (local.get $z))
+   (if (i32.const 1)
+    (local.set $y (i32.const 1))
+   )
+   (local.set $x (local.get $z))
+   (if (i32.const 1)
+    (local.set $y (i32.const 1))
+   )
+   (local.set $y (local.get $x))
+   (local.set $z (local.get $y))
+   (local.set $w (local.get $z))
+   (local.set $z (i32.const 2))
+   (local.set $x (local.get $z))
+   (if (i32.const 1)
+    (local.set $y (i32.const 1))
+   )
+   (local.set $y (local.get $x))
+   (local.set $z (local.get $y))
+   (local.set $w (local.get $z))
+   (local.set $z (i32.const 2))
+   (local.set $x (local.get $w))
+  )
+  (func $loop-copies (param $x i32) (param $y i32)
+   (loop $loop
+    (local.set $x (local.get $y))
+    (local.set $y (local.get $x))
+    (br_if $loop (local.get $x))
+   )
+  )
+  (func $proper-type (result f64)
+   (local $var$0 i32)
+   (local $var$2 f64)
+   (local.set $var$0
+    (select
+     (i32.const 0)
+     (i32.const 1)
+     (local.get $var$0)
+    )
+   )
+   (local.tee $var$2 ;; the locals will be reordered, this should be the f64
+    (local.get $var$2)
+   )
+  )
+  (func $reuse-param (param $x i32) (param $y i32) (result i32)
+   (local $temp i32)
+   (i32.add
+    (local.tee $temp
+     (i32.xor
+      (i32.shr_s
+       (i32.shl
+        (local.get $x) ;; $x and $temp do not interfere
+        (i32.const 16)
+       )
+      (i32.const 16)
+     )
+     (i32.shr_s
+      (i32.shl
+        (local.get $y)
+        (i32.const 16)
+       )
+       (i32.const 16)
+      )
+     )
+    )
+    (local.get $temp)
+   )
+  )
+)
diff --git a/binaryen/test/passes/code-folding_enable-threads.txt b/binaryen/test/passes/code-folding_enable-threads.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/code-folding_enable-threads.txt
@@ -0,0 +1,206 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_f32 (func (result f32)))
+ (type $f32_=>_none (func (param f32)))
+ (memory $0 1 1)
+ (table $0 282 282 funcref)
+ (func $0
+  (block $label$1
+   (if
+    (i32.const 1)
+    (block
+     (block $label$3
+      (call_indirect (type $f32_=>_none)
+       (block $label$4
+        (br $label$3)
+       )
+       (i32.const 105)
+      )
+     )
+     (nop)
+    )
+   )
+  )
+ )
+ (func $negative-zero (result f32)
+  (if (result f32)
+   (i32.const 0)
+   (block $label$0 (result f32)
+    (f32.const 0)
+   )
+   (block $label$1 (result f32)
+    (f32.const -0)
+   )
+  )
+ )
+ (func $negative-zero-b (result f32)
+  (drop
+   (i32.const 0)
+  )
+  (block $label$0 (result f32)
+   (f32.const -0)
+  )
+ )
+ (func $negative-zero-c (result f32)
+  (drop
+   (i32.const 0)
+  )
+  (block $label$0 (result f32)
+   (f32.const 0)
+  )
+ )
+ (func $break-target-outside-of-return-merged-code
+  (block $label$A
+   (if
+    (unreachable)
+    (block $block
+     (block $block0
+      (block $label$B
+       (if
+        (unreachable)
+        (br_table $label$A $label$B
+         (unreachable)
+        )
+       )
+      )
+      (return)
+     )
+    )
+    (block $block2
+     (block $label$C
+      (if
+       (unreachable)
+       (br_table $label$A $label$C
+        (unreachable)
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+ )
+ (func $break-target-inside-all-good
+  (block $folding-inner0
+   (block $label$A
+    (if
+     (unreachable)
+     (block $block
+      (block $block4
+       (br $folding-inner0)
+      )
+     )
+     (block $block6
+      (br $folding-inner0)
+     )
+    )
+   )
+  )
+  (block $label$B
+   (if
+    (unreachable)
+    (br_table $label$B $label$B
+     (unreachable)
+    )
+   )
+  )
+  (return)
+ )
+ (func $leave-inner-block-type
+  (block $label$1
+   (drop
+    (block $label$2
+     (block
+      (unreachable)
+      (unreachable)
+     )
+     (br $label$1)
+    )
+   )
+  )
+  (drop
+   (i32.const 1)
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 (shared 1 1))
+ (export "func_2224" (func $0))
+ (func $0 (result i32)
+  (local $var$0 i32)
+  (if (result i32)
+   (i32.const 0)
+   (i32.load offset=22
+    (local.get $var$0)
+   )
+   (i32.atomic.load offset=22
+    (local.get $var$0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (global $global$0 (mut i32) (i32.const 10))
+ (func $determinism
+  (block $folding-inner0
+   (block
+    (block $label$1
+     (br_if $label$1
+      (i32.const 1)
+     )
+     (br $folding-inner0)
+    )
+    (block $label$2
+     (br_if $label$2
+      (i32.const 0)
+     )
+     (if
+      (global.get $global$0)
+      (block $block
+       (br $folding-inner0)
+      )
+     )
+     (unreachable)
+    )
+    (if
+     (global.get $global$0)
+     (block $block1
+      (br $folding-inner0)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (global.set $global$0
+   (i32.sub
+    (global.get $global$0)
+    (i32.const 1)
+   )
+  )
+  (unreachable)
+ )
+ (func $careful-of-the-switch (param $0 i32)
+  (block $label$1
+   (block $label$3
+    (block $label$5
+     (block $label$7
+      (br_table $label$3 $label$7
+       (i32.const 0)
+      )
+     )
+     (br $label$1)
+    )
+    (block $label$8
+     (br_table $label$3 $label$8
+      (i32.const 0)
+     )
+    )
+    (br $label$1)
+   )
+   (unreachable)
+  )
+ )
+)
diff --git a/binaryen/test/passes/code-folding_enable-threads.wast b/binaryen/test/passes/code-folding_enable-threads.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/code-folding_enable-threads.wast
@@ -0,0 +1,223 @@
+(module
+ (type $13 (func (param f32)))
+ (table 282 282 funcref)
+ (memory $0 1 1)
+ (func $0
+  (block $label$1
+   (if
+    (i32.const 1)
+    (block $label$3
+     (call_indirect (type $13)
+      (block $label$4 (result f32) ;; but this type may change dangerously
+       (nop) ;; fold this
+       (br $label$3)
+      )
+      (i32.const 105)
+     )
+     (nop) ;; with this
+    )
+   )
+  )
+ )
+ (func $negative-zero (result f32)
+  (if (result f32)
+   (i32.const 0)
+   (block $label$0 (result f32)
+    (f32.const 0)
+   )
+   (block $label$1 (result f32)
+    (f32.const -0)
+   )
+  )
+ )
+ (func $negative-zero-b (result f32)
+  (if (result f32)
+   (i32.const 0)
+   (block $label$0 (result f32)
+    (f32.const -0)
+   )
+   (block $label$1 (result f32)
+    (f32.const -0)
+   )
+  )
+ )
+ (func $negative-zero-c (result f32)
+  (if (result f32)
+   (i32.const 0)
+   (block $label$0 (result f32)
+    (f32.const 0)
+   )
+   (block $label$1 (result f32)
+    (f32.const 0)
+   )
+  )
+ )
+ (func $break-target-outside-of-return-merged-code
+  (block $label$A
+   (if
+    (unreachable)
+    (block
+     (block
+      (block $label$B
+       (if
+        (unreachable)
+        (br_table $label$A $label$B
+         (unreachable)
+        )
+       )
+      )
+      (return)
+     )
+    )
+    (block
+     (block $label$C
+      (if
+       (unreachable)
+       (br_table $label$A $label$C ;; this all looks mergeable, but $label$A is outside
+        (unreachable)
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+ )
+ (func $break-target-inside-all-good
+  (block $label$A
+   (if
+    (unreachable)
+    (block
+     (block
+      (block $label$B
+       (if
+        (unreachable)
+        (br_table $label$B $label$B
+         (unreachable)
+        )
+       )
+      )
+      (return)
+     )
+    )
+    (block
+     (block $label$C
+      (if
+       (unreachable)
+       (br_table $label$C $label$C ;; this all looks mergeable, and is, B ~~ C
+        (unreachable)
+       )
+      )
+     )
+     (return)
+    )
+   )
+  )
+ )
+ (func $leave-inner-block-type
+  (block $label$1
+   (drop
+    (block $label$2 (result i32) ;; leave this alone (otherwise, if we make it unreachable, we need to do more updating)
+     (br_if $label$2
+      (unreachable)
+      (unreachable)
+     )
+     (drop
+      (i32.const 1)
+     )
+     (br $label$1)
+    )
+   )
+   (drop
+    (i32.const 1)
+   )
+  )
+ )
+)
+(module
+ (memory $0 (shared 1 1))
+ (export "func_2224" (func $0))
+ (func $0 (result i32)
+  (local $var$0 i32)
+  (if (result i32)
+   (i32.const 0)
+   (i32.load offset=22
+    (local.get $var$0)
+   )
+   (i32.atomic.load offset=22
+    (local.get $var$0)
+   )
+  )
+ )
+)
+(module
+ (type $0 (func))
+ (global $global$0 (mut i32) (i32.const 10))
+ (func $determinism (; 0 ;) (type $0)
+  (block $label$1
+   (br_if $label$1
+    (i32.const 1)
+   )
+   (global.set $global$0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 1)
+    )
+   )
+   (unreachable)
+  )
+  (block $label$2
+   (br_if $label$2
+    (i32.const 0)
+   )
+   (if
+    (global.get $global$0)
+    (block
+     (global.set $global$0
+      (i32.sub
+       (global.get $global$0)
+       (i32.const 1)
+      )
+     )
+     (unreachable)
+    )
+   )
+   (unreachable)
+  )
+  (if
+   (global.get $global$0)
+   (block
+    (global.set $global$0
+     (i32.sub
+      (global.get $global$0)
+      (i32.const 1)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (unreachable)
+ )
+ (func $careful-of-the-switch (param $0 i32)
+  (block $label$1
+    (block $label$3
+      (block $label$5
+       (block $label$7 ;;  this is block is equal to $label$8 when accounting for the internal 7/8 difference
+        (br_table $label$3 $label$7 ;; the reference to $label$3 must remain valid, cannot hoist out of it!
+         (i32.const 0)
+        )
+       )
+       (br $label$1)
+      )
+      (block $label$8
+       (br_table $label$3 $label$8
+        (i32.const 0)
+       )
+      )
+      (br $label$1)
+    )
+    (unreachable)
+  )
+ )
+)
+
diff --git a/binaryen/test/passes/code-pushing_all-features.txt b/binaryen/test/passes/code-pushing_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/code-pushing_all-features.txt
@@ -0,0 +1,118 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (event $e (attr 0) (param i32))
+ (func $cant-push-past-call
+  (local $x i32)
+  (block $out
+   (local.set $x
+    (i32.const 1)
+   )
+   (call $cant-push-past-call)
+   (drop
+    (i32.const 1)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $cant-push-past-throw
+  (local $x i32)
+  (block $out
+   (local.set $x
+    (i32.const 1)
+   )
+   (throw $e
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 1)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $can-push-past-throw-within-try
+  (local $x i32)
+  (block $out
+   (try
+    (do
+     (throw $e
+      (i32.const 0)
+     )
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+    )
+   )
+   (drop
+    (i32.const 1)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (local.set $x
+    (i32.const 1)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $cant-push-past-rethrow-within-catch
+  (local $x i32)
+  (block $out
+   (local.set $x
+    (i32.const 1)
+   )
+   (try
+    (do
+     (throw $e
+      (i32.const 0)
+     )
+    )
+    (catch
+     (rethrow
+      (pop exnref)
+     )
+    )
+   )
+   (drop
+    (i32.const 1)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $push-past-br-on-exn
+  (local $x i32)
+  (local $y exnref)
+  (drop
+   (block $out (result i32)
+    (drop
+     (br_on_exn $out $e
+      (local.get $y)
+     )
+    )
+    (local.set $x
+     (i32.const 1)
+    )
+    (local.get $x)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/code-pushing_all-features.wast b/binaryen/test/passes/code-pushing_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/code-pushing_all-features.wast
@@ -0,0 +1,81 @@
+(module
+  (event $e (attr 0) (param i32))
+
+  (func $cant-push-past-call
+    (local $x i32)
+    (block $out
+      ;; This local.set cannot be pushed down, because the call below can throw
+      (local.set $x (i32.const 1))
+      (call $cant-push-past-call)
+      (drop (i32.const 1))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+    )
+  )
+
+  (func $cant-push-past-throw
+    (local $x i32)
+    (block $out
+      ;; This local.set cannot be pushed down, because there is 'throw' below
+      (local.set $x (i32.const 1))
+      (throw $e (i32.const 0))
+      (drop (i32.const 1))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+    )
+  )
+
+  (func $can-push-past-throw-within-try
+    (local $x i32)
+    (block $out
+      ;; This local.set can be pushed down, because the 'throw' below is going
+      ;; to be caught by the inner catch
+      (local.set $x (i32.const 1))
+      (try
+        (do
+          (throw $e (i32.const 0))
+        )
+        (catch
+          (drop (pop exnref))
+        )
+      )
+      (drop (i32.const 1))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+    )
+  )
+
+  (func $cant-push-past-rethrow-within-catch
+    (local $x i32)
+    (block $out
+      ;; This local.set cannot be pushed down, because there is 'rethrow' within
+      ;; the inner catch
+      (local.set $x (i32.const 1))
+      (try
+        (do
+          (throw $e (i32.const 0))
+        )
+        (catch
+          (rethrow (pop exnref))
+        )
+      )
+      (drop (i32.const 1))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+    )
+  )
+
+  (func $push-past-br-on-exn
+    (local $x i32)
+    (local $y exnref)
+    (drop
+      (block $out (result i32)
+        (local.set $x (i32.const 1))
+        (drop
+          (br_on_exn $out $e (local.get $y))
+        )
+        (local.get $x)
+      )
+    )
+  )
+)
diff --git a/binaryen/test/passes/code-pushing_ignore-implicit-traps.txt b/binaryen/test/passes/code-pushing_ignore-implicit-traps.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/code-pushing_ignore-implicit-traps.txt
@@ -0,0 +1,460 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 1)
+ (func $push1
+  (local $x i32)
+  (block $out
+   (br_if $out
+    (i32.const 2)
+   )
+   (local.set $x
+    (i32.const 1)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $push2
+  (local $x i32)
+  (local $y i32)
+  (block $out
+   (br_if $out
+    (i32.const 2)
+   )
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 3)
+   )
+   (drop
+    (local.get $x)
+   )
+   (drop
+    (local.get $y)
+   )
+  )
+ )
+ (func $push1-twice
+  (local $x i32)
+  (block $out
+   (br_if $out
+    (i32.const 2)
+   )
+   (br_if $out
+    (i32.const 3)
+   )
+   (local.set $x
+    (i32.const 1)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $push1-twiceb
+  (local $x i32)
+  (block $out
+   (br_if $out
+    (i32.const 2)
+   )
+   (nop)
+   (br_if $out
+    (i32.const 3)
+   )
+   (local.set $x
+    (i32.const 1)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $push2-twice
+  (local $x i32)
+  (local $y i32)
+  (block $out
+   (br_if $out
+    (i32.const 2)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 3)
+   )
+   (drop
+    (local.get $x)
+   )
+   (drop
+    (local.get $y)
+   )
+  )
+ )
+ (func $ignore-last
+  (local $x i32)
+  (block $out
+   (local.set $x
+    (i32.const 1)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+  )
+ )
+ (func $ignore-last2
+  (local $x i32)
+  (block $out
+   (local.set $x
+    (i32.const 1)
+   )
+   (nop)
+   (nop)
+   (br_if $out
+    (i32.const 2)
+   )
+  )
+ )
+ (func $push-if
+  (local $x i32)
+  (block $out
+   (if
+    (i32.const 2)
+    (nop)
+   )
+   (local.set $x
+    (i32.const 1)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $push-dropped (result i32)
+  (local $x i32)
+  (block $out (result i32)
+   (drop
+    (br_if $out
+     (i32.const 2)
+     (i32.const 3)
+    )
+   )
+   (local.set $x
+    (i32.const 1)
+   )
+   (drop
+    (local.get $x)
+   )
+   (i32.const 4)
+  )
+ )
+ (func $push-past-stuff
+  (local $x i32)
+  (block $out
+   (call $push-past-stuff)
+   (drop
+    (i32.const 1)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (local.set $x
+    (i32.const 1)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $fail-then-push
+  (local $x i32)
+  (local $y i32)
+  (block $out
+   (local.set $x
+    (i32.const 1)
+   )
+   (drop
+    (local.get $x)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (br_if $out
+    (i32.const 3)
+   )
+   (local.set $y
+    (i32.const 1)
+   )
+   (drop
+    (local.get $x)
+   )
+   (drop
+    (local.get $y)
+   )
+  )
+ )
+ (func $used
+  (local $x i32)
+  (block $out
+   (local.set $x
+    (i32.const 1)
+   )
+   (br_if $out
+    (local.get $x)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $not-sfa
+  (local $x i32)
+  (local.set $x
+   (i32.const 1)
+  )
+  (block $out
+   (local.set $x
+    (i32.const 1)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $not-sfa2
+  (local $x i32)
+  (drop
+   (local.get $x)
+  )
+  (block $out
+   (local.set $x
+    (i32.const 1)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $used-out
+  (local $x i32)
+  (block $out
+   (local.set $x
+    (i32.const 1)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $value-might-interfere
+  (local $x i32)
+  (block $out
+   (br_if $out
+    (i32.const 2)
+   )
+   (local.set $x
+    (i32.load
+     (i32.const 0)
+    )
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $value-interferes
+  (local $x i32)
+  (block $out
+   (local.set $x
+    (i32.load
+     (i32.const 0)
+    )
+   )
+   (i32.store
+    (i32.const 1)
+    (i32.const 3)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $value-interferes-accumulation
+  (local $x i32)
+  (block $out
+   (local.set $x
+    (i32.load
+     (i32.const 0)
+    )
+   )
+   (nop)
+   (i32.store
+    (i32.const 1)
+    (i32.const 3)
+   )
+   (nop)
+   (br_if $out
+    (i32.const 2)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $value-interferes-in-pushpoint
+  (local $x i32)
+  (block $out
+   (local.set $x
+    (i32.load
+     (i32.const 0)
+    )
+   )
+   (if
+    (i32.const 1)
+    (call $value-interferes)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $values-might-interfere
+  (local $x i32)
+  (local $y i32)
+  (block $out
+   (local.set $x
+    (call $push-dropped)
+   )
+   (local.set $y
+    (call $push-dropped)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (drop
+    (local.get $x)
+   )
+   (drop
+    (local.get $y)
+   )
+  )
+ )
+ (func $unpushed-interferes
+  (local $x i32)
+  (local $y i32)
+  (block $out
+   (local.set $x
+    (call $push-dropped)
+   )
+   (local.set $y
+    (call $push-dropped)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (drop
+    (local.get $x)
+   )
+   (drop
+    (local.get $y)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+ )
+ (func $unpushed-ignorable
+  (local $x i32)
+  (local $y i32)
+  (block $out
+   (local.set $x
+    (i32.const 1)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (local.set $y
+    (i32.const 3)
+   )
+   (drop
+    (local.get $x)
+   )
+   (drop
+    (local.get $y)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $unpushed-ignorable-side-effect
+  (local $x i32)
+  (local $y i32)
+  (block $out
+   (local.set $x
+    (call $push-dropped)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (local.set $y
+    (i32.const 3)
+   )
+   (drop
+    (local.get $x)
+   )
+   (drop
+    (local.get $y)
+   )
+  )
+ )
+ (func $unpushed-side-effect-into-drop
+  (local $x i32)
+  (block $out
+   (local.set $x
+    (call $push-dropped)
+   )
+   (br_if $out
+    (i32.const 1)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $unpushed-side-effect-into-if
+  (local $x i32)
+  (block $out
+   (local.set $x
+    (call $push-dropped)
+   )
+   (br_if $out
+    (i32.const 1)
+   )
+   (if
+    (local.get $x)
+    (nop)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/code-pushing_ignore-implicit-traps.wast b/binaryen/test/passes/code-pushing_ignore-implicit-traps.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/code-pushing_ignore-implicit-traps.wast
@@ -0,0 +1,249 @@
+(module
+  (memory 1)
+  (func $push1
+    (local $x i32)
+    (block $out
+      (local.set $x (i32.const 1))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+    )
+  )
+  (func $push2
+    (local $x i32)
+    (local $y i32)
+    (block $out
+      (local.set $x (i32.const 1))
+      (local.set $y (i32.const 3))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+      (drop (local.get $y))
+    )
+  )
+  (func $push1-twice
+    (local $x i32)
+    (block $out
+      (local.set $x (i32.const 1))
+      (br_if $out (i32.const 2))
+      (br_if $out (i32.const 3))
+      (drop (local.get $x))
+    )
+  )
+  (func $push1-twiceb
+    (local $x i32)
+    (block $out
+      (local.set $x (i32.const 1))
+      (br_if $out (i32.const 2))
+      (nop)
+      (br_if $out (i32.const 3))
+      (drop (local.get $x))
+    )
+  )
+  (func $push2-twice
+    (local $x i32)
+    (local $y i32)
+    (block $out
+      (local.set $x (i32.const 1))
+      (local.set $y (i32.const 3))
+      (br_if $out (i32.const 2))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+      (drop (local.get $y))
+    )
+  )
+  (func $ignore-last
+    (local $x i32)
+    (block $out
+      (local.set $x (i32.const 1))
+      (br_if $out (i32.const 2))
+    )
+  )
+  (func $ignore-last2
+    (local $x i32)
+    (block $out
+      (local.set $x (i32.const 1))
+      (nop)
+      (nop)
+      (br_if $out (i32.const 2))
+    )
+  )
+  (func $push-if
+    (local $x i32)
+    (block $out
+      (local.set $x (i32.const 1))
+      (if (i32.const 2) (nop))
+      (drop (local.get $x))
+    )
+  )
+  (func $push-dropped (result i32)
+    (local $x i32)
+    (block $out (result i32)
+      (local.set $x (i32.const 1))
+      (drop (br_if $out (i32.const 2) (i32.const 3)))
+      (drop (local.get $x))
+      (i32.const 4)
+    )
+  )
+  (func $push-past-stuff
+    (local $x i32)
+    (block $out
+      (local.set $x (i32.const 1))
+      (call $push-past-stuff)
+      (drop (i32.const 1))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+    )
+  )
+  (func $fail-then-push
+    (local $x i32)
+    (local $y i32)
+    (block $out
+      (local.set $x (i32.const 1))
+      (drop (local.get $x))
+      (br_if $out (i32.const 2))
+      (local.set $y (i32.const 1))
+      (br_if $out (i32.const 3))
+      (drop (local.get $x))
+      (drop (local.get $y))
+    )
+  )
+  ;; and now for stuff that should *not* be pushed
+  (func $used
+    (local $x i32)
+    (block $out
+      (local.set $x (i32.const 1))
+      (br_if $out (local.get $x))
+      (drop (local.get $x))
+    )
+  )
+  (func $not-sfa
+    (local $x i32)
+    (local.set $x (i32.const 1))
+    (block $out
+      (local.set $x (i32.const 1))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+    )
+  )
+  (func $not-sfa2
+    (local $x i32)
+    (drop (local.get $x))
+    (block $out
+      (local.set $x (i32.const 1))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+    )
+  )
+  (func $used-out
+    (local $x i32)
+    (block $out
+      (local.set $x (i32.const 1))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+    )
+    (drop (local.get $x))
+  )
+  (func $value-might-interfere ;; but doesn't
+    (local $x i32)
+    (block $out
+      (local.set $x (i32.load (i32.const 0)))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+    )
+  )
+  (func $value-interferes
+    (local $x i32)
+    (block $out
+      (local.set $x (i32.load (i32.const 0)))
+      (i32.store (i32.const 1) (i32.const 3))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+    )
+  )
+  (func $value-interferes-accumulation
+    (local $x i32)
+    (block $out
+      (local.set $x (i32.load (i32.const 0)))
+      (nop)
+      (i32.store (i32.const 1) (i32.const 3))
+      (nop)
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+    )
+  )
+  (func $value-interferes-in-pushpoint
+    (local $x i32)
+    (block $out
+      (local.set $x (i32.load (i32.const 0)))
+      (if (i32.const 1)
+        (call $value-interferes)
+      )
+      (drop (local.get $x))
+    )
+  )
+  (func $values-might-interfere ;; they don't, as we keep the order - but here their side effects prevent pushing
+    (local $x i32)
+    (local $y i32)
+    (block $out
+      (local.set $x (call $push-dropped))
+      (local.set $y (call $push-dropped))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+      (drop (local.get $y))
+    )
+  )
+  (func $unpushed-interferes
+    (local $x i32)
+    (local $y i32)
+    (block $out
+      (local.set $x (call $push-dropped))
+      (local.set $y (call $push-dropped))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+      (drop (local.get $y))
+    )
+    (drop (local.get $y)) ;; $y can't be pushed, so x can't be
+  )
+  (func $unpushed-ignorable
+    (local $x i32)
+    (local $y i32)
+    (block $out
+      (local.set $x (i32.const 1))
+      (local.set $y (i32.const 3))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+      (drop (local.get $y))
+    )
+    (drop (local.get $x)) ;; $x can't be pushed, but y doesn't care
+  )
+  (func $unpushed-ignorable-side-effect
+    (local $x i32)
+    (local $y i32)
+    (block $out
+      (local.set $x (call $push-dropped)) ;; $x can't be pushed, but y doesn't care
+      (local.set $y (i32.const 3))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+      (drop (local.get $y))
+    )
+  )
+  (func $unpushed-side-effect-into-drop
+    (local $x i32)
+    (block $out
+      (local.set $x (call $push-dropped))
+      (br_if $out (i32.const 1))
+      (drop (local.get $x))
+    )
+  )
+  (func $unpushed-side-effect-into-if
+    (local $x i32)
+    (block $out
+      (local.set $x (call $push-dropped))
+      (br_if $out (i32.const 1))
+      (if
+        (local.get $x)
+        (nop)
+      )
+    )
+  )
+)
+
diff --git a/binaryen/test/passes/const-hoisting.txt b/binaryen/test/passes/const-hoisting.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/const-hoisting.txt
@@ -0,0 +1,629 @@
+(module
+ (type $none_=>_none (func))
+ (func $10-of-each
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (block
+   (local.set $0
+    (i32.const -1048577)
+   )
+   (local.set $1
+    (i32.const -1048576)
+   )
+   (local.set $2
+    (i32.const -8193)
+   )
+   (local.set $3
+    (i32.const 8192)
+   )
+   (local.set $4
+    (i32.const 1048575)
+   )
+   (local.set $5
+    (i32.const 1048576)
+   )
+  )
+  (block
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 63)
+   )
+   (drop
+    (i32.const 64)
+   )
+   (drop
+    (i32.const 8191)
+   )
+   (drop
+    (local.get $3)
+   )
+   (drop
+    (local.get $4)
+   )
+   (drop
+    (local.get $5)
+   )
+   (drop
+    (i32.const -64)
+   )
+   (drop
+    (i32.const -65)
+   )
+   (drop
+    (i32.const -8192)
+   )
+   (drop
+    (local.get $2)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 63)
+   )
+   (drop
+    (i32.const 64)
+   )
+   (drop
+    (i32.const 8191)
+   )
+   (drop
+    (local.get $3)
+   )
+   (drop
+    (local.get $4)
+   )
+   (drop
+    (local.get $5)
+   )
+   (drop
+    (i32.const -64)
+   )
+   (drop
+    (i32.const -65)
+   )
+   (drop
+    (i32.const -8192)
+   )
+   (drop
+    (local.get $2)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 63)
+   )
+   (drop
+    (i32.const 64)
+   )
+   (drop
+    (i32.const 8191)
+   )
+   (drop
+    (local.get $3)
+   )
+   (drop
+    (local.get $4)
+   )
+   (drop
+    (local.get $5)
+   )
+   (drop
+    (i32.const -64)
+   )
+   (drop
+    (i32.const -65)
+   )
+   (drop
+    (i32.const -8192)
+   )
+   (drop
+    (local.get $2)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 63)
+   )
+   (drop
+    (i32.const 64)
+   )
+   (drop
+    (i32.const 8191)
+   )
+   (drop
+    (local.get $3)
+   )
+   (drop
+    (local.get $4)
+   )
+   (drop
+    (local.get $5)
+   )
+   (drop
+    (i32.const -64)
+   )
+   (drop
+    (i32.const -65)
+   )
+   (drop
+    (i32.const -8192)
+   )
+   (drop
+    (local.get $2)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 63)
+   )
+   (drop
+    (i32.const 64)
+   )
+   (drop
+    (i32.const 8191)
+   )
+   (drop
+    (local.get $3)
+   )
+   (drop
+    (local.get $4)
+   )
+   (drop
+    (local.get $5)
+   )
+   (drop
+    (i32.const -64)
+   )
+   (drop
+    (i32.const -65)
+   )
+   (drop
+    (i32.const -8192)
+   )
+   (drop
+    (local.get $2)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 63)
+   )
+   (drop
+    (i32.const 64)
+   )
+   (drop
+    (i32.const 8191)
+   )
+   (drop
+    (local.get $3)
+   )
+   (drop
+    (local.get $4)
+   )
+   (drop
+    (local.get $5)
+   )
+   (drop
+    (i32.const -64)
+   )
+   (drop
+    (i32.const -65)
+   )
+   (drop
+    (i32.const -8192)
+   )
+   (drop
+    (local.get $2)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 63)
+   )
+   (drop
+    (i32.const 64)
+   )
+   (drop
+    (i32.const 8191)
+   )
+   (drop
+    (local.get $3)
+   )
+   (drop
+    (local.get $4)
+   )
+   (drop
+    (local.get $5)
+   )
+   (drop
+    (i32.const -64)
+   )
+   (drop
+    (i32.const -65)
+   )
+   (drop
+    (i32.const -8192)
+   )
+   (drop
+    (local.get $2)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 63)
+   )
+   (drop
+    (i32.const 64)
+   )
+   (drop
+    (i32.const 8191)
+   )
+   (drop
+    (local.get $3)
+   )
+   (drop
+    (local.get $4)
+   )
+   (drop
+    (local.get $5)
+   )
+   (drop
+    (i32.const -64)
+   )
+   (drop
+    (i32.const -65)
+   )
+   (drop
+    (i32.const -8192)
+   )
+   (drop
+    (local.get $2)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 63)
+   )
+   (drop
+    (i32.const 64)
+   )
+   (drop
+    (i32.const 8191)
+   )
+   (drop
+    (local.get $3)
+   )
+   (drop
+    (local.get $4)
+   )
+   (drop
+    (local.get $5)
+   )
+   (drop
+    (i32.const -64)
+   )
+   (drop
+    (i32.const -65)
+   )
+   (drop
+    (i32.const -8192)
+   )
+   (drop
+    (local.get $2)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 63)
+   )
+   (drop
+    (i32.const 64)
+   )
+   (drop
+    (i32.const 8191)
+   )
+   (drop
+    (local.get $3)
+   )
+   (drop
+    (local.get $4)
+   )
+   (drop
+    (local.get $5)
+   )
+   (drop
+    (i32.const -64)
+   )
+   (drop
+    (i32.const -65)
+   )
+   (drop
+    (i32.const -8192)
+   )
+   (drop
+    (local.get $2)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+  )
+ )
+ (func $floats-10-times
+  (local $0 f32)
+  (local $1 f64)
+  (block
+   (local.set $0
+    (f32.const 0)
+   )
+   (local.set $1
+    (f64.const 0)
+   )
+  )
+  (block
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+  )
+ )
+ (func $too-few
+  (drop
+   (i32.const 8192)
+  )
+  (drop
+   (i32.const 8192)
+  )
+  (drop
+   (i32.const 8192)
+  )
+  (drop
+   (i32.const 8192)
+  )
+  (drop
+   (i32.const 8192)
+  )
+ )
+ (func $just-enough
+  (local $0 i32)
+  (block
+   (local.set $0
+    (i32.const 8192)
+   )
+  )
+  (block
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $0)
+   )
+  )
+ )
+ (func $too-few-b
+  (drop
+   (i32.const 1048576)
+  )
+  (drop
+   (i32.const 1048576)
+  )
+  (drop
+   (i32.const 1048576)
+  )
+ )
+ (func $enough-b
+  (local $0 i32)
+  (block
+   (local.set $0
+    (i32.const 1048576)
+   )
+  )
+  (block
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $0)
+   )
+  )
+ )
+ (func $too-few-c
+  (drop
+   (f32.const 0)
+  )
+  (drop
+   (f32.const 0)
+  )
+  (drop
+   (f32.const 0)
+  )
+ )
+ (func $enough-c
+  (local $0 f32)
+  (block
+   (local.set $0
+    (f32.const 0)
+   )
+  )
+  (block
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $0)
+   )
+  )
+ )
+ (func $too-few-d
+  (drop
+   (f64.const 0)
+  )
+ )
+ (func $enough-d
+  (local $0 f64)
+  (block
+   (local.set $0
+    (f64.const 0)
+   )
+  )
+  (block
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $0)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/const-hoisting.wast b/binaryen/test/passes/const-hoisting.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/const-hoisting.wast
@@ -0,0 +1,201 @@
+(module
+  (func $10-of-each
+    (drop (i32.const 0)) ;; 1 byte
+    (drop (i32.const 63)) ;; 1 byte
+    (drop (i32.const 64)) ;; 2 bytes
+    (drop (i32.const 8191)) ;; 2 bytes
+    (drop (i32.const 8192)) ;; 3 bytes
+    (drop (i32.const 1048575)) ;; 3 bytes
+    (drop (i32.const 1048576)) ;; 4 bytes
+    (drop (i32.const -64)) ;; 1 byte
+    (drop (i32.const -65)) ;; 2 bytes
+    (drop (i32.const -8192)) ;; 2 bytes
+    (drop (i32.const -8193)) ;; 3 bytes
+    (drop (i32.const -1048576)) ;; 3 bytes
+    (drop (i32.const -1048577)) ;; 4 bytes
+    (drop (i32.const 0)) ;; 1 byte
+    (drop (i32.const 63)) ;; 1 byte
+    (drop (i32.const 64)) ;; 2 bytes
+    (drop (i32.const 8191)) ;; 2 bytes
+    (drop (i32.const 8192)) ;; 3 bytes
+    (drop (i32.const 1048575)) ;; 3 bytes
+    (drop (i32.const 1048576)) ;; 4 bytes
+    (drop (i32.const -64)) ;; 1 byte
+    (drop (i32.const -65)) ;; 2 bytes
+    (drop (i32.const -8192)) ;; 2 bytes
+    (drop (i32.const -8193)) ;; 3 bytes
+    (drop (i32.const -1048576)) ;; 3 bytes
+    (drop (i32.const -1048577)) ;; 4 bytes
+    (drop (i32.const 0)) ;; 1 byte
+    (drop (i32.const 63)) ;; 1 byte
+    (drop (i32.const 64)) ;; 2 bytes
+    (drop (i32.const 8191)) ;; 2 bytes
+    (drop (i32.const 8192)) ;; 3 bytes
+    (drop (i32.const 1048575)) ;; 3 bytes
+    (drop (i32.const 1048576)) ;; 4 bytes
+    (drop (i32.const -64)) ;; 1 byte
+    (drop (i32.const -65)) ;; 2 bytes
+    (drop (i32.const -8192)) ;; 2 bytes
+    (drop (i32.const -8193)) ;; 3 bytes
+    (drop (i32.const -1048576)) ;; 3 bytes
+    (drop (i32.const -1048577)) ;; 4 bytes
+    (drop (i32.const 0)) ;; 1 byte
+    (drop (i32.const 63)) ;; 1 byte
+    (drop (i32.const 64)) ;; 2 bytes
+    (drop (i32.const 8191)) ;; 2 bytes
+    (drop (i32.const 8192)) ;; 3 bytes
+    (drop (i32.const 1048575)) ;; 3 bytes
+    (drop (i32.const 1048576)) ;; 4 bytes
+    (drop (i32.const -64)) ;; 1 byte
+    (drop (i32.const -65)) ;; 2 bytes
+    (drop (i32.const -8192)) ;; 2 bytes
+    (drop (i32.const -8193)) ;; 3 bytes
+    (drop (i32.const -1048576)) ;; 3 bytes
+    (drop (i32.const -1048577)) ;; 4 bytes
+    (drop (i32.const 0)) ;; 1 byte
+    (drop (i32.const 63)) ;; 1 byte
+    (drop (i32.const 64)) ;; 2 bytes
+    (drop (i32.const 8191)) ;; 2 bytes
+    (drop (i32.const 8192)) ;; 3 bytes
+    (drop (i32.const 1048575)) ;; 3 bytes
+    (drop (i32.const 1048576)) ;; 4 bytes
+    (drop (i32.const -64)) ;; 1 byte
+    (drop (i32.const -65)) ;; 2 bytes
+    (drop (i32.const -8192)) ;; 2 bytes
+    (drop (i32.const -8193)) ;; 3 bytes
+    (drop (i32.const -1048576)) ;; 3 bytes
+    (drop (i32.const -1048577)) ;; 4 bytes
+    (drop (i32.const 0)) ;; 1 byte
+    (drop (i32.const 63)) ;; 1 byte
+    (drop (i32.const 64)) ;; 2 bytes
+    (drop (i32.const 8191)) ;; 2 bytes
+    (drop (i32.const 8192)) ;; 3 bytes
+    (drop (i32.const 1048575)) ;; 3 bytes
+    (drop (i32.const 1048576)) ;; 4 bytes
+    (drop (i32.const -64)) ;; 1 byte
+    (drop (i32.const -65)) ;; 2 bytes
+    (drop (i32.const -8192)) ;; 2 bytes
+    (drop (i32.const -8193)) ;; 3 bytes
+    (drop (i32.const -1048576)) ;; 3 bytes
+    (drop (i32.const -1048577)) ;; 4 bytes
+    (drop (i32.const 0)) ;; 1 byte
+    (drop (i32.const 63)) ;; 1 byte
+    (drop (i32.const 64)) ;; 2 bytes
+    (drop (i32.const 8191)) ;; 2 bytes
+    (drop (i32.const 8192)) ;; 3 bytes
+    (drop (i32.const 1048575)) ;; 3 bytes
+    (drop (i32.const 1048576)) ;; 4 bytes
+    (drop (i32.const -64)) ;; 1 byte
+    (drop (i32.const -65)) ;; 2 bytes
+    (drop (i32.const -8192)) ;; 2 bytes
+    (drop (i32.const -8193)) ;; 3 bytes
+    (drop (i32.const -1048576)) ;; 3 bytes
+    (drop (i32.const -1048577)) ;; 4 bytes
+    (drop (i32.const 0)) ;; 1 byte
+    (drop (i32.const 63)) ;; 1 byte
+    (drop (i32.const 64)) ;; 2 bytes
+    (drop (i32.const 8191)) ;; 2 bytes
+    (drop (i32.const 8192)) ;; 3 bytes
+    (drop (i32.const 1048575)) ;; 3 bytes
+    (drop (i32.const 1048576)) ;; 4 bytes
+    (drop (i32.const -64)) ;; 1 byte
+    (drop (i32.const -65)) ;; 2 bytes
+    (drop (i32.const -8192)) ;; 2 bytes
+    (drop (i32.const -8193)) ;; 3 bytes
+    (drop (i32.const -1048576)) ;; 3 bytes
+    (drop (i32.const -1048577)) ;; 4 bytes
+    (drop (i32.const 0)) ;; 1 byte
+    (drop (i32.const 63)) ;; 1 byte
+    (drop (i32.const 64)) ;; 2 bytes
+    (drop (i32.const 8191)) ;; 2 bytes
+    (drop (i32.const 8192)) ;; 3 bytes
+    (drop (i32.const 1048575)) ;; 3 bytes
+    (drop (i32.const 1048576)) ;; 4 bytes
+    (drop (i32.const -64)) ;; 1 byte
+    (drop (i32.const -65)) ;; 2 bytes
+    (drop (i32.const -8192)) ;; 2 bytes
+    (drop (i32.const -8193)) ;; 3 bytes
+    (drop (i32.const -1048576)) ;; 3 bytes
+    (drop (i32.const -1048577)) ;; 4 bytes
+    (drop (i32.const 0)) ;; 1 byte
+    (drop (i32.const 63)) ;; 1 byte
+    (drop (i32.const 64)) ;; 2 bytes
+    (drop (i32.const 8191)) ;; 2 bytes
+    (drop (i32.const 8192)) ;; 3 bytes
+    (drop (i32.const 1048575)) ;; 3 bytes
+    (drop (i32.const 1048576)) ;; 4 bytes
+    (drop (i32.const -64)) ;; 1 byte
+    (drop (i32.const -65)) ;; 2 bytes
+    (drop (i32.const -8192)) ;; 2 bytes
+    (drop (i32.const -8193)) ;; 3 bytes
+    (drop (i32.const -1048576)) ;; 3 bytes
+    (drop (i32.const -1048577)) ;; 4 bytes
+  )
+  (func $floats-10-times
+    (drop (f32.const 0)) ;; 4 bytes
+    (drop (f64.const 0)) ;; 8 bytes
+    (drop (f32.const 0)) ;; 4 bytes
+    (drop (f64.const 0)) ;; 8 bytes
+    (drop (f32.const 0)) ;; 4 bytes
+    (drop (f64.const 0)) ;; 8 bytes
+    (drop (f32.const 0)) ;; 4 bytes
+    (drop (f64.const 0)) ;; 8 bytes
+    (drop (f32.const 0)) ;; 4 bytes
+    (drop (f64.const 0)) ;; 8 bytes
+    (drop (f32.const 0)) ;; 4 bytes
+    (drop (f64.const 0)) ;; 8 bytes
+    (drop (f32.const 0)) ;; 4 bytes
+    (drop (f64.const 0)) ;; 8 bytes
+    (drop (f32.const 0)) ;; 4 bytes
+    (drop (f64.const 0)) ;; 8 bytes
+    (drop (f32.const 0)) ;; 4 bytes
+    (drop (f64.const 0)) ;; 8 bytes
+    (drop (f32.const 0)) ;; 4 bytes
+    (drop (f64.const 0)) ;; 8 bytes
+  )
+  (func $too-few
+    (drop (i32.const 8192)) ;; 3 bytes, need 6 appearances
+    (drop (i32.const 8192))
+    (drop (i32.const 8192))
+    (drop (i32.const 8192))
+    (drop (i32.const 8192))
+  )
+  (func $just-enough
+    (drop (i32.const 8192)) ;; 3 bytes, need 6 appearances
+    (drop (i32.const 8192))
+    (drop (i32.const 8192))
+    (drop (i32.const 8192))
+    (drop (i32.const 8192))
+    (drop (i32.const 8192))
+  )
+  (func $too-few-b
+    (drop (i32.const 1048576)) ;; 4 bytes, need 4 appearances
+    (drop (i32.const 1048576))
+    (drop (i32.const 1048576))
+  )
+  (func $enough-b
+    (drop (i32.const 1048576)) ;; 4 bytes, need 4 appearances
+    (drop (i32.const 1048576))
+    (drop (i32.const 1048576))
+    (drop (i32.const 1048576))
+  )
+  (func $too-few-c
+    (drop (f32.const 0)) ;; 4 bytes, need 4 appearances
+    (drop (f32.const 0))
+    (drop (f32.const 0))
+  )
+  (func $enough-c
+    (drop (f32.const 0)) ;; 4 bytes, need 4 appearances
+    (drop (f32.const 0))
+    (drop (f32.const 0))
+    (drop (f32.const 0))
+  )
+  (func $too-few-d
+    (drop (f64.const 0)) ;; 8 bytes, need 2 appearances
+  )
+  (func $enough-d
+    (drop (f64.const 0)) ;; 4 bytes, need 4 appearances
+    (drop (f64.const 0))
+  )
+)
+
diff --git a/binaryen/test/passes/converge_O3_metrics.bin.txt b/binaryen/test/passes/converge_O3_metrics.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/converge_O3_metrics.bin.txt
@@ -0,0 +1,490 @@
+total
+ [events]       : 0       
+ [exports]      : 2       
+ [funcs]        : 8       
+ [globals]      : 1       
+ [imports]      : 3       
+ [memory-data]  : 28      
+ [table-data]   : 429     
+ [total]        : 132     
+ [vars]         : 4       
+ binary         : 12      
+ block          : 8       
+ break          : 3       
+ call           : 3       
+ call_indirect  : 4       
+ const          : 47      
+ drop           : 3       
+ global.get     : 1       
+ global.set     : 1       
+ if             : 3       
+ load           : 16      
+ local.get      : 18      
+ local.set      : 7       
+ loop           : 1       
+ store          : 5       
+(module
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_none (func))
+ (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))
+ (data (i32.const 2948) "\03")
+ (data (i32.const 6828) "\04")
+ (data (i32.const 7028) "\0d\00\00\00\06")
+ (data (i32.const 10888) "hello, world!")
+ (data (i32.const 18100) "\b8\1a")
+ (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))
+ (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))
+ (export "_main" (func $_main))
+ (export "_malloc" (func $_malloc))
+ (func $b0 (; has Stack IR ;) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (param $5 i32) (param $6 i32) (result i32)
+  (i32.const 0)
+ )
+ (func $_malloc (; has Stack IR ;) (param $0 i32) (result i32)
+  (i32.const 0)
+ )
+ (func $___stdio_write (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
+  (i32.store
+   (i32.const 8)
+   (local.get $0)
+  )
+  (i32.store
+   (i32.const 12)
+   (local.get $1)
+  )
+  (i32.store
+   (local.tee $0
+    (global.get $global$0)
+   )
+   (i32.const 1)
+  )
+  (i32.store offset=8
+   (local.get $0)
+   (i32.const 2)
+  )
+  (drop
+   (if (result i32)
+    (call $import$0
+     (i32.const 146)
+     (local.get $0)
+    )
+    (i32.const -1)
+    (i32.const 0)
+   )
+  )
+  (i32.const 1)
+ )
+ (func $_main (; has Stack IR ;) (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $1
+   (i32.load offset=24
+    (i32.add
+     (i32.load
+      (i32.add
+       (i32.load
+        (i32.const 18100)
+       )
+       (i32.const -12)
+      )
+     )
+     (i32.const 18100)
+    )
+   )
+  )
+  (if
+   (block (result i32)
+    (local.set $0
+     (i32.const 10888)
+    )
+    (loop $label$3
+     (br_if $label$3
+      (i32.load8_s
+       (local.tee $0
+        (i32.add
+         (local.get $0)
+         (i32.const 1)
+        )
+       )
+      )
+     )
+    )
+    (local.tee $0
+     (i32.sub
+      (local.get $0)
+      (i32.const 10888)
+     )
+    )
+   )
+   (block $label$2
+    (br_if $label$2
+     (call_indirect (type $i32_i32_i32_=>_i32)
+      (local.get $1)
+      (i32.const 10888)
+      (local.get $0)
+      (i32.add
+       (i32.load offset=48
+        (i32.load
+         (local.get $1)
+        )
+       )
+       (i32.const 8)
+      )
+     )
+    )
+   )
+  )
+  (call $__ZNSt3__213basic_ostreamIcNS_11char_traitsIcEEE3putEc)
+  (i32.const 0)
+ )
+ (func $___stdout_write (; has Stack IR ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (global.set $global$0
+   (i32.const 32)
+  )
+  (call $___stdio_write
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $__ZNSt3__213basic_ostreamIcNS_11char_traitsIcEEE3putEc (; has Stack IR ;)
+  (local $0 i32)
+  (local $1 i32)
+  (block $label$1
+   (br_if $label$1
+    (if (result i32)
+     (i32.load
+      (i32.add
+       (local.tee $1
+        (local.tee $0
+         (i32.load
+          (i32.add
+           (i32.load
+            (i32.add
+             (i32.load
+              (i32.const 18100)
+             )
+             (i32.const -12)
+            )
+           )
+           (i32.const 18124)
+          )
+         )
+        )
+       )
+       (i32.const 24)
+      )
+     )
+     (i32.const 0)
+     (call_indirect (type $i32_i32_=>_i32)
+      (local.get $1)
+      (i32.const 10)
+      (i32.add
+       (i32.load offset=52
+        (i32.load
+         (local.get $0)
+        )
+       )
+       (i32.const 422)
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $__ZNSt3__211__stdoutbufIcE8overflowEi (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
+  (i32.store8
+   (i32.const 0)
+   (local.get $1)
+  )
+  (drop
+   (call_indirect (type $i32_i32_i32_=>_i32)
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 1)
+    (i32.add
+     (i32.load offset=36
+      (i32.load
+       (i32.add
+        (local.get $0)
+        (i32.const 32)
+       )
+      )
+     )
+     (i32.const 8)
+    )
+   )
+  )
+  (i32.const 0)
+ )
+ (func $__ZNSt3__211__stdoutbufIcE6xsputnEPKci (; has Stack IR ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (drop
+   (call_indirect (type $i32_i32_i32_=>_i32)
+    (i32.const 0)
+    (local.get $1)
+    (local.get $2)
+    (i32.add
+     (i32.load offset=36
+      (i32.load offset=32
+       (local.get $0)
+      )
+     )
+     (i32.const 8)
+    )
+   )
+  )
+  (i32.const 0)
+ )
+)
+total
+ [events]       : 0       
+ [exports]      : 2       
+ [funcs]        : 8       
+ [globals]      : 1       
+ [imports]      : 3       
+ [memory-data]  : 28      
+ [table-data]   : 429     
+ [total]        : 132     
+ [vars]         : 4       
+ binary         : 12      
+ block          : 8       
+ break          : 3       
+ call           : 3       
+ call_indirect  : 4       
+ const          : 47      
+ drop           : 3       
+ global.get     : 1       
+ global.set     : 1       
+ if             : 3       
+ load           : 16      
+ local.get      : 18      
+ local.set      : 7       
+ loop           : 1       
+ store          : 5       
+(module
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_none (func))
+ (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))
+ (data (i32.const 2948) "\03")
+ (data (i32.const 6828) "\04")
+ (data (i32.const 7028) "\0d\00\00\00\06")
+ (data (i32.const 10888) "hello, world!")
+ (data (i32.const 18100) "\b8\1a")
+ (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))
+ (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))
+ (export "_main" (func $_main))
+ (export "_malloc" (func $_malloc))
+ (func $b0 (; has Stack IR ;) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (param $5 i32) (param $6 i32) (result i32)
+  (i32.const 0)
+ )
+ (func $_malloc (; has Stack IR ;) (param $0 i32) (result i32)
+  (i32.const 0)
+ )
+ (func $___stdio_write (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
+  (i32.store
+   (i32.const 8)
+   (local.get $0)
+  )
+  (i32.store
+   (i32.const 12)
+   (local.get $1)
+  )
+  (i32.store
+   (local.tee $0
+    (global.get $global$0)
+   )
+   (i32.const 1)
+  )
+  (i32.store offset=8
+   (local.get $0)
+   (i32.const 2)
+  )
+  (drop
+   (if (result i32)
+    (call $import$0
+     (i32.const 146)
+     (local.get $0)
+    )
+    (i32.const -1)
+    (i32.const 0)
+   )
+  )
+  (i32.const 1)
+ )
+ (func $_main (; has Stack IR ;) (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $1
+   (i32.load offset=24
+    (i32.add
+     (i32.load
+      (i32.add
+       (i32.load
+        (i32.const 18100)
+       )
+       (i32.const -12)
+      )
+     )
+     (i32.const 18100)
+    )
+   )
+  )
+  (if
+   (block (result i32)
+    (local.set $0
+     (i32.const 10888)
+    )
+    (loop $label$3
+     (br_if $label$3
+      (i32.load8_s
+       (local.tee $0
+        (i32.add
+         (local.get $0)
+         (i32.const 1)
+        )
+       )
+      )
+     )
+    )
+    (local.tee $0
+     (i32.sub
+      (local.get $0)
+      (i32.const 10888)
+     )
+    )
+   )
+   (block $label$2
+    (br_if $label$2
+     (call_indirect (type $i32_i32_i32_=>_i32)
+      (local.get $1)
+      (i32.const 10888)
+      (local.get $0)
+      (i32.add
+       (i32.load offset=48
+        (i32.load
+         (local.get $1)
+        )
+       )
+       (i32.const 8)
+      )
+     )
+    )
+   )
+  )
+  (call $__ZNSt3__213basic_ostreamIcNS_11char_traitsIcEEE3putEc)
+  (i32.const 0)
+ )
+ (func $___stdout_write (; has Stack IR ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (global.set $global$0
+   (i32.const 32)
+  )
+  (call $___stdio_write
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $__ZNSt3__213basic_ostreamIcNS_11char_traitsIcEEE3putEc (; has Stack IR ;)
+  (local $0 i32)
+  (local $1 i32)
+  (block $label$1
+   (br_if $label$1
+    (if (result i32)
+     (i32.load
+      (i32.add
+       (local.tee $1
+        (local.tee $0
+         (i32.load
+          (i32.add
+           (i32.load
+            (i32.add
+             (i32.load
+              (i32.const 18100)
+             )
+             (i32.const -12)
+            )
+           )
+           (i32.const 18124)
+          )
+         )
+        )
+       )
+       (i32.const 24)
+      )
+     )
+     (i32.const 0)
+     (call_indirect (type $i32_i32_=>_i32)
+      (local.get $1)
+      (i32.const 10)
+      (i32.add
+       (i32.load offset=52
+        (i32.load
+         (local.get $0)
+        )
+       )
+       (i32.const 422)
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $__ZNSt3__211__stdoutbufIcE8overflowEi (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
+  (i32.store8
+   (i32.const 0)
+   (local.get $1)
+  )
+  (drop
+   (call_indirect (type $i32_i32_i32_=>_i32)
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 1)
+    (i32.add
+     (i32.load offset=36
+      (i32.load
+       (i32.add
+        (local.get $0)
+        (i32.const 32)
+       )
+      )
+     )
+     (i32.const 8)
+    )
+   )
+  )
+  (i32.const 0)
+ )
+ (func $__ZNSt3__211__stdoutbufIcE6xsputnEPKci (; has Stack IR ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (drop
+   (call_indirect (type $i32_i32_i32_=>_i32)
+    (i32.const 0)
+    (local.get $1)
+    (local.get $2)
+    (i32.add
+     (i32.load offset=36
+      (i32.load offset=32
+       (local.get $0)
+      )
+     )
+     (i32.const 8)
+    )
+   )
+  )
+  (i32.const 0)
+ )
+)
diff --git a/binaryen/test/passes/converge_O3_metrics.wasm b/binaryen/test/passes/converge_O3_metrics.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/converge_O3_metrics.wasm differ
diff --git a/binaryen/test/passes/dae-optimizing.txt b/binaryen/test/passes/dae-optimizing.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dae-optimizing.txt
@@ -0,0 +1,43 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $f64_f32_f32_f64_f32_i32_i32_f64_=>_i32 (func (param f64 f32 f32 f64 f32 i32 i32 f64) (result i32)))
+ (type $none_=>_f32 (func (result f32)))
+ (global $global$0 (mut i32) (i32.const 10))
+ (func $0 (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (drop
+   (if (result f32)
+    (local.tee $0
+     (i32.const 33554432)
+    )
+    (loop $label$2 (result f32)
+     (if
+      (global.get $global$0)
+      (return
+       (local.get $0)
+      )
+     )
+     (local.set $0
+      (local.get $1)
+     )
+     (local.set $1
+      (i32.const 0)
+     )
+     (br_if $label$2
+      (local.get $0)
+     )
+     (f32.const 1)
+    )
+    (call $1)
+   )
+  )
+  (i32.const -11)
+ )
+ (func $1 (result f32)
+  (f32.const 0)
+ )
+ (func $2 (param $0 f64) (param $1 f32) (param $2 f32) (param $3 f64) (param $4 f32) (param $5 i32) (param $6 i32) (param $7 f64) (result i32)
+  (call $0)
+ )
+)
diff --git a/binaryen/test/passes/dae-optimizing.wast b/binaryen/test/passes/dae-optimizing.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dae-optimizing.wast
@@ -0,0 +1,60 @@
+(module
+ (type $0 (func (param f32) (result f32)))
+ (type $1 (func (param f64 f32 f32 f64 f32 i64 f64) (result i32)))
+ (type $2 (func (param f64 f32 f32 f64 f32 i32 i32 f64) (result i32)))
+ (global $global$0 (mut i32) (i32.const 10))
+ (func $0 (; 0 ;) (type $1) (param $0 f64) (param $1 f32) (param $2 f32) (param $3 f64) (param $4 f32) (param $5 i64) (param $6 f64) (result i32)
+  (local $7 i32)
+  (local $8 i32)
+  (if
+   (local.tee $7
+    (i32.const 33554432)
+   )
+   (drop
+    (loop $label$2 (result f32)
+     (if
+      (global.get $global$0)
+      (return
+       (local.get $7)
+      )
+     )
+     (local.set $8
+      (block $label$4 (result i32)
+       (drop
+        (local.tee $7
+         (local.get $8)
+        )
+       )
+       (i32.const 0)
+      )
+     )
+     (br_if $label$2
+      (local.get $7)
+     )
+     (f32.const 1)
+    )
+   )
+   (drop
+    (call $1
+     (f32.const 1)
+    )
+   )
+  )
+  (i32.const -11)
+ )
+ (func $1 (; 1 ;) (type $0) (param $0 f32) (result f32)
+  (f32.const 0)
+ )
+ (func $2 (; 2 ;) (type $2) (param $0 f64) (param $1 f32) (param $2 f32) (param $3 f64) (param $4 f32) (param $5 i32) (param $6 i32) (param $7 f64) (result i32)
+  (call $0
+   (f64.const 1)
+   (f32.const 1)
+   (f32.const 1)
+   (f64.const 1)
+   (f32.const 1)
+   (i64.const 1)
+   (f64.const 1)
+  )
+ )
+)
+
diff --git a/binaryen/test/passes/dae_enable-tail-call.txt b/binaryen/test/passes/dae_enable-tail-call.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dae_enable-tail-call.txt
@@ -0,0 +1,281 @@
+(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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dae_enable-tail-call.wast
@@ -0,0 +1,163 @@
+(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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dce_all-features.txt
@@ -0,0 +1,553 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $f32_i64_=>_none (func (param f32 i64)))
+ (type $f32_i64_=>_i32 (func (param f32 i64) (result i32)))
+ (type $i64_i64_=>_i64 (func (param i64 i64) (result i64)))
+ (memory $0 10)
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $call-me)
+ (global $x (mut i32) (i32.const 0))
+ (func $call-me (param $0 i32) (param $1 i32)
+  (nop)
+ )
+ (func $code-to-kill
+  (local $x i32)
+  (block $out
+   (br $out)
+  )
+  (if
+   (i32.const 0)
+   (unreachable)
+  )
+  (if
+   (i32.const 0)
+   (return)
+  )
+  (block $out4
+   (br_table $out4 $out4 $out4 $out4
+    (i32.const 4)
+   )
+  )
+  (block $out5
+   (br_if $out5
+    (i32.const 3)
+   )
+   (drop
+    (i32.const 0)
+   )
+  )
+  (if
+   (i32.const 0)
+   (if
+    (i32.const 0)
+    (unreachable)
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 0)
+   (unreachable)
+  )
+  (if
+   (i32.const 0)
+   (unreachable)
+  )
+  (if
+   (i32.const 0)
+   (unreachable)
+  )
+  (block $out16
+   (block $in
+    (br_if $out16
+     (i32.const 1)
+    )
+   )
+   (unreachable)
+  )
+  (if
+   (i32.const 0)
+   (block $out18
+    (block $in19
+     (br_if $in19
+      (i32.const 1)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (block $out20
+   (block $in21
+    (br_table $out20 $in21
+     (i32.const 1)
+    )
+   )
+   (unreachable)
+  )
+  (block $out22
+   (block $in23
+    (br_table $in23 $out22
+     (i32.const 1)
+    )
+   )
+   (unreachable)
+  )
+  (if
+   (i32.const 0)
+   (block $out25
+    (block $in26
+     (br_table $in26 $in26
+      (i32.const 1)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 0)
+   (block $block15
+    (drop
+     (i32.const 10)
+    )
+    (drop
+     (i32.const 42)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 0)
+   (unreachable)
+  )
+  (block $out29
+   (block
+    (br_if $out29
+     (i32.const 1)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 0)
+   (loop $in32
+    (br_if $in32
+     (i32.const 1)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 1)
+   (block
+    (drop
+     (i32.const 123)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 2)
+   (unreachable)
+  )
+  (if
+   (i32.const 3)
+   (unreachable)
+  )
+  (if
+   (i32.const -1)
+   (block
+    (drop
+     (i32.const 123)
+    )
+    (drop
+     (i32.const 456)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const -2)
+   (block
+    (drop
+     (i32.const 139)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const -3)
+   (block
+    (drop
+     (i32.const 246)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const -4)
+   (unreachable)
+  )
+  (if
+   (i32.const 11)
+   (unreachable)
+  )
+  (if
+   (i32.const 22)
+   (unreachable)
+  )
+  (if
+   (i32.const 33)
+   (block
+    (drop
+     (i32.const 0)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 44)
+   (unreachable)
+  )
+  (if
+   (i32.const 55)
+   (unreachable)
+  )
+  (if
+   (i32.const 66)
+   (unreachable)
+  )
+  (if
+   (i32.const 77)
+   (unreachable)
+  )
+  (if
+   (i32.const 88)
+   (block
+    (drop
+     (i32.const 0)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 99)
+   (unreachable)
+  )
+  (if
+   (i32.const 100)
+   (block
+    (drop
+     (i32.const 123)
+    )
+    (drop
+     (i32.const 456)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 101)
+   (block
+    (drop
+     (i32.const 123)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 102)
+   (unreachable)
+  )
+  (drop
+   (i32.const 1337)
+  )
+ )
+ (func $killer
+  (unreachable)
+ )
+ (func $target
+  (drop
+   (i32.const 2000)
+  )
+ )
+ (func $typed-block-none-then-unreachable (result i32)
+  (return
+   (i32.const 0)
+  )
+ )
+ (func $typed-block-remove-br-changes-type (param $$$0 i32) (result i32)
+  (block $switch$7
+   (block $switch-default$10
+    (block $switch-case$9
+     (block $switch-case$8
+      (br_table $switch-case$9 $switch-case$8 $switch-default$10
+       (i32.const -1)
+      )
+     )
+    )
+    (return
+     (local.get $$$0)
+    )
+   )
+   (return
+    (local.get $$$0)
+   )
+  )
+ )
+ (func $global
+  (unreachable)
+ )
+ (func $ret (result i32)
+  (return
+   (i32.const 0)
+  )
+ )
+ (func $unreachable-br (result i32)
+  (block $out (result i32)
+   (br $out
+    (i32.const 0)
+   )
+  )
+ )
+ (func $unreachable-br-loop (result i32)
+  (loop $out
+   (br $out)
+  )
+ )
+ (func $unreachable-block-ends-switch (result i32)
+  (block $label$3
+   (nop)
+   (unreachable)
+  )
+ )
+ (func $unreachable-block-ends-br_if (result i32)
+  (block $label$2
+   (nop)
+   (unreachable)
+  )
+ )
+ (func $unreachable-brs-3 (result i32)
+  (block $label$0 (result i32)
+   (br $label$0
+    (i32.const 18)
+   )
+  )
+ )
+ (func $unreachable-brs-4 (param $var$0 i32) (result i32)
+  (drop
+   (i32.const 1)
+  )
+  (block
+   (drop
+    (i32.const 4104)
+   )
+   (unreachable)
+  )
+ )
+ (func $call-unreach (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $2 i64)
+  (if (result i64)
+   (i64.eqz
+    (local.get $var$0)
+   )
+   (block $label$0 (result i64)
+    (local.get $var$1)
+   )
+   (block
+    (drop
+     (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)
+      )
+     )
+     (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)
+  )
+ )
+ (func $br-with-unreachable-value-should-not-give-a-block-a-value (param $var$0 i32) (result i32)
+  (block $label$0 (result i32)
+   (block $block
+    (drop
+     (br_if $label$0
+      (i32.const 8)
+      (local.get $var$0)
+     )
+    )
+    (unreachable)
+   )
+  )
+ )
+ (func $replace-br-value-of-i32-with-unreachable (result i32)
+  (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)
+  )
+ )
+ (func $if-with-type-but-is-unreachable (param $var$0 i32) (result i32)
+  (if
+   (local.get $var$0)
+   (unreachable)
+   (unreachable)
+  )
+ )
+ (func $unreachable-loop
+  (unreachable)
+ )
+ (func $br-block-from-unary (result i32)
+  (block $label$6 (result i32)
+   (br $label$6
+    (i32.const 8)
+   )
+  )
+ )
+ (func $replace-unary-with-br-child
+  (drop
+   (block $label$6 (result i32)
+    (br $label$6
+     (i32.const 8)
+    )
+   )
+  )
+ )
+ (func $br_if-unreach-then-br_if-normal
+  (block $out
+   (nop)
+   (unreachable)
+  )
+ )
+ (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)
+    )
+    (i32.const 1)
+   )
+   (unreachable)
+   (unreachable)
+  )
+ )
+ (func $replace-block-changes-later-when-if-goes
+  (block $top
+   (global.set $x
+    (i32.const 0)
+   )
+   (block $inner
+    (drop
+     (call $helper
+      (f32.const 1)
+      (i64.const -15917430362925035)
+     )
+    )
+    (unreachable)
+   )
+  )
+ )
+ (func $helper (param $var$0 f32) (param $var$1 i64) (result i32)
+  (i32.const 0)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (global $global (mut f64) (f64.const 0))
+ (func $0
+  (if
+   (i32.const 0)
+   (unreachable)
+   (unreachable)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (func $0
+  (local $local f64)
+  (if
+   (i32.const 0)
+   (unreachable)
+   (unreachable)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (event $e (attr 0) (param))
+ (func $foo
+  (nop)
+ )
+ (func $try_unreachable
+  (try
+   (do
+    (unreachable)
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+   )
+  )
+  (call $foo)
+ )
+ (func $catch_unreachable
+  (try
+   (do
+    (nop)
+   )
+   (catch
+    (unreachable)
+   )
+  )
+  (call $foo)
+ )
+ (func $both_unreachable
+  (try
+   (do
+    (unreachable)
+   )
+   (catch
+    (unreachable)
+   )
+  )
+ )
+ (func $throw
+  (throw $e
+  )
+ )
+ (func $rethrow
+  (rethrow
+   (ref.null exn)
+  )
+ )
+)
diff --git a/binaryen/test/passes/dce_all-features.wast b/binaryen/test/passes/dce_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dce_all-features.wast
@@ -0,0 +1,813 @@
+(module
+  (memory 10)
+  (type $ii (func (param i32 i32)))
+  (type $1 (func))
+  (table 1 1 funcref)
+  (elem (i32.const 0) $call-me)
+  (global $x (mut i32) (i32.const 0))
+  (func $call-me (type $ii) (param $0 i32) (param $1 i32)
+    (nop)
+  )
+  (func $code-to-kill (type $1)
+    (local $x i32)
+    (block $out
+      (br $out)
+      (drop
+        (i32.const 0)
+      )
+      (if
+        (i32.const 1)
+        (drop
+          (i32.const 2)
+        )
+      )
+      (br_table $out $out $out $out
+        (i32.const 3)
+      )
+      (call $code-to-kill)
+    )
+    (if
+      (i32.const 0)
+      (block $out
+        (unreachable)
+        (drop
+          (i32.const 0)
+        )
+      )
+    )
+    (if
+      (i32.const 0)
+      (block $out
+        (return)
+        (drop
+          (i32.const 0)
+        )
+      )
+    )
+    (block $out
+      (br_table $out $out $out $out
+        (i32.const 4)
+      )
+      (drop
+        (i32.const 0)
+      )
+    )
+    (block $out
+      (br_if $out
+        (i32.const 3)
+      )
+      (drop
+        (i32.const 0)
+      )
+    )
+    (if
+      (i32.const 0)
+      (block $block4
+        (if
+          (i32.const 0)
+          (block $out
+            (unreachable)
+            (drop
+              (i32.const 0)
+            )
+          )
+          (block $out
+            (unreachable)
+            (drop
+              (i32.const 0)
+            )
+          )
+        )
+        (drop
+          (i32.const 0)
+        )
+      )
+    )
+    (if
+      (i32.const 0)
+      (drop
+        (block $out (result i32)
+          (br $out
+            (unreachable)
+          )
+          (drop
+            (i32.const 0)
+          )
+          (unreachable)
+        )
+      )
+    )
+    (if
+      (i32.const 0)
+      (drop
+        (block $out (result i32)
+          (br_if $out
+            (unreachable)
+            (i32.const 0)
+          )
+          (drop
+            (i32.const 0)
+          )
+          (unreachable)
+        )
+      )
+    )
+    (if
+      (i32.const 0)
+      (drop
+        (block $out (result i32)
+          (br_if $out
+            (unreachable)
+            (unreachable)
+          )
+          (drop
+            (i32.const 0)
+          )
+          (unreachable)
+        )
+      )
+    )
+    (block $out
+      (block $in
+        (br_if $out
+          (i32.const 1)
+        )
+      )
+      (unreachable)
+    )
+    (if
+      (i32.const 0)
+      (block $block11
+        (block $out
+          (block $in
+            (br_if $in
+              (i32.const 1)
+            )
+          )
+          (unreachable)
+        )
+        (drop
+          (i32.const 10)
+        )
+      )
+    )
+    (block $out
+      (block $in
+        (br_table $out $in
+          (i32.const 1)
+        )
+      )
+      (unreachable)
+    )
+    (block $out
+      (block $in
+        (br_table $in $out
+          (i32.const 1)
+        )
+      )
+      (unreachable)
+    )
+    (if
+      (i32.const 0)
+      (block $block13
+        (block $out
+          (block $in
+            (br_table $in $in
+              (i32.const 1)
+            )
+          )
+          (unreachable)
+        )
+        (drop
+          (i32.const 10)
+        )
+      )
+    )
+    (if
+      (i32.const 0)
+      (block $block15
+        (drop
+          (i32.const 10)
+        )
+        (drop
+          (i32.const 42)
+        )
+        (unreachable)
+        (return
+          (unreachable)
+        )
+        (unreachable)
+        (return)
+      )
+    )
+    (if
+      (i32.const 0)
+      (loop $loop-in18
+        (unreachable)
+      )
+    )
+    (block $out
+    (loop $in
+      (br_if $out
+        (i32.const 1)
+      )
+      (unreachable)
+    )
+    )
+    (if
+      (i32.const 0)
+      (block $block20
+        (loop $in
+          (br_if $in
+            (i32.const 1)
+          )
+          (unreachable)
+        )
+        (drop
+          (i32.const 10)
+        )
+      )
+    )
+    (if
+      (i32.const 1)
+      (call $call-me
+        (i32.const 123)
+        (unreachable)
+      )
+    )
+    (if
+      (i32.const 2)
+      (call $call-me
+        (unreachable)
+        (i32.const 0)
+      )
+    )
+    (if
+      (i32.const 3)
+      (call $call-me
+        (unreachable)
+        (unreachable)
+      )
+    )
+    (if
+      (i32.const -1)
+      (call_indirect (type $ii)
+        (i32.const 123)
+        (i32.const 456)
+        (unreachable)
+      )
+    )
+    (if
+      (i32.const -2)
+      (call_indirect (type $ii)
+        (i32.const 139)
+        (unreachable)
+        (i32.const 0)
+      )
+    )
+    (if
+      (i32.const -3)
+      (call_indirect (type $ii)
+        (i32.const 246)
+        (unreachable)
+        (unreachable)
+      )
+    )
+    (if
+      (i32.const -4)
+      (call_indirect (type $ii)
+        (unreachable)
+        (unreachable)
+        (unreachable)
+      )
+    )
+    (if
+      (i32.const 11)
+      (local.set $x
+        (unreachable)
+      )
+    )
+    (if
+      (i32.const 22)
+      (drop
+        (i32.load
+          (unreachable)
+        )
+      )
+    )
+    (if
+      (i32.const 33)
+      (i32.store
+        (i32.const 0)
+        (unreachable)
+      )
+    )
+    (if
+      (i32.const 44)
+      (i32.store
+        (unreachable)
+        (i32.const 0)
+      )
+    )
+    (if
+      (i32.const 55)
+      (i32.store
+        (unreachable)
+        (unreachable)
+      )
+    )
+    (if
+      (i32.const 66)
+      (drop
+        (i32.eqz
+          (unreachable)
+        )
+      )
+    )
+    (if
+      (i32.const 77)
+      (drop
+        (i32.add
+          (unreachable)
+          (i32.const 0)
+        )
+      )
+    )
+    (if
+      (i32.const 88)
+      (drop
+        (i32.add
+          (i32.const 0)
+          (unreachable)
+        )
+      )
+    )
+    (if
+      (i32.const 99)
+      (i32.add
+        (unreachable)
+        (unreachable)
+      )
+    )
+    (if
+      (i32.const 100)
+      (drop
+        (select
+          (i32.const 123)
+          (i32.const 456)
+          (unreachable)
+        )
+      )
+    )
+    (if
+      (i32.const 101)
+      (drop
+        (select
+          (i32.const 123)
+          (unreachable)
+          (i32.const 456)
+        )
+      )
+    )
+    (if
+      (i32.const 102)
+      (drop
+        (select
+          (unreachable)
+          (i32.const 123)
+          (i32.const 456)
+        )
+      )
+    )
+    (drop
+      (i32.const 1337)
+    )
+  )
+  (func $killer (type $1)
+    (unreachable)
+    (drop
+      (i32.const 1000)
+    )
+  )
+  (func $target (type $1)
+    (drop
+      (i32.const 2000)
+    )
+  )
+  (func $typed-block-none-then-unreachable (result i32)
+    (block $top-typed (result i32)
+      (block $switch$0 ;; this looks like it can be broken to, so it gets type 'none'
+        (return
+          (i32.const 0)
+        )
+        (br $switch$0) ;; this is not reachable, so dce cleans it up, changing $switch$0's type
+      )
+      (return ;; and this is cleaned up as well, leaving $top-typed in need of a type change
+        (i32.const 1)
+      )
+    )
+  )
+  (func $typed-block-remove-br-changes-type (param $$$0 i32) (result i32)
+    (block $switch$7
+      (block $switch-default$10
+        (block $switch-case$9
+          (block $switch-case$8
+            (br_table $switch-case$9 $switch-case$8 $switch-default$10
+              (i32.const -1)
+            )
+          )
+        )
+        (return
+          (local.get $$$0)
+        )
+        (br $switch$7)
+      )
+      (return
+        (local.get $$$0)
+      )
+    )
+    (return
+      (i32.const 0)
+    )
+  )
+  (func $global
+    (unreachable)
+    (drop (global.get $x))
+    (global.set $x (i32.const 1))
+  )
+  (func $ret (result i32)
+    (return
+      (i32.const 0)
+    )
+    (nop)
+    (i32.const 0)
+  )
+  (func $unreachable-br (result i32)
+    (block $out (result i32)
+      (br $out
+        (br $out (i32.const 0))
+      )
+    )
+  )
+  (func $unreachable-br-loop (result i32)
+    (loop $out
+      (br $out)
+    )
+  )
+ (func $unreachable-block-ends-switch (result i32)
+  (block $label$0 (result i32)
+   (block $label$3
+    (nop)
+    (br_table $label$3
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (i32.const 19)
+  )
+ )
+ (func $unreachable-block-ends-br_if (result i32)
+  (block $label$0 (result i32)
+   (block $label$2
+    (nop)
+    (br_if $label$2
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (i32.const 19)
+  )
+ )
+ (func $unreachable-brs-3 (result i32)
+  (block $label$0 (result i32)
+   (br $label$0
+    (memory.grow
+     (br $label$0
+      (i32.const 18)
+     )
+    )
+   )
+   (i32.const 21)
+  )
+ )
+ (func $unreachable-brs-4 (param $var$0 i32) (result i32)
+  (i32.add
+   (i32.const 1)
+   (block $label$0 (result i32)
+    (br $label$0
+     (block $label$1 (result i32) ;; this block is declared i32, but we can see it is unreachable
+      (drop
+       (br_if $label$0
+        (i32.const 4104)
+        (unreachable)
+       )
+      )
+      (i32.const 4)
+     )
+    )
+    (i32.const 16)
+   )
+  )
+ )
+ (func $call-unreach (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $2 i64)
+  (if (result i64)
+   (i64.eqz
+    (local.get $var$0)
+   )
+   (block $label$0 (result i64)
+    (local.get $var$1)
+   )
+   (block $label$1 (result i64)
+    (call $call-unreach
+     (i64.sub
+      (local.get $var$0)
+      (i64.const 1)
+     )
+     (i64.mul
+      (block (result i64)
+       (local.set $2
+        (local.get $var$0)
+       )
+       (nop)
+       (local.get $2)
+      )
+      (unreachable)
+     )
+    )
+   )
+  )
+ )
+ (func $br-gone-means-block-type-changes-then-refinalize-at-end-is-too-late (param $var$0 i32) (result i32)
+  (block $label$0 (result i32)
+   (br $label$0
+    (block (result i32)
+     (nop)
+     (drop
+      (br_if $label$0
+       (unreachable)
+       (local.get $var$0)
+      )
+     )
+     (i32.const 4)
+    )
+   )
+  )
+ )
+ (func $br-with-unreachable-value-should-not-give-a-block-a-value (param $var$0 i32) (result i32)
+  (block $label$0 (result i32)
+   (br $label$0
+    (block (result i32) ;; turns into unreachable when refinalized
+     (drop
+      (br_if $label$0
+       (i32.const 8)
+       (local.get $var$0)
+      )
+     )
+     (unreachable)
+    )
+   )
+   (i32.const 16)
+  )
+ )
+ (func $replace-br-value-of-i32-with-unreachable (result i32)
+  (block $label$0 (result i32)
+   (br $label$0
+    (block $label$1 (result i32)
+     (nop)
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $shorten-block-requires-sync-refinalize (param $var$0 i32) (param $var$1 i32)
+  (block $label$0
+   (unreachable)
+   (if
+    (unreachable)
+    (br_if $label$0
+     (local.get $var$1)
+    )
+   )
+  )
+ )
+ (func $block-with-type-but-is-unreachable (param $var$0 i32) (result i32)
+  (block $label$0 (result i32)
+   (br $label$0
+    (block $block (result i32)
+     (nop)
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $if-with-type-but-is-unreachable (param $var$0 i32) (result i32)
+  (block $label$0 (result i32)
+   (br $label$0
+    (if (result i32)
+     (local.get $var$0)
+     (unreachable)
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $unreachable-loop
+  (loop $label$2
+   (unreachable)
+   (br $label$2)
+  )
+ )
+ (func $br-block-from-unary (result i32)
+  (block $label$6 (result i32)
+   (i32.ctz
+    (block $label$7 (result i32)
+     (br $label$6
+      (i32.const 8)
+     )
+    )
+   )
+  )
+ )
+ (func $replace-unary-with-br-child
+  (drop
+   (block $label$6 (result i32)
+    (i32.ctz
+     (br $label$6
+      (i32.const 8)
+     )
+    )
+   )
+  )
+ )
+ (func $br_if-unreach-then-br_if-normal
+  (block $out
+    (nop)
+    (br_if $out
+      (unreachable)
+    )
+    (br_if $out
+      (i32.const 1)
+    )
+  )
+ )
+ (func $replace-with-unreachable-affects-parent (param $var$0 f32) (param $var$1 i64)
+  (block $top
+   (drop
+    (f32.load offset=4
+     (i64.ne
+      (i64.const 0)
+      (if (result i64)
+       (block (result i32)
+        (call $replace-with-unreachable-affects-parent
+         (f32.const 1)
+         (i64.const -15917430362925035)
+        )
+        (i32.const 1)
+       )
+       (unreachable)
+       (unreachable)
+      )
+     )
+    )
+   )
+   (nop) ;; this is not reachable due to the above code, so we replace it with unreachable. type should go to parent
+  )
+ )
+ (func $replace-block-changes-later-when-if-goes
+  (block $top ;; and so should this
+   (global.set $x
+    (i32.const 0)
+   )
+   (drop
+    (f32.load offset=4
+     (i64.ne
+      (block $inner (result i64) ;; this becomes unreachable
+       (drop
+        (call $helper
+         (f32.const 1)
+         (i64.const -15917430362925035)
+        )
+       )
+       (unreachable)
+      )
+      (i64.const 0)
+     )
+    )
+   )
+   (if
+    (i32.load16_s offset=22 align=1
+     (i32.const 0)
+    )
+    (br $top) ;; this keeps the block none after the inner block gets unreachable. but it will vanish into unreachable itself
+    (unreachable)
+   )
+  )
+ )
+ (func $helper (param $var$0 f32) (param $var$1 i64) (result i32)
+  (i32.const 0)
+ )
+)
+;; if goes to unreachable, need to propagate that up to the global.set
+(module
+ (global $global (mut f64) (f64.const 0))
+ (func $0
+  (global.set $global
+   (if (result f64)
+    (i32.const 0)
+    (unreachable)
+    (unreachable)
+   )
+  )
+ )
+)
+(module
+ (func $0
+  (local $local f64)
+  (local.set $local
+   (if (result f64)
+    (i32.const 0)
+    (unreachable)
+    (unreachable)
+   )
+  )
+ )
+)
+
+;; Exception handling instruction support
+;; If either try body or catch body is reachable, the whole try construct is
+;; reachable
+(module
+  (func $foo)
+  (event $e (attr 0))
+
+  (func $try_unreachable
+    (try
+      (do
+        (unreachable)
+      )
+      (catch
+        (drop
+          (pop exnref)
+        )
+      )
+    )
+    (call $foo) ;; shouldn't be dce'd
+  )
+
+  (func $catch_unreachable
+    (try
+      (do)
+      (catch
+        (unreachable)
+      )
+    )
+    (call $foo) ;; shouldn't be dce'd
+  )
+
+  (func $both_unreachable
+    (try
+      (do
+        (unreachable)
+      )
+      (catch
+        (unreachable)
+      )
+    )
+    (call $foo) ;; should be dce'd
+  )
+
+  (func $throw
+    (drop
+      (block $label$0 (result externref)
+        (if
+          (i32.clz
+            (block $label$1 (result i32)
+              (throw $e)
+            )
+          )
+          (nop)
+        )
+        (ref.null extern)
+      )
+    )
+  )
+
+  (func $rethrow
+    (drop
+      (block $label$0 (result externref)
+        (if
+          (i32.clz
+            (block $label$1 (result i32)
+              (rethrow
+                (ref.null exn)
+              )
+            )
+          )
+          (nop)
+        )
+        (ref.null extern)
+      )
+    )
+  )
+)
diff --git a/binaryen/test/passes/dce_vacuum.bin.txt b/binaryen/test/passes/dce_vacuum.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dce_vacuum.bin.txt
@@ -0,0 +1,98 @@
+(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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dce_vacuum.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.wasm b/binaryen/test/passes/dce_vacuum.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/dce_vacuum.wasm differ
diff --git a/binaryen/test/passes/dce_vacuum.wast b/binaryen/test/passes/dce_vacuum.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dce_vacuum.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/dealign.txt b/binaryen/test/passes/dealign.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dealign.txt
@@ -0,0 +1,33 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 1 1)
+ (func $test
+  (drop
+   (i32.load align=1
+    (i32.const 4)
+   )
+  )
+  (drop
+   (i32.load align=1
+    (i32.const 8)
+   )
+  )
+  (drop
+   (i32.load align=1
+    (i32.const 12)
+   )
+  )
+  (i32.store align=1
+   (i32.const 16)
+   (i32.const 28)
+  )
+  (i32.store align=1
+   (i32.const 20)
+   (i32.const 32)
+  )
+  (i32.store align=1
+   (i32.const 24)
+   (i32.const 36)
+  )
+ )
+)
diff --git a/binaryen/test/passes/dealign.wast b/binaryen/test/passes/dealign.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dealign.wast
@@ -0,0 +1,11 @@
+(module
+ (memory $0 1 1)
+ (func $test
+  (drop (i32.load         (i32.const 4)))
+  (drop (i32.load align=1 (i32.const 8)))
+  (drop (i32.load align=2 (i32.const 12)))
+  (i32.store         (i32.const 16) (i32.const 28))
+  (i32.store align=1 (i32.const 20) (i32.const 32))
+  (i32.store align=2 (i32.const 24) (i32.const 36))
+ )
+)
diff --git a/binaryen/test/passes/dealign64.passes b/binaryen/test/passes/dealign64.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dealign64.passes
@@ -0,0 +1,1 @@
+dealign_enable-memory64
diff --git a/binaryen/test/passes/dealign64.txt b/binaryen/test/passes/dealign64.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dealign64.txt
@@ -0,0 +1,33 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 i64 1 1)
+ (func $test
+  (drop
+   (i32.load align=1
+    (i64.const 4)
+   )
+  )
+  (drop
+   (i32.load align=1
+    (i64.const 8)
+   )
+  )
+  (drop
+   (i32.load align=1
+    (i64.const 12)
+   )
+  )
+  (i32.store align=1
+   (i64.const 16)
+   (i32.const 28)
+  )
+  (i32.store align=1
+   (i64.const 20)
+   (i32.const 32)
+  )
+  (i32.store align=1
+   (i64.const 24)
+   (i32.const 36)
+  )
+ )
+)
diff --git a/binaryen/test/passes/dealign64.wast b/binaryen/test/passes/dealign64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dealign64.wast
@@ -0,0 +1,11 @@
+(module
+ (memory $0 i64 1 1)
+ (func $test
+  (drop (i32.load         (i64.const 4)))
+  (drop (i32.load align=1 (i64.const 8)))
+  (drop (i32.load align=2 (i64.const 12)))
+  (i32.store         (i64.const 16) (i32.const 28))
+  (i32.store align=1 (i64.const 20) (i32.const 32))
+  (i32.store align=2 (i64.const 24) (i32.const 36))
+ )
+)
diff --git a/binaryen/test/passes/denan.txt b/binaryen/test/passes/denan.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/denan.txt
@@ -0,0 +1,157 @@
+(module
+ (type $f32_=>_f32 (func (param f32) (result f32)))
+ (type $f64_=>_f64 (func (param f64) (result f64)))
+ (type $i32_f32_i64_f64_=>_none (func (param i32 f32 i64 f64)))
+ (type $f32_f64_=>_none (func (param f32 f64)))
+ (global $global$1 (mut f32) (f32.const 0))
+ (global $global$2 (mut f32) (f32.const 12.34000015258789))
+ (func $foo32 (param $x f32) (result f32)
+  (local.set $x
+   (call $deNan32
+    (local.get $x)
+   )
+  )
+  (call $deNan32
+   (call $foo32
+    (local.get $x)
+   )
+  )
+ )
+ (func $foo64 (param $x f64) (result f64)
+  (local.set $x
+   (call $deNan64
+    (local.get $x)
+   )
+  )
+  (call $deNan64
+   (call $foo64
+    (local.get $x)
+   )
+  )
+ )
+ (func $various (param $x i32) (param $y f32) (param $z i64) (param $w f64)
+  (local.set $y
+   (call $deNan32
+    (local.get $y)
+   )
+  )
+  (local.set $w
+   (call $deNan64
+    (local.get $w)
+   )
+  )
+  (nop)
+ )
+ (func $ignore-local.get (param $f f32) (param $d f64)
+  (local.set $f
+   (call $deNan32
+    (local.get $f)
+   )
+  )
+  (local.set $d
+   (call $deNan64
+    (local.get $d)
+   )
+  )
+  (drop
+   (local.get $f)
+  )
+  (drop
+   (local.get $d)
+  )
+  (local.set $f
+   (local.get $f)
+  )
+  (local.set $d
+   (local.get $d)
+  )
+  (drop
+   (local.get $f)
+  )
+  (drop
+   (local.get $d)
+  )
+  (drop
+   (call $deNan32
+    (f32.abs
+     (local.get $f)
+    )
+   )
+  )
+  (drop
+   (call $deNan64
+    (f64.abs
+     (local.get $d)
+    )
+   )
+  )
+  (local.set $f
+   (call $deNan32
+    (f32.abs
+     (local.get $f)
+    )
+   )
+  )
+  (local.set $d
+   (call $deNan64
+    (f64.abs
+     (local.get $d)
+    )
+   )
+  )
+  (drop
+   (local.get $f)
+  )
+  (drop
+   (local.get $d)
+  )
+ )
+ (func $tees (param $x f32) (result f32)
+  (local.set $x
+   (call $deNan32
+    (local.get $x)
+   )
+  )
+  (local.tee $x
+   (local.tee $x
+    (local.tee $x
+     (local.tee $x
+      (local.get $x)
+     )
+    )
+   )
+  )
+ )
+ (func $select (param $x f32) (result f32)
+  (local.set $x
+   (call $deNan32
+    (local.get $x)
+   )
+  )
+  (select
+   (local.get $x)
+   (local.get $x)
+   (i32.const 1)
+  )
+ )
+ (func $deNan32 (param $0 f32) (result f32)
+  (if (result f32)
+   (f32.eq
+    (local.get $0)
+    (local.get $0)
+   )
+   (local.get $0)
+   (f32.const 0)
+  )
+ )
+ (func $deNan64 (param $0 f64) (result f64)
+  (if (result f64)
+   (f64.eq
+    (local.get $0)
+    (local.get $0)
+   )
+   (local.get $0)
+   (f64.const 0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/denan.wast b/binaryen/test/passes/denan.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/denan.wast
@@ -0,0 +1,37 @@
+(module
+  (global $global$1 (mut f32) (f32.const nan))
+  (global $global$2 (mut f32) (f32.const 12.34))
+  (func $foo32 (param $x f32) (result f32)
+    (call $foo32 (local.get $x))
+  )
+  (func $foo64 (param $x f64) (result f64)
+    (call $foo64 (local.get $x))
+  )
+  (func $various (param $x i32) (param $y f32) (param $z i64) (param $w f64)
+  )
+  (func $ignore-local.get (param $f f32) (param $d f64)
+    (drop (local.get $f))
+    (drop (local.get $d))
+    (local.set $f (local.get $f))
+    (local.set $d (local.get $d))
+    (drop (local.get $f))
+    (drop (local.get $d))
+    (drop (f32.abs (local.get $f)))
+    (drop (f64.abs (local.get $d)))
+    (local.set $f (f32.abs (local.get $f)))
+    (local.set $d (f64.abs (local.get $d)))
+    (drop (local.get $f))
+    (drop (local.get $d))
+  )
+  (func $tees (param $x f32) (result f32)
+    (local.tee $x
+      (local.tee $x
+        (local.tee $x
+          (local.tee $x
+            (local.get $x))))))
+  (func $select (param $x f32) (result f32)
+    (select
+      (local.get $x)
+      (local.get $x)
+      (i32.const 1)))
+)
diff --git a/binaryen/test/passes/directize_enable-tail-call.txt b/binaryen/test/passes/directize_enable-tail-call.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/directize_enable-tail-call.txt
@@ -0,0 +1,211 @@
+(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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/directize_enable-tail-call.wast
@@ -0,0 +1,209 @@
+(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/duplicate-function-elimination_all-features.txt b/binaryen/test/passes/duplicate-function-elimination_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/duplicate-function-elimination_all-features.txt
@@ -0,0 +1,20 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_funcref (func (result funcref)))
+ (func $0 (result i32)
+  (i32.const 0)
+ )
+ (func $test (result funcref)
+  (ref.func $0)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $foo 16 16)
+ (global $bar i32 (i32.const 0))
+ (export "memory" (memory $foo))
+ (export "global" (global $bar))
+ (func $bar
+  (nop)
+ )
+)
diff --git a/binaryen/test/passes/duplicate-function-elimination_all-features.wast b/binaryen/test/passes/duplicate-function-elimination_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/duplicate-function-elimination_all-features.wast
@@ -0,0 +1,23 @@
+;; --duplicate-function-elimination should not remove functions used in ref.func.
+(module
+  (func $0 (result i32)
+    (i32.const 0)
+  )
+  (func $1 (result i32)
+    (i32.const 0)
+  )
+  (func $test (result funcref)
+    (ref.func $1)
+  )
+)
+;; renaming after deduplication must only affect functions
+(module
+ (memory $foo 16 16)
+ (global $bar i32 (i32.const 0))
+ (export "memory" (memory $foo))
+ (export "global" (global $bar))
+ (func $bar ;; happens to share a name with the global
+ )
+ (func $foo ;; happens to share a name with the memory
+ )
+)
diff --git a/binaryen/test/passes/duplicate-function-elimination_optimize-level=1.txt b/binaryen/test/passes/duplicate-function-elimination_optimize-level=1.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/duplicate-function-elimination_optimize-level=1.txt
@@ -0,0 +1,1058 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (nop)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (nop)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (drop
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (drop
+   (i32.const 1)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (table $0 3 3 funcref)
+ (elem (i32.const 0) $keep2 $keep2 $caller)
+ (export "keep2" (func $keep2))
+ (export "other" (func $keep2))
+ (start $keep2)
+ (func $keep2
+  (nop)
+ )
+ (func $caller
+  (call $keep2)
+  (call $keep2)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2-after-two-passes
+  (nop)
+ )
+ (func $keep-caller
+  (call $keep2-after-two-passes)
+ )
+ (func $other-caller
+  (call $keep2-after-two-passes)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep-4
+  (nop)
+ )
+ (func $other
+  (unreachable)
+ )
+ (func $keep-caller
+  (call $keep-4)
+ )
+ (func $other-caller
+  (call $other)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 0)
+ (func $keep4-similar-but-func-sig-differs
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other1 (param $i i32)
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other2 (result i32)
+  (i32.const 0)
+ )
+)
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 0)
+ (func $keep2-similar-but-func-sig-differs (param $i i32)
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other2 (result i32)
+  (i32.const 0)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (nop)
+ )
+ (func $other
+  (nop)
+  (nop)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (block $block0
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (block $block0
+  )
+ )
+ (func $other
+  (block $block0
+   (nop)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (block $block0
+   (nop)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (block $block0
+   (nop)
+  )
+ )
+ (func $other
+  (block $block0
+   (nop)
+   (unreachable)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (block $block0
+   (nop)
+  )
+ )
+ (func $other
+  (block $block0
+   (unreachable)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase-since-block-names-do-not-matter
+  (block $foo
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase-since-block-names-do-not-matter
+  (block $foo
+   (br $foo)
+   (br_table $foo $foo
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (block $foo
+   (block $block
+    (drop
+     (i32.const 0)
+    )
+    (br $foo)
+   )
+  )
+ )
+ (func $other
+  (block $bar
+   (block $block
+    (drop
+     (i32.const 1)
+    )
+    (br $bar)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (block $foo
+   (br_if $foo
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (block $bar
+   (br_if $bar
+    (i32.const 1)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (block $foo
+   (br_if $foo
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (block $foo
+   (br_table $foo $foo
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (block $bar
+   (br_table $bar $bar
+    (i32.const 1)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (loop $bar
+   (nop)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (block $foo (result i32)
+    (br_table $foo $foo
+     (i32.const 0)
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $other
+  (drop
+   (block $bar (result i32)
+    (br_table $bar $bar
+     (i32.const 0)
+     (i32.const 1)
+    )
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (block $foo
+   (block $bar
+    (br_table $foo $bar
+     (i32.const 0)
+    )
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (block $foo
+   (block $bar
+    (br_table $foo $bar
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $other
+  (block $bar
+   (block $foo
+    (br_table $foo $bar
+     (i32.const 0)
+    )
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (call $erase)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2-but-in-theory-we-could-erase
+  (call $keep2-but-in-theory-we-could-erase)
+ )
+ (func $other
+  (call $other)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "i" (func $i))
+ (import "env" "j" (func $j))
+ (memory $0 0)
+ (func $erase
+  (call $i)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "i" (func $i))
+ (import "env" "j" (func $j))
+ (memory $0 0)
+ (func $keep2
+  (call $i)
+ )
+ (func $other
+  (call $j)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $erase $erase)
+ (func $erase
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $keep2 $other)
+ (func $keep2
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (call_indirect (type $none_=>_none)
+   (i32.const 1)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $keep2 $keep2)
+ (func $keep2
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase-even-locals-with-different-names
+  (local $i i32)
+  (drop
+   (local.get $i)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (local $i i32)
+  (drop
+   (local.get $i)
+  )
+ )
+ (func $other
+  (local $j i64)
+  (drop
+   (local.get $j)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase-even-locals-with-different-names
+  (local $i i32)
+  (local.set $i
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (local $i i32)
+  (local.set $i
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (local $j i64)
+  (local.set $j
+   (i64.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (local $i i32)
+  (local.set $i
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (local $j i32)
+  (local.set $j
+   (i32.const 1)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $erase
+  (drop
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.load16_s offset=3
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (drop
+   (i32.load offset=3
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (i32.load16_s offset=3
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (drop
+   (i32.load16_s offset=3
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (i32.load16_s offset=3 align=1
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (drop
+   (i32.load16_s
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (i32.load16_s offset=3
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (drop
+   (i32.load16_s offset=3
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (i32.load16_s offset=3
+    (i32.const 1)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (drop
+   (i32.load16_u offset=3
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (i32.load16_s offset=3
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $erase
+  (i32.store
+   (i32.const 0)
+   (i32.const 100)
+  )
+  (i32.store16 offset=3
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (i32.store offset=3
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+ (func $other
+  (i32.store16 offset=3
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (i32.store16 offset=3
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+ (func $other
+  (i32.store16 offset=3 align=1
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (i32.store16
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+ (func $other
+  (i32.store16 offset=3
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (i32.store16 offset=3
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+ (func $other
+  (i32.store16 offset=3
+   (i32.const 1)
+   (i32.const 100)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (i32.store16 offset=3
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+ (func $other
+  (i32.store16 offset=3
+   (i32.const 0)
+   (i32.const 101)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (drop
+   (i64.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (drop
+   (f32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (drop
+   (f64.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (i64.const 0)
+  )
+ )
+ (func $other
+  (drop
+   (i64.const 1)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (f32.const 0.10000000149011612)
+  )
+ )
+ (func $other
+  (drop
+   (f32.const -0.10000000149011612)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (f64.const 0.1)
+  )
+ )
+ (func $other
+  (drop
+   (f64.const 0.2)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (drop
+   (f32.abs
+    (f32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (f32.abs
+    (f32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (f32.abs
+    (f32.const 1)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (f32.abs
+    (f32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (f32.neg
+    (f32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (drop
+   (f32.add
+    (f32.const 0)
+    (f32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (f32.add
+    (f32.const 0)
+    (f32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (f32.add
+    (f32.const 0)
+    (f32.const 1)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (f32.add
+    (f32.const 0)
+    (f32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (f32.add
+    (f32.const 1)
+    (f32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (f32.add
+    (f32.const 0)
+    (f32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (f32.sub
+    (f32.const 0)
+    (f32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (select
+    (i32.const 1)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 2)
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 3)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (return)
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 0)
+ (func $erase (result i32)
+  (return
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 0)
+ (func $keep (result i32)
+  (return
+   (i32.const 0)
+  )
+ )
+ (func $other (result i32)
+  (return
+   (i32.const 1)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (drop
+   (memory.size)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (drop
+   (memory.grow
+    (i32.const 10)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep
+  (drop
+   (memory.grow
+    (i32.const 10)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (memory.grow
+    (i32.const 11)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep
+  (drop
+   (memory.size)
+  )
+ )
+ (func $other
+  (drop
+   (memory.grow
+    (i32.const 10)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/duplicate-function-elimination_optimize-level=1.wast b/binaryen/test/passes/duplicate-function-elimination_optimize-level=1.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/duplicate-function-elimination_optimize-level=1.wast
@@ -0,0 +1,1221 @@
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (nop)
+  )
+  (func $other (type $0)
+    (nop)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (nop)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.const 1)
+    )
+  )
+)
+(module
+  (memory 0)
+  (start $other)
+  (type $0 (func))
+  (export "keep2" $keep2)
+  (export "other" $other)
+  (table 3 3 funcref)
+  (elem (i32.const 0) $keep2 $other $caller)
+  (func $keep2 (type $0)
+    (nop)
+  )
+  (func $other (type $0)
+    (nop)
+  )
+  (func $caller (type $0)
+    (call $keep2)
+    (call $other)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2-after-two-passes (type $0)
+    (nop)
+  )
+  (func $other (type $0)
+    (nop)
+  )
+  (func $keep-caller (type $0)
+    (call $keep2-after-two-passes)
+  )
+  (func $other-caller (type $0)
+    (call $other)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep-4 (type $0)
+    (nop)
+  )
+  (func $other (type $0)
+    (unreachable)
+  )
+  (func $keep-caller (type $0)
+    (call $keep-4)
+  )
+  (func $other-caller (type $0)
+    (call $other)
+  )
+)
+(module
+  (memory 0)
+  (type $T (func (result i32)))
+  (type $S (func (result i32)))
+  (type $2 (func))
+  (type $3 (func (param i32)))
+  (func $keep4-similar-but-func-sig-differs (type $2)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other1 (type $3) (param $i i32)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other2 (type $T) (result i32)
+    (i32.const 0)
+  )
+  (func $other3 (type $S) (result i32)
+    (i32.const 0)
+  )
+)
+(module
+  (memory 0)
+  (type $S (func (result i32)))
+  (type $1 (func (param i32)))
+  (func $keep2-similar-but-func-sig-differs (type $1) (param $i i32)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other1 (type $1) (param $i i32)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other2 (type $S) (result i32)
+    (i32.const 0)
+  )
+  (func $other3 (type $S) (result i32)
+    (i32.const 0)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (nop)
+  )
+  (func $other (type $0)
+    (nop)
+    (nop)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (block $block0
+    )
+  )
+  (func $other (type $0)
+    (block $block0
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (block $block0
+    )
+  )
+  (func $other (type $0)
+    (block $block0
+      (nop)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (block $block0
+      (nop)
+    )
+  )
+  (func $other (type $0)
+    (block $block0
+      (nop)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (block $block0
+      (nop)
+    )
+  )
+  (func $other (type $0)
+    (block $block0
+      (nop)
+      (unreachable)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (block $block0
+      (nop)
+    )
+  )
+  (func $other (type $0)
+    (block $block0
+      (unreachable)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase-since-block-names-do-not-matter (type $0)
+    (block $foo
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase-since-block-names-do-not-matter (type $0)
+    (block $foo
+      (br $foo)
+      (br_table $foo $foo
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+      (br $bar)
+      (br_table $bar $bar
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (block $foo
+      (block
+        (drop
+          (i32.const 0)
+        )
+        (br $foo)
+      )
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+      (block
+        (drop
+          (i32.const 1)
+        )
+        (br $bar)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (block $foo
+      (br_if $foo
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+      (br_if $bar
+        (i32.const 1)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (block $foo
+      (br_if $foo
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+      (br_if $bar
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (block $foo
+      (br_table $foo $foo
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+      (br_table $bar $bar
+        (i32.const 1)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (loop $bar
+      (nop)
+    )
+  )
+  (func $other (type $0)
+    (loop $sjc
+      (nop)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (block $foo (result i32)
+        (br_table $foo $foo
+          (i32.const 0)
+          (i32.const 0)
+        )
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (block $bar (result i32)
+        (br_table $bar $bar
+          (i32.const 0)
+          (i32.const 1)
+        )
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (block $foo
+      (block $bar
+        (br_table $foo $bar
+          (i32.const 0)
+        )
+      )
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+      (block $foo
+        (br_table $bar $foo
+          (i32.const 0)
+        )
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (block $foo
+      (block $bar
+        (br_table $foo $bar
+          (i32.const 0)
+        )
+      )
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+      (block $foo
+        (br_table $foo $bar
+          (i32.const 0)
+        )
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (call $erase)
+  )
+  (func $other (type $0)
+    (call $erase)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2-but-in-theory-we-could-erase (type $0)
+    (call $keep2-but-in-theory-we-could-erase)
+  )
+  (func $other (type $0)
+    (call $other)
+  )
+)
+(module
+  (memory 0)
+  (type $FUNCSIG$v (func))
+  (import $i "env" "i")
+  (import $j "env" "j")
+  (func $erase (type $FUNCSIG$v)
+    (call $i)
+  )
+  (func $other (type $FUNCSIG$v)
+    (call $i)
+  )
+)
+(module
+  (memory 0)
+  (type $FUNCSIG$v (func))
+  (import $i "env" "i")
+  (import $j "env" "j")
+  (func $keep2 (type $FUNCSIG$v)
+    (call $i)
+  )
+  (func $other (type $FUNCSIG$v)
+    (call $j)
+  )
+)
+(module
+  (memory 0)
+  (type $T (func))
+  (table 2 2 funcref)
+  (elem (i32.const 0)  $erase $other)
+  (func $erase (type $T)
+    (call_indirect (type $T)
+      (i32.const 0)
+    )
+  )
+  (func $other (type $T)
+    (call_indirect (type $T)
+      (i32.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $T (func))
+  (table 2 2 funcref)
+  (elem (i32.const 0)  $keep2 $other)
+  (func $keep2 (type $T)
+    (call_indirect (type $T)
+      (i32.const 0)
+    )
+  )
+  (func $other (type $T)
+    (call_indirect (type $T)
+      (i32.const 1)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $T (func))
+  (type $S (func))
+  (table 2 2 funcref)
+  (elem (i32.const 0)  $keep2 $other)
+  (func $keep2 (type $T)
+    (call_indirect (type $T)
+      (i32.const 0)
+    )
+  )
+  (func $other (type $T)
+    (call_indirect (type $S)
+      (i32.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase-even-locals-with-different-names (type $0)
+    (local $i i32)
+    (drop
+      (local.get $i)
+    )
+  )
+  (func $other (type $0)
+    (local $j i32)
+    (drop
+      (local.get $j)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (local $i i32)
+    (drop
+      (local.get $i)
+    )
+  )
+  (func $other (type $0)
+    (local $j i64)
+    (drop
+      (local.get $j)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase-even-locals-with-different-names (type $0)
+    (local $i i32)
+    (local.set $i
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (local $j i32)
+    (local.set $j
+      (i32.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (local $i i32)
+    (local.set $i
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (local $j i64)
+    (local.set $j
+      (i64.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (local $i i32)
+    (local.set $i
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (local $j i32)
+    (local.set $j
+      (i32.const 1)
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $erase (type $0)
+    (drop
+      (i32.load
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.load16_s offset=3 align=2
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.load
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.load16_s offset=3 align=2
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.load offset=3
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.load16_s offset=3 align=2
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.load16_s offset=3
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.load16_s offset=3 align=1
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.load16_s align=2
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.load16_s offset=3 align=2
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.load16_s offset=3 align=2
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.load16_s offset=3 align=2
+        (i32.const 1)
+      )
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.load16_u offset=3 align=2
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.load16_s offset=3 align=2
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $erase (type $0)
+    (i32.store
+      (i32.const 0)
+      (i32.const 100)
+    )
+    (i32.store16 offset=3 align=2
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+  (func $other (type $0)
+    (i32.store
+      (i32.const 0)
+      (i32.const 100)
+    )
+    (i32.store16 offset=3 align=2
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (i32.store offset=3
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+  (func $other (type $0)
+    (i32.store16 offset=3 align=2
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (i32.store16 offset=3
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+  (func $other (type $0)
+    (i32.store16 offset=3 align=1
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (i32.store16 align=2
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+  (func $other (type $0)
+    (i32.store16 offset=3 align=2
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (i32.store16 offset=3 align=2
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+  (func $other (type $0)
+    (i32.store16 offset=3 align=2
+      (i32.const 1)
+      (i32.const 100)
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (i32.store16 offset=3 align=2
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+  (func $other (type $0)
+    (i32.store16 offset=3 align=2
+      (i32.const 0)
+      (i32.const 101)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i64.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f64.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i64.const 0)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i64.const 1)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (f32.const 0.10000000149011612)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.const -0.10000000149011612)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (f64.const 0.1)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f64.const 0.2)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (drop
+      (f32.abs
+        (f32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.abs
+        (f32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (f32.abs
+        (f32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.abs
+        (f32.const 1)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (f32.abs
+        (f32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.neg
+        (f32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (drop
+      (f32.add
+        (f32.const 0)
+        (f32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.add
+        (f32.const 0)
+        (f32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (f32.add
+        (f32.const 0)
+        (f32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.add
+        (f32.const 0)
+        (f32.const 1)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (f32.add
+        (f32.const 0)
+        (f32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.add
+        (f32.const 1)
+        (f32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (f32.add
+        (f32.const 0)
+        (f32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.sub
+        (f32.const 0)
+        (f32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 0)
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 0)
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep (type $0)
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 0)
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (select
+        (i32.const 1)
+        (i32.const 0)
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep (type $0)
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 0)
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 2)
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep (type $0)
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 0)
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 0)
+        (i32.const 3)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (return)
+  )
+  (func $other (type $0)
+    (return)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func (result i32)))
+  (func $erase (type $0) (result i32)
+    (return
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0) (result i32)
+    (return
+      (i32.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func (result i32)))
+  (func $keep (type $0) (result i32)
+    (return
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0) (result i32)
+    (return
+      (i32.const 1)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (drop
+      (memory.size)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (memory.size)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (drop
+      (memory.grow
+        (i32.const 10)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (memory.grow
+        (i32.const 10)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep (type $0)
+    (drop
+      (memory.grow
+        (i32.const 10)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (memory.grow
+        (i32.const 11)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep (type $0)
+    (drop
+      (memory.size)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (memory.grow
+        (i32.const 10)
+      )
+    )
+  )
+)
diff --git a/binaryen/test/passes/duplicate-function-elimination_optimize-level=2.txt b/binaryen/test/passes/duplicate-function-elimination_optimize-level=2.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/duplicate-function-elimination_optimize-level=2.txt
@@ -0,0 +1,1055 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (nop)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (nop)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (drop
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (drop
+   (i32.const 1)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (table $0 3 3 funcref)
+ (elem (i32.const 0) $keep2 $keep2 $caller)
+ (export "keep2" (func $keep2))
+ (export "other" (func $keep2))
+ (start $keep2)
+ (func $keep2
+  (nop)
+ )
+ (func $caller
+  (call $keep2)
+  (call $keep2)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2-after-two-passes
+  (nop)
+ )
+ (func $keep-caller
+  (call $keep2-after-two-passes)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep-4
+  (nop)
+ )
+ (func $other
+  (unreachable)
+ )
+ (func $keep-caller
+  (call $keep-4)
+ )
+ (func $other-caller
+  (call $other)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 0)
+ (func $keep4-similar-but-func-sig-differs
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other1 (param $i i32)
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other2 (result i32)
+  (i32.const 0)
+ )
+)
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 0)
+ (func $keep2-similar-but-func-sig-differs (param $i i32)
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other2 (result i32)
+  (i32.const 0)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (nop)
+ )
+ (func $other
+  (nop)
+  (nop)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (block $block0
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (block $block0
+  )
+ )
+ (func $other
+  (block $block0
+   (nop)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (block $block0
+   (nop)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (block $block0
+   (nop)
+  )
+ )
+ (func $other
+  (block $block0
+   (nop)
+   (unreachable)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (block $block0
+   (nop)
+  )
+ )
+ (func $other
+  (block $block0
+   (unreachable)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase-since-block-names-do-not-matter
+  (block $foo
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase-since-block-names-do-not-matter
+  (block $foo
+   (br $foo)
+   (br_table $foo $foo
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (block $foo
+   (block $block
+    (drop
+     (i32.const 0)
+    )
+    (br $foo)
+   )
+  )
+ )
+ (func $other
+  (block $bar
+   (block $block
+    (drop
+     (i32.const 1)
+    )
+    (br $bar)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (block $foo
+   (br_if $foo
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (block $bar
+   (br_if $bar
+    (i32.const 1)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (block $foo
+   (br_if $foo
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (block $foo
+   (br_table $foo $foo
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (block $bar
+   (br_table $bar $bar
+    (i32.const 1)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (loop $bar
+   (nop)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (block $foo (result i32)
+    (br_table $foo $foo
+     (i32.const 0)
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $other
+  (drop
+   (block $bar (result i32)
+    (br_table $bar $bar
+     (i32.const 0)
+     (i32.const 1)
+    )
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (block $foo
+   (block $bar
+    (br_table $foo $bar
+     (i32.const 0)
+    )
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (block $foo
+   (block $bar
+    (br_table $foo $bar
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $other
+  (block $bar
+   (block $foo
+    (br_table $foo $bar
+     (i32.const 0)
+    )
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (call $erase)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2-but-in-theory-we-could-erase
+  (call $keep2-but-in-theory-we-could-erase)
+ )
+ (func $other
+  (call $other)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "i" (func $i))
+ (import "env" "j" (func $j))
+ (memory $0 0)
+ (func $erase
+  (call $i)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "i" (func $i))
+ (import "env" "j" (func $j))
+ (memory $0 0)
+ (func $keep2
+  (call $i)
+ )
+ (func $other
+  (call $j)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $erase $erase)
+ (func $erase
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $keep2 $other)
+ (func $keep2
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (call_indirect (type $none_=>_none)
+   (i32.const 1)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $keep2 $keep2)
+ (func $keep2
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase-even-locals-with-different-names
+  (local $i i32)
+  (drop
+   (local.get $i)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (local $i i32)
+  (drop
+   (local.get $i)
+  )
+ )
+ (func $other
+  (local $j i64)
+  (drop
+   (local.get $j)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase-even-locals-with-different-names
+  (local $i i32)
+  (local.set $i
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (local $i i32)
+  (local.set $i
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (local $j i64)
+  (local.set $j
+   (i64.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (local $i i32)
+  (local.set $i
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (local $j i32)
+  (local.set $j
+   (i32.const 1)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $erase
+  (drop
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.load16_s offset=3
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (drop
+   (i32.load offset=3
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (i32.load16_s offset=3
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (drop
+   (i32.load16_s offset=3
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (i32.load16_s offset=3 align=1
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (drop
+   (i32.load16_s
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (i32.load16_s offset=3
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (drop
+   (i32.load16_s offset=3
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (i32.load16_s offset=3
+    (i32.const 1)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (drop
+   (i32.load16_u offset=3
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (i32.load16_s offset=3
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $erase
+  (i32.store
+   (i32.const 0)
+   (i32.const 100)
+  )
+  (i32.store16 offset=3
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (i32.store offset=3
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+ (func $other
+  (i32.store16 offset=3
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (i32.store16 offset=3
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+ (func $other
+  (i32.store16 offset=3 align=1
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (i32.store16
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+ (func $other
+  (i32.store16 offset=3
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (i32.store16 offset=3
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+ (func $other
+  (i32.store16 offset=3
+   (i32.const 1)
+   (i32.const 100)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 10)
+ (func $keep2
+  (i32.store16 offset=3
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+ (func $other
+  (i32.store16 offset=3
+   (i32.const 0)
+   (i32.const 101)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (drop
+   (i64.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (drop
+   (f32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $other
+  (drop
+   (f64.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (i64.const 0)
+  )
+ )
+ (func $other
+  (drop
+   (i64.const 1)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (f32.const 0.10000000149011612)
+  )
+ )
+ (func $other
+  (drop
+   (f32.const -0.10000000149011612)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (f64.const 0.1)
+  )
+ )
+ (func $other
+  (drop
+   (f64.const 0.2)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (drop
+   (f32.abs
+    (f32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (f32.abs
+    (f32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (f32.abs
+    (f32.const 1)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (f32.abs
+    (f32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (f32.neg
+    (f32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (drop
+   (f32.add
+    (f32.const 0)
+    (f32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (f32.add
+    (f32.const 0)
+    (f32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (f32.add
+    (f32.const 0)
+    (f32.const 1)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (f32.add
+    (f32.const 0)
+    (f32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (f32.add
+    (f32.const 1)
+    (f32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep2
+  (drop
+   (f32.add
+    (f32.const 0)
+    (f32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (f32.sub
+    (f32.const 0)
+    (f32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (select
+    (i32.const 1)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 2)
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 3)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (return)
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 0)
+ (func $erase (result i32)
+  (return
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 0)
+ (func $keep (result i32)
+  (return
+   (i32.const 0)
+  )
+ )
+ (func $other (result i32)
+  (return
+   (i32.const 1)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (drop
+   (memory.size)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $erase
+  (drop
+   (memory.grow
+    (i32.const 10)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep
+  (drop
+   (memory.grow
+    (i32.const 10)
+   )
+  )
+ )
+ (func $other
+  (drop
+   (memory.grow
+    (i32.const 11)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $keep
+  (drop
+   (memory.size)
+  )
+ )
+ (func $other
+  (drop
+   (memory.grow
+    (i32.const 10)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/duplicate-function-elimination_optimize-level=2.wast b/binaryen/test/passes/duplicate-function-elimination_optimize-level=2.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/duplicate-function-elimination_optimize-level=2.wast
@@ -0,0 +1,1221 @@
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (nop)
+  )
+  (func $other (type $0)
+    (nop)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (nop)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.const 1)
+    )
+  )
+)
+(module
+  (memory 0)
+  (start $other)
+  (type $0 (func))
+  (export "keep2" $keep2)
+  (export "other" $other)
+  (table 3 3 funcref)
+  (elem (i32.const 0) $keep2 $other $caller)
+  (func $keep2 (type $0)
+    (nop)
+  )
+  (func $other (type $0)
+    (nop)
+  )
+  (func $caller (type $0)
+    (call $keep2)
+    (call $other)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2-after-two-passes (type $0)
+    (nop)
+  )
+  (func $other (type $0)
+    (nop)
+  )
+  (func $keep-caller (type $0)
+    (call $keep2-after-two-passes)
+  )
+  (func $other-caller (type $0)
+    (call $other)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep-4 (type $0)
+    (nop)
+  )
+  (func $other (type $0)
+    (unreachable)
+  )
+  (func $keep-caller (type $0)
+    (call $keep-4)
+  )
+  (func $other-caller (type $0)
+    (call $other)
+  )
+)
+(module
+  (memory 0)
+  (type $T (func (result i32)))
+  (type $S (func (result i32)))
+  (type $2 (func))
+  (type $3 (func (param i32)))
+  (func $keep4-similar-but-func-sig-differs (type $2)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other1 (type $3) (param $i i32)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other2 (type $T) (result i32)
+    (i32.const 0)
+  )
+  (func $other3 (type $S) (result i32)
+    (i32.const 0)
+  )
+)
+(module
+  (memory 0)
+  (type $S (func (result i32)))
+  (type $1 (func (param i32)))
+  (func $keep2-similar-but-func-sig-differs (type $1) (param $i i32)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other1 (type $1) (param $i i32)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other2 (type $S) (result i32)
+    (i32.const 0)
+  )
+  (func $other3 (type $S) (result i32)
+    (i32.const 0)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (nop)
+  )
+  (func $other (type $0)
+    (nop)
+    (nop)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (block $block0
+    )
+  )
+  (func $other (type $0)
+    (block $block0
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (block $block0
+    )
+  )
+  (func $other (type $0)
+    (block $block0
+      (nop)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (block $block0
+      (nop)
+    )
+  )
+  (func $other (type $0)
+    (block $block0
+      (nop)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (block $block0
+      (nop)
+    )
+  )
+  (func $other (type $0)
+    (block $block0
+      (nop)
+      (unreachable)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (block $block0
+      (nop)
+    )
+  )
+  (func $other (type $0)
+    (block $block0
+      (unreachable)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase-since-block-names-do-not-matter (type $0)
+    (block $foo
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase-since-block-names-do-not-matter (type $0)
+    (block $foo
+      (br $foo)
+      (br_table $foo $foo
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+      (br $bar)
+      (br_table $bar $bar
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (block $foo
+      (block
+        (drop
+          (i32.const 0)
+        )
+        (br $foo)
+      )
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+      (block
+        (drop
+          (i32.const 1)
+        )
+        (br $bar)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (block $foo
+      (br_if $foo
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+      (br_if $bar
+        (i32.const 1)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (block $foo
+      (br_if $foo
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+      (br_if $bar
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (block $foo
+      (br_table $foo $foo
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+      (br_table $bar $bar
+        (i32.const 1)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (loop $bar
+      (nop)
+    )
+  )
+  (func $other (type $0)
+    (loop $sjc
+      (nop)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (block $foo (result i32)
+        (br_table $foo $foo
+          (i32.const 0)
+          (i32.const 0)
+        )
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (block $bar (result i32)
+        (br_table $bar $bar
+          (i32.const 0)
+          (i32.const 1)
+        )
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (block $foo
+      (block $bar
+        (br_table $foo $bar
+          (i32.const 0)
+        )
+      )
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+      (block $foo
+        (br_table $bar $foo
+          (i32.const 0)
+        )
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (block $foo
+      (block $bar
+        (br_table $foo $bar
+          (i32.const 0)
+        )
+      )
+    )
+  )
+  (func $other (type $0)
+    (block $bar
+      (block $foo
+        (br_table $foo $bar
+          (i32.const 0)
+        )
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (call $erase)
+  )
+  (func $other (type $0)
+    (call $erase)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2-but-in-theory-we-could-erase (type $0)
+    (call $keep2-but-in-theory-we-could-erase)
+  )
+  (func $other (type $0)
+    (call $other)
+  )
+)
+(module
+  (memory 0)
+  (type $FUNCSIG$v (func))
+  (import $i "env" "i")
+  (import $j "env" "j")
+  (func $erase (type $FUNCSIG$v)
+    (call $i)
+  )
+  (func $other (type $FUNCSIG$v)
+    (call $i)
+  )
+)
+(module
+  (memory 0)
+  (type $FUNCSIG$v (func))
+  (import $i "env" "i")
+  (import $j "env" "j")
+  (func $keep2 (type $FUNCSIG$v)
+    (call $i)
+  )
+  (func $other (type $FUNCSIG$v)
+    (call $j)
+  )
+)
+(module
+  (memory 0)
+  (type $T (func))
+  (table 2 2 funcref)
+  (elem (i32.const 0)  $erase $other)
+  (func $erase (type $T)
+    (call_indirect (type $T)
+      (i32.const 0)
+    )
+  )
+  (func $other (type $T)
+    (call_indirect (type $T)
+      (i32.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $T (func))
+  (table 2 2 funcref)
+  (elem (i32.const 0)  $keep2 $other)
+  (func $keep2 (type $T)
+    (call_indirect (type $T)
+      (i32.const 0)
+    )
+  )
+  (func $other (type $T)
+    (call_indirect (type $T)
+      (i32.const 1)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $T (func))
+  (type $S (func))
+  (table 2 2 funcref)
+  (elem (i32.const 0)  $keep2 $other)
+  (func $keep2 (type $T)
+    (call_indirect (type $T)
+      (i32.const 0)
+    )
+  )
+  (func $other (type $T)
+    (call_indirect (type $S)
+      (i32.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase-even-locals-with-different-names (type $0)
+    (local $i i32)
+    (drop
+      (local.get $i)
+    )
+  )
+  (func $other (type $0)
+    (local $j i32)
+    (drop
+      (local.get $j)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (local $i i32)
+    (drop
+      (local.get $i)
+    )
+  )
+  (func $other (type $0)
+    (local $j i64)
+    (drop
+      (local.get $j)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase-even-locals-with-different-names (type $0)
+    (local $i i32)
+    (local.set $i
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (local $j i32)
+    (local.set $j
+      (i32.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (local $i i32)
+    (local.set $i
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (local $j i64)
+    (local.set $j
+      (i64.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (local $i i32)
+    (local.set $i
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (local $j i32)
+    (local.set $j
+      (i32.const 1)
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $erase (type $0)
+    (drop
+      (i32.load
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.load16_s offset=3 align=2
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.load
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.load16_s offset=3 align=2
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.load offset=3
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.load16_s offset=3 align=2
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.load16_s offset=3
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.load16_s offset=3 align=1
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.load16_s align=2
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.load16_s offset=3 align=2
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.load16_s offset=3 align=2
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.load16_s offset=3 align=2
+        (i32.const 1)
+      )
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.load16_u offset=3 align=2
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i32.load16_s offset=3 align=2
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $erase (type $0)
+    (i32.store
+      (i32.const 0)
+      (i32.const 100)
+    )
+    (i32.store16 offset=3 align=2
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+  (func $other (type $0)
+    (i32.store
+      (i32.const 0)
+      (i32.const 100)
+    )
+    (i32.store16 offset=3 align=2
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (i32.store offset=3
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+  (func $other (type $0)
+    (i32.store16 offset=3 align=2
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (i32.store16 offset=3
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+  (func $other (type $0)
+    (i32.store16 offset=3 align=1
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (i32.store16 align=2
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+  (func $other (type $0)
+    (i32.store16 offset=3 align=2
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (i32.store16 offset=3 align=2
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+  (func $other (type $0)
+    (i32.store16 offset=3 align=2
+      (i32.const 1)
+      (i32.const 100)
+    )
+  )
+)
+(module
+  (memory 10)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (i32.store16 offset=3 align=2
+      (i32.const 0)
+      (i32.const 100)
+    )
+  )
+  (func $other (type $0)
+    (i32.store16 offset=3 align=2
+      (i32.const 0)
+      (i32.const 101)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i64.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f64.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (i64.const 0)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (i64.const 1)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (f32.const 0.10000000149011612)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.const -0.10000000149011612)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (f64.const 0.1)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f64.const 0.2)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (drop
+      (f32.abs
+        (f32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.abs
+        (f32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (f32.abs
+        (f32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.abs
+        (f32.const 1)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (f32.abs
+        (f32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.neg
+        (f32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (drop
+      (f32.add
+        (f32.const 0)
+        (f32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.add
+        (f32.const 0)
+        (f32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (f32.add
+        (f32.const 0)
+        (f32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.add
+        (f32.const 0)
+        (f32.const 1)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (f32.add
+        (f32.const 0)
+        (f32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.add
+        (f32.const 1)
+        (f32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep2 (type $0)
+    (drop
+      (f32.add
+        (f32.const 0)
+        (f32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (f32.sub
+        (f32.const 0)
+        (f32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 0)
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 0)
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep (type $0)
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 0)
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (select
+        (i32.const 1)
+        (i32.const 0)
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep (type $0)
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 0)
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 2)
+        (i32.const 0)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep (type $0)
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 0)
+        (i32.const 0)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 0)
+        (i32.const 3)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (return)
+  )
+  (func $other (type $0)
+    (return)
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func (result i32)))
+  (func $erase (type $0) (result i32)
+    (return
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0) (result i32)
+    (return
+      (i32.const 0)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func (result i32)))
+  (func $keep (type $0) (result i32)
+    (return
+      (i32.const 0)
+    )
+  )
+  (func $other (type $0) (result i32)
+    (return
+      (i32.const 1)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (drop
+      (memory.size)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (memory.size)
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $erase (type $0)
+    (drop
+      (memory.grow
+        (i32.const 10)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (memory.grow
+        (i32.const 10)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep (type $0)
+    (drop
+      (memory.grow
+        (i32.const 10)
+      )
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (memory.grow
+        (i32.const 11)
+      )
+    )
+  )
+)
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $keep (type $0)
+    (drop
+      (memory.size)
+    )
+  )
+  (func $other (type $0)
+    (drop
+      (memory.grow
+        (i32.const 10)
+      )
+    )
+  )
+)
diff --git a/binaryen/test/passes/duplicate-import-elimination.txt b/binaryen/test/passes/duplicate-import-elimination.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/duplicate-import-elimination.txt
@@ -0,0 +1,17 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (import "env" "waka" (func $foo))
+ (import "env" "waka" (func $wrong (param i32)))
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $foo $foo)
+ (export "baz" (func $0))
+ (start $foo)
+ (func $0
+  (call $foo)
+  (call $foo)
+  (call $wrong
+   (i32.const 1)
+  )
+ )
+)
diff --git a/binaryen/test/passes/duplicate-import-elimination.wast b/binaryen/test/passes/duplicate-import-elimination.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/duplicate-import-elimination.wast
@@ -0,0 +1,14 @@
+(module
+  (import "env" "waka" (func $foo))
+  (import "env" "waka" (func $bar))
+  (import "env" "waka" (func $wrong (param i32)))
+  (table 2 2 funcref)
+  (elem (i32.const 0) $foo $bar)
+  (start $bar)
+  (func "baz"
+    (call $foo)
+    (call $bar)
+    (call $wrong (i32.const 1))
+  )
+)
+
diff --git a/binaryen/test/passes/dwarf-local-order.bin.txt b/binaryen/test/passes/dwarf-local-order.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dwarf-local-order.bin.txt
@@ -0,0 +1,703 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 256 256)
+ (table $0 1 1 funcref)
+ (global $global$0 (mut i32) (i32.const 5243904))
+ (global $global$1 i32 (i32.const 1024))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "foo" (func $foo))
+ (export "__data_end" (global $global$1))
+ (func $__wasm_call_ctors
+ )
+ (func $foo (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 f32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 f32)
+  (local $8 f32)
+  (local $9 f32)
+  (local $10 i32)
+  (local $11 f32)
+  (local $12 f32)
+  (local $13 f32)
+  (local $14 f32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (local $19 i32)
+  (local $20 i32)
+  (local.set $0
+   (global.get $global$0)
+  )
+  (local.set $1
+   (i32.const 16)
+  )
+  (local.set $2
+   (i32.sub
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (local.set $3
+   (i32.const 3)
+  )
+  (local.set $4
+   (f32.const 2)
+  )
+  (local.set $5
+   (i32.const 1)
+  )
+  (i32.store offset=12
+   (local.get $2)
+   (local.get $5)
+  )
+  (f32.store offset=8
+   (local.get $2)
+   (local.get $4)
+  )
+  (i32.store offset=4
+   (local.get $2)
+   (local.get $3)
+  )
+  (local.set $6
+   (i32.load offset=12
+    (local.get $2)
+   )
+  )
+  (local.set $7
+   (f32.convert_i32_s
+    (local.get $6)
+   )
+  )
+  (local.set $8
+   (f32.load offset=8
+    (local.get $2)
+   )
+  )
+  (local.set $9
+   (f32.add
+    (local.get $7)
+    (local.get $8)
+   )
+  )
+  (local.set $10
+   (i32.load offset=4
+    (local.get $2)
+   )
+  )
+  (local.set $11
+   (f32.convert_i32_s
+    (local.get $10)
+   )
+  )
+  (local.set $12
+   (f32.add
+    (local.get $9)
+    (local.get $11)
+   )
+  )
+  (local.set $13
+   (f32.abs
+    (local.get $12)
+   )
+  )
+  (local.set $14
+   (f32.const 2147483648)
+  )
+  (local.set $15
+   (f32.lt
+    (local.get $13)
+    (local.get $14)
+   )
+  )
+  (local.set $16
+   (i32.eqz
+    (local.get $15)
+   )
+  )
+  (block $label$1
+   (block $label$2
+    (br_if $label$2
+     (local.get $16)
+    )
+    (local.set $17
+     (i32.trunc_f32_s
+      (local.get $12)
+     )
+    )
+    (local.set $18
+     (local.get $17)
+    )
+    (br $label$1)
+   )
+   (local.set $19
+    (i32.const -2147483648)
+   )
+   (local.set $18
+    (local.get $19)
+   )
+  )
+  (local.set $20
+   (local.get $18)
+  )
+  (return
+   (local.get $20)
+  )
+ )
+ ;; custom section ".debug_info", size 120
+ ;; custom section ".debug_abbrev", size 67
+ ;; custom section ".debug_line", size 94
+ ;; custom section ".debug_str", size 201
+ ;; custom section "producers", size 172
+)
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 256 256)
+ (table $0 1 1 funcref)
+ (global $global$0 (mut i32) (i32.const 5243904))
+ (global $global$1 i32 (i32.const 1024))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "foo" (func $foo))
+ (export "__data_end" (global $global$1))
+ (func $__wasm_call_ctors
+ )
+ (func $foo (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 f32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 f32)
+  (local $8 f32)
+  (local $9 f32)
+  (local $10 i32)
+  (local $11 f32)
+  (local $12 f32)
+  (local $13 f32)
+  (local $14 f32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (local $19 i32)
+  (local $20 i32)
+  ;; code offset: 0x33
+  (local.set $0
+   ;; code offset: 0x31
+   (global.get $global$0)
+  )
+  ;; code offset: 0x37
+  (local.set $1
+   ;; code offset: 0x35
+   (i32.const 16)
+  )
+  ;; code offset: 0x3e
+  (local.set $2
+   ;; code offset: 0x3d
+   (i32.sub
+    ;; code offset: 0x39
+    (local.get $0)
+    ;; code offset: 0x3b
+    (local.get $1)
+   )
+  )
+  ;; code offset: 0x42
+  (local.set $3
+   ;; code offset: 0x40
+   (i32.const 3)
+  )
+  ;; code offset: 0x49
+  (local.set $4
+   ;; code offset: 0x44
+   (f32.const 2)
+  )
+  ;; code offset: 0x4d
+  (local.set $5
+   ;; code offset: 0x4b
+   (i32.const 1)
+  )
+  ;; code offset: 0x53
+  (i32.store offset=12
+   ;; code offset: 0x4f
+   (local.get $2)
+   ;; code offset: 0x51
+   (local.get $5)
+  )
+  ;; code offset: 0x5a
+  (f32.store offset=8
+   ;; code offset: 0x56
+   (local.get $2)
+   ;; code offset: 0x58
+   (local.get $4)
+  )
+  ;; code offset: 0x61
+  (i32.store offset=4
+   ;; code offset: 0x5d
+   (local.get $2)
+   ;; code offset: 0x5f
+   (local.get $3)
+  )
+  ;; code offset: 0x69
+  (local.set $6
+   ;; code offset: 0x66
+   (i32.load offset=12
+    ;; code offset: 0x64
+    (local.get $2)
+   )
+  )
+  ;; code offset: 0x6e
+  (local.set $7
+   ;; code offset: 0x6d
+   (f32.convert_i32_s
+    ;; code offset: 0x6b
+    (local.get $6)
+   )
+  )
+  ;; code offset: 0x75
+  (local.set $8
+   ;; code offset: 0x72
+   (f32.load offset=8
+    ;; code offset: 0x70
+    (local.get $2)
+   )
+  )
+  ;; code offset: 0x7c
+  (local.set $9
+   ;; code offset: 0x7b
+   (f32.add
+    ;; code offset: 0x77
+    (local.get $7)
+    ;; code offset: 0x79
+    (local.get $8)
+   )
+  )
+  ;; code offset: 0x83
+  (local.set $10
+   ;; code offset: 0x80
+   (i32.load offset=4
+    ;; code offset: 0x7e
+    (local.get $2)
+   )
+  )
+  ;; code offset: 0x88
+  (local.set $11
+   ;; code offset: 0x87
+   (f32.convert_i32_s
+    ;; code offset: 0x85
+    (local.get $10)
+   )
+  )
+  ;; code offset: 0x8f
+  (local.set $12
+   ;; code offset: 0x8e
+   (f32.add
+    ;; code offset: 0x8a
+    (local.get $9)
+    ;; code offset: 0x8c
+    (local.get $11)
+   )
+  )
+  ;; code offset: 0x94
+  (local.set $13
+   ;; code offset: 0x93
+   (f32.abs
+    ;; code offset: 0x91
+    (local.get $12)
+   )
+  )
+  ;; code offset: 0x9b
+  (local.set $14
+   ;; code offset: 0x96
+   (f32.const 2147483648)
+  )
+  ;; code offset: 0xa2
+  (local.set $15
+   ;; code offset: 0xa1
+   (f32.lt
+    ;; code offset: 0x9d
+    (local.get $13)
+    ;; code offset: 0x9f
+    (local.get $14)
+   )
+  )
+  ;; code offset: 0xa7
+  (local.set $16
+   ;; code offset: 0xa6
+   (i32.eqz
+    ;; code offset: 0xa4
+    (local.get $15)
+   )
+  )
+  ;; code offset: 0xa9
+  (block $label$1
+   (block $label$2
+    ;; code offset: 0xaf
+    (br_if $label$2
+     ;; code offset: 0xad
+     (local.get $16)
+    )
+    ;; code offset: 0xb4
+    (local.set $17
+     ;; code offset: 0xb3
+     (i32.trunc_f32_s
+      ;; code offset: 0xb1
+      (local.get $12)
+     )
+    )
+    ;; code offset: 0xb8
+    (local.set $18
+     ;; code offset: 0xb6
+     (local.get $17)
+    )
+    ;; code offset: 0xba
+    (br $label$1)
+   )
+   ;; code offset: 0xc3
+   (local.set $19
+    ;; code offset: 0xbd
+    (i32.const -2147483648)
+   )
+   ;; code offset: 0xc7
+   (local.set $18
+    ;; code offset: 0xc5
+    (local.get $19)
+   )
+  )
+  ;; code offset: 0xcc
+  (local.set $20
+   ;; code offset: 0xca
+   (local.get $18)
+  )
+  ;; code offset: 0xd0
+  (return
+   ;; code offset: 0xce
+   (local.get $20)
+  )
+ )
+ ;; custom section ".debug_info", size 120
+ ;; custom section ".debug_abbrev", size 67
+ ;; custom section ".debug_line", size 37
+ ;; custom section ".debug_str", size 201
+ ;; custom section "producers", size 172
+)
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 256 256)
+ (table $0 1 1 funcref)
+ (global $global$0 (mut i32) (i32.const 5243904))
+ (global $global$1 i32 (i32.const 1024))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "foo" (func $foo))
+ (export "__data_end" (global $global$1))
+ (func $__wasm_call_ctors
+ )
+ (func $foo (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 f32)
+  (local $14 f32)
+  (local $15 f32)
+  (local $16 f32)
+  (local $17 f32)
+  (local $18 f32)
+  (local $19 f32)
+  (local $20 f32)
+  (local.set $0
+   (global.get $global$0)
+  )
+  (local.set $1
+   (i32.const 16)
+  )
+  (local.set $2
+   (i32.sub
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (local.set $3
+   (i32.const 3)
+  )
+  (local.set $13
+   (f32.const 2)
+  )
+  (local.set $4
+   (i32.const 1)
+  )
+  (i32.store offset=12
+   (local.get $2)
+   (local.get $4)
+  )
+  (f32.store offset=8
+   (local.get $2)
+   (local.get $13)
+  )
+  (i32.store offset=4
+   (local.get $2)
+   (local.get $3)
+  )
+  (local.set $5
+   (i32.load offset=12
+    (local.get $2)
+   )
+  )
+  (local.set $14
+   (f32.convert_i32_s
+    (local.get $5)
+   )
+  )
+  (local.set $15
+   (f32.load offset=8
+    (local.get $2)
+   )
+  )
+  (local.set $16
+   (f32.add
+    (local.get $14)
+    (local.get $15)
+   )
+  )
+  (local.set $6
+   (i32.load offset=4
+    (local.get $2)
+   )
+  )
+  (local.set $17
+   (f32.convert_i32_s
+    (local.get $6)
+   )
+  )
+  (local.set $18
+   (f32.add
+    (local.get $16)
+    (local.get $17)
+   )
+  )
+  (local.set $19
+   (f32.abs
+    (local.get $18)
+   )
+  )
+  (local.set $20
+   (f32.const 2147483648)
+  )
+  (local.set $7
+   (f32.lt
+    (local.get $19)
+    (local.get $20)
+   )
+  )
+  (local.set $8
+   (i32.eqz
+    (local.get $7)
+   )
+  )
+  (block $label$1
+   (block $label$2
+    (br_if $label$2
+     (local.get $8)
+    )
+    (local.set $9
+     (i32.trunc_f32_s
+      (local.get $18)
+     )
+    )
+    (local.set $10
+     (local.get $9)
+    )
+    (br $label$1)
+   )
+   (local.set $11
+    (i32.const -2147483648)
+   )
+   (local.set $10
+    (local.get $11)
+   )
+  )
+  (local.set $12
+   (local.get $10)
+  )
+  (return
+   (local.get $12)
+  )
+ )
+ ;; custom section "producers", size 172
+)
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 256 256)
+ (table $0 1 1 funcref)
+ (global $global$0 (mut i32) (i32.const 5243904))
+ (global $global$1 i32 (i32.const 1024))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "foo" (func $foo))
+ (export "__data_end" (global $global$1))
+ (func $__wasm_call_ctors
+ )
+ (func $foo (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 f32)
+  (local $14 f32)
+  (local $15 f32)
+  (local $16 f32)
+  (local $17 f32)
+  (local $18 f32)
+  (local $19 f32)
+  (local $20 f32)
+  (local.set $0
+   (global.get $global$0)
+  )
+  (local.set $1
+   (i32.const 16)
+  )
+  (local.set $2
+   (i32.sub
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (local.set $3
+   (i32.const 3)
+  )
+  (local.set $13
+   (f32.const 2)
+  )
+  (local.set $4
+   (i32.const 1)
+  )
+  (i32.store offset=12
+   (local.get $2)
+   (local.get $4)
+  )
+  (f32.store offset=8
+   (local.get $2)
+   (local.get $13)
+  )
+  (i32.store offset=4
+   (local.get $2)
+   (local.get $3)
+  )
+  (local.set $5
+   (i32.load offset=12
+    (local.get $2)
+   )
+  )
+  (local.set $14
+   (f32.convert_i32_s
+    (local.get $5)
+   )
+  )
+  (local.set $15
+   (f32.load offset=8
+    (local.get $2)
+   )
+  )
+  (local.set $16
+   (f32.add
+    (local.get $14)
+    (local.get $15)
+   )
+  )
+  (local.set $6
+   (i32.load offset=4
+    (local.get $2)
+   )
+  )
+  (local.set $17
+   (f32.convert_i32_s
+    (local.get $6)
+   )
+  )
+  (local.set $18
+   (f32.add
+    (local.get $16)
+    (local.get $17)
+   )
+  )
+  (local.set $19
+   (f32.abs
+    (local.get $18)
+   )
+  )
+  (local.set $20
+   (f32.const 2147483648)
+  )
+  (local.set $7
+   (f32.lt
+    (local.get $19)
+    (local.get $20)
+   )
+  )
+  (local.set $8
+   (i32.eqz
+    (local.get $7)
+   )
+  )
+  (block $label$1
+   (block $label$2
+    (br_if $label$2
+     (local.get $8)
+    )
+    (local.set $9
+     (i32.trunc_f32_s
+      (local.get $18)
+     )
+    )
+    (local.set $10
+     (local.get $9)
+    )
+    (br $label$1)
+   )
+   (local.set $11
+    (i32.const -2147483648)
+   )
+   (local.set $10
+    (local.get $11)
+   )
+  )
+  (local.set $12
+   (local.get $10)
+  )
+  (return
+   (local.get $12)
+  )
+ )
+ ;; custom section "producers", size 172
+)
diff --git a/binaryen/test/passes/dwarf-local-order.passes b/binaryen/test/passes/dwarf-local-order.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dwarf-local-order.passes
@@ -0,0 +1,1 @@
+g_print_roundtrip_print_strip-dwarf_roundtrip_print
diff --git a/binaryen/test/passes/dwarf-local-order.wasm b/binaryen/test/passes/dwarf-local-order.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/dwarf-local-order.wasm differ
diff --git a/binaryen/test/passes/dwarf_unit_with_no_abbrevs_noprint.bin.txt b/binaryen/test/passes/dwarf_unit_with_no_abbrevs_noprint.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dwarf_unit_with_no_abbrevs_noprint.bin.txt
diff --git a/binaryen/test/passes/dwarf_unit_with_no_abbrevs_noprint.passes b/binaryen/test/passes/dwarf_unit_with_no_abbrevs_noprint.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dwarf_unit_with_no_abbrevs_noprint.passes
@@ -0,0 +1,1 @@
+roundtrip_g
diff --git a/binaryen/test/passes/dwarf_unit_with_no_abbrevs_noprint.wasm b/binaryen/test/passes/dwarf_unit_with_no_abbrevs_noprint.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/dwarf_unit_with_no_abbrevs_noprint.wasm differ
diff --git a/binaryen/test/passes/dwarfdump.bin.txt b/binaryen/test/passes/dwarfdump.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dwarfdump.bin.txt
@@ -0,0 +1,137 @@
+DWARF debug info
+================
+
+Contains section .debug_info (58 bytes)
+Contains section .debug_abbrev (39 bytes)
+Contains section .debug_line (56 bytes)
+Contains section .debug_str (212 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+[2] DW_TAG_subprogram	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_external	DW_FORM_flag_present
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x00000036 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x0000003a)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project f2e65447b3cb6340883957e033e77095a025ebdc)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000095] = "a.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x0000009b] = "/usr/local/google/home/azakai/Dev/emscripten")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000005)
+              DW_AT_high_pc [DW_FORM_data4]	(0x00000002)
+
+0x00000026:   DW_TAG_subprogram [2]  
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000005)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000002)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x000000c8] = "_Z3foov")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d0] = "foo")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/a.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(3)
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000039:   NULL
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x00000034
+         version: 4
+ prologue_length: 0x0000001d
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "a.cpp"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000027: 00 DW_LNE_set_address (0x0000000000000005)
+0x0000002e: 14 address += 0,  line += 2
+            0x0000000000000005      3      0      1   0             0  is_stmt
+
+0x0000002f: 05 DW_LNS_set_column (1)
+0x00000031: 0a DW_LNS_set_prologue_end
+0x00000032: 21 address += 1,  line += 1
+            0x0000000000000006      4      1      1   0             0  is_stmt prologue_end
+
+0x00000033: 02 DW_LNS_advance_pc (1)
+0x00000035: 00 DW_LNE_end_sequence
+            0x0000000000000007      4      1      1   0             0  is_stmt end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project f2e65447b3cb6340883957e033e77095a025ebdc)"
+0x00000095: "a.cpp"
+0x0000009b: "/usr/local/google/home/azakai/Dev/emscripten"
+0x000000c8: "_Z3foov"
+0x000000d0: "foo"
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (import "env" "__wasm_call_ctors" (func $fimport$0))
+ (import "env" "dlmalloc" (func $fimport$1 (param i32) (result i32)))
+ (import "env" "dlfree" (func $fimport$2 (param i32)))
+ (import "env" "setThrew" (func $fimport$3 (param i32 i32)))
+ (import "env" "stackSave" (func $fimport$4 (result i32)))
+ (import "env" "stackAlloc" (func $fimport$5 (param i32) (result i32)))
+ (import "env" "stackRestore" (func $fimport$6 (param i32)))
+ (import "env" "__growWasmMemory" (func $fimport$7 (param i32) (result i32)))
+ (global $global$0 i32 (i32.const 1532))
+ (export "__wasm_call_ctors" (func $fimport$0))
+ (export "_Z3foov" (func $fimport$0))
+ (export "__errno_location" (func $0))
+ (export "setThrew" (func $fimport$3))
+ (export "malloc" (func $fimport$1))
+ (export "free" (func $fimport$2))
+ (export "__data_end" (global $global$0))
+ (export "stackSave" (func $fimport$4))
+ (export "stackAlloc" (func $fimport$5))
+ (export "stackRestore" (func $fimport$6))
+ (export "__growWasmMemory" (func $fimport$7))
+ (func $0 (result i32)
+  (i32.const 1024)
+ )
+ ;; custom section "sourceMappingURL", size 15
+ ;; custom section "sourceMappingURL", size 15
+ ;; custom section ".debug_info", size 58
+ ;; custom section ".debug_abbrev", size 39
+ ;; custom section ".debug_line", size 56
+ ;; custom section ".debug_str", size 212
+)
diff --git a/binaryen/test/passes/dwarfdump.wasm b/binaryen/test/passes/dwarfdump.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/dwarfdump.wasm differ
diff --git a/binaryen/test/passes/dwarfdump_roundtrip_dwarfdump.bin.txt b/binaryen/test/passes/dwarfdump_roundtrip_dwarfdump.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dwarfdump_roundtrip_dwarfdump.bin.txt
@@ -0,0 +1,225 @@
+DWARF debug info
+================
+
+Contains section .debug_info (58 bytes)
+Contains section .debug_abbrev (39 bytes)
+Contains section .debug_line (56 bytes)
+Contains section .debug_str (212 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+[2] DW_TAG_subprogram	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_external	DW_FORM_flag_present
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x00000036 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x0000003a)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project f2e65447b3cb6340883957e033e77095a025ebdc)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000095] = "a.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x0000009b] = "/usr/local/google/home/azakai/Dev/emscripten")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000005)
+              DW_AT_high_pc [DW_FORM_data4]	(0x00000002)
+
+0x00000026:   DW_TAG_subprogram [2]  
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000005)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000002)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x000000c8] = "_Z3foov")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d0] = "foo")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/a.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(3)
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000039:   NULL
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x00000034
+         version: 4
+ prologue_length: 0x0000001d
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "a.cpp"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000027: 00 DW_LNE_set_address (0x0000000000000005)
+0x0000002e: 14 address += 0,  line += 2
+            0x0000000000000005      3      0      1   0             0  is_stmt
+
+0x0000002f: 05 DW_LNS_set_column (1)
+0x00000031: 0a DW_LNS_set_prologue_end
+0x00000032: 21 address += 1,  line += 1
+            0x0000000000000006      4      1      1   0             0  is_stmt prologue_end
+
+0x00000033: 02 DW_LNS_advance_pc (1)
+0x00000035: 00 DW_LNE_end_sequence
+            0x0000000000000007      4      1      1   0             0  is_stmt end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project f2e65447b3cb6340883957e033e77095a025ebdc)"
+0x00000095: "a.cpp"
+0x0000009b: "/usr/local/google/home/azakai/Dev/emscripten"
+0x000000c8: "_Z3foov"
+0x000000d0: "foo"
+DWARF debug info
+================
+
+Contains section .debug_info (58 bytes)
+Contains section .debug_abbrev (39 bytes)
+Contains section .debug_line (39 bytes)
+Contains section .debug_str (212 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+[2] DW_TAG_subprogram	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_external	DW_FORM_flag_present
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x00000036 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x0000003a)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project f2e65447b3cb6340883957e033e77095a025ebdc)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000095] = "a.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x0000009b] = "/usr/local/google/home/azakai/Dev/emscripten")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+              DW_AT_high_pc [DW_FORM_data4]	(0x00000000)
+
+0x00000026:   DW_TAG_subprogram [2]  
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000000)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x000000c8] = "_Z3foov")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d0] = "foo")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/a.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(3)
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000039:   NULL
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x00000023
+         version: 4
+ prologue_length: 0x0000001d
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "a.cpp"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+
+.debug_str contents:
+0x00000000: "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project f2e65447b3cb6340883957e033e77095a025ebdc)"
+0x00000095: "a.cpp"
+0x0000009b: "/usr/local/google/home/azakai/Dev/emscripten"
+0x000000c8: "_Z3foov"
+0x000000d0: "foo"
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (import "env" "__wasm_call_ctors" (func $fimport$0))
+ (import "env" "dlmalloc" (func $fimport$1 (param i32) (result i32)))
+ (import "env" "dlfree" (func $fimport$2 (param i32)))
+ (import "env" "setThrew" (func $fimport$3 (param i32 i32)))
+ (import "env" "stackSave" (func $fimport$4 (result i32)))
+ (import "env" "stackAlloc" (func $fimport$5 (param i32) (result i32)))
+ (import "env" "stackRestore" (func $fimport$6 (param i32)))
+ (import "env" "__growWasmMemory" (func $fimport$7 (param i32) (result i32)))
+ (global $global$0 i32 (i32.const 1532))
+ (export "__wasm_call_ctors" (func $fimport$0))
+ (export "_Z3foov" (func $fimport$0))
+ (export "__errno_location" (func $0))
+ (export "setThrew" (func $fimport$3))
+ (export "malloc" (func $fimport$1))
+ (export "free" (func $fimport$2))
+ (export "__data_end" (global $global$0))
+ (export "stackSave" (func $fimport$4))
+ (export "stackAlloc" (func $fimport$5))
+ (export "stackRestore" (func $fimport$6))
+ (export "__growWasmMemory" (func $fimport$7))
+ (func $0 (result i32)
+  (i32.const 1024)
+ )
+ ;; custom section "sourceMappingURL", size 15
+ ;; custom section "sourceMappingURL", size 15
+ ;; custom section ".debug_info", size 58
+ ;; custom section ".debug_abbrev", size 39
+ ;; custom section ".debug_line", size 39
+ ;; custom section ".debug_str", size 212
+)
diff --git a/binaryen/test/passes/dwarfdump_roundtrip_dwarfdump.wasm b/binaryen/test/passes/dwarfdump_roundtrip_dwarfdump.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/dwarfdump_roundtrip_dwarfdump.wasm differ
diff --git a/binaryen/test/passes/emit-js-wrapper=a.js.txt b/binaryen/test/passes/emit-js-wrapper=a.js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/emit-js-wrapper=a.js.txt
@@ -0,0 +1,84 @@
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_i32_i32_f32_f64_=>_none (func (param i32 i32 i32 f32 f64)))
+ (type $i32_i64_f32_f64_=>_none (func (param i32 i64 f32 f64)))
+ (type $i32_f32_f64_=>_none (func (param i32 f32 f64)))
+ (type $i32_f32_f64_=>_i32 (func (param i32 f32 f64) (result i32)))
+ (type $i32_f32_f64_=>_i64 (func (param i32 f32 f64) (result i64)))
+ (import "env" "setTempRet0" (func $setTempRet0 (param i32)))
+ (memory $0 256 256)
+ (export "add" (func $add))
+ (export "no_return" (func $no-return))
+ (export "types" (func $legalstub$types))
+ (export "types2" (func $types2))
+ (export "types3" (func $legalstub$types3))
+ (func $add (param $x i32) (param $y i32) (result i32)
+  (i32.add
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+ (func $unexported (param $x i32) (param $y i32) (result i32)
+  (i32.add
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+ (func $no-return (param $x i32)
+  (drop
+   (i32.add
+    (local.get $x)
+    (local.get $x)
+   )
+  )
+ )
+ (func $types (param $x i32) (param $y i64) (param $z f32) (param $w f64)
+  (nop)
+ )
+ (func $types2 (param $x i32) (param $z f32) (param $w f64)
+  (nop)
+ )
+ (func $types3 (param $x i32) (param $z f32) (param $w f64) (result i64)
+  (i64.const 1)
+ )
+ (func $legalstub$types (param $0 i32) (param $1 i32) (param $2 i32) (param $3 f32) (param $4 f64)
+  (call $types
+   (local.get $0)
+   (i64.or
+    (i64.extend_i32_u
+     (local.get $1)
+    )
+    (i64.shl
+     (i64.extend_i32_u
+      (local.get $2)
+     )
+     (i64.const 32)
+    )
+   )
+   (local.get $3)
+   (local.get $4)
+  )
+ )
+ (func $legalstub$types3 (param $0 i32) (param $1 f32) (param $2 f64) (result i32)
+  (local $3 i64)
+  (local.set $3
+   (call $types3
+    (local.get $0)
+    (local.get $1)
+    (local.get $2)
+   )
+  )
+  (call $setTempRet0
+   (i32.wrap_i64
+    (i64.shr_u
+     (local.get $3)
+     (i64.const 32)
+    )
+   )
+  )
+  (i32.wrap_i64
+   (local.get $3)
+  )
+ )
+)
diff --git a/binaryen/test/passes/emit-js-wrapper=a.js.wast b/binaryen/test/passes/emit-js-wrapper=a.js.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/emit-js-wrapper=a.js.wast
@@ -0,0 +1,37 @@
+(module
+ (memory $0 256 256)
+ (export "add" (func $add))
+ (export "no_return" (func $no-return)) ;; note exported name is slightly different
+ (export "types" (func $types))
+ (export "types2" (func $types2))
+ (export "types3" (func $types3))
+ (func $add (param $x i32) (param $y i32) (result i32)
+  (i32.add
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+ (func $unexported (param $x i32) (param $y i32) (result i32)
+  (i32.add
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+ (func $no-return (param $x i32)
+  (drop
+   (i32.add
+    (local.get $x)
+    (local.get $x)
+   )
+  )
+ )
+ (func $types (param $x i32) (param $y i64) (param $z f32) (param $w f64)
+  (nop)
+ )
+ (func $types2 (param $x i32) (param $z f32) (param $w f64)
+  (nop)
+ )
+ (func $types3 (param $x i32) (param $z f32) (param $w f64) (result i64)
+  (i64.const 1)
+ )
+)
diff --git a/binaryen/test/passes/emit-js-wrapper=a.js.wast.js b/binaryen/test/passes/emit-js-wrapper=a.js.wast.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/emit-js-wrapper=a.js.wast.js
@@ -0,0 +1,83 @@
+if (typeof console === 'undefined') {
+  console = { log: print };
+}
+var tempRet0;
+var binary;
+if (typeof process === 'object' && typeof require === 'function' /* node.js detection */) {
+  var args = process.argv.slice(2);
+  binary = require('fs').readFileSync(args[0]);
+  if (!binary.buffer) binary = new Uint8Array(binary);
+} else {
+  var args;
+  if (typeof scriptArgs != 'undefined') {
+    args = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    args = arguments;
+  }
+  if (typeof readbuffer === 'function') {
+    binary = new Uint8Array(readbuffer(args[0]));
+  } else {
+    binary = read(args[0], 'binary');
+  }
+}
+function literal(x, type) {
+  var ret = '';
+  switch (type) {
+    case 'i32': ret += (x | 0); break;
+    case 'f32':
+    case 'f64': {
+      if (x == 0 && (1 / x) < 0) ret += '-';
+      ret += Number(x).toString();
+      break;
+    }
+    default: throw 'what?';
+  }
+  return ret;
+}
+var instance = new WebAssembly.Instance(new WebAssembly.Module(binary), {
+  'fuzzing-support': {
+    'log-i32': function(x)    { console.log('[LoggingExternalInterface logging ' + literal(x, 'i32') + ']') },
+    'log-i64': function(x, y) { console.log('[LoggingExternalInterface logging ' + literal(x, 'i32') + ' ' + literal(y, 'i32') + ']') },
+    'log-f32': function(x)    { console.log('[LoggingExternalInterface logging ' + literal(x, 'f64') + ']') },
+    'log-f64': function(x)    { console.log('[LoggingExternalInterface logging ' + literal(x, 'f64') + ']') },
+  },
+  'env': {
+    'setTempRet0': function(x) { tempRet0 = x },
+    'getTempRet0': function() { return tempRet0 },
+  },
+});
+if (instance.exports.hangLimitInitializer) instance.exports.hangLimitInitializer();
+try {
+  console.log('[fuzz-exec] calling add');
+  console.log('[fuzz-exec] note result: add => ' + literal(instance.exports.add(0, 0), 'i32'));
+} catch (e) {
+  console.log('exception!' /* + e */);
+}
+if (instance.exports.hangLimitInitializer) instance.exports.hangLimitInitializer();
+try {
+  console.log('[fuzz-exec] calling no_return');
+  instance.exports.no_return(0);
+} catch (e) {
+  console.log('exception!' /* + e */);
+}
+if (instance.exports.hangLimitInitializer) instance.exports.hangLimitInitializer();
+try {
+  console.log('[fuzz-exec] calling types');
+  instance.exports.types(0, 0, 0, 0, 0);
+} catch (e) {
+  console.log('exception!' /* + e */);
+}
+if (instance.exports.hangLimitInitializer) instance.exports.hangLimitInitializer();
+try {
+  console.log('[fuzz-exec] calling types2');
+  instance.exports.types2(0, 0, 0);
+} catch (e) {
+  console.log('exception!' /* + e */);
+}
+if (instance.exports.hangLimitInitializer) instance.exports.hangLimitInitializer();
+try {
+  console.log('[fuzz-exec] calling types3');
+  console.log('[fuzz-exec] note result: types3 => ' + literal(instance.exports.types3(0, 0, 0), 'i32'));
+} catch (e) {
+  console.log('exception!' /* + e */);
+}
diff --git a/binaryen/test/passes/emit-spec-wrapper=a.wat.txt b/binaryen/test/passes/emit-spec-wrapper=a.wat.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/emit-spec-wrapper=a.wat.txt
@@ -0,0 +1,42 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i64_f32_f64_=>_none (func (param i32 i64 f32 f64)))
+ (type $i32_f32_f64_=>_none (func (param i32 f32 f64)))
+ (type $i32_f32_f64_=>_i64 (func (param i32 f32 f64) (result i64)))
+ (memory $0 256 256)
+ (export "add" (func $add))
+ (export "no_return" (func $no-return))
+ (export "types" (func $types))
+ (export "types2" (func $types2))
+ (export "types3" (func $types3))
+ (func $add (param $x i32) (param $y i32) (result i32)
+  (i32.add
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+ (func $unexported (param $x i32) (param $y i32) (result i32)
+  (i32.add
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+ (func $no-return (param $x i32)
+  (drop
+   (i32.add
+    (local.get $x)
+    (local.get $x)
+   )
+  )
+ )
+ (func $types (param $x i32) (param $y i64) (param $z f32) (param $w f64)
+  (nop)
+ )
+ (func $types2 (param $x i32) (param $z f32) (param $w f64)
+  (nop)
+ )
+ (func $types3 (param $x i32) (param $z f32) (param $w f64) (result i64)
+  (i64.const 1)
+ )
+)
diff --git a/binaryen/test/passes/emit-spec-wrapper=a.wat.wast b/binaryen/test/passes/emit-spec-wrapper=a.wat.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/emit-spec-wrapper=a.wat.wast
@@ -0,0 +1,37 @@
+(module
+ (memory $0 256 256)
+ (export "add" (func $add))
+ (export "no_return" (func $no-return)) ;; note exported name is slightly different
+ (export "types" (func $types))
+ (export "types2" (func $types2))
+ (export "types3" (func $types3))
+ (func $add (param $x i32) (param $y i32) (result i32)
+  (i32.add
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+ (func $unexported (param $x i32) (param $y i32) (result i32)
+  (i32.add
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+ (func $no-return (param $x i32)
+  (drop
+   (i32.add
+    (local.get $x)
+    (local.get $x)
+   )
+  )
+ )
+ (func $types (param $x i32) (param $y i64) (param $z f32) (param $w f64)
+  (nop)
+ )
+ (func $types2 (param $x i32) (param $z f32) (param $w f64)
+  (nop)
+ )
+ (func $types3 (param $x i32) (param $z f32) (param $w f64) (result i64)
+  (i64.const 1)
+ )
+)
diff --git a/binaryen/test/passes/emit-spec-wrapper=a.wat.wast.wat b/binaryen/test/passes/emit-spec-wrapper=a.wat.wast.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/emit-spec-wrapper=a.wat.wast.wat
@@ -0,0 +1,1 @@
+(invoke "hangLimitInitializer") (invoke "add" (i32.const 0) (i32.const 0) ) (invoke "hangLimitInitializer") (invoke "no_return" (i32.const 0) ) (invoke "hangLimitInitializer") (invoke "types" (i32.const 0) (i64.const 0) (f32.const 0) (f64.const 0) ) (invoke "hangLimitInitializer") (invoke "types2" (i32.const 0) (f32.const 0) (f64.const 0) ) (invoke "hangLimitInitializer") (invoke "types3" (i32.const 0) (f32.const 0) (f64.const 0) ) 
diff --git a/binaryen/test/passes/extract-function_pass-arg=extract@foo.txt b/binaryen/test/passes/extract-function_pass-arg=extract@foo.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/extract-function_pass-arg=extract@foo.txt
@@ -0,0 +1,9 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "bar" (func $bar))
+ (import "env" "other" (func $other))
+ (export "foo" (func $foo))
+ (func $foo
+  (call $bar)
+ )
+)
diff --git a/binaryen/test/passes/extract-function_pass-arg=extract@foo.wast b/binaryen/test/passes/extract-function_pass-arg=extract@foo.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/extract-function_pass-arg=extract@foo.wast
@@ -0,0 +1,12 @@
+(module
+  (func $foo
+    (call $bar)
+  )
+  (func $bar
+    (call $foo)
+  )
+  (func $other
+    (drop (i32.const 1))
+  )
+)
+
diff --git a/binaryen/test/passes/fannkuch0_dwarf.bin.txt b/binaryen/test/passes/fannkuch0_dwarf.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fannkuch0_dwarf.bin.txt
@@ -0,0 +1,10164 @@
+DWARF debug info
+================
+
+Contains section .debug_info (640 bytes)
+Contains section .debug_ranges (32 bytes)
+Contains section .debug_abbrev (222 bytes)
+Contains section .debug_line (1558 bytes)
+Contains section .debug_str (409 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[2] DW_TAG_pointer_type	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[3] DW_TAG_structure_type	DW_CHILDREN_yes
+	DW_AT_calling_convention	DW_FORM_data1
+	DW_AT_name	DW_FORM_strp
+	DW_AT_byte_size	DW_FORM_data1
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[4] DW_TAG_member	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_data_member_location	DW_FORM_data1
+
+[5] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+[6] DW_TAG_namespace	DW_CHILDREN_yes
+	DW_AT_name	DW_FORM_strp
+
+[7] DW_TAG_typedef	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[8] DW_TAG_unspecified_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+
+[9] DW_TAG_imported_declaration	DW_CHILDREN_no
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_import	DW_FORM_ref4
+
+[10] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[11] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_exprloc
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[12] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_exprloc
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[13] DW_TAG_lexical_block	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+[14] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[15] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[16] DW_TAG_label	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_low_pc	DW_FORM_addr
+
+[17] DW_TAG_pointer_type	DW_CHILDREN_no
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x0000027c version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x00000280)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 11.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 2d7a8cf90478cd845ffb39763b0e95b7715322d2)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000095] = "tests/fannkuch.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x000000a8] = "/home/alon/Dev/emscripten")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+              DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
+                 [0x00000006, 0x0000088c)
+                 [0x0000088e, 0x000009dc)
+                 [0x000009de, 0x00001042))
+
+0x00000026:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x002b => {0x0000002b} "worker_args")
+
+0x0000002b:   DW_TAG_structure_type [3] *
+                DW_AT_calling_convention [DW_FORM_data1]	(DW_CC_pass_by_value)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000cf] = "worker_args")
+                DW_AT_byte_size [DW_FORM_data1]	(0x0c)
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(20)
+
+0x00000034:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c2] = "i")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(21)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x00)
+
+0x00000040:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c8] = "n")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(21)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x04)
+
+0x0000004c:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ca] = "next")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(22)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x08)
+
+0x00000058:     NULL
+
+0x00000059:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c4] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x00000060:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000065:   DW_TAG_namespace [6] *
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000db] = "std")
+
+0x0000006a:     DW_TAG_typedef [7]  
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0076 => {0x00000076} "decltype(nullptr)")
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000f1] = "nullptr_t")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/system/include/libcxx/__nullptr")
+                  DW_AT_decl_line [DW_FORM_data1]	(57)
+
+0x00000075:     NULL
+
+0x00000076:   DW_TAG_unspecified_type [8]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000df] = "decltype(nullptr)")
+
+0x0000007b:   DW_TAG_imported_declaration [9]  
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/system/include/libcxx/stddef.h")
+                DW_AT_decl_line [DW_FORM_data1]	(52)
+                DW_AT_import [DW_FORM_ref4]	(cu + 0x006a => {0x0000006a})
+
+0x00000082:   DW_TAG_subprogram [10] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000006)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000886)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x000000fb] = "_Z15fannkuch_workerPv")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000111] = "fannkuch_worker")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(26)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000099:     DW_TAG_formal_parameter [11]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x3c)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000013d] = "_arg")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(26)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x026d => {0x0000026d} "*")
+
+0x000000a7:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x38)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000142] = "args")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(28)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000000b5:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x34)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000147] = "perm1")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000000c3:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x30)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014d] = "count")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000000d1:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x2c)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000153] = "perm")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000000df:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x28)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000158] = "maxflips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000ed:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x24)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000161] = "flips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000fb:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x20)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c2] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000109:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x1c)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c8] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000117:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x18)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000167] = "r")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000125:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x14)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000169] = "j")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000133:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x10)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000016b] = "k")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000141:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0xc)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000016d] = "tmp")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000014f:     DW_TAG_lexical_block [13] *
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000006b4)
+                  DW_AT_high_pc [DW_FORM_data4]	(0x00000135)
+
+0x00000158:       DW_TAG_variable [12]  
+                    DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x8)
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000171] = "p0")
+                    DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                    DW_AT_decl_line [DW_FORM_data1]	(74)
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000166:       NULL
+
+0x00000167:     NULL
+
+0x00000168:   DW_TAG_subprogram [14] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x000000000000088e)
+                DW_AT_high_pc [DW_FORM_data4]	(0x0000014e)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000121] = "main")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(152)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000017b:     DW_TAG_formal_parameter [11]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x18)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000174] = "argc")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(152)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000189:     DW_TAG_formal_parameter [11]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x14)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000179] = "argv")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(152)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x026e => {0x0000026e} "char**")
+
+0x00000197:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x10)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c8] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(153)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001a5:     NULL
+
+0x000001a6:   DW_TAG_subprogram [15] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x00000000000009de)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000664)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x00000126] = "_ZL8fannkuchi")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000134] = "fannkuch")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(87)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001bd:     DW_TAG_formal_parameter [11]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x2c)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c8] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(87)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001cb:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x28)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000142] = "args")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(89)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000001d9:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x24)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000183] = "targs")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(89)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000001e7:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x20)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000189] = "showmax")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(90)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001f5:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x1c)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000147] = "perm1")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x00000203:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x18)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014d] = "count")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x00000211:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x14)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c2] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000021f:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x10)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000167] = "r")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000022d:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0xc)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000158] = "maxflips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000023b:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x8)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000161] = "flips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000249:     DW_TAG_label [16]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000191] = "cleanup")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(137)
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000f10)
+
+0x00000254:     DW_TAG_lexical_block [13] *
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000d62)
+                  DW_AT_high_pc [DW_FORM_data4]	(0x00000106)
+
+0x0000025d:       DW_TAG_variable [12]  
+                    DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x4)
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000171] = "p0")
+                    DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                    DW_AT_decl_line [DW_FORM_data1]	(125)
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000026b:       NULL
+
+0x0000026c:     NULL
+
+0x0000026d:   DW_TAG_pointer_type [17]  
+
+0x0000026e:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0273 => {0x00000273} "char*")
+
+0x00000273:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0278 => {0x00000278} "char")
+
+0x00000278:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000017e] = "char")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed_char)
+                DW_AT_byte_size [DW_FORM_data1]	(0x01)
+
+0x0000027f:   NULL
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x00000612
+         version: 4
+ prologue_length: 0x00000059
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+include_directories[  1] = "tests"
+include_directories[  2] = "system/include/libcxx"
+file_names[  1]:
+           name: "fannkuch.cpp"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  2]:
+           name: "__nullptr"
+      dir_index: 2
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  3]:
+           name: "stddef.h"
+      dir_index: 2
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000063: 00 DW_LNE_set_address (0x0000000000000006)
+0x0000006a: 03 DW_LNS_advance_line (27)
+0x0000006c: 01 DW_LNS_copy
+            0x0000000000000006     27      0      1   0             0  is_stmt
+
+
+0x0000006d: 05 DW_LNS_set_column (45)
+0x0000006f: 0a DW_LNS_set_prologue_end
+0x00000070: 02 DW_LNS_advance_pc (43)
+0x00000072: 13 address += 0,  line += 1
+            0x0000000000000031     28     45      1   0             0  is_stmt prologue_end
+
+0x00000073: 05 DW_LNS_set_column (24)
+0x00000075: 06 DW_LNS_negate_stmt
+0x00000076: 74 address += 7,  line += 0
+            0x0000000000000038     28     24      1   0             0 
+
+0x00000077: 05 DW_LNS_set_column (13)
+0x00000079: 06 DW_LNS_negate_stmt
+0x0000007a: 78 address += 7,  line += 4
+            0x000000000000003f     32     13      1   0             0  is_stmt
+
+0x0000007b: 05 DW_LNS_set_column (8)
+0x0000007d: 75 address += 7,  line += 1
+            0x0000000000000046     33      8      1   0             0  is_stmt
+
+0x0000007e: 05 DW_LNS_set_column (14)
+0x00000080: 06 DW_LNS_negate_stmt
+0x00000081: 74 address += 7,  line += 0
+            0x000000000000004d     33     14      1   0             0 
+
+0x00000082: 05 DW_LNS_set_column (6)
+0x00000084: 74 address += 7,  line += 0
+            0x0000000000000054     33      6      1   0             0 
+
+0x00000085: 05 DW_LNS_set_column (25)
+0x00000087: 06 DW_LNS_negate_stmt
+0x00000088: 75 address += 7,  line += 1
+            0x000000000000005b     34     25      1   0             0  is_stmt
+
+0x00000089: 05 DW_LNS_set_column (27)
+0x0000008b: 06 DW_LNS_negate_stmt
+0x0000008c: 74 address += 7,  line += 0
+            0x0000000000000062     34     27      1   0             0 
+
+0x0000008d: 05 DW_LNS_set_column (18)
+0x0000008f: ac address += 11,  line += 0
+            0x000000000000006d     34     18      1   0             0 
+
+0x00000090: 05 DW_LNS_set_column (10)
+0x00000092: 9e address += 10,  line += 0
+            0x0000000000000077     34     10      1   0             0 
+
+0x00000093: 05 DW_LNS_set_column (24)
+0x00000095: 06 DW_LNS_negate_stmt
+0x00000096: 75 address += 7,  line += 1
+            0x000000000000007e     35     24      1   0             0  is_stmt
+
+0x00000097: 05 DW_LNS_set_column (26)
+0x00000099: 06 DW_LNS_negate_stmt
+0x0000009a: 74 address += 7,  line += 0
+            0x0000000000000085     35     26      1   0             0 
+
+0x0000009b: 05 DW_LNS_set_column (17)
+0x0000009d: ac address += 11,  line += 0
+            0x0000000000000090     35     17      1   0             0 
+
+0x0000009e: 05 DW_LNS_set_column (9)
+0x000000a0: 9e address += 10,  line += 0
+            0x000000000000009a     35      9      1   0             0 
+
+0x000000a1: 05 DW_LNS_set_column (25)
+0x000000a3: 06 DW_LNS_negate_stmt
+0x000000a4: 75 address += 7,  line += 1
+            0x00000000000000a1     36     25      1   0             0  is_stmt
+
+0x000000a5: 05 DW_LNS_set_column (27)
+0x000000a7: 06 DW_LNS_negate_stmt
+0x000000a8: 74 address += 7,  line += 0
+            0x00000000000000a8     36     27      1   0             0 
+
+0x000000a9: 05 DW_LNS_set_column (18)
+0x000000ab: ac address += 11,  line += 0
+            0x00000000000000b3     36     18      1   0             0 
+
+0x000000ac: 05 DW_LNS_set_column (10)
+0x000000ae: 9e address += 10,  line += 0
+            0x00000000000000bd     36     10      1   0             0 
+
+0x000000af: 05 DW_LNS_set_column (11)
+0x000000b1: 06 DW_LNS_negate_stmt
+0x000000b2: 75 address += 7,  line += 1
+            0x00000000000000c4     37     11      1   0             0  is_stmt
+
+0x000000b3: 05 DW_LNS_set_column (16)
+0x000000b5: 06 DW_LNS_negate_stmt
+0x000000b6: 74 address += 7,  line += 0
+            0x00000000000000cb     37     16      1   0             0 
+
+0x000000b7: 05 DW_LNS_set_column (20)
+0x000000b9: ac address += 11,  line += 0
+            0x00000000000000d6     37     20      1   0             0 
+
+0x000000ba: 05 DW_LNS_set_column (18)
+0x000000bc: 74 address += 7,  line += 0
+            0x00000000000000dd     37     18      1   0             0 
+
+0x000000bd: 05 DW_LNS_set_column (4)
+0x000000bf: e4 address += 15,  line += 0
+            0x00000000000000ec     37      4      1   0             0 
+
+0x000000c0: 05 DW_LNS_set_column (18)
+0x000000c2: 06 DW_LNS_negate_stmt
+0x000000c3: f3 address += 16,  line += 1
+            0x00000000000000fc     38     18      1   0             0  is_stmt
+
+0x000000c4: 05 DW_LNS_set_column (7)
+0x000000c6: 06 DW_LNS_negate_stmt
+0x000000c7: 74 address += 7,  line += 0
+            0x0000000000000103     38      7      1   0             0 
+
+0x000000c8: 05 DW_LNS_set_column (13)
+0x000000ca: 74 address += 7,  line += 0
+            0x000000000000010a     38     13      1   0             0 
+
+0x000000cb: 05 DW_LNS_set_column (7)
+0x000000cd: 74 address += 7,  line += 0
+            0x0000000000000111     38      7      1   0             0 
+
+0x000000ce: 05 DW_LNS_set_column (16)
+0x000000d0: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000000d1: 20 address += 1,  line += 0
+            0x0000000000000123     38     16      1   0             0 
+
+0x000000d2: 05 DW_LNS_set_column (24)
+0x000000d4: 06 DW_LNS_negate_stmt
+0x000000d5: 73 address += 7,  line += -1
+            0x000000000000012a     37     24      1   0             0  is_stmt
+
+0x000000d6: 05 DW_LNS_set_column (4)
+0x000000d8: 06 DW_LNS_negate_stmt
+0x000000d9: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000000da: 82 address += 8,  line += 0
+            0x0000000000000143     37      4      1   0             0 
+
+0x000000db: 2e address += 2,  line += 0
+            0x0000000000000145     37      4      1   0             0 
+
+0x000000dc: 05 DW_LNS_set_column (21)
+0x000000de: 06 DW_LNS_negate_stmt
+0x000000df: 30 address += 2,  line += 2
+            0x0000000000000147     39     21      1   0             0  is_stmt
+
+0x000000e0: 05 DW_LNS_set_column (23)
+0x000000e2: 06 DW_LNS_negate_stmt
+0x000000e3: 74 address += 7,  line += 0
+            0x000000000000014e     39     23      1   0             0 
+
+0x000000e4: 05 DW_LNS_set_column (4)
+0x000000e6: ac address += 11,  line += 0
+            0x0000000000000159     39      4      1   0             0 
+
+0x000000e7: 05 DW_LNS_set_column (10)
+0x000000e9: 74 address += 7,  line += 0
+            0x0000000000000160     39     10      1   0             0 
+
+0x000000ea: 05 DW_LNS_set_column (16)
+0x000000ec: 74 address += 7,  line += 0
+            0x0000000000000167     39     16      1   0             0 
+
+0x000000ed: 05 DW_LNS_set_column (4)
+0x000000ef: 74 address += 7,  line += 0
+            0x000000000000016e     39      4      1   0             0 
+
+0x000000f0: 05 DW_LNS_set_column (19)
+0x000000f2: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000000f3: 20 address += 1,  line += 0
+            0x0000000000000180     39     19      1   0             0 
+
+0x000000f4: 06 DW_LNS_negate_stmt
+0x000000f5: 75 address += 7,  line += 1
+            0x0000000000000187     40     19      1   0             0  is_stmt
+
+0x000000f6: 05 DW_LNS_set_column (25)
+0x000000f8: 06 DW_LNS_negate_stmt
+0x000000f9: 74 address += 7,  line += 0
+            0x000000000000018e     40     25      1   0             0 
+
+0x000000fa: 05 DW_LNS_set_column (4)
+0x000000fc: 74 address += 7,  line += 0
+            0x0000000000000195     40      4      1   0             0 
+
+0x000000fd: 05 DW_LNS_set_column (10)
+0x000000ff: 74 address += 7,  line += 0
+            0x000000000000019c     40     10      1   0             0 
+
+0x00000100: 05 DW_LNS_set_column (12)
+0x00000102: 74 address += 7,  line += 0
+            0x00000000000001a3     40     12      1   0             0 
+
+0x00000103: 05 DW_LNS_set_column (4)
+0x00000105: ac address += 11,  line += 0
+            0x00000000000001ae     40      4      1   0             0 
+
+0x00000106: 05 DW_LNS_set_column (17)
+0x00000108: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000109: 20 address += 1,  line += 0
+            0x00000000000001c0     40     17      1   0             0 
+
+0x0000010a: 05 DW_LNS_set_column (8)
+0x0000010c: 06 DW_LNS_negate_stmt
+0x0000010d: 75 address += 7,  line += 1
+            0x00000000000001c7     41      8      1   0             0  is_stmt
+
+0x0000010e: 05 DW_LNS_set_column (6)
+0x00000110: 06 DW_LNS_negate_stmt
+0x00000111: 74 address += 7,  line += 0
+            0x00000000000001ce     41      6      1   0             0 
+
+0x00000112: 03 DW_LNS_advance_line (0)
+0x00000114: 74 address += 7,  line += 0
+            0x00000000000001d5      0      6      1   0             0 
+
+0x00000115: 05 DW_LNS_set_column (14)
+0x00000117: 06 DW_LNS_negate_stmt
+0x00000118: 03 DW_LNS_advance_line (44)
+0x0000011a: 9e address += 10,  line += 0
+            0x00000000000001df     44     14      1   0             0  is_stmt
+
+0x0000011b: 05 DW_LNS_set_column (16)
+0x0000011d: 06 DW_LNS_negate_stmt
+0x0000011e: 74 address += 7,  line += 0
+            0x00000000000001e6     44     16      1   0             0 
+
+0x0000011f: 05 DW_LNS_set_column (7)
+0x00000121: e4 address += 15,  line += 0
+            0x00000000000001f5     44      7      1   0             0 
+
+0x00000122: 05 DW_LNS_set_column (25)
+0x00000124: 06 DW_LNS_negate_stmt
+0x00000125: f3 address += 16,  line += 1
+            0x0000000000000205     45     25      1   0             0  is_stmt
+
+0x00000126: 05 DW_LNS_set_column (10)
+0x00000128: 06 DW_LNS_negate_stmt
+0x00000129: 74 address += 7,  line += 0
+            0x000000000000020c     45     10      1   0             0 
+
+0x0000012a: 05 DW_LNS_set_column (16)
+0x0000012c: 74 address += 7,  line += 0
+            0x0000000000000213     45     16      1   0             0 
+
+0x0000012d: 05 DW_LNS_set_column (18)
+0x0000012f: 74 address += 7,  line += 0
+            0x000000000000021a     45     18      1   0             0 
+
+0x00000130: 05 DW_LNS_set_column (10)
+0x00000132: ac address += 11,  line += 0
+            0x0000000000000225     45     10      1   0             0 
+
+0x00000133: 05 DW_LNS_set_column (23)
+0x00000135: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000136: 20 address += 1,  line += 0
+            0x0000000000000237     45     23      1   0             0 
+
+0x00000137: 05 DW_LNS_set_column (22)
+0x00000139: 06 DW_LNS_negate_stmt
+0x0000013a: 73 address += 7,  line += -1
+            0x000000000000023e     44     22      1   0             0  is_stmt
+
+0x0000013b: 05 DW_LNS_set_column (7)
+0x0000013d: 06 DW_LNS_negate_stmt
+0x0000013e: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x0000013f: 82 address += 8,  line += 0
+            0x0000000000000257     44      7      1   0             0 
+
+0x00000140: 2e address += 2,  line += 0
+            0x0000000000000259     44      7      1   0             0 
+
+0x00000141: 05 DW_LNS_set_column (11)
+0x00000143: 06 DW_LNS_negate_stmt
+0x00000144: 30 address += 2,  line += 2
+            0x000000000000025b     46     11      1   0             0  is_stmt
+
+0x00000145: 05 DW_LNS_set_column (25)
+0x00000147: 06 DW_LNS_negate_stmt
+0x00000148: d6 address += 14,  line += 0
+            0x0000000000000269     46     25      1   0             0 
+
+0x00000149: 05 DW_LNS_set_column (28)
+0x0000014b: 74 address += 7,  line += 0
+            0x0000000000000270     46     28      1   0             0 
+
+0x0000014c: 05 DW_LNS_set_column (34)
+0x0000014e: 74 address += 7,  line += 0
+            0x0000000000000277     46     34      1   0             0 
+
+0x0000014f: 05 DW_LNS_set_column (36)
+0x00000151: 74 address += 7,  line += 0
+            0x000000000000027e     46     36      1   0             0 
+
+0x00000152: 05 DW_LNS_set_column (28)
+0x00000154: ac address += 11,  line += 0
+            0x0000000000000289     46     28      1   0             0 
+
+0x00000155: 05 DW_LNS_set_column (44)
+0x00000157: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000158: 82 address += 8,  line += 0
+            0x00000000000002a2     46     44      1   0             0 
+
+0x00000159: 05 DW_LNS_set_column (46)
+0x0000015b: 74 address += 7,  line += 0
+            0x00000000000002a9     46     46      1   0             0 
+
+0x0000015c: 05 DW_LNS_set_column (41)
+0x0000015e: ac address += 11,  line += 0
+            0x00000000000002b4     46     41      1   0             0 
+
+0x0000015f: 05 DW_LNS_set_column (11)
+0x00000161: e4 address += 15,  line += 0
+            0x00000000000002c3     46     11      1   0             0 
+
+0x00000162: 03 DW_LNS_advance_line (0)
+0x00000164: f2 address += 16,  line += 0
+            0x00000000000002d3      0     11      1   0             0 
+
+0x00000165: 05 DW_LNS_set_column (17)
+0x00000167: 06 DW_LNS_negate_stmt
+0x00000168: 03 DW_LNS_advance_line (47)
+0x0000016a: 4a address += 4,  line += 0
+            0x00000000000002d7     47     17      1   0             0  is_stmt
+
+0x0000016b: 05 DW_LNS_set_column (22)
+0x0000016d: 06 DW_LNS_negate_stmt
+0x0000016e: 74 address += 7,  line += 0
+            0x00000000000002de     47     22      1   0             0 
+
+0x0000016f: 05 DW_LNS_set_column (26)
+0x00000171: ac address += 11,  line += 0
+            0x00000000000002e9     47     26      1   0             0 
+
+0x00000172: 05 DW_LNS_set_column (24)
+0x00000174: 74 address += 7,  line += 0
+            0x00000000000002f0     47     24      1   0             0 
+
+0x00000175: 05 DW_LNS_set_column (10)
+0x00000177: e4 address += 15,  line += 0
+            0x00000000000002ff     47     10      1   0             0 
+
+0x00000178: 05 DW_LNS_set_column (23)
+0x0000017a: 06 DW_LNS_negate_stmt
+0x0000017b: f3 address += 16,  line += 1
+            0x000000000000030f     48     23      1   0             0  is_stmt
+
+0x0000017c: 05 DW_LNS_set_column (29)
+0x0000017e: 06 DW_LNS_negate_stmt
+0x0000017f: 74 address += 7,  line += 0
+            0x0000000000000316     48     29      1   0             0 
+
+0x00000180: 05 DW_LNS_set_column (23)
+0x00000182: 74 address += 7,  line += 0
+            0x000000000000031d     48     23      1   0             0 
+
+0x00000183: 05 DW_LNS_set_column (13)
+0x00000185: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000186: 82 address += 8,  line += 0
+            0x0000000000000336     48     13      1   0             0 
+
+0x00000187: 05 DW_LNS_set_column (18)
+0x00000189: 74 address += 7,  line += 0
+            0x000000000000033d     48     18      1   0             0 
+
+0x0000018a: 05 DW_LNS_set_column (13)
+0x0000018c: 74 address += 7,  line += 0
+            0x0000000000000344     48     13      1   0             0 
+
+0x0000018d: 05 DW_LNS_set_column (21)
+0x0000018f: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000190: 20 address += 1,  line += 0
+            0x0000000000000356     48     21      1   0             0 
+
+0x00000191: 05 DW_LNS_set_column (30)
+0x00000193: 06 DW_LNS_negate_stmt
+0x00000194: 73 address += 7,  line += -1
+            0x000000000000035d     47     30      1   0             0  is_stmt
+
+0x00000195: 05 DW_LNS_set_column (10)
+0x00000197: 06 DW_LNS_negate_stmt
+0x00000198: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000199: 82 address += 8,  line += 0
+            0x0000000000000376     47     10      1   0             0 
+
+0x0000019a: 2e address += 2,  line += 0
+            0x0000000000000378     47     10      1   0             0 
+
+0x0000019b: 05 DW_LNS_set_column (16)
+0x0000019d: 06 DW_LNS_negate_stmt
+0x0000019e: 68 address += 6,  line += 2
+            0x000000000000037e     49     16      1   0             0  is_stmt
+
+0x0000019f: 05 DW_LNS_set_column (14)
+0x000001a1: 75 address += 7,  line += 1
+            0x0000000000000385     50     14      1   0             0  is_stmt
+
+0x000001a2: 05 DW_LNS_set_column (12)
+0x000001a4: 06 DW_LNS_negate_stmt
+0x000001a5: d6 address += 14,  line += 0
+            0x0000000000000393     50     12      1   0             0 
+
+0x000001a6: 03 DW_LNS_advance_line (0)
+0x000001a8: 74 address += 7,  line += 0
+            0x000000000000039a      0     12      1   0             0 
+
+0x000001a9: 05 DW_LNS_set_column (20)
+0x000001ab: 06 DW_LNS_negate_stmt
+0x000001ac: 03 DW_LNS_advance_line (52)
+0x000001ae: 66 address += 6,  line += 0
+            0x00000000000003a0     52     20      1   0             0  is_stmt
+
+0x000001af: 05 DW_LNS_set_column (29)
+0x000001b1: 06 DW_LNS_negate_stmt
+0x000001b2: 74 address += 7,  line += 0
+            0x00000000000003a7     52     29      1   0             0 
+
+0x000001b3: 05 DW_LNS_set_column (31)
+0x000001b5: 74 address += 7,  line += 0
+            0x00000000000003ae     52     31      1   0             0 
+
+0x000001b6: 05 DW_LNS_set_column (27)
+0x000001b8: ac address += 11,  line += 0
+            0x00000000000003b9     52     27      1   0             0 
+
+0x000001b9: 05 DW_LNS_set_column (36)
+0x000001bb: 74 address += 7,  line += 0
+            0x00000000000003c0     52     36      1   0             0 
+
+0x000001bc: 05 DW_LNS_set_column (40)
+0x000001be: ac address += 11,  line += 0
+            0x00000000000003cb     52     40      1   0             0 
+
+0x000001bf: 05 DW_LNS_set_column (38)
+0x000001c1: 74 address += 7,  line += 0
+            0x00000000000003d2     52     38      1   0             0 
+
+0x000001c2: 05 DW_LNS_set_column (13)
+0x000001c4: e4 address += 15,  line += 0
+            0x00000000000003e1     52     13      1   0             0 
+
+0x000001c5: 05 DW_LNS_set_column (22)
+0x000001c7: 06 DW_LNS_negate_stmt
+0x000001c8: f3 address += 16,  line += 1
+            0x00000000000003f1     53     22      1   0             0  is_stmt
+
+0x000001c9: 05 DW_LNS_set_column (27)
+0x000001cb: 06 DW_LNS_negate_stmt
+0x000001cc: 74 address += 7,  line += 0
+            0x00000000000003f8     53     27      1   0             0 
+
+0x000001cd: 05 DW_LNS_set_column (22)
+0x000001cf: 82 address += 8,  line += 0
+            0x0000000000000400     53     22      1   0             0 
+
+0x000001d0: 05 DW_LNS_set_column (20)
+0x000001d2: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000001d3: f2 address += 16,  line += 0
+            0x0000000000000421     53     20      1   0             0 
+
+0x000001d4: 05 DW_LNS_set_column (26)
+0x000001d6: 06 DW_LNS_negate_stmt
+0x000001d7: 83 address += 8,  line += 1
+            0x0000000000000429     54     26      1   0             0  is_stmt
+
+0x000001d8: 05 DW_LNS_set_column (31)
+0x000001da: 06 DW_LNS_negate_stmt
+0x000001db: 82 address += 8,  line += 0
+            0x0000000000000431     54     31      1   0             0 
+
+0x000001dc: 05 DW_LNS_set_column (26)
+0x000001de: 82 address += 8,  line += 0
+            0x0000000000000439     54     26      1   0             0 
+
+0x000001df: 05 DW_LNS_set_column (16)
+0x000001e1: 02 DW_LNS_advance_pc (34)
+0x000001e3: 12 address += 0,  line += 0
+            0x000000000000045b     54     16      1   0             0 
+
+0x000001e4: 05 DW_LNS_set_column (21)
+0x000001e6: 82 address += 8,  line += 0
+            0x0000000000000463     54     21      1   0             0 
+
+0x000001e7: 05 DW_LNS_set_column (16)
+0x000001e9: 82 address += 8,  line += 0
+            0x000000000000046b     54     16      1   0             0 
+
+0x000001ea: 05 DW_LNS_set_column (24)
+0x000001ec: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000001ed: 82 address += 8,  line += 0
+            0x0000000000000484     54     24      1   0             0 
+
+0x000001ee: 05 DW_LNS_set_column (26)
+0x000001f0: 06 DW_LNS_negate_stmt
+0x000001f1: 91 address += 9,  line += 1
+            0x000000000000048d     55     26      1   0             0  is_stmt
+
+0x000001f2: 05 DW_LNS_set_column (16)
+0x000001f4: 06 DW_LNS_negate_stmt
+0x000001f5: 82 address += 8,  line += 0
+            0x0000000000000495     55     16      1   0             0 
+
+0x000001f6: 05 DW_LNS_set_column (21)
+0x000001f8: 82 address += 8,  line += 0
+            0x000000000000049d     55     21      1   0             0 
+
+0x000001f9: 05 DW_LNS_set_column (16)
+0x000001fb: 82 address += 8,  line += 0
+            0x00000000000004a5     55     16      1   0             0 
+
+0x000001fc: 05 DW_LNS_set_column (24)
+0x000001fe: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000001ff: 82 address += 8,  line += 0
+            0x00000000000004be     55     24      1   0             0 
+
+0x00000200: 05 DW_LNS_set_column (44)
+0x00000202: 06 DW_LNS_negate_stmt
+0x00000203: 8d address += 9,  line += -3
+            0x00000000000004c7     52     44      1   0             0  is_stmt
+
+0x00000204: 05 DW_LNS_set_column (49)
+0x00000206: 06 DW_LNS_negate_stmt
+0x00000207: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000208: d6 address += 14,  line += 0
+            0x00000000000004e6     52     49      1   0             0 
+
+0x00000209: 05 DW_LNS_set_column (13)
+0x0000020b: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x0000020c: d6 address += 14,  line += 0
+            0x0000000000000505     52     13      1   0             0 
+
+0x0000020d: 2e address += 2,  line += 0
+            0x0000000000000507     52     13      1   0             0 
+
+0x0000020e: 05 DW_LNS_set_column (18)
+0x00000210: 06 DW_LNS_negate_stmt
+0x00000211: 33 address += 2,  line += 5
+            0x0000000000000509     57     18      1   0             0  is_stmt
+
+0x00000212: 05 DW_LNS_set_column (19)
+0x00000214: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000215: d7 address += 14,  line += 1
+            0x0000000000000528     58     19      1   0             0  is_stmt
+
+0x00000216: 05 DW_LNS_set_column (24)
+0x00000218: 06 DW_LNS_negate_stmt
+0x00000219: 82 address += 8,  line += 0
+            0x0000000000000530     58     24      1   0             0 
+
+0x0000021a: 05 DW_LNS_set_column (19)
+0x0000021c: 82 address += 8,  line += 0
+            0x0000000000000538     58     19      1   0             0 
+
+0x0000021d: 05 DW_LNS_set_column (17)
+0x0000021f: 02 DW_LNS_advance_pc (34)
+0x00000221: 12 address += 0,  line += 0
+            0x000000000000055a     58     17      1   0             0 
+
+0x00000222: 05 DW_LNS_set_column (23)
+0x00000224: 06 DW_LNS_negate_stmt
+0x00000225: 83 address += 8,  line += 1
+            0x0000000000000562     59     23      1   0             0  is_stmt
+
+0x00000226: 05 DW_LNS_set_column (13)
+0x00000228: 06 DW_LNS_negate_stmt
+0x00000229: 82 address += 8,  line += 0
+            0x000000000000056a     59     13      1   0             0 
+
+0x0000022a: 05 DW_LNS_set_column (18)
+0x0000022c: 82 address += 8,  line += 0
+            0x0000000000000572     59     18      1   0             0 
+
+0x0000022d: 05 DW_LNS_set_column (13)
+0x0000022f: 82 address += 8,  line += 0
+            0x000000000000057a     59     13      1   0             0 
+
+0x00000230: 05 DW_LNS_set_column (21)
+0x00000232: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000233: 82 address += 8,  line += 0
+            0x0000000000000593     59     21      1   0             0 
+
+0x00000234: 05 DW_LNS_set_column (17)
+0x00000236: 06 DW_LNS_negate_stmt
+0x00000237: 91 address += 9,  line += 1
+            0x000000000000059c     60     17      1   0             0  is_stmt
+
+0x00000238: 05 DW_LNS_set_column (15)
+0x0000023a: 06 DW_LNS_negate_stmt
+0x0000023b: 82 address += 8,  line += 0
+            0x00000000000005a4     60     15      1   0             0 
+
+0x0000023c: 05 DW_LNS_set_column (19)
+0x0000023e: 06 DW_LNS_negate_stmt
+0x0000023f: 83 address += 8,  line += 1
+            0x00000000000005ac     61     19      1   0             0  is_stmt
+
+0x00000240: 05 DW_LNS_set_column (10)
+0x00000242: 06 DW_LNS_negate_stmt
+0x00000243: 82 address += 8,  line += 0
+            0x00000000000005b4     61     10      1   0             0 
+
+0x00000244: 05 DW_LNS_set_column (14)
+0x00000246: 06 DW_LNS_negate_stmt
+0x00000247: 67 address += 6,  line += 1
+            0x00000000000005ba     62     14      1   0             0  is_stmt
+
+0x00000248: 05 DW_LNS_set_column (25)
+0x0000024a: 06 DW_LNS_negate_stmt
+0x0000024b: 82 address += 8,  line += 0
+            0x00000000000005c2     62     25      1   0             0 
+
+0x0000024c: 05 DW_LNS_set_column (23)
+0x0000024e: 82 address += 8,  line += 0
+            0x00000000000005ca     62     23      1   0             0 
+
+0x0000024f: 05 DW_LNS_set_column (14)
+0x00000251: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000252: 58 address += 5,  line += 0
+            0x00000000000005e0     62     14      1   0             0 
+
+0x00000253: 05 DW_LNS_set_column (24)
+0x00000255: 06 DW_LNS_negate_stmt
+0x00000256: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000257: 67 address += 6,  line += 1
+            0x00000000000005f7     63     24      1   0             0  is_stmt
+
+0x00000258: 05 DW_LNS_set_column (22)
+0x0000025a: 06 DW_LNS_negate_stmt
+0x0000025b: 82 address += 8,  line += 0
+            0x00000000000005ff     63     22      1   0             0 
+
+0x0000025c: 03 DW_LNS_advance_line (0)
+0x0000025e: 82 address += 8,  line += 0
+            0x0000000000000607      0     22      1   0             0 
+
+0x0000025f: 05 DW_LNS_set_column (14)
+0x00000261: 06 DW_LNS_negate_stmt
+0x00000262: 03 DW_LNS_advance_line (66)
+0x00000265: 2e address += 2,  line += 0
+            0x0000000000000609     66     14      1   0             0  is_stmt
+
+0x00000266: 05 DW_LNS_set_column (19)
+0x00000268: 06 DW_LNS_negate_stmt
+0x00000269: 9e address += 10,  line += 0
+            0x0000000000000613     66     19      1   0             0 
+
+0x0000026a: 05 DW_LNS_set_column (21)
+0x0000026c: 82 address += 8,  line += 0
+            0x000000000000061b     66     21      1   0             0 
+
+0x0000026d: 05 DW_LNS_set_column (16)
+0x0000026f: e4 address += 15,  line += 0
+            0x000000000000062a     66     16      1   0             0 
+
+0x00000270: 05 DW_LNS_set_column (14)
+0x00000272: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000273: 58 address += 5,  line += 0
+            0x0000000000000640     66     14      1   0             0 
+
+0x00000274: 05 DW_LNS_set_column (18)
+0x00000276: 06 DW_LNS_negate_stmt
+0x00000277: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000278: 67 address += 6,  line += 1
+            0x0000000000000657     67     18      1   0             0  is_stmt
+
+0x00000279: 05 DW_LNS_set_column (13)
+0x0000027b: 06 DW_LNS_negate_stmt
+0x0000027c: 82 address += 8,  line += 0
+            0x000000000000065f     67     13      1   0             0 
+
+0x0000027d: 05 DW_LNS_set_column (18)
+0x0000027f: 06 DW_LNS_negate_stmt
+0x00000280: 91 address += 9,  line += 1
+            0x0000000000000668     68     18      1   0             0  is_stmt
+
+0x00000281: 05 DW_LNS_set_column (13)
+0x00000283: 06 DW_LNS_negate_stmt
+0x00000284: 82 address += 8,  line += 0
+            0x0000000000000670     68     13      1   0             0 
+
+0x00000285: 05 DW_LNS_set_column (18)
+0x00000287: 06 DW_LNS_negate_stmt
+0x00000288: 91 address += 9,  line += 1
+            0x0000000000000679     69     18      1   0             0  is_stmt
+
+0x00000289: 05 DW_LNS_set_column (13)
+0x0000028b: 06 DW_LNS_negate_stmt
+0x0000028c: 82 address += 8,  line += 0
+            0x0000000000000681     69     13      1   0             0 
+
+0x0000028d: 05 DW_LNS_set_column (20)
+0x0000028f: 06 DW_LNS_negate_stmt
+0x00000290: 91 address += 9,  line += 1
+            0x000000000000068a     70     20      1   0             0  is_stmt
+
+0x00000291: 05 DW_LNS_set_column (13)
+0x00000293: 06 DW_LNS_negate_stmt
+0x00000294: 82 address += 8,  line += 0
+            0x0000000000000692     70     13      1   0             0 
+
+0x00000295: 03 DW_LNS_advance_line (0)
+0x00000298: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000299: ac address += 11,  line += 0
+            0x00000000000006ae      0     13      1   0             0 
+
+0x0000029a: 05 DW_LNS_set_column (22)
+0x0000029c: 06 DW_LNS_negate_stmt
+0x0000029d: 03 DW_LNS_advance_line (74)
+0x000002a0: 66 address += 6,  line += 0
+            0x00000000000006b4     74     22      1   0             0  is_stmt
+
+0x000002a1: 05 DW_LNS_set_column (17)
+0x000002a3: 06 DW_LNS_negate_stmt
+0x000002a4: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000002a5: 12 address += 0,  line += 0
+            0x00000000000006c5     74     17      1   0             0 
+
+0x000002a6: 05 DW_LNS_set_column (20)
+0x000002a8: 06 DW_LNS_negate_stmt
+0x000002a9: 83 address += 8,  line += 1
+            0x00000000000006cd     75     20      1   0             0  is_stmt
+
+0x000002aa: 05 DW_LNS_set_column (25)
+0x000002ac: 06 DW_LNS_negate_stmt
+0x000002ad: 82 address += 8,  line += 0
+            0x00000000000006d5     75     25      1   0             0 
+
+0x000002ae: 05 DW_LNS_set_column (29)
+0x000002b0: ba address += 12,  line += 0
+            0x00000000000006e1     75     29      1   0             0 
+
+0x000002b1: 05 DW_LNS_set_column (27)
+0x000002b3: 82 address += 8,  line += 0
+            0x00000000000006e9     75     27      1   0             0 
+
+0x000002b4: 05 DW_LNS_set_column (13)
+0x000002b6: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000002b7: 58 address += 5,  line += 0
+            0x00000000000006ff     75     13      1   0             0 
+
+0x000002b8: 05 DW_LNS_set_column (27)
+0x000002ba: 06 DW_LNS_negate_stmt
+0x000002bb: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000002bc: 4b address += 4,  line += 1
+            0x0000000000000714     76     27      1   0             0  is_stmt
+
+0x000002bd: 05 DW_LNS_set_column (33)
+0x000002bf: 06 DW_LNS_negate_stmt
+0x000002c0: 82 address += 8,  line += 0
+            0x000000000000071c     76     33      1   0             0 
+
+0x000002c1: 05 DW_LNS_set_column (35)
+0x000002c3: 82 address += 8,  line += 0
+            0x0000000000000724     76     35      1   0             0 
+
+0x000002c4: 05 DW_LNS_set_column (27)
+0x000002c6: e4 address += 15,  line += 0
+            0x0000000000000733     76     27      1   0             0 
+
+0x000002c7: 05 DW_LNS_set_column (16)
+0x000002c9: 02 DW_LNS_advance_pc (34)
+0x000002cb: 12 address += 0,  line += 0
+            0x0000000000000755     76     16      1   0             0 
+
+0x000002cc: 05 DW_LNS_set_column (22)
+0x000002ce: 82 address += 8,  line += 0
+            0x000000000000075d     76     22      1   0             0 
+
+0x000002cf: 05 DW_LNS_set_column (16)
+0x000002d1: 82 address += 8,  line += 0
+            0x0000000000000765     76     16      1   0             0 
+
+0x000002d2: 05 DW_LNS_set_column (25)
+0x000002d4: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000002d5: 82 address += 8,  line += 0
+            0x000000000000077e     76     25      1   0             0 
+
+0x000002d6: 05 DW_LNS_set_column (33)
+0x000002d8: 06 DW_LNS_negate_stmt
+0x000002d9: 8f address += 9,  line += -1
+            0x0000000000000787     75     33      1   0             0  is_stmt
+
+0x000002da: 05 DW_LNS_set_column (13)
+0x000002dc: 06 DW_LNS_negate_stmt
+0x000002dd: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000002de: d6 address += 14,  line += 0
+            0x00000000000007a6     75     13      1   0             0 
+
+0x000002df: 2e address += 2,  line += 0
+            0x00000000000007a8     75     13      1   0             0 
+
+0x000002e0: 05 DW_LNS_set_column (24)
+0x000002e2: 06 DW_LNS_negate_stmt
+0x000002e3: 76 address += 7,  line += 2
+            0x00000000000007af     77     24      1   0             0  is_stmt
+
+0x000002e4: 05 DW_LNS_set_column (13)
+0x000002e6: 06 DW_LNS_negate_stmt
+0x000002e7: 82 address += 8,  line += 0
+            0x00000000000007b7     77     13      1   0             0 
+
+0x000002e8: 05 DW_LNS_set_column (19)
+0x000002ea: 82 address += 8,  line += 0
+            0x00000000000007bf     77     19      1   0             0 
+
+0x000002eb: 05 DW_LNS_set_column (13)
+0x000002ed: 82 address += 8,  line += 0
+            0x00000000000007c7     77     13      1   0             0 
+
+0x000002ee: 05 DW_LNS_set_column (22)
+0x000002f0: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000002f1: 82 address += 8,  line += 0
+            0x00000000000007e0     77     22      1   0             0 
+
+0x000002f2: 05 DW_LNS_set_column (16)
+0x000002f4: 06 DW_LNS_negate_stmt
+0x000002f5: 92 address += 9,  line += 2
+            0x00000000000007e9     79     16      1   0             0  is_stmt
+
+0x000002f6: 05 DW_LNS_set_column (22)
+0x000002f8: 06 DW_LNS_negate_stmt
+0x000002f9: 82 address += 8,  line += 0
+            0x00000000000007f1     79     22      1   0             0 
+
+0x000002fa: 05 DW_LNS_set_column (16)
+0x000002fc: 82 address += 8,  line += 0
+            0x00000000000007f9     79     16      1   0             0 
+
+0x000002fd: 05 DW_LNS_set_column (14)
+0x000002ff: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000300: 82 address += 8,  line += 0
+            0x0000000000000812     79     14      1   0             0 
+
+0x00000301: 05 DW_LNS_set_column (25)
+0x00000303: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000304: f2 address += 16,  line += 0
+            0x0000000000000833     79     25      1   0             0 
+
+0x00000305: 05 DW_LNS_set_column (14)
+0x00000307: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000308: 58 address += 5,  line += 0
+            0x0000000000000849     79     14      1   0             0 
+
+0x00000309: 05 DW_LNS_set_column (13)
+0x0000030b: 06 DW_LNS_negate_stmt
+0x0000030c: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x0000030d: 83 address += 8,  line += 1
+            0x0000000000000862     80     13      1   0             0  is_stmt
+
+0x0000030e: 06 DW_LNS_negate_stmt
+0x0000030f: 03 DW_LNS_advance_line (0)
+0x00000312: 2e address += 2,  line += 0
+            0x0000000000000864      0     13      1   0             0 
+
+0x00000313: 05 DW_LNS_set_column (11)
+0x00000315: 06 DW_LNS_negate_stmt
+0x00000316: 03 DW_LNS_advance_line (81)
+0x00000319: 20 address += 1,  line += 0
+            0x0000000000000865     81     11      1   0             0  is_stmt
+
+0x0000031a: 05 DW_LNS_set_column (7)
+0x0000031c: 03 DW_LNS_advance_line (65)
+0x0000031e: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x0000031f: d6 address += 14,  line += 0
+            0x0000000000000884     65      7      1   0             0  is_stmt
+
+0x00000320: 06 DW_LNS_negate_stmt
+0x00000321: 03 DW_LNS_advance_line (0)
+0x00000324: 2e address += 2,  line += 0
+            0x0000000000000886      0      7      1   0             0 
+
+0x00000325: 05 DW_LNS_set_column (13)
+0x00000327: 06 DW_LNS_negate_stmt
+0x00000328: 03 DW_LNS_advance_line (80)
+0x0000032b: 20 address += 1,  line += 0
+            0x0000000000000887     80     13      1   0             0  is_stmt
+
+0x0000032c: 05 DW_LNS_set_column (4)
+0x0000032e: 03 DW_LNS_advance_line (43)
+0x00000330: 20 address += 1,  line += 0
+            0x0000000000000888     43      4      1   0             0  is_stmt
+
+0x00000331: 06 DW_LNS_negate_stmt
+0x00000332: 03 DW_LNS_advance_line (0)
+0x00000334: 2e address += 2,  line += 0
+            0x000000000000088a      0      4      1   0             0 
+
+0x00000335: 02 DW_LNS_advance_pc (2)
+0x00000337: 00 DW_LNE_end_sequence
+            0x000000000000088c      0      4      1   0             0  end_sequence
+
+0x0000033a: 00 DW_LNE_set_address (0x000000000000088e)
+0x00000341: 03 DW_LNS_advance_line (152)
+0x00000344: 01 DW_LNS_copy
+            0x000000000000088e    152      0      1   0             0  is_stmt
+
+
+0x00000345: 05 DW_LNS_set_column (12)
+0x00000347: 0a DW_LNS_set_prologue_end
+0x00000348: 02 DW_LNS_advance_pc (59)
+0x0000034a: 13 address += 0,  line += 1
+            0x00000000000008c9    153     12      1   0             0  is_stmt prologue_end
+
+0x0000034b: 05 DW_LNS_set_column (17)
+0x0000034d: 06 DW_LNS_negate_stmt
+0x0000034e: 74 address += 7,  line += 0
+            0x00000000000008d0    153     17      1   0             0 
+
+0x0000034f: 05 DW_LNS_set_column (12)
+0x00000351: e4 address += 15,  line += 0
+            0x00000000000008df    153     12      1   0             0 
+
+0x00000352: 05 DW_LNS_set_column (28)
+0x00000354: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000355: 3c address += 3,  line += 0
+            0x00000000000008f3    153     28      1   0             0 
+
+0x00000356: 05 DW_LNS_set_column (23)
+0x00000358: d6 address += 14,  line += 0
+            0x0000000000000901    153     23      1   0             0 
+
+0x00000359: 05 DW_LNS_set_column (12)
+0x0000035b: 9e address += 10,  line += 0
+            0x000000000000090b    153     12      1   0             0 
+
+0x0000035c: 03 DW_LNS_advance_line (0)
+0x0000035f: 66 address += 6,  line += 0
+            0x0000000000000911      0     12      1   0             0 
+
+0x00000360: 03 DW_LNS_advance_line (153)
+0x00000363: 58 address += 5,  line += 0
+            0x0000000000000916    153     12      1   0             0 
+
+0x00000364: 03 DW_LNS_advance_line (0)
+0x00000367: 4a address += 4,  line += 0
+            0x000000000000091a      0     12      1   0             0 
+
+0x00000368: 03 DW_LNS_advance_line (153)
+0x0000036b: 20 address += 1,  line += 0
+            0x000000000000091b    153     12      1   0             0 
+
+0x0000036c: 05 DW_LNS_set_column (8)
+0x0000036e: 82 address += 8,  line += 0
+            0x0000000000000923    153      8      1   0             0 
+
+0x0000036f: 06 DW_LNS_negate_stmt
+0x00000370: 76 address += 7,  line += 2
+            0x000000000000092a    155      8      1   0             0  is_stmt
+
+0x00000371: 05 DW_LNS_set_column (10)
+0x00000373: 06 DW_LNS_negate_stmt
+0x00000374: 74 address += 7,  line += 0
+            0x0000000000000931    155     10      1   0             0 
+
+0x00000375: 05 DW_LNS_set_column (8)
+0x00000377: e4 address += 15,  line += 0
+            0x0000000000000940    155      8      1   0             0 
+
+0x00000378: 05 DW_LNS_set_column (7)
+0x0000037a: 06 DW_LNS_negate_stmt
+0x0000037b: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x0000037c: 3d address += 3,  line += 1
+            0x0000000000000954    156      7      1   0             0  is_stmt
+
+0x0000037d: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x0000037e: 9f address += 10,  line += 1
+            0x000000000000096f    157      7      1   0             0  is_stmt
+
+0x0000037f: 06 DW_LNS_negate_stmt
+0x00000380: 03 DW_LNS_advance_line (0)
+0x00000383: 90 address += 9,  line += 0
+            0x0000000000000978      0      7      1   0             0 
+
+0x00000384: 05 DW_LNS_set_column (38)
+0x00000386: 06 DW_LNS_negate_stmt
+0x00000387: 03 DW_LNS_advance_line (159)
+0x0000038a: 20 address += 1,  line += 0
+            0x0000000000000979    159     38      1   0             0  is_stmt
+
+0x0000038b: 05 DW_LNS_set_column (50)
+0x0000038d: 06 DW_LNS_negate_stmt
+0x0000038e: 74 address += 7,  line += 0
+            0x0000000000000980    159     50      1   0             0 
+
+0x0000038f: 05 DW_LNS_set_column (41)
+0x00000391: 74 address += 7,  line += 0
+            0x0000000000000987    159     41      1   0             0 
+
+0x00000392: 05 DW_LNS_set_column (4)
+0x00000394: 9e address += 10,  line += 0
+            0x0000000000000991    159      4      1   0             0 
+
+0x00000395: 06 DW_LNS_negate_stmt
+0x00000396: 02 DW_LNS_advance_pc (37)
+0x00000398: 13 address += 0,  line += 1
+            0x00000000000009b6    160      4      1   0             0  is_stmt
+
+0x00000399: 06 DW_LNS_negate_stmt
+0x0000039a: 03 DW_LNS_advance_line (0)
+0x0000039d: 74 address += 7,  line += 0
+            0x00000000000009bd      0      4      1   0             0 
+
+0x0000039e: 05 DW_LNS_set_column (1)
+0x000003a0: 06 DW_LNS_negate_stmt
+0x000003a1: 03 DW_LNS_advance_line (161)
+0x000003a4: 20 address += 1,  line += 0
+            0x00000000000009be    161      1      1   0             0  is_stmt
+
+0x000003a5: 02 DW_LNS_advance_pc (30)
+0x000003a7: 00 DW_LNE_end_sequence
+            0x00000000000009dc    161      1      1   0             0  is_stmt end_sequence
+
+0x000003aa: 00 DW_LNE_set_address (0x00000000000009de)
+0x000003b1: 03 DW_LNS_advance_line (88)
+0x000003b4: 01 DW_LNS_copy
+            0x00000000000009de     88      0      1   0             0  is_stmt
+
+
+0x000003b5: 05 DW_LNS_set_column (8)
+0x000003b7: 0a DW_LNS_set_prologue_end
+0x000003b8: 02 DW_LNS_advance_pc (46)
+0x000003ba: 14 address += 0,  line += 2
+            0x0000000000000a0c     90      8      1   0             0  is_stmt prologue_end
+
+0x000003bb: 05 DW_LNS_set_column (9)
+0x000003bd: 77 address += 7,  line += 3
+            0x0000000000000a13     93      9      1   0             0  is_stmt
+
+0x000003be: 05 DW_LNS_set_column (11)
+0x000003c0: 75 address += 7,  line += 1
+            0x0000000000000a1a     94     11      1   0             0  is_stmt
+
+0x000003c1: 05 DW_LNS_set_column (16)
+0x000003c3: 06 DW_LNS_negate_stmt
+0x000003c4: 74 address += 7,  line += 0
+            0x0000000000000a21     94     16      1   0             0 
+
+0x000003c5: 05 DW_LNS_set_column (20)
+0x000003c7: ac address += 11,  line += 0
+            0x0000000000000a2c     94     20      1   0             0 
+
+0x000003c8: 05 DW_LNS_set_column (22)
+0x000003ca: 74 address += 7,  line += 0
+            0x0000000000000a33     94     22      1   0             0 
+
+0x000003cb: 05 DW_LNS_set_column (18)
+0x000003cd: ac address += 11,  line += 0
+            0x0000000000000a3e     94     18      1   0             0 
+
+0x000003ce: 05 DW_LNS_set_column (4)
+0x000003d0: e4 address += 15,  line += 0
+            0x0000000000000a4d     94      4      1   0             0 
+
+0x000003d1: 03 DW_LNS_advance_line (0)
+0x000003d4: f2 address += 16,  line += 0
+            0x0000000000000a5d      0      4      1   0             0 
+
+0x000003d5: 05 DW_LNS_set_column (29)
+0x000003d7: 06 DW_LNS_negate_stmt
+0x000003d8: 03 DW_LNS_advance_line (95)
+0x000003db: 4a address += 4,  line += 0
+            0x0000000000000a61     95     29      1   0             0  is_stmt
+
+0x000003dc: 05 DW_LNS_set_column (13)
+0x000003de: 06 DW_LNS_negate_stmt
+0x000003df: 9e address += 10,  line += 0
+            0x0000000000000a6b     95     13      1   0             0 
+
+0x000003e0: 05 DW_LNS_set_column (18)
+0x000003e2: 06 DW_LNS_negate_stmt
+0x000003e3: 75 address += 7,  line += 1
+            0x0000000000000a72     96     18      1   0             0  is_stmt
+
+0x000003e4: 05 DW_LNS_set_column (7)
+0x000003e6: 06 DW_LNS_negate_stmt
+0x000003e7: 74 address += 7,  line += 0
+            0x0000000000000a79     96      7      1   0             0 
+
+0x000003e8: 05 DW_LNS_set_column (16)
+0x000003ea: 74 address += 7,  line += 0
+            0x0000000000000a80     96     16      1   0             0 
+
+0x000003eb: 05 DW_LNS_set_column (18)
+0x000003ed: 06 DW_LNS_negate_stmt
+0x000003ee: 75 address += 7,  line += 1
+            0x0000000000000a87     97     18      1   0             0  is_stmt
+
+0x000003ef: 05 DW_LNS_set_column (7)
+0x000003f1: 06 DW_LNS_negate_stmt
+0x000003f2: 74 address += 7,  line += 0
+            0x0000000000000a8e     97      7      1   0             0 
+
+0x000003f3: 05 DW_LNS_set_column (16)
+0x000003f5: 74 address += 7,  line += 0
+            0x0000000000000a95     97     16      1   0             0 
+
+0x000003f6: 05 DW_LNS_set_column (21)
+0x000003f8: 06 DW_LNS_negate_stmt
+0x000003f9: 75 address += 7,  line += 1
+            0x0000000000000a9c     98     21      1   0             0  is_stmt
+
+0x000003fa: 05 DW_LNS_set_column (7)
+0x000003fc: 06 DW_LNS_negate_stmt
+0x000003fd: 74 address += 7,  line += 0
+            0x0000000000000aa3     98      7      1   0             0 
+
+0x000003fe: 05 DW_LNS_set_column (19)
+0x00000400: 74 address += 7,  line += 0
+            0x0000000000000aaa     98     19      1   0             0 
+
+0x00000401: 05 DW_LNS_set_column (14)
+0x00000403: 06 DW_LNS_negate_stmt
+0x00000404: 75 address += 7,  line += 1
+            0x0000000000000ab1     99     14      1   0             0  is_stmt
+
+0x00000405: 05 DW_LNS_set_column (12)
+0x00000407: 06 DW_LNS_negate_stmt
+0x00000408: 74 address += 7,  line += 0
+            0x0000000000000ab8     99     12      1   0             0 
+
+0x00000409: 05 DW_LNS_set_column (28)
+0x0000040b: 06 DW_LNS_negate_stmt
+0x0000040c: 6f address += 7,  line += -5
+            0x0000000000000abf     94     28      1   0             0  is_stmt
+
+0x0000040d: 05 DW_LNS_set_column (4)
+0x0000040f: 06 DW_LNS_negate_stmt
+0x00000410: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000411: 82 address += 8,  line += 0
+            0x0000000000000ad8     94      4      1   0             0 
+
+0x00000412: 2e address += 2,  line += 0
+            0x0000000000000ada     94      4      1   0             0 
+
+0x00000413: 05 DW_LNS_set_column (25)
+0x00000415: 06 DW_LNS_negate_stmt
+0x00000416: 6e address += 6,  line += 8
+            0x0000000000000ae0    102     25      1   0             0  is_stmt
+
+0x00000417: 05 DW_LNS_set_column (27)
+0x00000419: 06 DW_LNS_negate_stmt
+0x0000041a: 74 address += 7,  line += 0
+            0x0000000000000ae7    102     27      1   0             0 
+
+0x0000041b: 05 DW_LNS_set_column (18)
+0x0000041d: ac address += 11,  line += 0
+            0x0000000000000af2    102     18      1   0             0 
+
+0x0000041e: 05 DW_LNS_set_column (10)
+0x00000420: 9e address += 10,  line += 0
+            0x0000000000000afc    102     10      1   0             0 
+
+0x00000421: 05 DW_LNS_set_column (25)
+0x00000423: 06 DW_LNS_negate_stmt
+0x00000424: 75 address += 7,  line += 1
+            0x0000000000000b03    103     25      1   0             0  is_stmt
+
+0x00000425: 05 DW_LNS_set_column (27)
+0x00000427: 06 DW_LNS_negate_stmt
+0x00000428: 74 address += 7,  line += 0
+            0x0000000000000b0a    103     27      1   0             0 
+
+0x00000429: 05 DW_LNS_set_column (18)
+0x0000042b: ac address += 11,  line += 0
+            0x0000000000000b15    103     18      1   0             0 
+
+0x0000042c: 05 DW_LNS_set_column (10)
+0x0000042e: 9e address += 10,  line += 0
+            0x0000000000000b1f    103     10      1   0             0 
+
+0x0000042f: 05 DW_LNS_set_column (11)
+0x00000431: 06 DW_LNS_negate_stmt
+0x00000432: 76 address += 7,  line += 2
+            0x0000000000000b26    105     11      1   0             0  is_stmt
+
+0x00000433: 05 DW_LNS_set_column (16)
+0x00000435: 06 DW_LNS_negate_stmt
+0x00000436: 74 address += 7,  line += 0
+            0x0000000000000b2d    105     16      1   0             0 
+
+0x00000437: 05 DW_LNS_set_column (20)
+0x00000439: ac address += 11,  line += 0
+            0x0000000000000b38    105     20      1   0             0 
+
+0x0000043a: 05 DW_LNS_set_column (18)
+0x0000043c: 74 address += 7,  line += 0
+            0x0000000000000b3f    105     18      1   0             0 
+
+0x0000043d: 05 DW_LNS_set_column (4)
+0x0000043f: e4 address += 15,  line += 0
+            0x0000000000000b4e    105      4      1   0             0 
+
+0x00000440: 05 DW_LNS_set_column (18)
+0x00000442: 06 DW_LNS_negate_stmt
+0x00000443: f3 address += 16,  line += 1
+            0x0000000000000b5e    106     18      1   0             0  is_stmt
+
+0x00000444: 05 DW_LNS_set_column (7)
+0x00000446: 06 DW_LNS_negate_stmt
+0x00000447: 74 address += 7,  line += 0
+            0x0000000000000b65    106      7      1   0             0 
+
+0x00000448: 05 DW_LNS_set_column (13)
+0x0000044a: 74 address += 7,  line += 0
+            0x0000000000000b6c    106     13      1   0             0 
+
+0x0000044b: 05 DW_LNS_set_column (7)
+0x0000044d: 74 address += 7,  line += 0
+            0x0000000000000b73    106      7      1   0             0 
+
+0x0000044e: 05 DW_LNS_set_column (16)
+0x00000450: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000451: 20 address += 1,  line += 0
+            0x0000000000000b85    106     16      1   0             0 
+
+0x00000452: 05 DW_LNS_set_column (24)
+0x00000454: 06 DW_LNS_negate_stmt
+0x00000455: 73 address += 7,  line += -1
+            0x0000000000000b8c    105     24      1   0             0  is_stmt
+
+0x00000456: 05 DW_LNS_set_column (4)
+0x00000458: 06 DW_LNS_negate_stmt
+0x00000459: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x0000045a: 82 address += 8,  line += 0
+            0x0000000000000ba5    105      4      1   0             0 
+
+0x0000045b: 2e address += 2,  line += 0
+            0x0000000000000ba7    105      4      1   0             0 
+
+0x0000045c: 05 DW_LNS_set_column (8)
+0x0000045e: 06 DW_LNS_negate_stmt
+0x0000045f: 31 address += 2,  line += 3
+            0x0000000000000ba9    108      8      1   0             0  is_stmt
+
+0x00000460: 05 DW_LNS_set_column (6)
+0x00000462: 06 DW_LNS_negate_stmt
+0x00000463: 74 address += 7,  line += 0
+            0x0000000000000bb0    108      6      1   0             0 
+
+0x00000464: 05 DW_LNS_set_column (11)
+0x00000466: 06 DW_LNS_negate_stmt
+0x00000467: 76 address += 7,  line += 2
+            0x0000000000000bb7    110     11      1   0             0  is_stmt
+
+0x00000468: 06 DW_LNS_negate_stmt
+0x00000469: ac address += 11,  line += 0
+            0x0000000000000bc2    110     11      1   0             0 
+
+0x0000046a: 03 DW_LNS_advance_line (0)
+0x0000046d: 90 address += 9,  line += 0
+            0x0000000000000bcb      0     11      1   0             0 
+
+0x0000046e: 05 DW_LNS_set_column (17)
+0x00000470: 06 DW_LNS_negate_stmt
+0x00000471: 03 DW_LNS_advance_line (111)
+0x00000474: 4a address += 4,  line += 0
+            0x0000000000000bcf    111     17      1   0             0  is_stmt
+
+0x00000475: 05 DW_LNS_set_column (22)
+0x00000477: 06 DW_LNS_negate_stmt
+0x00000478: 74 address += 7,  line += 0
+            0x0000000000000bd6    111     22      1   0             0 
+
+0x00000479: 05 DW_LNS_set_column (26)
+0x0000047b: ac address += 11,  line += 0
+            0x0000000000000be1    111     26      1   0             0 
+
+0x0000047c: 05 DW_LNS_set_column (24)
+0x0000047e: 74 address += 7,  line += 0
+            0x0000000000000be8    111     24      1   0             0 
+
+0x0000047f: 05 DW_LNS_set_column (10)
+0x00000481: e4 address += 15,  line += 0
+            0x0000000000000bf7    111     10      1   0             0 
+
+0x00000482: 05 DW_LNS_set_column (26)
+0x00000484: 06 DW_LNS_negate_stmt
+0x00000485: f3 address += 16,  line += 1
+            0x0000000000000c07    112     26      1   0             0  is_stmt
+
+0x00000486: 05 DW_LNS_set_column (32)
+0x00000488: 06 DW_LNS_negate_stmt
+0x00000489: 74 address += 7,  line += 0
+            0x0000000000000c0e    112     32      1   0             0 
+
+0x0000048a: 05 DW_LNS_set_column (26)
+0x0000048c: 74 address += 7,  line += 0
+            0x0000000000000c15    112     26      1   0             0 
+
+0x0000048d: 05 DW_LNS_set_column (35)
+0x0000048f: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000490: 82 address += 8,  line += 0
+            0x0000000000000c2e    112     35      1   0             0 
+
+0x00000491: 05 DW_LNS_set_column (13)
+0x00000493: ac address += 11,  line += 0
+            0x0000000000000c39    112     13      1   0             0 
+
+0x00000494: 05 DW_LNS_set_column (30)
+0x00000496: 06 DW_LNS_negate_stmt
+0x00000497: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000498: 8f address += 9,  line += -1
+            0x0000000000000c53    111     30      1   0             0  is_stmt
+
+0x00000499: 05 DW_LNS_set_column (10)
+0x0000049b: 06 DW_LNS_negate_stmt
+0x0000049c: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x0000049d: 82 address += 8,  line += 0
+            0x0000000000000c6c    111     10      1   0             0 
+
+0x0000049e: 2e address += 2,  line += 0
+            0x0000000000000c6e    111     10      1   0             0 
+
+0x0000049f: 06 DW_LNS_negate_stmt
+0x000004a0: 30 address += 2,  line += 2
+            0x0000000000000c70    113     10      1   0             0  is_stmt
+
+0x000004a1: 05 DW_LNS_set_column (17)
+0x000004a3: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000004a4: 67 address += 6,  line += 1
+            0x0000000000000c87    114     17      1   0             0  is_stmt
+
+0x000004a5: 05 DW_LNS_set_column (7)
+0x000004a7: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000004a8: 83 address += 8,  line += 1
+            0x0000000000000ca0    115      7      1   0             0  is_stmt
+
+0x000004a9: 06 DW_LNS_negate_stmt
+0x000004aa: 03 DW_LNS_advance_line (0)
+0x000004ad: 2e address += 2,  line += 0
+            0x0000000000000ca2      0      7      1   0             0 
+
+0x000004ae: 05 DW_LNS_set_column (10)
+0x000004b0: 06 DW_LNS_negate_stmt
+0x000004b1: 03 DW_LNS_advance_line (116)
+0x000004b4: 20 address += 1,  line += 0
+            0x0000000000000ca3    116     10      1   0             0  is_stmt
+
+0x000004b5: 06 DW_LNS_negate_stmt
+0x000004b6: 03 DW_LNS_advance_line (0)
+0x000004b9: 2e address += 2,  line += 0
+            0x0000000000000ca5      0     10      1   0             0 
+
+0x000004ba: 05 DW_LNS_set_column (14)
+0x000004bc: 06 DW_LNS_negate_stmt
+0x000004bd: 03 DW_LNS_advance_line (118)
+0x000004c0: 90 address += 9,  line += 0
+            0x0000000000000cae    118     14      1   0             0  is_stmt
+
+0x000004c1: 05 DW_LNS_set_column (16)
+0x000004c3: 06 DW_LNS_negate_stmt
+0x000004c4: 74 address += 7,  line += 0
+            0x0000000000000cb5    118     16      1   0             0 
+
+0x000004c5: 05 DW_LNS_set_column (7)
+0x000004c7: e4 address += 15,  line += 0
+            0x0000000000000cc4    118      7      1   0             0 
+
+0x000004c8: 05 DW_LNS_set_column (25)
+0x000004ca: 06 DW_LNS_negate_stmt
+0x000004cb: f3 address += 16,  line += 1
+            0x0000000000000cd4    119     25      1   0             0  is_stmt
+
+0x000004cc: 05 DW_LNS_set_column (10)
+0x000004ce: 06 DW_LNS_negate_stmt
+0x000004cf: 74 address += 7,  line += 0
+            0x0000000000000cdb    119     10      1   0             0 
+
+0x000004d0: 05 DW_LNS_set_column (16)
+0x000004d2: 74 address += 7,  line += 0
+            0x0000000000000ce2    119     16      1   0             0 
+
+0x000004d3: 05 DW_LNS_set_column (18)
+0x000004d5: 74 address += 7,  line += 0
+            0x0000000000000ce9    119     18      1   0             0 
+
+0x000004d6: 05 DW_LNS_set_column (10)
+0x000004d8: ac address += 11,  line += 0
+            0x0000000000000cf4    119     10      1   0             0 
+
+0x000004d9: 05 DW_LNS_set_column (23)
+0x000004db: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000004dc: 20 address += 1,  line += 0
+            0x0000000000000d06    119     23      1   0             0 
+
+0x000004dd: 05 DW_LNS_set_column (22)
+0x000004df: 06 DW_LNS_negate_stmt
+0x000004e0: 73 address += 7,  line += -1
+            0x0000000000000d0d    118     22      1   0             0  is_stmt
+
+0x000004e1: 05 DW_LNS_set_column (7)
+0x000004e3: 06 DW_LNS_negate_stmt
+0x000004e4: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000004e5: 82 address += 8,  line += 0
+            0x0000000000000d26    118      7      1   0             0 
+
+0x000004e6: 2e address += 2,  line += 0
+            0x0000000000000d28    118      7      1   0             0 
+
+0x000004e7: 05 DW_LNS_set_column (14)
+0x000004e9: 06 DW_LNS_negate_stmt
+0x000004ea: 32 address += 2,  line += 4
+            0x0000000000000d2a    122     14      1   0             0  is_stmt
+
+0x000004eb: 05 DW_LNS_set_column (19)
+0x000004ed: 06 DW_LNS_negate_stmt
+0x000004ee: 90 address += 9,  line += 0
+            0x0000000000000d33    122     19      1   0             0 
+
+0x000004ef: 05 DW_LNS_set_column (16)
+0x000004f1: 74 address += 7,  line += 0
+            0x0000000000000d3a    122     16      1   0             0 
+
+0x000004f2: 05 DW_LNS_set_column (14)
+0x000004f4: e4 address += 15,  line += 0
+            0x0000000000000d49    122     14      1   0             0 
+
+0x000004f5: 05 DW_LNS_set_column (13)
+0x000004f7: 06 DW_LNS_negate_stmt
+0x000004f8: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000004f9: 21 address += 1,  line += 1
+            0x0000000000000d5b    123     13      1   0             0  is_stmt
+
+0x000004fa: 06 DW_LNS_negate_stmt
+0x000004fb: 03 DW_LNS_advance_line (0)
+0x000004fe: 2e address += 2,  line += 0
+            0x0000000000000d5d      0     13      1   0             0 
+
+0x000004ff: 05 DW_LNS_set_column (22)
+0x00000501: 06 DW_LNS_negate_stmt
+0x00000502: 03 DW_LNS_advance_line (125)
+0x00000505: 58 address += 5,  line += 0
+            0x0000000000000d62    125     22      1   0             0  is_stmt
+
+0x00000506: 05 DW_LNS_set_column (17)
+0x00000508: 06 DW_LNS_negate_stmt
+0x00000509: d6 address += 14,  line += 0
+            0x0000000000000d70    125     17      1   0             0 
+
+0x0000050a: 05 DW_LNS_set_column (20)
+0x0000050c: 06 DW_LNS_negate_stmt
+0x0000050d: 75 address += 7,  line += 1
+            0x0000000000000d77    126     20      1   0             0  is_stmt
+
+0x0000050e: 05 DW_LNS_set_column (25)
+0x00000510: 06 DW_LNS_negate_stmt
+0x00000511: 74 address += 7,  line += 0
+            0x0000000000000d7e    126     25      1   0             0 
+
+0x00000512: 05 DW_LNS_set_column (29)
+0x00000514: ac address += 11,  line += 0
+            0x0000000000000d89    126     29      1   0             0 
+
+0x00000515: 05 DW_LNS_set_column (27)
+0x00000517: 74 address += 7,  line += 0
+            0x0000000000000d90    126     27      1   0             0 
+
+0x00000518: 05 DW_LNS_set_column (13)
+0x0000051a: e4 address += 15,  line += 0
+            0x0000000000000d9f    126     13      1   0             0 
+
+0x0000051b: 05 DW_LNS_set_column (27)
+0x0000051d: 06 DW_LNS_negate_stmt
+0x0000051e: f3 address += 16,  line += 1
+            0x0000000000000daf    127     27      1   0             0  is_stmt
+
+0x0000051f: 05 DW_LNS_set_column (33)
+0x00000521: 06 DW_LNS_negate_stmt
+0x00000522: 74 address += 7,  line += 0
+            0x0000000000000db6    127     33      1   0             0 
+
+0x00000523: 05 DW_LNS_set_column (35)
+0x00000525: 74 address += 7,  line += 0
+            0x0000000000000dbd    127     35      1   0             0 
+
+0x00000526: 05 DW_LNS_set_column (27)
+0x00000528: ac address += 11,  line += 0
+            0x0000000000000dc8    127     27      1   0             0 
+
+0x00000529: 05 DW_LNS_set_column (16)
+0x0000052b: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x0000052c: 82 address += 8,  line += 0
+            0x0000000000000de1    127     16      1   0             0 
+
+0x0000052d: 05 DW_LNS_set_column (22)
+0x0000052f: 74 address += 7,  line += 0
+            0x0000000000000de8    127     22      1   0             0 
+
+0x00000530: 05 DW_LNS_set_column (16)
+0x00000532: 74 address += 7,  line += 0
+            0x0000000000000def    127     16      1   0             0 
+
+0x00000533: 05 DW_LNS_set_column (25)
+0x00000535: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000536: 20 address += 1,  line += 0
+            0x0000000000000e01    127     25      1   0             0 
+
+0x00000537: 05 DW_LNS_set_column (33)
+0x00000539: 06 DW_LNS_negate_stmt
+0x0000053a: 73 address += 7,  line += -1
+            0x0000000000000e08    126     33      1   0             0  is_stmt
+
+0x0000053b: 05 DW_LNS_set_column (13)
+0x0000053d: 06 DW_LNS_negate_stmt
+0x0000053e: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x0000053f: ba address += 12,  line += 0
+            0x0000000000000e25    126     13      1   0             0 
+
+0x00000540: 2e address += 2,  line += 0
+            0x0000000000000e27    126     13      1   0             0 
+
+0x00000541: 05 DW_LNS_set_column (24)
+0x00000543: 06 DW_LNS_negate_stmt
+0x00000544: 76 address += 7,  line += 2
+            0x0000000000000e2e    128     24      1   0             0  is_stmt
+
+0x00000545: 05 DW_LNS_set_column (13)
+0x00000547: 06 DW_LNS_negate_stmt
+0x00000548: 82 address += 8,  line += 0
+            0x0000000000000e36    128     13      1   0             0 
+
+0x00000549: 05 DW_LNS_set_column (19)
+0x0000054b: 82 address += 8,  line += 0
+            0x0000000000000e3e    128     19      1   0             0 
+
+0x0000054c: 05 DW_LNS_set_column (13)
+0x0000054e: 82 address += 8,  line += 0
+            0x0000000000000e46    128     13      1   0             0 
+
+0x0000054f: 05 DW_LNS_set_column (22)
+0x00000551: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000552: 82 address += 8,  line += 0
+            0x0000000000000e5f    128     22      1   0             0 
+
+0x00000553: 05 DW_LNS_set_column (16)
+0x00000555: 06 DW_LNS_negate_stmt
+0x00000556: 92 address += 9,  line += 2
+            0x0000000000000e68    130     16      1   0             0  is_stmt
+
+0x00000557: 05 DW_LNS_set_column (22)
+0x00000559: 06 DW_LNS_negate_stmt
+0x0000055a: 82 address += 8,  line += 0
+            0x0000000000000e70    130     22      1   0             0 
+
+0x0000055b: 05 DW_LNS_set_column (16)
+0x0000055d: 82 address += 8,  line += 0
+            0x0000000000000e78    130     16      1   0             0 
+
+0x0000055e: 05 DW_LNS_set_column (14)
+0x00000560: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000561: 82 address += 8,  line += 0
+            0x0000000000000e91    130     14      1   0             0 
+
+0x00000562: 05 DW_LNS_set_column (25)
+0x00000564: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000565: f2 address += 16,  line += 0
+            0x0000000000000eb2    130     25      1   0             0 
+
+0x00000566: 05 DW_LNS_set_column (14)
+0x00000568: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000569: 58 address += 5,  line += 0
+            0x0000000000000ec8    130     14      1   0             0 
+
+0x0000056a: 05 DW_LNS_set_column (13)
+0x0000056c: 06 DW_LNS_negate_stmt
+0x0000056d: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x0000056e: 83 address += 8,  line += 1
+            0x0000000000000ee1    131     13      1   0             0  is_stmt
+
+0x0000056f: 06 DW_LNS_negate_stmt
+0x00000570: 03 DW_LNS_advance_line (0)
+0x00000573: 2e address += 2,  line += 0
+            0x0000000000000ee3      0     13      1   0             0 
+
+0x00000574: 05 DW_LNS_set_column (11)
+0x00000576: 06 DW_LNS_negate_stmt
+0x00000577: 03 DW_LNS_advance_line (133)
+0x0000057a: 20 address += 1,  line += 0
+            0x0000000000000ee4    133     11      1   0             0  is_stmt
+
+0x0000057b: 05 DW_LNS_set_column (7)
+0x0000057d: 03 DW_LNS_advance_line (121)
+0x0000057f: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000580: d6 address += 14,  line += 0
+            0x0000000000000f03    121      7      1   0             0  is_stmt
+
+0x00000581: 06 DW_LNS_negate_stmt
+0x00000582: 03 DW_LNS_advance_line (0)
+0x00000585: 2e address += 2,  line += 0
+            0x0000000000000f05      0      7      1   0             0 
+
+0x00000586: 05 DW_LNS_set_column (13)
+0x00000588: 06 DW_LNS_negate_stmt
+0x00000589: 03 DW_LNS_advance_line (131)
+0x0000058c: 20 address += 1,  line += 0
+            0x0000000000000f06    131     13      1   0             0  is_stmt
+
+0x0000058d: 05 DW_LNS_set_column (4)
+0x0000058f: 03 DW_LNS_advance_line (109)
+0x00000591: 20 address += 1,  line += 0
+            0x0000000000000f07    109      4      1   0             0  is_stmt
+
+0x00000592: 05 DW_LNS_set_column (13)
+0x00000594: 03 DW_LNS_advance_line (123)
+0x00000596: 2e address += 2,  line += 0
+            0x0000000000000f09    123     13      1   0             0  is_stmt
+
+0x00000597: 05 DW_LNS_set_column (9)
+0x00000599: 03 DW_LNS_advance_line (138)
+0x0000059b: 74 address += 7,  line += 0
+            0x0000000000000f10    138      9      1   0             0  is_stmt
+
+0x0000059c: 05 DW_LNS_set_column (4)
+0x0000059e: 06 DW_LNS_negate_stmt
+0x0000059f: 82 address += 8,  line += 0
+            0x0000000000000f18    138      4      1   0             0 
+
+0x000005a0: 05 DW_LNS_set_column (9)
+0x000005a2: 06 DW_LNS_negate_stmt
+0x000005a3: 91 address += 9,  line += 1
+            0x0000000000000f21    139      9      1   0             0  is_stmt
+
+0x000005a4: 05 DW_LNS_set_column (4)
+0x000005a6: 06 DW_LNS_negate_stmt
+0x000005a7: 82 address += 8,  line += 0
+            0x0000000000000f29    139      4      1   0             0 
+
+0x000005a8: 05 DW_LNS_set_column (13)
+0x000005aa: 06 DW_LNS_negate_stmt
+0x000005ab: 91 address += 9,  line += 1
+            0x0000000000000f32    140     13      1   0             0  is_stmt
+
+0x000005ac: 06 DW_LNS_negate_stmt
+0x000005ad: 03 DW_LNS_advance_line (0)
+0x000005b0: 82 address += 8,  line += 0
+            0x0000000000000f3a      0     13      1   0             0 
+
+0x000005b1: 05 DW_LNS_set_column (11)
+0x000005b3: 06 DW_LNS_negate_stmt
+0x000005b4: 03 DW_LNS_advance_line (141)
+0x000005b7: 90 address += 9,  line += 0
+            0x0000000000000f43    141     11      1   0             0  is_stmt
+
+0x000005b8: 05 DW_LNS_set_column (16)
+0x000005ba: 06 DW_LNS_negate_stmt
+0x000005bb: 82 address += 8,  line += 0
+            0x0000000000000f4b    141     16      1   0             0 
+
+0x000005bc: 05 DW_LNS_set_column (4)
+0x000005be: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000005bf: 58 address += 5,  line += 0
+            0x0000000000000f61    141      4      1   0             0 
+
+0x000005c0: 05 DW_LNS_set_column (36)
+0x000005c2: 06 DW_LNS_negate_stmt
+0x000005c3: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000005c4: 4b address += 4,  line += 1
+            0x0000000000000f76    142     36      1   0             0  is_stmt
+
+0x000005c5: 05 DW_LNS_set_column (20)
+0x000005c7: 06 DW_LNS_negate_stmt
+0x000005c8: 82 address += 8,  line += 0
+            0x0000000000000f7e    142     20      1   0             0 
+
+0x000005c9: 05 DW_LNS_set_column (13)
+0x000005cb: ba address += 12,  line += 0
+            0x0000000000000f8a    142     13      1   0             0 
+
+0x000005cc: 05 DW_LNS_set_column (11)
+0x000005ce: 06 DW_LNS_negate_stmt
+0x000005cf: 83 address += 8,  line += 1
+            0x0000000000000f92    143     11      1   0             0  is_stmt
+
+0x000005d0: 05 DW_LNS_set_column (22)
+0x000005d2: 06 DW_LNS_negate_stmt
+0x000005d3: 82 address += 8,  line += 0
+            0x0000000000000f9a    143     22      1   0             0 
+
+0x000005d4: 05 DW_LNS_set_column (20)
+0x000005d6: 82 address += 8,  line += 0
+            0x0000000000000fa2    143     20      1   0             0 
+
+0x000005d7: 05 DW_LNS_set_column (11)
+0x000005d9: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000005da: 58 address += 5,  line += 0
+            0x0000000000000fb8    143     11      1   0             0 
+
+0x000005db: 05 DW_LNS_set_column (21)
+0x000005dd: 06 DW_LNS_negate_stmt
+0x000005de: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000005df: 67 address += 6,  line += 1
+            0x0000000000000fcf    144     21      1   0             0  is_stmt
+
+0x000005e0: 05 DW_LNS_set_column (19)
+0x000005e2: 06 DW_LNS_negate_stmt
+0x000005e3: 82 address += 8,  line += 0
+            0x0000000000000fd7    144     19      1   0             0 
+
+0x000005e4: 03 DW_LNS_advance_line (0)
+0x000005e7: 82 address += 8,  line += 0
+            0x0000000000000fdf      0     19      1   0             0 
+
+0x000005e8: 05 DW_LNS_set_column (15)
+0x000005ea: 06 DW_LNS_negate_stmt
+0x000005eb: 03 DW_LNS_advance_line (145)
+0x000005ee: 20 address += 1,  line += 0
+            0x0000000000000fe0    145     15      1   0             0  is_stmt
+
+0x000005ef: 05 DW_LNS_set_column (13)
+0x000005f1: 06 DW_LNS_negate_stmt
+0x000005f2: 82 address += 8,  line += 0
+            0x0000000000000fe8    145     13      1   0             0 
+
+0x000005f3: 05 DW_LNS_set_column (14)
+0x000005f5: 06 DW_LNS_negate_stmt
+0x000005f6: 83 address += 8,  line += 1
+            0x0000000000000ff0    146     14      1   0             0  is_stmt
+
+0x000005f7: 05 DW_LNS_set_column (20)
+0x000005f9: 06 DW_LNS_negate_stmt
+0x000005fa: 82 address += 8,  line += 0
+            0x0000000000000ff8    146     20      1   0             0 
+
+0x000005fb: 05 DW_LNS_set_column (12)
+0x000005fd: 90 address += 9,  line += 0
+            0x0000000000001001    146     12      1   0             0 
+
+0x000005fe: 06 DW_LNS_negate_stmt
+0x000005ff: 83 address += 8,  line += 1
+            0x0000000000001009    147     12      1   0             0  is_stmt
+
+0x00000600: 05 DW_LNS_set_column (7)
+0x00000602: 06 DW_LNS_negate_stmt
+0x00000603: 82 address += 8,  line += 0
+            0x0000000000001011    147      7      1   0             0 
+
+0x00000604: 05 DW_LNS_set_column (4)
+0x00000606: 06 DW_LNS_negate_stmt
+0x00000607: 03 DW_LNS_advance_line (141)
+0x00000609: 90 address += 9,  line += 0
+            0x000000000000101a    141      4      1   0             0  is_stmt
+
+0x0000060a: 05 DW_LNS_set_column (11)
+0x0000060c: 52 address += 4,  line += 8
+            0x000000000000101e    149     11      1   0             0  is_stmt
+
+0x0000060d: 05 DW_LNS_set_column (4)
+0x0000060f: 06 DW_LNS_negate_stmt
+0x00000610: 82 address += 8,  line += 0
+            0x0000000000001026    149      4      1   0             0 
+
+0x00000611: 02 DW_LNS_advance_pc (28)
+0x00000613: 00 DW_LNE_end_sequence
+            0x0000000000001042    149      4      1   0             0  end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 11.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 2d7a8cf90478cd845ffb39763b0e95b7715322d2)"
+0x00000095: "tests/fannkuch.cpp"
+0x000000a8: "/home/alon/Dev/emscripten"
+0x000000c2: "i"
+0x000000c4: "int"
+0x000000c8: "n"
+0x000000ca: "next"
+0x000000cf: "worker_args"
+0x000000db: "std"
+0x000000df: "decltype(nullptr)"
+0x000000f1: "nullptr_t"
+0x000000fb: "_Z15fannkuch_workerPv"
+0x00000111: "fannkuch_worker"
+0x00000121: "main"
+0x00000126: "_ZL8fannkuchi"
+0x00000134: "fannkuch"
+0x0000013d: "_arg"
+0x00000142: "args"
+0x00000147: "perm1"
+0x0000014d: "count"
+0x00000153: "perm"
+0x00000158: "maxflips"
+0x00000161: "flips"
+0x00000167: "r"
+0x00000169: "j"
+0x0000016b: "k"
+0x0000016d: "tmp"
+0x00000171: "p0"
+0x00000174: "argc"
+0x00000179: "argv"
+0x0000017e: "char"
+0x00000183: "targs"
+0x00000189: "showmax"
+0x00000191: "cleanup"
+
+.debug_ranges contents:
+00000000 00000006 0000088c
+00000000 0000088e 000009dc
+00000000 000009de 00001042
+00000000 <End of list>
+DWARF debug info
+================
+
+Contains section .debug_info (640 bytes)
+Contains section .debug_ranges (32 bytes)
+Contains section .debug_abbrev (222 bytes)
+Contains section .debug_line (3965 bytes)
+Contains section .debug_str (409 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[2] DW_TAG_pointer_type	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[3] DW_TAG_structure_type	DW_CHILDREN_yes
+	DW_AT_calling_convention	DW_FORM_data1
+	DW_AT_name	DW_FORM_strp
+	DW_AT_byte_size	DW_FORM_data1
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[4] DW_TAG_member	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_data_member_location	DW_FORM_data1
+
+[5] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+[6] DW_TAG_namespace	DW_CHILDREN_yes
+	DW_AT_name	DW_FORM_strp
+
+[7] DW_TAG_typedef	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[8] DW_TAG_unspecified_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+
+[9] DW_TAG_imported_declaration	DW_CHILDREN_no
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_import	DW_FORM_ref4
+
+[10] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[11] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_exprloc
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[12] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_exprloc
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[13] DW_TAG_lexical_block	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+[14] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[15] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[16] DW_TAG_label	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_low_pc	DW_FORM_addr
+
+[17] DW_TAG_pointer_type	DW_CHILDREN_no
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x0000027c version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x00000280)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 11.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 2d7a8cf90478cd845ffb39763b0e95b7715322d2)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000095] = "tests/fannkuch.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x000000a8] = "/home/alon/Dev/emscripten")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+              DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
+                 [0x00000006, 0x00000a53)
+                 [0x00000a55, 0x00000bc5)
+                 [0x00000bc7, 0x00001360))
+
+0x00000026:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x002b => {0x0000002b} "worker_args")
+
+0x0000002b:   DW_TAG_structure_type [3] *
+                DW_AT_calling_convention [DW_FORM_data1]	(DW_CC_pass_by_value)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000cf] = "worker_args")
+                DW_AT_byte_size [DW_FORM_data1]	(0x0c)
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(20)
+
+0x00000034:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c2] = "i")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(21)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x00)
+
+0x00000040:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c8] = "n")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(21)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x04)
+
+0x0000004c:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ca] = "next")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(22)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x08)
+
+0x00000058:     NULL
+
+0x00000059:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c4] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x00000060:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000065:   DW_TAG_namespace [6] *
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000db] = "std")
+
+0x0000006a:     DW_TAG_typedef [7]  
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0076 => {0x00000076} "decltype(nullptr)")
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000f1] = "nullptr_t")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/system/include/libcxx/__nullptr")
+                  DW_AT_decl_line [DW_FORM_data1]	(57)
+
+0x00000075:     NULL
+
+0x00000076:   DW_TAG_unspecified_type [8]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000df] = "decltype(nullptr)")
+
+0x0000007b:   DW_TAG_imported_declaration [9]  
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/system/include/libcxx/stddef.h")
+                DW_AT_decl_line [DW_FORM_data1]	(52)
+                DW_AT_import [DW_FORM_ref4]	(cu + 0x006a => {0x0000006a})
+
+0x00000082:   DW_TAG_subprogram [10] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000006)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000a4d)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x000000fb] = "_Z15fannkuch_workerPv")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000111] = "fannkuch_worker")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(26)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000099:     DW_TAG_formal_parameter [11]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x3c)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000013d] = "_arg")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(26)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x026d => {0x0000026d} "*")
+
+0x000000a7:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x38)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000142] = "args")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(28)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000000b5:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x34)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000147] = "perm1")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000000c3:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x30)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014d] = "count")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000000d1:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x2c)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000153] = "perm")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000000df:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x28)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000158] = "maxflips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000ed:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x24)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000161] = "flips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000fb:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x20)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c2] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000109:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x1c)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c8] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000117:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x18)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000167] = "r")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000125:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x14)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000169] = "j")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000133:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x10)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000016b] = "k")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000141:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0xc)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000016d] = "tmp")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000014f:     DW_TAG_lexical_block [13] *
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000087a)
+                  DW_AT_high_pc [DW_FORM_data4]	(0x00000136)
+
+0x00000158:       DW_TAG_variable [12]  
+                    DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x8)
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000171] = "p0")
+                    DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                    DW_AT_decl_line [DW_FORM_data1]	(74)
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000166:       NULL
+
+0x00000167:     NULL
+
+0x00000168:   DW_TAG_subprogram [14] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000a55)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000170)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000121] = "main")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(152)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000017b:     DW_TAG_formal_parameter [11]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x18)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000174] = "argc")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(152)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000189:     DW_TAG_formal_parameter [11]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x14)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000179] = "argv")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(152)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x026e => {0x0000026e} "char**")
+
+0x00000197:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x10)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c8] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(153)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001a5:     NULL
+
+0x000001a6:   DW_TAG_subprogram [15] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000bc7)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000799)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x00000126] = "_ZL8fannkuchi")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000134] = "fannkuch")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(87)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001bd:     DW_TAG_formal_parameter [11]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x2c)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c8] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(87)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001cb:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x28)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000142] = "args")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(89)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000001d9:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x24)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000183] = "targs")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(89)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000001e7:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x20)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000189] = "showmax")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(90)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001f5:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x1c)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000147] = "perm1")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x00000203:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x18)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014d] = "count")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x00000211:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x14)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c2] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000021f:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x10)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000167] = "r")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000022d:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0xc)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000158] = "maxflips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000023b:     DW_TAG_variable [12]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x8)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000161] = "flips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000249:     DW_TAG_label [16]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000191] = "cleanup")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(137)
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000001241)
+
+0x00000254:     DW_TAG_lexical_block [13] *
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000001091)
+                  DW_AT_high_pc [DW_FORM_data4]	(0x00000107)
+
+0x0000025d:       DW_TAG_variable [12]  
+                    DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0x4)
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000171] = "p0")
+                    DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/tests/fannkuch.cpp")
+                    DW_AT_decl_line [DW_FORM_data1]	(125)
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000026b:       NULL
+
+0x0000026c:     NULL
+
+0x0000026d:   DW_TAG_pointer_type [17]  
+
+0x0000026e:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0273 => {0x00000273} "char*")
+
+0x00000273:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0278 => {0x00000278} "char")
+
+0x00000278:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000017e] = "char")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed_char)
+                DW_AT_byte_size [DW_FORM_data1]	(0x01)
+
+0x0000027f:   NULL
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x00000f79
+         version: 4
+ prologue_length: 0x00000059
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+include_directories[  1] = "tests"
+include_directories[  2] = "system/include/libcxx"
+file_names[  1]:
+           name: "fannkuch.cpp"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  2]:
+           name: "__nullptr"
+      dir_index: 2
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  3]:
+           name: "stddef.h"
+      dir_index: 2
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000063: 00 DW_LNE_set_address (0x0000000000000006)
+0x0000006a: 03 DW_LNS_advance_line (27)
+0x0000006c: 01 DW_LNS_copy
+            0x0000000000000006     27      0      1   0             0  is_stmt
+
+
+0x0000006d: 00 DW_LNE_set_address (0x000000000000020f)
+0x00000074: 03 DW_LNS_advance_line (28)
+0x00000076: 05 DW_LNS_set_column (45)
+0x00000078: 0a DW_LNS_set_prologue_end
+0x00000079: 01 DW_LNS_copy
+            0x000000000000020f     28     45      1   0             0  is_stmt prologue_end
+
+
+0x0000007a: 00 DW_LNE_set_address (0x0000000000000216)
+0x00000081: 05 DW_LNS_set_column (24)
+0x00000083: 06 DW_LNS_negate_stmt
+0x00000084: 01 DW_LNS_copy
+            0x0000000000000216     28     24      1   0             0 
+
+
+0x00000085: 00 DW_LNE_set_address (0x000000000000021d)
+0x0000008c: 03 DW_LNS_advance_line (32)
+0x0000008e: 05 DW_LNS_set_column (13)
+0x00000090: 06 DW_LNS_negate_stmt
+0x00000091: 01 DW_LNS_copy
+            0x000000000000021d     32     13      1   0             0  is_stmt
+
+
+0x00000092: 00 DW_LNE_set_address (0x0000000000000224)
+0x00000099: 03 DW_LNS_advance_line (33)
+0x0000009b: 05 DW_LNS_set_column (8)
+0x0000009d: 01 DW_LNS_copy
+            0x0000000000000224     33      8      1   0             0  is_stmt
+
+
+0x0000009e: 00 DW_LNE_set_address (0x000000000000022b)
+0x000000a5: 05 DW_LNS_set_column (14)
+0x000000a7: 06 DW_LNS_negate_stmt
+0x000000a8: 01 DW_LNS_copy
+            0x000000000000022b     33     14      1   0             0 
+
+
+0x000000a9: 00 DW_LNE_set_address (0x0000000000000232)
+0x000000b0: 05 DW_LNS_set_column (6)
+0x000000b2: 01 DW_LNS_copy
+            0x0000000000000232     33      6      1   0             0 
+
+
+0x000000b3: 00 DW_LNE_set_address (0x0000000000000239)
+0x000000ba: 03 DW_LNS_advance_line (34)
+0x000000bc: 05 DW_LNS_set_column (25)
+0x000000be: 06 DW_LNS_negate_stmt
+0x000000bf: 01 DW_LNS_copy
+            0x0000000000000239     34     25      1   0             0  is_stmt
+
+
+0x000000c0: 00 DW_LNE_set_address (0x0000000000000240)
+0x000000c7: 05 DW_LNS_set_column (27)
+0x000000c9: 06 DW_LNS_negate_stmt
+0x000000ca: 01 DW_LNS_copy
+            0x0000000000000240     34     27      1   0             0 
+
+
+0x000000cb: 00 DW_LNE_set_address (0x000000000000024b)
+0x000000d2: 05 DW_LNS_set_column (18)
+0x000000d4: 01 DW_LNS_copy
+            0x000000000000024b     34     18      1   0             0 
+
+
+0x000000d5: 00 DW_LNE_set_address (0x0000000000000251)
+0x000000dc: 05 DW_LNS_set_column (10)
+0x000000de: 01 DW_LNS_copy
+            0x0000000000000251     34     10      1   0             0 
+
+
+0x000000df: 00 DW_LNE_set_address (0x0000000000000258)
+0x000000e6: 03 DW_LNS_advance_line (35)
+0x000000e8: 05 DW_LNS_set_column (24)
+0x000000ea: 06 DW_LNS_negate_stmt
+0x000000eb: 01 DW_LNS_copy
+            0x0000000000000258     35     24      1   0             0  is_stmt
+
+
+0x000000ec: 00 DW_LNE_set_address (0x000000000000025f)
+0x000000f3: 05 DW_LNS_set_column (26)
+0x000000f5: 06 DW_LNS_negate_stmt
+0x000000f6: 01 DW_LNS_copy
+            0x000000000000025f     35     26      1   0             0 
+
+
+0x000000f7: 00 DW_LNE_set_address (0x000000000000026a)
+0x000000fe: 05 DW_LNS_set_column (17)
+0x00000100: 01 DW_LNS_copy
+            0x000000000000026a     35     17      1   0             0 
+
+
+0x00000101: 00 DW_LNE_set_address (0x0000000000000270)
+0x00000108: 05 DW_LNS_set_column (9)
+0x0000010a: 01 DW_LNS_copy
+            0x0000000000000270     35      9      1   0             0 
+
+
+0x0000010b: 00 DW_LNE_set_address (0x0000000000000277)
+0x00000112: 03 DW_LNS_advance_line (36)
+0x00000114: 05 DW_LNS_set_column (25)
+0x00000116: 06 DW_LNS_negate_stmt
+0x00000117: 01 DW_LNS_copy
+            0x0000000000000277     36     25      1   0             0  is_stmt
+
+
+0x00000118: 00 DW_LNE_set_address (0x000000000000027e)
+0x0000011f: 05 DW_LNS_set_column (27)
+0x00000121: 06 DW_LNS_negate_stmt
+0x00000122: 01 DW_LNS_copy
+            0x000000000000027e     36     27      1   0             0 
+
+
+0x00000123: 00 DW_LNE_set_address (0x0000000000000289)
+0x0000012a: 05 DW_LNS_set_column (18)
+0x0000012c: 01 DW_LNS_copy
+            0x0000000000000289     36     18      1   0             0 
+
+
+0x0000012d: 00 DW_LNE_set_address (0x000000000000028f)
+0x00000134: 05 DW_LNS_set_column (10)
+0x00000136: 01 DW_LNS_copy
+            0x000000000000028f     36     10      1   0             0 
+
+
+0x00000137: 00 DW_LNE_set_address (0x0000000000000296)
+0x0000013e: 03 DW_LNS_advance_line (37)
+0x00000140: 05 DW_LNS_set_column (11)
+0x00000142: 06 DW_LNS_negate_stmt
+0x00000143: 01 DW_LNS_copy
+            0x0000000000000296     37     11      1   0             0  is_stmt
+
+
+0x00000144: 00 DW_LNE_set_address (0x000000000000029d)
+0x0000014b: 05 DW_LNS_set_column (16)
+0x0000014d: 06 DW_LNS_negate_stmt
+0x0000014e: 01 DW_LNS_copy
+            0x000000000000029d     37     16      1   0             0 
+
+
+0x0000014f: 00 DW_LNE_set_address (0x00000000000002a8)
+0x00000156: 05 DW_LNS_set_column (20)
+0x00000158: 01 DW_LNS_copy
+            0x00000000000002a8     37     20      1   0             0 
+
+
+0x00000159: 00 DW_LNE_set_address (0x00000000000002af)
+0x00000160: 05 DW_LNS_set_column (18)
+0x00000162: 01 DW_LNS_copy
+            0x00000000000002af     37     18      1   0             0 
+
+
+0x00000163: 00 DW_LNE_set_address (0x00000000000002be)
+0x0000016a: 05 DW_LNS_set_column (4)
+0x0000016c: 01 DW_LNS_copy
+            0x00000000000002be     37      4      1   0             0 
+
+
+0x0000016d: 00 DW_LNE_set_address (0x00000000000002ce)
+0x00000174: 03 DW_LNS_advance_line (38)
+0x00000176: 05 DW_LNS_set_column (18)
+0x00000178: 06 DW_LNS_negate_stmt
+0x00000179: 01 DW_LNS_copy
+            0x00000000000002ce     38     18      1   0             0  is_stmt
+
+
+0x0000017a: 00 DW_LNE_set_address (0x00000000000002d5)
+0x00000181: 05 DW_LNS_set_column (7)
+0x00000183: 06 DW_LNS_negate_stmt
+0x00000184: 01 DW_LNS_copy
+            0x00000000000002d5     38      7      1   0             0 
+
+
+0x00000185: 00 DW_LNE_set_address (0x00000000000002dc)
+0x0000018c: 05 DW_LNS_set_column (13)
+0x0000018e: 01 DW_LNS_copy
+            0x00000000000002dc     38     13      1   0             0 
+
+
+0x0000018f: 00 DW_LNE_set_address (0x00000000000002e3)
+0x00000196: 05 DW_LNS_set_column (7)
+0x00000198: 01 DW_LNS_copy
+            0x00000000000002e3     38      7      1   0             0 
+
+
+0x00000199: 00 DW_LNE_set_address (0x00000000000002f5)
+0x000001a0: 05 DW_LNS_set_column (16)
+0x000001a2: 01 DW_LNS_copy
+            0x00000000000002f5     38     16      1   0             0 
+
+
+0x000001a3: 00 DW_LNE_set_address (0x00000000000002fc)
+0x000001aa: 03 DW_LNS_advance_line (37)
+0x000001ac: 05 DW_LNS_set_column (24)
+0x000001ae: 06 DW_LNS_negate_stmt
+0x000001af: 01 DW_LNS_copy
+            0x00000000000002fc     37     24      1   0             0  is_stmt
+
+
+0x000001b0: 00 DW_LNE_set_address (0x0000000000000315)
+0x000001b7: 05 DW_LNS_set_column (4)
+0x000001b9: 06 DW_LNS_negate_stmt
+0x000001ba: 01 DW_LNS_copy
+            0x0000000000000315     37      4      1   0             0 
+
+
+0x000001bb: 00 DW_LNE_set_address (0x0000000000000317)
+0x000001c2: 01 DW_LNS_copy
+            0x0000000000000317     37      4      1   0             0 
+
+
+0x000001c3: 00 DW_LNE_set_address (0x000000000000031a)
+0x000001ca: 03 DW_LNS_advance_line (39)
+0x000001cc: 05 DW_LNS_set_column (21)
+0x000001ce: 06 DW_LNS_negate_stmt
+0x000001cf: 01 DW_LNS_copy
+            0x000000000000031a     39     21      1   0             0  is_stmt
+
+
+0x000001d0: 00 DW_LNE_set_address (0x0000000000000321)
+0x000001d7: 05 DW_LNS_set_column (23)
+0x000001d9: 06 DW_LNS_negate_stmt
+0x000001da: 01 DW_LNS_copy
+            0x0000000000000321     39     23      1   0             0 
+
+
+0x000001db: 00 DW_LNE_set_address (0x000000000000032c)
+0x000001e2: 05 DW_LNS_set_column (4)
+0x000001e4: 01 DW_LNS_copy
+            0x000000000000032c     39      4      1   0             0 
+
+
+0x000001e5: 00 DW_LNE_set_address (0x0000000000000333)
+0x000001ec: 05 DW_LNS_set_column (10)
+0x000001ee: 01 DW_LNS_copy
+            0x0000000000000333     39     10      1   0             0 
+
+
+0x000001ef: 00 DW_LNE_set_address (0x000000000000033a)
+0x000001f6: 05 DW_LNS_set_column (16)
+0x000001f8: 01 DW_LNS_copy
+            0x000000000000033a     39     16      1   0             0 
+
+
+0x000001f9: 00 DW_LNE_set_address (0x0000000000000341)
+0x00000200: 05 DW_LNS_set_column (4)
+0x00000202: 01 DW_LNS_copy
+            0x0000000000000341     39      4      1   0             0 
+
+
+0x00000203: 00 DW_LNE_set_address (0x0000000000000353)
+0x0000020a: 05 DW_LNS_set_column (19)
+0x0000020c: 01 DW_LNS_copy
+            0x0000000000000353     39     19      1   0             0 
+
+
+0x0000020d: 00 DW_LNE_set_address (0x000000000000035a)
+0x00000214: 03 DW_LNS_advance_line (40)
+0x00000216: 06 DW_LNS_negate_stmt
+0x00000217: 01 DW_LNS_copy
+            0x000000000000035a     40     19      1   0             0  is_stmt
+
+
+0x00000218: 00 DW_LNE_set_address (0x0000000000000361)
+0x0000021f: 05 DW_LNS_set_column (25)
+0x00000221: 06 DW_LNS_negate_stmt
+0x00000222: 01 DW_LNS_copy
+            0x0000000000000361     40     25      1   0             0 
+
+
+0x00000223: 00 DW_LNE_set_address (0x0000000000000368)
+0x0000022a: 05 DW_LNS_set_column (4)
+0x0000022c: 01 DW_LNS_copy
+            0x0000000000000368     40      4      1   0             0 
+
+
+0x0000022d: 00 DW_LNE_set_address (0x000000000000036f)
+0x00000234: 05 DW_LNS_set_column (10)
+0x00000236: 01 DW_LNS_copy
+            0x000000000000036f     40     10      1   0             0 
+
+
+0x00000237: 00 DW_LNE_set_address (0x0000000000000376)
+0x0000023e: 05 DW_LNS_set_column (12)
+0x00000240: 01 DW_LNS_copy
+            0x0000000000000376     40     12      1   0             0 
+
+
+0x00000241: 00 DW_LNE_set_address (0x0000000000000381)
+0x00000248: 05 DW_LNS_set_column (4)
+0x0000024a: 01 DW_LNS_copy
+            0x0000000000000381     40      4      1   0             0 
+
+
+0x0000024b: 00 DW_LNE_set_address (0x0000000000000393)
+0x00000252: 05 DW_LNS_set_column (17)
+0x00000254: 01 DW_LNS_copy
+            0x0000000000000393     40     17      1   0             0 
+
+
+0x00000255: 00 DW_LNE_set_address (0x000000000000039a)
+0x0000025c: 03 DW_LNS_advance_line (41)
+0x0000025e: 05 DW_LNS_set_column (8)
+0x00000260: 06 DW_LNS_negate_stmt
+0x00000261: 01 DW_LNS_copy
+            0x000000000000039a     41      8      1   0             0  is_stmt
+
+
+0x00000262: 00 DW_LNE_set_address (0x00000000000003a1)
+0x00000269: 05 DW_LNS_set_column (6)
+0x0000026b: 06 DW_LNS_negate_stmt
+0x0000026c: 01 DW_LNS_copy
+            0x00000000000003a1     41      6      1   0             0 
+
+
+0x0000026d: 00 DW_LNE_set_address (0x00000000000003b2)
+0x00000274: 03 DW_LNS_advance_line (44)
+0x00000276: 05 DW_LNS_set_column (14)
+0x00000278: 06 DW_LNS_negate_stmt
+0x00000279: 01 DW_LNS_copy
+            0x00000000000003b2     44     14      1   0             0  is_stmt
+
+
+0x0000027a: 00 DW_LNE_set_address (0x00000000000003b9)
+0x00000281: 05 DW_LNS_set_column (16)
+0x00000283: 06 DW_LNS_negate_stmt
+0x00000284: 01 DW_LNS_copy
+            0x00000000000003b9     44     16      1   0             0 
+
+
+0x00000285: 00 DW_LNE_set_address (0x00000000000003c8)
+0x0000028c: 05 DW_LNS_set_column (7)
+0x0000028e: 01 DW_LNS_copy
+            0x00000000000003c8     44      7      1   0             0 
+
+
+0x0000028f: 00 DW_LNE_set_address (0x00000000000003d8)
+0x00000296: 03 DW_LNS_advance_line (45)
+0x00000298: 05 DW_LNS_set_column (25)
+0x0000029a: 06 DW_LNS_negate_stmt
+0x0000029b: 01 DW_LNS_copy
+            0x00000000000003d8     45     25      1   0             0  is_stmt
+
+
+0x0000029c: 00 DW_LNE_set_address (0x00000000000003df)
+0x000002a3: 05 DW_LNS_set_column (10)
+0x000002a5: 06 DW_LNS_negate_stmt
+0x000002a6: 01 DW_LNS_copy
+            0x00000000000003df     45     10      1   0             0 
+
+
+0x000002a7: 00 DW_LNE_set_address (0x00000000000003e6)
+0x000002ae: 05 DW_LNS_set_column (16)
+0x000002b0: 01 DW_LNS_copy
+            0x00000000000003e6     45     16      1   0             0 
+
+
+0x000002b1: 00 DW_LNE_set_address (0x00000000000003ed)
+0x000002b8: 05 DW_LNS_set_column (18)
+0x000002ba: 01 DW_LNS_copy
+            0x00000000000003ed     45     18      1   0             0 
+
+
+0x000002bb: 00 DW_LNE_set_address (0x00000000000003f8)
+0x000002c2: 05 DW_LNS_set_column (10)
+0x000002c4: 01 DW_LNS_copy
+            0x00000000000003f8     45     10      1   0             0 
+
+
+0x000002c5: 00 DW_LNE_set_address (0x000000000000040a)
+0x000002cc: 05 DW_LNS_set_column (23)
+0x000002ce: 01 DW_LNS_copy
+            0x000000000000040a     45     23      1   0             0 
+
+
+0x000002cf: 00 DW_LNE_set_address (0x0000000000000411)
+0x000002d6: 03 DW_LNS_advance_line (44)
+0x000002d8: 05 DW_LNS_set_column (22)
+0x000002da: 06 DW_LNS_negate_stmt
+0x000002db: 01 DW_LNS_copy
+            0x0000000000000411     44     22      1   0             0  is_stmt
+
+
+0x000002dc: 00 DW_LNE_set_address (0x000000000000042a)
+0x000002e3: 05 DW_LNS_set_column (7)
+0x000002e5: 06 DW_LNS_negate_stmt
+0x000002e6: 01 DW_LNS_copy
+            0x000000000000042a     44      7      1   0             0 
+
+
+0x000002e7: 00 DW_LNE_set_address (0x000000000000042c)
+0x000002ee: 01 DW_LNS_copy
+            0x000000000000042c     44      7      1   0             0 
+
+
+0x000002ef: 00 DW_LNE_set_address (0x000000000000042f)
+0x000002f6: 03 DW_LNS_advance_line (46)
+0x000002f8: 05 DW_LNS_set_column (11)
+0x000002fa: 06 DW_LNS_negate_stmt
+0x000002fb: 01 DW_LNS_copy
+            0x000000000000042f     46     11      1   0             0  is_stmt
+
+
+0x000002fc: 00 DW_LNE_set_address (0x000000000000043d)
+0x00000303: 05 DW_LNS_set_column (25)
+0x00000305: 06 DW_LNS_negate_stmt
+0x00000306: 01 DW_LNS_copy
+            0x000000000000043d     46     25      1   0             0 
+
+
+0x00000307: 00 DW_LNE_set_address (0x0000000000000444)
+0x0000030e: 05 DW_LNS_set_column (28)
+0x00000310: 01 DW_LNS_copy
+            0x0000000000000444     46     28      1   0             0 
+
+
+0x00000311: 00 DW_LNE_set_address (0x000000000000044b)
+0x00000318: 05 DW_LNS_set_column (34)
+0x0000031a: 01 DW_LNS_copy
+            0x000000000000044b     46     34      1   0             0 
+
+
+0x0000031b: 00 DW_LNE_set_address (0x0000000000000452)
+0x00000322: 05 DW_LNS_set_column (36)
+0x00000324: 01 DW_LNS_copy
+            0x0000000000000452     46     36      1   0             0 
+
+
+0x00000325: 00 DW_LNE_set_address (0x000000000000045d)
+0x0000032c: 05 DW_LNS_set_column (28)
+0x0000032e: 01 DW_LNS_copy
+            0x000000000000045d     46     28      1   0             0 
+
+
+0x0000032f: 00 DW_LNE_set_address (0x0000000000000476)
+0x00000336: 05 DW_LNS_set_column (44)
+0x00000338: 01 DW_LNS_copy
+            0x0000000000000476     46     44      1   0             0 
+
+
+0x00000339: 00 DW_LNE_set_address (0x000000000000047d)
+0x00000340: 05 DW_LNS_set_column (46)
+0x00000342: 01 DW_LNS_copy
+            0x000000000000047d     46     46      1   0             0 
+
+
+0x00000343: 00 DW_LNE_set_address (0x0000000000000488)
+0x0000034a: 05 DW_LNS_set_column (41)
+0x0000034c: 01 DW_LNS_copy
+            0x0000000000000488     46     41      1   0             0 
+
+
+0x0000034d: 00 DW_LNE_set_address (0x0000000000000497)
+0x00000354: 05 DW_LNS_set_column (11)
+0x00000356: 01 DW_LNS_copy
+            0x0000000000000497     46     11      1   0             0 
+
+
+0x00000357: 00 DW_LNE_set_address (0x00000000000004ab)
+0x0000035e: 03 DW_LNS_advance_line (47)
+0x00000360: 05 DW_LNS_set_column (17)
+0x00000362: 06 DW_LNS_negate_stmt
+0x00000363: 01 DW_LNS_copy
+            0x00000000000004ab     47     17      1   0             0  is_stmt
+
+
+0x00000364: 00 DW_LNE_set_address (0x00000000000004b2)
+0x0000036b: 05 DW_LNS_set_column (22)
+0x0000036d: 06 DW_LNS_negate_stmt
+0x0000036e: 01 DW_LNS_copy
+            0x00000000000004b2     47     22      1   0             0 
+
+
+0x0000036f: 00 DW_LNE_set_address (0x00000000000004bd)
+0x00000376: 05 DW_LNS_set_column (26)
+0x00000378: 01 DW_LNS_copy
+            0x00000000000004bd     47     26      1   0             0 
+
+
+0x00000379: 00 DW_LNE_set_address (0x00000000000004c4)
+0x00000380: 05 DW_LNS_set_column (24)
+0x00000382: 01 DW_LNS_copy
+            0x00000000000004c4     47     24      1   0             0 
+
+
+0x00000383: 00 DW_LNE_set_address (0x00000000000004d3)
+0x0000038a: 05 DW_LNS_set_column (10)
+0x0000038c: 01 DW_LNS_copy
+            0x00000000000004d3     47     10      1   0             0 
+
+
+0x0000038d: 00 DW_LNE_set_address (0x00000000000004e3)
+0x00000394: 03 DW_LNS_advance_line (48)
+0x00000396: 05 DW_LNS_set_column (23)
+0x00000398: 06 DW_LNS_negate_stmt
+0x00000399: 01 DW_LNS_copy
+            0x00000000000004e3     48     23      1   0             0  is_stmt
+
+
+0x0000039a: 00 DW_LNE_set_address (0x00000000000004ea)
+0x000003a1: 05 DW_LNS_set_column (29)
+0x000003a3: 06 DW_LNS_negate_stmt
+0x000003a4: 01 DW_LNS_copy
+            0x00000000000004ea     48     29      1   0             0 
+
+
+0x000003a5: 00 DW_LNE_set_address (0x00000000000004f1)
+0x000003ac: 05 DW_LNS_set_column (23)
+0x000003ae: 01 DW_LNS_copy
+            0x00000000000004f1     48     23      1   0             0 
+
+
+0x000003af: 00 DW_LNE_set_address (0x000000000000050a)
+0x000003b6: 05 DW_LNS_set_column (13)
+0x000003b8: 01 DW_LNS_copy
+            0x000000000000050a     48     13      1   0             0 
+
+
+0x000003b9: 00 DW_LNE_set_address (0x0000000000000511)
+0x000003c0: 05 DW_LNS_set_column (18)
+0x000003c2: 01 DW_LNS_copy
+            0x0000000000000511     48     18      1   0             0 
+
+
+0x000003c3: 00 DW_LNE_set_address (0x0000000000000518)
+0x000003ca: 05 DW_LNS_set_column (13)
+0x000003cc: 01 DW_LNS_copy
+            0x0000000000000518     48     13      1   0             0 
+
+
+0x000003cd: 00 DW_LNE_set_address (0x000000000000052a)
+0x000003d4: 05 DW_LNS_set_column (21)
+0x000003d6: 01 DW_LNS_copy
+            0x000000000000052a     48     21      1   0             0 
+
+
+0x000003d7: 00 DW_LNE_set_address (0x0000000000000531)
+0x000003de: 03 DW_LNS_advance_line (47)
+0x000003e0: 05 DW_LNS_set_column (30)
+0x000003e2: 06 DW_LNS_negate_stmt
+0x000003e3: 01 DW_LNS_copy
+            0x0000000000000531     47     30      1   0             0  is_stmt
+
+
+0x000003e4: 00 DW_LNE_set_address (0x000000000000054a)
+0x000003eb: 05 DW_LNS_set_column (10)
+0x000003ed: 06 DW_LNS_negate_stmt
+0x000003ee: 01 DW_LNS_copy
+            0x000000000000054a     47     10      1   0             0 
+
+
+0x000003ef: 00 DW_LNE_set_address (0x000000000000054c)
+0x000003f6: 01 DW_LNS_copy
+            0x000000000000054c     47     10      1   0             0 
+
+
+0x000003f7: 00 DW_LNE_set_address (0x0000000000000553)
+0x000003fe: 03 DW_LNS_advance_line (49)
+0x00000400: 05 DW_LNS_set_column (16)
+0x00000402: 06 DW_LNS_negate_stmt
+0x00000403: 01 DW_LNS_copy
+            0x0000000000000553     49     16      1   0             0  is_stmt
+
+
+0x00000404: 00 DW_LNE_set_address (0x000000000000055a)
+0x0000040b: 03 DW_LNS_advance_line (50)
+0x0000040d: 05 DW_LNS_set_column (14)
+0x0000040f: 01 DW_LNS_copy
+            0x000000000000055a     50     14      1   0             0  is_stmt
+
+
+0x00000410: 00 DW_LNE_set_address (0x0000000000000568)
+0x00000417: 05 DW_LNS_set_column (12)
+0x00000419: 06 DW_LNS_negate_stmt
+0x0000041a: 01 DW_LNS_copy
+            0x0000000000000568     50     12      1   0             0 
+
+
+0x0000041b: 00 DW_LNE_set_address (0x0000000000000575)
+0x00000422: 03 DW_LNS_advance_line (52)
+0x00000424: 05 DW_LNS_set_column (20)
+0x00000426: 06 DW_LNS_negate_stmt
+0x00000427: 01 DW_LNS_copy
+            0x0000000000000575     52     20      1   0             0  is_stmt
+
+
+0x00000428: 00 DW_LNE_set_address (0x000000000000057c)
+0x0000042f: 05 DW_LNS_set_column (29)
+0x00000431: 06 DW_LNS_negate_stmt
+0x00000432: 01 DW_LNS_copy
+            0x000000000000057c     52     29      1   0             0 
+
+
+0x00000433: 00 DW_LNE_set_address (0x0000000000000583)
+0x0000043a: 05 DW_LNS_set_column (31)
+0x0000043c: 01 DW_LNS_copy
+            0x0000000000000583     52     31      1   0             0 
+
+
+0x0000043d: 00 DW_LNE_set_address (0x000000000000058e)
+0x00000444: 05 DW_LNS_set_column (27)
+0x00000446: 01 DW_LNS_copy
+            0x000000000000058e     52     27      1   0             0 
+
+
+0x00000447: 00 DW_LNE_set_address (0x0000000000000595)
+0x0000044e: 05 DW_LNS_set_column (36)
+0x00000450: 01 DW_LNS_copy
+            0x0000000000000595     52     36      1   0             0 
+
+
+0x00000451: 00 DW_LNE_set_address (0x00000000000005a0)
+0x00000458: 05 DW_LNS_set_column (40)
+0x0000045a: 01 DW_LNS_copy
+            0x00000000000005a0     52     40      1   0             0 
+
+
+0x0000045b: 00 DW_LNE_set_address (0x00000000000005a7)
+0x00000462: 05 DW_LNS_set_column (38)
+0x00000464: 01 DW_LNS_copy
+            0x00000000000005a7     52     38      1   0             0 
+
+
+0x00000465: 00 DW_LNE_set_address (0x00000000000005b6)
+0x0000046c: 05 DW_LNS_set_column (13)
+0x0000046e: 01 DW_LNS_copy
+            0x00000000000005b6     52     13      1   0             0 
+
+
+0x0000046f: 00 DW_LNE_set_address (0x00000000000005c6)
+0x00000476: 03 DW_LNS_advance_line (53)
+0x00000478: 05 DW_LNS_set_column (22)
+0x0000047a: 06 DW_LNS_negate_stmt
+0x0000047b: 01 DW_LNS_copy
+            0x00000000000005c6     53     22      1   0             0  is_stmt
+
+
+0x0000047c: 00 DW_LNE_set_address (0x00000000000005cd)
+0x00000483: 05 DW_LNS_set_column (27)
+0x00000485: 06 DW_LNS_negate_stmt
+0x00000486: 01 DW_LNS_copy
+            0x00000000000005cd     53     27      1   0             0 
+
+
+0x00000487: 00 DW_LNE_set_address (0x00000000000005d5)
+0x0000048e: 05 DW_LNS_set_column (22)
+0x00000490: 01 DW_LNS_copy
+            0x00000000000005d5     53     22      1   0             0 
+
+
+0x00000491: 00 DW_LNE_set_address (0x00000000000005f6)
+0x00000498: 05 DW_LNS_set_column (20)
+0x0000049a: 01 DW_LNS_copy
+            0x00000000000005f6     53     20      1   0             0 
+
+
+0x0000049b: 00 DW_LNE_set_address (0x00000000000005fe)
+0x000004a2: 03 DW_LNS_advance_line (54)
+0x000004a4: 05 DW_LNS_set_column (26)
+0x000004a6: 06 DW_LNS_negate_stmt
+0x000004a7: 01 DW_LNS_copy
+            0x00000000000005fe     54     26      1   0             0  is_stmt
+
+
+0x000004a8: 00 DW_LNE_set_address (0x0000000000000606)
+0x000004af: 05 DW_LNS_set_column (31)
+0x000004b1: 06 DW_LNS_negate_stmt
+0x000004b2: 01 DW_LNS_copy
+            0x0000000000000606     54     31      1   0             0 
+
+
+0x000004b3: 00 DW_LNE_set_address (0x000000000000060e)
+0x000004ba: 05 DW_LNS_set_column (26)
+0x000004bc: 01 DW_LNS_copy
+            0x000000000000060e     54     26      1   0             0 
+
+
+0x000004bd: 00 DW_LNE_set_address (0x0000000000000630)
+0x000004c4: 05 DW_LNS_set_column (16)
+0x000004c6: 01 DW_LNS_copy
+            0x0000000000000630     54     16      1   0             0 
+
+
+0x000004c7: 00 DW_LNE_set_address (0x0000000000000638)
+0x000004ce: 05 DW_LNS_set_column (21)
+0x000004d0: 01 DW_LNS_copy
+            0x0000000000000638     54     21      1   0             0 
+
+
+0x000004d1: 00 DW_LNE_set_address (0x0000000000000640)
+0x000004d8: 05 DW_LNS_set_column (16)
+0x000004da: 01 DW_LNS_copy
+            0x0000000000000640     54     16      1   0             0 
+
+
+0x000004db: 00 DW_LNE_set_address (0x0000000000000659)
+0x000004e2: 05 DW_LNS_set_column (24)
+0x000004e4: 01 DW_LNS_copy
+            0x0000000000000659     54     24      1   0             0 
+
+
+0x000004e5: 00 DW_LNE_set_address (0x0000000000000662)
+0x000004ec: 03 DW_LNS_advance_line (55)
+0x000004ee: 05 DW_LNS_set_column (26)
+0x000004f0: 06 DW_LNS_negate_stmt
+0x000004f1: 01 DW_LNS_copy
+            0x0000000000000662     55     26      1   0             0  is_stmt
+
+
+0x000004f2: 00 DW_LNE_set_address (0x000000000000066a)
+0x000004f9: 05 DW_LNS_set_column (16)
+0x000004fb: 06 DW_LNS_negate_stmt
+0x000004fc: 01 DW_LNS_copy
+            0x000000000000066a     55     16      1   0             0 
+
+
+0x000004fd: 00 DW_LNE_set_address (0x0000000000000672)
+0x00000504: 05 DW_LNS_set_column (21)
+0x00000506: 01 DW_LNS_copy
+            0x0000000000000672     55     21      1   0             0 
+
+
+0x00000507: 00 DW_LNE_set_address (0x000000000000067a)
+0x0000050e: 05 DW_LNS_set_column (16)
+0x00000510: 01 DW_LNS_copy
+            0x000000000000067a     55     16      1   0             0 
+
+
+0x00000511: 00 DW_LNE_set_address (0x0000000000000693)
+0x00000518: 05 DW_LNS_set_column (24)
+0x0000051a: 01 DW_LNS_copy
+            0x0000000000000693     55     24      1   0             0 
+
+
+0x0000051b: 00 DW_LNE_set_address (0x000000000000069c)
+0x00000522: 03 DW_LNS_advance_line (52)
+0x00000524: 05 DW_LNS_set_column (44)
+0x00000526: 06 DW_LNS_negate_stmt
+0x00000527: 01 DW_LNS_copy
+            0x000000000000069c     52     44      1   0             0  is_stmt
+
+
+0x00000528: 00 DW_LNE_set_address (0x00000000000006bb)
+0x0000052f: 05 DW_LNS_set_column (49)
+0x00000531: 06 DW_LNS_negate_stmt
+0x00000532: 01 DW_LNS_copy
+            0x00000000000006bb     52     49      1   0             0 
+
+
+0x00000533: 00 DW_LNE_set_address (0x00000000000006da)
+0x0000053a: 05 DW_LNS_set_column (13)
+0x0000053c: 01 DW_LNS_copy
+            0x00000000000006da     52     13      1   0             0 
+
+
+0x0000053d: 00 DW_LNE_set_address (0x00000000000006dc)
+0x00000544: 01 DW_LNS_copy
+            0x00000000000006dc     52     13      1   0             0 
+
+
+0x00000545: 00 DW_LNE_set_address (0x00000000000006df)
+0x0000054c: 03 DW_LNS_advance_line (57)
+0x0000054e: 05 DW_LNS_set_column (18)
+0x00000550: 06 DW_LNS_negate_stmt
+0x00000551: 01 DW_LNS_copy
+            0x00000000000006df     57     18      1   0             0  is_stmt
+
+
+0x00000552: 00 DW_LNE_set_address (0x00000000000006fe)
+0x00000559: 03 DW_LNS_advance_line (58)
+0x0000055b: 05 DW_LNS_set_column (19)
+0x0000055d: 01 DW_LNS_copy
+            0x00000000000006fe     58     19      1   0             0  is_stmt
+
+
+0x0000055e: 00 DW_LNE_set_address (0x0000000000000706)
+0x00000565: 05 DW_LNS_set_column (24)
+0x00000567: 06 DW_LNS_negate_stmt
+0x00000568: 01 DW_LNS_copy
+            0x0000000000000706     58     24      1   0             0 
+
+
+0x00000569: 00 DW_LNE_set_address (0x000000000000070e)
+0x00000570: 05 DW_LNS_set_column (19)
+0x00000572: 01 DW_LNS_copy
+            0x000000000000070e     58     19      1   0             0 
+
+
+0x00000573: 00 DW_LNE_set_address (0x0000000000000730)
+0x0000057a: 05 DW_LNS_set_column (17)
+0x0000057c: 01 DW_LNS_copy
+            0x0000000000000730     58     17      1   0             0 
+
+
+0x0000057d: 00 DW_LNE_set_address (0x0000000000000738)
+0x00000584: 03 DW_LNS_advance_line (59)
+0x00000586: 05 DW_LNS_set_column (23)
+0x00000588: 06 DW_LNS_negate_stmt
+0x00000589: 01 DW_LNS_copy
+            0x0000000000000738     59     23      1   0             0  is_stmt
+
+
+0x0000058a: 00 DW_LNE_set_address (0x0000000000000740)
+0x00000591: 05 DW_LNS_set_column (13)
+0x00000593: 06 DW_LNS_negate_stmt
+0x00000594: 01 DW_LNS_copy
+            0x0000000000000740     59     13      1   0             0 
+
+
+0x00000595: 00 DW_LNE_set_address (0x0000000000000748)
+0x0000059c: 05 DW_LNS_set_column (18)
+0x0000059e: 01 DW_LNS_copy
+            0x0000000000000748     59     18      1   0             0 
+
+
+0x0000059f: 00 DW_LNE_set_address (0x0000000000000750)
+0x000005a6: 05 DW_LNS_set_column (13)
+0x000005a8: 01 DW_LNS_copy
+            0x0000000000000750     59     13      1   0             0 
+
+
+0x000005a9: 00 DW_LNE_set_address (0x0000000000000769)
+0x000005b0: 05 DW_LNS_set_column (21)
+0x000005b2: 01 DW_LNS_copy
+            0x0000000000000769     59     21      1   0             0 
+
+
+0x000005b3: 00 DW_LNE_set_address (0x0000000000000772)
+0x000005ba: 03 DW_LNS_advance_line (60)
+0x000005bc: 05 DW_LNS_set_column (17)
+0x000005be: 06 DW_LNS_negate_stmt
+0x000005bf: 01 DW_LNS_copy
+            0x0000000000000772     60     17      1   0             0  is_stmt
+
+
+0x000005c0: 00 DW_LNE_set_address (0x000000000000077a)
+0x000005c7: 05 DW_LNS_set_column (15)
+0x000005c9: 06 DW_LNS_negate_stmt
+0x000005ca: 01 DW_LNS_copy
+            0x000000000000077a     60     15      1   0             0 
+
+
+0x000005cb: 00 DW_LNE_set_address (0x0000000000000782)
+0x000005d2: 03 DW_LNS_advance_line (61)
+0x000005d4: 05 DW_LNS_set_column (19)
+0x000005d6: 06 DW_LNS_negate_stmt
+0x000005d7: 01 DW_LNS_copy
+            0x0000000000000782     61     19      1   0             0  is_stmt
+
+
+0x000005d8: 00 DW_LNE_set_address (0x000000000000078a)
+0x000005df: 05 DW_LNS_set_column (10)
+0x000005e1: 06 DW_LNS_negate_stmt
+0x000005e2: 01 DW_LNS_copy
+            0x000000000000078a     61     10      1   0             0 
+
+
+0x000005e3: 00 DW_LNE_set_address (0x0000000000000790)
+0x000005ea: 03 DW_LNS_advance_line (62)
+0x000005ec: 05 DW_LNS_set_column (14)
+0x000005ee: 06 DW_LNS_negate_stmt
+0x000005ef: 01 DW_LNS_copy
+            0x0000000000000790     62     14      1   0             0  is_stmt
+
+
+0x000005f0: 00 DW_LNE_set_address (0x0000000000000798)
+0x000005f7: 05 DW_LNS_set_column (25)
+0x000005f9: 06 DW_LNS_negate_stmt
+0x000005fa: 01 DW_LNS_copy
+            0x0000000000000798     62     25      1   0             0 
+
+
+0x000005fb: 00 DW_LNE_set_address (0x00000000000007a0)
+0x00000602: 05 DW_LNS_set_column (23)
+0x00000604: 01 DW_LNS_copy
+            0x00000000000007a0     62     23      1   0             0 
+
+
+0x00000605: 00 DW_LNE_set_address (0x00000000000007b6)
+0x0000060c: 05 DW_LNS_set_column (14)
+0x0000060e: 01 DW_LNS_copy
+            0x00000000000007b6     62     14      1   0             0 
+
+
+0x0000060f: 00 DW_LNE_set_address (0x00000000000007cd)
+0x00000616: 03 DW_LNS_advance_line (63)
+0x00000618: 05 DW_LNS_set_column (24)
+0x0000061a: 06 DW_LNS_negate_stmt
+0x0000061b: 01 DW_LNS_copy
+            0x00000000000007cd     63     24      1   0             0  is_stmt
+
+
+0x0000061c: 00 DW_LNE_set_address (0x00000000000007d5)
+0x00000623: 05 DW_LNS_set_column (22)
+0x00000625: 06 DW_LNS_negate_stmt
+0x00000626: 01 DW_LNS_copy
+            0x00000000000007d5     63     22      1   0             0 
+
+
+0x00000627: 00 DW_LNE_set_address (0x00000000000007df)
+0x0000062e: 03 DW_LNS_advance_line (66)
+0x00000630: 05 DW_LNS_set_column (14)
+0x00000632: 06 DW_LNS_negate_stmt
+0x00000633: 01 DW_LNS_copy
+            0x00000000000007df     66     14      1   0             0  is_stmt
+
+
+0x00000634: 00 DW_LNE_set_address (0x00000000000007e9)
+0x0000063b: 05 DW_LNS_set_column (19)
+0x0000063d: 06 DW_LNS_negate_stmt
+0x0000063e: 01 DW_LNS_copy
+            0x00000000000007e9     66     19      1   0             0 
+
+
+0x0000063f: 00 DW_LNE_set_address (0x00000000000007f1)
+0x00000646: 05 DW_LNS_set_column (21)
+0x00000648: 01 DW_LNS_copy
+            0x00000000000007f1     66     21      1   0             0 
+
+
+0x00000649: 00 DW_LNE_set_address (0x0000000000000800)
+0x00000650: 05 DW_LNS_set_column (16)
+0x00000652: 01 DW_LNS_copy
+            0x0000000000000800     66     16      1   0             0 
+
+
+0x00000653: 00 DW_LNE_set_address (0x0000000000000816)
+0x0000065a: 05 DW_LNS_set_column (14)
+0x0000065c: 01 DW_LNS_copy
+            0x0000000000000816     66     14      1   0             0 
+
+
+0x0000065d: 00 DW_LNE_set_address (0x000000000000082d)
+0x00000664: 03 DW_LNS_advance_line (67)
+0x00000666: 05 DW_LNS_set_column (18)
+0x00000668: 06 DW_LNS_negate_stmt
+0x00000669: 01 DW_LNS_copy
+            0x000000000000082d     67     18      1   0             0  is_stmt
+
+
+0x0000066a: 00 DW_LNE_set_address (0x0000000000000835)
+0x00000671: 05 DW_LNS_set_column (13)
+0x00000673: 06 DW_LNS_negate_stmt
+0x00000674: 01 DW_LNS_copy
+            0x0000000000000835     67     13      1   0             0 
+
+
+0x00000675: 00 DW_LNE_set_address (0x000000000000083a)
+0x0000067c: 03 DW_LNS_advance_line (68)
+0x0000067e: 05 DW_LNS_set_column (18)
+0x00000680: 06 DW_LNS_negate_stmt
+0x00000681: 01 DW_LNS_copy
+            0x000000000000083a     68     18      1   0             0  is_stmt
+
+
+0x00000682: 00 DW_LNE_set_address (0x0000000000000842)
+0x00000689: 05 DW_LNS_set_column (13)
+0x0000068b: 06 DW_LNS_negate_stmt
+0x0000068c: 01 DW_LNS_copy
+            0x0000000000000842     68     13      1   0             0 
+
+
+0x0000068d: 00 DW_LNE_set_address (0x0000000000000847)
+0x00000694: 03 DW_LNS_advance_line (69)
+0x00000696: 05 DW_LNS_set_column (18)
+0x00000698: 06 DW_LNS_negate_stmt
+0x00000699: 01 DW_LNS_copy
+            0x0000000000000847     69     18      1   0             0  is_stmt
+
+
+0x0000069a: 00 DW_LNE_set_address (0x000000000000084f)
+0x000006a1: 05 DW_LNS_set_column (13)
+0x000006a3: 06 DW_LNS_negate_stmt
+0x000006a4: 01 DW_LNS_copy
+            0x000000000000084f     69     13      1   0             0 
+
+
+0x000006a5: 00 DW_LNE_set_address (0x0000000000000854)
+0x000006ac: 03 DW_LNS_advance_line (70)
+0x000006ae: 05 DW_LNS_set_column (20)
+0x000006b0: 06 DW_LNS_negate_stmt
+0x000006b1: 01 DW_LNS_copy
+            0x0000000000000854     70     20      1   0             0  is_stmt
+
+
+0x000006b2: 00 DW_LNE_set_address (0x000000000000085c)
+0x000006b9: 05 DW_LNS_set_column (13)
+0x000006bb: 06 DW_LNS_negate_stmt
+0x000006bc: 01 DW_LNS_copy
+            0x000000000000085c     70     13      1   0             0 
+
+
+0x000006bd: 00 DW_LNE_set_address (0x000000000000087a)
+0x000006c4: 03 DW_LNS_advance_line (74)
+0x000006c6: 05 DW_LNS_set_column (22)
+0x000006c8: 06 DW_LNS_negate_stmt
+0x000006c9: 01 DW_LNS_copy
+            0x000000000000087a     74     22      1   0             0  is_stmt
+
+
+0x000006ca: 00 DW_LNE_set_address (0x000000000000088b)
+0x000006d1: 05 DW_LNS_set_column (17)
+0x000006d3: 06 DW_LNS_negate_stmt
+0x000006d4: 01 DW_LNS_copy
+            0x000000000000088b     74     17      1   0             0 
+
+
+0x000006d5: 00 DW_LNE_set_address (0x0000000000000893)
+0x000006dc: 03 DW_LNS_advance_line (75)
+0x000006de: 05 DW_LNS_set_column (20)
+0x000006e0: 06 DW_LNS_negate_stmt
+0x000006e1: 01 DW_LNS_copy
+            0x0000000000000893     75     20      1   0             0  is_stmt
+
+
+0x000006e2: 00 DW_LNE_set_address (0x000000000000089b)
+0x000006e9: 05 DW_LNS_set_column (25)
+0x000006eb: 06 DW_LNS_negate_stmt
+0x000006ec: 01 DW_LNS_copy
+            0x000000000000089b     75     25      1   0             0 
+
+
+0x000006ed: 00 DW_LNE_set_address (0x00000000000008a7)
+0x000006f4: 05 DW_LNS_set_column (29)
+0x000006f6: 01 DW_LNS_copy
+            0x00000000000008a7     75     29      1   0             0 
+
+
+0x000006f7: 00 DW_LNE_set_address (0x00000000000008af)
+0x000006fe: 05 DW_LNS_set_column (27)
+0x00000700: 01 DW_LNS_copy
+            0x00000000000008af     75     27      1   0             0 
+
+
+0x00000701: 00 DW_LNE_set_address (0x00000000000008c5)
+0x00000708: 05 DW_LNS_set_column (13)
+0x0000070a: 01 DW_LNS_copy
+            0x00000000000008c5     75     13      1   0             0 
+
+
+0x0000070b: 00 DW_LNE_set_address (0x00000000000008da)
+0x00000712: 03 DW_LNS_advance_line (76)
+0x00000714: 05 DW_LNS_set_column (27)
+0x00000716: 06 DW_LNS_negate_stmt
+0x00000717: 01 DW_LNS_copy
+            0x00000000000008da     76     27      1   0             0  is_stmt
+
+
+0x00000718: 00 DW_LNE_set_address (0x00000000000008e2)
+0x0000071f: 05 DW_LNS_set_column (33)
+0x00000721: 06 DW_LNS_negate_stmt
+0x00000722: 01 DW_LNS_copy
+            0x00000000000008e2     76     33      1   0             0 
+
+
+0x00000723: 00 DW_LNE_set_address (0x00000000000008ea)
+0x0000072a: 05 DW_LNS_set_column (35)
+0x0000072c: 01 DW_LNS_copy
+            0x00000000000008ea     76     35      1   0             0 
+
+
+0x0000072d: 00 DW_LNE_set_address (0x00000000000008f9)
+0x00000734: 05 DW_LNS_set_column (27)
+0x00000736: 01 DW_LNS_copy
+            0x00000000000008f9     76     27      1   0             0 
+
+
+0x00000737: 00 DW_LNE_set_address (0x000000000000091b)
+0x0000073e: 05 DW_LNS_set_column (16)
+0x00000740: 01 DW_LNS_copy
+            0x000000000000091b     76     16      1   0             0 
+
+
+0x00000741: 00 DW_LNE_set_address (0x0000000000000923)
+0x00000748: 05 DW_LNS_set_column (22)
+0x0000074a: 01 DW_LNS_copy
+            0x0000000000000923     76     22      1   0             0 
+
+
+0x0000074b: 00 DW_LNE_set_address (0x000000000000092b)
+0x00000752: 05 DW_LNS_set_column (16)
+0x00000754: 01 DW_LNS_copy
+            0x000000000000092b     76     16      1   0             0 
+
+
+0x00000755: 00 DW_LNE_set_address (0x0000000000000944)
+0x0000075c: 05 DW_LNS_set_column (25)
+0x0000075e: 01 DW_LNS_copy
+            0x0000000000000944     76     25      1   0             0 
+
+
+0x0000075f: 00 DW_LNE_set_address (0x000000000000094d)
+0x00000766: 03 DW_LNS_advance_line (75)
+0x00000768: 05 DW_LNS_set_column (33)
+0x0000076a: 06 DW_LNS_negate_stmt
+0x0000076b: 01 DW_LNS_copy
+            0x000000000000094d     75     33      1   0             0  is_stmt
+
+
+0x0000076c: 00 DW_LNE_set_address (0x000000000000096c)
+0x00000773: 05 DW_LNS_set_column (13)
+0x00000775: 06 DW_LNS_negate_stmt
+0x00000776: 01 DW_LNS_copy
+            0x000000000000096c     75     13      1   0             0 
+
+
+0x00000777: 00 DW_LNE_set_address (0x000000000000096e)
+0x0000077e: 01 DW_LNS_copy
+            0x000000000000096e     75     13      1   0             0 
+
+
+0x0000077f: 00 DW_LNE_set_address (0x0000000000000976)
+0x00000786: 03 DW_LNS_advance_line (77)
+0x00000788: 05 DW_LNS_set_column (24)
+0x0000078a: 06 DW_LNS_negate_stmt
+0x0000078b: 01 DW_LNS_copy
+            0x0000000000000976     77     24      1   0             0  is_stmt
+
+
+0x0000078c: 00 DW_LNE_set_address (0x000000000000097e)
+0x00000793: 05 DW_LNS_set_column (13)
+0x00000795: 06 DW_LNS_negate_stmt
+0x00000796: 01 DW_LNS_copy
+            0x000000000000097e     77     13      1   0             0 
+
+
+0x00000797: 00 DW_LNE_set_address (0x0000000000000986)
+0x0000079e: 05 DW_LNS_set_column (19)
+0x000007a0: 01 DW_LNS_copy
+            0x0000000000000986     77     19      1   0             0 
+
+
+0x000007a1: 00 DW_LNE_set_address (0x000000000000098e)
+0x000007a8: 05 DW_LNS_set_column (13)
+0x000007aa: 01 DW_LNS_copy
+            0x000000000000098e     77     13      1   0             0 
+
+
+0x000007ab: 00 DW_LNE_set_address (0x00000000000009a7)
+0x000007b2: 05 DW_LNS_set_column (22)
+0x000007b4: 01 DW_LNS_copy
+            0x00000000000009a7     77     22      1   0             0 
+
+
+0x000007b5: 00 DW_LNE_set_address (0x00000000000009b0)
+0x000007bc: 03 DW_LNS_advance_line (79)
+0x000007be: 05 DW_LNS_set_column (16)
+0x000007c0: 06 DW_LNS_negate_stmt
+0x000007c1: 01 DW_LNS_copy
+            0x00000000000009b0     79     16      1   0             0  is_stmt
+
+
+0x000007c2: 00 DW_LNE_set_address (0x00000000000009b8)
+0x000007c9: 05 DW_LNS_set_column (22)
+0x000007cb: 06 DW_LNS_negate_stmt
+0x000007cc: 01 DW_LNS_copy
+            0x00000000000009b8     79     22      1   0             0 
+
+
+0x000007cd: 00 DW_LNE_set_address (0x00000000000009c0)
+0x000007d4: 05 DW_LNS_set_column (16)
+0x000007d6: 01 DW_LNS_copy
+            0x00000000000009c0     79     16      1   0             0 
+
+
+0x000007d7: 00 DW_LNE_set_address (0x00000000000009d9)
+0x000007de: 05 DW_LNS_set_column (14)
+0x000007e0: 01 DW_LNS_copy
+            0x00000000000009d9     79     14      1   0             0 
+
+
+0x000007e1: 00 DW_LNE_set_address (0x00000000000009fa)
+0x000007e8: 05 DW_LNS_set_column (25)
+0x000007ea: 01 DW_LNS_copy
+            0x00000000000009fa     79     25      1   0             0 
+
+
+0x000007eb: 00 DW_LNE_set_address (0x0000000000000a10)
+0x000007f2: 05 DW_LNS_set_column (14)
+0x000007f4: 01 DW_LNS_copy
+            0x0000000000000a10     79     14      1   0             0 
+
+
+0x000007f5: 00 DW_LNE_set_address (0x0000000000000a29)
+0x000007fc: 03 DW_LNS_advance_line (80)
+0x000007fe: 05 DW_LNS_set_column (13)
+0x00000800: 06 DW_LNS_negate_stmt
+0x00000801: 01 DW_LNS_copy
+            0x0000000000000a29     80     13      1   0             0  is_stmt
+
+
+0x00000802: 00 DW_LNE_set_address (0x0000000000000a2c)
+0x00000809: 03 DW_LNS_advance_line (81)
+0x0000080b: 05 DW_LNS_set_column (11)
+0x0000080d: 01 DW_LNS_copy
+            0x0000000000000a2c     81     11      1   0             0  is_stmt
+
+
+0x0000080e: 00 DW_LNE_set_address (0x0000000000000a4b)
+0x00000815: 03 DW_LNS_advance_line (65)
+0x00000817: 05 DW_LNS_set_column (7)
+0x00000819: 01 DW_LNS_copy
+            0x0000000000000a4b     65      7      1   0             0  is_stmt
+
+
+0x0000081a: 00 DW_LNE_set_address (0x0000000000000a4e)
+0x00000821: 03 DW_LNS_advance_line (80)
+0x00000823: 05 DW_LNS_set_column (13)
+0x00000825: 01 DW_LNS_copy
+            0x0000000000000a4e     80     13      1   0             0  is_stmt
+
+
+0x00000826: 00 DW_LNE_set_address (0x0000000000000a4f)
+0x0000082d: 03 DW_LNS_advance_line (43)
+0x0000082f: 05 DW_LNS_set_column (4)
+0x00000831: 00 DW_LNE_end_sequence
+            0x0000000000000a4f     43      4      1   0             0  is_stmt end_sequence
+
+0x00000834: 00 DW_LNE_set_address (0x0000000000000a55)
+0x0000083b: 03 DW_LNS_advance_line (152)
+0x0000083e: 01 DW_LNS_copy
+            0x0000000000000a55    152      0      1   0             0  is_stmt
+
+
+0x0000083f: 00 DW_LNE_set_address (0x0000000000000acc)
+0x00000846: 03 DW_LNS_advance_line (153)
+0x00000848: 05 DW_LNS_set_column (12)
+0x0000084a: 0a DW_LNS_set_prologue_end
+0x0000084b: 01 DW_LNS_copy
+            0x0000000000000acc    153     12      1   0             0  is_stmt prologue_end
+
+
+0x0000084c: 00 DW_LNE_set_address (0x0000000000000ad3)
+0x00000853: 05 DW_LNS_set_column (17)
+0x00000855: 06 DW_LNS_negate_stmt
+0x00000856: 01 DW_LNS_copy
+            0x0000000000000ad3    153     17      1   0             0 
+
+
+0x00000857: 00 DW_LNE_set_address (0x0000000000000ae2)
+0x0000085e: 05 DW_LNS_set_column (12)
+0x00000860: 01 DW_LNS_copy
+            0x0000000000000ae2    153     12      1   0             0 
+
+
+0x00000861: 00 DW_LNE_set_address (0x0000000000000af6)
+0x00000868: 05 DW_LNS_set_column (28)
+0x0000086a: 01 DW_LNS_copy
+            0x0000000000000af6    153     28      1   0             0 
+
+
+0x0000086b: 00 DW_LNE_set_address (0x0000000000000b04)
+0x00000872: 05 DW_LNS_set_column (23)
+0x00000874: 01 DW_LNS_copy
+            0x0000000000000b04    153     23      1   0             0 
+
+
+0x00000875: 00 DW_LNE_set_address (0x0000000000000b0a)
+0x0000087c: 05 DW_LNS_set_column (12)
+0x0000087e: 01 DW_LNS_copy
+            0x0000000000000b0a    153     12      1   0             0 
+
+
+0x0000087f: 00 DW_LNE_set_address (0x0000000000000b15)
+0x00000886: 01 DW_LNS_copy
+            0x0000000000000b15    153     12      1   0             0 
+
+
+0x00000887: 00 DW_LNE_set_address (0x0000000000000b1a)
+0x0000088e: 01 DW_LNS_copy
+            0x0000000000000b1a    153     12      1   0             0 
+
+
+0x0000088f: 00 DW_LNE_set_address (0x0000000000000b22)
+0x00000896: 05 DW_LNS_set_column (8)
+0x00000898: 01 DW_LNS_copy
+            0x0000000000000b22    153      8      1   0             0 
+
+
+0x00000899: 00 DW_LNE_set_address (0x0000000000000b29)
+0x000008a0: 03 DW_LNS_advance_line (155)
+0x000008a2: 06 DW_LNS_negate_stmt
+0x000008a3: 01 DW_LNS_copy
+            0x0000000000000b29    155      8      1   0             0  is_stmt
+
+
+0x000008a4: 00 DW_LNE_set_address (0x0000000000000b30)
+0x000008ab: 05 DW_LNS_set_column (10)
+0x000008ad: 06 DW_LNS_negate_stmt
+0x000008ae: 01 DW_LNS_copy
+            0x0000000000000b30    155     10      1   0             0 
+
+
+0x000008af: 00 DW_LNE_set_address (0x0000000000000b3f)
+0x000008b6: 05 DW_LNS_set_column (8)
+0x000008b8: 01 DW_LNS_copy
+            0x0000000000000b3f    155      8      1   0             0 
+
+
+0x000008b9: 00 DW_LNE_set_address (0x0000000000000b53)
+0x000008c0: 03 DW_LNS_advance_line (156)
+0x000008c2: 05 DW_LNS_set_column (7)
+0x000008c4: 06 DW_LNS_negate_stmt
+0x000008c5: 01 DW_LNS_copy
+            0x0000000000000b53    156      7      1   0             0  is_stmt
+
+
+0x000008c6: 00 DW_LNE_set_address (0x0000000000000b67)
+0x000008cd: 03 DW_LNS_advance_line (157)
+0x000008cf: 01 DW_LNS_copy
+            0x0000000000000b67    157      7      1   0             0  is_stmt
+
+
+0x000008d0: 00 DW_LNE_set_address (0x0000000000000b71)
+0x000008d7: 03 DW_LNS_advance_line (159)
+0x000008d9: 05 DW_LNS_set_column (38)
+0x000008db: 01 DW_LNS_copy
+            0x0000000000000b71    159     38      1   0             0  is_stmt
+
+
+0x000008dc: 00 DW_LNE_set_address (0x0000000000000b78)
+0x000008e3: 05 DW_LNS_set_column (50)
+0x000008e5: 06 DW_LNS_negate_stmt
+0x000008e6: 01 DW_LNS_copy
+            0x0000000000000b78    159     50      1   0             0 
+
+
+0x000008e7: 00 DW_LNE_set_address (0x0000000000000b7f)
+0x000008ee: 05 DW_LNS_set_column (41)
+0x000008f0: 01 DW_LNS_copy
+            0x0000000000000b7f    159     41      1   0             0 
+
+
+0x000008f1: 00 DW_LNE_set_address (0x0000000000000b85)
+0x000008f8: 05 DW_LNS_set_column (4)
+0x000008fa: 01 DW_LNS_copy
+            0x0000000000000b85    159      4      1   0             0 
+
+
+0x000008fb: 00 DW_LNE_set_address (0x0000000000000ba3)
+0x00000902: 03 DW_LNS_advance_line (160)
+0x00000904: 06 DW_LNS_negate_stmt
+0x00000905: 01 DW_LNS_copy
+            0x0000000000000ba3    160      4      1   0             0  is_stmt
+
+
+0x00000906: 00 DW_LNE_set_address (0x0000000000000bab)
+0x0000090d: 03 DW_LNS_advance_line (161)
+0x0000090f: 05 DW_LNS_set_column (1)
+0x00000911: 01 DW_LNS_copy
+            0x0000000000000bab    161      1      1   0             0  is_stmt
+
+
+0x00000912: 00 DW_LNE_set_address (0x0000000000000bc5)
+0x00000919: 00 DW_LNE_end_sequence
+            0x0000000000000bc5    161      1      1   0             0  is_stmt end_sequence
+
+0x0000091c: 00 DW_LNE_set_address (0x0000000000000bc7)
+0x00000923: 03 DW_LNS_advance_line (88)
+0x00000926: 01 DW_LNS_copy
+            0x0000000000000bc7     88      0      1   0             0  is_stmt
+
+
+0x00000927: 00 DW_LNE_set_address (0x0000000000000d51)
+0x0000092e: 03 DW_LNS_advance_line (90)
+0x00000930: 05 DW_LNS_set_column (8)
+0x00000932: 0a DW_LNS_set_prologue_end
+0x00000933: 01 DW_LNS_copy
+            0x0000000000000d51     90      8      1   0             0  is_stmt prologue_end
+
+
+0x00000934: 00 DW_LNE_set_address (0x0000000000000d58)
+0x0000093b: 03 DW_LNS_advance_line (93)
+0x0000093d: 05 DW_LNS_set_column (9)
+0x0000093f: 01 DW_LNS_copy
+            0x0000000000000d58     93      9      1   0             0  is_stmt
+
+
+0x00000940: 00 DW_LNE_set_address (0x0000000000000d5f)
+0x00000947: 03 DW_LNS_advance_line (94)
+0x00000949: 05 DW_LNS_set_column (11)
+0x0000094b: 01 DW_LNS_copy
+            0x0000000000000d5f     94     11      1   0             0  is_stmt
+
+
+0x0000094c: 00 DW_LNE_set_address (0x0000000000000d66)
+0x00000953: 05 DW_LNS_set_column (16)
+0x00000955: 06 DW_LNS_negate_stmt
+0x00000956: 01 DW_LNS_copy
+            0x0000000000000d66     94     16      1   0             0 
+
+
+0x00000957: 00 DW_LNE_set_address (0x0000000000000d71)
+0x0000095e: 05 DW_LNS_set_column (20)
+0x00000960: 01 DW_LNS_copy
+            0x0000000000000d71     94     20      1   0             0 
+
+
+0x00000961: 00 DW_LNE_set_address (0x0000000000000d78)
+0x00000968: 05 DW_LNS_set_column (22)
+0x0000096a: 01 DW_LNS_copy
+            0x0000000000000d78     94     22      1   0             0 
+
+
+0x0000096b: 00 DW_LNE_set_address (0x0000000000000d83)
+0x00000972: 05 DW_LNS_set_column (18)
+0x00000974: 01 DW_LNS_copy
+            0x0000000000000d83     94     18      1   0             0 
+
+
+0x00000975: 00 DW_LNE_set_address (0x0000000000000d92)
+0x0000097c: 05 DW_LNS_set_column (4)
+0x0000097e: 01 DW_LNS_copy
+            0x0000000000000d92     94      4      1   0             0 
+
+
+0x0000097f: 00 DW_LNE_set_address (0x0000000000000da6)
+0x00000986: 03 DW_LNS_advance_line (95)
+0x00000988: 05 DW_LNS_set_column (29)
+0x0000098a: 06 DW_LNS_negate_stmt
+0x0000098b: 01 DW_LNS_copy
+            0x0000000000000da6     95     29      1   0             0  is_stmt
+
+
+0x0000098c: 00 DW_LNE_set_address (0x0000000000000dac)
+0x00000993: 05 DW_LNS_set_column (13)
+0x00000995: 06 DW_LNS_negate_stmt
+0x00000996: 01 DW_LNS_copy
+            0x0000000000000dac     95     13      1   0             0 
+
+
+0x00000997: 00 DW_LNE_set_address (0x0000000000000db3)
+0x0000099e: 03 DW_LNS_advance_line (96)
+0x000009a0: 05 DW_LNS_set_column (18)
+0x000009a2: 06 DW_LNS_negate_stmt
+0x000009a3: 01 DW_LNS_copy
+            0x0000000000000db3     96     18      1   0             0  is_stmt
+
+
+0x000009a4: 00 DW_LNE_set_address (0x0000000000000dba)
+0x000009ab: 05 DW_LNS_set_column (7)
+0x000009ad: 06 DW_LNS_negate_stmt
+0x000009ae: 01 DW_LNS_copy
+            0x0000000000000dba     96      7      1   0             0 
+
+
+0x000009af: 00 DW_LNE_set_address (0x0000000000000dc1)
+0x000009b6: 05 DW_LNS_set_column (16)
+0x000009b8: 01 DW_LNS_copy
+            0x0000000000000dc1     96     16      1   0             0 
+
+
+0x000009b9: 00 DW_LNE_set_address (0x0000000000000dc8)
+0x000009c0: 03 DW_LNS_advance_line (97)
+0x000009c2: 05 DW_LNS_set_column (18)
+0x000009c4: 06 DW_LNS_negate_stmt
+0x000009c5: 01 DW_LNS_copy
+            0x0000000000000dc8     97     18      1   0             0  is_stmt
+
+
+0x000009c6: 00 DW_LNE_set_address (0x0000000000000dcf)
+0x000009cd: 05 DW_LNS_set_column (7)
+0x000009cf: 06 DW_LNS_negate_stmt
+0x000009d0: 01 DW_LNS_copy
+            0x0000000000000dcf     97      7      1   0             0 
+
+
+0x000009d1: 00 DW_LNE_set_address (0x0000000000000dd6)
+0x000009d8: 05 DW_LNS_set_column (16)
+0x000009da: 01 DW_LNS_copy
+            0x0000000000000dd6     97     16      1   0             0 
+
+
+0x000009db: 00 DW_LNE_set_address (0x0000000000000ddd)
+0x000009e2: 03 DW_LNS_advance_line (98)
+0x000009e4: 05 DW_LNS_set_column (21)
+0x000009e6: 06 DW_LNS_negate_stmt
+0x000009e7: 01 DW_LNS_copy
+            0x0000000000000ddd     98     21      1   0             0  is_stmt
+
+
+0x000009e8: 00 DW_LNE_set_address (0x0000000000000de4)
+0x000009ef: 05 DW_LNS_set_column (7)
+0x000009f1: 06 DW_LNS_negate_stmt
+0x000009f2: 01 DW_LNS_copy
+            0x0000000000000de4     98      7      1   0             0 
+
+
+0x000009f3: 00 DW_LNE_set_address (0x0000000000000deb)
+0x000009fa: 05 DW_LNS_set_column (19)
+0x000009fc: 01 DW_LNS_copy
+            0x0000000000000deb     98     19      1   0             0 
+
+
+0x000009fd: 00 DW_LNE_set_address (0x0000000000000df2)
+0x00000a04: 03 DW_LNS_advance_line (99)
+0x00000a06: 05 DW_LNS_set_column (14)
+0x00000a08: 06 DW_LNS_negate_stmt
+0x00000a09: 01 DW_LNS_copy
+            0x0000000000000df2     99     14      1   0             0  is_stmt
+
+
+0x00000a0a: 00 DW_LNE_set_address (0x0000000000000df9)
+0x00000a11: 05 DW_LNS_set_column (12)
+0x00000a13: 06 DW_LNS_negate_stmt
+0x00000a14: 01 DW_LNS_copy
+            0x0000000000000df9     99     12      1   0             0 
+
+
+0x00000a15: 00 DW_LNE_set_address (0x0000000000000e00)
+0x00000a1c: 03 DW_LNS_advance_line (94)
+0x00000a1e: 05 DW_LNS_set_column (28)
+0x00000a20: 06 DW_LNS_negate_stmt
+0x00000a21: 01 DW_LNS_copy
+            0x0000000000000e00     94     28      1   0             0  is_stmt
+
+
+0x00000a22: 00 DW_LNE_set_address (0x0000000000000e19)
+0x00000a29: 05 DW_LNS_set_column (4)
+0x00000a2b: 06 DW_LNS_negate_stmt
+0x00000a2c: 01 DW_LNS_copy
+            0x0000000000000e19     94      4      1   0             0 
+
+
+0x00000a2d: 00 DW_LNE_set_address (0x0000000000000e1b)
+0x00000a34: 01 DW_LNS_copy
+            0x0000000000000e1b     94      4      1   0             0 
+
+
+0x00000a35: 00 DW_LNE_set_address (0x0000000000000e22)
+0x00000a3c: 03 DW_LNS_advance_line (102)
+0x00000a3e: 05 DW_LNS_set_column (25)
+0x00000a40: 06 DW_LNS_negate_stmt
+0x00000a41: 01 DW_LNS_copy
+            0x0000000000000e22    102     25      1   0             0  is_stmt
+
+
+0x00000a42: 00 DW_LNE_set_address (0x0000000000000e29)
+0x00000a49: 05 DW_LNS_set_column (27)
+0x00000a4b: 06 DW_LNS_negate_stmt
+0x00000a4c: 01 DW_LNS_copy
+            0x0000000000000e29    102     27      1   0             0 
+
+
+0x00000a4d: 00 DW_LNE_set_address (0x0000000000000e34)
+0x00000a54: 05 DW_LNS_set_column (18)
+0x00000a56: 01 DW_LNS_copy
+            0x0000000000000e34    102     18      1   0             0 
+
+
+0x00000a57: 00 DW_LNE_set_address (0x0000000000000e3a)
+0x00000a5e: 05 DW_LNS_set_column (10)
+0x00000a60: 01 DW_LNS_copy
+            0x0000000000000e3a    102     10      1   0             0 
+
+
+0x00000a61: 00 DW_LNE_set_address (0x0000000000000e41)
+0x00000a68: 03 DW_LNS_advance_line (103)
+0x00000a6a: 05 DW_LNS_set_column (25)
+0x00000a6c: 06 DW_LNS_negate_stmt
+0x00000a6d: 01 DW_LNS_copy
+            0x0000000000000e41    103     25      1   0             0  is_stmt
+
+
+0x00000a6e: 00 DW_LNE_set_address (0x0000000000000e48)
+0x00000a75: 05 DW_LNS_set_column (27)
+0x00000a77: 06 DW_LNS_negate_stmt
+0x00000a78: 01 DW_LNS_copy
+            0x0000000000000e48    103     27      1   0             0 
+
+
+0x00000a79: 00 DW_LNE_set_address (0x0000000000000e53)
+0x00000a80: 05 DW_LNS_set_column (18)
+0x00000a82: 01 DW_LNS_copy
+            0x0000000000000e53    103     18      1   0             0 
+
+
+0x00000a83: 00 DW_LNE_set_address (0x0000000000000e59)
+0x00000a8a: 05 DW_LNS_set_column (10)
+0x00000a8c: 01 DW_LNS_copy
+            0x0000000000000e59    103     10      1   0             0 
+
+
+0x00000a8d: 00 DW_LNE_set_address (0x0000000000000e60)
+0x00000a94: 03 DW_LNS_advance_line (105)
+0x00000a96: 05 DW_LNS_set_column (11)
+0x00000a98: 06 DW_LNS_negate_stmt
+0x00000a99: 01 DW_LNS_copy
+            0x0000000000000e60    105     11      1   0             0  is_stmt
+
+
+0x00000a9a: 00 DW_LNE_set_address (0x0000000000000e67)
+0x00000aa1: 05 DW_LNS_set_column (16)
+0x00000aa3: 06 DW_LNS_negate_stmt
+0x00000aa4: 01 DW_LNS_copy
+            0x0000000000000e67    105     16      1   0             0 
+
+
+0x00000aa5: 00 DW_LNE_set_address (0x0000000000000e72)
+0x00000aac: 05 DW_LNS_set_column (20)
+0x00000aae: 01 DW_LNS_copy
+            0x0000000000000e72    105     20      1   0             0 
+
+
+0x00000aaf: 00 DW_LNE_set_address (0x0000000000000e79)
+0x00000ab6: 05 DW_LNS_set_column (18)
+0x00000ab8: 01 DW_LNS_copy
+            0x0000000000000e79    105     18      1   0             0 
+
+
+0x00000ab9: 00 DW_LNE_set_address (0x0000000000000e88)
+0x00000ac0: 05 DW_LNS_set_column (4)
+0x00000ac2: 01 DW_LNS_copy
+            0x0000000000000e88    105      4      1   0             0 
+
+
+0x00000ac3: 00 DW_LNE_set_address (0x0000000000000e98)
+0x00000aca: 03 DW_LNS_advance_line (106)
+0x00000acc: 05 DW_LNS_set_column (18)
+0x00000ace: 06 DW_LNS_negate_stmt
+0x00000acf: 01 DW_LNS_copy
+            0x0000000000000e98    106     18      1   0             0  is_stmt
+
+
+0x00000ad0: 00 DW_LNE_set_address (0x0000000000000e9f)
+0x00000ad7: 05 DW_LNS_set_column (7)
+0x00000ad9: 06 DW_LNS_negate_stmt
+0x00000ada: 01 DW_LNS_copy
+            0x0000000000000e9f    106      7      1   0             0 
+
+
+0x00000adb: 00 DW_LNE_set_address (0x0000000000000ea6)
+0x00000ae2: 05 DW_LNS_set_column (13)
+0x00000ae4: 01 DW_LNS_copy
+            0x0000000000000ea6    106     13      1   0             0 
+
+
+0x00000ae5: 00 DW_LNE_set_address (0x0000000000000ead)
+0x00000aec: 05 DW_LNS_set_column (7)
+0x00000aee: 01 DW_LNS_copy
+            0x0000000000000ead    106      7      1   0             0 
+
+
+0x00000aef: 00 DW_LNE_set_address (0x0000000000000ebf)
+0x00000af6: 05 DW_LNS_set_column (16)
+0x00000af8: 01 DW_LNS_copy
+            0x0000000000000ebf    106     16      1   0             0 
+
+
+0x00000af9: 00 DW_LNE_set_address (0x0000000000000ec6)
+0x00000b00: 03 DW_LNS_advance_line (105)
+0x00000b02: 05 DW_LNS_set_column (24)
+0x00000b04: 06 DW_LNS_negate_stmt
+0x00000b05: 01 DW_LNS_copy
+            0x0000000000000ec6    105     24      1   0             0  is_stmt
+
+
+0x00000b06: 00 DW_LNE_set_address (0x0000000000000edf)
+0x00000b0d: 05 DW_LNS_set_column (4)
+0x00000b0f: 06 DW_LNS_negate_stmt
+0x00000b10: 01 DW_LNS_copy
+            0x0000000000000edf    105      4      1   0             0 
+
+
+0x00000b11: 00 DW_LNE_set_address (0x0000000000000ee1)
+0x00000b18: 01 DW_LNS_copy
+            0x0000000000000ee1    105      4      1   0             0 
+
+
+0x00000b19: 00 DW_LNE_set_address (0x0000000000000ee4)
+0x00000b20: 03 DW_LNS_advance_line (108)
+0x00000b22: 05 DW_LNS_set_column (8)
+0x00000b24: 06 DW_LNS_negate_stmt
+0x00000b25: 01 DW_LNS_copy
+            0x0000000000000ee4    108      8      1   0             0  is_stmt
+
+
+0x00000b26: 00 DW_LNE_set_address (0x0000000000000eeb)
+0x00000b2d: 05 DW_LNS_set_column (6)
+0x00000b2f: 06 DW_LNS_negate_stmt
+0x00000b30: 01 DW_LNS_copy
+            0x0000000000000eeb    108      6      1   0             0 
+
+
+0x00000b31: 00 DW_LNE_set_address (0x0000000000000ef2)
+0x00000b38: 03 DW_LNS_advance_line (110)
+0x00000b3a: 05 DW_LNS_set_column (11)
+0x00000b3c: 06 DW_LNS_negate_stmt
+0x00000b3d: 01 DW_LNS_copy
+            0x0000000000000ef2    110     11      1   0             0  is_stmt
+
+
+0x00000b3e: 00 DW_LNE_set_address (0x0000000000000efd)
+0x00000b45: 06 DW_LNS_negate_stmt
+0x00000b46: 01 DW_LNS_copy
+            0x0000000000000efd    110     11      1   0             0 
+
+
+0x00000b47: 00 DW_LNE_set_address (0x0000000000000f0a)
+0x00000b4e: 03 DW_LNS_advance_line (111)
+0x00000b50: 05 DW_LNS_set_column (17)
+0x00000b52: 06 DW_LNS_negate_stmt
+0x00000b53: 01 DW_LNS_copy
+            0x0000000000000f0a    111     17      1   0             0  is_stmt
+
+
+0x00000b54: 00 DW_LNE_set_address (0x0000000000000f11)
+0x00000b5b: 05 DW_LNS_set_column (22)
+0x00000b5d: 06 DW_LNS_negate_stmt
+0x00000b5e: 01 DW_LNS_copy
+            0x0000000000000f11    111     22      1   0             0 
+
+
+0x00000b5f: 00 DW_LNE_set_address (0x0000000000000f1c)
+0x00000b66: 05 DW_LNS_set_column (26)
+0x00000b68: 01 DW_LNS_copy
+            0x0000000000000f1c    111     26      1   0             0 
+
+
+0x00000b69: 00 DW_LNE_set_address (0x0000000000000f23)
+0x00000b70: 05 DW_LNS_set_column (24)
+0x00000b72: 01 DW_LNS_copy
+            0x0000000000000f23    111     24      1   0             0 
+
+
+0x00000b73: 00 DW_LNE_set_address (0x0000000000000f32)
+0x00000b7a: 05 DW_LNS_set_column (10)
+0x00000b7c: 01 DW_LNS_copy
+            0x0000000000000f32    111     10      1   0             0 
+
+
+0x00000b7d: 00 DW_LNE_set_address (0x0000000000000f42)
+0x00000b84: 03 DW_LNS_advance_line (112)
+0x00000b86: 05 DW_LNS_set_column (26)
+0x00000b88: 06 DW_LNS_negate_stmt
+0x00000b89: 01 DW_LNS_copy
+            0x0000000000000f42    112     26      1   0             0  is_stmt
+
+
+0x00000b8a: 00 DW_LNE_set_address (0x0000000000000f49)
+0x00000b91: 05 DW_LNS_set_column (32)
+0x00000b93: 06 DW_LNS_negate_stmt
+0x00000b94: 01 DW_LNS_copy
+            0x0000000000000f49    112     32      1   0             0 
+
+
+0x00000b95: 00 DW_LNE_set_address (0x0000000000000f50)
+0x00000b9c: 05 DW_LNS_set_column (26)
+0x00000b9e: 01 DW_LNS_copy
+            0x0000000000000f50    112     26      1   0             0 
+
+
+0x00000b9f: 00 DW_LNE_set_address (0x0000000000000f69)
+0x00000ba6: 05 DW_LNS_set_column (35)
+0x00000ba8: 01 DW_LNS_copy
+            0x0000000000000f69    112     35      1   0             0 
+
+
+0x00000ba9: 00 DW_LNE_set_address (0x0000000000000f74)
+0x00000bb0: 05 DW_LNS_set_column (13)
+0x00000bb2: 01 DW_LNS_copy
+            0x0000000000000f74    112     13      1   0             0 
+
+
+0x00000bb3: 00 DW_LNE_set_address (0x0000000000000f87)
+0x00000bba: 03 DW_LNS_advance_line (111)
+0x00000bbc: 05 DW_LNS_set_column (30)
+0x00000bbe: 06 DW_LNS_negate_stmt
+0x00000bbf: 01 DW_LNS_copy
+            0x0000000000000f87    111     30      1   0             0  is_stmt
+
+
+0x00000bc0: 00 DW_LNE_set_address (0x0000000000000fa0)
+0x00000bc7: 05 DW_LNS_set_column (10)
+0x00000bc9: 06 DW_LNS_negate_stmt
+0x00000bca: 01 DW_LNS_copy
+            0x0000000000000fa0    111     10      1   0             0 
+
+
+0x00000bcb: 00 DW_LNE_set_address (0x0000000000000fa2)
+0x00000bd2: 01 DW_LNS_copy
+            0x0000000000000fa2    111     10      1   0             0 
+
+
+0x00000bd3: 00 DW_LNE_set_address (0x0000000000000fa5)
+0x00000bda: 03 DW_LNS_advance_line (113)
+0x00000bdc: 06 DW_LNS_negate_stmt
+0x00000bdd: 01 DW_LNS_copy
+            0x0000000000000fa5    113     10      1   0             0  is_stmt
+
+
+0x00000bde: 00 DW_LNE_set_address (0x0000000000000fb5)
+0x00000be5: 03 DW_LNS_advance_line (114)
+0x00000be7: 05 DW_LNS_set_column (17)
+0x00000be9: 01 DW_LNS_copy
+            0x0000000000000fb5    114     17      1   0             0  is_stmt
+
+
+0x00000bea: 00 DW_LNE_set_address (0x0000000000000fce)
+0x00000bf1: 03 DW_LNS_advance_line (115)
+0x00000bf3: 05 DW_LNS_set_column (7)
+0x00000bf5: 01 DW_LNS_copy
+            0x0000000000000fce    115      7      1   0             0  is_stmt
+
+
+0x00000bf6: 00 DW_LNE_set_address (0x0000000000000fd1)
+0x00000bfd: 03 DW_LNS_advance_line (116)
+0x00000bff: 05 DW_LNS_set_column (10)
+0x00000c01: 01 DW_LNS_copy
+            0x0000000000000fd1    116     10      1   0             0  is_stmt
+
+
+0x00000c02: 00 DW_LNE_set_address (0x0000000000000fdc)
+0x00000c09: 03 DW_LNS_advance_line (118)
+0x00000c0b: 05 DW_LNS_set_column (14)
+0x00000c0d: 01 DW_LNS_copy
+            0x0000000000000fdc    118     14      1   0             0  is_stmt
+
+
+0x00000c0e: 00 DW_LNE_set_address (0x0000000000000fe3)
+0x00000c15: 05 DW_LNS_set_column (16)
+0x00000c17: 06 DW_LNS_negate_stmt
+0x00000c18: 01 DW_LNS_copy
+            0x0000000000000fe3    118     16      1   0             0 
+
+
+0x00000c19: 00 DW_LNE_set_address (0x0000000000000ff2)
+0x00000c20: 05 DW_LNS_set_column (7)
+0x00000c22: 01 DW_LNS_copy
+            0x0000000000000ff2    118      7      1   0             0 
+
+
+0x00000c23: 00 DW_LNE_set_address (0x0000000000001002)
+0x00000c2a: 03 DW_LNS_advance_line (119)
+0x00000c2c: 05 DW_LNS_set_column (25)
+0x00000c2e: 06 DW_LNS_negate_stmt
+0x00000c2f: 01 DW_LNS_copy
+            0x0000000000001002    119     25      1   0             0  is_stmt
+
+
+0x00000c30: 00 DW_LNE_set_address (0x0000000000001009)
+0x00000c37: 05 DW_LNS_set_column (10)
+0x00000c39: 06 DW_LNS_negate_stmt
+0x00000c3a: 01 DW_LNS_copy
+            0x0000000000001009    119     10      1   0             0 
+
+
+0x00000c3b: 00 DW_LNE_set_address (0x0000000000001010)
+0x00000c42: 05 DW_LNS_set_column (16)
+0x00000c44: 01 DW_LNS_copy
+            0x0000000000001010    119     16      1   0             0 
+
+
+0x00000c45: 00 DW_LNE_set_address (0x0000000000001017)
+0x00000c4c: 05 DW_LNS_set_column (18)
+0x00000c4e: 01 DW_LNS_copy
+            0x0000000000001017    119     18      1   0             0 
+
+
+0x00000c4f: 00 DW_LNE_set_address (0x0000000000001022)
+0x00000c56: 05 DW_LNS_set_column (10)
+0x00000c58: 01 DW_LNS_copy
+            0x0000000000001022    119     10      1   0             0 
+
+
+0x00000c59: 00 DW_LNE_set_address (0x0000000000001034)
+0x00000c60: 05 DW_LNS_set_column (23)
+0x00000c62: 01 DW_LNS_copy
+            0x0000000000001034    119     23      1   0             0 
+
+
+0x00000c63: 00 DW_LNE_set_address (0x000000000000103b)
+0x00000c6a: 03 DW_LNS_advance_line (118)
+0x00000c6c: 05 DW_LNS_set_column (22)
+0x00000c6e: 06 DW_LNS_negate_stmt
+0x00000c6f: 01 DW_LNS_copy
+            0x000000000000103b    118     22      1   0             0  is_stmt
+
+
+0x00000c70: 00 DW_LNE_set_address (0x0000000000001054)
+0x00000c77: 05 DW_LNS_set_column (7)
+0x00000c79: 06 DW_LNS_negate_stmt
+0x00000c7a: 01 DW_LNS_copy
+            0x0000000000001054    118      7      1   0             0 
+
+
+0x00000c7b: 00 DW_LNE_set_address (0x0000000000001056)
+0x00000c82: 01 DW_LNS_copy
+            0x0000000000001056    118      7      1   0             0 
+
+
+0x00000c83: 00 DW_LNE_set_address (0x0000000000001059)
+0x00000c8a: 03 DW_LNS_advance_line (122)
+0x00000c8c: 05 DW_LNS_set_column (14)
+0x00000c8e: 06 DW_LNS_negate_stmt
+0x00000c8f: 01 DW_LNS_copy
+            0x0000000000001059    122     14      1   0             0  is_stmt
+
+
+0x00000c90: 00 DW_LNE_set_address (0x0000000000001062)
+0x00000c97: 05 DW_LNS_set_column (19)
+0x00000c99: 06 DW_LNS_negate_stmt
+0x00000c9a: 01 DW_LNS_copy
+            0x0000000000001062    122     19      1   0             0 
+
+
+0x00000c9b: 00 DW_LNE_set_address (0x0000000000001069)
+0x00000ca2: 05 DW_LNS_set_column (16)
+0x00000ca4: 01 DW_LNS_copy
+            0x0000000000001069    122     16      1   0             0 
+
+
+0x00000ca5: 00 DW_LNE_set_address (0x0000000000001078)
+0x00000cac: 05 DW_LNS_set_column (14)
+0x00000cae: 01 DW_LNS_copy
+            0x0000000000001078    122     14      1   0             0 
+
+
+0x00000caf: 00 DW_LNE_set_address (0x000000000000108a)
+0x00000cb6: 03 DW_LNS_advance_line (123)
+0x00000cb8: 05 DW_LNS_set_column (13)
+0x00000cba: 06 DW_LNS_negate_stmt
+0x00000cbb: 01 DW_LNS_copy
+            0x000000000000108a    123     13      1   0             0  is_stmt
+
+
+0x00000cbc: 00 DW_LNE_set_address (0x0000000000001091)
+0x00000cc3: 03 DW_LNS_advance_line (125)
+0x00000cc5: 05 DW_LNS_set_column (22)
+0x00000cc7: 01 DW_LNS_copy
+            0x0000000000001091    125     22      1   0             0  is_stmt
+
+
+0x00000cc8: 00 DW_LNE_set_address (0x000000000000109f)
+0x00000ccf: 05 DW_LNS_set_column (17)
+0x00000cd1: 06 DW_LNS_negate_stmt
+0x00000cd2: 01 DW_LNS_copy
+            0x000000000000109f    125     17      1   0             0 
+
+
+0x00000cd3: 00 DW_LNE_set_address (0x00000000000010a6)
+0x00000cda: 03 DW_LNS_advance_line (126)
+0x00000cdc: 05 DW_LNS_set_column (20)
+0x00000cde: 06 DW_LNS_negate_stmt
+0x00000cdf: 01 DW_LNS_copy
+            0x00000000000010a6    126     20      1   0             0  is_stmt
+
+
+0x00000ce0: 00 DW_LNE_set_address (0x00000000000010ad)
+0x00000ce7: 05 DW_LNS_set_column (25)
+0x00000ce9: 06 DW_LNS_negate_stmt
+0x00000cea: 01 DW_LNS_copy
+            0x00000000000010ad    126     25      1   0             0 
+
+
+0x00000ceb: 00 DW_LNE_set_address (0x00000000000010b8)
+0x00000cf2: 05 DW_LNS_set_column (29)
+0x00000cf4: 01 DW_LNS_copy
+            0x00000000000010b8    126     29      1   0             0 
+
+
+0x00000cf5: 00 DW_LNE_set_address (0x00000000000010bf)
+0x00000cfc: 05 DW_LNS_set_column (27)
+0x00000cfe: 01 DW_LNS_copy
+            0x00000000000010bf    126     27      1   0             0 
+
+
+0x00000cff: 00 DW_LNE_set_address (0x00000000000010ce)
+0x00000d06: 05 DW_LNS_set_column (13)
+0x00000d08: 01 DW_LNS_copy
+            0x00000000000010ce    126     13      1   0             0 
+
+
+0x00000d09: 00 DW_LNE_set_address (0x00000000000010de)
+0x00000d10: 03 DW_LNS_advance_line (127)
+0x00000d12: 05 DW_LNS_set_column (27)
+0x00000d14: 06 DW_LNS_negate_stmt
+0x00000d15: 01 DW_LNS_copy
+            0x00000000000010de    127     27      1   0             0  is_stmt
+
+
+0x00000d16: 00 DW_LNE_set_address (0x00000000000010e5)
+0x00000d1d: 05 DW_LNS_set_column (33)
+0x00000d1f: 06 DW_LNS_negate_stmt
+0x00000d20: 01 DW_LNS_copy
+            0x00000000000010e5    127     33      1   0             0 
+
+
+0x00000d21: 00 DW_LNE_set_address (0x00000000000010ec)
+0x00000d28: 05 DW_LNS_set_column (35)
+0x00000d2a: 01 DW_LNS_copy
+            0x00000000000010ec    127     35      1   0             0 
+
+
+0x00000d2b: 00 DW_LNE_set_address (0x00000000000010f7)
+0x00000d32: 05 DW_LNS_set_column (27)
+0x00000d34: 01 DW_LNS_copy
+            0x00000000000010f7    127     27      1   0             0 
+
+
+0x00000d35: 00 DW_LNE_set_address (0x0000000000001110)
+0x00000d3c: 05 DW_LNS_set_column (16)
+0x00000d3e: 01 DW_LNS_copy
+            0x0000000000001110    127     16      1   0             0 
+
+
+0x00000d3f: 00 DW_LNE_set_address (0x0000000000001117)
+0x00000d46: 05 DW_LNS_set_column (22)
+0x00000d48: 01 DW_LNS_copy
+            0x0000000000001117    127     22      1   0             0 
+
+
+0x00000d49: 00 DW_LNE_set_address (0x000000000000111e)
+0x00000d50: 05 DW_LNS_set_column (16)
+0x00000d52: 01 DW_LNS_copy
+            0x000000000000111e    127     16      1   0             0 
+
+
+0x00000d53: 00 DW_LNE_set_address (0x0000000000001130)
+0x00000d5a: 05 DW_LNS_set_column (25)
+0x00000d5c: 01 DW_LNS_copy
+            0x0000000000001130    127     25      1   0             0 
+
+
+0x00000d5d: 00 DW_LNE_set_address (0x0000000000001137)
+0x00000d64: 03 DW_LNS_advance_line (126)
+0x00000d66: 05 DW_LNS_set_column (33)
+0x00000d68: 06 DW_LNS_negate_stmt
+0x00000d69: 01 DW_LNS_copy
+            0x0000000000001137    126     33      1   0             0  is_stmt
+
+
+0x00000d6a: 00 DW_LNE_set_address (0x0000000000001154)
+0x00000d71: 05 DW_LNS_set_column (13)
+0x00000d73: 06 DW_LNS_negate_stmt
+0x00000d74: 01 DW_LNS_copy
+            0x0000000000001154    126     13      1   0             0 
+
+
+0x00000d75: 00 DW_LNE_set_address (0x0000000000001156)
+0x00000d7c: 01 DW_LNS_copy
+            0x0000000000001156    126     13      1   0             0 
+
+
+0x00000d7d: 00 DW_LNE_set_address (0x000000000000115e)
+0x00000d84: 03 DW_LNS_advance_line (128)
+0x00000d86: 05 DW_LNS_set_column (24)
+0x00000d88: 06 DW_LNS_negate_stmt
+0x00000d89: 01 DW_LNS_copy
+            0x000000000000115e    128     24      1   0             0  is_stmt
+
+
+0x00000d8a: 00 DW_LNE_set_address (0x0000000000001166)
+0x00000d91: 05 DW_LNS_set_column (13)
+0x00000d93: 06 DW_LNS_negate_stmt
+0x00000d94: 01 DW_LNS_copy
+            0x0000000000001166    128     13      1   0             0 
+
+
+0x00000d95: 00 DW_LNE_set_address (0x000000000000116e)
+0x00000d9c: 05 DW_LNS_set_column (19)
+0x00000d9e: 01 DW_LNS_copy
+            0x000000000000116e    128     19      1   0             0 
+
+
+0x00000d9f: 00 DW_LNE_set_address (0x0000000000001176)
+0x00000da6: 05 DW_LNS_set_column (13)
+0x00000da8: 01 DW_LNS_copy
+            0x0000000000001176    128     13      1   0             0 
+
+
+0x00000da9: 00 DW_LNE_set_address (0x000000000000118f)
+0x00000db0: 05 DW_LNS_set_column (22)
+0x00000db2: 01 DW_LNS_copy
+            0x000000000000118f    128     22      1   0             0 
+
+
+0x00000db3: 00 DW_LNE_set_address (0x0000000000001198)
+0x00000dba: 03 DW_LNS_advance_line (130)
+0x00000dbc: 05 DW_LNS_set_column (16)
+0x00000dbe: 06 DW_LNS_negate_stmt
+0x00000dbf: 01 DW_LNS_copy
+            0x0000000000001198    130     16      1   0             0  is_stmt
+
+
+0x00000dc0: 00 DW_LNE_set_address (0x00000000000011a0)
+0x00000dc7: 05 DW_LNS_set_column (22)
+0x00000dc9: 06 DW_LNS_negate_stmt
+0x00000dca: 01 DW_LNS_copy
+            0x00000000000011a0    130     22      1   0             0 
+
+
+0x00000dcb: 00 DW_LNE_set_address (0x00000000000011a8)
+0x00000dd2: 05 DW_LNS_set_column (16)
+0x00000dd4: 01 DW_LNS_copy
+            0x00000000000011a8    130     16      1   0             0 
+
+
+0x00000dd5: 00 DW_LNE_set_address (0x00000000000011c1)
+0x00000ddc: 05 DW_LNS_set_column (14)
+0x00000dde: 01 DW_LNS_copy
+            0x00000000000011c1    130     14      1   0             0 
+
+
+0x00000ddf: 00 DW_LNE_set_address (0x00000000000011e2)
+0x00000de6: 05 DW_LNS_set_column (25)
+0x00000de8: 01 DW_LNS_copy
+            0x00000000000011e2    130     25      1   0             0 
+
+
+0x00000de9: 00 DW_LNE_set_address (0x00000000000011f8)
+0x00000df0: 05 DW_LNS_set_column (14)
+0x00000df2: 01 DW_LNS_copy
+            0x00000000000011f8    130     14      1   0             0 
+
+
+0x00000df3: 00 DW_LNE_set_address (0x0000000000001211)
+0x00000dfa: 03 DW_LNS_advance_line (131)
+0x00000dfc: 05 DW_LNS_set_column (13)
+0x00000dfe: 06 DW_LNS_negate_stmt
+0x00000dff: 01 DW_LNS_copy
+            0x0000000000001211    131     13      1   0             0  is_stmt
+
+
+0x00000e00: 00 DW_LNE_set_address (0x0000000000001214)
+0x00000e07: 03 DW_LNS_advance_line (133)
+0x00000e09: 05 DW_LNS_set_column (11)
+0x00000e0b: 01 DW_LNS_copy
+            0x0000000000001214    133     11      1   0             0  is_stmt
+
+
+0x00000e0c: 00 DW_LNE_set_address (0x0000000000001233)
+0x00000e13: 03 DW_LNS_advance_line (121)
+0x00000e15: 05 DW_LNS_set_column (7)
+0x00000e17: 01 DW_LNS_copy
+            0x0000000000001233    121      7      1   0             0  is_stmt
+
+
+0x00000e18: 00 DW_LNE_set_address (0x0000000000001236)
+0x00000e1f: 03 DW_LNS_advance_line (131)
+0x00000e21: 05 DW_LNS_set_column (13)
+0x00000e23: 01 DW_LNS_copy
+            0x0000000000001236    131     13      1   0             0  is_stmt
+
+
+0x00000e24: 00 DW_LNE_set_address (0x0000000000001237)
+0x00000e2b: 03 DW_LNS_advance_line (109)
+0x00000e2d: 05 DW_LNS_set_column (4)
+0x00000e2f: 01 DW_LNS_copy
+            0x0000000000001237    109      4      1   0             0  is_stmt
+
+
+0x00000e30: 00 DW_LNE_set_address (0x0000000000001239)
+0x00000e37: 03 DW_LNS_advance_line (123)
+0x00000e39: 05 DW_LNS_set_column (13)
+0x00000e3b: 01 DW_LNS_copy
+            0x0000000000001239    123     13      1   0             0  is_stmt
+
+
+0x00000e3c: 00 DW_LNE_set_address (0x0000000000001241)
+0x00000e43: 03 DW_LNS_advance_line (138)
+0x00000e45: 05 DW_LNS_set_column (9)
+0x00000e47: 01 DW_LNS_copy
+            0x0000000000001241    138      9      1   0             0  is_stmt
+
+
+0x00000e48: 00 DW_LNE_set_address (0x0000000000001249)
+0x00000e4f: 05 DW_LNS_set_column (4)
+0x00000e51: 06 DW_LNS_negate_stmt
+0x00000e52: 01 DW_LNS_copy
+            0x0000000000001249    138      4      1   0             0 
+
+
+0x00000e53: 00 DW_LNE_set_address (0x000000000000124e)
+0x00000e5a: 03 DW_LNS_advance_line (139)
+0x00000e5c: 05 DW_LNS_set_column (9)
+0x00000e5e: 06 DW_LNS_negate_stmt
+0x00000e5f: 01 DW_LNS_copy
+            0x000000000000124e    139      9      1   0             0  is_stmt
+
+
+0x00000e60: 00 DW_LNE_set_address (0x0000000000001256)
+0x00000e67: 05 DW_LNS_set_column (4)
+0x00000e69: 06 DW_LNS_negate_stmt
+0x00000e6a: 01 DW_LNS_copy
+            0x0000000000001256    139      4      1   0             0 
+
+
+0x00000e6b: 00 DW_LNE_set_address (0x000000000000125b)
+0x00000e72: 03 DW_LNS_advance_line (140)
+0x00000e74: 05 DW_LNS_set_column (13)
+0x00000e76: 06 DW_LNS_negate_stmt
+0x00000e77: 01 DW_LNS_copy
+            0x000000000000125b    140     13      1   0             0  is_stmt
+
+
+0x00000e78: 00 DW_LNE_set_address (0x000000000000126c)
+0x00000e7f: 03 DW_LNS_advance_line (141)
+0x00000e81: 05 DW_LNS_set_column (11)
+0x00000e83: 01 DW_LNS_copy
+            0x000000000000126c    141     11      1   0             0  is_stmt
+
+
+0x00000e84: 00 DW_LNE_set_address (0x0000000000001274)
+0x00000e8b: 05 DW_LNS_set_column (16)
+0x00000e8d: 06 DW_LNS_negate_stmt
+0x00000e8e: 01 DW_LNS_copy
+            0x0000000000001274    141     16      1   0             0 
+
+
+0x00000e8f: 00 DW_LNE_set_address (0x000000000000128a)
+0x00000e96: 05 DW_LNS_set_column (4)
+0x00000e98: 01 DW_LNS_copy
+            0x000000000000128a    141      4      1   0             0 
+
+
+0x00000e99: 00 DW_LNE_set_address (0x000000000000129f)
+0x00000ea0: 03 DW_LNS_advance_line (142)
+0x00000ea2: 05 DW_LNS_set_column (36)
+0x00000ea4: 06 DW_LNS_negate_stmt
+0x00000ea5: 01 DW_LNS_copy
+            0x000000000000129f    142     36      1   0             0  is_stmt
+
+
+0x00000ea6: 00 DW_LNE_set_address (0x00000000000012a7)
+0x00000ead: 05 DW_LNS_set_column (20)
+0x00000eaf: 06 DW_LNS_negate_stmt
+0x00000eb0: 01 DW_LNS_copy
+            0x00000000000012a7    142     20      1   0             0 
+
+
+0x00000eb1: 00 DW_LNE_set_address (0x00000000000012af)
+0x00000eb8: 05 DW_LNS_set_column (13)
+0x00000eba: 01 DW_LNS_copy
+            0x00000000000012af    142     13      1   0             0 
+
+
+0x00000ebb: 00 DW_LNE_set_address (0x00000000000012b7)
+0x00000ec2: 03 DW_LNS_advance_line (143)
+0x00000ec4: 05 DW_LNS_set_column (11)
+0x00000ec6: 06 DW_LNS_negate_stmt
+0x00000ec7: 01 DW_LNS_copy
+            0x00000000000012b7    143     11      1   0             0  is_stmt
+
+
+0x00000ec8: 00 DW_LNE_set_address (0x00000000000012bf)
+0x00000ecf: 05 DW_LNS_set_column (22)
+0x00000ed1: 06 DW_LNS_negate_stmt
+0x00000ed2: 01 DW_LNS_copy
+            0x00000000000012bf    143     22      1   0             0 
+
+
+0x00000ed3: 00 DW_LNE_set_address (0x00000000000012c7)
+0x00000eda: 05 DW_LNS_set_column (20)
+0x00000edc: 01 DW_LNS_copy
+            0x00000000000012c7    143     20      1   0             0 
+
+
+0x00000edd: 00 DW_LNE_set_address (0x00000000000012dd)
+0x00000ee4: 05 DW_LNS_set_column (11)
+0x00000ee6: 01 DW_LNS_copy
+            0x00000000000012dd    143     11      1   0             0 
+
+
+0x00000ee7: 00 DW_LNE_set_address (0x00000000000012f4)
+0x00000eee: 03 DW_LNS_advance_line (144)
+0x00000ef0: 05 DW_LNS_set_column (21)
+0x00000ef2: 06 DW_LNS_negate_stmt
+0x00000ef3: 01 DW_LNS_copy
+            0x00000000000012f4    144     21      1   0             0  is_stmt
+
+
+0x00000ef4: 00 DW_LNE_set_address (0x00000000000012fc)
+0x00000efb: 05 DW_LNS_set_column (19)
+0x00000efd: 06 DW_LNS_negate_stmt
+0x00000efe: 01 DW_LNS_copy
+            0x00000000000012fc    144     19      1   0             0 
+
+
+0x00000eff: 00 DW_LNE_set_address (0x0000000000001305)
+0x00000f06: 03 DW_LNS_advance_line (145)
+0x00000f08: 05 DW_LNS_set_column (15)
+0x00000f0a: 06 DW_LNS_negate_stmt
+0x00000f0b: 01 DW_LNS_copy
+            0x0000000000001305    145     15      1   0             0  is_stmt
+
+
+0x00000f0c: 00 DW_LNE_set_address (0x000000000000130d)
+0x00000f13: 05 DW_LNS_set_column (13)
+0x00000f15: 06 DW_LNS_negate_stmt
+0x00000f16: 01 DW_LNS_copy
+            0x000000000000130d    145     13      1   0             0 
+
+
+0x00000f17: 00 DW_LNE_set_address (0x0000000000001315)
+0x00000f1e: 03 DW_LNS_advance_line (146)
+0x00000f20: 05 DW_LNS_set_column (14)
+0x00000f22: 06 DW_LNS_negate_stmt
+0x00000f23: 01 DW_LNS_copy
+            0x0000000000001315    146     14      1   0             0  is_stmt
+
+
+0x00000f24: 00 DW_LNE_set_address (0x000000000000131d)
+0x00000f2b: 05 DW_LNS_set_column (20)
+0x00000f2d: 06 DW_LNS_negate_stmt
+0x00000f2e: 01 DW_LNS_copy
+            0x000000000000131d    146     20      1   0             0 
+
+
+0x00000f2f: 00 DW_LNE_set_address (0x0000000000001326)
+0x00000f36: 05 DW_LNS_set_column (12)
+0x00000f38: 01 DW_LNS_copy
+            0x0000000000001326    146     12      1   0             0 
+
+
+0x00000f39: 00 DW_LNE_set_address (0x000000000000132e)
+0x00000f40: 03 DW_LNS_advance_line (147)
+0x00000f42: 06 DW_LNS_negate_stmt
+0x00000f43: 01 DW_LNS_copy
+            0x000000000000132e    147     12      1   0             0  is_stmt
+
+
+0x00000f44: 00 DW_LNE_set_address (0x0000000000001336)
+0x00000f4b: 05 DW_LNS_set_column (7)
+0x00000f4d: 06 DW_LNS_negate_stmt
+0x00000f4e: 01 DW_LNS_copy
+            0x0000000000001336    147      7      1   0             0 
+
+
+0x00000f4f: 00 DW_LNE_set_address (0x000000000000133b)
+0x00000f56: 03 DW_LNS_advance_line (141)
+0x00000f58: 05 DW_LNS_set_column (4)
+0x00000f5a: 06 DW_LNS_negate_stmt
+0x00000f5b: 01 DW_LNS_copy
+            0x000000000000133b    141      4      1   0             0  is_stmt
+
+
+0x00000f5c: 00 DW_LNE_set_address (0x0000000000001340)
+0x00000f63: 03 DW_LNS_advance_line (149)
+0x00000f65: 05 DW_LNS_set_column (11)
+0x00000f67: 01 DW_LNS_copy
+            0x0000000000001340    149     11      1   0             0  is_stmt
+
+
+0x00000f68: 00 DW_LNE_set_address (0x0000000000001348)
+0x00000f6f: 05 DW_LNS_set_column (4)
+0x00000f71: 06 DW_LNS_negate_stmt
+0x00000f72: 01 DW_LNS_copy
+            0x0000000000001348    149      4      1   0             0 
+
+
+0x00000f73: 00 DW_LNE_set_address (0x0000000000001360)
+0x00000f7a: 00 DW_LNE_end_sequence
+            0x0000000000001360    149      4      1   0             0  end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 11.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 2d7a8cf90478cd845ffb39763b0e95b7715322d2)"
+0x00000095: "tests/fannkuch.cpp"
+0x000000a8: "/home/alon/Dev/emscripten"
+0x000000c2: "i"
+0x000000c4: "int"
+0x000000c8: "n"
+0x000000ca: "next"
+0x000000cf: "worker_args"
+0x000000db: "std"
+0x000000df: "decltype(nullptr)"
+0x000000f1: "nullptr_t"
+0x000000fb: "_Z15fannkuch_workerPv"
+0x00000111: "fannkuch_worker"
+0x00000121: "main"
+0x00000126: "_ZL8fannkuchi"
+0x00000134: "fannkuch"
+0x0000013d: "_arg"
+0x00000142: "args"
+0x00000147: "perm1"
+0x0000014d: "count"
+0x00000153: "perm"
+0x00000158: "maxflips"
+0x00000161: "flips"
+0x00000167: "r"
+0x00000169: "j"
+0x0000016b: "k"
+0x0000016d: "tmp"
+0x00000171: "p0"
+0x00000174: "argc"
+0x00000179: "argv"
+0x0000017e: "char"
+0x00000183: "targs"
+0x00000189: "showmax"
+0x00000191: "cleanup"
+
+.debug_ranges contents:
+00000000 00000006 00000a53
+00000000 00000a55 00000bc5
+00000000 00000bc7 00001360
+00000000 <End of list>
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_none (func))
+ (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" "malloc" (func $malloc (param i32) (result i32)))
+ (import "env" "free" (func $free (param i32)))
+ (import "env" "atoi" (func $atoi (param i32) (result i32)))
+ (import "env" "printf" (func $printf (param i32 i32) (result i32)))
+ (global $global$0 (mut i32) (i32.const 5243952))
+ (global $global$1 i32 (i32.const 1069))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__data_end" (global $global$1))
+ (func $__wasm_call_ctors
+ )
+ (func $fannkuch_worker\28void*\29 (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (local $19 i32)
+  (local $20 i32)
+  (local $21 i32)
+  (local $22 i32)
+  (local $23 i32)
+  (local $24 i32)
+  (local $25 i32)
+  (local $26 i32)
+  (local $27 i32)
+  (local $28 i32)
+  (local $29 i32)
+  (local $30 i32)
+  (local $31 i32)
+  (local $32 i32)
+  (local $33 i32)
+  (local $34 i32)
+  (local $35 i32)
+  (local $36 i32)
+  (local $37 i32)
+  (local $38 i32)
+  (local $39 i32)
+  (local $40 i32)
+  (local $41 i32)
+  (local $42 i32)
+  (local $43 i32)
+  (local $44 i32)
+  (local $45 i32)
+  (local $46 i32)
+  (local $47 i32)
+  (local $48 i32)
+  (local $49 i32)
+  (local $50 i32)
+  (local $51 i32)
+  (local $52 i32)
+  (local $53 i32)
+  (local $54 i32)
+  (local $55 i32)
+  (local $56 i32)
+  (local $57 i32)
+  (local $58 i32)
+  (local $59 i32)
+  (local $60 i32)
+  (local $61 i32)
+  (local $62 i32)
+  (local $63 i32)
+  (local $64 i32)
+  (local $65 i32)
+  (local $66 i32)
+  (local $67 i32)
+  (local $68 i32)
+  (local $69 i32)
+  (local $70 i32)
+  (local $71 i32)
+  (local $72 i32)
+  (local $73 i32)
+  (local $74 i32)
+  (local $75 i32)
+  (local $76 i32)
+  (local $77 i32)
+  (local $78 i32)
+  (local $79 i32)
+  (local $80 i32)
+  (local $81 i32)
+  (local $82 i32)
+  (local $83 i32)
+  (local $84 i32)
+  (local $85 i32)
+  (local $86 i32)
+  (local $87 i32)
+  (local $88 i32)
+  (local $89 i32)
+  (local $90 i32)
+  (local $91 i32)
+  (local $92 i32)
+  (local $93 i32)
+  (local $94 i32)
+  (local $95 i32)
+  (local $96 i32)
+  (local $97 i32)
+  (local $98 i32)
+  (local $99 i32)
+  (local $100 i32)
+  (local $101 i32)
+  (local $102 i32)
+  (local $103 i32)
+  (local $104 i32)
+  (local $105 i32)
+  (local $106 i32)
+  (local $107 i32)
+  (local $108 i32)
+  (local $109 i32)
+  (local $110 i32)
+  (local $111 i32)
+  (local $112 i32)
+  (local $113 i32)
+  (local $114 i32)
+  (local $115 i32)
+  (local $116 i32)
+  (local $117 i32)
+  (local $118 i32)
+  (local $119 i32)
+  (local $120 i32)
+  (local $121 i32)
+  (local $122 i32)
+  (local $123 i32)
+  (local $124 i32)
+  (local $125 i32)
+  (local $126 i32)
+  (local $127 i32)
+  (local $128 i32)
+  (local $129 i32)
+  (local $130 i32)
+  (local $131 i32)
+  (local $132 i32)
+  (local $133 i32)
+  (local $134 i32)
+  (local $135 i32)
+  (local $136 i32)
+  (local $137 i32)
+  (local $138 i32)
+  (local $139 i32)
+  (local $140 i32)
+  (local $141 i32)
+  (local $142 i32)
+  (local $143 i32)
+  (local $144 i32)
+  (local $145 i32)
+  (local $146 i32)
+  (local $147 i32)
+  (local $148 i32)
+  (local $149 i32)
+  (local $150 i32)
+  (local $151 i32)
+  (local $152 i32)
+  (local $153 i32)
+  (local $154 i32)
+  (local $155 i32)
+  (local $156 i32)
+  (local $157 i32)
+  (local $158 i32)
+  (local $159 i32)
+  (local $160 i32)
+  (local $161 i32)
+  (local $162 i32)
+  (local $163 i32)
+  (local $164 i32)
+  (local $165 i32)
+  (local $166 i32)
+  (local $167 i32)
+  (local $168 i32)
+  (local $169 i32)
+  (local $170 i32)
+  (local $171 i32)
+  (local $172 i32)
+  (local $173 i32)
+  (local $174 i32)
+  (local $175 i32)
+  (local $176 i32)
+  (local $177 i32)
+  (local $178 i32)
+  (local $179 i32)
+  (local $180 i32)
+  (local $181 i32)
+  (local $182 i32)
+  (local $183 i32)
+  (local $184 i32)
+  (local $185 i32)
+  (local $186 i32)
+  (local $187 i32)
+  (local $188 i32)
+  (local $189 i32)
+  (local $190 i32)
+  (local $191 i32)
+  (local $192 i32)
+  (local $193 i32)
+  (local $194 i32)
+  (local $195 i32)
+  (local $196 i32)
+  (local $197 i32)
+  (local $198 i32)
+  (local $199 i32)
+  (local $200 i32)
+  (local $201 i32)
+  (local $202 i32)
+  (local $203 i32)
+  (local $204 i32)
+  (local $205 i32)
+  (local $206 i32)
+  (local $207 i32)
+  (local $208 i32)
+  (local $209 i32)
+  (local $210 i32)
+  (local $211 i32)
+  (local $212 i32)
+  (local $213 i32)
+  (local $214 i32)
+  (local $215 i32)
+  (local $216 i32)
+  (local $217 i32)
+  (local $218 i32)
+  (local $219 i32)
+  (local $220 i32)
+  (local $221 i32)
+  (local $222 i32)
+  (local $223 i32)
+  (local $224 i32)
+  (local $225 i32)
+  (local $226 i32)
+  (local $227 i32)
+  (local $228 i32)
+  (local $229 i32)
+  (local $230 i32)
+  (local $231 i32)
+  (local $232 i32)
+  (local $233 i32)
+  (local $234 i32)
+  (local $235 i32)
+  (local $236 i32)
+  (local $237 i32)
+  (local $238 i32)
+  (local $239 i32)
+  (local $240 i32)
+  (local $241 i32)
+  (local $242 i32)
+  (local $243 i32)
+  (local $244 i32)
+  ;; code offset: 0x1f2
+  (local.set $1
+   ;; code offset: 0x1f0
+   (global.get $global$0)
+  )
+  ;; code offset: 0x1f7
+  (local.set $2
+   ;; code offset: 0x1f4
+   (i32.const 64)
+  )
+  ;; code offset: 0x1fe
+  (local.set $3
+   ;; code offset: 0x1fd
+   (i32.sub
+    ;; code offset: 0x1f9
+    (local.get $1)
+    ;; code offset: 0x1fb
+    (local.get $2)
+   )
+  )
+  ;; code offset: 0x202
+  (global.set $global$0
+   ;; code offset: 0x200
+   (local.get $3)
+  )
+  ;; code offset: 0x206
+  (local.set $4
+   ;; code offset: 0x204
+   (i32.const 0)
+  )
+  ;; code offset: 0x20c
+  (i32.store offset=60
+   ;; code offset: 0x208
+   (local.get $3)
+   ;; code offset: 0x20a
+   (local.get $0)
+  )
+  ;; code offset: 0x214
+  (local.set $5
+   ;; code offset: 0x211
+   (i32.load offset=60
+    ;; code offset: 0x20f
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x21a
+  (i32.store offset=56
+   ;; code offset: 0x216
+   (local.get $3)
+   ;; code offset: 0x218
+   (local.get $5)
+  )
+  ;; code offset: 0x221
+  (i32.store offset=40
+   ;; code offset: 0x21d
+   (local.get $3)
+   ;; code offset: 0x21f
+   (local.get $4)
+  )
+  ;; code offset: 0x229
+  (local.set $6
+   ;; code offset: 0x226
+   (i32.load offset=56
+    ;; code offset: 0x224
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x230
+  (local.set $7
+   ;; code offset: 0x22d
+   (i32.load offset=4
+    ;; code offset: 0x22b
+    (local.get $6)
+   )
+  )
+  ;; code offset: 0x236
+  (i32.store offset=28
+   ;; code offset: 0x232
+   (local.get $3)
+   ;; code offset: 0x234
+   (local.get $7)
+  )
+  ;; code offset: 0x23e
+  (local.set $8
+   ;; code offset: 0x23b
+   (i32.load offset=28
+    ;; code offset: 0x239
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x242
+  (local.set $9
+   ;; code offset: 0x240
+   (i32.const 2)
+  )
+  ;; code offset: 0x249
+  (local.set $10
+   ;; code offset: 0x248
+   (i32.shl
+    ;; code offset: 0x244
+    (local.get $8)
+    ;; code offset: 0x246
+    (local.get $9)
+   )
+  )
+  ;; code offset: 0x24f
+  (local.set $11
+   ;; code offset: 0x24d
+   (call $malloc
+    ;; code offset: 0x24b
+    (local.get $10)
+   )
+  )
+  ;; code offset: 0x255
+  (i32.store offset=52
+   ;; code offset: 0x251
+   (local.get $3)
+   ;; code offset: 0x253
+   (local.get $11)
+  )
+  ;; code offset: 0x25d
+  (local.set $12
+   ;; code offset: 0x25a
+   (i32.load offset=28
+    ;; code offset: 0x258
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x261
+  (local.set $13
+   ;; code offset: 0x25f
+   (i32.const 2)
+  )
+  ;; code offset: 0x268
+  (local.set $14
+   ;; code offset: 0x267
+   (i32.shl
+    ;; code offset: 0x263
+    (local.get $12)
+    ;; code offset: 0x265
+    (local.get $13)
+   )
+  )
+  ;; code offset: 0x26e
+  (local.set $15
+   ;; code offset: 0x26c
+   (call $malloc
+    ;; code offset: 0x26a
+    (local.get $14)
+   )
+  )
+  ;; code offset: 0x274
+  (i32.store offset=44
+   ;; code offset: 0x270
+   (local.get $3)
+   ;; code offset: 0x272
+   (local.get $15)
+  )
+  ;; code offset: 0x27c
+  (local.set $16
+   ;; code offset: 0x279
+   (i32.load offset=28
+    ;; code offset: 0x277
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x280
+  (local.set $17
+   ;; code offset: 0x27e
+   (i32.const 2)
+  )
+  ;; code offset: 0x287
+  (local.set $18
+   ;; code offset: 0x286
+   (i32.shl
+    ;; code offset: 0x282
+    (local.get $16)
+    ;; code offset: 0x284
+    (local.get $17)
+   )
+  )
+  ;; code offset: 0x28d
+  (local.set $19
+   ;; code offset: 0x28b
+   (call $malloc
+    ;; code offset: 0x289
+    (local.get $18)
+   )
+  )
+  ;; code offset: 0x293
+  (i32.store offset=48
+   ;; code offset: 0x28f
+   (local.get $3)
+   ;; code offset: 0x291
+   (local.get $19)
+  )
+  ;; code offset: 0x29a
+  (i32.store offset=32
+   ;; code offset: 0x296
+   (local.get $3)
+   ;; code offset: 0x298
+   (local.get $4)
+  )
+  ;; code offset: 0x29d
+  (block $label$1
+   ;; code offset: 0x29f
+   (loop $label$2
+    ;; code offset: 0x2a6
+    (local.set $20
+     ;; code offset: 0x2a3
+     (i32.load offset=32
+      ;; code offset: 0x2a1
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x2ad
+    (local.set $21
+     ;; code offset: 0x2aa
+     (i32.load offset=28
+      ;; code offset: 0x2a8
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x2b1
+    (local.set $22
+     ;; code offset: 0x2af
+     (local.get $20)
+    )
+    ;; code offset: 0x2b5
+    (local.set $23
+     ;; code offset: 0x2b3
+     (local.get $21)
+    )
+    ;; code offset: 0x2bc
+    (local.set $24
+     ;; code offset: 0x2bb
+     (i32.lt_s
+      ;; code offset: 0x2b7
+      (local.get $22)
+      ;; code offset: 0x2b9
+      (local.get $23)
+     )
+    )
+    ;; code offset: 0x2c0
+    (local.set $25
+     ;; code offset: 0x2be
+     (i32.const 1)
+    )
+    ;; code offset: 0x2c7
+    (local.set $26
+     ;; code offset: 0x2c6
+     (i32.and
+      ;; code offset: 0x2c2
+      (local.get $24)
+      ;; code offset: 0x2c4
+      (local.get $25)
+     )
+    )
+    ;; code offset: 0x2cc
+    (br_if $label$1
+     ;; code offset: 0x2cb
+     (i32.eqz
+      ;; code offset: 0x2c9
+      (local.get $26)
+     )
+    )
+    ;; code offset: 0x2d3
+    (local.set $27
+     ;; code offset: 0x2d0
+     (i32.load offset=32
+      ;; code offset: 0x2ce
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x2da
+    (local.set $28
+     ;; code offset: 0x2d7
+     (i32.load offset=52
+      ;; code offset: 0x2d5
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x2e1
+    (local.set $29
+     ;; code offset: 0x2de
+     (i32.load offset=32
+      ;; code offset: 0x2dc
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x2e5
+    (local.set $30
+     ;; code offset: 0x2e3
+     (i32.const 2)
+    )
+    ;; code offset: 0x2ec
+    (local.set $31
+     ;; code offset: 0x2eb
+     (i32.shl
+      ;; code offset: 0x2e7
+      (local.get $29)
+      ;; code offset: 0x2e9
+      (local.get $30)
+     )
+    )
+    ;; code offset: 0x2f3
+    (local.set $32
+     ;; code offset: 0x2f2
+     (i32.add
+      ;; code offset: 0x2ee
+      (local.get $28)
+      ;; code offset: 0x2f0
+      (local.get $31)
+     )
+    )
+    ;; code offset: 0x2f9
+    (i32.store
+     ;; code offset: 0x2f5
+     (local.get $32)
+     ;; code offset: 0x2f7
+     (local.get $27)
+    )
+    ;; code offset: 0x301
+    (local.set $33
+     ;; code offset: 0x2fe
+     (i32.load offset=32
+      ;; code offset: 0x2fc
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x305
+    (local.set $34
+     ;; code offset: 0x303
+     (i32.const 1)
+    )
+    ;; code offset: 0x30c
+    (local.set $35
+     ;; code offset: 0x30b
+     (i32.add
+      ;; code offset: 0x307
+      (local.get $33)
+      ;; code offset: 0x309
+      (local.get $34)
+     )
+    )
+    ;; code offset: 0x312
+    (i32.store offset=32
+     ;; code offset: 0x30e
+     (local.get $3)
+     ;; code offset: 0x310
+     (local.get $35)
+    )
+    ;; code offset: 0x315
+    (br $label$2)
+   )
+  )
+  ;; code offset: 0x31f
+  (local.set $36
+   ;; code offset: 0x31c
+   (i32.load offset=28
+    ;; code offset: 0x31a
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x323
+  (local.set $37
+   ;; code offset: 0x321
+   (i32.const 1)
+  )
+  ;; code offset: 0x32a
+  (local.set $38
+   ;; code offset: 0x329
+   (i32.sub
+    ;; code offset: 0x325
+    (local.get $36)
+    ;; code offset: 0x327
+    (local.get $37)
+   )
+  )
+  ;; code offset: 0x331
+  (local.set $39
+   ;; code offset: 0x32e
+   (i32.load offset=52
+    ;; code offset: 0x32c
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x338
+  (local.set $40
+   ;; code offset: 0x335
+   (i32.load offset=56
+    ;; code offset: 0x333
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x33f
+  (local.set $41
+   ;; code offset: 0x33c
+   (i32.load
+    ;; code offset: 0x33a
+    (local.get $40)
+   )
+  )
+  ;; code offset: 0x343
+  (local.set $42
+   ;; code offset: 0x341
+   (i32.const 2)
+  )
+  ;; code offset: 0x34a
+  (local.set $43
+   ;; code offset: 0x349
+   (i32.shl
+    ;; code offset: 0x345
+    (local.get $41)
+    ;; code offset: 0x347
+    (local.get $42)
+   )
+  )
+  ;; code offset: 0x351
+  (local.set $44
+   ;; code offset: 0x350
+   (i32.add
+    ;; code offset: 0x34c
+    (local.get $39)
+    ;; code offset: 0x34e
+    (local.get $43)
+   )
+  )
+  ;; code offset: 0x357
+  (i32.store
+   ;; code offset: 0x353
+   (local.get $44)
+   ;; code offset: 0x355
+   (local.get $38)
+  )
+  ;; code offset: 0x35f
+  (local.set $45
+   ;; code offset: 0x35c
+   (i32.load offset=56
+    ;; code offset: 0x35a
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x366
+  (local.set $46
+   ;; code offset: 0x363
+   (i32.load
+    ;; code offset: 0x361
+    (local.get $45)
+   )
+  )
+  ;; code offset: 0x36d
+  (local.set $47
+   ;; code offset: 0x36a
+   (i32.load offset=52
+    ;; code offset: 0x368
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x374
+  (local.set $48
+   ;; code offset: 0x371
+   (i32.load offset=28
+    ;; code offset: 0x36f
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x378
+  (local.set $49
+   ;; code offset: 0x376
+   (i32.const 1)
+  )
+  ;; code offset: 0x37f
+  (local.set $50
+   ;; code offset: 0x37e
+   (i32.sub
+    ;; code offset: 0x37a
+    (local.get $48)
+    ;; code offset: 0x37c
+    (local.get $49)
+   )
+  )
+  ;; code offset: 0x383
+  (local.set $51
+   ;; code offset: 0x381
+   (i32.const 2)
+  )
+  ;; code offset: 0x38a
+  (local.set $52
+   ;; code offset: 0x389
+   (i32.shl
+    ;; code offset: 0x385
+    (local.get $50)
+    ;; code offset: 0x387
+    (local.get $51)
+   )
+  )
+  ;; code offset: 0x391
+  (local.set $53
+   ;; code offset: 0x390
+   (i32.add
+    ;; code offset: 0x38c
+    (local.get $47)
+    ;; code offset: 0x38e
+    (local.get $52)
+   )
+  )
+  ;; code offset: 0x397
+  (i32.store
+   ;; code offset: 0x393
+   (local.get $53)
+   ;; code offset: 0x395
+   (local.get $46)
+  )
+  ;; code offset: 0x39f
+  (local.set $54
+   ;; code offset: 0x39c
+   (i32.load offset=28
+    ;; code offset: 0x39a
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x3a5
+  (i32.store offset=24
+   ;; code offset: 0x3a1
+   (local.get $3)
+   ;; code offset: 0x3a3
+   (local.get $54)
+  )
+  ;; code offset: 0x3a8
+  (loop $label$3 (result i32)
+   ;; code offset: 0x3aa
+   (block $label$4
+    ;; code offset: 0x3ac
+    (loop $label$5
+     ;; code offset: 0x3b0
+     (local.set $55
+      ;; code offset: 0x3ae
+      (i32.const 1)
+     )
+     ;; code offset: 0x3b7
+     (local.set $56
+      ;; code offset: 0x3b4
+      (i32.load offset=24
+       ;; code offset: 0x3b2
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x3bb
+     (local.set $57
+      ;; code offset: 0x3b9
+      (local.get $56)
+     )
+     ;; code offset: 0x3bf
+     (local.set $58
+      ;; code offset: 0x3bd
+      (local.get $55)
+     )
+     ;; code offset: 0x3c6
+     (local.set $59
+      ;; code offset: 0x3c5
+      (i32.gt_s
+       ;; code offset: 0x3c1
+       (local.get $57)
+       ;; code offset: 0x3c3
+       (local.get $58)
+      )
+     )
+     ;; code offset: 0x3ca
+     (local.set $60
+      ;; code offset: 0x3c8
+      (i32.const 1)
+     )
+     ;; code offset: 0x3d1
+     (local.set $61
+      ;; code offset: 0x3d0
+      (i32.and
+       ;; code offset: 0x3cc
+       (local.get $59)
+       ;; code offset: 0x3ce
+       (local.get $60)
+      )
+     )
+     ;; code offset: 0x3d6
+     (br_if $label$4
+      ;; code offset: 0x3d5
+      (i32.eqz
+       ;; code offset: 0x3d3
+       (local.get $61)
+      )
+     )
+     ;; code offset: 0x3dd
+     (local.set $62
+      ;; code offset: 0x3da
+      (i32.load offset=24
+       ;; code offset: 0x3d8
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x3e4
+     (local.set $63
+      ;; code offset: 0x3e1
+      (i32.load offset=48
+       ;; code offset: 0x3df
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x3eb
+     (local.set $64
+      ;; code offset: 0x3e8
+      (i32.load offset=24
+       ;; code offset: 0x3e6
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x3ef
+     (local.set $65
+      ;; code offset: 0x3ed
+      (i32.const 1)
+     )
+     ;; code offset: 0x3f6
+     (local.set $66
+      ;; code offset: 0x3f5
+      (i32.sub
+       ;; code offset: 0x3f1
+       (local.get $64)
+       ;; code offset: 0x3f3
+       (local.get $65)
+      )
+     )
+     ;; code offset: 0x3fa
+     (local.set $67
+      ;; code offset: 0x3f8
+      (i32.const 2)
+     )
+     ;; code offset: 0x401
+     (local.set $68
+      ;; code offset: 0x400
+      (i32.shl
+       ;; code offset: 0x3fc
+       (local.get $66)
+       ;; code offset: 0x3fe
+       (local.get $67)
+      )
+     )
+     ;; code offset: 0x408
+     (local.set $69
+      ;; code offset: 0x407
+      (i32.add
+       ;; code offset: 0x403
+       (local.get $63)
+       ;; code offset: 0x405
+       (local.get $68)
+      )
+     )
+     ;; code offset: 0x40e
+     (i32.store
+      ;; code offset: 0x40a
+      (local.get $69)
+      ;; code offset: 0x40c
+      (local.get $62)
+     )
+     ;; code offset: 0x416
+     (local.set $70
+      ;; code offset: 0x413
+      (i32.load offset=24
+       ;; code offset: 0x411
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x41a
+     (local.set $71
+      ;; code offset: 0x418
+      (i32.const -1)
+     )
+     ;; code offset: 0x421
+     (local.set $72
+      ;; code offset: 0x420
+      (i32.add
+       ;; code offset: 0x41c
+       (local.get $70)
+       ;; code offset: 0x41e
+       (local.get $71)
+      )
+     )
+     ;; code offset: 0x427
+     (i32.store offset=24
+      ;; code offset: 0x423
+      (local.get $3)
+      ;; code offset: 0x425
+      (local.get $72)
+     )
+     ;; code offset: 0x42a
+     (br $label$5)
+    )
+   )
+   ;; code offset: 0x434
+   (local.set $73
+    ;; code offset: 0x431
+    (i32.load offset=52
+     ;; code offset: 0x42f
+     (local.get $3)
+    )
+   )
+   ;; code offset: 0x43b
+   (local.set $74
+    ;; code offset: 0x438
+    (i32.load
+     ;; code offset: 0x436
+     (local.get $73)
+    )
+   )
+   ;; code offset: 0x43d
+   (block $label$6
+    ;; code offset: 0x442
+    (br_if $label$6
+     ;; code offset: 0x441
+     (i32.eqz
+      ;; code offset: 0x43f
+      (local.get $74)
+     )
+    )
+    ;; code offset: 0x449
+    (local.set $75
+     ;; code offset: 0x446
+     (i32.load offset=52
+      ;; code offset: 0x444
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x450
+    (local.set $76
+     ;; code offset: 0x44d
+     (i32.load offset=28
+      ;; code offset: 0x44b
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x454
+    (local.set $77
+     ;; code offset: 0x452
+     (i32.const 1)
+    )
+    ;; code offset: 0x45b
+    (local.set $78
+     ;; code offset: 0x45a
+     (i32.sub
+      ;; code offset: 0x456
+      (local.get $76)
+      ;; code offset: 0x458
+      (local.get $77)
+     )
+    )
+    ;; code offset: 0x45f
+    (local.set $79
+     ;; code offset: 0x45d
+     (i32.const 2)
+    )
+    ;; code offset: 0x466
+    (local.set $80
+     ;; code offset: 0x465
+     (i32.shl
+      ;; code offset: 0x461
+      (local.get $78)
+      ;; code offset: 0x463
+      (local.get $79)
+     )
+    )
+    ;; code offset: 0x46d
+    (local.set $81
+     ;; code offset: 0x46c
+     (i32.add
+      ;; code offset: 0x468
+      (local.get $75)
+      ;; code offset: 0x46a
+      (local.get $80)
+     )
+    )
+    ;; code offset: 0x474
+    (local.set $82
+     ;; code offset: 0x471
+     (i32.load
+      ;; code offset: 0x46f
+      (local.get $81)
+     )
+    )
+    ;; code offset: 0x47b
+    (local.set $83
+     ;; code offset: 0x478
+     (i32.load offset=28
+      ;; code offset: 0x476
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x47f
+    (local.set $84
+     ;; code offset: 0x47d
+     (i32.const 1)
+    )
+    ;; code offset: 0x486
+    (local.set $85
+     ;; code offset: 0x485
+     (i32.sub
+      ;; code offset: 0x481
+      (local.get $83)
+      ;; code offset: 0x483
+      (local.get $84)
+     )
+    )
+    ;; code offset: 0x48a
+    (local.set $86
+     ;; code offset: 0x488
+     (local.get $82)
+    )
+    ;; code offset: 0x48e
+    (local.set $87
+     ;; code offset: 0x48c
+     (local.get $85)
+    )
+    ;; code offset: 0x495
+    (local.set $88
+     ;; code offset: 0x494
+     (i32.ne
+      ;; code offset: 0x490
+      (local.get $86)
+      ;; code offset: 0x492
+      (local.get $87)
+     )
+    )
+    ;; code offset: 0x499
+    (local.set $89
+     ;; code offset: 0x497
+     (i32.const 1)
+    )
+    ;; code offset: 0x4a0
+    (local.set $90
+     ;; code offset: 0x49f
+     (i32.and
+      ;; code offset: 0x49b
+      (local.get $88)
+      ;; code offset: 0x49d
+      (local.get $89)
+     )
+    )
+    ;; code offset: 0x4a5
+    (br_if $label$6
+     ;; code offset: 0x4a4
+     (i32.eqz
+      ;; code offset: 0x4a2
+      (local.get $90)
+     )
+    )
+    ;; code offset: 0x4a9
+    (local.set $91
+     ;; code offset: 0x4a7
+     (i32.const 0)
+    )
+    ;; code offset: 0x4af
+    (i32.store offset=32
+     ;; code offset: 0x4ab
+     (local.get $3)
+     ;; code offset: 0x4ad
+     (local.get $91)
+    )
+    ;; code offset: 0x4b2
+    (block $label$7
+     ;; code offset: 0x4b4
+     (loop $label$8
+      ;; code offset: 0x4bb
+      (local.set $92
+       ;; code offset: 0x4b8
+       (i32.load offset=32
+        ;; code offset: 0x4b6
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x4c2
+      (local.set $93
+       ;; code offset: 0x4bf
+       (i32.load offset=28
+        ;; code offset: 0x4bd
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x4c6
+      (local.set $94
+       ;; code offset: 0x4c4
+       (local.get $92)
+      )
+      ;; code offset: 0x4ca
+      (local.set $95
+       ;; code offset: 0x4c8
+       (local.get $93)
+      )
+      ;; code offset: 0x4d1
+      (local.set $96
+       ;; code offset: 0x4d0
+       (i32.lt_s
+        ;; code offset: 0x4cc
+        (local.get $94)
+        ;; code offset: 0x4ce
+        (local.get $95)
+       )
+      )
+      ;; code offset: 0x4d5
+      (local.set $97
+       ;; code offset: 0x4d3
+       (i32.const 1)
+      )
+      ;; code offset: 0x4dc
+      (local.set $98
+       ;; code offset: 0x4db
+       (i32.and
+        ;; code offset: 0x4d7
+        (local.get $96)
+        ;; code offset: 0x4d9
+        (local.get $97)
+       )
+      )
+      ;; code offset: 0x4e1
+      (br_if $label$7
+       ;; code offset: 0x4e0
+       (i32.eqz
+        ;; code offset: 0x4de
+        (local.get $98)
+       )
+      )
+      ;; code offset: 0x4e8
+      (local.set $99
+       ;; code offset: 0x4e5
+       (i32.load offset=52
+        ;; code offset: 0x4e3
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x4ef
+      (local.set $100
+       ;; code offset: 0x4ec
+       (i32.load offset=32
+        ;; code offset: 0x4ea
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x4f3
+      (local.set $101
+       ;; code offset: 0x4f1
+       (i32.const 2)
+      )
+      ;; code offset: 0x4fa
+      (local.set $102
+       ;; code offset: 0x4f9
+       (i32.shl
+        ;; code offset: 0x4f5
+        (local.get $100)
+        ;; code offset: 0x4f7
+        (local.get $101)
+       )
+      )
+      ;; code offset: 0x501
+      (local.set $103
+       ;; code offset: 0x500
+       (i32.add
+        ;; code offset: 0x4fc
+        (local.get $99)
+        ;; code offset: 0x4fe
+        (local.get $102)
+       )
+      )
+      ;; code offset: 0x508
+      (local.set $104
+       ;; code offset: 0x505
+       (i32.load
+        ;; code offset: 0x503
+        (local.get $103)
+       )
+      )
+      ;; code offset: 0x50f
+      (local.set $105
+       ;; code offset: 0x50c
+       (i32.load offset=44
+        ;; code offset: 0x50a
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x516
+      (local.set $106
+       ;; code offset: 0x513
+       (i32.load offset=32
+        ;; code offset: 0x511
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x51a
+      (local.set $107
+       ;; code offset: 0x518
+       (i32.const 2)
+      )
+      ;; code offset: 0x521
+      (local.set $108
+       ;; code offset: 0x520
+       (i32.shl
+        ;; code offset: 0x51c
+        (local.get $106)
+        ;; code offset: 0x51e
+        (local.get $107)
+       )
+      )
+      ;; code offset: 0x528
+      (local.set $109
+       ;; code offset: 0x527
+       (i32.add
+        ;; code offset: 0x523
+        (local.get $105)
+        ;; code offset: 0x525
+        (local.get $108)
+       )
+      )
+      ;; code offset: 0x52e
+      (i32.store
+       ;; code offset: 0x52a
+       (local.get $109)
+       ;; code offset: 0x52c
+       (local.get $104)
+      )
+      ;; code offset: 0x536
+      (local.set $110
+       ;; code offset: 0x533
+       (i32.load offset=32
+        ;; code offset: 0x531
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x53a
+      (local.set $111
+       ;; code offset: 0x538
+       (i32.const 1)
+      )
+      ;; code offset: 0x541
+      (local.set $112
+       ;; code offset: 0x540
+       (i32.add
+        ;; code offset: 0x53c
+        (local.get $110)
+        ;; code offset: 0x53e
+        (local.get $111)
+       )
+      )
+      ;; code offset: 0x547
+      (i32.store offset=32
+       ;; code offset: 0x543
+       (local.get $3)
+       ;; code offset: 0x545
+       (local.get $112)
+      )
+      ;; code offset: 0x54a
+      (br $label$8)
+     )
+    )
+    ;; code offset: 0x551
+    (local.set $113
+     ;; code offset: 0x54f
+     (i32.const 0)
+    )
+    ;; code offset: 0x557
+    (i32.store offset=36
+     ;; code offset: 0x553
+     (local.get $3)
+     ;; code offset: 0x555
+     (local.get $113)
+    )
+    ;; code offset: 0x55f
+    (local.set $114
+     ;; code offset: 0x55c
+     (i32.load offset=44
+      ;; code offset: 0x55a
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x566
+    (local.set $115
+     ;; code offset: 0x563
+     (i32.load
+      ;; code offset: 0x561
+      (local.get $114)
+     )
+    )
+    ;; code offset: 0x56c
+    (i32.store offset=16
+     ;; code offset: 0x568
+     (local.get $3)
+     ;; code offset: 0x56a
+     (local.get $115)
+    )
+    ;; code offset: 0x56f
+    (loop $label$9
+     ;; code offset: 0x573
+     (local.set $116
+      ;; code offset: 0x571
+      (i32.const 1)
+     )
+     ;; code offset: 0x579
+     (i32.store offset=32
+      ;; code offset: 0x575
+      (local.get $3)
+      ;; code offset: 0x577
+      (local.get $116)
+     )
+     ;; code offset: 0x581
+     (local.set $117
+      ;; code offset: 0x57e
+      (i32.load offset=16
+       ;; code offset: 0x57c
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x585
+     (local.set $118
+      ;; code offset: 0x583
+      (i32.const 1)
+     )
+     ;; code offset: 0x58c
+     (local.set $119
+      ;; code offset: 0x58b
+      (i32.sub
+       ;; code offset: 0x587
+       (local.get $117)
+       ;; code offset: 0x589
+       (local.get $118)
+      )
+     )
+     ;; code offset: 0x592
+     (i32.store offset=20
+      ;; code offset: 0x58e
+      (local.get $3)
+      ;; code offset: 0x590
+      (local.get $119)
+     )
+     ;; code offset: 0x595
+     (block $label$10
+      ;; code offset: 0x597
+      (loop $label$11
+       ;; code offset: 0x59e
+       (local.set $120
+        ;; code offset: 0x59b
+        (i32.load offset=32
+         ;; code offset: 0x599
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x5a5
+       (local.set $121
+        ;; code offset: 0x5a2
+        (i32.load offset=20
+         ;; code offset: 0x5a0
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x5a9
+       (local.set $122
+        ;; code offset: 0x5a7
+        (local.get $120)
+       )
+       ;; code offset: 0x5ad
+       (local.set $123
+        ;; code offset: 0x5ab
+        (local.get $121)
+       )
+       ;; code offset: 0x5b4
+       (local.set $124
+        ;; code offset: 0x5b3
+        (i32.lt_s
+         ;; code offset: 0x5af
+         (local.get $122)
+         ;; code offset: 0x5b1
+         (local.get $123)
+        )
+       )
+       ;; code offset: 0x5b8
+       (local.set $125
+        ;; code offset: 0x5b6
+        (i32.const 1)
+       )
+       ;; code offset: 0x5bf
+       (local.set $126
+        ;; code offset: 0x5be
+        (i32.and
+         ;; code offset: 0x5ba
+         (local.get $124)
+         ;; code offset: 0x5bc
+         (local.get $125)
+        )
+       )
+       ;; code offset: 0x5c4
+       (br_if $label$10
+        ;; code offset: 0x5c3
+        (i32.eqz
+         ;; code offset: 0x5c1
+         (local.get $126)
+        )
+       )
+       ;; code offset: 0x5cb
+       (local.set $127
+        ;; code offset: 0x5c8
+        (i32.load offset=44
+         ;; code offset: 0x5c6
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x5d2
+       (local.set $128
+        ;; code offset: 0x5cf
+        (i32.load offset=32
+         ;; code offset: 0x5cd
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x5d7
+       (local.set $129
+        ;; code offset: 0x5d5
+        (i32.const 2)
+       )
+       ;; code offset: 0x5e1
+       (local.set $130
+        ;; code offset: 0x5e0
+        (i32.shl
+         ;; code offset: 0x5da
+         (local.get $128)
+         ;; code offset: 0x5dd
+         (local.get $129)
+        )
+       )
+       ;; code offset: 0x5ea
+       (local.set $131
+        ;; code offset: 0x5e9
+        (i32.add
+         ;; code offset: 0x5e4
+         (local.get $127)
+         ;; code offset: 0x5e6
+         (local.get $130)
+        )
+       )
+       ;; code offset: 0x5f3
+       (local.set $132
+        ;; code offset: 0x5f0
+        (i32.load
+         ;; code offset: 0x5ed
+         (local.get $131)
+        )
+       )
+       ;; code offset: 0x5fb
+       (i32.store offset=12
+        ;; code offset: 0x5f6
+        (local.get $3)
+        ;; code offset: 0x5f8
+        (local.get $132)
+       )
+       ;; code offset: 0x603
+       (local.set $133
+        ;; code offset: 0x600
+        (i32.load offset=44
+         ;; code offset: 0x5fe
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x60b
+       (local.set $134
+        ;; code offset: 0x608
+        (i32.load offset=20
+         ;; code offset: 0x606
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x610
+       (local.set $135
+        ;; code offset: 0x60e
+        (i32.const 2)
+       )
+       ;; code offset: 0x61a
+       (local.set $136
+        ;; code offset: 0x619
+        (i32.shl
+         ;; code offset: 0x613
+         (local.get $134)
+         ;; code offset: 0x616
+         (local.get $135)
+        )
+       )
+       ;; code offset: 0x624
+       (local.set $137
+        ;; code offset: 0x623
+        (i32.add
+         ;; code offset: 0x61d
+         (local.get $133)
+         ;; code offset: 0x620
+         (local.get $136)
+        )
+       )
+       ;; code offset: 0x62d
+       (local.set $138
+        ;; code offset: 0x62a
+        (i32.load
+         ;; code offset: 0x627
+         (local.get $137)
+        )
+       )
+       ;; code offset: 0x635
+       (local.set $139
+        ;; code offset: 0x632
+        (i32.load offset=44
+         ;; code offset: 0x630
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x63d
+       (local.set $140
+        ;; code offset: 0x63a
+        (i32.load offset=32
+         ;; code offset: 0x638
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x642
+       (local.set $141
+        ;; code offset: 0x640
+        (i32.const 2)
+       )
+       ;; code offset: 0x64c
+       (local.set $142
+        ;; code offset: 0x64b
+        (i32.shl
+         ;; code offset: 0x645
+         (local.get $140)
+         ;; code offset: 0x648
+         (local.get $141)
+        )
+       )
+       ;; code offset: 0x656
+       (local.set $143
+        ;; code offset: 0x655
+        (i32.add
+         ;; code offset: 0x64f
+         (local.get $139)
+         ;; code offset: 0x652
+         (local.get $142)
+        )
+       )
+       ;; code offset: 0x65f
+       (i32.store
+        ;; code offset: 0x659
+        (local.get $143)
+        ;; code offset: 0x65c
+        (local.get $138)
+       )
+       ;; code offset: 0x667
+       (local.set $144
+        ;; code offset: 0x664
+        (i32.load offset=12
+         ;; code offset: 0x662
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x66f
+       (local.set $145
+        ;; code offset: 0x66c
+        (i32.load offset=44
+         ;; code offset: 0x66a
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x677
+       (local.set $146
+        ;; code offset: 0x674
+        (i32.load offset=20
+         ;; code offset: 0x672
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x67c
+       (local.set $147
+        ;; code offset: 0x67a
+        (i32.const 2)
+       )
+       ;; code offset: 0x686
+       (local.set $148
+        ;; code offset: 0x685
+        (i32.shl
+         ;; code offset: 0x67f
+         (local.get $146)
+         ;; code offset: 0x682
+         (local.get $147)
+        )
+       )
+       ;; code offset: 0x690
+       (local.set $149
+        ;; code offset: 0x68f
+        (i32.add
+         ;; code offset: 0x689
+         (local.get $145)
+         ;; code offset: 0x68c
+         (local.get $148)
+        )
+       )
+       ;; code offset: 0x699
+       (i32.store
+        ;; code offset: 0x693
+        (local.get $149)
+        ;; code offset: 0x696
+        (local.get $144)
+       )
+       ;; code offset: 0x6a1
+       (local.set $150
+        ;; code offset: 0x69e
+        (i32.load offset=32
+         ;; code offset: 0x69c
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x6a6
+       (local.set $151
+        ;; code offset: 0x6a4
+        (i32.const 1)
+       )
+       ;; code offset: 0x6b0
+       (local.set $152
+        ;; code offset: 0x6af
+        (i32.add
+         ;; code offset: 0x6a9
+         (local.get $150)
+         ;; code offset: 0x6ac
+         (local.get $151)
+        )
+       )
+       ;; code offset: 0x6b8
+       (i32.store offset=32
+        ;; code offset: 0x6b3
+        (local.get $3)
+        ;; code offset: 0x6b5
+        (local.get $152)
+       )
+       ;; code offset: 0x6c0
+       (local.set $153
+        ;; code offset: 0x6bd
+        (i32.load offset=20
+         ;; code offset: 0x6bb
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x6c5
+       (local.set $154
+        ;; code offset: 0x6c3
+        (i32.const -1)
+       )
+       ;; code offset: 0x6cf
+       (local.set $155
+        ;; code offset: 0x6ce
+        (i32.add
+         ;; code offset: 0x6c8
+         (local.get $153)
+         ;; code offset: 0x6cb
+         (local.get $154)
+        )
+       )
+       ;; code offset: 0x6d7
+       (i32.store offset=20
+        ;; code offset: 0x6d2
+        (local.get $3)
+        ;; code offset: 0x6d4
+        (local.get $155)
+       )
+       ;; code offset: 0x6da
+       (br $label$11)
+      )
+     )
+     ;; code offset: 0x6e4
+     (local.set $156
+      ;; code offset: 0x6e1
+      (i32.load offset=36
+       ;; code offset: 0x6df
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x6e9
+     (local.set $157
+      ;; code offset: 0x6e7
+      (i32.const 1)
+     )
+     ;; code offset: 0x6f3
+     (local.set $158
+      ;; code offset: 0x6f2
+      (i32.add
+       ;; code offset: 0x6ec
+       (local.get $156)
+       ;; code offset: 0x6ef
+       (local.get $157)
+      )
+     )
+     ;; code offset: 0x6fb
+     (i32.store offset=36
+      ;; code offset: 0x6f6
+      (local.get $3)
+      ;; code offset: 0x6f8
+      (local.get $158)
+     )
+     ;; code offset: 0x703
+     (local.set $159
+      ;; code offset: 0x700
+      (i32.load offset=44
+       ;; code offset: 0x6fe
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x70b
+     (local.set $160
+      ;; code offset: 0x708
+      (i32.load offset=16
+       ;; code offset: 0x706
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x710
+     (local.set $161
+      ;; code offset: 0x70e
+      (i32.const 2)
+     )
+     ;; code offset: 0x71a
+     (local.set $162
+      ;; code offset: 0x719
+      (i32.shl
+       ;; code offset: 0x713
+       (local.get $160)
+       ;; code offset: 0x716
+       (local.get $161)
+      )
+     )
+     ;; code offset: 0x724
+     (local.set $163
+      ;; code offset: 0x723
+      (i32.add
+       ;; code offset: 0x71d
+       (local.get $159)
+       ;; code offset: 0x720
+       (local.get $162)
+      )
+     )
+     ;; code offset: 0x72d
+     (local.set $164
+      ;; code offset: 0x72a
+      (i32.load
+       ;; code offset: 0x727
+       (local.get $163)
+      )
+     )
+     ;; code offset: 0x735
+     (i32.store offset=12
+      ;; code offset: 0x730
+      (local.get $3)
+      ;; code offset: 0x732
+      (local.get $164)
+     )
+     ;; code offset: 0x73d
+     (local.set $165
+      ;; code offset: 0x73a
+      (i32.load offset=16
+       ;; code offset: 0x738
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x745
+     (local.set $166
+      ;; code offset: 0x742
+      (i32.load offset=44
+       ;; code offset: 0x740
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x74d
+     (local.set $167
+      ;; code offset: 0x74a
+      (i32.load offset=16
+       ;; code offset: 0x748
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x752
+     (local.set $168
+      ;; code offset: 0x750
+      (i32.const 2)
+     )
+     ;; code offset: 0x75c
+     (local.set $169
+      ;; code offset: 0x75b
+      (i32.shl
+       ;; code offset: 0x755
+       (local.get $167)
+       ;; code offset: 0x758
+       (local.get $168)
+      )
+     )
+     ;; code offset: 0x766
+     (local.set $170
+      ;; code offset: 0x765
+      (i32.add
+       ;; code offset: 0x75f
+       (local.get $166)
+       ;; code offset: 0x762
+       (local.get $169)
+      )
+     )
+     ;; code offset: 0x76f
+     (i32.store
+      ;; code offset: 0x769
+      (local.get $170)
+      ;; code offset: 0x76c
+      (local.get $165)
+     )
+     ;; code offset: 0x777
+     (local.set $171
+      ;; code offset: 0x774
+      (i32.load offset=12
+       ;; code offset: 0x772
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x77f
+     (i32.store offset=16
+      ;; code offset: 0x77a
+      (local.get $3)
+      ;; code offset: 0x77c
+      (local.get $171)
+     )
+     ;; code offset: 0x787
+     (local.set $172
+      ;; code offset: 0x784
+      (i32.load offset=16
+       ;; code offset: 0x782
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x78d
+     (br_if $label$9
+      ;; code offset: 0x78a
+      (local.get $172)
+     )
+    )
+    ;; code offset: 0x795
+    (local.set $173
+     ;; code offset: 0x792
+     (i32.load offset=40
+      ;; code offset: 0x790
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x79d
+    (local.set $174
+     ;; code offset: 0x79a
+     (i32.load offset=36
+      ;; code offset: 0x798
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x7a3
+    (local.set $175
+     ;; code offset: 0x7a0
+     (local.get $173)
+    )
+    ;; code offset: 0x7a9
+    (local.set $176
+     ;; code offset: 0x7a6
+     (local.get $174)
+    )
+    ;; code offset: 0x7b3
+    (local.set $177
+     ;; code offset: 0x7b2
+     (i32.lt_s
+      ;; code offset: 0x7ac
+      (local.get $175)
+      ;; code offset: 0x7af
+      (local.get $176)
+     )
+    )
+    ;; code offset: 0x7b8
+    (local.set $178
+     ;; code offset: 0x7b6
+     (i32.const 1)
+    )
+    ;; code offset: 0x7c2
+    (local.set $179
+     ;; code offset: 0x7c1
+     (i32.and
+      ;; code offset: 0x7bb
+      (local.get $177)
+      ;; code offset: 0x7be
+      (local.get $178)
+     )
+    )
+    ;; code offset: 0x7c5
+    (block $label$12
+     ;; code offset: 0x7cb
+     (br_if $label$12
+      ;; code offset: 0x7ca
+      (i32.eqz
+       ;; code offset: 0x7c7
+       (local.get $179)
+      )
+     )
+     ;; code offset: 0x7d2
+     (local.set $180
+      ;; code offset: 0x7cf
+      (i32.load offset=36
+       ;; code offset: 0x7cd
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x7da
+     (i32.store offset=40
+      ;; code offset: 0x7d5
+      (local.get $3)
+      ;; code offset: 0x7d7
+      (local.get $180)
+     )
+    )
+   )
+   ;; code offset: 0x7df
+   (loop $label$13
+    ;; code offset: 0x7e6
+    (local.set $181
+     ;; code offset: 0x7e3
+     (i32.load offset=24
+      ;; code offset: 0x7e1
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x7ee
+    (local.set $182
+     ;; code offset: 0x7eb
+     (i32.load offset=28
+      ;; code offset: 0x7e9
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x7f3
+    (local.set $183
+     ;; code offset: 0x7f1
+     (i32.const 1)
+    )
+    ;; code offset: 0x7fd
+    (local.set $184
+     ;; code offset: 0x7fc
+     (i32.sub
+      ;; code offset: 0x7f6
+      (local.get $182)
+      ;; code offset: 0x7f9
+      (local.get $183)
+     )
+    )
+    ;; code offset: 0x803
+    (local.set $185
+     ;; code offset: 0x800
+     (local.get $181)
+    )
+    ;; code offset: 0x809
+    (local.set $186
+     ;; code offset: 0x806
+     (local.get $184)
+    )
+    ;; code offset: 0x813
+    (local.set $187
+     ;; code offset: 0x812
+     (i32.ge_s
+      ;; code offset: 0x80c
+      (local.get $185)
+      ;; code offset: 0x80f
+      (local.get $186)
+     )
+    )
+    ;; code offset: 0x818
+    (local.set $188
+     ;; code offset: 0x816
+     (i32.const 1)
+    )
+    ;; code offset: 0x822
+    (local.set $189
+     ;; code offset: 0x821
+     (i32.and
+      ;; code offset: 0x81b
+      (local.get $187)
+      ;; code offset: 0x81e
+      (local.get $188)
+     )
+    )
+    ;; code offset: 0x825
+    (block $label$14
+     ;; code offset: 0x82b
+     (br_if $label$14
+      ;; code offset: 0x82a
+      (i32.eqz
+       ;; code offset: 0x827
+       (local.get $189)
+      )
+     )
+     ;; code offset: 0x832
+     (local.set $190
+      ;; code offset: 0x82f
+      (i32.load offset=52
+       ;; code offset: 0x82d
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x838
+     (call $free
+      ;; code offset: 0x835
+      (local.get $190)
+     )
+     ;; code offset: 0x83f
+     (local.set $191
+      ;; code offset: 0x83c
+      (i32.load offset=44
+       ;; code offset: 0x83a
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x845
+     (call $free
+      ;; code offset: 0x842
+      (local.get $191)
+     )
+     ;; code offset: 0x84c
+     (local.set $192
+      ;; code offset: 0x849
+      (i32.load offset=48
+       ;; code offset: 0x847
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x852
+     (call $free
+      ;; code offset: 0x84f
+      (local.get $192)
+     )
+     ;; code offset: 0x859
+     (local.set $193
+      ;; code offset: 0x856
+      (i32.load offset=40
+       ;; code offset: 0x854
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x85f
+     (local.set $194
+      ;; code offset: 0x85c
+      (i32.const 64)
+     )
+     ;; code offset: 0x868
+     (local.set $195
+      ;; code offset: 0x867
+      (i32.add
+       ;; code offset: 0x862
+       (local.get $3)
+       ;; code offset: 0x864
+       (local.get $194)
+      )
+     )
+     ;; code offset: 0x86e
+     (global.set $global$0
+      ;; code offset: 0x86b
+      (local.get $195)
+     )
+     ;; code offset: 0x873
+     (return
+      ;; code offset: 0x870
+      (local.get $193)
+     )
+    )
+    ;; code offset: 0x877
+    (local.set $196
+     ;; code offset: 0x875
+     (i32.const 0)
+    )
+    ;; code offset: 0x87f
+    (local.set $197
+     ;; code offset: 0x87c
+     (i32.load offset=52
+      ;; code offset: 0x87a
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x888
+    (local.set $198
+     ;; code offset: 0x885
+     (i32.load
+      ;; code offset: 0x882
+      (local.get $197)
+     )
+    )
+    ;; code offset: 0x890
+    (i32.store offset=8
+     ;; code offset: 0x88b
+     (local.get $3)
+     ;; code offset: 0x88d
+     (local.get $198)
+    )
+    ;; code offset: 0x898
+    (i32.store offset=32
+     ;; code offset: 0x893
+     (local.get $3)
+     ;; code offset: 0x895
+     (local.get $196)
+    )
+    ;; code offset: 0x89b
+    (block $label$15
+     ;; code offset: 0x89d
+     (loop $label$16
+      ;; code offset: 0x8a4
+      (local.set $199
+       ;; code offset: 0x8a1
+       (i32.load offset=32
+        ;; code offset: 0x89f
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x8ac
+      (local.set $200
+       ;; code offset: 0x8a9
+       (i32.load offset=24
+        ;; code offset: 0x8a7
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x8b2
+      (local.set $201
+       ;; code offset: 0x8af
+       (local.get $199)
+      )
+      ;; code offset: 0x8b8
+      (local.set $202
+       ;; code offset: 0x8b5
+       (local.get $200)
+      )
+      ;; code offset: 0x8c2
+      (local.set $203
+       ;; code offset: 0x8c1
+       (i32.lt_s
+        ;; code offset: 0x8bb
+        (local.get $201)
+        ;; code offset: 0x8be
+        (local.get $202)
+       )
+      )
+      ;; code offset: 0x8c7
+      (local.set $204
+       ;; code offset: 0x8c5
+       (i32.const 1)
+      )
+      ;; code offset: 0x8d1
+      (local.set $205
+       ;; code offset: 0x8d0
+       (i32.and
+        ;; code offset: 0x8ca
+        (local.get $203)
+        ;; code offset: 0x8cd
+        (local.get $204)
+       )
+      )
+      ;; code offset: 0x8d8
+      (br_if $label$15
+       ;; code offset: 0x8d7
+       (i32.eqz
+        ;; code offset: 0x8d4
+        (local.get $205)
+       )
+      )
+      ;; code offset: 0x8df
+      (local.set $206
+       ;; code offset: 0x8dc
+       (i32.load offset=52
+        ;; code offset: 0x8da
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x8e7
+      (local.set $207
+       ;; code offset: 0x8e4
+       (i32.load offset=32
+        ;; code offset: 0x8e2
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x8ec
+      (local.set $208
+       ;; code offset: 0x8ea
+       (i32.const 1)
+      )
+      ;; code offset: 0x8f6
+      (local.set $209
+       ;; code offset: 0x8f5
+       (i32.add
+        ;; code offset: 0x8ef
+        (local.get $207)
+        ;; code offset: 0x8f2
+        (local.get $208)
+       )
+      )
+      ;; code offset: 0x8fb
+      (local.set $210
+       ;; code offset: 0x8f9
+       (i32.const 2)
+      )
+      ;; code offset: 0x905
+      (local.set $211
+       ;; code offset: 0x904
+       (i32.shl
+        ;; code offset: 0x8fe
+        (local.get $209)
+        ;; code offset: 0x901
+        (local.get $210)
+       )
+      )
+      ;; code offset: 0x90f
+      (local.set $212
+       ;; code offset: 0x90e
+       (i32.add
+        ;; code offset: 0x908
+        (local.get $206)
+        ;; code offset: 0x90b
+        (local.get $211)
+       )
+      )
+      ;; code offset: 0x918
+      (local.set $213
+       ;; code offset: 0x915
+       (i32.load
+        ;; code offset: 0x912
+        (local.get $212)
+       )
+      )
+      ;; code offset: 0x920
+      (local.set $214
+       ;; code offset: 0x91d
+       (i32.load offset=52
+        ;; code offset: 0x91b
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x928
+      (local.set $215
+       ;; code offset: 0x925
+       (i32.load offset=32
+        ;; code offset: 0x923
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x92d
+      (local.set $216
+       ;; code offset: 0x92b
+       (i32.const 2)
+      )
+      ;; code offset: 0x937
+      (local.set $217
+       ;; code offset: 0x936
+       (i32.shl
+        ;; code offset: 0x930
+        (local.get $215)
+        ;; code offset: 0x933
+        (local.get $216)
+       )
+      )
+      ;; code offset: 0x941
+      (local.set $218
+       ;; code offset: 0x940
+       (i32.add
+        ;; code offset: 0x93a
+        (local.get $214)
+        ;; code offset: 0x93d
+        (local.get $217)
+       )
+      )
+      ;; code offset: 0x94a
+      (i32.store
+       ;; code offset: 0x944
+       (local.get $218)
+       ;; code offset: 0x947
+       (local.get $213)
+      )
+      ;; code offset: 0x952
+      (local.set $219
+       ;; code offset: 0x94f
+       (i32.load offset=32
+        ;; code offset: 0x94d
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x957
+      (local.set $220
+       ;; code offset: 0x955
+       (i32.const 1)
+      )
+      ;; code offset: 0x961
+      (local.set $221
+       ;; code offset: 0x960
+       (i32.add
+        ;; code offset: 0x95a
+        (local.get $219)
+        ;; code offset: 0x95d
+        (local.get $220)
+       )
+      )
+      ;; code offset: 0x969
+      (i32.store offset=32
+       ;; code offset: 0x964
+       (local.get $3)
+       ;; code offset: 0x966
+       (local.get $221)
+      )
+      ;; code offset: 0x96c
+      (br $label$16)
+     )
+    )
+    ;; code offset: 0x973
+    (local.set $222
+     ;; code offset: 0x971
+     (i32.const 0)
+    )
+    ;; code offset: 0x97b
+    (local.set $223
+     ;; code offset: 0x978
+     (i32.load offset=8
+      ;; code offset: 0x976
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x983
+    (local.set $224
+     ;; code offset: 0x980
+     (i32.load offset=52
+      ;; code offset: 0x97e
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x98b
+    (local.set $225
+     ;; code offset: 0x988
+     (i32.load offset=32
+      ;; code offset: 0x986
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x990
+    (local.set $226
+     ;; code offset: 0x98e
+     (i32.const 2)
+    )
+    ;; code offset: 0x99a
+    (local.set $227
+     ;; code offset: 0x999
+     (i32.shl
+      ;; code offset: 0x993
+      (local.get $225)
+      ;; code offset: 0x996
+      (local.get $226)
+     )
+    )
+    ;; code offset: 0x9a4
+    (local.set $228
+     ;; code offset: 0x9a3
+     (i32.add
+      ;; code offset: 0x99d
+      (local.get $224)
+      ;; code offset: 0x9a0
+      (local.get $227)
+     )
+    )
+    ;; code offset: 0x9ad
+    (i32.store
+     ;; code offset: 0x9a7
+     (local.get $228)
+     ;; code offset: 0x9aa
+     (local.get $223)
+    )
+    ;; code offset: 0x9b5
+    (local.set $229
+     ;; code offset: 0x9b2
+     (i32.load offset=48
+      ;; code offset: 0x9b0
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x9bd
+    (local.set $230
+     ;; code offset: 0x9ba
+     (i32.load offset=24
+      ;; code offset: 0x9b8
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x9c2
+    (local.set $231
+     ;; code offset: 0x9c0
+     (i32.const 2)
+    )
+    ;; code offset: 0x9cc
+    (local.set $232
+     ;; code offset: 0x9cb
+     (i32.shl
+      ;; code offset: 0x9c5
+      (local.get $230)
+      ;; code offset: 0x9c8
+      (local.get $231)
+     )
+    )
+    ;; code offset: 0x9d6
+    (local.set $233
+     ;; code offset: 0x9d5
+     (i32.add
+      ;; code offset: 0x9cf
+      (local.get $229)
+      ;; code offset: 0x9d2
+      (local.get $232)
+     )
+    )
+    ;; code offset: 0x9df
+    (local.set $234
+     ;; code offset: 0x9dc
+     (i32.load
+      ;; code offset: 0x9d9
+      (local.get $233)
+     )
+    )
+    ;; code offset: 0x9e4
+    (local.set $235
+     ;; code offset: 0x9e2
+     (i32.const -1)
+    )
+    ;; code offset: 0x9ee
+    (local.set $236
+     ;; code offset: 0x9ed
+     (i32.add
+      ;; code offset: 0x9e7
+      (local.get $234)
+      ;; code offset: 0x9ea
+      (local.get $235)
+     )
+    )
+    ;; code offset: 0x9f7
+    (i32.store
+     ;; code offset: 0x9f1
+     (local.get $233)
+     ;; code offset: 0x9f4
+     (local.get $236)
+    )
+    ;; code offset: 0x9fd
+    (local.set $237
+     ;; code offset: 0x9fa
+     (local.get $236)
+    )
+    ;; code offset: 0xa03
+    (local.set $238
+     ;; code offset: 0xa00
+     (local.get $222)
+    )
+    ;; code offset: 0xa0d
+    (local.set $239
+     ;; code offset: 0xa0c
+     (i32.gt_s
+      ;; code offset: 0xa06
+      (local.get $237)
+      ;; code offset: 0xa09
+      (local.get $238)
+     )
+    )
+    ;; code offset: 0xa12
+    (local.set $240
+     ;; code offset: 0xa10
+     (i32.const 1)
+    )
+    ;; code offset: 0xa1c
+    (local.set $241
+     ;; code offset: 0xa1b
+     (i32.and
+      ;; code offset: 0xa15
+      (local.get $239)
+      ;; code offset: 0xa18
+      (local.get $240)
+     )
+    )
+    ;; code offset: 0xa1f
+    (block $label$17
+     (block $label$18
+      ;; code offset: 0xa27
+      (br_if $label$18
+       ;; code offset: 0xa26
+       (i32.eqz
+        ;; code offset: 0xa23
+        (local.get $241)
+       )
+      )
+      ;; code offset: 0xa29
+      (br $label$17)
+     )
+     ;; code offset: 0xa31
+     (local.set $242
+      ;; code offset: 0xa2e
+      (i32.load offset=24
+       ;; code offset: 0xa2c
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0xa36
+     (local.set $243
+      ;; code offset: 0xa34
+      (i32.const 1)
+     )
+     ;; code offset: 0xa40
+     (local.set $244
+      ;; code offset: 0xa3f
+      (i32.add
+       ;; code offset: 0xa39
+       (local.get $242)
+       ;; code offset: 0xa3c
+       (local.get $243)
+      )
+     )
+     ;; code offset: 0xa48
+     (i32.store offset=24
+      ;; code offset: 0xa43
+      (local.get $3)
+      ;; code offset: 0xa45
+      (local.get $244)
+     )
+     ;; code offset: 0xa4b
+     (br $label$13)
+    )
+   )
+   ;; code offset: 0xa4f
+   (br $label$3)
+  )
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (local $19 i32)
+  (local $20 i32)
+  (local $21 i32)
+  (local $22 i32)
+  (local $23 i32)
+  (local $24 i32)
+  (local $25 i32)
+  (local $26 i32)
+  (local $27 i32)
+  (local $28 i32)
+  (local $29 i32)
+  (local $30 i32)
+  (local $31 i32)
+  (local $32 i32)
+  (local $33 i32)
+  (local $34 i32)
+  (local $35 i32)
+  (local $36 i32)
+  ;; code offset: 0xa9e
+  (local.set $2
+   ;; code offset: 0xa9c
+   (global.get $global$0)
+  )
+  ;; code offset: 0xaa2
+  (local.set $3
+   ;; code offset: 0xaa0
+   (i32.const 32)
+  )
+  ;; code offset: 0xaa9
+  (local.set $4
+   ;; code offset: 0xaa8
+   (i32.sub
+    ;; code offset: 0xaa4
+    (local.get $2)
+    ;; code offset: 0xaa6
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0xaad
+  (global.set $global$0
+   ;; code offset: 0xaab
+   (local.get $4)
+  )
+  ;; code offset: 0xab1
+  (local.set $5
+   ;; code offset: 0xaaf
+   (i32.const 1)
+  )
+  ;; code offset: 0xab5
+  (local.set $6
+   ;; code offset: 0xab3
+   (i32.const 0)
+  )
+  ;; code offset: 0xabb
+  (i32.store offset=28
+   ;; code offset: 0xab7
+   (local.get $4)
+   ;; code offset: 0xab9
+   (local.get $6)
+  )
+  ;; code offset: 0xac2
+  (i32.store offset=24
+   ;; code offset: 0xabe
+   (local.get $4)
+   ;; code offset: 0xac0
+   (local.get $0)
+  )
+  ;; code offset: 0xac9
+  (i32.store offset=20
+   ;; code offset: 0xac5
+   (local.get $4)
+   ;; code offset: 0xac7
+   (local.get $1)
+  )
+  ;; code offset: 0xad1
+  (local.set $7
+   ;; code offset: 0xace
+   (i32.load offset=24
+    ;; code offset: 0xacc
+    (local.get $4)
+   )
+  )
+  ;; code offset: 0xad5
+  (local.set $8
+   ;; code offset: 0xad3
+   (local.get $7)
+  )
+  ;; code offset: 0xad9
+  (local.set $9
+   ;; code offset: 0xad7
+   (local.get $5)
+  )
+  ;; code offset: 0xae0
+  (local.set $10
+   ;; code offset: 0xadf
+   (i32.gt_s
+    ;; code offset: 0xadb
+    (local.get $8)
+    ;; code offset: 0xadd
+    (local.get $9)
+   )
+  )
+  ;; code offset: 0xae4
+  (local.set $11
+   ;; code offset: 0xae2
+   (i32.const 1)
+  )
+  ;; code offset: 0xaeb
+  (local.set $12
+   ;; code offset: 0xaea
+   (i32.and
+    ;; code offset: 0xae6
+    (local.get $10)
+    ;; code offset: 0xae8
+    (local.get $11)
+   )
+  )
+  ;; code offset: 0xaed
+  (block $label$1
+   (block $label$2
+    ;; code offset: 0xaf4
+    (br_if $label$2
+     ;; code offset: 0xaf3
+     (i32.eqz
+      ;; code offset: 0xaf1
+      (local.get $12)
+     )
+    )
+    ;; code offset: 0xafb
+    (local.set $13
+     ;; code offset: 0xaf8
+     (i32.load offset=20
+      ;; code offset: 0xaf6
+      (local.get $4)
+     )
+    )
+    ;; code offset: 0xb02
+    (local.set $14
+     ;; code offset: 0xaff
+     (i32.load offset=4
+      ;; code offset: 0xafd
+      (local.get $13)
+     )
+    )
+    ;; code offset: 0xb08
+    (local.set $15
+     ;; code offset: 0xb06
+     (call $atoi
+      ;; code offset: 0xb04
+      (local.get $14)
+     )
+    )
+    ;; code offset: 0xb0c
+    (local.set $16
+     ;; code offset: 0xb0a
+     (local.get $15)
+    )
+    ;; code offset: 0xb0e
+    (br $label$1)
+   )
+   ;; code offset: 0xb13
+   (local.set $17
+    ;; code offset: 0xb11
+    (i32.const 0)
+   )
+   ;; code offset: 0xb17
+   (local.set $16
+    ;; code offset: 0xb15
+    (local.get $17)
+   )
+  )
+  ;; code offset: 0xb1c
+  (local.set $18
+   ;; code offset: 0xb1a
+   (local.get $16)
+  )
+  ;; code offset: 0xb20
+  (local.set $19
+   ;; code offset: 0xb1e
+   (i32.const 1)
+  )
+  ;; code offset: 0xb26
+  (i32.store offset=16
+   ;; code offset: 0xb22
+   (local.get $4)
+   ;; code offset: 0xb24
+   (local.get $18)
+  )
+  ;; code offset: 0xb2e
+  (local.set $20
+   ;; code offset: 0xb2b
+   (i32.load offset=16
+    ;; code offset: 0xb29
+    (local.get $4)
+   )
+  )
+  ;; code offset: 0xb32
+  (local.set $21
+   ;; code offset: 0xb30
+   (local.get $20)
+  )
+  ;; code offset: 0xb36
+  (local.set $22
+   ;; code offset: 0xb34
+   (local.get $19)
+  )
+  ;; code offset: 0xb3d
+  (local.set $23
+   ;; code offset: 0xb3c
+   (i32.lt_s
+    ;; code offset: 0xb38
+    (local.get $21)
+    ;; code offset: 0xb3a
+    (local.get $22)
+   )
+  )
+  ;; code offset: 0xb41
+  (local.set $24
+   ;; code offset: 0xb3f
+   (i32.const 1)
+  )
+  ;; code offset: 0xb48
+  (local.set $25
+   ;; code offset: 0xb47
+   (i32.and
+    ;; code offset: 0xb43
+    (local.get $23)
+    ;; code offset: 0xb45
+    (local.get $24)
+   )
+  )
+  ;; code offset: 0xb4a
+  (block $label$3
+   (block $label$4
+    ;; code offset: 0xb51
+    (br_if $label$4
+     ;; code offset: 0xb50
+     (i32.eqz
+      ;; code offset: 0xb4e
+      (local.get $25)
+     )
+    )
+    ;; code offset: 0xb56
+    (local.set $26
+     ;; code offset: 0xb53
+     (i32.const 1024)
+    )
+    ;; code offset: 0xb5a
+    (local.set $27
+     ;; code offset: 0xb58
+     (i32.const 0)
+    )
+    ;; code offset: 0xb62
+    (drop
+     ;; code offset: 0xb60
+     (call $printf
+      ;; code offset: 0xb5c
+      (local.get $26)
+      ;; code offset: 0xb5e
+      (local.get $27)
+     )
+    )
+    ;; code offset: 0xb65
+    (local.set $28
+     ;; code offset: 0xb63
+     (i32.const 1)
+    )
+    ;; code offset: 0xb6b
+    (i32.store offset=28
+     ;; code offset: 0xb67
+     (local.get $4)
+     ;; code offset: 0xb69
+     (local.get $28)
+    )
+    ;; code offset: 0xb6e
+    (br $label$3)
+   )
+   ;; code offset: 0xb76
+   (local.set $29
+    ;; code offset: 0xb73
+    (i32.load offset=16
+     ;; code offset: 0xb71
+     (local.get $4)
+    )
+   )
+   ;; code offset: 0xb7d
+   (local.set $30
+    ;; code offset: 0xb7a
+    (i32.load offset=16
+     ;; code offset: 0xb78
+     (local.get $4)
+    )
+   )
+   ;; code offset: 0xb83
+   (local.set $31
+    ;; code offset: 0xb81
+    (call $fannkuch\28int\29
+     ;; code offset: 0xb7f
+     (local.get $30)
+    )
+   )
+   ;; code offset: 0xb89
+   (i32.store offset=4
+    ;; code offset: 0xb85
+    (local.get $4)
+    ;; code offset: 0xb87
+    (local.get $31)
+   )
+   ;; code offset: 0xb90
+   (i32.store
+    ;; code offset: 0xb8c
+    (local.get $4)
+    ;; code offset: 0xb8e
+    (local.get $29)
+   )
+   ;; code offset: 0xb96
+   (local.set $32
+    ;; code offset: 0xb93
+    (i32.const 1041)
+   )
+   ;; code offset: 0xb9e
+   (drop
+    ;; code offset: 0xb9c
+    (call $printf
+     ;; code offset: 0xb98
+     (local.get $32)
+     ;; code offset: 0xb9a
+     (local.get $4)
+    )
+   )
+   ;; code offset: 0xba1
+   (local.set $33
+    ;; code offset: 0xb9f
+    (i32.const 0)
+   )
+   ;; code offset: 0xba7
+   (i32.store offset=28
+    ;; code offset: 0xba3
+    (local.get $4)
+    ;; code offset: 0xba5
+    (local.get $33)
+   )
+  )
+  ;; code offset: 0xbb0
+  (local.set $34
+   ;; code offset: 0xbad
+   (i32.load offset=28
+    ;; code offset: 0xbab
+    (local.get $4)
+   )
+  )
+  ;; code offset: 0xbb4
+  (local.set $35
+   ;; code offset: 0xbb2
+   (i32.const 32)
+  )
+  ;; code offset: 0xbbb
+  (local.set $36
+   ;; code offset: 0xbba
+   (i32.add
+    ;; code offset: 0xbb6
+    (local.get $4)
+    ;; code offset: 0xbb8
+    (local.get $35)
+   )
+  )
+  ;; code offset: 0xbbf
+  (global.set $global$0
+   ;; code offset: 0xbbd
+   (local.get $36)
+  )
+  ;; code offset: 0xbc3
+  (return
+   ;; code offset: 0xbc1
+   (local.get $34)
+  )
+ )
+ (func $fannkuch\28int\29 (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (local $19 i32)
+  (local $20 i32)
+  (local $21 i32)
+  (local $22 i32)
+  (local $23 i32)
+  (local $24 i32)
+  (local $25 i32)
+  (local $26 i32)
+  (local $27 i32)
+  (local $28 i32)
+  (local $29 i32)
+  (local $30 i32)
+  (local $31 i32)
+  (local $32 i32)
+  (local $33 i32)
+  (local $34 i32)
+  (local $35 i32)
+  (local $36 i32)
+  (local $37 i32)
+  (local $38 i32)
+  (local $39 i32)
+  (local $40 i32)
+  (local $41 i32)
+  (local $42 i32)
+  (local $43 i32)
+  (local $44 i32)
+  (local $45 i32)
+  (local $46 i32)
+  (local $47 i32)
+  (local $48 i32)
+  (local $49 i32)
+  (local $50 i32)
+  (local $51 i32)
+  (local $52 i32)
+  (local $53 i32)
+  (local $54 i32)
+  (local $55 i32)
+  (local $56 i32)
+  (local $57 i32)
+  (local $58 i32)
+  (local $59 i32)
+  (local $60 i32)
+  (local $61 i32)
+  (local $62 i32)
+  (local $63 i32)
+  (local $64 i32)
+  (local $65 i32)
+  (local $66 i32)
+  (local $67 i32)
+  (local $68 i32)
+  (local $69 i32)
+  (local $70 i32)
+  (local $71 i32)
+  (local $72 i32)
+  (local $73 i32)
+  (local $74 i32)
+  (local $75 i32)
+  (local $76 i32)
+  (local $77 i32)
+  (local $78 i32)
+  (local $79 i32)
+  (local $80 i32)
+  (local $81 i32)
+  (local $82 i32)
+  (local $83 i32)
+  (local $84 i32)
+  (local $85 i32)
+  (local $86 i32)
+  (local $87 i32)
+  (local $88 i32)
+  (local $89 i32)
+  (local $90 i32)
+  (local $91 i32)
+  (local $92 i32)
+  (local $93 i32)
+  (local $94 i32)
+  (local $95 i32)
+  (local $96 i32)
+  (local $97 i32)
+  (local $98 i32)
+  (local $99 i32)
+  (local $100 i32)
+  (local $101 i32)
+  (local $102 i32)
+  (local $103 i32)
+  (local $104 i32)
+  (local $105 i32)
+  (local $106 i32)
+  (local $107 i32)
+  (local $108 i32)
+  (local $109 i32)
+  (local $110 i32)
+  (local $111 i32)
+  (local $112 i32)
+  (local $113 i32)
+  (local $114 i32)
+  (local $115 i32)
+  (local $116 i32)
+  (local $117 i32)
+  (local $118 i32)
+  (local $119 i32)
+  (local $120 i32)
+  (local $121 i32)
+  (local $122 i32)
+  (local $123 i32)
+  (local $124 i32)
+  (local $125 i32)
+  (local $126 i32)
+  (local $127 i32)
+  (local $128 i32)
+  (local $129 i32)
+  (local $130 i32)
+  (local $131 i32)
+  (local $132 i32)
+  (local $133 i32)
+  (local $134 i32)
+  (local $135 i32)
+  (local $136 i32)
+  (local $137 i32)
+  (local $138 i32)
+  (local $139 i32)
+  (local $140 i32)
+  (local $141 i32)
+  (local $142 i32)
+  (local $143 i32)
+  (local $144 i32)
+  (local $145 i32)
+  (local $146 i32)
+  (local $147 i32)
+  (local $148 i32)
+  (local $149 i32)
+  (local $150 i32)
+  (local $151 i32)
+  (local $152 i32)
+  (local $153 i32)
+  (local $154 i32)
+  (local $155 i32)
+  (local $156 i32)
+  (local $157 i32)
+  (local $158 i32)
+  (local $159 i32)
+  (local $160 i32)
+  (local $161 i32)
+  (local $162 i32)
+  (local $163 i32)
+  (local $164 i32)
+  (local $165 i32)
+  (local $166 i32)
+  (local $167 i32)
+  (local $168 i32)
+  (local $169 i32)
+  (local $170 i32)
+  (local $171 i32)
+  (local $172 i32)
+  (local $173 i32)
+  (local $174 i32)
+  (local $175 i32)
+  (local $176 i32)
+  (local $177 i32)
+  (local $178 i32)
+  (local $179 i32)
+  ;; code offset: 0xd31
+  (local.set $1
+   ;; code offset: 0xd2f
+   (global.get $global$0)
+  )
+  ;; code offset: 0xd35
+  (local.set $2
+   ;; code offset: 0xd33
+   (i32.const 48)
+  )
+  ;; code offset: 0xd3c
+  (local.set $3
+   ;; code offset: 0xd3b
+   (i32.sub
+    ;; code offset: 0xd37
+    (local.get $1)
+    ;; code offset: 0xd39
+    (local.get $2)
+   )
+  )
+  ;; code offset: 0xd40
+  (global.set $global$0
+   ;; code offset: 0xd3e
+   (local.get $3)
+  )
+  ;; code offset: 0xd44
+  (local.set $4
+   ;; code offset: 0xd42
+   (i32.const 0)
+  )
+  ;; code offset: 0xd48
+  (local.set $5
+   ;; code offset: 0xd46
+   (i32.const 30)
+  )
+  ;; code offset: 0xd4e
+  (i32.store offset=44
+   ;; code offset: 0xd4a
+   (local.get $3)
+   ;; code offset: 0xd4c
+   (local.get $0)
+  )
+  ;; code offset: 0xd55
+  (i32.store offset=32
+   ;; code offset: 0xd51
+   (local.get $3)
+   ;; code offset: 0xd53
+   (local.get $5)
+  )
+  ;; code offset: 0xd5c
+  (i32.store offset=40
+   ;; code offset: 0xd58
+   (local.get $3)
+   ;; code offset: 0xd5a
+   (local.get $4)
+  )
+  ;; code offset: 0xd63
+  (i32.store offset=20
+   ;; code offset: 0xd5f
+   (local.get $3)
+   ;; code offset: 0xd61
+   (local.get $4)
+  )
+  ;; code offset: 0xd66
+  (block $label$1
+   ;; code offset: 0xd68
+   (loop $label$2
+    ;; code offset: 0xd6f
+    (local.set $6
+     ;; code offset: 0xd6c
+     (i32.load offset=20
+      ;; code offset: 0xd6a
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xd76
+    (local.set $7
+     ;; code offset: 0xd73
+     (i32.load offset=44
+      ;; code offset: 0xd71
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xd7a
+    (local.set $8
+     ;; code offset: 0xd78
+     (i32.const 1)
+    )
+    ;; code offset: 0xd81
+    (local.set $9
+     ;; code offset: 0xd80
+     (i32.sub
+      ;; code offset: 0xd7c
+      (local.get $7)
+      ;; code offset: 0xd7e
+      (local.get $8)
+     )
+    )
+    ;; code offset: 0xd85
+    (local.set $10
+     ;; code offset: 0xd83
+     (local.get $6)
+    )
+    ;; code offset: 0xd89
+    (local.set $11
+     ;; code offset: 0xd87
+     (local.get $9)
+    )
+    ;; code offset: 0xd90
+    (local.set $12
+     ;; code offset: 0xd8f
+     (i32.lt_s
+      ;; code offset: 0xd8b
+      (local.get $10)
+      ;; code offset: 0xd8d
+      (local.get $11)
+     )
+    )
+    ;; code offset: 0xd94
+    (local.set $13
+     ;; code offset: 0xd92
+     (i32.const 1)
+    )
+    ;; code offset: 0xd9b
+    (local.set $14
+     ;; code offset: 0xd9a
+     (i32.and
+      ;; code offset: 0xd96
+      (local.get $12)
+      ;; code offset: 0xd98
+      (local.get $13)
+     )
+    )
+    ;; code offset: 0xda0
+    (br_if $label$1
+     ;; code offset: 0xd9f
+     (i32.eqz
+      ;; code offset: 0xd9d
+      (local.get $14)
+     )
+    )
+    ;; code offset: 0xda4
+    (local.set $15
+     ;; code offset: 0xda2
+     (i32.const 12)
+    )
+    ;; code offset: 0xdaa
+    (local.set $16
+     ;; code offset: 0xda8
+     (call $malloc
+      ;; code offset: 0xda6
+      (local.get $15)
+     )
+    )
+    ;; code offset: 0xdb0
+    (i32.store offset=36
+     ;; code offset: 0xdac
+     (local.get $3)
+     ;; code offset: 0xdae
+     (local.get $16)
+    )
+    ;; code offset: 0xdb8
+    (local.set $17
+     ;; code offset: 0xdb5
+     (i32.load offset=20
+      ;; code offset: 0xdb3
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xdbf
+    (local.set $18
+     ;; code offset: 0xdbc
+     (i32.load offset=36
+      ;; code offset: 0xdba
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xdc5
+    (i32.store
+     ;; code offset: 0xdc1
+     (local.get $18)
+     ;; code offset: 0xdc3
+     (local.get $17)
+    )
+    ;; code offset: 0xdcd
+    (local.set $19
+     ;; code offset: 0xdca
+     (i32.load offset=44
+      ;; code offset: 0xdc8
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xdd4
+    (local.set $20
+     ;; code offset: 0xdd1
+     (i32.load offset=36
+      ;; code offset: 0xdcf
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xdda
+    (i32.store offset=4
+     ;; code offset: 0xdd6
+     (local.get $20)
+     ;; code offset: 0xdd8
+     (local.get $19)
+    )
+    ;; code offset: 0xde2
+    (local.set $21
+     ;; code offset: 0xddf
+     (i32.load offset=40
+      ;; code offset: 0xddd
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xde9
+    (local.set $22
+     ;; code offset: 0xde6
+     (i32.load offset=36
+      ;; code offset: 0xde4
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xdef
+    (i32.store offset=8
+     ;; code offset: 0xdeb
+     (local.get $22)
+     ;; code offset: 0xded
+     (local.get $21)
+    )
+    ;; code offset: 0xdf7
+    (local.set $23
+     ;; code offset: 0xdf4
+     (i32.load offset=36
+      ;; code offset: 0xdf2
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xdfd
+    (i32.store offset=40
+     ;; code offset: 0xdf9
+     (local.get $3)
+     ;; code offset: 0xdfb
+     (local.get $23)
+    )
+    ;; code offset: 0xe05
+    (local.set $24
+     ;; code offset: 0xe02
+     (i32.load offset=20
+      ;; code offset: 0xe00
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xe09
+    (local.set $25
+     ;; code offset: 0xe07
+     (i32.const 1)
+    )
+    ;; code offset: 0xe10
+    (local.set $26
+     ;; code offset: 0xe0f
+     (i32.add
+      ;; code offset: 0xe0b
+      (local.get $24)
+      ;; code offset: 0xe0d
+      (local.get $25)
+     )
+    )
+    ;; code offset: 0xe16
+    (i32.store offset=20
+     ;; code offset: 0xe12
+     (local.get $3)
+     ;; code offset: 0xe14
+     (local.get $26)
+    )
+    ;; code offset: 0xe19
+    (br $label$2)
+   )
+  )
+  ;; code offset: 0xe20
+  (local.set $27
+   ;; code offset: 0xe1e
+   (i32.const 0)
+  )
+  ;; code offset: 0xe27
+  (local.set $28
+   ;; code offset: 0xe24
+   (i32.load offset=44
+    ;; code offset: 0xe22
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0xe2b
+  (local.set $29
+   ;; code offset: 0xe29
+   (i32.const 2)
+  )
+  ;; code offset: 0xe32
+  (local.set $30
+   ;; code offset: 0xe31
+   (i32.shl
+    ;; code offset: 0xe2d
+    (local.get $28)
+    ;; code offset: 0xe2f
+    (local.get $29)
+   )
+  )
+  ;; code offset: 0xe38
+  (local.set $31
+   ;; code offset: 0xe36
+   (call $malloc
+    ;; code offset: 0xe34
+    (local.get $30)
+   )
+  )
+  ;; code offset: 0xe3e
+  (i32.store offset=28
+   ;; code offset: 0xe3a
+   (local.get $3)
+   ;; code offset: 0xe3c
+   (local.get $31)
+  )
+  ;; code offset: 0xe46
+  (local.set $32
+   ;; code offset: 0xe43
+   (i32.load offset=44
+    ;; code offset: 0xe41
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0xe4a
+  (local.set $33
+   ;; code offset: 0xe48
+   (i32.const 2)
+  )
+  ;; code offset: 0xe51
+  (local.set $34
+   ;; code offset: 0xe50
+   (i32.shl
+    ;; code offset: 0xe4c
+    (local.get $32)
+    ;; code offset: 0xe4e
+    (local.get $33)
+   )
+  )
+  ;; code offset: 0xe57
+  (local.set $35
+   ;; code offset: 0xe55
+   (call $malloc
+    ;; code offset: 0xe53
+    (local.get $34)
+   )
+  )
+  ;; code offset: 0xe5d
+  (i32.store offset=24
+   ;; code offset: 0xe59
+   (local.get $3)
+   ;; code offset: 0xe5b
+   (local.get $35)
+  )
+  ;; code offset: 0xe64
+  (i32.store offset=20
+   ;; code offset: 0xe60
+   (local.get $3)
+   ;; code offset: 0xe62
+   (local.get $27)
+  )
+  ;; code offset: 0xe67
+  (block $label$3
+   ;; code offset: 0xe69
+   (loop $label$4
+    ;; code offset: 0xe70
+    (local.set $36
+     ;; code offset: 0xe6d
+     (i32.load offset=20
+      ;; code offset: 0xe6b
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xe77
+    (local.set $37
+     ;; code offset: 0xe74
+     (i32.load offset=44
+      ;; code offset: 0xe72
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xe7b
+    (local.set $38
+     ;; code offset: 0xe79
+     (local.get $36)
+    )
+    ;; code offset: 0xe7f
+    (local.set $39
+     ;; code offset: 0xe7d
+     (local.get $37)
+    )
+    ;; code offset: 0xe86
+    (local.set $40
+     ;; code offset: 0xe85
+     (i32.lt_s
+      ;; code offset: 0xe81
+      (local.get $38)
+      ;; code offset: 0xe83
+      (local.get $39)
+     )
+    )
+    ;; code offset: 0xe8a
+    (local.set $41
+     ;; code offset: 0xe88
+     (i32.const 1)
+    )
+    ;; code offset: 0xe91
+    (local.set $42
+     ;; code offset: 0xe90
+     (i32.and
+      ;; code offset: 0xe8c
+      (local.get $40)
+      ;; code offset: 0xe8e
+      (local.get $41)
+     )
+    )
+    ;; code offset: 0xe96
+    (br_if $label$3
+     ;; code offset: 0xe95
+     (i32.eqz
+      ;; code offset: 0xe93
+      (local.get $42)
+     )
+    )
+    ;; code offset: 0xe9d
+    (local.set $43
+     ;; code offset: 0xe9a
+     (i32.load offset=20
+      ;; code offset: 0xe98
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xea4
+    (local.set $44
+     ;; code offset: 0xea1
+     (i32.load offset=28
+      ;; code offset: 0xe9f
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xeab
+    (local.set $45
+     ;; code offset: 0xea8
+     (i32.load offset=20
+      ;; code offset: 0xea6
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xeaf
+    (local.set $46
+     ;; code offset: 0xead
+     (i32.const 2)
+    )
+    ;; code offset: 0xeb6
+    (local.set $47
+     ;; code offset: 0xeb5
+     (i32.shl
+      ;; code offset: 0xeb1
+      (local.get $45)
+      ;; code offset: 0xeb3
+      (local.get $46)
+     )
+    )
+    ;; code offset: 0xebd
+    (local.set $48
+     ;; code offset: 0xebc
+     (i32.add
+      ;; code offset: 0xeb8
+      (local.get $44)
+      ;; code offset: 0xeba
+      (local.get $47)
+     )
+    )
+    ;; code offset: 0xec3
+    (i32.store
+     ;; code offset: 0xebf
+     (local.get $48)
+     ;; code offset: 0xec1
+     (local.get $43)
+    )
+    ;; code offset: 0xecb
+    (local.set $49
+     ;; code offset: 0xec8
+     (i32.load offset=20
+      ;; code offset: 0xec6
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xecf
+    (local.set $50
+     ;; code offset: 0xecd
+     (i32.const 1)
+    )
+    ;; code offset: 0xed6
+    (local.set $51
+     ;; code offset: 0xed5
+     (i32.add
+      ;; code offset: 0xed1
+      (local.get $49)
+      ;; code offset: 0xed3
+      (local.get $50)
+     )
+    )
+    ;; code offset: 0xedc
+    (i32.store offset=20
+     ;; code offset: 0xed8
+     (local.get $3)
+     ;; code offset: 0xeda
+     (local.get $51)
+    )
+    ;; code offset: 0xedf
+    (br $label$4)
+   )
+  )
+  ;; code offset: 0xee9
+  (local.set $52
+   ;; code offset: 0xee6
+   (i32.load offset=44
+    ;; code offset: 0xee4
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0xeef
+  (i32.store offset=16
+   ;; code offset: 0xeeb
+   (local.get $3)
+   ;; code offset: 0xeed
+   (local.get $52)
+  )
+  ;; code offset: 0xef2
+  (block $label$5
+   ;; code offset: 0xef4
+   (loop $label$6
+    ;; code offset: 0xefb
+    (local.set $53
+     ;; code offset: 0xef8
+     (i32.load offset=32
+      ;; code offset: 0xef6
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0xefd
+    (block $label$7
+     (block $label$8
+      ;; code offset: 0xf04
+      (br_if $label$8
+       ;; code offset: 0xf03
+       (i32.eqz
+        ;; code offset: 0xf01
+        (local.get $53)
+       )
+      )
+      ;; code offset: 0xf08
+      (local.set $54
+       ;; code offset: 0xf06
+       (i32.const 0)
+      )
+      ;; code offset: 0xf0e
+      (i32.store offset=20
+       ;; code offset: 0xf0a
+       (local.get $3)
+       ;; code offset: 0xf0c
+       (local.get $54)
+      )
+      ;; code offset: 0xf11
+      (block $label$9
+       ;; code offset: 0xf13
+       (loop $label$10
+        ;; code offset: 0xf1a
+        (local.set $55
+         ;; code offset: 0xf17
+         (i32.load offset=20
+          ;; code offset: 0xf15
+          (local.get $3)
+         )
+        )
+        ;; code offset: 0xf21
+        (local.set $56
+         ;; code offset: 0xf1e
+         (i32.load offset=44
+          ;; code offset: 0xf1c
+          (local.get $3)
+         )
+        )
+        ;; code offset: 0xf25
+        (local.set $57
+         ;; code offset: 0xf23
+         (local.get $55)
+        )
+        ;; code offset: 0xf29
+        (local.set $58
+         ;; code offset: 0xf27
+         (local.get $56)
+        )
+        ;; code offset: 0xf30
+        (local.set $59
+         ;; code offset: 0xf2f
+         (i32.lt_s
+          ;; code offset: 0xf2b
+          (local.get $57)
+          ;; code offset: 0xf2d
+          (local.get $58)
+         )
+        )
+        ;; code offset: 0xf34
+        (local.set $60
+         ;; code offset: 0xf32
+         (i32.const 1)
+        )
+        ;; code offset: 0xf3b
+        (local.set $61
+         ;; code offset: 0xf3a
+         (i32.and
+          ;; code offset: 0xf36
+          (local.get $59)
+          ;; code offset: 0xf38
+          (local.get $60)
+         )
+        )
+        ;; code offset: 0xf40
+        (br_if $label$9
+         ;; code offset: 0xf3f
+         (i32.eqz
+          ;; code offset: 0xf3d
+          (local.get $61)
+         )
+        )
+        ;; code offset: 0xf47
+        (local.set $62
+         ;; code offset: 0xf44
+         (i32.load offset=28
+          ;; code offset: 0xf42
+          (local.get $3)
+         )
+        )
+        ;; code offset: 0xf4e
+        (local.set $63
+         ;; code offset: 0xf4b
+         (i32.load offset=20
+          ;; code offset: 0xf49
+          (local.get $3)
+         )
+        )
+        ;; code offset: 0xf52
+        (local.set $64
+         ;; code offset: 0xf50
+         (i32.const 2)
+        )
+        ;; code offset: 0xf59
+        (local.set $65
+         ;; code offset: 0xf58
+         (i32.shl
+          ;; code offset: 0xf54
+          (local.get $63)
+          ;; code offset: 0xf56
+          (local.get $64)
+         )
+        )
+        ;; code offset: 0xf60
+        (local.set $66
+         ;; code offset: 0xf5f
+         (i32.add
+          ;; code offset: 0xf5b
+          (local.get $62)
+          ;; code offset: 0xf5d
+          (local.get $65)
+         )
+        )
+        ;; code offset: 0xf67
+        (local.set $67
+         ;; code offset: 0xf64
+         (i32.load
+          ;; code offset: 0xf62
+          (local.get $66)
+         )
+        )
+        ;; code offset: 0xf6b
+        (local.set $68
+         ;; code offset: 0xf69
+         (i32.const 1)
+        )
+        ;; code offset: 0xf72
+        (local.set $69
+         ;; code offset: 0xf71
+         (i32.add
+          ;; code offset: 0xf6d
+          (local.get $67)
+          ;; code offset: 0xf6f
+          (local.get $68)
+         )
+        )
+        ;; code offset: 0xf78
+        (i32.store
+         ;; code offset: 0xf74
+         (local.get $3)
+         ;; code offset: 0xf76
+         (local.get $69)
+        )
+        ;; code offset: 0xf7e
+        (local.set $70
+         ;; code offset: 0xf7b
+         (i32.const 1064)
+        )
+        ;; code offset: 0xf86
+        (drop
+         ;; code offset: 0xf84
+         (call $printf
+          ;; code offset: 0xf80
+          (local.get $70)
+          ;; code offset: 0xf82
+          (local.get $3)
+         )
+        )
+        ;; code offset: 0xf8c
+        (local.set $71
+         ;; code offset: 0xf89
+         (i32.load offset=20
+          ;; code offset: 0xf87
+          (local.get $3)
+         )
+        )
+        ;; code offset: 0xf90
+        (local.set $72
+         ;; code offset: 0xf8e
+         (i32.const 1)
+        )
+        ;; code offset: 0xf97
+        (local.set $73
+         ;; code offset: 0xf96
+         (i32.add
+          ;; code offset: 0xf92
+          (local.get $71)
+          ;; code offset: 0xf94
+          (local.get $72)
+         )
+        )
+        ;; code offset: 0xf9d
+        (i32.store offset=20
+         ;; code offset: 0xf99
+         (local.get $3)
+         ;; code offset: 0xf9b
+         (local.get $73)
+        )
+        ;; code offset: 0xfa0
+        (br $label$10)
+       )
+      )
+      ;; code offset: 0xfa8
+      (local.set $74
+       ;; code offset: 0xfa5
+       (i32.const 1067)
+      )
+      ;; code offset: 0xfac
+      (local.set $75
+       ;; code offset: 0xfaa
+       (i32.const 0)
+      )
+      ;; code offset: 0xfb4
+      (drop
+       ;; code offset: 0xfb2
+       (call $printf
+        ;; code offset: 0xfae
+        (local.get $74)
+        ;; code offset: 0xfb0
+        (local.get $75)
+       )
+      )
+      ;; code offset: 0xfba
+      (local.set $76
+       ;; code offset: 0xfb7
+       (i32.load offset=32
+        ;; code offset: 0xfb5
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0xfbe
+      (local.set $77
+       ;; code offset: 0xfbc
+       (i32.const -1)
+      )
+      ;; code offset: 0xfc5
+      (local.set $78
+       ;; code offset: 0xfc4
+       (i32.add
+        ;; code offset: 0xfc0
+        (local.get $76)
+        ;; code offset: 0xfc2
+        (local.get $77)
+       )
+      )
+      ;; code offset: 0xfcb
+      (i32.store offset=32
+       ;; code offset: 0xfc7
+       (local.get $3)
+       ;; code offset: 0xfc9
+       (local.get $78)
+      )
+      ;; code offset: 0xfce
+      (br $label$7)
+     )
+     ;; code offset: 0xfd1
+     (br $label$5)
+    )
+    ;; code offset: 0xfd4
+    (block $label$11
+     ;; code offset: 0xfd6
+     (loop $label$12
+      ;; code offset: 0xfda
+      (local.set $79
+       ;; code offset: 0xfd8
+       (i32.const 1)
+      )
+      ;; code offset: 0xfe1
+      (local.set $80
+       ;; code offset: 0xfde
+       (i32.load offset=16
+        ;; code offset: 0xfdc
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0xfe5
+      (local.set $81
+       ;; code offset: 0xfe3
+       (local.get $80)
+      )
+      ;; code offset: 0xfe9
+      (local.set $82
+       ;; code offset: 0xfe7
+       (local.get $79)
+      )
+      ;; code offset: 0xff0
+      (local.set $83
+       ;; code offset: 0xfef
+       (i32.gt_s
+        ;; code offset: 0xfeb
+        (local.get $81)
+        ;; code offset: 0xfed
+        (local.get $82)
+       )
+      )
+      ;; code offset: 0xff4
+      (local.set $84
+       ;; code offset: 0xff2
+       (i32.const 1)
+      )
+      ;; code offset: 0xffb
+      (local.set $85
+       ;; code offset: 0xffa
+       (i32.and
+        ;; code offset: 0xff6
+        (local.get $83)
+        ;; code offset: 0xff8
+        (local.get $84)
+       )
+      )
+      ;; code offset: 0x1000
+      (br_if $label$11
+       ;; code offset: 0xfff
+       (i32.eqz
+        ;; code offset: 0xffd
+        (local.get $85)
+       )
+      )
+      ;; code offset: 0x1007
+      (local.set $86
+       ;; code offset: 0x1004
+       (i32.load offset=16
+        ;; code offset: 0x1002
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x100e
+      (local.set $87
+       ;; code offset: 0x100b
+       (i32.load offset=24
+        ;; code offset: 0x1009
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x1015
+      (local.set $88
+       ;; code offset: 0x1012
+       (i32.load offset=16
+        ;; code offset: 0x1010
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x1019
+      (local.set $89
+       ;; code offset: 0x1017
+       (i32.const 1)
+      )
+      ;; code offset: 0x1020
+      (local.set $90
+       ;; code offset: 0x101f
+       (i32.sub
+        ;; code offset: 0x101b
+        (local.get $88)
+        ;; code offset: 0x101d
+        (local.get $89)
+       )
+      )
+      ;; code offset: 0x1024
+      (local.set $91
+       ;; code offset: 0x1022
+       (i32.const 2)
+      )
+      ;; code offset: 0x102b
+      (local.set $92
+       ;; code offset: 0x102a
+       (i32.shl
+        ;; code offset: 0x1026
+        (local.get $90)
+        ;; code offset: 0x1028
+        (local.get $91)
+       )
+      )
+      ;; code offset: 0x1032
+      (local.set $93
+       ;; code offset: 0x1031
+       (i32.add
+        ;; code offset: 0x102d
+        (local.get $87)
+        ;; code offset: 0x102f
+        (local.get $92)
+       )
+      )
+      ;; code offset: 0x1038
+      (i32.store
+       ;; code offset: 0x1034
+       (local.get $93)
+       ;; code offset: 0x1036
+       (local.get $86)
+      )
+      ;; code offset: 0x1040
+      (local.set $94
+       ;; code offset: 0x103d
+       (i32.load offset=16
+        ;; code offset: 0x103b
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x1044
+      (local.set $95
+       ;; code offset: 0x1042
+       (i32.const -1)
+      )
+      ;; code offset: 0x104b
+      (local.set $96
+       ;; code offset: 0x104a
+       (i32.add
+        ;; code offset: 0x1046
+        (local.get $94)
+        ;; code offset: 0x1048
+        (local.get $95)
+       )
+      )
+      ;; code offset: 0x1051
+      (i32.store offset=16
+       ;; code offset: 0x104d
+       (local.get $3)
+       ;; code offset: 0x104f
+       (local.get $96)
+      )
+      ;; code offset: 0x1054
+      (br $label$12)
+     )
+    )
+    ;; code offset: 0x1059
+    (loop $label$13
+     ;; code offset: 0x1060
+     (local.set $97
+      ;; code offset: 0x105d
+      (i32.load offset=16
+       ;; code offset: 0x105b
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x1067
+     (local.set $98
+      ;; code offset: 0x1064
+      (i32.load offset=44
+       ;; code offset: 0x1062
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x106b
+     (local.set $99
+      ;; code offset: 0x1069
+      (local.get $97)
+     )
+     ;; code offset: 0x106f
+     (local.set $100
+      ;; code offset: 0x106d
+      (local.get $98)
+     )
+     ;; code offset: 0x1076
+     (local.set $101
+      ;; code offset: 0x1075
+      (i32.eq
+       ;; code offset: 0x1071
+       (local.get $99)
+       ;; code offset: 0x1073
+       (local.get $100)
+      )
+     )
+     ;; code offset: 0x107a
+     (local.set $102
+      ;; code offset: 0x1078
+      (i32.const 1)
+     )
+     ;; code offset: 0x1081
+     (local.set $103
+      ;; code offset: 0x1080
+      (i32.and
+       ;; code offset: 0x107c
+       (local.get $101)
+       ;; code offset: 0x107e
+       (local.get $102)
+      )
+     )
+     ;; code offset: 0x1083
+     (block $label$14
+      ;; code offset: 0x1088
+      (br_if $label$14
+       ;; code offset: 0x1087
+       (i32.eqz
+        ;; code offset: 0x1085
+        (local.get $103)
+       )
+      )
+      ;; code offset: 0x108a
+      (br $label$5)
+     )
+     ;; code offset: 0x108f
+     (local.set $104
+      ;; code offset: 0x108d
+      (i32.const 0)
+     )
+     ;; code offset: 0x1096
+     (local.set $105
+      ;; code offset: 0x1093
+      (i32.load offset=28
+       ;; code offset: 0x1091
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x109d
+     (local.set $106
+      ;; code offset: 0x109a
+      (i32.load
+       ;; code offset: 0x1098
+       (local.get $105)
+      )
+     )
+     ;; code offset: 0x10a3
+     (i32.store offset=4
+      ;; code offset: 0x109f
+      (local.get $3)
+      ;; code offset: 0x10a1
+      (local.get $106)
+     )
+     ;; code offset: 0x10aa
+     (i32.store offset=20
+      ;; code offset: 0x10a6
+      (local.get $3)
+      ;; code offset: 0x10a8
+      (local.get $104)
+     )
+     ;; code offset: 0x10ad
+     (block $label$15
+      ;; code offset: 0x10af
+      (loop $label$16
+       ;; code offset: 0x10b6
+       (local.set $107
+        ;; code offset: 0x10b3
+        (i32.load offset=20
+         ;; code offset: 0x10b1
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x10bd
+       (local.set $108
+        ;; code offset: 0x10ba
+        (i32.load offset=16
+         ;; code offset: 0x10b8
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x10c1
+       (local.set $109
+        ;; code offset: 0x10bf
+        (local.get $107)
+       )
+       ;; code offset: 0x10c5
+       (local.set $110
+        ;; code offset: 0x10c3
+        (local.get $108)
+       )
+       ;; code offset: 0x10cc
+       (local.set $111
+        ;; code offset: 0x10cb
+        (i32.lt_s
+         ;; code offset: 0x10c7
+         (local.get $109)
+         ;; code offset: 0x10c9
+         (local.get $110)
+        )
+       )
+       ;; code offset: 0x10d0
+       (local.set $112
+        ;; code offset: 0x10ce
+        (i32.const 1)
+       )
+       ;; code offset: 0x10d7
+       (local.set $113
+        ;; code offset: 0x10d6
+        (i32.and
+         ;; code offset: 0x10d2
+         (local.get $111)
+         ;; code offset: 0x10d4
+         (local.get $112)
+        )
+       )
+       ;; code offset: 0x10dc
+       (br_if $label$15
+        ;; code offset: 0x10db
+        (i32.eqz
+         ;; code offset: 0x10d9
+         (local.get $113)
+        )
+       )
+       ;; code offset: 0x10e3
+       (local.set $114
+        ;; code offset: 0x10e0
+        (i32.load offset=28
+         ;; code offset: 0x10de
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x10ea
+       (local.set $115
+        ;; code offset: 0x10e7
+        (i32.load offset=20
+         ;; code offset: 0x10e5
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x10ee
+       (local.set $116
+        ;; code offset: 0x10ec
+        (i32.const 1)
+       )
+       ;; code offset: 0x10f5
+       (local.set $117
+        ;; code offset: 0x10f4
+        (i32.add
+         ;; code offset: 0x10f0
+         (local.get $115)
+         ;; code offset: 0x10f2
+         (local.get $116)
+        )
+       )
+       ;; code offset: 0x10f9
+       (local.set $118
+        ;; code offset: 0x10f7
+        (i32.const 2)
+       )
+       ;; code offset: 0x1100
+       (local.set $119
+        ;; code offset: 0x10ff
+        (i32.shl
+         ;; code offset: 0x10fb
+         (local.get $117)
+         ;; code offset: 0x10fd
+         (local.get $118)
+        )
+       )
+       ;; code offset: 0x1107
+       (local.set $120
+        ;; code offset: 0x1106
+        (i32.add
+         ;; code offset: 0x1102
+         (local.get $114)
+         ;; code offset: 0x1104
+         (local.get $119)
+        )
+       )
+       ;; code offset: 0x110e
+       (local.set $121
+        ;; code offset: 0x110b
+        (i32.load
+         ;; code offset: 0x1109
+         (local.get $120)
+        )
+       )
+       ;; code offset: 0x1115
+       (local.set $122
+        ;; code offset: 0x1112
+        (i32.load offset=28
+         ;; code offset: 0x1110
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x111c
+       (local.set $123
+        ;; code offset: 0x1119
+        (i32.load offset=20
+         ;; code offset: 0x1117
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x1120
+       (local.set $124
+        ;; code offset: 0x111e
+        (i32.const 2)
+       )
+       ;; code offset: 0x1127
+       (local.set $125
+        ;; code offset: 0x1126
+        (i32.shl
+         ;; code offset: 0x1122
+         (local.get $123)
+         ;; code offset: 0x1124
+         (local.get $124)
+        )
+       )
+       ;; code offset: 0x112e
+       (local.set $126
+        ;; code offset: 0x112d
+        (i32.add
+         ;; code offset: 0x1129
+         (local.get $122)
+         ;; code offset: 0x112b
+         (local.get $125)
+        )
+       )
+       ;; code offset: 0x1134
+       (i32.store
+        ;; code offset: 0x1130
+        (local.get $126)
+        ;; code offset: 0x1132
+        (local.get $121)
+       )
+       ;; code offset: 0x113c
+       (local.set $127
+        ;; code offset: 0x1139
+        (i32.load offset=20
+         ;; code offset: 0x1137
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x1140
+       (local.set $128
+        ;; code offset: 0x113e
+        (i32.const 1)
+       )
+       ;; code offset: 0x1149
+       (local.set $129
+        ;; code offset: 0x1148
+        (i32.add
+         ;; code offset: 0x1143
+         (local.get $127)
+         ;; code offset: 0x1145
+         (local.get $128)
+        )
+       )
+       ;; code offset: 0x1151
+       (i32.store offset=20
+        ;; code offset: 0x114c
+        (local.get $3)
+        ;; code offset: 0x114e
+        (local.get $129)
+       )
+       ;; code offset: 0x1154
+       (br $label$16)
+      )
+     )
+     ;; code offset: 0x115b
+     (local.set $130
+      ;; code offset: 0x1159
+      (i32.const 0)
+     )
+     ;; code offset: 0x1163
+     (local.set $131
+      ;; code offset: 0x1160
+      (i32.load offset=4
+       ;; code offset: 0x115e
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x116b
+     (local.set $132
+      ;; code offset: 0x1168
+      (i32.load offset=28
+       ;; code offset: 0x1166
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x1173
+     (local.set $133
+      ;; code offset: 0x1170
+      (i32.load offset=20
+       ;; code offset: 0x116e
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x1178
+     (local.set $134
+      ;; code offset: 0x1176
+      (i32.const 2)
+     )
+     ;; code offset: 0x1182
+     (local.set $135
+      ;; code offset: 0x1181
+      (i32.shl
+       ;; code offset: 0x117b
+       (local.get $133)
+       ;; code offset: 0x117e
+       (local.get $134)
+      )
+     )
+     ;; code offset: 0x118c
+     (local.set $136
+      ;; code offset: 0x118b
+      (i32.add
+       ;; code offset: 0x1185
+       (local.get $132)
+       ;; code offset: 0x1188
+       (local.get $135)
+      )
+     )
+     ;; code offset: 0x1195
+     (i32.store
+      ;; code offset: 0x118f
+      (local.get $136)
+      ;; code offset: 0x1192
+      (local.get $131)
+     )
+     ;; code offset: 0x119d
+     (local.set $137
+      ;; code offset: 0x119a
+      (i32.load offset=24
+       ;; code offset: 0x1198
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x11a5
+     (local.set $138
+      ;; code offset: 0x11a2
+      (i32.load offset=16
+       ;; code offset: 0x11a0
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x11aa
+     (local.set $139
+      ;; code offset: 0x11a8
+      (i32.const 2)
+     )
+     ;; code offset: 0x11b4
+     (local.set $140
+      ;; code offset: 0x11b3
+      (i32.shl
+       ;; code offset: 0x11ad
+       (local.get $138)
+       ;; code offset: 0x11b0
+       (local.get $139)
+      )
+     )
+     ;; code offset: 0x11be
+     (local.set $141
+      ;; code offset: 0x11bd
+      (i32.add
+       ;; code offset: 0x11b7
+       (local.get $137)
+       ;; code offset: 0x11ba
+       (local.get $140)
+      )
+     )
+     ;; code offset: 0x11c7
+     (local.set $142
+      ;; code offset: 0x11c4
+      (i32.load
+       ;; code offset: 0x11c1
+       (local.get $141)
+      )
+     )
+     ;; code offset: 0x11cc
+     (local.set $143
+      ;; code offset: 0x11ca
+      (i32.const -1)
+     )
+     ;; code offset: 0x11d6
+     (local.set $144
+      ;; code offset: 0x11d5
+      (i32.add
+       ;; code offset: 0x11cf
+       (local.get $142)
+       ;; code offset: 0x11d2
+       (local.get $143)
+      )
+     )
+     ;; code offset: 0x11df
+     (i32.store
+      ;; code offset: 0x11d9
+      (local.get $141)
+      ;; code offset: 0x11dc
+      (local.get $144)
+     )
+     ;; code offset: 0x11e5
+     (local.set $145
+      ;; code offset: 0x11e2
+      (local.get $144)
+     )
+     ;; code offset: 0x11eb
+     (local.set $146
+      ;; code offset: 0x11e8
+      (local.get $130)
+     )
+     ;; code offset: 0x11f5
+     (local.set $147
+      ;; code offset: 0x11f4
+      (i32.gt_s
+       ;; code offset: 0x11ee
+       (local.get $145)
+       ;; code offset: 0x11f1
+       (local.get $146)
+      )
+     )
+     ;; code offset: 0x11fa
+     (local.set $148
+      ;; code offset: 0x11f8
+      (i32.const 1)
+     )
+     ;; code offset: 0x1204
+     (local.set $149
+      ;; code offset: 0x1203
+      (i32.and
+       ;; code offset: 0x11fd
+       (local.get $147)
+       ;; code offset: 0x1200
+       (local.get $148)
+      )
+     )
+     ;; code offset: 0x1207
+     (block $label$17
+      (block $label$18
+       ;; code offset: 0x120f
+       (br_if $label$18
+        ;; code offset: 0x120e
+        (i32.eqz
+         ;; code offset: 0x120b
+         (local.get $149)
+        )
+       )
+       ;; code offset: 0x1211
+       (br $label$17)
+      )
+      ;; code offset: 0x1219
+      (local.set $150
+       ;; code offset: 0x1216
+       (i32.load offset=16
+        ;; code offset: 0x1214
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x121e
+      (local.set $151
+       ;; code offset: 0x121c
+       (i32.const 1)
+      )
+      ;; code offset: 0x1228
+      (local.set $152
+       ;; code offset: 0x1227
+       (i32.add
+        ;; code offset: 0x1221
+        (local.get $150)
+        ;; code offset: 0x1224
+        (local.get $151)
+       )
+      )
+      ;; code offset: 0x1230
+      (i32.store offset=16
+       ;; code offset: 0x122b
+       (local.get $3)
+       ;; code offset: 0x122d
+       (local.get $152)
+      )
+      ;; code offset: 0x1233
+      (br $label$13)
+     )
+    )
+    ;; code offset: 0x1237
+    (br $label$6)
+   )
+  )
+  ;; code offset: 0x123e
+  (local.set $153
+   ;; code offset: 0x123c
+   (i32.const 0)
+  )
+  ;; code offset: 0x1246
+  (local.set $154
+   ;; code offset: 0x1243
+   (i32.load offset=28
+    ;; code offset: 0x1241
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x124c
+  (call $free
+   ;; code offset: 0x1249
+   (local.get $154)
+  )
+  ;; code offset: 0x1253
+  (local.set $155
+   ;; code offset: 0x1250
+   (i32.load offset=24
+    ;; code offset: 0x124e
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x1259
+  (call $free
+   ;; code offset: 0x1256
+   (local.get $155)
+  )
+  ;; code offset: 0x1260
+  (i32.store offset=12
+   ;; code offset: 0x125b
+   (local.get $3)
+   ;; code offset: 0x125d
+   (local.get $153)
+  )
+  ;; code offset: 0x1263
+  (block $label$19
+   ;; code offset: 0x1265
+   (loop $label$20
+    ;; code offset: 0x1269
+    (local.set $156
+     ;; code offset: 0x1267
+     (i32.const 0)
+    )
+    ;; code offset: 0x1271
+    (local.set $157
+     ;; code offset: 0x126e
+     (i32.load offset=40
+      ;; code offset: 0x126c
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x1277
+    (local.set $158
+     ;; code offset: 0x1274
+     (local.get $157)
+    )
+    ;; code offset: 0x127d
+    (local.set $159
+     ;; code offset: 0x127a
+     (local.get $156)
+    )
+    ;; code offset: 0x1287
+    (local.set $160
+     ;; code offset: 0x1286
+     (i32.ne
+      ;; code offset: 0x1280
+      (local.get $158)
+      ;; code offset: 0x1283
+      (local.get $159)
+     )
+    )
+    ;; code offset: 0x128c
+    (local.set $161
+     ;; code offset: 0x128a
+     (i32.const 1)
+    )
+    ;; code offset: 0x1296
+    (local.set $162
+     ;; code offset: 0x1295
+     (i32.and
+      ;; code offset: 0x128f
+      (local.get $160)
+      ;; code offset: 0x1292
+      (local.get $161)
+     )
+    )
+    ;; code offset: 0x129d
+    (br_if $label$19
+     ;; code offset: 0x129c
+     (i32.eqz
+      ;; code offset: 0x1299
+      (local.get $162)
+     )
+    )
+    ;; code offset: 0x12a4
+    (local.set $163
+     ;; code offset: 0x12a1
+     (i32.load offset=40
+      ;; code offset: 0x129f
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x12ac
+    (local.set $164
+     ;; code offset: 0x12aa
+     (call $fannkuch_worker\28void*\29
+      ;; code offset: 0x12a7
+      (local.get $163)
+     )
+    )
+    ;; code offset: 0x12b4
+    (i32.store offset=8
+     ;; code offset: 0x12af
+     (local.get $3)
+     ;; code offset: 0x12b1
+     (local.get $164)
+    )
+    ;; code offset: 0x12bc
+    (local.set $165
+     ;; code offset: 0x12b9
+     (i32.load offset=12
+      ;; code offset: 0x12b7
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x12c4
+    (local.set $166
+     ;; code offset: 0x12c1
+     (i32.load offset=8
+      ;; code offset: 0x12bf
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x12ca
+    (local.set $167
+     ;; code offset: 0x12c7
+     (local.get $165)
+    )
+    ;; code offset: 0x12d0
+    (local.set $168
+     ;; code offset: 0x12cd
+     (local.get $166)
+    )
+    ;; code offset: 0x12da
+    (local.set $169
+     ;; code offset: 0x12d9
+     (i32.lt_s
+      ;; code offset: 0x12d3
+      (local.get $167)
+      ;; code offset: 0x12d6
+      (local.get $168)
+     )
+    )
+    ;; code offset: 0x12df
+    (local.set $170
+     ;; code offset: 0x12dd
+     (i32.const 1)
+    )
+    ;; code offset: 0x12e9
+    (local.set $171
+     ;; code offset: 0x12e8
+     (i32.and
+      ;; code offset: 0x12e2
+      (local.get $169)
+      ;; code offset: 0x12e5
+      (local.get $170)
+     )
+    )
+    ;; code offset: 0x12ec
+    (block $label$21
+     ;; code offset: 0x12f2
+     (br_if $label$21
+      ;; code offset: 0x12f1
+      (i32.eqz
+       ;; code offset: 0x12ee
+       (local.get $171)
+      )
+     )
+     ;; code offset: 0x12f9
+     (local.set $172
+      ;; code offset: 0x12f6
+      (i32.load offset=8
+       ;; code offset: 0x12f4
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x1301
+     (i32.store offset=12
+      ;; code offset: 0x12fc
+      (local.get $3)
+      ;; code offset: 0x12fe
+      (local.get $172)
+     )
+    )
+    ;; code offset: 0x130a
+    (local.set $173
+     ;; code offset: 0x1307
+     (i32.load offset=40
+      ;; code offset: 0x1305
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x1312
+    (i32.store offset=36
+     ;; code offset: 0x130d
+     (local.get $3)
+     ;; code offset: 0x130f
+     (local.get $173)
+    )
+    ;; code offset: 0x131a
+    (local.set $174
+     ;; code offset: 0x1317
+     (i32.load offset=40
+      ;; code offset: 0x1315
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x1323
+    (local.set $175
+     ;; code offset: 0x1320
+     (i32.load offset=8
+      ;; code offset: 0x131d
+      (local.get $174)
+     )
+    )
+    ;; code offset: 0x132b
+    (i32.store offset=40
+     ;; code offset: 0x1326
+     (local.get $3)
+     ;; code offset: 0x1328
+     (local.get $175)
+    )
+    ;; code offset: 0x1333
+    (local.set $176
+     ;; code offset: 0x1330
+     (i32.load offset=36
+      ;; code offset: 0x132e
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x1339
+    (call $free
+     ;; code offset: 0x1336
+     (local.get $176)
+    )
+    ;; code offset: 0x133b
+    (br $label$20)
+   )
+  )
+  ;; code offset: 0x1345
+  (local.set $177
+   ;; code offset: 0x1342
+   (i32.load offset=12
+    ;; code offset: 0x1340
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x134a
+  (local.set $178
+   ;; code offset: 0x1348
+   (i32.const 48)
+  )
+  ;; code offset: 0x1353
+  (local.set $179
+   ;; code offset: 0x1352
+   (i32.add
+    ;; code offset: 0x134d
+    (local.get $3)
+    ;; code offset: 0x134f
+    (local.get $178)
+   )
+  )
+  ;; code offset: 0x1359
+  (global.set $global$0
+   ;; code offset: 0x1356
+   (local.get $179)
+  )
+  ;; code offset: 0x135e
+  (return
+   ;; code offset: 0x135b
+   (local.get $177)
+  )
+ )
+ ;; custom section ".debug_info", size 640
+ ;; custom section ".debug_ranges", size 32
+ ;; custom section ".debug_abbrev", size 222
+ ;; custom section ".debug_line", size 3965
+ ;; custom section ".debug_str", size 409
+ ;; custom section "producers", size 180
+)
diff --git a/binaryen/test/passes/fannkuch0_dwarf.passes b/binaryen/test/passes/fannkuch0_dwarf.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fannkuch0_dwarf.passes
@@ -0,0 +1,1 @@
+dwarfdump_roundtrip_dwarfdump_g
diff --git a/binaryen/test/passes/fannkuch0_dwarf.wasm b/binaryen/test/passes/fannkuch0_dwarf.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/fannkuch0_dwarf.wasm differ
diff --git a/binaryen/test/passes/fannkuch3_dwarf.bin.txt b/binaryen/test/passes/fannkuch3_dwarf.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fannkuch3_dwarf.bin.txt
@@ -0,0 +1,7003 @@
+DWARF debug info
+================
+
+Contains section .debug_info (851 bytes)
+Contains section .debug_loc (1073 bytes)
+Contains section .debug_ranges (88 bytes)
+Contains section .debug_abbrev (333 bytes)
+Contains section .debug_line (1477 bytes)
+Contains section .debug_str (434 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[2] DW_TAG_pointer_type	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[3] DW_TAG_structure_type	DW_CHILDREN_yes
+	DW_AT_calling_convention	DW_FORM_data1
+	DW_AT_name	DW_FORM_strp
+	DW_AT_byte_size	DW_FORM_data1
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[4] DW_TAG_member	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_data_member_location	DW_FORM_data1
+
+[5] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+[6] DW_TAG_namespace	DW_CHILDREN_yes
+	DW_AT_name	DW_FORM_strp
+
+[7] DW_TAG_typedef	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[8] DW_TAG_unspecified_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+
+[9] DW_TAG_imported_declaration	DW_CHILDREN_no
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_import	DW_FORM_ref4
+
+[10] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[11] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[12] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[13] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[14] DW_TAG_lexical_block	DW_CHILDREN_yes
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[15] DW_TAG_GNU_call_site	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+
+[16] DW_TAG_GNU_call_site	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+	DW_AT_low_pc	DW_FORM_addr
+
+[17] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_declaration	DW_FORM_flag_present
+	DW_AT_external	DW_FORM_flag_present
+
+[18] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[19] DW_TAG_pointer_type	DW_CHILDREN_no
+
+[20] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_inline	DW_FORM_data1
+
+[21] DW_TAG_label	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[22] DW_TAG_lexical_block	DW_CHILDREN_yes
+
+[23] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[24] DW_TAG_inlined_subroutine	DW_CHILDREN_yes
+	DW_AT_abstract_origin	DW_FORM_ref4
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_call_file	DW_FORM_data1
+	DW_AT_call_line	DW_FORM_data1
+	DW_AT_call_column	DW_FORM_data1
+
+[25] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[26] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[27] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[28] DW_TAG_label	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+	DW_AT_low_pc	DW_FORM_addr
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x0000034f version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x00000353)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000069] = "/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x000000a9] = "/usr/local/google/home/azakai/Dev/2-binaryen")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+              DW_AT_ranges [DW_FORM_sec_offset]	(0x00000040
+                 [0x00000006, 0x0000039d)
+                 [0x0000039f, 0x000006e1))
+
+0x00000026:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x002b => {0x0000002b} "worker_args")
+
+0x0000002b:   DW_TAG_structure_type [3] *
+                DW_AT_calling_convention [DW_FORM_data1]	(DW_CC_pass_by_value)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000e3] = "worker_args")
+                DW_AT_byte_size [DW_FORM_data1]	(0x0c)
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(20)
+
+0x00000034:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d6] = "i")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(21)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x00)
+
+0x00000040:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(21)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x04)
+
+0x0000004c:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000de] = "next")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(22)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x08)
+
+0x00000058:     NULL
+
+0x00000059:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d8] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x00000060:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000065:   DW_TAG_namespace [6] *
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ef] = "std")
+
+0x0000006a:     DW_TAG_typedef [7]  
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0076 => {0x00000076} "decltype(nullptr)")
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000105] = "nullptr_t")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/system/include/libcxx/__nullptr")
+                  DW_AT_decl_line [DW_FORM_data1]	(57)
+
+0x00000075:     NULL
+
+0x00000076:   DW_TAG_unspecified_type [8]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000f3] = "decltype(nullptr)")
+
+0x0000007b:   DW_TAG_imported_declaration [9]  
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/system/include/libcxx/stddef.h")
+                DW_AT_decl_line [DW_FORM_data1]	(52)
+                DW_AT_import [DW_FORM_ref4]	(cu + 0x006a => {0x0000006a})
+
+0x00000082:   DW_TAG_subprogram [10] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000006)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000397)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x1 +0, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x00000166] = "_Z15fannkuch_workerPv")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000017c] = "fannkuch_worker")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(26)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000009e:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000191] = "_arg")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(26)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x01a7 => {0x000001a7} "*")
+
+0x000000a9:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000133] = "args")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(28)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000000b4:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000000: 
+                     [0xffffffff,  0x00000006): 
+                     [0x00000000,  0x0000003c): DW_OP_consts +0, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014c] = "maxflips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000c3:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000001d: 
+                     [0xffffffff,  0x00000006): 
+                     [0x00000007,  0x0000003c): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000052,  0x00000057): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x000000ec,  0x000000f5): DW_OP_consts +1, DW_OP_stack_value
+                     [0x00000131,  0x0000013b): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                     [0x00000179,  0x00000186): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000264,  0x0000026f): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000275,  0x0000027e): DW_OP_consts +1, DW_OP_stack_value
+                     [0x000002ba,  0x000002c4): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                     [0x00000302,  0x0000030f): DW_OP_consts +0, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d6] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000d2:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000a5: 
+                     [0xffffffff,  0x00000006): 
+                     [0x0000000e,  0x0000003c): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000e1:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000c3: 
+                     [0xffffffff,  0x00000006): 
+                     [0x0000001b,  0x0000003c): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000013e] = "perm1")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000000f0:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000e1: 
+                     [0xffffffff,  0x00000006): 
+                     [0x00000025,  0x0000003c): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000196] = "perm")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000000ff:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000ff: 
+                     [0xffffffff,  0x00000006): 
+                     [0x0000002f,  0x0000003c): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000144] = "count")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x0000010e:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000011d: 
+                     [0xffffffff,  0x00000006): 
+                     [0x000001e2,  0x000001e7): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+                     [0x0000036b,  0x00000370): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014a] = "r")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000011d:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000149: 
+                     [0xffffffff,  0x00000006): 
+                     [0x000000cf,  0x000000e6): DW_OP_consts +0, DW_OP_stack_value
+                     [0x000000ec,  0x000000f5): DW_OP_WASM_location 0x0 +13, DW_OP_stack_value
+                     [0x0000015a,  0x00000162): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                     [0x00000264,  0x0000026f): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000275,  0x0000027e): DW_OP_WASM_location 0x0 +10, DW_OP_stack_value
+                     [0x000002e3,  0x000002eb): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000155] = "flips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000012c:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000001ab: 
+                     [0xffffffff,  0x00000006): 
+                     [0x000000e2,  0x000000e6): DW_OP_WASM_location 0x0 +12, DW_OP_stack_value
+                     [0x0000026b,  0x0000026f): DW_OP_WASM_location 0x0 +16, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000019b] = "k")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000013b:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000001d7: 
+                     [0xffffffff,  0x00000006): 
+                     [0x000000fc,  0x00000100): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x00000138,  0x0000013b): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x00000285,  0x00000289): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x000002c1,  0x000002c4): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000019d] = "j")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000014a:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000021f: 
+                     [0xffffffff,  0x00000006): 
+                     [0x00000111,  0x0000013b): DW_OP_WASM_location 0x0 +15, DW_OP_stack_value
+                     [0x0000014c,  0x00000162): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x0000029a,  0x000002c4): DW_OP_WASM_location 0x0 +14, DW_OP_stack_value
+                     [0x000002d5,  0x000002eb): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000019f] = "tmp")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000159:     DW_TAG_lexical_block [14] *
+                  DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
+                     [0x00000185, 0x000001c3)
+                     [0x000001ed, 0x000001f6)
+                     [0x0000030e, 0x0000034c)
+                     [0x00000376, 0x0000037f))
+
+0x0000015e:       DW_TAG_variable [12]  
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000163] = "p0")
+                    DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                    DW_AT_decl_line [DW_FORM_data1]	(74)
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000169:       NULL
+
+0x0000016a:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000001f)
+
+0x0000016f:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000029)
+
+0x00000174:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000033)
+
+0x00000179:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000000e1)
+
+0x0000017e:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000038a)
+
+0x00000187:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000392)
+
+0x00000190:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000039a)
+
+0x00000199:     NULL
+
+0x0000019a:   DW_TAG_subprogram [17] *
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000010f] = "free")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/system/include/libc/stdlib.h")
+                DW_AT_decl_line [DW_FORM_data1]	(41)
+                DW_AT_declaration [DW_FORM_flag_present]	(true)
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x000001a1:     DW_TAG_formal_parameter [18]  
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x01a7 => {0x000001a7} "*")
+
+0x000001a6:     NULL
+
+0x000001a7:   DW_TAG_pointer_type [19]  
+
+0x000001a8:   DW_TAG_subprogram [20] *
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x00000114] = "_ZL8fannkuchi")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000122] = "fannkuch")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(87)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_inline [DW_FORM_data1]	(DW_INL_inlined)
+
+0x000001b8:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(87)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001c3:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000012b] = "showmax")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(90)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001ce:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000133] = "args")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(89)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000001d9:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d6] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001e4:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000138] = "targs")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(89)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000001ef:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000013e] = "perm1")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000001fa:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000144] = "count")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x00000205:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014a] = "r")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000210:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014c] = "maxflips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000021b:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000155] = "flips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000226:     DW_TAG_label [21]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000015b] = "cleanup")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(137)
+
+0x0000022d:     DW_TAG_lexical_block [22] *
+
+0x0000022e:       DW_TAG_variable [12]  
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000163] = "p0")
+                    DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                    DW_AT_decl_line [DW_FORM_data1]	(125)
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000239:       NULL
+
+0x0000023a:     NULL
+
+0x0000023b:   DW_TAG_subprogram [23] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x000000000000039f)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000342)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x0 +2, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000018c] = "main")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(152)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000253:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000001a3] = "argc")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(152)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000025e:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000001a8] = "argv")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(152)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0341 => {0x00000341} "char**")
+
+0x00000269:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000267: 
+                     [0xffffffff,  0x0000039f): 
+                     [0x00000032,  0x00000037): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(153)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000278:     DW_TAG_inlined_subroutine [24] *
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01a8 => {0x000001a8} "_ZL8fannkuchi")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000003ed)
+                  DW_AT_high_pc [DW_FORM_data4]	(0x000002c8)
+                  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)
+
+0x00000288:       DW_TAG_formal_parameter [25]  
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01b8 => {0x000001b8} "n")
+
+0x0000028d:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000285: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x0000004c,  0x00000055): DW_OP_consts +30, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01c3 => {0x000001c3} "showmax")
+
+0x00000296:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x000002a2: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x0000004c,  0x00000055): DW_OP_lit0, DW_OP_stack_value
+                       [0x000002f8,  0x00000314): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01ce => {0x000001ce} "args")
+
+0x0000029f:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x000002cc: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x0000004c,  0x00000055): DW_OP_consts +0, DW_OP_stack_value
+                       [0x0000008e,  0x00000093): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                       [0x00000099,  0x000000c1): DW_OP_consts +0, DW_OP_stack_value
+                       [0x000000d7,  0x000000dc): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                       [0x000000f5,  0x000000f9): DW_OP_consts +0, DW_OP_stack_value
+                       [0x00000127,  0x0000012c): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                       [0x00000178,  0x00000188): DW_OP_consts +0, DW_OP_stack_value
+                       [0x000001fa,  0x0000020c): DW_OP_consts +0, DW_OP_stack_value
+                       [0x00000241,  0x00000255): DW_OP_consts +0, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01d9 => {0x000001d9} "i")
+
+0x000002a8:       DW_TAG_variable [27]  
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01e4 => {0x000001e4} "targs")
+
+0x000002ad:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000354: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x000000a8,  0x000000c1): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01ef => {0x000001ef} "perm1")
+
+0x000002b6:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000372: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x000000b2,  0x000000c1): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01fa => {0x000001fa} "count")
+
+0x000002bf:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000390: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x000001e6,  0x000001ed): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+                       [0x000002b3,  0x000002ba): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x0205 => {0x00000205} "r")
+
+0x000002c8:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x000003e8: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x000002d6,  0x000002e1): DW_OP_consts +0, DW_OP_stack_value
+                       [0x0000030c,  0x00000314): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x0210 => {0x00000210} "maxflips")
+
+0x000002d1:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000413: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x000002f1,  0x00000314): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x021b => {0x0000021b} "flips")
+
+0x000002da:       DW_TAG_label [28]  
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x0226 => {0x00000226} "cleanup")
+                    DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000661)
+
+0x000002e3:       DW_TAG_lexical_block [14] *
+                    DW_AT_ranges [DW_FORM_sec_offset]	(0x00000028
+                       [0x00000517, 0x0000055e)
+                       [0x000005de, 0x0000062b))
+
+0x000002e8:         DW_TAG_variable [26]  
+                      DW_AT_location [DW_FORM_sec_offset]	(0x000003bc: 
+                         [0xffffffff,  0x0000039f): 
+                         [0x0000017f,  0x00000188): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value
+                         [0x00000248,  0x00000255): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value)
+                      DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x022e => {0x0000022e} "p0")
+
+0x000002f1:         NULL
+
+0x000002f2:       NULL
+
+0x000002f3:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000003cf)
+
+0x000002f8:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000003e3)
+
+0x000002fd:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000040d)
+
+0x00000302:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000445)
+
+0x00000307:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000044f)
+
+0x0000030c:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000004be)
+
+0x00000311:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000004d4)
+
+0x00000316:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000005a1)
+
+0x0000031b:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000669)
+
+0x00000324:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000671)
+
+0x0000032d:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000068e)
+
+0x00000332:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000069f)
+
+0x0000033b:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000006d1)
+
+0x00000340:     NULL
+
+0x00000341:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0346 => {0x00000346} "char*")
+
+0x00000346:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x034b => {0x0000034b} "char")
+
+0x0000034b:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000001ad] = "char")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed_char)
+                DW_AT_byte_size [DW_FORM_data1]	(0x01)
+
+0x00000352:   NULL
+
+.debug_loc contents:
+0x00000000: 
+            [0xffffffff,  0x00000006): 
+            [0x00000000,  0x0000003c): DW_OP_consts +0, DW_OP_stack_value
+
+0x0000001d: 
+            [0xffffffff,  0x00000006): 
+            [0x00000007,  0x0000003c): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000052,  0x00000057): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x000000ec,  0x000000f5): DW_OP_consts +1, DW_OP_stack_value
+            [0x00000131,  0x0000013b): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000179,  0x00000186): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000264,  0x0000026f): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000275,  0x0000027e): DW_OP_consts +1, DW_OP_stack_value
+            [0x000002ba,  0x000002c4): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000302,  0x0000030f): DW_OP_consts +0, DW_OP_stack_value
+
+0x000000a5: 
+            [0xffffffff,  0x00000006): 
+            [0x0000000e,  0x0000003c): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+
+0x000000c3: 
+            [0xffffffff,  0x00000006): 
+            [0x0000001b,  0x0000003c): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+
+0x000000e1: 
+            [0xffffffff,  0x00000006): 
+            [0x00000025,  0x0000003c): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value
+
+0x000000ff: 
+            [0xffffffff,  0x00000006): 
+            [0x0000002f,  0x0000003c): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+
+0x0000011d: 
+            [0xffffffff,  0x00000006): 
+            [0x000001e2,  0x000001e7): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+            [0x0000036b,  0x00000370): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+
+0x00000149: 
+            [0xffffffff,  0x00000006): 
+            [0x000000cf,  0x000000e6): DW_OP_consts +0, DW_OP_stack_value
+            [0x000000ec,  0x000000f5): DW_OP_WASM_location 0x0 +13, DW_OP_stack_value
+            [0x0000015a,  0x00000162): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000264,  0x0000026f): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000275,  0x0000027e): DW_OP_WASM_location 0x0 +10, DW_OP_stack_value
+            [0x000002e3,  0x000002eb): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+
+0x000001ab: 
+            [0xffffffff,  0x00000006): 
+            [0x000000e2,  0x000000e6): DW_OP_WASM_location 0x0 +12, DW_OP_stack_value
+            [0x0000026b,  0x0000026f): DW_OP_WASM_location 0x0 +16, DW_OP_stack_value
+
+0x000001d7: 
+            [0xffffffff,  0x00000006): 
+            [0x000000fc,  0x00000100): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x00000138,  0x0000013b): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x00000285,  0x00000289): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x000002c1,  0x000002c4): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x0000021f: 
+            [0xffffffff,  0x00000006): 
+            [0x00000111,  0x0000013b): DW_OP_WASM_location 0x0 +15, DW_OP_stack_value
+            [0x0000014c,  0x00000162): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x0000029a,  0x000002c4): DW_OP_WASM_location 0x0 +14, DW_OP_stack_value
+            [0x000002d5,  0x000002eb): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000267: 
+            [0xffffffff,  0x0000039f): 
+            [0x00000032,  0x00000037): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+
+0x00000285: 
+            [0xffffffff,  0x0000039f): 
+            [0x0000004c,  0x00000055): DW_OP_consts +30, DW_OP_stack_value
+
+0x000002a2: 
+            [0xffffffff,  0x0000039f): 
+            [0x0000004c,  0x00000055): DW_OP_lit0, DW_OP_stack_value
+            [0x000002f8,  0x00000314): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+
+0x000002cc: 
+            [0xffffffff,  0x0000039f): 
+            [0x0000004c,  0x00000055): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000008e,  0x00000093): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000099,  0x000000c1): DW_OP_consts +0, DW_OP_stack_value
+            [0x000000d7,  0x000000dc): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x000000f5,  0x000000f9): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000127,  0x0000012c): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000178,  0x00000188): DW_OP_consts +0, DW_OP_stack_value
+            [0x000001fa,  0x0000020c): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000241,  0x00000255): DW_OP_consts +0, DW_OP_stack_value
+
+0x00000354: 
+            [0xffffffff,  0x0000039f): 
+            [0x000000a8,  0x000000c1): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000372: 
+            [0xffffffff,  0x0000039f): 
+            [0x000000b2,  0x000000c1): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value
+
+0x00000390: 
+            [0xffffffff,  0x0000039f): 
+            [0x000001e6,  0x000001ed): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+            [0x000002b3,  0x000002ba): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+
+0x000003bc: 
+            [0xffffffff,  0x0000039f): 
+            [0x0000017f,  0x00000188): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value
+            [0x00000248,  0x00000255): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value
+
+0x000003e8: 
+            [0xffffffff,  0x0000039f): 
+            [0x000002d6,  0x000002e1): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000030c,  0x00000314): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+
+0x00000413: 
+            [0xffffffff,  0x0000039f): 
+            [0x000002f1,  0x00000314): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x000005c1
+         version: 4
+ prologue_length: 0x000000dd
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+include_directories[  1] = "/usr/local/google/home/azakai/Dev"
+file_names[  1]:
+           name: "emscripten/tests/fannkuch.cpp"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  2]:
+           name: "emscripten/system/include/libcxx/__nullptr"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  3]:
+           name: "emscripten/system/include/libcxx/stddef.h"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  4]:
+           name: "emscripten/system/include/libc/stdlib.h"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+0x000000e7: 00 DW_LNE_set_address (0x0000000000000006)
+0x000000ee: 03 DW_LNS_advance_line (27)
+0x000000f0: 01 DW_LNS_copy
+            0x0000000000000006     27      0      1   0             0  is_stmt
+
+
+0x000000f1: 05 DW_LNS_set_column (14)
+0x000000f3: 0a DW_LNS_set_prologue_end
+0x000000f4: 7a address += 7,  line += 6
+            0x000000000000000d     33     14      1   0             0  is_stmt prologue_end
+
+0x000000f5: 06 DW_LNS_negate_stmt
+0x000000f6: 03 DW_LNS_advance_line (0)
+0x000000f8: 58 address += 5,  line += 0
+            0x0000000000000012      0     14      1   0             0 
+
+0x000000f9: 05 DW_LNS_set_column (27)
+0x000000fb: 06 DW_LNS_negate_stmt
+0x000000fc: 03 DW_LNS_advance_line (34)
+0x000000fe: 4a address += 4,  line += 0
+            0x0000000000000016     34     27      1   0             0  is_stmt
+
+0x000000ff: 05 DW_LNS_set_column (18)
+0x00000101: 06 DW_LNS_negate_stmt
+0x00000102: 20 address += 1,  line += 0
+            0x0000000000000017     34     18      1   0             0 
+
+0x00000103: 05 DW_LNS_set_column (17)
+0x00000105: 06 DW_LNS_negate_stmt
+0x00000106: 9f address += 10,  line += 1
+            0x0000000000000021     35     17      1   0             0  is_stmt
+
+0x00000107: 05 DW_LNS_set_column (18)
+0x00000109: 9f address += 10,  line += 1
+            0x000000000000002b     36     18      1   0             0  is_stmt
+
+0x0000010a: 06 DW_LNS_negate_stmt
+0x0000010b: 03 DW_LNS_advance_line (0)
+0x0000010d: 9e address += 10,  line += 0
+            0x0000000000000035      0     18      1   0             0 
+
+0x0000010e: 06 DW_LNS_negate_stmt
+0x0000010f: 03 DW_LNS_advance_line (37)
+0x00000111: 66 address += 6,  line += 0
+            0x000000000000003b     37     18      1   0             0  is_stmt
+
+0x00000112: 05 DW_LNS_set_column (4)
+0x00000114: 06 DW_LNS_negate_stmt
+0x00000115: 58 address += 5,  line += 0
+            0x0000000000000040     37      4      1   0             0 
+
+0x00000116: 03 DW_LNS_advance_line (0)
+0x00000118: 2e address += 2,  line += 0
+            0x0000000000000042      0      4      1   0             0 
+
+0x00000119: 05 DW_LNS_set_column (7)
+0x0000011b: 06 DW_LNS_negate_stmt
+0x0000011c: 03 DW_LNS_advance_line (38)
+0x0000011e: 2e address += 2,  line += 0
+            0x0000000000000044     38      7      1   0             0  is_stmt
+
+0x0000011f: 05 DW_LNS_set_column (16)
+0x00000121: 06 DW_LNS_negate_stmt
+0x00000122: 82 address += 8,  line += 0
+            0x000000000000004c     38     16      1   0             0 
+
+0x00000123: 05 DW_LNS_set_column (24)
+0x00000125: 06 DW_LNS_negate_stmt
+0x00000126: 57 address += 5,  line += -1
+            0x0000000000000051     37     24      1   0             0  is_stmt
+
+0x00000127: 05 DW_LNS_set_column (18)
+0x00000129: 06 DW_LNS_negate_stmt
+0x0000012a: 58 address += 5,  line += 0
+            0x0000000000000056     37     18      1   0             0 
+
+0x0000012b: 05 DW_LNS_set_column (4)
+0x0000012d: 58 address += 5,  line += 0
+            0x000000000000005b     37      4      1   0             0 
+
+0x0000012e: 06 DW_LNS_negate_stmt
+0x0000012f: 3e address += 3,  line += 2
+            0x000000000000005e     39      4      1   0             0  is_stmt
+
+0x00000130: 05 DW_LNS_set_column (16)
+0x00000132: 06 DW_LNS_negate_stmt
+0x00000133: 2e address += 2,  line += 0
+            0x0000000000000060     39     16      1   0             0 
+
+0x00000134: 05 DW_LNS_set_column (4)
+0x00000136: 90 address += 9,  line += 0
+            0x0000000000000069     39      4      1   0             0 
+
+0x00000137: 05 DW_LNS_set_column (23)
+0x00000139: 2e address += 2,  line += 0
+            0x000000000000006b     39     23      1   0             0 
+
+0x0000013a: 05 DW_LNS_set_column (19)
+0x0000013c: 58 address += 5,  line += 0
+            0x0000000000000070     39     19      1   0             0 
+
+0x0000013d: 05 DW_LNS_set_column (4)
+0x0000013f: 06 DW_LNS_negate_stmt
+0x00000140: 59 address += 5,  line += 1
+            0x0000000000000075     40      4      1   0             0  is_stmt
+
+0x00000141: 05 DW_LNS_set_column (17)
+0x00000143: 06 DW_LNS_negate_stmt
+0x00000144: 82 address += 8,  line += 0
+            0x000000000000007d     40     17      1   0             0 
+
+0x00000145: 05 DW_LNS_set_column (18)
+0x00000147: 06 DW_LNS_negate_stmt
+0x00000148: a9 address += 11,  line += -3
+            0x0000000000000088     37     18      1   0             0  is_stmt
+
+0x00000149: 05 DW_LNS_set_column (4)
+0x0000014b: 5e address += 5,  line += 6
+            0x000000000000008d     43      4      1   0             0  is_stmt
+
+0x0000014c: 06 DW_LNS_negate_stmt
+0x0000014d: 03 DW_LNS_advance_line (0)
+0x0000014f: 2e address += 2,  line += 0
+            0x000000000000008f      0      4      1   0             0 
+
+0x00000150: 05 DW_LNS_set_column (16)
+0x00000152: 06 DW_LNS_negate_stmt
+0x00000153: 03 DW_LNS_advance_line (44)
+0x00000155: 4a address += 4,  line += 0
+            0x0000000000000093     44     16      1   0             0  is_stmt
+
+0x00000156: 06 DW_LNS_negate_stmt
+0x00000157: 03 DW_LNS_advance_line (0)
+0x00000159: 74 address += 7,  line += 0
+            0x000000000000009a      0     16      1   0             0 
+
+0x0000015a: 05 DW_LNS_set_column (10)
+0x0000015c: 06 DW_LNS_negate_stmt
+0x0000015d: 03 DW_LNS_advance_line (45)
+0x0000015f: 2e address += 2,  line += 0
+            0x000000000000009c     45     10      1   0             0  is_stmt
+
+0x00000160: 05 DW_LNS_set_column (18)
+0x00000162: 06 DW_LNS_negate_stmt
+0x00000163: 2e address += 2,  line += 0
+            0x000000000000009e     45     18      1   0             0 
+
+0x00000164: 05 DW_LNS_set_column (10)
+0x00000166: 90 address += 9,  line += 0
+            0x00000000000000a7     45     10      1   0             0 
+
+0x00000167: 05 DW_LNS_set_column (23)
+0x00000169: 2e address += 2,  line += 0
+            0x00000000000000a9     45     23      1   0             0 
+
+0x0000016a: 05 DW_LNS_set_column (16)
+0x0000016c: 06 DW_LNS_negate_stmt
+0x0000016d: 57 address += 5,  line += -1
+            0x00000000000000ae     44     16      1   0             0  is_stmt
+
+0x0000016e: 05 DW_LNS_set_column (0)
+0x00000170: 06 DW_LNS_negate_stmt
+0x00000171: 03 DW_LNS_advance_line (0)
+0x00000173: 74 address += 7,  line += 0
+            0x00000000000000b5      0      0      1   0             0 
+
+0x00000174: 05 DW_LNS_set_column (7)
+0x00000176: 03 DW_LNS_advance_line (44)
+0x00000178: 4a address += 4,  line += 0
+            0x00000000000000b9     44      7      1   0             0 
+
+0x00000179: 05 DW_LNS_set_column (11)
+0x0000017b: 06 DW_LNS_negate_stmt
+0x0000017c: 68 address += 6,  line += 2
+            0x00000000000000bf     46     11      1   0             0  is_stmt
+
+0x0000017d: 05 DW_LNS_set_column (28)
+0x0000017f: 06 DW_LNS_negate_stmt
+0x00000180: ba address += 12,  line += 0
+            0x00000000000000cb     46     28      1   0             0 
+
+0x00000181: 05 DW_LNS_set_column (41)
+0x00000183: 58 address += 5,  line += 0
+            0x00000000000000d0     46     41      1   0             0 
+
+0x00000184: 05 DW_LNS_set_column (21)
+0x00000186: 06 DW_LNS_negate_stmt
+0x00000187: 5a address += 5,  line += 2
+            0x00000000000000d5     48     21      1   0             0  is_stmt
+
+0x00000188: 05 DW_LNS_set_column (14)
+0x0000018a: bc address += 12,  line += 2
+            0x00000000000000e1     50     14      1   0             0  is_stmt
+
+0x0000018b: 06 DW_LNS_negate_stmt
+0x0000018c: 03 DW_LNS_advance_line (0)
+0x0000018e: 74 address += 7,  line += 0
+            0x00000000000000e8      0     14      1   0             0 
+
+0x0000018f: 05 DW_LNS_set_column (38)
+0x00000191: 06 DW_LNS_negate_stmt
+0x00000192: 03 DW_LNS_advance_line (52)
+0x00000194: ba address += 12,  line += 0
+            0x00000000000000f4     52     38      1   0             0  is_stmt
+
+0x00000195: 05 DW_LNS_set_column (0)
+0x00000197: 06 DW_LNS_negate_stmt
+0x00000198: 03 DW_LNS_advance_line (0)
+0x0000019a: 74 address += 7,  line += 0
+            0x00000000000000fb      0      0      1   0             0 
+
+0x0000019b: 05 DW_LNS_set_column (22)
+0x0000019d: 06 DW_LNS_negate_stmt
+0x0000019e: 03 DW_LNS_advance_line (53)
+0x000001a0: c8 address += 13,  line += 0
+            0x0000000000000108     53     22      1   0             0  is_stmt
+
+0x000001a1: 05 DW_LNS_set_column (24)
+0x000001a3: e5 address += 15,  line += 1
+            0x0000000000000117     54     24      1   0             0  is_stmt
+
+0x000001a4: 05 DW_LNS_set_column (26)
+0x000001a6: 06 DW_LNS_negate_stmt
+0x000001a7: 2e address += 2,  line += 0
+            0x0000000000000119     54     26      1   0             0 
+
+0x000001a8: 05 DW_LNS_set_column (24)
+0x000001aa: c8 address += 13,  line += 0
+            0x0000000000000126     54     24      1   0             0 
+
+0x000001ab: 06 DW_LNS_negate_stmt
+0x000001ac: 3d address += 3,  line += 1
+            0x0000000000000129     55     24      1   0             0  is_stmt
+
+0x000001ad: 05 DW_LNS_set_column (44)
+0x000001af: 71 address += 7,  line += -3
+            0x0000000000000130     52     44      1   0             0  is_stmt
+
+0x000001b0: 06 DW_LNS_negate_stmt
+0x000001b1: 03 DW_LNS_advance_line (0)
+0x000001b3: 58 address += 5,  line += 0
+            0x0000000000000135      0     44      1   0             0 
+
+0x000001b4: 05 DW_LNS_set_column (38)
+0x000001b6: 03 DW_LNS_advance_line (52)
+0x000001b8: 74 address += 7,  line += 0
+            0x000000000000013c     52     38      1   0             0 
+
+0x000001b9: 05 DW_LNS_set_column (13)
+0x000001bb: 3c address += 3,  line += 0
+            0x000000000000013f     52     13      1   0             0 
+
+0x000001bc: 05 DW_LNS_set_column (19)
+0x000001be: 06 DW_LNS_negate_stmt
+0x000001bf: 50 address += 4,  line += 6
+            0x0000000000000143     58     19      1   0             0  is_stmt
+
+0x000001c0: 05 DW_LNS_set_column (21)
+0x000001c2: e5 address += 15,  line += 1
+            0x0000000000000152     59     21      1   0             0  is_stmt
+
+0x000001c3: 05 DW_LNS_set_column (18)
+0x000001c5: 72 address += 7,  line += -2
+            0x0000000000000159     57     18      1   0             0  is_stmt
+
+0x000001c6: 05 DW_LNS_set_column (0)
+0x000001c8: 06 DW_LNS_negate_stmt
+0x000001c9: 03 DW_LNS_advance_line (0)
+0x000001cb: 74 address += 7,  line += 0
+            0x0000000000000160      0      0      1   0             0 
+
+0x000001cc: 05 DW_LNS_set_column (14)
+0x000001ce: 06 DW_LNS_negate_stmt
+0x000001cf: 03 DW_LNS_advance_line (62)
+0x000001d1: 90 address += 9,  line += 0
+            0x0000000000000169     62     14      1   0             0  is_stmt
+
+0x000001d2: 05 DW_LNS_set_column (23)
+0x000001d4: 06 DW_LNS_negate_stmt
+0x000001d5: 4a address += 4,  line += 0
+            0x000000000000016d     62     23      1   0             0 
+
+0x000001d6: 05 DW_LNS_set_column (14)
+0x000001d8: 58 address += 5,  line += 0
+            0x0000000000000172     62     14      1   0             0 
+
+0x000001d9: 03 DW_LNS_advance_line (0)
+0x000001db: 3c address += 3,  line += 0
+            0x0000000000000175      0     14      1   0             0 
+
+0x000001dc: 05 DW_LNS_set_column (16)
+0x000001de: 06 DW_LNS_negate_stmt
+0x000001df: 03 DW_LNS_advance_line (66)
+0x000001e2: 20 address += 1,  line += 0
+            0x0000000000000176     66     16      1   0             0  is_stmt
+
+0x000001e3: 06 DW_LNS_negate_stmt
+0x000001e4: 03 DW_LNS_advance_line (0)
+0x000001e7: 74 address += 7,  line += 0
+            0x000000000000017d      0     16      1   0             0 
+
+0x000001e8: 05 DW_LNS_set_column (27)
+0x000001ea: 06 DW_LNS_negate_stmt
+0x000001eb: 03 DW_LNS_advance_line (75)
+0x000001ee: 82 address += 8,  line += 0
+            0x0000000000000185     75     27      1   0             0  is_stmt
+
+0x000001ef: 06 DW_LNS_negate_stmt
+0x000001f0: 03 DW_LNS_advance_line (0)
+0x000001f3: 74 address += 7,  line += 0
+            0x000000000000018c      0     27      1   0             0 
+
+0x000001f4: 05 DW_LNS_set_column (16)
+0x000001f6: 06 DW_LNS_negate_stmt
+0x000001f7: 03 DW_LNS_advance_line (76)
+0x000001fa: 2e address += 2,  line += 0
+            0x000000000000018e     76     16      1   0             0  is_stmt
+
+0x000001fb: 05 DW_LNS_set_column (27)
+0x000001fd: 06 DW_LNS_negate_stmt
+0x000001fe: 82 address += 8,  line += 0
+            0x0000000000000196     76     27      1   0             0 
+
+0x000001ff: 05 DW_LNS_set_column (35)
+0x00000201: 2e address += 2,  line += 0
+            0x0000000000000198     76     35      1   0             0 
+
+0x00000202: 05 DW_LNS_set_column (27)
+0x00000204: 90 address += 9,  line += 0
+            0x00000000000001a1     76     27      1   0             0 
+
+0x00000205: 05 DW_LNS_set_column (25)
+0x00000207: 58 address += 5,  line += 0
+            0x00000000000001a6     76     25      1   0             0 
+
+0x00000208: 05 DW_LNS_set_column (27)
+0x0000020a: 06 DW_LNS_negate_stmt
+0x0000020b: 3b address += 3,  line += -1
+            0x00000000000001a9     75     27      1   0             0  is_stmt
+
+0x0000020c: 05 DW_LNS_set_column (13)
+0x0000020e: 06 DW_LNS_negate_stmt
+0x0000020f: 58 address += 5,  line += 0
+            0x00000000000001ae     75     13      1   0             0 
+
+0x00000210: 05 DW_LNS_set_column (0)
+0x00000212: 03 DW_LNS_advance_line (0)
+0x00000215: 3c address += 3,  line += 0
+            0x00000000000001b1      0      0      1   0             0 
+
+0x00000216: 05 DW_LNS_set_column (13)
+0x00000218: 06 DW_LNS_negate_stmt
+0x00000219: 03 DW_LNS_advance_line (77)
+0x0000021c: 58 address += 5,  line += 0
+            0x00000000000001b6     77     13      1   0             0  is_stmt
+
+0x0000021d: 05 DW_LNS_set_column (22)
+0x0000021f: 06 DW_LNS_negate_stmt
+0x00000220: 82 address += 8,  line += 0
+            0x00000000000001be     77     22      1   0             0 
+
+0x00000221: 05 DW_LNS_set_column (16)
+0x00000223: 06 DW_LNS_negate_stmt
+0x00000224: 5a address += 5,  line += 2
+            0x00000000000001c3     79     16      1   0             0  is_stmt
+
+0x00000225: 05 DW_LNS_set_column (14)
+0x00000227: 06 DW_LNS_negate_stmt
+0x00000228: 82 address += 8,  line += 0
+            0x00000000000001cb     79     14      1   0             0 
+
+0x00000229: 05 DW_LNS_set_column (25)
+0x0000022b: e4 address += 15,  line += 0
+            0x00000000000001da     79     25      1   0             0 
+
+0x0000022c: 05 DW_LNS_set_column (11)
+0x0000022e: 06 DW_LNS_negate_stmt
+0x0000022f: 76 address += 7,  line += 2
+            0x00000000000001e1     81     11      1   0             0  is_stmt
+
+0x00000230: 05 DW_LNS_set_column (16)
+0x00000232: 03 DW_LNS_advance_line (66)
+0x00000234: 58 address += 5,  line += 0
+            0x00000000000001e6     66     16      1   0             0  is_stmt
+
+0x00000235: 05 DW_LNS_set_column (22)
+0x00000237: 7c address += 7,  line += 8
+            0x00000000000001ed     74     22      1   0             0  is_stmt
+
+0x00000238: 05 DW_LNS_set_column (4)
+0x0000023a: 03 DW_LNS_advance_line (37)
+0x0000023c: 90 address += 9,  line += 0
+            0x00000000000001f6     37      4      1   0             0  is_stmt
+
+0x0000023d: 3e address += 3,  line += 2
+            0x00000000000001f9     39      4      1   0             0  is_stmt
+
+0x0000023e: 05 DW_LNS_set_column (16)
+0x00000240: 06 DW_LNS_negate_stmt
+0x00000241: 2e address += 2,  line += 0
+            0x00000000000001fb     39     16      1   0             0 
+
+0x00000242: 05 DW_LNS_set_column (4)
+0x00000244: 90 address += 9,  line += 0
+            0x0000000000000204     39      4      1   0             0 
+
+0x00000245: 05 DW_LNS_set_column (23)
+0x00000247: 2e address += 2,  line += 0
+            0x0000000000000206     39     23      1   0             0 
+
+0x00000248: 05 DW_LNS_set_column (19)
+0x0000024a: 58 address += 5,  line += 0
+            0x000000000000020b     39     19      1   0             0 
+
+0x0000024b: 05 DW_LNS_set_column (4)
+0x0000024d: 06 DW_LNS_negate_stmt
+0x0000024e: 59 address += 5,  line += 1
+            0x0000000000000210     40      4      1   0             0  is_stmt
+
+0x0000024f: 05 DW_LNS_set_column (17)
+0x00000251: 06 DW_LNS_negate_stmt
+0x00000252: 82 address += 8,  line += 0
+            0x0000000000000218     40     17      1   0             0 
+
+0x00000253: 03 DW_LNS_advance_line (0)
+0x00000255: 74 address += 7,  line += 0
+            0x000000000000021f      0     17      1   0             0 
+
+0x00000256: 05 DW_LNS_set_column (16)
+0x00000258: 06 DW_LNS_negate_stmt
+0x00000259: 03 DW_LNS_advance_line (44)
+0x0000025b: 90 address += 9,  line += 0
+            0x0000000000000228     44     16      1   0             0  is_stmt
+
+0x0000025c: 06 DW_LNS_negate_stmt
+0x0000025d: 03 DW_LNS_advance_line (0)
+0x0000025f: 74 address += 7,  line += 0
+            0x000000000000022f      0     16      1   0             0 
+
+0x00000260: 05 DW_LNS_set_column (10)
+0x00000262: 06 DW_LNS_negate_stmt
+0x00000263: 03 DW_LNS_advance_line (45)
+0x00000265: 2e address += 2,  line += 0
+            0x0000000000000231     45     10      1   0             0  is_stmt
+
+0x00000266: 05 DW_LNS_set_column (18)
+0x00000268: 06 DW_LNS_negate_stmt
+0x00000269: 2e address += 2,  line += 0
+            0x0000000000000233     45     18      1   0             0 
+
+0x0000026a: 05 DW_LNS_set_column (10)
+0x0000026c: 90 address += 9,  line += 0
+            0x000000000000023c     45     10      1   0             0 
+
+0x0000026d: 05 DW_LNS_set_column (23)
+0x0000026f: 2e address += 2,  line += 0
+            0x000000000000023e     45     23      1   0             0 
+
+0x00000270: 05 DW_LNS_set_column (16)
+0x00000272: 06 DW_LNS_negate_stmt
+0x00000273: 57 address += 5,  line += -1
+            0x0000000000000243     44     16      1   0             0  is_stmt
+
+0x00000274: 06 DW_LNS_negate_stmt
+0x00000275: 03 DW_LNS_advance_line (0)
+0x00000277: e4 address += 15,  line += 0
+            0x0000000000000252      0     16      1   0             0 
+
+0x00000278: 05 DW_LNS_set_column (11)
+0x0000027a: 06 DW_LNS_negate_stmt
+0x0000027b: 03 DW_LNS_advance_line (46)
+0x0000027d: 2e address += 2,  line += 0
+            0x0000000000000254     46     11      1   0             0  is_stmt
+
+0x0000027e: 05 DW_LNS_set_column (28)
+0x00000280: 06 DW_LNS_negate_stmt
+0x00000281: ba address += 12,  line += 0
+            0x0000000000000260     46     28      1   0             0 
+
+0x00000282: 05 DW_LNS_set_column (41)
+0x00000284: 58 address += 5,  line += 0
+            0x0000000000000265     46     41      1   0             0 
+
+0x00000285: 05 DW_LNS_set_column (14)
+0x00000287: 06 DW_LNS_negate_stmt
+0x00000288: 5c address += 5,  line += 4
+            0x000000000000026a     50     14      1   0             0  is_stmt
+
+0x00000289: 06 DW_LNS_negate_stmt
+0x0000028a: 03 DW_LNS_advance_line (0)
+0x0000028c: 74 address += 7,  line += 0
+            0x0000000000000271      0     14      1   0             0 
+
+0x0000028d: 05 DW_LNS_set_column (38)
+0x0000028f: 06 DW_LNS_negate_stmt
+0x00000290: 03 DW_LNS_advance_line (52)
+0x00000292: ba address += 12,  line += 0
+            0x000000000000027d     52     38      1   0             0  is_stmt
+
+0x00000293: 05 DW_LNS_set_column (0)
+0x00000295: 06 DW_LNS_negate_stmt
+0x00000296: 03 DW_LNS_advance_line (0)
+0x00000298: 74 address += 7,  line += 0
+            0x0000000000000284      0      0      1   0             0 
+
+0x00000299: 05 DW_LNS_set_column (22)
+0x0000029b: 06 DW_LNS_negate_stmt
+0x0000029c: 03 DW_LNS_advance_line (53)
+0x0000029e: c8 address += 13,  line += 0
+            0x0000000000000291     53     22      1   0             0  is_stmt
+
+0x0000029f: 05 DW_LNS_set_column (24)
+0x000002a1: e5 address += 15,  line += 1
+            0x00000000000002a0     54     24      1   0             0  is_stmt
+
+0x000002a2: 05 DW_LNS_set_column (26)
+0x000002a4: 06 DW_LNS_negate_stmt
+0x000002a5: 2e address += 2,  line += 0
+            0x00000000000002a2     54     26      1   0             0 
+
+0x000002a6: 05 DW_LNS_set_column (24)
+0x000002a8: c8 address += 13,  line += 0
+            0x00000000000002af     54     24      1   0             0 
+
+0x000002a9: 06 DW_LNS_negate_stmt
+0x000002aa: 3d address += 3,  line += 1
+            0x00000000000002b2     55     24      1   0             0  is_stmt
+
+0x000002ab: 05 DW_LNS_set_column (44)
+0x000002ad: 71 address += 7,  line += -3
+            0x00000000000002b9     52     44      1   0             0  is_stmt
+
+0x000002ae: 06 DW_LNS_negate_stmt
+0x000002af: 03 DW_LNS_advance_line (0)
+0x000002b1: 58 address += 5,  line += 0
+            0x00000000000002be      0     44      1   0             0 
+
+0x000002b2: 05 DW_LNS_set_column (38)
+0x000002b4: 03 DW_LNS_advance_line (52)
+0x000002b6: 74 address += 7,  line += 0
+            0x00000000000002c5     52     38      1   0             0 
+
+0x000002b7: 03 DW_LNS_advance_line (0)
+0x000002b9: 58 address += 5,  line += 0
+            0x00000000000002ca      0     38      1   0             0 
+
+0x000002ba: 05 DW_LNS_set_column (19)
+0x000002bc: 06 DW_LNS_negate_stmt
+0x000002bd: 03 DW_LNS_advance_line (58)
+0x000002bf: 2e address += 2,  line += 0
+            0x00000000000002cc     58     19      1   0             0  is_stmt
+
+0x000002c0: 05 DW_LNS_set_column (21)
+0x000002c2: e5 address += 15,  line += 1
+            0x00000000000002db     59     21      1   0             0  is_stmt
+
+0x000002c3: 05 DW_LNS_set_column (18)
+0x000002c5: 72 address += 7,  line += -2
+            0x00000000000002e2     57     18      1   0             0  is_stmt
+
+0x000002c6: 05 DW_LNS_set_column (0)
+0x000002c8: 06 DW_LNS_negate_stmt
+0x000002c9: 03 DW_LNS_advance_line (0)
+0x000002cb: 74 address += 7,  line += 0
+            0x00000000000002e9      0      0      1   0             0 
+
+0x000002cc: 05 DW_LNS_set_column (14)
+0x000002ce: 06 DW_LNS_negate_stmt
+0x000002cf: 03 DW_LNS_advance_line (62)
+0x000002d1: 90 address += 9,  line += 0
+            0x00000000000002f2     62     14      1   0             0  is_stmt
+
+0x000002d2: 05 DW_LNS_set_column (23)
+0x000002d4: 06 DW_LNS_negate_stmt
+0x000002d5: 4a address += 4,  line += 0
+            0x00000000000002f6     62     23      1   0             0 
+
+0x000002d6: 05 DW_LNS_set_column (14)
+0x000002d8: 58 address += 5,  line += 0
+            0x00000000000002fb     62     14      1   0             0 
+
+0x000002d9: 03 DW_LNS_advance_line (0)
+0x000002db: 3c address += 3,  line += 0
+            0x00000000000002fe      0     14      1   0             0 
+
+0x000002dc: 05 DW_LNS_set_column (16)
+0x000002de: 06 DW_LNS_negate_stmt
+0x000002df: 03 DW_LNS_advance_line (66)
+0x000002e2: 20 address += 1,  line += 0
+            0x00000000000002ff     66     16      1   0             0  is_stmt
+
+0x000002e3: 06 DW_LNS_negate_stmt
+0x000002e4: 03 DW_LNS_advance_line (0)
+0x000002e7: 74 address += 7,  line += 0
+            0x0000000000000306      0     16      1   0             0 
+
+0x000002e8: 05 DW_LNS_set_column (27)
+0x000002ea: 06 DW_LNS_negate_stmt
+0x000002eb: 03 DW_LNS_advance_line (75)
+0x000002ee: 82 address += 8,  line += 0
+            0x000000000000030e     75     27      1   0             0  is_stmt
+
+0x000002ef: 06 DW_LNS_negate_stmt
+0x000002f0: 03 DW_LNS_advance_line (0)
+0x000002f3: 74 address += 7,  line += 0
+            0x0000000000000315      0     27      1   0             0 
+
+0x000002f4: 05 DW_LNS_set_column (16)
+0x000002f6: 06 DW_LNS_negate_stmt
+0x000002f7: 03 DW_LNS_advance_line (76)
+0x000002fa: 2e address += 2,  line += 0
+            0x0000000000000317     76     16      1   0             0  is_stmt
+
+0x000002fb: 05 DW_LNS_set_column (27)
+0x000002fd: 06 DW_LNS_negate_stmt
+0x000002fe: 82 address += 8,  line += 0
+            0x000000000000031f     76     27      1   0             0 
+
+0x000002ff: 05 DW_LNS_set_column (35)
+0x00000301: 2e address += 2,  line += 0
+            0x0000000000000321     76     35      1   0             0 
+
+0x00000302: 05 DW_LNS_set_column (27)
+0x00000304: 90 address += 9,  line += 0
+            0x000000000000032a     76     27      1   0             0 
+
+0x00000305: 05 DW_LNS_set_column (25)
+0x00000307: 58 address += 5,  line += 0
+            0x000000000000032f     76     25      1   0             0 
+
+0x00000308: 05 DW_LNS_set_column (27)
+0x0000030a: 06 DW_LNS_negate_stmt
+0x0000030b: 3b address += 3,  line += -1
+            0x0000000000000332     75     27      1   0             0  is_stmt
+
+0x0000030c: 06 DW_LNS_negate_stmt
+0x0000030d: 03 DW_LNS_advance_line (0)
+0x00000310: 74 address += 7,  line += 0
+            0x0000000000000339      0     27      1   0             0 
+
+0x00000311: 05 DW_LNS_set_column (13)
+0x00000313: 06 DW_LNS_negate_stmt
+0x00000314: 03 DW_LNS_advance_line (77)
+0x00000317: 66 address += 6,  line += 0
+            0x000000000000033f     77     13      1   0             0  is_stmt
+
+0x00000318: 05 DW_LNS_set_column (22)
+0x0000031a: 06 DW_LNS_negate_stmt
+0x0000031b: 82 address += 8,  line += 0
+            0x0000000000000347     77     22      1   0             0 
+
+0x0000031c: 05 DW_LNS_set_column (16)
+0x0000031e: 06 DW_LNS_negate_stmt
+0x0000031f: 5a address += 5,  line += 2
+            0x000000000000034c     79     16      1   0             0  is_stmt
+
+0x00000320: 05 DW_LNS_set_column (14)
+0x00000322: 06 DW_LNS_negate_stmt
+0x00000323: 82 address += 8,  line += 0
+            0x0000000000000354     79     14      1   0             0 
+
+0x00000324: 05 DW_LNS_set_column (25)
+0x00000326: e4 address += 15,  line += 0
+            0x0000000000000363     79     25      1   0             0 
+
+0x00000327: 05 DW_LNS_set_column (11)
+0x00000329: 06 DW_LNS_negate_stmt
+0x0000032a: 76 address += 7,  line += 2
+            0x000000000000036a     81     11      1   0             0  is_stmt
+
+0x0000032b: 05 DW_LNS_set_column (16)
+0x0000032d: 03 DW_LNS_advance_line (66)
+0x0000032f: 58 address += 5,  line += 0
+            0x000000000000036f     66     16      1   0             0  is_stmt
+
+0x00000330: 05 DW_LNS_set_column (22)
+0x00000332: 7c address += 7,  line += 8
+            0x0000000000000376     74     22      1   0             0  is_stmt
+
+0x00000333: 06 DW_LNS_negate_stmt
+0x00000334: 03 DW_LNS_advance_line (0)
+0x00000337: 90 address += 9,  line += 0
+            0x000000000000037f      0     22      1   0             0 
+
+0x00000338: 05 DW_LNS_set_column (13)
+0x0000033a: 06 DW_LNS_negate_stmt
+0x0000033b: 03 DW_LNS_advance_line (67)
+0x0000033e: 3c address += 3,  line += 0
+            0x0000000000000382     67     13      1   0             0  is_stmt
+
+0x0000033f: 83 address += 8,  line += 1
+            0x000000000000038a     68     13      1   0             0  is_stmt
+
+0x00000340: 83 address += 8,  line += 1
+            0x0000000000000392     69     13      1   0             0  is_stmt
+
+0x00000341: 83 address += 8,  line += 1
+            0x000000000000039a     70     13      1   0             0  is_stmt
+
+0x00000342: 02 DW_LNS_advance_pc (3)
+0x00000344: 00 DW_LNE_end_sequence
+            0x000000000000039d     70     13      1   0             0  is_stmt end_sequence
+
+0x00000347: 00 DW_LNE_set_address (0x000000000000039f)
+0x0000034e: 03 DW_LNS_advance_line (152)
+0x00000351: 01 DW_LNS_copy
+            0x000000000000039f    152      0      1   0             0  is_stmt
+
+
+0x00000352: 05 DW_LNS_set_column (17)
+0x00000354: 0a DW_LNS_set_prologue_end
+0x00000355: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000356: 91 address += 9,  line += 1
+            0x00000000000003b9    153     17      1   0             0  is_stmt prologue_end
+
+0x00000357: 05 DW_LNS_set_column (12)
+0x00000359: 06 DW_LNS_negate_stmt
+0x0000035a: 58 address += 5,  line += 0
+            0x00000000000003be    153     12      1   0             0 
+
+0x0000035b: 03 DW_LNS_advance_line (0)
+0x0000035e: 2e address += 2,  line += 0
+            0x00000000000003c0      0     12      1   0             0 
+
+0x0000035f: 05 DW_LNS_set_column (28)
+0x00000361: 03 DW_LNS_advance_line (153)
+0x00000364: 4a address += 4,  line += 0
+            0x00000000000003c4    153     28      1   0             0 
+
+0x00000365: 05 DW_LNS_set_column (23)
+0x00000367: 58 address += 5,  line += 0
+            0x00000000000003c9    153     23      1   0             0 
+
+0x00000368: 03 DW_LNS_advance_line (0)
+0x0000036b: 66 address += 6,  line += 0
+            0x00000000000003cf      0     23      1   0             0 
+
+0x0000036c: 05 DW_LNS_set_column (10)
+0x0000036e: 06 DW_LNS_negate_stmt
+0x0000036f: 03 DW_LNS_advance_line (155)
+0x00000372: 4a address += 4,  line += 0
+            0x00000000000003d3    155     10      1   0             0  is_stmt
+
+0x00000373: 05 DW_LNS_set_column (8)
+0x00000375: 06 DW_LNS_negate_stmt
+0x00000376: 20 address += 1,  line += 0
+            0x00000000000003d4    155      8      1   0             0 
+
+0x00000377: 03 DW_LNS_advance_line (0)
+0x0000037a: 2e address += 2,  line += 0
+            0x00000000000003d6      0      8      1   0             0 
+
+0x0000037b: 05 DW_LNS_set_column (7)
+0x0000037d: 06 DW_LNS_negate_stmt
+0x0000037e: 03 DW_LNS_advance_line (156)
+0x00000381: 20 address += 1,  line += 0
+            0x00000000000003d7    156      7      1   0             0  is_stmt
+
+0x00000382: 06 DW_LNS_negate_stmt
+0x00000383: 03 DW_LNS_advance_line (0)
+0x00000386: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000387: 2e address += 2,  line += 0
+            0x00000000000003ea      0      7      1   0             0 
+
+0x00000388: 05 DW_LNS_set_column (18)
+0x0000038a: 06 DW_LNS_negate_stmt
+0x0000038b: 03 DW_LNS_advance_line (94)
+0x0000038e: 3c address += 3,  line += 0
+            0x00000000000003ed     94     18      1   0             0  is_stmt
+
+0x0000038f: 05 DW_LNS_set_column (4)
+0x00000391: 06 DW_LNS_negate_stmt
+0x00000392: 58 address += 5,  line += 0
+            0x00000000000003f2     94      4      1   0             0 
+
+0x00000393: 03 DW_LNS_advance_line (0)
+0x00000396: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000397: 12 address += 0,  line += 0
+            0x0000000000000403      0      4      1   0             0 
+
+0x00000398: 05 DW_LNS_set_column (29)
+0x0000039a: 06 DW_LNS_negate_stmt
+0x0000039b: 03 DW_LNS_advance_line (95)
+0x0000039e: 4a address += 4,  line += 0
+            0x0000000000000407     95     29      1   0             0  is_stmt
+
+0x0000039f: 05 DW_LNS_set_column (19)
+0x000003a1: 69 address += 6,  line += 3
+            0x000000000000040d     98     19      1   0             0  is_stmt
+
+0x000003a2: 05 DW_LNS_set_column (16)
+0x000003a4: 73 address += 7,  line += -1
+            0x0000000000000414     97     16      1   0             0  is_stmt
+
+0x000003a5: 73 address += 7,  line += -1
+            0x000000000000041b     96     16      1   0             0  is_stmt
+
+0x000003a6: 06 DW_LNS_negate_stmt
+0x000003a7: 03 DW_LNS_advance_line (0)
+0x000003aa: 74 address += 7,  line += 0
+            0x0000000000000422      0     16      1   0             0 
+
+0x000003ab: 05 DW_LNS_set_column (28)
+0x000003ad: 06 DW_LNS_negate_stmt
+0x000003ae: 03 DW_LNS_advance_line (94)
+0x000003b1: 4a address += 4,  line += 0
+            0x0000000000000426     94     28      1   0             0  is_stmt
+
+0x000003b2: 05 DW_LNS_set_column (18)
+0x000003b4: 06 DW_LNS_negate_stmt
+0x000003b5: 58 address += 5,  line += 0
+            0x000000000000042b     94     18      1   0             0 
+
+0x000003b6: 05 DW_LNS_set_column (4)
+0x000003b8: 58 address += 5,  line += 0
+            0x0000000000000430     94      4      1   0             0 
+
+0x000003b9: 03 DW_LNS_advance_line (0)
+0x000003bc: 4a address += 4,  line += 0
+            0x0000000000000434      0      4      1   0             0 
+
+0x000003bd: 05 DW_LNS_set_column (27)
+0x000003bf: 06 DW_LNS_negate_stmt
+0x000003c0: 03 DW_LNS_advance_line (102)
+0x000003c3: 4a address += 4,  line += 0
+            0x0000000000000438    102     27      1   0             0  is_stmt
+
+0x000003c4: 05 DW_LNS_set_column (18)
+0x000003c6: 06 DW_LNS_negate_stmt
+0x000003c7: 58 address += 5,  line += 0
+            0x000000000000043d    102     18      1   0             0 
+
+0x000003c8: 06 DW_LNS_negate_stmt
+0x000003c9: 9f address += 10,  line += 1
+            0x0000000000000447    103     18      1   0             0  is_stmt
+
+0x000003ca: 06 DW_LNS_negate_stmt
+0x000003cb: 03 DW_LNS_advance_line (0)
+0x000003ce: 9e address += 10,  line += 0
+            0x0000000000000451      0     18      1   0             0 
+
+0x000003cf: 06 DW_LNS_negate_stmt
+0x000003d0: 03 DW_LNS_advance_line (105)
+0x000003d3: 82 address += 8,  line += 0
+            0x0000000000000459    105     18      1   0             0  is_stmt
+
+0x000003d4: 05 DW_LNS_set_column (4)
+0x000003d6: 06 DW_LNS_negate_stmt
+0x000003d7: 58 address += 5,  line += 0
+            0x000000000000045e    105      4      1   0             0 
+
+0x000003d8: 03 DW_LNS_advance_line (0)
+0x000003db: 2e address += 2,  line += 0
+            0x0000000000000460      0      4      1   0             0 
+
+0x000003dc: 05 DW_LNS_set_column (7)
+0x000003de: 06 DW_LNS_negate_stmt
+0x000003df: 03 DW_LNS_advance_line (106)
+0x000003e2: 2e address += 2,  line += 0
+            0x0000000000000462    106      7      1   0             0  is_stmt
+
+0x000003e3: 05 DW_LNS_set_column (16)
+0x000003e5: 06 DW_LNS_negate_stmt
+0x000003e6: 82 address += 8,  line += 0
+            0x000000000000046a    106     16      1   0             0 
+
+0x000003e7: 05 DW_LNS_set_column (24)
+0x000003e9: 06 DW_LNS_negate_stmt
+0x000003ea: 57 address += 5,  line += -1
+            0x000000000000046f    105     24      1   0             0  is_stmt
+
+0x000003eb: 05 DW_LNS_set_column (18)
+0x000003ed: 06 DW_LNS_negate_stmt
+0x000003ee: 58 address += 5,  line += 0
+            0x0000000000000474    105     18      1   0             0 
+
+0x000003ef: 03 DW_LNS_advance_line (0)
+0x000003f2: 74 address += 7,  line += 0
+            0x000000000000047b      0     18      1   0             0 
+
+0x000003f3: 05 DW_LNS_set_column (13)
+0x000003f5: 06 DW_LNS_negate_stmt
+0x000003f6: 03 DW_LNS_advance_line (112)
+0x000003f9: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000003fa: d6 address += 14,  line += 0
+            0x000000000000049a    112     13      1   0             0  is_stmt
+
+0x000003fb: 05 DW_LNS_set_column (26)
+0x000003fd: 06 DW_LNS_negate_stmt
+0x000003fe: 2e address += 2,  line += 0
+            0x000000000000049c    112     26      1   0             0 
+
+0x000003ff: 05 DW_LNS_set_column (35)
+0x00000401: c8 address += 13,  line += 0
+            0x00000000000004a9    112     35      1   0             0 
+
+0x00000402: 05 DW_LNS_set_column (13)
+0x00000404: 20 address += 1,  line += 0
+            0x00000000000004aa    112     13      1   0             0 
+
+0x00000405: 05 DW_LNS_set_column (30)
+0x00000407: 06 DW_LNS_negate_stmt
+0x00000408: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000409: 49 address += 4,  line += -1
+            0x00000000000004bf    111     30      1   0             0  is_stmt
+
+0x0000040a: 05 DW_LNS_set_column (24)
+0x0000040c: 06 DW_LNS_negate_stmt
+0x0000040d: 58 address += 5,  line += 0
+            0x00000000000004c4    111     24      1   0             0 
+
+0x0000040e: 05 DW_LNS_set_column (10)
+0x00000410: 58 address += 5,  line += 0
+            0x00000000000004c9    111     10      1   0             0 
+
+0x00000411: 06 DW_LNS_negate_stmt
+0x00000412: 5a address += 5,  line += 2
+            0x00000000000004ce    113     10      1   0             0  is_stmt
+
+0x00000413: 06 DW_LNS_negate_stmt
+0x00000414: 03 DW_LNS_advance_line (0)
+0x00000417: 74 address += 7,  line += 0
+            0x00000000000004d5      0     10      1   0             0 
+
+0x00000418: 05 DW_LNS_set_column (16)
+0x0000041a: 06 DW_LNS_negate_stmt
+0x0000041b: 03 DW_LNS_advance_line (118)
+0x0000041e: 2e address += 2,  line += 0
+            0x00000000000004d7    118     16      1   0             0  is_stmt
+
+0x0000041f: 05 DW_LNS_set_column (7)
+0x00000421: 06 DW_LNS_negate_stmt
+0x00000422: 58 address += 5,  line += 0
+            0x00000000000004dc    118      7      1   0             0 
+
+0x00000423: 03 DW_LNS_advance_line (0)
+0x00000426: 2e address += 2,  line += 0
+            0x00000000000004de      0      7      1   0             0 
+
+0x00000427: 05 DW_LNS_set_column (10)
+0x00000429: 06 DW_LNS_negate_stmt
+0x0000042a: 03 DW_LNS_advance_line (119)
+0x0000042d: 2e address += 2,  line += 0
+            0x00000000000004e0    119     10      1   0             0  is_stmt
+
+0x0000042e: 05 DW_LNS_set_column (18)
+0x00000430: 06 DW_LNS_negate_stmt
+0x00000431: 2e address += 2,  line += 0
+            0x00000000000004e2    119     18      1   0             0 
+
+0x00000432: 05 DW_LNS_set_column (10)
+0x00000434: 90 address += 9,  line += 0
+            0x00000000000004eb    119     10      1   0             0 
+
+0x00000435: 05 DW_LNS_set_column (23)
+0x00000437: 2e address += 2,  line += 0
+            0x00000000000004ed    119     23      1   0             0 
+
+0x00000438: 05 DW_LNS_set_column (16)
+0x0000043a: 06 DW_LNS_negate_stmt
+0x0000043b: 57 address += 5,  line += -1
+            0x00000000000004f2    118     16      1   0             0  is_stmt
+
+0x0000043c: 05 DW_LNS_set_column (7)
+0x0000043e: 06 DW_LNS_negate_stmt
+0x0000043f: ac address += 11,  line += 0
+            0x00000000000004fd    118      7      1   0             0 
+
+0x00000440: 05 DW_LNS_set_column (16)
+0x00000442: 06 DW_LNS_negate_stmt
+0x00000443: 6a address += 6,  line += 4
+            0x0000000000000503    122     16      1   0             0  is_stmt
+
+0x00000444: 06 DW_LNS_negate_stmt
+0x00000445: 03 DW_LNS_advance_line (0)
+0x00000448: 74 address += 7,  line += 0
+            0x000000000000050a      0     16      1   0             0 
+
+0x00000449: 05 DW_LNS_set_column (22)
+0x0000044b: 06 DW_LNS_negate_stmt
+0x0000044c: 03 DW_LNS_advance_line (125)
+0x0000044f: c8 address += 13,  line += 0
+            0x0000000000000517    125     22      1   0             0  is_stmt
+
+0x00000450: 06 DW_LNS_negate_stmt
+0x00000451: 03 DW_LNS_advance_line (0)
+0x00000454: 74 address += 7,  line += 0
+            0x000000000000051e      0     22      1   0             0 
+
+0x00000455: 05 DW_LNS_set_column (27)
+0x00000457: 06 DW_LNS_negate_stmt
+0x00000458: 03 DW_LNS_advance_line (126)
+0x0000045b: 2e address += 2,  line += 0
+            0x0000000000000520    126     27      1   0             0  is_stmt
+
+0x0000045c: 05 DW_LNS_set_column (13)
+0x0000045e: 06 DW_LNS_negate_stmt
+0x0000045f: 58 address += 5,  line += 0
+            0x0000000000000525    126     13      1   0             0 
+
+0x00000460: 03 DW_LNS_advance_line (0)
+0x00000463: 2e address += 2,  line += 0
+            0x0000000000000527      0     13      1   0             0 
+
+0x00000464: 05 DW_LNS_set_column (16)
+0x00000466: 06 DW_LNS_negate_stmt
+0x00000467: 03 DW_LNS_advance_line (127)
+0x0000046a: 2e address += 2,  line += 0
+            0x0000000000000529    127     16      1   0             0  is_stmt
+
+0x0000046b: 05 DW_LNS_set_column (27)
+0x0000046d: 06 DW_LNS_negate_stmt
+0x0000046e: 82 address += 8,  line += 0
+            0x0000000000000531    127     27      1   0             0 
+
+0x0000046f: 05 DW_LNS_set_column (35)
+0x00000471: 2e address += 2,  line += 0
+            0x0000000000000533    127     35      1   0             0 
+
+0x00000472: 05 DW_LNS_set_column (27)
+0x00000474: 90 address += 9,  line += 0
+            0x000000000000053c    127     27      1   0             0 
+
+0x00000475: 05 DW_LNS_set_column (25)
+0x00000477: 58 address += 5,  line += 0
+            0x0000000000000541    127     25      1   0             0 
+
+0x00000478: 05 DW_LNS_set_column (27)
+0x0000047a: 06 DW_LNS_negate_stmt
+0x0000047b: 3b address += 3,  line += -1
+            0x0000000000000544    126     27      1   0             0  is_stmt
+
+0x0000047c: 05 DW_LNS_set_column (13)
+0x0000047e: 06 DW_LNS_negate_stmt
+0x0000047f: 58 address += 5,  line += 0
+            0x0000000000000549    126     13      1   0             0 
+
+0x00000480: 05 DW_LNS_set_column (0)
+0x00000482: 03 DW_LNS_advance_line (0)
+0x00000485: 3c address += 3,  line += 0
+            0x000000000000054c      0      0      1   0             0 
+
+0x00000486: 05 DW_LNS_set_column (13)
+0x00000488: 06 DW_LNS_negate_stmt
+0x00000489: 03 DW_LNS_advance_line (128)
+0x0000048c: 58 address += 5,  line += 0
+            0x0000000000000551    128     13      1   0             0  is_stmt
+
+0x0000048d: 05 DW_LNS_set_column (22)
+0x0000048f: 06 DW_LNS_negate_stmt
+0x00000490: 82 address += 8,  line += 0
+            0x0000000000000559    128     22      1   0             0 
+
+0x00000491: 05 DW_LNS_set_column (16)
+0x00000493: 06 DW_LNS_negate_stmt
+0x00000494: 5a address += 5,  line += 2
+            0x000000000000055e    130     16      1   0             0  is_stmt
+
+0x00000495: 05 DW_LNS_set_column (14)
+0x00000497: 06 DW_LNS_negate_stmt
+0x00000498: 82 address += 8,  line += 0
+            0x0000000000000566    130     14      1   0             0 
+
+0x00000499: 05 DW_LNS_set_column (25)
+0x0000049b: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x0000049c: 12 address += 0,  line += 0
+            0x0000000000000577    130     25      1   0             0 
+
+0x0000049d: 05 DW_LNS_set_column (14)
+0x0000049f: 58 address += 5,  line += 0
+            0x000000000000057c    130     14      1   0             0 
+
+0x000004a0: 05 DW_LNS_set_column (11)
+0x000004a2: 06 DW_LNS_negate_stmt
+0x000004a3: 31 address += 2,  line += 3
+            0x000000000000057e    133     11      1   0             0  is_stmt
+
+0x000004a4: 05 DW_LNS_set_column (16)
+0x000004a6: 03 DW_LNS_advance_line (122)
+0x000004a8: 58 address += 5,  line += 0
+            0x0000000000000583    122     16      1   0             0  is_stmt
+
+0x000004a9: 05 DW_LNS_set_column (14)
+0x000004ab: 06 DW_LNS_negate_stmt
+0x000004ac: 58 address += 5,  line += 0
+            0x0000000000000588    122     14      1   0             0 
+
+0x000004ad: 03 DW_LNS_advance_line (0)
+0x000004b0: 4a address += 4,  line += 0
+            0x000000000000058c      0     14      1   0             0 
+
+0x000004b1: 06 DW_LNS_negate_stmt
+0x000004b2: 03 DW_LNS_advance_line (130)
+0x000004b5: 20 address += 1,  line += 0
+            0x000000000000058d    130     14      1   0             0  is_stmt
+
+0x000004b6: 05 DW_LNS_set_column (11)
+0x000004b8: 03 DW_LNS_advance_line (110)
+0x000004ba: 20 address += 1,  line += 0
+            0x000000000000058e    110     11      1   0             0  is_stmt
+
+0x000004bb: 06 DW_LNS_negate_stmt
+0x000004bc: 03 DW_LNS_advance_line (0)
+0x000004bf: 74 address += 7,  line += 0
+            0x0000000000000595      0     11      1   0             0 
+
+0x000004c0: 05 DW_LNS_set_column (10)
+0x000004c2: 06 DW_LNS_negate_stmt
+0x000004c3: 03 DW_LNS_advance_line (113)
+0x000004c6: 66 address += 6,  line += 0
+            0x000000000000059b    113     10      1   0             0  is_stmt
+
+0x000004c7: 06 DW_LNS_negate_stmt
+0x000004c8: 03 DW_LNS_advance_line (0)
+0x000004cb: 74 address += 7,  line += 0
+            0x00000000000005a2      0     10      1   0             0 
+
+0x000004cc: 05 DW_LNS_set_column (16)
+0x000004ce: 06 DW_LNS_negate_stmt
+0x000004cf: 03 DW_LNS_advance_line (118)
+0x000004d2: 2e address += 2,  line += 0
+            0x00000000000005a4    118     16      1   0             0  is_stmt
+
+0x000004d3: 05 DW_LNS_set_column (7)
+0x000004d5: 06 DW_LNS_negate_stmt
+0x000004d6: 58 address += 5,  line += 0
+            0x00000000000005a9    118      7      1   0             0 
+
+0x000004d7: 03 DW_LNS_advance_line (0)
+0x000004da: 2e address += 2,  line += 0
+            0x00000000000005ab      0      7      1   0             0 
+
+0x000004db: 05 DW_LNS_set_column (10)
+0x000004dd: 06 DW_LNS_negate_stmt
+0x000004de: 03 DW_LNS_advance_line (119)
+0x000004e1: 2e address += 2,  line += 0
+            0x00000000000005ad    119     10      1   0             0  is_stmt
+
+0x000004e2: 05 DW_LNS_set_column (18)
+0x000004e4: 06 DW_LNS_negate_stmt
+0x000004e5: 2e address += 2,  line += 0
+            0x00000000000005af    119     18      1   0             0 
+
+0x000004e6: 05 DW_LNS_set_column (10)
+0x000004e8: 90 address += 9,  line += 0
+            0x00000000000005b8    119     10      1   0             0 
+
+0x000004e9: 05 DW_LNS_set_column (23)
+0x000004eb: 2e address += 2,  line += 0
+            0x00000000000005ba    119     23      1   0             0 
+
+0x000004ec: 05 DW_LNS_set_column (16)
+0x000004ee: 06 DW_LNS_negate_stmt
+0x000004ef: 57 address += 5,  line += -1
+            0x00000000000005bf    118     16      1   0             0  is_stmt
+
+0x000004f0: 05 DW_LNS_set_column (0)
+0x000004f2: 06 DW_LNS_negate_stmt
+0x000004f3: 03 DW_LNS_advance_line (0)
+0x000004f6: 74 address += 7,  line += 0
+            0x00000000000005c6      0      0      1   0             0 
+
+0x000004f7: 05 DW_LNS_set_column (7)
+0x000004f9: 03 DW_LNS_advance_line (118)
+0x000004fc: 4a address += 4,  line += 0
+            0x00000000000005ca    118      7      1   0             0 
+
+0x000004fd: 05 DW_LNS_set_column (16)
+0x000004ff: 06 DW_LNS_negate_stmt
+0x00000500: 6a address += 6,  line += 4
+            0x00000000000005d0    122     16      1   0             0  is_stmt
+
+0x00000501: 05 DW_LNS_set_column (14)
+0x00000503: 06 DW_LNS_negate_stmt
+0x00000504: 58 address += 5,  line += 0
+            0x00000000000005d5    122     14      1   0             0 
+
+0x00000505: 03 DW_LNS_advance_line (0)
+0x00000508: 2e address += 2,  line += 0
+            0x00000000000005d7      0     14      1   0             0 
+
+0x00000509: 05 DW_LNS_set_column (22)
+0x0000050b: 06 DW_LNS_negate_stmt
+0x0000050c: 03 DW_LNS_advance_line (125)
+0x0000050f: 74 address += 7,  line += 0
+            0x00000000000005de    125     22      1   0             0  is_stmt
+
+0x00000510: 06 DW_LNS_negate_stmt
+0x00000511: 03 DW_LNS_advance_line (0)
+0x00000514: 90 address += 9,  line += 0
+            0x00000000000005e7      0     22      1   0             0 
+
+0x00000515: 05 DW_LNS_set_column (27)
+0x00000517: 06 DW_LNS_negate_stmt
+0x00000518: 03 DW_LNS_advance_line (126)
+0x0000051b: 66 address += 6,  line += 0
+            0x00000000000005ed    126     27      1   0             0  is_stmt
+
+0x0000051c: 05 DW_LNS_set_column (13)
+0x0000051e: 06 DW_LNS_negate_stmt
+0x0000051f: 58 address += 5,  line += 0
+            0x00000000000005f2    126     13      1   0             0 
+
+0x00000520: 03 DW_LNS_advance_line (0)
+0x00000523: 2e address += 2,  line += 0
+            0x00000000000005f4      0     13      1   0             0 
+
+0x00000524: 05 DW_LNS_set_column (16)
+0x00000526: 06 DW_LNS_negate_stmt
+0x00000527: 03 DW_LNS_advance_line (127)
+0x0000052a: 2e address += 2,  line += 0
+            0x00000000000005f6    127     16      1   0             0  is_stmt
+
+0x0000052b: 05 DW_LNS_set_column (27)
+0x0000052d: 06 DW_LNS_negate_stmt
+0x0000052e: 82 address += 8,  line += 0
+            0x00000000000005fe    127     27      1   0             0 
+
+0x0000052f: 05 DW_LNS_set_column (35)
+0x00000531: 2e address += 2,  line += 0
+            0x0000000000000600    127     35      1   0             0 
+
+0x00000532: 05 DW_LNS_set_column (27)
+0x00000534: 90 address += 9,  line += 0
+            0x0000000000000609    127     27      1   0             0 
+
+0x00000535: 05 DW_LNS_set_column (25)
+0x00000537: 58 address += 5,  line += 0
+            0x000000000000060e    127     25      1   0             0 
+
+0x00000538: 05 DW_LNS_set_column (27)
+0x0000053a: 06 DW_LNS_negate_stmt
+0x0000053b: 3b address += 3,  line += -1
+            0x0000000000000611    126     27      1   0             0  is_stmt
+
+0x0000053c: 05 DW_LNS_set_column (13)
+0x0000053e: 06 DW_LNS_negate_stmt
+0x0000053f: 58 address += 5,  line += 0
+            0x0000000000000616    126     13      1   0             0 
+
+0x00000540: 05 DW_LNS_set_column (0)
+0x00000542: 03 DW_LNS_advance_line (0)
+0x00000545: 3c address += 3,  line += 0
+            0x0000000000000619      0      0      1   0             0 
+
+0x00000546: 05 DW_LNS_set_column (13)
+0x00000548: 06 DW_LNS_negate_stmt
+0x00000549: 03 DW_LNS_advance_line (128)
+0x0000054c: 58 address += 5,  line += 0
+            0x000000000000061e    128     13      1   0             0  is_stmt
+
+0x0000054d: 05 DW_LNS_set_column (22)
+0x0000054f: 06 DW_LNS_negate_stmt
+0x00000550: 82 address += 8,  line += 0
+            0x0000000000000626    128     22      1   0             0 
+
+0x00000551: 05 DW_LNS_set_column (16)
+0x00000553: 06 DW_LNS_negate_stmt
+0x00000554: 5a address += 5,  line += 2
+            0x000000000000062b    130     16      1   0             0  is_stmt
+
+0x00000555: 05 DW_LNS_set_column (14)
+0x00000557: 06 DW_LNS_negate_stmt
+0x00000558: 82 address += 8,  line += 0
+            0x0000000000000633    130     14      1   0             0 
+
+0x00000559: 05 DW_LNS_set_column (25)
+0x0000055b: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x0000055c: 12 address += 0,  line += 0
+            0x0000000000000644    130     25      1   0             0 
+
+0x0000055d: 05 DW_LNS_set_column (14)
+0x0000055f: 58 address += 5,  line += 0
+            0x0000000000000649    130     14      1   0             0 
+
+0x00000560: 05 DW_LNS_set_column (11)
+0x00000562: 06 DW_LNS_negate_stmt
+0x00000563: 31 address += 2,  line += 3
+            0x000000000000064b    133     11      1   0             0  is_stmt
+
+0x00000564: 05 DW_LNS_set_column (16)
+0x00000566: 03 DW_LNS_advance_line (122)
+0x00000568: 58 address += 5,  line += 0
+            0x0000000000000650    122     16      1   0             0  is_stmt
+
+0x00000569: 05 DW_LNS_set_column (14)
+0x0000056b: 06 DW_LNS_negate_stmt
+0x0000056c: 58 address += 5,  line += 0
+            0x0000000000000655    122     14      1   0             0 
+
+0x0000056d: 03 DW_LNS_advance_line (0)
+0x00000570: 4a address += 4,  line += 0
+            0x0000000000000659      0     14      1   0             0 
+
+0x00000571: 06 DW_LNS_negate_stmt
+0x00000572: 03 DW_LNS_advance_line (130)
+0x00000575: 20 address += 1,  line += 0
+            0x000000000000065a    130     14      1   0             0  is_stmt
+
+0x00000576: 05 DW_LNS_set_column (11)
+0x00000578: 03 DW_LNS_advance_line (110)
+0x0000057a: 20 address += 1,  line += 0
+            0x000000000000065b    110     11      1   0             0  is_stmt
+
+0x0000057b: 05 DW_LNS_set_column (4)
+0x0000057d: 03 DW_LNS_advance_line (138)
+0x0000057f: 66 address += 6,  line += 0
+            0x0000000000000661    138      4      1   0             0  is_stmt
+
+0x00000580: 83 address += 8,  line += 1
+            0x0000000000000669    139      4      1   0             0  is_stmt
+
+0x00000581: 06 DW_LNS_negate_stmt
+0x00000582: 03 DW_LNS_advance_line (0)
+0x00000585: 82 address += 8,  line += 0
+            0x0000000000000671      0      4      1   0             0 
+
+0x00000586: 06 DW_LNS_negate_stmt
+0x00000587: 03 DW_LNS_advance_line (141)
+0x0000058a: 82 address += 8,  line += 0
+            0x0000000000000679    141      4      1   0             0  is_stmt
+
+0x0000058b: 06 DW_LNS_negate_stmt
+0x0000058c: 03 DW_LNS_advance_line (0)
+0x0000058f: 74 address += 7,  line += 0
+            0x0000000000000680      0      4      1   0             0 
+
+0x00000590: 05 DW_LNS_set_column (20)
+0x00000592: 06 DW_LNS_negate_stmt
+0x00000593: 03 DW_LNS_advance_line (142)
+0x00000596: 4a address += 4,  line += 0
+            0x0000000000000684    142     20      1   0             0  is_stmt
+
+0x00000597: be address += 12,  line += 4
+            0x0000000000000690    146     20      1   0             0  is_stmt
+
+0x00000598: 05 DW_LNS_set_column (7)
+0x0000059a: 75 address += 7,  line += 1
+            0x0000000000000697    147      7      1   0             0  is_stmt
+
+0x0000059b: 05 DW_LNS_set_column (11)
+0x0000059d: 7e address += 8,  line += -4
+            0x000000000000069f    143     11      1   0             0  is_stmt
+
+0x0000059e: 05 DW_LNS_set_column (20)
+0x000005a0: 06 DW_LNS_negate_stmt
+0x000005a1: 4a address += 4,  line += 0
+            0x00000000000006a3    143     20      1   0             0 
+
+0x000005a2: 05 DW_LNS_set_column (11)
+0x000005a4: 58 address += 5,  line += 0
+            0x00000000000006a8    143     11      1   0             0 
+
+0x000005a5: 03 DW_LNS_advance_line (0)
+0x000005a8: 3c address += 3,  line += 0
+            0x00000000000006ab      0     11      1   0             0 
+
+0x000005a9: 05 DW_LNS_set_column (4)
+0x000005ab: 06 DW_LNS_negate_stmt
+0x000005ac: 03 DW_LNS_advance_line (141)
+0x000005af: 4a address += 4,  line += 0
+            0x00000000000006af    141      4      1   0             0  is_stmt
+
+0x000005b0: 03 DW_LNS_advance_line (159)
+0x000005b2: 66 address += 6,  line += 0
+            0x00000000000006b5    159      4      1   0             0  is_stmt
+
+0x000005b3: 06 DW_LNS_negate_stmt
+0x000005b4: 03 DW_LNS_advance_line (0)
+0x000005b7: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000005b8: ba address += 12,  line += 0
+            0x00000000000006d2      0      4      1   0             0 
+
+0x000005b9: 05 DW_LNS_set_column (1)
+0x000005bb: 06 DW_LNS_negate_stmt
+0x000005bc: 03 DW_LNS_advance_line (161)
+0x000005bf: 20 address += 1,  line += 0
+            0x00000000000006d3    161      1      1   0             0  is_stmt
+
+0x000005c0: 02 DW_LNS_advance_pc (14)
+0x000005c2: 00 DW_LNE_end_sequence
+            0x00000000000006e1    161      1      1   0             0  is_stmt end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)"
+0x00000069: "/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp"
+0x000000a9: "/usr/local/google/home/azakai/Dev/2-binaryen"
+0x000000d6: "i"
+0x000000d8: "int"
+0x000000dc: "n"
+0x000000de: "next"
+0x000000e3: "worker_args"
+0x000000ef: "std"
+0x000000f3: "decltype(nullptr)"
+0x00000105: "nullptr_t"
+0x0000010f: "free"
+0x00000114: "_ZL8fannkuchi"
+0x00000122: "fannkuch"
+0x0000012b: "showmax"
+0x00000133: "args"
+0x00000138: "targs"
+0x0000013e: "perm1"
+0x00000144: "count"
+0x0000014a: "r"
+0x0000014c: "maxflips"
+0x00000155: "flips"
+0x0000015b: "cleanup"
+0x00000163: "p0"
+0x00000166: "_Z15fannkuch_workerPv"
+0x0000017c: "fannkuch_worker"
+0x0000018c: "main"
+0x00000191: "_arg"
+0x00000196: "perm"
+0x0000019b: "k"
+0x0000019d: "j"
+0x0000019f: "tmp"
+0x000001a3: "argc"
+0x000001a8: "argv"
+0x000001ad: "char"
+
+.debug_ranges contents:
+00000000 00000185 000001c3
+00000000 000001ed 000001f6
+00000000 0000030e 0000034c
+00000000 00000376 0000037f
+00000000 <End of list>
+00000028 00000517 0000055e
+00000028 000005de 0000062b
+00000028 <End of list>
+00000040 00000006 0000039d
+00000040 0000039f 000006e1
+00000040 <End of list>
+DWARF debug info
+================
+
+Contains section .debug_info (851 bytes)
+Contains section .debug_loc (1073 bytes)
+Contains section .debug_ranges (88 bytes)
+Contains section .debug_abbrev (333 bytes)
+Contains section .debug_line (2826 bytes)
+Contains section .debug_str (434 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[2] DW_TAG_pointer_type	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[3] DW_TAG_structure_type	DW_CHILDREN_yes
+	DW_AT_calling_convention	DW_FORM_data1
+	DW_AT_name	DW_FORM_strp
+	DW_AT_byte_size	DW_FORM_data1
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[4] DW_TAG_member	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_data_member_location	DW_FORM_data1
+
+[5] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+[6] DW_TAG_namespace	DW_CHILDREN_yes
+	DW_AT_name	DW_FORM_strp
+
+[7] DW_TAG_typedef	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[8] DW_TAG_unspecified_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+
+[9] DW_TAG_imported_declaration	DW_CHILDREN_no
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_import	DW_FORM_ref4
+
+[10] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[11] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[12] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[13] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[14] DW_TAG_lexical_block	DW_CHILDREN_yes
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[15] DW_TAG_GNU_call_site	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+
+[16] DW_TAG_GNU_call_site	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+	DW_AT_low_pc	DW_FORM_addr
+
+[17] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_declaration	DW_FORM_flag_present
+	DW_AT_external	DW_FORM_flag_present
+
+[18] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[19] DW_TAG_pointer_type	DW_CHILDREN_no
+
+[20] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_inline	DW_FORM_data1
+
+[21] DW_TAG_label	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[22] DW_TAG_lexical_block	DW_CHILDREN_yes
+
+[23] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[24] DW_TAG_inlined_subroutine	DW_CHILDREN_yes
+	DW_AT_abstract_origin	DW_FORM_ref4
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_call_file	DW_FORM_data1
+	DW_AT_call_line	DW_FORM_data1
+	DW_AT_call_column	DW_FORM_data1
+
+[25] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[26] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[27] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[28] DW_TAG_label	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+	DW_AT_low_pc	DW_FORM_addr
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x0000034f version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x00000353)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000069] = "/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x000000a9] = "/usr/local/google/home/azakai/Dev/2-binaryen")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+              DW_AT_ranges [DW_FORM_sec_offset]	(0x00000040
+                 [0x00000006, 0x000003a3)
+                 [0x000003a5, 0x000006ab))
+
+0x00000026:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x002b => {0x0000002b} "worker_args")
+
+0x0000002b:   DW_TAG_structure_type [3] *
+                DW_AT_calling_convention [DW_FORM_data1]	(DW_CC_pass_by_value)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000e3] = "worker_args")
+                DW_AT_byte_size [DW_FORM_data1]	(0x0c)
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(20)
+
+0x00000034:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d6] = "i")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(21)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x00)
+
+0x00000040:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(21)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x04)
+
+0x0000004c:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000de] = "next")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(22)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x08)
+
+0x00000058:     NULL
+
+0x00000059:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d8] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x00000060:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000065:   DW_TAG_namespace [6] *
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ef] = "std")
+
+0x0000006a:     DW_TAG_typedef [7]  
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0076 => {0x00000076} "decltype(nullptr)")
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000105] = "nullptr_t")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/system/include/libcxx/__nullptr")
+                  DW_AT_decl_line [DW_FORM_data1]	(57)
+
+0x00000075:     NULL
+
+0x00000076:   DW_TAG_unspecified_type [8]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000f3] = "decltype(nullptr)")
+
+0x0000007b:   DW_TAG_imported_declaration [9]  
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/system/include/libcxx/stddef.h")
+                DW_AT_decl_line [DW_FORM_data1]	(52)
+                DW_AT_import [DW_FORM_ref4]	(cu + 0x006a => {0x0000006a})
+
+0x00000082:   DW_TAG_subprogram [10] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000006)
+                DW_AT_high_pc [DW_FORM_data4]	(0x0000039d)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x1 +0, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x00000166] = "_Z15fannkuch_workerPv")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000017c] = "fannkuch_worker")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(26)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000009e:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000191] = "_arg")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(26)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x01a7 => {0x000001a7} "*")
+
+0x000000a9:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000133] = "args")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(28)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000000b4:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000000: 
+                     [0xffffffff,  0x00000006): 
+                     [0x00000000,  0x0000004e): DW_OP_consts +0, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014c] = "maxflips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000c3:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000001d: 
+                     [0xffffffff,  0x0000002b): 
+                     [0x00000000,  0x00000029): DW_OP_consts +0, DW_OP_stack_value
+                     [0x0000003f,  0x00000044): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x000000d5,  0x000000de): DW_OP_consts +1, DW_OP_stack_value
+                     [0x0000011a,  0x00000124): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                     [0x00000162,  0x0000016f): DW_OP_consts +0, DW_OP_stack_value
+                     [0x0000024f,  0x0000025a): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000260,  0x00000269): DW_OP_consts +1, DW_OP_stack_value
+                     [0x000002a5,  0x000002af): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                     [0x000002ed,  0x000002fa): DW_OP_consts +0, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d6] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000d2:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000a5: 
+                     [0xffffffff,  0x00000032): 
+                     [0x00000000,  0x00000022): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000e1:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000c3: 
+                     [0xffffffff,  0x0000003b): 
+                     [0x00000000,  0x00000019): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000013e] = "perm1")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000000f0:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000e1: 
+                     [0xffffffff,  0x00000041): 
+                     [0x00000000,  0x00000013): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000196] = "perm")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000000ff:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000ff: 
+                     [0xffffffff,  0x00000047): 
+                     [0x00000000,  0x0000000d): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000144] = "count")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x0000010e:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000011d: 
+                     [0xffffffff,  0x000001f6): 
+                     [0x00000000,  0x00000005): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+                     [0x0000018b,  0x00000190): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014a] = "r")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000011d:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000149: 
+                     [0xffffffff,  0x000000e7): 
+                     [0x00000000,  0x00000013): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000019,  0x00000022): DW_OP_WASM_location 0x0 +13, DW_OP_stack_value
+                     [0x00000087,  0x0000008f): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                     [0x00000193,  0x0000019e): DW_OP_consts +0, DW_OP_stack_value
+                     [0x000001a4,  0x000001ad): DW_OP_WASM_location 0x0 +10, DW_OP_stack_value
+                     [0x00000212,  0x0000021a): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000155] = "flips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000012c:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000001ab: 
+                     [0xffffffff,  0x000000f6): 
+                     [0x00000000,  0x00000004): DW_OP_WASM_location 0x0 +12, DW_OP_stack_value
+                     [0x0000018b,  0x0000018f): DW_OP_WASM_location 0x0 +16, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000019b] = "k")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000013b:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000001d7: 
+                     [0xffffffff,  0x00000110): 
+                     [0x00000000,  0x00000004): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x0000003c,  0x0000003f): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x0000018b,  0x0000018f): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x000001c7,  0x000001ca): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000019d] = "j")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000014a:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000021f: 
+                     [0xffffffff,  0x00000125): 
+                     [0x00000000,  0x0000002a): DW_OP_WASM_location 0x0 +15, DW_OP_stack_value
+                     [0x0000003b,  0x00000051): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x0000018b,  0x000001b5): DW_OP_WASM_location 0x0 +14, DW_OP_stack_value
+                     [0x000001c6,  0x000001dc): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000019f] = "tmp")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000159:     DW_TAG_lexical_block [14] *
+                  DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
+                     [0x00000193, 0x000001d1)
+                     [0x000001fb, 0x00000204)
+                     [0x0000031e, 0x0000035c)
+                     [0x00000386, 0x0000038f))
+
+0x0000015e:       DW_TAG_variable [12]  
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000163] = "p0")
+                    DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                    DW_AT_decl_line [DW_FORM_data1]	(74)
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000169:       NULL
+
+0x0000016a:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000039)
+
+0x0000016f:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000003f)
+
+0x00000174:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000045)
+
+0x00000179:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000000ef)
+
+0x0000017e:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000398)
+
+0x00000187:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000039c)
+
+0x00000190:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000003a0)
+
+0x00000199:     NULL
+
+0x0000019a:   DW_TAG_subprogram [17] *
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000010f] = "free")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/system/include/libc/stdlib.h")
+                DW_AT_decl_line [DW_FORM_data1]	(41)
+                DW_AT_declaration [DW_FORM_flag_present]	(true)
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x000001a1:     DW_TAG_formal_parameter [18]  
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x01a7 => {0x000001a7} "*")
+
+0x000001a6:     NULL
+
+0x000001a7:   DW_TAG_pointer_type [19]  
+
+0x000001a8:   DW_TAG_subprogram [20] *
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x00000114] = "_ZL8fannkuchi")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000122] = "fannkuch")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(87)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_inline [DW_FORM_data1]	(DW_INL_inlined)
+
+0x000001b8:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(87)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001c3:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000012b] = "showmax")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(90)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001ce:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000133] = "args")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(89)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000001d9:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d6] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001e4:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000138] = "targs")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(89)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000001ef:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000013e] = "perm1")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000001fa:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000144] = "count")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x00000205:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014a] = "r")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000210:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014c] = "maxflips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000021b:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000155] = "flips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000226:     DW_TAG_label [21]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000015b] = "cleanup")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(137)
+
+0x0000022d:     DW_TAG_lexical_block [22] *
+
+0x0000022e:       DW_TAG_variable [12]  
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000163] = "p0")
+                    DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                    DW_AT_decl_line [DW_FORM_data1]	(125)
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000239:       NULL
+
+0x0000023a:     NULL
+
+0x0000023b:   DW_TAG_subprogram [23] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x00000000000003a5)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000306)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x0 +2, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000018c] = "main")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(152)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000253:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000001a3] = "argc")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(152)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000025e:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000001a8] = "argv")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(152)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0341 => {0x00000341} "char**")
+
+0x00000269:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000267: 
+                     [0xffffffff,  0x000003d7): 
+                     [0x00000000,  0x00000005): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(153)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+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_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)
+
+0x00000288:       DW_TAG_formal_parameter [25]  
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01b8 => {0x000001b8} "n")
+
+0x0000028d:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000285: 
+                       [0xffffffff,  0x000003ea): 
+                       [0x00000000,  0x00000009): DW_OP_consts +30, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01c3 => {0x000001c3} "showmax")
+
+0x00000296:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x000002a2: 
+                       [0xffffffff,  0x000003ea): 
+                       [0x00000000,  0x00000009): DW_OP_lit0, DW_OP_stack_value
+                       [0x00000286,  0x0000029e): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01ce => {0x000001ce} "args")
+
+0x0000029f:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x000002cc: 
+                       [0xffffffff,  0x000003ea): 
+                       [0x00000000,  0x00000009): DW_OP_consts +0, DW_OP_stack_value
+                       [0x0000003e,  0x00000043): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                       [0x00000049,  0x00000069): DW_OP_consts +0, DW_OP_stack_value
+                       [0x0000007f,  0x00000084): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                       [0x0000009d,  0x000000a1): DW_OP_consts +0, DW_OP_stack_value
+                       [0x000000c8,  0x000000cd): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                       [0x00000115,  0x00000125): DW_OP_consts +0, DW_OP_stack_value
+                       [0x00000198,  0x000001a6): DW_OP_consts +0, DW_OP_stack_value
+                       [0x000001db,  0x000001ef): DW_OP_consts +0, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01d9 => {0x000001d9} "i")
+
+0x000002a8:       DW_TAG_variable [27]  
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01e4 => {0x000001e4} "targs")
+
+0x000002ad:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000354: 
+                       [0xffffffff,  0x0000043e): 
+                       [0x00000000,  0x00000015): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01ef => {0x000001ef} "perm1")
+
+0x000002b6:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000372: 
+                       [0xffffffff,  0x00000444): 
+                       [0x00000000,  0x0000000f): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01fa => {0x000001fa} "count")
+
+0x000002bf:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000390: 
+                       [0xffffffff,  0x0000056d): 
+                       [0x00000000,  0x00000007): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+                       [0x000000ca,  0x000000d1): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x0205 => {0x00000205} "r")
+
+0x000002c8:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x000003e8: 
+                       [0xffffffff,  0x00000652): 
+                       [0x00000000,  0x0000000b): DW_OP_consts +0, DW_OP_stack_value
+                       [0x0000002e,  0x00000036): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x0210 => {0x00000210} "maxflips")
+
+0x000002d1:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000413: 
+                       [0xffffffff,  0x00000669): 
+                       [0x00000000,  0x0000001f): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x021b => {0x0000021b} "flips")
+
+0x000002da:       DW_TAG_label [28]  
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x0226 => {0x00000226} "cleanup")
+                    DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000646)
+
+0x000002e3:       DW_TAG_lexical_block [14] *
+                    DW_AT_ranges [DW_FORM_sec_offset]	(0x00000028
+                       [0x000004ff, 0x00000546)
+                       [0x000005c3, 0x00000610))
+
+0x000002e8:         DW_TAG_variable [26]  
+                      DW_AT_location [DW_FORM_sec_offset]	(0x000003bc: 
+                         [0xffffffff,  0x00000506): 
+                         [0x00000000,  0x00000009): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value
+                         [0x000000c6,  0x000000d3): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value)
+                      DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x022e => {0x0000022e} "p0")
+
+0x000002f1:         NULL
+
+0x000002f2:       NULL
+
+0x000002f3:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000003d5)
+
+0x000002f8:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000003e2)
+
+0x000002fd:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000408)
+
+0x00000302:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000043c)
+
+0x00000307:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000442)
+
+0x0000030c:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000004aa)
+
+0x00000311:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000004bc)
+
+0x00000316:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000586)
+
+0x0000031b:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000064a)
+
+0x00000324:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000064e)
+
+0x0000032d:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000667)
+
+0x00000332:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000674)
+
+0x0000033b:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000069f)
+
+0x00000340:     NULL
+
+0x00000341:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0346 => {0x00000346} "char*")
+
+0x00000346:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x034b => {0x0000034b} "char")
+
+0x0000034b:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000001ad] = "char")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed_char)
+                DW_AT_byte_size [DW_FORM_data1]	(0x01)
+
+0x00000352:   NULL
+
+.debug_loc contents:
+0x00000000: 
+            [0xffffffff,  0x00000006): 
+            [0x00000000,  0x0000004e): DW_OP_consts +0, DW_OP_stack_value
+
+0x0000001d: 
+            [0xffffffff,  0x0000002b): 
+            [0x00000000,  0x00000029): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000003f,  0x00000044): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x000000d5,  0x000000de): DW_OP_consts +1, DW_OP_stack_value
+            [0x0000011a,  0x00000124): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000162,  0x0000016f): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000024f,  0x0000025a): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000260,  0x00000269): DW_OP_consts +1, DW_OP_stack_value
+            [0x000002a5,  0x000002af): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x000002ed,  0x000002fa): DW_OP_consts +0, DW_OP_stack_value
+
+0x000000a5: 
+            [0xffffffff,  0x00000032): 
+            [0x00000000,  0x00000022): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+
+0x000000c3: 
+            [0xffffffff,  0x0000003b): 
+            [0x00000000,  0x00000019): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+
+0x000000e1: 
+            [0xffffffff,  0x00000041): 
+            [0x00000000,  0x00000013): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value
+
+0x000000ff: 
+            [0xffffffff,  0x00000047): 
+            [0x00000000,  0x0000000d): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+
+0x0000011d: 
+            [0xffffffff,  0x000001f6): 
+            [0x00000000,  0x00000005): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+            [0x0000018b,  0x00000190): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+
+0x00000149: 
+            [0xffffffff,  0x000000e7): 
+            [0x00000000,  0x00000013): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000019,  0x00000022): DW_OP_WASM_location 0x0 +13, DW_OP_stack_value
+            [0x00000087,  0x0000008f): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000193,  0x0000019e): DW_OP_consts +0, DW_OP_stack_value
+            [0x000001a4,  0x000001ad): DW_OP_WASM_location 0x0 +10, DW_OP_stack_value
+            [0x00000212,  0x0000021a): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+
+0x000001ab: 
+            [0xffffffff,  0x000000f6): 
+            [0x00000000,  0x00000004): DW_OP_WASM_location 0x0 +12, DW_OP_stack_value
+            [0x0000018b,  0x0000018f): DW_OP_WASM_location 0x0 +16, DW_OP_stack_value
+
+0x000001d7: 
+            [0xffffffff,  0x00000110): 
+            [0x00000000,  0x00000004): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x0000003c,  0x0000003f): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x0000018b,  0x0000018f): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x000001c7,  0x000001ca): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x0000021f: 
+            [0xffffffff,  0x00000125): 
+            [0x00000000,  0x0000002a): DW_OP_WASM_location 0x0 +15, DW_OP_stack_value
+            [0x0000003b,  0x00000051): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x0000018b,  0x000001b5): DW_OP_WASM_location 0x0 +14, DW_OP_stack_value
+            [0x000001c6,  0x000001dc): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000267: 
+            [0xffffffff,  0x000003d7): 
+            [0x00000000,  0x00000005): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+
+0x00000285: 
+            [0xffffffff,  0x000003ea): 
+            [0x00000000,  0x00000009): DW_OP_consts +30, DW_OP_stack_value
+
+0x000002a2: 
+            [0xffffffff,  0x000003ea): 
+            [0x00000000,  0x00000009): DW_OP_lit0, DW_OP_stack_value
+            [0x00000286,  0x0000029e): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+
+0x000002cc: 
+            [0xffffffff,  0x000003ea): 
+            [0x00000000,  0x00000009): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000003e,  0x00000043): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000049,  0x00000069): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000007f,  0x00000084): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x0000009d,  0x000000a1): DW_OP_consts +0, DW_OP_stack_value
+            [0x000000c8,  0x000000cd): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000115,  0x00000125): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000198,  0x000001a6): DW_OP_consts +0, DW_OP_stack_value
+            [0x000001db,  0x000001ef): DW_OP_consts +0, DW_OP_stack_value
+
+0x00000354: 
+            [0xffffffff,  0x0000043e): 
+            [0x00000000,  0x00000015): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000372: 
+            [0xffffffff,  0x00000444): 
+            [0x00000000,  0x0000000f): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value
+
+0x00000390: 
+            [0xffffffff,  0x0000056d): 
+            [0x00000000,  0x00000007): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+            [0x000000ca,  0x000000d1): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+
+0x000003bc: 
+            [0xffffffff,  0x00000506): 
+            [0x00000000,  0x00000009): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value
+            [0x000000c6,  0x000000d3): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value
+
+0x000003e8: 
+            [0xffffffff,  0x00000652): 
+            [0x00000000,  0x0000000b): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000002e,  0x00000036): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+
+0x00000413: 
+            [0xffffffff,  0x00000669): 
+            [0x00000000,  0x0000001f): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x00000b06
+         version: 4
+ prologue_length: 0x000000dd
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+include_directories[  1] = "/usr/local/google/home/azakai/Dev"
+file_names[  1]:
+           name: "emscripten/tests/fannkuch.cpp"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  2]:
+           name: "emscripten/system/include/libcxx/__nullptr"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  3]:
+           name: "emscripten/system/include/libcxx/stddef.h"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  4]:
+           name: "emscripten/system/include/libc/stdlib.h"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+0x000000e7: 00 DW_LNE_set_address (0x0000000000000006)
+0x000000ee: 03 DW_LNS_advance_line (27)
+0x000000f0: 01 DW_LNS_copy
+            0x0000000000000006     27      0      1   0             0  is_stmt
+
+
+0x000000f1: 00 DW_LNE_set_address (0x000000000000002b)
+0x000000f8: 03 DW_LNS_advance_line (33)
+0x000000fa: 05 DW_LNS_set_column (14)
+0x000000fc: 0a DW_LNS_set_prologue_end
+0x000000fd: 01 DW_LNS_copy
+            0x000000000000002b     33     14      1   0             0  is_stmt prologue_end
+
+
+0x000000fe: 00 DW_LNE_set_address (0x0000000000000034)
+0x00000105: 03 DW_LNS_advance_line (34)
+0x00000107: 05 DW_LNS_set_column (27)
+0x00000109: 01 DW_LNS_copy
+            0x0000000000000034     34     27      1   0             0  is_stmt
+
+
+0x0000010a: 00 DW_LNE_set_address (0x0000000000000035)
+0x00000111: 05 DW_LNS_set_column (18)
+0x00000113: 06 DW_LNS_negate_stmt
+0x00000114: 01 DW_LNS_copy
+            0x0000000000000035     34     18      1   0             0 
+
+
+0x00000115: 00 DW_LNE_set_address (0x000000000000003b)
+0x0000011c: 03 DW_LNS_advance_line (35)
+0x0000011e: 05 DW_LNS_set_column (17)
+0x00000120: 06 DW_LNS_negate_stmt
+0x00000121: 01 DW_LNS_copy
+            0x000000000000003b     35     17      1   0             0  is_stmt
+
+
+0x00000122: 00 DW_LNE_set_address (0x0000000000000041)
+0x00000129: 03 DW_LNS_advance_line (36)
+0x0000012b: 05 DW_LNS_set_column (18)
+0x0000012d: 01 DW_LNS_copy
+            0x0000000000000041     36     18      1   0             0  is_stmt
+
+
+0x0000012e: 00 DW_LNE_set_address (0x000000000000004d)
+0x00000135: 03 DW_LNS_advance_line (37)
+0x00000137: 01 DW_LNS_copy
+            0x000000000000004d     37     18      1   0             0  is_stmt
+
+
+0x00000138: 00 DW_LNE_set_address (0x0000000000000052)
+0x0000013f: 05 DW_LNS_set_column (4)
+0x00000141: 06 DW_LNS_negate_stmt
+0x00000142: 01 DW_LNS_copy
+            0x0000000000000052     37      4      1   0             0 
+
+
+0x00000143: 00 DW_LNE_set_address (0x0000000000000056)
+0x0000014a: 03 DW_LNS_advance_line (38)
+0x0000014c: 05 DW_LNS_set_column (7)
+0x0000014e: 06 DW_LNS_negate_stmt
+0x0000014f: 01 DW_LNS_copy
+            0x0000000000000056     38      7      1   0             0  is_stmt
+
+
+0x00000150: 00 DW_LNE_set_address (0x000000000000005e)
+0x00000157: 05 DW_LNS_set_column (16)
+0x00000159: 06 DW_LNS_negate_stmt
+0x0000015a: 01 DW_LNS_copy
+            0x000000000000005e     38     16      1   0             0 
+
+
+0x0000015b: 00 DW_LNE_set_address (0x0000000000000063)
+0x00000162: 03 DW_LNS_advance_line (37)
+0x00000164: 05 DW_LNS_set_column (24)
+0x00000166: 06 DW_LNS_negate_stmt
+0x00000167: 01 DW_LNS_copy
+            0x0000000000000063     37     24      1   0             0  is_stmt
+
+
+0x00000168: 00 DW_LNE_set_address (0x0000000000000068)
+0x0000016f: 05 DW_LNS_set_column (18)
+0x00000171: 06 DW_LNS_negate_stmt
+0x00000172: 01 DW_LNS_copy
+            0x0000000000000068     37     18      1   0             0 
+
+
+0x00000173: 00 DW_LNE_set_address (0x000000000000006d)
+0x0000017a: 05 DW_LNS_set_column (4)
+0x0000017c: 01 DW_LNS_copy
+            0x000000000000006d     37      4      1   0             0 
+
+
+0x0000017d: 00 DW_LNE_set_address (0x0000000000000070)
+0x00000184: 03 DW_LNS_advance_line (39)
+0x00000186: 06 DW_LNS_negate_stmt
+0x00000187: 01 DW_LNS_copy
+            0x0000000000000070     39      4      1   0             0  is_stmt
+
+
+0x00000188: 00 DW_LNE_set_address (0x0000000000000072)
+0x0000018f: 05 DW_LNS_set_column (16)
+0x00000191: 06 DW_LNS_negate_stmt
+0x00000192: 01 DW_LNS_copy
+            0x0000000000000072     39     16      1   0             0 
+
+
+0x00000193: 00 DW_LNE_set_address (0x000000000000007b)
+0x0000019a: 05 DW_LNS_set_column (4)
+0x0000019c: 01 DW_LNS_copy
+            0x000000000000007b     39      4      1   0             0 
+
+
+0x0000019d: 00 DW_LNE_set_address (0x000000000000007d)
+0x000001a4: 05 DW_LNS_set_column (23)
+0x000001a6: 01 DW_LNS_copy
+            0x000000000000007d     39     23      1   0             0 
+
+
+0x000001a7: 00 DW_LNE_set_address (0x0000000000000082)
+0x000001ae: 05 DW_LNS_set_column (19)
+0x000001b0: 01 DW_LNS_copy
+            0x0000000000000082     39     19      1   0             0 
+
+
+0x000001b1: 00 DW_LNE_set_address (0x0000000000000087)
+0x000001b8: 03 DW_LNS_advance_line (40)
+0x000001ba: 05 DW_LNS_set_column (4)
+0x000001bc: 06 DW_LNS_negate_stmt
+0x000001bd: 01 DW_LNS_copy
+            0x0000000000000087     40      4      1   0             0  is_stmt
+
+
+0x000001be: 00 DW_LNE_set_address (0x000000000000008f)
+0x000001c5: 05 DW_LNS_set_column (17)
+0x000001c7: 06 DW_LNS_negate_stmt
+0x000001c8: 01 DW_LNS_copy
+            0x000000000000008f     40     17      1   0             0 
+
+
+0x000001c9: 00 DW_LNE_set_address (0x000000000000009a)
+0x000001d0: 03 DW_LNS_advance_line (37)
+0x000001d2: 05 DW_LNS_set_column (18)
+0x000001d4: 06 DW_LNS_negate_stmt
+0x000001d5: 01 DW_LNS_copy
+            0x000000000000009a     37     18      1   0             0  is_stmt
+
+
+0x000001d6: 00 DW_LNE_set_address (0x000000000000009f)
+0x000001dd: 03 DW_LNS_advance_line (43)
+0x000001df: 05 DW_LNS_set_column (4)
+0x000001e1: 01 DW_LNS_copy
+            0x000000000000009f     43      4      1   0             0  is_stmt
+
+
+0x000001e2: 00 DW_LNE_set_address (0x00000000000000a5)
+0x000001e9: 03 DW_LNS_advance_line (44)
+0x000001eb: 05 DW_LNS_set_column (16)
+0x000001ed: 01 DW_LNS_copy
+            0x00000000000000a5     44     16      1   0             0  is_stmt
+
+
+0x000001ee: 00 DW_LNE_set_address (0x00000000000000ae)
+0x000001f5: 03 DW_LNS_advance_line (45)
+0x000001f7: 05 DW_LNS_set_column (10)
+0x000001f9: 01 DW_LNS_copy
+            0x00000000000000ae     45     10      1   0             0  is_stmt
+
+
+0x000001fa: 00 DW_LNE_set_address (0x00000000000000b0)
+0x00000201: 05 DW_LNS_set_column (18)
+0x00000203: 06 DW_LNS_negate_stmt
+0x00000204: 01 DW_LNS_copy
+            0x00000000000000b0     45     18      1   0             0 
+
+
+0x00000205: 00 DW_LNE_set_address (0x00000000000000b9)
+0x0000020c: 05 DW_LNS_set_column (10)
+0x0000020e: 01 DW_LNS_copy
+            0x00000000000000b9     45     10      1   0             0 
+
+
+0x0000020f: 00 DW_LNE_set_address (0x00000000000000bb)
+0x00000216: 05 DW_LNS_set_column (23)
+0x00000218: 01 DW_LNS_copy
+            0x00000000000000bb     45     23      1   0             0 
+
+
+0x00000219: 00 DW_LNE_set_address (0x00000000000000c0)
+0x00000220: 03 DW_LNS_advance_line (44)
+0x00000222: 05 DW_LNS_set_column (16)
+0x00000224: 06 DW_LNS_negate_stmt
+0x00000225: 01 DW_LNS_copy
+            0x00000000000000c0     44     16      1   0             0  is_stmt
+
+
+0x00000226: 00 DW_LNE_set_address (0x00000000000000cb)
+0x0000022d: 05 DW_LNS_set_column (7)
+0x0000022f: 06 DW_LNS_negate_stmt
+0x00000230: 01 DW_LNS_copy
+            0x00000000000000cb     44      7      1   0             0 
+
+
+0x00000231: 00 DW_LNE_set_address (0x00000000000000d1)
+0x00000238: 03 DW_LNS_advance_line (46)
+0x0000023a: 05 DW_LNS_set_column (11)
+0x0000023c: 06 DW_LNS_negate_stmt
+0x0000023d: 01 DW_LNS_copy
+            0x00000000000000d1     46     11      1   0             0  is_stmt
+
+
+0x0000023e: 00 DW_LNE_set_address (0x00000000000000dd)
+0x00000245: 05 DW_LNS_set_column (28)
+0x00000247: 06 DW_LNS_negate_stmt
+0x00000248: 01 DW_LNS_copy
+            0x00000000000000dd     46     28      1   0             0 
+
+
+0x00000249: 00 DW_LNE_set_address (0x00000000000000e2)
+0x00000250: 05 DW_LNS_set_column (41)
+0x00000252: 01 DW_LNS_copy
+            0x00000000000000e2     46     41      1   0             0 
+
+
+0x00000253: 00 DW_LNE_set_address (0x00000000000000e7)
+0x0000025a: 03 DW_LNS_advance_line (48)
+0x0000025c: 05 DW_LNS_set_column (21)
+0x0000025e: 06 DW_LNS_negate_stmt
+0x0000025f: 01 DW_LNS_copy
+            0x00000000000000e7     48     21      1   0             0  is_stmt
+
+
+0x00000260: 00 DW_LNE_set_address (0x00000000000000ef)
+0x00000267: 03 DW_LNS_advance_line (50)
+0x00000269: 05 DW_LNS_set_column (14)
+0x0000026b: 01 DW_LNS_copy
+            0x00000000000000ef     50     14      1   0             0  is_stmt
+
+
+0x0000026c: 00 DW_LNE_set_address (0x0000000000000102)
+0x00000273: 03 DW_LNS_advance_line (52)
+0x00000275: 05 DW_LNS_set_column (38)
+0x00000277: 01 DW_LNS_copy
+            0x0000000000000102     52     38      1   0             0  is_stmt
+
+
+0x00000278: 00 DW_LNE_set_address (0x0000000000000116)
+0x0000027f: 03 DW_LNS_advance_line (53)
+0x00000281: 05 DW_LNS_set_column (22)
+0x00000283: 01 DW_LNS_copy
+            0x0000000000000116     53     22      1   0             0  is_stmt
+
+
+0x00000284: 00 DW_LNE_set_address (0x0000000000000125)
+0x0000028b: 03 DW_LNS_advance_line (54)
+0x0000028d: 05 DW_LNS_set_column (24)
+0x0000028f: 01 DW_LNS_copy
+            0x0000000000000125     54     24      1   0             0  is_stmt
+
+
+0x00000290: 00 DW_LNE_set_address (0x0000000000000127)
+0x00000297: 05 DW_LNS_set_column (26)
+0x00000299: 06 DW_LNS_negate_stmt
+0x0000029a: 01 DW_LNS_copy
+            0x0000000000000127     54     26      1   0             0 
+
+
+0x0000029b: 00 DW_LNE_set_address (0x0000000000000134)
+0x000002a2: 05 DW_LNS_set_column (24)
+0x000002a4: 01 DW_LNS_copy
+            0x0000000000000134     54     24      1   0             0 
+
+
+0x000002a5: 00 DW_LNE_set_address (0x0000000000000137)
+0x000002ac: 03 DW_LNS_advance_line (55)
+0x000002ae: 06 DW_LNS_negate_stmt
+0x000002af: 01 DW_LNS_copy
+            0x0000000000000137     55     24      1   0             0  is_stmt
+
+
+0x000002b0: 00 DW_LNE_set_address (0x000000000000013e)
+0x000002b7: 03 DW_LNS_advance_line (52)
+0x000002b9: 05 DW_LNS_set_column (44)
+0x000002bb: 01 DW_LNS_copy
+            0x000000000000013e     52     44      1   0             0  is_stmt
+
+
+0x000002bc: 00 DW_LNE_set_address (0x000000000000014a)
+0x000002c3: 05 DW_LNS_set_column (38)
+0x000002c5: 06 DW_LNS_negate_stmt
+0x000002c6: 01 DW_LNS_copy
+            0x000000000000014a     52     38      1   0             0 
+
+
+0x000002c7: 00 DW_LNE_set_address (0x000000000000014d)
+0x000002ce: 05 DW_LNS_set_column (13)
+0x000002d0: 01 DW_LNS_copy
+            0x000000000000014d     52     13      1   0             0 
+
+
+0x000002d1: 00 DW_LNE_set_address (0x0000000000000151)
+0x000002d8: 03 DW_LNS_advance_line (58)
+0x000002da: 05 DW_LNS_set_column (19)
+0x000002dc: 06 DW_LNS_negate_stmt
+0x000002dd: 01 DW_LNS_copy
+            0x0000000000000151     58     19      1   0             0  is_stmt
+
+
+0x000002de: 00 DW_LNE_set_address (0x0000000000000160)
+0x000002e5: 03 DW_LNS_advance_line (59)
+0x000002e7: 05 DW_LNS_set_column (21)
+0x000002e9: 01 DW_LNS_copy
+            0x0000000000000160     59     21      1   0             0  is_stmt
+
+
+0x000002ea: 00 DW_LNE_set_address (0x0000000000000167)
+0x000002f1: 03 DW_LNS_advance_line (57)
+0x000002f3: 05 DW_LNS_set_column (18)
+0x000002f5: 01 DW_LNS_copy
+            0x0000000000000167     57     18      1   0             0  is_stmt
+
+
+0x000002f6: 00 DW_LNE_set_address (0x0000000000000177)
+0x000002fd: 03 DW_LNS_advance_line (62)
+0x000002ff: 05 DW_LNS_set_column (14)
+0x00000301: 01 DW_LNS_copy
+            0x0000000000000177     62     14      1   0             0  is_stmt
+
+
+0x00000302: 00 DW_LNE_set_address (0x000000000000017b)
+0x00000309: 05 DW_LNS_set_column (23)
+0x0000030b: 06 DW_LNS_negate_stmt
+0x0000030c: 01 DW_LNS_copy
+            0x000000000000017b     62     23      1   0             0 
+
+
+0x0000030d: 00 DW_LNE_set_address (0x0000000000000180)
+0x00000314: 05 DW_LNS_set_column (14)
+0x00000316: 01 DW_LNS_copy
+            0x0000000000000180     62     14      1   0             0 
+
+
+0x00000317: 00 DW_LNE_set_address (0x0000000000000184)
+0x0000031e: 03 DW_LNS_advance_line (66)
+0x00000320: 05 DW_LNS_set_column (16)
+0x00000322: 06 DW_LNS_negate_stmt
+0x00000323: 01 DW_LNS_copy
+            0x0000000000000184     66     16      1   0             0  is_stmt
+
+
+0x00000324: 00 DW_LNE_set_address (0x0000000000000193)
+0x0000032b: 03 DW_LNS_advance_line (75)
+0x0000032d: 05 DW_LNS_set_column (27)
+0x0000032f: 01 DW_LNS_copy
+            0x0000000000000193     75     27      1   0             0  is_stmt
+
+
+0x00000330: 00 DW_LNE_set_address (0x000000000000019c)
+0x00000337: 03 DW_LNS_advance_line (76)
+0x00000339: 05 DW_LNS_set_column (16)
+0x0000033b: 01 DW_LNS_copy
+            0x000000000000019c     76     16      1   0             0  is_stmt
+
+
+0x0000033c: 00 DW_LNE_set_address (0x00000000000001a4)
+0x00000343: 05 DW_LNS_set_column (27)
+0x00000345: 06 DW_LNS_negate_stmt
+0x00000346: 01 DW_LNS_copy
+            0x00000000000001a4     76     27      1   0             0 
+
+
+0x00000347: 00 DW_LNE_set_address (0x00000000000001a6)
+0x0000034e: 05 DW_LNS_set_column (35)
+0x00000350: 01 DW_LNS_copy
+            0x00000000000001a6     76     35      1   0             0 
+
+
+0x00000351: 00 DW_LNE_set_address (0x00000000000001af)
+0x00000358: 05 DW_LNS_set_column (27)
+0x0000035a: 01 DW_LNS_copy
+            0x00000000000001af     76     27      1   0             0 
+
+
+0x0000035b: 00 DW_LNE_set_address (0x00000000000001b4)
+0x00000362: 05 DW_LNS_set_column (25)
+0x00000364: 01 DW_LNS_copy
+            0x00000000000001b4     76     25      1   0             0 
+
+
+0x00000365: 00 DW_LNE_set_address (0x00000000000001b7)
+0x0000036c: 03 DW_LNS_advance_line (75)
+0x0000036e: 05 DW_LNS_set_column (27)
+0x00000370: 06 DW_LNS_negate_stmt
+0x00000371: 01 DW_LNS_copy
+            0x00000000000001b7     75     27      1   0             0  is_stmt
+
+
+0x00000372: 00 DW_LNE_set_address (0x00000000000001bc)
+0x00000379: 05 DW_LNS_set_column (13)
+0x0000037b: 06 DW_LNS_negate_stmt
+0x0000037c: 01 DW_LNS_copy
+            0x00000000000001bc     75     13      1   0             0 
+
+
+0x0000037d: 00 DW_LNE_set_address (0x00000000000001c4)
+0x00000384: 03 DW_LNS_advance_line (77)
+0x00000386: 06 DW_LNS_negate_stmt
+0x00000387: 01 DW_LNS_copy
+            0x00000000000001c4     77     13      1   0             0  is_stmt
+
+
+0x00000388: 00 DW_LNE_set_address (0x00000000000001cc)
+0x0000038f: 05 DW_LNS_set_column (22)
+0x00000391: 06 DW_LNS_negate_stmt
+0x00000392: 01 DW_LNS_copy
+            0x00000000000001cc     77     22      1   0             0 
+
+
+0x00000393: 00 DW_LNE_set_address (0x00000000000001d1)
+0x0000039a: 03 DW_LNS_advance_line (79)
+0x0000039c: 05 DW_LNS_set_column (16)
+0x0000039e: 06 DW_LNS_negate_stmt
+0x0000039f: 01 DW_LNS_copy
+            0x00000000000001d1     79     16      1   0             0  is_stmt
+
+
+0x000003a0: 00 DW_LNE_set_address (0x00000000000001d9)
+0x000003a7: 05 DW_LNS_set_column (14)
+0x000003a9: 06 DW_LNS_negate_stmt
+0x000003aa: 01 DW_LNS_copy
+            0x00000000000001d9     79     14      1   0             0 
+
+
+0x000003ab: 00 DW_LNE_set_address (0x00000000000001e8)
+0x000003b2: 05 DW_LNS_set_column (25)
+0x000003b4: 01 DW_LNS_copy
+            0x00000000000001e8     79     25      1   0             0 
+
+
+0x000003b5: 00 DW_LNE_set_address (0x00000000000001ef)
+0x000003bc: 03 DW_LNS_advance_line (81)
+0x000003be: 05 DW_LNS_set_column (11)
+0x000003c0: 06 DW_LNS_negate_stmt
+0x000003c1: 01 DW_LNS_copy
+            0x00000000000001ef     81     11      1   0             0  is_stmt
+
+
+0x000003c2: 00 DW_LNE_set_address (0x00000000000001f4)
+0x000003c9: 03 DW_LNS_advance_line (66)
+0x000003cb: 05 DW_LNS_set_column (16)
+0x000003cd: 01 DW_LNS_copy
+            0x00000000000001f4     66     16      1   0             0  is_stmt
+
+
+0x000003ce: 00 DW_LNE_set_address (0x00000000000001fb)
+0x000003d5: 03 DW_LNS_advance_line (74)
+0x000003d7: 05 DW_LNS_set_column (22)
+0x000003d9: 01 DW_LNS_copy
+            0x00000000000001fb     74     22      1   0             0  is_stmt
+
+
+0x000003da: 00 DW_LNE_set_address (0x0000000000000204)
+0x000003e1: 03 DW_LNS_advance_line (37)
+0x000003e3: 05 DW_LNS_set_column (4)
+0x000003e5: 01 DW_LNS_copy
+            0x0000000000000204     37      4      1   0             0  is_stmt
+
+
+0x000003e6: 00 DW_LNE_set_address (0x0000000000000209)
+0x000003ed: 03 DW_LNS_advance_line (39)
+0x000003ef: 01 DW_LNS_copy
+            0x0000000000000209     39      4      1   0             0  is_stmt
+
+
+0x000003f0: 00 DW_LNE_set_address (0x000000000000020b)
+0x000003f7: 05 DW_LNS_set_column (16)
+0x000003f9: 06 DW_LNS_negate_stmt
+0x000003fa: 01 DW_LNS_copy
+            0x000000000000020b     39     16      1   0             0 
+
+
+0x000003fb: 00 DW_LNE_set_address (0x0000000000000214)
+0x00000402: 05 DW_LNS_set_column (4)
+0x00000404: 01 DW_LNS_copy
+            0x0000000000000214     39      4      1   0             0 
+
+
+0x00000405: 00 DW_LNE_set_address (0x0000000000000216)
+0x0000040c: 05 DW_LNS_set_column (23)
+0x0000040e: 01 DW_LNS_copy
+            0x0000000000000216     39     23      1   0             0 
+
+
+0x0000040f: 00 DW_LNE_set_address (0x000000000000021b)
+0x00000416: 05 DW_LNS_set_column (19)
+0x00000418: 01 DW_LNS_copy
+            0x000000000000021b     39     19      1   0             0 
+
+
+0x00000419: 00 DW_LNE_set_address (0x0000000000000220)
+0x00000420: 03 DW_LNS_advance_line (40)
+0x00000422: 05 DW_LNS_set_column (4)
+0x00000424: 06 DW_LNS_negate_stmt
+0x00000425: 01 DW_LNS_copy
+            0x0000000000000220     40      4      1   0             0  is_stmt
+
+
+0x00000426: 00 DW_LNE_set_address (0x0000000000000228)
+0x0000042d: 05 DW_LNS_set_column (17)
+0x0000042f: 06 DW_LNS_negate_stmt
+0x00000430: 01 DW_LNS_copy
+            0x0000000000000228     40     17      1   0             0 
+
+
+0x00000431: 00 DW_LNE_set_address (0x0000000000000238)
+0x00000438: 03 DW_LNS_advance_line (44)
+0x0000043a: 05 DW_LNS_set_column (16)
+0x0000043c: 06 DW_LNS_negate_stmt
+0x0000043d: 01 DW_LNS_copy
+            0x0000000000000238     44     16      1   0             0  is_stmt
+
+
+0x0000043e: 00 DW_LNE_set_address (0x0000000000000241)
+0x00000445: 03 DW_LNS_advance_line (45)
+0x00000447: 05 DW_LNS_set_column (10)
+0x00000449: 01 DW_LNS_copy
+            0x0000000000000241     45     10      1   0             0  is_stmt
+
+
+0x0000044a: 00 DW_LNE_set_address (0x0000000000000243)
+0x00000451: 05 DW_LNS_set_column (18)
+0x00000453: 06 DW_LNS_negate_stmt
+0x00000454: 01 DW_LNS_copy
+            0x0000000000000243     45     18      1   0             0 
+
+
+0x00000455: 00 DW_LNE_set_address (0x000000000000024c)
+0x0000045c: 05 DW_LNS_set_column (10)
+0x0000045e: 01 DW_LNS_copy
+            0x000000000000024c     45     10      1   0             0 
+
+
+0x0000045f: 00 DW_LNE_set_address (0x000000000000024e)
+0x00000466: 05 DW_LNS_set_column (23)
+0x00000468: 01 DW_LNS_copy
+            0x000000000000024e     45     23      1   0             0 
+
+
+0x00000469: 00 DW_LNE_set_address (0x0000000000000253)
+0x00000470: 03 DW_LNS_advance_line (44)
+0x00000472: 05 DW_LNS_set_column (16)
+0x00000474: 06 DW_LNS_negate_stmt
+0x00000475: 01 DW_LNS_copy
+            0x0000000000000253     44     16      1   0             0  is_stmt
+
+
+0x00000476: 00 DW_LNE_set_address (0x0000000000000264)
+0x0000047d: 03 DW_LNS_advance_line (46)
+0x0000047f: 05 DW_LNS_set_column (11)
+0x00000481: 01 DW_LNS_copy
+            0x0000000000000264     46     11      1   0             0  is_stmt
+
+
+0x00000482: 00 DW_LNE_set_address (0x0000000000000270)
+0x00000489: 05 DW_LNS_set_column (28)
+0x0000048b: 06 DW_LNS_negate_stmt
+0x0000048c: 01 DW_LNS_copy
+            0x0000000000000270     46     28      1   0             0 
+
+
+0x0000048d: 00 DW_LNE_set_address (0x0000000000000275)
+0x00000494: 05 DW_LNS_set_column (41)
+0x00000496: 01 DW_LNS_copy
+            0x0000000000000275     46     41      1   0             0 
+
+
+0x00000497: 00 DW_LNE_set_address (0x000000000000027a)
+0x0000049e: 03 DW_LNS_advance_line (50)
+0x000004a0: 05 DW_LNS_set_column (14)
+0x000004a2: 06 DW_LNS_negate_stmt
+0x000004a3: 01 DW_LNS_copy
+            0x000000000000027a     50     14      1   0             0  is_stmt
+
+
+0x000004a4: 00 DW_LNE_set_address (0x000000000000028d)
+0x000004ab: 03 DW_LNS_advance_line (52)
+0x000004ad: 05 DW_LNS_set_column (38)
+0x000004af: 01 DW_LNS_copy
+            0x000000000000028d     52     38      1   0             0  is_stmt
+
+
+0x000004b0: 00 DW_LNE_set_address (0x00000000000002a1)
+0x000004b7: 03 DW_LNS_advance_line (53)
+0x000004b9: 05 DW_LNS_set_column (22)
+0x000004bb: 01 DW_LNS_copy
+            0x00000000000002a1     53     22      1   0             0  is_stmt
+
+
+0x000004bc: 00 DW_LNE_set_address (0x00000000000002b0)
+0x000004c3: 03 DW_LNS_advance_line (54)
+0x000004c5: 05 DW_LNS_set_column (24)
+0x000004c7: 01 DW_LNS_copy
+            0x00000000000002b0     54     24      1   0             0  is_stmt
+
+
+0x000004c8: 00 DW_LNE_set_address (0x00000000000002b2)
+0x000004cf: 05 DW_LNS_set_column (26)
+0x000004d1: 06 DW_LNS_negate_stmt
+0x000004d2: 01 DW_LNS_copy
+            0x00000000000002b2     54     26      1   0             0 
+
+
+0x000004d3: 00 DW_LNE_set_address (0x00000000000002bf)
+0x000004da: 05 DW_LNS_set_column (24)
+0x000004dc: 01 DW_LNS_copy
+            0x00000000000002bf     54     24      1   0             0 
+
+
+0x000004dd: 00 DW_LNE_set_address (0x00000000000002c2)
+0x000004e4: 03 DW_LNS_advance_line (55)
+0x000004e6: 06 DW_LNS_negate_stmt
+0x000004e7: 01 DW_LNS_copy
+            0x00000000000002c2     55     24      1   0             0  is_stmt
+
+
+0x000004e8: 00 DW_LNE_set_address (0x00000000000002c9)
+0x000004ef: 03 DW_LNS_advance_line (52)
+0x000004f1: 05 DW_LNS_set_column (44)
+0x000004f3: 01 DW_LNS_copy
+            0x00000000000002c9     52     44      1   0             0  is_stmt
+
+
+0x000004f4: 00 DW_LNE_set_address (0x00000000000002d5)
+0x000004fb: 05 DW_LNS_set_column (38)
+0x000004fd: 06 DW_LNS_negate_stmt
+0x000004fe: 01 DW_LNS_copy
+            0x00000000000002d5     52     38      1   0             0 
+
+
+0x000004ff: 00 DW_LNE_set_address (0x00000000000002dc)
+0x00000506: 03 DW_LNS_advance_line (58)
+0x00000508: 05 DW_LNS_set_column (19)
+0x0000050a: 06 DW_LNS_negate_stmt
+0x0000050b: 01 DW_LNS_copy
+            0x00000000000002dc     58     19      1   0             0  is_stmt
+
+
+0x0000050c: 00 DW_LNE_set_address (0x00000000000002eb)
+0x00000513: 03 DW_LNS_advance_line (59)
+0x00000515: 05 DW_LNS_set_column (21)
+0x00000517: 01 DW_LNS_copy
+            0x00000000000002eb     59     21      1   0             0  is_stmt
+
+
+0x00000518: 00 DW_LNE_set_address (0x00000000000002f2)
+0x0000051f: 03 DW_LNS_advance_line (57)
+0x00000521: 05 DW_LNS_set_column (18)
+0x00000523: 01 DW_LNS_copy
+            0x00000000000002f2     57     18      1   0             0  is_stmt
+
+
+0x00000524: 00 DW_LNE_set_address (0x0000000000000302)
+0x0000052b: 03 DW_LNS_advance_line (62)
+0x0000052d: 05 DW_LNS_set_column (14)
+0x0000052f: 01 DW_LNS_copy
+            0x0000000000000302     62     14      1   0             0  is_stmt
+
+
+0x00000530: 00 DW_LNE_set_address (0x0000000000000306)
+0x00000537: 05 DW_LNS_set_column (23)
+0x00000539: 06 DW_LNS_negate_stmt
+0x0000053a: 01 DW_LNS_copy
+            0x0000000000000306     62     23      1   0             0 
+
+
+0x0000053b: 00 DW_LNE_set_address (0x000000000000030b)
+0x00000542: 05 DW_LNS_set_column (14)
+0x00000544: 01 DW_LNS_copy
+            0x000000000000030b     62     14      1   0             0 
+
+
+0x00000545: 00 DW_LNE_set_address (0x000000000000030f)
+0x0000054c: 03 DW_LNS_advance_line (66)
+0x0000054e: 05 DW_LNS_set_column (16)
+0x00000550: 06 DW_LNS_negate_stmt
+0x00000551: 01 DW_LNS_copy
+            0x000000000000030f     66     16      1   0             0  is_stmt
+
+
+0x00000552: 00 DW_LNE_set_address (0x000000000000031e)
+0x00000559: 03 DW_LNS_advance_line (75)
+0x0000055b: 05 DW_LNS_set_column (27)
+0x0000055d: 01 DW_LNS_copy
+            0x000000000000031e     75     27      1   0             0  is_stmt
+
+
+0x0000055e: 00 DW_LNE_set_address (0x0000000000000327)
+0x00000565: 03 DW_LNS_advance_line (76)
+0x00000567: 05 DW_LNS_set_column (16)
+0x00000569: 01 DW_LNS_copy
+            0x0000000000000327     76     16      1   0             0  is_stmt
+
+
+0x0000056a: 00 DW_LNE_set_address (0x000000000000032f)
+0x00000571: 05 DW_LNS_set_column (27)
+0x00000573: 06 DW_LNS_negate_stmt
+0x00000574: 01 DW_LNS_copy
+            0x000000000000032f     76     27      1   0             0 
+
+
+0x00000575: 00 DW_LNE_set_address (0x0000000000000331)
+0x0000057c: 05 DW_LNS_set_column (35)
+0x0000057e: 01 DW_LNS_copy
+            0x0000000000000331     76     35      1   0             0 
+
+
+0x0000057f: 00 DW_LNE_set_address (0x000000000000033a)
+0x00000586: 05 DW_LNS_set_column (27)
+0x00000588: 01 DW_LNS_copy
+            0x000000000000033a     76     27      1   0             0 
+
+
+0x00000589: 00 DW_LNE_set_address (0x000000000000033f)
+0x00000590: 05 DW_LNS_set_column (25)
+0x00000592: 01 DW_LNS_copy
+            0x000000000000033f     76     25      1   0             0 
+
+
+0x00000593: 00 DW_LNE_set_address (0x0000000000000342)
+0x0000059a: 03 DW_LNS_advance_line (75)
+0x0000059c: 05 DW_LNS_set_column (27)
+0x0000059e: 06 DW_LNS_negate_stmt
+0x0000059f: 01 DW_LNS_copy
+            0x0000000000000342     75     27      1   0             0  is_stmt
+
+
+0x000005a0: 00 DW_LNE_set_address (0x000000000000034f)
+0x000005a7: 03 DW_LNS_advance_line (77)
+0x000005a9: 05 DW_LNS_set_column (13)
+0x000005ab: 01 DW_LNS_copy
+            0x000000000000034f     77     13      1   0             0  is_stmt
+
+
+0x000005ac: 00 DW_LNE_set_address (0x0000000000000357)
+0x000005b3: 05 DW_LNS_set_column (22)
+0x000005b5: 06 DW_LNS_negate_stmt
+0x000005b6: 01 DW_LNS_copy
+            0x0000000000000357     77     22      1   0             0 
+
+
+0x000005b7: 00 DW_LNE_set_address (0x000000000000035c)
+0x000005be: 03 DW_LNS_advance_line (79)
+0x000005c0: 05 DW_LNS_set_column (16)
+0x000005c2: 06 DW_LNS_negate_stmt
+0x000005c3: 01 DW_LNS_copy
+            0x000000000000035c     79     16      1   0             0  is_stmt
+
+
+0x000005c4: 00 DW_LNE_set_address (0x0000000000000364)
+0x000005cb: 05 DW_LNS_set_column (14)
+0x000005cd: 06 DW_LNS_negate_stmt
+0x000005ce: 01 DW_LNS_copy
+            0x0000000000000364     79     14      1   0             0 
+
+
+0x000005cf: 00 DW_LNE_set_address (0x0000000000000373)
+0x000005d6: 05 DW_LNS_set_column (25)
+0x000005d8: 01 DW_LNS_copy
+            0x0000000000000373     79     25      1   0             0 
+
+
+0x000005d9: 00 DW_LNE_set_address (0x000000000000037a)
+0x000005e0: 03 DW_LNS_advance_line (81)
+0x000005e2: 05 DW_LNS_set_column (11)
+0x000005e4: 06 DW_LNS_negate_stmt
+0x000005e5: 01 DW_LNS_copy
+            0x000000000000037a     81     11      1   0             0  is_stmt
+
+
+0x000005e6: 00 DW_LNE_set_address (0x000000000000037f)
+0x000005ed: 03 DW_LNS_advance_line (66)
+0x000005ef: 05 DW_LNS_set_column (16)
+0x000005f1: 01 DW_LNS_copy
+            0x000000000000037f     66     16      1   0             0  is_stmt
+
+
+0x000005f2: 00 DW_LNE_set_address (0x0000000000000386)
+0x000005f9: 03 DW_LNS_advance_line (74)
+0x000005fb: 05 DW_LNS_set_column (22)
+0x000005fd: 01 DW_LNS_copy
+            0x0000000000000386     74     22      1   0             0  is_stmt
+
+
+0x000005fe: 00 DW_LNE_set_address (0x0000000000000394)
+0x00000605: 03 DW_LNS_advance_line (67)
+0x00000607: 05 DW_LNS_set_column (13)
+0x00000609: 01 DW_LNS_copy
+            0x0000000000000394     67     13      1   0             0  is_stmt
+
+
+0x0000060a: 00 DW_LNE_set_address (0x0000000000000398)
+0x00000611: 03 DW_LNS_advance_line (68)
+0x00000613: 01 DW_LNS_copy
+            0x0000000000000398     68     13      1   0             0  is_stmt
+
+
+0x00000614: 00 DW_LNE_set_address (0x000000000000039c)
+0x0000061b: 03 DW_LNS_advance_line (69)
+0x0000061d: 01 DW_LNS_copy
+            0x000000000000039c     69     13      1   0             0  is_stmt
+
+
+0x0000061e: 00 DW_LNE_set_address (0x00000000000003a0)
+0x00000625: 03 DW_LNS_advance_line (70)
+0x00000627: 01 DW_LNS_copy
+            0x00000000000003a0     70     13      1   0             0  is_stmt
+
+
+0x00000628: 00 DW_LNE_set_address (0x00000000000003a3)
+0x0000062f: 00 DW_LNE_end_sequence
+            0x00000000000003a3     70     13      1   0             0  is_stmt end_sequence
+
+0x00000632: 00 DW_LNE_set_address (0x00000000000003a5)
+0x00000639: 03 DW_LNS_advance_line (152)
+0x0000063c: 01 DW_LNS_copy
+            0x00000000000003a5    152      0      1   0             0  is_stmt
+
+
+0x0000063d: 00 DW_LNE_set_address (0x00000000000003c3)
+0x00000644: 03 DW_LNS_advance_line (153)
+0x00000646: 05 DW_LNS_set_column (17)
+0x00000648: 0a DW_LNS_set_prologue_end
+0x00000649: 01 DW_LNS_copy
+            0x00000000000003c3    153     17      1   0             0  is_stmt prologue_end
+
+
+0x0000064a: 00 DW_LNE_set_address (0x00000000000003c8)
+0x00000651: 05 DW_LNS_set_column (12)
+0x00000653: 06 DW_LNS_negate_stmt
+0x00000654: 01 DW_LNS_copy
+            0x00000000000003c8    153     12      1   0             0 
+
+
+0x00000655: 00 DW_LNE_set_address (0x00000000000003ce)
+0x0000065c: 05 DW_LNS_set_column (28)
+0x0000065e: 01 DW_LNS_copy
+            0x00000000000003ce    153     28      1   0             0 
+
+
+0x0000065f: 00 DW_LNE_set_address (0x00000000000003d3)
+0x00000666: 05 DW_LNS_set_column (23)
+0x00000668: 01 DW_LNS_copy
+            0x00000000000003d3    153     23      1   0             0 
+
+
+0x00000669: 00 DW_LNE_set_address (0x00000000000003d9)
+0x00000670: 03 DW_LNS_advance_line (155)
+0x00000672: 05 DW_LNS_set_column (10)
+0x00000674: 06 DW_LNS_negate_stmt
+0x00000675: 01 DW_LNS_copy
+            0x00000000000003d9    155     10      1   0             0  is_stmt
+
+
+0x00000676: 00 DW_LNE_set_address (0x00000000000003da)
+0x0000067d: 05 DW_LNS_set_column (8)
+0x0000067f: 06 DW_LNS_negate_stmt
+0x00000680: 01 DW_LNS_copy
+            0x00000000000003da    155      8      1   0             0 
+
+
+0x00000681: 00 DW_LNE_set_address (0x00000000000003dd)
+0x00000688: 03 DW_LNS_advance_line (156)
+0x0000068a: 05 DW_LNS_set_column (7)
+0x0000068c: 06 DW_LNS_negate_stmt
+0x0000068d: 01 DW_LNS_copy
+            0x00000000000003dd    156      7      1   0             0  is_stmt
+
+
+0x0000068e: 00 DW_LNE_set_address (0x00000000000003ec)
+0x00000695: 03 DW_LNS_advance_line (94)
+0x00000697: 05 DW_LNS_set_column (18)
+0x00000699: 01 DW_LNS_copy
+            0x00000000000003ec     94     18      1   0             0  is_stmt
+
+
+0x0000069a: 00 DW_LNE_set_address (0x00000000000003f1)
+0x000006a1: 05 DW_LNS_set_column (4)
+0x000006a3: 06 DW_LNS_negate_stmt
+0x000006a4: 01 DW_LNS_copy
+            0x00000000000003f1     94      4      1   0             0 
+
+
+0x000006a5: 00 DW_LNE_set_address (0x0000000000000406)
+0x000006ac: 03 DW_LNS_advance_line (95)
+0x000006ae: 05 DW_LNS_set_column (29)
+0x000006b0: 06 DW_LNS_negate_stmt
+0x000006b1: 01 DW_LNS_copy
+            0x0000000000000406     95     29      1   0             0  is_stmt
+
+
+0x000006b2: 00 DW_LNE_set_address (0x0000000000000408)
+0x000006b9: 03 DW_LNS_advance_line (98)
+0x000006bb: 05 DW_LNS_set_column (19)
+0x000006bd: 01 DW_LNS_copy
+            0x0000000000000408     98     19      1   0             0  is_stmt
+
+
+0x000006be: 00 DW_LNE_set_address (0x000000000000040f)
+0x000006c5: 03 DW_LNS_advance_line (97)
+0x000006c7: 05 DW_LNS_set_column (16)
+0x000006c9: 01 DW_LNS_copy
+            0x000000000000040f     97     16      1   0             0  is_stmt
+
+
+0x000006ca: 00 DW_LNE_set_address (0x0000000000000416)
+0x000006d1: 03 DW_LNS_advance_line (96)
+0x000006d3: 01 DW_LNS_copy
+            0x0000000000000416     96     16      1   0             0  is_stmt
+
+
+0x000006d4: 00 DW_LNE_set_address (0x0000000000000421)
+0x000006db: 03 DW_LNS_advance_line (94)
+0x000006dd: 05 DW_LNS_set_column (28)
+0x000006df: 01 DW_LNS_copy
+            0x0000000000000421     94     28      1   0             0  is_stmt
+
+
+0x000006e0: 00 DW_LNE_set_address (0x0000000000000426)
+0x000006e7: 05 DW_LNS_set_column (18)
+0x000006e9: 06 DW_LNS_negate_stmt
+0x000006ea: 01 DW_LNS_copy
+            0x0000000000000426     94     18      1   0             0 
+
+
+0x000006eb: 00 DW_LNE_set_address (0x000000000000042b)
+0x000006f2: 05 DW_LNS_set_column (4)
+0x000006f4: 01 DW_LNS_copy
+            0x000000000000042b     94      4      1   0             0 
+
+
+0x000006f5: 00 DW_LNE_set_address (0x0000000000000433)
+0x000006fc: 03 DW_LNS_advance_line (102)
+0x000006fe: 05 DW_LNS_set_column (27)
+0x00000700: 06 DW_LNS_negate_stmt
+0x00000701: 01 DW_LNS_copy
+            0x0000000000000433    102     27      1   0             0  is_stmt
+
+
+0x00000702: 00 DW_LNE_set_address (0x0000000000000438)
+0x00000709: 05 DW_LNS_set_column (18)
+0x0000070b: 06 DW_LNS_negate_stmt
+0x0000070c: 01 DW_LNS_copy
+            0x0000000000000438    102     18      1   0             0 
+
+
+0x0000070d: 00 DW_LNE_set_address (0x000000000000043e)
+0x00000714: 03 DW_LNS_advance_line (103)
+0x00000716: 06 DW_LNS_negate_stmt
+0x00000717: 01 DW_LNS_copy
+            0x000000000000043e    103     18      1   0             0  is_stmt
+
+
+0x00000718: 00 DW_LNE_set_address (0x000000000000044c)
+0x0000071f: 03 DW_LNS_advance_line (105)
+0x00000721: 01 DW_LNS_copy
+            0x000000000000044c    105     18      1   0             0  is_stmt
+
+
+0x00000722: 00 DW_LNE_set_address (0x0000000000000451)
+0x00000729: 05 DW_LNS_set_column (4)
+0x0000072b: 06 DW_LNS_negate_stmt
+0x0000072c: 01 DW_LNS_copy
+            0x0000000000000451    105      4      1   0             0 
+
+
+0x0000072d: 00 DW_LNE_set_address (0x0000000000000455)
+0x00000734: 03 DW_LNS_advance_line (106)
+0x00000736: 05 DW_LNS_set_column (7)
+0x00000738: 06 DW_LNS_negate_stmt
+0x00000739: 01 DW_LNS_copy
+            0x0000000000000455    106      7      1   0             0  is_stmt
+
+
+0x0000073a: 00 DW_LNE_set_address (0x000000000000045d)
+0x00000741: 05 DW_LNS_set_column (16)
+0x00000743: 06 DW_LNS_negate_stmt
+0x00000744: 01 DW_LNS_copy
+            0x000000000000045d    106     16      1   0             0 
+
+
+0x00000745: 00 DW_LNE_set_address (0x0000000000000462)
+0x0000074c: 03 DW_LNS_advance_line (105)
+0x0000074e: 05 DW_LNS_set_column (24)
+0x00000750: 06 DW_LNS_negate_stmt
+0x00000751: 01 DW_LNS_copy
+            0x0000000000000462    105     24      1   0             0  is_stmt
+
+
+0x00000752: 00 DW_LNE_set_address (0x0000000000000467)
+0x00000759: 05 DW_LNS_set_column (18)
+0x0000075b: 06 DW_LNS_negate_stmt
+0x0000075c: 01 DW_LNS_copy
+            0x0000000000000467    105     18      1   0             0 
+
+
+0x0000075d: 00 DW_LNE_set_address (0x000000000000048d)
+0x00000764: 03 DW_LNS_advance_line (112)
+0x00000766: 05 DW_LNS_set_column (13)
+0x00000768: 06 DW_LNS_negate_stmt
+0x00000769: 01 DW_LNS_copy
+            0x000000000000048d    112     13      1   0             0  is_stmt
+
+
+0x0000076a: 00 DW_LNE_set_address (0x000000000000048f)
+0x00000771: 05 DW_LNS_set_column (26)
+0x00000773: 06 DW_LNS_negate_stmt
+0x00000774: 01 DW_LNS_copy
+            0x000000000000048f    112     26      1   0             0 
+
+
+0x00000775: 00 DW_LNE_set_address (0x000000000000049c)
+0x0000077c: 05 DW_LNS_set_column (35)
+0x0000077e: 01 DW_LNS_copy
+            0x000000000000049c    112     35      1   0             0 
+
+
+0x0000077f: 00 DW_LNE_set_address (0x000000000000049d)
+0x00000786: 05 DW_LNS_set_column (13)
+0x00000788: 01 DW_LNS_copy
+            0x000000000000049d    112     13      1   0             0 
+
+
+0x00000789: 00 DW_LNE_set_address (0x00000000000004ab)
+0x00000790: 03 DW_LNS_advance_line (111)
+0x00000792: 05 DW_LNS_set_column (30)
+0x00000794: 06 DW_LNS_negate_stmt
+0x00000795: 01 DW_LNS_copy
+            0x00000000000004ab    111     30      1   0             0  is_stmt
+
+
+0x00000796: 00 DW_LNE_set_address (0x00000000000004b0)
+0x0000079d: 05 DW_LNS_set_column (24)
+0x0000079f: 06 DW_LNS_negate_stmt
+0x000007a0: 01 DW_LNS_copy
+            0x00000000000004b0    111     24      1   0             0 
+
+
+0x000007a1: 00 DW_LNE_set_address (0x00000000000004b5)
+0x000007a8: 05 DW_LNS_set_column (10)
+0x000007aa: 01 DW_LNS_copy
+            0x00000000000004b5    111     10      1   0             0 
+
+
+0x000007ab: 00 DW_LNE_set_address (0x00000000000004ba)
+0x000007b2: 03 DW_LNS_advance_line (113)
+0x000007b4: 06 DW_LNS_negate_stmt
+0x000007b5: 01 DW_LNS_copy
+            0x00000000000004ba    113     10      1   0             0  is_stmt
+
+
+0x000007b6: 00 DW_LNE_set_address (0x00000000000004bf)
+0x000007bd: 03 DW_LNS_advance_line (118)
+0x000007bf: 05 DW_LNS_set_column (16)
+0x000007c1: 01 DW_LNS_copy
+            0x00000000000004bf    118     16      1   0             0  is_stmt
+
+
+0x000007c2: 00 DW_LNE_set_address (0x00000000000004c4)
+0x000007c9: 05 DW_LNS_set_column (7)
+0x000007cb: 06 DW_LNS_negate_stmt
+0x000007cc: 01 DW_LNS_copy
+            0x00000000000004c4    118      7      1   0             0 
+
+
+0x000007cd: 00 DW_LNE_set_address (0x00000000000004c8)
+0x000007d4: 03 DW_LNS_advance_line (119)
+0x000007d6: 05 DW_LNS_set_column (10)
+0x000007d8: 06 DW_LNS_negate_stmt
+0x000007d9: 01 DW_LNS_copy
+            0x00000000000004c8    119     10      1   0             0  is_stmt
+
+
+0x000007da: 00 DW_LNE_set_address (0x00000000000004ca)
+0x000007e1: 05 DW_LNS_set_column (18)
+0x000007e3: 06 DW_LNS_negate_stmt
+0x000007e4: 01 DW_LNS_copy
+            0x00000000000004ca    119     18      1   0             0 
+
+
+0x000007e5: 00 DW_LNE_set_address (0x00000000000004d3)
+0x000007ec: 05 DW_LNS_set_column (10)
+0x000007ee: 01 DW_LNS_copy
+            0x00000000000004d3    119     10      1   0             0 
+
+
+0x000007ef: 00 DW_LNE_set_address (0x00000000000004d5)
+0x000007f6: 05 DW_LNS_set_column (23)
+0x000007f8: 01 DW_LNS_copy
+            0x00000000000004d5    119     23      1   0             0 
+
+
+0x000007f9: 00 DW_LNE_set_address (0x00000000000004da)
+0x00000800: 03 DW_LNS_advance_line (118)
+0x00000802: 05 DW_LNS_set_column (16)
+0x00000804: 06 DW_LNS_negate_stmt
+0x00000805: 01 DW_LNS_copy
+            0x00000000000004da    118     16      1   0             0  is_stmt
+
+
+0x00000806: 00 DW_LNE_set_address (0x00000000000004e5)
+0x0000080d: 05 DW_LNS_set_column (7)
+0x0000080f: 06 DW_LNS_negate_stmt
+0x00000810: 01 DW_LNS_copy
+            0x00000000000004e5    118      7      1   0             0 
+
+
+0x00000811: 00 DW_LNE_set_address (0x00000000000004eb)
+0x00000818: 03 DW_LNS_advance_line (122)
+0x0000081a: 05 DW_LNS_set_column (16)
+0x0000081c: 06 DW_LNS_negate_stmt
+0x0000081d: 01 DW_LNS_copy
+            0x00000000000004eb    122     16      1   0             0  is_stmt
+
+
+0x0000081e: 00 DW_LNE_set_address (0x00000000000004ff)
+0x00000825: 03 DW_LNS_advance_line (125)
+0x00000827: 05 DW_LNS_set_column (22)
+0x00000829: 01 DW_LNS_copy
+            0x00000000000004ff    125     22      1   0             0  is_stmt
+
+
+0x0000082a: 00 DW_LNE_set_address (0x0000000000000508)
+0x00000831: 03 DW_LNS_advance_line (126)
+0x00000833: 05 DW_LNS_set_column (27)
+0x00000835: 01 DW_LNS_copy
+            0x0000000000000508    126     27      1   0             0  is_stmt
+
+
+0x00000836: 00 DW_LNE_set_address (0x000000000000050d)
+0x0000083d: 05 DW_LNS_set_column (13)
+0x0000083f: 06 DW_LNS_negate_stmt
+0x00000840: 01 DW_LNS_copy
+            0x000000000000050d    126     13      1   0             0 
+
+
+0x00000841: 00 DW_LNE_set_address (0x0000000000000511)
+0x00000848: 03 DW_LNS_advance_line (127)
+0x0000084a: 05 DW_LNS_set_column (16)
+0x0000084c: 06 DW_LNS_negate_stmt
+0x0000084d: 01 DW_LNS_copy
+            0x0000000000000511    127     16      1   0             0  is_stmt
+
+
+0x0000084e: 00 DW_LNE_set_address (0x0000000000000519)
+0x00000855: 05 DW_LNS_set_column (27)
+0x00000857: 06 DW_LNS_negate_stmt
+0x00000858: 01 DW_LNS_copy
+            0x0000000000000519    127     27      1   0             0 
+
+
+0x00000859: 00 DW_LNE_set_address (0x000000000000051b)
+0x00000860: 05 DW_LNS_set_column (35)
+0x00000862: 01 DW_LNS_copy
+            0x000000000000051b    127     35      1   0             0 
+
+
+0x00000863: 00 DW_LNE_set_address (0x0000000000000524)
+0x0000086a: 05 DW_LNS_set_column (27)
+0x0000086c: 01 DW_LNS_copy
+            0x0000000000000524    127     27      1   0             0 
+
+
+0x0000086d: 00 DW_LNE_set_address (0x0000000000000529)
+0x00000874: 05 DW_LNS_set_column (25)
+0x00000876: 01 DW_LNS_copy
+            0x0000000000000529    127     25      1   0             0 
+
+
+0x00000877: 00 DW_LNE_set_address (0x000000000000052c)
+0x0000087e: 03 DW_LNS_advance_line (126)
+0x00000880: 05 DW_LNS_set_column (27)
+0x00000882: 06 DW_LNS_negate_stmt
+0x00000883: 01 DW_LNS_copy
+            0x000000000000052c    126     27      1   0             0  is_stmt
+
+
+0x00000884: 00 DW_LNE_set_address (0x0000000000000531)
+0x0000088b: 05 DW_LNS_set_column (13)
+0x0000088d: 06 DW_LNS_negate_stmt
+0x0000088e: 01 DW_LNS_copy
+            0x0000000000000531    126     13      1   0             0 
+
+
+0x0000088f: 00 DW_LNE_set_address (0x0000000000000539)
+0x00000896: 03 DW_LNS_advance_line (128)
+0x00000898: 06 DW_LNS_negate_stmt
+0x00000899: 01 DW_LNS_copy
+            0x0000000000000539    128     13      1   0             0  is_stmt
+
+
+0x0000089a: 00 DW_LNE_set_address (0x0000000000000541)
+0x000008a1: 05 DW_LNS_set_column (22)
+0x000008a3: 06 DW_LNS_negate_stmt
+0x000008a4: 01 DW_LNS_copy
+            0x0000000000000541    128     22      1   0             0 
+
+
+0x000008a5: 00 DW_LNE_set_address (0x0000000000000546)
+0x000008ac: 03 DW_LNS_advance_line (130)
+0x000008ae: 05 DW_LNS_set_column (16)
+0x000008b0: 06 DW_LNS_negate_stmt
+0x000008b1: 01 DW_LNS_copy
+            0x0000000000000546    130     16      1   0             0  is_stmt
+
+
+0x000008b2: 00 DW_LNE_set_address (0x000000000000054e)
+0x000008b9: 05 DW_LNS_set_column (14)
+0x000008bb: 06 DW_LNS_negate_stmt
+0x000008bc: 01 DW_LNS_copy
+            0x000000000000054e    130     14      1   0             0 
+
+
+0x000008bd: 00 DW_LNE_set_address (0x000000000000055f)
+0x000008c4: 05 DW_LNS_set_column (25)
+0x000008c6: 01 DW_LNS_copy
+            0x000000000000055f    130     25      1   0             0 
+
+
+0x000008c7: 00 DW_LNE_set_address (0x0000000000000564)
+0x000008ce: 05 DW_LNS_set_column (14)
+0x000008d0: 01 DW_LNS_copy
+            0x0000000000000564    130     14      1   0             0 
+
+
+0x000008d1: 00 DW_LNE_set_address (0x0000000000000566)
+0x000008d8: 03 DW_LNS_advance_line (133)
+0x000008da: 05 DW_LNS_set_column (11)
+0x000008dc: 06 DW_LNS_negate_stmt
+0x000008dd: 01 DW_LNS_copy
+            0x0000000000000566    133     11      1   0             0  is_stmt
+
+
+0x000008de: 00 DW_LNE_set_address (0x000000000000056b)
+0x000008e5: 03 DW_LNS_advance_line (122)
+0x000008e7: 05 DW_LNS_set_column (16)
+0x000008e9: 01 DW_LNS_copy
+            0x000000000000056b    122     16      1   0             0  is_stmt
+
+
+0x000008ea: 00 DW_LNE_set_address (0x0000000000000570)
+0x000008f1: 05 DW_LNS_set_column (14)
+0x000008f3: 06 DW_LNS_negate_stmt
+0x000008f4: 01 DW_LNS_copy
+            0x0000000000000570    122     14      1   0             0 
+
+
+0x000008f5: 00 DW_LNE_set_address (0x0000000000000575)
+0x000008fc: 03 DW_LNS_advance_line (130)
+0x000008fe: 06 DW_LNS_negate_stmt
+0x000008ff: 01 DW_LNS_copy
+            0x0000000000000575    130     14      1   0             0  is_stmt
+
+
+0x00000900: 00 DW_LNE_set_address (0x0000000000000576)
+0x00000907: 03 DW_LNS_advance_line (110)
+0x00000909: 05 DW_LNS_set_column (11)
+0x0000090b: 01 DW_LNS_copy
+            0x0000000000000576    110     11      1   0             0  is_stmt
+
+
+0x0000090c: 00 DW_LNE_set_address (0x0000000000000584)
+0x00000913: 03 DW_LNS_advance_line (113)
+0x00000915: 05 DW_LNS_set_column (10)
+0x00000917: 01 DW_LNS_copy
+            0x0000000000000584    113     10      1   0             0  is_stmt
+
+
+0x00000918: 00 DW_LNE_set_address (0x0000000000000589)
+0x0000091f: 03 DW_LNS_advance_line (118)
+0x00000921: 05 DW_LNS_set_column (16)
+0x00000923: 01 DW_LNS_copy
+            0x0000000000000589    118     16      1   0             0  is_stmt
+
+
+0x00000924: 00 DW_LNE_set_address (0x000000000000058e)
+0x0000092b: 05 DW_LNS_set_column (7)
+0x0000092d: 06 DW_LNS_negate_stmt
+0x0000092e: 01 DW_LNS_copy
+            0x000000000000058e    118      7      1   0             0 
+
+
+0x0000092f: 00 DW_LNE_set_address (0x0000000000000592)
+0x00000936: 03 DW_LNS_advance_line (119)
+0x00000938: 05 DW_LNS_set_column (10)
+0x0000093a: 06 DW_LNS_negate_stmt
+0x0000093b: 01 DW_LNS_copy
+            0x0000000000000592    119     10      1   0             0  is_stmt
+
+
+0x0000093c: 00 DW_LNE_set_address (0x0000000000000594)
+0x00000943: 05 DW_LNS_set_column (18)
+0x00000945: 06 DW_LNS_negate_stmt
+0x00000946: 01 DW_LNS_copy
+            0x0000000000000594    119     18      1   0             0 
+
+
+0x00000947: 00 DW_LNE_set_address (0x000000000000059d)
+0x0000094e: 05 DW_LNS_set_column (10)
+0x00000950: 01 DW_LNS_copy
+            0x000000000000059d    119     10      1   0             0 
+
+
+0x00000951: 00 DW_LNE_set_address (0x000000000000059f)
+0x00000958: 05 DW_LNS_set_column (23)
+0x0000095a: 01 DW_LNS_copy
+            0x000000000000059f    119     23      1   0             0 
+
+
+0x0000095b: 00 DW_LNE_set_address (0x00000000000005a4)
+0x00000962: 03 DW_LNS_advance_line (118)
+0x00000964: 05 DW_LNS_set_column (16)
+0x00000966: 06 DW_LNS_negate_stmt
+0x00000967: 01 DW_LNS_copy
+            0x00000000000005a4    118     16      1   0             0  is_stmt
+
+
+0x00000968: 00 DW_LNE_set_address (0x00000000000005af)
+0x0000096f: 05 DW_LNS_set_column (7)
+0x00000971: 06 DW_LNS_negate_stmt
+0x00000972: 01 DW_LNS_copy
+            0x00000000000005af    118      7      1   0             0 
+
+
+0x00000973: 00 DW_LNE_set_address (0x00000000000005b5)
+0x0000097a: 03 DW_LNS_advance_line (122)
+0x0000097c: 05 DW_LNS_set_column (16)
+0x0000097e: 06 DW_LNS_negate_stmt
+0x0000097f: 01 DW_LNS_copy
+            0x00000000000005b5    122     16      1   0             0  is_stmt
+
+
+0x00000980: 00 DW_LNE_set_address (0x00000000000005ba)
+0x00000987: 05 DW_LNS_set_column (14)
+0x00000989: 06 DW_LNS_negate_stmt
+0x0000098a: 01 DW_LNS_copy
+            0x00000000000005ba    122     14      1   0             0 
+
+
+0x0000098b: 00 DW_LNE_set_address (0x00000000000005c3)
+0x00000992: 03 DW_LNS_advance_line (125)
+0x00000994: 05 DW_LNS_set_column (22)
+0x00000996: 06 DW_LNS_negate_stmt
+0x00000997: 01 DW_LNS_copy
+            0x00000000000005c3    125     22      1   0             0  is_stmt
+
+
+0x00000998: 00 DW_LNE_set_address (0x00000000000005d2)
+0x0000099f: 03 DW_LNS_advance_line (126)
+0x000009a1: 05 DW_LNS_set_column (27)
+0x000009a3: 01 DW_LNS_copy
+            0x00000000000005d2    126     27      1   0             0  is_stmt
+
+
+0x000009a4: 00 DW_LNE_set_address (0x00000000000005d7)
+0x000009ab: 05 DW_LNS_set_column (13)
+0x000009ad: 06 DW_LNS_negate_stmt
+0x000009ae: 01 DW_LNS_copy
+            0x00000000000005d7    126     13      1   0             0 
+
+
+0x000009af: 00 DW_LNE_set_address (0x00000000000005db)
+0x000009b6: 03 DW_LNS_advance_line (127)
+0x000009b8: 05 DW_LNS_set_column (16)
+0x000009ba: 06 DW_LNS_negate_stmt
+0x000009bb: 01 DW_LNS_copy
+            0x00000000000005db    127     16      1   0             0  is_stmt
+
+
+0x000009bc: 00 DW_LNE_set_address (0x00000000000005e3)
+0x000009c3: 05 DW_LNS_set_column (27)
+0x000009c5: 06 DW_LNS_negate_stmt
+0x000009c6: 01 DW_LNS_copy
+            0x00000000000005e3    127     27      1   0             0 
+
+
+0x000009c7: 00 DW_LNE_set_address (0x00000000000005e5)
+0x000009ce: 05 DW_LNS_set_column (35)
+0x000009d0: 01 DW_LNS_copy
+            0x00000000000005e5    127     35      1   0             0 
+
+
+0x000009d1: 00 DW_LNE_set_address (0x00000000000005ee)
+0x000009d8: 05 DW_LNS_set_column (27)
+0x000009da: 01 DW_LNS_copy
+            0x00000000000005ee    127     27      1   0             0 
+
+
+0x000009db: 00 DW_LNE_set_address (0x00000000000005f3)
+0x000009e2: 05 DW_LNS_set_column (25)
+0x000009e4: 01 DW_LNS_copy
+            0x00000000000005f3    127     25      1   0             0 
+
+
+0x000009e5: 00 DW_LNE_set_address (0x00000000000005f6)
+0x000009ec: 03 DW_LNS_advance_line (126)
+0x000009ee: 05 DW_LNS_set_column (27)
+0x000009f0: 06 DW_LNS_negate_stmt
+0x000009f1: 01 DW_LNS_copy
+            0x00000000000005f6    126     27      1   0             0  is_stmt
+
+
+0x000009f2: 00 DW_LNE_set_address (0x00000000000005fb)
+0x000009f9: 05 DW_LNS_set_column (13)
+0x000009fb: 06 DW_LNS_negate_stmt
+0x000009fc: 01 DW_LNS_copy
+            0x00000000000005fb    126     13      1   0             0 
+
+
+0x000009fd: 00 DW_LNE_set_address (0x0000000000000603)
+0x00000a04: 03 DW_LNS_advance_line (128)
+0x00000a06: 06 DW_LNS_negate_stmt
+0x00000a07: 01 DW_LNS_copy
+            0x0000000000000603    128     13      1   0             0  is_stmt
+
+
+0x00000a08: 00 DW_LNE_set_address (0x000000000000060b)
+0x00000a0f: 05 DW_LNS_set_column (22)
+0x00000a11: 06 DW_LNS_negate_stmt
+0x00000a12: 01 DW_LNS_copy
+            0x000000000000060b    128     22      1   0             0 
+
+
+0x00000a13: 00 DW_LNE_set_address (0x0000000000000610)
+0x00000a1a: 03 DW_LNS_advance_line (130)
+0x00000a1c: 05 DW_LNS_set_column (16)
+0x00000a1e: 06 DW_LNS_negate_stmt
+0x00000a1f: 01 DW_LNS_copy
+            0x0000000000000610    130     16      1   0             0  is_stmt
+
+
+0x00000a20: 00 DW_LNE_set_address (0x0000000000000618)
+0x00000a27: 05 DW_LNS_set_column (14)
+0x00000a29: 06 DW_LNS_negate_stmt
+0x00000a2a: 01 DW_LNS_copy
+            0x0000000000000618    130     14      1   0             0 
+
+
+0x00000a2b: 00 DW_LNE_set_address (0x0000000000000629)
+0x00000a32: 05 DW_LNS_set_column (25)
+0x00000a34: 01 DW_LNS_copy
+            0x0000000000000629    130     25      1   0             0 
+
+
+0x00000a35: 00 DW_LNE_set_address (0x000000000000062e)
+0x00000a3c: 05 DW_LNS_set_column (14)
+0x00000a3e: 01 DW_LNS_copy
+            0x000000000000062e    130     14      1   0             0 
+
+
+0x00000a3f: 00 DW_LNE_set_address (0x0000000000000630)
+0x00000a46: 03 DW_LNS_advance_line (133)
+0x00000a48: 05 DW_LNS_set_column (11)
+0x00000a4a: 06 DW_LNS_negate_stmt
+0x00000a4b: 01 DW_LNS_copy
+            0x0000000000000630    133     11      1   0             0  is_stmt
+
+
+0x00000a4c: 00 DW_LNE_set_address (0x0000000000000635)
+0x00000a53: 03 DW_LNS_advance_line (122)
+0x00000a55: 05 DW_LNS_set_column (16)
+0x00000a57: 01 DW_LNS_copy
+            0x0000000000000635    122     16      1   0             0  is_stmt
+
+
+0x00000a58: 00 DW_LNE_set_address (0x000000000000063a)
+0x00000a5f: 05 DW_LNS_set_column (14)
+0x00000a61: 06 DW_LNS_negate_stmt
+0x00000a62: 01 DW_LNS_copy
+            0x000000000000063a    122     14      1   0             0 
+
+
+0x00000a63: 00 DW_LNE_set_address (0x000000000000063f)
+0x00000a6a: 03 DW_LNS_advance_line (130)
+0x00000a6c: 06 DW_LNS_negate_stmt
+0x00000a6d: 01 DW_LNS_copy
+            0x000000000000063f    130     14      1   0             0  is_stmt
+
+
+0x00000a6e: 00 DW_LNE_set_address (0x0000000000000640)
+0x00000a75: 03 DW_LNS_advance_line (110)
+0x00000a77: 05 DW_LNS_set_column (11)
+0x00000a79: 01 DW_LNS_copy
+            0x0000000000000640    110     11      1   0             0  is_stmt
+
+
+0x00000a7a: 00 DW_LNE_set_address (0x0000000000000646)
+0x00000a81: 03 DW_LNS_advance_line (138)
+0x00000a83: 05 DW_LNS_set_column (4)
+0x00000a85: 01 DW_LNS_copy
+            0x0000000000000646    138      4      1   0             0  is_stmt
+
+
+0x00000a86: 00 DW_LNE_set_address (0x000000000000064a)
+0x00000a8d: 03 DW_LNS_advance_line (139)
+0x00000a8f: 01 DW_LNS_copy
+            0x000000000000064a    139      4      1   0             0  is_stmt
+
+
+0x00000a90: 00 DW_LNE_set_address (0x0000000000000656)
+0x00000a97: 03 DW_LNS_advance_line (141)
+0x00000a99: 01 DW_LNS_copy
+            0x0000000000000656    141      4      1   0             0  is_stmt
+
+
+0x00000a9a: 00 DW_LNE_set_address (0x0000000000000661)
+0x00000aa1: 03 DW_LNS_advance_line (142)
+0x00000aa3: 05 DW_LNS_set_column (20)
+0x00000aa5: 01 DW_LNS_copy
+            0x0000000000000661    142     20      1   0             0  is_stmt
+
+
+0x00000aa6: 00 DW_LNE_set_address (0x0000000000000669)
+0x00000aad: 03 DW_LNS_advance_line (146)
+0x00000aaf: 01 DW_LNS_copy
+            0x0000000000000669    146     20      1   0             0  is_stmt
+
+
+0x00000ab0: 00 DW_LNE_set_address (0x0000000000000670)
+0x00000ab7: 03 DW_LNS_advance_line (147)
+0x00000ab9: 05 DW_LNS_set_column (7)
+0x00000abb: 01 DW_LNS_copy
+            0x0000000000000670    147      7      1   0             0  is_stmt
+
+
+0x00000abc: 00 DW_LNE_set_address (0x0000000000000674)
+0x00000ac3: 03 DW_LNS_advance_line (143)
+0x00000ac5: 05 DW_LNS_set_column (11)
+0x00000ac7: 01 DW_LNS_copy
+            0x0000000000000674    143     11      1   0             0  is_stmt
+
+
+0x00000ac8: 00 DW_LNE_set_address (0x0000000000000678)
+0x00000acf: 05 DW_LNS_set_column (20)
+0x00000ad1: 06 DW_LNS_negate_stmt
+0x00000ad2: 01 DW_LNS_copy
+            0x0000000000000678    143     20      1   0             0 
+
+
+0x00000ad3: 00 DW_LNE_set_address (0x000000000000067d)
+0x00000ada: 05 DW_LNS_set_column (11)
+0x00000adc: 01 DW_LNS_copy
+            0x000000000000067d    143     11      1   0             0 
+
+
+0x00000add: 00 DW_LNE_set_address (0x0000000000000684)
+0x00000ae4: 03 DW_LNS_advance_line (141)
+0x00000ae6: 05 DW_LNS_set_column (4)
+0x00000ae8: 06 DW_LNS_negate_stmt
+0x00000ae9: 01 DW_LNS_copy
+            0x0000000000000684    141      4      1   0             0  is_stmt
+
+
+0x00000aea: 00 DW_LNE_set_address (0x000000000000068a)
+0x00000af1: 03 DW_LNS_advance_line (159)
+0x00000af3: 01 DW_LNS_copy
+            0x000000000000068a    159      4      1   0             0  is_stmt
+
+
+0x00000af4: 00 DW_LNE_set_address (0x00000000000006a1)
+0x00000afb: 03 DW_LNS_advance_line (161)
+0x00000afd: 05 DW_LNS_set_column (1)
+0x00000aff: 01 DW_LNS_copy
+            0x00000000000006a1    161      1      1   0             0  is_stmt
+
+
+0x00000b00: 00 DW_LNE_set_address (0x00000000000006ab)
+0x00000b07: 00 DW_LNE_end_sequence
+            0x00000000000006ab    161      1      1   0             0  is_stmt end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)"
+0x00000069: "/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp"
+0x000000a9: "/usr/local/google/home/azakai/Dev/2-binaryen"
+0x000000d6: "i"
+0x000000d8: "int"
+0x000000dc: "n"
+0x000000de: "next"
+0x000000e3: "worker_args"
+0x000000ef: "std"
+0x000000f3: "decltype(nullptr)"
+0x00000105: "nullptr_t"
+0x0000010f: "free"
+0x00000114: "_ZL8fannkuchi"
+0x00000122: "fannkuch"
+0x0000012b: "showmax"
+0x00000133: "args"
+0x00000138: "targs"
+0x0000013e: "perm1"
+0x00000144: "count"
+0x0000014a: "r"
+0x0000014c: "maxflips"
+0x00000155: "flips"
+0x0000015b: "cleanup"
+0x00000163: "p0"
+0x00000166: "_Z15fannkuch_workerPv"
+0x0000017c: "fannkuch_worker"
+0x0000018c: "main"
+0x00000191: "_arg"
+0x00000196: "perm"
+0x0000019b: "k"
+0x0000019d: "j"
+0x0000019f: "tmp"
+0x000001a3: "argc"
+0x000001a8: "argv"
+0x000001ad: "char"
+
+.debug_ranges contents:
+00000000 00000193 000001d1
+00000000 000001fb 00000204
+00000000 0000031e 0000035c
+00000000 00000386 0000038f
+00000000 <End of list>
+00000028 000004ff 00000546
+00000028 000005c3 00000610
+00000028 <End of list>
+00000040 00000006 000003a3
+00000040 000003a5 000006ab
+00000040 <End of list>
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_none (func))
+ (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.\00")
+ (import "env" "__indirect_function_table" (table $timport$1 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)))
+ (import "env" "atoi" (func $atoi (param i32) (result i32)))
+ (import "env" "puts" (func $puts (param i32) (result i32)))
+ (import "env" "iprintf" (func $iprintf (param i32 i32) (result i32)))
+ (import "env" "putchar" (func $putchar (param i32) (result i32)))
+ (global $global$0 (mut i32) (i32.const 5243952))
+ (global $global$1 i32 (i32.const 1066))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__data_end" (global $global$1))
+ (func $__wasm_call_ctors
+ )
+ (func $fannkuch_worker\28void*\29 (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  ;; code offset: 0x29
+  (local.set $1
+   ;; code offset: 0x27
+   (i32.const 0)
+  )
+  ;; code offset: 0x39
+  (local.set $4
+   ;; code offset: 0x37
+   (call $malloc
+    ;; code offset: 0x35
+    (local.tee $3
+     ;; code offset: 0x34
+     (i32.shl
+      ;; code offset: 0x30
+      (local.tee $2
+       ;; code offset: 0x2d
+       (i32.load offset=4
+        ;; code offset: 0x2b
+        (local.get $0)
+       )
+      )
+      ;; code offset: 0x32
+      (i32.const 2)
+     )
+    )
+   )
+  )
+  ;; code offset: 0x3f
+  (local.set $5
+   ;; code offset: 0x3d
+   (call $malloc
+    ;; code offset: 0x3b
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x45
+  (local.set $6
+   ;; code offset: 0x43
+   (call $malloc
+    ;; code offset: 0x41
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x47
+  (block $label$1
+   (block $label$2
+    (block $label$3
+     ;; code offset: 0x52
+     (br_if $label$3
+      ;; code offset: 0x51
+      (i32.le_s
+       ;; code offset: 0x4d
+       (local.get $2)
+       ;; code offset: 0x4f
+       (i32.const 0)
+      )
+     )
+     ;; code offset: 0x54
+     (loop $label$4
+      ;; code offset: 0x60
+      (i32.store
+       ;; code offset: 0x5d
+       (i32.add
+        ;; code offset: 0x56
+        (local.get $4)
+        ;; code offset: 0x5c
+        (i32.shl
+         ;; code offset: 0x58
+         (local.get $1)
+         ;; code offset: 0x5a
+         (i32.const 2)
+        )
+       )
+       ;; code offset: 0x5e
+       (local.get $1)
+      )
+      ;; code offset: 0x6d
+      (br_if $label$4
+       ;; code offset: 0x6c
+       (i32.ne
+        ;; code offset: 0x68
+        (local.tee $1
+         ;; code offset: 0x67
+         (i32.add
+          ;; code offset: 0x63
+          (local.get $1)
+          ;; code offset: 0x65
+          (i32.const 1)
+         )
+        )
+        ;; code offset: 0x6a
+        (local.get $2)
+       )
+      )
+     )
+     ;; code offset: 0x84
+     (i32.store
+      ;; code offset: 0x7c
+      (i32.add
+       ;; code offset: 0x70
+       (local.get $4)
+       ;; code offset: 0x7b
+       (i32.shl
+        ;; code offset: 0x77
+        (local.tee $1
+         ;; code offset: 0x74
+         (i32.load
+          ;; code offset: 0x72
+          (local.get $0)
+         )
+        )
+        ;; code offset: 0x79
+        (i32.const 2)
+       )
+      )
+      ;; code offset: 0x82
+      (local.tee $7
+       ;; code offset: 0x81
+       (i32.add
+        ;; code offset: 0x7d
+        (local.get $2)
+        ;; code offset: 0x7f
+        (i32.const -1)
+       )
+      )
+     )
+     ;; code offset: 0x93
+     (i32.store
+      ;; code offset: 0x8f
+      (local.tee $8
+       ;; code offset: 0x8e
+       (i32.add
+        ;; code offset: 0x87
+        (local.get $4)
+        ;; code offset: 0x8d
+        (i32.shl
+         ;; code offset: 0x89
+         (local.get $7)
+         ;; code offset: 0x8b
+         (i32.const 2)
+        )
+       )
+      )
+      ;; code offset: 0x91
+      (local.get $1)
+     )
+     ;; code offset: 0x98
+     (local.set $9
+      ;; code offset: 0x96
+      (i32.const 0)
+     )
+     ;; code offset: 0x9f
+     (br_if $label$2
+      ;; code offset: 0x9e
+      (i32.le_s
+       ;; code offset: 0x9a
+       (local.get $2)
+       ;; code offset: 0x9c
+       (i32.const 0)
+      )
+     )
+     ;; code offset: 0xa1
+     (loop $label$5
+      ;; code offset: 0xa3
+      (block $label$6
+       ;; code offset: 0xaa
+       (br_if $label$6
+        ;; code offset: 0xa9
+        (i32.le_s
+         ;; code offset: 0xa5
+         (local.get $2)
+         ;; code offset: 0xa7
+         (i32.const 1)
+        )
+       )
+       ;; code offset: 0xac
+       (loop $label$7
+        ;; code offset: 0xbd
+        (i32.store
+         ;; code offset: 0xba
+         (i32.add
+          ;; code offset: 0xae
+          (local.get $6)
+          ;; code offset: 0xb9
+          (i32.shl
+           ;; code offset: 0xb5
+           (local.tee $1
+            ;; code offset: 0xb4
+            (i32.add
+             ;; code offset: 0xb0
+             (local.get $2)
+             ;; code offset: 0xb2
+             (i32.const -1)
+            )
+           )
+           ;; code offset: 0xb7
+           (i32.const 2)
+          )
+         )
+         ;; code offset: 0xbb
+         (local.get $2)
+        )
+        ;; code offset: 0xc5
+        (local.set $0
+         ;; code offset: 0xc4
+         (i32.gt_s
+          ;; code offset: 0xc0
+          (local.get $2)
+          ;; code offset: 0xc2
+          (i32.const 2)
+         )
+        )
+        ;; code offset: 0xc9
+        (local.set $2
+         ;; code offset: 0xc7
+         (local.get $1)
+        )
+        ;; code offset: 0xcd
+        (br_if $label$7
+         ;; code offset: 0xcb
+         (local.get $0)
+        )
+       )
+      )
+      ;; code offset: 0xd1
+      (block $label$8
+       ;; code offset: 0xdb
+       (br_if $label$8
+        ;; code offset: 0xda
+        (i32.eqz
+         ;; code offset: 0xd8
+         (local.tee $10
+          ;; code offset: 0xd5
+          (i32.load
+           ;; code offset: 0xd3
+           (local.get $4)
+          )
+         )
+        )
+       )
+       ;; code offset: 0xe5
+       (br_if $label$8
+        ;; code offset: 0xe4
+        (i32.eq
+         ;; code offset: 0xdf
+         (i32.load
+          ;; code offset: 0xdd
+          (local.get $8)
+         )
+         ;; code offset: 0xe2
+         (local.get $7)
+        )
+       )
+       ;; code offset: 0xf4
+       (local.set $12
+        ;; code offset: 0xf1
+        (i32.load
+         ;; code offset: 0xef
+         (local.tee $11
+          ;; code offset: 0xed
+          (call $memcpy
+           ;; code offset: 0xe7
+           (local.get $5)
+           ;; code offset: 0xe9
+           (local.get $4)
+           ;; code offset: 0xeb
+           (local.get $3)
+          )
+         )
+        )
+       )
+       ;; code offset: 0xf8
+       (local.set $0
+        ;; code offset: 0xf6
+        (i32.const 0)
+       )
+       ;; code offset: 0xfa
+       (loop $label$9
+        ;; code offset: 0xfe
+        (local.set $13
+         ;; code offset: 0xfc
+         (local.get $0)
+        )
+        ;; code offset: 0x100
+        (block $label$10
+         ;; code offset: 0x107
+         (br_if $label$10
+          ;; code offset: 0x106
+          (i32.lt_s
+           ;; code offset: 0x102
+           (local.get $12)
+           ;; code offset: 0x104
+           (i32.const 3)
+          )
+         )
+         ;; code offset: 0x10e
+         (local.set $1
+          ;; code offset: 0x10d
+          (i32.add
+           ;; code offset: 0x109
+           (local.get $12)
+           ;; code offset: 0x10b
+           (i32.const -1)
+          )
+         )
+         ;; code offset: 0x112
+         (local.set $0
+          ;; code offset: 0x110
+          (i32.const 1)
+         )
+         ;; code offset: 0x114
+         (loop $label$11
+          ;; code offset: 0x123
+          (local.set $15
+           ;; code offset: 0x120
+           (i32.load
+            ;; code offset: 0x11e
+            (local.tee $14
+             ;; code offset: 0x11d
+             (i32.add
+              ;; code offset: 0x116
+              (local.get $11)
+              ;; code offset: 0x11c
+              (i32.shl
+               ;; code offset: 0x118
+               (local.get $0)
+               ;; code offset: 0x11a
+               (i32.const 2)
+              )
+             )
+            )
+           )
+          )
+          ;; code offset: 0x134
+          (i32.store
+           ;; code offset: 0x125
+           (local.get $14)
+           ;; code offset: 0x131
+           (i32.load
+            ;; code offset: 0x12f
+            (local.tee $16
+             ;; code offset: 0x12e
+             (i32.add
+              ;; code offset: 0x127
+              (local.get $11)
+              ;; code offset: 0x12d
+              (i32.shl
+               ;; code offset: 0x129
+               (local.get $1)
+               ;; code offset: 0x12b
+               (i32.const 2)
+              )
+             )
+            )
+           )
+          )
+          ;; code offset: 0x13b
+          (i32.store
+           ;; code offset: 0x137
+           (local.get $16)
+           ;; code offset: 0x139
+           (local.get $15)
+          )
+          ;; code offset: 0x14d
+          (br_if $label$11
+           ;; code offset: 0x14c
+           (i32.lt_s
+            ;; code offset: 0x143
+            (local.tee $0
+             ;; code offset: 0x142
+             (i32.add
+              ;; code offset: 0x13e
+              (local.get $0)
+              ;; code offset: 0x140
+              (i32.const 1)
+             )
+            )
+            ;; code offset: 0x14a
+            (local.tee $1
+             ;; code offset: 0x149
+             (i32.add
+              ;; code offset: 0x145
+              (local.get $1)
+              ;; code offset: 0x147
+              (i32.const -1)
+             )
+            )
+           )
+          )
+         )
+        )
+        ;; code offset: 0x15e
+        (local.set $1
+         ;; code offset: 0x15b
+         (i32.load
+          ;; code offset: 0x159
+          (local.tee $0
+           ;; code offset: 0x158
+           (i32.add
+            ;; code offset: 0x151
+            (local.get $11)
+            ;; code offset: 0x157
+            (i32.shl
+             ;; code offset: 0x153
+             (local.get $12)
+             ;; code offset: 0x155
+             (i32.const 2)
+            )
+           )
+          )
+         )
+        )
+        ;; code offset: 0x164
+        (i32.store
+         ;; code offset: 0x160
+         (local.get $0)
+         ;; code offset: 0x162
+         (local.get $12)
+        )
+        ;; code offset: 0x16c
+        (local.set $0
+         ;; code offset: 0x16b
+         (i32.add
+          ;; code offset: 0x167
+          (local.get $13)
+          ;; code offset: 0x169
+          (i32.const 1)
+         )
+        )
+        ;; code offset: 0x170
+        (local.set $12
+         ;; code offset: 0x16e
+         (local.get $1)
+        )
+        ;; code offset: 0x174
+        (br_if $label$9
+         ;; code offset: 0x172
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x181
+       (local.set $9
+        ;; code offset: 0x180
+        (select
+         ;; code offset: 0x177
+         (local.get $9)
+         ;; code offset: 0x179
+         (local.get $0)
+         ;; code offset: 0x17f
+         (i32.gt_s
+          ;; code offset: 0x17b
+          (local.get $9)
+          ;; code offset: 0x17d
+          (local.get $13)
+         )
+        )
+       )
+      )
+      ;; code offset: 0x189
+      (br_if $label$1
+       ;; code offset: 0x188
+       (i32.ge_s
+        ;; code offset: 0x184
+        (local.get $2)
+        ;; code offset: 0x186
+        (local.get $7)
+       )
+      )
+      ;; code offset: 0x18b
+      (loop $label$12
+       ;; code offset: 0x18f
+       (local.set $1
+        ;; code offset: 0x18d
+        (i32.const 0)
+       )
+       ;; code offset: 0x191
+       (block $label$13
+        ;; code offset: 0x198
+        (br_if $label$13
+         ;; code offset: 0x197
+         (i32.le_s
+          ;; code offset: 0x193
+          (local.get $2)
+          ;; code offset: 0x195
+          (i32.const 0)
+         )
+        )
+        ;; code offset: 0x19a
+        (loop $label$14
+         ;; code offset: 0x1b4
+         (i32.store
+          ;; code offset: 0x1a3
+          (i32.add
+           ;; code offset: 0x19c
+           (local.get $4)
+           ;; code offset: 0x1a2
+           (i32.shl
+            ;; code offset: 0x19e
+            (local.get $1)
+            ;; code offset: 0x1a0
+            (i32.const 2)
+           )
+          )
+          ;; code offset: 0x1b1
+          (i32.load
+           ;; code offset: 0x1b0
+           (i32.add
+            ;; code offset: 0x1a4
+            (local.get $4)
+            ;; code offset: 0x1af
+            (i32.shl
+             ;; code offset: 0x1ab
+             (local.tee $1
+              ;; code offset: 0x1aa
+              (i32.add
+               ;; code offset: 0x1a6
+               (local.get $1)
+               ;; code offset: 0x1a8
+               (i32.const 1)
+              )
+             )
+             ;; code offset: 0x1ad
+             (i32.const 2)
+            )
+           )
+          )
+         )
+         ;; code offset: 0x1bc
+         (br_if $label$14
+          ;; code offset: 0x1bb
+          (i32.ne
+           ;; code offset: 0x1b7
+           (local.get $1)
+           ;; code offset: 0x1b9
+           (local.get $2)
+          )
+         )
+        )
+        ;; code offset: 0x1c1
+        (local.set $1
+         ;; code offset: 0x1bf
+         (local.get $2)
+        )
+       )
+       ;; code offset: 0x1ce
+       (i32.store
+        ;; code offset: 0x1cb
+        (i32.add
+         ;; code offset: 0x1c4
+         (local.get $4)
+         ;; code offset: 0x1ca
+         (i32.shl
+          ;; code offset: 0x1c6
+          (local.get $1)
+          ;; code offset: 0x1c8
+          (i32.const 2)
+         )
+        )
+        ;; code offset: 0x1cc
+        (local.get $10)
+       )
+       ;; code offset: 0x1e5
+       (i32.store
+        ;; code offset: 0x1d9
+        (local.tee $1
+         ;; code offset: 0x1d8
+         (i32.add
+          ;; code offset: 0x1d1
+          (local.get $6)
+          ;; code offset: 0x1d7
+          (i32.shl
+           ;; code offset: 0x1d3
+           (local.get $2)
+           ;; code offset: 0x1d5
+           (i32.const 2)
+          )
+         )
+        )
+        ;; code offset: 0x1e4
+        (i32.add
+         ;; code offset: 0x1e0
+         (local.tee $1
+          ;; code offset: 0x1dd
+          (i32.load
+           ;; code offset: 0x1db
+           (local.get $1)
+          )
+         )
+         ;; code offset: 0x1e2
+         (i32.const -1)
+        )
+       )
+       ;; code offset: 0x1ed
+       (br_if $label$5
+        ;; code offset: 0x1ec
+        (i32.gt_s
+         ;; code offset: 0x1e8
+         (local.get $1)
+         ;; code offset: 0x1ea
+         (i32.const 1)
+        )
+       )
+       ;; code offset: 0x1f9
+       (br_if $label$1
+        ;; code offset: 0x1f8
+        (i32.eq
+         ;; code offset: 0x1f4
+         (local.tee $2
+          ;; code offset: 0x1f3
+          (i32.add
+           ;; code offset: 0x1ef
+           (local.get $2)
+           ;; code offset: 0x1f1
+           (i32.const 1)
+          )
+         )
+         ;; code offset: 0x1f6
+         (local.get $7)
+        )
+       )
+       ;; code offset: 0x200
+       (local.set $10
+        ;; code offset: 0x1fd
+        (i32.load
+         ;; code offset: 0x1fb
+         (local.get $4)
+        )
+       )
+       ;; code offset: 0x202
+       (br $label$12)
+      )
+     )
+    )
+    ;; code offset: 0x21d
+    (i32.store
+     ;; code offset: 0x215
+     (i32.add
+      ;; code offset: 0x209
+      (local.get $4)
+      ;; code offset: 0x214
+      (i32.shl
+       ;; code offset: 0x210
+       (local.tee $1
+        ;; code offset: 0x20d
+        (i32.load
+         ;; code offset: 0x20b
+         (local.get $0)
+        )
+       )
+       ;; code offset: 0x212
+       (i32.const 2)
+      )
+     )
+     ;; code offset: 0x21b
+     (local.tee $7
+      ;; code offset: 0x21a
+      (i32.add
+       ;; code offset: 0x216
+       (local.get $2)
+       ;; code offset: 0x218
+       (i32.const -1)
+      )
+     )
+    )
+    ;; code offset: 0x22c
+    (i32.store
+     ;; code offset: 0x228
+     (local.tee $8
+      ;; code offset: 0x227
+      (i32.add
+       ;; code offset: 0x220
+       (local.get $4)
+       ;; code offset: 0x226
+       (i32.shl
+        ;; code offset: 0x222
+        (local.get $7)
+        ;; code offset: 0x224
+        (i32.const 2)
+       )
+      )
+     )
+     ;; code offset: 0x22a
+     (local.get $1)
+    )
+   )
+   ;; code offset: 0x232
+   (local.set $9
+    ;; code offset: 0x230
+    (i32.const 0)
+   )
+   ;; code offset: 0x234
+   (loop $label$15
+    ;; code offset: 0x236
+    (block $label$16
+     ;; code offset: 0x23d
+     (br_if $label$16
+      ;; code offset: 0x23c
+      (i32.lt_s
+       ;; code offset: 0x238
+       (local.get $2)
+       ;; code offset: 0x23a
+       (i32.const 2)
+      )
+     )
+     ;; code offset: 0x23f
+     (loop $label$17
+      ;; code offset: 0x250
+      (i32.store
+       ;; code offset: 0x24d
+       (i32.add
+        ;; code offset: 0x241
+        (local.get $6)
+        ;; code offset: 0x24c
+        (i32.shl
+         ;; code offset: 0x248
+         (local.tee $1
+          ;; code offset: 0x247
+          (i32.add
+           ;; code offset: 0x243
+           (local.get $2)
+           ;; code offset: 0x245
+           (i32.const -1)
+          )
+         )
+         ;; code offset: 0x24a
+         (i32.const 2)
+        )
+       )
+       ;; code offset: 0x24e
+       (local.get $2)
+      )
+      ;; code offset: 0x258
+      (local.set $0
+       ;; code offset: 0x257
+       (i32.gt_s
+        ;; code offset: 0x253
+        (local.get $2)
+        ;; code offset: 0x255
+        (i32.const 2)
+       )
+      )
+      ;; code offset: 0x25c
+      (local.set $2
+       ;; code offset: 0x25a
+       (local.get $1)
+      )
+      ;; code offset: 0x260
+      (br_if $label$17
+       ;; code offset: 0x25e
+       (local.get $0)
+      )
+     )
+    )
+    ;; code offset: 0x264
+    (block $label$18
+     ;; code offset: 0x26e
+     (br_if $label$18
+      ;; code offset: 0x26d
+      (i32.eqz
+       ;; code offset: 0x26b
+       (local.tee $12
+        ;; code offset: 0x268
+        (i32.load
+         ;; code offset: 0x266
+         (local.get $4)
+        )
+       )
+      )
+     )
+     ;; code offset: 0x278
+     (br_if $label$18
+      ;; code offset: 0x277
+      (i32.eq
+       ;; code offset: 0x272
+       (i32.load
+        ;; code offset: 0x270
+        (local.get $8)
+       )
+       ;; code offset: 0x275
+       (local.get $7)
+      )
+     )
+     ;; code offset: 0x27f
+     (local.set $16
+      ;; code offset: 0x27c
+      (i32.load
+       ;; code offset: 0x27a
+       (local.get $5)
+      )
+     )
+     ;; code offset: 0x283
+     (local.set $0
+      ;; code offset: 0x281
+      (i32.const 0)
+     )
+     ;; code offset: 0x285
+     (loop $label$19
+      ;; code offset: 0x289
+      (local.set $10
+       ;; code offset: 0x287
+       (local.get $0)
+      )
+      ;; code offset: 0x28b
+      (block $label$20
+       ;; code offset: 0x292
+       (br_if $label$20
+        ;; code offset: 0x291
+        (i32.lt_s
+         ;; code offset: 0x28d
+         (local.get $16)
+         ;; code offset: 0x28f
+         (i32.const 3)
+        )
+       )
+       ;; code offset: 0x299
+       (local.set $1
+        ;; code offset: 0x298
+        (i32.add
+         ;; code offset: 0x294
+         (local.get $16)
+         ;; code offset: 0x296
+         (i32.const -1)
+        )
+       )
+       ;; code offset: 0x29d
+       (local.set $0
+        ;; code offset: 0x29b
+        (i32.const 1)
+       )
+       ;; code offset: 0x29f
+       (loop $label$21
+        ;; code offset: 0x2ae
+        (local.set $14
+         ;; code offset: 0x2ab
+         (i32.load
+          ;; code offset: 0x2a9
+          (local.tee $11
+           ;; code offset: 0x2a8
+           (i32.add
+            ;; code offset: 0x2a1
+            (local.get $5)
+            ;; code offset: 0x2a7
+            (i32.shl
+             ;; code offset: 0x2a3
+             (local.get $0)
+             ;; code offset: 0x2a5
+             (i32.const 2)
+            )
+           )
+          )
+         )
+        )
+        ;; code offset: 0x2bf
+        (i32.store
+         ;; code offset: 0x2b0
+         (local.get $11)
+         ;; code offset: 0x2bc
+         (i32.load
+          ;; code offset: 0x2ba
+          (local.tee $15
+           ;; code offset: 0x2b9
+           (i32.add
+            ;; code offset: 0x2b2
+            (local.get $5)
+            ;; code offset: 0x2b8
+            (i32.shl
+             ;; code offset: 0x2b4
+             (local.get $1)
+             ;; code offset: 0x2b6
+             (i32.const 2)
+            )
+           )
+          )
+         )
+        )
+        ;; code offset: 0x2c6
+        (i32.store
+         ;; code offset: 0x2c2
+         (local.get $15)
+         ;; code offset: 0x2c4
+         (local.get $14)
+        )
+        ;; code offset: 0x2d8
+        (br_if $label$21
+         ;; code offset: 0x2d7
+         (i32.lt_s
+          ;; code offset: 0x2ce
+          (local.tee $0
+           ;; code offset: 0x2cd
+           (i32.add
+            ;; code offset: 0x2c9
+            (local.get $0)
+            ;; code offset: 0x2cb
+            (i32.const 1)
+           )
+          )
+          ;; code offset: 0x2d5
+          (local.tee $1
+           ;; code offset: 0x2d4
+           (i32.add
+            ;; code offset: 0x2d0
+            (local.get $1)
+            ;; code offset: 0x2d2
+            (i32.const -1)
+           )
+          )
+         )
+        )
+       )
+      )
+      ;; code offset: 0x2e9
+      (local.set $1
+       ;; code offset: 0x2e6
+       (i32.load
+        ;; code offset: 0x2e4
+        (local.tee $0
+         ;; code offset: 0x2e3
+         (i32.add
+          ;; code offset: 0x2dc
+          (local.get $5)
+          ;; code offset: 0x2e2
+          (i32.shl
+           ;; code offset: 0x2de
+           (local.get $16)
+           ;; code offset: 0x2e0
+           (i32.const 2)
+          )
+         )
+        )
+       )
+      )
+      ;; code offset: 0x2ef
+      (i32.store
+       ;; code offset: 0x2eb
+       (local.get $0)
+       ;; code offset: 0x2ed
+       (local.get $16)
+      )
+      ;; code offset: 0x2f7
+      (local.set $0
+       ;; code offset: 0x2f6
+       (i32.add
+        ;; code offset: 0x2f2
+        (local.get $10)
+        ;; code offset: 0x2f4
+        (i32.const 1)
+       )
+      )
+      ;; code offset: 0x2fb
+      (local.set $16
+       ;; code offset: 0x2f9
+       (local.get $1)
+      )
+      ;; code offset: 0x2ff
+      (br_if $label$19
+       ;; code offset: 0x2fd
+       (local.get $1)
+      )
+     )
+     ;; code offset: 0x30c
+     (local.set $9
+      ;; code offset: 0x30b
+      (select
+       ;; code offset: 0x302
+       (local.get $9)
+       ;; code offset: 0x304
+       (local.get $0)
+       ;; code offset: 0x30a
+       (i32.gt_s
+        ;; code offset: 0x306
+        (local.get $9)
+        ;; code offset: 0x308
+        (local.get $10)
+       )
+      )
+     )
+    )
+    ;; code offset: 0x314
+    (br_if $label$1
+     ;; code offset: 0x313
+     (i32.ge_s
+      ;; code offset: 0x30f
+      (local.get $2)
+      ;; code offset: 0x311
+      (local.get $7)
+     )
+    )
+    ;; code offset: 0x316
+    (loop $label$22
+     ;; code offset: 0x31a
+     (local.set $1
+      ;; code offset: 0x318
+      (i32.const 0)
+     )
+     ;; code offset: 0x31c
+     (block $label$23
+      ;; code offset: 0x323
+      (br_if $label$23
+       ;; code offset: 0x322
+       (i32.lt_s
+        ;; code offset: 0x31e
+        (local.get $2)
+        ;; code offset: 0x320
+        (i32.const 1)
+       )
+      )
+      ;; code offset: 0x325
+      (loop $label$24
+       ;; code offset: 0x33f
+       (i32.store
+        ;; code offset: 0x32e
+        (i32.add
+         ;; code offset: 0x327
+         (local.get $4)
+         ;; code offset: 0x32d
+         (i32.shl
+          ;; code offset: 0x329
+          (local.get $1)
+          ;; code offset: 0x32b
+          (i32.const 2)
+         )
+        )
+        ;; code offset: 0x33c
+        (i32.load
+         ;; code offset: 0x33b
+         (i32.add
+          ;; code offset: 0x32f
+          (local.get $4)
+          ;; code offset: 0x33a
+          (i32.shl
+           ;; code offset: 0x336
+           (local.tee $1
+            ;; code offset: 0x335
+            (i32.add
+             ;; code offset: 0x331
+             (local.get $1)
+             ;; code offset: 0x333
+             (i32.const 1)
+            )
+           )
+           ;; code offset: 0x338
+           (i32.const 2)
+          )
+         )
+        )
+       )
+       ;; code offset: 0x347
+       (br_if $label$24
+        ;; code offset: 0x346
+        (i32.ne
+         ;; code offset: 0x342
+         (local.get $1)
+         ;; code offset: 0x344
+         (local.get $2)
+        )
+       )
+      )
+      ;; code offset: 0x34c
+      (local.set $1
+       ;; code offset: 0x34a
+       (local.get $2)
+      )
+     )
+     ;; code offset: 0x359
+     (i32.store
+      ;; code offset: 0x356
+      (i32.add
+       ;; code offset: 0x34f
+       (local.get $4)
+       ;; code offset: 0x355
+       (i32.shl
+        ;; code offset: 0x351
+        (local.get $1)
+        ;; code offset: 0x353
+        (i32.const 2)
+       )
+      )
+      ;; code offset: 0x357
+      (local.get $12)
+     )
+     ;; code offset: 0x370
+     (i32.store
+      ;; code offset: 0x364
+      (local.tee $1
+       ;; code offset: 0x363
+       (i32.add
+        ;; code offset: 0x35c
+        (local.get $6)
+        ;; code offset: 0x362
+        (i32.shl
+         ;; code offset: 0x35e
+         (local.get $2)
+         ;; code offset: 0x360
+         (i32.const 2)
+        )
+       )
+      )
+      ;; code offset: 0x36f
+      (i32.add
+       ;; code offset: 0x36b
+       (local.tee $1
+        ;; code offset: 0x368
+        (i32.load
+         ;; code offset: 0x366
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x36d
+       (i32.const -1)
+      )
+     )
+     ;; code offset: 0x378
+     (br_if $label$15
+      ;; code offset: 0x377
+      (i32.gt_s
+       ;; code offset: 0x373
+       (local.get $1)
+       ;; code offset: 0x375
+       (i32.const 1)
+      )
+     )
+     ;; code offset: 0x384
+     (br_if $label$1
+      ;; code offset: 0x383
+      (i32.eq
+       ;; code offset: 0x37f
+       (local.tee $2
+        ;; code offset: 0x37e
+        (i32.add
+         ;; code offset: 0x37a
+         (local.get $2)
+         ;; code offset: 0x37c
+         (i32.const 1)
+        )
+       )
+       ;; code offset: 0x381
+       (local.get $7)
+      )
+     )
+     ;; code offset: 0x38b
+     (local.set $12
+      ;; code offset: 0x388
+      (i32.load
+       ;; code offset: 0x386
+       (local.get $4)
+      )
+     )
+     ;; code offset: 0x38d
+     (br $label$22)
+    )
+   )
+  )
+  ;; code offset: 0x396
+  (call $free
+   ;; code offset: 0x394
+   (local.get $4)
+  )
+  ;; code offset: 0x39a
+  (call $free
+   ;; code offset: 0x398
+   (local.get $5)
+  )
+  ;; code offset: 0x39e
+  (call $free
+   ;; code offset: 0x39c
+   (local.get $6)
+  )
+  ;; code offset: 0x3a0
+  (local.get $9)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  ;; code offset: 0x3bb
+  (global.set $global$0
+   ;; code offset: 0x3b9
+   (local.tee $2
+    ;; code offset: 0x3b8
+    (i32.sub
+     ;; code offset: 0x3b4
+     (global.get $global$0)
+     ;; code offset: 0x3b6
+     (i32.const 32)
+    )
+   )
+  )
+  ;; code offset: 0x3bd
+  (block $label$1
+   (block $label$2
+    (block $label$3
+     ;; code offset: 0x3c8
+     (br_if $label$3
+      ;; code offset: 0x3c7
+      (i32.lt_s
+       ;; code offset: 0x3c3
+       (local.get $0)
+       ;; code offset: 0x3c5
+       (i32.const 2)
+      )
+     )
+     ;; code offset: 0x3cc
+     (local.set $3
+      ;; code offset: 0x3ca
+      (i32.const 0)
+     )
+     ;; code offset: 0x3da
+     (br_if $label$2
+      ;; code offset: 0x3d9
+      (i32.gt_s
+       ;; code offset: 0x3d5
+       (local.tee $4
+        ;; code offset: 0x3d3
+        (call $atoi
+         ;; code offset: 0x3d0
+         (i32.load offset=4
+          ;; code offset: 0x3ce
+          (local.get $1)
+         )
+        )
+       )
+       ;; code offset: 0x3d7
+       (i32.const 0)
+      )
+     )
+    )
+    ;; code offset: 0x3e2
+    (drop
+     ;; code offset: 0x3e0
+     (call $puts
+      ;; code offset: 0x3dd
+      (i32.const 1050)
+     )
+    )
+    ;; code offset: 0x3e5
+    (local.set $5
+     ;; code offset: 0x3e3
+     (i32.const 1)
+    )
+    ;; code offset: 0x3e7
+    (br $label$1)
+   )
+   ;; code offset: 0x3ea
+   (block $label$4
+    ;; code offset: 0x3f1
+    (br_if $label$4
+     ;; code offset: 0x3f0
+     (i32.eq
+      ;; code offset: 0x3ec
+      (local.get $4)
+      ;; code offset: 0x3ee
+      (i32.const 1)
+     )
+    )
+    ;; code offset: 0x3f8
+    (local.set $6
+     ;; code offset: 0x3f7
+     (i32.add
+      ;; code offset: 0x3f3
+      (local.get $4)
+      ;; code offset: 0x3f5
+      (i32.const -1)
+     )
+    )
+    ;; code offset: 0x3fc
+    (local.set $1
+     ;; code offset: 0x3fa
+     (i32.const 0)
+    )
+    ;; code offset: 0x400
+    (local.set $0
+     ;; code offset: 0x3fe
+     (i32.const 0)
+    )
+    ;; code offset: 0x402
+    (loop $label$5
+     ;; code offset: 0x40c
+     (i32.store offset=8
+      ;; code offset: 0x408
+      (local.tee $3
+       ;; code offset: 0x406
+       (call $malloc
+        ;; code offset: 0x404
+        (i32.const 12)
+       )
+      )
+      ;; code offset: 0x40a
+      (local.get $1)
+     )
+     ;; code offset: 0x413
+     (i32.store offset=4
+      ;; code offset: 0x40f
+      (local.get $3)
+      ;; code offset: 0x411
+      (local.get $4)
+     )
+     ;; code offset: 0x41a
+     (i32.store
+      ;; code offset: 0x416
+      (local.get $3)
+      ;; code offset: 0x418
+      (local.get $0)
+     )
+     ;; code offset: 0x41f
+     (local.set $1
+      ;; code offset: 0x41d
+      (local.get $3)
+     )
+     ;; code offset: 0x42b
+     (br_if $label$5
+      ;; code offset: 0x42a
+      (i32.ne
+       ;; code offset: 0x426
+       (local.tee $0
+        ;; code offset: 0x425
+        (i32.add
+         ;; code offset: 0x421
+         (local.get $0)
+         ;; code offset: 0x423
+         (i32.const 1)
+        )
+       )
+       ;; code offset: 0x428
+       (local.get $6)
+      )
+     )
+    )
+   )
+   ;; code offset: 0x431
+   (local.set $0
+    ;; code offset: 0x42f
+    (i32.const 0)
+   )
+   ;; code offset: 0x43c
+   (local.set $1
+    ;; code offset: 0x43a
+    (call $malloc
+     ;; code offset: 0x438
+     (local.tee $6
+      ;; code offset: 0x437
+      (i32.shl
+       ;; code offset: 0x433
+       (local.get $4)
+       ;; code offset: 0x435
+       (i32.const 2)
+      )
+     )
+    )
+   )
+   ;; code offset: 0x442
+   (local.set $5
+    ;; code offset: 0x440
+    (call $malloc
+     ;; code offset: 0x43e
+     (local.get $6)
+    )
+   )
+   ;; code offset: 0x444
+   (block $label$6
+    (block $label$7
+     (block $label$8
+      (block $label$9
+       ;; code offset: 0x451
+       (br_if $label$9
+        ;; code offset: 0x450
+        (i32.le_s
+         ;; code offset: 0x44c
+         (local.get $4)
+         ;; code offset: 0x44e
+         (i32.const 0)
+        )
+       )
+       ;; code offset: 0x453
+       (loop $label$10
+        ;; code offset: 0x45f
+        (i32.store
+         ;; code offset: 0x45c
+         (i32.add
+          ;; code offset: 0x455
+          (local.get $1)
+          ;; code offset: 0x45b
+          (i32.shl
+           ;; code offset: 0x457
+           (local.get $0)
+           ;; code offset: 0x459
+           (i32.const 2)
+          )
+         )
+         ;; code offset: 0x45d
+         (local.get $0)
+        )
+        ;; code offset: 0x46c
+        (br_if $label$10
+         ;; code offset: 0x46b
+         (i32.ne
+          ;; code offset: 0x467
+          (local.tee $0
+           ;; code offset: 0x466
+           (i32.add
+            ;; code offset: 0x462
+            (local.get $0)
+            ;; code offset: 0x464
+            (i32.const 1)
+           )
+          )
+          ;; code offset: 0x469
+          (local.get $4)
+         )
+        )
+       )
+       ;; code offset: 0x471
+       (local.set $7
+        ;; code offset: 0x46f
+        (i32.const 30)
+       )
+       ;; code offset: 0x475
+       (local.set $6
+        ;; code offset: 0x473
+        (local.get $4)
+       )
+       ;; code offset: 0x477
+       (br $label$8)
+      )
+      ;; code offset: 0x47c
+      (local.set $7
+       ;; code offset: 0x47a
+       (i32.const 30)
+      )
+      ;; code offset: 0x480
+      (local.set $6
+       ;; code offset: 0x47e
+       (local.get $4)
+      )
+      ;; code offset: 0x482
+      (br $label$7)
+     )
+     ;; code offset: 0x485
+     (loop $label$11
+      ;; code offset: 0x489
+      (local.set $0
+       ;; code offset: 0x487
+       (i32.const 0)
+      )
+      ;; code offset: 0x48b
+      (loop $label$12
+       ;; code offset: 0x49d
+       (i32.store offset=16
+        ;; code offset: 0x48d
+        (local.get $2)
+        ;; code offset: 0x49c
+        (i32.add
+         ;; code offset: 0x497
+         (i32.load
+          ;; code offset: 0x496
+          (i32.add
+           ;; code offset: 0x48f
+           (local.get $1)
+           ;; code offset: 0x495
+           (i32.shl
+            ;; code offset: 0x491
+            (local.get $0)
+            ;; code offset: 0x493
+            (i32.const 2)
+           )
+          )
+         )
+         ;; code offset: 0x49a
+         (i32.const 1)
+        )
+       )
+       ;; code offset: 0x4aa
+       (drop
+        ;; code offset: 0x4a8
+        (call $iprintf
+         ;; code offset: 0x4a0
+         (i32.const 1047)
+         ;; code offset: 0x4a7
+         (i32.add
+          ;; code offset: 0x4a3
+          (local.get $2)
+          ;; code offset: 0x4a5
+          (i32.const 16)
+         )
+        )
+       )
+       ;; code offset: 0x4b5
+       (br_if $label$12
+        ;; code offset: 0x4b4
+        (i32.ne
+         ;; code offset: 0x4b0
+         (local.tee $0
+          ;; code offset: 0x4af
+          (i32.add
+           ;; code offset: 0x4ab
+           (local.get $0)
+           ;; code offset: 0x4ad
+           (i32.const 1)
+          )
+         )
+         ;; code offset: 0x4b2
+         (local.get $4)
+        )
+       )
+      )
+      ;; code offset: 0x4bc
+      (drop
+       ;; code offset: 0x4ba
+       (call $putchar
+        ;; code offset: 0x4b8
+        (i32.const 10)
+       )
+      )
+      ;; code offset: 0x4bd
+      (block $label$13
+       ;; code offset: 0x4c4
+       (br_if $label$13
+        ;; code offset: 0x4c3
+        (i32.le_s
+         ;; code offset: 0x4bf
+         (local.get $6)
+         ;; code offset: 0x4c1
+         (i32.const 1)
+        )
+       )
+       ;; code offset: 0x4c6
+       (loop $label$14
+        ;; code offset: 0x4d7
+        (i32.store
+         ;; code offset: 0x4d4
+         (i32.add
+          ;; code offset: 0x4c8
+          (local.get $5)
+          ;; code offset: 0x4d3
+          (i32.shl
+           ;; code offset: 0x4cf
+           (local.tee $0
+            ;; code offset: 0x4ce
+            (i32.add
+             ;; code offset: 0x4ca
+             (local.get $6)
+             ;; code offset: 0x4cc
+             (i32.const -1)
+            )
+           )
+           ;; code offset: 0x4d1
+           (i32.const 2)
+          )
+         )
+         ;; code offset: 0x4d5
+         (local.get $6)
+        )
+        ;; code offset: 0x4df
+        (local.set $8
+         ;; code offset: 0x4de
+         (i32.gt_s
+          ;; code offset: 0x4da
+          (local.get $6)
+          ;; code offset: 0x4dc
+          (i32.const 2)
+         )
+        )
+        ;; code offset: 0x4e3
+        (local.set $6
+         ;; code offset: 0x4e1
+         (local.get $0)
+        )
+        ;; code offset: 0x4e7
+        (br_if $label$14
+         ;; code offset: 0x4e5
+         (local.get $8)
+        )
+       )
+      )
+      ;; code offset: 0x4f0
+      (br_if $label$6
+       ;; code offset: 0x4ef
+       (i32.eq
+        ;; code offset: 0x4eb
+        (local.get $6)
+        ;; code offset: 0x4ed
+        (local.get $4)
+       )
+      )
+      ;; code offset: 0x4f7
+      (local.set $7
+       ;; code offset: 0x4f6
+       (i32.add
+        ;; code offset: 0x4f2
+        (local.get $7)
+        ;; code offset: 0x4f4
+        (i32.const -1)
+       )
+      )
+      ;; code offset: 0x4f9
+      (loop $label$15
+       ;; code offset: 0x4fd
+       (local.set $0
+        ;; code offset: 0x4fb
+        (i32.const 0)
+       )
+       ;; code offset: 0x504
+       (local.set $8
+        ;; code offset: 0x501
+        (i32.load
+         ;; code offset: 0x4ff
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x506
+       (block $label$16
+        ;; code offset: 0x50d
+        (br_if $label$16
+         ;; code offset: 0x50c
+         (i32.le_s
+          ;; code offset: 0x508
+          (local.get $6)
+          ;; code offset: 0x50a
+          (i32.const 0)
+         )
+        )
+        ;; code offset: 0x50f
+        (loop $label$17
+         ;; code offset: 0x529
+         (i32.store
+          ;; code offset: 0x518
+          (i32.add
+           ;; code offset: 0x511
+           (local.get $1)
+           ;; code offset: 0x517
+           (i32.shl
+            ;; code offset: 0x513
+            (local.get $0)
+            ;; code offset: 0x515
+            (i32.const 2)
+           )
+          )
+          ;; code offset: 0x526
+          (i32.load
+           ;; code offset: 0x525
+           (i32.add
+            ;; code offset: 0x519
+            (local.get $1)
+            ;; code offset: 0x524
+            (i32.shl
+             ;; code offset: 0x520
+             (local.tee $0
+              ;; code offset: 0x51f
+              (i32.add
+               ;; code offset: 0x51b
+               (local.get $0)
+               ;; code offset: 0x51d
+               (i32.const 1)
+              )
+             )
+             ;; code offset: 0x522
+             (i32.const 2)
+            )
+           )
+          )
+         )
+         ;; code offset: 0x531
+         (br_if $label$17
+          ;; code offset: 0x530
+          (i32.ne
+           ;; code offset: 0x52c
+           (local.get $0)
+           ;; code offset: 0x52e
+           (local.get $6)
+          )
+         )
+        )
+        ;; code offset: 0x536
+        (local.set $0
+         ;; code offset: 0x534
+         (local.get $6)
+        )
+       )
+       ;; code offset: 0x543
+       (i32.store
+        ;; code offset: 0x540
+        (i32.add
+         ;; code offset: 0x539
+         (local.get $1)
+         ;; code offset: 0x53f
+         (i32.shl
+          ;; code offset: 0x53b
+          (local.get $0)
+          ;; code offset: 0x53d
+          (i32.const 2)
+         )
+        )
+        ;; code offset: 0x541
+        (local.get $8)
+       )
+       ;; code offset: 0x55a
+       (i32.store
+        ;; code offset: 0x54e
+        (local.tee $0
+         ;; code offset: 0x54d
+         (i32.add
+          ;; code offset: 0x546
+          (local.get $5)
+          ;; code offset: 0x54c
+          (i32.shl
+           ;; code offset: 0x548
+           (local.get $6)
+           ;; code offset: 0x54a
+           (i32.const 2)
+          )
+         )
+        )
+        ;; code offset: 0x559
+        (i32.add
+         ;; code offset: 0x555
+         (local.tee $0
+          ;; code offset: 0x552
+          (i32.load
+           ;; code offset: 0x550
+           (local.get $0)
+          )
+         )
+         ;; code offset: 0x557
+         (i32.const -1)
+        )
+       )
+       ;; code offset: 0x55d
+       (block $label$18
+        ;; code offset: 0x564
+        (br_if $label$18
+         ;; code offset: 0x563
+         (i32.gt_s
+          ;; code offset: 0x55f
+          (local.get $0)
+          ;; code offset: 0x561
+          (i32.const 1)
+         )
+        )
+        ;; code offset: 0x570
+        (br_if $label$15
+         ;; code offset: 0x56f
+         (i32.ne
+          ;; code offset: 0x56b
+          (local.tee $6
+           ;; code offset: 0x56a
+           (i32.add
+            ;; code offset: 0x566
+            (local.get $6)
+            ;; code offset: 0x568
+            (i32.const 1)
+           )
+          )
+          ;; code offset: 0x56d
+          (local.get $4)
+         )
+        )
+        ;; code offset: 0x572
+        (br $label$6)
+       )
+      )
+      ;; code offset: 0x579
+      (br_if $label$6
+       ;; code offset: 0x578
+       (i32.eqz
+        ;; code offset: 0x576
+        (local.get $7)
+       )
+      )
+      ;; code offset: 0x57b
+      (br $label$11)
+     )
+    )
+    ;; code offset: 0x580
+    (loop $label$19
+     ;; code offset: 0x586
+     (drop
+      ;; code offset: 0x584
+      (call $putchar
+       ;; code offset: 0x582
+       (i32.const 10)
+      )
+     )
+     ;; code offset: 0x587
+     (block $label$20
+      ;; code offset: 0x58e
+      (br_if $label$20
+       ;; code offset: 0x58d
+       (i32.le_s
+        ;; code offset: 0x589
+        (local.get $6)
+        ;; code offset: 0x58b
+        (i32.const 1)
+       )
+      )
+      ;; code offset: 0x590
+      (loop $label$21
+       ;; code offset: 0x5a1
+       (i32.store
+        ;; code offset: 0x59e
+        (i32.add
+         ;; code offset: 0x592
+         (local.get $5)
+         ;; code offset: 0x59d
+         (i32.shl
+          ;; code offset: 0x599
+          (local.tee $0
+           ;; code offset: 0x598
+           (i32.add
+            ;; code offset: 0x594
+            (local.get $6)
+            ;; code offset: 0x596
+            (i32.const -1)
+           )
+          )
+          ;; code offset: 0x59b
+          (i32.const 2)
+         )
+        )
+        ;; code offset: 0x59f
+        (local.get $6)
+       )
+       ;; code offset: 0x5a9
+       (local.set $8
+        ;; code offset: 0x5a8
+        (i32.gt_s
+         ;; code offset: 0x5a4
+         (local.get $6)
+         ;; code offset: 0x5a6
+         (i32.const 2)
+        )
+       )
+       ;; code offset: 0x5ad
+       (local.set $6
+        ;; code offset: 0x5ab
+        (local.get $0)
+       )
+       ;; code offset: 0x5b1
+       (br_if $label$21
+        ;; code offset: 0x5af
+        (local.get $8)
+       )
+      )
+     )
+     ;; code offset: 0x5ba
+     (br_if $label$6
+      ;; code offset: 0x5b9
+      (i32.eq
+       ;; code offset: 0x5b5
+       (local.get $6)
+       ;; code offset: 0x5b7
+       (local.get $4)
+      )
+     )
+     ;; code offset: 0x5c1
+     (local.set $7
+      ;; code offset: 0x5c0
+      (i32.add
+       ;; code offset: 0x5bc
+       (local.get $7)
+       ;; code offset: 0x5be
+       (i32.const -1)
+      )
+     )
+     ;; code offset: 0x5c3
+     (loop $label$22
+      ;; code offset: 0x5ca
+      (local.set $8
+       ;; code offset: 0x5c7
+       (i32.load
+        ;; code offset: 0x5c5
+        (local.get $1)
+       )
+      )
+      ;; code offset: 0x5ce
+      (local.set $0
+       ;; code offset: 0x5cc
+       (i32.const 0)
+      )
+      ;; code offset: 0x5d0
+      (block $label$23
+       ;; code offset: 0x5d7
+       (br_if $label$23
+        ;; code offset: 0x5d6
+        (i32.lt_s
+         ;; code offset: 0x5d2
+         (local.get $6)
+         ;; code offset: 0x5d4
+         (i32.const 1)
+        )
+       )
+       ;; code offset: 0x5d9
+       (loop $label$24
+        ;; code offset: 0x5f3
+        (i32.store
+         ;; code offset: 0x5e2
+         (i32.add
+          ;; code offset: 0x5db
+          (local.get $1)
+          ;; code offset: 0x5e1
+          (i32.shl
+           ;; code offset: 0x5dd
+           (local.get $0)
+           ;; code offset: 0x5df
+           (i32.const 2)
+          )
+         )
+         ;; code offset: 0x5f0
+         (i32.load
+          ;; code offset: 0x5ef
+          (i32.add
+           ;; code offset: 0x5e3
+           (local.get $1)
+           ;; code offset: 0x5ee
+           (i32.shl
+            ;; code offset: 0x5ea
+            (local.tee $0
+             ;; code offset: 0x5e9
+             (i32.add
+              ;; code offset: 0x5e5
+              (local.get $0)
+              ;; code offset: 0x5e7
+              (i32.const 1)
+             )
+            )
+            ;; code offset: 0x5ec
+            (i32.const 2)
+           )
+          )
+         )
+        )
+        ;; code offset: 0x5fb
+        (br_if $label$24
+         ;; code offset: 0x5fa
+         (i32.ne
+          ;; code offset: 0x5f6
+          (local.get $0)
+          ;; code offset: 0x5f8
+          (local.get $6)
+         )
+        )
+       )
+       ;; code offset: 0x600
+       (local.set $0
+        ;; code offset: 0x5fe
+        (local.get $6)
+       )
+      )
+      ;; code offset: 0x60d
+      (i32.store
+       ;; code offset: 0x60a
+       (i32.add
+        ;; code offset: 0x603
+        (local.get $1)
+        ;; code offset: 0x609
+        (i32.shl
+         ;; code offset: 0x605
+         (local.get $0)
+         ;; code offset: 0x607
+         (i32.const 2)
+        )
+       )
+       ;; code offset: 0x60b
+       (local.get $8)
+      )
+      ;; code offset: 0x624
+      (i32.store
+       ;; code offset: 0x618
+       (local.tee $0
+        ;; code offset: 0x617
+        (i32.add
+         ;; code offset: 0x610
+         (local.get $5)
+         ;; code offset: 0x616
+         (i32.shl
+          ;; code offset: 0x612
+          (local.get $6)
+          ;; code offset: 0x614
+          (i32.const 2)
+         )
+        )
+       )
+       ;; code offset: 0x623
+       (i32.add
+        ;; code offset: 0x61f
+        (local.tee $0
+         ;; code offset: 0x61c
+         (i32.load
+          ;; code offset: 0x61a
+          (local.get $0)
+         )
+        )
+        ;; code offset: 0x621
+        (i32.const -1)
+       )
+      )
+      ;; code offset: 0x627
+      (block $label$25
+       ;; code offset: 0x62e
+       (br_if $label$25
+        ;; code offset: 0x62d
+        (i32.gt_s
+         ;; code offset: 0x629
+         (local.get $0)
+         ;; code offset: 0x62b
+         (i32.const 1)
+        )
+       )
+       ;; code offset: 0x63a
+       (br_if $label$22
+        ;; code offset: 0x639
+        (i32.ne
+         ;; code offset: 0x635
+         (local.tee $6
+          ;; code offset: 0x634
+          (i32.add
+           ;; code offset: 0x630
+           (local.get $6)
+           ;; code offset: 0x632
+           (i32.const 1)
+          )
+         )
+         ;; code offset: 0x637
+         (local.get $4)
+        )
+       )
+       ;; code offset: 0x63c
+       (br $label$6)
+      )
+     )
+     ;; code offset: 0x642
+     (br_if $label$19
+      ;; code offset: 0x640
+      (local.get $7)
+     )
+    )
+   )
+   ;; code offset: 0x648
+   (call $free
+    ;; code offset: 0x646
+    (local.get $1)
+   )
+   ;; code offset: 0x64c
+   (call $free
+    ;; code offset: 0x64a
+    (local.get $5)
+   )
+   ;; code offset: 0x650
+   (local.set $5
+    ;; code offset: 0x64e
+    (i32.const 0)
+   )
+   ;; code offset: 0x654
+   (local.set $0
+    ;; code offset: 0x652
+    (i32.const 0)
+   )
+   ;; code offset: 0x656
+   (block $label$26
+    ;; code offset: 0x65b
+    (br_if $label$26
+     ;; code offset: 0x65a
+     (i32.eqz
+      ;; code offset: 0x658
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x65f
+    (local.set $0
+     ;; code offset: 0x65d
+     (i32.const 0)
+    )
+    ;; code offset: 0x661
+    (loop $label$27
+     ;; code offset: 0x667
+     (local.set $1
+      ;; code offset: 0x665
+      (call $fannkuch_worker\28void*\29
+       ;; code offset: 0x663
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x66e
+     (local.set $6
+      ;; code offset: 0x66b
+      (i32.load offset=8
+       ;; code offset: 0x669
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x672
+     (call $free
+      ;; code offset: 0x670
+      (local.get $3)
+     )
+     ;; code offset: 0x67e
+     (local.set $0
+      ;; code offset: 0x67d
+      (select
+       ;; code offset: 0x674
+       (local.get $1)
+       ;; code offset: 0x676
+       (local.get $0)
+       ;; code offset: 0x67c
+       (i32.lt_s
+        ;; code offset: 0x678
+        (local.get $0)
+        ;; code offset: 0x67a
+        (local.get $1)
+       )
+      )
+     )
+     ;; code offset: 0x682
+     (local.set $3
+      ;; code offset: 0x680
+      (local.get $6)
+     )
+     ;; code offset: 0x686
+     (br_if $label$27
+      ;; code offset: 0x684
+      (local.get $6)
+     )
+    )
+   )
+   ;; code offset: 0x68e
+   (i32.store offset=4
+    ;; code offset: 0x68a
+    (local.get $2)
+    ;; code offset: 0x68c
+    (local.get $0)
+   )
+   ;; code offset: 0x695
+   (i32.store
+    ;; code offset: 0x691
+    (local.get $2)
+    ;; code offset: 0x693
+    (local.get $4)
+   )
+   ;; code offset: 0x69f
+   (drop
+    ;; code offset: 0x69d
+    (call $iprintf
+     ;; code offset: 0x698
+     (i32.const 1024)
+     ;; code offset: 0x69b
+     (local.get $2)
+    )
+   )
+  )
+  ;; code offset: 0x6a6
+  (global.set $global$0
+   ;; code offset: 0x6a5
+   (i32.add
+    ;; code offset: 0x6a1
+    (local.get $2)
+    ;; code offset: 0x6a3
+    (i32.const 32)
+   )
+  )
+  ;; code offset: 0x6a8
+  (local.get $5)
+ )
+ ;; custom section ".debug_info", size 851
+ ;; custom section ".debug_loc", size 1073
+ ;; custom section ".debug_ranges", size 88
+ ;; custom section ".debug_abbrev", size 333
+ ;; custom section ".debug_line", size 2826
+ ;; custom section ".debug_str", size 434
+ ;; custom section "producers", size 135
+)
diff --git a/binaryen/test/passes/fannkuch3_dwarf.passes b/binaryen/test/passes/fannkuch3_dwarf.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fannkuch3_dwarf.passes
@@ -0,0 +1,1 @@
+dwarfdump_roundtrip_dwarfdump_g
diff --git a/binaryen/test/passes/fannkuch3_dwarf.wasm b/binaryen/test/passes/fannkuch3_dwarf.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/fannkuch3_dwarf.wasm differ
diff --git a/binaryen/test/passes/fannkuch3_manyopts_dwarf.bin.txt b/binaryen/test/passes/fannkuch3_manyopts_dwarf.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fannkuch3_manyopts_dwarf.bin.txt
@@ -0,0 +1,6867 @@
+DWARF debug info
+================
+
+Contains section .debug_info (851 bytes)
+Contains section .debug_loc (1073 bytes)
+Contains section .debug_ranges (88 bytes)
+Contains section .debug_abbrev (333 bytes)
+Contains section .debug_line (1477 bytes)
+Contains section .debug_str (434 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[2] DW_TAG_pointer_type	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[3] DW_TAG_structure_type	DW_CHILDREN_yes
+	DW_AT_calling_convention	DW_FORM_data1
+	DW_AT_name	DW_FORM_strp
+	DW_AT_byte_size	DW_FORM_data1
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[4] DW_TAG_member	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_data_member_location	DW_FORM_data1
+
+[5] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+[6] DW_TAG_namespace	DW_CHILDREN_yes
+	DW_AT_name	DW_FORM_strp
+
+[7] DW_TAG_typedef	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[8] DW_TAG_unspecified_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+
+[9] DW_TAG_imported_declaration	DW_CHILDREN_no
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_import	DW_FORM_ref4
+
+[10] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[11] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[12] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[13] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[14] DW_TAG_lexical_block	DW_CHILDREN_yes
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[15] DW_TAG_GNU_call_site	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+
+[16] DW_TAG_GNU_call_site	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+	DW_AT_low_pc	DW_FORM_addr
+
+[17] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_declaration	DW_FORM_flag_present
+	DW_AT_external	DW_FORM_flag_present
+
+[18] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[19] DW_TAG_pointer_type	DW_CHILDREN_no
+
+[20] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_inline	DW_FORM_data1
+
+[21] DW_TAG_label	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[22] DW_TAG_lexical_block	DW_CHILDREN_yes
+
+[23] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[24] DW_TAG_inlined_subroutine	DW_CHILDREN_yes
+	DW_AT_abstract_origin	DW_FORM_ref4
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_call_file	DW_FORM_data1
+	DW_AT_call_line	DW_FORM_data1
+	DW_AT_call_column	DW_FORM_data1
+
+[25] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[26] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[27] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[28] DW_TAG_label	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+	DW_AT_low_pc	DW_FORM_addr
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x0000034f version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x00000353)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000069] = "/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x000000a9] = "/usr/local/google/home/azakai/Dev/2-binaryen")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+              DW_AT_ranges [DW_FORM_sec_offset]	(0x00000040
+                 [0x00000006, 0x0000039d)
+                 [0x0000039f, 0x000006e1))
+
+0x00000026:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x002b => {0x0000002b} "worker_args")
+
+0x0000002b:   DW_TAG_structure_type [3] *
+                DW_AT_calling_convention [DW_FORM_data1]	(DW_CC_pass_by_value)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000e3] = "worker_args")
+                DW_AT_byte_size [DW_FORM_data1]	(0x0c)
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(20)
+
+0x00000034:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d6] = "i")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(21)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x00)
+
+0x00000040:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(21)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x04)
+
+0x0000004c:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000de] = "next")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(22)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x08)
+
+0x00000058:     NULL
+
+0x00000059:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d8] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x00000060:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000065:   DW_TAG_namespace [6] *
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ef] = "std")
+
+0x0000006a:     DW_TAG_typedef [7]  
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0076 => {0x00000076} "decltype(nullptr)")
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000105] = "nullptr_t")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/system/include/libcxx/__nullptr")
+                  DW_AT_decl_line [DW_FORM_data1]	(57)
+
+0x00000075:     NULL
+
+0x00000076:   DW_TAG_unspecified_type [8]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000f3] = "decltype(nullptr)")
+
+0x0000007b:   DW_TAG_imported_declaration [9]  
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/system/include/libcxx/stddef.h")
+                DW_AT_decl_line [DW_FORM_data1]	(52)
+                DW_AT_import [DW_FORM_ref4]	(cu + 0x006a => {0x0000006a})
+
+0x00000082:   DW_TAG_subprogram [10] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000006)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000397)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x1 +0, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x00000166] = "_Z15fannkuch_workerPv")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000017c] = "fannkuch_worker")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(26)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000009e:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000191] = "_arg")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(26)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x01a7 => {0x000001a7} "*")
+
+0x000000a9:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000133] = "args")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(28)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000000b4:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000000: 
+                     [0xffffffff,  0x00000006): 
+                     [0x00000000,  0x0000003c): DW_OP_consts +0, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014c] = "maxflips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000c3:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000001d: 
+                     [0xffffffff,  0x00000006): 
+                     [0x00000007,  0x0000003c): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000052,  0x00000057): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x000000ec,  0x000000f5): DW_OP_consts +1, DW_OP_stack_value
+                     [0x00000131,  0x0000013b): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                     [0x00000179,  0x00000186): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000264,  0x0000026f): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000275,  0x0000027e): DW_OP_consts +1, DW_OP_stack_value
+                     [0x000002ba,  0x000002c4): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                     [0x00000302,  0x0000030f): DW_OP_consts +0, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d6] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000d2:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000a5: 
+                     [0xffffffff,  0x00000006): 
+                     [0x0000000e,  0x0000003c): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000e1:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000c3: 
+                     [0xffffffff,  0x00000006): 
+                     [0x0000001b,  0x0000003c): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000013e] = "perm1")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000000f0:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000e1: 
+                     [0xffffffff,  0x00000006): 
+                     [0x00000025,  0x0000003c): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000196] = "perm")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000000ff:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000ff: 
+                     [0xffffffff,  0x00000006): 
+                     [0x0000002f,  0x0000003c): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000144] = "count")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x0000010e:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000011d: 
+                     [0xffffffff,  0x00000006): 
+                     [0x000001e2,  0x000001e7): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+                     [0x0000036b,  0x00000370): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014a] = "r")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000011d:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000149: 
+                     [0xffffffff,  0x00000006): 
+                     [0x000000cf,  0x000000e6): DW_OP_consts +0, DW_OP_stack_value
+                     [0x000000ec,  0x000000f5): DW_OP_WASM_location 0x0 +13, DW_OP_stack_value
+                     [0x0000015a,  0x00000162): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                     [0x00000264,  0x0000026f): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000275,  0x0000027e): DW_OP_WASM_location 0x0 +10, DW_OP_stack_value
+                     [0x000002e3,  0x000002eb): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000155] = "flips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000012c:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000001ab: 
+                     [0xffffffff,  0x00000006): 
+                     [0x000000e2,  0x000000e6): DW_OP_WASM_location 0x0 +12, DW_OP_stack_value
+                     [0x0000026b,  0x0000026f): DW_OP_WASM_location 0x0 +16, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000019b] = "k")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000013b:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000001d7: 
+                     [0xffffffff,  0x00000006): 
+                     [0x000000fc,  0x00000100): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x00000138,  0x0000013b): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x00000285,  0x00000289): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x000002c1,  0x000002c4): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000019d] = "j")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000014a:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000021f: 
+                     [0xffffffff,  0x00000006): 
+                     [0x00000111,  0x0000013b): DW_OP_WASM_location 0x0 +15, DW_OP_stack_value
+                     [0x0000014c,  0x00000162): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x0000029a,  0x000002c4): DW_OP_WASM_location 0x0 +14, DW_OP_stack_value
+                     [0x000002d5,  0x000002eb): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000019f] = "tmp")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000159:     DW_TAG_lexical_block [14] *
+                  DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
+                     [0x00000185, 0x000001c3)
+                     [0x000001ed, 0x000001f6)
+                     [0x0000030e, 0x0000034c)
+                     [0x00000376, 0x0000037f))
+
+0x0000015e:       DW_TAG_variable [12]  
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000163] = "p0")
+                    DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                    DW_AT_decl_line [DW_FORM_data1]	(74)
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000169:       NULL
+
+0x0000016a:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000001f)
+
+0x0000016f:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000029)
+
+0x00000174:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000033)
+
+0x00000179:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000000e1)
+
+0x0000017e:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000038a)
+
+0x00000187:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000392)
+
+0x00000190:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000039a)
+
+0x00000199:     NULL
+
+0x0000019a:   DW_TAG_subprogram [17] *
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000010f] = "free")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/system/include/libc/stdlib.h")
+                DW_AT_decl_line [DW_FORM_data1]	(41)
+                DW_AT_declaration [DW_FORM_flag_present]	(true)
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x000001a1:     DW_TAG_formal_parameter [18]  
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x01a7 => {0x000001a7} "*")
+
+0x000001a6:     NULL
+
+0x000001a7:   DW_TAG_pointer_type [19]  
+
+0x000001a8:   DW_TAG_subprogram [20] *
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x00000114] = "_ZL8fannkuchi")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000122] = "fannkuch")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(87)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_inline [DW_FORM_data1]	(DW_INL_inlined)
+
+0x000001b8:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(87)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001c3:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000012b] = "showmax")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(90)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001ce:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000133] = "args")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(89)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000001d9:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d6] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001e4:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000138] = "targs")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(89)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000001ef:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000013e] = "perm1")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000001fa:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000144] = "count")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x00000205:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014a] = "r")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000210:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014c] = "maxflips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000021b:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000155] = "flips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000226:     DW_TAG_label [21]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000015b] = "cleanup")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(137)
+
+0x0000022d:     DW_TAG_lexical_block [22] *
+
+0x0000022e:       DW_TAG_variable [12]  
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000163] = "p0")
+                    DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                    DW_AT_decl_line [DW_FORM_data1]	(125)
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000239:       NULL
+
+0x0000023a:     NULL
+
+0x0000023b:   DW_TAG_subprogram [23] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x000000000000039f)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000342)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x0 +2, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000018c] = "main")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(152)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000253:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000001a3] = "argc")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(152)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000025e:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000001a8] = "argv")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(152)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0341 => {0x00000341} "char**")
+
+0x00000269:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000267: 
+                     [0xffffffff,  0x0000039f): 
+                     [0x00000032,  0x00000037): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(153)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000278:     DW_TAG_inlined_subroutine [24] *
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01a8 => {0x000001a8} "_ZL8fannkuchi")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000003ed)
+                  DW_AT_high_pc [DW_FORM_data4]	(0x000002c8)
+                  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)
+
+0x00000288:       DW_TAG_formal_parameter [25]  
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01b8 => {0x000001b8} "n")
+
+0x0000028d:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000285: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x0000004c,  0x00000055): DW_OP_consts +30, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01c3 => {0x000001c3} "showmax")
+
+0x00000296:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x000002a2: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x0000004c,  0x00000055): DW_OP_lit0, DW_OP_stack_value
+                       [0x000002f8,  0x00000314): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01ce => {0x000001ce} "args")
+
+0x0000029f:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x000002cc: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x0000004c,  0x00000055): DW_OP_consts +0, DW_OP_stack_value
+                       [0x0000008e,  0x00000093): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                       [0x00000099,  0x000000c1): DW_OP_consts +0, DW_OP_stack_value
+                       [0x000000d7,  0x000000dc): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                       [0x000000f5,  0x000000f9): DW_OP_consts +0, DW_OP_stack_value
+                       [0x00000127,  0x0000012c): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                       [0x00000178,  0x00000188): DW_OP_consts +0, DW_OP_stack_value
+                       [0x000001fa,  0x0000020c): DW_OP_consts +0, DW_OP_stack_value
+                       [0x00000241,  0x00000255): DW_OP_consts +0, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01d9 => {0x000001d9} "i")
+
+0x000002a8:       DW_TAG_variable [27]  
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01e4 => {0x000001e4} "targs")
+
+0x000002ad:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000354: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x000000a8,  0x000000c1): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01ef => {0x000001ef} "perm1")
+
+0x000002b6:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000372: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x000000b2,  0x000000c1): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01fa => {0x000001fa} "count")
+
+0x000002bf:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000390: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x000001e6,  0x000001ed): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+                       [0x000002b3,  0x000002ba): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x0205 => {0x00000205} "r")
+
+0x000002c8:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x000003e8: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x000002d6,  0x000002e1): DW_OP_consts +0, DW_OP_stack_value
+                       [0x0000030c,  0x00000314): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x0210 => {0x00000210} "maxflips")
+
+0x000002d1:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000413: 
+                       [0xffffffff,  0x0000039f): 
+                       [0x000002f1,  0x00000314): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x021b => {0x0000021b} "flips")
+
+0x000002da:       DW_TAG_label [28]  
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x0226 => {0x00000226} "cleanup")
+                    DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000661)
+
+0x000002e3:       DW_TAG_lexical_block [14] *
+                    DW_AT_ranges [DW_FORM_sec_offset]	(0x00000028
+                       [0x00000517, 0x0000055e)
+                       [0x000005de, 0x0000062b))
+
+0x000002e8:         DW_TAG_variable [26]  
+                      DW_AT_location [DW_FORM_sec_offset]	(0x000003bc: 
+                         [0xffffffff,  0x0000039f): 
+                         [0x0000017f,  0x00000188): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value
+                         [0x00000248,  0x00000255): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value)
+                      DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x022e => {0x0000022e} "p0")
+
+0x000002f1:         NULL
+
+0x000002f2:       NULL
+
+0x000002f3:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000003cf)
+
+0x000002f8:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000003e3)
+
+0x000002fd:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000040d)
+
+0x00000302:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000445)
+
+0x00000307:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000044f)
+
+0x0000030c:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000004be)
+
+0x00000311:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000004d4)
+
+0x00000316:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000005a1)
+
+0x0000031b:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000669)
+
+0x00000324:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000671)
+
+0x0000032d:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000068e)
+
+0x00000332:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000069f)
+
+0x0000033b:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000006d1)
+
+0x00000340:     NULL
+
+0x00000341:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0346 => {0x00000346} "char*")
+
+0x00000346:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x034b => {0x0000034b} "char")
+
+0x0000034b:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000001ad] = "char")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed_char)
+                DW_AT_byte_size [DW_FORM_data1]	(0x01)
+
+0x00000352:   NULL
+
+.debug_loc contents:
+0x00000000: 
+            [0xffffffff,  0x00000006): 
+            [0x00000000,  0x0000003c): DW_OP_consts +0, DW_OP_stack_value
+
+0x0000001d: 
+            [0xffffffff,  0x00000006): 
+            [0x00000007,  0x0000003c): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000052,  0x00000057): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x000000ec,  0x000000f5): DW_OP_consts +1, DW_OP_stack_value
+            [0x00000131,  0x0000013b): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000179,  0x00000186): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000264,  0x0000026f): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000275,  0x0000027e): DW_OP_consts +1, DW_OP_stack_value
+            [0x000002ba,  0x000002c4): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000302,  0x0000030f): DW_OP_consts +0, DW_OP_stack_value
+
+0x000000a5: 
+            [0xffffffff,  0x00000006): 
+            [0x0000000e,  0x0000003c): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+
+0x000000c3: 
+            [0xffffffff,  0x00000006): 
+            [0x0000001b,  0x0000003c): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+
+0x000000e1: 
+            [0xffffffff,  0x00000006): 
+            [0x00000025,  0x0000003c): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value
+
+0x000000ff: 
+            [0xffffffff,  0x00000006): 
+            [0x0000002f,  0x0000003c): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+
+0x0000011d: 
+            [0xffffffff,  0x00000006): 
+            [0x000001e2,  0x000001e7): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+            [0x0000036b,  0x00000370): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+
+0x00000149: 
+            [0xffffffff,  0x00000006): 
+            [0x000000cf,  0x000000e6): DW_OP_consts +0, DW_OP_stack_value
+            [0x000000ec,  0x000000f5): DW_OP_WASM_location 0x0 +13, DW_OP_stack_value
+            [0x0000015a,  0x00000162): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000264,  0x0000026f): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000275,  0x0000027e): DW_OP_WASM_location 0x0 +10, DW_OP_stack_value
+            [0x000002e3,  0x000002eb): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+
+0x000001ab: 
+            [0xffffffff,  0x00000006): 
+            [0x000000e2,  0x000000e6): DW_OP_WASM_location 0x0 +12, DW_OP_stack_value
+            [0x0000026b,  0x0000026f): DW_OP_WASM_location 0x0 +16, DW_OP_stack_value
+
+0x000001d7: 
+            [0xffffffff,  0x00000006): 
+            [0x000000fc,  0x00000100): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x00000138,  0x0000013b): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x00000285,  0x00000289): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x000002c1,  0x000002c4): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x0000021f: 
+            [0xffffffff,  0x00000006): 
+            [0x00000111,  0x0000013b): DW_OP_WASM_location 0x0 +15, DW_OP_stack_value
+            [0x0000014c,  0x00000162): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x0000029a,  0x000002c4): DW_OP_WASM_location 0x0 +14, DW_OP_stack_value
+            [0x000002d5,  0x000002eb): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000267: 
+            [0xffffffff,  0x0000039f): 
+            [0x00000032,  0x00000037): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+
+0x00000285: 
+            [0xffffffff,  0x0000039f): 
+            [0x0000004c,  0x00000055): DW_OP_consts +30, DW_OP_stack_value
+
+0x000002a2: 
+            [0xffffffff,  0x0000039f): 
+            [0x0000004c,  0x00000055): DW_OP_lit0, DW_OP_stack_value
+            [0x000002f8,  0x00000314): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+
+0x000002cc: 
+            [0xffffffff,  0x0000039f): 
+            [0x0000004c,  0x00000055): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000008e,  0x00000093): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000099,  0x000000c1): DW_OP_consts +0, DW_OP_stack_value
+            [0x000000d7,  0x000000dc): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x000000f5,  0x000000f9): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000127,  0x0000012c): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000178,  0x00000188): DW_OP_consts +0, DW_OP_stack_value
+            [0x000001fa,  0x0000020c): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000241,  0x00000255): DW_OP_consts +0, DW_OP_stack_value
+
+0x00000354: 
+            [0xffffffff,  0x0000039f): 
+            [0x000000a8,  0x000000c1): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000372: 
+            [0xffffffff,  0x0000039f): 
+            [0x000000b2,  0x000000c1): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value
+
+0x00000390: 
+            [0xffffffff,  0x0000039f): 
+            [0x000001e6,  0x000001ed): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+            [0x000002b3,  0x000002ba): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+
+0x000003bc: 
+            [0xffffffff,  0x0000039f): 
+            [0x0000017f,  0x00000188): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value
+            [0x00000248,  0x00000255): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value
+
+0x000003e8: 
+            [0xffffffff,  0x0000039f): 
+            [0x000002d6,  0x000002e1): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000030c,  0x00000314): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+
+0x00000413: 
+            [0xffffffff,  0x0000039f): 
+            [0x000002f1,  0x00000314): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x000005c1
+         version: 4
+ prologue_length: 0x000000dd
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+include_directories[  1] = "/usr/local/google/home/azakai/Dev"
+file_names[  1]:
+           name: "emscripten/tests/fannkuch.cpp"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  2]:
+           name: "emscripten/system/include/libcxx/__nullptr"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  3]:
+           name: "emscripten/system/include/libcxx/stddef.h"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  4]:
+           name: "emscripten/system/include/libc/stdlib.h"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+0x000000e7: 00 DW_LNE_set_address (0x0000000000000006)
+0x000000ee: 03 DW_LNS_advance_line (27)
+0x000000f0: 01 DW_LNS_copy
+            0x0000000000000006     27      0      1   0             0  is_stmt
+
+
+0x000000f1: 05 DW_LNS_set_column (14)
+0x000000f3: 0a DW_LNS_set_prologue_end
+0x000000f4: 7a address += 7,  line += 6
+            0x000000000000000d     33     14      1   0             0  is_stmt prologue_end
+
+0x000000f5: 06 DW_LNS_negate_stmt
+0x000000f6: 03 DW_LNS_advance_line (0)
+0x000000f8: 58 address += 5,  line += 0
+            0x0000000000000012      0     14      1   0             0 
+
+0x000000f9: 05 DW_LNS_set_column (27)
+0x000000fb: 06 DW_LNS_negate_stmt
+0x000000fc: 03 DW_LNS_advance_line (34)
+0x000000fe: 4a address += 4,  line += 0
+            0x0000000000000016     34     27      1   0             0  is_stmt
+
+0x000000ff: 05 DW_LNS_set_column (18)
+0x00000101: 06 DW_LNS_negate_stmt
+0x00000102: 20 address += 1,  line += 0
+            0x0000000000000017     34     18      1   0             0 
+
+0x00000103: 05 DW_LNS_set_column (17)
+0x00000105: 06 DW_LNS_negate_stmt
+0x00000106: 9f address += 10,  line += 1
+            0x0000000000000021     35     17      1   0             0  is_stmt
+
+0x00000107: 05 DW_LNS_set_column (18)
+0x00000109: 9f address += 10,  line += 1
+            0x000000000000002b     36     18      1   0             0  is_stmt
+
+0x0000010a: 06 DW_LNS_negate_stmt
+0x0000010b: 03 DW_LNS_advance_line (0)
+0x0000010d: 9e address += 10,  line += 0
+            0x0000000000000035      0     18      1   0             0 
+
+0x0000010e: 06 DW_LNS_negate_stmt
+0x0000010f: 03 DW_LNS_advance_line (37)
+0x00000111: 66 address += 6,  line += 0
+            0x000000000000003b     37     18      1   0             0  is_stmt
+
+0x00000112: 05 DW_LNS_set_column (4)
+0x00000114: 06 DW_LNS_negate_stmt
+0x00000115: 58 address += 5,  line += 0
+            0x0000000000000040     37      4      1   0             0 
+
+0x00000116: 03 DW_LNS_advance_line (0)
+0x00000118: 2e address += 2,  line += 0
+            0x0000000000000042      0      4      1   0             0 
+
+0x00000119: 05 DW_LNS_set_column (7)
+0x0000011b: 06 DW_LNS_negate_stmt
+0x0000011c: 03 DW_LNS_advance_line (38)
+0x0000011e: 2e address += 2,  line += 0
+            0x0000000000000044     38      7      1   0             0  is_stmt
+
+0x0000011f: 05 DW_LNS_set_column (16)
+0x00000121: 06 DW_LNS_negate_stmt
+0x00000122: 82 address += 8,  line += 0
+            0x000000000000004c     38     16      1   0             0 
+
+0x00000123: 05 DW_LNS_set_column (24)
+0x00000125: 06 DW_LNS_negate_stmt
+0x00000126: 57 address += 5,  line += -1
+            0x0000000000000051     37     24      1   0             0  is_stmt
+
+0x00000127: 05 DW_LNS_set_column (18)
+0x00000129: 06 DW_LNS_negate_stmt
+0x0000012a: 58 address += 5,  line += 0
+            0x0000000000000056     37     18      1   0             0 
+
+0x0000012b: 05 DW_LNS_set_column (4)
+0x0000012d: 58 address += 5,  line += 0
+            0x000000000000005b     37      4      1   0             0 
+
+0x0000012e: 06 DW_LNS_negate_stmt
+0x0000012f: 3e address += 3,  line += 2
+            0x000000000000005e     39      4      1   0             0  is_stmt
+
+0x00000130: 05 DW_LNS_set_column (16)
+0x00000132: 06 DW_LNS_negate_stmt
+0x00000133: 2e address += 2,  line += 0
+            0x0000000000000060     39     16      1   0             0 
+
+0x00000134: 05 DW_LNS_set_column (4)
+0x00000136: 90 address += 9,  line += 0
+            0x0000000000000069     39      4      1   0             0 
+
+0x00000137: 05 DW_LNS_set_column (23)
+0x00000139: 2e address += 2,  line += 0
+            0x000000000000006b     39     23      1   0             0 
+
+0x0000013a: 05 DW_LNS_set_column (19)
+0x0000013c: 58 address += 5,  line += 0
+            0x0000000000000070     39     19      1   0             0 
+
+0x0000013d: 05 DW_LNS_set_column (4)
+0x0000013f: 06 DW_LNS_negate_stmt
+0x00000140: 59 address += 5,  line += 1
+            0x0000000000000075     40      4      1   0             0  is_stmt
+
+0x00000141: 05 DW_LNS_set_column (17)
+0x00000143: 06 DW_LNS_negate_stmt
+0x00000144: 82 address += 8,  line += 0
+            0x000000000000007d     40     17      1   0             0 
+
+0x00000145: 05 DW_LNS_set_column (18)
+0x00000147: 06 DW_LNS_negate_stmt
+0x00000148: a9 address += 11,  line += -3
+            0x0000000000000088     37     18      1   0             0  is_stmt
+
+0x00000149: 05 DW_LNS_set_column (4)
+0x0000014b: 5e address += 5,  line += 6
+            0x000000000000008d     43      4      1   0             0  is_stmt
+
+0x0000014c: 06 DW_LNS_negate_stmt
+0x0000014d: 03 DW_LNS_advance_line (0)
+0x0000014f: 2e address += 2,  line += 0
+            0x000000000000008f      0      4      1   0             0 
+
+0x00000150: 05 DW_LNS_set_column (16)
+0x00000152: 06 DW_LNS_negate_stmt
+0x00000153: 03 DW_LNS_advance_line (44)
+0x00000155: 4a address += 4,  line += 0
+            0x0000000000000093     44     16      1   0             0  is_stmt
+
+0x00000156: 06 DW_LNS_negate_stmt
+0x00000157: 03 DW_LNS_advance_line (0)
+0x00000159: 74 address += 7,  line += 0
+            0x000000000000009a      0     16      1   0             0 
+
+0x0000015a: 05 DW_LNS_set_column (10)
+0x0000015c: 06 DW_LNS_negate_stmt
+0x0000015d: 03 DW_LNS_advance_line (45)
+0x0000015f: 2e address += 2,  line += 0
+            0x000000000000009c     45     10      1   0             0  is_stmt
+
+0x00000160: 05 DW_LNS_set_column (18)
+0x00000162: 06 DW_LNS_negate_stmt
+0x00000163: 2e address += 2,  line += 0
+            0x000000000000009e     45     18      1   0             0 
+
+0x00000164: 05 DW_LNS_set_column (10)
+0x00000166: 90 address += 9,  line += 0
+            0x00000000000000a7     45     10      1   0             0 
+
+0x00000167: 05 DW_LNS_set_column (23)
+0x00000169: 2e address += 2,  line += 0
+            0x00000000000000a9     45     23      1   0             0 
+
+0x0000016a: 05 DW_LNS_set_column (16)
+0x0000016c: 06 DW_LNS_negate_stmt
+0x0000016d: 57 address += 5,  line += -1
+            0x00000000000000ae     44     16      1   0             0  is_stmt
+
+0x0000016e: 05 DW_LNS_set_column (0)
+0x00000170: 06 DW_LNS_negate_stmt
+0x00000171: 03 DW_LNS_advance_line (0)
+0x00000173: 74 address += 7,  line += 0
+            0x00000000000000b5      0      0      1   0             0 
+
+0x00000174: 05 DW_LNS_set_column (7)
+0x00000176: 03 DW_LNS_advance_line (44)
+0x00000178: 4a address += 4,  line += 0
+            0x00000000000000b9     44      7      1   0             0 
+
+0x00000179: 05 DW_LNS_set_column (11)
+0x0000017b: 06 DW_LNS_negate_stmt
+0x0000017c: 68 address += 6,  line += 2
+            0x00000000000000bf     46     11      1   0             0  is_stmt
+
+0x0000017d: 05 DW_LNS_set_column (28)
+0x0000017f: 06 DW_LNS_negate_stmt
+0x00000180: ba address += 12,  line += 0
+            0x00000000000000cb     46     28      1   0             0 
+
+0x00000181: 05 DW_LNS_set_column (41)
+0x00000183: 58 address += 5,  line += 0
+            0x00000000000000d0     46     41      1   0             0 
+
+0x00000184: 05 DW_LNS_set_column (21)
+0x00000186: 06 DW_LNS_negate_stmt
+0x00000187: 5a address += 5,  line += 2
+            0x00000000000000d5     48     21      1   0             0  is_stmt
+
+0x00000188: 05 DW_LNS_set_column (14)
+0x0000018a: bc address += 12,  line += 2
+            0x00000000000000e1     50     14      1   0             0  is_stmt
+
+0x0000018b: 06 DW_LNS_negate_stmt
+0x0000018c: 03 DW_LNS_advance_line (0)
+0x0000018e: 74 address += 7,  line += 0
+            0x00000000000000e8      0     14      1   0             0 
+
+0x0000018f: 05 DW_LNS_set_column (38)
+0x00000191: 06 DW_LNS_negate_stmt
+0x00000192: 03 DW_LNS_advance_line (52)
+0x00000194: ba address += 12,  line += 0
+            0x00000000000000f4     52     38      1   0             0  is_stmt
+
+0x00000195: 05 DW_LNS_set_column (0)
+0x00000197: 06 DW_LNS_negate_stmt
+0x00000198: 03 DW_LNS_advance_line (0)
+0x0000019a: 74 address += 7,  line += 0
+            0x00000000000000fb      0      0      1   0             0 
+
+0x0000019b: 05 DW_LNS_set_column (22)
+0x0000019d: 06 DW_LNS_negate_stmt
+0x0000019e: 03 DW_LNS_advance_line (53)
+0x000001a0: c8 address += 13,  line += 0
+            0x0000000000000108     53     22      1   0             0  is_stmt
+
+0x000001a1: 05 DW_LNS_set_column (24)
+0x000001a3: e5 address += 15,  line += 1
+            0x0000000000000117     54     24      1   0             0  is_stmt
+
+0x000001a4: 05 DW_LNS_set_column (26)
+0x000001a6: 06 DW_LNS_negate_stmt
+0x000001a7: 2e address += 2,  line += 0
+            0x0000000000000119     54     26      1   0             0 
+
+0x000001a8: 05 DW_LNS_set_column (24)
+0x000001aa: c8 address += 13,  line += 0
+            0x0000000000000126     54     24      1   0             0 
+
+0x000001ab: 06 DW_LNS_negate_stmt
+0x000001ac: 3d address += 3,  line += 1
+            0x0000000000000129     55     24      1   0             0  is_stmt
+
+0x000001ad: 05 DW_LNS_set_column (44)
+0x000001af: 71 address += 7,  line += -3
+            0x0000000000000130     52     44      1   0             0  is_stmt
+
+0x000001b0: 06 DW_LNS_negate_stmt
+0x000001b1: 03 DW_LNS_advance_line (0)
+0x000001b3: 58 address += 5,  line += 0
+            0x0000000000000135      0     44      1   0             0 
+
+0x000001b4: 05 DW_LNS_set_column (38)
+0x000001b6: 03 DW_LNS_advance_line (52)
+0x000001b8: 74 address += 7,  line += 0
+            0x000000000000013c     52     38      1   0             0 
+
+0x000001b9: 05 DW_LNS_set_column (13)
+0x000001bb: 3c address += 3,  line += 0
+            0x000000000000013f     52     13      1   0             0 
+
+0x000001bc: 05 DW_LNS_set_column (19)
+0x000001be: 06 DW_LNS_negate_stmt
+0x000001bf: 50 address += 4,  line += 6
+            0x0000000000000143     58     19      1   0             0  is_stmt
+
+0x000001c0: 05 DW_LNS_set_column (21)
+0x000001c2: e5 address += 15,  line += 1
+            0x0000000000000152     59     21      1   0             0  is_stmt
+
+0x000001c3: 05 DW_LNS_set_column (18)
+0x000001c5: 72 address += 7,  line += -2
+            0x0000000000000159     57     18      1   0             0  is_stmt
+
+0x000001c6: 05 DW_LNS_set_column (0)
+0x000001c8: 06 DW_LNS_negate_stmt
+0x000001c9: 03 DW_LNS_advance_line (0)
+0x000001cb: 74 address += 7,  line += 0
+            0x0000000000000160      0      0      1   0             0 
+
+0x000001cc: 05 DW_LNS_set_column (14)
+0x000001ce: 06 DW_LNS_negate_stmt
+0x000001cf: 03 DW_LNS_advance_line (62)
+0x000001d1: 90 address += 9,  line += 0
+            0x0000000000000169     62     14      1   0             0  is_stmt
+
+0x000001d2: 05 DW_LNS_set_column (23)
+0x000001d4: 06 DW_LNS_negate_stmt
+0x000001d5: 4a address += 4,  line += 0
+            0x000000000000016d     62     23      1   0             0 
+
+0x000001d6: 05 DW_LNS_set_column (14)
+0x000001d8: 58 address += 5,  line += 0
+            0x0000000000000172     62     14      1   0             0 
+
+0x000001d9: 03 DW_LNS_advance_line (0)
+0x000001db: 3c address += 3,  line += 0
+            0x0000000000000175      0     14      1   0             0 
+
+0x000001dc: 05 DW_LNS_set_column (16)
+0x000001de: 06 DW_LNS_negate_stmt
+0x000001df: 03 DW_LNS_advance_line (66)
+0x000001e2: 20 address += 1,  line += 0
+            0x0000000000000176     66     16      1   0             0  is_stmt
+
+0x000001e3: 06 DW_LNS_negate_stmt
+0x000001e4: 03 DW_LNS_advance_line (0)
+0x000001e7: 74 address += 7,  line += 0
+            0x000000000000017d      0     16      1   0             0 
+
+0x000001e8: 05 DW_LNS_set_column (27)
+0x000001ea: 06 DW_LNS_negate_stmt
+0x000001eb: 03 DW_LNS_advance_line (75)
+0x000001ee: 82 address += 8,  line += 0
+            0x0000000000000185     75     27      1   0             0  is_stmt
+
+0x000001ef: 06 DW_LNS_negate_stmt
+0x000001f0: 03 DW_LNS_advance_line (0)
+0x000001f3: 74 address += 7,  line += 0
+            0x000000000000018c      0     27      1   0             0 
+
+0x000001f4: 05 DW_LNS_set_column (16)
+0x000001f6: 06 DW_LNS_negate_stmt
+0x000001f7: 03 DW_LNS_advance_line (76)
+0x000001fa: 2e address += 2,  line += 0
+            0x000000000000018e     76     16      1   0             0  is_stmt
+
+0x000001fb: 05 DW_LNS_set_column (27)
+0x000001fd: 06 DW_LNS_negate_stmt
+0x000001fe: 82 address += 8,  line += 0
+            0x0000000000000196     76     27      1   0             0 
+
+0x000001ff: 05 DW_LNS_set_column (35)
+0x00000201: 2e address += 2,  line += 0
+            0x0000000000000198     76     35      1   0             0 
+
+0x00000202: 05 DW_LNS_set_column (27)
+0x00000204: 90 address += 9,  line += 0
+            0x00000000000001a1     76     27      1   0             0 
+
+0x00000205: 05 DW_LNS_set_column (25)
+0x00000207: 58 address += 5,  line += 0
+            0x00000000000001a6     76     25      1   0             0 
+
+0x00000208: 05 DW_LNS_set_column (27)
+0x0000020a: 06 DW_LNS_negate_stmt
+0x0000020b: 3b address += 3,  line += -1
+            0x00000000000001a9     75     27      1   0             0  is_stmt
+
+0x0000020c: 05 DW_LNS_set_column (13)
+0x0000020e: 06 DW_LNS_negate_stmt
+0x0000020f: 58 address += 5,  line += 0
+            0x00000000000001ae     75     13      1   0             0 
+
+0x00000210: 05 DW_LNS_set_column (0)
+0x00000212: 03 DW_LNS_advance_line (0)
+0x00000215: 3c address += 3,  line += 0
+            0x00000000000001b1      0      0      1   0             0 
+
+0x00000216: 05 DW_LNS_set_column (13)
+0x00000218: 06 DW_LNS_negate_stmt
+0x00000219: 03 DW_LNS_advance_line (77)
+0x0000021c: 58 address += 5,  line += 0
+            0x00000000000001b6     77     13      1   0             0  is_stmt
+
+0x0000021d: 05 DW_LNS_set_column (22)
+0x0000021f: 06 DW_LNS_negate_stmt
+0x00000220: 82 address += 8,  line += 0
+            0x00000000000001be     77     22      1   0             0 
+
+0x00000221: 05 DW_LNS_set_column (16)
+0x00000223: 06 DW_LNS_negate_stmt
+0x00000224: 5a address += 5,  line += 2
+            0x00000000000001c3     79     16      1   0             0  is_stmt
+
+0x00000225: 05 DW_LNS_set_column (14)
+0x00000227: 06 DW_LNS_negate_stmt
+0x00000228: 82 address += 8,  line += 0
+            0x00000000000001cb     79     14      1   0             0 
+
+0x00000229: 05 DW_LNS_set_column (25)
+0x0000022b: e4 address += 15,  line += 0
+            0x00000000000001da     79     25      1   0             0 
+
+0x0000022c: 05 DW_LNS_set_column (11)
+0x0000022e: 06 DW_LNS_negate_stmt
+0x0000022f: 76 address += 7,  line += 2
+            0x00000000000001e1     81     11      1   0             0  is_stmt
+
+0x00000230: 05 DW_LNS_set_column (16)
+0x00000232: 03 DW_LNS_advance_line (66)
+0x00000234: 58 address += 5,  line += 0
+            0x00000000000001e6     66     16      1   0             0  is_stmt
+
+0x00000235: 05 DW_LNS_set_column (22)
+0x00000237: 7c address += 7,  line += 8
+            0x00000000000001ed     74     22      1   0             0  is_stmt
+
+0x00000238: 05 DW_LNS_set_column (4)
+0x0000023a: 03 DW_LNS_advance_line (37)
+0x0000023c: 90 address += 9,  line += 0
+            0x00000000000001f6     37      4      1   0             0  is_stmt
+
+0x0000023d: 3e address += 3,  line += 2
+            0x00000000000001f9     39      4      1   0             0  is_stmt
+
+0x0000023e: 05 DW_LNS_set_column (16)
+0x00000240: 06 DW_LNS_negate_stmt
+0x00000241: 2e address += 2,  line += 0
+            0x00000000000001fb     39     16      1   0             0 
+
+0x00000242: 05 DW_LNS_set_column (4)
+0x00000244: 90 address += 9,  line += 0
+            0x0000000000000204     39      4      1   0             0 
+
+0x00000245: 05 DW_LNS_set_column (23)
+0x00000247: 2e address += 2,  line += 0
+            0x0000000000000206     39     23      1   0             0 
+
+0x00000248: 05 DW_LNS_set_column (19)
+0x0000024a: 58 address += 5,  line += 0
+            0x000000000000020b     39     19      1   0             0 
+
+0x0000024b: 05 DW_LNS_set_column (4)
+0x0000024d: 06 DW_LNS_negate_stmt
+0x0000024e: 59 address += 5,  line += 1
+            0x0000000000000210     40      4      1   0             0  is_stmt
+
+0x0000024f: 05 DW_LNS_set_column (17)
+0x00000251: 06 DW_LNS_negate_stmt
+0x00000252: 82 address += 8,  line += 0
+            0x0000000000000218     40     17      1   0             0 
+
+0x00000253: 03 DW_LNS_advance_line (0)
+0x00000255: 74 address += 7,  line += 0
+            0x000000000000021f      0     17      1   0             0 
+
+0x00000256: 05 DW_LNS_set_column (16)
+0x00000258: 06 DW_LNS_negate_stmt
+0x00000259: 03 DW_LNS_advance_line (44)
+0x0000025b: 90 address += 9,  line += 0
+            0x0000000000000228     44     16      1   0             0  is_stmt
+
+0x0000025c: 06 DW_LNS_negate_stmt
+0x0000025d: 03 DW_LNS_advance_line (0)
+0x0000025f: 74 address += 7,  line += 0
+            0x000000000000022f      0     16      1   0             0 
+
+0x00000260: 05 DW_LNS_set_column (10)
+0x00000262: 06 DW_LNS_negate_stmt
+0x00000263: 03 DW_LNS_advance_line (45)
+0x00000265: 2e address += 2,  line += 0
+            0x0000000000000231     45     10      1   0             0  is_stmt
+
+0x00000266: 05 DW_LNS_set_column (18)
+0x00000268: 06 DW_LNS_negate_stmt
+0x00000269: 2e address += 2,  line += 0
+            0x0000000000000233     45     18      1   0             0 
+
+0x0000026a: 05 DW_LNS_set_column (10)
+0x0000026c: 90 address += 9,  line += 0
+            0x000000000000023c     45     10      1   0             0 
+
+0x0000026d: 05 DW_LNS_set_column (23)
+0x0000026f: 2e address += 2,  line += 0
+            0x000000000000023e     45     23      1   0             0 
+
+0x00000270: 05 DW_LNS_set_column (16)
+0x00000272: 06 DW_LNS_negate_stmt
+0x00000273: 57 address += 5,  line += -1
+            0x0000000000000243     44     16      1   0             0  is_stmt
+
+0x00000274: 06 DW_LNS_negate_stmt
+0x00000275: 03 DW_LNS_advance_line (0)
+0x00000277: e4 address += 15,  line += 0
+            0x0000000000000252      0     16      1   0             0 
+
+0x00000278: 05 DW_LNS_set_column (11)
+0x0000027a: 06 DW_LNS_negate_stmt
+0x0000027b: 03 DW_LNS_advance_line (46)
+0x0000027d: 2e address += 2,  line += 0
+            0x0000000000000254     46     11      1   0             0  is_stmt
+
+0x0000027e: 05 DW_LNS_set_column (28)
+0x00000280: 06 DW_LNS_negate_stmt
+0x00000281: ba address += 12,  line += 0
+            0x0000000000000260     46     28      1   0             0 
+
+0x00000282: 05 DW_LNS_set_column (41)
+0x00000284: 58 address += 5,  line += 0
+            0x0000000000000265     46     41      1   0             0 
+
+0x00000285: 05 DW_LNS_set_column (14)
+0x00000287: 06 DW_LNS_negate_stmt
+0x00000288: 5c address += 5,  line += 4
+            0x000000000000026a     50     14      1   0             0  is_stmt
+
+0x00000289: 06 DW_LNS_negate_stmt
+0x0000028a: 03 DW_LNS_advance_line (0)
+0x0000028c: 74 address += 7,  line += 0
+            0x0000000000000271      0     14      1   0             0 
+
+0x0000028d: 05 DW_LNS_set_column (38)
+0x0000028f: 06 DW_LNS_negate_stmt
+0x00000290: 03 DW_LNS_advance_line (52)
+0x00000292: ba address += 12,  line += 0
+            0x000000000000027d     52     38      1   0             0  is_stmt
+
+0x00000293: 05 DW_LNS_set_column (0)
+0x00000295: 06 DW_LNS_negate_stmt
+0x00000296: 03 DW_LNS_advance_line (0)
+0x00000298: 74 address += 7,  line += 0
+            0x0000000000000284      0      0      1   0             0 
+
+0x00000299: 05 DW_LNS_set_column (22)
+0x0000029b: 06 DW_LNS_negate_stmt
+0x0000029c: 03 DW_LNS_advance_line (53)
+0x0000029e: c8 address += 13,  line += 0
+            0x0000000000000291     53     22      1   0             0  is_stmt
+
+0x0000029f: 05 DW_LNS_set_column (24)
+0x000002a1: e5 address += 15,  line += 1
+            0x00000000000002a0     54     24      1   0             0  is_stmt
+
+0x000002a2: 05 DW_LNS_set_column (26)
+0x000002a4: 06 DW_LNS_negate_stmt
+0x000002a5: 2e address += 2,  line += 0
+            0x00000000000002a2     54     26      1   0             0 
+
+0x000002a6: 05 DW_LNS_set_column (24)
+0x000002a8: c8 address += 13,  line += 0
+            0x00000000000002af     54     24      1   0             0 
+
+0x000002a9: 06 DW_LNS_negate_stmt
+0x000002aa: 3d address += 3,  line += 1
+            0x00000000000002b2     55     24      1   0             0  is_stmt
+
+0x000002ab: 05 DW_LNS_set_column (44)
+0x000002ad: 71 address += 7,  line += -3
+            0x00000000000002b9     52     44      1   0             0  is_stmt
+
+0x000002ae: 06 DW_LNS_negate_stmt
+0x000002af: 03 DW_LNS_advance_line (0)
+0x000002b1: 58 address += 5,  line += 0
+            0x00000000000002be      0     44      1   0             0 
+
+0x000002b2: 05 DW_LNS_set_column (38)
+0x000002b4: 03 DW_LNS_advance_line (52)
+0x000002b6: 74 address += 7,  line += 0
+            0x00000000000002c5     52     38      1   0             0 
+
+0x000002b7: 03 DW_LNS_advance_line (0)
+0x000002b9: 58 address += 5,  line += 0
+            0x00000000000002ca      0     38      1   0             0 
+
+0x000002ba: 05 DW_LNS_set_column (19)
+0x000002bc: 06 DW_LNS_negate_stmt
+0x000002bd: 03 DW_LNS_advance_line (58)
+0x000002bf: 2e address += 2,  line += 0
+            0x00000000000002cc     58     19      1   0             0  is_stmt
+
+0x000002c0: 05 DW_LNS_set_column (21)
+0x000002c2: e5 address += 15,  line += 1
+            0x00000000000002db     59     21      1   0             0  is_stmt
+
+0x000002c3: 05 DW_LNS_set_column (18)
+0x000002c5: 72 address += 7,  line += -2
+            0x00000000000002e2     57     18      1   0             0  is_stmt
+
+0x000002c6: 05 DW_LNS_set_column (0)
+0x000002c8: 06 DW_LNS_negate_stmt
+0x000002c9: 03 DW_LNS_advance_line (0)
+0x000002cb: 74 address += 7,  line += 0
+            0x00000000000002e9      0      0      1   0             0 
+
+0x000002cc: 05 DW_LNS_set_column (14)
+0x000002ce: 06 DW_LNS_negate_stmt
+0x000002cf: 03 DW_LNS_advance_line (62)
+0x000002d1: 90 address += 9,  line += 0
+            0x00000000000002f2     62     14      1   0             0  is_stmt
+
+0x000002d2: 05 DW_LNS_set_column (23)
+0x000002d4: 06 DW_LNS_negate_stmt
+0x000002d5: 4a address += 4,  line += 0
+            0x00000000000002f6     62     23      1   0             0 
+
+0x000002d6: 05 DW_LNS_set_column (14)
+0x000002d8: 58 address += 5,  line += 0
+            0x00000000000002fb     62     14      1   0             0 
+
+0x000002d9: 03 DW_LNS_advance_line (0)
+0x000002db: 3c address += 3,  line += 0
+            0x00000000000002fe      0     14      1   0             0 
+
+0x000002dc: 05 DW_LNS_set_column (16)
+0x000002de: 06 DW_LNS_negate_stmt
+0x000002df: 03 DW_LNS_advance_line (66)
+0x000002e2: 20 address += 1,  line += 0
+            0x00000000000002ff     66     16      1   0             0  is_stmt
+
+0x000002e3: 06 DW_LNS_negate_stmt
+0x000002e4: 03 DW_LNS_advance_line (0)
+0x000002e7: 74 address += 7,  line += 0
+            0x0000000000000306      0     16      1   0             0 
+
+0x000002e8: 05 DW_LNS_set_column (27)
+0x000002ea: 06 DW_LNS_negate_stmt
+0x000002eb: 03 DW_LNS_advance_line (75)
+0x000002ee: 82 address += 8,  line += 0
+            0x000000000000030e     75     27      1   0             0  is_stmt
+
+0x000002ef: 06 DW_LNS_negate_stmt
+0x000002f0: 03 DW_LNS_advance_line (0)
+0x000002f3: 74 address += 7,  line += 0
+            0x0000000000000315      0     27      1   0             0 
+
+0x000002f4: 05 DW_LNS_set_column (16)
+0x000002f6: 06 DW_LNS_negate_stmt
+0x000002f7: 03 DW_LNS_advance_line (76)
+0x000002fa: 2e address += 2,  line += 0
+            0x0000000000000317     76     16      1   0             0  is_stmt
+
+0x000002fb: 05 DW_LNS_set_column (27)
+0x000002fd: 06 DW_LNS_negate_stmt
+0x000002fe: 82 address += 8,  line += 0
+            0x000000000000031f     76     27      1   0             0 
+
+0x000002ff: 05 DW_LNS_set_column (35)
+0x00000301: 2e address += 2,  line += 0
+            0x0000000000000321     76     35      1   0             0 
+
+0x00000302: 05 DW_LNS_set_column (27)
+0x00000304: 90 address += 9,  line += 0
+            0x000000000000032a     76     27      1   0             0 
+
+0x00000305: 05 DW_LNS_set_column (25)
+0x00000307: 58 address += 5,  line += 0
+            0x000000000000032f     76     25      1   0             0 
+
+0x00000308: 05 DW_LNS_set_column (27)
+0x0000030a: 06 DW_LNS_negate_stmt
+0x0000030b: 3b address += 3,  line += -1
+            0x0000000000000332     75     27      1   0             0  is_stmt
+
+0x0000030c: 06 DW_LNS_negate_stmt
+0x0000030d: 03 DW_LNS_advance_line (0)
+0x00000310: 74 address += 7,  line += 0
+            0x0000000000000339      0     27      1   0             0 
+
+0x00000311: 05 DW_LNS_set_column (13)
+0x00000313: 06 DW_LNS_negate_stmt
+0x00000314: 03 DW_LNS_advance_line (77)
+0x00000317: 66 address += 6,  line += 0
+            0x000000000000033f     77     13      1   0             0  is_stmt
+
+0x00000318: 05 DW_LNS_set_column (22)
+0x0000031a: 06 DW_LNS_negate_stmt
+0x0000031b: 82 address += 8,  line += 0
+            0x0000000000000347     77     22      1   0             0 
+
+0x0000031c: 05 DW_LNS_set_column (16)
+0x0000031e: 06 DW_LNS_negate_stmt
+0x0000031f: 5a address += 5,  line += 2
+            0x000000000000034c     79     16      1   0             0  is_stmt
+
+0x00000320: 05 DW_LNS_set_column (14)
+0x00000322: 06 DW_LNS_negate_stmt
+0x00000323: 82 address += 8,  line += 0
+            0x0000000000000354     79     14      1   0             0 
+
+0x00000324: 05 DW_LNS_set_column (25)
+0x00000326: e4 address += 15,  line += 0
+            0x0000000000000363     79     25      1   0             0 
+
+0x00000327: 05 DW_LNS_set_column (11)
+0x00000329: 06 DW_LNS_negate_stmt
+0x0000032a: 76 address += 7,  line += 2
+            0x000000000000036a     81     11      1   0             0  is_stmt
+
+0x0000032b: 05 DW_LNS_set_column (16)
+0x0000032d: 03 DW_LNS_advance_line (66)
+0x0000032f: 58 address += 5,  line += 0
+            0x000000000000036f     66     16      1   0             0  is_stmt
+
+0x00000330: 05 DW_LNS_set_column (22)
+0x00000332: 7c address += 7,  line += 8
+            0x0000000000000376     74     22      1   0             0  is_stmt
+
+0x00000333: 06 DW_LNS_negate_stmt
+0x00000334: 03 DW_LNS_advance_line (0)
+0x00000337: 90 address += 9,  line += 0
+            0x000000000000037f      0     22      1   0             0 
+
+0x00000338: 05 DW_LNS_set_column (13)
+0x0000033a: 06 DW_LNS_negate_stmt
+0x0000033b: 03 DW_LNS_advance_line (67)
+0x0000033e: 3c address += 3,  line += 0
+            0x0000000000000382     67     13      1   0             0  is_stmt
+
+0x0000033f: 83 address += 8,  line += 1
+            0x000000000000038a     68     13      1   0             0  is_stmt
+
+0x00000340: 83 address += 8,  line += 1
+            0x0000000000000392     69     13      1   0             0  is_stmt
+
+0x00000341: 83 address += 8,  line += 1
+            0x000000000000039a     70     13      1   0             0  is_stmt
+
+0x00000342: 02 DW_LNS_advance_pc (3)
+0x00000344: 00 DW_LNE_end_sequence
+            0x000000000000039d     70     13      1   0             0  is_stmt end_sequence
+
+0x00000347: 00 DW_LNE_set_address (0x000000000000039f)
+0x0000034e: 03 DW_LNS_advance_line (152)
+0x00000351: 01 DW_LNS_copy
+            0x000000000000039f    152      0      1   0             0  is_stmt
+
+
+0x00000352: 05 DW_LNS_set_column (17)
+0x00000354: 0a DW_LNS_set_prologue_end
+0x00000355: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000356: 91 address += 9,  line += 1
+            0x00000000000003b9    153     17      1   0             0  is_stmt prologue_end
+
+0x00000357: 05 DW_LNS_set_column (12)
+0x00000359: 06 DW_LNS_negate_stmt
+0x0000035a: 58 address += 5,  line += 0
+            0x00000000000003be    153     12      1   0             0 
+
+0x0000035b: 03 DW_LNS_advance_line (0)
+0x0000035e: 2e address += 2,  line += 0
+            0x00000000000003c0      0     12      1   0             0 
+
+0x0000035f: 05 DW_LNS_set_column (28)
+0x00000361: 03 DW_LNS_advance_line (153)
+0x00000364: 4a address += 4,  line += 0
+            0x00000000000003c4    153     28      1   0             0 
+
+0x00000365: 05 DW_LNS_set_column (23)
+0x00000367: 58 address += 5,  line += 0
+            0x00000000000003c9    153     23      1   0             0 
+
+0x00000368: 03 DW_LNS_advance_line (0)
+0x0000036b: 66 address += 6,  line += 0
+            0x00000000000003cf      0     23      1   0             0 
+
+0x0000036c: 05 DW_LNS_set_column (10)
+0x0000036e: 06 DW_LNS_negate_stmt
+0x0000036f: 03 DW_LNS_advance_line (155)
+0x00000372: 4a address += 4,  line += 0
+            0x00000000000003d3    155     10      1   0             0  is_stmt
+
+0x00000373: 05 DW_LNS_set_column (8)
+0x00000375: 06 DW_LNS_negate_stmt
+0x00000376: 20 address += 1,  line += 0
+            0x00000000000003d4    155      8      1   0             0 
+
+0x00000377: 03 DW_LNS_advance_line (0)
+0x0000037a: 2e address += 2,  line += 0
+            0x00000000000003d6      0      8      1   0             0 
+
+0x0000037b: 05 DW_LNS_set_column (7)
+0x0000037d: 06 DW_LNS_negate_stmt
+0x0000037e: 03 DW_LNS_advance_line (156)
+0x00000381: 20 address += 1,  line += 0
+            0x00000000000003d7    156      7      1   0             0  is_stmt
+
+0x00000382: 06 DW_LNS_negate_stmt
+0x00000383: 03 DW_LNS_advance_line (0)
+0x00000386: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000387: 2e address += 2,  line += 0
+            0x00000000000003ea      0      7      1   0             0 
+
+0x00000388: 05 DW_LNS_set_column (18)
+0x0000038a: 06 DW_LNS_negate_stmt
+0x0000038b: 03 DW_LNS_advance_line (94)
+0x0000038e: 3c address += 3,  line += 0
+            0x00000000000003ed     94     18      1   0             0  is_stmt
+
+0x0000038f: 05 DW_LNS_set_column (4)
+0x00000391: 06 DW_LNS_negate_stmt
+0x00000392: 58 address += 5,  line += 0
+            0x00000000000003f2     94      4      1   0             0 
+
+0x00000393: 03 DW_LNS_advance_line (0)
+0x00000396: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000397: 12 address += 0,  line += 0
+            0x0000000000000403      0      4      1   0             0 
+
+0x00000398: 05 DW_LNS_set_column (29)
+0x0000039a: 06 DW_LNS_negate_stmt
+0x0000039b: 03 DW_LNS_advance_line (95)
+0x0000039e: 4a address += 4,  line += 0
+            0x0000000000000407     95     29      1   0             0  is_stmt
+
+0x0000039f: 05 DW_LNS_set_column (19)
+0x000003a1: 69 address += 6,  line += 3
+            0x000000000000040d     98     19      1   0             0  is_stmt
+
+0x000003a2: 05 DW_LNS_set_column (16)
+0x000003a4: 73 address += 7,  line += -1
+            0x0000000000000414     97     16      1   0             0  is_stmt
+
+0x000003a5: 73 address += 7,  line += -1
+            0x000000000000041b     96     16      1   0             0  is_stmt
+
+0x000003a6: 06 DW_LNS_negate_stmt
+0x000003a7: 03 DW_LNS_advance_line (0)
+0x000003aa: 74 address += 7,  line += 0
+            0x0000000000000422      0     16      1   0             0 
+
+0x000003ab: 05 DW_LNS_set_column (28)
+0x000003ad: 06 DW_LNS_negate_stmt
+0x000003ae: 03 DW_LNS_advance_line (94)
+0x000003b1: 4a address += 4,  line += 0
+            0x0000000000000426     94     28      1   0             0  is_stmt
+
+0x000003b2: 05 DW_LNS_set_column (18)
+0x000003b4: 06 DW_LNS_negate_stmt
+0x000003b5: 58 address += 5,  line += 0
+            0x000000000000042b     94     18      1   0             0 
+
+0x000003b6: 05 DW_LNS_set_column (4)
+0x000003b8: 58 address += 5,  line += 0
+            0x0000000000000430     94      4      1   0             0 
+
+0x000003b9: 03 DW_LNS_advance_line (0)
+0x000003bc: 4a address += 4,  line += 0
+            0x0000000000000434      0      4      1   0             0 
+
+0x000003bd: 05 DW_LNS_set_column (27)
+0x000003bf: 06 DW_LNS_negate_stmt
+0x000003c0: 03 DW_LNS_advance_line (102)
+0x000003c3: 4a address += 4,  line += 0
+            0x0000000000000438    102     27      1   0             0  is_stmt
+
+0x000003c4: 05 DW_LNS_set_column (18)
+0x000003c6: 06 DW_LNS_negate_stmt
+0x000003c7: 58 address += 5,  line += 0
+            0x000000000000043d    102     18      1   0             0 
+
+0x000003c8: 06 DW_LNS_negate_stmt
+0x000003c9: 9f address += 10,  line += 1
+            0x0000000000000447    103     18      1   0             0  is_stmt
+
+0x000003ca: 06 DW_LNS_negate_stmt
+0x000003cb: 03 DW_LNS_advance_line (0)
+0x000003ce: 9e address += 10,  line += 0
+            0x0000000000000451      0     18      1   0             0 
+
+0x000003cf: 06 DW_LNS_negate_stmt
+0x000003d0: 03 DW_LNS_advance_line (105)
+0x000003d3: 82 address += 8,  line += 0
+            0x0000000000000459    105     18      1   0             0  is_stmt
+
+0x000003d4: 05 DW_LNS_set_column (4)
+0x000003d6: 06 DW_LNS_negate_stmt
+0x000003d7: 58 address += 5,  line += 0
+            0x000000000000045e    105      4      1   0             0 
+
+0x000003d8: 03 DW_LNS_advance_line (0)
+0x000003db: 2e address += 2,  line += 0
+            0x0000000000000460      0      4      1   0             0 
+
+0x000003dc: 05 DW_LNS_set_column (7)
+0x000003de: 06 DW_LNS_negate_stmt
+0x000003df: 03 DW_LNS_advance_line (106)
+0x000003e2: 2e address += 2,  line += 0
+            0x0000000000000462    106      7      1   0             0  is_stmt
+
+0x000003e3: 05 DW_LNS_set_column (16)
+0x000003e5: 06 DW_LNS_negate_stmt
+0x000003e6: 82 address += 8,  line += 0
+            0x000000000000046a    106     16      1   0             0 
+
+0x000003e7: 05 DW_LNS_set_column (24)
+0x000003e9: 06 DW_LNS_negate_stmt
+0x000003ea: 57 address += 5,  line += -1
+            0x000000000000046f    105     24      1   0             0  is_stmt
+
+0x000003eb: 05 DW_LNS_set_column (18)
+0x000003ed: 06 DW_LNS_negate_stmt
+0x000003ee: 58 address += 5,  line += 0
+            0x0000000000000474    105     18      1   0             0 
+
+0x000003ef: 03 DW_LNS_advance_line (0)
+0x000003f2: 74 address += 7,  line += 0
+            0x000000000000047b      0     18      1   0             0 
+
+0x000003f3: 05 DW_LNS_set_column (13)
+0x000003f5: 06 DW_LNS_negate_stmt
+0x000003f6: 03 DW_LNS_advance_line (112)
+0x000003f9: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000003fa: d6 address += 14,  line += 0
+            0x000000000000049a    112     13      1   0             0  is_stmt
+
+0x000003fb: 05 DW_LNS_set_column (26)
+0x000003fd: 06 DW_LNS_negate_stmt
+0x000003fe: 2e address += 2,  line += 0
+            0x000000000000049c    112     26      1   0             0 
+
+0x000003ff: 05 DW_LNS_set_column (35)
+0x00000401: c8 address += 13,  line += 0
+            0x00000000000004a9    112     35      1   0             0 
+
+0x00000402: 05 DW_LNS_set_column (13)
+0x00000404: 20 address += 1,  line += 0
+            0x00000000000004aa    112     13      1   0             0 
+
+0x00000405: 05 DW_LNS_set_column (30)
+0x00000407: 06 DW_LNS_negate_stmt
+0x00000408: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000409: 49 address += 4,  line += -1
+            0x00000000000004bf    111     30      1   0             0  is_stmt
+
+0x0000040a: 05 DW_LNS_set_column (24)
+0x0000040c: 06 DW_LNS_negate_stmt
+0x0000040d: 58 address += 5,  line += 0
+            0x00000000000004c4    111     24      1   0             0 
+
+0x0000040e: 05 DW_LNS_set_column (10)
+0x00000410: 58 address += 5,  line += 0
+            0x00000000000004c9    111     10      1   0             0 
+
+0x00000411: 06 DW_LNS_negate_stmt
+0x00000412: 5a address += 5,  line += 2
+            0x00000000000004ce    113     10      1   0             0  is_stmt
+
+0x00000413: 06 DW_LNS_negate_stmt
+0x00000414: 03 DW_LNS_advance_line (0)
+0x00000417: 74 address += 7,  line += 0
+            0x00000000000004d5      0     10      1   0             0 
+
+0x00000418: 05 DW_LNS_set_column (16)
+0x0000041a: 06 DW_LNS_negate_stmt
+0x0000041b: 03 DW_LNS_advance_line (118)
+0x0000041e: 2e address += 2,  line += 0
+            0x00000000000004d7    118     16      1   0             0  is_stmt
+
+0x0000041f: 05 DW_LNS_set_column (7)
+0x00000421: 06 DW_LNS_negate_stmt
+0x00000422: 58 address += 5,  line += 0
+            0x00000000000004dc    118      7      1   0             0 
+
+0x00000423: 03 DW_LNS_advance_line (0)
+0x00000426: 2e address += 2,  line += 0
+            0x00000000000004de      0      7      1   0             0 
+
+0x00000427: 05 DW_LNS_set_column (10)
+0x00000429: 06 DW_LNS_negate_stmt
+0x0000042a: 03 DW_LNS_advance_line (119)
+0x0000042d: 2e address += 2,  line += 0
+            0x00000000000004e0    119     10      1   0             0  is_stmt
+
+0x0000042e: 05 DW_LNS_set_column (18)
+0x00000430: 06 DW_LNS_negate_stmt
+0x00000431: 2e address += 2,  line += 0
+            0x00000000000004e2    119     18      1   0             0 
+
+0x00000432: 05 DW_LNS_set_column (10)
+0x00000434: 90 address += 9,  line += 0
+            0x00000000000004eb    119     10      1   0             0 
+
+0x00000435: 05 DW_LNS_set_column (23)
+0x00000437: 2e address += 2,  line += 0
+            0x00000000000004ed    119     23      1   0             0 
+
+0x00000438: 05 DW_LNS_set_column (16)
+0x0000043a: 06 DW_LNS_negate_stmt
+0x0000043b: 57 address += 5,  line += -1
+            0x00000000000004f2    118     16      1   0             0  is_stmt
+
+0x0000043c: 05 DW_LNS_set_column (7)
+0x0000043e: 06 DW_LNS_negate_stmt
+0x0000043f: ac address += 11,  line += 0
+            0x00000000000004fd    118      7      1   0             0 
+
+0x00000440: 05 DW_LNS_set_column (16)
+0x00000442: 06 DW_LNS_negate_stmt
+0x00000443: 6a address += 6,  line += 4
+            0x0000000000000503    122     16      1   0             0  is_stmt
+
+0x00000444: 06 DW_LNS_negate_stmt
+0x00000445: 03 DW_LNS_advance_line (0)
+0x00000448: 74 address += 7,  line += 0
+            0x000000000000050a      0     16      1   0             0 
+
+0x00000449: 05 DW_LNS_set_column (22)
+0x0000044b: 06 DW_LNS_negate_stmt
+0x0000044c: 03 DW_LNS_advance_line (125)
+0x0000044f: c8 address += 13,  line += 0
+            0x0000000000000517    125     22      1   0             0  is_stmt
+
+0x00000450: 06 DW_LNS_negate_stmt
+0x00000451: 03 DW_LNS_advance_line (0)
+0x00000454: 74 address += 7,  line += 0
+            0x000000000000051e      0     22      1   0             0 
+
+0x00000455: 05 DW_LNS_set_column (27)
+0x00000457: 06 DW_LNS_negate_stmt
+0x00000458: 03 DW_LNS_advance_line (126)
+0x0000045b: 2e address += 2,  line += 0
+            0x0000000000000520    126     27      1   0             0  is_stmt
+
+0x0000045c: 05 DW_LNS_set_column (13)
+0x0000045e: 06 DW_LNS_negate_stmt
+0x0000045f: 58 address += 5,  line += 0
+            0x0000000000000525    126     13      1   0             0 
+
+0x00000460: 03 DW_LNS_advance_line (0)
+0x00000463: 2e address += 2,  line += 0
+            0x0000000000000527      0     13      1   0             0 
+
+0x00000464: 05 DW_LNS_set_column (16)
+0x00000466: 06 DW_LNS_negate_stmt
+0x00000467: 03 DW_LNS_advance_line (127)
+0x0000046a: 2e address += 2,  line += 0
+            0x0000000000000529    127     16      1   0             0  is_stmt
+
+0x0000046b: 05 DW_LNS_set_column (27)
+0x0000046d: 06 DW_LNS_negate_stmt
+0x0000046e: 82 address += 8,  line += 0
+            0x0000000000000531    127     27      1   0             0 
+
+0x0000046f: 05 DW_LNS_set_column (35)
+0x00000471: 2e address += 2,  line += 0
+            0x0000000000000533    127     35      1   0             0 
+
+0x00000472: 05 DW_LNS_set_column (27)
+0x00000474: 90 address += 9,  line += 0
+            0x000000000000053c    127     27      1   0             0 
+
+0x00000475: 05 DW_LNS_set_column (25)
+0x00000477: 58 address += 5,  line += 0
+            0x0000000000000541    127     25      1   0             0 
+
+0x00000478: 05 DW_LNS_set_column (27)
+0x0000047a: 06 DW_LNS_negate_stmt
+0x0000047b: 3b address += 3,  line += -1
+            0x0000000000000544    126     27      1   0             0  is_stmt
+
+0x0000047c: 05 DW_LNS_set_column (13)
+0x0000047e: 06 DW_LNS_negate_stmt
+0x0000047f: 58 address += 5,  line += 0
+            0x0000000000000549    126     13      1   0             0 
+
+0x00000480: 05 DW_LNS_set_column (0)
+0x00000482: 03 DW_LNS_advance_line (0)
+0x00000485: 3c address += 3,  line += 0
+            0x000000000000054c      0      0      1   0             0 
+
+0x00000486: 05 DW_LNS_set_column (13)
+0x00000488: 06 DW_LNS_negate_stmt
+0x00000489: 03 DW_LNS_advance_line (128)
+0x0000048c: 58 address += 5,  line += 0
+            0x0000000000000551    128     13      1   0             0  is_stmt
+
+0x0000048d: 05 DW_LNS_set_column (22)
+0x0000048f: 06 DW_LNS_negate_stmt
+0x00000490: 82 address += 8,  line += 0
+            0x0000000000000559    128     22      1   0             0 
+
+0x00000491: 05 DW_LNS_set_column (16)
+0x00000493: 06 DW_LNS_negate_stmt
+0x00000494: 5a address += 5,  line += 2
+            0x000000000000055e    130     16      1   0             0  is_stmt
+
+0x00000495: 05 DW_LNS_set_column (14)
+0x00000497: 06 DW_LNS_negate_stmt
+0x00000498: 82 address += 8,  line += 0
+            0x0000000000000566    130     14      1   0             0 
+
+0x00000499: 05 DW_LNS_set_column (25)
+0x0000049b: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x0000049c: 12 address += 0,  line += 0
+            0x0000000000000577    130     25      1   0             0 
+
+0x0000049d: 05 DW_LNS_set_column (14)
+0x0000049f: 58 address += 5,  line += 0
+            0x000000000000057c    130     14      1   0             0 
+
+0x000004a0: 05 DW_LNS_set_column (11)
+0x000004a2: 06 DW_LNS_negate_stmt
+0x000004a3: 31 address += 2,  line += 3
+            0x000000000000057e    133     11      1   0             0  is_stmt
+
+0x000004a4: 05 DW_LNS_set_column (16)
+0x000004a6: 03 DW_LNS_advance_line (122)
+0x000004a8: 58 address += 5,  line += 0
+            0x0000000000000583    122     16      1   0             0  is_stmt
+
+0x000004a9: 05 DW_LNS_set_column (14)
+0x000004ab: 06 DW_LNS_negate_stmt
+0x000004ac: 58 address += 5,  line += 0
+            0x0000000000000588    122     14      1   0             0 
+
+0x000004ad: 03 DW_LNS_advance_line (0)
+0x000004b0: 4a address += 4,  line += 0
+            0x000000000000058c      0     14      1   0             0 
+
+0x000004b1: 06 DW_LNS_negate_stmt
+0x000004b2: 03 DW_LNS_advance_line (130)
+0x000004b5: 20 address += 1,  line += 0
+            0x000000000000058d    130     14      1   0             0  is_stmt
+
+0x000004b6: 05 DW_LNS_set_column (11)
+0x000004b8: 03 DW_LNS_advance_line (110)
+0x000004ba: 20 address += 1,  line += 0
+            0x000000000000058e    110     11      1   0             0  is_stmt
+
+0x000004bb: 06 DW_LNS_negate_stmt
+0x000004bc: 03 DW_LNS_advance_line (0)
+0x000004bf: 74 address += 7,  line += 0
+            0x0000000000000595      0     11      1   0             0 
+
+0x000004c0: 05 DW_LNS_set_column (10)
+0x000004c2: 06 DW_LNS_negate_stmt
+0x000004c3: 03 DW_LNS_advance_line (113)
+0x000004c6: 66 address += 6,  line += 0
+            0x000000000000059b    113     10      1   0             0  is_stmt
+
+0x000004c7: 06 DW_LNS_negate_stmt
+0x000004c8: 03 DW_LNS_advance_line (0)
+0x000004cb: 74 address += 7,  line += 0
+            0x00000000000005a2      0     10      1   0             0 
+
+0x000004cc: 05 DW_LNS_set_column (16)
+0x000004ce: 06 DW_LNS_negate_stmt
+0x000004cf: 03 DW_LNS_advance_line (118)
+0x000004d2: 2e address += 2,  line += 0
+            0x00000000000005a4    118     16      1   0             0  is_stmt
+
+0x000004d3: 05 DW_LNS_set_column (7)
+0x000004d5: 06 DW_LNS_negate_stmt
+0x000004d6: 58 address += 5,  line += 0
+            0x00000000000005a9    118      7      1   0             0 
+
+0x000004d7: 03 DW_LNS_advance_line (0)
+0x000004da: 2e address += 2,  line += 0
+            0x00000000000005ab      0      7      1   0             0 
+
+0x000004db: 05 DW_LNS_set_column (10)
+0x000004dd: 06 DW_LNS_negate_stmt
+0x000004de: 03 DW_LNS_advance_line (119)
+0x000004e1: 2e address += 2,  line += 0
+            0x00000000000005ad    119     10      1   0             0  is_stmt
+
+0x000004e2: 05 DW_LNS_set_column (18)
+0x000004e4: 06 DW_LNS_negate_stmt
+0x000004e5: 2e address += 2,  line += 0
+            0x00000000000005af    119     18      1   0             0 
+
+0x000004e6: 05 DW_LNS_set_column (10)
+0x000004e8: 90 address += 9,  line += 0
+            0x00000000000005b8    119     10      1   0             0 
+
+0x000004e9: 05 DW_LNS_set_column (23)
+0x000004eb: 2e address += 2,  line += 0
+            0x00000000000005ba    119     23      1   0             0 
+
+0x000004ec: 05 DW_LNS_set_column (16)
+0x000004ee: 06 DW_LNS_negate_stmt
+0x000004ef: 57 address += 5,  line += -1
+            0x00000000000005bf    118     16      1   0             0  is_stmt
+
+0x000004f0: 05 DW_LNS_set_column (0)
+0x000004f2: 06 DW_LNS_negate_stmt
+0x000004f3: 03 DW_LNS_advance_line (0)
+0x000004f6: 74 address += 7,  line += 0
+            0x00000000000005c6      0      0      1   0             0 
+
+0x000004f7: 05 DW_LNS_set_column (7)
+0x000004f9: 03 DW_LNS_advance_line (118)
+0x000004fc: 4a address += 4,  line += 0
+            0x00000000000005ca    118      7      1   0             0 
+
+0x000004fd: 05 DW_LNS_set_column (16)
+0x000004ff: 06 DW_LNS_negate_stmt
+0x00000500: 6a address += 6,  line += 4
+            0x00000000000005d0    122     16      1   0             0  is_stmt
+
+0x00000501: 05 DW_LNS_set_column (14)
+0x00000503: 06 DW_LNS_negate_stmt
+0x00000504: 58 address += 5,  line += 0
+            0x00000000000005d5    122     14      1   0             0 
+
+0x00000505: 03 DW_LNS_advance_line (0)
+0x00000508: 2e address += 2,  line += 0
+            0x00000000000005d7      0     14      1   0             0 
+
+0x00000509: 05 DW_LNS_set_column (22)
+0x0000050b: 06 DW_LNS_negate_stmt
+0x0000050c: 03 DW_LNS_advance_line (125)
+0x0000050f: 74 address += 7,  line += 0
+            0x00000000000005de    125     22      1   0             0  is_stmt
+
+0x00000510: 06 DW_LNS_negate_stmt
+0x00000511: 03 DW_LNS_advance_line (0)
+0x00000514: 90 address += 9,  line += 0
+            0x00000000000005e7      0     22      1   0             0 
+
+0x00000515: 05 DW_LNS_set_column (27)
+0x00000517: 06 DW_LNS_negate_stmt
+0x00000518: 03 DW_LNS_advance_line (126)
+0x0000051b: 66 address += 6,  line += 0
+            0x00000000000005ed    126     27      1   0             0  is_stmt
+
+0x0000051c: 05 DW_LNS_set_column (13)
+0x0000051e: 06 DW_LNS_negate_stmt
+0x0000051f: 58 address += 5,  line += 0
+            0x00000000000005f2    126     13      1   0             0 
+
+0x00000520: 03 DW_LNS_advance_line (0)
+0x00000523: 2e address += 2,  line += 0
+            0x00000000000005f4      0     13      1   0             0 
+
+0x00000524: 05 DW_LNS_set_column (16)
+0x00000526: 06 DW_LNS_negate_stmt
+0x00000527: 03 DW_LNS_advance_line (127)
+0x0000052a: 2e address += 2,  line += 0
+            0x00000000000005f6    127     16      1   0             0  is_stmt
+
+0x0000052b: 05 DW_LNS_set_column (27)
+0x0000052d: 06 DW_LNS_negate_stmt
+0x0000052e: 82 address += 8,  line += 0
+            0x00000000000005fe    127     27      1   0             0 
+
+0x0000052f: 05 DW_LNS_set_column (35)
+0x00000531: 2e address += 2,  line += 0
+            0x0000000000000600    127     35      1   0             0 
+
+0x00000532: 05 DW_LNS_set_column (27)
+0x00000534: 90 address += 9,  line += 0
+            0x0000000000000609    127     27      1   0             0 
+
+0x00000535: 05 DW_LNS_set_column (25)
+0x00000537: 58 address += 5,  line += 0
+            0x000000000000060e    127     25      1   0             0 
+
+0x00000538: 05 DW_LNS_set_column (27)
+0x0000053a: 06 DW_LNS_negate_stmt
+0x0000053b: 3b address += 3,  line += -1
+            0x0000000000000611    126     27      1   0             0  is_stmt
+
+0x0000053c: 05 DW_LNS_set_column (13)
+0x0000053e: 06 DW_LNS_negate_stmt
+0x0000053f: 58 address += 5,  line += 0
+            0x0000000000000616    126     13      1   0             0 
+
+0x00000540: 05 DW_LNS_set_column (0)
+0x00000542: 03 DW_LNS_advance_line (0)
+0x00000545: 3c address += 3,  line += 0
+            0x0000000000000619      0      0      1   0             0 
+
+0x00000546: 05 DW_LNS_set_column (13)
+0x00000548: 06 DW_LNS_negate_stmt
+0x00000549: 03 DW_LNS_advance_line (128)
+0x0000054c: 58 address += 5,  line += 0
+            0x000000000000061e    128     13      1   0             0  is_stmt
+
+0x0000054d: 05 DW_LNS_set_column (22)
+0x0000054f: 06 DW_LNS_negate_stmt
+0x00000550: 82 address += 8,  line += 0
+            0x0000000000000626    128     22      1   0             0 
+
+0x00000551: 05 DW_LNS_set_column (16)
+0x00000553: 06 DW_LNS_negate_stmt
+0x00000554: 5a address += 5,  line += 2
+            0x000000000000062b    130     16      1   0             0  is_stmt
+
+0x00000555: 05 DW_LNS_set_column (14)
+0x00000557: 06 DW_LNS_negate_stmt
+0x00000558: 82 address += 8,  line += 0
+            0x0000000000000633    130     14      1   0             0 
+
+0x00000559: 05 DW_LNS_set_column (25)
+0x0000055b: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x0000055c: 12 address += 0,  line += 0
+            0x0000000000000644    130     25      1   0             0 
+
+0x0000055d: 05 DW_LNS_set_column (14)
+0x0000055f: 58 address += 5,  line += 0
+            0x0000000000000649    130     14      1   0             0 
+
+0x00000560: 05 DW_LNS_set_column (11)
+0x00000562: 06 DW_LNS_negate_stmt
+0x00000563: 31 address += 2,  line += 3
+            0x000000000000064b    133     11      1   0             0  is_stmt
+
+0x00000564: 05 DW_LNS_set_column (16)
+0x00000566: 03 DW_LNS_advance_line (122)
+0x00000568: 58 address += 5,  line += 0
+            0x0000000000000650    122     16      1   0             0  is_stmt
+
+0x00000569: 05 DW_LNS_set_column (14)
+0x0000056b: 06 DW_LNS_negate_stmt
+0x0000056c: 58 address += 5,  line += 0
+            0x0000000000000655    122     14      1   0             0 
+
+0x0000056d: 03 DW_LNS_advance_line (0)
+0x00000570: 4a address += 4,  line += 0
+            0x0000000000000659      0     14      1   0             0 
+
+0x00000571: 06 DW_LNS_negate_stmt
+0x00000572: 03 DW_LNS_advance_line (130)
+0x00000575: 20 address += 1,  line += 0
+            0x000000000000065a    130     14      1   0             0  is_stmt
+
+0x00000576: 05 DW_LNS_set_column (11)
+0x00000578: 03 DW_LNS_advance_line (110)
+0x0000057a: 20 address += 1,  line += 0
+            0x000000000000065b    110     11      1   0             0  is_stmt
+
+0x0000057b: 05 DW_LNS_set_column (4)
+0x0000057d: 03 DW_LNS_advance_line (138)
+0x0000057f: 66 address += 6,  line += 0
+            0x0000000000000661    138      4      1   0             0  is_stmt
+
+0x00000580: 83 address += 8,  line += 1
+            0x0000000000000669    139      4      1   0             0  is_stmt
+
+0x00000581: 06 DW_LNS_negate_stmt
+0x00000582: 03 DW_LNS_advance_line (0)
+0x00000585: 82 address += 8,  line += 0
+            0x0000000000000671      0      4      1   0             0 
+
+0x00000586: 06 DW_LNS_negate_stmt
+0x00000587: 03 DW_LNS_advance_line (141)
+0x0000058a: 82 address += 8,  line += 0
+            0x0000000000000679    141      4      1   0             0  is_stmt
+
+0x0000058b: 06 DW_LNS_negate_stmt
+0x0000058c: 03 DW_LNS_advance_line (0)
+0x0000058f: 74 address += 7,  line += 0
+            0x0000000000000680      0      4      1   0             0 
+
+0x00000590: 05 DW_LNS_set_column (20)
+0x00000592: 06 DW_LNS_negate_stmt
+0x00000593: 03 DW_LNS_advance_line (142)
+0x00000596: 4a address += 4,  line += 0
+            0x0000000000000684    142     20      1   0             0  is_stmt
+
+0x00000597: be address += 12,  line += 4
+            0x0000000000000690    146     20      1   0             0  is_stmt
+
+0x00000598: 05 DW_LNS_set_column (7)
+0x0000059a: 75 address += 7,  line += 1
+            0x0000000000000697    147      7      1   0             0  is_stmt
+
+0x0000059b: 05 DW_LNS_set_column (11)
+0x0000059d: 7e address += 8,  line += -4
+            0x000000000000069f    143     11      1   0             0  is_stmt
+
+0x0000059e: 05 DW_LNS_set_column (20)
+0x000005a0: 06 DW_LNS_negate_stmt
+0x000005a1: 4a address += 4,  line += 0
+            0x00000000000006a3    143     20      1   0             0 
+
+0x000005a2: 05 DW_LNS_set_column (11)
+0x000005a4: 58 address += 5,  line += 0
+            0x00000000000006a8    143     11      1   0             0 
+
+0x000005a5: 03 DW_LNS_advance_line (0)
+0x000005a8: 3c address += 3,  line += 0
+            0x00000000000006ab      0     11      1   0             0 
+
+0x000005a9: 05 DW_LNS_set_column (4)
+0x000005ab: 06 DW_LNS_negate_stmt
+0x000005ac: 03 DW_LNS_advance_line (141)
+0x000005af: 4a address += 4,  line += 0
+            0x00000000000006af    141      4      1   0             0  is_stmt
+
+0x000005b0: 03 DW_LNS_advance_line (159)
+0x000005b2: 66 address += 6,  line += 0
+            0x00000000000006b5    159      4      1   0             0  is_stmt
+
+0x000005b3: 06 DW_LNS_negate_stmt
+0x000005b4: 03 DW_LNS_advance_line (0)
+0x000005b7: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x000005b8: ba address += 12,  line += 0
+            0x00000000000006d2      0      4      1   0             0 
+
+0x000005b9: 05 DW_LNS_set_column (1)
+0x000005bb: 06 DW_LNS_negate_stmt
+0x000005bc: 03 DW_LNS_advance_line (161)
+0x000005bf: 20 address += 1,  line += 0
+            0x00000000000006d3    161      1      1   0             0  is_stmt
+
+0x000005c0: 02 DW_LNS_advance_pc (14)
+0x000005c2: 00 DW_LNE_end_sequence
+            0x00000000000006e1    161      1      1   0             0  is_stmt end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)"
+0x00000069: "/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp"
+0x000000a9: "/usr/local/google/home/azakai/Dev/2-binaryen"
+0x000000d6: "i"
+0x000000d8: "int"
+0x000000dc: "n"
+0x000000de: "next"
+0x000000e3: "worker_args"
+0x000000ef: "std"
+0x000000f3: "decltype(nullptr)"
+0x00000105: "nullptr_t"
+0x0000010f: "free"
+0x00000114: "_ZL8fannkuchi"
+0x00000122: "fannkuch"
+0x0000012b: "showmax"
+0x00000133: "args"
+0x00000138: "targs"
+0x0000013e: "perm1"
+0x00000144: "count"
+0x0000014a: "r"
+0x0000014c: "maxflips"
+0x00000155: "flips"
+0x0000015b: "cleanup"
+0x00000163: "p0"
+0x00000166: "_Z15fannkuch_workerPv"
+0x0000017c: "fannkuch_worker"
+0x0000018c: "main"
+0x00000191: "_arg"
+0x00000196: "perm"
+0x0000019b: "k"
+0x0000019d: "j"
+0x0000019f: "tmp"
+0x000001a3: "argc"
+0x000001a8: "argv"
+0x000001ad: "char"
+
+.debug_ranges contents:
+00000000 00000185 000001c3
+00000000 000001ed 000001f6
+00000000 0000030e 0000034c
+00000000 00000376 0000037f
+00000000 <End of list>
+00000028 00000517 0000055e
+00000028 000005de 0000062b
+00000028 <End of list>
+00000040 00000006 0000039d
+00000040 0000039f 000006e1
+00000040 <End of list>
+DWARF debug info
+================
+
+Contains section .debug_info (851 bytes)
+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_str (434 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[2] DW_TAG_pointer_type	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[3] DW_TAG_structure_type	DW_CHILDREN_yes
+	DW_AT_calling_convention	DW_FORM_data1
+	DW_AT_name	DW_FORM_strp
+	DW_AT_byte_size	DW_FORM_data1
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[4] DW_TAG_member	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_data_member_location	DW_FORM_data1
+
+[5] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+[6] DW_TAG_namespace	DW_CHILDREN_yes
+	DW_AT_name	DW_FORM_strp
+
+[7] DW_TAG_typedef	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[8] DW_TAG_unspecified_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+
+[9] DW_TAG_imported_declaration	DW_CHILDREN_no
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_import	DW_FORM_ref4
+
+[10] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[11] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[12] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[13] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[14] DW_TAG_lexical_block	DW_CHILDREN_yes
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[15] DW_TAG_GNU_call_site	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+
+[16] DW_TAG_GNU_call_site	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+	DW_AT_low_pc	DW_FORM_addr
+
+[17] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_declaration	DW_FORM_flag_present
+	DW_AT_external	DW_FORM_flag_present
+
+[18] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[19] DW_TAG_pointer_type	DW_CHILDREN_no
+
+[20] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_inline	DW_FORM_data1
+
+[21] DW_TAG_label	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+
+[22] DW_TAG_lexical_block	DW_CHILDREN_yes
+
+[23] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[24] DW_TAG_inlined_subroutine	DW_CHILDREN_yes
+	DW_AT_abstract_origin	DW_FORM_ref4
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_call_file	DW_FORM_data1
+	DW_AT_call_line	DW_FORM_data1
+	DW_AT_call_column	DW_FORM_data1
+
+[25] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[26] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[27] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[28] DW_TAG_label	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+	DW_AT_low_pc	DW_FORM_addr
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x0000034f version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x00000353)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000069] = "/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x000000a9] = "/usr/local/google/home/azakai/Dev/2-binaryen")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+              DW_AT_ranges [DW_FORM_sec_offset]	(0x00000040
+                 [0x00000007, 0x0000038a)
+                 [0x0000038c, 0x00000673))
+
+0x00000026:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x002b => {0x0000002b} "worker_args")
+
+0x0000002b:   DW_TAG_structure_type [3] *
+                DW_AT_calling_convention [DW_FORM_data1]	(DW_CC_pass_by_value)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000e3] = "worker_args")
+                DW_AT_byte_size [DW_FORM_data1]	(0x0c)
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(20)
+
+0x00000034:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d6] = "i")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(21)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x00)
+
+0x00000040:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(21)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x04)
+
+0x0000004c:     DW_TAG_member [4]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000de] = "next")
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(22)
+                  DW_AT_data_member_location [DW_FORM_data1]	(0x08)
+
+0x00000058:     NULL
+
+0x00000059:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d8] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x00000060:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000065:   DW_TAG_namespace [6] *
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ef] = "std")
+
+0x0000006a:     DW_TAG_typedef [7]  
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0076 => {0x00000076} "decltype(nullptr)")
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000105] = "nullptr_t")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/system/include/libcxx/__nullptr")
+                  DW_AT_decl_line [DW_FORM_data1]	(57)
+
+0x00000075:     NULL
+
+0x00000076:   DW_TAG_unspecified_type [8]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000f3] = "decltype(nullptr)")
+
+0x0000007b:   DW_TAG_imported_declaration [9]  
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/system/include/libcxx/stddef.h")
+                DW_AT_decl_line [DW_FORM_data1]	(52)
+                DW_AT_import [DW_FORM_ref4]	(cu + 0x006a => {0x0000006a})
+
+0x00000082:   DW_TAG_subprogram [10] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000007)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000383)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x1 +0, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x00000166] = "_Z15fannkuch_workerPv")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000017c] = "fannkuch_worker")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(26)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000009e:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000191] = "_arg")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(26)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x01a7 => {0x000001a7} "*")
+
+0x000000a9:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000133] = "args")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(28)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000000b4:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000000: 
+                     [0xffffffff,  0x00000007): 
+                     [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014c] = "maxflips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000c3:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000001d: 
+                     [0xffffffff,  0x00000028): 
+                     [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+                     [0x0000003d,  0x00000042): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x00000001,  0x00000001): DW_OP_consts +1, DW_OP_stack_value
+                     [0x00000110,  0x0000011a): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                     [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+                     [0x0000023d,  0x00000248): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000001,  0x00000001): DW_OP_consts +1, DW_OP_stack_value
+                     [0x00000291,  0x0000029b): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                     [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d6] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000d2:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000a5: 
+                     [0xffffffff,  0x0000002f): 
+                     [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000000e1:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000c3: 
+                     [0xffffffff,  0x00000038): 
+                     [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000013e] = "perm1")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000000f0:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000e1: 
+                     [0xffffffff,  0x0000003e): 
+                     [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000196] = "perm")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000000ff:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000000ff: 
+                     [0xffffffff,  0x00000044): 
+                     [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000144] = "count")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(29)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x0000010e:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000011d: 
+                     [0xffffffff,  0x000001e7): 
+                     [0x00000000,  0x00000005): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+                     [0x00000181,  0x00000186): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014a] = "r")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000011d:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000149: 
+                     [0xffffffff,  0x000000dc): 
+                     [0x00000000,  0x00000013): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +13, DW_OP_stack_value
+                     [0x00000085,  0x0000008d): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                     [0x00000189,  0x00000194): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +10, DW_OP_stack_value
+                     [0x00000206,  0x0000020e): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000155] = "flips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000012c:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000001ab: 
+                     [0xffffffff,  0x000000eb): 
+                     [0x00000000,  0x00000004): DW_OP_WASM_location 0x0 +12, DW_OP_stack_value
+                     [0x00000181,  0x00000185): DW_OP_WASM_location 0x0 +16, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000019b] = "k")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000013b:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x000001d7: 
+                     [0xffffffff,  0x00000103): 
+                     [0x00000000,  0x00000004): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x0000003c,  0x0000003f): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x00000181,  0x00000185): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x000001bd,  0x000001c0): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000019d] = "j")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000014a:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000021f: 
+                     [0xffffffff,  0x00000118): 
+                     [0x00000000,  0x0000002a): DW_OP_WASM_location 0x0 +15, DW_OP_stack_value
+                     [0x0000003b,  0x00000051): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+                     [0x00000181,  0x000001ab): DW_OP_WASM_location 0x0 +14, DW_OP_stack_value
+                     [0x000001bc,  0x000001d2): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000019f] = "tmp")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(30)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000159:     DW_TAG_lexical_block [14] *
+                  DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
+                     [0x00000184, 0x000001c2)
+                     [0x000001ec, 0x000001f5)
+                     [0x00000305, 0x00000343)
+                     [0x0000036d, 0x00000376))
+
+0x0000015e:       DW_TAG_variable [12]  
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000163] = "p0")
+                    DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                    DW_AT_decl_line [DW_FORM_data1]	(74)
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000169:       NULL
+
+0x0000016a:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000036)
+
+0x0000016f:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000003c)
+
+0x00000174:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000042)
+
+0x00000179:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000000e4)
+
+0x0000017e:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000037f)
+
+0x00000187:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000383)
+
+0x00000190:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000387)
+
+0x00000199:     NULL
+
+0x0000019a:   DW_TAG_subprogram [17] *
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000010f] = "free")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/system/include/libc/stdlib.h")
+                DW_AT_decl_line [DW_FORM_data1]	(41)
+                DW_AT_declaration [DW_FORM_flag_present]	(true)
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x000001a1:     DW_TAG_formal_parameter [18]  
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x01a7 => {0x000001a7} "*")
+
+0x000001a6:     NULL
+
+0x000001a7:   DW_TAG_pointer_type [19]  
+
+0x000001a8:   DW_TAG_subprogram [20] *
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x00000114] = "_ZL8fannkuchi")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000122] = "fannkuch")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(87)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_inline [DW_FORM_data1]	(DW_INL_inlined)
+
+0x000001b8:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(87)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001c3:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000012b] = "showmax")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(90)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001ce:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000133] = "args")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(89)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000001d9:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d6] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x000001e4:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000138] = "targs")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(89)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0026 => {0x00000026} "worker_args*")
+
+0x000001ef:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000013e] = "perm1")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x000001fa:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000144] = "count")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0060 => {0x00000060} "int*")
+
+0x00000205:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014a] = "r")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000210:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000014c] = "maxflips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000021b:     DW_TAG_variable [12]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000155] = "flips")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(91)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000226:     DW_TAG_label [21]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000015b] = "cleanup")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(137)
+
+0x0000022d:     DW_TAG_lexical_block [22] *
+
+0x0000022e:       DW_TAG_variable [12]  
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000163] = "p0")
+                    DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                    DW_AT_decl_line [DW_FORM_data1]	(125)
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000239:       NULL
+
+0x0000023a:     NULL
+
+0x0000023b:   DW_TAG_subprogram [23] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x000000000000038c)
+                DW_AT_high_pc [DW_FORM_data4]	(0x000002e7)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x0 +2, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000018c] = "main")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(152)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000253:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000001a3] = "argc")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(152)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x0000025e:     DW_TAG_formal_parameter [11]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000001a8] = "argv")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(152)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0341 => {0x00000341} "char**")
+
+0x00000269:     DW_TAG_variable [13]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000267: 
+                     [0xffffffff,  0x000003b8): 
+                     [0x00000000,  0x00000005): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dc] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(153)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0059 => {0x00000059} "int")
+
+0x00000278:     DW_TAG_inlined_subroutine [24] *
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01a8 => {0x000001a8} "_ZL8fannkuchi")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000003cb)
+                  DW_AT_high_pc [DW_FORM_data4]	(0xfffffc35)
+                  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)
+
+0x00000288:       DW_TAG_formal_parameter [25]  
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01b8 => {0x000001b8} "n")
+
+0x0000028d:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000285: 
+                       [0xffffffff,  0x00000000): 
+                       [0x00000001,  0x00000001): DW_OP_consts +30, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01c3 => {0x000001c3} "showmax")
+
+0x00000296:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x000002a2: 
+                       [0xffffffff,  0x00000638): 
+                       [0x00000001,  0x00000001): DW_OP_lit0, DW_OP_stack_value
+                       [0x00000000,  0x00000018): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01ce => {0x000001ce} "args")
+
+0x0000029f:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x000002cc: 
+                       [0xffffffff,  0x00000407): 
+                       [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+                       [0x00000000,  0x00000005): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                       [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+                       [0x0000003f,  0x00000044): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                       [0x0000005d,  0x00000061): DW_OP_consts +0, DW_OP_stack_value
+                       [0x00000088,  0x0000008d): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+                       [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+                       [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+                       [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01d9 => {0x000001d9} "i")
+
+0x000002a8:       DW_TAG_variable [27]  
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01e4 => {0x000001e4} "targs")
+
+0x000002ad:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000354: 
+                       [0xffffffff,  0x0000041d): 
+                       [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01ef => {0x000001ef} "perm1")
+
+0x000002b6:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000372: 
+                       [0xffffffff,  0x00000423): 
+                       [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01fa => {0x000001fa} "count")
+
+0x000002bf:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000390: 
+                       [0xffffffff,  0x00000544): 
+                       [0x00000000,  0x00000007): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+                       [0x000000c2,  0x000000c9): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x0205 => {0x00000205} "r")
+
+0x000002c8:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x000003e8: 
+                       [0xffffffff,  0x00000621): 
+                       [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+                       [0x00000027,  0x0000002f): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x0210 => {0x00000210} "maxflips")
+
+0x000002d1:       DW_TAG_variable [26]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000413: 
+                       [0xffffffff,  0x00000631): 
+                       [0x00000000,  0x0000001f): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x021b => {0x0000021b} "flips")
+
+0x000002da:       DW_TAG_label [28]  
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x0226 => {0x00000226} "cleanup")
+                    DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000615)
+
+0x000002e3:       DW_TAG_lexical_block [14] *
+                    DW_AT_ranges [DW_FORM_sec_offset]	(0x00000028
+                       [0x000004da, 0x0000051f)
+                       [0x00000596, 0x000005e1))
+
+0x000002e8:         DW_TAG_variable [26]  
+                      DW_AT_location [DW_FORM_sec_offset]	(0x000003bc: 
+                         [0xffffffff,  0x0000059f): 
+                         [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value
+                         [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value)
+                      DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x022e => {0x0000022e} "p0")
+
+0x000002f1:         NULL
+
+0x000002f2:       NULL
+
+0x000002f3:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000003b6)
+
+0x000002f8:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000003c3)
+
+0x000002fd:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x00000000000003e7)
+
+0x00000302:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000041b)
+
+0x00000307:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000421)
+
+0x0000030c:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000487)
+
+0x00000311:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000499)
+
+0x00000316:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000055b)
+
+0x0000031b:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000619)
+
+0x00000324:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000061d)
+
+0x0000032d:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000062f)
+
+0x00000332:     DW_TAG_GNU_call_site [16]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x019a => {0x0000019a} "free")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000063c)
+
+0x0000033b:     DW_TAG_GNU_call_site [15]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000667)
+
+0x00000340:     NULL
+
+0x00000341:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0346 => {0x00000346} "char*")
+
+0x00000346:   DW_TAG_pointer_type [2]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x034b => {0x0000034b} "char")
+
+0x0000034b:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000001ad] = "char")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed_char)
+                DW_AT_byte_size [DW_FORM_data1]	(0x01)
+
+0x00000352:   NULL
+
+.debug_loc contents:
+0x00000000: 
+            [0xffffffff,  0x00000007): 
+            [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+
+0x0000001d: 
+            [0xffffffff,  0x00000028): 
+            [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000003d,  0x00000042): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x00000001,  0x00000001): DW_OP_consts +1, DW_OP_stack_value
+            [0x00000110,  0x0000011a): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000023d,  0x00000248): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000001,  0x00000001): DW_OP_consts +1, DW_OP_stack_value
+            [0x00000291,  0x0000029b): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+
+0x000000a5: 
+            [0xffffffff,  0x0000002f): 
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+
+0x000000c3: 
+            [0xffffffff,  0x00000038): 
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+
+0x000000e1: 
+            [0xffffffff,  0x0000003e): 
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value
+
+0x000000ff: 
+            [0xffffffff,  0x00000044): 
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+
+0x0000011d: 
+            [0xffffffff,  0x000001e7): 
+            [0x00000000,  0x00000005): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+            [0x00000181,  0x00000186): DW_OP_WASM_location 0x0 +2, DW_OP_stack_value
+
+0x00000149: 
+            [0xffffffff,  0x000000dc): 
+            [0x00000000,  0x00000013): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +13, DW_OP_stack_value
+            [0x00000085,  0x0000008d): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000189,  0x00000194): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +10, DW_OP_stack_value
+            [0x00000206,  0x0000020e): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+
+0x000001ab: 
+            [0xffffffff,  0x000000eb): 
+            [0x00000000,  0x00000004): DW_OP_WASM_location 0x0 +12, DW_OP_stack_value
+            [0x00000181,  0x00000185): DW_OP_WASM_location 0x0 +16, DW_OP_stack_value
+
+0x000001d7: 
+            [0xffffffff,  0x00000103): 
+            [0x00000000,  0x00000004): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x0000003c,  0x0000003f): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x00000181,  0x00000185): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x000001bd,  0x000001c0): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x0000021f: 
+            [0xffffffff,  0x00000118): 
+            [0x00000000,  0x0000002a): DW_OP_WASM_location 0x0 +15, DW_OP_stack_value
+            [0x0000003b,  0x00000051): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+            [0x00000181,  0x000001ab): DW_OP_WASM_location 0x0 +14, DW_OP_stack_value
+            [0x000001bc,  0x000001d2): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000267: 
+            [0xffffffff,  0x000003b8): 
+            [0x00000000,  0x00000005): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+
+0x00000285: 
+            [0xffffffff,  0x00000000): 
+            [0x00000001,  0x00000001): DW_OP_consts +30, DW_OP_stack_value
+
+0x000002a2: 
+            [0xffffffff,  0x00000638): 
+            [0x00000001,  0x00000001): DW_OP_lit0, DW_OP_stack_value
+            [0x00000000,  0x00000018): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+
+0x000002cc: 
+            [0xffffffff,  0x00000407): 
+            [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000000,  0x00000005): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000003f,  0x00000044): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x0000005d,  0x00000061): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000088,  0x0000008d): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+            [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+
+0x00000354: 
+            [0xffffffff,  0x0000041d): 
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000372: 
+            [0xffffffff,  0x00000423): 
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +5, DW_OP_stack_value
+
+0x00000390: 
+            [0xffffffff,  0x00000544): 
+            [0x00000000,  0x00000007): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+            [0x000000c2,  0x000000c9): DW_OP_WASM_location 0x0 +6, DW_OP_stack_value
+
+0x000003bc: 
+            [0xffffffff,  0x0000059f): 
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x0 +8, DW_OP_stack_value
+
+0x000003e8: 
+            [0xffffffff,  0x00000621): 
+            [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000027,  0x0000002f): DW_OP_WASM_location 0x0 +0, DW_OP_stack_value
+
+0x00000413: 
+            [0xffffffff,  0x00000631): 
+            [0x00000000,  0x0000001f): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x00000a8a
+         version: 4
+ prologue_length: 0x000000dd
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+include_directories[  1] = "/usr/local/google/home/azakai/Dev"
+file_names[  1]:
+           name: "emscripten/tests/fannkuch.cpp"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  2]:
+           name: "emscripten/system/include/libcxx/__nullptr"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  3]:
+           name: "emscripten/system/include/libcxx/stddef.h"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+file_names[  4]:
+           name: "emscripten/system/include/libc/stdlib.h"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+0x000000e7: 00 DW_LNE_set_address (0x0000000000000007)
+0x000000ee: 03 DW_LNS_advance_line (27)
+0x000000f0: 01 DW_LNS_copy
+            0x0000000000000007     27      0      1   0             0  is_stmt
+
+
+0x000000f1: 00 DW_LNE_set_address (0x0000000000000028)
+0x000000f8: 03 DW_LNS_advance_line (33)
+0x000000fa: 05 DW_LNS_set_column (14)
+0x000000fc: 0a DW_LNS_set_prologue_end
+0x000000fd: 01 DW_LNS_copy
+            0x0000000000000028     33     14      1   0             0  is_stmt prologue_end
+
+
+0x000000fe: 00 DW_LNE_set_address (0x0000000000000031)
+0x00000105: 03 DW_LNS_advance_line (34)
+0x00000107: 05 DW_LNS_set_column (27)
+0x00000109: 01 DW_LNS_copy
+            0x0000000000000031     34     27      1   0             0  is_stmt
+
+
+0x0000010a: 00 DW_LNE_set_address (0x0000000000000032)
+0x00000111: 05 DW_LNS_set_column (18)
+0x00000113: 06 DW_LNS_negate_stmt
+0x00000114: 01 DW_LNS_copy
+            0x0000000000000032     34     18      1   0             0 
+
+
+0x00000115: 00 DW_LNE_set_address (0x0000000000000038)
+0x0000011c: 03 DW_LNS_advance_line (35)
+0x0000011e: 05 DW_LNS_set_column (17)
+0x00000120: 06 DW_LNS_negate_stmt
+0x00000121: 01 DW_LNS_copy
+            0x0000000000000038     35     17      1   0             0  is_stmt
+
+
+0x00000122: 00 DW_LNE_set_address (0x000000000000003e)
+0x00000129: 03 DW_LNS_advance_line (36)
+0x0000012b: 05 DW_LNS_set_column (18)
+0x0000012d: 01 DW_LNS_copy
+            0x000000000000003e     36     18      1   0             0  is_stmt
+
+
+0x0000012e: 00 DW_LNE_set_address (0x0000000000000048)
+0x00000135: 03 DW_LNS_advance_line (37)
+0x00000137: 01 DW_LNS_copy
+            0x0000000000000048     37     18      1   0             0  is_stmt
+
+
+0x00000138: 00 DW_LNE_set_address (0x0000000000000051)
+0x0000013f: 03 DW_LNS_advance_line (38)
+0x00000141: 05 DW_LNS_set_column (7)
+0x00000143: 01 DW_LNS_copy
+            0x0000000000000051     38      7      1   0             0  is_stmt
+
+
+0x00000144: 00 DW_LNE_set_address (0x0000000000000059)
+0x0000014b: 05 DW_LNS_set_column (16)
+0x0000014d: 06 DW_LNS_negate_stmt
+0x0000014e: 01 DW_LNS_copy
+            0x0000000000000059     38     16      1   0             0 
+
+
+0x0000014f: 00 DW_LNE_set_address (0x000000000000005e)
+0x00000156: 03 DW_LNS_advance_line (37)
+0x00000158: 05 DW_LNS_set_column (24)
+0x0000015a: 06 DW_LNS_negate_stmt
+0x0000015b: 01 DW_LNS_copy
+            0x000000000000005e     37     24      1   0             0  is_stmt
+
+
+0x0000015c: 00 DW_LNE_set_address (0x0000000000000063)
+0x00000163: 05 DW_LNS_set_column (18)
+0x00000165: 06 DW_LNS_negate_stmt
+0x00000166: 01 DW_LNS_copy
+            0x0000000000000063     37     18      1   0             0 
+
+
+0x00000167: 00 DW_LNE_set_address (0x0000000000000068)
+0x0000016e: 05 DW_LNS_set_column (4)
+0x00000170: 01 DW_LNS_copy
+            0x0000000000000068     37      4      1   0             0 
+
+
+0x00000171: 00 DW_LNE_set_address (0x000000000000006b)
+0x00000178: 03 DW_LNS_advance_line (39)
+0x0000017a: 06 DW_LNS_negate_stmt
+0x0000017b: 01 DW_LNS_copy
+            0x000000000000006b     39      4      1   0             0  is_stmt
+
+
+0x0000017c: 00 DW_LNE_set_address (0x000000000000006d)
+0x00000183: 05 DW_LNS_set_column (16)
+0x00000185: 06 DW_LNS_negate_stmt
+0x00000186: 01 DW_LNS_copy
+            0x000000000000006d     39     16      1   0             0 
+
+
+0x00000187: 00 DW_LNE_set_address (0x0000000000000076)
+0x0000018e: 05 DW_LNS_set_column (4)
+0x00000190: 01 DW_LNS_copy
+            0x0000000000000076     39      4      1   0             0 
+
+
+0x00000191: 00 DW_LNE_set_address (0x0000000000000078)
+0x00000198: 05 DW_LNS_set_column (23)
+0x0000019a: 01 DW_LNS_copy
+            0x0000000000000078     39     23      1   0             0 
+
+
+0x0000019b: 00 DW_LNE_set_address (0x000000000000007d)
+0x000001a2: 05 DW_LNS_set_column (19)
+0x000001a4: 01 DW_LNS_copy
+            0x000000000000007d     39     19      1   0             0 
+
+
+0x000001a5: 00 DW_LNE_set_address (0x0000000000000082)
+0x000001ac: 03 DW_LNS_advance_line (40)
+0x000001ae: 05 DW_LNS_set_column (4)
+0x000001b0: 06 DW_LNS_negate_stmt
+0x000001b1: 01 DW_LNS_copy
+            0x0000000000000082     40      4      1   0             0  is_stmt
+
+
+0x000001b2: 00 DW_LNE_set_address (0x000000000000008a)
+0x000001b9: 05 DW_LNS_set_column (17)
+0x000001bb: 06 DW_LNS_negate_stmt
+0x000001bc: 01 DW_LNS_copy
+            0x000000000000008a     40     17      1   0             0 
+
+
+0x000001bd: 00 DW_LNE_set_address (0x0000000000000091)
+0x000001c4: 03 DW_LNS_advance_line (37)
+0x000001c6: 05 DW_LNS_set_column (18)
+0x000001c8: 06 DW_LNS_negate_stmt
+0x000001c9: 01 DW_LNS_copy
+            0x0000000000000091     37     18      1   0             0  is_stmt
+
+
+0x000001ca: 00 DW_LNE_set_address (0x0000000000000096)
+0x000001d1: 03 DW_LNS_advance_line (43)
+0x000001d3: 05 DW_LNS_set_column (4)
+0x000001d5: 01 DW_LNS_copy
+            0x0000000000000096     43      4      1   0             0  is_stmt
+
+
+0x000001d6: 00 DW_LNE_set_address (0x000000000000009a)
+0x000001dd: 03 DW_LNS_advance_line (44)
+0x000001df: 05 DW_LNS_set_column (16)
+0x000001e1: 01 DW_LNS_copy
+            0x000000000000009a     44     16      1   0             0  is_stmt
+
+
+0x000001e2: 00 DW_LNE_set_address (0x00000000000000a3)
+0x000001e9: 03 DW_LNS_advance_line (45)
+0x000001eb: 05 DW_LNS_set_column (10)
+0x000001ed: 01 DW_LNS_copy
+            0x00000000000000a3     45     10      1   0             0  is_stmt
+
+
+0x000001ee: 00 DW_LNE_set_address (0x00000000000000a5)
+0x000001f5: 05 DW_LNS_set_column (18)
+0x000001f7: 06 DW_LNS_negate_stmt
+0x000001f8: 01 DW_LNS_copy
+            0x00000000000000a5     45     18      1   0             0 
+
+
+0x000001f9: 00 DW_LNE_set_address (0x00000000000000ae)
+0x00000200: 05 DW_LNS_set_column (10)
+0x00000202: 01 DW_LNS_copy
+            0x00000000000000ae     45     10      1   0             0 
+
+
+0x00000203: 00 DW_LNE_set_address (0x00000000000000b0)
+0x0000020a: 05 DW_LNS_set_column (23)
+0x0000020c: 01 DW_LNS_copy
+            0x00000000000000b0     45     23      1   0             0 
+
+
+0x0000020d: 00 DW_LNE_set_address (0x00000000000000b5)
+0x00000214: 03 DW_LNS_advance_line (44)
+0x00000216: 05 DW_LNS_set_column (16)
+0x00000218: 06 DW_LNS_negate_stmt
+0x00000219: 01 DW_LNS_copy
+            0x00000000000000b5     44     16      1   0             0  is_stmt
+
+
+0x0000021a: 00 DW_LNE_set_address (0x00000000000000c0)
+0x00000221: 05 DW_LNS_set_column (7)
+0x00000223: 06 DW_LNS_negate_stmt
+0x00000224: 01 DW_LNS_copy
+            0x00000000000000c0     44      7      1   0             0 
+
+
+0x00000225: 00 DW_LNE_set_address (0x00000000000000c6)
+0x0000022c: 03 DW_LNS_advance_line (46)
+0x0000022e: 05 DW_LNS_set_column (11)
+0x00000230: 06 DW_LNS_negate_stmt
+0x00000231: 01 DW_LNS_copy
+            0x00000000000000c6     46     11      1   0             0  is_stmt
+
+
+0x00000232: 00 DW_LNE_set_address (0x00000000000000d2)
+0x00000239: 05 DW_LNS_set_column (28)
+0x0000023b: 06 DW_LNS_negate_stmt
+0x0000023c: 01 DW_LNS_copy
+            0x00000000000000d2     46     28      1   0             0 
+
+
+0x0000023d: 00 DW_LNE_set_address (0x00000000000000d7)
+0x00000244: 05 DW_LNS_set_column (41)
+0x00000246: 01 DW_LNS_copy
+            0x00000000000000d7     46     41      1   0             0 
+
+
+0x00000247: 00 DW_LNE_set_address (0x00000000000000dc)
+0x0000024e: 03 DW_LNS_advance_line (48)
+0x00000250: 05 DW_LNS_set_column (21)
+0x00000252: 06 DW_LNS_negate_stmt
+0x00000253: 01 DW_LNS_copy
+            0x00000000000000dc     48     21      1   0             0  is_stmt
+
+
+0x00000254: 00 DW_LNE_set_address (0x00000000000000e4)
+0x0000025b: 03 DW_LNS_advance_line (50)
+0x0000025d: 05 DW_LNS_set_column (14)
+0x0000025f: 01 DW_LNS_copy
+            0x00000000000000e4     50     14      1   0             0  is_stmt
+
+
+0x00000260: 00 DW_LNE_set_address (0x00000000000000f5)
+0x00000267: 03 DW_LNS_advance_line (52)
+0x00000269: 05 DW_LNS_set_column (38)
+0x0000026b: 01 DW_LNS_copy
+            0x00000000000000f5     52     38      1   0             0  is_stmt
+
+
+0x0000026c: 00 DW_LNE_set_address (0x0000000000000109)
+0x00000273: 03 DW_LNS_advance_line (53)
+0x00000275: 05 DW_LNS_set_column (22)
+0x00000277: 01 DW_LNS_copy
+            0x0000000000000109     53     22      1   0             0  is_stmt
+
+
+0x00000278: 00 DW_LNE_set_address (0x0000000000000118)
+0x0000027f: 03 DW_LNS_advance_line (54)
+0x00000281: 05 DW_LNS_set_column (24)
+0x00000283: 01 DW_LNS_copy
+            0x0000000000000118     54     24      1   0             0  is_stmt
+
+
+0x00000284: 00 DW_LNE_set_address (0x000000000000011a)
+0x0000028b: 05 DW_LNS_set_column (26)
+0x0000028d: 06 DW_LNS_negate_stmt
+0x0000028e: 01 DW_LNS_copy
+            0x000000000000011a     54     26      1   0             0 
+
+
+0x0000028f: 00 DW_LNE_set_address (0x0000000000000127)
+0x00000296: 05 DW_LNS_set_column (24)
+0x00000298: 01 DW_LNS_copy
+            0x0000000000000127     54     24      1   0             0 
+
+
+0x00000299: 00 DW_LNE_set_address (0x000000000000012a)
+0x000002a0: 03 DW_LNS_advance_line (55)
+0x000002a2: 06 DW_LNS_negate_stmt
+0x000002a3: 01 DW_LNS_copy
+            0x000000000000012a     55     24      1   0             0  is_stmt
+
+
+0x000002a4: 00 DW_LNE_set_address (0x0000000000000131)
+0x000002ab: 03 DW_LNS_advance_line (52)
+0x000002ad: 05 DW_LNS_set_column (44)
+0x000002af: 01 DW_LNS_copy
+            0x0000000000000131     52     44      1   0             0  is_stmt
+
+
+0x000002b0: 00 DW_LNE_set_address (0x000000000000013d)
+0x000002b7: 05 DW_LNS_set_column (38)
+0x000002b9: 06 DW_LNS_negate_stmt
+0x000002ba: 01 DW_LNS_copy
+            0x000000000000013d     52     38      1   0             0 
+
+
+0x000002bb: 00 DW_LNE_set_address (0x0000000000000140)
+0x000002c2: 05 DW_LNS_set_column (13)
+0x000002c4: 01 DW_LNS_copy
+            0x0000000000000140     52     13      1   0             0 
+
+
+0x000002c5: 00 DW_LNE_set_address (0x0000000000000144)
+0x000002cc: 03 DW_LNS_advance_line (58)
+0x000002ce: 05 DW_LNS_set_column (19)
+0x000002d0: 06 DW_LNS_negate_stmt
+0x000002d1: 01 DW_LNS_copy
+            0x0000000000000144     58     19      1   0             0  is_stmt
+
+
+0x000002d2: 00 DW_LNE_set_address (0x0000000000000153)
+0x000002d9: 03 DW_LNS_advance_line (59)
+0x000002db: 05 DW_LNS_set_column (21)
+0x000002dd: 01 DW_LNS_copy
+            0x0000000000000153     59     21      1   0             0  is_stmt
+
+
+0x000002de: 00 DW_LNE_set_address (0x000000000000015a)
+0x000002e5: 03 DW_LNS_advance_line (57)
+0x000002e7: 05 DW_LNS_set_column (18)
+0x000002e9: 01 DW_LNS_copy
+            0x000000000000015a     57     18      1   0             0  is_stmt
+
+
+0x000002ea: 00 DW_LNE_set_address (0x000000000000016a)
+0x000002f1: 03 DW_LNS_advance_line (62)
+0x000002f3: 05 DW_LNS_set_column (14)
+0x000002f5: 01 DW_LNS_copy
+            0x000000000000016a     62     14      1   0             0  is_stmt
+
+
+0x000002f6: 00 DW_LNE_set_address (0x000000000000016e)
+0x000002fd: 05 DW_LNS_set_column (23)
+0x000002ff: 06 DW_LNS_negate_stmt
+0x00000300: 01 DW_LNS_copy
+            0x000000000000016e     62     23      1   0             0 
+
+
+0x00000301: 00 DW_LNE_set_address (0x0000000000000173)
+0x00000308: 05 DW_LNS_set_column (14)
+0x0000030a: 01 DW_LNS_copy
+            0x0000000000000173     62     14      1   0             0 
+
+
+0x0000030b: 00 DW_LNE_set_address (0x0000000000000177)
+0x00000312: 03 DW_LNS_advance_line (66)
+0x00000314: 05 DW_LNS_set_column (16)
+0x00000316: 06 DW_LNS_negate_stmt
+0x00000317: 01 DW_LNS_copy
+            0x0000000000000177     66     16      1   0             0  is_stmt
+
+
+0x00000318: 00 DW_LNE_set_address (0x0000000000000184)
+0x0000031f: 03 DW_LNS_advance_line (75)
+0x00000321: 05 DW_LNS_set_column (27)
+0x00000323: 01 DW_LNS_copy
+            0x0000000000000184     75     27      1   0             0  is_stmt
+
+
+0x00000324: 00 DW_LNE_set_address (0x000000000000018d)
+0x0000032b: 03 DW_LNS_advance_line (76)
+0x0000032d: 05 DW_LNS_set_column (16)
+0x0000032f: 01 DW_LNS_copy
+            0x000000000000018d     76     16      1   0             0  is_stmt
+
+
+0x00000330: 00 DW_LNE_set_address (0x0000000000000195)
+0x00000337: 05 DW_LNS_set_column (27)
+0x00000339: 06 DW_LNS_negate_stmt
+0x0000033a: 01 DW_LNS_copy
+            0x0000000000000195     76     27      1   0             0 
+
+
+0x0000033b: 00 DW_LNE_set_address (0x0000000000000197)
+0x00000342: 05 DW_LNS_set_column (35)
+0x00000344: 01 DW_LNS_copy
+            0x0000000000000197     76     35      1   0             0 
+
+
+0x00000345: 00 DW_LNE_set_address (0x00000000000001a0)
+0x0000034c: 05 DW_LNS_set_column (27)
+0x0000034e: 01 DW_LNS_copy
+            0x00000000000001a0     76     27      1   0             0 
+
+
+0x0000034f: 00 DW_LNE_set_address (0x00000000000001a5)
+0x00000356: 05 DW_LNS_set_column (25)
+0x00000358: 01 DW_LNS_copy
+            0x00000000000001a5     76     25      1   0             0 
+
+
+0x00000359: 00 DW_LNE_set_address (0x00000000000001a8)
+0x00000360: 03 DW_LNS_advance_line (75)
+0x00000362: 05 DW_LNS_set_column (27)
+0x00000364: 06 DW_LNS_negate_stmt
+0x00000365: 01 DW_LNS_copy
+            0x00000000000001a8     75     27      1   0             0  is_stmt
+
+
+0x00000366: 00 DW_LNE_set_address (0x00000000000001ad)
+0x0000036d: 05 DW_LNS_set_column (13)
+0x0000036f: 06 DW_LNS_negate_stmt
+0x00000370: 01 DW_LNS_copy
+            0x00000000000001ad     75     13      1   0             0 
+
+
+0x00000371: 00 DW_LNE_set_address (0x00000000000001b5)
+0x00000378: 03 DW_LNS_advance_line (77)
+0x0000037a: 06 DW_LNS_negate_stmt
+0x0000037b: 01 DW_LNS_copy
+            0x00000000000001b5     77     13      1   0             0  is_stmt
+
+
+0x0000037c: 00 DW_LNE_set_address (0x00000000000001bd)
+0x00000383: 05 DW_LNS_set_column (22)
+0x00000385: 06 DW_LNS_negate_stmt
+0x00000386: 01 DW_LNS_copy
+            0x00000000000001bd     77     22      1   0             0 
+
+
+0x00000387: 00 DW_LNE_set_address (0x00000000000001c2)
+0x0000038e: 03 DW_LNS_advance_line (79)
+0x00000390: 05 DW_LNS_set_column (16)
+0x00000392: 06 DW_LNS_negate_stmt
+0x00000393: 01 DW_LNS_copy
+            0x00000000000001c2     79     16      1   0             0  is_stmt
+
+
+0x00000394: 00 DW_LNE_set_address (0x00000000000001ca)
+0x0000039b: 05 DW_LNS_set_column (14)
+0x0000039d: 06 DW_LNS_negate_stmt
+0x0000039e: 01 DW_LNS_copy
+            0x00000000000001ca     79     14      1   0             0 
+
+
+0x0000039f: 00 DW_LNE_set_address (0x00000000000001d9)
+0x000003a6: 05 DW_LNS_set_column (25)
+0x000003a8: 01 DW_LNS_copy
+            0x00000000000001d9     79     25      1   0             0 
+
+
+0x000003a9: 00 DW_LNE_set_address (0x00000000000001e0)
+0x000003b0: 03 DW_LNS_advance_line (81)
+0x000003b2: 05 DW_LNS_set_column (11)
+0x000003b4: 06 DW_LNS_negate_stmt
+0x000003b5: 01 DW_LNS_copy
+            0x00000000000001e0     81     11      1   0             0  is_stmt
+
+
+0x000003b6: 00 DW_LNE_set_address (0x00000000000001e5)
+0x000003bd: 03 DW_LNS_advance_line (66)
+0x000003bf: 05 DW_LNS_set_column (16)
+0x000003c1: 01 DW_LNS_copy
+            0x00000000000001e5     66     16      1   0             0  is_stmt
+
+
+0x000003c2: 00 DW_LNE_set_address (0x00000000000001ec)
+0x000003c9: 03 DW_LNS_advance_line (74)
+0x000003cb: 05 DW_LNS_set_column (22)
+0x000003cd: 01 DW_LNS_copy
+            0x00000000000001ec     74     22      1   0             0  is_stmt
+
+
+0x000003ce: 00 DW_LNE_set_address (0x00000000000001f5)
+0x000003d5: 03 DW_LNS_advance_line (37)
+0x000003d7: 05 DW_LNS_set_column (4)
+0x000003d9: 01 DW_LNS_copy
+            0x00000000000001f5     37      4      1   0             0  is_stmt
+
+
+0x000003da: 00 DW_LNE_set_address (0x00000000000001fa)
+0x000003e1: 03 DW_LNS_advance_line (39)
+0x000003e3: 01 DW_LNS_copy
+            0x00000000000001fa     39      4      1   0             0  is_stmt
+
+
+0x000003e4: 00 DW_LNE_set_address (0x00000000000001fc)
+0x000003eb: 05 DW_LNS_set_column (16)
+0x000003ed: 06 DW_LNS_negate_stmt
+0x000003ee: 01 DW_LNS_copy
+            0x00000000000001fc     39     16      1   0             0 
+
+
+0x000003ef: 00 DW_LNE_set_address (0x0000000000000205)
+0x000003f6: 05 DW_LNS_set_column (4)
+0x000003f8: 01 DW_LNS_copy
+            0x0000000000000205     39      4      1   0             0 
+
+
+0x000003f9: 00 DW_LNE_set_address (0x0000000000000207)
+0x00000400: 05 DW_LNS_set_column (23)
+0x00000402: 01 DW_LNS_copy
+            0x0000000000000207     39     23      1   0             0 
+
+
+0x00000403: 00 DW_LNE_set_address (0x000000000000020c)
+0x0000040a: 05 DW_LNS_set_column (19)
+0x0000040c: 01 DW_LNS_copy
+            0x000000000000020c     39     19      1   0             0 
+
+
+0x0000040d: 00 DW_LNE_set_address (0x0000000000000211)
+0x00000414: 03 DW_LNS_advance_line (40)
+0x00000416: 05 DW_LNS_set_column (4)
+0x00000418: 06 DW_LNS_negate_stmt
+0x00000419: 01 DW_LNS_copy
+            0x0000000000000211     40      4      1   0             0  is_stmt
+
+
+0x0000041a: 00 DW_LNE_set_address (0x0000000000000219)
+0x00000421: 05 DW_LNS_set_column (17)
+0x00000423: 06 DW_LNS_negate_stmt
+0x00000424: 01 DW_LNS_copy
+            0x0000000000000219     40     17      1   0             0 
+
+
+0x00000425: 00 DW_LNE_set_address (0x0000000000000223)
+0x0000042c: 03 DW_LNS_advance_line (44)
+0x0000042e: 05 DW_LNS_set_column (16)
+0x00000430: 06 DW_LNS_negate_stmt
+0x00000431: 01 DW_LNS_copy
+            0x0000000000000223     44     16      1   0             0  is_stmt
+
+
+0x00000432: 00 DW_LNE_set_address (0x000000000000022c)
+0x00000439: 03 DW_LNS_advance_line (45)
+0x0000043b: 05 DW_LNS_set_column (10)
+0x0000043d: 01 DW_LNS_copy
+            0x000000000000022c     45     10      1   0             0  is_stmt
+
+
+0x0000043e: 00 DW_LNE_set_address (0x000000000000022e)
+0x00000445: 05 DW_LNS_set_column (18)
+0x00000447: 06 DW_LNS_negate_stmt
+0x00000448: 01 DW_LNS_copy
+            0x000000000000022e     45     18      1   0             0 
+
+
+0x00000449: 00 DW_LNE_set_address (0x0000000000000237)
+0x00000450: 05 DW_LNS_set_column (10)
+0x00000452: 01 DW_LNS_copy
+            0x0000000000000237     45     10      1   0             0 
+
+
+0x00000453: 00 DW_LNE_set_address (0x0000000000000239)
+0x0000045a: 05 DW_LNS_set_column (23)
+0x0000045c: 01 DW_LNS_copy
+            0x0000000000000239     45     23      1   0             0 
+
+
+0x0000045d: 00 DW_LNE_set_address (0x000000000000023e)
+0x00000464: 03 DW_LNS_advance_line (44)
+0x00000466: 05 DW_LNS_set_column (16)
+0x00000468: 06 DW_LNS_negate_stmt
+0x00000469: 01 DW_LNS_copy
+            0x000000000000023e     44     16      1   0             0  is_stmt
+
+
+0x0000046a: 00 DW_LNE_set_address (0x000000000000024f)
+0x00000471: 03 DW_LNS_advance_line (46)
+0x00000473: 05 DW_LNS_set_column (11)
+0x00000475: 01 DW_LNS_copy
+            0x000000000000024f     46     11      1   0             0  is_stmt
+
+
+0x00000476: 00 DW_LNE_set_address (0x000000000000025b)
+0x0000047d: 05 DW_LNS_set_column (28)
+0x0000047f: 06 DW_LNS_negate_stmt
+0x00000480: 01 DW_LNS_copy
+            0x000000000000025b     46     28      1   0             0 
+
+
+0x00000481: 00 DW_LNE_set_address (0x0000000000000260)
+0x00000488: 05 DW_LNS_set_column (41)
+0x0000048a: 01 DW_LNS_copy
+            0x0000000000000260     46     41      1   0             0 
+
+
+0x0000048b: 00 DW_LNE_set_address (0x0000000000000265)
+0x00000492: 03 DW_LNS_advance_line (50)
+0x00000494: 05 DW_LNS_set_column (14)
+0x00000496: 06 DW_LNS_negate_stmt
+0x00000497: 01 DW_LNS_copy
+            0x0000000000000265     50     14      1   0             0  is_stmt
+
+
+0x00000498: 00 DW_LNE_set_address (0x0000000000000276)
+0x0000049f: 03 DW_LNS_advance_line (52)
+0x000004a1: 05 DW_LNS_set_column (38)
+0x000004a3: 01 DW_LNS_copy
+            0x0000000000000276     52     38      1   0             0  is_stmt
+
+
+0x000004a4: 00 DW_LNE_set_address (0x000000000000028a)
+0x000004ab: 03 DW_LNS_advance_line (53)
+0x000004ad: 05 DW_LNS_set_column (22)
+0x000004af: 01 DW_LNS_copy
+            0x000000000000028a     53     22      1   0             0  is_stmt
+
+
+0x000004b0: 00 DW_LNE_set_address (0x0000000000000299)
+0x000004b7: 03 DW_LNS_advance_line (54)
+0x000004b9: 05 DW_LNS_set_column (24)
+0x000004bb: 01 DW_LNS_copy
+            0x0000000000000299     54     24      1   0             0  is_stmt
+
+
+0x000004bc: 00 DW_LNE_set_address (0x000000000000029b)
+0x000004c3: 05 DW_LNS_set_column (26)
+0x000004c5: 06 DW_LNS_negate_stmt
+0x000004c6: 01 DW_LNS_copy
+            0x000000000000029b     54     26      1   0             0 
+
+
+0x000004c7: 00 DW_LNE_set_address (0x00000000000002a8)
+0x000004ce: 05 DW_LNS_set_column (24)
+0x000004d0: 01 DW_LNS_copy
+            0x00000000000002a8     54     24      1   0             0 
+
+
+0x000004d1: 00 DW_LNE_set_address (0x00000000000002ab)
+0x000004d8: 03 DW_LNS_advance_line (55)
+0x000004da: 06 DW_LNS_negate_stmt
+0x000004db: 01 DW_LNS_copy
+            0x00000000000002ab     55     24      1   0             0  is_stmt
+
+
+0x000004dc: 00 DW_LNE_set_address (0x00000000000002b2)
+0x000004e3: 03 DW_LNS_advance_line (52)
+0x000004e5: 05 DW_LNS_set_column (44)
+0x000004e7: 01 DW_LNS_copy
+            0x00000000000002b2     52     44      1   0             0  is_stmt
+
+
+0x000004e8: 00 DW_LNE_set_address (0x00000000000002be)
+0x000004ef: 05 DW_LNS_set_column (38)
+0x000004f1: 06 DW_LNS_negate_stmt
+0x000004f2: 01 DW_LNS_copy
+            0x00000000000002be     52     38      1   0             0 
+
+
+0x000004f3: 00 DW_LNE_set_address (0x00000000000002c5)
+0x000004fa: 03 DW_LNS_advance_line (58)
+0x000004fc: 05 DW_LNS_set_column (19)
+0x000004fe: 06 DW_LNS_negate_stmt
+0x000004ff: 01 DW_LNS_copy
+            0x00000000000002c5     58     19      1   0             0  is_stmt
+
+
+0x00000500: 00 DW_LNE_set_address (0x00000000000002d4)
+0x00000507: 03 DW_LNS_advance_line (59)
+0x00000509: 05 DW_LNS_set_column (21)
+0x0000050b: 01 DW_LNS_copy
+            0x00000000000002d4     59     21      1   0             0  is_stmt
+
+
+0x0000050c: 00 DW_LNE_set_address (0x00000000000002db)
+0x00000513: 03 DW_LNS_advance_line (57)
+0x00000515: 05 DW_LNS_set_column (18)
+0x00000517: 01 DW_LNS_copy
+            0x00000000000002db     57     18      1   0             0  is_stmt
+
+
+0x00000518: 00 DW_LNE_set_address (0x00000000000002eb)
+0x0000051f: 03 DW_LNS_advance_line (62)
+0x00000521: 05 DW_LNS_set_column (14)
+0x00000523: 01 DW_LNS_copy
+            0x00000000000002eb     62     14      1   0             0  is_stmt
+
+
+0x00000524: 00 DW_LNE_set_address (0x00000000000002ef)
+0x0000052b: 05 DW_LNS_set_column (23)
+0x0000052d: 06 DW_LNS_negate_stmt
+0x0000052e: 01 DW_LNS_copy
+            0x00000000000002ef     62     23      1   0             0 
+
+
+0x0000052f: 00 DW_LNE_set_address (0x00000000000002f4)
+0x00000536: 05 DW_LNS_set_column (14)
+0x00000538: 01 DW_LNS_copy
+            0x00000000000002f4     62     14      1   0             0 
+
+
+0x00000539: 00 DW_LNE_set_address (0x00000000000002f8)
+0x00000540: 03 DW_LNS_advance_line (66)
+0x00000542: 05 DW_LNS_set_column (16)
+0x00000544: 06 DW_LNS_negate_stmt
+0x00000545: 01 DW_LNS_copy
+            0x00000000000002f8     66     16      1   0             0  is_stmt
+
+
+0x00000546: 00 DW_LNE_set_address (0x0000000000000305)
+0x0000054d: 03 DW_LNS_advance_line (75)
+0x0000054f: 05 DW_LNS_set_column (27)
+0x00000551: 01 DW_LNS_copy
+            0x0000000000000305     75     27      1   0             0  is_stmt
+
+
+0x00000552: 00 DW_LNE_set_address (0x000000000000030e)
+0x00000559: 03 DW_LNS_advance_line (76)
+0x0000055b: 05 DW_LNS_set_column (16)
+0x0000055d: 01 DW_LNS_copy
+            0x000000000000030e     76     16      1   0             0  is_stmt
+
+
+0x0000055e: 00 DW_LNE_set_address (0x0000000000000316)
+0x00000565: 05 DW_LNS_set_column (27)
+0x00000567: 06 DW_LNS_negate_stmt
+0x00000568: 01 DW_LNS_copy
+            0x0000000000000316     76     27      1   0             0 
+
+
+0x00000569: 00 DW_LNE_set_address (0x0000000000000318)
+0x00000570: 05 DW_LNS_set_column (35)
+0x00000572: 01 DW_LNS_copy
+            0x0000000000000318     76     35      1   0             0 
+
+
+0x00000573: 00 DW_LNE_set_address (0x0000000000000321)
+0x0000057a: 05 DW_LNS_set_column (27)
+0x0000057c: 01 DW_LNS_copy
+            0x0000000000000321     76     27      1   0             0 
+
+
+0x0000057d: 00 DW_LNE_set_address (0x0000000000000326)
+0x00000584: 05 DW_LNS_set_column (25)
+0x00000586: 01 DW_LNS_copy
+            0x0000000000000326     76     25      1   0             0 
+
+
+0x00000587: 00 DW_LNE_set_address (0x0000000000000329)
+0x0000058e: 03 DW_LNS_advance_line (75)
+0x00000590: 05 DW_LNS_set_column (27)
+0x00000592: 06 DW_LNS_negate_stmt
+0x00000593: 01 DW_LNS_copy
+            0x0000000000000329     75     27      1   0             0  is_stmt
+
+
+0x00000594: 00 DW_LNE_set_address (0x0000000000000336)
+0x0000059b: 03 DW_LNS_advance_line (77)
+0x0000059d: 05 DW_LNS_set_column (13)
+0x0000059f: 01 DW_LNS_copy
+            0x0000000000000336     77     13      1   0             0  is_stmt
+
+
+0x000005a0: 00 DW_LNE_set_address (0x000000000000033e)
+0x000005a7: 05 DW_LNS_set_column (22)
+0x000005a9: 06 DW_LNS_negate_stmt
+0x000005aa: 01 DW_LNS_copy
+            0x000000000000033e     77     22      1   0             0 
+
+
+0x000005ab: 00 DW_LNE_set_address (0x0000000000000343)
+0x000005b2: 03 DW_LNS_advance_line (79)
+0x000005b4: 05 DW_LNS_set_column (16)
+0x000005b6: 06 DW_LNS_negate_stmt
+0x000005b7: 01 DW_LNS_copy
+            0x0000000000000343     79     16      1   0             0  is_stmt
+
+
+0x000005b8: 00 DW_LNE_set_address (0x000000000000034b)
+0x000005bf: 05 DW_LNS_set_column (14)
+0x000005c1: 06 DW_LNS_negate_stmt
+0x000005c2: 01 DW_LNS_copy
+            0x000000000000034b     79     14      1   0             0 
+
+
+0x000005c3: 00 DW_LNE_set_address (0x000000000000035a)
+0x000005ca: 05 DW_LNS_set_column (25)
+0x000005cc: 01 DW_LNS_copy
+            0x000000000000035a     79     25      1   0             0 
+
+
+0x000005cd: 00 DW_LNE_set_address (0x0000000000000361)
+0x000005d4: 03 DW_LNS_advance_line (81)
+0x000005d6: 05 DW_LNS_set_column (11)
+0x000005d8: 06 DW_LNS_negate_stmt
+0x000005d9: 01 DW_LNS_copy
+            0x0000000000000361     81     11      1   0             0  is_stmt
+
+
+0x000005da: 00 DW_LNE_set_address (0x0000000000000366)
+0x000005e1: 03 DW_LNS_advance_line (66)
+0x000005e3: 05 DW_LNS_set_column (16)
+0x000005e5: 01 DW_LNS_copy
+            0x0000000000000366     66     16      1   0             0  is_stmt
+
+
+0x000005e6: 00 DW_LNE_set_address (0x000000000000036d)
+0x000005ed: 03 DW_LNS_advance_line (74)
+0x000005ef: 05 DW_LNS_set_column (22)
+0x000005f1: 01 DW_LNS_copy
+            0x000000000000036d     74     22      1   0             0  is_stmt
+
+
+0x000005f2: 00 DW_LNE_set_address (0x000000000000037b)
+0x000005f9: 03 DW_LNS_advance_line (67)
+0x000005fb: 05 DW_LNS_set_column (13)
+0x000005fd: 01 DW_LNS_copy
+            0x000000000000037b     67     13      1   0             0  is_stmt
+
+
+0x000005fe: 00 DW_LNE_set_address (0x000000000000037f)
+0x00000605: 03 DW_LNS_advance_line (68)
+0x00000607: 01 DW_LNS_copy
+            0x000000000000037f     68     13      1   0             0  is_stmt
+
+
+0x00000608: 00 DW_LNE_set_address (0x0000000000000383)
+0x0000060f: 03 DW_LNS_advance_line (69)
+0x00000611: 01 DW_LNS_copy
+            0x0000000000000383     69     13      1   0             0  is_stmt
+
+
+0x00000612: 00 DW_LNE_set_address (0x0000000000000387)
+0x00000619: 03 DW_LNS_advance_line (70)
+0x0000061b: 01 DW_LNS_copy
+            0x0000000000000387     70     13      1   0             0  is_stmt
+
+
+0x0000061c: 00 DW_LNE_set_address (0x000000000000038a)
+0x00000623: 00 DW_LNE_end_sequence
+            0x000000000000038a     70     13      1   0             0  is_stmt end_sequence
+
+0x00000626: 00 DW_LNE_set_address (0x000000000000038c)
+0x0000062d: 03 DW_LNS_advance_line (152)
+0x00000630: 01 DW_LNS_copy
+            0x000000000000038c    152      0      1   0             0  is_stmt
+
+
+0x00000631: 00 DW_LNE_set_address (0x00000000000003a8)
+0x00000638: 03 DW_LNS_advance_line (153)
+0x0000063a: 05 DW_LNS_set_column (17)
+0x0000063c: 0a DW_LNS_set_prologue_end
+0x0000063d: 01 DW_LNS_copy
+            0x00000000000003a8    153     17      1   0             0  is_stmt prologue_end
+
+
+0x0000063e: 00 DW_LNE_set_address (0x00000000000003af)
+0x00000645: 05 DW_LNS_set_column (28)
+0x00000647: 06 DW_LNS_negate_stmt
+0x00000648: 01 DW_LNS_copy
+            0x00000000000003af    153     28      1   0             0 
+
+
+0x00000649: 00 DW_LNE_set_address (0x00000000000003b4)
+0x00000650: 05 DW_LNS_set_column (23)
+0x00000652: 01 DW_LNS_copy
+            0x00000000000003b4    153     23      1   0             0 
+
+
+0x00000653: 00 DW_LNE_set_address (0x00000000000003ba)
+0x0000065a: 03 DW_LNS_advance_line (155)
+0x0000065c: 05 DW_LNS_set_column (10)
+0x0000065e: 06 DW_LNS_negate_stmt
+0x0000065f: 01 DW_LNS_copy
+            0x00000000000003ba    155     10      1   0             0  is_stmt
+
+
+0x00000660: 00 DW_LNE_set_address (0x00000000000003bb)
+0x00000667: 05 DW_LNS_set_column (8)
+0x00000669: 06 DW_LNS_negate_stmt
+0x0000066a: 01 DW_LNS_copy
+            0x00000000000003bb    155      8      1   0             0 
+
+
+0x0000066b: 00 DW_LNE_set_address (0x00000000000003be)
+0x00000672: 03 DW_LNS_advance_line (156)
+0x00000674: 05 DW_LNS_set_column (7)
+0x00000676: 06 DW_LNS_negate_stmt
+0x00000677: 01 DW_LNS_copy
+            0x00000000000003be    156      7      1   0             0  is_stmt
+
+
+0x00000678: 00 DW_LNE_set_address (0x00000000000003cb)
+0x0000067f: 03 DW_LNS_advance_line (94)
+0x00000681: 05 DW_LNS_set_column (18)
+0x00000683: 01 DW_LNS_copy
+            0x00000000000003cb     94     18      1   0             0  is_stmt
+
+
+0x00000684: 00 DW_LNE_set_address (0x00000000000003e5)
+0x0000068b: 03 DW_LNS_advance_line (95)
+0x0000068d: 05 DW_LNS_set_column (29)
+0x0000068f: 01 DW_LNS_copy
+            0x00000000000003e5     95     29      1   0             0  is_stmt
+
+
+0x00000690: 00 DW_LNE_set_address (0x00000000000003e7)
+0x00000697: 03 DW_LNS_advance_line (98)
+0x00000699: 05 DW_LNS_set_column (19)
+0x0000069b: 01 DW_LNS_copy
+            0x00000000000003e7     98     19      1   0             0  is_stmt
+
+
+0x0000069c: 00 DW_LNE_set_address (0x00000000000003ee)
+0x000006a3: 03 DW_LNS_advance_line (97)
+0x000006a5: 05 DW_LNS_set_column (16)
+0x000006a7: 01 DW_LNS_copy
+            0x00000000000003ee     97     16      1   0             0  is_stmt
+
+
+0x000006a8: 00 DW_LNE_set_address (0x00000000000003f5)
+0x000006af: 03 DW_LNS_advance_line (96)
+0x000006b1: 01 DW_LNS_copy
+            0x00000000000003f5     96     16      1   0             0  is_stmt
+
+
+0x000006b2: 00 DW_LNE_set_address (0x0000000000000400)
+0x000006b9: 03 DW_LNS_advance_line (94)
+0x000006bb: 05 DW_LNS_set_column (28)
+0x000006bd: 01 DW_LNS_copy
+            0x0000000000000400     94     28      1   0             0  is_stmt
+
+
+0x000006be: 00 DW_LNE_set_address (0x0000000000000405)
+0x000006c5: 05 DW_LNS_set_column (18)
+0x000006c7: 06 DW_LNS_negate_stmt
+0x000006c8: 01 DW_LNS_copy
+            0x0000000000000405     94     18      1   0             0 
+
+
+0x000006c9: 00 DW_LNE_set_address (0x000000000000040a)
+0x000006d0: 05 DW_LNS_set_column (4)
+0x000006d2: 01 DW_LNS_copy
+            0x000000000000040a     94      4      1   0             0 
+
+
+0x000006d3: 00 DW_LNE_set_address (0x0000000000000412)
+0x000006da: 03 DW_LNS_advance_line (102)
+0x000006dc: 05 DW_LNS_set_column (27)
+0x000006de: 06 DW_LNS_negate_stmt
+0x000006df: 01 DW_LNS_copy
+            0x0000000000000412    102     27      1   0             0  is_stmt
+
+
+0x000006e0: 00 DW_LNE_set_address (0x0000000000000417)
+0x000006e7: 05 DW_LNS_set_column (18)
+0x000006e9: 06 DW_LNS_negate_stmt
+0x000006ea: 01 DW_LNS_copy
+            0x0000000000000417    102     18      1   0             0 
+
+
+0x000006eb: 00 DW_LNE_set_address (0x000000000000041d)
+0x000006f2: 03 DW_LNS_advance_line (103)
+0x000006f4: 06 DW_LNS_negate_stmt
+0x000006f5: 01 DW_LNS_copy
+            0x000000000000041d    103     18      1   0             0  is_stmt
+
+
+0x000006f6: 00 DW_LNE_set_address (0x0000000000000429)
+0x000006fd: 03 DW_LNS_advance_line (105)
+0x000006ff: 01 DW_LNS_copy
+            0x0000000000000429    105     18      1   0             0  is_stmt
+
+
+0x00000700: 00 DW_LNE_set_address (0x0000000000000432)
+0x00000707: 03 DW_LNS_advance_line (106)
+0x00000709: 05 DW_LNS_set_column (7)
+0x0000070b: 01 DW_LNS_copy
+            0x0000000000000432    106      7      1   0             0  is_stmt
+
+
+0x0000070c: 00 DW_LNE_set_address (0x000000000000043a)
+0x00000713: 05 DW_LNS_set_column (16)
+0x00000715: 06 DW_LNS_negate_stmt
+0x00000716: 01 DW_LNS_copy
+            0x000000000000043a    106     16      1   0             0 
+
+
+0x00000717: 00 DW_LNE_set_address (0x000000000000043f)
+0x0000071e: 03 DW_LNS_advance_line (105)
+0x00000720: 05 DW_LNS_set_column (24)
+0x00000722: 06 DW_LNS_negate_stmt
+0x00000723: 01 DW_LNS_copy
+            0x000000000000043f    105     24      1   0             0  is_stmt
+
+
+0x00000724: 00 DW_LNE_set_address (0x0000000000000444)
+0x0000072b: 05 DW_LNS_set_column (18)
+0x0000072d: 06 DW_LNS_negate_stmt
+0x0000072e: 01 DW_LNS_copy
+            0x0000000000000444    105     18      1   0             0 
+
+
+0x0000072f: 00 DW_LNE_set_address (0x000000000000046a)
+0x00000736: 03 DW_LNS_advance_line (112)
+0x00000738: 05 DW_LNS_set_column (13)
+0x0000073a: 06 DW_LNS_negate_stmt
+0x0000073b: 01 DW_LNS_copy
+            0x000000000000046a    112     13      1   0             0  is_stmt
+
+
+0x0000073c: 00 DW_LNE_set_address (0x000000000000046c)
+0x00000743: 05 DW_LNS_set_column (26)
+0x00000745: 06 DW_LNS_negate_stmt
+0x00000746: 01 DW_LNS_copy
+            0x000000000000046c    112     26      1   0             0 
+
+
+0x00000747: 00 DW_LNE_set_address (0x0000000000000479)
+0x0000074e: 05 DW_LNS_set_column (35)
+0x00000750: 01 DW_LNS_copy
+            0x0000000000000479    112     35      1   0             0 
+
+
+0x00000751: 00 DW_LNE_set_address (0x000000000000047a)
+0x00000758: 05 DW_LNS_set_column (13)
+0x0000075a: 01 DW_LNS_copy
+            0x000000000000047a    112     13      1   0             0 
+
+
+0x0000075b: 00 DW_LNE_set_address (0x0000000000000488)
+0x00000762: 03 DW_LNS_advance_line (111)
+0x00000764: 05 DW_LNS_set_column (30)
+0x00000766: 06 DW_LNS_negate_stmt
+0x00000767: 01 DW_LNS_copy
+            0x0000000000000488    111     30      1   0             0  is_stmt
+
+
+0x00000768: 00 DW_LNE_set_address (0x000000000000048d)
+0x0000076f: 05 DW_LNS_set_column (24)
+0x00000771: 06 DW_LNS_negate_stmt
+0x00000772: 01 DW_LNS_copy
+            0x000000000000048d    111     24      1   0             0 
+
+
+0x00000773: 00 DW_LNE_set_address (0x0000000000000492)
+0x0000077a: 05 DW_LNS_set_column (10)
+0x0000077c: 01 DW_LNS_copy
+            0x0000000000000492    111     10      1   0             0 
+
+
+0x0000077d: 00 DW_LNE_set_address (0x0000000000000497)
+0x00000784: 03 DW_LNS_advance_line (113)
+0x00000786: 06 DW_LNS_negate_stmt
+0x00000787: 01 DW_LNS_copy
+            0x0000000000000497    113     10      1   0             0  is_stmt
+
+
+0x00000788: 00 DW_LNE_set_address (0x000000000000049a)
+0x0000078f: 03 DW_LNS_advance_line (118)
+0x00000791: 05 DW_LNS_set_column (16)
+0x00000793: 01 DW_LNS_copy
+            0x000000000000049a    118     16      1   0             0  is_stmt
+
+
+0x00000794: 00 DW_LNE_set_address (0x00000000000004a3)
+0x0000079b: 03 DW_LNS_advance_line (119)
+0x0000079d: 05 DW_LNS_set_column (10)
+0x0000079f: 01 DW_LNS_copy
+            0x00000000000004a3    119     10      1   0             0  is_stmt
+
+
+0x000007a0: 00 DW_LNE_set_address (0x00000000000004a5)
+0x000007a7: 05 DW_LNS_set_column (18)
+0x000007a9: 06 DW_LNS_negate_stmt
+0x000007aa: 01 DW_LNS_copy
+            0x00000000000004a5    119     18      1   0             0 
+
+
+0x000007ab: 00 DW_LNE_set_address (0x00000000000004ae)
+0x000007b2: 05 DW_LNS_set_column (10)
+0x000007b4: 01 DW_LNS_copy
+            0x00000000000004ae    119     10      1   0             0 
+
+
+0x000007b5: 00 DW_LNE_set_address (0x00000000000004b0)
+0x000007bc: 05 DW_LNS_set_column (23)
+0x000007be: 01 DW_LNS_copy
+            0x00000000000004b0    119     23      1   0             0 
+
+
+0x000007bf: 00 DW_LNE_set_address (0x00000000000004b5)
+0x000007c6: 03 DW_LNS_advance_line (118)
+0x000007c8: 05 DW_LNS_set_column (16)
+0x000007ca: 06 DW_LNS_negate_stmt
+0x000007cb: 01 DW_LNS_copy
+            0x00000000000004b5    118     16      1   0             0  is_stmt
+
+
+0x000007cc: 00 DW_LNE_set_address (0x00000000000004c0)
+0x000007d3: 05 DW_LNS_set_column (7)
+0x000007d5: 06 DW_LNS_negate_stmt
+0x000007d6: 01 DW_LNS_copy
+            0x00000000000004c0    118      7      1   0             0 
+
+
+0x000007d7: 00 DW_LNE_set_address (0x00000000000004c6)
+0x000007de: 03 DW_LNS_advance_line (122)
+0x000007e0: 05 DW_LNS_set_column (16)
+0x000007e2: 06 DW_LNS_negate_stmt
+0x000007e3: 01 DW_LNS_copy
+            0x00000000000004c6    122     16      1   0             0  is_stmt
+
+
+0x000007e4: 00 DW_LNE_set_address (0x00000000000004da)
+0x000007eb: 03 DW_LNS_advance_line (125)
+0x000007ed: 05 DW_LNS_set_column (22)
+0x000007ef: 01 DW_LNS_copy
+            0x00000000000004da    125     22      1   0             0  is_stmt
+
+
+0x000007f0: 00 DW_LNE_set_address (0x00000000000004e1)
+0x000007f7: 03 DW_LNS_advance_line (126)
+0x000007f9: 05 DW_LNS_set_column (27)
+0x000007fb: 01 DW_LNS_copy
+            0x00000000000004e1    126     27      1   0             0  is_stmt
+
+
+0x000007fc: 00 DW_LNE_set_address (0x00000000000004ea)
+0x00000803: 03 DW_LNS_advance_line (127)
+0x00000805: 05 DW_LNS_set_column (16)
+0x00000807: 01 DW_LNS_copy
+            0x00000000000004ea    127     16      1   0             0  is_stmt
+
+
+0x00000808: 00 DW_LNE_set_address (0x00000000000004f2)
+0x0000080f: 05 DW_LNS_set_column (27)
+0x00000811: 06 DW_LNS_negate_stmt
+0x00000812: 01 DW_LNS_copy
+            0x00000000000004f2    127     27      1   0             0 
+
+
+0x00000813: 00 DW_LNE_set_address (0x00000000000004f4)
+0x0000081a: 05 DW_LNS_set_column (35)
+0x0000081c: 01 DW_LNS_copy
+            0x00000000000004f4    127     35      1   0             0 
+
+
+0x0000081d: 00 DW_LNE_set_address (0x00000000000004fd)
+0x00000824: 05 DW_LNS_set_column (27)
+0x00000826: 01 DW_LNS_copy
+            0x00000000000004fd    127     27      1   0             0 
+
+
+0x00000827: 00 DW_LNE_set_address (0x0000000000000502)
+0x0000082e: 05 DW_LNS_set_column (25)
+0x00000830: 01 DW_LNS_copy
+            0x0000000000000502    127     25      1   0             0 
+
+
+0x00000831: 00 DW_LNE_set_address (0x0000000000000505)
+0x00000838: 03 DW_LNS_advance_line (126)
+0x0000083a: 05 DW_LNS_set_column (27)
+0x0000083c: 06 DW_LNS_negate_stmt
+0x0000083d: 01 DW_LNS_copy
+            0x0000000000000505    126     27      1   0             0  is_stmt
+
+
+0x0000083e: 00 DW_LNE_set_address (0x000000000000050a)
+0x00000845: 05 DW_LNS_set_column (13)
+0x00000847: 06 DW_LNS_negate_stmt
+0x00000848: 01 DW_LNS_copy
+            0x000000000000050a    126     13      1   0             0 
+
+
+0x00000849: 00 DW_LNE_set_address (0x0000000000000512)
+0x00000850: 03 DW_LNS_advance_line (128)
+0x00000852: 06 DW_LNS_negate_stmt
+0x00000853: 01 DW_LNS_copy
+            0x0000000000000512    128     13      1   0             0  is_stmt
+
+
+0x00000854: 00 DW_LNE_set_address (0x000000000000051a)
+0x0000085b: 05 DW_LNS_set_column (22)
+0x0000085d: 06 DW_LNS_negate_stmt
+0x0000085e: 01 DW_LNS_copy
+            0x000000000000051a    128     22      1   0             0 
+
+
+0x0000085f: 00 DW_LNE_set_address (0x000000000000051f)
+0x00000866: 03 DW_LNS_advance_line (130)
+0x00000868: 05 DW_LNS_set_column (16)
+0x0000086a: 06 DW_LNS_negate_stmt
+0x0000086b: 01 DW_LNS_copy
+            0x000000000000051f    130     16      1   0             0  is_stmt
+
+
+0x0000086c: 00 DW_LNE_set_address (0x0000000000000527)
+0x00000873: 05 DW_LNS_set_column (14)
+0x00000875: 06 DW_LNS_negate_stmt
+0x00000876: 01 DW_LNS_copy
+            0x0000000000000527    130     14      1   0             0 
+
+
+0x00000877: 00 DW_LNE_set_address (0x0000000000000536)
+0x0000087e: 05 DW_LNS_set_column (25)
+0x00000880: 01 DW_LNS_copy
+            0x0000000000000536    130     25      1   0             0 
+
+
+0x00000881: 00 DW_LNE_set_address (0x000000000000053d)
+0x00000888: 03 DW_LNS_advance_line (133)
+0x0000088a: 05 DW_LNS_set_column (11)
+0x0000088c: 06 DW_LNS_negate_stmt
+0x0000088d: 01 DW_LNS_copy
+            0x000000000000053d    133     11      1   0             0  is_stmt
+
+
+0x0000088e: 00 DW_LNE_set_address (0x0000000000000542)
+0x00000895: 03 DW_LNS_advance_line (122)
+0x00000897: 05 DW_LNS_set_column (16)
+0x00000899: 01 DW_LNS_copy
+            0x0000000000000542    122     16      1   0             0  is_stmt
+
+
+0x0000089a: 00 DW_LNE_set_address (0x0000000000000547)
+0x000008a1: 05 DW_LNS_set_column (14)
+0x000008a3: 06 DW_LNS_negate_stmt
+0x000008a4: 01 DW_LNS_copy
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            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
+            0x0000000000000669    161      1      1   0             0  is_stmt
+
+
+0x00000a84: 00 DW_LNE_set_address (0x0000000000000673)
+0x00000a8b: 00 DW_LNE_end_sequence
+            0x0000000000000673    161      1      1   0             0  is_stmt end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)"
+0x00000069: "/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp"
+0x000000a9: "/usr/local/google/home/azakai/Dev/2-binaryen"
+0x000000d6: "i"
+0x000000d8: "int"
+0x000000dc: "n"
+0x000000de: "next"
+0x000000e3: "worker_args"
+0x000000ef: "std"
+0x000000f3: "decltype(nullptr)"
+0x00000105: "nullptr_t"
+0x0000010f: "free"
+0x00000114: "_ZL8fannkuchi"
+0x00000122: "fannkuch"
+0x0000012b: "showmax"
+0x00000133: "args"
+0x00000138: "targs"
+0x0000013e: "perm1"
+0x00000144: "count"
+0x0000014a: "r"
+0x0000014c: "maxflips"
+0x00000155: "flips"
+0x0000015b: "cleanup"
+0x00000163: "p0"
+0x00000166: "_Z15fannkuch_workerPv"
+0x0000017c: "fannkuch_worker"
+0x0000018c: "main"
+0x00000191: "_arg"
+0x00000196: "perm"
+0x0000019b: "k"
+0x0000019d: "j"
+0x0000019f: "tmp"
+0x000001a3: "argc"
+0x000001a8: "argv"
+0x000001ad: "char"
+
+.debug_ranges contents:
+00000000 00000184 000001c2
+00000000 000001ec 000001f5
+00000000 00000305 00000343
+00000000 0000036d 00000376
+00000000 <End of list>
+00000028 000004da 0000051f
+00000028 00000596 000005e1
+00000028 <End of list>
+00000040 00000007 0000038a
+00000040 0000038c 00000673
+00000040 <End of list>
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_none (func))
+ (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.")
+ (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)))
+ (import "env" "atoi" (func $atoi (param i32) (result i32)))
+ (import "env" "puts" (func $puts (param i32) (result i32)))
+ (import "env" "iprintf" (func $iprintf (param i32 i32) (result i32)))
+ (import "env" "putchar" (func $putchar (param i32) (result i32)))
+ (global $global$0 (mut i32) (i32.const 5243952))
+ (global $global$1 i32 (i32.const 1066))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__data_end" (global $global$1))
+ (func $__wasm_call_ctors
+  ;; code offset: 0x3
+  (nop)
+ )
+ (func $fannkuch_worker\28void*\29 (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  ;; code offset: 0x36
+  (local.set $3
+   ;; code offset: 0x34
+   (call $malloc
+    ;; code offset: 0x32
+    (local.tee $12
+     ;; code offset: 0x31
+     (i32.shl
+      ;; code offset: 0x2d
+      (local.tee $2
+       ;; code offset: 0x2a
+       (i32.load offset=4
+        ;; code offset: 0x28
+        (local.get $0)
+       )
+      )
+      ;; code offset: 0x2f
+      (i32.const 2)
+     )
+    )
+   )
+  )
+  ;; code offset: 0x3c
+  (local.set $8
+   ;; code offset: 0x3a
+   (call $malloc
+    ;; code offset: 0x38
+    (local.get $12)
+   )
+  )
+  ;; code offset: 0x42
+  (local.set $9
+   ;; code offset: 0x40
+   (call $malloc
+    ;; code offset: 0x3e
+    (local.get $12)
+   )
+  )
+  ;; code offset: 0x44
+  (block $label$1
+   (block $label$2
+    ;; code offset: 0x4d
+    (if
+     ;; code offset: 0x4c
+     (i32.gt_s
+      ;; code offset: 0x48
+      (local.get $2)
+      ;; code offset: 0x4a
+      (i32.const 0)
+     )
+     (block
+      ;; code offset: 0x4f
+      (loop $label$4
+       ;; code offset: 0x5b
+       (i32.store
+        ;; code offset: 0x58
+        (i32.add
+         ;; code offset: 0x51
+         (local.get $3)
+         ;; code offset: 0x57
+         (i32.shl
+          ;; code offset: 0x53
+          (local.get $1)
+          ;; code offset: 0x55
+          (i32.const 2)
+         )
+        )
+        ;; code offset: 0x59
+        (local.get $1)
+       )
+       ;; code offset: 0x68
+       (br_if $label$4
+        ;; code offset: 0x67
+        (i32.ne
+         ;; code offset: 0x63
+         (local.tee $1
+          ;; code offset: 0x62
+          (i32.add
+           ;; code offset: 0x5e
+           (local.get $1)
+           ;; code offset: 0x60
+           (i32.const 1)
+          )
+         )
+         ;; code offset: 0x65
+         (local.get $2)
+        )
+       )
+      )
+      ;; code offset: 0x7f
+      (i32.store
+       ;; code offset: 0x77
+       (i32.add
+        ;; code offset: 0x6b
+        (local.get $3)
+        ;; code offset: 0x76
+        (i32.shl
+         ;; code offset: 0x72
+         (local.tee $1
+          ;; code offset: 0x6f
+          (i32.load
+           ;; code offset: 0x6d
+           (local.get $0)
+          )
+         )
+         ;; code offset: 0x74
+         (i32.const 2)
+        )
+       )
+       ;; code offset: 0x7d
+       (local.tee $4
+        ;; code offset: 0x7c
+        (i32.add
+         ;; code offset: 0x78
+         (local.get $2)
+         ;; code offset: 0x7a
+         (i32.const -1)
+        )
+       )
+      )
+      ;; code offset: 0x8e
+      (i32.store
+       ;; code offset: 0x8a
+       (local.tee $13
+        ;; code offset: 0x89
+        (i32.add
+         ;; code offset: 0x82
+         (local.get $3)
+         ;; code offset: 0x88
+         (i32.shl
+          ;; code offset: 0x84
+          (local.get $4)
+          ;; code offset: 0x86
+          (i32.const 2)
+         )
+        )
+       )
+       ;; code offset: 0x8c
+       (local.get $1)
+      )
+      ;; code offset: 0x96
+      (br_if $label$2
+       ;; code offset: 0x95
+       (i32.le_s
+        ;; code offset: 0x91
+        (local.get $2)
+        ;; code offset: 0x93
+        (i32.const 0)
+       )
+      )
+      ;; code offset: 0x98
+      (loop $label$5
+       ;; code offset: 0x9f
+       (if
+        ;; code offset: 0x9e
+        (i32.gt_s
+         ;; code offset: 0x9a
+         (local.get $2)
+         ;; code offset: 0x9c
+         (i32.const 1)
+        )
+        ;; code offset: 0xa1
+        (loop $label$7
+         ;; code offset: 0xb2
+         (i32.store
+          ;; code offset: 0xaf
+          (i32.add
+           ;; code offset: 0xa3
+           (local.get $9)
+           ;; code offset: 0xae
+           (i32.shl
+            ;; code offset: 0xaa
+            (local.tee $1
+             ;; code offset: 0xa9
+             (i32.add
+              ;; code offset: 0xa5
+              (local.get $2)
+              ;; code offset: 0xa7
+              (i32.const -1)
+             )
+            )
+            ;; code offset: 0xac
+            (i32.const 2)
+           )
+          )
+          ;; code offset: 0xb0
+          (local.get $2)
+         )
+         ;; code offset: 0xba
+         (local.set $0
+          ;; code offset: 0xb9
+          (i32.gt_s
+           ;; code offset: 0xb5
+           (local.get $2)
+           ;; code offset: 0xb7
+           (i32.const 2)
+          )
+         )
+         ;; code offset: 0xbe
+         (local.set $2
+          ;; code offset: 0xbc
+          (local.get $1)
+         )
+         ;; code offset: 0xc2
+         (br_if $label$7
+          ;; code offset: 0xc0
+          (local.get $0)
+         )
+        )
+       )
+       ;; code offset: 0xc6
+       (block $label$8
+        ;; code offset: 0xd0
+        (br_if $label$8
+         ;; code offset: 0xcf
+         (i32.eqz
+          ;; code offset: 0xcd
+          (local.tee $10
+           ;; code offset: 0xca
+           (i32.load
+            ;; code offset: 0xc8
+            (local.get $3)
+           )
+          )
+         )
+        )
+        ;; code offset: 0xda
+        (br_if $label$8
+         ;; code offset: 0xd9
+         (i32.eq
+          ;; code offset: 0xd4
+          (i32.load
+           ;; code offset: 0xd2
+           (local.get $13)
+          )
+          ;; code offset: 0xd7
+          (local.get $4)
+         )
+        )
+        ;; code offset: 0xe9
+        (local.set $6
+         ;; code offset: 0xe6
+         (i32.load
+          ;; code offset: 0xe4
+          (local.tee $11
+           ;; code offset: 0xe2
+           (call $memcpy
+            ;; code offset: 0xdc
+            (local.get $8)
+            ;; code offset: 0xde
+            (local.get $3)
+            ;; code offset: 0xe0
+            (local.get $12)
+           )
+          )
+         )
+        )
+        ;; code offset: 0xed
+        (local.set $0
+         ;; code offset: 0xeb
+         (i32.const 0)
+        )
+        ;; code offset: 0xef
+        (loop $label$9
+         ;; code offset: 0xf3
+         (local.set $16
+          ;; code offset: 0xf1
+          (local.get $0)
+         )
+         ;; code offset: 0xfa
+         (if
+          ;; code offset: 0xf9
+          (i32.ge_s
+           ;; code offset: 0xf5
+           (local.get $6)
+           ;; code offset: 0xf7
+           (i32.const 3)
+          )
+          (block
+           ;; code offset: 0x101
+           (local.set $1
+            ;; code offset: 0x100
+            (i32.add
+             ;; code offset: 0xfc
+             (local.get $6)
+             ;; code offset: 0xfe
+             (i32.const -1)
+            )
+           )
+           ;; code offset: 0x105
+           (local.set $0
+            ;; code offset: 0x103
+            (i32.const 1)
+           )
+           ;; code offset: 0x107
+           (loop $label$11
+            ;; code offset: 0x116
+            (local.set $15
+             ;; code offset: 0x113
+             (i32.load
+              ;; code offset: 0x111
+              (local.tee $14
+               ;; code offset: 0x110
+               (i32.add
+                ;; code offset: 0x109
+                (local.get $11)
+                ;; code offset: 0x10f
+                (i32.shl
+                 ;; code offset: 0x10b
+                 (local.get $0)
+                 ;; code offset: 0x10d
+                 (i32.const 2)
+                )
+               )
+              )
+             )
+            )
+            ;; code offset: 0x127
+            (i32.store
+             ;; code offset: 0x118
+             (local.get $14)
+             ;; code offset: 0x124
+             (i32.load
+              ;; code offset: 0x122
+              (local.tee $7
+               ;; code offset: 0x121
+               (i32.add
+                ;; code offset: 0x11a
+                (local.get $11)
+                ;; code offset: 0x120
+                (i32.shl
+                 ;; code offset: 0x11c
+                 (local.get $1)
+                 ;; code offset: 0x11e
+                 (i32.const 2)
+                )
+               )
+              )
+             )
+            )
+            ;; code offset: 0x12e
+            (i32.store
+             ;; code offset: 0x12a
+             (local.get $7)
+             ;; code offset: 0x12c
+             (local.get $15)
+            )
+            ;; code offset: 0x140
+            (br_if $label$11
+             ;; code offset: 0x13f
+             (i32.lt_s
+              ;; code offset: 0x136
+              (local.tee $0
+               ;; code offset: 0x135
+               (i32.add
+                ;; code offset: 0x131
+                (local.get $0)
+                ;; code offset: 0x133
+                (i32.const 1)
+               )
+              )
+              ;; code offset: 0x13d
+              (local.tee $1
+               ;; code offset: 0x13c
+               (i32.add
+                ;; code offset: 0x138
+                (local.get $1)
+                ;; code offset: 0x13a
+                (i32.const -1)
+               )
+              )
+             )
+            )
+           )
+          )
+         )
+         ;; code offset: 0x151
+         (local.set $1
+          ;; code offset: 0x14e
+          (i32.load
+           ;; code offset: 0x14c
+           (local.tee $0
+            ;; code offset: 0x14b
+            (i32.add
+             ;; code offset: 0x144
+             (local.get $11)
+             ;; code offset: 0x14a
+             (i32.shl
+              ;; code offset: 0x146
+              (local.get $6)
+              ;; code offset: 0x148
+              (i32.const 2)
+             )
+            )
+           )
+          )
+         )
+         ;; code offset: 0x157
+         (i32.store
+          ;; code offset: 0x153
+          (local.get $0)
+          ;; code offset: 0x155
+          (local.get $6)
+         )
+         ;; code offset: 0x15f
+         (local.set $0
+          ;; code offset: 0x15e
+          (i32.add
+           ;; code offset: 0x15a
+           (local.get $16)
+           ;; code offset: 0x15c
+           (i32.const 1)
+          )
+         )
+         ;; code offset: 0x163
+         (local.set $6
+          ;; code offset: 0x161
+          (local.get $1)
+         )
+         ;; code offset: 0x167
+         (br_if $label$9
+          ;; code offset: 0x165
+          (local.get $1)
+         )
+        )
+        ;; code offset: 0x174
+        (local.set $5
+         ;; code offset: 0x173
+         (select
+          ;; code offset: 0x16a
+          (local.get $5)
+          ;; code offset: 0x16c
+          (local.get $0)
+          ;; code offset: 0x172
+          (i32.gt_s
+           ;; code offset: 0x16e
+           (local.get $5)
+           ;; code offset: 0x170
+           (local.get $16)
+          )
+         )
+        )
+       )
+       ;; code offset: 0x17c
+       (br_if $label$1
+        ;; code offset: 0x17b
+        (i32.ge_s
+         ;; code offset: 0x177
+         (local.get $2)
+         ;; code offset: 0x179
+         (local.get $4)
+        )
+       )
+       ;; code offset: 0x17e
+       (loop $label$12
+        ;; code offset: 0x182
+        (local.set $1
+         ;; code offset: 0x180
+         (i32.const 0)
+        )
+        ;; code offset: 0x189
+        (if
+         ;; code offset: 0x188
+         (i32.gt_s
+          ;; code offset: 0x184
+          (local.get $2)
+          ;; code offset: 0x186
+          (i32.const 0)
+         )
+         (block
+          ;; code offset: 0x18b
+          (loop $label$14
+           ;; code offset: 0x1a5
+           (i32.store
+            ;; code offset: 0x194
+            (i32.add
+             ;; code offset: 0x18d
+             (local.get $3)
+             ;; code offset: 0x193
+             (i32.shl
+              ;; code offset: 0x18f
+              (local.get $1)
+              ;; code offset: 0x191
+              (i32.const 2)
+             )
+            )
+            ;; code offset: 0x1a2
+            (i32.load
+             ;; code offset: 0x1a1
+             (i32.add
+              ;; code offset: 0x195
+              (local.get $3)
+              ;; code offset: 0x1a0
+              (i32.shl
+               ;; code offset: 0x19c
+               (local.tee $1
+                ;; code offset: 0x19b
+                (i32.add
+                 ;; code offset: 0x197
+                 (local.get $1)
+                 ;; code offset: 0x199
+                 (i32.const 1)
+                )
+               )
+               ;; code offset: 0x19e
+               (i32.const 2)
+              )
+             )
+            )
+           )
+           ;; code offset: 0x1ad
+           (br_if $label$14
+            ;; code offset: 0x1ac
+            (i32.ne
+             ;; code offset: 0x1a8
+             (local.get $1)
+             ;; code offset: 0x1aa
+             (local.get $2)
+            )
+           )
+          )
+          ;; code offset: 0x1b2
+          (local.set $1
+           ;; code offset: 0x1b0
+           (local.get $2)
+          )
+         )
+        )
+        ;; code offset: 0x1bf
+        (i32.store
+         ;; code offset: 0x1bc
+         (i32.add
+          ;; code offset: 0x1b5
+          (local.get $3)
+          ;; code offset: 0x1bb
+          (i32.shl
+           ;; code offset: 0x1b7
+           (local.get $1)
+           ;; code offset: 0x1b9
+           (i32.const 2)
+          )
+         )
+         ;; code offset: 0x1bd
+         (local.get $10)
+        )
+        ;; code offset: 0x1d6
+        (i32.store
+         ;; code offset: 0x1ca
+         (local.tee $1
+          ;; code offset: 0x1c9
+          (i32.add
+           ;; code offset: 0x1c2
+           (local.get $9)
+           ;; code offset: 0x1c8
+           (i32.shl
+            ;; code offset: 0x1c4
+            (local.get $2)
+            ;; code offset: 0x1c6
+            (i32.const 2)
+           )
+          )
+         )
+         ;; code offset: 0x1d5
+         (i32.add
+          ;; code offset: 0x1d1
+          (local.tee $1
+           ;; code offset: 0x1ce
+           (i32.load
+            ;; code offset: 0x1cc
+            (local.get $1)
+           )
+          )
+          ;; code offset: 0x1d3
+          (i32.const -1)
+         )
+        )
+        ;; code offset: 0x1de
+        (br_if $label$5
+         ;; code offset: 0x1dd
+         (i32.gt_s
+          ;; code offset: 0x1d9
+          (local.get $1)
+          ;; code offset: 0x1db
+          (i32.const 1)
+         )
+        )
+        ;; code offset: 0x1ea
+        (br_if $label$1
+         ;; code offset: 0x1e9
+         (i32.eq
+          ;; code offset: 0x1e5
+          (local.tee $2
+           ;; code offset: 0x1e4
+           (i32.add
+            ;; code offset: 0x1e0
+            (local.get $2)
+            ;; code offset: 0x1e2
+            (i32.const 1)
+           )
+          )
+          ;; code offset: 0x1e7
+          (local.get $4)
+         )
+        )
+        ;; code offset: 0x1f1
+        (local.set $10
+         ;; code offset: 0x1ee
+         (i32.load
+          ;; code offset: 0x1ec
+          (local.get $3)
+         )
+        )
+        ;; code offset: 0x1f3
+        (br $label$12)
+       )
+      )
+     )
+    )
+    ;; code offset: 0x20e
+    (i32.store
+     ;; code offset: 0x206
+     (i32.add
+      ;; code offset: 0x1fa
+      (local.get $3)
+      ;; code offset: 0x205
+      (i32.shl
+       ;; code offset: 0x201
+       (local.tee $1
+        ;; code offset: 0x1fe
+        (i32.load
+         ;; code offset: 0x1fc
+         (local.get $0)
+        )
+       )
+       ;; code offset: 0x203
+       (i32.const 2)
+      )
+     )
+     ;; code offset: 0x20c
+     (local.tee $4
+      ;; code offset: 0x20b
+      (i32.add
+       ;; code offset: 0x207
+       (local.get $2)
+       ;; code offset: 0x209
+       (i32.const -1)
+      )
+     )
+    )
+    ;; code offset: 0x21d
+    (i32.store
+     ;; code offset: 0x219
+     (local.tee $13
+      ;; code offset: 0x218
+      (i32.add
+       ;; code offset: 0x211
+       (local.get $3)
+       ;; code offset: 0x217
+       (i32.shl
+        ;; code offset: 0x213
+        (local.get $4)
+        ;; code offset: 0x215
+        (i32.const 2)
+       )
+      )
+     )
+     ;; code offset: 0x21b
+     (local.get $1)
+    )
+   )
+   ;; code offset: 0x221
+   (loop $label$15
+    ;; code offset: 0x228
+    (if
+     ;; code offset: 0x227
+     (i32.ge_s
+      ;; code offset: 0x223
+      (local.get $2)
+      ;; code offset: 0x225
+      (i32.const 2)
+     )
+     ;; code offset: 0x22a
+     (loop $label$17
+      ;; code offset: 0x23b
+      (i32.store
+       ;; code offset: 0x238
+       (i32.add
+        ;; code offset: 0x22c
+        (local.get $9)
+        ;; code offset: 0x237
+        (i32.shl
+         ;; code offset: 0x233
+         (local.tee $1
+          ;; code offset: 0x232
+          (i32.add
+           ;; code offset: 0x22e
+           (local.get $2)
+           ;; code offset: 0x230
+           (i32.const -1)
+          )
+         )
+         ;; code offset: 0x235
+         (i32.const 2)
+        )
+       )
+       ;; code offset: 0x239
+       (local.get $2)
+      )
+      ;; code offset: 0x243
+      (local.set $0
+       ;; code offset: 0x242
+       (i32.gt_s
+        ;; code offset: 0x23e
+        (local.get $2)
+        ;; code offset: 0x240
+        (i32.const 2)
+       )
+      )
+      ;; code offset: 0x247
+      (local.set $2
+       ;; code offset: 0x245
+       (local.get $1)
+      )
+      ;; code offset: 0x24b
+      (br_if $label$17
+       ;; code offset: 0x249
+       (local.get $0)
+      )
+     )
+    )
+    ;; code offset: 0x24f
+    (block $label$18
+     ;; code offset: 0x259
+     (br_if $label$18
+      ;; code offset: 0x258
+      (i32.eqz
+       ;; code offset: 0x256
+       (local.tee $6
+        ;; code offset: 0x253
+        (i32.load
+         ;; code offset: 0x251
+         (local.get $3)
+        )
+       )
+      )
+     )
+     ;; code offset: 0x263
+     (br_if $label$18
+      ;; code offset: 0x262
+      (i32.eq
+       ;; code offset: 0x25d
+       (i32.load
+        ;; code offset: 0x25b
+        (local.get $13)
+       )
+       ;; code offset: 0x260
+       (local.get $4)
+      )
+     )
+     ;; code offset: 0x26a
+     (local.set $7
+      ;; code offset: 0x267
+      (i32.load
+       ;; code offset: 0x265
+       (local.get $8)
+      )
+     )
+     ;; code offset: 0x26e
+     (local.set $0
+      ;; code offset: 0x26c
+      (i32.const 0)
+     )
+     ;; code offset: 0x270
+     (loop $label$19
+      ;; code offset: 0x274
+      (local.set $10
+       ;; code offset: 0x272
+       (local.get $0)
+      )
+      ;; code offset: 0x27b
+      (if
+       ;; code offset: 0x27a
+       (i32.ge_s
+        ;; code offset: 0x276
+        (local.get $7)
+        ;; code offset: 0x278
+        (i32.const 3)
+       )
+       (block
+        ;; code offset: 0x282
+        (local.set $1
+         ;; code offset: 0x281
+         (i32.add
+          ;; code offset: 0x27d
+          (local.get $7)
+          ;; code offset: 0x27f
+          (i32.const -1)
+         )
+        )
+        ;; code offset: 0x286
+        (local.set $0
+         ;; code offset: 0x284
+         (i32.const 1)
+        )
+        ;; code offset: 0x288
+        (loop $label$21
+         ;; code offset: 0x297
+         (local.set $14
+          ;; code offset: 0x294
+          (i32.load
+           ;; code offset: 0x292
+           (local.tee $11
+            ;; code offset: 0x291
+            (i32.add
+             ;; code offset: 0x28a
+             (local.get $8)
+             ;; code offset: 0x290
+             (i32.shl
+              ;; code offset: 0x28c
+              (local.get $0)
+              ;; code offset: 0x28e
+              (i32.const 2)
+             )
+            )
+           )
+          )
+         )
+         ;; code offset: 0x2a8
+         (i32.store
+          ;; code offset: 0x299
+          (local.get $11)
+          ;; code offset: 0x2a5
+          (i32.load
+           ;; code offset: 0x2a3
+           (local.tee $15
+            ;; code offset: 0x2a2
+            (i32.add
+             ;; code offset: 0x29b
+             (local.get $8)
+             ;; code offset: 0x2a1
+             (i32.shl
+              ;; code offset: 0x29d
+              (local.get $1)
+              ;; code offset: 0x29f
+              (i32.const 2)
+             )
+            )
+           )
+          )
+         )
+         ;; code offset: 0x2af
+         (i32.store
+          ;; code offset: 0x2ab
+          (local.get $15)
+          ;; code offset: 0x2ad
+          (local.get $14)
+         )
+         ;; code offset: 0x2c1
+         (br_if $label$21
+          ;; code offset: 0x2c0
+          (i32.lt_s
+           ;; code offset: 0x2b7
+           (local.tee $0
+            ;; code offset: 0x2b6
+            (i32.add
+             ;; code offset: 0x2b2
+             (local.get $0)
+             ;; code offset: 0x2b4
+             (i32.const 1)
+            )
+           )
+           ;; code offset: 0x2be
+           (local.tee $1
+            ;; code offset: 0x2bd
+            (i32.add
+             ;; code offset: 0x2b9
+             (local.get $1)
+             ;; code offset: 0x2bb
+             (i32.const -1)
+            )
+           )
+          )
+         )
+        )
+       )
+      )
+      ;; code offset: 0x2d2
+      (local.set $1
+       ;; code offset: 0x2cf
+       (i32.load
+        ;; code offset: 0x2cd
+        (local.tee $0
+         ;; code offset: 0x2cc
+         (i32.add
+          ;; code offset: 0x2c5
+          (local.get $8)
+          ;; code offset: 0x2cb
+          (i32.shl
+           ;; code offset: 0x2c7
+           (local.get $7)
+           ;; code offset: 0x2c9
+           (i32.const 2)
+          )
+         )
+        )
+       )
+      )
+      ;; code offset: 0x2d8
+      (i32.store
+       ;; code offset: 0x2d4
+       (local.get $0)
+       ;; code offset: 0x2d6
+       (local.get $7)
+      )
+      ;; code offset: 0x2e0
+      (local.set $0
+       ;; code offset: 0x2df
+       (i32.add
+        ;; code offset: 0x2db
+        (local.get $10)
+        ;; code offset: 0x2dd
+        (i32.const 1)
+       )
+      )
+      ;; code offset: 0x2e4
+      (local.set $7
+       ;; code offset: 0x2e2
+       (local.get $1)
+      )
+      ;; code offset: 0x2e8
+      (br_if $label$19
+       ;; code offset: 0x2e6
+       (local.get $1)
+      )
+     )
+     ;; code offset: 0x2f5
+     (local.set $5
+      ;; code offset: 0x2f4
+      (select
+       ;; code offset: 0x2eb
+       (local.get $5)
+       ;; code offset: 0x2ed
+       (local.get $0)
+       ;; code offset: 0x2f3
+       (i32.gt_s
+        ;; code offset: 0x2ef
+        (local.get $5)
+        ;; code offset: 0x2f1
+        (local.get $10)
+       )
+      )
+     )
+    )
+    ;; code offset: 0x2fd
+    (br_if $label$1
+     ;; code offset: 0x2fc
+     (i32.ge_s
+      ;; code offset: 0x2f8
+      (local.get $2)
+      ;; code offset: 0x2fa
+      (local.get $4)
+     )
+    )
+    ;; code offset: 0x2ff
+    (loop $label$22
+     ;; code offset: 0x303
+     (local.set $1
+      ;; code offset: 0x301
+      (i32.const 0)
+     )
+     ;; code offset: 0x30a
+     (if
+      ;; code offset: 0x309
+      (i32.ge_s
+       ;; code offset: 0x305
+       (local.get $2)
+       ;; code offset: 0x307
+       (i32.const 1)
+      )
+      (block
+       ;; code offset: 0x30c
+       (loop $label$24
+        ;; code offset: 0x326
+        (i32.store
+         ;; code offset: 0x315
+         (i32.add
+          ;; code offset: 0x30e
+          (local.get $3)
+          ;; code offset: 0x314
+          (i32.shl
+           ;; code offset: 0x310
+           (local.get $1)
+           ;; code offset: 0x312
+           (i32.const 2)
+          )
+         )
+         ;; code offset: 0x323
+         (i32.load
+          ;; code offset: 0x322
+          (i32.add
+           ;; code offset: 0x316
+           (local.get $3)
+           ;; code offset: 0x321
+           (i32.shl
+            ;; code offset: 0x31d
+            (local.tee $1
+             ;; code offset: 0x31c
+             (i32.add
+              ;; code offset: 0x318
+              (local.get $1)
+              ;; code offset: 0x31a
+              (i32.const 1)
+             )
+            )
+            ;; code offset: 0x31f
+            (i32.const 2)
+           )
+          )
+         )
+        )
+        ;; code offset: 0x32e
+        (br_if $label$24
+         ;; code offset: 0x32d
+         (i32.ne
+          ;; code offset: 0x329
+          (local.get $1)
+          ;; code offset: 0x32b
+          (local.get $2)
+         )
+        )
+       )
+       ;; code offset: 0x333
+       (local.set $1
+        ;; code offset: 0x331
+        (local.get $2)
+       )
+      )
+     )
+     ;; code offset: 0x340
+     (i32.store
+      ;; code offset: 0x33d
+      (i32.add
+       ;; code offset: 0x336
+       (local.get $3)
+       ;; code offset: 0x33c
+       (i32.shl
+        ;; code offset: 0x338
+        (local.get $1)
+        ;; code offset: 0x33a
+        (i32.const 2)
+       )
+      )
+      ;; code offset: 0x33e
+      (local.get $6)
+     )
+     ;; code offset: 0x357
+     (i32.store
+      ;; code offset: 0x34b
+      (local.tee $1
+       ;; code offset: 0x34a
+       (i32.add
+        ;; code offset: 0x343
+        (local.get $9)
+        ;; code offset: 0x349
+        (i32.shl
+         ;; code offset: 0x345
+         (local.get $2)
+         ;; code offset: 0x347
+         (i32.const 2)
+        )
+       )
+      )
+      ;; code offset: 0x356
+      (i32.add
+       ;; code offset: 0x352
+       (local.tee $1
+        ;; code offset: 0x34f
+        (i32.load
+         ;; code offset: 0x34d
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x354
+       (i32.const -1)
+      )
+     )
+     ;; code offset: 0x35f
+     (br_if $label$15
+      ;; code offset: 0x35e
+      (i32.gt_s
+       ;; code offset: 0x35a
+       (local.get $1)
+       ;; code offset: 0x35c
+       (i32.const 1)
+      )
+     )
+     ;; code offset: 0x36b
+     (br_if $label$1
+      ;; code offset: 0x36a
+      (i32.eq
+       ;; code offset: 0x366
+       (local.tee $2
+        ;; code offset: 0x365
+        (i32.add
+         ;; code offset: 0x361
+         (local.get $2)
+         ;; code offset: 0x363
+         (i32.const 1)
+        )
+       )
+       ;; code offset: 0x368
+       (local.get $4)
+      )
+     )
+     ;; code offset: 0x372
+     (local.set $6
+      ;; code offset: 0x36f
+      (i32.load
+       ;; code offset: 0x36d
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x374
+     (br $label$22)
+    )
+   )
+  )
+  ;; code offset: 0x37d
+  (call $free
+   ;; code offset: 0x37b
+   (local.get $3)
+  )
+  ;; code offset: 0x381
+  (call $free
+   ;; code offset: 0x37f
+   (local.get $8)
+  )
+  ;; code offset: 0x385
+  (call $free
+   ;; code offset: 0x383
+   (local.get $9)
+  )
+  ;; code offset: 0x387
+  (local.get $5)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  ;; code offset: 0x3a2
+  (global.set $global$0
+   ;; code offset: 0x3a0
+   (local.tee $8
+    ;; code offset: 0x39f
+    (i32.sub
+     ;; code offset: 0x39b
+     (global.get $global$0)
+     ;; code offset: 0x39d
+     (i32.const 32)
+    )
+   )
+  )
+  ;; code offset: 0x3a4
+  (block $label$1
+   (block $label$2
+    ;; code offset: 0x3ad
+    (if
+     ;; code offset: 0x3ac
+     (i32.ge_s
+      ;; code offset: 0x3a8
+      (local.get $0)
+      ;; code offset: 0x3aa
+      (i32.const 2)
+     )
+     ;; code offset: 0x3bb
+     (br_if $label$2
+      ;; code offset: 0x3ba
+      (i32.gt_s
+       ;; code offset: 0x3b6
+       (local.tee $3
+        ;; code offset: 0x3b4
+        (call $atoi
+         ;; code offset: 0x3b1
+         (i32.load offset=4
+          ;; code offset: 0x3af
+          (local.get $1)
+         )
+        )
+       )
+       ;; code offset: 0x3b8
+       (i32.const 0)
+      )
+     )
+    )
+    ;; code offset: 0x3c3
+    (drop
+     ;; code offset: 0x3c1
+     (call $puts
+      ;; code offset: 0x3be
+      (i32.const 1050)
+     )
+    )
+    ;; code offset: 0x3c6
+    (local.set $5
+     ;; code offset: 0x3c4
+     (i32.const 1)
+    )
+    ;; code offset: 0x3c8
+    (br $label$1)
+   )
+   ;; code offset: 0x3d0
+   (if
+    ;; code offset: 0x3cf
+    (i32.ne
+     ;; code offset: 0x3cb
+     (local.get $3)
+     ;; code offset: 0x3cd
+     (i32.const 1)
+    )
+    (block
+     ;; code offset: 0x3d7
+     (local.set $2
+      ;; code offset: 0x3d6
+      (i32.add
+       ;; code offset: 0x3d2
+       (local.get $3)
+       ;; code offset: 0x3d4
+       (i32.const -1)
+      )
+     )
+     ;; code offset: 0x3db
+     (local.set $1
+      ;; code offset: 0x3d9
+      (i32.const 0)
+     )
+     ;; code offset: 0x3df
+     (local.set $0
+      ;; code offset: 0x3dd
+      (i32.const 0)
+     )
+     ;; code offset: 0x3e1
+     (loop $label$5
+      ;; code offset: 0x3eb
+      (i32.store offset=8
+       ;; code offset: 0x3e7
+       (local.tee $4
+        ;; code offset: 0x3e5
+        (call $malloc
+         ;; code offset: 0x3e3
+         (i32.const 12)
+        )
+       )
+       ;; code offset: 0x3e9
+       (local.get $1)
+      )
+      ;; code offset: 0x3f2
+      (i32.store offset=4
+       ;; code offset: 0x3ee
+       (local.get $4)
+       ;; code offset: 0x3f0
+       (local.get $3)
+      )
+      ;; code offset: 0x3f9
+      (i32.store
+       ;; code offset: 0x3f5
+       (local.get $4)
+       ;; code offset: 0x3f7
+       (local.get $0)
+      )
+      ;; code offset: 0x3fe
+      (local.set $1
+       ;; code offset: 0x3fc
+       (local.get $4)
+      )
+      ;; code offset: 0x40a
+      (br_if $label$5
+       ;; code offset: 0x409
+       (i32.ne
+        ;; code offset: 0x405
+        (local.tee $0
+         ;; code offset: 0x404
+         (i32.add
+          ;; code offset: 0x400
+          (local.get $0)
+          ;; code offset: 0x402
+          (i32.const 1)
+         )
+        )
+        ;; code offset: 0x407
+        (local.get $2)
+       )
+      )
+     )
+    )
+   )
+   ;; code offset: 0x410
+   (local.set $0
+    ;; code offset: 0x40e
+    (i32.const 0)
+   )
+   ;; code offset: 0x41b
+   (local.set $1
+    ;; code offset: 0x419
+    (call $malloc
+     ;; code offset: 0x417
+     (local.tee $2
+      ;; code offset: 0x416
+      (i32.shl
+       ;; code offset: 0x412
+       (local.get $3)
+       ;; code offset: 0x414
+       (i32.const 2)
+      )
+     )
+    )
+   )
+   ;; code offset: 0x421
+   (local.set $5
+    ;; code offset: 0x41f
+    (call $malloc
+     ;; code offset: 0x41d
+     (local.get $2)
+    )
+   )
+   ;; code offset: 0x423
+   (block $label$6
+    (block $label$7
+     (block $label$8
+      ;; code offset: 0x42e
+      (if
+       ;; code offset: 0x42d
+       (i32.gt_s
+        ;; code offset: 0x429
+        (local.get $3)
+        ;; code offset: 0x42b
+        (i32.const 0)
+       )
+       (block
+        ;; code offset: 0x430
+        (loop $label$10
+         ;; code offset: 0x43c
+         (i32.store
+          ;; code offset: 0x439
+          (i32.add
+           ;; code offset: 0x432
+           (local.get $1)
+           ;; code offset: 0x438
+           (i32.shl
+            ;; code offset: 0x434
+            (local.get $0)
+            ;; code offset: 0x436
+            (i32.const 2)
+           )
+          )
+          ;; code offset: 0x43a
+          (local.get $0)
+         )
+         ;; code offset: 0x449
+         (br_if $label$10
+          ;; code offset: 0x448
+          (i32.ne
+           ;; code offset: 0x444
+           (local.tee $0
+            ;; code offset: 0x443
+            (i32.add
+             ;; code offset: 0x43f
+             (local.get $0)
+             ;; code offset: 0x441
+             (i32.const 1)
+            )
+           )
+           ;; code offset: 0x446
+           (local.get $3)
+          )
+         )
+        )
+        ;; code offset: 0x44e
+        (local.set $6
+         ;; code offset: 0x44c
+         (i32.const 30)
+        )
+        ;; code offset: 0x452
+        (local.set $2
+         ;; code offset: 0x450
+         (local.get $3)
+        )
+        ;; code offset: 0x454
+        (br $label$8)
+       )
+      )
+      ;; code offset: 0x459
+      (local.set $6
+       ;; code offset: 0x457
+       (i32.const 30)
+      )
+      ;; code offset: 0x45d
+      (local.set $2
+       ;; code offset: 0x45b
+       (local.get $3)
+      )
+      ;; code offset: 0x45f
+      (br $label$7)
+     )
+     ;; code offset: 0x462
+     (loop $label$11
+      ;; code offset: 0x466
+      (local.set $0
+       ;; code offset: 0x464
+       (i32.const 0)
+      )
+      ;; code offset: 0x468
+      (loop $label$12
+       ;; code offset: 0x47a
+       (i32.store offset=16
+        ;; code offset: 0x46a
+        (local.get $8)
+        ;; code offset: 0x479
+        (i32.add
+         ;; code offset: 0x474
+         (i32.load
+          ;; code offset: 0x473
+          (i32.add
+           ;; code offset: 0x46c
+           (local.get $1)
+           ;; code offset: 0x472
+           (i32.shl
+            ;; code offset: 0x46e
+            (local.get $0)
+            ;; code offset: 0x470
+            (i32.const 2)
+           )
+          )
+         )
+         ;; code offset: 0x477
+         (i32.const 1)
+        )
+       )
+       ;; code offset: 0x487
+       (drop
+        ;; code offset: 0x485
+        (call $iprintf
+         ;; code offset: 0x47d
+         (i32.const 1047)
+         ;; code offset: 0x484
+         (i32.add
+          ;; code offset: 0x480
+          (local.get $8)
+          ;; code offset: 0x482
+          (i32.const 16)
+         )
+        )
+       )
+       ;; code offset: 0x492
+       (br_if $label$12
+        ;; code offset: 0x491
+        (i32.ne
+         ;; code offset: 0x48d
+         (local.tee $0
+          ;; code offset: 0x48c
+          (i32.add
+           ;; code offset: 0x488
+           (local.get $0)
+           ;; code offset: 0x48a
+           (i32.const 1)
+          )
+         )
+         ;; code offset: 0x48f
+         (local.get $3)
+        )
+       )
+      )
+      ;; code offset: 0x499
+      (drop
+       ;; code offset: 0x497
+       (call $putchar
+        ;; code offset: 0x495
+        (i32.const 10)
+       )
+      )
+      ;; code offset: 0x49f
+      (if
+       ;; code offset: 0x49e
+       (i32.gt_s
+        ;; code offset: 0x49a
+        (local.get $2)
+        ;; code offset: 0x49c
+        (i32.const 1)
+       )
+       ;; code offset: 0x4a1
+       (loop $label$14
+        ;; code offset: 0x4b2
+        (i32.store
+         ;; code offset: 0x4af
+         (i32.add
+          ;; code offset: 0x4a3
+          (local.get $5)
+          ;; code offset: 0x4ae
+          (i32.shl
+           ;; code offset: 0x4aa
+           (local.tee $0
+            ;; code offset: 0x4a9
+            (i32.add
+             ;; code offset: 0x4a5
+             (local.get $2)
+             ;; code offset: 0x4a7
+             (i32.const -1)
+            )
+           )
+           ;; code offset: 0x4ac
+           (i32.const 2)
+          )
+         )
+         ;; code offset: 0x4b0
+         (local.get $2)
+        )
+        ;; code offset: 0x4ba
+        (local.set $7
+         ;; code offset: 0x4b9
+         (i32.gt_s
+          ;; code offset: 0x4b5
+          (local.get $2)
+          ;; code offset: 0x4b7
+          (i32.const 2)
+         )
+        )
+        ;; code offset: 0x4be
+        (local.set $2
+         ;; code offset: 0x4bc
+         (local.get $0)
+        )
+        ;; code offset: 0x4c2
+        (br_if $label$14
+         ;; code offset: 0x4c0
+         (local.get $7)
+        )
+       )
+      )
+      ;; code offset: 0x4cb
+      (br_if $label$6
+       ;; code offset: 0x4ca
+       (i32.eq
+        ;; code offset: 0x4c6
+        (local.get $2)
+        ;; code offset: 0x4c8
+        (local.get $3)
+       )
+      )
+      ;; code offset: 0x4d2
+      (local.set $6
+       ;; code offset: 0x4d1
+       (i32.add
+        ;; code offset: 0x4cd
+        (local.get $6)
+        ;; code offset: 0x4cf
+        (i32.const -1)
+       )
+      )
+      ;; code offset: 0x4d4
+      (loop $label$15
+       ;; code offset: 0x4d8
+       (local.set $0
+        ;; code offset: 0x4d6
+        (i32.const 0)
+       )
+       ;; code offset: 0x4df
+       (local.set $7
+        ;; code offset: 0x4dc
+        (i32.load
+         ;; code offset: 0x4da
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x4e6
+       (if
+        ;; code offset: 0x4e5
+        (i32.gt_s
+         ;; code offset: 0x4e1
+         (local.get $2)
+         ;; code offset: 0x4e3
+         (i32.const 0)
+        )
+        (block
+         ;; code offset: 0x4e8
+         (loop $label$17
+          ;; code offset: 0x502
+          (i32.store
+           ;; code offset: 0x4f1
+           (i32.add
+            ;; code offset: 0x4ea
+            (local.get $1)
+            ;; code offset: 0x4f0
+            (i32.shl
+             ;; code offset: 0x4ec
+             (local.get $0)
+             ;; code offset: 0x4ee
+             (i32.const 2)
+            )
+           )
+           ;; code offset: 0x4ff
+           (i32.load
+            ;; code offset: 0x4fe
+            (i32.add
+             ;; code offset: 0x4f2
+             (local.get $1)
+             ;; code offset: 0x4fd
+             (i32.shl
+              ;; code offset: 0x4f9
+              (local.tee $0
+               ;; code offset: 0x4f8
+               (i32.add
+                ;; code offset: 0x4f4
+                (local.get $0)
+                ;; code offset: 0x4f6
+                (i32.const 1)
+               )
+              )
+              ;; code offset: 0x4fb
+              (i32.const 2)
+             )
+            )
+           )
+          )
+          ;; code offset: 0x50a
+          (br_if $label$17
+           ;; code offset: 0x509
+           (i32.ne
+            ;; code offset: 0x505
+            (local.get $0)
+            ;; code offset: 0x507
+            (local.get $2)
+           )
+          )
+         )
+         ;; code offset: 0x50f
+         (local.set $0
+          ;; code offset: 0x50d
+          (local.get $2)
+         )
+        )
+       )
+       ;; code offset: 0x51c
+       (i32.store
+        ;; code offset: 0x519
+        (i32.add
+         ;; code offset: 0x512
+         (local.get $1)
+         ;; code offset: 0x518
+         (i32.shl
+          ;; code offset: 0x514
+          (local.get $0)
+          ;; code offset: 0x516
+          (i32.const 2)
+         )
+        )
+        ;; code offset: 0x51a
+        (local.get $7)
+       )
+       ;; code offset: 0x533
+       (i32.store
+        ;; code offset: 0x527
+        (local.tee $0
+         ;; code offset: 0x526
+         (i32.add
+          ;; code offset: 0x51f
+          (local.get $5)
+          ;; code offset: 0x525
+          (i32.shl
+           ;; code offset: 0x521
+           (local.get $2)
+           ;; code offset: 0x523
+           (i32.const 2)
+          )
+         )
+        )
+        ;; code offset: 0x532
+        (i32.add
+         ;; code offset: 0x52e
+         (local.tee $0
+          ;; code offset: 0x52b
+          (i32.load
+           ;; code offset: 0x529
+           (local.get $0)
+          )
+         )
+         ;; code offset: 0x530
+         (i32.const -1)
+        )
+       )
+       ;; code offset: 0x53b
+       (if
+        ;; code offset: 0x53a
+        (i32.le_s
+         ;; code offset: 0x536
+         (local.get $0)
+         ;; code offset: 0x538
+         (i32.const 1)
+        )
+        (block
+         ;; code offset: 0x547
+         (br_if $label$15
+          ;; code offset: 0x546
+          (i32.ne
+           ;; code offset: 0x542
+           (local.tee $2
+            ;; code offset: 0x541
+            (i32.add
+             ;; code offset: 0x53d
+             (local.get $2)
+             ;; code offset: 0x53f
+             (i32.const 1)
+            )
+           )
+           ;; code offset: 0x544
+           (local.get $3)
+          )
+         )
+         ;; code offset: 0x549
+         (br $label$6)
+        )
+       )
+      )
+      ;; code offset: 0x54f
+      (br_if $label$11
+       ;; code offset: 0x54d
+       (local.get $6)
+      )
+     )
+     ;; code offset: 0x552
+     (br $label$6)
+    )
+    ;; code offset: 0x555
+    (loop $label$19
+     ;; code offset: 0x55b
+     (drop
+      ;; code offset: 0x559
+      (call $putchar
+       ;; code offset: 0x557
+       (i32.const 10)
+      )
+     )
+     ;; code offset: 0x561
+     (if
+      ;; code offset: 0x560
+      (i32.gt_s
+       ;; code offset: 0x55c
+       (local.get $2)
+       ;; code offset: 0x55e
+       (i32.const 1)
+      )
+      ;; code offset: 0x563
+      (loop $label$21
+       ;; code offset: 0x574
+       (i32.store
+        ;; code offset: 0x571
+        (i32.add
+         ;; code offset: 0x565
+         (local.get $5)
+         ;; code offset: 0x570
+         (i32.shl
+          ;; code offset: 0x56c
+          (local.tee $0
+           ;; code offset: 0x56b
+           (i32.add
+            ;; code offset: 0x567
+            (local.get $2)
+            ;; code offset: 0x569
+            (i32.const -1)
+           )
+          )
+          ;; code offset: 0x56e
+          (i32.const 2)
+         )
+        )
+        ;; code offset: 0x572
+        (local.get $2)
+       )
+       ;; code offset: 0x57c
+       (local.set $7
+        ;; code offset: 0x57b
+        (i32.gt_s
+         ;; code offset: 0x577
+         (local.get $2)
+         ;; code offset: 0x579
+         (i32.const 2)
+        )
+       )
+       ;; code offset: 0x580
+       (local.set $2
+        ;; code offset: 0x57e
+        (local.get $0)
+       )
+       ;; code offset: 0x584
+       (br_if $label$21
+        ;; code offset: 0x582
+        (local.get $7)
+       )
+      )
+     )
+     ;; code offset: 0x58d
+     (br_if $label$6
+      ;; code offset: 0x58c
+      (i32.eq
+       ;; code offset: 0x588
+       (local.get $2)
+       ;; code offset: 0x58a
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x594
+     (local.set $6
+      ;; code offset: 0x593
+      (i32.add
+       ;; code offset: 0x58f
+       (local.get $6)
+       ;; code offset: 0x591
+       (i32.const -1)
+      )
+     )
+     ;; code offset: 0x596
+     (loop $label$22
+      ;; code offset: 0x59d
+      (local.set $7
+       ;; code offset: 0x59a
+       (i32.load
+        ;; code offset: 0x598
+        (local.get $1)
+       )
+      )
+      ;; code offset: 0x5a1
+      (local.set $0
+       ;; code offset: 0x59f
+       (i32.const 0)
+      )
+      ;; code offset: 0x5a8
+      (if
+       ;; code offset: 0x5a7
+       (i32.ge_s
+        ;; code offset: 0x5a3
+        (local.get $2)
+        ;; code offset: 0x5a5
+        (i32.const 1)
+       )
+       (block
+        ;; code offset: 0x5aa
+        (loop $label$24
+         ;; code offset: 0x5c4
+         (i32.store
+          ;; code offset: 0x5b3
+          (i32.add
+           ;; code offset: 0x5ac
+           (local.get $1)
+           ;; code offset: 0x5b2
+           (i32.shl
+            ;; code offset: 0x5ae
+            (local.get $0)
+            ;; code offset: 0x5b0
+            (i32.const 2)
+           )
+          )
+          ;; code offset: 0x5c1
+          (i32.load
+           ;; code offset: 0x5c0
+           (i32.add
+            ;; code offset: 0x5b4
+            (local.get $1)
+            ;; code offset: 0x5bf
+            (i32.shl
+             ;; code offset: 0x5bb
+             (local.tee $0
+              ;; code offset: 0x5ba
+              (i32.add
+               ;; code offset: 0x5b6
+               (local.get $0)
+               ;; code offset: 0x5b8
+               (i32.const 1)
+              )
+             )
+             ;; code offset: 0x5bd
+             (i32.const 2)
+            )
+           )
+          )
+         )
+         ;; code offset: 0x5cc
+         (br_if $label$24
+          ;; code offset: 0x5cb
+          (i32.ne
+           ;; code offset: 0x5c7
+           (local.get $0)
+           ;; code offset: 0x5c9
+           (local.get $2)
+          )
+         )
+        )
+        ;; code offset: 0x5d1
+        (local.set $0
+         ;; code offset: 0x5cf
+         (local.get $2)
+        )
+       )
+      )
+      ;; code offset: 0x5de
+      (i32.store
+       ;; code offset: 0x5db
+       (i32.add
+        ;; code offset: 0x5d4
+        (local.get $1)
+        ;; code offset: 0x5da
+        (i32.shl
+         ;; code offset: 0x5d6
+         (local.get $0)
+         ;; code offset: 0x5d8
+         (i32.const 2)
+        )
+       )
+       ;; code offset: 0x5dc
+       (local.get $7)
+      )
+      ;; code offset: 0x5f5
+      (i32.store
+       ;; code offset: 0x5e9
+       (local.tee $0
+        ;; code offset: 0x5e8
+        (i32.add
+         ;; code offset: 0x5e1
+         (local.get $5)
+         ;; code offset: 0x5e7
+         (i32.shl
+          ;; code offset: 0x5e3
+          (local.get $2)
+          ;; code offset: 0x5e5
+          (i32.const 2)
+         )
+        )
+       )
+       ;; code offset: 0x5f4
+       (i32.add
+        ;; code offset: 0x5f0
+        (local.tee $0
+         ;; code offset: 0x5ed
+         (i32.load
+          ;; code offset: 0x5eb
+          (local.get $0)
+         )
+        )
+        ;; code offset: 0x5f2
+        (i32.const -1)
+       )
+      )
+      ;; code offset: 0x5fd
+      (if
+       ;; code offset: 0x5fc
+       (i32.le_s
+        ;; code offset: 0x5f8
+        (local.get $0)
+        ;; code offset: 0x5fa
+        (i32.const 1)
+       )
+       (block
+        ;; code offset: 0x609
+        (br_if $label$22
+         ;; code offset: 0x608
+         (i32.ne
+          ;; code offset: 0x604
+          (local.tee $2
+           ;; code offset: 0x603
+           (i32.add
+            ;; code offset: 0x5ff
+            (local.get $2)
+            ;; code offset: 0x601
+            (i32.const 1)
+           )
+          )
+          ;; code offset: 0x606
+          (local.get $3)
+         )
+        )
+        ;; code offset: 0x60b
+        (br $label$6)
+       )
+      )
+     )
+     ;; code offset: 0x611
+     (br_if $label$19
+      ;; code offset: 0x60f
+      (local.get $6)
+     )
+    )
+   )
+   ;; code offset: 0x617
+   (call $free
+    ;; code offset: 0x615
+    (local.get $1)
+   )
+   ;; code offset: 0x61b
+   (call $free
+    ;; code offset: 0x619
+    (local.get $5)
+   )
+   ;; code offset: 0x61f
+   (local.set $5
+    ;; code offset: 0x61d
+    (i32.const 0)
+   )
+   ;; code offset: 0x623
+   (local.set $0
+    ;; code offset: 0x621
+    (i32.const 0)
+   )
+   ;; code offset: 0x627
+   (if
+    ;; code offset: 0x625
+    (local.get $4)
+    ;; code offset: 0x629
+    (loop $label$27
+     ;; code offset: 0x62f
+     (local.set $1
+      ;; code offset: 0x62d
+      (call $fannkuch_worker\28void*\29
+       ;; code offset: 0x62b
+       (local.get $4)
+      )
+     )
+     ;; code offset: 0x636
+     (local.set $2
+      ;; code offset: 0x633
+      (i32.load offset=8
+       ;; code offset: 0x631
+       (local.get $4)
+      )
+     )
+     ;; code offset: 0x63a
+     (call $free
+      ;; code offset: 0x638
+      (local.get $4)
+     )
+     ;; code offset: 0x646
+     (local.set $0
+      ;; code offset: 0x645
+      (select
+       ;; code offset: 0x63c
+       (local.get $1)
+       ;; code offset: 0x63e
+       (local.get $0)
+       ;; code offset: 0x644
+       (i32.lt_s
+        ;; code offset: 0x640
+        (local.get $0)
+        ;; code offset: 0x642
+        (local.get $1)
+       )
+      )
+     )
+     ;; code offset: 0x64a
+     (local.set $4
+      ;; code offset: 0x648
+      (local.get $2)
+     )
+     ;; code offset: 0x64e
+     (br_if $label$27
+      ;; code offset: 0x64c
+      (local.get $2)
+     )
+    )
+   )
+   ;; code offset: 0x656
+   (i32.store offset=4
+    ;; code offset: 0x652
+    (local.get $8)
+    ;; code offset: 0x654
+    (local.get $0)
+   )
+   ;; code offset: 0x65d
+   (i32.store
+    ;; code offset: 0x659
+    (local.get $8)
+    ;; code offset: 0x65b
+    (local.get $3)
+   )
+   ;; code offset: 0x667
+   (drop
+    ;; code offset: 0x665
+    (call $iprintf
+     ;; code offset: 0x660
+     (i32.const 1024)
+     ;; code offset: 0x663
+     (local.get $8)
+    )
+   )
+  )
+  ;; code offset: 0x66e
+  (global.set $global$0
+   ;; code offset: 0x66d
+   (i32.add
+    ;; code offset: 0x669
+    (local.get $8)
+    ;; code offset: 0x66b
+    (i32.const 32)
+   )
+  )
+  ;; code offset: 0x670
+  (local.get $5)
+ )
+ ;; custom section ".debug_info", size 851
+ ;; 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_str", size 434
+ ;; custom section "producers", size 135
+)
diff --git a/binaryen/test/passes/fannkuch3_manyopts_dwarf.passes b/binaryen/test/passes/fannkuch3_manyopts_dwarf.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fannkuch3_manyopts_dwarf.passes
@@ -0,0 +1,1 @@
+dwarfdump_O4_roundtrip_dwarfdump_g
diff --git a/binaryen/test/passes/fannkuch3_manyopts_dwarf.wasm b/binaryen/test/passes/fannkuch3_manyopts_dwarf.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/fannkuch3_manyopts_dwarf.wasm differ
diff --git a/binaryen/test/passes/fib2_dwarf.bin.txt b/binaryen/test/passes/fib2_dwarf.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fib2_dwarf.bin.txt
@@ -0,0 +1,722 @@
+DWARF debug info
+================
+
+Contains section .debug_info (168 bytes)
+Contains section .debug_loc (143 bytes)
+Contains section .debug_ranges (24 bytes)
+Contains section .debug_abbrev (131 bytes)
+Contains section .debug_line (106 bytes)
+Contains section .debug_str (180 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[2] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_prototyped	DW_FORM_flag_present
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[3] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[4] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[5] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[6] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[7] DW_TAG_GNU_call_site	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+
+[8] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x000000a4 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x000000a8)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C99)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000069] = "fib2.c")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x00000070] = "/usr/local/google/home/azakai/Dev/2-binaryen")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+              DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
+                 [0x00000005, 0x0000003d)
+                 [0x0000003e, 0x00000048))
+
+0x00000026:   DW_TAG_subprogram [2] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000005)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000038)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x1 +0, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000009d] = "fib")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                DW_AT_decl_line [DW_FORM_data1]	(1)
+                DW_AT_prototyped [DW_FORM_flag_present]	(true)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000003e:     DW_TAG_formal_parameter [3]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000aa] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(1)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000049:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000000: 
+                     [0xffffffff,  0x00000005): 
+                     [0x00000007,  0x00000010): DW_OP_consts +0, DW_OP_stack_value
+                     [0x0000001e,  0x00000033): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ac] = "a")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000058:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000002b: 
+                     [0xffffffff,  0x00000005): 
+                     [0x00000007,  0x00000010): DW_OP_consts +1, DW_OP_stack_value
+                     [0x0000001e,  0x00000023): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+                     [0x00000023,  0x00000033): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ae] = "b")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000067:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000064: 
+                     [0xffffffff,  0x00000005): 
+                     [0x00000007,  0x00000010): DW_OP_consts +0, DW_OP_stack_value
+                     [0x0000002e,  0x00000033): DW_OP_WASM_location 0x0 +3, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000b0] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000076:     DW_TAG_variable [5]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000b2] = "t")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000081:     NULL
+
+0x00000082:   DW_TAG_subprogram [6] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x000000000000003e)
+                DW_AT_high_pc [DW_FORM_data4]	(0x0000000a)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x1 +0, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000a5] = "main")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                DW_AT_decl_line [DW_FORM_data1]	(11)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000009a:     DW_TAG_GNU_call_site [7]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000047)
+
+0x0000009f:     NULL
+
+0x000000a0:   DW_TAG_base_type [8]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000a1] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x000000a7:   NULL
+
+.debug_loc contents:
+0x00000000: 
+            [0xffffffff,  0x00000005): 
+            [0x00000007,  0x00000010): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000001e,  0x00000033): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+
+0x0000002b: 
+            [0xffffffff,  0x00000005): 
+            [0x00000007,  0x00000010): DW_OP_consts +1, DW_OP_stack_value
+            [0x0000001e,  0x00000023): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+            [0x00000023,  0x00000033): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000064: 
+            [0xffffffff,  0x00000005): 
+            [0x00000007,  0x00000010): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000002e,  0x00000033): DW_OP_WASM_location 0x0 +3, DW_OP_stack_value
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x00000066
+         version: 4
+ prologue_length: 0x0000001e
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "fib2.c"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000028: 00 DW_LNE_set_address (0x0000000000000005)
+0x0000002f: 01 DW_LNS_copy
+            0x0000000000000005      1      0      1   0             0  is_stmt
+
+
+0x00000030: 05 DW_LNS_set_column (17)
+0x00000032: 0a DW_LNS_set_prologue_end
+0x00000033: 92 address += 9,  line += 2
+            0x000000000000000e      3     17      1   0             0  is_stmt prologue_end
+
+0x00000034: 05 DW_LNS_set_column (3)
+0x00000036: 06 DW_LNS_negate_stmt
+0x00000037: 58 address += 5,  line += 0
+            0x0000000000000013      3      3      1   0             0 
+
+0x00000038: 2b address += 2,  line += -3
+            0x0000000000000015      0      3      1   0             0 
+
+0x00000039: 05 DW_LNS_set_column (7)
+0x0000003b: 06 DW_LNS_negate_stmt
+0x0000003c: c0 address += 12,  line += 6
+            0x0000000000000021      6      7      1   0             0  is_stmt
+
+0x0000003d: 06 DW_LNS_negate_stmt
+0x0000003e: 03 DW_LNS_advance_line (0)
+0x00000040: 74 address += 7,  line += 0
+            0x0000000000000028      0      7      1   0             0 
+
+0x00000041: 05 DW_LNS_set_column (23)
+0x00000043: 06 DW_LNS_negate_stmt
+0x00000044: 4d address += 4,  line += 3
+            0x000000000000002c      3     23      1   0             0  is_stmt
+
+0x00000045: 05 DW_LNS_set_column (17)
+0x00000047: 06 DW_LNS_negate_stmt
+0x00000048: 58 address += 5,  line += 0
+            0x0000000000000031      3     17      1   0             0 
+
+0x00000049: 05 DW_LNS_set_column (3)
+0x0000004b: 58 address += 5,  line += 0
+            0x0000000000000036      3      3      1   0             0 
+
+0x0000004c: 06 DW_LNS_negate_stmt
+0x0000004d: 4f address += 4,  line += 5
+            0x000000000000003a      8      3      1   0             0  is_stmt
+
+0x0000004e: 02 DW_LNS_advance_pc (3)
+0x00000050: 00 DW_LNE_end_sequence
+            0x000000000000003d      8      3      1   0             0  is_stmt end_sequence
+
+0x00000053: 00 DW_LNE_set_address (0x000000000000003e)
+0x0000005a: 03 DW_LNS_advance_line (11)
+0x0000005c: 01 DW_LNS_copy
+            0x000000000000003e     11      0      1   0             0  is_stmt
+
+
+0x0000005d: 05 DW_LNS_set_column (10)
+0x0000005f: 0a DW_LNS_set_prologue_end
+0x00000060: 3d address += 3,  line += 1
+            0x0000000000000041     12     10      1   0             0  is_stmt prologue_end
+
+0x00000061: 05 DW_LNS_set_column (3)
+0x00000063: 06 DW_LNS_negate_stmt
+0x00000064: 66 address += 6,  line += 0
+            0x0000000000000047     12      3      1   0             0 
+
+0x00000065: 02 DW_LNS_advance_pc (1)
+0x00000067: 00 DW_LNE_end_sequence
+            0x0000000000000048     12      3      1   0             0  end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)"
+0x00000069: "fib2.c"
+0x00000070: "/usr/local/google/home/azakai/Dev/2-binaryen"
+0x0000009d: "fib"
+0x000000a1: "int"
+0x000000a5: "main"
+0x000000aa: "n"
+0x000000ac: "a"
+0x000000ae: "b"
+0x000000b0: "i"
+0x000000b2: "t"
+
+.debug_ranges contents:
+00000000 00000005 0000003d
+00000000 0000003e 00000048
+00000000 <End of list>
+DWARF debug info
+================
+
+Contains section .debug_info (168 bytes)
+Contains section .debug_loc (143 bytes)
+Contains section .debug_ranges (24 bytes)
+Contains section .debug_abbrev (131 bytes)
+Contains section .debug_line (183 bytes)
+Contains section .debug_str (180 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[2] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_prototyped	DW_FORM_flag_present
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[3] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[4] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[5] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[6] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[7] DW_TAG_GNU_call_site	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+
+[8] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x000000a4 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x000000a8)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C99)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000069] = "fib2.c")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x00000070] = "/usr/local/google/home/azakai/Dev/2-binaryen")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+              DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
+                 [0x00000005, 0x00000043)
+                 [0x00000044, 0x0000004a))
+
+0x00000026:   DW_TAG_subprogram [2] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000005)
+                DW_AT_high_pc [DW_FORM_data4]	(0x0000003e)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x1 +0, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000009d] = "fib")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                DW_AT_decl_line [DW_FORM_data1]	(1)
+                DW_AT_prototyped [DW_FORM_flag_present]	(true)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000003e:     DW_TAG_formal_parameter [3]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000aa] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(1)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000049:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000000: 
+                     [0xffffffff,  0x00000012): 
+                     [0x00000000,  0x00000009): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000017,  0x0000002c): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ac] = "a")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000058:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000002b: 
+                     [0xffffffff,  0x00000012): 
+                     [0x00000000,  0x00000009): DW_OP_consts +1, DW_OP_stack_value
+                     [0x00000017,  0x0000001c): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+                     [0x0000001c,  0x0000002c): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ae] = "b")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000067:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000064: 
+                     [0xffffffff,  0x00000012): 
+                     [0x00000000,  0x00000009): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000027,  0x0000002c): DW_OP_WASM_location 0x0 +3, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000b0] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000076:     DW_TAG_variable [5]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000b2] = "t")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000081:     NULL
+
+0x00000082:   DW_TAG_subprogram [6] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000044)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000006)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x1 +0, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000a5] = "main")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                DW_AT_decl_line [DW_FORM_data1]	(11)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000009a:     DW_TAG_GNU_call_site [7]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+
+0x0000009f:     NULL
+
+0x000000a0:   DW_TAG_base_type [8]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000a1] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x000000a7:   NULL
+
+.debug_loc contents:
+0x00000000: 
+            [0xffffffff,  0x00000012): 
+            [0x00000000,  0x00000009): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000017,  0x0000002c): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+
+0x0000002b: 
+            [0xffffffff,  0x00000012): 
+            [0x00000000,  0x00000009): DW_OP_consts +1, DW_OP_stack_value
+            [0x00000017,  0x0000001c): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+            [0x0000001c,  0x0000002c): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000064: 
+            [0xffffffff,  0x00000012): 
+            [0x00000000,  0x00000009): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000027,  0x0000002c): DW_OP_WASM_location 0x0 +3, DW_OP_stack_value
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x000000b3
+         version: 4
+ prologue_length: 0x0000001e
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "fib2.c"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000028: 00 DW_LNE_set_address (0x0000000000000005)
+0x0000002f: 01 DW_LNS_copy
+            0x0000000000000005      1      0      1   0             0  is_stmt
+
+
+0x00000030: 00 DW_LNE_set_address (0x0000000000000014)
+0x00000037: 03 DW_LNS_advance_line (3)
+0x00000039: 05 DW_LNS_set_column (17)
+0x0000003b: 0a DW_LNS_set_prologue_end
+0x0000003c: 01 DW_LNS_copy
+            0x0000000000000014      3     17      1   0             0  is_stmt prologue_end
+
+
+0x0000003d: 00 DW_LNE_set_address (0x0000000000000019)
+0x00000044: 05 DW_LNS_set_column (3)
+0x00000046: 06 DW_LNS_negate_stmt
+0x00000047: 01 DW_LNS_copy
+            0x0000000000000019      3      3      1   0             0 
+
+
+0x00000048: 00 DW_LNE_set_address (0x0000000000000027)
+0x0000004f: 03 DW_LNS_advance_line (6)
+0x00000051: 05 DW_LNS_set_column (7)
+0x00000053: 06 DW_LNS_negate_stmt
+0x00000054: 01 DW_LNS_copy
+            0x0000000000000027      6      7      1   0             0  is_stmt
+
+
+0x00000055: 00 DW_LNE_set_address (0x0000000000000032)
+0x0000005c: 03 DW_LNS_advance_line (3)
+0x0000005e: 05 DW_LNS_set_column (23)
+0x00000060: 01 DW_LNS_copy
+            0x0000000000000032      3     23      1   0             0  is_stmt
+
+
+0x00000061: 00 DW_LNE_set_address (0x0000000000000037)
+0x00000068: 05 DW_LNS_set_column (17)
+0x0000006a: 06 DW_LNS_negate_stmt
+0x0000006b: 01 DW_LNS_copy
+            0x0000000000000037      3     17      1   0             0 
+
+
+0x0000006c: 00 DW_LNE_set_address (0x000000000000003c)
+0x00000073: 05 DW_LNS_set_column (3)
+0x00000075: 01 DW_LNS_copy
+            0x000000000000003c      3      3      1   0             0 
+
+
+0x00000076: 00 DW_LNE_set_address (0x0000000000000040)
+0x0000007d: 03 DW_LNS_advance_line (8)
+0x0000007f: 06 DW_LNS_negate_stmt
+0x00000080: 01 DW_LNS_copy
+            0x0000000000000040      8      3      1   0             0  is_stmt
+
+
+0x00000081: 00 DW_LNE_set_address (0x0000000000000043)
+0x00000088: 00 DW_LNE_end_sequence
+            0x0000000000000043      8      3      1   0             0  is_stmt end_sequence
+
+0x0000008b: 00 DW_LNE_set_address (0x0000000000000044)
+0x00000092: 03 DW_LNS_advance_line (11)
+0x00000094: 01 DW_LNS_copy
+            0x0000000000000044     11      0      1   0             0  is_stmt
+
+
+0x00000095: 00 DW_LNE_set_address (0x0000000000000047)
+0x0000009c: 03 DW_LNS_advance_line (12)
+0x0000009e: 05 DW_LNS_set_column (10)
+0x000000a0: 0a DW_LNS_set_prologue_end
+0x000000a1: 01 DW_LNS_copy
+            0x0000000000000047     12     10      1   0             0  is_stmt prologue_end
+
+
+0x000000a2: 00 DW_LNE_set_address (0x0000000000000049)
+0x000000a9: 05 DW_LNS_set_column (3)
+0x000000ab: 06 DW_LNS_negate_stmt
+0x000000ac: 01 DW_LNS_copy
+            0x0000000000000049     12      3      1   0             0 
+
+
+0x000000ad: 00 DW_LNE_set_address (0x000000000000004a)
+0x000000b4: 00 DW_LNE_end_sequence
+            0x000000000000004a     12      3      1   0             0  end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)"
+0x00000069: "fib2.c"
+0x00000070: "/usr/local/google/home/azakai/Dev/2-binaryen"
+0x0000009d: "fib"
+0x000000a1: "int"
+0x000000a5: "main"
+0x000000aa: "n"
+0x000000ac: "a"
+0x000000ae: "b"
+0x000000b0: "i"
+0x000000b2: "t"
+
+.debug_ranges contents:
+00000000 00000005 00000043
+00000000 00000044 0000004a
+00000000 <End of list>
+(module
+ (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)))
+ (import "env" "memory" (memory $mimport$0 256 256))
+ (import "env" "__indirect_function_table" (table $timport$1 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))
+ (export "main" (func $main))
+ (export "__data_end" (global $global$1))
+ (func $__wasm_call_ctors
+ )
+ (func $fib (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  ;; code offset: 0x10
+  (local.set $1
+   ;; code offset: 0xe
+   (i32.const 1)
+  )
+  ;; code offset: 0x12
+  (block $label$1
+   ;; code offset: 0x19
+   (br_if $label$1
+    ;; code offset: 0x18
+    (i32.lt_s
+     ;; code offset: 0x14
+     (local.get $0)
+     ;; code offset: 0x16
+     (i32.const 1)
+    )
+   )
+   ;; code offset: 0x1d
+   (local.set $2
+    ;; code offset: 0x1b
+    (i32.const 0)
+   )
+   ;; code offset: 0x21
+   (local.set $3
+    ;; code offset: 0x1f
+    (i32.const 0)
+   )
+   ;; code offset: 0x23
+   (loop $label$2
+    ;; code offset: 0x2c
+    (local.set $1
+     ;; code offset: 0x2b
+     (i32.add
+      ;; code offset: 0x27
+      (local.tee $4
+       ;; code offset: 0x25
+       (local.get $1)
+      )
+      ;; code offset: 0x29
+      (local.get $2)
+     )
+    )
+    ;; code offset: 0x30
+    (local.set $2
+     ;; code offset: 0x2e
+     (local.get $4)
+    )
+    ;; code offset: 0x3c
+    (br_if $label$2
+     ;; code offset: 0x3b
+     (i32.ne
+      ;; code offset: 0x37
+      (local.tee $3
+       ;; code offset: 0x36
+       (i32.add
+        ;; code offset: 0x32
+        (local.get $3)
+        ;; code offset: 0x34
+        (i32.const 1)
+       )
+      )
+      ;; code offset: 0x39
+      (local.get $0)
+     )
+    )
+   )
+  )
+  ;; code offset: 0x40
+  (local.get $1)
+ )
+ (func $__original_main (result i32)
+  ;; code offset: 0x47
+  (call $fib
+   ;; code offset: 0x45
+   (i32.const 6)
+  )
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  ;; code offset: 0x4c
+  (call $__original_main)
+ )
+ ;; custom section ".debug_info", size 168
+ ;; custom section ".debug_loc", size 143
+ ;; custom section ".debug_ranges", size 24
+ ;; custom section ".debug_abbrev", size 131
+ ;; custom section ".debug_line", size 183
+ ;; custom section ".debug_str", size 180
+ ;; custom section "producers", size 127
+)
diff --git a/binaryen/test/passes/fib2_dwarf.passes b/binaryen/test/passes/fib2_dwarf.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fib2_dwarf.passes
@@ -0,0 +1,1 @@
+dwarfdump_roundtrip_dwarfdump_g
diff --git a/binaryen/test/passes/fib2_dwarf.wasm b/binaryen/test/passes/fib2_dwarf.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/fib2_dwarf.wasm differ
diff --git a/binaryen/test/passes/fib2_emptylocspan_dwarf.bin.txt b/binaryen/test/passes/fib2_emptylocspan_dwarf.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fib2_emptylocspan_dwarf.bin.txt
@@ -0,0 +1,722 @@
+DWARF debug info
+================
+
+Contains section .debug_info (168 bytes)
+Contains section .debug_loc (143 bytes)
+Contains section .debug_ranges (24 bytes)
+Contains section .debug_abbrev (131 bytes)
+Contains section .debug_line (106 bytes)
+Contains section .debug_str (180 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[2] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_prototyped	DW_FORM_flag_present
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[3] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[4] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[5] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[6] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[7] DW_TAG_GNU_call_site	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+
+[8] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x000000a4 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x000000a8)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C99)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000069] = "fib2.c")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x00000070] = "/usr/local/google/home/azakai/Dev/2-binaryen")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+              DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
+                 [0x00000005, 0x0000003d)
+                 [0x0000003e, 0x00000048))
+
+0x00000026:   DW_TAG_subprogram [2] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000005)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000038)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x1 +0, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000009d] = "fib")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                DW_AT_decl_line [DW_FORM_data1]	(1)
+                DW_AT_prototyped [DW_FORM_flag_present]	(true)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000003e:     DW_TAG_formal_parameter [3]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000aa] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(1)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000049:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000000: 
+                     [0xffffffff,  0x00000005): 
+                     [0x00000007,  0x00000007): DW_OP_consts +0, DW_OP_stack_value
+                     [0x0000001e,  0x0000001e): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ac] = "a")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000058:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000002b: 
+                     [0xffffffff,  0x00000005): 
+                     [0x00000007,  0x00000010): DW_OP_consts +1, DW_OP_stack_value
+                     [0x0000001e,  0x00000023): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+                     [0x00000023,  0x00000033): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ae] = "b")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000067:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000064: 
+                     [0xffffffff,  0x00000005): 
+                     [0x00000007,  0x00000010): DW_OP_consts +0, DW_OP_stack_value
+                     [0x0000002e,  0x00000033): DW_OP_WASM_location 0x0 +3, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000b0] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000076:     DW_TAG_variable [5]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000b2] = "t")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000081:     NULL
+
+0x00000082:   DW_TAG_subprogram [6] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x000000000000003e)
+                DW_AT_high_pc [DW_FORM_data4]	(0x0000000a)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x1 +0, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000a5] = "main")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                DW_AT_decl_line [DW_FORM_data1]	(11)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000009a:     DW_TAG_GNU_call_site [7]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000047)
+
+0x0000009f:     NULL
+
+0x000000a0:   DW_TAG_base_type [8]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000a1] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x000000a7:   NULL
+
+.debug_loc contents:
+0x00000000: 
+            [0xffffffff,  0x00000005): 
+            [0x00000007,  0x00000007): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000001e,  0x0000001e): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+
+0x0000002b: 
+            [0xffffffff,  0x00000005): 
+            [0x00000007,  0x00000010): DW_OP_consts +1, DW_OP_stack_value
+            [0x0000001e,  0x00000023): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+            [0x00000023,  0x00000033): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000064: 
+            [0xffffffff,  0x00000005): 
+            [0x00000007,  0x00000010): DW_OP_consts +0, DW_OP_stack_value
+            [0x0000002e,  0x00000033): DW_OP_WASM_location 0x0 +3, DW_OP_stack_value
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x00000066
+         version: 4
+ prologue_length: 0x0000001e
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "fib2.c"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000028: 00 DW_LNE_set_address (0x0000000000000005)
+0x0000002f: 01 DW_LNS_copy
+            0x0000000000000005      1      0      1   0             0  is_stmt
+
+
+0x00000030: 05 DW_LNS_set_column (17)
+0x00000032: 0a DW_LNS_set_prologue_end
+0x00000033: 92 address += 9,  line += 2
+            0x000000000000000e      3     17      1   0             0  is_stmt prologue_end
+
+0x00000034: 05 DW_LNS_set_column (3)
+0x00000036: 06 DW_LNS_negate_stmt
+0x00000037: 58 address += 5,  line += 0
+            0x0000000000000013      3      3      1   0             0 
+
+0x00000038: 2b address += 2,  line += -3
+            0x0000000000000015      0      3      1   0             0 
+
+0x00000039: 05 DW_LNS_set_column (7)
+0x0000003b: 06 DW_LNS_negate_stmt
+0x0000003c: c0 address += 12,  line += 6
+            0x0000000000000021      6      7      1   0             0  is_stmt
+
+0x0000003d: 06 DW_LNS_negate_stmt
+0x0000003e: 03 DW_LNS_advance_line (0)
+0x00000040: 74 address += 7,  line += 0
+            0x0000000000000028      0      7      1   0             0 
+
+0x00000041: 05 DW_LNS_set_column (23)
+0x00000043: 06 DW_LNS_negate_stmt
+0x00000044: 4d address += 4,  line += 3
+            0x000000000000002c      3     23      1   0             0  is_stmt
+
+0x00000045: 05 DW_LNS_set_column (17)
+0x00000047: 06 DW_LNS_negate_stmt
+0x00000048: 58 address += 5,  line += 0
+            0x0000000000000031      3     17      1   0             0 
+
+0x00000049: 05 DW_LNS_set_column (3)
+0x0000004b: 58 address += 5,  line += 0
+            0x0000000000000036      3      3      1   0             0 
+
+0x0000004c: 06 DW_LNS_negate_stmt
+0x0000004d: 4f address += 4,  line += 5
+            0x000000000000003a      8      3      1   0             0  is_stmt
+
+0x0000004e: 02 DW_LNS_advance_pc (3)
+0x00000050: 00 DW_LNE_end_sequence
+            0x000000000000003d      8      3      1   0             0  is_stmt end_sequence
+
+0x00000053: 00 DW_LNE_set_address (0x000000000000003e)
+0x0000005a: 03 DW_LNS_advance_line (11)
+0x0000005c: 01 DW_LNS_copy
+            0x000000000000003e     11      0      1   0             0  is_stmt
+
+
+0x0000005d: 05 DW_LNS_set_column (10)
+0x0000005f: 0a DW_LNS_set_prologue_end
+0x00000060: 3d address += 3,  line += 1
+            0x0000000000000041     12     10      1   0             0  is_stmt prologue_end
+
+0x00000061: 05 DW_LNS_set_column (3)
+0x00000063: 06 DW_LNS_negate_stmt
+0x00000064: 66 address += 6,  line += 0
+            0x0000000000000047     12      3      1   0             0 
+
+0x00000065: 02 DW_LNS_advance_pc (1)
+0x00000067: 00 DW_LNE_end_sequence
+            0x0000000000000048     12      3      1   0             0  end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)"
+0x00000069: "fib2.c"
+0x00000070: "/usr/local/google/home/azakai/Dev/2-binaryen"
+0x0000009d: "fib"
+0x000000a1: "int"
+0x000000a5: "main"
+0x000000aa: "n"
+0x000000ac: "a"
+0x000000ae: "b"
+0x000000b0: "i"
+0x000000b2: "t"
+
+.debug_ranges contents:
+00000000 00000005 0000003d
+00000000 0000003e 00000048
+00000000 <End of list>
+DWARF debug info
+================
+
+Contains section .debug_info (168 bytes)
+Contains section .debug_loc (143 bytes)
+Contains section .debug_ranges (24 bytes)
+Contains section .debug_abbrev (131 bytes)
+Contains section .debug_line (183 bytes)
+Contains section .debug_str (180 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[2] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_prototyped	DW_FORM_flag_present
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[3] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[4] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[5] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[6] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[7] DW_TAG_GNU_call_site	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+
+[8] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x000000a4 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x000000a8)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C99)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000069] = "fib2.c")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x00000070] = "/usr/local/google/home/azakai/Dev/2-binaryen")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+              DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
+                 [0x00000005, 0x00000043)
+                 [0x00000044, 0x0000004a))
+
+0x00000026:   DW_TAG_subprogram [2] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000005)
+                DW_AT_high_pc [DW_FORM_data4]	(0x0000003e)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x1 +0, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000009d] = "fib")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                DW_AT_decl_line [DW_FORM_data1]	(1)
+                DW_AT_prototyped [DW_FORM_flag_present]	(true)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000003e:     DW_TAG_formal_parameter [3]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000aa] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(1)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000049:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000000: 
+                     [0xffffffff,  0x00000012): 
+                     [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000017,  0x00000017): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ac] = "a")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000058:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000002b: 
+                     [0xffffffff,  0x00000012): 
+                     [0x00000000,  0x00000009): DW_OP_consts +1, DW_OP_stack_value
+                     [0x00000017,  0x0000001c): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+                     [0x0000001c,  0x0000002c): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ae] = "b")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000067:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000064: 
+                     [0xffffffff,  0x00000012): 
+                     [0x00000000,  0x00000009): DW_OP_consts +0, DW_OP_stack_value
+                     [0x00000027,  0x0000002c): DW_OP_WASM_location 0x0 +3, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000b0] = "i")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000076:     DW_TAG_variable [5]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000b2] = "t")
+                  DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+
+0x00000081:     NULL
+
+0x00000082:   DW_TAG_subprogram [6] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000044)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000006)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x1 +0, DW_OP_stack_value)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000a5] = "main")
+                DW_AT_decl_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/2-binaryen/fib2.c")
+                DW_AT_decl_line [DW_FORM_data1]	(11)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x00a0 => {0x000000a0} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000009a:     DW_TAG_GNU_call_site [7]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+
+0x0000009f:     NULL
+
+0x000000a0:   DW_TAG_base_type [8]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000a1] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x000000a7:   NULL
+
+.debug_loc contents:
+0x00000000: 
+            [0xffffffff,  0x00000012): 
+            [0x00000001,  0x00000001): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000017,  0x00000017): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+
+0x0000002b: 
+            [0xffffffff,  0x00000012): 
+            [0x00000000,  0x00000009): DW_OP_consts +1, DW_OP_stack_value
+            [0x00000017,  0x0000001c): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+            [0x0000001c,  0x0000002c): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000064: 
+            [0xffffffff,  0x00000012): 
+            [0x00000000,  0x00000009): DW_OP_consts +0, DW_OP_stack_value
+            [0x00000027,  0x0000002c): DW_OP_WASM_location 0x0 +3, DW_OP_stack_value
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x000000b3
+         version: 4
+ prologue_length: 0x0000001e
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "fib2.c"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000028: 00 DW_LNE_set_address (0x0000000000000005)
+0x0000002f: 01 DW_LNS_copy
+            0x0000000000000005      1      0      1   0             0  is_stmt
+
+
+0x00000030: 00 DW_LNE_set_address (0x0000000000000014)
+0x00000037: 03 DW_LNS_advance_line (3)
+0x00000039: 05 DW_LNS_set_column (17)
+0x0000003b: 0a DW_LNS_set_prologue_end
+0x0000003c: 01 DW_LNS_copy
+            0x0000000000000014      3     17      1   0             0  is_stmt prologue_end
+
+
+0x0000003d: 00 DW_LNE_set_address (0x0000000000000019)
+0x00000044: 05 DW_LNS_set_column (3)
+0x00000046: 06 DW_LNS_negate_stmt
+0x00000047: 01 DW_LNS_copy
+            0x0000000000000019      3      3      1   0             0 
+
+
+0x00000048: 00 DW_LNE_set_address (0x0000000000000027)
+0x0000004f: 03 DW_LNS_advance_line (6)
+0x00000051: 05 DW_LNS_set_column (7)
+0x00000053: 06 DW_LNS_negate_stmt
+0x00000054: 01 DW_LNS_copy
+            0x0000000000000027      6      7      1   0             0  is_stmt
+
+
+0x00000055: 00 DW_LNE_set_address (0x0000000000000032)
+0x0000005c: 03 DW_LNS_advance_line (3)
+0x0000005e: 05 DW_LNS_set_column (23)
+0x00000060: 01 DW_LNS_copy
+            0x0000000000000032      3     23      1   0             0  is_stmt
+
+
+0x00000061: 00 DW_LNE_set_address (0x0000000000000037)
+0x00000068: 05 DW_LNS_set_column (17)
+0x0000006a: 06 DW_LNS_negate_stmt
+0x0000006b: 01 DW_LNS_copy
+            0x0000000000000037      3     17      1   0             0 
+
+
+0x0000006c: 00 DW_LNE_set_address (0x000000000000003c)
+0x00000073: 05 DW_LNS_set_column (3)
+0x00000075: 01 DW_LNS_copy
+            0x000000000000003c      3      3      1   0             0 
+
+
+0x00000076: 00 DW_LNE_set_address (0x0000000000000040)
+0x0000007d: 03 DW_LNS_advance_line (8)
+0x0000007f: 06 DW_LNS_negate_stmt
+0x00000080: 01 DW_LNS_copy
+            0x0000000000000040      8      3      1   0             0  is_stmt
+
+
+0x00000081: 00 DW_LNE_set_address (0x0000000000000043)
+0x00000088: 00 DW_LNE_end_sequence
+            0x0000000000000043      8      3      1   0             0  is_stmt end_sequence
+
+0x0000008b: 00 DW_LNE_set_address (0x0000000000000044)
+0x00000092: 03 DW_LNS_advance_line (11)
+0x00000094: 01 DW_LNS_copy
+            0x0000000000000044     11      0      1   0             0  is_stmt
+
+
+0x00000095: 00 DW_LNE_set_address (0x0000000000000047)
+0x0000009c: 03 DW_LNS_advance_line (12)
+0x0000009e: 05 DW_LNS_set_column (10)
+0x000000a0: 0a DW_LNS_set_prologue_end
+0x000000a1: 01 DW_LNS_copy
+            0x0000000000000047     12     10      1   0             0  is_stmt prologue_end
+
+
+0x000000a2: 00 DW_LNE_set_address (0x0000000000000049)
+0x000000a9: 05 DW_LNS_set_column (3)
+0x000000ab: 06 DW_LNS_negate_stmt
+0x000000ac: 01 DW_LNS_copy
+            0x0000000000000049     12      3      1   0             0 
+
+
+0x000000ad: 00 DW_LNE_set_address (0x000000000000004a)
+0x000000b4: 00 DW_LNE_end_sequence
+            0x000000000000004a     12      3      1   0             0  end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 313d89724ce3ccf66c1c51849903e1e6d184dd85)"
+0x00000069: "fib2.c"
+0x00000070: "/usr/local/google/home/azakai/Dev/2-binaryen"
+0x0000009d: "fib"
+0x000000a1: "int"
+0x000000a5: "main"
+0x000000aa: "n"
+0x000000ac: "a"
+0x000000ae: "b"
+0x000000b0: "i"
+0x000000b2: "t"
+
+.debug_ranges contents:
+00000000 00000005 00000043
+00000000 00000044 0000004a
+00000000 <End of list>
+(module
+ (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)))
+ (import "env" "memory" (memory $mimport$0 256 256))
+ (import "env" "__indirect_function_table" (table $timport$1 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))
+ (export "main" (func $main))
+ (export "__data_end" (global $global$1))
+ (func $__wasm_call_ctors
+ )
+ (func $fib (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  ;; code offset: 0x10
+  (local.set $1
+   ;; code offset: 0xe
+   (i32.const 1)
+  )
+  ;; code offset: 0x12
+  (block $label$1
+   ;; code offset: 0x19
+   (br_if $label$1
+    ;; code offset: 0x18
+    (i32.lt_s
+     ;; code offset: 0x14
+     (local.get $0)
+     ;; code offset: 0x16
+     (i32.const 1)
+    )
+   )
+   ;; code offset: 0x1d
+   (local.set $2
+    ;; code offset: 0x1b
+    (i32.const 0)
+   )
+   ;; code offset: 0x21
+   (local.set $3
+    ;; code offset: 0x1f
+    (i32.const 0)
+   )
+   ;; code offset: 0x23
+   (loop $label$2
+    ;; code offset: 0x2c
+    (local.set $1
+     ;; code offset: 0x2b
+     (i32.add
+      ;; code offset: 0x27
+      (local.tee $4
+       ;; code offset: 0x25
+       (local.get $1)
+      )
+      ;; code offset: 0x29
+      (local.get $2)
+     )
+    )
+    ;; code offset: 0x30
+    (local.set $2
+     ;; code offset: 0x2e
+     (local.get $4)
+    )
+    ;; code offset: 0x3c
+    (br_if $label$2
+     ;; code offset: 0x3b
+     (i32.ne
+      ;; code offset: 0x37
+      (local.tee $3
+       ;; code offset: 0x36
+       (i32.add
+        ;; code offset: 0x32
+        (local.get $3)
+        ;; code offset: 0x34
+        (i32.const 1)
+       )
+      )
+      ;; code offset: 0x39
+      (local.get $0)
+     )
+    )
+   )
+  )
+  ;; code offset: 0x40
+  (local.get $1)
+ )
+ (func $__original_main (result i32)
+  ;; code offset: 0x47
+  (call $fib
+   ;; code offset: 0x45
+   (i32.const 6)
+  )
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  ;; code offset: 0x4c
+  (call $__original_main)
+ )
+ ;; custom section ".debug_info", size 168
+ ;; custom section ".debug_loc", size 143
+ ;; custom section ".debug_ranges", size 24
+ ;; custom section ".debug_abbrev", size 131
+ ;; custom section ".debug_line", size 183
+ ;; custom section ".debug_str", size 180
+ ;; custom section "producers", size 127
+)
diff --git a/binaryen/test/passes/fib2_emptylocspan_dwarf.passes b/binaryen/test/passes/fib2_emptylocspan_dwarf.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fib2_emptylocspan_dwarf.passes
@@ -0,0 +1,1 @@
+dwarfdump_roundtrip_dwarfdump_g
diff --git a/binaryen/test/passes/fib2_emptylocspan_dwarf.wasm b/binaryen/test/passes/fib2_emptylocspan_dwarf.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/fib2_emptylocspan_dwarf.wasm differ
diff --git a/binaryen/test/passes/fib_nonzero-low-pc_dwarf.bin.txt b/binaryen/test/passes/fib_nonzero-low-pc_dwarf.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fib_nonzero-low-pc_dwarf.bin.txt
@@ -0,0 +1,627 @@
+DWARF debug info
+================
+
+Contains section .debug_info (155 bytes)
+Contains section .debug_loc (182 bytes)
+Contains section .debug_abbrev (94 bytes)
+Contains section .debug_line (86 bytes)
+Contains section .debug_str (157 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+[2] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_prototyped	DW_FORM_flag_present
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[3] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[4] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[5] DW_TAG_lexical_block	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+[6] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x00000097 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x0000009b)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 11.0.0 (https://github.com/llvm/llvm-project.git b0e51167aff84e52fb99f69db6f8965304eee2cf)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C99)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000069] = "fib.c")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x0000006f] = "D:\\test\\fib")
+              DW_AT_low_pc [DW_FORM_addr]	(0x000000000000000a)
+              DW_AT_high_pc [DW_FORM_data4]	(0x0000003f)
+
+0x00000026:   DW_TAG_subprogram [2] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x000000000000000a)
+                DW_AT_high_pc [DW_FORM_data4]	(0x0000003f)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x3 +0, <decoding error> 00 00 9f)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000007b] = "fib")
+                DW_AT_decl_file [DW_FORM_data1]	("D:\test\fib/fib.c")
+                DW_AT_decl_line [DW_FORM_data1]	(3)
+                DW_AT_prototyped [DW_FORM_flag_present]	(true)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0093 => {0x00000093} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000041:     DW_TAG_formal_parameter [3]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000083] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("D:\test\fib/fib.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(3)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0093 => {0x00000093} "int")
+
+0x0000004c:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000000: 
+                     [0x0000000a,  0x0000001a): DW_OP_consts +1, DW_OP_stack_value
+                     [0x00000026,  0x00000028): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value
+                     [0x00000028,  0x00000044): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000085] = "previous")
+                  DW_AT_decl_file [DW_FORM_data1]	("D:\test\fib/fib.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(4)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0093 => {0x00000093} "int")
+
+0x0000005b:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000031: 
+                     [0x0000000a,  0x0000001a): DW_OP_consts +1, DW_OP_stack_value
+                     [0x0000002d,  0x00000044): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000008e] = "current")
+                  DW_AT_decl_file [DW_FORM_data1]	("D:\test\fib/fib.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(5)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0093 => {0x00000093} "int")
+
+0x0000006a:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000054: 
+                     [0x0000000a,  0x0000001a): DW_OP_consts +1, DW_OP_stack_value
+                     [0x00000026,  0x00000028): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value
+                     [0x00000028,  0x0000002d): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+                     [0x0000002d,  0x00000044): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000096] = "next")
+                  DW_AT_decl_file [DW_FORM_data1]	("D:\test\fib/fib.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(6)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0093 => {0x00000093} "int")
+
+0x00000079:     DW_TAG_lexical_block [5] *
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000013)
+                  DW_AT_high_pc [DW_FORM_data4]	(0x00000033)
+
+0x00000082:       DW_TAG_variable [4]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000093: 
+                       [0x0000000a,  0x0000001a): DW_OP_consts +3, DW_OP_stack_value
+                       [0x00000039,  0x0000003b): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value)
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000009b] = "i")
+                    DW_AT_decl_file [DW_FORM_data1]	("D:\test\fib/fib.c")
+                    DW_AT_decl_line [DW_FORM_data1]	(7)
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x0093 => {0x00000093} "int")
+
+0x00000091:       NULL
+
+0x00000092:     NULL
+
+0x00000093:   DW_TAG_base_type [6]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000007f] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x0000009a:   NULL
+
+.debug_loc contents:
+0x00000000: 
+            [0x00000000,  0x00000010): DW_OP_consts +1, DW_OP_stack_value
+            [0x0000001c,  0x0000001e): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value
+            [0x0000001e,  0x0000003a): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+
+0x00000031: 
+            [0x00000000,  0x00000010): DW_OP_consts +1, DW_OP_stack_value
+            [0x00000023,  0x0000003a): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000054: 
+            [0x00000000,  0x00000010): DW_OP_consts +1, DW_OP_stack_value
+            [0x0000001c,  0x0000001e): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value
+            [0x0000001e,  0x00000023): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+            [0x00000023,  0x0000003a): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000093: 
+            [0x00000000,  0x00000010): DW_OP_consts +3, DW_OP_stack_value
+            [0x0000002f,  0x00000031): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x00000052
+         version: 4
+ prologue_length: 0x0000001d
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "fib.c"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000027: 00 DW_LNE_set_address (0x000000000000000a)
+0x0000002e: 14 address += 0,  line += 2
+            0x000000000000000a      3      0      1   0             0  is_stmt
+
+0x0000002f: 05 DW_LNS_set_column (23)
+0x00000031: 0a DW_LNS_set_prologue_end
+0x00000032: 94 address += 9,  line += 4
+            0x0000000000000013      7     23      1   0             0  is_stmt prologue_end
+
+0x00000033: 05 DW_LNS_set_column (5)
+0x00000035: 06 DW_LNS_negate_stmt
+0x00000036: 58 address += 5,  line += 0
+            0x0000000000000018      7      5      1   0             0 
+
+0x00000037: 03 DW_LNS_advance_line (0)
+0x00000039: 2e address += 2,  line += 0
+            0x000000000000001a      0      5      1   0             0 
+
+0x0000003a: 05 DW_LNS_set_column (24)
+0x0000003c: 06 DW_LNS_negate_stmt
+0x0000003d: 03 DW_LNS_advance_line (9)
+0x0000003f: ba address += 12,  line += 0
+            0x0000000000000026      9     24      1   0             0  is_stmt
+
+0x00000040: 05 DW_LNS_set_column (23)
+0x00000042: 72 address += 7,  line += -2
+            0x000000000000002d      7     23      1   0             0  is_stmt
+
+0x00000043: 05 DW_LNS_set_column (29)
+0x00000045: 06 DW_LNS_negate_stmt
+0x00000046: 74 address += 7,  line += 0
+            0x0000000000000034      7     29      1   0             0 
+
+0x00000047: 03 DW_LNS_advance_line (0)
+0x00000049: 58 address += 5,  line += 0
+            0x0000000000000039      0     29      1   0             0 
+
+0x0000004a: 05 DW_LNS_set_column (5)
+0x0000004c: 6d address += 6,  line += 7
+            0x000000000000003f      7      5      1   0             0 
+
+0x0000004d: 06 DW_LNS_negate_stmt
+0x0000004e: 03 DW_LNS_advance_line (16)
+0x00000050: 74 address += 7,  line += 0
+            0x0000000000000046     16      5      1   0             0  is_stmt
+
+0x00000051: 02 DW_LNS_advance_pc (3)
+0x00000053: 00 DW_LNE_end_sequence
+            0x0000000000000049     16      5      1   0             0  is_stmt end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git b0e51167aff84e52fb99f69db6f8965304eee2cf)"
+0x00000069: "fib.c"
+0x0000006f: "D:\test\fib"
+0x0000007b: "fib"
+0x0000007f: "int"
+0x00000083: "n"
+0x00000085: "previous"
+0x0000008e: "current"
+0x00000096: "next"
+0x0000009b: "i"
+DWARF debug info
+================
+
+Contains section .debug_info (155 bytes)
+Contains section .debug_loc (182 bytes)
+Contains section .debug_abbrev (94 bytes)
+Contains section .debug_line (140 bytes)
+Contains section .debug_str (157 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+[2] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_prototyped	DW_FORM_flag_present
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[3] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[4] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[5] DW_TAG_lexical_block	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+[6] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x00000097 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x0000009b)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 11.0.0 (https://github.com/llvm/llvm-project.git b0e51167aff84e52fb99f69db6f8965304eee2cf)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C99)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000069] = "fib.c")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x0000006f] = "D:\\test\\fib")
+              DW_AT_low_pc [DW_FORM_addr]	(0x000000000000000a)
+              DW_AT_high_pc [DW_FORM_data4]	(0x00000047)
+
+0x00000026:   DW_TAG_subprogram [2] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x000000000000000a)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000047)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x3 +0, <decoding error> 00 00 9f)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000007b] = "fib")
+                DW_AT_decl_file [DW_FORM_data1]	("D:\test\fib/fib.c")
+                DW_AT_decl_line [DW_FORM_data1]	(3)
+                DW_AT_prototyped [DW_FORM_flag_present]	(true)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0093 => {0x00000093} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000041:     DW_TAG_formal_parameter [3]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000083] = "n")
+                  DW_AT_decl_file [DW_FORM_data1]	("D:\test\fib/fib.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(3)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0093 => {0x00000093} "int")
+
+0x0000004c:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000000: 
+                     [0x0000000a,  0x00000022): DW_OP_consts +1, DW_OP_stack_value
+                     [0x0000002e,  0x00000030): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value
+                     [0x00000030,  0x0000004c): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000085] = "previous")
+                  DW_AT_decl_file [DW_FORM_data1]	("D:\test\fib/fib.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(4)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0093 => {0x00000093} "int")
+
+0x0000005b:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000031: 
+                     [0x0000000a,  0x00000022): DW_OP_consts +1, DW_OP_stack_value
+                     [0x00000035,  0x0000004c): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000008e] = "current")
+                  DW_AT_decl_file [DW_FORM_data1]	("D:\test\fib/fib.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(5)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0093 => {0x00000093} "int")
+
+0x0000006a:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000054: 
+                     [0x0000000a,  0x00000022): DW_OP_consts +1, DW_OP_stack_value
+                     [0x0000002e,  0x00000030): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value
+                     [0x00000030,  0x00000035): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+                     [0x00000035,  0x0000004c): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000096] = "next")
+                  DW_AT_decl_file [DW_FORM_data1]	("D:\test\fib/fib.c")
+                  DW_AT_decl_line [DW_FORM_data1]	(6)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0093 => {0x00000093} "int")
+
+0x00000079:     DW_TAG_lexical_block [5] *
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000001b)
+                  DW_AT_high_pc [DW_FORM_data4]	(0x00000000)
+
+0x00000082:       DW_TAG_variable [4]  
+                    DW_AT_location [DW_FORM_sec_offset]	(0x00000093: 
+                       [0x0000000a,  0x00000022): DW_OP_consts +3, DW_OP_stack_value
+                       [0x00000041,  0x00000043): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value)
+                    DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000009b] = "i")
+                    DW_AT_decl_file [DW_FORM_data1]	("D:\test\fib/fib.c")
+                    DW_AT_decl_line [DW_FORM_data1]	(7)
+                    DW_AT_type [DW_FORM_ref4]	(cu + 0x0093 => {0x00000093} "int")
+
+0x00000091:       NULL
+
+0x00000092:     NULL
+
+0x00000093:   DW_TAG_base_type [6]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000007f] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x0000009a:   NULL
+
+.debug_loc contents:
+0x00000000: 
+            [0x00000000,  0x00000018): DW_OP_consts +1, DW_OP_stack_value
+            [0x00000024,  0x00000026): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value
+            [0x00000026,  0x00000042): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+
+0x00000031: 
+            [0x00000000,  0x00000018): DW_OP_consts +1, DW_OP_stack_value
+            [0x0000002b,  0x00000042): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000054: 
+            [0x00000000,  0x00000018): DW_OP_consts +1, DW_OP_stack_value
+            [0x00000024,  0x00000026): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value
+            [0x00000026,  0x0000002b): DW_OP_WASM_location 0x0 +4, DW_OP_stack_value
+            [0x0000002b,  0x00000042): DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
+
+0x00000093: 
+            [0x00000000,  0x00000018): DW_OP_consts +3, DW_OP_stack_value
+            [0x00000037,  0x00000039): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x00000088
+         version: 4
+ prologue_length: 0x0000001d
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "fib.c"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000027: 00 DW_LNE_set_address (0x000000000000000a)
+0x0000002e: 03 DW_LNS_advance_line (3)
+0x00000030: 01 DW_LNS_copy
+            0x000000000000000a      3      0      1   0             0  is_stmt
+
+
+0x00000031: 00 DW_LNE_set_address (0x000000000000001b)
+0x00000038: 03 DW_LNS_advance_line (7)
+0x0000003a: 05 DW_LNS_set_column (23)
+0x0000003c: 0a DW_LNS_set_prologue_end
+0x0000003d: 01 DW_LNS_copy
+            0x000000000000001b      7     23      1   0             0  is_stmt prologue_end
+
+
+0x0000003e: 00 DW_LNE_set_address (0x0000000000000020)
+0x00000045: 05 DW_LNS_set_column (5)
+0x00000047: 06 DW_LNS_negate_stmt
+0x00000048: 01 DW_LNS_copy
+            0x0000000000000020      7      5      1   0             0 
+
+
+0x00000049: 00 DW_LNE_set_address (0x000000000000002e)
+0x00000050: 03 DW_LNS_advance_line (9)
+0x00000052: 05 DW_LNS_set_column (24)
+0x00000054: 06 DW_LNS_negate_stmt
+0x00000055: 01 DW_LNS_copy
+            0x000000000000002e      9     24      1   0             0  is_stmt
+
+
+0x00000056: 00 DW_LNE_set_address (0x0000000000000035)
+0x0000005d: 03 DW_LNS_advance_line (7)
+0x0000005f: 05 DW_LNS_set_column (23)
+0x00000061: 01 DW_LNS_copy
+            0x0000000000000035      7     23      1   0             0  is_stmt
+
+
+0x00000062: 00 DW_LNE_set_address (0x000000000000003c)
+0x00000069: 05 DW_LNS_set_column (29)
+0x0000006b: 06 DW_LNS_negate_stmt
+0x0000006c: 01 DW_LNS_copy
+            0x000000000000003c      7     29      1   0             0 
+
+
+0x0000006d: 00 DW_LNE_set_address (0x0000000000000047)
+0x00000074: 05 DW_LNS_set_column (5)
+0x00000076: 01 DW_LNS_copy
+            0x0000000000000047      7      5      1   0             0 
+
+
+0x00000077: 00 DW_LNE_set_address (0x000000000000004e)
+0x0000007e: 03 DW_LNS_advance_line (16)
+0x00000080: 06 DW_LNS_negate_stmt
+0x00000081: 01 DW_LNS_copy
+            0x000000000000004e     16      5      1   0             0  is_stmt
+
+
+0x00000082: 00 DW_LNE_set_address (0x0000000000000051)
+0x00000089: 00 DW_LNE_end_sequence
+            0x0000000000000051     16      5      1   0             0  is_stmt end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git b0e51167aff84e52fb99f69db6f8965304eee2cf)"
+0x00000069: "fib.c"
+0x0000006f: "D:\test\fib"
+0x0000007b: "fib"
+0x0000007f: "int"
+0x00000083: "n"
+0x00000085: "previous"
+0x0000008e: "current"
+0x00000096: "next"
+0x0000009b: "i"
+(module
+ (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))
+ (global $global$0 i32 (i32.const 0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "__wasm_apply_relocs" (func $__wasm_apply_relocs))
+ (export "fib" (func $fib))
+ (export "__dso_handle" (global $global$0))
+ (func $__wasm_call_ctors
+  ;; code offset: 0x3
+  (call $__wasm_apply_relocs)
+ )
+ (func $__wasm_apply_relocs
+ )
+ (func $fib (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  ;; code offset: 0x17
+  (local.set $1
+   ;; code offset: 0x15
+   (i32.const 1)
+  )
+  ;; code offset: 0x19
+  (block $label$1
+   ;; code offset: 0x20
+   (br_if $label$1
+    ;; code offset: 0x1f
+    (i32.le_s
+     ;; code offset: 0x1b
+     (local.get $0)
+     ;; code offset: 0x1d
+     (i32.const 2)
+    )
+   )
+   ;; code offset: 0x24
+   (local.set $2
+    ;; code offset: 0x22
+    (i32.const 3)
+   )
+   ;; code offset: 0x28
+   (local.set $3
+    ;; code offset: 0x26
+    (i32.const 1)
+   )
+   ;; code offset: 0x2a
+   (loop $label$2
+    ;; code offset: 0x33
+    (local.set $1
+     ;; code offset: 0x32
+     (i32.add
+      ;; code offset: 0x2e
+      (local.tee $4
+       ;; code offset: 0x2c
+       (local.get $1)
+      )
+      ;; code offset: 0x30
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x3a
+    (local.set $5
+     ;; code offset: 0x39
+     (i32.eq
+      ;; code offset: 0x35
+      (local.get $2)
+      ;; code offset: 0x37
+      (local.get $0)
+     )
+    )
+    ;; code offset: 0x41
+    (local.set $2
+     ;; code offset: 0x40
+     (i32.add
+      ;; code offset: 0x3c
+      (local.get $2)
+      ;; code offset: 0x3e
+      (i32.const 1)
+     )
+    )
+    ;; code offset: 0x45
+    (local.set $3
+     ;; code offset: 0x43
+     (local.get $4)
+    )
+    ;; code offset: 0x4a
+    (br_if $label$2
+     ;; code offset: 0x49
+     (i32.eqz
+      ;; code offset: 0x47
+      (local.get $5)
+     )
+    )
+   )
+  )
+  ;; code offset: 0x4e
+  (local.get $1)
+ )
+ ;; dylink section
+ ;;   memorysize: 0
+ ;;   memoryalignment: 0
+ ;;   tablesize: 0
+ ;;   tablealignment: 0
+ ;; custom section ".debug_info", size 155
+ ;; custom section ".debug_loc", size 182
+ ;; custom section ".debug_abbrev", size 94
+ ;; custom section ".debug_line", size 140
+ ;; custom section ".debug_str", size 157
+ ;; custom section "producers", size 127
+)
diff --git a/binaryen/test/passes/fib_nonzero-low-pc_dwarf.passes b/binaryen/test/passes/fib_nonzero-low-pc_dwarf.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fib_nonzero-low-pc_dwarf.passes
@@ -0,0 +1,1 @@
+enable-mutable-globals_dwarfdump_roundtrip_dwarfdump_g
diff --git a/binaryen/test/passes/fib_nonzero-low-pc_dwarf.wasm b/binaryen/test/passes/fib_nonzero-low-pc_dwarf.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/fib_nonzero-low-pc_dwarf.wasm differ
diff --git a/binaryen/test/passes/flatten.bin.txt b/binaryen/test/passes/flatten.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten.bin.txt
@@ -0,0 +1,272 @@
+(module
+ (type $i64_f32_f64_i32_i32_=>_none (func (param i64 f32 f64 i32 i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_i64 (func (result i64)))
+ (type $i64_=>_i64 (func (param i64) (result i64)))
+ (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)))
+ (export "type-local-i32" (func $0))
+ (export "type-local-i64" (func $1))
+ (export "type-local-f32" (func $2))
+ (export "type-local-f64" (func $3))
+ (export "type-param-i32" (func $4))
+ (export "type-param-i64" (func $5))
+ (export "type-param-f32" (func $6))
+ (export "type-param-f64" (func $7))
+ (export "type-mixed" (func $8))
+ (export "read" (func $9))
+ (func $0 (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $1 (result i64)
+  (local $0 i64)
+  (local $1 i64)
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $2 (result f32)
+  (local $0 f32)
+  (local $1 f32)
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $3 (result f64)
+  (local $0 f64)
+  (local $1 f64)
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $4 (param $0 i32) (result i32)
+  (local $1 i32)
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $5 (param $0 i64) (result i64)
+  (local $1 i64)
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $6 (param $0 f32) (result f32)
+  (local $1 f32)
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $7 (param $0 f64) (result f64)
+  (local $1 f64)
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $8 (param $0 i64) (param $1 f32) (param $2 f64) (param $3 i32) (param $4 i32)
+  (local $5 i64)
+  (local $6 i64)
+  (local $7 f32)
+  (local $8 f64)
+  (block $label$1
+   (nop)
+   (unreachable)
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $9 (param $0 i64) (param $1 f32) (param $2 f64) (param $3 i32) (param $4 i32) (result f64)
+  (local $5 i64)
+  (local $6 i64)
+  (local $7 f32)
+  (local $8 f64)
+  (local $9 i64)
+  (local $10 f64)
+  (local $11 f32)
+  (local $12 f64)
+  (local $13 f64)
+  (local $14 i32)
+  (local $15 f64)
+  (local $16 i32)
+  (local $17 f64)
+  (local $18 f32)
+  (local $19 f64)
+  (local $20 i64)
+  (local $21 f64)
+  (local $22 i64)
+  (local $23 f64)
+  (local $24 f64)
+  (local $25 f64)
+  (local $26 f64)
+  (local $27 f64)
+  (local $28 f64)
+  (local $29 f64)
+  (local $30 f64)
+  (local $31 f64)
+  (local $32 f64)
+  (local $33 f64)
+  (local $34 f64)
+  (block $label$1
+   (local.set $7
+    (f32.const 5.5)
+   )
+   (local.set $5
+    (i64.const 6)
+   )
+   (local.set $8
+    (f64.const 8)
+   )
+   (local.set $9
+    (local.get $0)
+   )
+   (local.set $10
+    (f64.convert_i64_u
+     (local.get $9)
+    )
+   )
+   (local.set $11
+    (local.get $1)
+   )
+   (local.set $12
+    (f64.promote_f32
+     (local.get $11)
+    )
+   )
+   (local.set $13
+    (local.get $2)
+   )
+   (local.set $14
+    (local.get $3)
+   )
+   (local.set $15
+    (f64.convert_i32_u
+     (local.get $14)
+    )
+   )
+   (local.set $16
+    (local.get $4)
+   )
+   (local.set $17
+    (f64.convert_i32_s
+     (local.get $16)
+    )
+   )
+   (local.set $18
+    (local.get $7)
+   )
+   (local.set $19
+    (f64.promote_f32
+     (local.get $18)
+    )
+   )
+   (local.set $20
+    (local.get $5)
+   )
+   (local.set $21
+    (f64.convert_i64_u
+     (local.get $20)
+    )
+   )
+   (local.set $22
+    (local.get $6)
+   )
+   (local.set $23
+    (f64.convert_i64_u
+     (local.get $22)
+    )
+   )
+   (local.set $24
+    (local.get $8)
+   )
+   (local.set $25
+    (f64.add
+     (local.get $23)
+     (local.get $24)
+    )
+   )
+   (local.set $26
+    (f64.add
+     (local.get $21)
+     (local.get $25)
+    )
+   )
+   (local.set $27
+    (f64.add
+     (local.get $19)
+     (local.get $26)
+    )
+   )
+   (local.set $28
+    (f64.add
+     (local.get $17)
+     (local.get $27)
+    )
+   )
+   (local.set $29
+    (f64.add
+     (local.get $15)
+     (local.get $28)
+    )
+   )
+   (local.set $30
+    (f64.add
+     (local.get $13)
+     (local.get $29)
+    )
+   )
+   (local.set $31
+    (f64.add
+     (local.get $12)
+     (local.get $30)
+    )
+   )
+   (local.set $32
+    (f64.add
+     (local.get $10)
+     (local.get $31)
+    )
+   )
+   (local.set $33
+    (local.get $32)
+   )
+  )
+  (local.set $34
+   (local.get $33)
+  )
+  (return
+   (local.get $34)
+  )
+ )
+)
diff --git a/binaryen/test/passes/flatten.wasm b/binaryen/test/passes/flatten.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/flatten.wasm differ
diff --git a/binaryen/test/passes/flatten_all-features.txt b/binaryen/test/passes/flatten_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_all-features.txt
@@ -0,0 +1,2445 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_f32 (func (result f32)))
+ (type $i64_i64_=>_i64 (func (param i64 i64) (result i64)))
+ (type $none_=>_anyref (func (result anyref)))
+ (memory $0 10)
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $call-me)
+ (global $x (mut i32) (i32.const 0))
+ (func $a1
+  (local $0 i32)
+  (local.set $0
+   (i32.add
+    (i32.const 0)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $a2 (result i32)
+  (local $0 i32)
+  (local.set $0
+   (i32.add
+    (i32.const 0)
+    (i32.const 1)
+   )
+  )
+  (return
+   (local.get $0)
+  )
+ )
+ (func $a3 (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block $block
+   (local.set $0
+    (i32.const 1)
+   )
+  )
+  (local.set $1
+   (local.get $0)
+  )
+  (local.set $2
+   (i32.add
+    (i32.const 0)
+    (local.get $1)
+   )
+  )
+  (return
+   (local.get $2)
+  )
+ )
+ (func $a4
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block $block
+   (local.set $0
+    (i32.const 1)
+   )
+  )
+  (local.set $1
+   (local.get $0)
+  )
+  (local.set $2
+   (i32.add
+    (i32.const 0)
+    (local.get $1)
+   )
+  )
+  (drop
+   (local.get $2)
+  )
+ )
+ (func $a5 (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (block $block
+   (local.set $0
+    (i32.const 0)
+   )
+  )
+  (local.set $1
+   (local.get $0)
+  )
+  (block $block0
+   (local.set $2
+    (i32.const 1)
+   )
+  )
+  (local.set $3
+   (local.get $2)
+  )
+  (local.set $4
+   (i32.add
+    (local.get $1)
+    (local.get $3)
+   )
+  )
+  (return
+   (local.get $4)
+  )
+ )
+ (func $a6 (result i32)
+  (local $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (block $block
+   (local.set $x
+    (i32.const 0)
+   )
+   (local.set $1
+    (local.get $x)
+   )
+   (local.set $2
+    (local.get $1)
+   )
+  )
+  (local.set $3
+   (local.get $2)
+  )
+  (block $block1
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $4
+    (local.get $x)
+   )
+   (local.set $5
+    (local.get $4)
+   )
+  )
+  (local.set $6
+   (local.get $5)
+  )
+  (local.set $7
+   (i32.add
+    (local.get $3)
+    (local.get $6)
+   )
+  )
+  (return
+   (local.get $7)
+  )
+ )
+ (func $a7 (result i32)
+  (local $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (block $block
+   (block $block2
+    (local.set $x
+     (i32.const 0)
+    )
+    (local.set $1
+     (local.get $x)
+    )
+    (local.set $2
+     (local.get $1)
+    )
+   )
+   (local.set $3
+    (local.get $2)
+   )
+   (block $block3
+    (local.set $x
+     (i32.const 1)
+    )
+    (local.set $4
+     (local.get $x)
+    )
+    (local.set $5
+     (local.get $4)
+    )
+   )
+   (local.set $6
+    (local.get $5)
+   )
+   (local.set $7
+    (i32.add
+     (local.get $3)
+     (local.get $6)
+    )
+   )
+   (local.set $8
+    (local.get $7)
+   )
+  )
+  (local.set $9
+   (local.get $8)
+  )
+  (return
+   (local.get $9)
+  )
+ )
+ (func $a8 (result i32)
+  (local $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block $outer
+   (block $inner
+    (block $block
+     (local.set $1
+      (i32.const -1)
+     )
+     (br $inner)
+     (unreachable)
+     (local.set $2
+      (i32.const 0)
+     )
+     (br $outer)
+     (unreachable)
+     (local.set $3
+      (i32.const 1)
+     )
+    )
+    (local.set $4
+     (local.get $3)
+    )
+    (block $block4
+     (local.set $2
+      (i32.const 2)
+     )
+     (br $outer)
+     (unreachable)
+     (local.set $x
+      (i32.const 3)
+     )
+     (local.set $5
+      (local.get $x)
+     )
+     (local.set $6
+      (local.get $5)
+     )
+    )
+    (local.set $7
+     (local.get $6)
+    )
+    (local.set $8
+     (i32.add
+      (local.get $4)
+      (local.get $7)
+     )
+    )
+    (local.set $1
+     (local.get $8)
+    )
+   )
+   (local.set $9
+    (local.get $1)
+   )
+   (local.set $2
+    (local.get $9)
+   )
+  )
+  (local.set $10
+   (local.get $2)
+  )
+  (return
+   (local.get $10)
+  )
+ )
+ (func $a9 (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (loop $outer
+   (loop $inner
+    (block
+     (br_if $outer
+      (i32.const -1)
+     )
+     (local.set $0
+      (i32.add
+       (i32.const 0)
+       (i32.const 1)
+      )
+     )
+     (local.set $1
+      (local.get $0)
+     )
+    )
+    (local.set $2
+     (local.get $1)
+    )
+    (local.set $3
+     (local.get $2)
+    )
+   )
+   (local.set $4
+    (local.get $3)
+   )
+   (local.set $5
+    (local.get $4)
+   )
+  )
+  (local.set $6
+   (local.get $5)
+  )
+  (return
+   (local.get $6)
+  )
+ )
+ (func $a10 (result i32)
+  (local $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block $outer
+   (local.set $1
+    (i32.const 0)
+   )
+   (br_if $outer
+    (i32.const 1)
+   )
+   (local.set $2
+    (local.get $1)
+   )
+   (drop
+    (local.get $2)
+   )
+   (local.set $x
+    (i32.const 2)
+   )
+   (local.set $3
+    (local.get $x)
+   )
+   (local.set $1
+    (local.get $3)
+   )
+   (br_if $outer
+    (i32.const 3)
+   )
+   (local.set $4
+    (local.get $1)
+   )
+   (drop
+    (local.get $4)
+   )
+   (local.set $x
+    (i32.const 5)
+   )
+   (local.set $5
+    (local.get $x)
+   )
+   (local.set $1
+    (i32.const 4)
+   )
+   (br_if $outer
+    (local.get $5)
+   )
+   (local.set $6
+    (local.get $1)
+   )
+   (drop
+    (local.get $6)
+   )
+   (local.set $x
+    (i32.const 6)
+   )
+   (local.set $7
+    (local.get $x)
+   )
+   (local.set $x
+    (i32.const 7)
+   )
+   (local.set $8
+    (local.get $x)
+   )
+   (local.set $1
+    (local.get $7)
+   )
+   (br_if $outer
+    (local.get $8)
+   )
+   (local.set $9
+    (local.get $1)
+   )
+   (drop
+    (local.get $9)
+   )
+   (local.set $1
+    (i32.const 8)
+   )
+   (br $outer)
+   (unreachable)
+  )
+  (local.set $10
+   (local.get $1)
+  )
+  (return
+   (local.get $10)
+  )
+ )
+ (func $a11
+  (if
+   (i32.const 0)
+   (drop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $a12 (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (if
+   (i32.const 0)
+   (local.set $0
+    (i32.const 1)
+   )
+   (local.set $0
+    (i32.const 2)
+   )
+  )
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $a13 (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (block $x
+   (block
+    (local.set $0
+     (i32.const 2)
+    )
+    (local.set $1
+     (local.get $0)
+    )
+    (br_table $x
+     (i32.const 0)
+    )
+    (if
+     (unreachable)
+     (local.set $2
+      (i32.const 0)
+     )
+     (local.set $2
+      (i32.const 1)
+     )
+    )
+   )
+   (local.set $3
+    (local.get $2)
+   )
+   (local.set $1
+    (local.get $3)
+   )
+  )
+  (local.set $4
+   (local.get $1)
+  )
+  (return
+   (local.get $4)
+  )
+ )
+ (func $a14 (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block $block
+   (local.set $0
+    (i32.const 7)
+   )
+   (local.set $1
+    (local.get $0)
+   )
+   (br_table $block
+    (i32.const 1)
+   )
+   (select
+    (i32.const 0)
+    (i32.const 1)
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (local.set $2
+   (local.get $1)
+  )
+  (return
+   (local.get $2)
+  )
+ )
+ (func $a15
+  (local $0 i32)
+  (local $1 f32)
+  (local $2 f32)
+  (block
+   (local.set $0
+    (i32.load16_u
+     (i32.const 53)
+    )
+   )
+   (if
+    (local.get $0)
+    (block
+     (unreachable)
+     (unreachable)
+    )
+    (block
+     (block $label$3
+      (unreachable)
+      (unreachable)
+     )
+     (local.set $2
+      (local.get $1)
+     )
+     (drop
+      (local.get $2)
+     )
+    )
+   )
+  )
+  (unreachable)
+ )
+ (func $a16 (result i32)
+  (local $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (block $label$1
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $1
+    (local.get $x)
+   )
+   (block $label$2
+    (local.set $x
+     (i32.const 0)
+    )
+    (local.set $2
+     (i32.const 0)
+    )
+   )
+   (local.set $3
+    (local.get $2)
+   )
+   (local.set $4
+    (i32.eqz
+     (local.get $3)
+    )
+   )
+   (local.set $5
+    (local.get $1)
+   )
+   (br_if $label$1
+    (local.get $4)
+   )
+   (local.set $6
+    (local.get $5)
+   )
+   (drop
+    (local.get $6)
+   )
+   (local.set $5
+    (i32.const 0)
+   )
+  )
+  (local.set $7
+   (local.get $5)
+  )
+  (return
+   (local.get $7)
+  )
+ )
+ (func $a17 (result f32)
+  (local $var$0 f32)
+  (local $1 f32)
+  (local $2 f32)
+  (local $3 f32)
+  (local $4 f32)
+  (local $5 f32)
+  (local.set $1
+   (local.get $var$0)
+  )
+  (local.set $var$0
+   (f32.const -137438953472)
+  )
+  (local.set $2
+   (local.get $var$0)
+  )
+  (local.set $3
+   (local.get $var$0)
+  )
+  (local.set $4
+   (select
+    (local.get $2)
+    (local.get $3)
+    (i32.const 0)
+   )
+  )
+  (local.set $5
+   (f32.max
+    (local.get $1)
+    (local.get $4)
+   )
+  )
+  (return
+   (local.get $5)
+  )
+ )
+ (func $a18 (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (block $label$1
+   (unreachable)
+   (local.set $0
+    (i32.const 1)
+   )
+   (br_if $label$1
+    (unreachable)
+   )
+   (unreachable)
+   (drop
+    (unreachable)
+   )
+   (i32.load
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $a19 (result f32)
+  (block $label$0
+   (block $label$1
+    (unreachable)
+    (return
+     (f32.const 4289944320)
+    )
+    (select
+     (unreachable)
+     (unreachable)
+     (i32.const 65535)
+    )
+    (drop
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $call-me (param $0 i32) (param $1 i32)
+  (nop)
+ )
+ (func $code-to-kill
+  (local $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block $out
+   (br $out)
+   (unreachable)
+   (drop
+    (i32.const 0)
+   )
+   (if
+    (i32.const 1)
+    (drop
+     (i32.const 2)
+    )
+   )
+   (br_table $out $out $out $out
+    (i32.const 3)
+   )
+   (unreachable)
+   (call $code-to-kill)
+  )
+  (if
+   (i32.const 0)
+   (block
+    (block $out1
+     (unreachable)
+     (unreachable)
+     (drop
+      (i32.const 0)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 0)
+   (block
+    (block $out3
+     (return)
+     (unreachable)
+     (drop
+      (i32.const 0)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (block $out4
+   (br_table $out4 $out4 $out4 $out4
+    (i32.const 4)
+   )
+   (unreachable)
+   (drop
+    (i32.const 0)
+   )
+  )
+  (block $out5
+   (br_if $out5
+    (i32.const 3)
+   )
+   (drop
+    (i32.const 0)
+   )
+  )
+  (if
+   (i32.const 0)
+   (block
+    (block $block4
+     (if
+      (i32.const 0)
+      (block
+       (block $out8
+        (unreachable)
+        (unreachable)
+        (drop
+         (i32.const 0)
+        )
+       )
+       (unreachable)
+      )
+      (block
+       (block $out9
+        (unreachable)
+        (unreachable)
+        (drop
+         (i32.const 0)
+        )
+       )
+       (unreachable)
+      )
+     )
+     (unreachable)
+     (drop
+      (i32.const 0)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 0)
+   (block
+    (block $out11
+     (unreachable)
+     (unreachable)
+     (unreachable)
+     (drop
+      (i32.const 0)
+     )
+     (unreachable)
+     (unreachable)
+    )
+    (local.set $2
+     (local.get $1)
+    )
+    (drop
+     (local.get $2)
+    )
+   )
+  )
+  (if
+   (i32.const 0)
+   (block
+    (block $out13
+     (unreachable)
+     (unreachable)
+     (unreachable)
+     (drop
+      (i32.const 0)
+     )
+     (unreachable)
+     (unreachable)
+    )
+    (local.set $4
+     (local.get $3)
+    )
+    (drop
+     (local.get $4)
+    )
+   )
+  )
+  (if
+   (i32.const 0)
+   (block
+    (block $out15
+     (unreachable)
+     (unreachable)
+     (unreachable)
+     (unreachable)
+     (drop
+      (i32.const 0)
+     )
+     (unreachable)
+     (unreachable)
+    )
+    (local.set $6
+     (local.get $5)
+    )
+    (drop
+     (local.get $6)
+    )
+   )
+  )
+  (block $out16
+   (block $in
+    (br_if $out16
+     (i32.const 1)
+    )
+   )
+   (unreachable)
+   (unreachable)
+  )
+  (if
+   (i32.const 0)
+   (block
+    (block $block11
+     (block $out18
+      (block $in19
+       (br_if $in19
+        (i32.const 1)
+       )
+      )
+      (unreachable)
+      (unreachable)
+     )
+     (unreachable)
+     (drop
+      (i32.const 10)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (block $out20
+   (block $in21
+    (br_table $out20 $in21
+     (i32.const 1)
+    )
+    (unreachable)
+   )
+   (unreachable)
+   (unreachable)
+  )
+  (block $out22
+   (block $in23
+    (br_table $in23 $out22
+     (i32.const 1)
+    )
+    (unreachable)
+   )
+   (unreachable)
+   (unreachable)
+  )
+  (if
+   (i32.const 0)
+   (block
+    (block $block13
+     (block $out25
+      (block $in26
+       (br_table $in26 $in26
+        (i32.const 1)
+       )
+       (unreachable)
+      )
+      (unreachable)
+      (unreachable)
+     )
+     (unreachable)
+     (drop
+      (i32.const 10)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 0)
+   (block
+    (block $block15
+     (drop
+      (i32.const 10)
+     )
+     (drop
+      (i32.const 42)
+     )
+     (unreachable)
+     (unreachable)
+     (unreachable)
+     (return
+      (unreachable)
+     )
+     (unreachable)
+     (unreachable)
+     (unreachable)
+     (return)
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 0)
+   (block
+    (loop $loop-in18
+     (unreachable)
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (block $out29
+   (loop $in30
+    (block
+     (br_if $out29
+      (i32.const 1)
+     )
+     (unreachable)
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (if
+   (i32.const 0)
+   (block
+    (block $block20
+     (loop $in32
+      (block
+       (br_if $in32
+        (i32.const 1)
+       )
+       (unreachable)
+       (unreachable)
+      )
+      (unreachable)
+     )
+     (unreachable)
+     (drop
+      (i32.const 10)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 1)
+   (block
+    (unreachable)
+    (call $call-me
+     (i32.const 123)
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 2)
+   (block
+    (unreachable)
+    (call $call-me
+     (unreachable)
+     (i32.const 0)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 3)
+   (block
+    (unreachable)
+    (unreachable)
+    (call $call-me
+     (unreachable)
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const -1)
+   (block
+    (unreachable)
+    (call_indirect (type $i32_i32_=>_none)
+     (i32.const 123)
+     (i32.const 456)
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const -2)
+   (block
+    (unreachable)
+    (call_indirect (type $i32_i32_=>_none)
+     (i32.const 139)
+     (unreachable)
+     (i32.const 0)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const -3)
+   (block
+    (unreachable)
+    (unreachable)
+    (call_indirect (type $i32_i32_=>_none)
+     (i32.const 246)
+     (unreachable)
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const -4)
+   (block
+    (unreachable)
+    (unreachable)
+    (unreachable)
+    (call_indirect (type $i32_i32_=>_none)
+     (unreachable)
+     (unreachable)
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 11)
+   (block
+    (unreachable)
+    (unreachable)
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 22)
+   (block
+    (unreachable)
+    (i32.load
+     (unreachable)
+    )
+    (drop
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 33)
+   (block
+    (unreachable)
+    (i32.store
+     (i32.const 0)
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 44)
+   (block
+    (unreachable)
+    (i32.store
+     (unreachable)
+     (i32.const 0)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 55)
+   (block
+    (unreachable)
+    (unreachable)
+    (i32.store
+     (unreachable)
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 66)
+   (block
+    (unreachable)
+    (i32.eqz
+     (unreachable)
+    )
+    (drop
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 77)
+   (block
+    (unreachable)
+    (i32.add
+     (unreachable)
+     (i32.const 0)
+    )
+    (drop
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 88)
+   (block
+    (unreachable)
+    (i32.add
+     (i32.const 0)
+     (unreachable)
+    )
+    (drop
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 99)
+   (block
+    (unreachable)
+    (unreachable)
+    (i32.add
+     (unreachable)
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 100)
+   (block
+    (unreachable)
+    (select
+     (i32.const 123)
+     (i32.const 456)
+     (unreachable)
+    )
+    (drop
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 101)
+   (block
+    (unreachable)
+    (select
+     (i32.const 123)
+     (unreachable)
+     (i32.const 456)
+    )
+    (drop
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 102)
+   (block
+    (unreachable)
+    (select
+     (unreachable)
+     (i32.const 123)
+     (i32.const 456)
+    )
+    (drop
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (drop
+   (i32.const 1337)
+  )
+ )
+ (func $killer
+  (block
+   (unreachable)
+   (unreachable)
+   (drop
+    (i32.const 1000)
+   )
+  )
+  (unreachable)
+ )
+ (func $target
+  (drop
+   (i32.const 2000)
+  )
+ )
+ (func $typed-block-none-then-unreachable (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (block $top-typed
+   (block $switch$0
+    (return
+     (i32.const 0)
+    )
+    (unreachable)
+    (br $switch$0)
+    (unreachable)
+   )
+   (return
+    (i32.const 1)
+   )
+   (unreachable)
+  )
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $typed-block-remove-br-changes-type (param $$$0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (block
+   (block $switch$7
+    (block $switch-default$10
+     (block $switch-case$9
+      (block $switch-case$8
+       (br_table $switch-case$9 $switch-case$8 $switch-default$10
+        (i32.const -1)
+       )
+       (unreachable)
+      )
+     )
+     (local.set $1
+      (local.get $$$0)
+     )
+     (return
+      (local.get $1)
+     )
+     (unreachable)
+     (br $switch$7)
+     (unreachable)
+    )
+    (local.set $2
+     (local.get $$$0)
+    )
+    (return
+     (local.get $2)
+    )
+    (unreachable)
+   )
+   (return
+    (i32.const 0)
+   )
+   (unreachable)
+  )
+  (local.set $4
+   (local.get $3)
+  )
+  (return
+   (local.get $4)
+  )
+ )
+ (func $global
+  (local $0 i32)
+  (block
+   (unreachable)
+   (unreachable)
+   (local.set $0
+    (global.get $x)
+   )
+   (drop
+    (local.get $0)
+   )
+   (global.set $x
+    (i32.const 1)
+   )
+  )
+  (unreachable)
+ )
+ (func $ret (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (block
+   (return
+    (i32.const 0)
+   )
+   (unreachable)
+   (nop)
+   (local.set $0
+    (i32.const 0)
+   )
+  )
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $unreachable-br (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (block $out
+   (local.set $0
+    (i32.const 0)
+   )
+   (br $out)
+   (unreachable)
+   (unreachable)
+  )
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $unreachable-br-loop (result i32)
+  (loop $out
+   (br $out)
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $unreachable-block-ends-switch (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (block $label$0
+   (block $label$3
+    (nop)
+    (unreachable)
+    (br_table $label$3
+     (unreachable)
+    )
+    (unreachable)
+    (unreachable)
+    (unreachable)
+   )
+   (local.set $0
+    (i32.const 19)
+   )
+  )
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $unreachable-block-ends-br_if (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (block $label$0
+   (block $label$2
+    (nop)
+    (unreachable)
+    (br_if $label$2
+     (unreachable)
+    )
+    (unreachable)
+    (unreachable)
+    (unreachable)
+   )
+   (local.set $0
+    (i32.const 19)
+   )
+  )
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $unreachable-brs-3 (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (block $label$0
+   (local.set $0
+    (i32.const 18)
+   )
+   (br $label$0)
+   (memory.grow
+    (unreachable)
+   )
+   (unreachable)
+   (unreachable)
+   (local.set $0
+    (i32.const 21)
+   )
+  )
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $unreachable-brs-4 (param $var$0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (block $label$0
+   (block $label$1
+    (unreachable)
+    (local.set $1
+     (i32.const 4104)
+    )
+    (br_if $label$0
+     (unreachable)
+    )
+    (unreachable)
+    (drop
+     (unreachable)
+    )
+    (unreachable)
+    (local.set $2
+     (i32.const 4)
+    )
+   )
+   (local.set $3
+    (local.get $2)
+   )
+   (local.set $1
+    (local.get $3)
+   )
+   (br $label$0)
+   (unreachable)
+   (local.set $1
+    (i32.const 16)
+   )
+  )
+  (local.set $4
+   (local.get $1)
+  )
+  (local.set $5
+   (i32.add
+    (i32.const 1)
+    (local.get $4)
+   )
+  )
+  (return
+   (local.get $5)
+  )
+ )
+ (func $call-unreach (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $2 i64)
+  (local $3 i64)
+  (local $4 i32)
+  (local $5 i64)
+  (local $6 i64)
+  (local $7 i64)
+  (local $8 i64)
+  (local $9 i64)
+  (local $10 i64)
+  (local $11 i64)
+  (local $12 i64)
+  (local $13 i64)
+  (local $14 i64)
+  (local $15 i64)
+  (local $16 i64)
+  (local $17 i64)
+  (block
+   (local.set $3
+    (local.get $var$0)
+   )
+   (local.set $4
+    (i64.eqz
+     (local.get $3)
+    )
+   )
+   (if
+    (local.get $4)
+    (block
+     (block $label$0
+      (local.set $5
+       (local.get $var$1)
+      )
+      (local.set $6
+       (local.get $5)
+      )
+     )
+     (local.set $7
+      (local.get $6)
+     )
+     (local.set $16
+      (local.get $7)
+     )
+    )
+    (block
+     (block $label$1
+      (local.set $8
+       (local.get $var$0)
+      )
+      (local.set $9
+       (i64.sub
+        (local.get $8)
+        (i64.const 1)
+       )
+      )
+      (block $block
+       (local.set $10
+        (local.get $var$0)
+       )
+       (local.set $2
+        (local.get $10)
+       )
+       (nop)
+       (local.set $11
+        (local.get $2)
+       )
+       (local.set $12
+        (local.get $11)
+       )
+      )
+      (local.set $13
+       (local.get $12)
+      )
+      (unreachable)
+      (i64.mul
+       (local.get $13)
+       (unreachable)
+      )
+      (call $call-unreach
+       (local.get $9)
+       (unreachable)
+      )
+      (unreachable)
+     )
+     (local.set $15
+      (local.get $14)
+     )
+     (local.set $16
+      (local.get $15)
+     )
+    )
+   )
+  )
+  (local.set $17
+   (local.get $16)
+  )
+  (return
+   (local.get $17)
+  )
+ )
+ (func $test-flatten
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (local $19 i32)
+  (local $20 i32)
+  (local $21 i32)
+  (local $22 i32)
+  (local $23 i32)
+  (local $24 i32)
+  (local $25 i32)
+  (local $26 i32)
+  (local $27 i32)
+  (local $28 i32)
+  (local $29 i32)
+  (local $30 i32)
+  (local $31 i32)
+  (local $32 i32)
+  (local $33 i32)
+  (local $34 i32)
+  (local $35 i32)
+  (local $36 i32)
+  (local $37 i32)
+  (local $38 i32)
+  (local $39 i32)
+  (block $out
+   (local.set $0
+    (i32.add
+     (i32.const 1)
+     (i32.const 2)
+    )
+   )
+   (drop
+    (local.get $0)
+   )
+   (br $out)
+   (i32.add
+    (i32.const 1)
+    (unreachable)
+   )
+   (drop
+    (unreachable)
+   )
+   (unreachable)
+   (br $out)
+   (i32.add
+    (unreachable)
+    (i32.const 1)
+   )
+   (drop
+    (unreachable)
+   )
+   (unreachable)
+   (br_table $out $out $out $out
+    (i32.const 3)
+   )
+   (i32.add
+    (i32.const 1)
+    (unreachable)
+   )
+   (drop
+    (unreachable)
+   )
+   (unreachable)
+   (block $block
+    (drop
+     (i32.const 2)
+    )
+    (drop
+     (i32.const 3)
+    )
+    (local.set $1
+     (i32.const 4)
+    )
+   )
+   (local.set $2
+    (local.get $1)
+   )
+   (local.set $3
+    (i32.add
+     (i32.const 1)
+     (local.get $2)
+    )
+   )
+   (drop
+    (local.get $3)
+   )
+   (block $in
+    (block $switch-in
+     (local.set $4
+      (i32.const 2)
+     )
+     (local.set $5
+      (local.get $4)
+     )
+     (local.set $6
+      (local.get $4)
+     )
+     (br_table $in $switch-in $in
+      (i32.const 777)
+     )
+     (unreachable)
+    )
+    (local.set $7
+     (local.get $6)
+    )
+    (drop
+     (local.get $7)
+    )
+    (local.set $5
+     (i32.const 3)
+    )
+    (br $in)
+    (unreachable)
+    (local.set $5
+     (i32.const 4)
+    )
+   )
+   (local.set $8
+    (local.get $5)
+   )
+   (local.set $9
+    (i32.add
+     (i32.const 1)
+     (local.get $8)
+    )
+   )
+   (drop
+    (local.get $9)
+   )
+   (loop $loop-in
+    (local.set $10
+     (i32.const 5)
+    )
+   )
+   (local.set $11
+    (local.get $10)
+   )
+   (local.set $12
+    (i32.add
+     (i32.const 1)
+     (local.get $11)
+    )
+   )
+   (drop
+    (local.get $12)
+   )
+   (if
+    (i32.const 6)
+    (local.set $13
+     (i32.const 7)
+    )
+    (local.set $13
+     (i32.const 8)
+    )
+   )
+   (local.set $14
+    (local.get $13)
+   )
+   (local.set $15
+    (i32.add
+     (i32.const 1)
+     (local.get $14)
+    )
+   )
+   (drop
+    (local.get $15)
+   )
+   (local.set $16
+    (select
+     (i32.const 9)
+     (i32.const 10)
+     (i32.const 11)
+    )
+   )
+   (drop
+    (local.get $16)
+   )
+   (br $out)
+   (select
+    (unreachable)
+    (i32.const 10)
+    (i32.const 11)
+   )
+   (drop
+    (unreachable)
+   )
+   (unreachable)
+   (br $out)
+   (select
+    (i32.const 9)
+    (unreachable)
+    (i32.const 11)
+   )
+   (drop
+    (unreachable)
+   )
+   (unreachable)
+   (br $out)
+   (select
+    (i32.const 9)
+    (i32.const 10)
+    (unreachable)
+   )
+   (drop
+    (unreachable)
+   )
+   (unreachable)
+   (if
+    (i32.const 11)
+    (local.set $17
+     (i32.const 12)
+    )
+    (local.set $17
+     (i32.const 13)
+    )
+   )
+   (local.set $18
+    (local.get $17)
+   )
+   (local.set $19
+    (select
+     (local.get $18)
+     (i32.const 9)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (local.get $19)
+   )
+   (if
+    (i32.const 11)
+    (local.set $20
+     (i32.const 12)
+    )
+    (local.set $20
+     (i32.const 13)
+    )
+   )
+   (local.set $21
+    (local.get $20)
+   )
+   (local.set $22
+    (select
+     (i32.const 9)
+     (local.get $21)
+     (i32.const 10)
+    )
+   )
+   (drop
+    (local.get $22)
+   )
+   (if
+    (i32.const 11)
+    (local.set $23
+     (i32.const 12)
+    )
+    (local.set $23
+     (i32.const 13)
+    )
+   )
+   (local.set $24
+    (local.get $23)
+   )
+   (local.set $25
+    (select
+     (i32.const 9)
+     (i32.const 10)
+     (local.get $24)
+    )
+   )
+   (drop
+    (local.get $25)
+   )
+   (if
+    (i32.const 11)
+    (local.set $26
+     (i32.const 12)
+    )
+    (local.set $26
+     (i32.const 13)
+    )
+   )
+   (local.set $27
+    (local.get $26)
+   )
+   (if
+    (i32.const 15)
+    (local.set $28
+     (i32.const 16)
+    )
+    (local.set $28
+     (i32.const 17)
+    )
+   )
+   (local.set $29
+    (local.get $28)
+   )
+   (local.set $30
+    (select
+     (local.get $27)
+     (i32.const 14)
+     (local.get $29)
+    )
+   )
+   (drop
+    (local.get $30)
+   )
+   (return)
+   (i32.add
+    (i32.const 1)
+    (unreachable)
+   )
+   (drop
+    (unreachable)
+   )
+   (unreachable)
+   (unreachable)
+   (i32.add
+    (i32.const 1)
+    (unreachable)
+   )
+   (drop
+    (unreachable)
+   )
+   (unreachable)
+   (block
+    (if
+     (i32.const 5)
+     (local.set $31
+      (i32.const 6)
+     )
+     (local.set $31
+      (i32.const 7)
+     )
+    )
+    (local.set $32
+     (local.get $31)
+    )
+    (if
+     (local.get $32)
+     (local.set $35
+      (i32.const 8)
+     )
+     (block
+      (if
+       (i32.const 9)
+       (local.set $33
+        (i32.const 10)
+       )
+       (local.set $33
+        (i32.const 11)
+       )
+      )
+      (local.set $34
+       (local.get $33)
+      )
+      (local.set $35
+       (local.get $34)
+      )
+     )
+    )
+   )
+   (local.set $36
+    (local.get $35)
+   )
+   (drop
+    (local.get $36)
+   )
+   (block $temp
+    (local.set $37
+     (i32.const 1)
+    )
+    (br_if $temp
+     (i32.const 2)
+    )
+    (local.set $38
+     (local.get $37)
+    )
+    (local.set $37
+     (local.get $38)
+    )
+   )
+   (local.set $39
+    (local.get $37)
+   )
+   (drop
+    (local.get $39)
+   )
+  )
+ )
+ (func $flatten-return-value (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (block
+   (return
+    (i32.const 2)
+   )
+   (i32.add
+    (i32.const 1)
+    (unreachable)
+   )
+   (drop
+    (unreachable)
+   )
+   (unreachable)
+   (local.set $0
+    (i32.const 3)
+   )
+  )
+  (local.set $1
+   (local.get $0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $unbug
+  (local $12 i32)
+  (local $432 i32)
+  (local $430 i32)
+  (local $431 i32)
+  (local $9 i32)
+  (local $5 i32)
+  (local $433 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (local $19 i32)
+  (local $20 i32)
+  (local $21 i32)
+  (local $22 i32)
+  (block $block
+   (block
+    (local.set $7
+     (local.get $12)
+    )
+    (local.set $8
+     (i32.eq
+      (local.get $7)
+      (i32.const 65535)
+     )
+    )
+    (if
+     (local.get $8)
+     (block $block44
+      (block $label$78
+       (local.set $430
+        (i32.const 0)
+       )
+      )
+      (local.set $9
+       (local.get $430)
+      )
+      (local.set $432
+       (local.get $9)
+      )
+     )
+     (block $block45
+      (block $label$79
+       (local.set $10
+        (local.get $9)
+       )
+       (local.set $11
+        (local.get $5)
+       )
+       (local.set $12
+        (local.get $12)
+       )
+       (local.set $13
+        (i32.mul
+         (local.get $12)
+         (i32.const 12)
+        )
+       )
+       (local.set $14
+        (i32.add
+         (local.get $11)
+         (local.get $13)
+        )
+       )
+       (local.set $15
+        (i32.load16_u offset=2
+         (local.get $14)
+        )
+       )
+       (local.set $16
+        (i32.lt_u
+         (local.get $10)
+         (local.get $15)
+        )
+       )
+       (local.set $431
+        (local.get $16)
+       )
+      )
+      (local.set $17
+       (local.get $431)
+      )
+      (local.set $432
+       (local.get $17)
+      )
+     )
+    )
+   )
+   (local.set $433
+    (i32.const 1)
+   )
+   (local.set $18
+    (local.get $432)
+   )
+   (local.set $19
+    (local.get $433)
+   )
+   (local.set $20
+    (i32.xor
+     (local.get $18)
+     (local.get $19)
+    )
+   )
+   (local.set $21
+    (local.get $20)
+   )
+  )
+  (local.set $22
+   (local.get $21)
+  )
+  (drop
+   (local.get $22)
+  )
+ )
+ (func $outer-block-typed (param $var$0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (block $block
+   (block $label$0
+    (local.set $1
+     (i32.const 16)
+    )
+   )
+   (local.set $2
+    (local.get $1)
+   )
+   (local.set $3
+    (i32.add
+     (i32.const 1)
+     (local.get $2)
+    )
+   )
+   (local.set $4
+    (local.get $3)
+   )
+  )
+  (local.set $5
+   (local.get $4)
+  )
+  (return
+   (local.get $5)
+  )
+ )
+ (func $nested-br_if-with-value (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block $label$0
+   (block $block
+    (local.set $1
+     (local.get $0)
+    )
+    (local.set $2
+     (local.get $1)
+    )
+   )
+   (local.set $3
+    (local.get $2)
+   )
+   (local.set $4
+    (i32.const 0)
+   )
+   (br_if $label$0
+    (local.get $3)
+   )
+   (local.set $5
+    (local.get $4)
+   )
+   (drop
+    (local.get $5)
+   )
+   (local.set $4
+    (i32.const 1)
+   )
+  )
+  (local.set $6
+   (local.get $4)
+  )
+  (return
+   (local.get $6)
+  )
+ )
+ (func $switch-unreachable
+  (block $label$3
+   (unreachable)
+   (br_table $label$3
+    (unreachable)
+   )
+   (unreachable)
+  )
+ )
+ (func $br_if_order (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (block $outer
+   (block $inner
+    (local.set $1
+     (i32.const 0)
+    )
+    (br_if $outer
+     (i32.const 1)
+    )
+    (local.set $2
+     (local.get $1)
+    )
+    (block $block
+     (local.set $3
+      (i32.const -16)
+     )
+    )
+    (local.set $4
+     (local.get $3)
+    )
+    (local.set $5
+     (call $br_if_order
+      (local.get $4)
+     )
+    )
+    (local.set $6
+     (local.get $2)
+    )
+    (br_if $inner
+     (local.get $5)
+    )
+    (local.set $7
+     (local.get $6)
+    )
+    (local.set $6
+     (local.get $7)
+    )
+   )
+   (local.set $8
+    (local.get $6)
+   )
+   (local.set $1
+    (local.get $8)
+   )
+  )
+  (local.set $9
+   (local.get $1)
+  )
+  (return
+   (local.get $9)
+  )
+ )
+ (func $tees (param $x i32) (param $y i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $2
+    (local.get $x)
+   )
+   (drop
+    (local.get $2)
+   )
+   (unreachable)
+   (unreachable)
+   (drop
+    (unreachable)
+   )
+   (unreachable)
+   (local.set $x
+    (i32.const 2)
+   )
+   (local.set $3
+    (local.get $x)
+   )
+   (local.set $y
+    (local.get $3)
+   )
+   (local.set $4
+    (local.get $y)
+   )
+   (drop
+    (local.get $4)
+   )
+  )
+  (unreachable)
+ )
+ (func $return (param $x i32) (result i32)
+  (local $1 i32)
+  (local.set $1
+   (i32.sub
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (return
+   (local.get $1)
+  )
+  (unreachable)
+ )
+ (func $subtype (result anyref)
+  (local $0 externref)
+  (local $1 anyref)
+  (local $2 externref)
+  (local $3 externref)
+  (local $4 externref)
+  (local $5 externref)
+  (local $6 externref)
+  (local $7 anyref)
+  (block $label0
+   (block $block
+    (local.set $1
+     (ref.null extern)
+    )
+    (local.set $2
+     (ref.null extern)
+    )
+    (br_if $label0
+     (i32.const 0)
+    )
+    (local.set $3
+     (local.get $2)
+    )
+    (local.set $0
+     (local.get $3)
+    )
+    (local.set $4
+     (local.get $0)
+    )
+    (local.set $5
+     (local.get $4)
+    )
+   )
+   (local.set $6
+    (local.get $5)
+   )
+   (local.set $1
+    (local.get $6)
+   )
+  )
+  (local.set $7
+   (local.get $1)
+  )
+  (return
+   (local.get $7)
+  )
+ )
+)
+(module
+ (type $i64_f32_=>_none (func (param i64 f32)))
+ (type $none_=>_i32 (func (result i32)))
+ (export "test" (func $1))
+ (func $0 (param $0 i64) (param $1 f32)
+  (nop)
+ )
+ (func $1 (result i32)
+  (unreachable)
+  (return
+   (i32.const -111)
+  )
+  (call $0
+   (unreachable)
+   (unreachable)
+  )
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/passes/flatten_all-features.wast b/binaryen/test/passes/flatten_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_all-features.wast
@@ -0,0 +1,1057 @@
+(module
+ (type $ii (func (param i32 i32)))
+ (type $1 (func))
+ (type $2 (func (result i32)))
+ (type $3 (func (param i32) (result i32)))
+ (type $4 (func (param i64 i64) (result i64)))
+ (global $x (mut i32) (i32.const 0))
+ (table 1 1 funcref)
+ (elem (i32.const 0) $call-me)
+ (memory $0 10)
+ (func $a1
+  (drop (i32.add (i32.const 0) (i32.const 1)))
+ )
+ (func $a2 (result i32)
+  (i32.add (i32.const 0) (i32.const 1))
+ )
+ (func $a3 (result i32)
+  (i32.add
+   (i32.const 0)
+   (block (result i32)
+    (i32.const 1)
+   )
+  )
+ )
+ (func $a4
+  (drop
+   (i32.add
+    (i32.const 0)
+    (block (result i32)
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $a5 (result i32)
+  (i32.add
+   (block (result i32)
+    (i32.const 0)
+   )
+   (block (result i32)
+    (i32.const 1)
+   )
+  )
+ )
+ (func $a6 (result i32)
+  (local $x i32)
+  (i32.add
+   (block (result i32)
+    (local.tee $x
+     (i32.const 0)
+    )
+   )
+   (block (result i32)
+    (local.tee $x
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $a7 (result i32)
+  (local $x i32)
+  (block (result i32)
+   (i32.add
+    (block (result i32)
+     (local.tee $x
+      (i32.const 0)
+     )
+    )
+    (block (result i32)
+     (local.tee $x
+      (i32.const 1)
+     )
+    )
+   )
+  )
+ )
+ (func $a8 (result i32)
+  (local $x i32)
+  (block $outer (result i32)
+   (block $inner (result i32)
+    (i32.add
+     (block (result i32)
+      (br $inner
+       (i32.const -1)
+      )
+      (br $outer
+       (i32.const 0)
+      )
+      (i32.const 1)
+     )
+     (block (result i32)
+      (br $outer
+       (i32.const 2)
+      )
+      (local.tee $x
+       (i32.const 3)
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $a9 (result i32)
+  (loop $outer (result i32)
+   (loop $inner (result i32)
+    (br_if $outer (i32.const -1))
+    (i32.add
+     (i32.const 0)
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $a10 (result i32)
+  (local $x i32)
+  (block $outer (result i32)
+   (drop (br_if $outer (i32.const 0) (i32.const 1)))
+   (drop (br_if $outer (local.tee $x (i32.const 2)) (i32.const 3)))
+   (drop (br_if $outer (i32.const 4) (local.tee $x (i32.const 5))))
+   (drop (br_if $outer (local.tee $x (i32.const 6)) (local.tee $x (i32.const 7))))
+   (br $outer (i32.const 8))
+  )
+ )
+ (func $a11
+  (if (i32.const 0)
+   (drop (i32.const 1))
+  )
+ )
+ (func $a12 (result i32)
+  (if (result i32) (i32.const 0)
+   (i32.const 1)
+   (i32.const 2)
+  )
+ )
+ (func $a13 (result i32)
+  (block $x i32
+   (if i32
+    (br_table $x (i32.const 2) (i32.const 0))
+    (i32.const 0)
+    (i32.const 1)
+   )
+  )
+ )
+ (func $a14 (result i32)
+  (block i32
+   (select
+    (i32.const 0) (i32.const 1) (br_table 0 (i32.const 7) (i32.const 1))
+   )
+  )
+ )
+ (func $a15
+  (if
+   (i32.load16_u
+    (i32.const 53)
+   )
+   (unreachable)
+   (drop
+    (block $label$3 (result f32)
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $a16 (result i32)
+  (local $x i32)
+  (block $label$1 (result i32)
+   (drop
+    (br_if $label$1
+     (local.tee $x ;; set here, then it is undone later, but this value is used, not the contents of $x!
+      (i32.const 1)
+     )
+     (i32.eqz ;; 0 into 1, so take the br_if
+      (block $label$2 (result i32)
+       (local.set $x
+        (i32.const 0) ;; undo the above tee
+       )
+       (i32.const 0)
+      )
+     )
+    )
+   )
+   (i32.const 0)
+  )
+ )
+ (func $a17 (result f32)
+  (local $var$0 f32)
+  (f32.max
+   (local.get $var$0)
+   (select
+    (local.tee $var$0
+     (f32.const -137438953472)
+    )
+    (local.get $var$0)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $a18 (result i32)
+  (block $label$1 (result i32)
+   (i32.load16_s
+    (drop ;; an unreachable drop. one we move its contents outside, it should stay unreachable
+     (br_if $label$1
+      (i32.const 1)
+      (unreachable)
+     )
+    )
+   )
+  )
+ )
+ (func $a19 (result f32)
+  (block $label$0
+   (block $label$1
+    (drop
+     (select
+      (unreachable) ;; move this out, so it happens before the return
+      (return
+       (f32.const 4289944320)
+      )
+      (i32.const 65535)
+     )
+    )
+   )
+  )
+ )
+ (func $call-me (param $0 i32) (param $1 i32)
+  (nop)
+ )
+ (func $code-to-kill
+  (local $x i32)
+  (block $out
+   (br $out)
+   (drop
+    (i32.const 0)
+   )
+   (if
+    (i32.const 1)
+    (drop
+     (i32.const 2)
+    )
+   )
+   (br_table $out $out $out $out
+    (i32.const 3)
+   )
+   (call $code-to-kill)
+  )
+  (if
+   (i32.const 0)
+   (block $out1
+    (unreachable)
+    (drop
+     (i32.const 0)
+    )
+   )
+  )
+  (if
+   (i32.const 0)
+   (block $out3
+    (return)
+    (drop
+     (i32.const 0)
+    )
+   )
+  )
+  (block $out4
+   (br_table $out4 $out4 $out4 $out4
+    (i32.const 4)
+   )
+   (drop
+    (i32.const 0)
+   )
+  )
+  (block $out5
+   (br_if $out5
+    (i32.const 3)
+   )
+   (drop
+    (i32.const 0)
+   )
+  )
+  (if
+   (i32.const 0)
+   (block $block4
+    (if
+     (i32.const 0)
+     (block $out8
+      (unreachable)
+      (drop
+       (i32.const 0)
+      )
+     )
+     (block $out9
+      (unreachable)
+      (drop
+       (i32.const 0)
+      )
+     )
+    )
+    (drop
+     (i32.const 0)
+    )
+   )
+  )
+  (if
+   (i32.const 0)
+   (drop
+    (block $out11 (result i32)
+     (br $out11
+      (unreachable)
+     )
+     (drop
+      (i32.const 0)
+     )
+     (unreachable)
+    )
+   )
+  )
+  (if
+   (i32.const 0)
+   (drop
+    (block $out13 (result i32)
+     (br_if $out13
+      (unreachable)
+      (i32.const 0)
+     )
+     (drop
+      (i32.const 0)
+     )
+     (unreachable)
+    )
+   )
+  )
+  (if
+   (i32.const 0)
+   (drop
+    (block $out15 (result i32)
+     (br_if $out15
+      (unreachable)
+      (unreachable)
+     )
+     (drop
+      (i32.const 0)
+     )
+     (unreachable)
+    )
+   )
+  )
+  (block $out16
+   (block $in
+    (br_if $out16
+     (i32.const 1)
+    )
+   )
+   (unreachable)
+  )
+  (if
+   (i32.const 0)
+   (block $block11
+    (block $out18
+     (block $in19
+      (br_if $in19
+       (i32.const 1)
+      )
+     )
+     (unreachable)
+    )
+    (drop
+     (i32.const 10)
+    )
+   )
+  )
+  (block $out20
+   (block $in21
+    (br_table $out20 $in21
+     (i32.const 1)
+    )
+   )
+   (unreachable)
+  )
+  (block $out22
+   (block $in23
+    (br_table $in23 $out22
+     (i32.const 1)
+    )
+   )
+   (unreachable)
+  )
+  (if
+   (i32.const 0)
+   (block $block13
+    (block $out25
+     (block $in26
+      (br_table $in26 $in26
+       (i32.const 1)
+      )
+     )
+     (unreachable)
+    )
+    (drop
+     (i32.const 10)
+    )
+   )
+  )
+  (if
+   (i32.const 0)
+   (block $block15
+    (drop
+     (i32.const 10)
+    )
+    (drop
+     (i32.const 42)
+    )
+    (unreachable)
+    (return
+     (unreachable)
+    )
+    (unreachable)
+    (return)
+   )
+  )
+  (if
+   (i32.const 0)
+   (loop $loop-in18
+    (unreachable)
+   )
+  )
+  (block $out29
+   (loop $in30
+    (br_if $out29
+     (i32.const 1)
+    )
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 0)
+   (block $block20
+    (loop $in32
+     (br_if $in32
+      (i32.const 1)
+     )
+     (unreachable)
+    )
+    (drop
+     (i32.const 10)
+    )
+   )
+  )
+  (if
+   (i32.const 1)
+   (call $call-me
+    (i32.const 123)
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 2)
+   (call $call-me
+    (unreachable)
+    (i32.const 0)
+   )
+  )
+  (if
+   (i32.const 3)
+   (call $call-me
+    (unreachable)
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const -1)
+   (call_indirect (type $ii)
+    (i32.const 123)
+    (i32.const 456)
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const -2)
+   (call_indirect (type $ii)
+    (i32.const 139)
+    (unreachable)
+    (i32.const 0)
+   )
+  )
+  (if
+   (i32.const -3)
+   (call_indirect (type $ii)
+    (i32.const 246)
+    (unreachable)
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const -4)
+   (call_indirect (type $ii)
+    (unreachable)
+    (unreachable)
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 11)
+   (local.set $x
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 22)
+   (drop
+    (i32.load
+     (unreachable)
+    )
+   )
+  )
+  (if
+   (i32.const 33)
+   (i32.store
+    (i32.const 0)
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 44)
+   (i32.store
+    (unreachable)
+    (i32.const 0)
+   )
+  )
+  (if
+   (i32.const 55)
+   (i32.store
+    (unreachable)
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 66)
+   (drop
+    (i32.eqz
+     (unreachable)
+    )
+   )
+  )
+  (if
+   (i32.const 77)
+   (drop
+    (i32.add
+     (unreachable)
+     (i32.const 0)
+    )
+   )
+  )
+  (if
+   (i32.const 88)
+   (drop
+    (i32.add
+     (i32.const 0)
+     (unreachable)
+    )
+   )
+  )
+  (if
+   (i32.const 99)
+   (i32.add
+    (unreachable)
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 100)
+   (drop
+    (select
+     (i32.const 123)
+     (i32.const 456)
+     (unreachable)
+    )
+   )
+  )
+  (if
+   (i32.const 101)
+   (drop
+    (select
+     (i32.const 123)
+     (unreachable)
+     (i32.const 456)
+    )
+   )
+  )
+  (if
+   (i32.const 102)
+   (drop
+    (select
+     (unreachable)
+     (i32.const 123)
+     (i32.const 456)
+    )
+   )
+  )
+  (drop
+   (i32.const 1337)
+  )
+ )
+ (func $killer (type $1)
+  (unreachable)
+  (drop
+   (i32.const 1000)
+  )
+ )
+ (func $target (type $1)
+  (drop
+   (i32.const 2000)
+  )
+ )
+ (func $typed-block-none-then-unreachable (type $2) (result i32)
+  (block $top-typed (result i32)
+   (block $switch$0
+    (return
+     (i32.const 0)
+    )
+    (br $switch$0)
+   )
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $typed-block-remove-br-changes-type (type $3) (param $$$0 i32) (result i32)
+  (block $switch$7
+   (block $switch-default$10
+    (block $switch-case$9
+     (block $switch-case$8
+      (br_table $switch-case$9 $switch-case$8 $switch-default$10
+       (i32.const -1)
+      )
+     )
+    )
+    (return
+     (local.get $$$0)
+    )
+    (br $switch$7)
+   )
+   (return
+    (local.get $$$0)
+   )
+  )
+  (return
+   (i32.const 0)
+  )
+ )
+ (func $global (type $1)
+  (unreachable)
+  (drop
+   (global.get $x)
+  )
+  (global.set $x
+   (i32.const 1)
+  )
+ )
+ (func $ret (type $2) (result i32)
+  (return
+   (i32.const 0)
+  )
+  (nop)
+  (i32.const 0)
+ )
+ (func $unreachable-br (type $2) (result i32)
+  (block $out (result i32)
+   (br $out
+    (br $out
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $unreachable-br-loop (type $2) (result i32)
+  (loop $out
+   (br $out)
+  )
+ )
+ (func $unreachable-block-ends-switch (type $2) (result i32)
+  (block $label$0 (result i32)
+   (block $label$3
+    (nop)
+    (br_table $label$3
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (i32.const 19)
+  )
+ )
+ (func $unreachable-block-ends-br_if (result i32)
+  (block $label$0 (result i32)
+   (block $label$2
+    (nop)
+    (br_if $label$2
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (i32.const 19)
+  )
+ )
+ (func $unreachable-brs-3 (result i32)
+  (block $label$0 (result i32)
+   (br $label$0
+    (memory.grow
+     (br $label$0
+      (i32.const 18)
+     )
+    )
+   )
+   (i32.const 21)
+  )
+ )
+ (func $unreachable-brs-4 (param $var$0 i32) (result i32)
+  (i32.add
+   (i32.const 1)
+   (block $label$0 (result i32)
+    (br $label$0
+     (block $label$1 (result i32)
+      (drop
+       (br_if $label$0
+        (i32.const 4104)
+        (unreachable)
+       )
+      )
+      (i32.const 4)
+     )
+    )
+    (i32.const 16)
+   )
+  )
+ )
+ (func $call-unreach (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $2 i64)
+  (if (result i64)
+   (i64.eqz
+    (local.get $var$0)
+   )
+   (block $label$0 (result i64)
+    (local.get $var$1)
+   )
+   (block $label$1 (result i64)
+    (call $call-unreach
+     (i64.sub
+      (local.get $var$0)
+      (i64.const 1)
+     )
+     (i64.mul
+      (block $block (result i64)
+       (local.set $2
+        (local.get $var$0)
+       )
+       (nop)
+       (local.get $2)
+      )
+      (unreachable)
+     )
+    )
+   )
+  )
+ )
+
+  ;; flatten-specific
+  (func $test-flatten
+    (block $out
+      (drop (i32.add (i32.const 1) (i32.const 2)))
+      (drop (i32.add (i32.const 1) (br $out)))
+      (drop (i32.add (br $out) (i32.const 1)))
+      (drop (i32.add (i32.const 1) (br_table $out $out $out $out (i32.const 3))))
+      (drop (i32.add (i32.const 1)
+        (block (result i32)
+          (drop (i32.const 2))
+          (drop (i32.const 3))
+          (i32.const 4)
+        )
+      ))
+      (drop (i32.add (i32.const 1)
+        (block $in (result i32)
+          (drop
+            (block $switch-in (result i32)
+              (br_table $in $switch-in $in (i32.const 2) (i32.const 777))
+            )
+          )
+          (br $in (i32.const 3))
+          (i32.const 4)
+        )
+      ))
+      (drop (i32.add (i32.const 1)
+        (loop (result i32)
+          (i32.const 5)
+        )
+      ))
+      (drop (i32.add (i32.const 1)
+        (if (result i32)
+          (i32.const 6)
+          (i32.const 7)
+          (i32.const 8)
+        )
+      ))
+      (drop
+        (select
+         (i32.const 9)
+         (i32.const 10)
+         (i32.const 11)
+        )
+      )
+      (drop
+        (select
+         (br $out)
+         (i32.const 10)
+         (i32.const 11)
+        )
+      )
+      (drop
+        (select
+         (i32.const 9)
+         (br $out)
+         (i32.const 11)
+        )
+      )
+      (drop
+        (select
+         (i32.const 9)
+         (i32.const 10)
+         (br $out)
+        )
+      )
+      (drop
+        (select
+          (if (result i32)
+            (i32.const 11)
+            (i32.const 12)
+            (i32.const 13)
+          )
+          (i32.const 9)
+          (i32.const 10)
+        )
+      )
+      (drop
+        (select
+          (i32.const 9)
+          (if (result i32)
+            (i32.const 11)
+            (i32.const 12)
+            (i32.const 13)
+          )
+          (i32.const 10)
+        )
+      )
+      (drop
+        (select
+          (i32.const 9)
+          (i32.const 10)
+          (if (result i32)
+            (i32.const 11)
+            (i32.const 12)
+            (i32.const 13)
+          )
+        )
+      )
+      (drop
+        (select
+          (if (result i32)
+            (i32.const 11)
+            (i32.const 12)
+            (i32.const 13)
+          )
+          (i32.const 14)
+          (if (result i32)
+            (i32.const 15)
+            (i32.const 16)
+            (i32.const 17)
+          )
+        )
+      )
+      (drop (i32.add (i32.const 1) (return)))
+      (drop (i32.add (i32.const 1) (unreachable)))
+      (drop
+        (if (result i32)
+          (if (result i32)
+            (i32.const 5)
+            (i32.const 6)
+            (i32.const 7)
+          )
+          (i32.const 8)
+          (if (result i32)
+            (i32.const 9)
+            (i32.const 10)
+            (i32.const 11)
+          )
+        )
+      )
+      (drop
+        (block $temp (result i32)
+          (br_if $temp
+            (i32.const 1)
+            (i32.const 2)
+          )
+        )
+      )
+    )
+  )
+  (func $flatten-return-value (result i32)
+    (drop (i32.add (i32.const 1) (return (i32.const 2))))
+    (i32.const 3)
+  )
+  (func $unbug
+   (local $12 i32)
+   (local $432 i32)
+   (local $430 i32)
+   (local $431 i32)
+   (local $9 i32)
+   (local $5 i32)
+   (local $433 i32)
+   (drop
+    (block (result i32)
+     (if
+      (i32.eq
+       (local.get $12)
+       (i32.const 65535)
+      )
+      (block
+       (block $label$78
+        (local.set $430
+         (i32.const 0)
+        )
+       )
+       (local.set $432
+        (local.get $430)
+       )
+      )
+      (block
+       (block $label$79
+        (local.set $431
+         (i32.lt_u
+          (local.get $9)
+          (i32.load16_u offset=2
+           (i32.add
+            (local.get $5)
+            (i32.mul
+             (local.get $12)
+             (i32.const 12)
+            )
+           )
+          )
+         )
+        )
+       )
+       (local.set $432
+        (local.get $431)
+       )
+      )
+     )
+     (local.set $433
+      (i32.const 1)
+     )
+     (i32.xor
+      (local.get $432)
+      (local.get $433)
+     )
+    )
+   )
+  )
+  (func $outer-block-typed (type $3) (param $var$0 i32) (result i32)
+   (block (result i32)
+    (i32.add
+     (i32.const 1)
+     (block $label$0 (result i32)
+      (i32.const 16)
+     )
+    )
+   )
+  )
+  (func $nested-br_if-with-value (result i32)
+   (local $0 i32)
+   (block $label$0 (result i32)
+    (drop
+     (br_if $label$0
+      (i32.const 0)
+      (block (result i32)
+       (local.get $0)
+      )
+     )
+    )
+    (i32.const 1)
+   )
+  )
+  (func $switch-unreachable
+   (block $label$3
+    (br_table $label$3
+     (unreachable)
+    )
+   )
+  )
+  (func $br_if_order (param $x i32) (result i32)
+   (block $outer (result i32)
+    (block $inner (result i32)
+     (br_if $inner
+      (br_if $outer
+       (i32.const 0)
+       (i32.const 1)
+      )
+      (call $br_if_order
+       (block (result i32)
+        (i32.const -16)
+       )
+      )
+     )
+    )
+   )
+  )
+  (func $tees (param $x i32) (param $y i32)
+    (drop (local.tee $x (i32.const 1)))
+    (drop (local.tee $x (unreachable)))
+    (drop (local.tee $y (local.tee $x (i32.const 2))))
+  )
+  (func $return (param $x i32) (result i32)
+    (return (i32.sub (i32.const 1) (i32.const 2)))
+  )
+
+  ;; subtypes
+
+  ;; br_if leaves a value on the stack if not taken, which later can be the last
+  ;; element of the enclosing innermost block and flow out. So in case br_if
+  ;; targets an outer branch whose return type is a supertype of the br_if's
+  ;; value type, we need the value to be set into two locals: one with the outer
+  ;; block's type, and one with its value type.
+  (func $subtype (result anyref)
+    (local $0 externref)
+    (block $label0 (result anyref)
+      (block (result externref)
+        (local.tee $0
+          (br_if $label0
+            (ref.null extern)
+            (i32.const 0)
+          )
+        )
+      )
+    )
+  )
+)
+(module
+ (func $0 (param $0 i64) (param $1 f32)
+  (nop)
+ )
+ (func "test" (result i32)
+  (call $0
+   (unreachable) ;; the unreachable should be handled properly, and not be
+                 ;; reordered with the return
+   (return
+    (i32.const -111)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/flatten_dfo_O3_enable-threads.txt b/binaryen/test/passes/flatten_dfo_O3_enable-threads.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_dfo_O3_enable-threads.txt
@@ -0,0 +1,50 @@
+(module
+ (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)))
+ (memory $0 (shared 1 1))
+ (export "one" (func $0))
+ (export "two" (func $1))
+ (export "use-var" (func $2))
+ (export "bad1" (func $3))
+ (export "only-dfo" (func $4))
+ (export "dfo-tee-get" (func $5))
+ (func $0 (; has Stack IR ;)
+  (block $label$3
+   (br_if $label$3
+    (i32.load
+     (i32.const 3060)
+    )
+   )
+  )
+  (unreachable)
+ )
+ (func $1 (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
+  (i32.const 0)
+ )
+ (func $2 (; has Stack IR ;) (param $0 i64) (param $1 i32) (result f64)
+  (loop $label$8
+   (br_if $label$8
+    (local.get $1)
+   )
+  )
+  (unreachable)
+ )
+ (func $3 (; has Stack IR ;)
+  (i32.store
+   (i32.const 1)
+   (i32.const -16384)
+  )
+ )
+ (func $4 (; has Stack IR ;) (param $0 f64) (result f64)
+  (local $1 i32)
+  (loop $label$1
+   (br $label$1)
+  )
+ )
+ (func $5 (; has Stack IR ;) (result i32)
+  (i32.const 1)
+ )
+)
diff --git a/binaryen/test/passes/flatten_dfo_O3_enable-threads.wast b/binaryen/test/passes/flatten_dfo_O3_enable-threads.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_dfo_O3_enable-threads.wast
@@ -0,0 +1,203 @@
+(module
+ (memory $0 (shared 1 1))
+ (func "one"
+  (loop $label$2
+   (br_if $label$2
+    (block $label$3 (result i32)
+     (drop
+      (br_if $label$3
+       (i32.const 0)
+       (i32.load
+        (i32.const 3060)
+       )
+      )
+     )
+     (i32.const 0)
+    )
+   )
+  )
+  (unreachable)
+ )
+ (func "two" (param $var$0 i32) (param $var$1 i32) (result i32)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (if
+   (i32.const 0)
+   (i32.store8
+    (i32.const 8)
+    (block $label$2 (result i32)
+     (drop
+      (br_if $label$2
+       (i32.const 1)
+       (i32.const 0)
+      )
+     )
+     (if
+      (i32.const 0)
+      (drop
+       (br_if $label$2
+        (i32.const 1)
+        (i32.const 1)
+       )
+      )
+     )
+     (block $label$4
+      (br_if $label$4
+       (i32.const 0)
+      )
+      (br_if $label$4
+       (i32.const 0)
+      )
+      (drop
+       (br_if $label$2
+        (i32.const 1)
+        (i32.const 0)
+       )
+      )
+     )
+     (i32.const 6704)
+    )
+   )
+  )
+  (nop)
+  (i32.const 0)
+ )
+ (func "use-var" (param $var$0 i64) (param $var$1 i32) (result f64)
+  (local $var$2 i32)
+  (block $label$1
+   (br_table $label$1 $label$1 $label$1 $label$1 $label$1 $label$1 $label$1 $label$1 $label$1 $label$1
+    (i32.wrap_i64
+     (if (result i64)
+      (i32.const 0)
+      (i64.const 1)
+      (if (result i64)
+       (if (result i32)
+        (i32.const 0)
+        (unreachable)
+        (block $label$6 (result i32)
+         (block $label$7
+          (loop $label$8
+           (br_if $label$8
+            (br_if $label$6
+             (local.tee $var$2
+              (block $label$9 (result i32)
+               (local.get $var$1)
+              )
+             )
+             (i32.const 0)
+            )
+           )
+           (loop $label$10
+            (if
+             (i32.const 0)
+             (local.set $var$2
+              (local.get $var$1)
+             )
+            )
+           )
+           (drop
+            (i32.eqz
+             (local.get $var$2)
+            )
+           )
+          )
+         )
+         (unreachable)
+        )
+       )
+       (unreachable)
+       (i64.const 1)
+      )
+     )
+    )
+   )
+  )
+  (unreachable)
+ )
+ (func "bad1"
+  (local $var$2 i32)
+  (local $var$4 i32)
+  (block $label$1
+   (loop $label$2
+    (local.set $var$4
+     (if (result i32)
+      (i32.const 0)
+      (block (result i32)
+       (local.set $var$4
+        (local.tee $var$2
+         (i32.xor
+          (i32.const 0)
+          (i32.const -1)
+         )
+        )
+       )
+       (i32.const 0)
+      )
+      (block (result i32)
+       (local.set $var$4
+        (local.tee $var$2
+         (i32.xor
+          (i32.const 0)
+          (i32.const -1)
+         )
+        )
+       )
+       (i32.const 0)
+      )
+     )
+    )
+    (i32.store
+     (i32.const 1)
+     (i32.shl
+      (local.get $var$2)
+      (i32.const 14)
+     )
+    )
+   )
+  )
+ )
+ (func "only-dfo" (param $var$0 f64) (result f64)
+  (local $var$1 i32)
+  (local $var$2 i32)
+  (loop $label$1
+   (if
+    (local.tee $var$1
+     (local.tee $var$2
+      (local.get $var$1)
+     )
+    )
+    (if
+     (local.get $var$2)
+     (i64.atomic.store32 offset=3
+      (i32.and
+       (local.get $var$1) ;; only dfo can figure out that this is 0
+       (i32.const 15)
+      )
+      (i64.const -32768)
+     )
+    )
+   )
+   (br $label$1)
+  )
+ )
+ (func "dfo-tee-get" (result i32)
+  (local $0 i32)
+  (if (result i32)
+   (local.tee $0
+    (i32.const 1)
+   )
+   (loop $label$2 (result i32)
+    (select
+     (i32.const 1)
+     (i32.const -1709605511)
+     (local.get $0)
+    )
+   )
+   (unreachable)
+  )
+ )
+)
+
diff --git a/binaryen/test/passes/flatten_i64-to-i32-lowering.txt b/binaryen/test/passes/flatten_i64-to-i32-lowering.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_i64-to-i32-lowering.txt
@@ -0,0 +1,551 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $none_=>_i64 (func (result i64)))
+ (import "env" "func" (func $import (result i64)))
+ (memory $0 1 1)
+ (global $i64toi32_i32$HIGH_BITS (mut i32) (i32.const 0))
+ (func $defined (result i32)
+  (local $0 i32)
+  (local $0$hi i32)
+  (local $i64toi32_i32$0 i32)
+  (local $i64toi32_i32$1 i32)
+  (local $i64toi32_i32$2 i32)
+  (local $i64toi32_i32$3 i32)
+  (local $i64toi32_i32$4 i32)
+  (local $i64toi32_i32$5 i32)
+  (block
+   (local.set $0
+    (block (result i32)
+     (local.set $i64toi32_i32$2
+      (block (result i32)
+       (local.set $i64toi32_i32$0
+        (i32.const 0)
+       )
+       (i32.const 1)
+      )
+     )
+     (local.set $i64toi32_i32$3
+      (block (result i32)
+       (local.set $i64toi32_i32$1
+        (i32.const 0)
+       )
+       (i32.const 2)
+      )
+     )
+     (local.set $i64toi32_i32$4
+      (i32.add
+       (local.get $i64toi32_i32$2)
+       (local.get $i64toi32_i32$3)
+      )
+     )
+     (local.set $i64toi32_i32$5
+      (i32.add
+       (local.get $i64toi32_i32$0)
+       (local.get $i64toi32_i32$1)
+      )
+     )
+     (if
+      (i32.lt_u
+       (local.get $i64toi32_i32$4)
+       (local.get $i64toi32_i32$3)
+      )
+      (local.set $i64toi32_i32$5
+       (i32.add
+        (local.get $i64toi32_i32$5)
+        (i32.const 1)
+       )
+      )
+     )
+     (local.get $i64toi32_i32$4)
+    )
+   )
+   (local.set $0$hi
+    (local.get $i64toi32_i32$5)
+   )
+  )
+  (block
+   (local.set $i64toi32_i32$2
+    (block (result i32)
+     (local.set $i64toi32_i32$5
+      (local.get $0$hi)
+     )
+     (local.get $0)
+    )
+   )
+   (global.set $i64toi32_i32$HIGH_BITS
+    (local.get $i64toi32_i32$5)
+   )
+   (return
+    (local.get $i64toi32_i32$2)
+   )
+  )
+ )
+ (func $unreachable-select-i64 (result i32)
+  (local $i64toi32_i32$0 i32)
+  (unreachable)
+  (block
+   (drop
+    (block (result i32)
+     (local.set $i64toi32_i32$0
+      (i32.const 0)
+     )
+     (i32.const 1)
+    )
+   )
+   (unreachable)
+   (drop
+    (i32.const 2)
+   )
+  )
+  (unreachable)
+ )
+ (func $unreachable-select-i64-b (result i32)
+  (local $i64toi32_i32$0 i32)
+  (unreachable)
+  (block
+   (unreachable)
+   (drop
+    (block (result i32)
+     (local.set $i64toi32_i32$0
+      (i32.const 0)
+     )
+     (i32.const 3)
+    )
+   )
+   (drop
+    (i32.const 4)
+   )
+  )
+  (unreachable)
+ )
+ (func $unreachable-select-i64-c (result i32)
+  (local $i64toi32_i32$0 i32)
+  (local $i64toi32_i32$1 i32)
+  (unreachable)
+  (block
+   (drop
+    (block (result i32)
+     (local.set $i64toi32_i32$0
+      (i32.const 0)
+     )
+     (i32.const 5)
+    )
+   )
+   (drop
+    (block (result i32)
+     (local.set $i64toi32_i32$1
+      (i32.const 0)
+     )
+     (i32.const 6)
+    )
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $mem
+  (local $0 i32)
+  (local $0$hi i32)
+  (local $1 i32)
+  (local $1$hi i32)
+  (local $2 i32)
+  (local $2$hi i32)
+  (local $3 i32)
+  (local $3$hi i32)
+  (local $4 i32)
+  (local $4$hi i32)
+  (local $i64toi32_i32$0 i32)
+  (local $i64toi32_i32$1 i32)
+  (local $i64toi32_i32$2 i32)
+  (block
+   (local.set $0
+    (block (result i32)
+     (local.set $i64toi32_i32$2
+      (i32.const 0)
+     )
+     (local.set $i64toi32_i32$0
+      (i32.load
+       (local.get $i64toi32_i32$2)
+      )
+     )
+     (local.set $i64toi32_i32$1
+      (i32.load offset=4
+       (local.get $i64toi32_i32$2)
+      )
+     )
+     (local.get $i64toi32_i32$0)
+    )
+   )
+   (local.set $0$hi
+    (local.get $i64toi32_i32$1)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $i64toi32_i32$1
+     (local.get $0$hi)
+    )
+    (local.get $0)
+   )
+  )
+  (block
+   (local.set $1
+    (block (result i32)
+     (local.set $i64toi32_i32$2
+      (i32.const 0)
+     )
+     (local.set $i64toi32_i32$1
+      (i32.load
+       (local.get $i64toi32_i32$2)
+      )
+     )
+     (local.set $i64toi32_i32$0
+      (i32.load offset=4
+       (local.get $i64toi32_i32$2)
+      )
+     )
+     (local.get $i64toi32_i32$1)
+    )
+   )
+   (local.set $1$hi
+    (local.get $i64toi32_i32$0)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $i64toi32_i32$0
+     (local.get $1$hi)
+    )
+    (local.get $1)
+   )
+  )
+  (block
+   (local.set $2
+    (block (result i32)
+     (local.set $i64toi32_i32$2
+      (i32.const 0)
+     )
+     (local.set $i64toi32_i32$0
+      (i32.load align=2
+       (local.get $i64toi32_i32$2)
+      )
+     )
+     (local.set $i64toi32_i32$1
+      (i32.load offset=4 align=2
+       (local.get $i64toi32_i32$2)
+      )
+     )
+     (local.get $i64toi32_i32$0)
+    )
+   )
+   (local.set $2$hi
+    (local.get $i64toi32_i32$1)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $i64toi32_i32$1
+     (local.get $2$hi)
+    )
+    (local.get $2)
+   )
+  )
+  (block
+   (local.set $3
+    (block (result i32)
+     (local.set $i64toi32_i32$2
+      (i32.const 0)
+     )
+     (local.set $i64toi32_i32$1
+      (i32.load align=1
+       (local.get $i64toi32_i32$2)
+      )
+     )
+     (local.set $i64toi32_i32$0
+      (i32.load offset=4 align=1
+       (local.get $i64toi32_i32$2)
+      )
+     )
+     (local.get $i64toi32_i32$1)
+    )
+   )
+   (local.set $3$hi
+    (local.get $i64toi32_i32$0)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $i64toi32_i32$0
+     (local.get $3$hi)
+    )
+    (local.get $3)
+   )
+  )
+  (block
+   (local.set $4
+    (block (result i32)
+     (local.set $i64toi32_i32$2
+      (i32.const 0)
+     )
+     (local.set $i64toi32_i32$0
+      (i32.load
+       (local.get $i64toi32_i32$2)
+      )
+     )
+     (local.set $i64toi32_i32$1
+      (i32.load offset=4
+       (local.get $i64toi32_i32$2)
+      )
+     )
+     (local.get $i64toi32_i32$0)
+    )
+   )
+   (local.set $4$hi
+    (local.get $i64toi32_i32$1)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $i64toi32_i32$1
+     (local.get $4$hi)
+    )
+    (local.get $4)
+   )
+  )
+  (block
+   (local.set $i64toi32_i32$0
+    (i32.const 0)
+   )
+   (i32.store
+    (local.get $i64toi32_i32$0)
+    (block (result i32)
+     (local.set $i64toi32_i32$1
+      (i32.const 0)
+     )
+     (i32.const 1)
+    )
+   )
+   (i32.store offset=4
+    (local.get $i64toi32_i32$0)
+    (local.get $i64toi32_i32$1)
+   )
+  )
+  (block
+   (local.set $i64toi32_i32$0
+    (i32.const 0)
+   )
+   (i32.store
+    (local.get $i64toi32_i32$0)
+    (block (result i32)
+     (local.set $i64toi32_i32$1
+      (i32.const 0)
+     )
+     (i32.const 2)
+    )
+   )
+   (i32.store offset=4
+    (local.get $i64toi32_i32$0)
+    (local.get $i64toi32_i32$1)
+   )
+  )
+  (block
+   (local.set $i64toi32_i32$0
+    (i32.const 0)
+   )
+   (i32.store align=2
+    (local.get $i64toi32_i32$0)
+    (block (result i32)
+     (local.set $i64toi32_i32$1
+      (i32.const 0)
+     )
+     (i32.const 3)
+    )
+   )
+   (i32.store offset=4 align=2
+    (local.get $i64toi32_i32$0)
+    (local.get $i64toi32_i32$1)
+   )
+  )
+  (block
+   (local.set $i64toi32_i32$0
+    (i32.const 0)
+   )
+   (i32.store align=1
+    (local.get $i64toi32_i32$0)
+    (block (result i32)
+     (local.set $i64toi32_i32$1
+      (i32.const 0)
+     )
+     (i32.const 4)
+    )
+   )
+   (i32.store offset=4 align=1
+    (local.get $i64toi32_i32$0)
+    (local.get $i64toi32_i32$1)
+   )
+  )
+  (block
+   (local.set $i64toi32_i32$0
+    (i32.const 0)
+   )
+   (i32.store
+    (local.get $i64toi32_i32$0)
+    (block (result i32)
+     (local.set $i64toi32_i32$1
+      (i32.const 0)
+     )
+     (i32.const 5)
+    )
+   )
+   (i32.store offset=4
+    (local.get $i64toi32_i32$0)
+    (local.get $i64toi32_i32$1)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (global $f (mut i32) (i32.const -1412567121))
+ (global $g (mut i32) (global.get $f))
+ (global $f$hi (mut i32) (i32.const 305419896))
+ (global $g$hi (mut i32) (global.get $f$hi))
+ (global $i64toi32_i32$HIGH_BITS (mut i32) (i32.const 0))
+ (export "exp" (func $1))
+ (export "unreach" (func $2))
+ (func $call (param $0 i32) (param $0$hi i32)
+  (nop)
+ )
+ (func $1
+  (local $0 i32)
+  (local $0$hi i32)
+  (local $i64toi32_i32$0 i32)
+  (block
+   (local.set $0
+    (block (result i32)
+     (local.set $i64toi32_i32$0
+      (global.get $f$hi)
+     )
+     (global.get $f)
+    )
+   )
+   (local.set $0$hi
+    (local.get $i64toi32_i32$0)
+   )
+  )
+  (call $call
+   (block (result i32)
+    (local.set $i64toi32_i32$0
+     (local.get $0$hi)
+    )
+    (local.get $0)
+   )
+   (local.get $i64toi32_i32$0)
+  )
+  (block
+   (global.set $f
+    (block (result i32)
+     (local.set $i64toi32_i32$0
+      (i32.const 287454020)
+     )
+     (i32.const 1432778632)
+    )
+   )
+   (global.set $f$hi
+    (local.get $i64toi32_i32$0)
+   )
+  )
+ )
+ (func $2
+  (local $0 i32)
+  (local $0$hi i32)
+  (local $1 i32)
+  (local $1$hi i32)
+  (local $i64toi32_i32$0 i32)
+  (block $label$1
+   (unreachable)
+   (unreachable)
+  )
+  (block
+   (local.set $1
+    (block (result i32)
+     (local.set $i64toi32_i32$0
+      (local.get $0$hi)
+     )
+     (local.get $0)
+    )
+   )
+   (local.set $1$hi
+    (local.get $i64toi32_i32$0)
+   )
+  )
+  (block
+   (global.set $f
+    (block (result i32)
+     (local.set $i64toi32_i32$0
+      (local.get $1$hi)
+     )
+     (local.get $1)
+    )
+   )
+   (global.set $f$hi
+    (local.get $i64toi32_i32$0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (global $f (mut i32) (i32.const -1412567121))
+ (global $g (mut i32) (global.get $f))
+ (global $f$hi (mut i32) (i32.const 305419896))
+ (global $g$hi (mut i32) (global.get $f$hi))
+ (global $i64toi32_i32$HIGH_BITS (mut i32) (i32.const 0))
+ (export "exp" (func $1))
+ (func $call (param $0 i32) (param $0$hi i32)
+  (nop)
+ )
+ (func $1
+  (local $0 i32)
+  (local $0$hi i32)
+  (local $i64toi32_i32$0 i32)
+  (block
+   (local.set $0
+    (block (result i32)
+     (local.set $i64toi32_i32$0
+      (global.get $f$hi)
+     )
+     (global.get $f)
+    )
+   )
+   (local.set $0$hi
+    (local.get $i64toi32_i32$0)
+   )
+  )
+  (call $call
+   (block (result i32)
+    (local.set $i64toi32_i32$0
+     (local.get $0$hi)
+    )
+    (local.get $0)
+   )
+   (local.get $i64toi32_i32$0)
+  )
+  (block
+   (global.set $f
+    (block (result i32)
+     (local.set $i64toi32_i32$0
+      (i32.const 287454020)
+     )
+     (i32.const 1432778632)
+    )
+   )
+   (global.set $f$hi
+    (local.get $i64toi32_i32$0)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/flatten_i64-to-i32-lowering.wast b/binaryen/test/passes/flatten_i64-to-i32-lowering.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_i64-to-i32-lowering.wast
@@ -0,0 +1,66 @@
+(module
+ (memory 1 1)
+ (import "env" "func" (func $import (result i64)))
+ (func $defined (result i64)
+  (i64.add (i64.const 1) (i64.const 2))
+ )
+ (func $unreachable-select-i64 (result i64)
+  (select
+   (i64.const 1)
+   (unreachable)
+   (i32.const 2)
+  )
+ )
+ (func $unreachable-select-i64-b (result i64)
+  (select
+   (unreachable)
+   (i64.const 3)
+   (i32.const 4)
+  )
+ )
+ (func $unreachable-select-i64-c (result i64)
+  (select
+   (i64.const 5)
+   (i64.const 6)
+   (unreachable)
+  )
+ )
+ (func $mem
+  (drop (i64.load align=8 (i32.const 0)))
+  (drop (i64.load align=4 (i32.const 0)))
+  (drop (i64.load align=2 (i32.const 0)))
+  (drop (i64.load align=1 (i32.const 0)))
+  (drop (i64.load          (i32.const 0)))
+  (i64.store align=8 (i32.const 0) (i64.const 1))
+  (i64.store align=4 (i32.const 0) (i64.const 2))
+  (i64.store align=2 (i32.const 0) (i64.const 3))
+  (i64.store align=1 (i32.const 0) (i64.const 4))
+  (i64.store         (i32.const 0) (i64.const 5))
+ )
+)
+(module
+ (global $f (mut i64) (i64.const 0x12345678ABCDEFAF))
+ (global $g (mut i64) (global.get $f))
+ (func $call (param i64))
+ (func "exp"
+  (call $call (global.get $f))
+  (global.set $f (i64.const 0x1122334455667788))
+ )
+ (func "unreach"
+  (global.set $f
+   (block $label$1 (result i64)
+    (unreachable)
+   )
+  )
+ )
+)
+(module
+ (global $f (mut i64) (i64.const 0x12345678ABCDEFAF))
+ (global $g (mut i64) (global.get $f))
+ (func $call (param i64))
+ (func "exp"
+  (call $call (global.get $f))
+  (global.set $f (i64.const 0x1122334455667788))
+ )
+)
+
diff --git a/binaryen/test/passes/flatten_local-cse_Os.txt b/binaryen/test/passes/flatten_local-cse_Os.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_local-cse_Os.txt
@@ -0,0 +1,27 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (export "div16_internal" (func $0))
+ (func $0 (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (local.tee $0
+    (i32.xor
+     (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)
+     )
+    )
+   )
+   (local.get $0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/flatten_local-cse_Os.wast b/binaryen/test/passes/flatten_local-cse_Os.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_local-cse_Os.wast
@@ -0,0 +1,39 @@
+(module
+ ;; testcase from AssemblyScript
+ (func "div16_internal" (param $0 i32) (param $1 i32) (result i32)
+  (i32.add
+   (i32.xor
+    (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)
+    )
+   )
+   (i32.xor
+    (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)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/flatten_local-cse_all-features.txt b/binaryen/test/passes/flatten_local-cse_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_local-cse_all-features.txt
@@ -0,0 +1,815 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $f64_f64_i32_=>_f32 (func (param f64 f64 i32) (result f32)))
+ (memory $0 100 100)
+ (func $basics
+  (local $x i32)
+  (local $y i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (local $19 i32)
+  (local.set $2
+   (i32.add
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (local.get $2)
+  )
+  (local.set $3
+   (local.get $2)
+  )
+  (drop
+   (local.get $2)
+  )
+  (if
+   (i32.const 0)
+   (nop)
+  )
+  (local.set $4
+   (i32.add
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (local.get $4)
+  )
+  (local.set $5
+   (local.get $x)
+  )
+  (local.set $6
+   (local.get $y)
+  )
+  (local.set $7
+   (i32.add
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (local.get $7)
+  )
+  (local.set $8
+   (local.get $x)
+  )
+  (local.set $9
+   (local.get $y)
+  )
+  (local.set $10
+   (local.get $7)
+  )
+  (drop
+   (local.get $7)
+  )
+  (local.set $11
+   (local.get $x)
+  )
+  (local.set $12
+   (local.get $y)
+  )
+  (local.set $13
+   (local.get $7)
+  )
+  (drop
+   (local.get $7)
+  )
+  (call $basics)
+  (local.set $14
+   (local.get $x)
+  )
+  (local.set $15
+   (local.get $y)
+  )
+  (local.set $16
+   (local.get $7)
+  )
+  (drop
+   (local.get $7)
+  )
+  (local.set $x
+   (i32.const 100)
+  )
+  (local.set $17
+   (local.get $x)
+  )
+  (local.set $18
+   (local.get $y)
+  )
+  (local.set $19
+   (i32.add
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (local.get $19)
+  )
+ )
+ (func $recursive1
+  (local $x i32)
+  (local $y i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local.set $2
+   (i32.add
+    (i32.const 2)
+    (i32.const 3)
+   )
+  )
+  (local.set $3
+   (i32.add
+    (i32.const 1)
+    (local.get $2)
+   )
+  )
+  (drop
+   (local.get $3)
+  )
+  (local.set $4
+   (local.get $2)
+  )
+  (local.set $5
+   (local.get $3)
+  )
+  (drop
+   (local.get $3)
+  )
+  (local.set $6
+   (local.get $2)
+  )
+  (drop
+   (local.get $2)
+  )
+ )
+ (func $recursive2
+  (local $x i32)
+  (local $y i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local.set $2
+   (i32.add
+    (i32.const 2)
+    (i32.const 3)
+   )
+  )
+  (local.set $3
+   (i32.add
+    (i32.const 1)
+    (local.get $2)
+   )
+  )
+  (drop
+   (local.get $3)
+  )
+  (local.set $4
+   (local.get $2)
+  )
+  (drop
+   (local.get $2)
+  )
+  (local.set $5
+   (local.get $2)
+  )
+  (local.set $6
+   (local.get $3)
+  )
+  (drop
+   (local.get $3)
+  )
+ )
+ (func $self
+  (local $x i32)
+  (local $y i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $2
+   (i32.add
+    (i32.const 2)
+    (i32.const 3)
+   )
+  )
+  (local.set $3
+   (local.get $2)
+  )
+  (local.set $4
+   (i32.add
+    (local.get $2)
+    (local.get $2)
+   )
+  )
+  (drop
+   (local.get $4)
+  )
+  (local.set $5
+   (local.get $2)
+  )
+  (drop
+   (local.get $2)
+  )
+ )
+ (func $loads
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $0
+   (i32.load
+    (i32.const 10)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+  (local.set $1
+   (i32.load
+    (i32.const 10)
+   )
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $8 (param $var$0 i32) (result i32)
+  (local $var$1 i32)
+  (local $var$2 i32)
+  (local $var$3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (local $19 i32)
+  (local $20 i32)
+  (local $21 i32)
+  (block $label$0
+   (local.set $4
+    (local.get $var$1)
+   )
+   (local.set $5
+    (i32.add
+     (local.get $var$1)
+     (i32.const 4)
+    )
+   )
+   (local.set $var$2
+    (local.get $5)
+   )
+   (local.set $6
+    (local.get $var$2)
+   )
+   (local.set $7
+    (local.get $var$2)
+   )
+   (local.set $8
+    (i32.load
+     (local.get $var$2)
+    )
+   )
+   (local.set $var$2
+    (i32.const 74)
+   )
+   (local.set $9
+    (local.get $var$2)
+   )
+   (local.set $10
+    (i32.xor
+     (local.get $var$2)
+     (i32.const -1)
+    )
+   )
+   (local.set $11
+    (i32.and
+     (local.get $8)
+     (local.get $10)
+    )
+   )
+   (i32.store
+    (local.get $5)
+    (local.get $11)
+   )
+   (local.set $12
+    (local.get $var$1)
+   )
+   (local.set $13
+    (local.get $5)
+   )
+   (local.set $var$1
+    (local.get $5)
+   )
+   (local.set $14
+    (local.get $var$1)
+   )
+   (local.set $15
+    (local.get $var$1)
+   )
+   (local.set $16
+    (i32.load
+     (local.get $var$1)
+    )
+   )
+   (local.set $17
+    (local.get $var$2)
+   )
+   (local.set $18
+    (i32.and
+     (local.get $var$2)
+     (i32.const 8)
+    )
+   )
+   (local.set $19
+    (i32.or
+     (local.get $16)
+     (local.get $18)
+    )
+   )
+   (i32.store
+    (local.get $var$1)
+    (local.get $19)
+   )
+   (local.set $20
+    (i32.const 0)
+   )
+  )
+  (local.set $21
+   (local.get $20)
+  )
+  (return
+   (local.get $20)
+  )
+ )
+ (func $loop1 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (block
+   (local.set $2
+    (local.get $y)
+   )
+   (local.set $x
+    (local.get $y)
+   )
+   (local.set $3
+    (local.get $x)
+   )
+   (local.set $y
+    (local.get $x)
+   )
+   (local.set $4
+    (local.get $x)
+   )
+   (local.set $x
+    (local.get $x)
+   )
+   (local.set $5
+    (local.get $x)
+   )
+   (local.set $y
+    (local.get $x)
+   )
+   (local.set $6
+    (local.get $x)
+   )
+   (return
+    (local.get $x)
+   )
+   (unreachable)
+  )
+  (local.set $8
+   (local.get $7)
+  )
+  (return
+   (local.get $7)
+  )
+ )
+ (func $loop2 (param $x i32) (param $y i32) (param $z i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (block
+   (local.set $3
+    (local.get $y)
+   )
+   (local.set $x
+    (local.get $y)
+   )
+   (local.set $4
+    (local.get $z)
+   )
+   (local.set $y
+    (local.get $z)
+   )
+   (local.set $5
+    (local.get $x)
+   )
+   (local.set $z
+    (local.get $x)
+   )
+   (local.set $6
+    (local.get $y)
+   )
+   (local.set $x
+    (local.get $y)
+   )
+   (local.set $7
+    (local.get $z)
+   )
+   (local.set $y
+    (local.get $z)
+   )
+   (local.set $8
+    (local.get $x)
+   )
+   (local.set $z
+    (local.get $x)
+   )
+   (local.set $9
+    (local.get $x)
+   )
+   (return
+    (local.get $x)
+   )
+   (unreachable)
+  )
+  (local.set $11
+   (local.get $10)
+  )
+  (return
+   (local.get $10)
+  )
+ )
+ (func $loop3 (param $x i32) (param $y i32) (param $z i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block
+   (local.set $3
+    (local.get $y)
+   )
+   (local.set $x
+    (local.get $y)
+   )
+   (local.set $4
+    (local.get $z)
+   )
+   (local.set $y
+    (local.get $z)
+   )
+   (local.set $5
+    (local.get $y)
+   )
+   (local.set $z
+    (local.get $y)
+   )
+   (local.set $6
+    (local.get $y)
+   )
+   (local.set $y
+    (local.get $y)
+   )
+   (local.set $7
+    (local.get $y)
+   )
+   (local.set $z
+    (local.get $y)
+   )
+   (local.set $8
+    (local.get $y)
+   )
+   (return
+    (local.get $y)
+   )
+   (unreachable)
+  )
+  (local.set $10
+   (local.get $9)
+  )
+  (return
+   (local.get $9)
+  )
+ )
+ (func $handle-removing (param $var$0 f64) (param $var$1 f64) (param $var$2 i32) (result f32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 f32)
+  (local $7 f32)
+  (block
+   (local.set $var$2
+    (i32.const 32767)
+   )
+   (local.set $3
+    (local.get $var$2)
+   )
+   (local.set $var$2
+    (i32.const 1024)
+   )
+   (local.set $4
+    (local.get $var$2)
+   )
+   (local.set $5
+    (select
+     (local.get $3)
+     (local.get $var$2)
+     (i32.const -2147483648)
+    )
+   )
+   (local.set $var$2
+    (local.get $5)
+   )
+   (local.set $6
+    (f32.const 1)
+   )
+  )
+  (local.set $7
+   (local.get $6)
+  )
+  (return
+   (local.get $6)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i64_f32_i32_=>_none (func (param i64 f32 i32)))
+ (type $i32_f64_=>_i32 (func (param i32 f64) (result i32)))
+ (table $0 23 23 funcref)
+ (global $global$0 (mut i32) (i32.const 10))
+ (export "func_1_invoker" (func $1))
+ (export "func_6" (func $2))
+ (func $0 (param $var$0 i64) (param $var$1 f32) (param $var$2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block $label$1
+   (local.set $3
+    (i32.const 128)
+   )
+   (br_if $label$1
+    (i32.const 0)
+   )
+   (local.set $4
+    (local.get $3)
+   )
+   (local.set $3
+    (i32.const 0)
+   )
+   (br_if $label$1
+    (local.get $4)
+   )
+   (local.set $5
+    (local.get $3)
+   )
+   (drop
+    (local.get $3)
+   )
+   (local.set $3
+    (i32.const -14051)
+   )
+  )
+  (local.set $6
+   (local.get $3)
+  )
+  (if
+   (local.get $3)
+   (global.set $global$0
+    (i32.const 0)
+   )
+  )
+ )
+ (func $1
+  (call $0
+   (i64.const 1125899906842624)
+   (f32.const -nan:0x7fc91a)
+   (i32.const -46)
+  )
+ )
+ (func $2 (param $var$0 i32) (param $var$1 f64) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (block
+   (block
+    (local.set $2
+     (global.get $global$0)
+    )
+    (if
+     (local.get $2)
+     (block
+      (unreachable)
+      (unreachable)
+     )
+    )
+   )
+   (local.set $3
+    (i32.const 0)
+   )
+  )
+  (local.set $4
+   (local.get $3)
+  )
+  (return
+   (local.get $3)
+  )
+ )
+)
+(module
+ (type $i32_=>_none (func (param i32)))
+ (import "env" "out" (func $out (param i32)))
+ (func $each-pass-must-clear (param $var$0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local.set $1
+   (local.get $var$0)
+  )
+  (local.set $2
+   (i32.eqz
+    (local.get $var$0)
+   )
+  )
+  (call $out
+   (local.get $2)
+  )
+  (local.set $3
+   (local.get $var$0)
+  )
+  (local.set $4
+   (local.get $2)
+  )
+  (call $out
+   (local.get $2)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i64 (func (result i64)))
+ (global $glob (mut i32) (i32.const 1))
+ (func $i64-shifts (result i64)
+  (local $temp i64)
+  (local $1 i64)
+  (local $2 i64)
+  (local $3 i64)
+  (local $4 i64)
+  (local $5 i64)
+  (block
+   (local.set $1
+    (i64.add
+     (i64.const 1)
+     (i64.const 2)
+    )
+   )
+   (local.set $temp
+    (local.get $1)
+   )
+   (local.set $temp
+    (i64.const 9999)
+   )
+   (local.set $2
+    (local.get $1)
+   )
+   (local.set $temp
+    (local.get $1)
+   )
+   (local.set $3
+    (local.get $temp)
+   )
+   (local.set $4
+    (local.get $temp)
+   )
+  )
+  (local.set $5
+   (local.get $temp)
+  )
+  (return
+   (local.get $temp)
+  )
+ )
+ (func $global
+  (local $x i32)
+  (local $y i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local.set $2
+   (global.get $glob)
+  )
+  (local.set $x
+   (local.get $2)
+  )
+  (local.set $3
+   (local.get $x)
+  )
+  (local.set $y
+   (local.get $x)
+  )
+  (local.set $4
+   (local.get $x)
+  )
+  (local.set $y
+   (local.get $x)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_anyref (func (result anyref)))
+ (func $subtype-test (result anyref)
+  (local $0 funcref)
+  (local $1 funcref)
+  (local $2 anyref)
+  (local $3 anyref)
+  (block
+   (nop)
+   (loop $label$1
+    (local.set $0
+     (ref.null func)
+    )
+   )
+   (local.set $1
+    (local.get $0)
+   )
+   (local.set $2
+    (local.get $0)
+   )
+  )
+  (local.set $3
+   (local.get $2)
+  )
+  (return
+   (local.get $2)
+  )
+ )
+ (func $test
+  (local $0 anyref)
+  (local $1 funcref)
+  (local $2 funcref)
+  (block $label$1
+   (local.set $0
+    (ref.null func)
+   )
+   (local.set $1
+    (ref.null func)
+   )
+  )
+  (local.set $2
+   (local.get $1)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+)
diff --git a/binaryen/test/passes/flatten_local-cse_all-features.wast b/binaryen/test/passes/flatten_local-cse_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_local-cse_all-features.wast
@@ -0,0 +1,316 @@
+(module
+  (memory 100 100)
+  (func $basics
+    (local $x i32)
+    (local $y i32)
+    (drop
+      (i32.add (i32.const 1) (i32.const 2))
+    )
+    (drop
+      (i32.add (i32.const 1) (i32.const 2))
+    )
+    (if (i32.const 0) (nop))
+    (drop ;; we can't do this yet, non-linear
+      (i32.add (i32.const 1) (i32.const 2))
+    )
+    (drop
+      (i32.add (local.get $x) (local.get $y))
+    )
+    (drop
+      (i32.add (local.get $x) (local.get $y))
+    )
+    (drop
+      (i32.add (local.get $x) (local.get $y))
+    )
+    (call $basics) ;; side effects, but no matter for our locals
+    (drop
+      (i32.add (local.get $x) (local.get $y))
+    )
+    (local.set $x (i32.const 100))
+    (drop ;; x was changed!
+      (i32.add (local.get $x) (local.get $y))
+    )
+  )
+  (func $recursive1
+    (local $x i32)
+    (local $y i32)
+    (drop
+      (i32.add
+        (i32.const 1)
+        (i32.add
+          (i32.const 2)
+          (i32.const 3)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.const 1)
+        (i32.add
+          (i32.const 2)
+          (i32.const 3)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.const 2)
+        (i32.const 3)
+      )
+    )
+  )
+  (func $recursive2
+    (local $x i32)
+    (local $y i32)
+    (drop
+      (i32.add
+        (i32.const 1)
+        (i32.add
+          (i32.const 2)
+          (i32.const 3)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.const 2)
+        (i32.const 3)
+      )
+    )
+    (drop
+      (i32.add
+        (i32.const 1)
+        (i32.add
+          (i32.const 2)
+          (i32.const 3)
+        )
+      )
+    )
+  )
+  (func $self
+    (local $x i32)
+    (local $y i32)
+    (drop
+      (i32.add
+        (i32.add
+          (i32.const 2)
+          (i32.const 3)
+        )
+        (i32.add
+          (i32.const 2)
+          (i32.const 3)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.const 2)
+        (i32.const 3)
+      )
+    )
+  )
+  (func $loads
+    (drop
+      (i32.load (i32.const 10))
+    )
+    (drop
+      (i32.load (i32.const 10)) ;; implicit traps, sad
+    )
+  )
+  (func $8 (param $var$0 i32) (result i32)
+    (local $var$1 i32)
+    (local $var$2 i32)
+    (local $var$3 i32)
+    (block $label$0 (result i32)
+      (i32.store
+        (local.tee $var$2
+          (i32.add
+            (local.get $var$1)
+            (i32.const 4)
+          )
+        )
+        (i32.and
+          (i32.load
+            (local.get $var$2)
+          )
+          (i32.xor
+            (local.tee $var$2
+              (i32.const 74)
+            )
+            (i32.const -1)
+          )
+        )
+      )
+      (i32.store
+        (local.tee $var$1
+          (i32.add
+            (local.get $var$1)
+            (i32.const 4)
+          )
+        )
+        (i32.or
+          (i32.load
+            (local.get $var$1)
+          )
+          (i32.and
+            (local.get $var$2)
+            (i32.const 8)
+          )
+        )
+      )
+      (i32.const 0)
+    )
+  )
+  (func $loop1 (param $x i32) (param $y i32) (result i32)
+    (local.set $x (local.get $y))
+    (local.set $y (local.get $x))
+    (local.set $x (local.get $y))
+    (local.set $y (local.get $x))
+    (return (local.get $y))
+  )
+  (func $loop2 (param $x i32) (param $y i32) (param $z i32) (result i32)
+    (local.set $x (local.get $y))
+    (local.set $y (local.get $z))
+    (local.set $z (local.get $x))
+    (local.set $x (local.get $y))
+    (local.set $y (local.get $z))
+    (local.set $z (local.get $x))
+    (return (local.get $x))
+  )
+  (func $loop3 (param $x i32) (param $y i32) (param $z i32) (result i32)
+    (local.set $x (local.get $y))
+    (local.set $y (local.get $z))
+    (local.set $z (local.get $y))
+    (local.set $y (local.get $z))
+    (local.set $z (local.get $y))
+    (return (local.get $y))
+  )
+  (func $handle-removing (param $var$0 f64) (param $var$1 f64) (param $var$2 i32) (result f32)
+   (local.set $var$2
+    (select
+     (local.tee $var$2
+      (i32.const 32767)
+     )
+     (local.tee $var$2
+      (i32.const 1024)
+     )
+     (i32.const -2147483648)
+    )
+   )
+   (f32.const 1)
+  )
+)
+;; a testcase that fails if we don't handle equivalent local canonicalization properly
+(module
+ (type $0 (func))
+ (type $1 (func (param i32 f64) (result i32)))
+ (type $2 (func (param i64 f32 i32)))
+ (global $global$0 (mut i32) (i32.const 10))
+ (table 23 23 funcref)
+ (export "func_1_invoker" (func $1))
+ (export "func_6" (func $2))
+ (func $0 (; 0 ;) (type $2) (param $var$0 i64) (param $var$1 f32) (param $var$2 i32)
+  (if
+   (block $label$1 (result i32)
+    (drop
+     (br_if $label$1
+      (i32.const 0)
+      (br_if $label$1
+       (i32.const 128)
+       (i32.const 0)
+      )
+     )
+    )
+    (i32.const -14051)
+   )
+   (global.set $global$0
+    (i32.const 0)
+   )
+  )
+ )
+ (func $1 (; 1 ;) (type $0)
+  (call $0
+   (i64.const 1125899906842624)
+   (f32.const -nan:0x7fc91a)
+   (i32.const -46)
+  )
+ )
+ (func $2 (; 2 ;) (type $1) (param $var$0 i32) (param $var$1 f64) (result i32)
+  (if
+   (global.get $global$0)
+   (unreachable)
+  )
+  (i32.const 0)
+ )
+)
+(module
+ (import "env" "out" (func $out (param i32)))
+ (func $each-pass-must-clear (param $var$0 i32)
+  (call $out
+   (i32.eqz
+    (local.get $var$0)
+   )
+  )
+  (call $out
+   (i32.eqz
+    (local.get $var$0)
+   )
+  )
+ )
+)
+(module
+ (global $glob (mut i32) (i32.const 1))
+ (func $i64-shifts (result i64)
+  (local $temp i64)
+  (local.set $temp
+   (i64.add
+    (i64.const 1)
+    (i64.const 2)
+   )
+  )
+  (local.set $temp
+   (i64.const 9999)
+  )
+  (local.set $temp
+   (i64.add
+    (i64.const 1)
+    (i64.const 2)
+   )
+  )
+  (local.get $temp)
+ )
+ (func $global
+  (local $x i32)
+  (local $y i32)
+  (local.set $x (global.get $glob))
+  (local.set $y (global.get $glob))
+  (local.set $y (global.get $glob))
+ )
+)
+
+(module
+ ;; After --flatten, there will be a series of chain copies between multiple
+ ;; locals, but some of the locals will be funcref type and others anyref
+ ;; type. We cannot make locals of different types a common subexpression.
+ (func $subtype-test (result anyref)
+  (nop)
+  (loop $label$1 (result funcref)
+   (ref.null func)
+  )
+ )
+
+ (func $test
+  (local $0 anyref)
+  (drop
+   (block $label$1 (result funcref)
+    (local.set $0
+     (ref.null func)
+    )
+    ;; After --flatten, this will be assigned to a local of funcref type. After
+    ;; --local-cse, even if we set (ref.null func) to local $0 above, this
+    ;; should not be replaced with $0, because it is of type anyref.
+    (ref.null func)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/flatten_rereloop.txt b/binaryen/test/passes/flatten_rereloop.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_rereloop.txt
@@ -0,0 +1,1182 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_f32 (func (result f32)))
+ (type $i32_=>_f32 (func (param i32) (result f32)))
+ (type $none_=>_f64 (func (result f64)))
+ (memory $0 1)
+ (global $global (mut i32) (i32.const 0))
+ (func $0 (result f64)
+  (local $0 f64)
+  (local $1 f64)
+  (local $2 i32)
+  (block
+  )
+  (if
+   (i32.const 0)
+   (block
+    (unreachable)
+   )
+   (block
+    (block
+     (local.set $0
+      (f64.const -nan:0xfffffd63e4e5a)
+     )
+     (local.set $1
+      (local.get $0)
+     )
+     (return
+      (local.get $1)
+     )
+    )
+   )
+  )
+ )
+ (func $1 (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block
+   (block $block$6$break
+    (block
+    )
+    (block $switch$1$leave
+     (block $switch$1$default
+      (block $switch$1$case$4
+       (br_table $switch$1$case$4 $switch$1$case$4 $switch$1$default
+        (i32.const 0)
+       )
+      )
+      (block
+       (block
+        (unreachable)
+       )
+      )
+     )
+     (block
+      (br $block$6$break)
+     )
+    )
+   )
+   (block
+    (block
+    )
+    (block $switch$6$leave
+     (block $switch$6$default
+      (block $switch$6$case$3
+       (br_table $switch$6$case$3 $switch$6$default
+        (i32.const 1)
+       )
+      )
+      (block
+       (block
+        (unreachable)
+       )
+      )
+     )
+     (block
+      (block
+       (block
+        (local.set $0
+         (i32.const 2)
+        )
+        (local.set $1
+         (local.get $0)
+        )
+        (return
+         (local.get $1)
+        )
+       )
+      )
+     )
+    )
+   )
+  )
+  (unreachable)
+ )
+ (func $skip-empty
+  (local $0 i32)
+  (block $block$2$break
+   (block
+   )
+   (block
+    (br $block$2$break)
+   )
+  )
+  (block
+   (return)
+  )
+ )
+ (func $skip-empty-2
+  (local $0 i32)
+  (block $block$5$break
+   (block
+   )
+   (block
+    (br $block$5$break)
+   )
+  )
+  (block
+   (block $block$4$break
+    (call $skip-empty)
+    (block
+     (br $block$4$break)
+    )
+   )
+   (block
+    (block $block$2$break
+     (call $skip-empty)
+     (block
+      (br $block$2$break)
+     )
+    )
+    (block
+     (return)
+    )
+   )
+  )
+ )
+ (func $skip-empty-3
+  (local $0 i32)
+  (block $block$5$break
+   (block
+   )
+   (block
+    (br $block$5$break)
+   )
+  )
+  (block
+   (block $block$4$break
+    (call $skip-empty)
+    (block
+     (br $block$4$break)
+    )
+   )
+   (block
+    (block $block$2$break
+     (call $skip-empty)
+     (block
+      (br $block$2$break)
+     )
+    )
+    (block
+     (return)
+    )
+   )
+  )
+ )
+ (func $skip-empty-4 (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block $block$2$break
+   (local.set $1
+    (local.get $x)
+   )
+   (block
+    (br $block$2$break)
+   )
+  )
+  (block
+   (return)
+  )
+ )
+ (func $skipping (param $0 i32) (result f32)
+  (local $1 f32)
+  (local $2 f32)
+  (local $3 f32)
+  (local $4 f32)
+  (local $5 i32)
+  (block
+  )
+  (if
+   (i32.const 0)
+   (block
+    (unreachable)
+   )
+   (block
+    (block
+     (local.set $1
+      (f32.const 1)
+     )
+     (local.set $2
+      (local.get $1)
+     )
+     (local.set $3
+      (local.get $2)
+     )
+     (local.set $4
+      (local.get $3)
+     )
+     (return
+      (local.get $4)
+     )
+    )
+   )
+  )
+ )
+ (func $merging
+  (local $0 i32)
+  (block
+   (block
+   )
+   (return)
+  )
+ )
+ (func $unswitch
+  (local $0 i32)
+  (block $block$2$break
+   (block
+   )
+   (block
+    (br $block$2$break)
+   )
+  )
+  (block
+   (return)
+  )
+ )
+ (func $skip-only-empty
+  (local $0 i32)
+  (block $block$3$break
+   (block
+   )
+   (if
+    (i32.const 1)
+    (block
+     (global.set $global
+      (i32.const 0)
+     )
+     (block
+      (br $block$3$break)
+     )
+    )
+    (br $block$3$break)
+   )
+  )
+  (block
+   (return)
+  )
+ )
+ (func $skip-only-one-branch-out (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block
+   (block
+   )
+   (block
+   )
+  )
+  (if
+   (i32.const 1)
+   (block
+    (unreachable)
+   )
+   (block
+    (block
+     (local.set $0
+      (i32.const 0)
+     )
+     (local.set $1
+      (local.get $0)
+     )
+     (return
+      (local.get $1)
+     )
+    )
+   )
+  )
+ )
+ (func $multipass-for-skips (result f32)
+  (local $0 f32)
+  (local $1 f32)
+  (local $2 f32)
+  (local $3 f32)
+  (local $4 i32)
+  (block $block$7$break
+   (block
+   )
+   (if
+    (i32.const 0)
+    (block
+     (block
+      (local.set $0
+       (f32.const 9223372036854775808)
+      )
+      (block
+       (local.set $1
+        (local.get $0)
+       )
+       (local.set $2
+        (local.get $1)
+       )
+      )
+     )
+     (block
+      (br $block$7$break)
+     )
+    )
+    (block
+     (local.set $2
+      (f32.const 65505)
+     )
+     (block
+      (br $block$7$break)
+     )
+    )
+   )
+  )
+  (block
+   (block
+    (local.set $3
+     (local.get $2)
+    )
+    (return
+     (local.get $3)
+    )
+   )
+  )
+ )
+ (func $branch-merge-vs-replace
+  (local $0 i32)
+  (block
+  )
+  (if
+   (i32.const 0)
+   (block
+    (unreachable)
+   )
+   (block
+    (return)
+   )
+  )
+ )
+ (func $unswitch-amount
+  (local $0 i32)
+  (block $block$2$break
+   (block
+   )
+   (if
+    (i32.const -23)
+    (br $block$2$break)
+    (block
+     (block $block$6$break
+      (block
+      )
+      (block $switch$4$leave
+       (block $switch$4$default
+        (block $switch$4$case$2
+         (br_table $switch$4$case$2 $switch$4$default
+          (i32.const 44064)
+         )
+        )
+        (block
+         (br $block$2$break)
+        )
+       )
+       (block
+        (br $block$6$break)
+       )
+      )
+     )
+     (block
+      (unreachable)
+     )
+    )
+   )
+  )
+  (block
+   (return)
+  )
+ )
+)
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_none (func))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (func $trivial
+  (local $0 i32)
+  (return)
+ )
+ (func $trivial2
+  (local $0 i32)
+  (block
+   (block
+    (call $trivial)
+    (call $trivial)
+   )
+   (return)
+  )
+ )
+ (func $return-void
+  (local $0 i32)
+  (return)
+ )
+ (func $return-val (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (return
+   (i32.const 1)
+  )
+ )
+ (func $ifs (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (block
+   (local.set $6
+    (local.get $x)
+   )
+   (local.set $1
+    (local.get $6)
+   )
+   (local.set $7
+    (local.get $1)
+   )
+  )
+  (if
+   (local.get $7)
+   (block
+    (block
+     (local.set $8
+      (local.get $x)
+     )
+     (local.set $2
+      (local.get $8)
+     )
+     (local.set $9
+      (local.get $2)
+     )
+    )
+    (if
+     (local.get $9)
+     (block
+      (return
+       (i32.const 2)
+      )
+     )
+     (block
+      (return
+       (i32.const 3)
+      )
+     )
+    )
+   )
+   (block
+    (block
+     (local.set $10
+      (local.get $x)
+     )
+     (local.set $3
+      (local.get $10)
+     )
+     (local.set $11
+      (local.get $3)
+     )
+    )
+    (if
+     (local.get $11)
+     (block
+      (return
+       (i32.const 4)
+      )
+     )
+     (block
+      (return
+       (i32.const 5)
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $loops (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block $block$21$break
+   (block
+    (local.set $4
+     (local.get $x)
+    )
+    (local.set $1
+     (local.get $4)
+    )
+    (local.set $5
+     (local.get $1)
+    )
+   )
+   (if
+    (local.get $5)
+    (loop $shape$2$continue
+     (call $trivial)
+     (block
+      (br $shape$2$continue)
+     )
+    )
+    (br $block$21$break)
+   )
+  )
+  (block
+   (block $block$24$break
+    (loop $shape$4$continue
+     (block
+      (call $trivial)
+      (local.set $6
+       (local.get $x)
+      )
+      (local.set $2
+       (local.get $6)
+      )
+      (local.set $7
+       (local.get $2)
+      )
+     )
+     (if
+      (local.get $7)
+      (br $shape$4$continue)
+      (br $block$24$break)
+     )
+    )
+   )
+   (block
+    (block $block$2$break
+     (loop $shape$6$continue
+      (block
+       (call $trivial)
+       (local.set $8
+        (local.get $x)
+       )
+       (local.set $3
+        (local.get $8)
+       )
+       (local.set $9
+        (local.get $3)
+       )
+      )
+      (if
+       (local.get $9)
+       (br $shape$6$continue)
+       (br $block$2$break)
+      )
+     )
+    )
+    (block
+     (return)
+    )
+   )
+  )
+ )
+ (func $br-out (param $x i32)
+  (local $1 i32)
+  (block $block$2$break
+   (call $br-out
+    (i32.const 5)
+   )
+   (block
+    (br $block$2$break)
+   )
+  )
+  (block
+   (return)
+  )
+ )
+ (func $unreachable (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (block $block$4$break
+   (block
+    (local.set $3
+     (local.get $x)
+    )
+    (local.set $1
+     (local.get $3)
+    )
+    (local.set $4
+     (local.get $1)
+    )
+   )
+   (if
+    (local.get $4)
+    (br $block$4$break)
+    (block
+     (block $block$2$break
+      (call $unreachable
+       (i32.const 5)
+      )
+      (block
+       (br $block$2$break)
+      )
+     )
+     (block
+      (return)
+     )
+    )
+   )
+  )
+  (block
+   (block
+    (local.set $5
+     (local.get $x)
+    )
+    (local.set $2
+     (local.get $5)
+    )
+    (local.set $6
+     (local.get $2)
+    )
+   )
+   (if
+    (local.get $6)
+    (block
+     (block
+      (call $unreachable
+       (i32.const 1)
+      )
+      (unreachable)
+     )
+    )
+    (block
+     (block
+      (call $unreachable
+       (i32.const 3)
+      )
+      (return)
+     )
+    )
+   )
+  )
+ )
+ (func $empty-blocks (param $x i32)
+  (local $1 i32)
+  (block $block$2$break
+   (block
+   )
+   (block
+    (br $block$2$break)
+   )
+  )
+  (block
+   (return)
+  )
+ )
+ (func $before-and-after (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (block $block$4$break
+   (block
+    (block
+     (call $before-and-after
+      (i32.const 1)
+     )
+     (call $before-and-after
+      (i32.const 2)
+     )
+    )
+    (block
+     (call $before-and-after
+      (i32.const 3)
+     )
+     (call $before-and-after
+      (i32.const 4)
+     )
+     (local.set $6
+      (local.get $x)
+     )
+     (local.set $1
+      (local.get $6)
+     )
+     (local.set $7
+      (local.get $1)
+     )
+    )
+   )
+   (if
+    (local.get $7)
+    (br $block$4$break)
+    (block
+     (call $before-and-after
+      (i32.const 5)
+     )
+     (block
+      (br $block$4$break)
+     )
+    )
+   )
+  )
+  (block
+   (block $block$8$break
+    (block
+     (block
+      (call $before-and-after
+       (i32.const 6)
+      )
+      (call $before-and-after
+       (i32.const 7)
+      )
+     )
+     (call $before-and-after
+      (i32.const 8)
+     )
+    )
+    (block
+     (br $block$8$break)
+    )
+   )
+   (block
+    (block $block$10$break
+     (loop $shape$4$continue
+      (block
+       (call $before-and-after
+        (i32.const 9)
+       )
+       (local.set $8
+        (local.get $x)
+       )
+       (local.set $2
+        (local.get $8)
+       )
+       (local.set $9
+        (local.get $2)
+       )
+      )
+      (if
+       (local.get $9)
+       (br $shape$4$continue)
+       (br $block$10$break)
+      )
+     )
+    )
+    (block
+     (block $block$11$break
+      (block
+       (call $before-and-after
+        (i32.const 10)
+       )
+       (block
+        (call $before-and-after
+         (i32.const 11)
+        )
+        (local.set $10
+         (local.get $x)
+        )
+        (local.set $3
+         (local.get $10)
+        )
+        (local.set $11
+         (local.get $3)
+        )
+       )
+      )
+      (if
+       (local.get $11)
+       (block
+        (call $before-and-after
+         (i32.const 12)
+        )
+        (block
+         (br $block$11$break)
+        )
+       )
+       (br $block$11$break)
+      )
+     )
+     (block
+      (block $block$15$break
+       (block
+        (call $before-and-after
+         (i32.const 13)
+        )
+        (local.set $12
+         (local.get $x)
+        )
+        (local.set $4
+         (local.get $12)
+        )
+        (local.set $13
+         (local.get $4)
+        )
+       )
+       (if
+        (local.get $13)
+        (block
+         (call $before-and-after
+          (i32.const 14)
+         )
+         (block
+          (br $block$15$break)
+         )
+        )
+        (block
+         (call $before-and-after
+          (i32.const 15)
+         )
+         (block
+          (br $block$15$break)
+         )
+        )
+       )
+      )
+      (block
+       (block $block$21$break
+        (block
+         (local.set $14
+          (local.get $x)
+         )
+         (local.set $5
+          (local.get $14)
+         )
+         (local.set $15
+          (local.get $5)
+         )
+        )
+        (if
+         (local.get $15)
+         (block
+          (call $before-and-after
+           (i32.const 16)
+          )
+          (block
+           (br $block$21$break)
+          )
+         )
+         (br $block$21$break)
+        )
+       )
+       (block
+        (block $block$28$break
+         (block
+          (block
+           (block
+            (call $before-and-after
+             (i32.const 17)
+            )
+            (call $before-and-after
+             (i32.const 18)
+            )
+            (call $before-and-after
+             (i32.const 19)
+            )
+           )
+           (call $before-and-after
+            (i32.const 20)
+           )
+          )
+          (block
+           (call $before-and-after
+            (i32.const 21)
+           )
+           (call $before-and-after
+            (i32.const 22)
+           )
+          )
+         )
+         (block
+          (br $block$28$break)
+         )
+        )
+        (block
+         (block $block$30$break
+          (block
+           (call $before-and-after
+            (i32.const 23)
+           )
+           (call $before-and-after
+            (i32.const 24)
+           )
+          )
+          (block
+           (br $block$30$break)
+          )
+         )
+         (block
+          (block
+           (call $before-and-after
+            (i32.const 25)
+           )
+           (return)
+          )
+         )
+        )
+       )
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $switch (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (block $block$3$break
+   (block
+    (local.set $3
+     (local.get $x)
+    )
+    (local.set $1
+     (local.get $3)
+    )
+    (local.set $4
+     (local.get $1)
+    )
+   )
+   (block
+    (br $block$3$break)
+   )
+  )
+  (block
+   (block $block$9$break
+    (block
+     (call $switch
+      (i32.const 1)
+     )
+     (local.set $5
+      (local.get $x)
+     )
+     (local.set $2
+      (local.get $5)
+     )
+     (local.set $6
+      (local.get $2)
+     )
+    )
+    (block $switch$3$leave
+     (block $switch$3$default
+      (block $switch$3$case$9
+       (br_table $switch$3$case$9 $switch$3$case$9 $switch$3$case$9 $switch$3$default
+        (local.get $6)
+       )
+      )
+      (block
+       (br $block$9$break)
+      )
+     )
+     (block
+      (block
+       (call $switch
+        (i32.const 2)
+       )
+       (block
+        (br $block$9$break)
+       )
+      )
+     )
+    )
+   )
+   (block
+    (block
+     (call $switch
+      (i32.const 3)
+     )
+     (return)
+    )
+   )
+  )
+ )
+ (func $no-return
+  (local $0 i32)
+  (block $block$6$break
+   (block
+   )
+   (if
+    (i32.const 1)
+    (block
+     (drop
+      (i32.const 2)
+     )
+     (block
+      (br $block$6$break)
+     )
+    )
+    (block
+     (drop
+      (i32.const 3)
+     )
+     (block
+      (br $block$6$break)
+     )
+    )
+   )
+  )
+  (block
+   (return)
+  )
+ )
+ (func $if-br-wat (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (block $block$3$break
+   (block $block$4$break
+    (block
+     (call $if-br-wat
+      (i32.const 0)
+     )
+     (local.set $3
+      (local.get $x)
+     )
+     (local.set $1
+      (local.get $3)
+     )
+     (local.set $4
+      (local.get $1)
+     )
+    )
+    (if
+     (local.get $4)
+     (block
+      (call $if-br-wat
+       (i32.const 1)
+      )
+      (block
+       (br $block$4$break)
+      )
+     )
+     (block
+      (block
+       (local.set $5
+        (local.get $x)
+       )
+       (local.set $2
+        (local.get $5)
+       )
+       (local.set $6
+        (local.get $2)
+       )
+      )
+      (if
+       (local.get $6)
+       (br $block$3$break)
+       (br $block$4$break)
+      )
+     )
+    )
+   )
+   (block
+    (call $if-br-wat
+     (i32.const 2)
+    )
+    (block
+     (br $block$3$break)
+    )
+   )
+  )
+  (block
+   (block
+    (call $if-br-wat
+     (i32.const 3)
+    )
+    (return)
+   )
+  )
+ )
+ (func $switcher-to-nowhere (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block
+   (block
+    (local.set $4
+     (local.get $0)
+    )
+    (local.set $1
+     (local.get $4)
+    )
+    (local.set $5
+     (local.get $1)
+    )
+   )
+   (block $switch$1$leave
+    (block $switch$1$default
+     (block $switch$1$case$4
+      (block $switch$1$case$5
+       (br_table $switch$1$case$5 $switch$1$case$4 $switch$1$default
+        (local.get $5)
+       )
+      )
+      (block
+       (block
+        (return
+         (i32.const 1)
+        )
+       )
+      )
+     )
+     (block
+      (block
+       (return
+        (i32.const 2)
+       )
+      )
+     )
+    )
+    (block
+     (block
+      (return
+       (i32.const 3)
+      )
+     )
+    )
+   )
+  )
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/passes/flatten_rereloop.wast b/binaryen/test/passes/flatten_rereloop.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_rereloop.wast
@@ -0,0 +1,783 @@
+(module
+ (memory 1)
+ (global $global (mut i32) (i32.const 0))
+ (func $0 (result f64)
+  (if
+   (i32.const 0)
+   (loop $label$2
+    (unreachable)
+   )
+  )
+  (f64.const -nan:0xfffffd63e4e5a)
+ )
+ (func $1 (result i32)
+  (block $label$8
+   (block $label$9
+    (block $label$16
+     (block $label$18
+      (block $label$19
+       (br_table $label$18 $label$16 $label$19
+        (i32.const 0)
+       )
+      )
+      (br_table $label$9 $label$8
+       (i32.const 1)
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (i32.const 2)
+ )
+ (func $skip-empty
+  (block $a1
+   (block $a2
+    (block $a3
+     (block $a4
+      (br $a4)
+     )
+     (br $a3)
+    )
+    (br $a2)
+   )
+   (br $a1)
+  )
+ )
+ (func $skip-empty-2
+  (block $a1
+   (block $a2
+    (block $a3
+     (block $a4
+      (br $a4)
+     )
+     (call $skip-empty)
+     (br $a3)
+    )
+    (call $skip-empty)
+    (br $a2)
+   )
+   (br $a1)
+  )
+ )
+ (func $skip-empty-3
+  (block $a1
+   (block $a2
+    (block $a3
+     (block $a4
+      (nop)
+      (br $a4)
+      (nop)
+     )
+     (nop)
+     (call $skip-empty)
+     (nop)
+     (br $a3)
+    )
+    (nop)
+    (call $skip-empty)
+    (nop)
+    (br $a2)
+   )
+   (br $a1)
+  )
+ )
+ (func $skip-empty-4 (param $x i32)
+  (block $a1
+   (block $a2
+    (block $a3
+     (block $a4
+      (br_table $a1 $a2 $a3 $a4 $a1 $a2 $a3 $a4 (local.get $x))
+     )
+     (br $a3)
+    )
+    (br $a2)
+   )
+   (br $a1)
+  )
+ )
+ (func $skipping (param $0 i32) (result f32)
+  (if
+   (i32.const 0)
+   (unreachable)
+  ) ;; branches joining here lead to skip opportunities
+  (loop $label$2 (result f32)
+   (f32.const 1)
+  )
+ )
+ (func $merging
+  (if
+   (i32.const 0)
+   (return)
+   ;; no else, but the else ends up with a return too, and we can merge them
+  )
+ )
+ (func $unswitch
+  (block $label$1
+   (br_table $label$1 $label$1
+    (i32.const 0)
+   )
+  )
+ )
+ (func $skip-only-empty
+  (if
+   (i32.const 1)
+   (global.set $global
+    (i32.const 0)
+   )
+  )
+ )
+ (func $skip-only-one-branch-out (result i32)
+  (block $label$1
+   (nop)
+  )
+  (if
+   (i32.const 1)
+   (unreachable) ;; blocks a path through
+  )
+  (i32.const 0)
+ )
+ (func $multipass-for-skips (result f32)
+  (if (result f32)
+   (i32.const 0)
+   (block (result f32)
+    (block $label$2
+     (br_if $label$2
+      (i32.const 536870912)
+     )
+    )
+    (f32.const 9223372036854775808)
+   )
+   (f32.const 65505)
+  )
+ )
+ (func $branch-merge-vs-replace
+  (if
+   (i32.const 0)
+   (unreachable)
+  )
+ )
+ (func $unswitch-amount
+  (block $label$1
+   (if
+    (i32.const -23)
+    (nop)
+    (block
+     (block $label$4
+      (br_table $label$1 $label$4
+       (i32.const 44064)
+      )
+     )
+     (unreachable)
+    )
+   )
+  )
+ )
+)
+;; manual TODO: merge branches, all the parts
+(module
+ (type $0 (func))
+ (type $1 (func (result i32)))
+ (type $2 (func (param i32) (result i32)))
+ (type $3 (func (param i32)))
+ (func $trivial (; 0 ;) (type $0)
+  (nop)
+ )
+ (func $trivial2 (; 1 ;) (type $0)
+  (block
+   (call $trivial)
+   (nop)
+   (call $trivial)
+   (nop)
+  )
+  (nop)
+ )
+ (func $return-void (; 2 ;) (type $0)
+  (return)
+  (unreachable)
+ )
+ (func $return-val (; 3 ;) (type $1) (result i32)
+  (return
+   (i32.const 1)
+  )
+  (unreachable)
+ )
+ (func $ifs (; 4 ;) (type $2) (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (block
+   (block
+    (local.set $1
+     (local.get $x)
+    )
+    (if
+     (local.get $1)
+     (block
+      (block
+       (local.set $2
+        (local.get $x)
+       )
+       (if
+        (local.get $2)
+        (block
+         (return
+          (i32.const 2)
+         )
+         (unreachable)
+        )
+        (block
+         (return
+          (i32.const 3)
+         )
+         (unreachable)
+        )
+       )
+      )
+      (unreachable)
+     )
+    )
+   )
+   (nop)
+   (block
+    (local.set $3
+     (local.get $x)
+    )
+    (if
+     (local.get $3)
+     (block
+      (return
+       (i32.const 4)
+      )
+      (unreachable)
+     )
+    )
+   )
+   (nop)
+   (return
+    (i32.const 5)
+   )
+   (unreachable)
+  )
+  (local.set $5
+   (local.get $4)
+  )
+  (return
+   (local.get $5)
+  )
+ )
+ (func $loops (; 5 ;) (type $3) (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (block
+   (block
+    (local.set $1
+     (local.get $x)
+    )
+    (if
+     (local.get $1)
+     (block
+      (loop $top
+       (block
+        (call $trivial)
+        (nop)
+        (br $top)
+        (unreachable)
+       )
+       (unreachable)
+      )
+      (unreachable)
+     )
+    )
+   )
+   (nop)
+   (loop $top2
+    (block
+     (call $trivial)
+     (nop)
+     (local.set $2
+      (local.get $x)
+     )
+     (br_if $top2
+      (local.get $2)
+     )
+     (nop)
+    )
+    (nop)
+   )
+   (nop)
+   (loop $top3
+    (block
+     (call $trivial)
+     (nop)
+     (block
+      (local.set $3
+       (local.get $x)
+      )
+      (if
+       (local.get $3)
+       (block
+        (br $top3)
+        (unreachable)
+       )
+      )
+     )
+     (nop)
+    )
+    (nop)
+   )
+   (nop)
+  )
+  (nop)
+ )
+ (func $br-out (; 6 ;) (type $3) (param $x i32)
+  (block $out
+   (call $br-out
+    (i32.const 5)
+   )
+   (nop)
+   (br $out)
+   (unreachable)
+  )
+  (nop)
+ )
+ (func $unreachable (; 7 ;) (type $3) (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block
+   (block
+    (local.set $1
+     (local.get $x)
+    )
+    (if
+     (local.get $1)
+     (block
+      (block
+       (local.set $2
+        (local.get $x)
+       )
+       (if
+        (local.get $2)
+        (block
+         (block $block
+          (call $unreachable
+           (i32.const 1)
+          )
+          (nop)
+          (unreachable)
+          (unreachable)
+          (call $unreachable
+           (i32.const 2)
+          )
+          (nop)
+         )
+         (unreachable)
+        )
+        (block
+         (block $block4
+          (call $unreachable
+           (i32.const 3)
+          )
+          (nop)
+          (return)
+          (unreachable)
+          (call $unreachable
+           (i32.const 4)
+          )
+          (nop)
+         )
+         (unreachable)
+        )
+       )
+      )
+      (unreachable)
+     )
+    )
+   )
+   (nop)
+   (block $out
+    (call $unreachable
+     (i32.const 5)
+    )
+    (nop)
+    (br $out)
+    (unreachable)
+    (call $unreachable
+     (i32.const 6)
+    )
+    (nop)
+   )
+   (nop)
+  )
+  (nop)
+ )
+ (func $empty-blocks (; 8 ;) (type $3) (param $x i32)
+  (block
+   (block $block
+   )
+   (nop)
+   (block $block5
+   )
+   (nop)
+  )
+  (nop)
+ )
+ (func $before-and-after (; 9 ;) (type $3) (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (block
+   (call $before-and-after
+    (i32.const 1)
+   )
+   (nop)
+   (block $block
+    (call $before-and-after
+     (i32.const 2)
+    )
+    (nop)
+   )
+   (nop)
+   (call $before-and-after
+    (i32.const 3)
+   )
+   (nop)
+   (block $out
+    (call $before-and-after
+     (i32.const 4)
+    )
+    (nop)
+    (local.set $1
+     (local.get $x)
+    )
+    (br_if $out
+     (local.get $1)
+    )
+    (nop)
+    (call $before-and-after
+     (i32.const 5)
+    )
+    (nop)
+   )
+   (nop)
+   (call $before-and-after
+    (i32.const 6)
+   )
+   (nop)
+   (loop $loop-in
+    (nop)
+   )
+   (nop)
+   (call $before-and-after
+    (i32.const 7)
+   )
+   (nop)
+   (loop $top
+    (nop)
+   )
+   (nop)
+   (call $before-and-after
+    (i32.const 8)
+   )
+   (nop)
+   (loop $top2
+    (block
+     (call $before-and-after
+      (i32.const 9)
+     )
+     (nop)
+     (local.set $2
+      (local.get $x)
+     )
+     (br_if $top2
+      (local.get $2)
+     )
+     (nop)
+     (call $before-and-after
+      (i32.const 10)
+     )
+     (nop)
+    )
+    (nop)
+   )
+   (nop)
+   (call $before-and-after
+    (i32.const 11)
+   )
+   (nop)
+   (block
+    (local.set $3
+     (local.get $x)
+    )
+    (if
+     (local.get $3)
+     (block
+      (call $before-and-after
+       (i32.const 12)
+      )
+      (nop)
+     )
+    )
+   )
+   (nop)
+   (call $before-and-after
+    (i32.const 13)
+   )
+   (nop)
+   (block
+    (local.set $4
+     (local.get $x)
+    )
+    (if
+     (local.get $4)
+     (block
+      (call $before-and-after
+       (i32.const 14)
+      )
+      (nop)
+     )
+     (block
+      (call $before-and-after
+       (i32.const 15)
+      )
+      (nop)
+     )
+    )
+   )
+   (nop)
+   (block
+    (local.set $5
+     (local.get $x)
+    )
+    (if
+     (local.get $5)
+     (block
+      (block $block8
+       (call $before-and-after
+        (i32.const 16)
+       )
+       (nop)
+      )
+      (nop)
+     )
+    )
+   )
+   (nop)
+   (call $before-and-after
+    (i32.const 17)
+   )
+   (nop)
+   (block $block9
+    (call $before-and-after
+     (i32.const 18)
+    )
+    (nop)
+    (block $block10
+     (call $before-and-after
+      (i32.const 19)
+     )
+     (nop)
+    )
+    (nop)
+    (call $before-and-after
+     (i32.const 20)
+    )
+    (nop)
+   )
+   (nop)
+   (call $before-and-after
+    (i32.const 21)
+   )
+   (nop)
+   (block $block11
+    (block $block12
+     (call $before-and-after
+      (i32.const 22)
+     )
+     (nop)
+    )
+    (nop)
+   )
+   (nop)
+   (call $before-and-after
+    (i32.const 23)
+   )
+   (nop)
+   (block $no1
+    (block $no2
+     (call $before-and-after
+      (i32.const 24)
+     )
+     (nop)
+    )
+    (nop)
+   )
+   (nop)
+   (call $before-and-after
+    (i32.const 25)
+   )
+   (nop)
+  )
+  (nop)
+ )
+ (func $switch (; 10 ;) (type $3) (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block $out
+   (block $a
+    (local.set $1
+     (local.get $x)
+    )
+    (br_table $a $a
+     (local.get $1)
+    )
+    (unreachable)
+   )
+   (nop)
+   (call $switch
+    (i32.const 1)
+   )
+   (nop)
+   (block $b
+    (block $c
+     (local.set $2
+      (local.get $x)
+     )
+     (br_table $b $b $b $c
+      (local.get $2)
+     )
+     (unreachable)
+    )
+    (nop)
+    (call $switch
+     (i32.const 2)
+    )
+    (nop)
+   )
+   (nop)
+   (call $switch
+    (i32.const 3)
+   )
+   (nop)
+  )
+  (nop)
+ )
+ (func $no-return (; 11 ;) (type $0)
+  (if
+   (i32.const 1)
+   (block
+    (drop
+     (i32.const 2)
+    )
+    (nop)
+   )
+   (block
+    (drop
+     (i32.const 3)
+    )
+    (nop)
+   )
+  )
+  (nop)
+ )
+ (func $if-br-wat (; 12 ;) (type $3) (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block
+   (call $if-br-wat
+    (i32.const 0)
+   )
+   (nop)
+   (block $label$2
+    (block
+     (local.set $1
+      (local.get $x)
+     )
+     (if
+      (local.get $1)
+      (block
+       (call $if-br-wat
+        (i32.const 1)
+       )
+       (nop)
+      )
+      (block
+       (block
+        (local.set $2
+         (local.get $x)
+        )
+        (if
+         (local.get $2)
+         (block
+          (br $label$2)
+          (unreachable)
+         )
+        )
+       )
+       (nop)
+      )
+     )
+    )
+    (nop)
+    (call $if-br-wat
+     (i32.const 2)
+    )
+    (nop)
+   )
+   (nop)
+   (call $if-br-wat
+    (i32.const 3)
+   )
+   (nop)
+  )
+  (nop)
+ )
+ (func $switcher-to-nowhere (; 13 ;) (type $2) (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (block
+   (block $switch
+    (block $switch-case0
+     (block $switch-case
+      (local.set $1
+       (local.get $0)
+      )
+      (br_table $switch-case $switch-case0 $switch
+       (local.get $1)
+      )
+      (unreachable)
+     )
+     (nop)
+     (return
+      (i32.const 1)
+     )
+     (unreachable)
+    )
+    (nop)
+    (return
+     (i32.const 2)
+    )
+    (unreachable)
+   )
+   (nop)
+   (return
+    (i32.const 3)
+   )
+   (unreachable)
+  )
+  (local.set $3
+   (local.get $2)
+  )
+  (return
+   (local.get $3)
+  )
+ )
+)
diff --git a/binaryen/test/passes/flatten_simplify-locals-nonesting_dfo_O3.txt b/binaryen/test/passes/flatten_simplify-locals-nonesting_dfo_O3.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_simplify-locals-nonesting_dfo_O3.txt
@@ -0,0 +1,41 @@
+(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 $none_=>_f64 (func (result f64)))
+ (export "if-select" (func $0))
+ (export "unreachable-body-update-zext" (func $1))
+ (export "ssa-const" (func $2))
+ (export "if-nothing" (func $3))
+ (export "only-dfo" (func $4))
+ (func $0 (; has Stack IR ;)
+  (nop)
+ )
+ (func $1 (; has Stack IR ;) (result f64)
+  (unreachable)
+ )
+ (func $2 (; has Stack IR ;) (param $0 i32) (param $1 f64) (param $2 f64) (result i32)
+  (unreachable)
+ )
+ (func $3 (; has Stack IR ;) (param $0 i64)
+  (unreachable)
+ )
+ (func $4 (; has Stack IR ;) (param $0 f64) (result i32)
+  (local $1 i32)
+  (loop $label$1
+   (if
+    (i32.eqz
+     (local.get $1)
+    )
+    (block
+     (local.set $1
+      (i32.const -2147483648)
+     )
+     (br $label$1)
+    )
+   )
+  )
+  (i32.const -2766)
+ )
+)
diff --git a/binaryen/test/passes/flatten_simplify-locals-nonesting_dfo_O3.wast b/binaryen/test/passes/flatten_simplify-locals-nonesting_dfo_O3.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_simplify-locals-nonesting_dfo_O3.wast
@@ -0,0 +1,113 @@
+(module
+ (memory 1)
+ (func "if-select"
+  (local $var$0 i32)
+  (nop)
+  (drop
+   (if (result i32)
+    (select
+     (i32.const 65473)
+     (i32.const 1)
+     (local.get $var$0)
+    )
+    (i32.const -2405046)
+    (i32.const 1)
+   )
+  )
+ )
+ (func "unreachable-body-update-zext" (result f64)
+  (if
+   (i32.eqz
+    (i32.const 0)
+   )
+   (unreachable)
+  )
+  (f64.const -9223372036854775808)
+ )
+ (func "ssa-const" (param $var$0 i32) (param $var$1 f64) (param $var$2 f64) (result i32)
+  (block $label$1 (result i32)
+   (block $label$2
+    (if
+     (i32.const 1)
+     (block
+      (drop
+       (loop $label$5 (result i64)
+        (if (result i64)
+         (i32.const 0)
+         (i64.load offset=22
+          (i32.and
+           (br_if $label$1
+            (i32.const 0)
+            (i32.const 0)
+           )
+           (i32.const 15)
+          )
+          (i64.const 1)
+         )
+         (i64.const 1)
+        )
+       )
+      )
+     )
+    )
+    (unreachable)
+   )
+  )
+ )
+ (func "if-nothing" (param $var$0 i64)
+  (local $var$1 i32)
+  (local $var$2 i32)
+  (block $label$1
+   (loop $label$2
+    (block $label$3
+     (block $label$4
+      (br_if $label$3
+       (i32.eqz
+        (if (result i32)
+         (i32.const 0)
+         (i32.const 0)
+         (local.get $var$2)
+        )
+       )
+      )
+      (unreachable)
+     )
+     (unreachable)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func "only-dfo" (param $var$0 f64) (result i32)
+  (local $var$1 i32)
+  (local $var$2 i32)
+  (local $var$3 i32)
+  (local $var$4 i32)
+  (loop $label$1
+   (local.set $var$3
+    (local.tee $var$1
+     (local.tee $var$2
+      (local.get $var$1)
+     )
+    )
+   )
+   (if
+    (i32.eqz
+     (local.get $var$4)
+    )
+    (block
+     (local.set $var$4
+      (select
+       (local.get $var$3)
+       (i32.const -2147483648)
+       (local.get $var$2)
+      )
+     )
+     (br $label$1)
+    )
+   )
+  )
+  (i32.const -2766)
+ )
+)
+
diff --git a/binaryen/test/passes/flatten_simplify-locals-nonesting_souperify-single-use_enable-threads.txt b/binaryen/test/passes/flatten_simplify-locals-nonesting_souperify-single-use_enable-threads.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_simplify-locals-nonesting_souperify-single-use_enable-threads.txt
@@ -0,0 +1,4775 @@
+
+; function: figure-1a
+
+; start LHS (in figure-1a)
+%0:i64 = var
+%1:i64 = var
+%2 = eq %0, %1
+infer %2
+
+
+; start LHS (in figure-1a)
+%0:i64 = var
+%1:i64 = var
+%2 = ne %0, %1
+infer %2
+
+
+; start LHS (in figure-1a)
+%0:i64 = var
+%1:i64 = var
+%2 = eq %0, %1
+%3:i32 = zext %2
+%4:i64 = var
+%5 = ne %0, %4
+%6:i32 = zext %5
+%7 = and %3, %6
+infer %7
+
+
+; function: figure-1b
+
+; start LHS (in figure-1b)
+%0:i64 = var
+%1:i64 = var
+%2 = slt %0, %1
+infer %2
+
+
+; start LHS (in figure-1b)
+%0:i64 = var
+%1:i64 = var
+%2 = eq %0, %1
+%3:i64 = var
+%4 = slt %1, %3
+pc %4 1:i1
+infer %2
+
+
+; start LHS (in figure-1b)
+%0:i64 = var
+%1:i64 = var
+%2 = ne %0, %1
+%3:i64 = var
+%4 = slt %3, %1
+pc %4 1:i1
+infer %2
+
+
+; start LHS (in figure-1b)
+%0:i64 = var
+%1:i64 = var
+%2 = eq %0, %1
+%3:i32 = zext %2
+%4:i64 = var
+%5 = ne %0, %4
+%6:i32 = zext %5
+%7 = and %3, %6
+%8 = slt %1, %4
+pc %8 1:i1
+infer %7
+
+
+; function: figure-3-if
+
+; start LHS (in figure-3-if)
+%0:i32 = var
+%1 = and %0, 1:i32
+infer %1
+
+
+; start LHS (in figure-3-if)
+%0:i32 = var
+%1 = add %0, 1:i32
+%2 = and %0, 1:i32
+%3 = ne %2, 0:i32
+pc %3 1:i1
+infer %1
+
+
+; start LHS (in figure-3-if)
+%0:i32 = var
+%1 = add %0, 2:i32
+%2 = and %0, 1:i32
+%3 = eq %2, 0:i32
+pc %3 1:i1
+infer %1
+
+
+; start LHS (in figure-3-if)
+%0 = block 2
+%1:i32 = var
+%2 = add %1, 1:i32
+%3 = add %1, 2:i32
+%4 = phi %0, %2, %3
+%5 = and %4, 1:i32
+%6 = and %1, 1:i32
+%7 = ne %6, 0:i32
+blockpc %0 0 %7 1:i1
+%8 = eq %6, 0:i32
+blockpc %0 1 %8 1:i1
+infer %5
+
+
+; function: flips
+
+; start LHS (in flips)
+%0 = sle 0:i32, 0:i32
+infer %0
+
+
+; start LHS (in flips)
+%0 = sle 0:i32, 0:i32
+%1:i32 = zext %0
+%2 = ule 0:i32, %1
+infer %2
+
+
+; start LHS (in flips)
+%0 = sle 0:i32, 0:i32
+%1:i32 = zext %0
+%2 = ule 0:i32, %1
+%3:i32 = zext %2
+%4 = slt 0:i32, %3
+infer %4
+
+
+; start LHS (in flips)
+%0 = sle 0:i32, 0:i32
+%1:i32 = zext %0
+%2 = ule 0:i32, %1
+%3:i32 = zext %2
+%4 = slt 0:i32, %3
+%5:i32 = zext %4
+%6 = ult 0:i32, %5
+infer %6
+
+
+; function: various-conditions-1
+
+; start LHS (in various-conditions-1)
+%0:i32 = var
+%1 = add %0, 1:i32
+%2 = ne %0, 0:i32
+pc %2 1:i1
+infer %1
+
+
+; function: various-conditions-2
+
+; start LHS (in various-conditions-2)
+%0:i32 = var
+%1 = slt %0, 0:i32
+infer %1
+
+
+; start LHS (in various-conditions-2)
+%0:i32 = var
+%1 = sub %0, 2:i32
+%2 = slt %0, 0:i32
+pc %2 1:i1
+infer %1
+
+
+; function: various-conditions-3
+
+; start LHS (in various-conditions-3)
+%0:i32 = var
+%1 = sub %0, 4:i32
+%2:i32 = var
+%3 = ne %2, 0:i32
+pc %3 1:i1
+infer %1
+
+
+; function: various-conditions-4
+
+; function: unaries
+
+; start LHS (in unaries)
+%0:i32 = var
+%1 = eq %0, 0:i32
+infer %1
+
+
+; start LHS (in unaries)
+%0:i32 = var
+%1 = cttz %0
+%2:i32 = var
+%3 = eq %2, 0:i32
+pc %3 1:i1
+infer %1
+
+
+; start LHS (in unaries)
+%0:i32 = var
+%1 = ctlz %0
+%2 = eq %0, 0:i32
+pc %2 1:i1
+infer %1
+
+
+; start LHS (in unaries)
+%0:i32 = var
+%1 = ctpop %0
+%2:i32 = var
+%3 = eq %2, 0:i32
+pc %3 1:i1
+infer %1
+
+
+; start LHS (in unaries)
+%0:i32 = var
+%1 = ctlz %0
+%2:i32 = var
+%3 = ctpop %2
+%4 = sub %1, %3
+%5 = eq %0, 0:i32
+pc %5 1:i1
+infer %4
+
+
+; start LHS (in unaries)
+%0:i32 = var
+%1 = cttz %0
+%2:i32 = var
+%3 = ctlz %2
+%4 = ctpop %0
+%5 = sub %3, %4
+%6 = add %1, %5
+%7 = eq %2, 0:i32
+pc %7 1:i1
+infer %6
+
+
+; function: unary-condition
+
+; start LHS (in unary-condition)
+%0:i32 = var
+%1 = ult 1:i32, %0
+infer %1
+
+
+; start LHS (in unary-condition)
+%0:i32 = var
+%1 = ult 1:i32, %0
+%2:i32 = zext %1
+%3 = cttz %2
+infer %3
+
+
+; start LHS (in unary-condition)
+%0:i32 = var
+%1 = add %0, 2:i32
+%2 = ult 1:i32, %0
+%3:i32 = zext %2
+%4 = cttz %3
+%5 = ne %4, 0:i32
+pc %5 1:i1
+infer %1
+
+
+; function: unary-condition-2
+
+; start LHS (in unary-condition-2)
+%0:i32 = var
+%1 = ult 1:i32, %0
+infer %1
+
+
+; start LHS (in unary-condition-2)
+%0:i32 = var
+%1 = ult 1:i32, %0
+%2:i32 = zext %1
+%3 = eq %2, 0:i32
+infer %3
+
+
+; start LHS (in unary-condition-2)
+%0:i32 = var
+%1 = add %0, 2:i32
+%2 = ult 1:i32, %0
+%3:i32 = zext %2
+%4 = eq %3, 0:i32
+pc %4 1:i1
+infer %1
+
+
+; function: if-else-cond
+
+; start LHS (in if-else-cond)
+%0:i32 = var
+%1 = slt %0, 1:i32
+infer %1
+
+
+; start LHS (in if-else-cond)
+%0:i32 = var
+%1 = add %0, 1:i32
+%2 = slt %0, 1:i32
+pc %2 1:i1
+infer %1
+
+
+; start LHS (in if-else-cond)
+%0:i32 = var
+%1 = add %0, 2:i32
+%2 = slt %0, 1:i32
+%3:i32 = zext %2
+%4 = eq %3, 0:i32
+pc %4 1:i1
+infer %1
+
+
+; start LHS (in if-else-cond)
+%0 = block 2
+%1:i32 = var
+%2 = add %1, 1:i32
+%3 = add %1, 2:i32
+%4 = phi %0, %2, %3
+%5 = and %4, 1:i32
+%6 = slt %1, 1:i32
+blockpc %0 0 %6 1:i1
+%7:i32 = zext %6
+%8 = eq %7, 0:i32
+blockpc %0 1 %8 1:i1
+infer %5
+
+
+; function: trivial-ret
+
+; start LHS (in trivial-ret)
+%0 = add 0:i32, 1:i32
+infer %0
+
+
+; function: trivial-const
+
+; function: trivial-const-block
+
+; function: bad-phi-value
+
+; function: bad-phi-value-2
+
+; function: select
+
+; start LHS (in select)
+%0 = ne 3:i32, 0:i32
+infer %0
+
+
+; start LHS (in select)
+%0 = ne 3:i32, 0:i32
+%1 = select %0, 1:i32, 2:i32
+infer %1
+
+
+; function: select-2
+
+; start LHS (in select-2)
+%0:i32 = var
+%1:i32 = var
+%2 = add %0, %1
+infer %2
+
+
+; start LHS (in select-2)
+%0:i32 = var
+%1 = add %0, 1:i32
+infer %1
+
+
+; start LHS (in select-2)
+%0:i32 = var
+%1 = add 2:i32, %0
+infer %1
+
+
+; start LHS (in select-2)
+%0:i32 = var
+%1 = add 2:i32, %0
+%2 = ne %1, 0:i32
+infer %2
+
+
+; start LHS (in select-2)
+%0:i32 = var
+%1 = add 2:i32, %0
+%2 = ne %1, 0:i32
+%3:i32 = var
+%4 = add %3, %0
+%5 = add %3, 1:i32
+%6 = select %2, %4, %5
+infer %6
+
+
+; function: block-phi-1
+
+; start LHS (in block-phi-1)
+%0:i32 = var
+%1 = add %0, 1:i32
+infer %1
+
+
+; start LHS (in block-phi-1)
+%0:i32 = var
+%1 = add %0, 2:i32
+infer %1
+
+
+; start LHS (in block-phi-1)
+%0 = block 2
+%1:i32 = var
+%2 = add %1, 2:i32
+%3 = phi %0, %1, %2
+%4 = add %3, 3:i32
+infer %4
+
+
+; function: block-phi-2
+
+; start LHS (in block-phi-2)
+%0 = block 2
+%1 = phi %0, 1:i32, 2:i32
+%2 = add %1, 3:i32
+infer %2
+
+
+; function: zero_init-phi-bad_type
+
+; function: phi-bad-type
+
+; function: phi-one-side-i1
+
+; start LHS (in phi-one-side-i1)
+%0:i32 = var
+%1:i32 = var
+%2 = sle %0, %1
+infer %2
+
+
+; start LHS (in phi-one-side-i1)
+%0:i32 = var
+%1:i32 = var
+%2 = eq %0, %1
+%3 = sle %0, %1
+pc %3 1:i1
+infer %2
+
+
+; start LHS (in phi-one-side-i1)
+%0:i32 = var
+%1:i32 = var
+%2 = add %0, %1
+%3 = sle %0, %1
+%4:i32 = zext %3
+%5 = eq %4, 0:i32
+pc %5 1:i1
+infer %2
+
+
+; function: call
+
+; start LHS (in call)
+%0:i32 = var
+%1:i32 = var
+%2 = add %0, %1
+infer %2
+
+
+; start LHS (in call)
+%0:i32 = var
+%1 = add 10:i32, %0
+infer %1
+
+
+; start LHS (in call)
+%0:i32 = var
+%1:i32 = var
+%2 = add %0, %1
+%3:i32 = var
+%4 = add 10:i32, %3
+%5 = mul %2, %4
+infer %5
+
+
+; function: in-unreachable-1
+
+; function: in-unreachable-2
+
+; function: in-unreachable-3
+
+; function: in-unreachable-4
+
+; function: in-unreachable-br_if
+
+; function: in-unreachable-big
+
+; function: in-unreachable-operations
+
+; function: merge-with-one-less
+
+; function: deep
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+infer %1
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+infer %2
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+infer %3
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+infer %4
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+infer %5
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+infer %6
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+infer %7
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+infer %8
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; function: two-pcs
+
+; start LHS (in two-pcs)
+%0:i64 = var
+%1:i64 = var
+%2 = slt %0, %1
+infer %2
+
+
+; start LHS (in two-pcs)
+%0:i64 = var
+%1 = eq %0, 0:i64
+%2:i64 = var
+%3 = slt %0, %2
+pc %3 1:i1
+infer %1
+
+
+; start LHS (in two-pcs)
+%0:i64 = var
+%1:i64 = var
+%2 = add %0, %1
+%3 = eq %0, 0:i64
+%4 = slt %0, %1
+pc %3 1:i1
+pc %4 1:i1
+infer %2
+
+
+; start LHS (in two-pcs)
+%0:i64 = var
+%1:i64 = var
+%2 = sub %0, %1
+%3 = eq %0, 0:i64
+%4:i32 = zext %3
+%5 = eq %4, 0:i32
+%6 = slt %0, %1
+pc %5 1:i1
+pc %6 1:i1
+infer %2
+
+
+; start LHS (in two-pcs)
+%0:i64 = var
+%1 = eq %0, 0:i64
+%2:i64 = var
+%3 = slt %2, %0
+%4:i32 = zext %3
+%5 = eq %4, 0:i32
+pc %5 1:i1
+infer %1
+
+
+; start LHS (in two-pcs)
+%0:i64 = var
+%1:i64 = var
+%2 = mul %0, %1
+%3 = eq %1, 0:i64
+%4 = slt %0, %1
+%5:i32 = zext %4
+%6 = eq %5, 0:i32
+pc %3 1:i1
+pc %6 1:i1
+infer %2
+
+
+; start LHS (in two-pcs)
+%0:i64 = var
+%1:i64 = var
+%2 = sdiv %0, %1
+%3 = eq %1, 0:i64
+%4:i32 = zext %3
+%5 = eq %4, 0:i32
+%6 = slt %0, %1
+%7:i32 = zext %6
+%8 = eq %7, 0:i32
+pc %5 1:i1
+pc %8 1:i1
+infer %2
+
+
+; function: loop-1
+
+; start LHS (in loop-1)
+%0 = add 1:i32, 2:i32
+infer %0
+
+
+; function: loop-2
+
+; start LHS (in loop-2)
+%0 = add 1:i32, 3:i32
+infer %0
+
+
+; start LHS (in loop-2)
+%0 = add 2:i32, 4:i32
+infer %0
+
+
+; start LHS (in loop-2)
+%0 = add 1:i32, 3:i32
+%1 = add 2:i32, 4:i32
+%2 = add %0, %1
+infer %2
+
+
+; function: loop-3
+
+; start LHS (in loop-3)
+%0:i32 = var
+%1 = add %0, 3:i32
+infer %1
+
+
+; start LHS (in loop-3)
+%0:i32 = var
+%1 = add %0, 4:i32
+infer %1
+
+
+; start LHS (in loop-3)
+%0:i32 = var
+%1:i32 = var
+%2 = add %0, %1
+infer %2
+
+
+; function: loop-4
+
+; start LHS (in loop-4)
+%0:i32 = var
+%1 = add %0, 3:i32
+infer %1
+
+
+; start LHS (in loop-4)
+%0:i32 = var
+%1 = add %0, 2:i32
+infer %1
+
+
+; function: loop-5
+
+; start LHS (in loop-5)
+%0:i32 = var
+%1 = add %0, 3:i32
+infer %1
+
+
+; start LHS (in loop-5)
+%0:i32 = var
+%1 = add %0, 2:i32
+infer %1
+
+
+; function: loop-6
+
+; start LHS (in loop-6)
+%0:i32 = var
+%1 = add %0, 3:i32
+infer %1
+
+
+; start LHS (in loop-6)
+%0:i32 = var
+%1 = add %0, 2:i32
+infer %1
+
+
+; function: loop-7
+
+; start LHS (in loop-7)
+%0:i32 = var
+%1 = add %0, 3:i32
+infer %1
+
+
+; start LHS (in loop-7)
+%0:i32 = var
+%1 = add %0, 5:i32
+infer %1
+
+
+; function: loop-8
+
+; start LHS (in loop-8)
+%0 = add 1:i32, 4:i32
+infer %0
+
+
+; start LHS (in loop-8)
+%0:i32 = var
+%1 = sub 1:i32, %0
+infer %1
+
+
+; start LHS (in loop-8)
+%0 = add 1:i32, 4:i32
+%1:i32 = var
+%2 = sub 1:i32, %1
+%3 = mul %0, %2
+infer %3
+
+
+; function: loop-9
+
+; start LHS (in loop-9)
+%0:i32 = var
+%1:i32 = var
+%2 = add %0, %1
+infer %2
+
+
+; function: loop-10
+
+; start LHS (in loop-10)
+%0:i32 = var
+%1:i32 = var
+%2 = add %0, %1
+infer %2
+
+
+; function: loop-multicond-1
+
+; start LHS (in loop-multicond-1)
+%0 = ne 6:i32, 0:i32
+infer %0
+
+
+; start LHS (in loop-multicond-1)
+%0 = ne 6:i32, 0:i32
+%1 = select %0, 4:i32, 5:i32
+infer %1
+
+
+; function: loop-multicond-2
+
+; start LHS (in loop-multicond-2)
+%0:i32 = var
+%1 = add %0, 4:i32
+infer %1
+
+
+; start LHS (in loop-multicond-2)
+%0:i32 = var
+%1 = add %0, 5:i32
+infer %1
+
+
+; start LHS (in loop-multicond-2)
+%0 = add 3:i32, 6:i32
+infer %0
+
+
+; start LHS (in loop-multicond-2)
+%0 = add 3:i32, 6:i32
+%1 = ne %0, 0:i32
+infer %1
+
+
+; start LHS (in loop-multicond-2)
+%0 = add 3:i32, 6:i32
+%1 = ne %0, 0:i32
+%2:i32 = var
+%3:i32 = var
+%4 = select %1, %2, %3
+infer %4
+
+
+; function: loop-block-1
+
+; start LHS (in loop-block-1)
+%0:i32 = var
+%1 = add %0, 4:i32
+infer %1
+
+
+; start LHS (in loop-block-1)
+%0:i32 = var
+%1 = add %0, 5:i32
+infer %1
+
+
+; start LHS (in loop-block-1)
+%0:i32 = var
+%1 = add %0, 6:i32
+infer %1
+
+
+; start LHS (in loop-block-1)
+%0:i32 = var
+%1 = ne %0, 0:i32
+infer %1
+
+
+; start LHS (in loop-block-1)
+%0:i32 = var
+%1 = ne %0, 0:i32
+%2:i32 = var
+%3 = block 2
+%4:i32 = var
+%5:i32 = var
+%6 = phi %3, %4, %5
+%7 = select %1, %2, %6
+infer %7
+
+
+; function: loop-block-2
+
+; start LHS (in loop-block-2)
+%0:i32 = var
+%1 = add %0, 4:i32
+infer %1
+
+
+; start LHS (in loop-block-2)
+%0:i32 = var
+%1 = add %0, 5:i32
+infer %1
+
+
+; start LHS (in loop-block-2)
+%0:i32 = var
+%1 = add %0, 6:i32
+infer %1
+
+
+; start LHS (in loop-block-2)
+%0:i32 = var
+%1 = ne %0, 0:i32
+infer %1
+
+
+; start LHS (in loop-block-2)
+%0:i32 = var
+%1 = ne %0, 0:i32
+%2:i32 = var
+%3 = block 2
+%4:i32 = var
+%5:i32 = var
+%6 = phi %3, %4, %5
+%7 = select %1, %2, %6
+infer %7
+
+
+; function: bad-phi-type
+
+; function: loop-unreachable
+
+; function: phi-value-turns-bad
+
+; start LHS (in phi-value-turns-bad)
+%0:i32 = var
+%1 = ctlz %0
+%2 = eq %0, 0:i32
+pc %2 1:i1
+infer %1
+
+
+; function: multi-use
+
+; start LHS (in multi-use)
+%0:i32 = var
+%1 = add %0, 1:i32
+infer %1
+
+
+; start LHS (in multi-use)
+%0:i32 = var
+%1 = add %0, %0
+infer %1
+
+
+; function: multi-use-2
+
+; start LHS (in multi-use-2)
+%0:i32 = var
+%1 = add %0, 1:i32
+infer %1
+
+
+; start LHS (in multi-use-2)
+%0:i32 = var
+%1 = mul %0, 2:i32
+infer %1
+
+
+; start LHS (in multi-use-2)
+%0:i32 = var
+%1 = mul %0, 2:i32
+%2 = sub %1, %0
+infer %2
+
+
+; function: many-single-uses-with-param
+
+; start LHS (in many-single-uses-with-param)
+%0:i32 = var
+%1 = mul 10:i32, %0
+infer %1
+
+
+; start LHS (in many-single-uses-with-param)
+%0:i32 = var
+%1 = cttz %0
+infer %1
+
+
+; start LHS (in many-single-uses-with-param)
+%0:i32 = var
+%1 = cttz %0
+%2 = sub %1, 20:i32
+infer %2
+
+
+; start LHS (in many-single-uses-with-param)
+%0:i32 = var
+%1 = mul 10:i32, %0
+%2 = cttz %0
+%3 = sub %2, 20:i32
+%4 = add %1, %3
+infer %4
+
+
+; start LHS (in many-single-uses-with-param)
+%0:i32 = var
+%1 = mul 10:i32, %0
+%2 = cttz %0
+%3 = sub %2, 20:i32
+%4 = add %1, %3
+%5 = eq %4, 0:i32
+infer %5
+
+
+; function: 55
+
+; start LHS (in 55)
+%0:i32 = var
+%1 = add %0, -7:i32
+infer %1
+
+
+; start LHS (in 55)
+%0:i32 = var
+%1 = eq %0, 0:i32
+%2 = ne %0, 0:i32
+pc %2 1:i1
+infer %1
+
+
+; start LHS (in 55)
+%0:i32 = var
+%1:i32 = var
+%2 = ne %0, %1
+%3 = ne %1, 0:i32
+pc %3 1:i1
+infer %2
+
+
+; function: multiple-uses-to-non-expression
+
+; start LHS (in multiple-uses-to-non-expression)
+%0:i32 = var
+%1 = add %0, 10:i32
+infer %1
+
+
+; start LHS (in multiple-uses-to-non-expression)
+%0:i32 = var
+%1 = add %0, 20:i32
+infer %1
+
+
+; function: nested-phi-forwarding
+
+; start LHS (in nested-phi-forwarding)
+%0 = block 2
+%1:i32 = var
+%2 = block 2
+%3 = block 2
+%4 = phi %3, %1, 1:i32
+%5 = phi %2, %1, %4
+%6 = phi %0, %1, %5
+%7 = or 1:i32, %6
+infer %7
+
+
+; function: zext-numGets
+
+; start LHS (in zext-numGets)
+%0:i32 = var
+%1 = eq %0, 0:i32
+infer %1
+
+
+; start LHS (in zext-numGets)
+%0 = block 2
+%1:i32 = var
+%2 = eq %1, 0:i32
+%3:i32 = zext %2
+%4 = phi %0, 1:i32, %3
+%5 = cttz %4
+infer %5
+
+
+; function: zext-numGets-hasAnotherUse
+
+; start LHS (in zext-numGets-hasAnotherUse)
+%0:i32 = var
+%1 = eq %0, 0:i32
+infer %1
+
+
+; start LHS (in zext-numGets-hasAnotherUse)
+%0 = block 2
+%1:i32 = var
+%2 = eq %1, 0:i32
+%3:i32 = zext %2
+%4 = phi %0, 1:i32, %3
+%5 = cttz %4
+infer %5
+
+
+; function: flipped-needs-right-origin
+
+; start LHS (in flipped-needs-right-origin)
+%0 = block 2
+%1 = phi %0, 0:i32, 2:i32
+%2 = add %1, 4:i32
+infer %2
+
+
+; start LHS (in flipped-needs-right-origin)
+%0 = block 2
+%1 = phi %0, 0:i32, 2:i32
+%2 = add %1, 4:i32
+%3 = slt %2, 3:i32
+infer %3
+
+
+; function: non-expr-nodes-may-have-multiple-uses-too-its-the-ORIGIN
+
+; start LHS (in non-expr-nodes-may-have-multiple-uses-too-its-the-ORIGIN)
+%0:i32 = var
+%1 = ult 1:i32, %0
+infer %1
+
+
+; start LHS (in non-expr-nodes-may-have-multiple-uses-too-its-the-ORIGIN)
+%0:i32 = var
+%1:i32 = zext %0
+%2 = sub 4:i32, %1
+infer %2
+
+
+; function: loop-of-set-connections
+
+; start LHS (in loop-of-set-connections)
+%0 = add 0:i32, 1:i32
+%1 = ne 0:i32, 0:i32
+pc %1 1:i1
+infer %0
+
+
+; function: conditions-in-conditions
+
+; start LHS (in conditions-in-conditions)
+%0 = sub 0:i32, 1:i32
+%1 = ne 0:i32, 0:i32
+pc %1 1:i1
+infer %0
+
+
+; start LHS (in conditions-in-conditions)
+%0 = block 2
+%1 = block 2
+%2 = phi %1, 0:i32, 1:i32
+%3 = phi %0, %2, 1:i32
+%4 = add %3, 16:i32
+%5 = ne 0:i32, 0:i32
+blockpc %1 0 %5 1:i1
+%6 = eq 0:i32, 0:i32
+blockpc %1 1 %6 1:i1
+%7:i32 = var
+%8 = phi %1, 1:i32, %7
+%9 = ne %8, 0:i32
+blockpc %0 0 %9 1:i1
+%10 = eq %8, 0:i32
+blockpc %0 1 %10 1:i1
+infer %4
+
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $none_=>_f64 (func (result f64)))
+ (type $none_=>_none (func))
+ (type $i64_i64_i64_=>_i32 (func (param i64 i64 i64) (result i32)))
+ (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32)))
+ (type $i64_i64_i32_f32_=>_none (func (param i64 i64 i32 f32)))
+ (type $i32_i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32 i32) (result i32)))
+ (type $i64_i64_i64_=>_i64 (func (param i64 i64 i64) (result i64)))
+ (memory $0 (shared 1 1))
+ (export "replaced-print-internal" (func $55))
+ (func $figure-1a (param $a i64) (param $x i64) (param $y i64) (result i32)
+  (local $i i32)
+  (local $j i32)
+  (local $r i32)
+  (local $6 i64)
+  (local $7 i64)
+  (local $8 i32)
+  (local $9 i64)
+  (local $10 i64)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (block
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (local.set $12
+    (i64.eq
+     (local.get $a)
+     (local.get $x)
+    )
+   )
+   (local.set $13
+    (i64.ne
+     (local.get $a)
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $15
+    (i32.and
+     (local.get $12)
+     (local.get $13)
+    )
+   )
+   (return
+    (local.get $15)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $16)
+  )
+ )
+ (func $figure-1b (param $a i64) (param $x i64) (param $y i64) (result i32)
+  (local $i i32)
+  (local $j i32)
+  (local $r i32)
+  (local $6 i64)
+  (local $7 i64)
+  (local $8 i32)
+  (local $9 i64)
+  (local $10 i64)
+  (local $11 i32)
+  (local $12 i64)
+  (local $13 i64)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (block
+   (nop)
+   (nop)
+   (local.set $8
+    (i64.lt_s
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (if
+    (local.get $8)
+    (block
+     (block $block
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (local.set $15
+       (i64.eq
+        (local.get $a)
+        (local.get $x)
+       )
+      )
+      (local.set $16
+       (i64.ne
+        (local.get $a)
+        (local.get $y)
+       )
+      )
+      (nop)
+      (nop)
+      (local.set $18
+       (i32.and
+        (local.get $15)
+        (local.get $16)
+       )
+      )
+      (return
+       (local.get $18)
+      )
+      (unreachable)
+     )
+     (unreachable)
+    )
+    (block
+     (unreachable)
+     (unreachable)
+    )
+   )
+  )
+  (unreachable)
+ )
+ (func $figure-3-if (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block
+   (block
+    (nop)
+    (local.set $2
+     (i32.and
+      (local.get $x)
+      (i32.const 1)
+     )
+    )
+    (if
+     (local.get $2)
+     (block
+      (nop)
+      (nop)
+      (local.set $x
+       (i32.add
+        (local.get $x)
+        (i32.const 1)
+       )
+      )
+     )
+     (block
+      (nop)
+      (nop)
+      (local.set $x
+       (i32.add
+        (local.get $x)
+        (i32.const 2)
+       )
+      )
+     )
+    )
+   )
+   (nop)
+   (local.set $8
+    (i32.and
+     (local.get $x)
+     (i32.const 1)
+    )
+   )
+   (return
+    (local.get $8)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $9)
+  )
+ )
+ (func $flips
+  (local $x i32)
+  (local $y i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (nop)
+  (nop)
+  (nop)
+  (local.set $x
+   (i32.ge_s
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (nop)
+  (nop)
+  (nop)
+  (local.set $x
+   (i32.ge_u
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (nop)
+  (nop)
+  (nop)
+  (local.set $x
+   (i32.gt_s
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (nop)
+  (nop)
+  (nop)
+  (local.set $x
+   (i32.gt_u
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+ )
+ (func $various-conditions-1 (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (nop)
+  (if
+   (local.get $x)
+   (block
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 1)
+     )
+    )
+   )
+  )
+ )
+ (func $various-conditions-2 (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (nop)
+  (local.set $2
+   (i32.lt_s
+    (local.get $x)
+    (i32.const 0)
+   )
+  )
+  (if
+   (local.get $2)
+   (block
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.sub
+      (local.get $x)
+      (i32.const 2)
+     )
+    )
+   )
+  )
+ )
+ (func $various-conditions-3 (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local.set $1
+   (i32.reinterpret_f32
+    (f32.const 0)
+   )
+  )
+  (if
+   (local.get $1)
+   (block
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.sub
+      (local.get $x)
+      (i32.const 4)
+     )
+    )
+   )
+  )
+ )
+ (func $various-conditions-4 (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block
+   (unreachable)
+   (if
+    (unreachable)
+    (block
+     (nop)
+     (nop)
+     (local.set $x
+      (i32.add
+       (local.get $x)
+       (i32.const 3)
+      )
+     )
+    )
+   )
+  )
+  (unreachable)
+ )
+ (func $unaries (param $x i32) (param $y i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (nop)
+  (local.set $3
+   (i32.eqz
+    (local.get $x)
+   )
+  )
+  (if
+   (local.get $3)
+   (block
+    (nop)
+    (local.set $5
+     (i32.ctz
+      (local.get $y)
+     )
+    )
+    (nop)
+    (local.set $7
+     (i32.clz
+      (local.get $x)
+     )
+    )
+    (nop)
+    (local.set $9
+     (i32.popcnt
+      (local.get $y)
+     )
+    )
+    (local.set $10
+     (i32.sub
+      (local.get $7)
+      (local.get $9)
+     )
+    )
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $5)
+      (local.get $10)
+     )
+    )
+   )
+  )
+ )
+ (func $unary-condition (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (nop)
+  (local.set $2
+   (i32.gt_u
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (local.set $3
+   (i32.ctz
+    (local.get $2)
+   )
+  )
+  (if
+   (local.get $3)
+   (block
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 2)
+     )
+    )
+   )
+  )
+ )
+ (func $unary-condition-2 (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (nop)
+  (local.set $2
+   (i32.gt_u
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (local.set $3
+   (i32.eqz
+    (local.get $2)
+   )
+  )
+  (if
+   (local.get $3)
+   (block
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 2)
+     )
+    )
+   )
+  )
+ )
+ (func $if-else-cond (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block
+   (block
+    (nop)
+    (local.set $2
+     (i32.lt_s
+      (local.get $x)
+      (i32.const 1)
+     )
+    )
+    (if
+     (local.get $2)
+     (block
+      (nop)
+      (nop)
+      (local.set $x
+       (i32.add
+        (local.get $x)
+        (i32.const 1)
+       )
+      )
+     )
+     (block
+      (nop)
+      (nop)
+      (local.set $x
+       (i32.add
+        (local.get $x)
+        (i32.const 2)
+       )
+      )
+     )
+    )
+   )
+   (nop)
+   (local.set $8
+    (i32.and
+     (local.get $x)
+     (i32.const 1)
+    )
+   )
+   (return
+    (local.get $8)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $9)
+  )
+ )
+ (func $trivial-ret (result i32)
+  (local $0 i32)
+  (local.set $0
+   (i32.add
+    (i32.const 0)
+    (i32.const 1)
+   )
+  )
+  (return
+   (local.get $0)
+  )
+ )
+ (func $trivial-const (result i32)
+  (return
+   (i32.const 0)
+  )
+ )
+ (func $trivial-const-block (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (block
+   (nop)
+   (nop)
+  )
+  (local.set $1
+   (i32.const 0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $bad-phi-value (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (block
+   (if
+    (i32.const 1)
+    (block
+     (nop)
+     (local.set $1
+      (i32.load
+       (i32.const 0)
+      )
+     )
+    )
+    (local.set $1
+     (i32.const 0)
+    )
+   )
+   (nop)
+   (if
+    (local.get $1)
+    (local.set $3
+     (i32.const 0)
+    )
+    (local.set $3
+     (i32.const 1)
+    )
+   )
+  )
+  (nop)
+  (return
+   (local.get $3)
+  )
+ )
+ (func $bad-phi-value-2 (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block
+   (block
+    (if
+     (i32.const 1)
+     (block
+      (nop)
+      (local.set $2
+       (i32.load
+        (i32.const 0)
+       )
+      )
+     )
+     (local.set $2
+      (i32.const 0)
+     )
+    )
+    (nop)
+    (if
+     (local.get $2)
+     (local.set $x
+      (i32.const 1)
+     )
+     (local.set $x
+      (i32.const 2)
+     )
+    )
+   )
+   (nop)
+   (nop)
+  )
+  (nop)
+  (return
+   (local.get $x)
+  )
+ )
+ (func $select (param $x i32) (result i32)
+  (local $1 i32)
+  (local.set $1
+   (select
+    (i32.const 1)
+    (i32.const 2)
+    (i32.const 3)
+   )
+  )
+  (return
+   (local.get $1)
+  )
+  (unreachable)
+ )
+ (func $select-2 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (nop)
+  (nop)
+  (local.set $4
+   (i32.add
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (nop)
+  (local.set $6
+   (i32.add
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (nop)
+  (local.set $8
+   (i32.add
+    (i32.const 2)
+    (local.get $y)
+   )
+  )
+  (local.set $9
+   (select
+    (local.get $4)
+    (local.get $6)
+    (local.get $8)
+   )
+  )
+  (return
+   (local.get $9)
+  )
+  (unreachable)
+ )
+ (func $block-phi-1 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block
+   (block $out
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 1)
+     )
+    )
+    (nop)
+    (br_if $out
+     (local.get $y)
+    )
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 2)
+     )
+    )
+   )
+   (nop)
+   (nop)
+   (nop)
+  )
+  (local.set $10
+   (i32.add
+    (local.get $x)
+    (i32.const 3)
+   )
+  )
+  (return
+   (local.get $10)
+  )
+ )
+ (func $block-phi-2 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block
+   (block $out
+    (local.set $x
+     (i32.const 1)
+    )
+    (nop)
+    (br_if $out
+     (local.get $y)
+    )
+    (local.set $x
+     (i32.const 2)
+    )
+   )
+   (nop)
+   (nop)
+   (nop)
+  )
+  (local.set $6
+   (i32.add
+    (local.get $x)
+    (i32.const 3)
+   )
+  )
+  (return
+   (local.get $6)
+  )
+ )
+ (func $zero_init-phi-bad_type (result f64)
+  (local $x f64)
+  (local $1 f64)
+  (local $2 f64)
+  (local $3 f64)
+  (block
+   (if
+    (i32.const 0)
+    (local.set $x
+     (f64.const 1)
+    )
+   )
+   (nop)
+   (nop)
+  )
+  (nop)
+  (return
+   (local.get $x)
+  )
+ )
+ (func $phi-bad-type (result f64)
+  (local $0 f64)
+  (local $1 f64)
+  (local $2 f64)
+  (local $3 f64)
+  (block $label$1
+   (if
+    (i32.const 0)
+    (local.set $0
+     (f64.const 0)
+    )
+    (local.set $0
+     (f64.const 1)
+    )
+   )
+   (nop)
+   (nop)
+  )
+  (nop)
+  (return
+   (local.get $0)
+  )
+ )
+ (func $phi-one-side-i1 (param $x i32) (param $y i32) (result i32)
+  (local $i i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (block
+   (block
+    (nop)
+    (nop)
+    (local.set $5
+     (i32.le_s
+      (local.get $x)
+      (local.get $y)
+     )
+    )
+    (if
+     (local.get $5)
+     (block
+      (nop)
+      (nop)
+      (nop)
+      (local.set $i
+       (i32.eq
+        (local.get $x)
+        (local.get $y)
+       )
+      )
+     )
+     (block
+      (nop)
+      (nop)
+      (nop)
+      (local.set $i
+       (i32.add
+        (local.get $x)
+        (local.get $y)
+       )
+      )
+     )
+    )
+   )
+   (nop)
+   (nop)
+  )
+  (nop)
+  (return
+   (local.get $i)
+  )
+ )
+ (func $call (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $0
+   (call $call)
+  )
+  (local.set $1
+   (call $call)
+  )
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (local.set $3
+   (call $call)
+  )
+  (local.set $4
+   (i32.add
+    (i32.const 10)
+    (local.get $3)
+   )
+  )
+  (local.set $5
+   (i32.mul
+    (local.get $2)
+    (local.get $4)
+   )
+  )
+  (return
+   (local.get $5)
+  )
+  (unreachable)
+ )
+ (func $in-unreachable-1 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block
+   (block
+    (nop)
+    (if
+     (local.get $x)
+     (block
+      (block $block
+       (local.set $x
+        (i32.const 1)
+       )
+       (nop)
+       (return
+        (local.get $x)
+       )
+       (unreachable)
+      )
+      (unreachable)
+     )
+     (local.set $x
+      (i32.const 2)
+     )
+    )
+   )
+   (nop)
+   (return
+    (local.get $x)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $5)
+  )
+ )
+ (func $in-unreachable-2 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (block
+   (block
+    (nop)
+    (if
+     (local.get $x)
+     (block
+      (block $block
+       (local.set $x
+        (i32.const 1)
+       )
+       (unreachable)
+       (unreachable)
+      )
+      (unreachable)
+     )
+     (local.set $x
+      (i32.const 2)
+     )
+    )
+   )
+   (nop)
+   (return
+    (local.get $x)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $4)
+  )
+ )
+ (func $in-unreachable-3 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block
+   (block $out
+    (block
+     (nop)
+     (if
+      (local.get $x)
+      (block
+       (block $block
+        (local.set $x
+         (i32.const 1)
+        )
+        (br $out)
+        (unreachable)
+       )
+       (unreachable)
+      )
+      (local.set $x
+       (i32.const 2)
+      )
+     )
+    )
+    (nop)
+    (return
+     (local.get $x)
+    )
+    (unreachable)
+   )
+   (nop)
+   (return
+    (local.get $x)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $5)
+  )
+ )
+ (func $in-unreachable-4 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block
+   (block $out
+    (block
+     (nop)
+     (if
+      (local.get $x)
+      (block
+       (block $block
+        (local.set $x
+         (i32.const 1)
+        )
+        (br_table $out $out $out
+         (i32.const 1)
+        )
+        (unreachable)
+       )
+       (unreachable)
+      )
+      (local.set $x
+       (i32.const 2)
+      )
+     )
+    )
+    (nop)
+    (return
+     (local.get $x)
+    )
+    (unreachable)
+   )
+   (nop)
+   (return
+    (local.get $x)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $5)
+  )
+ )
+ (func $in-unreachable-br_if (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (block
+   (block $out
+    (block
+     (nop)
+     (if
+      (local.get $x)
+      (block $block
+       (local.set $x
+        (i32.const 1)
+       )
+       (nop)
+       (br_if $out
+        (local.get $x)
+       )
+      )
+      (local.set $x
+       (i32.const 2)
+      )
+     )
+    )
+    (nop)
+    (return
+     (local.get $x)
+    )
+    (unreachable)
+   )
+   (nop)
+   (return
+    (local.get $x)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $6)
+  )
+ )
+ (func $in-unreachable-big (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (block $label$1
+   (block $label$2
+    (block $label$3
+     (block
+      (nop)
+      (if
+       (local.get $2)
+       (block
+        (block
+         (nop)
+         (if
+          (local.get $0)
+          (block
+           (block $block
+            (local.set $1
+             (i32.const -8531)
+            )
+            (br $label$3)
+            (unreachable)
+           )
+           (unreachable)
+          )
+          (block
+           (block $block3
+            (local.set $1
+             (i32.const -8531)
+            )
+            (br $label$1)
+            (unreachable)
+           )
+           (unreachable)
+          )
+         )
+        )
+        (unreachable)
+       )
+      )
+     )
+     (br $label$2)
+     (unreachable)
+    )
+    (local.set $6
+     (i32.load
+      (i32.const 0)
+     )
+    )
+    (drop
+     (local.get $6)
+    )
+    (br $label$1)
+    (unreachable)
+   )
+   (nop)
+   (i32.store16
+    (i32.const 1)
+    (local.get $1)
+   )
+   (unreachable)
+   (unreachable)
+  )
+  (i32.store16
+   (i32.const 0)
+   (i32.const -8531)
+  )
+ )
+ (func $in-unreachable-operations (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (block $block
+   (unreachable)
+   (unreachable)
+   (block
+    (nop)
+    (if
+     (local.get $x)
+     (local.set $x
+      (i32.const 1)
+     )
+     (local.set $x
+      (i32.const 2)
+     )
+    )
+   )
+   (nop)
+   (return
+    (local.get $x)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $merge-with-one-less (param $var$0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block
+   (block $label$1
+    (block $label$2
+     (block $label$3
+      (block $label$4
+       (block $label$5
+        (local.set $1
+         (i32.load
+          (i32.const 1)
+         )
+        )
+        (br_table $label$5 $label$4 $label$3 $label$2
+         (local.get $1)
+        )
+        (unreachable)
+       )
+       (unreachable)
+       (unreachable)
+      )
+      (br $label$1)
+      (unreachable)
+     )
+     (local.set $var$0
+      (i32.const 8)
+     )
+     (nop)
+     (local.set $3
+      (i32.load
+       (local.get $var$0)
+      )
+     )
+     (f64.store
+      (local.get $3)
+      (f64.const 0)
+     )
+     (br $label$1)
+     (unreachable)
+    )
+    (unreachable)
+    (unreachable)
+   )
+   (nop)
+   (i32.store
+    (local.get $var$0)
+    (i32.const 16)
+   )
+   (nop)
+  )
+  (local.set $6
+   (i32.const 1)
+  )
+  (return
+   (local.get $6)
+  )
+ )
+ (func $deep (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (local $19 i32)
+  (local $20 i32)
+  (local $21 i32)
+  (local $22 i32)
+  (local $23 i32)
+  (local $24 i32)
+  (local $25 i32)
+  (local $26 i32)
+  (local $27 i32)
+  (local $28 i32)
+  (local $29 i32)
+  (local $30 i32)
+  (local $31 i32)
+  (local $32 i32)
+  (local $33 i32)
+  (local $34 i32)
+  (local $35 i32)
+  (local $36 i32)
+  (local $37 i32)
+  (local $38 i32)
+  (local $39 i32)
+  (local $40 i32)
+  (local $41 i32)
+  (local $42 i32)
+  (local $43 i32)
+  (local $44 i32)
+  (local $45 i32)
+  (local $46 i32)
+  (local $47 i32)
+  (local $48 i32)
+  (local $49 i32)
+  (local $50 i32)
+  (local $51 i32)
+  (local $52 i32)
+  (local $53 i32)
+  (local $54 i32)
+  (local $55 i32)
+  (block
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+  )
+  (nop)
+  (return
+   (local.get $x)
+  )
+ )
+ (func $two-pcs (param $x i64) (param $y i64) (param $t i64) (result i64)
+  (local $3 i64)
+  (local $4 i64)
+  (local $5 i32)
+  (local $6 i64)
+  (local $7 i32)
+  (local $8 i64)
+  (local $9 i64)
+  (local $10 i64)
+  (local $11 i64)
+  (local $12 i64)
+  (local $13 i64)
+  (local $14 i64)
+  (local $15 i32)
+  (local $16 i64)
+  (local $17 i64)
+  (local $18 i64)
+  (local $19 i64)
+  (local $20 i64)
+  (local $21 i64)
+  (local $22 i64)
+  (local $23 i64)
+  (local $24 i64)
+  (block
+   (block
+    (nop)
+    (nop)
+    (local.set $5
+     (i64.lt_s
+      (local.get $x)
+      (local.get $y)
+     )
+    )
+    (if
+     (local.get $5)
+     (block
+      (nop)
+      (local.set $7
+       (i64.eqz
+        (local.get $x)
+       )
+      )
+      (if
+       (local.get $7)
+       (block
+        (nop)
+        (nop)
+        (nop)
+        (local.set $t
+         (i64.add
+          (local.get $x)
+          (local.get $y)
+         )
+        )
+       )
+       (block
+        (nop)
+        (nop)
+        (nop)
+        (local.set $t
+         (i64.sub
+          (local.get $x)
+          (local.get $y)
+         )
+        )
+       )
+      )
+     )
+     (block
+      (nop)
+      (local.set $15
+       (i64.eqz
+        (local.get $y)
+       )
+      )
+      (if
+       (local.get $15)
+       (block
+        (nop)
+        (nop)
+        (nop)
+        (local.set $t
+         (i64.mul
+          (local.get $x)
+          (local.get $y)
+         )
+        )
+       )
+       (block
+        (nop)
+        (nop)
+        (nop)
+        (local.set $t
+         (i64.div_s
+          (local.get $x)
+          (local.get $y)
+         )
+        )
+       )
+      )
+     )
+    )
+   )
+   (nop)
+   (return
+    (local.get $t)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $23)
+  )
+ )
+ (func $loop-1 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+   )
+   (nop)
+   (nop)
+   (local.set $4
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $4)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $5)
+  )
+ )
+ (func $loop-2 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 3)
+     )
+    )
+    (nop)
+    (nop)
+    (local.set $y
+     (i32.add
+      (local.get $y)
+      (i32.const 4)
+     )
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $8
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $8)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $9)
+  )
+ )
+ (func $loop-3 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 3)
+     )
+    )
+    (nop)
+    (nop)
+    (local.set $y
+     (i32.add
+      (local.get $y)
+      (i32.const 4)
+     )
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $9
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $9)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $10)
+  )
+ )
+ (func $loop-4 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 3)
+     )
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $7
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $7)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $8)
+  )
+ )
+ (func $loop-5 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 3)
+     )
+    )
+    (local.set $y
+     (i32.const 2)
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $7
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $7)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $8)
+  )
+ )
+ (func $loop-6 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 3)
+     )
+    )
+    (nop)
+    (nop)
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $8
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $8)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $9)
+  )
+ )
+ (func $loop-7 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 3)
+     )
+    )
+    (local.set $y
+     (i32.const 5)
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $7
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $7)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $8)
+  )
+ )
+ (func $loop-8 (param $x i32) (param $y i32) (result i32)
+  (local $z i32)
+  (local $w i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (local.set $z
+     (local.get $x)
+    )
+    (nop)
+    (local.set $w
+     (local.get $y)
+    )
+    (local.set $x
+     (i32.const 1)
+    )
+    (local.set $y
+     (i32.const 4)
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $9
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $12
+    (i32.sub
+     (local.get $z)
+     (local.get $w)
+    )
+   )
+   (local.set $13
+    (i32.mul
+     (local.get $9)
+     (local.get $12)
+    )
+   )
+   (return
+    (local.get $13)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $14)
+  )
+ )
+ (func $loop-9 (param $x i32) (param $y i32) (result i32)
+  (local $t i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (local.set $t
+     (local.get $x)
+    )
+    (nop)
+    (local.set $x
+     (local.get $y)
+    )
+    (nop)
+    (local.set $y
+     (local.get $t)
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $9
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $9)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $10)
+  )
+ )
+ (func $loop-10 (param $x i32) (param $y i32) (result i32)
+  (local $t i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 1)
+   )
+   (loop $loopy
+    (nop)
+    (local.set $t
+     (local.get $x)
+    )
+    (nop)
+    (local.set $x
+     (local.get $y)
+    )
+    (nop)
+    (local.set $y
+     (local.get $t)
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $9
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $9)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $10)
+  )
+ )
+ (func $loop-multicond-1 (param $x i32) (param $y i32) (param $z i32) (result i32)
+  (local $t i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (local.set $z
+    (i32.const 3)
+   )
+   (loop $loopy
+    (local.set $x
+     (i32.const 4)
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $t)
+    )
+    (local.set $y
+     (i32.const 5)
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $t)
+    )
+    (local.set $z
+     (i32.const 6)
+    )
+   )
+   (nop)
+   (nop)
+   (nop)
+   (local.set $9
+    (select
+     (local.get $x)
+     (local.get $y)
+     (local.get $z)
+    )
+   )
+   (return
+    (local.get $9)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $10)
+  )
+ )
+ (func $loop-multicond-2 (param $x i32) (param $y i32) (param $z i32) (result i32)
+  (local $t i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (local.set $z
+    (i32.const 3)
+   )
+   (loop $loopy
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 4)
+     )
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $t)
+    )
+    (nop)
+    (nop)
+    (local.set $y
+     (i32.add
+      (local.get $y)
+      (i32.const 5)
+     )
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $t)
+    )
+    (nop)
+    (nop)
+    (local.set $z
+     (i32.add
+      (local.get $z)
+      (i32.const 6)
+     )
+    )
+   )
+   (nop)
+   (nop)
+   (nop)
+   (local.set $15
+    (select
+     (local.get $x)
+     (local.get $y)
+     (local.get $z)
+    )
+   )
+   (return
+    (local.get $15)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $16)
+  )
+ )
+ (func $loop-block-1 (param $x i32) (param $y i32) (param $z i32) (result i32)
+  (local $t i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (local.set $z
+    (i32.const 3)
+   )
+   (loop $loopy
+    (block $out
+     (nop)
+     (nop)
+     (local.set $x
+      (i32.add
+       (local.get $x)
+       (i32.const 4)
+      )
+     )
+     (nop)
+     (br_if $out
+      (local.get $t)
+     )
+     (nop)
+     (nop)
+     (local.set $y
+      (i32.add
+       (local.get $y)
+       (i32.const 5)
+      )
+     )
+     (nop)
+     (br_if $out
+      (local.get $t)
+     )
+     (nop)
+     (nop)
+     (local.set $z
+      (i32.add
+       (local.get $z)
+       (i32.const 6)
+      )
+     )
+     (br $loopy)
+     (unreachable)
+    )
+   )
+   (nop)
+   (nop)
+   (nop)
+   (local.set $15
+    (select
+     (local.get $x)
+     (local.get $y)
+     (local.get $z)
+    )
+   )
+   (return
+    (local.get $15)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $16)
+  )
+ )
+ (func $loop-block-2 (param $x i32) (param $y i32) (param $z i32) (result i32)
+  (local $t i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (local.set $z
+    (i32.const 3)
+   )
+   (block $out
+    (loop $loopy
+     (block
+      (nop)
+      (nop)
+      (local.set $x
+       (i32.add
+        (local.get $x)
+        (i32.const 4)
+       )
+      )
+      (nop)
+      (br_if $out
+       (local.get $t)
+      )
+      (nop)
+      (nop)
+      (local.set $y
+       (i32.add
+        (local.get $y)
+        (i32.const 5)
+       )
+      )
+      (nop)
+      (br_if $out
+       (local.get $t)
+      )
+      (nop)
+      (nop)
+      (local.set $z
+       (i32.add
+        (local.get $z)
+        (i32.const 6)
+       )
+      )
+      (br $loopy)
+      (unreachable)
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (nop)
+   (nop)
+   (nop)
+   (local.set $15
+    (select
+     (local.get $x)
+     (local.get $y)
+     (local.get $z)
+    )
+   )
+   (return
+    (local.get $15)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $16)
+  )
+ )
+ (func $bad-phi-type (param $var$0 i64) (param $var$1 i64) (param $var$2 i32) (param $var$3 f32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 f64)
+  (local $9 f64)
+  (local $10 f64)
+  (local $11 f64)
+  (nop)
+  (if
+   (local.get $var$2)
+   (block
+    (loop $label$2
+     (block
+      (block
+       (block $label$3
+        (if
+         (i32.const 0)
+         (block
+          (unreachable)
+          (unreachable)
+         )
+        )
+        (nop)
+        (nop)
+       )
+       (local.set $6
+        (i32.const 0)
+       )
+       (if
+        (local.get $6)
+        (block
+         (unreachable)
+         (unreachable)
+        )
+       )
+      )
+      (nop)
+      (br_if $label$2
+       (local.get $var$2)
+      )
+      (nop)
+     )
+     (nop)
+     (local.set $10
+      (f64.const 0)
+     )
+    )
+    (nop)
+    (drop
+     (local.get $10)
+    )
+   )
+  )
+ )
+ (func $loop-unreachable
+  (local $var$0 i32)
+  (local $var$1 f64)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 f64)
+  (local $12 f64)
+  (local $13 f64)
+  (loop $label$1
+   (block
+    (block $label$2
+     (block $label$3
+      (block $label$4
+       (if
+        (i32.const 1337)
+        (block
+         (unreachable)
+         (unreachable)
+        )
+       )
+       (nop)
+       (nop)
+      )
+      (nop)
+      (nop)
+      (loop $label$6
+       (block $label$7
+        (nop)
+        (local.set $6
+         (local.get $var$0)
+        )
+        (br_if $label$7
+         (i32.const 65535)
+        )
+        (nop)
+        (drop
+         (local.get $6)
+        )
+        (nop)
+        (local.set $6
+         (local.get $var$0)
+        )
+        (br_if $label$7
+         (i32.const 0)
+        )
+        (nop)
+        (drop
+         (local.get $6)
+        )
+        (unreachable)
+        (unreachable)
+       )
+       (nop)
+       (br_if $label$6
+        (local.get $6)
+       )
+      )
+     )
+     (nop)
+     (nop)
+    )
+    (nop)
+    (nop)
+    (br $label$1)
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $phi-value-turns-bad (result f64)
+  (local $var$0 i32)
+  (local $var$1 i32)
+  (local $var$2 f32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 f32)
+  (local $13 f32)
+  (local $14 f32)
+  (local $15 f32)
+  (local $16 f64)
+  (local $17 f64)
+  (block
+   (block
+    (nop)
+    (local.set $var$0
+     (i32.atomic.rmw16.sub_u offset=22
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+    (nop)
+    (if
+     (local.get $var$0)
+     (block
+      (unreachable)
+      (unreachable)
+     )
+     (block
+      (block $block
+       (block
+        (loop $label$3
+         (block $label$4
+          (nop)
+          (local.set $6
+           (local.get $var$0)
+          )
+          (br_if $label$4
+           (i32.const 1)
+          )
+          (nop)
+          (nop)
+          (local.set $6
+           (i32.clz
+            (local.get $6)
+           )
+          )
+         )
+         (nop)
+         (nop)
+        )
+        (nop)
+        (if
+         (local.get $6)
+         (nop)
+        )
+       )
+       (nop)
+      )
+      (nop)
+      (local.set $14
+       (f32.const 1)
+      )
+     )
+    )
+   )
+   (nop)
+   (nop)
+   (unreachable)
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $16)
+  )
+ )
+ (func $multi-use (param $x i32) (result i32)
+  (local $temp i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (block
+   (nop)
+   (nop)
+   (local.set $temp
+    (i32.add
+     (local.get $x)
+     (i32.const 1)
+    )
+   )
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+  )
+  (local.set $8
+   (i32.add
+    (local.get $temp)
+    (local.get $temp)
+   )
+  )
+  (return
+   (local.get $8)
+  )
+ )
+ (func $multi-use-2 (param $x i32) (result i32)
+  (local $temp i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block
+   (nop)
+   (nop)
+   (local.set $temp
+    (i32.add
+     (local.get $x)
+     (i32.const 1)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $temp)
+     (i32.const 2)
+    )
+   )
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+  )
+  (local.set $10
+   (i32.sub
+    (local.get $x)
+    (local.get $temp)
+   )
+  )
+  (return
+   (local.get $10)
+  )
+ )
+ (func $many-single-uses-with-param (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (nop)
+  (local.set $2
+   (i32.mul
+    (i32.const 10)
+    (local.get $x)
+   )
+  )
+  (nop)
+  (local.set $4
+   (i32.ctz
+    (local.get $x)
+   )
+  )
+  (local.set $5
+   (i32.sub
+    (local.get $4)
+    (i32.const 20)
+   )
+  )
+  (local.set $6
+   (i32.add
+    (local.get $2)
+    (local.get $5)
+   )
+  )
+  (local.set $7
+   (i32.eqz
+    (local.get $6)
+   )
+  )
+  (return
+   (local.get $7)
+  )
+  (unreachable)
+ )
+ (func $55 (param $var$0 i32)
+  (local $var$1 i32)
+  (local $var$2 i32)
+  (local $var$3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (nop)
+  (nop)
+  (local.set $var$0
+   (i32.add
+    (local.get $var$0)
+    (i32.const -7)
+   )
+  )
+  (nop)
+  (if
+   (local.get $var$0)
+   (block $label$2
+    (block $label$3
+     (nop)
+     (local.set $var$1
+      (local.get $var$0)
+     )
+     (nop)
+     (local.set $8
+      (i32.const 12)
+     )
+     (br_if $label$3
+      (local.get $8)
+     )
+     (unreachable)
+     (unreachable)
+    )
+    (nop)
+    (local.set $10
+     (i32.eqz
+      (local.get $var$1)
+     )
+    )
+    (br_if $label$2
+     (local.get $10)
+    )
+    (block
+     (local.set $11
+      (i32.load
+       (i32.const 0)
+      )
+     )
+     (nop)
+     (local.set $13
+      (i32.ne
+       (local.get $11)
+       (local.get $var$0)
+      )
+     )
+     (if
+      (local.get $13)
+      (block
+       (unreachable)
+       (unreachable)
+      )
+     )
+    )
+    (unreachable)
+    (unreachable)
+   )
+  )
+ )
+ (func $multiple-uses-to-non-expression (param $x i32)
+  (local $temp i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (nop)
+  (nop)
+  (local.set $x
+   (i32.add
+    (local.get $x)
+    (i32.const 10)
+   )
+  )
+  (nop)
+  (i32.store
+   (i32.const 1)
+   (local.get $x)
+  )
+  (nop)
+  (local.set $6
+   (i32.add
+    (local.get $x)
+    (i32.const 20)
+   )
+  )
+  (i32.store
+   (i32.const 2)
+   (local.get $6)
+  )
+ )
+ (func $nested-phi-forwarding (param $var$0 i32) (result i32)
+  (local $var$1 i32)
+  (local $var$2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (block
+   (block $label$1
+    (block $label$2
+     (loop $label$3
+      (block $label$4
+       (block $label$5
+        (block $label$6
+         (block $label$7
+          (block $label$8
+           (nop)
+           (br_table $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$8 $label$2 $label$2 $label$2 $label$6 $label$2 $label$2 $label$7 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$5 $label$4
+            (local.get $var$0)
+           )
+           (unreachable)
+          )
+          (local.set $var$1
+           (i32.const 1)
+          )
+         )
+         (br $label$4)
+         (unreachable)
+        )
+        (unreachable)
+        (unreachable)
+       )
+       (br $label$1)
+       (unreachable)
+      )
+      (local.set $var$2
+       (i32.const 1)
+      )
+      (nop)
+      (br_if $label$3
+       (local.get $var$2)
+      )
+     )
+    )
+    (block $label$9
+     (nop)
+     (local.set $6
+      (i32.or
+       (i32.const 1)
+       (local.get $var$1)
+      )
+     )
+     (br_if $label$9
+      (local.get $6)
+     )
+    )
+    (unreachable)
+    (unreachable)
+   )
+   (nop)
+   (i32.store offset=176
+    (i32.const 0)
+    (local.get $var$2)
+   )
+   (nop)
+  )
+  (local.set $9
+   (i32.const 0)
+  )
+  (return
+   (local.get $9)
+  )
+ )
+ (func $zext-numGets (param $var$0 i32) (param $var$1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (block $label$1
+   (local.set $2
+    (i32.load
+     (i32.const -8)
+    )
+   )
+   (local.set $3
+    (i32.const 1)
+   )
+   (br_if $label$1
+    (local.get $2)
+   )
+   (nop)
+   (drop
+    (local.get $3)
+   )
+   (local.set $5
+    (i32.load
+     (i32.const -16)
+    )
+   )
+   (nop)
+   (local.set $3
+    (i32.eqz
+     (local.get $5)
+    )
+   )
+  )
+  (nop)
+  (local.set $8
+   (i32.ctz
+    (local.get $3)
+   )
+  )
+  (if
+   (local.get $8)
+   (block
+    (unreachable)
+    (unreachable)
+   )
+  )
+ )
+ (func $zext-numGets-hasAnotherUse (param $var$0 i32) (param $var$1 i32)
+  (local $temp i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (block $label$1
+   (local.set $3
+    (i32.load
+     (i32.const -8)
+    )
+   )
+   (local.set $4
+    (i32.const 1)
+   )
+   (br_if $label$1
+    (local.get $3)
+   )
+   (nop)
+   (drop
+    (local.get $4)
+   )
+   (local.set $6
+    (i32.load
+     (i32.const -16)
+    )
+   )
+   (nop)
+   (local.set $temp
+    (i32.eqz
+     (local.get $6)
+    )
+   )
+   (nop)
+   (drop
+    (local.get $temp)
+   )
+   (nop)
+   (local.set $4
+    (local.get $temp)
+   )
+  )
+  (nop)
+  (local.set $11
+   (i32.ctz
+    (local.get $4)
+   )
+  )
+  (if
+   (local.get $11)
+   (block
+    (unreachable)
+    (unreachable)
+   )
+  )
+ )
+ (func $flipped-needs-right-origin (param $var$0 i32) (result i32)
+  (local $var$1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (block
+   (block $label$1
+    (local.set $2
+     (i32.load
+      (i32.const 1)
+     )
+    )
+    (br_if $label$1
+     (local.get $2)
+    )
+    (local.set $var$1
+     (i32.const 2)
+    )
+   )
+   (block
+    (nop)
+    (local.set $4
+     (i32.add
+      (local.get $var$1)
+      (i32.const 4)
+     )
+    )
+    (local.set $5
+     (i32.gt_s
+      (i32.const 3)
+      (local.get $4)
+     )
+    )
+    (if
+     (local.get $5)
+     (block
+      (unreachable)
+      (unreachable)
+     )
+    )
+   )
+   (nop)
+  )
+  (local.set $7
+   (i32.const 5)
+  )
+  (return
+   (local.get $7)
+  )
+ )
+ (func $non-expr-nodes-may-have-multiple-uses-too-its-the-ORIGIN (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (block
+   (nop)
+   (nop)
+   (local.set $var$1
+    (i32.gt_u
+     (local.get $var$1)
+     (i32.const 1)
+    )
+   )
+   (nop)
+   (i32.store
+    (local.get $var$1)
+    (i32.const 2)
+   )
+   (nop)
+   (local.set $7
+    (i32.sub
+     (i32.const 4)
+     (local.get $var$1)
+    )
+   )
+   (i32.store offset=8
+    (i32.const 3)
+    (local.get $7)
+   )
+   (unreachable)
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $8)
+  )
+ )
+ (func $loop-of-set-connections (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (param $var$3 i32) (param $var$4 i32) (result i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (loop $label$1
+   (block
+    (if
+     (i32.const 0)
+     (block
+      (block $block
+       (nop)
+       (local.set $var$2
+        (i32.add
+         (i32.const 0)
+         (i32.const 1)
+        )
+       )
+       (br $label$1)
+       (unreachable)
+      )
+      (unreachable)
+     )
+    )
+    (nop)
+    (nop)
+    (nop)
+    (nop)
+    (br $label$1)
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $conditions-in-conditions (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (result i32)
+  (local $var$3 i32)
+  (local $var$4 i32)
+  (local $var$5 i32)
+  (local $var$6 i32)
+  (local $var$7 i32)
+  (local $var$8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (block
+   (local.set $var$1
+    (i32.const 1)
+   )
+   (if
+    (i32.const 0)
+    (loop $label$2
+     (block
+      (nop)
+      (if
+       (local.get $var$1)
+       (nop)
+      )
+     )
+     (local.set $var$3
+      (i32.const 1)
+     )
+     (nop)
+     (nop)
+     (local.set $var$1
+      (i32.sub
+       (i32.const 0)
+       (local.get $var$3)
+      )
+     )
+     (br_if $label$2
+      (i32.const 0)
+     )
+    )
+   )
+   (block
+    (nop)
+    (if
+     (local.get $var$1)
+     (local.set $var$3
+      (i32.const 1)
+     )
+    )
+   )
+   (nop)
+   (local.set $14
+    (i32.add
+     (local.get $var$3)
+     (i32.const 16)
+    )
+   )
+   (i32.store
+    (i32.const 8)
+    (local.get $14)
+   )
+   (i32.store
+    (i32.const 8)
+    (i32.const 64)
+   )
+   (unreachable)
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $15)
+  )
+ )
+)
diff --git a/binaryen/test/passes/flatten_simplify-locals-nonesting_souperify-single-use_enable-threads.wast b/binaryen/test/passes/flatten_simplify-locals-nonesting_souperify-single-use_enable-threads.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_simplify-locals-nonesting_souperify-single-use_enable-threads.wast
@@ -0,0 +1,1246 @@
+(module
+  (memory $0 (shared 1 1))
+  ;; Figure 1a from the Souper paper https://arxiv.org/pdf/1711.04422.pdf
+  (func $figure-1a (param $a i64) (param $x i64) (param $y i64) (result i32)
+    (local $i i32)
+    (local $j i32)
+    (local $r i32)
+    (local.set $i
+      (i64.eq
+        (local.get $a)
+        (local.get $x)
+      )
+    )
+    (local.set $j
+      (i64.ne
+        (local.get $a)
+        (local.get $y)
+      )
+    )
+    (local.set $r
+      (i32.and
+        (local.get $i)
+        (local.get $j)
+      )
+    )
+    (return (local.get $r))
+  )
+  ;; Figure 1b, with a potential path condition
+  (func $figure-1b (param $a i64) (param $x i64) (param $y i64) (result i32)
+    (local $i i32)
+    (local $j i32)
+    (local $r i32)
+    (if
+      (i64.lt_s
+        (local.get $x)
+        (local.get $y)
+      )
+      (block
+        (local.set $i
+          (i64.eq
+            (local.get $a)
+            (local.get $x)
+          )
+        )
+        (local.set $j
+          (i64.ne
+            (local.get $a)
+            (local.get $y)
+          )
+        )
+        (local.set $r
+          (i32.and
+            (local.get $i)
+            (local.get $j)
+          )
+        )
+        (return (local.get $r))
+      )
+      (unreachable)
+    )
+  )
+  ;; Figure 3, simplified to an if
+  (func $figure-3-if (param $x i32) (result i32)
+    (if
+      (i32.and
+        (local.get $x)
+        (i32.const 1)
+      )
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 2)
+        )
+      )
+    )
+    (return
+      (i32.and
+        (local.get $x)
+        (i32.const 1)
+      )
+    )
+  )
+  ;; flipping of greater than/or equals ops, which are not in Souper IR
+  (func $flips
+    (local $x i32)
+    (local $y i32)
+    (local.set $x (i32.ge_s (local.get $x) (local.get $y)))
+    (local.set $x (i32.ge_u (local.get $x) (local.get $y)))
+    (local.set $x (i32.gt_s (local.get $x) (local.get $y)))
+    (local.set $x (i32.gt_u (local.get $x) (local.get $y)))
+  )
+  (func $various-conditions-1 (param $x i32)
+    (if
+      (local.get $x)
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+    )
+  )
+  (func $various-conditions-2 (param $x i32)
+    (if
+      (i32.lt_s
+        (local.get $x)
+        (i32.const 0)
+      )
+      (local.set $x
+        (i32.sub
+          (local.get $x)
+          (i32.const 2)
+        )
+      )
+    )
+  )
+  (func $various-conditions-3 (param $x i32)
+    (if
+      (i32.reinterpret_f32 (f32.const 0))
+      (local.set $x
+        (i32.sub
+          (local.get $x)
+          (i32.const 4)
+        )
+      )
+    )
+  )
+  (func $various-conditions-4 (param $x i32)
+    (if
+      (unreachable)
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 3)
+        )
+      )
+    )
+  )
+  (func $unaries (param $x i32) (param $y i32)
+    (if
+      (i32.eqz
+        (local.get $x)
+      )
+      (local.set $x
+        (i32.add
+          (i32.ctz
+            (local.get $y)
+          )
+          (i32.sub
+            (i32.clz
+              (local.get $x)
+            )
+            (i32.popcnt
+              (local.get $y)
+            )
+          )
+        )
+      )
+    )
+  )
+  (func $unary-condition (param $x i32)
+    (if
+      (i32.ctz
+        (i32.gt_u
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 2)
+        )
+      )
+    )
+  )
+  (func $unary-condition-2 (param $x i32)
+    (if
+      (i32.eqz
+        (i32.gt_u
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 2)
+        )
+      )
+    )
+  )
+  (func $if-else-cond (param $x i32) (result i32)
+    (if
+      (i32.lt_s
+        (local.get $x)
+        (i32.const 1)
+      )
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 2)
+        )
+      )
+    )
+    (return
+      (i32.and
+        (local.get $x)
+        (i32.const 1)
+      )
+    )
+  )
+  (func $trivial-ret (result i32)
+    (i32.add
+      (i32.const 0)
+      (i32.const 1)
+    )
+  )
+  (func $trivial-const (result i32)
+    (i32.const 0)
+  )
+  (func $trivial-const-block (result i32)
+    (nop)
+    (i32.const 0)
+  )
+  (func $bad-phi-value (result i32)
+    (if (result i32)
+      (if (result i32)
+        (i32.const 1)
+        (i32.load
+          (i32.const 0)
+        )
+        (i32.const 0)
+      )
+      (i32.const 0)
+      (i32.const 1)
+    )
+  )
+  (func $bad-phi-value-2 (param $x i32) (result i32)
+    (if
+      (if (result i32)
+        (i32.const 1)
+        (i32.load
+          (i32.const 0)
+        )
+        (i32.const 0)
+      )
+      (local.set $x (i32.const 1))
+      (local.set $x (i32.const 2))
+    )
+    (local.get $x)
+  )
+  (func $select (param $x i32) (result i32)
+    (return
+      (select
+        (i32.const 1)
+        (i32.const 2)
+        (i32.const 3)
+      )
+    )
+  )
+  (func $select-2 (param $x i32) (param $y i32) (result i32)
+    (return
+      (select
+        (i32.add
+          (local.get $x)
+          (local.get $y)
+        )
+        (i32.add
+          (local.get $x)
+          (i32.const 1)
+        )
+        (i32.add
+          (i32.const 2)
+          (local.get $y)
+        )
+      )
+    )
+  )
+  (func $block-phi-1 (param $x i32) (param $y i32) (result i32)
+    (block $out
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+      (br_if $out (local.get $y))
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 2)
+        )
+      )
+    )
+    (i32.add
+      (local.get $x)
+      (i32.const 3)
+    )
+  )
+  (func $block-phi-2 (param $x i32) (param $y i32) (result i32)
+    (block $out
+      (local.set $x
+        (i32.const 1)
+      )
+      (br_if $out (local.get $y))
+      (local.set $x
+        (i32.const 2)
+      )
+    )
+    (i32.add
+      (local.get $x)
+      (i32.const 3)
+    )
+  )
+  (func $zero_init-phi-bad_type (result f64)
+    (local $x f64)
+    (if
+      (i32.const 0)
+      (local.set $x
+        (f64.const 1)
+      )
+    )
+    (local.get $x)
+  )
+  (func $phi-bad-type  (result f64)
+    (block $label$1 (result f64)
+      (if (result f64)
+        (i32.const 0)
+        (f64.const 0)
+        (f64.const 1)
+      )
+    )
+  )
+  (func $phi-one-side-i1 (param $x i32) (param $y i32) (result i32)
+    (local $i i32)
+    (if
+      (i32.le_s
+        (local.get $x)
+        (local.get $y)
+      )
+      (local.set $i
+        (i32.eq
+          (local.get $x)
+          (local.get $y)
+        )
+      )
+      (local.set $i
+        (i32.add
+          (local.get $x)
+          (local.get $y)
+        )
+      )
+    )
+    (local.get $i)
+  )
+  (func $call (result i32)
+    (return
+      (i32.mul
+        (i32.add
+          (call $call)
+          (call $call)
+        )
+        (i32.add
+          (i32.const 10)
+          (call $call)
+        )
+      )
+    )
+  )
+  (func $in-unreachable-1 (param $x i32) (param $y i32) (result i32)
+    (if
+      (local.get $x)
+      (block
+        (local.set $x
+          (i32.const 1)
+        )
+        (return (local.get $x))
+      )
+      (local.set $x
+        (i32.const 2)
+      )
+    )
+    ;; no phi here!
+    (return
+      (local.get $x)
+    )
+  )
+  (func $in-unreachable-2 (param $x i32) (param $y i32) (result i32)
+    (if
+      (local.get $x)
+      (block
+        (local.set $x
+          (i32.const 1)
+        )
+        (unreachable)
+      )
+      (local.set $x
+        (i32.const 2)
+      )
+    )
+    ;; no phi here!
+    (return
+      (local.get $x)
+    )
+  )
+  (func $in-unreachable-3 (param $x i32) (param $y i32) (result i32)
+    (block $out
+      (if
+        (local.get $x)
+        (block
+          (local.set $x
+            (i32.const 1)
+          )
+          (br $out)
+        )
+        (local.set $x
+          (i32.const 2)
+        )
+      )
+      ;; no phi here!
+      (return
+        (local.get $x)
+      )
+    )
+    (return
+      (local.get $x)
+    )
+  )
+  (func $in-unreachable-4 (param $x i32) (param $y i32) (result i32)
+    (block $out
+      (if
+        (local.get $x)
+        (block
+          (local.set $x
+            (i32.const 1)
+          )
+          (br_table $out $out $out (i32.const 1))
+        )
+        (local.set $x
+          (i32.const 2)
+        )
+      )
+      ;; no phi here!
+      (return
+        (local.get $x)
+      )
+    )
+    (return
+      (local.get $x)
+    )
+  )
+  (func $in-unreachable-br_if (param $x i32) (param $y i32) (result i32)
+    (block $out
+      (if
+        (local.get $x)
+        (block
+          (local.set $x
+            (i32.const 1)
+          )
+          (br_if $out
+            (local.get $x)
+          )
+        )
+        (local.set $x
+          (i32.const 2)
+        )
+      )
+      ;; there *IS* a phi here since it was a br_if
+      (return
+        (local.get $x)
+      )
+    )
+    (return
+      (local.get $x)
+    )
+  )
+  (func $in-unreachable-big (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
+   (block $label$1
+    (block $label$2
+     (block $label$3
+      (if
+       (local.get $2)
+       (if
+        (local.get $0)
+        (block
+         (local.set $1
+          (i32.const -8531)
+         )
+         (br $label$3)
+        )
+        (block
+         (local.set $1
+          (i32.const -8531)
+         )
+         (br $label$1)
+        )
+       )
+      )
+      (br $label$2)
+     )
+     (drop
+      (i32.load
+       (i32.const 0)
+      )
+     )
+     (br $label$1)
+    )
+    (i32.store16
+     (i32.const 1)
+     (local.get $1)
+    )
+    (unreachable)
+   )
+   (i32.store16
+    (i32.const 0)
+    (i32.const -8531)
+   )
+  )
+  (func $in-unreachable-operations (param $x i32) (param $y i32) (result i32)
+    (block
+      (unreachable)
+      (if
+        (local.get $x)
+        (local.set $x
+          (i32.const 1)
+        )
+        (local.set $x
+          (i32.const 2)
+        )
+      )
+      (return
+        (local.get $x)
+      )
+    )
+  )
+  (func $merge-with-one-less (param $var$0 i32) (result i32)
+   (block $label$1
+    (block $label$2
+     (block $label$3
+      (block $label$4
+       (block $label$5
+        (br_table $label$5 $label$4 $label$3 $label$2
+         (i32.load
+          (i32.const 1)
+         )
+        )
+       )
+       (unreachable)
+      )
+      (br $label$1)
+     )
+     (f64.store
+      (i32.load
+       (local.tee $var$0
+        (i32.const 8)
+       )
+      )
+      (f64.const 0)
+     )
+     (br $label$1)
+    )
+    (unreachable)
+   )
+   (i32.store
+    (local.get $var$0)
+    (i32.const 16)
+   )
+   (i32.const 1)
+  )
+  (func $deep (param $x i32) (result i32)
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.get $x)
+  )
+  (func $two-pcs (param $x i64) (param $y i64) (param $t i64) (result i64)
+    (if
+      (i64.lt_s
+        (local.get $x)
+        (local.get $y)
+      )
+      (if
+        (i64.eqz
+          (local.get $x)
+        )
+        (local.set $t
+          (i64.add
+            (local.get $x)
+            (local.get $y)
+          )
+        )
+        (local.set $t
+          (i64.sub
+            (local.get $x)
+            (local.get $y)
+          )
+        )
+      )
+      (if
+        (i64.eqz
+          (local.get $y)
+        )
+        (local.set $t
+          (i64.mul
+            (local.get $x)
+            (local.get $y)
+          )
+        )
+        (local.set $t
+          (i64.div_s
+            (local.get $x)
+            (local.get $y)
+          )
+        )
+      )
+    )
+    (return (local.get $t))
+  )
+  (func $loop-1 (param $x i32) (param $y i32) (result i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+    )
+    ;; neither needed a phi
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-2 (param $x i32) (param $y i32) (result i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $x (i32.add (local.get $x) (i32.const 3)))
+      (local.set $y (i32.add (local.get $y) (i32.const 4)))
+    )
+    ;; neither needed a phi
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-3 (param $x i32) (param $y i32) (result i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $x (i32.add (local.get $x) (i32.const 3)))
+      (local.set $y (i32.add (local.get $y) (i32.const 4)))
+      (br_if $loopy (local.get $y))
+    )
+    ;; both needed
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-4 (param $x i32) (param $y i32) (result i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $x (i32.add (local.get $x) (i32.const 3)))
+      (br_if $loopy (local.get $y))
+    )
+    ;; only x needed a phi
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-5 (param $x i32) (param $y i32) (result i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $x (i32.add (local.get $x) (i32.const 3)))
+      (local.set $y (i32.const 2)) ;; same value
+      (br_if $loopy (local.get $y))
+    )
+    ;; only x needed a phi
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-6 (param $x i32) (param $y i32) (result i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $x (i32.add (local.get $x) (i32.const 3)))
+      (local.set $y (local.get $y)) ;; same value
+      (br_if $loopy (local.get $y))
+    )
+    ;; only x needed a phi
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-7 (param $x i32) (param $y i32) (result i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $x (i32.add (local.get $x) (i32.const 3)))
+      (local.set $y (i32.const 5)) ;; different!
+      (br_if $loopy (local.get $y))
+    )
+    ;; y changed but we don't need a phi for it
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-8 (param $x i32) (param $y i32) (result i32)
+    (local $z i32)
+    (local $w i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $z (local.get $x))
+      (local.set $w (local.get $y))
+      (local.set $x (i32.const 1)) ;; same!
+      (local.set $y (i32.const 4)) ;; different!
+      (br_if $loopy (local.get $y))
+    )
+    ;; x is always 3, and y needs a phi.
+    ;; each is also copied to another local, which we need
+    ;; to handle properly
+    (return
+      (i32.mul
+        (i32.add
+          (local.get $x)
+          (local.get $y)
+        )
+        (i32.sub
+          (local.get $z)
+          (local.get $w)
+        )
+      )
+    )
+  )
+  (func $loop-9 (param $x i32) (param $y i32) (result i32)
+    (local $t i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $t (local.get $x))
+      (local.set $x (local.get $y))
+      (local.set $y (local.get $t))
+      (br_if $loopy (local.get $t))
+    )
+    ;; x and y swapped, so both need phis
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-10 (param $x i32) (param $y i32) (result i32)
+    (local $t i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 1))
+    (loop $loopy ;; we swap the values. but we need a deeper analysis to figure that out...
+      (local.set $t (local.get $x))
+      (local.set $x (local.get $y))
+      (local.set $y (local.get $t))
+      (br_if $loopy (local.get $t))
+    )
+    ;; x and y swapped, but the same constant was swapped
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-multicond-1 (param $x i32) (param $y i32) (param $z i32) (result i32)
+    (local $t i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (local.set $z (i32.const 3))
+    (loop $loopy
+      (local.set $x (i32.const 4))
+      (br_if $loopy (local.get $t))
+      (local.set $y (i32.const 5))
+      (br_if $loopy (local.get $t))
+      (local.set $z (i32.const 6))
+    )
+    (return (select (local.get $x) (local.get $y) (local.get $z)))
+  )
+  (func $loop-multicond-2 (param $x i32) (param $y i32) (param $z i32) (result i32)
+    (local $t i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (local.set $z (i32.const 3))
+    (loop $loopy
+      (local.set $x (i32.add (local.get $x) (i32.const 4)))
+      (br_if $loopy (local.get $t))
+      (local.set $y (i32.add (local.get $y) (i32.const 5)))
+      (br_if $loopy (local.get $t))
+      (local.set $z (i32.add (local.get $z) (i32.const 6)))
+    )
+    (return (select (local.get $x) (local.get $y) (local.get $z)))
+  )
+  (func $loop-block-1 (param $x i32) (param $y i32) (param $z i32) (result i32)
+    (local $t i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (local.set $z (i32.const 3))
+    (loop $loopy
+      (block $out
+        (local.set $x (i32.add (local.get $x) (i32.const 4)))
+        (br_if $out (local.get $t))
+        (local.set $y (i32.add (local.get $y) (i32.const 5)))
+        (br_if $out (local.get $t))
+        (local.set $z (i32.add (local.get $z) (i32.const 6)))
+        (br $loopy)
+      )
+    )
+    (return (select (local.get $x) (local.get $y) (local.get $z)))
+  )
+  (func $loop-block-2 (param $x i32) (param $y i32) (param $z i32) (result i32)
+    (local $t i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (local.set $z (i32.const 3))
+    (block $out
+      (loop $loopy
+        (local.set $x (i32.add (local.get $x) (i32.const 4)))
+        (br_if $out (local.get $t))
+        (local.set $y (i32.add (local.get $y) (i32.const 5)))
+        (br_if $out (local.get $t))
+        (local.set $z (i32.add (local.get $z) (i32.const 6)))
+        (br $loopy)
+      )
+    )
+    (return (select (local.get $x) (local.get $y) (local.get $z)))
+  )
+  (func $bad-phi-type (param $var$0 i64) (param $var$1 i64) (param $var$2 i32) (param $var$3 f32)
+   (if
+    (local.get $var$2)
+    (drop
+     (loop $label$2 (result f64)
+      (if
+       (block $label$3 (result i32)
+        (if
+         (i32.const 0)
+         (unreachable)
+        )
+        (nop)
+        (i32.const 0)
+       )
+       (unreachable)
+      )
+      (br_if $label$2
+       (local.get $var$2)
+      )
+      (f64.const 0)
+     )
+    )
+   )
+  )
+  (func $loop-unreachable
+   (local $var$0 i32)
+   (local $var$1 f64)
+   (loop $label$1
+    (local.set $var$1
+     (block $label$2 (result f64)
+      (block $label$3
+       (local.set $var$0
+        (block $label$4 (result i32)
+         (if
+          (i32.const 1337)
+          (unreachable)
+         )
+         (local.get $var$0)
+        )
+       )
+       (loop $label$6
+        (br_if $label$6
+         (block $label$7 (result i32)
+          (drop
+           (br_if $label$7
+            (local.get $var$0)
+            (i32.const 65535)
+           )
+          )
+          (drop
+           (br_if $label$7
+            (local.get $var$0)
+            (i32.const 0)
+           )
+          )
+          (unreachable)
+         )
+        )
+       )
+      )
+      (local.get $var$1)
+     )
+    )
+    (br $label$1)
+   )
+  )
+  (func $phi-value-turns-bad (result f64)
+   (local $var$0 i32)
+   (local $var$1 i32)
+   (local $var$2 f32)
+   (local.set $var$2
+    (if (result f32)
+     (local.tee $var$0
+      (i32.atomic.rmw16.sub_u offset=22
+       (i32.const 0)
+       (i32.const 0)
+      )
+     )
+     (unreachable)
+     (block (result f32)
+      (if
+       (loop $label$3 (result i32)
+        (block $label$4 (result i32)
+         (i32.clz
+          (br_if $label$4
+           (local.get $var$0)
+           (i32.const 1)
+          )
+         )
+        )
+       )
+       (nop)
+      )
+      (f32.const 1)
+     )
+    )
+   )
+   (unreachable)
+  )
+  (func $multi-use (param $x i32) (result i32)
+    (local $temp i32)
+    (local.set $temp (i32.add (local.get $x) (i32.const 1)))
+    (i32.add (local.get $temp) (local.get $temp))
+  )
+  (func $multi-use-2 (param $x i32) (result i32)
+    (local $temp i32)
+    (local.set $temp (i32.add (local.get $x) (i32.const 1)))
+    (local.set $x (i32.mul (local.get $temp) (i32.const 2)))
+    (i32.sub (local.get $x) (local.get $temp))
+  )
+  (func $many-single-uses-with-param (param $x i32) (result i32)
+    (return
+      (i32.eqz
+        (i32.add
+          (i32.mul
+            (i32.const 10)
+            (local.get $x)
+          )
+          (i32.sub
+            (i32.ctz
+              (local.get $x)
+            )
+            (i32.const 20)
+          )
+        )
+      )
+    )
+  )
+ (func "replaced-print-internal" (param $var$0 i32)
+  (local $var$1 i32)
+  (local $var$2 i32)
+  (local $var$3 i32)
+  (if
+   (local.tee $var$0
+    (i32.add
+     (local.get $var$0)
+     (i32.const -7)
+    )
+   )
+   (block $label$2
+    (block $label$3
+     (local.set $var$1
+      (local.get $var$0)
+     )
+     (br_if $label$3
+      (local.tee $var$3
+       (i32.const 12)
+      )
+     )
+     (unreachable)
+    )
+    (br_if $label$2
+     (i32.eqz
+      (local.get $var$1)
+     )
+    )
+    (if
+     (i32.ne
+      (i32.load
+       (i32.const 0)
+      )
+      (local.get $var$0)
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+ )
+ (func $multiple-uses-to-non-expression (param $x i32)
+  (local $temp i32)
+  (local.set $x
+   (i32.add
+    (local.get $x)
+    (i32.const 10)
+   )
+  )
+  (i32.store
+   (i32.const 1)
+   (local.get $x) ;; x+10 has two uses!
+  )
+  (i32.store
+   (i32.const 2)
+   (i32.add
+    (local.get $x)
+    (i32.const 20)
+   )
+  )
+ )
+ (func $nested-phi-forwarding (param $var$0 i32) (result i32)
+  (local $var$1 i32)
+  (local $var$2 i32)
+  (block $label$1
+   (block $label$2
+    (loop $label$3
+     (block $label$4
+      (block $label$5
+       (block $label$6
+        (block $label$7
+         (block $label$8
+          (br_table $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$8 $label$2 $label$2 $label$2 $label$6 $label$2 $label$2 $label$7 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$5 $label$4
+           (local.get $var$0)
+          )
+         )
+         (local.set $var$1
+          (i32.const 1)
+         )
+        )
+        (br $label$4)
+       )
+       (unreachable)
+      )
+      (br $label$1)
+     )
+     (br_if $label$3
+      (local.tee $var$2
+       (i32.const 1)
+      )
+     )
+    )
+   )
+   (block $label$9
+    (br_if $label$9
+     (i32.or
+      (i32.const 1)
+      (local.get $var$1)
+     )
+    )
+   )
+   (unreachable)
+  )
+  (i32.store offset=176
+   (i32.const 0)
+   (local.get $var$2)
+  )
+  (i32.const 0)
+ )
+ (func $zext-numGets (param $var$0 i32) (param $var$1 i32)
+  (if
+   (i32.ctz
+    (block $label$1 (result i32)
+     (drop
+      (br_if $label$1
+       (i32.const 1)
+       (i32.load
+        (i32.const -8)
+       )
+      )
+     )
+     (i32.eqz
+      (i32.load
+       (i32.const -16)
+      )
+     )
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $zext-numGets-hasAnotherUse (param $var$0 i32) (param $var$1 i32)
+  (local $temp i32)
+  (if
+   (i32.ctz
+    (block $label$1 (result i32)
+     (drop
+      (br_if $label$1
+       (i32.const 1)
+       (i32.load
+        (i32.const -8)
+       )
+      )
+     )
+     (local.set $temp
+      (i32.eqz
+       (i32.load
+        (i32.const -16)
+       )
+      )
+     )
+     (drop
+      (local.get $temp)
+     )
+     (local.get $temp)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $flipped-needs-right-origin (param $var$0 i32) (result i32)
+  (local $var$1 i32)
+  (block $label$1
+   (br_if $label$1
+    (i32.load
+     (i32.const 1)
+    )
+   )
+   (local.set $var$1
+    (i32.const 2)
+   )
+  )
+  (if
+   (i32.gt_s
+    (i32.const 3)
+    (i32.add
+     (local.get $var$1)
+     (i32.const 4)
+    )
+   )
+   (unreachable)
+  )
+  (i32.const 5)
+ )
+ (func $non-expr-nodes-may-have-multiple-uses-too-its-the-ORIGIN (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (result i32)
+  (i32.store
+   (local.tee $var$1
+    (i32.gt_u
+     (local.get $var$1)
+     (i32.const 1)
+    )
+   )
+   (i32.const 2)
+  )
+  (i32.store offset=8
+   (i32.const 3)
+   (i32.sub
+    (i32.const 4)
+    (local.get $var$1)
+   )
+  )
+  (unreachable)
+ )
+ (func $loop-of-set-connections (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (param $var$3 i32) (param $var$4 i32) (result i32)
+  (loop $label$1
+   (if
+    (i32.const 0)
+    (block
+     (local.set $var$2
+      (i32.add
+       (i32.const 0)
+       (i32.const 1)
+      )
+     )
+     (br $label$1)
+    )
+   )
+   (local.set $var$3
+    (local.get $var$2)
+   )
+   (local.set $var$2
+    (local.get $var$3)
+   )
+   (br $label$1)
+  )
+ )
+ (func $conditions-in-conditions (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (result i32)
+  (local $var$3 i32)
+  (local $var$4 i32)
+  (local $var$5 i32)
+  (local $var$6 i32)
+  (local $var$7 i32)
+  (local $var$8 i32)
+  (local.set $var$1
+   (i32.const 1)
+  )
+  (if
+   (i32.const 0)
+   (loop $label$2
+    (if
+     (local.get $var$1)
+     (nop)
+    )
+    (local.set $var$1
+     (i32.sub
+      (i32.const 0)
+      (local.tee $var$3
+       (i32.const 1)
+      )
+     )
+    )
+    (br_if $label$2
+     (i32.const 0)
+    )
+   )
+  )
+  (if
+   (local.get $var$1)
+   (local.set $var$3
+    (i32.const 1)
+   )
+  )
+  (i32.store
+   (i32.const 8)
+   (i32.add
+    (local.get $var$3)
+    (i32.const 16)
+   )
+  )
+  (i32.store
+   (i32.const 8)
+   (i32.const 64)
+  )
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/passes/flatten_simplify-locals-nonesting_souperify_enable-threads.txt b/binaryen/test/passes/flatten_simplify-locals-nonesting_souperify_enable-threads.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_simplify-locals-nonesting_souperify_enable-threads.txt
@@ -0,0 +1,4877 @@
+
+; function: figure-1a
+
+; start LHS (in figure-1a)
+%0:i64 = var
+%1:i64 = var
+%2 = eq %0, %1
+infer %2
+
+
+; start LHS (in figure-1a)
+%0:i64 = var
+%1:i64 = var
+%2 = ne %0, %1
+infer %2
+
+
+; start LHS (in figure-1a)
+%0:i64 = var
+%1:i64 = var
+%2 = eq %0, %1
+%3:i32 = zext %2
+%4:i64 = var
+%5 = ne %0, %4
+%6:i32 = zext %5
+%7 = and %3, %6
+infer %7
+
+
+; function: figure-1b
+
+; start LHS (in figure-1b)
+%0:i64 = var
+%1:i64 = var
+%2 = slt %0, %1
+infer %2
+
+
+; start LHS (in figure-1b)
+%0:i64 = var
+%1:i64 = var
+%2 = eq %0, %1
+%3:i64 = var
+%4 = slt %1, %3
+pc %4 1:i1
+infer %2
+
+
+; start LHS (in figure-1b)
+%0:i64 = var
+%1:i64 = var
+%2 = ne %0, %1
+%3:i64 = var
+%4 = slt %3, %1
+pc %4 1:i1
+infer %2
+
+
+; start LHS (in figure-1b)
+%0:i64 = var
+%1:i64 = var
+%2 = eq %0, %1
+%3:i32 = zext %2
+%4:i64 = var
+%5 = ne %0, %4
+%6:i32 = zext %5
+%7 = and %3, %6
+%8 = slt %1, %4
+pc %8 1:i1
+infer %7
+
+
+; function: figure-3-if
+
+; start LHS (in figure-3-if)
+%0:i32 = var
+%1 = and %0, 1:i32
+infer %1
+
+
+; start LHS (in figure-3-if)
+%0:i32 = var
+%1 = add %0, 1:i32
+%2 = and %0, 1:i32
+%3 = ne %2, 0:i32
+pc %3 1:i1
+infer %1
+
+
+; start LHS (in figure-3-if)
+%0:i32 = var
+%1 = add %0, 2:i32
+%2 = and %0, 1:i32
+%3 = eq %2, 0:i32
+pc %3 1:i1
+infer %1
+
+
+; start LHS (in figure-3-if)
+%0 = block 2
+%1:i32 = var
+%2 = add %1, 1:i32
+%3 = add %1, 2:i32
+%4 = phi %0, %2, %3
+%5 = and %4, 1:i32
+%6 = and %1, 1:i32
+%7 = ne %6, 0:i32
+blockpc %0 0 %7 1:i1
+%8 = eq %6, 0:i32
+blockpc %0 1 %8 1:i1
+infer %5
+
+
+; function: send-i32
+
+; function: flips
+
+; start LHS (in flips)
+%0 = sle 0:i32, 0:i32
+infer %0
+
+
+; start LHS (in flips)
+%0 = sle 0:i32, 0:i32
+%1:i32 = zext %0
+%2 = ule 0:i32, %1
+infer %2
+
+
+; start LHS (in flips)
+%0 = sle 0:i32, 0:i32
+%1:i32 = zext %0
+%2 = ule 0:i32, %1
+%3:i32 = zext %2
+%4 = slt 0:i32, %3
+infer %4
+
+
+; start LHS (in flips)
+%0 = sle 0:i32, 0:i32
+%1:i32 = zext %0
+%2 = ule 0:i32, %1
+%3:i32 = zext %2
+%4 = slt 0:i32, %3
+%5:i32 = zext %4
+%6 = ult 0:i32, %5
+infer %6
+
+
+; start LHS (in flips)
+%0 = sle 0:i64, 0:i64
+infer %0
+
+
+; start LHS (in flips)
+%0 = ule 0:i64, 0:i64
+infer %0
+
+
+; start LHS (in flips)
+%0 = slt 0:i64, 0:i64
+infer %0
+
+
+; start LHS (in flips)
+%0 = ult 0:i64, 0:i64
+infer %0
+
+
+; function: various-conditions-1
+
+; start LHS (in various-conditions-1)
+%0:i32 = var
+%1 = add %0, 1:i32
+%2 = ne %0, 0:i32
+pc %2 1:i1
+infer %1
+
+
+; function: various-conditions-2
+
+; start LHS (in various-conditions-2)
+%0:i32 = var
+%1 = slt %0, 0:i32
+infer %1
+
+
+; start LHS (in various-conditions-2)
+%0:i32 = var
+%1 = sub %0, 2:i32
+%2 = slt %0, 0:i32
+pc %2 1:i1
+infer %1
+
+
+; function: various-conditions-3
+
+; start LHS (in various-conditions-3)
+%0:i32 = var
+%1 = sub %0, 4:i32
+%2:i32 = var
+%3 = ne %2, 0:i32
+pc %3 1:i1
+infer %1
+
+
+; function: various-conditions-4
+
+; function: unaries
+
+; start LHS (in unaries)
+%0:i32 = var
+%1 = eq %0, 0:i32
+infer %1
+
+
+; start LHS (in unaries)
+%0:i32 = var
+%1 = cttz %0
+%2:i32 = var
+%3 = eq %2, 0:i32
+pc %3 1:i1
+infer %1
+
+
+; start LHS (in unaries)
+%0:i32 = var
+%1 = ctlz %0
+%2 = eq %0, 0:i32
+pc %2 1:i1
+infer %1
+
+
+; start LHS (in unaries)
+%0:i32 = var
+%1 = ctpop %0
+%2:i32 = var
+%3 = eq %2, 0:i32
+pc %3 1:i1
+infer %1
+
+
+; start LHS (in unaries)
+%0:i32 = var
+%1 = ctlz %0
+%2:i32 = var
+%3 = ctpop %2
+%4 = sub %1, %3
+%5 = eq %0, 0:i32
+pc %5 1:i1
+infer %4
+
+
+; start LHS (in unaries)
+%0:i32 = var
+%1 = cttz %0
+%2:i32 = var
+%3 = ctlz %2
+%4 = ctpop %0
+%5 = sub %3, %4
+%6 = add %1, %5
+%7 = eq %2, 0:i32
+pc %7 1:i1
+infer %6
+
+
+; function: unary-condition
+
+; start LHS (in unary-condition)
+%0:i32 = var
+%1 = ult 1:i32, %0
+infer %1
+
+
+; start LHS (in unary-condition)
+%0:i32 = var
+%1 = ult 1:i32, %0
+%2:i32 = zext %1
+%3 = cttz %2
+infer %3
+
+
+; start LHS (in unary-condition)
+%0:i32 = var
+%1 = add %0, 2:i32
+%2 = ult 1:i32, %0
+%3:i32 = zext %2
+%4 = cttz %3
+%5 = ne %4, 0:i32
+pc %5 1:i1
+infer %1
+
+
+; function: unary-condition-2
+
+; start LHS (in unary-condition-2)
+%0:i32 = var
+%1 = ult 1:i32, %0
+infer %1
+
+
+; start LHS (in unary-condition-2)
+%0:i32 = var
+%1 = ult 1:i32, %0
+%2:i32 = zext %1
+%3 = eq %2, 0:i32
+infer %3
+
+
+; start LHS (in unary-condition-2)
+%0:i32 = var
+%1 = add %0, 2:i32
+%2 = ult 1:i32, %0
+%3:i32 = zext %2
+%4 = eq %3, 0:i32
+pc %4 1:i1
+infer %1
+
+
+; function: if-else-cond
+
+; start LHS (in if-else-cond)
+%0:i32 = var
+%1 = slt %0, 1:i32
+infer %1
+
+
+; start LHS (in if-else-cond)
+%0:i32 = var
+%1 = add %0, 1:i32
+%2 = slt %0, 1:i32
+pc %2 1:i1
+infer %1
+
+
+; start LHS (in if-else-cond)
+%0:i32 = var
+%1 = add %0, 2:i32
+%2 = slt %0, 1:i32
+%3:i32 = zext %2
+%4 = eq %3, 0:i32
+pc %4 1:i1
+infer %1
+
+
+; start LHS (in if-else-cond)
+%0 = block 2
+%1:i32 = var
+%2 = add %1, 1:i32
+%3 = add %1, 2:i32
+%4 = phi %0, %2, %3
+%5 = and %4, 1:i32
+%6 = slt %1, 1:i32
+blockpc %0 0 %6 1:i1
+%7:i32 = zext %6
+%8 = eq %7, 0:i32
+blockpc %0 1 %8 1:i1
+infer %5
+
+
+; function: trivial-ret
+
+; start LHS (in trivial-ret)
+%0 = add 0:i32, 1:i32
+infer %0
+
+
+; function: trivial-const
+
+; function: trivial-const-block
+
+; function: bad-phi-value
+
+; function: bad-phi-value-2
+
+; function: select
+
+; start LHS (in select)
+%0 = ne 3:i32, 0:i32
+infer %0
+
+
+; start LHS (in select)
+%0 = ne 3:i32, 0:i32
+%1 = select %0, 1:i32, 2:i32
+infer %1
+
+
+; function: select-2
+
+; start LHS (in select-2)
+%0:i32 = var
+%1:i32 = var
+%2 = add %0, %1
+infer %2
+
+
+; start LHS (in select-2)
+%0:i32 = var
+%1 = add %0, 1:i32
+infer %1
+
+
+; start LHS (in select-2)
+%0:i32 = var
+%1 = add 2:i32, %0
+infer %1
+
+
+; start LHS (in select-2)
+%0:i32 = var
+%1 = add 2:i32, %0
+%2 = ne %1, 0:i32
+infer %2
+
+
+; start LHS (in select-2)
+%0:i32 = var
+%1 = add 2:i32, %0
+%2 = ne %1, 0:i32
+%3:i32 = var
+%4 = add %3, %0
+%5 = add %3, 1:i32
+%6 = select %2, %4, %5
+infer %6
+
+
+; function: block-phi-1
+
+; start LHS (in block-phi-1)
+%0:i32 = var
+%1 = add %0, 1:i32
+infer %1
+
+
+; start LHS (in block-phi-1)
+%0:i32 = var
+%1 = add %0, 1:i32 (hasExternalUses)
+%2 = add %1, 2:i32
+infer %2
+
+
+; start LHS (in block-phi-1)
+%0 = block 2
+%1:i32 = var
+%2 = add %1, 1:i32
+%3 = add %2, 2:i32
+%4 = phi %0, %2, %3
+%5 = add %4, 3:i32
+infer %5
+
+
+; function: block-phi-2
+
+; start LHS (in block-phi-2)
+%0 = block 2
+%1 = phi %0, 1:i32, 2:i32
+%2 = add %1, 3:i32
+infer %2
+
+
+; function: zero_init-phi-bad_type
+
+; function: phi-bad-type
+
+; function: phi-one-side-i1
+
+; start LHS (in phi-one-side-i1)
+%0:i32 = var
+%1:i32 = var
+%2 = sle %0, %1
+infer %2
+
+
+; start LHS (in phi-one-side-i1)
+%0:i32 = var
+%1:i32 = var
+%2 = eq %0, %1
+%3 = sle %0, %1
+pc %3 1:i1
+infer %2
+
+
+; start LHS (in phi-one-side-i1)
+%0:i32 = var
+%1:i32 = var
+%2 = add %0, %1
+%3 = sle %0, %1
+%4:i32 = zext %3
+%5 = eq %4, 0:i32
+pc %5 1:i1
+infer %2
+
+
+; function: call
+
+; start LHS (in call)
+%0:i32 = var
+%1:i32 = var
+%2 = add %0, %1
+infer %2
+
+
+; start LHS (in call)
+%0:i32 = var
+%1 = add 10:i32, %0
+infer %1
+
+
+; start LHS (in call)
+%0:i32 = var
+%1:i32 = var
+%2 = add %0, %1
+%3:i32 = var
+%4 = add 10:i32, %3
+%5 = mul %2, %4
+infer %5
+
+
+; function: in-unreachable-1
+
+; function: in-unreachable-2
+
+; function: in-unreachable-3
+
+; function: in-unreachable-4
+
+; function: in-unreachable-br_if
+
+; function: in-unreachable-big
+
+; function: in-unreachable-operations
+
+; function: merge-with-one-less
+
+; function: deep
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+infer %1
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+infer %2
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+infer %3
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+infer %4
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+infer %5
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+infer %6
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+infer %7
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+infer %8
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = xor %0, 1234:i32
+%2 = mul %1, 1234:i32
+%3 = xor %2, 1234:i32
+%4 = mul %3, 1234:i32
+%5 = xor %4, 1234:i32
+%6 = mul %5, 1234:i32
+%7 = xor %6, 1234:i32
+%8 = mul %7, 1234:i32
+%9 = xor %8, 1234:i32
+infer %9
+
+
+; start LHS (in deep)
+%0:i32 = var
+%1 = mul %0, 1234:i32
+%2 = xor %1, 1234:i32
+%3 = mul %2, 1234:i32
+%4 = xor %3, 1234:i32
+%5 = mul %4, 1234:i32
+%6 = xor %5, 1234:i32
+%7 = mul %6, 1234:i32
+%8 = xor %7, 1234:i32
+%9 = mul %8, 1234:i32
+infer %9
+
+
+; function: two-pcs
+
+; start LHS (in two-pcs)
+%0:i64 = var
+%1:i64 = var
+%2 = slt %0, %1
+infer %2
+
+
+; start LHS (in two-pcs)
+%0:i64 = var
+%1 = eq %0, 0:i64
+%2:i64 = var
+%3 = slt %0, %2
+pc %3 1:i1
+infer %1
+
+
+; start LHS (in two-pcs)
+%0:i64 = var
+%1:i64 = var
+%2 = add %0, %1
+%3 = eq %0, 0:i64
+%4 = slt %0, %1
+pc %3 1:i1
+pc %4 1:i1
+infer %2
+
+
+; start LHS (in two-pcs)
+%0:i64 = var
+%1:i64 = var
+%2 = sub %0, %1
+%3 = eq %0, 0:i64
+%4:i32 = zext %3
+%5 = eq %4, 0:i32
+%6 = slt %0, %1
+pc %5 1:i1
+pc %6 1:i1
+infer %2
+
+
+; start LHS (in two-pcs)
+%0:i64 = var
+%1 = eq %0, 0:i64
+%2:i64 = var
+%3 = slt %2, %0
+%4:i32 = zext %3
+%5 = eq %4, 0:i32
+pc %5 1:i1
+infer %1
+
+
+; start LHS (in two-pcs)
+%0:i64 = var
+%1:i64 = var
+%2 = mul %0, %1
+%3 = eq %1, 0:i64
+%4 = slt %0, %1
+%5:i32 = zext %4
+%6 = eq %5, 0:i32
+pc %3 1:i1
+pc %6 1:i1
+infer %2
+
+
+; start LHS (in two-pcs)
+%0:i64 = var
+%1:i64 = var
+%2 = sdiv %0, %1
+%3 = eq %1, 0:i64
+%4:i32 = zext %3
+%5 = eq %4, 0:i32
+%6 = slt %0, %1
+%7:i32 = zext %6
+%8 = eq %7, 0:i32
+pc %5 1:i1
+pc %8 1:i1
+infer %2
+
+
+; function: loop-1
+
+; start LHS (in loop-1)
+%0 = add 1:i32, 2:i32
+infer %0
+
+
+; function: loop-2
+
+; start LHS (in loop-2)
+%0 = add 1:i32, 3:i32
+infer %0
+
+
+; start LHS (in loop-2)
+%0 = add 2:i32, 4:i32
+infer %0
+
+
+; start LHS (in loop-2)
+%0 = add 1:i32, 3:i32
+%1 = add 2:i32, 4:i32
+%2 = add %0, %1
+infer %2
+
+
+; function: loop-3
+
+; start LHS (in loop-3)
+%0:i32 = var
+%1 = add %0, 3:i32
+infer %1
+
+
+; start LHS (in loop-3)
+%0:i32 = var
+%1 = add %0, 4:i32
+infer %1
+
+
+; start LHS (in loop-3)
+%0:i32 = var
+%1 = add %0, 3:i32
+%2:i32 = var
+%3 = add %2, 4:i32 (hasExternalUses)
+%4 = add %1, %3
+infer %4
+
+
+; function: loop-4
+
+; start LHS (in loop-4)
+%0:i32 = var
+%1 = add %0, 3:i32
+infer %1
+
+
+; start LHS (in loop-4)
+%0:i32 = var
+%1 = add %0, 3:i32
+%2 = add %1, 2:i32
+infer %2
+
+
+; function: loop-5
+
+; start LHS (in loop-5)
+%0:i32 = var
+%1 = add %0, 3:i32
+infer %1
+
+
+; start LHS (in loop-5)
+%0:i32 = var
+%1 = add %0, 3:i32
+%2 = add %1, 2:i32
+infer %2
+
+
+; function: loop-6
+
+; start LHS (in loop-6)
+%0:i32 = var
+%1 = add %0, 3:i32
+infer %1
+
+
+; start LHS (in loop-6)
+%0:i32 = var
+%1 = add %0, 3:i32
+%2 = add %1, 2:i32
+infer %2
+
+
+; function: loop-7
+
+; start LHS (in loop-7)
+%0:i32 = var
+%1 = add %0, 3:i32
+infer %1
+
+
+; start LHS (in loop-7)
+%0:i32 = var
+%1 = add %0, 3:i32
+%2 = add %1, 5:i32
+infer %2
+
+
+; function: loop-8
+
+; start LHS (in loop-8)
+%0 = add 1:i32, 4:i32
+infer %0
+
+
+; start LHS (in loop-8)
+%0:i32 = var
+%1 = sub 1:i32, %0
+infer %1
+
+
+; start LHS (in loop-8)
+%0 = add 1:i32, 4:i32
+%1:i32 = var
+%2 = sub 1:i32, %1
+%3 = mul %0, %2
+infer %3
+
+
+; function: loop-9
+
+; start LHS (in loop-9)
+%0:i32 = var
+%1:i32 = var
+%2 = add %0, %1
+infer %2
+
+
+; function: loop-10
+
+; start LHS (in loop-10)
+%0:i32 = var
+%1:i32 = var
+%2 = add %0, %1
+infer %2
+
+
+; function: loop-multicond-1
+
+; start LHS (in loop-multicond-1)
+%0 = ne 6:i32, 0:i32
+infer %0
+
+
+; start LHS (in loop-multicond-1)
+%0 = ne 6:i32, 0:i32
+%1 = select %0, 4:i32, 5:i32
+infer %1
+
+
+; function: loop-multicond-2
+
+; start LHS (in loop-multicond-2)
+%0:i32 = var
+%1 = add %0, 4:i32
+infer %1
+
+
+; start LHS (in loop-multicond-2)
+%0:i32 = var
+%1 = add %0, 5:i32
+infer %1
+
+
+; start LHS (in loop-multicond-2)
+%0 = add 3:i32, 6:i32
+infer %0
+
+
+; start LHS (in loop-multicond-2)
+%0 = add 3:i32, 6:i32
+%1 = ne %0, 0:i32
+infer %1
+
+
+; start LHS (in loop-multicond-2)
+%0 = add 3:i32, 6:i32
+%1 = ne %0, 0:i32
+%2:i32 = var
+%3 = add %2, 4:i32
+%4:i32 = var
+%5 = add %4, 5:i32
+%6 = select %1, %3, %5
+infer %6
+
+
+; function: loop-block-1
+
+; start LHS (in loop-block-1)
+%0:i32 = var
+%1 = add %0, 4:i32
+infer %1
+
+
+; start LHS (in loop-block-1)
+%0:i32 = var
+%1 = add %0, 5:i32
+infer %1
+
+
+; start LHS (in loop-block-1)
+%0:i32 = var
+%1 = add %0, 6:i32
+infer %1
+
+
+; start LHS (in loop-block-1)
+%0:i32 = var
+%1 = ne %0, 0:i32
+infer %1
+
+
+; start LHS (in loop-block-1)
+%0:i32 = var
+%1 = ne %0, 0:i32
+%2:i32 = var
+%3 = add %2, 4:i32
+%4 = block 2
+%5:i32 = var
+%6 = add %5, 5:i32
+%7 = phi %4, %5, %6
+%8 = select %1, %3, %7
+infer %8
+
+
+; function: loop-block-2
+
+; start LHS (in loop-block-2)
+%0:i32 = var
+%1 = add %0, 4:i32
+infer %1
+
+
+; start LHS (in loop-block-2)
+%0:i32 = var
+%1 = add %0, 5:i32
+infer %1
+
+
+; start LHS (in loop-block-2)
+%0:i32 = var
+%1 = add %0, 6:i32
+infer %1
+
+
+; start LHS (in loop-block-2)
+%0:i32 = var
+%1 = ne %0, 0:i32
+infer %1
+
+
+; start LHS (in loop-block-2)
+%0:i32 = var
+%1 = ne %0, 0:i32
+%2:i32 = var
+%3 = add %2, 4:i32
+%4 = block 2
+%5:i32 = var
+%6 = add %5, 5:i32
+%7 = phi %4, %5, %6
+%8 = select %1, %3, %7
+infer %8
+
+
+; function: bad-phi-type
+
+; function: loop-unreachable
+
+; function: phi-value-turns-bad
+
+; start LHS (in phi-value-turns-bad)
+%0:i32 = var
+%1 = ctlz %0
+%2 = eq %0, 0:i32
+pc %2 1:i1
+infer %1
+
+
+; function: multi-use
+
+; start LHS (in multi-use)
+%0:i32 = var
+%1 = add %0, 1:i32
+infer %1
+
+
+; start LHS (in multi-use)
+%0:i32 = var
+%1 = add %0, 1:i32
+%2 = add %1, %1
+infer %2
+
+
+; function: multi-use-2
+
+; start LHS (in multi-use-2)
+%0:i32 = var
+%1 = add %0, 1:i32
+infer %1
+
+
+; start LHS (in multi-use-2)
+%0:i32 = var
+%1 = add %0, 1:i32 (hasExternalUses)
+%2 = mul %1, 2:i32
+infer %2
+
+
+; start LHS (in multi-use-2)
+%0:i32 = var
+%1 = add %0, 1:i32
+%2 = mul %1, 2:i32
+%3 = sub %2, %1
+infer %3
+
+
+; function: many-single-uses-with-param
+
+; start LHS (in many-single-uses-with-param)
+%0:i32 = var
+%1 = mul 10:i32, %0
+infer %1
+
+
+; start LHS (in many-single-uses-with-param)
+%0:i32 = var
+%1 = cttz %0
+infer %1
+
+
+; start LHS (in many-single-uses-with-param)
+%0:i32 = var
+%1 = cttz %0
+%2 = sub %1, 20:i32
+infer %2
+
+
+; start LHS (in many-single-uses-with-param)
+%0:i32 = var
+%1 = mul 10:i32, %0
+%2 = cttz %0
+%3 = sub %2, 20:i32
+%4 = add %1, %3
+infer %4
+
+
+; start LHS (in many-single-uses-with-param)
+%0:i32 = var
+%1 = mul 10:i32, %0
+%2 = cttz %0
+%3 = sub %2, 20:i32
+%4 = add %1, %3
+%5 = eq %4, 0:i32
+infer %5
+
+
+; function: 56
+
+; start LHS (in 56)
+%0:i32 = var
+%1 = add %0, -7:i32
+infer %1
+
+
+; start LHS (in 56)
+%0:i32 = var
+%1 = add %0, -7:i32 (hasExternalUses)
+%2 = eq %1, 0:i32
+%3 = ne %1, 0:i32
+pc %3 1:i1
+infer %2
+
+
+; start LHS (in 56)
+%0:i32 = var
+%1:i32 = var
+%2 = add %1, -7:i32 (hasExternalUses)
+%3 = ne %0, %2
+%4 = ne %2, 0:i32
+pc %4 1:i1
+infer %3
+
+
+; function: multiple-uses-to-non-expression
+
+; start LHS (in multiple-uses-to-non-expression)
+%0:i32 = var
+%1 = add %0, 10:i32
+infer %1
+
+
+; start LHS (in multiple-uses-to-non-expression)
+%0:i32 = var
+%1 = add %0, 10:i32 (hasExternalUses)
+%2 = add %1, 20:i32
+infer %2
+
+
+; function: nested-phi-forwarding
+
+; start LHS (in nested-phi-forwarding)
+%0 = block 2
+%1:i32 = var
+%2 = block 2
+%3 = block 2
+%4 = phi %3, %1, 1:i32
+%5 = phi %2, %1, %4
+%6 = phi %0, %1, %5
+%7 = or 1:i32, %6
+infer %7
+
+
+; function: zext-numGets
+
+; start LHS (in zext-numGets)
+%0:i32 = var
+%1 = eq %0, 0:i32
+infer %1
+
+
+; start LHS (in zext-numGets)
+%0 = block 2
+%1:i32 = var
+%2 = eq %1, 0:i32
+%3:i32 = zext %2
+%4 = phi %0, 1:i32, %3
+%5 = cttz %4
+infer %5
+
+
+; function: zext-numGets-hasAnotherUse
+
+; start LHS (in zext-numGets-hasAnotherUse)
+%0:i32 = var
+%1 = eq %0, 0:i32
+infer %1
+
+
+; start LHS (in zext-numGets-hasAnotherUse)
+%0 = block 2
+%1:i32 = var
+%2 = eq %1, 0:i32
+%3:i32 = zext %2
+%4 = phi %0, 1:i32, %3
+%5 = cttz %4
+infer %5
+
+
+; function: flipped-needs-right-origin
+
+; start LHS (in flipped-needs-right-origin)
+%0 = block 2
+%1 = phi %0, 0:i32, 2:i32
+%2 = add %1, 4:i32
+infer %2
+
+
+; start LHS (in flipped-needs-right-origin)
+%0 = block 2
+%1 = phi %0, 0:i32, 2:i32
+%2 = add %1, 4:i32
+%3 = slt %2, 3:i32
+infer %3
+
+
+; function: non-expr-nodes-may-have-multiple-uses-too-its-the-ORIGIN
+
+; start LHS (in non-expr-nodes-may-have-multiple-uses-too-its-the-ORIGIN)
+%0:i32 = var
+%1 = ult 1:i32, %0
+infer %1
+
+
+; start LHS (in non-expr-nodes-may-have-multiple-uses-too-its-the-ORIGIN)
+%0:i32 = var
+%1 = ult 1:i32, %0 (hasExternalUses)
+%2:i32 = zext %1
+%3 = sub 4:i32, %2
+infer %3
+
+
+; function: loop-of-set-connections
+
+; start LHS (in loop-of-set-connections)
+%0 = add 0:i32, 1:i32
+%1 = ne 0:i32, 0:i32
+pc %1 1:i1
+infer %0
+
+
+; function: conditions-in-conditions
+
+; start LHS (in conditions-in-conditions)
+%0 = sub 0:i32, 1:i32
+%1 = ne 0:i32, 0:i32
+pc %1 1:i1
+infer %0
+
+
+; start LHS (in conditions-in-conditions)
+%0 = block 2
+%1 = block 2
+%2 = phi %1, 0:i32, 1:i32
+%3 = phi %0, %2, 1:i32
+%4 = add %3, 16:i32
+%5 = ne 0:i32, 0:i32
+blockpc %1 0 %5 1:i1
+%6 = eq 0:i32, 0:i32
+blockpc %1 1 %6 1:i1
+%7 = sub 0:i32, 1:i32
+%8 = phi %1, 1:i32, %7
+%9 = ne %8, 0:i32
+blockpc %0 0 %9 1:i1
+%10 = eq %8, 0:i32
+blockpc %0 1 %10 1:i1
+infer %4
+
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $none_=>_f64 (func (result f64)))
+ (type $none_=>_none (func))
+ (type $i64_i64_i64_=>_i32 (func (param i64 i64 i64) (result i32)))
+ (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32)))
+ (type $i64_i64_i32_f32_=>_none (func (param i64 i64 i32 f32)))
+ (type $i32_i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32 i32) (result i32)))
+ (type $i64_i64_i64_=>_i64 (func (param i64 i64 i64) (result i64)))
+ (memory $0 (shared 1 1))
+ (export "replaced-print-internal" (func $56))
+ (func $figure-1a (param $a i64) (param $x i64) (param $y i64) (result i32)
+  (local $i i32)
+  (local $j i32)
+  (local $r i32)
+  (local $6 i64)
+  (local $7 i64)
+  (local $8 i32)
+  (local $9 i64)
+  (local $10 i64)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (block
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (local.set $12
+    (i64.eq
+     (local.get $a)
+     (local.get $x)
+    )
+   )
+   (local.set $13
+    (i64.ne
+     (local.get $a)
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $15
+    (i32.and
+     (local.get $12)
+     (local.get $13)
+    )
+   )
+   (return
+    (local.get $15)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $16)
+  )
+ )
+ (func $figure-1b (param $a i64) (param $x i64) (param $y i64) (result i32)
+  (local $i i32)
+  (local $j i32)
+  (local $r i32)
+  (local $6 i64)
+  (local $7 i64)
+  (local $8 i32)
+  (local $9 i64)
+  (local $10 i64)
+  (local $11 i32)
+  (local $12 i64)
+  (local $13 i64)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (block
+   (nop)
+   (nop)
+   (local.set $8
+    (i64.lt_s
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (if
+    (local.get $8)
+    (block
+     (block $block
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (local.set $15
+       (i64.eq
+        (local.get $a)
+        (local.get $x)
+       )
+      )
+      (local.set $16
+       (i64.ne
+        (local.get $a)
+        (local.get $y)
+       )
+      )
+      (nop)
+      (nop)
+      (local.set $18
+       (i32.and
+        (local.get $15)
+        (local.get $16)
+       )
+      )
+      (return
+       (local.get $18)
+      )
+      (unreachable)
+     )
+     (unreachable)
+    )
+    (block
+     (unreachable)
+     (unreachable)
+    )
+   )
+  )
+  (unreachable)
+ )
+ (func $figure-3-if (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block
+   (block
+    (nop)
+    (local.set $2
+     (i32.and
+      (local.get $x)
+      (i32.const 1)
+     )
+    )
+    (if
+     (local.get $2)
+     (block
+      (nop)
+      (nop)
+      (local.set $x
+       (i32.add
+        (local.get $x)
+        (i32.const 1)
+       )
+      )
+     )
+     (block
+      (nop)
+      (nop)
+      (local.set $x
+       (i32.add
+        (local.get $x)
+        (i32.const 2)
+       )
+      )
+     )
+    )
+   )
+   (nop)
+   (local.set $8
+    (i32.and
+     (local.get $x)
+     (i32.const 1)
+    )
+   )
+   (return
+    (local.get $8)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $9)
+  )
+ )
+ (func $send-i32 (param $0 i32)
+  (nop)
+ )
+ (func $flips
+  (local $x i32)
+  (local $y i32)
+  (local $z i64)
+  (local $w i64)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i64)
+  (local $17 i64)
+  (local $18 i32)
+  (local $19 i64)
+  (local $20 i64)
+  (local $21 i32)
+  (local $22 i64)
+  (local $23 i64)
+  (local $24 i32)
+  (local $25 i64)
+  (local $26 i64)
+  (local $27 i32)
+  (nop)
+  (nop)
+  (nop)
+  (local.set $x
+   (i32.ge_s
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (nop)
+  (nop)
+  (nop)
+  (local.set $x
+   (i32.ge_u
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (nop)
+  (nop)
+  (nop)
+  (local.set $x
+   (i32.gt_s
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (nop)
+  (nop)
+  (nop)
+  (local.set $x
+   (i32.gt_u
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (nop)
+  (nop)
+  (local.set $18
+   (i64.ge_s
+    (local.get $z)
+    (local.get $w)
+   )
+  )
+  (call $send-i32
+   (local.get $18)
+  )
+  (nop)
+  (nop)
+  (local.set $21
+   (i64.ge_u
+    (local.get $z)
+    (local.get $w)
+   )
+  )
+  (call $send-i32
+   (local.get $21)
+  )
+  (nop)
+  (nop)
+  (local.set $24
+   (i64.gt_s
+    (local.get $z)
+    (local.get $w)
+   )
+  )
+  (call $send-i32
+   (local.get $24)
+  )
+  (nop)
+  (nop)
+  (local.set $27
+   (i64.gt_u
+    (local.get $z)
+    (local.get $w)
+   )
+  )
+  (call $send-i32
+   (local.get $27)
+  )
+ )
+ (func $various-conditions-1 (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (nop)
+  (if
+   (local.get $x)
+   (block
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 1)
+     )
+    )
+   )
+  )
+ )
+ (func $various-conditions-2 (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (nop)
+  (local.set $2
+   (i32.lt_s
+    (local.get $x)
+    (i32.const 0)
+   )
+  )
+  (if
+   (local.get $2)
+   (block
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.sub
+      (local.get $x)
+      (i32.const 2)
+     )
+    )
+   )
+  )
+ )
+ (func $various-conditions-3 (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local.set $1
+   (i32.reinterpret_f32
+    (f32.const 0)
+   )
+  )
+  (if
+   (local.get $1)
+   (block
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.sub
+      (local.get $x)
+      (i32.const 4)
+     )
+    )
+   )
+  )
+ )
+ (func $various-conditions-4 (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block
+   (unreachable)
+   (if
+    (unreachable)
+    (block
+     (nop)
+     (nop)
+     (local.set $x
+      (i32.add
+       (local.get $x)
+       (i32.const 3)
+      )
+     )
+    )
+   )
+  )
+  (unreachable)
+ )
+ (func $unaries (param $x i32) (param $y i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (nop)
+  (local.set $3
+   (i32.eqz
+    (local.get $x)
+   )
+  )
+  (if
+   (local.get $3)
+   (block
+    (nop)
+    (local.set $5
+     (i32.ctz
+      (local.get $y)
+     )
+    )
+    (nop)
+    (local.set $7
+     (i32.clz
+      (local.get $x)
+     )
+    )
+    (nop)
+    (local.set $9
+     (i32.popcnt
+      (local.get $y)
+     )
+    )
+    (local.set $10
+     (i32.sub
+      (local.get $7)
+      (local.get $9)
+     )
+    )
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $5)
+      (local.get $10)
+     )
+    )
+   )
+  )
+ )
+ (func $unary-condition (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (nop)
+  (local.set $2
+   (i32.gt_u
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (local.set $3
+   (i32.ctz
+    (local.get $2)
+   )
+  )
+  (if
+   (local.get $3)
+   (block
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 2)
+     )
+    )
+   )
+  )
+ )
+ (func $unary-condition-2 (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (nop)
+  (local.set $2
+   (i32.gt_u
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (local.set $3
+   (i32.eqz
+    (local.get $2)
+   )
+  )
+  (if
+   (local.get $3)
+   (block
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 2)
+     )
+    )
+   )
+  )
+ )
+ (func $if-else-cond (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block
+   (block
+    (nop)
+    (local.set $2
+     (i32.lt_s
+      (local.get $x)
+      (i32.const 1)
+     )
+    )
+    (if
+     (local.get $2)
+     (block
+      (nop)
+      (nop)
+      (local.set $x
+       (i32.add
+        (local.get $x)
+        (i32.const 1)
+       )
+      )
+     )
+     (block
+      (nop)
+      (nop)
+      (local.set $x
+       (i32.add
+        (local.get $x)
+        (i32.const 2)
+       )
+      )
+     )
+    )
+   )
+   (nop)
+   (local.set $8
+    (i32.and
+     (local.get $x)
+     (i32.const 1)
+    )
+   )
+   (return
+    (local.get $8)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $9)
+  )
+ )
+ (func $trivial-ret (result i32)
+  (local $0 i32)
+  (local.set $0
+   (i32.add
+    (i32.const 0)
+    (i32.const 1)
+   )
+  )
+  (return
+   (local.get $0)
+  )
+ )
+ (func $trivial-const (result i32)
+  (return
+   (i32.const 0)
+  )
+ )
+ (func $trivial-const-block (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (block
+   (nop)
+   (nop)
+  )
+  (local.set $1
+   (i32.const 0)
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $bad-phi-value (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (block
+   (if
+    (i32.const 1)
+    (block
+     (nop)
+     (local.set $1
+      (i32.load
+       (i32.const 0)
+      )
+     )
+    )
+    (local.set $1
+     (i32.const 0)
+    )
+   )
+   (nop)
+   (if
+    (local.get $1)
+    (local.set $3
+     (i32.const 0)
+    )
+    (local.set $3
+     (i32.const 1)
+    )
+   )
+  )
+  (nop)
+  (return
+   (local.get $3)
+  )
+ )
+ (func $bad-phi-value-2 (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block
+   (block
+    (if
+     (i32.const 1)
+     (block
+      (nop)
+      (local.set $2
+       (i32.load
+        (i32.const 0)
+       )
+      )
+     )
+     (local.set $2
+      (i32.const 0)
+     )
+    )
+    (nop)
+    (if
+     (local.get $2)
+     (local.set $x
+      (i32.const 1)
+     )
+     (local.set $x
+      (i32.const 2)
+     )
+    )
+   )
+   (nop)
+   (nop)
+  )
+  (nop)
+  (return
+   (local.get $x)
+  )
+ )
+ (func $select (param $x i32) (result i32)
+  (local $1 i32)
+  (local.set $1
+   (select
+    (i32.const 1)
+    (i32.const 2)
+    (i32.const 3)
+   )
+  )
+  (return
+   (local.get $1)
+  )
+  (unreachable)
+ )
+ (func $select-2 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (nop)
+  (nop)
+  (local.set $4
+   (i32.add
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (nop)
+  (local.set $6
+   (i32.add
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (nop)
+  (local.set $8
+   (i32.add
+    (i32.const 2)
+    (local.get $y)
+   )
+  )
+  (local.set $9
+   (select
+    (local.get $4)
+    (local.get $6)
+    (local.get $8)
+   )
+  )
+  (return
+   (local.get $9)
+  )
+  (unreachable)
+ )
+ (func $block-phi-1 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block
+   (block $out
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 1)
+     )
+    )
+    (nop)
+    (br_if $out
+     (local.get $y)
+    )
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 2)
+     )
+    )
+   )
+   (nop)
+   (nop)
+   (nop)
+  )
+  (local.set $10
+   (i32.add
+    (local.get $x)
+    (i32.const 3)
+   )
+  )
+  (return
+   (local.get $10)
+  )
+ )
+ (func $block-phi-2 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block
+   (block $out
+    (local.set $x
+     (i32.const 1)
+    )
+    (nop)
+    (br_if $out
+     (local.get $y)
+    )
+    (local.set $x
+     (i32.const 2)
+    )
+   )
+   (nop)
+   (nop)
+   (nop)
+  )
+  (local.set $6
+   (i32.add
+    (local.get $x)
+    (i32.const 3)
+   )
+  )
+  (return
+   (local.get $6)
+  )
+ )
+ (func $zero_init-phi-bad_type (result f64)
+  (local $x f64)
+  (local $1 f64)
+  (local $2 f64)
+  (local $3 f64)
+  (block
+   (if
+    (i32.const 0)
+    (local.set $x
+     (f64.const 1)
+    )
+   )
+   (nop)
+   (nop)
+  )
+  (nop)
+  (return
+   (local.get $x)
+  )
+ )
+ (func $phi-bad-type (result f64)
+  (local $0 f64)
+  (local $1 f64)
+  (local $2 f64)
+  (local $3 f64)
+  (block $label$1
+   (if
+    (i32.const 0)
+    (local.set $0
+     (f64.const 0)
+    )
+    (local.set $0
+     (f64.const 1)
+    )
+   )
+   (nop)
+   (nop)
+  )
+  (nop)
+  (return
+   (local.get $0)
+  )
+ )
+ (func $phi-one-side-i1 (param $x i32) (param $y i32) (result i32)
+  (local $i i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (block
+   (block
+    (nop)
+    (nop)
+    (local.set $5
+     (i32.le_s
+      (local.get $x)
+      (local.get $y)
+     )
+    )
+    (if
+     (local.get $5)
+     (block
+      (nop)
+      (nop)
+      (nop)
+      (local.set $i
+       (i32.eq
+        (local.get $x)
+        (local.get $y)
+       )
+      )
+     )
+     (block
+      (nop)
+      (nop)
+      (nop)
+      (local.set $i
+       (i32.add
+        (local.get $x)
+        (local.get $y)
+       )
+      )
+     )
+    )
+   )
+   (nop)
+   (nop)
+  )
+  (nop)
+  (return
+   (local.get $i)
+  )
+ )
+ (func $call (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $0
+   (call $call)
+  )
+  (local.set $1
+   (call $call)
+  )
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (local.set $3
+   (call $call)
+  )
+  (local.set $4
+   (i32.add
+    (i32.const 10)
+    (local.get $3)
+   )
+  )
+  (local.set $5
+   (i32.mul
+    (local.get $2)
+    (local.get $4)
+   )
+  )
+  (return
+   (local.get $5)
+  )
+  (unreachable)
+ )
+ (func $in-unreachable-1 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block
+   (block
+    (nop)
+    (if
+     (local.get $x)
+     (block
+      (block $block
+       (local.set $x
+        (i32.const 1)
+       )
+       (nop)
+       (return
+        (local.get $x)
+       )
+       (unreachable)
+      )
+      (unreachable)
+     )
+     (local.set $x
+      (i32.const 2)
+     )
+    )
+   )
+   (nop)
+   (return
+    (local.get $x)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $5)
+  )
+ )
+ (func $in-unreachable-2 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (block
+   (block
+    (nop)
+    (if
+     (local.get $x)
+     (block
+      (block $block
+       (local.set $x
+        (i32.const 1)
+       )
+       (unreachable)
+       (unreachable)
+      )
+      (unreachable)
+     )
+     (local.set $x
+      (i32.const 2)
+     )
+    )
+   )
+   (nop)
+   (return
+    (local.get $x)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $4)
+  )
+ )
+ (func $in-unreachable-3 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block
+   (block $out
+    (block
+     (nop)
+     (if
+      (local.get $x)
+      (block
+       (block $block
+        (local.set $x
+         (i32.const 1)
+        )
+        (br $out)
+        (unreachable)
+       )
+       (unreachable)
+      )
+      (local.set $x
+       (i32.const 2)
+      )
+     )
+    )
+    (nop)
+    (return
+     (local.get $x)
+    )
+    (unreachable)
+   )
+   (nop)
+   (return
+    (local.get $x)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $5)
+  )
+ )
+ (func $in-unreachable-4 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block
+   (block $out
+    (block
+     (nop)
+     (if
+      (local.get $x)
+      (block
+       (block $block
+        (local.set $x
+         (i32.const 1)
+        )
+        (br_table $out $out $out
+         (i32.const 1)
+        )
+        (unreachable)
+       )
+       (unreachable)
+      )
+      (local.set $x
+       (i32.const 2)
+      )
+     )
+    )
+    (nop)
+    (return
+     (local.get $x)
+    )
+    (unreachable)
+   )
+   (nop)
+   (return
+    (local.get $x)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $5)
+  )
+ )
+ (func $in-unreachable-br_if (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (block
+   (block $out
+    (block
+     (nop)
+     (if
+      (local.get $x)
+      (block $block
+       (local.set $x
+        (i32.const 1)
+       )
+       (nop)
+       (br_if $out
+        (local.get $x)
+       )
+      )
+      (local.set $x
+       (i32.const 2)
+      )
+     )
+    )
+    (nop)
+    (return
+     (local.get $x)
+    )
+    (unreachable)
+   )
+   (nop)
+   (return
+    (local.get $x)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $6)
+  )
+ )
+ (func $in-unreachable-big (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (block $label$1
+   (block $label$2
+    (block $label$3
+     (block
+      (nop)
+      (if
+       (local.get $2)
+       (block
+        (block
+         (nop)
+         (if
+          (local.get $0)
+          (block
+           (block $block
+            (local.set $1
+             (i32.const -8531)
+            )
+            (br $label$3)
+            (unreachable)
+           )
+           (unreachable)
+          )
+          (block
+           (block $block3
+            (local.set $1
+             (i32.const -8531)
+            )
+            (br $label$1)
+            (unreachable)
+           )
+           (unreachable)
+          )
+         )
+        )
+        (unreachable)
+       )
+      )
+     )
+     (br $label$2)
+     (unreachable)
+    )
+    (local.set $6
+     (i32.load
+      (i32.const 0)
+     )
+    )
+    (drop
+     (local.get $6)
+    )
+    (br $label$1)
+    (unreachable)
+   )
+   (nop)
+   (i32.store16
+    (i32.const 1)
+    (local.get $1)
+   )
+   (unreachable)
+   (unreachable)
+  )
+  (i32.store16
+   (i32.const 0)
+   (i32.const -8531)
+  )
+ )
+ (func $in-unreachable-operations (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (block $block
+   (unreachable)
+   (unreachable)
+   (block
+    (nop)
+    (if
+     (local.get $x)
+     (local.set $x
+      (i32.const 1)
+     )
+     (local.set $x
+      (i32.const 2)
+     )
+    )
+   )
+   (nop)
+   (return
+    (local.get $x)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $merge-with-one-less (param $var$0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block
+   (block $label$1
+    (block $label$2
+     (block $label$3
+      (block $label$4
+       (block $label$5
+        (local.set $1
+         (i32.load
+          (i32.const 1)
+         )
+        )
+        (br_table $label$5 $label$4 $label$3 $label$2
+         (local.get $1)
+        )
+        (unreachable)
+       )
+       (unreachable)
+       (unreachable)
+      )
+      (br $label$1)
+      (unreachable)
+     )
+     (local.set $var$0
+      (i32.const 8)
+     )
+     (nop)
+     (local.set $3
+      (i32.load
+       (local.get $var$0)
+      )
+     )
+     (f64.store
+      (local.get $3)
+      (f64.const 0)
+     )
+     (br $label$1)
+     (unreachable)
+    )
+    (unreachable)
+    (unreachable)
+   )
+   (nop)
+   (i32.store
+    (local.get $var$0)
+    (i32.const 16)
+   )
+   (nop)
+  )
+  (local.set $6
+   (i32.const 1)
+  )
+  (return
+   (local.get $6)
+  )
+ )
+ (func $deep (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (local $19 i32)
+  (local $20 i32)
+  (local $21 i32)
+  (local $22 i32)
+  (local $23 i32)
+  (local $24 i32)
+  (local $25 i32)
+  (local $26 i32)
+  (local $27 i32)
+  (local $28 i32)
+  (local $29 i32)
+  (local $30 i32)
+  (local $31 i32)
+  (local $32 i32)
+  (local $33 i32)
+  (local $34 i32)
+  (local $35 i32)
+  (local $36 i32)
+  (local $37 i32)
+  (local $38 i32)
+  (local $39 i32)
+  (local $40 i32)
+  (local $41 i32)
+  (local $42 i32)
+  (local $43 i32)
+  (local $44 i32)
+  (local $45 i32)
+  (local $46 i32)
+  (local $47 i32)
+  (local $48 i32)
+  (local $49 i32)
+  (local $50 i32)
+  (local $51 i32)
+  (local $52 i32)
+  (local $53 i32)
+  (local $54 i32)
+  (local $55 i32)
+  (block
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.xor
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $x)
+     (i32.const 1234)
+    )
+   )
+   (nop)
+   (nop)
+  )
+  (nop)
+  (return
+   (local.get $x)
+  )
+ )
+ (func $two-pcs (param $x i64) (param $y i64) (param $t i64) (result i64)
+  (local $3 i64)
+  (local $4 i64)
+  (local $5 i32)
+  (local $6 i64)
+  (local $7 i32)
+  (local $8 i64)
+  (local $9 i64)
+  (local $10 i64)
+  (local $11 i64)
+  (local $12 i64)
+  (local $13 i64)
+  (local $14 i64)
+  (local $15 i32)
+  (local $16 i64)
+  (local $17 i64)
+  (local $18 i64)
+  (local $19 i64)
+  (local $20 i64)
+  (local $21 i64)
+  (local $22 i64)
+  (local $23 i64)
+  (local $24 i64)
+  (block
+   (block
+    (nop)
+    (nop)
+    (local.set $5
+     (i64.lt_s
+      (local.get $x)
+      (local.get $y)
+     )
+    )
+    (if
+     (local.get $5)
+     (block
+      (nop)
+      (local.set $7
+       (i64.eqz
+        (local.get $x)
+       )
+      )
+      (if
+       (local.get $7)
+       (block
+        (nop)
+        (nop)
+        (nop)
+        (local.set $t
+         (i64.add
+          (local.get $x)
+          (local.get $y)
+         )
+        )
+       )
+       (block
+        (nop)
+        (nop)
+        (nop)
+        (local.set $t
+         (i64.sub
+          (local.get $x)
+          (local.get $y)
+         )
+        )
+       )
+      )
+     )
+     (block
+      (nop)
+      (local.set $15
+       (i64.eqz
+        (local.get $y)
+       )
+      )
+      (if
+       (local.get $15)
+       (block
+        (nop)
+        (nop)
+        (nop)
+        (local.set $t
+         (i64.mul
+          (local.get $x)
+          (local.get $y)
+         )
+        )
+       )
+       (block
+        (nop)
+        (nop)
+        (nop)
+        (local.set $t
+         (i64.div_s
+          (local.get $x)
+          (local.get $y)
+         )
+        )
+       )
+      )
+     )
+    )
+   )
+   (nop)
+   (return
+    (local.get $t)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $23)
+  )
+ )
+ (func $loop-1 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+   )
+   (nop)
+   (nop)
+   (local.set $4
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $4)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $5)
+  )
+ )
+ (func $loop-2 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 3)
+     )
+    )
+    (nop)
+    (nop)
+    (local.set $y
+     (i32.add
+      (local.get $y)
+      (i32.const 4)
+     )
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $8
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $8)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $9)
+  )
+ )
+ (func $loop-3 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 3)
+     )
+    )
+    (nop)
+    (nop)
+    (local.set $y
+     (i32.add
+      (local.get $y)
+      (i32.const 4)
+     )
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $9
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $9)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $10)
+  )
+ )
+ (func $loop-4 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 3)
+     )
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $7
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $7)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $8)
+  )
+ )
+ (func $loop-5 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 3)
+     )
+    )
+    (local.set $y
+     (i32.const 2)
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $7
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $7)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $8)
+  )
+ )
+ (func $loop-6 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 3)
+     )
+    )
+    (nop)
+    (nop)
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $8
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $8)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $9)
+  )
+ )
+ (func $loop-7 (param $x i32) (param $y i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 3)
+     )
+    )
+    (local.set $y
+     (i32.const 5)
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $7
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $7)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $8)
+  )
+ )
+ (func $loop-8 (param $x i32) (param $y i32) (result i32)
+  (local $z i32)
+  (local $w i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (local.set $z
+     (local.get $x)
+    )
+    (nop)
+    (local.set $w
+     (local.get $y)
+    )
+    (local.set $x
+     (i32.const 1)
+    )
+    (local.set $y
+     (i32.const 4)
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $9
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $12
+    (i32.sub
+     (local.get $z)
+     (local.get $w)
+    )
+   )
+   (local.set $13
+    (i32.mul
+     (local.get $9)
+     (local.get $12)
+    )
+   )
+   (return
+    (local.get $13)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $14)
+  )
+ )
+ (func $loop-9 (param $x i32) (param $y i32) (result i32)
+  (local $t i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (loop $loopy
+    (nop)
+    (local.set $t
+     (local.get $x)
+    )
+    (nop)
+    (local.set $x
+     (local.get $y)
+    )
+    (nop)
+    (local.set $y
+     (local.get $t)
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $9
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $9)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $10)
+  )
+ )
+ (func $loop-10 (param $x i32) (param $y i32) (result i32)
+  (local $t i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 1)
+   )
+   (loop $loopy
+    (nop)
+    (local.set $t
+     (local.get $x)
+    )
+    (nop)
+    (local.set $x
+     (local.get $y)
+    )
+    (nop)
+    (local.set $y
+     (local.get $t)
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $9
+    (i32.add
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (return
+    (local.get $9)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $10)
+  )
+ )
+ (func $loop-multicond-1 (param $x i32) (param $y i32) (param $z i32) (result i32)
+  (local $t i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (local.set $z
+    (i32.const 3)
+   )
+   (loop $loopy
+    (local.set $x
+     (i32.const 4)
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $t)
+    )
+    (local.set $y
+     (i32.const 5)
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $t)
+    )
+    (local.set $z
+     (i32.const 6)
+    )
+   )
+   (nop)
+   (nop)
+   (nop)
+   (local.set $9
+    (select
+     (local.get $x)
+     (local.get $y)
+     (local.get $z)
+    )
+   )
+   (return
+    (local.get $9)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $10)
+  )
+ )
+ (func $loop-multicond-2 (param $x i32) (param $y i32) (param $z i32) (result i32)
+  (local $t i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (local.set $z
+    (i32.const 3)
+   )
+   (loop $loopy
+    (nop)
+    (nop)
+    (local.set $x
+     (i32.add
+      (local.get $x)
+      (i32.const 4)
+     )
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $t)
+    )
+    (nop)
+    (nop)
+    (local.set $y
+     (i32.add
+      (local.get $y)
+      (i32.const 5)
+     )
+    )
+    (nop)
+    (br_if $loopy
+     (local.get $t)
+    )
+    (nop)
+    (nop)
+    (local.set $z
+     (i32.add
+      (local.get $z)
+      (i32.const 6)
+     )
+    )
+   )
+   (nop)
+   (nop)
+   (nop)
+   (local.set $15
+    (select
+     (local.get $x)
+     (local.get $y)
+     (local.get $z)
+    )
+   )
+   (return
+    (local.get $15)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $16)
+  )
+ )
+ (func $loop-block-1 (param $x i32) (param $y i32) (param $z i32) (result i32)
+  (local $t i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (local.set $z
+    (i32.const 3)
+   )
+   (loop $loopy
+    (block $out
+     (nop)
+     (nop)
+     (local.set $x
+      (i32.add
+       (local.get $x)
+       (i32.const 4)
+      )
+     )
+     (nop)
+     (br_if $out
+      (local.get $t)
+     )
+     (nop)
+     (nop)
+     (local.set $y
+      (i32.add
+       (local.get $y)
+       (i32.const 5)
+      )
+     )
+     (nop)
+     (br_if $out
+      (local.get $t)
+     )
+     (nop)
+     (nop)
+     (local.set $z
+      (i32.add
+       (local.get $z)
+       (i32.const 6)
+      )
+     )
+     (br $loopy)
+     (unreachable)
+    )
+   )
+   (nop)
+   (nop)
+   (nop)
+   (local.set $15
+    (select
+     (local.get $x)
+     (local.get $y)
+     (local.get $z)
+    )
+   )
+   (return
+    (local.get $15)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $16)
+  )
+ )
+ (func $loop-block-2 (param $x i32) (param $y i32) (param $z i32) (result i32)
+  (local $t i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (block
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (local.set $z
+    (i32.const 3)
+   )
+   (block $out
+    (loop $loopy
+     (block
+      (nop)
+      (nop)
+      (local.set $x
+       (i32.add
+        (local.get $x)
+        (i32.const 4)
+       )
+      )
+      (nop)
+      (br_if $out
+       (local.get $t)
+      )
+      (nop)
+      (nop)
+      (local.set $y
+       (i32.add
+        (local.get $y)
+        (i32.const 5)
+       )
+      )
+      (nop)
+      (br_if $out
+       (local.get $t)
+      )
+      (nop)
+      (nop)
+      (local.set $z
+       (i32.add
+        (local.get $z)
+        (i32.const 6)
+       )
+      )
+      (br $loopy)
+      (unreachable)
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (nop)
+   (nop)
+   (nop)
+   (local.set $15
+    (select
+     (local.get $x)
+     (local.get $y)
+     (local.get $z)
+    )
+   )
+   (return
+    (local.get $15)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $16)
+  )
+ )
+ (func $bad-phi-type (param $var$0 i64) (param $var$1 i64) (param $var$2 i32) (param $var$3 f32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 f64)
+  (local $9 f64)
+  (local $10 f64)
+  (local $11 f64)
+  (nop)
+  (if
+   (local.get $var$2)
+   (block
+    (loop $label$2
+     (block
+      (block
+       (block $label$3
+        (if
+         (i32.const 0)
+         (block
+          (unreachable)
+          (unreachable)
+         )
+        )
+        (nop)
+        (nop)
+       )
+       (local.set $6
+        (i32.const 0)
+       )
+       (if
+        (local.get $6)
+        (block
+         (unreachable)
+         (unreachable)
+        )
+       )
+      )
+      (nop)
+      (br_if $label$2
+       (local.get $var$2)
+      )
+      (nop)
+     )
+     (nop)
+     (local.set $10
+      (f64.const 0)
+     )
+    )
+    (nop)
+    (drop
+     (local.get $10)
+    )
+   )
+  )
+ )
+ (func $loop-unreachable
+  (local $var$0 i32)
+  (local $var$1 f64)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 f64)
+  (local $12 f64)
+  (local $13 f64)
+  (loop $label$1
+   (block
+    (block $label$2
+     (block $label$3
+      (block $label$4
+       (if
+        (i32.const 1337)
+        (block
+         (unreachable)
+         (unreachable)
+        )
+       )
+       (nop)
+       (nop)
+      )
+      (nop)
+      (nop)
+      (loop $label$6
+       (block $label$7
+        (nop)
+        (local.set $6
+         (local.get $var$0)
+        )
+        (br_if $label$7
+         (i32.const 65535)
+        )
+        (nop)
+        (drop
+         (local.get $6)
+        )
+        (nop)
+        (local.set $6
+         (local.get $var$0)
+        )
+        (br_if $label$7
+         (i32.const 0)
+        )
+        (nop)
+        (drop
+         (local.get $6)
+        )
+        (unreachable)
+        (unreachable)
+       )
+       (nop)
+       (br_if $label$6
+        (local.get $6)
+       )
+      )
+     )
+     (nop)
+     (nop)
+    )
+    (nop)
+    (nop)
+    (br $label$1)
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $phi-value-turns-bad (result f64)
+  (local $var$0 i32)
+  (local $var$1 i32)
+  (local $var$2 f32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 f32)
+  (local $13 f32)
+  (local $14 f32)
+  (local $15 f32)
+  (local $16 f64)
+  (local $17 f64)
+  (block
+   (block
+    (nop)
+    (local.set $var$0
+     (i32.atomic.rmw16.sub_u offset=22
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+    (nop)
+    (if
+     (local.get $var$0)
+     (block
+      (unreachable)
+      (unreachable)
+     )
+     (block
+      (block $block
+       (block
+        (loop $label$3
+         (block $label$4
+          (nop)
+          (local.set $6
+           (local.get $var$0)
+          )
+          (br_if $label$4
+           (i32.const 1)
+          )
+          (nop)
+          (nop)
+          (local.set $6
+           (i32.clz
+            (local.get $6)
+           )
+          )
+         )
+         (nop)
+         (nop)
+        )
+        (nop)
+        (if
+         (local.get $6)
+         (nop)
+        )
+       )
+       (nop)
+      )
+      (nop)
+      (local.set $14
+       (f32.const 1)
+      )
+     )
+    )
+   )
+   (nop)
+   (nop)
+   (unreachable)
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $16)
+  )
+ )
+ (func $multi-use (param $x i32) (result i32)
+  (local $temp i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (block
+   (nop)
+   (nop)
+   (local.set $temp
+    (i32.add
+     (local.get $x)
+     (i32.const 1)
+    )
+   )
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+  )
+  (local.set $8
+   (i32.add
+    (local.get $temp)
+    (local.get $temp)
+   )
+  )
+  (return
+   (local.get $8)
+  )
+ )
+ (func $multi-use-2 (param $x i32) (result i32)
+  (local $temp i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block
+   (nop)
+   (nop)
+   (local.set $temp
+    (i32.add
+     (local.get $x)
+     (i32.const 1)
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $x
+    (i32.mul
+     (local.get $temp)
+     (i32.const 2)
+    )
+   )
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+  )
+  (local.set $10
+   (i32.sub
+    (local.get $x)
+    (local.get $temp)
+   )
+  )
+  (return
+   (local.get $10)
+  )
+ )
+ (func $many-single-uses-with-param (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (nop)
+  (local.set $2
+   (i32.mul
+    (i32.const 10)
+    (local.get $x)
+   )
+  )
+  (nop)
+  (local.set $4
+   (i32.ctz
+    (local.get $x)
+   )
+  )
+  (local.set $5
+   (i32.sub
+    (local.get $4)
+    (i32.const 20)
+   )
+  )
+  (local.set $6
+   (i32.add
+    (local.get $2)
+    (local.get $5)
+   )
+  )
+  (local.set $7
+   (i32.eqz
+    (local.get $6)
+   )
+  )
+  (return
+   (local.get $7)
+  )
+  (unreachable)
+ )
+ (func $56 (param $var$0 i32)
+  (local $var$1 i32)
+  (local $var$2 i32)
+  (local $var$3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (nop)
+  (nop)
+  (local.set $var$0
+   (i32.add
+    (local.get $var$0)
+    (i32.const -7)
+   )
+  )
+  (nop)
+  (if
+   (local.get $var$0)
+   (block $label$2
+    (block $label$3
+     (nop)
+     (local.set $var$1
+      (local.get $var$0)
+     )
+     (nop)
+     (local.set $8
+      (i32.const 12)
+     )
+     (br_if $label$3
+      (local.get $8)
+     )
+     (unreachable)
+     (unreachable)
+    )
+    (nop)
+    (local.set $10
+     (i32.eqz
+      (local.get $var$1)
+     )
+    )
+    (br_if $label$2
+     (local.get $10)
+    )
+    (block
+     (local.set $11
+      (i32.load
+       (i32.const 0)
+      )
+     )
+     (nop)
+     (local.set $13
+      (i32.ne
+       (local.get $11)
+       (local.get $var$0)
+      )
+     )
+     (if
+      (local.get $13)
+      (block
+       (unreachable)
+       (unreachable)
+      )
+     )
+    )
+    (unreachable)
+    (unreachable)
+   )
+  )
+ )
+ (func $multiple-uses-to-non-expression (param $x i32)
+  (local $temp i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (nop)
+  (nop)
+  (local.set $x
+   (i32.add
+    (local.get $x)
+    (i32.const 10)
+   )
+  )
+  (nop)
+  (i32.store
+   (i32.const 1)
+   (local.get $x)
+  )
+  (nop)
+  (local.set $6
+   (i32.add
+    (local.get $x)
+    (i32.const 20)
+   )
+  )
+  (i32.store
+   (i32.const 2)
+   (local.get $6)
+  )
+ )
+ (func $nested-phi-forwarding (param $var$0 i32) (result i32)
+  (local $var$1 i32)
+  (local $var$2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (block
+   (block $label$1
+    (block $label$2
+     (loop $label$3
+      (block $label$4
+       (block $label$5
+        (block $label$6
+         (block $label$7
+          (block $label$8
+           (nop)
+           (br_table $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$8 $label$2 $label$2 $label$2 $label$6 $label$2 $label$2 $label$7 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$5 $label$4
+            (local.get $var$0)
+           )
+           (unreachable)
+          )
+          (local.set $var$1
+           (i32.const 1)
+          )
+         )
+         (br $label$4)
+         (unreachable)
+        )
+        (unreachable)
+        (unreachable)
+       )
+       (br $label$1)
+       (unreachable)
+      )
+      (local.set $var$2
+       (i32.const 1)
+      )
+      (nop)
+      (br_if $label$3
+       (local.get $var$2)
+      )
+     )
+    )
+    (block $label$9
+     (nop)
+     (local.set $6
+      (i32.or
+       (i32.const 1)
+       (local.get $var$1)
+      )
+     )
+     (br_if $label$9
+      (local.get $6)
+     )
+    )
+    (unreachable)
+    (unreachable)
+   )
+   (nop)
+   (i32.store offset=176
+    (i32.const 0)
+    (local.get $var$2)
+   )
+   (nop)
+  )
+  (local.set $9
+   (i32.const 0)
+  )
+  (return
+   (local.get $9)
+  )
+ )
+ (func $zext-numGets (param $var$0 i32) (param $var$1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (block $label$1
+   (local.set $2
+    (i32.load
+     (i32.const -8)
+    )
+   )
+   (local.set $3
+    (i32.const 1)
+   )
+   (br_if $label$1
+    (local.get $2)
+   )
+   (nop)
+   (drop
+    (local.get $3)
+   )
+   (local.set $5
+    (i32.load
+     (i32.const -16)
+    )
+   )
+   (nop)
+   (local.set $3
+    (i32.eqz
+     (local.get $5)
+    )
+   )
+  )
+  (nop)
+  (local.set $8
+   (i32.ctz
+    (local.get $3)
+   )
+  )
+  (if
+   (local.get $8)
+   (block
+    (unreachable)
+    (unreachable)
+   )
+  )
+ )
+ (func $zext-numGets-hasAnotherUse (param $var$0 i32) (param $var$1 i32)
+  (local $temp i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (block $label$1
+   (local.set $3
+    (i32.load
+     (i32.const -8)
+    )
+   )
+   (local.set $4
+    (i32.const 1)
+   )
+   (br_if $label$1
+    (local.get $3)
+   )
+   (nop)
+   (drop
+    (local.get $4)
+   )
+   (local.set $6
+    (i32.load
+     (i32.const -16)
+    )
+   )
+   (nop)
+   (local.set $temp
+    (i32.eqz
+     (local.get $6)
+    )
+   )
+   (nop)
+   (drop
+    (local.get $temp)
+   )
+   (nop)
+   (local.set $4
+    (local.get $temp)
+   )
+  )
+  (nop)
+  (local.set $11
+   (i32.ctz
+    (local.get $4)
+   )
+  )
+  (if
+   (local.get $11)
+   (block
+    (unreachable)
+    (unreachable)
+   )
+  )
+ )
+ (func $flipped-needs-right-origin (param $var$0 i32) (result i32)
+  (local $var$1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (block
+   (block $label$1
+    (local.set $2
+     (i32.load
+      (i32.const 1)
+     )
+    )
+    (br_if $label$1
+     (local.get $2)
+    )
+    (local.set $var$1
+     (i32.const 2)
+    )
+   )
+   (block
+    (nop)
+    (local.set $4
+     (i32.add
+      (local.get $var$1)
+      (i32.const 4)
+     )
+    )
+    (local.set $5
+     (i32.gt_s
+      (i32.const 3)
+      (local.get $4)
+     )
+    )
+    (if
+     (local.get $5)
+     (block
+      (unreachable)
+      (unreachable)
+     )
+    )
+   )
+   (nop)
+  )
+  (local.set $7
+   (i32.const 5)
+  )
+  (return
+   (local.get $7)
+  )
+ )
+ (func $non-expr-nodes-may-have-multiple-uses-too-its-the-ORIGIN (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (block
+   (nop)
+   (nop)
+   (local.set $var$1
+    (i32.gt_u
+     (local.get $var$1)
+     (i32.const 1)
+    )
+   )
+   (nop)
+   (i32.store
+    (local.get $var$1)
+    (i32.const 2)
+   )
+   (nop)
+   (local.set $7
+    (i32.sub
+     (i32.const 4)
+     (local.get $var$1)
+    )
+   )
+   (i32.store offset=8
+    (i32.const 3)
+    (local.get $7)
+   )
+   (unreachable)
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $8)
+  )
+ )
+ (func $loop-of-set-connections (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (param $var$3 i32) (param $var$4 i32) (result i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (loop $label$1
+   (block
+    (if
+     (i32.const 0)
+     (block
+      (block $block
+       (nop)
+       (local.set $var$2
+        (i32.add
+         (i32.const 0)
+         (i32.const 1)
+        )
+       )
+       (br $label$1)
+       (unreachable)
+      )
+      (unreachable)
+     )
+    )
+    (nop)
+    (nop)
+    (nop)
+    (nop)
+    (br $label$1)
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $conditions-in-conditions (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (result i32)
+  (local $var$3 i32)
+  (local $var$4 i32)
+  (local $var$5 i32)
+  (local $var$6 i32)
+  (local $var$7 i32)
+  (local $var$8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (block
+   (local.set $var$1
+    (i32.const 1)
+   )
+   (if
+    (i32.const 0)
+    (loop $label$2
+     (block
+      (nop)
+      (if
+       (local.get $var$1)
+       (nop)
+      )
+     )
+     (local.set $var$3
+      (i32.const 1)
+     )
+     (nop)
+     (nop)
+     (local.set $var$1
+      (i32.sub
+       (i32.const 0)
+       (local.get $var$3)
+      )
+     )
+     (br_if $label$2
+      (i32.const 0)
+     )
+    )
+   )
+   (block
+    (nop)
+    (if
+     (local.get $var$1)
+     (local.set $var$3
+      (i32.const 1)
+     )
+    )
+   )
+   (nop)
+   (local.set $14
+    (i32.add
+     (local.get $var$3)
+     (i32.const 16)
+    )
+   )
+   (i32.store
+    (i32.const 8)
+    (local.get $14)
+   )
+   (i32.store
+    (i32.const 8)
+    (i32.const 64)
+   )
+   (unreachable)
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $15)
+  )
+ )
+)
diff --git a/binaryen/test/passes/flatten_simplify-locals-nonesting_souperify_enable-threads.wast b/binaryen/test/passes/flatten_simplify-locals-nonesting_souperify_enable-threads.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/flatten_simplify-locals-nonesting_souperify_enable-threads.wast
@@ -0,0 +1,1253 @@
+(module
+  (memory $0 (shared 1 1))
+  ;; Figure 1a from the Souper paper https://arxiv.org/pdf/1711.04422.pdf
+  (func $figure-1a (param $a i64) (param $x i64) (param $y i64) (result i32)
+    (local $i i32)
+    (local $j i32)
+    (local $r i32)
+    (local.set $i
+      (i64.eq
+        (local.get $a)
+        (local.get $x)
+      )
+    )
+    (local.set $j
+      (i64.ne
+        (local.get $a)
+        (local.get $y)
+      )
+    )
+    (local.set $r
+      (i32.and
+        (local.get $i)
+        (local.get $j)
+      )
+    )
+    (return (local.get $r))
+  )
+  ;; Figure 1b, with a potential path condition
+  (func $figure-1b (param $a i64) (param $x i64) (param $y i64) (result i32)
+    (local $i i32)
+    (local $j i32)
+    (local $r i32)
+    (if
+      (i64.lt_s
+        (local.get $x)
+        (local.get $y)
+      )
+      (block
+        (local.set $i
+          (i64.eq
+            (local.get $a)
+            (local.get $x)
+          )
+        )
+        (local.set $j
+          (i64.ne
+            (local.get $a)
+            (local.get $y)
+          )
+        )
+        (local.set $r
+          (i32.and
+            (local.get $i)
+            (local.get $j)
+          )
+        )
+        (return (local.get $r))
+      )
+      (unreachable)
+    )
+  )
+  ;; Figure 3, simplified to an if
+  (func $figure-3-if (param $x i32) (result i32)
+    (if
+      (i32.and
+        (local.get $x)
+        (i32.const 1)
+      )
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 2)
+        )
+      )
+    )
+    (return
+      (i32.and
+        (local.get $x)
+        (i32.const 1)
+      )
+    )
+  )
+  (func $send-i32 (param i32))
+  ;; flipping of greater than/or equals ops, which are not in Souper IR
+  (func $flips
+    (local $x i32)
+    (local $y i32)
+    (local $z i64)
+    (local $w i64)
+    (local.set $x (i32.ge_s (local.get $x) (local.get $y)))
+    (local.set $x (i32.ge_u (local.get $x) (local.get $y)))
+    (local.set $x (i32.gt_s (local.get $x) (local.get $y)))
+    (local.set $x (i32.gt_u (local.get $x) (local.get $y)))
+    (call $send-i32 (i64.ge_s (local.get $z) (local.get $w)))
+    (call $send-i32 (i64.ge_u (local.get $z) (local.get $w)))
+    (call $send-i32 (i64.gt_s (local.get $z) (local.get $w)))
+    (call $send-i32 (i64.gt_u (local.get $z) (local.get $w)))
+  )
+  (func $various-conditions-1 (param $x i32)
+    (if
+      (local.get $x)
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+    )
+  )
+  (func $various-conditions-2 (param $x i32)
+    (if
+      (i32.lt_s
+        (local.get $x)
+        (i32.const 0)
+      )
+      (local.set $x
+        (i32.sub
+          (local.get $x)
+          (i32.const 2)
+        )
+      )
+    )
+  )
+  (func $various-conditions-3 (param $x i32)
+    (if
+      (i32.reinterpret_f32 (f32.const 0))
+      (local.set $x
+        (i32.sub
+          (local.get $x)
+          (i32.const 4)
+        )
+      )
+    )
+  )
+  (func $various-conditions-4 (param $x i32)
+    (if
+      (unreachable)
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 3)
+        )
+      )
+    )
+  )
+  (func $unaries (param $x i32) (param $y i32)
+    (if
+      (i32.eqz
+        (local.get $x)
+      )
+      (local.set $x
+        (i32.add
+          (i32.ctz
+            (local.get $y)
+          )
+          (i32.sub
+            (i32.clz
+              (local.get $x)
+            )
+            (i32.popcnt
+              (local.get $y)
+            )
+          )
+        )
+      )
+    )
+  )
+  (func $unary-condition (param $x i32)
+    (if
+      (i32.ctz
+        (i32.gt_u
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 2)
+        )
+      )
+    )
+  )
+  (func $unary-condition-2 (param $x i32)
+    (if
+      (i32.eqz
+        (i32.gt_u
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 2)
+        )
+      )
+    )
+  )
+  (func $if-else-cond (param $x i32) (result i32)
+    (if
+      (i32.lt_s
+        (local.get $x)
+        (i32.const 1)
+      )
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 2)
+        )
+      )
+    )
+    (return
+      (i32.and
+        (local.get $x)
+        (i32.const 1)
+      )
+    )
+  )
+  (func $trivial-ret (result i32)
+    (i32.add
+      (i32.const 0)
+      (i32.const 1)
+    )
+  )
+  (func $trivial-const (result i32)
+    (i32.const 0)
+  )
+  (func $trivial-const-block (result i32)
+    (nop)
+    (i32.const 0)
+  )
+  (func $bad-phi-value (result i32)
+    (if (result i32)
+      (if (result i32)
+        (i32.const 1)
+        (i32.load
+          (i32.const 0)
+        )
+        (i32.const 0)
+      )
+      (i32.const 0)
+      (i32.const 1)
+    )
+  )
+  (func $bad-phi-value-2 (param $x i32) (result i32)
+    (if
+      (if (result i32)
+        (i32.const 1)
+        (i32.load
+          (i32.const 0)
+        )
+        (i32.const 0)
+      )
+      (local.set $x (i32.const 1))
+      (local.set $x (i32.const 2))
+    )
+    (local.get $x)
+  )
+  (func $select (param $x i32) (result i32)
+    (return
+      (select
+        (i32.const 1)
+        (i32.const 2)
+        (i32.const 3)
+      )
+    )
+  )
+  (func $select-2 (param $x i32) (param $y i32) (result i32)
+    (return
+      (select
+        (i32.add
+          (local.get $x)
+          (local.get $y)
+        )
+        (i32.add
+          (local.get $x)
+          (i32.const 1)
+        )
+        (i32.add
+          (i32.const 2)
+          (local.get $y)
+        )
+      )
+    )
+  )
+  (func $block-phi-1 (param $x i32) (param $y i32) (result i32)
+    (block $out
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+      (br_if $out (local.get $y))
+      (local.set $x
+        (i32.add
+          (local.get $x)
+          (i32.const 2)
+        )
+      )
+    )
+    (i32.add
+      (local.get $x)
+      (i32.const 3)
+    )
+  )
+  (func $block-phi-2 (param $x i32) (param $y i32) (result i32)
+    (block $out
+      (local.set $x
+        (i32.const 1)
+      )
+      (br_if $out (local.get $y))
+      (local.set $x
+        (i32.const 2)
+      )
+    )
+    (i32.add
+      (local.get $x)
+      (i32.const 3)
+    )
+  )
+  (func $zero_init-phi-bad_type (result f64)
+    (local $x f64)
+    (if
+      (i32.const 0)
+      (local.set $x
+        (f64.const 1)
+      )
+    )
+    (local.get $x)
+  )
+  (func $phi-bad-type  (result f64)
+    (block $label$1 (result f64)
+      (if (result f64)
+        (i32.const 0)
+        (f64.const 0)
+        (f64.const 1)
+      )
+    )
+  )
+  (func $phi-one-side-i1 (param $x i32) (param $y i32) (result i32)
+    (local $i i32)
+    (if
+      (i32.le_s
+        (local.get $x)
+        (local.get $y)
+      )
+      (local.set $i
+        (i32.eq
+          (local.get $x)
+          (local.get $y)
+        )
+      )
+      (local.set $i
+        (i32.add
+          (local.get $x)
+          (local.get $y)
+        )
+      )
+    )
+    (local.get $i)
+  )
+  (func $call (result i32)
+    (return
+      (i32.mul
+        (i32.add
+          (call $call)
+          (call $call)
+        )
+        (i32.add
+          (i32.const 10)
+          (call $call)
+        )
+      )
+    )
+  )
+  (func $in-unreachable-1 (param $x i32) (param $y i32) (result i32)
+    (if
+      (local.get $x)
+      (block
+        (local.set $x
+          (i32.const 1)
+        )
+        (return (local.get $x))
+      )
+      (local.set $x
+        (i32.const 2)
+      )
+    )
+    ;; no phi here!
+    (return
+      (local.get $x)
+    )
+  )
+  (func $in-unreachable-2 (param $x i32) (param $y i32) (result i32)
+    (if
+      (local.get $x)
+      (block
+        (local.set $x
+          (i32.const 1)
+        )
+        (unreachable)
+      )
+      (local.set $x
+        (i32.const 2)
+      )
+    )
+    ;; no phi here!
+    (return
+      (local.get $x)
+    )
+  )
+  (func $in-unreachable-3 (param $x i32) (param $y i32) (result i32)
+    (block $out
+      (if
+        (local.get $x)
+        (block
+          (local.set $x
+            (i32.const 1)
+          )
+          (br $out)
+        )
+        (local.set $x
+          (i32.const 2)
+        )
+      )
+      ;; no phi here!
+      (return
+        (local.get $x)
+      )
+    )
+    (return
+      (local.get $x)
+    )
+  )
+  (func $in-unreachable-4 (param $x i32) (param $y i32) (result i32)
+    (block $out
+      (if
+        (local.get $x)
+        (block
+          (local.set $x
+            (i32.const 1)
+          )
+          (br_table $out $out $out (i32.const 1))
+        )
+        (local.set $x
+          (i32.const 2)
+        )
+      )
+      ;; no phi here!
+      (return
+        (local.get $x)
+      )
+    )
+    (return
+      (local.get $x)
+    )
+  )
+  (func $in-unreachable-br_if (param $x i32) (param $y i32) (result i32)
+    (block $out
+      (if
+        (local.get $x)
+        (block
+          (local.set $x
+            (i32.const 1)
+          )
+          (br_if $out
+            (local.get $x)
+          )
+        )
+        (local.set $x
+          (i32.const 2)
+        )
+      )
+      ;; there *IS* a phi here since it was a br_if
+      (return
+        (local.get $x)
+      )
+    )
+    (return
+      (local.get $x)
+    )
+  )
+  (func $in-unreachable-big (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
+   (block $label$1
+    (block $label$2
+     (block $label$3
+      (if
+       (local.get $2)
+       (if
+        (local.get $0)
+        (block
+         (local.set $1
+          (i32.const -8531)
+         )
+         (br $label$3)
+        )
+        (block
+         (local.set $1
+          (i32.const -8531)
+         )
+         (br $label$1)
+        )
+       )
+      )
+      (br $label$2)
+     )
+     (drop
+      (i32.load
+       (i32.const 0)
+      )
+     )
+     (br $label$1)
+    )
+    (i32.store16
+     (i32.const 1)
+     (local.get $1)
+    )
+    (unreachable)
+   )
+   (i32.store16
+    (i32.const 0)
+    (i32.const -8531)
+   )
+  )
+  (func $in-unreachable-operations (param $x i32) (param $y i32) (result i32)
+    (block
+      (unreachable)
+      (if
+        (local.get $x)
+        (local.set $x
+          (i32.const 1)
+        )
+        (local.set $x
+          (i32.const 2)
+        )
+      )
+      (return
+        (local.get $x)
+      )
+    )
+  )
+  (func $merge-with-one-less (param $var$0 i32) (result i32)
+   (block $label$1
+    (block $label$2
+     (block $label$3
+      (block $label$4
+       (block $label$5
+        (br_table $label$5 $label$4 $label$3 $label$2
+         (i32.load
+          (i32.const 1)
+         )
+        )
+       )
+       (unreachable)
+      )
+      (br $label$1)
+     )
+     (f64.store
+      (i32.load
+       (local.tee $var$0
+        (i32.const 8)
+       )
+      )
+      (f64.const 0)
+     )
+     (br $label$1)
+    )
+    (unreachable)
+   )
+   (i32.store
+    (local.get $var$0)
+    (i32.const 16)
+   )
+   (i32.const 1)
+  )
+  (func $deep (param $x i32) (result i32)
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.xor (local.get $x) (i32.const 1234)))
+    (local.set $x (i32.mul (local.get $x) (i32.const 1234)))
+    (local.get $x)
+  )
+  (func $two-pcs (param $x i64) (param $y i64) (param $t i64) (result i64)
+    (if
+      (i64.lt_s
+        (local.get $x)
+        (local.get $y)
+      )
+      (if
+        (i64.eqz
+          (local.get $x)
+        )
+        (local.set $t
+          (i64.add
+            (local.get $x)
+            (local.get $y)
+          )
+        )
+        (local.set $t
+          (i64.sub
+            (local.get $x)
+            (local.get $y)
+          )
+        )
+      )
+      (if
+        (i64.eqz
+          (local.get $y)
+        )
+        (local.set $t
+          (i64.mul
+            (local.get $x)
+            (local.get $y)
+          )
+        )
+        (local.set $t
+          (i64.div_s
+            (local.get $x)
+            (local.get $y)
+          )
+        )
+      )
+    )
+    (return (local.get $t))
+  )
+  (func $loop-1 (param $x i32) (param $y i32) (result i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+    )
+    ;; neither needed a phi
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-2 (param $x i32) (param $y i32) (result i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $x (i32.add (local.get $x) (i32.const 3)))
+      (local.set $y (i32.add (local.get $y) (i32.const 4)))
+    )
+    ;; neither needed a phi
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-3 (param $x i32) (param $y i32) (result i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $x (i32.add (local.get $x) (i32.const 3)))
+      (local.set $y (i32.add (local.get $y) (i32.const 4)))
+      (br_if $loopy (local.get $y))
+    )
+    ;; both needed
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-4 (param $x i32) (param $y i32) (result i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $x (i32.add (local.get $x) (i32.const 3)))
+      (br_if $loopy (local.get $y))
+    )
+    ;; only x needed a phi
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-5 (param $x i32) (param $y i32) (result i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $x (i32.add (local.get $x) (i32.const 3)))
+      (local.set $y (i32.const 2)) ;; same value
+      (br_if $loopy (local.get $y))
+    )
+    ;; only x needed a phi
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-6 (param $x i32) (param $y i32) (result i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $x (i32.add (local.get $x) (i32.const 3)))
+      (local.set $y (local.get $y)) ;; same value
+      (br_if $loopy (local.get $y))
+    )
+    ;; only x needed a phi
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-7 (param $x i32) (param $y i32) (result i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $x (i32.add (local.get $x) (i32.const 3)))
+      (local.set $y (i32.const 5)) ;; different!
+      (br_if $loopy (local.get $y))
+    )
+    ;; y changed but we don't need a phi for it
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-8 (param $x i32) (param $y i32) (result i32)
+    (local $z i32)
+    (local $w i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $z (local.get $x))
+      (local.set $w (local.get $y))
+      (local.set $x (i32.const 1)) ;; same!
+      (local.set $y (i32.const 4)) ;; different!
+      (br_if $loopy (local.get $y))
+    )
+    ;; x is always 3, and y needs a phi.
+    ;; each is also copied to another local, which we need
+    ;; to handle properly
+    (return
+      (i32.mul
+        (i32.add
+          (local.get $x)
+          (local.get $y)
+        )
+        (i32.sub
+          (local.get $z)
+          (local.get $w)
+        )
+      )
+    )
+  )
+  (func $loop-9 (param $x i32) (param $y i32) (result i32)
+    (local $t i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (loop $loopy
+      (local.set $t (local.get $x))
+      (local.set $x (local.get $y))
+      (local.set $y (local.get $t))
+      (br_if $loopy (local.get $t))
+    )
+    ;; x and y swapped, so both need phis
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-10 (param $x i32) (param $y i32) (result i32)
+    (local $t i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 1))
+    (loop $loopy ;; we swap the values. but we need a deeper analysis to figure that out...
+      (local.set $t (local.get $x))
+      (local.set $x (local.get $y))
+      (local.set $y (local.get $t))
+      (br_if $loopy (local.get $t))
+    )
+    ;; x and y swapped, but the same constant was swapped
+    (return (i32.add (local.get $x) (local.get $y)))
+  )
+  (func $loop-multicond-1 (param $x i32) (param $y i32) (param $z i32) (result i32)
+    (local $t i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (local.set $z (i32.const 3))
+    (loop $loopy
+      (local.set $x (i32.const 4))
+      (br_if $loopy (local.get $t))
+      (local.set $y (i32.const 5))
+      (br_if $loopy (local.get $t))
+      (local.set $z (i32.const 6))
+    )
+    (return (select (local.get $x) (local.get $y) (local.get $z)))
+  )
+  (func $loop-multicond-2 (param $x i32) (param $y i32) (param $z i32) (result i32)
+    (local $t i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (local.set $z (i32.const 3))
+    (loop $loopy
+      (local.set $x (i32.add (local.get $x) (i32.const 4)))
+      (br_if $loopy (local.get $t))
+      (local.set $y (i32.add (local.get $y) (i32.const 5)))
+      (br_if $loopy (local.get $t))
+      (local.set $z (i32.add (local.get $z) (i32.const 6)))
+    )
+    (return (select (local.get $x) (local.get $y) (local.get $z)))
+  )
+  (func $loop-block-1 (param $x i32) (param $y i32) (param $z i32) (result i32)
+    (local $t i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (local.set $z (i32.const 3))
+    (loop $loopy
+      (block $out
+        (local.set $x (i32.add (local.get $x) (i32.const 4)))
+        (br_if $out (local.get $t))
+        (local.set $y (i32.add (local.get $y) (i32.const 5)))
+        (br_if $out (local.get $t))
+        (local.set $z (i32.add (local.get $z) (i32.const 6)))
+        (br $loopy)
+      )
+    )
+    (return (select (local.get $x) (local.get $y) (local.get $z)))
+  )
+  (func $loop-block-2 (param $x i32) (param $y i32) (param $z i32) (result i32)
+    (local $t i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (i32.const 2))
+    (local.set $z (i32.const 3))
+    (block $out
+      (loop $loopy
+        (local.set $x (i32.add (local.get $x) (i32.const 4)))
+        (br_if $out (local.get $t))
+        (local.set $y (i32.add (local.get $y) (i32.const 5)))
+        (br_if $out (local.get $t))
+        (local.set $z (i32.add (local.get $z) (i32.const 6)))
+        (br $loopy)
+      )
+    )
+    (return (select (local.get $x) (local.get $y) (local.get $z)))
+  )
+  (func $bad-phi-type (param $var$0 i64) (param $var$1 i64) (param $var$2 i32) (param $var$3 f32)
+   (if
+    (local.get $var$2)
+    (drop
+     (loop $label$2 (result f64)
+      (if
+       (block $label$3 (result i32)
+        (if
+         (i32.const 0)
+         (unreachable)
+        )
+        (nop)
+        (i32.const 0)
+       )
+       (unreachable)
+      )
+      (br_if $label$2
+       (local.get $var$2)
+      )
+      (f64.const 0)
+     )
+    )
+   )
+  )
+  (func $loop-unreachable
+   (local $var$0 i32)
+   (local $var$1 f64)
+   (loop $label$1
+    (local.set $var$1
+     (block $label$2 (result f64)
+      (block $label$3
+       (local.set $var$0
+        (block $label$4 (result i32)
+         (if
+          (i32.const 1337)
+          (unreachable)
+         )
+         (local.get $var$0)
+        )
+       )
+       (loop $label$6
+        (br_if $label$6
+         (block $label$7 (result i32)
+          (drop
+           (br_if $label$7
+            (local.get $var$0)
+            (i32.const 65535)
+           )
+          )
+          (drop
+           (br_if $label$7
+            (local.get $var$0)
+            (i32.const 0)
+           )
+          )
+          (unreachable)
+         )
+        )
+       )
+      )
+      (local.get $var$1)
+     )
+    )
+    (br $label$1)
+   )
+  )
+  (func $phi-value-turns-bad (result f64)
+   (local $var$0 i32)
+   (local $var$1 i32)
+   (local $var$2 f32)
+   (local.set $var$2
+    (if (result f32)
+     (local.tee $var$0
+      (i32.atomic.rmw16.sub_u offset=22
+       (i32.const 0)
+       (i32.const 0)
+      )
+     )
+     (unreachable)
+     (block (result f32)
+      (if
+       (loop $label$3 (result i32)
+        (block $label$4 (result i32)
+         (i32.clz
+          (br_if $label$4
+           (local.get $var$0)
+           (i32.const 1)
+          )
+         )
+        )
+       )
+       (nop)
+      )
+      (f32.const 1)
+     )
+    )
+   )
+   (unreachable)
+  )
+  (func $multi-use (param $x i32) (result i32)
+    (local $temp i32)
+    (local.set $temp (i32.add (local.get $x) (i32.const 1)))
+    (i32.add (local.get $temp) (local.get $temp))
+  )
+  (func $multi-use-2 (param $x i32) (result i32)
+    (local $temp i32)
+    (local.set $temp (i32.add (local.get $x) (i32.const 1)))
+    (local.set $x (i32.mul (local.get $temp) (i32.const 2)))
+    (i32.sub (local.get $x) (local.get $temp))
+  )
+  (func $many-single-uses-with-param (param $x i32) (result i32)
+    (return
+      (i32.eqz
+        (i32.add
+          (i32.mul
+            (i32.const 10)
+            (local.get $x)
+          )
+          (i32.sub
+            (i32.ctz
+              (local.get $x)
+            )
+            (i32.const 20)
+          )
+        )
+      )
+    )
+  )
+ (func "replaced-print-internal" (param $var$0 i32)
+  (local $var$1 i32)
+  (local $var$2 i32)
+  (local $var$3 i32)
+  (if
+   (local.tee $var$0
+    (i32.add
+     (local.get $var$0)
+     (i32.const -7)
+    )
+   )
+   (block $label$2
+    (block $label$3
+     (local.set $var$1
+      (local.get $var$0)
+     )
+     (br_if $label$3
+      (local.tee $var$3
+       (i32.const 12)
+      )
+     )
+     (unreachable)
+    )
+    (br_if $label$2
+     (i32.eqz
+      (local.get $var$1)
+     )
+    )
+    (if
+     (i32.ne
+      (i32.load
+       (i32.const 0)
+      )
+      (local.get $var$0)
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+ )
+ (func $multiple-uses-to-non-expression (param $x i32)
+  (local $temp i32)
+  (local.set $x
+   (i32.add
+    (local.get $x)
+    (i32.const 10)
+   )
+  )
+  (i32.store
+   (i32.const 1)
+   (local.get $x) ;; x+10 has two uses!
+  )
+  (i32.store
+   (i32.const 2)
+   (i32.add
+    (local.get $x)
+    (i32.const 20)
+   )
+  )
+ )
+ (func $nested-phi-forwarding (param $var$0 i32) (result i32)
+  (local $var$1 i32)
+  (local $var$2 i32)
+  (block $label$1
+   (block $label$2
+    (loop $label$3
+     (block $label$4
+      (block $label$5
+       (block $label$6
+        (block $label$7
+         (block $label$8
+          (br_table $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$8 $label$2 $label$2 $label$2 $label$6 $label$2 $label$2 $label$7 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$2 $label$5 $label$4
+           (local.get $var$0)
+          )
+         )
+         (local.set $var$1
+          (i32.const 1)
+         )
+        )
+        (br $label$4)
+       )
+       (unreachable)
+      )
+      (br $label$1)
+     )
+     (br_if $label$3
+      (local.tee $var$2
+       (i32.const 1)
+      )
+     )
+    )
+   )
+   (block $label$9
+    (br_if $label$9
+     (i32.or
+      (i32.const 1)
+      (local.get $var$1)
+     )
+    )
+   )
+   (unreachable)
+  )
+  (i32.store offset=176
+   (i32.const 0)
+   (local.get $var$2)
+  )
+  (i32.const 0)
+ )
+ (func $zext-numGets (param $var$0 i32) (param $var$1 i32)
+  (if
+   (i32.ctz
+    (block $label$1 (result i32)
+     (drop
+      (br_if $label$1
+       (i32.const 1)
+       (i32.load
+        (i32.const -8)
+       )
+      )
+     )
+     (i32.eqz
+      (i32.load
+       (i32.const -16)
+      )
+     )
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $zext-numGets-hasAnotherUse (param $var$0 i32) (param $var$1 i32)
+  (local $temp i32)
+  (if
+   (i32.ctz
+    (block $label$1 (result i32)
+     (drop
+      (br_if $label$1
+       (i32.const 1)
+       (i32.load
+        (i32.const -8)
+       )
+      )
+     )
+     (local.set $temp
+      (i32.eqz
+       (i32.load
+        (i32.const -16)
+       )
+      )
+     )
+     (drop
+      (local.get $temp)
+     )
+     (local.get $temp)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $flipped-needs-right-origin (param $var$0 i32) (result i32)
+  (local $var$1 i32)
+  (block $label$1
+   (br_if $label$1
+    (i32.load
+     (i32.const 1)
+    )
+   )
+   (local.set $var$1
+    (i32.const 2)
+   )
+  )
+  (if
+   (i32.gt_s
+    (i32.const 3)
+    (i32.add
+     (local.get $var$1)
+     (i32.const 4)
+    )
+   )
+   (unreachable)
+  )
+  (i32.const 5)
+ )
+ (func $non-expr-nodes-may-have-multiple-uses-too-its-the-ORIGIN (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (result i32)
+  (i32.store
+   (local.tee $var$1
+    (i32.gt_u
+     (local.get $var$1)
+     (i32.const 1)
+    )
+   )
+   (i32.const 2)
+  )
+  (i32.store offset=8
+   (i32.const 3)
+   (i32.sub
+    (i32.const 4)
+    (local.get $var$1)
+   )
+  )
+  (unreachable)
+ )
+ (func $loop-of-set-connections (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (param $var$3 i32) (param $var$4 i32) (result i32)
+  (loop $label$1
+   (if
+    (i32.const 0)
+    (block
+     (local.set $var$2
+      (i32.add
+       (i32.const 0)
+       (i32.const 1)
+      )
+     )
+     (br $label$1)
+    )
+   )
+   (local.set $var$3
+    (local.get $var$2)
+   )
+   (local.set $var$2
+    (local.get $var$3)
+   )
+   (br $label$1)
+  )
+ )
+ (func $conditions-in-conditions (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (result i32)
+  (local $var$3 i32)
+  (local $var$4 i32)
+  (local $var$5 i32)
+  (local $var$6 i32)
+  (local $var$7 i32)
+  (local $var$8 i32)
+  (local.set $var$1
+   (i32.const 1)
+  )
+  (if
+   (i32.const 0)
+   (loop $label$2
+    (if
+     (local.get $var$1)
+     (nop)
+    )
+    (local.set $var$1
+     (i32.sub
+      (i32.const 0)
+      (local.tee $var$3
+       (i32.const 1)
+      )
+     )
+    )
+    (br_if $label$2
+     (i32.const 0)
+    )
+   )
+  )
+  (if
+   (local.get $var$1)
+   (local.set $var$3
+    (i32.const 1)
+   )
+  )
+  (i32.store
+   (i32.const 8)
+   (i32.add
+    (local.get $var$3)
+    (i32.const 16)
+   )
+  )
+  (i32.store
+   (i32.const 8)
+   (i32.const 64)
+  )
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/passes/fpcast-emu.txt b/binaryen/test/passes/fpcast-emu.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fpcast-emu.txt
@@ -0,0 +1,312 @@
+(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 $i32_i64_f32_f64_=>_none (func (param i32 i64 f32 f64)))
+ (type $f64_f64_=>_i32 (func (param f64 f64) (result i32)))
+ (type $i32_i32_=>_i64 (func (param i32 i32) (result i64)))
+ (type $i32_i64_f32_f64_=>_f32 (func (param i32 i64 f32 f64) (result f32)))
+ (type $i64_i64_=>_f32 (func (param i64 i64) (result f32)))
+ (type $f32_f32_=>_f64 (func (param f32 f32) (result f64)))
+ (import "env" "imported_func" (func $imported-func (param i32 i64 f32 f64) (result f32)))
+ (table $0 10 10 funcref)
+ (elem (i32.const 0) $byn$fpcast-emu$a $byn$fpcast-emu$b $byn$fpcast-emu$c $byn$fpcast-emu$d $byn$fpcast-emu$e $byn$fpcast-emu$e $byn$fpcast-emu$imported-func)
+ (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_i64_i64_i64_i64_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)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i32.const 1337)
+   )
+  )
+ )
+ (func $b (param $x i32) (param $y i32) (result i64)
+  (call_indirect (type $i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_=>_i64)
+   (i64.extend_i32_u
+    (i32.const 1)
+   )
+   (i64.extend_i32_u
+    (i32.const 2)
+   )
+   (i64.const 0)
+   (i64.const 0)
+   (i64.const 0)
+   (i64.const 0)
+   (i64.const 0)
+   (i64.const 0)
+   (i64.const 0)
+   (i64.const 0)
+   (i64.const 0)
+   (i64.const 0)
+   (i64.const 0)
+   (i64.const 0)
+   (i64.const 0)
+   (i64.const 0)
+   (i32.const 1337)
+  )
+ )
+ (func $c (param $x i64) (param $y i64) (result f32)
+  (f32.reinterpret_i32
+   (i32.wrap_i64
+    (call_indirect (type $i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_=>_i64)
+     (i64.const 1)
+     (i64.const 2)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i32.const 1337)
+    )
+   )
+  )
+ )
+ (func $d (param $x f32) (param $y f32) (result f64)
+  (f64.reinterpret_i64
+   (call_indirect (type $i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_=>_i64)
+    (i64.extend_i32_u
+     (i32.reinterpret_f32
+      (f32.const 1)
+     )
+    )
+    (i64.extend_i32_u
+     (i32.reinterpret_f32
+      (f32.const 2)
+     )
+    )
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i32.const 1337)
+   )
+  )
+ )
+ (func $e (param $x f64) (param $y f64) (result i32)
+  (i32.wrap_i64
+   (call_indirect (type $i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_=>_i64)
+    (i64.reinterpret_f64
+     (f64.const 1)
+    )
+    (i64.reinterpret_f64
+     (f64.const 2)
+    )
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (i64.const 0)
+    (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) (param $5 i64) (param $6 i64) (param $7 i64) (param $8 i64) (param $9 i64) (param $10 i64) (param $11 i64) (param $12 i64) (param $13 i64) (param $14 i64) (param $15 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)
+ )
+ (func $byn$fpcast-emu$b (param $0 i64) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (param $5 i64) (param $6 i64) (param $7 i64) (param $8 i64) (param $9 i64) (param $10 i64) (param $11 i64) (param $12 i64) (param $13 i64) (param $14 i64) (param $15 i64) (result i64)
+  (call $b
+   (i32.wrap_i64
+    (local.get $0)
+   )
+   (i32.wrap_i64
+    (local.get $1)
+   )
+  )
+ )
+ (func $byn$fpcast-emu$c (param $0 i64) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (param $5 i64) (param $6 i64) (param $7 i64) (param $8 i64) (param $9 i64) (param $10 i64) (param $11 i64) (param $12 i64) (param $13 i64) (param $14 i64) (param $15 i64) (result i64)
+  (i64.extend_i32_u
+   (i32.reinterpret_f32
+    (call $c
+     (local.get $0)
+     (local.get $1)
+    )
+   )
+  )
+ )
+ (func $byn$fpcast-emu$d (param $0 i64) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (param $5 i64) (param $6 i64) (param $7 i64) (param $8 i64) (param $9 i64) (param $10 i64) (param $11 i64) (param $12 i64) (param $13 i64) (param $14 i64) (param $15 i64) (result i64)
+  (i64.reinterpret_f64
+   (call $d
+    (f32.reinterpret_i32
+     (i32.wrap_i64
+      (local.get $0)
+     )
+    )
+    (f32.reinterpret_i32
+     (i32.wrap_i64
+      (local.get $1)
+     )
+    )
+   )
+  )
+ )
+ (func $byn$fpcast-emu$e (param $0 i64) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (param $5 i64) (param $6 i64) (param $7 i64) (param $8 i64) (param $9 i64) (param $10 i64) (param $11 i64) (param $12 i64) (param $13 i64) (param $14 i64) (param $15 i64) (result i64)
+  (i64.extend_i32_u
+   (call $e
+    (f64.reinterpret_i64
+     (local.get $0)
+    )
+    (f64.reinterpret_i64
+     (local.get $1)
+    )
+   )
+  )
+ )
+ (func $byn$fpcast-emu$imported-func (param $0 i64) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (param $5 i64) (param $6 i64) (param $7 i64) (param $8 i64) (param $9 i64) (param $10 i64) (param $11 i64) (param $12 i64) (param $13 i64) (param $14 i64) (param $15 i64) (result i64)
+  (i64.extend_i32_u
+   (i32.reinterpret_f32
+    (call $imported-func
+     (i32.wrap_i64
+      (local.get $0)
+     )
+     (local.get $1)
+     (f32.reinterpret_i32
+      (i32.wrap_i64
+       (local.get $2)
+      )
+     )
+     (f64.reinterpret_i64
+      (local.get $3)
+     )
+    )
+   )
+  )
+ )
+)
+(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)))
+ (table $0 42 42 funcref)
+ (global $global$0 (mut i32) (i32.const 10))
+ (export "func_106" (func $0))
+ (func $0 (param $0 f32) (result i64)
+  (block $label$1 (result i64)
+   (loop $label$2
+    (global.set $global$0
+     (i32.const 0)
+    )
+    (call_indirect (type $i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_=>_i64)
+     (br $label$1
+      (i64.const 4294967295)
+     )
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i64.const 0)
+     (i32.const 18)
+    )
+   )
+  )
+ )
+)
+(module
+ (type $f32_=>_none (func (param f32)))
+ (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 $f64_=>_none (func (param f64)))
+ (table $0 42 42 funcref)
+ (elem (i32.const 0) $byn$fpcast-emu$a $byn$fpcast-emu$b)
+ (export "dynCall_vf" (func $dynCall_vf))
+ (export "dynCall_vd" (func $min_vd))
+ (func $a (param $0 f32)
+  (nop)
+ )
+ (func $b (param $0 f64)
+  (nop)
+ )
+ (func $dynCall_vf (param $0 f32)
+  (nop)
+ )
+ (func $min_vd (param $0 f32)
+  (nop)
+ )
+ (func $byn$fpcast-emu$a (param $0 i64) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (param $5 i64) (param $6 i64) (param $7 i64) (param $8 i64) (param $9 i64) (param $10 i64) (param $11 i64) (param $12 i64) (param $13 i64) (param $14 i64) (param $15 i64) (result i64)
+  (call $a
+   (f32.reinterpret_i32
+    (i32.wrap_i64
+     (local.get $0)
+    )
+   )
+  )
+  (i64.const 0)
+ )
+ (func $byn$fpcast-emu$b (param $0 i64) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (param $5 i64) (param $6 i64) (param $7 i64) (param $8 i64) (param $9 i64) (param $10 i64) (param $11 i64) (param $12 i64) (param $13 i64) (param $14 i64) (param $15 i64) (result i64)
+  (call $b
+   (f64.reinterpret_i64
+    (local.get $0)
+   )
+  )
+  (i64.const 0)
+ )
+)
diff --git a/binaryen/test/passes/fpcast-emu.wast b/binaryen/test/passes/fpcast-emu.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fpcast-emu.wast
@@ -0,0 +1,80 @@
+(module
+  (type $vijfd (func (param i32) (param i64) (param f32) (param f64)))
+  (type $jii (func (param i32) (param i32) (result i64)))
+  (type $fjj (func (param i64) (param i64) (result f32)))
+  (type $dff (func (param f32) (param f32) (result f64)))
+  (type $idd (func (param f64) (param f64) (result i32)))
+  (import "env" "imported_func" (func $imported-func (param i32 i64 f32 f64) (result f32)))
+  (table 10 10 funcref)
+  (elem (i32.const 0) $a $b $c $d $e $e $imported-func)
+  (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)
+    )
+  )
+  (func $b (param $x i32) (param $y i32) (result i64)
+    (call_indirect (type $jii)
+      (i32.const 1)
+      (i32.const 2)
+      (i32.const 1337)
+    )
+  )
+  (func $c (param $x i64) (param $y i64) (result f32)
+    (call_indirect (type $fjj)
+      (i64.const 1)
+      (i64.const 2)
+      (i32.const 1337)
+    )
+  )
+  (func $d (param $x f32) (param $y f32) (result f64)
+    (call_indirect (type $dff)
+      (f32.const 1)
+      (f32.const 2)
+      (i32.const 1337)
+    )
+  )
+  (func $e (param $x f64) (param $y f64) (result i32)
+    (call_indirect (type $idd)
+      (f64.const 1)
+      (f64.const 2)
+      (i32.const 1337)
+    )
+  )
+)
+(module
+ (type $0 (func (param i64)))
+ (type $1 (func (param f32) (result i64)))
+ (global $global$0 (mut i32) (i32.const 10))
+ (table 42 42 funcref)
+ (export "func_106" (func $0))
+ (func $0 (; 0 ;) (type $1) (param $0 f32) (result i64)
+  (block $label$1 (result i64)
+   (loop $label$2
+    (global.set $global$0
+     (i32.const 0)
+    )
+    (call_indirect (type $0)
+     (br $label$1
+      (i64.const 4294967295)
+     )
+     (i32.const 18)
+    )
+   )
+  )
+ )
+)
+(module
+ (table 42 42 funcref)
+ (elem (i32.const 0) $a $b)
+ (export "dynCall_vf" (func $dynCall_vf))
+ (export "dynCall_vd" (func $min_vd))
+ (func $a (param $0 f32))
+ (func $b (param $0 f64))
+ (func $dynCall_vf (param $0 f32))
+ (func $min_vd (param $0 f32))
+)
+
diff --git a/binaryen/test/passes/func-metrics.txt b/binaryen/test/passes/func-metrics.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/func-metrics.txt
@@ -0,0 +1,260 @@
+global
+ [events]       : 0       
+ [exports]      : 0       
+ [funcs]        : 3       
+ [globals]      : 1       
+ [imports]      : 0       
+ [memory-data]  : 9       
+ [table-data]   : 3       
+ [total]        : 3       
+ const          : 3       
+func: empty
+ [binary-bytes] : 3       
+ [total]        : 1       
+ [vars]         : 0       
+ nop            : 1       
+func: small
+ [binary-bytes] : 9       
+ [total]        : 5       
+ [vars]         : 0       
+ block          : 1       
+ const          : 1       
+ drop           : 1       
+ nop            : 1       
+ return         : 1       
+func: ifs
+ [binary-bytes] : 51      
+ [total]        : 24      
+ [vars]         : 1       
+ binary         : 1       
+ block          : 1       
+ const          : 12      
+ drop           : 6       
+ if             : 4       
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (memory $0 256 256)
+ (data (i32.const 0) "\ff\ef\0f\1f 0@P\99")
+ (table $0 256 256 funcref)
+ (elem (i32.const 0) $ifs $ifs $ifs)
+ (global $glob i32 (i32.const 1337))
+ (func $empty
+  (nop)
+ )
+ (func $small
+  (nop)
+  (drop
+   (i32.const 100421)
+  )
+  (return)
+ )
+ (func $ifs (param $x i32)
+  (local $y f32)
+  (block $block0
+   (if
+    (i32.const 0)
+    (drop
+     (i32.const 1)
+    )
+   )
+   (if
+    (i32.const 0)
+    (drop
+     (i32.const 1)
+    )
+    (drop
+     (i32.const 2)
+    )
+   )
+   (if
+    (i32.const 4)
+    (drop
+     (i32.const 5)
+    )
+    (drop
+     (i32.const 6)
+    )
+   )
+   (drop
+    (i32.eq
+     (if (result i32)
+      (i32.const 4)
+      (i32.const 5)
+      (i32.const 6)
+     )
+     (i32.const 177)
+    )
+   )
+  )
+ )
+)
+global
+ [events]       : 0       
+ [exports]      : 0       
+ [funcs]        : 0       
+ [globals]      : 0       
+ [imports]      : 0       
+ [total]        : 0       
+(module
+)
+global
+ [events]       : 0       
+ [exports]      : 2       
+ [funcs]        : 3       
+ [globals]      : 0       
+ [imports]      : 1       
+ [total]        : 0       
+func: func_a
+ [binary-bytes] : 16      
+ [total]        : 8       
+ [vars]         : 0       
+ block          : 1       
+ call           : 7       
+func: func_b
+ [binary-bytes] : 22      
+ [total]        : 11      
+ [vars]         : 0       
+ block          : 1       
+ call           : 10      
+func: func_c
+ [binary-bytes] : 32      
+ [total]        : 16      
+ [vars]         : 0       
+ block          : 1       
+ call           : 15      
+export: a (func_a)
+ [removable-bytes-without-it]: 72      
+ [total]        : 0       
+export: b (func_b)
+ [removable-bytes-without-it]: 18      
+ [total]        : 0       
+(module
+ (type $none_=>_none (func))
+ (import "env" "waka" (func $waka))
+ (export "a" (func $func_a))
+ (export "b" (func $func_b))
+ (func $func_a
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $func_b)
+  (call $func_c)
+ )
+ (func $func_b
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+ )
+ (func $func_c
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+ )
+)
+global
+ [events]       : 0       
+ [exports]      : 1       
+ [funcs]        : 1       
+ [globals]      : 0       
+ [imports]      : 1       
+ [total]        : 0       
+func: func_a
+ [binary-bytes] : 12      
+ [total]        : 6       
+ [vars]         : 0       
+ block          : 1       
+ call           : 5       
+export: a (func_a)
+ [removable-bytes-without-it]: 7       
+ [total]        : 0       
+start: func_a
+ [removable-bytes-without-it]: 3       
+ [total]        : 0       
+(module
+ (type $none_=>_none (func))
+ (import "env" "waka" (func $waka))
+ (export "a" (func $func_a))
+ (start $func_a)
+ (func $func_a
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+ )
+)
+global
+ [events]       : 0       
+ [exports]      : 0       
+ [funcs]        : 1       
+ [globals]      : 0       
+ [imports]      : 1       
+ [total]        : 0       
+func: func_a
+ [binary-bytes] : 12      
+ [total]        : 6       
+ [vars]         : 0       
+ block          : 1       
+ call           : 5       
+start: func_a
+ [removable-bytes-without-it]: 57      
+ [total]        : 0       
+(module
+ (type $none_=>_none (func))
+ (import "env" "waka" (func $waka))
+ (start $func_a)
+ (func $func_a
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+ )
+)
+global
+ [events]       : 0       
+ [exports]      : 1       
+ [funcs]        : 1       
+ [globals]      : 1       
+ [imports]      : 1       
+ [total]        : 1       
+ global.get     : 1       
+func: 0
+ [binary-bytes] : 4       
+ [total]        : 1       
+ [vars]         : 0       
+ global.get     : 1       
+export: stackSave (0)
+ [removable-bytes-without-it]: 70      
+ [total]        : 0       
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "STACKTOP" (global $gimport$0 i32))
+ (global $global$0 (mut i32) (global.get $gimport$0))
+ (export "stackSave" (func $0))
+ (func $0 (result i32)
+  (global.get $global$0)
+ )
+)
diff --git a/binaryen/test/passes/func-metrics.wast b/binaryen/test/passes/func-metrics.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/func-metrics.wast
@@ -0,0 +1,134 @@
+(module
+  (memory 256 256)
+  (table 256 256 funcref)
+  (elem (i32.const 0) $ifs $ifs $ifs)
+  (data (i32.const 0) "\ff\ef\0f\1f\20\30\40\50\99")
+  (type $0 (func (param i32)))
+  (global $glob i32 (i32.const 1337))
+  (func $empty)
+  (func $small
+    (nop)
+    (drop (i32.const 100421))
+    (return)
+  )
+  (func $ifs (type $0) (param $x i32)
+    (local $y f32)
+    (block $block0
+      (if
+        (i32.const 0)
+        (drop
+          (i32.const 1)
+        )
+      )
+      (if
+        (i32.const 0)
+        (drop
+          (i32.const 1)
+        )
+        (drop
+          (i32.const 2)
+        )
+      )
+      (if
+        (i32.const 4)
+        (drop
+          (i32.const 5)
+        )
+        (drop
+          (i32.const 6)
+        )
+      )
+      (drop
+        (i32.eq
+          (if (result i32)
+            (i32.const 4)
+            (i32.const 5)
+            (i32.const 6)
+          )
+          (i32.const 177)
+        )
+      )
+    )
+  )
+)
+;; module with no table or memory or anything for that matter
+(module
+)
+;; export size checking
+(module
+ (import "env" "waka" (func $waka))
+ (export "a" (func $func_a))
+ (export "b" (func $func_b))
+ (func $func_a
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $func_b)
+  (call $func_c)
+ )
+ (func $func_b
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+ )
+ (func $func_c
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+ )
+)
+;; start size checking
+(module
+ (import "env" "waka" (func $waka))
+ (export "a" (func $func_a))
+ (start $func_a)
+ (func $func_a
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+ )
+)
+(module
+ (import "env" "waka" (func $waka))
+ (start $func_a)
+ (func $func_a
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+  (call $waka)
+ )
+)
+(module ;; various globals
+ (type $0 (func (result i32)))
+ (import "env" "STACKTOP" (global $gimport$0 i32))
+ (global $global$0 (mut i32) (global.get $gimport$0))
+ (export "stackSave" (func $0))
+ (func $0 (; 0 ;) (type $0) (result i32)
+  (global.get $global$0)
+ )
+)
+
diff --git a/binaryen/test/passes/fuzz-exec_O.txt b/binaryen/test/passes/fuzz-exec_O.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fuzz-exec_O.txt
@@ -0,0 +1,95 @@
+[fuzz-exec] calling func_0
+[trap final > memory: 18446744073709551615 > 65514]
+[fuzz-exec] calling func_1
+[trap final > memory: 18446744073709551615 > 65514]
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_i64 (func (result i64)))
+ (memory $0 1 1)
+ (export "func_0" (func $func_0))
+ (export "func_1" (func $func_1))
+ (func $func_0 (; has Stack IR ;) (result i64)
+  (block $label$0 (result i64)
+   (br_if $label$0
+    (i64.const 1234)
+    (i32.load16_s offset=22 align=1
+     (i32.const -1)
+    )
+   )
+  )
+ )
+ (func $func_1 (; has Stack IR ;) (result i32)
+  (i32.load16_s offset=22 align=1
+   (i32.const -1)
+  )
+ )
+)
+[fuzz-exec] calling func_0
+[trap final > memory: 18446744073709551615 > 65514]
+[fuzz-exec] calling func_1
+[trap final > memory: 18446744073709551615 > 65514]
+[fuzz-exec] comparing func_0
+[fuzz-exec] comparing func_1
+[fuzz-exec] calling div
+[fuzz-exec] note result: div => -nan:0x63017a
+[fuzz-exec] calling mul1
+[fuzz-exec] note result: mul1 => -nan:0x74546d
+[fuzz-exec] calling mul2
+[fuzz-exec] note result: mul2 => -nan:0x74546d
+[fuzz-exec] calling add1
+[fuzz-exec] note result: add1 => -nan:0x74546d
+[fuzz-exec] calling add2
+[fuzz-exec] note result: add2 => -nan:0x74546d
+[fuzz-exec] calling add3
+[fuzz-exec] note result: add3 => -nan:0x74546d
+[fuzz-exec] calling add4
+[fuzz-exec] note result: add4 => -nan:0x74546d
+[fuzz-exec] calling sub1
+[fuzz-exec] note result: sub1 => -nan:0x74546d
+[fuzz-exec] calling sub2
+[fuzz-exec] note result: sub2 => -nan:0x74546d
+(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))
+ (func $0 (; has Stack IR ;) (result f32)
+  (f32.const -nan:0x63017a)
+ )
+ (func $1 (; has Stack IR ;) (result f32)
+  (f32.const -nan:0x74546d)
+ )
+)
+[fuzz-exec] calling div
+[fuzz-exec] note result: div => -nan:0x63017a
+[fuzz-exec] calling mul1
+[fuzz-exec] note result: mul1 => -nan:0x74546d
+[fuzz-exec] calling mul2
+[fuzz-exec] note result: mul2 => -nan:0x74546d
+[fuzz-exec] calling add1
+[fuzz-exec] note result: add1 => -nan:0x74546d
+[fuzz-exec] calling add2
+[fuzz-exec] note result: add2 => -nan:0x74546d
+[fuzz-exec] calling add3
+[fuzz-exec] note result: add3 => -nan:0x74546d
+[fuzz-exec] calling add4
+[fuzz-exec] note result: add4 => -nan:0x74546d
+[fuzz-exec] calling sub1
+[fuzz-exec] note result: sub1 => -nan:0x74546d
+[fuzz-exec] calling sub2
+[fuzz-exec] note result: sub2 => -nan:0x74546d
+[fuzz-exec] comparing add1
+[fuzz-exec] comparing add2
+[fuzz-exec] comparing add3
+[fuzz-exec] comparing add4
+[fuzz-exec] comparing div
+[fuzz-exec] comparing mul1
+[fuzz-exec] comparing mul2
+[fuzz-exec] comparing sub1
+[fuzz-exec] comparing sub2
diff --git a/binaryen/test/passes/fuzz-exec_O.wast b/binaryen/test/passes/fuzz-exec_O.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fuzz-exec_O.wast
@@ -0,0 +1,78 @@
+(module
+ (memory $0 1 1)
+ (export "func_0" (func $func_0))
+ (export "func_1" (func $func_1))
+ (func $func_0 (result i64)
+  (block $label$0 (result i64)
+   (loop $label$1 (result i64)
+    (br_if $label$0
+     (i64.const 1234)
+     (i32.load16_s offset=22 align=1
+      (i32.const -1)
+     )
+    )
+   )
+  )
+ )
+ (func $func_1 (result i32)
+  (i32.load16_s offset=22 align=1
+   (i32.const -1)
+  )
+ )
+)
+(module
+ (func "div" (result f32)
+  (f32.div
+   (f32.const -nan:0x23017a)
+   (f32.const 1)
+  )
+ )
+ (func "mul1" (result f32)
+  (f32.mul
+   (f32.const -nan:0x34546d)
+   (f32.const 1)
+  )
+ )
+ (func "mul2" (result f32)
+  (f32.mul
+   (f32.const 1)
+   (f32.const -nan:0x34546d)
+  )
+ )
+ (func "add1" (result f32)
+  (f32.add
+   (f32.const -nan:0x34546d)
+   (f32.const -0)
+  )
+ )
+ (func "add2" (result f32)
+  (f32.add
+   (f32.const -0)
+   (f32.const -nan:0x34546d)
+  )
+ )
+ (func "add3" (result f32)
+  (f32.add
+   (f32.const -nan:0x34546d)
+   (f32.const 0)
+  )
+ )
+ (func "add4" (result f32)
+  (f32.add
+   (f32.const 0)
+   (f32.const -nan:0x34546d)
+  )
+ )
+ (func "sub1" (result f32)
+  (f32.sub
+   (f32.const -nan:0x34546d)
+   (f32.const 0)
+  )
+ )
+ (func "sub2" (result f32)
+  (f32.sub
+   (f32.const -nan:0x34546d)
+   (f32.const -0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/fuzz-exec_all-features.txt b/binaryen/test/passes/fuzz-exec_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fuzz-exec_all-features.txt
@@ -0,0 +1,209 @@
+[fuzz-exec] calling a
+[fuzz-exec] note result: a => -69
+[fuzz-exec] calling b
+[fuzz-exec] note result: b => -31768
+[fuzz-exec] calling c
+[fuzz-exec] note result: c => -69
+[fuzz-exec] calling d
+[fuzz-exec] note result: d => -31768
+[fuzz-exec] calling e
+[fuzz-exec] note result: e => -2146649112
+(module
+ (type $none_=>_i64 (func (result i64)))
+ (type $none_=>_i32 (func (result i32)))
+ (export "a" (func $a))
+ (export "b" (func $b))
+ (export "c" (func $c))
+ (export "d" (func $d))
+ (export "e" (func $e))
+ (func $a (result i32)
+  (i32.extend8_s
+   (i32.const 187)
+  )
+ )
+ (func $b (result i32)
+  (i32.extend16_s
+   (i32.const 33768)
+  )
+ )
+ (func $c (result i64)
+  (i64.extend8_s
+   (i64.const 187)
+  )
+ )
+ (func $d (result i64)
+  (i64.extend16_s
+   (i64.const 33768)
+  )
+ )
+ (func $e (result i64)
+  (i64.extend32_s
+   (i64.const 2148318184)
+  )
+ )
+)
+[fuzz-exec] calling a
+[fuzz-exec] note result: a => -69
+[fuzz-exec] calling b
+[fuzz-exec] note result: b => -31768
+[fuzz-exec] calling c
+[fuzz-exec] note result: c => -69
+[fuzz-exec] calling d
+[fuzz-exec] note result: d => -31768
+[fuzz-exec] calling e
+[fuzz-exec] note result: e => -2146649112
+[fuzz-exec] comparing a
+[fuzz-exec] comparing b
+[fuzz-exec] comparing c
+[fuzz-exec] comparing d
+[fuzz-exec] comparing e
+[fuzz-exec] calling unaligned_load
+[trap unaligned atomic operation]
+[fuzz-exec] calling unaligned_load_offset
+[trap unaligned atomic operation]
+[fuzz-exec] calling aligned_for_size
+[fuzz-exec] note result: aligned_for_size => 0
+[fuzz-exec] calling unaligned_notify
+[trap unaligned atomic operation]
+[fuzz-exec] calling wrap_cmpxchg
+[LoggingExternalInterface logging 42]
+[fuzz-exec] calling oob_notify
+[trap final > memory: 18446744073709551512 > 65514]
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (import "fuzzing-support" "log-i32" (func $fimport$0 (param i32)))
+ (memory $0 (shared 1 1))
+ (export "unaligned_load" (func $0))
+ (export "unaligned_load_offset" (func $1))
+ (export "aligned_for_size" (func $2))
+ (export "unaligned_notify" (func $3))
+ (export "wrap_cmpxchg" (func $4))
+ (export "oob_notify" (func $5))
+ (func $0 (result i32)
+  (i32.atomic.load
+   (i32.const 1)
+  )
+ )
+ (func $1 (result i32)
+  (i32.atomic.load offset=1
+   (i32.const 0)
+  )
+ )
+ (func $2 (result i32)
+  (i32.atomic.load16_u offset=2
+   (i32.const 0)
+  )
+ )
+ (func $3 (result i32)
+  (atomic.notify
+   (i32.const 1)
+   (i32.const 1)
+  )
+ )
+ (func $4 (param $0 i32) (param $1 i32)
+  (drop
+   (i32.atomic.rmw8.cmpxchg_u
+    (i32.const 0)
+    (i32.const 256)
+    (i32.const 42)
+   )
+  )
+  (call $fimport$0
+   (i32.load
+    (i32.const 0)
+   )
+  )
+ )
+ (func $5
+  (drop
+   (atomic.notify offset=22
+    (i32.const -104)
+    (i32.const -72)
+   )
+  )
+ )
+)
+[fuzz-exec] calling unaligned_load
+[trap unaligned atomic operation]
+[fuzz-exec] calling unaligned_load_offset
+[trap unaligned atomic operation]
+[fuzz-exec] calling aligned_for_size
+[fuzz-exec] note result: aligned_for_size => 0
+[fuzz-exec] calling unaligned_notify
+[trap unaligned atomic operation]
+[fuzz-exec] calling wrap_cmpxchg
+[LoggingExternalInterface logging 42]
+[fuzz-exec] calling oob_notify
+[trap final > memory: 18446744073709551512 > 65514]
+[fuzz-exec] comparing aligned_for_size
+[fuzz-exec] comparing unaligned_load
+[fuzz-exec] comparing unaligned_load_offset
+[fuzz-exec] comparing unaligned_notify
+[fuzz-exec] calling unsigned_2_bytes
+[fuzz-exec] note result: unsigned_2_bytes => 65535
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 (shared 1 1))
+ (data (i32.const 0) "\ff\ff")
+ (export "unsigned_2_bytes" (func $0))
+ (func $0 (result i32)
+  (i32.atomic.rmw16.xor_u
+   (i32.const 0)
+   (i32.const 0)
+  )
+ )
+)
+[fuzz-exec] calling unsigned_2_bytes
+[fuzz-exec] note result: unsigned_2_bytes => 65535
+[fuzz-exec] comparing unsigned_2_bytes
+[fuzz-exec] calling rmw-reads-modifies-and-writes
+[LoggingExternalInterface logging 0]
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (import "fuzzing-support" "log-i32" (func $fimport$0 (param i32)))
+ (memory $0 (shared 1 1))
+ (export "rmw-reads-modifies-and-writes" (func $0))
+ (func $0
+  (drop
+   (i64.atomic.rmw16.and_u offset=4
+    (i32.const 0)
+    (i64.const 65535)
+   )
+  )
+  (call $fimport$0
+   (i32.load8_u
+    (i32.const 5)
+   )
+  )
+ )
+)
+[fuzz-exec] calling rmw-reads-modifies-and-writes
+[LoggingExternalInterface logging 0]
+[fuzz-exec] calling rmw-reads-modifies-and-writes-asymmetrical
+[LoggingExternalInterface logging 214]
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (import "fuzzing-support" "log-i32" (func $fimport$0 (param i32)))
+ (memory $0 (shared 1 1))
+ (export "rmw-reads-modifies-and-writes-asymmetrical" (func $0))
+ (func $0
+  (drop
+   (i32.atomic.rmw8.sub_u
+    (i32.const 3)
+    (i32.const 42)
+   )
+  )
+  (call $fimport$0
+   (i32.load8_u
+    (i32.const 3)
+   )
+  )
+ )
+)
+[fuzz-exec] calling rmw-reads-modifies-and-writes-asymmetrical
+[LoggingExternalInterface logging 214]
diff --git a/binaryen/test/passes/fuzz-exec_all-features.wast b/binaryen/test/passes/fuzz-exec_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fuzz-exec_all-features.wast
@@ -0,0 +1,123 @@
+(module
+ (export "a" (func $a))
+ (export "b" (func $b))
+ (export "c" (func $c))
+ (export "d" (func $d))
+ (export "e" (func $e))
+ (func $a (result i32)
+  (i32.extend8_s
+   (i32.const 187)
+  )
+ )
+ (func $b (result i32)
+  (i32.extend16_s
+   (i32.const 33768)
+  )
+ )
+ (func $c (result i64)
+  (i64.extend8_s
+   (i64.const 187)
+  )
+ )
+ (func $d (result i64)
+  (i64.extend16_s
+   (i64.const 33768)
+  )
+ )
+ (func $e (result i64)
+  (i64.extend32_s
+   (i64.const 2148318184)
+  )
+ )
+)
+(module
+ (import "fuzzing-support" "log-i32" (func $fimport$0 (param i32)))
+ (memory $0 (shared 1 1))
+ (func "unaligned_load" (result i32)
+  (i32.atomic.load
+   (i32.const 1) ;; unaligned ptr
+   (i32.const 1)
+  )
+ )
+ (func "unaligned_load_offset" (result i32)
+  (i32.atomic.load offset=1 ;; unaligned with offset
+   (i32.const 0)
+   (i32.const 1)
+  )
+ )
+ (func "aligned_for_size" (result i32)
+  (i32.atomic.load16_u offset=2 ;; just 2 bytes loaded, so size is ok
+   (i32.const 0)
+  )
+ )
+ (func "unaligned_notify" (result i32)
+  (atomic.notify
+   (i32.const 1) ;; unaligned
+   (i32.const 1)
+  )
+ )
+ (func "wrap_cmpxchg" (param $0 i32) (param $1 i32)
+  (drop
+   (i32.atomic.rmw8.cmpxchg_u
+    (i32.const 0)
+    (i32.const 256) ;; 0x100, lower byte is 0 - should be wrapped to that
+    (i32.const 42)
+   )
+  )
+  (call $fimport$0
+   (i32.load (i32.const 0))
+  )
+ )
+ (func "oob_notify"
+  (drop
+   (atomic.notify offset=22
+    (i32.const -104) ;; illegal address
+    (i32.const -72)
+   )
+  )
+ )
+)
+(module
+ (memory $0 (shared 1 1))
+ (data (i32.const 0) "\ff\ff")
+ (func "unsigned_2_bytes" (result i32)
+  (i32.atomic.rmw16.xor_u ;; should be unsigned
+   (i32.const 0)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (import "fuzzing-support" "log-i32" (func $fimport$0 (param i32)))
+ (memory $0 (shared 1 1))
+ (func "rmw-reads-modifies-and-writes"
+  (drop
+   (i64.atomic.rmw16.and_u offset=4
+    (i32.const 0)
+    (i64.const 65535)
+   )
+  )
+  (call $fimport$0
+   (i32.load8_u
+    (i32.const 5)
+   )
+  )
+ )
+)
+(module
+ (import "fuzzing-support" "log-i32" (func $fimport$0 (param i32)))
+ (memory $0 (shared 1 1))
+ (func "rmw-reads-modifies-and-writes-asymmetrical"
+  (drop
+   (i32.atomic.rmw8.sub_u
+    (i32.const 3)
+    (i32.const 42)
+   )
+  )
+  (call $fimport$0
+   (i32.load8_u
+    (i32.const 3)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/fuzz_metrics_noprint.bin.txt b/binaryen/test/passes/fuzz_metrics_noprint.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fuzz_metrics_noprint.bin.txt
@@ -0,0 +1,30 @@
+total
+ [events]       : 0       
+ [exports]      : 18      
+ [funcs]        : 22      
+ [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     
diff --git a/binaryen/test/passes/fuzz_metrics_noprint.passes b/binaryen/test/passes/fuzz_metrics_noprint.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fuzz_metrics_noprint.passes
@@ -0,0 +1,1 @@
+translate-to-fuzz_metrics
diff --git a/binaryen/test/passes/fuzz_metrics_noprint.wasm b/binaryen/test/passes/fuzz_metrics_noprint.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/fuzz_metrics_noprint.wasm differ
diff --git a/binaryen/test/passes/generate-dyncalls.txt b/binaryen/test/passes/generate-dyncalls.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/generate-dyncalls.txt
@@ -0,0 +1,38 @@
+(module
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i64 (func (param i32) (result i64)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_=>_i64 (func (param i32 i32) (result i64)))
+ (import "env" "invoke_vii" (func $invoke_vii (param i32 i32 i32)))
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $f1 $f2)
+ (export "dynCall_i" (func $dynCall_i))
+ (export "dynCall_ji" (func $dynCall_ji))
+ (export "dynCall_vii" (func $dynCall_vii))
+ (func $f1 (result i32)
+  (i32.const 1024)
+ )
+ (func $f2 (param $0 i32) (result i64)
+  (i64.const 42)
+ )
+ (func $dynCall_i (param $fptr i32) (result i32)
+  (call_indirect (type $none_=>_i32)
+   (local.get $fptr)
+  )
+ )
+ (func $dynCall_ji (param $fptr i32) (param $0 i32) (result i64)
+  (call_indirect (type $i32_=>_i64)
+   (local.get $0)
+   (local.get $fptr)
+  )
+ )
+ (func $dynCall_vii (param $fptr i32) (param $0 i32) (param $1 i32)
+  (call_indirect (type $i32_i32_=>_none)
+   (local.get $0)
+   (local.get $1)
+   (local.get $fptr)
+  )
+ )
+)
diff --git a/binaryen/test/passes/generate-dyncalls.wast b/binaryen/test/passes/generate-dyncalls.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/generate-dyncalls.wast
@@ -0,0 +1,11 @@
+(module
+ (import "env" "invoke_vii" (func $invoke_vii (param i32 i32 i32)))
+ (func $f1 (result i32)
+  (i32.const 1024)
+ )
+ (func $f2 (param i32) (result i64)
+  (i64.const 42)
+ )
+ (table 2 2 funcref)
+ (elem (i32.const 0) $f1 $f2)
+)
diff --git a/binaryen/test/passes/generate-i64-dyncalls.txt b/binaryen/test/passes/generate-i64-dyncalls.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/generate-i64-dyncalls.txt
@@ -0,0 +1,20 @@
+(module
+ (type $i32_=>_i64 (func (param i32) (result i64)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_=>_i64 (func (param i32 i32) (result i64)))
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $f1 $f2)
+ (export "dynCall_ji" (func $dynCall_ji))
+ (func $f1 (result i32)
+  (i32.const 1024)
+ )
+ (func $f2 (param $0 i32) (result i64)
+  (i64.const 42)
+ )
+ (func $dynCall_ji (param $fptr i32) (param $0 i32) (result i64)
+  (call_indirect (type $i32_=>_i64)
+   (local.get $0)
+   (local.get $fptr)
+  )
+ )
+)
diff --git a/binaryen/test/passes/generate-i64-dyncalls.wast b/binaryen/test/passes/generate-i64-dyncalls.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/generate-i64-dyncalls.wast
@@ -0,0 +1,10 @@
+(module
+ (func $f1 (result i32)
+  (i32.const 1024)
+ )
+ (func $f2 (param i32) (result i64)
+  (i64.const 42)
+ )
+ (table 2 2 funcref)
+ (elem (i32.const 0) $f1 $f2)
+)
diff --git a/binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_all-features.txt b/binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_all-features.txt
@@ -0,0 +1,50 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (event $e0 (attr 0) (param i32))
+ (func $eh
+  (local $exn exnref)
+  try
+   i32.const 0
+   throw $e0
+  catch
+   
+   local.set $exn
+   block $l0 (result i32)
+    local.get $exn
+    br_on_exn $l0 $e0
+    rethrow
+   end
+   drop
+  end
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (event $e0 (attr 0) (param i32))
+ (func $eh (; has Stack IR ;)
+  (local $exn exnref)
+  (try
+   (do
+    (throw $e0
+     (i32.const 0)
+    )
+   )
+   (catch
+    (local.set $exn
+     (pop exnref)
+    )
+    (drop
+     (block $l0 (result i32)
+      (rethrow
+       (br_on_exn $l0 $e0
+        (local.get $exn)
+       )
+      )
+     )
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_all-features.wast b/binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_all-features.wast
@@ -0,0 +1,21 @@
+(module
+  (event $e0 (attr 0) (param i32))
+
+  (func $eh (local $exn exnref)
+    (try
+      (do
+        (throw $e0 (i32.const 0))
+      )
+      (catch
+        (local.set $exn (pop exnref))
+        (drop
+          (block $l0 (result i32)
+            (rethrow
+              (br_on_exn $l0 $e0 (local.get $exn))
+            )
+          )
+        )
+      )
+    )
+  )
+)
diff --git a/binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_optimize-level=3.txt b/binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_optimize-level=3.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_optimize-level=3.txt
@@ -0,0 +1,1600 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $f32_=>_none (func (param f32)))
+ (type $none_=>_f64 (func (result f64)))
+ (type $f64_f64_=>_f64 (func (param f64 f64) (result f64)))
+ (type $i32_i64_=>_none (func (param i32 i64)))
+ (type $f64_=>_i32 (func (param f64) (result i32)))
+ (type $none_=>_i64 (func (result i64)))
+ (type $f64_=>_f64 (func (param f64) (result f64)))
+ (import "env" "_emscripten_asm_const_vi" (func $_emscripten_asm_const_vi))
+ (import "asm2wasm" "f64-to-int" (func $f64-to-int (param f64) (result i32)))
+ (import "asm2wasm" "f64-rem" (func $f64-rem (param f64 f64) (result f64)))
+ (memory $0 4096 4096)
+ (data (i32.const 1026) "\14\00")
+ (table $0 10 funcref)
+ (elem (i32.const 0) $z $big_negative $z $z $w $w $importedDoubles $w $z $cneg)
+ (export "big_negative" (func $big_negative))
+ (func $big_negative
+  (local $temp f64)
+  f64.const -2147483648
+  local.set $temp
+  f64.const -2147483648
+  local.set $temp
+  f64.const -21474836480
+  local.set $temp
+  f64.const 0.039625
+  local.set $temp
+  f64.const -0.039625
+  local.set $temp
+ )
+ (func $importedDoubles (result f64)
+  (local $temp f64)
+  block $topmost (result f64)
+   i32.const 8
+   f64.load
+   i32.const 16
+   f64.load
+   f64.add
+   i32.const 16
+   f64.load
+   f64.neg
+   f64.add
+   i32.const 8
+   f64.load
+   f64.neg
+   f64.add
+   local.set $temp
+   i32.const 24
+   i32.load
+   i32.const 0
+   i32.gt_s
+   if
+    f64.const -3.4
+    br $topmost
+   end
+   i32.const 32
+   f64.load
+   f64.const 0
+   f64.gt
+   if
+    f64.const 5.6
+    br $topmost
+   end
+   f64.const 1.2
+  end
+ )
+ (func $doubleCompares (param $x f64) (param $y f64) (result f64)
+  (local $t f64)
+  (local $Int f64)
+  (local $Double i32)
+  block $topmost (result f64)
+   local.get $x
+   f64.const 0
+   f64.gt
+   if
+    f64.const 1.2
+    br $topmost
+   end
+   local.get $Int
+   f64.const 0
+   f64.gt
+   if
+    f64.const -3.4
+    br $topmost
+   end
+   local.get $Double
+   i32.const 0
+   i32.gt_s
+   if
+    f64.const 5.6
+    br $topmost
+   end
+   local.get $x
+   local.get $y
+   f64.lt
+   if
+    local.get $x
+    br $topmost
+   end
+   local.get $y
+  end
+ )
+ (func $intOps (result i32)
+  (local $x i32)
+  local.get $x
+  i32.const 0
+  i32.eq
+ )
+ (func $hexLiterals
+  i32.const 0
+  i32.const 313249263
+  i32.add
+  i32.const -19088752
+  i32.add
+  drop
+ )
+ (func $conversions
+  (local $i i32)
+  (local $d f64)
+  local.get $d
+  call $f64-to-int
+  local.set $i
+  local.get $i
+  f64.convert_i32_s
+  local.set $d
+  local.get $i
+  i32.const 0
+  i32.shr_u
+  f64.convert_i32_u
+  local.set $d
+ )
+ (func $seq
+  (local $J f64)
+  f64.const 0.1
+  drop
+  f64.const 5.1
+  f64.const 3.2
+  drop
+  f64.const 4.2
+  f64.sub
+  local.set $J
+ )
+ (func $switcher (param $x i32) (result i32)
+  block $topmost (result i32)
+   block $switch-default$3
+    block $switch-case$2
+     block $switch-case$1
+      local.get $x
+      i32.const 1
+      i32.sub
+      br_table $switch-case$1 $switch-case$2 $switch-default$3
+     end
+     i32.const 1
+     br $topmost
+    end
+    i32.const 2
+    br $topmost
+   end
+   nop
+   block $switch-default$7
+    block $switch-case$6
+     block $switch-case$5
+      local.get $x
+      i32.const 5
+      i32.sub
+      br_table $switch-case$6 $switch-default$7 $switch-default$7 $switch-default$7 $switch-default$7 $switch-default$7 $switch-default$7 $switch-case$5 $switch-default$7
+     end
+     i32.const 121
+     br $topmost
+    end
+    i32.const 51
+    br $topmost
+   end
+   nop
+   block $label$break$Lout
+    block $switch-default$16
+     block $switch-case$15
+      block $switch-case$12
+       block $switch-case$9
+        block $switch-case$8
+         local.get $x
+         i32.const 2
+         i32.sub
+         br_table $switch-case$15 $switch-default$16 $switch-default$16 $switch-case$12 $switch-default$16 $switch-default$16 $switch-default$16 $switch-default$16 $switch-case$9 $switch-default$16 $switch-case$8 $switch-default$16
+        end
+        br $label$break$Lout
+       end
+       br $label$break$Lout
+      end
+      block $while-out$10
+       loop $while-in$11
+        br $while-out$10
+       end
+       unreachable
+      end
+     end
+     loop $while-in$14
+      br $label$break$Lout
+     end
+     unreachable
+    end
+    nop
+   end
+   i32.const 0
+  end
+ )
+ (func $blocker
+  block $label$break$L
+   br $label$break$L
+  end
+ )
+ (func $frem (result f64)
+  f64.const 5.5
+  f64.const 1.2
+  call $f64-rem
+ )
+ (func $big_uint_div_u (result i32)
+  (local $x i32)
+  i32.const -1
+  i32.const 2
+  i32.div_u
+  i32.const -1
+  i32.and
+ )
+ (func $fr (param $x f32)
+  (local $y f32)
+  (local $z f64)
+  local.get $z
+  f32.demote_f64
+  drop
+  local.get $y
+  drop
+  f32.const 5
+  drop
+  f32.const 0
+  drop
+  f32.const 5
+  drop
+  f32.const 0
+  drop
+ )
+ (func $negZero (result f64)
+  f64.const -0
+ )
+ (func $abs
+  (local $x i32)
+  (local $y f64)
+  (local $z f32)
+  (local $asm2wasm_i32_temp i32)
+  i32.const 0
+  local.set $asm2wasm_i32_temp
+  i32.const 0
+  local.get $asm2wasm_i32_temp
+  i32.sub
+  local.get $asm2wasm_i32_temp
+  local.get $asm2wasm_i32_temp
+  i32.const 0
+  i32.lt_s
+  select
+  local.set $x
+  f64.const 0
+  f64.abs
+  local.set $y
+  f32.const 0
+  f32.abs
+  local.set $z
+ )
+ (func $neg
+  (local $x f32)
+  local.get $x
+  f32.neg
+  i32.const 1
+  i32.const 7
+  i32.and
+  i32.const 8
+  i32.add
+  call_indirect (type $f32_=>_none)
+ )
+ (func $cneg (param $x f32)
+  local.get $x
+  i32.const 1
+  i32.const 7
+  i32.and
+  i32.const 8
+  i32.add
+  call_indirect (type $f32_=>_none)
+ )
+ (func $___syscall_ret
+  (local $$0 i32)
+  local.get $$0
+  i32.const 0
+  i32.shr_u
+  i32.const -4096
+  i32.gt_u
+  drop
+ )
+ (func $z
+  nop
+ )
+ (func $w
+  nop
+ )
+ (func $block_and_after (result i32)
+  block $waka
+   i32.const 1
+   drop
+   br $waka
+  end
+  i32.const 0
+ )
+ (func $loop-roundtrip (param $0 f64) (result f64)
+  loop $loop-in1 (result f64)
+   local.get $0
+   drop
+   local.get $0
+  end
+ )
+ (func $big-i64 (result i64)
+  i64.const -9218868437227405313
+ )
+ (func $i64-store32 (param $0 i32) (param $1 i64)
+  local.get $0
+  local.get $1
+  i64.store32
+ )
+ (func $return-unreachable (result i32)
+  i32.const 1
+  return
+ )
+ (func $unreachable-block (result i32)
+  i32.const 1
+  drop
+  i32.const 2
+  return
+ )
+ (func $unreachable-block-toplevel (result i32)
+  i32.const 1
+  drop
+  i32.const 2
+  return
+ )
+ (func $unreachable-block0 (result i32)
+  i32.const 2
+  return
+ )
+ (func $unreachable-block0-toplevel (result i32)
+  i32.const 2
+  return
+ )
+ (func $unreachable-block-with-br (result i32)
+  block $block
+   i32.const 1
+   drop
+   br $block
+  end
+  i32.const 1
+ )
+ (func $unreachable-if (result i32)
+  i32.const 3
+  if
+   i32.const 2
+   return
+  else
+   i32.const 1
+   return
+  end
+  unreachable
+ )
+ (func $unreachable-if-toplevel (result i32)
+  i32.const 3
+  if
+   i32.const 2
+   return
+  else
+   i32.const 1
+   return
+  end
+  unreachable
+ )
+ (func $unreachable-loop (result i32)
+  loop $loop-in
+   nop
+   i32.const 1
+   return
+  end
+  unreachable
+ )
+ (func $unreachable-loop0 (result i32)
+  loop $loop-in
+   i32.const 1
+   return
+  end
+  unreachable
+ )
+ (func $unreachable-loop-toplevel (result i32)
+  loop $loop-in
+   nop
+   i32.const 1
+   return
+  end
+  unreachable
+ )
+ (func $unreachable-loop0-toplevel (result i32)
+  loop $loop-in
+   i32.const 1
+   return
+  end
+  unreachable
+ )
+ (func $unreachable-ifs
+  unreachable
+ )
+ (func $unreachable-if-arm
+  i32.const 1
+  if
+   nop
+  else
+   unreachable
+  end
+ )
+ (func $local-to-stack (param $x i32) (result i32)
+  (local $temp i32)
+  i32.const 1
+  call $local-to-stack
+  i32.const 2
+  call $local-to-stack
+  drop
+ )
+ (func $local-to-stack-1 (param $x i32) (result i32)
+  (local $temp i32)
+  i32.const 1
+  call $local-to-stack
+  i32.const 2
+  call $local-to-stack
+  drop
+  i32.eqz
+ )
+ (func $local-to-stack-1b (param $x i32) (result i32)
+  (local $temp i32)
+  i32.const 1
+  call $local-to-stack
+  i32.const 2
+  call $local-to-stack
+  drop
+  i32.const 3
+  i32.add
+ )
+ (func $local-to-stack-1c-no (param $x i32) (result i32)
+  (local $temp i32)
+  i32.const 1
+  call $local-to-stack
+  local.set $temp
+  i32.const 2
+  call $local-to-stack
+  drop
+  i32.const 3
+  local.get $temp
+  i32.add
+ )
+ (func $local-to-stack-2-no (param $x i32) (result i32)
+  (local $temp i32)
+  i32.const 1
+  call $local-to-stack
+  local.set $temp
+  i32.const 2
+  call $local-to-stack
+  drop
+  local.get $temp
+  local.get $temp
+  i32.add
+ )
+ (func $local-to-stack-3-no (param $x i32) (result i32)
+  (local $temp i32)
+  i32.const 1
+  if
+   i32.const 1
+   call $local-to-stack
+   local.set $temp
+  else
+   i32.const 2
+   call $local-to-stack
+   local.set $temp
+  end
+  i32.const 3
+  call $local-to-stack
+  drop
+  local.get $temp
+ )
+ (func $local-to-stack-multi-4 (param $x i32) (result i32)
+  (local $temp1 i32)
+  (local $temp2 i32)
+  i32.const 1
+  call $local-to-stack-multi-4
+  i32.const 2
+  call $local-to-stack-multi-4
+  drop
+  drop
+  i32.const 3
+  call $local-to-stack-multi-4
+  i32.const 4
+  call $local-to-stack-multi-4
+  drop
+ )
+ (func $local-to-stack-multi-5 (param $x i32) (result i32)
+  (local $temp1 i32)
+  (local $temp2 i32)
+  i32.const 1
+  call $local-to-stack-multi-4
+  i32.const 2
+  call $local-to-stack-multi-4
+  drop
+  drop
+  i32.const 3
+  call $local-to-stack-multi-4
+  i32.const 4
+  call $local-to-stack-multi-4
+  drop
+ )
+ (func $local-to-stack-multi-6-justone (param $x i32) (result i32)
+  (local $temp1 i32)
+  (local $temp2 i32)
+  i32.const 1
+  call $local-to-stack-multi-4
+  i32.const 2
+  call $local-to-stack-multi-4
+  drop
+  drop
+  i32.const 3
+  call $local-to-stack-multi-4
+  local.set $temp2
+  i32.const 4
+  call $local-to-stack-multi-4
+  drop
+  local.get $temp2
+  local.get $temp2
+  i32.add
+ )
+ (func $local-to-stack-multi-7-justone (param $x i32) (result i32)
+  (local $temp1 i32)
+  (local $temp2 i32)
+  i32.const 1
+  call $local-to-stack-multi-4
+  local.set $temp1
+  i32.const 2
+  call $local-to-stack-multi-4
+  drop
+  local.get $temp1
+  local.get $temp1
+  i32.add
+  drop
+  i32.const 3
+  call $local-to-stack-multi-4
+  i32.const 4
+  call $local-to-stack-multi-4
+  drop
+ )
+ (func $local-to-stack-overlapping-multi-8-no (param $x i32) (result i32)
+  (local $temp1 i32)
+  (local $temp2 i32)
+  i32.const 1
+  call $local-to-stack-multi-4
+  local.set $temp1
+  i32.const 1
+  call $local-to-stack-multi-4
+  i32.const 3
+  call $local-to-stack-multi-4
+  drop
+  local.get $temp1
+  i32.add
+ )
+ (func $local-to-stack-overlapping-multi-9-yes (param $x i32) (result i32)
+  (local $temp1 i32)
+  (local $temp2 i32)
+  i32.const 1
+  call $local-to-stack-multi-4
+  i32.const 1
+  call $local-to-stack-multi-4
+  i32.const 3
+  call $local-to-stack-multi-4
+  drop
+  i32.add
+ )
+ (func $local-to-stack-through-control-flow
+  (local $temp1 i32)
+  (local $temp2 i32)
+  i32.const 0
+  call $local-to-stack-multi-4
+  i32.const 1
+  call $local-to-stack-multi-4
+  i32.const 0
+  if
+   nop
+  end
+  drop
+  i32.const 2
+  call $local-to-stack-multi-4
+  block $block
+   br $block
+  end
+  drop
+  drop
+ )
+ (func $local-to-stack-in-control-flow
+  (local $temp1 i32)
+  i32.const 0
+  if
+   i32.const 0
+   call $local-to-stack-multi-4
+   drop
+  else
+   i32.const 1
+   call $local-to-stack-multi-4
+   drop
+  end
+ )
+ (func $remove-block (param $x i32) (result i32)
+  (local $temp i32)
+  i32.const 0
+  call $remove-block
+  i32.const 1
+  call $remove-block
+  i32.const 2
+  call $remove-block
+  drop
+  i32.eqz
+  i32.add
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $f32_=>_none (func (param f32)))
+ (type $none_=>_f64 (func (result f64)))
+ (type $f64_f64_=>_f64 (func (param f64 f64) (result f64)))
+ (type $i32_i64_=>_none (func (param i32 i64)))
+ (type $f64_=>_i32 (func (param f64) (result i32)))
+ (type $none_=>_i64 (func (result i64)))
+ (type $f64_=>_f64 (func (param f64) (result f64)))
+ (import "env" "_emscripten_asm_const_vi" (func $_emscripten_asm_const_vi))
+ (import "asm2wasm" "f64-to-int" (func $f64-to-int (param f64) (result i32)))
+ (import "asm2wasm" "f64-rem" (func $f64-rem (param f64 f64) (result f64)))
+ (memory $0 4096 4096)
+ (data (i32.const 1026) "\14\00")
+ (table $0 10 funcref)
+ (elem (i32.const 0) $z $big_negative $z $z $w $w $importedDoubles $w $z $cneg)
+ (export "big_negative" (func $big_negative))
+ (func $big_negative (; has Stack IR ;)
+  (local $temp f64)
+  (block $block0
+   (local.set $temp
+    (f64.const -2147483648)
+   )
+   (local.set $temp
+    (f64.const -2147483648)
+   )
+   (local.set $temp
+    (f64.const -21474836480)
+   )
+   (local.set $temp
+    (f64.const 0.039625)
+   )
+   (local.set $temp
+    (f64.const -0.039625)
+   )
+  )
+ )
+ (func $importedDoubles (; has Stack IR ;) (result f64)
+  (local $temp f64)
+  (block $topmost (result f64)
+   (local.set $temp
+    (f64.add
+     (f64.add
+      (f64.add
+       (f64.load
+        (i32.const 8)
+       )
+       (f64.load
+        (i32.const 16)
+       )
+      )
+      (f64.neg
+       (f64.load
+        (i32.const 16)
+       )
+      )
+     )
+     (f64.neg
+      (f64.load
+       (i32.const 8)
+      )
+     )
+    )
+   )
+   (if
+    (i32.gt_s
+     (i32.load
+      (i32.const 24)
+     )
+     (i32.const 0)
+    )
+    (br $topmost
+     (f64.const -3.4)
+    )
+   )
+   (if
+    (f64.gt
+     (f64.load
+      (i32.const 32)
+     )
+     (f64.const 0)
+    )
+    (br $topmost
+     (f64.const 5.6)
+    )
+   )
+   (f64.const 1.2)
+  )
+ )
+ (func $doubleCompares (; has Stack IR ;) (param $x f64) (param $y f64) (result f64)
+  (local $t f64)
+  (local $Int f64)
+  (local $Double i32)
+  (block $topmost (result f64)
+   (if
+    (f64.gt
+     (local.get $x)
+     (f64.const 0)
+    )
+    (br $topmost
+     (f64.const 1.2)
+    )
+   )
+   (if
+    (f64.gt
+     (local.get $Int)
+     (f64.const 0)
+    )
+    (br $topmost
+     (f64.const -3.4)
+    )
+   )
+   (if
+    (i32.gt_s
+     (local.get $Double)
+     (i32.const 0)
+    )
+    (br $topmost
+     (f64.const 5.6)
+    )
+   )
+   (if
+    (f64.lt
+     (local.get $x)
+     (local.get $y)
+    )
+    (br $topmost
+     (local.get $x)
+    )
+   )
+   (local.get $y)
+  )
+ )
+ (func $intOps (; has Stack IR ;) (result i32)
+  (local $x i32)
+  (i32.eq
+   (local.get $x)
+   (i32.const 0)
+  )
+ )
+ (func $hexLiterals (; has Stack IR ;)
+  (drop
+   (i32.add
+    (i32.add
+     (i32.const 0)
+     (i32.const 313249263)
+    )
+    (i32.const -19088752)
+   )
+  )
+ )
+ (func $conversions (; has Stack IR ;)
+  (local $i i32)
+  (local $d f64)
+  (block $block0
+   (local.set $i
+    (call $f64-to-int
+     (local.get $d)
+    )
+   )
+   (local.set $d
+    (f64.convert_i32_s
+     (local.get $i)
+    )
+   )
+   (local.set $d
+    (f64.convert_i32_u
+     (i32.shr_u
+      (local.get $i)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+ )
+ (func $seq (; has Stack IR ;)
+  (local $J f64)
+  (local.set $J
+   (f64.sub
+    (block $block0 (result f64)
+     (drop
+      (f64.const 0.1)
+     )
+     (f64.const 5.1)
+    )
+    (block $block1 (result f64)
+     (drop
+      (f64.const 3.2)
+     )
+     (f64.const 4.2)
+    )
+   )
+  )
+ )
+ (func $switcher (; has Stack IR ;) (param $x i32) (result i32)
+  (block $topmost (result i32)
+   (block $switch$0
+    (block $switch-default$3
+     (block $switch-case$2
+      (block $switch-case$1
+       (br_table $switch-case$1 $switch-case$2 $switch-default$3
+        (i32.sub
+         (local.get $x)
+         (i32.const 1)
+        )
+       )
+      )
+      (br $topmost
+       (i32.const 1)
+      )
+     )
+     (br $topmost
+      (i32.const 2)
+     )
+    )
+    (nop)
+   )
+   (block $switch$4
+    (block $switch-default$7
+     (block $switch-case$6
+      (block $switch-case$5
+       (br_table $switch-case$6 $switch-default$7 $switch-default$7 $switch-default$7 $switch-default$7 $switch-default$7 $switch-default$7 $switch-case$5 $switch-default$7
+        (i32.sub
+         (local.get $x)
+         (i32.const 5)
+        )
+       )
+      )
+      (br $topmost
+       (i32.const 121)
+      )
+     )
+     (br $topmost
+      (i32.const 51)
+     )
+    )
+    (nop)
+   )
+   (block $label$break$Lout
+    (block $switch-default$16
+     (block $switch-case$15
+      (block $switch-case$12
+       (block $switch-case$9
+        (block $switch-case$8
+         (br_table $switch-case$15 $switch-default$16 $switch-default$16 $switch-case$12 $switch-default$16 $switch-default$16 $switch-default$16 $switch-default$16 $switch-case$9 $switch-default$16 $switch-case$8 $switch-default$16
+          (i32.sub
+           (local.get $x)
+           (i32.const 2)
+          )
+         )
+        )
+        (br $label$break$Lout)
+       )
+       (br $label$break$Lout)
+      )
+      (block $while-out$10
+       (loop $while-in$11
+        (block $block1
+         (br $while-out$10)
+         (br $while-in$11)
+        )
+       )
+       (br $label$break$Lout)
+      )
+     )
+     (block $while-out$13
+      (loop $while-in$14
+       (block $block3
+        (br $label$break$Lout)
+        (br $while-in$14)
+       )
+      )
+      (br $label$break$Lout)
+     )
+    )
+    (nop)
+   )
+   (i32.const 0)
+  )
+ )
+ (func $blocker (; has Stack IR ;)
+  (block $label$break$L
+   (br $label$break$L)
+  )
+ )
+ (func $frem (; has Stack IR ;) (result f64)
+  (call $f64-rem
+   (f64.const 5.5)
+   (f64.const 1.2)
+  )
+ )
+ (func $big_uint_div_u (; has Stack IR ;) (result i32)
+  (local $x i32)
+  (block $topmost (result i32)
+   (local.set $x
+    (i32.and
+     (i32.div_u
+      (i32.const -1)
+      (i32.const 2)
+     )
+     (i32.const -1)
+    )
+   )
+   (local.get $x)
+  )
+ )
+ (func $fr (; has Stack IR ;) (param $x f32)
+  (local $y f32)
+  (local $z f64)
+  (block $block0
+   (drop
+    (f32.demote_f64
+     (local.get $z)
+    )
+   )
+   (drop
+    (local.get $y)
+   )
+   (drop
+    (f32.const 5)
+   )
+   (drop
+    (f32.const 0)
+   )
+   (drop
+    (f32.const 5)
+   )
+   (drop
+    (f32.const 0)
+   )
+  )
+ )
+ (func $negZero (; has Stack IR ;) (result f64)
+  (f64.const -0)
+ )
+ (func $abs (; has Stack IR ;)
+  (local $x i32)
+  (local $y f64)
+  (local $z f32)
+  (local $asm2wasm_i32_temp i32)
+  (block $block0
+   (local.set $x
+    (block $block1 (result i32)
+     (local.set $asm2wasm_i32_temp
+      (i32.const 0)
+     )
+     (select
+      (i32.sub
+       (i32.const 0)
+       (local.get $asm2wasm_i32_temp)
+      )
+      (local.get $asm2wasm_i32_temp)
+      (i32.lt_s
+       (local.get $asm2wasm_i32_temp)
+       (i32.const 0)
+      )
+     )
+    )
+   )
+   (local.set $y
+    (f64.abs
+     (f64.const 0)
+    )
+   )
+   (local.set $z
+    (f32.abs
+     (f32.const 0)
+    )
+   )
+  )
+ )
+ (func $neg (; has Stack IR ;)
+  (local $x f32)
+  (block $block0
+   (local.set $x
+    (f32.neg
+     (local.get $x)
+    )
+   )
+   (call_indirect (type $f32_=>_none)
+    (local.get $x)
+    (i32.add
+     (i32.and
+      (i32.const 1)
+      (i32.const 7)
+     )
+     (i32.const 8)
+    )
+   )
+  )
+ )
+ (func $cneg (; has Stack IR ;) (param $x f32)
+  (call_indirect (type $f32_=>_none)
+   (local.get $x)
+   (i32.add
+    (i32.and
+     (i32.const 1)
+     (i32.const 7)
+    )
+    (i32.const 8)
+   )
+  )
+ )
+ (func $___syscall_ret (; has Stack IR ;)
+  (local $$0 i32)
+  (drop
+   (i32.gt_u
+    (i32.shr_u
+     (local.get $$0)
+     (i32.const 0)
+    )
+    (i32.const -4096)
+   )
+  )
+ )
+ (func $z (; has Stack IR ;)
+  (nop)
+ )
+ (func $w (; has Stack IR ;)
+  (nop)
+ )
+ (func $block_and_after (; has Stack IR ;) (result i32)
+  (block $waka
+   (drop
+    (i32.const 1)
+   )
+   (br $waka)
+  )
+  (i32.const 0)
+ )
+ (func $loop-roundtrip (; has Stack IR ;) (param $0 f64) (result f64)
+  (loop $loop-in1 (result f64)
+   (drop
+    (local.get $0)
+   )
+   (local.get $0)
+  )
+ )
+ (func $big-i64 (; has Stack IR ;) (result i64)
+  (i64.const -9218868437227405313)
+ )
+ (func $i64-store32 (; has Stack IR ;) (param $0 i32) (param $1 i64)
+  (i64.store32
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $return-unreachable (; has Stack IR ;) (result i32)
+  (return
+   (i32.const 1)
+  )
+ )
+ (func $unreachable-block (; has Stack IR ;) (result i32)
+  (f64.abs
+   (block $block
+    (drop
+     (i32.const 1)
+    )
+    (return
+     (i32.const 2)
+    )
+   )
+  )
+ )
+ (func $unreachable-block-toplevel (; has Stack IR ;) (result i32)
+  (block $block
+   (drop
+    (i32.const 1)
+   )
+   (return
+    (i32.const 2)
+   )
+  )
+ )
+ (func $unreachable-block0 (; has Stack IR ;) (result i32)
+  (f64.abs
+   (block $block
+    (return
+     (i32.const 2)
+    )
+   )
+  )
+ )
+ (func $unreachable-block0-toplevel (; has Stack IR ;) (result i32)
+  (block $block
+   (return
+    (i32.const 2)
+   )
+  )
+ )
+ (func $unreachable-block-with-br (; has Stack IR ;) (result i32)
+  (block $block
+   (drop
+    (i32.const 1)
+   )
+   (br $block)
+  )
+  (i32.const 1)
+ )
+ (func $unreachable-if (; has Stack IR ;) (result i32)
+  (f64.abs
+   (if
+    (i32.const 3)
+    (return
+     (i32.const 2)
+    )
+    (return
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $unreachable-if-toplevel (; has Stack IR ;) (result i32)
+  (if
+   (i32.const 3)
+   (return
+    (i32.const 2)
+   )
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $unreachable-loop (; has Stack IR ;) (result i32)
+  (f64.abs
+   (loop $loop-in
+    (nop)
+    (return
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $unreachable-loop0 (; has Stack IR ;) (result i32)
+  (f64.abs
+   (loop $loop-in
+    (return
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $unreachable-loop-toplevel (; has Stack IR ;) (result i32)
+  (loop $loop-in
+   (nop)
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $unreachable-loop0-toplevel (; has Stack IR ;) (result i32)
+  (loop $loop-in
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $unreachable-ifs (; has Stack IR ;)
+  (if
+   (unreachable)
+   (nop)
+  )
+  (if
+   (unreachable)
+   (unreachable)
+  )
+  (if
+   (unreachable)
+   (nop)
+   (nop)
+  )
+  (if
+   (unreachable)
+   (unreachable)
+   (nop)
+  )
+  (if
+   (unreachable)
+   (nop)
+   (unreachable)
+  )
+  (if
+   (unreachable)
+   (unreachable)
+   (unreachable)
+  )
+  (if
+   (i32.const 1)
+   (unreachable)
+   (nop)
+  )
+  (if
+   (i32.const 1)
+   (nop)
+   (unreachable)
+  )
+  (if
+   (i32.const 1)
+   (unreachable)
+   (unreachable)
+  )
+ )
+ (func $unreachable-if-arm (; has Stack IR ;)
+  (if
+   (i32.const 1)
+   (block $block
+    (nop)
+   )
+   (block $block12
+    (unreachable)
+    (drop
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $local-to-stack (; has Stack IR ;) (param $x i32) (result i32)
+  (local $temp i32)
+  (local.set $temp
+   (call $local-to-stack
+    (i32.const 1)
+   )
+  )
+  (drop
+   (call $local-to-stack
+    (i32.const 2)
+   )
+  )
+  (local.get $temp)
+ )
+ (func $local-to-stack-1 (; has Stack IR ;) (param $x i32) (result i32)
+  (local $temp i32)
+  (local.set $temp
+   (call $local-to-stack
+    (i32.const 1)
+   )
+  )
+  (drop
+   (call $local-to-stack
+    (i32.const 2)
+   )
+  )
+  (i32.eqz
+   (local.get $temp)
+  )
+ )
+ (func $local-to-stack-1b (; has Stack IR ;) (param $x i32) (result i32)
+  (local $temp i32)
+  (local.set $temp
+   (call $local-to-stack
+    (i32.const 1)
+   )
+  )
+  (drop
+   (call $local-to-stack
+    (i32.const 2)
+   )
+  )
+  (i32.add
+   (local.get $temp)
+   (i32.const 3)
+  )
+ )
+ (func $local-to-stack-1c-no (; has Stack IR ;) (param $x i32) (result i32)
+  (local $temp i32)
+  (local.set $temp
+   (call $local-to-stack
+    (i32.const 1)
+   )
+  )
+  (drop
+   (call $local-to-stack
+    (i32.const 2)
+   )
+  )
+  (i32.add
+   (i32.const 3)
+   (local.get $temp)
+  )
+ )
+ (func $local-to-stack-2-no (; has Stack IR ;) (param $x i32) (result i32)
+  (local $temp i32)
+  (local.set $temp
+   (call $local-to-stack
+    (i32.const 1)
+   )
+  )
+  (drop
+   (call $local-to-stack
+    (i32.const 2)
+   )
+  )
+  (i32.add
+   (local.get $temp)
+   (local.get $temp)
+  )
+ )
+ (func $local-to-stack-3-no (; has Stack IR ;) (param $x i32) (result i32)
+  (local $temp i32)
+  (if
+   (i32.const 1)
+   (local.set $temp
+    (call $local-to-stack
+     (i32.const 1)
+    )
+   )
+   (local.set $temp
+    (call $local-to-stack
+     (i32.const 2)
+    )
+   )
+  )
+  (drop
+   (call $local-to-stack
+    (i32.const 3)
+   )
+  )
+  (local.get $temp)
+ )
+ (func $local-to-stack-multi-4 (; has Stack IR ;) (param $x i32) (result i32)
+  (local $temp1 i32)
+  (local $temp2 i32)
+  (local.set $temp1
+   (call $local-to-stack-multi-4
+    (i32.const 1)
+   )
+  )
+  (drop
+   (call $local-to-stack-multi-4
+    (i32.const 2)
+   )
+  )
+  (drop
+   (local.get $temp1)
+  )
+  (local.set $temp1
+   (call $local-to-stack-multi-4
+    (i32.const 3)
+   )
+  )
+  (drop
+   (call $local-to-stack-multi-4
+    (i32.const 4)
+   )
+  )
+  (local.get $temp1)
+ )
+ (func $local-to-stack-multi-5 (; has Stack IR ;) (param $x i32) (result i32)
+  (local $temp1 i32)
+  (local $temp2 i32)
+  (local.set $temp1
+   (call $local-to-stack-multi-4
+    (i32.const 1)
+   )
+  )
+  (drop
+   (call $local-to-stack-multi-4
+    (i32.const 2)
+   )
+  )
+  (drop
+   (local.get $temp1)
+  )
+  (local.set $temp2
+   (call $local-to-stack-multi-4
+    (i32.const 3)
+   )
+  )
+  (drop
+   (call $local-to-stack-multi-4
+    (i32.const 4)
+   )
+  )
+  (local.get $temp2)
+ )
+ (func $local-to-stack-multi-6-justone (; has Stack IR ;) (param $x i32) (result i32)
+  (local $temp1 i32)
+  (local $temp2 i32)
+  (local.set $temp1
+   (call $local-to-stack-multi-4
+    (i32.const 1)
+   )
+  )
+  (drop
+   (call $local-to-stack-multi-4
+    (i32.const 2)
+   )
+  )
+  (drop
+   (local.get $temp1)
+  )
+  (local.set $temp2
+   (call $local-to-stack-multi-4
+    (i32.const 3)
+   )
+  )
+  (drop
+   (call $local-to-stack-multi-4
+    (i32.const 4)
+   )
+  )
+  (i32.add
+   (local.get $temp2)
+   (local.get $temp2)
+  )
+ )
+ (func $local-to-stack-multi-7-justone (; has Stack IR ;) (param $x i32) (result i32)
+  (local $temp1 i32)
+  (local $temp2 i32)
+  (local.set $temp1
+   (call $local-to-stack-multi-4
+    (i32.const 1)
+   )
+  )
+  (drop
+   (call $local-to-stack-multi-4
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.add
+    (local.get $temp1)
+    (local.get $temp1)
+   )
+  )
+  (local.set $temp2
+   (call $local-to-stack-multi-4
+    (i32.const 3)
+   )
+  )
+  (drop
+   (call $local-to-stack-multi-4
+    (i32.const 4)
+   )
+  )
+  (local.get $temp2)
+ )
+ (func $local-to-stack-overlapping-multi-8-no (; has Stack IR ;) (param $x i32) (result i32)
+  (local $temp1 i32)
+  (local $temp2 i32)
+  (local.set $temp1
+   (call $local-to-stack-multi-4
+    (i32.const 1)
+   )
+  )
+  (local.set $temp2
+   (call $local-to-stack-multi-4
+    (i32.const 1)
+   )
+  )
+  (drop
+   (call $local-to-stack-multi-4
+    (i32.const 3)
+   )
+  )
+  (i32.add
+   (local.get $temp2)
+   (local.get $temp1)
+  )
+ )
+ (func $local-to-stack-overlapping-multi-9-yes (; has Stack IR ;) (param $x i32) (result i32)
+  (local $temp1 i32)
+  (local $temp2 i32)
+  (local.set $temp1
+   (call $local-to-stack-multi-4
+    (i32.const 1)
+   )
+  )
+  (local.set $temp2
+   (call $local-to-stack-multi-4
+    (i32.const 1)
+   )
+  )
+  (drop
+   (call $local-to-stack-multi-4
+    (i32.const 3)
+   )
+  )
+  (i32.add
+   (local.get $temp1)
+   (local.get $temp2)
+  )
+ )
+ (func $local-to-stack-through-control-flow (; has Stack IR ;)
+  (local $temp1 i32)
+  (local $temp2 i32)
+  (local.set $temp2
+   (call $local-to-stack-multi-4
+    (i32.const 0)
+   )
+  )
+  (local.set $temp1
+   (call $local-to-stack-multi-4
+    (i32.const 1)
+   )
+  )
+  (if
+   (i32.const 0)
+   (nop)
+  )
+  (drop
+   (local.get $temp1)
+  )
+  (local.set $temp1
+   (call $local-to-stack-multi-4
+    (i32.const 2)
+   )
+  )
+  (block $block
+   (br $block)
+  )
+  (drop
+   (local.get $temp1)
+  )
+  (drop
+   (local.get $temp2)
+  )
+ )
+ (func $local-to-stack-in-control-flow (; has Stack IR ;)
+  (local $temp1 i32)
+  (if
+   (i32.const 0)
+   (block $block
+    (local.set $temp1
+     (call $local-to-stack-multi-4
+      (i32.const 0)
+     )
+    )
+    (drop
+     (local.get $temp1)
+    )
+   )
+   (block $block13
+    (local.set $temp1
+     (call $local-to-stack-multi-4
+      (i32.const 1)
+     )
+    )
+    (drop
+     (local.get $temp1)
+    )
+   )
+  )
+ )
+ (func $remove-block (; has Stack IR ;) (param $x i32) (result i32)
+  (local $temp i32)
+  (i32.add
+   (call $remove-block
+    (i32.const 0)
+   )
+   (i32.eqz
+    (block $block (result i32)
+     (local.set $temp
+      (call $remove-block
+       (i32.const 1)
+      )
+     )
+     (drop
+      (call $remove-block
+       (i32.const 2)
+      )
+     )
+     (local.get $temp)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_optimize-level=3.wast b/binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_optimize-level=3.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_optimize-level=3.wast
@@ -0,0 +1,712 @@
+(module
+  (type $FUNCSIG$vf (func (param f32)))
+  (type $FUNCSIG$v (func))
+  (type $FUNCSIG$id (func (param f64) (result i32)))
+  (type $FUNCSIG$ddd (func (param f64 f64) (result f64)))
+  (type $4 (func (result f64)))
+  (type $5 (func (result i32)))
+  (type $6 (func (param i32) (result i32)))
+  (type $7 (func (param f64) (result f64)))
+  (type $8 (func (result i64)))
+  (type $9 (func (param i32 i64)))
+  (import "env" "_emscripten_asm_const_vi" (func $_emscripten_asm_const_vi))
+  (import "asm2wasm" "f64-to-int" (func $f64-to-int (param f64) (result i32)))
+  (import "asm2wasm" "f64-rem" (func $f64-rem (param f64 f64) (result f64)))
+  (table 10 funcref)
+  (elem (i32.const 0) $z $big_negative $z $z $w $w $importedDoubles $w $z $cneg)
+  (memory $0 4096 4096)
+  (data (i32.const 1026) "\14\00")
+  (export "big_negative" (func $big_negative))
+  (func $big_negative (type $FUNCSIG$v)
+    (local $temp f64)
+    (block $block0
+      (local.set $temp
+        (f64.const -2147483648)
+      )
+      (local.set $temp
+        (f64.const -2147483648)
+      )
+      (local.set $temp
+        (f64.const -21474836480)
+      )
+      (local.set $temp
+        (f64.const 0.039625)
+      )
+      (local.set $temp
+        (f64.const -0.039625)
+      )
+    )
+  )
+  (func $importedDoubles (type $4) (result f64)
+    (local $temp f64)
+    (block $topmost (result f64)
+      (local.set $temp
+        (f64.add
+          (f64.add
+            (f64.add
+              (f64.load
+                (i32.const 8)
+              )
+              (f64.load
+                (i32.const 16)
+              )
+            )
+            (f64.neg
+              (f64.load
+                (i32.const 16)
+              )
+            )
+          )
+          (f64.neg
+            (f64.load
+              (i32.const 8)
+            )
+          )
+        )
+      )
+      (if
+        (i32.gt_s
+          (i32.load
+            (i32.const 24)
+          )
+          (i32.const 0)
+        )
+        (br $topmost
+          (f64.const -3.4)
+        )
+      )
+      (if
+        (f64.gt
+          (f64.load
+            (i32.const 32)
+          )
+          (f64.const 0)
+        )
+        (br $topmost
+          (f64.const 5.6)
+        )
+      )
+      (f64.const 1.2)
+    )
+  )
+  (func $doubleCompares (type $FUNCSIG$ddd) (param $x f64) (param $y f64) (result f64)
+    (local $t f64)
+    (local $Int f64)
+    (local $Double i32)
+    (block $topmost (result f64)
+      (if
+        (f64.gt
+          (local.get $x)
+          (f64.const 0)
+        )
+        (br $topmost
+          (f64.const 1.2)
+        )
+      )
+      (if
+        (f64.gt
+          (local.get $Int)
+          (f64.const 0)
+        )
+        (br $topmost
+          (f64.const -3.4)
+        )
+      )
+      (if
+        (i32.gt_s
+          (local.get $Double)
+          (i32.const 0)
+        )
+        (br $topmost
+          (f64.const 5.6)
+        )
+      )
+      (if
+        (f64.lt
+          (local.get $x)
+          (local.get $y)
+        )
+        (br $topmost
+          (local.get $x)
+        )
+      )
+      (local.get $y)
+    )
+  )
+  (func $intOps (type $5) (result i32)
+    (local $x i32)
+    (i32.eq
+      (local.get $x)
+      (i32.const 0)
+    )
+  )
+  (func $hexLiterals (type $FUNCSIG$v)
+    (drop
+      (i32.add
+        (i32.add
+          (i32.const 0)
+          (i32.const 313249263)
+        )
+        (i32.const -19088752)
+      )
+    )
+  )
+  (func $conversions (type $FUNCSIG$v)
+    (local $i i32)
+    (local $d f64)
+    (block $block0
+      (local.set $i
+        (call $f64-to-int
+          (local.get $d)
+        )
+      )
+      (local.set $d
+        (f64.convert_i32_s
+          (local.get $i)
+        )
+      )
+      (local.set $d
+        (f64.convert_i32_u
+          (i32.shr_u
+            (local.get $i)
+            (i32.const 0)
+          )
+        )
+      )
+    )
+  )
+  (func $seq (type $FUNCSIG$v)
+    (local $J f64)
+    (local.set $J
+      (f64.sub
+        (block $block0 (result f64)
+          (drop
+            (f64.const 0.1)
+          )
+          (f64.const 5.1)
+        )
+        (block $block1 (result f64)
+          (drop
+            (f64.const 3.2)
+          )
+          (f64.const 4.2)
+        )
+      )
+    )
+  )
+  (func $switcher (type $6) (param $x i32) (result i32)
+    (block $topmost (result i32)
+      (block $switch$0
+        (block $switch-default$3
+          (block $switch-case$2
+            (block $switch-case$1
+              (br_table $switch-case$1 $switch-case$2 $switch-default$3
+                (i32.sub
+                  (local.get $x)
+                  (i32.const 1)
+                )
+              )
+            )
+            (br $topmost
+              (i32.const 1)
+            )
+          )
+          (br $topmost
+            (i32.const 2)
+          )
+        )
+        (nop)
+      )
+      (block $switch$4
+        (block $switch-default$7
+          (block $switch-case$6
+            (block $switch-case$5
+              (br_table $switch-case$6 $switch-default$7 $switch-default$7 $switch-default$7 $switch-default$7 $switch-default$7 $switch-default$7 $switch-case$5 $switch-default$7
+                (i32.sub
+                  (local.get $x)
+                  (i32.const 5)
+                )
+              )
+            )
+            (br $topmost
+              (i32.const 121)
+            )
+          )
+          (br $topmost
+            (i32.const 51)
+          )
+        )
+        (nop)
+      )
+      (block $label$break$Lout
+        (block $switch-default$16
+          (block $switch-case$15
+            (block $switch-case$12
+              (block $switch-case$9
+                (block $switch-case$8
+                  (br_table $switch-case$15 $switch-default$16 $switch-default$16 $switch-case$12 $switch-default$16 $switch-default$16 $switch-default$16 $switch-default$16 $switch-case$9 $switch-default$16 $switch-case$8 $switch-default$16
+                    (i32.sub
+                      (local.get $x)
+                      (i32.const 2)
+                    )
+                  )
+                )
+                (br $label$break$Lout)
+              )
+              (br $label$break$Lout)
+            )
+            (block $while-out$10
+              (loop $while-in$11
+                (block $block1
+                  (br $while-out$10)
+                  (br $while-in$11)
+                )
+              )
+              (br $label$break$Lout)
+            )
+          )
+          (block $while-out$13
+            (loop $while-in$14
+              (block $block3
+                (br $label$break$Lout)
+                (br $while-in$14)
+              )
+            )
+            (br $label$break$Lout)
+          )
+        )
+        (nop)
+      )
+      (i32.const 0)
+    )
+  )
+  (func $blocker (type $FUNCSIG$v)
+    (block $label$break$L
+      (br $label$break$L)
+    )
+  )
+  (func $frem (type $4) (result f64)
+    (call $f64-rem
+      (f64.const 5.5)
+      (f64.const 1.2)
+    )
+  )
+  (func $big_uint_div_u (type $5) (result i32)
+    (local $x i32)
+    (block $topmost (result i32)
+      (local.set $x
+        (i32.and
+          (i32.div_u
+            (i32.const -1)
+            (i32.const 2)
+          )
+          (i32.const -1)
+        )
+      )
+      (local.get $x)
+    )
+  )
+  (func $fr (type $FUNCSIG$vf) (param $x f32)
+    (local $y f32)
+    (local $z f64)
+    (block $block0
+      (drop
+        (f32.demote_f64
+          (local.get $z)
+        )
+      )
+      (drop
+        (local.get $y)
+      )
+      (drop
+        (f32.const 5)
+      )
+      (drop
+        (f32.const 0)
+      )
+      (drop
+        (f32.const 5)
+      )
+      (drop
+        (f32.const 0)
+      )
+    )
+  )
+  (func $negZero (type $4) (result f64)
+    (f64.const -0)
+  )
+  (func $abs (type $FUNCSIG$v)
+    (local $x i32)
+    (local $y f64)
+    (local $z f32)
+    (local $asm2wasm_i32_temp i32)
+    (block $block0
+      (local.set $x
+        (block $block1 (result i32)
+          (local.set $asm2wasm_i32_temp
+            (i32.const 0)
+          )
+          (select
+            (i32.sub
+              (i32.const 0)
+              (local.get $asm2wasm_i32_temp)
+            )
+            (local.get $asm2wasm_i32_temp)
+            (i32.lt_s
+              (local.get $asm2wasm_i32_temp)
+              (i32.const 0)
+            )
+          )
+        )
+      )
+      (local.set $y
+        (f64.abs
+          (f64.const 0)
+        )
+      )
+      (local.set $z
+        (f32.abs
+          (f32.const 0)
+        )
+      )
+    )
+  )
+  (func $neg (type $FUNCSIG$v)
+    (local $x f32)
+    (block $block0
+      (local.set $x
+        (f32.neg
+          (local.get $x)
+        )
+      )
+      (call_indirect (type $FUNCSIG$vf)
+        (local.get $x)
+        (i32.add
+          (i32.and
+            (i32.const 1)
+            (i32.const 7)
+          )
+          (i32.const 8)
+        )
+      )
+    )
+  )
+  (func $cneg (type $FUNCSIG$vf) (param $x f32)
+    (call_indirect (type $FUNCSIG$vf)
+      (local.get $x)
+      (i32.add
+        (i32.and
+          (i32.const 1)
+          (i32.const 7)
+        )
+        (i32.const 8)
+      )
+    )
+  )
+  (func $___syscall_ret (type $FUNCSIG$v)
+    (local $$0 i32)
+    (drop
+      (i32.gt_u
+        (i32.shr_u
+          (local.get $$0)
+          (i32.const 0)
+        )
+        (i32.const -4096)
+      )
+    )
+  )
+  (func $z (type $FUNCSIG$v)
+    (nop)
+  )
+  (func $w (type $FUNCSIG$v)
+    (nop)
+  )
+  (func $block_and_after (type $5) (result i32)
+    (block $waka
+      (drop
+        (i32.const 1)
+      )
+      (br $waka)
+    )
+    (i32.const 0)
+  )
+  (func $loop-roundtrip (type $7) (param $0 f64) (result f64)
+    (loop $loop-in1 (result f64)
+      (drop
+        (local.get $0)
+      )
+      (local.get $0)
+    )
+  )
+  (func $big-i64 (type $8) (result i64)
+    (i64.const -9218868437227405313)
+  )
+  (func $i64-store32 (type $9) (param $0 i32) (param $1 i64)
+    (i64.store32
+      (local.get $0)
+      (local.get $1)
+    )
+  )
+  (func $return-unreachable (result i32)
+    (return (i32.const 1))
+  )
+  (func $unreachable-block (result i32)
+    (f64.abs
+      (block ;; note no type - valid in binaryen IR, in wasm must be i32
+        (drop (i32.const 1))
+        (return (i32.const 2))
+      )
+    )
+  )
+  (func $unreachable-block-toplevel (result i32)
+    (block ;; note no type - valid in binaryen IR, in wasm must be i32
+      (drop (i32.const 1))
+      (return (i32.const 2))
+    )
+  )
+  (func $unreachable-block0 (result i32)
+    (f64.abs
+      (block ;; note no type - valid in binaryen IR, in wasm must be i32
+        (return (i32.const 2))
+      )
+    )
+  )
+  (func $unreachable-block0-toplevel (result i32)
+    (block ;; note no type - valid in binaryen IR, in wasm must be i32
+      (return (i32.const 2))
+    )
+  )
+  (func $unreachable-block-with-br (result i32)
+    (block $block ;; unreachable type due to last element having that type, but the block is exitable
+      (drop (i32.const 1))
+      (br $block)
+    )
+    (i32.const 1)
+  )
+  (func $unreachable-if (result i32)
+    (f64.abs
+      (if ;; note no type - valid in binaryen IR, in wasm must be i32
+        (i32.const 3)
+        (return (i32.const 2))
+        (return (i32.const 1))
+      )
+    )
+  )
+  (func $unreachable-if-toplevel (result i32)
+    (if ;; note no type - valid in binaryen IR, in wasm must be i32
+      (i32.const 3)
+      (return (i32.const 2))
+      (return (i32.const 1))
+    )
+  )
+  (func $unreachable-loop (result i32)
+    (f64.abs
+      (loop ;; note no type - valid in binaryen IR, in wasm must be i32
+        (nop)
+        (return (i32.const 1))
+      )
+    )
+  )
+  (func $unreachable-loop0 (result i32)
+    (f64.abs
+      (loop ;; note no type - valid in binaryen IR, in wasm must be i32
+        (return (i32.const 1))
+      )
+    )
+  )
+  (func $unreachable-loop-toplevel (result i32)
+    (loop ;; note no type - valid in binaryen IR, in wasm must be i32
+      (nop)
+      (return (i32.const 1))
+    )
+  )
+  (func $unreachable-loop0-toplevel (result i32)
+    (loop ;; note no type - valid in binaryen IR, in wasm must be i32
+      (return (i32.const 1))
+    )
+  )
+  (func $unreachable-ifs
+    (if (unreachable) (nop))
+    (if (unreachable) (unreachable))
+    (if (unreachable) (nop) (nop))
+    (if (unreachable) (unreachable) (nop))
+    (if (unreachable) (nop) (unreachable))
+    (if (unreachable) (unreachable) (unreachable))
+    ;;
+    (if (i32.const 1) (unreachable) (nop))
+    (if (i32.const 1) (nop) (unreachable))
+    (if (i32.const 1) (unreachable) (unreachable))
+  )
+  (func $unreachable-if-arm
+    (if
+      (i32.const 1)
+      (block
+        (nop)
+      )
+      (block
+        (unreachable)
+        (drop
+          (i32.const 1)
+        )
+      )
+    )
+  )
+  (func $local-to-stack (param $x i32) (result i32)
+    (local $temp i32)
+    (local.set $temp (call $local-to-stack (i32.const 1))) ;; this set could just be on the stack
+    (drop (call $local-to-stack (i32.const 2)))
+    (local.get $temp)
+  )
+  (func $local-to-stack-1 (param $x i32) (result i32)
+    (local $temp i32)
+    (local.set $temp (call $local-to-stack (i32.const 1)))
+    (drop (call $local-to-stack (i32.const 2)))
+    (i32.eqz
+      (local.get $temp)
+    )
+  )
+  (func $local-to-stack-1b (param $x i32) (result i32)
+    (local $temp i32)
+    (local.set $temp (call $local-to-stack (i32.const 1)))
+    (drop (call $local-to-stack (i32.const 2)))
+    (i32.add
+      (local.get $temp)
+      (i32.const 3)
+    )
+  )
+  (func $local-to-stack-1c-no (param $x i32) (result i32)
+    (local $temp i32)
+    (local.set $temp (call $local-to-stack (i32.const 1)))
+    (drop (call $local-to-stack (i32.const 2)))
+    (i32.add
+      (i32.const 3) ;; this is in the way
+      (local.get $temp)
+    )
+  )
+  (func $local-to-stack-2-no (param $x i32) (result i32)
+    (local $temp i32)
+    (local.set $temp (call $local-to-stack (i32.const 1)))
+    (drop (call $local-to-stack (i32.const 2)))
+    (i32.add
+      (local.get $temp)
+      (local.get $temp) ;; a second use - so cannot stack it
+    )
+  )
+  (func $local-to-stack-3-no (param $x i32) (result i32)
+    (local $temp i32)
+    (if (i32.const 1)
+      (local.set $temp (call $local-to-stack (i32.const 1)))
+      (local.set $temp (call $local-to-stack (i32.const 2))) ;; two sets for that get
+    )
+    (drop (call $local-to-stack (i32.const 3)))
+    (local.get $temp)
+  )
+  (func $local-to-stack-multi-4 (param $x i32) (result i32)
+    (local $temp1 i32)
+    (local $temp2 i32)
+    (local.set $temp1 (call $local-to-stack-multi-4 (i32.const 1)))
+    (drop (call $local-to-stack-multi-4 (i32.const 2)))
+    (drop (local.get $temp1))
+    (local.set $temp1 (call $local-to-stack-multi-4 (i32.const 3))) ;; same local, used later
+    (drop (call $local-to-stack-multi-4 (i32.const 4)))
+    (local.get $temp1)
+  )
+  (func $local-to-stack-multi-5 (param $x i32) (result i32)
+    (local $temp1 i32)
+    (local $temp2 i32)
+    (local.set $temp1 (call $local-to-stack-multi-4 (i32.const 1)))
+    (drop (call $local-to-stack-multi-4 (i32.const 2)))
+    (drop (local.get $temp1))
+    (local.set $temp2 (call $local-to-stack-multi-4 (i32.const 3))) ;; different local, used later
+    (drop (call $local-to-stack-multi-4 (i32.const 4)))
+    (local.get $temp2)
+  )
+  (func $local-to-stack-multi-6-justone (param $x i32) (result i32)
+    (local $temp1 i32)
+    (local $temp2 i32)
+    (local.set $temp1 (call $local-to-stack-multi-4 (i32.const 1)))
+    (drop (call $local-to-stack-multi-4 (i32.const 2)))
+    (drop (local.get $temp1))
+    (local.set $temp2 (call $local-to-stack-multi-4 (i32.const 3))) ;; different local, used later
+    (drop (call $local-to-stack-multi-4 (i32.const 4)))
+    (i32.add
+      (local.get $temp2)
+      (local.get $temp2)
+    )
+  )
+  (func $local-to-stack-multi-7-justone (param $x i32) (result i32)
+    (local $temp1 i32)
+    (local $temp2 i32)
+    (local.set $temp1 (call $local-to-stack-multi-4 (i32.const 1)))
+    (drop (call $local-to-stack-multi-4 (i32.const 2)))
+    (drop
+      (i32.add
+        (local.get $temp1)
+        (local.get $temp1)
+      )
+    )
+    (local.set $temp2 (call $local-to-stack-multi-4 (i32.const 3))) ;; different local, used later
+    (drop (call $local-to-stack-multi-4 (i32.const 4)))
+    (local.get $temp2)
+  )
+  (func $local-to-stack-overlapping-multi-8-no (param $x i32) (result i32)
+    (local $temp1 i32)
+    (local $temp2 i32)
+    (local.set $temp1 (call $local-to-stack-multi-4 (i32.const 1)))
+    (local.set $temp2 (call $local-to-stack-multi-4 (i32.const 1)))
+    (drop (call $local-to-stack-multi-4 (i32.const 3)))
+    (i32.add
+      (local.get $temp2) ;; the timing
+      (local.get $temp1) ;; it sucks
+    )
+  )
+  (func $local-to-stack-overlapping-multi-9-yes (param $x i32) (result i32)
+    (local $temp1 i32)
+    (local $temp2 i32)
+    (local.set $temp1 (call $local-to-stack-multi-4 (i32.const 1)))
+    (local.set $temp2 (call $local-to-stack-multi-4 (i32.const 1)))
+    (drop (call $local-to-stack-multi-4 (i32.const 3)))
+    (i32.add
+      (local.get $temp1) ;; the stars align
+      (local.get $temp2) ;; and a time presents itself
+    )
+  )
+  (func $local-to-stack-through-control-flow
+    (local $temp1 i32)
+    (local $temp2 i32)
+    (local.set $temp2 (call $local-to-stack-multi-4 (i32.const 0)))
+    (local.set $temp1 (call $local-to-stack-multi-4 (i32.const 1)))
+    (if (i32.const 0) (nop))
+    (drop (local.get $temp1))
+    (local.set $temp1 (call $local-to-stack-multi-4 (i32.const 2)))
+    (block $block (br $block))
+    (drop (local.get $temp1))
+    (drop (local.get $temp2))
+  )
+  (func $local-to-stack-in-control-flow
+    (local $temp1 i32)
+    (if (i32.const 0)
+      (block
+        (local.set $temp1 (call $local-to-stack-multi-4 (i32.const 0)))
+        (drop (local.get $temp1))
+      )
+      (block
+        (local.set $temp1 (call $local-to-stack-multi-4 (i32.const 1)))
+        (drop (local.get $temp1))
+      )
+    )
+  )
+  (func $remove-block (param $x i32) (result i32)
+   (local $temp i32)
+   (i32.add
+    (call $remove-block (i32.const 0))
+    (i32.eqz
+     (block (result i32) ;; after we use the stack instead of the local, we can remove this block
+      (local.set $temp (call $remove-block (i32.const 1)))
+      (drop (call $remove-block (i32.const 2)))
+      (local.get $temp)
+     )
+    )
+   )
+  )
+)
diff --git a/binaryen/test/passes/ignore_missing_func_dwarf.bin.txt b/binaryen/test/passes/ignore_missing_func_dwarf.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/ignore_missing_func_dwarf.bin.txt
@@ -0,0 +1,1082 @@
+(module
+ (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)))
+ (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))
+ (global $global$0 (mut i32) (i32.const 5244064))
+ (global $global$1 i32 (i32.const 1172))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__data_end" (global $global$1))
+ (func $__wasm_call_ctors
+ )
+ (func $used\28int\29 (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  ;; code offset: 0xe
+  (local.set $1
+   ;; code offset: 0x8
+   (global.get $global$0)
+  )
+  ;; code offset: 0x12
+  (local.set $2
+   ;; code offset: 0x10
+   (i32.const 16)
+  )
+  ;; code offset: 0x19
+  (local.set $3
+   ;; code offset: 0x18
+   (i32.sub
+    ;; code offset: 0x14
+    (local.get $1)
+    ;; code offset: 0x16
+    (local.get $2)
+   )
+  )
+  ;; code offset: 0x1f
+  (i32.store offset=12
+   ;; code offset: 0x1b
+   (local.get $3)
+   ;; code offset: 0x1d
+   (local.get $0)
+  )
+  ;; code offset: 0x27
+  (local.set $4
+   ;; code offset: 0x24
+   (i32.load offset=12
+    ;; code offset: 0x22
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x2b
+  (local.set $5
+   ;; code offset: 0x29
+   (i32.const 1)
+  )
+  ;; code offset: 0x32
+  (local.set $6
+   ;; code offset: 0x31
+   (i32.add
+    ;; code offset: 0x2d
+    (local.get $4)
+    ;; code offset: 0x2f
+    (local.get $5)
+   )
+  )
+  ;; code offset: 0x38
+  (i32.store offset=12
+   ;; code offset: 0x34
+   (local.get $3)
+   ;; code offset: 0x36
+   (local.get $6)
+  )
+  ;; code offset: 0x40
+  (local.set $7
+   ;; code offset: 0x3d
+   (i32.load offset=12
+    ;; code offset: 0x3b
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x44
+  (local.set $8
+   ;; code offset: 0x42
+   (i32.const -1)
+  )
+  ;; code offset: 0x4b
+  (local.set $9
+   ;; code offset: 0x4a
+   (i32.add
+    ;; code offset: 0x46
+    (local.get $7)
+    ;; code offset: 0x48
+    (local.get $8)
+   )
+  )
+  ;; code offset: 0x51
+  (i32.store offset=12
+   ;; code offset: 0x4d
+   (local.get $3)
+   ;; code offset: 0x4f
+   (local.get $9)
+  )
+  ;; code offset: 0x59
+  (local.set $10
+   ;; code offset: 0x56
+   (i32.load offset=12
+    ;; code offset: 0x54
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x5d
+  (return
+   ;; code offset: 0x5b
+   (local.get $10)
+  )
+ )
+ (func $__original_main (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  ;; code offset: 0x69
+  (local.set $0
+   ;; code offset: 0x63
+   (global.get $global$0)
+  )
+  ;; code offset: 0x6d
+  (local.set $1
+   ;; code offset: 0x6b
+   (i32.const 16)
+  )
+  ;; code offset: 0x74
+  (local.set $2
+   ;; code offset: 0x73
+   (i32.sub
+    ;; code offset: 0x6f
+    (local.get $0)
+    ;; code offset: 0x71
+    (local.get $1)
+   )
+  )
+  ;; code offset: 0x78
+  (global.set $global$0
+   ;; code offset: 0x76
+   (local.get $2)
+  )
+  ;; code offset: 0x80
+  (local.set $3
+   ;; code offset: 0x7e
+   (i32.const 42)
+  )
+  ;; code offset: 0x84
+  (local.set $4
+   ;; code offset: 0x82
+   (i32.const 0)
+  )
+  ;; code offset: 0x8a
+  (i32.store offset=12
+   ;; code offset: 0x86
+   (local.get $2)
+   ;; code offset: 0x88
+   (local.get $4)
+  )
+  ;; code offset: 0x95
+  (local.set $5
+   ;; code offset: 0x8f
+   (call $used\28int\29
+    ;; code offset: 0x8d
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x99
+  (local.set $6
+   ;; code offset: 0x97
+   (i32.const 0)
+  )
+  ;; code offset: 0xa4
+  (local.set $7
+   ;; code offset: 0x9d
+   (i32.load offset=1168
+    ;; code offset: 0x9b
+    (local.get $6)
+   )
+  )
+  ;; code offset: 0xab
+  (local.set $8
+   ;; code offset: 0xaa
+   (i32.add
+    ;; code offset: 0xa6
+    (local.get $5)
+    ;; code offset: 0xa8
+    (local.get $7)
+   )
+  )
+  ;; code offset: 0xaf
+  (local.set $9
+   ;; code offset: 0xad
+   (i32.const 16)
+  )
+  ;; code offset: 0xb6
+  (local.set $10
+   ;; code offset: 0xb5
+   (i32.add
+    ;; code offset: 0xb1
+    (local.get $2)
+    ;; code offset: 0xb3
+    (local.get $9)
+   )
+  )
+  ;; code offset: 0xba
+  (global.set $global$0
+   ;; code offset: 0xb8
+   (local.get $10)
+  )
+  ;; code offset: 0xc2
+  (return
+   ;; code offset: 0xc0
+   (local.get $8)
+  )
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  ;; code offset: 0xce
+  (local.set $2
+   ;; code offset: 0xc8
+   (call $__original_main)
+  )
+  ;; code offset: 0xd2
+  (return
+   ;; code offset: 0xd0
+   (local.get $2)
+  )
+ )
+ ;; custom section ".debug_info", size 175
+ ;; custom section ".debug_ranges", size 32
+ ;; custom section ".debug_abbrev", size 117
+ ;; custom section ".debug_line", size 128
+ ;; custom section ".debug_str", size 235
+ ;; custom section "producers", size 180
+)
+DWARF debug info
+================
+
+Contains section .debug_info (175 bytes)
+Contains section .debug_ranges (32 bytes)
+Contains section .debug_abbrev (117 bytes)
+Contains section .debug_line (128 bytes)
+Contains section .debug_str (235 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[2] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_location	DW_FORM_exprloc
+
+[3] DW_TAG_pointer_type	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[4] DW_TAG_const_type	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[5] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+[6] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[7] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_exprloc
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[8] DW_TAG_subprogram	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x000000ab version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x000000af)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project f39277c1d370ccbbec2e20a20375ee6fb7281ae4)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000095] = "a.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x0000009b] = "/home/alon/Dev/emscripten")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+              DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
+                 [0x00000005, 0x0000005f))
+
+0x00000026:   DW_TAG_variable [2]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000b5] = "quine")
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0037 => {0x00000037} "const char*")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/a.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(2)
+                DW_AT_location [DW_FORM_exprloc]	(DW_OP_addr 0x490)
+
+0x00000037:   DW_TAG_pointer_type [3]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x003c => {0x0000003c} "const char")
+
+0x0000003c:   DW_TAG_const_type [4]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0041 => {0x00000041} "char")
+
+0x00000041:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000bb] = "char")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed_char)
+                DW_AT_byte_size [DW_FORM_data1]	(0x01)
+
+0x00000048:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c0] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x0000004f:   DW_TAG_subprogram [6] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000005)
+                DW_AT_high_pc [DW_FORM_data4]	(0x0000005a)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x000000c4] = "_Z4usedi")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000cd] = "used")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/a.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(4)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0048 => {0x00000048} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000066:     DW_TAG_formal_parameter [7]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0xc)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000e9] = "x")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/a.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(4)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0048 => {0x00000048} "int")
+
+0x00000074:     NULL
+
+0x00000075:   DW_TAG_subprogram [6] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+                DW_AT_high_pc [DW_FORM_data4]	(0x0000005a)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x000000d2] = "_Z6unusedi")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dd] = "unused")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/a.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(10)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0048 => {0x00000048} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000008c:     DW_TAG_formal_parameter [7]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0xc)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000e9] = "x")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/a.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(10)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0048 => {0x00000048} "int")
+
+0x0000009a:     NULL
+
+0x0000009b:   DW_TAG_subprogram [8]  
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000060)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000064)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000e4] = "main")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/a.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(16)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0048 => {0x00000048} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x000000ae:   NULL
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x0000007c
+         version: 4
+ prologue_length: 0x0000001d
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "a.cpp"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000027: 00 DW_LNE_set_address (0x0000000000000005)
+0x0000002e: 15 address += 0,  line += 3
+            0x0000000000000005      4      0      1   0             0  is_stmt
+
+0x0000002f: 05 DW_LNS_set_column (4)
+0x00000031: 0a DW_LNS_set_prologue_end
+0x00000032: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000033: bb address += 12,  line += 1
+            0x0000000000000022      5      4      1   0             0  is_stmt prologue_end
+
+0x00000034: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000035: 83 address += 8,  line += 1
+            0x000000000000003b      6      4      1   0             0  is_stmt
+
+0x00000036: 05 DW_LNS_set_column (10)
+0x00000038: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000039: 83 address += 8,  line += 1
+            0x0000000000000054      7     10      1   0             0  is_stmt
+
+0x0000003a: 05 DW_LNS_set_column (3)
+0x0000003c: 06 DW_LNS_negate_stmt
+0x0000003d: 74 address += 7,  line += 0
+            0x000000000000005b      7      3      1   0             0 
+
+0x0000003e: 02 DW_LNS_advance_pc (4)
+0x00000040: 00 DW_LNE_end_sequence
+            0x000000000000005f      7      3      1   0             0  end_sequence
+
+0x00000043: 00 DW_LNE_set_address (0x0000000000000000)
+0x0000004a: 03 DW_LNS_advance_line (10)
+0x0000004c: 01 DW_LNS_copy
+            0x0000000000000000     10      0      1   0             0  is_stmt
+
+
+0x0000004d: 05 DW_LNS_set_column (5)
+0x0000004f: 0a DW_LNS_set_prologue_end
+0x00000050: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000051: bb address += 12,  line += 1
+            0x000000000000001d     11      5      1   0             0  is_stmt prologue_end
+
+0x00000052: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000053: 83 address += 8,  line += 1
+            0x0000000000000036     12      5      1   0             0  is_stmt
+
+0x00000054: 05 DW_LNS_set_column (10)
+0x00000056: 08 DW_LNS_const_add_pc (0x0000000000000011)
+0x00000057: 83 address += 8,  line += 1
+            0x000000000000004f     13     10      1   0             0  is_stmt
+
+0x00000058: 05 DW_LNS_set_column (3)
+0x0000005a: 06 DW_LNS_negate_stmt
+0x0000005b: 74 address += 7,  line += 0
+            0x0000000000000056     13      3      1   0             0 
+
+0x0000005c: 02 DW_LNS_advance_pc (4)
+0x0000005e: 00 DW_LNE_end_sequence
+            0x000000000000005a     13      3      1   0             0  end_sequence
+
+0x00000061: 00 DW_LNE_set_address (0x0000000000000060)
+0x00000068: 03 DW_LNS_advance_line (16)
+0x0000006a: 01 DW_LNS_copy
+            0x0000000000000060     16      0      1   0             0  is_stmt
+
+
+0x0000006b: 05 DW_LNS_set_column (10)
+0x0000006d: 0a DW_LNS_set_prologue_end
+0x0000006e: 02 DW_LNS_advance_pc (45)
+0x00000070: 13 address += 0,  line += 1
+            0x000000000000008d     17     10      1   0             0  is_stmt prologue_end
+
+0x00000071: 05 DW_LNS_set_column (25)
+0x00000073: 06 DW_LNS_negate_stmt
+0x00000074: 9e address += 10,  line += 0
+            0x0000000000000097     17     25      1   0             0 
+
+0x00000075: 05 DW_LNS_set_column (19)
+0x00000077: e4 address += 15,  line += 0
+            0x00000000000000a6     17     19      1   0             0 
+
+0x00000078: 05 DW_LNS_set_column (3)
+0x0000007a: 74 address += 7,  line += 0
+            0x00000000000000ad     17      3      1   0             0 
+
+0x0000007b: 02 DW_LNS_advance_pc (23)
+0x0000007d: 00 DW_LNE_end_sequence
+            0x00000000000000c4     17      3      1   0             0  end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project f39277c1d370ccbbec2e20a20375ee6fb7281ae4)"
+0x00000095: "a.cpp"
+0x0000009b: "/home/alon/Dev/emscripten"
+0x000000b5: "quine"
+0x000000bb: "char"
+0x000000c0: "int"
+0x000000c4: "_Z4usedi"
+0x000000cd: "used"
+0x000000d2: "_Z6unusedi"
+0x000000dd: "unused"
+0x000000e4: "main"
+0x000000e9: "x"
+
+.debug_ranges contents:
+00000000 00000005 0000005f
+00000000 <End of list>
+00000010 00000060 000000c4
+00000010 <End of list>
+DWARF debug info
+================
+
+Contains section .debug_info (175 bytes)
+Contains section .debug_ranges (32 bytes)
+Contains section .debug_abbrev (117 bytes)
+Contains section .debug_line (169 bytes)
+Contains section .debug_str (235 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[2] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_location	DW_FORM_exprloc
+
+[3] DW_TAG_pointer_type	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[4] DW_TAG_const_type	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+[5] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+[6] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[7] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_exprloc
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[8] DW_TAG_subprogram	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x000000ab version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x000000af)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project f39277c1d370ccbbec2e20a20375ee6fb7281ae4)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000095] = "a.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x0000009b] = "/home/alon/Dev/emscripten")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+              DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
+                 [0x00000005, 0x0000006d))
+
+0x00000026:   DW_TAG_variable [2]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000b5] = "quine")
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0037 => {0x00000037} "const char*")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/a.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(2)
+                DW_AT_location [DW_FORM_exprloc]	(DW_OP_addr 0x490)
+
+0x00000037:   DW_TAG_pointer_type [3]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x003c => {0x0000003c} "const char")
+
+0x0000003c:   DW_TAG_const_type [4]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0041 => {0x00000041} "char")
+
+0x00000041:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000bb] = "char")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed_char)
+                DW_AT_byte_size [DW_FORM_data1]	(0x01)
+
+0x00000048:   DW_TAG_base_type [5]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c0] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x0000004f:   DW_TAG_subprogram [6] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000005)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000068)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x000000c4] = "_Z4usedi")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000cd] = "used")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/a.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(4)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0048 => {0x00000048} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000066:     DW_TAG_formal_parameter [7]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0xc)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000e9] = "x")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/a.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(4)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0048 => {0x00000048} "int")
+
+0x00000074:     NULL
+
+0x00000075:   DW_TAG_subprogram [6] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000000)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x000000d2] = "_Z6unusedi")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000dd] = "unused")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/a.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(10)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0048 => {0x00000048} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000008c:     DW_TAG_formal_parameter [7]  
+                  DW_AT_location [DW_FORM_exprloc]	(DW_OP_plus_uconst 0xc)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000e9] = "x")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/a.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(10)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0048 => {0x00000048} "int")
+
+0x0000009a:     NULL
+
+0x0000009b:   DW_TAG_subprogram [8]  
+                DW_AT_low_pc [DW_FORM_addr]	(0x000000000000006e)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000065)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000e4] = "main")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/alon/Dev/emscripten/a.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(16)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0048 => {0x00000048} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x000000ae:   NULL
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x000000a5
+         version: 4
+ prologue_length: 0x0000001d
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "a.cpp"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000027: 00 DW_LNE_set_address (0x0000000000000005)
+0x0000002e: 03 DW_LNS_advance_line (4)
+0x00000030: 01 DW_LNS_copy
+            0x0000000000000005      4      0      1   0             0  is_stmt
+
+
+0x00000031: 00 DW_LNE_set_address (0x0000000000000030)
+0x00000038: 03 DW_LNS_advance_line (5)
+0x0000003a: 05 DW_LNS_set_column (4)
+0x0000003c: 0a DW_LNS_set_prologue_end
+0x0000003d: 01 DW_LNS_copy
+            0x0000000000000030      5      4      1   0             0  is_stmt prologue_end
+
+
+0x0000003e: 00 DW_LNE_set_address (0x0000000000000049)
+0x00000045: 03 DW_LNS_advance_line (6)
+0x00000047: 01 DW_LNS_copy
+            0x0000000000000049      6      4      1   0             0  is_stmt
+
+
+0x00000048: 00 DW_LNE_set_address (0x0000000000000062)
+0x0000004f: 03 DW_LNS_advance_line (7)
+0x00000051: 05 DW_LNS_set_column (10)
+0x00000053: 01 DW_LNS_copy
+            0x0000000000000062      7     10      1   0             0  is_stmt
+
+
+0x00000054: 00 DW_LNE_set_address (0x0000000000000069)
+0x0000005b: 05 DW_LNS_set_column (3)
+0x0000005d: 06 DW_LNS_negate_stmt
+0x0000005e: 01 DW_LNS_copy
+            0x0000000000000069      7      3      1   0             0 
+
+
+0x0000005f: 00 DW_LNE_set_address (0x000000000000006d)
+0x00000066: 00 DW_LNE_end_sequence
+            0x000000000000006d      7      3      1   0             0  end_sequence
+
+0x00000069: 00 DW_LNE_set_address (0x000000000000006e)
+0x00000070: 03 DW_LNS_advance_line (16)
+0x00000072: 01 DW_LNS_copy
+            0x000000000000006e     16      0      1   0             0  is_stmt
+
+
+0x00000073: 00 DW_LNE_set_address (0x00000000000000a7)
+0x0000007a: 03 DW_LNS_advance_line (17)
+0x0000007c: 05 DW_LNS_set_column (10)
+0x0000007e: 0a DW_LNS_set_prologue_end
+0x0000007f: 01 DW_LNS_copy
+            0x00000000000000a7     17     10      1   0             0  is_stmt prologue_end
+
+
+0x00000080: 00 DW_LNE_set_address (0x00000000000000ad)
+0x00000087: 05 DW_LNS_set_column (25)
+0x00000089: 06 DW_LNS_negate_stmt
+0x0000008a: 01 DW_LNS_copy
+            0x00000000000000ad     17     25      1   0             0 
+
+
+0x0000008b: 00 DW_LNE_set_address (0x00000000000000b9)
+0x00000092: 05 DW_LNS_set_column (19)
+0x00000094: 01 DW_LNS_copy
+            0x00000000000000b9     17     19      1   0             0 
+
+
+0x00000095: 00 DW_LNE_set_address (0x00000000000000c0)
+0x0000009c: 05 DW_LNS_set_column (3)
+0x0000009e: 01 DW_LNS_copy
+            0x00000000000000c0     17      3      1   0             0 
+
+
+0x0000009f: 00 DW_LNE_set_address (0x00000000000000d3)
+0x000000a6: 00 DW_LNE_end_sequence
+            0x00000000000000d3     17      3      1   0             0  end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project f39277c1d370ccbbec2e20a20375ee6fb7281ae4)"
+0x00000095: "a.cpp"
+0x0000009b: "/home/alon/Dev/emscripten"
+0x000000b5: "quine"
+0x000000bb: "char"
+0x000000c0: "int"
+0x000000c4: "_Z4usedi"
+0x000000cd: "used"
+0x000000d2: "_Z6unusedi"
+0x000000dd: "unused"
+0x000000e4: "main"
+0x000000e9: "x"
+
+.debug_ranges contents:
+00000000 00000005 0000006d
+00000000 <End of list>
+00000010 0000006e 000000d3
+00000010 <End of list>
+(module
+ (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)))
+ (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))
+ (global $global$0 (mut i32) (i32.const 5244064))
+ (global $global$1 i32 (i32.const 1172))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__data_end" (global $global$1))
+ (func $__wasm_call_ctors
+ )
+ (func $used\28int\29 (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  ;; code offset: 0x1c
+  (local.set $1
+   ;; code offset: 0x1a
+   (global.get $global$0)
+  )
+  ;; code offset: 0x20
+  (local.set $2
+   ;; code offset: 0x1e
+   (i32.const 16)
+  )
+  ;; code offset: 0x27
+  (local.set $3
+   ;; code offset: 0x26
+   (i32.sub
+    ;; code offset: 0x22
+    (local.get $1)
+    ;; code offset: 0x24
+    (local.get $2)
+   )
+  )
+  ;; code offset: 0x2d
+  (i32.store offset=12
+   ;; code offset: 0x29
+   (local.get $3)
+   ;; code offset: 0x2b
+   (local.get $0)
+  )
+  ;; code offset: 0x35
+  (local.set $4
+   ;; code offset: 0x32
+   (i32.load offset=12
+    ;; code offset: 0x30
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x39
+  (local.set $5
+   ;; code offset: 0x37
+   (i32.const 1)
+  )
+  ;; code offset: 0x40
+  (local.set $6
+   ;; code offset: 0x3f
+   (i32.add
+    ;; code offset: 0x3b
+    (local.get $4)
+    ;; code offset: 0x3d
+    (local.get $5)
+   )
+  )
+  ;; code offset: 0x46
+  (i32.store offset=12
+   ;; code offset: 0x42
+   (local.get $3)
+   ;; code offset: 0x44
+   (local.get $6)
+  )
+  ;; code offset: 0x4e
+  (local.set $7
+   ;; code offset: 0x4b
+   (i32.load offset=12
+    ;; code offset: 0x49
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x52
+  (local.set $8
+   ;; code offset: 0x50
+   (i32.const -1)
+  )
+  ;; code offset: 0x59
+  (local.set $9
+   ;; code offset: 0x58
+   (i32.add
+    ;; code offset: 0x54
+    (local.get $7)
+    ;; code offset: 0x56
+    (local.get $8)
+   )
+  )
+  ;; code offset: 0x5f
+  (i32.store offset=12
+   ;; code offset: 0x5b
+   (local.get $3)
+   ;; code offset: 0x5d
+   (local.get $9)
+  )
+  ;; code offset: 0x67
+  (local.set $10
+   ;; code offset: 0x64
+   (i32.load offset=12
+    ;; code offset: 0x62
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x6b
+  (return
+   ;; code offset: 0x69
+   (local.get $10)
+  )
+ )
+ (func $__original_main (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  ;; code offset: 0x87
+  (local.set $0
+   ;; code offset: 0x85
+   (global.get $global$0)
+  )
+  ;; code offset: 0x8b
+  (local.set $1
+   ;; code offset: 0x89
+   (i32.const 16)
+  )
+  ;; code offset: 0x92
+  (local.set $2
+   ;; code offset: 0x91
+   (i32.sub
+    ;; code offset: 0x8d
+    (local.get $0)
+    ;; code offset: 0x8f
+    (local.get $1)
+   )
+  )
+  ;; code offset: 0x96
+  (global.set $global$0
+   ;; code offset: 0x94
+   (local.get $2)
+  )
+  ;; code offset: 0x9a
+  (local.set $3
+   ;; code offset: 0x98
+   (i32.const 42)
+  )
+  ;; code offset: 0x9e
+  (local.set $4
+   ;; code offset: 0x9c
+   (i32.const 0)
+  )
+  ;; code offset: 0xa4
+  (i32.store offset=12
+   ;; code offset: 0xa0
+   (local.get $2)
+   ;; code offset: 0xa2
+   (local.get $4)
+  )
+  ;; code offset: 0xab
+  (local.set $5
+   ;; code offset: 0xa9
+   (call $used\28int\29
+    ;; code offset: 0xa7
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0xaf
+  (local.set $6
+   ;; code offset: 0xad
+   (i32.const 0)
+  )
+  ;; code offset: 0xb7
+  (local.set $7
+   ;; code offset: 0xb3
+   (i32.load offset=1168
+    ;; code offset: 0xb1
+    (local.get $6)
+   )
+  )
+  ;; code offset: 0xbe
+  (local.set $8
+   ;; code offset: 0xbd
+   (i32.add
+    ;; code offset: 0xb9
+    (local.get $5)
+    ;; code offset: 0xbb
+    (local.get $7)
+   )
+  )
+  ;; code offset: 0xc2
+  (local.set $9
+   ;; code offset: 0xc0
+   (i32.const 16)
+  )
+  ;; code offset: 0xc9
+  (local.set $10
+   ;; code offset: 0xc8
+   (i32.add
+    ;; code offset: 0xc4
+    (local.get $2)
+    ;; code offset: 0xc6
+    (local.get $9)
+   )
+  )
+  ;; code offset: 0xcd
+  (global.set $global$0
+   ;; code offset: 0xcb
+   (local.get $10)
+  )
+  ;; code offset: 0xd1
+  (return
+   ;; code offset: 0xcf
+   (local.get $8)
+  )
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  ;; code offset: 0xd9
+  (local.set $2
+   ;; code offset: 0xd7
+   (call $__original_main)
+  )
+  ;; code offset: 0xdd
+  (return
+   ;; code offset: 0xdb
+   (local.get $2)
+  )
+ )
+ ;; custom section ".debug_info", size 175
+ ;; custom section ".debug_ranges", size 32
+ ;; custom section ".debug_abbrev", size 117
+ ;; custom section ".debug_line", size 169
+ ;; custom section ".debug_str", size 235
+ ;; custom section "producers", size 180
+)
diff --git a/binaryen/test/passes/ignore_missing_func_dwarf.passes b/binaryen/test/passes/ignore_missing_func_dwarf.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/ignore_missing_func_dwarf.passes
@@ -0,0 +1,1 @@
+print_dwarfdump_roundtrip_dwarfdump_g
diff --git a/binaryen/test/passes/ignore_missing_func_dwarf.wasm b/binaryen/test/passes/ignore_missing_func_dwarf.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/ignore_missing_func_dwarf.wasm differ
diff --git a/binaryen/test/passes/inline-main.txt b/binaryen/test/passes/inline-main.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/inline-main.txt
@@ -0,0 +1,69 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (export "main" (func $main))
+ (func $__original_main (result i32)
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (block $__inlined_func$__original_main (result i32)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (export "main" (func $main))
+ (func $__original_main (result i32)
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (i32.const 0)
+ )
+)
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (export "main" (func $main))
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (i32.const 0)
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (export "main" (func $main))
+ (func $__original_main (result i32)
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (drop
+   (call $__original_main)
+  )
+  (call $__original_main)
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (func $__original_main (result i32)
+  (i32.const 0)
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (import "env" "main" (func $main (param i32 i32) (result i32)))
+ (export "main" (func $main))
+ (func $__original_main (result i32)
+  (i32.const 0)
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (import "env" "original_main" (func $__original_main (result i32)))
+ (export "main" (func $main))
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+)
diff --git a/binaryen/test/passes/inline-main.wast b/binaryen/test/passes/inline-main.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/inline-main.wast
@@ -0,0 +1,53 @@
+(module
+ (export "main" (func $main))
+ (func $__original_main (result i32)
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+)
+(module
+ (export "main" (func $main))
+ (func $__original_main (result i32)
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (i32.const 0)
+ )
+)
+(module
+ (export "main" (func $main))
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (i32.const 0)
+ )
+)
+(module
+ (export "main" (func $main))
+ (func $__original_main (result i32)
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (drop (call $__original_main))
+  (call $__original_main)
+ )
+)
+(module
+ (func $__original_main (result i32)
+  (i32.const 0)
+ )
+)
+(module
+ (import "env" "main" (func $main (param i32 i32) (result i32)))
+ (export "main" (func $main))
+ (func $__original_main (result i32)
+  (i32.const 0)
+ )
+)
+(module
+ (import "env" "original_main" (func $__original_main (result i32)))
+ (export "main" (func $main))
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (call $__original_main)
+ )
+)
diff --git a/binaryen/test/passes/inlined_to_start_dwarf.bin.txt b/binaryen/test/passes/inlined_to_start_dwarf.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/inlined_to_start_dwarf.bin.txt
@@ -0,0 +1,505 @@
+DWARF debug info
+================
+
+Contains section .debug_info (321 bytes)
+Contains section .debug_loc (104 bytes)
+Contains section .debug_ranges (32 bytes)
+Contains section .debug_abbrev (206 bytes)
+Contains section .debug_line (151 bytes)
+Contains section .debug_str (217 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_ranges	DW_FORM_sec_offset
+
+[2] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[3] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[4] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_abstract_origin	DW_FORM_ref4
+
+[5] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+	DW_AT_inline	DW_FORM_data1
+
+[6] DW_TAG_formal_parameter	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[7] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[8] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+[9] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_linkage_name	DW_FORM_strp
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[10] DW_TAG_variable	DW_CHILDREN_no
+	DW_AT_location	DW_FORM_sec_offset
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+
+[11] DW_TAG_inlined_subroutine	DW_CHILDREN_yes
+	DW_AT_abstract_origin	DW_FORM_ref4
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_call_file	DW_FORM_data1
+	DW_AT_call_line	DW_FORM_data1
+	DW_AT_call_column	DW_FORM_data1
+
+[12] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[13] DW_TAG_GNU_call_site	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+
+[14] DW_TAG_pointer_type	DW_CHILDREN_no
+	DW_AT_type	DW_FORM_ref4
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x0000013d version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x00000141)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 12.0.0 (https://github.com/llvm/llvm-project.git 132f29ce0611754e0ffb2b534c34b2ffe27b40a8)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus_14)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000069] = "a.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x0000006f] = "/home/azakai/Dev/emscripten")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+              DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
+                 [0x00000000, 0x00000007)
+                 [0x00000005, 0x00000012)
+                 [0x00000013, 0x0000001b))
+
+0x00000026:   DW_TAG_subprogram [2] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000000)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x3 +0, <decoding error> 00 00 9f)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x004a => {0x0000004a} "_Z6squarei")
+
+0x0000003b:     DW_TAG_formal_parameter [3]  
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x005a => {0x0000005a} "x")
+
+0x00000040:     DW_TAG_variable [4]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x00000000: 
+                     [0xffffffff,  0x00000006): 
+                     [0x00000001,  0x00000001): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value)
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x0065 => {0x00000065} "result")
+
+0x00000049:     NULL
+
+0x0000004a:   DW_TAG_subprogram [5] *
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x0000008b] = "_Z6squarei")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000096] = "square")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/azakai/Dev/emscripten/a.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(1)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0071 => {0x00000071} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+                DW_AT_inline [DW_FORM_data1]	(DW_INL_inlined)
+
+0x0000005a:     DW_TAG_formal_parameter [6]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000a1] = "x")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/azakai/Dev/emscripten/a.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(1)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0071 => {0x00000071} "int")
+
+0x00000065:     DW_TAG_variable [7]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000a3] = "result")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/azakai/Dev/emscripten/a.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(2)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0071 => {0x00000071} "int")
+
+0x00000070:     NULL
+
+0x00000071:   DW_TAG_base_type [8]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000009d] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x00000078:   DW_TAG_subprogram [9] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000005)
+                DW_AT_high_pc [DW_FORM_data4]	(0x0000000d)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x3 +0, <decoding error> 00 00 9f)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_linkage_name [DW_FORM_strp]	( .debug_str[0x000000aa] = "_Z7dsquareii")
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000b7] = "dsquare")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/azakai/Dev/emscripten/a.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(6)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0071 => {0x00000071} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000097:     DW_TAG_formal_parameter [6]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000a1] = "x")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/azakai/Dev/emscripten/a.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(6)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0071 => {0x00000071} "int")
+
+0x000000a2:     DW_TAG_formal_parameter [6]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c4] = "y")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/azakai/Dev/emscripten/a.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(6)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0071 => {0x00000071} "int")
+
+0x000000ad:     DW_TAG_variable [10]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000001e: 
+                     [0xffffffff,  0x00000010): 
+                     [0x00000000,  0x00000001): DW_OP_WASM_location 0x2 +1, DW_OP_stack_value
+                     [0x00000001,  0x00000001): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c6] = "dsq")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/azakai/Dev/emscripten/a.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(7)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0071 => {0x00000071} "int")
+
+0x000000bc:     DW_TAG_inlined_subroutine [11] *
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x004a => {0x0000004a} "_Z6squarei")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000005)
+                  DW_AT_high_pc [DW_FORM_data4]	(0x00000006)
+                  DW_AT_call_file [DW_FORM_data1]	("/home/azakai/Dev/emscripten/a.cpp")
+                  DW_AT_call_line [DW_FORM_data1]	(8)
+                  DW_AT_call_column [DW_FORM_data1]	(0x0a)
+
+0x000000cc:       DW_TAG_formal_parameter [3]  
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x005a => {0x0000005a} "x")
+
+0x000000d1:       NULL
+
+0x000000d2:     DW_TAG_inlined_subroutine [11] *
+                  DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x004a => {0x0000004a} "_Z6squarei")
+                  DW_AT_low_pc [DW_FORM_addr]	(0x000000000000000b)
+                  DW_AT_high_pc [DW_FORM_data4]	(0x00000005)
+                  DW_AT_call_file [DW_FORM_data1]	("/home/azakai/Dev/emscripten/a.cpp")
+                  DW_AT_call_line [DW_FORM_data1]	(7)
+                  DW_AT_call_column [DW_FORM_data1]	(0x0d)
+
+0x000000e2:       DW_TAG_formal_parameter [3]  
+                    DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x005a => {0x0000005a} "x")
+
+0x000000e7:       NULL
+
+0x000000e8:     NULL
+
+0x000000e9:   DW_TAG_subprogram [12] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000013)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000008)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x3 +0, <decoding error> 00 00 9f)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000bf] = "main")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/azakai/Dev/emscripten/a.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(12)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0071 => {0x00000071} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000104:     DW_TAG_formal_parameter [6]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ca] = "argc")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/azakai/Dev/emscripten/a.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(12)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0071 => {0x00000071} "int")
+
+0x0000010f:     DW_TAG_formal_parameter [6]  
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000cf] = "argv")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/azakai/Dev/emscripten/a.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(12)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x012f => {0x0000012f} "char**")
+
+0x0000011a:     DW_TAG_variable [10]  
+                  DW_AT_location [DW_FORM_sec_offset]	(0x0000004a: 
+                     [0xffffffff,  0x00000000): 
+                     [0x00000001,  0x00000001): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value)
+                  DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000a3] = "result")
+                  DW_AT_decl_file [DW_FORM_data1]	("/home/azakai/Dev/emscripten/a.cpp")
+                  DW_AT_decl_line [DW_FORM_data1]	(13)
+                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0071 => {0x00000071} "int")
+
+0x00000129:     DW_TAG_GNU_call_site [13]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+
+0x0000012e:     NULL
+
+0x0000012f:   DW_TAG_pointer_type [14]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0134 => {0x00000134} "char*")
+
+0x00000134:   DW_TAG_pointer_type [14]  
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0139 => {0x00000139} "char")
+
+0x00000139:   DW_TAG_base_type [8]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000d4] = "char")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed_char)
+                DW_AT_byte_size [DW_FORM_data1]	(0x01)
+
+0x00000140:   NULL
+
+.debug_loc contents:
+0x00000000: 
+            [0xffffffff,  0x00000006): 
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value
+
+0x0000001e: 
+            [0xffffffff,  0x00000010): 
+            [0x00000000,  0x00000001): DW_OP_WASM_location 0x2 +1, DW_OP_stack_value
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value
+
+0x0000004a: 
+            [0xffffffff,  0x00000000): 
+            [0x00000001,  0x00000001): DW_OP_WASM_location 0x2 +0, DW_OP_stack_value
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x00000093
+         version: 4
+ prologue_length: 0x0000001d
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "a.cpp"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000027: 00 DW_LNE_set_address (0x0000000000000005)
+0x0000002e: 03 DW_LNS_advance_line (6)
+0x00000030: 01 DW_LNS_copy
+            0x0000000000000005      6      0      1   0             0  is_stmt
+
+
+0x00000031: 00 DW_LNE_set_address (0x0000000000000006)
+0x00000038: 03 DW_LNS_advance_line (2)
+0x0000003a: 05 DW_LNS_set_column (18)
+0x0000003c: 0a DW_LNS_set_prologue_end
+0x0000003d: 01 DW_LNS_copy
+            0x0000000000000006      2     18      1   0             0  is_stmt prologue_end
+
+
+0x0000003e: 00 DW_LNE_set_address (0x000000000000000b)
+0x00000045: 06 DW_LNS_negate_stmt
+0x00000046: 01 DW_LNS_copy
+            0x000000000000000b      2     18      1   0             0 
+
+
+0x00000047: 00 DW_LNE_set_address (0x0000000000000010)
+0x0000004e: 03 DW_LNS_advance_line (8)
+0x00000050: 05 DW_LNS_set_column (7)
+0x00000052: 06 DW_LNS_negate_stmt
+0x00000053: 01 DW_LNS_copy
+            0x0000000000000010      8      7      1   0             0  is_stmt
+
+
+0x00000054: 00 DW_LNE_set_address (0x0000000000000011)
+0x0000005b: 03 DW_LNS_advance_line (9)
+0x0000005d: 05 DW_LNS_set_column (3)
+0x0000005f: 01 DW_LNS_copy
+            0x0000000000000011      9      3      1   0             0  is_stmt
+
+
+0x00000060: 00 DW_LNE_set_address (0x0000000000000012)
+0x00000067: 00 DW_LNE_end_sequence
+            0x0000000000000012      9      3      1   0             0  is_stmt end_sequence
+
+0x0000006a: 00 DW_LNE_set_address (0x0000000000000013)
+0x00000071: 03 DW_LNS_advance_line (12)
+0x00000073: 01 DW_LNS_copy
+            0x0000000000000013     12      0      1   0             0  is_stmt
+
+
+0x00000074: 00 DW_LNE_set_address (0x0000000000000018)
+0x0000007b: 03 DW_LNS_advance_line (13)
+0x0000007d: 05 DW_LNS_set_column (16)
+0x0000007f: 0a DW_LNS_set_prologue_end
+0x00000080: 01 DW_LNS_copy
+            0x0000000000000018     13     16      1   0             0  is_stmt prologue_end
+
+
+0x00000081: 00 DW_LNE_set_address (0x000000000000001a)
+0x00000088: 03 DW_LNS_advance_line (14)
+0x0000008a: 05 DW_LNS_set_column (3)
+0x0000008c: 01 DW_LNS_copy
+            0x000000000000001a     14      3      1   0             0  is_stmt
+
+
+0x0000008d: 00 DW_LNE_set_address (0x000000000000001b)
+0x00000094: 00 DW_LNE_end_sequence
+            0x000000000000001b     14      3      1   0             0  is_stmt end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 12.0.0 (https://github.com/llvm/llvm-project.git 132f29ce0611754e0ffb2b534c34b2ffe27b40a8)"
+0x00000069: "a.cpp"
+0x0000006f: "/home/azakai/Dev/emscripten"
+0x0000008b: "_Z6squarei"
+0x00000096: "square"
+0x0000009d: "int"
+0x000000a1: "x"
+0x000000a3: "result"
+0x000000aa: "_Z7dsquareii"
+0x000000b7: "dsquare"
+0x000000bf: "main"
+0x000000c4: "y"
+0x000000c6: "dsq"
+0x000000ca: "argc"
+0x000000cf: "argv"
+0x000000d4: "char"
+
+.debug_ranges contents:
+00000000 00000000 00000007
+00000000 00000005 00000012
+00000000 00000013 0000001b
+00000000 <End of list>
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "memory" (memory $mimport$0 256 256))
+ (data (i32.const 1024) "\00\00\00\00")
+ (table $0 1 1 funcref)
+ (global $global$0 (mut i32) (i32.const 5243920))
+ (global $global$1 i32 (i32.const 1028))
+ (export "__indirect_function_table" (table $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__errno_location" (func $__errno_location))
+ (export "stackSave" (func $stackSave))
+ (export "stackRestore" (func $stackRestore))
+ (export "stackAlloc" (func $stackAlloc))
+ (export "__data_end" (global $global$1))
+ (func $__wasm_call_ctors
+ )
+ (func $dsquare\28int\2c\20int\29 (param $0 i32) (param $1 i32) (result i32)
+  ;; code offset: 0x10
+  (i32.add
+   ;; code offset: 0xa
+   (i32.mul
+    ;; code offset: 0x6
+    (local.get $1)
+    ;; code offset: 0x8
+    (local.get $1)
+   )
+   ;; code offset: 0xf
+   (i32.mul
+    ;; code offset: 0xb
+    (local.get $0)
+    ;; code offset: 0xd
+    (local.get $0)
+   )
+  )
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  ;; code offset: 0x18
+  (call $dsquare\28int\2c\20int\29
+   ;; code offset: 0x14
+   (i32.const 6)
+   ;; code offset: 0x16
+   (i32.const 8)
+  )
+ )
+ (func $stackSave (result i32)
+  ;; code offset: 0x1d
+  (global.get $global$0)
+ )
+ (func $stackRestore (param $0 i32)
+  ;; code offset: 0x24
+  (global.set $global$0
+   ;; code offset: 0x22
+   (local.get $0)
+  )
+ )
+ (func $stackAlloc (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  ;; code offset: 0x37
+  (global.set $global$0
+   ;; code offset: 0x35
+   (local.tee $1
+    ;; code offset: 0x34
+    (i32.and
+     ;; code offset: 0x31
+     (i32.sub
+      ;; code offset: 0x2d
+      (global.get $global$0)
+      ;; code offset: 0x2f
+      (local.get $0)
+     )
+     ;; code offset: 0x32
+     (i32.const -16)
+    )
+   )
+  )
+  ;; code offset: 0x39
+  (local.get $1)
+ )
+ (func $__errno_location (result i32)
+  ;; code offset: 0x3e
+  (i32.const 1024)
+ )
+ ;; custom section ".debug_info", size 321
+ ;; custom section ".debug_loc", size 104
+ ;; custom section ".debug_ranges", size 32
+ ;; custom section ".debug_abbrev", size 206
+ ;; custom section ".debug_line", size 151
+ ;; custom section ".debug_str", size 217
+)
diff --git a/binaryen/test/passes/inlined_to_start_dwarf.passes b/binaryen/test/passes/inlined_to_start_dwarf.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/inlined_to_start_dwarf.passes
@@ -0,0 +1,1 @@
+g_roundtrip_dwarfdump
diff --git a/binaryen/test/passes/inlined_to_start_dwarf.wasm b/binaryen/test/passes/inlined_to_start_dwarf.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/inlined_to_start_dwarf.wasm differ
diff --git a/binaryen/test/passes/inlining-optimizing_enable-threads.txt b/binaryen/test/passes/inlining-optimizing_enable-threads.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/inlining-optimizing_enable-threads.txt
@@ -0,0 +1,95 @@
+(module
+ (type $none_=>_none (func))
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $tabled)
+ (export "user" (func $user))
+ (export "exported" (func $exported))
+ (export "exported_small" (func $exported_small))
+ (func $user
+  (call $exported)
+  (call $tabled)
+  (call $multi)
+  (call $multi)
+ )
+ (func $exported
+  (nop)
+  (nop)
+ )
+ (func $exported_small
+  (nop)
+ )
+ (func $recursive
+  (call $recursive)
+ )
+ (func $tabled
+  (nop)
+  (nop)
+ )
+ (func $cycle1
+  (call $cycle1)
+ )
+ (func $multi
+  (nop)
+  (nop)
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (func $main (result i32)
+  (unreachable)
+ )
+)
+(module
+ (type $none_=>_i64 (func (result i64)))
+ (memory $0 (shared 1 1))
+ (func $1 (result i64)
+  (i32.atomic.store16
+   (i32.const 0)
+   (i32.const 0)
+  )
+  (i64.const 0)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (func $main
+  (call $one)
+  (call $one)
+ )
+ (func $one
+  (call $one)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (func $main
+  (call $two)
+  (call $two)
+ )
+ (func $two
+  (call $two)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 17)
+ (table $0 89 89 funcref)
+ (start $1)
+ (func $1
+  (i32.store
+   (i32.const 4)
+   (i32.const 0)
+  )
+  (i32.store
+   (i32.const 56)
+   (i32.const 0)
+  )
+  (i64.store
+   (i32.const 49)
+   (i64.load
+    (i32.const 24)
+   )
+  )
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/passes/inlining-optimizing_enable-threads.wast b/binaryen/test/passes/inlining-optimizing_enable-threads.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/inlining-optimizing_enable-threads.wast
@@ -0,0 +1,180 @@
+(module
+  (table 1 1 funcref)
+  (elem (i32.const 0) $tabled)
+  (func $user (export "user")
+    (local $x i32)
+    (local $y f64)
+    (call $exported)
+    (call $exported_small)
+    (call $tabled)
+    (call $tabled_small)
+    (call $multi)
+    (call $multi)
+    (call $multi_small)
+    (call $multi_small)
+    (call $ok)
+    (drop (call $int))
+    (drop (call $double))
+    (local.set $x (call $int2))
+    (local.set $y (call $double2))
+    (call $with-local)
+    (call $with-local2)
+    (drop (call $return))
+    (call $multipass)
+    (call $param (f32.const 12.34) (i64.const 890005350012))
+  )
+  (func $exported (export "exported")
+    (nop)
+    (nop)
+  )
+  (func $exported_small (export "exported_small")
+    (nop)
+  )
+  (func $recursive
+    (call $recursive)
+  )
+  (func $tabled
+    (nop)
+    (nop)
+  )
+  (func $tabled_small
+    (nop)
+  )
+  (func $cycle1
+    (call $cycle2)
+  )
+  (func $cycle2
+    (call $cycle1)
+  )
+  (func $multi
+    (nop)
+    (nop)
+  )
+  (func $multi_small
+    (nop)
+  )
+  (func $ok
+    (drop (i32.const 1))
+  )
+  (func $int (result i32)
+    (i32.const 2)
+  )
+  (func $double (result f64)
+    (f64.const 3.14159)
+  )
+  (func $int2 (result i32)
+    (i32.const 112)
+  )
+  (func $double2 (result f64)
+    (f64.const 113.14159)
+  )
+  (func $with-local
+    (local $x f32)
+    (local.set $x (f32.const 2.141828))
+  )
+  (func $with-local2
+    (local $y i64)
+    (local.set $y (i64.const 4))
+  )
+  (func $return (result i32)
+    (return (i32.const 5))
+  )
+  (func $multipass
+    (call $multipass2)
+  )
+  (func $multipass2
+    (drop (i32.const 6))
+  )
+  (func $param (param $x f32) (param $y i64)
+    (local $z f32)
+    (drop (local.get $x))
+    (drop (local.get $y))
+    (drop (local.get $z))
+  )
+)
+(module
+ (func $main (result i32)
+  (call $func_51)
+  (i32.const 0)
+ )
+ (func $func_51
+  (unreachable) ;; void function but having unreachable body, when inlined, type must be fixed
+ )
+)
+(module
+ (memory $0 (shared 1 1))
+ (func $0 (result i32)
+  (i32.atomic.store16
+   (i32.const 0)
+   (i32.const 0)
+  )
+  (i32.const 1)
+ )
+ (func $1 (result i64)
+  (drop
+   (call $0)
+  )
+  (i64.const 0)
+ )
+)
+;; potential infinite recursion
+(module
+ (func $main
+  (call $one)
+  (call $one)
+ )
+ (func $one
+  (call $one)
+ )
+)
+;; potential infinite cycling recursion
+(module
+ (func $main
+  (call $one)
+  (call $one)
+ )
+ (func $one
+  (call $two)
+ )
+ (func $two
+  (call $one)
+ )
+)
+;; make sure to dce, as we may be combining unreachable code with others
+(module
+ (type $0 (func))
+ (type $1 (func (param i32 i32) (result i32)))
+ (table 89 89 funcref)
+ (memory $0 17)
+ (start $1)
+ (func $0 (; 0 ;) (type $1) (param $0 i32) (param $1 i32) (result i32)
+  (i32.store
+   (i32.const 4)
+   (local.tee $0
+    (i32.const 0)
+   )
+  )
+  (i32.store
+   (i32.add
+    (local.get $0)
+    (i32.const 56)
+   )
+   (i32.const 0)
+  )
+  (i64.store
+   (i32.const 49)
+   (i64.load
+    (i32.const 24)
+   )
+  )
+  (unreachable)
+ )
+ (func $1 (; 1 ;) (type $0)
+  (drop
+   (call $0
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/inlining-optimizing_optimize-level=3.txt b/binaryen/test/passes/inlining-optimizing_optimize-level=3.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/inlining-optimizing_optimize-level=3.txt
@@ -0,0 +1,15437 @@
+(module
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32) (result i32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32 i32) (result i32)))
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (type $i32_i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32 i32)))
+ (type $f64_i32_=>_f64 (func (param f64 i32) (result f64)))
+ (import "env" "memory" (memory $0 256 256))
+ (data (i32.const 1024) "emcc_hello_world.asm.js")
+ (import "env" "table" (table $timport$0 18 18 funcref))
+ (elem (global.get $tableBase) $b0 $___stdio_close $b1 $b1 $___stdout_write $___stdio_seek $___stdio_write $b1 $b1 $b1 $b2 $b2 $b2 $b2 $b2 $_cleanup $b2 $b2)
+ (import "env" "STACKTOP" (global $STACKTOP$asm2wasm$import i32))
+ (import "env" "STACK_MAX" (global $STACK_MAX$asm2wasm$import i32))
+ (import "env" "tempDoublePtr" (global $tempDoublePtr$asm2wasm$import i32))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "abort" (func $abort))
+ (import "env" "nullFunc_ii" (func $nullFunc_ii (param i32)))
+ (import "env" "nullFunc_iiii" (func $nullFunc_iiii (param i32)))
+ (import "env" "nullFunc_vi" (func $nullFunc_vi (param i32)))
+ (import "env" "_pthread_cleanup_pop" (func $_pthread_cleanup_pop (param i32)))
+ (import "env" "___lock" (func $___lock (param i32)))
+ (import "env" "_pthread_self" (func $_pthread_self (result i32)))
+ (import "env" "_abort" (func $_abort))
+ (import "env" "___syscall6" (func $___syscall6 (param i32 i32) (result i32)))
+ (import "env" "_sbrk" (func $_sbrk (param i32) (result i32)))
+ (import "env" "_time" (func $_time (param i32) (result i32)))
+ (import "env" "_emscripten_memcpy_big" (func $_emscripten_memcpy_big (param i32 i32 i32) (result i32)))
+ (import "env" "___syscall54" (func $___syscall54 (param i32 i32) (result i32)))
+ (import "env" "___unlock" (func $___unlock (param i32)))
+ (import "env" "___syscall140" (func $___syscall140 (param i32 i32) (result i32)))
+ (import "env" "_pthread_cleanup_push" (func $_pthread_cleanup_push (param i32 i32)))
+ (import "env" "_sysconf" (func $_sysconf (param i32) (result i32)))
+ (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 $tempDoublePtr (mut i32) (global.get $tempDoublePtr$asm2wasm$import))
+ (global $__THREW__ (mut i32) (i32.const 0))
+ (global $threwValue (mut i32) (i32.const 0))
+ (global $tempRet0 (mut i32) (i32.const 0))
+ (export "_i64Subtract" (func $_i64Subtract))
+ (export "_free" (func $_free))
+ (export "_main" (func $_main))
+ (export "_i64Add" (func $_i64Add))
+ (export "_memset" (func $_memset))
+ (export "_malloc" (func $_malloc))
+ (export "_memcpy" (func $_memcpy))
+ (export "_bitshift64Lshr" (func $_bitshift64Lshr))
+ (export "_fflush" (func $_fflush))
+ (export "___errno_location" (func $___errno_location))
+ (export "_bitshift64Shl" (func $_bitshift64Shl))
+ (export "runPostSets" (func $runPostSets))
+ (export "stackAlloc" (func $stackAlloc))
+ (export "stackSave" (func $stackSave))
+ (export "stackRestore" (func $stackRestore))
+ (export "establishStackSpace" (func $establishStackSpace))
+ (export "setThrew" (func $setThrew))
+ (export "setTempRet0" (func $setTempRet0))
+ (export "getTempRet0" (func $getTempRet0))
+ (export "dynCall_ii" (func $dynCall_ii))
+ (export "dynCall_iiii" (func $dynCall_iiii))
+ (export "dynCall_vi" (func $dynCall_vi))
+ (export "___udivmoddi4" (func $___udivmoddi4))
+ (func $stackAlloc (param $0 i32) (result i32)
+  (local $1 i32)
+  (local.set $1
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (local.get $0)
+   )
+  )
+  (global.set $STACKTOP
+   (i32.and
+    (i32.add
+     (global.get $STACKTOP)
+     (i32.const 15)
+    )
+    (i32.const -16)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (local.get $1)
+ )
+ (func $stackSave (result i32)
+  (global.get $STACKTOP)
+ )
+ (func $stackRestore (param $0 i32)
+  (global.set $STACKTOP
+   (local.get $0)
+  )
+ )
+ (func $establishStackSpace (param $0 i32) (param $1 i32)
+  (global.set $STACKTOP
+   (local.get $0)
+  )
+  (global.set $STACK_MAX
+   (local.get $1)
+  )
+ )
+ (func $setThrew (param $0 i32) (param $1 i32)
+  (if
+   (i32.eqz
+    (global.get $__THREW__)
+   )
+   (block $block
+    (global.set $__THREW__
+     (local.get $0)
+    )
+    (global.set $threwValue
+     (local.get $1)
+    )
+   )
+  )
+ )
+ (func $setTempRet0 (param $0 i32)
+  (global.set $tempRet0
+   (local.get $0)
+  )
+ )
+ (func $getTempRet0 (result i32)
+  (global.get $tempRet0)
+ )
+ (func $_main (result i32)
+  (local $0 i32)
+  (local.set $0
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 16)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (drop
+   (call $_printf
+    (i32.const 672)
+    (local.get $0)
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $0)
+  )
+  (i32.const 0)
+ )
+ (func $_frexp (param $0 f64) (param $1 i32) (result f64)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (f64.store
+   (global.get $tempDoublePtr)
+   (local.get $0)
+  )
+  (block $switch
+   (block $switch-default
+    (block $switch-case0
+     (block $switch-case
+      (br_table $switch-case $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-case0 $switch-default
+       (local.tee $3
+        (i32.and
+         (local.tee $3
+          (call $_bitshift64Lshr
+           (local.tee $2
+            (i32.load
+             (global.get $tempDoublePtr)
+            )
+           )
+           (local.tee $4
+            (i32.load offset=4
+             (global.get $tempDoublePtr)
+            )
+           )
+           (i32.const 52)
+          )
+         )
+         (i32.const 2047)
+        )
+       )
+      )
+     )
+     (i32.store
+      (local.get $1)
+      (local.tee $2
+       (if (result i32)
+        (f64.ne
+         (local.get $0)
+         (f64.const 0)
+        )
+        (block $block (result i32)
+         (local.set $0
+          (call $_frexp
+           (f64.mul
+            (local.get $0)
+            (f64.const 18446744073709551615)
+           )
+           (local.get $1)
+          )
+         )
+         (i32.add
+          (i32.load
+           (local.get $1)
+          )
+          (i32.const -64)
+         )
+        )
+        (i32.const 0)
+       )
+      )
+     )
+     (br $switch)
+    )
+    (br $switch)
+   )
+   (i32.store
+    (local.get $1)
+    (i32.add
+     (local.get $3)
+     (i32.const -1022)
+    )
+   )
+   (i32.store
+    (global.get $tempDoublePtr)
+    (local.get $2)
+   )
+   (i32.store offset=4
+    (global.get $tempDoublePtr)
+    (i32.or
+     (i32.and
+      (local.get $4)
+      (i32.const -2146435073)
+     )
+     (i32.const 1071644672)
+    )
+   )
+   (local.set $0
+    (f64.load
+     (global.get $tempDoublePtr)
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $_strerror (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $1
+   (i32.const 0)
+  )
+  (block $__rjto$1
+   (block $__rjti$1
+    (block $__rjti$0
+     (loop $while-in
+      (br_if $__rjti$0
+       (i32.eq
+        (i32.load8_u offset=687
+         (local.get $1)
+        )
+        (local.get $0)
+       )
+      )
+      (br_if $while-in
+       (i32.ne
+        (local.tee $1
+         (i32.add
+          (local.get $1)
+          (i32.const 1)
+         )
+        )
+        (i32.const 87)
+       )
+      )
+      (local.set $1
+       (i32.const 87)
+      )
+      (br $__rjti$1)
+     )
+    )
+    (br_if $__rjti$1
+     (local.get $1)
+    )
+    (local.set $0
+     (i32.const 775)
+    )
+    (br $__rjto$1)
+   )
+   (local.set $0
+    (i32.const 775)
+   )
+   (loop $while-in1
+    (loop $while-in3
+     (local.set $2
+      (i32.add
+       (local.get $0)
+       (i32.const 1)
+      )
+     )
+     (if
+      (i32.load8_s
+       (local.get $0)
+      )
+      (block $block
+       (local.set $0
+        (local.get $2)
+       )
+       (br $while-in3)
+      )
+      (local.set $0
+       (local.get $2)
+      )
+     )
+    )
+    (br_if $while-in1
+     (local.tee $1
+      (i32.add
+       (local.get $1)
+       (i32.const -1)
+      )
+     )
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $___errno_location (result i32)
+  (if (result i32)
+   (i32.load
+    (i32.const 16)
+   )
+   (i32.load offset=60
+    (call $_pthread_self)
+   )
+   (i32.const 60)
+  )
+ )
+ (func $___stdio_close (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $1
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 16)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (i32.store
+   (local.tee $2
+    (local.get $1)
+   )
+   (i32.load offset=60
+    (local.get $0)
+   )
+  )
+  (local.set $0
+   (call $___syscall_ret
+    (call $___syscall6
+     (i32.const 6)
+     (local.get $2)
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $1)
+  )
+  (local.get $0)
+ )
+ (func $___stdout_write (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $4
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 80)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (local.set $3
+   (local.get $4)
+  )
+  (local.set $5
+   (i32.add
+    (local.get $4)
+    (i32.const 12)
+   )
+  )
+  (i32.store offset=36
+   (local.get $0)
+   (i32.const 4)
+  )
+  (if
+   (i32.eqz
+    (i32.and
+     (i32.load
+      (local.get $0)
+     )
+     (i32.const 64)
+    )
+   )
+   (block $block
+    (i32.store
+     (local.get $3)
+     (i32.load offset=60
+      (local.get $0)
+     )
+    )
+    (i32.store offset=4
+     (local.get $3)
+     (i32.const 21505)
+    )
+    (i32.store offset=8
+     (local.get $3)
+     (local.get $5)
+    )
+    (if
+     (call $___syscall54
+      (i32.const 54)
+      (local.get $3)
+     )
+     (i32.store8 offset=75
+      (local.get $0)
+      (i32.const -1)
+     )
+    )
+   )
+  )
+  (local.set $0
+   (call $___stdio_write
+    (local.get $0)
+    (local.get $1)
+    (local.get $2)
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $4)
+  )
+  (local.get $0)
+ )
+ (func $___stdio_seek (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local.set $4
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 32)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (i32.store
+   (local.tee $3
+    (local.get $4)
+   )
+   (i32.load offset=60
+    (local.get $0)
+   )
+  )
+  (i32.store offset=4
+   (local.get $3)
+   (i32.const 0)
+  )
+  (i32.store offset=8
+   (local.get $3)
+   (local.get $1)
+  )
+  (i32.store offset=12
+   (local.get $3)
+   (local.tee $0
+    (i32.add
+     (local.get $4)
+     (i32.const 20)
+    )
+   )
+  )
+  (i32.store offset=16
+   (local.get $3)
+   (local.get $2)
+  )
+  (local.set $0
+   (if (result i32)
+    (i32.lt_s
+     (call $___syscall_ret
+      (call $___syscall140
+       (i32.const 140)
+       (local.get $3)
+      )
+     )
+     (i32.const 0)
+    )
+    (block $block (result i32)
+     (i32.store
+      (local.get $0)
+      (i32.const -1)
+     )
+     (i32.const -1)
+    )
+    (i32.load
+     (local.get $0)
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $4)
+  )
+  (local.get $0)
+ )
+ (func $_fflush (param $0 i32) (result i32)
+  (local $1 i32)
+  (if
+   (local.get $0)
+   (local.set $0
+    (block $do-once (result i32)
+     (if
+      (i32.le_s
+       (i32.load offset=76
+        (local.get $0)
+       )
+       (i32.const -1)
+      )
+      (br $do-once
+       (call $___fflush_unlocked
+        (local.get $0)
+       )
+      )
+     )
+     (local.tee $0
+      (call $___fflush_unlocked
+       (local.get $0)
+      )
+     )
+    )
+   )
+   (block
+    (local.set $0
+     (if (result i32)
+      (i32.load
+       (i32.const 12)
+      )
+      (call $_fflush
+       (i32.load
+        (i32.const 12)
+       )
+      )
+      (i32.const 0)
+     )
+    )
+    (call $___lock
+     (i32.const 44)
+    )
+    (if
+     (local.tee $1
+      (i32.load
+       (i32.const 40)
+      )
+     )
+     (loop $while-in
+      (drop
+       (i32.load offset=76
+        (local.get $1)
+       )
+      )
+      (if
+       (i32.gt_u
+        (i32.load offset=20
+         (local.get $1)
+        )
+        (i32.load offset=28
+         (local.get $1)
+        )
+       )
+       (local.set $0
+        (i32.or
+         (call $___fflush_unlocked
+          (local.get $1)
+         )
+         (local.get $0)
+        )
+       )
+      )
+      (br_if $while-in
+       (local.tee $1
+        (i32.load offset=56
+         (local.get $1)
+        )
+       )
+      )
+     )
+    )
+    (call $___unlock
+     (i32.const 44)
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $_printf (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local.set $2
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 16)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (i32.store
+   (local.tee $3
+    (local.get $2)
+   )
+   (local.get $1)
+  )
+  (local.set $0
+   (call $_vfprintf
+    (i32.load
+     (i32.const 8)
+    )
+    (local.get $0)
+    (local.get $3)
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $2)
+  )
+  (local.get $0)
+ )
+ (func $___stdio_write (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local.set $8
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 48)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (local.set $9
+   (i32.add
+    (local.get $8)
+    (i32.const 16)
+   )
+  )
+  (local.set $10
+   (local.get $8)
+  )
+  (i32.store
+   (local.tee $4
+    (i32.add
+     (local.get $8)
+     (i32.const 32)
+    )
+   )
+   (local.tee $3
+    (i32.load
+     (local.tee $6
+      (i32.add
+       (local.get $0)
+       (i32.const 28)
+      )
+     )
+    )
+   )
+  )
+  (i32.store offset=4
+   (local.get $4)
+   (local.tee $3
+    (i32.sub
+     (i32.load
+      (local.tee $11
+       (i32.add
+        (local.get $0)
+        (i32.const 20)
+       )
+      )
+     )
+     (local.get $3)
+    )
+   )
+  )
+  (i32.store offset=8
+   (local.get $4)
+   (local.get $1)
+  )
+  (i32.store offset=12
+   (local.get $4)
+   (local.get $2)
+  )
+  (local.set $13
+   (i32.add
+    (local.get $0)
+    (i32.const 60)
+   )
+  )
+  (local.set $14
+   (i32.add
+    (local.get $0)
+    (i32.const 44)
+   )
+  )
+  (local.set $1
+   (local.get $4)
+  )
+  (local.set $4
+   (i32.const 2)
+  )
+  (local.set $12
+   (i32.add
+    (local.get $3)
+    (local.get $2)
+   )
+  )
+  (block $__rjto$1
+   (block $__rjti$1
+    (block $__rjti$0
+     (loop $while-in
+      (if
+       (i32.load
+        (i32.const 16)
+       )
+       (block $block
+        (call $_pthread_cleanup_push
+         (i32.const 5)
+         (local.get $0)
+        )
+        (i32.store
+         (local.get $10)
+         (i32.load
+          (local.get $13)
+         )
+        )
+        (i32.store offset=4
+         (local.get $10)
+         (local.get $1)
+        )
+        (i32.store offset=8
+         (local.get $10)
+         (local.get $4)
+        )
+        (local.set $3
+         (call $___syscall_ret
+          (call $___syscall146
+           (i32.const 146)
+           (local.get $10)
+          )
+         )
+        )
+        (call $_pthread_cleanup_pop
+         (i32.const 0)
+        )
+       )
+       (block $block14
+        (i32.store
+         (local.get $9)
+         (i32.load
+          (local.get $13)
+         )
+        )
+        (i32.store offset=4
+         (local.get $9)
+         (local.get $1)
+        )
+        (i32.store offset=8
+         (local.get $9)
+         (local.get $4)
+        )
+        (local.set $3
+         (call $___syscall_ret
+          (call $___syscall146
+           (i32.const 146)
+           (local.get $9)
+          )
+         )
+        )
+       )
+      )
+      (br_if $__rjti$0
+       (i32.eq
+        (local.get $12)
+        (local.get $3)
+       )
+      )
+      (br_if $__rjti$1
+       (i32.lt_s
+        (local.get $3)
+        (i32.const 0)
+       )
+      )
+      (local.set $5
+       (if (result i32)
+        (i32.gt_u
+         (local.get $3)
+         (local.tee $5
+          (i32.load offset=4
+           (local.get $1)
+          )
+         )
+        )
+        (block $block16 (result i32)
+         (i32.store
+          (local.get $6)
+          (local.tee $7
+           (i32.load
+            (local.get $14)
+           )
+          )
+         )
+         (i32.store
+          (local.get $11)
+          (local.get $7)
+         )
+         (local.set $7
+          (i32.load offset=12
+           (local.get $1)
+          )
+         )
+         (local.set $1
+          (i32.add
+           (local.get $1)
+           (i32.const 8)
+          )
+         )
+         (local.set $4
+          (i32.add
+           (local.get $4)
+           (i32.const -1)
+          )
+         )
+         (i32.sub
+          (local.get $3)
+          (local.get $5)
+         )
+        )
+        (block $block17 (result i32)
+         (if
+          (i32.eq
+           (local.get $4)
+           (i32.const 2)
+          )
+          (block $block19
+           (i32.store
+            (local.get $6)
+            (i32.add
+             (i32.load
+              (local.get $6)
+             )
+             (local.get $3)
+            )
+           )
+           (local.set $7
+            (local.get $5)
+           )
+           (local.set $4
+            (i32.const 2)
+           )
+          )
+          (local.set $7
+           (local.get $5)
+          )
+         )
+         (local.get $3)
+        )
+       )
+      )
+      (i32.store
+       (local.get $1)
+       (i32.add
+        (i32.load
+         (local.get $1)
+        )
+        (local.get $5)
+       )
+      )
+      (i32.store offset=4
+       (local.get $1)
+       (i32.sub
+        (local.get $7)
+        (local.get $5)
+       )
+      )
+      (local.set $12
+       (i32.sub
+        (local.get $12)
+        (local.get $3)
+       )
+      )
+      (br $while-in)
+     )
+    )
+    (i32.store offset=16
+     (local.get $0)
+     (i32.add
+      (local.tee $1
+       (i32.load
+        (local.get $14)
+       )
+      )
+      (i32.load offset=48
+       (local.get $0)
+      )
+     )
+    )
+    (i32.store
+     (local.get $6)
+     (local.get $1)
+    )
+    (i32.store
+     (local.get $11)
+     (local.get $1)
+    )
+    (br $__rjto$1)
+   )
+   (i32.store offset=16
+    (local.get $0)
+    (i32.const 0)
+   )
+   (i32.store
+    (local.get $6)
+    (i32.const 0)
+   )
+   (i32.store
+    (local.get $11)
+    (i32.const 0)
+   )
+   (i32.store
+    (local.get $0)
+    (i32.or
+     (i32.load
+      (local.get $0)
+     )
+     (i32.const 32)
+    )
+   )
+   (local.set $2
+    (if (result i32)
+     (i32.eq
+      (local.get $4)
+      (i32.const 2)
+     )
+     (i32.const 0)
+     (i32.sub
+      (local.get $2)
+      (i32.load offset=4
+       (local.get $1)
+      )
+     )
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $8)
+  )
+  (local.get $2)
+ )
+ (func $_vfprintf (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local.set $3
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 224)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (local.set $5
+   (i32.add
+    (local.get $3)
+    (i32.const 120)
+   )
+  )
+  (local.set $6
+   (i32.add
+    (local.get $3)
+    (i32.const 136)
+   )
+  )
+  (local.set $8
+   (i32.add
+    (local.tee $4
+     (local.tee $7
+      (i32.add
+       (local.get $3)
+       (i32.const 80)
+      )
+     )
+    )
+    (i32.const 40)
+   )
+  )
+  (loop $do-in
+   (i32.store
+    (local.get $4)
+    (i32.const 0)
+   )
+   (br_if $do-in
+    (i32.lt_s
+     (local.tee $4
+      (i32.add
+       (local.get $4)
+       (i32.const 4)
+      )
+     )
+     (local.get $8)
+    )
+   )
+  )
+  (i32.store
+   (local.get $5)
+   (i32.load
+    (local.get $2)
+   )
+  )
+  (local.set $0
+   (if (result i32)
+    (i32.lt_s
+     (call $_printf_core
+      (i32.const 0)
+      (local.get $1)
+      (local.get $5)
+      (local.get $3)
+      (local.get $7)
+     )
+     (i32.const 0)
+    )
+    (i32.const -1)
+    (block (result i32)
+     (drop
+      (i32.load offset=76
+       (local.get $0)
+      )
+     )
+     (local.set $4
+      (i32.load
+       (local.get $0)
+      )
+     )
+     (if
+      (i32.lt_s
+       (i32.load8_s offset=74
+        (local.get $0)
+       )
+       (i32.const 1)
+      )
+      (i32.store
+       (local.get $0)
+       (i32.and
+        (local.get $4)
+        (i32.const -33)
+       )
+      )
+     )
+     (if
+      (i32.load
+       (local.tee $9
+        (i32.add
+         (local.get $0)
+         (i32.const 48)
+        )
+       )
+      )
+      (local.set $1
+       (call $_printf_core
+        (local.get $0)
+        (local.get $1)
+        (local.get $5)
+        (local.get $3)
+        (local.get $7)
+       )
+      )
+      (block
+       (local.set $11
+        (i32.load
+         (local.tee $10
+          (i32.add
+           (local.get $0)
+           (i32.const 44)
+          )
+         )
+        )
+       )
+       (i32.store
+        (local.get $10)
+        (local.get $6)
+       )
+       (i32.store
+        (local.tee $8
+         (i32.add
+          (local.get $0)
+          (i32.const 28)
+         )
+        )
+        (local.get $6)
+       )
+       (i32.store
+        (local.tee $12
+         (i32.add
+          (local.get $0)
+          (i32.const 20)
+         )
+        )
+        (local.get $6)
+       )
+       (i32.store
+        (local.get $9)
+        (i32.const 80)
+       )
+       (i32.store
+        (local.tee $2
+         (i32.add
+          (local.get $0)
+          (i32.const 16)
+         )
+        )
+        (i32.add
+         (local.get $6)
+         (i32.const 80)
+        )
+       )
+       (local.set $1
+        (call $_printf_core
+         (local.get $0)
+         (local.get $1)
+         (local.get $5)
+         (local.get $3)
+         (local.get $7)
+        )
+       )
+       (if
+        (local.get $11)
+        (block
+         (drop
+          (call_indirect (type $i32_i32_i32_=>_i32)
+           (local.get $0)
+           (i32.const 0)
+           (i32.const 0)
+           (i32.add
+            (i32.and
+             (i32.load offset=36
+              (local.get $0)
+             )
+             (i32.const 7)
+            )
+            (i32.const 2)
+           )
+          )
+         )
+         (local.set $1
+          (select
+           (local.get $1)
+           (i32.const -1)
+           (i32.load
+            (local.get $12)
+           )
+          )
+         )
+         (i32.store
+          (local.get $10)
+          (local.get $11)
+         )
+         (i32.store
+          (local.get $9)
+          (i32.const 0)
+         )
+         (i32.store
+          (local.get $2)
+          (i32.const 0)
+         )
+         (i32.store
+          (local.get $8)
+          (i32.const 0)
+         )
+         (i32.store
+          (local.get $12)
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (i32.store
+      (local.get $0)
+      (i32.or
+       (local.tee $0
+        (i32.load
+         (local.get $0)
+        )
+       )
+       (i32.and
+        (local.get $4)
+        (i32.const 32)
+       )
+      )
+     )
+     (select
+      (i32.const -1)
+      (local.get $1)
+      (i32.and
+       (local.get $0)
+       (i32.const 32)
+      )
+     )
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $3)
+  )
+  (local.get $0)
+ )
+ (func $___fwritex (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block $label$break$L5
+   (block $__rjti$0
+    (br_if $__rjti$0
+     (local.tee $3
+      (i32.load
+       (local.tee $4
+        (i32.add
+         (local.get $2)
+         (i32.const 16)
+        )
+       )
+      )
+     )
+    )
+    (if
+     (call $___towrite
+      (local.get $2)
+     )
+     (local.set $3
+      (i32.const 0)
+     )
+     (block $block
+      (local.set $3
+       (i32.load
+        (local.get $4)
+       )
+      )
+      (br $__rjti$0)
+     )
+    )
+    (br $label$break$L5)
+   )
+   (if
+    (i32.lt_u
+     (i32.sub
+      (local.get $3)
+      (local.tee $4
+       (i32.load
+        (local.tee $5
+         (i32.add
+          (local.get $2)
+          (i32.const 20)
+         )
+        )
+       )
+      )
+     )
+     (local.get $1)
+    )
+    (block $block30
+     (local.set $3
+      (call_indirect (type $i32_i32_i32_=>_i32)
+       (local.get $2)
+       (local.get $0)
+       (local.get $1)
+       (i32.add
+        (i32.and
+         (i32.load offset=36
+          (local.get $2)
+         )
+         (i32.const 7)
+        )
+        (i32.const 2)
+       )
+      )
+     )
+     (br $label$break$L5)
+    )
+   )
+   (local.set $2
+    (block $label$break$L10 (result i32)
+     (if (result i32)
+      (i32.gt_s
+       (i32.load8_s offset=75
+        (local.get $2)
+       )
+       (i32.const -1)
+      )
+      (block $block32 (result i32)
+       (local.set $3
+        (local.get $1)
+       )
+       (loop $while-in
+        (drop
+         (br_if $label$break$L10
+          (i32.const 0)
+          (i32.eqz
+           (local.get $3)
+          )
+         )
+        )
+        (if
+         (i32.ne
+          (i32.load8_s
+           (i32.add
+            (local.get $0)
+            (local.tee $6
+             (i32.add
+              (local.get $3)
+              (i32.const -1)
+             )
+            )
+           )
+          )
+          (i32.const 10)
+         )
+         (block $block34
+          (local.set $3
+           (local.get $6)
+          )
+          (br $while-in)
+         )
+        )
+       )
+       (br_if $label$break$L5
+        (i32.lt_u
+         (call_indirect (type $i32_i32_i32_=>_i32)
+          (local.get $2)
+          (local.get $0)
+          (local.get $3)
+          (i32.add
+           (i32.and
+            (i32.load offset=36
+             (local.get $2)
+            )
+            (i32.const 7)
+           )
+           (i32.const 2)
+          )
+         )
+         (local.get $3)
+        )
+       )
+       (local.set $4
+        (i32.load
+         (local.get $5)
+        )
+       )
+       (local.set $1
+        (i32.sub
+         (local.get $1)
+         (local.get $3)
+        )
+       )
+       (local.set $0
+        (i32.add
+         (local.get $0)
+         (local.get $3)
+        )
+       )
+       (local.get $3)
+      )
+      (i32.const 0)
+     )
+    )
+   )
+   (drop
+    (call $_memcpy
+     (local.get $4)
+     (local.get $0)
+     (local.get $1)
+    )
+   )
+   (i32.store
+    (local.get $5)
+    (i32.add
+     (i32.load
+      (local.get $5)
+     )
+     (local.get $1)
+    )
+   )
+   (local.set $3
+    (i32.add
+     (local.get $2)
+     (local.get $1)
+    )
+   )
+  )
+  (local.get $3)
+ )
+ (func $___towrite (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $1
+   (i32.load8_s
+    (local.tee $2
+     (i32.add
+      (local.get $0)
+      (i32.const 74)
+     )
+    )
+   )
+  )
+  (i32.store8
+   (local.get $2)
+   (i32.or
+    (i32.add
+     (local.get $1)
+     (i32.const 255)
+    )
+    (local.get $1)
+   )
+  )
+  (local.tee $0
+   (if (result i32)
+    (i32.and
+     (local.tee $1
+      (i32.load
+       (local.get $0)
+      )
+     )
+     (i32.const 8)
+    )
+    (block $block (result i32)
+     (i32.store
+      (local.get $0)
+      (i32.or
+       (local.get $1)
+       (i32.const 32)
+      )
+     )
+     (i32.const -1)
+    )
+    (block $block35 (result i32)
+     (i32.store offset=8
+      (local.get $0)
+      (i32.const 0)
+     )
+     (i32.store offset=4
+      (local.get $0)
+      (i32.const 0)
+     )
+     (i32.store offset=28
+      (local.get $0)
+      (local.tee $1
+       (i32.load offset=44
+        (local.get $0)
+       )
+      )
+     )
+     (i32.store offset=20
+      (local.get $0)
+      (local.get $1)
+     )
+     (i32.store offset=16
+      (local.get $0)
+      (i32.add
+       (local.get $1)
+       (i32.load offset=48
+        (local.get $0)
+       )
+      )
+     )
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $_wcrtomb (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (block $do-once (result i32)
+   (if (result i32)
+    (local.get $0)
+    (block $block (result i32)
+     (if
+      (i32.lt_u
+       (local.get $1)
+       (i32.const 128)
+      )
+      (block $block37
+       (i32.store8
+        (local.get $0)
+        (local.get $1)
+       )
+       (br $do-once
+        (i32.const 1)
+       )
+      )
+     )
+     (if
+      (i32.lt_u
+       (local.get $1)
+       (i32.const 2048)
+      )
+      (block $block39
+       (i32.store8
+        (local.get $0)
+        (i32.or
+         (i32.shr_u
+          (local.get $1)
+          (i32.const 6)
+         )
+         (i32.const 192)
+        )
+       )
+       (i32.store8 offset=1
+        (local.get $0)
+        (i32.or
+         (i32.and
+          (local.get $1)
+          (i32.const 63)
+         )
+         (i32.const 128)
+        )
+       )
+       (br $do-once
+        (i32.const 2)
+       )
+      )
+     )
+     (if
+      (i32.or
+       (i32.lt_u
+        (local.get $1)
+        (i32.const 55296)
+       )
+       (i32.eq
+        (i32.and
+         (local.get $1)
+         (i32.const -8192)
+        )
+        (i32.const 57344)
+       )
+      )
+      (block $block41
+       (i32.store8
+        (local.get $0)
+        (i32.or
+         (i32.shr_u
+          (local.get $1)
+          (i32.const 12)
+         )
+         (i32.const 224)
+        )
+       )
+       (i32.store8 offset=1
+        (local.get $0)
+        (i32.or
+         (i32.and
+          (i32.shr_u
+           (local.get $1)
+           (i32.const 6)
+          )
+          (i32.const 63)
+         )
+         (i32.const 128)
+        )
+       )
+       (i32.store8 offset=2
+        (local.get $0)
+        (i32.or
+         (i32.and
+          (local.get $1)
+          (i32.const 63)
+         )
+         (i32.const 128)
+        )
+       )
+       (br $do-once
+        (i32.const 3)
+       )
+      )
+     )
+     (if (result i32)
+      (i32.lt_u
+       (i32.add
+        (local.get $1)
+        (i32.const -65536)
+       )
+       (i32.const 1048576)
+      )
+      (block $block43 (result i32)
+       (i32.store8
+        (local.get $0)
+        (i32.or
+         (i32.shr_u
+          (local.get $1)
+          (i32.const 18)
+         )
+         (i32.const 240)
+        )
+       )
+       (i32.store8 offset=1
+        (local.get $0)
+        (i32.or
+         (i32.and
+          (i32.shr_u
+           (local.get $1)
+           (i32.const 12)
+          )
+          (i32.const 63)
+         )
+         (i32.const 128)
+        )
+       )
+       (i32.store8 offset=2
+        (local.get $0)
+        (i32.or
+         (i32.and
+          (i32.shr_u
+           (local.get $1)
+           (i32.const 6)
+          )
+          (i32.const 63)
+         )
+         (i32.const 128)
+        )
+       )
+       (i32.store8 offset=3
+        (local.get $0)
+        (i32.or
+         (i32.and
+          (local.get $1)
+          (i32.const 63)
+         )
+         (i32.const 128)
+        )
+       )
+       (i32.const 4)
+      )
+      (block $block44 (result i32)
+       (i32.store
+        (call $___errno_location)
+        (i32.const 84)
+       )
+       (i32.const -1)
+      )
+     )
+    )
+    (i32.const 1)
+   )
+  )
+ )
+ (func $_wctomb (param $0 i32) (param $1 i32) (result i32)
+  (if (result i32)
+   (local.get $0)
+   (call $_wcrtomb
+    (local.get $0)
+    (local.get $1)
+    (i32.const 0)
+   )
+   (i32.const 0)
+  )
+ )
+ (func $_memchr (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $5
+   (i32.and
+    (local.get $1)
+    (i32.const 255)
+   )
+  )
+  (block $label$break$L8
+   (block $__rjti$2
+    (if
+     (i32.and
+      (local.tee $4
+       (i32.ne
+        (local.get $2)
+        (i32.const 0)
+       )
+      )
+      (i32.ne
+       (i32.and
+        (local.get $0)
+        (i32.const 3)
+       )
+       (i32.const 0)
+      )
+     )
+     (block $block
+      (local.set $4
+       (i32.and
+        (local.get $1)
+        (i32.const 255)
+       )
+      )
+      (local.set $3
+       (local.get $2)
+      )
+      (local.set $2
+       (local.get $0)
+      )
+      (loop $while-in
+       (br_if $__rjti$2
+        (i32.eq
+         (i32.load8_u
+          (local.get $2)
+         )
+         (i32.and
+          (local.get $4)
+          (i32.const 255)
+         )
+        )
+       )
+       (br_if $while-in
+        (i32.and
+         (local.tee $0
+          (i32.ne
+           (local.tee $3
+            (i32.add
+             (local.get $3)
+             (i32.const -1)
+            )
+           )
+           (i32.const 0)
+          )
+         )
+         (i32.ne
+          (i32.and
+           (local.tee $2
+            (i32.add
+             (local.get $2)
+             (i32.const 1)
+            )
+           )
+           (i32.const 3)
+          )
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (block $block45
+      (local.set $3
+       (local.get $2)
+      )
+      (local.set $2
+       (local.get $0)
+      )
+      (local.set $0
+       (local.get $4)
+      )
+     )
+    )
+    (br_if $__rjti$2
+     (local.get $0)
+    )
+    (local.set $0
+     (i32.const 0)
+    )
+    (br $label$break$L8)
+   )
+   (local.set $0
+    (local.get $3)
+   )
+   (if
+    (i32.ne
+     (i32.load8_u
+      (local.get $2)
+     )
+     (local.tee $1
+      (i32.and
+       (local.get $1)
+       (i32.const 255)
+      )
+     )
+    )
+    (block $block47
+     (local.set $3
+      (i32.mul
+       (local.get $5)
+       (i32.const 16843009)
+      )
+     )
+     (block $__rjto$0
+      (block $__rjti$0
+       (br_if $__rjti$0
+        (i32.le_u
+         (local.get $0)
+         (i32.const 3)
+        )
+       )
+       (loop $while-in3
+        (if
+         (i32.eqz
+          (i32.and
+           (i32.xor
+            (i32.and
+             (local.tee $4
+              (i32.xor
+               (i32.load
+                (local.get $2)
+               )
+               (local.get $3)
+              )
+             )
+             (i32.const -2139062144)
+            )
+            (i32.const -2139062144)
+           )
+           (i32.add
+            (local.get $4)
+            (i32.const -16843009)
+           )
+          )
+         )
+         (block $block49
+          (local.set $2
+           (i32.add
+            (local.get $2)
+            (i32.const 4)
+           )
+          )
+          (br_if $while-in3
+           (i32.gt_u
+            (local.tee $0
+             (i32.add
+              (local.get $0)
+              (i32.const -4)
+             )
+            )
+            (i32.const 3)
+           )
+          )
+          (br $__rjti$0)
+         )
+        )
+       )
+       (br $__rjto$0)
+      )
+      (if
+       (i32.eqz
+        (local.get $0)
+       )
+       (block $block51
+        (local.set $0
+         (i32.const 0)
+        )
+        (br $label$break$L8)
+       )
+      )
+     )
+     (loop $while-in5
+      (br_if $label$break$L8
+       (i32.eq
+        (i32.load8_u
+         (local.get $2)
+        )
+        (i32.and
+         (local.get $1)
+         (i32.const 255)
+        )
+       )
+      )
+      (local.set $2
+       (i32.add
+        (local.get $2)
+        (i32.const 1)
+       )
+      )
+      (br_if $while-in5
+       (local.tee $0
+        (i32.add
+         (local.get $0)
+         (i32.const -1)
+        )
+       )
+      )
+      (local.set $0
+       (i32.const 0)
+      )
+     )
+    )
+   )
+  )
+  (select
+   (local.get $2)
+   (i32.const 0)
+   (local.get $0)
+  )
+ )
+ (func $___syscall_ret (param $0 i32) (result i32)
+  (if (result i32)
+   (i32.gt_u
+    (local.get $0)
+    (i32.const -4096)
+   )
+   (block $block (result i32)
+    (i32.store
+     (call $___errno_location)
+     (i32.sub
+      (i32.const 0)
+      (local.get $0)
+     )
+    )
+    (i32.const -1)
+   )
+   (local.get $0)
+  )
+ )
+ (func $___fflush_unlocked (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local.tee $0
+   (block $__rjto$0 (result i32)
+    (block $__rjti$0
+     (br_if $__rjti$0
+      (i32.le_u
+       (i32.load
+        (local.tee $1
+         (i32.add
+          (local.get $0)
+          (i32.const 20)
+         )
+        )
+       )
+       (i32.load
+        (local.tee $2
+         (i32.add
+          (local.get $0)
+          (i32.const 28)
+         )
+        )
+       )
+      )
+     )
+     (drop
+      (call_indirect (type $i32_i32_i32_=>_i32)
+       (local.get $0)
+       (i32.const 0)
+       (i32.const 0)
+       (i32.add
+        (i32.and
+         (i32.load offset=36
+          (local.get $0)
+         )
+         (i32.const 7)
+        )
+        (i32.const 2)
+       )
+      )
+     )
+     (br_if $__rjti$0
+      (i32.load
+       (local.get $1)
+      )
+     )
+     (br $__rjto$0
+      (i32.const -1)
+     )
+    )
+    (if
+     (i32.lt_u
+      (local.tee $4
+       (i32.load
+        (local.tee $3
+         (i32.add
+          (local.get $0)
+          (i32.const 4)
+         )
+        )
+       )
+      )
+      (local.tee $6
+       (i32.load
+        (local.tee $5
+         (i32.add
+          (local.get $0)
+          (i32.const 8)
+         )
+        )
+       )
+      )
+     )
+     (drop
+      (call_indirect (type $i32_i32_i32_=>_i32)
+       (local.get $0)
+       (i32.sub
+        (local.get $4)
+        (local.get $6)
+       )
+       (i32.const 1)
+       (i32.add
+        (i32.and
+         (i32.load offset=40
+          (local.get $0)
+         )
+         (i32.const 7)
+        )
+        (i32.const 2)
+       )
+      )
+     )
+    )
+    (i32.store offset=16
+     (local.get $0)
+     (i32.const 0)
+    )
+    (i32.store
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.store
+     (local.get $1)
+     (i32.const 0)
+    )
+    (i32.store
+     (local.get $5)
+     (i32.const 0)
+    )
+    (i32.store
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.const 0)
+   )
+  )
+ )
+ (func $_cleanup (param $0 i32)
+  (drop
+   (i32.load offset=68
+    (local.get $0)
+   )
+  )
+ )
+ (func $_printf_core (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (result i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 f64)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (local $19 i32)
+  (local $20 i32)
+  (local $21 i32)
+  (local $22 i32)
+  (local $23 i32)
+  (local $24 f64)
+  (local $25 i32)
+  (local $26 i32)
+  (local $27 i32)
+  (local $28 i32)
+  (local $29 i32)
+  (local $30 i32)
+  (local $31 i32)
+  (local $32 i32)
+  (local $33 i32)
+  (local $34 i32)
+  (local $35 i32)
+  (local $36 i32)
+  (local $37 i32)
+  (local $38 i32)
+  (local $39 i32)
+  (local $40 i32)
+  (local $41 i32)
+  (local $42 i32)
+  (local $43 i32)
+  (local $44 i32)
+  (local $45 i32)
+  (local $46 i32)
+  (local $47 i32)
+  (local $48 i32)
+  (local.set $13
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 624)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (local.set $21
+   (i32.add
+    (local.get $13)
+    (i32.const 16)
+   )
+  )
+  (local.set $33
+   (i32.add
+    (local.get $13)
+    (i32.const 528)
+   )
+  )
+  (local.set $28
+   (i32.ne
+    (local.get $0)
+    (i32.const 0)
+   )
+  )
+  (local.set $37
+   (local.tee $25
+    (i32.add
+     (local.tee $5
+      (i32.add
+       (local.get $13)
+       (i32.const 536)
+      )
+     )
+     (i32.const 40)
+    )
+   )
+  )
+  (local.set $38
+   (i32.add
+    (local.get $5)
+    (i32.const 39)
+   )
+  )
+  (local.set $42
+   (i32.add
+    (local.tee $39
+     (i32.add
+      (local.get $13)
+      (i32.const 8)
+     )
+    )
+    (i32.const 4)
+   )
+  )
+  (local.set $22
+   (i32.add
+    (local.tee $5
+     (i32.add
+      (local.get $13)
+      (i32.const 576)
+     )
+    )
+    (i32.const 12)
+   )
+  )
+  (local.set $40
+   (i32.add
+    (local.get $5)
+    (i32.const 11)
+   )
+  )
+  (local.set $43
+   (i32.sub
+    (local.get $22)
+    (local.tee $34
+     (local.tee $23
+      (i32.add
+       (local.get $13)
+       (i32.const 588)
+      )
+     )
+    )
+   )
+  )
+  (local.set $44
+   (i32.sub
+    (i32.const -2)
+    (local.get $34)
+   )
+  )
+  (local.set $45
+   (i32.add
+    (local.get $22)
+    (i32.const 2)
+   )
+  )
+  (local.set $47
+   (i32.add
+    (local.tee $46
+     (i32.add
+      (local.get $13)
+      (i32.const 24)
+     )
+    )
+    (i32.const 288)
+   )
+  )
+  (local.set $41
+   (local.tee $29
+    (i32.add
+     (local.get $23)
+     (i32.const 9)
+    )
+   )
+  )
+  (local.set $32
+   (i32.add
+    (local.get $23)
+    (i32.const 8)
+   )
+  )
+  (local.set $5
+   (local.get $1)
+  )
+  (local.set $1
+   (i32.const 0)
+  )
+  (block $label$break$L343
+   (block $__rjti$9
+    (loop $label$continue$L1
+     (block $label$break$L1
+      (if
+       (i32.gt_s
+        (local.get $18)
+        (i32.const -1)
+       )
+       (local.set $18
+        (if (result i32)
+         (i32.gt_s
+          (local.get $10)
+          (i32.sub
+           (i32.const 2147483647)
+           (local.get $18)
+          )
+         )
+         (block (result i32)
+          (i32.store
+           (call $___errno_location)
+           (i32.const 75)
+          )
+          (i32.const -1)
+         )
+         (i32.add
+          (local.get $10)
+          (local.get $18)
+         )
+        )
+       )
+      )
+      (br_if $__rjti$9
+       (i32.eqz
+        (local.tee $7
+         (i32.load8_s
+          (local.get $5)
+         )
+        )
+       )
+      )
+      (local.set $10
+       (local.get $5)
+      )
+      (block $label$break$L12
+       (block $__rjti$1
+        (loop $label$continue$L9
+         (block $label$break$L9
+          (block $switch-default
+           (block $switch-case0
+            (block $switch-case
+             (br_table $switch-case0 $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-case $switch-default
+              (i32.shr_s
+               (i32.shl
+                (local.get $7)
+                (i32.const 24)
+               )
+               (i32.const 24)
+              )
+             )
+            )
+            (local.set $6
+             (local.get $10)
+            )
+            (br $__rjti$1)
+           )
+           (local.set $6
+            (local.get $10)
+           )
+           (br $label$break$L9)
+          )
+          (local.set $7
+           (i32.load8_s
+            (local.tee $10
+             (i32.add
+              (local.get $10)
+              (i32.const 1)
+             )
+            )
+           )
+          )
+          (br $label$continue$L9)
+         )
+        )
+        (br $label$break$L12)
+       )
+       (loop $while-in
+        (br_if $label$break$L12
+         (i32.ne
+          (i32.load8_s offset=1
+           (local.get $6)
+          )
+          (i32.const 37)
+         )
+        )
+        (local.set $10
+         (i32.add
+          (local.get $10)
+          (i32.const 1)
+         )
+        )
+        (br_if $while-in
+         (i32.eq
+          (i32.load8_s
+           (local.tee $6
+            (i32.add
+             (local.get $6)
+             (i32.const 2)
+            )
+           )
+          )
+          (i32.const 37)
+         )
+        )
+       )
+      )
+      (local.set $7
+       (i32.sub
+        (local.get $10)
+        (local.get $5)
+       )
+      )
+      (if
+       (local.get $28)
+       (if
+        (i32.eqz
+         (i32.and
+          (i32.load
+           (local.get $0)
+          )
+          (i32.const 32)
+         )
+        )
+        (drop
+         (call $___fwritex
+          (local.get $5)
+          (local.get $7)
+          (local.get $0)
+         )
+        )
+       )
+      )
+      (if
+       (i32.ne
+        (local.get $5)
+        (local.get $10)
+       )
+       (block
+        (local.set $5
+         (local.get $6)
+        )
+        (local.set $10
+         (local.get $7)
+        )
+        (br $label$continue$L1)
+       )
+      )
+      (local.set $8
+       (if (result i32)
+        (i32.lt_u
+         (local.tee $8
+          (i32.add
+           (local.tee $12
+            (i32.load8_s
+             (local.tee $10
+              (i32.add
+               (local.get $6)
+               (i32.const 1)
+              )
+             )
+            )
+           )
+           (i32.const -48)
+          )
+         )
+         (i32.const 10)
+        )
+        (block (result i32)
+         (local.set $6
+          (i32.load8_s
+           (local.tee $10
+            (select
+             (i32.add
+              (local.get $6)
+              (i32.const 3)
+             )
+             (local.get $10)
+             (local.tee $12
+              (i32.eq
+               (i32.load8_s offset=2
+                (local.get $6)
+               )
+               (i32.const 36)
+              )
+             )
+            )
+           )
+          )
+         )
+         (local.set $19
+          (select
+           (local.get $8)
+           (i32.const -1)
+           (local.get $12)
+          )
+         )
+         (select
+          (i32.const 1)
+          (local.get $1)
+          (local.get $12)
+         )
+        )
+        (block (result i32)
+         (local.set $6
+          (local.get $12)
+         )
+         (local.set $19
+          (i32.const -1)
+         )
+         (local.get $1)
+        )
+       )
+      )
+      (local.set $1
+       (if (result i32)
+        (i32.eq
+         (i32.and
+          (local.tee $12
+           (i32.shr_s
+            (i32.shl
+             (local.get $6)
+             (i32.const 24)
+            )
+            (i32.const 24)
+           )
+          )
+          (i32.const -32)
+         )
+         (i32.const 32)
+        )
+        (block $label$break$L25 (result i32)
+         (local.set $1
+          (local.get $6)
+         )
+         (local.set $6
+          (local.get $12)
+         )
+         (local.set $12
+          (i32.const 0)
+         )
+         (loop $while-in4 (result i32)
+          (if
+           (i32.eqz
+            (i32.and
+             (i32.shl
+              (i32.const 1)
+              (i32.add
+               (local.get $6)
+               (i32.const -32)
+              )
+             )
+             (i32.const 75913)
+            )
+           )
+           (block
+            (local.set $6
+             (local.get $1)
+            )
+            (br $label$break$L25
+             (local.get $12)
+            )
+           )
+          )
+          (local.set $12
+           (i32.or
+            (i32.shl
+             (i32.const 1)
+             (i32.add
+              (i32.shr_s
+               (i32.shl
+                (local.get $1)
+                (i32.const 24)
+               )
+               (i32.const 24)
+              )
+              (i32.const -32)
+             )
+            )
+            (local.get $12)
+           )
+          )
+          (br_if $while-in4
+           (i32.eq
+            (i32.and
+             (local.tee $6
+              (local.tee $1
+               (i32.load8_s
+                (local.tee $10
+                 (i32.add
+                  (local.get $10)
+                  (i32.const 1)
+                 )
+                )
+               )
+              )
+             )
+             (i32.const -32)
+            )
+            (i32.const 32)
+           )
+          )
+          (local.set $6
+           (local.get $1)
+          )
+          (local.get $12)
+         )
+        )
+        (i32.const 0)
+       )
+      )
+      (local.set $1
+       (if (result i32)
+        (i32.eq
+         (i32.and
+          (local.get $6)
+          (i32.const 255)
+         )
+         (i32.const 42)
+        )
+        (block $do-once5 (result i32)
+         (local.set $10
+          (block $__rjto$0 (result i32)
+           (block $__rjti$0
+            (br_if $__rjti$0
+             (i32.ge_u
+              (local.tee $12
+               (i32.add
+                (i32.load8_s
+                 (local.tee $6
+                  (i32.add
+                   (local.get $10)
+                   (i32.const 1)
+                  )
+                 )
+                )
+                (i32.const -48)
+               )
+              )
+              (i32.const 10)
+             )
+            )
+            (br_if $__rjti$0
+             (i32.ne
+              (i32.load8_s offset=2
+               (local.get $10)
+              )
+              (i32.const 36)
+             )
+            )
+            (i32.store
+             (i32.add
+              (local.get $4)
+              (i32.shl
+               (local.get $12)
+               (i32.const 2)
+              )
+             )
+             (i32.const 10)
+            )
+            (drop
+             (i32.load offset=4
+              (local.tee $6
+               (i32.add
+                (local.get $3)
+                (i32.shl
+                 (i32.add
+                  (i32.load8_s
+                   (local.get $6)
+                  )
+                  (i32.const -48)
+                 )
+                 (i32.const 3)
+                )
+               )
+              )
+             )
+            )
+            (local.set $8
+             (i32.const 1)
+            )
+            (local.set $17
+             (i32.load
+              (local.get $6)
+             )
+            )
+            (br $__rjto$0
+             (i32.add
+              (local.get $10)
+              (i32.const 3)
+             )
+            )
+           )
+           (if
+            (local.get $8)
+            (block
+             (local.set $18
+              (i32.const -1)
+             )
+             (br $label$break$L1)
+            )
+           )
+           (if
+            (i32.eqz
+             (local.get $28)
+            )
+            (block
+             (local.set $12
+              (local.get $1)
+             )
+             (local.set $10
+              (local.get $6)
+             )
+             (local.set $17
+              (i32.const 0)
+             )
+             (br $do-once5
+              (i32.const 0)
+             )
+            )
+           )
+           (local.set $17
+            (i32.load
+             (local.tee $10
+              (i32.and
+               (i32.add
+                (i32.load
+                 (local.get $2)
+                )
+                (i32.const 3)
+               )
+               (i32.const -4)
+              )
+             )
+            )
+           )
+           (i32.store
+            (local.get $2)
+            (i32.add
+             (local.get $10)
+             (i32.const 4)
+            )
+           )
+           (local.set $8
+            (i32.const 0)
+           )
+           (local.get $6)
+          )
+         )
+         (local.set $12
+          (if (result i32)
+           (i32.lt_s
+            (local.get $17)
+            (i32.const 0)
+           )
+           (block (result i32)
+            (local.set $17
+             (i32.sub
+              (i32.const 0)
+              (local.get $17)
+             )
+            )
+            (i32.or
+             (local.get $1)
+             (i32.const 8192)
+            )
+           )
+           (local.get $1)
+          )
+         )
+         (local.get $8)
+        )
+        (if (result i32)
+         (i32.lt_u
+          (local.tee $6
+           (i32.add
+            (i32.shr_s
+             (i32.shl
+              (local.get $6)
+              (i32.const 24)
+             )
+             (i32.const 24)
+            )
+            (i32.const -48)
+           )
+          )
+          (i32.const 10)
+         )
+         (block (result i32)
+          (local.set $12
+           (i32.const 0)
+          )
+          (loop $while-in8
+           (local.set $6
+            (i32.add
+             (i32.mul
+              (local.get $12)
+              (i32.const 10)
+             )
+             (local.get $6)
+            )
+           )
+           (if
+            (i32.lt_u
+             (local.tee $9
+              (i32.add
+               (i32.load8_s
+                (local.tee $10
+                 (i32.add
+                  (local.get $10)
+                  (i32.const 1)
+                 )
+                )
+               )
+               (i32.const -48)
+              )
+             )
+             (i32.const 10)
+            )
+            (block
+             (local.set $12
+              (local.get $6)
+             )
+             (local.set $6
+              (local.get $9)
+             )
+             (br $while-in8)
+            )
+           )
+          )
+          (if (result i32)
+           (i32.lt_s
+            (local.get $6)
+            (i32.const 0)
+           )
+           (block
+            (local.set $18
+             (i32.const -1)
+            )
+            (br $label$break$L1)
+           )
+           (block (result i32)
+            (local.set $12
+             (local.get $1)
+            )
+            (local.set $17
+             (local.get $6)
+            )
+            (local.get $8)
+           )
+          )
+         )
+         (block (result i32)
+          (local.set $12
+           (local.get $1)
+          )
+          (local.set $17
+           (i32.const 0)
+          )
+          (local.get $8)
+         )
+        )
+       )
+      )
+      (local.set $6
+       (if (result i32)
+        (i32.eq
+         (i32.load8_s
+          (local.get $10)
+         )
+         (i32.const 46)
+        )
+        (block $label$break$L46 (result i32)
+         (if
+          (i32.ne
+           (local.tee $8
+            (i32.load8_s
+             (local.tee $6
+              (i32.add
+               (local.get $10)
+               (i32.const 1)
+              )
+             )
+            )
+           )
+           (i32.const 42)
+          )
+          (block
+           (local.set $6
+            (if (result i32)
+             (i32.lt_u
+              (local.tee $9
+               (i32.add
+                (local.get $8)
+                (i32.const -48)
+               )
+              )
+              (i32.const 10)
+             )
+             (block (result i32)
+              (local.set $10
+               (local.get $6)
+              )
+              (local.set $8
+               (i32.const 0)
+              )
+              (local.get $9)
+             )
+             (block
+              (local.set $10
+               (local.get $6)
+              )
+              (br $label$break$L46
+               (i32.const 0)
+              )
+             )
+            )
+           )
+           (loop $while-in11
+            (drop
+             (br_if $label$break$L46
+              (local.tee $8
+               (i32.add
+                (i32.mul
+                 (local.get $8)
+                 (i32.const 10)
+                )
+                (local.get $6)
+               )
+              )
+              (i32.ge_u
+               (local.tee $6
+                (i32.add
+                 (i32.load8_s
+                  (local.tee $10
+                   (i32.add
+                    (local.get $10)
+                    (i32.const 1)
+                   )
+                  )
+                 )
+                 (i32.const -48)
+                )
+               )
+               (i32.const 10)
+              )
+             )
+            )
+            (br $while-in11)
+           )
+          )
+         )
+         (if
+          (i32.lt_u
+           (local.tee $8
+            (i32.add
+             (i32.load8_s
+              (local.tee $6
+               (i32.add
+                (local.get $10)
+                (i32.const 2)
+               )
+              )
+             )
+             (i32.const -48)
+            )
+           )
+           (i32.const 10)
+          )
+          (if
+           (i32.eq
+            (i32.load8_s offset=3
+             (local.get $10)
+            )
+            (i32.const 36)
+           )
+           (block
+            (i32.store
+             (i32.add
+              (local.get $4)
+              (i32.shl
+               (local.get $8)
+               (i32.const 2)
+              )
+             )
+             (i32.const 10)
+            )
+            (drop
+             (i32.load offset=4
+              (local.tee $6
+               (i32.add
+                (local.get $3)
+                (i32.shl
+                 (i32.add
+                  (i32.load8_s
+                   (local.get $6)
+                  )
+                  (i32.const -48)
+                 )
+                 (i32.const 3)
+                )
+               )
+              )
+             )
+            )
+            (local.set $10
+             (i32.add
+              (local.get $10)
+              (i32.const 4)
+             )
+            )
+            (br $label$break$L46
+             (i32.load
+              (local.get $6)
+             )
+            )
+           )
+          )
+         )
+         (if
+          (local.get $1)
+          (block
+           (local.set $18
+            (i32.const -1)
+           )
+           (br $label$break$L1)
+          )
+         )
+         (if (result i32)
+          (local.get $28)
+          (block (result i32)
+           (local.set $8
+            (i32.load
+             (local.tee $10
+              (i32.and
+               (i32.add
+                (i32.load
+                 (local.get $2)
+                )
+                (i32.const 3)
+               )
+               (i32.const -4)
+              )
+             )
+            )
+           )
+           (i32.store
+            (local.get $2)
+            (i32.add
+             (local.get $10)
+             (i32.const 4)
+            )
+           )
+           (local.set $10
+            (local.get $6)
+           )
+           (local.get $8)
+          )
+          (block (result i32)
+           (local.set $10
+            (local.get $6)
+           )
+           (i32.const 0)
+          )
+         )
+        )
+        (i32.const -1)
+       )
+      )
+      (local.set $8
+       (local.get $10)
+      )
+      (local.set $9
+       (i32.const 0)
+      )
+      (local.set $16
+       (loop $while-in13 (result i32)
+        (if
+         (i32.gt_u
+          (local.tee $11
+           (i32.add
+            (i32.load8_s
+             (local.get $8)
+            )
+            (i32.const -65)
+           )
+          )
+          (i32.const 57)
+         )
+         (block
+          (local.set $18
+           (i32.const -1)
+          )
+          (br $label$break$L1)
+         )
+        )
+        (local.set $10
+         (i32.add
+          (local.get $8)
+          (i32.const 1)
+         )
+        )
+        (if (result i32)
+         (i32.lt_u
+          (i32.add
+           (local.tee $11
+            (i32.and
+             (local.tee $15
+              (i32.load8_s
+               (i32.add
+                (i32.add
+                 (i32.mul
+                  (local.get $9)
+                  (i32.const 58)
+                 )
+                 (i32.const 3611)
+                )
+                (local.get $11)
+               )
+              )
+             )
+             (i32.const 255)
+            )
+           )
+           (i32.const -1)
+          )
+          (i32.const 8)
+         )
+         (block
+          (local.set $8
+           (local.get $10)
+          )
+          (local.set $9
+           (local.get $11)
+          )
+          (br $while-in13)
+         )
+         (local.get $8)
+        )
+       )
+      )
+      (if
+       (i32.eqz
+        (i32.and
+         (local.get $15)
+         (i32.const 255)
+        )
+       )
+       (block
+        (local.set $18
+         (i32.const -1)
+        )
+        (br $label$break$L1)
+       )
+      )
+      (local.set $8
+       (i32.gt_s
+        (local.get $19)
+        (i32.const -1)
+       )
+      )
+      (block $__rjto$2
+       (block $__rjti$2
+        (if
+         (i32.eq
+          (i32.and
+           (local.get $15)
+           (i32.const 255)
+          )
+          (i32.const 19)
+         )
+         (if
+          (local.get $8)
+          (block
+           (local.set $18
+            (i32.const -1)
+           )
+           (br $label$break$L1)
+          )
+          (br $__rjti$2)
+         )
+         (block
+          (if
+           (local.get $8)
+           (block
+            (i32.store
+             (i32.add
+              (local.get $4)
+              (i32.shl
+               (local.get $19)
+               (i32.const 2)
+              )
+             )
+             (local.get $11)
+            )
+            (local.set $11
+             (i32.load offset=4
+              (local.tee $8
+               (i32.add
+                (local.get $3)
+                (i32.shl
+                 (local.get $19)
+                 (i32.const 3)
+                )
+               )
+              )
+             )
+            )
+            (i32.store
+             (local.get $13)
+             (i32.load
+              (local.get $8)
+             )
+            )
+            (i32.store offset=4
+             (local.get $13)
+             (local.get $11)
+            )
+            (br $__rjti$2)
+           )
+          )
+          (if
+           (i32.eqz
+            (local.get $28)
+           )
+           (block
+            (local.set $18
+             (i32.const 0)
+            )
+            (br $label$break$L1)
+           )
+          )
+          (call $_pop_arg_336
+           (local.get $13)
+           (local.get $11)
+           (local.get $2)
+          )
+         )
+        )
+        (br $__rjto$2)
+       )
+       (if
+        (i32.eqz
+         (local.get $28)
+        )
+        (block
+         (local.set $5
+          (local.get $10)
+         )
+         (local.set $10
+          (local.get $7)
+         )
+         (br $label$continue$L1)
+        )
+       )
+      )
+      (local.set $12
+       (select
+        (local.tee $8
+         (i32.and
+          (local.get $12)
+          (i32.const -65537)
+         )
+        )
+        (local.get $12)
+        (i32.and
+         (local.get $12)
+         (i32.const 8192)
+        )
+       )
+      )
+      (call $_pad
+       (local.get $0)
+       (i32.const 32)
+       (local.tee $6
+        (select
+         (local.tee $5
+          (i32.add
+           (local.tee $11
+            (select
+             (local.tee $16
+              (i32.sub
+               (block $__rjto$8 (result i32)
+                (block $__rjti$8
+                 (call $_pad
+                  (local.get $0)
+                  (i32.const 32)
+                  (local.get $17)
+                  (local.tee $7
+                   (block $__rjti$7 (result i32)
+                    (block $__rjti$6
+                     (block $__rjti$5
+                      (block $__rjti$4
+                       (block $__rjti$3
+                        (block $switch-default120
+                         (block $switch-case42
+                          (block $switch-case41
+                           (block $switch-case40
+                            (block $switch-case39
+                             (block $switch-case38
+                              (block $switch-case37
+                               (block $switch-case36
+                                (block $switch-case34
+                                 (block $switch-case33
+                                  (block $switch-case29
+                                   (block $switch-case28
+                                    (block $switch-case27
+                                     (br_table $switch-case42 $switch-default120 $switch-case40 $switch-default120 $switch-case42 $switch-case42 $switch-case42 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-case41 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-case29 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-case42 $switch-default120 $switch-case37 $switch-case34 $switch-case42 $switch-case42 $switch-case42 $switch-default120 $switch-case34 $switch-default120 $switch-default120 $switch-default120 $switch-case38 $switch-case27 $switch-case33 $switch-case28 $switch-default120 $switch-default120 $switch-case39 $switch-default120 $switch-case36 $switch-default120 $switch-default120 $switch-case29 $switch-default120
+                                      (i32.sub
+                                       (local.tee $16
+                                        (select
+                                         (i32.and
+                                          (local.tee $11
+                                           (i32.load8_s
+                                            (local.get $16)
+                                           )
+                                          )
+                                          (i32.const -33)
+                                         )
+                                         (local.get $11)
+                                         (i32.and
+                                          (i32.eq
+                                           (i32.and
+                                            (local.get $11)
+                                            (i32.const 15)
+                                           )
+                                           (i32.const 3)
+                                          )
+                                          (i32.ne
+                                           (local.get $9)
+                                           (i32.const 0)
+                                          )
+                                         )
+                                        )
+                                       )
+                                       (i32.const 65)
+                                      )
+                                     )
+                                    )
+                                    (block $switch-default26
+                                     (block $switch-case25
+                                      (block $switch-case24
+                                       (block $switch-case23
+                                        (block $switch-case22
+                                         (block $switch-case21
+                                          (block $switch-case20
+                                           (block $switch-case19
+                                            (br_table $switch-case19 $switch-case20 $switch-case21 $switch-case22 $switch-case23 $switch-default26 $switch-case24 $switch-case25 $switch-default26
+                                             (local.get $9)
+                                            )
+                                           )
+                                           (i32.store
+                                            (i32.load
+                                             (local.get $13)
+                                            )
+                                            (local.get $18)
+                                           )
+                                           (local.set $5
+                                            (local.get $10)
+                                           )
+                                           (local.set $10
+                                            (local.get $7)
+                                           )
+                                           (br $label$continue$L1)
+                                          )
+                                          (i32.store
+                                           (i32.load
+                                            (local.get $13)
+                                           )
+                                           (local.get $18)
+                                          )
+                                          (local.set $5
+                                           (local.get $10)
+                                          )
+                                          (local.set $10
+                                           (local.get $7)
+                                          )
+                                          (br $label$continue$L1)
+                                         )
+                                         (i32.store
+                                          (local.tee $5
+                                           (i32.load
+                                            (local.get $13)
+                                           )
+                                          )
+                                          (local.get $18)
+                                         )
+                                         (i32.store offset=4
+                                          (local.get $5)
+                                          (i32.shr_s
+                                           (i32.shl
+                                            (i32.lt_s
+                                             (local.get $18)
+                                             (i32.const 0)
+                                            )
+                                            (i32.const 31)
+                                           )
+                                           (i32.const 31)
+                                          )
+                                         )
+                                         (local.set $5
+                                          (local.get $10)
+                                         )
+                                         (local.set $10
+                                          (local.get $7)
+                                         )
+                                         (br $label$continue$L1)
+                                        )
+                                        (i32.store16
+                                         (i32.load
+                                          (local.get $13)
+                                         )
+                                         (local.get $18)
+                                        )
+                                        (local.set $5
+                                         (local.get $10)
+                                        )
+                                        (local.set $10
+                                         (local.get $7)
+                                        )
+                                        (br $label$continue$L1)
+                                       )
+                                       (i32.store8
+                                        (i32.load
+                                         (local.get $13)
+                                        )
+                                        (local.get $18)
+                                       )
+                                       (local.set $5
+                                        (local.get $10)
+                                       )
+                                       (local.set $10
+                                        (local.get $7)
+                                       )
+                                       (br $label$continue$L1)
+                                      )
+                                      (i32.store
+                                       (i32.load
+                                        (local.get $13)
+                                       )
+                                       (local.get $18)
+                                      )
+                                      (local.set $5
+                                       (local.get $10)
+                                      )
+                                      (local.set $10
+                                       (local.get $7)
+                                      )
+                                      (br $label$continue$L1)
+                                     )
+                                     (i32.store
+                                      (local.tee $5
+                                       (i32.load
+                                        (local.get $13)
+                                       )
+                                      )
+                                      (local.get $18)
+                                     )
+                                     (i32.store offset=4
+                                      (local.get $5)
+                                      (i32.shr_s
+                                       (i32.shl
+                                        (i32.lt_s
+                                         (local.get $18)
+                                         (i32.const 0)
+                                        )
+                                        (i32.const 31)
+                                       )
+                                       (i32.const 31)
+                                      )
+                                     )
+                                     (local.set $5
+                                      (local.get $10)
+                                     )
+                                     (local.set $10
+                                      (local.get $7)
+                                     )
+                                     (br $label$continue$L1)
+                                    )
+                                    (local.set $5
+                                     (local.get $10)
+                                    )
+                                    (local.set $10
+                                     (local.get $7)
+                                    )
+                                    (br $label$continue$L1)
+                                   )
+                                   (local.set $7
+                                    (i32.or
+                                     (local.get $12)
+                                     (i32.const 8)
+                                    )
+                                   )
+                                   (local.set $6
+                                    (select
+                                     (local.get $6)
+                                     (i32.const 8)
+                                     (i32.gt_u
+                                      (local.get $6)
+                                      (i32.const 8)
+                                     )
+                                    )
+                                   )
+                                   (local.set $16
+                                    (i32.const 120)
+                                   )
+                                   (br $__rjti$3)
+                                  )
+                                  (local.set $7
+                                   (local.get $12)
+                                  )
+                                  (br $__rjti$3)
+                                 )
+                                 (if
+                                  (i32.or
+                                   (local.tee $5
+                                    (i32.load
+                                     (local.get $13)
+                                    )
+                                   )
+                                   (local.tee $7
+                                    (i32.load offset=4
+                                     (local.get $13)
+                                    )
+                                   )
+                                  )
+                                  (block
+                                   (local.set $8
+                                    (local.get $25)
+                                   )
+                                   (loop $while-in32
+                                    (i32.store8
+                                     (local.tee $8
+                                      (i32.add
+                                       (local.get $8)
+                                       (i32.const -1)
+                                      )
+                                     )
+                                     (i32.or
+                                      (i32.and
+                                       (local.get $5)
+                                       (i32.const 7)
+                                      )
+                                      (i32.const 48)
+                                     )
+                                    )
+                                    (br_if $while-in32
+                                     (i32.or
+                                      (local.tee $5
+                                       (call $_bitshift64Lshr
+                                        (local.get $5)
+                                        (local.get $7)
+                                        (i32.const 3)
+                                       )
+                                      )
+                                      (local.tee $7
+                                       (global.get $tempRet0)
+                                      )
+                                     )
+                                    )
+                                   )
+                                  )
+                                  (local.set $8
+                                   (local.get $25)
+                                  )
+                                 )
+                                 (if
+                                  (i32.and
+                                   (local.get $12)
+                                   (i32.const 8)
+                                  )
+                                  (block
+                                   (local.set $7
+                                    (local.get $12)
+                                   )
+                                   (local.set $6
+                                    (select
+                                     (local.tee $5
+                                      (i32.add
+                                       (i32.sub
+                                        (local.get $37)
+                                        (local.get $8)
+                                       )
+                                       (i32.const 1)
+                                      )
+                                     )
+                                     (local.get $6)
+                                     (i32.lt_s
+                                      (local.get $6)
+                                      (local.get $5)
+                                     )
+                                    )
+                                   )
+                                  )
+                                  (local.set $7
+                                   (local.get $12)
+                                  )
+                                 )
+                                 (local.set $5
+                                  (local.get $8)
+                                 )
+                                 (local.set $8
+                                  (i32.const 0)
+                                 )
+                                 (local.set $9
+                                  (i32.const 4091)
+                                 )
+                                 (br $__rjti$8)
+                                )
+                                (local.set $5
+                                 (i32.load
+                                  (local.get $13)
+                                 )
+                                )
+                                (if
+                                 (i32.lt_s
+                                  (local.tee $7
+                                   (i32.load offset=4
+                                    (local.get $13)
+                                   )
+                                  )
+                                  (i32.const 0)
+                                 )
+                                 (block
+                                  (global.set $tempRet0
+                                   (i32.sub
+                                    (i32.sub
+                                     (i32.const 0)
+                                     (local.get $7)
+                                    )
+                                    (i32.gt_u
+                                     (local.get $5)
+                                     (i32.const 0)
+                                    )
+                                   )
+                                  )
+                                  (i32.store
+                                   (local.get $13)
+                                   (local.tee $5
+                                    (i32.sub
+                                     (i32.const 0)
+                                     (local.get $5)
+                                    )
+                                   )
+                                  )
+                                  (i32.store offset=4
+                                   (local.get $13)
+                                   (local.tee $7
+                                    (global.get $tempRet0)
+                                   )
+                                  )
+                                  (local.set $8
+                                   (i32.const 1)
+                                  )
+                                  (local.set $9
+                                   (i32.const 4091)
+                                  )
+                                  (br $__rjti$4)
+                                 )
+                                )
+                                (local.set $9
+                                 (if (result i32)
+                                  (i32.and
+                                   (local.get $12)
+                                   (i32.const 2048)
+                                  )
+                                  (block (result i32)
+                                   (local.set $8
+                                    (i32.const 1)
+                                   )
+                                   (i32.const 4092)
+                                  )
+                                  (block (result i32)
+                                   (local.set $8
+                                    (local.tee $9
+                                     (i32.and
+                                      (local.get $12)
+                                      (i32.const 1)
+                                     )
+                                    )
+                                   )
+                                   (select
+                                    (i32.const 4093)
+                                    (i32.const 4091)
+                                    (local.get $9)
+                                   )
+                                  )
+                                 )
+                                )
+                                (br $__rjti$4)
+                               )
+                               (local.set $5
+                                (i32.load
+                                 (local.get $13)
+                                )
+                               )
+                               (local.set $7
+                                (i32.load offset=4
+                                 (local.get $13)
+                                )
+                               )
+                               (local.set $8
+                                (i32.const 0)
+                               )
+                               (local.set $9
+                                (i32.const 4091)
+                               )
+                               (br $__rjti$4)
+                              )
+                              (drop
+                               (i32.load offset=4
+                                (local.get $13)
+                               )
+                              )
+                              (i32.store8
+                               (local.get $38)
+                               (i32.load
+                                (local.get $13)
+                               )
+                              )
+                              (local.set $7
+                               (local.get $38)
+                              )
+                              (local.set $12
+                               (local.get $8)
+                              )
+                              (local.set $11
+                               (i32.const 1)
+                              )
+                              (local.set $8
+                               (i32.const 0)
+                              )
+                              (local.set $9
+                               (i32.const 4091)
+                              )
+                              (br $__rjto$8
+                               (local.get $25)
+                              )
+                             )
+                             (local.set $5
+                              (call $_strerror
+                               (i32.load
+                                (call $___errno_location)
+                               )
+                              )
+                             )
+                             (br $__rjti$5)
+                            )
+                            (local.set $5
+                             (select
+                              (local.tee $5
+                               (i32.load
+                                (local.get $13)
+                               )
+                              )
+                              (i32.const 4101)
+                              (local.get $5)
+                             )
+                            )
+                            (br $__rjti$5)
+                           )
+                           (drop
+                            (i32.load offset=4
+                             (local.get $13)
+                            )
+                           )
+                           (i32.store
+                            (local.get $39)
+                            (i32.load
+                             (local.get $13)
+                            )
+                           )
+                           (i32.store
+                            (local.get $42)
+                            (i32.const 0)
+                           )
+                           (i32.store
+                            (local.get $13)
+                            (local.get $39)
+                           )
+                           (local.set $8
+                            (i32.const -1)
+                           )
+                           (br $__rjti$6)
+                          )
+                          (if
+                           (local.get $6)
+                           (block
+                            (local.set $8
+                             (local.get $6)
+                            )
+                            (br $__rjti$6)
+                           )
+                           (block
+                            (call $_pad
+                             (local.get $0)
+                             (i32.const 32)
+                             (local.get $17)
+                             (i32.const 0)
+                             (local.get $12)
+                            )
+                            (br $__rjti$7
+                             (i32.const 0)
+                            )
+                           )
+                          )
+                         )
+                         (local.set $14
+                          (f64.load
+                           (local.get $13)
+                          )
+                         )
+                         (i32.store
+                          (local.get $21)
+                          (i32.const 0)
+                         )
+                         (f64.store
+                          (global.get $tempDoublePtr)
+                          (local.get $14)
+                         )
+                         (drop
+                          (i32.load
+                           (global.get $tempDoublePtr)
+                          )
+                         )
+                         (local.set $30
+                          (if (result i32)
+                           (i32.lt_s
+                            (i32.load offset=4
+                             (global.get $tempDoublePtr)
+                            )
+                            (i32.const 0)
+                           )
+                           (block (result i32)
+                            (local.set $27
+                             (i32.const 1)
+                            )
+                            (local.set $14
+                             (f64.neg
+                              (local.get $14)
+                             )
+                            )
+                            (i32.const 4108)
+                           )
+                           (if (result i32)
+                            (i32.and
+                             (local.get $12)
+                             (i32.const 2048)
+                            )
+                            (block (result i32)
+                             (local.set $27
+                              (i32.const 1)
+                             )
+                             (i32.const 4111)
+                            )
+                            (block (result i32)
+                             (local.set $27
+                              (local.tee $5
+                               (i32.and
+                                (local.get $12)
+                                (i32.const 1)
+                               )
+                              )
+                             )
+                             (select
+                              (i32.const 4114)
+                              (i32.const 4109)
+                              (local.get $5)
+                             )
+                            )
+                           )
+                          )
+                         )
+                         (f64.store
+                          (global.get $tempDoublePtr)
+                          (local.get $14)
+                         )
+                         (drop
+                          (i32.load
+                           (global.get $tempDoublePtr)
+                          )
+                         )
+                         (local.set $7
+                          (if (result i32)
+                           (i32.lt_u
+                            (i32.and
+                             (i32.load offset=4
+                              (global.get $tempDoublePtr)
+                             )
+                             (i32.const 2146435072)
+                            )
+                            (i32.const 2146435072)
+                           )
+                           (block $do-once49 (result i32)
+                            (if
+                             (local.tee $5
+                              (f64.ne
+                               (local.tee $24
+                                (f64.mul
+                                 (call $_frexp
+                                  (local.get $14)
+                                  (local.get $21)
+                                 )
+                                 (f64.const 2)
+                                )
+                               )
+                               (f64.const 0)
+                              )
+                             )
+                             (i32.store
+                              (local.get $21)
+                              (i32.add
+                               (i32.load
+                                (local.get $21)
+                               )
+                               (i32.const -1)
+                              )
+                             )
+                            )
+                            (if
+                             (i32.eq
+                              (local.tee $26
+                               (i32.or
+                                (local.get $16)
+                                (i32.const 32)
+                               )
+                              )
+                              (i32.const 97)
+                             )
+                             (block
+                              (local.set $9
+                               (select
+                                (i32.add
+                                 (local.get $30)
+                                 (i32.const 9)
+                                )
+                                (local.get $30)
+                                (local.tee $15
+                                 (i32.and
+                                  (local.get $16)
+                                  (i32.const 32)
+                                 )
+                                )
+                               )
+                              )
+                              (local.set $14
+                               (if (result f64)
+                                (i32.or
+                                 (i32.eqz
+                                  (local.tee $5
+                                   (i32.sub
+                                    (i32.const 12)
+                                    (local.get $6)
+                                   )
+                                  )
+                                 )
+                                 (i32.gt_u
+                                  (local.get $6)
+                                  (i32.const 11)
+                                 )
+                                )
+                                (local.get $24)
+                                (block (result f64)
+                                 (local.set $14
+                                  (f64.const 8)
+                                 )
+                                 (loop $while-in54
+                                  (local.set $14
+                                   (f64.mul
+                                    (local.get $14)
+                                    (f64.const 16)
+                                   )
+                                  )
+                                  (br_if $while-in54
+                                   (local.tee $5
+                                    (i32.add
+                                     (local.get $5)
+                                     (i32.const -1)
+                                    )
+                                   )
+                                  )
+                                 )
+                                 (if (result f64)
+                                  (i32.eq
+                                   (i32.load8_s
+                                    (local.get $9)
+                                   )
+                                   (i32.const 45)
+                                  )
+                                  (f64.neg
+                                   (f64.add
+                                    (local.get $14)
+                                    (f64.sub
+                                     (f64.neg
+                                      (local.get $24)
+                                     )
+                                     (local.get $14)
+                                    )
+                                   )
+                                  )
+                                  (f64.sub
+                                   (f64.add
+                                    (local.get $24)
+                                    (local.get $14)
+                                   )
+                                   (local.get $14)
+                                  )
+                                 )
+                                )
+                               )
+                              )
+                              (local.set $11
+                               (i32.or
+                                (local.get $27)
+                                (i32.const 2)
+                               )
+                              )
+                              (if
+                               (i32.eq
+                                (local.tee $5
+                                 (call $_fmt_u
+                                  (local.tee $5
+                                   (select
+                                    (i32.sub
+                                     (i32.const 0)
+                                     (local.tee $7
+                                      (i32.load
+                                       (local.get $21)
+                                      )
+                                     )
+                                    )
+                                    (local.get $7)
+                                    (i32.lt_s
+                                     (local.get $7)
+                                     (i32.const 0)
+                                    )
+                                   )
+                                  )
+                                  (i32.shr_s
+                                   (i32.shl
+                                    (i32.lt_s
+                                     (local.get $5)
+                                     (i32.const 0)
+                                    )
+                                    (i32.const 31)
+                                   )
+                                   (i32.const 31)
+                                  )
+                                  (local.get $22)
+                                 )
+                                )
+                                (local.get $22)
+                               )
+                               (block
+                                (i32.store8
+                                 (local.get $40)
+                                 (i32.const 48)
+                                )
+                                (local.set $5
+                                 (local.get $40)
+                                )
+                               )
+                              )
+                              (i32.store8
+                               (i32.add
+                                (local.get $5)
+                                (i32.const -1)
+                               )
+                               (i32.add
+                                (i32.and
+                                 (i32.shr_s
+                                  (local.get $7)
+                                  (i32.const 31)
+                                 )
+                                 (i32.const 2)
+                                )
+                                (i32.const 43)
+                               )
+                              )
+                              (i32.store8
+                               (local.tee $8
+                                (i32.add
+                                 (local.get $5)
+                                 (i32.const -2)
+                                )
+                               )
+                               (i32.add
+                                (local.get $16)
+                                (i32.const 15)
+                               )
+                              )
+                              (local.set $16
+                               (i32.lt_s
+                                (local.get $6)
+                                (i32.const 1)
+                               )
+                              )
+                              (local.set $20
+                               (i32.eqz
+                                (i32.and
+                                 (local.get $12)
+                                 (i32.const 8)
+                                )
+                               )
+                              )
+                              (local.set $5
+                               (local.get $23)
+                              )
+                              (loop $while-in56
+                               (i32.store8
+                                (local.get $5)
+                                (i32.or
+                                 (i32.load8_u
+                                  (i32.add
+                                   (local.tee $7
+                                    (if (result i32)
+                                     (f64.ne
+                                      (local.get $14)
+                                      (local.get $14)
+                                     )
+                                     (i32.const -2147483648)
+                                     (if (result i32)
+                                      (f64.ge
+                                       (local.get $14)
+                                       (f64.const 2147483648)
+                                      )
+                                      (i32.const -2147483648)
+                                      (if (result i32)
+                                       (f64.le
+                                        (local.get $14)
+                                        (f64.const -2147483649)
+                                       )
+                                       (i32.const -2147483648)
+                                       (i32.trunc_f64_s
+                                        (local.get $14)
+                                       )
+                                      )
+                                     )
+                                    )
+                                   )
+                                   (i32.const 4075)
+                                  )
+                                 )
+                                 (local.get $15)
+                                )
+                               )
+                               (local.set $14
+                                (f64.mul
+                                 (f64.sub
+                                  (local.get $14)
+                                  (f64.convert_i32_s
+                                   (local.get $7)
+                                  )
+                                 )
+                                 (f64.const 16)
+                                )
+                               )
+                               (local.set $5
+                                (if (result i32)
+                                 (i32.eq
+                                  (i32.sub
+                                   (local.tee $7
+                                    (i32.add
+                                     (local.get $5)
+                                     (i32.const 1)
+                                    )
+                                   )
+                                   (local.get $34)
+                                  )
+                                  (i32.const 1)
+                                 )
+                                 (if (result i32)
+                                  (i32.and
+                                   (local.get $20)
+                                   (i32.and
+                                    (local.get $16)
+                                    (f64.eq
+                                     (local.get $14)
+                                     (f64.const 0)
+                                    )
+                                   )
+                                  )
+                                  (local.get $7)
+                                  (block (result i32)
+                                   (i32.store8
+                                    (local.get $7)
+                                    (i32.const 46)
+                                   )
+                                   (i32.add
+                                    (local.get $5)
+                                    (i32.const 2)
+                                   )
+                                  )
+                                 )
+                                 (local.get $7)
+                                )
+                               )
+                               (br_if $while-in56
+                                (f64.ne
+                                 (local.get $14)
+                                 (f64.const 0)
+                                )
+                               )
+                              )
+                              (call $_pad
+                               (local.get $0)
+                               (i32.const 32)
+                               (local.get $17)
+                               (local.tee $7
+                                (i32.add
+                                 (local.tee $6
+                                  (select
+                                   (i32.sub
+                                    (i32.add
+                                     (local.get $6)
+                                     (local.get $45)
+                                    )
+                                    (local.get $8)
+                                   )
+                                   (i32.add
+                                    (i32.sub
+                                     (local.get $43)
+                                     (local.get $8)
+                                    )
+                                    (local.get $5)
+                                   )
+                                   (i32.and
+                                    (i32.ne
+                                     (local.get $6)
+                                     (i32.const 0)
+                                    )
+                                    (i32.lt_s
+                                     (i32.add
+                                      (local.get $5)
+                                      (local.get $44)
+                                     )
+                                     (local.get $6)
+                                    )
+                                   )
+                                  )
+                                 )
+                                 (local.get $11)
+                                )
+                               )
+                               (local.get $12)
+                              )
+                              (if
+                               (i32.eqz
+                                (i32.and
+                                 (i32.load
+                                  (local.get $0)
+                                 )
+                                 (i32.const 32)
+                                )
+                               )
+                               (drop
+                                (call $___fwritex
+                                 (local.get $9)
+                                 (local.get $11)
+                                 (local.get $0)
+                                )
+                               )
+                              )
+                              (call $_pad
+                               (local.get $0)
+                               (i32.const 48)
+                               (local.get $17)
+                               (local.get $7)
+                               (i32.xor
+                                (local.get $12)
+                                (i32.const 65536)
+                               )
+                              )
+                              (local.set $5
+                               (i32.sub
+                                (local.get $5)
+                                (local.get $34)
+                               )
+                              )
+                              (if
+                               (i32.eqz
+                                (i32.and
+                                 (i32.load
+                                  (local.get $0)
+                                 )
+                                 (i32.const 32)
+                                )
+                               )
+                               (drop
+                                (call $___fwritex
+                                 (local.get $23)
+                                 (local.get $5)
+                                 (local.get $0)
+                                )
+                               )
+                              )
+                              (call $_pad
+                               (local.get $0)
+                               (i32.const 48)
+                               (i32.sub
+                                (local.get $6)
+                                (i32.add
+                                 (local.get $5)
+                                 (local.tee $6
+                                  (i32.sub
+                                   (local.get $22)
+                                   (local.get $8)
+                                  )
+                                 )
+                                )
+                               )
+                               (i32.const 0)
+                               (i32.const 0)
+                              )
+                              (if
+                               (i32.eqz
+                                (i32.and
+                                 (i32.load
+                                  (local.get $0)
+                                 )
+                                 (i32.const 32)
+                                )
+                               )
+                               (drop
+                                (call $___fwritex
+                                 (local.get $8)
+                                 (local.get $6)
+                                 (local.get $0)
+                                )
+                               )
+                              )
+                              (call $_pad
+                               (local.get $0)
+                               (i32.const 32)
+                               (local.get $17)
+                               (local.get $7)
+                               (i32.xor
+                                (local.get $12)
+                                (i32.const 8192)
+                               )
+                              )
+                              (br $do-once49
+                               (select
+                                (local.get $17)
+                                (local.get $7)
+                                (i32.lt_s
+                                 (local.get $7)
+                                 (local.get $17)
+                                )
+                               )
+                              )
+                             )
+                            )
+                            (local.set $14
+                             (if (result f64)
+                              (local.get $5)
+                              (block (result f64)
+                               (i32.store
+                                (local.get $21)
+                                (local.tee $5
+                                 (i32.add
+                                  (i32.load
+                                   (local.get $21)
+                                  )
+                                  (i32.const -28)
+                                 )
+                                )
+                               )
+                               (f64.mul
+                                (local.get $24)
+                                (f64.const 268435456)
+                               )
+                              )
+                              (block (result f64)
+                               (local.set $5
+                                (i32.load
+                                 (local.get $21)
+                                )
+                               )
+                               (local.get $24)
+                              )
+                             )
+                            )
+                            (local.set $7
+                             (local.tee $8
+                              (select
+                               (local.get $46)
+                               (local.get $47)
+                               (i32.lt_s
+                                (local.get $5)
+                                (i32.const 0)
+                               )
+                              )
+                             )
+                            )
+                            (loop $while-in60
+                             (i32.store
+                              (local.get $7)
+                              (local.tee $5
+                               (if (result i32)
+                                (f64.ne
+                                 (local.get $14)
+                                 (local.get $14)
+                                )
+                                (i32.const -2147483648)
+                                (if (result i32)
+                                 (f64.ge
+                                  (local.get $14)
+                                  (f64.const 2147483648)
+                                 )
+                                 (i32.const -2147483648)
+                                 (if (result i32)
+                                  (f64.le
+                                   (local.get $14)
+                                   (f64.const -2147483649)
+                                  )
+                                  (i32.const -2147483648)
+                                  (i32.trunc_f64_s
+                                   (local.get $14)
+                                  )
+                                 )
+                                )
+                               )
+                              )
+                             )
+                             (local.set $7
+                              (i32.add
+                               (local.get $7)
+                               (i32.const 4)
+                              )
+                             )
+                             (br_if $while-in60
+                              (f64.ne
+                               (local.tee $14
+                                (f64.mul
+                                 (f64.sub
+                                  (local.get $14)
+                                  (f64.convert_i32_u
+                                   (local.get $5)
+                                  )
+                                 )
+                                 (f64.const 1e9)
+                                )
+                               )
+                               (f64.const 0)
+                              )
+                             )
+                            )
+                            (if
+                             (i32.gt_s
+                              (local.tee $9
+                               (i32.load
+                                (local.get $21)
+                               )
+                              )
+                              (i32.const 0)
+                             )
+                             (block
+                              (local.set $5
+                               (local.get $8)
+                              )
+                              (loop $while-in62
+                               (local.set $15
+                                (select
+                                 (i32.const 29)
+                                 (local.get $9)
+                                 (i32.gt_s
+                                  (local.get $9)
+                                  (i32.const 29)
+                                 )
+                                )
+                               )
+                               (if
+                                (i32.ge_u
+                                 (local.tee $9
+                                  (i32.add
+                                   (local.get $7)
+                                   (i32.const -4)
+                                  )
+                                 )
+                                 (local.get $5)
+                                )
+                                (block $do-once63
+                                 (local.set $11
+                                  (i32.const 0)
+                                 )
+                                 (loop $while-in66
+                                  (i32.store
+                                   (local.get $9)
+                                   (call $___uremdi3
+                                    (block (result i32)
+                                     (global.set $tempRet0
+                                      (i32.add
+                                       (i32.lt_u
+                                        (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)
+                                       )
+                                       (global.get $tempRet0)
+                                      )
+                                     )
+                                     (local.get $11)
+                                    )
+                                    (local.tee $20
+                                     (global.get $tempRet0)
+                                    )
+                                    (i32.const 1000000000)
+                                    (i32.const 0)
+                                   )
+                                  )
+                                  (local.set $11
+                                   (call $___udivdi3
+                                    (local.get $11)
+                                    (local.get $20)
+                                    (i32.const 1000000000)
+                                    (i32.const 0)
+                                   )
+                                  )
+                                  (br_if $while-in66
+                                   (i32.ge_u
+                                    (local.tee $9
+                                     (i32.add
+                                      (local.get $9)
+                                      (i32.const -4)
+                                     )
+                                    )
+                                    (local.get $5)
+                                   )
+                                  )
+                                 )
+                                 (br_if $do-once63
+                                  (i32.eqz
+                                   (local.get $11)
+                                  )
+                                 )
+                                 (i32.store
+                                  (local.tee $5
+                                   (i32.add
+                                    (local.get $5)
+                                    (i32.const -4)
+                                   )
+                                  )
+                                  (local.get $11)
+                                 )
+                                )
+                               )
+                               (loop $while-in68
+                                (if
+                                 (i32.gt_u
+                                  (local.get $7)
+                                  (local.get $5)
+                                 )
+                                 (if
+                                  (i32.eqz
+                                   (i32.load
+                                    (local.tee $9
+                                     (i32.add
+                                      (local.get $7)
+                                      (i32.const -4)
+                                     )
+                                    )
+                                   )
+                                  )
+                                  (block
+                                   (local.set $7
+                                    (local.get $9)
+                                   )
+                                   (br $while-in68)
+                                  )
+                                 )
+                                )
+                               )
+                               (i32.store
+                                (local.get $21)
+                                (local.tee $9
+                                 (i32.sub
+                                  (i32.load
+                                   (local.get $21)
+                                  )
+                                  (local.get $15)
+                                 )
+                                )
+                               )
+                               (br_if $while-in62
+                                (i32.gt_s
+                                 (local.get $9)
+                                 (i32.const 0)
+                                )
+                               )
+                              )
+                             )
+                             (local.set $5
+                              (local.get $8)
+                             )
+                            )
+                            (local.set $19
+                             (select
+                              (i32.const 6)
+                              (local.get $6)
+                              (i32.lt_s
+                               (local.get $6)
+                               (i32.const 0)
+                              )
+                             )
+                            )
+                            (if
+                             (i32.lt_s
+                              (local.get $9)
+                              (i32.const 0)
+                             )
+                             (block
+                              (local.set $20
+                               (i32.add
+                                (i32.div_s
+                                 (i32.add
+                                  (local.get $19)
+                                  (i32.const 25)
+                                 )
+                                 (i32.const 9)
+                                )
+                                (i32.const 1)
+                               )
+                              )
+                              (local.set $31
+                               (i32.eq
+                                (local.get $26)
+                                (i32.const 102)
+                               )
+                              )
+                              (local.set $6
+                               (local.get $5)
+                              )
+                              (local.set $5
+                               (local.get $7)
+                              )
+                              (local.set $5
+                               (loop $while-in70 (result i32)
+                                (local.set $15
+                                 (select
+                                  (i32.const 9)
+                                  (local.tee $7
+                                   (i32.sub
+                                    (i32.const 0)
+                                    (local.get $9)
+                                   )
+                                  )
+                                  (i32.gt_s
+                                   (local.get $7)
+                                   (i32.const 9)
+                                  )
+                                 )
+                                )
+                                (if
+                                 (i32.lt_u
+                                  (local.get $6)
+                                  (local.get $5)
+                                 )
+                                 (block $do-once71
+                                  (local.set $11
+                                   (i32.add
+                                    (i32.shl
+                                     (i32.const 1)
+                                     (local.get $15)
+                                    )
+                                    (i32.const -1)
+                                   )
+                                  )
+                                  (local.set $35
+                                   (i32.shr_u
+                                    (i32.const 1000000000)
+                                    (local.get $15)
+                                   )
+                                  )
+                                  (local.set $9
+                                   (i32.const 0)
+                                  )
+                                  (local.set $7
+                                   (local.get $6)
+                                  )
+                                  (loop $while-in74
+                                   (i32.store
+                                    (local.get $7)
+                                    (i32.add
+                                     (local.get $9)
+                                     (i32.shr_u
+                                      (local.tee $9
+                                       (i32.load
+                                        (local.get $7)
+                                       )
+                                      )
+                                      (local.get $15)
+                                     )
+                                    )
+                                   )
+                                   (local.set $9
+                                    (i32.mul
+                                     (i32.and
+                                      (local.get $9)
+                                      (local.get $11)
+                                     )
+                                     (local.get $35)
+                                    )
+                                   )
+                                   (br_if $while-in74
+                                    (i32.lt_u
+                                     (local.tee $7
+                                      (i32.add
+                                       (local.get $7)
+                                       (i32.const 4)
+                                      )
+                                     )
+                                     (local.get $5)
+                                    )
+                                   )
+                                  )
+                                  (local.set $7
+                                   (select
+                                    (local.get $6)
+                                    (i32.add
+                                     (local.get $6)
+                                     (i32.const 4)
+                                    )
+                                    (i32.load
+                                     (local.get $6)
+                                    )
+                                   )
+                                  )
+                                  (br_if $do-once71
+                                   (i32.eqz
+                                    (local.get $9)
+                                   )
+                                  )
+                                  (i32.store
+                                   (local.get $5)
+                                   (local.get $9)
+                                  )
+                                  (local.set $5
+                                   (i32.add
+                                    (local.get $5)
+                                    (i32.const 4)
+                                   )
+                                  )
+                                 )
+                                 (local.set $7
+                                  (select
+                                   (local.get $6)
+                                   (i32.add
+                                    (local.get $6)
+                                    (i32.const 4)
+                                   )
+                                   (i32.load
+                                    (local.get $6)
+                                   )
+                                  )
+                                 )
+                                )
+                                (local.set $11
+                                 (select
+                                  (i32.add
+                                   (local.tee $6
+                                    (select
+                                     (local.get $8)
+                                     (local.get $7)
+                                     (local.get $31)
+                                    )
+                                   )
+                                   (i32.shl
+                                    (local.get $20)
+                                    (i32.const 2)
+                                   )
+                                  )
+                                  (local.get $5)
+                                  (i32.gt_s
+                                   (i32.shr_s
+                                    (i32.sub
+                                     (local.get $5)
+                                     (local.get $6)
+                                    )
+                                    (i32.const 2)
+                                   )
+                                   (local.get $20)
+                                  )
+                                 )
+                                )
+                                (i32.store
+                                 (local.get $21)
+                                 (local.tee $9
+                                  (i32.add
+                                   (i32.load
+                                    (local.get $21)
+                                   )
+                                   (local.get $15)
+                                  )
+                                 )
+                                )
+                                (if (result i32)
+                                 (i32.lt_s
+                                  (local.get $9)
+                                  (i32.const 0)
+                                 )
+                                 (block
+                                  (local.set $6
+                                   (local.get $7)
+                                  )
+                                  (local.set $5
+                                   (local.get $11)
+                                  )
+                                  (br $while-in70)
+                                 )
+                                 (block (result i32)
+                                  (local.set $9
+                                   (local.get $11)
+                                  )
+                                  (local.get $7)
+                                 )
+                                )
+                               )
+                              )
+                             )
+                             (local.set $9
+                              (local.get $7)
+                             )
+                            )
+                            (local.set $20
+                             (local.get $8)
+                            )
+                            (if
+                             (i32.lt_u
+                              (local.get $5)
+                              (local.get $9)
+                             )
+                             (block $do-once75
+                              (local.set $7
+                               (i32.mul
+                                (i32.shr_s
+                                 (i32.sub
+                                  (local.get $20)
+                                  (local.get $5)
+                                 )
+                                 (i32.const 2)
+                                )
+                                (i32.const 9)
+                               )
+                              )
+                              (br_if $do-once75
+                               (i32.lt_u
+                                (local.tee $8
+                                 (i32.load
+                                  (local.get $5)
+                                 )
+                                )
+                                (i32.const 10)
+                               )
+                              )
+                              (local.set $6
+                               (i32.const 10)
+                              )
+                              (loop $while-in78
+                               (local.set $7
+                                (i32.add
+                                 (local.get $7)
+                                 (i32.const 1)
+                                )
+                               )
+                               (br_if $while-in78
+                                (i32.ge_u
+                                 (local.get $8)
+                                 (local.tee $6
+                                  (i32.mul
+                                   (local.get $6)
+                                   (i32.const 10)
+                                  )
+                                 )
+                                )
+                               )
+                              )
+                             )
+                             (local.set $7
+                              (i32.const 0)
+                             )
+                            )
+                            (local.set $5
+                             (if (result i32)
+                              (i32.lt_s
+                               (local.tee $6
+                                (i32.add
+                                 (i32.sub
+                                  (local.get $19)
+                                  (select
+                                   (local.get $7)
+                                   (i32.const 0)
+                                   (i32.ne
+                                    (local.get $26)
+                                    (i32.const 102)
+                                   )
+                                  )
+                                 )
+                                 (i32.shr_s
+                                  (i32.shl
+                                   (i32.and
+                                    (local.tee $31
+                                     (i32.ne
+                                      (local.get $19)
+                                      (i32.const 0)
+                                     )
+                                    )
+                                    (local.tee $35
+                                     (i32.eq
+                                      (local.get $26)
+                                      (i32.const 103)
+                                     )
+                                    )
+                                   )
+                                   (i32.const 31)
+                                  )
+                                  (i32.const 31)
+                                 )
+                                )
+                               )
+                               (i32.add
+                                (i32.mul
+                                 (i32.shr_s
+                                  (i32.sub
+                                   (local.get $9)
+                                   (local.get $20)
+                                  )
+                                  (i32.const 2)
+                                 )
+                                 (i32.const 9)
+                                )
+                                (i32.const -9)
+                               )
+                              )
+                              (block (result i32)
+                               (local.set $8
+                                (i32.div_s
+                                 (local.tee $6
+                                  (i32.add
+                                   (local.get $6)
+                                   (i32.const 9216)
+                                  )
+                                 )
+                                 (i32.const 9)
+                                )
+                               )
+                               (if
+                                (i32.lt_s
+                                 (local.tee $6
+                                  (i32.add
+                                   (i32.rem_s
+                                    (local.get $6)
+                                    (i32.const 9)
+                                   )
+                                   (i32.const 1)
+                                  )
+                                 )
+                                 (i32.const 9)
+                                )
+                                (block
+                                 (local.set $11
+                                  (i32.const 10)
+                                 )
+                                 (loop $while-in80
+                                  (local.set $11
+                                   (i32.mul
+                                    (local.get $11)
+                                    (i32.const 10)
+                                   )
+                                  )
+                                  (br_if $while-in80
+                                   (i32.ne
+                                    (local.tee $6
+                                     (i32.add
+                                      (local.get $6)
+                                      (i32.const 1)
+                                     )
+                                    )
+                                    (i32.const 9)
+                                   )
+                                  )
+                                 )
+                                )
+                                (local.set $11
+                                 (i32.const 10)
+                                )
+                               )
+                               (local.set $15
+                                (local.tee $8
+                                 (i32.load
+                                  (local.tee $6
+                                   (i32.add
+                                    (i32.add
+                                     (local.get $20)
+                                     (i32.shl
+                                      (local.get $8)
+                                      (i32.const 2)
+                                     )
+                                    )
+                                    (i32.const -4092)
+                                   )
+                                  )
+                                 )
+                                )
+                               )
+                               (local.set $15
+                                (if (result i32)
+                                 (local.get $11)
+                                 (i32.rem_u
+                                  (local.get $15)
+                                  (local.get $11)
+                                 )
+                                 (i32.const 0)
+                                )
+                               )
+                               (if
+                                (i32.eqz
+                                 (i32.and
+                                  (local.tee $26
+                                   (i32.eq
+                                    (i32.add
+                                     (local.get $6)
+                                     (i32.const 4)
+                                    )
+                                    (local.get $9)
+                                   )
+                                  )
+                                  (i32.eqz
+                                   (local.get $15)
+                                  )
+                                 )
+                                )
+                                (block $do-once81
+                                 (local.set $36
+                                  (if (result i32)
+                                   (local.get $11)
+                                   (i32.div_u
+                                    (local.get $8)
+                                    (local.get $11)
+                                   )
+                                   (i32.const 0)
+                                  )
+                                 )
+                                 (local.set $14
+                                  (if (result f64)
+                                   (i32.lt_u
+                                    (local.get $15)
+                                    (local.tee $48
+                                     (i32.div_s
+                                      (local.get $11)
+                                      (i32.const 2)
+                                     )
+                                    )
+                                   )
+                                   (f64.const 0.5)
+                                   (select
+                                    (f64.const 1)
+                                    (f64.const 1.5)
+                                    (i32.and
+                                     (local.get $26)
+                                     (i32.eq
+                                      (local.get $15)
+                                      (local.get $48)
+                                     )
+                                    )
+                                   )
+                                  )
+                                 )
+                                 (local.set $24
+                                  (select
+                                   (f64.const 9007199254740994)
+                                   (f64.const 9007199254740992)
+                                   (i32.and
+                                    (local.get $36)
+                                    (i32.const 1)
+                                   )
+                                  )
+                                 )
+                                 (if
+                                  (local.get $27)
+                                  (if
+                                   (i32.eq
+                                    (i32.load8_s
+                                     (local.get $30)
+                                    )
+                                    (i32.const 45)
+                                   )
+                                   (block
+                                    (local.set $24
+                                     (f64.neg
+                                      (local.get $24)
+                                     )
+                                    )
+                                    (local.set $14
+                                     (f64.neg
+                                      (local.get $14)
+                                     )
+                                    )
+                                   )
+                                  )
+                                 )
+                                 (i32.store
+                                  (local.get $6)
+                                  (local.tee $8
+                                   (i32.sub
+                                    (local.get $8)
+                                    (local.get $15)
+                                   )
+                                  )
+                                 )
+                                 (br_if $do-once81
+                                  (f64.eq
+                                   (f64.add
+                                    (local.get $24)
+                                    (local.get $14)
+                                   )
+                                   (local.get $24)
+                                  )
+                                 )
+                                 (i32.store
+                                  (local.get $6)
+                                  (local.tee $7
+                                   (i32.add
+                                    (local.get $8)
+                                    (local.get $11)
+                                   )
+                                  )
+                                 )
+                                 (if
+                                  (i32.gt_u
+                                   (local.get $7)
+                                   (i32.const 999999999)
+                                  )
+                                  (loop $while-in86
+                                   (i32.store
+                                    (local.get $6)
+                                    (i32.const 0)
+                                   )
+                                   (if
+                                    (i32.lt_u
+                                     (local.tee $6
+                                      (i32.add
+                                       (local.get $6)
+                                       (i32.const -4)
+                                      )
+                                     )
+                                     (local.get $5)
+                                    )
+                                    (i32.store
+                                     (local.tee $5
+                                      (i32.add
+                                       (local.get $5)
+                                       (i32.const -4)
+                                      )
+                                     )
+                                     (i32.const 0)
+                                    )
+                                   )
+                                   (i32.store
+                                    (local.get $6)
+                                    (local.tee $7
+                                     (i32.add
+                                      (i32.load
+                                       (local.get $6)
+                                      )
+                                      (i32.const 1)
+                                     )
+                                    )
+                                   )
+                                   (br_if $while-in86
+                                    (i32.gt_u
+                                     (local.get $7)
+                                     (i32.const 999999999)
+                                    )
+                                   )
+                                  )
+                                 )
+                                 (local.set $7
+                                  (i32.mul
+                                   (i32.shr_s
+                                    (i32.sub
+                                     (local.get $20)
+                                     (local.get $5)
+                                    )
+                                    (i32.const 2)
+                                   )
+                                   (i32.const 9)
+                                  )
+                                 )
+                                 (br_if $do-once81
+                                  (i32.lt_u
+                                   (local.tee $8
+                                    (i32.load
+                                     (local.get $5)
+                                    )
+                                   )
+                                   (i32.const 10)
+                                  )
+                                 )
+                                 (local.set $11
+                                  (i32.const 10)
+                                 )
+                                 (loop $while-in88
+                                  (local.set $7
+                                   (i32.add
+                                    (local.get $7)
+                                    (i32.const 1)
+                                   )
+                                  )
+                                  (br_if $while-in88
+                                   (i32.ge_u
+                                    (local.get $8)
+                                    (local.tee $11
+                                     (i32.mul
+                                      (local.get $11)
+                                      (i32.const 10)
+                                     )
+                                    )
+                                   )
+                                  )
+                                 )
+                                )
+                               )
+                               (local.set $11
+                                (local.get $5)
+                               )
+                               (local.set $8
+                                (local.get $7)
+                               )
+                               (select
+                                (local.tee $5
+                                 (i32.add
+                                  (local.get $6)
+                                  (i32.const 4)
+                                 )
+                                )
+                                (local.get $9)
+                                (i32.gt_u
+                                 (local.get $9)
+                                 (local.get $5)
+                                )
+                               )
+                              )
+                              (block (result i32)
+                               (local.set $11
+                                (local.get $5)
+                               )
+                               (local.set $8
+                                (local.get $7)
+                               )
+                               (local.get $9)
+                              )
+                             )
+                            )
+                            (local.set $36
+                             (i32.sub
+                              (i32.const 0)
+                              (local.get $8)
+                             )
+                            )
+                            (local.set $9
+                             (loop $while-in90 (result i32)
+                              (block $while-out89 (result i32)
+                               (if
+                                (i32.le_u
+                                 (local.get $5)
+                                 (local.get $11)
+                                )
+                                (block
+                                 (local.set $26
+                                  (i32.const 0)
+                                 )
+                                 (br $while-out89
+                                  (local.get $5)
+                                 )
+                                )
+                               )
+                               (if (result i32)
+                                (i32.load
+                                 (local.tee $7
+                                  (i32.add
+                                   (local.get $5)
+                                   (i32.const -4)
+                                  )
+                                 )
+                                )
+                                (block (result i32)
+                                 (local.set $26
+                                  (i32.const 1)
+                                 )
+                                 (local.get $5)
+                                )
+                                (block
+                                 (local.set $5
+                                  (local.get $7)
+                                 )
+                                 (br $while-in90)
+                                )
+                               )
+                              )
+                             )
+                            )
+                            (call $_pad
+                             (local.get $0)
+                             (i32.const 32)
+                             (local.get $17)
+                             (local.tee $8
+                              (i32.add
+                               (i32.add
+                                (i32.add
+                                 (local.tee $5
+                                  (if (result i32)
+                                   (local.get $35)
+                                   (block $do-once91 (result i32)
+                                    (local.set $7
+                                     (if (result i32)
+                                      (i32.and
+                                       (i32.gt_s
+                                        (local.tee $5
+                                         (i32.add
+                                          (i32.xor
+                                           (local.get $31)
+                                           (i32.const 1)
+                                          )
+                                          (local.get $19)
+                                         )
+                                        )
+                                        (local.get $8)
+                                       )
+                                       (i32.gt_s
+                                        (local.get $8)
+                                        (i32.const -5)
+                                       )
+                                      )
+                                      (block (result i32)
+                                       (local.set $19
+                                        (i32.sub
+                                         (i32.add
+                                          (local.get $5)
+                                          (i32.const -1)
+                                         )
+                                         (local.get $8)
+                                        )
+                                       )
+                                       (i32.add
+                                        (local.get $16)
+                                        (i32.const -1)
+                                       )
+                                      )
+                                      (block (result i32)
+                                       (local.set $19
+                                        (i32.add
+                                         (local.get $5)
+                                         (i32.const -1)
+                                        )
+                                       )
+                                       (i32.add
+                                        (local.get $16)
+                                        (i32.const -2)
+                                       )
+                                      )
+                                     )
+                                    )
+                                    (drop
+                                     (br_if $do-once91
+                                      (local.get $19)
+                                      (local.tee $15
+                                       (i32.and
+                                        (local.get $12)
+                                        (i32.const 8)
+                                       )
+                                      )
+                                     )
+                                    )
+                                    (if
+                                     (local.get $26)
+                                     (block $do-once93
+                                      (if
+                                       (i32.eqz
+                                        (local.tee $16
+                                         (i32.load
+                                          (i32.add
+                                           (local.get $9)
+                                           (i32.const -4)
+                                          )
+                                         )
+                                        )
+                                       )
+                                       (block
+                                        (local.set $5
+                                         (i32.const 9)
+                                        )
+                                        (br $do-once93)
+                                       )
+                                      )
+                                      (local.set $5
+                                       (if (result i32)
+                                        (i32.rem_u
+                                         (local.get $16)
+                                         (i32.const 10)
+                                        )
+                                        (block
+                                         (local.set $5
+                                          (i32.const 0)
+                                         )
+                                         (br $do-once93)
+                                        )
+                                        (block (result i32)
+                                         (local.set $6
+                                          (i32.const 10)
+                                         )
+                                         (i32.const 0)
+                                        )
+                                       )
+                                      )
+                                      (loop $while-in96
+                                       (local.set $5
+                                        (i32.add
+                                         (local.get $5)
+                                         (i32.const 1)
+                                        )
+                                       )
+                                       (br_if $while-in96
+                                        (i32.eqz
+                                         (if (result i32)
+                                          (local.tee $15
+                                           (local.tee $6
+                                            (i32.mul
+                                             (local.get $6)
+                                             (i32.const 10)
+                                            )
+                                           )
+                                          )
+                                          (i32.rem_u
+                                           (local.get $16)
+                                           (local.get $15)
+                                          )
+                                          (i32.const 0)
+                                         )
+                                        )
+                                       )
+                                      )
+                                     )
+                                     (local.set $5
+                                      (i32.const 9)
+                                     )
+                                    )
+                                    (local.set $6
+                                     (i32.add
+                                      (i32.mul
+                                       (i32.shr_s
+                                        (i32.sub
+                                         (local.get $9)
+                                         (local.get $20)
+                                        )
+                                        (i32.const 2)
+                                       )
+                                       (i32.const 9)
+                                      )
+                                      (i32.const -9)
+                                     )
+                                    )
+                                    (if (result i32)
+                                     (i32.eq
+                                      (i32.or
+                                       (local.get $7)
+                                       (i32.const 32)
+                                      )
+                                      (i32.const 102)
+                                     )
+                                     (block (result i32)
+                                      (local.set $15
+                                       (i32.const 0)
+                                      )
+                                      (select
+                                       (local.get $19)
+                                       (local.tee $5
+                                        (select
+                                         (i32.const 0)
+                                         (local.tee $5
+                                          (i32.sub
+                                           (local.get $6)
+                                           (local.get $5)
+                                          )
+                                         )
+                                         (i32.lt_s
+                                          (local.get $5)
+                                          (i32.const 0)
+                                         )
+                                        )
+                                       )
+                                       (i32.lt_s
+                                        (local.get $19)
+                                        (local.get $5)
+                                       )
+                                      )
+                                     )
+                                     (block (result i32)
+                                      (local.set $15
+                                       (i32.const 0)
+                                      )
+                                      (select
+                                       (local.get $19)
+                                       (local.tee $5
+                                        (select
+                                         (i32.const 0)
+                                         (local.tee $5
+                                          (i32.sub
+                                           (i32.add
+                                            (local.get $6)
+                                            (local.get $8)
+                                           )
+                                           (local.get $5)
+                                          )
+                                         )
+                                         (i32.lt_s
+                                          (local.get $5)
+                                          (i32.const 0)
+                                         )
+                                        )
+                                       )
+                                       (i32.lt_s
+                                        (local.get $19)
+                                        (local.get $5)
+                                       )
+                                      )
+                                     )
+                                    )
+                                   )
+                                   (block (result i32)
+                                    (local.set $15
+                                     (i32.and
+                                      (local.get $12)
+                                      (i32.const 8)
+                                     )
+                                    )
+                                    (local.set $7
+                                     (local.get $16)
+                                    )
+                                    (local.get $19)
+                                   )
+                                  )
+                                 )
+                                 (i32.add
+                                  (local.get $27)
+                                  (i32.const 1)
+                                 )
+                                )
+                                (i32.ne
+                                 (local.tee $19
+                                  (i32.or
+                                   (local.get $5)
+                                   (local.get $15)
+                                  )
+                                 )
+                                 (i32.const 0)
+                                )
+                               )
+                               (if (result i32)
+                                (local.tee $31
+                                 (i32.eq
+                                  (i32.or
+                                   (local.get $7)
+                                   (i32.const 32)
+                                  )
+                                  (i32.const 102)
+                                 )
+                                )
+                                (block (result i32)
+                                 (local.set $16
+                                  (i32.const 0)
+                                 )
+                                 (select
+                                  (local.get $8)
+                                  (i32.const 0)
+                                  (i32.gt_s
+                                   (local.get $8)
+                                   (i32.const 0)
+                                  )
+                                 )
+                                )
+                                (block (result i32)
+                                 (if
+                                  (i32.lt_s
+                                   (i32.sub
+                                    (local.get $22)
+                                    (local.tee $6
+                                     (call $_fmt_u
+                                      (local.tee $6
+                                       (select
+                                        (local.get $36)
+                                        (local.get $8)
+                                        (i32.lt_s
+                                         (local.get $8)
+                                         (i32.const 0)
+                                        )
+                                       )
+                                      )
+                                      (i32.shr_s
+                                       (i32.shl
+                                        (i32.lt_s
+                                         (local.get $6)
+                                         (i32.const 0)
+                                        )
+                                        (i32.const 31)
+                                       )
+                                       (i32.const 31)
+                                      )
+                                      (local.get $22)
+                                     )
+                                    )
+                                   )
+                                   (i32.const 2)
+                                  )
+                                  (loop $while-in98
+                                   (i32.store8
+                                    (local.tee $6
+                                     (i32.add
+                                      (local.get $6)
+                                      (i32.const -1)
+                                     )
+                                    )
+                                    (i32.const 48)
+                                   )
+                                   (br_if $while-in98
+                                    (i32.lt_s
+                                     (i32.sub
+                                      (local.get $22)
+                                      (local.get $6)
+                                     )
+                                     (i32.const 2)
+                                    )
+                                   )
+                                  )
+                                 )
+                                 (i32.store8
+                                  (i32.add
+                                   (local.get $6)
+                                   (i32.const -1)
+                                  )
+                                  (i32.add
+                                   (i32.and
+                                    (i32.shr_s
+                                     (local.get $8)
+                                     (i32.const 31)
+                                    )
+                                    (i32.const 2)
+                                   )
+                                   (i32.const 43)
+                                  )
+                                 )
+                                 (i32.store8
+                                  (local.tee $16
+                                   (i32.add
+                                    (local.get $6)
+                                    (i32.const -2)
+                                   )
+                                  )
+                                  (local.get $7)
+                                 )
+                                 (i32.sub
+                                  (local.get $22)
+                                  (local.get $16)
+                                 )
+                                )
+                               )
+                              )
+                             )
+                             (local.get $12)
+                            )
+                            (if
+                             (i32.eqz
+                              (i32.and
+                               (i32.load
+                                (local.get $0)
+                               )
+                               (i32.const 32)
+                              )
+                             )
+                             (drop
+                              (call $___fwritex
+                               (local.get $30)
+                               (local.get $27)
+                               (local.get $0)
+                              )
+                             )
+                            )
+                            (call $_pad
+                             (local.get $0)
+                             (i32.const 48)
+                             (local.get $17)
+                             (local.get $8)
+                             (i32.xor
+                              (local.get $12)
+                              (i32.const 65536)
+                             )
+                            )
+                            (if
+                             (local.get $31)
+                             (block
+                              (local.set $6
+                               (local.tee $11
+                                (select
+                                 (local.get $20)
+                                 (local.get $11)
+                                 (i32.gt_u
+                                  (local.get $11)
+                                  (local.get $20)
+                                 )
+                                )
+                               )
+                              )
+                              (loop $while-in102
+                               (local.set $7
+                                (call $_fmt_u
+                                 (i32.load
+                                  (local.get $6)
+                                 )
+                                 (i32.const 0)
+                                 (local.get $29)
+                                )
+                               )
+                               (block $do-once103
+                                (if
+                                 (i32.eq
+                                  (local.get $6)
+                                  (local.get $11)
+                                 )
+                                 (block
+                                  (br_if $do-once103
+                                   (i32.ne
+                                    (local.get $7)
+                                    (local.get $29)
+                                   )
+                                  )
+                                  (i32.store8
+                                   (local.get $32)
+                                   (i32.const 48)
+                                  )
+                                  (local.set $7
+                                   (local.get $32)
+                                  )
+                                 )
+                                 (block
+                                  (br_if $do-once103
+                                   (i32.le_u
+                                    (local.get $7)
+                                    (local.get $23)
+                                   )
+                                  )
+                                  (loop $while-in106
+                                   (i32.store8
+                                    (local.tee $7
+                                     (i32.add
+                                      (local.get $7)
+                                      (i32.const -1)
+                                     )
+                                    )
+                                    (i32.const 48)
+                                   )
+                                   (br_if $while-in106
+                                    (i32.gt_u
+                                     (local.get $7)
+                                     (local.get $23)
+                                    )
+                                   )
+                                  )
+                                 )
+                                )
+                               )
+                               (if
+                                (i32.eqz
+                                 (i32.and
+                                  (i32.load
+                                   (local.get $0)
+                                  )
+                                  (i32.const 32)
+                                 )
+                                )
+                                (drop
+                                 (call $___fwritex
+                                  (local.get $7)
+                                  (i32.sub
+                                   (local.get $41)
+                                   (local.get $7)
+                                  )
+                                  (local.get $0)
+                                 )
+                                )
+                               )
+                               (if
+                                (i32.le_u
+                                 (local.tee $7
+                                  (i32.add
+                                   (local.get $6)
+                                   (i32.const 4)
+                                  )
+                                 )
+                                 (local.get $20)
+                                )
+                                (block
+                                 (local.set $6
+                                  (local.get $7)
+                                 )
+                                 (br $while-in102)
+                                )
+                               )
+                              )
+                              (if
+                               (local.get $19)
+                               (if
+                                (i32.eqz
+                                 (i32.and
+                                  (i32.load
+                                   (local.get $0)
+                                  )
+                                  (i32.const 32)
+                                 )
+                                )
+                                (drop
+                                 (call $___fwritex
+                                  (i32.const 4143)
+                                  (i32.const 1)
+                                  (local.get $0)
+                                 )
+                                )
+                               )
+                              )
+                              (call $_pad
+                               (local.get $0)
+                               (i32.const 48)
+                               (i32.add
+                                (if (result i32)
+                                 (i32.and
+                                  (i32.lt_u
+                                   (local.get $7)
+                                   (local.get $9)
+                                  )
+                                  (i32.gt_s
+                                   (local.get $5)
+                                   (i32.const 0)
+                                  )
+                                 )
+                                 (loop $while-in110 (result i32)
+                                  (if
+                                   (i32.gt_u
+                                    (local.tee $6
+                                     (call $_fmt_u
+                                      (i32.load
+                                       (local.get $7)
+                                      )
+                                      (i32.const 0)
+                                      (local.get $29)
+                                     )
+                                    )
+                                    (local.get $23)
+                                   )
+                                   (loop $while-in112
+                                    (i32.store8
+                                     (local.tee $6
+                                      (i32.add
+                                       (local.get $6)
+                                       (i32.const -1)
+                                      )
+                                     )
+                                     (i32.const 48)
+                                    )
+                                    (br_if $while-in112
+                                     (i32.gt_u
+                                      (local.get $6)
+                                      (local.get $23)
+                                     )
+                                    )
+                                   )
+                                  )
+                                  (if
+                                   (i32.eqz
+                                    (i32.and
+                                     (i32.load
+                                      (local.get $0)
+                                     )
+                                     (i32.const 32)
+                                    )
+                                   )
+                                   (drop
+                                    (call $___fwritex
+                                     (local.get $6)
+                                     (select
+                                      (i32.const 9)
+                                      (local.get $5)
+                                      (i32.gt_s
+                                       (local.get $5)
+                                       (i32.const 9)
+                                      )
+                                     )
+                                     (local.get $0)
+                                    )
+                                   )
+                                  )
+                                  (local.set $6
+                                   (i32.add
+                                    (local.get $5)
+                                    (i32.const -9)
+                                   )
+                                  )
+                                  (if (result i32)
+                                   (i32.and
+                                    (i32.lt_u
+                                     (local.tee $7
+                                      (i32.add
+                                       (local.get $7)
+                                       (i32.const 4)
+                                      )
+                                     )
+                                     (local.get $9)
+                                    )
+                                    (i32.gt_s
+                                     (local.get $5)
+                                     (i32.const 9)
+                                    )
+                                   )
+                                   (block
+                                    (local.set $5
+                                     (local.get $6)
+                                    )
+                                    (br $while-in110)
+                                   )
+                                   (local.get $6)
+                                  )
+                                 )
+                                 (local.get $5)
+                                )
+                                (i32.const 9)
+                               )
+                               (i32.const 9)
+                               (i32.const 0)
+                              )
+                             )
+                             (block $do-once99
+                              (local.set $20
+                               (select
+                                (local.get $9)
+                                (i32.add
+                                 (local.get $11)
+                                 (i32.const 4)
+                                )
+                                (local.get $26)
+                               )
+                              )
+                              (call $_pad
+                               (local.get $0)
+                               (i32.const 48)
+                               (i32.add
+                                (if (result i32)
+                                 (i32.gt_s
+                                  (local.get $5)
+                                  (i32.const -1)
+                                 )
+                                 (block (result i32)
+                                  (local.set $15
+                                   (i32.eqz
+                                    (local.get $15)
+                                   )
+                                  )
+                                  (local.set $6
+                                   (local.get $11)
+                                  )
+                                  (local.set $7
+                                   (local.get $5)
+                                  )
+                                  (loop $while-in114 (result i32)
+                                   (if
+                                    (i32.eq
+                                     (local.tee $5
+                                      (call $_fmt_u
+                                       (i32.load
+                                        (local.get $6)
+                                       )
+                                       (i32.const 0)
+                                       (local.get $29)
+                                      )
+                                     )
+                                     (local.get $29)
+                                    )
+                                    (block
+                                     (i32.store8
+                                      (local.get $32)
+                                      (i32.const 48)
+                                     )
+                                     (local.set $5
+                                      (local.get $32)
+                                     )
+                                    )
+                                   )
+                                   (block $do-once115
+                                    (if
+                                     (i32.eq
+                                      (local.get $6)
+                                      (local.get $11)
+                                     )
+                                     (block
+                                      (if
+                                       (i32.eqz
+                                        (i32.and
+                                         (i32.load
+                                          (local.get $0)
+                                         )
+                                         (i32.const 32)
+                                        )
+                                       )
+                                       (drop
+                                        (call $___fwritex
+                                         (local.get $5)
+                                         (i32.const 1)
+                                         (local.get $0)
+                                        )
+                                       )
+                                      )
+                                      (local.set $5
+                                       (i32.add
+                                        (local.get $5)
+                                        (i32.const 1)
+                                       )
+                                      )
+                                      (br_if $do-once115
+                                       (i32.and
+                                        (local.get $15)
+                                        (i32.lt_s
+                                         (local.get $7)
+                                         (i32.const 1)
+                                        )
+                                       )
+                                      )
+                                      (br_if $do-once115
+                                       (i32.and
+                                        (i32.load
+                                         (local.get $0)
+                                        )
+                                        (i32.const 32)
+                                       )
+                                      )
+                                      (drop
+                                       (call $___fwritex
+                                        (i32.const 4143)
+                                        (i32.const 1)
+                                        (local.get $0)
+                                       )
+                                      )
+                                     )
+                                     (block
+                                      (br_if $do-once115
+                                       (i32.le_u
+                                        (local.get $5)
+                                        (local.get $23)
+                                       )
+                                      )
+                                      (loop $while-in118
+                                       (i32.store8
+                                        (local.tee $5
+                                         (i32.add
+                                          (local.get $5)
+                                          (i32.const -1)
+                                         )
+                                        )
+                                        (i32.const 48)
+                                       )
+                                       (br_if $while-in118
+                                        (i32.gt_u
+                                         (local.get $5)
+                                         (local.get $23)
+                                        )
+                                       )
+                                      )
+                                     )
+                                    )
+                                   )
+                                   (local.set $9
+                                    (i32.sub
+                                     (local.get $41)
+                                     (local.get $5)
+                                    )
+                                   )
+                                   (if
+                                    (i32.eqz
+                                     (i32.and
+                                      (i32.load
+                                       (local.get $0)
+                                      )
+                                      (i32.const 32)
+                                     )
+                                    )
+                                    (drop
+                                     (call $___fwritex
+                                      (local.get $5)
+                                      (select
+                                       (local.get $9)
+                                       (local.get $7)
+                                       (i32.gt_s
+                                        (local.get $7)
+                                        (local.get $9)
+                                       )
+                                      )
+                                      (local.get $0)
+                                     )
+                                    )
+                                   )
+                                   (br_if $while-in114
+                                    (i32.and
+                                     (i32.lt_u
+                                      (local.tee $6
+                                       (i32.add
+                                        (local.get $6)
+                                        (i32.const 4)
+                                       )
+                                      )
+                                      (local.get $20)
+                                     )
+                                     (i32.gt_s
+                                      (local.tee $7
+                                       (i32.sub
+                                        (local.get $7)
+                                        (local.get $9)
+                                       )
+                                      )
+                                      (i32.const -1)
+                                     )
+                                    )
+                                   )
+                                   (local.get $7)
+                                  )
+                                 )
+                                 (local.get $5)
+                                )
+                                (i32.const 18)
+                               )
+                               (i32.const 18)
+                               (i32.const 0)
+                              )
+                              (br_if $do-once99
+                               (i32.and
+                                (i32.load
+                                 (local.get $0)
+                                )
+                                (i32.const 32)
+                               )
+                              )
+                              (drop
+                               (call $___fwritex
+                                (local.get $16)
+                                (i32.sub
+                                 (local.get $22)
+                                 (local.get $16)
+                                )
+                                (local.get $0)
+                               )
+                              )
+                             )
+                            )
+                            (call $_pad
+                             (local.get $0)
+                             (i32.const 32)
+                             (local.get $17)
+                             (local.get $8)
+                             (i32.xor
+                              (local.get $12)
+                              (i32.const 8192)
+                             )
+                            )
+                            (select
+                             (local.get $17)
+                             (local.get $8)
+                             (i32.lt_s
+                              (local.get $8)
+                              (local.get $17)
+                             )
+                            )
+                           )
+                           (block (result i32)
+                            (call $_pad
+                             (local.get $0)
+                             (i32.const 32)
+                             (local.get $17)
+                             (local.tee $7
+                              (i32.add
+                               (local.tee $9
+                                (select
+                                 (i32.const 0)
+                                 (local.get $27)
+                                 (local.tee $6
+                                  (f64.ne
+                                   (local.get $14)
+                                   (local.get $14)
+                                  )
+                                 )
+                                )
+                               )
+                               (i32.const 3)
+                              )
+                             )
+                             (local.get $8)
+                            )
+                            (local.set $6
+                             (select
+                              (select
+                               (i32.const 4135)
+                               (i32.const 4139)
+                               (local.tee $8
+                                (i32.ne
+                                 (i32.and
+                                  (local.get $16)
+                                  (i32.const 32)
+                                 )
+                                 (i32.const 0)
+                                )
+                               )
+                              )
+                              (select
+                               (i32.const 4127)
+                               (i32.const 4131)
+                               (local.get $8)
+                              )
+                              (local.get $6)
+                             )
+                            )
+                            (if
+                             (i32.eqz
+                              (i32.and
+                               (if (result i32)
+                                (i32.and
+                                 (local.tee $5
+                                  (i32.load
+                                   (local.get $0)
+                                  )
+                                 )
+                                 (i32.const 32)
+                                )
+                                (local.get $5)
+                                (block (result i32)
+                                 (drop
+                                  (call $___fwritex
+                                   (local.get $30)
+                                   (local.get $9)
+                                   (local.get $0)
+                                  )
+                                 )
+                                 (i32.load
+                                  (local.get $0)
+                                 )
+                                )
+                               )
+                               (i32.const 32)
+                              )
+                             )
+                             (drop
+                              (call $___fwritex
+                               (local.get $6)
+                               (i32.const 3)
+                               (local.get $0)
+                              )
+                             )
+                            )
+                            (call $_pad
+                             (local.get $0)
+                             (i32.const 32)
+                             (local.get $17)
+                             (local.get $7)
+                             (i32.xor
+                              (local.get $12)
+                              (i32.const 8192)
+                             )
+                            )
+                            (select
+                             (local.get $17)
+                             (local.get $7)
+                             (i32.lt_s
+                              (local.get $7)
+                              (local.get $17)
+                             )
+                            )
+                           )
+                          )
+                         )
+                         (local.set $5
+                          (local.get $10)
+                         )
+                         (local.set $10
+                          (local.get $7)
+                         )
+                         (br $label$continue$L1)
+                        )
+                        (local.set $7
+                         (local.get $5)
+                        )
+                        (local.set $11
+                         (local.get $6)
+                        )
+                        (local.set $8
+                         (i32.const 0)
+                        )
+                        (local.set $9
+                         (i32.const 4091)
+                        )
+                        (br $__rjto$8
+                         (local.get $25)
+                        )
+                       )
+                       (local.set $9
+                        (i32.and
+                         (local.get $16)
+                         (i32.const 32)
+                        )
+                       )
+                       (if
+                        (i32.or
+                         (local.tee $5
+                          (i32.load
+                           (local.get $13)
+                          )
+                         )
+                         (local.tee $12
+                          (i32.load offset=4
+                           (local.get $13)
+                          )
+                         )
+                        )
+                        (block
+                         (local.set $8
+                          (local.get $25)
+                         )
+                         (local.set $5
+                          (loop $while-in123 (result i32)
+                           (i32.store8
+                            (local.tee $8
+                             (i32.add
+                              (local.get $8)
+                              (i32.const -1)
+                             )
+                            )
+                            (i32.or
+                             (i32.load8_u
+                              (i32.add
+                               (i32.and
+                                (local.get $5)
+                                (i32.const 15)
+                               )
+                               (i32.const 4075)
+                              )
+                             )
+                             (local.get $9)
+                            )
+                           )
+                           (br_if $while-in123
+                            (i32.or
+                             (local.tee $5
+                              (call $_bitshift64Lshr
+                               (local.get $5)
+                               (local.get $12)
+                               (i32.const 4)
+                              )
+                             )
+                             (local.tee $12
+                              (global.get $tempRet0)
+                             )
+                            )
+                           )
+                           (local.get $8)
+                          )
+                         )
+                         (local.set $8
+                          (if (result i32)
+                           (i32.or
+                            (i32.eqz
+                             (i32.and
+                              (local.get $7)
+                              (i32.const 8)
+                             )
+                            )
+                            (i32.eqz
+                             (i32.or
+                              (i32.load
+                               (local.get $13)
+                              )
+                              (i32.load offset=4
+                               (local.get $13)
+                              )
+                             )
+                            )
+                           )
+                           (block (result i32)
+                            (local.set $9
+                             (i32.const 4091)
+                            )
+                            (i32.const 0)
+                           )
+                           (block (result i32)
+                            (local.set $9
+                             (i32.add
+                              (i32.shr_s
+                               (local.get $16)
+                               (i32.const 4)
+                              )
+                              (i32.const 4091)
+                             )
+                            )
+                            (i32.const 2)
+                           )
+                          )
+                         )
+                        )
+                        (block
+                         (local.set $5
+                          (local.get $25)
+                         )
+                         (local.set $8
+                          (i32.const 0)
+                         )
+                         (local.set $9
+                          (i32.const 4091)
+                         )
+                        )
+                       )
+                       (br $__rjti$8)
+                      )
+                      (local.set $5
+                       (call $_fmt_u
+                        (local.get $5)
+                        (local.get $7)
+                        (local.get $25)
+                       )
+                      )
+                      (local.set $7
+                       (local.get $12)
+                      )
+                      (br $__rjti$8)
+                     )
+                     (local.set $15
+                      (i32.eqz
+                       (local.tee $16
+                        (call $_memchr
+                         (local.get $5)
+                         (i32.const 0)
+                         (local.get $6)
+                        )
+                       )
+                      )
+                     )
+                     (local.set $12
+                      (local.get $8)
+                     )
+                     (local.set $11
+                      (select
+                       (local.get $6)
+                       (i32.sub
+                        (local.get $16)
+                        (local.tee $7
+                         (local.get $5)
+                        )
+                       )
+                       (local.get $15)
+                      )
+                     )
+                     (local.set $8
+                      (i32.const 0)
+                     )
+                     (local.set $9
+                      (i32.const 4091)
+                     )
+                     (br $__rjto$8
+                      (select
+                       (i32.add
+                        (local.get $5)
+                        (local.get $6)
+                       )
+                       (local.get $16)
+                       (local.get $15)
+                      )
+                     )
+                    )
+                    (local.set $5
+                     (i32.const 0)
+                    )
+                    (local.set $7
+                     (i32.const 0)
+                    )
+                    (local.set $6
+                     (i32.load
+                      (local.get $13)
+                     )
+                    )
+                    (loop $while-in125
+                     (block $while-out124
+                      (br_if $while-out124
+                       (i32.eqz
+                        (local.tee $9
+                         (i32.load
+                          (local.get $6)
+                         )
+                        )
+                       )
+                      )
+                      (br_if $while-out124
+                       (i32.or
+                        (i32.lt_s
+                         (local.tee $7
+                          (call $_wctomb
+                           (local.get $33)
+                           (local.get $9)
+                          )
+                         )
+                         (i32.const 0)
+                        )
+                        (i32.gt_u
+                         (local.get $7)
+                         (i32.sub
+                          (local.get $8)
+                          (local.get $5)
+                         )
+                        )
+                       )
+                      )
+                      (local.set $6
+                       (i32.add
+                        (local.get $6)
+                        (i32.const 4)
+                       )
+                      )
+                      (br_if $while-in125
+                       (i32.gt_u
+                        (local.get $8)
+                        (local.tee $5
+                         (i32.add
+                          (local.get $5)
+                          (local.get $7)
+                         )
+                        )
+                       )
+                      )
+                     )
+                    )
+                    (if
+                     (i32.lt_s
+                      (local.get $7)
+                      (i32.const 0)
+                     )
+                     (block
+                      (local.set $18
+                       (i32.const -1)
+                      )
+                      (br $label$break$L1)
+                     )
+                    )
+                    (call $_pad
+                     (local.get $0)
+                     (i32.const 32)
+                     (local.get $17)
+                     (local.get $5)
+                     (local.get $12)
+                    )
+                    (if (result i32)
+                     (local.get $5)
+                     (block (result i32)
+                      (local.set $6
+                       (i32.const 0)
+                      )
+                      (local.set $7
+                       (i32.load
+                        (local.get $13)
+                       )
+                      )
+                      (loop $while-in127 (result i32)
+                       (drop
+                        (br_if $__rjti$7
+                         (local.get $5)
+                         (i32.eqz
+                          (local.tee $8
+                           (i32.load
+                            (local.get $7)
+                           )
+                          )
+                         )
+                        )
+                       )
+                       (drop
+                        (br_if $__rjti$7
+                         (local.get $5)
+                         (i32.gt_s
+                          (local.tee $6
+                           (i32.add
+                            (local.tee $8
+                             (call $_wctomb
+                              (local.get $33)
+                              (local.get $8)
+                             )
+                            )
+                            (local.get $6)
+                           )
+                          )
+                          (local.get $5)
+                         )
+                        )
+                       )
+                       (if
+                        (i32.eqz
+                         (i32.and
+                          (i32.load
+                           (local.get $0)
+                          )
+                          (i32.const 32)
+                         )
+                        )
+                        (drop
+                         (call $___fwritex
+                          (local.get $33)
+                          (local.get $8)
+                          (local.get $0)
+                         )
+                        )
+                       )
+                       (local.set $7
+                        (i32.add
+                         (local.get $7)
+                         (i32.const 4)
+                        )
+                       )
+                       (br_if $while-in127
+                        (i32.lt_u
+                         (local.get $6)
+                         (local.get $5)
+                        )
+                       )
+                       (local.get $5)
+                      )
+                     )
+                     (i32.const 0)
+                    )
+                   )
+                  )
+                  (i32.xor
+                   (local.get $12)
+                   (i32.const 8192)
+                  )
+                 )
+                 (local.set $5
+                  (local.get $10)
+                 )
+                 (local.set $10
+                  (select
+                   (local.get $17)
+                   (local.get $7)
+                   (i32.gt_s
+                    (local.get $17)
+                    (local.get $7)
+                   )
+                  )
+                 )
+                 (br $label$continue$L1)
+                )
+                (local.set $12
+                 (select
+                  (i32.and
+                   (local.get $7)
+                   (i32.const -65537)
+                  )
+                  (local.get $7)
+                  (i32.gt_s
+                   (local.get $6)
+                   (i32.const -1)
+                  )
+                 )
+                )
+                (local.set $11
+                 (if (result i32)
+                  (i32.or
+                   (local.get $6)
+                   (local.tee $11
+                    (i32.or
+                     (i32.ne
+                      (i32.load
+                       (local.get $13)
+                      )
+                      (i32.const 0)
+                     )
+                     (i32.ne
+                      (i32.load offset=4
+                       (local.get $13)
+                      )
+                      (i32.const 0)
+                     )
+                    )
+                   )
+                  )
+                  (select
+                   (local.get $6)
+                   (local.tee $5
+                    (i32.add
+                     (i32.sub
+                      (local.get $37)
+                      (local.tee $7
+                       (local.get $5)
+                      )
+                     )
+                     (i32.xor
+                      (local.get $11)
+                      (i32.const 1)
+                     )
+                    )
+                   )
+                   (i32.gt_s
+                    (local.get $6)
+                    (local.get $5)
+                   )
+                  )
+                  (block (result i32)
+                   (local.set $7
+                    (local.get $25)
+                   )
+                   (i32.const 0)
+                  )
+                 )
+                )
+                (local.get $25)
+               )
+               (local.get $7)
+              )
+             )
+             (local.get $11)
+             (i32.lt_s
+              (local.get $11)
+              (local.get $16)
+             )
+            )
+           )
+           (local.get $8)
+          )
+         )
+         (local.get $17)
+         (i32.lt_s
+          (local.get $17)
+          (local.get $5)
+         )
+        )
+       )
+       (local.get $5)
+       (local.get $12)
+      )
+      (if
+       (i32.eqz
+        (i32.and
+         (i32.load
+          (local.get $0)
+         )
+         (i32.const 32)
+        )
+       )
+       (drop
+        (call $___fwritex
+         (local.get $9)
+         (local.get $8)
+         (local.get $0)
+        )
+       )
+      )
+      (call $_pad
+       (local.get $0)
+       (i32.const 48)
+       (local.get $6)
+       (local.get $5)
+       (i32.xor
+        (local.get $12)
+        (i32.const 65536)
+       )
+      )
+      (call $_pad
+       (local.get $0)
+       (i32.const 48)
+       (local.get $11)
+       (local.get $16)
+       (i32.const 0)
+      )
+      (if
+       (i32.eqz
+        (i32.and
+         (i32.load
+          (local.get $0)
+         )
+         (i32.const 32)
+        )
+       )
+       (drop
+        (call $___fwritex
+         (local.get $7)
+         (local.get $16)
+         (local.get $0)
+        )
+       )
+      )
+      (call $_pad
+       (local.get $0)
+       (i32.const 32)
+       (local.get $6)
+       (local.get $5)
+       (i32.xor
+        (local.get $12)
+        (i32.const 8192)
+       )
+      )
+      (local.set $5
+       (local.get $10)
+      )
+      (local.set $10
+       (local.get $6)
+      )
+      (br $label$continue$L1)
+     )
+    )
+    (br $label$break$L343)
+   )
+   (if
+    (i32.eqz
+     (local.get $0)
+    )
+    (local.set $18
+     (if (result i32)
+      (local.get $1)
+      (block (result i32)
+       (local.set $0
+        (i32.const 1)
+       )
+       (loop $while-in130
+        (if
+         (local.tee $1
+          (i32.load
+           (i32.add
+            (local.get $4)
+            (i32.shl
+             (local.get $0)
+             (i32.const 2)
+            )
+           )
+          )
+         )
+         (block
+          (call $_pop_arg_336
+           (i32.add
+            (local.get $3)
+            (i32.shl
+             (local.get $0)
+             (i32.const 3)
+            )
+           )
+           (local.get $1)
+           (local.get $2)
+          )
+          (br_if $while-in130
+           (i32.lt_s
+            (local.tee $0
+             (i32.add
+              (local.get $0)
+              (i32.const 1)
+             )
+            )
+            (i32.const 10)
+           )
+          )
+          (local.set $18
+           (i32.const 1)
+          )
+          (br $label$break$L343)
+         )
+        )
+       )
+       (if (result i32)
+        (i32.lt_s
+         (local.get $0)
+         (i32.const 10)
+        )
+        (loop $while-in132 (result i32)
+         (if
+          (i32.load
+           (i32.add
+            (local.get $4)
+            (i32.shl
+             (local.get $0)
+             (i32.const 2)
+            )
+           )
+          )
+          (block
+           (local.set $18
+            (i32.const -1)
+           )
+           (br $label$break$L343)
+          )
+         )
+         (br_if $while-in132
+          (i32.lt_s
+           (local.tee $0
+            (i32.add
+             (local.get $0)
+             (i32.const 1)
+            )
+           )
+           (i32.const 10)
+          )
+         )
+         (i32.const 1)
+        )
+        (i32.const 1)
+       )
+      )
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $13)
+  )
+  (local.get $18)
+ )
+ (func $_pop_arg_336 (param $0 i32) (param $1 i32) (param $2 i32)
+  (local $3 i32)
+  (local $4 f64)
+  (local $5 i32)
+  (block $label$break$L1
+   (if
+    (i32.le_u
+     (local.get $1)
+     (i32.const 20)
+    )
+    (block $switch-default
+     (block $switch-case9
+      (block $switch-case8
+       (block $switch-case7
+        (block $switch-case6
+         (block $switch-case5
+          (block $switch-case4
+           (block $switch-case3
+            (block $switch-case2
+             (block $switch-case1
+              (block $switch-case
+               (br_table $switch-case $switch-case1 $switch-case2 $switch-case3 $switch-case4 $switch-case5 $switch-case6 $switch-case7 $switch-case8 $switch-case9 $switch-default
+                (i32.sub
+                 (local.get $1)
+                 (i32.const 9)
+                )
+               )
+              )
+              (local.set $3
+               (i32.load
+                (local.tee $1
+                 (i32.and
+                  (i32.add
+                   (i32.load
+                    (local.get $2)
+                   )
+                   (i32.const 3)
+                  )
+                  (i32.const -4)
+                 )
+                )
+               )
+              )
+              (i32.store
+               (local.get $2)
+               (i32.add
+                (local.get $1)
+                (i32.const 4)
+               )
+              )
+              (i32.store
+               (local.get $0)
+               (local.get $3)
+              )
+              (br $label$break$L1)
+             )
+             (local.set $1
+              (i32.load
+               (local.tee $3
+                (i32.and
+                 (i32.add
+                  (i32.load
+                   (local.get $2)
+                  )
+                  (i32.const 3)
+                 )
+                 (i32.const -4)
+                )
+               )
+              )
+             )
+             (i32.store
+              (local.get $2)
+              (i32.add
+               (local.get $3)
+               (i32.const 4)
+              )
+             )
+             (i32.store
+              (local.get $0)
+              (local.get $1)
+             )
+             (i32.store offset=4
+              (local.get $0)
+              (i32.shr_s
+               (i32.shl
+                (i32.lt_s
+                 (local.get $1)
+                 (i32.const 0)
+                )
+                (i32.const 31)
+               )
+               (i32.const 31)
+              )
+             )
+             (br $label$break$L1)
+            )
+            (local.set $3
+             (i32.load
+              (local.tee $1
+               (i32.and
+                (i32.add
+                 (i32.load
+                  (local.get $2)
+                 )
+                 (i32.const 3)
+                )
+                (i32.const -4)
+               )
+              )
+             )
+            )
+            (i32.store
+             (local.get $2)
+             (i32.add
+              (local.get $1)
+              (i32.const 4)
+             )
+            )
+            (i32.store
+             (local.get $0)
+             (local.get $3)
+            )
+            (i32.store offset=4
+             (local.get $0)
+             (i32.const 0)
+            )
+            (br $label$break$L1)
+           )
+           (local.set $5
+            (i32.load
+             (local.tee $3
+              (local.tee $1
+               (i32.and
+                (i32.add
+                 (i32.load
+                  (local.get $2)
+                 )
+                 (i32.const 7)
+                )
+                (i32.const -8)
+               )
+              )
+             )
+            )
+           )
+           (local.set $3
+            (i32.load offset=4
+             (local.get $3)
+            )
+           )
+           (i32.store
+            (local.get $2)
+            (i32.add
+             (local.get $1)
+             (i32.const 8)
+            )
+           )
+           (i32.store
+            (local.get $0)
+            (local.get $5)
+           )
+           (i32.store offset=4
+            (local.get $0)
+            (local.get $3)
+           )
+           (br $label$break$L1)
+          )
+          (local.set $3
+           (i32.load
+            (local.tee $1
+             (i32.and
+              (i32.add
+               (i32.load
+                (local.get $2)
+               )
+               (i32.const 3)
+              )
+              (i32.const -4)
+             )
+            )
+           )
+          )
+          (i32.store
+           (local.get $2)
+           (i32.add
+            (local.get $1)
+            (i32.const 4)
+           )
+          )
+          (i32.store
+           (local.get $0)
+           (local.tee $1
+            (i32.shr_s
+             (i32.shl
+              (i32.and
+               (local.get $3)
+               (i32.const 65535)
+              )
+              (i32.const 16)
+             )
+             (i32.const 16)
+            )
+           )
+          )
+          (i32.store offset=4
+           (local.get $0)
+           (i32.shr_s
+            (i32.shl
+             (i32.lt_s
+              (local.get $1)
+              (i32.const 0)
+             )
+             (i32.const 31)
+            )
+            (i32.const 31)
+           )
+          )
+          (br $label$break$L1)
+         )
+         (local.set $3
+          (i32.load
+           (local.tee $1
+            (i32.and
+             (i32.add
+              (i32.load
+               (local.get $2)
+              )
+              (i32.const 3)
+             )
+             (i32.const -4)
+            )
+           )
+          )
+         )
+         (i32.store
+          (local.get $2)
+          (i32.add
+           (local.get $1)
+           (i32.const 4)
+          )
+         )
+         (i32.store
+          (local.get $0)
+          (i32.and
+           (local.get $3)
+           (i32.const 65535)
+          )
+         )
+         (i32.store offset=4
+          (local.get $0)
+          (i32.const 0)
+         )
+         (br $label$break$L1)
+        )
+        (local.set $3
+         (i32.load
+          (local.tee $1
+           (i32.and
+            (i32.add
+             (i32.load
+              (local.get $2)
+             )
+             (i32.const 3)
+            )
+            (i32.const -4)
+           )
+          )
+         )
+        )
+        (i32.store
+         (local.get $2)
+         (i32.add
+          (local.get $1)
+          (i32.const 4)
+         )
+        )
+        (i32.store
+         (local.get $0)
+         (local.tee $1
+          (i32.shr_s
+           (i32.shl
+            (i32.and
+             (local.get $3)
+             (i32.const 255)
+            )
+            (i32.const 24)
+           )
+           (i32.const 24)
+          )
+         )
+        )
+        (i32.store offset=4
+         (local.get $0)
+         (i32.shr_s
+          (i32.shl
+           (i32.lt_s
+            (local.get $1)
+            (i32.const 0)
+           )
+           (i32.const 31)
+          )
+          (i32.const 31)
+         )
+        )
+        (br $label$break$L1)
+       )
+       (local.set $3
+        (i32.load
+         (local.tee $1
+          (i32.and
+           (i32.add
+            (i32.load
+             (local.get $2)
+            )
+            (i32.const 3)
+           )
+           (i32.const -4)
+          )
+         )
+        )
+       )
+       (i32.store
+        (local.get $2)
+        (i32.add
+         (local.get $1)
+         (i32.const 4)
+        )
+       )
+       (i32.store
+        (local.get $0)
+        (i32.and
+         (local.get $3)
+         (i32.const 255)
+        )
+       )
+       (i32.store offset=4
+        (local.get $0)
+        (i32.const 0)
+       )
+       (br $label$break$L1)
+      )
+      (local.set $4
+       (f64.load
+        (local.tee $1
+         (i32.and
+          (i32.add
+           (i32.load
+            (local.get $2)
+           )
+           (i32.const 7)
+          )
+          (i32.const -8)
+         )
+        )
+       )
+      )
+      (i32.store
+       (local.get $2)
+       (i32.add
+        (local.get $1)
+        (i32.const 8)
+       )
+      )
+      (f64.store
+       (local.get $0)
+       (local.get $4)
+      )
+      (br $label$break$L1)
+     )
+     (local.set $4
+      (f64.load
+       (local.tee $1
+        (i32.and
+         (i32.add
+          (i32.load
+           (local.get $2)
+          )
+          (i32.const 7)
+         )
+         (i32.const -8)
+        )
+       )
+      )
+     )
+     (i32.store
+      (local.get $2)
+      (i32.add
+       (local.get $1)
+       (i32.const 8)
+      )
+     )
+     (f64.store
+      (local.get $0)
+      (local.get $4)
+     )
+    )
+   )
+  )
+ )
+ (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)
+   )
+   (loop $while-in
+    (i32.store8
+     (local.tee $2
+      (i32.add
+       (local.get $2)
+       (i32.const -1)
+      )
+     )
+     (i32.or
+      (call $___uremdi3
+       (local.get $0)
+       (local.get $1)
+       (i32.const 10)
+       (i32.const 0)
+      )
+      (i32.const 48)
+     )
+    )
+    (local.set $0
+     (call $___udivdi3
+      (local.get $0)
+      (local.get $1)
+      (i32.const 10)
+      (i32.const 0)
+     )
+    )
+    (local.set $3
+     (global.get $tempRet0)
+    )
+    (if
+     (i32.gt_u
+      (local.get $1)
+      (i32.const 9)
+     )
+     (block
+      (local.set $1
+       (local.get $3)
+      )
+      (br $while-in)
+     )
+    )
+   )
+  )
+  (if
+   (local.get $0)
+   (loop $while-in1
+    (i32.store8
+     (local.tee $2
+      (i32.add
+       (local.get $2)
+       (i32.const -1)
+      )
+     )
+     (i32.or
+      (i32.rem_u
+       (local.get $0)
+       (i32.const 10)
+      )
+      (i32.const 48)
+     )
+    )
+    (local.set $0
+     (i32.div_u
+      (local.tee $1
+       (local.get $0)
+      )
+      (i32.const 10)
+     )
+    )
+    (br_if $while-in1
+     (i32.ge_u
+      (local.get $1)
+      (i32.const 10)
+     )
+    )
+   )
+  )
+  (local.get $2)
+ )
+ (func $_pad (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local.set $7
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 256)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (local.set $6
+   (local.get $7)
+  )
+  (block $do-once
+   (if
+    (i32.and
+     (i32.gt_s
+      (local.get $2)
+      (local.get $3)
+     )
+     (i32.eqz
+      (i32.and
+       (local.get $4)
+       (i32.const 73728)
+      )
+     )
+    )
+    (block $block
+     (drop
+      (call $_memset
+       (local.get $6)
+       (local.get $1)
+       (select
+        (i32.const 256)
+        (local.tee $5
+         (i32.sub
+          (local.get $2)
+          (local.get $3)
+         )
+        )
+        (i32.gt_u
+         (local.get $5)
+         (i32.const 256)
+        )
+       )
+      )
+     )
+     (local.set $4
+      (i32.eqz
+       (i32.and
+        (local.tee $1
+         (i32.load
+          (local.get $0)
+         )
+        )
+        (i32.const 32)
+       )
+      )
+     )
+     (if
+      (i32.gt_u
+       (local.get $5)
+       (i32.const 255)
+      )
+      (block $block271
+       (loop $while-in
+        (if
+         (local.get $4)
+         (block $block273
+          (drop
+           (call $___fwritex
+            (local.get $6)
+            (i32.const 256)
+            (local.get $0)
+           )
+          )
+          (local.set $1
+           (i32.load
+            (local.get $0)
+           )
+          )
+         )
+        )
+        (local.set $4
+         (i32.eqz
+          (i32.and
+           (local.get $1)
+           (i32.const 32)
+          )
+         )
+        )
+        (br_if $while-in
+         (i32.gt_u
+          (local.tee $5
+           (i32.add
+            (local.get $5)
+            (i32.const -256)
+           )
+          )
+          (i32.const 255)
+         )
+        )
+       )
+       (br_if $do-once
+        (i32.eqz
+         (local.get $4)
+        )
+       )
+       (local.set $5
+        (i32.and
+         (i32.sub
+          (local.get $2)
+          (local.get $3)
+         )
+         (i32.const 255)
+        )
+       )
+      )
+      (br_if $do-once
+       (i32.eqz
+        (local.get $4)
+       )
+      )
+     )
+     (drop
+      (call $___fwritex
+       (local.get $6)
+       (local.get $5)
+       (local.get $0)
+      )
+     )
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $7)
+  )
+ )
+ (func $_malloc (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (block $folding-inner0
+   (block $do-once
+    (if
+     (i32.lt_u
+      (local.get $0)
+      (i32.const 245)
+     )
+     (block $block
+      (if
+       (i32.and
+        (local.tee $5
+         (i32.shr_u
+          (local.tee $11
+           (i32.load
+            (i32.const 176)
+           )
+          )
+          (local.tee $13
+           (i32.shr_u
+            (local.tee $4
+             (select
+              (i32.const 16)
+              (i32.and
+               (i32.add
+                (local.get $0)
+                (i32.const 11)
+               )
+               (i32.const -8)
+              )
+              (i32.lt_u
+               (local.get $0)
+               (i32.const 11)
+              )
+             )
+            )
+            (i32.const 3)
+           )
+          )
+         )
+        )
+        (i32.const 3)
+       )
+       (block $block275
+        (local.set $10
+         (i32.load
+          (local.tee $1
+           (i32.add
+            (local.tee $7
+             (i32.load
+              (local.tee $3
+               (i32.add
+                (local.tee $2
+                 (i32.add
+                  (i32.shl
+                   (local.tee $4
+                    (i32.add
+                     (i32.xor
+                      (i32.and
+                       (local.get $5)
+                       (i32.const 1)
+                      )
+                      (i32.const 1)
+                     )
+                     (local.get $13)
+                    )
+                   )
+                   (i32.const 3)
+                  )
+                  (i32.const 216)
+                 )
+                )
+                (i32.const 8)
+               )
+              )
+             )
+            )
+            (i32.const 8)
+           )
+          )
+         )
+        )
+        (if
+         (i32.eq
+          (local.get $2)
+          (local.get $10)
+         )
+         (i32.store
+          (i32.const 176)
+          (i32.and
+           (local.get $11)
+           (i32.xor
+            (i32.shl
+             (i32.const 1)
+             (local.get $4)
+            )
+            (i32.const -1)
+           )
+          )
+         )
+         (block $block277
+          (if
+           (i32.lt_u
+            (local.get $10)
+            (i32.load
+             (i32.const 192)
+            )
+           )
+           (call $_abort)
+          )
+          (if
+           (i32.eq
+            (i32.load
+             (local.tee $0
+              (i32.add
+               (local.get $10)
+               (i32.const 12)
+              )
+             )
+            )
+            (local.get $7)
+           )
+           (block $block280
+            (i32.store
+             (local.get $0)
+             (local.get $2)
+            )
+            (i32.store
+             (local.get $3)
+             (local.get $10)
+            )
+           )
+           (call $_abort)
+          )
+         )
+        )
+        (i32.store offset=4
+         (local.get $7)
+         (i32.or
+          (local.tee $0
+           (i32.shl
+            (local.get $4)
+            (i32.const 3)
+           )
+          )
+          (i32.const 3)
+         )
+        )
+        (i32.store
+         (local.tee $0
+          (i32.add
+           (i32.add
+            (local.get $7)
+            (local.get $0)
+           )
+           (i32.const 4)
+          )
+         )
+         (i32.or
+          (i32.load
+           (local.get $0)
+          )
+          (i32.const 1)
+         )
+        )
+        (return
+         (local.get $1)
+        )
+       )
+      )
+      (if
+       (i32.gt_u
+        (local.get $4)
+        (local.tee $0
+         (i32.load
+          (i32.const 184)
+         )
+        )
+       )
+       (block $block282
+        (if
+         (local.get $5)
+         (block $block284
+          (local.set $10
+           (i32.and
+            (i32.shr_u
+             (local.tee $3
+              (i32.add
+               (i32.and
+                (local.tee $3
+                 (i32.and
+                  (i32.shl
+                   (local.get $5)
+                   (local.get $13)
+                  )
+                  (i32.or
+                   (local.tee $3
+                    (i32.shl
+                     (i32.const 2)
+                     (local.get $13)
+                    )
+                   )
+                   (i32.sub
+                    (i32.const 0)
+                    (local.get $3)
+                   )
+                  )
+                 )
+                )
+                (i32.sub
+                 (i32.const 0)
+                 (local.get $3)
+                )
+               )
+               (i32.const -1)
+              )
+             )
+             (i32.const 12)
+            )
+            (i32.const 16)
+           )
+          )
+          (local.set $9
+           (i32.load
+            (local.tee $7
+             (i32.add
+              (local.tee $12
+               (i32.load
+                (local.tee $3
+                 (i32.add
+                  (local.tee $10
+                   (i32.add
+                    (i32.shl
+                     (local.tee $5
+                      (i32.add
+                       (i32.or
+                        (i32.or
+                         (i32.or
+                          (i32.or
+                           (local.tee $3
+                            (i32.and
+                             (i32.shr_u
+                              (local.tee $7
+                               (i32.shr_u
+                                (local.get $3)
+                                (local.get $10)
+                               )
+                              )
+                              (i32.const 5)
+                             )
+                             (i32.const 8)
+                            )
+                           )
+                           (local.get $10)
+                          )
+                          (local.tee $3
+                           (i32.and
+                            (i32.shr_u
+                             (local.tee $7
+                              (i32.shr_u
+                               (local.get $7)
+                               (local.get $3)
+                              )
+                             )
+                             (i32.const 2)
+                            )
+                            (i32.const 4)
+                           )
+                          )
+                         )
+                         (local.tee $3
+                          (i32.and
+                           (i32.shr_u
+                            (local.tee $7
+                             (i32.shr_u
+                              (local.get $7)
+                              (local.get $3)
+                             )
+                            )
+                            (i32.const 1)
+                           )
+                           (i32.const 2)
+                          )
+                         )
+                        )
+                        (local.tee $3
+                         (i32.and
+                          (i32.shr_u
+                           (local.tee $7
+                            (i32.shr_u
+                             (local.get $7)
+                             (local.get $3)
+                            )
+                           )
+                           (i32.const 1)
+                          )
+                          (i32.const 1)
+                         )
+                        )
+                       )
+                       (i32.shr_u
+                        (local.get $7)
+                        (local.get $3)
+                       )
+                      )
+                     )
+                     (i32.const 3)
+                    )
+                    (i32.const 216)
+                   )
+                  )
+                  (i32.const 8)
+                 )
+                )
+               )
+              )
+              (i32.const 8)
+             )
+            )
+           )
+          )
+          (if
+           (i32.eq
+            (local.get $10)
+            (local.get $9)
+           )
+           (block $block286
+            (i32.store
+             (i32.const 176)
+             (i32.and
+              (local.get $11)
+              (i32.xor
+               (i32.shl
+                (i32.const 1)
+                (local.get $5)
+               )
+               (i32.const -1)
+              )
+             )
+            )
+            (local.set $8
+             (local.get $0)
+            )
+           )
+           (block $block287
+            (if
+             (i32.lt_u
+              (local.get $9)
+              (i32.load
+               (i32.const 192)
+              )
+             )
+             (call $_abort)
+            )
+            (if
+             (i32.eq
+              (i32.load
+               (local.tee $0
+                (i32.add
+                 (local.get $9)
+                 (i32.const 12)
+                )
+               )
+              )
+              (local.get $12)
+             )
+             (block $block290
+              (i32.store
+               (local.get $0)
+               (local.get $10)
+              )
+              (i32.store
+               (local.get $3)
+               (local.get $9)
+              )
+              (local.set $8
+               (i32.load
+                (i32.const 184)
+               )
+              )
+             )
+             (call $_abort)
+            )
+           )
+          )
+          (i32.store offset=4
+           (local.get $12)
+           (i32.or
+            (local.get $4)
+            (i32.const 3)
+           )
+          )
+          (i32.store offset=4
+           (local.tee $10
+            (i32.add
+             (local.get $12)
+             (local.get $4)
+            )
+           )
+           (i32.or
+            (local.tee $5
+             (i32.sub
+              (i32.shl
+               (local.get $5)
+               (i32.const 3)
+              )
+              (local.get $4)
+             )
+            )
+            (i32.const 1)
+           )
+          )
+          (i32.store
+           (i32.add
+            (local.get $10)
+            (local.get $5)
+           )
+           (local.get $5)
+          )
+          (if
+           (local.get $8)
+           (block $block292
+            (local.set $12
+             (i32.load
+              (i32.const 196)
+             )
+            )
+            (local.set $4
+             (i32.add
+              (i32.shl
+               (local.tee $0
+                (i32.shr_u
+                 (local.get $8)
+                 (i32.const 3)
+                )
+               )
+               (i32.const 3)
+              )
+              (i32.const 216)
+             )
+            )
+            (if
+             (i32.and
+              (local.tee $3
+               (i32.load
+                (i32.const 176)
+               )
+              )
+              (local.tee $0
+               (i32.shl
+                (i32.const 1)
+                (local.get $0)
+               )
+              )
+             )
+             (if
+              (i32.lt_u
+               (local.tee $0
+                (i32.load
+                 (local.tee $3
+                  (i32.add
+                   (local.get $4)
+                   (i32.const 8)
+                  )
+                 )
+                )
+               )
+               (i32.load
+                (i32.const 192)
+               )
+              )
+              (call $_abort)
+              (block $block295
+               (local.set $2
+                (local.get $3)
+               )
+               (local.set $1
+                (local.get $0)
+               )
+              )
+             )
+             (block $block296
+              (i32.store
+               (i32.const 176)
+               (i32.or
+                (local.get $3)
+                (local.get $0)
+               )
+              )
+              (local.set $2
+               (i32.add
+                (local.get $4)
+                (i32.const 8)
+               )
+              )
+              (local.set $1
+               (local.get $4)
+              )
+             )
+            )
+            (i32.store
+             (local.get $2)
+             (local.get $12)
+            )
+            (i32.store offset=12
+             (local.get $1)
+             (local.get $12)
+            )
+            (i32.store offset=8
+             (local.get $12)
+             (local.get $1)
+            )
+            (i32.store offset=12
+             (local.get $12)
+             (local.get $4)
+            )
+           )
+          )
+          (i32.store
+           (i32.const 184)
+           (local.get $5)
+          )
+          (i32.store
+           (i32.const 196)
+           (local.get $10)
+          )
+          (return
+           (local.get $7)
+          )
+         )
+        )
+        (if
+         (local.tee $0
+          (i32.load
+           (i32.const 180)
+          )
+         )
+         (block $block298
+          (local.set $2
+           (i32.and
+            (i32.shr_u
+             (local.tee $0
+              (i32.add
+               (i32.and
+                (local.get $0)
+                (i32.sub
+                 (i32.const 0)
+                 (local.get $0)
+                )
+               )
+               (i32.const -1)
+              )
+             )
+             (i32.const 12)
+            )
+            (i32.const 16)
+           )
+          )
+          (local.set $7
+           (i32.sub
+            (i32.and
+             (i32.load offset=4
+              (local.tee $0
+               (i32.load offset=480
+                (i32.shl
+                 (i32.add
+                  (i32.or
+                   (i32.or
+                    (i32.or
+                     (i32.or
+                      (local.tee $0
+                       (i32.and
+                        (i32.shr_u
+                         (local.tee $1
+                          (i32.shr_u
+                           (local.get $0)
+                           (local.get $2)
+                          )
+                         )
+                         (i32.const 5)
+                        )
+                        (i32.const 8)
+                       )
+                      )
+                      (local.get $2)
+                     )
+                     (local.tee $0
+                      (i32.and
+                       (i32.shr_u
+                        (local.tee $1
+                         (i32.shr_u
+                          (local.get $1)
+                          (local.get $0)
+                         )
+                        )
+                        (i32.const 2)
+                       )
+                       (i32.const 4)
+                      )
+                     )
+                    )
+                    (local.tee $0
+                     (i32.and
+                      (i32.shr_u
+                       (local.tee $1
+                        (i32.shr_u
+                         (local.get $1)
+                         (local.get $0)
+                        )
+                       )
+                       (i32.const 1)
+                      )
+                      (i32.const 2)
+                     )
+                    )
+                   )
+                   (local.tee $0
+                    (i32.and
+                     (i32.shr_u
+                      (local.tee $1
+                       (i32.shr_u
+                        (local.get $1)
+                        (local.get $0)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                     (i32.const 1)
+                    )
+                   )
+                  )
+                  (i32.shr_u
+                   (local.get $1)
+                   (local.get $0)
+                  )
+                 )
+                 (i32.const 2)
+                )
+               )
+              )
+             )
+             (i32.const -8)
+            )
+            (local.get $4)
+           )
+          )
+          (local.set $1
+           (local.get $0)
+          )
+          (local.set $2
+           (local.get $0)
+          )
+          (loop $while-in
+           (block $while-out
+            (if
+             (i32.eqz
+              (local.tee $0
+               (i32.load offset=16
+                (local.get $1)
+               )
+              )
+             )
+             (if
+              (i32.eqz
+               (local.tee $0
+                (i32.load offset=20
+                 (local.get $1)
+                )
+               )
+              )
+              (block $block301
+               (local.set $10
+                (local.get $7)
+               )
+               (local.set $5
+                (local.get $2)
+               )
+               (br $while-out)
+              )
+             )
+            )
+            (local.set $10
+             (i32.lt_u
+              (local.tee $1
+               (i32.sub
+                (i32.and
+                 (i32.load offset=4
+                  (local.get $0)
+                 )
+                 (i32.const -8)
+                )
+                (local.get $4)
+               )
+              )
+              (local.get $7)
+             )
+            )
+            (local.set $7
+             (select
+              (local.get $1)
+              (local.get $7)
+              (local.get $10)
+             )
+            )
+            (local.set $1
+             (local.get $0)
+            )
+            (local.set $2
+             (select
+              (local.get $0)
+              (local.get $2)
+              (local.get $10)
+             )
+            )
+            (br $while-in)
+           )
+          )
+          (if
+           (i32.lt_u
+            (local.get $5)
+            (local.tee $12
+             (i32.load
+              (i32.const 192)
+             )
+            )
+           )
+           (call $_abort)
+          )
+          (if
+           (i32.ge_u
+            (local.get $5)
+            (local.tee $11
+             (i32.add
+              (local.get $5)
+              (local.get $4)
+             )
+            )
+           )
+           (call $_abort)
+          )
+          (local.set $8
+           (i32.load offset=24
+            (local.get $5)
+           )
+          )
+          (block $do-once4
+           (if
+            (i32.eq
+             (local.tee $0
+              (i32.load offset=12
+               (local.get $5)
+              )
+             )
+             (local.get $5)
+            )
+            (block $block305
+             (if
+              (i32.eqz
+               (local.tee $1
+                (i32.load
+                 (local.tee $0
+                  (i32.add
+                   (local.get $5)
+                   (i32.const 20)
+                  )
+                 )
+                )
+               )
+              )
+              (if
+               (i32.eqz
+                (local.tee $1
+                 (i32.load
+                  (local.tee $0
+                   (i32.add
+                    (local.get $5)
+                    (i32.const 16)
+                   )
+                  )
+                 )
+                )
+               )
+               (block $block308
+                (local.set $9
+                 (i32.const 0)
+                )
+                (br $do-once4)
+               )
+              )
+             )
+             (loop $while-in7
+              (if
+               (local.tee $2
+                (i32.load
+                 (local.tee $7
+                  (i32.add
+                   (local.get $1)
+                   (i32.const 20)
+                  )
+                 )
+                )
+               )
+               (block $block310
+                (local.set $1
+                 (local.get $2)
+                )
+                (local.set $0
+                 (local.get $7)
+                )
+                (br $while-in7)
+               )
+              )
+              (if
+               (local.tee $2
+                (i32.load
+                 (local.tee $7
+                  (i32.add
+                   (local.get $1)
+                   (i32.const 16)
+                  )
+                 )
+                )
+               )
+               (block $block312
+                (local.set $1
+                 (local.get $2)
+                )
+                (local.set $0
+                 (local.get $7)
+                )
+                (br $while-in7)
+               )
+              )
+             )
+             (if
+              (i32.lt_u
+               (local.get $0)
+               (local.get $12)
+              )
+              (call $_abort)
+              (block $block314
+               (i32.store
+                (local.get $0)
+                (i32.const 0)
+               )
+               (local.set $9
+                (local.get $1)
+               )
+              )
+             )
+            )
+            (block $block315
+             (if
+              (i32.lt_u
+               (local.tee $7
+                (i32.load offset=8
+                 (local.get $5)
+                )
+               )
+               (local.get $12)
+              )
+              (call $_abort)
+             )
+             (if
+              (i32.ne
+               (i32.load
+                (local.tee $2
+                 (i32.add
+                  (local.get $7)
+                  (i32.const 12)
+                 )
+                )
+               )
+               (local.get $5)
+              )
+              (call $_abort)
+             )
+             (if
+              (i32.eq
+               (i32.load
+                (local.tee $1
+                 (i32.add
+                  (local.get $0)
+                  (i32.const 8)
+                 )
+                )
+               )
+               (local.get $5)
+              )
+              (block $block319
+               (i32.store
+                (local.get $2)
+                (local.get $0)
+               )
+               (i32.store
+                (local.get $1)
+                (local.get $7)
+               )
+               (local.set $9
+                (local.get $0)
+               )
+              )
+              (call $_abort)
+             )
+            )
+           )
+          )
+          (block $do-once8
+           (if
+            (local.get $8)
+            (block $block321
+             (if
+              (i32.eq
+               (local.get $5)
+               (i32.load
+                (local.tee $0
+                 (i32.add
+                  (i32.shl
+                   (local.tee $1
+                    (i32.load offset=28
+                     (local.get $5)
+                    )
+                   )
+                   (i32.const 2)
+                  )
+                  (i32.const 480)
+                 )
+                )
+               )
+              )
+              (block $block323
+               (i32.store
+                (local.get $0)
+                (local.get $9)
+               )
+               (if
+                (i32.eqz
+                 (local.get $9)
+                )
+                (block $block325
+                 (i32.store
+                  (i32.const 180)
+                  (i32.and
+                   (i32.load
+                    (i32.const 180)
+                   )
+                   (i32.xor
+                    (i32.shl
+                     (i32.const 1)
+                     (local.get $1)
+                    )
+                    (i32.const -1)
+                   )
+                  )
+                 )
+                 (br $do-once8)
+                )
+               )
+              )
+              (block $block326
+               (if
+                (i32.lt_u
+                 (local.get $8)
+                 (i32.load
+                  (i32.const 192)
+                 )
+                )
+                (call $_abort)
+               )
+               (if
+                (i32.eq
+                 (i32.load
+                  (local.tee $0
+                   (i32.add
+                    (local.get $8)
+                    (i32.const 16)
+                   )
+                  )
+                 )
+                 (local.get $5)
+                )
+                (i32.store
+                 (local.get $0)
+                 (local.get $9)
+                )
+                (i32.store offset=20
+                 (local.get $8)
+                 (local.get $9)
+                )
+               )
+               (br_if $do-once8
+                (i32.eqz
+                 (local.get $9)
+                )
+               )
+              )
+             )
+             (if
+              (i32.lt_u
+               (local.get $9)
+               (local.tee $0
+                (i32.load
+                 (i32.const 192)
+                )
+               )
+              )
+              (call $_abort)
+             )
+             (i32.store offset=24
+              (local.get $9)
+              (local.get $8)
+             )
+             (if
+              (local.tee $1
+               (i32.load offset=16
+                (local.get $5)
+               )
+              )
+              (if
+               (i32.lt_u
+                (local.get $1)
+                (local.get $0)
+               )
+               (call $_abort)
+               (block $block332
+                (i32.store offset=16
+                 (local.get $9)
+                 (local.get $1)
+                )
+                (i32.store offset=24
+                 (local.get $1)
+                 (local.get $9)
+                )
+               )
+              )
+             )
+             (if
+              (local.tee $0
+               (i32.load offset=20
+                (local.get $5)
+               )
+              )
+              (if
+               (i32.lt_u
+                (local.get $0)
+                (i32.load
+                 (i32.const 192)
+                )
+               )
+               (call $_abort)
+               (block $block335
+                (i32.store offset=20
+                 (local.get $9)
+                 (local.get $0)
+                )
+                (i32.store offset=24
+                 (local.get $0)
+                 (local.get $9)
+                )
+               )
+              )
+             )
+            )
+           )
+          )
+          (if
+           (i32.lt_u
+            (local.get $10)
+            (i32.const 16)
+           )
+           (block $block337
+            (i32.store offset=4
+             (local.get $5)
+             (i32.or
+              (local.tee $0
+               (i32.add
+                (local.get $10)
+                (local.get $4)
+               )
+              )
+              (i32.const 3)
+             )
+            )
+            (i32.store
+             (local.tee $0
+              (i32.add
+               (i32.add
+                (local.get $5)
+                (local.get $0)
+               )
+               (i32.const 4)
+              )
+             )
+             (i32.or
+              (i32.load
+               (local.get $0)
+              )
+              (i32.const 1)
+             )
+            )
+           )
+           (block $block338
+            (i32.store offset=4
+             (local.get $5)
+             (i32.or
+              (local.get $4)
+              (i32.const 3)
+             )
+            )
+            (i32.store offset=4
+             (local.get $11)
+             (i32.or
+              (local.get $10)
+              (i32.const 1)
+             )
+            )
+            (i32.store
+             (i32.add
+              (local.get $11)
+              (local.get $10)
+             )
+             (local.get $10)
+            )
+            (if
+             (local.tee $0
+              (i32.load
+               (i32.const 184)
+              )
+             )
+             (block $block340
+              (local.set $4
+               (i32.load
+                (i32.const 196)
+               )
+              )
+              (local.set $2
+               (i32.add
+                (i32.shl
+                 (local.tee $0
+                  (i32.shr_u
+                   (local.get $0)
+                   (i32.const 3)
+                  )
+                 )
+                 (i32.const 3)
+                )
+                (i32.const 216)
+               )
+              )
+              (if
+               (i32.and
+                (local.tee $1
+                 (i32.load
+                  (i32.const 176)
+                 )
+                )
+                (local.tee $0
+                 (i32.shl
+                  (i32.const 1)
+                  (local.get $0)
+                 )
+                )
+               )
+               (if
+                (i32.lt_u
+                 (local.tee $0
+                  (i32.load
+                   (local.tee $1
+                    (i32.add
+                     (local.get $2)
+                     (i32.const 8)
+                    )
+                   )
+                  )
+                 )
+                 (i32.load
+                  (i32.const 192)
+                 )
+                )
+                (call $_abort)
+                (block $block343
+                 (local.set $6
+                  (local.get $1)
+                 )
+                 (local.set $3
+                  (local.get $0)
+                 )
+                )
+               )
+               (block $block344
+                (i32.store
+                 (i32.const 176)
+                 (i32.or
+                  (local.get $1)
+                  (local.get $0)
+                 )
+                )
+                (local.set $6
+                 (i32.add
+                  (local.get $2)
+                  (i32.const 8)
+                 )
+                )
+                (local.set $3
+                 (local.get $2)
+                )
+               )
+              )
+              (i32.store
+               (local.get $6)
+               (local.get $4)
+              )
+              (i32.store offset=12
+               (local.get $3)
+               (local.get $4)
+              )
+              (i32.store offset=8
+               (local.get $4)
+               (local.get $3)
+              )
+              (i32.store offset=12
+               (local.get $4)
+               (local.get $2)
+              )
+             )
+            )
+            (i32.store
+             (i32.const 184)
+             (local.get $10)
+            )
+            (i32.store
+             (i32.const 196)
+             (local.get $11)
+            )
+           )
+          )
+          (return
+           (i32.add
+            (local.get $5)
+            (i32.const 8)
+           )
+          )
+         )
+         (local.set $0
+          (local.get $4)
+         )
+        )
+       )
+       (local.set $0
+        (local.get $4)
+       )
+      )
+     )
+     (if
+      (i32.gt_u
+       (local.get $0)
+       (i32.const -65)
+      )
+      (local.set $0
+       (i32.const -1)
+      )
+      (block $block346
+       (local.set $2
+        (i32.and
+         (local.tee $0
+          (i32.add
+           (local.get $0)
+           (i32.const 11)
+          )
+         )
+         (i32.const -8)
+        )
+       )
+       (if
+        (local.tee $18
+         (i32.load
+          (i32.const 180)
+         )
+        )
+        (block $block348
+         (local.set $14
+          (if (result i32)
+           (local.tee $0
+            (i32.shr_u
+             (local.get $0)
+             (i32.const 8)
+            )
+           )
+           (if (result i32)
+            (i32.gt_u
+             (local.get $2)
+             (i32.const 16777215)
+            )
+            (i32.const 31)
+            (i32.or
+             (i32.and
+              (i32.shr_u
+               (local.get $2)
+               (i32.add
+                (local.tee $0
+                 (i32.add
+                  (i32.sub
+                   (i32.const 14)
+                   (i32.or
+                    (i32.or
+                     (local.tee $0
+                      (i32.and
+                       (i32.shr_u
+                        (i32.add
+                         (local.tee $1
+                          (i32.shl
+                           (local.get $0)
+                           (local.tee $3
+                            (i32.and
+                             (i32.shr_u
+                              (i32.add
+                               (local.get $0)
+                               (i32.const 1048320)
+                              )
+                              (i32.const 16)
+                             )
+                             (i32.const 8)
+                            )
+                           )
+                          )
+                         )
+                         (i32.const 520192)
+                        )
+                        (i32.const 16)
+                       )
+                       (i32.const 4)
+                      )
+                     )
+                     (local.get $3)
+                    )
+                    (local.tee $0
+                     (i32.and
+                      (i32.shr_u
+                       (i32.add
+                        (local.tee $1
+                         (i32.shl
+                          (local.get $1)
+                          (local.get $0)
+                         )
+                        )
+                        (i32.const 245760)
+                       )
+                       (i32.const 16)
+                      )
+                      (i32.const 2)
+                     )
+                    )
+                   )
+                  )
+                  (i32.shr_u
+                   (i32.shl
+                    (local.get $1)
+                    (local.get $0)
+                   )
+                   (i32.const 15)
+                  )
+                 )
+                )
+                (i32.const 7)
+               )
+              )
+              (i32.const 1)
+             )
+             (i32.shl
+              (local.get $0)
+              (i32.const 1)
+             )
+            )
+           )
+           (i32.const 0)
+          )
+         )
+         (local.set $3
+          (i32.sub
+           (i32.const 0)
+           (local.get $2)
+          )
+         )
+         (block $__rjto$3
+          (block $__rjti$3
+           (if
+            (local.tee $0
+             (i32.load offset=480
+              (i32.shl
+               (local.get $14)
+               (i32.const 2)
+              )
+             )
+            )
+            (block $block352
+             (local.set $6
+              (i32.const 0)
+             )
+             (local.set $8
+              (i32.shl
+               (local.get $2)
+               (select
+                (i32.const 0)
+                (i32.sub
+                 (i32.const 25)
+                 (i32.shr_u
+                  (local.get $14)
+                  (i32.const 1)
+                 )
+                )
+                (i32.eq
+                 (local.get $14)
+                 (i32.const 31)
+                )
+               )
+              )
+             )
+             (local.set $1
+              (i32.const 0)
+             )
+             (loop $while-in14
+              (if
+               (i32.lt_u
+                (local.tee $4
+                 (i32.sub
+                  (local.tee $9
+                   (i32.and
+                    (i32.load offset=4
+                     (local.get $0)
+                    )
+                    (i32.const -8)
+                   )
+                  )
+                  (local.get $2)
+                 )
+                )
+                (local.get $3)
+               )
+               (if
+                (i32.eq
+                 (local.get $9)
+                 (local.get $2)
+                )
+                (block $block355
+                 (local.set $1
+                  (local.get $4)
+                 )
+                 (local.set $3
+                  (local.get $0)
+                 )
+                 (br $__rjti$3)
+                )
+                (block $block356
+                 (local.set $3
+                  (local.get $4)
+                 )
+                 (local.set $1
+                  (local.get $0)
+                 )
+                )
+               )
+              )
+              (local.set $0
+               (select
+                (local.get $6)
+                (local.tee $4
+                 (i32.load offset=20
+                  (local.get $0)
+                 )
+                )
+                (i32.or
+                 (i32.eqz
+                  (local.get $4)
+                 )
+                 (i32.eq
+                  (local.get $4)
+                  (local.tee $9
+                   (i32.load
+                    (i32.add
+                     (i32.add
+                      (local.get $0)
+                      (i32.const 16)
+                     )
+                     (i32.shl
+                      (i32.shr_u
+                       (local.get $8)
+                       (i32.const 31)
+                      )
+                      (i32.const 2)
+                     )
+                    )
+                   )
+                  )
+                 )
+                )
+               )
+              )
+              (local.set $4
+               (i32.shl
+                (local.get $8)
+                (i32.xor
+                 (local.tee $6
+                  (i32.eqz
+                   (local.get $9)
+                  )
+                 )
+                 (i32.const 1)
+                )
+               )
+              )
+              (if
+               (local.get $6)
+               (block $block358
+                (local.set $4
+                 (local.get $0)
+                )
+                (local.set $0
+                 (local.get $1)
+                )
+               )
+               (block $block359
+                (local.set $6
+                 (local.get $0)
+                )
+                (local.set $8
+                 (local.get $4)
+                )
+                (local.set $0
+                 (local.get $9)
+                )
+                (br $while-in14)
+               )
+              )
+             )
+            )
+            (block $block360
+             (local.set $4
+              (i32.const 0)
+             )
+             (local.set $0
+              (i32.const 0)
+             )
+            )
+           )
+           (if
+            (i32.and
+             (i32.eqz
+              (local.get $4)
+             )
+             (i32.eqz
+              (local.get $0)
+             )
+            )
+            (block $block362
+             (if
+              (i32.eqz
+               (local.tee $1
+                (i32.and
+                 (local.get $18)
+                 (i32.or
+                  (local.tee $1
+                   (i32.shl
+                    (i32.const 2)
+                    (local.get $14)
+                   )
+                  )
+                  (i32.sub
+                   (i32.const 0)
+                   (local.get $1)
+                  )
+                 )
+                )
+               )
+              )
+              (block $block364
+               (local.set $0
+                (local.get $2)
+               )
+               (br $do-once)
+              )
+             )
+             (local.set $9
+              (i32.and
+               (i32.shr_u
+                (local.tee $1
+                 (i32.add
+                  (i32.and
+                   (local.get $1)
+                   (i32.sub
+                    (i32.const 0)
+                    (local.get $1)
+                   )
+                  )
+                  (i32.const -1)
+                 )
+                )
+                (i32.const 12)
+               )
+               (i32.const 16)
+              )
+             )
+             (local.set $4
+              (i32.load offset=480
+               (i32.shl
+                (i32.add
+                 (i32.or
+                  (i32.or
+                   (i32.or
+                    (i32.or
+                     (local.tee $1
+                      (i32.and
+                       (i32.shr_u
+                        (local.tee $4
+                         (i32.shr_u
+                          (local.get $1)
+                          (local.get $9)
+                         )
+                        )
+                        (i32.const 5)
+                       )
+                       (i32.const 8)
+                      )
+                     )
+                     (local.get $9)
+                    )
+                    (local.tee $1
+                     (i32.and
+                      (i32.shr_u
+                       (local.tee $4
+                        (i32.shr_u
+                         (local.get $4)
+                         (local.get $1)
+                        )
+                       )
+                       (i32.const 2)
+                      )
+                      (i32.const 4)
+                     )
+                    )
+                   )
+                   (local.tee $1
+                    (i32.and
+                     (i32.shr_u
+                      (local.tee $4
+                       (i32.shr_u
+                        (local.get $4)
+                        (local.get $1)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                     (i32.const 2)
+                    )
+                   )
+                  )
+                  (local.tee $1
+                   (i32.and
+                    (i32.shr_u
+                     (local.tee $4
+                      (i32.shr_u
+                       (local.get $4)
+                       (local.get $1)
+                      )
+                     )
+                     (i32.const 1)
+                    )
+                    (i32.const 1)
+                   )
+                  )
+                 )
+                 (i32.shr_u
+                  (local.get $4)
+                  (local.get $1)
+                 )
+                )
+                (i32.const 2)
+               )
+              )
+             )
+            )
+           )
+           (if
+            (local.get $4)
+            (block $block366
+             (local.set $1
+              (local.get $3)
+             )
+             (local.set $3
+              (local.get $4)
+             )
+             (br $__rjti$3)
+            )
+            (local.set $4
+             (local.get $0)
+            )
+           )
+           (br $__rjto$3)
+          )
+          (loop $while-in16
+           (local.set $9
+            (i32.lt_u
+             (local.tee $4
+              (i32.sub
+               (i32.and
+                (i32.load offset=4
+                 (local.get $3)
+                )
+                (i32.const -8)
+               )
+               (local.get $2)
+              )
+             )
+             (local.get $1)
+            )
+           )
+           (local.set $1
+            (select
+             (local.get $4)
+             (local.get $1)
+             (local.get $9)
+            )
+           )
+           (local.set $0
+            (select
+             (local.get $3)
+             (local.get $0)
+             (local.get $9)
+            )
+           )
+           (if
+            (local.tee $4
+             (i32.load offset=16
+              (local.get $3)
+             )
+            )
+            (block $block368
+             (local.set $3
+              (local.get $4)
+             )
+             (br $while-in16)
+            )
+           )
+           (br_if $while-in16
+            (local.tee $3
+             (i32.load offset=20
+              (local.get $3)
+             )
+            )
+           )
+           (local.set $3
+            (local.get $1)
+           )
+           (local.set $4
+            (local.get $0)
+           )
+          )
+         )
+         (if
+          (local.get $4)
+          (if
+           (i32.lt_u
+            (local.get $3)
+            (i32.sub
+             (i32.load
+              (i32.const 184)
+             )
+             (local.get $2)
+            )
+           )
+           (block $block371
+            (if
+             (i32.lt_u
+              (local.get $4)
+              (local.tee $12
+               (i32.load
+                (i32.const 192)
+               )
+              )
+             )
+             (call $_abort)
+            )
+            (if
+             (i32.ge_u
+              (local.get $4)
+              (local.tee $6
+               (i32.add
+                (local.get $4)
+                (local.get $2)
+               )
+              )
+             )
+             (call $_abort)
+            )
+            (local.set $9
+             (i32.load offset=24
+              (local.get $4)
+             )
+            )
+            (block $do-once17
+             (if
+              (i32.eq
+               (local.tee $0
+                (i32.load offset=12
+                 (local.get $4)
+                )
+               )
+               (local.get $4)
+              )
+              (block $block375
+               (if
+                (i32.eqz
+                 (local.tee $1
+                  (i32.load
+                   (local.tee $0
+                    (i32.add
+                     (local.get $4)
+                     (i32.const 20)
+                    )
+                   )
+                  )
+                 )
+                )
+                (if
+                 (i32.eqz
+                  (local.tee $1
+                   (i32.load
+                    (local.tee $0
+                     (i32.add
+                      (local.get $4)
+                      (i32.const 16)
+                     )
+                    )
+                   )
+                  )
+                 )
+                 (block $block378
+                  (local.set $11
+                   (i32.const 0)
+                  )
+                  (br $do-once17)
+                 )
+                )
+               )
+               (loop $while-in20
+                (if
+                 (local.tee $7
+                  (i32.load
+                   (local.tee $10
+                    (i32.add
+                     (local.get $1)
+                     (i32.const 20)
+                    )
+                   )
+                  )
+                 )
+                 (block $block380
+                  (local.set $1
+                   (local.get $7)
+                  )
+                  (local.set $0
+                   (local.get $10)
+                  )
+                  (br $while-in20)
+                 )
+                )
+                (if
+                 (local.tee $7
+                  (i32.load
+                   (local.tee $10
+                    (i32.add
+                     (local.get $1)
+                     (i32.const 16)
+                    )
+                   )
+                  )
+                 )
+                 (block $block382
+                  (local.set $1
+                   (local.get $7)
+                  )
+                  (local.set $0
+                   (local.get $10)
+                  )
+                  (br $while-in20)
+                 )
+                )
+               )
+               (if
+                (i32.lt_u
+                 (local.get $0)
+                 (local.get $12)
+                )
+                (call $_abort)
+                (block $block384
+                 (i32.store
+                  (local.get $0)
+                  (i32.const 0)
+                 )
+                 (local.set $11
+                  (local.get $1)
+                 )
+                )
+               )
+              )
+              (block $block385
+               (if
+                (i32.lt_u
+                 (local.tee $10
+                  (i32.load offset=8
+                   (local.get $4)
+                  )
+                 )
+                 (local.get $12)
+                )
+                (call $_abort)
+               )
+               (if
+                (i32.ne
+                 (i32.load
+                  (local.tee $7
+                   (i32.add
+                    (local.get $10)
+                    (i32.const 12)
+                   )
+                  )
+                 )
+                 (local.get $4)
+                )
+                (call $_abort)
+               )
+               (if
+                (i32.eq
+                 (i32.load
+                  (local.tee $1
+                   (i32.add
+                    (local.get $0)
+                    (i32.const 8)
+                   )
+                  )
+                 )
+                 (local.get $4)
+                )
+                (block $block389
+                 (i32.store
+                  (local.get $7)
+                  (local.get $0)
+                 )
+                 (i32.store
+                  (local.get $1)
+                  (local.get $10)
+                 )
+                 (local.set $11
+                  (local.get $0)
+                 )
+                )
+                (call $_abort)
+               )
+              )
+             )
+            )
+            (block $do-once21
+             (if
+              (local.get $9)
+              (block $block391
+               (if
+                (i32.eq
+                 (local.get $4)
+                 (i32.load
+                  (local.tee $0
+                   (i32.add
+                    (i32.shl
+                     (local.tee $1
+                      (i32.load offset=28
+                       (local.get $4)
+                      )
+                     )
+                     (i32.const 2)
+                    )
+                    (i32.const 480)
+                   )
+                  )
+                 )
+                )
+                (block $block393
+                 (i32.store
+                  (local.get $0)
+                  (local.get $11)
+                 )
+                 (if
+                  (i32.eqz
+                   (local.get $11)
+                  )
+                  (block $block395
+                   (i32.store
+                    (i32.const 180)
+                    (i32.and
+                     (i32.load
+                      (i32.const 180)
+                     )
+                     (i32.xor
+                      (i32.shl
+                       (i32.const 1)
+                       (local.get $1)
+                      )
+                      (i32.const -1)
+                     )
+                    )
+                   )
+                   (br $do-once21)
+                  )
+                 )
+                )
+                (block $block396
+                 (if
+                  (i32.lt_u
+                   (local.get $9)
+                   (i32.load
+                    (i32.const 192)
+                   )
+                  )
+                  (call $_abort)
+                 )
+                 (if
+                  (i32.eq
+                   (i32.load
+                    (local.tee $0
+                     (i32.add
+                      (local.get $9)
+                      (i32.const 16)
+                     )
+                    )
+                   )
+                   (local.get $4)
+                  )
+                  (i32.store
+                   (local.get $0)
+                   (local.get $11)
+                  )
+                  (i32.store offset=20
+                   (local.get $9)
+                   (local.get $11)
+                  )
+                 )
+                 (br_if $do-once21
+                  (i32.eqz
+                   (local.get $11)
+                  )
+                 )
+                )
+               )
+               (if
+                (i32.lt_u
+                 (local.get $11)
+                 (local.tee $0
+                  (i32.load
+                   (i32.const 192)
+                  )
+                 )
+                )
+                (call $_abort)
+               )
+               (i32.store offset=24
+                (local.get $11)
+                (local.get $9)
+               )
+               (if
+                (local.tee $1
+                 (i32.load offset=16
+                  (local.get $4)
+                 )
+                )
+                (if
+                 (i32.lt_u
+                  (local.get $1)
+                  (local.get $0)
+                 )
+                 (call $_abort)
+                 (block $block402
+                  (i32.store offset=16
+                   (local.get $11)
+                   (local.get $1)
+                  )
+                  (i32.store offset=24
+                   (local.get $1)
+                   (local.get $11)
+                  )
+                 )
+                )
+               )
+               (if
+                (local.tee $0
+                 (i32.load offset=20
+                  (local.get $4)
+                 )
+                )
+                (if
+                 (i32.lt_u
+                  (local.get $0)
+                  (i32.load
+                   (i32.const 192)
+                  )
+                 )
+                 (call $_abort)
+                 (block $block405
+                  (i32.store offset=20
+                   (local.get $11)
+                   (local.get $0)
+                  )
+                  (i32.store offset=24
+                   (local.get $0)
+                   (local.get $11)
+                  )
+                 )
+                )
+               )
+              )
+             )
+            )
+            (block $do-once25
+             (if
+              (i32.lt_u
+               (local.get $3)
+               (i32.const 16)
+              )
+              (block $block407
+               (i32.store offset=4
+                (local.get $4)
+                (i32.or
+                 (local.tee $0
+                  (i32.add
+                   (local.get $3)
+                   (local.get $2)
+                  )
+                 )
+                 (i32.const 3)
+                )
+               )
+               (i32.store
+                (local.tee $0
+                 (i32.add
+                  (i32.add
+                   (local.get $4)
+                   (local.get $0)
+                  )
+                  (i32.const 4)
+                 )
+                )
+                (i32.or
+                 (i32.load
+                  (local.get $0)
+                 )
+                 (i32.const 1)
+                )
+               )
+              )
+              (block $block408
+               (i32.store offset=4
+                (local.get $4)
+                (i32.or
+                 (local.get $2)
+                 (i32.const 3)
+                )
+               )
+               (i32.store offset=4
+                (local.get $6)
+                (i32.or
+                 (local.get $3)
+                 (i32.const 1)
+                )
+               )
+               (i32.store
+                (i32.add
+                 (local.get $6)
+                 (local.get $3)
+                )
+                (local.get $3)
+               )
+               (local.set $0
+                (i32.shr_u
+                 (local.get $3)
+                 (i32.const 3)
+                )
+               )
+               (if
+                (i32.lt_u
+                 (local.get $3)
+                 (i32.const 256)
+                )
+                (block $block410
+                 (local.set $3
+                  (i32.add
+                   (i32.shl
+                    (local.get $0)
+                    (i32.const 3)
+                   )
+                   (i32.const 216)
+                  )
+                 )
+                 (if
+                  (i32.and
+                   (local.tee $1
+                    (i32.load
+                     (i32.const 176)
+                    )
+                   )
+                   (local.tee $0
+                    (i32.shl
+                     (i32.const 1)
+                     (local.get $0)
+                    )
+                   )
+                  )
+                  (if
+                   (i32.lt_u
+                    (local.tee $0
+                     (i32.load
+                      (local.tee $1
+                       (i32.add
+                        (local.get $3)
+                        (i32.const 8)
+                       )
+                      )
+                     )
+                    )
+                    (i32.load
+                     (i32.const 192)
+                    )
+                   )
+                   (call $_abort)
+                   (block $block413
+                    (local.set $13
+                     (local.get $1)
+                    )
+                    (local.set $5
+                     (local.get $0)
+                    )
+                   )
+                  )
+                  (block $block414
+                   (i32.store
+                    (i32.const 176)
+                    (i32.or
+                     (local.get $1)
+                     (local.get $0)
+                    )
+                   )
+                   (local.set $13
+                    (i32.add
+                     (local.get $3)
+                     (i32.const 8)
+                    )
+                   )
+                   (local.set $5
+                    (local.get $3)
+                   )
+                  )
+                 )
+                 (i32.store
+                  (local.get $13)
+                  (local.get $6)
+                 )
+                 (i32.store offset=12
+                  (local.get $5)
+                  (local.get $6)
+                 )
+                 (i32.store offset=8
+                  (local.get $6)
+                  (local.get $5)
+                 )
+                 (i32.store offset=12
+                  (local.get $6)
+                  (local.get $3)
+                 )
+                 (br $do-once25)
+                )
+               )
+               (local.set $2
+                (i32.add
+                 (i32.shl
+                  (local.tee $7
+                   (if (result i32)
+                    (local.tee $0
+                     (i32.shr_u
+                      (local.get $3)
+                      (i32.const 8)
+                     )
+                    )
+                    (if (result i32)
+                     (i32.gt_u
+                      (local.get $3)
+                      (i32.const 16777215)
+                     )
+                     (i32.const 31)
+                     (i32.or
+                      (i32.and
+                       (i32.shr_u
+                        (local.get $3)
+                        (i32.add
+                         (local.tee $0
+                          (i32.add
+                           (i32.sub
+                            (i32.const 14)
+                            (i32.or
+                             (i32.or
+                              (local.tee $0
+                               (i32.and
+                                (i32.shr_u
+                                 (i32.add
+                                  (local.tee $1
+                                   (i32.shl
+                                    (local.get $0)
+                                    (local.tee $2
+                                     (i32.and
+                                      (i32.shr_u
+                                       (i32.add
+                                        (local.get $0)
+                                        (i32.const 1048320)
+                                       )
+                                       (i32.const 16)
+                                      )
+                                      (i32.const 8)
+                                     )
+                                    )
+                                   )
+                                  )
+                                  (i32.const 520192)
+                                 )
+                                 (i32.const 16)
+                                )
+                                (i32.const 4)
+                               )
+                              )
+                              (local.get $2)
+                             )
+                             (local.tee $0
+                              (i32.and
+                               (i32.shr_u
+                                (i32.add
+                                 (local.tee $1
+                                  (i32.shl
+                                   (local.get $1)
+                                   (local.get $0)
+                                  )
+                                 )
+                                 (i32.const 245760)
+                                )
+                                (i32.const 16)
+                               )
+                               (i32.const 2)
+                              )
+                             )
+                            )
+                           )
+                           (i32.shr_u
+                            (i32.shl
+                             (local.get $1)
+                             (local.get $0)
+                            )
+                            (i32.const 15)
+                           )
+                          )
+                         )
+                         (i32.const 7)
+                        )
+                       )
+                       (i32.const 1)
+                      )
+                      (i32.shl
+                       (local.get $0)
+                       (i32.const 1)
+                      )
+                     )
+                    )
+                    (i32.const 0)
+                   )
+                  )
+                  (i32.const 2)
+                 )
+                 (i32.const 480)
+                )
+               )
+               (i32.store offset=28
+                (local.get $6)
+                (local.get $7)
+               )
+               (i32.store offset=4
+                (local.tee $0
+                 (i32.add
+                  (local.get $6)
+                  (i32.const 16)
+                 )
+                )
+                (i32.const 0)
+               )
+               (i32.store
+                (local.get $0)
+                (i32.const 0)
+               )
+               (if
+                (i32.eqz
+                 (i32.and
+                  (local.tee $1
+                   (i32.load
+                    (i32.const 180)
+                   )
+                  )
+                  (local.tee $0
+                   (i32.shl
+                    (i32.const 1)
+                    (local.get $7)
+                   )
+                  )
+                 )
+                )
+                (block $block418
+                 (i32.store
+                  (i32.const 180)
+                  (i32.or
+                   (local.get $1)
+                   (local.get $0)
+                  )
+                 )
+                 (i32.store
+                  (local.get $2)
+                  (local.get $6)
+                 )
+                 (i32.store offset=24
+                  (local.get $6)
+                  (local.get $2)
+                 )
+                 (i32.store offset=12
+                  (local.get $6)
+                  (local.get $6)
+                 )
+                 (i32.store offset=8
+                  (local.get $6)
+                  (local.get $6)
+                 )
+                 (br $do-once25)
+                )
+               )
+               (local.set $7
+                (i32.shl
+                 (local.get $3)
+                 (select
+                  (i32.const 0)
+                  (i32.sub
+                   (i32.const 25)
+                   (i32.shr_u
+                    (local.get $7)
+                    (i32.const 1)
+                   )
+                  )
+                  (i32.eq
+                   (local.get $7)
+                   (i32.const 31)
+                  )
+                 )
+                )
+               )
+               (local.set $0
+                (i32.load
+                 (local.get $2)
+                )
+               )
+               (block $__rjto$1
+                (block $__rjti$1
+                 (loop $while-in28
+                  (br_if $__rjti$1
+                   (i32.eq
+                    (i32.and
+                     (i32.load offset=4
+                      (local.get $0)
+                     )
+                     (i32.const -8)
+                    )
+                    (local.get $3)
+                   )
+                  )
+                  (local.set $2
+                   (i32.shl
+                    (local.get $7)
+                    (i32.const 1)
+                   )
+                  )
+                  (if
+                   (local.tee $1
+                    (i32.load
+                     (local.tee $7
+                      (i32.add
+                       (i32.add
+                        (local.get $0)
+                        (i32.const 16)
+                       )
+                       (i32.shl
+                        (i32.shr_u
+                         (local.get $7)
+                         (i32.const 31)
+                        )
+                        (i32.const 2)
+                       )
+                      )
+                     )
+                    )
+                   )
+                   (block $block420
+                    (local.set $7
+                     (local.get $2)
+                    )
+                    (local.set $0
+                     (local.get $1)
+                    )
+                    (br $while-in28)
+                   )
+                  )
+                 )
+                 (if
+                  (i32.lt_u
+                   (local.get $7)
+                   (i32.load
+                    (i32.const 192)
+                   )
+                  )
+                  (call $_abort)
+                  (block $block422
+                   (i32.store
+                    (local.get $7)
+                    (local.get $6)
+                   )
+                   (i32.store offset=24
+                    (local.get $6)
+                    (local.get $0)
+                   )
+                   (i32.store offset=12
+                    (local.get $6)
+                    (local.get $6)
+                   )
+                   (i32.store offset=8
+                    (local.get $6)
+                    (local.get $6)
+                   )
+                   (br $do-once25)
+                  )
+                 )
+                 (br $__rjto$1)
+                )
+                (if
+                 (i32.and
+                  (i32.ge_u
+                   (local.tee $2
+                    (i32.load
+                     (local.tee $3
+                      (i32.add
+                       (local.get $0)
+                       (i32.const 8)
+                      )
+                     )
+                    )
+                   )
+                   (local.tee $1
+                    (i32.load
+                     (i32.const 192)
+                    )
+                   )
+                  )
+                  (i32.ge_u
+                   (local.get $0)
+                   (local.get $1)
+                  )
+                 )
+                 (block $block424
+                  (i32.store offset=12
+                   (local.get $2)
+                   (local.get $6)
+                  )
+                  (i32.store
+                   (local.get $3)
+                   (local.get $6)
+                  )
+                  (i32.store offset=8
+                   (local.get $6)
+                   (local.get $2)
+                  )
+                  (i32.store offset=12
+                   (local.get $6)
+                   (local.get $0)
+                  )
+                  (i32.store offset=24
+                   (local.get $6)
+                   (i32.const 0)
+                  )
+                 )
+                 (call $_abort)
+                )
+               )
+              )
+             )
+            )
+            (return
+             (i32.add
+              (local.get $4)
+              (i32.const 8)
+             )
+            )
+           )
+           (local.set $0
+            (local.get $2)
+           )
+          )
+          (local.set $0
+           (local.get $2)
+          )
+         )
+        )
+        (local.set $0
+         (local.get $2)
+        )
+       )
+      )
+     )
+    )
+   )
+   (if
+    (i32.ge_u
+     (local.tee $1
+      (i32.load
+       (i32.const 184)
+      )
+     )
+     (local.get $0)
+    )
+    (block $block426
+     (local.set $2
+      (i32.load
+       (i32.const 196)
+      )
+     )
+     (if
+      (i32.gt_u
+       (local.tee $3
+        (i32.sub
+         (local.get $1)
+         (local.get $0)
+        )
+       )
+       (i32.const 15)
+      )
+      (block $block428
+       (i32.store
+        (i32.const 196)
+        (local.tee $1
+         (i32.add
+          (local.get $2)
+          (local.get $0)
+         )
+        )
+       )
+       (i32.store
+        (i32.const 184)
+        (local.get $3)
+       )
+       (i32.store offset=4
+        (local.get $1)
+        (i32.or
+         (local.get $3)
+         (i32.const 1)
+        )
+       )
+       (i32.store
+        (i32.add
+         (local.get $1)
+         (local.get $3)
+        )
+        (local.get $3)
+       )
+       (i32.store offset=4
+        (local.get $2)
+        (i32.or
+         (local.get $0)
+         (i32.const 3)
+        )
+       )
+      )
+      (block $block429
+       (i32.store
+        (i32.const 184)
+        (i32.const 0)
+       )
+       (i32.store
+        (i32.const 196)
+        (i32.const 0)
+       )
+       (i32.store offset=4
+        (local.get $2)
+        (i32.or
+         (local.get $1)
+         (i32.const 3)
+        )
+       )
+       (i32.store
+        (local.tee $0
+         (i32.add
+          (i32.add
+           (local.get $2)
+           (local.get $1)
+          )
+          (i32.const 4)
+         )
+        )
+        (i32.or
+         (i32.load
+          (local.get $0)
+         )
+         (i32.const 1)
+        )
+       )
+      )
+     )
+     (return
+      (i32.add
+       (local.get $2)
+       (i32.const 8)
+      )
+     )
+    )
+   )
+   (br_if $folding-inner0
+    (i32.gt_u
+     (local.tee $1
+      (i32.load
+       (i32.const 188)
+      )
+     )
+     (local.get $0)
+    )
+   )
+   (if
+    (i32.eqz
+     (i32.load
+      (i32.const 648)
+     )
+    )
+    (if
+     (i32.and
+      (i32.add
+       (local.tee $1
+        (call $_sysconf
+         (i32.const 30)
+        )
+       )
+       (i32.const -1)
+      )
+      (local.get $1)
+     )
+     (call $_abort)
+     (block $block432
+      (i32.store
+       (i32.const 656)
+       (local.get $1)
+      )
+      (i32.store
+       (i32.const 652)
+       (local.get $1)
+      )
+      (i32.store
+       (i32.const 660)
+       (i32.const -1)
+      )
+      (i32.store
+       (i32.const 664)
+       (i32.const -1)
+      )
+      (i32.store
+       (i32.const 668)
+       (i32.const 0)
+      )
+      (i32.store
+       (i32.const 620)
+       (i32.const 0)
+      )
+      (i32.store
+       (i32.const 648)
+       (i32.xor
+        (i32.and
+         (call $_time
+          (i32.const 0)
+         )
+         (i32.const -16)
+        )
+        (i32.const 1431655768)
+       )
+      )
+     )
+    )
+   )
+   (if
+    (i32.le_u
+     (local.tee $5
+      (i32.and
+       (local.tee $6
+        (i32.add
+         (local.tee $1
+          (i32.load
+           (i32.const 656)
+          )
+         )
+         (local.tee $8
+          (i32.add
+           (local.get $0)
+           (i32.const 47)
+          )
+         )
+        )
+       )
+       (local.tee $9
+        (i32.sub
+         (i32.const 0)
+         (local.get $1)
+        )
+       )
+      )
+     )
+     (local.get $0)
+    )
+    (return
+     (i32.const 0)
+    )
+   )
+   (if
+    (local.tee $2
+     (i32.load
+      (i32.const 616)
+     )
+    )
+    (if
+     (i32.or
+      (i32.le_u
+       (local.tee $1
+        (i32.add
+         (local.tee $3
+          (i32.load
+           (i32.const 608)
+          )
+         )
+         (local.get $5)
+        )
+       )
+       (local.get $3)
+      )
+      (i32.gt_u
+       (local.get $1)
+       (local.get $2)
+      )
+     )
+     (return
+      (i32.const 0)
+     )
+    )
+   )
+   (local.set $11
+    (i32.add
+     (local.get $0)
+     (i32.const 48)
+    )
+   )
+   (block $__rjto$13
+    (block $__rjti$13
+     (if
+      (i32.eqz
+       (i32.and
+        (i32.load
+         (i32.const 620)
+        )
+        (i32.const 4)
+       )
+      )
+      (block $block437
+       (block $label$break$L279
+        (block $__rjti$5
+         (block $__rjti$4
+          (br_if $__rjti$4
+           (i32.eqz
+            (local.tee $4
+             (i32.load
+              (i32.const 200)
+             )
+            )
+           )
+          )
+          (local.set $1
+           (i32.const 624)
+          )
+          (loop $while-in34
+           (block $while-out33
+            (if
+             (i32.le_u
+              (local.tee $3
+               (i32.load
+                (local.get $1)
+               )
+              )
+              (local.get $4)
+             )
+             (if
+              (i32.gt_u
+               (i32.add
+                (local.get $3)
+                (i32.load
+                 (local.tee $2
+                  (i32.add
+                   (local.get $1)
+                   (i32.const 4)
+                  )
+                 )
+                )
+               )
+               (local.get $4)
+              )
+              (block $block440
+               (local.set $4
+                (local.get $1)
+               )
+               (br $while-out33)
+              )
+             )
+            )
+            (br_if $while-in34
+             (local.tee $1
+              (i32.load offset=8
+               (local.get $1)
+              )
+             )
+            )
+            (br $__rjti$4)
+           )
+          )
+          (if
+           (i32.lt_u
+            (local.tee $3
+             (i32.and
+              (i32.sub
+               (local.get $6)
+               (i32.load
+                (i32.const 188)
+               )
+              )
+              (local.get $9)
+             )
+            )
+            (i32.const 2147483647)
+           )
+           (if
+            (i32.eq
+             (local.tee $1
+              (call $_sbrk
+               (local.get $3)
+              )
+             )
+             (i32.add
+              (i32.load
+               (local.get $4)
+              )
+              (i32.load
+               (local.get $2)
+              )
+             )
+            )
+            (br_if $__rjti$13
+             (i32.ne
+              (local.get $1)
+              (i32.const -1)
+             )
+            )
+            (block $block443
+             (local.set $2
+              (local.get $1)
+             )
+             (br $__rjti$5)
+            )
+           )
+          )
+          (br $label$break$L279)
+         )
+         (if
+          (i32.ne
+           (local.tee $1
+            (call $_sbrk
+             (i32.const 0)
+            )
+           )
+           (i32.const -1)
+          )
+          (block $block445
+           (local.set $3
+            (if (result i32)
+             (i32.and
+              (local.tee $2
+               (i32.add
+                (local.tee $4
+                 (i32.load
+                  (i32.const 652)
+                 )
+                )
+                (i32.const -1)
+               )
+              )
+              (local.tee $3
+               (local.get $1)
+              )
+             )
+             (i32.add
+              (i32.sub
+               (local.get $5)
+               (local.get $3)
+              )
+              (i32.and
+               (i32.add
+                (local.get $2)
+                (local.get $3)
+               )
+               (i32.sub
+                (i32.const 0)
+                (local.get $4)
+               )
+              )
+             )
+             (local.get $5)
+            )
+           )
+           (local.set $9
+            (i32.add
+             (local.tee $4
+              (i32.load
+               (i32.const 608)
+              )
+             )
+             (local.get $3)
+            )
+           )
+           (if
+            (i32.and
+             (i32.gt_u
+              (local.get $3)
+              (local.get $0)
+             )
+             (i32.lt_u
+              (local.get $3)
+              (i32.const 2147483647)
+             )
+            )
+            (block $block448
+             (if
+              (local.tee $2
+               (i32.load
+                (i32.const 616)
+               )
+              )
+              (br_if $label$break$L279
+               (i32.or
+                (i32.le_u
+                 (local.get $9)
+                 (local.get $4)
+                )
+                (i32.gt_u
+                 (local.get $9)
+                 (local.get $2)
+                )
+               )
+              )
+             )
+             (br_if $__rjti$13
+              (i32.eq
+               (local.tee $2
+                (call $_sbrk
+                 (local.get $3)
+                )
+               )
+               (local.get $1)
+              )
+             )
+             (br $__rjti$5)
+            )
+           )
+          )
+         )
+         (br $label$break$L279)
+        )
+        (local.set $1
+         (local.get $3)
+        )
+        (local.set $4
+         (i32.sub
+          (i32.const 0)
+          (local.get $1)
+         )
+        )
+        (if
+         (i32.and
+          (i32.gt_u
+           (local.get $11)
+           (local.get $1)
+          )
+          (i32.and
+           (i32.lt_u
+            (local.get $1)
+            (i32.const 2147483647)
+           )
+           (i32.ne
+            (local.get $2)
+            (i32.const -1)
+           )
+          )
+         )
+         (if
+          (i32.lt_u
+           (local.tee $3
+            (i32.and
+             (i32.add
+              (i32.sub
+               (local.get $8)
+               (local.get $1)
+              )
+              (local.tee $3
+               (i32.load
+                (i32.const 656)
+               )
+              )
+             )
+             (i32.sub
+              (i32.const 0)
+              (local.get $3)
+             )
+            )
+           )
+           (i32.const 2147483647)
+          )
+          (if
+           (i32.eq
+            (call $_sbrk
+             (local.get $3)
+            )
+            (i32.const -1)
+           )
+           (block $block453
+            (drop
+             (call $_sbrk
+              (local.get $4)
+             )
+            )
+            (br $label$break$L279)
+           )
+           (local.set $3
+            (i32.add
+             (local.get $3)
+             (local.get $1)
+            )
+           )
+          )
+          (local.set $3
+           (local.get $1)
+          )
+         )
+         (local.set $3
+          (local.get $1)
+         )
+        )
+        (if
+         (i32.ne
+          (local.get $2)
+          (i32.const -1)
+         )
+         (block $block455
+          (local.set $1
+           (local.get $2)
+          )
+          (br $__rjti$13)
+         )
+        )
+       )
+       (i32.store
+        (i32.const 620)
+        (i32.or
+         (i32.load
+          (i32.const 620)
+         )
+         (i32.const 4)
+        )
+       )
+      )
+     )
+     (if
+      (i32.lt_u
+       (local.get $5)
+       (i32.const 2147483647)
+      )
+      (if
+       (i32.and
+        (i32.lt_u
+         (local.tee $1
+          (call $_sbrk
+           (local.get $5)
+          )
+         )
+         (local.tee $3
+          (call $_sbrk
+           (i32.const 0)
+          )
+         )
+        )
+        (i32.and
+         (i32.ne
+          (local.get $1)
+          (i32.const -1)
+         )
+         (i32.ne
+          (local.get $3)
+          (i32.const -1)
+         )
+        )
+       )
+       (br_if $__rjti$13
+        (i32.gt_u
+         (local.tee $3
+          (i32.sub
+           (local.get $3)
+           (local.get $1)
+          )
+         )
+         (i32.add
+          (local.get $0)
+          (i32.const 40)
+         )
+        )
+       )
+      )
+     )
+     (br $__rjto$13)
+    )
+    (i32.store
+     (i32.const 608)
+     (local.tee $2
+      (i32.add
+       (i32.load
+        (i32.const 608)
+       )
+       (local.get $3)
+      )
+     )
+    )
+    (if
+     (i32.gt_u
+      (local.get $2)
+      (i32.load
+       (i32.const 612)
+      )
+     )
+     (i32.store
+      (i32.const 612)
+      (local.get $2)
+     )
+    )
+    (block $do-once40
+     (if
+      (local.tee $6
+       (i32.load
+        (i32.const 200)
+       )
+      )
+      (block $block460
+       (local.set $2
+        (i32.const 624)
+       )
+       (block $__rjto$10
+        (block $__rjti$10
+         (loop $while-in45
+          (br_if $__rjti$10
+           (i32.eq
+            (local.get $1)
+            (i32.add
+             (local.tee $11
+              (i32.load
+               (local.get $2)
+              )
+             )
+             (local.tee $5
+              (i32.load
+               (local.tee $4
+                (i32.add
+                 (local.get $2)
+                 (i32.const 4)
+                )
+               )
+              )
+             )
+            )
+           )
+          )
+          (br_if $while-in45
+           (local.tee $2
+            (i32.load offset=8
+             (local.get $2)
+            )
+           )
+          )
+         )
+         (br $__rjto$10)
+        )
+        (if
+         (i32.eqz
+          (i32.and
+           (i32.load offset=12
+            (local.get $2)
+           )
+           (i32.const 8)
+          )
+         )
+         (if
+          (i32.and
+           (i32.lt_u
+            (local.get $6)
+            (local.get $1)
+           )
+           (i32.ge_u
+            (local.get $6)
+            (local.get $11)
+           )
+          )
+          (block $block463
+           (i32.store
+            (local.get $4)
+            (i32.add
+             (local.get $5)
+             (local.get $3)
+            )
+           )
+           (local.set $2
+            (i32.add
+             (local.get $6)
+             (local.tee $1
+              (select
+               (i32.and
+                (i32.sub
+                 (i32.const 0)
+                 (local.tee $1
+                  (i32.add
+                   (local.get $6)
+                   (i32.const 8)
+                  )
+                 )
+                )
+                (i32.const 7)
+               )
+               (i32.const 0)
+               (i32.and
+                (local.get $1)
+                (i32.const 7)
+               )
+              )
+             )
+            )
+           )
+           (local.set $1
+            (i32.add
+             (i32.sub
+              (local.get $3)
+              (local.get $1)
+             )
+             (i32.load
+              (i32.const 188)
+             )
+            )
+           )
+           (i32.store
+            (i32.const 200)
+            (local.get $2)
+           )
+           (i32.store
+            (i32.const 188)
+            (local.get $1)
+           )
+           (i32.store offset=4
+            (local.get $2)
+            (i32.or
+             (local.get $1)
+             (i32.const 1)
+            )
+           )
+           (i32.store offset=4
+            (i32.add
+             (local.get $2)
+             (local.get $1)
+            )
+            (i32.const 40)
+           )
+           (i32.store
+            (i32.const 204)
+            (i32.load
+             (i32.const 664)
+            )
+           )
+           (br $do-once40)
+          )
+         )
+        )
+       )
+       (if
+        (i32.lt_u
+         (local.get $1)
+         (local.tee $4
+          (i32.load
+           (i32.const 192)
+          )
+         )
+        )
+        (block $block465
+         (i32.store
+          (i32.const 192)
+          (local.get $1)
+         )
+         (local.set $4
+          (local.get $1)
+         )
+        )
+       )
+       (local.set $11
+        (i32.add
+         (local.get $1)
+         (local.get $3)
+        )
+       )
+       (local.set $2
+        (i32.const 624)
+       )
+       (block $__rjto$11
+        (block $__rjti$11
+         (loop $while-in47
+          (if
+           (i32.eq
+            (i32.load
+             (local.get $2)
+            )
+            (local.get $11)
+           )
+           (block $block467
+            (local.set $5
+             (local.get $2)
+            )
+            (br $__rjti$11)
+           )
+          )
+          (br_if $while-in47
+           (local.tee $2
+            (i32.load offset=8
+             (local.get $2)
+            )
+           )
+          )
+          (local.set $4
+           (i32.const 624)
+          )
+         )
+         (br $__rjto$11)
+        )
+        (if
+         (i32.and
+          (i32.load offset=12
+           (local.get $2)
+          )
+          (i32.const 8)
+         )
+         (local.set $4
+          (i32.const 624)
+         )
+         (block $block469
+          (i32.store
+           (local.get $5)
+           (local.get $1)
+          )
+          (i32.store
+           (local.tee $2
+            (i32.add
+             (local.get $2)
+             (i32.const 4)
+            )
+           )
+           (i32.add
+            (i32.load
+             (local.get $2)
+            )
+            (local.get $3)
+           )
+          )
+          (local.set $8
+           (i32.add
+            (local.tee $9
+             (i32.add
+              (local.get $1)
+              (select
+               (i32.and
+                (i32.sub
+                 (i32.const 0)
+                 (local.tee $1
+                  (i32.add
+                   (local.get $1)
+                   (i32.const 8)
+                  )
+                 )
+                )
+                (i32.const 7)
+               )
+               (i32.const 0)
+               (i32.and
+                (local.get $1)
+                (i32.const 7)
+               )
+              )
+             )
+            )
+            (local.get $0)
+           )
+          )
+          (local.set $7
+           (i32.sub
+            (i32.sub
+             (local.tee $5
+              (i32.add
+               (local.get $11)
+               (select
+                (i32.and
+                 (i32.sub
+                  (i32.const 0)
+                  (local.tee $1
+                   (i32.add
+                    (local.get $11)
+                    (i32.const 8)
+                   )
+                  )
+                 )
+                 (i32.const 7)
+                )
+                (i32.const 0)
+                (i32.and
+                 (local.get $1)
+                 (i32.const 7)
+                )
+               )
+              )
+             )
+             (local.get $9)
+            )
+            (local.get $0)
+           )
+          )
+          (i32.store offset=4
+           (local.get $9)
+           (i32.or
+            (local.get $0)
+            (i32.const 3)
+           )
+          )
+          (block $do-once48
+           (if
+            (i32.eq
+             (local.get $5)
+             (local.get $6)
+            )
+            (block $block471
+             (i32.store
+              (i32.const 188)
+              (local.tee $0
+               (i32.add
+                (i32.load
+                 (i32.const 188)
+                )
+                (local.get $7)
+               )
+              )
+             )
+             (i32.store
+              (i32.const 200)
+              (local.get $8)
+             )
+             (i32.store offset=4
+              (local.get $8)
+              (i32.or
+               (local.get $0)
+               (i32.const 1)
+              )
+             )
+            )
+            (block $block472
+             (if
+              (i32.eq
+               (local.get $5)
+               (i32.load
+                (i32.const 196)
+               )
+              )
+              (block $block474
+               (i32.store
+                (i32.const 184)
+                (local.tee $0
+                 (i32.add
+                  (i32.load
+                   (i32.const 184)
+                  )
+                  (local.get $7)
+                 )
+                )
+               )
+               (i32.store
+                (i32.const 196)
+                (local.get $8)
+               )
+               (i32.store offset=4
+                (local.get $8)
+                (i32.or
+                 (local.get $0)
+                 (i32.const 1)
+                )
+               )
+               (i32.store
+                (i32.add
+                 (local.get $8)
+                 (local.get $0)
+                )
+                (local.get $0)
+               )
+               (br $do-once48)
+              )
+             )
+             (i32.store
+              (local.tee $0
+               (i32.add
+                (local.tee $0
+                 (if (result i32)
+                  (i32.eq
+                   (i32.and
+                    (local.tee $0
+                     (i32.load offset=4
+                      (local.get $5)
+                     )
+                    )
+                    (i32.const 3)
+                   )
+                   (i32.const 1)
+                  )
+                  (block $block476 (result i32)
+                   (local.set $11
+                    (i32.and
+                     (local.get $0)
+                     (i32.const -8)
+                    )
+                   )
+                   (local.set $1
+                    (i32.shr_u
+                     (local.get $0)
+                     (i32.const 3)
+                    )
+                   )
+                   (block $label$break$L331
+                    (if
+                     (i32.lt_u
+                      (local.get $0)
+                      (i32.const 256)
+                     )
+                     (block $block478
+                      (local.set $2
+                       (i32.load offset=12
+                        (local.get $5)
+                       )
+                      )
+                      (block $do-once51
+                       (if
+                        (i32.ne
+                         (local.tee $3
+                          (i32.load offset=8
+                           (local.get $5)
+                          )
+                         )
+                         (local.tee $0
+                          (i32.add
+                           (i32.shl
+                            (local.get $1)
+                            (i32.const 3)
+                           )
+                           (i32.const 216)
+                          )
+                         )
+                        )
+                        (block $block480
+                         (if
+                          (i32.lt_u
+                           (local.get $3)
+                           (local.get $4)
+                          )
+                          (call $_abort)
+                         )
+                         (br_if $do-once51
+                          (i32.eq
+                           (i32.load offset=12
+                            (local.get $3)
+                           )
+                           (local.get $5)
+                          )
+                         )
+                         (call $_abort)
+                        )
+                       )
+                      )
+                      (if
+                       (i32.eq
+                        (local.get $2)
+                        (local.get $3)
+                       )
+                       (block $block483
+                        (i32.store
+                         (i32.const 176)
+                         (i32.and
+                          (i32.load
+                           (i32.const 176)
+                          )
+                          (i32.xor
+                           (i32.shl
+                            (i32.const 1)
+                            (local.get $1)
+                           )
+                           (i32.const -1)
+                          )
+                         )
+                        )
+                        (br $label$break$L331)
+                       )
+                      )
+                      (block $do-once53
+                       (if
+                        (i32.eq
+                         (local.get $2)
+                         (local.get $0)
+                        )
+                        (local.set $15
+                         (i32.add
+                          (local.get $2)
+                          (i32.const 8)
+                         )
+                        )
+                        (block $block485
+                         (if
+                          (i32.lt_u
+                           (local.get $2)
+                           (local.get $4)
+                          )
+                          (call $_abort)
+                         )
+                         (if
+                          (i32.eq
+                           (i32.load
+                            (local.tee $0
+                             (i32.add
+                              (local.get $2)
+                              (i32.const 8)
+                             )
+                            )
+                           )
+                           (local.get $5)
+                          )
+                          (block $block488
+                           (local.set $15
+                            (local.get $0)
+                           )
+                           (br $do-once53)
+                          )
+                         )
+                         (call $_abort)
+                        )
+                       )
+                      )
+                      (i32.store offset=12
+                       (local.get $3)
+                       (local.get $2)
+                      )
+                      (i32.store
+                       (local.get $15)
+                       (local.get $3)
+                      )
+                     )
+                     (block $block489
+                      (local.set $6
+                       (i32.load offset=24
+                        (local.get $5)
+                       )
+                      )
+                      (block $do-once55
+                       (if
+                        (i32.eq
+                         (local.tee $0
+                          (i32.load offset=12
+                           (local.get $5)
+                          )
+                         )
+                         (local.get $5)
+                        )
+                        (block $block491
+                         (if
+                          (i32.eqz
+                           (local.tee $1
+                            (i32.load
+                             (local.tee $0
+                              (i32.add
+                               (local.tee $3
+                                (i32.add
+                                 (local.get $5)
+                                 (i32.const 16)
+                                )
+                               )
+                               (i32.const 4)
+                              )
+                             )
+                            )
+                           )
+                          )
+                          (if
+                           (local.tee $1
+                            (i32.load
+                             (local.get $3)
+                            )
+                           )
+                           (local.set $0
+                            (local.get $3)
+                           )
+                           (block $block494
+                            (local.set $12
+                             (i32.const 0)
+                            )
+                            (br $do-once55)
+                           )
+                          )
+                         )
+                         (loop $while-in58
+                          (if
+                           (local.tee $3
+                            (i32.load
+                             (local.tee $2
+                              (i32.add
+                               (local.get $1)
+                               (i32.const 20)
+                              )
+                             )
+                            )
+                           )
+                           (block $block496
+                            (local.set $1
+                             (local.get $3)
+                            )
+                            (local.set $0
+                             (local.get $2)
+                            )
+                            (br $while-in58)
+                           )
+                          )
+                          (if
+                           (local.tee $3
+                            (i32.load
+                             (local.tee $2
+                              (i32.add
+                               (local.get $1)
+                               (i32.const 16)
+                              )
+                             )
+                            )
+                           )
+                           (block $block498
+                            (local.set $1
+                             (local.get $3)
+                            )
+                            (local.set $0
+                             (local.get $2)
+                            )
+                            (br $while-in58)
+                           )
+                          )
+                         )
+                         (if
+                          (i32.lt_u
+                           (local.get $0)
+                           (local.get $4)
+                          )
+                          (call $_abort)
+                          (block $block500
+                           (i32.store
+                            (local.get $0)
+                            (i32.const 0)
+                           )
+                           (local.set $12
+                            (local.get $1)
+                           )
+                          )
+                         )
+                        )
+                        (block $block501
+                         (if
+                          (i32.lt_u
+                           (local.tee $2
+                            (i32.load offset=8
+                             (local.get $5)
+                            )
+                           )
+                           (local.get $4)
+                          )
+                          (call $_abort)
+                         )
+                         (if
+                          (i32.ne
+                           (i32.load
+                            (local.tee $3
+                             (i32.add
+                              (local.get $2)
+                              (i32.const 12)
+                             )
+                            )
+                           )
+                           (local.get $5)
+                          )
+                          (call $_abort)
+                         )
+                         (if
+                          (i32.eq
+                           (i32.load
+                            (local.tee $1
+                             (i32.add
+                              (local.get $0)
+                              (i32.const 8)
+                             )
+                            )
+                           )
+                           (local.get $5)
+                          )
+                          (block $block505
+                           (i32.store
+                            (local.get $3)
+                            (local.get $0)
+                           )
+                           (i32.store
+                            (local.get $1)
+                            (local.get $2)
+                           )
+                           (local.set $12
+                            (local.get $0)
+                           )
+                          )
+                          (call $_abort)
+                         )
+                        )
+                       )
+                      )
+                      (br_if $label$break$L331
+                       (i32.eqz
+                        (local.get $6)
+                       )
+                      )
+                      (block $do-once59
+                       (if
+                        (i32.eq
+                         (local.get $5)
+                         (i32.load
+                          (local.tee $0
+                           (i32.add
+                            (i32.shl
+                             (local.tee $1
+                              (i32.load offset=28
+                               (local.get $5)
+                              )
+                             )
+                             (i32.const 2)
+                            )
+                            (i32.const 480)
+                           )
+                          )
+                         )
+                        )
+                        (block $block507
+                         (i32.store
+                          (local.get $0)
+                          (local.get $12)
+                         )
+                         (br_if $do-once59
+                          (local.get $12)
+                         )
+                         (i32.store
+                          (i32.const 180)
+                          (i32.and
+                           (i32.load
+                            (i32.const 180)
+                           )
+                           (i32.xor
+                            (i32.shl
+                             (i32.const 1)
+                             (local.get $1)
+                            )
+                            (i32.const -1)
+                           )
+                          )
+                         )
+                         (br $label$break$L331)
+                        )
+                        (block $block508
+                         (if
+                          (i32.lt_u
+                           (local.get $6)
+                           (i32.load
+                            (i32.const 192)
+                           )
+                          )
+                          (call $_abort)
+                         )
+                         (if
+                          (i32.eq
+                           (i32.load
+                            (local.tee $0
+                             (i32.add
+                              (local.get $6)
+                              (i32.const 16)
+                             )
+                            )
+                           )
+                           (local.get $5)
+                          )
+                          (i32.store
+                           (local.get $0)
+                           (local.get $12)
+                          )
+                          (i32.store offset=20
+                           (local.get $6)
+                           (local.get $12)
+                          )
+                         )
+                         (br_if $label$break$L331
+                          (i32.eqz
+                           (local.get $12)
+                          )
+                         )
+                        )
+                       )
+                      )
+                      (if
+                       (i32.lt_u
+                        (local.get $12)
+                        (local.tee $1
+                         (i32.load
+                          (i32.const 192)
+                         )
+                        )
+                       )
+                       (call $_abort)
+                      )
+                      (i32.store offset=24
+                       (local.get $12)
+                       (local.get $6)
+                      )
+                      (if
+                       (local.tee $3
+                        (i32.load
+                         (local.tee $0
+                          (i32.add
+                           (local.get $5)
+                           (i32.const 16)
+                          )
+                         )
+                        )
+                       )
+                       (if
+                        (i32.lt_u
+                         (local.get $3)
+                         (local.get $1)
+                        )
+                        (call $_abort)
+                        (block $block514
+                         (i32.store offset=16
+                          (local.get $12)
+                          (local.get $3)
+                         )
+                         (i32.store offset=24
+                          (local.get $3)
+                          (local.get $12)
+                         )
+                        )
+                       )
+                      )
+                      (br_if $label$break$L331
+                       (i32.eqz
+                        (local.tee $0
+                         (i32.load offset=4
+                          (local.get $0)
+                         )
+                        )
+                       )
+                      )
+                      (if
+                       (i32.lt_u
+                        (local.get $0)
+                        (i32.load
+                         (i32.const 192)
+                        )
+                       )
+                       (call $_abort)
+                       (block $block516
+                        (i32.store offset=20
+                         (local.get $12)
+                         (local.get $0)
+                        )
+                        (i32.store offset=24
+                         (local.get $0)
+                         (local.get $12)
+                        )
+                       )
+                      )
+                     )
+                    )
+                   )
+                   (local.set $7
+                    (i32.add
+                     (local.get $11)
+                     (local.get $7)
+                    )
+                   )
+                   (i32.add
+                    (local.get $5)
+                    (local.get $11)
+                   )
+                  )
+                  (local.get $5)
+                 )
+                )
+                (i32.const 4)
+               )
+              )
+              (i32.and
+               (i32.load
+                (local.get $0)
+               )
+               (i32.const -2)
+              )
+             )
+             (i32.store offset=4
+              (local.get $8)
+              (i32.or
+               (local.get $7)
+               (i32.const 1)
+              )
+             )
+             (i32.store
+              (i32.add
+               (local.get $8)
+               (local.get $7)
+              )
+              (local.get $7)
+             )
+             (local.set $0
+              (i32.shr_u
+               (local.get $7)
+               (i32.const 3)
+              )
+             )
+             (if
+              (i32.lt_u
+               (local.get $7)
+               (i32.const 256)
+              )
+              (block $block518
+               (local.set $3
+                (i32.add
+                 (i32.shl
+                  (local.get $0)
+                  (i32.const 3)
+                 )
+                 (i32.const 216)
+                )
+               )
+               (block $do-once63
+                (if
+                 (i32.and
+                  (local.tee $1
+                   (i32.load
+                    (i32.const 176)
+                   )
+                  )
+                  (local.tee $0
+                   (i32.shl
+                    (i32.const 1)
+                    (local.get $0)
+                   )
+                  )
+                 )
+                 (block $block520
+                  (if
+                   (i32.ge_u
+                    (local.tee $0
+                     (i32.load
+                      (local.tee $1
+                       (i32.add
+                        (local.get $3)
+                        (i32.const 8)
+                       )
+                      )
+                     )
+                    )
+                    (i32.load
+                     (i32.const 192)
+                    )
+                   )
+                   (block $block522
+                    (local.set $16
+                     (local.get $1)
+                    )
+                    (local.set $10
+                     (local.get $0)
+                    )
+                    (br $do-once63)
+                   )
+                  )
+                  (call $_abort)
+                 )
+                 (block $block523
+                  (i32.store
+                   (i32.const 176)
+                   (i32.or
+                    (local.get $1)
+                    (local.get $0)
+                   )
+                  )
+                  (local.set $16
+                   (i32.add
+                    (local.get $3)
+                    (i32.const 8)
+                   )
+                  )
+                  (local.set $10
+                   (local.get $3)
+                  )
+                 )
+                )
+               )
+               (i32.store
+                (local.get $16)
+                (local.get $8)
+               )
+               (i32.store offset=12
+                (local.get $10)
+                (local.get $8)
+               )
+               (i32.store offset=8
+                (local.get $8)
+                (local.get $10)
+               )
+               (i32.store offset=12
+                (local.get $8)
+                (local.get $3)
+               )
+               (br $do-once48)
+              )
+             )
+             (local.set $3
+              (i32.add
+               (i32.shl
+                (local.tee $2
+                 (block $do-once65 (result i32)
+                  (if (result i32)
+                   (local.tee $0
+                    (i32.shr_u
+                     (local.get $7)
+                     (i32.const 8)
+                    )
+                   )
+                   (block $block525 (result i32)
+                    (drop
+                     (br_if $do-once65
+                      (i32.const 31)
+                      (i32.gt_u
+                       (local.get $7)
+                       (i32.const 16777215)
+                      )
+                     )
+                    )
+                    (i32.or
+                     (i32.and
+                      (i32.shr_u
+                       (local.get $7)
+                       (i32.add
+                        (local.tee $0
+                         (i32.add
+                          (i32.sub
+                           (i32.const 14)
+                           (i32.or
+                            (i32.or
+                             (local.tee $0
+                              (i32.and
+                               (i32.shr_u
+                                (i32.add
+                                 (local.tee $1
+                                  (i32.shl
+                                   (local.get $0)
+                                   (local.tee $3
+                                    (i32.and
+                                     (i32.shr_u
+                                      (i32.add
+                                       (local.get $0)
+                                       (i32.const 1048320)
+                                      )
+                                      (i32.const 16)
+                                     )
+                                     (i32.const 8)
+                                    )
+                                   )
+                                  )
+                                 )
+                                 (i32.const 520192)
+                                )
+                                (i32.const 16)
+                               )
+                               (i32.const 4)
+                              )
+                             )
+                             (local.get $3)
+                            )
+                            (local.tee $0
+                             (i32.and
+                              (i32.shr_u
+                               (i32.add
+                                (local.tee $1
+                                 (i32.shl
+                                  (local.get $1)
+                                  (local.get $0)
+                                 )
+                                )
+                                (i32.const 245760)
+                               )
+                               (i32.const 16)
+                              )
+                              (i32.const 2)
+                             )
+                            )
+                           )
+                          )
+                          (i32.shr_u
+                           (i32.shl
+                            (local.get $1)
+                            (local.get $0)
+                           )
+                           (i32.const 15)
+                          )
+                         )
+                        )
+                        (i32.const 7)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                     (i32.shl
+                      (local.get $0)
+                      (i32.const 1)
+                     )
+                    )
+                   )
+                   (i32.const 0)
+                  )
+                 )
+                )
+                (i32.const 2)
+               )
+               (i32.const 480)
+              )
+             )
+             (i32.store offset=28
+              (local.get $8)
+              (local.get $2)
+             )
+             (i32.store offset=4
+              (local.tee $0
+               (i32.add
+                (local.get $8)
+                (i32.const 16)
+               )
+              )
+              (i32.const 0)
+             )
+             (i32.store
+              (local.get $0)
+              (i32.const 0)
+             )
+             (if
+              (i32.eqz
+               (i32.and
+                (local.tee $1
+                 (i32.load
+                  (i32.const 180)
+                 )
+                )
+                (local.tee $0
+                 (i32.shl
+                  (i32.const 1)
+                  (local.get $2)
+                 )
+                )
+               )
+              )
+              (block $block527
+               (i32.store
+                (i32.const 180)
+                (i32.or
+                 (local.get $1)
+                 (local.get $0)
+                )
+               )
+               (i32.store
+                (local.get $3)
+                (local.get $8)
+               )
+               (i32.store offset=24
+                (local.get $8)
+                (local.get $3)
+               )
+               (i32.store offset=12
+                (local.get $8)
+                (local.get $8)
+               )
+               (i32.store offset=8
+                (local.get $8)
+                (local.get $8)
+               )
+               (br $do-once48)
+              )
+             )
+             (local.set $2
+              (i32.shl
+               (local.get $7)
+               (select
+                (i32.const 0)
+                (i32.sub
+                 (i32.const 25)
+                 (i32.shr_u
+                  (local.get $2)
+                  (i32.const 1)
+                 )
+                )
+                (i32.eq
+                 (local.get $2)
+                 (i32.const 31)
+                )
+               )
+              )
+             )
+             (local.set $0
+              (i32.load
+               (local.get $3)
+              )
+             )
+             (block $__rjto$7
+              (block $__rjti$7
+               (loop $while-in68
+                (br_if $__rjti$7
+                 (i32.eq
+                  (i32.and
+                   (i32.load offset=4
+                    (local.get $0)
+                   )
+                   (i32.const -8)
+                  )
+                  (local.get $7)
+                 )
+                )
+                (local.set $3
+                 (i32.shl
+                  (local.get $2)
+                  (i32.const 1)
+                 )
+                )
+                (if
+                 (local.tee $1
+                  (i32.load
+                   (local.tee $2
+                    (i32.add
+                     (i32.add
+                      (local.get $0)
+                      (i32.const 16)
+                     )
+                     (i32.shl
+                      (i32.shr_u
+                       (local.get $2)
+                       (i32.const 31)
+                      )
+                      (i32.const 2)
+                     )
+                    )
+                   )
+                  )
+                 )
+                 (block $block529
+                  (local.set $2
+                   (local.get $3)
+                  )
+                  (local.set $0
+                   (local.get $1)
+                  )
+                  (br $while-in68)
+                 )
+                )
+               )
+               (if
+                (i32.lt_u
+                 (local.get $2)
+                 (i32.load
+                  (i32.const 192)
+                 )
+                )
+                (call $_abort)
+                (block $block531
+                 (i32.store
+                  (local.get $2)
+                  (local.get $8)
+                 )
+                 (i32.store offset=24
+                  (local.get $8)
+                  (local.get $0)
+                 )
+                 (i32.store offset=12
+                  (local.get $8)
+                  (local.get $8)
+                 )
+                 (i32.store offset=8
+                  (local.get $8)
+                  (local.get $8)
+                 )
+                 (br $do-once48)
+                )
+               )
+               (br $__rjto$7)
+              )
+              (if
+               (i32.and
+                (i32.ge_u
+                 (local.tee $2
+                  (i32.load
+                   (local.tee $3
+                    (i32.add
+                     (local.get $0)
+                     (i32.const 8)
+                    )
+                   )
+                  )
+                 )
+                 (local.tee $1
+                  (i32.load
+                   (i32.const 192)
+                  )
+                 )
+                )
+                (i32.ge_u
+                 (local.get $0)
+                 (local.get $1)
+                )
+               )
+               (block $block533
+                (i32.store offset=12
+                 (local.get $2)
+                 (local.get $8)
+                )
+                (i32.store
+                 (local.get $3)
+                 (local.get $8)
+                )
+                (i32.store offset=8
+                 (local.get $8)
+                 (local.get $2)
+                )
+                (i32.store offset=12
+                 (local.get $8)
+                 (local.get $0)
+                )
+                (i32.store offset=24
+                 (local.get $8)
+                 (i32.const 0)
+                )
+               )
+               (call $_abort)
+              )
+             )
+            )
+           )
+          )
+          (return
+           (i32.add
+            (local.get $9)
+            (i32.const 8)
+           )
+          )
+         )
+        )
+       )
+       (loop $while-in70
+        (block $while-out69
+         (if
+          (i32.le_u
+           (local.tee $2
+            (i32.load
+             (local.get $4)
+            )
+           )
+           (local.get $6)
+          )
+          (br_if $while-out69
+           (i32.gt_u
+            (local.tee $2
+             (i32.add
+              (local.get $2)
+              (i32.load offset=4
+               (local.get $4)
+              )
+             )
+            )
+            (local.get $6)
+           )
+          )
+         )
+         (local.set $4
+          (i32.load offset=8
+           (local.get $4)
+          )
+         )
+         (br $while-in70)
+        )
+       )
+       (local.set $10
+        (i32.add
+         (local.tee $4
+          (i32.add
+           (local.get $2)
+           (i32.const -47)
+          )
+         )
+         (i32.const 8)
+        )
+       )
+       (local.set $12
+        (i32.add
+         (local.tee $11
+          (select
+           (local.get $6)
+           (local.tee $4
+            (i32.add
+             (local.get $4)
+             (select
+              (i32.and
+               (i32.sub
+                (i32.const 0)
+                (local.get $10)
+               )
+               (i32.const 7)
+              )
+              (i32.const 0)
+              (i32.and
+               (local.get $10)
+               (i32.const 7)
+              )
+             )
+            )
+           )
+           (i32.lt_u
+            (local.get $4)
+            (local.tee $10
+             (i32.add
+              (local.get $6)
+              (i32.const 16)
+             )
+            )
+           )
+          )
+         )
+         (i32.const 8)
+        )
+       )
+       (i32.store
+        (i32.const 200)
+        (local.tee $5
+         (i32.add
+          (local.get $1)
+          (local.tee $4
+           (select
+            (i32.and
+             (i32.sub
+              (i32.const 0)
+              (local.tee $4
+               (i32.add
+                (local.get $1)
+                (i32.const 8)
+               )
+              )
+             )
+             (i32.const 7)
+            )
+            (i32.const 0)
+            (i32.and
+             (local.get $4)
+             (i32.const 7)
+            )
+           )
+          )
+         )
+        )
+       )
+       (i32.store
+        (i32.const 188)
+        (local.tee $4
+         (i32.sub
+          (i32.add
+           (local.get $3)
+           (i32.const -40)
+          )
+          (local.get $4)
+         )
+        )
+       )
+       (i32.store offset=4
+        (local.get $5)
+        (i32.or
+         (local.get $4)
+         (i32.const 1)
+        )
+       )
+       (i32.store offset=4
+        (i32.add
+         (local.get $5)
+         (local.get $4)
+        )
+        (i32.const 40)
+       )
+       (i32.store
+        (i32.const 204)
+        (i32.load
+         (i32.const 664)
+        )
+       )
+       (i32.store
+        (local.tee $4
+         (i32.add
+          (local.get $11)
+          (i32.const 4)
+         )
+        )
+        (i32.const 27)
+       )
+       (i32.store
+        (local.get $12)
+        (i32.load
+         (i32.const 624)
+        )
+       )
+       (i32.store offset=4
+        (local.get $12)
+        (i32.load
+         (i32.const 628)
+        )
+       )
+       (i32.store offset=8
+        (local.get $12)
+        (i32.load
+         (i32.const 632)
+        )
+       )
+       (i32.store offset=12
+        (local.get $12)
+        (i32.load
+         (i32.const 636)
+        )
+       )
+       (i32.store
+        (i32.const 624)
+        (local.get $1)
+       )
+       (i32.store
+        (i32.const 628)
+        (local.get $3)
+       )
+       (i32.store
+        (i32.const 636)
+        (i32.const 0)
+       )
+       (i32.store
+        (i32.const 632)
+        (local.get $12)
+       )
+       (local.set $1
+        (i32.add
+         (local.get $11)
+         (i32.const 24)
+        )
+       )
+       (loop $while-in72
+        (i32.store
+         (local.tee $1
+          (i32.add
+           (local.get $1)
+           (i32.const 4)
+          )
+         )
+         (i32.const 7)
+        )
+        (br_if $while-in72
+         (i32.lt_u
+          (i32.add
+           (local.get $1)
+           (i32.const 4)
+          )
+          (local.get $2)
+         )
+        )
+       )
+       (if
+        (i32.ne
+         (local.get $11)
+         (local.get $6)
+        )
+        (block $block536
+         (i32.store
+          (local.get $4)
+          (i32.and
+           (i32.load
+            (local.get $4)
+           )
+           (i32.const -2)
+          )
+         )
+         (i32.store offset=4
+          (local.get $6)
+          (i32.or
+           (local.tee $5
+            (i32.sub
+             (local.get $11)
+             (local.get $6)
+            )
+           )
+           (i32.const 1)
+          )
+         )
+         (i32.store
+          (local.get $11)
+          (local.get $5)
+         )
+         (local.set $1
+          (i32.shr_u
+           (local.get $5)
+           (i32.const 3)
+          )
+         )
+         (if
+          (i32.lt_u
+           (local.get $5)
+           (i32.const 256)
+          )
+          (block $block538
+           (local.set $2
+            (i32.add
+             (i32.shl
+              (local.get $1)
+              (i32.const 3)
+             )
+             (i32.const 216)
+            )
+           )
+           (if
+            (i32.and
+             (local.tee $3
+              (i32.load
+               (i32.const 176)
+              )
+             )
+             (local.tee $1
+              (i32.shl
+               (i32.const 1)
+               (local.get $1)
+              )
+             )
+            )
+            (if
+             (i32.lt_u
+              (local.tee $1
+               (i32.load
+                (local.tee $3
+                 (i32.add
+                  (local.get $2)
+                  (i32.const 8)
+                 )
+                )
+               )
+              )
+              (i32.load
+               (i32.const 192)
+              )
+             )
+             (call $_abort)
+             (block $block541
+              (local.set $17
+               (local.get $3)
+              )
+              (local.set $7
+               (local.get $1)
+              )
+             )
+            )
+            (block $block542
+             (i32.store
+              (i32.const 176)
+              (i32.or
+               (local.get $3)
+               (local.get $1)
+              )
+             )
+             (local.set $17
+              (i32.add
+               (local.get $2)
+               (i32.const 8)
+              )
+             )
+             (local.set $7
+              (local.get $2)
+             )
+            )
+           )
+           (i32.store
+            (local.get $17)
+            (local.get $6)
+           )
+           (i32.store offset=12
+            (local.get $7)
+            (local.get $6)
+           )
+           (i32.store offset=8
+            (local.get $6)
+            (local.get $7)
+           )
+           (i32.store offset=12
+            (local.get $6)
+            (local.get $2)
+           )
+           (br $do-once40)
+          )
+         )
+         (local.set $2
+          (i32.add
+           (i32.shl
+            (local.tee $4
+             (if (result i32)
+              (local.tee $1
+               (i32.shr_u
+                (local.get $5)
+                (i32.const 8)
+               )
+              )
+              (if (result i32)
+               (i32.gt_u
+                (local.get $5)
+                (i32.const 16777215)
+               )
+               (i32.const 31)
+               (i32.or
+                (i32.and
+                 (i32.shr_u
+                  (local.get $5)
+                  (i32.add
+                   (local.tee $1
+                    (i32.add
+                     (i32.sub
+                      (i32.const 14)
+                      (i32.or
+                       (i32.or
+                        (local.tee $1
+                         (i32.and
+                          (i32.shr_u
+                           (i32.add
+                            (local.tee $3
+                             (i32.shl
+                              (local.get $1)
+                              (local.tee $2
+                               (i32.and
+                                (i32.shr_u
+                                 (i32.add
+                                  (local.get $1)
+                                  (i32.const 1048320)
+                                 )
+                                 (i32.const 16)
+                                )
+                                (i32.const 8)
+                               )
+                              )
+                             )
+                            )
+                            (i32.const 520192)
+                           )
+                           (i32.const 16)
+                          )
+                          (i32.const 4)
+                         )
+                        )
+                        (local.get $2)
+                       )
+                       (local.tee $1
+                        (i32.and
+                         (i32.shr_u
+                          (i32.add
+                           (local.tee $3
+                            (i32.shl
+                             (local.get $3)
+                             (local.get $1)
+                            )
+                           )
+                           (i32.const 245760)
+                          )
+                          (i32.const 16)
+                         )
+                         (i32.const 2)
+                        )
+                       )
+                      )
+                     )
+                     (i32.shr_u
+                      (i32.shl
+                       (local.get $3)
+                       (local.get $1)
+                      )
+                      (i32.const 15)
+                     )
+                    )
+                   )
+                   (i32.const 7)
+                  )
+                 )
+                 (i32.const 1)
+                )
+                (i32.shl
+                 (local.get $1)
+                 (i32.const 1)
+                )
+               )
+              )
+              (i32.const 0)
+             )
+            )
+            (i32.const 2)
+           )
+           (i32.const 480)
+          )
+         )
+         (i32.store offset=28
+          (local.get $6)
+          (local.get $4)
+         )
+         (i32.store offset=20
+          (local.get $6)
+          (i32.const 0)
+         )
+         (i32.store
+          (local.get $10)
+          (i32.const 0)
+         )
+         (if
+          (i32.eqz
+           (i32.and
+            (local.tee $3
+             (i32.load
+              (i32.const 180)
+             )
+            )
+            (local.tee $1
+             (i32.shl
+              (i32.const 1)
+              (local.get $4)
+             )
+            )
+           )
+          )
+          (block $block546
+           (i32.store
+            (i32.const 180)
+            (i32.or
+             (local.get $3)
+             (local.get $1)
+            )
+           )
+           (i32.store
+            (local.get $2)
+            (local.get $6)
+           )
+           (i32.store offset=24
+            (local.get $6)
+            (local.get $2)
+           )
+           (i32.store offset=12
+            (local.get $6)
+            (local.get $6)
+           )
+           (i32.store offset=8
+            (local.get $6)
+            (local.get $6)
+           )
+           (br $do-once40)
+          )
+         )
+         (local.set $4
+          (i32.shl
+           (local.get $5)
+           (select
+            (i32.const 0)
+            (i32.sub
+             (i32.const 25)
+             (i32.shr_u
+              (local.get $4)
+              (i32.const 1)
+             )
+            )
+            (i32.eq
+             (local.get $4)
+             (i32.const 31)
+            )
+           )
+          )
+         )
+         (local.set $1
+          (i32.load
+           (local.get $2)
+          )
+         )
+         (block $__rjto$9
+          (block $__rjti$9
+           (loop $while-in74
+            (br_if $__rjti$9
+             (i32.eq
+              (i32.and
+               (i32.load offset=4
+                (local.get $1)
+               )
+               (i32.const -8)
+              )
+              (local.get $5)
+             )
+            )
+            (local.set $2
+             (i32.shl
+              (local.get $4)
+              (i32.const 1)
+             )
+            )
+            (if
+             (local.tee $3
+              (i32.load
+               (local.tee $4
+                (i32.add
+                 (i32.add
+                  (local.get $1)
+                  (i32.const 16)
+                 )
+                 (i32.shl
+                  (i32.shr_u
+                   (local.get $4)
+                   (i32.const 31)
+                  )
+                  (i32.const 2)
+                 )
+                )
+               )
+              )
+             )
+             (block $block548
+              (local.set $4
+               (local.get $2)
+              )
+              (local.set $1
+               (local.get $3)
+              )
+              (br $while-in74)
+             )
+            )
+           )
+           (if
+            (i32.lt_u
+             (local.get $4)
+             (i32.load
+              (i32.const 192)
+             )
+            )
+            (call $_abort)
+            (block $block550
+             (i32.store
+              (local.get $4)
+              (local.get $6)
+             )
+             (i32.store offset=24
+              (local.get $6)
+              (local.get $1)
+             )
+             (i32.store offset=12
+              (local.get $6)
+              (local.get $6)
+             )
+             (i32.store offset=8
+              (local.get $6)
+              (local.get $6)
+             )
+             (br $do-once40)
+            )
+           )
+           (br $__rjto$9)
+          )
+          (if
+           (i32.and
+            (i32.ge_u
+             (local.tee $4
+              (i32.load
+               (local.tee $2
+                (i32.add
+                 (local.get $1)
+                 (i32.const 8)
+                )
+               )
+              )
+             )
+             (local.tee $3
+              (i32.load
+               (i32.const 192)
+              )
+             )
+            )
+            (i32.ge_u
+             (local.get $1)
+             (local.get $3)
+            )
+           )
+           (block $block552
+            (i32.store offset=12
+             (local.get $4)
+             (local.get $6)
+            )
+            (i32.store
+             (local.get $2)
+             (local.get $6)
+            )
+            (i32.store offset=8
+             (local.get $6)
+             (local.get $4)
+            )
+            (i32.store offset=12
+             (local.get $6)
+             (local.get $1)
+            )
+            (i32.store offset=24
+             (local.get $6)
+             (i32.const 0)
+            )
+           )
+           (call $_abort)
+          )
+         )
+        )
+       )
+      )
+      (block $block553
+       (if
+        (i32.or
+         (i32.eqz
+          (local.tee $2
+           (i32.load
+            (i32.const 192)
+           )
+          )
+         )
+         (i32.lt_u
+          (local.get $1)
+          (local.get $2)
+         )
+        )
+        (i32.store
+         (i32.const 192)
+         (local.get $1)
+        )
+       )
+       (i32.store
+        (i32.const 624)
+        (local.get $1)
+       )
+       (i32.store
+        (i32.const 628)
+        (local.get $3)
+       )
+       (i32.store
+        (i32.const 636)
+        (i32.const 0)
+       )
+       (i32.store
+        (i32.const 212)
+        (i32.load
+         (i32.const 648)
+        )
+       )
+       (i32.store
+        (i32.const 208)
+        (i32.const -1)
+       )
+       (local.set $2
+        (i32.const 0)
+       )
+       (loop $while-in43
+        (i32.store offset=12
+         (local.tee $4
+          (i32.add
+           (i32.shl
+            (local.get $2)
+            (i32.const 3)
+           )
+           (i32.const 216)
+          )
+         )
+         (local.get $4)
+        )
+        (i32.store offset=8
+         (local.get $4)
+         (local.get $4)
+        )
+        (br_if $while-in43
+         (i32.ne
+          (local.tee $2
+           (i32.add
+            (local.get $2)
+            (i32.const 1)
+           )
+          )
+          (i32.const 32)
+         )
+        )
+       )
+       (i32.store
+        (i32.const 200)
+        (local.tee $2
+         (i32.add
+          (local.get $1)
+          (local.tee $1
+           (select
+            (i32.and
+             (i32.sub
+              (i32.const 0)
+              (local.tee $1
+               (i32.add
+                (local.get $1)
+                (i32.const 8)
+               )
+              )
+             )
+             (i32.const 7)
+            )
+            (i32.const 0)
+            (i32.and
+             (local.get $1)
+             (i32.const 7)
+            )
+           )
+          )
+         )
+        )
+       )
+       (i32.store
+        (i32.const 188)
+        (local.tee $1
+         (i32.sub
+          (i32.add
+           (local.get $3)
+           (i32.const -40)
+          )
+          (local.get $1)
+         )
+        )
+       )
+       (i32.store offset=4
+        (local.get $2)
+        (i32.or
+         (local.get $1)
+         (i32.const 1)
+        )
+       )
+       (i32.store offset=4
+        (i32.add
+         (local.get $2)
+         (local.get $1)
+        )
+        (i32.const 40)
+       )
+       (i32.store
+        (i32.const 204)
+        (i32.load
+         (i32.const 664)
+        )
+       )
+      )
+     )
+    )
+    (br_if $folding-inner0
+     (i32.gt_u
+      (local.tee $1
+       (i32.load
+        (i32.const 188)
+       )
+      )
+      (local.get $0)
+     )
+    )
+   )
+   (i32.store
+    (call $___errno_location)
+    (i32.const 12)
+   )
+   (return
+    (i32.const 0)
+   )
+  )
+  (i32.store
+   (i32.const 188)
+   (local.tee $3
+    (i32.sub
+     (local.get $1)
+     (local.get $0)
+    )
+   )
+  )
+  (i32.store
+   (i32.const 200)
+   (local.tee $1
+    (i32.add
+     (local.tee $2
+      (i32.load
+       (i32.const 200)
+      )
+     )
+     (local.get $0)
+    )
+   )
+  )
+  (i32.store offset=4
+   (local.get $1)
+   (i32.or
+    (local.get $3)
+    (i32.const 1)
+   )
+  )
+  (i32.store offset=4
+   (local.get $2)
+   (i32.or
+    (local.get $0)
+    (i32.const 3)
+   )
+  )
+  (i32.add
+   (local.get $2)
+   (i32.const 8)
+  )
+ )
+ (func $_free (param $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (if
+   (i32.eqz
+    (local.get $0)
+   )
+   (return)
+  )
+  (if
+   (i32.lt_u
+    (local.tee $1
+     (i32.add
+      (local.get $0)
+      (i32.const -8)
+     )
+    )
+    (local.tee $11
+     (i32.load
+      (i32.const 192)
+     )
+    )
+   )
+   (call $_abort)
+  )
+  (if
+   (i32.eq
+    (local.tee $5
+     (i32.and
+      (local.tee $7
+       (i32.load
+        (i32.add
+         (local.get $0)
+         (i32.const -4)
+        )
+       )
+      )
+      (i32.const 3)
+     )
+    )
+    (i32.const 1)
+   )
+   (call $_abort)
+  )
+  (local.set $8
+   (i32.add
+    (local.get $1)
+    (local.tee $0
+     (i32.and
+      (local.get $7)
+      (i32.const -8)
+     )
+    )
+   )
+  )
+  (block $do-once
+   (if
+    (i32.and
+     (local.get $7)
+     (i32.const 1)
+    )
+    (block $block
+     (local.set $2
+      (local.get $1)
+     )
+     (local.set $3
+      (local.get $0)
+     )
+    )
+    (block $block558
+     (local.set $7
+      (i32.load
+       (local.get $1)
+      )
+     )
+     (if
+      (i32.eqz
+       (local.get $5)
+      )
+      (return)
+     )
+     (if
+      (i32.lt_u
+       (local.tee $1
+        (i32.add
+         (local.get $1)
+         (i32.sub
+          (i32.const 0)
+          (local.get $7)
+         )
+        )
+       )
+       (local.get $11)
+      )
+      (call $_abort)
+     )
+     (local.set $0
+      (i32.add
+       (local.get $7)
+       (local.get $0)
+      )
+     )
+     (if
+      (i32.eq
+       (local.get $1)
+       (i32.load
+        (i32.const 196)
+       )
+      )
+      (block $block562
+       (if
+        (i32.ne
+         (i32.and
+          (local.tee $3
+           (i32.load
+            (local.tee $2
+             (i32.add
+              (local.get $8)
+              (i32.const 4)
+             )
+            )
+           )
+          )
+          (i32.const 3)
+         )
+         (i32.const 3)
+        )
+        (block $block564
+         (local.set $2
+          (local.get $1)
+         )
+         (local.set $3
+          (local.get $0)
+         )
+         (br $do-once)
+        )
+       )
+       (i32.store
+        (i32.const 184)
+        (local.get $0)
+       )
+       (i32.store
+        (local.get $2)
+        (i32.and
+         (local.get $3)
+         (i32.const -2)
+        )
+       )
+       (i32.store offset=4
+        (local.get $1)
+        (i32.or
+         (local.get $0)
+         (i32.const 1)
+        )
+       )
+       (i32.store
+        (i32.add
+         (local.get $1)
+         (local.get $0)
+        )
+        (local.get $0)
+       )
+       (return)
+      )
+     )
+     (local.set $5
+      (i32.shr_u
+       (local.get $7)
+       (i32.const 3)
+      )
+     )
+     (if
+      (i32.lt_u
+       (local.get $7)
+       (i32.const 256)
+      )
+      (block $block566
+       (local.set $6
+        (i32.load offset=12
+         (local.get $1)
+        )
+       )
+       (if
+        (i32.ne
+         (local.tee $2
+          (i32.load offset=8
+           (local.get $1)
+          )
+         )
+         (local.tee $3
+          (i32.add
+           (i32.shl
+            (local.get $5)
+            (i32.const 3)
+           )
+           (i32.const 216)
+          )
+         )
+        )
+        (block $block568
+         (if
+          (i32.lt_u
+           (local.get $2)
+           (local.get $11)
+          )
+          (call $_abort)
+         )
+         (if
+          (i32.ne
+           (i32.load offset=12
+            (local.get $2)
+           )
+           (local.get $1)
+          )
+          (call $_abort)
+         )
+        )
+       )
+       (if
+        (i32.eq
+         (local.get $6)
+         (local.get $2)
+        )
+        (block $block572
+         (i32.store
+          (i32.const 176)
+          (i32.and
+           (i32.load
+            (i32.const 176)
+           )
+           (i32.xor
+            (i32.shl
+             (i32.const 1)
+             (local.get $5)
+            )
+            (i32.const -1)
+           )
+          )
+         )
+         (local.set $2
+          (local.get $1)
+         )
+         (local.set $3
+          (local.get $0)
+         )
+         (br $do-once)
+        )
+       )
+       (if
+        (i32.eq
+         (local.get $6)
+         (local.get $3)
+        )
+        (local.set $4
+         (i32.add
+          (local.get $6)
+          (i32.const 8)
+         )
+        )
+        (block $block574
+         (if
+          (i32.lt_u
+           (local.get $6)
+           (local.get $11)
+          )
+          (call $_abort)
+         )
+         (if
+          (i32.eq
+           (i32.load
+            (local.tee $3
+             (i32.add
+              (local.get $6)
+              (i32.const 8)
+             )
+            )
+           )
+           (local.get $1)
+          )
+          (local.set $4
+           (local.get $3)
+          )
+          (call $_abort)
+         )
+        )
+       )
+       (i32.store offset=12
+        (local.get $2)
+        (local.get $6)
+       )
+       (i32.store
+        (local.get $4)
+        (local.get $2)
+       )
+       (local.set $2
+        (local.get $1)
+       )
+       (local.set $3
+        (local.get $0)
+       )
+       (br $do-once)
+      )
+     )
+     (local.set $12
+      (i32.load offset=24
+       (local.get $1)
+      )
+     )
+     (block $do-once0
+      (if
+       (i32.eq
+        (local.tee $4
+         (i32.load offset=12
+          (local.get $1)
+         )
+        )
+        (local.get $1)
+       )
+       (block $block578
+        (if
+         (i32.eqz
+          (local.tee $5
+           (i32.load
+            (local.tee $4
+             (i32.add
+              (local.tee $7
+               (i32.add
+                (local.get $1)
+                (i32.const 16)
+               )
+              )
+              (i32.const 4)
+             )
+            )
+           )
+          )
+         )
+         (if
+          (local.tee $5
+           (i32.load
+            (local.get $7)
+           )
+          )
+          (local.set $4
+           (local.get $7)
+          )
+          (block $block581
+           (local.set $6
+            (i32.const 0)
+           )
+           (br $do-once0)
+          )
+         )
+        )
+        (loop $while-in
+         (if
+          (local.tee $7
+           (i32.load
+            (local.tee $10
+             (i32.add
+              (local.get $5)
+              (i32.const 20)
+             )
+            )
+           )
+          )
+          (block $block583
+           (local.set $5
+            (local.get $7)
+           )
+           (local.set $4
+            (local.get $10)
+           )
+           (br $while-in)
+          )
+         )
+         (if
+          (local.tee $7
+           (i32.load
+            (local.tee $10
+             (i32.add
+              (local.get $5)
+              (i32.const 16)
+             )
+            )
+           )
+          )
+          (block $block585
+           (local.set $5
+            (local.get $7)
+           )
+           (local.set $4
+            (local.get $10)
+           )
+           (br $while-in)
+          )
+         )
+        )
+        (if
+         (i32.lt_u
+          (local.get $4)
+          (local.get $11)
+         )
+         (call $_abort)
+         (block $block587
+          (i32.store
+           (local.get $4)
+           (i32.const 0)
+          )
+          (local.set $6
+           (local.get $5)
+          )
+         )
+        )
+       )
+       (block $block588
+        (if
+         (i32.lt_u
+          (local.tee $10
+           (i32.load offset=8
+            (local.get $1)
+           )
+          )
+          (local.get $11)
+         )
+         (call $_abort)
+        )
+        (if
+         (i32.ne
+          (i32.load
+           (local.tee $7
+            (i32.add
+             (local.get $10)
+             (i32.const 12)
+            )
+           )
+          )
+          (local.get $1)
+         )
+         (call $_abort)
+        )
+        (if
+         (i32.eq
+          (i32.load
+           (local.tee $5
+            (i32.add
+             (local.get $4)
+             (i32.const 8)
+            )
+           )
+          )
+          (local.get $1)
+         )
+         (block $block592
+          (i32.store
+           (local.get $7)
+           (local.get $4)
+          )
+          (i32.store
+           (local.get $5)
+           (local.get $10)
+          )
+          (local.set $6
+           (local.get $4)
+          )
+         )
+         (call $_abort)
+        )
+       )
+      )
+     )
+     (if
+      (local.get $12)
+      (block $block594
+       (if
+        (i32.eq
+         (local.get $1)
+         (i32.load
+          (local.tee $4
+           (i32.add
+            (i32.shl
+             (local.tee $5
+              (i32.load offset=28
+               (local.get $1)
+              )
+             )
+             (i32.const 2)
+            )
+            (i32.const 480)
+           )
+          )
+         )
+        )
+        (block $block596
+         (i32.store
+          (local.get $4)
+          (local.get $6)
+         )
+         (if
+          (i32.eqz
+           (local.get $6)
+          )
+          (block $block598
+           (i32.store
+            (i32.const 180)
+            (i32.and
+             (i32.load
+              (i32.const 180)
+             )
+             (i32.xor
+              (i32.shl
+               (i32.const 1)
+               (local.get $5)
+              )
+              (i32.const -1)
+             )
+            )
+           )
+           (local.set $2
+            (local.get $1)
+           )
+           (local.set $3
+            (local.get $0)
+           )
+           (br $do-once)
+          )
+         )
+        )
+        (block $block599
+         (if
+          (i32.lt_u
+           (local.get $12)
+           (i32.load
+            (i32.const 192)
+           )
+          )
+          (call $_abort)
+         )
+         (if
+          (i32.eq
+           (i32.load
+            (local.tee $4
+             (i32.add
+              (local.get $12)
+              (i32.const 16)
+             )
+            )
+           )
+           (local.get $1)
+          )
+          (i32.store
+           (local.get $4)
+           (local.get $6)
+          )
+          (i32.store offset=20
+           (local.get $12)
+           (local.get $6)
+          )
+         )
+         (if
+          (i32.eqz
+           (local.get $6)
+          )
+          (block $block603
+           (local.set $2
+            (local.get $1)
+           )
+           (local.set $3
+            (local.get $0)
+           )
+           (br $do-once)
+          )
+         )
+        )
+       )
+       (if
+        (i32.lt_u
+         (local.get $6)
+         (local.tee $5
+          (i32.load
+           (i32.const 192)
+          )
+         )
+        )
+        (call $_abort)
+       )
+       (i32.store offset=24
+        (local.get $6)
+        (local.get $12)
+       )
+       (if
+        (local.tee $7
+         (i32.load
+          (local.tee $4
+           (i32.add
+            (local.get $1)
+            (i32.const 16)
+           )
+          )
+         )
+        )
+        (if
+         (i32.lt_u
+          (local.get $7)
+          (local.get $5)
+         )
+         (call $_abort)
+         (block $block607
+          (i32.store offset=16
+           (local.get $6)
+           (local.get $7)
+          )
+          (i32.store offset=24
+           (local.get $7)
+           (local.get $6)
+          )
+         )
+        )
+       )
+       (if
+        (local.tee $4
+         (i32.load offset=4
+          (local.get $4)
+         )
+        )
+        (if
+         (i32.lt_u
+          (local.get $4)
+          (i32.load
+           (i32.const 192)
+          )
+         )
+         (call $_abort)
+         (block $block610
+          (i32.store offset=20
+           (local.get $6)
+           (local.get $4)
+          )
+          (i32.store offset=24
+           (local.get $4)
+           (local.get $6)
+          )
+          (local.set $2
+           (local.get $1)
+          )
+          (local.set $3
+           (local.get $0)
+          )
+         )
+        )
+        (block $block611
+         (local.set $2
+          (local.get $1)
+         )
+         (local.set $3
+          (local.get $0)
+         )
+        )
+       )
+      )
+      (block $block612
+       (local.set $2
+        (local.get $1)
+       )
+       (local.set $3
+        (local.get $0)
+       )
+      )
+     )
+    )
+   )
+  )
+  (if
+   (i32.ge_u
+    (local.get $2)
+    (local.get $8)
+   )
+   (call $_abort)
+  )
+  (if
+   (i32.eqz
+    (i32.and
+     (local.tee $1
+      (i32.load
+       (local.tee $0
+        (i32.add
+         (local.get $8)
+         (i32.const 4)
+        )
+       )
+      )
+     )
+     (i32.const 1)
+    )
+   )
+   (call $_abort)
+  )
+  (if
+   (i32.and
+    (local.get $1)
+    (i32.const 2)
+   )
+   (block $block616
+    (i32.store
+     (local.get $0)
+     (i32.and
+      (local.get $1)
+      (i32.const -2)
+     )
+    )
+    (i32.store offset=4
+     (local.get $2)
+     (i32.or
+      (local.get $3)
+      (i32.const 1)
+     )
+    )
+    (i32.store
+     (i32.add
+      (local.get $2)
+      (local.get $3)
+     )
+     (local.get $3)
+    )
+   )
+   (block $block617
+    (if
+     (i32.eq
+      (local.get $8)
+      (i32.load
+       (i32.const 200)
+      )
+     )
+     (block $block619
+      (i32.store
+       (i32.const 188)
+       (local.tee $0
+        (i32.add
+         (i32.load
+          (i32.const 188)
+         )
+         (local.get $3)
+        )
+       )
+      )
+      (i32.store
+       (i32.const 200)
+       (local.get $2)
+      )
+      (i32.store offset=4
+       (local.get $2)
+       (i32.or
+        (local.get $0)
+        (i32.const 1)
+       )
+      )
+      (if
+       (i32.ne
+        (local.get $2)
+        (i32.load
+         (i32.const 196)
+        )
+       )
+       (return)
+      )
+      (i32.store
+       (i32.const 196)
+       (i32.const 0)
+      )
+      (i32.store
+       (i32.const 184)
+       (i32.const 0)
+      )
+      (return)
+     )
+    )
+    (if
+     (i32.eq
+      (local.get $8)
+      (i32.load
+       (i32.const 196)
+      )
+     )
+     (block $block622
+      (i32.store
+       (i32.const 184)
+       (local.tee $0
+        (i32.add
+         (i32.load
+          (i32.const 184)
+         )
+         (local.get $3)
+        )
+       )
+      )
+      (i32.store
+       (i32.const 196)
+       (local.get $2)
+      )
+      (i32.store offset=4
+       (local.get $2)
+       (i32.or
+        (local.get $0)
+        (i32.const 1)
+       )
+      )
+      (i32.store
+       (i32.add
+        (local.get $2)
+        (local.get $0)
+       )
+       (local.get $0)
+      )
+      (return)
+     )
+    )
+    (local.set $5
+     (i32.add
+      (i32.and
+       (local.get $1)
+       (i32.const -8)
+      )
+      (local.get $3)
+     )
+    )
+    (local.set $3
+     (i32.shr_u
+      (local.get $1)
+      (i32.const 3)
+     )
+    )
+    (block $do-once4
+     (if
+      (i32.lt_u
+       (local.get $1)
+       (i32.const 256)
+      )
+      (block $block624
+       (local.set $4
+        (i32.load offset=12
+         (local.get $8)
+        )
+       )
+       (if
+        (i32.ne
+         (local.tee $1
+          (i32.load offset=8
+           (local.get $8)
+          )
+         )
+         (local.tee $0
+          (i32.add
+           (i32.shl
+            (local.get $3)
+            (i32.const 3)
+           )
+           (i32.const 216)
+          )
+         )
+        )
+        (block $block626
+         (if
+          (i32.lt_u
+           (local.get $1)
+           (i32.load
+            (i32.const 192)
+           )
+          )
+          (call $_abort)
+         )
+         (if
+          (i32.ne
+           (i32.load offset=12
+            (local.get $1)
+           )
+           (local.get $8)
+          )
+          (call $_abort)
+         )
+        )
+       )
+       (if
+        (i32.eq
+         (local.get $4)
+         (local.get $1)
+        )
+        (block $block630
+         (i32.store
+          (i32.const 176)
+          (i32.and
+           (i32.load
+            (i32.const 176)
+           )
+           (i32.xor
+            (i32.shl
+             (i32.const 1)
+             (local.get $3)
+            )
+            (i32.const -1)
+           )
+          )
+         )
+         (br $do-once4)
+        )
+       )
+       (if
+        (i32.eq
+         (local.get $4)
+         (local.get $0)
+        )
+        (local.set $14
+         (i32.add
+          (local.get $4)
+          (i32.const 8)
+         )
+        )
+        (block $block632
+         (if
+          (i32.lt_u
+           (local.get $4)
+           (i32.load
+            (i32.const 192)
+           )
+          )
+          (call $_abort)
+         )
+         (if
+          (i32.eq
+           (i32.load
+            (local.tee $0
+             (i32.add
+              (local.get $4)
+              (i32.const 8)
+             )
+            )
+           )
+           (local.get $8)
+          )
+          (local.set $14
+           (local.get $0)
+          )
+          (call $_abort)
+         )
+        )
+       )
+       (i32.store offset=12
+        (local.get $1)
+        (local.get $4)
+       )
+       (i32.store
+        (local.get $14)
+        (local.get $1)
+       )
+      )
+      (block $block635
+       (local.set $6
+        (i32.load offset=24
+         (local.get $8)
+        )
+       )
+       (block $do-once6
+        (if
+         (i32.eq
+          (local.tee $0
+           (i32.load offset=12
+            (local.get $8)
+           )
+          )
+          (local.get $8)
+         )
+         (block $block637
+          (if
+           (i32.eqz
+            (local.tee $3
+             (i32.load
+              (local.tee $0
+               (i32.add
+                (local.tee $1
+                 (i32.add
+                  (local.get $8)
+                  (i32.const 16)
+                 )
+                )
+                (i32.const 4)
+               )
+              )
+             )
+            )
+           )
+           (if
+            (local.tee $3
+             (i32.load
+              (local.get $1)
+             )
+            )
+            (local.set $0
+             (local.get $1)
+            )
+            (block $block640
+             (local.set $9
+              (i32.const 0)
+             )
+             (br $do-once6)
+            )
+           )
+          )
+          (loop $while-in9
+           (if
+            (local.tee $1
+             (i32.load
+              (local.tee $4
+               (i32.add
+                (local.get $3)
+                (i32.const 20)
+               )
+              )
+             )
+            )
+            (block $block642
+             (local.set $3
+              (local.get $1)
+             )
+             (local.set $0
+              (local.get $4)
+             )
+             (br $while-in9)
+            )
+           )
+           (if
+            (local.tee $1
+             (i32.load
+              (local.tee $4
+               (i32.add
+                (local.get $3)
+                (i32.const 16)
+               )
+              )
+             )
+            )
+            (block $block644
+             (local.set $3
+              (local.get $1)
+             )
+             (local.set $0
+              (local.get $4)
+             )
+             (br $while-in9)
+            )
+           )
+          )
+          (if
+           (i32.lt_u
+            (local.get $0)
+            (i32.load
+             (i32.const 192)
+            )
+           )
+           (call $_abort)
+           (block $block646
+            (i32.store
+             (local.get $0)
+             (i32.const 0)
+            )
+            (local.set $9
+             (local.get $3)
+            )
+           )
+          )
+         )
+         (block $block647
+          (if
+           (i32.lt_u
+            (local.tee $4
+             (i32.load offset=8
+              (local.get $8)
+             )
+            )
+            (i32.load
+             (i32.const 192)
+            )
+           )
+           (call $_abort)
+          )
+          (if
+           (i32.ne
+            (i32.load
+             (local.tee $1
+              (i32.add
+               (local.get $4)
+               (i32.const 12)
+              )
+             )
+            )
+            (local.get $8)
+           )
+           (call $_abort)
+          )
+          (if
+           (i32.eq
+            (i32.load
+             (local.tee $3
+              (i32.add
+               (local.get $0)
+               (i32.const 8)
+              )
+             )
+            )
+            (local.get $8)
+           )
+           (block $block651
+            (i32.store
+             (local.get $1)
+             (local.get $0)
+            )
+            (i32.store
+             (local.get $3)
+             (local.get $4)
+            )
+            (local.set $9
+             (local.get $0)
+            )
+           )
+           (call $_abort)
+          )
+         )
+        )
+       )
+       (if
+        (local.get $6)
+        (block $block653
+         (if
+          (i32.eq
+           (local.get $8)
+           (i32.load
+            (local.tee $0
+             (i32.add
+              (i32.shl
+               (local.tee $3
+                (i32.load offset=28
+                 (local.get $8)
+                )
+               )
+               (i32.const 2)
+              )
+              (i32.const 480)
+             )
+            )
+           )
+          )
+          (block $block655
+           (i32.store
+            (local.get $0)
+            (local.get $9)
+           )
+           (if
+            (i32.eqz
+             (local.get $9)
+            )
+            (block $block657
+             (i32.store
+              (i32.const 180)
+              (i32.and
+               (i32.load
+                (i32.const 180)
+               )
+               (i32.xor
+                (i32.shl
+                 (i32.const 1)
+                 (local.get $3)
+                )
+                (i32.const -1)
+               )
+              )
+             )
+             (br $do-once4)
+            )
+           )
+          )
+          (block $block658
+           (if
+            (i32.lt_u
+             (local.get $6)
+             (i32.load
+              (i32.const 192)
+             )
+            )
+            (call $_abort)
+           )
+           (if
+            (i32.eq
+             (i32.load
+              (local.tee $0
+               (i32.add
+                (local.get $6)
+                (i32.const 16)
+               )
+              )
+             )
+             (local.get $8)
+            )
+            (i32.store
+             (local.get $0)
+             (local.get $9)
+            )
+            (i32.store offset=20
+             (local.get $6)
+             (local.get $9)
+            )
+           )
+           (br_if $do-once4
+            (i32.eqz
+             (local.get $9)
+            )
+           )
+          )
+         )
+         (if
+          (i32.lt_u
+           (local.get $9)
+           (local.tee $3
+            (i32.load
+             (i32.const 192)
+            )
+           )
+          )
+          (call $_abort)
+         )
+         (i32.store offset=24
+          (local.get $9)
+          (local.get $6)
+         )
+         (if
+          (local.tee $1
+           (i32.load
+            (local.tee $0
+             (i32.add
+              (local.get $8)
+              (i32.const 16)
+             )
+            )
+           )
+          )
+          (if
+           (i32.lt_u
+            (local.get $1)
+            (local.get $3)
+           )
+           (call $_abort)
+           (block $block664
+            (i32.store offset=16
+             (local.get $9)
+             (local.get $1)
+            )
+            (i32.store offset=24
+             (local.get $1)
+             (local.get $9)
+            )
+           )
+          )
+         )
+         (if
+          (local.tee $0
+           (i32.load offset=4
+            (local.get $0)
+           )
+          )
+          (if
+           (i32.lt_u
+            (local.get $0)
+            (i32.load
+             (i32.const 192)
+            )
+           )
+           (call $_abort)
+           (block $block667
+            (i32.store offset=20
+             (local.get $9)
+             (local.get $0)
+            )
+            (i32.store offset=24
+             (local.get $0)
+             (local.get $9)
+            )
+           )
+          )
+         )
+        )
+       )
+      )
+     )
+    )
+    (i32.store offset=4
+     (local.get $2)
+     (i32.or
+      (local.get $5)
+      (i32.const 1)
+     )
+    )
+    (i32.store
+     (i32.add
+      (local.get $2)
+      (local.get $5)
+     )
+     (local.get $5)
+    )
+    (if
+     (i32.eq
+      (local.get $2)
+      (i32.load
+       (i32.const 196)
+      )
+     )
+     (block $block669
+      (i32.store
+       (i32.const 184)
+       (local.get $5)
+      )
+      (return)
+     )
+     (local.set $3
+      (local.get $5)
+     )
+    )
+   )
+  )
+  (local.set $0
+   (i32.shr_u
+    (local.get $3)
+    (i32.const 3)
+   )
+  )
+  (if
+   (i32.lt_u
+    (local.get $3)
+    (i32.const 256)
+   )
+   (block $block671
+    (local.set $1
+     (i32.add
+      (i32.shl
+       (local.get $0)
+       (i32.const 3)
+      )
+      (i32.const 216)
+     )
+    )
+    (if
+     (i32.and
+      (local.tee $3
+       (i32.load
+        (i32.const 176)
+       )
+      )
+      (local.tee $0
+       (i32.shl
+        (i32.const 1)
+        (local.get $0)
+       )
+      )
+     )
+     (if
+      (i32.lt_u
+       (local.tee $0
+        (i32.load
+         (local.tee $3
+          (i32.add
+           (local.get $1)
+           (i32.const 8)
+          )
+         )
+        )
+       )
+       (i32.load
+        (i32.const 192)
+       )
+      )
+      (call $_abort)
+      (block $block674
+       (local.set $15
+        (local.get $3)
+       )
+       (local.set $13
+        (local.get $0)
+       )
+      )
+     )
+     (block $block675
+      (i32.store
+       (i32.const 176)
+       (i32.or
+        (local.get $3)
+        (local.get $0)
+       )
+      )
+      (local.set $15
+       (i32.add
+        (local.get $1)
+        (i32.const 8)
+       )
+      )
+      (local.set $13
+       (local.get $1)
+      )
+     )
+    )
+    (i32.store
+     (local.get $15)
+     (local.get $2)
+    )
+    (i32.store offset=12
+     (local.get $13)
+     (local.get $2)
+    )
+    (i32.store offset=8
+     (local.get $2)
+     (local.get $13)
+    )
+    (i32.store offset=12
+     (local.get $2)
+     (local.get $1)
+    )
+    (return)
+   )
+  )
+  (local.set $4
+   (i32.add
+    (i32.shl
+     (local.tee $5
+      (if (result i32)
+       (local.tee $0
+        (i32.shr_u
+         (local.get $3)
+         (i32.const 8)
+        )
+       )
+       (if (result i32)
+        (i32.gt_u
+         (local.get $3)
+         (i32.const 16777215)
+        )
+        (i32.const 31)
+        (i32.or
+         (i32.and
+          (i32.shr_u
+           (local.get $3)
+           (i32.add
+            (local.tee $0
+             (i32.add
+              (i32.sub
+               (i32.const 14)
+               (i32.or
+                (i32.or
+                 (local.tee $0
+                  (i32.and
+                   (i32.shr_u
+                    (i32.add
+                     (local.tee $1
+                      (i32.shl
+                       (local.get $0)
+                       (local.tee $4
+                        (i32.and
+                         (i32.shr_u
+                          (i32.add
+                           (local.get $0)
+                           (i32.const 1048320)
+                          )
+                          (i32.const 16)
+                         )
+                         (i32.const 8)
+                        )
+                       )
+                      )
+                     )
+                     (i32.const 520192)
+                    )
+                    (i32.const 16)
+                   )
+                   (i32.const 4)
+                  )
+                 )
+                 (local.get $4)
+                )
+                (local.tee $0
+                 (i32.and
+                  (i32.shr_u
+                   (i32.add
+                    (local.tee $1
+                     (i32.shl
+                      (local.get $1)
+                      (local.get $0)
+                     )
+                    )
+                    (i32.const 245760)
+                   )
+                   (i32.const 16)
+                  )
+                  (i32.const 2)
+                 )
+                )
+               )
+              )
+              (i32.shr_u
+               (i32.shl
+                (local.get $1)
+                (local.get $0)
+               )
+               (i32.const 15)
+              )
+             )
+            )
+            (i32.const 7)
+           )
+          )
+          (i32.const 1)
+         )
+         (i32.shl
+          (local.get $0)
+          (i32.const 1)
+         )
+        )
+       )
+       (i32.const 0)
+      )
+     )
+     (i32.const 2)
+    )
+    (i32.const 480)
+   )
+  )
+  (i32.store offset=28
+   (local.get $2)
+   (local.get $5)
+  )
+  (i32.store offset=20
+   (local.get $2)
+   (i32.const 0)
+  )
+  (i32.store offset=16
+   (local.get $2)
+   (i32.const 0)
+  )
+  (block $do-once12
+   (if
+    (i32.and
+     (local.tee $1
+      (i32.load
+       (i32.const 180)
+      )
+     )
+     (local.tee $0
+      (i32.shl
+       (i32.const 1)
+       (local.get $5)
+      )
+     )
+    )
+    (block $block679
+     (local.set $5
+      (i32.shl
+       (local.get $3)
+       (select
+        (i32.const 0)
+        (i32.sub
+         (i32.const 25)
+         (i32.shr_u
+          (local.get $5)
+          (i32.const 1)
+         )
+        )
+        (i32.eq
+         (local.get $5)
+         (i32.const 31)
+        )
+       )
+      )
+     )
+     (local.set $0
+      (i32.load
+       (local.get $4)
+      )
+     )
+     (block $__rjto$1
+      (block $__rjti$1
+       (loop $while-in15
+        (br_if $__rjti$1
+         (i32.eq
+          (i32.and
+           (i32.load offset=4
+            (local.get $0)
+           )
+           (i32.const -8)
+          )
+          (local.get $3)
+         )
+        )
+        (local.set $4
+         (i32.shl
+          (local.get $5)
+          (i32.const 1)
+         )
+        )
+        (if
+         (local.tee $1
+          (i32.load
+           (local.tee $5
+            (i32.add
+             (i32.add
+              (local.get $0)
+              (i32.const 16)
+             )
+             (i32.shl
+              (i32.shr_u
+               (local.get $5)
+               (i32.const 31)
+              )
+              (i32.const 2)
+             )
+            )
+           )
+          )
+         )
+         (block $block681
+          (local.set $5
+           (local.get $4)
+          )
+          (local.set $0
+           (local.get $1)
+          )
+          (br $while-in15)
+         )
+        )
+       )
+       (if
+        (i32.lt_u
+         (local.get $5)
+         (i32.load
+          (i32.const 192)
+         )
+        )
+        (call $_abort)
+        (block $block683
+         (i32.store
+          (local.get $5)
+          (local.get $2)
+         )
+         (i32.store offset=24
+          (local.get $2)
+          (local.get $0)
+         )
+         (i32.store offset=12
+          (local.get $2)
+          (local.get $2)
+         )
+         (i32.store offset=8
+          (local.get $2)
+          (local.get $2)
+         )
+         (br $do-once12)
+        )
+       )
+       (br $__rjto$1)
+      )
+      (if
+       (i32.and
+        (i32.ge_u
+         (local.tee $4
+          (i32.load
+           (local.tee $1
+            (i32.add
+             (local.get $0)
+             (i32.const 8)
+            )
+           )
+          )
+         )
+         (local.tee $3
+          (i32.load
+           (i32.const 192)
+          )
+         )
+        )
+        (i32.ge_u
+         (local.get $0)
+         (local.get $3)
+        )
+       )
+       (block $block685
+        (i32.store offset=12
+         (local.get $4)
+         (local.get $2)
+        )
+        (i32.store
+         (local.get $1)
+         (local.get $2)
+        )
+        (i32.store offset=8
+         (local.get $2)
+         (local.get $4)
+        )
+        (i32.store offset=12
+         (local.get $2)
+         (local.get $0)
+        )
+        (i32.store offset=24
+         (local.get $2)
+         (i32.const 0)
+        )
+       )
+       (call $_abort)
+      )
+     )
+    )
+    (block $block686
+     (i32.store
+      (i32.const 180)
+      (i32.or
+       (local.get $1)
+       (local.get $0)
+      )
+     )
+     (i32.store
+      (local.get $4)
+      (local.get $2)
+     )
+     (i32.store offset=24
+      (local.get $2)
+      (local.get $4)
+     )
+     (i32.store offset=12
+      (local.get $2)
+      (local.get $2)
+     )
+     (i32.store offset=8
+      (local.get $2)
+      (local.get $2)
+     )
+    )
+   )
+  )
+  (i32.store
+   (i32.const 208)
+   (local.tee $0
+    (i32.add
+     (i32.load
+      (i32.const 208)
+     )
+     (i32.const -1)
+    )
+   )
+  )
+  (if
+   (local.get $0)
+   (return)
+   (local.set $0
+    (i32.const 632)
+   )
+  )
+  (loop $while-in17
+   (local.set $0
+    (i32.add
+     (local.tee $3
+      (i32.load
+       (local.get $0)
+      )
+     )
+     (i32.const 8)
+    )
+   )
+   (br_if $while-in17
+    (local.get $3)
+   )
+  )
+  (i32.store
+   (i32.const 208)
+   (i32.const -1)
+  )
+ )
+ (func $runPostSets
+  (nop)
+ )
+ (func $_i64Subtract (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
+  (global.set $tempRet0
+   (i32.sub
+    (i32.sub
+     (local.get $1)
+     (local.get $3)
+    )
+    (i32.gt_u
+     (local.get $2)
+     (local.get $0)
+    )
+   )
+  )
+  (i32.sub
+   (local.get $0)
+   (local.get $2)
+  )
+ )
+ (func $_i64Add (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
+  (local $4 i32)
+  (global.set $tempRet0
+   (i32.add
+    (i32.add
+     (local.get $1)
+     (local.get $3)
+    )
+    (i32.lt_u
+     (local.tee $4
+      (i32.add
+       (local.get $0)
+       (local.get $2)
+      )
+     )
+     (local.get $0)
+    )
+   )
+  )
+  (local.get $4)
+ )
+ (func $_memset (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $4
+   (i32.add
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (if
+   (i32.ge_s
+    (local.get $2)
+    (i32.const 20)
+   )
+   (block $block
+    (local.set $1
+     (i32.and
+      (local.get $1)
+      (i32.const 255)
+     )
+    )
+    (if
+     (local.tee $3
+      (i32.and
+       (local.get $0)
+       (i32.const 3)
+      )
+     )
+     (block $block689
+      (local.set $3
+       (i32.sub
+        (i32.add
+         (local.get $0)
+         (i32.const 4)
+        )
+        (local.get $3)
+       )
+      )
+      (loop $while-in
+       (if
+        (i32.lt_s
+         (local.get $0)
+         (local.get $3)
+        )
+        (block $block691
+         (i32.store8
+          (local.get $0)
+          (local.get $1)
+         )
+         (local.set $0
+          (i32.add
+           (local.get $0)
+           (i32.const 1)
+          )
+         )
+         (br $while-in)
+        )
+       )
+      )
+     )
+    )
+    (local.set $3
+     (i32.or
+      (i32.or
+       (i32.or
+        (local.get $1)
+        (i32.shl
+         (local.get $1)
+         (i32.const 8)
+        )
+       )
+       (i32.shl
+        (local.get $1)
+        (i32.const 16)
+       )
+      )
+      (i32.shl
+       (local.get $1)
+       (i32.const 24)
+      )
+     )
+    )
+    (local.set $5
+     (i32.and
+      (local.get $4)
+      (i32.const -4)
+     )
+    )
+    (loop $while-in1
+     (if
+      (i32.lt_s
+       (local.get $0)
+       (local.get $5)
+      )
+      (block $block693
+       (i32.store
+        (local.get $0)
+        (local.get $3)
+       )
+       (local.set $0
+        (i32.add
+         (local.get $0)
+         (i32.const 4)
+        )
+       )
+       (br $while-in1)
+      )
+     )
+    )
+   )
+  )
+  (loop $while-in3
+   (if
+    (i32.lt_s
+     (local.get $0)
+     (local.get $4)
+    )
+    (block $block695
+     (i32.store8
+      (local.get $0)
+      (local.get $1)
+     )
+     (local.set $0
+      (i32.add
+       (local.get $0)
+       (i32.const 1)
+      )
+     )
+     (br $while-in3)
+    )
+   )
+  )
+  (i32.sub
+   (local.get $0)
+   (local.get $2)
+  )
+ )
+ (func $_bitshift64Lshr (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (if
+   (i32.lt_s
+    (local.get $2)
+    (i32.const 32)
+   )
+   (block $block
+    (global.set $tempRet0
+     (i32.shr_u
+      (local.get $1)
+      (local.get $2)
+     )
+    )
+    (return
+     (i32.or
+      (i32.shr_u
+       (local.get $0)
+       (local.get $2)
+      )
+      (i32.shl
+       (i32.and
+        (local.get $1)
+        (i32.sub
+         (i32.shl
+          (i32.const 1)
+          (local.get $2)
+         )
+         (i32.const 1)
+        )
+       )
+       (i32.sub
+        (i32.const 32)
+        (local.get $2)
+       )
+      )
+     )
+    )
+   )
+  )
+  (global.set $tempRet0
+   (i32.const 0)
+  )
+  (i32.shr_u
+   (local.get $1)
+   (i32.sub
+    (local.get $2)
+    (i32.const 32)
+   )
+  )
+ )
+ (func $_bitshift64Shl (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (if
+   (i32.lt_s
+    (local.get $2)
+    (i32.const 32)
+   )
+   (block $block
+    (global.set $tempRet0
+     (i32.or
+      (i32.shl
+       (local.get $1)
+       (local.get $2)
+      )
+      (i32.shr_u
+       (i32.and
+        (local.get $0)
+        (i32.shl
+         (i32.sub
+          (i32.shl
+           (i32.const 1)
+           (local.get $2)
+          )
+          (i32.const 1)
+         )
+         (i32.sub
+          (i32.const 32)
+          (local.get $2)
+         )
+        )
+       )
+       (i32.sub
+        (i32.const 32)
+        (local.get $2)
+       )
+      )
+     )
+    )
+    (return
+     (i32.shl
+      (local.get $0)
+      (local.get $2)
+     )
+    )
+   )
+  )
+  (global.set $tempRet0
+   (i32.shl
+    (local.get $0)
+    (i32.sub
+     (local.get $2)
+     (i32.const 32)
+    )
+   )
+  )
+  (i32.const 0)
+ )
+ (func $_memcpy (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (if
+   (i32.ge_s
+    (local.get $2)
+    (i32.const 4096)
+   )
+   (return
+    (call $_emscripten_memcpy_big
+     (local.get $0)
+     (local.get $1)
+     (local.get $2)
+    )
+   )
+  )
+  (local.set $3
+   (local.get $0)
+  )
+  (if
+   (i32.eq
+    (i32.and
+     (local.get $0)
+     (i32.const 3)
+    )
+    (i32.and
+     (local.get $1)
+     (i32.const 3)
+    )
+   )
+   (block $block
+    (loop $while-in
+     (if
+      (i32.and
+       (local.get $0)
+       (i32.const 3)
+      )
+      (block $block698
+       (if
+        (i32.eqz
+         (local.get $2)
+        )
+        (return
+         (local.get $3)
+        )
+       )
+       (i32.store8
+        (local.get $0)
+        (i32.load8_s
+         (local.get $1)
+        )
+       )
+       (local.set $0
+        (i32.add
+         (local.get $0)
+         (i32.const 1)
+        )
+       )
+       (local.set $1
+        (i32.add
+         (local.get $1)
+         (i32.const 1)
+        )
+       )
+       (local.set $2
+        (i32.sub
+         (local.get $2)
+         (i32.const 1)
+        )
+       )
+       (br $while-in)
+      )
+     )
+    )
+    (loop $while-in1
+     (if
+      (i32.ge_s
+       (local.get $2)
+       (i32.const 4)
+      )
+      (block $block701
+       (i32.store
+        (local.get $0)
+        (i32.load
+         (local.get $1)
+        )
+       )
+       (local.set $0
+        (i32.add
+         (local.get $0)
+         (i32.const 4)
+        )
+       )
+       (local.set $1
+        (i32.add
+         (local.get $1)
+         (i32.const 4)
+        )
+       )
+       (local.set $2
+        (i32.sub
+         (local.get $2)
+         (i32.const 4)
+        )
+       )
+       (br $while-in1)
+      )
+     )
+    )
+   )
+  )
+  (loop $while-in3
+   (if
+    (i32.gt_s
+     (local.get $2)
+     (i32.const 0)
+    )
+    (block $block703
+     (i32.store8
+      (local.get $0)
+      (i32.load8_s
+       (local.get $1)
+      )
+     )
+     (local.set $0
+      (i32.add
+       (local.get $0)
+       (i32.const 1)
+      )
+     )
+     (local.set $1
+      (i32.add
+       (local.get $1)
+       (i32.const 1)
+      )
+     )
+     (local.set $2
+      (i32.sub
+       (local.get $2)
+       (i32.const 1)
+      )
+     )
+     (br $while-in3)
+    )
+   )
+  )
+  (local.get $3)
+ )
+ (func $___udivdi3 (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
+  (call $___udivmoddi4
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+   (local.get $3)
+   (i32.const 0)
+  )
+ )
+ (func $___uremdi3 (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
+  (local $4 i32)
+  (local.set $4
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 16)
+   )
+  )
+  (drop
+   (call $___udivmoddi4
+    (local.get $0)
+    (local.get $1)
+    (local.get $2)
+    (local.get $3)
+    (local.tee $0
+     (local.get $4)
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $4)
+  )
+  (global.set $tempRet0
+   (i32.load offset=4
+    (local.get $0)
+   )
+  )
+  (i32.load
+   (local.get $0)
+  )
+ )
+ (func $___udivmoddi4 (param $xl i32) (param $xh i32) (param $yl i32) (param $yh i32) (param $r i32) (result i32)
+  (local $x64 i64)
+  (local $y64 i64)
+  (local.set $x64
+   (i64.or
+    (i64.extend_i32_u
+     (local.get $xl)
+    )
+    (i64.shl
+     (i64.extend_i32_u
+      (local.get $xh)
+     )
+     (i64.const 32)
+    )
+   )
+  )
+  (local.set $y64
+   (i64.or
+    (i64.extend_i32_u
+     (local.get $yl)
+    )
+    (i64.shl
+     (i64.extend_i32_u
+      (local.get $yh)
+     )
+     (i64.const 32)
+    )
+   )
+  )
+  (if
+   (local.get $r)
+   (i64.store
+    (local.get $r)
+    (i64.rem_u
+     (local.get $x64)
+     (local.get $y64)
+    )
+   )
+  )
+  (local.set $x64
+   (i64.div_u
+    (local.get $x64)
+    (local.get $y64)
+   )
+  )
+  (global.set $tempRet0
+   (i32.wrap_i64
+    (i64.shr_u
+     (local.get $x64)
+     (i64.const 32)
+    )
+   )
+  )
+  (i32.wrap_i64
+   (local.get $x64)
+  )
+ )
+ (func $dynCall_ii (param $0 i32) (param $1 i32) (result i32)
+  (call_indirect (type $i32_=>_i32)
+   (local.get $1)
+   (i32.and
+    (local.get $0)
+    (i32.const 1)
+   )
+  )
+ )
+ (func $dynCall_iiii (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
+  (call_indirect (type $i32_i32_i32_=>_i32)
+   (local.get $1)
+   (local.get $2)
+   (local.get $3)
+   (i32.add
+    (i32.and
+     (local.get $0)
+     (i32.const 7)
+    )
+    (i32.const 2)
+   )
+  )
+ )
+ (func $dynCall_vi (param $0 i32) (param $1 i32)
+  (call_indirect (type $i32_=>_none)
+   (local.get $1)
+   (i32.add
+    (i32.and
+     (local.get $0)
+     (i32.const 7)
+    )
+    (i32.const 10)
+   )
+  )
+ )
+ (func $b0 (param $0 i32) (result i32)
+  (call $nullFunc_ii
+   (i32.const 0)
+  )
+  (i32.const 0)
+ )
+ (func $b1 (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (call $nullFunc_iiii
+   (i32.const 1)
+  )
+  (i32.const 0)
+ )
+ (func $b2 (param $0 i32)
+  (call $nullFunc_vi
+   (i32.const 2)
+  )
+ )
+)
diff --git a/binaryen/test/passes/inlining-optimizing_optimize-level=3.wast b/binaryen/test/passes/inlining-optimizing_optimize-level=3.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/inlining-optimizing_optimize-level=3.wast
@@ -0,0 +1,15703 @@
+;; similar to test/emcc_hello_world.fromasm.clamp ;;
+(module
+ (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32)))
+ (type $FUNCSIG$ii (func (param i32) (result i32)))
+ (type $FUNCSIG$vi (func (param i32)))
+ (type $FUNCSIG$v (func))
+ (type $FUNCSIG$i (func (result i32)))
+ (type $FUNCSIG$iii (func (param i32 i32) (result i32)))
+ (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" "tempDoublePtr" (global $tempDoublePtr$asm2wasm$import i32))
+ (import "env" "abort" (func $abort))
+ (import "env" "nullFunc_ii" (func $nullFunc_ii (param i32)))
+ (import "env" "nullFunc_iiii" (func $nullFunc_iiii (param i32)))
+ (import "env" "nullFunc_vi" (func $nullFunc_vi (param i32)))
+ (import "env" "_pthread_cleanup_pop" (func $_pthread_cleanup_pop (param i32)))
+ (import "env" "___lock" (func $___lock (param i32)))
+ (import "env" "_pthread_self" (func $_pthread_self (result i32)))
+ (import "env" "_abort" (func $_abort))
+ (import "env" "___syscall6" (func $___syscall6 (param i32 i32) (result i32)))
+ (import "env" "_sbrk" (func $_sbrk (param i32) (result i32)))
+ (import "env" "_time" (func $_time (param i32) (result i32)))
+ (import "env" "_emscripten_memcpy_big" (func $_emscripten_memcpy_big (param i32 i32 i32) (result i32)))
+ (import "env" "___syscall54" (func $___syscall54 (param i32 i32) (result i32)))
+ (import "env" "___unlock" (func $___unlock (param i32)))
+ (import "env" "___syscall140" (func $___syscall140 (param i32 i32) (result i32)))
+ (import "env" "_pthread_cleanup_push" (func $_pthread_cleanup_push (param i32 i32)))
+ (import "env" "_sysconf" (func $_sysconf (param i32) (result i32)))
+ (import "env" "___syscall146" (func $___syscall146 (param i32 i32) (result i32)))
+ (import "env" "memory" (memory $0 256 256))
+ (import "env" "table" (table 18 18 funcref))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (global $STACKTOP (mut i32) (global.get $STACKTOP$asm2wasm$import))
+ (global $STACK_MAX (mut i32) (global.get $STACK_MAX$asm2wasm$import))
+ (global $tempDoublePtr (mut i32) (global.get $tempDoublePtr$asm2wasm$import))
+ (global $__THREW__ (mut i32) (i32.const 0))
+ (global $threwValue (mut i32) (i32.const 0))
+ (global $tempRet0 (mut i32) (i32.const 0))
+ (elem (global.get $tableBase) $b0 $___stdio_close $b1 $b1 $___stdout_write $___stdio_seek $___stdio_write $b1 $b1 $b1 $b2 $b2 $b2 $b2 $b2 $_cleanup $b2 $b2)
+ (data (i32.const 1024) "emcc_hello_world.asm.js")
+ (export "_i64Subtract" (func $_i64Subtract))
+ (export "_free" (func $_free))
+ (export "_main" (func $_main))
+ (export "_i64Add" (func $_i64Add))
+ (export "_memset" (func $_memset))
+ (export "_malloc" (func $_malloc))
+ (export "_memcpy" (func $_memcpy))
+ (export "_bitshift64Lshr" (func $_bitshift64Lshr))
+ (export "_fflush" (func $_fflush))
+ (export "___errno_location" (func $___errno_location))
+ (export "_bitshift64Shl" (func $_bitshift64Shl))
+ (export "runPostSets" (func $runPostSets))
+ (export "stackAlloc" (func $stackAlloc))
+ (export "stackSave" (func $stackSave))
+ (export "stackRestore" (func $stackRestore))
+ (export "establishStackSpace" (func $establishStackSpace))
+ (export "setThrew" (func $setThrew))
+ (export "setTempRet0" (func $setTempRet0))
+ (export "getTempRet0" (func $getTempRet0))
+ (export "dynCall_ii" (func $dynCall_ii))
+ (export "dynCall_iiii" (func $dynCall_iiii))
+ (export "dynCall_vi" (func $dynCall_vi))
+ (export "___udivmoddi4" (func $___udivmoddi4))
+ (func $stackAlloc (param $0 i32) (result i32)
+  (local $1 i32)
+  (local.set $1
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (local.get $0)
+   )
+  )
+  (global.set $STACKTOP
+   (i32.and
+    (i32.add
+     (global.get $STACKTOP)
+     (i32.const 15)
+    )
+    (i32.const -16)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (local.get $1)
+ )
+ (func $stackSave (result i32)
+  (global.get $STACKTOP)
+ )
+ (func $stackRestore (param $0 i32)
+  (global.set $STACKTOP
+   (local.get $0)
+  )
+ )
+ (func $establishStackSpace (param $0 i32) (param $1 i32)
+  (global.set $STACKTOP
+   (local.get $0)
+  )
+  (global.set $STACK_MAX
+   (local.get $1)
+  )
+ )
+ (func $setThrew (param $0 i32) (param $1 i32)
+  (if
+   (i32.eqz
+    (global.get $__THREW__)
+   )
+   (block
+    (global.set $__THREW__
+     (local.get $0)
+    )
+    (global.set $threwValue
+     (local.get $1)
+    )
+   )
+  )
+ )
+ (func $setTempRet0 (param $0 i32)
+  (global.set $tempRet0
+   (local.get $0)
+  )
+ )
+ (func $getTempRet0 (result i32)
+  (global.get $tempRet0)
+ )
+ (func $_main (result i32)
+  (local $0 i32)
+  (local.set $0
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 16)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (drop
+   (call $_printf
+    (i32.const 672)
+    (local.get $0)
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $0)
+  )
+  (i32.const 0)
+ )
+ (func $_frexp (param $0 f64) (param $1 i32) (result f64)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (f64.store
+   (global.get $tempDoublePtr)
+   (local.get $0)
+  )
+  (block $switch
+   (block $switch-default
+    (block $switch-case0
+     (block $switch-case
+      (br_table $switch-case $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-case0 $switch-default
+       (local.tee $3
+        (i32.and
+         (local.tee $3
+          (call $_bitshift64Lshr
+           (local.tee $2
+            (i32.load
+             (global.get $tempDoublePtr)
+            )
+           )
+           (local.tee $4
+            (i32.load offset=4
+             (global.get $tempDoublePtr)
+            )
+           )
+           (i32.const 52)
+          )
+         )
+         (i32.const 2047)
+        )
+       )
+      )
+     )
+     (i32.store
+      (local.get $1)
+      (local.tee $2
+       (if (result i32)
+        (f64.ne
+         (local.get $0)
+         (f64.const 0)
+        )
+        (block (result i32)
+         (local.set $0
+          (call $_frexp
+           (f64.mul
+            (local.get $0)
+            (f64.const 18446744073709551615)
+           )
+           (local.get $1)
+          )
+         )
+         (i32.add
+          (i32.load
+           (local.get $1)
+          )
+          (i32.const -64)
+         )
+        )
+        (i32.const 0)
+       )
+      )
+     )
+     (br $switch)
+    )
+    (br $switch)
+   )
+   (i32.store
+    (local.get $1)
+    (i32.add
+     (local.get $3)
+     (i32.const -1022)
+    )
+   )
+   (i32.store
+    (global.get $tempDoublePtr)
+    (local.get $2)
+   )
+   (i32.store offset=4
+    (global.get $tempDoublePtr)
+    (i32.or
+     (i32.and
+      (local.get $4)
+      (i32.const -2146435073)
+     )
+     (i32.const 1071644672)
+    )
+   )
+   (local.set $0
+    (f64.load
+     (global.get $tempDoublePtr)
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $_strerror (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $1
+   (i32.const 0)
+  )
+  (block $__rjto$1
+   (block $__rjti$1
+    (block $__rjti$0
+     (loop $while-in
+      (br_if $__rjti$0
+       (i32.eq
+        (i32.load8_u offset=687
+         (local.get $1)
+        )
+        (local.get $0)
+       )
+      )
+      (br_if $while-in
+       (i32.ne
+        (local.tee $1
+         (i32.add
+          (local.get $1)
+          (i32.const 1)
+         )
+        )
+        (i32.const 87)
+       )
+      )
+      (local.set $1
+       (i32.const 87)
+      )
+      (br $__rjti$1)
+     )
+    )
+    (br_if $__rjti$1
+     (local.get $1)
+    )
+    (local.set $0
+     (i32.const 775)
+    )
+    (br $__rjto$1)
+   )
+   (local.set $0
+    (i32.const 775)
+   )
+   (loop $while-in1
+    (loop $while-in3
+     (local.set $2
+      (i32.add
+       (local.get $0)
+       (i32.const 1)
+      )
+     )
+     (if
+      (i32.load8_s
+       (local.get $0)
+      )
+      (block
+       (local.set $0
+        (local.get $2)
+       )
+       (br $while-in3)
+      )
+      (local.set $0
+       (local.get $2)
+      )
+     )
+    )
+    (br_if $while-in1
+     (local.tee $1
+      (i32.add
+       (local.get $1)
+       (i32.const -1)
+      )
+     )
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $___errno_location (result i32)
+  (if (result i32)
+   (i32.load
+    (i32.const 16)
+   )
+   (i32.load offset=60
+    (call $_pthread_self)
+   )
+   (i32.const 60)
+  )
+ )
+ (func $___stdio_close (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $1
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 16)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (i32.store
+   (local.tee $2
+    (local.get $1)
+   )
+   (i32.load offset=60
+    (local.get $0)
+   )
+  )
+  (local.set $0
+   (call $___syscall_ret
+    (call $___syscall6
+     (i32.const 6)
+     (local.get $2)
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $1)
+  )
+  (local.get $0)
+ )
+ (func $___stdout_write (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $4
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 80)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (local.set $3
+   (local.get $4)
+  )
+  (local.set $5
+   (i32.add
+    (local.get $4)
+    (i32.const 12)
+   )
+  )
+  (i32.store offset=36
+   (local.get $0)
+   (i32.const 4)
+  )
+  (if
+   (i32.eqz
+    (i32.and
+     (i32.load
+      (local.get $0)
+     )
+     (i32.const 64)
+    )
+   )
+   (block
+    (i32.store
+     (local.get $3)
+     (i32.load offset=60
+      (local.get $0)
+     )
+    )
+    (i32.store offset=4
+     (local.get $3)
+     (i32.const 21505)
+    )
+    (i32.store offset=8
+     (local.get $3)
+     (local.get $5)
+    )
+    (if
+     (call $___syscall54
+      (i32.const 54)
+      (local.get $3)
+     )
+     (i32.store8 offset=75
+      (local.get $0)
+      (i32.const -1)
+     )
+    )
+   )
+  )
+  (local.set $0
+   (call $___stdio_write
+    (local.get $0)
+    (local.get $1)
+    (local.get $2)
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $4)
+  )
+  (local.get $0)
+ )
+ (func $___stdio_seek (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local.set $4
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 32)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (i32.store
+   (local.tee $3
+    (local.get $4)
+   )
+   (i32.load offset=60
+    (local.get $0)
+   )
+  )
+  (i32.store offset=4
+   (local.get $3)
+   (i32.const 0)
+  )
+  (i32.store offset=8
+   (local.get $3)
+   (local.get $1)
+  )
+  (i32.store offset=12
+   (local.get $3)
+   (local.tee $0
+    (i32.add
+     (local.get $4)
+     (i32.const 20)
+    )
+   )
+  )
+  (i32.store offset=16
+   (local.get $3)
+   (local.get $2)
+  )
+  (local.set $0
+   (if (result i32)
+    (i32.lt_s
+     (call $___syscall_ret
+      (call $___syscall140
+       (i32.const 140)
+       (local.get $3)
+      )
+     )
+     (i32.const 0)
+    )
+    (block (result i32)
+     (i32.store
+      (local.get $0)
+      (i32.const -1)
+     )
+     (i32.const -1)
+    )
+    (i32.load
+     (local.get $0)
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $4)
+  )
+  (local.get $0)
+ )
+ (func $_fflush (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block $do-once
+   (if
+    (local.get $0)
+    (block
+     (if
+      (i32.le_s
+       (i32.load offset=76
+        (local.get $0)
+       )
+       (i32.const -1)
+      )
+      (block
+       (local.set $0
+        (call $___fflush_unlocked
+         (local.get $0)
+        )
+       )
+       (br $do-once)
+      )
+     )
+     (local.set $2
+      (i32.eqz
+       (call $___lockfile
+        (local.get $0)
+       )
+      )
+     )
+     (local.set $1
+      (call $___fflush_unlocked
+       (local.get $0)
+      )
+     )
+     (local.set $0
+      (if (result i32)
+       (local.get $2)
+       (local.get $1)
+       (block (result i32)
+        (call $___unlockfile
+         (local.get $0)
+        )
+        (local.get $1)
+       )
+      )
+     )
+    )
+    (block
+     (local.set $0
+      (if (result i32)
+       (i32.load
+        (i32.const 12)
+       )
+       (call $_fflush
+        (i32.load
+         (i32.const 12)
+        )
+       )
+       (i32.const 0)
+      )
+     )
+     (call $___lock
+      (i32.const 44)
+     )
+     (if
+      (local.tee $1
+       (i32.load
+        (i32.const 40)
+       )
+      )
+      (loop $while-in
+       (local.set $2
+        (if (result i32)
+         (i32.gt_s
+          (i32.load offset=76
+           (local.get $1)
+          )
+          (i32.const -1)
+         )
+         (call $___lockfile
+          (local.get $1)
+         )
+         (i32.const 0)
+        )
+       )
+       (if
+        (i32.gt_u
+         (i32.load offset=20
+          (local.get $1)
+         )
+         (i32.load offset=28
+          (local.get $1)
+         )
+        )
+        (local.set $0
+         (i32.or
+          (call $___fflush_unlocked
+           (local.get $1)
+          )
+          (local.get $0)
+         )
+        )
+       )
+       (if
+        (local.get $2)
+        (call $___unlockfile
+         (local.get $1)
+        )
+       )
+       (br_if $while-in
+        (local.tee $1
+         (i32.load offset=56
+          (local.get $1)
+         )
+        )
+       )
+      )
+     )
+     (call $___unlock
+      (i32.const 44)
+     )
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $_printf (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local.set $2
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 16)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (i32.store
+   (local.tee $3
+    (local.get $2)
+   )
+   (local.get $1)
+  )
+  (local.set $0
+   (call $_vfprintf
+    (i32.load
+     (i32.const 8)
+    )
+    (local.get $0)
+    (local.get $3)
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $2)
+  )
+  (local.get $0)
+ )
+ (func $___lockfile (param $0 i32) (result i32)
+  (i32.const 0)
+ )
+ (func $___unlockfile (param $0 i32)
+  (nop)
+ )
+ (func $___stdio_write (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local.set $8
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 48)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (local.set $9
+   (i32.add
+    (local.get $8)
+    (i32.const 16)
+   )
+  )
+  (local.set $10
+   (local.get $8)
+  )
+  (i32.store
+   (local.tee $4
+    (i32.add
+     (local.get $8)
+     (i32.const 32)
+    )
+   )
+   (local.tee $3
+    (i32.load
+     (local.tee $6
+      (i32.add
+       (local.get $0)
+       (i32.const 28)
+      )
+     )
+    )
+   )
+  )
+  (i32.store offset=4
+   (local.get $4)
+   (local.tee $3
+    (i32.sub
+     (i32.load
+      (local.tee $11
+       (i32.add
+        (local.get $0)
+        (i32.const 20)
+       )
+      )
+     )
+     (local.get $3)
+    )
+   )
+  )
+  (i32.store offset=8
+   (local.get $4)
+   (local.get $1)
+  )
+  (i32.store offset=12
+   (local.get $4)
+   (local.get $2)
+  )
+  (local.set $13
+   (i32.add
+    (local.get $0)
+    (i32.const 60)
+   )
+  )
+  (local.set $14
+   (i32.add
+    (local.get $0)
+    (i32.const 44)
+   )
+  )
+  (local.set $1
+   (local.get $4)
+  )
+  (local.set $4
+   (i32.const 2)
+  )
+  (local.set $12
+   (i32.add
+    (local.get $3)
+    (local.get $2)
+   )
+  )
+  (block $__rjto$1
+   (block $__rjti$1
+    (block $__rjti$0
+     (loop $while-in
+      (if
+       (i32.load
+        (i32.const 16)
+       )
+       (block
+        (call $_pthread_cleanup_push
+         (i32.const 5)
+         (local.get $0)
+        )
+        (i32.store
+         (local.get $10)
+         (i32.load
+          (local.get $13)
+         )
+        )
+        (i32.store offset=4
+         (local.get $10)
+         (local.get $1)
+        )
+        (i32.store offset=8
+         (local.get $10)
+         (local.get $4)
+        )
+        (local.set $3
+         (call $___syscall_ret
+          (call $___syscall146
+           (i32.const 146)
+           (local.get $10)
+          )
+         )
+        )
+        (call $_pthread_cleanup_pop
+         (i32.const 0)
+        )
+       )
+       (block
+        (i32.store
+         (local.get $9)
+         (i32.load
+          (local.get $13)
+         )
+        )
+        (i32.store offset=4
+         (local.get $9)
+         (local.get $1)
+        )
+        (i32.store offset=8
+         (local.get $9)
+         (local.get $4)
+        )
+        (local.set $3
+         (call $___syscall_ret
+          (call $___syscall146
+           (i32.const 146)
+           (local.get $9)
+          )
+         )
+        )
+       )
+      )
+      (br_if $__rjti$0
+       (i32.eq
+        (local.get $12)
+        (local.get $3)
+       )
+      )
+      (br_if $__rjti$1
+       (i32.lt_s
+        (local.get $3)
+        (i32.const 0)
+       )
+      )
+      (local.set $5
+       (if (result i32)
+        (i32.gt_u
+         (local.get $3)
+         (local.tee $5
+          (i32.load offset=4
+           (local.get $1)
+          )
+         )
+        )
+        (block (result i32)
+         (i32.store
+          (local.get $6)
+          (local.tee $7
+           (i32.load
+            (local.get $14)
+           )
+          )
+         )
+         (i32.store
+          (local.get $11)
+          (local.get $7)
+         )
+         (local.set $7
+          (i32.load offset=12
+           (local.get $1)
+          )
+         )
+         (local.set $1
+          (i32.add
+           (local.get $1)
+           (i32.const 8)
+          )
+         )
+         (local.set $4
+          (i32.add
+           (local.get $4)
+           (i32.const -1)
+          )
+         )
+         (i32.sub
+          (local.get $3)
+          (local.get $5)
+         )
+        )
+        (block (result i32)
+         (if
+          (i32.eq
+           (local.get $4)
+           (i32.const 2)
+          )
+          (block
+           (i32.store
+            (local.get $6)
+            (i32.add
+             (i32.load
+              (local.get $6)
+             )
+             (local.get $3)
+            )
+           )
+           (local.set $7
+            (local.get $5)
+           )
+           (local.set $4
+            (i32.const 2)
+           )
+          )
+          (local.set $7
+           (local.get $5)
+          )
+         )
+         (local.get $3)
+        )
+       )
+      )
+      (i32.store
+       (local.get $1)
+       (i32.add
+        (i32.load
+         (local.get $1)
+        )
+        (local.get $5)
+       )
+      )
+      (i32.store offset=4
+       (local.get $1)
+       (i32.sub
+        (local.get $7)
+        (local.get $5)
+       )
+      )
+      (local.set $12
+       (i32.sub
+        (local.get $12)
+        (local.get $3)
+       )
+      )
+      (br $while-in)
+     )
+    )
+    (i32.store offset=16
+     (local.get $0)
+     (i32.add
+      (local.tee $1
+       (i32.load
+        (local.get $14)
+       )
+      )
+      (i32.load offset=48
+       (local.get $0)
+      )
+     )
+    )
+    (i32.store
+     (local.get $6)
+     (local.get $1)
+    )
+    (i32.store
+     (local.get $11)
+     (local.get $1)
+    )
+    (br $__rjto$1)
+   )
+   (i32.store offset=16
+    (local.get $0)
+    (i32.const 0)
+   )
+   (i32.store
+    (local.get $6)
+    (i32.const 0)
+   )
+   (i32.store
+    (local.get $11)
+    (i32.const 0)
+   )
+   (i32.store
+    (local.get $0)
+    (i32.or
+     (i32.load
+      (local.get $0)
+     )
+     (i32.const 32)
+    )
+   )
+   (local.set $2
+    (if (result i32)
+     (i32.eq
+      (local.get $4)
+      (i32.const 2)
+     )
+     (i32.const 0)
+     (i32.sub
+      (local.get $2)
+      (i32.load offset=4
+       (local.get $1)
+      )
+     )
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $8)
+  )
+  (local.get $2)
+ )
+ (func $_vfprintf (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local.set $4
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 224)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (local.set $5
+   (i32.add
+    (local.get $4)
+    (i32.const 120)
+   )
+  )
+  (local.set $7
+   (local.get $4)
+  )
+  (local.set $6
+   (i32.add
+    (local.get $4)
+    (i32.const 136)
+   )
+  )
+  (local.set $9
+   (i32.add
+    (local.tee $3
+     (local.tee $8
+      (i32.add
+       (local.get $4)
+       (i32.const 80)
+      )
+     )
+    )
+    (i32.const 40)
+   )
+  )
+  (loop $do-in
+   (i32.store
+    (local.get $3)
+    (i32.const 0)
+   )
+   (br_if $do-in
+    (i32.lt_s
+     (local.tee $3
+      (i32.add
+       (local.get $3)
+       (i32.const 4)
+      )
+     )
+     (local.get $9)
+    )
+   )
+  )
+  (i32.store
+   (local.get $5)
+   (i32.load
+    (local.get $2)
+   )
+  )
+  (local.set $0
+   (if (result i32)
+    (i32.lt_s
+     (call $_printf_core
+      (i32.const 0)
+      (local.get $1)
+      (local.get $5)
+      (local.get $7)
+      (local.get $8)
+     )
+     (i32.const 0)
+    )
+    (i32.const -1)
+    (block (result i32)
+     (local.set $14
+      (if (result i32)
+       (i32.gt_s
+        (i32.load offset=76
+         (local.get $0)
+        )
+        (i32.const -1)
+       )
+       (call $___lockfile
+        (local.get $0)
+       )
+       (i32.const 0)
+      )
+     )
+     (local.set $10
+      (i32.load
+       (local.get $0)
+      )
+     )
+     (if
+      (i32.lt_s
+       (i32.load8_s offset=74
+        (local.get $0)
+       )
+       (i32.const 1)
+      )
+      (i32.store
+       (local.get $0)
+       (i32.and
+        (local.get $10)
+        (i32.const -33)
+       )
+      )
+     )
+     (if
+      (i32.load
+       (local.tee $11
+        (i32.add
+         (local.get $0)
+         (i32.const 48)
+        )
+       )
+      )
+      (local.set $1
+       (call $_printf_core
+        (local.get $0)
+        (local.get $1)
+        (local.get $5)
+        (local.get $7)
+        (local.get $8)
+       )
+      )
+      (block
+       (local.set $13
+        (i32.load
+         (local.tee $12
+          (i32.add
+           (local.get $0)
+           (i32.const 44)
+          )
+         )
+        )
+       )
+       (i32.store
+        (local.get $12)
+        (local.get $6)
+       )
+       (i32.store
+        (local.tee $9
+         (i32.add
+          (local.get $0)
+          (i32.const 28)
+         )
+        )
+        (local.get $6)
+       )
+       (i32.store
+        (local.tee $3
+         (i32.add
+          (local.get $0)
+          (i32.const 20)
+         )
+        )
+        (local.get $6)
+       )
+       (i32.store
+        (local.get $11)
+        (i32.const 80)
+       )
+       (i32.store
+        (local.tee $2
+         (i32.add
+          (local.get $0)
+          (i32.const 16)
+         )
+        )
+        (i32.add
+         (local.get $6)
+         (i32.const 80)
+        )
+       )
+       (local.set $1
+        (call $_printf_core
+         (local.get $0)
+         (local.get $1)
+         (local.get $5)
+         (local.get $7)
+         (local.get $8)
+        )
+       )
+       (if
+        (local.get $13)
+        (block
+         (drop
+          (call_indirect (type $FUNCSIG$iiii)
+           (local.get $0)
+           (i32.const 0)
+           (i32.const 0)
+           (i32.add
+            (i32.and
+             (i32.load offset=36
+              (local.get $0)
+             )
+             (i32.const 7)
+            )
+            (i32.const 2)
+           )
+          )
+         )
+         (local.set $1
+          (select
+           (local.get $1)
+           (i32.const -1)
+           (i32.load
+            (local.get $3)
+           )
+          )
+         )
+         (i32.store
+          (local.get $12)
+          (local.get $13)
+         )
+         (i32.store
+          (local.get $11)
+          (i32.const 0)
+         )
+         (i32.store
+          (local.get $2)
+          (i32.const 0)
+         )
+         (i32.store
+          (local.get $9)
+          (i32.const 0)
+         )
+         (i32.store
+          (local.get $3)
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (i32.store
+      (local.get $0)
+      (i32.or
+       (local.tee $2
+        (i32.load
+         (local.get $0)
+        )
+       )
+       (i32.and
+        (local.get $10)
+        (i32.const 32)
+       )
+      )
+     )
+     (if
+      (local.get $14)
+      (call $___unlockfile
+       (local.get $0)
+      )
+     )
+     (select
+      (i32.const -1)
+      (local.get $1)
+      (i32.and
+       (local.get $2)
+       (i32.const 32)
+      )
+     )
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $4)
+  )
+  (local.get $0)
+ )
+ (func $___fwritex (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block $label$break$L5
+   (block $__rjti$0
+    (br_if $__rjti$0
+     (local.tee $3
+      (i32.load
+       (local.tee $4
+        (i32.add
+         (local.get $2)
+         (i32.const 16)
+        )
+       )
+      )
+     )
+    )
+    (if
+     (call $___towrite
+      (local.get $2)
+     )
+     (local.set $3
+      (i32.const 0)
+     )
+     (block
+      (local.set $3
+       (i32.load
+        (local.get $4)
+       )
+      )
+      (br $__rjti$0)
+     )
+    )
+    (br $label$break$L5)
+   )
+   (if
+    (i32.lt_u
+     (i32.sub
+      (local.get $3)
+      (local.tee $4
+       (i32.load
+        (local.tee $5
+         (i32.add
+          (local.get $2)
+          (i32.const 20)
+         )
+        )
+       )
+      )
+     )
+     (local.get $1)
+    )
+    (block
+     (local.set $3
+      (call_indirect (type $FUNCSIG$iiii)
+       (local.get $2)
+       (local.get $0)
+       (local.get $1)
+       (i32.add
+        (i32.and
+         (i32.load offset=36
+          (local.get $2)
+         )
+         (i32.const 7)
+        )
+        (i32.const 2)
+       )
+      )
+     )
+     (br $label$break$L5)
+    )
+   )
+   (local.set $2
+    (block $label$break$L10 (result i32)
+     (if (result i32)
+      (i32.gt_s
+       (i32.load8_s offset=75
+        (local.get $2)
+       )
+       (i32.const -1)
+      )
+      (block (result i32)
+       (local.set $3
+        (local.get $1)
+       )
+       (loop $while-in
+        (drop
+         (br_if $label$break$L10
+          (i32.const 0)
+          (i32.eqz
+           (local.get $3)
+          )
+         )
+        )
+        (if
+         (i32.ne
+          (i32.load8_s
+           (i32.add
+            (local.get $0)
+            (local.tee $6
+             (i32.add
+              (local.get $3)
+              (i32.const -1)
+             )
+            )
+           )
+          )
+          (i32.const 10)
+         )
+         (block
+          (local.set $3
+           (local.get $6)
+          )
+          (br $while-in)
+         )
+        )
+       )
+       (br_if $label$break$L5
+        (i32.lt_u
+         (call_indirect (type $FUNCSIG$iiii)
+          (local.get $2)
+          (local.get $0)
+          (local.get $3)
+          (i32.add
+           (i32.and
+            (i32.load offset=36
+             (local.get $2)
+            )
+            (i32.const 7)
+           )
+           (i32.const 2)
+          )
+         )
+         (local.get $3)
+        )
+       )
+       (local.set $4
+        (i32.load
+         (local.get $5)
+        )
+       )
+       (local.set $1
+        (i32.sub
+         (local.get $1)
+         (local.get $3)
+        )
+       )
+       (local.set $0
+        (i32.add
+         (local.get $0)
+         (local.get $3)
+        )
+       )
+       (local.get $3)
+      )
+      (i32.const 0)
+     )
+    )
+   )
+   (drop
+    (call $_memcpy
+     (local.get $4)
+     (local.get $0)
+     (local.get $1)
+    )
+   )
+   (i32.store
+    (local.get $5)
+    (i32.add
+     (i32.load
+      (local.get $5)
+     )
+     (local.get $1)
+    )
+   )
+   (local.set $3
+    (i32.add
+     (local.get $2)
+     (local.get $1)
+    )
+   )
+  )
+  (local.get $3)
+ )
+ (func $___towrite (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $1
+   (i32.load8_s
+    (local.tee $2
+     (i32.add
+      (local.get $0)
+      (i32.const 74)
+     )
+    )
+   )
+  )
+  (i32.store8
+   (local.get $2)
+   (i32.or
+    (i32.add
+     (local.get $1)
+     (i32.const 255)
+    )
+    (local.get $1)
+   )
+  )
+  (local.tee $0
+   (if (result i32)
+    (i32.and
+     (local.tee $1
+      (i32.load
+       (local.get $0)
+      )
+     )
+     (i32.const 8)
+    )
+    (block (result i32)
+     (i32.store
+      (local.get $0)
+      (i32.or
+       (local.get $1)
+       (i32.const 32)
+      )
+     )
+     (i32.const -1)
+    )
+    (block (result i32)
+     (i32.store offset=8
+      (local.get $0)
+      (i32.const 0)
+     )
+     (i32.store offset=4
+      (local.get $0)
+      (i32.const 0)
+     )
+     (i32.store offset=28
+      (local.get $0)
+      (local.tee $1
+       (i32.load offset=44
+        (local.get $0)
+       )
+      )
+     )
+     (i32.store offset=20
+      (local.get $0)
+      (local.get $1)
+     )
+     (i32.store offset=16
+      (local.get $0)
+      (i32.add
+       (local.get $1)
+       (i32.load offset=48
+        (local.get $0)
+       )
+      )
+     )
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $_wcrtomb (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (block $do-once (result i32)
+   (if (result i32)
+    (local.get $0)
+    (block (result i32)
+     (if
+      (i32.lt_u
+       (local.get $1)
+       (i32.const 128)
+      )
+      (block
+       (i32.store8
+        (local.get $0)
+        (local.get $1)
+       )
+       (br $do-once
+        (i32.const 1)
+       )
+      )
+     )
+     (if
+      (i32.lt_u
+       (local.get $1)
+       (i32.const 2048)
+      )
+      (block
+       (i32.store8
+        (local.get $0)
+        (i32.or
+         (i32.shr_u
+          (local.get $1)
+          (i32.const 6)
+         )
+         (i32.const 192)
+        )
+       )
+       (i32.store8 offset=1
+        (local.get $0)
+        (i32.or
+         (i32.and
+          (local.get $1)
+          (i32.const 63)
+         )
+         (i32.const 128)
+        )
+       )
+       (br $do-once
+        (i32.const 2)
+       )
+      )
+     )
+     (if
+      (i32.or
+       (i32.lt_u
+        (local.get $1)
+        (i32.const 55296)
+       )
+       (i32.eq
+        (i32.and
+         (local.get $1)
+         (i32.const -8192)
+        )
+        (i32.const 57344)
+       )
+      )
+      (block
+       (i32.store8
+        (local.get $0)
+        (i32.or
+         (i32.shr_u
+          (local.get $1)
+          (i32.const 12)
+         )
+         (i32.const 224)
+        )
+       )
+       (i32.store8 offset=1
+        (local.get $0)
+        (i32.or
+         (i32.and
+          (i32.shr_u
+           (local.get $1)
+           (i32.const 6)
+          )
+          (i32.const 63)
+         )
+         (i32.const 128)
+        )
+       )
+       (i32.store8 offset=2
+        (local.get $0)
+        (i32.or
+         (i32.and
+          (local.get $1)
+          (i32.const 63)
+         )
+         (i32.const 128)
+        )
+       )
+       (br $do-once
+        (i32.const 3)
+       )
+      )
+     )
+     (if (result i32)
+      (i32.lt_u
+       (i32.add
+        (local.get $1)
+        (i32.const -65536)
+       )
+       (i32.const 1048576)
+      )
+      (block (result i32)
+       (i32.store8
+        (local.get $0)
+        (i32.or
+         (i32.shr_u
+          (local.get $1)
+          (i32.const 18)
+         )
+         (i32.const 240)
+        )
+       )
+       (i32.store8 offset=1
+        (local.get $0)
+        (i32.or
+         (i32.and
+          (i32.shr_u
+           (local.get $1)
+           (i32.const 12)
+          )
+          (i32.const 63)
+         )
+         (i32.const 128)
+        )
+       )
+       (i32.store8 offset=2
+        (local.get $0)
+        (i32.or
+         (i32.and
+          (i32.shr_u
+           (local.get $1)
+           (i32.const 6)
+          )
+          (i32.const 63)
+         )
+         (i32.const 128)
+        )
+       )
+       (i32.store8 offset=3
+        (local.get $0)
+        (i32.or
+         (i32.and
+          (local.get $1)
+          (i32.const 63)
+         )
+         (i32.const 128)
+        )
+       )
+       (i32.const 4)
+      )
+      (block (result i32)
+       (i32.store
+        (call $___errno_location)
+        (i32.const 84)
+       )
+       (i32.const -1)
+      )
+     )
+    )
+    (i32.const 1)
+   )
+  )
+ )
+ (func $_wctomb (param $0 i32) (param $1 i32) (result i32)
+  (if (result i32)
+   (local.get $0)
+   (call $_wcrtomb
+    (local.get $0)
+    (local.get $1)
+    (i32.const 0)
+   )
+   (i32.const 0)
+  )
+ )
+ (func $_memchr (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $5
+   (i32.and
+    (local.get $1)
+    (i32.const 255)
+   )
+  )
+  (block $label$break$L8
+   (block $__rjti$2
+    (if
+     (i32.and
+      (local.tee $4
+       (i32.ne
+        (local.get $2)
+        (i32.const 0)
+       )
+      )
+      (i32.ne
+       (i32.and
+        (local.get $0)
+        (i32.const 3)
+       )
+       (i32.const 0)
+      )
+     )
+     (block
+      (local.set $4
+       (i32.and
+        (local.get $1)
+        (i32.const 255)
+       )
+      )
+      (local.set $3
+       (local.get $2)
+      )
+      (local.set $2
+       (local.get $0)
+      )
+      (loop $while-in
+       (br_if $__rjti$2
+        (i32.eq
+         (i32.load8_u
+          (local.get $2)
+         )
+         (i32.and
+          (local.get $4)
+          (i32.const 255)
+         )
+        )
+       )
+       (br_if $while-in
+        (i32.and
+         (local.tee $0
+          (i32.ne
+           (local.tee $3
+            (i32.add
+             (local.get $3)
+             (i32.const -1)
+            )
+           )
+           (i32.const 0)
+          )
+         )
+         (i32.ne
+          (i32.and
+           (local.tee $2
+            (i32.add
+             (local.get $2)
+             (i32.const 1)
+            )
+           )
+           (i32.const 3)
+          )
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (block
+      (local.set $3
+       (local.get $2)
+      )
+      (local.set $2
+       (local.get $0)
+      )
+      (local.set $0
+       (local.get $4)
+      )
+     )
+    )
+    (br_if $__rjti$2
+     (local.get $0)
+    )
+    (local.set $0
+     (i32.const 0)
+    )
+    (br $label$break$L8)
+   )
+   (local.set $0
+    (local.get $3)
+   )
+   (if
+    (i32.ne
+     (i32.load8_u
+      (local.get $2)
+     )
+     (local.tee $1
+      (i32.and
+       (local.get $1)
+       (i32.const 255)
+      )
+     )
+    )
+    (block
+     (local.set $3
+      (i32.mul
+       (local.get $5)
+       (i32.const 16843009)
+      )
+     )
+     (block $__rjto$0
+      (block $__rjti$0
+       (br_if $__rjti$0
+        (i32.le_u
+         (local.get $0)
+         (i32.const 3)
+        )
+       )
+       (loop $while-in3
+        (if
+         (i32.eqz
+          (i32.and
+           (i32.xor
+            (i32.and
+             (local.tee $4
+              (i32.xor
+               (i32.load
+                (local.get $2)
+               )
+               (local.get $3)
+              )
+             )
+             (i32.const -2139062144)
+            )
+            (i32.const -2139062144)
+           )
+           (i32.add
+            (local.get $4)
+            (i32.const -16843009)
+           )
+          )
+         )
+         (block
+          (local.set $2
+           (i32.add
+            (local.get $2)
+            (i32.const 4)
+           )
+          )
+          (br_if $while-in3
+           (i32.gt_u
+            (local.tee $0
+             (i32.add
+              (local.get $0)
+              (i32.const -4)
+             )
+            )
+            (i32.const 3)
+           )
+          )
+          (br $__rjti$0)
+         )
+        )
+       )
+       (br $__rjto$0)
+      )
+      (if
+       (i32.eqz
+        (local.get $0)
+       )
+       (block
+        (local.set $0
+         (i32.const 0)
+        )
+        (br $label$break$L8)
+       )
+      )
+     )
+     (loop $while-in5
+      (br_if $label$break$L8
+       (i32.eq
+        (i32.load8_u
+         (local.get $2)
+        )
+        (i32.and
+         (local.get $1)
+         (i32.const 255)
+        )
+       )
+      )
+      (local.set $2
+       (i32.add
+        (local.get $2)
+        (i32.const 1)
+       )
+      )
+      (br_if $while-in5
+       (local.tee $0
+        (i32.add
+         (local.get $0)
+         (i32.const -1)
+        )
+       )
+      )
+      (local.set $0
+       (i32.const 0)
+      )
+     )
+    )
+   )
+  )
+  (select
+   (local.get $2)
+   (i32.const 0)
+   (local.get $0)
+  )
+ )
+ (func $___syscall_ret (param $0 i32) (result i32)
+  (if (result i32)
+   (i32.gt_u
+    (local.get $0)
+    (i32.const -4096)
+   )
+   (block (result i32)
+    (i32.store
+     (call $___errno_location)
+     (i32.sub
+      (i32.const 0)
+      (local.get $0)
+     )
+    )
+    (i32.const -1)
+   )
+   (local.get $0)
+  )
+ )
+ (func $___fflush_unlocked (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local.tee $0
+   (block $__rjto$0 (result i32)
+    (block $__rjti$0
+     (br_if $__rjti$0
+      (i32.le_u
+       (i32.load
+        (local.tee $1
+         (i32.add
+          (local.get $0)
+          (i32.const 20)
+         )
+        )
+       )
+       (i32.load
+        (local.tee $2
+         (i32.add
+          (local.get $0)
+          (i32.const 28)
+         )
+        )
+       )
+      )
+     )
+     (drop
+      (call_indirect (type $FUNCSIG$iiii)
+       (local.get $0)
+       (i32.const 0)
+       (i32.const 0)
+       (i32.add
+        (i32.and
+         (i32.load offset=36
+          (local.get $0)
+         )
+         (i32.const 7)
+        )
+        (i32.const 2)
+       )
+      )
+     )
+     (br_if $__rjti$0
+      (i32.load
+       (local.get $1)
+      )
+     )
+     (br $__rjto$0
+      (i32.const -1)
+     )
+    )
+    (if
+     (i32.lt_u
+      (local.tee $4
+       (i32.load
+        (local.tee $3
+         (i32.add
+          (local.get $0)
+          (i32.const 4)
+         )
+        )
+       )
+      )
+      (local.tee $6
+       (i32.load
+        (local.tee $5
+         (i32.add
+          (local.get $0)
+          (i32.const 8)
+         )
+        )
+       )
+      )
+     )
+     (drop
+      (call_indirect (type $FUNCSIG$iiii)
+       (local.get $0)
+       (i32.sub
+        (local.get $4)
+        (local.get $6)
+       )
+       (i32.const 1)
+       (i32.add
+        (i32.and
+         (i32.load offset=40
+          (local.get $0)
+         )
+         (i32.const 7)
+        )
+        (i32.const 2)
+       )
+      )
+     )
+    )
+    (i32.store offset=16
+     (local.get $0)
+     (i32.const 0)
+    )
+    (i32.store
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.store
+     (local.get $1)
+     (i32.const 0)
+    )
+    (i32.store
+     (local.get $5)
+     (i32.const 0)
+    )
+    (i32.store
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.const 0)
+   )
+  )
+ )
+ (func $_cleanup (param $0 i32)
+  (if
+   (i32.eqz
+    (i32.load offset=68
+     (local.get $0)
+    )
+   )
+   (call $___unlockfile
+    (local.get $0)
+   )
+  )
+ )
+ (func $f64-to-int (param $0 f64) (result i32)
+  (if (result i32)
+   (f64.ne
+    (local.get $0)
+    (local.get $0)
+   )
+   (i32.const -2147483648)
+   (if (result i32)
+    (f64.ge
+     (local.get $0)
+     (f64.const 2147483648)
+    )
+    (i32.const -2147483648)
+    (if (result i32)
+     (f64.le
+      (local.get $0)
+      (f64.const -2147483649)
+     )
+     (i32.const -2147483648)
+     (i32.trunc_f64_s
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $i32s-div (param $0 i32) (param $1 i32) (result i32)
+  (if (result i32)
+   (local.get $1)
+   (if (result i32)
+    (i32.and
+     (i32.eq
+      (local.get $0)
+      (i32.const -2147483648)
+     )
+     (i32.eq
+      (local.get $1)
+      (i32.const -1)
+     )
+    )
+    (i32.const 0)
+    (i32.div_s
+     (local.get $0)
+     (local.get $1)
+    )
+   )
+   (i32.const 0)
+  )
+ )
+ (func $i32u-rem (param $0 i32) (param $1 i32) (result i32)
+  (if (result i32)
+   (local.get $1)
+   (i32.rem_u
+    (local.get $0)
+    (local.get $1)
+   )
+   (i32.const 0)
+  )
+ )
+ (func $i32u-div (param $0 i32) (param $1 i32) (result i32)
+  (if (result i32)
+   (local.get $1)
+   (i32.div_u
+    (local.get $0)
+    (local.get $1)
+   )
+   (i32.const 0)
+  )
+ )
+ (func $_printf_core (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (result i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 f64)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (local $19 i32)
+  (local $20 i32)
+  (local $21 i32)
+  (local $22 i32)
+  (local $23 f64)
+  (local $24 i32)
+  (local $25 i32)
+  (local $26 i32)
+  (local $27 i32)
+  (local $28 i32)
+  (local $29 i32)
+  (local $30 i32)
+  (local $31 i32)
+  (local $32 i32)
+  (local $33 i32)
+  (local $34 i32)
+  (local $35 i32)
+  (local $36 i32)
+  (local $37 i32)
+  (local $38 i32)
+  (local $39 i32)
+  (local $40 i32)
+  (local $41 i32)
+  (local $42 i32)
+  (local $43 i32)
+  (local $44 i32)
+  (local $45 i32)
+  (local $46 i32)
+  (local $47 i32)
+  (local $48 i32)
+  (local $49 i32)
+  (local $50 i32)
+  (local $51 i32)
+  (local.set $25
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 624)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (local.set $20
+   (i32.add
+    (local.get $25)
+    (i32.const 16)
+   )
+  )
+  (local.set $19
+   (local.get $25)
+  )
+  (local.set $36
+   (i32.add
+    (local.get $25)
+    (i32.const 528)
+   )
+  )
+  (local.set $29
+   (i32.ne
+    (local.get $0)
+    (i32.const 0)
+   )
+  )
+  (local.set $39
+   (local.tee $26
+    (i32.add
+     (local.tee $5
+      (i32.add
+       (local.get $25)
+       (i32.const 536)
+      )
+     )
+     (i32.const 40)
+    )
+   )
+  )
+  (local.set $40
+   (i32.add
+    (local.get $5)
+    (i32.const 39)
+   )
+  )
+  (local.set $44
+   (i32.add
+    (local.tee $41
+     (i32.add
+      (local.get $25)
+      (i32.const 8)
+     )
+    )
+    (i32.const 4)
+   )
+  )
+  (local.set $34
+   (i32.add
+    (local.tee $5
+     (i32.add
+      (local.get $25)
+      (i32.const 576)
+     )
+    )
+    (i32.const 12)
+   )
+  )
+  (local.set $42
+   (i32.add
+    (local.get $5)
+    (i32.const 11)
+   )
+  )
+  (local.set $45
+   (i32.sub
+    (local.tee $28
+     (local.get $34)
+    )
+    (local.tee $37
+     (local.tee $22
+      (i32.add
+       (local.get $25)
+       (i32.const 588)
+      )
+     )
+    )
+   )
+  )
+  (local.set $46
+   (i32.sub
+    (i32.const -2)
+    (local.get $37)
+   )
+  )
+  (local.set $47
+   (i32.add
+    (local.get $28)
+    (i32.const 2)
+   )
+  )
+  (local.set $49
+   (i32.add
+    (local.tee $48
+     (i32.add
+      (local.get $25)
+      (i32.const 24)
+     )
+    )
+    (i32.const 288)
+   )
+  )
+  (local.set $43
+   (local.tee $30
+    (i32.add
+     (local.get $22)
+     (i32.const 9)
+    )
+   )
+  )
+  (local.set $35
+   (i32.add
+    (local.get $22)
+    (i32.const 8)
+   )
+  )
+  (local.set $16
+   (i32.const 0)
+  )
+  (local.set $5
+   (local.get $1)
+  )
+  (local.set $10
+   (i32.const 0)
+  )
+  (local.set $1
+   (i32.const 0)
+  )
+  (block $label$break$L343
+   (block $__rjti$9
+    (loop $label$continue$L1
+     (block $label$break$L1
+      (if
+       (i32.gt_s
+        (local.get $16)
+        (i32.const -1)
+       )
+       (local.set $16
+        (if (result i32)
+         (i32.gt_s
+          (local.get $10)
+          (i32.sub
+           (i32.const 2147483647)
+           (local.get $16)
+          )
+         )
+         (block (result i32)
+          (i32.store
+           (call $___errno_location)
+           (i32.const 75)
+          )
+          (i32.const -1)
+         )
+         (i32.add
+          (local.get $10)
+          (local.get $16)
+         )
+        )
+       )
+      )
+      (br_if $__rjti$9
+       (i32.eqz
+        (local.tee $7
+         (i32.load8_s
+          (local.get $5)
+         )
+        )
+       )
+      )
+      (local.set $10
+       (local.get $5)
+      )
+      (block $label$break$L12
+       (block $__rjti$1
+        (loop $label$continue$L9
+         (block $label$break$L9
+          (block $switch-default
+           (block $switch-case0
+            (block $switch-case
+             (br_table $switch-case0 $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-case $switch-default
+              (i32.shr_s
+               (i32.shl
+                (local.get $7)
+                (i32.const 24)
+               )
+               (i32.const 24)
+              )
+             )
+            )
+            (local.set $6
+             (local.get $10)
+            )
+            (br $__rjti$1)
+           )
+           (local.set $6
+            (local.get $10)
+           )
+           (br $label$break$L9)
+          )
+          (local.set $7
+           (i32.load8_s
+            (local.tee $10
+             (i32.add
+              (local.get $10)
+              (i32.const 1)
+             )
+            )
+           )
+          )
+          (br $label$continue$L9)
+         )
+        )
+        (br $label$break$L12)
+       )
+       (loop $while-in
+        (br_if $label$break$L12
+         (i32.ne
+          (i32.load8_s offset=1
+           (local.get $6)
+          )
+          (i32.const 37)
+         )
+        )
+        (local.set $10
+         (i32.add
+          (local.get $10)
+          (i32.const 1)
+         )
+        )
+        (br_if $while-in
+         (i32.eq
+          (i32.load8_s
+           (local.tee $6
+            (i32.add
+             (local.get $6)
+             (i32.const 2)
+            )
+           )
+          )
+          (i32.const 37)
+         )
+        )
+       )
+      )
+      (local.set $7
+       (i32.sub
+        (local.get $10)
+        (local.get $5)
+       )
+      )
+      (if
+       (local.get $29)
+       (if
+        (i32.eqz
+         (i32.and
+          (i32.load
+           (local.get $0)
+          )
+          (i32.const 32)
+         )
+        )
+        (drop
+         (call $___fwritex
+          (local.get $5)
+          (local.get $7)
+          (local.get $0)
+         )
+        )
+       )
+      )
+      (if
+       (i32.ne
+        (local.get $10)
+        (local.get $5)
+       )
+       (block
+        (local.set $5
+         (local.get $6)
+        )
+        (local.set $10
+         (local.get $7)
+        )
+        (br $label$continue$L1)
+       )
+      )
+      (local.set $8
+       (if (result i32)
+        (i32.lt_u
+         (local.tee $8
+          (i32.add
+           (local.tee $11
+            (i32.load8_s
+             (local.tee $10
+              (i32.add
+               (local.get $6)
+               (i32.const 1)
+              )
+             )
+            )
+           )
+           (i32.const -48)
+          )
+         )
+         (i32.const 10)
+        )
+        (block (result i32)
+         (local.set $6
+          (i32.load8_s
+           (local.tee $10
+            (select
+             (i32.add
+              (local.get $6)
+              (i32.const 3)
+             )
+             (local.get $10)
+             (local.tee $11
+              (i32.eq
+               (i32.load8_s offset=2
+                (local.get $6)
+               )
+               (i32.const 36)
+              )
+             )
+            )
+           )
+          )
+         )
+         (local.set $17
+          (select
+           (local.get $8)
+           (i32.const -1)
+           (local.get $11)
+          )
+         )
+         (select
+          (i32.const 1)
+          (local.get $1)
+          (local.get $11)
+         )
+        )
+        (block (result i32)
+         (local.set $6
+          (local.get $11)
+         )
+         (local.set $17
+          (i32.const -1)
+         )
+         (local.get $1)
+        )
+       )
+      )
+      (block $label$break$L25
+       (if
+        (i32.eq
+         (i32.and
+          (local.tee $11
+           (i32.shr_s
+            (i32.shl
+             (local.get $6)
+             (i32.const 24)
+            )
+            (i32.const 24)
+           )
+          )
+          (i32.const -32)
+         )
+         (i32.const 32)
+        )
+        (block
+         (local.set $1
+          (local.get $6)
+         )
+         (local.set $6
+          (local.get $11)
+         )
+         (local.set $11
+          (i32.const 0)
+         )
+         (loop $while-in4
+          (if
+           (i32.eqz
+            (i32.and
+             (i32.shl
+              (i32.const 1)
+              (i32.add
+               (local.get $6)
+               (i32.const -32)
+              )
+             )
+             (i32.const 75913)
+            )
+           )
+           (block
+            (local.set $6
+             (local.get $1)
+            )
+            (local.set $1
+             (local.get $11)
+            )
+            (br $label$break$L25)
+           )
+          )
+          (local.set $11
+           (i32.or
+            (i32.shl
+             (i32.const 1)
+             (i32.add
+              (i32.shr_s
+               (i32.shl
+                (local.get $1)
+                (i32.const 24)
+               )
+               (i32.const 24)
+              )
+              (i32.const -32)
+             )
+            )
+            (local.get $11)
+           )
+          )
+          (br_if $while-in4
+           (i32.eq
+            (i32.and
+             (local.tee $6
+              (local.tee $1
+               (i32.load8_s
+                (local.tee $10
+                 (i32.add
+                  (local.get $10)
+                  (i32.const 1)
+                 )
+                )
+               )
+              )
+             )
+             (i32.const -32)
+            )
+            (i32.const 32)
+           )
+          )
+          (local.set $6
+           (local.get $1)
+          )
+          (local.set $1
+           (local.get $11)
+          )
+         )
+        )
+        (local.set $1
+         (i32.const 0)
+        )
+       )
+      )
+      (block $do-once5
+       (if
+        (i32.eq
+         (i32.and
+          (local.get $6)
+          (i32.const 255)
+         )
+         (i32.const 42)
+        )
+        (block
+         (local.set $10
+          (block $__rjto$0 (result i32)
+           (block $__rjti$0
+            (br_if $__rjti$0
+             (i32.ge_u
+              (local.tee $11
+               (i32.add
+                (i32.load8_s
+                 (local.tee $6
+                  (i32.add
+                   (local.get $10)
+                   (i32.const 1)
+                  )
+                 )
+                )
+                (i32.const -48)
+               )
+              )
+              (i32.const 10)
+             )
+            )
+            (br_if $__rjti$0
+             (i32.ne
+              (i32.load8_s offset=2
+               (local.get $10)
+              )
+              (i32.const 36)
+             )
+            )
+            (i32.store
+             (i32.add
+              (local.get $4)
+              (i32.shl
+               (local.get $11)
+               (i32.const 2)
+              )
+             )
+             (i32.const 10)
+            )
+            (drop
+             (i32.load offset=4
+              (local.tee $6
+               (i32.add
+                (local.get $3)
+                (i32.shl
+                 (i32.add
+                  (i32.load8_s
+                   (local.get $6)
+                  )
+                  (i32.const -48)
+                 )
+                 (i32.const 3)
+                )
+               )
+              )
+             )
+            )
+            (local.set $8
+             (i32.const 1)
+            )
+            (local.set $14
+             (i32.load
+              (local.get $6)
+             )
+            )
+            (br $__rjto$0
+             (i32.add
+              (local.get $10)
+              (i32.const 3)
+             )
+            )
+           )
+           (if
+            (local.get $8)
+            (block
+             (local.set $16
+              (i32.const -1)
+             )
+             (br $label$break$L1)
+            )
+           )
+           (if
+            (i32.eqz
+             (local.get $29)
+            )
+            (block
+             (local.set $11
+              (local.get $1)
+             )
+             (local.set $10
+              (local.get $6)
+             )
+             (local.set $1
+              (i32.const 0)
+             )
+             (local.set $14
+              (i32.const 0)
+             )
+             (br $do-once5)
+            )
+           )
+           (local.set $14
+            (i32.load
+             (local.tee $10
+              (i32.and
+               (i32.add
+                (i32.load
+                 (local.get $2)
+                )
+                (i32.const 3)
+               )
+               (i32.const -4)
+              )
+             )
+            )
+           )
+           (i32.store
+            (local.get $2)
+            (i32.add
+             (local.get $10)
+             (i32.const 4)
+            )
+           )
+           (local.set $8
+            (i32.const 0)
+           )
+           (local.get $6)
+          )
+         )
+         (local.set $11
+          (if (result i32)
+           (i32.lt_s
+            (local.get $14)
+            (i32.const 0)
+           )
+           (block (result i32)
+            (local.set $14
+             (i32.sub
+              (i32.const 0)
+              (local.get $14)
+             )
+            )
+            (i32.or
+             (local.get $1)
+             (i32.const 8192)
+            )
+           )
+           (local.get $1)
+          )
+         )
+         (local.set $1
+          (local.get $8)
+         )
+        )
+        (if
+         (i32.lt_u
+          (local.tee $6
+           (i32.add
+            (i32.shr_s
+             (i32.shl
+              (local.get $6)
+              (i32.const 24)
+             )
+             (i32.const 24)
+            )
+            (i32.const -48)
+           )
+          )
+          (i32.const 10)
+         )
+         (block
+          (local.set $11
+           (i32.const 0)
+          )
+          (loop $while-in8
+           (local.set $6
+            (i32.add
+             (i32.mul
+              (local.get $11)
+              (i32.const 10)
+             )
+             (local.get $6)
+            )
+           )
+           (if
+            (i32.lt_u
+             (local.tee $9
+              (i32.add
+               (i32.load8_s
+                (local.tee $10
+                 (i32.add
+                  (local.get $10)
+                  (i32.const 1)
+                 )
+                )
+               )
+               (i32.const -48)
+              )
+             )
+             (i32.const 10)
+            )
+            (block
+             (local.set $11
+              (local.get $6)
+             )
+             (local.set $6
+              (local.get $9)
+             )
+             (br $while-in8)
+            )
+           )
+          )
+          (if
+           (i32.lt_s
+            (local.get $6)
+            (i32.const 0)
+           )
+           (block
+            (local.set $16
+             (i32.const -1)
+            )
+            (br $label$break$L1)
+           )
+           (block
+            (local.set $11
+             (local.get $1)
+            )
+            (local.set $1
+             (local.get $8)
+            )
+            (local.set $14
+             (local.get $6)
+            )
+           )
+          )
+         )
+         (block
+          (local.set $11
+           (local.get $1)
+          )
+          (local.set $1
+           (local.get $8)
+          )
+          (local.set $14
+           (i32.const 0)
+          )
+         )
+        )
+       )
+      )
+      (local.set $6
+       (block $label$break$L46 (result i32)
+        (if (result i32)
+         (i32.eq
+          (i32.load8_s
+           (local.get $10)
+          )
+          (i32.const 46)
+         )
+         (block (result i32)
+          (if
+           (i32.ne
+            (local.tee $8
+             (i32.load8_s
+              (local.tee $6
+               (i32.add
+                (local.get $10)
+                (i32.const 1)
+               )
+              )
+             )
+            )
+            (i32.const 42)
+           )
+           (block
+            (if
+             (i32.lt_u
+              (local.tee $9
+               (i32.add
+                (local.get $8)
+                (i32.const -48)
+               )
+              )
+              (i32.const 10)
+             )
+             (block
+              (local.set $10
+               (local.get $6)
+              )
+              (local.set $8
+               (i32.const 0)
+              )
+              (local.set $6
+               (local.get $9)
+              )
+             )
+             (block
+              (local.set $10
+               (local.get $6)
+              )
+              (br $label$break$L46
+               (i32.const 0)
+              )
+             )
+            )
+            (loop $while-in11
+             (drop
+              (br_if $label$break$L46
+               (local.tee $6
+                (i32.add
+                 (i32.mul
+                  (local.get $8)
+                  (i32.const 10)
+                 )
+                 (local.get $6)
+                )
+               )
+               (i32.ge_u
+                (local.tee $9
+                 (i32.add
+                  (i32.load8_s
+                   (local.tee $10
+                    (i32.add
+                     (local.get $10)
+                     (i32.const 1)
+                    )
+                   )
+                  )
+                  (i32.const -48)
+                 )
+                )
+                (i32.const 10)
+               )
+              )
+             )
+             (local.set $8
+              (local.get $6)
+             )
+             (local.set $6
+              (local.get $9)
+             )
+             (br $while-in11)
+            )
+           )
+          )
+          (if
+           (i32.lt_u
+            (local.tee $8
+             (i32.add
+              (i32.load8_s
+               (local.tee $6
+                (i32.add
+                 (local.get $10)
+                 (i32.const 2)
+                )
+               )
+              )
+              (i32.const -48)
+             )
+            )
+            (i32.const 10)
+           )
+           (if
+            (i32.eq
+             (i32.load8_s offset=3
+              (local.get $10)
+             )
+             (i32.const 36)
+            )
+            (block
+             (i32.store
+              (i32.add
+               (local.get $4)
+               (i32.shl
+                (local.get $8)
+                (i32.const 2)
+               )
+              )
+              (i32.const 10)
+             )
+             (drop
+              (i32.load offset=4
+               (local.tee $6
+                (i32.add
+                 (local.get $3)
+                 (i32.shl
+                  (i32.add
+                   (i32.load8_s
+                    (local.get $6)
+                   )
+                   (i32.const -48)
+                  )
+                  (i32.const 3)
+                 )
+                )
+               )
+              )
+             )
+             (local.set $10
+              (i32.add
+               (local.get $10)
+               (i32.const 4)
+              )
+             )
+             (br $label$break$L46
+              (i32.load
+               (local.get $6)
+              )
+             )
+            )
+           )
+          )
+          (if
+           (local.get $1)
+           (block
+            (local.set $16
+             (i32.const -1)
+            )
+            (br $label$break$L1)
+           )
+          )
+          (if (result i32)
+           (local.get $29)
+           (block (result i32)
+            (local.set $8
+             (i32.load
+              (local.tee $10
+               (i32.and
+                (i32.add
+                 (i32.load
+                  (local.get $2)
+                 )
+                 (i32.const 3)
+                )
+                (i32.const -4)
+               )
+              )
+             )
+            )
+            (i32.store
+             (local.get $2)
+             (i32.add
+              (local.get $10)
+              (i32.const 4)
+             )
+            )
+            (local.set $10
+             (local.get $6)
+            )
+            (local.get $8)
+           )
+           (block (result i32)
+            (local.set $10
+             (local.get $6)
+            )
+            (i32.const 0)
+           )
+          )
+         )
+         (i32.const -1)
+        )
+       )
+      )
+      (local.set $8
+       (local.get $10)
+      )
+      (local.set $9
+       (i32.const 0)
+      )
+      (loop $while-in13
+       (if
+        (i32.gt_u
+         (local.tee $12
+          (i32.add
+           (i32.load8_s
+            (local.get $8)
+           )
+           (i32.const -65)
+          )
+         )
+         (i32.const 57)
+        )
+        (block
+         (local.set $16
+          (i32.const -1)
+         )
+         (br $label$break$L1)
+        )
+       )
+       (local.set $10
+        (i32.add
+         (local.get $8)
+         (i32.const 1)
+        )
+       )
+       (if
+        (i32.lt_u
+         (i32.add
+          (local.tee $12
+           (i32.and
+            (local.tee $13
+             (i32.load8_s
+              (i32.add
+               (i32.add
+                (i32.mul
+                 (local.get $9)
+                 (i32.const 58)
+                )
+                (i32.const 3611)
+               )
+               (local.get $12)
+              )
+             )
+            )
+            (i32.const 255)
+           )
+          )
+          (i32.const -1)
+         )
+         (i32.const 8)
+        )
+        (block
+         (local.set $8
+          (local.get $10)
+         )
+         (local.set $9
+          (local.get $12)
+         )
+         (br $while-in13)
+        )
+        (local.set $18
+         (local.get $8)
+        )
+       )
+      )
+      (if
+       (i32.eqz
+        (i32.and
+         (local.get $13)
+         (i32.const 255)
+        )
+       )
+       (block
+        (local.set $16
+         (i32.const -1)
+        )
+        (br $label$break$L1)
+       )
+      )
+      (local.set $8
+       (i32.gt_s
+        (local.get $17)
+        (i32.const -1)
+       )
+      )
+      (block $__rjto$2
+       (block $__rjti$2
+        (if
+         (i32.eq
+          (i32.and
+           (local.get $13)
+           (i32.const 255)
+          )
+          (i32.const 19)
+         )
+         (if
+          (local.get $8)
+          (block
+           (local.set $16
+            (i32.const -1)
+           )
+           (br $label$break$L1)
+          )
+          (br $__rjti$2)
+         )
+         (block
+          (if
+           (local.get $8)
+           (block
+            (i32.store
+             (i32.add
+              (local.get $4)
+              (i32.shl
+               (local.get $17)
+               (i32.const 2)
+              )
+             )
+             (local.get $12)
+            )
+            (local.set $13
+             (i32.load offset=4
+              (local.tee $12
+               (i32.add
+                (local.get $3)
+                (i32.shl
+                 (local.get $17)
+                 (i32.const 3)
+                )
+               )
+              )
+             )
+            )
+            (i32.store
+             (local.tee $8
+              (local.get $19)
+             )
+             (i32.load
+              (local.get $12)
+             )
+            )
+            (i32.store offset=4
+             (local.get $8)
+             (local.get $13)
+            )
+            (br $__rjti$2)
+           )
+          )
+          (if
+           (i32.eqz
+            (local.get $29)
+           )
+           (block
+            (local.set $16
+             (i32.const 0)
+            )
+            (br $label$break$L1)
+           )
+          )
+          (call $_pop_arg_336
+           (local.get $19)
+           (local.get $12)
+           (local.get $2)
+          )
+         )
+        )
+        (br $__rjto$2)
+       )
+       (if
+        (i32.eqz
+         (local.get $29)
+        )
+        (block
+         (local.set $5
+          (local.get $10)
+         )
+         (local.set $10
+          (local.get $7)
+         )
+         (br $label$continue$L1)
+        )
+       )
+      )
+      (local.set $11
+       (select
+        (local.tee $8
+         (i32.and
+          (local.get $11)
+          (i32.const -65537)
+         )
+        )
+        (local.get $11)
+        (i32.and
+         (local.get $11)
+         (i32.const 8192)
+        )
+       )
+      )
+      (local.set $5
+       (block $__rjto$8 (result i32)
+        (block $__rjti$8
+         (block $__rjti$7
+          (block $__rjti$6
+           (block $__rjti$5
+            (block $__rjti$4
+             (block $__rjti$3
+              (block $switch-default120
+               (block $switch-case42
+                (block $switch-case41
+                 (block $switch-case40
+                  (block $switch-case39
+                   (block $switch-case38
+                    (block $switch-case37
+                     (block $switch-case36
+                      (block $switch-case34
+                       (block $switch-case33
+                        (block $switch-case29
+                         (block $switch-case28
+                          (block $switch-case27
+                           (br_table $switch-case42 $switch-default120 $switch-case40 $switch-default120 $switch-case42 $switch-case42 $switch-case42 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-case41 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-case29 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-default120 $switch-case42 $switch-default120 $switch-case37 $switch-case34 $switch-case42 $switch-case42 $switch-case42 $switch-default120 $switch-case34 $switch-default120 $switch-default120 $switch-default120 $switch-case38 $switch-case27 $switch-case33 $switch-case28 $switch-default120 $switch-default120 $switch-case39 $switch-default120 $switch-case36 $switch-default120 $switch-default120 $switch-case29 $switch-default120
+                            (i32.sub
+                             (local.tee $18
+                              (select
+                               (i32.and
+                                (local.tee $12
+                                 (i32.load8_s
+                                  (local.get $18)
+                                 )
+                                )
+                                (i32.const -33)
+                               )
+                               (local.get $12)
+                               (i32.and
+                                (i32.ne
+                                 (local.get $9)
+                                 (i32.const 0)
+                                )
+                                (i32.eq
+                                 (i32.and
+                                  (local.get $12)
+                                  (i32.const 15)
+                                 )
+                                 (i32.const 3)
+                                )
+                               )
+                              )
+                             )
+                             (i32.const 65)
+                            )
+                           )
+                          )
+                          (block $switch-default26
+                           (block $switch-case25
+                            (block $switch-case24
+                             (block $switch-case23
+                              (block $switch-case22
+                               (block $switch-case21
+                                (block $switch-case20
+                                 (block $switch-case19
+                                  (br_table $switch-case19 $switch-case20 $switch-case21 $switch-case22 $switch-case23 $switch-default26 $switch-case24 $switch-case25 $switch-default26
+                                   (local.get $9)
+                                  )
+                                 )
+                                 (i32.store
+                                  (i32.load
+                                   (local.get $19)
+                                  )
+                                  (local.get $16)
+                                 )
+                                 (local.set $5
+                                  (local.get $10)
+                                 )
+                                 (local.set $10
+                                  (local.get $7)
+                                 )
+                                 (br $label$continue$L1)
+                                )
+                                (i32.store
+                                 (i32.load
+                                  (local.get $19)
+                                 )
+                                 (local.get $16)
+                                )
+                                (local.set $5
+                                 (local.get $10)
+                                )
+                                (local.set $10
+                                 (local.get $7)
+                                )
+                                (br $label$continue$L1)
+                               )
+                               (i32.store
+                                (local.tee $5
+                                 (i32.load
+                                  (local.get $19)
+                                 )
+                                )
+                                (local.get $16)
+                               )
+                               (i32.store offset=4
+                                (local.get $5)
+                                (i32.shr_s
+                                 (i32.shl
+                                  (i32.lt_s
+                                   (local.get $16)
+                                   (i32.const 0)
+                                  )
+                                  (i32.const 31)
+                                 )
+                                 (i32.const 31)
+                                )
+                               )
+                               (local.set $5
+                                (local.get $10)
+                               )
+                               (local.set $10
+                                (local.get $7)
+                               )
+                               (br $label$continue$L1)
+                              )
+                              (i32.store16
+                               (i32.load
+                                (local.get $19)
+                               )
+                               (local.get $16)
+                              )
+                              (local.set $5
+                               (local.get $10)
+                              )
+                              (local.set $10
+                               (local.get $7)
+                              )
+                              (br $label$continue$L1)
+                             )
+                             (i32.store8
+                              (i32.load
+                               (local.get $19)
+                              )
+                              (local.get $16)
+                             )
+                             (local.set $5
+                              (local.get $10)
+                             )
+                             (local.set $10
+                              (local.get $7)
+                             )
+                             (br $label$continue$L1)
+                            )
+                            (i32.store
+                             (i32.load
+                              (local.get $19)
+                             )
+                             (local.get $16)
+                            )
+                            (local.set $5
+                             (local.get $10)
+                            )
+                            (local.set $10
+                             (local.get $7)
+                            )
+                            (br $label$continue$L1)
+                           )
+                           (i32.store
+                            (local.tee $5
+                             (i32.load
+                              (local.get $19)
+                             )
+                            )
+                            (local.get $16)
+                           )
+                           (i32.store offset=4
+                            (local.get $5)
+                            (i32.shr_s
+                             (i32.shl
+                              (i32.lt_s
+                               (local.get $16)
+                               (i32.const 0)
+                              )
+                              (i32.const 31)
+                             )
+                             (i32.const 31)
+                            )
+                           )
+                           (local.set $5
+                            (local.get $10)
+                           )
+                           (local.set $10
+                            (local.get $7)
+                           )
+                           (br $label$continue$L1)
+                          )
+                          (local.set $5
+                           (local.get $10)
+                          )
+                          (local.set $10
+                           (local.get $7)
+                          )
+                          (br $label$continue$L1)
+                         )
+                         (local.set $7
+                          (i32.or
+                           (local.get $11)
+                           (i32.const 8)
+                          )
+                         )
+                         (local.set $6
+                          (select
+                           (local.get $6)
+                           (i32.const 8)
+                           (i32.gt_u
+                            (local.get $6)
+                            (i32.const 8)
+                           )
+                          )
+                         )
+                         (local.set $18
+                          (i32.const 120)
+                         )
+                         (br $__rjti$3)
+                        )
+                        (local.set $7
+                         (local.get $11)
+                        )
+                        (br $__rjti$3)
+                       )
+                       (if
+                        (i32.and
+                         (i32.eqz
+                          (local.tee $7
+                           (i32.load
+                            (local.tee $5
+                             (local.get $19)
+                            )
+                           )
+                          )
+                         )
+                         (i32.eqz
+                          (local.tee $8
+                           (i32.load offset=4
+                            (local.get $5)
+                           )
+                          )
+                         )
+                        )
+                        (local.set $8
+                         (local.get $26)
+                        )
+                        (block
+                         (local.set $5
+                          (local.get $7)
+                         )
+                         (local.set $7
+                          (local.get $8)
+                         )
+                         (local.set $8
+                          (local.get $26)
+                         )
+                         (loop $while-in32
+                          (i32.store8
+                           (local.tee $8
+                            (i32.add
+                             (local.get $8)
+                             (i32.const -1)
+                            )
+                           )
+                           (i32.or
+                            (i32.and
+                             (local.get $5)
+                             (i32.const 7)
+                            )
+                            (i32.const 48)
+                           )
+                          )
+                          (br_if $while-in32
+                           (i32.eqz
+                            (i32.and
+                             (i32.eqz
+                              (local.tee $5
+                               (call $_bitshift64Lshr
+                                (local.get $5)
+                                (local.get $7)
+                                (i32.const 3)
+                               )
+                              )
+                             )
+                             (i32.eqz
+                              (local.tee $7
+                               (global.get $tempRet0)
+                              )
+                             )
+                            )
+                           )
+                          )
+                         )
+                        )
+                       )
+                       (local.set $5
+                        (if (result i32)
+                         (i32.and
+                          (local.get $11)
+                          (i32.const 8)
+                         )
+                         (block (result i32)
+                          (local.set $7
+                           (local.get $11)
+                          )
+                          (local.set $6
+                           (select
+                            (local.tee $11
+                             (i32.add
+                              (i32.sub
+                               (local.get $39)
+                               (local.get $8)
+                              )
+                              (i32.const 1)
+                             )
+                            )
+                            (local.get $6)
+                            (i32.lt_s
+                             (local.get $6)
+                             (local.get $11)
+                            )
+                           )
+                          )
+                          (local.get $8)
+                         )
+                         (block (result i32)
+                          (local.set $7
+                           (local.get $11)
+                          )
+                          (local.get $8)
+                         )
+                        )
+                       )
+                       (local.set $8
+                        (i32.const 0)
+                       )
+                       (local.set $9
+                        (i32.const 4091)
+                       )
+                       (br $__rjti$8)
+                      )
+                      (local.set $5
+                       (i32.load
+                        (local.tee $7
+                         (local.get $19)
+                        )
+                       )
+                      )
+                      (if
+                       (i32.lt_s
+                        (local.tee $7
+                         (i32.load offset=4
+                          (local.get $7)
+                         )
+                        )
+                        (i32.const 0)
+                       )
+                       (block
+                        (i32.store
+                         (local.tee $8
+                          (local.get $19)
+                         )
+                         (local.tee $5
+                          (call $_i64Subtract
+                           (i32.const 0)
+                           (i32.const 0)
+                           (local.get $5)
+                           (local.get $7)
+                          )
+                         )
+                        )
+                        (i32.store offset=4
+                         (local.get $8)
+                         (local.tee $7
+                          (global.get $tempRet0)
+                         )
+                        )
+                        (local.set $8
+                         (i32.const 1)
+                        )
+                        (local.set $9
+                         (i32.const 4091)
+                        )
+                        (br $__rjti$4)
+                       )
+                      )
+                      (local.set $9
+                       (if (result i32)
+                        (i32.and
+                         (local.get $11)
+                         (i32.const 2048)
+                        )
+                        (block (result i32)
+                         (local.set $8
+                          (i32.const 1)
+                         )
+                         (i32.const 4092)
+                        )
+                        (block (result i32)
+                         (local.set $8
+                          (local.tee $9
+                           (i32.and
+                            (local.get $11)
+                            (i32.const 1)
+                           )
+                          )
+                         )
+                         (select
+                          (i32.const 4093)
+                          (i32.const 4091)
+                          (local.get $9)
+                         )
+                        )
+                       )
+                      )
+                      (br $__rjti$4)
+                     )
+                     (local.set $5
+                      (i32.load
+                       (local.tee $7
+                        (local.get $19)
+                       )
+                      )
+                     )
+                     (local.set $7
+                      (i32.load offset=4
+                       (local.get $7)
+                      )
+                     )
+                     (local.set $8
+                      (i32.const 0)
+                     )
+                     (local.set $9
+                      (i32.const 4091)
+                     )
+                     (br $__rjti$4)
+                    )
+                    (drop
+                     (i32.load offset=4
+                      (local.tee $5
+                       (local.get $19)
+                      )
+                     )
+                    )
+                    (i32.store8
+                     (local.get $40)
+                     (i32.load
+                      (local.get $5)
+                     )
+                    )
+                    (local.set $7
+                     (local.get $40)
+                    )
+                    (local.set $11
+                     (local.get $8)
+                    )
+                    (local.set $12
+                     (i32.const 1)
+                    )
+                    (local.set $8
+                     (i32.const 0)
+                    )
+                    (local.set $9
+                     (i32.const 4091)
+                    )
+                    (br $__rjto$8
+                     (local.get $26)
+                    )
+                   )
+                   (local.set $5
+                    (call $_strerror
+                     (i32.load
+                      (call $___errno_location)
+                     )
+                    )
+                   )
+                   (br $__rjti$5)
+                  )
+                  (local.set $5
+                   (select
+                    (local.tee $5
+                     (i32.load
+                      (local.get $19)
+                     )
+                    )
+                    (i32.const 4101)
+                    (local.get $5)
+                   )
+                  )
+                  (br $__rjti$5)
+                 )
+                 (drop
+                  (i32.load offset=4
+                   (local.tee $5
+                    (local.get $19)
+                   )
+                  )
+                 )
+                 (i32.store
+                  (local.get $41)
+                  (i32.load
+                   (local.get $5)
+                  )
+                 )
+                 (i32.store
+                  (local.get $44)
+                  (i32.const 0)
+                 )
+                 (i32.store
+                  (local.get $19)
+                  (local.get $41)
+                 )
+                 (local.set $8
+                  (i32.const -1)
+                 )
+                 (br $__rjti$6)
+                )
+                (if
+                 (local.get $6)
+                 (block
+                  (local.set $8
+                   (local.get $6)
+                  )
+                  (br $__rjti$6)
+                 )
+                 (block
+                  (call $_pad
+                   (local.get $0)
+                   (i32.const 32)
+                   (local.get $14)
+                   (i32.const 0)
+                   (local.get $11)
+                  )
+                  (local.set $7
+                   (i32.const 0)
+                  )
+                  (br $__rjti$7)
+                 )
+                )
+               )
+               (local.set $15
+                (f64.load
+                 (local.get $19)
+                )
+               )
+               (i32.store
+                (local.get $20)
+                (i32.const 0)
+               )
+               (f64.store
+                (global.get $tempDoublePtr)
+                (local.get $15)
+               )
+               (drop
+                (i32.load
+                 (global.get $tempDoublePtr)
+                )
+               )
+               (local.set $31
+                (if (result i32)
+                 (i32.lt_s
+                  (i32.load offset=4
+                   (global.get $tempDoublePtr)
+                  )
+                  (i32.const 0)
+                 )
+                 (block (result i32)
+                  (local.set $27
+                   (i32.const 1)
+                  )
+                  (local.set $15
+                   (f64.neg
+                    (local.get $15)
+                   )
+                  )
+                  (i32.const 4108)
+                 )
+                 (if (result i32)
+                  (i32.and
+                   (local.get $11)
+                   (i32.const 2048)
+                  )
+                  (block (result i32)
+                   (local.set $27
+                    (i32.const 1)
+                   )
+                   (i32.const 4111)
+                  )
+                  (block (result i32)
+                   (local.set $27
+                    (local.tee $5
+                     (i32.and
+                      (local.get $11)
+                      (i32.const 1)
+                     )
+                    )
+                   )
+                   (select
+                    (i32.const 4114)
+                    (i32.const 4109)
+                    (local.get $5)
+                   )
+                  )
+                 )
+                )
+               )
+               (f64.store
+                (global.get $tempDoublePtr)
+                (local.get $15)
+               )
+               (drop
+                (i32.load
+                 (global.get $tempDoublePtr)
+                )
+               )
+               (local.set $7
+                (block $do-once49 (result i32)
+                 (if (result i32)
+                  (i32.or
+                   (i32.lt_u
+                    (local.tee $5
+                     (i32.and
+                      (i32.load offset=4
+                       (global.get $tempDoublePtr)
+                      )
+                      (i32.const 2146435072)
+                     )
+                    )
+                    (i32.const 2146435072)
+                   )
+                   (i32.and
+                    (i32.eq
+                     (local.get $5)
+                     (i32.const 2146435072)
+                    )
+                    (i32.const 0)
+                   )
+                  )
+                  (block (result i32)
+                   (if
+                    (local.tee $5
+                     (f64.ne
+                      (local.tee $23
+                       (f64.mul
+                        (call $_frexp
+                         (local.get $15)
+                         (local.tee $5
+                          (local.get $20)
+                         )
+                        )
+                        (f64.const 2)
+                       )
+                      )
+                      (f64.const 0)
+                     )
+                    )
+                    (i32.store
+                     (local.get $20)
+                     (i32.add
+                      (i32.load
+                       (local.get $20)
+                      )
+                      (i32.const -1)
+                     )
+                    )
+                   )
+                   (if
+                    (i32.eq
+                     (local.tee $24
+                      (i32.or
+                       (local.get $18)
+                       (i32.const 32)
+                      )
+                     )
+                     (i32.const 97)
+                    )
+                    (block
+                     (local.set $9
+                      (select
+                       (i32.add
+                        (local.get $31)
+                        (i32.const 9)
+                       )
+                       (local.get $31)
+                       (local.tee $13
+                        (i32.and
+                         (local.get $18)
+                         (i32.const 32)
+                        )
+                       )
+                      )
+                     )
+                     (local.set $15
+                      (if (result f64)
+                       (i32.or
+                        (i32.gt_u
+                         (local.get $6)
+                         (i32.const 11)
+                        )
+                        (i32.eqz
+                         (local.tee $5
+                          (i32.sub
+                           (i32.const 12)
+                           (local.get $6)
+                          )
+                         )
+                        )
+                       )
+                       (local.get $23)
+                       (block (result f64)
+                        (local.set $15
+                         (f64.const 8)
+                        )
+                        (loop $while-in54
+                         (local.set $15
+                          (f64.mul
+                           (local.get $15)
+                           (f64.const 16)
+                          )
+                         )
+                         (br_if $while-in54
+                          (local.tee $5
+                           (i32.add
+                            (local.get $5)
+                            (i32.const -1)
+                           )
+                          )
+                         )
+                        )
+                        (if (result f64)
+                         (i32.eq
+                          (i32.load8_s
+                           (local.get $9)
+                          )
+                          (i32.const 45)
+                         )
+                         (f64.neg
+                          (f64.add
+                           (local.get $15)
+                           (f64.sub
+                            (f64.neg
+                             (local.get $23)
+                            )
+                            (local.get $15)
+                           )
+                          )
+                         )
+                         (f64.sub
+                          (f64.add
+                           (local.get $23)
+                           (local.get $15)
+                          )
+                          (local.get $15)
+                         )
+                        )
+                       )
+                      )
+                     )
+                     (if
+                      (i32.eq
+                       (local.tee $5
+                        (call $_fmt_u
+                         (local.tee $5
+                          (select
+                           (i32.sub
+                            (i32.const 0)
+                            (local.tee $7
+                             (i32.load
+                              (local.get $20)
+                             )
+                            )
+                           )
+                           (local.get $7)
+                           (i32.lt_s
+                            (local.get $7)
+                            (i32.const 0)
+                           )
+                          )
+                         )
+                         (i32.shr_s
+                          (i32.shl
+                           (i32.lt_s
+                            (local.get $5)
+                            (i32.const 0)
+                           )
+                           (i32.const 31)
+                          )
+                          (i32.const 31)
+                         )
+                         (local.get $34)
+                        )
+                       )
+                       (local.get $34)
+                      )
+                      (block
+                       (i32.store8
+                        (local.get $42)
+                        (i32.const 48)
+                       )
+                       (local.set $5
+                        (local.get $42)
+                       )
+                      )
+                     )
+                     (local.set $12
+                      (i32.or
+                       (local.get $27)
+                       (i32.const 2)
+                      )
+                     )
+                     (i32.store8
+                      (i32.add
+                       (local.get $5)
+                       (i32.const -1)
+                      )
+                      (i32.add
+                       (i32.and
+                        (i32.shr_s
+                         (local.get $7)
+                         (i32.const 31)
+                        )
+                        (i32.const 2)
+                       )
+                       (i32.const 43)
+                      )
+                     )
+                     (i32.store8
+                      (local.tee $8
+                       (i32.add
+                        (local.get $5)
+                        (i32.const -2)
+                       )
+                      )
+                      (i32.add
+                       (local.get $18)
+                       (i32.const 15)
+                      )
+                     )
+                     (local.set $18
+                      (i32.lt_s
+                       (local.get $6)
+                       (i32.const 1)
+                      )
+                     )
+                     (local.set $17
+                      (i32.eqz
+                       (i32.and
+                        (local.get $11)
+                        (i32.const 8)
+                       )
+                      )
+                     )
+                     (local.set $5
+                      (local.get $22)
+                     )
+                     (loop $while-in56
+                      (i32.store8
+                       (local.get $5)
+                       (i32.or
+                        (i32.load8_u
+                         (i32.add
+                          (local.tee $7
+                           (call $f64-to-int
+                            (local.get $15)
+                           )
+                          )
+                          (i32.const 4075)
+                         )
+                        )
+                        (local.get $13)
+                       )
+                      )
+                      (local.set $15
+                       (f64.mul
+                        (f64.sub
+                         (local.get $15)
+                         (f64.convert_i32_s
+                          (local.get $7)
+                         )
+                        )
+                        (f64.const 16)
+                       )
+                      )
+                      (local.set $5
+                       (block $do-once57 (result i32)
+                        (if (result i32)
+                         (i32.eq
+                          (i32.sub
+                           (local.tee $7
+                            (i32.add
+                             (local.get $5)
+                             (i32.const 1)
+                            )
+                           )
+                           (local.get $37)
+                          )
+                          (i32.const 1)
+                         )
+                         (block (result i32)
+                          (drop
+                           (br_if $do-once57
+                            (local.get $7)
+                            (i32.and
+                             (local.get $17)
+                             (i32.and
+                              (local.get $18)
+                              (f64.eq
+                               (local.get $15)
+                               (f64.const 0)
+                              )
+                             )
+                            )
+                           )
+                          )
+                          (i32.store8
+                           (local.get $7)
+                           (i32.const 46)
+                          )
+                          (i32.add
+                           (local.get $5)
+                           (i32.const 2)
+                          )
+                         )
+                         (local.get $7)
+                        )
+                       )
+                      )
+                      (br_if $while-in56
+                       (f64.ne
+                        (local.get $15)
+                        (f64.const 0)
+                       )
+                      )
+                     )
+                     (call $_pad
+                      (local.get $0)
+                      (i32.const 32)
+                      (local.get $14)
+                      (local.tee $7
+                       (i32.add
+                        (local.tee $6
+                         (select
+                          (i32.sub
+                           (i32.add
+                            (local.get $47)
+                            (local.get $6)
+                           )
+                           (local.get $8)
+                          )
+                          (i32.add
+                           (i32.sub
+                            (local.get $45)
+                            (local.get $8)
+                           )
+                           (local.get $5)
+                          )
+                          (i32.and
+                           (i32.ne
+                            (local.get $6)
+                            (i32.const 0)
+                           )
+                           (i32.lt_s
+                            (i32.add
+                             (local.get $46)
+                             (local.get $5)
+                            )
+                            (local.get $6)
+                           )
+                          )
+                         )
+                        )
+                        (local.get $12)
+                       )
+                      )
+                      (local.get $11)
+                     )
+                     (if
+                      (i32.eqz
+                       (i32.and
+                        (i32.load
+                         (local.get $0)
+                        )
+                        (i32.const 32)
+                       )
+                      )
+                      (drop
+                       (call $___fwritex
+                        (local.get $9)
+                        (local.get $12)
+                        (local.get $0)
+                       )
+                      )
+                     )
+                     (call $_pad
+                      (local.get $0)
+                      (i32.const 48)
+                      (local.get $14)
+                      (local.get $7)
+                      (i32.xor
+                       (local.get $11)
+                       (i32.const 65536)
+                      )
+                     )
+                     (local.set $5
+                      (i32.sub
+                       (local.get $5)
+                       (local.get $37)
+                      )
+                     )
+                     (if
+                      (i32.eqz
+                       (i32.and
+                        (i32.load
+                         (local.get $0)
+                        )
+                        (i32.const 32)
+                       )
+                      )
+                      (drop
+                       (call $___fwritex
+                        (local.get $22)
+                        (local.get $5)
+                        (local.get $0)
+                       )
+                      )
+                     )
+                     (call $_pad
+                      (local.get $0)
+                      (i32.const 48)
+                      (i32.sub
+                       (local.get $6)
+                       (i32.add
+                        (local.get $5)
+                        (local.tee $5
+                         (i32.sub
+                          (local.get $28)
+                          (local.get $8)
+                         )
+                        )
+                       )
+                      )
+                      (i32.const 0)
+                      (i32.const 0)
+                     )
+                     (if
+                      (i32.eqz
+                       (i32.and
+                        (i32.load
+                         (local.get $0)
+                        )
+                        (i32.const 32)
+                       )
+                      )
+                      (drop
+                       (call $___fwritex
+                        (local.get $8)
+                        (local.get $5)
+                        (local.get $0)
+                       )
+                      )
+                     )
+                     (call $_pad
+                      (local.get $0)
+                      (i32.const 32)
+                      (local.get $14)
+                      (local.get $7)
+                      (i32.xor
+                       (local.get $11)
+                       (i32.const 8192)
+                      )
+                     )
+                     (br $do-once49
+                      (select
+                       (local.get $14)
+                       (local.get $7)
+                       (i32.lt_s
+                        (local.get $7)
+                        (local.get $14)
+                       )
+                      )
+                     )
+                    )
+                   )
+                   (local.set $15
+                    (if (result f64)
+                     (local.get $5)
+                     (block (result f64)
+                      (i32.store
+                       (local.get $20)
+                       (local.tee $5
+                        (i32.add
+                         (i32.load
+                          (local.get $20)
+                         )
+                         (i32.const -28)
+                        )
+                       )
+                      )
+                      (f64.mul
+                       (local.get $23)
+                       (f64.const 268435456)
+                      )
+                     )
+                     (block (result f64)
+                      (local.set $5
+                       (i32.load
+                        (local.get $20)
+                       )
+                      )
+                      (local.get $23)
+                     )
+                    )
+                   )
+                   (local.set $7
+                    (local.tee $8
+                     (select
+                      (local.get $48)
+                      (local.get $49)
+                      (i32.lt_s
+                       (local.get $5)
+                       (i32.const 0)
+                      )
+                     )
+                    )
+                   )
+                   (loop $while-in60
+                    (i32.store
+                     (local.get $7)
+                     (local.tee $5
+                      (call $f64-to-int
+                       (local.get $15)
+                      )
+                     )
+                    )
+                    (local.set $7
+                     (i32.add
+                      (local.get $7)
+                      (i32.const 4)
+                     )
+                    )
+                    (br_if $while-in60
+                     (f64.ne
+                      (local.tee $15
+                       (f64.mul
+                        (f64.sub
+                         (local.get $15)
+                         (f64.convert_i32_u
+                          (local.get $5)
+                         )
+                        )
+                        (f64.const 1e9)
+                       )
+                      )
+                      (f64.const 0)
+                     )
+                    )
+                   )
+                   (if
+                    (i32.gt_s
+                     (local.tee $9
+                      (i32.load
+                       (local.get $20)
+                      )
+                     )
+                     (i32.const 0)
+                    )
+                    (block
+                     (local.set $5
+                      (local.get $8)
+                     )
+                     (loop $while-in62
+                      (local.set $13
+                       (select
+                        (i32.const 29)
+                        (local.get $9)
+                        (i32.gt_s
+                         (local.get $9)
+                         (i32.const 29)
+                        )
+                       )
+                      )
+                      (block $do-once63
+                       (if
+                        (i32.ge_u
+                         (local.tee $9
+                          (i32.add
+                           (local.get $7)
+                           (i32.const -4)
+                          )
+                         )
+                         (local.get $5)
+                        )
+                        (block
+                         (local.set $12
+                          (i32.const 0)
+                         )
+                         (loop $while-in66
+                          (i32.store
+                           (local.get $9)
+                           (call $___uremdi3
+                            (local.tee $12
+                             (call $_i64Add
+                              (call $_bitshift64Shl
+                               (i32.load
+                                (local.get $9)
+                               )
+                               (i32.const 0)
+                               (local.get $13)
+                              )
+                              (global.get $tempRet0)
+                              (local.get $12)
+                              (i32.const 0)
+                             )
+                            )
+                            (local.tee $17
+                             (global.get $tempRet0)
+                            )
+                            (i32.const 1000000000)
+                            (i32.const 0)
+                           )
+                          )
+                          (local.set $12
+                           (call $___udivdi3
+                            (local.get $12)
+                            (local.get $17)
+                            (i32.const 1000000000)
+                            (i32.const 0)
+                           )
+                          )
+                          (br_if $while-in66
+                           (i32.ge_u
+                            (local.tee $9
+                             (i32.add
+                              (local.get $9)
+                              (i32.const -4)
+                             )
+                            )
+                            (local.get $5)
+                           )
+                          )
+                         )
+                         (br_if $do-once63
+                          (i32.eqz
+                           (local.get $12)
+                          )
+                         )
+                         (i32.store
+                          (local.tee $5
+                           (i32.add
+                            (local.get $5)
+                            (i32.const -4)
+                           )
+                          )
+                          (local.get $12)
+                         )
+                        )
+                       )
+                      )
+                      (loop $while-in68
+                       (if
+                        (i32.gt_u
+                         (local.get $7)
+                         (local.get $5)
+                        )
+                        (if
+                         (i32.eqz
+                          (i32.load
+                           (local.tee $9
+                            (i32.add
+                             (local.get $7)
+                             (i32.const -4)
+                            )
+                           )
+                          )
+                         )
+                         (block
+                          (local.set $7
+                           (local.get $9)
+                          )
+                          (br $while-in68)
+                         )
+                        )
+                       )
+                      )
+                      (i32.store
+                       (local.get $20)
+                       (local.tee $9
+                        (i32.sub
+                         (i32.load
+                          (local.get $20)
+                         )
+                         (local.get $13)
+                        )
+                       )
+                      )
+                      (br_if $while-in62
+                       (i32.gt_s
+                        (local.get $9)
+                        (i32.const 0)
+                       )
+                      )
+                     )
+                    )
+                    (local.set $5
+                     (local.get $8)
+                    )
+                   )
+                   (local.set $17
+                    (select
+                     (i32.const 6)
+                     (local.get $6)
+                     (i32.lt_s
+                      (local.get $6)
+                      (i32.const 0)
+                     )
+                    )
+                   )
+                   (if
+                    (i32.lt_s
+                     (local.get $9)
+                     (i32.const 0)
+                    )
+                    (block
+                     (local.set $21
+                      (i32.add
+                       (call $i32s-div
+                        (i32.add
+                         (local.get $17)
+                         (i32.const 25)
+                        )
+                        (i32.const 9)
+                       )
+                       (i32.const 1)
+                      )
+                     )
+                     (local.set $32
+                      (i32.eq
+                       (local.get $24)
+                       (i32.const 102)
+                      )
+                     )
+                     (local.set $6
+                      (local.get $5)
+                     )
+                     (local.set $5
+                      (local.get $7)
+                     )
+                     (loop $while-in70
+                      (local.set $13
+                       (select
+                        (i32.const 9)
+                        (local.tee $7
+                         (i32.sub
+                          (i32.const 0)
+                          (local.get $9)
+                         )
+                        )
+                        (i32.gt_s
+                         (local.get $7)
+                         (i32.const 9)
+                        )
+                       )
+                      )
+                      (block $do-once71
+                       (if
+                        (i32.lt_u
+                         (local.get $6)
+                         (local.get $5)
+                        )
+                        (block
+                         (local.set $12
+                          (i32.add
+                           (i32.shl
+                            (i32.const 1)
+                            (local.get $13)
+                           )
+                           (i32.const -1)
+                          )
+                         )
+                         (local.set $38
+                          (i32.shr_u
+                           (i32.const 1000000000)
+                           (local.get $13)
+                          )
+                         )
+                         (local.set $9
+                          (i32.const 0)
+                         )
+                         (local.set $7
+                          (local.get $6)
+                         )
+                         (loop $while-in74
+                          (i32.store
+                           (local.get $7)
+                           (i32.add
+                            (i32.shr_u
+                             (local.tee $33
+                              (i32.load
+                               (local.get $7)
+                              )
+                             )
+                             (local.get $13)
+                            )
+                            (local.get $9)
+                           )
+                          )
+                          (local.set $9
+                           (i32.mul
+                            (i32.and
+                             (local.get $33)
+                             (local.get $12)
+                            )
+                            (local.get $38)
+                           )
+                          )
+                          (br_if $while-in74
+                           (i32.lt_u
+                            (local.tee $7
+                             (i32.add
+                              (local.get $7)
+                              (i32.const 4)
+                             )
+                            )
+                            (local.get $5)
+                           )
+                          )
+                         )
+                         (local.set $7
+                          (select
+                           (local.get $6)
+                           (i32.add
+                            (local.get $6)
+                            (i32.const 4)
+                           )
+                           (i32.load
+                            (local.get $6)
+                           )
+                          )
+                         )
+                         (br_if $do-once71
+                          (i32.eqz
+                           (local.get $9)
+                          )
+                         )
+                         (i32.store
+                          (local.get $5)
+                          (local.get $9)
+                         )
+                         (local.set $5
+                          (i32.add
+                           (local.get $5)
+                           (i32.const 4)
+                          )
+                         )
+                        )
+                        (local.set $7
+                         (select
+                          (local.get $6)
+                          (i32.add
+                           (local.get $6)
+                           (i32.const 4)
+                          )
+                          (i32.load
+                           (local.get $6)
+                          )
+                         )
+                        )
+                       )
+                      )
+                      (local.set $12
+                       (select
+                        (i32.add
+                         (local.tee $6
+                          (select
+                           (local.get $8)
+                           (local.get $7)
+                           (local.get $32)
+                          )
+                         )
+                         (i32.shl
+                          (local.get $21)
+                          (i32.const 2)
+                         )
+                        )
+                        (local.get $5)
+                        (i32.gt_s
+                         (i32.shr_s
+                          (i32.sub
+                           (local.get $5)
+                           (local.get $6)
+                          )
+                          (i32.const 2)
+                         )
+                         (local.get $21)
+                        )
+                       )
+                      )
+                      (i32.store
+                       (local.get $20)
+                       (local.tee $9
+                        (i32.add
+                         (i32.load
+                          (local.get $20)
+                         )
+                         (local.get $13)
+                        )
+                       )
+                      )
+                      (if
+                       (i32.lt_s
+                        (local.get $9)
+                        (i32.const 0)
+                       )
+                       (block
+                        (local.set $6
+                         (local.get $7)
+                        )
+                        (local.set $5
+                         (local.get $12)
+                        )
+                        (br $while-in70)
+                       )
+                       (block
+                        (local.set $5
+                         (local.get $7)
+                        )
+                        (local.set $9
+                         (local.get $12)
+                        )
+                       )
+                      )
+                     )
+                    )
+                    (local.set $9
+                     (local.get $7)
+                    )
+                   )
+                   (local.set $21
+                    (local.get $8)
+                   )
+                   (block $do-once75
+                    (if
+                     (i32.lt_u
+                      (local.get $5)
+                      (local.get $9)
+                     )
+                     (block
+                      (local.set $7
+                       (i32.mul
+                        (i32.shr_s
+                         (i32.sub
+                          (local.get $21)
+                          (local.get $5)
+                         )
+                         (i32.const 2)
+                        )
+                        (i32.const 9)
+                       )
+                      )
+                      (br_if $do-once75
+                       (i32.lt_u
+                        (local.tee $12
+                         (i32.load
+                          (local.get $5)
+                         )
+                        )
+                        (i32.const 10)
+                       )
+                      )
+                      (local.set $6
+                       (i32.const 10)
+                      )
+                      (loop $while-in78
+                       (local.set $7
+                        (i32.add
+                         (local.get $7)
+                         (i32.const 1)
+                        )
+                       )
+                       (br_if $while-in78
+                        (i32.ge_u
+                         (local.get $12)
+                         (local.tee $6
+                          (i32.mul
+                           (local.get $6)
+                           (i32.const 10)
+                          )
+                         )
+                        )
+                       )
+                      )
+                     )
+                     (local.set $7
+                      (i32.const 0)
+                     )
+                    )
+                   )
+                   (local.set $5
+                    (if (result i32)
+                     (i32.lt_s
+                      (local.tee $6
+                       (i32.add
+                        (i32.sub
+                         (local.get $17)
+                         (select
+                          (local.get $7)
+                          (i32.const 0)
+                          (i32.ne
+                           (local.get $24)
+                           (i32.const 102)
+                          )
+                         )
+                        )
+                        (i32.shr_s
+                         (i32.shl
+                          (i32.and
+                           (local.tee $32
+                            (i32.ne
+                             (local.get $17)
+                             (i32.const 0)
+                            )
+                           )
+                           (local.tee $38
+                            (i32.eq
+                             (local.get $24)
+                             (i32.const 103)
+                            )
+                           )
+                          )
+                          (i32.const 31)
+                         )
+                         (i32.const 31)
+                        )
+                       )
+                      )
+                      (i32.add
+                       (i32.mul
+                        (i32.shr_s
+                         (i32.sub
+                          (local.get $9)
+                          (local.get $21)
+                         )
+                         (i32.const 2)
+                        )
+                        (i32.const 9)
+                       )
+                       (i32.const -9)
+                      )
+                     )
+                     (block (result i32)
+                      (local.set $13
+                       (call $i32s-div
+                        (local.tee $6
+                         (i32.add
+                          (local.get $6)
+                          (i32.const 9216)
+                         )
+                        )
+                        (i32.const 9)
+                       )
+                      )
+                      (if
+                       (i32.lt_s
+                        (local.tee $6
+                         (i32.add
+                          (if (result i32)
+                           (local.tee $12
+                            (i32.const 9)
+                           )
+                           (i32.rem_s
+                            (local.get $6)
+                            (local.get $12)
+                           )
+                           (i32.const 0)
+                          )
+                          (i32.const 1)
+                         )
+                        )
+                        (i32.const 9)
+                       )
+                       (block
+                        (local.set $12
+                         (i32.const 10)
+                        )
+                        (loop $while-in80
+                         (local.set $12
+                          (i32.mul
+                           (local.get $12)
+                           (i32.const 10)
+                          )
+                         )
+                         (br_if $while-in80
+                          (i32.ne
+                           (local.tee $6
+                            (i32.add
+                             (local.get $6)
+                             (i32.const 1)
+                            )
+                           )
+                           (i32.const 9)
+                          )
+                         )
+                        )
+                       )
+                       (local.set $12
+                        (i32.const 10)
+                       )
+                      )
+                      (local.set $13
+                       (call $i32u-rem
+                        (local.tee $24
+                         (i32.load
+                          (local.tee $6
+                           (i32.add
+                            (i32.add
+                             (local.get $8)
+                             (i32.shl
+                              (local.get $13)
+                              (i32.const 2)
+                             )
+                            )
+                            (i32.const -4092)
+                           )
+                          )
+                         )
+                        )
+                        (local.get $12)
+                       )
+                      )
+                      (block $do-once81
+                       (if
+                        (i32.eqz
+                         (i32.and
+                          (local.tee $33
+                           (i32.eq
+                            (i32.add
+                             (local.get $6)
+                             (i32.const 4)
+                            )
+                            (local.get $9)
+                           )
+                          )
+                          (i32.eqz
+                           (local.get $13)
+                          )
+                         )
+                        )
+                        (block
+                         (local.set $50
+                          (call $i32u-div
+                           (local.get $24)
+                           (local.get $12)
+                          )
+                         )
+                         (local.set $15
+                          (if (result f64)
+                           (i32.lt_u
+                            (local.get $13)
+                            (local.tee $51
+                             (call $i32s-div
+                              (local.get $12)
+                              (i32.const 2)
+                             )
+                            )
+                           )
+                           (f64.const 0.5)
+                           (select
+                            (f64.const 1)
+                            (f64.const 1.5)
+                            (i32.and
+                             (local.get $33)
+                             (i32.eq
+                              (local.get $13)
+                              (local.get $51)
+                             )
+                            )
+                           )
+                          )
+                         )
+                         (local.set $23
+                          (select
+                           (f64.const 9007199254740994)
+                           (f64.const 9007199254740992)
+                           (i32.and
+                            (local.get $50)
+                            (i32.const 1)
+                           )
+                          )
+                         )
+                         (block $do-once83
+                          (if
+                           (local.get $27)
+                           (block
+                            (br_if $do-once83
+                             (i32.ne
+                              (i32.load8_s
+                               (local.get $31)
+                              )
+                              (i32.const 45)
+                             )
+                            )
+                            (local.set $23
+                             (f64.neg
+                              (local.get $23)
+                             )
+                            )
+                            (local.set $15
+                             (f64.neg
+                              (local.get $15)
+                             )
+                            )
+                           )
+                          )
+                         )
+                         (i32.store
+                          (local.get $6)
+                          (local.tee $13
+                           (i32.sub
+                            (local.get $24)
+                            (local.get $13)
+                           )
+                          )
+                         )
+                         (br_if $do-once81
+                          (f64.eq
+                           (f64.add
+                            (local.get $23)
+                            (local.get $15)
+                           )
+                           (local.get $23)
+                          )
+                         )
+                         (i32.store
+                          (local.get $6)
+                          (local.tee $7
+                           (i32.add
+                            (local.get $13)
+                            (local.get $12)
+                           )
+                          )
+                         )
+                         (if
+                          (i32.gt_u
+                           (local.get $7)
+                           (i32.const 999999999)
+                          )
+                          (loop $while-in86
+                           (i32.store
+                            (local.get $6)
+                            (i32.const 0)
+                           )
+                           (if
+                            (i32.lt_u
+                             (local.tee $6
+                              (i32.add
+                               (local.get $6)
+                               (i32.const -4)
+                              )
+                             )
+                             (local.get $5)
+                            )
+                            (i32.store
+                             (local.tee $5
+                              (i32.add
+                               (local.get $5)
+                               (i32.const -4)
+                              )
+                             )
+                             (i32.const 0)
+                            )
+                           )
+                           (i32.store
+                            (local.get $6)
+                            (local.tee $7
+                             (i32.add
+                              (i32.load
+                               (local.get $6)
+                              )
+                              (i32.const 1)
+                             )
+                            )
+                           )
+                           (br_if $while-in86
+                            (i32.gt_u
+                             (local.get $7)
+                             (i32.const 999999999)
+                            )
+                           )
+                          )
+                         )
+                         (local.set $7
+                          (i32.mul
+                           (i32.shr_s
+                            (i32.sub
+                             (local.get $21)
+                             (local.get $5)
+                            )
+                            (i32.const 2)
+                           )
+                           (i32.const 9)
+                          )
+                         )
+                         (br_if $do-once81
+                          (i32.lt_u
+                           (local.tee $13
+                            (i32.load
+                             (local.get $5)
+                            )
+                           )
+                           (i32.const 10)
+                          )
+                         )
+                         (local.set $12
+                          (i32.const 10)
+                         )
+                         (loop $while-in88
+                          (local.set $7
+                           (i32.add
+                            (local.get $7)
+                            (i32.const 1)
+                           )
+                          )
+                          (br_if $while-in88
+                           (i32.ge_u
+                            (local.get $13)
+                            (local.tee $12
+                             (i32.mul
+                              (local.get $12)
+                              (i32.const 10)
+                             )
+                            )
+                           )
+                          )
+                         )
+                        )
+                       )
+                      )
+                      (local.set $12
+                       (local.get $5)
+                      )
+                      (local.set $13
+                       (local.get $7)
+                      )
+                      (select
+                       (local.tee $5
+                        (i32.add
+                         (local.get $6)
+                         (i32.const 4)
+                        )
+                       )
+                       (local.get $9)
+                       (i32.gt_u
+                        (local.get $9)
+                        (local.get $5)
+                       )
+                      )
+                     )
+                     (block (result i32)
+                      (local.set $12
+                       (local.get $5)
+                      )
+                      (local.set $13
+                       (local.get $7)
+                      )
+                      (local.get $9)
+                     )
+                    )
+                   )
+                   (local.set $33
+                    (i32.sub
+                     (i32.const 0)
+                     (local.get $13)
+                    )
+                   )
+                   (loop $while-in90
+                    (block $while-out89
+                     (if
+                      (i32.le_u
+                       (local.get $5)
+                       (local.get $12)
+                      )
+                      (block
+                       (local.set $24
+                        (i32.const 0)
+                       )
+                       (local.set $9
+                        (local.get $5)
+                       )
+                       (br $while-out89)
+                      )
+                     )
+                     (if
+                      (i32.load
+                       (local.tee $7
+                        (i32.add
+                         (local.get $5)
+                         (i32.const -4)
+                        )
+                       )
+                      )
+                      (block
+                       (local.set $24
+                        (i32.const 1)
+                       )
+                       (local.set $9
+                        (local.get $5)
+                       )
+                      )
+                      (block
+                       (local.set $5
+                        (local.get $7)
+                       )
+                       (br $while-in90)
+                      )
+                     )
+                    )
+                   )
+                   (call $_pad
+                    (local.get $0)
+                    (i32.const 32)
+                    (local.get $14)
+                    (local.tee $13
+                     (i32.add
+                      (i32.add
+                       (i32.add
+                        (i32.add
+                         (local.get $27)
+                         (i32.const 1)
+                        )
+                        (local.tee $5
+                         (block $do-once91 (result i32)
+                          (if (result i32)
+                           (local.get $38)
+                           (block (result i32)
+                            (local.set $7
+                             (if (result i32)
+                              (i32.and
+                               (i32.gt_s
+                                (local.tee $5
+                                 (i32.add
+                                  (i32.xor
+                                   (local.get $32)
+                                   (i32.const 1)
+                                  )
+                                  (local.get $17)
+                                 )
+                                )
+                                (local.get $13)
+                               )
+                               (i32.gt_s
+                                (local.get $13)
+                                (i32.const -5)
+                               )
+                              )
+                              (block (result i32)
+                               (local.set $17
+                                (i32.sub
+                                 (i32.add
+                                  (local.get $5)
+                                  (i32.const -1)
+                                 )
+                                 (local.get $13)
+                                )
+                               )
+                               (i32.add
+                                (local.get $18)
+                                (i32.const -1)
+                               )
+                              )
+                              (block (result i32)
+                               (local.set $17
+                                (i32.add
+                                 (local.get $5)
+                                 (i32.const -1)
+                                )
+                               )
+                               (i32.add
+                                (local.get $18)
+                                (i32.const -2)
+                               )
+                              )
+                             )
+                            )
+                            (if
+                             (local.tee $5
+                              (i32.and
+                               (local.get $11)
+                               (i32.const 8)
+                              )
+                             )
+                             (block
+                              (local.set $21
+                               (local.get $5)
+                              )
+                              (br $do-once91
+                               (local.get $17)
+                              )
+                             )
+                            )
+                            (block $do-once93
+                             (if
+                              (local.get $24)
+                              (block
+                               (if
+                                (i32.eqz
+                                 (local.tee $18
+                                  (i32.load
+                                   (i32.add
+                                    (local.get $9)
+                                    (i32.const -4)
+                                   )
+                                  )
+                                 )
+                                )
+                                (block
+                                 (local.set $5
+                                  (i32.const 9)
+                                 )
+                                 (br $do-once93)
+                                )
+                               )
+                               (if
+                                (call $i32u-rem
+                                 (local.get $18)
+                                 (i32.const 10)
+                                )
+                                (block
+                                 (local.set $5
+                                  (i32.const 0)
+                                 )
+                                 (br $do-once93)
+                                )
+                                (block
+                                 (local.set $6
+                                  (i32.const 10)
+                                 )
+                                 (local.set $5
+                                  (i32.const 0)
+                                 )
+                                )
+                               )
+                               (loop $while-in96
+                                (local.set $5
+                                 (i32.add
+                                  (local.get $5)
+                                  (i32.const 1)
+                                 )
+                                )
+                                (br_if $while-in96
+                                 (i32.eqz
+                                  (call $i32u-rem
+                                   (local.get $18)
+                                   (local.tee $6
+                                    (i32.mul
+                                     (local.get $6)
+                                     (i32.const 10)
+                                    )
+                                   )
+                                  )
+                                 )
+                                )
+                               )
+                              )
+                              (local.set $5
+                               (i32.const 9)
+                              )
+                             )
+                            )
+                            (local.set $6
+                             (i32.add
+                              (i32.mul
+                               (i32.shr_s
+                                (i32.sub
+                                 (local.get $9)
+                                 (local.get $21)
+                                )
+                                (i32.const 2)
+                               )
+                               (i32.const 9)
+                              )
+                              (i32.const -9)
+                             )
+                            )
+                            (if (result i32)
+                             (i32.eq
+                              (i32.or
+                               (local.get $7)
+                               (i32.const 32)
+                              )
+                              (i32.const 102)
+                             )
+                             (block (result i32)
+                              (local.set $21
+                               (i32.const 0)
+                              )
+                              (select
+                               (local.get $17)
+                               (local.tee $5
+                                (select
+                                 (i32.const 0)
+                                 (local.tee $5
+                                  (i32.sub
+                                   (local.get $6)
+                                   (local.get $5)
+                                  )
+                                 )
+                                 (i32.lt_s
+                                  (local.get $5)
+                                  (i32.const 0)
+                                 )
+                                )
+                               )
+                               (i32.lt_s
+                                (local.get $17)
+                                (local.get $5)
+                               )
+                              )
+                             )
+                             (block (result i32)
+                              (local.set $21
+                               (i32.const 0)
+                              )
+                              (select
+                               (local.get $17)
+                               (local.tee $5
+                                (select
+                                 (i32.const 0)
+                                 (local.tee $5
+                                  (i32.sub
+                                   (i32.add
+                                    (local.get $6)
+                                    (local.get $13)
+                                   )
+                                   (local.get $5)
+                                  )
+                                 )
+                                 (i32.lt_s
+                                  (local.get $5)
+                                  (i32.const 0)
+                                 )
+                                )
+                               )
+                               (i32.lt_s
+                                (local.get $17)
+                                (local.get $5)
+                               )
+                              )
+                             )
+                            )
+                           )
+                           (block (result i32)
+                            (local.set $21
+                             (i32.and
+                              (local.get $11)
+                              (i32.const 8)
+                             )
+                            )
+                            (local.set $7
+                             (local.get $18)
+                            )
+                            (local.get $17)
+                           )
+                          )
+                         )
+                        )
+                       )
+                       (i32.ne
+                        (local.tee $32
+                         (i32.or
+                          (local.get $5)
+                          (local.get $21)
+                         )
+                        )
+                        (i32.const 0)
+                       )
+                      )
+                      (if (result i32)
+                       (local.tee $17
+                        (i32.eq
+                         (i32.or
+                          (local.get $7)
+                          (i32.const 32)
+                         )
+                         (i32.const 102)
+                        )
+                       )
+                       (block (result i32)
+                        (local.set $18
+                         (i32.const 0)
+                        )
+                        (select
+                         (local.get $13)
+                         (i32.const 0)
+                         (i32.gt_s
+                          (local.get $13)
+                          (i32.const 0)
+                         )
+                        )
+                       )
+                       (block (result i32)
+                        (if
+                         (i32.lt_s
+                          (i32.sub
+                           (local.get $28)
+                           (local.tee $6
+                            (call $_fmt_u
+                             (local.tee $6
+                              (select
+                               (local.get $33)
+                               (local.get $13)
+                               (i32.lt_s
+                                (local.get $13)
+                                (i32.const 0)
+                               )
+                              )
+                             )
+                             (i32.shr_s
+                              (i32.shl
+                               (i32.lt_s
+                                (local.get $6)
+                                (i32.const 0)
+                               )
+                               (i32.const 31)
+                              )
+                              (i32.const 31)
+                             )
+                             (local.get $34)
+                            )
+                           )
+                          )
+                          (i32.const 2)
+                         )
+                         (loop $while-in98
+                          (i32.store8
+                           (local.tee $6
+                            (i32.add
+                             (local.get $6)
+                             (i32.const -1)
+                            )
+                           )
+                           (i32.const 48)
+                          )
+                          (br_if $while-in98
+                           (i32.lt_s
+                            (i32.sub
+                             (local.get $28)
+                             (local.get $6)
+                            )
+                            (i32.const 2)
+                           )
+                          )
+                         )
+                        )
+                        (i32.store8
+                         (i32.add
+                          (local.get $6)
+                          (i32.const -1)
+                         )
+                         (i32.add
+                          (i32.and
+                           (i32.shr_s
+                            (local.get $13)
+                            (i32.const 31)
+                           )
+                           (i32.const 2)
+                          )
+                          (i32.const 43)
+                         )
+                        )
+                        (i32.store8
+                         (local.tee $6
+                          (i32.add
+                           (local.get $6)
+                           (i32.const -2)
+                          )
+                         )
+                         (local.get $7)
+                        )
+                        (local.set $18
+                         (local.get $6)
+                        )
+                        (i32.sub
+                         (local.get $28)
+                         (local.get $6)
+                        )
+                       )
+                      )
+                     )
+                    )
+                    (local.get $11)
+                   )
+                   (if
+                    (i32.eqz
+                     (i32.and
+                      (i32.load
+                       (local.get $0)
+                      )
+                      (i32.const 32)
+                     )
+                    )
+                    (drop
+                     (call $___fwritex
+                      (local.get $31)
+                      (local.get $27)
+                      (local.get $0)
+                     )
+                    )
+                   )
+                   (call $_pad
+                    (local.get $0)
+                    (i32.const 48)
+                    (local.get $14)
+                    (local.get $13)
+                    (i32.xor
+                     (local.get $11)
+                     (i32.const 65536)
+                    )
+                   )
+                   (block $do-once99
+                    (if
+                     (local.get $17)
+                     (block
+                      (local.set $6
+                       (local.tee $12
+                        (select
+                         (local.get $8)
+                         (local.get $12)
+                         (i32.gt_u
+                          (local.get $12)
+                          (local.get $8)
+                         )
+                        )
+                       )
+                      )
+                      (loop $while-in102
+                       (local.set $7
+                        (call $_fmt_u
+                         (i32.load
+                          (local.get $6)
+                         )
+                         (i32.const 0)
+                         (local.get $30)
+                        )
+                       )
+                       (block $do-once103
+                        (if
+                         (i32.eq
+                          (local.get $6)
+                          (local.get $12)
+                         )
+                         (block
+                          (br_if $do-once103
+                           (i32.ne
+                            (local.get $7)
+                            (local.get $30)
+                           )
+                          )
+                          (i32.store8
+                           (local.get $35)
+                           (i32.const 48)
+                          )
+                          (local.set $7
+                           (local.get $35)
+                          )
+                         )
+                         (block
+                          (br_if $do-once103
+                           (i32.le_u
+                            (local.get $7)
+                            (local.get $22)
+                           )
+                          )
+                          (loop $while-in106
+                           (i32.store8
+                            (local.tee $7
+                             (i32.add
+                              (local.get $7)
+                              (i32.const -1)
+                             )
+                            )
+                            (i32.const 48)
+                           )
+                           (br_if $while-in106
+                            (i32.gt_u
+                             (local.get $7)
+                             (local.get $22)
+                            )
+                           )
+                          )
+                         )
+                        )
+                       )
+                       (if
+                        (i32.eqz
+                         (i32.and
+                          (i32.load
+                           (local.get $0)
+                          )
+                          (i32.const 32)
+                         )
+                        )
+                        (drop
+                         (call $___fwritex
+                          (local.get $7)
+                          (i32.sub
+                           (local.get $43)
+                           (local.get $7)
+                          )
+                          (local.get $0)
+                         )
+                        )
+                       )
+                       (if
+                        (i32.le_u
+                         (local.tee $7
+                          (i32.add
+                           (local.get $6)
+                           (i32.const 4)
+                          )
+                         )
+                         (local.get $8)
+                        )
+                        (block
+                         (local.set $6
+                          (local.get $7)
+                         )
+                         (br $while-in102)
+                        )
+                       )
+                      )
+                      (block $do-once107
+                       (if
+                        (local.get $32)
+                        (block
+                         (br_if $do-once107
+                          (i32.and
+                           (i32.load
+                            (local.get $0)
+                           )
+                           (i32.const 32)
+                          )
+                         )
+                         (drop
+                          (call $___fwritex
+                           (i32.const 4143)
+                           (i32.const 1)
+                           (local.get $0)
+                          )
+                         )
+                        )
+                       )
+                      )
+                      (if
+                       (i32.and
+                        (i32.gt_s
+                         (local.get $5)
+                         (i32.const 0)
+                        )
+                        (i32.lt_u
+                         (local.get $7)
+                         (local.get $9)
+                        )
+                       )
+                       (loop $while-in110
+                        (if
+                         (i32.gt_u
+                          (local.tee $6
+                           (call $_fmt_u
+                            (i32.load
+                             (local.get $7)
+                            )
+                            (i32.const 0)
+                            (local.get $30)
+                           )
+                          )
+                          (local.get $22)
+                         )
+                         (loop $while-in112
+                          (i32.store8
+                           (local.tee $6
+                            (i32.add
+                             (local.get $6)
+                             (i32.const -1)
+                            )
+                           )
+                           (i32.const 48)
+                          )
+                          (br_if $while-in112
+                           (i32.gt_u
+                            (local.get $6)
+                            (local.get $22)
+                           )
+                          )
+                         )
+                        )
+                        (if
+                         (i32.eqz
+                          (i32.and
+                           (i32.load
+                            (local.get $0)
+                           )
+                           (i32.const 32)
+                          )
+                         )
+                         (drop
+                          (call $___fwritex
+                           (local.get $6)
+                           (select
+                            (i32.const 9)
+                            (local.get $5)
+                            (i32.gt_s
+                             (local.get $5)
+                             (i32.const 9)
+                            )
+                           )
+                           (local.get $0)
+                          )
+                         )
+                        )
+                        (local.set $6
+                         (i32.add
+                          (local.get $5)
+                          (i32.const -9)
+                         )
+                        )
+                        (if
+                         (i32.and
+                          (i32.gt_s
+                           (local.get $5)
+                           (i32.const 9)
+                          )
+                          (i32.lt_u
+                           (local.tee $7
+                            (i32.add
+                             (local.get $7)
+                             (i32.const 4)
+                            )
+                           )
+                           (local.get $9)
+                          )
+                         )
+                         (block
+                          (local.set $5
+                           (local.get $6)
+                          )
+                          (br $while-in110)
+                         )
+                         (local.set $5
+                          (local.get $6)
+                         )
+                        )
+                       )
+                      )
+                      (call $_pad
+                       (local.get $0)
+                       (i32.const 48)
+                       (i32.add
+                        (local.get $5)
+                        (i32.const 9)
+                       )
+                       (i32.const 9)
+                       (i32.const 0)
+                      )
+                     )
+                     (block
+                      (local.set $9
+                       (select
+                        (local.get $9)
+                        (i32.add
+                         (local.get $12)
+                         (i32.const 4)
+                        )
+                        (local.get $24)
+                       )
+                      )
+                      (if
+                       (i32.gt_s
+                        (local.get $5)
+                        (i32.const -1)
+                       )
+                       (block
+                        (local.set $17
+                         (i32.eqz
+                          (local.get $21)
+                         )
+                        )
+                        (local.set $6
+                         (local.get $12)
+                        )
+                        (local.set $7
+                         (local.get $5)
+                        )
+                        (loop $while-in114
+                         (if
+                          (i32.eq
+                           (local.tee $5
+                            (call $_fmt_u
+                             (i32.load
+                              (local.get $6)
+                             )
+                             (i32.const 0)
+                             (local.get $30)
+                            )
+                           )
+                           (local.get $30)
+                          )
+                          (block
+                           (i32.store8
+                            (local.get $35)
+                            (i32.const 48)
+                           )
+                           (local.set $5
+                            (local.get $35)
+                           )
+                          )
+                         )
+                         (block $do-once115
+                          (if
+                           (i32.eq
+                            (local.get $6)
+                            (local.get $12)
+                           )
+                           (block
+                            (if
+                             (i32.eqz
+                              (i32.and
+                               (i32.load
+                                (local.get $0)
+                               )
+                               (i32.const 32)
+                              )
+                             )
+                             (drop
+                              (call $___fwritex
+                               (local.get $5)
+                               (i32.const 1)
+                               (local.get $0)
+                              )
+                             )
+                            )
+                            (local.set $5
+                             (i32.add
+                              (local.get $5)
+                              (i32.const 1)
+                             )
+                            )
+                            (br_if $do-once115
+                             (i32.and
+                              (local.get $17)
+                              (i32.lt_s
+                               (local.get $7)
+                               (i32.const 1)
+                              )
+                             )
+                            )
+                            (br_if $do-once115
+                             (i32.and
+                              (i32.load
+                               (local.get $0)
+                              )
+                              (i32.const 32)
+                             )
+                            )
+                            (drop
+                             (call $___fwritex
+                              (i32.const 4143)
+                              (i32.const 1)
+                              (local.get $0)
+                             )
+                            )
+                           )
+                           (block
+                            (br_if $do-once115
+                             (i32.le_u
+                              (local.get $5)
+                              (local.get $22)
+                             )
+                            )
+                            (loop $while-in118
+                             (i32.store8
+                              (local.tee $5
+                               (i32.add
+                                (local.get $5)
+                                (i32.const -1)
+                               )
+                              )
+                              (i32.const 48)
+                             )
+                             (br_if $while-in118
+                              (i32.gt_u
+                               (local.get $5)
+                               (local.get $22)
+                              )
+                             )
+                            )
+                           )
+                          )
+                         )
+                         (local.set $8
+                          (i32.sub
+                           (local.get $43)
+                           (local.get $5)
+                          )
+                         )
+                         (if
+                          (i32.eqz
+                           (i32.and
+                            (i32.load
+                             (local.get $0)
+                            )
+                            (i32.const 32)
+                           )
+                          )
+                          (drop
+                           (call $___fwritex
+                            (local.get $5)
+                            (select
+                             (local.get $8)
+                             (local.get $7)
+                             (i32.gt_s
+                              (local.get $7)
+                              (local.get $8)
+                             )
+                            )
+                            (local.get $0)
+                           )
+                          )
+                         )
+                         (br_if $while-in114
+                          (i32.and
+                           (i32.lt_u
+                            (local.tee $6
+                             (i32.add
+                              (local.get $6)
+                              (i32.const 4)
+                             )
+                            )
+                            (local.get $9)
+                           )
+                           (i32.gt_s
+                            (local.tee $7
+                             (i32.sub
+                              (local.get $7)
+                              (local.get $8)
+                             )
+                            )
+                            (i32.const -1)
+                           )
+                          )
+                         )
+                         (local.set $5
+                          (local.get $7)
+                         )
+                        )
+                       )
+                      )
+                      (call $_pad
+                       (local.get $0)
+                       (i32.const 48)
+                       (i32.add
+                        (local.get $5)
+                        (i32.const 18)
+                       )
+                       (i32.const 18)
+                       (i32.const 0)
+                      )
+                      (br_if $do-once99
+                       (i32.and
+                        (i32.load
+                         (local.get $0)
+                        )
+                        (i32.const 32)
+                       )
+                      )
+                      (drop
+                       (call $___fwritex
+                        (local.get $18)
+                        (i32.sub
+                         (local.get $28)
+                         (local.get $18)
+                        )
+                        (local.get $0)
+                       )
+                      )
+                     )
+                    )
+                   )
+                   (call $_pad
+                    (local.get $0)
+                    (i32.const 32)
+                    (local.get $14)
+                    (local.get $13)
+                    (i32.xor
+                     (local.get $11)
+                     (i32.const 8192)
+                    )
+                   )
+                   (select
+                    (local.get $14)
+                    (local.get $13)
+                    (i32.lt_s
+                     (local.get $13)
+                     (local.get $14)
+                    )
+                   )
+                  )
+                  (block (result i32)
+                   (call $_pad
+                    (local.get $0)
+                    (i32.const 32)
+                    (local.get $14)
+                    (local.tee $7
+                     (i32.add
+                      (local.tee $9
+                       (select
+                        (i32.const 0)
+                        (local.get $27)
+                        (local.tee $6
+                         (i32.or
+                          (f64.ne
+                           (local.get $15)
+                           (local.get $15)
+                          )
+                          (i32.const 0)
+                         )
+                        )
+                       )
+                      )
+                      (i32.const 3)
+                     )
+                    )
+                    (local.get $8)
+                   )
+                   (if
+                    (i32.eqz
+                     (i32.and
+                      (local.tee $5
+                       (i32.load
+                        (local.get $0)
+                       )
+                      )
+                      (i32.const 32)
+                     )
+                    )
+                    (block
+                     (drop
+                      (call $___fwritex
+                       (local.get $31)
+                       (local.get $9)
+                       (local.get $0)
+                      )
+                     )
+                     (local.set $5
+                      (i32.load
+                       (local.get $0)
+                      )
+                     )
+                    )
+                   )
+                   (local.set $6
+                    (select
+                     (select
+                      (i32.const 4135)
+                      (i32.const 4139)
+                      (local.tee $8
+                       (i32.ne
+                        (i32.and
+                         (local.get $18)
+                         (i32.const 32)
+                        )
+                        (i32.const 0)
+                       )
+                      )
+                     )
+                     (select
+                      (i32.const 4127)
+                      (i32.const 4131)
+                      (local.get $8)
+                     )
+                     (local.get $6)
+                    )
+                   )
+                   (if
+                    (i32.eqz
+                     (i32.and
+                      (local.get $5)
+                      (i32.const 32)
+                     )
+                    )
+                    (drop
+                     (call $___fwritex
+                      (local.get $6)
+                      (i32.const 3)
+                      (local.get $0)
+                     )
+                    )
+                   )
+                   (call $_pad
+                    (local.get $0)
+                    (i32.const 32)
+                    (local.get $14)
+                    (local.get $7)
+                    (i32.xor
+                     (local.get $11)
+                     (i32.const 8192)
+                    )
+                   )
+                   (select
+                    (local.get $14)
+                    (local.get $7)
+                    (i32.lt_s
+                     (local.get $7)
+                     (local.get $14)
+                    )
+                   )
+                  )
+                 )
+                )
+               )
+               (local.set $5
+                (local.get $10)
+               )
+               (local.set $10
+                (local.get $7)
+               )
+               (br $label$continue$L1)
+              )
+              (local.set $7
+               (local.get $5)
+              )
+              (local.set $12
+               (local.get $6)
+              )
+              (local.set $8
+               (i32.const 0)
+              )
+              (local.set $9
+               (i32.const 4091)
+              )
+              (br $__rjto$8
+               (local.get $26)
+              )
+             )
+             (local.set $9
+              (i32.and
+               (local.get $18)
+               (i32.const 32)
+              )
+             )
+             (if
+              (i32.and
+               (i32.eqz
+                (local.tee $8
+                 (i32.load
+                  (local.tee $5
+                   (local.get $19)
+                  )
+                 )
+                )
+               )
+               (i32.eqz
+                (local.tee $11
+                 (i32.load offset=4
+                  (local.get $5)
+                 )
+                )
+               )
+              )
+              (block
+               (local.set $5
+                (local.get $26)
+               )
+               (local.set $8
+                (i32.const 0)
+               )
+               (local.set $9
+                (i32.const 4091)
+               )
+               (br $__rjti$8)
+              )
+              (block
+               (local.set $5
+                (local.get $8)
+               )
+               (local.set $8
+                (local.get $26)
+               )
+               (loop $while-in123
+                (i32.store8
+                 (local.tee $8
+                  (i32.add
+                   (local.get $8)
+                   (i32.const -1)
+                  )
+                 )
+                 (i32.or
+                  (i32.load8_u
+                   (i32.add
+                    (i32.and
+                     (local.get $5)
+                     (i32.const 15)
+                    )
+                    (i32.const 4075)
+                   )
+                  )
+                  (local.get $9)
+                 )
+                )
+                (br_if $while-in123
+                 (i32.eqz
+                  (i32.and
+                   (i32.eqz
+                    (local.tee $5
+                     (call $_bitshift64Lshr
+                      (local.get $5)
+                      (local.get $11)
+                      (i32.const 4)
+                     )
+                    )
+                   )
+                   (i32.eqz
+                    (local.tee $11
+                     (global.get $tempRet0)
+                    )
+                   )
+                  )
+                 )
+                )
+                (local.set $5
+                 (local.get $8)
+                )
+               )
+               (local.set $8
+                (if (result i32)
+                 (i32.or
+                  (i32.eqz
+                   (i32.and
+                    (local.get $7)
+                    (i32.const 8)
+                   )
+                  )
+                  (i32.and
+                   (i32.eqz
+                    (i32.load
+                     (local.tee $11
+                      (local.get $19)
+                     )
+                    )
+                   )
+                   (i32.eqz
+                    (i32.load offset=4
+                     (local.get $11)
+                    )
+                   )
+                  )
+                 )
+                 (block (result i32)
+                  (local.set $9
+                   (i32.const 4091)
+                  )
+                  (i32.const 0)
+                 )
+                 (block (result i32)
+                  (local.set $9
+                   (i32.add
+                    (i32.shr_s
+                     (local.get $18)
+                     (i32.const 4)
+                    )
+                    (i32.const 4091)
+                   )
+                  )
+                  (i32.const 2)
+                 )
+                )
+               )
+               (br $__rjti$8)
+              )
+             )
+            )
+            (local.set $5
+             (call $_fmt_u
+              (local.get $5)
+              (local.get $7)
+              (local.get $26)
+             )
+            )
+            (local.set $7
+             (local.get $11)
+            )
+            (br $__rjti$8)
+           )
+           (local.set $18
+            (i32.eqz
+             (local.tee $13
+              (call $_memchr
+               (local.get $5)
+               (i32.const 0)
+               (local.get $6)
+              )
+             )
+            )
+           )
+           (local.set $7
+            (local.get $5)
+           )
+           (local.set $11
+            (local.get $8)
+           )
+           (local.set $12
+            (select
+             (local.get $6)
+             (i32.sub
+              (local.get $13)
+              (local.get $5)
+             )
+             (local.get $18)
+            )
+           )
+           (local.set $8
+            (i32.const 0)
+           )
+           (local.set $9
+            (i32.const 4091)
+           )
+           (br $__rjto$8
+            (select
+             (i32.add
+              (local.get $5)
+              (local.get $6)
+             )
+             (local.get $13)
+             (local.get $18)
+            )
+           )
+          )
+          (local.set $5
+           (i32.const 0)
+          )
+          (local.set $7
+           (i32.const 0)
+          )
+          (local.set $6
+           (i32.load
+            (local.get $19)
+           )
+          )
+          (loop $while-in125
+           (block $while-out124
+            (br_if $while-out124
+             (i32.eqz
+              (local.tee $9
+               (i32.load
+                (local.get $6)
+               )
+              )
+             )
+            )
+            (br_if $while-out124
+             (i32.or
+              (i32.lt_s
+               (local.tee $7
+                (call $_wctomb
+                 (local.get $36)
+                 (local.get $9)
+                )
+               )
+               (i32.const 0)
+              )
+              (i32.gt_u
+               (local.get $7)
+               (i32.sub
+                (local.get $8)
+                (local.get $5)
+               )
+              )
+             )
+            )
+            (local.set $6
+             (i32.add
+              (local.get $6)
+              (i32.const 4)
+             )
+            )
+            (br_if $while-in125
+             (i32.gt_u
+              (local.get $8)
+              (local.tee $5
+               (i32.add
+                (local.get $7)
+                (local.get $5)
+               )
+              )
+             )
+            )
+           )
+          )
+          (if
+           (i32.lt_s
+            (local.get $7)
+            (i32.const 0)
+           )
+           (block
+            (local.set $16
+             (i32.const -1)
+            )
+            (br $label$break$L1)
+           )
+          )
+          (call $_pad
+           (local.get $0)
+           (i32.const 32)
+           (local.get $14)
+           (local.get $5)
+           (local.get $11)
+          )
+          (if
+           (local.get $5)
+           (block
+            (local.set $6
+             (i32.const 0)
+            )
+            (local.set $7
+             (i32.load
+              (local.get $19)
+             )
+            )
+            (loop $while-in127
+             (if
+              (i32.eqz
+               (local.tee $8
+                (i32.load
+                 (local.get $7)
+                )
+               )
+              )
+              (block
+               (local.set $7
+                (local.get $5)
+               )
+               (br $__rjti$7)
+              )
+             )
+             (if
+              (i32.gt_s
+               (local.tee $6
+                (i32.add
+                 (local.tee $8
+                  (call $_wctomb
+                   (local.get $36)
+                   (local.get $8)
+                  )
+                 )
+                 (local.get $6)
+                )
+               )
+               (local.get $5)
+              )
+              (block
+               (local.set $7
+                (local.get $5)
+               )
+               (br $__rjti$7)
+              )
+             )
+             (if
+              (i32.eqz
+               (i32.and
+                (i32.load
+                 (local.get $0)
+                )
+                (i32.const 32)
+               )
+              )
+              (drop
+               (call $___fwritex
+                (local.get $36)
+                (local.get $8)
+                (local.get $0)
+               )
+              )
+             )
+             (local.set $7
+              (i32.add
+               (local.get $7)
+               (i32.const 4)
+              )
+             )
+             (br_if $while-in127
+              (i32.lt_u
+               (local.get $6)
+               (local.get $5)
+              )
+             )
+             (local.set $7
+              (local.get $5)
+             )
+            )
+           )
+           (local.set $7
+            (i32.const 0)
+           )
+          )
+         )
+         (call $_pad
+          (local.get $0)
+          (i32.const 32)
+          (local.get $14)
+          (local.get $7)
+          (i32.xor
+           (local.get $11)
+           (i32.const 8192)
+          )
+         )
+         (local.set $5
+          (local.get $10)
+         )
+         (local.set $10
+          (select
+           (local.get $14)
+           (local.get $7)
+           (i32.gt_s
+            (local.get $14)
+            (local.get $7)
+           )
+          )
+         )
+         (br $label$continue$L1)
+        )
+        (local.set $11
+         (select
+          (i32.and
+           (local.get $7)
+           (i32.const -65537)
+          )
+          (local.get $7)
+          (i32.gt_s
+           (local.get $6)
+           (i32.const -1)
+          )
+         )
+        )
+        (local.set $12
+         (if (result i32)
+          (i32.or
+           (local.get $6)
+           (local.tee $12
+            (i32.or
+             (i32.ne
+              (i32.load
+               (local.tee $7
+                (local.get $19)
+               )
+              )
+              (i32.const 0)
+             )
+             (i32.ne
+              (i32.load offset=4
+               (local.get $7)
+              )
+              (i32.const 0)
+             )
+            )
+           )
+          )
+          (block (result i32)
+           (local.set $7
+            (local.get $5)
+           )
+           (select
+            (local.get $6)
+            (local.tee $5
+             (i32.add
+              (i32.xor
+               (i32.and
+                (local.get $12)
+                (i32.const 1)
+               )
+               (i32.const 1)
+              )
+              (i32.sub
+               (local.get $39)
+               (local.get $5)
+              )
+             )
+            )
+            (i32.gt_s
+             (local.get $6)
+             (local.get $5)
+            )
+           )
+          )
+          (block (result i32)
+           (local.set $7
+            (local.get $26)
+           )
+           (i32.const 0)
+          )
+         )
+        )
+        (local.get $26)
+       )
+      )
+      (call $_pad
+       (local.get $0)
+       (i32.const 32)
+       (local.tee $6
+        (select
+         (local.tee $5
+          (i32.add
+           (local.get $8)
+           (local.tee $12
+            (select
+             (local.tee $13
+              (i32.sub
+               (local.get $5)
+               (local.get $7)
+              )
+             )
+             (local.get $12)
+             (i32.lt_s
+              (local.get $12)
+              (local.get $13)
+             )
+            )
+           )
+          )
+         )
+         (local.get $14)
+         (i32.lt_s
+          (local.get $14)
+          (local.get $5)
+         )
+        )
+       )
+       (local.get $5)
+       (local.get $11)
+      )
+      (if
+       (i32.eqz
+        (i32.and
+         (i32.load
+          (local.get $0)
+         )
+         (i32.const 32)
+        )
+       )
+       (drop
+        (call $___fwritex
+         (local.get $9)
+         (local.get $8)
+         (local.get $0)
+        )
+       )
+      )
+      (call $_pad
+       (local.get $0)
+       (i32.const 48)
+       (local.get $6)
+       (local.get $5)
+       (i32.xor
+        (local.get $11)
+        (i32.const 65536)
+       )
+      )
+      (call $_pad
+       (local.get $0)
+       (i32.const 48)
+       (local.get $12)
+       (local.get $13)
+       (i32.const 0)
+      )
+      (if
+       (i32.eqz
+        (i32.and
+         (i32.load
+          (local.get $0)
+         )
+         (i32.const 32)
+        )
+       )
+       (drop
+        (call $___fwritex
+         (local.get $7)
+         (local.get $13)
+         (local.get $0)
+        )
+       )
+      )
+      (call $_pad
+       (local.get $0)
+       (i32.const 32)
+       (local.get $6)
+       (local.get $5)
+       (i32.xor
+        (local.get $11)
+        (i32.const 8192)
+       )
+      )
+      (local.set $5
+       (local.get $10)
+      )
+      (local.set $10
+       (local.get $6)
+      )
+      (br $label$continue$L1)
+     )
+    )
+    (br $label$break$L343)
+   )
+   (if
+    (i32.eqz
+     (local.get $0)
+    )
+    (if
+     (local.get $1)
+     (block
+      (local.set $0
+       (i32.const 1)
+      )
+      (loop $while-in130
+       (if
+        (local.tee $1
+         (i32.load
+          (i32.add
+           (local.get $4)
+           (i32.shl
+            (local.get $0)
+            (i32.const 2)
+           )
+          )
+         )
+        )
+        (block
+         (call $_pop_arg_336
+          (i32.add
+           (local.get $3)
+           (i32.shl
+            (local.get $0)
+            (i32.const 3)
+           )
+          )
+          (local.get $1)
+          (local.get $2)
+         )
+         (br_if $while-in130
+          (i32.lt_s
+           (local.tee $0
+            (i32.add
+             (local.get $0)
+             (i32.const 1)
+            )
+           )
+           (i32.const 10)
+          )
+         )
+         (local.set $16
+          (i32.const 1)
+         )
+         (br $label$break$L343)
+        )
+       )
+      )
+      (if
+       (i32.lt_s
+        (local.get $0)
+        (i32.const 10)
+       )
+       (loop $while-in132
+        (if
+         (i32.load
+          (i32.add
+           (local.get $4)
+           (i32.shl
+            (local.get $0)
+            (i32.const 2)
+           )
+          )
+         )
+         (block
+          (local.set $16
+           (i32.const -1)
+          )
+          (br $label$break$L343)
+         )
+        )
+        (br_if $while-in132
+         (i32.lt_s
+          (local.tee $0
+           (i32.add
+            (local.get $0)
+            (i32.const 1)
+           )
+          )
+          (i32.const 10)
+         )
+        )
+        (local.set $16
+         (i32.const 1)
+        )
+       )
+       (local.set $16
+        (i32.const 1)
+       )
+      )
+     )
+     (local.set $16
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $25)
+  )
+  (local.get $16)
+ )
+ (func $_pop_arg_336 (param $0 i32) (param $1 i32) (param $2 i32)
+  (local $3 i32)
+  (local $4 f64)
+  (local $5 i32)
+  (block $label$break$L1
+   (if
+    (i32.le_u
+     (local.get $1)
+     (i32.const 20)
+    )
+    (block $switch-default
+     (block $switch-case9
+      (block $switch-case8
+       (block $switch-case7
+        (block $switch-case6
+         (block $switch-case5
+          (block $switch-case4
+           (block $switch-case3
+            (block $switch-case2
+             (block $switch-case1
+              (block $switch-case
+               (br_table $switch-case $switch-case1 $switch-case2 $switch-case3 $switch-case4 $switch-case5 $switch-case6 $switch-case7 $switch-case8 $switch-case9 $switch-default
+                (i32.sub
+                 (local.get $1)
+                 (i32.const 9)
+                )
+               )
+              )
+              (local.set $3
+               (i32.load
+                (local.tee $1
+                 (i32.and
+                  (i32.add
+                   (i32.load
+                    (local.get $2)
+                   )
+                   (i32.const 3)
+                  )
+                  (i32.const -4)
+                 )
+                )
+               )
+              )
+              (i32.store
+               (local.get $2)
+               (i32.add
+                (local.get $1)
+                (i32.const 4)
+               )
+              )
+              (i32.store
+               (local.get $0)
+               (local.get $3)
+              )
+              (br $label$break$L1)
+             )
+             (local.set $1
+              (i32.load
+               (local.tee $3
+                (i32.and
+                 (i32.add
+                  (i32.load
+                   (local.get $2)
+                  )
+                  (i32.const 3)
+                 )
+                 (i32.const -4)
+                )
+               )
+              )
+             )
+             (i32.store
+              (local.get $2)
+              (i32.add
+               (local.get $3)
+               (i32.const 4)
+              )
+             )
+             (i32.store
+              (local.get $0)
+              (local.get $1)
+             )
+             (i32.store offset=4
+              (local.get $0)
+              (i32.shr_s
+               (i32.shl
+                (i32.lt_s
+                 (local.get $1)
+                 (i32.const 0)
+                )
+                (i32.const 31)
+               )
+               (i32.const 31)
+              )
+             )
+             (br $label$break$L1)
+            )
+            (local.set $3
+             (i32.load
+              (local.tee $1
+               (i32.and
+                (i32.add
+                 (i32.load
+                  (local.get $2)
+                 )
+                 (i32.const 3)
+                )
+                (i32.const -4)
+               )
+              )
+             )
+            )
+            (i32.store
+             (local.get $2)
+             (i32.add
+              (local.get $1)
+              (i32.const 4)
+             )
+            )
+            (i32.store
+             (local.get $0)
+             (local.get $3)
+            )
+            (i32.store offset=4
+             (local.get $0)
+             (i32.const 0)
+            )
+            (br $label$break$L1)
+           )
+           (local.set $5
+            (i32.load
+             (local.tee $3
+              (local.tee $1
+               (i32.and
+                (i32.add
+                 (i32.load
+                  (local.get $2)
+                 )
+                 (i32.const 7)
+                )
+                (i32.const -8)
+               )
+              )
+             )
+            )
+           )
+           (local.set $3
+            (i32.load offset=4
+             (local.get $3)
+            )
+           )
+           (i32.store
+            (local.get $2)
+            (i32.add
+             (local.get $1)
+             (i32.const 8)
+            )
+           )
+           (i32.store
+            (local.get $0)
+            (local.get $5)
+           )
+           (i32.store offset=4
+            (local.get $0)
+            (local.get $3)
+           )
+           (br $label$break$L1)
+          )
+          (local.set $3
+           (i32.load
+            (local.tee $1
+             (i32.and
+              (i32.add
+               (i32.load
+                (local.get $2)
+               )
+               (i32.const 3)
+              )
+              (i32.const -4)
+             )
+            )
+           )
+          )
+          (i32.store
+           (local.get $2)
+           (i32.add
+            (local.get $1)
+            (i32.const 4)
+           )
+          )
+          (i32.store
+           (local.get $0)
+           (local.tee $1
+            (i32.shr_s
+             (i32.shl
+              (i32.and
+               (local.get $3)
+               (i32.const 65535)
+              )
+              (i32.const 16)
+             )
+             (i32.const 16)
+            )
+           )
+          )
+          (i32.store offset=4
+           (local.get $0)
+           (i32.shr_s
+            (i32.shl
+             (i32.lt_s
+              (local.get $1)
+              (i32.const 0)
+             )
+             (i32.const 31)
+            )
+            (i32.const 31)
+           )
+          )
+          (br $label$break$L1)
+         )
+         (local.set $3
+          (i32.load
+           (local.tee $1
+            (i32.and
+             (i32.add
+              (i32.load
+               (local.get $2)
+              )
+              (i32.const 3)
+             )
+             (i32.const -4)
+            )
+           )
+          )
+         )
+         (i32.store
+          (local.get $2)
+          (i32.add
+           (local.get $1)
+           (i32.const 4)
+          )
+         )
+         (i32.store
+          (local.get $0)
+          (i32.and
+           (local.get $3)
+           (i32.const 65535)
+          )
+         )
+         (i32.store offset=4
+          (local.get $0)
+          (i32.const 0)
+         )
+         (br $label$break$L1)
+        )
+        (local.set $3
+         (i32.load
+          (local.tee $1
+           (i32.and
+            (i32.add
+             (i32.load
+              (local.get $2)
+             )
+             (i32.const 3)
+            )
+            (i32.const -4)
+           )
+          )
+         )
+        )
+        (i32.store
+         (local.get $2)
+         (i32.add
+          (local.get $1)
+          (i32.const 4)
+         )
+        )
+        (i32.store
+         (local.get $0)
+         (local.tee $1
+          (i32.shr_s
+           (i32.shl
+            (i32.and
+             (local.get $3)
+             (i32.const 255)
+            )
+            (i32.const 24)
+           )
+           (i32.const 24)
+          )
+         )
+        )
+        (i32.store offset=4
+         (local.get $0)
+         (i32.shr_s
+          (i32.shl
+           (i32.lt_s
+            (local.get $1)
+            (i32.const 0)
+           )
+           (i32.const 31)
+          )
+          (i32.const 31)
+         )
+        )
+        (br $label$break$L1)
+       )
+       (local.set $3
+        (i32.load
+         (local.tee $1
+          (i32.and
+           (i32.add
+            (i32.load
+             (local.get $2)
+            )
+            (i32.const 3)
+           )
+           (i32.const -4)
+          )
+         )
+        )
+       )
+       (i32.store
+        (local.get $2)
+        (i32.add
+         (local.get $1)
+         (i32.const 4)
+        )
+       )
+       (i32.store
+        (local.get $0)
+        (i32.and
+         (local.get $3)
+         (i32.const 255)
+        )
+       )
+       (i32.store offset=4
+        (local.get $0)
+        (i32.const 0)
+       )
+       (br $label$break$L1)
+      )
+      (local.set $4
+       (f64.load
+        (local.tee $1
+         (i32.and
+          (i32.add
+           (i32.load
+            (local.get $2)
+           )
+           (i32.const 7)
+          )
+          (i32.const -8)
+         )
+        )
+       )
+      )
+      (i32.store
+       (local.get $2)
+       (i32.add
+        (local.get $1)
+        (i32.const 8)
+       )
+      )
+      (f64.store
+       (local.get $0)
+       (local.get $4)
+      )
+      (br $label$break$L1)
+     )
+     (local.set $4
+      (f64.load
+       (local.tee $1
+        (i32.and
+         (i32.add
+          (i32.load
+           (local.get $2)
+          )
+          (i32.const 7)
+         )
+         (i32.const -8)
+        )
+       )
+      )
+     )
+     (i32.store
+      (local.get $2)
+      (i32.add
+       (local.get $1)
+       (i32.const 8)
+      )
+     )
+     (f64.store
+      (local.get $0)
+      (local.get $4)
+     )
+    )
+   )
+  )
+ )
+ (func $_fmt_u (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (if
+   (i32.or
+    (i32.gt_u
+     (local.get $1)
+     (i32.const 0)
+    )
+    (i32.and
+     (i32.eqz
+      (local.get $1)
+     )
+     (i32.gt_u
+      (local.get $0)
+      (i32.const -1)
+     )
+    )
+   )
+   (loop $while-in
+    (i32.store8
+     (local.tee $2
+      (i32.add
+       (local.get $2)
+       (i32.const -1)
+      )
+     )
+     (i32.or
+      (local.tee $3
+       (call $___uremdi3
+        (local.get $0)
+        (local.get $1)
+        (i32.const 10)
+        (i32.const 0)
+       )
+      )
+      (i32.const 48)
+     )
+    )
+    (local.set $3
+     (call $___udivdi3
+      (local.get $0)
+      (local.get $1)
+      (i32.const 10)
+      (i32.const 0)
+     )
+    )
+    (local.set $4
+     (global.get $tempRet0)
+    )
+    (if
+     (i32.or
+      (i32.gt_u
+       (local.get $1)
+       (i32.const 9)
+      )
+      (i32.and
+       (i32.eq
+        (local.get $1)
+        (i32.const 9)
+       )
+       (i32.gt_u
+        (local.get $0)
+        (i32.const -1)
+       )
+      )
+     )
+     (block
+      (local.set $0
+       (local.get $3)
+      )
+      (local.set $1
+       (local.get $4)
+      )
+      (br $while-in)
+     )
+     (local.set $0
+      (local.get $3)
+     )
+    )
+   )
+  )
+  (if
+   (local.get $0)
+   (loop $while-in1
+    (i32.store8
+     (local.tee $2
+      (i32.add
+       (local.get $2)
+       (i32.const -1)
+      )
+     )
+     (i32.or
+      (call $i32u-rem
+       (local.get $0)
+       (i32.const 10)
+      )
+      (i32.const 48)
+     )
+    )
+    (local.set $1
+     (call $i32u-div
+      (local.get $0)
+      (i32.const 10)
+     )
+    )
+    (if
+     (i32.ge_u
+      (local.get $0)
+      (i32.const 10)
+     )
+     (block
+      (local.set $0
+       (local.get $1)
+      )
+      (br $while-in1)
+     )
+    )
+   )
+  )
+  (local.get $2)
+ )
+ (func $_pad (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local.set $7
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 256)
+   )
+  )
+  (if
+   (i32.ge_s
+    (global.get $STACKTOP)
+    (global.get $STACK_MAX)
+   )
+   (call $abort)
+  )
+  (local.set $6
+   (local.get $7)
+  )
+  (block $do-once
+   (if
+    (i32.and
+     (i32.gt_s
+      (local.get $2)
+      (local.get $3)
+     )
+     (i32.eqz
+      (i32.and
+       (local.get $4)
+       (i32.const 73728)
+      )
+     )
+    )
+    (block
+     (drop
+      (call $_memset
+       (local.get $6)
+       (local.get $1)
+       (select
+        (i32.const 256)
+        (local.tee $5
+         (i32.sub
+          (local.get $2)
+          (local.get $3)
+         )
+        )
+        (i32.gt_u
+         (local.get $5)
+         (i32.const 256)
+        )
+       )
+      )
+     )
+     (local.set $4
+      (i32.eqz
+       (i32.and
+        (local.tee $1
+         (i32.load
+          (local.get $0)
+         )
+        )
+        (i32.const 32)
+       )
+      )
+     )
+     (if
+      (i32.gt_u
+       (local.get $5)
+       (i32.const 255)
+      )
+      (block
+       (loop $while-in
+        (if
+         (local.get $4)
+         (block
+          (drop
+           (call $___fwritex
+            (local.get $6)
+            (i32.const 256)
+            (local.get $0)
+           )
+          )
+          (local.set $1
+           (i32.load
+            (local.get $0)
+           )
+          )
+         )
+        )
+        (local.set $4
+         (i32.eqz
+          (i32.and
+           (local.get $1)
+           (i32.const 32)
+          )
+         )
+        )
+        (br_if $while-in
+         (i32.gt_u
+          (local.tee $5
+           (i32.add
+            (local.get $5)
+            (i32.const -256)
+           )
+          )
+          (i32.const 255)
+         )
+        )
+       )
+       (br_if $do-once
+        (i32.eqz
+         (local.get $4)
+        )
+       )
+       (local.set $5
+        (i32.and
+         (i32.sub
+          (local.get $2)
+          (local.get $3)
+         )
+         (i32.const 255)
+        )
+       )
+      )
+      (br_if $do-once
+       (i32.eqz
+        (local.get $4)
+       )
+      )
+     )
+     (drop
+      (call $___fwritex
+       (local.get $6)
+       (local.get $5)
+       (local.get $0)
+      )
+     )
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $7)
+  )
+ )
+ (func $_malloc (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (block $folding-inner0
+   (block $do-once
+    (if
+     (i32.lt_u
+      (local.get $0)
+      (i32.const 245)
+     )
+     (block
+      (if
+       (i32.and
+        (local.tee $5
+         (i32.shr_u
+          (local.tee $11
+           (i32.load
+            (i32.const 176)
+           )
+          )
+          (local.tee $13
+           (i32.shr_u
+            (local.tee $4
+             (select
+              (i32.const 16)
+              (i32.and
+               (i32.add
+                (local.get $0)
+                (i32.const 11)
+               )
+               (i32.const -8)
+              )
+              (i32.lt_u
+               (local.get $0)
+               (i32.const 11)
+              )
+             )
+            )
+            (i32.const 3)
+           )
+          )
+         )
+        )
+        (i32.const 3)
+       )
+       (block
+        (local.set $10
+         (i32.load
+          (local.tee $1
+           (i32.add
+            (local.tee $7
+             (i32.load
+              (local.tee $3
+               (i32.add
+                (local.tee $2
+                 (i32.add
+                  (i32.shl
+                   (local.tee $4
+                    (i32.add
+                     (i32.xor
+                      (i32.and
+                       (local.get $5)
+                       (i32.const 1)
+                      )
+                      (i32.const 1)
+                     )
+                     (local.get $13)
+                    )
+                   )
+                   (i32.const 3)
+                  )
+                  (i32.const 216)
+                 )
+                )
+                (i32.const 8)
+               )
+              )
+             )
+            )
+            (i32.const 8)
+           )
+          )
+         )
+        )
+        (if
+         (i32.eq
+          (local.get $2)
+          (local.get $10)
+         )
+         (i32.store
+          (i32.const 176)
+          (i32.and
+           (local.get $11)
+           (i32.xor
+            (i32.shl
+             (i32.const 1)
+             (local.get $4)
+            )
+            (i32.const -1)
+           )
+          )
+         )
+         (block
+          (if
+           (i32.lt_u
+            (local.get $10)
+            (i32.load
+             (i32.const 192)
+            )
+           )
+           (call $_abort)
+          )
+          (if
+           (i32.eq
+            (i32.load
+             (local.tee $0
+              (i32.add
+               (local.get $10)
+               (i32.const 12)
+              )
+             )
+            )
+            (local.get $7)
+           )
+           (block
+            (i32.store
+             (local.get $0)
+             (local.get $2)
+            )
+            (i32.store
+             (local.get $3)
+             (local.get $10)
+            )
+           )
+           (call $_abort)
+          )
+         )
+        )
+        (i32.store offset=4
+         (local.get $7)
+         (i32.or
+          (local.tee $0
+           (i32.shl
+            (local.get $4)
+            (i32.const 3)
+           )
+          )
+          (i32.const 3)
+         )
+        )
+        (i32.store
+         (local.tee $0
+          (i32.add
+           (i32.add
+            (local.get $7)
+            (local.get $0)
+           )
+           (i32.const 4)
+          )
+         )
+         (i32.or
+          (i32.load
+           (local.get $0)
+          )
+          (i32.const 1)
+         )
+        )
+        (return
+         (local.get $1)
+        )
+       )
+      )
+      (if
+       (i32.gt_u
+        (local.get $4)
+        (local.tee $0
+         (i32.load
+          (i32.const 184)
+         )
+        )
+       )
+       (block
+        (if
+         (local.get $5)
+         (block
+          (local.set $10
+           (i32.and
+            (i32.shr_u
+             (local.tee $3
+              (i32.add
+               (i32.and
+                (local.tee $3
+                 (i32.and
+                  (i32.shl
+                   (local.get $5)
+                   (local.get $13)
+                  )
+                  (i32.or
+                   (local.tee $3
+                    (i32.shl
+                     (i32.const 2)
+                     (local.get $13)
+                    )
+                   )
+                   (i32.sub
+                    (i32.const 0)
+                    (local.get $3)
+                   )
+                  )
+                 )
+                )
+                (i32.sub
+                 (i32.const 0)
+                 (local.get $3)
+                )
+               )
+               (i32.const -1)
+              )
+             )
+             (i32.const 12)
+            )
+            (i32.const 16)
+           )
+          )
+          (local.set $9
+           (i32.load
+            (local.tee $7
+             (i32.add
+              (local.tee $12
+               (i32.load
+                (local.tee $3
+                 (i32.add
+                  (local.tee $10
+                   (i32.add
+                    (i32.shl
+                     (local.tee $5
+                      (i32.add
+                       (i32.or
+                        (i32.or
+                         (i32.or
+                          (i32.or
+                           (local.tee $3
+                            (i32.and
+                             (i32.shr_u
+                              (local.tee $7
+                               (i32.shr_u
+                                (local.get $3)
+                                (local.get $10)
+                               )
+                              )
+                              (i32.const 5)
+                             )
+                             (i32.const 8)
+                            )
+                           )
+                           (local.get $10)
+                          )
+                          (local.tee $3
+                           (i32.and
+                            (i32.shr_u
+                             (local.tee $7
+                              (i32.shr_u
+                               (local.get $7)
+                               (local.get $3)
+                              )
+                             )
+                             (i32.const 2)
+                            )
+                            (i32.const 4)
+                           )
+                          )
+                         )
+                         (local.tee $3
+                          (i32.and
+                           (i32.shr_u
+                            (local.tee $7
+                             (i32.shr_u
+                              (local.get $7)
+                              (local.get $3)
+                             )
+                            )
+                            (i32.const 1)
+                           )
+                           (i32.const 2)
+                          )
+                         )
+                        )
+                        (local.tee $3
+                         (i32.and
+                          (i32.shr_u
+                           (local.tee $7
+                            (i32.shr_u
+                             (local.get $7)
+                             (local.get $3)
+                            )
+                           )
+                           (i32.const 1)
+                          )
+                          (i32.const 1)
+                         )
+                        )
+                       )
+                       (i32.shr_u
+                        (local.get $7)
+                        (local.get $3)
+                       )
+                      )
+                     )
+                     (i32.const 3)
+                    )
+                    (i32.const 216)
+                   )
+                  )
+                  (i32.const 8)
+                 )
+                )
+               )
+              )
+              (i32.const 8)
+             )
+            )
+           )
+          )
+          (if
+           (i32.eq
+            (local.get $10)
+            (local.get $9)
+           )
+           (block
+            (i32.store
+             (i32.const 176)
+             (i32.and
+              (local.get $11)
+              (i32.xor
+               (i32.shl
+                (i32.const 1)
+                (local.get $5)
+               )
+               (i32.const -1)
+              )
+             )
+            )
+            (local.set $8
+             (local.get $0)
+            )
+           )
+           (block
+            (if
+             (i32.lt_u
+              (local.get $9)
+              (i32.load
+               (i32.const 192)
+              )
+             )
+             (call $_abort)
+            )
+            (if
+             (i32.eq
+              (i32.load
+               (local.tee $0
+                (i32.add
+                 (local.get $9)
+                 (i32.const 12)
+                )
+               )
+              )
+              (local.get $12)
+             )
+             (block
+              (i32.store
+               (local.get $0)
+               (local.get $10)
+              )
+              (i32.store
+               (local.get $3)
+               (local.get $9)
+              )
+              (local.set $8
+               (i32.load
+                (i32.const 184)
+               )
+              )
+             )
+             (call $_abort)
+            )
+           )
+          )
+          (i32.store offset=4
+           (local.get $12)
+           (i32.or
+            (local.get $4)
+            (i32.const 3)
+           )
+          )
+          (i32.store offset=4
+           (local.tee $10
+            (i32.add
+             (local.get $12)
+             (local.get $4)
+            )
+           )
+           (i32.or
+            (local.tee $5
+             (i32.sub
+              (i32.shl
+               (local.get $5)
+               (i32.const 3)
+              )
+              (local.get $4)
+             )
+            )
+            (i32.const 1)
+           )
+          )
+          (i32.store
+           (i32.add
+            (local.get $10)
+            (local.get $5)
+           )
+           (local.get $5)
+          )
+          (if
+           (local.get $8)
+           (block
+            (local.set $12
+             (i32.load
+              (i32.const 196)
+             )
+            )
+            (local.set $4
+             (i32.add
+              (i32.shl
+               (local.tee $0
+                (i32.shr_u
+                 (local.get $8)
+                 (i32.const 3)
+                )
+               )
+               (i32.const 3)
+              )
+              (i32.const 216)
+             )
+            )
+            (if
+             (i32.and
+              (local.tee $3
+               (i32.load
+                (i32.const 176)
+               )
+              )
+              (local.tee $0
+               (i32.shl
+                (i32.const 1)
+                (local.get $0)
+               )
+              )
+             )
+             (if
+              (i32.lt_u
+               (local.tee $0
+                (i32.load
+                 (local.tee $3
+                  (i32.add
+                   (local.get $4)
+                   (i32.const 8)
+                  )
+                 )
+                )
+               )
+               (i32.load
+                (i32.const 192)
+               )
+              )
+              (call $_abort)
+              (block
+               (local.set $2
+                (local.get $3)
+               )
+               (local.set $1
+                (local.get $0)
+               )
+              )
+             )
+             (block
+              (i32.store
+               (i32.const 176)
+               (i32.or
+                (local.get $3)
+                (local.get $0)
+               )
+              )
+              (local.set $2
+               (i32.add
+                (local.get $4)
+                (i32.const 8)
+               )
+              )
+              (local.set $1
+               (local.get $4)
+              )
+             )
+            )
+            (i32.store
+             (local.get $2)
+             (local.get $12)
+            )
+            (i32.store offset=12
+             (local.get $1)
+             (local.get $12)
+            )
+            (i32.store offset=8
+             (local.get $12)
+             (local.get $1)
+            )
+            (i32.store offset=12
+             (local.get $12)
+             (local.get $4)
+            )
+           )
+          )
+          (i32.store
+           (i32.const 184)
+           (local.get $5)
+          )
+          (i32.store
+           (i32.const 196)
+           (local.get $10)
+          )
+          (return
+           (local.get $7)
+          )
+         )
+        )
+        (if
+         (local.tee $0
+          (i32.load
+           (i32.const 180)
+          )
+         )
+         (block
+          (local.set $2
+           (i32.and
+            (i32.shr_u
+             (local.tee $0
+              (i32.add
+               (i32.and
+                (local.get $0)
+                (i32.sub
+                 (i32.const 0)
+                 (local.get $0)
+                )
+               )
+               (i32.const -1)
+              )
+             )
+             (i32.const 12)
+            )
+            (i32.const 16)
+           )
+          )
+          (local.set $7
+           (i32.sub
+            (i32.and
+             (i32.load offset=4
+              (local.tee $0
+               (i32.load offset=480
+                (i32.shl
+                 (i32.add
+                  (i32.or
+                   (i32.or
+                    (i32.or
+                     (i32.or
+                      (local.tee $0
+                       (i32.and
+                        (i32.shr_u
+                         (local.tee $1
+                          (i32.shr_u
+                           (local.get $0)
+                           (local.get $2)
+                          )
+                         )
+                         (i32.const 5)
+                        )
+                        (i32.const 8)
+                       )
+                      )
+                      (local.get $2)
+                     )
+                     (local.tee $0
+                      (i32.and
+                       (i32.shr_u
+                        (local.tee $1
+                         (i32.shr_u
+                          (local.get $1)
+                          (local.get $0)
+                         )
+                        )
+                        (i32.const 2)
+                       )
+                       (i32.const 4)
+                      )
+                     )
+                    )
+                    (local.tee $0
+                     (i32.and
+                      (i32.shr_u
+                       (local.tee $1
+                        (i32.shr_u
+                         (local.get $1)
+                         (local.get $0)
+                        )
+                       )
+                       (i32.const 1)
+                      )
+                      (i32.const 2)
+                     )
+                    )
+                   )
+                   (local.tee $0
+                    (i32.and
+                     (i32.shr_u
+                      (local.tee $1
+                       (i32.shr_u
+                        (local.get $1)
+                        (local.get $0)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                     (i32.const 1)
+                    )
+                   )
+                  )
+                  (i32.shr_u
+                   (local.get $1)
+                   (local.get $0)
+                  )
+                 )
+                 (i32.const 2)
+                )
+               )
+              )
+             )
+             (i32.const -8)
+            )
+            (local.get $4)
+           )
+          )
+          (local.set $1
+           (local.get $0)
+          )
+          (local.set $2
+           (local.get $0)
+          )
+          (loop $while-in
+           (block $while-out
+            (if
+             (i32.eqz
+              (local.tee $0
+               (i32.load offset=16
+                (local.get $1)
+               )
+              )
+             )
+             (if
+              (i32.eqz
+               (local.tee $0
+                (i32.load offset=20
+                 (local.get $1)
+                )
+               )
+              )
+              (block
+               (local.set $10
+                (local.get $7)
+               )
+               (local.set $5
+                (local.get $2)
+               )
+               (br $while-out)
+              )
+             )
+            )
+            (local.set $10
+             (i32.lt_u
+              (local.tee $1
+               (i32.sub
+                (i32.and
+                 (i32.load offset=4
+                  (local.get $0)
+                 )
+                 (i32.const -8)
+                )
+                (local.get $4)
+               )
+              )
+              (local.get $7)
+             )
+            )
+            (local.set $7
+             (select
+              (local.get $1)
+              (local.get $7)
+              (local.get $10)
+             )
+            )
+            (local.set $1
+             (local.get $0)
+            )
+            (local.set $2
+             (select
+              (local.get $0)
+              (local.get $2)
+              (local.get $10)
+             )
+            )
+            (br $while-in)
+           )
+          )
+          (if
+           (i32.lt_u
+            (local.get $5)
+            (local.tee $12
+             (i32.load
+              (i32.const 192)
+             )
+            )
+           )
+           (call $_abort)
+          )
+          (if
+           (i32.ge_u
+            (local.get $5)
+            (local.tee $11
+             (i32.add
+              (local.get $5)
+              (local.get $4)
+             )
+            )
+           )
+           (call $_abort)
+          )
+          (local.set $8
+           (i32.load offset=24
+            (local.get $5)
+           )
+          )
+          (block $do-once4
+           (if
+            (i32.eq
+             (local.tee $0
+              (i32.load offset=12
+               (local.get $5)
+              )
+             )
+             (local.get $5)
+            )
+            (block
+             (if
+              (i32.eqz
+               (local.tee $1
+                (i32.load
+                 (local.tee $0
+                  (i32.add
+                   (local.get $5)
+                   (i32.const 20)
+                  )
+                 )
+                )
+               )
+              )
+              (if
+               (i32.eqz
+                (local.tee $1
+                 (i32.load
+                  (local.tee $0
+                   (i32.add
+                    (local.get $5)
+                    (i32.const 16)
+                   )
+                  )
+                 )
+                )
+               )
+               (block
+                (local.set $9
+                 (i32.const 0)
+                )
+                (br $do-once4)
+               )
+              )
+             )
+             (loop $while-in7
+              (if
+               (local.tee $2
+                (i32.load
+                 (local.tee $7
+                  (i32.add
+                   (local.get $1)
+                   (i32.const 20)
+                  )
+                 )
+                )
+               )
+               (block
+                (local.set $1
+                 (local.get $2)
+                )
+                (local.set $0
+                 (local.get $7)
+                )
+                (br $while-in7)
+               )
+              )
+              (if
+               (local.tee $2
+                (i32.load
+                 (local.tee $7
+                  (i32.add
+                   (local.get $1)
+                   (i32.const 16)
+                  )
+                 )
+                )
+               )
+               (block
+                (local.set $1
+                 (local.get $2)
+                )
+                (local.set $0
+                 (local.get $7)
+                )
+                (br $while-in7)
+               )
+              )
+             )
+             (if
+              (i32.lt_u
+               (local.get $0)
+               (local.get $12)
+              )
+              (call $_abort)
+              (block
+               (i32.store
+                (local.get $0)
+                (i32.const 0)
+               )
+               (local.set $9
+                (local.get $1)
+               )
+              )
+             )
+            )
+            (block
+             (if
+              (i32.lt_u
+               (local.tee $7
+                (i32.load offset=8
+                 (local.get $5)
+                )
+               )
+               (local.get $12)
+              )
+              (call $_abort)
+             )
+             (if
+              (i32.ne
+               (i32.load
+                (local.tee $2
+                 (i32.add
+                  (local.get $7)
+                  (i32.const 12)
+                 )
+                )
+               )
+               (local.get $5)
+              )
+              (call $_abort)
+             )
+             (if
+              (i32.eq
+               (i32.load
+                (local.tee $1
+                 (i32.add
+                  (local.get $0)
+                  (i32.const 8)
+                 )
+                )
+               )
+               (local.get $5)
+              )
+              (block
+               (i32.store
+                (local.get $2)
+                (local.get $0)
+               )
+               (i32.store
+                (local.get $1)
+                (local.get $7)
+               )
+               (local.set $9
+                (local.get $0)
+               )
+              )
+              (call $_abort)
+             )
+            )
+           )
+          )
+          (block $do-once8
+           (if
+            (local.get $8)
+            (block
+             (if
+              (i32.eq
+               (local.get $5)
+               (i32.load
+                (local.tee $0
+                 (i32.add
+                  (i32.shl
+                   (local.tee $1
+                    (i32.load offset=28
+                     (local.get $5)
+                    )
+                   )
+                   (i32.const 2)
+                  )
+                  (i32.const 480)
+                 )
+                )
+               )
+              )
+              (block
+               (i32.store
+                (local.get $0)
+                (local.get $9)
+               )
+               (if
+                (i32.eqz
+                 (local.get $9)
+                )
+                (block
+                 (i32.store
+                  (i32.const 180)
+                  (i32.and
+                   (i32.load
+                    (i32.const 180)
+                   )
+                   (i32.xor
+                    (i32.shl
+                     (i32.const 1)
+                     (local.get $1)
+                    )
+                    (i32.const -1)
+                   )
+                  )
+                 )
+                 (br $do-once8)
+                )
+               )
+              )
+              (block
+               (if
+                (i32.lt_u
+                 (local.get $8)
+                 (i32.load
+                  (i32.const 192)
+                 )
+                )
+                (call $_abort)
+               )
+               (if
+                (i32.eq
+                 (i32.load
+                  (local.tee $0
+                   (i32.add
+                    (local.get $8)
+                    (i32.const 16)
+                   )
+                  )
+                 )
+                 (local.get $5)
+                )
+                (i32.store
+                 (local.get $0)
+                 (local.get $9)
+                )
+                (i32.store offset=20
+                 (local.get $8)
+                 (local.get $9)
+                )
+               )
+               (br_if $do-once8
+                (i32.eqz
+                 (local.get $9)
+                )
+               )
+              )
+             )
+             (if
+              (i32.lt_u
+               (local.get $9)
+               (local.tee $0
+                (i32.load
+                 (i32.const 192)
+                )
+               )
+              )
+              (call $_abort)
+             )
+             (i32.store offset=24
+              (local.get $9)
+              (local.get $8)
+             )
+             (if
+              (local.tee $1
+               (i32.load offset=16
+                (local.get $5)
+               )
+              )
+              (if
+               (i32.lt_u
+                (local.get $1)
+                (local.get $0)
+               )
+               (call $_abort)
+               (block
+                (i32.store offset=16
+                 (local.get $9)
+                 (local.get $1)
+                )
+                (i32.store offset=24
+                 (local.get $1)
+                 (local.get $9)
+                )
+               )
+              )
+             )
+             (if
+              (local.tee $0
+               (i32.load offset=20
+                (local.get $5)
+               )
+              )
+              (if
+               (i32.lt_u
+                (local.get $0)
+                (i32.load
+                 (i32.const 192)
+                )
+               )
+               (call $_abort)
+               (block
+                (i32.store offset=20
+                 (local.get $9)
+                 (local.get $0)
+                )
+                (i32.store offset=24
+                 (local.get $0)
+                 (local.get $9)
+                )
+               )
+              )
+             )
+            )
+           )
+          )
+          (if
+           (i32.lt_u
+            (local.get $10)
+            (i32.const 16)
+           )
+           (block
+            (i32.store offset=4
+             (local.get $5)
+             (i32.or
+              (local.tee $0
+               (i32.add
+                (local.get $10)
+                (local.get $4)
+               )
+              )
+              (i32.const 3)
+             )
+            )
+            (i32.store
+             (local.tee $0
+              (i32.add
+               (i32.add
+                (local.get $5)
+                (local.get $0)
+               )
+               (i32.const 4)
+              )
+             )
+             (i32.or
+              (i32.load
+               (local.get $0)
+              )
+              (i32.const 1)
+             )
+            )
+           )
+           (block
+            (i32.store offset=4
+             (local.get $5)
+             (i32.or
+              (local.get $4)
+              (i32.const 3)
+             )
+            )
+            (i32.store offset=4
+             (local.get $11)
+             (i32.or
+              (local.get $10)
+              (i32.const 1)
+             )
+            )
+            (i32.store
+             (i32.add
+              (local.get $11)
+              (local.get $10)
+             )
+             (local.get $10)
+            )
+            (if
+             (local.tee $0
+              (i32.load
+               (i32.const 184)
+              )
+             )
+             (block
+              (local.set $4
+               (i32.load
+                (i32.const 196)
+               )
+              )
+              (local.set $2
+               (i32.add
+                (i32.shl
+                 (local.tee $0
+                  (i32.shr_u
+                   (local.get $0)
+                   (i32.const 3)
+                  )
+                 )
+                 (i32.const 3)
+                )
+                (i32.const 216)
+               )
+              )
+              (if
+               (i32.and
+                (local.tee $1
+                 (i32.load
+                  (i32.const 176)
+                 )
+                )
+                (local.tee $0
+                 (i32.shl
+                  (i32.const 1)
+                  (local.get $0)
+                 )
+                )
+               )
+               (if
+                (i32.lt_u
+                 (local.tee $0
+                  (i32.load
+                   (local.tee $1
+                    (i32.add
+                     (local.get $2)
+                     (i32.const 8)
+                    )
+                   )
+                  )
+                 )
+                 (i32.load
+                  (i32.const 192)
+                 )
+                )
+                (call $_abort)
+                (block
+                 (local.set $6
+                  (local.get $1)
+                 )
+                 (local.set $3
+                  (local.get $0)
+                 )
+                )
+               )
+               (block
+                (i32.store
+                 (i32.const 176)
+                 (i32.or
+                  (local.get $1)
+                  (local.get $0)
+                 )
+                )
+                (local.set $6
+                 (i32.add
+                  (local.get $2)
+                  (i32.const 8)
+                 )
+                )
+                (local.set $3
+                 (local.get $2)
+                )
+               )
+              )
+              (i32.store
+               (local.get $6)
+               (local.get $4)
+              )
+              (i32.store offset=12
+               (local.get $3)
+               (local.get $4)
+              )
+              (i32.store offset=8
+               (local.get $4)
+               (local.get $3)
+              )
+              (i32.store offset=12
+               (local.get $4)
+               (local.get $2)
+              )
+             )
+            )
+            (i32.store
+             (i32.const 184)
+             (local.get $10)
+            )
+            (i32.store
+             (i32.const 196)
+             (local.get $11)
+            )
+           )
+          )
+          (return
+           (i32.add
+            (local.get $5)
+            (i32.const 8)
+           )
+          )
+         )
+         (local.set $0
+          (local.get $4)
+         )
+        )
+       )
+       (local.set $0
+        (local.get $4)
+       )
+      )
+     )
+     (if
+      (i32.gt_u
+       (local.get $0)
+       (i32.const -65)
+      )
+      (local.set $0
+       (i32.const -1)
+      )
+      (block
+       (local.set $2
+        (i32.and
+         (local.tee $0
+          (i32.add
+           (local.get $0)
+           (i32.const 11)
+          )
+         )
+         (i32.const -8)
+        )
+       )
+       (if
+        (local.tee $18
+         (i32.load
+          (i32.const 180)
+         )
+        )
+        (block
+         (local.set $14
+          (if (result i32)
+           (local.tee $0
+            (i32.shr_u
+             (local.get $0)
+             (i32.const 8)
+            )
+           )
+           (if (result i32)
+            (i32.gt_u
+             (local.get $2)
+             (i32.const 16777215)
+            )
+            (i32.const 31)
+            (i32.or
+             (i32.and
+              (i32.shr_u
+               (local.get $2)
+               (i32.add
+                (local.tee $0
+                 (i32.add
+                  (i32.sub
+                   (i32.const 14)
+                   (i32.or
+                    (i32.or
+                     (local.tee $0
+                      (i32.and
+                       (i32.shr_u
+                        (i32.add
+                         (local.tee $1
+                          (i32.shl
+                           (local.get $0)
+                           (local.tee $3
+                            (i32.and
+                             (i32.shr_u
+                              (i32.add
+                               (local.get $0)
+                               (i32.const 1048320)
+                              )
+                              (i32.const 16)
+                             )
+                             (i32.const 8)
+                            )
+                           )
+                          )
+                         )
+                         (i32.const 520192)
+                        )
+                        (i32.const 16)
+                       )
+                       (i32.const 4)
+                      )
+                     )
+                     (local.get $3)
+                    )
+                    (local.tee $0
+                     (i32.and
+                      (i32.shr_u
+                       (i32.add
+                        (local.tee $1
+                         (i32.shl
+                          (local.get $1)
+                          (local.get $0)
+                         )
+                        )
+                        (i32.const 245760)
+                       )
+                       (i32.const 16)
+                      )
+                      (i32.const 2)
+                     )
+                    )
+                   )
+                  )
+                  (i32.shr_u
+                   (i32.shl
+                    (local.get $1)
+                    (local.get $0)
+                   )
+                   (i32.const 15)
+                  )
+                 )
+                )
+                (i32.const 7)
+               )
+              )
+              (i32.const 1)
+             )
+             (i32.shl
+              (local.get $0)
+              (i32.const 1)
+             )
+            )
+           )
+           (i32.const 0)
+          )
+         )
+         (local.set $3
+          (i32.sub
+           (i32.const 0)
+           (local.get $2)
+          )
+         )
+         (block $__rjto$3
+          (block $__rjti$3
+           (if
+            (local.tee $0
+             (i32.load offset=480
+              (i32.shl
+               (local.get $14)
+               (i32.const 2)
+              )
+             )
+            )
+            (block
+             (local.set $6
+              (i32.const 0)
+             )
+             (local.set $8
+              (i32.shl
+               (local.get $2)
+               (select
+                (i32.const 0)
+                (i32.sub
+                 (i32.const 25)
+                 (i32.shr_u
+                  (local.get $14)
+                  (i32.const 1)
+                 )
+                )
+                (i32.eq
+                 (local.get $14)
+                 (i32.const 31)
+                )
+               )
+              )
+             )
+             (local.set $1
+              (i32.const 0)
+             )
+             (loop $while-in14
+              (if
+               (i32.lt_u
+                (local.tee $4
+                 (i32.sub
+                  (local.tee $9
+                   (i32.and
+                    (i32.load offset=4
+                     (local.get $0)
+                    )
+                    (i32.const -8)
+                   )
+                  )
+                  (local.get $2)
+                 )
+                )
+                (local.get $3)
+               )
+               (if
+                (i32.eq
+                 (local.get $9)
+                 (local.get $2)
+                )
+                (block
+                 (local.set $1
+                  (local.get $4)
+                 )
+                 (local.set $3
+                  (local.get $0)
+                 )
+                 (br $__rjti$3)
+                )
+                (block
+                 (local.set $3
+                  (local.get $4)
+                 )
+                 (local.set $1
+                  (local.get $0)
+                 )
+                )
+               )
+              )
+              (local.set $0
+               (select
+                (local.get $6)
+                (local.tee $4
+                 (i32.load offset=20
+                  (local.get $0)
+                 )
+                )
+                (i32.or
+                 (i32.eqz
+                  (local.get $4)
+                 )
+                 (i32.eq
+                  (local.get $4)
+                  (local.tee $9
+                   (i32.load
+                    (i32.add
+                     (i32.add
+                      (local.get $0)
+                      (i32.const 16)
+                     )
+                     (i32.shl
+                      (i32.shr_u
+                       (local.get $8)
+                       (i32.const 31)
+                      )
+                      (i32.const 2)
+                     )
+                    )
+                   )
+                  )
+                 )
+                )
+               )
+              )
+              (local.set $4
+               (i32.shl
+                (local.get $8)
+                (i32.xor
+                 (local.tee $6
+                  (i32.eqz
+                   (local.get $9)
+                  )
+                 )
+                 (i32.const 1)
+                )
+               )
+              )
+              (if
+               (local.get $6)
+               (block
+                (local.set $4
+                 (local.get $0)
+                )
+                (local.set $0
+                 (local.get $1)
+                )
+               )
+               (block
+                (local.set $6
+                 (local.get $0)
+                )
+                (local.set $8
+                 (local.get $4)
+                )
+                (local.set $0
+                 (local.get $9)
+                )
+                (br $while-in14)
+               )
+              )
+             )
+            )
+            (block
+             (local.set $4
+              (i32.const 0)
+             )
+             (local.set $0
+              (i32.const 0)
+             )
+            )
+           )
+           (if
+            (i32.and
+             (i32.eqz
+              (local.get $4)
+             )
+             (i32.eqz
+              (local.get $0)
+             )
+            )
+            (block
+             (if
+              (i32.eqz
+               (local.tee $1
+                (i32.and
+                 (local.get $18)
+                 (i32.or
+                  (local.tee $1
+                   (i32.shl
+                    (i32.const 2)
+                    (local.get $14)
+                   )
+                  )
+                  (i32.sub
+                   (i32.const 0)
+                   (local.get $1)
+                  )
+                 )
+                )
+               )
+              )
+              (block
+               (local.set $0
+                (local.get $2)
+               )
+               (br $do-once)
+              )
+             )
+             (local.set $9
+              (i32.and
+               (i32.shr_u
+                (local.tee $1
+                 (i32.add
+                  (i32.and
+                   (local.get $1)
+                   (i32.sub
+                    (i32.const 0)
+                    (local.get $1)
+                   )
+                  )
+                  (i32.const -1)
+                 )
+                )
+                (i32.const 12)
+               )
+               (i32.const 16)
+              )
+             )
+             (local.set $4
+              (i32.load offset=480
+               (i32.shl
+                (i32.add
+                 (i32.or
+                  (i32.or
+                   (i32.or
+                    (i32.or
+                     (local.tee $1
+                      (i32.and
+                       (i32.shr_u
+                        (local.tee $4
+                         (i32.shr_u
+                          (local.get $1)
+                          (local.get $9)
+                         )
+                        )
+                        (i32.const 5)
+                       )
+                       (i32.const 8)
+                      )
+                     )
+                     (local.get $9)
+                    )
+                    (local.tee $1
+                     (i32.and
+                      (i32.shr_u
+                       (local.tee $4
+                        (i32.shr_u
+                         (local.get $4)
+                         (local.get $1)
+                        )
+                       )
+                       (i32.const 2)
+                      )
+                      (i32.const 4)
+                     )
+                    )
+                   )
+                   (local.tee $1
+                    (i32.and
+                     (i32.shr_u
+                      (local.tee $4
+                       (i32.shr_u
+                        (local.get $4)
+                        (local.get $1)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                     (i32.const 2)
+                    )
+                   )
+                  )
+                  (local.tee $1
+                   (i32.and
+                    (i32.shr_u
+                     (local.tee $4
+                      (i32.shr_u
+                       (local.get $4)
+                       (local.get $1)
+                      )
+                     )
+                     (i32.const 1)
+                    )
+                    (i32.const 1)
+                   )
+                  )
+                 )
+                 (i32.shr_u
+                  (local.get $4)
+                  (local.get $1)
+                 )
+                )
+                (i32.const 2)
+               )
+              )
+             )
+            )
+           )
+           (if
+            (local.get $4)
+            (block
+             (local.set $1
+              (local.get $3)
+             )
+             (local.set $3
+              (local.get $4)
+             )
+             (br $__rjti$3)
+            )
+            (local.set $4
+             (local.get $0)
+            )
+           )
+           (br $__rjto$3)
+          )
+          (loop $while-in16
+           (local.set $9
+            (i32.lt_u
+             (local.tee $4
+              (i32.sub
+               (i32.and
+                (i32.load offset=4
+                 (local.get $3)
+                )
+                (i32.const -8)
+               )
+               (local.get $2)
+              )
+             )
+             (local.get $1)
+            )
+           )
+           (local.set $1
+            (select
+             (local.get $4)
+             (local.get $1)
+             (local.get $9)
+            )
+           )
+           (local.set $0
+            (select
+             (local.get $3)
+             (local.get $0)
+             (local.get $9)
+            )
+           )
+           (if
+            (local.tee $4
+             (i32.load offset=16
+              (local.get $3)
+             )
+            )
+            (block
+             (local.set $3
+              (local.get $4)
+             )
+             (br $while-in16)
+            )
+           )
+           (br_if $while-in16
+            (local.tee $3
+             (i32.load offset=20
+              (local.get $3)
+             )
+            )
+           )
+           (local.set $3
+            (local.get $1)
+           )
+           (local.set $4
+            (local.get $0)
+           )
+          )
+         )
+         (if
+          (local.get $4)
+          (if
+           (i32.lt_u
+            (local.get $3)
+            (i32.sub
+             (i32.load
+              (i32.const 184)
+             )
+             (local.get $2)
+            )
+           )
+           (block
+            (if
+             (i32.lt_u
+              (local.get $4)
+              (local.tee $12
+               (i32.load
+                (i32.const 192)
+               )
+              )
+             )
+             (call $_abort)
+            )
+            (if
+             (i32.ge_u
+              (local.get $4)
+              (local.tee $6
+               (i32.add
+                (local.get $4)
+                (local.get $2)
+               )
+              )
+             )
+             (call $_abort)
+            )
+            (local.set $9
+             (i32.load offset=24
+              (local.get $4)
+             )
+            )
+            (block $do-once17
+             (if
+              (i32.eq
+               (local.tee $0
+                (i32.load offset=12
+                 (local.get $4)
+                )
+               )
+               (local.get $4)
+              )
+              (block
+               (if
+                (i32.eqz
+                 (local.tee $1
+                  (i32.load
+                   (local.tee $0
+                    (i32.add
+                     (local.get $4)
+                     (i32.const 20)
+                    )
+                   )
+                  )
+                 )
+                )
+                (if
+                 (i32.eqz
+                  (local.tee $1
+                   (i32.load
+                    (local.tee $0
+                     (i32.add
+                      (local.get $4)
+                      (i32.const 16)
+                     )
+                    )
+                   )
+                  )
+                 )
+                 (block
+                  (local.set $11
+                   (i32.const 0)
+                  )
+                  (br $do-once17)
+                 )
+                )
+               )
+               (loop $while-in20
+                (if
+                 (local.tee $7
+                  (i32.load
+                   (local.tee $10
+                    (i32.add
+                     (local.get $1)
+                     (i32.const 20)
+                    )
+                   )
+                  )
+                 )
+                 (block
+                  (local.set $1
+                   (local.get $7)
+                  )
+                  (local.set $0
+                   (local.get $10)
+                  )
+                  (br $while-in20)
+                 )
+                )
+                (if
+                 (local.tee $7
+                  (i32.load
+                   (local.tee $10
+                    (i32.add
+                     (local.get $1)
+                     (i32.const 16)
+                    )
+                   )
+                  )
+                 )
+                 (block
+                  (local.set $1
+                   (local.get $7)
+                  )
+                  (local.set $0
+                   (local.get $10)
+                  )
+                  (br $while-in20)
+                 )
+                )
+               )
+               (if
+                (i32.lt_u
+                 (local.get $0)
+                 (local.get $12)
+                )
+                (call $_abort)
+                (block
+                 (i32.store
+                  (local.get $0)
+                  (i32.const 0)
+                 )
+                 (local.set $11
+                  (local.get $1)
+                 )
+                )
+               )
+              )
+              (block
+               (if
+                (i32.lt_u
+                 (local.tee $10
+                  (i32.load offset=8
+                   (local.get $4)
+                  )
+                 )
+                 (local.get $12)
+                )
+                (call $_abort)
+               )
+               (if
+                (i32.ne
+                 (i32.load
+                  (local.tee $7
+                   (i32.add
+                    (local.get $10)
+                    (i32.const 12)
+                   )
+                  )
+                 )
+                 (local.get $4)
+                )
+                (call $_abort)
+               )
+               (if
+                (i32.eq
+                 (i32.load
+                  (local.tee $1
+                   (i32.add
+                    (local.get $0)
+                    (i32.const 8)
+                   )
+                  )
+                 )
+                 (local.get $4)
+                )
+                (block
+                 (i32.store
+                  (local.get $7)
+                  (local.get $0)
+                 )
+                 (i32.store
+                  (local.get $1)
+                  (local.get $10)
+                 )
+                 (local.set $11
+                  (local.get $0)
+                 )
+                )
+                (call $_abort)
+               )
+              )
+             )
+            )
+            (block $do-once21
+             (if
+              (local.get $9)
+              (block
+               (if
+                (i32.eq
+                 (local.get $4)
+                 (i32.load
+                  (local.tee $0
+                   (i32.add
+                    (i32.shl
+                     (local.tee $1
+                      (i32.load offset=28
+                       (local.get $4)
+                      )
+                     )
+                     (i32.const 2)
+                    )
+                    (i32.const 480)
+                   )
+                  )
+                 )
+                )
+                (block
+                 (i32.store
+                  (local.get $0)
+                  (local.get $11)
+                 )
+                 (if
+                  (i32.eqz
+                   (local.get $11)
+                  )
+                  (block
+                   (i32.store
+                    (i32.const 180)
+                    (i32.and
+                     (i32.load
+                      (i32.const 180)
+                     )
+                     (i32.xor
+                      (i32.shl
+                       (i32.const 1)
+                       (local.get $1)
+                      )
+                      (i32.const -1)
+                     )
+                    )
+                   )
+                   (br $do-once21)
+                  )
+                 )
+                )
+                (block
+                 (if
+                  (i32.lt_u
+                   (local.get $9)
+                   (i32.load
+                    (i32.const 192)
+                   )
+                  )
+                  (call $_abort)
+                 )
+                 (if
+                  (i32.eq
+                   (i32.load
+                    (local.tee $0
+                     (i32.add
+                      (local.get $9)
+                      (i32.const 16)
+                     )
+                    )
+                   )
+                   (local.get $4)
+                  )
+                  (i32.store
+                   (local.get $0)
+                   (local.get $11)
+                  )
+                  (i32.store offset=20
+                   (local.get $9)
+                   (local.get $11)
+                  )
+                 )
+                 (br_if $do-once21
+                  (i32.eqz
+                   (local.get $11)
+                  )
+                 )
+                )
+               )
+               (if
+                (i32.lt_u
+                 (local.get $11)
+                 (local.tee $0
+                  (i32.load
+                   (i32.const 192)
+                  )
+                 )
+                )
+                (call $_abort)
+               )
+               (i32.store offset=24
+                (local.get $11)
+                (local.get $9)
+               )
+               (if
+                (local.tee $1
+                 (i32.load offset=16
+                  (local.get $4)
+                 )
+                )
+                (if
+                 (i32.lt_u
+                  (local.get $1)
+                  (local.get $0)
+                 )
+                 (call $_abort)
+                 (block
+                  (i32.store offset=16
+                   (local.get $11)
+                   (local.get $1)
+                  )
+                  (i32.store offset=24
+                   (local.get $1)
+                   (local.get $11)
+                  )
+                 )
+                )
+               )
+               (if
+                (local.tee $0
+                 (i32.load offset=20
+                  (local.get $4)
+                 )
+                )
+                (if
+                 (i32.lt_u
+                  (local.get $0)
+                  (i32.load
+                   (i32.const 192)
+                  )
+                 )
+                 (call $_abort)
+                 (block
+                  (i32.store offset=20
+                   (local.get $11)
+                   (local.get $0)
+                  )
+                  (i32.store offset=24
+                   (local.get $0)
+                   (local.get $11)
+                  )
+                 )
+                )
+               )
+              )
+             )
+            )
+            (block $do-once25
+             (if
+              (i32.lt_u
+               (local.get $3)
+               (i32.const 16)
+              )
+              (block
+               (i32.store offset=4
+                (local.get $4)
+                (i32.or
+                 (local.tee $0
+                  (i32.add
+                   (local.get $3)
+                   (local.get $2)
+                  )
+                 )
+                 (i32.const 3)
+                )
+               )
+               (i32.store
+                (local.tee $0
+                 (i32.add
+                  (i32.add
+                   (local.get $4)
+                   (local.get $0)
+                  )
+                  (i32.const 4)
+                 )
+                )
+                (i32.or
+                 (i32.load
+                  (local.get $0)
+                 )
+                 (i32.const 1)
+                )
+               )
+              )
+              (block
+               (i32.store offset=4
+                (local.get $4)
+                (i32.or
+                 (local.get $2)
+                 (i32.const 3)
+                )
+               )
+               (i32.store offset=4
+                (local.get $6)
+                (i32.or
+                 (local.get $3)
+                 (i32.const 1)
+                )
+               )
+               (i32.store
+                (i32.add
+                 (local.get $6)
+                 (local.get $3)
+                )
+                (local.get $3)
+               )
+               (local.set $0
+                (i32.shr_u
+                 (local.get $3)
+                 (i32.const 3)
+                )
+               )
+               (if
+                (i32.lt_u
+                 (local.get $3)
+                 (i32.const 256)
+                )
+                (block
+                 (local.set $3
+                  (i32.add
+                   (i32.shl
+                    (local.get $0)
+                    (i32.const 3)
+                   )
+                   (i32.const 216)
+                  )
+                 )
+                 (if
+                  (i32.and
+                   (local.tee $1
+                    (i32.load
+                     (i32.const 176)
+                    )
+                   )
+                   (local.tee $0
+                    (i32.shl
+                     (i32.const 1)
+                     (local.get $0)
+                    )
+                   )
+                  )
+                  (if
+                   (i32.lt_u
+                    (local.tee $0
+                     (i32.load
+                      (local.tee $1
+                       (i32.add
+                        (local.get $3)
+                        (i32.const 8)
+                       )
+                      )
+                     )
+                    )
+                    (i32.load
+                     (i32.const 192)
+                    )
+                   )
+                   (call $_abort)
+                   (block
+                    (local.set $13
+                     (local.get $1)
+                    )
+                    (local.set $5
+                     (local.get $0)
+                    )
+                   )
+                  )
+                  (block
+                   (i32.store
+                    (i32.const 176)
+                    (i32.or
+                     (local.get $1)
+                     (local.get $0)
+                    )
+                   )
+                   (local.set $13
+                    (i32.add
+                     (local.get $3)
+                     (i32.const 8)
+                    )
+                   )
+                   (local.set $5
+                    (local.get $3)
+                   )
+                  )
+                 )
+                 (i32.store
+                  (local.get $13)
+                  (local.get $6)
+                 )
+                 (i32.store offset=12
+                  (local.get $5)
+                  (local.get $6)
+                 )
+                 (i32.store offset=8
+                  (local.get $6)
+                  (local.get $5)
+                 )
+                 (i32.store offset=12
+                  (local.get $6)
+                  (local.get $3)
+                 )
+                 (br $do-once25)
+                )
+               )
+               (local.set $2
+                (i32.add
+                 (i32.shl
+                  (local.tee $7
+                   (if (result i32)
+                    (local.tee $0
+                     (i32.shr_u
+                      (local.get $3)
+                      (i32.const 8)
+                     )
+                    )
+                    (if (result i32)
+                     (i32.gt_u
+                      (local.get $3)
+                      (i32.const 16777215)
+                     )
+                     (i32.const 31)
+                     (i32.or
+                      (i32.and
+                       (i32.shr_u
+                        (local.get $3)
+                        (i32.add
+                         (local.tee $0
+                          (i32.add
+                           (i32.sub
+                            (i32.const 14)
+                            (i32.or
+                             (i32.or
+                              (local.tee $0
+                               (i32.and
+                                (i32.shr_u
+                                 (i32.add
+                                  (local.tee $1
+                                   (i32.shl
+                                    (local.get $0)
+                                    (local.tee $2
+                                     (i32.and
+                                      (i32.shr_u
+                                       (i32.add
+                                        (local.get $0)
+                                        (i32.const 1048320)
+                                       )
+                                       (i32.const 16)
+                                      )
+                                      (i32.const 8)
+                                     )
+                                    )
+                                   )
+                                  )
+                                  (i32.const 520192)
+                                 )
+                                 (i32.const 16)
+                                )
+                                (i32.const 4)
+                               )
+                              )
+                              (local.get $2)
+                             )
+                             (local.tee $0
+                              (i32.and
+                               (i32.shr_u
+                                (i32.add
+                                 (local.tee $1
+                                  (i32.shl
+                                   (local.get $1)
+                                   (local.get $0)
+                                  )
+                                 )
+                                 (i32.const 245760)
+                                )
+                                (i32.const 16)
+                               )
+                               (i32.const 2)
+                              )
+                             )
+                            )
+                           )
+                           (i32.shr_u
+                            (i32.shl
+                             (local.get $1)
+                             (local.get $0)
+                            )
+                            (i32.const 15)
+                           )
+                          )
+                         )
+                         (i32.const 7)
+                        )
+                       )
+                       (i32.const 1)
+                      )
+                      (i32.shl
+                       (local.get $0)
+                       (i32.const 1)
+                      )
+                     )
+                    )
+                    (i32.const 0)
+                   )
+                  )
+                  (i32.const 2)
+                 )
+                 (i32.const 480)
+                )
+               )
+               (i32.store offset=28
+                (local.get $6)
+                (local.get $7)
+               )
+               (i32.store offset=4
+                (local.tee $0
+                 (i32.add
+                  (local.get $6)
+                  (i32.const 16)
+                 )
+                )
+                (i32.const 0)
+               )
+               (i32.store
+                (local.get $0)
+                (i32.const 0)
+               )
+               (if
+                (i32.eqz
+                 (i32.and
+                  (local.tee $1
+                   (i32.load
+                    (i32.const 180)
+                   )
+                  )
+                  (local.tee $0
+                   (i32.shl
+                    (i32.const 1)
+                    (local.get $7)
+                   )
+                  )
+                 )
+                )
+                (block
+                 (i32.store
+                  (i32.const 180)
+                  (i32.or
+                   (local.get $1)
+                   (local.get $0)
+                  )
+                 )
+                 (i32.store
+                  (local.get $2)
+                  (local.get $6)
+                 )
+                 (i32.store offset=24
+                  (local.get $6)
+                  (local.get $2)
+                 )
+                 (i32.store offset=12
+                  (local.get $6)
+                  (local.get $6)
+                 )
+                 (i32.store offset=8
+                  (local.get $6)
+                  (local.get $6)
+                 )
+                 (br $do-once25)
+                )
+               )
+               (local.set $7
+                (i32.shl
+                 (local.get $3)
+                 (select
+                  (i32.const 0)
+                  (i32.sub
+                   (i32.const 25)
+                   (i32.shr_u
+                    (local.get $7)
+                    (i32.const 1)
+                   )
+                  )
+                  (i32.eq
+                   (local.get $7)
+                   (i32.const 31)
+                  )
+                 )
+                )
+               )
+               (local.set $0
+                (i32.load
+                 (local.get $2)
+                )
+               )
+               (block $__rjto$1
+                (block $__rjti$1
+                 (loop $while-in28
+                  (br_if $__rjti$1
+                   (i32.eq
+                    (i32.and
+                     (i32.load offset=4
+                      (local.get $0)
+                     )
+                     (i32.const -8)
+                    )
+                    (local.get $3)
+                   )
+                  )
+                  (local.set $2
+                   (i32.shl
+                    (local.get $7)
+                    (i32.const 1)
+                   )
+                  )
+                  (if
+                   (local.tee $1
+                    (i32.load
+                     (local.tee $7
+                      (i32.add
+                       (i32.add
+                        (local.get $0)
+                        (i32.const 16)
+                       )
+                       (i32.shl
+                        (i32.shr_u
+                         (local.get $7)
+                         (i32.const 31)
+                        )
+                        (i32.const 2)
+                       )
+                      )
+                     )
+                    )
+                   )
+                   (block
+                    (local.set $7
+                     (local.get $2)
+                    )
+                    (local.set $0
+                     (local.get $1)
+                    )
+                    (br $while-in28)
+                   )
+                  )
+                 )
+                 (if
+                  (i32.lt_u
+                   (local.get $7)
+                   (i32.load
+                    (i32.const 192)
+                   )
+                  )
+                  (call $_abort)
+                  (block
+                   (i32.store
+                    (local.get $7)
+                    (local.get $6)
+                   )
+                   (i32.store offset=24
+                    (local.get $6)
+                    (local.get $0)
+                   )
+                   (i32.store offset=12
+                    (local.get $6)
+                    (local.get $6)
+                   )
+                   (i32.store offset=8
+                    (local.get $6)
+                    (local.get $6)
+                   )
+                   (br $do-once25)
+                  )
+                 )
+                 (br $__rjto$1)
+                )
+                (if
+                 (i32.and
+                  (i32.ge_u
+                   (local.tee $2
+                    (i32.load
+                     (local.tee $3
+                      (i32.add
+                       (local.get $0)
+                       (i32.const 8)
+                      )
+                     )
+                    )
+                   )
+                   (local.tee $1
+                    (i32.load
+                     (i32.const 192)
+                    )
+                   )
+                  )
+                  (i32.ge_u
+                   (local.get $0)
+                   (local.get $1)
+                  )
+                 )
+                 (block
+                  (i32.store offset=12
+                   (local.get $2)
+                   (local.get $6)
+                  )
+                  (i32.store
+                   (local.get $3)
+                   (local.get $6)
+                  )
+                  (i32.store offset=8
+                   (local.get $6)
+                   (local.get $2)
+                  )
+                  (i32.store offset=12
+                   (local.get $6)
+                   (local.get $0)
+                  )
+                  (i32.store offset=24
+                   (local.get $6)
+                   (i32.const 0)
+                  )
+                 )
+                 (call $_abort)
+                )
+               )
+              )
+             )
+            )
+            (return
+             (i32.add
+              (local.get $4)
+              (i32.const 8)
+             )
+            )
+           )
+           (local.set $0
+            (local.get $2)
+           )
+          )
+          (local.set $0
+           (local.get $2)
+          )
+         )
+        )
+        (local.set $0
+         (local.get $2)
+        )
+       )
+      )
+     )
+    )
+   )
+   (if
+    (i32.ge_u
+     (local.tee $1
+      (i32.load
+       (i32.const 184)
+      )
+     )
+     (local.get $0)
+    )
+    (block
+     (local.set $2
+      (i32.load
+       (i32.const 196)
+      )
+     )
+     (if
+      (i32.gt_u
+       (local.tee $3
+        (i32.sub
+         (local.get $1)
+         (local.get $0)
+        )
+       )
+       (i32.const 15)
+      )
+      (block
+       (i32.store
+        (i32.const 196)
+        (local.tee $1
+         (i32.add
+          (local.get $2)
+          (local.get $0)
+         )
+        )
+       )
+       (i32.store
+        (i32.const 184)
+        (local.get $3)
+       )
+       (i32.store offset=4
+        (local.get $1)
+        (i32.or
+         (local.get $3)
+         (i32.const 1)
+        )
+       )
+       (i32.store
+        (i32.add
+         (local.get $1)
+         (local.get $3)
+        )
+        (local.get $3)
+       )
+       (i32.store offset=4
+        (local.get $2)
+        (i32.or
+         (local.get $0)
+         (i32.const 3)
+        )
+       )
+      )
+      (block
+       (i32.store
+        (i32.const 184)
+        (i32.const 0)
+       )
+       (i32.store
+        (i32.const 196)
+        (i32.const 0)
+       )
+       (i32.store offset=4
+        (local.get $2)
+        (i32.or
+         (local.get $1)
+         (i32.const 3)
+        )
+       )
+       (i32.store
+        (local.tee $0
+         (i32.add
+          (i32.add
+           (local.get $2)
+           (local.get $1)
+          )
+          (i32.const 4)
+         )
+        )
+        (i32.or
+         (i32.load
+          (local.get $0)
+         )
+         (i32.const 1)
+        )
+       )
+      )
+     )
+     (return
+      (i32.add
+       (local.get $2)
+       (i32.const 8)
+      )
+     )
+    )
+   )
+   (br_if $folding-inner0
+    (i32.gt_u
+     (local.tee $1
+      (i32.load
+       (i32.const 188)
+      )
+     )
+     (local.get $0)
+    )
+   )
+   (if
+    (i32.eqz
+     (i32.load
+      (i32.const 648)
+     )
+    )
+    (if
+     (i32.and
+      (i32.add
+       (local.tee $1
+        (call $_sysconf
+         (i32.const 30)
+        )
+       )
+       (i32.const -1)
+      )
+      (local.get $1)
+     )
+     (call $_abort)
+     (block
+      (i32.store
+       (i32.const 656)
+       (local.get $1)
+      )
+      (i32.store
+       (i32.const 652)
+       (local.get $1)
+      )
+      (i32.store
+       (i32.const 660)
+       (i32.const -1)
+      )
+      (i32.store
+       (i32.const 664)
+       (i32.const -1)
+      )
+      (i32.store
+       (i32.const 668)
+       (i32.const 0)
+      )
+      (i32.store
+       (i32.const 620)
+       (i32.const 0)
+      )
+      (i32.store
+       (i32.const 648)
+       (i32.xor
+        (i32.and
+         (call $_time
+          (i32.const 0)
+         )
+         (i32.const -16)
+        )
+        (i32.const 1431655768)
+       )
+      )
+     )
+    )
+   )
+   (if
+    (i32.le_u
+     (local.tee $5
+      (i32.and
+       (local.tee $6
+        (i32.add
+         (local.tee $1
+          (i32.load
+           (i32.const 656)
+          )
+         )
+         (local.tee $8
+          (i32.add
+           (local.get $0)
+           (i32.const 47)
+          )
+         )
+        )
+       )
+       (local.tee $9
+        (i32.sub
+         (i32.const 0)
+         (local.get $1)
+        )
+       )
+      )
+     )
+     (local.get $0)
+    )
+    (return
+     (i32.const 0)
+    )
+   )
+   (if
+    (local.tee $2
+     (i32.load
+      (i32.const 616)
+     )
+    )
+    (if
+     (i32.or
+      (i32.le_u
+       (local.tee $1
+        (i32.add
+         (local.tee $3
+          (i32.load
+           (i32.const 608)
+          )
+         )
+         (local.get $5)
+        )
+       )
+       (local.get $3)
+      )
+      (i32.gt_u
+       (local.get $1)
+       (local.get $2)
+      )
+     )
+     (return
+      (i32.const 0)
+     )
+    )
+   )
+   (local.set $11
+    (i32.add
+     (local.get $0)
+     (i32.const 48)
+    )
+   )
+   (block $__rjto$13
+    (block $__rjti$13
+     (if
+      (i32.eqz
+       (i32.and
+        (i32.load
+         (i32.const 620)
+        )
+        (i32.const 4)
+       )
+      )
+      (block
+       (block $label$break$L279
+        (block $__rjti$5
+         (block $__rjti$4
+          (br_if $__rjti$4
+           (i32.eqz
+            (local.tee $4
+             (i32.load
+              (i32.const 200)
+             )
+            )
+           )
+          )
+          (local.set $1
+           (i32.const 624)
+          )
+          (loop $while-in34
+           (block $while-out33
+            (if
+             (i32.le_u
+              (local.tee $3
+               (i32.load
+                (local.get $1)
+               )
+              )
+              (local.get $4)
+             )
+             (if
+              (i32.gt_u
+               (i32.add
+                (local.get $3)
+                (i32.load
+                 (local.tee $2
+                  (i32.add
+                   (local.get $1)
+                   (i32.const 4)
+                  )
+                 )
+                )
+               )
+               (local.get $4)
+              )
+              (block
+               (local.set $4
+                (local.get $1)
+               )
+               (br $while-out33)
+              )
+             )
+            )
+            (br_if $while-in34
+             (local.tee $1
+              (i32.load offset=8
+               (local.get $1)
+              )
+             )
+            )
+            (br $__rjti$4)
+           )
+          )
+          (if
+           (i32.lt_u
+            (local.tee $3
+             (i32.and
+              (i32.sub
+               (local.get $6)
+               (i32.load
+                (i32.const 188)
+               )
+              )
+              (local.get $9)
+             )
+            )
+            (i32.const 2147483647)
+           )
+           (if
+            (i32.eq
+             (local.tee $1
+              (call $_sbrk
+               (local.get $3)
+              )
+             )
+             (i32.add
+              (i32.load
+               (local.get $4)
+              )
+              (i32.load
+               (local.get $2)
+              )
+             )
+            )
+            (br_if $__rjti$13
+             (i32.ne
+              (local.get $1)
+              (i32.const -1)
+             )
+            )
+            (block
+             (local.set $2
+              (local.get $1)
+             )
+             (br $__rjti$5)
+            )
+           )
+          )
+          (br $label$break$L279)
+         )
+         (if
+          (i32.ne
+           (local.tee $1
+            (call $_sbrk
+             (i32.const 0)
+            )
+           )
+           (i32.const -1)
+          )
+          (block
+           (local.set $3
+            (if (result i32)
+             (i32.and
+              (local.tee $2
+               (i32.add
+                (local.tee $4
+                 (i32.load
+                  (i32.const 652)
+                 )
+                )
+                (i32.const -1)
+               )
+              )
+              (local.tee $3
+               (local.get $1)
+              )
+             )
+             (i32.add
+              (i32.sub
+               (local.get $5)
+               (local.get $3)
+              )
+              (i32.and
+               (i32.add
+                (local.get $2)
+                (local.get $3)
+               )
+               (i32.sub
+                (i32.const 0)
+                (local.get $4)
+               )
+              )
+             )
+             (local.get $5)
+            )
+           )
+           (local.set $9
+            (i32.add
+             (local.tee $4
+              (i32.load
+               (i32.const 608)
+              )
+             )
+             (local.get $3)
+            )
+           )
+           (if
+            (i32.and
+             (i32.gt_u
+              (local.get $3)
+              (local.get $0)
+             )
+             (i32.lt_u
+              (local.get $3)
+              (i32.const 2147483647)
+             )
+            )
+            (block
+             (if
+              (local.tee $2
+               (i32.load
+                (i32.const 616)
+               )
+              )
+              (br_if $label$break$L279
+               (i32.or
+                (i32.le_u
+                 (local.get $9)
+                 (local.get $4)
+                )
+                (i32.gt_u
+                 (local.get $9)
+                 (local.get $2)
+                )
+               )
+              )
+             )
+             (br_if $__rjti$13
+              (i32.eq
+               (local.tee $2
+                (call $_sbrk
+                 (local.get $3)
+                )
+               )
+               (local.get $1)
+              )
+             )
+             (br $__rjti$5)
+            )
+           )
+          )
+         )
+         (br $label$break$L279)
+        )
+        (local.set $1
+         (local.get $3)
+        )
+        (local.set $4
+         (i32.sub
+          (i32.const 0)
+          (local.get $1)
+         )
+        )
+        (if
+         (i32.and
+          (i32.gt_u
+           (local.get $11)
+           (local.get $1)
+          )
+          (i32.and
+           (i32.lt_u
+            (local.get $1)
+            (i32.const 2147483647)
+           )
+           (i32.ne
+            (local.get $2)
+            (i32.const -1)
+           )
+          )
+         )
+         (if
+          (i32.lt_u
+           (local.tee $3
+            (i32.and
+             (i32.add
+              (i32.sub
+               (local.get $8)
+               (local.get $1)
+              )
+              (local.tee $3
+               (i32.load
+                (i32.const 656)
+               )
+              )
+             )
+             (i32.sub
+              (i32.const 0)
+              (local.get $3)
+             )
+            )
+           )
+           (i32.const 2147483647)
+          )
+          (if
+           (i32.eq
+            (call $_sbrk
+             (local.get $3)
+            )
+            (i32.const -1)
+           )
+           (block
+            (drop
+             (call $_sbrk
+              (local.get $4)
+             )
+            )
+            (br $label$break$L279)
+           )
+           (local.set $3
+            (i32.add
+             (local.get $3)
+             (local.get $1)
+            )
+           )
+          )
+          (local.set $3
+           (local.get $1)
+          )
+         )
+         (local.set $3
+          (local.get $1)
+         )
+        )
+        (if
+         (i32.ne
+          (local.get $2)
+          (i32.const -1)
+         )
+         (block
+          (local.set $1
+           (local.get $2)
+          )
+          (br $__rjti$13)
+         )
+        )
+       )
+       (i32.store
+        (i32.const 620)
+        (i32.or
+         (i32.load
+          (i32.const 620)
+         )
+         (i32.const 4)
+        )
+       )
+      )
+     )
+     (if
+      (i32.lt_u
+       (local.get $5)
+       (i32.const 2147483647)
+      )
+      (if
+       (i32.and
+        (i32.lt_u
+         (local.tee $1
+          (call $_sbrk
+           (local.get $5)
+          )
+         )
+         (local.tee $3
+          (call $_sbrk
+           (i32.const 0)
+          )
+         )
+        )
+        (i32.and
+         (i32.ne
+          (local.get $1)
+          (i32.const -1)
+         )
+         (i32.ne
+          (local.get $3)
+          (i32.const -1)
+         )
+        )
+       )
+       (br_if $__rjti$13
+        (i32.gt_u
+         (local.tee $3
+          (i32.sub
+           (local.get $3)
+           (local.get $1)
+          )
+         )
+         (i32.add
+          (local.get $0)
+          (i32.const 40)
+         )
+        )
+       )
+      )
+     )
+     (br $__rjto$13)
+    )
+    (i32.store
+     (i32.const 608)
+     (local.tee $2
+      (i32.add
+       (i32.load
+        (i32.const 608)
+       )
+       (local.get $3)
+      )
+     )
+    )
+    (if
+     (i32.gt_u
+      (local.get $2)
+      (i32.load
+       (i32.const 612)
+      )
+     )
+     (i32.store
+      (i32.const 612)
+      (local.get $2)
+     )
+    )
+    (block $do-once40
+     (if
+      (local.tee $6
+       (i32.load
+        (i32.const 200)
+       )
+      )
+      (block
+       (local.set $2
+        (i32.const 624)
+       )
+       (block $__rjto$10
+        (block $__rjti$10
+         (loop $while-in45
+          (br_if $__rjti$10
+           (i32.eq
+            (local.get $1)
+            (i32.add
+             (local.tee $11
+              (i32.load
+               (local.get $2)
+              )
+             )
+             (local.tee $5
+              (i32.load
+               (local.tee $4
+                (i32.add
+                 (local.get $2)
+                 (i32.const 4)
+                )
+               )
+              )
+             )
+            )
+           )
+          )
+          (br_if $while-in45
+           (local.tee $2
+            (i32.load offset=8
+             (local.get $2)
+            )
+           )
+          )
+         )
+         (br $__rjto$10)
+        )
+        (if
+         (i32.eqz
+          (i32.and
+           (i32.load offset=12
+            (local.get $2)
+           )
+           (i32.const 8)
+          )
+         )
+         (if
+          (i32.and
+           (i32.lt_u
+            (local.get $6)
+            (local.get $1)
+           )
+           (i32.ge_u
+            (local.get $6)
+            (local.get $11)
+           )
+          )
+          (block
+           (i32.store
+            (local.get $4)
+            (i32.add
+             (local.get $5)
+             (local.get $3)
+            )
+           )
+           (local.set $2
+            (i32.add
+             (local.get $6)
+             (local.tee $1
+              (select
+               (i32.and
+                (i32.sub
+                 (i32.const 0)
+                 (local.tee $1
+                  (i32.add
+                   (local.get $6)
+                   (i32.const 8)
+                  )
+                 )
+                )
+                (i32.const 7)
+               )
+               (i32.const 0)
+               (i32.and
+                (local.get $1)
+                (i32.const 7)
+               )
+              )
+             )
+            )
+           )
+           (local.set $1
+            (i32.add
+             (i32.sub
+              (local.get $3)
+              (local.get $1)
+             )
+             (i32.load
+              (i32.const 188)
+             )
+            )
+           )
+           (i32.store
+            (i32.const 200)
+            (local.get $2)
+           )
+           (i32.store
+            (i32.const 188)
+            (local.get $1)
+           )
+           (i32.store offset=4
+            (local.get $2)
+            (i32.or
+             (local.get $1)
+             (i32.const 1)
+            )
+           )
+           (i32.store offset=4
+            (i32.add
+             (local.get $2)
+             (local.get $1)
+            )
+            (i32.const 40)
+           )
+           (i32.store
+            (i32.const 204)
+            (i32.load
+             (i32.const 664)
+            )
+           )
+           (br $do-once40)
+          )
+         )
+        )
+       )
+       (if
+        (i32.lt_u
+         (local.get $1)
+         (local.tee $4
+          (i32.load
+           (i32.const 192)
+          )
+         )
+        )
+        (block
+         (i32.store
+          (i32.const 192)
+          (local.get $1)
+         )
+         (local.set $4
+          (local.get $1)
+         )
+        )
+       )
+       (local.set $11
+        (i32.add
+         (local.get $1)
+         (local.get $3)
+        )
+       )
+       (local.set $2
+        (i32.const 624)
+       )
+       (block $__rjto$11
+        (block $__rjti$11
+         (loop $while-in47
+          (if
+           (i32.eq
+            (i32.load
+             (local.get $2)
+            )
+            (local.get $11)
+           )
+           (block
+            (local.set $5
+             (local.get $2)
+            )
+            (br $__rjti$11)
+           )
+          )
+          (br_if $while-in47
+           (local.tee $2
+            (i32.load offset=8
+             (local.get $2)
+            )
+           )
+          )
+          (local.set $4
+           (i32.const 624)
+          )
+         )
+         (br $__rjto$11)
+        )
+        (if
+         (i32.and
+          (i32.load offset=12
+           (local.get $2)
+          )
+          (i32.const 8)
+         )
+         (local.set $4
+          (i32.const 624)
+         )
+         (block
+          (i32.store
+           (local.get $5)
+           (local.get $1)
+          )
+          (i32.store
+           (local.tee $2
+            (i32.add
+             (local.get $2)
+             (i32.const 4)
+            )
+           )
+           (i32.add
+            (i32.load
+             (local.get $2)
+            )
+            (local.get $3)
+           )
+          )
+          (local.set $8
+           (i32.add
+            (local.tee $9
+             (i32.add
+              (local.get $1)
+              (select
+               (i32.and
+                (i32.sub
+                 (i32.const 0)
+                 (local.tee $1
+                  (i32.add
+                   (local.get $1)
+                   (i32.const 8)
+                  )
+                 )
+                )
+                (i32.const 7)
+               )
+               (i32.const 0)
+               (i32.and
+                (local.get $1)
+                (i32.const 7)
+               )
+              )
+             )
+            )
+            (local.get $0)
+           )
+          )
+          (local.set $7
+           (i32.sub
+            (i32.sub
+             (local.tee $5
+              (i32.add
+               (local.get $11)
+               (select
+                (i32.and
+                 (i32.sub
+                  (i32.const 0)
+                  (local.tee $1
+                   (i32.add
+                    (local.get $11)
+                    (i32.const 8)
+                   )
+                  )
+                 )
+                 (i32.const 7)
+                )
+                (i32.const 0)
+                (i32.and
+                 (local.get $1)
+                 (i32.const 7)
+                )
+               )
+              )
+             )
+             (local.get $9)
+            )
+            (local.get $0)
+           )
+          )
+          (i32.store offset=4
+           (local.get $9)
+           (i32.or
+            (local.get $0)
+            (i32.const 3)
+           )
+          )
+          (block $do-once48
+           (if
+            (i32.eq
+             (local.get $5)
+             (local.get $6)
+            )
+            (block
+             (i32.store
+              (i32.const 188)
+              (local.tee $0
+               (i32.add
+                (i32.load
+                 (i32.const 188)
+                )
+                (local.get $7)
+               )
+              )
+             )
+             (i32.store
+              (i32.const 200)
+              (local.get $8)
+             )
+             (i32.store offset=4
+              (local.get $8)
+              (i32.or
+               (local.get $0)
+               (i32.const 1)
+              )
+             )
+            )
+            (block
+             (if
+              (i32.eq
+               (local.get $5)
+               (i32.load
+                (i32.const 196)
+               )
+              )
+              (block
+               (i32.store
+                (i32.const 184)
+                (local.tee $0
+                 (i32.add
+                  (i32.load
+                   (i32.const 184)
+                  )
+                  (local.get $7)
+                 )
+                )
+               )
+               (i32.store
+                (i32.const 196)
+                (local.get $8)
+               )
+               (i32.store offset=4
+                (local.get $8)
+                (i32.or
+                 (local.get $0)
+                 (i32.const 1)
+                )
+               )
+               (i32.store
+                (i32.add
+                 (local.get $8)
+                 (local.get $0)
+                )
+                (local.get $0)
+               )
+               (br $do-once48)
+              )
+             )
+             (i32.store
+              (local.tee $0
+               (i32.add
+                (local.tee $0
+                 (if (result i32)
+                  (i32.eq
+                   (i32.and
+                    (local.tee $0
+                     (i32.load offset=4
+                      (local.get $5)
+                     )
+                    )
+                    (i32.const 3)
+                   )
+                   (i32.const 1)
+                  )
+                  (block (result i32)
+                   (local.set $11
+                    (i32.and
+                     (local.get $0)
+                     (i32.const -8)
+                    )
+                   )
+                   (local.set $1
+                    (i32.shr_u
+                     (local.get $0)
+                     (i32.const 3)
+                    )
+                   )
+                   (block $label$break$L331
+                    (if
+                     (i32.lt_u
+                      (local.get $0)
+                      (i32.const 256)
+                     )
+                     (block
+                      (local.set $2
+                       (i32.load offset=12
+                        (local.get $5)
+                       )
+                      )
+                      (block $do-once51
+                       (if
+                        (i32.ne
+                         (local.tee $3
+                          (i32.load offset=8
+                           (local.get $5)
+                          )
+                         )
+                         (local.tee $0
+                          (i32.add
+                           (i32.shl
+                            (local.get $1)
+                            (i32.const 3)
+                           )
+                           (i32.const 216)
+                          )
+                         )
+                        )
+                        (block
+                         (if
+                          (i32.lt_u
+                           (local.get $3)
+                           (local.get $4)
+                          )
+                          (call $_abort)
+                         )
+                         (br_if $do-once51
+                          (i32.eq
+                           (i32.load offset=12
+                            (local.get $3)
+                           )
+                           (local.get $5)
+                          )
+                         )
+                         (call $_abort)
+                        )
+                       )
+                      )
+                      (if
+                       (i32.eq
+                        (local.get $2)
+                        (local.get $3)
+                       )
+                       (block
+                        (i32.store
+                         (i32.const 176)
+                         (i32.and
+                          (i32.load
+                           (i32.const 176)
+                          )
+                          (i32.xor
+                           (i32.shl
+                            (i32.const 1)
+                            (local.get $1)
+                           )
+                           (i32.const -1)
+                          )
+                         )
+                        )
+                        (br $label$break$L331)
+                       )
+                      )
+                      (block $do-once53
+                       (if
+                        (i32.eq
+                         (local.get $2)
+                         (local.get $0)
+                        )
+                        (local.set $15
+                         (i32.add
+                          (local.get $2)
+                          (i32.const 8)
+                         )
+                        )
+                        (block
+                         (if
+                          (i32.lt_u
+                           (local.get $2)
+                           (local.get $4)
+                          )
+                          (call $_abort)
+                         )
+                         (if
+                          (i32.eq
+                           (i32.load
+                            (local.tee $0
+                             (i32.add
+                              (local.get $2)
+                              (i32.const 8)
+                             )
+                            )
+                           )
+                           (local.get $5)
+                          )
+                          (block
+                           (local.set $15
+                            (local.get $0)
+                           )
+                           (br $do-once53)
+                          )
+                         )
+                         (call $_abort)
+                        )
+                       )
+                      )
+                      (i32.store offset=12
+                       (local.get $3)
+                       (local.get $2)
+                      )
+                      (i32.store
+                       (local.get $15)
+                       (local.get $3)
+                      )
+                     )
+                     (block
+                      (local.set $6
+                       (i32.load offset=24
+                        (local.get $5)
+                       )
+                      )
+                      (block $do-once55
+                       (if
+                        (i32.eq
+                         (local.tee $0
+                          (i32.load offset=12
+                           (local.get $5)
+                          )
+                         )
+                         (local.get $5)
+                        )
+                        (block
+                         (if
+                          (i32.eqz
+                           (local.tee $1
+                            (i32.load
+                             (local.tee $0
+                              (i32.add
+                               (local.tee $3
+                                (i32.add
+                                 (local.get $5)
+                                 (i32.const 16)
+                                )
+                               )
+                               (i32.const 4)
+                              )
+                             )
+                            )
+                           )
+                          )
+                          (if
+                           (local.tee $1
+                            (i32.load
+                             (local.get $3)
+                            )
+                           )
+                           (local.set $0
+                            (local.get $3)
+                           )
+                           (block
+                            (local.set $12
+                             (i32.const 0)
+                            )
+                            (br $do-once55)
+                           )
+                          )
+                         )
+                         (loop $while-in58
+                          (if
+                           (local.tee $3
+                            (i32.load
+                             (local.tee $2
+                              (i32.add
+                               (local.get $1)
+                               (i32.const 20)
+                              )
+                             )
+                            )
+                           )
+                           (block
+                            (local.set $1
+                             (local.get $3)
+                            )
+                            (local.set $0
+                             (local.get $2)
+                            )
+                            (br $while-in58)
+                           )
+                          )
+                          (if
+                           (local.tee $3
+                            (i32.load
+                             (local.tee $2
+                              (i32.add
+                               (local.get $1)
+                               (i32.const 16)
+                              )
+                             )
+                            )
+                           )
+                           (block
+                            (local.set $1
+                             (local.get $3)
+                            )
+                            (local.set $0
+                             (local.get $2)
+                            )
+                            (br $while-in58)
+                           )
+                          )
+                         )
+                         (if
+                          (i32.lt_u
+                           (local.get $0)
+                           (local.get $4)
+                          )
+                          (call $_abort)
+                          (block
+                           (i32.store
+                            (local.get $0)
+                            (i32.const 0)
+                           )
+                           (local.set $12
+                            (local.get $1)
+                           )
+                          )
+                         )
+                        )
+                        (block
+                         (if
+                          (i32.lt_u
+                           (local.tee $2
+                            (i32.load offset=8
+                             (local.get $5)
+                            )
+                           )
+                           (local.get $4)
+                          )
+                          (call $_abort)
+                         )
+                         (if
+                          (i32.ne
+                           (i32.load
+                            (local.tee $3
+                             (i32.add
+                              (local.get $2)
+                              (i32.const 12)
+                             )
+                            )
+                           )
+                           (local.get $5)
+                          )
+                          (call $_abort)
+                         )
+                         (if
+                          (i32.eq
+                           (i32.load
+                            (local.tee $1
+                             (i32.add
+                              (local.get $0)
+                              (i32.const 8)
+                             )
+                            )
+                           )
+                           (local.get $5)
+                          )
+                          (block
+                           (i32.store
+                            (local.get $3)
+                            (local.get $0)
+                           )
+                           (i32.store
+                            (local.get $1)
+                            (local.get $2)
+                           )
+                           (local.set $12
+                            (local.get $0)
+                           )
+                          )
+                          (call $_abort)
+                         )
+                        )
+                       )
+                      )
+                      (br_if $label$break$L331
+                       (i32.eqz
+                        (local.get $6)
+                       )
+                      )
+                      (block $do-once59
+                       (if
+                        (i32.eq
+                         (local.get $5)
+                         (i32.load
+                          (local.tee $0
+                           (i32.add
+                            (i32.shl
+                             (local.tee $1
+                              (i32.load offset=28
+                               (local.get $5)
+                              )
+                             )
+                             (i32.const 2)
+                            )
+                            (i32.const 480)
+                           )
+                          )
+                         )
+                        )
+                        (block
+                         (i32.store
+                          (local.get $0)
+                          (local.get $12)
+                         )
+                         (br_if $do-once59
+                          (local.get $12)
+                         )
+                         (i32.store
+                          (i32.const 180)
+                          (i32.and
+                           (i32.load
+                            (i32.const 180)
+                           )
+                           (i32.xor
+                            (i32.shl
+                             (i32.const 1)
+                             (local.get $1)
+                            )
+                            (i32.const -1)
+                           )
+                          )
+                         )
+                         (br $label$break$L331)
+                        )
+                        (block
+                         (if
+                          (i32.lt_u
+                           (local.get $6)
+                           (i32.load
+                            (i32.const 192)
+                           )
+                          )
+                          (call $_abort)
+                         )
+                         (if
+                          (i32.eq
+                           (i32.load
+                            (local.tee $0
+                             (i32.add
+                              (local.get $6)
+                              (i32.const 16)
+                             )
+                            )
+                           )
+                           (local.get $5)
+                          )
+                          (i32.store
+                           (local.get $0)
+                           (local.get $12)
+                          )
+                          (i32.store offset=20
+                           (local.get $6)
+                           (local.get $12)
+                          )
+                         )
+                         (br_if $label$break$L331
+                          (i32.eqz
+                           (local.get $12)
+                          )
+                         )
+                        )
+                       )
+                      )
+                      (if
+                       (i32.lt_u
+                        (local.get $12)
+                        (local.tee $1
+                         (i32.load
+                          (i32.const 192)
+                         )
+                        )
+                       )
+                       (call $_abort)
+                      )
+                      (i32.store offset=24
+                       (local.get $12)
+                       (local.get $6)
+                      )
+                      (if
+                       (local.tee $3
+                        (i32.load
+                         (local.tee $0
+                          (i32.add
+                           (local.get $5)
+                           (i32.const 16)
+                          )
+                         )
+                        )
+                       )
+                       (if
+                        (i32.lt_u
+                         (local.get $3)
+                         (local.get $1)
+                        )
+                        (call $_abort)
+                        (block
+                         (i32.store offset=16
+                          (local.get $12)
+                          (local.get $3)
+                         )
+                         (i32.store offset=24
+                          (local.get $3)
+                          (local.get $12)
+                         )
+                        )
+                       )
+                      )
+                      (br_if $label$break$L331
+                       (i32.eqz
+                        (local.tee $0
+                         (i32.load offset=4
+                          (local.get $0)
+                         )
+                        )
+                       )
+                      )
+                      (if
+                       (i32.lt_u
+                        (local.get $0)
+                        (i32.load
+                         (i32.const 192)
+                        )
+                       )
+                       (call $_abort)
+                       (block
+                        (i32.store offset=20
+                         (local.get $12)
+                         (local.get $0)
+                        )
+                        (i32.store offset=24
+                         (local.get $0)
+                         (local.get $12)
+                        )
+                       )
+                      )
+                     )
+                    )
+                   )
+                   (local.set $7
+                    (i32.add
+                     (local.get $11)
+                     (local.get $7)
+                    )
+                   )
+                   (i32.add
+                    (local.get $5)
+                    (local.get $11)
+                   )
+                  )
+                  (local.get $5)
+                 )
+                )
+                (i32.const 4)
+               )
+              )
+              (i32.and
+               (i32.load
+                (local.get $0)
+               )
+               (i32.const -2)
+              )
+             )
+             (i32.store offset=4
+              (local.get $8)
+              (i32.or
+               (local.get $7)
+               (i32.const 1)
+              )
+             )
+             (i32.store
+              (i32.add
+               (local.get $8)
+               (local.get $7)
+              )
+              (local.get $7)
+             )
+             (local.set $0
+              (i32.shr_u
+               (local.get $7)
+               (i32.const 3)
+              )
+             )
+             (if
+              (i32.lt_u
+               (local.get $7)
+               (i32.const 256)
+              )
+              (block
+               (local.set $3
+                (i32.add
+                 (i32.shl
+                  (local.get $0)
+                  (i32.const 3)
+                 )
+                 (i32.const 216)
+                )
+               )
+               (block $do-once63
+                (if
+                 (i32.and
+                  (local.tee $1
+                   (i32.load
+                    (i32.const 176)
+                   )
+                  )
+                  (local.tee $0
+                   (i32.shl
+                    (i32.const 1)
+                    (local.get $0)
+                   )
+                  )
+                 )
+                 (block
+                  (if
+                   (i32.ge_u
+                    (local.tee $0
+                     (i32.load
+                      (local.tee $1
+                       (i32.add
+                        (local.get $3)
+                        (i32.const 8)
+                       )
+                      )
+                     )
+                    )
+                    (i32.load
+                     (i32.const 192)
+                    )
+                   )
+                   (block
+                    (local.set $16
+                     (local.get $1)
+                    )
+                    (local.set $10
+                     (local.get $0)
+                    )
+                    (br $do-once63)
+                   )
+                  )
+                  (call $_abort)
+                 )
+                 (block
+                  (i32.store
+                   (i32.const 176)
+                   (i32.or
+                    (local.get $1)
+                    (local.get $0)
+                   )
+                  )
+                  (local.set $16
+                   (i32.add
+                    (local.get $3)
+                    (i32.const 8)
+                   )
+                  )
+                  (local.set $10
+                   (local.get $3)
+                  )
+                 )
+                )
+               )
+               (i32.store
+                (local.get $16)
+                (local.get $8)
+               )
+               (i32.store offset=12
+                (local.get $10)
+                (local.get $8)
+               )
+               (i32.store offset=8
+                (local.get $8)
+                (local.get $10)
+               )
+               (i32.store offset=12
+                (local.get $8)
+                (local.get $3)
+               )
+               (br $do-once48)
+              )
+             )
+             (local.set $3
+              (i32.add
+               (i32.shl
+                (local.tee $2
+                 (block $do-once65 (result i32)
+                  (if (result i32)
+                   (local.tee $0
+                    (i32.shr_u
+                     (local.get $7)
+                     (i32.const 8)
+                    )
+                   )
+                   (block (result i32)
+                    (drop
+                     (br_if $do-once65
+                      (i32.const 31)
+                      (i32.gt_u
+                       (local.get $7)
+                       (i32.const 16777215)
+                      )
+                     )
+                    )
+                    (i32.or
+                     (i32.and
+                      (i32.shr_u
+                       (local.get $7)
+                       (i32.add
+                        (local.tee $0
+                         (i32.add
+                          (i32.sub
+                           (i32.const 14)
+                           (i32.or
+                            (i32.or
+                             (local.tee $0
+                              (i32.and
+                               (i32.shr_u
+                                (i32.add
+                                 (local.tee $1
+                                  (i32.shl
+                                   (local.get $0)
+                                   (local.tee $3
+                                    (i32.and
+                                     (i32.shr_u
+                                      (i32.add
+                                       (local.get $0)
+                                       (i32.const 1048320)
+                                      )
+                                      (i32.const 16)
+                                     )
+                                     (i32.const 8)
+                                    )
+                                   )
+                                  )
+                                 )
+                                 (i32.const 520192)
+                                )
+                                (i32.const 16)
+                               )
+                               (i32.const 4)
+                              )
+                             )
+                             (local.get $3)
+                            )
+                            (local.tee $0
+                             (i32.and
+                              (i32.shr_u
+                               (i32.add
+                                (local.tee $1
+                                 (i32.shl
+                                  (local.get $1)
+                                  (local.get $0)
+                                 )
+                                )
+                                (i32.const 245760)
+                               )
+                               (i32.const 16)
+                              )
+                              (i32.const 2)
+                             )
+                            )
+                           )
+                          )
+                          (i32.shr_u
+                           (i32.shl
+                            (local.get $1)
+                            (local.get $0)
+                           )
+                           (i32.const 15)
+                          )
+                         )
+                        )
+                        (i32.const 7)
+                       )
+                      )
+                      (i32.const 1)
+                     )
+                     (i32.shl
+                      (local.get $0)
+                      (i32.const 1)
+                     )
+                    )
+                   )
+                   (i32.const 0)
+                  )
+                 )
+                )
+                (i32.const 2)
+               )
+               (i32.const 480)
+              )
+             )
+             (i32.store offset=28
+              (local.get $8)
+              (local.get $2)
+             )
+             (i32.store offset=4
+              (local.tee $0
+               (i32.add
+                (local.get $8)
+                (i32.const 16)
+               )
+              )
+              (i32.const 0)
+             )
+             (i32.store
+              (local.get $0)
+              (i32.const 0)
+             )
+             (if
+              (i32.eqz
+               (i32.and
+                (local.tee $1
+                 (i32.load
+                  (i32.const 180)
+                 )
+                )
+                (local.tee $0
+                 (i32.shl
+                  (i32.const 1)
+                  (local.get $2)
+                 )
+                )
+               )
+              )
+              (block
+               (i32.store
+                (i32.const 180)
+                (i32.or
+                 (local.get $1)
+                 (local.get $0)
+                )
+               )
+               (i32.store
+                (local.get $3)
+                (local.get $8)
+               )
+               (i32.store offset=24
+                (local.get $8)
+                (local.get $3)
+               )
+               (i32.store offset=12
+                (local.get $8)
+                (local.get $8)
+               )
+               (i32.store offset=8
+                (local.get $8)
+                (local.get $8)
+               )
+               (br $do-once48)
+              )
+             )
+             (local.set $2
+              (i32.shl
+               (local.get $7)
+               (select
+                (i32.const 0)
+                (i32.sub
+                 (i32.const 25)
+                 (i32.shr_u
+                  (local.get $2)
+                  (i32.const 1)
+                 )
+                )
+                (i32.eq
+                 (local.get $2)
+                 (i32.const 31)
+                )
+               )
+              )
+             )
+             (local.set $0
+              (i32.load
+               (local.get $3)
+              )
+             )
+             (block $__rjto$7
+              (block $__rjti$7
+               (loop $while-in68
+                (br_if $__rjti$7
+                 (i32.eq
+                  (i32.and
+                   (i32.load offset=4
+                    (local.get $0)
+                   )
+                   (i32.const -8)
+                  )
+                  (local.get $7)
+                 )
+                )
+                (local.set $3
+                 (i32.shl
+                  (local.get $2)
+                  (i32.const 1)
+                 )
+                )
+                (if
+                 (local.tee $1
+                  (i32.load
+                   (local.tee $2
+                    (i32.add
+                     (i32.add
+                      (local.get $0)
+                      (i32.const 16)
+                     )
+                     (i32.shl
+                      (i32.shr_u
+                       (local.get $2)
+                       (i32.const 31)
+                      )
+                      (i32.const 2)
+                     )
+                    )
+                   )
+                  )
+                 )
+                 (block
+                  (local.set $2
+                   (local.get $3)
+                  )
+                  (local.set $0
+                   (local.get $1)
+                  )
+                  (br $while-in68)
+                 )
+                )
+               )
+               (if
+                (i32.lt_u
+                 (local.get $2)
+                 (i32.load
+                  (i32.const 192)
+                 )
+                )
+                (call $_abort)
+                (block
+                 (i32.store
+                  (local.get $2)
+                  (local.get $8)
+                 )
+                 (i32.store offset=24
+                  (local.get $8)
+                  (local.get $0)
+                 )
+                 (i32.store offset=12
+                  (local.get $8)
+                  (local.get $8)
+                 )
+                 (i32.store offset=8
+                  (local.get $8)
+                  (local.get $8)
+                 )
+                 (br $do-once48)
+                )
+               )
+               (br $__rjto$7)
+              )
+              (if
+               (i32.and
+                (i32.ge_u
+                 (local.tee $2
+                  (i32.load
+                   (local.tee $3
+                    (i32.add
+                     (local.get $0)
+                     (i32.const 8)
+                    )
+                   )
+                  )
+                 )
+                 (local.tee $1
+                  (i32.load
+                   (i32.const 192)
+                  )
+                 )
+                )
+                (i32.ge_u
+                 (local.get $0)
+                 (local.get $1)
+                )
+               )
+               (block
+                (i32.store offset=12
+                 (local.get $2)
+                 (local.get $8)
+                )
+                (i32.store
+                 (local.get $3)
+                 (local.get $8)
+                )
+                (i32.store offset=8
+                 (local.get $8)
+                 (local.get $2)
+                )
+                (i32.store offset=12
+                 (local.get $8)
+                 (local.get $0)
+                )
+                (i32.store offset=24
+                 (local.get $8)
+                 (i32.const 0)
+                )
+               )
+               (call $_abort)
+              )
+             )
+            )
+           )
+          )
+          (return
+           (i32.add
+            (local.get $9)
+            (i32.const 8)
+           )
+          )
+         )
+        )
+       )
+       (loop $while-in70
+        (block $while-out69
+         (if
+          (i32.le_u
+           (local.tee $2
+            (i32.load
+             (local.get $4)
+            )
+           )
+           (local.get $6)
+          )
+          (br_if $while-out69
+           (i32.gt_u
+            (local.tee $2
+             (i32.add
+              (local.get $2)
+              (i32.load offset=4
+               (local.get $4)
+              )
+             )
+            )
+            (local.get $6)
+           )
+          )
+         )
+         (local.set $4
+          (i32.load offset=8
+           (local.get $4)
+          )
+         )
+         (br $while-in70)
+        )
+       )
+       (local.set $10
+        (i32.add
+         (local.tee $4
+          (i32.add
+           (local.get $2)
+           (i32.const -47)
+          )
+         )
+         (i32.const 8)
+        )
+       )
+       (local.set $12
+        (i32.add
+         (local.tee $11
+          (select
+           (local.get $6)
+           (local.tee $4
+            (i32.add
+             (local.get $4)
+             (select
+              (i32.and
+               (i32.sub
+                (i32.const 0)
+                (local.get $10)
+               )
+               (i32.const 7)
+              )
+              (i32.const 0)
+              (i32.and
+               (local.get $10)
+               (i32.const 7)
+              )
+             )
+            )
+           )
+           (i32.lt_u
+            (local.get $4)
+            (local.tee $10
+             (i32.add
+              (local.get $6)
+              (i32.const 16)
+             )
+            )
+           )
+          )
+         )
+         (i32.const 8)
+        )
+       )
+       (i32.store
+        (i32.const 200)
+        (local.tee $5
+         (i32.add
+          (local.get $1)
+          (local.tee $4
+           (select
+            (i32.and
+             (i32.sub
+              (i32.const 0)
+              (local.tee $4
+               (i32.add
+                (local.get $1)
+                (i32.const 8)
+               )
+              )
+             )
+             (i32.const 7)
+            )
+            (i32.const 0)
+            (i32.and
+             (local.get $4)
+             (i32.const 7)
+            )
+           )
+          )
+         )
+        )
+       )
+       (i32.store
+        (i32.const 188)
+        (local.tee $4
+         (i32.sub
+          (i32.add
+           (local.get $3)
+           (i32.const -40)
+          )
+          (local.get $4)
+         )
+        )
+       )
+       (i32.store offset=4
+        (local.get $5)
+        (i32.or
+         (local.get $4)
+         (i32.const 1)
+        )
+       )
+       (i32.store offset=4
+        (i32.add
+         (local.get $5)
+         (local.get $4)
+        )
+        (i32.const 40)
+       )
+       (i32.store
+        (i32.const 204)
+        (i32.load
+         (i32.const 664)
+        )
+       )
+       (i32.store
+        (local.tee $4
+         (i32.add
+          (local.get $11)
+          (i32.const 4)
+         )
+        )
+        (i32.const 27)
+       )
+       (i32.store
+        (local.get $12)
+        (i32.load
+         (i32.const 624)
+        )
+       )
+       (i32.store offset=4
+        (local.get $12)
+        (i32.load
+         (i32.const 628)
+        )
+       )
+       (i32.store offset=8
+        (local.get $12)
+        (i32.load
+         (i32.const 632)
+        )
+       )
+       (i32.store offset=12
+        (local.get $12)
+        (i32.load
+         (i32.const 636)
+        )
+       )
+       (i32.store
+        (i32.const 624)
+        (local.get $1)
+       )
+       (i32.store
+        (i32.const 628)
+        (local.get $3)
+       )
+       (i32.store
+        (i32.const 636)
+        (i32.const 0)
+       )
+       (i32.store
+        (i32.const 632)
+        (local.get $12)
+       )
+       (local.set $1
+        (i32.add
+         (local.get $11)
+         (i32.const 24)
+        )
+       )
+       (loop $while-in72
+        (i32.store
+         (local.tee $1
+          (i32.add
+           (local.get $1)
+           (i32.const 4)
+          )
+         )
+         (i32.const 7)
+        )
+        (br_if $while-in72
+         (i32.lt_u
+          (i32.add
+           (local.get $1)
+           (i32.const 4)
+          )
+          (local.get $2)
+         )
+        )
+       )
+       (if
+        (i32.ne
+         (local.get $11)
+         (local.get $6)
+        )
+        (block
+         (i32.store
+          (local.get $4)
+          (i32.and
+           (i32.load
+            (local.get $4)
+           )
+           (i32.const -2)
+          )
+         )
+         (i32.store offset=4
+          (local.get $6)
+          (i32.or
+           (local.tee $5
+            (i32.sub
+             (local.get $11)
+             (local.get $6)
+            )
+           )
+           (i32.const 1)
+          )
+         )
+         (i32.store
+          (local.get $11)
+          (local.get $5)
+         )
+         (local.set $1
+          (i32.shr_u
+           (local.get $5)
+           (i32.const 3)
+          )
+         )
+         (if
+          (i32.lt_u
+           (local.get $5)
+           (i32.const 256)
+          )
+          (block
+           (local.set $2
+            (i32.add
+             (i32.shl
+              (local.get $1)
+              (i32.const 3)
+             )
+             (i32.const 216)
+            )
+           )
+           (if
+            (i32.and
+             (local.tee $3
+              (i32.load
+               (i32.const 176)
+              )
+             )
+             (local.tee $1
+              (i32.shl
+               (i32.const 1)
+               (local.get $1)
+              )
+             )
+            )
+            (if
+             (i32.lt_u
+              (local.tee $1
+               (i32.load
+                (local.tee $3
+                 (i32.add
+                  (local.get $2)
+                  (i32.const 8)
+                 )
+                )
+               )
+              )
+              (i32.load
+               (i32.const 192)
+              )
+             )
+             (call $_abort)
+             (block
+              (local.set $17
+               (local.get $3)
+              )
+              (local.set $7
+               (local.get $1)
+              )
+             )
+            )
+            (block
+             (i32.store
+              (i32.const 176)
+              (i32.or
+               (local.get $3)
+               (local.get $1)
+              )
+             )
+             (local.set $17
+              (i32.add
+               (local.get $2)
+               (i32.const 8)
+              )
+             )
+             (local.set $7
+              (local.get $2)
+             )
+            )
+           )
+           (i32.store
+            (local.get $17)
+            (local.get $6)
+           )
+           (i32.store offset=12
+            (local.get $7)
+            (local.get $6)
+           )
+           (i32.store offset=8
+            (local.get $6)
+            (local.get $7)
+           )
+           (i32.store offset=12
+            (local.get $6)
+            (local.get $2)
+           )
+           (br $do-once40)
+          )
+         )
+         (local.set $2
+          (i32.add
+           (i32.shl
+            (local.tee $4
+             (if (result i32)
+              (local.tee $1
+               (i32.shr_u
+                (local.get $5)
+                (i32.const 8)
+               )
+              )
+              (if (result i32)
+               (i32.gt_u
+                (local.get $5)
+                (i32.const 16777215)
+               )
+               (i32.const 31)
+               (i32.or
+                (i32.and
+                 (i32.shr_u
+                  (local.get $5)
+                  (i32.add
+                   (local.tee $1
+                    (i32.add
+                     (i32.sub
+                      (i32.const 14)
+                      (i32.or
+                       (i32.or
+                        (local.tee $1
+                         (i32.and
+                          (i32.shr_u
+                           (i32.add
+                            (local.tee $3
+                             (i32.shl
+                              (local.get $1)
+                              (local.tee $2
+                               (i32.and
+                                (i32.shr_u
+                                 (i32.add
+                                  (local.get $1)
+                                  (i32.const 1048320)
+                                 )
+                                 (i32.const 16)
+                                )
+                                (i32.const 8)
+                               )
+                              )
+                             )
+                            )
+                            (i32.const 520192)
+                           )
+                           (i32.const 16)
+                          )
+                          (i32.const 4)
+                         )
+                        )
+                        (local.get $2)
+                       )
+                       (local.tee $1
+                        (i32.and
+                         (i32.shr_u
+                          (i32.add
+                           (local.tee $3
+                            (i32.shl
+                             (local.get $3)
+                             (local.get $1)
+                            )
+                           )
+                           (i32.const 245760)
+                          )
+                          (i32.const 16)
+                         )
+                         (i32.const 2)
+                        )
+                       )
+                      )
+                     )
+                     (i32.shr_u
+                      (i32.shl
+                       (local.get $3)
+                       (local.get $1)
+                      )
+                      (i32.const 15)
+                     )
+                    )
+                   )
+                   (i32.const 7)
+                  )
+                 )
+                 (i32.const 1)
+                )
+                (i32.shl
+                 (local.get $1)
+                 (i32.const 1)
+                )
+               )
+              )
+              (i32.const 0)
+             )
+            )
+            (i32.const 2)
+           )
+           (i32.const 480)
+          )
+         )
+         (i32.store offset=28
+          (local.get $6)
+          (local.get $4)
+         )
+         (i32.store offset=20
+          (local.get $6)
+          (i32.const 0)
+         )
+         (i32.store
+          (local.get $10)
+          (i32.const 0)
+         )
+         (if
+          (i32.eqz
+           (i32.and
+            (local.tee $3
+             (i32.load
+              (i32.const 180)
+             )
+            )
+            (local.tee $1
+             (i32.shl
+              (i32.const 1)
+              (local.get $4)
+             )
+            )
+           )
+          )
+          (block
+           (i32.store
+            (i32.const 180)
+            (i32.or
+             (local.get $3)
+             (local.get $1)
+            )
+           )
+           (i32.store
+            (local.get $2)
+            (local.get $6)
+           )
+           (i32.store offset=24
+            (local.get $6)
+            (local.get $2)
+           )
+           (i32.store offset=12
+            (local.get $6)
+            (local.get $6)
+           )
+           (i32.store offset=8
+            (local.get $6)
+            (local.get $6)
+           )
+           (br $do-once40)
+          )
+         )
+         (local.set $4
+          (i32.shl
+           (local.get $5)
+           (select
+            (i32.const 0)
+            (i32.sub
+             (i32.const 25)
+             (i32.shr_u
+              (local.get $4)
+              (i32.const 1)
+             )
+            )
+            (i32.eq
+             (local.get $4)
+             (i32.const 31)
+            )
+           )
+          )
+         )
+         (local.set $1
+          (i32.load
+           (local.get $2)
+          )
+         )
+         (block $__rjto$9
+          (block $__rjti$9
+           (loop $while-in74
+            (br_if $__rjti$9
+             (i32.eq
+              (i32.and
+               (i32.load offset=4
+                (local.get $1)
+               )
+               (i32.const -8)
+              )
+              (local.get $5)
+             )
+            )
+            (local.set $2
+             (i32.shl
+              (local.get $4)
+              (i32.const 1)
+             )
+            )
+            (if
+             (local.tee $3
+              (i32.load
+               (local.tee $4
+                (i32.add
+                 (i32.add
+                  (local.get $1)
+                  (i32.const 16)
+                 )
+                 (i32.shl
+                  (i32.shr_u
+                   (local.get $4)
+                   (i32.const 31)
+                  )
+                  (i32.const 2)
+                 )
+                )
+               )
+              )
+             )
+             (block
+              (local.set $4
+               (local.get $2)
+              )
+              (local.set $1
+               (local.get $3)
+              )
+              (br $while-in74)
+             )
+            )
+           )
+           (if
+            (i32.lt_u
+             (local.get $4)
+             (i32.load
+              (i32.const 192)
+             )
+            )
+            (call $_abort)
+            (block
+             (i32.store
+              (local.get $4)
+              (local.get $6)
+             )
+             (i32.store offset=24
+              (local.get $6)
+              (local.get $1)
+             )
+             (i32.store offset=12
+              (local.get $6)
+              (local.get $6)
+             )
+             (i32.store offset=8
+              (local.get $6)
+              (local.get $6)
+             )
+             (br $do-once40)
+            )
+           )
+           (br $__rjto$9)
+          )
+          (if
+           (i32.and
+            (i32.ge_u
+             (local.tee $4
+              (i32.load
+               (local.tee $2
+                (i32.add
+                 (local.get $1)
+                 (i32.const 8)
+                )
+               )
+              )
+             )
+             (local.tee $3
+              (i32.load
+               (i32.const 192)
+              )
+             )
+            )
+            (i32.ge_u
+             (local.get $1)
+             (local.get $3)
+            )
+           )
+           (block
+            (i32.store offset=12
+             (local.get $4)
+             (local.get $6)
+            )
+            (i32.store
+             (local.get $2)
+             (local.get $6)
+            )
+            (i32.store offset=8
+             (local.get $6)
+             (local.get $4)
+            )
+            (i32.store offset=12
+             (local.get $6)
+             (local.get $1)
+            )
+            (i32.store offset=24
+             (local.get $6)
+             (i32.const 0)
+            )
+           )
+           (call $_abort)
+          )
+         )
+        )
+       )
+      )
+      (block
+       (if
+        (i32.or
+         (i32.eqz
+          (local.tee $2
+           (i32.load
+            (i32.const 192)
+           )
+          )
+         )
+         (i32.lt_u
+          (local.get $1)
+          (local.get $2)
+         )
+        )
+        (i32.store
+         (i32.const 192)
+         (local.get $1)
+        )
+       )
+       (i32.store
+        (i32.const 624)
+        (local.get $1)
+       )
+       (i32.store
+        (i32.const 628)
+        (local.get $3)
+       )
+       (i32.store
+        (i32.const 636)
+        (i32.const 0)
+       )
+       (i32.store
+        (i32.const 212)
+        (i32.load
+         (i32.const 648)
+        )
+       )
+       (i32.store
+        (i32.const 208)
+        (i32.const -1)
+       )
+       (local.set $2
+        (i32.const 0)
+       )
+       (loop $while-in43
+        (i32.store offset=12
+         (local.tee $4
+          (i32.add
+           (i32.shl
+            (local.get $2)
+            (i32.const 3)
+           )
+           (i32.const 216)
+          )
+         )
+         (local.get $4)
+        )
+        (i32.store offset=8
+         (local.get $4)
+         (local.get $4)
+        )
+        (br_if $while-in43
+         (i32.ne
+          (local.tee $2
+           (i32.add
+            (local.get $2)
+            (i32.const 1)
+           )
+          )
+          (i32.const 32)
+         )
+        )
+       )
+       (i32.store
+        (i32.const 200)
+        (local.tee $2
+         (i32.add
+          (local.get $1)
+          (local.tee $1
+           (select
+            (i32.and
+             (i32.sub
+              (i32.const 0)
+              (local.tee $1
+               (i32.add
+                (local.get $1)
+                (i32.const 8)
+               )
+              )
+             )
+             (i32.const 7)
+            )
+            (i32.const 0)
+            (i32.and
+             (local.get $1)
+             (i32.const 7)
+            )
+           )
+          )
+         )
+        )
+       )
+       (i32.store
+        (i32.const 188)
+        (local.tee $1
+         (i32.sub
+          (i32.add
+           (local.get $3)
+           (i32.const -40)
+          )
+          (local.get $1)
+         )
+        )
+       )
+       (i32.store offset=4
+        (local.get $2)
+        (i32.or
+         (local.get $1)
+         (i32.const 1)
+        )
+       )
+       (i32.store offset=4
+        (i32.add
+         (local.get $2)
+         (local.get $1)
+        )
+        (i32.const 40)
+       )
+       (i32.store
+        (i32.const 204)
+        (i32.load
+         (i32.const 664)
+        )
+       )
+      )
+     )
+    )
+    (br_if $folding-inner0
+     (i32.gt_u
+      (local.tee $1
+       (i32.load
+        (i32.const 188)
+       )
+      )
+      (local.get $0)
+     )
+    )
+   )
+   (i32.store
+    (call $___errno_location)
+    (i32.const 12)
+   )
+   (return
+    (i32.const 0)
+   )
+  )
+  (i32.store
+   (i32.const 188)
+   (local.tee $3
+    (i32.sub
+     (local.get $1)
+     (local.get $0)
+    )
+   )
+  )
+  (i32.store
+   (i32.const 200)
+   (local.tee $1
+    (i32.add
+     (local.tee $2
+      (i32.load
+       (i32.const 200)
+      )
+     )
+     (local.get $0)
+    )
+   )
+  )
+  (i32.store offset=4
+   (local.get $1)
+   (i32.or
+    (local.get $3)
+    (i32.const 1)
+   )
+  )
+  (i32.store offset=4
+   (local.get $2)
+   (i32.or
+    (local.get $0)
+    (i32.const 3)
+   )
+  )
+  (i32.add
+   (local.get $2)
+   (i32.const 8)
+  )
+ )
+ (func $_free (param $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (if
+   (i32.eqz
+    (local.get $0)
+   )
+   (return)
+  )
+  (if
+   (i32.lt_u
+    (local.tee $1
+     (i32.add
+      (local.get $0)
+      (i32.const -8)
+     )
+    )
+    (local.tee $11
+     (i32.load
+      (i32.const 192)
+     )
+    )
+   )
+   (call $_abort)
+  )
+  (if
+   (i32.eq
+    (local.tee $5
+     (i32.and
+      (local.tee $7
+       (i32.load
+        (i32.add
+         (local.get $0)
+         (i32.const -4)
+        )
+       )
+      )
+      (i32.const 3)
+     )
+    )
+    (i32.const 1)
+   )
+   (call $_abort)
+  )
+  (local.set $8
+   (i32.add
+    (local.get $1)
+    (local.tee $0
+     (i32.and
+      (local.get $7)
+      (i32.const -8)
+     )
+    )
+   )
+  )
+  (block $do-once
+   (if
+    (i32.and
+     (local.get $7)
+     (i32.const 1)
+    )
+    (block
+     (local.set $2
+      (local.get $1)
+     )
+     (local.set $3
+      (local.get $0)
+     )
+    )
+    (block
+     (local.set $7
+      (i32.load
+       (local.get $1)
+      )
+     )
+     (if
+      (i32.eqz
+       (local.get $5)
+      )
+      (return)
+     )
+     (if
+      (i32.lt_u
+       (local.tee $1
+        (i32.add
+         (local.get $1)
+         (i32.sub
+          (i32.const 0)
+          (local.get $7)
+         )
+        )
+       )
+       (local.get $11)
+      )
+      (call $_abort)
+     )
+     (local.set $0
+      (i32.add
+       (local.get $7)
+       (local.get $0)
+      )
+     )
+     (if
+      (i32.eq
+       (local.get $1)
+       (i32.load
+        (i32.const 196)
+       )
+      )
+      (block
+       (if
+        (i32.ne
+         (i32.and
+          (local.tee $3
+           (i32.load
+            (local.tee $2
+             (i32.add
+              (local.get $8)
+              (i32.const 4)
+             )
+            )
+           )
+          )
+          (i32.const 3)
+         )
+         (i32.const 3)
+        )
+        (block
+         (local.set $2
+          (local.get $1)
+         )
+         (local.set $3
+          (local.get $0)
+         )
+         (br $do-once)
+        )
+       )
+       (i32.store
+        (i32.const 184)
+        (local.get $0)
+       )
+       (i32.store
+        (local.get $2)
+        (i32.and
+         (local.get $3)
+         (i32.const -2)
+        )
+       )
+       (i32.store offset=4
+        (local.get $1)
+        (i32.or
+         (local.get $0)
+         (i32.const 1)
+        )
+       )
+       (i32.store
+        (i32.add
+         (local.get $1)
+         (local.get $0)
+        )
+        (local.get $0)
+       )
+       (return)
+      )
+     )
+     (local.set $5
+      (i32.shr_u
+       (local.get $7)
+       (i32.const 3)
+      )
+     )
+     (if
+      (i32.lt_u
+       (local.get $7)
+       (i32.const 256)
+      )
+      (block
+       (local.set $6
+        (i32.load offset=12
+         (local.get $1)
+        )
+       )
+       (if
+        (i32.ne
+         (local.tee $2
+          (i32.load offset=8
+           (local.get $1)
+          )
+         )
+         (local.tee $3
+          (i32.add
+           (i32.shl
+            (local.get $5)
+            (i32.const 3)
+           )
+           (i32.const 216)
+          )
+         )
+        )
+        (block
+         (if
+          (i32.lt_u
+           (local.get $2)
+           (local.get $11)
+          )
+          (call $_abort)
+         )
+         (if
+          (i32.ne
+           (i32.load offset=12
+            (local.get $2)
+           )
+           (local.get $1)
+          )
+          (call $_abort)
+         )
+        )
+       )
+       (if
+        (i32.eq
+         (local.get $6)
+         (local.get $2)
+        )
+        (block
+         (i32.store
+          (i32.const 176)
+          (i32.and
+           (i32.load
+            (i32.const 176)
+           )
+           (i32.xor
+            (i32.shl
+             (i32.const 1)
+             (local.get $5)
+            )
+            (i32.const -1)
+           )
+          )
+         )
+         (local.set $2
+          (local.get $1)
+         )
+         (local.set $3
+          (local.get $0)
+         )
+         (br $do-once)
+        )
+       )
+       (if
+        (i32.eq
+         (local.get $6)
+         (local.get $3)
+        )
+        (local.set $4
+         (i32.add
+          (local.get $6)
+          (i32.const 8)
+         )
+        )
+        (block
+         (if
+          (i32.lt_u
+           (local.get $6)
+           (local.get $11)
+          )
+          (call $_abort)
+         )
+         (if
+          (i32.eq
+           (i32.load
+            (local.tee $3
+             (i32.add
+              (local.get $6)
+              (i32.const 8)
+             )
+            )
+           )
+           (local.get $1)
+          )
+          (local.set $4
+           (local.get $3)
+          )
+          (call $_abort)
+         )
+        )
+       )
+       (i32.store offset=12
+        (local.get $2)
+        (local.get $6)
+       )
+       (i32.store
+        (local.get $4)
+        (local.get $2)
+       )
+       (local.set $2
+        (local.get $1)
+       )
+       (local.set $3
+        (local.get $0)
+       )
+       (br $do-once)
+      )
+     )
+     (local.set $12
+      (i32.load offset=24
+       (local.get $1)
+      )
+     )
+     (block $do-once0
+      (if
+       (i32.eq
+        (local.tee $4
+         (i32.load offset=12
+          (local.get $1)
+         )
+        )
+        (local.get $1)
+       )
+       (block
+        (if
+         (i32.eqz
+          (local.tee $5
+           (i32.load
+            (local.tee $4
+             (i32.add
+              (local.tee $7
+               (i32.add
+                (local.get $1)
+                (i32.const 16)
+               )
+              )
+              (i32.const 4)
+             )
+            )
+           )
+          )
+         )
+         (if
+          (local.tee $5
+           (i32.load
+            (local.get $7)
+           )
+          )
+          (local.set $4
+           (local.get $7)
+          )
+          (block
+           (local.set $6
+            (i32.const 0)
+           )
+           (br $do-once0)
+          )
+         )
+        )
+        (loop $while-in
+         (if
+          (local.tee $7
+           (i32.load
+            (local.tee $10
+             (i32.add
+              (local.get $5)
+              (i32.const 20)
+             )
+            )
+           )
+          )
+          (block
+           (local.set $5
+            (local.get $7)
+           )
+           (local.set $4
+            (local.get $10)
+           )
+           (br $while-in)
+          )
+         )
+         (if
+          (local.tee $7
+           (i32.load
+            (local.tee $10
+             (i32.add
+              (local.get $5)
+              (i32.const 16)
+             )
+            )
+           )
+          )
+          (block
+           (local.set $5
+            (local.get $7)
+           )
+           (local.set $4
+            (local.get $10)
+           )
+           (br $while-in)
+          )
+         )
+        )
+        (if
+         (i32.lt_u
+          (local.get $4)
+          (local.get $11)
+         )
+         (call $_abort)
+         (block
+          (i32.store
+           (local.get $4)
+           (i32.const 0)
+          )
+          (local.set $6
+           (local.get $5)
+          )
+         )
+        )
+       )
+       (block
+        (if
+         (i32.lt_u
+          (local.tee $10
+           (i32.load offset=8
+            (local.get $1)
+           )
+          )
+          (local.get $11)
+         )
+         (call $_abort)
+        )
+        (if
+         (i32.ne
+          (i32.load
+           (local.tee $7
+            (i32.add
+             (local.get $10)
+             (i32.const 12)
+            )
+           )
+          )
+          (local.get $1)
+         )
+         (call $_abort)
+        )
+        (if
+         (i32.eq
+          (i32.load
+           (local.tee $5
+            (i32.add
+             (local.get $4)
+             (i32.const 8)
+            )
+           )
+          )
+          (local.get $1)
+         )
+         (block
+          (i32.store
+           (local.get $7)
+           (local.get $4)
+          )
+          (i32.store
+           (local.get $5)
+           (local.get $10)
+          )
+          (local.set $6
+           (local.get $4)
+          )
+         )
+         (call $_abort)
+        )
+       )
+      )
+     )
+     (if
+      (local.get $12)
+      (block
+       (if
+        (i32.eq
+         (local.get $1)
+         (i32.load
+          (local.tee $4
+           (i32.add
+            (i32.shl
+             (local.tee $5
+              (i32.load offset=28
+               (local.get $1)
+              )
+             )
+             (i32.const 2)
+            )
+            (i32.const 480)
+           )
+          )
+         )
+        )
+        (block
+         (i32.store
+          (local.get $4)
+          (local.get $6)
+         )
+         (if
+          (i32.eqz
+           (local.get $6)
+          )
+          (block
+           (i32.store
+            (i32.const 180)
+            (i32.and
+             (i32.load
+              (i32.const 180)
+             )
+             (i32.xor
+              (i32.shl
+               (i32.const 1)
+               (local.get $5)
+              )
+              (i32.const -1)
+             )
+            )
+           )
+           (local.set $2
+            (local.get $1)
+           )
+           (local.set $3
+            (local.get $0)
+           )
+           (br $do-once)
+          )
+         )
+        )
+        (block
+         (if
+          (i32.lt_u
+           (local.get $12)
+           (i32.load
+            (i32.const 192)
+           )
+          )
+          (call $_abort)
+         )
+         (if
+          (i32.eq
+           (i32.load
+            (local.tee $4
+             (i32.add
+              (local.get $12)
+              (i32.const 16)
+             )
+            )
+           )
+           (local.get $1)
+          )
+          (i32.store
+           (local.get $4)
+           (local.get $6)
+          )
+          (i32.store offset=20
+           (local.get $12)
+           (local.get $6)
+          )
+         )
+         (if
+          (i32.eqz
+           (local.get $6)
+          )
+          (block
+           (local.set $2
+            (local.get $1)
+           )
+           (local.set $3
+            (local.get $0)
+           )
+           (br $do-once)
+          )
+         )
+        )
+       )
+       (if
+        (i32.lt_u
+         (local.get $6)
+         (local.tee $5
+          (i32.load
+           (i32.const 192)
+          )
+         )
+        )
+        (call $_abort)
+       )
+       (i32.store offset=24
+        (local.get $6)
+        (local.get $12)
+       )
+       (if
+        (local.tee $7
+         (i32.load
+          (local.tee $4
+           (i32.add
+            (local.get $1)
+            (i32.const 16)
+           )
+          )
+         )
+        )
+        (if
+         (i32.lt_u
+          (local.get $7)
+          (local.get $5)
+         )
+         (call $_abort)
+         (block
+          (i32.store offset=16
+           (local.get $6)
+           (local.get $7)
+          )
+          (i32.store offset=24
+           (local.get $7)
+           (local.get $6)
+          )
+         )
+        )
+       )
+       (if
+        (local.tee $4
+         (i32.load offset=4
+          (local.get $4)
+         )
+        )
+        (if
+         (i32.lt_u
+          (local.get $4)
+          (i32.load
+           (i32.const 192)
+          )
+         )
+         (call $_abort)
+         (block
+          (i32.store offset=20
+           (local.get $6)
+           (local.get $4)
+          )
+          (i32.store offset=24
+           (local.get $4)
+           (local.get $6)
+          )
+          (local.set $2
+           (local.get $1)
+          )
+          (local.set $3
+           (local.get $0)
+          )
+         )
+        )
+        (block
+         (local.set $2
+          (local.get $1)
+         )
+         (local.set $3
+          (local.get $0)
+         )
+        )
+       )
+      )
+      (block
+       (local.set $2
+        (local.get $1)
+       )
+       (local.set $3
+        (local.get $0)
+       )
+      )
+     )
+    )
+   )
+  )
+  (if
+   (i32.ge_u
+    (local.get $2)
+    (local.get $8)
+   )
+   (call $_abort)
+  )
+  (if
+   (i32.eqz
+    (i32.and
+     (local.tee $1
+      (i32.load
+       (local.tee $0
+        (i32.add
+         (local.get $8)
+         (i32.const 4)
+        )
+       )
+      )
+     )
+     (i32.const 1)
+    )
+   )
+   (call $_abort)
+  )
+  (if
+   (i32.and
+    (local.get $1)
+    (i32.const 2)
+   )
+   (block
+    (i32.store
+     (local.get $0)
+     (i32.and
+      (local.get $1)
+      (i32.const -2)
+     )
+    )
+    (i32.store offset=4
+     (local.get $2)
+     (i32.or
+      (local.get $3)
+      (i32.const 1)
+     )
+    )
+    (i32.store
+     (i32.add
+      (local.get $2)
+      (local.get $3)
+     )
+     (local.get $3)
+    )
+   )
+   (block
+    (if
+     (i32.eq
+      (local.get $8)
+      (i32.load
+       (i32.const 200)
+      )
+     )
+     (block
+      (i32.store
+       (i32.const 188)
+       (local.tee $0
+        (i32.add
+         (i32.load
+          (i32.const 188)
+         )
+         (local.get $3)
+        )
+       )
+      )
+      (i32.store
+       (i32.const 200)
+       (local.get $2)
+      )
+      (i32.store offset=4
+       (local.get $2)
+       (i32.or
+        (local.get $0)
+        (i32.const 1)
+       )
+      )
+      (if
+       (i32.ne
+        (local.get $2)
+        (i32.load
+         (i32.const 196)
+        )
+       )
+       (return)
+      )
+      (i32.store
+       (i32.const 196)
+       (i32.const 0)
+      )
+      (i32.store
+       (i32.const 184)
+       (i32.const 0)
+      )
+      (return)
+     )
+    )
+    (if
+     (i32.eq
+      (local.get $8)
+      (i32.load
+       (i32.const 196)
+      )
+     )
+     (block
+      (i32.store
+       (i32.const 184)
+       (local.tee $0
+        (i32.add
+         (i32.load
+          (i32.const 184)
+         )
+         (local.get $3)
+        )
+       )
+      )
+      (i32.store
+       (i32.const 196)
+       (local.get $2)
+      )
+      (i32.store offset=4
+       (local.get $2)
+       (i32.or
+        (local.get $0)
+        (i32.const 1)
+       )
+      )
+      (i32.store
+       (i32.add
+        (local.get $2)
+        (local.get $0)
+       )
+       (local.get $0)
+      )
+      (return)
+     )
+    )
+    (local.set $5
+     (i32.add
+      (i32.and
+       (local.get $1)
+       (i32.const -8)
+      )
+      (local.get $3)
+     )
+    )
+    (local.set $3
+     (i32.shr_u
+      (local.get $1)
+      (i32.const 3)
+     )
+    )
+    (block $do-once4
+     (if
+      (i32.lt_u
+       (local.get $1)
+       (i32.const 256)
+      )
+      (block
+       (local.set $4
+        (i32.load offset=12
+         (local.get $8)
+        )
+       )
+       (if
+        (i32.ne
+         (local.tee $1
+          (i32.load offset=8
+           (local.get $8)
+          )
+         )
+         (local.tee $0
+          (i32.add
+           (i32.shl
+            (local.get $3)
+            (i32.const 3)
+           )
+           (i32.const 216)
+          )
+         )
+        )
+        (block
+         (if
+          (i32.lt_u
+           (local.get $1)
+           (i32.load
+            (i32.const 192)
+           )
+          )
+          (call $_abort)
+         )
+         (if
+          (i32.ne
+           (i32.load offset=12
+            (local.get $1)
+           )
+           (local.get $8)
+          )
+          (call $_abort)
+         )
+        )
+       )
+       (if
+        (i32.eq
+         (local.get $4)
+         (local.get $1)
+        )
+        (block
+         (i32.store
+          (i32.const 176)
+          (i32.and
+           (i32.load
+            (i32.const 176)
+           )
+           (i32.xor
+            (i32.shl
+             (i32.const 1)
+             (local.get $3)
+            )
+            (i32.const -1)
+           )
+          )
+         )
+         (br $do-once4)
+        )
+       )
+       (if
+        (i32.eq
+         (local.get $4)
+         (local.get $0)
+        )
+        (local.set $14
+         (i32.add
+          (local.get $4)
+          (i32.const 8)
+         )
+        )
+        (block
+         (if
+          (i32.lt_u
+           (local.get $4)
+           (i32.load
+            (i32.const 192)
+           )
+          )
+          (call $_abort)
+         )
+         (if
+          (i32.eq
+           (i32.load
+            (local.tee $0
+             (i32.add
+              (local.get $4)
+              (i32.const 8)
+             )
+            )
+           )
+           (local.get $8)
+          )
+          (local.set $14
+           (local.get $0)
+          )
+          (call $_abort)
+         )
+        )
+       )
+       (i32.store offset=12
+        (local.get $1)
+        (local.get $4)
+       )
+       (i32.store
+        (local.get $14)
+        (local.get $1)
+       )
+      )
+      (block
+       (local.set $6
+        (i32.load offset=24
+         (local.get $8)
+        )
+       )
+       (block $do-once6
+        (if
+         (i32.eq
+          (local.tee $0
+           (i32.load offset=12
+            (local.get $8)
+           )
+          )
+          (local.get $8)
+         )
+         (block
+          (if
+           (i32.eqz
+            (local.tee $3
+             (i32.load
+              (local.tee $0
+               (i32.add
+                (local.tee $1
+                 (i32.add
+                  (local.get $8)
+                  (i32.const 16)
+                 )
+                )
+                (i32.const 4)
+               )
+              )
+             )
+            )
+           )
+           (if
+            (local.tee $3
+             (i32.load
+              (local.get $1)
+             )
+            )
+            (local.set $0
+             (local.get $1)
+            )
+            (block
+             (local.set $9
+              (i32.const 0)
+             )
+             (br $do-once6)
+            )
+           )
+          )
+          (loop $while-in9
+           (if
+            (local.tee $1
+             (i32.load
+              (local.tee $4
+               (i32.add
+                (local.get $3)
+                (i32.const 20)
+               )
+              )
+             )
+            )
+            (block
+             (local.set $3
+              (local.get $1)
+             )
+             (local.set $0
+              (local.get $4)
+             )
+             (br $while-in9)
+            )
+           )
+           (if
+            (local.tee $1
+             (i32.load
+              (local.tee $4
+               (i32.add
+                (local.get $3)
+                (i32.const 16)
+               )
+              )
+             )
+            )
+            (block
+             (local.set $3
+              (local.get $1)
+             )
+             (local.set $0
+              (local.get $4)
+             )
+             (br $while-in9)
+            )
+           )
+          )
+          (if
+           (i32.lt_u
+            (local.get $0)
+            (i32.load
+             (i32.const 192)
+            )
+           )
+           (call $_abort)
+           (block
+            (i32.store
+             (local.get $0)
+             (i32.const 0)
+            )
+            (local.set $9
+             (local.get $3)
+            )
+           )
+          )
+         )
+         (block
+          (if
+           (i32.lt_u
+            (local.tee $4
+             (i32.load offset=8
+              (local.get $8)
+             )
+            )
+            (i32.load
+             (i32.const 192)
+            )
+           )
+           (call $_abort)
+          )
+          (if
+           (i32.ne
+            (i32.load
+             (local.tee $1
+              (i32.add
+               (local.get $4)
+               (i32.const 12)
+              )
+             )
+            )
+            (local.get $8)
+           )
+           (call $_abort)
+          )
+          (if
+           (i32.eq
+            (i32.load
+             (local.tee $3
+              (i32.add
+               (local.get $0)
+               (i32.const 8)
+              )
+             )
+            )
+            (local.get $8)
+           )
+           (block
+            (i32.store
+             (local.get $1)
+             (local.get $0)
+            )
+            (i32.store
+             (local.get $3)
+             (local.get $4)
+            )
+            (local.set $9
+             (local.get $0)
+            )
+           )
+           (call $_abort)
+          )
+         )
+        )
+       )
+       (if
+        (local.get $6)
+        (block
+         (if
+          (i32.eq
+           (local.get $8)
+           (i32.load
+            (local.tee $0
+             (i32.add
+              (i32.shl
+               (local.tee $3
+                (i32.load offset=28
+                 (local.get $8)
+                )
+               )
+               (i32.const 2)
+              )
+              (i32.const 480)
+             )
+            )
+           )
+          )
+          (block
+           (i32.store
+            (local.get $0)
+            (local.get $9)
+           )
+           (if
+            (i32.eqz
+             (local.get $9)
+            )
+            (block
+             (i32.store
+              (i32.const 180)
+              (i32.and
+               (i32.load
+                (i32.const 180)
+               )
+               (i32.xor
+                (i32.shl
+                 (i32.const 1)
+                 (local.get $3)
+                )
+                (i32.const -1)
+               )
+              )
+             )
+             (br $do-once4)
+            )
+           )
+          )
+          (block
+           (if
+            (i32.lt_u
+             (local.get $6)
+             (i32.load
+              (i32.const 192)
+             )
+            )
+            (call $_abort)
+           )
+           (if
+            (i32.eq
+             (i32.load
+              (local.tee $0
+               (i32.add
+                (local.get $6)
+                (i32.const 16)
+               )
+              )
+             )
+             (local.get $8)
+            )
+            (i32.store
+             (local.get $0)
+             (local.get $9)
+            )
+            (i32.store offset=20
+             (local.get $6)
+             (local.get $9)
+            )
+           )
+           (br_if $do-once4
+            (i32.eqz
+             (local.get $9)
+            )
+           )
+          )
+         )
+         (if
+          (i32.lt_u
+           (local.get $9)
+           (local.tee $3
+            (i32.load
+             (i32.const 192)
+            )
+           )
+          )
+          (call $_abort)
+         )
+         (i32.store offset=24
+          (local.get $9)
+          (local.get $6)
+         )
+         (if
+          (local.tee $1
+           (i32.load
+            (local.tee $0
+             (i32.add
+              (local.get $8)
+              (i32.const 16)
+             )
+            )
+           )
+          )
+          (if
+           (i32.lt_u
+            (local.get $1)
+            (local.get $3)
+           )
+           (call $_abort)
+           (block
+            (i32.store offset=16
+             (local.get $9)
+             (local.get $1)
+            )
+            (i32.store offset=24
+             (local.get $1)
+             (local.get $9)
+            )
+           )
+          )
+         )
+         (if
+          (local.tee $0
+           (i32.load offset=4
+            (local.get $0)
+           )
+          )
+          (if
+           (i32.lt_u
+            (local.get $0)
+            (i32.load
+             (i32.const 192)
+            )
+           )
+           (call $_abort)
+           (block
+            (i32.store offset=20
+             (local.get $9)
+             (local.get $0)
+            )
+            (i32.store offset=24
+             (local.get $0)
+             (local.get $9)
+            )
+           )
+          )
+         )
+        )
+       )
+      )
+     )
+    )
+    (i32.store offset=4
+     (local.get $2)
+     (i32.or
+      (local.get $5)
+      (i32.const 1)
+     )
+    )
+    (i32.store
+     (i32.add
+      (local.get $2)
+      (local.get $5)
+     )
+     (local.get $5)
+    )
+    (if
+     (i32.eq
+      (local.get $2)
+      (i32.load
+       (i32.const 196)
+      )
+     )
+     (block
+      (i32.store
+       (i32.const 184)
+       (local.get $5)
+      )
+      (return)
+     )
+     (local.set $3
+      (local.get $5)
+     )
+    )
+   )
+  )
+  (local.set $0
+   (i32.shr_u
+    (local.get $3)
+    (i32.const 3)
+   )
+  )
+  (if
+   (i32.lt_u
+    (local.get $3)
+    (i32.const 256)
+   )
+   (block
+    (local.set $1
+     (i32.add
+      (i32.shl
+       (local.get $0)
+       (i32.const 3)
+      )
+      (i32.const 216)
+     )
+    )
+    (if
+     (i32.and
+      (local.tee $3
+       (i32.load
+        (i32.const 176)
+       )
+      )
+      (local.tee $0
+       (i32.shl
+        (i32.const 1)
+        (local.get $0)
+       )
+      )
+     )
+     (if
+      (i32.lt_u
+       (local.tee $0
+        (i32.load
+         (local.tee $3
+          (i32.add
+           (local.get $1)
+           (i32.const 8)
+          )
+         )
+        )
+       )
+       (i32.load
+        (i32.const 192)
+       )
+      )
+      (call $_abort)
+      (block
+       (local.set $15
+        (local.get $3)
+       )
+       (local.set $13
+        (local.get $0)
+       )
+      )
+     )
+     (block
+      (i32.store
+       (i32.const 176)
+       (i32.or
+        (local.get $3)
+        (local.get $0)
+       )
+      )
+      (local.set $15
+       (i32.add
+        (local.get $1)
+        (i32.const 8)
+       )
+      )
+      (local.set $13
+       (local.get $1)
+      )
+     )
+    )
+    (i32.store
+     (local.get $15)
+     (local.get $2)
+    )
+    (i32.store offset=12
+     (local.get $13)
+     (local.get $2)
+    )
+    (i32.store offset=8
+     (local.get $2)
+     (local.get $13)
+    )
+    (i32.store offset=12
+     (local.get $2)
+     (local.get $1)
+    )
+    (return)
+   )
+  )
+  (local.set $4
+   (i32.add
+    (i32.shl
+     (local.tee $5
+      (if (result i32)
+       (local.tee $0
+        (i32.shr_u
+         (local.get $3)
+         (i32.const 8)
+        )
+       )
+       (if (result i32)
+        (i32.gt_u
+         (local.get $3)
+         (i32.const 16777215)
+        )
+        (i32.const 31)
+        (i32.or
+         (i32.and
+          (i32.shr_u
+           (local.get $3)
+           (i32.add
+            (local.tee $0
+             (i32.add
+              (i32.sub
+               (i32.const 14)
+               (i32.or
+                (i32.or
+                 (local.tee $0
+                  (i32.and
+                   (i32.shr_u
+                    (i32.add
+                     (local.tee $1
+                      (i32.shl
+                       (local.get $0)
+                       (local.tee $4
+                        (i32.and
+                         (i32.shr_u
+                          (i32.add
+                           (local.get $0)
+                           (i32.const 1048320)
+                          )
+                          (i32.const 16)
+                         )
+                         (i32.const 8)
+                        )
+                       )
+                      )
+                     )
+                     (i32.const 520192)
+                    )
+                    (i32.const 16)
+                   )
+                   (i32.const 4)
+                  )
+                 )
+                 (local.get $4)
+                )
+                (local.tee $0
+                 (i32.and
+                  (i32.shr_u
+                   (i32.add
+                    (local.tee $1
+                     (i32.shl
+                      (local.get $1)
+                      (local.get $0)
+                     )
+                    )
+                    (i32.const 245760)
+                   )
+                   (i32.const 16)
+                  )
+                  (i32.const 2)
+                 )
+                )
+               )
+              )
+              (i32.shr_u
+               (i32.shl
+                (local.get $1)
+                (local.get $0)
+               )
+               (i32.const 15)
+              )
+             )
+            )
+            (i32.const 7)
+           )
+          )
+          (i32.const 1)
+         )
+         (i32.shl
+          (local.get $0)
+          (i32.const 1)
+         )
+        )
+       )
+       (i32.const 0)
+      )
+     )
+     (i32.const 2)
+    )
+    (i32.const 480)
+   )
+  )
+  (i32.store offset=28
+   (local.get $2)
+   (local.get $5)
+  )
+  (i32.store offset=20
+   (local.get $2)
+   (i32.const 0)
+  )
+  (i32.store offset=16
+   (local.get $2)
+   (i32.const 0)
+  )
+  (block $do-once12
+   (if
+    (i32.and
+     (local.tee $1
+      (i32.load
+       (i32.const 180)
+      )
+     )
+     (local.tee $0
+      (i32.shl
+       (i32.const 1)
+       (local.get $5)
+      )
+     )
+    )
+    (block
+     (local.set $5
+      (i32.shl
+       (local.get $3)
+       (select
+        (i32.const 0)
+        (i32.sub
+         (i32.const 25)
+         (i32.shr_u
+          (local.get $5)
+          (i32.const 1)
+         )
+        )
+        (i32.eq
+         (local.get $5)
+         (i32.const 31)
+        )
+       )
+      )
+     )
+     (local.set $0
+      (i32.load
+       (local.get $4)
+      )
+     )
+     (block $__rjto$1
+      (block $__rjti$1
+       (loop $while-in15
+        (br_if $__rjti$1
+         (i32.eq
+          (i32.and
+           (i32.load offset=4
+            (local.get $0)
+           )
+           (i32.const -8)
+          )
+          (local.get $3)
+         )
+        )
+        (local.set $4
+         (i32.shl
+          (local.get $5)
+          (i32.const 1)
+         )
+        )
+        (if
+         (local.tee $1
+          (i32.load
+           (local.tee $5
+            (i32.add
+             (i32.add
+              (local.get $0)
+              (i32.const 16)
+             )
+             (i32.shl
+              (i32.shr_u
+               (local.get $5)
+               (i32.const 31)
+              )
+              (i32.const 2)
+             )
+            )
+           )
+          )
+         )
+         (block
+          (local.set $5
+           (local.get $4)
+          )
+          (local.set $0
+           (local.get $1)
+          )
+          (br $while-in15)
+         )
+        )
+       )
+       (if
+        (i32.lt_u
+         (local.get $5)
+         (i32.load
+          (i32.const 192)
+         )
+        )
+        (call $_abort)
+        (block
+         (i32.store
+          (local.get $5)
+          (local.get $2)
+         )
+         (i32.store offset=24
+          (local.get $2)
+          (local.get $0)
+         )
+         (i32.store offset=12
+          (local.get $2)
+          (local.get $2)
+         )
+         (i32.store offset=8
+          (local.get $2)
+          (local.get $2)
+         )
+         (br $do-once12)
+        )
+       )
+       (br $__rjto$1)
+      )
+      (if
+       (i32.and
+        (i32.ge_u
+         (local.tee $4
+          (i32.load
+           (local.tee $1
+            (i32.add
+             (local.get $0)
+             (i32.const 8)
+            )
+           )
+          )
+         )
+         (local.tee $3
+          (i32.load
+           (i32.const 192)
+          )
+         )
+        )
+        (i32.ge_u
+         (local.get $0)
+         (local.get $3)
+        )
+       )
+       (block
+        (i32.store offset=12
+         (local.get $4)
+         (local.get $2)
+        )
+        (i32.store
+         (local.get $1)
+         (local.get $2)
+        )
+        (i32.store offset=8
+         (local.get $2)
+         (local.get $4)
+        )
+        (i32.store offset=12
+         (local.get $2)
+         (local.get $0)
+        )
+        (i32.store offset=24
+         (local.get $2)
+         (i32.const 0)
+        )
+       )
+       (call $_abort)
+      )
+     )
+    )
+    (block
+     (i32.store
+      (i32.const 180)
+      (i32.or
+       (local.get $1)
+       (local.get $0)
+      )
+     )
+     (i32.store
+      (local.get $4)
+      (local.get $2)
+     )
+     (i32.store offset=24
+      (local.get $2)
+      (local.get $4)
+     )
+     (i32.store offset=12
+      (local.get $2)
+      (local.get $2)
+     )
+     (i32.store offset=8
+      (local.get $2)
+      (local.get $2)
+     )
+    )
+   )
+  )
+  (i32.store
+   (i32.const 208)
+   (local.tee $0
+    (i32.add
+     (i32.load
+      (i32.const 208)
+     )
+     (i32.const -1)
+    )
+   )
+  )
+  (if
+   (local.get $0)
+   (return)
+   (local.set $0
+    (i32.const 632)
+   )
+  )
+  (loop $while-in17
+   (local.set $0
+    (i32.add
+     (local.tee $3
+      (i32.load
+       (local.get $0)
+      )
+     )
+     (i32.const 8)
+    )
+   )
+   (br_if $while-in17
+    (local.get $3)
+   )
+  )
+  (i32.store
+   (i32.const 208)
+   (i32.const -1)
+  )
+ )
+ (func $runPostSets
+  (nop)
+ )
+ (func $_i64Subtract (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
+  (global.set $tempRet0
+   (i32.sub
+    (i32.sub
+     (local.get $1)
+     (local.get $3)
+    )
+    (i32.gt_u
+     (local.get $2)
+     (local.get $0)
+    )
+   )
+  )
+  (i32.sub
+   (local.get $0)
+   (local.get $2)
+  )
+ )
+ (func $_i64Add (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
+  (local $4 i32)
+  (global.set $tempRet0
+   (i32.add
+    (i32.add
+     (local.get $1)
+     (local.get $3)
+    )
+    (i32.lt_u
+     (local.tee $4
+      (i32.add
+       (local.get $0)
+       (local.get $2)
+      )
+     )
+     (local.get $0)
+    )
+   )
+  )
+  (local.get $4)
+ )
+ (func $_memset (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $4
+   (i32.add
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (if
+   (i32.ge_s
+    (local.get $2)
+    (i32.const 20)
+   )
+   (block
+    (local.set $1
+     (i32.and
+      (local.get $1)
+      (i32.const 255)
+     )
+    )
+    (if
+     (local.tee $3
+      (i32.and
+       (local.get $0)
+       (i32.const 3)
+      )
+     )
+     (block
+      (local.set $3
+       (i32.sub
+        (i32.add
+         (local.get $0)
+         (i32.const 4)
+        )
+        (local.get $3)
+       )
+      )
+      (loop $while-in
+       (if
+        (i32.lt_s
+         (local.get $0)
+         (local.get $3)
+        )
+        (block
+         (i32.store8
+          (local.get $0)
+          (local.get $1)
+         )
+         (local.set $0
+          (i32.add
+           (local.get $0)
+           (i32.const 1)
+          )
+         )
+         (br $while-in)
+        )
+       )
+      )
+     )
+    )
+    (local.set $3
+     (i32.or
+      (i32.or
+       (i32.or
+        (local.get $1)
+        (i32.shl
+         (local.get $1)
+         (i32.const 8)
+        )
+       )
+       (i32.shl
+        (local.get $1)
+        (i32.const 16)
+       )
+      )
+      (i32.shl
+       (local.get $1)
+       (i32.const 24)
+      )
+     )
+    )
+    (local.set $5
+     (i32.and
+      (local.get $4)
+      (i32.const -4)
+     )
+    )
+    (loop $while-in1
+     (if
+      (i32.lt_s
+       (local.get $0)
+       (local.get $5)
+      )
+      (block
+       (i32.store
+        (local.get $0)
+        (local.get $3)
+       )
+       (local.set $0
+        (i32.add
+         (local.get $0)
+         (i32.const 4)
+        )
+       )
+       (br $while-in1)
+      )
+     )
+    )
+   )
+  )
+  (loop $while-in3
+   (if
+    (i32.lt_s
+     (local.get $0)
+     (local.get $4)
+    )
+    (block
+     (i32.store8
+      (local.get $0)
+      (local.get $1)
+     )
+     (local.set $0
+      (i32.add
+       (local.get $0)
+       (i32.const 1)
+      )
+     )
+     (br $while-in3)
+    )
+   )
+  )
+  (i32.sub
+   (local.get $0)
+   (local.get $2)
+  )
+ )
+ (func $_bitshift64Lshr (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (if
+   (i32.lt_s
+    (local.get $2)
+    (i32.const 32)
+   )
+   (block
+    (global.set $tempRet0
+     (i32.shr_u
+      (local.get $1)
+      (local.get $2)
+     )
+    )
+    (return
+     (i32.or
+      (i32.shr_u
+       (local.get $0)
+       (local.get $2)
+      )
+      (i32.shl
+       (i32.and
+        (local.get $1)
+        (i32.sub
+         (i32.shl
+          (i32.const 1)
+          (local.get $2)
+         )
+         (i32.const 1)
+        )
+       )
+       (i32.sub
+        (i32.const 32)
+        (local.get $2)
+       )
+      )
+     )
+    )
+   )
+  )
+  (global.set $tempRet0
+   (i32.const 0)
+  )
+  (i32.shr_u
+   (local.get $1)
+   (i32.sub
+    (local.get $2)
+    (i32.const 32)
+   )
+  )
+ )
+ (func $_bitshift64Shl (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (if
+   (i32.lt_s
+    (local.get $2)
+    (i32.const 32)
+   )
+   (block
+    (global.set $tempRet0
+     (i32.or
+      (i32.shl
+       (local.get $1)
+       (local.get $2)
+      )
+      (i32.shr_u
+       (i32.and
+        (local.get $0)
+        (i32.shl
+         (i32.sub
+          (i32.shl
+           (i32.const 1)
+           (local.get $2)
+          )
+          (i32.const 1)
+         )
+         (i32.sub
+          (i32.const 32)
+          (local.get $2)
+         )
+        )
+       )
+       (i32.sub
+        (i32.const 32)
+        (local.get $2)
+       )
+      )
+     )
+    )
+    (return
+     (i32.shl
+      (local.get $0)
+      (local.get $2)
+     )
+    )
+   )
+  )
+  (global.set $tempRet0
+   (i32.shl
+    (local.get $0)
+    (i32.sub
+     (local.get $2)
+     (i32.const 32)
+    )
+   )
+  )
+  (i32.const 0)
+ )
+ (func $_memcpy (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (if
+   (i32.ge_s
+    (local.get $2)
+    (i32.const 4096)
+   )
+   (return
+    (call $_emscripten_memcpy_big
+     (local.get $0)
+     (local.get $1)
+     (local.get $2)
+    )
+   )
+  )
+  (local.set $3
+   (local.get $0)
+  )
+  (if
+   (i32.eq
+    (i32.and
+     (local.get $0)
+     (i32.const 3)
+    )
+    (i32.and
+     (local.get $1)
+     (i32.const 3)
+    )
+   )
+   (block
+    (loop $while-in
+     (if
+      (i32.and
+       (local.get $0)
+       (i32.const 3)
+      )
+      (block
+       (if
+        (i32.eqz
+         (local.get $2)
+        )
+        (return
+         (local.get $3)
+        )
+       )
+       (i32.store8
+        (local.get $0)
+        (i32.load8_s
+         (local.get $1)
+        )
+       )
+       (local.set $0
+        (i32.add
+         (local.get $0)
+         (i32.const 1)
+        )
+       )
+       (local.set $1
+        (i32.add
+         (local.get $1)
+         (i32.const 1)
+        )
+       )
+       (local.set $2
+        (i32.sub
+         (local.get $2)
+         (i32.const 1)
+        )
+       )
+       (br $while-in)
+      )
+     )
+    )
+    (loop $while-in1
+     (if
+      (i32.ge_s
+       (local.get $2)
+       (i32.const 4)
+      )
+      (block
+       (i32.store
+        (local.get $0)
+        (i32.load
+         (local.get $1)
+        )
+       )
+       (local.set $0
+        (i32.add
+         (local.get $0)
+         (i32.const 4)
+        )
+       )
+       (local.set $1
+        (i32.add
+         (local.get $1)
+         (i32.const 4)
+        )
+       )
+       (local.set $2
+        (i32.sub
+         (local.get $2)
+         (i32.const 4)
+        )
+       )
+       (br $while-in1)
+      )
+     )
+    )
+   )
+  )
+  (loop $while-in3
+   (if
+    (i32.gt_s
+     (local.get $2)
+     (i32.const 0)
+    )
+    (block
+     (i32.store8
+      (local.get $0)
+      (i32.load8_s
+       (local.get $1)
+      )
+     )
+     (local.set $0
+      (i32.add
+       (local.get $0)
+       (i32.const 1)
+      )
+     )
+     (local.set $1
+      (i32.add
+       (local.get $1)
+       (i32.const 1)
+      )
+     )
+     (local.set $2
+      (i32.sub
+       (local.get $2)
+       (i32.const 1)
+      )
+     )
+     (br $while-in3)
+    )
+   )
+  )
+  (local.get $3)
+ )
+ (func $___udivdi3 (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
+  (call $___udivmoddi4
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+   (local.get $3)
+   (i32.const 0)
+  )
+ )
+ (func $___uremdi3 (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
+  (local $4 i32)
+  (local.set $4
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 16)
+   )
+  )
+  (drop
+   (call $___udivmoddi4
+    (local.get $0)
+    (local.get $1)
+    (local.get $2)
+    (local.get $3)
+    (local.tee $0
+     (local.get $4)
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $4)
+  )
+  (global.set $tempRet0
+   (i32.load offset=4
+    (local.get $0)
+   )
+  )
+  (i32.load
+   (local.get $0)
+  )
+ )
+ (func $___udivmoddi4 (param $xl i32) (param $xh i32) (param $yl i32) (param $yh i32) (param $r i32) (result i32)
+  (local $x64 i64)
+  (local $y64 i64)
+  (local.set $x64
+   (i64.or
+    (i64.extend_i32_u
+     (local.get $xl)
+    )
+    (i64.shl
+     (i64.extend_i32_u
+      (local.get $xh)
+     )
+     (i64.const 32)
+    )
+   )
+  )
+  (local.set $y64
+   (i64.or
+    (i64.extend_i32_u
+     (local.get $yl)
+    )
+    (i64.shl
+     (i64.extend_i32_u
+      (local.get $yh)
+     )
+     (i64.const 32)
+    )
+   )
+  )
+  (if
+   (local.get $r)
+   (i64.store
+    (local.get $r)
+    (i64.rem_u
+     (local.get $x64)
+     (local.get $y64)
+    )
+   )
+  )
+  (local.set $x64
+   (i64.div_u
+    (local.get $x64)
+    (local.get $y64)
+   )
+  )
+  (global.set $tempRet0
+   (i32.wrap_i64
+    (i64.shr_u
+     (local.get $x64)
+     (i64.const 32)
+    )
+   )
+  )
+  (i32.wrap_i64
+   (local.get $x64)
+  )
+ )
+ (func $dynCall_ii (param $0 i32) (param $1 i32) (result i32)
+  (call_indirect (type $FUNCSIG$ii)
+   (local.get $1)
+   (i32.and
+    (local.get $0)
+    (i32.const 1)
+   )
+  )
+ )
+ (func $dynCall_iiii (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
+  (call_indirect (type $FUNCSIG$iiii)
+   (local.get $1)
+   (local.get $2)
+   (local.get $3)
+   (i32.add
+    (i32.and
+     (local.get $0)
+     (i32.const 7)
+    )
+    (i32.const 2)
+   )
+  )
+ )
+ (func $dynCall_vi (param $0 i32) (param $1 i32)
+  (call_indirect (type $FUNCSIG$vi)
+   (local.get $1)
+   (i32.add
+    (i32.and
+     (local.get $0)
+     (i32.const 7)
+    )
+    (i32.const 10)
+   )
+  )
+ )
+ (func $b0 (param $0 i32) (result i32)
+  (call $nullFunc_ii
+   (i32.const 0)
+  )
+  (i32.const 0)
+ )
+ (func $b1 (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (call $nullFunc_iiii
+   (i32.const 1)
+  )
+  (i32.const 0)
+ )
+ (func $b2 (param $0 i32)
+  (call $nullFunc_vi
+   (i32.const 2)
+  )
+ )
+)
diff --git a/binaryen/test/passes/inlining_all-features.txt b/binaryen/test/passes/inlining_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/inlining_all-features.txt
@@ -0,0 +1,49 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_funcref (func (result funcref)))
+ (event $e (attr 0) (param i32))
+ (export "ref_func_test" (func $ref_func_test))
+ (func $foo
+  (nop)
+ )
+ (func $ref_func_test (result funcref)
+  (block
+   (block $__inlined_func$foo
+    (nop)
+   )
+  )
+  (ref.func $foo)
+ )
+ (func $br_on_exn_name_uniquify_test
+  (local $exn exnref)
+  (local $1 exnref)
+  (drop
+   (block $l (result i32)
+    (block
+     (block $__inlined_func$func_inner
+      (local.set $1
+       (ref.null exn)
+      )
+      (drop
+       (block $l0 (result i32)
+        (drop
+         (br_on_exn $l0 $e
+          (local.get $1)
+         )
+        )
+        (i32.const 0)
+       )
+      )
+     )
+    )
+    (drop
+     (br_on_exn $l $e
+      (local.get $exn)
+     )
+    )
+    (i32.const 0)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/inlining_all-features.wast b/binaryen/test/passes/inlining_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/inlining_all-features.wast
@@ -0,0 +1,38 @@
+(module
+  (export "ref_func_test" (func $ref_func_test))
+  ;; $foo should not be removed after being inlined, because there is 'ref.func'
+  ;; instruction that refers to it
+  (func $foo)
+  (func $ref_func_test (result funcref)
+    (call $foo)
+    (ref.func $foo)
+  )
+
+  ;; Tests if UniqueNameMapper works correctly for br_on_exn labels.
+  ;; We have $l in br_on_exns in both $func_inner and $br_on_name_uniquify_test,
+  ;; which should become unique names respectively after inlining.
+  (event $e (attr 0) (param i32))
+  (func $func_inner
+    (local $exn exnref)
+    (drop
+      (block $l (result i32)
+        (drop
+          (br_on_exn $l $e (local.get $exn))
+        )
+        (i32.const 0)
+      )
+    )
+  )
+  (func $br_on_exn_name_uniquify_test
+    (local $exn exnref)
+    (drop
+      (block $l (result i32)
+        (call $func_inner)
+        (drop
+          (br_on_exn $l $e (local.get $exn))
+        )
+        (i32.const 0)
+      )
+    )
+  )
+)
diff --git a/binaryen/test/passes/inlining_enable-tail-call.txt b/binaryen/test/passes/inlining_enable-tail-call.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/inlining_enable-tail-call.txt
@@ -0,0 +1,418 @@
+(module
+ (type $none_=>_none (func))
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $tabled)
+ (export "user" (func $user))
+ (export "exported" (func $exported))
+ (func $user
+  (local $x i32)
+  (local $y f64)
+  (local $2 f32)
+  (local $3 i64)
+  (local $4 f32)
+  (local $5 i64)
+  (local $6 f32)
+  (block
+   (block $__inlined_func$exported
+    (nop)
+   )
+  )
+  (block
+   (block $__inlined_func$tabled
+    (nop)
+   )
+  )
+  (block
+   (block $__inlined_func$multi
+    (nop)
+   )
+  )
+  (block
+   (block $__inlined_func$multi0
+    (nop)
+   )
+  )
+  (block
+   (block $__inlined_func$ok
+    (drop
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (block $__inlined_func$int (result i32)
+     (i32.const 2)
+    )
+   )
+  )
+  (drop
+   (block (result f64)
+    (block $__inlined_func$double (result f64)
+     (f64.const 3.14159)
+    )
+   )
+  )
+  (local.set $x
+   (block (result i32)
+    (block $__inlined_func$int2 (result i32)
+     (i32.const 112)
+    )
+   )
+  )
+  (local.set $y
+   (block (result f64)
+    (block $__inlined_func$double2 (result f64)
+     (f64.const 113.14159)
+    )
+   )
+  )
+  (block
+   (block $__inlined_func$with-local
+    (local.set $2
+     (f32.const 0)
+    )
+    (local.set $2
+     (f32.const 2.1418280601501465)
+    )
+   )
+  )
+  (block
+   (block $__inlined_func$with-local2
+    (local.set $3
+     (i64.const 0)
+    )
+    (local.set $3
+     (i64.const 4)
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (block $__inlined_func$return (result i32)
+     (br $__inlined_func$return
+      (i32.const 5)
+     )
+    )
+   )
+  )
+  (block
+   (block $__inlined_func$multipass
+    (block
+     (block
+      (block $__inlined_func$multipass2
+       (drop
+        (i32.const 6)
+       )
+      )
+     )
+    )
+   )
+  )
+  (block
+   (block $__inlined_func$param
+    (local.set $4
+     (f32.const 12.34000015258789)
+    )
+    (local.set $5
+     (i64.const 890005350012)
+    )
+    (local.set $6
+     (f32.const 0)
+    )
+    (block
+     (drop
+      (local.get $4)
+     )
+     (drop
+      (local.get $5)
+     )
+     (drop
+      (local.get $6)
+     )
+    )
+   )
+  )
+ )
+ (func $exported
+  (nop)
+ )
+ (func $recursive
+  (call $recursive)
+ )
+ (func $tabled
+  (nop)
+ )
+ (func $cycle1
+  (block $__inlined_func$cycle2
+   (block
+    (call $cycle1)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $child (param $0 i32) (result i32)
+  (i32.const 1234)
+ )
+ (func $parent (result i32)
+  (call $child
+   (unreachable)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $f32_i32_=>_i32 (func (param f32 i32) (result i32)))
+ (memory $0 1 1)
+ (global $hangLimit (mut i32) (i32.const 25))
+ (export "hangLimitInitializer" (func $hangLimitInitializer))
+ (func $func_4 (param $0 f32) (param $1 i32) (result i32)
+  (local $2 i64)
+  (local $3 f64)
+  (local $4 f32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 f64)
+  (local $8 i32)
+  (loop $label$0 (result i32)
+   (block $block
+    (if
+     (i32.eqz
+      (global.get $hangLimit)
+     )
+     (return
+      (i32.const 54)
+     )
+    )
+    (global.set $hangLimit
+     (i32.sub
+      (global.get $hangLimit)
+      (i32.const 1)
+     )
+    )
+   )
+   (i32.eqz
+    (if (result i32)
+     (i32.const 1)
+     (if (result i32)
+      (i32.eqz
+       (block (result i32)
+        (block $__inlined_func$func_3 (result i32)
+         (local.set $8
+          (i32.const 0)
+         )
+         (select
+          (local.get $8)
+          (local.tee $8
+           (i32.const -1)
+          )
+          (i32.const 1)
+         )
+        )
+       )
+      )
+      (br $label$0)
+      (i32.const 0)
+     )
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $hangLimitInitializer
+  (global.set $hangLimit
+   (i32.const 25)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (table $0 10 funcref)
+ (func $0
+  (block $__inlined_func$1
+   (call_indirect (type $i32_=>_none)
+    (if (result i32)
+     (i32.const 0)
+     (unreachable)
+     (unreachable)
+    )
+    (i32.const 1)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (func $1
+  (block $__inlined_func$0
+   (block $label$1
+    (br_table $label$1 $label$1
+     (i32.const 0)
+    )
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (func $0 (result i32)
+  (return
+   (block $__inlined_func$1 (result i32)
+    (i32.const 42)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (func $0
+  (local $0 i32)
+  (block
+   (block $__inlined_func$1
+    (local.set $0
+     (i32.const 42)
+    )
+    (drop
+     (local.get $0)
+    )
+   )
+   (return)
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (func $0 (result i32)
+  (local $0 i32)
+  (return
+   (block $__inlined_func$1 (result i32)
+    (local.set $0
+     (i32.const 42)
+    )
+    (local.get $0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (func $0
+  (drop
+   (block (result i32)
+    (block $__inlined_func$1 (result i32)
+     (block
+      (br $__inlined_func$1
+       (block (result i32)
+        (block $__inlined_func$2 (result i32)
+         (i32.const 42)
+        )
+       )
+      )
+     )
+    )
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (func $0
+  (local $0 i32)
+  (block $__inlined_func$1
+   (block
+    (block
+     (block
+      (block $__inlined_func$2
+       (local.set $0
+        (i32.const 42)
+       )
+       (drop
+        (local.get $0)
+       )
+      )
+     )
+     (br $__inlined_func$1)
+    )
+   )
+   (br $__inlined_func$1)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (table $0 10 funcref)
+ (func $0
+  (drop
+   (block (result i32)
+    (block $__inlined_func$1 (result i32)
+     (br $__inlined_func$1
+      (call_indirect (type $i32_=>_i32)
+       (i32.const 42)
+       (i32.const 0)
+      )
+     )
+    )
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (table $0 10 funcref)
+ (func $0
+  (block $__inlined_func$1
+   (block
+    (call_indirect (type $i32_=>_none)
+     (i32.const 42)
+     (i32.const 0)
+    )
+    (br $__inlined_func$1)
+   )
+   (br $__inlined_func$1)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 1 1)
+ (global $global$0 (mut i32) (i32.const 10))
+ (export "func_102_invoker" (func $19))
+ (func $19
+  (block
+   (block
+    (block $__inlined_func$13
+     (block
+      (if
+       (global.get $global$0)
+       (unreachable)
+      )
+      (block
+       (block
+        (block $__inlined_func$2
+         (block
+          (if
+           (global.get $global$0)
+           (br $__inlined_func$2)
+          )
+          (global.set $global$0
+           (i32.const 1)
+          )
+         )
+        )
+        (br $__inlined_func$13)
+       )
+      )
+     )
+     (br $__inlined_func$13)
+    )
+   )
+  )
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/passes/inlining_enable-tail-call.wast b/binaryen/test/passes/inlining_enable-tail-call.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/inlining_enable-tail-call.wast
@@ -0,0 +1,288 @@
+(module
+  (table 1 1 funcref)
+  (elem (i32.const 0) $tabled)
+  (func $user (export "user")
+    (local $x i32)
+    (local $y f64)
+    (call $exported)
+    (call $tabled)
+    (call $multi)
+    (call $multi)
+    (call $ok)
+    (drop (call $int))
+    (drop (call $double))
+    (local.set $x (call $int2))
+    (local.set $y (call $double2))
+    (call $with-local)
+    (call $with-local2)
+    (drop (call $return))
+    (call $multipass)
+    (call $param (f32.const 12.34) (i64.const 890005350012))
+  )
+  (func $exported (export "exported")
+    (nop)
+  )
+  (func $recursive
+    (call $recursive)
+  )
+  (func $tabled
+    (nop)
+  )
+  (func $cycle1
+    (call $cycle2)
+  )
+  (func $cycle2
+    (call $cycle1)
+  )
+  (func $multi
+    (nop)
+  )
+  (func $ok
+    (drop (i32.const 1))
+  )
+  (func $int (result i32)
+    (i32.const 2)
+  )
+  (func $double (result f64)
+    (f64.const 3.14159)
+  )
+  (func $int2 (result i32)
+    (i32.const 112)
+  )
+  (func $double2 (result f64)
+    (f64.const 113.14159)
+  )
+  (func $with-local
+    (local $x f32)
+    (local.set $x (f32.const 2.141828))
+  )
+  (func $with-local2
+    (local $y i64)
+    (local.set $y (i64.const 4))
+  )
+  (func $return (result i32)
+    (return (i32.const 5))
+  )
+  (func $multipass
+    (call $multipass2)
+  )
+  (func $multipass2
+    (drop (i32.const 6))
+  )
+  (func $param (param $x f32) (param $y i64)
+    (local $z f32)
+    (drop (local.get $x))
+    (drop (local.get $y))
+    (drop (local.get $z))
+  )
+)
+(module
+  (func $child (param i32) (result i32)
+    (i32.const 1234)
+  )
+  (func $parent (result i32)
+    (call $child
+      (unreachable) ;; call is not performed, no sense to inline
+    )
+  )
+)
+(module
+ (global $hangLimit (mut i32) (i32.const 25))
+ (memory $0 1 1)
+ (export "hangLimitInitializer" (func $hangLimitInitializer))
+ (func $func_3 (result i32)
+  (local $0 i32)
+  (select
+   (local.get $0) ;; we depend on the zero-init value here, so it must be set when inlining!
+   (local.tee $0
+    (i32.const -1)
+   )
+   (i32.const 1)
+  )
+ )
+ (func $func_4 (param $0 f32) (param $1 i32) (result i32)
+  (local $2 i64)
+  (local $3 f64)
+  (local $4 f32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 f64)
+  (loop $label$0 (result i32)
+   (block
+    (if
+     (i32.eqz
+      (global.get $hangLimit)
+     )
+     (return
+      (i32.const 54)
+     )
+    )
+    (global.set $hangLimit
+     (i32.sub
+      (global.get $hangLimit)
+      (i32.const 1)
+     )
+    )
+   )
+   (i32.eqz
+    (if (result i32)
+     (i32.const 1)
+     (if (result i32)
+      (i32.eqz
+       (call $func_3)
+      )
+      (br $label$0)
+      (i32.const 0)
+     )
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $hangLimitInitializer
+  (global.set $hangLimit
+   (i32.const 25)
+  )
+ )
+)
+(module
+ (type $T (func (param i32)))
+ (table 10 funcref)
+ (func $0
+  (call $1)
+ )
+ (func $1
+  (call_indirect (type $T)
+   (if (result i32) ;; if copy must preserve the forced type
+    (i32.const 0)
+    (unreachable)
+    (unreachable)
+   )
+   (i32.const 1)
+  )
+ )
+)
+(module
+ (func $0
+  (block $label$1 ;; copy this name
+   (br_table $label$1 $label$1
+    (i32.const 0)
+   )
+  )
+ )
+ (func $1
+  (call $0)
+ )
+)
+(module
+ (func $0 (result i32)
+  (return_call $1)
+ )
+ (func $1 (result i32)
+  (i32.const 42)
+ )
+)
+(module
+ (func $0
+  (return_call $1
+   (i32.const 42)
+  )
+ )
+ (func $1 (param i32)
+  (drop
+   (local.get 0)
+  )
+ )
+)
+(module
+ (func $0 (result i32)
+  (return_call $1
+   (i32.const 42)
+  )
+ )
+ (func $1 (param i32) (result i32)
+  (local.get 0)
+ )
+)
+(module
+ (func $0
+  (drop
+   (call $1)
+  )
+ )
+ (func $1 (result i32)
+  (return_call $2)
+ )
+ (func $2 (result i32)
+  (i32.const 42)
+ )
+)
+(module
+ (func $0
+  (call $1)
+ )
+ (func $1
+  (return_call $2
+   (i32.const 42)
+  )
+ )
+ (func $2 (param i32)
+  (drop
+   (local.get 0)
+  )
+ )
+)
+(module
+ (type $T (func (param i32) (result i32)))
+ (table 10 funcref)
+ (func $0
+  (drop
+   (call $1)
+  )
+ )
+ (func $1 (result i32)
+  (return_call_indirect (type $T)
+   (i32.const 42)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $T (func (param i32)))
+ (table 10 funcref)
+ (func $0
+  (call $1)
+ )
+ (func $1
+  (return_call_indirect (type $T)
+   (i32.const 42)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $6 (func))
+ (memory $0 1 1)
+ (global $global$0 (mut i32) (i32.const 10))
+ (export "func_102_invoker" (func $19))
+ (func $2 (; 2 ;) (type $6)
+  (if
+   (global.get $global$0)
+   (return)
+  )
+  (global.set $global$0
+   (i32.const 1)
+  )
+ )
+ (func $13 (; 13 ;) (type $6)
+  (if
+   (global.get $global$0)
+   (unreachable)
+  )
+  (return_call $2)
+ )
+ (func $19 (; 19 ;) (type $6)
+  (call $13)
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/passes/inlining_optimize-level=3.txt b/binaryen/test/passes/inlining_optimize-level=3.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/inlining_optimize-level=3.txt
@@ -0,0 +1,156 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $no-loops-but-one-use-but-tabled)
+ (export "yes" (func $yes))
+ (export "no-loops-but-one-use-but-exported" (func $no-loops-but-one-use-but-exported))
+ (func $yes (result i32)
+  (i32.const 1)
+ )
+ (func $no-tooBig (result i32)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (i32.const 1)
+ )
+ (func $no-loops-but-one-use-but-exported (result i32)
+  (loop $loop-in (result i32)
+   (i32.const 1)
+  )
+ )
+ (func $no-loops-but-one-use-but-tabled (result i32)
+  (loop $loop-in (result i32)
+   (i32.const 1)
+  )
+ )
+ (func $intoHere
+  (drop
+   (block (result i32)
+    (block $__inlined_func$yes (result i32)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (call $no-tooBig)
+  )
+  (drop
+   (block (result i32)
+    (block (result i32)
+     (block $__inlined_func$no-calls (result i32)
+      (block (result i32)
+       (block $__inlined_func$yes0 (result i32)
+        (i32.const 1)
+       )
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (block (result i32)
+     (block $__inlined_func$no-calls1 (result i32)
+      (block (result i32)
+       (block $__inlined_func$yes2 (result i32)
+        (i32.const 1)
+       )
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (block (result i32)
+     (block $__inlined_func$yes-calls-but-one-use (result i32)
+      (block (result i32)
+       (block $__inlined_func$yes3 (result i32)
+        (i32.const 1)
+       )
+      )
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (block $__inlined_func$no-loops (result i32)
+     (loop $loop-in (result i32)
+      (i32.const 1)
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (block $__inlined_func$no-loops0 (result i32)
+     (loop $loop-in1 (result i32)
+      (i32.const 1)
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (block $__inlined_func$yes-loops-but-one-use (result i32)
+     (loop $loop-in2 (result i32)
+      (i32.const 1)
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (block $__inlined_func$no-loops-but-one-use-but-exported (result i32)
+     (loop $loop-in3 (result i32)
+      (i32.const 1)
+     )
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (block $__inlined_func$no-loops-but-one-use-but-tabled (result i32)
+     (loop $loop-in4 (result i32)
+      (i32.const 1)
+     )
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/inlining_optimize-level=3.wast b/binaryen/test/passes/inlining_optimize-level=3.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/inlining_optimize-level=3.wast
@@ -0,0 +1,58 @@
+(module
+  (export "yes" (func $yes))
+  (export "no-loops-but-one-use-but-exported" (func $no-loops-but-one-use-but-exported))
+  (table 1 1 funcref)
+  (elem (i32.const 0) $no-loops-but-one-use-but-tabled)
+
+  (func $yes (result i32) ;; inlinable: small, lightweight, even with multi uses and a global use, ok when opt-level=3
+    (i32.const 1)
+  )
+  (func $no-tooBig (result i32)
+    (nop) (nop) (nop) (nop) (nop) (nop)
+    (nop) (nop) (nop) (nop) (nop) (nop)
+    (nop) (nop) (nop) (nop) (nop) (nop)
+    (nop) (nop) (nop) (nop) (nop) (nop)
+    (nop) (nop) (nop) (nop) (nop) (nop)
+    (nop) (nop) (nop) (nop) (nop) (nop)
+    (i32.const 1)
+  )
+  (func $no-calls (result i32)
+    (call $yes)
+  )
+  (func $yes-calls-but-one-use (result i32)
+    (call $yes)
+  )
+  (func $no-loops (result i32)
+    (loop (result i32)
+      (i32.const 1)
+    )
+  )
+  (func $yes-loops-but-one-use (result i32)
+    (loop (result i32)
+      (i32.const 1)
+    )
+  )
+  (func $no-loops-but-one-use-but-exported (result i32)
+    (loop (result i32)
+      (i32.const 1)
+    )
+  )
+  (func $no-loops-but-one-use-but-tabled (result i32)
+    (loop (result i32)
+      (i32.const 1)
+    )
+  )
+  (func $intoHere
+    (drop (call $yes))
+    (drop (call $no-tooBig))
+    (drop (call $no-calls))
+    (drop (call $no-calls))
+    (drop (call $yes-calls-but-one-use))
+    (drop (call $no-loops))
+    (drop (call $no-loops))
+    (drop (call $yes-loops-but-one-use))
+    (drop (call $no-loops-but-one-use-but-exported))
+    (drop (call $no-loops-but-one-use-but-tabled))
+  )
+)
+
diff --git a/binaryen/test/passes/instrument-locals_all-features.txt b/binaryen/test/passes/instrument-locals_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/instrument-locals_all-features.txt
@@ -0,0 +1,269 @@
+(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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/instrument-locals_all-features.wast
@@ -0,0 +1,54 @@
+(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-memory.txt b/binaryen/test/passes/instrument-memory.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/instrument-memory.txt
@@ -0,0 +1,603 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32) (result i32)))
+ (type $i32_i64_=>_i64 (func (param i32 i64) (result i64)))
+ (type $i32_f32_=>_f32 (func (param i32 f32) (result f32)))
+ (type $i32_f64_=>_f64 (func (param i32 f64) (result f64)))
+ (import "env" "load_ptr" (func $load_ptr (param i32 i32 i32 i32) (result i32)))
+ (import "env" "load_val_i32" (func $load_val_i32 (param i32 i32) (result i32)))
+ (import "env" "load_val_i64" (func $load_val_i64 (param i32 i64) (result i64)))
+ (import "env" "load_val_f32" (func $load_val_f32 (param i32 f32) (result f32)))
+ (import "env" "load_val_f64" (func $load_val_f64 (param i32 f64) (result f64)))
+ (import "env" "store_ptr" (func $store_ptr (param i32 i32 i32 i32) (result i32)))
+ (import "env" "store_val_i32" (func $store_val_i32 (param i32 i32) (result i32)))
+ (import "env" "store_val_i64" (func $store_val_i64 (param i32 i64) (result i64)))
+ (import "env" "store_val_f32" (func $store_val_f32 (param i32 f32) (result f32)))
+ (import "env" "store_val_f64" (func $store_val_f64 (param i32 f64) (result f64)))
+ (memory $0 256 256)
+ (func $A
+  (drop
+   (call $load_val_i32
+    (i32.const 1)
+    (i32.load8_s
+     (call $load_ptr
+      (i32.const 1)
+      (i32.const 1)
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 2)
+    (i32.load8_u
+     (call $load_ptr
+      (i32.const 2)
+      (i32.const 1)
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 3)
+    (i32.load16_s
+     (call $load_ptr
+      (i32.const 3)
+      (i32.const 2)
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 4)
+    (i32.load16_u
+     (call $load_ptr
+      (i32.const 4)
+      (i32.const 2)
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 5)
+    (i32.load
+     (call $load_ptr
+      (i32.const 5)
+      (i32.const 4)
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 6)
+    (i64.load8_s
+     (call $load_ptr
+      (i32.const 6)
+      (i32.const 1)
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 7)
+    (i64.load8_u
+     (call $load_ptr
+      (i32.const 7)
+      (i32.const 1)
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 8)
+    (i64.load16_s
+     (call $load_ptr
+      (i32.const 8)
+      (i32.const 2)
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 9)
+    (i64.load16_u
+     (call $load_ptr
+      (i32.const 9)
+      (i32.const 2)
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 10)
+    (i64.load32_s
+     (call $load_ptr
+      (i32.const 10)
+      (i32.const 4)
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 11)
+    (i64.load32_u
+     (call $load_ptr
+      (i32.const 11)
+      (i32.const 4)
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 12)
+    (i64.load
+     (call $load_ptr
+      (i32.const 12)
+      (i32.const 8)
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_f32
+    (i32.const 13)
+    (f32.load
+     (call $load_ptr
+      (i32.const 13)
+      (i32.const 4)
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_f64
+    (i32.const 14)
+    (f64.load
+     (call $load_ptr
+      (i32.const 14)
+      (i32.const 8)
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 15)
+    (i32.load8_s offset=1
+     (call $load_ptr
+      (i32.const 15)
+      (i32.const 1)
+      (i32.const 1)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 16)
+    (i32.load8_u offset=2
+     (call $load_ptr
+      (i32.const 16)
+      (i32.const 1)
+      (i32.const 2)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 17)
+    (i32.load16_s offset=3 align=1
+     (call $load_ptr
+      (i32.const 17)
+      (i32.const 2)
+      (i32.const 3)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 18)
+    (i32.load16_u offset=4 align=1
+     (call $load_ptr
+      (i32.const 18)
+      (i32.const 2)
+      (i32.const 4)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 19)
+    (i32.load offset=5 align=2
+     (call $load_ptr
+      (i32.const 19)
+      (i32.const 4)
+      (i32.const 5)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 20)
+    (i64.load8_s offset=6
+     (call $load_ptr
+      (i32.const 20)
+      (i32.const 1)
+      (i32.const 6)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 21)
+    (i64.load8_u offset=7
+     (call $load_ptr
+      (i32.const 21)
+      (i32.const 1)
+      (i32.const 7)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 22)
+    (i64.load16_s offset=8 align=1
+     (call $load_ptr
+      (i32.const 22)
+      (i32.const 2)
+      (i32.const 8)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 23)
+    (i64.load16_u offset=9 align=1
+     (call $load_ptr
+      (i32.const 23)
+      (i32.const 2)
+      (i32.const 9)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 24)
+    (i64.load32_s offset=10 align=2
+     (call $load_ptr
+      (i32.const 24)
+      (i32.const 4)
+      (i32.const 10)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 25)
+    (i64.load32_u offset=11 align=2
+     (call $load_ptr
+      (i32.const 25)
+      (i32.const 4)
+      (i32.const 11)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 26)
+    (i64.load offset=12 align=2
+     (call $load_ptr
+      (i32.const 26)
+      (i32.const 8)
+      (i32.const 12)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_f32
+    (i32.const 27)
+    (f32.load offset=13 align=2
+     (call $load_ptr
+      (i32.const 27)
+      (i32.const 4)
+      (i32.const 13)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_f64
+    (i32.const 28)
+    (f64.load offset=14 align=2
+     (call $load_ptr
+      (i32.const 28)
+      (i32.const 8)
+      (i32.const 14)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+ )
+ (func $B
+  (i32.store8
+   (call $store_ptr
+    (i32.const 29)
+    (i32.const 1)
+    (i32.const 0)
+    (i32.const 0)
+   )
+   (call $store_val_i32
+    (i32.const 29)
+    (i32.const 1)
+   )
+  )
+  (i32.store16
+   (call $store_ptr
+    (i32.const 30)
+    (i32.const 2)
+    (i32.const 0)
+    (i32.const 0)
+   )
+   (call $store_val_i32
+    (i32.const 30)
+    (i32.const 2)
+   )
+  )
+  (i32.store
+   (call $store_ptr
+    (i32.const 31)
+    (i32.const 4)
+    (i32.const 0)
+    (i32.const 0)
+   )
+   (call $store_val_i32
+    (i32.const 31)
+    (i32.const 3)
+   )
+  )
+  (i64.store8
+   (call $store_ptr
+    (i32.const 32)
+    (i32.const 1)
+    (i32.const 0)
+    (i32.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 32)
+    (i64.const 4)
+   )
+  )
+  (i64.store16
+   (call $store_ptr
+    (i32.const 33)
+    (i32.const 2)
+    (i32.const 0)
+    (i32.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 33)
+    (i64.const 5)
+   )
+  )
+  (i64.store32
+   (call $store_ptr
+    (i32.const 34)
+    (i32.const 4)
+    (i32.const 0)
+    (i32.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 34)
+    (i64.const 6)
+   )
+  )
+  (i64.store
+   (call $store_ptr
+    (i32.const 35)
+    (i32.const 8)
+    (i32.const 0)
+    (i32.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 35)
+    (i64.const 7)
+   )
+  )
+  (f32.store
+   (call $store_ptr
+    (i32.const 36)
+    (i32.const 4)
+    (i32.const 0)
+    (i32.const 0)
+   )
+   (call $store_val_f32
+    (i32.const 36)
+    (f32.const 8)
+   )
+  )
+  (f64.store
+   (call $store_ptr
+    (i32.const 37)
+    (i32.const 8)
+    (i32.const 0)
+    (i32.const 0)
+   )
+   (call $store_val_f64
+    (i32.const 37)
+    (f64.const 9)
+   )
+  )
+  (i32.store8 offset=1
+   (call $store_ptr
+    (i32.const 38)
+    (i32.const 1)
+    (i32.const 1)
+    (i32.const 0)
+   )
+   (call $store_val_i32
+    (i32.const 38)
+    (i32.const 1)
+   )
+  )
+  (i32.store16 offset=2 align=1
+   (call $store_ptr
+    (i32.const 39)
+    (i32.const 2)
+    (i32.const 2)
+    (i32.const 0)
+   )
+   (call $store_val_i32
+    (i32.const 39)
+    (i32.const 2)
+   )
+  )
+  (i32.store offset=3 align=2
+   (call $store_ptr
+    (i32.const 40)
+    (i32.const 4)
+    (i32.const 3)
+    (i32.const 0)
+   )
+   (call $store_val_i32
+    (i32.const 40)
+    (i32.const 3)
+   )
+  )
+  (i64.store8 offset=4
+   (call $store_ptr
+    (i32.const 41)
+    (i32.const 1)
+    (i32.const 4)
+    (i32.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 41)
+    (i64.const 4)
+   )
+  )
+  (i64.store16 offset=5
+   (call $store_ptr
+    (i32.const 42)
+    (i32.const 2)
+    (i32.const 5)
+    (i32.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 42)
+    (i64.const 5)
+   )
+  )
+  (i64.store32 offset=6 align=2
+   (call $store_ptr
+    (i32.const 43)
+    (i32.const 4)
+    (i32.const 6)
+    (i32.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 43)
+    (i64.const 6)
+   )
+  )
+  (i64.store offset=7 align=2
+   (call $store_ptr
+    (i32.const 44)
+    (i32.const 8)
+    (i32.const 7)
+    (i32.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 44)
+    (i64.const 7)
+   )
+  )
+  (f32.store offset=8 align=2
+   (call $store_ptr
+    (i32.const 45)
+    (i32.const 4)
+    (i32.const 8)
+    (i32.const 0)
+   )
+   (call $store_val_f32
+    (i32.const 45)
+    (f32.const 8)
+   )
+  )
+  (f64.store offset=9 align=2
+   (call $store_ptr
+    (i32.const 46)
+    (i32.const 8)
+    (i32.const 9)
+    (i32.const 0)
+   )
+   (call $store_val_f64
+    (i32.const 46)
+    (f64.const 9)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/instrument-memory.wast b/binaryen/test/passes/instrument-memory.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/instrument-memory.wast
@@ -0,0 +1,57 @@
+(module
+  (memory 256 256)
+  (type $1 (func))
+  (func $A (type $1)
+    (drop (i32.load8_s (i32.const 0)))
+    (drop (i32.load8_u (i32.const 0)))
+    (drop (i32.load16_s (i32.const 0)))
+    (drop (i32.load16_u (i32.const 0)))
+    (drop (i32.load (i32.const 0)))
+    (drop (i64.load8_s (i32.const 0)))
+    (drop (i64.load8_u (i32.const 0)))
+    (drop (i64.load16_s (i32.const 0)))
+    (drop (i64.load16_u (i32.const 0)))
+    (drop (i64.load32_s (i32.const 0)))
+    (drop (i64.load32_u (i32.const 0)))
+    (drop (i64.load (i32.const 0)))
+    (drop (f32.load (i32.const 0)))
+    (drop (f64.load (i32.const 0)))
+
+    (drop (i32.load8_s align=1 offset=1 (i32.const 0)))
+    (drop (i32.load8_u align=1 offset=2 (i32.const 0)))
+    (drop (i32.load16_s align=1 offset=3 (i32.const 0)))
+    (drop (i32.load16_u align=1 offset=4 (i32.const 0)))
+    (drop (i32.load align=2 offset=5 (i32.const 0)))
+    (drop (i64.load8_s align=1 offset=6 (i32.const 0)))
+    (drop (i64.load8_u align=1 offset=7 (i32.const 0)))
+    (drop (i64.load16_s align=1 offset=8 (i32.const 0)))
+    (drop (i64.load16_u align=1 offset=9 (i32.const 0)))
+    (drop (i64.load32_s align=2 offset=10 (i32.const 0)))
+    (drop (i64.load32_u align=2 offset=11 (i32.const 0)))
+    (drop (i64.load align=2 offset=12 (i32.const 0)))
+    (drop (f32.load align=2 offset=13 (i32.const 0)))
+    (drop (f64.load align=2 offset=14 (i32.const 0)))
+  )
+
+  (func $B (type $1)
+    (i32.store8 (i32.const 0) (i32.const 1))
+    (i32.store16 (i32.const 0) (i32.const 2))
+    (i32.store (i32.const 0) (i32.const 3))
+    (i64.store8 (i32.const 0) (i64.const 4))
+    (i64.store16 (i32.const 0) (i64.const 5))
+    (i64.store32 (i32.const 0) (i64.const 6))
+    (i64.store (i32.const 0) (i64.const 7))
+    (f32.store (i32.const 0) (f32.const 8))
+    (f64.store (i32.const 0) (f64.const 9))
+
+    (i32.store8 align=1 offset=1 (i32.const 0) (i32.const 1))
+    (i32.store16 align=1 offset=2 (i32.const 0) (i32.const 2))
+    (i32.store align=2 offset=3 (i32.const 0) (i32.const 3))
+    (i64.store8 align=1 offset=4 (i32.const 0) (i64.const 4))
+    (i64.store16 align=2 offset=5 (i32.const 0) (i64.const 5))
+    (i64.store32 align=2 offset=6 (i32.const 0) (i64.const 6))
+    (i64.store align=2 offset=7 (i32.const 0) (i64.const 7))
+    (f32.store align=2 offset=8 (i32.const 0) (f32.const 8))
+    (f64.store align=2 offset=9 (i32.const 0) (f64.const 9))
+  )
+)
diff --git a/binaryen/test/passes/instrument-memory64.passes b/binaryen/test/passes/instrument-memory64.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/instrument-memory64.passes
@@ -0,0 +1,1 @@
+instrument-memory_enable-memory64
diff --git a/binaryen/test/passes/instrument-memory64.txt b/binaryen/test/passes/instrument-memory64.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/instrument-memory64.txt
@@ -0,0 +1,603 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_i32_i64_i64_=>_i64 (func (param i32 i32 i64 i64) (result i64)))
+ (type $i32_i64_=>_i64 (func (param i32 i64) (result i64)))
+ (type $i32_f32_=>_f32 (func (param i32 f32) (result f32)))
+ (type $i32_f64_=>_f64 (func (param i32 f64) (result f64)))
+ (import "env" "load_ptr" (func $load_ptr (param i32 i32 i64 i64) (result i64)))
+ (import "env" "load_val_i32" (func $load_val_i32 (param i32 i32) (result i32)))
+ (import "env" "load_val_i64" (func $load_val_i64 (param i32 i64) (result i64)))
+ (import "env" "load_val_f32" (func $load_val_f32 (param i32 f32) (result f32)))
+ (import "env" "load_val_f64" (func $load_val_f64 (param i32 f64) (result f64)))
+ (import "env" "store_ptr" (func $store_ptr (param i32 i32 i64 i64) (result i64)))
+ (import "env" "store_val_i32" (func $store_val_i32 (param i32 i32) (result i32)))
+ (import "env" "store_val_i64" (func $store_val_i64 (param i32 i64) (result i64)))
+ (import "env" "store_val_f32" (func $store_val_f32 (param i32 f32) (result f32)))
+ (import "env" "store_val_f64" (func $store_val_f64 (param i32 f64) (result f64)))
+ (memory $0 i64 256 256)
+ (func $A
+  (drop
+   (call $load_val_i32
+    (i32.const 1)
+    (i32.load8_s
+     (call $load_ptr
+      (i32.const 1)
+      (i32.const 1)
+      (i64.const 0)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 2)
+    (i32.load8_u
+     (call $load_ptr
+      (i32.const 2)
+      (i32.const 1)
+      (i64.const 0)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 3)
+    (i32.load16_s
+     (call $load_ptr
+      (i32.const 3)
+      (i32.const 2)
+      (i64.const 0)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 4)
+    (i32.load16_u
+     (call $load_ptr
+      (i32.const 4)
+      (i32.const 2)
+      (i64.const 0)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 5)
+    (i32.load
+     (call $load_ptr
+      (i32.const 5)
+      (i32.const 4)
+      (i64.const 0)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 6)
+    (i64.load8_s
+     (call $load_ptr
+      (i32.const 6)
+      (i32.const 1)
+      (i64.const 0)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 7)
+    (i64.load8_u
+     (call $load_ptr
+      (i32.const 7)
+      (i32.const 1)
+      (i64.const 0)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 8)
+    (i64.load16_s
+     (call $load_ptr
+      (i32.const 8)
+      (i32.const 2)
+      (i64.const 0)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 9)
+    (i64.load16_u
+     (call $load_ptr
+      (i32.const 9)
+      (i32.const 2)
+      (i64.const 0)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 10)
+    (i64.load32_s
+     (call $load_ptr
+      (i32.const 10)
+      (i32.const 4)
+      (i64.const 0)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 11)
+    (i64.load32_u
+     (call $load_ptr
+      (i32.const 11)
+      (i32.const 4)
+      (i64.const 0)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 12)
+    (i64.load
+     (call $load_ptr
+      (i32.const 12)
+      (i32.const 8)
+      (i64.const 0)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_f32
+    (i32.const 13)
+    (f32.load
+     (call $load_ptr
+      (i32.const 13)
+      (i32.const 4)
+      (i64.const 0)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_f64
+    (i32.const 14)
+    (f64.load
+     (call $load_ptr
+      (i32.const 14)
+      (i32.const 8)
+      (i64.const 0)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 15)
+    (i32.load8_s offset=1
+     (call $load_ptr
+      (i32.const 15)
+      (i32.const 1)
+      (i64.const 1)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 16)
+    (i32.load8_u offset=2
+     (call $load_ptr
+      (i32.const 16)
+      (i32.const 1)
+      (i64.const 2)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 17)
+    (i32.load16_s offset=3 align=1
+     (call $load_ptr
+      (i32.const 17)
+      (i32.const 2)
+      (i64.const 3)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 18)
+    (i32.load16_u offset=4 align=1
+     (call $load_ptr
+      (i32.const 18)
+      (i32.const 2)
+      (i64.const 4)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i32
+    (i32.const 19)
+    (i32.load offset=5 align=2
+     (call $load_ptr
+      (i32.const 19)
+      (i32.const 4)
+      (i64.const 5)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 20)
+    (i64.load8_s offset=6
+     (call $load_ptr
+      (i32.const 20)
+      (i32.const 1)
+      (i64.const 6)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 21)
+    (i64.load8_u offset=7
+     (call $load_ptr
+      (i32.const 21)
+      (i32.const 1)
+      (i64.const 7)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 22)
+    (i64.load16_s offset=8 align=1
+     (call $load_ptr
+      (i32.const 22)
+      (i32.const 2)
+      (i64.const 8)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 23)
+    (i64.load16_u offset=9 align=1
+     (call $load_ptr
+      (i32.const 23)
+      (i32.const 2)
+      (i64.const 9)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 24)
+    (i64.load32_s offset=10 align=2
+     (call $load_ptr
+      (i32.const 24)
+      (i32.const 4)
+      (i64.const 10)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 25)
+    (i64.load32_u offset=11 align=2
+     (call $load_ptr
+      (i32.const 25)
+      (i32.const 4)
+      (i64.const 11)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_i64
+    (i32.const 26)
+    (i64.load offset=12 align=2
+     (call $load_ptr
+      (i32.const 26)
+      (i32.const 8)
+      (i64.const 12)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_f32
+    (i32.const 27)
+    (f32.load offset=13 align=2
+     (call $load_ptr
+      (i32.const 27)
+      (i32.const 4)
+      (i64.const 13)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (drop
+   (call $load_val_f64
+    (i32.const 28)
+    (f64.load offset=14 align=2
+     (call $load_ptr
+      (i32.const 28)
+      (i32.const 8)
+      (i64.const 14)
+      (i64.const 0)
+     )
+    )
+   )
+  )
+ )
+ (func $B
+  (i32.store8
+   (call $store_ptr
+    (i32.const 29)
+    (i32.const 1)
+    (i64.const 0)
+    (i64.const 0)
+   )
+   (call $store_val_i32
+    (i32.const 29)
+    (i32.const 1)
+   )
+  )
+  (i32.store16
+   (call $store_ptr
+    (i32.const 30)
+    (i32.const 2)
+    (i64.const 0)
+    (i64.const 0)
+   )
+   (call $store_val_i32
+    (i32.const 30)
+    (i32.const 2)
+   )
+  )
+  (i32.store
+   (call $store_ptr
+    (i32.const 31)
+    (i32.const 4)
+    (i64.const 0)
+    (i64.const 0)
+   )
+   (call $store_val_i32
+    (i32.const 31)
+    (i32.const 3)
+   )
+  )
+  (i64.store8
+   (call $store_ptr
+    (i32.const 32)
+    (i32.const 1)
+    (i64.const 0)
+    (i64.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 32)
+    (i64.const 4)
+   )
+  )
+  (i64.store16
+   (call $store_ptr
+    (i32.const 33)
+    (i32.const 2)
+    (i64.const 0)
+    (i64.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 33)
+    (i64.const 5)
+   )
+  )
+  (i64.store32
+   (call $store_ptr
+    (i32.const 34)
+    (i32.const 4)
+    (i64.const 0)
+    (i64.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 34)
+    (i64.const 6)
+   )
+  )
+  (i64.store
+   (call $store_ptr
+    (i32.const 35)
+    (i32.const 8)
+    (i64.const 0)
+    (i64.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 35)
+    (i64.const 7)
+   )
+  )
+  (f32.store
+   (call $store_ptr
+    (i32.const 36)
+    (i32.const 4)
+    (i64.const 0)
+    (i64.const 0)
+   )
+   (call $store_val_f32
+    (i32.const 36)
+    (f32.const 8)
+   )
+  )
+  (f64.store
+   (call $store_ptr
+    (i32.const 37)
+    (i32.const 8)
+    (i64.const 0)
+    (i64.const 0)
+   )
+   (call $store_val_f64
+    (i32.const 37)
+    (f64.const 9)
+   )
+  )
+  (i32.store8 offset=1
+   (call $store_ptr
+    (i32.const 38)
+    (i32.const 1)
+    (i64.const 1)
+    (i64.const 0)
+   )
+   (call $store_val_i32
+    (i32.const 38)
+    (i32.const 1)
+   )
+  )
+  (i32.store16 offset=2 align=1
+   (call $store_ptr
+    (i32.const 39)
+    (i32.const 2)
+    (i64.const 2)
+    (i64.const 0)
+   )
+   (call $store_val_i32
+    (i32.const 39)
+    (i32.const 2)
+   )
+  )
+  (i32.store offset=3 align=2
+   (call $store_ptr
+    (i32.const 40)
+    (i32.const 4)
+    (i64.const 3)
+    (i64.const 0)
+   )
+   (call $store_val_i32
+    (i32.const 40)
+    (i32.const 3)
+   )
+  )
+  (i64.store8 offset=4
+   (call $store_ptr
+    (i32.const 41)
+    (i32.const 1)
+    (i64.const 4)
+    (i64.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 41)
+    (i64.const 4)
+   )
+  )
+  (i64.store16 offset=5
+   (call $store_ptr
+    (i32.const 42)
+    (i32.const 2)
+    (i64.const 5)
+    (i64.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 42)
+    (i64.const 5)
+   )
+  )
+  (i64.store32 offset=6 align=2
+   (call $store_ptr
+    (i32.const 43)
+    (i32.const 4)
+    (i64.const 6)
+    (i64.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 43)
+    (i64.const 6)
+   )
+  )
+  (i64.store offset=7 align=2
+   (call $store_ptr
+    (i32.const 44)
+    (i32.const 8)
+    (i64.const 7)
+    (i64.const 0)
+   )
+   (call $store_val_i64
+    (i32.const 44)
+    (i64.const 7)
+   )
+  )
+  (f32.store offset=8 align=2
+   (call $store_ptr
+    (i32.const 45)
+    (i32.const 4)
+    (i64.const 8)
+    (i64.const 0)
+   )
+   (call $store_val_f32
+    (i32.const 45)
+    (f32.const 8)
+   )
+  )
+  (f64.store offset=9 align=2
+   (call $store_ptr
+    (i32.const 46)
+    (i32.const 8)
+    (i64.const 9)
+    (i64.const 0)
+   )
+   (call $store_val_f64
+    (i32.const 46)
+    (f64.const 9)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/instrument-memory64.wast b/binaryen/test/passes/instrument-memory64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/instrument-memory64.wast
@@ -0,0 +1,57 @@
+(module
+  (memory i64 256 256)
+  (type $1 (func))
+  (func $A (type $1)
+    (drop (i32.load8_s (i64.const 0)))
+    (drop (i32.load8_u (i64.const 0)))
+    (drop (i32.load16_s (i64.const 0)))
+    (drop (i32.load16_u (i64.const 0)))
+    (drop (i32.load (i64.const 0)))
+    (drop (i64.load8_s (i64.const 0)))
+    (drop (i64.load8_u (i64.const 0)))
+    (drop (i64.load16_s (i64.const 0)))
+    (drop (i64.load16_u (i64.const 0)))
+    (drop (i64.load32_s (i64.const 0)))
+    (drop (i64.load32_u (i64.const 0)))
+    (drop (i64.load (i64.const 0)))
+    (drop (f32.load (i64.const 0)))
+    (drop (f64.load (i64.const 0)))
+
+    (drop (i32.load8_s align=1 offset=1 (i64.const 0)))
+    (drop (i32.load8_u align=1 offset=2 (i64.const 0)))
+    (drop (i32.load16_s align=1 offset=3 (i64.const 0)))
+    (drop (i32.load16_u align=1 offset=4 (i64.const 0)))
+    (drop (i32.load align=2 offset=5 (i64.const 0)))
+    (drop (i64.load8_s align=1 offset=6 (i64.const 0)))
+    (drop (i64.load8_u align=1 offset=7 (i64.const 0)))
+    (drop (i64.load16_s align=1 offset=8 (i64.const 0)))
+    (drop (i64.load16_u align=1 offset=9 (i64.const 0)))
+    (drop (i64.load32_s align=2 offset=10 (i64.const 0)))
+    (drop (i64.load32_u align=2 offset=11 (i64.const 0)))
+    (drop (i64.load align=2 offset=12 (i64.const 0)))
+    (drop (f32.load align=2 offset=13 (i64.const 0)))
+    (drop (f64.load align=2 offset=14 (i64.const 0)))
+  )
+
+  (func $B (type $1)
+    (i32.store8 (i64.const 0) (i32.const 1))
+    (i32.store16 (i64.const 0) (i32.const 2))
+    (i32.store (i64.const 0) (i32.const 3))
+    (i64.store8 (i64.const 0) (i64.const 4))
+    (i64.store16 (i64.const 0) (i64.const 5))
+    (i64.store32 (i64.const 0) (i64.const 6))
+    (i64.store (i64.const 0) (i64.const 7))
+    (f32.store (i64.const 0) (f32.const 8))
+    (f64.store (i64.const 0) (f64.const 9))
+
+    (i32.store8 align=1 offset=1 (i64.const 0) (i32.const 1))
+    (i32.store16 align=1 offset=2 (i64.const 0) (i32.const 2))
+    (i32.store align=2 offset=3 (i64.const 0) (i32.const 3))
+    (i64.store8 align=1 offset=4 (i64.const 0) (i64.const 4))
+    (i64.store16 align=2 offset=5 (i64.const 0) (i64.const 5))
+    (i64.store32 align=2 offset=6 (i64.const 0) (i64.const 6))
+    (i64.store align=2 offset=7 (i64.const 0) (i64.const 7))
+    (f32.store align=2 offset=8 (i64.const 0) (f32.const 8))
+    (f64.store align=2 offset=9 (i64.const 0) (f64.const 9))
+  )
+)
diff --git a/binaryen/test/passes/interesting-pass-mix.passes b/binaryen/test/passes/interesting-pass-mix.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/interesting-pass-mix.passes
@@ -0,0 +1,1 @@
+flatten_rereloop_dce_remove-unused-brs_remove-unused-names_coalesce-locals_simplify-locals_reorder-locals_remove-unused-brs_merge-blocks_vacuum
diff --git a/binaryen/test/passes/interesting-pass-mix.txt b/binaryen/test/passes/interesting-pass-mix.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/interesting-pass-mix.txt
@@ -0,0 +1,227 @@
+(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)))
+ (func $trivial
+  (nop)
+ )
+ (func $trivial2
+  (call $trivial)
+  (call $trivial)
+ )
+ (func $return-void
+  (nop)
+ )
+ (func $return-val (result i32)
+  (i32.const 1)
+ )
+ (func $ifs (param $0 i32) (result i32)
+  (if (result i32)
+   (local.get $0)
+   (select
+    (i32.const 2)
+    (i32.const 3)
+    (local.get $0)
+   )
+   (select
+    (i32.const 4)
+    (i32.const 5)
+    (local.get $0)
+   )
+  )
+ )
+ (func $loops (param $0 i32)
+  (if
+   (local.get $0)
+   (loop $shape$2$continue
+    (call $trivial)
+    (br $shape$2$continue)
+   )
+  )
+  (loop $shape$4$continue
+   (call $trivial)
+   (br_if $shape$4$continue
+    (local.get $0)
+   )
+  )
+  (loop $shape$6$continue
+   (call $trivial)
+   (br_if $shape$6$continue
+    (local.get $0)
+   )
+  )
+ )
+ (func $br-out (param $0 i32)
+  (call $br-out
+   (i32.const 5)
+  )
+ )
+ (func $unreachable (param $0 i32)
+  (if
+   (i32.eqz
+    (local.get $0)
+   )
+   (block
+    (call $unreachable
+     (i32.const 5)
+    )
+    (return)
+   )
+  )
+  (if
+   (local.get $0)
+   (block
+    (call $unreachable
+     (i32.const 1)
+    )
+    (unreachable)
+   )
+   (call $unreachable
+    (i32.const 3)
+   )
+  )
+ )
+ (func $empty-blocks (param $0 i32)
+  (nop)
+ )
+ (func $before-and-after (param $0 i32)
+  (call $before-and-after
+   (i32.const 1)
+  )
+  (call $before-and-after
+   (i32.const 2)
+  )
+  (call $before-and-after
+   (i32.const 3)
+  )
+  (call $before-and-after
+   (i32.const 4)
+  )
+  (if
+   (i32.eqz
+    (local.get $0)
+   )
+   (call $before-and-after
+    (i32.const 5)
+   )
+  )
+  (call $before-and-after
+   (i32.const 6)
+  )
+  (call $before-and-after
+   (i32.const 7)
+  )
+  (call $before-and-after
+   (i32.const 8)
+  )
+  (loop $shape$4$continue
+   (call $before-and-after
+    (i32.const 9)
+   )
+   (br_if $shape$4$continue
+    (local.get $0)
+   )
+  )
+  (call $before-and-after
+   (i32.const 10)
+  )
+  (call $before-and-after
+   (i32.const 11)
+  )
+  (if
+   (local.get $0)
+   (call $before-and-after
+    (i32.const 12)
+   )
+  )
+  (call $before-and-after
+   (i32.const 13)
+  )
+  (if
+   (local.get $0)
+   (call $before-and-after
+    (i32.const 14)
+   )
+   (call $before-and-after
+    (i32.const 15)
+   )
+  )
+  (if
+   (local.get $0)
+   (call $before-and-after
+    (i32.const 16)
+   )
+  )
+  (call $before-and-after
+   (i32.const 17)
+  )
+  (call $before-and-after
+   (i32.const 18)
+  )
+  (call $before-and-after
+   (i32.const 19)
+  )
+  (call $before-and-after
+   (i32.const 20)
+  )
+  (call $before-and-after
+   (i32.const 21)
+  )
+  (call $before-and-after
+   (i32.const 22)
+  )
+  (call $before-and-after
+   (i32.const 23)
+  )
+  (call $before-and-after
+   (i32.const 24)
+  )
+  (call $before-and-after
+   (i32.const 25)
+  )
+ )
+ (func $switch (param $0 i32)
+  (call $switch
+   (i32.const 1)
+  )
+  (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)
+    )
+   )
+   (call $switch
+    (i32.const 2)
+   )
+  )
+  (call $switch
+   (i32.const 3)
+  )
+ )
+ (func $no-return
+  (nop)
+ )
+ (func $if-br-wat (param $0 i32)
+  (call $if-br-wat
+   (i32.const 0)
+  )
+  (block $block$2$break
+   (if
+    (local.get $0)
+    (call $if-br-wat
+     (i32.const 1)
+    )
+    (br_if $block$2$break
+     (local.get $0)
+    )
+   )
+   (call $if-br-wat
+    (i32.const 2)
+   )
+  )
+  (call $if-br-wat
+   (i32.const 3)
+  )
+ )
+)
diff --git a/binaryen/test/passes/interesting-pass-mix.wast b/binaryen/test/passes/interesting-pass-mix.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/interesting-pass-mix.wast
@@ -0,0 +1,179 @@
+(module
+  (func $trivial
+    (nop)
+  )
+  (func $trivial2
+    (call $trivial)
+    (call $trivial)
+  )
+  (func $return-void
+    (return)
+  )
+  (func $return-val (result i32)
+    (return (i32.const 1))
+  )
+  (func $ifs (param $x i32) (result i32)
+    (if
+      (local.get $x)
+      (if
+        (local.get $x)
+        (return (i32.const 2))
+        (return (i32.const 3))
+      )
+    )
+    (if
+      (local.get $x)
+      (return (i32.const 4))
+    )
+    (return (i32.const 5))
+  )
+  (func $loops (param $x i32)
+    (if (local.get $x)
+      (loop $top
+        (call $trivial)
+        (br $top)
+      )
+    )
+    (loop $top2
+      (call $trivial)
+      (br_if $top2 (local.get $x))
+    )
+    (loop $top3
+      (call $trivial)
+      (if (local.get $x) (br $top3))
+    )
+  )
+  (func $br-out (param $x i32)
+    (block $out
+      (call $br-out (i32.const 5))
+      (br $out)
+    )
+  )
+  (func $unreachable (param $x i32)
+    (if (local.get $x)
+      (if (local.get $x)
+        (block
+          (call $unreachable (i32.const 1))
+          (unreachable)
+          (call $unreachable (i32.const 2))
+        )
+        (block
+          (call $unreachable (i32.const 3))
+          (return)
+          (call $unreachable (i32.const 4))
+        )
+      )
+    )
+    (block $out
+      (call $unreachable (i32.const 5))
+      (br $out)
+      (call $unreachable (i32.const 6))
+    )
+  )
+  (func $empty-blocks (param $x i32)
+    (block)
+    (block)
+  )
+  (func $before-and-after (param $x i32)
+    (call $before-and-after (i32.const 1))
+    (block
+      (call $before-and-after (i32.const 2))
+    )
+    (call $before-and-after (i32.const 3))
+    (block $out
+      (call $before-and-after (i32.const 4))
+      (br_if $out (local.get $x))
+      (call $before-and-after (i32.const 5))
+    )
+    (call $before-and-after (i32.const 6))
+    (loop)
+    (call $before-and-after (i32.const 7))
+    (loop $top)
+    (call $before-and-after (i32.const 8))
+    (loop $top2
+      (call $before-and-after (i32.const 9))
+      (br_if $top2 (local.get $x))
+      (call $before-and-after (i32.const 10))
+    )
+    (call $before-and-after (i32.const 11))
+    (if (local.get $x)
+      (call $before-and-after (i32.const 12))
+    )
+    (call $before-and-after (i32.const 13))
+    (if (local.get $x)
+      (call $before-and-after (i32.const 14))
+      (call $before-and-after (i32.const 15))
+    )
+    (if (local.get $x)
+      (block
+        (call $before-and-after (i32.const 16))
+      )
+    )
+    (call $before-and-after (i32.const 17))
+    (block
+      (call $before-and-after (i32.const 18))
+      (block
+        (call $before-and-after (i32.const 19))
+      )
+      (call $before-and-after (i32.const 20))
+    )
+    (call $before-and-after (i32.const 21))
+    (block
+      (block
+        (call $before-and-after (i32.const 22))
+      )
+    )
+    (call $before-and-after (i32.const 23))
+    (block $no1
+      (block $no2
+        (call $before-and-after (i32.const 24))
+      )
+    )
+    (call $before-and-after (i32.const 25))
+  )
+  (func $switch (param $x i32)
+    (block $out
+      (block $a
+        (br_table $a $a (local.get $x))
+      )
+      (call $switch (i32.const 1))
+      (block $b
+        (block $c
+          (br_table $b $b $b $c (local.get $x))
+        )
+        (call $switch (i32.const 2))
+      )
+      (call $switch (i32.const 3))
+    )
+  )
+  (func $no-return
+    (if (i32.const 1)
+      (drop (i32.const 2))
+      (drop (i32.const 3))
+    )
+  )
+  (func $if-br-wat (param $x i32)
+   (call $if-br-wat
+    (i32.const 0)
+   )
+   (block $label$2
+    (if
+     (local.get $x)
+     (call $if-br-wat
+      (i32.const 1)
+     )
+     (if
+      (local.get $x)
+      (br $label$2) ;; waka
+     )
+    )
+    (call $if-br-wat
+     (i32.const 2)
+    )
+   )
+   (call $if-br-wat
+    (i32.const 3)
+   )
+  )
+)
+
diff --git a/binaryen/test/passes/legalize-js-interface-minimally.txt b/binaryen/test/passes/legalize-js-interface-minimally.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/legalize-js-interface-minimally.txt
@@ -0,0 +1,59 @@
+(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 $none_=>_i32 (func (result i32)))
+ (import "env" "imported" (func $imported (result i64)))
+ (import "env" "setTempRet0" (func $setTempRet0 (param i32)))
+ (import "env" "invoke_vj" (func $legalimport$invoke_vj (param i32 i32)))
+ (export "func" (func $func))
+ (export "dynCall_foo" (func $legalstub$dyn))
+ (func $func (result i64)
+  (drop
+   (call $imported)
+  )
+  (call $legalfunc$invoke_vj
+   (i64.const 0)
+  )
+  (unreachable)
+ )
+ (func $dyn (result i64)
+  (drop
+   (call $imported)
+  )
+  (unreachable)
+ )
+ (func $legalstub$dyn (result i32)
+  (local $0 i64)
+  (local.set $0
+   (call $dyn)
+  )
+  (call $setTempRet0
+   (i32.wrap_i64
+    (i64.shr_u
+     (local.get $0)
+     (i64.const 32)
+    )
+   )
+  )
+  (i32.wrap_i64
+   (local.get $0)
+  )
+ )
+ (func $legalfunc$invoke_vj (param $0 i64)
+  (call $legalimport$invoke_vj
+   (i32.wrap_i64
+    (local.get $0)
+   )
+   (i32.wrap_i64
+    (i64.shr_u
+     (local.get $0)
+     (i64.const 32)
+    )
+   )
+  )
+ )
+)
+(module
+)
diff --git a/binaryen/test/passes/legalize-js-interface-minimally.wast b/binaryen/test/passes/legalize-js-interface-minimally.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/legalize-js-interface-minimally.wast
@@ -0,0 +1,17 @@
+(module
+  (import "env" "imported" (func $imported (result i64)))
+  (import "env" "invoke_vj" (func $invoke_vj (param i64)))
+  (export "func" (func $func))
+  (export "dynCall_foo" (func $dyn))
+  (func $func (result i64)
+    (drop (call $imported))
+    (call $invoke_vj (i64.const 0))
+    (unreachable)
+  )
+  (func $dyn (result i64)
+    (drop (call $imported))
+    (unreachable)
+  )
+)
+(module)
+
diff --git a/binaryen/test/passes/legalize-js-interface_all-features.txt b/binaryen/test/passes/legalize-js-interface_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/legalize-js-interface_all-features.txt
@@ -0,0 +1,150 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_i64 (func (result i64)))
+ (type $i32_i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32 i32)))
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i64_i64_=>_none (func (param i32 i64 i64)))
+ (import "env" "ref-func-arg" (func $ref-func-arg (result i64)))
+ (import "env" "setTempRet0" (func $setTempRet0 (param i32)))
+ (import "env" "getTempRet0" (func $getTempRet0 (result i32)))
+ (import "env" "imported" (func $legalimport$imported (result i32)))
+ (import "env" "other" (func $legalimport$other (param i32 i32 i32 i32 i32)))
+ (import "env" "ref-func-arg" (func $legalimport$ref-func-arg (result i32)))
+ (export "func" (func $legalstub$func))
+ (export "ref-func-test" (func $ref-func-test))
+ (export "imported" (func $legalstub$imported))
+ (export "imported_again" (func $legalstub$imported))
+ (export "other" (func $legalstub$other))
+ (func $func (result i64)
+  (drop
+   (call $legalfunc$imported)
+  )
+  (call $legalfunc$other
+   (i32.const 0)
+   (i64.const 0)
+   (i64.const 0)
+  )
+  (unreachable)
+ )
+ (func $ref-func-test
+  (drop
+   (call $legalfunc$ref-func-arg)
+  )
+  (drop
+   (ref.func $ref-func-arg)
+  )
+ )
+ (func $legalstub$func (result i32)
+  (local $0 i64)
+  (local.set $0
+   (call $func)
+  )
+  (call $setTempRet0
+   (i32.wrap_i64
+    (i64.shr_u
+     (local.get $0)
+     (i64.const 32)
+    )
+   )
+  )
+  (i32.wrap_i64
+   (local.get $0)
+  )
+ )
+ (func $legalstub$imported (result i32)
+  (local $0 i64)
+  (local.set $0
+   (call $legalfunc$imported)
+  )
+  (call $setTempRet0
+   (i32.wrap_i64
+    (i64.shr_u
+     (local.get $0)
+     (i64.const 32)
+    )
+   )
+  )
+  (i32.wrap_i64
+   (local.get $0)
+  )
+ )
+ (func $legalstub$other (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32)
+  (call $legalfunc$other
+   (local.get $0)
+   (i64.or
+    (i64.extend_i32_u
+     (local.get $1)
+    )
+    (i64.shl
+     (i64.extend_i32_u
+      (local.get $2)
+     )
+     (i64.const 32)
+    )
+   )
+   (i64.or
+    (i64.extend_i32_u
+     (local.get $3)
+    )
+    (i64.shl
+     (i64.extend_i32_u
+      (local.get $4)
+     )
+     (i64.const 32)
+    )
+   )
+  )
+ )
+ (func $legalfunc$imported (result i64)
+  (i64.or
+   (i64.extend_i32_u
+    (call $legalimport$imported)
+   )
+   (i64.shl
+    (i64.extend_i32_u
+     (call $getTempRet0)
+    )
+    (i64.const 32)
+   )
+  )
+ )
+ (func $legalfunc$other (param $0 i32) (param $1 i64) (param $2 i64)
+  (call $legalimport$other
+   (local.get $0)
+   (i32.wrap_i64
+    (local.get $1)
+   )
+   (i32.wrap_i64
+    (i64.shr_u
+     (local.get $1)
+     (i64.const 32)
+    )
+   )
+   (i32.wrap_i64
+    (local.get $2)
+   )
+   (i32.wrap_i64
+    (i64.shr_u
+     (local.get $2)
+     (i64.const 32)
+    )
+   )
+  )
+ )
+ (func $legalfunc$ref-func-arg (result i64)
+  (i64.or
+   (i64.extend_i32_u
+    (call $legalimport$ref-func-arg)
+   )
+   (i64.shl
+    (i64.extend_i32_u
+     (call $getTempRet0)
+    )
+    (i64.const 32)
+   )
+  )
+ )
+)
+(module
+)
diff --git a/binaryen/test/passes/legalize-js-interface_all-features.wast b/binaryen/test/passes/legalize-js-interface_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/legalize-js-interface_all-features.wast
@@ -0,0 +1,31 @@
+(module
+  (import "env" "imported" (func $imported (result i64)))
+  (import "env" "other" (func $other (param i32) (param i64) (param i64)))
+  (import "env" "ref-func-arg" (func $ref-func-arg (result i64)))
+  (export "func" (func $func))
+  (export "ref-func-test" (func $ref-func-test))
+  (export "imported" (func $imported))
+  (export "imported_again" (func $imported))
+  (export "other" (func $other))
+  (func $func (result i64)
+    (drop (call $imported))
+    (call $other
+      (i32.const 0)
+      (i64.const 0)
+      (i64.const 0)
+    )
+    (unreachable)
+  )
+
+  ;; If an import is used in ref.func, even if it is legalized to another
+  ;; import, the original import should not be removed.
+  (func $ref-func-test
+    (drop
+      (call $ref-func-arg)
+    )
+    (drop
+      (ref.func $ref-func-arg)
+    )
+  )
+)
+(module)
diff --git a/binaryen/test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.txt b/binaryen/test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.txt
@@ -0,0 +1,28 @@
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_i64 (func (result i64)))
+ (import "env" "setTempRet0" (func $setTempRet0 (param i32)))
+ (export "func" (func $legalstub$func))
+ (export "orig$func" (func $func))
+ (func $func (result i64)
+  (unreachable)
+ )
+ (func $legalstub$func (result i32)
+  (local $0 i64)
+  (local.set $0
+   (call $func)
+  )
+  (call $setTempRet0
+   (i32.wrap_i64
+    (i64.shr_u
+     (local.get $0)
+     (i64.const 32)
+    )
+   )
+  )
+  (i32.wrap_i64
+   (local.get $0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.wast b/binaryen/test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/legalize-js-interface_pass-arg=legalize-js-interface-export-originals.wast
@@ -0,0 +1,7 @@
+(module
+  (export "func" (func $func))
+  (func $func (result i64)
+    (unreachable)
+  )
+)
+
diff --git a/binaryen/test/passes/licm.txt b/binaryen/test/passes/licm.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/licm.txt
@@ -0,0 +1,695 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_i64 (func (result i64)))
+ (memory $0 1)
+ (global $glob (mut i32) (i32.const 1))
+ (func $loop1
+  (drop
+   (i32.const 10)
+  )
+  (loop $loop
+   (nop)
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $loop2
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 20)
+  )
+  (loop $loop
+   (nop)
+   (nop)
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $loop3
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 20)
+  )
+  (loop $loop
+   (nop)
+   (call $loop2)
+   (nop)
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $loop4
+  (drop
+   (i32.load
+    (i32.const 1)
+   )
+  )
+  (loop $loop
+   (nop)
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $loop3-4
+  (loop $loop
+   (drop
+    (i32.load
+     (i32.const 10)
+    )
+   )
+   (call $loop2)
+   (drop
+    (i32.load
+     (i32.const 20)
+    )
+   )
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $loop3-4-b
+  (drop
+   (i32.load
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 20)
+   )
+  )
+  (loop $loop
+   (nop)
+   (nop)
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $loop5
+  (loop $loop
+   (i32.store
+    (i32.const 1)
+    (i32.const 2)
+   )
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $loop6
+  (loop $loop
+   (i32.store
+    (i32.const 1)
+    (i32.const 2)
+   )
+   (i32.store
+    (i32.const 2)
+    (i32.const 3)
+   )
+  )
+ )
+ (func $loop7
+  (loop $loop
+   (i32.store
+    (i32.const 1)
+    (i32.const 2)
+   )
+   (i32.store
+    (i32.const 2)
+    (i32.const 3)
+   )
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $loop8
+  (loop $loop
+   (i32.store
+    (i32.const 1)
+    (i32.const 2)
+   )
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $loop9
+  (loop $loop
+   (drop
+    (i32.load
+     (i32.const 1)
+    )
+   )
+   (i32.store
+    (i32.const 1)
+    (i32.const 2)
+   )
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $loop10
+  (drop
+   (i32.load
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 2)
+   )
+  )
+  (loop $loop
+   (nop)
+   (nop)
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $loop11
+  (local $x i32)
+  (local $y i32)
+  (loop $loop
+   (drop
+    (local.get $x)
+   )
+   (br_if $loop
+    (local.tee $x
+     (i32.const 2)
+    )
+   )
+  )
+ )
+ (func $loop12
+  (local $x i32)
+  (local $y i32)
+  (drop
+   (local.get $x)
+  )
+  (loop $loop
+   (nop)
+   (br_if $loop
+    (local.tee $y
+     (i32.const 2)
+    )
+   )
+  )
+ )
+ (func $loop13
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.eqz
+    (local.get $y)
+   )
+  )
+  (loop $loop
+   (nop)
+   (call $loop12)
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $loop14
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.eqz
+    (local.get $y)
+   )
+  )
+  (loop $loop
+   (nop)
+   (call $loop12)
+   (br_if $loop
+    (i32.const 1)
+   )
+   (local.set $y
+    (local.get $x)
+   )
+  )
+ )
+ (func $loop14-1
+  (local $x i32)
+  (local $y i32)
+  (loop $loop
+   (local.set $x
+    (i32.eqz
+     (local.get $y)
+    )
+   )
+   (call $loop12)
+   (local.set $y
+    (local.get $x)
+   )
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $loop15
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.eqz
+    (local.get $y)
+   )
+  )
+  (loop $loop
+   (nop)
+   (call $loop12)
+   (br_if $loop
+    (i32.const 1)
+   )
+   (drop
+    (local.get $y)
+   )
+  )
+ )
+ (func $loop15-1
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.eqz
+    (local.get $y)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+  (loop $loop
+   (nop)
+   (call $loop12)
+   (nop)
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $loop16
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.eqz
+    (local.get $y)
+   )
+  )
+  (loop $loop
+   (nop)
+   (call $loop12)
+   (br_if $loop
+    (i32.const 1)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+ )
+ (func $loop16-1
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.eqz
+    (local.get $y)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (loop $loop
+   (nop)
+   (call $loop12)
+   (nop)
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $loop16-2
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.const 2)
+  )
+  (block
+   (local.set $x
+    (i32.eqz
+     (local.get $y)
+    )
+   )
+   (drop
+    (local.get $x)
+   )
+   (loop $loop
+    (nop)
+    (call $loop12)
+    (nop)
+    (br_if $loop
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $loop16-3
+  (local $x i32)
+  (local $y i32)
+  (local.set $y
+   (i32.const 2)
+  )
+  (block
+   (local.set $x
+    (i32.eqz
+     (local.get $y)
+    )
+   )
+   (drop
+    (local.get $x)
+   )
+   (loop $loop
+    (nop)
+    (call $loop12)
+    (nop)
+    (br_if $loop
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $nop
+  (loop $loop
+   (nop)
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $nested-blocks
+  (loop $loop
+   (block $block
+    (nop)
+   )
+   (block $x
+    (nop)
+   )
+   (block $a
+    (block $b
+     (block $c
+      (nop)
+     )
+    )
+   )
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $nested-unhoistable-blocks
+  (loop $loop
+   (block $block
+    (call $nested-unhoistable-blocks)
+   )
+   (block $x
+    (call $nested-unhoistable-blocks)
+   )
+   (block $a
+    (block $b
+     (block $c
+      (call $nested-unhoistable-blocks)
+     )
+    )
+   )
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $conditional
+  (if
+   (i32.const 0)
+   (drop
+    (i32.const 10)
+   )
+  )
+  (loop $loop
+   (nop)
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $conditional1 (result i32)
+  (loop $loop
+   (if
+    (call $conditional1)
+    (drop
+     (i32.const 10)
+    )
+   )
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+  (unreachable)
+ )
+ (func $conditional2
+  (block $out
+   (loop $loop
+    (br_if $out
+     (i32.const 1)
+    )
+    (drop
+     (i32.const 10)
+    )
+    (br_if $loop
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $conditional3
+  (block $out
+   (block
+    (drop
+     (i32.const 10)
+    )
+    (loop $loop
+     (nop)
+     (br_if $out
+      (i32.const 1)
+     )
+     (br_if $loop
+      (i32.const 1)
+     )
+    )
+   )
+  )
+ )
+ (func $after
+  (loop $loop
+   (nop)
+  )
+  (drop
+   (i32.const 10)
+  )
+ )
+ (func $loops
+  (drop
+   (i32.const 10)
+  )
+  (loop $loop2
+   (nop)
+   (loop $loop1
+    (nop)
+    (br_if $loop1
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $loops2
+  (drop
+   (i32.const 10)
+  )
+  (loop $loop2
+   (nop)
+   (loop $loop1
+    (nop)
+    (br_if $loop2
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $fuzz1 (result i64)
+  (local $var$1 i64)
+  (drop
+   (block (result i32)
+    (local.set $var$1
+     (block $label$5 (result i64)
+      (local.set $var$1
+       (i64.const -29585)
+      )
+      (i64.const -70)
+     )
+    )
+    (loop $label$4 (result i32)
+     (nop)
+     (i32.const 1)
+    )
+   )
+  )
+  (loop $label$1 (result i64)
+   (block $label$2
+    (block $label$3
+     (nop)
+     (br $label$2)
+    )
+    (unreachable)
+   )
+   (local.get $var$1)
+  )
+ )
+ (func $self (result i32)
+  (local $x i32)
+  (loop $loop
+   (local.set $x
+    (i32.add
+     (local.get $x)
+     (i32.const 1)
+    )
+   )
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+  (local.get $x)
+ )
+ (func $nested-set
+  (local $var$0 i32)
+  (local $var$1 i64)
+  (loop $label$1
+   (local.set $var$0
+    (block $label$3 (result i32)
+     (local.set $var$1
+      (i64.const 0)
+     )
+     (local.get $var$0)
+    )
+   )
+   (local.set $var$1
+    (i64.const 1)
+   )
+   (br_if $label$1
+    (i32.const 0)
+   )
+  )
+ )
+ (func $load-store (param $x i32)
+  (loop $loop
+   (drop
+    (i32.load
+     (i32.const 0)
+    )
+   )
+   (i32.store
+    (local.get $x)
+    (local.get $x)
+   )
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $set-set (param $x i32) (result i32)
+  (loop $loop
+   (local.set $x
+    (i32.const 1)
+   )
+   (br_if $loop
+    (i32.const 2)
+   )
+   (local.set $x
+    (i32.const 3)
+   )
+   (br_if $loop
+    (i32.const 4)
+   )
+  )
+  (local.get $x)
+ )
+ (func $copies-no
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (local $a i32)
+  (local $b i32)
+  (local $c i32)
+  (loop $loop
+   (local.set $x
+    (local.get $x)
+   )
+   (local.set $y
+    (local.get $z)
+   )
+   (local.set $a
+    (local.tee $b
+     (local.get $c)
+    )
+   )
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $consts-no
+  (local $x i32)
+  (local $a i32)
+  (local $b i32)
+  (loop $loop
+   (local.set $x
+    (i32.const 0)
+   )
+   (local.set $a
+    (local.tee $b
+     (i32.const 1)
+    )
+   )
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+ (func $global
+  (local $x i32)
+  (local.set $x
+   (global.get $glob)
+  )
+  (drop
+   (local.get $x)
+  )
+  (loop $loop
+   (nop)
+   (nop)
+   (br_if $loop
+    (local.get $x)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/licm.wast b/binaryen/test/passes/licm.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/licm.wast
@@ -0,0 +1,401 @@
+(module
+  (memory 1)
+  (global $glob (mut i32) (i32.const 1))
+  (func $loop1
+    (loop $loop
+      (drop (i32.const 10))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $loop2
+    (loop $loop
+      (drop (i32.const 10))
+      (drop (i32.const 20))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $loop3
+    (loop $loop
+      (drop (i32.const 10))
+      (call $loop2)
+      (drop (i32.const 20))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $loop4
+    (loop $loop
+      (drop (i32.load (i32.const 1)))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $loop3-4
+    (loop $loop
+      (drop (i32.load (i32.const 10)))
+      (call $loop2) ;; may have global side effects which alter a load!
+      (drop (i32.load (i32.const 20))) ;; this load must stay put
+      (br_if $loop (i32.const 1))
+    )
+  )
+ (func $loop3-4-b (; 4 ;)
+  (loop $loop
+   (drop
+    (i32.load
+     (i32.const 10)
+    )
+   )
+   (drop
+    (i32.load
+     (i32.const 20)
+    )
+   )
+   (br_if $loop
+    (i32.const 1)
+   )
+  )
+ )
+  (func $loop5
+    (loop $loop
+      (i32.store (i32.const 1) (i32.const 2))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $loop6
+    (loop $loop
+      (i32.store (i32.const 1) (i32.const 2))
+      (i32.store (i32.const 2) (i32.const 3))
+    )
+  )
+  (func $loop7
+    (loop $loop
+      (i32.store (i32.const 1) (i32.const 2))
+      (i32.store (i32.const 2) (i32.const 3))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $loop8
+    (loop $loop
+      (i32.store (i32.const 1) (i32.const 2))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $loop9
+    (loop $loop
+      (drop (i32.load (i32.const 1)))
+      (i32.store (i32.const 1) (i32.const 2))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $loop10
+    (loop $loop
+      (drop (i32.load (i32.const 1)))
+      (drop (i32.load (i32.const 2)))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $loop11
+    (local $x i32)
+    (local $y i32)
+    (loop $loop
+      (drop (local.get $x))
+      (br_if $loop (local.tee $x (i32.const 2)))
+    )
+  )
+  (func $loop12
+    (local $x i32)
+    (local $y i32)
+    (loop $loop
+      (drop (local.get $x))
+      (br_if $loop (local.tee $y (i32.const 2)))
+    )
+  )
+  (func $loop13
+    (local $x i32)
+    (local $y i32)
+    (loop $loop
+      (local.set $x (i32.eqz (local.get $y)))
+      (call $loop12)
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $loop14
+    (local $x i32)
+    (local $y i32)
+    (loop $loop
+      (local.set $x (i32.eqz (local.get $y)))
+      (call $loop12)
+      (br_if $loop (i32.const 1))
+      (local.set $y (local.get $x)) ;; not actually in the loop!
+    )
+  )
+  (func $loop14-1
+    (local $x i32)
+    (local $y i32)
+    (loop $loop
+      (local.set $x (i32.eqz (local.get $y)))
+      (call $loop12)
+      (local.set $y (local.get $x)) ;; in the loop
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $loop15
+    (local $x i32)
+    (local $y i32)
+    (loop $loop
+      (local.set $x (i32.eqz (local.get $y)))
+      (call $loop12)
+      (br_if $loop (i32.const 1))
+      (drop (local.get $y))
+    )
+  )
+  (func $loop15-1
+    (local $x i32)
+    (local $y i32)
+    (loop $loop
+      (local.set $x (i32.eqz (local.get $y)))
+      (call $loop12)
+      (drop (local.get $y))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $loop16
+    (local $x i32)
+    (local $y i32)
+    (loop $loop
+      (local.set $x (i32.eqz (local.get $y)))
+      (call $loop12)
+      (br_if $loop (i32.const 1))
+      (drop (local.get $x))
+    )
+  )
+  (func $loop16-1
+    (local $x i32)
+    (local $y i32)
+    (loop $loop
+      (local.set $x (i32.eqz (local.get $y)))
+      (call $loop12)
+      (drop (local.get $x))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $loop16-2
+    (local $x i32)
+    (local $y i32)
+    (local.set $x (i32.const 2))
+    (loop $loop
+      (local.set $x (i32.eqz (local.get $y)))
+      (call $loop12)
+      (drop (local.get $x))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $loop16-3
+    (local $x i32)
+    (local $y i32)
+    (local.set $y (i32.const 2))
+    (loop $loop
+      (local.set $x (i32.eqz (local.get $y)))
+      (call $loop12)
+      (drop (local.get $x))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $nop
+    (loop $loop
+      (nop)
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $nested-blocks
+    (loop $loop
+      (block
+        (nop)
+      )
+      (block $x
+        (nop)
+      )
+      (block $a
+        (block $b
+          (block $c
+            (nop)
+          )
+        )
+      )
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $nested-unhoistable-blocks
+    (loop $loop
+      (block
+        (call $nested-unhoistable-blocks)
+      )
+      (block $x
+        (call $nested-unhoistable-blocks)
+      )
+      (block $a
+        (block $b
+          (block $c
+            (call $nested-unhoistable-blocks)
+          )
+        )
+      )
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $conditional
+    (loop $loop
+      (if (i32.const 0)
+        (drop (i32.const 10)) ;; cannot be hoisted - might never be reached
+      )
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $conditional1 (result i32)
+    (loop $loop
+      (if (call $conditional1)
+        (drop (i32.const 10)) ;; cannot be hoisted - might never be reached
+                              ;; also anyhow the whole if also cannot, due to the call
+      )
+      (br_if $loop (i32.const 1))
+    )
+    (unreachable)
+  )
+  (func $conditional2
+    (block $out
+      (loop $loop
+        (br_if $out (i32.const 1))
+        (drop (i32.const 10)) ;; cannot be hoisted - might never be reached
+        (br_if $loop (i32.const 1))
+      )
+    )
+  )
+  (func $conditional3
+    (block $out
+      (loop $loop
+        (drop (i32.const 10)) ;; *CAN* be hoisted - will definitely be reached
+        (br_if $out (i32.const 1))
+        (br_if $loop (i32.const 1))
+      )
+    )
+  )
+  (func $after
+    (loop $loop)
+    (drop (i32.const 10)) ;; may be part of the loop's basic block, logically, but is not nested in it
+  )
+  (func $loops
+    (loop $loop2
+      (loop $loop1
+        (drop (i32.const 10))
+        (br_if $loop1 (i32.const 1))
+      )
+    )
+  )
+  (func $loops2
+    (loop $loop2
+      (loop $loop1
+        (drop (i32.const 10))
+        (br_if $loop2 (i32.const 1))
+      )
+    )
+  )
+  (func $fuzz1 (result i64)
+   (local $var$1 i64)
+   (loop $label$1 (result i64) ;; multiple loops here require us to be careful not to Nop out stuff before we finalize things
+    (block $label$2
+     (block $label$3
+      (drop
+       (loop $label$4 (result i32)
+        (local.set $var$1
+         (block $label$5 (result i64)
+          (local.set $var$1
+           (i64.const -29585)
+          )
+          (i64.const -70)
+         )
+        )
+        (i32.const 1)
+       )
+      )
+      (br $label$2)
+     )
+     (unreachable)
+    )
+    (local.get $var$1)
+   )
+  )
+  (func $self (result i32)
+    (local $x i32)
+    (loop $loop
+      (local.set $x (i32.add (local.get $x) (i32.const 1)))
+      (br_if $loop (i32.const 1))
+    )
+    (local.get $x)
+  )
+  (func $nested-set
+   (local $var$0 i32)
+   (local $var$1 i64)
+   (loop $label$1
+    (local.set $var$0
+     (block $label$3 (result i32)
+      (local.set $var$1 ;; cannot be moved out (in current position - other opts would help), and invalidates moving out the set below
+       (i64.const 0)
+      )
+      (local.get $var$0)
+     )
+    )
+    (local.set $var$1
+     (i64.const 1)
+    )
+    (br_if $label$1
+     (i32.const 0)
+    )
+   )
+  )
+  (func $load-store (param $x i32)
+    (loop $loop
+      (drop (i32.load (i32.const 0))) ;; can't move this out, the store might affect it for later iterations
+      (i32.store (local.get $x) (local.get $x))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $set-set (param $x i32) (result i32)
+    (loop $loop
+      (local.set $x (i32.const 1))
+      (br_if $loop (i32.const 2))
+      (local.set $x (i32.const 3))
+      (br_if $loop (i32.const 4))
+    )
+    (local.get $x)
+  )
+  (func $copies-no
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local $a i32)
+    (local $b i32)
+    (local $c i32)
+    (loop $loop
+      (local.set $x (local.get $x))
+      (local.set $y (local.get $z))
+      (local.set $a (local.tee $b (local.get $c)))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $consts-no
+    (local $x i32)
+    (local $a i32)
+    (local $b i32)
+    (loop $loop
+      (local.set $x (i32.const 0))
+      (local.set $a (local.tee $b (i32.const 1)))
+      (br_if $loop (i32.const 1))
+    )
+  )
+  (func $global
+    (local $x i32)
+    (loop $loop
+      (local.set $x (global.get $glob))
+      (drop (local.get $x))
+      (br_if $loop (local.get $x))
+    )
+  )
+)
diff --git a/binaryen/test/passes/limit-segments_disable-bulk-memory.txt b/binaryen/test/passes/limit-segments_disable-bulk-memory.txt
new file mode 100644
# file too large to diff: binaryen/test/passes/limit-segments_disable-bulk-memory.txt
diff --git a/binaryen/test/passes/limit-segments_disable-bulk-memory.wast b/binaryen/test/passes/limit-segments_disable-bulk-memory.wast
new file mode 100644
# file too large to diff: binaryen/test/passes/limit-segments_disable-bulk-memory.wast
diff --git a/binaryen/test/passes/log-execution.txt b/binaryen/test/passes/log-execution.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/log-execution.txt
@@ -0,0 +1,98 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "func" (func $import))
+ (import "env" "log_execution" (func $log_execution (param i32)))
+ (func $nopp
+  (call $log_execution
+   (i32.const 0)
+  )
+  (nop)
+ )
+ (func $intt (result i32)
+  (call $log_execution
+   (i32.const 1)
+  )
+  (i32.const 10)
+ )
+ (func $workk
+  (call $log_execution
+   (i32.const 3)
+  )
+  (block
+   (if
+    (i32.const 0)
+    (nop)
+   )
+   (block
+    (call $log_execution
+     (i32.const 2)
+    )
+    (drop
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $loops
+  (call $log_execution
+   (i32.const 8)
+  )
+  (block
+   (loop $x
+    (call $log_execution
+     (i32.const 4)
+    )
+    (block
+     (call $loops)
+     (br $x)
+    )
+   )
+   (if
+    (call $intt)
+    (loop $y
+     (call $log_execution
+      (i32.const 5)
+     )
+     (call $loops)
+    )
+   )
+   (block
+    (call $log_execution
+     (i32.const 7)
+    )
+    (loop $loop-in
+     (call $log_execution
+      (i32.const 6)
+     )
+     (block
+      (drop
+       (i32.const 10)
+      )
+      (drop
+       (i32.const 20)
+      )
+      (drop
+       (i32.const 30)
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $loops-similar
+  (call $log_execution
+   (i32.const 10)
+  )
+  (loop $x
+   (call $log_execution
+    (i32.const 9)
+   )
+   (block
+    (call $loops)
+    (br $x)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/log-execution.wast b/binaryen/test/passes/log-execution.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/log-execution.wast
@@ -0,0 +1,36 @@
+(module
+  (import "env" "func" (func $import))
+  (func $nopp
+    (nop)
+  )
+  (func $intt (result i32)
+    (i32.const 10)
+  )
+  (func $workk
+    (if (i32.const 0) (nop))
+    (drop (i32.const 1))
+  )
+  (func $loops
+    (loop $x
+      (call $loops)
+      (br $x)
+    )
+    (if (call $intt)
+      (loop $y
+        (call $loops)
+      )
+    )
+    (loop
+      (drop (i32.const 10))
+      (drop (i32.const 20))
+      (drop (i32.const 30))
+    )
+  )
+  (func $loops-similar
+    (loop $x
+      (call $loops)
+      (br $x)
+    )
+  )
+)
+
diff --git a/binaryen/test/passes/memory-packing_all-features.txt b/binaryen/test/passes/memory-packing_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/memory-packing_all-features.txt
@@ -0,0 +1,1507 @@
+(module
+ (import "env" "memory" (memory $0 2048 2048))
+ (import "env" "memoryBase" (global $memoryBase i32))
+)
+(module
+ (import "env" "memory" (memory $0 2048 2048))
+ (import "env" "memoryBase" (global $memoryBase i32))
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "memory" (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")
+ (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")
+ (data (i32.const 3000) "zeros after")
+ (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
+    (i32.const 42)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 13)
+   )
+   (unreachable)
+  )
+  (nop)
+ )
+ (func $nonzero-offset-init-of-active-will-trap
+  (block
+   (drop
+    (i32.const 42)
+   )
+   (drop
+    (i32.const 13)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (unreachable)
+  )
+  (nop)
+ )
+ (func $zero-offset-size-init-of-active-may-trap
+  (if
+   (i32.gt_u
+    (i32.const 42)
+    (i32.shl
+     (memory.size)
+     (i32.const 16)
+    )
+   )
+   (unreachable)
+  )
+  (nop)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "memory" (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")
+ (data passive "zeroes at end")
+ (data passive "zeroes at end\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00")
+ (data passive "few zeroes at end\00\00\00")
+ (data passive "zeroes")
+ (data passive "in middle")
+ (data passive "zeroes\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00in middle")
+ (data passive "few zeroes\00\00\00in middle")
+ (data passive "multiple")
+ (data passive "spans")
+ (data passive "of zeroes")
+ (data passive "even")
+ (data passive "more")
+ (data passive "zeroes")
+ (data passive "no zeroes")
+ (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)
+    (unreachable)
+   )
+   (memory.fill
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 0
+    (i32.const 30)
+    (i32.const 0)
+    (i32.const 15)
+   )
+  )
+  (block
+   (global.set $__mem_segment_drop_state_0
+    (i32.const 1)
+   )
+   (data.drop 0)
+  )
+ )
+ (func $zeroes-at-start-not-split
+  (memory.init 1
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 45)
+  )
+  (memory.init 1
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 45)
+  )
+  (memory.init 1
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 45)
+  )
+  (memory.init 1
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 45)
+  )
+  (data.drop 1)
+ )
+ (func $few-zeroes-at-start
+  (memory.init 2
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 22)
+  )
+  (data.drop 2)
+ )
+ (func $zeroes-at-end
+  (block
+   (memory.init 3
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 13)
+   )
+   (memory.fill
+    (i32.const 13)
+    (i32.const 0)
+    (i32.const 30)
+   )
+  )
+  (data.drop 3)
+ )
+ (func $zeroes-at-end-not-split
+  (memory.init 4
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 43)
+  )
+  (memory.init 4
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 43)
+  )
+  (memory.init 4
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 43)
+  )
+  (memory.init 4
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 43)
+  )
+  (data.drop 4)
+ )
+ (func $few-zeroes-at-end
+  (memory.init 5
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 20)
+  )
+  (data.drop 5)
+ )
+ (func $zeroes-in-middle
+  (block
+   (memory.init 6
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 6)
+   )
+   (memory.fill
+    (i32.const 6)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 7
+    (i32.const 36)
+    (i32.const 0)
+    (i32.const 9)
+   )
+  )
+  (block
+   (data.drop 6)
+   (data.drop 7)
+  )
+ )
+ (func $zeroes-in-middle-not-split
+  (memory.init 8
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 35)
+  )
+  (memory.init 8
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 45)
+  )
+  (data.drop 8)
+ )
+ (func $few-zeroes-in-middle
+  (memory.init 9
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 22)
+  )
+  (data.drop 9)
+ )
+ (func $multiple-spans-of-zeroes
+  (block
+   (memory.init 10
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 8)
+   )
+   (memory.fill
+    (i32.const 8)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 11
+    (i32.const 38)
+    (i32.const 0)
+    (i32.const 5)
+   )
+   (memory.fill
+    (i32.const 43)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 12
+    (i32.const 73)
+    (i32.const 0)
+    (i32.const 9)
+   )
+  )
+  (block
+   (data.drop 10)
+   (data.drop 11)
+   (data.drop 12)
+  )
+ )
+ (func $even-more-zeroes
+  (block
+   (if
+    (global.get $__mem_segment_drop_state_1)
+    (unreachable)
+   )
+   (memory.fill
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 13
+    (i32.const 30)
+    (i32.const 0)
+    (i32.const 4)
+   )
+   (memory.fill
+    (i32.const 34)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 14
+    (i32.const 64)
+    (i32.const 0)
+    (i32.const 4)
+   )
+   (memory.fill
+    (i32.const 68)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 15
+    (i32.const 98)
+    (i32.const 0)
+    (i32.const 6)
+   )
+   (memory.fill
+    (i32.const 104)
+    (i32.const 0)
+    (i32.const 30)
+   )
+  )
+  (block
+   (global.set $__mem_segment_drop_state_1
+    (i32.const 1)
+   )
+   (data.drop 13)
+   (data.drop 14)
+   (data.drop 15)
+  )
+ )
+ (func $only-zeroes
+  (block
+   (if
+    (global.get $__mem_segment_drop_state_2)
+    (unreachable)
+   )
+   (memory.fill
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 30)
+   )
+  )
+  (global.set $__mem_segment_drop_state_2
+   (i32.const 1)
+  )
+ )
+ (func $no-zeroes
+  (memory.init 16
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 9)
+  )
+  (data.drop 16)
+ )
+ (func $empty
+  (if
+   (i32.gt_u
+    (i32.const 13)
+    (i32.shl
+     (memory.size)
+     (i32.const 16)
+    )
+   )
+   (unreachable)
+  )
+  (nop)
+ )
+ (func $only-dropped
+  (nop)
+  (nop)
+ )
+ (func $only-dropped-zeroes
+  (nop)
+  (nop)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "memory" (memory $0 2048 2048))
+ (data passive "even")
+ (data passive "more")
+ (data passive "zeroes")
+ (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")
+ (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")
+ (data passive "even")
+ (data passive "more")
+ (data passive "zeroes")
+ (data passive "even")
+ (data passive "more")
+ (data passive "zeroes")
+ (data passive "even")
+ (data passive "more")
+ (data passive "zeroes")
+ (data passive "even")
+ (data passive "more")
+ (data passive "zeroes")
+ (data passive "even")
+ (data passive "more")
+ (data passive "zeroes")
+ (data passive "even")
+ (data passive "more")
+ (data passive "zeroes")
+ (data passive "even")
+ (data passive "more")
+ (data passive "zeroes")
+ (data passive "even")
+ (data passive "more")
+ (data passive "zeroes")
+ (data passive "even")
+ (data passive "more")
+ (data passive "zeroes")
+ (import "env" "param" (global $param i32))
+ (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))
+ (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
+   (local.set $0
+    (global.get $param)
+   )
+   (if
+    (global.get $__mem_segment_drop_state_0)
+    (unreachable)
+   )
+   (memory.fill
+    (local.get $0)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 0
+    (i32.add
+     (local.get $0)
+     (i32.const 30)
+    )
+    (i32.const 0)
+    (i32.const 4)
+   )
+   (memory.fill
+    (i32.add
+     (local.get $0)
+     (i32.const 34)
+    )
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 1
+    (i32.add
+     (local.get $0)
+     (i32.const 64)
+    )
+    (i32.const 0)
+    (i32.const 4)
+   )
+   (memory.fill
+    (i32.add
+     (local.get $0)
+     (i32.const 68)
+    )
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 2
+    (i32.add
+     (local.get $0)
+     (i32.const 98)
+    )
+    (i32.const 0)
+    (i32.const 6)
+   )
+   (memory.fill
+    (i32.add
+     (local.get $0)
+     (i32.const 104)
+    )
+    (i32.const 0)
+    (i32.const 30)
+   )
+  )
+  (block
+   (global.set $__mem_segment_drop_state_0
+    (i32.const 1)
+   )
+   (data.drop 0)
+   (data.drop 1)
+   (data.drop 2)
+  )
+ )
+ (func $nonconst-offset
+  (memory.init 3
+   (i32.const 0)
+   (global.get $param)
+   (i32.const 134)
+  )
+  (data.drop 3)
+ )
+ (func $nonconst-size
+  (memory.init 4
+   (i32.const 0)
+   (i32.const 0)
+   (global.get $param)
+  )
+  (data.drop 4)
+ )
+ (func $partial-skip-start
+  (block
+   (if
+    (global.get $__mem_segment_drop_state_1)
+    (unreachable)
+   )
+   (memory.fill
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 20)
+   )
+   (memory.init 5
+    (i32.const 20)
+    (i32.const 0)
+    (i32.const 4)
+   )
+   (memory.fill
+    (i32.const 24)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 6
+    (i32.const 54)
+    (i32.const 0)
+    (i32.const 4)
+   )
+   (memory.fill
+    (i32.const 58)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 7
+    (i32.const 88)
+    (i32.const 0)
+    (i32.const 6)
+   )
+   (memory.fill
+    (i32.const 94)
+    (i32.const 0)
+    (i32.const 30)
+   )
+  )
+  (block
+   (global.set $__mem_segment_drop_state_1
+    (i32.const 1)
+   )
+   (data.drop 5)
+   (data.drop 6)
+   (data.drop 7)
+  )
+ )
+ (func $full-skip-start
+  (block
+   (memory.init 8
+    (i32.const 0)
+    (i32.const 2)
+    (i32.const 2)
+   )
+   (memory.fill
+    (i32.const 2)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 9
+    (i32.const 32)
+    (i32.const 0)
+    (i32.const 4)
+   )
+   (memory.fill
+    (i32.const 36)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 10
+    (i32.const 66)
+    (i32.const 0)
+    (i32.const 6)
+   )
+   (memory.fill
+    (i32.const 72)
+    (i32.const 0)
+    (i32.const 30)
+   )
+  )
+  (block
+   (data.drop 8)
+   (data.drop 9)
+   (data.drop 10)
+  )
+ )
+ (func $partial-skip-end
+  (block
+   (if
+    (global.get $__mem_segment_drop_state_2)
+    (unreachable)
+   )
+   (memory.fill
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 11
+    (i32.const 30)
+    (i32.const 0)
+    (i32.const 4)
+   )
+   (memory.fill
+    (i32.const 34)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 12
+    (i32.const 64)
+    (i32.const 0)
+    (i32.const 4)
+   )
+   (memory.fill
+    (i32.const 68)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 13
+    (i32.const 98)
+    (i32.const 0)
+    (i32.const 6)
+   )
+   (memory.fill
+    (i32.const 104)
+    (i32.const 0)
+    (i32.const 20)
+   )
+  )
+  (block
+   (global.set $__mem_segment_drop_state_2
+    (i32.const 1)
+   )
+   (data.drop 11)
+   (data.drop 12)
+   (data.drop 13)
+  )
+ )
+ (func $full-skip-end
+  (block
+   (if
+    (global.get $__mem_segment_drop_state_3)
+    (unreachable)
+   )
+   (memory.fill
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 14
+    (i32.const 30)
+    (i32.const 0)
+    (i32.const 4)
+   )
+   (memory.fill
+    (i32.const 34)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 15
+    (i32.const 64)
+    (i32.const 0)
+    (i32.const 4)
+   )
+   (memory.fill
+    (i32.const 68)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 16
+    (i32.const 98)
+    (i32.const 0)
+    (i32.const 4)
+   )
+  )
+  (block
+   (global.set $__mem_segment_drop_state_3
+    (i32.const 1)
+   )
+   (data.drop 14)
+   (data.drop 15)
+   (data.drop 16)
+  )
+ )
+ (func $slice-zeroes
+  (block
+   (if
+    (global.get $__mem_segment_drop_state_4)
+    (unreachable)
+   )
+   (memory.fill
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 10)
+   )
+  )
+  (block
+   (global.set $__mem_segment_drop_state_4
+    (i32.const 1)
+   )
+   (data.drop 17)
+   (data.drop 18)
+   (data.drop 19)
+  )
+ )
+ (func $slice-nonzeroes
+  (memory.init 20
+   (i32.const 0)
+   (i32.const 1)
+   (i32.const 2)
+  )
+  (block
+   (data.drop 20)
+   (data.drop 21)
+   (data.drop 22)
+  )
+ )
+ (func $zero-size
+  (if
+   (i32.or
+    (i32.gt_u
+     (i32.const 13)
+     (i32.shl
+      (memory.size)
+      (i32.const 16)
+     )
+    )
+    (global.get $__mem_segment_drop_state_5)
+   )
+   (unreachable)
+  )
+  (block
+   (global.set $__mem_segment_drop_state_5
+    (i32.const 1)
+   )
+   (data.drop 23)
+   (data.drop 24)
+   (data.drop 25)
+  )
+ )
+ (func $zero-size-undropped
+  (if
+   (i32.or
+    (i32.gt_u
+     (i32.const 13)
+     (i32.shl
+      (memory.size)
+      (i32.const 16)
+     )
+    )
+    (global.get $__mem_segment_drop_state_6)
+   )
+   (unreachable)
+  )
+ )
+ (func $out-of-bounds-offset
+  (block
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 135)
+   )
+   (drop
+    (i32.const 1)
+   )
+   (unreachable)
+  )
+  (nop)
+ )
+ (func $zero-size-out-of-bounds-offset
+  (block
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 135)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (unreachable)
+  )
+  (nop)
+ )
+ (func $out-of-bounds-size
+  (block
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 135)
+   )
+   (unreachable)
+  )
+  (nop)
+ )
+ (func $zero-size-at-bounds-offset
+  (if
+   (i32.or
+    (i32.gt_u
+     (i32.const 0)
+     (i32.shl
+      (memory.size)
+      (i32.const 16)
+     )
+    )
+    (global.get $__mem_segment_drop_state_7)
+   )
+   (unreachable)
+  )
+  (block
+   (global.set $__mem_segment_drop_state_7
+    (i32.const 1)
+   )
+   (data.drop 29)
+   (data.drop 30)
+   (data.drop 31)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "memory" (memory $0 2048 2048))
+ (data passive "hi")
+ (data passive "even")
+ (data passive "hi")
+ (data passive "hi")
+ (data passive "even")
+ (data passive "hi")
+ (data passive "even")
+ (data passive "hi")
+ (data passive "even")
+ (data passive "hi")
+ (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
+    (i32.gt_u
+     (i32.const 13)
+     (i32.shl
+      (memory.size)
+      (i32.const 16)
+     )
+    )
+    (global.get $__mem_segment_drop_state_0)
+   )
+   (unreachable)
+  )
+  (block
+   (global.set $__mem_segment_drop_state_0
+    (i32.const 1)
+   )
+   (data.drop 0)
+   (data.drop 1)
+   (data.drop 2)
+  )
+ )
+ (func $zero-length-init-nonzeroes
+  (if
+   (i32.or
+    (i32.gt_u
+     (i32.const 13)
+     (i32.shl
+      (memory.size)
+      (i32.const 16)
+     )
+    )
+    (global.get $__mem_segment_drop_state_1)
+   )
+   (unreachable)
+  )
+  (block
+   (global.set $__mem_segment_drop_state_1
+    (i32.const 1)
+   )
+   (data.drop 3)
+   (data.drop 4)
+   (data.drop 5)
+  )
+ )
+ (func $zero-length-init-zeroes-2
+  (if
+   (i32.or
+    (i32.gt_u
+     (i32.const 13)
+     (i32.shl
+      (memory.size)
+      (i32.const 16)
+     )
+    )
+    (global.get $__mem_segment_drop_state_2)
+   )
+   (unreachable)
+  )
+  (block
+   (global.set $__mem_segment_drop_state_2
+    (i32.const 1)
+   )
+   (data.drop 6)
+   (data.drop 7)
+  )
+ )
+ (func $zero-length-init-nonzeroes-2
+  (if
+   (i32.or
+    (i32.gt_u
+     (i32.const 13)
+     (i32.shl
+      (memory.size)
+      (i32.const 16)
+     )
+    )
+    (global.get $__mem_segment_drop_state_3)
+   )
+   (unreachable)
+  )
+  (block
+   (global.set $__mem_segment_drop_state_3
+    (i32.const 1)
+   )
+   (data.drop 8)
+   (data.drop 9)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "memory" (memory $0 2048 2048))
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (data passive "a")
+ (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")
+ (func $init-lots
+  (block
+   (memory.init 0
+    (i32.const 0)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 1)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 1
+    (i32.const 31)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 32)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 2
+    (i32.const 62)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 63)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 3
+    (i32.const 93)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 94)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 4
+    (i32.const 124)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 125)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 5
+    (i32.const 155)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 156)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 6
+    (i32.const 186)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 187)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 7
+    (i32.const 217)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 218)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 8
+    (i32.const 248)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 249)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 9
+    (i32.const 279)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 280)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 10
+    (i32.const 310)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 311)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 11
+    (i32.const 341)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 342)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 12
+    (i32.const 372)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 373)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 13
+    (i32.const 403)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 404)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 14
+    (i32.const 434)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 435)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 15
+    (i32.const 465)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 466)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 16
+    (i32.const 496)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 497)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 17
+    (i32.const 527)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 528)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 18
+    (i32.const 558)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 559)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 19
+    (i32.const 589)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 590)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 20
+    (i32.const 620)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 621)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 21
+    (i32.const 651)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 652)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 22
+    (i32.const 682)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 683)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 23
+    (i32.const 713)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 714)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 24
+    (i32.const 744)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 745)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 25
+    (i32.const 775)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 776)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 26
+    (i32.const 806)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 807)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 27
+    (i32.const 837)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 838)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 28
+    (i32.const 868)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 869)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 29
+    (i32.const 899)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 900)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 30
+    (i32.const 930)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 931)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 31
+    (i32.const 961)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 962)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 32
+    (i32.const 992)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 993)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 33
+    (i32.const 1023)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 1024)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 34
+    (i32.const 1054)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 1055)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 35
+    (i32.const 1085)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 1086)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 36
+    (i32.const 1116)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 1117)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 37
+    (i32.const 1147)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 1148)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 38
+    (i32.const 1178)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 1179)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 39
+    (i32.const 1209)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 1210)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 40
+    (i32.const 1240)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 1241)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 41
+    (i32.const 1271)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 1272)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 42
+    (i32.const 1302)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 1303)
+    (i32.const 0)
+    (i32.const 30)
+   )
+   (memory.init 43
+    (i32.const 1333)
+    (i32.const 0)
+    (i32.const 1)
+   )
+   (memory.fill
+    (i32.const 1334)
+    (i32.const 0)
+    (i32.const 11)
+   )
+  )
+  (block
+   (data.drop 0)
+   (data.drop 1)
+   (data.drop 2)
+   (data.drop 3)
+   (data.drop 4)
+   (data.drop 5)
+   (data.drop 6)
+   (data.drop 7)
+   (data.drop 8)
+   (data.drop 9)
+   (data.drop 10)
+   (data.drop 11)
+   (data.drop 12)
+   (data.drop 13)
+   (data.drop 14)
+   (data.drop 15)
+   (data.drop 16)
+   (data.drop 17)
+   (data.drop 18)
+   (data.drop 19)
+   (data.drop 20)
+   (data.drop 21)
+   (data.drop 22)
+   (data.drop 23)
+   (data.drop 24)
+   (data.drop 25)
+   (data.drop 26)
+   (data.drop 27)
+   (data.drop 28)
+   (data.drop 29)
+   (data.drop 30)
+   (data.drop 31)
+   (data.drop 32)
+   (data.drop 33)
+   (data.drop 34)
+   (data.drop 35)
+   (data.drop 36)
+   (data.drop 37)
+   (data.drop 38)
+   (data.drop 39)
+   (data.drop 40)
+   (data.drop 41)
+   (data.drop 42)
+   (data.drop 43)
+   (data.drop 44)
+   (data.drop 45)
+   (data.drop 46)
+   (data.drop 47)
+   (data.drop 48)
+   (data.drop 49)
+   (data.drop 50)
+   (data.drop 51)
+   (data.drop 52)
+   (data.drop 53)
+   (data.drop 54)
+   (data.drop 55)
+   (data.drop 56)
+   (data.drop 57)
+   (data.drop 58)
+   (data.drop 59)
+   (data.drop 60)
+   (data.drop 61)
+   (data.drop 62)
+  )
+ )
+)
diff --git a/binaryen/test/passes/memory-packing_all-features.wast b/binaryen/test/passes/memory-packing_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/memory-packing_all-features.wast
@@ -0,0 +1,497 @@
+(module
+  (import "env" "memory" (memory $0 2048 2048))
+  (import "env" "memoryBase" (global $memoryBase i32))
+  ;; nothing
+)
+
+(module
+  (import "env" "memory" (memory $0 2048 2048))
+  (import "env" "memoryBase" (global $memoryBase i32))
+  (data (i32.const 4066) "") ;; empty
+)
+
+(module
+  (import "env" "memory" (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")
+
+  (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")
+
+  (data (i32.const 3000) "zeros after\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00")
+
+  (data (i32.const 4000) "zeros\00in\00the\00middle\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00nice skip here\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00another\00but no")
+
+  (func $nonzero-size-init-of-active-will-trap
+    (memory.init 0
+      (i32.const 42)
+      (i32.const 0)
+      (i32.const 13)
+    )
+    (data.drop 0)
+  )
+
+  (func $nonzero-offset-init-of-active-will-trap
+    (memory.init 0
+      (i32.const 42)
+      (i32.const 13)
+      (i32.const 0)
+    )
+    (data.drop 0)
+  )
+
+  (func $zero-offset-size-init-of-active-may-trap
+    (memory.init 0
+      (i32.const 42)
+      (i32.const 0)
+      (i32.const 0)
+    )
+    (data.drop 0)
+  )
+)
+
+(module
+  (import "env" "memory" (memory $0 2048 2048))
+
+  (data passive "not referenced, delete me") ;; 0
+
+  (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") ;; 1
+
+  (func $zeroes-at-start
+    (memory.init 1
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 45)
+    )
+    (data.drop 1)
+  )
+
+  ;; the not-split tests have too many memory.init and data.drop instructions for splitting to be worth it
+  (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") ;; 2
+
+  (func $zeroes-at-start-not-split
+    (memory.init 2
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 45)
+    )
+    (memory.init 2
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 45)
+    )
+    (memory.init 2
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 45)
+    )
+    (memory.init 2
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 45)
+    )
+    (data.drop 2)
+  )
+
+  (data passive "\00\00\00few zeroes at start") ;; 3
+
+  (func $few-zeroes-at-start
+    (memory.init 3
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 22)
+    )
+    (data.drop 3)
+  )
+
+  (data passive "zeroes at end\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") ;; 4
+
+  (func $zeroes-at-end
+    (memory.init 4
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 43)
+    )
+    (data.drop 4)
+  )
+
+  (data passive "zeroes at end\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") ;; 5
+
+  (func $zeroes-at-end-not-split
+    (memory.init 5
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 43)
+    )
+    (memory.init 5
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 43)
+    )
+    (memory.init 5
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 43)
+    )
+    (memory.init 5
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 43)
+    )
+    (data.drop 5)
+  )
+
+  (data passive "few zeroes at end\00\00\00") ;; 6
+
+  (func $few-zeroes-at-end
+    (memory.init 6
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 20)
+    )
+    (data.drop 6)
+  )
+
+  (data passive "zeroes\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00in middle") ;; 7
+
+  (func $zeroes-in-middle
+    (memory.init 7
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 45)
+    )
+    (data.drop 7)
+  )
+
+  (data passive "zeroes\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00in middle") ;; 8
+
+  (func $zeroes-in-middle-not-split
+    (memory.init 8
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 35)
+    )
+    (memory.init 8
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 45)
+    )
+    (data.drop 8)
+  )
+
+  (data passive "few zeroes\00\00\00in middle") ;; 9
+
+  (func $few-zeroes-in-middle
+    (memory.init 9
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 22)
+    )
+    (data.drop 9)
+  )
+
+  (data passive "multiple\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00spans\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00of zeroes") ;; 10
+
+  (func $multiple-spans-of-zeroes
+    (memory.init 10
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 82)
+    )
+    (data.drop 10)
+  )
+
+  (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") ;; 11
+
+  (func $even-more-zeroes
+    (memory.init 11
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 134)
+    )
+    (data.drop 11)
+  )
+
+  (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\00") ;; 12
+
+  (func $only-zeroes
+    (memory.init 12
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 30)
+    )
+    (data.drop 12)
+  )
+
+  (data passive "no zeroes") ;; 13
+
+  (func $no-zeroes
+    (memory.init 13
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 9)
+    )
+    (data.drop 13)
+  )
+
+  (data passive "") ;; 14
+
+  (func $empty
+    (memory.init 14
+      (i32.const 13)
+      (i32.const 0)
+      (i32.const 0)
+    )
+    (data.drop 14)
+  )
+
+  (data passive "only dropped") ;; 15
+
+  (func $only-dropped
+    (data.drop 15)
+    (data.drop 15)
+  )
+
+  (data passive "\00\00\00\00\00") ;; 16
+
+  (func $only-dropped-zeroes
+    (data.drop 16)
+    (data.drop 16)
+  )
+
+  (data passive "") ;; not referenced
+
+  (data passive "\00\00\00\00\00") ;; not referenced
+)
+
+(module
+  (import "env" "memory" (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
+
+  (func $nonconst-dest
+    (memory.init 0
+      (global.get $param)
+      (i32.const 0)
+      (i32.const 134)
+    )
+    (data.drop 0)
+  )
+
+  (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") ;; 1
+
+  (func $nonconst-offset
+    (memory.init 1
+      (i32.const 0)
+      (global.get $param)
+      (i32.const 134)
+    )
+    (data.drop 1)
+  )
+
+  (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") ;; 2
+
+  (func $nonconst-size
+    (memory.init 2
+      (i32.const 0)
+      (i32.const 0)
+      (global.get $param)
+    )
+    (data.drop 2)
+  )
+
+  (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") ;; 3
+
+  (func $partial-skip-start
+    (memory.init 3
+      (i32.const 0)
+      (i32.const 10)
+      (i32.const 124)
+    )
+    (data.drop 3)
+  )
+
+  (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") ;; 4
+
+  (func $full-skip-start
+    (memory.init 4
+      (i32.const 0)
+      (i32.const 32)
+      (i32.const 102)
+    )
+    (data.drop 4)
+  )
+
+  (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") ;; 5
+
+  (func $partial-skip-end
+    (memory.init 5
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 124)
+    )
+    (data.drop 5)
+  )
+
+  (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") ;; 6
+
+  (func $full-skip-end
+    (memory.init 6
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 102)
+    )
+    (data.drop 6)
+  )
+
+  (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") ;; 7
+
+  (func $slice-zeroes
+    (memory.init 7
+      (i32.const 0)
+      (i32.const 35)
+      (i32.const 10)
+    )
+    (data.drop 7)
+  )
+
+  (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") ;; 8
+
+  (func $slice-nonzeroes
+    (memory.init 8
+      (i32.const 0)
+      (i32.const 31)
+      (i32.const 2)
+    )
+    (data.drop 8)
+  )
+
+  (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") ;; 9
+
+  (func $zero-size
+    (memory.init 9
+      (i32.const 13)
+      (i32.const 40)
+      (i32.const 0)
+    )
+    (data.drop 9)
+  )
+
+  (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") ;; 10
+
+  (func $zero-size-undropped
+    (memory.init 10
+      (i32.const 13)
+      (i32.const 40)
+      (i32.const 0)
+    )
+  )
+
+  (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") ;; 11
+
+  (func $out-of-bounds-offset
+    (memory.init 11
+      (i32.const 0)
+      (i32.const 135)
+      (i32.const 1)
+    )
+    (data.drop 11)
+  )
+
+  (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") ;; 12
+
+  (func $zero-size-out-of-bounds-offset
+    (memory.init 12
+      (i32.const 0)
+      (i32.const 135)
+      (i32.const 0)
+    )
+    (data.drop 12)
+  )
+
+  (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") ;; 13
+
+  (func $out-of-bounds-size
+    (memory.init 13
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 135)
+    )
+    (data.drop 13)
+  )
+
+  (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") ;; 14
+
+  (func $zero-size-at-bounds-offset
+    (memory.init 14
+      (i32.const 0)
+      (i32.const 134)
+      (i32.const 0)
+    )
+    (data.drop 14)
+  )
+)
+
+(module
+  (import "env" "memory" (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
+    (memory.init 0
+      (i32.const 13)
+      (i32.const 10)
+      (i32.const 0)
+    )
+    (data.drop 0)
+  )
+
+  (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") ;; 1
+
+  (func $zero-length-init-nonzeroes
+    (memory.init 1
+      (i32.const 13)
+      (i32.const 33)
+      (i32.const 0)
+    )
+    (data.drop 1)
+  )
+
+  (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\00hi") ;; 2
+
+  (func $zero-length-init-zeroes-2
+    (memory.init 2
+      (i32.const 13)
+      (i32.const 10)
+      (i32.const 0)
+    )
+    (data.drop 2)
+  )
+
+  (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\00hi") ;; 3
+
+  (func $zero-length-init-nonzeroes-2
+    (memory.init 3
+      (i32.const 13)
+      (i32.const 31)
+      (i32.const 0)
+    )
+    (data.drop 3)
+  )
+)
+
+(module
+  (import "env" "memory" (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
+    (memory.init 0
+      (i32.const 0)
+      (i32.const 0)
+      (i32.const 1345)
+    )
+    (data.drop 0)
+  )
+)
diff --git a/binaryen/test/passes/merge-blocks.txt b/binaryen/test/passes/merge-blocks.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/merge-blocks.txt
@@ -0,0 +1,286 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_f32 (func (result f32)))
+ (global $global$0 (mut i32) (i32.const 10))
+ (func $drop-block
+  (block $block
+   (drop
+    (i32.const 0)
+   )
+  )
+ )
+ (func $drop-block-br
+  (block $block
+   (drop
+    (block $x (result i32)
+     (br $x
+      (i32.const 1)
+     )
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $drop-block-br-if
+  (block $block
+   (drop
+    (i32.const 1)
+   )
+   (block $x
+    (br_if $x
+     (i32.const 2)
+    )
+    (drop
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $undroppable-block-br-if (param $0 i32)
+  (block $block
+   (drop
+    (block $x (result i32)
+     (call $undroppable-block-br-if
+      (br_if $x
+       (i32.const 1)
+       (i32.const 2)
+      )
+     )
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $drop-block-nested-br-if
+  (block $block
+   (block $x
+    (if
+     (i32.const 100)
+     (block $block0
+      (drop
+       (i32.const 1)
+      )
+      (br_if $x
+       (i32.const 2)
+      )
+      (nop)
+     )
+    )
+    (drop
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $drop-unreachable-br_if (result i32)
+  (block $label$0 (result i32)
+   (block $label$2 (result i32)
+    (br_if $label$2
+     (br $label$0
+      (i32.const 538976371)
+     )
+     (i32.const 1918987552)
+    )
+   )
+  )
+ )
+ (func $drop-block-squared-iloop
+  (drop
+   (block $label$0 (result i32)
+    (drop
+     (block $label$1
+      (loop $label$2
+       (br $label$2)
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $br-goes-away-label2-becomes-unreachable
+  (block $block
+   (drop
+    (block $label$1 (result i32)
+     (block $label$2
+      (drop
+       (br_if $label$1
+        (unreachable)
+        (i32.eqz
+         (br $label$2)
+        )
+       )
+      )
+     )
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $loop-block-drop-block-return
+  (loop $label$4
+   (block $label$5
+    (drop
+     (block $label$6 (result i32)
+      (return)
+     )
+    )
+   )
+  )
+ )
+ (func $if-block
+  (block $label
+   (if
+    (i32.const 1)
+    (block $block
+     (drop
+      (i32.const 2)
+     )
+     (drop
+      (i32.const 3)
+     )
+    )
+   )
+  )
+ )
+ (func $if-block-bad
+  (block $label
+   (if
+    (br $label)
+    (block $block
+     (drop
+      (i32.const 2)
+     )
+     (drop
+      (i32.const 3)
+     )
+    )
+   )
+  )
+ )
+ (func $if-block-br
+  (block $label
+   (if
+    (i32.const 1)
+    (br $label)
+   )
+  )
+ )
+ (func $if-block-br-1
+  (block $label
+   (if
+    (i32.const 1)
+    (br $label)
+    (drop
+     (i32.const 3)
+    )
+   )
+  )
+ )
+ (func $if-block-br-2
+  (block $label
+   (if
+    (i32.const 1)
+    (drop
+     (i32.const 3)
+    )
+    (br $label)
+   )
+  )
+ )
+ (func $if-block-br-3
+  (block $label
+   (if
+    (i32.const 1)
+    (br $label)
+    (br $label)
+   )
+  )
+ )
+ (func $if-block-br-4-eithre
+  (block $label
+   (if
+    (i32.const 1)
+    (drop
+     (i32.const 2)
+    )
+    (drop
+     (i32.const 3)
+    )
+   )
+  )
+ )
+ (func $if-block-br-5-value (result i32)
+  (block $label (result i32)
+   (if (result i32)
+    (i32.const 1)
+    (i32.const 2)
+    (i32.const 3)
+   )
+  )
+ )
+ (func $restructure-if-outerType-change
+  (loop $label$1
+   (br_if $label$1
+    (block $label$2
+     (block $label$3
+      (if
+       (block $label$4
+        (unreachable)
+       )
+       (br $label$3)
+      )
+     )
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $if-arm-unreachable
+  (block $label$1
+   (if
+    (unreachable)
+    (nop)
+    (unreachable)
+   )
+  )
+ )
+ (func $propagate-type-if-we-optimize
+  (if
+   (i32.const 1)
+   (nop)
+   (block $block
+    (drop
+     (loop $label$3 (result i64)
+      (br_if $label$3
+       (block $label$4 (result i32)
+        (if
+         (i32.const 0)
+         (unreachable)
+         (unreachable)
+        )
+       )
+      )
+      (i64.const -9)
+     )
+    )
+    (unreachable)
+   )
+  )
+ )
+ (func $br-value-blocktypechange (result f32)
+  (global.set $global$0
+   (i32.const 0)
+  )
+  (block $label$1 (result f32)
+   (global.set $global$0
+    (i32.const 0)
+   )
+   (br_if $label$1
+    (unreachable)
+    (i32.const 0)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/merge-blocks.wast b/binaryen/test/passes/merge-blocks.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/merge-blocks.wast
@@ -0,0 +1,250 @@
+(module
+  (global $global$0 (mut i32) (i32.const 10))
+  (func $drop-block
+    (block
+      (drop
+        (block $x (result i32)
+          (i32.const 0)
+        )
+      )
+    )
+  )
+  (func $drop-block-br
+    (block
+      (drop
+        (block $x (result i32)
+          (br $x (i32.const 1))
+          (i32.const 0)
+        )
+      )
+    )
+  )
+  (func $drop-block-br-if
+    (block
+      (drop
+        (block $x (result i32)
+          (drop (br_if $x (i32.const 1) (i32.const 2)))
+          (i32.const 0)
+        )
+      )
+    )
+  )
+  (func $undroppable-block-br-if (param i32)
+    (block
+      (drop
+        (block $x (result i32)
+          (call $undroppable-block-br-if (br_if $x (i32.const 1) (i32.const 2)))
+          (i32.const 0)
+        )
+      )
+    )
+  )
+  (func $drop-block-nested-br-if
+    (block
+      (drop
+        (block $x (result i32)
+          (if (i32.const 100)
+            (block
+              (drop (br_if $x (i32.const 1) (i32.const 2)))
+              (nop)
+            )
+          )
+          (i32.const 0)
+        )
+      )
+    )
+  )
+  (func $drop-unreachable-br_if (result i32)
+    (block $label$0 (result i32)
+     (block $label$2 (result i32)
+      (br_if $label$2
+       (br $label$0
+        (i32.const 538976371)
+       )
+       (i32.const 1918987552)
+      )
+     )
+    )
+  )
+  (func $drop-block-squared-iloop
+   (drop
+    (block $label$0 (result i32) ;; this block's type should not change, so the drop remains none and valid
+     (drop
+      (block $label$1
+       (loop $label$2
+        (br $label$2)
+       )
+      )
+     )
+    )
+   )
+  )
+  (func $br-goes-away-label2-becomes-unreachable
+   (block
+    (drop
+     (block $label$1 (result i32)
+      (block $label$2
+       (drop
+        (br_if $label$1
+         (unreachable)
+         (i32.eqz
+          (br $label$2)
+         )
+        )
+       )
+      )
+      (i32.const 1)
+     )
+    )
+   )
+  )
+  (func $loop-block-drop-block-return
+   (loop $label$4
+    (block $label$5
+     (drop
+      (block $label$6 (result i32)
+       (return)
+      )
+     )
+    )
+   )
+  )
+  (func $if-block
+   (block $label
+    (if
+     (i32.const 1)
+     (block
+      (drop (i32.const 2))
+      (drop (i32.const 3))
+     )
+    )
+   )
+  )
+  (func $if-block-bad
+   (block $label
+    (if
+     (br $label) ;; use outside of arm
+     (block
+      (drop (i32.const 2))
+      (drop (i32.const 3))
+     )
+    )
+   )
+  )
+  (func $if-block-br
+   (block $label
+    (if
+     (i32.const 1)
+     (br $label)
+    )
+   )
+  )
+  (func $if-block-br-1
+   (block $label
+    (if
+     (i32.const 1)
+     (br $label)
+     (drop (i32.const 3))
+    )
+   )
+  )
+  (func $if-block-br-2
+   (block $label
+    (if
+     (i32.const 1)
+     (drop (i32.const 3))
+     (br $label)
+    )
+   )
+  )
+  (func $if-block-br-3
+   (block $label
+    (if
+     (i32.const 1)
+     (br $label)
+     (br $label)
+    )
+   )
+  )
+  (func $if-block-br-4-eithre
+   (block $label
+    (if
+     (i32.const 1)
+     (drop (i32.const 2))
+     (drop (i32.const 3))
+    )
+   )
+  )
+  (func $if-block-br-5-value (result i32)
+   (block $label (result i32)
+    (if (result i32)
+     (i32.const 1)
+     (i32.const 2)
+     (i32.const 3)
+    )
+   )
+  )
+  (func $restructure-if-outerType-change
+   (loop $label$1
+    (br_if $label$1
+     (block $label$2
+      (block $label$3
+       (if
+        (block $label$4
+         (unreachable)
+        )
+        (br $label$3)
+       )
+      )
+      (unreachable)
+     )
+    )
+   )
+  )
+  (func $if-arm-unreachable
+   (block $label$1
+    (if
+     (unreachable) ;; unreachable condition
+     (nop)
+     (unreachable)
+    )
+   )
+  )
+  (func $propagate-type-if-we-optimize
+   (if
+    (i32.const 1)
+    (nop)
+    (block
+     (drop
+      (loop $label$3 (result i64)
+       (br_if $label$3
+        (block $label$4 (result i32)
+         (if
+          (i32.const 0)
+          (unreachable)
+          (unreachable)
+         )
+        )
+       )
+       (i64.const -9)
+      )
+     )
+     (unreachable)
+    )
+   )
+  )
+  (func $br-value-blocktypechange (result f32)
+   (global.set $global$0
+    (i32.const 0)
+   )
+   (block $label$1 (result f32)
+    (global.set $global$0
+     (i32.const 0)
+    )
+    (br_if $label$1
+     (unreachable)
+     (i32.const 0)
+    )
+   )
+  )
+)
diff --git a/binaryen/test/passes/merge-blocks_remove-unused-brs.txt b/binaryen/test/passes/merge-blocks_remove-unused-brs.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/merge-blocks_remove-unused-brs.txt
@@ -0,0 +1,16 @@
+(module
+ (type $i32_=>_none (func (param i32)))
+ (func $func (param $x i32)
+  (loop $loop
+   (block $out
+    (block
+     (br_if $out
+      (local.get $x)
+     )
+     (nop)
+     (br $loop)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/merge-blocks_remove-unused-brs.wast b/binaryen/test/passes/merge-blocks_remove-unused-brs.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/merge-blocks_remove-unused-brs.wast
@@ -0,0 +1,14 @@
+(module
+  (func $func (param $x i32)
+    (block $out
+      (loop $loop
+        (br_if $out
+          (local.get $x)
+        )
+        (nop)
+        (br $loop)
+      )
+    )
+  )
+)
+
diff --git a/binaryen/test/passes/merge-locals_all-features.txt b/binaryen/test/passes/merge-locals_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/merge-locals_all-features.txt
@@ -0,0 +1,471 @@
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (type $i32_f32_f32_=>_i64 (func (param i32 f32 f32) (result i64)))
+ (global $global$0 (mut i32) (i32.const 10))
+ (func $test (param $x i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (local.get $x)
+ )
+ (func $test2 (param $x i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (local.get $x)
+ )
+ (func $test-multiple (param $x i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (local.get $x)
+ )
+ (func $test-just-some (param $x i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (local.set $y
+   (i32.const 200)
+  )
+  (local.get $y)
+ )
+ (func $test-just-some2 (param $x i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (if
+   (i32.const 300)
+   (local.set $y
+    (i32.const 400)
+   )
+   (drop
+    (local.get $x)
+   )
+  )
+  (i32.const 500)
+ )
+ (func $test-just-some3 (param $x i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (i32.const 200)
+   )
+  )
+  (if
+   (i32.const 300)
+   (local.set $y
+    (i32.const 400)
+   )
+   (drop
+    (local.get $y)
+   )
+  )
+  (local.get $y)
+ )
+ (func $silly-self (param $x i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $x)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (local.get $y)
+ )
+ (func $silly-multi (param $x i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.tee $y
+      (local.get $x)
+     )
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (local.get $y)
+ )
+ (func $undo-1 (param $var$1 i32) (param $var$2 i32)
+  (local $var$5 i32)
+  (local.set $var$2
+   (local.get $var$1)
+  )
+  (local.set $var$2
+   (i32.const 1)
+  )
+  (drop
+   (local.get $var$1)
+  )
+ )
+ (func $undo-2 (param $var$1 i32) (param $var$2 i32)
+  (local $var$5 i32)
+  (local.set $var$2
+   (local.get $var$1)
+  )
+  (if
+   (local.get $var$1)
+   (local.set $var$2
+    (i32.const 1)
+   )
+  )
+  (drop
+   (local.get $var$1)
+  )
+ )
+ (func $reverse (param $x i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $y)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+  (if
+   (i32.const 1)
+   (local.set $y
+    (i32.const 200)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+ )
+ (func $reverse-end (param $x i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+ )
+ (func $reverse-lone-end-2 (param $x i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (local.set $y
+   (i32.const 200)
+  )
+  (drop
+   (local.get $y)
+  )
+ )
+ (func $reverse-undo (param $x i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $y)
+   )
+  )
+  (local.set $x
+   (i32.const 300)
+  )
+  (drop
+   (local.get $x)
+  )
+  (if
+   (i32.const 1)
+   (local.set $y
+    (i32.const 200)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+ )
+ (func $reverse-undo2 (param $x i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (i32.const 150)
+   )
+  )
+  (local.set $x
+   (i32.const 300)
+  )
+  (drop
+   (local.get $x)
+  )
+  (if
+   (i32.const 1)
+   (local.set $y
+    (i32.const 200)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+ )
+ (func $reverse-undo3-conditional (param $x i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (i32.const 150)
+   )
+  )
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.const 300)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (if
+   (i32.const 1)
+   (local.set $y
+    (i32.const 200)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+ )
+ (func $reverse-undo3-conditional-b (param $x i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.const 300)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (if
+   (i32.const 1)
+   (local.set $y
+    (i32.const 200)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+ )
+ (func $reverse-undo3-conditional-c (param $x i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (i32.const 150)
+   )
+  )
+  (if
+   (i32.const 1)
+   (drop
+    (local.get $x)
+   )
+   (block $block
+    (if
+     (i32.const 1)
+     (local.set $x
+      (i32.const 300)
+     )
+    )
+    (drop
+     (local.get $x)
+    )
+   )
+  )
+  (if
+   (i32.const 1)
+   (local.set $y
+    (i32.const 200)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+ )
+ (func $fuzz (param $var$0 i32) (param $var$1 f32) (param $var$2 f32) (result i64)
+  (local $var$3 i32)
+  (global.set $global$0
+   (i32.sub
+    (global.get $global$0)
+    (i32.const 1)
+   )
+  )
+  (loop $label$1 (result i64)
+   (global.set $global$0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 1)
+    )
+   )
+   (br_if $label$1
+    (block $label$2 (result i32)
+     (drop
+      (if (result i32)
+       (block $label$3 (result i32)
+        (global.set $global$0
+         (i32.sub
+          (global.get $global$0)
+          (i32.const 3)
+         )
+        )
+        (local.set $var$3
+         (i32.const 1)
+        )
+        (local.tee $var$3
+         (local.get $var$0)
+        )
+       )
+       (i32.const 0)
+       (block $block (result i32)
+        (local.set $var$3
+         (if (result i32)
+          (i32.const 0)
+          (block $block13 (result i32)
+           (block $label$7
+            (block $label$8
+             (local.set $var$0
+              (i32.const 34738786)
+             )
+            )
+           )
+           (local.get $var$3)
+          )
+          (block $block14 (result i32)
+           (if
+            (i32.eqz
+             (global.get $global$0)
+            )
+            (return
+             (i64.const 137438953472)
+            )
+           )
+           (global.set $global$0
+            (i32.sub
+             (global.get $global$0)
+             (i32.const 1)
+            )
+           )
+           (br_if $label$1
+            (i32.eqz
+             (local.get $var$3)
+            )
+           )
+           (return
+            (i64.const 44125)
+           )
+          )
+         )
+        )
+        (i32.const -129)
+       )
+      )
+     )
+     (i32.const 0)
+    )
+   )
+   (i64.const -36028797018963968)
+  )
+ )
+ (func $trivial-confusion (param $unused i32) (param $param i32) (param $result i32)
+  (loop $label$1
+   (if
+    (i32.const 1)
+    (drop
+     (local.get $result)
+    )
+   )
+   (local.set $result
+    (local.get $param)
+   )
+   (br_if $label$1
+    (local.tee $unused
+     (local.get $param)
+    )
+   )
+  )
+ )
+ (func $subtype-test
+  (local $0 anyref)
+  (local $1 funcref)
+  (local $2 funcref)
+  (local.set $0
+   (local.get $1)
+  )
+  (local.set $2
+   (local.get $1)
+  )
+ )
+)
diff --git a/binaryen/test/passes/merge-locals_all-features.wast b/binaryen/test/passes/merge-locals_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/merge-locals_all-features.wast
@@ -0,0 +1,390 @@
+(module
+ (global $global$0 (mut i32) (i32.const 10))
+ (func $test (param $x $i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (local.get $y) ;; turn this into $x
+ )
+ (func $test2 (param $x $i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (local.get $x)
+ )
+ (func $test-multiple (param $x $i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (drop (local.get $y)) ;; turn this into $x
+  (local.get $y) ;; turn this into $x
+ )
+ (func $test-just-some (param $x $i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (drop (local.get $y)) ;; turn this into $x
+  (local.set $y (i32.const 200))
+  (local.get $y) ;; but not this one!
+ )
+ (func $test-just-some2 (param $x $i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (if
+   (i32.const 300)
+   (local.set $y (i32.const 400))
+   (drop (local.get $y)) ;; turn this into $x
+  )
+  (i32.const 500)
+ )
+ (func $test-just-some3 (param $x $i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (i32.const 200)
+   )
+  )
+  (if
+   (i32.const 300)
+   (local.set $y (i32.const 400))
+   (drop (local.get $y)) ;; can turn this into $x, but another exists we can't, so do nothing
+  )
+  (local.get $y) ;; but not this one!
+ )
+ (func $silly-self (param $x $i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $x)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (local.get $y) ;; turn this into $x
+ )
+ (func $silly-multi (param $x $i32) (param $y i32) (result i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.tee $y
+      (local.get $x)
+     )
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (local.get $y) ;; turn this into $x
+ )
+ (func $undo-1 (param $var$1 i32) (param $var$2 i32)
+  (local $var$5 i32)
+  (local.set $var$2 ;; copy 1 to 2
+   (local.get $var$1)
+  )
+  (local.set $var$2 ;; overwrite 2
+   (i32.const 1)
+  )
+  (drop
+   (local.get $var$1) ;; can't be changed to $var$2, as it changes
+  )
+ )
+ (func $undo-2 (param $var$1 i32) (param $var$2 i32)
+  (local $var$5 i32)
+  (local.set $var$2 ;; copy 1 to 2
+   (local.get $var$1)
+  )
+  (if (local.get $var$1)
+   (local.set $var$2 ;; conditional overwrite 2
+    (i32.const 1)
+   )
+  )
+  (drop
+   (local.get $var$1) ;; can't be changed to $var$2, as it changes
+  )
+ )
+ (func $reverse (param $x $i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (drop (local.get $x)) ;; (read lower down first) but the reverse can work!
+  (if (i32.const 1)
+   (local.set $y (i32.const 200))
+  )
+  (drop (local.get $y)) ;; cannot this into $x, since this $y has multiple sources
+ )
+ (func $reverse-end (param $x $i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x) ;; don't change to $y, as its lifetime ended. leave it ended
+   )
+  )
+ )
+ (func $reverse-lone-end-2 (param $x $i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x) ;; don't change to $y, as its lifetime ended. leave it ended
+   )
+  )
+  (local.set $y (i32.const 200))
+  (drop (local.get $y)) ;; cannot this into $x, since this $y has multiple sources
+ )
+ (func $reverse-undo (param $x $i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x) ;; can optimize this ($y lives on)
+   )
+  )
+  (local.set $x (i32.const 300)) ;; force an undo
+  (drop (local.get $x)) ;; (read lower down first) but the reverse can almost work
+  (if (i32.const 1)
+   (local.set $y (i32.const 200))
+  )
+  (drop (local.get $y)) ;; cannot this into $x, since this $y has multiple sources
+ )
+ (func $reverse-undo2 (param $x $i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (i32.const 150)
+   )
+  )
+  (local.set $x (i32.const 300)) ;; force an undo
+  (drop (local.get $x)) ;; (read lower down first) but the reverse can almost work
+  (if (i32.const 1)
+   (local.set $y (i32.const 200))
+  )
+  (drop (local.get $y)) ;; cannot this into $x, since this $y has multiple sources
+ )
+ (func $reverse-undo3-conditional (param $x $i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (i32.const 150)
+   )
+  )
+  (if (i32.const 1)
+   (local.set $x (i32.const 300)) ;; force an undo
+  )
+  (drop (local.get $x)) ;; (read lower down first) but the reverse can almost work
+  (if (i32.const 1)
+   (local.set $y (i32.const 200))
+  )
+  (drop (local.get $y)) ;; cannot this into $x, since this $y has multiple sources
+ )
+ (func $reverse-undo3-conditional-b (param $x $i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (local.get $x)
+   )
+  )
+  (if (i32.const 1)
+   (local.set $x (i32.const 300)) ;; force an undo
+  )
+  (drop (local.get $x)) ;; (read lower down first) but the reverse can almost work
+  (if (i32.const 1)
+   (local.set $y (i32.const 200))
+  )
+  (drop (local.get $y)) ;; cannot this into $x, since this $y has multiple sources
+ )
+ (func $reverse-undo3-conditional-c (param $x $i32) (param $y i32)
+  (drop
+   (if (result i32)
+    (local.tee $x
+     (local.get $y)
+    )
+    (i32.const 100)
+    (i32.const 150)
+   )
+  )
+  (if (i32.const 1)
+   (drop (local.get $x))
+   (block
+    (if (i32.const 1)
+     (local.set $x (i32.const 300)) ;; force an undo
+    )
+    (drop (local.get $x)) ;; (read lower down first) but the reverse can almost work
+   )
+  )
+  (if (i32.const 1)
+   (local.set $y (i32.const 200))
+  )
+  (drop (local.get $y)) ;; cannot this into $x, since this $y has multiple sources
+ )
+ (func $fuzz (param $var$0 i32) (param $var$1 f32) (param $var$2 f32) (result i64)
+  (local $var$3 i32)
+  (global.set $global$0
+   (i32.sub
+    (global.get $global$0)
+    (i32.const 1)
+   )
+  )
+  (loop $label$1 (result i64)
+   (global.set $global$0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 1)
+    )
+   )
+   (br_if $label$1
+    (block $label$2 (result i32)
+     (drop
+      (if (result i32)
+       (block $label$3 (result i32)
+        (global.set $global$0
+         (i32.sub
+          (global.get $global$0)
+          (i32.const 3)
+         )
+        )
+        (local.set $var$3
+         (i32.const 1)
+        )
+        (local.tee $var$3
+         (local.get $var$0)
+        )
+       )
+       (i32.const 0)
+       (block (result i32)
+        (local.set $var$3
+         (if (result i32)
+          (i32.const 0)
+          (block (result i32)
+           (block $label$7
+            (block $label$8
+             (local.set $var$0
+              (i32.const 34738786)
+             )
+            )
+           )
+           (local.get $var$3)
+          )
+          (block (result i32)
+           (if
+            (i32.eqz
+             (global.get $global$0)
+            )
+            (return
+             (i64.const 137438953472)
+            )
+           )
+           (global.set $global$0
+            (i32.sub
+             (global.get $global$0)
+             (i32.const 1)
+            )
+           )
+           (br_if $label$1
+            (i32.eqz
+             (local.get $var$3)
+            )
+           )
+           (return
+            (i64.const 44125)
+           )
+          )
+         )
+        )
+        (i32.const -129)
+       )
+      )
+     )
+     (i32.const 0)
+    )
+   )
+   (i64.const -36028797018963968)
+  )
+ )
+ (func $trivial-confusion (param $unused i32) (param $param i32) (param $result i32)
+  (loop $label$1
+   (if
+    (i32.const 1)
+    (drop
+     (local.get $result)
+    )
+   )
+   (local.set $result ;; vanishes
+    (local.get $param)
+   )
+   (br_if $label$1
+    (local.tee $unused ;; unused, but forms part of a copy, with $result - the trivial tee we add here should not confuse us
+     (local.get $result) ;; flips
+    )
+   )
+  )
+ )
+ (func $subtype-test
+  (local $0 anyref)
+  (local $1 funcref)
+  (local $2 funcref)
+  (local.set $0
+   (local.get $1)
+  )
+  (local.set $2
+    ;; This should NOT become $0, because types of $0 and $1 are different
+   (local.get $1)
+  )
+ )
+)
diff --git a/binaryen/test/passes/metrics_all-features.txt b/binaryen/test/passes/metrics_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/metrics_all-features.txt
@@ -0,0 +1,75 @@
+total
+ [events]       : 2       
+ [exports]      : 0       
+ [funcs]        : 1       
+ [globals]      : 1       
+ [imports]      : 0       
+ [memory-data]  : 9       
+ [table-data]   : 3       
+ [total]        : 27      
+ [vars]         : 1       
+ binary         : 1       
+ block          : 1       
+ const          : 15      
+ drop           : 6       
+ if             : 4       
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (memory $0 256 256)
+ (data (i32.const 0) "\ff\ef\0f\1f 0@P\99")
+ (table $0 256 256 funcref)
+ (elem (i32.const 0) $ifs $ifs $ifs)
+ (global $glob i32 (i32.const 1337))
+ (event $e0 (attr 0) (param i32))
+ (event $e1 (attr 0) (param i32 i32))
+ (func $ifs (param $x i32)
+  (local $y f32)
+  (block $block0
+   (if
+    (i32.const 0)
+    (drop
+     (i32.const 1)
+    )
+   )
+   (if
+    (i32.const 0)
+    (drop
+     (i32.const 1)
+    )
+    (drop
+     (i32.const 2)
+    )
+   )
+   (if
+    (i32.const 4)
+    (drop
+     (i32.const 5)
+    )
+    (drop
+     (i32.const 6)
+    )
+   )
+   (drop
+    (i32.eq
+     (if (result i32)
+      (i32.const 4)
+      (i32.const 5)
+      (i32.const 6)
+     )
+     (i32.const 177)
+    )
+   )
+  )
+ )
+)
+total
+ [events]       : 0       
+ [exports]      : 0       
+ [funcs]        : 0       
+ [globals]      : 0       
+ [imports]      : 0       
+ [total]        : 0       
+ [vars]         : 0       
+(module
+)
diff --git a/binaryen/test/passes/metrics_all-features.wast b/binaryen/test/passes/metrics_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/metrics_all-features.wast
@@ -0,0 +1,52 @@
+(module
+  (memory 256 256)
+  (table 256 256 funcref)
+  (elem (i32.const 0) $ifs $ifs $ifs)
+  (data (i32.const 0) "\ff\ef\0f\1f\20\30\40\50\99")
+  (type $0 (func (param i32)))
+  (global $glob i32 (i32.const 1337))
+  (event $e0 (attr 0) (param i32))
+  (event $e1 (attr 0) (param i32 i32))
+  (func $ifs (type $0) (param $x i32)
+    (local $y f32)
+    (block $block0
+      (if
+        (i32.const 0)
+        (drop
+          (i32.const 1)
+        )
+      )
+      (if
+        (i32.const 0)
+        (drop
+          (i32.const 1)
+        )
+        (drop
+          (i32.const 2)
+        )
+      )
+      (if
+        (i32.const 4)
+        (drop
+          (i32.const 5)
+        )
+        (drop
+          (i32.const 6)
+        )
+      )
+      (drop
+        (i32.eq
+          (if (result i32)
+            (i32.const 4)
+            (i32.const 5)
+            (i32.const 6)
+          )
+          (i32.const 177)
+        )
+      )
+    )
+  )
+)
+;; module with no table or memory or anything for that matter
+(module
+)
diff --git a/binaryen/test/passes/metrics_strip-debug_metrics.bin.txt b/binaryen/test/passes/metrics_strip-debug_metrics.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/metrics_strip-debug_metrics.bin.txt
@@ -0,0 +1,27 @@
+total
+ [events]       : 0       
+ [exports]      : 1       
+ [funcs]        : 1       
+ [globals]      : 0       
+ [imports]      : 0       
+ [total]        : 1       
+ [vars]         : 0       
+ nop            : 1       
+total
+ [events]       : 0       
+ [exports]      : 1       
+ [funcs]        : 1       
+ [globals]      : 0       
+ [imports]      : 0       
+ [total]        : 1       
+ [vars]         : 0       
+ nop            : 1       
+(module
+ (type $none_=>_none (func))
+ (export "a" (func $0))
+ (func $0
+  (nop)
+ )
+ ;; custom section "emscripten_metadata", size 7
+ ;; custom section "producers", size 187
+)
diff --git a/binaryen/test/passes/metrics_strip-debug_metrics.wasm b/binaryen/test/passes/metrics_strip-debug_metrics.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/metrics_strip-debug_metrics.wasm differ
diff --git a/binaryen/test/passes/metrics_strip-producers_metrics.bin.txt b/binaryen/test/passes/metrics_strip-producers_metrics.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/metrics_strip-producers_metrics.bin.txt
@@ -0,0 +1,26 @@
+total
+ [events]       : 0       
+ [exports]      : 1       
+ [funcs]        : 1       
+ [globals]      : 0       
+ [imports]      : 0       
+ [total]        : 1       
+ [vars]         : 0       
+ nop            : 1       
+total
+ [events]       : 0       
+ [exports]      : 1       
+ [funcs]        : 1       
+ [globals]      : 0       
+ [imports]      : 0       
+ [total]        : 1       
+ [vars]         : 0       
+ nop            : 1       
+(module
+ (type $none_=>_none (func))
+ (export "a" (func $0))
+ (func $0
+  (nop)
+ )
+ ;; custom section "emscripten_metadata", size 7
+)
diff --git a/binaryen/test/passes/metrics_strip-producers_metrics.wasm b/binaryen/test/passes/metrics_strip-producers_metrics.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/metrics_strip-producers_metrics.wasm differ
diff --git a/binaryen/test/passes/minify-imports-and-exports-and-modules.txt b/binaryen/test/passes/minify-imports-and-exports-and-modules.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/minify-imports-and-exports-and-modules.txt
@@ -0,0 +1,15 @@
+memory => a
+table => b
+longname1 => c
+longname2 => d
+longname3 => e
+longname4 => f
+(module
+ (type $none_=>_none (func))
+ (import "a" "a" (memory $0 256 256))
+ (import "a" "b" (table $0 4 funcref))
+ (import "a" "c" (func $internal1))
+ (import "a" "d" (func $internal2))
+ (import "a" "e" (func $internal3))
+ (import "a" "f" (func $internal4))
+)
diff --git a/binaryen/test/passes/minify-imports-and-exports-and-modules.wast b/binaryen/test/passes/minify-imports-and-exports-and-modules.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/minify-imports-and-exports-and-modules.wast
@@ -0,0 +1,8 @@
+(module
+  (import "env" "memory" (memory $0 256 256))
+  (import "env" "table" (table $0 4 funcref))
+  (import "env" "longname1" (func $internal1))
+  (import "env" "longname2" (func $internal2))
+  (import "env" "longname3" (func $internal3))
+  (import "other" "longname4" (func $internal4))
+)
diff --git a/binaryen/test/passes/minify-imports-and-exports_all-features.txt b/binaryen/test/passes/minify-imports-and-exports_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/minify-imports-and-exports_all-features.txt
@@ -0,0 +1,10028 @@
+longname51 => $
+longname2964 => $$
+longname3018 => $0
+longname3072 => $1
+longname3126 => $2
+longname3180 => $3
+longname3234 => $4
+longname3288 => $5
+longname3342 => $6
+longname3396 => $7
+longname3450 => $8
+longname3504 => $9
+longname1506 => $A
+longname4962 => $Aa
+longname1560 => $B
+longname1614 => $C
+longname1668 => $D
+longname1722 => $E
+longname1776 => $F
+longname1830 => $G
+longname1884 => $H
+longname1938 => $I
+longname1992 => $J
+longname2046 => $K
+longname2100 => $L
+longname2154 => $M
+longname2208 => $N
+longname2262 => $O
+longname2316 => $P
+longname2370 => $Q
+longname2424 => $R
+longname2478 => $S
+longname2532 => $T
+longname2586 => $U
+longname2640 => $V
+longname2694 => $W
+longname2748 => $X
+longname2802 => $Y
+longname2856 => $Z
+longname2910 => $_
+longname105 => $a
+longname3558 => $aa
+longname159 => $b
+longname3612 => $ba
+longname213 => $c
+longname3666 => $ca
+longname267 => $d
+longname3720 => $da
+longname321 => $e
+longname3774 => $ea
+longname374 => $f
+longname3828 => $fa
+longname428 => $g
+longname3882 => $ga
+longname482 => $h
+longname3936 => $ha
+longname536 => $i
+longname3990 => $ia
+longname590 => $j
+longname4044 => $ja
+longname644 => $k
+longname4098 => $ka
+longname698 => $l
+longname4152 => $la
+longname752 => $m
+longname4206 => $ma
+longname805 => $n
+longname4260 => $na
+longname858 => $o
+longname4314 => $oa
+longname912 => $p
+longname4368 => $pa
+longname966 => $q
+longname4422 => $qa
+longname1020 => $r
+longname4476 => $ra
+longname1074 => $s
+longname4530 => $sa
+longname1128 => $t
+longname4584 => $ta
+longname1182 => $u
+longname4638 => $ua
+longname1236 => $v
+longname4692 => $va
+longname1290 => $w
+longname4746 => $wa
+longname1344 => $x
+longname4800 => $xa
+longname1398 => $y
+longname4854 => $ya
+longname1452 => $z
+longname4908 => $za
+longname24 => A
+longname2937 => A$
+longname2991 => A0
+longname3045 => A1
+longname3099 => A2
+longname3153 => A3
+longname3207 => A4
+longname3261 => A5
+longname3315 => A6
+longname3369 => A7
+longname3423 => A8
+longname3477 => A9
+longname1479 => AA
+longname4935 => AAa
+longname1533 => AB
+longname4989 => ABa
+longname1587 => AC
+longname1641 => AD
+longname1695 => AE
+longname1749 => AF
+longname1803 => AG
+longname1857 => AH
+longname1911 => AI
+longname1965 => AJ
+longname2019 => AK
+longname2073 => AL
+longname2127 => AM
+longname2181 => AN
+longname2235 => AO
+longname2289 => AP
+longname2343 => AQ
+longname2397 => AR
+longname2451 => AS
+longname2505 => AT
+longname2559 => AU
+longname2613 => AV
+longname2667 => AW
+longname2721 => AX
+longname2775 => AY
+longname2829 => AZ
+longname2883 => A_
+longname78 => Aa
+longname3531 => Aaa
+longname132 => Ab
+longname3585 => Aba
+longname186 => Ac
+longname3639 => Aca
+longname240 => Ad
+longname3693 => Ada
+longname294 => Ae
+longname3747 => Aea
+longname347 => Af
+longname3801 => Afa
+longname401 => Ag
+longname3855 => Aga
+longname455 => Ah
+longname3909 => Aha
+longname509 => Ai
+longname3963 => Aia
+longname563 => Aj
+longname4017 => Aja
+longname617 => Ak
+longname4071 => Aka
+longname671 => Al
+longname4125 => Ala
+longname725 => Am
+longname4179 => Ama
+longname778 => An
+longname4233 => Ana
+longname831 => Ao
+longname4287 => Aoa
+longname885 => Ap
+longname4341 => Apa
+longname939 => Aq
+longname4395 => Aqa
+longname993 => Ar
+longname4449 => Ara
+longname1047 => As
+longname4503 => Asa
+longname1101 => At
+longname4557 => Ata
+longname1155 => Au
+longname4611 => Aua
+longname1209 => Av
+longname4665 => Ava
+longname1263 => Aw
+longname4719 => Awa
+longname1317 => Ax
+longname4773 => Axa
+longname1371 => Ay
+longname4827 => Aya
+longname1425 => Az
+longname4881 => Aza
+longname25 => B
+longname2938 => B$
+longname2992 => B0
+longname3046 => B1
+longname3100 => B2
+longname3154 => B3
+longname3208 => B4
+longname3262 => B5
+longname3316 => B6
+longname3370 => B7
+longname3424 => B8
+longname3478 => B9
+longname1480 => BA
+longname4936 => BAa
+longname1534 => BB
+longname4990 => BBa
+longname1588 => BC
+longname1642 => BD
+longname1696 => BE
+longname1750 => BF
+longname1804 => BG
+longname1858 => BH
+longname1912 => BI
+longname1966 => BJ
+longname2020 => BK
+longname2074 => BL
+longname2128 => BM
+longname2182 => BN
+longname2236 => BO
+longname2290 => BP
+longname2344 => BQ
+longname2398 => BR
+longname2452 => BS
+longname2506 => BT
+longname2560 => BU
+longname2614 => BV
+longname2668 => BW
+longname2722 => BX
+longname2776 => BY
+longname2830 => BZ
+longname2884 => B_
+longname79 => Ba
+longname3532 => Baa
+longname133 => Bb
+longname3586 => Bba
+longname187 => Bc
+longname3640 => Bca
+longname241 => Bd
+longname3694 => Bda
+longname295 => Be
+longname3748 => Bea
+longname348 => Bf
+longname3802 => Bfa
+longname402 => Bg
+longname3856 => Bga
+longname456 => Bh
+longname3910 => Bha
+longname510 => Bi
+longname3964 => Bia
+longname564 => Bj
+longname4018 => Bja
+longname618 => Bk
+longname4072 => Bka
+longname672 => Bl
+longname4126 => Bla
+longname726 => Bm
+longname4180 => Bma
+longname779 => Bn
+longname4234 => Bna
+longname832 => Bo
+longname4288 => Boa
+longname886 => Bp
+longname4342 => Bpa
+longname940 => Bq
+longname4396 => Bqa
+longname994 => Br
+longname4450 => Bra
+longname1048 => Bs
+longname4504 => Bsa
+longname1102 => Bt
+longname4558 => Bta
+longname1156 => Bu
+longname4612 => Bua
+longname1210 => Bv
+longname4666 => Bva
+longname1264 => Bw
+longname4720 => Bwa
+longname1318 => Bx
+longname4774 => Bxa
+longname1372 => By
+longname4828 => Bya
+longname1426 => Bz
+longname4882 => Bza
+longname26 => C
+longname2939 => C$
+longname2993 => C0
+longname3047 => C1
+longname3101 => C2
+longname3155 => C3
+longname3209 => C4
+longname3263 => C5
+longname3317 => C6
+longname3371 => C7
+longname3425 => C8
+longname3479 => C9
+longname1481 => CA
+longname4937 => CAa
+longname1535 => CB
+longname4991 => CBa
+longname1589 => CC
+longname1643 => CD
+longname1697 => CE
+longname1751 => CF
+longname1805 => CG
+longname1859 => CH
+longname1913 => CI
+longname1967 => CJ
+longname2021 => CK
+longname2075 => CL
+longname2129 => CM
+longname2183 => CN
+longname2237 => CO
+longname2291 => CP
+longname2345 => CQ
+longname2399 => CR
+longname2453 => CS
+longname2507 => CT
+longname2561 => CU
+longname2615 => CV
+longname2669 => CW
+longname2723 => CX
+longname2777 => CY
+longname2831 => CZ
+longname2885 => C_
+longname80 => Ca
+longname3533 => Caa
+longname134 => Cb
+longname3587 => Cba
+longname188 => Cc
+longname3641 => Cca
+longname242 => Cd
+longname3695 => Cda
+longname296 => Ce
+longname3749 => Cea
+longname349 => Cf
+longname3803 => Cfa
+longname403 => Cg
+longname3857 => Cga
+longname457 => Ch
+longname3911 => Cha
+longname511 => Ci
+longname3965 => Cia
+longname565 => Cj
+longname4019 => Cja
+longname619 => Ck
+longname4073 => Cka
+longname673 => Cl
+longname4127 => Cla
+longname727 => Cm
+longname4181 => Cma
+longname780 => Cn
+longname4235 => Cna
+longname833 => Co
+longname4289 => Coa
+longname887 => Cp
+longname4343 => Cpa
+longname941 => Cq
+longname4397 => Cqa
+longname995 => Cr
+longname4451 => Cra
+longname1049 => Cs
+longname4505 => Csa
+longname1103 => Ct
+longname4559 => Cta
+longname1157 => Cu
+longname4613 => Cua
+longname1211 => Cv
+longname4667 => Cva
+longname1265 => Cw
+longname4721 => Cwa
+longname1319 => Cx
+longname4775 => Cxa
+longname1373 => Cy
+longname4829 => Cya
+longname1427 => Cz
+longname4883 => Cza
+longname27 => D
+longname2940 => D$
+longname2994 => D0
+longname3048 => D1
+longname3102 => D2
+longname3156 => D3
+longname3210 => D4
+longname3264 => D5
+longname3318 => D6
+longname3372 => D7
+longname3426 => D8
+longname3480 => D9
+longname1482 => DA
+longname4938 => DAa
+longname1536 => DB
+longname4992 => DBa
+longname1590 => DC
+longname1644 => DD
+longname1698 => DE
+longname1752 => DF
+longname1806 => DG
+longname1860 => DH
+longname1914 => DI
+longname1968 => DJ
+longname2022 => DK
+longname2076 => DL
+longname2130 => DM
+longname2184 => DN
+longname2238 => DO
+longname2292 => DP
+longname2346 => DQ
+longname2400 => DR
+longname2454 => DS
+longname2508 => DT
+longname2562 => DU
+longname2616 => DV
+longname2670 => DW
+longname2724 => DX
+longname2778 => DY
+longname2832 => DZ
+longname2886 => D_
+longname81 => Da
+longname3534 => Daa
+longname135 => Db
+longname3588 => Dba
+longname189 => Dc
+longname3642 => Dca
+longname243 => Dd
+longname3696 => Dda
+longname297 => De
+longname3750 => Dea
+longname350 => Df
+longname3804 => Dfa
+longname404 => Dg
+longname3858 => Dga
+longname458 => Dh
+longname3912 => Dha
+longname512 => Di
+longname3966 => Dia
+longname566 => Dj
+longname4020 => Dja
+longname620 => Dk
+longname4074 => Dka
+longname674 => Dl
+longname4128 => Dla
+longname728 => Dm
+longname4182 => Dma
+longname781 => Dn
+longname4236 => Dna
+longname834 => Do
+longname4290 => Doa
+longname888 => Dp
+longname4344 => Dpa
+longname942 => Dq
+longname4398 => Dqa
+longname996 => Dr
+longname4452 => Dra
+longname1050 => Ds
+longname4506 => Dsa
+longname1104 => Dt
+longname4560 => Dta
+longname1158 => Du
+longname4614 => Dua
+longname1212 => Dv
+longname4668 => Dva
+longname1266 => Dw
+longname4722 => Dwa
+longname1320 => Dx
+longname4776 => Dxa
+longname1374 => Dy
+longname4830 => Dya
+longname1428 => Dz
+longname4884 => Dza
+longname28 => E
+longname2941 => E$
+longname2995 => E0
+longname3049 => E1
+longname3103 => E2
+longname3157 => E3
+longname3211 => E4
+longname3265 => E5
+longname3319 => E6
+longname3373 => E7
+longname3427 => E8
+longname3481 => E9
+longname1483 => EA
+longname4939 => EAa
+longname1537 => EB
+longname4993 => EBa
+longname1591 => EC
+longname1645 => ED
+longname1699 => EE
+longname1753 => EF
+longname1807 => EG
+longname1861 => EH
+longname1915 => EI
+longname1969 => EJ
+longname2023 => EK
+longname2077 => EL
+longname2131 => EM
+longname2185 => EN
+longname2239 => EO
+longname2293 => EP
+longname2347 => EQ
+longname2401 => ER
+longname2455 => ES
+longname2509 => ET
+longname2563 => EU
+longname2617 => EV
+longname2671 => EW
+longname2725 => EX
+longname2779 => EY
+longname2833 => EZ
+longname2887 => E_
+longname82 => Ea
+longname3535 => Eaa
+longname136 => Eb
+longname3589 => Eba
+longname190 => Ec
+longname3643 => Eca
+longname244 => Ed
+longname3697 => Eda
+longname298 => Ee
+longname3751 => Eea
+longname351 => Ef
+longname3805 => Efa
+longname405 => Eg
+longname3859 => Ega
+longname459 => Eh
+longname3913 => Eha
+longname513 => Ei
+longname3967 => Eia
+longname567 => Ej
+longname4021 => Eja
+longname621 => Ek
+longname4075 => Eka
+longname675 => El
+longname4129 => Ela
+longname729 => Em
+longname4183 => Ema
+longname782 => En
+longname4237 => Ena
+longname835 => Eo
+longname4291 => Eoa
+longname889 => Ep
+longname4345 => Epa
+longname943 => Eq
+longname4399 => Eqa
+longname997 => Er
+longname4453 => Era
+longname1051 => Es
+longname4507 => Esa
+longname1105 => Et
+longname4561 => Eta
+longname1159 => Eu
+longname4615 => Eua
+longname1213 => Ev
+longname4669 => Eva
+longname1267 => Ew
+longname4723 => Ewa
+longname1321 => Ex
+longname4777 => Exa
+longname1375 => Ey
+longname4831 => Eya
+longname1429 => Ez
+longname4885 => Eza
+longname29 => F
+longname2942 => F$
+longname2996 => F0
+longname3050 => F1
+longname3104 => F2
+longname3158 => F3
+longname3212 => F4
+longname3266 => F5
+longname3320 => F6
+longname3374 => F7
+longname3428 => F8
+longname3482 => F9
+longname1484 => FA
+longname4940 => FAa
+longname1538 => FB
+longname4994 => FBa
+longname1592 => FC
+longname1646 => FD
+longname1700 => FE
+longname1754 => FF
+longname1808 => FG
+longname1862 => FH
+longname1916 => FI
+longname1970 => FJ
+longname2024 => FK
+longname2078 => FL
+longname2132 => FM
+longname2186 => FN
+longname2240 => FO
+longname2294 => FP
+longname2348 => FQ
+longname2402 => FR
+longname2456 => FS
+longname2510 => FT
+longname2564 => FU
+longname2618 => FV
+longname2672 => FW
+longname2726 => FX
+longname2780 => FY
+longname2834 => FZ
+longname2888 => F_
+longname83 => Fa
+longname3536 => Faa
+longname137 => Fb
+longname3590 => Fba
+longname191 => Fc
+longname3644 => Fca
+longname245 => Fd
+longname3698 => Fda
+longname299 => Fe
+longname3752 => Fea
+longname352 => Ff
+longname3806 => Ffa
+longname406 => Fg
+longname3860 => Fga
+longname460 => Fh
+longname3914 => Fha
+longname514 => Fi
+longname3968 => Fia
+longname568 => Fj
+longname4022 => Fja
+longname622 => Fk
+longname4076 => Fka
+longname676 => Fl
+longname4130 => Fla
+longname730 => Fm
+longname4184 => Fma
+longname783 => Fn
+longname4238 => Fna
+longname836 => Fo
+longname4292 => Foa
+longname890 => Fp
+longname4346 => Fpa
+longname944 => Fq
+longname4400 => Fqa
+longname998 => Fr
+longname4454 => Fra
+longname1052 => Fs
+longname4508 => Fsa
+longname1106 => Ft
+longname4562 => Fta
+longname1160 => Fu
+longname4616 => Fua
+longname1214 => Fv
+longname4670 => Fva
+longname1268 => Fw
+longname4724 => Fwa
+longname1322 => Fx
+longname4778 => Fxa
+longname1376 => Fy
+longname4832 => Fya
+longname1430 => Fz
+longname4886 => Fza
+longname30 => G
+longname2943 => G$
+longname2997 => G0
+longname3051 => G1
+longname3105 => G2
+longname3159 => G3
+longname3213 => G4
+longname3267 => G5
+longname3321 => G6
+longname3375 => G7
+longname3429 => G8
+longname3483 => G9
+longname1485 => GA
+longname4941 => GAa
+longname1539 => GB
+longname4995 => GBa
+longname1593 => GC
+longname1647 => GD
+longname1701 => GE
+longname1755 => GF
+longname1809 => GG
+longname1863 => GH
+longname1917 => GI
+longname1971 => GJ
+longname2025 => GK
+longname2079 => GL
+longname2133 => GM
+longname2187 => GN
+longname2241 => GO
+longname2295 => GP
+longname2349 => GQ
+longname2403 => GR
+longname2457 => GS
+longname2511 => GT
+longname2565 => GU
+longname2619 => GV
+longname2673 => GW
+longname2727 => GX
+longname2781 => GY
+longname2835 => GZ
+longname2889 => G_
+longname84 => Ga
+longname3537 => Gaa
+longname138 => Gb
+longname3591 => Gba
+longname192 => Gc
+longname3645 => Gca
+longname246 => Gd
+longname3699 => Gda
+longname300 => Ge
+longname3753 => Gea
+longname353 => Gf
+longname3807 => Gfa
+longname407 => Gg
+longname3861 => Gga
+longname461 => Gh
+longname3915 => Gha
+longname515 => Gi
+longname3969 => Gia
+longname569 => Gj
+longname4023 => Gja
+longname623 => Gk
+longname4077 => Gka
+longname677 => Gl
+longname4131 => Gla
+longname731 => Gm
+longname4185 => Gma
+longname784 => Gn
+longname4239 => Gna
+longname837 => Go
+longname4293 => Goa
+longname891 => Gp
+longname4347 => Gpa
+longname945 => Gq
+longname4401 => Gqa
+longname999 => Gr
+longname4455 => Gra
+longname1053 => Gs
+longname4509 => Gsa
+longname1107 => Gt
+longname4563 => Gta
+longname1161 => Gu
+longname4617 => Gua
+longname1215 => Gv
+longname4671 => Gva
+longname1269 => Gw
+longname4725 => Gwa
+longname1323 => Gx
+longname4779 => Gxa
+longname1377 => Gy
+longname4833 => Gya
+longname1431 => Gz
+longname4887 => Gza
+longname31 => H
+longname2944 => H$
+longname2998 => H0
+longname3052 => H1
+longname3106 => H2
+longname3160 => H3
+longname3214 => H4
+longname3268 => H5
+longname3322 => H6
+longname3376 => H7
+longname3430 => H8
+longname3484 => H9
+longname1486 => HA
+longname4942 => HAa
+longname1540 => HB
+longname4996 => HBa
+longname1594 => HC
+longname1648 => HD
+longname1702 => HE
+longname1756 => HF
+longname1810 => HG
+longname1864 => HH
+longname1918 => HI
+longname1972 => HJ
+longname2026 => HK
+longname2080 => HL
+longname2134 => HM
+longname2188 => HN
+longname2242 => HO
+longname2296 => HP
+longname2350 => HQ
+longname2404 => HR
+longname2458 => HS
+longname2512 => HT
+longname2566 => HU
+longname2620 => HV
+longname2674 => HW
+longname2728 => HX
+longname2782 => HY
+longname2836 => HZ
+longname2890 => H_
+longname85 => Ha
+longname3538 => Haa
+longname139 => Hb
+longname3592 => Hba
+longname193 => Hc
+longname3646 => Hca
+longname247 => Hd
+longname3700 => Hda
+longname301 => He
+longname3754 => Hea
+longname354 => Hf
+longname3808 => Hfa
+longname408 => Hg
+longname3862 => Hga
+longname462 => Hh
+longname3916 => Hha
+longname516 => Hi
+longname3970 => Hia
+longname570 => Hj
+longname4024 => Hja
+longname624 => Hk
+longname4078 => Hka
+longname678 => Hl
+longname4132 => Hla
+longname732 => Hm
+longname4186 => Hma
+longname785 => Hn
+longname4240 => Hna
+longname838 => Ho
+longname4294 => Hoa
+longname892 => Hp
+longname4348 => Hpa
+longname946 => Hq
+longname4402 => Hqa
+longname1000 => Hr
+longname4456 => Hra
+longname1054 => Hs
+longname4510 => Hsa
+longname1108 => Ht
+longname4564 => Hta
+longname1162 => Hu
+longname4618 => Hua
+longname1216 => Hv
+longname4672 => Hva
+longname1270 => Hw
+longname4726 => Hwa
+longname1324 => Hx
+longname4780 => Hxa
+longname1378 => Hy
+longname4834 => Hya
+longname1432 => Hz
+longname4888 => Hza
+longname32 => I
+longname2945 => I$
+longname2999 => I0
+longname3053 => I1
+longname3107 => I2
+longname3161 => I3
+longname3215 => I4
+longname3269 => I5
+longname3323 => I6
+longname3377 => I7
+longname3431 => I8
+longname3485 => I9
+longname1487 => IA
+longname4943 => IAa
+longname1541 => IB
+longname4997 => IBa
+longname1595 => IC
+longname1649 => ID
+longname1703 => IE
+longname1757 => IF
+longname1811 => IG
+longname1865 => IH
+longname1919 => II
+longname1973 => IJ
+longname2027 => IK
+longname2081 => IL
+longname2135 => IM
+longname2189 => IN
+longname2243 => IO
+longname2297 => IP
+longname2351 => IQ
+longname2405 => IR
+longname2459 => IS
+longname2513 => IT
+longname2567 => IU
+longname2621 => IV
+longname2675 => IW
+longname2729 => IX
+longname2783 => IY
+longname2837 => IZ
+longname2891 => I_
+longname86 => Ia
+longname3539 => Iaa
+longname140 => Ib
+longname3593 => Iba
+longname194 => Ic
+longname3647 => Ica
+longname248 => Id
+longname3701 => Ida
+longname302 => Ie
+longname3755 => Iea
+longname355 => If
+longname3809 => Ifa
+longname409 => Ig
+longname3863 => Iga
+longname463 => Ih
+longname3917 => Iha
+longname517 => Ii
+longname3971 => Iia
+longname571 => Ij
+longname4025 => Ija
+longname625 => Ik
+longname4079 => Ika
+longname679 => Il
+longname4133 => Ila
+longname733 => Im
+longname4187 => Ima
+longname786 => In
+longname4241 => Ina
+longname839 => Io
+longname4295 => Ioa
+longname893 => Ip
+longname4349 => Ipa
+longname947 => Iq
+longname4403 => Iqa
+longname1001 => Ir
+longname4457 => Ira
+longname1055 => Is
+longname4511 => Isa
+longname1109 => It
+longname4565 => Ita
+longname1163 => Iu
+longname4619 => Iua
+longname1217 => Iv
+longname4673 => Iva
+longname1271 => Iw
+longname4727 => Iwa
+longname1325 => Ix
+longname4781 => Ixa
+longname1379 => Iy
+longname4835 => Iya
+longname1433 => Iz
+longname4889 => Iza
+longname33 => J
+longname2946 => J$
+longname3000 => J0
+longname3054 => J1
+longname3108 => J2
+longname3162 => J3
+longname3216 => J4
+longname3270 => J5
+longname3324 => J6
+longname3378 => J7
+longname3432 => J8
+longname3486 => J9
+longname1488 => JA
+longname4944 => JAa
+longname1542 => JB
+longname4998 => JBa
+longname1596 => JC
+longname1650 => JD
+longname1704 => JE
+longname1758 => JF
+longname1812 => JG
+longname1866 => JH
+longname1920 => JI
+longname1974 => JJ
+longname2028 => JK
+longname2082 => JL
+longname2136 => JM
+longname2190 => JN
+longname2244 => JO
+longname2298 => JP
+longname2352 => JQ
+longname2406 => JR
+longname2460 => JS
+longname2514 => JT
+longname2568 => JU
+longname2622 => JV
+longname2676 => JW
+longname2730 => JX
+longname2784 => JY
+longname2838 => JZ
+longname2892 => J_
+longname87 => Ja
+longname3540 => Jaa
+longname141 => Jb
+longname3594 => Jba
+longname195 => Jc
+longname3648 => Jca
+longname249 => Jd
+longname3702 => Jda
+longname303 => Je
+longname3756 => Jea
+longname356 => Jf
+longname3810 => Jfa
+longname410 => Jg
+longname3864 => Jga
+longname464 => Jh
+longname3918 => Jha
+longname518 => Ji
+longname3972 => Jia
+longname572 => Jj
+longname4026 => Jja
+longname626 => Jk
+longname4080 => Jka
+longname680 => Jl
+longname4134 => Jla
+longname734 => Jm
+longname4188 => Jma
+longname787 => Jn
+longname4242 => Jna
+longname840 => Jo
+longname4296 => Joa
+longname894 => Jp
+longname4350 => Jpa
+longname948 => Jq
+longname4404 => Jqa
+longname1002 => Jr
+longname4458 => Jra
+longname1056 => Js
+longname4512 => Jsa
+longname1110 => Jt
+longname4566 => Jta
+longname1164 => Ju
+longname4620 => Jua
+longname1218 => Jv
+longname4674 => Jva
+longname1272 => Jw
+longname4728 => Jwa
+longname1326 => Jx
+longname4782 => Jxa
+longname1380 => Jy
+longname4836 => Jya
+longname1434 => Jz
+longname4890 => Jza
+longname34 => K
+longname2947 => K$
+longname3001 => K0
+longname3055 => K1
+longname3109 => K2
+longname3163 => K3
+longname3217 => K4
+longname3271 => K5
+longname3325 => K6
+longname3379 => K7
+longname3433 => K8
+longname3487 => K9
+longname1489 => KA
+longname4945 => KAa
+longname1543 => KB
+longname4999 => KBa
+longname1597 => KC
+longname1651 => KD
+longname1705 => KE
+longname1759 => KF
+longname1813 => KG
+longname1867 => KH
+longname1921 => KI
+longname1975 => KJ
+longname2029 => KK
+longname2083 => KL
+longname2137 => KM
+longname2191 => KN
+longname2245 => KO
+longname2299 => KP
+longname2353 => KQ
+longname2407 => KR
+longname2461 => KS
+longname2515 => KT
+longname2569 => KU
+longname2623 => KV
+longname2677 => KW
+longname2731 => KX
+longname2785 => KY
+longname2839 => KZ
+longname2893 => K_
+longname88 => Ka
+longname3541 => Kaa
+longname142 => Kb
+longname3595 => Kba
+longname196 => Kc
+longname3649 => Kca
+longname250 => Kd
+longname3703 => Kda
+longname304 => Ke
+longname3757 => Kea
+longname357 => Kf
+longname3811 => Kfa
+longname411 => Kg
+longname3865 => Kga
+longname465 => Kh
+longname3919 => Kha
+longname519 => Ki
+longname3973 => Kia
+longname573 => Kj
+longname4027 => Kja
+longname627 => Kk
+longname4081 => Kka
+longname681 => Kl
+longname4135 => Kla
+longname735 => Km
+longname4189 => Kma
+longname788 => Kn
+longname4243 => Kna
+longname841 => Ko
+longname4297 => Koa
+longname895 => Kp
+longname4351 => Kpa
+longname949 => Kq
+longname4405 => Kqa
+longname1003 => Kr
+longname4459 => Kra
+longname1057 => Ks
+longname4513 => Ksa
+longname1111 => Kt
+longname4567 => Kta
+longname1165 => Ku
+longname4621 => Kua
+longname1219 => Kv
+longname4675 => Kva
+longname1273 => Kw
+longname4729 => Kwa
+longname1327 => Kx
+longname4783 => Kxa
+longname1381 => Ky
+longname4837 => Kya
+longname1435 => Kz
+longname4891 => Kza
+longname35 => L
+longname2948 => L$
+longname3002 => L0
+longname3056 => L1
+longname3110 => L2
+longname3164 => L3
+longname3218 => L4
+longname3272 => L5
+longname3326 => L6
+longname3380 => L7
+longname3434 => L8
+longname3488 => L9
+longname1490 => LA
+longname4946 => LAa
+longname1544 => LB
+longname3-only => LBa
+longname1598 => LC
+longname1652 => LD
+longname1706 => LE
+longname1760 => LF
+longname1814 => LG
+longname1868 => LH
+longname1922 => LI
+longname1976 => LJ
+longname2030 => LK
+longname2084 => LL
+longname2138 => LM
+longname2192 => LN
+longname2246 => LO
+longname2300 => LP
+longname2354 => LQ
+longname2408 => LR
+longname2462 => LS
+longname2516 => LT
+longname2570 => LU
+longname2624 => LV
+longname2678 => LW
+longname2732 => LX
+longname2786 => LY
+longname2840 => LZ
+longname2894 => L_
+longname89 => La
+longname3542 => Laa
+longname143 => Lb
+longname3596 => Lba
+longname197 => Lc
+longname3650 => Lca
+longname251 => Ld
+longname3704 => Lda
+longname305 => Le
+longname3758 => Lea
+longname358 => Lf
+longname3812 => Lfa
+longname412 => Lg
+longname3866 => Lga
+longname466 => Lh
+longname3920 => Lha
+longname520 => Li
+longname3974 => Lia
+longname574 => Lj
+longname4028 => Lja
+longname628 => Lk
+longname4082 => Lka
+longname682 => Ll
+longname4136 => Lla
+longname736 => Lm
+longname4190 => Lma
+longname789 => Ln
+longname4244 => Lna
+longname842 => Lo
+longname4298 => Loa
+longname896 => Lp
+longname4352 => Lpa
+longname950 => Lq
+longname4406 => Lqa
+longname1004 => Lr
+longname4460 => Lra
+longname1058 => Ls
+longname4514 => Lsa
+longname1112 => Lt
+longname4568 => Lta
+longname1166 => Lu
+longname4622 => Lua
+longname1220 => Lv
+longname4676 => Lva
+longname1274 => Lw
+longname4730 => Lwa
+longname1328 => Lx
+longname4784 => Lxa
+longname1382 => Ly
+longname4838 => Lya
+longname1436 => Lz
+longname4892 => Lza
+longname36 => M
+longname2949 => M$
+longname3003 => M0
+longname3057 => M1
+longname3111 => M2
+longname3165 => M3
+longname3219 => M4
+longname3273 => M5
+longname3327 => M6
+longname3381 => M7
+longname3435 => M8
+longname3489 => M9
+longname1491 => MA
+longname4947 => MAa
+longname1545 => MB
+eventname1 => MBa
+longname1599 => MC
+longname1653 => MD
+longname1707 => ME
+longname1761 => MF
+longname1815 => MG
+longname1869 => MH
+longname1923 => MI
+longname1977 => MJ
+longname2031 => MK
+longname2085 => ML
+longname2139 => MM
+longname2193 => MN
+longname2247 => MO
+longname2301 => MP
+longname2355 => MQ
+longname2409 => MR
+longname2463 => MS
+longname2517 => MT
+longname2571 => MU
+longname2625 => MV
+longname2679 => MW
+longname2733 => MX
+longname2787 => MY
+longname2841 => MZ
+longname2895 => M_
+longname90 => Ma
+longname3543 => Maa
+longname144 => Mb
+longname3597 => Mba
+longname198 => Mc
+longname3651 => Mca
+longname252 => Md
+longname3705 => Mda
+longname306 => Me
+longname3759 => Mea
+longname359 => Mf
+longname3813 => Mfa
+longname413 => Mg
+longname3867 => Mga
+longname467 => Mh
+longname3921 => Mha
+longname521 => Mi
+longname3975 => Mia
+longname575 => Mj
+longname4029 => Mja
+longname629 => Mk
+longname4083 => Mka
+longname683 => Ml
+longname4137 => Mla
+longname737 => Mm
+longname4191 => Mma
+longname790 => Mn
+longname4245 => Mna
+longname843 => Mo
+longname4299 => Moa
+longname897 => Mp
+longname4353 => Mpa
+longname951 => Mq
+longname4407 => Mqa
+longname1005 => Mr
+longname4461 => Mra
+longname1059 => Ms
+longname4515 => Msa
+longname1113 => Mt
+longname4569 => Mta
+longname1167 => Mu
+longname4623 => Mua
+longname1221 => Mv
+longname4677 => Mva
+longname1275 => Mw
+longname4731 => Mwa
+longname1329 => Mx
+longname4785 => Mxa
+longname1383 => My
+longname4839 => Mya
+longname1437 => Mz
+longname4893 => Mza
+longname37 => N
+longname2950 => N$
+longname3004 => N0
+longname3058 => N1
+longname3112 => N2
+longname3166 => N3
+longname3220 => N4
+longname3274 => N5
+longname3328 => N6
+longname3382 => N7
+longname3436 => N8
+longname3490 => N9
+longname1492 => NA
+longname4948 => NAa
+longname1546 => NB
+exp1 => NBa
+longname1600 => NC
+longname1654 => ND
+longname1708 => NE
+longname1762 => NF
+longname1816 => NG
+longname1870 => NH
+longname1924 => NI
+longname1978 => NJ
+longname2032 => NK
+longname2086 => NL
+longname2140 => NM
+longname2194 => NN
+longname2248 => NO
+longname2302 => NP
+longname2356 => NQ
+longname2410 => NR
+longname2464 => NS
+longname2518 => NT
+longname2572 => NU
+longname2626 => NV
+longname2680 => NW
+longname2734 => NX
+longname2788 => NY
+longname2842 => NZ
+longname2896 => N_
+longname91 => Na
+longname3544 => Naa
+longname145 => Nb
+longname3598 => Nba
+longname199 => Nc
+longname3652 => Nca
+longname253 => Nd
+longname3706 => Nda
+longname307 => Ne
+longname3760 => Nea
+longname360 => Nf
+longname3814 => Nfa
+longname414 => Ng
+longname3868 => Nga
+longname468 => Nh
+longname3922 => Nha
+longname522 => Ni
+longname3976 => Nia
+longname576 => Nj
+longname4030 => Nja
+longname630 => Nk
+longname4084 => Nka
+longname684 => Nl
+longname4138 => Nla
+longname738 => Nm
+longname4192 => Nma
+longname791 => Nn
+longname4246 => Nna
+longname844 => No
+longname4300 => Noa
+longname898 => Np
+longname4354 => Npa
+longname952 => Nq
+longname4408 => Nqa
+longname1006 => Nr
+longname4462 => Nra
+longname1060 => Ns
+longname4516 => Nsa
+longname1114 => Nt
+longname4570 => Nta
+longname1168 => Nu
+longname4624 => Nua
+longname1222 => Nv
+longname4678 => Nva
+longname1276 => Nw
+longname4732 => Nwa
+longname1330 => Nx
+longname4786 => Nxa
+longname1384 => Ny
+longname4840 => Nya
+longname1438 => Nz
+longname4894 => Nza
+longname38 => O
+longname2951 => O$
+longname3005 => O0
+longname3059 => O1
+longname3113 => O2
+longname3167 => O3
+longname3221 => O4
+longname3275 => O5
+longname3329 => O6
+longname3383 => O7
+longname3437 => O8
+longname3491 => O9
+longname1493 => OA
+longname4949 => OAa
+longname1547 => OB
+exp2 => OBa
+longname1601 => OC
+longname1655 => OD
+longname1709 => OE
+longname1763 => OF
+longname1817 => OG
+longname1871 => OH
+longname1925 => OI
+longname1979 => OJ
+longname2033 => OK
+longname2087 => OL
+longname2141 => OM
+longname2195 => ON
+longname2249 => OO
+longname2303 => OP
+longname2357 => OQ
+longname2411 => OR
+longname2465 => OS
+longname2519 => OT
+longname2573 => OU
+longname2627 => OV
+longname2681 => OW
+longname2735 => OX
+longname2789 => OY
+longname2843 => OZ
+longname2897 => O_
+longname92 => Oa
+longname3545 => Oaa
+longname146 => Ob
+longname3599 => Oba
+longname200 => Oc
+longname3653 => Oca
+longname254 => Od
+longname3707 => Oda
+longname308 => Oe
+longname3761 => Oea
+longname361 => Of
+longname3815 => Ofa
+longname415 => Og
+longname3869 => Oga
+longname469 => Oh
+longname3923 => Oha
+longname523 => Oi
+longname3977 => Oia
+longname577 => Oj
+longname4031 => Oja
+longname631 => Ok
+longname4085 => Oka
+longname685 => Ol
+longname4139 => Ola
+longname739 => Om
+longname4193 => Oma
+longname792 => On
+longname4247 => Ona
+longname845 => Oo
+longname4301 => Ooa
+longname899 => Op
+longname4355 => Opa
+longname953 => Oq
+longname4409 => Oqa
+longname1007 => Or
+longname4463 => Ora
+longname1061 => Os
+longname4517 => Osa
+longname1115 => Ot
+longname4571 => Ota
+longname1169 => Ou
+longname4625 => Oua
+longname1223 => Ov
+longname4679 => Ova
+longname1277 => Ow
+longname4733 => Owa
+longname1331 => Ox
+longname4787 => Oxa
+longname1385 => Oy
+longname4841 => Oya
+longname1439 => Oz
+longname4895 => Oza
+longname39 => P
+longname2952 => P$
+longname3006 => P0
+longname3060 => P1
+longname3114 => P2
+longname3168 => P3
+longname3222 => P4
+longname3276 => P5
+longname3330 => P6
+longname3384 => P7
+longname3438 => P8
+longname3492 => P9
+longname1494 => PA
+longname4950 => PAa
+longname1548 => PB
+event1 => PBa
+longname1602 => PC
+longname1656 => PD
+longname1710 => PE
+longname1764 => PF
+longname1818 => PG
+longname1872 => PH
+longname1926 => PI
+longname1980 => PJ
+longname2034 => PK
+longname2088 => PL
+longname2142 => PM
+longname2196 => PN
+longname2250 => PO
+longname2304 => PP
+longname2358 => PQ
+longname2412 => PR
+longname2466 => PS
+longname2520 => PT
+longname2574 => PU
+longname2628 => PV
+longname2682 => PW
+longname2736 => PX
+longname2790 => PY
+longname2844 => PZ
+longname2898 => P_
+longname93 => Pa
+longname3546 => Paa
+longname147 => Pb
+longname3600 => Pba
+longname201 => Pc
+longname3654 => Pca
+longname255 => Pd
+longname3708 => Pda
+longname309 => Pe
+longname3762 => Pea
+longname362 => Pf
+longname3816 => Pfa
+longname416 => Pg
+longname3870 => Pga
+longname470 => Ph
+longname3924 => Pha
+longname524 => Pi
+longname3978 => Pia
+longname578 => Pj
+longname4032 => Pja
+longname632 => Pk
+longname4086 => Pka
+longname686 => Pl
+longname4140 => Pla
+longname740 => Pm
+longname4194 => Pma
+longname793 => Pn
+longname4248 => Pna
+longname846 => Po
+longname4302 => Poa
+longname900 => Pp
+longname4356 => Ppa
+longname954 => Pq
+longname4410 => Pqa
+longname1008 => Pr
+longname4464 => Pra
+longname1062 => Ps
+longname4518 => Psa
+longname1116 => Pt
+longname4572 => Pta
+longname1170 => Pu
+longname4626 => Pua
+longname1224 => Pv
+longname4680 => Pva
+longname1278 => Pw
+longname4734 => Pwa
+longname1332 => Px
+longname4788 => Pxa
+longname1386 => Py
+longname4842 => Pya
+longname1440 => Pz
+longname4896 => Pza
+longname40 => Q
+longname2953 => Q$
+longname3007 => Q0
+longname3061 => Q1
+longname3115 => Q2
+longname3169 => Q3
+longname3223 => Q4
+longname3277 => Q5
+longname3331 => Q6
+longname3385 => Q7
+longname3439 => Q8
+longname3493 => Q9
+longname1495 => QA
+longname4951 => QAa
+longname1549 => QB
+longname1603 => QC
+longname1657 => QD
+longname1711 => QE
+longname1765 => QF
+longname1819 => QG
+longname1873 => QH
+longname1927 => QI
+longname1981 => QJ
+longname2035 => QK
+longname2089 => QL
+longname2143 => QM
+longname2197 => QN
+longname2251 => QO
+longname2305 => QP
+longname2359 => QQ
+longname2413 => QR
+longname2467 => QS
+longname2521 => QT
+longname2575 => QU
+longname2629 => QV
+longname2683 => QW
+longname2737 => QX
+longname2791 => QY
+longname2845 => QZ
+longname2899 => Q_
+longname94 => Qa
+longname3547 => Qaa
+longname148 => Qb
+longname3601 => Qba
+longname202 => Qc
+longname3655 => Qca
+longname256 => Qd
+longname3709 => Qda
+longname310 => Qe
+longname3763 => Qea
+longname363 => Qf
+longname3817 => Qfa
+longname417 => Qg
+longname3871 => Qga
+longname471 => Qh
+longname3925 => Qha
+longname525 => Qi
+longname3979 => Qia
+longname579 => Qj
+longname4033 => Qja
+longname633 => Qk
+longname4087 => Qka
+longname687 => Ql
+longname4141 => Qla
+longname741 => Qm
+longname4195 => Qma
+longname794 => Qn
+longname4249 => Qna
+longname847 => Qo
+longname4303 => Qoa
+longname901 => Qp
+longname4357 => Qpa
+longname955 => Qq
+longname4411 => Qqa
+longname1009 => Qr
+longname4465 => Qra
+longname1063 => Qs
+longname4519 => Qsa
+longname1117 => Qt
+longname4573 => Qta
+longname1171 => Qu
+longname4627 => Qua
+longname1225 => Qv
+longname4681 => Qva
+longname1279 => Qw
+longname4735 => Qwa
+longname1333 => Qx
+longname4789 => Qxa
+longname1387 => Qy
+longname4843 => Qya
+longname1441 => Qz
+longname4897 => Qza
+longname41 => R
+longname2954 => R$
+longname3008 => R0
+longname3062 => R1
+longname3116 => R2
+longname3170 => R3
+longname3224 => R4
+longname3278 => R5
+longname3332 => R6
+longname3386 => R7
+longname3440 => R8
+longname3494 => R9
+longname1496 => RA
+longname4952 => RAa
+longname1550 => RB
+longname1604 => RC
+longname1658 => RD
+longname1712 => RE
+longname1766 => RF
+longname1820 => RG
+longname1874 => RH
+longname1928 => RI
+longname1982 => RJ
+longname2036 => RK
+longname2090 => RL
+longname2144 => RM
+longname2198 => RN
+longname2252 => RO
+longname2306 => RP
+longname2360 => RQ
+longname2414 => RR
+longname2468 => RS
+longname2522 => RT
+longname2576 => RU
+longname2630 => RV
+longname2684 => RW
+longname2738 => RX
+longname2792 => RY
+longname2846 => RZ
+longname2900 => R_
+longname95 => Ra
+longname3548 => Raa
+longname149 => Rb
+longname3602 => Rba
+longname203 => Rc
+longname3656 => Rca
+longname257 => Rd
+longname3710 => Rda
+longname311 => Re
+longname3764 => Rea
+longname364 => Rf
+longname3818 => Rfa
+longname418 => Rg
+longname3872 => Rga
+longname472 => Rh
+longname3926 => Rha
+longname526 => Ri
+longname3980 => Ria
+longname580 => Rj
+longname4034 => Rja
+longname634 => Rk
+longname4088 => Rka
+longname688 => Rl
+longname4142 => Rla
+longname742 => Rm
+longname4196 => Rma
+longname795 => Rn
+longname4250 => Rna
+longname848 => Ro
+longname4304 => Roa
+longname902 => Rp
+longname4358 => Rpa
+longname956 => Rq
+longname4412 => Rqa
+longname1010 => Rr
+longname4466 => Rra
+longname1064 => Rs
+longname4520 => Rsa
+longname1118 => Rt
+longname4574 => Rta
+longname1172 => Ru
+longname4628 => Rua
+longname1226 => Rv
+longname4682 => Rva
+longname1280 => Rw
+longname4736 => Rwa
+longname1334 => Rx
+longname4790 => Rxa
+longname1388 => Ry
+longname4844 => Rya
+longname1442 => Rz
+longname4898 => Rza
+longname42 => S
+longname2955 => S$
+longname3009 => S0
+longname3063 => S1
+longname3117 => S2
+longname3171 => S3
+longname3225 => S4
+longname3279 => S5
+longname3333 => S6
+longname3387 => S7
+longname3441 => S8
+longname3495 => S9
+longname1497 => SA
+longname4953 => SAa
+longname1551 => SB
+longname1605 => SC
+longname1659 => SD
+longname1713 => SE
+longname1767 => SF
+longname1821 => SG
+longname1875 => SH
+longname1929 => SI
+longname1983 => SJ
+longname2037 => SK
+longname2091 => SL
+longname2145 => SM
+longname2199 => SN
+longname2253 => SO
+longname2307 => SP
+longname2361 => SQ
+longname2415 => SR
+longname2469 => SS
+longname2523 => ST
+longname2577 => SU
+longname2631 => SV
+longname2685 => SW
+longname2739 => SX
+longname2793 => SY
+longname2847 => SZ
+longname2901 => S_
+longname96 => Sa
+longname3549 => Saa
+longname150 => Sb
+longname3603 => Sba
+longname204 => Sc
+longname3657 => Sca
+longname258 => Sd
+longname3711 => Sda
+longname312 => Se
+longname3765 => Sea
+longname365 => Sf
+longname3819 => Sfa
+longname419 => Sg
+longname3873 => Sga
+longname473 => Sh
+longname3927 => Sha
+longname527 => Si
+longname3981 => Sia
+longname581 => Sj
+longname4035 => Sja
+longname635 => Sk
+longname4089 => Ska
+longname689 => Sl
+longname4143 => Sla
+longname743 => Sm
+longname4197 => Sma
+longname796 => Sn
+longname4251 => Sna
+longname849 => So
+longname4305 => Soa
+longname903 => Sp
+longname4359 => Spa
+longname957 => Sq
+longname4413 => Sqa
+longname1011 => Sr
+longname4467 => Sra
+longname1065 => Ss
+longname4521 => Ssa
+longname1119 => St
+longname4575 => Sta
+longname1173 => Su
+longname4629 => Sua
+longname1227 => Sv
+longname4683 => Sva
+longname1281 => Sw
+longname4737 => Swa
+longname1335 => Sx
+longname4791 => Sxa
+longname1389 => Sy
+longname4845 => Sya
+longname1443 => Sz
+longname4899 => Sza
+longname43 => T
+longname2956 => T$
+longname3010 => T0
+longname3064 => T1
+longname3118 => T2
+longname3172 => T3
+longname3226 => T4
+longname3280 => T5
+longname3334 => T6
+longname3388 => T7
+longname3442 => T8
+longname3496 => T9
+longname1498 => TA
+longname4954 => TAa
+longname1552 => TB
+longname1606 => TC
+longname1660 => TD
+longname1714 => TE
+longname1768 => TF
+longname1822 => TG
+longname1876 => TH
+longname1930 => TI
+longname1984 => TJ
+longname2038 => TK
+longname2092 => TL
+longname2146 => TM
+longname2200 => TN
+longname2254 => TO
+longname2308 => TP
+longname2362 => TQ
+longname2416 => TR
+longname2470 => TS
+longname2524 => TT
+longname2578 => TU
+longname2632 => TV
+longname2686 => TW
+longname2740 => TX
+longname2794 => TY
+longname2848 => TZ
+longname2902 => T_
+longname97 => Ta
+longname3550 => Taa
+longname151 => Tb
+longname3604 => Tba
+longname205 => Tc
+longname3658 => Tca
+longname259 => Td
+longname3712 => Tda
+longname313 => Te
+longname3766 => Tea
+longname366 => Tf
+longname3820 => Tfa
+longname420 => Tg
+longname3874 => Tga
+longname474 => Th
+longname3928 => Tha
+longname528 => Ti
+longname3982 => Tia
+longname582 => Tj
+longname4036 => Tja
+longname636 => Tk
+longname4090 => Tka
+longname690 => Tl
+longname4144 => Tla
+longname744 => Tm
+longname4198 => Tma
+longname797 => Tn
+longname4252 => Tna
+longname850 => To
+longname4306 => Toa
+longname904 => Tp
+longname4360 => Tpa
+longname958 => Tq
+longname4414 => Tqa
+longname1012 => Tr
+longname4468 => Tra
+longname1066 => Ts
+longname4522 => Tsa
+longname1120 => Tt
+longname4576 => Tta
+longname1174 => Tu
+longname4630 => Tua
+longname1228 => Tv
+longname4684 => Tva
+longname1282 => Tw
+longname4738 => Twa
+longname1336 => Tx
+longname4792 => Txa
+longname1390 => Ty
+longname4846 => Tya
+longname1444 => Tz
+longname4900 => Tza
+longname44 => U
+longname2957 => U$
+longname3011 => U0
+longname3065 => U1
+longname3119 => U2
+longname3173 => U3
+longname3227 => U4
+longname3281 => U5
+longname3335 => U6
+longname3389 => U7
+longname3443 => U8
+longname3497 => U9
+longname1499 => UA
+longname4955 => UAa
+longname1553 => UB
+longname1607 => UC
+longname1661 => UD
+longname1715 => UE
+longname1769 => UF
+longname1823 => UG
+longname1877 => UH
+longname1931 => UI
+longname1985 => UJ
+longname2039 => UK
+longname2093 => UL
+longname2147 => UM
+longname2201 => UN
+longname2255 => UO
+longname2309 => UP
+longname2363 => UQ
+longname2417 => UR
+longname2471 => US
+longname2525 => UT
+longname2579 => UU
+longname2633 => UV
+longname2687 => UW
+longname2741 => UX
+longname2795 => UY
+longname2849 => UZ
+longname2903 => U_
+longname98 => Ua
+longname3551 => Uaa
+longname152 => Ub
+longname3605 => Uba
+longname206 => Uc
+longname3659 => Uca
+longname260 => Ud
+longname3713 => Uda
+longname314 => Ue
+longname3767 => Uea
+longname367 => Uf
+longname3821 => Ufa
+longname421 => Ug
+longname3875 => Uga
+longname475 => Uh
+longname3929 => Uha
+longname529 => Ui
+longname3983 => Uia
+longname583 => Uj
+longname4037 => Uja
+longname637 => Uk
+longname4091 => Uka
+longname691 => Ul
+longname4145 => Ula
+longname745 => Um
+longname4199 => Uma
+longname798 => Un
+longname4253 => Una
+longname851 => Uo
+longname4307 => Uoa
+longname905 => Up
+longname4361 => Upa
+longname959 => Uq
+longname4415 => Uqa
+longname1013 => Ur
+longname4469 => Ura
+longname1067 => Us
+longname4523 => Usa
+longname1121 => Ut
+longname4577 => Uta
+longname1175 => Uu
+longname4631 => Uua
+longname1229 => Uv
+longname4685 => Uva
+longname1283 => Uw
+longname4739 => Uwa
+longname1337 => Ux
+longname4793 => Uxa
+longname1391 => Uy
+longname4847 => Uya
+longname1445 => Uz
+longname4901 => Uza
+longname45 => V
+longname2958 => V$
+longname3012 => V0
+longname3066 => V1
+longname3120 => V2
+longname3174 => V3
+longname3228 => V4
+longname3282 => V5
+longname3336 => V6
+longname3390 => V7
+longname3444 => V8
+longname3498 => V9
+longname1500 => VA
+longname4956 => VAa
+longname1554 => VB
+longname1608 => VC
+longname1662 => VD
+longname1716 => VE
+longname1770 => VF
+longname1824 => VG
+longname1878 => VH
+longname1932 => VI
+longname1986 => VJ
+longname2040 => VK
+longname2094 => VL
+longname2148 => VM
+longname2202 => VN
+longname2256 => VO
+longname2310 => VP
+longname2364 => VQ
+longname2418 => VR
+longname2472 => VS
+longname2526 => VT
+longname2580 => VU
+longname2634 => VV
+longname2688 => VW
+longname2742 => VX
+longname2796 => VY
+longname2850 => VZ
+longname2904 => V_
+longname99 => Va
+longname3552 => Vaa
+longname153 => Vb
+longname3606 => Vba
+longname207 => Vc
+longname3660 => Vca
+longname261 => Vd
+longname3714 => Vda
+longname315 => Ve
+longname3768 => Vea
+longname368 => Vf
+longname3822 => Vfa
+longname422 => Vg
+longname3876 => Vga
+longname476 => Vh
+longname3930 => Vha
+longname530 => Vi
+longname3984 => Via
+longname584 => Vj
+longname4038 => Vja
+longname638 => Vk
+longname4092 => Vka
+longname692 => Vl
+longname4146 => Vla
+longname746 => Vm
+longname4200 => Vma
+longname799 => Vn
+longname4254 => Vna
+longname852 => Vo
+longname4308 => Voa
+longname906 => Vp
+longname4362 => Vpa
+longname960 => Vq
+longname4416 => Vqa
+longname1014 => Vr
+longname4470 => Vra
+longname1068 => Vs
+longname4524 => Vsa
+longname1122 => Vt
+longname4578 => Vta
+longname1176 => Vu
+longname4632 => Vua
+longname1230 => Vv
+longname4686 => Vva
+longname1284 => Vw
+longname4740 => Vwa
+longname1338 => Vx
+longname4794 => Vxa
+longname1392 => Vy
+longname4848 => Vya
+longname1446 => Vz
+longname4902 => Vza
+longname46 => W
+longname2959 => W$
+longname3013 => W0
+longname3067 => W1
+longname3121 => W2
+longname3175 => W3
+longname3229 => W4
+longname3283 => W5
+longname3337 => W6
+longname3391 => W7
+longname3445 => W8
+longname3499 => W9
+longname1501 => WA
+longname4957 => WAa
+longname1555 => WB
+longname1609 => WC
+longname1663 => WD
+longname1717 => WE
+longname1771 => WF
+longname1825 => WG
+longname1879 => WH
+longname1933 => WI
+longname1987 => WJ
+longname2041 => WK
+longname2095 => WL
+longname2149 => WM
+longname2203 => WN
+longname2257 => WO
+longname2311 => WP
+longname2365 => WQ
+longname2419 => WR
+longname2473 => WS
+longname2527 => WT
+longname2581 => WU
+longname2635 => WV
+longname2689 => WW
+longname2743 => WX
+longname2797 => WY
+longname2851 => WZ
+longname2905 => W_
+longname100 => Wa
+longname3553 => Waa
+longname154 => Wb
+longname3607 => Wba
+longname208 => Wc
+longname3661 => Wca
+longname262 => Wd
+longname3715 => Wda
+longname316 => We
+longname3769 => Wea
+longname369 => Wf
+longname3823 => Wfa
+longname423 => Wg
+longname3877 => Wga
+longname477 => Wh
+longname3931 => Wha
+longname531 => Wi
+longname3985 => Wia
+longname585 => Wj
+longname4039 => Wja
+longname639 => Wk
+longname4093 => Wka
+longname693 => Wl
+longname4147 => Wla
+longname747 => Wm
+longname4201 => Wma
+longname800 => Wn
+longname4255 => Wna
+longname853 => Wo
+longname4309 => Woa
+longname907 => Wp
+longname4363 => Wpa
+longname961 => Wq
+longname4417 => Wqa
+longname1015 => Wr
+longname4471 => Wra
+longname1069 => Ws
+longname4525 => Wsa
+longname1123 => Wt
+longname4579 => Wta
+longname1177 => Wu
+longname4633 => Wua
+longname1231 => Wv
+longname4687 => Wva
+longname1285 => Ww
+longname4741 => Wwa
+longname1339 => Wx
+longname4795 => Wxa
+longname1393 => Wy
+longname4849 => Wya
+longname1447 => Wz
+longname4903 => Wza
+longname47 => X
+longname2960 => X$
+longname3014 => X0
+longname3068 => X1
+longname3122 => X2
+longname3176 => X3
+longname3230 => X4
+longname3284 => X5
+longname3338 => X6
+longname3392 => X7
+longname3446 => X8
+longname3500 => X9
+longname1502 => XA
+longname4958 => XAa
+longname1556 => XB
+longname1610 => XC
+longname1664 => XD
+longname1718 => XE
+longname1772 => XF
+longname1826 => XG
+longname1880 => XH
+longname1934 => XI
+longname1988 => XJ
+longname2042 => XK
+longname2096 => XL
+longname2150 => XM
+longname2204 => XN
+longname2258 => XO
+longname2312 => XP
+longname2366 => XQ
+longname2420 => XR
+longname2474 => XS
+longname2528 => XT
+longname2582 => XU
+longname2636 => XV
+longname2690 => XW
+longname2744 => XX
+longname2798 => XY
+longname2852 => XZ
+longname2906 => X_
+longname101 => Xa
+longname3554 => Xaa
+longname155 => Xb
+longname3608 => Xba
+longname209 => Xc
+longname3662 => Xca
+longname263 => Xd
+longname3716 => Xda
+longname317 => Xe
+longname3770 => Xea
+longname370 => Xf
+longname3824 => Xfa
+longname424 => Xg
+longname3878 => Xga
+longname478 => Xh
+longname3932 => Xha
+longname532 => Xi
+longname3986 => Xia
+longname586 => Xj
+longname4040 => Xja
+longname640 => Xk
+longname4094 => Xka
+longname694 => Xl
+longname4148 => Xla
+longname748 => Xm
+longname4202 => Xma
+longname801 => Xn
+longname4256 => Xna
+longname854 => Xo
+longname4310 => Xoa
+longname908 => Xp
+longname4364 => Xpa
+longname962 => Xq
+longname4418 => Xqa
+longname1016 => Xr
+longname4472 => Xra
+longname1070 => Xs
+longname4526 => Xsa
+longname1124 => Xt
+longname4580 => Xta
+longname1178 => Xu
+longname4634 => Xua
+longname1232 => Xv
+longname4688 => Xva
+longname1286 => Xw
+longname4742 => Xwa
+longname1340 => Xx
+longname4796 => Xxa
+longname1394 => Xy
+longname4850 => Xya
+longname1448 => Xz
+longname4904 => Xza
+longname48 => Y
+longname2961 => Y$
+longname3015 => Y0
+longname3069 => Y1
+longname3123 => Y2
+longname3177 => Y3
+longname3231 => Y4
+longname3285 => Y5
+longname3339 => Y6
+longname3393 => Y7
+longname3447 => Y8
+longname3501 => Y9
+longname1503 => YA
+longname4959 => YAa
+longname1557 => YB
+longname1611 => YC
+longname1665 => YD
+longname1719 => YE
+longname1773 => YF
+longname1827 => YG
+longname1881 => YH
+longname1935 => YI
+longname1989 => YJ
+longname2043 => YK
+longname2097 => YL
+longname2151 => YM
+longname2205 => YN
+longname2259 => YO
+longname2313 => YP
+longname2367 => YQ
+longname2421 => YR
+longname2475 => YS
+longname2529 => YT
+longname2583 => YU
+longname2637 => YV
+longname2691 => YW
+longname2745 => YX
+longname2799 => YY
+longname2853 => YZ
+longname2907 => Y_
+longname102 => Ya
+longname3555 => Yaa
+longname156 => Yb
+longname3609 => Yba
+longname210 => Yc
+longname3663 => Yca
+longname264 => Yd
+longname3717 => Yda
+longname318 => Ye
+longname3771 => Yea
+longname371 => Yf
+longname3825 => Yfa
+longname425 => Yg
+longname3879 => Yga
+longname479 => Yh
+longname3933 => Yha
+longname533 => Yi
+longname3987 => Yia
+longname587 => Yj
+longname4041 => Yja
+longname641 => Yk
+longname4095 => Yka
+longname695 => Yl
+longname4149 => Yla
+longname749 => Ym
+longname4203 => Yma
+longname802 => Yn
+longname4257 => Yna
+longname855 => Yo
+longname4311 => Yoa
+longname909 => Yp
+longname4365 => Ypa
+longname963 => Yq
+longname4419 => Yqa
+longname1017 => Yr
+longname4473 => Yra
+longname1071 => Ys
+longname4527 => Ysa
+longname1125 => Yt
+longname4581 => Yta
+longname1179 => Yu
+longname4635 => Yua
+longname1233 => Yv
+longname4689 => Yva
+longname1287 => Yw
+longname4743 => Ywa
+longname1341 => Yx
+longname4797 => Yxa
+longname1395 => Yy
+longname4851 => Yya
+longname1449 => Yz
+longname4905 => Yza
+longname49 => Z
+longname2962 => Z$
+longname3016 => Z0
+longname3070 => Z1
+longname3124 => Z2
+longname3178 => Z3
+longname3232 => Z4
+longname3286 => Z5
+longname3340 => Z6
+longname3394 => Z7
+longname3448 => Z8
+longname3502 => Z9
+longname1504 => ZA
+longname4960 => ZAa
+longname1558 => ZB
+longname1612 => ZC
+longname1666 => ZD
+longname1720 => ZE
+longname1774 => ZF
+longname1828 => ZG
+longname1882 => ZH
+longname1936 => ZI
+longname1990 => ZJ
+longname2044 => ZK
+longname2098 => ZL
+longname2152 => ZM
+longname2206 => ZN
+longname2260 => ZO
+longname2314 => ZP
+longname2368 => ZQ
+longname2422 => ZR
+longname2476 => ZS
+longname2530 => ZT
+longname2584 => ZU
+longname2638 => ZV
+longname2692 => ZW
+longname2746 => ZX
+longname2800 => ZY
+longname2854 => ZZ
+longname2908 => Z_
+longname103 => Za
+longname3556 => Zaa
+longname157 => Zb
+longname3610 => Zba
+longname211 => Zc
+longname3664 => Zca
+longname265 => Zd
+longname3718 => Zda
+longname319 => Ze
+longname3772 => Zea
+longname372 => Zf
+longname3826 => Zfa
+longname426 => Zg
+longname3880 => Zga
+longname480 => Zh
+longname3934 => Zha
+longname534 => Zi
+longname3988 => Zia
+longname588 => Zj
+longname4042 => Zja
+longname642 => Zk
+longname4096 => Zka
+longname696 => Zl
+longname4150 => Zla
+longname750 => Zm
+longname4204 => Zma
+longname803 => Zn
+longname4258 => Zna
+longname856 => Zo
+longname4312 => Zoa
+longname910 => Zp
+longname4366 => Zpa
+longname964 => Zq
+longname4420 => Zqa
+longname1018 => Zr
+longname4474 => Zra
+longname1072 => Zs
+longname4528 => Zsa
+longname1126 => Zt
+longname4582 => Zta
+longname1180 => Zu
+longname4636 => Zua
+longname1234 => Zv
+longname4690 => Zva
+longname1288 => Zw
+longname4744 => Zwa
+longname1342 => Zx
+longname4798 => Zxa
+longname1396 => Zy
+longname4852 => Zya
+longname1450 => Zz
+longname4906 => Zza
+longname50 => _
+longname2963 => _$
+longname3017 => _0
+longname3071 => _1
+longname3125 => _2
+longname3179 => _3
+longname3233 => _4
+longname3287 => _5
+longname3341 => _6
+longname3395 => _7
+longname3449 => _8
+longname3503 => _9
+longname1505 => _A
+longname4961 => _Aa
+longname1559 => _B
+longname1613 => _C
+longname1667 => _D
+longname1721 => _E
+longname1775 => _F
+longname1829 => _G
+longname1883 => _H
+longname1937 => _I
+longname1991 => _J
+longname2045 => _K
+longname2099 => _L
+longname2153 => _M
+longname2207 => _N
+longname2261 => _O
+longname2315 => _P
+longname2369 => _Q
+longname2423 => _R
+longname2477 => _S
+longname2531 => _T
+longname2585 => _U
+longname2639 => _V
+longname2693 => _W
+longname2747 => _X
+longname2801 => _Y
+longname2855 => _Z
+longname2909 => __
+longname104 => _a
+longname3557 => _aa
+longname158 => _b
+longname3611 => _ba
+longname212 => _c
+longname3665 => _ca
+longname266 => _d
+longname3719 => _da
+longname320 => _e
+longname3773 => _ea
+longname373 => _f
+longname3827 => _fa
+longname427 => _g
+longname3881 => _ga
+longname481 => _h
+longname3935 => _ha
+longname535 => _i
+longname3989 => _ia
+longname589 => _j
+longname4043 => _ja
+longname643 => _k
+longname4097 => _ka
+longname697 => _l
+longname4151 => _la
+longname751 => _m
+longname4205 => _ma
+longname804 => _n
+longname4259 => _na
+longname857 => _o
+longname4313 => _oa
+longname911 => _p
+longname4367 => _pa
+longname965 => _q
+longname4421 => _qa
+longname1019 => _r
+longname4475 => _ra
+longname1073 => _s
+longname4529 => _sa
+longname1127 => _t
+longname4583 => _ta
+longname1181 => _u
+longname4637 => _ua
+longname1235 => _v
+longname4691 => _va
+longname1289 => _w
+longname4745 => _wa
+longname1343 => _x
+longname4799 => _xa
+longname1397 => _y
+longname4853 => _ya
+longname1451 => _z
+longname4907 => _za
+global => a
+longname2911 => a$
+longname2965 => a0
+longname3019 => a1
+longname3073 => a2
+longname3127 => a3
+longname3181 => a4
+longname3235 => a5
+longname3289 => a6
+longname3343 => a7
+longname3397 => a8
+longname3451 => a9
+longname1453 => aA
+longname4909 => aAa
+longname1507 => aB
+longname4963 => aBa
+longname1561 => aC
+longname1615 => aD
+longname1669 => aE
+longname1723 => aF
+longname1777 => aG
+longname1831 => aH
+longname1885 => aI
+longname1939 => aJ
+longname1993 => aK
+longname2047 => aL
+longname2101 => aM
+longname2155 => aN
+longname2209 => aO
+longname2263 => aP
+longname2317 => aQ
+longname2371 => aR
+longname2425 => aS
+longname2479 => aT
+longname2533 => aU
+longname2587 => aV
+longname2641 => aW
+longname2695 => aX
+longname2749 => aY
+longname2803 => aZ
+longname2857 => a_
+longname52 => aa
+longname3505 => aaa
+longname106 => ab
+longname3559 => aba
+longname160 => ac
+longname3613 => aca
+longname214 => ad
+longname3667 => ada
+longname268 => ae
+longname3721 => aea
+longname322 => af
+longname3775 => afa
+longname375 => ag
+longname3829 => aga
+longname429 => ah
+longname3883 => aha
+longname483 => ai
+longname3937 => aia
+longname537 => aj
+longname3991 => aja
+longname591 => ak
+longname4045 => aka
+longname645 => al
+longname4099 => ala
+longname699 => am
+longname4153 => ama
+longname753 => an
+longname4207 => ana
+longname806 => ao
+longname4261 => aoa
+longname859 => ap
+longname4315 => apa
+longname913 => aq
+longname4369 => aqa
+longname967 => ar
+longname4423 => ara
+longname1021 => as
+longname4477 => asa
+longname1075 => at
+longname4531 => ata
+longname1129 => au
+longname4585 => aua
+longname1183 => av
+longname4639 => ava
+longname1237 => aw
+longname4693 => awa
+longname1291 => ax
+longname4747 => axa
+longname1345 => ay
+longname4801 => aya
+longname1399 => az
+longname4855 => aza
+__memory_base => b
+longname2912 => b$
+longname2966 => b0
+longname3020 => b1
+longname3074 => b2
+longname3128 => b3
+longname3182 => b4
+longname3236 => b5
+longname3290 => b6
+longname3344 => b7
+longname3398 => b8
+longname3452 => b9
+longname1454 => bA
+longname4910 => bAa
+longname1508 => bB
+longname4964 => bBa
+longname1562 => bC
+longname1616 => bD
+longname1670 => bE
+longname1724 => bF
+longname1778 => bG
+longname1832 => bH
+longname1886 => bI
+longname1940 => bJ
+longname1994 => bK
+longname2048 => bL
+longname2102 => bM
+longname2156 => bN
+longname2210 => bO
+longname2264 => bP
+longname2318 => bQ
+longname2372 => bR
+longname2426 => bS
+longname2480 => bT
+longname2534 => bU
+longname2588 => bV
+longname2642 => bW
+longname2696 => bX
+longname2750 => bY
+longname2804 => bZ
+longname2858 => b_
+longname53 => ba
+longname3506 => baa
+longname107 => bb
+longname3560 => bba
+longname161 => bc
+longname3614 => bca
+longname215 => bd
+longname3668 => bda
+longname269 => be
+longname3722 => bea
+longname323 => bf
+longname3776 => bfa
+longname376 => bg
+longname3830 => bga
+longname430 => bh
+longname3884 => bha
+longname484 => bi
+longname3938 => bia
+longname538 => bj
+longname3992 => bja
+longname592 => bk
+longname4046 => bka
+longname646 => bl
+longname4100 => bla
+longname700 => bm
+longname4154 => bma
+longname754 => bn
+longname4208 => bna
+longname807 => bo
+longname4262 => boa
+longname860 => bp
+longname4316 => bpa
+longname914 => bq
+longname4370 => bqa
+longname968 => br
+longname4424 => bra
+longname1022 => bs
+longname4478 => bsa
+longname1076 => bt
+longname4532 => bta
+longname1130 => bu
+longname4586 => bua
+longname1184 => bv
+longname4640 => bva
+longname1238 => bw
+longname4694 => bwa
+longname1292 => bx
+longname4748 => bxa
+longname1346 => by
+longname4802 => bya
+longname1400 => bz
+longname4856 => bza
+__table_base => c
+longname2913 => c$
+longname2967 => c0
+longname3021 => c1
+longname3075 => c2
+longname3129 => c3
+longname3183 => c4
+longname3237 => c5
+longname3291 => c6
+longname3345 => c7
+longname3399 => c8
+longname3453 => c9
+longname1455 => cA
+longname4911 => cAa
+longname1509 => cB
+longname4965 => cBa
+longname1563 => cC
+longname1617 => cD
+longname1671 => cE
+longname1725 => cF
+longname1779 => cG
+longname1833 => cH
+longname1887 => cI
+longname1941 => cJ
+longname1995 => cK
+longname2049 => cL
+longname2103 => cM
+longname2157 => cN
+longname2211 => cO
+longname2265 => cP
+longname2319 => cQ
+longname2373 => cR
+longname2427 => cS
+longname2481 => cT
+longname2535 => cU
+longname2589 => cV
+longname2643 => cW
+longname2697 => cX
+longname2751 => cY
+longname2805 => cZ
+longname2859 => c_
+longname54 => ca
+longname3507 => caa
+longname108 => cb
+longname3561 => cba
+longname162 => cc
+longname3615 => cca
+longname216 => cd
+longname3669 => cda
+longname270 => ce
+longname3723 => cea
+longname324 => cf
+longname3777 => cfa
+longname377 => cg
+longname3831 => cga
+longname431 => ch
+longname3885 => cha
+longname485 => ci
+longname3939 => cia
+longname539 => cj
+longname3993 => cja
+longname593 => ck
+longname4047 => cka
+longname647 => cl
+longname4101 => cla
+longname701 => cm
+longname4155 => cma
+longname755 => cn
+longname4209 => cna
+longname808 => co
+longname4263 => coa
+longname861 => cp
+longname4317 => cpa
+longname915 => cq
+longname4371 => cqa
+longname969 => cr
+longname4425 => cra
+longname1023 => cs
+longname4479 => csa
+longname1077 => ct
+longname4533 => cta
+longname1131 => cu
+longname4587 => cua
+longname1185 => cv
+longname4641 => cva
+longname1239 => cw
+longname4695 => cwa
+longname1293 => cx
+longname4749 => cxa
+longname1347 => cy
+longname4803 => cya
+longname1401 => cz
+longname4857 => cza
+longname1 => d
+longname2914 => d$
+longname2968 => d0
+longname3022 => d1
+longname3076 => d2
+longname3130 => d3
+longname3184 => d4
+longname3238 => d5
+longname3292 => d6
+longname3346 => d7
+longname3400 => d8
+longname3454 => d9
+longname1456 => dA
+longname4912 => dAa
+longname1510 => dB
+longname4966 => dBa
+longname1564 => dC
+longname1618 => dD
+longname1672 => dE
+longname1726 => dF
+longname1780 => dG
+longname1834 => dH
+longname1888 => dI
+longname1942 => dJ
+longname1996 => dK
+longname2050 => dL
+longname2104 => dM
+longname2158 => dN
+longname2212 => dO
+longname2266 => dP
+longname2320 => dQ
+longname2374 => dR
+longname2428 => dS
+longname2482 => dT
+longname2536 => dU
+longname2590 => dV
+longname2644 => dW
+longname2698 => dX
+longname2752 => dY
+longname2806 => dZ
+longname2860 => d_
+longname55 => da
+longname3508 => daa
+longname109 => db
+longname3562 => dba
+longname163 => dc
+longname3616 => dca
+longname217 => dd
+longname3670 => dda
+longname271 => de
+longname3724 => dea
+longname325 => df
+longname3778 => dfa
+longname378 => dg
+longname3832 => dga
+longname432 => dh
+longname3886 => dha
+longname486 => di
+longname3940 => dia
+longname540 => dj
+longname3994 => dja
+longname594 => dk
+longname4048 => dka
+longname648 => dl
+longname4102 => dla
+longname702 => dm
+longname4156 => dma
+longname756 => dn
+longname4210 => dna
+longname4264 => doa
+longname862 => dp
+longname4318 => dpa
+longname916 => dq
+longname4372 => dqa
+longname970 => dr
+longname4426 => dra
+longname1024 => ds
+longname4480 => dsa
+longname1078 => dt
+longname4534 => dta
+longname1132 => du
+longname4588 => dua
+longname1186 => dv
+longname4642 => dva
+longname1240 => dw
+longname4696 => dwa
+longname1294 => dx
+longname4750 => dxa
+longname1348 => dy
+longname4804 => dya
+longname1402 => dz
+longname4858 => dza
+longname2 => e
+longname2915 => e$
+longname2969 => e0
+longname3023 => e1
+longname3077 => e2
+longname3131 => e3
+longname3185 => e4
+longname3239 => e5
+longname3293 => e6
+longname3347 => e7
+longname3401 => e8
+longname3455 => e9
+longname1457 => eA
+longname4913 => eAa
+longname1511 => eB
+longname4967 => eBa
+longname1565 => eC
+longname1619 => eD
+longname1673 => eE
+longname1727 => eF
+longname1781 => eG
+longname1835 => eH
+longname1889 => eI
+longname1943 => eJ
+longname1997 => eK
+longname2051 => eL
+longname2105 => eM
+longname2159 => eN
+longname2213 => eO
+longname2267 => eP
+longname2321 => eQ
+longname2375 => eR
+longname2429 => eS
+longname2483 => eT
+longname2537 => eU
+longname2591 => eV
+longname2645 => eW
+longname2699 => eX
+longname2753 => eY
+longname2807 => eZ
+longname2861 => e_
+longname56 => ea
+longname3509 => eaa
+longname110 => eb
+longname3563 => eba
+longname164 => ec
+longname3617 => eca
+longname218 => ed
+longname3671 => eda
+longname272 => ee
+longname3725 => eea
+longname326 => ef
+longname3779 => efa
+longname379 => eg
+longname3833 => ega
+longname433 => eh
+longname3887 => eha
+longname487 => ei
+longname3941 => eia
+longname541 => ej
+longname3995 => eja
+longname595 => ek
+longname4049 => eka
+longname649 => el
+longname4103 => ela
+longname703 => em
+longname4157 => ema
+longname757 => en
+longname4211 => ena
+longname809 => eo
+longname4265 => eoa
+longname863 => ep
+longname4319 => epa
+longname917 => eq
+longname4373 => eqa
+longname971 => er
+longname4427 => era
+longname1025 => es
+longname4481 => esa
+longname1079 => et
+longname4535 => eta
+longname1133 => eu
+longname4589 => eua
+longname1187 => ev
+longname4643 => eva
+longname1241 => ew
+longname4697 => ewa
+longname1295 => ex
+longname4751 => exa
+longname1349 => ey
+longname4805 => eya
+longname1403 => ez
+longname4859 => eza
+longname3 => f
+longname2916 => f$
+longname2970 => f0
+longname3024 => f1
+longname3078 => f2
+longname3132 => f3
+longname3186 => f4
+longname3240 => f5
+longname3294 => f6
+longname3348 => f7
+longname3402 => f8
+longname3456 => f9
+longname1458 => fA
+longname4914 => fAa
+longname1512 => fB
+longname4968 => fBa
+longname1566 => fC
+longname1620 => fD
+longname1674 => fE
+longname1728 => fF
+longname1782 => fG
+longname1836 => fH
+longname1890 => fI
+longname1944 => fJ
+longname1998 => fK
+longname2052 => fL
+longname2106 => fM
+longname2160 => fN
+longname2214 => fO
+longname2268 => fP
+longname2322 => fQ
+longname2376 => fR
+longname2430 => fS
+longname2484 => fT
+longname2538 => fU
+longname2592 => fV
+longname2646 => fW
+longname2700 => fX
+longname2754 => fY
+longname2808 => fZ
+longname2862 => f_
+longname57 => fa
+longname3510 => faa
+longname111 => fb
+longname3564 => fba
+longname165 => fc
+longname3618 => fca
+longname219 => fd
+longname3672 => fda
+longname273 => fe
+longname3726 => fea
+longname327 => ff
+longname3780 => ffa
+longname380 => fg
+longname3834 => fga
+longname434 => fh
+longname3888 => fha
+longname488 => fi
+longname3942 => fia
+longname542 => fj
+longname3996 => fja
+longname596 => fk
+longname4050 => fka
+longname650 => fl
+longname4104 => fla
+longname704 => fm
+longname4158 => fma
+longname758 => fn
+longname4212 => fna
+longname810 => fo
+longname4266 => foa
+longname864 => fp
+longname4320 => fpa
+longname918 => fq
+longname4374 => fqa
+longname972 => fr
+longname4428 => fra
+longname1026 => fs
+longname4482 => fsa
+longname1080 => ft
+longname4536 => fta
+longname1134 => fu
+longname4590 => fua
+longname1188 => fv
+longname4644 => fva
+longname1242 => fw
+longname4698 => fwa
+longname1296 => fx
+longname4752 => fxa
+longname1350 => fy
+longname4806 => fya
+longname1404 => fz
+longname4860 => fza
+longname4 => g
+longname2917 => g$
+longname2971 => g0
+longname3025 => g1
+longname3079 => g2
+longname3133 => g3
+longname3187 => g4
+longname3241 => g5
+longname3295 => g6
+longname3349 => g7
+longname3403 => g8
+longname3457 => g9
+longname1459 => gA
+longname4915 => gAa
+longname1513 => gB
+longname4969 => gBa
+longname1567 => gC
+longname1621 => gD
+longname1675 => gE
+longname1729 => gF
+longname1783 => gG
+longname1837 => gH
+longname1891 => gI
+longname1945 => gJ
+longname1999 => gK
+longname2053 => gL
+longname2107 => gM
+longname2161 => gN
+longname2215 => gO
+longname2269 => gP
+longname2323 => gQ
+longname2377 => gR
+longname2431 => gS
+longname2485 => gT
+longname2539 => gU
+longname2593 => gV
+longname2647 => gW
+longname2701 => gX
+longname2755 => gY
+longname2809 => gZ
+longname2863 => g_
+longname58 => ga
+longname3511 => gaa
+longname112 => gb
+longname3565 => gba
+longname166 => gc
+longname3619 => gca
+longname220 => gd
+longname3673 => gda
+longname274 => ge
+longname3727 => gea
+longname328 => gf
+longname3781 => gfa
+longname381 => gg
+longname3835 => gga
+longname435 => gh
+longname3889 => gha
+longname489 => gi
+longname3943 => gia
+longname543 => gj
+longname3997 => gja
+longname597 => gk
+longname4051 => gka
+longname651 => gl
+longname4105 => gla
+longname705 => gm
+longname4159 => gma
+longname759 => gn
+longname4213 => gna
+longname811 => go
+longname4267 => goa
+longname865 => gp
+longname4321 => gpa
+longname919 => gq
+longname4375 => gqa
+longname973 => gr
+longname4429 => gra
+longname1027 => gs
+longname4483 => gsa
+longname1081 => gt
+longname4537 => gta
+longname1135 => gu
+longname4591 => gua
+longname1189 => gv
+longname4645 => gva
+longname1243 => gw
+longname4699 => gwa
+longname1297 => gx
+longname4753 => gxa
+longname1351 => gy
+longname4807 => gya
+longname1405 => gz
+longname4861 => gza
+longname5 => h
+longname2918 => h$
+longname2972 => h0
+longname3026 => h1
+longname3080 => h2
+longname3134 => h3
+longname3188 => h4
+longname3242 => h5
+longname3296 => h6
+longname3350 => h7
+longname3404 => h8
+longname3458 => h9
+longname1460 => hA
+longname4916 => hAa
+longname1514 => hB
+longname4970 => hBa
+longname1568 => hC
+longname1622 => hD
+longname1676 => hE
+longname1730 => hF
+longname1784 => hG
+longname1838 => hH
+longname1892 => hI
+longname1946 => hJ
+longname2000 => hK
+longname2054 => hL
+longname2108 => hM
+longname2162 => hN
+longname2216 => hO
+longname2270 => hP
+longname2324 => hQ
+longname2378 => hR
+longname2432 => hS
+longname2486 => hT
+longname2540 => hU
+longname2594 => hV
+longname2648 => hW
+longname2702 => hX
+longname2756 => hY
+longname2810 => hZ
+longname2864 => h_
+longname59 => ha
+longname3512 => haa
+longname113 => hb
+longname3566 => hba
+longname167 => hc
+longname3620 => hca
+longname221 => hd
+longname3674 => hda
+longname275 => he
+longname3728 => hea
+longname329 => hf
+longname3782 => hfa
+longname382 => hg
+longname3836 => hga
+longname436 => hh
+longname3890 => hha
+longname490 => hi
+longname3944 => hia
+longname544 => hj
+longname3998 => hja
+longname598 => hk
+longname4052 => hka
+longname652 => hl
+longname4106 => hla
+longname706 => hm
+longname4160 => hma
+longname760 => hn
+longname4214 => hna
+longname812 => ho
+longname4268 => hoa
+longname866 => hp
+longname4322 => hpa
+longname920 => hq
+longname4376 => hqa
+longname974 => hr
+longname4430 => hra
+longname1028 => hs
+longname4484 => hsa
+longname1082 => ht
+longname4538 => hta
+longname1136 => hu
+longname4592 => hua
+longname1190 => hv
+longname4646 => hva
+longname1244 => hw
+longname4700 => hwa
+longname1298 => hx
+longname4754 => hxa
+longname1352 => hy
+longname4808 => hya
+longname1406 => hz
+longname4862 => hza
+longname6 => i
+longname2919 => i$
+longname2973 => i0
+longname3027 => i1
+longname3081 => i2
+longname3135 => i3
+longname3189 => i4
+longname3243 => i5
+longname3297 => i6
+longname3351 => i7
+longname3405 => i8
+longname3459 => i9
+longname1461 => iA
+longname4917 => iAa
+longname1515 => iB
+longname4971 => iBa
+longname1569 => iC
+longname1623 => iD
+longname1677 => iE
+longname1731 => iF
+longname1785 => iG
+longname1839 => iH
+longname1893 => iI
+longname1947 => iJ
+longname2001 => iK
+longname2055 => iL
+longname2109 => iM
+longname2163 => iN
+longname2217 => iO
+longname2271 => iP
+longname2325 => iQ
+longname2379 => iR
+longname2433 => iS
+longname2487 => iT
+longname2541 => iU
+longname2595 => iV
+longname2649 => iW
+longname2703 => iX
+longname2757 => iY
+longname2811 => iZ
+longname2865 => i_
+longname60 => ia
+longname3513 => iaa
+longname114 => ib
+longname3567 => iba
+longname168 => ic
+longname3621 => ica
+longname222 => id
+longname3675 => ida
+longname276 => ie
+longname3729 => iea
+longname3783 => ifa
+longname383 => ig
+longname3837 => iga
+longname437 => ih
+longname3891 => iha
+longname491 => ii
+longname3945 => iia
+longname545 => ij
+longname3999 => ija
+longname599 => ik
+longname4053 => ika
+longname653 => il
+longname4107 => ila
+longname707 => im
+longname4161 => ima
+longname4215 => ina
+longname813 => io
+longname4269 => ioa
+longname867 => ip
+longname4323 => ipa
+longname921 => iq
+longname4377 => iqa
+longname975 => ir
+longname4431 => ira
+longname1029 => is
+longname4485 => isa
+longname1083 => it
+longname4539 => ita
+longname1137 => iu
+longname4593 => iua
+longname1191 => iv
+longname4647 => iva
+longname1245 => iw
+longname4701 => iwa
+longname1299 => ix
+longname4755 => ixa
+longname1353 => iy
+longname4809 => iya
+longname1407 => iz
+longname4863 => iza
+longname7 => j
+longname2920 => j$
+longname2974 => j0
+longname3028 => j1
+longname3082 => j2
+longname3136 => j3
+longname3190 => j4
+longname3244 => j5
+longname3298 => j6
+longname3352 => j7
+longname3406 => j8
+longname3460 => j9
+longname1462 => jA
+longname4918 => jAa
+longname1516 => jB
+longname4972 => jBa
+longname1570 => jC
+longname1624 => jD
+longname1678 => jE
+longname1732 => jF
+longname1786 => jG
+longname1840 => jH
+longname1894 => jI
+longname1948 => jJ
+longname2002 => jK
+longname2056 => jL
+longname2110 => jM
+longname2164 => jN
+longname2218 => jO
+longname2272 => jP
+longname2326 => jQ
+longname2380 => jR
+longname2434 => jS
+longname2488 => jT
+longname2542 => jU
+longname2596 => jV
+longname2650 => jW
+longname2704 => jX
+longname2758 => jY
+longname2812 => jZ
+longname2866 => j_
+longname61 => ja
+longname3514 => jaa
+longname115 => jb
+longname3568 => jba
+longname169 => jc
+longname3622 => jca
+longname223 => jd
+longname3676 => jda
+longname277 => je
+longname3730 => jea
+longname330 => jf
+longname3784 => jfa
+longname384 => jg
+longname3838 => jga
+longname438 => jh
+longname3892 => jha
+longname492 => ji
+longname3946 => jia
+longname546 => jj
+longname4000 => jja
+longname600 => jk
+longname4054 => jka
+longname654 => jl
+longname4108 => jla
+longname708 => jm
+longname4162 => jma
+longname761 => jn
+longname4216 => jna
+longname814 => jo
+longname4270 => joa
+longname868 => jp
+longname4324 => jpa
+longname922 => jq
+longname4378 => jqa
+longname976 => jr
+longname4432 => jra
+longname1030 => js
+longname4486 => jsa
+longname1084 => jt
+longname4540 => jta
+longname1138 => ju
+longname4594 => jua
+longname1192 => jv
+longname4648 => jva
+longname1246 => jw
+longname4702 => jwa
+longname1300 => jx
+longname4756 => jxa
+longname1354 => jy
+longname4810 => jya
+longname1408 => jz
+longname4864 => jza
+longname8 => k
+longname2921 => k$
+longname2975 => k0
+longname3029 => k1
+longname3083 => k2
+longname3137 => k3
+longname3191 => k4
+longname3245 => k5
+longname3299 => k6
+longname3353 => k7
+longname3407 => k8
+longname3461 => k9
+longname1463 => kA
+longname4919 => kAa
+longname1517 => kB
+longname4973 => kBa
+longname1571 => kC
+longname1625 => kD
+longname1679 => kE
+longname1733 => kF
+longname1787 => kG
+longname1841 => kH
+longname1895 => kI
+longname1949 => kJ
+longname2003 => kK
+longname2057 => kL
+longname2111 => kM
+longname2165 => kN
+longname2219 => kO
+longname2273 => kP
+longname2327 => kQ
+longname2381 => kR
+longname2435 => kS
+longname2489 => kT
+longname2543 => kU
+longname2597 => kV
+longname2651 => kW
+longname2705 => kX
+longname2759 => kY
+longname2813 => kZ
+longname2867 => k_
+longname62 => ka
+longname3515 => kaa
+longname116 => kb
+longname3569 => kba
+longname170 => kc
+longname3623 => kca
+longname224 => kd
+longname3677 => kda
+longname278 => ke
+longname3731 => kea
+longname331 => kf
+longname3785 => kfa
+longname385 => kg
+longname3839 => kga
+longname439 => kh
+longname3893 => kha
+longname493 => ki
+longname3947 => kia
+longname547 => kj
+longname4001 => kja
+longname601 => kk
+longname4055 => kka
+longname655 => kl
+longname4109 => kla
+longname709 => km
+longname4163 => kma
+longname762 => kn
+longname4217 => kna
+longname815 => ko
+longname4271 => koa
+longname869 => kp
+longname4325 => kpa
+longname923 => kq
+longname4379 => kqa
+longname977 => kr
+longname4433 => kra
+longname1031 => ks
+longname4487 => ksa
+longname1085 => kt
+longname4541 => kta
+longname1139 => ku
+longname4595 => kua
+longname1193 => kv
+longname4649 => kva
+longname1247 => kw
+longname4703 => kwa
+longname1301 => kx
+longname4757 => kxa
+longname1355 => ky
+longname4811 => kya
+longname1409 => kz
+longname4865 => kza
+longname9 => l
+longname2922 => l$
+longname2976 => l0
+longname3030 => l1
+longname3084 => l2
+longname3138 => l3
+longname3192 => l4
+longname3246 => l5
+longname3300 => l6
+longname3354 => l7
+longname3408 => l8
+longname3462 => l9
+longname1464 => lA
+longname4920 => lAa
+longname1518 => lB
+longname4974 => lBa
+longname1572 => lC
+longname1626 => lD
+longname1680 => lE
+longname1734 => lF
+longname1788 => lG
+longname1842 => lH
+longname1896 => lI
+longname1950 => lJ
+longname2004 => lK
+longname2058 => lL
+longname2112 => lM
+longname2166 => lN
+longname2220 => lO
+longname2274 => lP
+longname2328 => lQ
+longname2382 => lR
+longname2436 => lS
+longname2490 => lT
+longname2544 => lU
+longname2598 => lV
+longname2652 => lW
+longname2706 => lX
+longname2760 => lY
+longname2814 => lZ
+longname2868 => l_
+longname63 => la
+longname3516 => laa
+longname117 => lb
+longname3570 => lba
+longname171 => lc
+longname3624 => lca
+longname225 => ld
+longname3678 => lda
+longname279 => le
+longname3732 => lea
+longname332 => lf
+longname3786 => lfa
+longname386 => lg
+longname3840 => lga
+longname440 => lh
+longname3894 => lha
+longname494 => li
+longname3948 => lia
+longname548 => lj
+longname4002 => lja
+longname602 => lk
+longname4056 => lka
+longname656 => ll
+longname4110 => lla
+longname710 => lm
+longname4164 => lma
+longname763 => ln
+longname4218 => lna
+longname816 => lo
+longname4272 => loa
+longname870 => lp
+longname4326 => lpa
+longname924 => lq
+longname4380 => lqa
+longname978 => lr
+longname4434 => lra
+longname1032 => ls
+longname4488 => lsa
+longname1086 => lt
+longname4542 => lta
+longname1140 => lu
+longname4596 => lua
+longname1194 => lv
+longname4650 => lva
+longname1248 => lw
+longname4704 => lwa
+longname1302 => lx
+longname4758 => lxa
+longname1356 => ly
+longname4812 => lya
+longname1410 => lz
+longname4866 => lza
+longname10 => m
+longname2923 => m$
+longname2977 => m0
+longname3031 => m1
+longname3085 => m2
+longname3139 => m3
+longname3193 => m4
+longname3247 => m5
+longname3301 => m6
+longname3355 => m7
+longname3409 => m8
+longname3463 => m9
+longname1465 => mA
+longname4921 => mAa
+longname1519 => mB
+longname4975 => mBa
+longname1573 => mC
+longname1627 => mD
+longname1681 => mE
+longname1735 => mF
+longname1789 => mG
+longname1843 => mH
+longname1897 => mI
+longname1951 => mJ
+longname2005 => mK
+longname2059 => mL
+longname2113 => mM
+longname2167 => mN
+longname2221 => mO
+longname2275 => mP
+longname2329 => mQ
+longname2383 => mR
+longname2437 => mS
+longname2491 => mT
+longname2545 => mU
+longname2599 => mV
+longname2653 => mW
+longname2707 => mX
+longname2761 => mY
+longname2815 => mZ
+longname2869 => m_
+longname64 => ma
+longname3517 => maa
+longname118 => mb
+longname3571 => mba
+longname172 => mc
+longname3625 => mca
+longname226 => md
+longname3679 => mda
+longname280 => me
+longname3733 => mea
+longname333 => mf
+longname3787 => mfa
+longname387 => mg
+longname3841 => mga
+longname441 => mh
+longname3895 => mha
+longname495 => mi
+longname3949 => mia
+longname549 => mj
+longname4003 => mja
+longname603 => mk
+longname4057 => mka
+longname657 => ml
+longname4111 => mla
+longname711 => mm
+longname4165 => mma
+longname764 => mn
+longname4219 => mna
+longname817 => mo
+longname4273 => moa
+longname871 => mp
+longname4327 => mpa
+longname925 => mq
+longname4381 => mqa
+longname979 => mr
+longname4435 => mra
+longname1033 => ms
+longname4489 => msa
+longname1087 => mt
+longname4543 => mta
+longname1141 => mu
+longname4597 => mua
+longname1195 => mv
+longname4651 => mva
+longname1249 => mw
+longname4705 => mwa
+longname1303 => mx
+longname4759 => mxa
+longname1357 => my
+longname4813 => mya
+longname1411 => mz
+longname4867 => mza
+longname11 => n
+longname2924 => n$
+longname2978 => n0
+longname3032 => n1
+longname3086 => n2
+longname3140 => n3
+longname3194 => n4
+longname3248 => n5
+longname3302 => n6
+longname3356 => n7
+longname3410 => n8
+longname3464 => n9
+longname1466 => nA
+longname4922 => nAa
+longname1520 => nB
+longname4976 => nBa
+longname1574 => nC
+longname1628 => nD
+longname1682 => nE
+longname1736 => nF
+longname1790 => nG
+longname1844 => nH
+longname1898 => nI
+longname1952 => nJ
+longname2006 => nK
+longname2060 => nL
+longname2114 => nM
+longname2168 => nN
+longname2222 => nO
+longname2276 => nP
+longname2330 => nQ
+longname2384 => nR
+longname2438 => nS
+longname2492 => nT
+longname2546 => nU
+longname2600 => nV
+longname2654 => nW
+longname2708 => nX
+longname2762 => nY
+longname2816 => nZ
+longname2870 => n_
+longname65 => na
+longname3518 => naa
+longname119 => nb
+longname3572 => nba
+longname173 => nc
+longname3626 => nca
+longname227 => nd
+longname3680 => nda
+longname281 => ne
+longname3734 => nea
+longname334 => nf
+longname3788 => nfa
+longname388 => ng
+longname3842 => nga
+longname442 => nh
+longname3896 => nha
+longname496 => ni
+longname3950 => nia
+longname550 => nj
+longname4004 => nja
+longname604 => nk
+longname4058 => nka
+longname658 => nl
+longname4112 => nla
+longname712 => nm
+longname4166 => nma
+longname765 => nn
+longname4220 => nna
+longname818 => no
+longname4274 => noa
+longname872 => np
+longname4328 => npa
+longname926 => nq
+longname4382 => nqa
+longname980 => nr
+longname4436 => nra
+longname1034 => ns
+longname4490 => nsa
+longname1088 => nt
+longname4544 => nta
+longname1142 => nu
+longname4598 => nua
+longname1196 => nv
+longname4652 => nva
+longname1250 => nw
+longname4706 => nwa
+longname1304 => nx
+longname4760 => nxa
+longname1358 => ny
+longname4814 => nya
+longname1412 => nz
+longname4868 => nza
+longname12 => o
+longname2925 => o$
+longname2979 => o0
+longname3033 => o1
+longname3087 => o2
+longname3141 => o3
+longname3195 => o4
+longname3249 => o5
+longname3303 => o6
+longname3357 => o7
+longname3411 => o8
+longname3465 => o9
+longname1467 => oA
+longname4923 => oAa
+longname1521 => oB
+longname4977 => oBa
+longname1575 => oC
+longname1629 => oD
+longname1683 => oE
+longname1737 => oF
+longname1791 => oG
+longname1845 => oH
+longname1899 => oI
+longname1953 => oJ
+longname2007 => oK
+longname2061 => oL
+longname2115 => oM
+longname2169 => oN
+longname2223 => oO
+longname2277 => oP
+longname2331 => oQ
+longname2385 => oR
+longname2439 => oS
+longname2493 => oT
+longname2547 => oU
+longname2601 => oV
+longname2655 => oW
+longname2709 => oX
+longname2763 => oY
+longname2817 => oZ
+longname2871 => o_
+longname66 => oa
+longname3519 => oaa
+longname120 => ob
+longname3573 => oba
+longname174 => oc
+longname3627 => oca
+longname228 => od
+longname3681 => oda
+longname282 => oe
+longname3735 => oea
+longname335 => of
+longname3789 => ofa
+longname389 => og
+longname3843 => oga
+longname443 => oh
+longname3897 => oha
+longname497 => oi
+longname3951 => oia
+longname551 => oj
+longname4005 => oja
+longname605 => ok
+longname4059 => oka
+longname659 => ol
+longname4113 => ola
+longname713 => om
+longname4167 => oma
+longname766 => on
+longname4221 => ona
+longname819 => oo
+longname4275 => ooa
+longname873 => op
+longname4329 => opa
+longname927 => oq
+longname4383 => oqa
+longname981 => or
+longname4437 => ora
+longname1035 => os
+longname4491 => osa
+longname1089 => ot
+longname4545 => ota
+longname1143 => ou
+longname4599 => oua
+longname1197 => ov
+longname4653 => ova
+longname1251 => ow
+longname4707 => owa
+longname1305 => ox
+longname4761 => oxa
+longname1359 => oy
+longname4815 => oya
+longname1413 => oz
+longname4869 => oza
+longname13 => p
+longname2926 => p$
+longname2980 => p0
+longname3034 => p1
+longname3088 => p2
+longname3142 => p3
+longname3196 => p4
+longname3250 => p5
+longname3304 => p6
+longname3358 => p7
+longname3412 => p8
+longname3466 => p9
+longname1468 => pA
+longname4924 => pAa
+longname1522 => pB
+longname4978 => pBa
+longname1576 => pC
+longname1630 => pD
+longname1684 => pE
+longname1738 => pF
+longname1792 => pG
+longname1846 => pH
+longname1900 => pI
+longname1954 => pJ
+longname2008 => pK
+longname2062 => pL
+longname2116 => pM
+longname2170 => pN
+longname2224 => pO
+longname2278 => pP
+longname2332 => pQ
+longname2386 => pR
+longname2440 => pS
+longname2494 => pT
+longname2548 => pU
+longname2602 => pV
+longname2656 => pW
+longname2710 => pX
+longname2764 => pY
+longname2818 => pZ
+longname2872 => p_
+longname67 => pa
+longname3520 => paa
+longname121 => pb
+longname3574 => pba
+longname175 => pc
+longname3628 => pca
+longname229 => pd
+longname3682 => pda
+longname283 => pe
+longname3736 => pea
+longname336 => pf
+longname3790 => pfa
+longname390 => pg
+longname3844 => pga
+longname444 => ph
+longname3898 => pha
+longname498 => pi
+longname3952 => pia
+longname552 => pj
+longname4006 => pja
+longname606 => pk
+longname4060 => pka
+longname660 => pl
+longname4114 => pla
+longname714 => pm
+longname4168 => pma
+longname767 => pn
+longname4222 => pna
+longname820 => po
+longname4276 => poa
+longname874 => pp
+longname4330 => ppa
+longname928 => pq
+longname4384 => pqa
+longname982 => pr
+longname4438 => pra
+longname1036 => ps
+longname4492 => psa
+longname1090 => pt
+longname4546 => pta
+longname1144 => pu
+longname4600 => pua
+longname1198 => pv
+longname4654 => pva
+longname1252 => pw
+longname4708 => pwa
+longname1306 => px
+longname4762 => pxa
+longname1360 => py
+longname4816 => pya
+longname1414 => pz
+longname4870 => pza
+longname14 => q
+longname2927 => q$
+longname2981 => q0
+longname3035 => q1
+longname3089 => q2
+longname3143 => q3
+longname3197 => q4
+longname3251 => q5
+longname3305 => q6
+longname3359 => q7
+longname3413 => q8
+longname3467 => q9
+longname1469 => qA
+longname4925 => qAa
+longname1523 => qB
+longname4979 => qBa
+longname1577 => qC
+longname1631 => qD
+longname1685 => qE
+longname1739 => qF
+longname1793 => qG
+longname1847 => qH
+longname1901 => qI
+longname1955 => qJ
+longname2009 => qK
+longname2063 => qL
+longname2117 => qM
+longname2171 => qN
+longname2225 => qO
+longname2279 => qP
+longname2333 => qQ
+longname2387 => qR
+longname2441 => qS
+longname2495 => qT
+longname2549 => qU
+longname2603 => qV
+longname2657 => qW
+longname2711 => qX
+longname2765 => qY
+longname2819 => qZ
+longname2873 => q_
+longname68 => qa
+longname3521 => qaa
+longname122 => qb
+longname3575 => qba
+longname176 => qc
+longname3629 => qca
+longname230 => qd
+longname3683 => qda
+longname284 => qe
+longname3737 => qea
+longname337 => qf
+longname3791 => qfa
+longname391 => qg
+longname3845 => qga
+longname445 => qh
+longname3899 => qha
+longname499 => qi
+longname3953 => qia
+longname553 => qj
+longname4007 => qja
+longname607 => qk
+longname4061 => qka
+longname661 => ql
+longname4115 => qla
+longname715 => qm
+longname4169 => qma
+longname768 => qn
+longname4223 => qna
+longname821 => qo
+longname4277 => qoa
+longname875 => qp
+longname4331 => qpa
+longname929 => qq
+longname4385 => qqa
+longname983 => qr
+longname4439 => qra
+longname1037 => qs
+longname4493 => qsa
+longname1091 => qt
+longname4547 => qta
+longname1145 => qu
+longname4601 => qua
+longname1199 => qv
+longname4655 => qva
+longname1253 => qw
+longname4709 => qwa
+longname1307 => qx
+longname4763 => qxa
+longname1361 => qy
+longname4817 => qya
+longname1415 => qz
+longname4871 => qza
+longname15 => r
+longname2928 => r$
+longname2982 => r0
+longname3036 => r1
+longname3090 => r2
+longname3144 => r3
+longname3198 => r4
+longname3252 => r5
+longname3306 => r6
+longname3360 => r7
+longname3414 => r8
+longname3468 => r9
+longname1470 => rA
+longname4926 => rAa
+longname1524 => rB
+longname4980 => rBa
+longname1578 => rC
+longname1632 => rD
+longname1686 => rE
+longname1740 => rF
+longname1794 => rG
+longname1848 => rH
+longname1902 => rI
+longname1956 => rJ
+longname2010 => rK
+longname2064 => rL
+longname2118 => rM
+longname2172 => rN
+longname2226 => rO
+longname2280 => rP
+longname2334 => rQ
+longname2388 => rR
+longname2442 => rS
+longname2496 => rT
+longname2550 => rU
+longname2604 => rV
+longname2658 => rW
+longname2712 => rX
+longname2766 => rY
+longname2820 => rZ
+longname2874 => r_
+longname69 => ra
+longname3522 => raa
+longname123 => rb
+longname3576 => rba
+longname177 => rc
+longname3630 => rca
+longname231 => rd
+longname3684 => rda
+longname285 => re
+longname3738 => rea
+longname338 => rf
+longname3792 => rfa
+longname392 => rg
+longname3846 => rga
+longname446 => rh
+longname3900 => rha
+longname500 => ri
+longname3954 => ria
+longname554 => rj
+longname4008 => rja
+longname608 => rk
+longname4062 => rka
+longname662 => rl
+longname4116 => rla
+longname716 => rm
+longname4170 => rma
+longname769 => rn
+longname4224 => rna
+longname822 => ro
+longname4278 => roa
+longname876 => rp
+longname4332 => rpa
+longname930 => rq
+longname4386 => rqa
+longname984 => rr
+longname4440 => rra
+longname1038 => rs
+longname4494 => rsa
+longname1092 => rt
+longname4548 => rta
+longname1146 => ru
+longname4602 => rua
+longname1200 => rv
+longname4656 => rva
+longname1254 => rw
+longname4710 => rwa
+longname1308 => rx
+longname4764 => rxa
+longname1362 => ry
+longname4818 => rya
+longname1416 => rz
+longname4872 => rza
+longname16 => s
+longname2929 => s$
+longname2983 => s0
+longname3037 => s1
+longname3091 => s2
+longname3145 => s3
+longname3199 => s4
+longname3253 => s5
+longname3307 => s6
+longname3361 => s7
+longname3415 => s8
+longname3469 => s9
+longname1471 => sA
+longname4927 => sAa
+longname1525 => sB
+longname4981 => sBa
+longname1579 => sC
+longname1633 => sD
+longname1687 => sE
+longname1741 => sF
+longname1795 => sG
+longname1849 => sH
+longname1903 => sI
+longname1957 => sJ
+longname2011 => sK
+longname2065 => sL
+longname2119 => sM
+longname2173 => sN
+longname2227 => sO
+longname2281 => sP
+longname2335 => sQ
+longname2389 => sR
+longname2443 => sS
+longname2497 => sT
+longname2551 => sU
+longname2605 => sV
+longname2659 => sW
+longname2713 => sX
+longname2767 => sY
+longname2821 => sZ
+longname2875 => s_
+longname70 => sa
+longname3523 => saa
+longname124 => sb
+longname3577 => sba
+longname178 => sc
+longname3631 => sca
+longname232 => sd
+longname3685 => sda
+longname286 => se
+longname3739 => sea
+longname339 => sf
+longname3793 => sfa
+longname393 => sg
+longname3847 => sga
+longname447 => sh
+longname3901 => sha
+longname501 => si
+longname3955 => sia
+longname555 => sj
+longname4009 => sja
+longname609 => sk
+longname4063 => ska
+longname663 => sl
+longname4117 => sla
+longname717 => sm
+longname4171 => sma
+longname770 => sn
+longname4225 => sna
+longname823 => so
+longname4279 => soa
+longname877 => sp
+longname4333 => spa
+longname931 => sq
+longname4387 => sqa
+longname985 => sr
+longname4441 => sra
+longname1039 => ss
+longname4495 => ssa
+longname1093 => st
+longname4549 => sta
+longname1147 => su
+longname4603 => sua
+longname1201 => sv
+longname4657 => sva
+longname1255 => sw
+longname4711 => swa
+longname1309 => sx
+longname4765 => sxa
+longname1363 => sy
+longname4819 => sya
+longname1417 => sz
+longname4873 => sza
+longname17 => t
+longname2930 => t$
+longname2984 => t0
+longname3038 => t1
+longname3092 => t2
+longname3146 => t3
+longname3200 => t4
+longname3254 => t5
+longname3308 => t6
+longname3362 => t7
+longname3416 => t8
+longname3470 => t9
+longname1472 => tA
+longname4928 => tAa
+longname1526 => tB
+longname4982 => tBa
+longname1580 => tC
+longname1634 => tD
+longname1688 => tE
+longname1742 => tF
+longname1796 => tG
+longname1850 => tH
+longname1904 => tI
+longname1958 => tJ
+longname2012 => tK
+longname2066 => tL
+longname2120 => tM
+longname2174 => tN
+longname2228 => tO
+longname2282 => tP
+longname2336 => tQ
+longname2390 => tR
+longname2444 => tS
+longname2498 => tT
+longname2552 => tU
+longname2606 => tV
+longname2660 => tW
+longname2714 => tX
+longname2768 => tY
+longname2822 => tZ
+longname2876 => t_
+longname71 => ta
+longname3524 => taa
+longname125 => tb
+longname3578 => tba
+longname179 => tc
+longname3632 => tca
+longname233 => td
+longname3686 => tda
+longname287 => te
+longname3740 => tea
+longname340 => tf
+longname3794 => tfa
+longname394 => tg
+longname3848 => tga
+longname448 => th
+longname3902 => tha
+longname502 => ti
+longname3956 => tia
+longname556 => tj
+longname4010 => tja
+longname610 => tk
+longname4064 => tka
+longname664 => tl
+longname4118 => tla
+longname718 => tm
+longname4172 => tma
+longname771 => tn
+longname4226 => tna
+longname824 => to
+longname4280 => toa
+longname878 => tp
+longname4334 => tpa
+longname932 => tq
+longname4388 => tqa
+longname986 => tr
+longname4442 => tra
+longname1040 => ts
+longname4496 => tsa
+longname1094 => tt
+longname4550 => tta
+longname1148 => tu
+longname4604 => tua
+longname1202 => tv
+longname4658 => tva
+longname1256 => tw
+longname4712 => twa
+longname1310 => tx
+longname4766 => txa
+longname1364 => ty
+longname4820 => tya
+longname1418 => tz
+longname4874 => tza
+longname18 => u
+longname2931 => u$
+longname2985 => u0
+longname3039 => u1
+longname3093 => u2
+longname3147 => u3
+longname3201 => u4
+longname3255 => u5
+longname3309 => u6
+longname3363 => u7
+longname3417 => u8
+longname3471 => u9
+longname1473 => uA
+longname4929 => uAa
+longname1527 => uB
+longname4983 => uBa
+longname1581 => uC
+longname1635 => uD
+longname1689 => uE
+longname1743 => uF
+longname1797 => uG
+longname1851 => uH
+longname1905 => uI
+longname1959 => uJ
+longname2013 => uK
+longname2067 => uL
+longname2121 => uM
+longname2175 => uN
+longname2229 => uO
+longname2283 => uP
+longname2337 => uQ
+longname2391 => uR
+longname2445 => uS
+longname2499 => uT
+longname2553 => uU
+longname2607 => uV
+longname2661 => uW
+longname2715 => uX
+longname2769 => uY
+longname2823 => uZ
+longname2877 => u_
+longname72 => ua
+longname3525 => uaa
+longname126 => ub
+longname3579 => uba
+longname180 => uc
+longname3633 => uca
+longname234 => ud
+longname3687 => uda
+longname288 => ue
+longname3741 => uea
+longname341 => uf
+longname3795 => ufa
+longname395 => ug
+longname3849 => uga
+longname449 => uh
+longname3903 => uha
+longname503 => ui
+longname3957 => uia
+longname557 => uj
+longname4011 => uja
+longname611 => uk
+longname4065 => uka
+longname665 => ul
+longname4119 => ula
+longname719 => um
+longname4173 => uma
+longname772 => un
+longname4227 => una
+longname825 => uo
+longname4281 => uoa
+longname879 => up
+longname4335 => upa
+longname933 => uq
+longname4389 => uqa
+longname987 => ur
+longname4443 => ura
+longname1041 => us
+longname4497 => usa
+longname1095 => ut
+longname4551 => uta
+longname1149 => uu
+longname4605 => uua
+longname1203 => uv
+longname4659 => uva
+longname1257 => uw
+longname4713 => uwa
+longname1311 => ux
+longname4767 => uxa
+longname1365 => uy
+longname4821 => uya
+longname1419 => uz
+longname4875 => uza
+longname19 => v
+longname2932 => v$
+longname2986 => v0
+longname3040 => v1
+longname3094 => v2
+longname3148 => v3
+longname3202 => v4
+longname3256 => v5
+longname3310 => v6
+longname3364 => v7
+longname3418 => v8
+longname3472 => v9
+longname1474 => vA
+longname4930 => vAa
+longname1528 => vB
+longname4984 => vBa
+longname1582 => vC
+longname1636 => vD
+longname1690 => vE
+longname1744 => vF
+longname1798 => vG
+longname1852 => vH
+longname1906 => vI
+longname1960 => vJ
+longname2014 => vK
+longname2068 => vL
+longname2122 => vM
+longname2176 => vN
+longname2230 => vO
+longname2284 => vP
+longname2338 => vQ
+longname2392 => vR
+longname2446 => vS
+longname2500 => vT
+longname2554 => vU
+longname2608 => vV
+longname2662 => vW
+longname2716 => vX
+longname2770 => vY
+longname2824 => vZ
+longname2878 => v_
+longname73 => va
+longname3526 => vaa
+longname127 => vb
+longname3580 => vba
+longname181 => vc
+longname3634 => vca
+longname235 => vd
+longname3688 => vda
+longname289 => ve
+longname3742 => vea
+longname342 => vf
+longname3796 => vfa
+longname396 => vg
+longname3850 => vga
+longname450 => vh
+longname3904 => vha
+longname504 => vi
+longname3958 => via
+longname558 => vj
+longname4012 => vja
+longname612 => vk
+longname4066 => vka
+longname666 => vl
+longname4120 => vla
+longname720 => vm
+longname4174 => vma
+longname773 => vn
+longname4228 => vna
+longname826 => vo
+longname4282 => voa
+longname880 => vp
+longname4336 => vpa
+longname934 => vq
+longname4390 => vqa
+longname988 => vr
+longname4444 => vra
+longname1042 => vs
+longname4498 => vsa
+longname1096 => vt
+longname4552 => vta
+longname1150 => vu
+longname4606 => vua
+longname1204 => vv
+longname4660 => vva
+longname1258 => vw
+longname4714 => vwa
+longname1312 => vx
+longname4768 => vxa
+longname1366 => vy
+longname4822 => vya
+longname1420 => vz
+longname4876 => vza
+longname20 => w
+longname2933 => w$
+longname2987 => w0
+longname3041 => w1
+longname3095 => w2
+longname3149 => w3
+longname3203 => w4
+longname3257 => w5
+longname3311 => w6
+longname3365 => w7
+longname3419 => w8
+longname3473 => w9
+longname1475 => wA
+longname4931 => wAa
+longname1529 => wB
+longname4985 => wBa
+longname1583 => wC
+longname1637 => wD
+longname1691 => wE
+longname1745 => wF
+longname1799 => wG
+longname1853 => wH
+longname1907 => wI
+longname1961 => wJ
+longname2015 => wK
+longname2069 => wL
+longname2123 => wM
+longname2177 => wN
+longname2231 => wO
+longname2285 => wP
+longname2339 => wQ
+longname2393 => wR
+longname2447 => wS
+longname2501 => wT
+longname2555 => wU
+longname2609 => wV
+longname2663 => wW
+longname2717 => wX
+longname2771 => wY
+longname2825 => wZ
+longname2879 => w_
+longname74 => wa
+longname3527 => waa
+longname128 => wb
+longname3581 => wba
+longname182 => wc
+longname3635 => wca
+longname236 => wd
+longname3689 => wda
+longname290 => we
+longname3743 => wea
+longname343 => wf
+longname3797 => wfa
+longname397 => wg
+longname3851 => wga
+longname451 => wh
+longname3905 => wha
+longname505 => wi
+longname3959 => wia
+longname559 => wj
+longname4013 => wja
+longname613 => wk
+longname4067 => wka
+longname667 => wl
+longname4121 => wla
+longname721 => wm
+longname4175 => wma
+longname774 => wn
+longname4229 => wna
+longname827 => wo
+longname4283 => woa
+longname881 => wp
+longname4337 => wpa
+longname935 => wq
+longname4391 => wqa
+longname989 => wr
+longname4445 => wra
+longname1043 => ws
+longname4499 => wsa
+longname1097 => wt
+longname4553 => wta
+longname1151 => wu
+longname4607 => wua
+longname1205 => wv
+longname4661 => wva
+longname1259 => ww
+longname4715 => wwa
+longname1313 => wx
+longname4769 => wxa
+longname1367 => wy
+longname4823 => wya
+longname1421 => wz
+longname4877 => wza
+longname21 => x
+longname2934 => x$
+longname2988 => x0
+longname3042 => x1
+longname3096 => x2
+longname3150 => x3
+longname3204 => x4
+longname3258 => x5
+longname3312 => x6
+longname3366 => x7
+longname3420 => x8
+longname3474 => x9
+longname1476 => xA
+longname4932 => xAa
+longname1530 => xB
+longname4986 => xBa
+longname1584 => xC
+longname1638 => xD
+longname1692 => xE
+longname1746 => xF
+longname1800 => xG
+longname1854 => xH
+longname1908 => xI
+longname1962 => xJ
+longname2016 => xK
+longname2070 => xL
+longname2124 => xM
+longname2178 => xN
+longname2232 => xO
+longname2286 => xP
+longname2340 => xQ
+longname2394 => xR
+longname2448 => xS
+longname2502 => xT
+longname2556 => xU
+longname2610 => xV
+longname2664 => xW
+longname2718 => xX
+longname2772 => xY
+longname2826 => xZ
+longname2880 => x_
+longname75 => xa
+longname3528 => xaa
+longname129 => xb
+longname3582 => xba
+longname183 => xc
+longname3636 => xca
+longname237 => xd
+longname3690 => xda
+longname291 => xe
+longname3744 => xea
+longname344 => xf
+longname3798 => xfa
+longname398 => xg
+longname3852 => xga
+longname452 => xh
+longname3906 => xha
+longname506 => xi
+longname3960 => xia
+longname560 => xj
+longname4014 => xja
+longname614 => xk
+longname4068 => xka
+longname668 => xl
+longname4122 => xla
+longname722 => xm
+longname4176 => xma
+longname775 => xn
+longname4230 => xna
+longname828 => xo
+longname4284 => xoa
+longname882 => xp
+longname4338 => xpa
+longname936 => xq
+longname4392 => xqa
+longname990 => xr
+longname4446 => xra
+longname1044 => xs
+longname4500 => xsa
+longname1098 => xt
+longname4554 => xta
+longname1152 => xu
+longname4608 => xua
+longname1206 => xv
+longname4662 => xva
+longname1260 => xw
+longname4716 => xwa
+longname1314 => xx
+longname4770 => xxa
+longname1368 => xy
+longname4824 => xya
+longname1422 => xz
+longname4878 => xza
+longname22 => y
+longname2935 => y$
+longname2989 => y0
+longname3043 => y1
+longname3097 => y2
+longname3151 => y3
+longname3205 => y4
+longname3259 => y5
+longname3313 => y6
+longname3367 => y7
+longname3421 => y8
+longname3475 => y9
+longname1477 => yA
+longname4933 => yAa
+longname1531 => yB
+longname4987 => yBa
+longname1585 => yC
+longname1639 => yD
+longname1693 => yE
+longname1747 => yF
+longname1801 => yG
+longname1855 => yH
+longname1909 => yI
+longname1963 => yJ
+longname2017 => yK
+longname2071 => yL
+longname2125 => yM
+longname2179 => yN
+longname2233 => yO
+longname2287 => yP
+longname2341 => yQ
+longname2395 => yR
+longname2449 => yS
+longname2503 => yT
+longname2557 => yU
+longname2611 => yV
+longname2665 => yW
+longname2719 => yX
+longname2773 => yY
+longname2827 => yZ
+longname2881 => y_
+longname76 => ya
+longname3529 => yaa
+longname130 => yb
+longname3583 => yba
+longname184 => yc
+longname3637 => yca
+longname238 => yd
+longname3691 => yda
+longname292 => ye
+longname3745 => yea
+longname345 => yf
+longname3799 => yfa
+longname399 => yg
+longname3853 => yga
+longname453 => yh
+longname3907 => yha
+longname507 => yi
+longname3961 => yia
+longname561 => yj
+longname4015 => yja
+longname615 => yk
+longname4069 => yka
+longname669 => yl
+longname4123 => yla
+longname723 => ym
+longname4177 => yma
+longname776 => yn
+longname4231 => yna
+longname829 => yo
+longname4285 => yoa
+longname883 => yp
+longname4339 => ypa
+longname937 => yq
+longname4393 => yqa
+longname991 => yr
+longname4447 => yra
+longname1045 => ys
+longname4501 => ysa
+longname1099 => yt
+longname4555 => yta
+longname1153 => yu
+longname4609 => yua
+longname1207 => yv
+longname4663 => yva
+longname1261 => yw
+longname4717 => ywa
+longname1315 => yx
+longname4771 => yxa
+longname1369 => yy
+longname4825 => yya
+longname1423 => yz
+longname4879 => yza
+longname23 => z
+longname2936 => z$
+longname2990 => z0
+longname3044 => z1
+longname3098 => z2
+longname3152 => z3
+longname3206 => z4
+longname3260 => z5
+longname3314 => z6
+longname3368 => z7
+longname3422 => z8
+longname3476 => z9
+longname1478 => zA
+longname4934 => zAa
+longname1532 => zB
+longname4988 => zBa
+longname1586 => zC
+longname1640 => zD
+longname1694 => zE
+longname1748 => zF
+longname1802 => zG
+longname1856 => zH
+longname1910 => zI
+longname1964 => zJ
+longname2018 => zK
+longname2072 => zL
+longname2126 => zM
+longname2180 => zN
+longname2234 => zO
+longname2288 => zP
+longname2342 => zQ
+longname2396 => zR
+longname2450 => zS
+longname2504 => zT
+longname2558 => zU
+longname2612 => zV
+longname2666 => zW
+longname2720 => zX
+longname2774 => zY
+longname2828 => zZ
+longname2882 => z_
+longname77 => za
+longname3530 => zaa
+longname131 => zb
+longname3584 => zba
+longname185 => zc
+longname3638 => zca
+longname239 => zd
+longname3692 => zda
+longname293 => ze
+longname3746 => zea
+longname346 => zf
+longname3800 => zfa
+longname400 => zg
+longname3854 => zga
+longname454 => zh
+longname3908 => zha
+longname508 => zi
+longname3962 => zia
+longname562 => zj
+longname4016 => zja
+longname616 => zk
+longname4070 => zka
+longname670 => zl
+longname4124 => zla
+longname724 => zm
+longname4178 => zma
+longname777 => zn
+longname4232 => zna
+longname830 => zo
+longname4286 => zoa
+longname884 => zp
+longname4340 => zpa
+longname938 => zq
+longname4394 => zqa
+longname992 => zr
+longname4448 => zra
+longname1046 => zs
+longname4502 => zsa
+longname1100 => zt
+longname4556 => zta
+longname1154 => zu
+longname4610 => zua
+longname1208 => zv
+longname4664 => zva
+longname1262 => zw
+longname4718 => zwa
+longname1316 => zx
+longname4772 => zxa
+longname1370 => zy
+longname4826 => zya
+longname1424 => zz
+longname4880 => zza
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (import "env" "a" (global $gimport$0 i32))
+ (import "env" "b" (global $gimport$1 i32))
+ (import "env" "c" (global $gimport$2 i32))
+ (import "env" "d" (func $internal1))
+ (import "env" "e" (func $internal2))
+ (import "env" "f" (func $internal3))
+ (import "env" "g" (func $internal4))
+ (import "env" "h" (func $internal5))
+ (import "env" "i" (func $internal6))
+ (import "env" "j" (func $internal7))
+ (import "env" "k" (func $internal8))
+ (import "env" "l" (func $internal9))
+ (import "env" "m" (func $internal10))
+ (import "env" "n" (func $internal11))
+ (import "env" "o" (func $internal12))
+ (import "env" "p" (func $internal13))
+ (import "env" "q" (func $internal14))
+ (import "env" "r" (func $internal15))
+ (import "env" "s" (func $internal16))
+ (import "env" "t" (func $internal17))
+ (import "env" "u" (func $internal18))
+ (import "env" "v" (func $internal19))
+ (import "env" "w" (func $internal20))
+ (import "env" "x" (func $internal21))
+ (import "env" "y" (func $internal22))
+ (import "env" "z" (func $internal23))
+ (import "env" "A" (func $internal24))
+ (import "env" "B" (func $internal25))
+ (import "env" "C" (func $internal26))
+ (import "env" "D" (func $internal27))
+ (import "env" "E" (func $internal28))
+ (import "env" "F" (func $internal29))
+ (import "env" "G" (func $internal30))
+ (import "env" "H" (func $internal31))
+ (import "env" "I" (func $internal32))
+ (import "env" "J" (func $internal33))
+ (import "env" "K" (func $internal34))
+ (import "env" "L" (func $internal35))
+ (import "env" "M" (func $internal36))
+ (import "env" "N" (func $internal37))
+ (import "env" "O" (func $internal38))
+ (import "env" "P" (func $internal39))
+ (import "env" "Q" (func $internal40))
+ (import "env" "R" (func $internal41))
+ (import "env" "S" (func $internal42))
+ (import "env" "T" (func $internal43))
+ (import "env" "U" (func $internal44))
+ (import "env" "V" (func $internal45))
+ (import "env" "W" (func $internal46))
+ (import "env" "X" (func $internal47))
+ (import "env" "Y" (func $internal48))
+ (import "env" "Z" (func $internal49))
+ (import "env" "_" (func $internal50))
+ (import "env" "$" (func $internal51))
+ (import "env" "aa" (func $internal52))
+ (import "env" "ba" (func $internal53))
+ (import "env" "ca" (func $internal54))
+ (import "env" "da" (func $internal55))
+ (import "env" "ea" (func $internal56))
+ (import "env" "fa" (func $internal57))
+ (import "env" "ga" (func $internal58))
+ (import "env" "ha" (func $internal59))
+ (import "env" "ia" (func $internal60))
+ (import "env" "ja" (func $internal61))
+ (import "env" "ka" (func $internal62))
+ (import "env" "la" (func $internal63))
+ (import "env" "ma" (func $internal64))
+ (import "env" "na" (func $internal65))
+ (import "env" "oa" (func $internal66))
+ (import "env" "pa" (func $internal67))
+ (import "env" "qa" (func $internal68))
+ (import "env" "ra" (func $internal69))
+ (import "env" "sa" (func $internal70))
+ (import "env" "ta" (func $internal71))
+ (import "env" "ua" (func $internal72))
+ (import "env" "va" (func $internal73))
+ (import "env" "wa" (func $internal74))
+ (import "env" "xa" (func $internal75))
+ (import "env" "ya" (func $internal76))
+ (import "env" "za" (func $internal77))
+ (import "env" "Aa" (func $internal78))
+ (import "env" "Ba" (func $internal79))
+ (import "env" "Ca" (func $internal80))
+ (import "env" "Da" (func $internal81))
+ (import "env" "Ea" (func $internal82))
+ (import "env" "Fa" (func $internal83))
+ (import "env" "Ga" (func $internal84))
+ (import "env" "Ha" (func $internal85))
+ (import "env" "Ia" (func $internal86))
+ (import "env" "Ja" (func $internal87))
+ (import "env" "Ka" (func $internal88))
+ (import "env" "La" (func $internal89))
+ (import "env" "Ma" (func $internal90))
+ (import "env" "Na" (func $internal91))
+ (import "env" "Oa" (func $internal92))
+ (import "env" "Pa" (func $internal93))
+ (import "env" "Qa" (func $internal94))
+ (import "env" "Ra" (func $internal95))
+ (import "env" "Sa" (func $internal96))
+ (import "env" "Ta" (func $internal97))
+ (import "env" "Ua" (func $internal98))
+ (import "env" "Va" (func $internal99))
+ (import "env" "Wa" (func $internal100))
+ (import "env" "Xa" (func $internal101))
+ (import "env" "Ya" (func $internal102))
+ (import "env" "Za" (func $internal103))
+ (import "env" "_a" (func $internal104))
+ (import "env" "$a" (func $internal105))
+ (import "env" "ab" (func $internal106))
+ (import "env" "bb" (func $internal107))
+ (import "env" "cb" (func $internal108))
+ (import "env" "db" (func $internal109))
+ (import "env" "eb" (func $internal110))
+ (import "env" "fb" (func $internal111))
+ (import "env" "gb" (func $internal112))
+ (import "env" "hb" (func $internal113))
+ (import "env" "ib" (func $internal114))
+ (import "env" "jb" (func $internal115))
+ (import "env" "kb" (func $internal116))
+ (import "env" "lb" (func $internal117))
+ (import "env" "mb" (func $internal118))
+ (import "env" "nb" (func $internal119))
+ (import "env" "ob" (func $internal120))
+ (import "env" "pb" (func $internal121))
+ (import "env" "qb" (func $internal122))
+ (import "env" "rb" (func $internal123))
+ (import "env" "sb" (func $internal124))
+ (import "env" "tb" (func $internal125))
+ (import "env" "ub" (func $internal126))
+ (import "env" "vb" (func $internal127))
+ (import "env" "wb" (func $internal128))
+ (import "env" "xb" (func $internal129))
+ (import "env" "yb" (func $internal130))
+ (import "env" "zb" (func $internal131))
+ (import "env" "Ab" (func $internal132))
+ (import "env" "Bb" (func $internal133))
+ (import "env" "Cb" (func $internal134))
+ (import "env" "Db" (func $internal135))
+ (import "env" "Eb" (func $internal136))
+ (import "env" "Fb" (func $internal137))
+ (import "env" "Gb" (func $internal138))
+ (import "env" "Hb" (func $internal139))
+ (import "env" "Ib" (func $internal140))
+ (import "env" "Jb" (func $internal141))
+ (import "env" "Kb" (func $internal142))
+ (import "env" "Lb" (func $internal143))
+ (import "env" "Mb" (func $internal144))
+ (import "env" "Nb" (func $internal145))
+ (import "env" "Ob" (func $internal146))
+ (import "env" "Pb" (func $internal147))
+ (import "env" "Qb" (func $internal148))
+ (import "env" "Rb" (func $internal149))
+ (import "env" "Sb" (func $internal150))
+ (import "env" "Tb" (func $internal151))
+ (import "env" "Ub" (func $internal152))
+ (import "env" "Vb" (func $internal153))
+ (import "env" "Wb" (func $internal154))
+ (import "env" "Xb" (func $internal155))
+ (import "env" "Yb" (func $internal156))
+ (import "env" "Zb" (func $internal157))
+ (import "env" "_b" (func $internal158))
+ (import "env" "$b" (func $internal159))
+ (import "env" "ac" (func $internal160))
+ (import "env" "bc" (func $internal161))
+ (import "env" "cc" (func $internal162))
+ (import "env" "dc" (func $internal163))
+ (import "env" "ec" (func $internal164))
+ (import "env" "fc" (func $internal165))
+ (import "env" "gc" (func $internal166))
+ (import "env" "hc" (func $internal167))
+ (import "env" "ic" (func $internal168))
+ (import "env" "jc" (func $internal169))
+ (import "env" "kc" (func $internal170))
+ (import "env" "lc" (func $internal171))
+ (import "env" "mc" (func $internal172))
+ (import "env" "nc" (func $internal173))
+ (import "env" "oc" (func $internal174))
+ (import "env" "pc" (func $internal175))
+ (import "env" "qc" (func $internal176))
+ (import "env" "rc" (func $internal177))
+ (import "env" "sc" (func $internal178))
+ (import "env" "tc" (func $internal179))
+ (import "env" "uc" (func $internal180))
+ (import "env" "vc" (func $internal181))
+ (import "env" "wc" (func $internal182))
+ (import "env" "xc" (func $internal183))
+ (import "env" "yc" (func $internal184))
+ (import "env" "zc" (func $internal185))
+ (import "env" "Ac" (func $internal186))
+ (import "env" "Bc" (func $internal187))
+ (import "env" "Cc" (func $internal188))
+ (import "env" "Dc" (func $internal189))
+ (import "env" "Ec" (func $internal190))
+ (import "env" "Fc" (func $internal191))
+ (import "env" "Gc" (func $internal192))
+ (import "env" "Hc" (func $internal193))
+ (import "env" "Ic" (func $internal194))
+ (import "env" "Jc" (func $internal195))
+ (import "env" "Kc" (func $internal196))
+ (import "env" "Lc" (func $internal197))
+ (import "env" "Mc" (func $internal198))
+ (import "env" "Nc" (func $internal199))
+ (import "env" "Oc" (func $internal200))
+ (import "env" "Pc" (func $internal201))
+ (import "env" "Qc" (func $internal202))
+ (import "env" "Rc" (func $internal203))
+ (import "env" "Sc" (func $internal204))
+ (import "env" "Tc" (func $internal205))
+ (import "env" "Uc" (func $internal206))
+ (import "env" "Vc" (func $internal207))
+ (import "env" "Wc" (func $internal208))
+ (import "env" "Xc" (func $internal209))
+ (import "env" "Yc" (func $internal210))
+ (import "env" "Zc" (func $internal211))
+ (import "env" "_c" (func $internal212))
+ (import "env" "$c" (func $internal213))
+ (import "env" "ad" (func $internal214))
+ (import "env" "bd" (func $internal215))
+ (import "env" "cd" (func $internal216))
+ (import "env" "dd" (func $internal217))
+ (import "env" "ed" (func $internal218))
+ (import "env" "fd" (func $internal219))
+ (import "env" "gd" (func $internal220))
+ (import "env" "hd" (func $internal221))
+ (import "env" "id" (func $internal222))
+ (import "env" "jd" (func $internal223))
+ (import "env" "kd" (func $internal224))
+ (import "env" "ld" (func $internal225))
+ (import "env" "md" (func $internal226))
+ (import "env" "nd" (func $internal227))
+ (import "env" "od" (func $internal228))
+ (import "env" "pd" (func $internal229))
+ (import "env" "qd" (func $internal230))
+ (import "env" "rd" (func $internal231))
+ (import "env" "sd" (func $internal232))
+ (import "env" "td" (func $internal233))
+ (import "env" "ud" (func $internal234))
+ (import "env" "vd" (func $internal235))
+ (import "env" "wd" (func $internal236))
+ (import "env" "xd" (func $internal237))
+ (import "env" "yd" (func $internal238))
+ (import "env" "zd" (func $internal239))
+ (import "env" "Ad" (func $internal240))
+ (import "env" "Bd" (func $internal241))
+ (import "env" "Cd" (func $internal242))
+ (import "env" "Dd" (func $internal243))
+ (import "env" "Ed" (func $internal244))
+ (import "env" "Fd" (func $internal245))
+ (import "env" "Gd" (func $internal246))
+ (import "env" "Hd" (func $internal247))
+ (import "env" "Id" (func $internal248))
+ (import "env" "Jd" (func $internal249))
+ (import "env" "Kd" (func $internal250))
+ (import "env" "Ld" (func $internal251))
+ (import "env" "Md" (func $internal252))
+ (import "env" "Nd" (func $internal253))
+ (import "env" "Od" (func $internal254))
+ (import "env" "Pd" (func $internal255))
+ (import "env" "Qd" (func $internal256))
+ (import "env" "Rd" (func $internal257))
+ (import "env" "Sd" (func $internal258))
+ (import "env" "Td" (func $internal259))
+ (import "env" "Ud" (func $internal260))
+ (import "env" "Vd" (func $internal261))
+ (import "env" "Wd" (func $internal262))
+ (import "env" "Xd" (func $internal263))
+ (import "env" "Yd" (func $internal264))
+ (import "env" "Zd" (func $internal265))
+ (import "env" "_d" (func $internal266))
+ (import "env" "$d" (func $internal267))
+ (import "env" "ae" (func $internal268))
+ (import "env" "be" (func $internal269))
+ (import "env" "ce" (func $internal270))
+ (import "env" "de" (func $internal271))
+ (import "env" "ee" (func $internal272))
+ (import "env" "fe" (func $internal273))
+ (import "env" "ge" (func $internal274))
+ (import "env" "he" (func $internal275))
+ (import "env" "ie" (func $internal276))
+ (import "env" "je" (func $internal277))
+ (import "env" "ke" (func $internal278))
+ (import "env" "le" (func $internal279))
+ (import "env" "me" (func $internal280))
+ (import "env" "ne" (func $internal281))
+ (import "env" "oe" (func $internal282))
+ (import "env" "pe" (func $internal283))
+ (import "env" "qe" (func $internal284))
+ (import "env" "re" (func $internal285))
+ (import "env" "se" (func $internal286))
+ (import "env" "te" (func $internal287))
+ (import "env" "ue" (func $internal288))
+ (import "env" "ve" (func $internal289))
+ (import "env" "we" (func $internal290))
+ (import "env" "xe" (func $internal291))
+ (import "env" "ye" (func $internal292))
+ (import "env" "ze" (func $internal293))
+ (import "env" "Ae" (func $internal294))
+ (import "env" "Be" (func $internal295))
+ (import "env" "Ce" (func $internal296))
+ (import "env" "De" (func $internal297))
+ (import "env" "Ee" (func $internal298))
+ (import "env" "Fe" (func $internal299))
+ (import "env" "Ge" (func $internal300))
+ (import "env" "He" (func $internal301))
+ (import "env" "Ie" (func $internal302))
+ (import "env" "Je" (func $internal303))
+ (import "env" "Ke" (func $internal304))
+ (import "env" "Le" (func $internal305))
+ (import "env" "Me" (func $internal306))
+ (import "env" "Ne" (func $internal307))
+ (import "env" "Oe" (func $internal308))
+ (import "env" "Pe" (func $internal309))
+ (import "env" "Qe" (func $internal310))
+ (import "env" "Re" (func $internal311))
+ (import "env" "Se" (func $internal312))
+ (import "env" "Te" (func $internal313))
+ (import "env" "Ue" (func $internal314))
+ (import "env" "Ve" (func $internal315))
+ (import "env" "We" (func $internal316))
+ (import "env" "Xe" (func $internal317))
+ (import "env" "Ye" (func $internal318))
+ (import "env" "Ze" (func $internal319))
+ (import "env" "_e" (func $internal320))
+ (import "env" "$e" (func $internal321))
+ (import "env" "af" (func $internal322))
+ (import "env" "bf" (func $internal323))
+ (import "env" "cf" (func $internal324))
+ (import "env" "df" (func $internal325))
+ (import "env" "ef" (func $internal326))
+ (import "env" "ff" (func $internal327))
+ (import "env" "gf" (func $internal328))
+ (import "env" "hf" (func $internal329))
+ (import "env" "jf" (func $internal330))
+ (import "env" "kf" (func $internal331))
+ (import "env" "lf" (func $internal332))
+ (import "env" "mf" (func $internal333))
+ (import "env" "nf" (func $internal334))
+ (import "env" "of" (func $internal335))
+ (import "env" "pf" (func $internal336))
+ (import "env" "qf" (func $internal337))
+ (import "env" "rf" (func $internal338))
+ (import "env" "sf" (func $internal339))
+ (import "env" "tf" (func $internal340))
+ (import "env" "uf" (func $internal341))
+ (import "env" "vf" (func $internal342))
+ (import "env" "wf" (func $internal343))
+ (import "env" "xf" (func $internal344))
+ (import "env" "yf" (func $internal345))
+ (import "env" "zf" (func $internal346))
+ (import "env" "Af" (func $internal347))
+ (import "env" "Bf" (func $internal348))
+ (import "env" "Cf" (func $internal349))
+ (import "env" "Df" (func $internal350))
+ (import "env" "Ef" (func $internal351))
+ (import "env" "Ff" (func $internal352))
+ (import "env" "Gf" (func $internal353))
+ (import "env" "Hf" (func $internal354))
+ (import "env" "If" (func $internal355))
+ (import "env" "Jf" (func $internal356))
+ (import "env" "Kf" (func $internal357))
+ (import "env" "Lf" (func $internal358))
+ (import "env" "Mf" (func $internal359))
+ (import "env" "Nf" (func $internal360))
+ (import "env" "Of" (func $internal361))
+ (import "env" "Pf" (func $internal362))
+ (import "env" "Qf" (func $internal363))
+ (import "env" "Rf" (func $internal364))
+ (import "env" "Sf" (func $internal365))
+ (import "env" "Tf" (func $internal366))
+ (import "env" "Uf" (func $internal367))
+ (import "env" "Vf" (func $internal368))
+ (import "env" "Wf" (func $internal369))
+ (import "env" "Xf" (func $internal370))
+ (import "env" "Yf" (func $internal371))
+ (import "env" "Zf" (func $internal372))
+ (import "env" "_f" (func $internal373))
+ (import "env" "$f" (func $internal374))
+ (import "env" "ag" (func $internal375))
+ (import "env" "bg" (func $internal376))
+ (import "env" "cg" (func $internal377))
+ (import "env" "dg" (func $internal378))
+ (import "env" "eg" (func $internal379))
+ (import "env" "fg" (func $internal380))
+ (import "env" "gg" (func $internal381))
+ (import "env" "hg" (func $internal382))
+ (import "env" "ig" (func $internal383))
+ (import "env" "jg" (func $internal384))
+ (import "env" "kg" (func $internal385))
+ (import "env" "lg" (func $internal386))
+ (import "env" "mg" (func $internal387))
+ (import "env" "ng" (func $internal388))
+ (import "env" "og" (func $internal389))
+ (import "env" "pg" (func $internal390))
+ (import "env" "qg" (func $internal391))
+ (import "env" "rg" (func $internal392))
+ (import "env" "sg" (func $internal393))
+ (import "env" "tg" (func $internal394))
+ (import "env" "ug" (func $internal395))
+ (import "env" "vg" (func $internal396))
+ (import "env" "wg" (func $internal397))
+ (import "env" "xg" (func $internal398))
+ (import "env" "yg" (func $internal399))
+ (import "env" "zg" (func $internal400))
+ (import "env" "Ag" (func $internal401))
+ (import "env" "Bg" (func $internal402))
+ (import "env" "Cg" (func $internal403))
+ (import "env" "Dg" (func $internal404))
+ (import "env" "Eg" (func $internal405))
+ (import "env" "Fg" (func $internal406))
+ (import "env" "Gg" (func $internal407))
+ (import "env" "Hg" (func $internal408))
+ (import "env" "Ig" (func $internal409))
+ (import "env" "Jg" (func $internal410))
+ (import "env" "Kg" (func $internal411))
+ (import "env" "Lg" (func $internal412))
+ (import "env" "Mg" (func $internal413))
+ (import "env" "Ng" (func $internal414))
+ (import "env" "Og" (func $internal415))
+ (import "env" "Pg" (func $internal416))
+ (import "env" "Qg" (func $internal417))
+ (import "env" "Rg" (func $internal418))
+ (import "env" "Sg" (func $internal419))
+ (import "env" "Tg" (func $internal420))
+ (import "env" "Ug" (func $internal421))
+ (import "env" "Vg" (func $internal422))
+ (import "env" "Wg" (func $internal423))
+ (import "env" "Xg" (func $internal424))
+ (import "env" "Yg" (func $internal425))
+ (import "env" "Zg" (func $internal426))
+ (import "env" "_g" (func $internal427))
+ (import "env" "$g" (func $internal428))
+ (import "env" "ah" (func $internal429))
+ (import "env" "bh" (func $internal430))
+ (import "env" "ch" (func $internal431))
+ (import "env" "dh" (func $internal432))
+ (import "env" "eh" (func $internal433))
+ (import "env" "fh" (func $internal434))
+ (import "env" "gh" (func $internal435))
+ (import "env" "hh" (func $internal436))
+ (import "env" "ih" (func $internal437))
+ (import "env" "jh" (func $internal438))
+ (import "env" "kh" (func $internal439))
+ (import "env" "lh" (func $internal440))
+ (import "env" "mh" (func $internal441))
+ (import "env" "nh" (func $internal442))
+ (import "env" "oh" (func $internal443))
+ (import "env" "ph" (func $internal444))
+ (import "env" "qh" (func $internal445))
+ (import "env" "rh" (func $internal446))
+ (import "env" "sh" (func $internal447))
+ (import "env" "th" (func $internal448))
+ (import "env" "uh" (func $internal449))
+ (import "env" "vh" (func $internal450))
+ (import "env" "wh" (func $internal451))
+ (import "env" "xh" (func $internal452))
+ (import "env" "yh" (func $internal453))
+ (import "env" "zh" (func $internal454))
+ (import "env" "Ah" (func $internal455))
+ (import "env" "Bh" (func $internal456))
+ (import "env" "Ch" (func $internal457))
+ (import "env" "Dh" (func $internal458))
+ (import "env" "Eh" (func $internal459))
+ (import "env" "Fh" (func $internal460))
+ (import "env" "Gh" (func $internal461))
+ (import "env" "Hh" (func $internal462))
+ (import "env" "Ih" (func $internal463))
+ (import "env" "Jh" (func $internal464))
+ (import "env" "Kh" (func $internal465))
+ (import "env" "Lh" (func $internal466))
+ (import "env" "Mh" (func $internal467))
+ (import "env" "Nh" (func $internal468))
+ (import "env" "Oh" (func $internal469))
+ (import "env" "Ph" (func $internal470))
+ (import "env" "Qh" (func $internal471))
+ (import "env" "Rh" (func $internal472))
+ (import "env" "Sh" (func $internal473))
+ (import "env" "Th" (func $internal474))
+ (import "env" "Uh" (func $internal475))
+ (import "env" "Vh" (func $internal476))
+ (import "env" "Wh" (func $internal477))
+ (import "env" "Xh" (func $internal478))
+ (import "env" "Yh" (func $internal479))
+ (import "env" "Zh" (func $internal480))
+ (import "env" "_h" (func $internal481))
+ (import "env" "$h" (func $internal482))
+ (import "env" "ai" (func $internal483))
+ (import "env" "bi" (func $internal484))
+ (import "env" "ci" (func $internal485))
+ (import "env" "di" (func $internal486))
+ (import "env" "ei" (func $internal487))
+ (import "env" "fi" (func $internal488))
+ (import "env" "gi" (func $internal489))
+ (import "env" "hi" (func $internal490))
+ (import "env" "ii" (func $internal491))
+ (import "env" "ji" (func $internal492))
+ (import "env" "ki" (func $internal493))
+ (import "env" "li" (func $internal494))
+ (import "env" "mi" (func $internal495))
+ (import "env" "ni" (func $internal496))
+ (import "env" "oi" (func $internal497))
+ (import "env" "pi" (func $internal498))
+ (import "env" "qi" (func $internal499))
+ (import "env" "ri" (func $internal500))
+ (import "env" "si" (func $internal501))
+ (import "env" "ti" (func $internal502))
+ (import "env" "ui" (func $internal503))
+ (import "env" "vi" (func $internal504))
+ (import "env" "wi" (func $internal505))
+ (import "env" "xi" (func $internal506))
+ (import "env" "yi" (func $internal507))
+ (import "env" "zi" (func $internal508))
+ (import "env" "Ai" (func $internal509))
+ (import "env" "Bi" (func $internal510))
+ (import "env" "Ci" (func $internal511))
+ (import "env" "Di" (func $internal512))
+ (import "env" "Ei" (func $internal513))
+ (import "env" "Fi" (func $internal514))
+ (import "env" "Gi" (func $internal515))
+ (import "env" "Hi" (func $internal516))
+ (import "env" "Ii" (func $internal517))
+ (import "env" "Ji" (func $internal518))
+ (import "env" "Ki" (func $internal519))
+ (import "env" "Li" (func $internal520))
+ (import "env" "Mi" (func $internal521))
+ (import "env" "Ni" (func $internal522))
+ (import "env" "Oi" (func $internal523))
+ (import "env" "Pi" (func $internal524))
+ (import "env" "Qi" (func $internal525))
+ (import "env" "Ri" (func $internal526))
+ (import "env" "Si" (func $internal527))
+ (import "env" "Ti" (func $internal528))
+ (import "env" "Ui" (func $internal529))
+ (import "env" "Vi" (func $internal530))
+ (import "env" "Wi" (func $internal531))
+ (import "env" "Xi" (func $internal532))
+ (import "env" "Yi" (func $internal533))
+ (import "env" "Zi" (func $internal534))
+ (import "env" "_i" (func $internal535))
+ (import "env" "$i" (func $internal536))
+ (import "env" "aj" (func $internal537))
+ (import "env" "bj" (func $internal538))
+ (import "env" "cj" (func $internal539))
+ (import "env" "dj" (func $internal540))
+ (import "env" "ej" (func $internal541))
+ (import "env" "fj" (func $internal542))
+ (import "env" "gj" (func $internal543))
+ (import "env" "hj" (func $internal544))
+ (import "env" "ij" (func $internal545))
+ (import "env" "jj" (func $internal546))
+ (import "env" "kj" (func $internal547))
+ (import "env" "lj" (func $internal548))
+ (import "env" "mj" (func $internal549))
+ (import "env" "nj" (func $internal550))
+ (import "env" "oj" (func $internal551))
+ (import "env" "pj" (func $internal552))
+ (import "env" "qj" (func $internal553))
+ (import "env" "rj" (func $internal554))
+ (import "env" "sj" (func $internal555))
+ (import "env" "tj" (func $internal556))
+ (import "env" "uj" (func $internal557))
+ (import "env" "vj" (func $internal558))
+ (import "env" "wj" (func $internal559))
+ (import "env" "xj" (func $internal560))
+ (import "env" "yj" (func $internal561))
+ (import "env" "zj" (func $internal562))
+ (import "env" "Aj" (func $internal563))
+ (import "env" "Bj" (func $internal564))
+ (import "env" "Cj" (func $internal565))
+ (import "env" "Dj" (func $internal566))
+ (import "env" "Ej" (func $internal567))
+ (import "env" "Fj" (func $internal568))
+ (import "env" "Gj" (func $internal569))
+ (import "env" "Hj" (func $internal570))
+ (import "env" "Ij" (func $internal571))
+ (import "env" "Jj" (func $internal572))
+ (import "env" "Kj" (func $internal573))
+ (import "env" "Lj" (func $internal574))
+ (import "env" "Mj" (func $internal575))
+ (import "env" "Nj" (func $internal576))
+ (import "env" "Oj" (func $internal577))
+ (import "env" "Pj" (func $internal578))
+ (import "env" "Qj" (func $internal579))
+ (import "env" "Rj" (func $internal580))
+ (import "env" "Sj" (func $internal581))
+ (import "env" "Tj" (func $internal582))
+ (import "env" "Uj" (func $internal583))
+ (import "env" "Vj" (func $internal584))
+ (import "env" "Wj" (func $internal585))
+ (import "env" "Xj" (func $internal586))
+ (import "env" "Yj" (func $internal587))
+ (import "env" "Zj" (func $internal588))
+ (import "env" "_j" (func $internal589))
+ (import "env" "$j" (func $internal590))
+ (import "env" "ak" (func $internal591))
+ (import "env" "bk" (func $internal592))
+ (import "env" "ck" (func $internal593))
+ (import "env" "dk" (func $internal594))
+ (import "env" "ek" (func $internal595))
+ (import "env" "fk" (func $internal596))
+ (import "env" "gk" (func $internal597))
+ (import "env" "hk" (func $internal598))
+ (import "env" "ik" (func $internal599))
+ (import "env" "jk" (func $internal600))
+ (import "env" "kk" (func $internal601))
+ (import "env" "lk" (func $internal602))
+ (import "env" "mk" (func $internal603))
+ (import "env" "nk" (func $internal604))
+ (import "env" "ok" (func $internal605))
+ (import "env" "pk" (func $internal606))
+ (import "env" "qk" (func $internal607))
+ (import "env" "rk" (func $internal608))
+ (import "env" "sk" (func $internal609))
+ (import "env" "tk" (func $internal610))
+ (import "env" "uk" (func $internal611))
+ (import "env" "vk" (func $internal612))
+ (import "env" "wk" (func $internal613))
+ (import "env" "xk" (func $internal614))
+ (import "env" "yk" (func $internal615))
+ (import "env" "zk" (func $internal616))
+ (import "env" "Ak" (func $internal617))
+ (import "env" "Bk" (func $internal618))
+ (import "env" "Ck" (func $internal619))
+ (import "env" "Dk" (func $internal620))
+ (import "env" "Ek" (func $internal621))
+ (import "env" "Fk" (func $internal622))
+ (import "env" "Gk" (func $internal623))
+ (import "env" "Hk" (func $internal624))
+ (import "env" "Ik" (func $internal625))
+ (import "env" "Jk" (func $internal626))
+ (import "env" "Kk" (func $internal627))
+ (import "env" "Lk" (func $internal628))
+ (import "env" "Mk" (func $internal629))
+ (import "env" "Nk" (func $internal630))
+ (import "env" "Ok" (func $internal631))
+ (import "env" "Pk" (func $internal632))
+ (import "env" "Qk" (func $internal633))
+ (import "env" "Rk" (func $internal634))
+ (import "env" "Sk" (func $internal635))
+ (import "env" "Tk" (func $internal636))
+ (import "env" "Uk" (func $internal637))
+ (import "env" "Vk" (func $internal638))
+ (import "env" "Wk" (func $internal639))
+ (import "env" "Xk" (func $internal640))
+ (import "env" "Yk" (func $internal641))
+ (import "env" "Zk" (func $internal642))
+ (import "env" "_k" (func $internal643))
+ (import "env" "$k" (func $internal644))
+ (import "env" "al" (func $internal645))
+ (import "env" "bl" (func $internal646))
+ (import "env" "cl" (func $internal647))
+ (import "env" "dl" (func $internal648))
+ (import "env" "el" (func $internal649))
+ (import "env" "fl" (func $internal650))
+ (import "env" "gl" (func $internal651))
+ (import "env" "hl" (func $internal652))
+ (import "env" "il" (func $internal653))
+ (import "env" "jl" (func $internal654))
+ (import "env" "kl" (func $internal655))
+ (import "env" "ll" (func $internal656))
+ (import "env" "ml" (func $internal657))
+ (import "env" "nl" (func $internal658))
+ (import "env" "ol" (func $internal659))
+ (import "env" "pl" (func $internal660))
+ (import "env" "ql" (func $internal661))
+ (import "env" "rl" (func $internal662))
+ (import "env" "sl" (func $internal663))
+ (import "env" "tl" (func $internal664))
+ (import "env" "ul" (func $internal665))
+ (import "env" "vl" (func $internal666))
+ (import "env" "wl" (func $internal667))
+ (import "env" "xl" (func $internal668))
+ (import "env" "yl" (func $internal669))
+ (import "env" "zl" (func $internal670))
+ (import "env" "Al" (func $internal671))
+ (import "env" "Bl" (func $internal672))
+ (import "env" "Cl" (func $internal673))
+ (import "env" "Dl" (func $internal674))
+ (import "env" "El" (func $internal675))
+ (import "env" "Fl" (func $internal676))
+ (import "env" "Gl" (func $internal677))
+ (import "env" "Hl" (func $internal678))
+ (import "env" "Il" (func $internal679))
+ (import "env" "Jl" (func $internal680))
+ (import "env" "Kl" (func $internal681))
+ (import "env" "Ll" (func $internal682))
+ (import "env" "Ml" (func $internal683))
+ (import "env" "Nl" (func $internal684))
+ (import "env" "Ol" (func $internal685))
+ (import "env" "Pl" (func $internal686))
+ (import "env" "Ql" (func $internal687))
+ (import "env" "Rl" (func $internal688))
+ (import "env" "Sl" (func $internal689))
+ (import "env" "Tl" (func $internal690))
+ (import "env" "Ul" (func $internal691))
+ (import "env" "Vl" (func $internal692))
+ (import "env" "Wl" (func $internal693))
+ (import "env" "Xl" (func $internal694))
+ (import "env" "Yl" (func $internal695))
+ (import "env" "Zl" (func $internal696))
+ (import "env" "_l" (func $internal697))
+ (import "env" "$l" (func $internal698))
+ (import "env" "am" (func $internal699))
+ (import "env" "bm" (func $internal700))
+ (import "env" "cm" (func $internal701))
+ (import "env" "dm" (func $internal702))
+ (import "env" "em" (func $internal703))
+ (import "env" "fm" (func $internal704))
+ (import "env" "gm" (func $internal705))
+ (import "env" "hm" (func $internal706))
+ (import "env" "im" (func $internal707))
+ (import "env" "jm" (func $internal708))
+ (import "env" "km" (func $internal709))
+ (import "env" "lm" (func $internal710))
+ (import "env" "mm" (func $internal711))
+ (import "env" "nm" (func $internal712))
+ (import "env" "om" (func $internal713))
+ (import "env" "pm" (func $internal714))
+ (import "env" "qm" (func $internal715))
+ (import "env" "rm" (func $internal716))
+ (import "env" "sm" (func $internal717))
+ (import "env" "tm" (func $internal718))
+ (import "env" "um" (func $internal719))
+ (import "env" "vm" (func $internal720))
+ (import "env" "wm" (func $internal721))
+ (import "env" "xm" (func $internal722))
+ (import "env" "ym" (func $internal723))
+ (import "env" "zm" (func $internal724))
+ (import "env" "Am" (func $internal725))
+ (import "env" "Bm" (func $internal726))
+ (import "env" "Cm" (func $internal727))
+ (import "env" "Dm" (func $internal728))
+ (import "env" "Em" (func $internal729))
+ (import "env" "Fm" (func $internal730))
+ (import "env" "Gm" (func $internal731))
+ (import "env" "Hm" (func $internal732))
+ (import "env" "Im" (func $internal733))
+ (import "env" "Jm" (func $internal734))
+ (import "env" "Km" (func $internal735))
+ (import "env" "Lm" (func $internal736))
+ (import "env" "Mm" (func $internal737))
+ (import "env" "Nm" (func $internal738))
+ (import "env" "Om" (func $internal739))
+ (import "env" "Pm" (func $internal740))
+ (import "env" "Qm" (func $internal741))
+ (import "env" "Rm" (func $internal742))
+ (import "env" "Sm" (func $internal743))
+ (import "env" "Tm" (func $internal744))
+ (import "env" "Um" (func $internal745))
+ (import "env" "Vm" (func $internal746))
+ (import "env" "Wm" (func $internal747))
+ (import "env" "Xm" (func $internal748))
+ (import "env" "Ym" (func $internal749))
+ (import "env" "Zm" (func $internal750))
+ (import "env" "_m" (func $internal751))
+ (import "env" "$m" (func $internal752))
+ (import "env" "an" (func $internal753))
+ (import "env" "bn" (func $internal754))
+ (import "env" "cn" (func $internal755))
+ (import "env" "dn" (func $internal756))
+ (import "env" "en" (func $internal757))
+ (import "env" "fn" (func $internal758))
+ (import "env" "gn" (func $internal759))
+ (import "env" "hn" (func $internal760))
+ (import "env" "jn" (func $internal761))
+ (import "env" "kn" (func $internal762))
+ (import "env" "ln" (func $internal763))
+ (import "env" "mn" (func $internal764))
+ (import "env" "nn" (func $internal765))
+ (import "env" "on" (func $internal766))
+ (import "env" "pn" (func $internal767))
+ (import "env" "qn" (func $internal768))
+ (import "env" "rn" (func $internal769))
+ (import "env" "sn" (func $internal770))
+ (import "env" "tn" (func $internal771))
+ (import "env" "un" (func $internal772))
+ (import "env" "vn" (func $internal773))
+ (import "env" "wn" (func $internal774))
+ (import "env" "xn" (func $internal775))
+ (import "env" "yn" (func $internal776))
+ (import "env" "zn" (func $internal777))
+ (import "env" "An" (func $internal778))
+ (import "env" "Bn" (func $internal779))
+ (import "env" "Cn" (func $internal780))
+ (import "env" "Dn" (func $internal781))
+ (import "env" "En" (func $internal782))
+ (import "env" "Fn" (func $internal783))
+ (import "env" "Gn" (func $internal784))
+ (import "env" "Hn" (func $internal785))
+ (import "env" "In" (func $internal786))
+ (import "env" "Jn" (func $internal787))
+ (import "env" "Kn" (func $internal788))
+ (import "env" "Ln" (func $internal789))
+ (import "env" "Mn" (func $internal790))
+ (import "env" "Nn" (func $internal791))
+ (import "env" "On" (func $internal792))
+ (import "env" "Pn" (func $internal793))
+ (import "env" "Qn" (func $internal794))
+ (import "env" "Rn" (func $internal795))
+ (import "env" "Sn" (func $internal796))
+ (import "env" "Tn" (func $internal797))
+ (import "env" "Un" (func $internal798))
+ (import "env" "Vn" (func $internal799))
+ (import "env" "Wn" (func $internal800))
+ (import "env" "Xn" (func $internal801))
+ (import "env" "Yn" (func $internal802))
+ (import "env" "Zn" (func $internal803))
+ (import "env" "_n" (func $internal804))
+ (import "env" "$n" (func $internal805))
+ (import "env" "ao" (func $internal806))
+ (import "env" "bo" (func $internal807))
+ (import "env" "co" (func $internal808))
+ (import "env" "eo" (func $internal809))
+ (import "env" "fo" (func $internal810))
+ (import "env" "go" (func $internal811))
+ (import "env" "ho" (func $internal812))
+ (import "env" "io" (func $internal813))
+ (import "env" "jo" (func $internal814))
+ (import "env" "ko" (func $internal815))
+ (import "env" "lo" (func $internal816))
+ (import "env" "mo" (func $internal817))
+ (import "env" "no" (func $internal818))
+ (import "env" "oo" (func $internal819))
+ (import "env" "po" (func $internal820))
+ (import "env" "qo" (func $internal821))
+ (import "env" "ro" (func $internal822))
+ (import "env" "so" (func $internal823))
+ (import "env" "to" (func $internal824))
+ (import "env" "uo" (func $internal825))
+ (import "env" "vo" (func $internal826))
+ (import "env" "wo" (func $internal827))
+ (import "env" "xo" (func $internal828))
+ (import "env" "yo" (func $internal829))
+ (import "env" "zo" (func $internal830))
+ (import "env" "Ao" (func $internal831))
+ (import "env" "Bo" (func $internal832))
+ (import "env" "Co" (func $internal833))
+ (import "env" "Do" (func $internal834))
+ (import "env" "Eo" (func $internal835))
+ (import "env" "Fo" (func $internal836))
+ (import "env" "Go" (func $internal837))
+ (import "env" "Ho" (func $internal838))
+ (import "env" "Io" (func $internal839))
+ (import "env" "Jo" (func $internal840))
+ (import "env" "Ko" (func $internal841))
+ (import "env" "Lo" (func $internal842))
+ (import "env" "Mo" (func $internal843))
+ (import "env" "No" (func $internal844))
+ (import "env" "Oo" (func $internal845))
+ (import "env" "Po" (func $internal846))
+ (import "env" "Qo" (func $internal847))
+ (import "env" "Ro" (func $internal848))
+ (import "env" "So" (func $internal849))
+ (import "env" "To" (func $internal850))
+ (import "env" "Uo" (func $internal851))
+ (import "env" "Vo" (func $internal852))
+ (import "env" "Wo" (func $internal853))
+ (import "env" "Xo" (func $internal854))
+ (import "env" "Yo" (func $internal855))
+ (import "env" "Zo" (func $internal856))
+ (import "env" "_o" (func $internal857))
+ (import "env" "$o" (func $internal858))
+ (import "env" "ap" (func $internal859))
+ (import "env" "bp" (func $internal860))
+ (import "env" "cp" (func $internal861))
+ (import "env" "dp" (func $internal862))
+ (import "env" "ep" (func $internal863))
+ (import "env" "fp" (func $internal864))
+ (import "env" "gp" (func $internal865))
+ (import "env" "hp" (func $internal866))
+ (import "env" "ip" (func $internal867))
+ (import "env" "jp" (func $internal868))
+ (import "env" "kp" (func $internal869))
+ (import "env" "lp" (func $internal870))
+ (import "env" "mp" (func $internal871))
+ (import "env" "np" (func $internal872))
+ (import "env" "op" (func $internal873))
+ (import "env" "pp" (func $internal874))
+ (import "env" "qp" (func $internal875))
+ (import "env" "rp" (func $internal876))
+ (import "env" "sp" (func $internal877))
+ (import "env" "tp" (func $internal878))
+ (import "env" "up" (func $internal879))
+ (import "env" "vp" (func $internal880))
+ (import "env" "wp" (func $internal881))
+ (import "env" "xp" (func $internal882))
+ (import "env" "yp" (func $internal883))
+ (import "env" "zp" (func $internal884))
+ (import "env" "Ap" (func $internal885))
+ (import "env" "Bp" (func $internal886))
+ (import "env" "Cp" (func $internal887))
+ (import "env" "Dp" (func $internal888))
+ (import "env" "Ep" (func $internal889))
+ (import "env" "Fp" (func $internal890))
+ (import "env" "Gp" (func $internal891))
+ (import "env" "Hp" (func $internal892))
+ (import "env" "Ip" (func $internal893))
+ (import "env" "Jp" (func $internal894))
+ (import "env" "Kp" (func $internal895))
+ (import "env" "Lp" (func $internal896))
+ (import "env" "Mp" (func $internal897))
+ (import "env" "Np" (func $internal898))
+ (import "env" "Op" (func $internal899))
+ (import "env" "Pp" (func $internal900))
+ (import "env" "Qp" (func $internal901))
+ (import "env" "Rp" (func $internal902))
+ (import "env" "Sp" (func $internal903))
+ (import "env" "Tp" (func $internal904))
+ (import "env" "Up" (func $internal905))
+ (import "env" "Vp" (func $internal906))
+ (import "env" "Wp" (func $internal907))
+ (import "env" "Xp" (func $internal908))
+ (import "env" "Yp" (func $internal909))
+ (import "env" "Zp" (func $internal910))
+ (import "env" "_p" (func $internal911))
+ (import "env" "$p" (func $internal912))
+ (import "env" "aq" (func $internal913))
+ (import "env" "bq" (func $internal914))
+ (import "env" "cq" (func $internal915))
+ (import "env" "dq" (func $internal916))
+ (import "env" "eq" (func $internal917))
+ (import "env" "fq" (func $internal918))
+ (import "env" "gq" (func $internal919))
+ (import "env" "hq" (func $internal920))
+ (import "env" "iq" (func $internal921))
+ (import "env" "jq" (func $internal922))
+ (import "env" "kq" (func $internal923))
+ (import "env" "lq" (func $internal924))
+ (import "env" "mq" (func $internal925))
+ (import "env" "nq" (func $internal926))
+ (import "env" "oq" (func $internal927))
+ (import "env" "pq" (func $internal928))
+ (import "env" "qq" (func $internal929))
+ (import "env" "rq" (func $internal930))
+ (import "env" "sq" (func $internal931))
+ (import "env" "tq" (func $internal932))
+ (import "env" "uq" (func $internal933))
+ (import "env" "vq" (func $internal934))
+ (import "env" "wq" (func $internal935))
+ (import "env" "xq" (func $internal936))
+ (import "env" "yq" (func $internal937))
+ (import "env" "zq" (func $internal938))
+ (import "env" "Aq" (func $internal939))
+ (import "env" "Bq" (func $internal940))
+ (import "env" "Cq" (func $internal941))
+ (import "env" "Dq" (func $internal942))
+ (import "env" "Eq" (func $internal943))
+ (import "env" "Fq" (func $internal944))
+ (import "env" "Gq" (func $internal945))
+ (import "env" "Hq" (func $internal946))
+ (import "env" "Iq" (func $internal947))
+ (import "env" "Jq" (func $internal948))
+ (import "env" "Kq" (func $internal949))
+ (import "env" "Lq" (func $internal950))
+ (import "env" "Mq" (func $internal951))
+ (import "env" "Nq" (func $internal952))
+ (import "env" "Oq" (func $internal953))
+ (import "env" "Pq" (func $internal954))
+ (import "env" "Qq" (func $internal955))
+ (import "env" "Rq" (func $internal956))
+ (import "env" "Sq" (func $internal957))
+ (import "env" "Tq" (func $internal958))
+ (import "env" "Uq" (func $internal959))
+ (import "env" "Vq" (func $internal960))
+ (import "env" "Wq" (func $internal961))
+ (import "env" "Xq" (func $internal962))
+ (import "env" "Yq" (func $internal963))
+ (import "env" "Zq" (func $internal964))
+ (import "env" "_q" (func $internal965))
+ (import "env" "$q" (func $internal966))
+ (import "env" "ar" (func $internal967))
+ (import "env" "br" (func $internal968))
+ (import "env" "cr" (func $internal969))
+ (import "env" "dr" (func $internal970))
+ (import "env" "er" (func $internal971))
+ (import "env" "fr" (func $internal972))
+ (import "env" "gr" (func $internal973))
+ (import "env" "hr" (func $internal974))
+ (import "env" "ir" (func $internal975))
+ (import "env" "jr" (func $internal976))
+ (import "env" "kr" (func $internal977))
+ (import "env" "lr" (func $internal978))
+ (import "env" "mr" (func $internal979))
+ (import "env" "nr" (func $internal980))
+ (import "env" "or" (func $internal981))
+ (import "env" "pr" (func $internal982))
+ (import "env" "qr" (func $internal983))
+ (import "env" "rr" (func $internal984))
+ (import "env" "sr" (func $internal985))
+ (import "env" "tr" (func $internal986))
+ (import "env" "ur" (func $internal987))
+ (import "env" "vr" (func $internal988))
+ (import "env" "wr" (func $internal989))
+ (import "env" "xr" (func $internal990))
+ (import "env" "yr" (func $internal991))
+ (import "env" "zr" (func $internal992))
+ (import "env" "Ar" (func $internal993))
+ (import "env" "Br" (func $internal994))
+ (import "env" "Cr" (func $internal995))
+ (import "env" "Dr" (func $internal996))
+ (import "env" "Er" (func $internal997))
+ (import "env" "Fr" (func $internal998))
+ (import "env" "Gr" (func $internal999))
+ (import "env" "Hr" (func $internal1000))
+ (import "env" "Ir" (func $internal1001))
+ (import "env" "Jr" (func $internal1002))
+ (import "env" "Kr" (func $internal1003))
+ (import "env" "Lr" (func $internal1004))
+ (import "env" "Mr" (func $internal1005))
+ (import "env" "Nr" (func $internal1006))
+ (import "env" "Or" (func $internal1007))
+ (import "env" "Pr" (func $internal1008))
+ (import "env" "Qr" (func $internal1009))
+ (import "env" "Rr" (func $internal1010))
+ (import "env" "Sr" (func $internal1011))
+ (import "env" "Tr" (func $internal1012))
+ (import "env" "Ur" (func $internal1013))
+ (import "env" "Vr" (func $internal1014))
+ (import "env" "Wr" (func $internal1015))
+ (import "env" "Xr" (func $internal1016))
+ (import "env" "Yr" (func $internal1017))
+ (import "env" "Zr" (func $internal1018))
+ (import "env" "_r" (func $internal1019))
+ (import "env" "$r" (func $internal1020))
+ (import "env" "as" (func $internal1021))
+ (import "env" "bs" (func $internal1022))
+ (import "env" "cs" (func $internal1023))
+ (import "env" "ds" (func $internal1024))
+ (import "env" "es" (func $internal1025))
+ (import "env" "fs" (func $internal1026))
+ (import "env" "gs" (func $internal1027))
+ (import "env" "hs" (func $internal1028))
+ (import "env" "is" (func $internal1029))
+ (import "env" "js" (func $internal1030))
+ (import "env" "ks" (func $internal1031))
+ (import "env" "ls" (func $internal1032))
+ (import "env" "ms" (func $internal1033))
+ (import "env" "ns" (func $internal1034))
+ (import "env" "os" (func $internal1035))
+ (import "env" "ps" (func $internal1036))
+ (import "env" "qs" (func $internal1037))
+ (import "env" "rs" (func $internal1038))
+ (import "env" "ss" (func $internal1039))
+ (import "env" "ts" (func $internal1040))
+ (import "env" "us" (func $internal1041))
+ (import "env" "vs" (func $internal1042))
+ (import "env" "ws" (func $internal1043))
+ (import "env" "xs" (func $internal1044))
+ (import "env" "ys" (func $internal1045))
+ (import "env" "zs" (func $internal1046))
+ (import "env" "As" (func $internal1047))
+ (import "env" "Bs" (func $internal1048))
+ (import "env" "Cs" (func $internal1049))
+ (import "env" "Ds" (func $internal1050))
+ (import "env" "Es" (func $internal1051))
+ (import "env" "Fs" (func $internal1052))
+ (import "env" "Gs" (func $internal1053))
+ (import "env" "Hs" (func $internal1054))
+ (import "env" "Is" (func $internal1055))
+ (import "env" "Js" (func $internal1056))
+ (import "env" "Ks" (func $internal1057))
+ (import "env" "Ls" (func $internal1058))
+ (import "env" "Ms" (func $internal1059))
+ (import "env" "Ns" (func $internal1060))
+ (import "env" "Os" (func $internal1061))
+ (import "env" "Ps" (func $internal1062))
+ (import "env" "Qs" (func $internal1063))
+ (import "env" "Rs" (func $internal1064))
+ (import "env" "Ss" (func $internal1065))
+ (import "env" "Ts" (func $internal1066))
+ (import "env" "Us" (func $internal1067))
+ (import "env" "Vs" (func $internal1068))
+ (import "env" "Ws" (func $internal1069))
+ (import "env" "Xs" (func $internal1070))
+ (import "env" "Ys" (func $internal1071))
+ (import "env" "Zs" (func $internal1072))
+ (import "env" "_s" (func $internal1073))
+ (import "env" "$s" (func $internal1074))
+ (import "env" "at" (func $internal1075))
+ (import "env" "bt" (func $internal1076))
+ (import "env" "ct" (func $internal1077))
+ (import "env" "dt" (func $internal1078))
+ (import "env" "et" (func $internal1079))
+ (import "env" "ft" (func $internal1080))
+ (import "env" "gt" (func $internal1081))
+ (import "env" "ht" (func $internal1082))
+ (import "env" "it" (func $internal1083))
+ (import "env" "jt" (func $internal1084))
+ (import "env" "kt" (func $internal1085))
+ (import "env" "lt" (func $internal1086))
+ (import "env" "mt" (func $internal1087))
+ (import "env" "nt" (func $internal1088))
+ (import "env" "ot" (func $internal1089))
+ (import "env" "pt" (func $internal1090))
+ (import "env" "qt" (func $internal1091))
+ (import "env" "rt" (func $internal1092))
+ (import "env" "st" (func $internal1093))
+ (import "env" "tt" (func $internal1094))
+ (import "env" "ut" (func $internal1095))
+ (import "env" "vt" (func $internal1096))
+ (import "env" "wt" (func $internal1097))
+ (import "env" "xt" (func $internal1098))
+ (import "env" "yt" (func $internal1099))
+ (import "env" "zt" (func $internal1100))
+ (import "env" "At" (func $internal1101))
+ (import "env" "Bt" (func $internal1102))
+ (import "env" "Ct" (func $internal1103))
+ (import "env" "Dt" (func $internal1104))
+ (import "env" "Et" (func $internal1105))
+ (import "env" "Ft" (func $internal1106))
+ (import "env" "Gt" (func $internal1107))
+ (import "env" "Ht" (func $internal1108))
+ (import "env" "It" (func $internal1109))
+ (import "env" "Jt" (func $internal1110))
+ (import "env" "Kt" (func $internal1111))
+ (import "env" "Lt" (func $internal1112))
+ (import "env" "Mt" (func $internal1113))
+ (import "env" "Nt" (func $internal1114))
+ (import "env" "Ot" (func $internal1115))
+ (import "env" "Pt" (func $internal1116))
+ (import "env" "Qt" (func $internal1117))
+ (import "env" "Rt" (func $internal1118))
+ (import "env" "St" (func $internal1119))
+ (import "env" "Tt" (func $internal1120))
+ (import "env" "Ut" (func $internal1121))
+ (import "env" "Vt" (func $internal1122))
+ (import "env" "Wt" (func $internal1123))
+ (import "env" "Xt" (func $internal1124))
+ (import "env" "Yt" (func $internal1125))
+ (import "env" "Zt" (func $internal1126))
+ (import "env" "_t" (func $internal1127))
+ (import "env" "$t" (func $internal1128))
+ (import "env" "au" (func $internal1129))
+ (import "env" "bu" (func $internal1130))
+ (import "env" "cu" (func $internal1131))
+ (import "env" "du" (func $internal1132))
+ (import "env" "eu" (func $internal1133))
+ (import "env" "fu" (func $internal1134))
+ (import "env" "gu" (func $internal1135))
+ (import "env" "hu" (func $internal1136))
+ (import "env" "iu" (func $internal1137))
+ (import "env" "ju" (func $internal1138))
+ (import "env" "ku" (func $internal1139))
+ (import "env" "lu" (func $internal1140))
+ (import "env" "mu" (func $internal1141))
+ (import "env" "nu" (func $internal1142))
+ (import "env" "ou" (func $internal1143))
+ (import "env" "pu" (func $internal1144))
+ (import "env" "qu" (func $internal1145))
+ (import "env" "ru" (func $internal1146))
+ (import "env" "su" (func $internal1147))
+ (import "env" "tu" (func $internal1148))
+ (import "env" "uu" (func $internal1149))
+ (import "env" "vu" (func $internal1150))
+ (import "env" "wu" (func $internal1151))
+ (import "env" "xu" (func $internal1152))
+ (import "env" "yu" (func $internal1153))
+ (import "env" "zu" (func $internal1154))
+ (import "env" "Au" (func $internal1155))
+ (import "env" "Bu" (func $internal1156))
+ (import "env" "Cu" (func $internal1157))
+ (import "env" "Du" (func $internal1158))
+ (import "env" "Eu" (func $internal1159))
+ (import "env" "Fu" (func $internal1160))
+ (import "env" "Gu" (func $internal1161))
+ (import "env" "Hu" (func $internal1162))
+ (import "env" "Iu" (func $internal1163))
+ (import "env" "Ju" (func $internal1164))
+ (import "env" "Ku" (func $internal1165))
+ (import "env" "Lu" (func $internal1166))
+ (import "env" "Mu" (func $internal1167))
+ (import "env" "Nu" (func $internal1168))
+ (import "env" "Ou" (func $internal1169))
+ (import "env" "Pu" (func $internal1170))
+ (import "env" "Qu" (func $internal1171))
+ (import "env" "Ru" (func $internal1172))
+ (import "env" "Su" (func $internal1173))
+ (import "env" "Tu" (func $internal1174))
+ (import "env" "Uu" (func $internal1175))
+ (import "env" "Vu" (func $internal1176))
+ (import "env" "Wu" (func $internal1177))
+ (import "env" "Xu" (func $internal1178))
+ (import "env" "Yu" (func $internal1179))
+ (import "env" "Zu" (func $internal1180))
+ (import "env" "_u" (func $internal1181))
+ (import "env" "$u" (func $internal1182))
+ (import "env" "av" (func $internal1183))
+ (import "env" "bv" (func $internal1184))
+ (import "env" "cv" (func $internal1185))
+ (import "env" "dv" (func $internal1186))
+ (import "env" "ev" (func $internal1187))
+ (import "env" "fv" (func $internal1188))
+ (import "env" "gv" (func $internal1189))
+ (import "env" "hv" (func $internal1190))
+ (import "env" "iv" (func $internal1191))
+ (import "env" "jv" (func $internal1192))
+ (import "env" "kv" (func $internal1193))
+ (import "env" "lv" (func $internal1194))
+ (import "env" "mv" (func $internal1195))
+ (import "env" "nv" (func $internal1196))
+ (import "env" "ov" (func $internal1197))
+ (import "env" "pv" (func $internal1198))
+ (import "env" "qv" (func $internal1199))
+ (import "env" "rv" (func $internal1200))
+ (import "env" "sv" (func $internal1201))
+ (import "env" "tv" (func $internal1202))
+ (import "env" "uv" (func $internal1203))
+ (import "env" "vv" (func $internal1204))
+ (import "env" "wv" (func $internal1205))
+ (import "env" "xv" (func $internal1206))
+ (import "env" "yv" (func $internal1207))
+ (import "env" "zv" (func $internal1208))
+ (import "env" "Av" (func $internal1209))
+ (import "env" "Bv" (func $internal1210))
+ (import "env" "Cv" (func $internal1211))
+ (import "env" "Dv" (func $internal1212))
+ (import "env" "Ev" (func $internal1213))
+ (import "env" "Fv" (func $internal1214))
+ (import "env" "Gv" (func $internal1215))
+ (import "env" "Hv" (func $internal1216))
+ (import "env" "Iv" (func $internal1217))
+ (import "env" "Jv" (func $internal1218))
+ (import "env" "Kv" (func $internal1219))
+ (import "env" "Lv" (func $internal1220))
+ (import "env" "Mv" (func $internal1221))
+ (import "env" "Nv" (func $internal1222))
+ (import "env" "Ov" (func $internal1223))
+ (import "env" "Pv" (func $internal1224))
+ (import "env" "Qv" (func $internal1225))
+ (import "env" "Rv" (func $internal1226))
+ (import "env" "Sv" (func $internal1227))
+ (import "env" "Tv" (func $internal1228))
+ (import "env" "Uv" (func $internal1229))
+ (import "env" "Vv" (func $internal1230))
+ (import "env" "Wv" (func $internal1231))
+ (import "env" "Xv" (func $internal1232))
+ (import "env" "Yv" (func $internal1233))
+ (import "env" "Zv" (func $internal1234))
+ (import "env" "_v" (func $internal1235))
+ (import "env" "$v" (func $internal1236))
+ (import "env" "aw" (func $internal1237))
+ (import "env" "bw" (func $internal1238))
+ (import "env" "cw" (func $internal1239))
+ (import "env" "dw" (func $internal1240))
+ (import "env" "ew" (func $internal1241))
+ (import "env" "fw" (func $internal1242))
+ (import "env" "gw" (func $internal1243))
+ (import "env" "hw" (func $internal1244))
+ (import "env" "iw" (func $internal1245))
+ (import "env" "jw" (func $internal1246))
+ (import "env" "kw" (func $internal1247))
+ (import "env" "lw" (func $internal1248))
+ (import "env" "mw" (func $internal1249))
+ (import "env" "nw" (func $internal1250))
+ (import "env" "ow" (func $internal1251))
+ (import "env" "pw" (func $internal1252))
+ (import "env" "qw" (func $internal1253))
+ (import "env" "rw" (func $internal1254))
+ (import "env" "sw" (func $internal1255))
+ (import "env" "tw" (func $internal1256))
+ (import "env" "uw" (func $internal1257))
+ (import "env" "vw" (func $internal1258))
+ (import "env" "ww" (func $internal1259))
+ (import "env" "xw" (func $internal1260))
+ (import "env" "yw" (func $internal1261))
+ (import "env" "zw" (func $internal1262))
+ (import "env" "Aw" (func $internal1263))
+ (import "env" "Bw" (func $internal1264))
+ (import "env" "Cw" (func $internal1265))
+ (import "env" "Dw" (func $internal1266))
+ (import "env" "Ew" (func $internal1267))
+ (import "env" "Fw" (func $internal1268))
+ (import "env" "Gw" (func $internal1269))
+ (import "env" "Hw" (func $internal1270))
+ (import "env" "Iw" (func $internal1271))
+ (import "env" "Jw" (func $internal1272))
+ (import "env" "Kw" (func $internal1273))
+ (import "env" "Lw" (func $internal1274))
+ (import "env" "Mw" (func $internal1275))
+ (import "env" "Nw" (func $internal1276))
+ (import "env" "Ow" (func $internal1277))
+ (import "env" "Pw" (func $internal1278))
+ (import "env" "Qw" (func $internal1279))
+ (import "env" "Rw" (func $internal1280))
+ (import "env" "Sw" (func $internal1281))
+ (import "env" "Tw" (func $internal1282))
+ (import "env" "Uw" (func $internal1283))
+ (import "env" "Vw" (func $internal1284))
+ (import "env" "Ww" (func $internal1285))
+ (import "env" "Xw" (func $internal1286))
+ (import "env" "Yw" (func $internal1287))
+ (import "env" "Zw" (func $internal1288))
+ (import "env" "_w" (func $internal1289))
+ (import "env" "$w" (func $internal1290))
+ (import "env" "ax" (func $internal1291))
+ (import "env" "bx" (func $internal1292))
+ (import "env" "cx" (func $internal1293))
+ (import "env" "dx" (func $internal1294))
+ (import "env" "ex" (func $internal1295))
+ (import "env" "fx" (func $internal1296))
+ (import "env" "gx" (func $internal1297))
+ (import "env" "hx" (func $internal1298))
+ (import "env" "ix" (func $internal1299))
+ (import "env" "jx" (func $internal1300))
+ (import "env" "kx" (func $internal1301))
+ (import "env" "lx" (func $internal1302))
+ (import "env" "mx" (func $internal1303))
+ (import "env" "nx" (func $internal1304))
+ (import "env" "ox" (func $internal1305))
+ (import "env" "px" (func $internal1306))
+ (import "env" "qx" (func $internal1307))
+ (import "env" "rx" (func $internal1308))
+ (import "env" "sx" (func $internal1309))
+ (import "env" "tx" (func $internal1310))
+ (import "env" "ux" (func $internal1311))
+ (import "env" "vx" (func $internal1312))
+ (import "env" "wx" (func $internal1313))
+ (import "env" "xx" (func $internal1314))
+ (import "env" "yx" (func $internal1315))
+ (import "env" "zx" (func $internal1316))
+ (import "env" "Ax" (func $internal1317))
+ (import "env" "Bx" (func $internal1318))
+ (import "env" "Cx" (func $internal1319))
+ (import "env" "Dx" (func $internal1320))
+ (import "env" "Ex" (func $internal1321))
+ (import "env" "Fx" (func $internal1322))
+ (import "env" "Gx" (func $internal1323))
+ (import "env" "Hx" (func $internal1324))
+ (import "env" "Ix" (func $internal1325))
+ (import "env" "Jx" (func $internal1326))
+ (import "env" "Kx" (func $internal1327))
+ (import "env" "Lx" (func $internal1328))
+ (import "env" "Mx" (func $internal1329))
+ (import "env" "Nx" (func $internal1330))
+ (import "env" "Ox" (func $internal1331))
+ (import "env" "Px" (func $internal1332))
+ (import "env" "Qx" (func $internal1333))
+ (import "env" "Rx" (func $internal1334))
+ (import "env" "Sx" (func $internal1335))
+ (import "env" "Tx" (func $internal1336))
+ (import "env" "Ux" (func $internal1337))
+ (import "env" "Vx" (func $internal1338))
+ (import "env" "Wx" (func $internal1339))
+ (import "env" "Xx" (func $internal1340))
+ (import "env" "Yx" (func $internal1341))
+ (import "env" "Zx" (func $internal1342))
+ (import "env" "_x" (func $internal1343))
+ (import "env" "$x" (func $internal1344))
+ (import "env" "ay" (func $internal1345))
+ (import "env" "by" (func $internal1346))
+ (import "env" "cy" (func $internal1347))
+ (import "env" "dy" (func $internal1348))
+ (import "env" "ey" (func $internal1349))
+ (import "env" "fy" (func $internal1350))
+ (import "env" "gy" (func $internal1351))
+ (import "env" "hy" (func $internal1352))
+ (import "env" "iy" (func $internal1353))
+ (import "env" "jy" (func $internal1354))
+ (import "env" "ky" (func $internal1355))
+ (import "env" "ly" (func $internal1356))
+ (import "env" "my" (func $internal1357))
+ (import "env" "ny" (func $internal1358))
+ (import "env" "oy" (func $internal1359))
+ (import "env" "py" (func $internal1360))
+ (import "env" "qy" (func $internal1361))
+ (import "env" "ry" (func $internal1362))
+ (import "env" "sy" (func $internal1363))
+ (import "env" "ty" (func $internal1364))
+ (import "env" "uy" (func $internal1365))
+ (import "env" "vy" (func $internal1366))
+ (import "env" "wy" (func $internal1367))
+ (import "env" "xy" (func $internal1368))
+ (import "env" "yy" (func $internal1369))
+ (import "env" "zy" (func $internal1370))
+ (import "env" "Ay" (func $internal1371))
+ (import "env" "By" (func $internal1372))
+ (import "env" "Cy" (func $internal1373))
+ (import "env" "Dy" (func $internal1374))
+ (import "env" "Ey" (func $internal1375))
+ (import "env" "Fy" (func $internal1376))
+ (import "env" "Gy" (func $internal1377))
+ (import "env" "Hy" (func $internal1378))
+ (import "env" "Iy" (func $internal1379))
+ (import "env" "Jy" (func $internal1380))
+ (import "env" "Ky" (func $internal1381))
+ (import "env" "Ly" (func $internal1382))
+ (import "env" "My" (func $internal1383))
+ (import "env" "Ny" (func $internal1384))
+ (import "env" "Oy" (func $internal1385))
+ (import "env" "Py" (func $internal1386))
+ (import "env" "Qy" (func $internal1387))
+ (import "env" "Ry" (func $internal1388))
+ (import "env" "Sy" (func $internal1389))
+ (import "env" "Ty" (func $internal1390))
+ (import "env" "Uy" (func $internal1391))
+ (import "env" "Vy" (func $internal1392))
+ (import "env" "Wy" (func $internal1393))
+ (import "env" "Xy" (func $internal1394))
+ (import "env" "Yy" (func $internal1395))
+ (import "env" "Zy" (func $internal1396))
+ (import "env" "_y" (func $internal1397))
+ (import "env" "$y" (func $internal1398))
+ (import "env" "az" (func $internal1399))
+ (import "env" "bz" (func $internal1400))
+ (import "env" "cz" (func $internal1401))
+ (import "env" "dz" (func $internal1402))
+ (import "env" "ez" (func $internal1403))
+ (import "env" "fz" (func $internal1404))
+ (import "env" "gz" (func $internal1405))
+ (import "env" "hz" (func $internal1406))
+ (import "env" "iz" (func $internal1407))
+ (import "env" "jz" (func $internal1408))
+ (import "env" "kz" (func $internal1409))
+ (import "env" "lz" (func $internal1410))
+ (import "env" "mz" (func $internal1411))
+ (import "env" "nz" (func $internal1412))
+ (import "env" "oz" (func $internal1413))
+ (import "env" "pz" (func $internal1414))
+ (import "env" "qz" (func $internal1415))
+ (import "env" "rz" (func $internal1416))
+ (import "env" "sz" (func $internal1417))
+ (import "env" "tz" (func $internal1418))
+ (import "env" "uz" (func $internal1419))
+ (import "env" "vz" (func $internal1420))
+ (import "env" "wz" (func $internal1421))
+ (import "env" "xz" (func $internal1422))
+ (import "env" "yz" (func $internal1423))
+ (import "env" "zz" (func $internal1424))
+ (import "env" "Az" (func $internal1425))
+ (import "env" "Bz" (func $internal1426))
+ (import "env" "Cz" (func $internal1427))
+ (import "env" "Dz" (func $internal1428))
+ (import "env" "Ez" (func $internal1429))
+ (import "env" "Fz" (func $internal1430))
+ (import "env" "Gz" (func $internal1431))
+ (import "env" "Hz" (func $internal1432))
+ (import "env" "Iz" (func $internal1433))
+ (import "env" "Jz" (func $internal1434))
+ (import "env" "Kz" (func $internal1435))
+ (import "env" "Lz" (func $internal1436))
+ (import "env" "Mz" (func $internal1437))
+ (import "env" "Nz" (func $internal1438))
+ (import "env" "Oz" (func $internal1439))
+ (import "env" "Pz" (func $internal1440))
+ (import "env" "Qz" (func $internal1441))
+ (import "env" "Rz" (func $internal1442))
+ (import "env" "Sz" (func $internal1443))
+ (import "env" "Tz" (func $internal1444))
+ (import "env" "Uz" (func $internal1445))
+ (import "env" "Vz" (func $internal1446))
+ (import "env" "Wz" (func $internal1447))
+ (import "env" "Xz" (func $internal1448))
+ (import "env" "Yz" (func $internal1449))
+ (import "env" "Zz" (func $internal1450))
+ (import "env" "_z" (func $internal1451))
+ (import "env" "$z" (func $internal1452))
+ (import "env" "aA" (func $internal1453))
+ (import "env" "bA" (func $internal1454))
+ (import "env" "cA" (func $internal1455))
+ (import "env" "dA" (func $internal1456))
+ (import "env" "eA" (func $internal1457))
+ (import "env" "fA" (func $internal1458))
+ (import "env" "gA" (func $internal1459))
+ (import "env" "hA" (func $internal1460))
+ (import "env" "iA" (func $internal1461))
+ (import "env" "jA" (func $internal1462))
+ (import "env" "kA" (func $internal1463))
+ (import "env" "lA" (func $internal1464))
+ (import "env" "mA" (func $internal1465))
+ (import "env" "nA" (func $internal1466))
+ (import "env" "oA" (func $internal1467))
+ (import "env" "pA" (func $internal1468))
+ (import "env" "qA" (func $internal1469))
+ (import "env" "rA" (func $internal1470))
+ (import "env" "sA" (func $internal1471))
+ (import "env" "tA" (func $internal1472))
+ (import "env" "uA" (func $internal1473))
+ (import "env" "vA" (func $internal1474))
+ (import "env" "wA" (func $internal1475))
+ (import "env" "xA" (func $internal1476))
+ (import "env" "yA" (func $internal1477))
+ (import "env" "zA" (func $internal1478))
+ (import "env" "AA" (func $internal1479))
+ (import "env" "BA" (func $internal1480))
+ (import "env" "CA" (func $internal1481))
+ (import "env" "DA" (func $internal1482))
+ (import "env" "EA" (func $internal1483))
+ (import "env" "FA" (func $internal1484))
+ (import "env" "GA" (func $internal1485))
+ (import "env" "HA" (func $internal1486))
+ (import "env" "IA" (func $internal1487))
+ (import "env" "JA" (func $internal1488))
+ (import "env" "KA" (func $internal1489))
+ (import "env" "LA" (func $internal1490))
+ (import "env" "MA" (func $internal1491))
+ (import "env" "NA" (func $internal1492))
+ (import "env" "OA" (func $internal1493))
+ (import "env" "PA" (func $internal1494))
+ (import "env" "QA" (func $internal1495))
+ (import "env" "RA" (func $internal1496))
+ (import "env" "SA" (func $internal1497))
+ (import "env" "TA" (func $internal1498))
+ (import "env" "UA" (func $internal1499))
+ (import "env" "VA" (func $internal1500))
+ (import "env" "WA" (func $internal1501))
+ (import "env" "XA" (func $internal1502))
+ (import "env" "YA" (func $internal1503))
+ (import "env" "ZA" (func $internal1504))
+ (import "env" "_A" (func $internal1505))
+ (import "env" "$A" (func $internal1506))
+ (import "env" "aB" (func $internal1507))
+ (import "env" "bB" (func $internal1508))
+ (import "env" "cB" (func $internal1509))
+ (import "env" "dB" (func $internal1510))
+ (import "env" "eB" (func $internal1511))
+ (import "env" "fB" (func $internal1512))
+ (import "env" "gB" (func $internal1513))
+ (import "env" "hB" (func $internal1514))
+ (import "env" "iB" (func $internal1515))
+ (import "env" "jB" (func $internal1516))
+ (import "env" "kB" (func $internal1517))
+ (import "env" "lB" (func $internal1518))
+ (import "env" "mB" (func $internal1519))
+ (import "env" "nB" (func $internal1520))
+ (import "env" "oB" (func $internal1521))
+ (import "env" "pB" (func $internal1522))
+ (import "env" "qB" (func $internal1523))
+ (import "env" "rB" (func $internal1524))
+ (import "env" "sB" (func $internal1525))
+ (import "env" "tB" (func $internal1526))
+ (import "env" "uB" (func $internal1527))
+ (import "env" "vB" (func $internal1528))
+ (import "env" "wB" (func $internal1529))
+ (import "env" "xB" (func $internal1530))
+ (import "env" "yB" (func $internal1531))
+ (import "env" "zB" (func $internal1532))
+ (import "env" "AB" (func $internal1533))
+ (import "env" "BB" (func $internal1534))
+ (import "env" "CB" (func $internal1535))
+ (import "env" "DB" (func $internal1536))
+ (import "env" "EB" (func $internal1537))
+ (import "env" "FB" (func $internal1538))
+ (import "env" "GB" (func $internal1539))
+ (import "env" "HB" (func $internal1540))
+ (import "env" "IB" (func $internal1541))
+ (import "env" "JB" (func $internal1542))
+ (import "env" "KB" (func $internal1543))
+ (import "env" "LB" (func $internal1544))
+ (import "env" "MB" (func $internal1545))
+ (import "env" "NB" (func $internal1546))
+ (import "env" "OB" (func $internal1547))
+ (import "env" "PB" (func $internal1548))
+ (import "env" "QB" (func $internal1549))
+ (import "env" "RB" (func $internal1550))
+ (import "env" "SB" (func $internal1551))
+ (import "env" "TB" (func $internal1552))
+ (import "env" "UB" (func $internal1553))
+ (import "env" "VB" (func $internal1554))
+ (import "env" "WB" (func $internal1555))
+ (import "env" "XB" (func $internal1556))
+ (import "env" "YB" (func $internal1557))
+ (import "env" "ZB" (func $internal1558))
+ (import "env" "_B" (func $internal1559))
+ (import "env" "$B" (func $internal1560))
+ (import "env" "aC" (func $internal1561))
+ (import "env" "bC" (func $internal1562))
+ (import "env" "cC" (func $internal1563))
+ (import "env" "dC" (func $internal1564))
+ (import "env" "eC" (func $internal1565))
+ (import "env" "fC" (func $internal1566))
+ (import "env" "gC" (func $internal1567))
+ (import "env" "hC" (func $internal1568))
+ (import "env" "iC" (func $internal1569))
+ (import "env" "jC" (func $internal1570))
+ (import "env" "kC" (func $internal1571))
+ (import "env" "lC" (func $internal1572))
+ (import "env" "mC" (func $internal1573))
+ (import "env" "nC" (func $internal1574))
+ (import "env" "oC" (func $internal1575))
+ (import "env" "pC" (func $internal1576))
+ (import "env" "qC" (func $internal1577))
+ (import "env" "rC" (func $internal1578))
+ (import "env" "sC" (func $internal1579))
+ (import "env" "tC" (func $internal1580))
+ (import "env" "uC" (func $internal1581))
+ (import "env" "vC" (func $internal1582))
+ (import "env" "wC" (func $internal1583))
+ (import "env" "xC" (func $internal1584))
+ (import "env" "yC" (func $internal1585))
+ (import "env" "zC" (func $internal1586))
+ (import "env" "AC" (func $internal1587))
+ (import "env" "BC" (func $internal1588))
+ (import "env" "CC" (func $internal1589))
+ (import "env" "DC" (func $internal1590))
+ (import "env" "EC" (func $internal1591))
+ (import "env" "FC" (func $internal1592))
+ (import "env" "GC" (func $internal1593))
+ (import "env" "HC" (func $internal1594))
+ (import "env" "IC" (func $internal1595))
+ (import "env" "JC" (func $internal1596))
+ (import "env" "KC" (func $internal1597))
+ (import "env" "LC" (func $internal1598))
+ (import "env" "MC" (func $internal1599))
+ (import "env" "NC" (func $internal1600))
+ (import "env" "OC" (func $internal1601))
+ (import "env" "PC" (func $internal1602))
+ (import "env" "QC" (func $internal1603))
+ (import "env" "RC" (func $internal1604))
+ (import "env" "SC" (func $internal1605))
+ (import "env" "TC" (func $internal1606))
+ (import "env" "UC" (func $internal1607))
+ (import "env" "VC" (func $internal1608))
+ (import "env" "WC" (func $internal1609))
+ (import "env" "XC" (func $internal1610))
+ (import "env" "YC" (func $internal1611))
+ (import "env" "ZC" (func $internal1612))
+ (import "env" "_C" (func $internal1613))
+ (import "env" "$C" (func $internal1614))
+ (import "env" "aD" (func $internal1615))
+ (import "env" "bD" (func $internal1616))
+ (import "env" "cD" (func $internal1617))
+ (import "env" "dD" (func $internal1618))
+ (import "env" "eD" (func $internal1619))
+ (import "env" "fD" (func $internal1620))
+ (import "env" "gD" (func $internal1621))
+ (import "env" "hD" (func $internal1622))
+ (import "env" "iD" (func $internal1623))
+ (import "env" "jD" (func $internal1624))
+ (import "env" "kD" (func $internal1625))
+ (import "env" "lD" (func $internal1626))
+ (import "env" "mD" (func $internal1627))
+ (import "env" "nD" (func $internal1628))
+ (import "env" "oD" (func $internal1629))
+ (import "env" "pD" (func $internal1630))
+ (import "env" "qD" (func $internal1631))
+ (import "env" "rD" (func $internal1632))
+ (import "env" "sD" (func $internal1633))
+ (import "env" "tD" (func $internal1634))
+ (import "env" "uD" (func $internal1635))
+ (import "env" "vD" (func $internal1636))
+ (import "env" "wD" (func $internal1637))
+ (import "env" "xD" (func $internal1638))
+ (import "env" "yD" (func $internal1639))
+ (import "env" "zD" (func $internal1640))
+ (import "env" "AD" (func $internal1641))
+ (import "env" "BD" (func $internal1642))
+ (import "env" "CD" (func $internal1643))
+ (import "env" "DD" (func $internal1644))
+ (import "env" "ED" (func $internal1645))
+ (import "env" "FD" (func $internal1646))
+ (import "env" "GD" (func $internal1647))
+ (import "env" "HD" (func $internal1648))
+ (import "env" "ID" (func $internal1649))
+ (import "env" "JD" (func $internal1650))
+ (import "env" "KD" (func $internal1651))
+ (import "env" "LD" (func $internal1652))
+ (import "env" "MD" (func $internal1653))
+ (import "env" "ND" (func $internal1654))
+ (import "env" "OD" (func $internal1655))
+ (import "env" "PD" (func $internal1656))
+ (import "env" "QD" (func $internal1657))
+ (import "env" "RD" (func $internal1658))
+ (import "env" "SD" (func $internal1659))
+ (import "env" "TD" (func $internal1660))
+ (import "env" "UD" (func $internal1661))
+ (import "env" "VD" (func $internal1662))
+ (import "env" "WD" (func $internal1663))
+ (import "env" "XD" (func $internal1664))
+ (import "env" "YD" (func $internal1665))
+ (import "env" "ZD" (func $internal1666))
+ (import "env" "_D" (func $internal1667))
+ (import "env" "$D" (func $internal1668))
+ (import "env" "aE" (func $internal1669))
+ (import "env" "bE" (func $internal1670))
+ (import "env" "cE" (func $internal1671))
+ (import "env" "dE" (func $internal1672))
+ (import "env" "eE" (func $internal1673))
+ (import "env" "fE" (func $internal1674))
+ (import "env" "gE" (func $internal1675))
+ (import "env" "hE" (func $internal1676))
+ (import "env" "iE" (func $internal1677))
+ (import "env" "jE" (func $internal1678))
+ (import "env" "kE" (func $internal1679))
+ (import "env" "lE" (func $internal1680))
+ (import "env" "mE" (func $internal1681))
+ (import "env" "nE" (func $internal1682))
+ (import "env" "oE" (func $internal1683))
+ (import "env" "pE" (func $internal1684))
+ (import "env" "qE" (func $internal1685))
+ (import "env" "rE" (func $internal1686))
+ (import "env" "sE" (func $internal1687))
+ (import "env" "tE" (func $internal1688))
+ (import "env" "uE" (func $internal1689))
+ (import "env" "vE" (func $internal1690))
+ (import "env" "wE" (func $internal1691))
+ (import "env" "xE" (func $internal1692))
+ (import "env" "yE" (func $internal1693))
+ (import "env" "zE" (func $internal1694))
+ (import "env" "AE" (func $internal1695))
+ (import "env" "BE" (func $internal1696))
+ (import "env" "CE" (func $internal1697))
+ (import "env" "DE" (func $internal1698))
+ (import "env" "EE" (func $internal1699))
+ (import "env" "FE" (func $internal1700))
+ (import "env" "GE" (func $internal1701))
+ (import "env" "HE" (func $internal1702))
+ (import "env" "IE" (func $internal1703))
+ (import "env" "JE" (func $internal1704))
+ (import "env" "KE" (func $internal1705))
+ (import "env" "LE" (func $internal1706))
+ (import "env" "ME" (func $internal1707))
+ (import "env" "NE" (func $internal1708))
+ (import "env" "OE" (func $internal1709))
+ (import "env" "PE" (func $internal1710))
+ (import "env" "QE" (func $internal1711))
+ (import "env" "RE" (func $internal1712))
+ (import "env" "SE" (func $internal1713))
+ (import "env" "TE" (func $internal1714))
+ (import "env" "UE" (func $internal1715))
+ (import "env" "VE" (func $internal1716))
+ (import "env" "WE" (func $internal1717))
+ (import "env" "XE" (func $internal1718))
+ (import "env" "YE" (func $internal1719))
+ (import "env" "ZE" (func $internal1720))
+ (import "env" "_E" (func $internal1721))
+ (import "env" "$E" (func $internal1722))
+ (import "env" "aF" (func $internal1723))
+ (import "env" "bF" (func $internal1724))
+ (import "env" "cF" (func $internal1725))
+ (import "env" "dF" (func $internal1726))
+ (import "env" "eF" (func $internal1727))
+ (import "env" "fF" (func $internal1728))
+ (import "env" "gF" (func $internal1729))
+ (import "env" "hF" (func $internal1730))
+ (import "env" "iF" (func $internal1731))
+ (import "env" "jF" (func $internal1732))
+ (import "env" "kF" (func $internal1733))
+ (import "env" "lF" (func $internal1734))
+ (import "env" "mF" (func $internal1735))
+ (import "env" "nF" (func $internal1736))
+ (import "env" "oF" (func $internal1737))
+ (import "env" "pF" (func $internal1738))
+ (import "env" "qF" (func $internal1739))
+ (import "env" "rF" (func $internal1740))
+ (import "env" "sF" (func $internal1741))
+ (import "env" "tF" (func $internal1742))
+ (import "env" "uF" (func $internal1743))
+ (import "env" "vF" (func $internal1744))
+ (import "env" "wF" (func $internal1745))
+ (import "env" "xF" (func $internal1746))
+ (import "env" "yF" (func $internal1747))
+ (import "env" "zF" (func $internal1748))
+ (import "env" "AF" (func $internal1749))
+ (import "env" "BF" (func $internal1750))
+ (import "env" "CF" (func $internal1751))
+ (import "env" "DF" (func $internal1752))
+ (import "env" "EF" (func $internal1753))
+ (import "env" "FF" (func $internal1754))
+ (import "env" "GF" (func $internal1755))
+ (import "env" "HF" (func $internal1756))
+ (import "env" "IF" (func $internal1757))
+ (import "env" "JF" (func $internal1758))
+ (import "env" "KF" (func $internal1759))
+ (import "env" "LF" (func $internal1760))
+ (import "env" "MF" (func $internal1761))
+ (import "env" "NF" (func $internal1762))
+ (import "env" "OF" (func $internal1763))
+ (import "env" "PF" (func $internal1764))
+ (import "env" "QF" (func $internal1765))
+ (import "env" "RF" (func $internal1766))
+ (import "env" "SF" (func $internal1767))
+ (import "env" "TF" (func $internal1768))
+ (import "env" "UF" (func $internal1769))
+ (import "env" "VF" (func $internal1770))
+ (import "env" "WF" (func $internal1771))
+ (import "env" "XF" (func $internal1772))
+ (import "env" "YF" (func $internal1773))
+ (import "env" "ZF" (func $internal1774))
+ (import "env" "_F" (func $internal1775))
+ (import "env" "$F" (func $internal1776))
+ (import "env" "aG" (func $internal1777))
+ (import "env" "bG" (func $internal1778))
+ (import "env" "cG" (func $internal1779))
+ (import "env" "dG" (func $internal1780))
+ (import "env" "eG" (func $internal1781))
+ (import "env" "fG" (func $internal1782))
+ (import "env" "gG" (func $internal1783))
+ (import "env" "hG" (func $internal1784))
+ (import "env" "iG" (func $internal1785))
+ (import "env" "jG" (func $internal1786))
+ (import "env" "kG" (func $internal1787))
+ (import "env" "lG" (func $internal1788))
+ (import "env" "mG" (func $internal1789))
+ (import "env" "nG" (func $internal1790))
+ (import "env" "oG" (func $internal1791))
+ (import "env" "pG" (func $internal1792))
+ (import "env" "qG" (func $internal1793))
+ (import "env" "rG" (func $internal1794))
+ (import "env" "sG" (func $internal1795))
+ (import "env" "tG" (func $internal1796))
+ (import "env" "uG" (func $internal1797))
+ (import "env" "vG" (func $internal1798))
+ (import "env" "wG" (func $internal1799))
+ (import "env" "xG" (func $internal1800))
+ (import "env" "yG" (func $internal1801))
+ (import "env" "zG" (func $internal1802))
+ (import "env" "AG" (func $internal1803))
+ (import "env" "BG" (func $internal1804))
+ (import "env" "CG" (func $internal1805))
+ (import "env" "DG" (func $internal1806))
+ (import "env" "EG" (func $internal1807))
+ (import "env" "FG" (func $internal1808))
+ (import "env" "GG" (func $internal1809))
+ (import "env" "HG" (func $internal1810))
+ (import "env" "IG" (func $internal1811))
+ (import "env" "JG" (func $internal1812))
+ (import "env" "KG" (func $internal1813))
+ (import "env" "LG" (func $internal1814))
+ (import "env" "MG" (func $internal1815))
+ (import "env" "NG" (func $internal1816))
+ (import "env" "OG" (func $internal1817))
+ (import "env" "PG" (func $internal1818))
+ (import "env" "QG" (func $internal1819))
+ (import "env" "RG" (func $internal1820))
+ (import "env" "SG" (func $internal1821))
+ (import "env" "TG" (func $internal1822))
+ (import "env" "UG" (func $internal1823))
+ (import "env" "VG" (func $internal1824))
+ (import "env" "WG" (func $internal1825))
+ (import "env" "XG" (func $internal1826))
+ (import "env" "YG" (func $internal1827))
+ (import "env" "ZG" (func $internal1828))
+ (import "env" "_G" (func $internal1829))
+ (import "env" "$G" (func $internal1830))
+ (import "env" "aH" (func $internal1831))
+ (import "env" "bH" (func $internal1832))
+ (import "env" "cH" (func $internal1833))
+ (import "env" "dH" (func $internal1834))
+ (import "env" "eH" (func $internal1835))
+ (import "env" "fH" (func $internal1836))
+ (import "env" "gH" (func $internal1837))
+ (import "env" "hH" (func $internal1838))
+ (import "env" "iH" (func $internal1839))
+ (import "env" "jH" (func $internal1840))
+ (import "env" "kH" (func $internal1841))
+ (import "env" "lH" (func $internal1842))
+ (import "env" "mH" (func $internal1843))
+ (import "env" "nH" (func $internal1844))
+ (import "env" "oH" (func $internal1845))
+ (import "env" "pH" (func $internal1846))
+ (import "env" "qH" (func $internal1847))
+ (import "env" "rH" (func $internal1848))
+ (import "env" "sH" (func $internal1849))
+ (import "env" "tH" (func $internal1850))
+ (import "env" "uH" (func $internal1851))
+ (import "env" "vH" (func $internal1852))
+ (import "env" "wH" (func $internal1853))
+ (import "env" "xH" (func $internal1854))
+ (import "env" "yH" (func $internal1855))
+ (import "env" "zH" (func $internal1856))
+ (import "env" "AH" (func $internal1857))
+ (import "env" "BH" (func $internal1858))
+ (import "env" "CH" (func $internal1859))
+ (import "env" "DH" (func $internal1860))
+ (import "env" "EH" (func $internal1861))
+ (import "env" "FH" (func $internal1862))
+ (import "env" "GH" (func $internal1863))
+ (import "env" "HH" (func $internal1864))
+ (import "env" "IH" (func $internal1865))
+ (import "env" "JH" (func $internal1866))
+ (import "env" "KH" (func $internal1867))
+ (import "env" "LH" (func $internal1868))
+ (import "env" "MH" (func $internal1869))
+ (import "env" "NH" (func $internal1870))
+ (import "env" "OH" (func $internal1871))
+ (import "env" "PH" (func $internal1872))
+ (import "env" "QH" (func $internal1873))
+ (import "env" "RH" (func $internal1874))
+ (import "env" "SH" (func $internal1875))
+ (import "env" "TH" (func $internal1876))
+ (import "env" "UH" (func $internal1877))
+ (import "env" "VH" (func $internal1878))
+ (import "env" "WH" (func $internal1879))
+ (import "env" "XH" (func $internal1880))
+ (import "env" "YH" (func $internal1881))
+ (import "env" "ZH" (func $internal1882))
+ (import "env" "_H" (func $internal1883))
+ (import "env" "$H" (func $internal1884))
+ (import "env" "aI" (func $internal1885))
+ (import "env" "bI" (func $internal1886))
+ (import "env" "cI" (func $internal1887))
+ (import "env" "dI" (func $internal1888))
+ (import "env" "eI" (func $internal1889))
+ (import "env" "fI" (func $internal1890))
+ (import "env" "gI" (func $internal1891))
+ (import "env" "hI" (func $internal1892))
+ (import "env" "iI" (func $internal1893))
+ (import "env" "jI" (func $internal1894))
+ (import "env" "kI" (func $internal1895))
+ (import "env" "lI" (func $internal1896))
+ (import "env" "mI" (func $internal1897))
+ (import "env" "nI" (func $internal1898))
+ (import "env" "oI" (func $internal1899))
+ (import "env" "pI" (func $internal1900))
+ (import "env" "qI" (func $internal1901))
+ (import "env" "rI" (func $internal1902))
+ (import "env" "sI" (func $internal1903))
+ (import "env" "tI" (func $internal1904))
+ (import "env" "uI" (func $internal1905))
+ (import "env" "vI" (func $internal1906))
+ (import "env" "wI" (func $internal1907))
+ (import "env" "xI" (func $internal1908))
+ (import "env" "yI" (func $internal1909))
+ (import "env" "zI" (func $internal1910))
+ (import "env" "AI" (func $internal1911))
+ (import "env" "BI" (func $internal1912))
+ (import "env" "CI" (func $internal1913))
+ (import "env" "DI" (func $internal1914))
+ (import "env" "EI" (func $internal1915))
+ (import "env" "FI" (func $internal1916))
+ (import "env" "GI" (func $internal1917))
+ (import "env" "HI" (func $internal1918))
+ (import "env" "II" (func $internal1919))
+ (import "env" "JI" (func $internal1920))
+ (import "env" "KI" (func $internal1921))
+ (import "env" "LI" (func $internal1922))
+ (import "env" "MI" (func $internal1923))
+ (import "env" "NI" (func $internal1924))
+ (import "env" "OI" (func $internal1925))
+ (import "env" "PI" (func $internal1926))
+ (import "env" "QI" (func $internal1927))
+ (import "env" "RI" (func $internal1928))
+ (import "env" "SI" (func $internal1929))
+ (import "env" "TI" (func $internal1930))
+ (import "env" "UI" (func $internal1931))
+ (import "env" "VI" (func $internal1932))
+ (import "env" "WI" (func $internal1933))
+ (import "env" "XI" (func $internal1934))
+ (import "env" "YI" (func $internal1935))
+ (import "env" "ZI" (func $internal1936))
+ (import "env" "_I" (func $internal1937))
+ (import "env" "$I" (func $internal1938))
+ (import "env" "aJ" (func $internal1939))
+ (import "env" "bJ" (func $internal1940))
+ (import "env" "cJ" (func $internal1941))
+ (import "env" "dJ" (func $internal1942))
+ (import "env" "eJ" (func $internal1943))
+ (import "env" "fJ" (func $internal1944))
+ (import "env" "gJ" (func $internal1945))
+ (import "env" "hJ" (func $internal1946))
+ (import "env" "iJ" (func $internal1947))
+ (import "env" "jJ" (func $internal1948))
+ (import "env" "kJ" (func $internal1949))
+ (import "env" "lJ" (func $internal1950))
+ (import "env" "mJ" (func $internal1951))
+ (import "env" "nJ" (func $internal1952))
+ (import "env" "oJ" (func $internal1953))
+ (import "env" "pJ" (func $internal1954))
+ (import "env" "qJ" (func $internal1955))
+ (import "env" "rJ" (func $internal1956))
+ (import "env" "sJ" (func $internal1957))
+ (import "env" "tJ" (func $internal1958))
+ (import "env" "uJ" (func $internal1959))
+ (import "env" "vJ" (func $internal1960))
+ (import "env" "wJ" (func $internal1961))
+ (import "env" "xJ" (func $internal1962))
+ (import "env" "yJ" (func $internal1963))
+ (import "env" "zJ" (func $internal1964))
+ (import "env" "AJ" (func $internal1965))
+ (import "env" "BJ" (func $internal1966))
+ (import "env" "CJ" (func $internal1967))
+ (import "env" "DJ" (func $internal1968))
+ (import "env" "EJ" (func $internal1969))
+ (import "env" "FJ" (func $internal1970))
+ (import "env" "GJ" (func $internal1971))
+ (import "env" "HJ" (func $internal1972))
+ (import "env" "IJ" (func $internal1973))
+ (import "env" "JJ" (func $internal1974))
+ (import "env" "KJ" (func $internal1975))
+ (import "env" "LJ" (func $internal1976))
+ (import "env" "MJ" (func $internal1977))
+ (import "env" "NJ" (func $internal1978))
+ (import "env" "OJ" (func $internal1979))
+ (import "env" "PJ" (func $internal1980))
+ (import "env" "QJ" (func $internal1981))
+ (import "env" "RJ" (func $internal1982))
+ (import "env" "SJ" (func $internal1983))
+ (import "env" "TJ" (func $internal1984))
+ (import "env" "UJ" (func $internal1985))
+ (import "env" "VJ" (func $internal1986))
+ (import "env" "WJ" (func $internal1987))
+ (import "env" "XJ" (func $internal1988))
+ (import "env" "YJ" (func $internal1989))
+ (import "env" "ZJ" (func $internal1990))
+ (import "env" "_J" (func $internal1991))
+ (import "env" "$J" (func $internal1992))
+ (import "env" "aK" (func $internal1993))
+ (import "env" "bK" (func $internal1994))
+ (import "env" "cK" (func $internal1995))
+ (import "env" "dK" (func $internal1996))
+ (import "env" "eK" (func $internal1997))
+ (import "env" "fK" (func $internal1998))
+ (import "env" "gK" (func $internal1999))
+ (import "env" "hK" (func $internal2000))
+ (import "env" "iK" (func $internal2001))
+ (import "env" "jK" (func $internal2002))
+ (import "env" "kK" (func $internal2003))
+ (import "env" "lK" (func $internal2004))
+ (import "env" "mK" (func $internal2005))
+ (import "env" "nK" (func $internal2006))
+ (import "env" "oK" (func $internal2007))
+ (import "env" "pK" (func $internal2008))
+ (import "env" "qK" (func $internal2009))
+ (import "env" "rK" (func $internal2010))
+ (import "env" "sK" (func $internal2011))
+ (import "env" "tK" (func $internal2012))
+ (import "env" "uK" (func $internal2013))
+ (import "env" "vK" (func $internal2014))
+ (import "env" "wK" (func $internal2015))
+ (import "env" "xK" (func $internal2016))
+ (import "env" "yK" (func $internal2017))
+ (import "env" "zK" (func $internal2018))
+ (import "env" "AK" (func $internal2019))
+ (import "env" "BK" (func $internal2020))
+ (import "env" "CK" (func $internal2021))
+ (import "env" "DK" (func $internal2022))
+ (import "env" "EK" (func $internal2023))
+ (import "env" "FK" (func $internal2024))
+ (import "env" "GK" (func $internal2025))
+ (import "env" "HK" (func $internal2026))
+ (import "env" "IK" (func $internal2027))
+ (import "env" "JK" (func $internal2028))
+ (import "env" "KK" (func $internal2029))
+ (import "env" "LK" (func $internal2030))
+ (import "env" "MK" (func $internal2031))
+ (import "env" "NK" (func $internal2032))
+ (import "env" "OK" (func $internal2033))
+ (import "env" "PK" (func $internal2034))
+ (import "env" "QK" (func $internal2035))
+ (import "env" "RK" (func $internal2036))
+ (import "env" "SK" (func $internal2037))
+ (import "env" "TK" (func $internal2038))
+ (import "env" "UK" (func $internal2039))
+ (import "env" "VK" (func $internal2040))
+ (import "env" "WK" (func $internal2041))
+ (import "env" "XK" (func $internal2042))
+ (import "env" "YK" (func $internal2043))
+ (import "env" "ZK" (func $internal2044))
+ (import "env" "_K" (func $internal2045))
+ (import "env" "$K" (func $internal2046))
+ (import "env" "aL" (func $internal2047))
+ (import "env" "bL" (func $internal2048))
+ (import "env" "cL" (func $internal2049))
+ (import "env" "dL" (func $internal2050))
+ (import "env" "eL" (func $internal2051))
+ (import "env" "fL" (func $internal2052))
+ (import "env" "gL" (func $internal2053))
+ (import "env" "hL" (func $internal2054))
+ (import "env" "iL" (func $internal2055))
+ (import "env" "jL" (func $internal2056))
+ (import "env" "kL" (func $internal2057))
+ (import "env" "lL" (func $internal2058))
+ (import "env" "mL" (func $internal2059))
+ (import "env" "nL" (func $internal2060))
+ (import "env" "oL" (func $internal2061))
+ (import "env" "pL" (func $internal2062))
+ (import "env" "qL" (func $internal2063))
+ (import "env" "rL" (func $internal2064))
+ (import "env" "sL" (func $internal2065))
+ (import "env" "tL" (func $internal2066))
+ (import "env" "uL" (func $internal2067))
+ (import "env" "vL" (func $internal2068))
+ (import "env" "wL" (func $internal2069))
+ (import "env" "xL" (func $internal2070))
+ (import "env" "yL" (func $internal2071))
+ (import "env" "zL" (func $internal2072))
+ (import "env" "AL" (func $internal2073))
+ (import "env" "BL" (func $internal2074))
+ (import "env" "CL" (func $internal2075))
+ (import "env" "DL" (func $internal2076))
+ (import "env" "EL" (func $internal2077))
+ (import "env" "FL" (func $internal2078))
+ (import "env" "GL" (func $internal2079))
+ (import "env" "HL" (func $internal2080))
+ (import "env" "IL" (func $internal2081))
+ (import "env" "JL" (func $internal2082))
+ (import "env" "KL" (func $internal2083))
+ (import "env" "LL" (func $internal2084))
+ (import "env" "ML" (func $internal2085))
+ (import "env" "NL" (func $internal2086))
+ (import "env" "OL" (func $internal2087))
+ (import "env" "PL" (func $internal2088))
+ (import "env" "QL" (func $internal2089))
+ (import "env" "RL" (func $internal2090))
+ (import "env" "SL" (func $internal2091))
+ (import "env" "TL" (func $internal2092))
+ (import "env" "UL" (func $internal2093))
+ (import "env" "VL" (func $internal2094))
+ (import "env" "WL" (func $internal2095))
+ (import "env" "XL" (func $internal2096))
+ (import "env" "YL" (func $internal2097))
+ (import "env" "ZL" (func $internal2098))
+ (import "env" "_L" (func $internal2099))
+ (import "env" "$L" (func $internal2100))
+ (import "env" "aM" (func $internal2101))
+ (import "env" "bM" (func $internal2102))
+ (import "env" "cM" (func $internal2103))
+ (import "env" "dM" (func $internal2104))
+ (import "env" "eM" (func $internal2105))
+ (import "env" "fM" (func $internal2106))
+ (import "env" "gM" (func $internal2107))
+ (import "env" "hM" (func $internal2108))
+ (import "env" "iM" (func $internal2109))
+ (import "env" "jM" (func $internal2110))
+ (import "env" "kM" (func $internal2111))
+ (import "env" "lM" (func $internal2112))
+ (import "env" "mM" (func $internal2113))
+ (import "env" "nM" (func $internal2114))
+ (import "env" "oM" (func $internal2115))
+ (import "env" "pM" (func $internal2116))
+ (import "env" "qM" (func $internal2117))
+ (import "env" "rM" (func $internal2118))
+ (import "env" "sM" (func $internal2119))
+ (import "env" "tM" (func $internal2120))
+ (import "env" "uM" (func $internal2121))
+ (import "env" "vM" (func $internal2122))
+ (import "env" "wM" (func $internal2123))
+ (import "env" "xM" (func $internal2124))
+ (import "env" "yM" (func $internal2125))
+ (import "env" "zM" (func $internal2126))
+ (import "env" "AM" (func $internal2127))
+ (import "env" "BM" (func $internal2128))
+ (import "env" "CM" (func $internal2129))
+ (import "env" "DM" (func $internal2130))
+ (import "env" "EM" (func $internal2131))
+ (import "env" "FM" (func $internal2132))
+ (import "env" "GM" (func $internal2133))
+ (import "env" "HM" (func $internal2134))
+ (import "env" "IM" (func $internal2135))
+ (import "env" "JM" (func $internal2136))
+ (import "env" "KM" (func $internal2137))
+ (import "env" "LM" (func $internal2138))
+ (import "env" "MM" (func $internal2139))
+ (import "env" "NM" (func $internal2140))
+ (import "env" "OM" (func $internal2141))
+ (import "env" "PM" (func $internal2142))
+ (import "env" "QM" (func $internal2143))
+ (import "env" "RM" (func $internal2144))
+ (import "env" "SM" (func $internal2145))
+ (import "env" "TM" (func $internal2146))
+ (import "env" "UM" (func $internal2147))
+ (import "env" "VM" (func $internal2148))
+ (import "env" "WM" (func $internal2149))
+ (import "env" "XM" (func $internal2150))
+ (import "env" "YM" (func $internal2151))
+ (import "env" "ZM" (func $internal2152))
+ (import "env" "_M" (func $internal2153))
+ (import "env" "$M" (func $internal2154))
+ (import "env" "aN" (func $internal2155))
+ (import "env" "bN" (func $internal2156))
+ (import "env" "cN" (func $internal2157))
+ (import "env" "dN" (func $internal2158))
+ (import "env" "eN" (func $internal2159))
+ (import "env" "fN" (func $internal2160))
+ (import "env" "gN" (func $internal2161))
+ (import "env" "hN" (func $internal2162))
+ (import "env" "iN" (func $internal2163))
+ (import "env" "jN" (func $internal2164))
+ (import "env" "kN" (func $internal2165))
+ (import "env" "lN" (func $internal2166))
+ (import "env" "mN" (func $internal2167))
+ (import "env" "nN" (func $internal2168))
+ (import "env" "oN" (func $internal2169))
+ (import "env" "pN" (func $internal2170))
+ (import "env" "qN" (func $internal2171))
+ (import "env" "rN" (func $internal2172))
+ (import "env" "sN" (func $internal2173))
+ (import "env" "tN" (func $internal2174))
+ (import "env" "uN" (func $internal2175))
+ (import "env" "vN" (func $internal2176))
+ (import "env" "wN" (func $internal2177))
+ (import "env" "xN" (func $internal2178))
+ (import "env" "yN" (func $internal2179))
+ (import "env" "zN" (func $internal2180))
+ (import "env" "AN" (func $internal2181))
+ (import "env" "BN" (func $internal2182))
+ (import "env" "CN" (func $internal2183))
+ (import "env" "DN" (func $internal2184))
+ (import "env" "EN" (func $internal2185))
+ (import "env" "FN" (func $internal2186))
+ (import "env" "GN" (func $internal2187))
+ (import "env" "HN" (func $internal2188))
+ (import "env" "IN" (func $internal2189))
+ (import "env" "JN" (func $internal2190))
+ (import "env" "KN" (func $internal2191))
+ (import "env" "LN" (func $internal2192))
+ (import "env" "MN" (func $internal2193))
+ (import "env" "NN" (func $internal2194))
+ (import "env" "ON" (func $internal2195))
+ (import "env" "PN" (func $internal2196))
+ (import "env" "QN" (func $internal2197))
+ (import "env" "RN" (func $internal2198))
+ (import "env" "SN" (func $internal2199))
+ (import "env" "TN" (func $internal2200))
+ (import "env" "UN" (func $internal2201))
+ (import "env" "VN" (func $internal2202))
+ (import "env" "WN" (func $internal2203))
+ (import "env" "XN" (func $internal2204))
+ (import "env" "YN" (func $internal2205))
+ (import "env" "ZN" (func $internal2206))
+ (import "env" "_N" (func $internal2207))
+ (import "env" "$N" (func $internal2208))
+ (import "env" "aO" (func $internal2209))
+ (import "env" "bO" (func $internal2210))
+ (import "env" "cO" (func $internal2211))
+ (import "env" "dO" (func $internal2212))
+ (import "env" "eO" (func $internal2213))
+ (import "env" "fO" (func $internal2214))
+ (import "env" "gO" (func $internal2215))
+ (import "env" "hO" (func $internal2216))
+ (import "env" "iO" (func $internal2217))
+ (import "env" "jO" (func $internal2218))
+ (import "env" "kO" (func $internal2219))
+ (import "env" "lO" (func $internal2220))
+ (import "env" "mO" (func $internal2221))
+ (import "env" "nO" (func $internal2222))
+ (import "env" "oO" (func $internal2223))
+ (import "env" "pO" (func $internal2224))
+ (import "env" "qO" (func $internal2225))
+ (import "env" "rO" (func $internal2226))
+ (import "env" "sO" (func $internal2227))
+ (import "env" "tO" (func $internal2228))
+ (import "env" "uO" (func $internal2229))
+ (import "env" "vO" (func $internal2230))
+ (import "env" "wO" (func $internal2231))
+ (import "env" "xO" (func $internal2232))
+ (import "env" "yO" (func $internal2233))
+ (import "env" "zO" (func $internal2234))
+ (import "env" "AO" (func $internal2235))
+ (import "env" "BO" (func $internal2236))
+ (import "env" "CO" (func $internal2237))
+ (import "env" "DO" (func $internal2238))
+ (import "env" "EO" (func $internal2239))
+ (import "env" "FO" (func $internal2240))
+ (import "env" "GO" (func $internal2241))
+ (import "env" "HO" (func $internal2242))
+ (import "env" "IO" (func $internal2243))
+ (import "env" "JO" (func $internal2244))
+ (import "env" "KO" (func $internal2245))
+ (import "env" "LO" (func $internal2246))
+ (import "env" "MO" (func $internal2247))
+ (import "env" "NO" (func $internal2248))
+ (import "env" "OO" (func $internal2249))
+ (import "env" "PO" (func $internal2250))
+ (import "env" "QO" (func $internal2251))
+ (import "env" "RO" (func $internal2252))
+ (import "env" "SO" (func $internal2253))
+ (import "env" "TO" (func $internal2254))
+ (import "env" "UO" (func $internal2255))
+ (import "env" "VO" (func $internal2256))
+ (import "env" "WO" (func $internal2257))
+ (import "env" "XO" (func $internal2258))
+ (import "env" "YO" (func $internal2259))
+ (import "env" "ZO" (func $internal2260))
+ (import "env" "_O" (func $internal2261))
+ (import "env" "$O" (func $internal2262))
+ (import "env" "aP" (func $internal2263))
+ (import "env" "bP" (func $internal2264))
+ (import "env" "cP" (func $internal2265))
+ (import "env" "dP" (func $internal2266))
+ (import "env" "eP" (func $internal2267))
+ (import "env" "fP" (func $internal2268))
+ (import "env" "gP" (func $internal2269))
+ (import "env" "hP" (func $internal2270))
+ (import "env" "iP" (func $internal2271))
+ (import "env" "jP" (func $internal2272))
+ (import "env" "kP" (func $internal2273))
+ (import "env" "lP" (func $internal2274))
+ (import "env" "mP" (func $internal2275))
+ (import "env" "nP" (func $internal2276))
+ (import "env" "oP" (func $internal2277))
+ (import "env" "pP" (func $internal2278))
+ (import "env" "qP" (func $internal2279))
+ (import "env" "rP" (func $internal2280))
+ (import "env" "sP" (func $internal2281))
+ (import "env" "tP" (func $internal2282))
+ (import "env" "uP" (func $internal2283))
+ (import "env" "vP" (func $internal2284))
+ (import "env" "wP" (func $internal2285))
+ (import "env" "xP" (func $internal2286))
+ (import "env" "yP" (func $internal2287))
+ (import "env" "zP" (func $internal2288))
+ (import "env" "AP" (func $internal2289))
+ (import "env" "BP" (func $internal2290))
+ (import "env" "CP" (func $internal2291))
+ (import "env" "DP" (func $internal2292))
+ (import "env" "EP" (func $internal2293))
+ (import "env" "FP" (func $internal2294))
+ (import "env" "GP" (func $internal2295))
+ (import "env" "HP" (func $internal2296))
+ (import "env" "IP" (func $internal2297))
+ (import "env" "JP" (func $internal2298))
+ (import "env" "KP" (func $internal2299))
+ (import "env" "LP" (func $internal2300))
+ (import "env" "MP" (func $internal2301))
+ (import "env" "NP" (func $internal2302))
+ (import "env" "OP" (func $internal2303))
+ (import "env" "PP" (func $internal2304))
+ (import "env" "QP" (func $internal2305))
+ (import "env" "RP" (func $internal2306))
+ (import "env" "SP" (func $internal2307))
+ (import "env" "TP" (func $internal2308))
+ (import "env" "UP" (func $internal2309))
+ (import "env" "VP" (func $internal2310))
+ (import "env" "WP" (func $internal2311))
+ (import "env" "XP" (func $internal2312))
+ (import "env" "YP" (func $internal2313))
+ (import "env" "ZP" (func $internal2314))
+ (import "env" "_P" (func $internal2315))
+ (import "env" "$P" (func $internal2316))
+ (import "env" "aQ" (func $internal2317))
+ (import "env" "bQ" (func $internal2318))
+ (import "env" "cQ" (func $internal2319))
+ (import "env" "dQ" (func $internal2320))
+ (import "env" "eQ" (func $internal2321))
+ (import "env" "fQ" (func $internal2322))
+ (import "env" "gQ" (func $internal2323))
+ (import "env" "hQ" (func $internal2324))
+ (import "env" "iQ" (func $internal2325))
+ (import "env" "jQ" (func $internal2326))
+ (import "env" "kQ" (func $internal2327))
+ (import "env" "lQ" (func $internal2328))
+ (import "env" "mQ" (func $internal2329))
+ (import "env" "nQ" (func $internal2330))
+ (import "env" "oQ" (func $internal2331))
+ (import "env" "pQ" (func $internal2332))
+ (import "env" "qQ" (func $internal2333))
+ (import "env" "rQ" (func $internal2334))
+ (import "env" "sQ" (func $internal2335))
+ (import "env" "tQ" (func $internal2336))
+ (import "env" "uQ" (func $internal2337))
+ (import "env" "vQ" (func $internal2338))
+ (import "env" "wQ" (func $internal2339))
+ (import "env" "xQ" (func $internal2340))
+ (import "env" "yQ" (func $internal2341))
+ (import "env" "zQ" (func $internal2342))
+ (import "env" "AQ" (func $internal2343))
+ (import "env" "BQ" (func $internal2344))
+ (import "env" "CQ" (func $internal2345))
+ (import "env" "DQ" (func $internal2346))
+ (import "env" "EQ" (func $internal2347))
+ (import "env" "FQ" (func $internal2348))
+ (import "env" "GQ" (func $internal2349))
+ (import "env" "HQ" (func $internal2350))
+ (import "env" "IQ" (func $internal2351))
+ (import "env" "JQ" (func $internal2352))
+ (import "env" "KQ" (func $internal2353))
+ (import "env" "LQ" (func $internal2354))
+ (import "env" "MQ" (func $internal2355))
+ (import "env" "NQ" (func $internal2356))
+ (import "env" "OQ" (func $internal2357))
+ (import "env" "PQ" (func $internal2358))
+ (import "env" "QQ" (func $internal2359))
+ (import "env" "RQ" (func $internal2360))
+ (import "env" "SQ" (func $internal2361))
+ (import "env" "TQ" (func $internal2362))
+ (import "env" "UQ" (func $internal2363))
+ (import "env" "VQ" (func $internal2364))
+ (import "env" "WQ" (func $internal2365))
+ (import "env" "XQ" (func $internal2366))
+ (import "env" "YQ" (func $internal2367))
+ (import "env" "ZQ" (func $internal2368))
+ (import "env" "_Q" (func $internal2369))
+ (import "env" "$Q" (func $internal2370))
+ (import "env" "aR" (func $internal2371))
+ (import "env" "bR" (func $internal2372))
+ (import "env" "cR" (func $internal2373))
+ (import "env" "dR" (func $internal2374))
+ (import "env" "eR" (func $internal2375))
+ (import "env" "fR" (func $internal2376))
+ (import "env" "gR" (func $internal2377))
+ (import "env" "hR" (func $internal2378))
+ (import "env" "iR" (func $internal2379))
+ (import "env" "jR" (func $internal2380))
+ (import "env" "kR" (func $internal2381))
+ (import "env" "lR" (func $internal2382))
+ (import "env" "mR" (func $internal2383))
+ (import "env" "nR" (func $internal2384))
+ (import "env" "oR" (func $internal2385))
+ (import "env" "pR" (func $internal2386))
+ (import "env" "qR" (func $internal2387))
+ (import "env" "rR" (func $internal2388))
+ (import "env" "sR" (func $internal2389))
+ (import "env" "tR" (func $internal2390))
+ (import "env" "uR" (func $internal2391))
+ (import "env" "vR" (func $internal2392))
+ (import "env" "wR" (func $internal2393))
+ (import "env" "xR" (func $internal2394))
+ (import "env" "yR" (func $internal2395))
+ (import "env" "zR" (func $internal2396))
+ (import "env" "AR" (func $internal2397))
+ (import "env" "BR" (func $internal2398))
+ (import "env" "CR" (func $internal2399))
+ (import "env" "DR" (func $internal2400))
+ (import "env" "ER" (func $internal2401))
+ (import "env" "FR" (func $internal2402))
+ (import "env" "GR" (func $internal2403))
+ (import "env" "HR" (func $internal2404))
+ (import "env" "IR" (func $internal2405))
+ (import "env" "JR" (func $internal2406))
+ (import "env" "KR" (func $internal2407))
+ (import "env" "LR" (func $internal2408))
+ (import "env" "MR" (func $internal2409))
+ (import "env" "NR" (func $internal2410))
+ (import "env" "OR" (func $internal2411))
+ (import "env" "PR" (func $internal2412))
+ (import "env" "QR" (func $internal2413))
+ (import "env" "RR" (func $internal2414))
+ (import "env" "SR" (func $internal2415))
+ (import "env" "TR" (func $internal2416))
+ (import "env" "UR" (func $internal2417))
+ (import "env" "VR" (func $internal2418))
+ (import "env" "WR" (func $internal2419))
+ (import "env" "XR" (func $internal2420))
+ (import "env" "YR" (func $internal2421))
+ (import "env" "ZR" (func $internal2422))
+ (import "env" "_R" (func $internal2423))
+ (import "env" "$R" (func $internal2424))
+ (import "env" "aS" (func $internal2425))
+ (import "env" "bS" (func $internal2426))
+ (import "env" "cS" (func $internal2427))
+ (import "env" "dS" (func $internal2428))
+ (import "env" "eS" (func $internal2429))
+ (import "env" "fS" (func $internal2430))
+ (import "env" "gS" (func $internal2431))
+ (import "env" "hS" (func $internal2432))
+ (import "env" "iS" (func $internal2433))
+ (import "env" "jS" (func $internal2434))
+ (import "env" "kS" (func $internal2435))
+ (import "env" "lS" (func $internal2436))
+ (import "env" "mS" (func $internal2437))
+ (import "env" "nS" (func $internal2438))
+ (import "env" "oS" (func $internal2439))
+ (import "env" "pS" (func $internal2440))
+ (import "env" "qS" (func $internal2441))
+ (import "env" "rS" (func $internal2442))
+ (import "env" "sS" (func $internal2443))
+ (import "env" "tS" (func $internal2444))
+ (import "env" "uS" (func $internal2445))
+ (import "env" "vS" (func $internal2446))
+ (import "env" "wS" (func $internal2447))
+ (import "env" "xS" (func $internal2448))
+ (import "env" "yS" (func $internal2449))
+ (import "env" "zS" (func $internal2450))
+ (import "env" "AS" (func $internal2451))
+ (import "env" "BS" (func $internal2452))
+ (import "env" "CS" (func $internal2453))
+ (import "env" "DS" (func $internal2454))
+ (import "env" "ES" (func $internal2455))
+ (import "env" "FS" (func $internal2456))
+ (import "env" "GS" (func $internal2457))
+ (import "env" "HS" (func $internal2458))
+ (import "env" "IS" (func $internal2459))
+ (import "env" "JS" (func $internal2460))
+ (import "env" "KS" (func $internal2461))
+ (import "env" "LS" (func $internal2462))
+ (import "env" "MS" (func $internal2463))
+ (import "env" "NS" (func $internal2464))
+ (import "env" "OS" (func $internal2465))
+ (import "env" "PS" (func $internal2466))
+ (import "env" "QS" (func $internal2467))
+ (import "env" "RS" (func $internal2468))
+ (import "env" "SS" (func $internal2469))
+ (import "env" "TS" (func $internal2470))
+ (import "env" "US" (func $internal2471))
+ (import "env" "VS" (func $internal2472))
+ (import "env" "WS" (func $internal2473))
+ (import "env" "XS" (func $internal2474))
+ (import "env" "YS" (func $internal2475))
+ (import "env" "ZS" (func $internal2476))
+ (import "env" "_S" (func $internal2477))
+ (import "env" "$S" (func $internal2478))
+ (import "env" "aT" (func $internal2479))
+ (import "env" "bT" (func $internal2480))
+ (import "env" "cT" (func $internal2481))
+ (import "env" "dT" (func $internal2482))
+ (import "env" "eT" (func $internal2483))
+ (import "env" "fT" (func $internal2484))
+ (import "env" "gT" (func $internal2485))
+ (import "env" "hT" (func $internal2486))
+ (import "env" "iT" (func $internal2487))
+ (import "env" "jT" (func $internal2488))
+ (import "env" "kT" (func $internal2489))
+ (import "env" "lT" (func $internal2490))
+ (import "env" "mT" (func $internal2491))
+ (import "env" "nT" (func $internal2492))
+ (import "env" "oT" (func $internal2493))
+ (import "env" "pT" (func $internal2494))
+ (import "env" "qT" (func $internal2495))
+ (import "env" "rT" (func $internal2496))
+ (import "env" "sT" (func $internal2497))
+ (import "env" "tT" (func $internal2498))
+ (import "env" "uT" (func $internal2499))
+ (import "env" "vT" (func $internal2500))
+ (import "env" "wT" (func $internal2501))
+ (import "env" "xT" (func $internal2502))
+ (import "env" "yT" (func $internal2503))
+ (import "env" "zT" (func $internal2504))
+ (import "env" "AT" (func $internal2505))
+ (import "env" "BT" (func $internal2506))
+ (import "env" "CT" (func $internal2507))
+ (import "env" "DT" (func $internal2508))
+ (import "env" "ET" (func $internal2509))
+ (import "env" "FT" (func $internal2510))
+ (import "env" "GT" (func $internal2511))
+ (import "env" "HT" (func $internal2512))
+ (import "env" "IT" (func $internal2513))
+ (import "env" "JT" (func $internal2514))
+ (import "env" "KT" (func $internal2515))
+ (import "env" "LT" (func $internal2516))
+ (import "env" "MT" (func $internal2517))
+ (import "env" "NT" (func $internal2518))
+ (import "env" "OT" (func $internal2519))
+ (import "env" "PT" (func $internal2520))
+ (import "env" "QT" (func $internal2521))
+ (import "env" "RT" (func $internal2522))
+ (import "env" "ST" (func $internal2523))
+ (import "env" "TT" (func $internal2524))
+ (import "env" "UT" (func $internal2525))
+ (import "env" "VT" (func $internal2526))
+ (import "env" "WT" (func $internal2527))
+ (import "env" "XT" (func $internal2528))
+ (import "env" "YT" (func $internal2529))
+ (import "env" "ZT" (func $internal2530))
+ (import "env" "_T" (func $internal2531))
+ (import "env" "$T" (func $internal2532))
+ (import "env" "aU" (func $internal2533))
+ (import "env" "bU" (func $internal2534))
+ (import "env" "cU" (func $internal2535))
+ (import "env" "dU" (func $internal2536))
+ (import "env" "eU" (func $internal2537))
+ (import "env" "fU" (func $internal2538))
+ (import "env" "gU" (func $internal2539))
+ (import "env" "hU" (func $internal2540))
+ (import "env" "iU" (func $internal2541))
+ (import "env" "jU" (func $internal2542))
+ (import "env" "kU" (func $internal2543))
+ (import "env" "lU" (func $internal2544))
+ (import "env" "mU" (func $internal2545))
+ (import "env" "nU" (func $internal2546))
+ (import "env" "oU" (func $internal2547))
+ (import "env" "pU" (func $internal2548))
+ (import "env" "qU" (func $internal2549))
+ (import "env" "rU" (func $internal2550))
+ (import "env" "sU" (func $internal2551))
+ (import "env" "tU" (func $internal2552))
+ (import "env" "uU" (func $internal2553))
+ (import "env" "vU" (func $internal2554))
+ (import "env" "wU" (func $internal2555))
+ (import "env" "xU" (func $internal2556))
+ (import "env" "yU" (func $internal2557))
+ (import "env" "zU" (func $internal2558))
+ (import "env" "AU" (func $internal2559))
+ (import "env" "BU" (func $internal2560))
+ (import "env" "CU" (func $internal2561))
+ (import "env" "DU" (func $internal2562))
+ (import "env" "EU" (func $internal2563))
+ (import "env" "FU" (func $internal2564))
+ (import "env" "GU" (func $internal2565))
+ (import "env" "HU" (func $internal2566))
+ (import "env" "IU" (func $internal2567))
+ (import "env" "JU" (func $internal2568))
+ (import "env" "KU" (func $internal2569))
+ (import "env" "LU" (func $internal2570))
+ (import "env" "MU" (func $internal2571))
+ (import "env" "NU" (func $internal2572))
+ (import "env" "OU" (func $internal2573))
+ (import "env" "PU" (func $internal2574))
+ (import "env" "QU" (func $internal2575))
+ (import "env" "RU" (func $internal2576))
+ (import "env" "SU" (func $internal2577))
+ (import "env" "TU" (func $internal2578))
+ (import "env" "UU" (func $internal2579))
+ (import "env" "VU" (func $internal2580))
+ (import "env" "WU" (func $internal2581))
+ (import "env" "XU" (func $internal2582))
+ (import "env" "YU" (func $internal2583))
+ (import "env" "ZU" (func $internal2584))
+ (import "env" "_U" (func $internal2585))
+ (import "env" "$U" (func $internal2586))
+ (import "env" "aV" (func $internal2587))
+ (import "env" "bV" (func $internal2588))
+ (import "env" "cV" (func $internal2589))
+ (import "env" "dV" (func $internal2590))
+ (import "env" "eV" (func $internal2591))
+ (import "env" "fV" (func $internal2592))
+ (import "env" "gV" (func $internal2593))
+ (import "env" "hV" (func $internal2594))
+ (import "env" "iV" (func $internal2595))
+ (import "env" "jV" (func $internal2596))
+ (import "env" "kV" (func $internal2597))
+ (import "env" "lV" (func $internal2598))
+ (import "env" "mV" (func $internal2599))
+ (import "env" "nV" (func $internal2600))
+ (import "env" "oV" (func $internal2601))
+ (import "env" "pV" (func $internal2602))
+ (import "env" "qV" (func $internal2603))
+ (import "env" "rV" (func $internal2604))
+ (import "env" "sV" (func $internal2605))
+ (import "env" "tV" (func $internal2606))
+ (import "env" "uV" (func $internal2607))
+ (import "env" "vV" (func $internal2608))
+ (import "env" "wV" (func $internal2609))
+ (import "env" "xV" (func $internal2610))
+ (import "env" "yV" (func $internal2611))
+ (import "env" "zV" (func $internal2612))
+ (import "env" "AV" (func $internal2613))
+ (import "env" "BV" (func $internal2614))
+ (import "env" "CV" (func $internal2615))
+ (import "env" "DV" (func $internal2616))
+ (import "env" "EV" (func $internal2617))
+ (import "env" "FV" (func $internal2618))
+ (import "env" "GV" (func $internal2619))
+ (import "env" "HV" (func $internal2620))
+ (import "env" "IV" (func $internal2621))
+ (import "env" "JV" (func $internal2622))
+ (import "env" "KV" (func $internal2623))
+ (import "env" "LV" (func $internal2624))
+ (import "env" "MV" (func $internal2625))
+ (import "env" "NV" (func $internal2626))
+ (import "env" "OV" (func $internal2627))
+ (import "env" "PV" (func $internal2628))
+ (import "env" "QV" (func $internal2629))
+ (import "env" "RV" (func $internal2630))
+ (import "env" "SV" (func $internal2631))
+ (import "env" "TV" (func $internal2632))
+ (import "env" "UV" (func $internal2633))
+ (import "env" "VV" (func $internal2634))
+ (import "env" "WV" (func $internal2635))
+ (import "env" "XV" (func $internal2636))
+ (import "env" "YV" (func $internal2637))
+ (import "env" "ZV" (func $internal2638))
+ (import "env" "_V" (func $internal2639))
+ (import "env" "$V" (func $internal2640))
+ (import "env" "aW" (func $internal2641))
+ (import "env" "bW" (func $internal2642))
+ (import "env" "cW" (func $internal2643))
+ (import "env" "dW" (func $internal2644))
+ (import "env" "eW" (func $internal2645))
+ (import "env" "fW" (func $internal2646))
+ (import "env" "gW" (func $internal2647))
+ (import "env" "hW" (func $internal2648))
+ (import "env" "iW" (func $internal2649))
+ (import "env" "jW" (func $internal2650))
+ (import "env" "kW" (func $internal2651))
+ (import "env" "lW" (func $internal2652))
+ (import "env" "mW" (func $internal2653))
+ (import "env" "nW" (func $internal2654))
+ (import "env" "oW" (func $internal2655))
+ (import "env" "pW" (func $internal2656))
+ (import "env" "qW" (func $internal2657))
+ (import "env" "rW" (func $internal2658))
+ (import "env" "sW" (func $internal2659))
+ (import "env" "tW" (func $internal2660))
+ (import "env" "uW" (func $internal2661))
+ (import "env" "vW" (func $internal2662))
+ (import "env" "wW" (func $internal2663))
+ (import "env" "xW" (func $internal2664))
+ (import "env" "yW" (func $internal2665))
+ (import "env" "zW" (func $internal2666))
+ (import "env" "AW" (func $internal2667))
+ (import "env" "BW" (func $internal2668))
+ (import "env" "CW" (func $internal2669))
+ (import "env" "DW" (func $internal2670))
+ (import "env" "EW" (func $internal2671))
+ (import "env" "FW" (func $internal2672))
+ (import "env" "GW" (func $internal2673))
+ (import "env" "HW" (func $internal2674))
+ (import "env" "IW" (func $internal2675))
+ (import "env" "JW" (func $internal2676))
+ (import "env" "KW" (func $internal2677))
+ (import "env" "LW" (func $internal2678))
+ (import "env" "MW" (func $internal2679))
+ (import "env" "NW" (func $internal2680))
+ (import "env" "OW" (func $internal2681))
+ (import "env" "PW" (func $internal2682))
+ (import "env" "QW" (func $internal2683))
+ (import "env" "RW" (func $internal2684))
+ (import "env" "SW" (func $internal2685))
+ (import "env" "TW" (func $internal2686))
+ (import "env" "UW" (func $internal2687))
+ (import "env" "VW" (func $internal2688))
+ (import "env" "WW" (func $internal2689))
+ (import "env" "XW" (func $internal2690))
+ (import "env" "YW" (func $internal2691))
+ (import "env" "ZW" (func $internal2692))
+ (import "env" "_W" (func $internal2693))
+ (import "env" "$W" (func $internal2694))
+ (import "env" "aX" (func $internal2695))
+ (import "env" "bX" (func $internal2696))
+ (import "env" "cX" (func $internal2697))
+ (import "env" "dX" (func $internal2698))
+ (import "env" "eX" (func $internal2699))
+ (import "env" "fX" (func $internal2700))
+ (import "env" "gX" (func $internal2701))
+ (import "env" "hX" (func $internal2702))
+ (import "env" "iX" (func $internal2703))
+ (import "env" "jX" (func $internal2704))
+ (import "env" "kX" (func $internal2705))
+ (import "env" "lX" (func $internal2706))
+ (import "env" "mX" (func $internal2707))
+ (import "env" "nX" (func $internal2708))
+ (import "env" "oX" (func $internal2709))
+ (import "env" "pX" (func $internal2710))
+ (import "env" "qX" (func $internal2711))
+ (import "env" "rX" (func $internal2712))
+ (import "env" "sX" (func $internal2713))
+ (import "env" "tX" (func $internal2714))
+ (import "env" "uX" (func $internal2715))
+ (import "env" "vX" (func $internal2716))
+ (import "env" "wX" (func $internal2717))
+ (import "env" "xX" (func $internal2718))
+ (import "env" "yX" (func $internal2719))
+ (import "env" "zX" (func $internal2720))
+ (import "env" "AX" (func $internal2721))
+ (import "env" "BX" (func $internal2722))
+ (import "env" "CX" (func $internal2723))
+ (import "env" "DX" (func $internal2724))
+ (import "env" "EX" (func $internal2725))
+ (import "env" "FX" (func $internal2726))
+ (import "env" "GX" (func $internal2727))
+ (import "env" "HX" (func $internal2728))
+ (import "env" "IX" (func $internal2729))
+ (import "env" "JX" (func $internal2730))
+ (import "env" "KX" (func $internal2731))
+ (import "env" "LX" (func $internal2732))
+ (import "env" "MX" (func $internal2733))
+ (import "env" "NX" (func $internal2734))
+ (import "env" "OX" (func $internal2735))
+ (import "env" "PX" (func $internal2736))
+ (import "env" "QX" (func $internal2737))
+ (import "env" "RX" (func $internal2738))
+ (import "env" "SX" (func $internal2739))
+ (import "env" "TX" (func $internal2740))
+ (import "env" "UX" (func $internal2741))
+ (import "env" "VX" (func $internal2742))
+ (import "env" "WX" (func $internal2743))
+ (import "env" "XX" (func $internal2744))
+ (import "env" "YX" (func $internal2745))
+ (import "env" "ZX" (func $internal2746))
+ (import "env" "_X" (func $internal2747))
+ (import "env" "$X" (func $internal2748))
+ (import "env" "aY" (func $internal2749))
+ (import "env" "bY" (func $internal2750))
+ (import "env" "cY" (func $internal2751))
+ (import "env" "dY" (func $internal2752))
+ (import "env" "eY" (func $internal2753))
+ (import "env" "fY" (func $internal2754))
+ (import "env" "gY" (func $internal2755))
+ (import "env" "hY" (func $internal2756))
+ (import "env" "iY" (func $internal2757))
+ (import "env" "jY" (func $internal2758))
+ (import "env" "kY" (func $internal2759))
+ (import "env" "lY" (func $internal2760))
+ (import "env" "mY" (func $internal2761))
+ (import "env" "nY" (func $internal2762))
+ (import "env" "oY" (func $internal2763))
+ (import "env" "pY" (func $internal2764))
+ (import "env" "qY" (func $internal2765))
+ (import "env" "rY" (func $internal2766))
+ (import "env" "sY" (func $internal2767))
+ (import "env" "tY" (func $internal2768))
+ (import "env" "uY" (func $internal2769))
+ (import "env" "vY" (func $internal2770))
+ (import "env" "wY" (func $internal2771))
+ (import "env" "xY" (func $internal2772))
+ (import "env" "yY" (func $internal2773))
+ (import "env" "zY" (func $internal2774))
+ (import "env" "AY" (func $internal2775))
+ (import "env" "BY" (func $internal2776))
+ (import "env" "CY" (func $internal2777))
+ (import "env" "DY" (func $internal2778))
+ (import "env" "EY" (func $internal2779))
+ (import "env" "FY" (func $internal2780))
+ (import "env" "GY" (func $internal2781))
+ (import "env" "HY" (func $internal2782))
+ (import "env" "IY" (func $internal2783))
+ (import "env" "JY" (func $internal2784))
+ (import "env" "KY" (func $internal2785))
+ (import "env" "LY" (func $internal2786))
+ (import "env" "MY" (func $internal2787))
+ (import "env" "NY" (func $internal2788))
+ (import "env" "OY" (func $internal2789))
+ (import "env" "PY" (func $internal2790))
+ (import "env" "QY" (func $internal2791))
+ (import "env" "RY" (func $internal2792))
+ (import "env" "SY" (func $internal2793))
+ (import "env" "TY" (func $internal2794))
+ (import "env" "UY" (func $internal2795))
+ (import "env" "VY" (func $internal2796))
+ (import "env" "WY" (func $internal2797))
+ (import "env" "XY" (func $internal2798))
+ (import "env" "YY" (func $internal2799))
+ (import "env" "ZY" (func $internal2800))
+ (import "env" "_Y" (func $internal2801))
+ (import "env" "$Y" (func $internal2802))
+ (import "env" "aZ" (func $internal2803))
+ (import "env" "bZ" (func $internal2804))
+ (import "env" "cZ" (func $internal2805))
+ (import "env" "dZ" (func $internal2806))
+ (import "env" "eZ" (func $internal2807))
+ (import "env" "fZ" (func $internal2808))
+ (import "env" "gZ" (func $internal2809))
+ (import "env" "hZ" (func $internal2810))
+ (import "env" "iZ" (func $internal2811))
+ (import "env" "jZ" (func $internal2812))
+ (import "env" "kZ" (func $internal2813))
+ (import "env" "lZ" (func $internal2814))
+ (import "env" "mZ" (func $internal2815))
+ (import "env" "nZ" (func $internal2816))
+ (import "env" "oZ" (func $internal2817))
+ (import "env" "pZ" (func $internal2818))
+ (import "env" "qZ" (func $internal2819))
+ (import "env" "rZ" (func $internal2820))
+ (import "env" "sZ" (func $internal2821))
+ (import "env" "tZ" (func $internal2822))
+ (import "env" "uZ" (func $internal2823))
+ (import "env" "vZ" (func $internal2824))
+ (import "env" "wZ" (func $internal2825))
+ (import "env" "xZ" (func $internal2826))
+ (import "env" "yZ" (func $internal2827))
+ (import "env" "zZ" (func $internal2828))
+ (import "env" "AZ" (func $internal2829))
+ (import "env" "BZ" (func $internal2830))
+ (import "env" "CZ" (func $internal2831))
+ (import "env" "DZ" (func $internal2832))
+ (import "env" "EZ" (func $internal2833))
+ (import "env" "FZ" (func $internal2834))
+ (import "env" "GZ" (func $internal2835))
+ (import "env" "HZ" (func $internal2836))
+ (import "env" "IZ" (func $internal2837))
+ (import "env" "JZ" (func $internal2838))
+ (import "env" "KZ" (func $internal2839))
+ (import "env" "LZ" (func $internal2840))
+ (import "env" "MZ" (func $internal2841))
+ (import "env" "NZ" (func $internal2842))
+ (import "env" "OZ" (func $internal2843))
+ (import "env" "PZ" (func $internal2844))
+ (import "env" "QZ" (func $internal2845))
+ (import "env" "RZ" (func $internal2846))
+ (import "env" "SZ" (func $internal2847))
+ (import "env" "TZ" (func $internal2848))
+ (import "env" "UZ" (func $internal2849))
+ (import "env" "VZ" (func $internal2850))
+ (import "env" "WZ" (func $internal2851))
+ (import "env" "XZ" (func $internal2852))
+ (import "env" "YZ" (func $internal2853))
+ (import "env" "ZZ" (func $internal2854))
+ (import "env" "_Z" (func $internal2855))
+ (import "env" "$Z" (func $internal2856))
+ (import "env" "a_" (func $internal2857))
+ (import "env" "b_" (func $internal2858))
+ (import "env" "c_" (func $internal2859))
+ (import "env" "d_" (func $internal2860))
+ (import "env" "e_" (func $internal2861))
+ (import "env" "f_" (func $internal2862))
+ (import "env" "g_" (func $internal2863))
+ (import "env" "h_" (func $internal2864))
+ (import "env" "i_" (func $internal2865))
+ (import "env" "j_" (func $internal2866))
+ (import "env" "k_" (func $internal2867))
+ (import "env" "l_" (func $internal2868))
+ (import "env" "m_" (func $internal2869))
+ (import "env" "n_" (func $internal2870))
+ (import "env" "o_" (func $internal2871))
+ (import "env" "p_" (func $internal2872))
+ (import "env" "q_" (func $internal2873))
+ (import "env" "r_" (func $internal2874))
+ (import "env" "s_" (func $internal2875))
+ (import "env" "t_" (func $internal2876))
+ (import "env" "u_" (func $internal2877))
+ (import "env" "v_" (func $internal2878))
+ (import "env" "w_" (func $internal2879))
+ (import "env" "x_" (func $internal2880))
+ (import "env" "y_" (func $internal2881))
+ (import "env" "z_" (func $internal2882))
+ (import "env" "A_" (func $internal2883))
+ (import "env" "B_" (func $internal2884))
+ (import "env" "C_" (func $internal2885))
+ (import "env" "D_" (func $internal2886))
+ (import "env" "E_" (func $internal2887))
+ (import "env" "F_" (func $internal2888))
+ (import "env" "G_" (func $internal2889))
+ (import "env" "H_" (func $internal2890))
+ (import "env" "I_" (func $internal2891))
+ (import "env" "J_" (func $internal2892))
+ (import "env" "K_" (func $internal2893))
+ (import "env" "L_" (func $internal2894))
+ (import "env" "M_" (func $internal2895))
+ (import "env" "N_" (func $internal2896))
+ (import "env" "O_" (func $internal2897))
+ (import "env" "P_" (func $internal2898))
+ (import "env" "Q_" (func $internal2899))
+ (import "env" "R_" (func $internal2900))
+ (import "env" "S_" (func $internal2901))
+ (import "env" "T_" (func $internal2902))
+ (import "env" "U_" (func $internal2903))
+ (import "env" "V_" (func $internal2904))
+ (import "env" "W_" (func $internal2905))
+ (import "env" "X_" (func $internal2906))
+ (import "env" "Y_" (func $internal2907))
+ (import "env" "Z_" (func $internal2908))
+ (import "env" "__" (func $internal2909))
+ (import "env" "$_" (func $internal2910))
+ (import "env" "a$" (func $internal2911))
+ (import "env" "b$" (func $internal2912))
+ (import "env" "c$" (func $internal2913))
+ (import "env" "d$" (func $internal2914))
+ (import "env" "e$" (func $internal2915))
+ (import "env" "f$" (func $internal2916))
+ (import "env" "g$" (func $internal2917))
+ (import "env" "h$" (func $internal2918))
+ (import "env" "i$" (func $internal2919))
+ (import "env" "j$" (func $internal2920))
+ (import "env" "k$" (func $internal2921))
+ (import "env" "l$" (func $internal2922))
+ (import "env" "m$" (func $internal2923))
+ (import "env" "n$" (func $internal2924))
+ (import "env" "o$" (func $internal2925))
+ (import "env" "p$" (func $internal2926))
+ (import "env" "q$" (func $internal2927))
+ (import "env" "r$" (func $internal2928))
+ (import "env" "s$" (func $internal2929))
+ (import "env" "t$" (func $internal2930))
+ (import "env" "u$" (func $internal2931))
+ (import "env" "v$" (func $internal2932))
+ (import "env" "w$" (func $internal2933))
+ (import "env" "x$" (func $internal2934))
+ (import "env" "y$" (func $internal2935))
+ (import "env" "z$" (func $internal2936))
+ (import "env" "A$" (func $internal2937))
+ (import "env" "B$" (func $internal2938))
+ (import "env" "C$" (func $internal2939))
+ (import "env" "D$" (func $internal2940))
+ (import "env" "E$" (func $internal2941))
+ (import "env" "F$" (func $internal2942))
+ (import "env" "G$" (func $internal2943))
+ (import "env" "H$" (func $internal2944))
+ (import "env" "I$" (func $internal2945))
+ (import "env" "J$" (func $internal2946))
+ (import "env" "K$" (func $internal2947))
+ (import "env" "L$" (func $internal2948))
+ (import "env" "M$" (func $internal2949))
+ (import "env" "N$" (func $internal2950))
+ (import "env" "O$" (func $internal2951))
+ (import "env" "P$" (func $internal2952))
+ (import "env" "Q$" (func $internal2953))
+ (import "env" "R$" (func $internal2954))
+ (import "env" "S$" (func $internal2955))
+ (import "env" "T$" (func $internal2956))
+ (import "env" "U$" (func $internal2957))
+ (import "env" "V$" (func $internal2958))
+ (import "env" "W$" (func $internal2959))
+ (import "env" "X$" (func $internal2960))
+ (import "env" "Y$" (func $internal2961))
+ (import "env" "Z$" (func $internal2962))
+ (import "env" "_$" (func $internal2963))
+ (import "env" "$$" (func $internal2964))
+ (import "env" "a0" (func $internal2965))
+ (import "env" "b0" (func $internal2966))
+ (import "env" "c0" (func $internal2967))
+ (import "env" "d0" (func $internal2968))
+ (import "env" "e0" (func $internal2969))
+ (import "env" "f0" (func $internal2970))
+ (import "env" "g0" (func $internal2971))
+ (import "env" "h0" (func $internal2972))
+ (import "env" "i0" (func $internal2973))
+ (import "env" "j0" (func $internal2974))
+ (import "env" "k0" (func $internal2975))
+ (import "env" "l0" (func $internal2976))
+ (import "env" "m0" (func $internal2977))
+ (import "env" "n0" (func $internal2978))
+ (import "env" "o0" (func $internal2979))
+ (import "env" "p0" (func $internal2980))
+ (import "env" "q0" (func $internal2981))
+ (import "env" "r0" (func $internal2982))
+ (import "env" "s0" (func $internal2983))
+ (import "env" "t0" (func $internal2984))
+ (import "env" "u0" (func $internal2985))
+ (import "env" "v0" (func $internal2986))
+ (import "env" "w0" (func $internal2987))
+ (import "env" "x0" (func $internal2988))
+ (import "env" "y0" (func $internal2989))
+ (import "env" "z0" (func $internal2990))
+ (import "env" "A0" (func $internal2991))
+ (import "env" "B0" (func $internal2992))
+ (import "env" "C0" (func $internal2993))
+ (import "env" "D0" (func $internal2994))
+ (import "env" "E0" (func $internal2995))
+ (import "env" "F0" (func $internal2996))
+ (import "env" "G0" (func $internal2997))
+ (import "env" "H0" (func $internal2998))
+ (import "env" "I0" (func $internal2999))
+ (import "env" "J0" (func $internal3000))
+ (import "env" "K0" (func $internal3001))
+ (import "env" "L0" (func $internal3002))
+ (import "env" "M0" (func $internal3003))
+ (import "env" "N0" (func $internal3004))
+ (import "env" "O0" (func $internal3005))
+ (import "env" "P0" (func $internal3006))
+ (import "env" "Q0" (func $internal3007))
+ (import "env" "R0" (func $internal3008))
+ (import "env" "S0" (func $internal3009))
+ (import "env" "T0" (func $internal3010))
+ (import "env" "U0" (func $internal3011))
+ (import "env" "V0" (func $internal3012))
+ (import "env" "W0" (func $internal3013))
+ (import "env" "X0" (func $internal3014))
+ (import "env" "Y0" (func $internal3015))
+ (import "env" "Z0" (func $internal3016))
+ (import "env" "_0" (func $internal3017))
+ (import "env" "$0" (func $internal3018))
+ (import "env" "a1" (func $internal3019))
+ (import "env" "b1" (func $internal3020))
+ (import "env" "c1" (func $internal3021))
+ (import "env" "d1" (func $internal3022))
+ (import "env" "e1" (func $internal3023))
+ (import "env" "f1" (func $internal3024))
+ (import "env" "g1" (func $internal3025))
+ (import "env" "h1" (func $internal3026))
+ (import "env" "i1" (func $internal3027))
+ (import "env" "j1" (func $internal3028))
+ (import "env" "k1" (func $internal3029))
+ (import "env" "l1" (func $internal3030))
+ (import "env" "m1" (func $internal3031))
+ (import "env" "n1" (func $internal3032))
+ (import "env" "o1" (func $internal3033))
+ (import "env" "p1" (func $internal3034))
+ (import "env" "q1" (func $internal3035))
+ (import "env" "r1" (func $internal3036))
+ (import "env" "s1" (func $internal3037))
+ (import "env" "t1" (func $internal3038))
+ (import "env" "u1" (func $internal3039))
+ (import "env" "v1" (func $internal3040))
+ (import "env" "w1" (func $internal3041))
+ (import "env" "x1" (func $internal3042))
+ (import "env" "y1" (func $internal3043))
+ (import "env" "z1" (func $internal3044))
+ (import "env" "A1" (func $internal3045))
+ (import "env" "B1" (func $internal3046))
+ (import "env" "C1" (func $internal3047))
+ (import "env" "D1" (func $internal3048))
+ (import "env" "E1" (func $internal3049))
+ (import "env" "F1" (func $internal3050))
+ (import "env" "G1" (func $internal3051))
+ (import "env" "H1" (func $internal3052))
+ (import "env" "I1" (func $internal3053))
+ (import "env" "J1" (func $internal3054))
+ (import "env" "K1" (func $internal3055))
+ (import "env" "L1" (func $internal3056))
+ (import "env" "M1" (func $internal3057))
+ (import "env" "N1" (func $internal3058))
+ (import "env" "O1" (func $internal3059))
+ (import "env" "P1" (func $internal3060))
+ (import "env" "Q1" (func $internal3061))
+ (import "env" "R1" (func $internal3062))
+ (import "env" "S1" (func $internal3063))
+ (import "env" "T1" (func $internal3064))
+ (import "env" "U1" (func $internal3065))
+ (import "env" "V1" (func $internal3066))
+ (import "env" "W1" (func $internal3067))
+ (import "env" "X1" (func $internal3068))
+ (import "env" "Y1" (func $internal3069))
+ (import "env" "Z1" (func $internal3070))
+ (import "env" "_1" (func $internal3071))
+ (import "env" "$1" (func $internal3072))
+ (import "env" "a2" (func $internal3073))
+ (import "env" "b2" (func $internal3074))
+ (import "env" "c2" (func $internal3075))
+ (import "env" "d2" (func $internal3076))
+ (import "env" "e2" (func $internal3077))
+ (import "env" "f2" (func $internal3078))
+ (import "env" "g2" (func $internal3079))
+ (import "env" "h2" (func $internal3080))
+ (import "env" "i2" (func $internal3081))
+ (import "env" "j2" (func $internal3082))
+ (import "env" "k2" (func $internal3083))
+ (import "env" "l2" (func $internal3084))
+ (import "env" "m2" (func $internal3085))
+ (import "env" "n2" (func $internal3086))
+ (import "env" "o2" (func $internal3087))
+ (import "env" "p2" (func $internal3088))
+ (import "env" "q2" (func $internal3089))
+ (import "env" "r2" (func $internal3090))
+ (import "env" "s2" (func $internal3091))
+ (import "env" "t2" (func $internal3092))
+ (import "env" "u2" (func $internal3093))
+ (import "env" "v2" (func $internal3094))
+ (import "env" "w2" (func $internal3095))
+ (import "env" "x2" (func $internal3096))
+ (import "env" "y2" (func $internal3097))
+ (import "env" "z2" (func $internal3098))
+ (import "env" "A2" (func $internal3099))
+ (import "env" "B2" (func $internal3100))
+ (import "env" "C2" (func $internal3101))
+ (import "env" "D2" (func $internal3102))
+ (import "env" "E2" (func $internal3103))
+ (import "env" "F2" (func $internal3104))
+ (import "env" "G2" (func $internal3105))
+ (import "env" "H2" (func $internal3106))
+ (import "env" "I2" (func $internal3107))
+ (import "env" "J2" (func $internal3108))
+ (import "env" "K2" (func $internal3109))
+ (import "env" "L2" (func $internal3110))
+ (import "env" "M2" (func $internal3111))
+ (import "env" "N2" (func $internal3112))
+ (import "env" "O2" (func $internal3113))
+ (import "env" "P2" (func $internal3114))
+ (import "env" "Q2" (func $internal3115))
+ (import "env" "R2" (func $internal3116))
+ (import "env" "S2" (func $internal3117))
+ (import "env" "T2" (func $internal3118))
+ (import "env" "U2" (func $internal3119))
+ (import "env" "V2" (func $internal3120))
+ (import "env" "W2" (func $internal3121))
+ (import "env" "X2" (func $internal3122))
+ (import "env" "Y2" (func $internal3123))
+ (import "env" "Z2" (func $internal3124))
+ (import "env" "_2" (func $internal3125))
+ (import "env" "$2" (func $internal3126))
+ (import "env" "a3" (func $internal3127))
+ (import "env" "b3" (func $internal3128))
+ (import "env" "c3" (func $internal3129))
+ (import "env" "d3" (func $internal3130))
+ (import "env" "e3" (func $internal3131))
+ (import "env" "f3" (func $internal3132))
+ (import "env" "g3" (func $internal3133))
+ (import "env" "h3" (func $internal3134))
+ (import "env" "i3" (func $internal3135))
+ (import "env" "j3" (func $internal3136))
+ (import "env" "k3" (func $internal3137))
+ (import "env" "l3" (func $internal3138))
+ (import "env" "m3" (func $internal3139))
+ (import "env" "n3" (func $internal3140))
+ (import "env" "o3" (func $internal3141))
+ (import "env" "p3" (func $internal3142))
+ (import "env" "q3" (func $internal3143))
+ (import "env" "r3" (func $internal3144))
+ (import "env" "s3" (func $internal3145))
+ (import "env" "t3" (func $internal3146))
+ (import "env" "u3" (func $internal3147))
+ (import "env" "v3" (func $internal3148))
+ (import "env" "w3" (func $internal3149))
+ (import "env" "x3" (func $internal3150))
+ (import "env" "y3" (func $internal3151))
+ (import "env" "z3" (func $internal3152))
+ (import "env" "A3" (func $internal3153))
+ (import "env" "B3" (func $internal3154))
+ (import "env" "C3" (func $internal3155))
+ (import "env" "D3" (func $internal3156))
+ (import "env" "E3" (func $internal3157))
+ (import "env" "F3" (func $internal3158))
+ (import "env" "G3" (func $internal3159))
+ (import "env" "H3" (func $internal3160))
+ (import "env" "I3" (func $internal3161))
+ (import "env" "J3" (func $internal3162))
+ (import "env" "K3" (func $internal3163))
+ (import "env" "L3" (func $internal3164))
+ (import "env" "M3" (func $internal3165))
+ (import "env" "N3" (func $internal3166))
+ (import "env" "O3" (func $internal3167))
+ (import "env" "P3" (func $internal3168))
+ (import "env" "Q3" (func $internal3169))
+ (import "env" "R3" (func $internal3170))
+ (import "env" "S3" (func $internal3171))
+ (import "env" "T3" (func $internal3172))
+ (import "env" "U3" (func $internal3173))
+ (import "env" "V3" (func $internal3174))
+ (import "env" "W3" (func $internal3175))
+ (import "env" "X3" (func $internal3176))
+ (import "env" "Y3" (func $internal3177))
+ (import "env" "Z3" (func $internal3178))
+ (import "env" "_3" (func $internal3179))
+ (import "env" "$3" (func $internal3180))
+ (import "env" "a4" (func $internal3181))
+ (import "env" "b4" (func $internal3182))
+ (import "env" "c4" (func $internal3183))
+ (import "env" "d4" (func $internal3184))
+ (import "env" "e4" (func $internal3185))
+ (import "env" "f4" (func $internal3186))
+ (import "env" "g4" (func $internal3187))
+ (import "env" "h4" (func $internal3188))
+ (import "env" "i4" (func $internal3189))
+ (import "env" "j4" (func $internal3190))
+ (import "env" "k4" (func $internal3191))
+ (import "env" "l4" (func $internal3192))
+ (import "env" "m4" (func $internal3193))
+ (import "env" "n4" (func $internal3194))
+ (import "env" "o4" (func $internal3195))
+ (import "env" "p4" (func $internal3196))
+ (import "env" "q4" (func $internal3197))
+ (import "env" "r4" (func $internal3198))
+ (import "env" "s4" (func $internal3199))
+ (import "env" "t4" (func $internal3200))
+ (import "env" "u4" (func $internal3201))
+ (import "env" "v4" (func $internal3202))
+ (import "env" "w4" (func $internal3203))
+ (import "env" "x4" (func $internal3204))
+ (import "env" "y4" (func $internal3205))
+ (import "env" "z4" (func $internal3206))
+ (import "env" "A4" (func $internal3207))
+ (import "env" "B4" (func $internal3208))
+ (import "env" "C4" (func $internal3209))
+ (import "env" "D4" (func $internal3210))
+ (import "env" "E4" (func $internal3211))
+ (import "env" "F4" (func $internal3212))
+ (import "env" "G4" (func $internal3213))
+ (import "env" "H4" (func $internal3214))
+ (import "env" "I4" (func $internal3215))
+ (import "env" "J4" (func $internal3216))
+ (import "env" "K4" (func $internal3217))
+ (import "env" "L4" (func $internal3218))
+ (import "env" "M4" (func $internal3219))
+ (import "env" "N4" (func $internal3220))
+ (import "env" "O4" (func $internal3221))
+ (import "env" "P4" (func $internal3222))
+ (import "env" "Q4" (func $internal3223))
+ (import "env" "R4" (func $internal3224))
+ (import "env" "S4" (func $internal3225))
+ (import "env" "T4" (func $internal3226))
+ (import "env" "U4" (func $internal3227))
+ (import "env" "V4" (func $internal3228))
+ (import "env" "W4" (func $internal3229))
+ (import "env" "X4" (func $internal3230))
+ (import "env" "Y4" (func $internal3231))
+ (import "env" "Z4" (func $internal3232))
+ (import "env" "_4" (func $internal3233))
+ (import "env" "$4" (func $internal3234))
+ (import "env" "a5" (func $internal3235))
+ (import "env" "b5" (func $internal3236))
+ (import "env" "c5" (func $internal3237))
+ (import "env" "d5" (func $internal3238))
+ (import "env" "e5" (func $internal3239))
+ (import "env" "f5" (func $internal3240))
+ (import "env" "g5" (func $internal3241))
+ (import "env" "h5" (func $internal3242))
+ (import "env" "i5" (func $internal3243))
+ (import "env" "j5" (func $internal3244))
+ (import "env" "k5" (func $internal3245))
+ (import "env" "l5" (func $internal3246))
+ (import "env" "m5" (func $internal3247))
+ (import "env" "n5" (func $internal3248))
+ (import "env" "o5" (func $internal3249))
+ (import "env" "p5" (func $internal3250))
+ (import "env" "q5" (func $internal3251))
+ (import "env" "r5" (func $internal3252))
+ (import "env" "s5" (func $internal3253))
+ (import "env" "t5" (func $internal3254))
+ (import "env" "u5" (func $internal3255))
+ (import "env" "v5" (func $internal3256))
+ (import "env" "w5" (func $internal3257))
+ (import "env" "x5" (func $internal3258))
+ (import "env" "y5" (func $internal3259))
+ (import "env" "z5" (func $internal3260))
+ (import "env" "A5" (func $internal3261))
+ (import "env" "B5" (func $internal3262))
+ (import "env" "C5" (func $internal3263))
+ (import "env" "D5" (func $internal3264))
+ (import "env" "E5" (func $internal3265))
+ (import "env" "F5" (func $internal3266))
+ (import "env" "G5" (func $internal3267))
+ (import "env" "H5" (func $internal3268))
+ (import "env" "I5" (func $internal3269))
+ (import "env" "J5" (func $internal3270))
+ (import "env" "K5" (func $internal3271))
+ (import "env" "L5" (func $internal3272))
+ (import "env" "M5" (func $internal3273))
+ (import "env" "N5" (func $internal3274))
+ (import "env" "O5" (func $internal3275))
+ (import "env" "P5" (func $internal3276))
+ (import "env" "Q5" (func $internal3277))
+ (import "env" "R5" (func $internal3278))
+ (import "env" "S5" (func $internal3279))
+ (import "env" "T5" (func $internal3280))
+ (import "env" "U5" (func $internal3281))
+ (import "env" "V5" (func $internal3282))
+ (import "env" "W5" (func $internal3283))
+ (import "env" "X5" (func $internal3284))
+ (import "env" "Y5" (func $internal3285))
+ (import "env" "Z5" (func $internal3286))
+ (import "env" "_5" (func $internal3287))
+ (import "env" "$5" (func $internal3288))
+ (import "env" "a6" (func $internal3289))
+ (import "env" "b6" (func $internal3290))
+ (import "env" "c6" (func $internal3291))
+ (import "env" "d6" (func $internal3292))
+ (import "env" "e6" (func $internal3293))
+ (import "env" "f6" (func $internal3294))
+ (import "env" "g6" (func $internal3295))
+ (import "env" "h6" (func $internal3296))
+ (import "env" "i6" (func $internal3297))
+ (import "env" "j6" (func $internal3298))
+ (import "env" "k6" (func $internal3299))
+ (import "env" "l6" (func $internal3300))
+ (import "env" "m6" (func $internal3301))
+ (import "env" "n6" (func $internal3302))
+ (import "env" "o6" (func $internal3303))
+ (import "env" "p6" (func $internal3304))
+ (import "env" "q6" (func $internal3305))
+ (import "env" "r6" (func $internal3306))
+ (import "env" "s6" (func $internal3307))
+ (import "env" "t6" (func $internal3308))
+ (import "env" "u6" (func $internal3309))
+ (import "env" "v6" (func $internal3310))
+ (import "env" "w6" (func $internal3311))
+ (import "env" "x6" (func $internal3312))
+ (import "env" "y6" (func $internal3313))
+ (import "env" "z6" (func $internal3314))
+ (import "env" "A6" (func $internal3315))
+ (import "env" "B6" (func $internal3316))
+ (import "env" "C6" (func $internal3317))
+ (import "env" "D6" (func $internal3318))
+ (import "env" "E6" (func $internal3319))
+ (import "env" "F6" (func $internal3320))
+ (import "env" "G6" (func $internal3321))
+ (import "env" "H6" (func $internal3322))
+ (import "env" "I6" (func $internal3323))
+ (import "env" "J6" (func $internal3324))
+ (import "env" "K6" (func $internal3325))
+ (import "env" "L6" (func $internal3326))
+ (import "env" "M6" (func $internal3327))
+ (import "env" "N6" (func $internal3328))
+ (import "env" "O6" (func $internal3329))
+ (import "env" "P6" (func $internal3330))
+ (import "env" "Q6" (func $internal3331))
+ (import "env" "R6" (func $internal3332))
+ (import "env" "S6" (func $internal3333))
+ (import "env" "T6" (func $internal3334))
+ (import "env" "U6" (func $internal3335))
+ (import "env" "V6" (func $internal3336))
+ (import "env" "W6" (func $internal3337))
+ (import "env" "X6" (func $internal3338))
+ (import "env" "Y6" (func $internal3339))
+ (import "env" "Z6" (func $internal3340))
+ (import "env" "_6" (func $internal3341))
+ (import "env" "$6" (func $internal3342))
+ (import "env" "a7" (func $internal3343))
+ (import "env" "b7" (func $internal3344))
+ (import "env" "c7" (func $internal3345))
+ (import "env" "d7" (func $internal3346))
+ (import "env" "e7" (func $internal3347))
+ (import "env" "f7" (func $internal3348))
+ (import "env" "g7" (func $internal3349))
+ (import "env" "h7" (func $internal3350))
+ (import "env" "i7" (func $internal3351))
+ (import "env" "j7" (func $internal3352))
+ (import "env" "k7" (func $internal3353))
+ (import "env" "l7" (func $internal3354))
+ (import "env" "m7" (func $internal3355))
+ (import "env" "n7" (func $internal3356))
+ (import "env" "o7" (func $internal3357))
+ (import "env" "p7" (func $internal3358))
+ (import "env" "q7" (func $internal3359))
+ (import "env" "r7" (func $internal3360))
+ (import "env" "s7" (func $internal3361))
+ (import "env" "t7" (func $internal3362))
+ (import "env" "u7" (func $internal3363))
+ (import "env" "v7" (func $internal3364))
+ (import "env" "w7" (func $internal3365))
+ (import "env" "x7" (func $internal3366))
+ (import "env" "y7" (func $internal3367))
+ (import "env" "z7" (func $internal3368))
+ (import "env" "A7" (func $internal3369))
+ (import "env" "B7" (func $internal3370))
+ (import "env" "C7" (func $internal3371))
+ (import "env" "D7" (func $internal3372))
+ (import "env" "E7" (func $internal3373))
+ (import "env" "F7" (func $internal3374))
+ (import "env" "G7" (func $internal3375))
+ (import "env" "H7" (func $internal3376))
+ (import "env" "I7" (func $internal3377))
+ (import "env" "J7" (func $internal3378))
+ (import "env" "K7" (func $internal3379))
+ (import "env" "L7" (func $internal3380))
+ (import "env" "M7" (func $internal3381))
+ (import "env" "N7" (func $internal3382))
+ (import "env" "O7" (func $internal3383))
+ (import "env" "P7" (func $internal3384))
+ (import "env" "Q7" (func $internal3385))
+ (import "env" "R7" (func $internal3386))
+ (import "env" "S7" (func $internal3387))
+ (import "env" "T7" (func $internal3388))
+ (import "env" "U7" (func $internal3389))
+ (import "env" "V7" (func $internal3390))
+ (import "env" "W7" (func $internal3391))
+ (import "env" "X7" (func $internal3392))
+ (import "env" "Y7" (func $internal3393))
+ (import "env" "Z7" (func $internal3394))
+ (import "env" "_7" (func $internal3395))
+ (import "env" "$7" (func $internal3396))
+ (import "env" "a8" (func $internal3397))
+ (import "env" "b8" (func $internal3398))
+ (import "env" "c8" (func $internal3399))
+ (import "env" "d8" (func $internal3400))
+ (import "env" "e8" (func $internal3401))
+ (import "env" "f8" (func $internal3402))
+ (import "env" "g8" (func $internal3403))
+ (import "env" "h8" (func $internal3404))
+ (import "env" "i8" (func $internal3405))
+ (import "env" "j8" (func $internal3406))
+ (import "env" "k8" (func $internal3407))
+ (import "env" "l8" (func $internal3408))
+ (import "env" "m8" (func $internal3409))
+ (import "env" "n8" (func $internal3410))
+ (import "env" "o8" (func $internal3411))
+ (import "env" "p8" (func $internal3412))
+ (import "env" "q8" (func $internal3413))
+ (import "env" "r8" (func $internal3414))
+ (import "env" "s8" (func $internal3415))
+ (import "env" "t8" (func $internal3416))
+ (import "env" "u8" (func $internal3417))
+ (import "env" "v8" (func $internal3418))
+ (import "env" "w8" (func $internal3419))
+ (import "env" "x8" (func $internal3420))
+ (import "env" "y8" (func $internal3421))
+ (import "env" "z8" (func $internal3422))
+ (import "env" "A8" (func $internal3423))
+ (import "env" "B8" (func $internal3424))
+ (import "env" "C8" (func $internal3425))
+ (import "env" "D8" (func $internal3426))
+ (import "env" "E8" (func $internal3427))
+ (import "env" "F8" (func $internal3428))
+ (import "env" "G8" (func $internal3429))
+ (import "env" "H8" (func $internal3430))
+ (import "env" "I8" (func $internal3431))
+ (import "env" "J8" (func $internal3432))
+ (import "env" "K8" (func $internal3433))
+ (import "env" "L8" (func $internal3434))
+ (import "env" "M8" (func $internal3435))
+ (import "env" "N8" (func $internal3436))
+ (import "env" "O8" (func $internal3437))
+ (import "env" "P8" (func $internal3438))
+ (import "env" "Q8" (func $internal3439))
+ (import "env" "R8" (func $internal3440))
+ (import "env" "S8" (func $internal3441))
+ (import "env" "T8" (func $internal3442))
+ (import "env" "U8" (func $internal3443))
+ (import "env" "V8" (func $internal3444))
+ (import "env" "W8" (func $internal3445))
+ (import "env" "X8" (func $internal3446))
+ (import "env" "Y8" (func $internal3447))
+ (import "env" "Z8" (func $internal3448))
+ (import "env" "_8" (func $internal3449))
+ (import "env" "$8" (func $internal3450))
+ (import "env" "a9" (func $internal3451))
+ (import "env" "b9" (func $internal3452))
+ (import "env" "c9" (func $internal3453))
+ (import "env" "d9" (func $internal3454))
+ (import "env" "e9" (func $internal3455))
+ (import "env" "f9" (func $internal3456))
+ (import "env" "g9" (func $internal3457))
+ (import "env" "h9" (func $internal3458))
+ (import "env" "i9" (func $internal3459))
+ (import "env" "j9" (func $internal3460))
+ (import "env" "k9" (func $internal3461))
+ (import "env" "l9" (func $internal3462))
+ (import "env" "m9" (func $internal3463))
+ (import "env" "n9" (func $internal3464))
+ (import "env" "o9" (func $internal3465))
+ (import "env" "p9" (func $internal3466))
+ (import "env" "q9" (func $internal3467))
+ (import "env" "r9" (func $internal3468))
+ (import "env" "s9" (func $internal3469))
+ (import "env" "t9" (func $internal3470))
+ (import "env" "u9" (func $internal3471))
+ (import "env" "v9" (func $internal3472))
+ (import "env" "w9" (func $internal3473))
+ (import "env" "x9" (func $internal3474))
+ (import "env" "y9" (func $internal3475))
+ (import "env" "z9" (func $internal3476))
+ (import "env" "A9" (func $internal3477))
+ (import "env" "B9" (func $internal3478))
+ (import "env" "C9" (func $internal3479))
+ (import "env" "D9" (func $internal3480))
+ (import "env" "E9" (func $internal3481))
+ (import "env" "F9" (func $internal3482))
+ (import "env" "G9" (func $internal3483))
+ (import "env" "H9" (func $internal3484))
+ (import "env" "I9" (func $internal3485))
+ (import "env" "J9" (func $internal3486))
+ (import "env" "K9" (func $internal3487))
+ (import "env" "L9" (func $internal3488))
+ (import "env" "M9" (func $internal3489))
+ (import "env" "N9" (func $internal3490))
+ (import "env" "O9" (func $internal3491))
+ (import "env" "P9" (func $internal3492))
+ (import "env" "Q9" (func $internal3493))
+ (import "env" "R9" (func $internal3494))
+ (import "env" "S9" (func $internal3495))
+ (import "env" "T9" (func $internal3496))
+ (import "env" "U9" (func $internal3497))
+ (import "env" "V9" (func $internal3498))
+ (import "env" "W9" (func $internal3499))
+ (import "env" "X9" (func $internal3500))
+ (import "env" "Y9" (func $internal3501))
+ (import "env" "Z9" (func $internal3502))
+ (import "env" "_9" (func $internal3503))
+ (import "env" "$9" (func $internal3504))
+ (import "env" "aaa" (func $internal3505))
+ (import "env" "baa" (func $internal3506))
+ (import "env" "caa" (func $internal3507))
+ (import "env" "daa" (func $internal3508))
+ (import "env" "eaa" (func $internal3509))
+ (import "env" "faa" (func $internal3510))
+ (import "env" "gaa" (func $internal3511))
+ (import "env" "haa" (func $internal3512))
+ (import "env" "iaa" (func $internal3513))
+ (import "env" "jaa" (func $internal3514))
+ (import "env" "kaa" (func $internal3515))
+ (import "env" "laa" (func $internal3516))
+ (import "env" "maa" (func $internal3517))
+ (import "env" "naa" (func $internal3518))
+ (import "env" "oaa" (func $internal3519))
+ (import "env" "paa" (func $internal3520))
+ (import "env" "qaa" (func $internal3521))
+ (import "env" "raa" (func $internal3522))
+ (import "env" "saa" (func $internal3523))
+ (import "env" "taa" (func $internal3524))
+ (import "env" "uaa" (func $internal3525))
+ (import "env" "vaa" (func $internal3526))
+ (import "env" "waa" (func $internal3527))
+ (import "env" "xaa" (func $internal3528))
+ (import "env" "yaa" (func $internal3529))
+ (import "env" "zaa" (func $internal3530))
+ (import "env" "Aaa" (func $internal3531))
+ (import "env" "Baa" (func $internal3532))
+ (import "env" "Caa" (func $internal3533))
+ (import "env" "Daa" (func $internal3534))
+ (import "env" "Eaa" (func $internal3535))
+ (import "env" "Faa" (func $internal3536))
+ (import "env" "Gaa" (func $internal3537))
+ (import "env" "Haa" (func $internal3538))
+ (import "env" "Iaa" (func $internal3539))
+ (import "env" "Jaa" (func $internal3540))
+ (import "env" "Kaa" (func $internal3541))
+ (import "env" "Laa" (func $internal3542))
+ (import "env" "Maa" (func $internal3543))
+ (import "env" "Naa" (func $internal3544))
+ (import "env" "Oaa" (func $internal3545))
+ (import "env" "Paa" (func $internal3546))
+ (import "env" "Qaa" (func $internal3547))
+ (import "env" "Raa" (func $internal3548))
+ (import "env" "Saa" (func $internal3549))
+ (import "env" "Taa" (func $internal3550))
+ (import "env" "Uaa" (func $internal3551))
+ (import "env" "Vaa" (func $internal3552))
+ (import "env" "Waa" (func $internal3553))
+ (import "env" "Xaa" (func $internal3554))
+ (import "env" "Yaa" (func $internal3555))
+ (import "env" "Zaa" (func $internal3556))
+ (import "env" "_aa" (func $internal3557))
+ (import "env" "$aa" (func $internal3558))
+ (import "env" "aba" (func $internal3559))
+ (import "env" "bba" (func $internal3560))
+ (import "env" "cba" (func $internal3561))
+ (import "env" "dba" (func $internal3562))
+ (import "env" "eba" (func $internal3563))
+ (import "env" "fba" (func $internal3564))
+ (import "env" "gba" (func $internal3565))
+ (import "env" "hba" (func $internal3566))
+ (import "env" "iba" (func $internal3567))
+ (import "env" "jba" (func $internal3568))
+ (import "env" "kba" (func $internal3569))
+ (import "env" "lba" (func $internal3570))
+ (import "env" "mba" (func $internal3571))
+ (import "env" "nba" (func $internal3572))
+ (import "env" "oba" (func $internal3573))
+ (import "env" "pba" (func $internal3574))
+ (import "env" "qba" (func $internal3575))
+ (import "env" "rba" (func $internal3576))
+ (import "env" "sba" (func $internal3577))
+ (import "env" "tba" (func $internal3578))
+ (import "env" "uba" (func $internal3579))
+ (import "env" "vba" (func $internal3580))
+ (import "env" "wba" (func $internal3581))
+ (import "env" "xba" (func $internal3582))
+ (import "env" "yba" (func $internal3583))
+ (import "env" "zba" (func $internal3584))
+ (import "env" "Aba" (func $internal3585))
+ (import "env" "Bba" (func $internal3586))
+ (import "env" "Cba" (func $internal3587))
+ (import "env" "Dba" (func $internal3588))
+ (import "env" "Eba" (func $internal3589))
+ (import "env" "Fba" (func $internal3590))
+ (import "env" "Gba" (func $internal3591))
+ (import "env" "Hba" (func $internal3592))
+ (import "env" "Iba" (func $internal3593))
+ (import "env" "Jba" (func $internal3594))
+ (import "env" "Kba" (func $internal3595))
+ (import "env" "Lba" (func $internal3596))
+ (import "env" "Mba" (func $internal3597))
+ (import "env" "Nba" (func $internal3598))
+ (import "env" "Oba" (func $internal3599))
+ (import "env" "Pba" (func $internal3600))
+ (import "env" "Qba" (func $internal3601))
+ (import "env" "Rba" (func $internal3602))
+ (import "env" "Sba" (func $internal3603))
+ (import "env" "Tba" (func $internal3604))
+ (import "env" "Uba" (func $internal3605))
+ (import "env" "Vba" (func $internal3606))
+ (import "env" "Wba" (func $internal3607))
+ (import "env" "Xba" (func $internal3608))
+ (import "env" "Yba" (func $internal3609))
+ (import "env" "Zba" (func $internal3610))
+ (import "env" "_ba" (func $internal3611))
+ (import "env" "$ba" (func $internal3612))
+ (import "env" "aca" (func $internal3613))
+ (import "env" "bca" (func $internal3614))
+ (import "env" "cca" (func $internal3615))
+ (import "env" "dca" (func $internal3616))
+ (import "env" "eca" (func $internal3617))
+ (import "env" "fca" (func $internal3618))
+ (import "env" "gca" (func $internal3619))
+ (import "env" "hca" (func $internal3620))
+ (import "env" "ica" (func $internal3621))
+ (import "env" "jca" (func $internal3622))
+ (import "env" "kca" (func $internal3623))
+ (import "env" "lca" (func $internal3624))
+ (import "env" "mca" (func $internal3625))
+ (import "env" "nca" (func $internal3626))
+ (import "env" "oca" (func $internal3627))
+ (import "env" "pca" (func $internal3628))
+ (import "env" "qca" (func $internal3629))
+ (import "env" "rca" (func $internal3630))
+ (import "env" "sca" (func $internal3631))
+ (import "env" "tca" (func $internal3632))
+ (import "env" "uca" (func $internal3633))
+ (import "env" "vca" (func $internal3634))
+ (import "env" "wca" (func $internal3635))
+ (import "env" "xca" (func $internal3636))
+ (import "env" "yca" (func $internal3637))
+ (import "env" "zca" (func $internal3638))
+ (import "env" "Aca" (func $internal3639))
+ (import "env" "Bca" (func $internal3640))
+ (import "env" "Cca" (func $internal3641))
+ (import "env" "Dca" (func $internal3642))
+ (import "env" "Eca" (func $internal3643))
+ (import "env" "Fca" (func $internal3644))
+ (import "env" "Gca" (func $internal3645))
+ (import "env" "Hca" (func $internal3646))
+ (import "env" "Ica" (func $internal3647))
+ (import "env" "Jca" (func $internal3648))
+ (import "env" "Kca" (func $internal3649))
+ (import "env" "Lca" (func $internal3650))
+ (import "env" "Mca" (func $internal3651))
+ (import "env" "Nca" (func $internal3652))
+ (import "env" "Oca" (func $internal3653))
+ (import "env" "Pca" (func $internal3654))
+ (import "env" "Qca" (func $internal3655))
+ (import "env" "Rca" (func $internal3656))
+ (import "env" "Sca" (func $internal3657))
+ (import "env" "Tca" (func $internal3658))
+ (import "env" "Uca" (func $internal3659))
+ (import "env" "Vca" (func $internal3660))
+ (import "env" "Wca" (func $internal3661))
+ (import "env" "Xca" (func $internal3662))
+ (import "env" "Yca" (func $internal3663))
+ (import "env" "Zca" (func $internal3664))
+ (import "env" "_ca" (func $internal3665))
+ (import "env" "$ca" (func $internal3666))
+ (import "env" "ada" (func $internal3667))
+ (import "env" "bda" (func $internal3668))
+ (import "env" "cda" (func $internal3669))
+ (import "env" "dda" (func $internal3670))
+ (import "env" "eda" (func $internal3671))
+ (import "env" "fda" (func $internal3672))
+ (import "env" "gda" (func $internal3673))
+ (import "env" "hda" (func $internal3674))
+ (import "env" "ida" (func $internal3675))
+ (import "env" "jda" (func $internal3676))
+ (import "env" "kda" (func $internal3677))
+ (import "env" "lda" (func $internal3678))
+ (import "env" "mda" (func $internal3679))
+ (import "env" "nda" (func $internal3680))
+ (import "env" "oda" (func $internal3681))
+ (import "env" "pda" (func $internal3682))
+ (import "env" "qda" (func $internal3683))
+ (import "env" "rda" (func $internal3684))
+ (import "env" "sda" (func $internal3685))
+ (import "env" "tda" (func $internal3686))
+ (import "env" "uda" (func $internal3687))
+ (import "env" "vda" (func $internal3688))
+ (import "env" "wda" (func $internal3689))
+ (import "env" "xda" (func $internal3690))
+ (import "env" "yda" (func $internal3691))
+ (import "env" "zda" (func $internal3692))
+ (import "env" "Ada" (func $internal3693))
+ (import "env" "Bda" (func $internal3694))
+ (import "env" "Cda" (func $internal3695))
+ (import "env" "Dda" (func $internal3696))
+ (import "env" "Eda" (func $internal3697))
+ (import "env" "Fda" (func $internal3698))
+ (import "env" "Gda" (func $internal3699))
+ (import "env" "Hda" (func $internal3700))
+ (import "env" "Ida" (func $internal3701))
+ (import "env" "Jda" (func $internal3702))
+ (import "env" "Kda" (func $internal3703))
+ (import "env" "Lda" (func $internal3704))
+ (import "env" "Mda" (func $internal3705))
+ (import "env" "Nda" (func $internal3706))
+ (import "env" "Oda" (func $internal3707))
+ (import "env" "Pda" (func $internal3708))
+ (import "env" "Qda" (func $internal3709))
+ (import "env" "Rda" (func $internal3710))
+ (import "env" "Sda" (func $internal3711))
+ (import "env" "Tda" (func $internal3712))
+ (import "env" "Uda" (func $internal3713))
+ (import "env" "Vda" (func $internal3714))
+ (import "env" "Wda" (func $internal3715))
+ (import "env" "Xda" (func $internal3716))
+ (import "env" "Yda" (func $internal3717))
+ (import "env" "Zda" (func $internal3718))
+ (import "env" "_da" (func $internal3719))
+ (import "env" "$da" (func $internal3720))
+ (import "env" "aea" (func $internal3721))
+ (import "env" "bea" (func $internal3722))
+ (import "env" "cea" (func $internal3723))
+ (import "env" "dea" (func $internal3724))
+ (import "env" "eea" (func $internal3725))
+ (import "env" "fea" (func $internal3726))
+ (import "env" "gea" (func $internal3727))
+ (import "env" "hea" (func $internal3728))
+ (import "env" "iea" (func $internal3729))
+ (import "env" "jea" (func $internal3730))
+ (import "env" "kea" (func $internal3731))
+ (import "env" "lea" (func $internal3732))
+ (import "env" "mea" (func $internal3733))
+ (import "env" "nea" (func $internal3734))
+ (import "env" "oea" (func $internal3735))
+ (import "env" "pea" (func $internal3736))
+ (import "env" "qea" (func $internal3737))
+ (import "env" "rea" (func $internal3738))
+ (import "env" "sea" (func $internal3739))
+ (import "env" "tea" (func $internal3740))
+ (import "env" "uea" (func $internal3741))
+ (import "env" "vea" (func $internal3742))
+ (import "env" "wea" (func $internal3743))
+ (import "env" "xea" (func $internal3744))
+ (import "env" "yea" (func $internal3745))
+ (import "env" "zea" (func $internal3746))
+ (import "env" "Aea" (func $internal3747))
+ (import "env" "Bea" (func $internal3748))
+ (import "env" "Cea" (func $internal3749))
+ (import "env" "Dea" (func $internal3750))
+ (import "env" "Eea" (func $internal3751))
+ (import "env" "Fea" (func $internal3752))
+ (import "env" "Gea" (func $internal3753))
+ (import "env" "Hea" (func $internal3754))
+ (import "env" "Iea" (func $internal3755))
+ (import "env" "Jea" (func $internal3756))
+ (import "env" "Kea" (func $internal3757))
+ (import "env" "Lea" (func $internal3758))
+ (import "env" "Mea" (func $internal3759))
+ (import "env" "Nea" (func $internal3760))
+ (import "env" "Oea" (func $internal3761))
+ (import "env" "Pea" (func $internal3762))
+ (import "env" "Qea" (func $internal3763))
+ (import "env" "Rea" (func $internal3764))
+ (import "env" "Sea" (func $internal3765))
+ (import "env" "Tea" (func $internal3766))
+ (import "env" "Uea" (func $internal3767))
+ (import "env" "Vea" (func $internal3768))
+ (import "env" "Wea" (func $internal3769))
+ (import "env" "Xea" (func $internal3770))
+ (import "env" "Yea" (func $internal3771))
+ (import "env" "Zea" (func $internal3772))
+ (import "env" "_ea" (func $internal3773))
+ (import "env" "$ea" (func $internal3774))
+ (import "env" "afa" (func $internal3775))
+ (import "env" "bfa" (func $internal3776))
+ (import "env" "cfa" (func $internal3777))
+ (import "env" "dfa" (func $internal3778))
+ (import "env" "efa" (func $internal3779))
+ (import "env" "ffa" (func $internal3780))
+ (import "env" "gfa" (func $internal3781))
+ (import "env" "hfa" (func $internal3782))
+ (import "env" "ifa" (func $internal3783))
+ (import "env" "jfa" (func $internal3784))
+ (import "env" "kfa" (func $internal3785))
+ (import "env" "lfa" (func $internal3786))
+ (import "env" "mfa" (func $internal3787))
+ (import "env" "nfa" (func $internal3788))
+ (import "env" "ofa" (func $internal3789))
+ (import "env" "pfa" (func $internal3790))
+ (import "env" "qfa" (func $internal3791))
+ (import "env" "rfa" (func $internal3792))
+ (import "env" "sfa" (func $internal3793))
+ (import "env" "tfa" (func $internal3794))
+ (import "env" "ufa" (func $internal3795))
+ (import "env" "vfa" (func $internal3796))
+ (import "env" "wfa" (func $internal3797))
+ (import "env" "xfa" (func $internal3798))
+ (import "env" "yfa" (func $internal3799))
+ (import "env" "zfa" (func $internal3800))
+ (import "env" "Afa" (func $internal3801))
+ (import "env" "Bfa" (func $internal3802))
+ (import "env" "Cfa" (func $internal3803))
+ (import "env" "Dfa" (func $internal3804))
+ (import "env" "Efa" (func $internal3805))
+ (import "env" "Ffa" (func $internal3806))
+ (import "env" "Gfa" (func $internal3807))
+ (import "env" "Hfa" (func $internal3808))
+ (import "env" "Ifa" (func $internal3809))
+ (import "env" "Jfa" (func $internal3810))
+ (import "env" "Kfa" (func $internal3811))
+ (import "env" "Lfa" (func $internal3812))
+ (import "env" "Mfa" (func $internal3813))
+ (import "env" "Nfa" (func $internal3814))
+ (import "env" "Ofa" (func $internal3815))
+ (import "env" "Pfa" (func $internal3816))
+ (import "env" "Qfa" (func $internal3817))
+ (import "env" "Rfa" (func $internal3818))
+ (import "env" "Sfa" (func $internal3819))
+ (import "env" "Tfa" (func $internal3820))
+ (import "env" "Ufa" (func $internal3821))
+ (import "env" "Vfa" (func $internal3822))
+ (import "env" "Wfa" (func $internal3823))
+ (import "env" "Xfa" (func $internal3824))
+ (import "env" "Yfa" (func $internal3825))
+ (import "env" "Zfa" (func $internal3826))
+ (import "env" "_fa" (func $internal3827))
+ (import "env" "$fa" (func $internal3828))
+ (import "env" "aga" (func $internal3829))
+ (import "env" "bga" (func $internal3830))
+ (import "env" "cga" (func $internal3831))
+ (import "env" "dga" (func $internal3832))
+ (import "env" "ega" (func $internal3833))
+ (import "env" "fga" (func $internal3834))
+ (import "env" "gga" (func $internal3835))
+ (import "env" "hga" (func $internal3836))
+ (import "env" "iga" (func $internal3837))
+ (import "env" "jga" (func $internal3838))
+ (import "env" "kga" (func $internal3839))
+ (import "env" "lga" (func $internal3840))
+ (import "env" "mga" (func $internal3841))
+ (import "env" "nga" (func $internal3842))
+ (import "env" "oga" (func $internal3843))
+ (import "env" "pga" (func $internal3844))
+ (import "env" "qga" (func $internal3845))
+ (import "env" "rga" (func $internal3846))
+ (import "env" "sga" (func $internal3847))
+ (import "env" "tga" (func $internal3848))
+ (import "env" "uga" (func $internal3849))
+ (import "env" "vga" (func $internal3850))
+ (import "env" "wga" (func $internal3851))
+ (import "env" "xga" (func $internal3852))
+ (import "env" "yga" (func $internal3853))
+ (import "env" "zga" (func $internal3854))
+ (import "env" "Aga" (func $internal3855))
+ (import "env" "Bga" (func $internal3856))
+ (import "env" "Cga" (func $internal3857))
+ (import "env" "Dga" (func $internal3858))
+ (import "env" "Ega" (func $internal3859))
+ (import "env" "Fga" (func $internal3860))
+ (import "env" "Gga" (func $internal3861))
+ (import "env" "Hga" (func $internal3862))
+ (import "env" "Iga" (func $internal3863))
+ (import "env" "Jga" (func $internal3864))
+ (import "env" "Kga" (func $internal3865))
+ (import "env" "Lga" (func $internal3866))
+ (import "env" "Mga" (func $internal3867))
+ (import "env" "Nga" (func $internal3868))
+ (import "env" "Oga" (func $internal3869))
+ (import "env" "Pga" (func $internal3870))
+ (import "env" "Qga" (func $internal3871))
+ (import "env" "Rga" (func $internal3872))
+ (import "env" "Sga" (func $internal3873))
+ (import "env" "Tga" (func $internal3874))
+ (import "env" "Uga" (func $internal3875))
+ (import "env" "Vga" (func $internal3876))
+ (import "env" "Wga" (func $internal3877))
+ (import "env" "Xga" (func $internal3878))
+ (import "env" "Yga" (func $internal3879))
+ (import "env" "Zga" (func $internal3880))
+ (import "env" "_ga" (func $internal3881))
+ (import "env" "$ga" (func $internal3882))
+ (import "env" "aha" (func $internal3883))
+ (import "env" "bha" (func $internal3884))
+ (import "env" "cha" (func $internal3885))
+ (import "env" "dha" (func $internal3886))
+ (import "env" "eha" (func $internal3887))
+ (import "env" "fha" (func $internal3888))
+ (import "env" "gha" (func $internal3889))
+ (import "env" "hha" (func $internal3890))
+ (import "env" "iha" (func $internal3891))
+ (import "env" "jha" (func $internal3892))
+ (import "env" "kha" (func $internal3893))
+ (import "env" "lha" (func $internal3894))
+ (import "env" "mha" (func $internal3895))
+ (import "env" "nha" (func $internal3896))
+ (import "env" "oha" (func $internal3897))
+ (import "env" "pha" (func $internal3898))
+ (import "env" "qha" (func $internal3899))
+ (import "env" "rha" (func $internal3900))
+ (import "env" "sha" (func $internal3901))
+ (import "env" "tha" (func $internal3902))
+ (import "env" "uha" (func $internal3903))
+ (import "env" "vha" (func $internal3904))
+ (import "env" "wha" (func $internal3905))
+ (import "env" "xha" (func $internal3906))
+ (import "env" "yha" (func $internal3907))
+ (import "env" "zha" (func $internal3908))
+ (import "env" "Aha" (func $internal3909))
+ (import "env" "Bha" (func $internal3910))
+ (import "env" "Cha" (func $internal3911))
+ (import "env" "Dha" (func $internal3912))
+ (import "env" "Eha" (func $internal3913))
+ (import "env" "Fha" (func $internal3914))
+ (import "env" "Gha" (func $internal3915))
+ (import "env" "Hha" (func $internal3916))
+ (import "env" "Iha" (func $internal3917))
+ (import "env" "Jha" (func $internal3918))
+ (import "env" "Kha" (func $internal3919))
+ (import "env" "Lha" (func $internal3920))
+ (import "env" "Mha" (func $internal3921))
+ (import "env" "Nha" (func $internal3922))
+ (import "env" "Oha" (func $internal3923))
+ (import "env" "Pha" (func $internal3924))
+ (import "env" "Qha" (func $internal3925))
+ (import "env" "Rha" (func $internal3926))
+ (import "env" "Sha" (func $internal3927))
+ (import "env" "Tha" (func $internal3928))
+ (import "env" "Uha" (func $internal3929))
+ (import "env" "Vha" (func $internal3930))
+ (import "env" "Wha" (func $internal3931))
+ (import "env" "Xha" (func $internal3932))
+ (import "env" "Yha" (func $internal3933))
+ (import "env" "Zha" (func $internal3934))
+ (import "env" "_ha" (func $internal3935))
+ (import "env" "$ha" (func $internal3936))
+ (import "env" "aia" (func $internal3937))
+ (import "env" "bia" (func $internal3938))
+ (import "env" "cia" (func $internal3939))
+ (import "env" "dia" (func $internal3940))
+ (import "env" "eia" (func $internal3941))
+ (import "env" "fia" (func $internal3942))
+ (import "env" "gia" (func $internal3943))
+ (import "env" "hia" (func $internal3944))
+ (import "env" "iia" (func $internal3945))
+ (import "env" "jia" (func $internal3946))
+ (import "env" "kia" (func $internal3947))
+ (import "env" "lia" (func $internal3948))
+ (import "env" "mia" (func $internal3949))
+ (import "env" "nia" (func $internal3950))
+ (import "env" "oia" (func $internal3951))
+ (import "env" "pia" (func $internal3952))
+ (import "env" "qia" (func $internal3953))
+ (import "env" "ria" (func $internal3954))
+ (import "env" "sia" (func $internal3955))
+ (import "env" "tia" (func $internal3956))
+ (import "env" "uia" (func $internal3957))
+ (import "env" "via" (func $internal3958))
+ (import "env" "wia" (func $internal3959))
+ (import "env" "xia" (func $internal3960))
+ (import "env" "yia" (func $internal3961))
+ (import "env" "zia" (func $internal3962))
+ (import "env" "Aia" (func $internal3963))
+ (import "env" "Bia" (func $internal3964))
+ (import "env" "Cia" (func $internal3965))
+ (import "env" "Dia" (func $internal3966))
+ (import "env" "Eia" (func $internal3967))
+ (import "env" "Fia" (func $internal3968))
+ (import "env" "Gia" (func $internal3969))
+ (import "env" "Hia" (func $internal3970))
+ (import "env" "Iia" (func $internal3971))
+ (import "env" "Jia" (func $internal3972))
+ (import "env" "Kia" (func $internal3973))
+ (import "env" "Lia" (func $internal3974))
+ (import "env" "Mia" (func $internal3975))
+ (import "env" "Nia" (func $internal3976))
+ (import "env" "Oia" (func $internal3977))
+ (import "env" "Pia" (func $internal3978))
+ (import "env" "Qia" (func $internal3979))
+ (import "env" "Ria" (func $internal3980))
+ (import "env" "Sia" (func $internal3981))
+ (import "env" "Tia" (func $internal3982))
+ (import "env" "Uia" (func $internal3983))
+ (import "env" "Via" (func $internal3984))
+ (import "env" "Wia" (func $internal3985))
+ (import "env" "Xia" (func $internal3986))
+ (import "env" "Yia" (func $internal3987))
+ (import "env" "Zia" (func $internal3988))
+ (import "env" "_ia" (func $internal3989))
+ (import "env" "$ia" (func $internal3990))
+ (import "env" "aja" (func $internal3991))
+ (import "env" "bja" (func $internal3992))
+ (import "env" "cja" (func $internal3993))
+ (import "env" "dja" (func $internal3994))
+ (import "env" "eja" (func $internal3995))
+ (import "env" "fja" (func $internal3996))
+ (import "env" "gja" (func $internal3997))
+ (import "env" "hja" (func $internal3998))
+ (import "env" "ija" (func $internal3999))
+ (import "env" "jja" (func $internal4000))
+ (import "env" "kja" (func $internal4001))
+ (import "env" "lja" (func $internal4002))
+ (import "env" "mja" (func $internal4003))
+ (import "env" "nja" (func $internal4004))
+ (import "env" "oja" (func $internal4005))
+ (import "env" "pja" (func $internal4006))
+ (import "env" "qja" (func $internal4007))
+ (import "env" "rja" (func $internal4008))
+ (import "env" "sja" (func $internal4009))
+ (import "env" "tja" (func $internal4010))
+ (import "env" "uja" (func $internal4011))
+ (import "env" "vja" (func $internal4012))
+ (import "env" "wja" (func $internal4013))
+ (import "env" "xja" (func $internal4014))
+ (import "env" "yja" (func $internal4015))
+ (import "env" "zja" (func $internal4016))
+ (import "env" "Aja" (func $internal4017))
+ (import "env" "Bja" (func $internal4018))
+ (import "env" "Cja" (func $internal4019))
+ (import "env" "Dja" (func $internal4020))
+ (import "env" "Eja" (func $internal4021))
+ (import "env" "Fja" (func $internal4022))
+ (import "env" "Gja" (func $internal4023))
+ (import "env" "Hja" (func $internal4024))
+ (import "env" "Ija" (func $internal4025))
+ (import "env" "Jja" (func $internal4026))
+ (import "env" "Kja" (func $internal4027))
+ (import "env" "Lja" (func $internal4028))
+ (import "env" "Mja" (func $internal4029))
+ (import "env" "Nja" (func $internal4030))
+ (import "env" "Oja" (func $internal4031))
+ (import "env" "Pja" (func $internal4032))
+ (import "env" "Qja" (func $internal4033))
+ (import "env" "Rja" (func $internal4034))
+ (import "env" "Sja" (func $internal4035))
+ (import "env" "Tja" (func $internal4036))
+ (import "env" "Uja" (func $internal4037))
+ (import "env" "Vja" (func $internal4038))
+ (import "env" "Wja" (func $internal4039))
+ (import "env" "Xja" (func $internal4040))
+ (import "env" "Yja" (func $internal4041))
+ (import "env" "Zja" (func $internal4042))
+ (import "env" "_ja" (func $internal4043))
+ (import "env" "$ja" (func $internal4044))
+ (import "env" "aka" (func $internal4045))
+ (import "env" "bka" (func $internal4046))
+ (import "env" "cka" (func $internal4047))
+ (import "env" "dka" (func $internal4048))
+ (import "env" "eka" (func $internal4049))
+ (import "env" "fka" (func $internal4050))
+ (import "env" "gka" (func $internal4051))
+ (import "env" "hka" (func $internal4052))
+ (import "env" "ika" (func $internal4053))
+ (import "env" "jka" (func $internal4054))
+ (import "env" "kka" (func $internal4055))
+ (import "env" "lka" (func $internal4056))
+ (import "env" "mka" (func $internal4057))
+ (import "env" "nka" (func $internal4058))
+ (import "env" "oka" (func $internal4059))
+ (import "env" "pka" (func $internal4060))
+ (import "env" "qka" (func $internal4061))
+ (import "env" "rka" (func $internal4062))
+ (import "env" "ska" (func $internal4063))
+ (import "env" "tka" (func $internal4064))
+ (import "env" "uka" (func $internal4065))
+ (import "env" "vka" (func $internal4066))
+ (import "env" "wka" (func $internal4067))
+ (import "env" "xka" (func $internal4068))
+ (import "env" "yka" (func $internal4069))
+ (import "env" "zka" (func $internal4070))
+ (import "env" "Aka" (func $internal4071))
+ (import "env" "Bka" (func $internal4072))
+ (import "env" "Cka" (func $internal4073))
+ (import "env" "Dka" (func $internal4074))
+ (import "env" "Eka" (func $internal4075))
+ (import "env" "Fka" (func $internal4076))
+ (import "env" "Gka" (func $internal4077))
+ (import "env" "Hka" (func $internal4078))
+ (import "env" "Ika" (func $internal4079))
+ (import "env" "Jka" (func $internal4080))
+ (import "env" "Kka" (func $internal4081))
+ (import "env" "Lka" (func $internal4082))
+ (import "env" "Mka" (func $internal4083))
+ (import "env" "Nka" (func $internal4084))
+ (import "env" "Oka" (func $internal4085))
+ (import "env" "Pka" (func $internal4086))
+ (import "env" "Qka" (func $internal4087))
+ (import "env" "Rka" (func $internal4088))
+ (import "env" "Ska" (func $internal4089))
+ (import "env" "Tka" (func $internal4090))
+ (import "env" "Uka" (func $internal4091))
+ (import "env" "Vka" (func $internal4092))
+ (import "env" "Wka" (func $internal4093))
+ (import "env" "Xka" (func $internal4094))
+ (import "env" "Yka" (func $internal4095))
+ (import "env" "Zka" (func $internal4096))
+ (import "env" "_ka" (func $internal4097))
+ (import "env" "$ka" (func $internal4098))
+ (import "env" "ala" (func $internal4099))
+ (import "env" "bla" (func $internal4100))
+ (import "env" "cla" (func $internal4101))
+ (import "env" "dla" (func $internal4102))
+ (import "env" "ela" (func $internal4103))
+ (import "env" "fla" (func $internal4104))
+ (import "env" "gla" (func $internal4105))
+ (import "env" "hla" (func $internal4106))
+ (import "env" "ila" (func $internal4107))
+ (import "env" "jla" (func $internal4108))
+ (import "env" "kla" (func $internal4109))
+ (import "env" "lla" (func $internal4110))
+ (import "env" "mla" (func $internal4111))
+ (import "env" "nla" (func $internal4112))
+ (import "env" "ola" (func $internal4113))
+ (import "env" "pla" (func $internal4114))
+ (import "env" "qla" (func $internal4115))
+ (import "env" "rla" (func $internal4116))
+ (import "env" "sla" (func $internal4117))
+ (import "env" "tla" (func $internal4118))
+ (import "env" "ula" (func $internal4119))
+ (import "env" "vla" (func $internal4120))
+ (import "env" "wla" (func $internal4121))
+ (import "env" "xla" (func $internal4122))
+ (import "env" "yla" (func $internal4123))
+ (import "env" "zla" (func $internal4124))
+ (import "env" "Ala" (func $internal4125))
+ (import "env" "Bla" (func $internal4126))
+ (import "env" "Cla" (func $internal4127))
+ (import "env" "Dla" (func $internal4128))
+ (import "env" "Ela" (func $internal4129))
+ (import "env" "Fla" (func $internal4130))
+ (import "env" "Gla" (func $internal4131))
+ (import "env" "Hla" (func $internal4132))
+ (import "env" "Ila" (func $internal4133))
+ (import "env" "Jla" (func $internal4134))
+ (import "env" "Kla" (func $internal4135))
+ (import "env" "Lla" (func $internal4136))
+ (import "env" "Mla" (func $internal4137))
+ (import "env" "Nla" (func $internal4138))
+ (import "env" "Ola" (func $internal4139))
+ (import "env" "Pla" (func $internal4140))
+ (import "env" "Qla" (func $internal4141))
+ (import "env" "Rla" (func $internal4142))
+ (import "env" "Sla" (func $internal4143))
+ (import "env" "Tla" (func $internal4144))
+ (import "env" "Ula" (func $internal4145))
+ (import "env" "Vla" (func $internal4146))
+ (import "env" "Wla" (func $internal4147))
+ (import "env" "Xla" (func $internal4148))
+ (import "env" "Yla" (func $internal4149))
+ (import "env" "Zla" (func $internal4150))
+ (import "env" "_la" (func $internal4151))
+ (import "env" "$la" (func $internal4152))
+ (import "env" "ama" (func $internal4153))
+ (import "env" "bma" (func $internal4154))
+ (import "env" "cma" (func $internal4155))
+ (import "env" "dma" (func $internal4156))
+ (import "env" "ema" (func $internal4157))
+ (import "env" "fma" (func $internal4158))
+ (import "env" "gma" (func $internal4159))
+ (import "env" "hma" (func $internal4160))
+ (import "env" "ima" (func $internal4161))
+ (import "env" "jma" (func $internal4162))
+ (import "env" "kma" (func $internal4163))
+ (import "env" "lma" (func $internal4164))
+ (import "env" "mma" (func $internal4165))
+ (import "env" "nma" (func $internal4166))
+ (import "env" "oma" (func $internal4167))
+ (import "env" "pma" (func $internal4168))
+ (import "env" "qma" (func $internal4169))
+ (import "env" "rma" (func $internal4170))
+ (import "env" "sma" (func $internal4171))
+ (import "env" "tma" (func $internal4172))
+ (import "env" "uma" (func $internal4173))
+ (import "env" "vma" (func $internal4174))
+ (import "env" "wma" (func $internal4175))
+ (import "env" "xma" (func $internal4176))
+ (import "env" "yma" (func $internal4177))
+ (import "env" "zma" (func $internal4178))
+ (import "env" "Ama" (func $internal4179))
+ (import "env" "Bma" (func $internal4180))
+ (import "env" "Cma" (func $internal4181))
+ (import "env" "Dma" (func $internal4182))
+ (import "env" "Ema" (func $internal4183))
+ (import "env" "Fma" (func $internal4184))
+ (import "env" "Gma" (func $internal4185))
+ (import "env" "Hma" (func $internal4186))
+ (import "env" "Ima" (func $internal4187))
+ (import "env" "Jma" (func $internal4188))
+ (import "env" "Kma" (func $internal4189))
+ (import "env" "Lma" (func $internal4190))
+ (import "env" "Mma" (func $internal4191))
+ (import "env" "Nma" (func $internal4192))
+ (import "env" "Oma" (func $internal4193))
+ (import "env" "Pma" (func $internal4194))
+ (import "env" "Qma" (func $internal4195))
+ (import "env" "Rma" (func $internal4196))
+ (import "env" "Sma" (func $internal4197))
+ (import "env" "Tma" (func $internal4198))
+ (import "env" "Uma" (func $internal4199))
+ (import "env" "Vma" (func $internal4200))
+ (import "env" "Wma" (func $internal4201))
+ (import "env" "Xma" (func $internal4202))
+ (import "env" "Yma" (func $internal4203))
+ (import "env" "Zma" (func $internal4204))
+ (import "env" "_ma" (func $internal4205))
+ (import "env" "$ma" (func $internal4206))
+ (import "env" "ana" (func $internal4207))
+ (import "env" "bna" (func $internal4208))
+ (import "env" "cna" (func $internal4209))
+ (import "env" "dna" (func $internal4210))
+ (import "env" "ena" (func $internal4211))
+ (import "env" "fna" (func $internal4212))
+ (import "env" "gna" (func $internal4213))
+ (import "env" "hna" (func $internal4214))
+ (import "env" "ina" (func $internal4215))
+ (import "env" "jna" (func $internal4216))
+ (import "env" "kna" (func $internal4217))
+ (import "env" "lna" (func $internal4218))
+ (import "env" "mna" (func $internal4219))
+ (import "env" "nna" (func $internal4220))
+ (import "env" "ona" (func $internal4221))
+ (import "env" "pna" (func $internal4222))
+ (import "env" "qna" (func $internal4223))
+ (import "env" "rna" (func $internal4224))
+ (import "env" "sna" (func $internal4225))
+ (import "env" "tna" (func $internal4226))
+ (import "env" "una" (func $internal4227))
+ (import "env" "vna" (func $internal4228))
+ (import "env" "wna" (func $internal4229))
+ (import "env" "xna" (func $internal4230))
+ (import "env" "yna" (func $internal4231))
+ (import "env" "zna" (func $internal4232))
+ (import "env" "Ana" (func $internal4233))
+ (import "env" "Bna" (func $internal4234))
+ (import "env" "Cna" (func $internal4235))
+ (import "env" "Dna" (func $internal4236))
+ (import "env" "Ena" (func $internal4237))
+ (import "env" "Fna" (func $internal4238))
+ (import "env" "Gna" (func $internal4239))
+ (import "env" "Hna" (func $internal4240))
+ (import "env" "Ina" (func $internal4241))
+ (import "env" "Jna" (func $internal4242))
+ (import "env" "Kna" (func $internal4243))
+ (import "env" "Lna" (func $internal4244))
+ (import "env" "Mna" (func $internal4245))
+ (import "env" "Nna" (func $internal4246))
+ (import "env" "Ona" (func $internal4247))
+ (import "env" "Pna" (func $internal4248))
+ (import "env" "Qna" (func $internal4249))
+ (import "env" "Rna" (func $internal4250))
+ (import "env" "Sna" (func $internal4251))
+ (import "env" "Tna" (func $internal4252))
+ (import "env" "Una" (func $internal4253))
+ (import "env" "Vna" (func $internal4254))
+ (import "env" "Wna" (func $internal4255))
+ (import "env" "Xna" (func $internal4256))
+ (import "env" "Yna" (func $internal4257))
+ (import "env" "Zna" (func $internal4258))
+ (import "env" "_na" (func $internal4259))
+ (import "env" "$na" (func $internal4260))
+ (import "env" "aoa" (func $internal4261))
+ (import "env" "boa" (func $internal4262))
+ (import "env" "coa" (func $internal4263))
+ (import "env" "doa" (func $internal4264))
+ (import "env" "eoa" (func $internal4265))
+ (import "env" "foa" (func $internal4266))
+ (import "env" "goa" (func $internal4267))
+ (import "env" "hoa" (func $internal4268))
+ (import "env" "ioa" (func $internal4269))
+ (import "env" "joa" (func $internal4270))
+ (import "env" "koa" (func $internal4271))
+ (import "env" "loa" (func $internal4272))
+ (import "env" "moa" (func $internal4273))
+ (import "env" "noa" (func $internal4274))
+ (import "env" "ooa" (func $internal4275))
+ (import "env" "poa" (func $internal4276))
+ (import "env" "qoa" (func $internal4277))
+ (import "env" "roa" (func $internal4278))
+ (import "env" "soa" (func $internal4279))
+ (import "env" "toa" (func $internal4280))
+ (import "env" "uoa" (func $internal4281))
+ (import "env" "voa" (func $internal4282))
+ (import "env" "woa" (func $internal4283))
+ (import "env" "xoa" (func $internal4284))
+ (import "env" "yoa" (func $internal4285))
+ (import "env" "zoa" (func $internal4286))
+ (import "env" "Aoa" (func $internal4287))
+ (import "env" "Boa" (func $internal4288))
+ (import "env" "Coa" (func $internal4289))
+ (import "env" "Doa" (func $internal4290))
+ (import "env" "Eoa" (func $internal4291))
+ (import "env" "Foa" (func $internal4292))
+ (import "env" "Goa" (func $internal4293))
+ (import "env" "Hoa" (func $internal4294))
+ (import "env" "Ioa" (func $internal4295))
+ (import "env" "Joa" (func $internal4296))
+ (import "env" "Koa" (func $internal4297))
+ (import "env" "Loa" (func $internal4298))
+ (import "env" "Moa" (func $internal4299))
+ (import "env" "Noa" (func $internal4300))
+ (import "env" "Ooa" (func $internal4301))
+ (import "env" "Poa" (func $internal4302))
+ (import "env" "Qoa" (func $internal4303))
+ (import "env" "Roa" (func $internal4304))
+ (import "env" "Soa" (func $internal4305))
+ (import "env" "Toa" (func $internal4306))
+ (import "env" "Uoa" (func $internal4307))
+ (import "env" "Voa" (func $internal4308))
+ (import "env" "Woa" (func $internal4309))
+ (import "env" "Xoa" (func $internal4310))
+ (import "env" "Yoa" (func $internal4311))
+ (import "env" "Zoa" (func $internal4312))
+ (import "env" "_oa" (func $internal4313))
+ (import "env" "$oa" (func $internal4314))
+ (import "env" "apa" (func $internal4315))
+ (import "env" "bpa" (func $internal4316))
+ (import "env" "cpa" (func $internal4317))
+ (import "env" "dpa" (func $internal4318))
+ (import "env" "epa" (func $internal4319))
+ (import "env" "fpa" (func $internal4320))
+ (import "env" "gpa" (func $internal4321))
+ (import "env" "hpa" (func $internal4322))
+ (import "env" "ipa" (func $internal4323))
+ (import "env" "jpa" (func $internal4324))
+ (import "env" "kpa" (func $internal4325))
+ (import "env" "lpa" (func $internal4326))
+ (import "env" "mpa" (func $internal4327))
+ (import "env" "npa" (func $internal4328))
+ (import "env" "opa" (func $internal4329))
+ (import "env" "ppa" (func $internal4330))
+ (import "env" "qpa" (func $internal4331))
+ (import "env" "rpa" (func $internal4332))
+ (import "env" "spa" (func $internal4333))
+ (import "env" "tpa" (func $internal4334))
+ (import "env" "upa" (func $internal4335))
+ (import "env" "vpa" (func $internal4336))
+ (import "env" "wpa" (func $internal4337))
+ (import "env" "xpa" (func $internal4338))
+ (import "env" "ypa" (func $internal4339))
+ (import "env" "zpa" (func $internal4340))
+ (import "env" "Apa" (func $internal4341))
+ (import "env" "Bpa" (func $internal4342))
+ (import "env" "Cpa" (func $internal4343))
+ (import "env" "Dpa" (func $internal4344))
+ (import "env" "Epa" (func $internal4345))
+ (import "env" "Fpa" (func $internal4346))
+ (import "env" "Gpa" (func $internal4347))
+ (import "env" "Hpa" (func $internal4348))
+ (import "env" "Ipa" (func $internal4349))
+ (import "env" "Jpa" (func $internal4350))
+ (import "env" "Kpa" (func $internal4351))
+ (import "env" "Lpa" (func $internal4352))
+ (import "env" "Mpa" (func $internal4353))
+ (import "env" "Npa" (func $internal4354))
+ (import "env" "Opa" (func $internal4355))
+ (import "env" "Ppa" (func $internal4356))
+ (import "env" "Qpa" (func $internal4357))
+ (import "env" "Rpa" (func $internal4358))
+ (import "env" "Spa" (func $internal4359))
+ (import "env" "Tpa" (func $internal4360))
+ (import "env" "Upa" (func $internal4361))
+ (import "env" "Vpa" (func $internal4362))
+ (import "env" "Wpa" (func $internal4363))
+ (import "env" "Xpa" (func $internal4364))
+ (import "env" "Ypa" (func $internal4365))
+ (import "env" "Zpa" (func $internal4366))
+ (import "env" "_pa" (func $internal4367))
+ (import "env" "$pa" (func $internal4368))
+ (import "env" "aqa" (func $internal4369))
+ (import "env" "bqa" (func $internal4370))
+ (import "env" "cqa" (func $internal4371))
+ (import "env" "dqa" (func $internal4372))
+ (import "env" "eqa" (func $internal4373))
+ (import "env" "fqa" (func $internal4374))
+ (import "env" "gqa" (func $internal4375))
+ (import "env" "hqa" (func $internal4376))
+ (import "env" "iqa" (func $internal4377))
+ (import "env" "jqa" (func $internal4378))
+ (import "env" "kqa" (func $internal4379))
+ (import "env" "lqa" (func $internal4380))
+ (import "env" "mqa" (func $internal4381))
+ (import "env" "nqa" (func $internal4382))
+ (import "env" "oqa" (func $internal4383))
+ (import "env" "pqa" (func $internal4384))
+ (import "env" "qqa" (func $internal4385))
+ (import "env" "rqa" (func $internal4386))
+ (import "env" "sqa" (func $internal4387))
+ (import "env" "tqa" (func $internal4388))
+ (import "env" "uqa" (func $internal4389))
+ (import "env" "vqa" (func $internal4390))
+ (import "env" "wqa" (func $internal4391))
+ (import "env" "xqa" (func $internal4392))
+ (import "env" "yqa" (func $internal4393))
+ (import "env" "zqa" (func $internal4394))
+ (import "env" "Aqa" (func $internal4395))
+ (import "env" "Bqa" (func $internal4396))
+ (import "env" "Cqa" (func $internal4397))
+ (import "env" "Dqa" (func $internal4398))
+ (import "env" "Eqa" (func $internal4399))
+ (import "env" "Fqa" (func $internal4400))
+ (import "env" "Gqa" (func $internal4401))
+ (import "env" "Hqa" (func $internal4402))
+ (import "env" "Iqa" (func $internal4403))
+ (import "env" "Jqa" (func $internal4404))
+ (import "env" "Kqa" (func $internal4405))
+ (import "env" "Lqa" (func $internal4406))
+ (import "env" "Mqa" (func $internal4407))
+ (import "env" "Nqa" (func $internal4408))
+ (import "env" "Oqa" (func $internal4409))
+ (import "env" "Pqa" (func $internal4410))
+ (import "env" "Qqa" (func $internal4411))
+ (import "env" "Rqa" (func $internal4412))
+ (import "env" "Sqa" (func $internal4413))
+ (import "env" "Tqa" (func $internal4414))
+ (import "env" "Uqa" (func $internal4415))
+ (import "env" "Vqa" (func $internal4416))
+ (import "env" "Wqa" (func $internal4417))
+ (import "env" "Xqa" (func $internal4418))
+ (import "env" "Yqa" (func $internal4419))
+ (import "env" "Zqa" (func $internal4420))
+ (import "env" "_qa" (func $internal4421))
+ (import "env" "$qa" (func $internal4422))
+ (import "env" "ara" (func $internal4423))
+ (import "env" "bra" (func $internal4424))
+ (import "env" "cra" (func $internal4425))
+ (import "env" "dra" (func $internal4426))
+ (import "env" "era" (func $internal4427))
+ (import "env" "fra" (func $internal4428))
+ (import "env" "gra" (func $internal4429))
+ (import "env" "hra" (func $internal4430))
+ (import "env" "ira" (func $internal4431))
+ (import "env" "jra" (func $internal4432))
+ (import "env" "kra" (func $internal4433))
+ (import "env" "lra" (func $internal4434))
+ (import "env" "mra" (func $internal4435))
+ (import "env" "nra" (func $internal4436))
+ (import "env" "ora" (func $internal4437))
+ (import "env" "pra" (func $internal4438))
+ (import "env" "qra" (func $internal4439))
+ (import "env" "rra" (func $internal4440))
+ (import "env" "sra" (func $internal4441))
+ (import "env" "tra" (func $internal4442))
+ (import "env" "ura" (func $internal4443))
+ (import "env" "vra" (func $internal4444))
+ (import "env" "wra" (func $internal4445))
+ (import "env" "xra" (func $internal4446))
+ (import "env" "yra" (func $internal4447))
+ (import "env" "zra" (func $internal4448))
+ (import "env" "Ara" (func $internal4449))
+ (import "env" "Bra" (func $internal4450))
+ (import "env" "Cra" (func $internal4451))
+ (import "env" "Dra" (func $internal4452))
+ (import "env" "Era" (func $internal4453))
+ (import "env" "Fra" (func $internal4454))
+ (import "env" "Gra" (func $internal4455))
+ (import "env" "Hra" (func $internal4456))
+ (import "env" "Ira" (func $internal4457))
+ (import "env" "Jra" (func $internal4458))
+ (import "env" "Kra" (func $internal4459))
+ (import "env" "Lra" (func $internal4460))
+ (import "env" "Mra" (func $internal4461))
+ (import "env" "Nra" (func $internal4462))
+ (import "env" "Ora" (func $internal4463))
+ (import "env" "Pra" (func $internal4464))
+ (import "env" "Qra" (func $internal4465))
+ (import "env" "Rra" (func $internal4466))
+ (import "env" "Sra" (func $internal4467))
+ (import "env" "Tra" (func $internal4468))
+ (import "env" "Ura" (func $internal4469))
+ (import "env" "Vra" (func $internal4470))
+ (import "env" "Wra" (func $internal4471))
+ (import "env" "Xra" (func $internal4472))
+ (import "env" "Yra" (func $internal4473))
+ (import "env" "Zra" (func $internal4474))
+ (import "env" "_ra" (func $internal4475))
+ (import "env" "$ra" (func $internal4476))
+ (import "env" "asa" (func $internal4477))
+ (import "env" "bsa" (func $internal4478))
+ (import "env" "csa" (func $internal4479))
+ (import "env" "dsa" (func $internal4480))
+ (import "env" "esa" (func $internal4481))
+ (import "env" "fsa" (func $internal4482))
+ (import "env" "gsa" (func $internal4483))
+ (import "env" "hsa" (func $internal4484))
+ (import "env" "isa" (func $internal4485))
+ (import "env" "jsa" (func $internal4486))
+ (import "env" "ksa" (func $internal4487))
+ (import "env" "lsa" (func $internal4488))
+ (import "env" "msa" (func $internal4489))
+ (import "env" "nsa" (func $internal4490))
+ (import "env" "osa" (func $internal4491))
+ (import "env" "psa" (func $internal4492))
+ (import "env" "qsa" (func $internal4493))
+ (import "env" "rsa" (func $internal4494))
+ (import "env" "ssa" (func $internal4495))
+ (import "env" "tsa" (func $internal4496))
+ (import "env" "usa" (func $internal4497))
+ (import "env" "vsa" (func $internal4498))
+ (import "env" "wsa" (func $internal4499))
+ (import "env" "xsa" (func $internal4500))
+ (import "env" "ysa" (func $internal4501))
+ (import "env" "zsa" (func $internal4502))
+ (import "env" "Asa" (func $internal4503))
+ (import "env" "Bsa" (func $internal4504))
+ (import "env" "Csa" (func $internal4505))
+ (import "env" "Dsa" (func $internal4506))
+ (import "env" "Esa" (func $internal4507))
+ (import "env" "Fsa" (func $internal4508))
+ (import "env" "Gsa" (func $internal4509))
+ (import "env" "Hsa" (func $internal4510))
+ (import "env" "Isa" (func $internal4511))
+ (import "env" "Jsa" (func $internal4512))
+ (import "env" "Ksa" (func $internal4513))
+ (import "env" "Lsa" (func $internal4514))
+ (import "env" "Msa" (func $internal4515))
+ (import "env" "Nsa" (func $internal4516))
+ (import "env" "Osa" (func $internal4517))
+ (import "env" "Psa" (func $internal4518))
+ (import "env" "Qsa" (func $internal4519))
+ (import "env" "Rsa" (func $internal4520))
+ (import "env" "Ssa" (func $internal4521))
+ (import "env" "Tsa" (func $internal4522))
+ (import "env" "Usa" (func $internal4523))
+ (import "env" "Vsa" (func $internal4524))
+ (import "env" "Wsa" (func $internal4525))
+ (import "env" "Xsa" (func $internal4526))
+ (import "env" "Ysa" (func $internal4527))
+ (import "env" "Zsa" (func $internal4528))
+ (import "env" "_sa" (func $internal4529))
+ (import "env" "$sa" (func $internal4530))
+ (import "env" "ata" (func $internal4531))
+ (import "env" "bta" (func $internal4532))
+ (import "env" "cta" (func $internal4533))
+ (import "env" "dta" (func $internal4534))
+ (import "env" "eta" (func $internal4535))
+ (import "env" "fta" (func $internal4536))
+ (import "env" "gta" (func $internal4537))
+ (import "env" "hta" (func $internal4538))
+ (import "env" "ita" (func $internal4539))
+ (import "env" "jta" (func $internal4540))
+ (import "env" "kta" (func $internal4541))
+ (import "env" "lta" (func $internal4542))
+ (import "env" "mta" (func $internal4543))
+ (import "env" "nta" (func $internal4544))
+ (import "env" "ota" (func $internal4545))
+ (import "env" "pta" (func $internal4546))
+ (import "env" "qta" (func $internal4547))
+ (import "env" "rta" (func $internal4548))
+ (import "env" "sta" (func $internal4549))
+ (import "env" "tta" (func $internal4550))
+ (import "env" "uta" (func $internal4551))
+ (import "env" "vta" (func $internal4552))
+ (import "env" "wta" (func $internal4553))
+ (import "env" "xta" (func $internal4554))
+ (import "env" "yta" (func $internal4555))
+ (import "env" "zta" (func $internal4556))
+ (import "env" "Ata" (func $internal4557))
+ (import "env" "Bta" (func $internal4558))
+ (import "env" "Cta" (func $internal4559))
+ (import "env" "Dta" (func $internal4560))
+ (import "env" "Eta" (func $internal4561))
+ (import "env" "Fta" (func $internal4562))
+ (import "env" "Gta" (func $internal4563))
+ (import "env" "Hta" (func $internal4564))
+ (import "env" "Ita" (func $internal4565))
+ (import "env" "Jta" (func $internal4566))
+ (import "env" "Kta" (func $internal4567))
+ (import "env" "Lta" (func $internal4568))
+ (import "env" "Mta" (func $internal4569))
+ (import "env" "Nta" (func $internal4570))
+ (import "env" "Ota" (func $internal4571))
+ (import "env" "Pta" (func $internal4572))
+ (import "env" "Qta" (func $internal4573))
+ (import "env" "Rta" (func $internal4574))
+ (import "env" "Sta" (func $internal4575))
+ (import "env" "Tta" (func $internal4576))
+ (import "env" "Uta" (func $internal4577))
+ (import "env" "Vta" (func $internal4578))
+ (import "env" "Wta" (func $internal4579))
+ (import "env" "Xta" (func $internal4580))
+ (import "env" "Yta" (func $internal4581))
+ (import "env" "Zta" (func $internal4582))
+ (import "env" "_ta" (func $internal4583))
+ (import "env" "$ta" (func $internal4584))
+ (import "env" "aua" (func $internal4585))
+ (import "env" "bua" (func $internal4586))
+ (import "env" "cua" (func $internal4587))
+ (import "env" "dua" (func $internal4588))
+ (import "env" "eua" (func $internal4589))
+ (import "env" "fua" (func $internal4590))
+ (import "env" "gua" (func $internal4591))
+ (import "env" "hua" (func $internal4592))
+ (import "env" "iua" (func $internal4593))
+ (import "env" "jua" (func $internal4594))
+ (import "env" "kua" (func $internal4595))
+ (import "env" "lua" (func $internal4596))
+ (import "env" "mua" (func $internal4597))
+ (import "env" "nua" (func $internal4598))
+ (import "env" "oua" (func $internal4599))
+ (import "env" "pua" (func $internal4600))
+ (import "env" "qua" (func $internal4601))
+ (import "env" "rua" (func $internal4602))
+ (import "env" "sua" (func $internal4603))
+ (import "env" "tua" (func $internal4604))
+ (import "env" "uua" (func $internal4605))
+ (import "env" "vua" (func $internal4606))
+ (import "env" "wua" (func $internal4607))
+ (import "env" "xua" (func $internal4608))
+ (import "env" "yua" (func $internal4609))
+ (import "env" "zua" (func $internal4610))
+ (import "env" "Aua" (func $internal4611))
+ (import "env" "Bua" (func $internal4612))
+ (import "env" "Cua" (func $internal4613))
+ (import "env" "Dua" (func $internal4614))
+ (import "env" "Eua" (func $internal4615))
+ (import "env" "Fua" (func $internal4616))
+ (import "env" "Gua" (func $internal4617))
+ (import "env" "Hua" (func $internal4618))
+ (import "env" "Iua" (func $internal4619))
+ (import "env" "Jua" (func $internal4620))
+ (import "env" "Kua" (func $internal4621))
+ (import "env" "Lua" (func $internal4622))
+ (import "env" "Mua" (func $internal4623))
+ (import "env" "Nua" (func $internal4624))
+ (import "env" "Oua" (func $internal4625))
+ (import "env" "Pua" (func $internal4626))
+ (import "env" "Qua" (func $internal4627))
+ (import "env" "Rua" (func $internal4628))
+ (import "env" "Sua" (func $internal4629))
+ (import "env" "Tua" (func $internal4630))
+ (import "env" "Uua" (func $internal4631))
+ (import "env" "Vua" (func $internal4632))
+ (import "env" "Wua" (func $internal4633))
+ (import "env" "Xua" (func $internal4634))
+ (import "env" "Yua" (func $internal4635))
+ (import "env" "Zua" (func $internal4636))
+ (import "env" "_ua" (func $internal4637))
+ (import "env" "$ua" (func $internal4638))
+ (import "env" "ava" (func $internal4639))
+ (import "env" "bva" (func $internal4640))
+ (import "env" "cva" (func $internal4641))
+ (import "env" "dva" (func $internal4642))
+ (import "env" "eva" (func $internal4643))
+ (import "env" "fva" (func $internal4644))
+ (import "env" "gva" (func $internal4645))
+ (import "env" "hva" (func $internal4646))
+ (import "env" "iva" (func $internal4647))
+ (import "env" "jva" (func $internal4648))
+ (import "env" "kva" (func $internal4649))
+ (import "env" "lva" (func $internal4650))
+ (import "env" "mva" (func $internal4651))
+ (import "env" "nva" (func $internal4652))
+ (import "env" "ova" (func $internal4653))
+ (import "env" "pva" (func $internal4654))
+ (import "env" "qva" (func $internal4655))
+ (import "env" "rva" (func $internal4656))
+ (import "env" "sva" (func $internal4657))
+ (import "env" "tva" (func $internal4658))
+ (import "env" "uva" (func $internal4659))
+ (import "env" "vva" (func $internal4660))
+ (import "env" "wva" (func $internal4661))
+ (import "env" "xva" (func $internal4662))
+ (import "env" "yva" (func $internal4663))
+ (import "env" "zva" (func $internal4664))
+ (import "env" "Ava" (func $internal4665))
+ (import "env" "Bva" (func $internal4666))
+ (import "env" "Cva" (func $internal4667))
+ (import "env" "Dva" (func $internal4668))
+ (import "env" "Eva" (func $internal4669))
+ (import "env" "Fva" (func $internal4670))
+ (import "env" "Gva" (func $internal4671))
+ (import "env" "Hva" (func $internal4672))
+ (import "env" "Iva" (func $internal4673))
+ (import "env" "Jva" (func $internal4674))
+ (import "env" "Kva" (func $internal4675))
+ (import "env" "Lva" (func $internal4676))
+ (import "env" "Mva" (func $internal4677))
+ (import "env" "Nva" (func $internal4678))
+ (import "env" "Ova" (func $internal4679))
+ (import "env" "Pva" (func $internal4680))
+ (import "env" "Qva" (func $internal4681))
+ (import "env" "Rva" (func $internal4682))
+ (import "env" "Sva" (func $internal4683))
+ (import "env" "Tva" (func $internal4684))
+ (import "env" "Uva" (func $internal4685))
+ (import "env" "Vva" (func $internal4686))
+ (import "env" "Wva" (func $internal4687))
+ (import "env" "Xva" (func $internal4688))
+ (import "env" "Yva" (func $internal4689))
+ (import "env" "Zva" (func $internal4690))
+ (import "env" "_va" (func $internal4691))
+ (import "env" "$va" (func $internal4692))
+ (import "env" "awa" (func $internal4693))
+ (import "env" "bwa" (func $internal4694))
+ (import "env" "cwa" (func $internal4695))
+ (import "env" "dwa" (func $internal4696))
+ (import "env" "ewa" (func $internal4697))
+ (import "env" "fwa" (func $internal4698))
+ (import "env" "gwa" (func $internal4699))
+ (import "env" "hwa" (func $internal4700))
+ (import "env" "iwa" (func $internal4701))
+ (import "env" "jwa" (func $internal4702))
+ (import "env" "kwa" (func $internal4703))
+ (import "env" "lwa" (func $internal4704))
+ (import "env" "mwa" (func $internal4705))
+ (import "env" "nwa" (func $internal4706))
+ (import "env" "owa" (func $internal4707))
+ (import "env" "pwa" (func $internal4708))
+ (import "env" "qwa" (func $internal4709))
+ (import "env" "rwa" (func $internal4710))
+ (import "env" "swa" (func $internal4711))
+ (import "env" "twa" (func $internal4712))
+ (import "env" "uwa" (func $internal4713))
+ (import "env" "vwa" (func $internal4714))
+ (import "env" "wwa" (func $internal4715))
+ (import "env" "xwa" (func $internal4716))
+ (import "env" "ywa" (func $internal4717))
+ (import "env" "zwa" (func $internal4718))
+ (import "env" "Awa" (func $internal4719))
+ (import "env" "Bwa" (func $internal4720))
+ (import "env" "Cwa" (func $internal4721))
+ (import "env" "Dwa" (func $internal4722))
+ (import "env" "Ewa" (func $internal4723))
+ (import "env" "Fwa" (func $internal4724))
+ (import "env" "Gwa" (func $internal4725))
+ (import "env" "Hwa" (func $internal4726))
+ (import "env" "Iwa" (func $internal4727))
+ (import "env" "Jwa" (func $internal4728))
+ (import "env" "Kwa" (func $internal4729))
+ (import "env" "Lwa" (func $internal4730))
+ (import "env" "Mwa" (func $internal4731))
+ (import "env" "Nwa" (func $internal4732))
+ (import "env" "Owa" (func $internal4733))
+ (import "env" "Pwa" (func $internal4734))
+ (import "env" "Qwa" (func $internal4735))
+ (import "env" "Rwa" (func $internal4736))
+ (import "env" "Swa" (func $internal4737))
+ (import "env" "Twa" (func $internal4738))
+ (import "env" "Uwa" (func $internal4739))
+ (import "env" "Vwa" (func $internal4740))
+ (import "env" "Wwa" (func $internal4741))
+ (import "env" "Xwa" (func $internal4742))
+ (import "env" "Ywa" (func $internal4743))
+ (import "env" "Zwa" (func $internal4744))
+ (import "env" "_wa" (func $internal4745))
+ (import "env" "$wa" (func $internal4746))
+ (import "env" "axa" (func $internal4747))
+ (import "env" "bxa" (func $internal4748))
+ (import "env" "cxa" (func $internal4749))
+ (import "env" "dxa" (func $internal4750))
+ (import "env" "exa" (func $internal4751))
+ (import "env" "fxa" (func $internal4752))
+ (import "env" "gxa" (func $internal4753))
+ (import "env" "hxa" (func $internal4754))
+ (import "env" "ixa" (func $internal4755))
+ (import "env" "jxa" (func $internal4756))
+ (import "env" "kxa" (func $internal4757))
+ (import "env" "lxa" (func $internal4758))
+ (import "env" "mxa" (func $internal4759))
+ (import "env" "nxa" (func $internal4760))
+ (import "env" "oxa" (func $internal4761))
+ (import "env" "pxa" (func $internal4762))
+ (import "env" "qxa" (func $internal4763))
+ (import "env" "rxa" (func $internal4764))
+ (import "env" "sxa" (func $internal4765))
+ (import "env" "txa" (func $internal4766))
+ (import "env" "uxa" (func $internal4767))
+ (import "env" "vxa" (func $internal4768))
+ (import "env" "wxa" (func $internal4769))
+ (import "env" "xxa" (func $internal4770))
+ (import "env" "yxa" (func $internal4771))
+ (import "env" "zxa" (func $internal4772))
+ (import "env" "Axa" (func $internal4773))
+ (import "env" "Bxa" (func $internal4774))
+ (import "env" "Cxa" (func $internal4775))
+ (import "env" "Dxa" (func $internal4776))
+ (import "env" "Exa" (func $internal4777))
+ (import "env" "Fxa" (func $internal4778))
+ (import "env" "Gxa" (func $internal4779))
+ (import "env" "Hxa" (func $internal4780))
+ (import "env" "Ixa" (func $internal4781))
+ (import "env" "Jxa" (func $internal4782))
+ (import "env" "Kxa" (func $internal4783))
+ (import "env" "Lxa" (func $internal4784))
+ (import "env" "Mxa" (func $internal4785))
+ (import "env" "Nxa" (func $internal4786))
+ (import "env" "Oxa" (func $internal4787))
+ (import "env" "Pxa" (func $internal4788))
+ (import "env" "Qxa" (func $internal4789))
+ (import "env" "Rxa" (func $internal4790))
+ (import "env" "Sxa" (func $internal4791))
+ (import "env" "Txa" (func $internal4792))
+ (import "env" "Uxa" (func $internal4793))
+ (import "env" "Vxa" (func $internal4794))
+ (import "env" "Wxa" (func $internal4795))
+ (import "env" "Xxa" (func $internal4796))
+ (import "env" "Yxa" (func $internal4797))
+ (import "env" "Zxa" (func $internal4798))
+ (import "env" "_xa" (func $internal4799))
+ (import "env" "$xa" (func $internal4800))
+ (import "env" "aya" (func $internal4801))
+ (import "env" "bya" (func $internal4802))
+ (import "env" "cya" (func $internal4803))
+ (import "env" "dya" (func $internal4804))
+ (import "env" "eya" (func $internal4805))
+ (import "env" "fya" (func $internal4806))
+ (import "env" "gya" (func $internal4807))
+ (import "env" "hya" (func $internal4808))
+ (import "env" "iya" (func $internal4809))
+ (import "env" "jya" (func $internal4810))
+ (import "env" "kya" (func $internal4811))
+ (import "env" "lya" (func $internal4812))
+ (import "env" "mya" (func $internal4813))
+ (import "env" "nya" (func $internal4814))
+ (import "env" "oya" (func $internal4815))
+ (import "env" "pya" (func $internal4816))
+ (import "env" "qya" (func $internal4817))
+ (import "env" "rya" (func $internal4818))
+ (import "env" "sya" (func $internal4819))
+ (import "env" "tya" (func $internal4820))
+ (import "env" "uya" (func $internal4821))
+ (import "env" "vya" (func $internal4822))
+ (import "env" "wya" (func $internal4823))
+ (import "env" "xya" (func $internal4824))
+ (import "env" "yya" (func $internal4825))
+ (import "env" "zya" (func $internal4826))
+ (import "env" "Aya" (func $internal4827))
+ (import "env" "Bya" (func $internal4828))
+ (import "env" "Cya" (func $internal4829))
+ (import "env" "Dya" (func $internal4830))
+ (import "env" "Eya" (func $internal4831))
+ (import "env" "Fya" (func $internal4832))
+ (import "env" "Gya" (func $internal4833))
+ (import "env" "Hya" (func $internal4834))
+ (import "env" "Iya" (func $internal4835))
+ (import "env" "Jya" (func $internal4836))
+ (import "env" "Kya" (func $internal4837))
+ (import "env" "Lya" (func $internal4838))
+ (import "env" "Mya" (func $internal4839))
+ (import "env" "Nya" (func $internal4840))
+ (import "env" "Oya" (func $internal4841))
+ (import "env" "Pya" (func $internal4842))
+ (import "env" "Qya" (func $internal4843))
+ (import "env" "Rya" (func $internal4844))
+ (import "env" "Sya" (func $internal4845))
+ (import "env" "Tya" (func $internal4846))
+ (import "env" "Uya" (func $internal4847))
+ (import "env" "Vya" (func $internal4848))
+ (import "env" "Wya" (func $internal4849))
+ (import "env" "Xya" (func $internal4850))
+ (import "env" "Yya" (func $internal4851))
+ (import "env" "Zya" (func $internal4852))
+ (import "env" "_ya" (func $internal4853))
+ (import "env" "$ya" (func $internal4854))
+ (import "env" "aza" (func $internal4855))
+ (import "env" "bza" (func $internal4856))
+ (import "env" "cza" (func $internal4857))
+ (import "env" "dza" (func $internal4858))
+ (import "env" "eza" (func $internal4859))
+ (import "env" "fza" (func $internal4860))
+ (import "env" "gza" (func $internal4861))
+ (import "env" "hza" (func $internal4862))
+ (import "env" "iza" (func $internal4863))
+ (import "env" "jza" (func $internal4864))
+ (import "env" "kza" (func $internal4865))
+ (import "env" "lza" (func $internal4866))
+ (import "env" "mza" (func $internal4867))
+ (import "env" "nza" (func $internal4868))
+ (import "env" "oza" (func $internal4869))
+ (import "env" "pza" (func $internal4870))
+ (import "env" "qza" (func $internal4871))
+ (import "env" "rza" (func $internal4872))
+ (import "env" "sza" (func $internal4873))
+ (import "env" "tza" (func $internal4874))
+ (import "env" "uza" (func $internal4875))
+ (import "env" "vza" (func $internal4876))
+ (import "env" "wza" (func $internal4877))
+ (import "env" "xza" (func $internal4878))
+ (import "env" "yza" (func $internal4879))
+ (import "env" "zza" (func $internal4880))
+ (import "env" "Aza" (func $internal4881))
+ (import "env" "Bza" (func $internal4882))
+ (import "env" "Cza" (func $internal4883))
+ (import "env" "Dza" (func $internal4884))
+ (import "env" "Eza" (func $internal4885))
+ (import "env" "Fza" (func $internal4886))
+ (import "env" "Gza" (func $internal4887))
+ (import "env" "Hza" (func $internal4888))
+ (import "env" "Iza" (func $internal4889))
+ (import "env" "Jza" (func $internal4890))
+ (import "env" "Kza" (func $internal4891))
+ (import "env" "Lza" (func $internal4892))
+ (import "env" "Mza" (func $internal4893))
+ (import "env" "Nza" (func $internal4894))
+ (import "env" "Oza" (func $internal4895))
+ (import "env" "Pza" (func $internal4896))
+ (import "env" "Qza" (func $internal4897))
+ (import "env" "Rza" (func $internal4898))
+ (import "env" "Sza" (func $internal4899))
+ (import "env" "Tza" (func $internal4900))
+ (import "env" "Uza" (func $internal4901))
+ (import "env" "Vza" (func $internal4902))
+ (import "env" "Wza" (func $internal4903))
+ (import "env" "Xza" (func $internal4904))
+ (import "env" "Yza" (func $internal4905))
+ (import "env" "Zza" (func $internal4906))
+ (import "env" "_za" (func $internal4907))
+ (import "env" "$za" (func $internal4908))
+ (import "env" "aAa" (func $internal4909))
+ (import "env" "bAa" (func $internal4910))
+ (import "env" "cAa" (func $internal4911))
+ (import "env" "dAa" (func $internal4912))
+ (import "env" "eAa" (func $internal4913))
+ (import "env" "fAa" (func $internal4914))
+ (import "env" "gAa" (func $internal4915))
+ (import "env" "hAa" (func $internal4916))
+ (import "env" "iAa" (func $internal4917))
+ (import "env" "jAa" (func $internal4918))
+ (import "env" "kAa" (func $internal4919))
+ (import "env" "lAa" (func $internal4920))
+ (import "env" "mAa" (func $internal4921))
+ (import "env" "nAa" (func $internal4922))
+ (import "env" "oAa" (func $internal4923))
+ (import "env" "pAa" (func $internal4924))
+ (import "env" "qAa" (func $internal4925))
+ (import "env" "rAa" (func $internal4926))
+ (import "env" "sAa" (func $internal4927))
+ (import "env" "tAa" (func $internal4928))
+ (import "env" "uAa" (func $internal4929))
+ (import "env" "vAa" (func $internal4930))
+ (import "env" "wAa" (func $internal4931))
+ (import "env" "xAa" (func $internal4932))
+ (import "env" "yAa" (func $internal4933))
+ (import "env" "zAa" (func $internal4934))
+ (import "env" "AAa" (func $internal4935))
+ (import "env" "BAa" (func $internal4936))
+ (import "env" "CAa" (func $internal4937))
+ (import "env" "DAa" (func $internal4938))
+ (import "env" "EAa" (func $internal4939))
+ (import "env" "FAa" (func $internal4940))
+ (import "env" "GAa" (func $internal4941))
+ (import "env" "HAa" (func $internal4942))
+ (import "env" "IAa" (func $internal4943))
+ (import "env" "JAa" (func $internal4944))
+ (import "env" "KAa" (func $internal4945))
+ (import "env" "LAa" (func $internal4946))
+ (import "env" "MAa" (func $internal4947))
+ (import "env" "NAa" (func $internal4948))
+ (import "env" "OAa" (func $internal4949))
+ (import "env" "PAa" (func $internal4950))
+ (import "env" "QAa" (func $internal4951))
+ (import "env" "RAa" (func $internal4952))
+ (import "env" "SAa" (func $internal4953))
+ (import "env" "TAa" (func $internal4954))
+ (import "env" "UAa" (func $internal4955))
+ (import "env" "VAa" (func $internal4956))
+ (import "env" "WAa" (func $internal4957))
+ (import "env" "XAa" (func $internal4958))
+ (import "env" "YAa" (func $internal4959))
+ (import "env" "ZAa" (func $internal4960))
+ (import "env" "_Aa" (func $internal4961))
+ (import "env" "$Aa" (func $internal4962))
+ (import "env" "aBa" (func $internal4963))
+ (import "env" "bBa" (func $internal4964))
+ (import "env" "cBa" (func $internal4965))
+ (import "env" "dBa" (func $internal4966))
+ (import "env" "eBa" (func $internal4967))
+ (import "env" "fBa" (func $internal4968))
+ (import "env" "gBa" (func $internal4969))
+ (import "env" "hBa" (func $internal4970))
+ (import "env" "iBa" (func $internal4971))
+ (import "env" "jBa" (func $internal4972))
+ (import "env" "kBa" (func $internal4973))
+ (import "env" "lBa" (func $internal4974))
+ (import "env" "mBa" (func $internal4975))
+ (import "env" "nBa" (func $internal4976))
+ (import "env" "oBa" (func $internal4977))
+ (import "env" "pBa" (func $internal4978))
+ (import "env" "qBa" (func $internal4979))
+ (import "env" "rBa" (func $internal4980))
+ (import "env" "sBa" (func $internal4981))
+ (import "env" "tBa" (func $internal4982))
+ (import "env" "uBa" (func $internal4983))
+ (import "env" "vBa" (func $internal4984))
+ (import "env" "wBa" (func $internal4985))
+ (import "env" "xBa" (func $internal4986))
+ (import "env" "yBa" (func $internal4987))
+ (import "env" "zBa" (func $internal4988))
+ (import "env" "ABa" (func $internal4989))
+ (import "env" "BBa" (func $internal4990))
+ (import "env" "CBa" (func $internal4991))
+ (import "env" "DBa" (func $internal4992))
+ (import "env" "EBa" (func $internal4993))
+ (import "env" "FBa" (func $internal4994))
+ (import "env" "GBa" (func $internal4995))
+ (import "env" "HBa" (func $internal4996))
+ (import "env" "IBa" (func $internal4997))
+ (import "env" "JBa" (func $internal4998))
+ (import "env" "KBa" (func $internal4999))
+ (import "other" "anything" (func $internalInfinity))
+ (import "wasi_unstable" "f" (func $internal3_wasi))
+ (import "wasi_unstable" "LBa" (func $internal3_wasi_only))
+ (import "env" "MBa" (event $eventname1 (attr 0) (param i32)))
+ (event $event1 (attr 0) (param i32 i32))
+ (export "NBa" (func $foo1))
+ (export "OBa" (func $foo2))
+ (export "PBa" (event $event1))
+ (func $foo1
+  (nop)
+ )
+ (func $foo2
+  (nop)
+ )
+)
diff --git a/binaryen/test/passes/minify-imports-and-exports_all-features.wast b/binaryen/test/passes/minify-imports-and-exports_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/minify-imports-and-exports_all-features.wast
@@ -0,0 +1,5014 @@
+(module
+  (import "env" "longname1" (func $internal1))
+  (import "env" "longname2" (func $internal2))
+  (import "env" "global" (global i32))
+  (import "env" "longname3" (func $internal3))
+  (import "env" "longname4" (func $internal4))
+  (import "env" "longname5" (func $internal5))
+  (import "env" "longname6" (func $internal6))
+  (import "env" "longname7" (func $internal7))
+  (import "env" "longname8" (func $internal8))
+  (import "env" "longname9" (func $internal9))
+  (import "env" "longname10" (func $internal10))
+  (import "env" "longname11" (func $internal11))
+  (import "env" "longname12" (func $internal12))
+  (import "env" "longname13" (func $internal13))
+  (import "env" "longname14" (func $internal14))
+  (import "env" "longname15" (func $internal15))
+  (import "env" "longname16" (func $internal16))
+  (import "env" "longname17" (func $internal17))
+  (import "env" "longname18" (func $internal18))
+  (import "env" "longname19" (func $internal19))
+  (import "env" "longname20" (func $internal20))
+  (import "env" "longname21" (func $internal21))
+  (import "env" "longname22" (func $internal22))
+  (import "env" "longname23" (func $internal23))
+  (import "env" "longname24" (func $internal24))
+  (import "env" "longname25" (func $internal25))
+  (import "env" "longname26" (func $internal26))
+  (import "env" "longname27" (func $internal27))
+  (import "env" "longname28" (func $internal28))
+  (import "env" "longname29" (func $internal29))
+  (import "env" "longname30" (func $internal30))
+  (import "env" "longname31" (func $internal31))
+  (import "env" "longname32" (func $internal32))
+  (import "env" "longname33" (func $internal33))
+  (import "env" "longname34" (func $internal34))
+  (import "env" "longname35" (func $internal35))
+  (import "env" "longname36" (func $internal36))
+  (import "env" "longname37" (func $internal37))
+  (import "env" "longname38" (func $internal38))
+  (import "env" "longname39" (func $internal39))
+  (import "env" "longname40" (func $internal40))
+  (import "env" "longname41" (func $internal41))
+  (import "env" "longname42" (func $internal42))
+  (import "env" "longname43" (func $internal43))
+  (import "env" "longname44" (func $internal44))
+  (import "env" "longname45" (func $internal45))
+  (import "env" "longname46" (func $internal46))
+  (import "env" "longname47" (func $internal47))
+  (import "env" "longname48" (func $internal48))
+  (import "env" "longname49" (func $internal49))
+  (import "env" "longname50" (func $internal50))
+  (import "env" "longname51" (func $internal51))
+  (import "env" "longname52" (func $internal52))
+  (import "env" "longname53" (func $internal53))
+  (import "env" "longname54" (func $internal54))
+  (import "env" "longname55" (func $internal55))
+  (import "env" "longname56" (func $internal56))
+  (import "env" "longname57" (func $internal57))
+  (import "env" "longname58" (func $internal58))
+  (import "env" "longname59" (func $internal59))
+  (import "env" "longname60" (func $internal60))
+  (import "env" "longname61" (func $internal61))
+  (import "env" "longname62" (func $internal62))
+  (import "env" "longname63" (func $internal63))
+  (import "env" "longname64" (func $internal64))
+  (import "env" "longname65" (func $internal65))
+  (import "env" "longname66" (func $internal66))
+  (import "env" "longname67" (func $internal67))
+  (import "env" "longname68" (func $internal68))
+  (import "env" "longname69" (func $internal69))
+  (import "env" "longname70" (func $internal70))
+  (import "env" "longname71" (func $internal71))
+  (import "env" "longname72" (func $internal72))
+  (import "env" "longname73" (func $internal73))
+  (import "env" "longname74" (func $internal74))
+  (import "env" "longname75" (func $internal75))
+  (import "env" "longname76" (func $internal76))
+  (import "env" "longname77" (func $internal77))
+  (import "env" "longname78" (func $internal78))
+  (import "env" "longname79" (func $internal79))
+  (import "env" "longname80" (func $internal80))
+  (import "env" "longname81" (func $internal81))
+  (import "env" "longname82" (func $internal82))
+  (import "env" "longname83" (func $internal83))
+  (import "env" "longname84" (func $internal84))
+  (import "env" "longname85" (func $internal85))
+  (import "env" "longname86" (func $internal86))
+  (import "env" "longname87" (func $internal87))
+  (import "env" "longname88" (func $internal88))
+  (import "env" "longname89" (func $internal89))
+  (import "env" "longname90" (func $internal90))
+  (import "env" "longname91" (func $internal91))
+  (import "env" "longname92" (func $internal92))
+  (import "env" "longname93" (func $internal93))
+  (import "env" "longname94" (func $internal94))
+  (import "env" "longname95" (func $internal95))
+  (import "env" "longname96" (func $internal96))
+  (import "env" "longname97" (func $internal97))
+  (import "env" "longname98" (func $internal98))
+  (import "env" "longname99" (func $internal99))
+  (import "env" "longname100" (func $internal100))
+  (import "env" "longname101" (func $internal101))
+  (import "env" "longname102" (func $internal102))
+  (import "env" "longname103" (func $internal103))
+  (import "env" "longname104" (func $internal104))
+  (import "env" "longname105" (func $internal105))
+  (import "env" "longname106" (func $internal106))
+  (import "env" "longname107" (func $internal107))
+  (import "env" "longname108" (func $internal108))
+  (import "env" "longname109" (func $internal109))
+  (import "env" "longname110" (func $internal110))
+  (import "env" "longname111" (func $internal111))
+  (import "env" "longname112" (func $internal112))
+  (import "env" "longname113" (func $internal113))
+  (import "env" "longname114" (func $internal114))
+  (import "env" "longname115" (func $internal115))
+  (import "env" "longname116" (func $internal116))
+  (import "env" "longname117" (func $internal117))
+  (import "env" "longname118" (func $internal118))
+  (import "env" "longname119" (func $internal119))
+  (import "env" "longname120" (func $internal120))
+  (import "env" "longname121" (func $internal121))
+  (import "env" "longname122" (func $internal122))
+  (import "env" "longname123" (func $internal123))
+  (import "env" "longname124" (func $internal124))
+  (import "env" "longname125" (func $internal125))
+  (import "env" "longname126" (func $internal126))
+  (import "env" "longname127" (func $internal127))
+  (import "env" "longname128" (func $internal128))
+  (import "env" "longname129" (func $internal129))
+  (import "env" "longname130" (func $internal130))
+  (import "env" "longname131" (func $internal131))
+  (import "env" "longname132" (func $internal132))
+  (import "env" "longname133" (func $internal133))
+  (import "env" "longname134" (func $internal134))
+  (import "env" "longname135" (func $internal135))
+  (import "env" "longname136" (func $internal136))
+  (import "env" "longname137" (func $internal137))
+  (import "env" "longname138" (func $internal138))
+  (import "env" "longname139" (func $internal139))
+  (import "env" "longname140" (func $internal140))
+  (import "env" "longname141" (func $internal141))
+  (import "env" "longname142" (func $internal142))
+  (import "env" "longname143" (func $internal143))
+  (import "env" "longname144" (func $internal144))
+  (import "env" "longname145" (func $internal145))
+  (import "env" "longname146" (func $internal146))
+  (import "env" "longname147" (func $internal147))
+  (import "env" "longname148" (func $internal148))
+  (import "env" "longname149" (func $internal149))
+  (import "env" "longname150" (func $internal150))
+  (import "env" "longname151" (func $internal151))
+  (import "env" "longname152" (func $internal152))
+  (import "env" "longname153" (func $internal153))
+  (import "env" "longname154" (func $internal154))
+  (import "env" "longname155" (func $internal155))
+  (import "env" "longname156" (func $internal156))
+  (import "env" "longname157" (func $internal157))
+  (import "env" "longname158" (func $internal158))
+  (import "env" "longname159" (func $internal159))
+  (import "env" "longname160" (func $internal160))
+  (import "env" "longname161" (func $internal161))
+  (import "env" "longname162" (func $internal162))
+  (import "env" "longname163" (func $internal163))
+  (import "env" "longname164" (func $internal164))
+  (import "env" "longname165" (func $internal165))
+  (import "env" "longname166" (func $internal166))
+  (import "env" "longname167" (func $internal167))
+  (import "env" "longname168" (func $internal168))
+  (import "env" "longname169" (func $internal169))
+  (import "env" "longname170" (func $internal170))
+  (import "env" "longname171" (func $internal171))
+  (import "env" "longname172" (func $internal172))
+  (import "env" "longname173" (func $internal173))
+  (import "env" "longname174" (func $internal174))
+  (import "env" "longname175" (func $internal175))
+  (import "env" "longname176" (func $internal176))
+  (import "env" "longname177" (func $internal177))
+  (import "env" "longname178" (func $internal178))
+  (import "env" "longname179" (func $internal179))
+  (import "env" "longname180" (func $internal180))
+  (import "env" "longname181" (func $internal181))
+  (import "env" "longname182" (func $internal182))
+  (import "env" "longname183" (func $internal183))
+  (import "env" "longname184" (func $internal184))
+  (import "env" "longname185" (func $internal185))
+  (import "env" "longname186" (func $internal186))
+  (import "env" "longname187" (func $internal187))
+  (import "env" "longname188" (func $internal188))
+  (import "env" "longname189" (func $internal189))
+  (import "env" "longname190" (func $internal190))
+  (import "env" "longname191" (func $internal191))
+  (import "env" "longname192" (func $internal192))
+  (import "env" "longname193" (func $internal193))
+  (import "env" "longname194" (func $internal194))
+  (import "env" "longname195" (func $internal195))
+  (import "env" "longname196" (func $internal196))
+  (import "env" "longname197" (func $internal197))
+  (import "env" "longname198" (func $internal198))
+  (import "env" "longname199" (func $internal199))
+  (import "env" "longname200" (func $internal200))
+  (import "env" "longname201" (func $internal201))
+  (import "env" "longname202" (func $internal202))
+  (import "env" "longname203" (func $internal203))
+  (import "env" "longname204" (func $internal204))
+  (import "env" "longname205" (func $internal205))
+  (import "env" "longname206" (func $internal206))
+  (import "env" "longname207" (func $internal207))
+  (import "env" "longname208" (func $internal208))
+  (import "env" "longname209" (func $internal209))
+  (import "env" "longname210" (func $internal210))
+  (import "env" "longname211" (func $internal211))
+  (import "env" "longname212" (func $internal212))
+  (import "env" "longname213" (func $internal213))
+  (import "env" "longname214" (func $internal214))
+  (import "env" "longname215" (func $internal215))
+  (import "env" "longname216" (func $internal216))
+  (import "env" "longname217" (func $internal217))
+  (import "env" "longname218" (func $internal218))
+  (import "env" "longname219" (func $internal219))
+  (import "env" "longname220" (func $internal220))
+  (import "env" "longname221" (func $internal221))
+  (import "env" "longname222" (func $internal222))
+  (import "env" "longname223" (func $internal223))
+  (import "env" "longname224" (func $internal224))
+  (import "env" "longname225" (func $internal225))
+  (import "env" "longname226" (func $internal226))
+  (import "env" "longname227" (func $internal227))
+  (import "env" "longname228" (func $internal228))
+  (import "env" "longname229" (func $internal229))
+  (import "env" "longname230" (func $internal230))
+  (import "env" "longname231" (func $internal231))
+  (import "env" "longname232" (func $internal232))
+  (import "env" "longname233" (func $internal233))
+  (import "env" "longname234" (func $internal234))
+  (import "env" "longname235" (func $internal235))
+  (import "env" "longname236" (func $internal236))
+  (import "env" "longname237" (func $internal237))
+  (import "env" "longname238" (func $internal238))
+  (import "env" "longname239" (func $internal239))
+  (import "env" "longname240" (func $internal240))
+  (import "env" "longname241" (func $internal241))
+  (import "env" "longname242" (func $internal242))
+  (import "env" "longname243" (func $internal243))
+  (import "env" "longname244" (func $internal244))
+  (import "env" "longname245" (func $internal245))
+  (import "env" "longname246" (func $internal246))
+  (import "env" "longname247" (func $internal247))
+  (import "env" "longname248" (func $internal248))
+  (import "env" "longname249" (func $internal249))
+  (import "env" "longname250" (func $internal250))
+  (import "env" "longname251" (func $internal251))
+  (import "env" "longname252" (func $internal252))
+  (import "env" "longname253" (func $internal253))
+  (import "env" "longname254" (func $internal254))
+  (import "env" "longname255" (func $internal255))
+  (import "env" "longname256" (func $internal256))
+  (import "env" "longname257" (func $internal257))
+  (import "env" "longname258" (func $internal258))
+  (import "env" "longname259" (func $internal259))
+  (import "env" "longname260" (func $internal260))
+  (import "env" "longname261" (func $internal261))
+  (import "env" "longname262" (func $internal262))
+  (import "env" "longname263" (func $internal263))
+  (import "env" "longname264" (func $internal264))
+  (import "env" "longname265" (func $internal265))
+  (import "env" "longname266" (func $internal266))
+  (import "env" "longname267" (func $internal267))
+  (import "env" "longname268" (func $internal268))
+  (import "env" "longname269" (func $internal269))
+  (import "env" "longname270" (func $internal270))
+  (import "env" "longname271" (func $internal271))
+  (import "env" "longname272" (func $internal272))
+  (import "env" "longname273" (func $internal273))
+  (import "env" "longname274" (func $internal274))
+  (import "env" "longname275" (func $internal275))
+  (import "env" "longname276" (func $internal276))
+  (import "env" "longname277" (func $internal277))
+  (import "env" "longname278" (func $internal278))
+  (import "env" "longname279" (func $internal279))
+  (import "env" "longname280" (func $internal280))
+  (import "env" "longname281" (func $internal281))
+  (import "env" "longname282" (func $internal282))
+  (import "env" "longname283" (func $internal283))
+  (import "env" "longname284" (func $internal284))
+  (import "env" "longname285" (func $internal285))
+  (import "env" "longname286" (func $internal286))
+  (import "env" "longname287" (func $internal287))
+  (import "env" "longname288" (func $internal288))
+  (import "env" "longname289" (func $internal289))
+  (import "env" "longname290" (func $internal290))
+  (import "env" "longname291" (func $internal291))
+  (import "env" "longname292" (func $internal292))
+  (import "env" "longname293" (func $internal293))
+  (import "env" "longname294" (func $internal294))
+  (import "env" "longname295" (func $internal295))
+  (import "env" "longname296" (func $internal296))
+  (import "env" "longname297" (func $internal297))
+  (import "env" "longname298" (func $internal298))
+  (import "env" "longname299" (func $internal299))
+  (import "env" "longname300" (func $internal300))
+  (import "env" "longname301" (func $internal301))
+  (import "env" "longname302" (func $internal302))
+  (import "env" "longname303" (func $internal303))
+  (import "env" "longname304" (func $internal304))
+  (import "env" "longname305" (func $internal305))
+  (import "env" "longname306" (func $internal306))
+  (import "env" "longname307" (func $internal307))
+  (import "env" "longname308" (func $internal308))
+  (import "env" "longname309" (func $internal309))
+  (import "env" "longname310" (func $internal310))
+  (import "env" "longname311" (func $internal311))
+  (import "env" "longname312" (func $internal312))
+  (import "env" "longname313" (func $internal313))
+  (import "env" "longname314" (func $internal314))
+  (import "env" "longname315" (func $internal315))
+  (import "env" "longname316" (func $internal316))
+  (import "env" "longname317" (func $internal317))
+  (import "env" "longname318" (func $internal318))
+  (import "env" "longname319" (func $internal319))
+  (import "env" "longname320" (func $internal320))
+  (import "env" "longname321" (func $internal321))
+  (import "env" "longname322" (func $internal322))
+  (import "env" "longname323" (func $internal323))
+  (import "env" "longname324" (func $internal324))
+  (import "env" "longname325" (func $internal325))
+  (import "env" "longname326" (func $internal326))
+  (import "env" "longname327" (func $internal327))
+  (import "env" "longname328" (func $internal328))
+  (import "env" "longname329" (func $internal329))
+  (import "env" "longname330" (func $internal330))
+  (import "env" "longname331" (func $internal331))
+  (import "env" "longname332" (func $internal332))
+  (import "env" "longname333" (func $internal333))
+  (import "env" "longname334" (func $internal334))
+  (import "env" "longname335" (func $internal335))
+  (import "env" "longname336" (func $internal336))
+  (import "env" "longname337" (func $internal337))
+  (import "env" "longname338" (func $internal338))
+  (import "env" "longname339" (func $internal339))
+  (import "env" "longname340" (func $internal340))
+  (import "env" "longname341" (func $internal341))
+  (import "env" "longname342" (func $internal342))
+  (import "env" "longname343" (func $internal343))
+  (import "env" "longname344" (func $internal344))
+  (import "env" "longname345" (func $internal345))
+  (import "env" "longname346" (func $internal346))
+  (import "env" "longname347" (func $internal347))
+  (import "env" "longname348" (func $internal348))
+  (import "env" "longname349" (func $internal349))
+  (import "env" "longname350" (func $internal350))
+  (import "env" "longname351" (func $internal351))
+  (import "env" "longname352" (func $internal352))
+  (import "env" "longname353" (func $internal353))
+  (import "env" "longname354" (func $internal354))
+  (import "env" "longname355" (func $internal355))
+  (import "env" "longname356" (func $internal356))
+  (import "env" "longname357" (func $internal357))
+  (import "env" "longname358" (func $internal358))
+  (import "env" "longname359" (func $internal359))
+  (import "env" "longname360" (func $internal360))
+  (import "env" "longname361" (func $internal361))
+  (import "env" "longname362" (func $internal362))
+  (import "env" "longname363" (func $internal363))
+  (import "env" "longname364" (func $internal364))
+  (import "env" "longname365" (func $internal365))
+  (import "env" "longname366" (func $internal366))
+  (import "env" "longname367" (func $internal367))
+  (import "env" "longname368" (func $internal368))
+  (import "env" "longname369" (func $internal369))
+  (import "env" "longname370" (func $internal370))
+  (import "env" "longname371" (func $internal371))
+  (import "env" "longname372" (func $internal372))
+  (import "env" "longname373" (func $internal373))
+  (import "env" "longname374" (func $internal374))
+  (import "env" "longname375" (func $internal375))
+  (import "env" "longname376" (func $internal376))
+  (import "env" "longname377" (func $internal377))
+  (import "env" "longname378" (func $internal378))
+  (import "env" "longname379" (func $internal379))
+  (import "env" "longname380" (func $internal380))
+  (import "env" "longname381" (func $internal381))
+  (import "env" "longname382" (func $internal382))
+  (import "env" "longname383" (func $internal383))
+  (import "env" "longname384" (func $internal384))
+  (import "env" "longname385" (func $internal385))
+  (import "env" "longname386" (func $internal386))
+  (import "env" "longname387" (func $internal387))
+  (import "env" "longname388" (func $internal388))
+  (import "env" "longname389" (func $internal389))
+  (import "env" "longname390" (func $internal390))
+  (import "env" "longname391" (func $internal391))
+  (import "env" "longname392" (func $internal392))
+  (import "env" "longname393" (func $internal393))
+  (import "env" "longname394" (func $internal394))
+  (import "env" "longname395" (func $internal395))
+  (import "env" "longname396" (func $internal396))
+  (import "env" "longname397" (func $internal397))
+  (import "env" "longname398" (func $internal398))
+  (import "env" "longname399" (func $internal399))
+  (import "env" "longname400" (func $internal400))
+  (import "env" "longname401" (func $internal401))
+  (import "env" "longname402" (func $internal402))
+  (import "env" "longname403" (func $internal403))
+  (import "env" "longname404" (func $internal404))
+  (import "env" "longname405" (func $internal405))
+  (import "env" "longname406" (func $internal406))
+  (import "env" "longname407" (func $internal407))
+  (import "env" "longname408" (func $internal408))
+  (import "env" "longname409" (func $internal409))
+  (import "env" "longname410" (func $internal410))
+  (import "env" "longname411" (func $internal411))
+  (import "env" "longname412" (func $internal412))
+  (import "env" "longname413" (func $internal413))
+  (import "env" "longname414" (func $internal414))
+  (import "env" "longname415" (func $internal415))
+  (import "env" "longname416" (func $internal416))
+  (import "env" "longname417" (func $internal417))
+  (import "env" "longname418" (func $internal418))
+  (import "env" "longname419" (func $internal419))
+  (import "env" "longname420" (func $internal420))
+  (import "env" "longname421" (func $internal421))
+  (import "env" "longname422" (func $internal422))
+  (import "env" "longname423" (func $internal423))
+  (import "env" "longname424" (func $internal424))
+  (import "env" "longname425" (func $internal425))
+  (import "env" "longname426" (func $internal426))
+  (import "env" "longname427" (func $internal427))
+  (import "env" "longname428" (func $internal428))
+  (import "env" "longname429" (func $internal429))
+  (import "env" "longname430" (func $internal430))
+  (import "env" "longname431" (func $internal431))
+  (import "env" "longname432" (func $internal432))
+  (import "env" "longname433" (func $internal433))
+  (import "env" "longname434" (func $internal434))
+  (import "env" "longname435" (func $internal435))
+  (import "env" "longname436" (func $internal436))
+  (import "env" "longname437" (func $internal437))
+  (import "env" "longname438" (func $internal438))
+  (import "env" "longname439" (func $internal439))
+  (import "env" "longname440" (func $internal440))
+  (import "env" "longname441" (func $internal441))
+  (import "env" "longname442" (func $internal442))
+  (import "env" "longname443" (func $internal443))
+  (import "env" "longname444" (func $internal444))
+  (import "env" "longname445" (func $internal445))
+  (import "env" "longname446" (func $internal446))
+  (import "env" "longname447" (func $internal447))
+  (import "env" "longname448" (func $internal448))
+  (import "env" "longname449" (func $internal449))
+  (import "env" "longname450" (func $internal450))
+  (import "env" "longname451" (func $internal451))
+  (import "env" "longname452" (func $internal452))
+  (import "env" "longname453" (func $internal453))
+  (import "env" "longname454" (func $internal454))
+  (import "env" "longname455" (func $internal455))
+  (import "env" "longname456" (func $internal456))
+  (import "env" "longname457" (func $internal457))
+  (import "env" "longname458" (func $internal458))
+  (import "env" "longname459" (func $internal459))
+  (import "env" "longname460" (func $internal460))
+  (import "env" "longname461" (func $internal461))
+  (import "env" "longname462" (func $internal462))
+  (import "env" "longname463" (func $internal463))
+  (import "env" "longname464" (func $internal464))
+  (import "env" "longname465" (func $internal465))
+  (import "env" "longname466" (func $internal466))
+  (import "env" "longname467" (func $internal467))
+  (import "env" "longname468" (func $internal468))
+  (import "env" "longname469" (func $internal469))
+  (import "env" "longname470" (func $internal470))
+  (import "env" "longname471" (func $internal471))
+  (import "env" "longname472" (func $internal472))
+  (import "env" "longname473" (func $internal473))
+  (import "env" "longname474" (func $internal474))
+  (import "env" "longname475" (func $internal475))
+  (import "env" "longname476" (func $internal476))
+  (import "env" "longname477" (func $internal477))
+  (import "env" "longname478" (func $internal478))
+  (import "env" "longname479" (func $internal479))
+  (import "env" "longname480" (func $internal480))
+  (import "env" "longname481" (func $internal481))
+  (import "env" "longname482" (func $internal482))
+  (import "env" "longname483" (func $internal483))
+  (import "env" "longname484" (func $internal484))
+  (import "env" "longname485" (func $internal485))
+  (import "env" "longname486" (func $internal486))
+  (import "env" "longname487" (func $internal487))
+  (import "env" "longname488" (func $internal488))
+  (import "env" "longname489" (func $internal489))
+  (import "env" "longname490" (func $internal490))
+  (import "env" "longname491" (func $internal491))
+  (import "env" "longname492" (func $internal492))
+  (import "env" "longname493" (func $internal493))
+  (import "env" "longname494" (func $internal494))
+  (import "env" "longname495" (func $internal495))
+  (import "env" "longname496" (func $internal496))
+  (import "env" "longname497" (func $internal497))
+  (import "env" "longname498" (func $internal498))
+  (import "env" "longname499" (func $internal499))
+  (import "env" "longname500" (func $internal500))
+  (import "env" "longname501" (func $internal501))
+  (import "env" "longname502" (func $internal502))
+  (import "env" "longname503" (func $internal503))
+  (import "env" "longname504" (func $internal504))
+  (import "env" "longname505" (func $internal505))
+  (import "env" "longname506" (func $internal506))
+  (import "env" "longname507" (func $internal507))
+  (import "env" "longname508" (func $internal508))
+  (import "env" "longname509" (func $internal509))
+  (import "env" "longname510" (func $internal510))
+  (import "env" "longname511" (func $internal511))
+  (import "env" "longname512" (func $internal512))
+  (import "env" "longname513" (func $internal513))
+  (import "env" "longname514" (func $internal514))
+  (import "env" "longname515" (func $internal515))
+  (import "env" "longname516" (func $internal516))
+  (import "env" "longname517" (func $internal517))
+  (import "env" "longname518" (func $internal518))
+  (import "env" "longname519" (func $internal519))
+  (import "env" "longname520" (func $internal520))
+  (import "env" "longname521" (func $internal521))
+  (import "env" "longname522" (func $internal522))
+  (import "env" "longname523" (func $internal523))
+  (import "env" "longname524" (func $internal524))
+  (import "env" "longname525" (func $internal525))
+  (import "env" "longname526" (func $internal526))
+  (import "env" "longname527" (func $internal527))
+  (import "env" "longname528" (func $internal528))
+  (import "env" "longname529" (func $internal529))
+  (import "env" "longname530" (func $internal530))
+  (import "env" "longname531" (func $internal531))
+  (import "env" "longname532" (func $internal532))
+  (import "env" "longname533" (func $internal533))
+  (import "env" "longname534" (func $internal534))
+  (import "env" "longname535" (func $internal535))
+  (import "env" "longname536" (func $internal536))
+  (import "env" "longname537" (func $internal537))
+  (import "env" "longname538" (func $internal538))
+  (import "env" "longname539" (func $internal539))
+  (import "env" "longname540" (func $internal540))
+  (import "env" "longname541" (func $internal541))
+  (import "env" "longname542" (func $internal542))
+  (import "env" "longname543" (func $internal543))
+  (import "env" "longname544" (func $internal544))
+  (import "env" "longname545" (func $internal545))
+  (import "env" "longname546" (func $internal546))
+  (import "env" "longname547" (func $internal547))
+  (import "env" "longname548" (func $internal548))
+  (import "env" "longname549" (func $internal549))
+  (import "env" "longname550" (func $internal550))
+  (import "env" "longname551" (func $internal551))
+  (import "env" "longname552" (func $internal552))
+  (import "env" "longname553" (func $internal553))
+  (import "env" "longname554" (func $internal554))
+  (import "env" "longname555" (func $internal555))
+  (import "env" "longname556" (func $internal556))
+  (import "env" "longname557" (func $internal557))
+  (import "env" "longname558" (func $internal558))
+  (import "env" "longname559" (func $internal559))
+  (import "env" "longname560" (func $internal560))
+  (import "env" "longname561" (func $internal561))
+  (import "env" "longname562" (func $internal562))
+  (import "env" "longname563" (func $internal563))
+  (import "env" "longname564" (func $internal564))
+  (import "env" "longname565" (func $internal565))
+  (import "env" "longname566" (func $internal566))
+  (import "env" "longname567" (func $internal567))
+  (import "env" "longname568" (func $internal568))
+  (import "env" "longname569" (func $internal569))
+  (import "env" "longname570" (func $internal570))
+  (import "env" "longname571" (func $internal571))
+  (import "env" "longname572" (func $internal572))
+  (import "env" "longname573" (func $internal573))
+  (import "env" "longname574" (func $internal574))
+  (import "env" "longname575" (func $internal575))
+  (import "env" "longname576" (func $internal576))
+  (import "env" "longname577" (func $internal577))
+  (import "env" "longname578" (func $internal578))
+  (import "env" "longname579" (func $internal579))
+  (import "env" "longname580" (func $internal580))
+  (import "env" "longname581" (func $internal581))
+  (import "env" "longname582" (func $internal582))
+  (import "env" "longname583" (func $internal583))
+  (import "env" "longname584" (func $internal584))
+  (import "env" "longname585" (func $internal585))
+  (import "env" "longname586" (func $internal586))
+  (import "env" "longname587" (func $internal587))
+  (import "env" "longname588" (func $internal588))
+  (import "env" "longname589" (func $internal589))
+  (import "env" "longname590" (func $internal590))
+  (import "env" "longname591" (func $internal591))
+  (import "env" "longname592" (func $internal592))
+  (import "env" "longname593" (func $internal593))
+  (import "env" "longname594" (func $internal594))
+  (import "env" "longname595" (func $internal595))
+  (import "env" "longname596" (func $internal596))
+  (import "env" "longname597" (func $internal597))
+  (import "env" "longname598" (func $internal598))
+  (import "env" "longname599" (func $internal599))
+  (import "env" "longname600" (func $internal600))
+  (import "env" "longname601" (func $internal601))
+  (import "env" "longname602" (func $internal602))
+  (import "env" "longname603" (func $internal603))
+  (import "env" "longname604" (func $internal604))
+  (import "env" "longname605" (func $internal605))
+  (import "env" "longname606" (func $internal606))
+  (import "env" "longname607" (func $internal607))
+  (import "env" "longname608" (func $internal608))
+  (import "env" "longname609" (func $internal609))
+  (import "env" "longname610" (func $internal610))
+  (import "env" "longname611" (func $internal611))
+  (import "env" "longname612" (func $internal612))
+  (import "env" "longname613" (func $internal613))
+  (import "env" "longname614" (func $internal614))
+  (import "env" "longname615" (func $internal615))
+  (import "env" "longname616" (func $internal616))
+  (import "env" "longname617" (func $internal617))
+  (import "env" "longname618" (func $internal618))
+  (import "env" "longname619" (func $internal619))
+  (import "env" "longname620" (func $internal620))
+  (import "env" "longname621" (func $internal621))
+  (import "env" "longname622" (func $internal622))
+  (import "env" "longname623" (func $internal623))
+  (import "env" "longname624" (func $internal624))
+  (import "env" "longname625" (func $internal625))
+  (import "env" "longname626" (func $internal626))
+  (import "env" "longname627" (func $internal627))
+  (import "env" "longname628" (func $internal628))
+  (import "env" "longname629" (func $internal629))
+  (import "env" "longname630" (func $internal630))
+  (import "env" "longname631" (func $internal631))
+  (import "env" "longname632" (func $internal632))
+  (import "env" "longname633" (func $internal633))
+  (import "env" "longname634" (func $internal634))
+  (import "env" "longname635" (func $internal635))
+  (import "env" "longname636" (func $internal636))
+  (import "env" "longname637" (func $internal637))
+  (import "env" "longname638" (func $internal638))
+  (import "env" "longname639" (func $internal639))
+  (import "env" "longname640" (func $internal640))
+  (import "env" "longname641" (func $internal641))
+  (import "env" "longname642" (func $internal642))
+  (import "env" "longname643" (func $internal643))
+  (import "env" "longname644" (func $internal644))
+  (import "env" "longname645" (func $internal645))
+  (import "env" "longname646" (func $internal646))
+  (import "env" "longname647" (func $internal647))
+  (import "env" "longname648" (func $internal648))
+  (import "env" "longname649" (func $internal649))
+  (import "env" "longname650" (func $internal650))
+  (import "env" "longname651" (func $internal651))
+  (import "env" "longname652" (func $internal652))
+  (import "env" "longname653" (func $internal653))
+  (import "env" "longname654" (func $internal654))
+  (import "env" "longname655" (func $internal655))
+  (import "env" "longname656" (func $internal656))
+  (import "env" "longname657" (func $internal657))
+  (import "env" "longname658" (func $internal658))
+  (import "env" "longname659" (func $internal659))
+  (import "env" "longname660" (func $internal660))
+  (import "env" "longname661" (func $internal661))
+  (import "env" "longname662" (func $internal662))
+  (import "env" "longname663" (func $internal663))
+  (import "env" "longname664" (func $internal664))
+  (import "env" "longname665" (func $internal665))
+  (import "env" "longname666" (func $internal666))
+  (import "env" "longname667" (func $internal667))
+  (import "env" "longname668" (func $internal668))
+  (import "env" "longname669" (func $internal669))
+  (import "env" "longname670" (func $internal670))
+  (import "env" "longname671" (func $internal671))
+  (import "env" "longname672" (func $internal672))
+  (import "env" "longname673" (func $internal673))
+  (import "env" "longname674" (func $internal674))
+  (import "env" "longname675" (func $internal675))
+  (import "env" "longname676" (func $internal676))
+  (import "env" "longname677" (func $internal677))
+  (import "env" "longname678" (func $internal678))
+  (import "env" "longname679" (func $internal679))
+  (import "env" "longname680" (func $internal680))
+  (import "env" "longname681" (func $internal681))
+  (import "env" "longname682" (func $internal682))
+  (import "env" "longname683" (func $internal683))
+  (import "env" "longname684" (func $internal684))
+  (import "env" "longname685" (func $internal685))
+  (import "env" "longname686" (func $internal686))
+  (import "env" "longname687" (func $internal687))
+  (import "env" "longname688" (func $internal688))
+  (import "env" "longname689" (func $internal689))
+  (import "env" "longname690" (func $internal690))
+  (import "env" "longname691" (func $internal691))
+  (import "env" "longname692" (func $internal692))
+  (import "env" "longname693" (func $internal693))
+  (import "env" "longname694" (func $internal694))
+  (import "env" "longname695" (func $internal695))
+  (import "env" "longname696" (func $internal696))
+  (import "env" "longname697" (func $internal697))
+  (import "env" "longname698" (func $internal698))
+  (import "env" "longname699" (func $internal699))
+  (import "env" "longname700" (func $internal700))
+  (import "env" "longname701" (func $internal701))
+  (import "env" "longname702" (func $internal702))
+  (import "env" "longname703" (func $internal703))
+  (import "env" "longname704" (func $internal704))
+  (import "env" "longname705" (func $internal705))
+  (import "env" "longname706" (func $internal706))
+  (import "env" "longname707" (func $internal707))
+  (import "env" "longname708" (func $internal708))
+  (import "env" "longname709" (func $internal709))
+  (import "env" "longname710" (func $internal710))
+  (import "env" "longname711" (func $internal711))
+  (import "env" "longname712" (func $internal712))
+  (import "env" "longname713" (func $internal713))
+  (import "env" "longname714" (func $internal714))
+  (import "env" "longname715" (func $internal715))
+  (import "env" "longname716" (func $internal716))
+  (import "env" "longname717" (func $internal717))
+  (import "env" "longname718" (func $internal718))
+  (import "env" "longname719" (func $internal719))
+  (import "env" "longname720" (func $internal720))
+  (import "env" "longname721" (func $internal721))
+  (import "env" "longname722" (func $internal722))
+  (import "env" "longname723" (func $internal723))
+  (import "env" "longname724" (func $internal724))
+  (import "env" "longname725" (func $internal725))
+  (import "env" "longname726" (func $internal726))
+  (import "env" "longname727" (func $internal727))
+  (import "env" "longname728" (func $internal728))
+  (import "env" "longname729" (func $internal729))
+  (import "env" "longname730" (func $internal730))
+  (import "env" "longname731" (func $internal731))
+  (import "env" "longname732" (func $internal732))
+  (import "env" "longname733" (func $internal733))
+  (import "env" "longname734" (func $internal734))
+  (import "env" "longname735" (func $internal735))
+  (import "env" "longname736" (func $internal736))
+  (import "env" "longname737" (func $internal737))
+  (import "env" "longname738" (func $internal738))
+  (import "env" "longname739" (func $internal739))
+  (import "env" "longname740" (func $internal740))
+  (import "env" "longname741" (func $internal741))
+  (import "env" "longname742" (func $internal742))
+  (import "env" "longname743" (func $internal743))
+  (import "env" "longname744" (func $internal744))
+  (import "env" "longname745" (func $internal745))
+  (import "env" "longname746" (func $internal746))
+  (import "env" "longname747" (func $internal747))
+  (import "env" "longname748" (func $internal748))
+  (import "env" "longname749" (func $internal749))
+  (import "env" "longname750" (func $internal750))
+  (import "env" "longname751" (func $internal751))
+  (import "env" "longname752" (func $internal752))
+  (import "env" "longname753" (func $internal753))
+  (import "env" "longname754" (func $internal754))
+  (import "env" "longname755" (func $internal755))
+  (import "env" "longname756" (func $internal756))
+  (import "env" "longname757" (func $internal757))
+  (import "env" "longname758" (func $internal758))
+  (import "env" "longname759" (func $internal759))
+  (import "env" "longname760" (func $internal760))
+  (import "env" "longname761" (func $internal761))
+  (import "env" "longname762" (func $internal762))
+  (import "env" "longname763" (func $internal763))
+  (import "env" "longname764" (func $internal764))
+  (import "env" "longname765" (func $internal765))
+  (import "env" "longname766" (func $internal766))
+  (import "env" "longname767" (func $internal767))
+  (import "env" "longname768" (func $internal768))
+  (import "env" "longname769" (func $internal769))
+  (import "env" "longname770" (func $internal770))
+  (import "env" "longname771" (func $internal771))
+  (import "env" "longname772" (func $internal772))
+  (import "env" "longname773" (func $internal773))
+  (import "env" "longname774" (func $internal774))
+  (import "env" "longname775" (func $internal775))
+  (import "env" "longname776" (func $internal776))
+  (import "env" "longname777" (func $internal777))
+  (import "env" "longname778" (func $internal778))
+  (import "env" "longname779" (func $internal779))
+  (import "env" "longname780" (func $internal780))
+  (import "env" "longname781" (func $internal781))
+  (import "env" "longname782" (func $internal782))
+  (import "env" "longname783" (func $internal783))
+  (import "env" "longname784" (func $internal784))
+  (import "env" "longname785" (func $internal785))
+  (import "env" "longname786" (func $internal786))
+  (import "env" "longname787" (func $internal787))
+  (import "env" "longname788" (func $internal788))
+  (import "env" "longname789" (func $internal789))
+  (import "env" "longname790" (func $internal790))
+  (import "env" "longname791" (func $internal791))
+  (import "env" "longname792" (func $internal792))
+  (import "env" "longname793" (func $internal793))
+  (import "env" "longname794" (func $internal794))
+  (import "env" "longname795" (func $internal795))
+  (import "env" "longname796" (func $internal796))
+  (import "env" "longname797" (func $internal797))
+  (import "env" "longname798" (func $internal798))
+  (import "env" "longname799" (func $internal799))
+  (import "env" "longname800" (func $internal800))
+  (import "env" "longname801" (func $internal801))
+  (import "env" "longname802" (func $internal802))
+  (import "env" "longname803" (func $internal803))
+  (import "env" "longname804" (func $internal804))
+  (import "env" "longname805" (func $internal805))
+  (import "env" "longname806" (func $internal806))
+  (import "env" "longname807" (func $internal807))
+  (import "env" "longname808" (func $internal808))
+  (import "env" "longname809" (func $internal809))
+  (import "env" "longname810" (func $internal810))
+  (import "env" "longname811" (func $internal811))
+  (import "env" "longname812" (func $internal812))
+  (import "env" "longname813" (func $internal813))
+  (import "env" "longname814" (func $internal814))
+  (import "env" "longname815" (func $internal815))
+  (import "env" "longname816" (func $internal816))
+  (import "env" "longname817" (func $internal817))
+  (import "env" "longname818" (func $internal818))
+  (import "env" "longname819" (func $internal819))
+  (import "env" "longname820" (func $internal820))
+  (import "env" "longname821" (func $internal821))
+  (import "env" "longname822" (func $internal822))
+  (import "env" "longname823" (func $internal823))
+  (import "env" "longname824" (func $internal824))
+  (import "env" "longname825" (func $internal825))
+  (import "env" "longname826" (func $internal826))
+  (import "env" "longname827" (func $internal827))
+  (import "env" "longname828" (func $internal828))
+  (import "env" "longname829" (func $internal829))
+  (import "env" "longname830" (func $internal830))
+  (import "env" "longname831" (func $internal831))
+  (import "env" "longname832" (func $internal832))
+  (import "env" "longname833" (func $internal833))
+  (import "env" "longname834" (func $internal834))
+  (import "env" "longname835" (func $internal835))
+  (import "env" "longname836" (func $internal836))
+  (import "env" "longname837" (func $internal837))
+  (import "env" "longname838" (func $internal838))
+  (import "env" "longname839" (func $internal839))
+  (import "env" "longname840" (func $internal840))
+  (import "env" "longname841" (func $internal841))
+  (import "env" "longname842" (func $internal842))
+  (import "env" "longname843" (func $internal843))
+  (import "env" "longname844" (func $internal844))
+  (import "env" "longname845" (func $internal845))
+  (import "env" "longname846" (func $internal846))
+  (import "env" "longname847" (func $internal847))
+  (import "env" "longname848" (func $internal848))
+  (import "env" "longname849" (func $internal849))
+  (import "env" "longname850" (func $internal850))
+  (import "env" "longname851" (func $internal851))
+  (import "env" "longname852" (func $internal852))
+  (import "env" "longname853" (func $internal853))
+  (import "env" "longname854" (func $internal854))
+  (import "env" "longname855" (func $internal855))
+  (import "env" "longname856" (func $internal856))
+  (import "env" "longname857" (func $internal857))
+  (import "env" "longname858" (func $internal858))
+  (import "env" "longname859" (func $internal859))
+  (import "env" "longname860" (func $internal860))
+  (import "env" "longname861" (func $internal861))
+  (import "env" "longname862" (func $internal862))
+  (import "env" "longname863" (func $internal863))
+  (import "env" "longname864" (func $internal864))
+  (import "env" "longname865" (func $internal865))
+  (import "env" "longname866" (func $internal866))
+  (import "env" "longname867" (func $internal867))
+  (import "env" "longname868" (func $internal868))
+  (import "env" "longname869" (func $internal869))
+  (import "env" "longname870" (func $internal870))
+  (import "env" "longname871" (func $internal871))
+  (import "env" "longname872" (func $internal872))
+  (import "env" "longname873" (func $internal873))
+  (import "env" "longname874" (func $internal874))
+  (import "env" "longname875" (func $internal875))
+  (import "env" "longname876" (func $internal876))
+  (import "env" "longname877" (func $internal877))
+  (import "env" "longname878" (func $internal878))
+  (import "env" "longname879" (func $internal879))
+  (import "env" "longname880" (func $internal880))
+  (import "env" "longname881" (func $internal881))
+  (import "env" "longname882" (func $internal882))
+  (import "env" "longname883" (func $internal883))
+  (import "env" "longname884" (func $internal884))
+  (import "env" "longname885" (func $internal885))
+  (import "env" "longname886" (func $internal886))
+  (import "env" "longname887" (func $internal887))
+  (import "env" "longname888" (func $internal888))
+  (import "env" "longname889" (func $internal889))
+  (import "env" "longname890" (func $internal890))
+  (import "env" "longname891" (func $internal891))
+  (import "env" "longname892" (func $internal892))
+  (import "env" "longname893" (func $internal893))
+  (import "env" "longname894" (func $internal894))
+  (import "env" "longname895" (func $internal895))
+  (import "env" "longname896" (func $internal896))
+  (import "env" "longname897" (func $internal897))
+  (import "env" "longname898" (func $internal898))
+  (import "env" "longname899" (func $internal899))
+  (import "env" "longname900" (func $internal900))
+  (import "env" "longname901" (func $internal901))
+  (import "env" "longname902" (func $internal902))
+  (import "env" "longname903" (func $internal903))
+  (import "env" "longname904" (func $internal904))
+  (import "env" "longname905" (func $internal905))
+  (import "env" "longname906" (func $internal906))
+  (import "env" "longname907" (func $internal907))
+  (import "env" "longname908" (func $internal908))
+  (import "env" "longname909" (func $internal909))
+  (import "env" "longname910" (func $internal910))
+  (import "env" "longname911" (func $internal911))
+  (import "env" "longname912" (func $internal912))
+  (import "env" "longname913" (func $internal913))
+  (import "env" "longname914" (func $internal914))
+  (import "env" "longname915" (func $internal915))
+  (import "env" "longname916" (func $internal916))
+  (import "env" "longname917" (func $internal917))
+  (import "env" "longname918" (func $internal918))
+  (import "env" "longname919" (func $internal919))
+  (import "env" "longname920" (func $internal920))
+  (import "env" "longname921" (func $internal921))
+  (import "env" "longname922" (func $internal922))
+  (import "env" "longname923" (func $internal923))
+  (import "env" "longname924" (func $internal924))
+  (import "env" "longname925" (func $internal925))
+  (import "env" "longname926" (func $internal926))
+  (import "env" "longname927" (func $internal927))
+  (import "env" "longname928" (func $internal928))
+  (import "env" "longname929" (func $internal929))
+  (import "env" "longname930" (func $internal930))
+  (import "env" "longname931" (func $internal931))
+  (import "env" "longname932" (func $internal932))
+  (import "env" "longname933" (func $internal933))
+  (import "env" "longname934" (func $internal934))
+  (import "env" "longname935" (func $internal935))
+  (import "env" "longname936" (func $internal936))
+  (import "env" "longname937" (func $internal937))
+  (import "env" "longname938" (func $internal938))
+  (import "env" "longname939" (func $internal939))
+  (import "env" "longname940" (func $internal940))
+  (import "env" "longname941" (func $internal941))
+  (import "env" "longname942" (func $internal942))
+  (import "env" "longname943" (func $internal943))
+  (import "env" "longname944" (func $internal944))
+  (import "env" "longname945" (func $internal945))
+  (import "env" "longname946" (func $internal946))
+  (import "env" "longname947" (func $internal947))
+  (import "env" "longname948" (func $internal948))
+  (import "env" "longname949" (func $internal949))
+  (import "env" "longname950" (func $internal950))
+  (import "env" "longname951" (func $internal951))
+  (import "env" "longname952" (func $internal952))
+  (import "env" "longname953" (func $internal953))
+  (import "env" "longname954" (func $internal954))
+  (import "env" "longname955" (func $internal955))
+  (import "env" "longname956" (func $internal956))
+  (import "env" "longname957" (func $internal957))
+  (import "env" "longname958" (func $internal958))
+  (import "env" "longname959" (func $internal959))
+  (import "env" "longname960" (func $internal960))
+  (import "env" "longname961" (func $internal961))
+  (import "env" "longname962" (func $internal962))
+  (import "env" "longname963" (func $internal963))
+  (import "env" "longname964" (func $internal964))
+  (import "env" "longname965" (func $internal965))
+  (import "env" "longname966" (func $internal966))
+  (import "env" "longname967" (func $internal967))
+  (import "env" "longname968" (func $internal968))
+  (import "env" "longname969" (func $internal969))
+  (import "env" "longname970" (func $internal970))
+  (import "env" "longname971" (func $internal971))
+  (import "env" "longname972" (func $internal972))
+  (import "env" "longname973" (func $internal973))
+  (import "env" "longname974" (func $internal974))
+  (import "env" "longname975" (func $internal975))
+  (import "env" "longname976" (func $internal976))
+  (import "env" "longname977" (func $internal977))
+  (import "env" "longname978" (func $internal978))
+  (import "env" "longname979" (func $internal979))
+  (import "env" "longname980" (func $internal980))
+  (import "env" "longname981" (func $internal981))
+  (import "env" "longname982" (func $internal982))
+  (import "env" "longname983" (func $internal983))
+  (import "env" "longname984" (func $internal984))
+  (import "env" "longname985" (func $internal985))
+  (import "env" "longname986" (func $internal986))
+  (import "env" "longname987" (func $internal987))
+  (import "env" "longname988" (func $internal988))
+  (import "env" "longname989" (func $internal989))
+  (import "env" "longname990" (func $internal990))
+  (import "env" "longname991" (func $internal991))
+  (import "env" "longname992" (func $internal992))
+  (import "env" "longname993" (func $internal993))
+  (import "env" "longname994" (func $internal994))
+  (import "env" "longname995" (func $internal995))
+  (import "env" "longname996" (func $internal996))
+  (import "env" "longname997" (func $internal997))
+  (import "env" "longname998" (func $internal998))
+  (import "env" "longname999" (func $internal999))
+  (import "env" "longname1000" (func $internal1000))
+  (import "env" "longname1001" (func $internal1001))
+  (import "env" "longname1002" (func $internal1002))
+  (import "env" "longname1003" (func $internal1003))
+  (import "env" "longname1004" (func $internal1004))
+  (import "env" "longname1005" (func $internal1005))
+  (import "env" "longname1006" (func $internal1006))
+  (import "env" "longname1007" (func $internal1007))
+  (import "env" "longname1008" (func $internal1008))
+  (import "env" "longname1009" (func $internal1009))
+  (import "env" "longname1010" (func $internal1010))
+  (import "env" "longname1011" (func $internal1011))
+  (import "env" "longname1012" (func $internal1012))
+  (import "env" "longname1013" (func $internal1013))
+  (import "env" "longname1014" (func $internal1014))
+  (import "env" "longname1015" (func $internal1015))
+  (import "env" "longname1016" (func $internal1016))
+  (import "env" "longname1017" (func $internal1017))
+  (import "env" "longname1018" (func $internal1018))
+  (import "env" "longname1019" (func $internal1019))
+  (import "env" "longname1020" (func $internal1020))
+  (import "env" "longname1021" (func $internal1021))
+  (import "env" "longname1022" (func $internal1022))
+  (import "env" "longname1023" (func $internal1023))
+  (import "env" "longname1024" (func $internal1024))
+  (import "env" "longname1025" (func $internal1025))
+  (import "env" "longname1026" (func $internal1026))
+  (import "env" "longname1027" (func $internal1027))
+  (import "env" "longname1028" (func $internal1028))
+  (import "env" "longname1029" (func $internal1029))
+  (import "env" "longname1030" (func $internal1030))
+  (import "env" "longname1031" (func $internal1031))
+  (import "env" "longname1032" (func $internal1032))
+  (import "env" "longname1033" (func $internal1033))
+  (import "env" "longname1034" (func $internal1034))
+  (import "env" "longname1035" (func $internal1035))
+  (import "env" "longname1036" (func $internal1036))
+  (import "env" "longname1037" (func $internal1037))
+  (import "env" "longname1038" (func $internal1038))
+  (import "env" "longname1039" (func $internal1039))
+  (import "env" "longname1040" (func $internal1040))
+  (import "env" "longname1041" (func $internal1041))
+  (import "env" "longname1042" (func $internal1042))
+  (import "env" "longname1043" (func $internal1043))
+  (import "env" "longname1044" (func $internal1044))
+  (import "env" "longname1045" (func $internal1045))
+  (import "env" "longname1046" (func $internal1046))
+  (import "env" "longname1047" (func $internal1047))
+  (import "env" "longname1048" (func $internal1048))
+  (import "env" "longname1049" (func $internal1049))
+  (import "env" "longname1050" (func $internal1050))
+  (import "env" "longname1051" (func $internal1051))
+  (import "env" "longname1052" (func $internal1052))
+  (import "env" "longname1053" (func $internal1053))
+  (import "env" "longname1054" (func $internal1054))
+  (import "env" "longname1055" (func $internal1055))
+  (import "env" "longname1056" (func $internal1056))
+  (import "env" "longname1057" (func $internal1057))
+  (import "env" "longname1058" (func $internal1058))
+  (import "env" "longname1059" (func $internal1059))
+  (import "env" "longname1060" (func $internal1060))
+  (import "env" "longname1061" (func $internal1061))
+  (import "env" "longname1062" (func $internal1062))
+  (import "env" "longname1063" (func $internal1063))
+  (import "env" "longname1064" (func $internal1064))
+  (import "env" "longname1065" (func $internal1065))
+  (import "env" "longname1066" (func $internal1066))
+  (import "env" "longname1067" (func $internal1067))
+  (import "env" "longname1068" (func $internal1068))
+  (import "env" "longname1069" (func $internal1069))
+  (import "env" "longname1070" (func $internal1070))
+  (import "env" "longname1071" (func $internal1071))
+  (import "env" "longname1072" (func $internal1072))
+  (import "env" "longname1073" (func $internal1073))
+  (import "env" "longname1074" (func $internal1074))
+  (import "env" "longname1075" (func $internal1075))
+  (import "env" "longname1076" (func $internal1076))
+  (import "env" "longname1077" (func $internal1077))
+  (import "env" "longname1078" (func $internal1078))
+  (import "env" "longname1079" (func $internal1079))
+  (import "env" "longname1080" (func $internal1080))
+  (import "env" "longname1081" (func $internal1081))
+  (import "env" "longname1082" (func $internal1082))
+  (import "env" "longname1083" (func $internal1083))
+  (import "env" "longname1084" (func $internal1084))
+  (import "env" "longname1085" (func $internal1085))
+  (import "env" "longname1086" (func $internal1086))
+  (import "env" "longname1087" (func $internal1087))
+  (import "env" "longname1088" (func $internal1088))
+  (import "env" "longname1089" (func $internal1089))
+  (import "env" "longname1090" (func $internal1090))
+  (import "env" "longname1091" (func $internal1091))
+  (import "env" "longname1092" (func $internal1092))
+  (import "env" "longname1093" (func $internal1093))
+  (import "env" "longname1094" (func $internal1094))
+  (import "env" "longname1095" (func $internal1095))
+  (import "env" "longname1096" (func $internal1096))
+  (import "env" "longname1097" (func $internal1097))
+  (import "env" "longname1098" (func $internal1098))
+  (import "env" "longname1099" (func $internal1099))
+  (import "env" "longname1100" (func $internal1100))
+  (import "env" "longname1101" (func $internal1101))
+  (import "env" "longname1102" (func $internal1102))
+  (import "env" "longname1103" (func $internal1103))
+  (import "env" "longname1104" (func $internal1104))
+  (import "env" "longname1105" (func $internal1105))
+  (import "env" "longname1106" (func $internal1106))
+  (import "env" "longname1107" (func $internal1107))
+  (import "env" "longname1108" (func $internal1108))
+  (import "env" "longname1109" (func $internal1109))
+  (import "env" "longname1110" (func $internal1110))
+  (import "env" "longname1111" (func $internal1111))
+  (import "env" "longname1112" (func $internal1112))
+  (import "env" "longname1113" (func $internal1113))
+  (import "env" "longname1114" (func $internal1114))
+  (import "env" "longname1115" (func $internal1115))
+  (import "env" "longname1116" (func $internal1116))
+  (import "env" "longname1117" (func $internal1117))
+  (import "env" "longname1118" (func $internal1118))
+  (import "env" "longname1119" (func $internal1119))
+  (import "env" "longname1120" (func $internal1120))
+  (import "env" "longname1121" (func $internal1121))
+  (import "env" "longname1122" (func $internal1122))
+  (import "env" "longname1123" (func $internal1123))
+  (import "env" "longname1124" (func $internal1124))
+  (import "env" "longname1125" (func $internal1125))
+  (import "env" "longname1126" (func $internal1126))
+  (import "env" "longname1127" (func $internal1127))
+  (import "env" "longname1128" (func $internal1128))
+  (import "env" "longname1129" (func $internal1129))
+  (import "env" "longname1130" (func $internal1130))
+  (import "env" "longname1131" (func $internal1131))
+  (import "env" "longname1132" (func $internal1132))
+  (import "env" "longname1133" (func $internal1133))
+  (import "env" "longname1134" (func $internal1134))
+  (import "env" "longname1135" (func $internal1135))
+  (import "env" "longname1136" (func $internal1136))
+  (import "env" "longname1137" (func $internal1137))
+  (import "env" "longname1138" (func $internal1138))
+  (import "env" "longname1139" (func $internal1139))
+  (import "env" "longname1140" (func $internal1140))
+  (import "env" "longname1141" (func $internal1141))
+  (import "env" "longname1142" (func $internal1142))
+  (import "env" "longname1143" (func $internal1143))
+  (import "env" "longname1144" (func $internal1144))
+  (import "env" "longname1145" (func $internal1145))
+  (import "env" "longname1146" (func $internal1146))
+  (import "env" "longname1147" (func $internal1147))
+  (import "env" "longname1148" (func $internal1148))
+  (import "env" "longname1149" (func $internal1149))
+  (import "env" "longname1150" (func $internal1150))
+  (import "env" "longname1151" (func $internal1151))
+  (import "env" "longname1152" (func $internal1152))
+  (import "env" "longname1153" (func $internal1153))
+  (import "env" "longname1154" (func $internal1154))
+  (import "env" "longname1155" (func $internal1155))
+  (import "env" "longname1156" (func $internal1156))
+  (import "env" "longname1157" (func $internal1157))
+  (import "env" "longname1158" (func $internal1158))
+  (import "env" "longname1159" (func $internal1159))
+  (import "env" "longname1160" (func $internal1160))
+  (import "env" "longname1161" (func $internal1161))
+  (import "env" "longname1162" (func $internal1162))
+  (import "env" "longname1163" (func $internal1163))
+  (import "env" "longname1164" (func $internal1164))
+  (import "env" "longname1165" (func $internal1165))
+  (import "env" "longname1166" (func $internal1166))
+  (import "env" "longname1167" (func $internal1167))
+  (import "env" "longname1168" (func $internal1168))
+  (import "env" "longname1169" (func $internal1169))
+  (import "env" "longname1170" (func $internal1170))
+  (import "env" "longname1171" (func $internal1171))
+  (import "env" "longname1172" (func $internal1172))
+  (import "env" "longname1173" (func $internal1173))
+  (import "env" "longname1174" (func $internal1174))
+  (import "env" "longname1175" (func $internal1175))
+  (import "env" "longname1176" (func $internal1176))
+  (import "env" "longname1177" (func $internal1177))
+  (import "env" "longname1178" (func $internal1178))
+  (import "env" "longname1179" (func $internal1179))
+  (import "env" "longname1180" (func $internal1180))
+  (import "env" "longname1181" (func $internal1181))
+  (import "env" "longname1182" (func $internal1182))
+  (import "env" "longname1183" (func $internal1183))
+  (import "env" "longname1184" (func $internal1184))
+  (import "env" "longname1185" (func $internal1185))
+  (import "env" "longname1186" (func $internal1186))
+  (import "env" "longname1187" (func $internal1187))
+  (import "env" "longname1188" (func $internal1188))
+  (import "env" "longname1189" (func $internal1189))
+  (import "env" "longname1190" (func $internal1190))
+  (import "env" "longname1191" (func $internal1191))
+  (import "env" "longname1192" (func $internal1192))
+  (import "env" "longname1193" (func $internal1193))
+  (import "env" "longname1194" (func $internal1194))
+  (import "env" "longname1195" (func $internal1195))
+  (import "env" "longname1196" (func $internal1196))
+  (import "env" "longname1197" (func $internal1197))
+  (import "env" "longname1198" (func $internal1198))
+  (import "env" "longname1199" (func $internal1199))
+  (import "env" "longname1200" (func $internal1200))
+  (import "env" "longname1201" (func $internal1201))
+  (import "env" "longname1202" (func $internal1202))
+  (import "env" "longname1203" (func $internal1203))
+  (import "env" "longname1204" (func $internal1204))
+  (import "env" "longname1205" (func $internal1205))
+  (import "env" "longname1206" (func $internal1206))
+  (import "env" "longname1207" (func $internal1207))
+  (import "env" "longname1208" (func $internal1208))
+  (import "env" "longname1209" (func $internal1209))
+  (import "env" "longname1210" (func $internal1210))
+  (import "env" "longname1211" (func $internal1211))
+  (import "env" "longname1212" (func $internal1212))
+  (import "env" "longname1213" (func $internal1213))
+  (import "env" "longname1214" (func $internal1214))
+  (import "env" "longname1215" (func $internal1215))
+  (import "env" "longname1216" (func $internal1216))
+  (import "env" "longname1217" (func $internal1217))
+  (import "env" "longname1218" (func $internal1218))
+  (import "env" "longname1219" (func $internal1219))
+  (import "env" "longname1220" (func $internal1220))
+  (import "env" "longname1221" (func $internal1221))
+  (import "env" "longname1222" (func $internal1222))
+  (import "env" "longname1223" (func $internal1223))
+  (import "env" "longname1224" (func $internal1224))
+  (import "env" "longname1225" (func $internal1225))
+  (import "env" "longname1226" (func $internal1226))
+  (import "env" "longname1227" (func $internal1227))
+  (import "env" "longname1228" (func $internal1228))
+  (import "env" "longname1229" (func $internal1229))
+  (import "env" "longname1230" (func $internal1230))
+  (import "env" "longname1231" (func $internal1231))
+  (import "env" "longname1232" (func $internal1232))
+  (import "env" "longname1233" (func $internal1233))
+  (import "env" "longname1234" (func $internal1234))
+  (import "env" "longname1235" (func $internal1235))
+  (import "env" "longname1236" (func $internal1236))
+  (import "env" "longname1237" (func $internal1237))
+  (import "env" "longname1238" (func $internal1238))
+  (import "env" "longname1239" (func $internal1239))
+  (import "env" "longname1240" (func $internal1240))
+  (import "env" "longname1241" (func $internal1241))
+  (import "env" "longname1242" (func $internal1242))
+  (import "env" "longname1243" (func $internal1243))
+  (import "env" "longname1244" (func $internal1244))
+  (import "env" "longname1245" (func $internal1245))
+  (import "env" "longname1246" (func $internal1246))
+  (import "env" "longname1247" (func $internal1247))
+  (import "env" "longname1248" (func $internal1248))
+  (import "env" "longname1249" (func $internal1249))
+  (import "env" "longname1250" (func $internal1250))
+  (import "env" "longname1251" (func $internal1251))
+  (import "env" "longname1252" (func $internal1252))
+  (import "env" "longname1253" (func $internal1253))
+  (import "env" "longname1254" (func $internal1254))
+  (import "env" "longname1255" (func $internal1255))
+  (import "env" "longname1256" (func $internal1256))
+  (import "env" "longname1257" (func $internal1257))
+  (import "env" "longname1258" (func $internal1258))
+  (import "env" "longname1259" (func $internal1259))
+  (import "env" "longname1260" (func $internal1260))
+  (import "env" "longname1261" (func $internal1261))
+  (import "env" "longname1262" (func $internal1262))
+  (import "env" "longname1263" (func $internal1263))
+  (import "env" "longname1264" (func $internal1264))
+  (import "env" "longname1265" (func $internal1265))
+  (import "env" "longname1266" (func $internal1266))
+  (import "env" "longname1267" (func $internal1267))
+  (import "env" "longname1268" (func $internal1268))
+  (import "env" "longname1269" (func $internal1269))
+  (import "env" "longname1270" (func $internal1270))
+  (import "env" "longname1271" (func $internal1271))
+  (import "env" "longname1272" (func $internal1272))
+  (import "env" "longname1273" (func $internal1273))
+  (import "env" "longname1274" (func $internal1274))
+  (import "env" "longname1275" (func $internal1275))
+  (import "env" "longname1276" (func $internal1276))
+  (import "env" "longname1277" (func $internal1277))
+  (import "env" "longname1278" (func $internal1278))
+  (import "env" "longname1279" (func $internal1279))
+  (import "env" "longname1280" (func $internal1280))
+  (import "env" "longname1281" (func $internal1281))
+  (import "env" "longname1282" (func $internal1282))
+  (import "env" "longname1283" (func $internal1283))
+  (import "env" "longname1284" (func $internal1284))
+  (import "env" "longname1285" (func $internal1285))
+  (import "env" "longname1286" (func $internal1286))
+  (import "env" "longname1287" (func $internal1287))
+  (import "env" "longname1288" (func $internal1288))
+  (import "env" "longname1289" (func $internal1289))
+  (import "env" "longname1290" (func $internal1290))
+  (import "env" "longname1291" (func $internal1291))
+  (import "env" "longname1292" (func $internal1292))
+  (import "env" "longname1293" (func $internal1293))
+  (import "env" "longname1294" (func $internal1294))
+  (import "env" "longname1295" (func $internal1295))
+  (import "env" "longname1296" (func $internal1296))
+  (import "env" "longname1297" (func $internal1297))
+  (import "env" "longname1298" (func $internal1298))
+  (import "env" "longname1299" (func $internal1299))
+  (import "env" "longname1300" (func $internal1300))
+  (import "env" "longname1301" (func $internal1301))
+  (import "env" "longname1302" (func $internal1302))
+  (import "env" "longname1303" (func $internal1303))
+  (import "env" "longname1304" (func $internal1304))
+  (import "env" "longname1305" (func $internal1305))
+  (import "env" "longname1306" (func $internal1306))
+  (import "env" "longname1307" (func $internal1307))
+  (import "env" "longname1308" (func $internal1308))
+  (import "env" "longname1309" (func $internal1309))
+  (import "env" "longname1310" (func $internal1310))
+  (import "env" "longname1311" (func $internal1311))
+  (import "env" "longname1312" (func $internal1312))
+  (import "env" "longname1313" (func $internal1313))
+  (import "env" "longname1314" (func $internal1314))
+  (import "env" "longname1315" (func $internal1315))
+  (import "env" "longname1316" (func $internal1316))
+  (import "env" "longname1317" (func $internal1317))
+  (import "env" "longname1318" (func $internal1318))
+  (import "env" "longname1319" (func $internal1319))
+  (import "env" "longname1320" (func $internal1320))
+  (import "env" "longname1321" (func $internal1321))
+  (import "env" "longname1322" (func $internal1322))
+  (import "env" "longname1323" (func $internal1323))
+  (import "env" "longname1324" (func $internal1324))
+  (import "env" "longname1325" (func $internal1325))
+  (import "env" "longname1326" (func $internal1326))
+  (import "env" "longname1327" (func $internal1327))
+  (import "env" "longname1328" (func $internal1328))
+  (import "env" "longname1329" (func $internal1329))
+  (import "env" "longname1330" (func $internal1330))
+  (import "env" "longname1331" (func $internal1331))
+  (import "env" "longname1332" (func $internal1332))
+  (import "env" "longname1333" (func $internal1333))
+  (import "env" "longname1334" (func $internal1334))
+  (import "env" "longname1335" (func $internal1335))
+  (import "env" "longname1336" (func $internal1336))
+  (import "env" "longname1337" (func $internal1337))
+  (import "env" "longname1338" (func $internal1338))
+  (import "env" "longname1339" (func $internal1339))
+  (import "env" "longname1340" (func $internal1340))
+  (import "env" "longname1341" (func $internal1341))
+  (import "env" "longname1342" (func $internal1342))
+  (import "env" "longname1343" (func $internal1343))
+  (import "env" "longname1344" (func $internal1344))
+  (import "env" "longname1345" (func $internal1345))
+  (import "env" "longname1346" (func $internal1346))
+  (import "env" "longname1347" (func $internal1347))
+  (import "env" "longname1348" (func $internal1348))
+  (import "env" "longname1349" (func $internal1349))
+  (import "env" "longname1350" (func $internal1350))
+  (import "env" "longname1351" (func $internal1351))
+  (import "env" "longname1352" (func $internal1352))
+  (import "env" "longname1353" (func $internal1353))
+  (import "env" "longname1354" (func $internal1354))
+  (import "env" "longname1355" (func $internal1355))
+  (import "env" "longname1356" (func $internal1356))
+  (import "env" "longname1357" (func $internal1357))
+  (import "env" "longname1358" (func $internal1358))
+  (import "env" "longname1359" (func $internal1359))
+  (import "env" "longname1360" (func $internal1360))
+  (import "env" "longname1361" (func $internal1361))
+  (import "env" "longname1362" (func $internal1362))
+  (import "env" "longname1363" (func $internal1363))
+  (import "env" "longname1364" (func $internal1364))
+  (import "env" "longname1365" (func $internal1365))
+  (import "env" "longname1366" (func $internal1366))
+  (import "env" "longname1367" (func $internal1367))
+  (import "env" "longname1368" (func $internal1368))
+  (import "env" "longname1369" (func $internal1369))
+  (import "env" "longname1370" (func $internal1370))
+  (import "env" "longname1371" (func $internal1371))
+  (import "env" "longname1372" (func $internal1372))
+  (import "env" "longname1373" (func $internal1373))
+  (import "env" "longname1374" (func $internal1374))
+  (import "env" "longname1375" (func $internal1375))
+  (import "env" "longname1376" (func $internal1376))
+  (import "env" "longname1377" (func $internal1377))
+  (import "env" "longname1378" (func $internal1378))
+  (import "env" "longname1379" (func $internal1379))
+  (import "env" "longname1380" (func $internal1380))
+  (import "env" "longname1381" (func $internal1381))
+  (import "env" "longname1382" (func $internal1382))
+  (import "env" "longname1383" (func $internal1383))
+  (import "env" "longname1384" (func $internal1384))
+  (import "env" "longname1385" (func $internal1385))
+  (import "env" "longname1386" (func $internal1386))
+  (import "env" "longname1387" (func $internal1387))
+  (import "env" "longname1388" (func $internal1388))
+  (import "env" "longname1389" (func $internal1389))
+  (import "env" "longname1390" (func $internal1390))
+  (import "env" "longname1391" (func $internal1391))
+  (import "env" "longname1392" (func $internal1392))
+  (import "env" "longname1393" (func $internal1393))
+  (import "env" "longname1394" (func $internal1394))
+  (import "env" "longname1395" (func $internal1395))
+  (import "env" "longname1396" (func $internal1396))
+  (import "env" "longname1397" (func $internal1397))
+  (import "env" "longname1398" (func $internal1398))
+  (import "env" "longname1399" (func $internal1399))
+  (import "env" "longname1400" (func $internal1400))
+  (import "env" "longname1401" (func $internal1401))
+  (import "env" "longname1402" (func $internal1402))
+  (import "env" "longname1403" (func $internal1403))
+  (import "env" "longname1404" (func $internal1404))
+  (import "env" "longname1405" (func $internal1405))
+  (import "env" "longname1406" (func $internal1406))
+  (import "env" "longname1407" (func $internal1407))
+  (import "env" "longname1408" (func $internal1408))
+  (import "env" "longname1409" (func $internal1409))
+  (import "env" "longname1410" (func $internal1410))
+  (import "env" "longname1411" (func $internal1411))
+  (import "env" "longname1412" (func $internal1412))
+  (import "env" "longname1413" (func $internal1413))
+  (import "env" "longname1414" (func $internal1414))
+  (import "env" "longname1415" (func $internal1415))
+  (import "env" "longname1416" (func $internal1416))
+  (import "env" "longname1417" (func $internal1417))
+  (import "env" "longname1418" (func $internal1418))
+  (import "env" "longname1419" (func $internal1419))
+  (import "env" "longname1420" (func $internal1420))
+  (import "env" "longname1421" (func $internal1421))
+  (import "env" "longname1422" (func $internal1422))
+  (import "env" "longname1423" (func $internal1423))
+  (import "env" "longname1424" (func $internal1424))
+  (import "env" "longname1425" (func $internal1425))
+  (import "env" "longname1426" (func $internal1426))
+  (import "env" "longname1427" (func $internal1427))
+  (import "env" "longname1428" (func $internal1428))
+  (import "env" "longname1429" (func $internal1429))
+  (import "env" "longname1430" (func $internal1430))
+  (import "env" "longname1431" (func $internal1431))
+  (import "env" "longname1432" (func $internal1432))
+  (import "env" "longname1433" (func $internal1433))
+  (import "env" "longname1434" (func $internal1434))
+  (import "env" "longname1435" (func $internal1435))
+  (import "env" "longname1436" (func $internal1436))
+  (import "env" "longname1437" (func $internal1437))
+  (import "env" "longname1438" (func $internal1438))
+  (import "env" "longname1439" (func $internal1439))
+  (import "env" "longname1440" (func $internal1440))
+  (import "env" "longname1441" (func $internal1441))
+  (import "env" "longname1442" (func $internal1442))
+  (import "env" "longname1443" (func $internal1443))
+  (import "env" "longname1444" (func $internal1444))
+  (import "env" "longname1445" (func $internal1445))
+  (import "env" "longname1446" (func $internal1446))
+  (import "env" "longname1447" (func $internal1447))
+  (import "env" "longname1448" (func $internal1448))
+  (import "env" "longname1449" (func $internal1449))
+  (import "env" "longname1450" (func $internal1450))
+  (import "env" "longname1451" (func $internal1451))
+  (import "env" "longname1452" (func $internal1452))
+  (import "env" "longname1453" (func $internal1453))
+  (import "env" "longname1454" (func $internal1454))
+  (import "env" "longname1455" (func $internal1455))
+  (import "env" "longname1456" (func $internal1456))
+  (import "env" "longname1457" (func $internal1457))
+  (import "env" "longname1458" (func $internal1458))
+  (import "env" "longname1459" (func $internal1459))
+  (import "env" "longname1460" (func $internal1460))
+  (import "env" "longname1461" (func $internal1461))
+  (import "env" "longname1462" (func $internal1462))
+  (import "env" "longname1463" (func $internal1463))
+  (import "env" "longname1464" (func $internal1464))
+  (import "env" "longname1465" (func $internal1465))
+  (import "env" "longname1466" (func $internal1466))
+  (import "env" "longname1467" (func $internal1467))
+  (import "env" "longname1468" (func $internal1468))
+  (import "env" "longname1469" (func $internal1469))
+  (import "env" "longname1470" (func $internal1470))
+  (import "env" "longname1471" (func $internal1471))
+  (import "env" "longname1472" (func $internal1472))
+  (import "env" "longname1473" (func $internal1473))
+  (import "env" "longname1474" (func $internal1474))
+  (import "env" "longname1475" (func $internal1475))
+  (import "env" "longname1476" (func $internal1476))
+  (import "env" "longname1477" (func $internal1477))
+  (import "env" "longname1478" (func $internal1478))
+  (import "env" "longname1479" (func $internal1479))
+  (import "env" "longname1480" (func $internal1480))
+  (import "env" "longname1481" (func $internal1481))
+  (import "env" "longname1482" (func $internal1482))
+  (import "env" "longname1483" (func $internal1483))
+  (import "env" "longname1484" (func $internal1484))
+  (import "env" "longname1485" (func $internal1485))
+  (import "env" "longname1486" (func $internal1486))
+  (import "env" "longname1487" (func $internal1487))
+  (import "env" "longname1488" (func $internal1488))
+  (import "env" "longname1489" (func $internal1489))
+  (import "env" "longname1490" (func $internal1490))
+  (import "env" "longname1491" (func $internal1491))
+  (import "env" "longname1492" (func $internal1492))
+  (import "env" "longname1493" (func $internal1493))
+  (import "env" "longname1494" (func $internal1494))
+  (import "env" "longname1495" (func $internal1495))
+  (import "env" "longname1496" (func $internal1496))
+  (import "env" "longname1497" (func $internal1497))
+  (import "env" "longname1498" (func $internal1498))
+  (import "env" "longname1499" (func $internal1499))
+  (import "env" "longname1500" (func $internal1500))
+  (import "env" "longname1501" (func $internal1501))
+  (import "env" "longname1502" (func $internal1502))
+  (import "env" "longname1503" (func $internal1503))
+  (import "env" "longname1504" (func $internal1504))
+  (import "env" "longname1505" (func $internal1505))
+  (import "env" "longname1506" (func $internal1506))
+  (import "env" "longname1507" (func $internal1507))
+  (import "env" "longname1508" (func $internal1508))
+  (import "env" "longname1509" (func $internal1509))
+  (import "env" "longname1510" (func $internal1510))
+  (import "env" "longname1511" (func $internal1511))
+  (import "env" "longname1512" (func $internal1512))
+  (import "env" "longname1513" (func $internal1513))
+  (import "env" "longname1514" (func $internal1514))
+  (import "env" "longname1515" (func $internal1515))
+  (import "env" "longname1516" (func $internal1516))
+  (import "env" "longname1517" (func $internal1517))
+  (import "env" "longname1518" (func $internal1518))
+  (import "env" "longname1519" (func $internal1519))
+  (import "env" "longname1520" (func $internal1520))
+  (import "env" "longname1521" (func $internal1521))
+  (import "env" "longname1522" (func $internal1522))
+  (import "env" "longname1523" (func $internal1523))
+  (import "env" "longname1524" (func $internal1524))
+  (import "env" "longname1525" (func $internal1525))
+  (import "env" "longname1526" (func $internal1526))
+  (import "env" "longname1527" (func $internal1527))
+  (import "env" "longname1528" (func $internal1528))
+  (import "env" "longname1529" (func $internal1529))
+  (import "env" "longname1530" (func $internal1530))
+  (import "env" "longname1531" (func $internal1531))
+  (import "env" "longname1532" (func $internal1532))
+  (import "env" "longname1533" (func $internal1533))
+  (import "env" "longname1534" (func $internal1534))
+  (import "env" "longname1535" (func $internal1535))
+  (import "env" "longname1536" (func $internal1536))
+  (import "env" "longname1537" (func $internal1537))
+  (import "env" "longname1538" (func $internal1538))
+  (import "env" "longname1539" (func $internal1539))
+  (import "env" "longname1540" (func $internal1540))
+  (import "env" "longname1541" (func $internal1541))
+  (import "env" "longname1542" (func $internal1542))
+  (import "env" "longname1543" (func $internal1543))
+  (import "env" "longname1544" (func $internal1544))
+  (import "env" "longname1545" (func $internal1545))
+  (import "env" "longname1546" (func $internal1546))
+  (import "env" "longname1547" (func $internal1547))
+  (import "env" "longname1548" (func $internal1548))
+  (import "env" "longname1549" (func $internal1549))
+  (import "env" "longname1550" (func $internal1550))
+  (import "env" "longname1551" (func $internal1551))
+  (import "env" "longname1552" (func $internal1552))
+  (import "env" "longname1553" (func $internal1553))
+  (import "env" "longname1554" (func $internal1554))
+  (import "env" "longname1555" (func $internal1555))
+  (import "env" "longname1556" (func $internal1556))
+  (import "env" "longname1557" (func $internal1557))
+  (import "env" "longname1558" (func $internal1558))
+  (import "env" "longname1559" (func $internal1559))
+  (import "env" "longname1560" (func $internal1560))
+  (import "env" "longname1561" (func $internal1561))
+  (import "env" "longname1562" (func $internal1562))
+  (import "env" "longname1563" (func $internal1563))
+  (import "env" "longname1564" (func $internal1564))
+  (import "env" "longname1565" (func $internal1565))
+  (import "env" "longname1566" (func $internal1566))
+  (import "env" "longname1567" (func $internal1567))
+  (import "env" "longname1568" (func $internal1568))
+  (import "env" "longname1569" (func $internal1569))
+  (import "env" "longname1570" (func $internal1570))
+  (import "env" "longname1571" (func $internal1571))
+  (import "env" "longname1572" (func $internal1572))
+  (import "env" "longname1573" (func $internal1573))
+  (import "env" "longname1574" (func $internal1574))
+  (import "env" "longname1575" (func $internal1575))
+  (import "env" "longname1576" (func $internal1576))
+  (import "env" "longname1577" (func $internal1577))
+  (import "env" "longname1578" (func $internal1578))
+  (import "env" "longname1579" (func $internal1579))
+  (import "env" "longname1580" (func $internal1580))
+  (import "env" "longname1581" (func $internal1581))
+  (import "env" "longname1582" (func $internal1582))
+  (import "env" "longname1583" (func $internal1583))
+  (import "env" "longname1584" (func $internal1584))
+  (import "env" "longname1585" (func $internal1585))
+  (import "env" "longname1586" (func $internal1586))
+  (import "env" "longname1587" (func $internal1587))
+  (import "env" "longname1588" (func $internal1588))
+  (import "env" "longname1589" (func $internal1589))
+  (import "env" "longname1590" (func $internal1590))
+  (import "env" "longname1591" (func $internal1591))
+  (import "env" "longname1592" (func $internal1592))
+  (import "env" "longname1593" (func $internal1593))
+  (import "env" "longname1594" (func $internal1594))
+  (import "env" "longname1595" (func $internal1595))
+  (import "env" "longname1596" (func $internal1596))
+  (import "env" "longname1597" (func $internal1597))
+  (import "env" "longname1598" (func $internal1598))
+  (import "env" "longname1599" (func $internal1599))
+  (import "env" "longname1600" (func $internal1600))
+  (import "env" "longname1601" (func $internal1601))
+  (import "env" "longname1602" (func $internal1602))
+  (import "env" "longname1603" (func $internal1603))
+  (import "env" "longname1604" (func $internal1604))
+  (import "env" "longname1605" (func $internal1605))
+  (import "env" "longname1606" (func $internal1606))
+  (import "env" "longname1607" (func $internal1607))
+  (import "env" "longname1608" (func $internal1608))
+  (import "env" "longname1609" (func $internal1609))
+  (import "env" "longname1610" (func $internal1610))
+  (import "env" "longname1611" (func $internal1611))
+  (import "env" "longname1612" (func $internal1612))
+  (import "env" "longname1613" (func $internal1613))
+  (import "env" "longname1614" (func $internal1614))
+  (import "env" "longname1615" (func $internal1615))
+  (import "env" "longname1616" (func $internal1616))
+  (import "env" "longname1617" (func $internal1617))
+  (import "env" "longname1618" (func $internal1618))
+  (import "env" "longname1619" (func $internal1619))
+  (import "env" "longname1620" (func $internal1620))
+  (import "env" "longname1621" (func $internal1621))
+  (import "env" "longname1622" (func $internal1622))
+  (import "env" "longname1623" (func $internal1623))
+  (import "env" "longname1624" (func $internal1624))
+  (import "env" "longname1625" (func $internal1625))
+  (import "env" "longname1626" (func $internal1626))
+  (import "env" "longname1627" (func $internal1627))
+  (import "env" "longname1628" (func $internal1628))
+  (import "env" "longname1629" (func $internal1629))
+  (import "env" "longname1630" (func $internal1630))
+  (import "env" "longname1631" (func $internal1631))
+  (import "env" "longname1632" (func $internal1632))
+  (import "env" "longname1633" (func $internal1633))
+  (import "env" "longname1634" (func $internal1634))
+  (import "env" "longname1635" (func $internal1635))
+  (import "env" "longname1636" (func $internal1636))
+  (import "env" "longname1637" (func $internal1637))
+  (import "env" "longname1638" (func $internal1638))
+  (import "env" "longname1639" (func $internal1639))
+  (import "env" "longname1640" (func $internal1640))
+  (import "env" "longname1641" (func $internal1641))
+  (import "env" "longname1642" (func $internal1642))
+  (import "env" "longname1643" (func $internal1643))
+  (import "env" "longname1644" (func $internal1644))
+  (import "env" "longname1645" (func $internal1645))
+  (import "env" "longname1646" (func $internal1646))
+  (import "env" "longname1647" (func $internal1647))
+  (import "env" "longname1648" (func $internal1648))
+  (import "env" "longname1649" (func $internal1649))
+  (import "env" "longname1650" (func $internal1650))
+  (import "env" "longname1651" (func $internal1651))
+  (import "env" "longname1652" (func $internal1652))
+  (import "env" "longname1653" (func $internal1653))
+  (import "env" "longname1654" (func $internal1654))
+  (import "env" "longname1655" (func $internal1655))
+  (import "env" "longname1656" (func $internal1656))
+  (import "env" "longname1657" (func $internal1657))
+  (import "env" "longname1658" (func $internal1658))
+  (import "env" "longname1659" (func $internal1659))
+  (import "env" "longname1660" (func $internal1660))
+  (import "env" "longname1661" (func $internal1661))
+  (import "env" "longname1662" (func $internal1662))
+  (import "env" "longname1663" (func $internal1663))
+  (import "env" "longname1664" (func $internal1664))
+  (import "env" "longname1665" (func $internal1665))
+  (import "env" "longname1666" (func $internal1666))
+  (import "env" "longname1667" (func $internal1667))
+  (import "env" "longname1668" (func $internal1668))
+  (import "env" "longname1669" (func $internal1669))
+  (import "env" "longname1670" (func $internal1670))
+  (import "env" "longname1671" (func $internal1671))
+  (import "env" "longname1672" (func $internal1672))
+  (import "env" "longname1673" (func $internal1673))
+  (import "env" "longname1674" (func $internal1674))
+  (import "env" "longname1675" (func $internal1675))
+  (import "env" "longname1676" (func $internal1676))
+  (import "env" "longname1677" (func $internal1677))
+  (import "env" "longname1678" (func $internal1678))
+  (import "env" "longname1679" (func $internal1679))
+  (import "env" "longname1680" (func $internal1680))
+  (import "env" "longname1681" (func $internal1681))
+  (import "env" "longname1682" (func $internal1682))
+  (import "env" "longname1683" (func $internal1683))
+  (import "env" "longname1684" (func $internal1684))
+  (import "env" "longname1685" (func $internal1685))
+  (import "env" "longname1686" (func $internal1686))
+  (import "env" "longname1687" (func $internal1687))
+  (import "env" "longname1688" (func $internal1688))
+  (import "env" "longname1689" (func $internal1689))
+  (import "env" "longname1690" (func $internal1690))
+  (import "env" "longname1691" (func $internal1691))
+  (import "env" "longname1692" (func $internal1692))
+  (import "env" "longname1693" (func $internal1693))
+  (import "env" "longname1694" (func $internal1694))
+  (import "env" "longname1695" (func $internal1695))
+  (import "env" "longname1696" (func $internal1696))
+  (import "env" "longname1697" (func $internal1697))
+  (import "env" "longname1698" (func $internal1698))
+  (import "env" "longname1699" (func $internal1699))
+  (import "env" "longname1700" (func $internal1700))
+  (import "env" "longname1701" (func $internal1701))
+  (import "env" "longname1702" (func $internal1702))
+  (import "env" "longname1703" (func $internal1703))
+  (import "env" "longname1704" (func $internal1704))
+  (import "env" "longname1705" (func $internal1705))
+  (import "env" "longname1706" (func $internal1706))
+  (import "env" "longname1707" (func $internal1707))
+  (import "env" "longname1708" (func $internal1708))
+  (import "env" "longname1709" (func $internal1709))
+  (import "env" "longname1710" (func $internal1710))
+  (import "env" "longname1711" (func $internal1711))
+  (import "env" "longname1712" (func $internal1712))
+  (import "env" "longname1713" (func $internal1713))
+  (import "env" "longname1714" (func $internal1714))
+  (import "env" "longname1715" (func $internal1715))
+  (import "env" "longname1716" (func $internal1716))
+  (import "env" "longname1717" (func $internal1717))
+  (import "env" "longname1718" (func $internal1718))
+  (import "env" "longname1719" (func $internal1719))
+  (import "env" "longname1720" (func $internal1720))
+  (import "env" "longname1721" (func $internal1721))
+  (import "env" "longname1722" (func $internal1722))
+  (import "env" "longname1723" (func $internal1723))
+  (import "env" "longname1724" (func $internal1724))
+  (import "env" "longname1725" (func $internal1725))
+  (import "env" "longname1726" (func $internal1726))
+  (import "env" "longname1727" (func $internal1727))
+  (import "env" "longname1728" (func $internal1728))
+  (import "env" "longname1729" (func $internal1729))
+  (import "env" "longname1730" (func $internal1730))
+  (import "env" "longname1731" (func $internal1731))
+  (import "env" "longname1732" (func $internal1732))
+  (import "env" "longname1733" (func $internal1733))
+  (import "env" "longname1734" (func $internal1734))
+  (import "env" "longname1735" (func $internal1735))
+  (import "env" "longname1736" (func $internal1736))
+  (import "env" "longname1737" (func $internal1737))
+  (import "env" "longname1738" (func $internal1738))
+  (import "env" "longname1739" (func $internal1739))
+  (import "env" "longname1740" (func $internal1740))
+  (import "env" "longname1741" (func $internal1741))
+  (import "env" "longname1742" (func $internal1742))
+  (import "env" "longname1743" (func $internal1743))
+  (import "env" "longname1744" (func $internal1744))
+  (import "env" "longname1745" (func $internal1745))
+  (import "env" "longname1746" (func $internal1746))
+  (import "env" "longname1747" (func $internal1747))
+  (import "env" "longname1748" (func $internal1748))
+  (import "env" "longname1749" (func $internal1749))
+  (import "env" "longname1750" (func $internal1750))
+  (import "env" "longname1751" (func $internal1751))
+  (import "env" "longname1752" (func $internal1752))
+  (import "env" "longname1753" (func $internal1753))
+  (import "env" "longname1754" (func $internal1754))
+  (import "env" "longname1755" (func $internal1755))
+  (import "env" "longname1756" (func $internal1756))
+  (import "env" "longname1757" (func $internal1757))
+  (import "env" "longname1758" (func $internal1758))
+  (import "env" "longname1759" (func $internal1759))
+  (import "env" "longname1760" (func $internal1760))
+  (import "env" "longname1761" (func $internal1761))
+  (import "env" "longname1762" (func $internal1762))
+  (import "env" "longname1763" (func $internal1763))
+  (import "env" "longname1764" (func $internal1764))
+  (import "env" "longname1765" (func $internal1765))
+  (import "env" "longname1766" (func $internal1766))
+  (import "env" "longname1767" (func $internal1767))
+  (import "env" "longname1768" (func $internal1768))
+  (import "env" "longname1769" (func $internal1769))
+  (import "env" "longname1770" (func $internal1770))
+  (import "env" "longname1771" (func $internal1771))
+  (import "env" "longname1772" (func $internal1772))
+  (import "env" "longname1773" (func $internal1773))
+  (import "env" "longname1774" (func $internal1774))
+  (import "env" "longname1775" (func $internal1775))
+  (import "env" "longname1776" (func $internal1776))
+  (import "env" "longname1777" (func $internal1777))
+  (import "env" "longname1778" (func $internal1778))
+  (import "env" "longname1779" (func $internal1779))
+  (import "env" "longname1780" (func $internal1780))
+  (import "env" "longname1781" (func $internal1781))
+  (import "env" "longname1782" (func $internal1782))
+  (import "env" "longname1783" (func $internal1783))
+  (import "env" "longname1784" (func $internal1784))
+  (import "env" "longname1785" (func $internal1785))
+  (import "env" "longname1786" (func $internal1786))
+  (import "env" "longname1787" (func $internal1787))
+  (import "env" "longname1788" (func $internal1788))
+  (import "env" "longname1789" (func $internal1789))
+  (import "env" "longname1790" (func $internal1790))
+  (import "env" "longname1791" (func $internal1791))
+  (import "env" "longname1792" (func $internal1792))
+  (import "env" "longname1793" (func $internal1793))
+  (import "env" "longname1794" (func $internal1794))
+  (import "env" "longname1795" (func $internal1795))
+  (import "env" "longname1796" (func $internal1796))
+  (import "env" "longname1797" (func $internal1797))
+  (import "env" "longname1798" (func $internal1798))
+  (import "env" "longname1799" (func $internal1799))
+  (import "env" "longname1800" (func $internal1800))
+  (import "env" "longname1801" (func $internal1801))
+  (import "env" "longname1802" (func $internal1802))
+  (import "env" "longname1803" (func $internal1803))
+  (import "env" "longname1804" (func $internal1804))
+  (import "env" "longname1805" (func $internal1805))
+  (import "env" "longname1806" (func $internal1806))
+  (import "env" "longname1807" (func $internal1807))
+  (import "env" "longname1808" (func $internal1808))
+  (import "env" "longname1809" (func $internal1809))
+  (import "env" "longname1810" (func $internal1810))
+  (import "env" "longname1811" (func $internal1811))
+  (import "env" "longname1812" (func $internal1812))
+  (import "env" "longname1813" (func $internal1813))
+  (import "env" "longname1814" (func $internal1814))
+  (import "env" "longname1815" (func $internal1815))
+  (import "env" "longname1816" (func $internal1816))
+  (import "env" "longname1817" (func $internal1817))
+  (import "env" "longname1818" (func $internal1818))
+  (import "env" "longname1819" (func $internal1819))
+  (import "env" "longname1820" (func $internal1820))
+  (import "env" "longname1821" (func $internal1821))
+  (import "env" "longname1822" (func $internal1822))
+  (import "env" "longname1823" (func $internal1823))
+  (import "env" "longname1824" (func $internal1824))
+  (import "env" "longname1825" (func $internal1825))
+  (import "env" "longname1826" (func $internal1826))
+  (import "env" "longname1827" (func $internal1827))
+  (import "env" "longname1828" (func $internal1828))
+  (import "env" "longname1829" (func $internal1829))
+  (import "env" "longname1830" (func $internal1830))
+  (import "env" "longname1831" (func $internal1831))
+  (import "env" "longname1832" (func $internal1832))
+  (import "env" "longname1833" (func $internal1833))
+  (import "env" "longname1834" (func $internal1834))
+  (import "env" "longname1835" (func $internal1835))
+  (import "env" "longname1836" (func $internal1836))
+  (import "env" "longname1837" (func $internal1837))
+  (import "env" "longname1838" (func $internal1838))
+  (import "env" "longname1839" (func $internal1839))
+  (import "env" "longname1840" (func $internal1840))
+  (import "env" "longname1841" (func $internal1841))
+  (import "env" "longname1842" (func $internal1842))
+  (import "env" "longname1843" (func $internal1843))
+  (import "env" "longname1844" (func $internal1844))
+  (import "env" "longname1845" (func $internal1845))
+  (import "env" "longname1846" (func $internal1846))
+  (import "env" "longname1847" (func $internal1847))
+  (import "env" "longname1848" (func $internal1848))
+  (import "env" "longname1849" (func $internal1849))
+  (import "env" "longname1850" (func $internal1850))
+  (import "env" "longname1851" (func $internal1851))
+  (import "env" "longname1852" (func $internal1852))
+  (import "env" "longname1853" (func $internal1853))
+  (import "env" "longname1854" (func $internal1854))
+  (import "env" "longname1855" (func $internal1855))
+  (import "env" "longname1856" (func $internal1856))
+  (import "env" "longname1857" (func $internal1857))
+  (import "env" "longname1858" (func $internal1858))
+  (import "env" "longname1859" (func $internal1859))
+  (import "env" "longname1860" (func $internal1860))
+  (import "env" "longname1861" (func $internal1861))
+  (import "env" "longname1862" (func $internal1862))
+  (import "env" "longname1863" (func $internal1863))
+  (import "env" "longname1864" (func $internal1864))
+  (import "env" "longname1865" (func $internal1865))
+  (import "env" "longname1866" (func $internal1866))
+  (import "env" "longname1867" (func $internal1867))
+  (import "env" "longname1868" (func $internal1868))
+  (import "env" "longname1869" (func $internal1869))
+  (import "env" "longname1870" (func $internal1870))
+  (import "env" "longname1871" (func $internal1871))
+  (import "env" "longname1872" (func $internal1872))
+  (import "env" "longname1873" (func $internal1873))
+  (import "env" "longname1874" (func $internal1874))
+  (import "env" "longname1875" (func $internal1875))
+  (import "env" "longname1876" (func $internal1876))
+  (import "env" "longname1877" (func $internal1877))
+  (import "env" "longname1878" (func $internal1878))
+  (import "env" "longname1879" (func $internal1879))
+  (import "env" "longname1880" (func $internal1880))
+  (import "env" "longname1881" (func $internal1881))
+  (import "env" "longname1882" (func $internal1882))
+  (import "env" "longname1883" (func $internal1883))
+  (import "env" "longname1884" (func $internal1884))
+  (import "env" "longname1885" (func $internal1885))
+  (import "env" "longname1886" (func $internal1886))
+  (import "env" "longname1887" (func $internal1887))
+  (import "env" "longname1888" (func $internal1888))
+  (import "env" "longname1889" (func $internal1889))
+  (import "env" "longname1890" (func $internal1890))
+  (import "env" "longname1891" (func $internal1891))
+  (import "env" "longname1892" (func $internal1892))
+  (import "env" "longname1893" (func $internal1893))
+  (import "env" "longname1894" (func $internal1894))
+  (import "env" "longname1895" (func $internal1895))
+  (import "env" "longname1896" (func $internal1896))
+  (import "env" "longname1897" (func $internal1897))
+  (import "env" "longname1898" (func $internal1898))
+  (import "env" "longname1899" (func $internal1899))
+  (import "env" "longname1900" (func $internal1900))
+  (import "env" "longname1901" (func $internal1901))
+  (import "env" "longname1902" (func $internal1902))
+  (import "env" "longname1903" (func $internal1903))
+  (import "env" "longname1904" (func $internal1904))
+  (import "env" "longname1905" (func $internal1905))
+  (import "env" "longname1906" (func $internal1906))
+  (import "env" "longname1907" (func $internal1907))
+  (import "env" "longname1908" (func $internal1908))
+  (import "env" "longname1909" (func $internal1909))
+  (import "env" "longname1910" (func $internal1910))
+  (import "env" "longname1911" (func $internal1911))
+  (import "env" "longname1912" (func $internal1912))
+  (import "env" "longname1913" (func $internal1913))
+  (import "env" "longname1914" (func $internal1914))
+  (import "env" "longname1915" (func $internal1915))
+  (import "env" "longname1916" (func $internal1916))
+  (import "env" "longname1917" (func $internal1917))
+  (import "env" "longname1918" (func $internal1918))
+  (import "env" "longname1919" (func $internal1919))
+  (import "env" "longname1920" (func $internal1920))
+  (import "env" "longname1921" (func $internal1921))
+  (import "env" "longname1922" (func $internal1922))
+  (import "env" "longname1923" (func $internal1923))
+  (import "env" "longname1924" (func $internal1924))
+  (import "env" "longname1925" (func $internal1925))
+  (import "env" "longname1926" (func $internal1926))
+  (import "env" "longname1927" (func $internal1927))
+  (import "env" "longname1928" (func $internal1928))
+  (import "env" "longname1929" (func $internal1929))
+  (import "env" "longname1930" (func $internal1930))
+  (import "env" "longname1931" (func $internal1931))
+  (import "env" "longname1932" (func $internal1932))
+  (import "env" "longname1933" (func $internal1933))
+  (import "env" "longname1934" (func $internal1934))
+  (import "env" "longname1935" (func $internal1935))
+  (import "env" "longname1936" (func $internal1936))
+  (import "env" "longname1937" (func $internal1937))
+  (import "env" "longname1938" (func $internal1938))
+  (import "env" "longname1939" (func $internal1939))
+  (import "env" "longname1940" (func $internal1940))
+  (import "env" "longname1941" (func $internal1941))
+  (import "env" "longname1942" (func $internal1942))
+  (import "env" "longname1943" (func $internal1943))
+  (import "env" "longname1944" (func $internal1944))
+  (import "env" "longname1945" (func $internal1945))
+  (import "env" "longname1946" (func $internal1946))
+  (import "env" "longname1947" (func $internal1947))
+  (import "env" "longname1948" (func $internal1948))
+  (import "env" "longname1949" (func $internal1949))
+  (import "env" "longname1950" (func $internal1950))
+  (import "env" "longname1951" (func $internal1951))
+  (import "env" "longname1952" (func $internal1952))
+  (import "env" "longname1953" (func $internal1953))
+  (import "env" "longname1954" (func $internal1954))
+  (import "env" "longname1955" (func $internal1955))
+  (import "env" "longname1956" (func $internal1956))
+  (import "env" "longname1957" (func $internal1957))
+  (import "env" "longname1958" (func $internal1958))
+  (import "env" "longname1959" (func $internal1959))
+  (import "env" "longname1960" (func $internal1960))
+  (import "env" "longname1961" (func $internal1961))
+  (import "env" "longname1962" (func $internal1962))
+  (import "env" "longname1963" (func $internal1963))
+  (import "env" "longname1964" (func $internal1964))
+  (import "env" "longname1965" (func $internal1965))
+  (import "env" "longname1966" (func $internal1966))
+  (import "env" "longname1967" (func $internal1967))
+  (import "env" "longname1968" (func $internal1968))
+  (import "env" "longname1969" (func $internal1969))
+  (import "env" "longname1970" (func $internal1970))
+  (import "env" "longname1971" (func $internal1971))
+  (import "env" "longname1972" (func $internal1972))
+  (import "env" "longname1973" (func $internal1973))
+  (import "env" "longname1974" (func $internal1974))
+  (import "env" "longname1975" (func $internal1975))
+  (import "env" "longname1976" (func $internal1976))
+  (import "env" "longname1977" (func $internal1977))
+  (import "env" "longname1978" (func $internal1978))
+  (import "env" "longname1979" (func $internal1979))
+  (import "env" "longname1980" (func $internal1980))
+  (import "env" "longname1981" (func $internal1981))
+  (import "env" "longname1982" (func $internal1982))
+  (import "env" "longname1983" (func $internal1983))
+  (import "env" "longname1984" (func $internal1984))
+  (import "env" "longname1985" (func $internal1985))
+  (import "env" "longname1986" (func $internal1986))
+  (import "env" "longname1987" (func $internal1987))
+  (import "env" "longname1988" (func $internal1988))
+  (import "env" "longname1989" (func $internal1989))
+  (import "env" "longname1990" (func $internal1990))
+  (import "env" "longname1991" (func $internal1991))
+  (import "env" "longname1992" (func $internal1992))
+  (import "env" "longname1993" (func $internal1993))
+  (import "env" "longname1994" (func $internal1994))
+  (import "env" "longname1995" (func $internal1995))
+  (import "env" "longname1996" (func $internal1996))
+  (import "env" "longname1997" (func $internal1997))
+  (import "env" "longname1998" (func $internal1998))
+  (import "env" "longname1999" (func $internal1999))
+  (import "env" "longname2000" (func $internal2000))
+  (import "env" "longname2001" (func $internal2001))
+  (import "env" "longname2002" (func $internal2002))
+  (import "env" "longname2003" (func $internal2003))
+  (import "env" "longname2004" (func $internal2004))
+  (import "env" "longname2005" (func $internal2005))
+  (import "env" "longname2006" (func $internal2006))
+  (import "env" "longname2007" (func $internal2007))
+  (import "env" "longname2008" (func $internal2008))
+  (import "env" "longname2009" (func $internal2009))
+  (import "env" "longname2010" (func $internal2010))
+  (import "env" "longname2011" (func $internal2011))
+  (import "env" "longname2012" (func $internal2012))
+  (import "env" "longname2013" (func $internal2013))
+  (import "env" "longname2014" (func $internal2014))
+  (import "env" "longname2015" (func $internal2015))
+  (import "env" "longname2016" (func $internal2016))
+  (import "env" "longname2017" (func $internal2017))
+  (import "env" "longname2018" (func $internal2018))
+  (import "env" "longname2019" (func $internal2019))
+  (import "env" "longname2020" (func $internal2020))
+  (import "env" "longname2021" (func $internal2021))
+  (import "env" "longname2022" (func $internal2022))
+  (import "env" "longname2023" (func $internal2023))
+  (import "env" "longname2024" (func $internal2024))
+  (import "env" "longname2025" (func $internal2025))
+  (import "env" "longname2026" (func $internal2026))
+  (import "env" "longname2027" (func $internal2027))
+  (import "env" "longname2028" (func $internal2028))
+  (import "env" "longname2029" (func $internal2029))
+  (import "env" "longname2030" (func $internal2030))
+  (import "env" "longname2031" (func $internal2031))
+  (import "env" "longname2032" (func $internal2032))
+  (import "env" "longname2033" (func $internal2033))
+  (import "env" "longname2034" (func $internal2034))
+  (import "env" "longname2035" (func $internal2035))
+  (import "env" "longname2036" (func $internal2036))
+  (import "env" "longname2037" (func $internal2037))
+  (import "env" "longname2038" (func $internal2038))
+  (import "env" "longname2039" (func $internal2039))
+  (import "env" "longname2040" (func $internal2040))
+  (import "env" "longname2041" (func $internal2041))
+  (import "env" "longname2042" (func $internal2042))
+  (import "env" "longname2043" (func $internal2043))
+  (import "env" "longname2044" (func $internal2044))
+  (import "env" "longname2045" (func $internal2045))
+  (import "env" "longname2046" (func $internal2046))
+  (import "env" "longname2047" (func $internal2047))
+  (import "env" "longname2048" (func $internal2048))
+  (import "env" "longname2049" (func $internal2049))
+  (import "env" "longname2050" (func $internal2050))
+  (import "env" "longname2051" (func $internal2051))
+  (import "env" "longname2052" (func $internal2052))
+  (import "env" "longname2053" (func $internal2053))
+  (import "env" "longname2054" (func $internal2054))
+  (import "env" "longname2055" (func $internal2055))
+  (import "env" "longname2056" (func $internal2056))
+  (import "env" "longname2057" (func $internal2057))
+  (import "env" "longname2058" (func $internal2058))
+  (import "env" "longname2059" (func $internal2059))
+  (import "env" "longname2060" (func $internal2060))
+  (import "env" "longname2061" (func $internal2061))
+  (import "env" "longname2062" (func $internal2062))
+  (import "env" "longname2063" (func $internal2063))
+  (import "env" "longname2064" (func $internal2064))
+  (import "env" "longname2065" (func $internal2065))
+  (import "env" "longname2066" (func $internal2066))
+  (import "env" "longname2067" (func $internal2067))
+  (import "env" "longname2068" (func $internal2068))
+  (import "env" "longname2069" (func $internal2069))
+  (import "env" "longname2070" (func $internal2070))
+  (import "env" "longname2071" (func $internal2071))
+  (import "env" "longname2072" (func $internal2072))
+  (import "env" "longname2073" (func $internal2073))
+  (import "env" "longname2074" (func $internal2074))
+  (import "env" "longname2075" (func $internal2075))
+  (import "env" "longname2076" (func $internal2076))
+  (import "env" "longname2077" (func $internal2077))
+  (import "env" "longname2078" (func $internal2078))
+  (import "env" "longname2079" (func $internal2079))
+  (import "env" "longname2080" (func $internal2080))
+  (import "env" "longname2081" (func $internal2081))
+  (import "env" "longname2082" (func $internal2082))
+  (import "env" "longname2083" (func $internal2083))
+  (import "env" "longname2084" (func $internal2084))
+  (import "env" "longname2085" (func $internal2085))
+  (import "env" "longname2086" (func $internal2086))
+  (import "env" "longname2087" (func $internal2087))
+  (import "env" "longname2088" (func $internal2088))
+  (import "env" "longname2089" (func $internal2089))
+  (import "env" "longname2090" (func $internal2090))
+  (import "env" "longname2091" (func $internal2091))
+  (import "env" "longname2092" (func $internal2092))
+  (import "env" "longname2093" (func $internal2093))
+  (import "env" "longname2094" (func $internal2094))
+  (import "env" "longname2095" (func $internal2095))
+  (import "env" "longname2096" (func $internal2096))
+  (import "env" "longname2097" (func $internal2097))
+  (import "env" "longname2098" (func $internal2098))
+  (import "env" "longname2099" (func $internal2099))
+  (import "env" "longname2100" (func $internal2100))
+  (import "env" "longname2101" (func $internal2101))
+  (import "env" "longname2102" (func $internal2102))
+  (import "env" "longname2103" (func $internal2103))
+  (import "env" "longname2104" (func $internal2104))
+  (import "env" "longname2105" (func $internal2105))
+  (import "env" "longname2106" (func $internal2106))
+  (import "env" "longname2107" (func $internal2107))
+  (import "env" "longname2108" (func $internal2108))
+  (import "env" "longname2109" (func $internal2109))
+  (import "env" "longname2110" (func $internal2110))
+  (import "env" "longname2111" (func $internal2111))
+  (import "env" "longname2112" (func $internal2112))
+  (import "env" "longname2113" (func $internal2113))
+  (import "env" "longname2114" (func $internal2114))
+  (import "env" "longname2115" (func $internal2115))
+  (import "env" "longname2116" (func $internal2116))
+  (import "env" "longname2117" (func $internal2117))
+  (import "env" "longname2118" (func $internal2118))
+  (import "env" "longname2119" (func $internal2119))
+  (import "env" "longname2120" (func $internal2120))
+  (import "env" "longname2121" (func $internal2121))
+  (import "env" "longname2122" (func $internal2122))
+  (import "env" "longname2123" (func $internal2123))
+  (import "env" "longname2124" (func $internal2124))
+  (import "env" "longname2125" (func $internal2125))
+  (import "env" "longname2126" (func $internal2126))
+  (import "env" "longname2127" (func $internal2127))
+  (import "env" "longname2128" (func $internal2128))
+  (import "env" "longname2129" (func $internal2129))
+  (import "env" "longname2130" (func $internal2130))
+  (import "env" "longname2131" (func $internal2131))
+  (import "env" "longname2132" (func $internal2132))
+  (import "env" "longname2133" (func $internal2133))
+  (import "env" "longname2134" (func $internal2134))
+  (import "env" "longname2135" (func $internal2135))
+  (import "env" "longname2136" (func $internal2136))
+  (import "env" "longname2137" (func $internal2137))
+  (import "env" "longname2138" (func $internal2138))
+  (import "env" "longname2139" (func $internal2139))
+  (import "env" "longname2140" (func $internal2140))
+  (import "env" "longname2141" (func $internal2141))
+  (import "env" "longname2142" (func $internal2142))
+  (import "env" "longname2143" (func $internal2143))
+  (import "env" "longname2144" (func $internal2144))
+  (import "env" "longname2145" (func $internal2145))
+  (import "env" "longname2146" (func $internal2146))
+  (import "env" "longname2147" (func $internal2147))
+  (import "env" "longname2148" (func $internal2148))
+  (import "env" "longname2149" (func $internal2149))
+  (import "env" "longname2150" (func $internal2150))
+  (import "env" "longname2151" (func $internal2151))
+  (import "env" "longname2152" (func $internal2152))
+  (import "env" "longname2153" (func $internal2153))
+  (import "env" "longname2154" (func $internal2154))
+  (import "env" "longname2155" (func $internal2155))
+  (import "env" "longname2156" (func $internal2156))
+  (import "env" "longname2157" (func $internal2157))
+  (import "env" "longname2158" (func $internal2158))
+  (import "env" "longname2159" (func $internal2159))
+  (import "env" "longname2160" (func $internal2160))
+  (import "env" "longname2161" (func $internal2161))
+  (import "env" "longname2162" (func $internal2162))
+  (import "env" "longname2163" (func $internal2163))
+  (import "env" "longname2164" (func $internal2164))
+  (import "env" "longname2165" (func $internal2165))
+  (import "env" "longname2166" (func $internal2166))
+  (import "env" "longname2167" (func $internal2167))
+  (import "env" "longname2168" (func $internal2168))
+  (import "env" "longname2169" (func $internal2169))
+  (import "env" "longname2170" (func $internal2170))
+  (import "env" "longname2171" (func $internal2171))
+  (import "env" "longname2172" (func $internal2172))
+  (import "env" "longname2173" (func $internal2173))
+  (import "env" "longname2174" (func $internal2174))
+  (import "env" "longname2175" (func $internal2175))
+  (import "env" "longname2176" (func $internal2176))
+  (import "env" "longname2177" (func $internal2177))
+  (import "env" "longname2178" (func $internal2178))
+  (import "env" "longname2179" (func $internal2179))
+  (import "env" "longname2180" (func $internal2180))
+  (import "env" "longname2181" (func $internal2181))
+  (import "env" "longname2182" (func $internal2182))
+  (import "env" "longname2183" (func $internal2183))
+  (import "env" "longname2184" (func $internal2184))
+  (import "env" "longname2185" (func $internal2185))
+  (import "env" "longname2186" (func $internal2186))
+  (import "env" "longname2187" (func $internal2187))
+  (import "env" "longname2188" (func $internal2188))
+  (import "env" "longname2189" (func $internal2189))
+  (import "env" "longname2190" (func $internal2190))
+  (import "env" "longname2191" (func $internal2191))
+  (import "env" "longname2192" (func $internal2192))
+  (import "env" "longname2193" (func $internal2193))
+  (import "env" "longname2194" (func $internal2194))
+  (import "env" "longname2195" (func $internal2195))
+  (import "env" "longname2196" (func $internal2196))
+  (import "env" "longname2197" (func $internal2197))
+  (import "env" "longname2198" (func $internal2198))
+  (import "env" "longname2199" (func $internal2199))
+  (import "env" "longname2200" (func $internal2200))
+  (import "env" "longname2201" (func $internal2201))
+  (import "env" "longname2202" (func $internal2202))
+  (import "env" "longname2203" (func $internal2203))
+  (import "env" "longname2204" (func $internal2204))
+  (import "env" "longname2205" (func $internal2205))
+  (import "env" "longname2206" (func $internal2206))
+  (import "env" "longname2207" (func $internal2207))
+  (import "env" "longname2208" (func $internal2208))
+  (import "env" "longname2209" (func $internal2209))
+  (import "env" "longname2210" (func $internal2210))
+  (import "env" "longname2211" (func $internal2211))
+  (import "env" "longname2212" (func $internal2212))
+  (import "env" "longname2213" (func $internal2213))
+  (import "env" "longname2214" (func $internal2214))
+  (import "env" "longname2215" (func $internal2215))
+  (import "env" "longname2216" (func $internal2216))
+  (import "env" "longname2217" (func $internal2217))
+  (import "env" "longname2218" (func $internal2218))
+  (import "env" "longname2219" (func $internal2219))
+  (import "env" "longname2220" (func $internal2220))
+  (import "env" "longname2221" (func $internal2221))
+  (import "env" "longname2222" (func $internal2222))
+  (import "env" "longname2223" (func $internal2223))
+  (import "env" "longname2224" (func $internal2224))
+  (import "env" "longname2225" (func $internal2225))
+  (import "env" "longname2226" (func $internal2226))
+  (import "env" "longname2227" (func $internal2227))
+  (import "env" "longname2228" (func $internal2228))
+  (import "env" "longname2229" (func $internal2229))
+  (import "env" "longname2230" (func $internal2230))
+  (import "env" "longname2231" (func $internal2231))
+  (import "env" "longname2232" (func $internal2232))
+  (import "env" "longname2233" (func $internal2233))
+  (import "env" "longname2234" (func $internal2234))
+  (import "env" "longname2235" (func $internal2235))
+  (import "env" "longname2236" (func $internal2236))
+  (import "env" "longname2237" (func $internal2237))
+  (import "env" "longname2238" (func $internal2238))
+  (import "env" "longname2239" (func $internal2239))
+  (import "env" "longname2240" (func $internal2240))
+  (import "env" "longname2241" (func $internal2241))
+  (import "env" "longname2242" (func $internal2242))
+  (import "env" "longname2243" (func $internal2243))
+  (import "env" "longname2244" (func $internal2244))
+  (import "env" "longname2245" (func $internal2245))
+  (import "env" "longname2246" (func $internal2246))
+  (import "env" "longname2247" (func $internal2247))
+  (import "env" "longname2248" (func $internal2248))
+  (import "env" "longname2249" (func $internal2249))
+  (import "env" "longname2250" (func $internal2250))
+  (import "env" "longname2251" (func $internal2251))
+  (import "env" "longname2252" (func $internal2252))
+  (import "env" "longname2253" (func $internal2253))
+  (import "env" "longname2254" (func $internal2254))
+  (import "env" "longname2255" (func $internal2255))
+  (import "env" "longname2256" (func $internal2256))
+  (import "env" "longname2257" (func $internal2257))
+  (import "env" "longname2258" (func $internal2258))
+  (import "env" "longname2259" (func $internal2259))
+  (import "env" "longname2260" (func $internal2260))
+  (import "env" "longname2261" (func $internal2261))
+  (import "env" "longname2262" (func $internal2262))
+  (import "env" "longname2263" (func $internal2263))
+  (import "env" "longname2264" (func $internal2264))
+  (import "env" "longname2265" (func $internal2265))
+  (import "env" "longname2266" (func $internal2266))
+  (import "env" "longname2267" (func $internal2267))
+  (import "env" "longname2268" (func $internal2268))
+  (import "env" "longname2269" (func $internal2269))
+  (import "env" "longname2270" (func $internal2270))
+  (import "env" "longname2271" (func $internal2271))
+  (import "env" "longname2272" (func $internal2272))
+  (import "env" "longname2273" (func $internal2273))
+  (import "env" "longname2274" (func $internal2274))
+  (import "env" "longname2275" (func $internal2275))
+  (import "env" "longname2276" (func $internal2276))
+  (import "env" "longname2277" (func $internal2277))
+  (import "env" "longname2278" (func $internal2278))
+  (import "env" "longname2279" (func $internal2279))
+  (import "env" "longname2280" (func $internal2280))
+  (import "env" "longname2281" (func $internal2281))
+  (import "env" "longname2282" (func $internal2282))
+  (import "env" "longname2283" (func $internal2283))
+  (import "env" "longname2284" (func $internal2284))
+  (import "env" "longname2285" (func $internal2285))
+  (import "env" "longname2286" (func $internal2286))
+  (import "env" "longname2287" (func $internal2287))
+  (import "env" "longname2288" (func $internal2288))
+  (import "env" "longname2289" (func $internal2289))
+  (import "env" "longname2290" (func $internal2290))
+  (import "env" "longname2291" (func $internal2291))
+  (import "env" "longname2292" (func $internal2292))
+  (import "env" "longname2293" (func $internal2293))
+  (import "env" "longname2294" (func $internal2294))
+  (import "env" "longname2295" (func $internal2295))
+  (import "env" "longname2296" (func $internal2296))
+  (import "env" "longname2297" (func $internal2297))
+  (import "env" "longname2298" (func $internal2298))
+  (import "env" "longname2299" (func $internal2299))
+  (import "env" "longname2300" (func $internal2300))
+  (import "env" "longname2301" (func $internal2301))
+  (import "env" "longname2302" (func $internal2302))
+  (import "env" "longname2303" (func $internal2303))
+  (import "env" "longname2304" (func $internal2304))
+  (import "env" "longname2305" (func $internal2305))
+  (import "env" "longname2306" (func $internal2306))
+  (import "env" "longname2307" (func $internal2307))
+  (import "env" "longname2308" (func $internal2308))
+  (import "env" "longname2309" (func $internal2309))
+  (import "env" "longname2310" (func $internal2310))
+  (import "env" "longname2311" (func $internal2311))
+  (import "env" "longname2312" (func $internal2312))
+  (import "env" "longname2313" (func $internal2313))
+  (import "env" "longname2314" (func $internal2314))
+  (import "env" "longname2315" (func $internal2315))
+  (import "env" "longname2316" (func $internal2316))
+  (import "env" "longname2317" (func $internal2317))
+  (import "env" "longname2318" (func $internal2318))
+  (import "env" "longname2319" (func $internal2319))
+  (import "env" "longname2320" (func $internal2320))
+  (import "env" "longname2321" (func $internal2321))
+  (import "env" "longname2322" (func $internal2322))
+  (import "env" "longname2323" (func $internal2323))
+  (import "env" "longname2324" (func $internal2324))
+  (import "env" "longname2325" (func $internal2325))
+  (import "env" "longname2326" (func $internal2326))
+  (import "env" "longname2327" (func $internal2327))
+  (import "env" "longname2328" (func $internal2328))
+  (import "env" "longname2329" (func $internal2329))
+  (import "env" "longname2330" (func $internal2330))
+  (import "env" "longname2331" (func $internal2331))
+  (import "env" "longname2332" (func $internal2332))
+  (import "env" "longname2333" (func $internal2333))
+  (import "env" "longname2334" (func $internal2334))
+  (import "env" "longname2335" (func $internal2335))
+  (import "env" "longname2336" (func $internal2336))
+  (import "env" "longname2337" (func $internal2337))
+  (import "env" "longname2338" (func $internal2338))
+  (import "env" "longname2339" (func $internal2339))
+  (import "env" "longname2340" (func $internal2340))
+  (import "env" "longname2341" (func $internal2341))
+  (import "env" "longname2342" (func $internal2342))
+  (import "env" "longname2343" (func $internal2343))
+  (import "env" "longname2344" (func $internal2344))
+  (import "env" "longname2345" (func $internal2345))
+  (import "env" "longname2346" (func $internal2346))
+  (import "env" "longname2347" (func $internal2347))
+  (import "env" "longname2348" (func $internal2348))
+  (import "env" "longname2349" (func $internal2349))
+  (import "env" "longname2350" (func $internal2350))
+  (import "env" "longname2351" (func $internal2351))
+  (import "env" "longname2352" (func $internal2352))
+  (import "env" "longname2353" (func $internal2353))
+  (import "env" "longname2354" (func $internal2354))
+  (import "env" "longname2355" (func $internal2355))
+  (import "env" "longname2356" (func $internal2356))
+  (import "env" "longname2357" (func $internal2357))
+  (import "env" "longname2358" (func $internal2358))
+  (import "env" "longname2359" (func $internal2359))
+  (import "env" "longname2360" (func $internal2360))
+  (import "env" "longname2361" (func $internal2361))
+  (import "env" "longname2362" (func $internal2362))
+  (import "env" "longname2363" (func $internal2363))
+  (import "env" "longname2364" (func $internal2364))
+  (import "env" "longname2365" (func $internal2365))
+  (import "env" "longname2366" (func $internal2366))
+  (import "env" "longname2367" (func $internal2367))
+  (import "env" "longname2368" (func $internal2368))
+  (import "env" "longname2369" (func $internal2369))
+  (import "env" "longname2370" (func $internal2370))
+  (import "env" "longname2371" (func $internal2371))
+  (import "env" "longname2372" (func $internal2372))
+  (import "env" "longname2373" (func $internal2373))
+  (import "env" "longname2374" (func $internal2374))
+  (import "env" "longname2375" (func $internal2375))
+  (import "env" "longname2376" (func $internal2376))
+  (import "env" "longname2377" (func $internal2377))
+  (import "env" "longname2378" (func $internal2378))
+  (import "env" "longname2379" (func $internal2379))
+  (import "env" "longname2380" (func $internal2380))
+  (import "env" "longname2381" (func $internal2381))
+  (import "env" "longname2382" (func $internal2382))
+  (import "env" "longname2383" (func $internal2383))
+  (import "env" "longname2384" (func $internal2384))
+  (import "env" "longname2385" (func $internal2385))
+  (import "env" "longname2386" (func $internal2386))
+  (import "env" "longname2387" (func $internal2387))
+  (import "env" "longname2388" (func $internal2388))
+  (import "env" "longname2389" (func $internal2389))
+  (import "env" "longname2390" (func $internal2390))
+  (import "env" "longname2391" (func $internal2391))
+  (import "env" "longname2392" (func $internal2392))
+  (import "env" "longname2393" (func $internal2393))
+  (import "env" "longname2394" (func $internal2394))
+  (import "env" "longname2395" (func $internal2395))
+  (import "env" "longname2396" (func $internal2396))
+  (import "env" "longname2397" (func $internal2397))
+  (import "env" "longname2398" (func $internal2398))
+  (import "env" "longname2399" (func $internal2399))
+  (import "env" "longname2400" (func $internal2400))
+  (import "env" "longname2401" (func $internal2401))
+  (import "env" "longname2402" (func $internal2402))
+  (import "env" "longname2403" (func $internal2403))
+  (import "env" "longname2404" (func $internal2404))
+  (import "env" "longname2405" (func $internal2405))
+  (import "env" "longname2406" (func $internal2406))
+  (import "env" "longname2407" (func $internal2407))
+  (import "env" "longname2408" (func $internal2408))
+  (import "env" "longname2409" (func $internal2409))
+  (import "env" "longname2410" (func $internal2410))
+  (import "env" "longname2411" (func $internal2411))
+  (import "env" "longname2412" (func $internal2412))
+  (import "env" "longname2413" (func $internal2413))
+  (import "env" "longname2414" (func $internal2414))
+  (import "env" "longname2415" (func $internal2415))
+  (import "env" "longname2416" (func $internal2416))
+  (import "env" "longname2417" (func $internal2417))
+  (import "env" "longname2418" (func $internal2418))
+  (import "env" "longname2419" (func $internal2419))
+  (import "env" "longname2420" (func $internal2420))
+  (import "env" "longname2421" (func $internal2421))
+  (import "env" "longname2422" (func $internal2422))
+  (import "env" "longname2423" (func $internal2423))
+  (import "env" "longname2424" (func $internal2424))
+  (import "env" "longname2425" (func $internal2425))
+  (import "env" "longname2426" (func $internal2426))
+  (import "env" "longname2427" (func $internal2427))
+  (import "env" "longname2428" (func $internal2428))
+  (import "env" "longname2429" (func $internal2429))
+  (import "env" "longname2430" (func $internal2430))
+  (import "env" "longname2431" (func $internal2431))
+  (import "env" "longname2432" (func $internal2432))
+  (import "env" "longname2433" (func $internal2433))
+  (import "env" "longname2434" (func $internal2434))
+  (import "env" "longname2435" (func $internal2435))
+  (import "env" "longname2436" (func $internal2436))
+  (import "env" "longname2437" (func $internal2437))
+  (import "env" "longname2438" (func $internal2438))
+  (import "env" "longname2439" (func $internal2439))
+  (import "env" "longname2440" (func $internal2440))
+  (import "env" "longname2441" (func $internal2441))
+  (import "env" "longname2442" (func $internal2442))
+  (import "env" "longname2443" (func $internal2443))
+  (import "env" "longname2444" (func $internal2444))
+  (import "env" "longname2445" (func $internal2445))
+  (import "env" "longname2446" (func $internal2446))
+  (import "env" "longname2447" (func $internal2447))
+  (import "env" "longname2448" (func $internal2448))
+  (import "env" "longname2449" (func $internal2449))
+  (import "env" "longname2450" (func $internal2450))
+  (import "env" "longname2451" (func $internal2451))
+  (import "env" "longname2452" (func $internal2452))
+  (import "env" "longname2453" (func $internal2453))
+  (import "env" "longname2454" (func $internal2454))
+  (import "env" "longname2455" (func $internal2455))
+  (import "env" "longname2456" (func $internal2456))
+  (import "env" "longname2457" (func $internal2457))
+  (import "env" "longname2458" (func $internal2458))
+  (import "env" "longname2459" (func $internal2459))
+  (import "env" "longname2460" (func $internal2460))
+  (import "env" "longname2461" (func $internal2461))
+  (import "env" "longname2462" (func $internal2462))
+  (import "env" "longname2463" (func $internal2463))
+  (import "env" "longname2464" (func $internal2464))
+  (import "env" "longname2465" (func $internal2465))
+  (import "env" "longname2466" (func $internal2466))
+  (import "env" "longname2467" (func $internal2467))
+  (import "env" "longname2468" (func $internal2468))
+  (import "env" "longname2469" (func $internal2469))
+  (import "env" "longname2470" (func $internal2470))
+  (import "env" "longname2471" (func $internal2471))
+  (import "env" "longname2472" (func $internal2472))
+  (import "env" "longname2473" (func $internal2473))
+  (import "env" "longname2474" (func $internal2474))
+  (import "env" "longname2475" (func $internal2475))
+  (import "env" "longname2476" (func $internal2476))
+  (import "env" "longname2477" (func $internal2477))
+  (import "env" "longname2478" (func $internal2478))
+  (import "env" "longname2479" (func $internal2479))
+  (import "env" "longname2480" (func $internal2480))
+  (import "env" "longname2481" (func $internal2481))
+  (import "env" "longname2482" (func $internal2482))
+  (import "env" "longname2483" (func $internal2483))
+  (import "env" "longname2484" (func $internal2484))
+  (import "env" "longname2485" (func $internal2485))
+  (import "env" "longname2486" (func $internal2486))
+  (import "env" "longname2487" (func $internal2487))
+  (import "env" "longname2488" (func $internal2488))
+  (import "env" "longname2489" (func $internal2489))
+  (import "env" "longname2490" (func $internal2490))
+  (import "env" "longname2491" (func $internal2491))
+  (import "env" "longname2492" (func $internal2492))
+  (import "env" "longname2493" (func $internal2493))
+  (import "env" "longname2494" (func $internal2494))
+  (import "env" "longname2495" (func $internal2495))
+  (import "env" "longname2496" (func $internal2496))
+  (import "env" "longname2497" (func $internal2497))
+  (import "env" "longname2498" (func $internal2498))
+  (import "env" "longname2499" (func $internal2499))
+  (import "env" "longname2500" (func $internal2500))
+  (import "env" "longname2501" (func $internal2501))
+  (import "env" "longname2502" (func $internal2502))
+  (import "env" "longname2503" (func $internal2503))
+  (import "env" "longname2504" (func $internal2504))
+  (import "env" "longname2505" (func $internal2505))
+  (import "env" "longname2506" (func $internal2506))
+  (import "env" "longname2507" (func $internal2507))
+  (import "env" "longname2508" (func $internal2508))
+  (import "env" "longname2509" (func $internal2509))
+  (import "env" "longname2510" (func $internal2510))
+  (import "env" "longname2511" (func $internal2511))
+  (import "env" "longname2512" (func $internal2512))
+  (import "env" "longname2513" (func $internal2513))
+  (import "env" "longname2514" (func $internal2514))
+  (import "env" "longname2515" (func $internal2515))
+  (import "env" "longname2516" (func $internal2516))
+  (import "env" "longname2517" (func $internal2517))
+  (import "env" "longname2518" (func $internal2518))
+  (import "env" "longname2519" (func $internal2519))
+  (import "env" "longname2520" (func $internal2520))
+  (import "env" "longname2521" (func $internal2521))
+  (import "env" "longname2522" (func $internal2522))
+  (import "env" "longname2523" (func $internal2523))
+  (import "env" "longname2524" (func $internal2524))
+  (import "env" "longname2525" (func $internal2525))
+  (import "env" "longname2526" (func $internal2526))
+  (import "env" "longname2527" (func $internal2527))
+  (import "env" "longname2528" (func $internal2528))
+  (import "env" "longname2529" (func $internal2529))
+  (import "env" "longname2530" (func $internal2530))
+  (import "env" "longname2531" (func $internal2531))
+  (import "env" "longname2532" (func $internal2532))
+  (import "env" "longname2533" (func $internal2533))
+  (import "env" "longname2534" (func $internal2534))
+  (import "env" "longname2535" (func $internal2535))
+  (import "env" "longname2536" (func $internal2536))
+  (import "env" "longname2537" (func $internal2537))
+  (import "env" "longname2538" (func $internal2538))
+  (import "env" "longname2539" (func $internal2539))
+  (import "env" "longname2540" (func $internal2540))
+  (import "env" "longname2541" (func $internal2541))
+  (import "env" "longname2542" (func $internal2542))
+  (import "env" "longname2543" (func $internal2543))
+  (import "env" "longname2544" (func $internal2544))
+  (import "env" "longname2545" (func $internal2545))
+  (import "env" "longname2546" (func $internal2546))
+  (import "env" "longname2547" (func $internal2547))
+  (import "env" "longname2548" (func $internal2548))
+  (import "env" "longname2549" (func $internal2549))
+  (import "env" "longname2550" (func $internal2550))
+  (import "env" "longname2551" (func $internal2551))
+  (import "env" "longname2552" (func $internal2552))
+  (import "env" "longname2553" (func $internal2553))
+  (import "env" "longname2554" (func $internal2554))
+  (import "env" "longname2555" (func $internal2555))
+  (import "env" "longname2556" (func $internal2556))
+  (import "env" "longname2557" (func $internal2557))
+  (import "env" "longname2558" (func $internal2558))
+  (import "env" "longname2559" (func $internal2559))
+  (import "env" "longname2560" (func $internal2560))
+  (import "env" "longname2561" (func $internal2561))
+  (import "env" "longname2562" (func $internal2562))
+  (import "env" "longname2563" (func $internal2563))
+  (import "env" "longname2564" (func $internal2564))
+  (import "env" "longname2565" (func $internal2565))
+  (import "env" "longname2566" (func $internal2566))
+  (import "env" "longname2567" (func $internal2567))
+  (import "env" "longname2568" (func $internal2568))
+  (import "env" "longname2569" (func $internal2569))
+  (import "env" "longname2570" (func $internal2570))
+  (import "env" "longname2571" (func $internal2571))
+  (import "env" "longname2572" (func $internal2572))
+  (import "env" "longname2573" (func $internal2573))
+  (import "env" "longname2574" (func $internal2574))
+  (import "env" "longname2575" (func $internal2575))
+  (import "env" "longname2576" (func $internal2576))
+  (import "env" "longname2577" (func $internal2577))
+  (import "env" "longname2578" (func $internal2578))
+  (import "env" "longname2579" (func $internal2579))
+  (import "env" "longname2580" (func $internal2580))
+  (import "env" "longname2581" (func $internal2581))
+  (import "env" "longname2582" (func $internal2582))
+  (import "env" "longname2583" (func $internal2583))
+  (import "env" "longname2584" (func $internal2584))
+  (import "env" "longname2585" (func $internal2585))
+  (import "env" "longname2586" (func $internal2586))
+  (import "env" "longname2587" (func $internal2587))
+  (import "env" "longname2588" (func $internal2588))
+  (import "env" "longname2589" (func $internal2589))
+  (import "env" "longname2590" (func $internal2590))
+  (import "env" "longname2591" (func $internal2591))
+  (import "env" "longname2592" (func $internal2592))
+  (import "env" "longname2593" (func $internal2593))
+  (import "env" "longname2594" (func $internal2594))
+  (import "env" "longname2595" (func $internal2595))
+  (import "env" "longname2596" (func $internal2596))
+  (import "env" "longname2597" (func $internal2597))
+  (import "env" "longname2598" (func $internal2598))
+  (import "env" "longname2599" (func $internal2599))
+  (import "env" "longname2600" (func $internal2600))
+  (import "env" "longname2601" (func $internal2601))
+  (import "env" "longname2602" (func $internal2602))
+  (import "env" "longname2603" (func $internal2603))
+  (import "env" "longname2604" (func $internal2604))
+  (import "env" "longname2605" (func $internal2605))
+  (import "env" "longname2606" (func $internal2606))
+  (import "env" "longname2607" (func $internal2607))
+  (import "env" "longname2608" (func $internal2608))
+  (import "env" "longname2609" (func $internal2609))
+  (import "env" "longname2610" (func $internal2610))
+  (import "env" "longname2611" (func $internal2611))
+  (import "env" "longname2612" (func $internal2612))
+  (import "env" "longname2613" (func $internal2613))
+  (import "env" "longname2614" (func $internal2614))
+  (import "env" "longname2615" (func $internal2615))
+  (import "env" "longname2616" (func $internal2616))
+  (import "env" "longname2617" (func $internal2617))
+  (import "env" "longname2618" (func $internal2618))
+  (import "env" "longname2619" (func $internal2619))
+  (import "env" "longname2620" (func $internal2620))
+  (import "env" "longname2621" (func $internal2621))
+  (import "env" "longname2622" (func $internal2622))
+  (import "env" "longname2623" (func $internal2623))
+  (import "env" "longname2624" (func $internal2624))
+  (import "env" "longname2625" (func $internal2625))
+  (import "env" "longname2626" (func $internal2626))
+  (import "env" "longname2627" (func $internal2627))
+  (import "env" "longname2628" (func $internal2628))
+  (import "env" "longname2629" (func $internal2629))
+  (import "env" "longname2630" (func $internal2630))
+  (import "env" "longname2631" (func $internal2631))
+  (import "env" "longname2632" (func $internal2632))
+  (import "env" "longname2633" (func $internal2633))
+  (import "env" "longname2634" (func $internal2634))
+  (import "env" "longname2635" (func $internal2635))
+  (import "env" "longname2636" (func $internal2636))
+  (import "env" "longname2637" (func $internal2637))
+  (import "env" "longname2638" (func $internal2638))
+  (import "env" "longname2639" (func $internal2639))
+  (import "env" "longname2640" (func $internal2640))
+  (import "env" "longname2641" (func $internal2641))
+  (import "env" "longname2642" (func $internal2642))
+  (import "env" "longname2643" (func $internal2643))
+  (import "env" "longname2644" (func $internal2644))
+  (import "env" "longname2645" (func $internal2645))
+  (import "env" "longname2646" (func $internal2646))
+  (import "env" "longname2647" (func $internal2647))
+  (import "env" "longname2648" (func $internal2648))
+  (import "env" "longname2649" (func $internal2649))
+  (import "env" "longname2650" (func $internal2650))
+  (import "env" "longname2651" (func $internal2651))
+  (import "env" "longname2652" (func $internal2652))
+  (import "env" "longname2653" (func $internal2653))
+  (import "env" "longname2654" (func $internal2654))
+  (import "env" "longname2655" (func $internal2655))
+  (import "env" "longname2656" (func $internal2656))
+  (import "env" "longname2657" (func $internal2657))
+  (import "env" "longname2658" (func $internal2658))
+  (import "env" "longname2659" (func $internal2659))
+  (import "env" "longname2660" (func $internal2660))
+  (import "env" "longname2661" (func $internal2661))
+  (import "env" "longname2662" (func $internal2662))
+  (import "env" "longname2663" (func $internal2663))
+  (import "env" "longname2664" (func $internal2664))
+  (import "env" "longname2665" (func $internal2665))
+  (import "env" "longname2666" (func $internal2666))
+  (import "env" "longname2667" (func $internal2667))
+  (import "env" "longname2668" (func $internal2668))
+  (import "env" "longname2669" (func $internal2669))
+  (import "env" "longname2670" (func $internal2670))
+  (import "env" "longname2671" (func $internal2671))
+  (import "env" "longname2672" (func $internal2672))
+  (import "env" "longname2673" (func $internal2673))
+  (import "env" "longname2674" (func $internal2674))
+  (import "env" "longname2675" (func $internal2675))
+  (import "env" "longname2676" (func $internal2676))
+  (import "env" "longname2677" (func $internal2677))
+  (import "env" "longname2678" (func $internal2678))
+  (import "env" "longname2679" (func $internal2679))
+  (import "env" "longname2680" (func $internal2680))
+  (import "env" "longname2681" (func $internal2681))
+  (import "env" "longname2682" (func $internal2682))
+  (import "env" "longname2683" (func $internal2683))
+  (import "env" "longname2684" (func $internal2684))
+  (import "env" "longname2685" (func $internal2685))
+  (import "env" "longname2686" (func $internal2686))
+  (import "env" "longname2687" (func $internal2687))
+  (import "env" "longname2688" (func $internal2688))
+  (import "env" "longname2689" (func $internal2689))
+  (import "env" "longname2690" (func $internal2690))
+  (import "env" "longname2691" (func $internal2691))
+  (import "env" "longname2692" (func $internal2692))
+  (import "env" "longname2693" (func $internal2693))
+  (import "env" "longname2694" (func $internal2694))
+  (import "env" "longname2695" (func $internal2695))
+  (import "env" "longname2696" (func $internal2696))
+  (import "env" "longname2697" (func $internal2697))
+  (import "env" "longname2698" (func $internal2698))
+  (import "env" "longname2699" (func $internal2699))
+  (import "env" "longname2700" (func $internal2700))
+  (import "env" "longname2701" (func $internal2701))
+  (import "env" "longname2702" (func $internal2702))
+  (import "env" "longname2703" (func $internal2703))
+  (import "env" "longname2704" (func $internal2704))
+  (import "env" "longname2705" (func $internal2705))
+  (import "env" "longname2706" (func $internal2706))
+  (import "env" "longname2707" (func $internal2707))
+  (import "env" "longname2708" (func $internal2708))
+  (import "env" "longname2709" (func $internal2709))
+  (import "env" "longname2710" (func $internal2710))
+  (import "env" "longname2711" (func $internal2711))
+  (import "env" "longname2712" (func $internal2712))
+  (import "env" "longname2713" (func $internal2713))
+  (import "env" "longname2714" (func $internal2714))
+  (import "env" "longname2715" (func $internal2715))
+  (import "env" "longname2716" (func $internal2716))
+  (import "env" "longname2717" (func $internal2717))
+  (import "env" "longname2718" (func $internal2718))
+  (import "env" "longname2719" (func $internal2719))
+  (import "env" "longname2720" (func $internal2720))
+  (import "env" "longname2721" (func $internal2721))
+  (import "env" "longname2722" (func $internal2722))
+  (import "env" "longname2723" (func $internal2723))
+  (import "env" "longname2724" (func $internal2724))
+  (import "env" "longname2725" (func $internal2725))
+  (import "env" "longname2726" (func $internal2726))
+  (import "env" "longname2727" (func $internal2727))
+  (import "env" "longname2728" (func $internal2728))
+  (import "env" "longname2729" (func $internal2729))
+  (import "env" "longname2730" (func $internal2730))
+  (import "env" "longname2731" (func $internal2731))
+  (import "env" "longname2732" (func $internal2732))
+  (import "env" "longname2733" (func $internal2733))
+  (import "env" "longname2734" (func $internal2734))
+  (import "env" "longname2735" (func $internal2735))
+  (import "env" "longname2736" (func $internal2736))
+  (import "env" "longname2737" (func $internal2737))
+  (import "env" "longname2738" (func $internal2738))
+  (import "env" "longname2739" (func $internal2739))
+  (import "env" "longname2740" (func $internal2740))
+  (import "env" "longname2741" (func $internal2741))
+  (import "env" "longname2742" (func $internal2742))
+  (import "env" "longname2743" (func $internal2743))
+  (import "env" "longname2744" (func $internal2744))
+  (import "env" "longname2745" (func $internal2745))
+  (import "env" "longname2746" (func $internal2746))
+  (import "env" "longname2747" (func $internal2747))
+  (import "env" "longname2748" (func $internal2748))
+  (import "env" "longname2749" (func $internal2749))
+  (import "env" "longname2750" (func $internal2750))
+  (import "env" "longname2751" (func $internal2751))
+  (import "env" "longname2752" (func $internal2752))
+  (import "env" "longname2753" (func $internal2753))
+  (import "env" "longname2754" (func $internal2754))
+  (import "env" "longname2755" (func $internal2755))
+  (import "env" "longname2756" (func $internal2756))
+  (import "env" "longname2757" (func $internal2757))
+  (import "env" "longname2758" (func $internal2758))
+  (import "env" "longname2759" (func $internal2759))
+  (import "env" "longname2760" (func $internal2760))
+  (import "env" "longname2761" (func $internal2761))
+  (import "env" "longname2762" (func $internal2762))
+  (import "env" "longname2763" (func $internal2763))
+  (import "env" "longname2764" (func $internal2764))
+  (import "env" "longname2765" (func $internal2765))
+  (import "env" "longname2766" (func $internal2766))
+  (import "env" "longname2767" (func $internal2767))
+  (import "env" "longname2768" (func $internal2768))
+  (import "env" "longname2769" (func $internal2769))
+  (import "env" "longname2770" (func $internal2770))
+  (import "env" "longname2771" (func $internal2771))
+  (import "env" "longname2772" (func $internal2772))
+  (import "env" "longname2773" (func $internal2773))
+  (import "env" "longname2774" (func $internal2774))
+  (import "env" "longname2775" (func $internal2775))
+  (import "env" "longname2776" (func $internal2776))
+  (import "env" "longname2777" (func $internal2777))
+  (import "env" "longname2778" (func $internal2778))
+  (import "env" "longname2779" (func $internal2779))
+  (import "env" "longname2780" (func $internal2780))
+  (import "env" "longname2781" (func $internal2781))
+  (import "env" "longname2782" (func $internal2782))
+  (import "env" "longname2783" (func $internal2783))
+  (import "env" "longname2784" (func $internal2784))
+  (import "env" "longname2785" (func $internal2785))
+  (import "env" "longname2786" (func $internal2786))
+  (import "env" "longname2787" (func $internal2787))
+  (import "env" "longname2788" (func $internal2788))
+  (import "env" "longname2789" (func $internal2789))
+  (import "env" "longname2790" (func $internal2790))
+  (import "env" "longname2791" (func $internal2791))
+  (import "env" "longname2792" (func $internal2792))
+  (import "env" "longname2793" (func $internal2793))
+  (import "env" "longname2794" (func $internal2794))
+  (import "env" "longname2795" (func $internal2795))
+  (import "env" "longname2796" (func $internal2796))
+  (import "env" "longname2797" (func $internal2797))
+  (import "env" "longname2798" (func $internal2798))
+  (import "env" "longname2799" (func $internal2799))
+  (import "env" "longname2800" (func $internal2800))
+  (import "env" "longname2801" (func $internal2801))
+  (import "env" "longname2802" (func $internal2802))
+  (import "env" "longname2803" (func $internal2803))
+  (import "env" "longname2804" (func $internal2804))
+  (import "env" "longname2805" (func $internal2805))
+  (import "env" "longname2806" (func $internal2806))
+  (import "env" "longname2807" (func $internal2807))
+  (import "env" "longname2808" (func $internal2808))
+  (import "env" "longname2809" (func $internal2809))
+  (import "env" "longname2810" (func $internal2810))
+  (import "env" "longname2811" (func $internal2811))
+  (import "env" "longname2812" (func $internal2812))
+  (import "env" "longname2813" (func $internal2813))
+  (import "env" "longname2814" (func $internal2814))
+  (import "env" "longname2815" (func $internal2815))
+  (import "env" "longname2816" (func $internal2816))
+  (import "env" "longname2817" (func $internal2817))
+  (import "env" "longname2818" (func $internal2818))
+  (import "env" "longname2819" (func $internal2819))
+  (import "env" "longname2820" (func $internal2820))
+  (import "env" "longname2821" (func $internal2821))
+  (import "env" "longname2822" (func $internal2822))
+  (import "env" "longname2823" (func $internal2823))
+  (import "env" "longname2824" (func $internal2824))
+  (import "env" "longname2825" (func $internal2825))
+  (import "env" "longname2826" (func $internal2826))
+  (import "env" "longname2827" (func $internal2827))
+  (import "env" "longname2828" (func $internal2828))
+  (import "env" "longname2829" (func $internal2829))
+  (import "env" "longname2830" (func $internal2830))
+  (import "env" "longname2831" (func $internal2831))
+  (import "env" "longname2832" (func $internal2832))
+  (import "env" "longname2833" (func $internal2833))
+  (import "env" "longname2834" (func $internal2834))
+  (import "env" "longname2835" (func $internal2835))
+  (import "env" "longname2836" (func $internal2836))
+  (import "env" "longname2837" (func $internal2837))
+  (import "env" "longname2838" (func $internal2838))
+  (import "env" "longname2839" (func $internal2839))
+  (import "env" "longname2840" (func $internal2840))
+  (import "env" "longname2841" (func $internal2841))
+  (import "env" "longname2842" (func $internal2842))
+  (import "env" "longname2843" (func $internal2843))
+  (import "env" "longname2844" (func $internal2844))
+  (import "env" "longname2845" (func $internal2845))
+  (import "env" "longname2846" (func $internal2846))
+  (import "env" "longname2847" (func $internal2847))
+  (import "env" "longname2848" (func $internal2848))
+  (import "env" "longname2849" (func $internal2849))
+  (import "env" "longname2850" (func $internal2850))
+  (import "env" "longname2851" (func $internal2851))
+  (import "env" "longname2852" (func $internal2852))
+  (import "env" "longname2853" (func $internal2853))
+  (import "env" "longname2854" (func $internal2854))
+  (import "env" "longname2855" (func $internal2855))
+  (import "env" "longname2856" (func $internal2856))
+  (import "env" "longname2857" (func $internal2857))
+  (import "env" "longname2858" (func $internal2858))
+  (import "env" "longname2859" (func $internal2859))
+  (import "env" "longname2860" (func $internal2860))
+  (import "env" "longname2861" (func $internal2861))
+  (import "env" "longname2862" (func $internal2862))
+  (import "env" "longname2863" (func $internal2863))
+  (import "env" "longname2864" (func $internal2864))
+  (import "env" "longname2865" (func $internal2865))
+  (import "env" "longname2866" (func $internal2866))
+  (import "env" "longname2867" (func $internal2867))
+  (import "env" "longname2868" (func $internal2868))
+  (import "env" "longname2869" (func $internal2869))
+  (import "env" "longname2870" (func $internal2870))
+  (import "env" "longname2871" (func $internal2871))
+  (import "env" "longname2872" (func $internal2872))
+  (import "env" "longname2873" (func $internal2873))
+  (import "env" "longname2874" (func $internal2874))
+  (import "env" "longname2875" (func $internal2875))
+  (import "env" "longname2876" (func $internal2876))
+  (import "env" "longname2877" (func $internal2877))
+  (import "env" "longname2878" (func $internal2878))
+  (import "env" "longname2879" (func $internal2879))
+  (import "env" "longname2880" (func $internal2880))
+  (import "env" "longname2881" (func $internal2881))
+  (import "env" "longname2882" (func $internal2882))
+  (import "env" "longname2883" (func $internal2883))
+  (import "env" "longname2884" (func $internal2884))
+  (import "env" "longname2885" (func $internal2885))
+  (import "env" "longname2886" (func $internal2886))
+  (import "env" "longname2887" (func $internal2887))
+  (import "env" "longname2888" (func $internal2888))
+  (import "env" "longname2889" (func $internal2889))
+  (import "env" "longname2890" (func $internal2890))
+  (import "env" "longname2891" (func $internal2891))
+  (import "env" "longname2892" (func $internal2892))
+  (import "env" "longname2893" (func $internal2893))
+  (import "env" "longname2894" (func $internal2894))
+  (import "env" "longname2895" (func $internal2895))
+  (import "env" "longname2896" (func $internal2896))
+  (import "env" "longname2897" (func $internal2897))
+  (import "env" "longname2898" (func $internal2898))
+  (import "env" "longname2899" (func $internal2899))
+  (import "env" "longname2900" (func $internal2900))
+  (import "env" "longname2901" (func $internal2901))
+  (import "env" "longname2902" (func $internal2902))
+  (import "env" "longname2903" (func $internal2903))
+  (import "env" "longname2904" (func $internal2904))
+  (import "env" "longname2905" (func $internal2905))
+  (import "env" "longname2906" (func $internal2906))
+  (import "env" "longname2907" (func $internal2907))
+  (import "env" "longname2908" (func $internal2908))
+  (import "env" "longname2909" (func $internal2909))
+  (import "env" "longname2910" (func $internal2910))
+  (import "env" "longname2911" (func $internal2911))
+  (import "env" "longname2912" (func $internal2912))
+  (import "env" "longname2913" (func $internal2913))
+  (import "env" "longname2914" (func $internal2914))
+  (import "env" "longname2915" (func $internal2915))
+  (import "env" "longname2916" (func $internal2916))
+  (import "env" "longname2917" (func $internal2917))
+  (import "env" "longname2918" (func $internal2918))
+  (import "env" "longname2919" (func $internal2919))
+  (import "env" "longname2920" (func $internal2920))
+  (import "env" "longname2921" (func $internal2921))
+  (import "env" "longname2922" (func $internal2922))
+  (import "env" "longname2923" (func $internal2923))
+  (import "env" "longname2924" (func $internal2924))
+  (import "env" "longname2925" (func $internal2925))
+  (import "env" "longname2926" (func $internal2926))
+  (import "env" "longname2927" (func $internal2927))
+  (import "env" "longname2928" (func $internal2928))
+  (import "env" "longname2929" (func $internal2929))
+  (import "env" "longname2930" (func $internal2930))
+  (import "env" "longname2931" (func $internal2931))
+  (import "env" "longname2932" (func $internal2932))
+  (import "env" "longname2933" (func $internal2933))
+  (import "env" "longname2934" (func $internal2934))
+  (import "env" "longname2935" (func $internal2935))
+  (import "env" "longname2936" (func $internal2936))
+  (import "env" "longname2937" (func $internal2937))
+  (import "env" "longname2938" (func $internal2938))
+  (import "env" "longname2939" (func $internal2939))
+  (import "env" "longname2940" (func $internal2940))
+  (import "env" "longname2941" (func $internal2941))
+  (import "env" "longname2942" (func $internal2942))
+  (import "env" "longname2943" (func $internal2943))
+  (import "env" "longname2944" (func $internal2944))
+  (import "env" "longname2945" (func $internal2945))
+  (import "env" "longname2946" (func $internal2946))
+  (import "env" "longname2947" (func $internal2947))
+  (import "env" "longname2948" (func $internal2948))
+  (import "env" "longname2949" (func $internal2949))
+  (import "env" "longname2950" (func $internal2950))
+  (import "env" "longname2951" (func $internal2951))
+  (import "env" "longname2952" (func $internal2952))
+  (import "env" "longname2953" (func $internal2953))
+  (import "env" "longname2954" (func $internal2954))
+  (import "env" "longname2955" (func $internal2955))
+  (import "env" "longname2956" (func $internal2956))
+  (import "env" "longname2957" (func $internal2957))
+  (import "env" "longname2958" (func $internal2958))
+  (import "env" "longname2959" (func $internal2959))
+  (import "env" "longname2960" (func $internal2960))
+  (import "env" "longname2961" (func $internal2961))
+  (import "env" "longname2962" (func $internal2962))
+  (import "env" "longname2963" (func $internal2963))
+  (import "env" "longname2964" (func $internal2964))
+  (import "env" "longname2965" (func $internal2965))
+  (import "env" "longname2966" (func $internal2966))
+  (import "env" "longname2967" (func $internal2967))
+  (import "env" "longname2968" (func $internal2968))
+  (import "env" "longname2969" (func $internal2969))
+  (import "env" "longname2970" (func $internal2970))
+  (import "env" "longname2971" (func $internal2971))
+  (import "env" "longname2972" (func $internal2972))
+  (import "env" "longname2973" (func $internal2973))
+  (import "env" "longname2974" (func $internal2974))
+  (import "env" "longname2975" (func $internal2975))
+  (import "env" "longname2976" (func $internal2976))
+  (import "env" "longname2977" (func $internal2977))
+  (import "env" "longname2978" (func $internal2978))
+  (import "env" "longname2979" (func $internal2979))
+  (import "env" "longname2980" (func $internal2980))
+  (import "env" "longname2981" (func $internal2981))
+  (import "env" "longname2982" (func $internal2982))
+  (import "env" "longname2983" (func $internal2983))
+  (import "env" "longname2984" (func $internal2984))
+  (import "env" "longname2985" (func $internal2985))
+  (import "env" "longname2986" (func $internal2986))
+  (import "env" "longname2987" (func $internal2987))
+  (import "env" "longname2988" (func $internal2988))
+  (import "env" "longname2989" (func $internal2989))
+  (import "env" "longname2990" (func $internal2990))
+  (import "env" "longname2991" (func $internal2991))
+  (import "env" "longname2992" (func $internal2992))
+  (import "env" "longname2993" (func $internal2993))
+  (import "env" "longname2994" (func $internal2994))
+  (import "env" "longname2995" (func $internal2995))
+  (import "env" "longname2996" (func $internal2996))
+  (import "env" "longname2997" (func $internal2997))
+  (import "env" "longname2998" (func $internal2998))
+  (import "env" "longname2999" (func $internal2999))
+  (import "env" "longname3000" (func $internal3000))
+  (import "env" "longname3001" (func $internal3001))
+  (import "env" "longname3002" (func $internal3002))
+  (import "env" "longname3003" (func $internal3003))
+  (import "env" "longname3004" (func $internal3004))
+  (import "env" "longname3005" (func $internal3005))
+  (import "env" "longname3006" (func $internal3006))
+  (import "env" "longname3007" (func $internal3007))
+  (import "env" "longname3008" (func $internal3008))
+  (import "env" "longname3009" (func $internal3009))
+  (import "env" "longname3010" (func $internal3010))
+  (import "env" "longname3011" (func $internal3011))
+  (import "env" "longname3012" (func $internal3012))
+  (import "env" "longname3013" (func $internal3013))
+  (import "env" "longname3014" (func $internal3014))
+  (import "env" "longname3015" (func $internal3015))
+  (import "env" "longname3016" (func $internal3016))
+  (import "env" "longname3017" (func $internal3017))
+  (import "env" "longname3018" (func $internal3018))
+  (import "env" "longname3019" (func $internal3019))
+  (import "env" "longname3020" (func $internal3020))
+  (import "env" "longname3021" (func $internal3021))
+  (import "env" "longname3022" (func $internal3022))
+  (import "env" "longname3023" (func $internal3023))
+  (import "env" "longname3024" (func $internal3024))
+  (import "env" "longname3025" (func $internal3025))
+  (import "env" "longname3026" (func $internal3026))
+  (import "env" "longname3027" (func $internal3027))
+  (import "env" "longname3028" (func $internal3028))
+  (import "env" "longname3029" (func $internal3029))
+  (import "env" "longname3030" (func $internal3030))
+  (import "env" "longname3031" (func $internal3031))
+  (import "env" "longname3032" (func $internal3032))
+  (import "env" "longname3033" (func $internal3033))
+  (import "env" "longname3034" (func $internal3034))
+  (import "env" "longname3035" (func $internal3035))
+  (import "env" "longname3036" (func $internal3036))
+  (import "env" "longname3037" (func $internal3037))
+  (import "env" "longname3038" (func $internal3038))
+  (import "env" "longname3039" (func $internal3039))
+  (import "env" "longname3040" (func $internal3040))
+  (import "env" "longname3041" (func $internal3041))
+  (import "env" "longname3042" (func $internal3042))
+  (import "env" "longname3043" (func $internal3043))
+  (import "env" "longname3044" (func $internal3044))
+  (import "env" "longname3045" (func $internal3045))
+  (import "env" "longname3046" (func $internal3046))
+  (import "env" "longname3047" (func $internal3047))
+  (import "env" "longname3048" (func $internal3048))
+  (import "env" "longname3049" (func $internal3049))
+  (import "env" "longname3050" (func $internal3050))
+  (import "env" "longname3051" (func $internal3051))
+  (import "env" "longname3052" (func $internal3052))
+  (import "env" "longname3053" (func $internal3053))
+  (import "env" "longname3054" (func $internal3054))
+  (import "env" "longname3055" (func $internal3055))
+  (import "env" "longname3056" (func $internal3056))
+  (import "env" "longname3057" (func $internal3057))
+  (import "env" "longname3058" (func $internal3058))
+  (import "env" "longname3059" (func $internal3059))
+  (import "env" "longname3060" (func $internal3060))
+  (import "env" "longname3061" (func $internal3061))
+  (import "env" "longname3062" (func $internal3062))
+  (import "env" "longname3063" (func $internal3063))
+  (import "env" "longname3064" (func $internal3064))
+  (import "env" "longname3065" (func $internal3065))
+  (import "env" "longname3066" (func $internal3066))
+  (import "env" "longname3067" (func $internal3067))
+  (import "env" "longname3068" (func $internal3068))
+  (import "env" "longname3069" (func $internal3069))
+  (import "env" "longname3070" (func $internal3070))
+  (import "env" "longname3071" (func $internal3071))
+  (import "env" "longname3072" (func $internal3072))
+  (import "env" "longname3073" (func $internal3073))
+  (import "env" "longname3074" (func $internal3074))
+  (import "env" "longname3075" (func $internal3075))
+  (import "env" "longname3076" (func $internal3076))
+  (import "env" "longname3077" (func $internal3077))
+  (import "env" "longname3078" (func $internal3078))
+  (import "env" "longname3079" (func $internal3079))
+  (import "env" "longname3080" (func $internal3080))
+  (import "env" "longname3081" (func $internal3081))
+  (import "env" "longname3082" (func $internal3082))
+  (import "env" "longname3083" (func $internal3083))
+  (import "env" "longname3084" (func $internal3084))
+  (import "env" "longname3085" (func $internal3085))
+  (import "env" "longname3086" (func $internal3086))
+  (import "env" "longname3087" (func $internal3087))
+  (import "env" "longname3088" (func $internal3088))
+  (import "env" "longname3089" (func $internal3089))
+  (import "env" "longname3090" (func $internal3090))
+  (import "env" "longname3091" (func $internal3091))
+  (import "env" "longname3092" (func $internal3092))
+  (import "env" "longname3093" (func $internal3093))
+  (import "env" "longname3094" (func $internal3094))
+  (import "env" "longname3095" (func $internal3095))
+  (import "env" "longname3096" (func $internal3096))
+  (import "env" "longname3097" (func $internal3097))
+  (import "env" "longname3098" (func $internal3098))
+  (import "env" "longname3099" (func $internal3099))
+  (import "env" "longname3100" (func $internal3100))
+  (import "env" "longname3101" (func $internal3101))
+  (import "env" "longname3102" (func $internal3102))
+  (import "env" "longname3103" (func $internal3103))
+  (import "env" "longname3104" (func $internal3104))
+  (import "env" "longname3105" (func $internal3105))
+  (import "env" "longname3106" (func $internal3106))
+  (import "env" "longname3107" (func $internal3107))
+  (import "env" "longname3108" (func $internal3108))
+  (import "env" "longname3109" (func $internal3109))
+  (import "env" "longname3110" (func $internal3110))
+  (import "env" "longname3111" (func $internal3111))
+  (import "env" "longname3112" (func $internal3112))
+  (import "env" "longname3113" (func $internal3113))
+  (import "env" "longname3114" (func $internal3114))
+  (import "env" "longname3115" (func $internal3115))
+  (import "env" "longname3116" (func $internal3116))
+  (import "env" "longname3117" (func $internal3117))
+  (import "env" "longname3118" (func $internal3118))
+  (import "env" "longname3119" (func $internal3119))
+  (import "env" "longname3120" (func $internal3120))
+  (import "env" "longname3121" (func $internal3121))
+  (import "env" "longname3122" (func $internal3122))
+  (import "env" "longname3123" (func $internal3123))
+  (import "env" "longname3124" (func $internal3124))
+  (import "env" "longname3125" (func $internal3125))
+  (import "env" "longname3126" (func $internal3126))
+  (import "env" "longname3127" (func $internal3127))
+  (import "env" "longname3128" (func $internal3128))
+  (import "env" "longname3129" (func $internal3129))
+  (import "env" "longname3130" (func $internal3130))
+  (import "env" "longname3131" (func $internal3131))
+  (import "env" "longname3132" (func $internal3132))
+  (import "env" "longname3133" (func $internal3133))
+  (import "env" "longname3134" (func $internal3134))
+  (import "env" "longname3135" (func $internal3135))
+  (import "env" "longname3136" (func $internal3136))
+  (import "env" "longname3137" (func $internal3137))
+  (import "env" "longname3138" (func $internal3138))
+  (import "env" "longname3139" (func $internal3139))
+  (import "env" "longname3140" (func $internal3140))
+  (import "env" "longname3141" (func $internal3141))
+  (import "env" "longname3142" (func $internal3142))
+  (import "env" "longname3143" (func $internal3143))
+  (import "env" "longname3144" (func $internal3144))
+  (import "env" "longname3145" (func $internal3145))
+  (import "env" "longname3146" (func $internal3146))
+  (import "env" "longname3147" (func $internal3147))
+  (import "env" "longname3148" (func $internal3148))
+  (import "env" "longname3149" (func $internal3149))
+  (import "env" "longname3150" (func $internal3150))
+  (import "env" "longname3151" (func $internal3151))
+  (import "env" "longname3152" (func $internal3152))
+  (import "env" "longname3153" (func $internal3153))
+  (import "env" "longname3154" (func $internal3154))
+  (import "env" "longname3155" (func $internal3155))
+  (import "env" "longname3156" (func $internal3156))
+  (import "env" "longname3157" (func $internal3157))
+  (import "env" "longname3158" (func $internal3158))
+  (import "env" "longname3159" (func $internal3159))
+  (import "env" "longname3160" (func $internal3160))
+  (import "env" "longname3161" (func $internal3161))
+  (import "env" "longname3162" (func $internal3162))
+  (import "env" "longname3163" (func $internal3163))
+  (import "env" "longname3164" (func $internal3164))
+  (import "env" "longname3165" (func $internal3165))
+  (import "env" "longname3166" (func $internal3166))
+  (import "env" "longname3167" (func $internal3167))
+  (import "env" "longname3168" (func $internal3168))
+  (import "env" "longname3169" (func $internal3169))
+  (import "env" "longname3170" (func $internal3170))
+  (import "env" "longname3171" (func $internal3171))
+  (import "env" "longname3172" (func $internal3172))
+  (import "env" "longname3173" (func $internal3173))
+  (import "env" "longname3174" (func $internal3174))
+  (import "env" "longname3175" (func $internal3175))
+  (import "env" "longname3176" (func $internal3176))
+  (import "env" "longname3177" (func $internal3177))
+  (import "env" "longname3178" (func $internal3178))
+  (import "env" "longname3179" (func $internal3179))
+  (import "env" "longname3180" (func $internal3180))
+  (import "env" "longname3181" (func $internal3181))
+  (import "env" "longname3182" (func $internal3182))
+  (import "env" "longname3183" (func $internal3183))
+  (import "env" "longname3184" (func $internal3184))
+  (import "env" "longname3185" (func $internal3185))
+  (import "env" "longname3186" (func $internal3186))
+  (import "env" "longname3187" (func $internal3187))
+  (import "env" "longname3188" (func $internal3188))
+  (import "env" "longname3189" (func $internal3189))
+  (import "env" "longname3190" (func $internal3190))
+  (import "env" "longname3191" (func $internal3191))
+  (import "env" "longname3192" (func $internal3192))
+  (import "env" "longname3193" (func $internal3193))
+  (import "env" "longname3194" (func $internal3194))
+  (import "env" "longname3195" (func $internal3195))
+  (import "env" "longname3196" (func $internal3196))
+  (import "env" "longname3197" (func $internal3197))
+  (import "env" "longname3198" (func $internal3198))
+  (import "env" "longname3199" (func $internal3199))
+  (import "env" "longname3200" (func $internal3200))
+  (import "env" "longname3201" (func $internal3201))
+  (import "env" "longname3202" (func $internal3202))
+  (import "env" "longname3203" (func $internal3203))
+  (import "env" "longname3204" (func $internal3204))
+  (import "env" "longname3205" (func $internal3205))
+  (import "env" "longname3206" (func $internal3206))
+  (import "env" "longname3207" (func $internal3207))
+  (import "env" "longname3208" (func $internal3208))
+  (import "env" "longname3209" (func $internal3209))
+  (import "env" "longname3210" (func $internal3210))
+  (import "env" "longname3211" (func $internal3211))
+  (import "env" "longname3212" (func $internal3212))
+  (import "env" "longname3213" (func $internal3213))
+  (import "env" "longname3214" (func $internal3214))
+  (import "env" "longname3215" (func $internal3215))
+  (import "env" "longname3216" (func $internal3216))
+  (import "env" "longname3217" (func $internal3217))
+  (import "env" "longname3218" (func $internal3218))
+  (import "env" "longname3219" (func $internal3219))
+  (import "env" "longname3220" (func $internal3220))
+  (import "env" "longname3221" (func $internal3221))
+  (import "env" "longname3222" (func $internal3222))
+  (import "env" "longname3223" (func $internal3223))
+  (import "env" "longname3224" (func $internal3224))
+  (import "env" "longname3225" (func $internal3225))
+  (import "env" "longname3226" (func $internal3226))
+  (import "env" "longname3227" (func $internal3227))
+  (import "env" "longname3228" (func $internal3228))
+  (import "env" "longname3229" (func $internal3229))
+  (import "env" "longname3230" (func $internal3230))
+  (import "env" "longname3231" (func $internal3231))
+  (import "env" "longname3232" (func $internal3232))
+  (import "env" "longname3233" (func $internal3233))
+  (import "env" "longname3234" (func $internal3234))
+  (import "env" "longname3235" (func $internal3235))
+  (import "env" "longname3236" (func $internal3236))
+  (import "env" "longname3237" (func $internal3237))
+  (import "env" "longname3238" (func $internal3238))
+  (import "env" "longname3239" (func $internal3239))
+  (import "env" "longname3240" (func $internal3240))
+  (import "env" "longname3241" (func $internal3241))
+  (import "env" "longname3242" (func $internal3242))
+  (import "env" "longname3243" (func $internal3243))
+  (import "env" "longname3244" (func $internal3244))
+  (import "env" "longname3245" (func $internal3245))
+  (import "env" "longname3246" (func $internal3246))
+  (import "env" "longname3247" (func $internal3247))
+  (import "env" "longname3248" (func $internal3248))
+  (import "env" "longname3249" (func $internal3249))
+  (import "env" "longname3250" (func $internal3250))
+  (import "env" "longname3251" (func $internal3251))
+  (import "env" "longname3252" (func $internal3252))
+  (import "env" "longname3253" (func $internal3253))
+  (import "env" "longname3254" (func $internal3254))
+  (import "env" "longname3255" (func $internal3255))
+  (import "env" "longname3256" (func $internal3256))
+  (import "env" "longname3257" (func $internal3257))
+  (import "env" "longname3258" (func $internal3258))
+  (import "env" "longname3259" (func $internal3259))
+  (import "env" "longname3260" (func $internal3260))
+  (import "env" "longname3261" (func $internal3261))
+  (import "env" "longname3262" (func $internal3262))
+  (import "env" "longname3263" (func $internal3263))
+  (import "env" "longname3264" (func $internal3264))
+  (import "env" "longname3265" (func $internal3265))
+  (import "env" "longname3266" (func $internal3266))
+  (import "env" "longname3267" (func $internal3267))
+  (import "env" "longname3268" (func $internal3268))
+  (import "env" "longname3269" (func $internal3269))
+  (import "env" "longname3270" (func $internal3270))
+  (import "env" "longname3271" (func $internal3271))
+  (import "env" "longname3272" (func $internal3272))
+  (import "env" "longname3273" (func $internal3273))
+  (import "env" "longname3274" (func $internal3274))
+  (import "env" "longname3275" (func $internal3275))
+  (import "env" "longname3276" (func $internal3276))
+  (import "env" "longname3277" (func $internal3277))
+  (import "env" "longname3278" (func $internal3278))
+  (import "env" "longname3279" (func $internal3279))
+  (import "env" "longname3280" (func $internal3280))
+  (import "env" "longname3281" (func $internal3281))
+  (import "env" "longname3282" (func $internal3282))
+  (import "env" "longname3283" (func $internal3283))
+  (import "env" "longname3284" (func $internal3284))
+  (import "env" "longname3285" (func $internal3285))
+  (import "env" "longname3286" (func $internal3286))
+  (import "env" "longname3287" (func $internal3287))
+  (import "env" "longname3288" (func $internal3288))
+  (import "env" "longname3289" (func $internal3289))
+  (import "env" "longname3290" (func $internal3290))
+  (import "env" "longname3291" (func $internal3291))
+  (import "env" "longname3292" (func $internal3292))
+  (import "env" "longname3293" (func $internal3293))
+  (import "env" "longname3294" (func $internal3294))
+  (import "env" "longname3295" (func $internal3295))
+  (import "env" "longname3296" (func $internal3296))
+  (import "env" "longname3297" (func $internal3297))
+  (import "env" "longname3298" (func $internal3298))
+  (import "env" "longname3299" (func $internal3299))
+  (import "env" "longname3300" (func $internal3300))
+  (import "env" "longname3301" (func $internal3301))
+  (import "env" "longname3302" (func $internal3302))
+  (import "env" "longname3303" (func $internal3303))
+  (import "env" "longname3304" (func $internal3304))
+  (import "env" "longname3305" (func $internal3305))
+  (import "env" "longname3306" (func $internal3306))
+  (import "env" "longname3307" (func $internal3307))
+  (import "env" "longname3308" (func $internal3308))
+  (import "env" "longname3309" (func $internal3309))
+  (import "env" "longname3310" (func $internal3310))
+  (import "env" "longname3311" (func $internal3311))
+  (import "env" "longname3312" (func $internal3312))
+  (import "env" "longname3313" (func $internal3313))
+  (import "env" "longname3314" (func $internal3314))
+  (import "env" "longname3315" (func $internal3315))
+  (import "env" "longname3316" (func $internal3316))
+  (import "env" "longname3317" (func $internal3317))
+  (import "env" "longname3318" (func $internal3318))
+  (import "env" "longname3319" (func $internal3319))
+  (import "env" "longname3320" (func $internal3320))
+  (import "env" "longname3321" (func $internal3321))
+  (import "env" "longname3322" (func $internal3322))
+  (import "env" "longname3323" (func $internal3323))
+  (import "env" "longname3324" (func $internal3324))
+  (import "env" "longname3325" (func $internal3325))
+  (import "env" "longname3326" (func $internal3326))
+  (import "env" "longname3327" (func $internal3327))
+  (import "env" "longname3328" (func $internal3328))
+  (import "env" "longname3329" (func $internal3329))
+  (import "env" "longname3330" (func $internal3330))
+  (import "env" "longname3331" (func $internal3331))
+  (import "env" "longname3332" (func $internal3332))
+  (import "env" "longname3333" (func $internal3333))
+  (import "env" "longname3334" (func $internal3334))
+  (import "env" "longname3335" (func $internal3335))
+  (import "env" "longname3336" (func $internal3336))
+  (import "env" "longname3337" (func $internal3337))
+  (import "env" "longname3338" (func $internal3338))
+  (import "env" "longname3339" (func $internal3339))
+  (import "env" "longname3340" (func $internal3340))
+  (import "env" "longname3341" (func $internal3341))
+  (import "env" "longname3342" (func $internal3342))
+  (import "env" "longname3343" (func $internal3343))
+  (import "env" "longname3344" (func $internal3344))
+  (import "env" "longname3345" (func $internal3345))
+  (import "env" "longname3346" (func $internal3346))
+  (import "env" "longname3347" (func $internal3347))
+  (import "env" "longname3348" (func $internal3348))
+  (import "env" "longname3349" (func $internal3349))
+  (import "env" "longname3350" (func $internal3350))
+  (import "env" "longname3351" (func $internal3351))
+  (import "env" "longname3352" (func $internal3352))
+  (import "env" "longname3353" (func $internal3353))
+  (import "env" "longname3354" (func $internal3354))
+  (import "env" "longname3355" (func $internal3355))
+  (import "env" "longname3356" (func $internal3356))
+  (import "env" "longname3357" (func $internal3357))
+  (import "env" "longname3358" (func $internal3358))
+  (import "env" "longname3359" (func $internal3359))
+  (import "env" "longname3360" (func $internal3360))
+  (import "env" "longname3361" (func $internal3361))
+  (import "env" "longname3362" (func $internal3362))
+  (import "env" "longname3363" (func $internal3363))
+  (import "env" "longname3364" (func $internal3364))
+  (import "env" "longname3365" (func $internal3365))
+  (import "env" "longname3366" (func $internal3366))
+  (import "env" "longname3367" (func $internal3367))
+  (import "env" "longname3368" (func $internal3368))
+  (import "env" "longname3369" (func $internal3369))
+  (import "env" "longname3370" (func $internal3370))
+  (import "env" "longname3371" (func $internal3371))
+  (import "env" "longname3372" (func $internal3372))
+  (import "env" "longname3373" (func $internal3373))
+  (import "env" "longname3374" (func $internal3374))
+  (import "env" "longname3375" (func $internal3375))
+  (import "env" "longname3376" (func $internal3376))
+  (import "env" "longname3377" (func $internal3377))
+  (import "env" "longname3378" (func $internal3378))
+  (import "env" "longname3379" (func $internal3379))
+  (import "env" "longname3380" (func $internal3380))
+  (import "env" "longname3381" (func $internal3381))
+  (import "env" "longname3382" (func $internal3382))
+  (import "env" "longname3383" (func $internal3383))
+  (import "env" "longname3384" (func $internal3384))
+  (import "env" "longname3385" (func $internal3385))
+  (import "env" "longname3386" (func $internal3386))
+  (import "env" "longname3387" (func $internal3387))
+  (import "env" "longname3388" (func $internal3388))
+  (import "env" "longname3389" (func $internal3389))
+  (import "env" "longname3390" (func $internal3390))
+  (import "env" "longname3391" (func $internal3391))
+  (import "env" "longname3392" (func $internal3392))
+  (import "env" "longname3393" (func $internal3393))
+  (import "env" "longname3394" (func $internal3394))
+  (import "env" "longname3395" (func $internal3395))
+  (import "env" "longname3396" (func $internal3396))
+  (import "env" "longname3397" (func $internal3397))
+  (import "env" "longname3398" (func $internal3398))
+  (import "env" "longname3399" (func $internal3399))
+  (import "env" "longname3400" (func $internal3400))
+  (import "env" "longname3401" (func $internal3401))
+  (import "env" "longname3402" (func $internal3402))
+  (import "env" "longname3403" (func $internal3403))
+  (import "env" "longname3404" (func $internal3404))
+  (import "env" "longname3405" (func $internal3405))
+  (import "env" "longname3406" (func $internal3406))
+  (import "env" "longname3407" (func $internal3407))
+  (import "env" "longname3408" (func $internal3408))
+  (import "env" "longname3409" (func $internal3409))
+  (import "env" "longname3410" (func $internal3410))
+  (import "env" "longname3411" (func $internal3411))
+  (import "env" "longname3412" (func $internal3412))
+  (import "env" "longname3413" (func $internal3413))
+  (import "env" "longname3414" (func $internal3414))
+  (import "env" "longname3415" (func $internal3415))
+  (import "env" "longname3416" (func $internal3416))
+  (import "env" "longname3417" (func $internal3417))
+  (import "env" "longname3418" (func $internal3418))
+  (import "env" "longname3419" (func $internal3419))
+  (import "env" "longname3420" (func $internal3420))
+  (import "env" "longname3421" (func $internal3421))
+  (import "env" "longname3422" (func $internal3422))
+  (import "env" "longname3423" (func $internal3423))
+  (import "env" "longname3424" (func $internal3424))
+  (import "env" "longname3425" (func $internal3425))
+  (import "env" "longname3426" (func $internal3426))
+  (import "env" "longname3427" (func $internal3427))
+  (import "env" "longname3428" (func $internal3428))
+  (import "env" "longname3429" (func $internal3429))
+  (import "env" "longname3430" (func $internal3430))
+  (import "env" "longname3431" (func $internal3431))
+  (import "env" "longname3432" (func $internal3432))
+  (import "env" "longname3433" (func $internal3433))
+  (import "env" "longname3434" (func $internal3434))
+  (import "env" "longname3435" (func $internal3435))
+  (import "env" "longname3436" (func $internal3436))
+  (import "env" "longname3437" (func $internal3437))
+  (import "env" "longname3438" (func $internal3438))
+  (import "env" "longname3439" (func $internal3439))
+  (import "env" "longname3440" (func $internal3440))
+  (import "env" "longname3441" (func $internal3441))
+  (import "env" "longname3442" (func $internal3442))
+  (import "env" "longname3443" (func $internal3443))
+  (import "env" "longname3444" (func $internal3444))
+  (import "env" "longname3445" (func $internal3445))
+  (import "env" "longname3446" (func $internal3446))
+  (import "env" "longname3447" (func $internal3447))
+  (import "env" "longname3448" (func $internal3448))
+  (import "env" "longname3449" (func $internal3449))
+  (import "env" "longname3450" (func $internal3450))
+  (import "env" "longname3451" (func $internal3451))
+  (import "env" "longname3452" (func $internal3452))
+  (import "env" "longname3453" (func $internal3453))
+  (import "env" "longname3454" (func $internal3454))
+  (import "env" "longname3455" (func $internal3455))
+  (import "env" "longname3456" (func $internal3456))
+  (import "env" "longname3457" (func $internal3457))
+  (import "env" "longname3458" (func $internal3458))
+  (import "env" "longname3459" (func $internal3459))
+  (import "env" "longname3460" (func $internal3460))
+  (import "env" "longname3461" (func $internal3461))
+  (import "env" "longname3462" (func $internal3462))
+  (import "env" "longname3463" (func $internal3463))
+  (import "env" "longname3464" (func $internal3464))
+  (import "env" "longname3465" (func $internal3465))
+  (import "env" "longname3466" (func $internal3466))
+  (import "env" "longname3467" (func $internal3467))
+  (import "env" "longname3468" (func $internal3468))
+  (import "env" "longname3469" (func $internal3469))
+  (import "env" "longname3470" (func $internal3470))
+  (import "env" "longname3471" (func $internal3471))
+  (import "env" "longname3472" (func $internal3472))
+  (import "env" "longname3473" (func $internal3473))
+  (import "env" "longname3474" (func $internal3474))
+  (import "env" "longname3475" (func $internal3475))
+  (import "env" "longname3476" (func $internal3476))
+  (import "env" "longname3477" (func $internal3477))
+  (import "env" "longname3478" (func $internal3478))
+  (import "env" "longname3479" (func $internal3479))
+  (import "env" "longname3480" (func $internal3480))
+  (import "env" "longname3481" (func $internal3481))
+  (import "env" "longname3482" (func $internal3482))
+  (import "env" "longname3483" (func $internal3483))
+  (import "env" "longname3484" (func $internal3484))
+  (import "env" "longname3485" (func $internal3485))
+  (import "env" "longname3486" (func $internal3486))
+  (import "env" "longname3487" (func $internal3487))
+  (import "env" "longname3488" (func $internal3488))
+  (import "env" "longname3489" (func $internal3489))
+  (import "env" "longname3490" (func $internal3490))
+  (import "env" "longname3491" (func $internal3491))
+  (import "env" "longname3492" (func $internal3492))
+  (import "env" "longname3493" (func $internal3493))
+  (import "env" "longname3494" (func $internal3494))
+  (import "env" "longname3495" (func $internal3495))
+  (import "env" "longname3496" (func $internal3496))
+  (import "env" "longname3497" (func $internal3497))
+  (import "env" "longname3498" (func $internal3498))
+  (import "env" "longname3499" (func $internal3499))
+  (import "env" "longname3500" (func $internal3500))
+  (import "env" "longname3501" (func $internal3501))
+  (import "env" "longname3502" (func $internal3502))
+  (import "env" "longname3503" (func $internal3503))
+  (import "env" "longname3504" (func $internal3504))
+  (import "env" "longname3505" (func $internal3505))
+  (import "env" "longname3506" (func $internal3506))
+  (import "env" "longname3507" (func $internal3507))
+  (import "env" "longname3508" (func $internal3508))
+  (import "env" "longname3509" (func $internal3509))
+  (import "env" "longname3510" (func $internal3510))
+  (import "env" "longname3511" (func $internal3511))
+  (import "env" "longname3512" (func $internal3512))
+  (import "env" "longname3513" (func $internal3513))
+  (import "env" "longname3514" (func $internal3514))
+  (import "env" "longname3515" (func $internal3515))
+  (import "env" "longname3516" (func $internal3516))
+  (import "env" "longname3517" (func $internal3517))
+  (import "env" "longname3518" (func $internal3518))
+  (import "env" "longname3519" (func $internal3519))
+  (import "env" "longname3520" (func $internal3520))
+  (import "env" "longname3521" (func $internal3521))
+  (import "env" "longname3522" (func $internal3522))
+  (import "env" "longname3523" (func $internal3523))
+  (import "env" "longname3524" (func $internal3524))
+  (import "env" "longname3525" (func $internal3525))
+  (import "env" "longname3526" (func $internal3526))
+  (import "env" "longname3527" (func $internal3527))
+  (import "env" "longname3528" (func $internal3528))
+  (import "env" "longname3529" (func $internal3529))
+  (import "env" "longname3530" (func $internal3530))
+  (import "env" "longname3531" (func $internal3531))
+  (import "env" "longname3532" (func $internal3532))
+  (import "env" "longname3533" (func $internal3533))
+  (import "env" "longname3534" (func $internal3534))
+  (import "env" "longname3535" (func $internal3535))
+  (import "env" "longname3536" (func $internal3536))
+  (import "env" "longname3537" (func $internal3537))
+  (import "env" "longname3538" (func $internal3538))
+  (import "env" "longname3539" (func $internal3539))
+  (import "env" "longname3540" (func $internal3540))
+  (import "env" "longname3541" (func $internal3541))
+  (import "env" "longname3542" (func $internal3542))
+  (import "env" "longname3543" (func $internal3543))
+  (import "env" "longname3544" (func $internal3544))
+  (import "env" "longname3545" (func $internal3545))
+  (import "env" "longname3546" (func $internal3546))
+  (import "env" "longname3547" (func $internal3547))
+  (import "env" "longname3548" (func $internal3548))
+  (import "env" "longname3549" (func $internal3549))
+  (import "env" "longname3550" (func $internal3550))
+  (import "env" "longname3551" (func $internal3551))
+  (import "env" "longname3552" (func $internal3552))
+  (import "env" "longname3553" (func $internal3553))
+  (import "env" "longname3554" (func $internal3554))
+  (import "env" "longname3555" (func $internal3555))
+  (import "env" "longname3556" (func $internal3556))
+  (import "env" "longname3557" (func $internal3557))
+  (import "env" "longname3558" (func $internal3558))
+  (import "env" "longname3559" (func $internal3559))
+  (import "env" "longname3560" (func $internal3560))
+  (import "env" "longname3561" (func $internal3561))
+  (import "env" "longname3562" (func $internal3562))
+  (import "env" "longname3563" (func $internal3563))
+  (import "env" "longname3564" (func $internal3564))
+  (import "env" "longname3565" (func $internal3565))
+  (import "env" "longname3566" (func $internal3566))
+  (import "env" "longname3567" (func $internal3567))
+  (import "env" "longname3568" (func $internal3568))
+  (import "env" "longname3569" (func $internal3569))
+  (import "env" "longname3570" (func $internal3570))
+  (import "env" "longname3571" (func $internal3571))
+  (import "env" "longname3572" (func $internal3572))
+  (import "env" "longname3573" (func $internal3573))
+  (import "env" "longname3574" (func $internal3574))
+  (import "env" "longname3575" (func $internal3575))
+  (import "env" "longname3576" (func $internal3576))
+  (import "env" "longname3577" (func $internal3577))
+  (import "env" "longname3578" (func $internal3578))
+  (import "env" "longname3579" (func $internal3579))
+  (import "env" "longname3580" (func $internal3580))
+  (import "env" "longname3581" (func $internal3581))
+  (import "env" "longname3582" (func $internal3582))
+  (import "env" "longname3583" (func $internal3583))
+  (import "env" "longname3584" (func $internal3584))
+  (import "env" "longname3585" (func $internal3585))
+  (import "env" "longname3586" (func $internal3586))
+  (import "env" "longname3587" (func $internal3587))
+  (import "env" "longname3588" (func $internal3588))
+  (import "env" "longname3589" (func $internal3589))
+  (import "env" "longname3590" (func $internal3590))
+  (import "env" "longname3591" (func $internal3591))
+  (import "env" "longname3592" (func $internal3592))
+  (import "env" "longname3593" (func $internal3593))
+  (import "env" "longname3594" (func $internal3594))
+  (import "env" "longname3595" (func $internal3595))
+  (import "env" "longname3596" (func $internal3596))
+  (import "env" "longname3597" (func $internal3597))
+  (import "env" "longname3598" (func $internal3598))
+  (import "env" "longname3599" (func $internal3599))
+  (import "env" "longname3600" (func $internal3600))
+  (import "env" "longname3601" (func $internal3601))
+  (import "env" "longname3602" (func $internal3602))
+  (import "env" "longname3603" (func $internal3603))
+  (import "env" "longname3604" (func $internal3604))
+  (import "env" "longname3605" (func $internal3605))
+  (import "env" "longname3606" (func $internal3606))
+  (import "env" "longname3607" (func $internal3607))
+  (import "env" "longname3608" (func $internal3608))
+  (import "env" "longname3609" (func $internal3609))
+  (import "env" "longname3610" (func $internal3610))
+  (import "env" "longname3611" (func $internal3611))
+  (import "env" "longname3612" (func $internal3612))
+  (import "env" "longname3613" (func $internal3613))
+  (import "env" "longname3614" (func $internal3614))
+  (import "env" "longname3615" (func $internal3615))
+  (import "env" "longname3616" (func $internal3616))
+  (import "env" "longname3617" (func $internal3617))
+  (import "env" "longname3618" (func $internal3618))
+  (import "env" "longname3619" (func $internal3619))
+  (import "env" "longname3620" (func $internal3620))
+  (import "env" "longname3621" (func $internal3621))
+  (import "env" "longname3622" (func $internal3622))
+  (import "env" "longname3623" (func $internal3623))
+  (import "env" "longname3624" (func $internal3624))
+  (import "env" "longname3625" (func $internal3625))
+  (import "env" "longname3626" (func $internal3626))
+  (import "env" "longname3627" (func $internal3627))
+  (import "env" "longname3628" (func $internal3628))
+  (import "env" "longname3629" (func $internal3629))
+  (import "env" "longname3630" (func $internal3630))
+  (import "env" "longname3631" (func $internal3631))
+  (import "env" "longname3632" (func $internal3632))
+  (import "env" "longname3633" (func $internal3633))
+  (import "env" "longname3634" (func $internal3634))
+  (import "env" "longname3635" (func $internal3635))
+  (import "env" "longname3636" (func $internal3636))
+  (import "env" "longname3637" (func $internal3637))
+  (import "env" "longname3638" (func $internal3638))
+  (import "env" "longname3639" (func $internal3639))
+  (import "env" "longname3640" (func $internal3640))
+  (import "env" "longname3641" (func $internal3641))
+  (import "env" "longname3642" (func $internal3642))
+  (import "env" "longname3643" (func $internal3643))
+  (import "env" "longname3644" (func $internal3644))
+  (import "env" "longname3645" (func $internal3645))
+  (import "env" "longname3646" (func $internal3646))
+  (import "env" "longname3647" (func $internal3647))
+  (import "env" "longname3648" (func $internal3648))
+  (import "env" "longname3649" (func $internal3649))
+  (import "env" "longname3650" (func $internal3650))
+  (import "env" "longname3651" (func $internal3651))
+  (import "env" "longname3652" (func $internal3652))
+  (import "env" "longname3653" (func $internal3653))
+  (import "env" "longname3654" (func $internal3654))
+  (import "env" "longname3655" (func $internal3655))
+  (import "env" "longname3656" (func $internal3656))
+  (import "env" "longname3657" (func $internal3657))
+  (import "env" "longname3658" (func $internal3658))
+  (import "env" "longname3659" (func $internal3659))
+  (import "env" "longname3660" (func $internal3660))
+  (import "env" "longname3661" (func $internal3661))
+  (import "env" "longname3662" (func $internal3662))
+  (import "env" "longname3663" (func $internal3663))
+  (import "env" "longname3664" (func $internal3664))
+  (import "env" "longname3665" (func $internal3665))
+  (import "env" "longname3666" (func $internal3666))
+  (import "env" "longname3667" (func $internal3667))
+  (import "env" "longname3668" (func $internal3668))
+  (import "env" "longname3669" (func $internal3669))
+  (import "env" "longname3670" (func $internal3670))
+  (import "env" "longname3671" (func $internal3671))
+  (import "env" "longname3672" (func $internal3672))
+  (import "env" "longname3673" (func $internal3673))
+  (import "env" "longname3674" (func $internal3674))
+  (import "env" "longname3675" (func $internal3675))
+  (import "env" "longname3676" (func $internal3676))
+  (import "env" "longname3677" (func $internal3677))
+  (import "env" "longname3678" (func $internal3678))
+  (import "env" "longname3679" (func $internal3679))
+  (import "env" "longname3680" (func $internal3680))
+  (import "env" "longname3681" (func $internal3681))
+  (import "env" "longname3682" (func $internal3682))
+  (import "env" "longname3683" (func $internal3683))
+  (import "env" "longname3684" (func $internal3684))
+  (import "env" "longname3685" (func $internal3685))
+  (import "env" "longname3686" (func $internal3686))
+  (import "env" "longname3687" (func $internal3687))
+  (import "env" "longname3688" (func $internal3688))
+  (import "env" "longname3689" (func $internal3689))
+  (import "env" "longname3690" (func $internal3690))
+  (import "env" "longname3691" (func $internal3691))
+  (import "env" "longname3692" (func $internal3692))
+  (import "env" "longname3693" (func $internal3693))
+  (import "env" "longname3694" (func $internal3694))
+  (import "env" "longname3695" (func $internal3695))
+  (import "env" "longname3696" (func $internal3696))
+  (import "env" "longname3697" (func $internal3697))
+  (import "env" "longname3698" (func $internal3698))
+  (import "env" "longname3699" (func $internal3699))
+  (import "env" "longname3700" (func $internal3700))
+  (import "env" "longname3701" (func $internal3701))
+  (import "env" "longname3702" (func $internal3702))
+  (import "env" "longname3703" (func $internal3703))
+  (import "env" "longname3704" (func $internal3704))
+  (import "env" "longname3705" (func $internal3705))
+  (import "env" "longname3706" (func $internal3706))
+  (import "env" "longname3707" (func $internal3707))
+  (import "env" "longname3708" (func $internal3708))
+  (import "env" "longname3709" (func $internal3709))
+  (import "env" "longname3710" (func $internal3710))
+  (import "env" "longname3711" (func $internal3711))
+  (import "env" "longname3712" (func $internal3712))
+  (import "env" "longname3713" (func $internal3713))
+  (import "env" "longname3714" (func $internal3714))
+  (import "env" "longname3715" (func $internal3715))
+  (import "env" "longname3716" (func $internal3716))
+  (import "env" "longname3717" (func $internal3717))
+  (import "env" "longname3718" (func $internal3718))
+  (import "env" "longname3719" (func $internal3719))
+  (import "env" "longname3720" (func $internal3720))
+  (import "env" "longname3721" (func $internal3721))
+  (import "env" "longname3722" (func $internal3722))
+  (import "env" "longname3723" (func $internal3723))
+  (import "env" "longname3724" (func $internal3724))
+  (import "env" "longname3725" (func $internal3725))
+  (import "env" "longname3726" (func $internal3726))
+  (import "env" "longname3727" (func $internal3727))
+  (import "env" "longname3728" (func $internal3728))
+  (import "env" "longname3729" (func $internal3729))
+  (import "env" "longname3730" (func $internal3730))
+  (import "env" "longname3731" (func $internal3731))
+  (import "env" "longname3732" (func $internal3732))
+  (import "env" "longname3733" (func $internal3733))
+  (import "env" "longname3734" (func $internal3734))
+  (import "env" "longname3735" (func $internal3735))
+  (import "env" "longname3736" (func $internal3736))
+  (import "env" "longname3737" (func $internal3737))
+  (import "env" "longname3738" (func $internal3738))
+  (import "env" "longname3739" (func $internal3739))
+  (import "env" "longname3740" (func $internal3740))
+  (import "env" "longname3741" (func $internal3741))
+  (import "env" "longname3742" (func $internal3742))
+  (import "env" "longname3743" (func $internal3743))
+  (import "env" "longname3744" (func $internal3744))
+  (import "env" "longname3745" (func $internal3745))
+  (import "env" "longname3746" (func $internal3746))
+  (import "env" "longname3747" (func $internal3747))
+  (import "env" "longname3748" (func $internal3748))
+  (import "env" "longname3749" (func $internal3749))
+  (import "env" "longname3750" (func $internal3750))
+  (import "env" "longname3751" (func $internal3751))
+  (import "env" "longname3752" (func $internal3752))
+  (import "env" "longname3753" (func $internal3753))
+  (import "env" "longname3754" (func $internal3754))
+  (import "env" "longname3755" (func $internal3755))
+  (import "env" "longname3756" (func $internal3756))
+  (import "env" "longname3757" (func $internal3757))
+  (import "env" "longname3758" (func $internal3758))
+  (import "env" "longname3759" (func $internal3759))
+  (import "env" "longname3760" (func $internal3760))
+  (import "env" "longname3761" (func $internal3761))
+  (import "env" "longname3762" (func $internal3762))
+  (import "env" "longname3763" (func $internal3763))
+  (import "env" "longname3764" (func $internal3764))
+  (import "env" "longname3765" (func $internal3765))
+  (import "env" "longname3766" (func $internal3766))
+  (import "env" "longname3767" (func $internal3767))
+  (import "env" "longname3768" (func $internal3768))
+  (import "env" "longname3769" (func $internal3769))
+  (import "env" "longname3770" (func $internal3770))
+  (import "env" "longname3771" (func $internal3771))
+  (import "env" "longname3772" (func $internal3772))
+  (import "env" "longname3773" (func $internal3773))
+  (import "env" "longname3774" (func $internal3774))
+  (import "env" "longname3775" (func $internal3775))
+  (import "env" "longname3776" (func $internal3776))
+  (import "env" "longname3777" (func $internal3777))
+  (import "env" "longname3778" (func $internal3778))
+  (import "env" "longname3779" (func $internal3779))
+  (import "env" "longname3780" (func $internal3780))
+  (import "env" "longname3781" (func $internal3781))
+  (import "env" "longname3782" (func $internal3782))
+  (import "env" "longname3783" (func $internal3783))
+  (import "env" "longname3784" (func $internal3784))
+  (import "env" "longname3785" (func $internal3785))
+  (import "env" "longname3786" (func $internal3786))
+  (import "env" "longname3787" (func $internal3787))
+  (import "env" "longname3788" (func $internal3788))
+  (import "env" "longname3789" (func $internal3789))
+  (import "env" "longname3790" (func $internal3790))
+  (import "env" "longname3791" (func $internal3791))
+  (import "env" "longname3792" (func $internal3792))
+  (import "env" "longname3793" (func $internal3793))
+  (import "env" "longname3794" (func $internal3794))
+  (import "env" "longname3795" (func $internal3795))
+  (import "env" "longname3796" (func $internal3796))
+  (import "env" "longname3797" (func $internal3797))
+  (import "env" "longname3798" (func $internal3798))
+  (import "env" "longname3799" (func $internal3799))
+  (import "env" "longname3800" (func $internal3800))
+  (import "env" "longname3801" (func $internal3801))
+  (import "env" "longname3802" (func $internal3802))
+  (import "env" "longname3803" (func $internal3803))
+  (import "env" "longname3804" (func $internal3804))
+  (import "env" "longname3805" (func $internal3805))
+  (import "env" "longname3806" (func $internal3806))
+  (import "env" "longname3807" (func $internal3807))
+  (import "env" "longname3808" (func $internal3808))
+  (import "env" "longname3809" (func $internal3809))
+  (import "env" "longname3810" (func $internal3810))
+  (import "env" "longname3811" (func $internal3811))
+  (import "env" "longname3812" (func $internal3812))
+  (import "env" "longname3813" (func $internal3813))
+  (import "env" "longname3814" (func $internal3814))
+  (import "env" "longname3815" (func $internal3815))
+  (import "env" "longname3816" (func $internal3816))
+  (import "env" "longname3817" (func $internal3817))
+  (import "env" "longname3818" (func $internal3818))
+  (import "env" "longname3819" (func $internal3819))
+  (import "env" "longname3820" (func $internal3820))
+  (import "env" "longname3821" (func $internal3821))
+  (import "env" "longname3822" (func $internal3822))
+  (import "env" "longname3823" (func $internal3823))
+  (import "env" "longname3824" (func $internal3824))
+  (import "env" "longname3825" (func $internal3825))
+  (import "env" "longname3826" (func $internal3826))
+  (import "env" "longname3827" (func $internal3827))
+  (import "env" "longname3828" (func $internal3828))
+  (import "env" "longname3829" (func $internal3829))
+  (import "env" "longname3830" (func $internal3830))
+  (import "env" "longname3831" (func $internal3831))
+  (import "env" "longname3832" (func $internal3832))
+  (import "env" "longname3833" (func $internal3833))
+  (import "env" "longname3834" (func $internal3834))
+  (import "env" "longname3835" (func $internal3835))
+  (import "env" "longname3836" (func $internal3836))
+  (import "env" "longname3837" (func $internal3837))
+  (import "env" "longname3838" (func $internal3838))
+  (import "env" "longname3839" (func $internal3839))
+  (import "env" "longname3840" (func $internal3840))
+  (import "env" "longname3841" (func $internal3841))
+  (import "env" "longname3842" (func $internal3842))
+  (import "env" "longname3843" (func $internal3843))
+  (import "env" "longname3844" (func $internal3844))
+  (import "env" "longname3845" (func $internal3845))
+  (import "env" "longname3846" (func $internal3846))
+  (import "env" "longname3847" (func $internal3847))
+  (import "env" "longname3848" (func $internal3848))
+  (import "env" "longname3849" (func $internal3849))
+  (import "env" "longname3850" (func $internal3850))
+  (import "env" "longname3851" (func $internal3851))
+  (import "env" "longname3852" (func $internal3852))
+  (import "env" "longname3853" (func $internal3853))
+  (import "env" "longname3854" (func $internal3854))
+  (import "env" "longname3855" (func $internal3855))
+  (import "env" "longname3856" (func $internal3856))
+  (import "env" "longname3857" (func $internal3857))
+  (import "env" "longname3858" (func $internal3858))
+  (import "env" "longname3859" (func $internal3859))
+  (import "env" "longname3860" (func $internal3860))
+  (import "env" "longname3861" (func $internal3861))
+  (import "env" "longname3862" (func $internal3862))
+  (import "env" "longname3863" (func $internal3863))
+  (import "env" "longname3864" (func $internal3864))
+  (import "env" "longname3865" (func $internal3865))
+  (import "env" "longname3866" (func $internal3866))
+  (import "env" "longname3867" (func $internal3867))
+  (import "env" "longname3868" (func $internal3868))
+  (import "env" "longname3869" (func $internal3869))
+  (import "env" "longname3870" (func $internal3870))
+  (import "env" "longname3871" (func $internal3871))
+  (import "env" "longname3872" (func $internal3872))
+  (import "env" "longname3873" (func $internal3873))
+  (import "env" "longname3874" (func $internal3874))
+  (import "env" "longname3875" (func $internal3875))
+  (import "env" "longname3876" (func $internal3876))
+  (import "env" "longname3877" (func $internal3877))
+  (import "env" "longname3878" (func $internal3878))
+  (import "env" "longname3879" (func $internal3879))
+  (import "env" "longname3880" (func $internal3880))
+  (import "env" "longname3881" (func $internal3881))
+  (import "env" "longname3882" (func $internal3882))
+  (import "env" "longname3883" (func $internal3883))
+  (import "env" "longname3884" (func $internal3884))
+  (import "env" "longname3885" (func $internal3885))
+  (import "env" "longname3886" (func $internal3886))
+  (import "env" "longname3887" (func $internal3887))
+  (import "env" "longname3888" (func $internal3888))
+  (import "env" "longname3889" (func $internal3889))
+  (import "env" "longname3890" (func $internal3890))
+  (import "env" "longname3891" (func $internal3891))
+  (import "env" "longname3892" (func $internal3892))
+  (import "env" "longname3893" (func $internal3893))
+  (import "env" "longname3894" (func $internal3894))
+  (import "env" "longname3895" (func $internal3895))
+  (import "env" "longname3896" (func $internal3896))
+  (import "env" "longname3897" (func $internal3897))
+  (import "env" "longname3898" (func $internal3898))
+  (import "env" "longname3899" (func $internal3899))
+  (import "env" "longname3900" (func $internal3900))
+  (import "env" "longname3901" (func $internal3901))
+  (import "env" "longname3902" (func $internal3902))
+  (import "env" "longname3903" (func $internal3903))
+  (import "env" "longname3904" (func $internal3904))
+  (import "env" "longname3905" (func $internal3905))
+  (import "env" "longname3906" (func $internal3906))
+  (import "env" "longname3907" (func $internal3907))
+  (import "env" "longname3908" (func $internal3908))
+  (import "env" "longname3909" (func $internal3909))
+  (import "env" "longname3910" (func $internal3910))
+  (import "env" "longname3911" (func $internal3911))
+  (import "env" "longname3912" (func $internal3912))
+  (import "env" "longname3913" (func $internal3913))
+  (import "env" "longname3914" (func $internal3914))
+  (import "env" "longname3915" (func $internal3915))
+  (import "env" "longname3916" (func $internal3916))
+  (import "env" "longname3917" (func $internal3917))
+  (import "env" "longname3918" (func $internal3918))
+  (import "env" "longname3919" (func $internal3919))
+  (import "env" "longname3920" (func $internal3920))
+  (import "env" "longname3921" (func $internal3921))
+  (import "env" "longname3922" (func $internal3922))
+  (import "env" "longname3923" (func $internal3923))
+  (import "env" "longname3924" (func $internal3924))
+  (import "env" "longname3925" (func $internal3925))
+  (import "env" "longname3926" (func $internal3926))
+  (import "env" "longname3927" (func $internal3927))
+  (import "env" "longname3928" (func $internal3928))
+  (import "env" "longname3929" (func $internal3929))
+  (import "env" "longname3930" (func $internal3930))
+  (import "env" "longname3931" (func $internal3931))
+  (import "env" "longname3932" (func $internal3932))
+  (import "env" "longname3933" (func $internal3933))
+  (import "env" "longname3934" (func $internal3934))
+  (import "env" "longname3935" (func $internal3935))
+  (import "env" "longname3936" (func $internal3936))
+  (import "env" "longname3937" (func $internal3937))
+  (import "env" "longname3938" (func $internal3938))
+  (import "env" "longname3939" (func $internal3939))
+  (import "env" "longname3940" (func $internal3940))
+  (import "env" "longname3941" (func $internal3941))
+  (import "env" "longname3942" (func $internal3942))
+  (import "env" "longname3943" (func $internal3943))
+  (import "env" "longname3944" (func $internal3944))
+  (import "env" "longname3945" (func $internal3945))
+  (import "env" "longname3946" (func $internal3946))
+  (import "env" "longname3947" (func $internal3947))
+  (import "env" "longname3948" (func $internal3948))
+  (import "env" "longname3949" (func $internal3949))
+  (import "env" "longname3950" (func $internal3950))
+  (import "env" "longname3951" (func $internal3951))
+  (import "env" "longname3952" (func $internal3952))
+  (import "env" "longname3953" (func $internal3953))
+  (import "env" "longname3954" (func $internal3954))
+  (import "env" "longname3955" (func $internal3955))
+  (import "env" "longname3956" (func $internal3956))
+  (import "env" "longname3957" (func $internal3957))
+  (import "env" "longname3958" (func $internal3958))
+  (import "env" "longname3959" (func $internal3959))
+  (import "env" "longname3960" (func $internal3960))
+  (import "env" "longname3961" (func $internal3961))
+  (import "env" "longname3962" (func $internal3962))
+  (import "env" "longname3963" (func $internal3963))
+  (import "env" "longname3964" (func $internal3964))
+  (import "env" "longname3965" (func $internal3965))
+  (import "env" "longname3966" (func $internal3966))
+  (import "env" "longname3967" (func $internal3967))
+  (import "env" "longname3968" (func $internal3968))
+  (import "env" "longname3969" (func $internal3969))
+  (import "env" "longname3970" (func $internal3970))
+  (import "env" "longname3971" (func $internal3971))
+  (import "env" "longname3972" (func $internal3972))
+  (import "env" "longname3973" (func $internal3973))
+  (import "env" "longname3974" (func $internal3974))
+  (import "env" "longname3975" (func $internal3975))
+  (import "env" "longname3976" (func $internal3976))
+  (import "env" "longname3977" (func $internal3977))
+  (import "env" "longname3978" (func $internal3978))
+  (import "env" "longname3979" (func $internal3979))
+  (import "env" "longname3980" (func $internal3980))
+  (import "env" "longname3981" (func $internal3981))
+  (import "env" "longname3982" (func $internal3982))
+  (import "env" "longname3983" (func $internal3983))
+  (import "env" "longname3984" (func $internal3984))
+  (import "env" "longname3985" (func $internal3985))
+  (import "env" "longname3986" (func $internal3986))
+  (import "env" "longname3987" (func $internal3987))
+  (import "env" "longname3988" (func $internal3988))
+  (import "env" "longname3989" (func $internal3989))
+  (import "env" "longname3990" (func $internal3990))
+  (import "env" "longname3991" (func $internal3991))
+  (import "env" "longname3992" (func $internal3992))
+  (import "env" "longname3993" (func $internal3993))
+  (import "env" "longname3994" (func $internal3994))
+  (import "env" "longname3995" (func $internal3995))
+  (import "env" "longname3996" (func $internal3996))
+  (import "env" "longname3997" (func $internal3997))
+  (import "env" "longname3998" (func $internal3998))
+  (import "env" "longname3999" (func $internal3999))
+  (import "env" "longname4000" (func $internal4000))
+  (import "env" "longname4001" (func $internal4001))
+  (import "env" "longname4002" (func $internal4002))
+  (import "env" "longname4003" (func $internal4003))
+  (import "env" "longname4004" (func $internal4004))
+  (import "env" "longname4005" (func $internal4005))
+  (import "env" "longname4006" (func $internal4006))
+  (import "env" "longname4007" (func $internal4007))
+  (import "env" "longname4008" (func $internal4008))
+  (import "env" "longname4009" (func $internal4009))
+  (import "env" "longname4010" (func $internal4010))
+  (import "env" "longname4011" (func $internal4011))
+  (import "env" "longname4012" (func $internal4012))
+  (import "env" "longname4013" (func $internal4013))
+  (import "env" "longname4014" (func $internal4014))
+  (import "env" "longname4015" (func $internal4015))
+  (import "env" "longname4016" (func $internal4016))
+  (import "env" "longname4017" (func $internal4017))
+  (import "env" "longname4018" (func $internal4018))
+  (import "env" "longname4019" (func $internal4019))
+  (import "env" "longname4020" (func $internal4020))
+  (import "env" "longname4021" (func $internal4021))
+  (import "env" "longname4022" (func $internal4022))
+  (import "env" "longname4023" (func $internal4023))
+  (import "env" "longname4024" (func $internal4024))
+  (import "env" "longname4025" (func $internal4025))
+  (import "env" "longname4026" (func $internal4026))
+  (import "env" "longname4027" (func $internal4027))
+  (import "env" "longname4028" (func $internal4028))
+  (import "env" "longname4029" (func $internal4029))
+  (import "env" "longname4030" (func $internal4030))
+  (import "env" "longname4031" (func $internal4031))
+  (import "env" "longname4032" (func $internal4032))
+  (import "env" "longname4033" (func $internal4033))
+  (import "env" "longname4034" (func $internal4034))
+  (import "env" "longname4035" (func $internal4035))
+  (import "env" "longname4036" (func $internal4036))
+  (import "env" "longname4037" (func $internal4037))
+  (import "env" "longname4038" (func $internal4038))
+  (import "env" "longname4039" (func $internal4039))
+  (import "env" "longname4040" (func $internal4040))
+  (import "env" "longname4041" (func $internal4041))
+  (import "env" "longname4042" (func $internal4042))
+  (import "env" "longname4043" (func $internal4043))
+  (import "env" "longname4044" (func $internal4044))
+  (import "env" "longname4045" (func $internal4045))
+  (import "env" "longname4046" (func $internal4046))
+  (import "env" "longname4047" (func $internal4047))
+  (import "env" "longname4048" (func $internal4048))
+  (import "env" "longname4049" (func $internal4049))
+  (import "env" "longname4050" (func $internal4050))
+  (import "env" "longname4051" (func $internal4051))
+  (import "env" "longname4052" (func $internal4052))
+  (import "env" "longname4053" (func $internal4053))
+  (import "env" "longname4054" (func $internal4054))
+  (import "env" "longname4055" (func $internal4055))
+  (import "env" "longname4056" (func $internal4056))
+  (import "env" "longname4057" (func $internal4057))
+  (import "env" "longname4058" (func $internal4058))
+  (import "env" "longname4059" (func $internal4059))
+  (import "env" "longname4060" (func $internal4060))
+  (import "env" "longname4061" (func $internal4061))
+  (import "env" "longname4062" (func $internal4062))
+  (import "env" "longname4063" (func $internal4063))
+  (import "env" "longname4064" (func $internal4064))
+  (import "env" "longname4065" (func $internal4065))
+  (import "env" "longname4066" (func $internal4066))
+  (import "env" "longname4067" (func $internal4067))
+  (import "env" "longname4068" (func $internal4068))
+  (import "env" "longname4069" (func $internal4069))
+  (import "env" "longname4070" (func $internal4070))
+  (import "env" "longname4071" (func $internal4071))
+  (import "env" "longname4072" (func $internal4072))
+  (import "env" "longname4073" (func $internal4073))
+  (import "env" "longname4074" (func $internal4074))
+  (import "env" "longname4075" (func $internal4075))
+  (import "env" "longname4076" (func $internal4076))
+  (import "env" "longname4077" (func $internal4077))
+  (import "env" "longname4078" (func $internal4078))
+  (import "env" "longname4079" (func $internal4079))
+  (import "env" "longname4080" (func $internal4080))
+  (import "env" "longname4081" (func $internal4081))
+  (import "env" "longname4082" (func $internal4082))
+  (import "env" "longname4083" (func $internal4083))
+  (import "env" "longname4084" (func $internal4084))
+  (import "env" "longname4085" (func $internal4085))
+  (import "env" "longname4086" (func $internal4086))
+  (import "env" "longname4087" (func $internal4087))
+  (import "env" "longname4088" (func $internal4088))
+  (import "env" "longname4089" (func $internal4089))
+  (import "env" "longname4090" (func $internal4090))
+  (import "env" "longname4091" (func $internal4091))
+  (import "env" "longname4092" (func $internal4092))
+  (import "env" "longname4093" (func $internal4093))
+  (import "env" "longname4094" (func $internal4094))
+  (import "env" "longname4095" (func $internal4095))
+  (import "env" "longname4096" (func $internal4096))
+  (import "env" "longname4097" (func $internal4097))
+  (import "env" "longname4098" (func $internal4098))
+  (import "env" "longname4099" (func $internal4099))
+  (import "env" "longname4100" (func $internal4100))
+  (import "env" "longname4101" (func $internal4101))
+  (import "env" "longname4102" (func $internal4102))
+  (import "env" "longname4103" (func $internal4103))
+  (import "env" "longname4104" (func $internal4104))
+  (import "env" "longname4105" (func $internal4105))
+  (import "env" "longname4106" (func $internal4106))
+  (import "env" "longname4107" (func $internal4107))
+  (import "env" "longname4108" (func $internal4108))
+  (import "env" "longname4109" (func $internal4109))
+  (import "env" "longname4110" (func $internal4110))
+  (import "env" "longname4111" (func $internal4111))
+  (import "env" "longname4112" (func $internal4112))
+  (import "env" "longname4113" (func $internal4113))
+  (import "env" "longname4114" (func $internal4114))
+  (import "env" "longname4115" (func $internal4115))
+  (import "env" "longname4116" (func $internal4116))
+  (import "env" "longname4117" (func $internal4117))
+  (import "env" "longname4118" (func $internal4118))
+  (import "env" "longname4119" (func $internal4119))
+  (import "env" "longname4120" (func $internal4120))
+  (import "env" "longname4121" (func $internal4121))
+  (import "env" "longname4122" (func $internal4122))
+  (import "env" "longname4123" (func $internal4123))
+  (import "env" "longname4124" (func $internal4124))
+  (import "env" "longname4125" (func $internal4125))
+  (import "env" "longname4126" (func $internal4126))
+  (import "env" "longname4127" (func $internal4127))
+  (import "env" "longname4128" (func $internal4128))
+  (import "env" "longname4129" (func $internal4129))
+  (import "env" "longname4130" (func $internal4130))
+  (import "env" "longname4131" (func $internal4131))
+  (import "env" "longname4132" (func $internal4132))
+  (import "env" "longname4133" (func $internal4133))
+  (import "env" "longname4134" (func $internal4134))
+  (import "env" "longname4135" (func $internal4135))
+  (import "env" "longname4136" (func $internal4136))
+  (import "env" "longname4137" (func $internal4137))
+  (import "env" "longname4138" (func $internal4138))
+  (import "env" "longname4139" (func $internal4139))
+  (import "env" "longname4140" (func $internal4140))
+  (import "env" "longname4141" (func $internal4141))
+  (import "env" "longname4142" (func $internal4142))
+  (import "env" "longname4143" (func $internal4143))
+  (import "env" "longname4144" (func $internal4144))
+  (import "env" "longname4145" (func $internal4145))
+  (import "env" "longname4146" (func $internal4146))
+  (import "env" "longname4147" (func $internal4147))
+  (import "env" "longname4148" (func $internal4148))
+  (import "env" "longname4149" (func $internal4149))
+  (import "env" "longname4150" (func $internal4150))
+  (import "env" "longname4151" (func $internal4151))
+  (import "env" "longname4152" (func $internal4152))
+  (import "env" "longname4153" (func $internal4153))
+  (import "env" "longname4154" (func $internal4154))
+  (import "env" "longname4155" (func $internal4155))
+  (import "env" "longname4156" (func $internal4156))
+  (import "env" "longname4157" (func $internal4157))
+  (import "env" "longname4158" (func $internal4158))
+  (import "env" "longname4159" (func $internal4159))
+  (import "env" "longname4160" (func $internal4160))
+  (import "env" "longname4161" (func $internal4161))
+  (import "env" "longname4162" (func $internal4162))
+  (import "env" "longname4163" (func $internal4163))
+  (import "env" "longname4164" (func $internal4164))
+  (import "env" "longname4165" (func $internal4165))
+  (import "env" "longname4166" (func $internal4166))
+  (import "env" "longname4167" (func $internal4167))
+  (import "env" "longname4168" (func $internal4168))
+  (import "env" "longname4169" (func $internal4169))
+  (import "env" "longname4170" (func $internal4170))
+  (import "env" "longname4171" (func $internal4171))
+  (import "env" "longname4172" (func $internal4172))
+  (import "env" "longname4173" (func $internal4173))
+  (import "env" "longname4174" (func $internal4174))
+  (import "env" "longname4175" (func $internal4175))
+  (import "env" "longname4176" (func $internal4176))
+  (import "env" "longname4177" (func $internal4177))
+  (import "env" "longname4178" (func $internal4178))
+  (import "env" "longname4179" (func $internal4179))
+  (import "env" "longname4180" (func $internal4180))
+  (import "env" "longname4181" (func $internal4181))
+  (import "env" "longname4182" (func $internal4182))
+  (import "env" "longname4183" (func $internal4183))
+  (import "env" "longname4184" (func $internal4184))
+  (import "env" "longname4185" (func $internal4185))
+  (import "env" "longname4186" (func $internal4186))
+  (import "env" "longname4187" (func $internal4187))
+  (import "env" "longname4188" (func $internal4188))
+  (import "env" "longname4189" (func $internal4189))
+  (import "env" "longname4190" (func $internal4190))
+  (import "env" "longname4191" (func $internal4191))
+  (import "env" "longname4192" (func $internal4192))
+  (import "env" "longname4193" (func $internal4193))
+  (import "env" "longname4194" (func $internal4194))
+  (import "env" "longname4195" (func $internal4195))
+  (import "env" "longname4196" (func $internal4196))
+  (import "env" "longname4197" (func $internal4197))
+  (import "env" "longname4198" (func $internal4198))
+  (import "env" "longname4199" (func $internal4199))
+  (import "env" "longname4200" (func $internal4200))
+  (import "env" "longname4201" (func $internal4201))
+  (import "env" "longname4202" (func $internal4202))
+  (import "env" "longname4203" (func $internal4203))
+  (import "env" "longname4204" (func $internal4204))
+  (import "env" "longname4205" (func $internal4205))
+  (import "env" "longname4206" (func $internal4206))
+  (import "env" "longname4207" (func $internal4207))
+  (import "env" "longname4208" (func $internal4208))
+  (import "env" "longname4209" (func $internal4209))
+  (import "env" "longname4210" (func $internal4210))
+  (import "env" "longname4211" (func $internal4211))
+  (import "env" "longname4212" (func $internal4212))
+  (import "env" "longname4213" (func $internal4213))
+  (import "env" "longname4214" (func $internal4214))
+  (import "env" "longname4215" (func $internal4215))
+  (import "env" "longname4216" (func $internal4216))
+  (import "env" "longname4217" (func $internal4217))
+  (import "env" "longname4218" (func $internal4218))
+  (import "env" "longname4219" (func $internal4219))
+  (import "env" "longname4220" (func $internal4220))
+  (import "env" "longname4221" (func $internal4221))
+  (import "env" "longname4222" (func $internal4222))
+  (import "env" "longname4223" (func $internal4223))
+  (import "env" "longname4224" (func $internal4224))
+  (import "env" "longname4225" (func $internal4225))
+  (import "env" "longname4226" (func $internal4226))
+  (import "env" "longname4227" (func $internal4227))
+  (import "env" "longname4228" (func $internal4228))
+  (import "env" "longname4229" (func $internal4229))
+  (import "env" "longname4230" (func $internal4230))
+  (import "env" "longname4231" (func $internal4231))
+  (import "env" "longname4232" (func $internal4232))
+  (import "env" "longname4233" (func $internal4233))
+  (import "env" "longname4234" (func $internal4234))
+  (import "env" "longname4235" (func $internal4235))
+  (import "env" "longname4236" (func $internal4236))
+  (import "env" "longname4237" (func $internal4237))
+  (import "env" "longname4238" (func $internal4238))
+  (import "env" "longname4239" (func $internal4239))
+  (import "env" "longname4240" (func $internal4240))
+  (import "env" "longname4241" (func $internal4241))
+  (import "env" "longname4242" (func $internal4242))
+  (import "env" "longname4243" (func $internal4243))
+  (import "env" "longname4244" (func $internal4244))
+  (import "env" "longname4245" (func $internal4245))
+  (import "env" "longname4246" (func $internal4246))
+  (import "env" "longname4247" (func $internal4247))
+  (import "env" "longname4248" (func $internal4248))
+  (import "env" "longname4249" (func $internal4249))
+  (import "env" "longname4250" (func $internal4250))
+  (import "env" "longname4251" (func $internal4251))
+  (import "env" "longname4252" (func $internal4252))
+  (import "env" "longname4253" (func $internal4253))
+  (import "env" "longname4254" (func $internal4254))
+  (import "env" "longname4255" (func $internal4255))
+  (import "env" "longname4256" (func $internal4256))
+  (import "env" "longname4257" (func $internal4257))
+  (import "env" "longname4258" (func $internal4258))
+  (import "env" "longname4259" (func $internal4259))
+  (import "env" "longname4260" (func $internal4260))
+  (import "env" "longname4261" (func $internal4261))
+  (import "env" "longname4262" (func $internal4262))
+  (import "env" "longname4263" (func $internal4263))
+  (import "env" "longname4264" (func $internal4264))
+  (import "env" "longname4265" (func $internal4265))
+  (import "env" "longname4266" (func $internal4266))
+  (import "env" "longname4267" (func $internal4267))
+  (import "env" "longname4268" (func $internal4268))
+  (import "env" "longname4269" (func $internal4269))
+  (import "env" "longname4270" (func $internal4270))
+  (import "env" "longname4271" (func $internal4271))
+  (import "env" "longname4272" (func $internal4272))
+  (import "env" "longname4273" (func $internal4273))
+  (import "env" "longname4274" (func $internal4274))
+  (import "env" "longname4275" (func $internal4275))
+  (import "env" "longname4276" (func $internal4276))
+  (import "env" "longname4277" (func $internal4277))
+  (import "env" "longname4278" (func $internal4278))
+  (import "env" "longname4279" (func $internal4279))
+  (import "env" "longname4280" (func $internal4280))
+  (import "env" "longname4281" (func $internal4281))
+  (import "env" "longname4282" (func $internal4282))
+  (import "env" "longname4283" (func $internal4283))
+  (import "env" "longname4284" (func $internal4284))
+  (import "env" "longname4285" (func $internal4285))
+  (import "env" "longname4286" (func $internal4286))
+  (import "env" "longname4287" (func $internal4287))
+  (import "env" "longname4288" (func $internal4288))
+  (import "env" "longname4289" (func $internal4289))
+  (import "env" "longname4290" (func $internal4290))
+  (import "env" "longname4291" (func $internal4291))
+  (import "env" "longname4292" (func $internal4292))
+  (import "env" "longname4293" (func $internal4293))
+  (import "env" "longname4294" (func $internal4294))
+  (import "env" "longname4295" (func $internal4295))
+  (import "env" "longname4296" (func $internal4296))
+  (import "env" "longname4297" (func $internal4297))
+  (import "env" "longname4298" (func $internal4298))
+  (import "env" "longname4299" (func $internal4299))
+  (import "env" "longname4300" (func $internal4300))
+  (import "env" "longname4301" (func $internal4301))
+  (import "env" "longname4302" (func $internal4302))
+  (import "env" "longname4303" (func $internal4303))
+  (import "env" "longname4304" (func $internal4304))
+  (import "env" "longname4305" (func $internal4305))
+  (import "env" "longname4306" (func $internal4306))
+  (import "env" "longname4307" (func $internal4307))
+  (import "env" "longname4308" (func $internal4308))
+  (import "env" "longname4309" (func $internal4309))
+  (import "env" "longname4310" (func $internal4310))
+  (import "env" "longname4311" (func $internal4311))
+  (import "env" "longname4312" (func $internal4312))
+  (import "env" "longname4313" (func $internal4313))
+  (import "env" "longname4314" (func $internal4314))
+  (import "env" "longname4315" (func $internal4315))
+  (import "env" "longname4316" (func $internal4316))
+  (import "env" "longname4317" (func $internal4317))
+  (import "env" "longname4318" (func $internal4318))
+  (import "env" "longname4319" (func $internal4319))
+  (import "env" "longname4320" (func $internal4320))
+  (import "env" "longname4321" (func $internal4321))
+  (import "env" "longname4322" (func $internal4322))
+  (import "env" "longname4323" (func $internal4323))
+  (import "env" "longname4324" (func $internal4324))
+  (import "env" "longname4325" (func $internal4325))
+  (import "env" "longname4326" (func $internal4326))
+  (import "env" "longname4327" (func $internal4327))
+  (import "env" "longname4328" (func $internal4328))
+  (import "env" "longname4329" (func $internal4329))
+  (import "env" "longname4330" (func $internal4330))
+  (import "env" "longname4331" (func $internal4331))
+  (import "env" "longname4332" (func $internal4332))
+  (import "env" "longname4333" (func $internal4333))
+  (import "env" "longname4334" (func $internal4334))
+  (import "env" "longname4335" (func $internal4335))
+  (import "env" "longname4336" (func $internal4336))
+  (import "env" "longname4337" (func $internal4337))
+  (import "env" "longname4338" (func $internal4338))
+  (import "env" "longname4339" (func $internal4339))
+  (import "env" "longname4340" (func $internal4340))
+  (import "env" "longname4341" (func $internal4341))
+  (import "env" "longname4342" (func $internal4342))
+  (import "env" "longname4343" (func $internal4343))
+  (import "env" "longname4344" (func $internal4344))
+  (import "env" "longname4345" (func $internal4345))
+  (import "env" "longname4346" (func $internal4346))
+  (import "env" "longname4347" (func $internal4347))
+  (import "env" "longname4348" (func $internal4348))
+  (import "env" "longname4349" (func $internal4349))
+  (import "env" "longname4350" (func $internal4350))
+  (import "env" "longname4351" (func $internal4351))
+  (import "env" "longname4352" (func $internal4352))
+  (import "env" "longname4353" (func $internal4353))
+  (import "env" "longname4354" (func $internal4354))
+  (import "env" "longname4355" (func $internal4355))
+  (import "env" "longname4356" (func $internal4356))
+  (import "env" "longname4357" (func $internal4357))
+  (import "env" "longname4358" (func $internal4358))
+  (import "env" "longname4359" (func $internal4359))
+  (import "env" "longname4360" (func $internal4360))
+  (import "env" "longname4361" (func $internal4361))
+  (import "env" "longname4362" (func $internal4362))
+  (import "env" "longname4363" (func $internal4363))
+  (import "env" "longname4364" (func $internal4364))
+  (import "env" "longname4365" (func $internal4365))
+  (import "env" "longname4366" (func $internal4366))
+  (import "env" "longname4367" (func $internal4367))
+  (import "env" "longname4368" (func $internal4368))
+  (import "env" "longname4369" (func $internal4369))
+  (import "env" "longname4370" (func $internal4370))
+  (import "env" "longname4371" (func $internal4371))
+  (import "env" "longname4372" (func $internal4372))
+  (import "env" "longname4373" (func $internal4373))
+  (import "env" "longname4374" (func $internal4374))
+  (import "env" "longname4375" (func $internal4375))
+  (import "env" "longname4376" (func $internal4376))
+  (import "env" "longname4377" (func $internal4377))
+  (import "env" "longname4378" (func $internal4378))
+  (import "env" "longname4379" (func $internal4379))
+  (import "env" "longname4380" (func $internal4380))
+  (import "env" "longname4381" (func $internal4381))
+  (import "env" "longname4382" (func $internal4382))
+  (import "env" "longname4383" (func $internal4383))
+  (import "env" "longname4384" (func $internal4384))
+  (import "env" "longname4385" (func $internal4385))
+  (import "env" "longname4386" (func $internal4386))
+  (import "env" "longname4387" (func $internal4387))
+  (import "env" "longname4388" (func $internal4388))
+  (import "env" "longname4389" (func $internal4389))
+  (import "env" "longname4390" (func $internal4390))
+  (import "env" "longname4391" (func $internal4391))
+  (import "env" "longname4392" (func $internal4392))
+  (import "env" "longname4393" (func $internal4393))
+  (import "env" "longname4394" (func $internal4394))
+  (import "env" "longname4395" (func $internal4395))
+  (import "env" "longname4396" (func $internal4396))
+  (import "env" "longname4397" (func $internal4397))
+  (import "env" "longname4398" (func $internal4398))
+  (import "env" "longname4399" (func $internal4399))
+  (import "env" "longname4400" (func $internal4400))
+  (import "env" "longname4401" (func $internal4401))
+  (import "env" "longname4402" (func $internal4402))
+  (import "env" "longname4403" (func $internal4403))
+  (import "env" "longname4404" (func $internal4404))
+  (import "env" "longname4405" (func $internal4405))
+  (import "env" "longname4406" (func $internal4406))
+  (import "env" "longname4407" (func $internal4407))
+  (import "env" "longname4408" (func $internal4408))
+  (import "env" "longname4409" (func $internal4409))
+  (import "env" "longname4410" (func $internal4410))
+  (import "env" "longname4411" (func $internal4411))
+  (import "env" "longname4412" (func $internal4412))
+  (import "env" "longname4413" (func $internal4413))
+  (import "env" "longname4414" (func $internal4414))
+  (import "env" "longname4415" (func $internal4415))
+  (import "env" "longname4416" (func $internal4416))
+  (import "env" "longname4417" (func $internal4417))
+  (import "env" "longname4418" (func $internal4418))
+  (import "env" "longname4419" (func $internal4419))
+  (import "env" "longname4420" (func $internal4420))
+  (import "env" "longname4421" (func $internal4421))
+  (import "env" "longname4422" (func $internal4422))
+  (import "env" "longname4423" (func $internal4423))
+  (import "env" "longname4424" (func $internal4424))
+  (import "env" "longname4425" (func $internal4425))
+  (import "env" "longname4426" (func $internal4426))
+  (import "env" "longname4427" (func $internal4427))
+  (import "env" "longname4428" (func $internal4428))
+  (import "env" "longname4429" (func $internal4429))
+  (import "env" "longname4430" (func $internal4430))
+  (import "env" "longname4431" (func $internal4431))
+  (import "env" "longname4432" (func $internal4432))
+  (import "env" "longname4433" (func $internal4433))
+  (import "env" "longname4434" (func $internal4434))
+  (import "env" "longname4435" (func $internal4435))
+  (import "env" "longname4436" (func $internal4436))
+  (import "env" "longname4437" (func $internal4437))
+  (import "env" "longname4438" (func $internal4438))
+  (import "env" "longname4439" (func $internal4439))
+  (import "env" "longname4440" (func $internal4440))
+  (import "env" "longname4441" (func $internal4441))
+  (import "env" "longname4442" (func $internal4442))
+  (import "env" "longname4443" (func $internal4443))
+  (import "env" "longname4444" (func $internal4444))
+  (import "env" "longname4445" (func $internal4445))
+  (import "env" "longname4446" (func $internal4446))
+  (import "env" "longname4447" (func $internal4447))
+  (import "env" "longname4448" (func $internal4448))
+  (import "env" "longname4449" (func $internal4449))
+  (import "env" "longname4450" (func $internal4450))
+  (import "env" "longname4451" (func $internal4451))
+  (import "env" "longname4452" (func $internal4452))
+  (import "env" "longname4453" (func $internal4453))
+  (import "env" "longname4454" (func $internal4454))
+  (import "env" "longname4455" (func $internal4455))
+  (import "env" "longname4456" (func $internal4456))
+  (import "env" "longname4457" (func $internal4457))
+  (import "env" "longname4458" (func $internal4458))
+  (import "env" "longname4459" (func $internal4459))
+  (import "env" "longname4460" (func $internal4460))
+  (import "env" "longname4461" (func $internal4461))
+  (import "env" "longname4462" (func $internal4462))
+  (import "env" "longname4463" (func $internal4463))
+  (import "env" "longname4464" (func $internal4464))
+  (import "env" "longname4465" (func $internal4465))
+  (import "env" "longname4466" (func $internal4466))
+  (import "env" "longname4467" (func $internal4467))
+  (import "env" "longname4468" (func $internal4468))
+  (import "env" "longname4469" (func $internal4469))
+  (import "env" "longname4470" (func $internal4470))
+  (import "env" "longname4471" (func $internal4471))
+  (import "env" "longname4472" (func $internal4472))
+  (import "env" "longname4473" (func $internal4473))
+  (import "env" "longname4474" (func $internal4474))
+  (import "env" "longname4475" (func $internal4475))
+  (import "env" "longname4476" (func $internal4476))
+  (import "env" "longname4477" (func $internal4477))
+  (import "env" "longname4478" (func $internal4478))
+  (import "env" "longname4479" (func $internal4479))
+  (import "env" "longname4480" (func $internal4480))
+  (import "env" "longname4481" (func $internal4481))
+  (import "env" "longname4482" (func $internal4482))
+  (import "env" "longname4483" (func $internal4483))
+  (import "env" "longname4484" (func $internal4484))
+  (import "env" "longname4485" (func $internal4485))
+  (import "env" "longname4486" (func $internal4486))
+  (import "env" "longname4487" (func $internal4487))
+  (import "env" "longname4488" (func $internal4488))
+  (import "env" "longname4489" (func $internal4489))
+  (import "env" "longname4490" (func $internal4490))
+  (import "env" "longname4491" (func $internal4491))
+  (import "env" "longname4492" (func $internal4492))
+  (import "env" "longname4493" (func $internal4493))
+  (import "env" "longname4494" (func $internal4494))
+  (import "env" "longname4495" (func $internal4495))
+  (import "env" "longname4496" (func $internal4496))
+  (import "env" "longname4497" (func $internal4497))
+  (import "env" "longname4498" (func $internal4498))
+  (import "env" "longname4499" (func $internal4499))
+  (import "env" "longname4500" (func $internal4500))
+  (import "env" "longname4501" (func $internal4501))
+  (import "env" "longname4502" (func $internal4502))
+  (import "env" "longname4503" (func $internal4503))
+  (import "env" "longname4504" (func $internal4504))
+  (import "env" "longname4505" (func $internal4505))
+  (import "env" "longname4506" (func $internal4506))
+  (import "env" "longname4507" (func $internal4507))
+  (import "env" "longname4508" (func $internal4508))
+  (import "env" "longname4509" (func $internal4509))
+  (import "env" "longname4510" (func $internal4510))
+  (import "env" "longname4511" (func $internal4511))
+  (import "env" "longname4512" (func $internal4512))
+  (import "env" "longname4513" (func $internal4513))
+  (import "env" "longname4514" (func $internal4514))
+  (import "env" "longname4515" (func $internal4515))
+  (import "env" "longname4516" (func $internal4516))
+  (import "env" "longname4517" (func $internal4517))
+  (import "env" "longname4518" (func $internal4518))
+  (import "env" "longname4519" (func $internal4519))
+  (import "env" "longname4520" (func $internal4520))
+  (import "env" "longname4521" (func $internal4521))
+  (import "env" "longname4522" (func $internal4522))
+  (import "env" "longname4523" (func $internal4523))
+  (import "env" "longname4524" (func $internal4524))
+  (import "env" "longname4525" (func $internal4525))
+  (import "env" "longname4526" (func $internal4526))
+  (import "env" "longname4527" (func $internal4527))
+  (import "env" "longname4528" (func $internal4528))
+  (import "env" "longname4529" (func $internal4529))
+  (import "env" "longname4530" (func $internal4530))
+  (import "env" "longname4531" (func $internal4531))
+  (import "env" "longname4532" (func $internal4532))
+  (import "env" "longname4533" (func $internal4533))
+  (import "env" "longname4534" (func $internal4534))
+  (import "env" "longname4535" (func $internal4535))
+  (import "env" "longname4536" (func $internal4536))
+  (import "env" "longname4537" (func $internal4537))
+  (import "env" "longname4538" (func $internal4538))
+  (import "env" "longname4539" (func $internal4539))
+  (import "env" "longname4540" (func $internal4540))
+  (import "env" "longname4541" (func $internal4541))
+  (import "env" "longname4542" (func $internal4542))
+  (import "env" "longname4543" (func $internal4543))
+  (import "env" "longname4544" (func $internal4544))
+  (import "env" "longname4545" (func $internal4545))
+  (import "env" "longname4546" (func $internal4546))
+  (import "env" "longname4547" (func $internal4547))
+  (import "env" "longname4548" (func $internal4548))
+  (import "env" "longname4549" (func $internal4549))
+  (import "env" "longname4550" (func $internal4550))
+  (import "env" "longname4551" (func $internal4551))
+  (import "env" "longname4552" (func $internal4552))
+  (import "env" "longname4553" (func $internal4553))
+  (import "env" "longname4554" (func $internal4554))
+  (import "env" "longname4555" (func $internal4555))
+  (import "env" "longname4556" (func $internal4556))
+  (import "env" "longname4557" (func $internal4557))
+  (import "env" "longname4558" (func $internal4558))
+  (import "env" "longname4559" (func $internal4559))
+  (import "env" "longname4560" (func $internal4560))
+  (import "env" "longname4561" (func $internal4561))
+  (import "env" "longname4562" (func $internal4562))
+  (import "env" "longname4563" (func $internal4563))
+  (import "env" "longname4564" (func $internal4564))
+  (import "env" "longname4565" (func $internal4565))
+  (import "env" "longname4566" (func $internal4566))
+  (import "env" "longname4567" (func $internal4567))
+  (import "env" "longname4568" (func $internal4568))
+  (import "env" "longname4569" (func $internal4569))
+  (import "env" "longname4570" (func $internal4570))
+  (import "env" "longname4571" (func $internal4571))
+  (import "env" "longname4572" (func $internal4572))
+  (import "env" "longname4573" (func $internal4573))
+  (import "env" "longname4574" (func $internal4574))
+  (import "env" "longname4575" (func $internal4575))
+  (import "env" "longname4576" (func $internal4576))
+  (import "env" "longname4577" (func $internal4577))
+  (import "env" "longname4578" (func $internal4578))
+  (import "env" "longname4579" (func $internal4579))
+  (import "env" "longname4580" (func $internal4580))
+  (import "env" "longname4581" (func $internal4581))
+  (import "env" "longname4582" (func $internal4582))
+  (import "env" "longname4583" (func $internal4583))
+  (import "env" "longname4584" (func $internal4584))
+  (import "env" "longname4585" (func $internal4585))
+  (import "env" "longname4586" (func $internal4586))
+  (import "env" "longname4587" (func $internal4587))
+  (import "env" "longname4588" (func $internal4588))
+  (import "env" "longname4589" (func $internal4589))
+  (import "env" "longname4590" (func $internal4590))
+  (import "env" "longname4591" (func $internal4591))
+  (import "env" "longname4592" (func $internal4592))
+  (import "env" "longname4593" (func $internal4593))
+  (import "env" "longname4594" (func $internal4594))
+  (import "env" "longname4595" (func $internal4595))
+  (import "env" "longname4596" (func $internal4596))
+  (import "env" "longname4597" (func $internal4597))
+  (import "env" "longname4598" (func $internal4598))
+  (import "env" "longname4599" (func $internal4599))
+  (import "env" "longname4600" (func $internal4600))
+  (import "env" "longname4601" (func $internal4601))
+  (import "env" "longname4602" (func $internal4602))
+  (import "env" "longname4603" (func $internal4603))
+  (import "env" "longname4604" (func $internal4604))
+  (import "env" "longname4605" (func $internal4605))
+  (import "env" "longname4606" (func $internal4606))
+  (import "env" "longname4607" (func $internal4607))
+  (import "env" "longname4608" (func $internal4608))
+  (import "env" "longname4609" (func $internal4609))
+  (import "env" "longname4610" (func $internal4610))
+  (import "env" "longname4611" (func $internal4611))
+  (import "env" "longname4612" (func $internal4612))
+  (import "env" "longname4613" (func $internal4613))
+  (import "env" "longname4614" (func $internal4614))
+  (import "env" "longname4615" (func $internal4615))
+  (import "env" "longname4616" (func $internal4616))
+  (import "env" "longname4617" (func $internal4617))
+  (import "env" "longname4618" (func $internal4618))
+  (import "env" "longname4619" (func $internal4619))
+  (import "env" "longname4620" (func $internal4620))
+  (import "env" "longname4621" (func $internal4621))
+  (import "env" "longname4622" (func $internal4622))
+  (import "env" "longname4623" (func $internal4623))
+  (import "env" "longname4624" (func $internal4624))
+  (import "env" "longname4625" (func $internal4625))
+  (import "env" "longname4626" (func $internal4626))
+  (import "env" "longname4627" (func $internal4627))
+  (import "env" "longname4628" (func $internal4628))
+  (import "env" "longname4629" (func $internal4629))
+  (import "env" "longname4630" (func $internal4630))
+  (import "env" "longname4631" (func $internal4631))
+  (import "env" "longname4632" (func $internal4632))
+  (import "env" "longname4633" (func $internal4633))
+  (import "env" "longname4634" (func $internal4634))
+  (import "env" "longname4635" (func $internal4635))
+  (import "env" "longname4636" (func $internal4636))
+  (import "env" "longname4637" (func $internal4637))
+  (import "env" "longname4638" (func $internal4638))
+  (import "env" "longname4639" (func $internal4639))
+  (import "env" "longname4640" (func $internal4640))
+  (import "env" "longname4641" (func $internal4641))
+  (import "env" "longname4642" (func $internal4642))
+  (import "env" "longname4643" (func $internal4643))
+  (import "env" "longname4644" (func $internal4644))
+  (import "env" "longname4645" (func $internal4645))
+  (import "env" "longname4646" (func $internal4646))
+  (import "env" "longname4647" (func $internal4647))
+  (import "env" "longname4648" (func $internal4648))
+  (import "env" "longname4649" (func $internal4649))
+  (import "env" "longname4650" (func $internal4650))
+  (import "env" "longname4651" (func $internal4651))
+  (import "env" "longname4652" (func $internal4652))
+  (import "env" "longname4653" (func $internal4653))
+  (import "env" "longname4654" (func $internal4654))
+  (import "env" "longname4655" (func $internal4655))
+  (import "env" "longname4656" (func $internal4656))
+  (import "env" "longname4657" (func $internal4657))
+  (import "env" "longname4658" (func $internal4658))
+  (import "env" "longname4659" (func $internal4659))
+  (import "env" "longname4660" (func $internal4660))
+  (import "env" "longname4661" (func $internal4661))
+  (import "env" "longname4662" (func $internal4662))
+  (import "env" "longname4663" (func $internal4663))
+  (import "env" "longname4664" (func $internal4664))
+  (import "env" "longname4665" (func $internal4665))
+  (import "env" "longname4666" (func $internal4666))
+  (import "env" "longname4667" (func $internal4667))
+  (import "env" "longname4668" (func $internal4668))
+  (import "env" "longname4669" (func $internal4669))
+  (import "env" "longname4670" (func $internal4670))
+  (import "env" "longname4671" (func $internal4671))
+  (import "env" "longname4672" (func $internal4672))
+  (import "env" "longname4673" (func $internal4673))
+  (import "env" "longname4674" (func $internal4674))
+  (import "env" "longname4675" (func $internal4675))
+  (import "env" "longname4676" (func $internal4676))
+  (import "env" "longname4677" (func $internal4677))
+  (import "env" "longname4678" (func $internal4678))
+  (import "env" "longname4679" (func $internal4679))
+  (import "env" "longname4680" (func $internal4680))
+  (import "env" "longname4681" (func $internal4681))
+  (import "env" "longname4682" (func $internal4682))
+  (import "env" "longname4683" (func $internal4683))
+  (import "env" "longname4684" (func $internal4684))
+  (import "env" "longname4685" (func $internal4685))
+  (import "env" "longname4686" (func $internal4686))
+  (import "env" "longname4687" (func $internal4687))
+  (import "env" "longname4688" (func $internal4688))
+  (import "env" "longname4689" (func $internal4689))
+  (import "env" "longname4690" (func $internal4690))
+  (import "env" "longname4691" (func $internal4691))
+  (import "env" "longname4692" (func $internal4692))
+  (import "env" "longname4693" (func $internal4693))
+  (import "env" "longname4694" (func $internal4694))
+  (import "env" "longname4695" (func $internal4695))
+  (import "env" "longname4696" (func $internal4696))
+  (import "env" "longname4697" (func $internal4697))
+  (import "env" "longname4698" (func $internal4698))
+  (import "env" "longname4699" (func $internal4699))
+  (import "env" "longname4700" (func $internal4700))
+  (import "env" "longname4701" (func $internal4701))
+  (import "env" "longname4702" (func $internal4702))
+  (import "env" "longname4703" (func $internal4703))
+  (import "env" "longname4704" (func $internal4704))
+  (import "env" "longname4705" (func $internal4705))
+  (import "env" "longname4706" (func $internal4706))
+  (import "env" "longname4707" (func $internal4707))
+  (import "env" "longname4708" (func $internal4708))
+  (import "env" "longname4709" (func $internal4709))
+  (import "env" "longname4710" (func $internal4710))
+  (import "env" "longname4711" (func $internal4711))
+  (import "env" "longname4712" (func $internal4712))
+  (import "env" "longname4713" (func $internal4713))
+  (import "env" "longname4714" (func $internal4714))
+  (import "env" "longname4715" (func $internal4715))
+  (import "env" "longname4716" (func $internal4716))
+  (import "env" "longname4717" (func $internal4717))
+  (import "env" "longname4718" (func $internal4718))
+  (import "env" "longname4719" (func $internal4719))
+  (import "env" "longname4720" (func $internal4720))
+  (import "env" "longname4721" (func $internal4721))
+  (import "env" "longname4722" (func $internal4722))
+  (import "env" "longname4723" (func $internal4723))
+  (import "env" "longname4724" (func $internal4724))
+  (import "env" "longname4725" (func $internal4725))
+  (import "env" "longname4726" (func $internal4726))
+  (import "env" "longname4727" (func $internal4727))
+  (import "env" "longname4728" (func $internal4728))
+  (import "env" "longname4729" (func $internal4729))
+  (import "env" "longname4730" (func $internal4730))
+  (import "env" "longname4731" (func $internal4731))
+  (import "env" "longname4732" (func $internal4732))
+  (import "env" "longname4733" (func $internal4733))
+  (import "env" "longname4734" (func $internal4734))
+  (import "env" "longname4735" (func $internal4735))
+  (import "env" "longname4736" (func $internal4736))
+  (import "env" "longname4737" (func $internal4737))
+  (import "env" "longname4738" (func $internal4738))
+  (import "env" "longname4739" (func $internal4739))
+  (import "env" "longname4740" (func $internal4740))
+  (import "env" "longname4741" (func $internal4741))
+  (import "env" "longname4742" (func $internal4742))
+  (import "env" "longname4743" (func $internal4743))
+  (import "env" "longname4744" (func $internal4744))
+  (import "env" "longname4745" (func $internal4745))
+  (import "env" "longname4746" (func $internal4746))
+  (import "env" "longname4747" (func $internal4747))
+  (import "env" "longname4748" (func $internal4748))
+  (import "env" "longname4749" (func $internal4749))
+  (import "env" "longname4750" (func $internal4750))
+  (import "env" "longname4751" (func $internal4751))
+  (import "env" "longname4752" (func $internal4752))
+  (import "env" "longname4753" (func $internal4753))
+  (import "env" "longname4754" (func $internal4754))
+  (import "env" "longname4755" (func $internal4755))
+  (import "env" "longname4756" (func $internal4756))
+  (import "env" "longname4757" (func $internal4757))
+  (import "env" "longname4758" (func $internal4758))
+  (import "env" "longname4759" (func $internal4759))
+  (import "env" "longname4760" (func $internal4760))
+  (import "env" "longname4761" (func $internal4761))
+  (import "env" "longname4762" (func $internal4762))
+  (import "env" "longname4763" (func $internal4763))
+  (import "env" "longname4764" (func $internal4764))
+  (import "env" "longname4765" (func $internal4765))
+  (import "env" "longname4766" (func $internal4766))
+  (import "env" "longname4767" (func $internal4767))
+  (import "env" "longname4768" (func $internal4768))
+  (import "env" "longname4769" (func $internal4769))
+  (import "env" "longname4770" (func $internal4770))
+  (import "env" "longname4771" (func $internal4771))
+  (import "env" "longname4772" (func $internal4772))
+  (import "env" "longname4773" (func $internal4773))
+  (import "env" "longname4774" (func $internal4774))
+  (import "env" "longname4775" (func $internal4775))
+  (import "env" "longname4776" (func $internal4776))
+  (import "env" "longname4777" (func $internal4777))
+  (import "env" "longname4778" (func $internal4778))
+  (import "env" "longname4779" (func $internal4779))
+  (import "env" "longname4780" (func $internal4780))
+  (import "env" "longname4781" (func $internal4781))
+  (import "env" "longname4782" (func $internal4782))
+  (import "env" "longname4783" (func $internal4783))
+  (import "env" "longname4784" (func $internal4784))
+  (import "env" "longname4785" (func $internal4785))
+  (import "env" "longname4786" (func $internal4786))
+  (import "env" "longname4787" (func $internal4787))
+  (import "env" "longname4788" (func $internal4788))
+  (import "env" "longname4789" (func $internal4789))
+  (import "env" "longname4790" (func $internal4790))
+  (import "env" "longname4791" (func $internal4791))
+  (import "env" "longname4792" (func $internal4792))
+  (import "env" "longname4793" (func $internal4793))
+  (import "env" "longname4794" (func $internal4794))
+  (import "env" "longname4795" (func $internal4795))
+  (import "env" "longname4796" (func $internal4796))
+  (import "env" "longname4797" (func $internal4797))
+  (import "env" "longname4798" (func $internal4798))
+  (import "env" "longname4799" (func $internal4799))
+  (import "env" "longname4800" (func $internal4800))
+  (import "env" "longname4801" (func $internal4801))
+  (import "env" "longname4802" (func $internal4802))
+  (import "env" "longname4803" (func $internal4803))
+  (import "env" "longname4804" (func $internal4804))
+  (import "env" "longname4805" (func $internal4805))
+  (import "env" "longname4806" (func $internal4806))
+  (import "env" "longname4807" (func $internal4807))
+  (import "env" "longname4808" (func $internal4808))
+  (import "env" "longname4809" (func $internal4809))
+  (import "env" "longname4810" (func $internal4810))
+  (import "env" "longname4811" (func $internal4811))
+  (import "env" "longname4812" (func $internal4812))
+  (import "env" "longname4813" (func $internal4813))
+  (import "env" "longname4814" (func $internal4814))
+  (import "env" "longname4815" (func $internal4815))
+  (import "env" "longname4816" (func $internal4816))
+  (import "env" "longname4817" (func $internal4817))
+  (import "env" "longname4818" (func $internal4818))
+  (import "env" "longname4819" (func $internal4819))
+  (import "env" "longname4820" (func $internal4820))
+  (import "env" "longname4821" (func $internal4821))
+  (import "env" "longname4822" (func $internal4822))
+  (import "env" "longname4823" (func $internal4823))
+  (import "env" "longname4824" (func $internal4824))
+  (import "env" "longname4825" (func $internal4825))
+  (import "env" "longname4826" (func $internal4826))
+  (import "env" "longname4827" (func $internal4827))
+  (import "env" "longname4828" (func $internal4828))
+  (import "env" "longname4829" (func $internal4829))
+  (import "env" "longname4830" (func $internal4830))
+  (import "env" "longname4831" (func $internal4831))
+  (import "env" "longname4832" (func $internal4832))
+  (import "env" "longname4833" (func $internal4833))
+  (import "env" "longname4834" (func $internal4834))
+  (import "env" "longname4835" (func $internal4835))
+  (import "env" "longname4836" (func $internal4836))
+  (import "env" "longname4837" (func $internal4837))
+  (import "env" "longname4838" (func $internal4838))
+  (import "env" "longname4839" (func $internal4839))
+  (import "env" "longname4840" (func $internal4840))
+  (import "env" "longname4841" (func $internal4841))
+  (import "env" "longname4842" (func $internal4842))
+  (import "env" "longname4843" (func $internal4843))
+  (import "env" "longname4844" (func $internal4844))
+  (import "env" "longname4845" (func $internal4845))
+  (import "env" "longname4846" (func $internal4846))
+  (import "env" "longname4847" (func $internal4847))
+  (import "env" "longname4848" (func $internal4848))
+  (import "env" "longname4849" (func $internal4849))
+  (import "env" "longname4850" (func $internal4850))
+  (import "env" "longname4851" (func $internal4851))
+  (import "env" "longname4852" (func $internal4852))
+  (import "env" "longname4853" (func $internal4853))
+  (import "env" "longname4854" (func $internal4854))
+  (import "env" "longname4855" (func $internal4855))
+  (import "env" "longname4856" (func $internal4856))
+  (import "env" "longname4857" (func $internal4857))
+  (import "env" "longname4858" (func $internal4858))
+  (import "env" "longname4859" (func $internal4859))
+  (import "env" "longname4860" (func $internal4860))
+  (import "env" "longname4861" (func $internal4861))
+  (import "env" "longname4862" (func $internal4862))
+  (import "env" "longname4863" (func $internal4863))
+  (import "env" "longname4864" (func $internal4864))
+  (import "env" "longname4865" (func $internal4865))
+  (import "env" "longname4866" (func $internal4866))
+  (import "env" "longname4867" (func $internal4867))
+  (import "env" "longname4868" (func $internal4868))
+  (import "env" "longname4869" (func $internal4869))
+  (import "env" "longname4870" (func $internal4870))
+  (import "env" "longname4871" (func $internal4871))
+  (import "env" "longname4872" (func $internal4872))
+  (import "env" "longname4873" (func $internal4873))
+  (import "env" "longname4874" (func $internal4874))
+  (import "env" "longname4875" (func $internal4875))
+  (import "env" "longname4876" (func $internal4876))
+  (import "env" "longname4877" (func $internal4877))
+  (import "env" "longname4878" (func $internal4878))
+  (import "env" "longname4879" (func $internal4879))
+  (import "env" "longname4880" (func $internal4880))
+  (import "env" "longname4881" (func $internal4881))
+  (import "env" "longname4882" (func $internal4882))
+  (import "env" "longname4883" (func $internal4883))
+  (import "env" "longname4884" (func $internal4884))
+  (import "env" "longname4885" (func $internal4885))
+  (import "env" "longname4886" (func $internal4886))
+  (import "env" "longname4887" (func $internal4887))
+  (import "env" "longname4888" (func $internal4888))
+  (import "env" "longname4889" (func $internal4889))
+  (import "env" "longname4890" (func $internal4890))
+  (import "env" "longname4891" (func $internal4891))
+  (import "env" "longname4892" (func $internal4892))
+  (import "env" "longname4893" (func $internal4893))
+  (import "env" "longname4894" (func $internal4894))
+  (import "env" "longname4895" (func $internal4895))
+  (import "env" "longname4896" (func $internal4896))
+  (import "env" "longname4897" (func $internal4897))
+  (import "env" "longname4898" (func $internal4898))
+  (import "env" "longname4899" (func $internal4899))
+  (import "env" "longname4900" (func $internal4900))
+  (import "env" "longname4901" (func $internal4901))
+  (import "env" "longname4902" (func $internal4902))
+  (import "env" "longname4903" (func $internal4903))
+  (import "env" "longname4904" (func $internal4904))
+  (import "env" "longname4905" (func $internal4905))
+  (import "env" "longname4906" (func $internal4906))
+  (import "env" "longname4907" (func $internal4907))
+  (import "env" "longname4908" (func $internal4908))
+  (import "env" "longname4909" (func $internal4909))
+  (import "env" "longname4910" (func $internal4910))
+  (import "env" "longname4911" (func $internal4911))
+  (import "env" "longname4912" (func $internal4912))
+  (import "env" "longname4913" (func $internal4913))
+  (import "env" "longname4914" (func $internal4914))
+  (import "env" "longname4915" (func $internal4915))
+  (import "env" "longname4916" (func $internal4916))
+  (import "env" "longname4917" (func $internal4917))
+  (import "env" "longname4918" (func $internal4918))
+  (import "env" "longname4919" (func $internal4919))
+  (import "env" "longname4920" (func $internal4920))
+  (import "env" "longname4921" (func $internal4921))
+  (import "env" "longname4922" (func $internal4922))
+  (import "env" "longname4923" (func $internal4923))
+  (import "env" "longname4924" (func $internal4924))
+  (import "env" "longname4925" (func $internal4925))
+  (import "env" "longname4926" (func $internal4926))
+  (import "env" "longname4927" (func $internal4927))
+  (import "env" "longname4928" (func $internal4928))
+  (import "env" "longname4929" (func $internal4929))
+  (import "env" "longname4930" (func $internal4930))
+  (import "env" "longname4931" (func $internal4931))
+  (import "env" "longname4932" (func $internal4932))
+  (import "env" "longname4933" (func $internal4933))
+  (import "env" "longname4934" (func $internal4934))
+  (import "env" "longname4935" (func $internal4935))
+  (import "env" "longname4936" (func $internal4936))
+  (import "env" "longname4937" (func $internal4937))
+  (import "env" "longname4938" (func $internal4938))
+  (import "env" "longname4939" (func $internal4939))
+  (import "env" "longname4940" (func $internal4940))
+  (import "env" "longname4941" (func $internal4941))
+  (import "env" "longname4942" (func $internal4942))
+  (import "env" "longname4943" (func $internal4943))
+  (import "env" "longname4944" (func $internal4944))
+  (import "env" "longname4945" (func $internal4945))
+  (import "env" "longname4946" (func $internal4946))
+  (import "env" "longname4947" (func $internal4947))
+  (import "env" "longname4948" (func $internal4948))
+  (import "env" "longname4949" (func $internal4949))
+  (import "env" "longname4950" (func $internal4950))
+  (import "env" "longname4951" (func $internal4951))
+  (import "env" "longname4952" (func $internal4952))
+  (import "env" "longname4953" (func $internal4953))
+  (import "env" "longname4954" (func $internal4954))
+  (import "env" "longname4955" (func $internal4955))
+  (import "env" "longname4956" (func $internal4956))
+  (import "env" "longname4957" (func $internal4957))
+  (import "env" "longname4958" (func $internal4958))
+  (import "env" "longname4959" (func $internal4959))
+  (import "env" "longname4960" (func $internal4960))
+  (import "env" "longname4961" (func $internal4961))
+  (import "env" "longname4962" (func $internal4962))
+  (import "env" "longname4963" (func $internal4963))
+  (import "env" "longname4964" (func $internal4964))
+  (import "env" "longname4965" (func $internal4965))
+  (import "env" "longname4966" (func $internal4966))
+  (import "env" "longname4967" (func $internal4967))
+  (import "env" "longname4968" (func $internal4968))
+  (import "env" "longname4969" (func $internal4969))
+  (import "env" "longname4970" (func $internal4970))
+  (import "env" "longname4971" (func $internal4971))
+  (import "env" "longname4972" (func $internal4972))
+  (import "env" "longname4973" (func $internal4973))
+  (import "env" "longname4974" (func $internal4974))
+  (import "env" "longname4975" (func $internal4975))
+  (import "env" "longname4976" (func $internal4976))
+  (import "env" "longname4977" (func $internal4977))
+  (import "env" "longname4978" (func $internal4978))
+  (import "env" "longname4979" (func $internal4979))
+  (import "env" "longname4980" (func $internal4980))
+  (import "env" "longname4981" (func $internal4981))
+  (import "env" "longname4982" (func $internal4982))
+  (import "env" "longname4983" (func $internal4983))
+  (import "env" "longname4984" (func $internal4984))
+  (import "env" "longname4985" (func $internal4985))
+  (import "env" "longname4986" (func $internal4986))
+  (import "env" "longname4987" (func $internal4987))
+  (import "env" "longname4988" (func $internal4988))
+  (import "env" "longname4989" (func $internal4989))
+  (import "env" "longname4990" (func $internal4990))
+  (import "env" "longname4991" (func $internal4991))
+  (import "env" "longname4992" (func $internal4992))
+  (import "env" "longname4993" (func $internal4993))
+  (import "env" "longname4994" (func $internal4994))
+  (import "env" "longname4995" (func $internal4995))
+  (import "env" "longname4996" (func $internal4996))
+  (import "env" "longname4997" (func $internal4997))
+  (import "env" "longname4998" (func $internal4998))
+  (import "env" "longname4999" (func $internal4999))
+  (import "env" "__memory_base" (global i32))
+  (import "env" "__table_base" (global i32))
+  (import "other" "anything" (func $internalInfinity))
+  (import "env" "eventname1" (event $eventname1 (attr 0) (param i32)))
+  (import "wasi_unstable" "longname3" (func $internal3_wasi)) ;; overlapping base
+  (import "wasi_unstable" "longname3-only" (func $internal3_wasi_only))
+  (export "exp1" (func $foo1))
+  (export "exp2" (func $foo2))
+  (func $foo1)
+  (func $foo2)
+  (export "event1" (event $event1))
+  (event $event1 (attr 0) (param i32 i32))
+)
diff --git a/binaryen/test/passes/minify-imports_all-features.txt b/binaryen/test/passes/minify-imports_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/minify-imports_all-features.txt
@@ -0,0 +1,10022 @@
+longname51 => $
+longname2964 => $$
+longname3018 => $0
+longname3072 => $1
+longname3126 => $2
+longname3180 => $3
+longname3234 => $4
+longname3288 => $5
+longname3342 => $6
+longname3396 => $7
+longname3450 => $8
+longname3504 => $9
+longname1506 => $A
+longname4962 => $Aa
+longname1560 => $B
+longname1614 => $C
+longname1668 => $D
+longname1722 => $E
+longname1776 => $F
+longname1830 => $G
+longname1884 => $H
+longname1938 => $I
+longname1992 => $J
+longname2046 => $K
+longname2100 => $L
+longname2154 => $M
+longname2208 => $N
+longname2262 => $O
+longname2316 => $P
+longname2370 => $Q
+longname2424 => $R
+longname2478 => $S
+longname2532 => $T
+longname2586 => $U
+longname2640 => $V
+longname2694 => $W
+longname2748 => $X
+longname2802 => $Y
+longname2856 => $Z
+longname2910 => $_
+longname105 => $a
+longname3558 => $aa
+longname159 => $b
+longname3612 => $ba
+longname213 => $c
+longname3666 => $ca
+longname267 => $d
+longname3720 => $da
+longname321 => $e
+longname3774 => $ea
+longname374 => $f
+longname3828 => $fa
+longname428 => $g
+longname3882 => $ga
+longname482 => $h
+longname3936 => $ha
+longname536 => $i
+longname3990 => $ia
+longname590 => $j
+longname4044 => $ja
+longname644 => $k
+longname4098 => $ka
+longname698 => $l
+longname4152 => $la
+longname752 => $m
+longname4206 => $ma
+longname805 => $n
+longname4260 => $na
+longname858 => $o
+longname4314 => $oa
+longname912 => $p
+longname4368 => $pa
+longname966 => $q
+longname4422 => $qa
+longname1020 => $r
+longname4476 => $ra
+longname1074 => $s
+longname4530 => $sa
+longname1128 => $t
+longname4584 => $ta
+longname1182 => $u
+longname4638 => $ua
+longname1236 => $v
+longname4692 => $va
+longname1290 => $w
+longname4746 => $wa
+longname1344 => $x
+longname4800 => $xa
+longname1398 => $y
+longname4854 => $ya
+longname1452 => $z
+longname4908 => $za
+longname24 => A
+longname2937 => A$
+longname2991 => A0
+longname3045 => A1
+longname3099 => A2
+longname3153 => A3
+longname3207 => A4
+longname3261 => A5
+longname3315 => A6
+longname3369 => A7
+longname3423 => A8
+longname3477 => A9
+longname1479 => AA
+longname4935 => AAa
+longname1533 => AB
+longname4989 => ABa
+longname1587 => AC
+longname1641 => AD
+longname1695 => AE
+longname1749 => AF
+longname1803 => AG
+longname1857 => AH
+longname1911 => AI
+longname1965 => AJ
+longname2019 => AK
+longname2073 => AL
+longname2127 => AM
+longname2181 => AN
+longname2235 => AO
+longname2289 => AP
+longname2343 => AQ
+longname2397 => AR
+longname2451 => AS
+longname2505 => AT
+longname2559 => AU
+longname2613 => AV
+longname2667 => AW
+longname2721 => AX
+longname2775 => AY
+longname2829 => AZ
+longname2883 => A_
+longname78 => Aa
+longname3531 => Aaa
+longname132 => Ab
+longname3585 => Aba
+longname186 => Ac
+longname3639 => Aca
+longname240 => Ad
+longname3693 => Ada
+longname294 => Ae
+longname3747 => Aea
+longname347 => Af
+longname3801 => Afa
+longname401 => Ag
+longname3855 => Aga
+longname455 => Ah
+longname3909 => Aha
+longname509 => Ai
+longname3963 => Aia
+longname563 => Aj
+longname4017 => Aja
+longname617 => Ak
+longname4071 => Aka
+longname671 => Al
+longname4125 => Ala
+longname725 => Am
+longname4179 => Ama
+longname778 => An
+longname4233 => Ana
+longname831 => Ao
+longname4287 => Aoa
+longname885 => Ap
+longname4341 => Apa
+longname939 => Aq
+longname4395 => Aqa
+longname993 => Ar
+longname4449 => Ara
+longname1047 => As
+longname4503 => Asa
+longname1101 => At
+longname4557 => Ata
+longname1155 => Au
+longname4611 => Aua
+longname1209 => Av
+longname4665 => Ava
+longname1263 => Aw
+longname4719 => Awa
+longname1317 => Ax
+longname4773 => Axa
+longname1371 => Ay
+longname4827 => Aya
+longname1425 => Az
+longname4881 => Aza
+longname25 => B
+longname2938 => B$
+longname2992 => B0
+longname3046 => B1
+longname3100 => B2
+longname3154 => B3
+longname3208 => B4
+longname3262 => B5
+longname3316 => B6
+longname3370 => B7
+longname3424 => B8
+longname3478 => B9
+longname1480 => BA
+longname4936 => BAa
+longname1534 => BB
+longname4990 => BBa
+longname1588 => BC
+longname1642 => BD
+longname1696 => BE
+longname1750 => BF
+longname1804 => BG
+longname1858 => BH
+longname1912 => BI
+longname1966 => BJ
+longname2020 => BK
+longname2074 => BL
+longname2128 => BM
+longname2182 => BN
+longname2236 => BO
+longname2290 => BP
+longname2344 => BQ
+longname2398 => BR
+longname2452 => BS
+longname2506 => BT
+longname2560 => BU
+longname2614 => BV
+longname2668 => BW
+longname2722 => BX
+longname2776 => BY
+longname2830 => BZ
+longname2884 => B_
+longname79 => Ba
+longname3532 => Baa
+longname133 => Bb
+longname3586 => Bba
+longname187 => Bc
+longname3640 => Bca
+longname241 => Bd
+longname3694 => Bda
+longname295 => Be
+longname3748 => Bea
+longname348 => Bf
+longname3802 => Bfa
+longname402 => Bg
+longname3856 => Bga
+longname456 => Bh
+longname3910 => Bha
+longname510 => Bi
+longname3964 => Bia
+longname564 => Bj
+longname4018 => Bja
+longname618 => Bk
+longname4072 => Bka
+longname672 => Bl
+longname4126 => Bla
+longname726 => Bm
+longname4180 => Bma
+longname779 => Bn
+longname4234 => Bna
+longname832 => Bo
+longname4288 => Boa
+longname886 => Bp
+longname4342 => Bpa
+longname940 => Bq
+longname4396 => Bqa
+longname994 => Br
+longname4450 => Bra
+longname1048 => Bs
+longname4504 => Bsa
+longname1102 => Bt
+longname4558 => Bta
+longname1156 => Bu
+longname4612 => Bua
+longname1210 => Bv
+longname4666 => Bva
+longname1264 => Bw
+longname4720 => Bwa
+longname1318 => Bx
+longname4774 => Bxa
+longname1372 => By
+longname4828 => Bya
+longname1426 => Bz
+longname4882 => Bza
+longname26 => C
+longname2939 => C$
+longname2993 => C0
+longname3047 => C1
+longname3101 => C2
+longname3155 => C3
+longname3209 => C4
+longname3263 => C5
+longname3317 => C6
+longname3371 => C7
+longname3425 => C8
+longname3479 => C9
+longname1481 => CA
+longname4937 => CAa
+longname1535 => CB
+longname4991 => CBa
+longname1589 => CC
+longname1643 => CD
+longname1697 => CE
+longname1751 => CF
+longname1805 => CG
+longname1859 => CH
+longname1913 => CI
+longname1967 => CJ
+longname2021 => CK
+longname2075 => CL
+longname2129 => CM
+longname2183 => CN
+longname2237 => CO
+longname2291 => CP
+longname2345 => CQ
+longname2399 => CR
+longname2453 => CS
+longname2507 => CT
+longname2561 => CU
+longname2615 => CV
+longname2669 => CW
+longname2723 => CX
+longname2777 => CY
+longname2831 => CZ
+longname2885 => C_
+longname80 => Ca
+longname3533 => Caa
+longname134 => Cb
+longname3587 => Cba
+longname188 => Cc
+longname3641 => Cca
+longname242 => Cd
+longname3695 => Cda
+longname296 => Ce
+longname3749 => Cea
+longname349 => Cf
+longname3803 => Cfa
+longname403 => Cg
+longname3857 => Cga
+longname457 => Ch
+longname3911 => Cha
+longname511 => Ci
+longname3965 => Cia
+longname565 => Cj
+longname4019 => Cja
+longname619 => Ck
+longname4073 => Cka
+longname673 => Cl
+longname4127 => Cla
+longname727 => Cm
+longname4181 => Cma
+longname780 => Cn
+longname4235 => Cna
+longname833 => Co
+longname4289 => Coa
+longname887 => Cp
+longname4343 => Cpa
+longname941 => Cq
+longname4397 => Cqa
+longname995 => Cr
+longname4451 => Cra
+longname1049 => Cs
+longname4505 => Csa
+longname1103 => Ct
+longname4559 => Cta
+longname1157 => Cu
+longname4613 => Cua
+longname1211 => Cv
+longname4667 => Cva
+longname1265 => Cw
+longname4721 => Cwa
+longname1319 => Cx
+longname4775 => Cxa
+longname1373 => Cy
+longname4829 => Cya
+longname1427 => Cz
+longname4883 => Cza
+longname27 => D
+longname2940 => D$
+longname2994 => D0
+longname3048 => D1
+longname3102 => D2
+longname3156 => D3
+longname3210 => D4
+longname3264 => D5
+longname3318 => D6
+longname3372 => D7
+longname3426 => D8
+longname3480 => D9
+longname1482 => DA
+longname4938 => DAa
+longname1536 => DB
+longname4992 => DBa
+longname1590 => DC
+longname1644 => DD
+longname1698 => DE
+longname1752 => DF
+longname1806 => DG
+longname1860 => DH
+longname1914 => DI
+longname1968 => DJ
+longname2022 => DK
+longname2076 => DL
+longname2130 => DM
+longname2184 => DN
+longname2238 => DO
+longname2292 => DP
+longname2346 => DQ
+longname2400 => DR
+longname2454 => DS
+longname2508 => DT
+longname2562 => DU
+longname2616 => DV
+longname2670 => DW
+longname2724 => DX
+longname2778 => DY
+longname2832 => DZ
+longname2886 => D_
+longname81 => Da
+longname3534 => Daa
+longname135 => Db
+longname3588 => Dba
+longname189 => Dc
+longname3642 => Dca
+longname243 => Dd
+longname3696 => Dda
+longname297 => De
+longname3750 => Dea
+longname350 => Df
+longname3804 => Dfa
+longname404 => Dg
+longname3858 => Dga
+longname458 => Dh
+longname3912 => Dha
+longname512 => Di
+longname3966 => Dia
+longname566 => Dj
+longname4020 => Dja
+longname620 => Dk
+longname4074 => Dka
+longname674 => Dl
+longname4128 => Dla
+longname728 => Dm
+longname4182 => Dma
+longname781 => Dn
+longname4236 => Dna
+longname834 => Do
+longname4290 => Doa
+longname888 => Dp
+longname4344 => Dpa
+longname942 => Dq
+longname4398 => Dqa
+longname996 => Dr
+longname4452 => Dra
+longname1050 => Ds
+longname4506 => Dsa
+longname1104 => Dt
+longname4560 => Dta
+longname1158 => Du
+longname4614 => Dua
+longname1212 => Dv
+longname4668 => Dva
+longname1266 => Dw
+longname4722 => Dwa
+longname1320 => Dx
+longname4776 => Dxa
+longname1374 => Dy
+longname4830 => Dya
+longname1428 => Dz
+longname4884 => Dza
+longname28 => E
+longname2941 => E$
+longname2995 => E0
+longname3049 => E1
+longname3103 => E2
+longname3157 => E3
+longname3211 => E4
+longname3265 => E5
+longname3319 => E6
+longname3373 => E7
+longname3427 => E8
+longname3481 => E9
+longname1483 => EA
+longname4939 => EAa
+longname1537 => EB
+longname4993 => EBa
+longname1591 => EC
+longname1645 => ED
+longname1699 => EE
+longname1753 => EF
+longname1807 => EG
+longname1861 => EH
+longname1915 => EI
+longname1969 => EJ
+longname2023 => EK
+longname2077 => EL
+longname2131 => EM
+longname2185 => EN
+longname2239 => EO
+longname2293 => EP
+longname2347 => EQ
+longname2401 => ER
+longname2455 => ES
+longname2509 => ET
+longname2563 => EU
+longname2617 => EV
+longname2671 => EW
+longname2725 => EX
+longname2779 => EY
+longname2833 => EZ
+longname2887 => E_
+longname82 => Ea
+longname3535 => Eaa
+longname136 => Eb
+longname3589 => Eba
+longname190 => Ec
+longname3643 => Eca
+longname244 => Ed
+longname3697 => Eda
+longname298 => Ee
+longname3751 => Eea
+longname351 => Ef
+longname3805 => Efa
+longname405 => Eg
+longname3859 => Ega
+longname459 => Eh
+longname3913 => Eha
+longname513 => Ei
+longname3967 => Eia
+longname567 => Ej
+longname4021 => Eja
+longname621 => Ek
+longname4075 => Eka
+longname675 => El
+longname4129 => Ela
+longname729 => Em
+longname4183 => Ema
+longname782 => En
+longname4237 => Ena
+longname835 => Eo
+longname4291 => Eoa
+longname889 => Ep
+longname4345 => Epa
+longname943 => Eq
+longname4399 => Eqa
+longname997 => Er
+longname4453 => Era
+longname1051 => Es
+longname4507 => Esa
+longname1105 => Et
+longname4561 => Eta
+longname1159 => Eu
+longname4615 => Eua
+longname1213 => Ev
+longname4669 => Eva
+longname1267 => Ew
+longname4723 => Ewa
+longname1321 => Ex
+longname4777 => Exa
+longname1375 => Ey
+longname4831 => Eya
+longname1429 => Ez
+longname4885 => Eza
+longname29 => F
+longname2942 => F$
+longname2996 => F0
+longname3050 => F1
+longname3104 => F2
+longname3158 => F3
+longname3212 => F4
+longname3266 => F5
+longname3320 => F6
+longname3374 => F7
+longname3428 => F8
+longname3482 => F9
+longname1484 => FA
+longname4940 => FAa
+longname1538 => FB
+longname4994 => FBa
+longname1592 => FC
+longname1646 => FD
+longname1700 => FE
+longname1754 => FF
+longname1808 => FG
+longname1862 => FH
+longname1916 => FI
+longname1970 => FJ
+longname2024 => FK
+longname2078 => FL
+longname2132 => FM
+longname2186 => FN
+longname2240 => FO
+longname2294 => FP
+longname2348 => FQ
+longname2402 => FR
+longname2456 => FS
+longname2510 => FT
+longname2564 => FU
+longname2618 => FV
+longname2672 => FW
+longname2726 => FX
+longname2780 => FY
+longname2834 => FZ
+longname2888 => F_
+longname83 => Fa
+longname3536 => Faa
+longname137 => Fb
+longname3590 => Fba
+longname191 => Fc
+longname3644 => Fca
+longname245 => Fd
+longname3698 => Fda
+longname299 => Fe
+longname3752 => Fea
+longname352 => Ff
+longname3806 => Ffa
+longname406 => Fg
+longname3860 => Fga
+longname460 => Fh
+longname3914 => Fha
+longname514 => Fi
+longname3968 => Fia
+longname568 => Fj
+longname4022 => Fja
+longname622 => Fk
+longname4076 => Fka
+longname676 => Fl
+longname4130 => Fla
+longname730 => Fm
+longname4184 => Fma
+longname783 => Fn
+longname4238 => Fna
+longname836 => Fo
+longname4292 => Foa
+longname890 => Fp
+longname4346 => Fpa
+longname944 => Fq
+longname4400 => Fqa
+longname998 => Fr
+longname4454 => Fra
+longname1052 => Fs
+longname4508 => Fsa
+longname1106 => Ft
+longname4562 => Fta
+longname1160 => Fu
+longname4616 => Fua
+longname1214 => Fv
+longname4670 => Fva
+longname1268 => Fw
+longname4724 => Fwa
+longname1322 => Fx
+longname4778 => Fxa
+longname1376 => Fy
+longname4832 => Fya
+longname1430 => Fz
+longname4886 => Fza
+longname30 => G
+longname2943 => G$
+longname2997 => G0
+longname3051 => G1
+longname3105 => G2
+longname3159 => G3
+longname3213 => G4
+longname3267 => G5
+longname3321 => G6
+longname3375 => G7
+longname3429 => G8
+longname3483 => G9
+longname1485 => GA
+longname4941 => GAa
+longname1539 => GB
+longname4995 => GBa
+longname1593 => GC
+longname1647 => GD
+longname1701 => GE
+longname1755 => GF
+longname1809 => GG
+longname1863 => GH
+longname1917 => GI
+longname1971 => GJ
+longname2025 => GK
+longname2079 => GL
+longname2133 => GM
+longname2187 => GN
+longname2241 => GO
+longname2295 => GP
+longname2349 => GQ
+longname2403 => GR
+longname2457 => GS
+longname2511 => GT
+longname2565 => GU
+longname2619 => GV
+longname2673 => GW
+longname2727 => GX
+longname2781 => GY
+longname2835 => GZ
+longname2889 => G_
+longname84 => Ga
+longname3537 => Gaa
+longname138 => Gb
+longname3591 => Gba
+longname192 => Gc
+longname3645 => Gca
+longname246 => Gd
+longname3699 => Gda
+longname300 => Ge
+longname3753 => Gea
+longname353 => Gf
+longname3807 => Gfa
+longname407 => Gg
+longname3861 => Gga
+longname461 => Gh
+longname3915 => Gha
+longname515 => Gi
+longname3969 => Gia
+longname569 => Gj
+longname4023 => Gja
+longname623 => Gk
+longname4077 => Gka
+longname677 => Gl
+longname4131 => Gla
+longname731 => Gm
+longname4185 => Gma
+longname784 => Gn
+longname4239 => Gna
+longname837 => Go
+longname4293 => Goa
+longname891 => Gp
+longname4347 => Gpa
+longname945 => Gq
+longname4401 => Gqa
+longname999 => Gr
+longname4455 => Gra
+longname1053 => Gs
+longname4509 => Gsa
+longname1107 => Gt
+longname4563 => Gta
+longname1161 => Gu
+longname4617 => Gua
+longname1215 => Gv
+longname4671 => Gva
+longname1269 => Gw
+longname4725 => Gwa
+longname1323 => Gx
+longname4779 => Gxa
+longname1377 => Gy
+longname4833 => Gya
+longname1431 => Gz
+longname4887 => Gza
+longname31 => H
+longname2944 => H$
+longname2998 => H0
+longname3052 => H1
+longname3106 => H2
+longname3160 => H3
+longname3214 => H4
+longname3268 => H5
+longname3322 => H6
+longname3376 => H7
+longname3430 => H8
+longname3484 => H9
+longname1486 => HA
+longname4942 => HAa
+longname1540 => HB
+longname4996 => HBa
+longname1594 => HC
+longname1648 => HD
+longname1702 => HE
+longname1756 => HF
+longname1810 => HG
+longname1864 => HH
+longname1918 => HI
+longname1972 => HJ
+longname2026 => HK
+longname2080 => HL
+longname2134 => HM
+longname2188 => HN
+longname2242 => HO
+longname2296 => HP
+longname2350 => HQ
+longname2404 => HR
+longname2458 => HS
+longname2512 => HT
+longname2566 => HU
+longname2620 => HV
+longname2674 => HW
+longname2728 => HX
+longname2782 => HY
+longname2836 => HZ
+longname2890 => H_
+longname85 => Ha
+longname3538 => Haa
+longname139 => Hb
+longname3592 => Hba
+longname193 => Hc
+longname3646 => Hca
+longname247 => Hd
+longname3700 => Hda
+longname301 => He
+longname3754 => Hea
+longname354 => Hf
+longname3808 => Hfa
+longname408 => Hg
+longname3862 => Hga
+longname462 => Hh
+longname3916 => Hha
+longname516 => Hi
+longname3970 => Hia
+longname570 => Hj
+longname4024 => Hja
+longname624 => Hk
+longname4078 => Hka
+longname678 => Hl
+longname4132 => Hla
+longname732 => Hm
+longname4186 => Hma
+longname785 => Hn
+longname4240 => Hna
+longname838 => Ho
+longname4294 => Hoa
+longname892 => Hp
+longname4348 => Hpa
+longname946 => Hq
+longname4402 => Hqa
+longname1000 => Hr
+longname4456 => Hra
+longname1054 => Hs
+longname4510 => Hsa
+longname1108 => Ht
+longname4564 => Hta
+longname1162 => Hu
+longname4618 => Hua
+longname1216 => Hv
+longname4672 => Hva
+longname1270 => Hw
+longname4726 => Hwa
+longname1324 => Hx
+longname4780 => Hxa
+longname1378 => Hy
+longname4834 => Hya
+longname1432 => Hz
+longname4888 => Hza
+longname32 => I
+longname2945 => I$
+longname2999 => I0
+longname3053 => I1
+longname3107 => I2
+longname3161 => I3
+longname3215 => I4
+longname3269 => I5
+longname3323 => I6
+longname3377 => I7
+longname3431 => I8
+longname3485 => I9
+longname1487 => IA
+longname4943 => IAa
+longname1541 => IB
+longname4997 => IBa
+longname1595 => IC
+longname1649 => ID
+longname1703 => IE
+longname1757 => IF
+longname1811 => IG
+longname1865 => IH
+longname1919 => II
+longname1973 => IJ
+longname2027 => IK
+longname2081 => IL
+longname2135 => IM
+longname2189 => IN
+longname2243 => IO
+longname2297 => IP
+longname2351 => IQ
+longname2405 => IR
+longname2459 => IS
+longname2513 => IT
+longname2567 => IU
+longname2621 => IV
+longname2675 => IW
+longname2729 => IX
+longname2783 => IY
+longname2837 => IZ
+longname2891 => I_
+longname86 => Ia
+longname3539 => Iaa
+longname140 => Ib
+longname3593 => Iba
+longname194 => Ic
+longname3647 => Ica
+longname248 => Id
+longname3701 => Ida
+longname302 => Ie
+longname3755 => Iea
+longname355 => If
+longname3809 => Ifa
+longname409 => Ig
+longname3863 => Iga
+longname463 => Ih
+longname3917 => Iha
+longname517 => Ii
+longname3971 => Iia
+longname571 => Ij
+longname4025 => Ija
+longname625 => Ik
+longname4079 => Ika
+longname679 => Il
+longname4133 => Ila
+longname733 => Im
+longname4187 => Ima
+longname786 => In
+longname4241 => Ina
+longname839 => Io
+longname4295 => Ioa
+longname893 => Ip
+longname4349 => Ipa
+longname947 => Iq
+longname4403 => Iqa
+longname1001 => Ir
+longname4457 => Ira
+longname1055 => Is
+longname4511 => Isa
+longname1109 => It
+longname4565 => Ita
+longname1163 => Iu
+longname4619 => Iua
+longname1217 => Iv
+longname4673 => Iva
+longname1271 => Iw
+longname4727 => Iwa
+longname1325 => Ix
+longname4781 => Ixa
+longname1379 => Iy
+longname4835 => Iya
+longname1433 => Iz
+longname4889 => Iza
+longname33 => J
+longname2946 => J$
+longname3000 => J0
+longname3054 => J1
+longname3108 => J2
+longname3162 => J3
+longname3216 => J4
+longname3270 => J5
+longname3324 => J6
+longname3378 => J7
+longname3432 => J8
+longname3486 => J9
+longname1488 => JA
+longname4944 => JAa
+longname1542 => JB
+longname4998 => JBa
+longname1596 => JC
+longname1650 => JD
+longname1704 => JE
+longname1758 => JF
+longname1812 => JG
+longname1866 => JH
+longname1920 => JI
+longname1974 => JJ
+longname2028 => JK
+longname2082 => JL
+longname2136 => JM
+longname2190 => JN
+longname2244 => JO
+longname2298 => JP
+longname2352 => JQ
+longname2406 => JR
+longname2460 => JS
+longname2514 => JT
+longname2568 => JU
+longname2622 => JV
+longname2676 => JW
+longname2730 => JX
+longname2784 => JY
+longname2838 => JZ
+longname2892 => J_
+longname87 => Ja
+longname3540 => Jaa
+longname141 => Jb
+longname3594 => Jba
+longname195 => Jc
+longname3648 => Jca
+longname249 => Jd
+longname3702 => Jda
+longname303 => Je
+longname3756 => Jea
+longname356 => Jf
+longname3810 => Jfa
+longname410 => Jg
+longname3864 => Jga
+longname464 => Jh
+longname3918 => Jha
+longname518 => Ji
+longname3972 => Jia
+longname572 => Jj
+longname4026 => Jja
+longname626 => Jk
+longname4080 => Jka
+longname680 => Jl
+longname4134 => Jla
+longname734 => Jm
+longname4188 => Jma
+longname787 => Jn
+longname4242 => Jna
+longname840 => Jo
+longname4296 => Joa
+longname894 => Jp
+longname4350 => Jpa
+longname948 => Jq
+longname4404 => Jqa
+longname1002 => Jr
+longname4458 => Jra
+longname1056 => Js
+longname4512 => Jsa
+longname1110 => Jt
+longname4566 => Jta
+longname1164 => Ju
+longname4620 => Jua
+longname1218 => Jv
+longname4674 => Jva
+longname1272 => Jw
+longname4728 => Jwa
+longname1326 => Jx
+longname4782 => Jxa
+longname1380 => Jy
+longname4836 => Jya
+longname1434 => Jz
+longname4890 => Jza
+longname34 => K
+longname2947 => K$
+longname3001 => K0
+longname3055 => K1
+longname3109 => K2
+longname3163 => K3
+longname3217 => K4
+longname3271 => K5
+longname3325 => K6
+longname3379 => K7
+longname3433 => K8
+longname3487 => K9
+longname1489 => KA
+longname4945 => KAa
+longname1543 => KB
+longname4999 => KBa
+longname1597 => KC
+longname1651 => KD
+longname1705 => KE
+longname1759 => KF
+longname1813 => KG
+longname1867 => KH
+longname1921 => KI
+longname1975 => KJ
+longname2029 => KK
+longname2083 => KL
+longname2137 => KM
+longname2191 => KN
+longname2245 => KO
+longname2299 => KP
+longname2353 => KQ
+longname2407 => KR
+longname2461 => KS
+longname2515 => KT
+longname2569 => KU
+longname2623 => KV
+longname2677 => KW
+longname2731 => KX
+longname2785 => KY
+longname2839 => KZ
+longname2893 => K_
+longname88 => Ka
+longname3541 => Kaa
+longname142 => Kb
+longname3595 => Kba
+longname196 => Kc
+longname3649 => Kca
+longname250 => Kd
+longname3703 => Kda
+longname304 => Ke
+longname3757 => Kea
+longname357 => Kf
+longname3811 => Kfa
+longname411 => Kg
+longname3865 => Kga
+longname465 => Kh
+longname3919 => Kha
+longname519 => Ki
+longname3973 => Kia
+longname573 => Kj
+longname4027 => Kja
+longname627 => Kk
+longname4081 => Kka
+longname681 => Kl
+longname4135 => Kla
+longname735 => Km
+longname4189 => Kma
+longname788 => Kn
+longname4243 => Kna
+longname841 => Ko
+longname4297 => Koa
+longname895 => Kp
+longname4351 => Kpa
+longname949 => Kq
+longname4405 => Kqa
+longname1003 => Kr
+longname4459 => Kra
+longname1057 => Ks
+longname4513 => Ksa
+longname1111 => Kt
+longname4567 => Kta
+longname1165 => Ku
+longname4621 => Kua
+longname1219 => Kv
+longname4675 => Kva
+longname1273 => Kw
+longname4729 => Kwa
+longname1327 => Kx
+longname4783 => Kxa
+longname1381 => Ky
+longname4837 => Kya
+longname1435 => Kz
+longname4891 => Kza
+longname35 => L
+longname2948 => L$
+longname3002 => L0
+longname3056 => L1
+longname3110 => L2
+longname3164 => L3
+longname3218 => L4
+longname3272 => L5
+longname3326 => L6
+longname3380 => L7
+longname3434 => L8
+longname3488 => L9
+longname1490 => LA
+longname4946 => LAa
+longname1544 => LB
+eventname1 => LBa
+longname1598 => LC
+longname1652 => LD
+longname1706 => LE
+longname1760 => LF
+longname1814 => LG
+longname1868 => LH
+longname1922 => LI
+longname1976 => LJ
+longname2030 => LK
+longname2084 => LL
+longname2138 => LM
+longname2192 => LN
+longname2246 => LO
+longname2300 => LP
+longname2354 => LQ
+longname2408 => LR
+longname2462 => LS
+longname2516 => LT
+longname2570 => LU
+longname2624 => LV
+longname2678 => LW
+longname2732 => LX
+longname2786 => LY
+longname2840 => LZ
+longname2894 => L_
+longname89 => La
+longname3542 => Laa
+longname143 => Lb
+longname3596 => Lba
+longname197 => Lc
+longname3650 => Lca
+longname251 => Ld
+longname3704 => Lda
+longname305 => Le
+longname3758 => Lea
+longname358 => Lf
+longname3812 => Lfa
+longname412 => Lg
+longname3866 => Lga
+longname466 => Lh
+longname3920 => Lha
+longname520 => Li
+longname3974 => Lia
+longname574 => Lj
+longname4028 => Lja
+longname628 => Lk
+longname4082 => Lka
+longname682 => Ll
+longname4136 => Lla
+longname736 => Lm
+longname4190 => Lma
+longname789 => Ln
+longname4244 => Lna
+longname842 => Lo
+longname4298 => Loa
+longname896 => Lp
+longname4352 => Lpa
+longname950 => Lq
+longname4406 => Lqa
+longname1004 => Lr
+longname4460 => Lra
+longname1058 => Ls
+longname4514 => Lsa
+longname1112 => Lt
+longname4568 => Lta
+longname1166 => Lu
+longname4622 => Lua
+longname1220 => Lv
+longname4676 => Lva
+longname1274 => Lw
+longname4730 => Lwa
+longname1328 => Lx
+longname4784 => Lxa
+longname1382 => Ly
+longname4838 => Lya
+longname1436 => Lz
+longname4892 => Lza
+longname36 => M
+longname2949 => M$
+longname3003 => M0
+longname3057 => M1
+longname3111 => M2
+longname3165 => M3
+longname3219 => M4
+longname3273 => M5
+longname3327 => M6
+longname3381 => M7
+longname3435 => M8
+longname3489 => M9
+longname1491 => MA
+longname4947 => MAa
+longname1545 => MB
+longname1599 => MC
+longname1653 => MD
+longname1707 => ME
+longname1761 => MF
+longname1815 => MG
+longname1869 => MH
+longname1923 => MI
+longname1977 => MJ
+longname2031 => MK
+longname2085 => ML
+longname2139 => MM
+longname2193 => MN
+longname2247 => MO
+longname2301 => MP
+longname2355 => MQ
+longname2409 => MR
+longname2463 => MS
+longname2517 => MT
+longname2571 => MU
+longname2625 => MV
+longname2679 => MW
+longname2733 => MX
+longname2787 => MY
+longname2841 => MZ
+longname2895 => M_
+longname90 => Ma
+longname3543 => Maa
+longname144 => Mb
+longname3597 => Mba
+longname198 => Mc
+longname3651 => Mca
+longname252 => Md
+longname3705 => Mda
+longname306 => Me
+longname3759 => Mea
+longname359 => Mf
+longname3813 => Mfa
+longname413 => Mg
+longname3867 => Mga
+longname467 => Mh
+longname3921 => Mha
+longname521 => Mi
+longname3975 => Mia
+longname575 => Mj
+longname4029 => Mja
+longname629 => Mk
+longname4083 => Mka
+longname683 => Ml
+longname4137 => Mla
+longname737 => Mm
+longname4191 => Mma
+longname790 => Mn
+longname4245 => Mna
+longname843 => Mo
+longname4299 => Moa
+longname897 => Mp
+longname4353 => Mpa
+longname951 => Mq
+longname4407 => Mqa
+longname1005 => Mr
+longname4461 => Mra
+longname1059 => Ms
+longname4515 => Msa
+longname1113 => Mt
+longname4569 => Mta
+longname1167 => Mu
+longname4623 => Mua
+longname1221 => Mv
+longname4677 => Mva
+longname1275 => Mw
+longname4731 => Mwa
+longname1329 => Mx
+longname4785 => Mxa
+longname1383 => My
+longname4839 => Mya
+longname1437 => Mz
+longname4893 => Mza
+longname37 => N
+longname2950 => N$
+longname3004 => N0
+longname3058 => N1
+longname3112 => N2
+longname3166 => N3
+longname3220 => N4
+longname3274 => N5
+longname3328 => N6
+longname3382 => N7
+longname3436 => N8
+longname3490 => N9
+longname1492 => NA
+longname4948 => NAa
+longname1546 => NB
+longname1600 => NC
+longname1654 => ND
+longname1708 => NE
+longname1762 => NF
+longname1816 => NG
+longname1870 => NH
+longname1924 => NI
+longname1978 => NJ
+longname2032 => NK
+longname2086 => NL
+longname2140 => NM
+longname2194 => NN
+longname2248 => NO
+longname2302 => NP
+longname2356 => NQ
+longname2410 => NR
+longname2464 => NS
+longname2518 => NT
+longname2572 => NU
+longname2626 => NV
+longname2680 => NW
+longname2734 => NX
+longname2788 => NY
+longname2842 => NZ
+longname2896 => N_
+longname91 => Na
+longname3544 => Naa
+longname145 => Nb
+longname3598 => Nba
+longname199 => Nc
+longname3652 => Nca
+longname253 => Nd
+longname3706 => Nda
+longname307 => Ne
+longname3760 => Nea
+longname360 => Nf
+longname3814 => Nfa
+longname414 => Ng
+longname3868 => Nga
+longname468 => Nh
+longname3922 => Nha
+longname522 => Ni
+longname3976 => Nia
+longname576 => Nj
+longname4030 => Nja
+longname630 => Nk
+longname4084 => Nka
+longname684 => Nl
+longname4138 => Nla
+longname738 => Nm
+longname4192 => Nma
+longname791 => Nn
+longname4246 => Nna
+longname844 => No
+longname4300 => Noa
+longname898 => Np
+longname4354 => Npa
+longname952 => Nq
+longname4408 => Nqa
+longname1006 => Nr
+longname4462 => Nra
+longname1060 => Ns
+longname4516 => Nsa
+longname1114 => Nt
+longname4570 => Nta
+longname1168 => Nu
+longname4624 => Nua
+longname1222 => Nv
+longname4678 => Nva
+longname1276 => Nw
+longname4732 => Nwa
+longname1330 => Nx
+longname4786 => Nxa
+longname1384 => Ny
+longname4840 => Nya
+longname1438 => Nz
+longname4894 => Nza
+longname38 => O
+longname2951 => O$
+longname3005 => O0
+longname3059 => O1
+longname3113 => O2
+longname3167 => O3
+longname3221 => O4
+longname3275 => O5
+longname3329 => O6
+longname3383 => O7
+longname3437 => O8
+longname3491 => O9
+longname1493 => OA
+longname4949 => OAa
+longname1547 => OB
+longname1601 => OC
+longname1655 => OD
+longname1709 => OE
+longname1763 => OF
+longname1817 => OG
+longname1871 => OH
+longname1925 => OI
+longname1979 => OJ
+longname2033 => OK
+longname2087 => OL
+longname2141 => OM
+longname2195 => ON
+longname2249 => OO
+longname2303 => OP
+longname2357 => OQ
+longname2411 => OR
+longname2465 => OS
+longname2519 => OT
+longname2573 => OU
+longname2627 => OV
+longname2681 => OW
+longname2735 => OX
+longname2789 => OY
+longname2843 => OZ
+longname2897 => O_
+longname92 => Oa
+longname3545 => Oaa
+longname146 => Ob
+longname3599 => Oba
+longname200 => Oc
+longname3653 => Oca
+longname254 => Od
+longname3707 => Oda
+longname308 => Oe
+longname3761 => Oea
+longname361 => Of
+longname3815 => Ofa
+longname415 => Og
+longname3869 => Oga
+longname469 => Oh
+longname3923 => Oha
+longname523 => Oi
+longname3977 => Oia
+longname577 => Oj
+longname4031 => Oja
+longname631 => Ok
+longname4085 => Oka
+longname685 => Ol
+longname4139 => Ola
+longname739 => Om
+longname4193 => Oma
+longname792 => On
+longname4247 => Ona
+longname845 => Oo
+longname4301 => Ooa
+longname899 => Op
+longname4355 => Opa
+longname953 => Oq
+longname4409 => Oqa
+longname1007 => Or
+longname4463 => Ora
+longname1061 => Os
+longname4517 => Osa
+longname1115 => Ot
+longname4571 => Ota
+longname1169 => Ou
+longname4625 => Oua
+longname1223 => Ov
+longname4679 => Ova
+longname1277 => Ow
+longname4733 => Owa
+longname1331 => Ox
+longname4787 => Oxa
+longname1385 => Oy
+longname4841 => Oya
+longname1439 => Oz
+longname4895 => Oza
+longname39 => P
+longname2952 => P$
+longname3006 => P0
+longname3060 => P1
+longname3114 => P2
+longname3168 => P3
+longname3222 => P4
+longname3276 => P5
+longname3330 => P6
+longname3384 => P7
+longname3438 => P8
+longname3492 => P9
+longname1494 => PA
+longname4950 => PAa
+longname1548 => PB
+longname1602 => PC
+longname1656 => PD
+longname1710 => PE
+longname1764 => PF
+longname1818 => PG
+longname1872 => PH
+longname1926 => PI
+longname1980 => PJ
+longname2034 => PK
+longname2088 => PL
+longname2142 => PM
+longname2196 => PN
+longname2250 => PO
+longname2304 => PP
+longname2358 => PQ
+longname2412 => PR
+longname2466 => PS
+longname2520 => PT
+longname2574 => PU
+longname2628 => PV
+longname2682 => PW
+longname2736 => PX
+longname2790 => PY
+longname2844 => PZ
+longname2898 => P_
+longname93 => Pa
+longname3546 => Paa
+longname147 => Pb
+longname3600 => Pba
+longname201 => Pc
+longname3654 => Pca
+longname255 => Pd
+longname3708 => Pda
+longname309 => Pe
+longname3762 => Pea
+longname362 => Pf
+longname3816 => Pfa
+longname416 => Pg
+longname3870 => Pga
+longname470 => Ph
+longname3924 => Pha
+longname524 => Pi
+longname3978 => Pia
+longname578 => Pj
+longname4032 => Pja
+longname632 => Pk
+longname4086 => Pka
+longname686 => Pl
+longname4140 => Pla
+longname740 => Pm
+longname4194 => Pma
+longname793 => Pn
+longname4248 => Pna
+longname846 => Po
+longname4302 => Poa
+longname900 => Pp
+longname4356 => Ppa
+longname954 => Pq
+longname4410 => Pqa
+longname1008 => Pr
+longname4464 => Pra
+longname1062 => Ps
+longname4518 => Psa
+longname1116 => Pt
+longname4572 => Pta
+longname1170 => Pu
+longname4626 => Pua
+longname1224 => Pv
+longname4680 => Pva
+longname1278 => Pw
+longname4734 => Pwa
+longname1332 => Px
+longname4788 => Pxa
+longname1386 => Py
+longname4842 => Pya
+longname1440 => Pz
+longname4896 => Pza
+longname40 => Q
+longname2953 => Q$
+longname3007 => Q0
+longname3061 => Q1
+longname3115 => Q2
+longname3169 => Q3
+longname3223 => Q4
+longname3277 => Q5
+longname3331 => Q6
+longname3385 => Q7
+longname3439 => Q8
+longname3493 => Q9
+longname1495 => QA
+longname4951 => QAa
+longname1549 => QB
+longname1603 => QC
+longname1657 => QD
+longname1711 => QE
+longname1765 => QF
+longname1819 => QG
+longname1873 => QH
+longname1927 => QI
+longname1981 => QJ
+longname2035 => QK
+longname2089 => QL
+longname2143 => QM
+longname2197 => QN
+longname2251 => QO
+longname2305 => QP
+longname2359 => QQ
+longname2413 => QR
+longname2467 => QS
+longname2521 => QT
+longname2575 => QU
+longname2629 => QV
+longname2683 => QW
+longname2737 => QX
+longname2791 => QY
+longname2845 => QZ
+longname2899 => Q_
+longname94 => Qa
+longname3547 => Qaa
+longname148 => Qb
+longname3601 => Qba
+longname202 => Qc
+longname3655 => Qca
+longname256 => Qd
+longname3709 => Qda
+longname310 => Qe
+longname3763 => Qea
+longname363 => Qf
+longname3817 => Qfa
+longname417 => Qg
+longname3871 => Qga
+longname471 => Qh
+longname3925 => Qha
+longname525 => Qi
+longname3979 => Qia
+longname579 => Qj
+longname4033 => Qja
+longname633 => Qk
+longname4087 => Qka
+longname687 => Ql
+longname4141 => Qla
+longname741 => Qm
+longname4195 => Qma
+longname794 => Qn
+longname4249 => Qna
+longname847 => Qo
+longname4303 => Qoa
+longname901 => Qp
+longname4357 => Qpa
+longname955 => Qq
+longname4411 => Qqa
+longname1009 => Qr
+longname4465 => Qra
+longname1063 => Qs
+longname4519 => Qsa
+longname1117 => Qt
+longname4573 => Qta
+longname1171 => Qu
+longname4627 => Qua
+longname1225 => Qv
+longname4681 => Qva
+longname1279 => Qw
+longname4735 => Qwa
+longname1333 => Qx
+longname4789 => Qxa
+longname1387 => Qy
+longname4843 => Qya
+longname1441 => Qz
+longname4897 => Qza
+longname41 => R
+longname2954 => R$
+longname3008 => R0
+longname3062 => R1
+longname3116 => R2
+longname3170 => R3
+longname3224 => R4
+longname3278 => R5
+longname3332 => R6
+longname3386 => R7
+longname3440 => R8
+longname3494 => R9
+longname1496 => RA
+longname4952 => RAa
+longname1550 => RB
+longname1604 => RC
+longname1658 => RD
+longname1712 => RE
+longname1766 => RF
+longname1820 => RG
+longname1874 => RH
+longname1928 => RI
+longname1982 => RJ
+longname2036 => RK
+longname2090 => RL
+longname2144 => RM
+longname2198 => RN
+longname2252 => RO
+longname2306 => RP
+longname2360 => RQ
+longname2414 => RR
+longname2468 => RS
+longname2522 => RT
+longname2576 => RU
+longname2630 => RV
+longname2684 => RW
+longname2738 => RX
+longname2792 => RY
+longname2846 => RZ
+longname2900 => R_
+longname95 => Ra
+longname3548 => Raa
+longname149 => Rb
+longname3602 => Rba
+longname203 => Rc
+longname3656 => Rca
+longname257 => Rd
+longname3710 => Rda
+longname311 => Re
+longname3764 => Rea
+longname364 => Rf
+longname3818 => Rfa
+longname418 => Rg
+longname3872 => Rga
+longname472 => Rh
+longname3926 => Rha
+longname526 => Ri
+longname3980 => Ria
+longname580 => Rj
+longname4034 => Rja
+longname634 => Rk
+longname4088 => Rka
+longname688 => Rl
+longname4142 => Rla
+longname742 => Rm
+longname4196 => Rma
+longname795 => Rn
+longname4250 => Rna
+longname848 => Ro
+longname4304 => Roa
+longname902 => Rp
+longname4358 => Rpa
+longname956 => Rq
+longname4412 => Rqa
+longname1010 => Rr
+longname4466 => Rra
+longname1064 => Rs
+longname4520 => Rsa
+longname1118 => Rt
+longname4574 => Rta
+longname1172 => Ru
+longname4628 => Rua
+longname1226 => Rv
+longname4682 => Rva
+longname1280 => Rw
+longname4736 => Rwa
+longname1334 => Rx
+longname4790 => Rxa
+longname1388 => Ry
+longname4844 => Rya
+longname1442 => Rz
+longname4898 => Rza
+longname42 => S
+longname2955 => S$
+longname3009 => S0
+longname3063 => S1
+longname3117 => S2
+longname3171 => S3
+longname3225 => S4
+longname3279 => S5
+longname3333 => S6
+longname3387 => S7
+longname3441 => S8
+longname3495 => S9
+longname1497 => SA
+longname4953 => SAa
+longname1551 => SB
+longname1605 => SC
+longname1659 => SD
+longname1713 => SE
+longname1767 => SF
+longname1821 => SG
+longname1875 => SH
+longname1929 => SI
+longname1983 => SJ
+longname2037 => SK
+longname2091 => SL
+longname2145 => SM
+longname2199 => SN
+longname2253 => SO
+longname2307 => SP
+longname2361 => SQ
+longname2415 => SR
+longname2469 => SS
+longname2523 => ST
+longname2577 => SU
+longname2631 => SV
+longname2685 => SW
+longname2739 => SX
+longname2793 => SY
+longname2847 => SZ
+longname2901 => S_
+longname96 => Sa
+longname3549 => Saa
+longname150 => Sb
+longname3603 => Sba
+longname204 => Sc
+longname3657 => Sca
+longname258 => Sd
+longname3711 => Sda
+longname312 => Se
+longname3765 => Sea
+longname365 => Sf
+longname3819 => Sfa
+longname419 => Sg
+longname3873 => Sga
+longname473 => Sh
+longname3927 => Sha
+longname527 => Si
+longname3981 => Sia
+longname581 => Sj
+longname4035 => Sja
+longname635 => Sk
+longname4089 => Ska
+longname689 => Sl
+longname4143 => Sla
+longname743 => Sm
+longname4197 => Sma
+longname796 => Sn
+longname4251 => Sna
+longname849 => So
+longname4305 => Soa
+longname903 => Sp
+longname4359 => Spa
+longname957 => Sq
+longname4413 => Sqa
+longname1011 => Sr
+longname4467 => Sra
+longname1065 => Ss
+longname4521 => Ssa
+longname1119 => St
+longname4575 => Sta
+longname1173 => Su
+longname4629 => Sua
+longname1227 => Sv
+longname4683 => Sva
+longname1281 => Sw
+longname4737 => Swa
+longname1335 => Sx
+longname4791 => Sxa
+longname1389 => Sy
+longname4845 => Sya
+longname1443 => Sz
+longname4899 => Sza
+longname43 => T
+longname2956 => T$
+longname3010 => T0
+longname3064 => T1
+longname3118 => T2
+longname3172 => T3
+longname3226 => T4
+longname3280 => T5
+longname3334 => T6
+longname3388 => T7
+longname3442 => T8
+longname3496 => T9
+longname1498 => TA
+longname4954 => TAa
+longname1552 => TB
+longname1606 => TC
+longname1660 => TD
+longname1714 => TE
+longname1768 => TF
+longname1822 => TG
+longname1876 => TH
+longname1930 => TI
+longname1984 => TJ
+longname2038 => TK
+longname2092 => TL
+longname2146 => TM
+longname2200 => TN
+longname2254 => TO
+longname2308 => TP
+longname2362 => TQ
+longname2416 => TR
+longname2470 => TS
+longname2524 => TT
+longname2578 => TU
+longname2632 => TV
+longname2686 => TW
+longname2740 => TX
+longname2794 => TY
+longname2848 => TZ
+longname2902 => T_
+longname97 => Ta
+longname3550 => Taa
+longname151 => Tb
+longname3604 => Tba
+longname205 => Tc
+longname3658 => Tca
+longname259 => Td
+longname3712 => Tda
+longname313 => Te
+longname3766 => Tea
+longname366 => Tf
+longname3820 => Tfa
+longname420 => Tg
+longname3874 => Tga
+longname474 => Th
+longname3928 => Tha
+longname528 => Ti
+longname3982 => Tia
+longname582 => Tj
+longname4036 => Tja
+longname636 => Tk
+longname4090 => Tka
+longname690 => Tl
+longname4144 => Tla
+longname744 => Tm
+longname4198 => Tma
+longname797 => Tn
+longname4252 => Tna
+longname850 => To
+longname4306 => Toa
+longname904 => Tp
+longname4360 => Tpa
+longname958 => Tq
+longname4414 => Tqa
+longname1012 => Tr
+longname4468 => Tra
+longname1066 => Ts
+longname4522 => Tsa
+longname1120 => Tt
+longname4576 => Tta
+longname1174 => Tu
+longname4630 => Tua
+longname1228 => Tv
+longname4684 => Tva
+longname1282 => Tw
+longname4738 => Twa
+longname1336 => Tx
+longname4792 => Txa
+longname1390 => Ty
+longname4846 => Tya
+longname1444 => Tz
+longname4900 => Tza
+longname44 => U
+longname2957 => U$
+longname3011 => U0
+longname3065 => U1
+longname3119 => U2
+longname3173 => U3
+longname3227 => U4
+longname3281 => U5
+longname3335 => U6
+longname3389 => U7
+longname3443 => U8
+longname3497 => U9
+longname1499 => UA
+longname4955 => UAa
+longname1553 => UB
+longname1607 => UC
+longname1661 => UD
+longname1715 => UE
+longname1769 => UF
+longname1823 => UG
+longname1877 => UH
+longname1931 => UI
+longname1985 => UJ
+longname2039 => UK
+longname2093 => UL
+longname2147 => UM
+longname2201 => UN
+longname2255 => UO
+longname2309 => UP
+longname2363 => UQ
+longname2417 => UR
+longname2471 => US
+longname2525 => UT
+longname2579 => UU
+longname2633 => UV
+longname2687 => UW
+longname2741 => UX
+longname2795 => UY
+longname2849 => UZ
+longname2903 => U_
+longname98 => Ua
+longname3551 => Uaa
+longname152 => Ub
+longname3605 => Uba
+longname206 => Uc
+longname3659 => Uca
+longname260 => Ud
+longname3713 => Uda
+longname314 => Ue
+longname3767 => Uea
+longname367 => Uf
+longname3821 => Ufa
+longname421 => Ug
+longname3875 => Uga
+longname475 => Uh
+longname3929 => Uha
+longname529 => Ui
+longname3983 => Uia
+longname583 => Uj
+longname4037 => Uja
+longname637 => Uk
+longname4091 => Uka
+longname691 => Ul
+longname4145 => Ula
+longname745 => Um
+longname4199 => Uma
+longname798 => Un
+longname4253 => Una
+longname851 => Uo
+longname4307 => Uoa
+longname905 => Up
+longname4361 => Upa
+longname959 => Uq
+longname4415 => Uqa
+longname1013 => Ur
+longname4469 => Ura
+longname1067 => Us
+longname4523 => Usa
+longname1121 => Ut
+longname4577 => Uta
+longname1175 => Uu
+longname4631 => Uua
+longname1229 => Uv
+longname4685 => Uva
+longname1283 => Uw
+longname4739 => Uwa
+longname1337 => Ux
+longname4793 => Uxa
+longname1391 => Uy
+longname4847 => Uya
+longname1445 => Uz
+longname4901 => Uza
+longname45 => V
+longname2958 => V$
+longname3012 => V0
+longname3066 => V1
+longname3120 => V2
+longname3174 => V3
+longname3228 => V4
+longname3282 => V5
+longname3336 => V6
+longname3390 => V7
+longname3444 => V8
+longname3498 => V9
+longname1500 => VA
+longname4956 => VAa
+longname1554 => VB
+longname1608 => VC
+longname1662 => VD
+longname1716 => VE
+longname1770 => VF
+longname1824 => VG
+longname1878 => VH
+longname1932 => VI
+longname1986 => VJ
+longname2040 => VK
+longname2094 => VL
+longname2148 => VM
+longname2202 => VN
+longname2256 => VO
+longname2310 => VP
+longname2364 => VQ
+longname2418 => VR
+longname2472 => VS
+longname2526 => VT
+longname2580 => VU
+longname2634 => VV
+longname2688 => VW
+longname2742 => VX
+longname2796 => VY
+longname2850 => VZ
+longname2904 => V_
+longname99 => Va
+longname3552 => Vaa
+longname153 => Vb
+longname3606 => Vba
+longname207 => Vc
+longname3660 => Vca
+longname261 => Vd
+longname3714 => Vda
+longname315 => Ve
+longname3768 => Vea
+longname368 => Vf
+longname3822 => Vfa
+longname422 => Vg
+longname3876 => Vga
+longname476 => Vh
+longname3930 => Vha
+longname530 => Vi
+longname3984 => Via
+longname584 => Vj
+longname4038 => Vja
+longname638 => Vk
+longname4092 => Vka
+longname692 => Vl
+longname4146 => Vla
+longname746 => Vm
+longname4200 => Vma
+longname799 => Vn
+longname4254 => Vna
+longname852 => Vo
+longname4308 => Voa
+longname906 => Vp
+longname4362 => Vpa
+longname960 => Vq
+longname4416 => Vqa
+longname1014 => Vr
+longname4470 => Vra
+longname1068 => Vs
+longname4524 => Vsa
+longname1122 => Vt
+longname4578 => Vta
+longname1176 => Vu
+longname4632 => Vua
+longname1230 => Vv
+longname4686 => Vva
+longname1284 => Vw
+longname4740 => Vwa
+longname1338 => Vx
+longname4794 => Vxa
+longname1392 => Vy
+longname4848 => Vya
+longname1446 => Vz
+longname4902 => Vza
+longname46 => W
+longname2959 => W$
+longname3013 => W0
+longname3067 => W1
+longname3121 => W2
+longname3175 => W3
+longname3229 => W4
+longname3283 => W5
+longname3337 => W6
+longname3391 => W7
+longname3445 => W8
+longname3499 => W9
+longname1501 => WA
+longname4957 => WAa
+longname1555 => WB
+longname1609 => WC
+longname1663 => WD
+longname1717 => WE
+longname1771 => WF
+longname1825 => WG
+longname1879 => WH
+longname1933 => WI
+longname1987 => WJ
+longname2041 => WK
+longname2095 => WL
+longname2149 => WM
+longname2203 => WN
+longname2257 => WO
+longname2311 => WP
+longname2365 => WQ
+longname2419 => WR
+longname2473 => WS
+longname2527 => WT
+longname2581 => WU
+longname2635 => WV
+longname2689 => WW
+longname2743 => WX
+longname2797 => WY
+longname2851 => WZ
+longname2905 => W_
+longname100 => Wa
+longname3553 => Waa
+longname154 => Wb
+longname3607 => Wba
+longname208 => Wc
+longname3661 => Wca
+longname262 => Wd
+longname3715 => Wda
+longname316 => We
+longname3769 => Wea
+longname369 => Wf
+longname3823 => Wfa
+longname423 => Wg
+longname3877 => Wga
+longname477 => Wh
+longname3931 => Wha
+longname531 => Wi
+longname3985 => Wia
+longname585 => Wj
+longname4039 => Wja
+longname639 => Wk
+longname4093 => Wka
+longname693 => Wl
+longname4147 => Wla
+longname747 => Wm
+longname4201 => Wma
+longname800 => Wn
+longname4255 => Wna
+longname853 => Wo
+longname4309 => Woa
+longname907 => Wp
+longname4363 => Wpa
+longname961 => Wq
+longname4417 => Wqa
+longname1015 => Wr
+longname4471 => Wra
+longname1069 => Ws
+longname4525 => Wsa
+longname1123 => Wt
+longname4579 => Wta
+longname1177 => Wu
+longname4633 => Wua
+longname1231 => Wv
+longname4687 => Wva
+longname1285 => Ww
+longname4741 => Wwa
+longname1339 => Wx
+longname4795 => Wxa
+longname1393 => Wy
+longname4849 => Wya
+longname1447 => Wz
+longname4903 => Wza
+longname47 => X
+longname2960 => X$
+longname3014 => X0
+longname3068 => X1
+longname3122 => X2
+longname3176 => X3
+longname3230 => X4
+longname3284 => X5
+longname3338 => X6
+longname3392 => X7
+longname3446 => X8
+longname3500 => X9
+longname1502 => XA
+longname4958 => XAa
+longname1556 => XB
+longname1610 => XC
+longname1664 => XD
+longname1718 => XE
+longname1772 => XF
+longname1826 => XG
+longname1880 => XH
+longname1934 => XI
+longname1988 => XJ
+longname2042 => XK
+longname2096 => XL
+longname2150 => XM
+longname2204 => XN
+longname2258 => XO
+longname2312 => XP
+longname2366 => XQ
+longname2420 => XR
+longname2474 => XS
+longname2528 => XT
+longname2582 => XU
+longname2636 => XV
+longname2690 => XW
+longname2744 => XX
+longname2798 => XY
+longname2852 => XZ
+longname2906 => X_
+longname101 => Xa
+longname3554 => Xaa
+longname155 => Xb
+longname3608 => Xba
+longname209 => Xc
+longname3662 => Xca
+longname263 => Xd
+longname3716 => Xda
+longname317 => Xe
+longname3770 => Xea
+longname370 => Xf
+longname3824 => Xfa
+longname424 => Xg
+longname3878 => Xga
+longname478 => Xh
+longname3932 => Xha
+longname532 => Xi
+longname3986 => Xia
+longname586 => Xj
+longname4040 => Xja
+longname640 => Xk
+longname4094 => Xka
+longname694 => Xl
+longname4148 => Xla
+longname748 => Xm
+longname4202 => Xma
+longname801 => Xn
+longname4256 => Xna
+longname854 => Xo
+longname4310 => Xoa
+longname908 => Xp
+longname4364 => Xpa
+longname962 => Xq
+longname4418 => Xqa
+longname1016 => Xr
+longname4472 => Xra
+longname1070 => Xs
+longname4526 => Xsa
+longname1124 => Xt
+longname4580 => Xta
+longname1178 => Xu
+longname4634 => Xua
+longname1232 => Xv
+longname4688 => Xva
+longname1286 => Xw
+longname4742 => Xwa
+longname1340 => Xx
+longname4796 => Xxa
+longname1394 => Xy
+longname4850 => Xya
+longname1448 => Xz
+longname4904 => Xza
+longname48 => Y
+longname2961 => Y$
+longname3015 => Y0
+longname3069 => Y1
+longname3123 => Y2
+longname3177 => Y3
+longname3231 => Y4
+longname3285 => Y5
+longname3339 => Y6
+longname3393 => Y7
+longname3447 => Y8
+longname3501 => Y9
+longname1503 => YA
+longname4959 => YAa
+longname1557 => YB
+longname1611 => YC
+longname1665 => YD
+longname1719 => YE
+longname1773 => YF
+longname1827 => YG
+longname1881 => YH
+longname1935 => YI
+longname1989 => YJ
+longname2043 => YK
+longname2097 => YL
+longname2151 => YM
+longname2205 => YN
+longname2259 => YO
+longname2313 => YP
+longname2367 => YQ
+longname2421 => YR
+longname2475 => YS
+longname2529 => YT
+longname2583 => YU
+longname2637 => YV
+longname2691 => YW
+longname2745 => YX
+longname2799 => YY
+longname2853 => YZ
+longname2907 => Y_
+longname102 => Ya
+longname3555 => Yaa
+longname156 => Yb
+longname3609 => Yba
+longname210 => Yc
+longname3663 => Yca
+longname264 => Yd
+longname3717 => Yda
+longname318 => Ye
+longname3771 => Yea
+longname371 => Yf
+longname3825 => Yfa
+longname425 => Yg
+longname3879 => Yga
+longname479 => Yh
+longname3933 => Yha
+longname533 => Yi
+longname3987 => Yia
+longname587 => Yj
+longname4041 => Yja
+longname641 => Yk
+longname4095 => Yka
+longname695 => Yl
+longname4149 => Yla
+longname749 => Ym
+longname4203 => Yma
+longname802 => Yn
+longname4257 => Yna
+longname855 => Yo
+longname4311 => Yoa
+longname909 => Yp
+longname4365 => Ypa
+longname963 => Yq
+longname4419 => Yqa
+longname1017 => Yr
+longname4473 => Yra
+longname1071 => Ys
+longname4527 => Ysa
+longname1125 => Yt
+longname4581 => Yta
+longname1179 => Yu
+longname4635 => Yua
+longname1233 => Yv
+longname4689 => Yva
+longname1287 => Yw
+longname4743 => Ywa
+longname1341 => Yx
+longname4797 => Yxa
+longname1395 => Yy
+longname4851 => Yya
+longname1449 => Yz
+longname4905 => Yza
+longname49 => Z
+longname2962 => Z$
+longname3016 => Z0
+longname3070 => Z1
+longname3124 => Z2
+longname3178 => Z3
+longname3232 => Z4
+longname3286 => Z5
+longname3340 => Z6
+longname3394 => Z7
+longname3448 => Z8
+longname3502 => Z9
+longname1504 => ZA
+longname4960 => ZAa
+longname1558 => ZB
+longname1612 => ZC
+longname1666 => ZD
+longname1720 => ZE
+longname1774 => ZF
+longname1828 => ZG
+longname1882 => ZH
+longname1936 => ZI
+longname1990 => ZJ
+longname2044 => ZK
+longname2098 => ZL
+longname2152 => ZM
+longname2206 => ZN
+longname2260 => ZO
+longname2314 => ZP
+longname2368 => ZQ
+longname2422 => ZR
+longname2476 => ZS
+longname2530 => ZT
+longname2584 => ZU
+longname2638 => ZV
+longname2692 => ZW
+longname2746 => ZX
+longname2800 => ZY
+longname2854 => ZZ
+longname2908 => Z_
+longname103 => Za
+longname3556 => Zaa
+longname157 => Zb
+longname3610 => Zba
+longname211 => Zc
+longname3664 => Zca
+longname265 => Zd
+longname3718 => Zda
+longname319 => Ze
+longname3772 => Zea
+longname372 => Zf
+longname3826 => Zfa
+longname426 => Zg
+longname3880 => Zga
+longname480 => Zh
+longname3934 => Zha
+longname534 => Zi
+longname3988 => Zia
+longname588 => Zj
+longname4042 => Zja
+longname642 => Zk
+longname4096 => Zka
+longname696 => Zl
+longname4150 => Zla
+longname750 => Zm
+longname4204 => Zma
+longname803 => Zn
+longname4258 => Zna
+longname856 => Zo
+longname4312 => Zoa
+longname910 => Zp
+longname4366 => Zpa
+longname964 => Zq
+longname4420 => Zqa
+longname1018 => Zr
+longname4474 => Zra
+longname1072 => Zs
+longname4528 => Zsa
+longname1126 => Zt
+longname4582 => Zta
+longname1180 => Zu
+longname4636 => Zua
+longname1234 => Zv
+longname4690 => Zva
+longname1288 => Zw
+longname4744 => Zwa
+longname1342 => Zx
+longname4798 => Zxa
+longname1396 => Zy
+longname4852 => Zya
+longname1450 => Zz
+longname4906 => Zza
+longname50 => _
+longname2963 => _$
+longname3017 => _0
+longname3071 => _1
+longname3125 => _2
+longname3179 => _3
+longname3233 => _4
+longname3287 => _5
+longname3341 => _6
+longname3395 => _7
+longname3449 => _8
+longname3503 => _9
+longname1505 => _A
+longname4961 => _Aa
+longname1559 => _B
+longname1613 => _C
+longname1667 => _D
+longname1721 => _E
+longname1775 => _F
+longname1829 => _G
+longname1883 => _H
+longname1937 => _I
+longname1991 => _J
+longname2045 => _K
+longname2099 => _L
+longname2153 => _M
+longname2207 => _N
+longname2261 => _O
+longname2315 => _P
+longname2369 => _Q
+longname2423 => _R
+longname2477 => _S
+longname2531 => _T
+longname2585 => _U
+longname2639 => _V
+longname2693 => _W
+longname2747 => _X
+longname2801 => _Y
+longname2855 => _Z
+longname2909 => __
+longname104 => _a
+longname3557 => _aa
+longname158 => _b
+longname3611 => _ba
+longname212 => _c
+longname3665 => _ca
+longname266 => _d
+longname3719 => _da
+longname320 => _e
+longname3773 => _ea
+longname373 => _f
+longname3827 => _fa
+longname427 => _g
+longname3881 => _ga
+longname481 => _h
+longname3935 => _ha
+longname535 => _i
+longname3989 => _ia
+longname589 => _j
+longname4043 => _ja
+longname643 => _k
+longname4097 => _ka
+longname697 => _l
+longname4151 => _la
+longname751 => _m
+longname4205 => _ma
+longname804 => _n
+longname4259 => _na
+longname857 => _o
+longname4313 => _oa
+longname911 => _p
+longname4367 => _pa
+longname965 => _q
+longname4421 => _qa
+longname1019 => _r
+longname4475 => _ra
+longname1073 => _s
+longname4529 => _sa
+longname1127 => _t
+longname4583 => _ta
+longname1181 => _u
+longname4637 => _ua
+longname1235 => _v
+longname4691 => _va
+longname1289 => _w
+longname4745 => _wa
+longname1343 => _x
+longname4799 => _xa
+longname1397 => _y
+longname4853 => _ya
+longname1451 => _z
+longname4907 => _za
+global => a
+longname2911 => a$
+longname2965 => a0
+longname3019 => a1
+longname3073 => a2
+longname3127 => a3
+longname3181 => a4
+longname3235 => a5
+longname3289 => a6
+longname3343 => a7
+longname3397 => a8
+longname3451 => a9
+longname1453 => aA
+longname4909 => aAa
+longname1507 => aB
+longname4963 => aBa
+longname1561 => aC
+longname1615 => aD
+longname1669 => aE
+longname1723 => aF
+longname1777 => aG
+longname1831 => aH
+longname1885 => aI
+longname1939 => aJ
+longname1993 => aK
+longname2047 => aL
+longname2101 => aM
+longname2155 => aN
+longname2209 => aO
+longname2263 => aP
+longname2317 => aQ
+longname2371 => aR
+longname2425 => aS
+longname2479 => aT
+longname2533 => aU
+longname2587 => aV
+longname2641 => aW
+longname2695 => aX
+longname2749 => aY
+longname2803 => aZ
+longname2857 => a_
+longname52 => aa
+longname3505 => aaa
+longname106 => ab
+longname3559 => aba
+longname160 => ac
+longname3613 => aca
+longname214 => ad
+longname3667 => ada
+longname268 => ae
+longname3721 => aea
+longname322 => af
+longname3775 => afa
+longname375 => ag
+longname3829 => aga
+longname429 => ah
+longname3883 => aha
+longname483 => ai
+longname3937 => aia
+longname537 => aj
+longname3991 => aja
+longname591 => ak
+longname4045 => aka
+longname645 => al
+longname4099 => ala
+longname699 => am
+longname4153 => ama
+longname753 => an
+longname4207 => ana
+longname806 => ao
+longname4261 => aoa
+longname859 => ap
+longname4315 => apa
+longname913 => aq
+longname4369 => aqa
+longname967 => ar
+longname4423 => ara
+longname1021 => as
+longname4477 => asa
+longname1075 => at
+longname4531 => ata
+longname1129 => au
+longname4585 => aua
+longname1183 => av
+longname4639 => ava
+longname1237 => aw
+longname4693 => awa
+longname1291 => ax
+longname4747 => axa
+longname1345 => ay
+longname4801 => aya
+longname1399 => az
+longname4855 => aza
+__memory_base => b
+longname2912 => b$
+longname2966 => b0
+longname3020 => b1
+longname3074 => b2
+longname3128 => b3
+longname3182 => b4
+longname3236 => b5
+longname3290 => b6
+longname3344 => b7
+longname3398 => b8
+longname3452 => b9
+longname1454 => bA
+longname4910 => bAa
+longname1508 => bB
+longname4964 => bBa
+longname1562 => bC
+longname1616 => bD
+longname1670 => bE
+longname1724 => bF
+longname1778 => bG
+longname1832 => bH
+longname1886 => bI
+longname1940 => bJ
+longname1994 => bK
+longname2048 => bL
+longname2102 => bM
+longname2156 => bN
+longname2210 => bO
+longname2264 => bP
+longname2318 => bQ
+longname2372 => bR
+longname2426 => bS
+longname2480 => bT
+longname2534 => bU
+longname2588 => bV
+longname2642 => bW
+longname2696 => bX
+longname2750 => bY
+longname2804 => bZ
+longname2858 => b_
+longname53 => ba
+longname3506 => baa
+longname107 => bb
+longname3560 => bba
+longname161 => bc
+longname3614 => bca
+longname215 => bd
+longname3668 => bda
+longname269 => be
+longname3722 => bea
+longname323 => bf
+longname3776 => bfa
+longname376 => bg
+longname3830 => bga
+longname430 => bh
+longname3884 => bha
+longname484 => bi
+longname3938 => bia
+longname538 => bj
+longname3992 => bja
+longname592 => bk
+longname4046 => bka
+longname646 => bl
+longname4100 => bla
+longname700 => bm
+longname4154 => bma
+longname754 => bn
+longname4208 => bna
+longname807 => bo
+longname4262 => boa
+longname860 => bp
+longname4316 => bpa
+longname914 => bq
+longname4370 => bqa
+longname968 => br
+longname4424 => bra
+longname1022 => bs
+longname4478 => bsa
+longname1076 => bt
+longname4532 => bta
+longname1130 => bu
+longname4586 => bua
+longname1184 => bv
+longname4640 => bva
+longname1238 => bw
+longname4694 => bwa
+longname1292 => bx
+longname4748 => bxa
+longname1346 => by
+longname4802 => bya
+longname1400 => bz
+longname4856 => bza
+__table_base => c
+longname2913 => c$
+longname2967 => c0
+longname3021 => c1
+longname3075 => c2
+longname3129 => c3
+longname3183 => c4
+longname3237 => c5
+longname3291 => c6
+longname3345 => c7
+longname3399 => c8
+longname3453 => c9
+longname1455 => cA
+longname4911 => cAa
+longname1509 => cB
+longname4965 => cBa
+longname1563 => cC
+longname1617 => cD
+longname1671 => cE
+longname1725 => cF
+longname1779 => cG
+longname1833 => cH
+longname1887 => cI
+longname1941 => cJ
+longname1995 => cK
+longname2049 => cL
+longname2103 => cM
+longname2157 => cN
+longname2211 => cO
+longname2265 => cP
+longname2319 => cQ
+longname2373 => cR
+longname2427 => cS
+longname2481 => cT
+longname2535 => cU
+longname2589 => cV
+longname2643 => cW
+longname2697 => cX
+longname2751 => cY
+longname2805 => cZ
+longname2859 => c_
+longname54 => ca
+longname3507 => caa
+longname108 => cb
+longname3561 => cba
+longname162 => cc
+longname3615 => cca
+longname216 => cd
+longname3669 => cda
+longname270 => ce
+longname3723 => cea
+longname324 => cf
+longname3777 => cfa
+longname377 => cg
+longname3831 => cga
+longname431 => ch
+longname3885 => cha
+longname485 => ci
+longname3939 => cia
+longname539 => cj
+longname3993 => cja
+longname593 => ck
+longname4047 => cka
+longname647 => cl
+longname4101 => cla
+longname701 => cm
+longname4155 => cma
+longname755 => cn
+longname4209 => cna
+longname808 => co
+longname4263 => coa
+longname861 => cp
+longname4317 => cpa
+longname915 => cq
+longname4371 => cqa
+longname969 => cr
+longname4425 => cra
+longname1023 => cs
+longname4479 => csa
+longname1077 => ct
+longname4533 => cta
+longname1131 => cu
+longname4587 => cua
+longname1185 => cv
+longname4641 => cva
+longname1239 => cw
+longname4695 => cwa
+longname1293 => cx
+longname4749 => cxa
+longname1347 => cy
+longname4803 => cya
+longname1401 => cz
+longname4857 => cza
+longname1 => d
+longname2914 => d$
+longname2968 => d0
+longname3022 => d1
+longname3076 => d2
+longname3130 => d3
+longname3184 => d4
+longname3238 => d5
+longname3292 => d6
+longname3346 => d7
+longname3400 => d8
+longname3454 => d9
+longname1456 => dA
+longname4912 => dAa
+longname1510 => dB
+longname4966 => dBa
+longname1564 => dC
+longname1618 => dD
+longname1672 => dE
+longname1726 => dF
+longname1780 => dG
+longname1834 => dH
+longname1888 => dI
+longname1942 => dJ
+longname1996 => dK
+longname2050 => dL
+longname2104 => dM
+longname2158 => dN
+longname2212 => dO
+longname2266 => dP
+longname2320 => dQ
+longname2374 => dR
+longname2428 => dS
+longname2482 => dT
+longname2536 => dU
+longname2590 => dV
+longname2644 => dW
+longname2698 => dX
+longname2752 => dY
+longname2806 => dZ
+longname2860 => d_
+longname55 => da
+longname3508 => daa
+longname109 => db
+longname3562 => dba
+longname163 => dc
+longname3616 => dca
+longname217 => dd
+longname3670 => dda
+longname271 => de
+longname3724 => dea
+longname325 => df
+longname3778 => dfa
+longname378 => dg
+longname3832 => dga
+longname432 => dh
+longname3886 => dha
+longname486 => di
+longname3940 => dia
+longname540 => dj
+longname3994 => dja
+longname594 => dk
+longname4048 => dka
+longname648 => dl
+longname4102 => dla
+longname702 => dm
+longname4156 => dma
+longname756 => dn
+longname4210 => dna
+longname4264 => doa
+longname862 => dp
+longname4318 => dpa
+longname916 => dq
+longname4372 => dqa
+longname970 => dr
+longname4426 => dra
+longname1024 => ds
+longname4480 => dsa
+longname1078 => dt
+longname4534 => dta
+longname1132 => du
+longname4588 => dua
+longname1186 => dv
+longname4642 => dva
+longname1240 => dw
+longname4696 => dwa
+longname1294 => dx
+longname4750 => dxa
+longname1348 => dy
+longname4804 => dya
+longname1402 => dz
+longname4858 => dza
+longname2 => e
+longname2915 => e$
+longname2969 => e0
+longname3023 => e1
+longname3077 => e2
+longname3131 => e3
+longname3185 => e4
+longname3239 => e5
+longname3293 => e6
+longname3347 => e7
+longname3401 => e8
+longname3455 => e9
+longname1457 => eA
+longname4913 => eAa
+longname1511 => eB
+longname4967 => eBa
+longname1565 => eC
+longname1619 => eD
+longname1673 => eE
+longname1727 => eF
+longname1781 => eG
+longname1835 => eH
+longname1889 => eI
+longname1943 => eJ
+longname1997 => eK
+longname2051 => eL
+longname2105 => eM
+longname2159 => eN
+longname2213 => eO
+longname2267 => eP
+longname2321 => eQ
+longname2375 => eR
+longname2429 => eS
+longname2483 => eT
+longname2537 => eU
+longname2591 => eV
+longname2645 => eW
+longname2699 => eX
+longname2753 => eY
+longname2807 => eZ
+longname2861 => e_
+longname56 => ea
+longname3509 => eaa
+longname110 => eb
+longname3563 => eba
+longname164 => ec
+longname3617 => eca
+longname218 => ed
+longname3671 => eda
+longname272 => ee
+longname3725 => eea
+longname326 => ef
+longname3779 => efa
+longname379 => eg
+longname3833 => ega
+longname433 => eh
+longname3887 => eha
+longname487 => ei
+longname3941 => eia
+longname541 => ej
+longname3995 => eja
+longname595 => ek
+longname4049 => eka
+longname649 => el
+longname4103 => ela
+longname703 => em
+longname4157 => ema
+longname757 => en
+longname4211 => ena
+longname809 => eo
+longname4265 => eoa
+longname863 => ep
+longname4319 => epa
+longname917 => eq
+longname4373 => eqa
+longname971 => er
+longname4427 => era
+longname1025 => es
+longname4481 => esa
+longname1079 => et
+longname4535 => eta
+longname1133 => eu
+longname4589 => eua
+longname1187 => ev
+longname4643 => eva
+longname1241 => ew
+longname4697 => ewa
+longname1295 => ex
+longname4751 => exa
+longname1349 => ey
+longname4805 => eya
+longname1403 => ez
+longname4859 => eza
+longname3 => f
+longname2916 => f$
+longname2970 => f0
+longname3024 => f1
+longname3078 => f2
+longname3132 => f3
+longname3186 => f4
+longname3240 => f5
+longname3294 => f6
+longname3348 => f7
+longname3402 => f8
+longname3456 => f9
+longname1458 => fA
+longname4914 => fAa
+longname1512 => fB
+longname4968 => fBa
+longname1566 => fC
+longname1620 => fD
+longname1674 => fE
+longname1728 => fF
+longname1782 => fG
+longname1836 => fH
+longname1890 => fI
+longname1944 => fJ
+longname1998 => fK
+longname2052 => fL
+longname2106 => fM
+longname2160 => fN
+longname2214 => fO
+longname2268 => fP
+longname2322 => fQ
+longname2376 => fR
+longname2430 => fS
+longname2484 => fT
+longname2538 => fU
+longname2592 => fV
+longname2646 => fW
+longname2700 => fX
+longname2754 => fY
+longname2808 => fZ
+longname2862 => f_
+longname57 => fa
+longname3510 => faa
+longname111 => fb
+longname3564 => fba
+longname165 => fc
+longname3618 => fca
+longname219 => fd
+longname3672 => fda
+longname273 => fe
+longname3726 => fea
+longname327 => ff
+longname3780 => ffa
+longname380 => fg
+longname3834 => fga
+longname434 => fh
+longname3888 => fha
+longname488 => fi
+longname3942 => fia
+longname542 => fj
+longname3996 => fja
+longname596 => fk
+longname4050 => fka
+longname650 => fl
+longname4104 => fla
+longname704 => fm
+longname4158 => fma
+longname758 => fn
+longname4212 => fna
+longname810 => fo
+longname4266 => foa
+longname864 => fp
+longname4320 => fpa
+longname918 => fq
+longname4374 => fqa
+longname972 => fr
+longname4428 => fra
+longname1026 => fs
+longname4482 => fsa
+longname1080 => ft
+longname4536 => fta
+longname1134 => fu
+longname4590 => fua
+longname1188 => fv
+longname4644 => fva
+longname1242 => fw
+longname4698 => fwa
+longname1296 => fx
+longname4752 => fxa
+longname1350 => fy
+longname4806 => fya
+longname1404 => fz
+longname4860 => fza
+longname4 => g
+longname2917 => g$
+longname2971 => g0
+longname3025 => g1
+longname3079 => g2
+longname3133 => g3
+longname3187 => g4
+longname3241 => g5
+longname3295 => g6
+longname3349 => g7
+longname3403 => g8
+longname3457 => g9
+longname1459 => gA
+longname4915 => gAa
+longname1513 => gB
+longname4969 => gBa
+longname1567 => gC
+longname1621 => gD
+longname1675 => gE
+longname1729 => gF
+longname1783 => gG
+longname1837 => gH
+longname1891 => gI
+longname1945 => gJ
+longname1999 => gK
+longname2053 => gL
+longname2107 => gM
+longname2161 => gN
+longname2215 => gO
+longname2269 => gP
+longname2323 => gQ
+longname2377 => gR
+longname2431 => gS
+longname2485 => gT
+longname2539 => gU
+longname2593 => gV
+longname2647 => gW
+longname2701 => gX
+longname2755 => gY
+longname2809 => gZ
+longname2863 => g_
+longname58 => ga
+longname3511 => gaa
+longname112 => gb
+longname3565 => gba
+longname166 => gc
+longname3619 => gca
+longname220 => gd
+longname3673 => gda
+longname274 => ge
+longname3727 => gea
+longname328 => gf
+longname3781 => gfa
+longname381 => gg
+longname3835 => gga
+longname435 => gh
+longname3889 => gha
+longname489 => gi
+longname3943 => gia
+longname543 => gj
+longname3997 => gja
+longname597 => gk
+longname4051 => gka
+longname651 => gl
+longname4105 => gla
+longname705 => gm
+longname4159 => gma
+longname759 => gn
+longname4213 => gna
+longname811 => go
+longname4267 => goa
+longname865 => gp
+longname4321 => gpa
+longname919 => gq
+longname4375 => gqa
+longname973 => gr
+longname4429 => gra
+longname1027 => gs
+longname4483 => gsa
+longname1081 => gt
+longname4537 => gta
+longname1135 => gu
+longname4591 => gua
+longname1189 => gv
+longname4645 => gva
+longname1243 => gw
+longname4699 => gwa
+longname1297 => gx
+longname4753 => gxa
+longname1351 => gy
+longname4807 => gya
+longname1405 => gz
+longname4861 => gza
+longname5 => h
+longname2918 => h$
+longname2972 => h0
+longname3026 => h1
+longname3080 => h2
+longname3134 => h3
+longname3188 => h4
+longname3242 => h5
+longname3296 => h6
+longname3350 => h7
+longname3404 => h8
+longname3458 => h9
+longname1460 => hA
+longname4916 => hAa
+longname1514 => hB
+longname4970 => hBa
+longname1568 => hC
+longname1622 => hD
+longname1676 => hE
+longname1730 => hF
+longname1784 => hG
+longname1838 => hH
+longname1892 => hI
+longname1946 => hJ
+longname2000 => hK
+longname2054 => hL
+longname2108 => hM
+longname2162 => hN
+longname2216 => hO
+longname2270 => hP
+longname2324 => hQ
+longname2378 => hR
+longname2432 => hS
+longname2486 => hT
+longname2540 => hU
+longname2594 => hV
+longname2648 => hW
+longname2702 => hX
+longname2756 => hY
+longname2810 => hZ
+longname2864 => h_
+longname59 => ha
+longname3512 => haa
+longname113 => hb
+longname3566 => hba
+longname167 => hc
+longname3620 => hca
+longname221 => hd
+longname3674 => hda
+longname275 => he
+longname3728 => hea
+longname329 => hf
+longname3782 => hfa
+longname382 => hg
+longname3836 => hga
+longname436 => hh
+longname3890 => hha
+longname490 => hi
+longname3944 => hia
+longname544 => hj
+longname3998 => hja
+longname598 => hk
+longname4052 => hka
+longname652 => hl
+longname4106 => hla
+longname706 => hm
+longname4160 => hma
+longname760 => hn
+longname4214 => hna
+longname812 => ho
+longname4268 => hoa
+longname866 => hp
+longname4322 => hpa
+longname920 => hq
+longname4376 => hqa
+longname974 => hr
+longname4430 => hra
+longname1028 => hs
+longname4484 => hsa
+longname1082 => ht
+longname4538 => hta
+longname1136 => hu
+longname4592 => hua
+longname1190 => hv
+longname4646 => hva
+longname1244 => hw
+longname4700 => hwa
+longname1298 => hx
+longname4754 => hxa
+longname1352 => hy
+longname4808 => hya
+longname1406 => hz
+longname4862 => hza
+longname6 => i
+longname2919 => i$
+longname2973 => i0
+longname3027 => i1
+longname3081 => i2
+longname3135 => i3
+longname3189 => i4
+longname3243 => i5
+longname3297 => i6
+longname3351 => i7
+longname3405 => i8
+longname3459 => i9
+longname1461 => iA
+longname4917 => iAa
+longname1515 => iB
+longname4971 => iBa
+longname1569 => iC
+longname1623 => iD
+longname1677 => iE
+longname1731 => iF
+longname1785 => iG
+longname1839 => iH
+longname1893 => iI
+longname1947 => iJ
+longname2001 => iK
+longname2055 => iL
+longname2109 => iM
+longname2163 => iN
+longname2217 => iO
+longname2271 => iP
+longname2325 => iQ
+longname2379 => iR
+longname2433 => iS
+longname2487 => iT
+longname2541 => iU
+longname2595 => iV
+longname2649 => iW
+longname2703 => iX
+longname2757 => iY
+longname2811 => iZ
+longname2865 => i_
+longname60 => ia
+longname3513 => iaa
+longname114 => ib
+longname3567 => iba
+longname168 => ic
+longname3621 => ica
+longname222 => id
+longname3675 => ida
+longname276 => ie
+longname3729 => iea
+longname3783 => ifa
+longname383 => ig
+longname3837 => iga
+longname437 => ih
+longname3891 => iha
+longname491 => ii
+longname3945 => iia
+longname545 => ij
+longname3999 => ija
+longname599 => ik
+longname4053 => ika
+longname653 => il
+longname4107 => ila
+longname707 => im
+longname4161 => ima
+longname4215 => ina
+longname813 => io
+longname4269 => ioa
+longname867 => ip
+longname4323 => ipa
+longname921 => iq
+longname4377 => iqa
+longname975 => ir
+longname4431 => ira
+longname1029 => is
+longname4485 => isa
+longname1083 => it
+longname4539 => ita
+longname1137 => iu
+longname4593 => iua
+longname1191 => iv
+longname4647 => iva
+longname1245 => iw
+longname4701 => iwa
+longname1299 => ix
+longname4755 => ixa
+longname1353 => iy
+longname4809 => iya
+longname1407 => iz
+longname4863 => iza
+longname7 => j
+longname2920 => j$
+longname2974 => j0
+longname3028 => j1
+longname3082 => j2
+longname3136 => j3
+longname3190 => j4
+longname3244 => j5
+longname3298 => j6
+longname3352 => j7
+longname3406 => j8
+longname3460 => j9
+longname1462 => jA
+longname4918 => jAa
+longname1516 => jB
+longname4972 => jBa
+longname1570 => jC
+longname1624 => jD
+longname1678 => jE
+longname1732 => jF
+longname1786 => jG
+longname1840 => jH
+longname1894 => jI
+longname1948 => jJ
+longname2002 => jK
+longname2056 => jL
+longname2110 => jM
+longname2164 => jN
+longname2218 => jO
+longname2272 => jP
+longname2326 => jQ
+longname2380 => jR
+longname2434 => jS
+longname2488 => jT
+longname2542 => jU
+longname2596 => jV
+longname2650 => jW
+longname2704 => jX
+longname2758 => jY
+longname2812 => jZ
+longname2866 => j_
+longname61 => ja
+longname3514 => jaa
+longname115 => jb
+longname3568 => jba
+longname169 => jc
+longname3622 => jca
+longname223 => jd
+longname3676 => jda
+longname277 => je
+longname3730 => jea
+longname330 => jf
+longname3784 => jfa
+longname384 => jg
+longname3838 => jga
+longname438 => jh
+longname3892 => jha
+longname492 => ji
+longname3946 => jia
+longname546 => jj
+longname4000 => jja
+longname600 => jk
+longname4054 => jka
+longname654 => jl
+longname4108 => jla
+longname708 => jm
+longname4162 => jma
+longname761 => jn
+longname4216 => jna
+longname814 => jo
+longname4270 => joa
+longname868 => jp
+longname4324 => jpa
+longname922 => jq
+longname4378 => jqa
+longname976 => jr
+longname4432 => jra
+longname1030 => js
+longname4486 => jsa
+longname1084 => jt
+longname4540 => jta
+longname1138 => ju
+longname4594 => jua
+longname1192 => jv
+longname4648 => jva
+longname1246 => jw
+longname4702 => jwa
+longname1300 => jx
+longname4756 => jxa
+longname1354 => jy
+longname4810 => jya
+longname1408 => jz
+longname4864 => jza
+longname8 => k
+longname2921 => k$
+longname2975 => k0
+longname3029 => k1
+longname3083 => k2
+longname3137 => k3
+longname3191 => k4
+longname3245 => k5
+longname3299 => k6
+longname3353 => k7
+longname3407 => k8
+longname3461 => k9
+longname1463 => kA
+longname4919 => kAa
+longname1517 => kB
+longname4973 => kBa
+longname1571 => kC
+longname1625 => kD
+longname1679 => kE
+longname1733 => kF
+longname1787 => kG
+longname1841 => kH
+longname1895 => kI
+longname1949 => kJ
+longname2003 => kK
+longname2057 => kL
+longname2111 => kM
+longname2165 => kN
+longname2219 => kO
+longname2273 => kP
+longname2327 => kQ
+longname2381 => kR
+longname2435 => kS
+longname2489 => kT
+longname2543 => kU
+longname2597 => kV
+longname2651 => kW
+longname2705 => kX
+longname2759 => kY
+longname2813 => kZ
+longname2867 => k_
+longname62 => ka
+longname3515 => kaa
+longname116 => kb
+longname3569 => kba
+longname170 => kc
+longname3623 => kca
+longname224 => kd
+longname3677 => kda
+longname278 => ke
+longname3731 => kea
+longname331 => kf
+longname3785 => kfa
+longname385 => kg
+longname3839 => kga
+longname439 => kh
+longname3893 => kha
+longname493 => ki
+longname3947 => kia
+longname547 => kj
+longname4001 => kja
+longname601 => kk
+longname4055 => kka
+longname655 => kl
+longname4109 => kla
+longname709 => km
+longname4163 => kma
+longname762 => kn
+longname4217 => kna
+longname815 => ko
+longname4271 => koa
+longname869 => kp
+longname4325 => kpa
+longname923 => kq
+longname4379 => kqa
+longname977 => kr
+longname4433 => kra
+longname1031 => ks
+longname4487 => ksa
+longname1085 => kt
+longname4541 => kta
+longname1139 => ku
+longname4595 => kua
+longname1193 => kv
+longname4649 => kva
+longname1247 => kw
+longname4703 => kwa
+longname1301 => kx
+longname4757 => kxa
+longname1355 => ky
+longname4811 => kya
+longname1409 => kz
+longname4865 => kza
+longname9 => l
+longname2922 => l$
+longname2976 => l0
+longname3030 => l1
+longname3084 => l2
+longname3138 => l3
+longname3192 => l4
+longname3246 => l5
+longname3300 => l6
+longname3354 => l7
+longname3408 => l8
+longname3462 => l9
+longname1464 => lA
+longname4920 => lAa
+longname1518 => lB
+longname4974 => lBa
+longname1572 => lC
+longname1626 => lD
+longname1680 => lE
+longname1734 => lF
+longname1788 => lG
+longname1842 => lH
+longname1896 => lI
+longname1950 => lJ
+longname2004 => lK
+longname2058 => lL
+longname2112 => lM
+longname2166 => lN
+longname2220 => lO
+longname2274 => lP
+longname2328 => lQ
+longname2382 => lR
+longname2436 => lS
+longname2490 => lT
+longname2544 => lU
+longname2598 => lV
+longname2652 => lW
+longname2706 => lX
+longname2760 => lY
+longname2814 => lZ
+longname2868 => l_
+longname63 => la
+longname3516 => laa
+longname117 => lb
+longname3570 => lba
+longname171 => lc
+longname3624 => lca
+longname225 => ld
+longname3678 => lda
+longname279 => le
+longname3732 => lea
+longname332 => lf
+longname3786 => lfa
+longname386 => lg
+longname3840 => lga
+longname440 => lh
+longname3894 => lha
+longname494 => li
+longname3948 => lia
+longname548 => lj
+longname4002 => lja
+longname602 => lk
+longname4056 => lka
+longname656 => ll
+longname4110 => lla
+longname710 => lm
+longname4164 => lma
+longname763 => ln
+longname4218 => lna
+longname816 => lo
+longname4272 => loa
+longname870 => lp
+longname4326 => lpa
+longname924 => lq
+longname4380 => lqa
+longname978 => lr
+longname4434 => lra
+longname1032 => ls
+longname4488 => lsa
+longname1086 => lt
+longname4542 => lta
+longname1140 => lu
+longname4596 => lua
+longname1194 => lv
+longname4650 => lva
+longname1248 => lw
+longname4704 => lwa
+longname1302 => lx
+longname4758 => lxa
+longname1356 => ly
+longname4812 => lya
+longname1410 => lz
+longname4866 => lza
+longname10 => m
+longname2923 => m$
+longname2977 => m0
+longname3031 => m1
+longname3085 => m2
+longname3139 => m3
+longname3193 => m4
+longname3247 => m5
+longname3301 => m6
+longname3355 => m7
+longname3409 => m8
+longname3463 => m9
+longname1465 => mA
+longname4921 => mAa
+longname1519 => mB
+longname4975 => mBa
+longname1573 => mC
+longname1627 => mD
+longname1681 => mE
+longname1735 => mF
+longname1789 => mG
+longname1843 => mH
+longname1897 => mI
+longname1951 => mJ
+longname2005 => mK
+longname2059 => mL
+longname2113 => mM
+longname2167 => mN
+longname2221 => mO
+longname2275 => mP
+longname2329 => mQ
+longname2383 => mR
+longname2437 => mS
+longname2491 => mT
+longname2545 => mU
+longname2599 => mV
+longname2653 => mW
+longname2707 => mX
+longname2761 => mY
+longname2815 => mZ
+longname2869 => m_
+longname64 => ma
+longname3517 => maa
+longname118 => mb
+longname3571 => mba
+longname172 => mc
+longname3625 => mca
+longname226 => md
+longname3679 => mda
+longname280 => me
+longname3733 => mea
+longname333 => mf
+longname3787 => mfa
+longname387 => mg
+longname3841 => mga
+longname441 => mh
+longname3895 => mha
+longname495 => mi
+longname3949 => mia
+longname549 => mj
+longname4003 => mja
+longname603 => mk
+longname4057 => mka
+longname657 => ml
+longname4111 => mla
+longname711 => mm
+longname4165 => mma
+longname764 => mn
+longname4219 => mna
+longname817 => mo
+longname4273 => moa
+longname871 => mp
+longname4327 => mpa
+longname925 => mq
+longname4381 => mqa
+longname979 => mr
+longname4435 => mra
+longname1033 => ms
+longname4489 => msa
+longname1087 => mt
+longname4543 => mta
+longname1141 => mu
+longname4597 => mua
+longname1195 => mv
+longname4651 => mva
+longname1249 => mw
+longname4705 => mwa
+longname1303 => mx
+longname4759 => mxa
+longname1357 => my
+longname4813 => mya
+longname1411 => mz
+longname4867 => mza
+longname11 => n
+longname2924 => n$
+longname2978 => n0
+longname3032 => n1
+longname3086 => n2
+longname3140 => n3
+longname3194 => n4
+longname3248 => n5
+longname3302 => n6
+longname3356 => n7
+longname3410 => n8
+longname3464 => n9
+longname1466 => nA
+longname4922 => nAa
+longname1520 => nB
+longname4976 => nBa
+longname1574 => nC
+longname1628 => nD
+longname1682 => nE
+longname1736 => nF
+longname1790 => nG
+longname1844 => nH
+longname1898 => nI
+longname1952 => nJ
+longname2006 => nK
+longname2060 => nL
+longname2114 => nM
+longname2168 => nN
+longname2222 => nO
+longname2276 => nP
+longname2330 => nQ
+longname2384 => nR
+longname2438 => nS
+longname2492 => nT
+longname2546 => nU
+longname2600 => nV
+longname2654 => nW
+longname2708 => nX
+longname2762 => nY
+longname2816 => nZ
+longname2870 => n_
+longname65 => na
+longname3518 => naa
+longname119 => nb
+longname3572 => nba
+longname173 => nc
+longname3626 => nca
+longname227 => nd
+longname3680 => nda
+longname281 => ne
+longname3734 => nea
+longname334 => nf
+longname3788 => nfa
+longname388 => ng
+longname3842 => nga
+longname442 => nh
+longname3896 => nha
+longname496 => ni
+longname3950 => nia
+longname550 => nj
+longname4004 => nja
+longname604 => nk
+longname4058 => nka
+longname658 => nl
+longname4112 => nla
+longname712 => nm
+longname4166 => nma
+longname765 => nn
+longname4220 => nna
+longname818 => no
+longname4274 => noa
+longname872 => np
+longname4328 => npa
+longname926 => nq
+longname4382 => nqa
+longname980 => nr
+longname4436 => nra
+longname1034 => ns
+longname4490 => nsa
+longname1088 => nt
+longname4544 => nta
+longname1142 => nu
+longname4598 => nua
+longname1196 => nv
+longname4652 => nva
+longname1250 => nw
+longname4706 => nwa
+longname1304 => nx
+longname4760 => nxa
+longname1358 => ny
+longname4814 => nya
+longname1412 => nz
+longname4868 => nza
+longname12 => o
+longname2925 => o$
+longname2979 => o0
+longname3033 => o1
+longname3087 => o2
+longname3141 => o3
+longname3195 => o4
+longname3249 => o5
+longname3303 => o6
+longname3357 => o7
+longname3411 => o8
+longname3465 => o9
+longname1467 => oA
+longname4923 => oAa
+longname1521 => oB
+longname4977 => oBa
+longname1575 => oC
+longname1629 => oD
+longname1683 => oE
+longname1737 => oF
+longname1791 => oG
+longname1845 => oH
+longname1899 => oI
+longname1953 => oJ
+longname2007 => oK
+longname2061 => oL
+longname2115 => oM
+longname2169 => oN
+longname2223 => oO
+longname2277 => oP
+longname2331 => oQ
+longname2385 => oR
+longname2439 => oS
+longname2493 => oT
+longname2547 => oU
+longname2601 => oV
+longname2655 => oW
+longname2709 => oX
+longname2763 => oY
+longname2817 => oZ
+longname2871 => o_
+longname66 => oa
+longname3519 => oaa
+longname120 => ob
+longname3573 => oba
+longname174 => oc
+longname3627 => oca
+longname228 => od
+longname3681 => oda
+longname282 => oe
+longname3735 => oea
+longname335 => of
+longname3789 => ofa
+longname389 => og
+longname3843 => oga
+longname443 => oh
+longname3897 => oha
+longname497 => oi
+longname3951 => oia
+longname551 => oj
+longname4005 => oja
+longname605 => ok
+longname4059 => oka
+longname659 => ol
+longname4113 => ola
+longname713 => om
+longname4167 => oma
+longname766 => on
+longname4221 => ona
+longname819 => oo
+longname4275 => ooa
+longname873 => op
+longname4329 => opa
+longname927 => oq
+longname4383 => oqa
+longname981 => or
+longname4437 => ora
+longname1035 => os
+longname4491 => osa
+longname1089 => ot
+longname4545 => ota
+longname1143 => ou
+longname4599 => oua
+longname1197 => ov
+longname4653 => ova
+longname1251 => ow
+longname4707 => owa
+longname1305 => ox
+longname4761 => oxa
+longname1359 => oy
+longname4815 => oya
+longname1413 => oz
+longname4869 => oza
+longname13 => p
+longname2926 => p$
+longname2980 => p0
+longname3034 => p1
+longname3088 => p2
+longname3142 => p3
+longname3196 => p4
+longname3250 => p5
+longname3304 => p6
+longname3358 => p7
+longname3412 => p8
+longname3466 => p9
+longname1468 => pA
+longname4924 => pAa
+longname1522 => pB
+longname4978 => pBa
+longname1576 => pC
+longname1630 => pD
+longname1684 => pE
+longname1738 => pF
+longname1792 => pG
+longname1846 => pH
+longname1900 => pI
+longname1954 => pJ
+longname2008 => pK
+longname2062 => pL
+longname2116 => pM
+longname2170 => pN
+longname2224 => pO
+longname2278 => pP
+longname2332 => pQ
+longname2386 => pR
+longname2440 => pS
+longname2494 => pT
+longname2548 => pU
+longname2602 => pV
+longname2656 => pW
+longname2710 => pX
+longname2764 => pY
+longname2818 => pZ
+longname2872 => p_
+longname67 => pa
+longname3520 => paa
+longname121 => pb
+longname3574 => pba
+longname175 => pc
+longname3628 => pca
+longname229 => pd
+longname3682 => pda
+longname283 => pe
+longname3736 => pea
+longname336 => pf
+longname3790 => pfa
+longname390 => pg
+longname3844 => pga
+longname444 => ph
+longname3898 => pha
+longname498 => pi
+longname3952 => pia
+longname552 => pj
+longname4006 => pja
+longname606 => pk
+longname4060 => pka
+longname660 => pl
+longname4114 => pla
+longname714 => pm
+longname4168 => pma
+longname767 => pn
+longname4222 => pna
+longname820 => po
+longname4276 => poa
+longname874 => pp
+longname4330 => ppa
+longname928 => pq
+longname4384 => pqa
+longname982 => pr
+longname4438 => pra
+longname1036 => ps
+longname4492 => psa
+longname1090 => pt
+longname4546 => pta
+longname1144 => pu
+longname4600 => pua
+longname1198 => pv
+longname4654 => pva
+longname1252 => pw
+longname4708 => pwa
+longname1306 => px
+longname4762 => pxa
+longname1360 => py
+longname4816 => pya
+longname1414 => pz
+longname4870 => pza
+longname14 => q
+longname2927 => q$
+longname2981 => q0
+longname3035 => q1
+longname3089 => q2
+longname3143 => q3
+longname3197 => q4
+longname3251 => q5
+longname3305 => q6
+longname3359 => q7
+longname3413 => q8
+longname3467 => q9
+longname1469 => qA
+longname4925 => qAa
+longname1523 => qB
+longname4979 => qBa
+longname1577 => qC
+longname1631 => qD
+longname1685 => qE
+longname1739 => qF
+longname1793 => qG
+longname1847 => qH
+longname1901 => qI
+longname1955 => qJ
+longname2009 => qK
+longname2063 => qL
+longname2117 => qM
+longname2171 => qN
+longname2225 => qO
+longname2279 => qP
+longname2333 => qQ
+longname2387 => qR
+longname2441 => qS
+longname2495 => qT
+longname2549 => qU
+longname2603 => qV
+longname2657 => qW
+longname2711 => qX
+longname2765 => qY
+longname2819 => qZ
+longname2873 => q_
+longname68 => qa
+longname3521 => qaa
+longname122 => qb
+longname3575 => qba
+longname176 => qc
+longname3629 => qca
+longname230 => qd
+longname3683 => qda
+longname284 => qe
+longname3737 => qea
+longname337 => qf
+longname3791 => qfa
+longname391 => qg
+longname3845 => qga
+longname445 => qh
+longname3899 => qha
+longname499 => qi
+longname3953 => qia
+longname553 => qj
+longname4007 => qja
+longname607 => qk
+longname4061 => qka
+longname661 => ql
+longname4115 => qla
+longname715 => qm
+longname4169 => qma
+longname768 => qn
+longname4223 => qna
+longname821 => qo
+longname4277 => qoa
+longname875 => qp
+longname4331 => qpa
+longname929 => qq
+longname4385 => qqa
+longname983 => qr
+longname4439 => qra
+longname1037 => qs
+longname4493 => qsa
+longname1091 => qt
+longname4547 => qta
+longname1145 => qu
+longname4601 => qua
+longname1199 => qv
+longname4655 => qva
+longname1253 => qw
+longname4709 => qwa
+longname1307 => qx
+longname4763 => qxa
+longname1361 => qy
+longname4817 => qya
+longname1415 => qz
+longname4871 => qza
+longname15 => r
+longname2928 => r$
+longname2982 => r0
+longname3036 => r1
+longname3090 => r2
+longname3144 => r3
+longname3198 => r4
+longname3252 => r5
+longname3306 => r6
+longname3360 => r7
+longname3414 => r8
+longname3468 => r9
+longname1470 => rA
+longname4926 => rAa
+longname1524 => rB
+longname4980 => rBa
+longname1578 => rC
+longname1632 => rD
+longname1686 => rE
+longname1740 => rF
+longname1794 => rG
+longname1848 => rH
+longname1902 => rI
+longname1956 => rJ
+longname2010 => rK
+longname2064 => rL
+longname2118 => rM
+longname2172 => rN
+longname2226 => rO
+longname2280 => rP
+longname2334 => rQ
+longname2388 => rR
+longname2442 => rS
+longname2496 => rT
+longname2550 => rU
+longname2604 => rV
+longname2658 => rW
+longname2712 => rX
+longname2766 => rY
+longname2820 => rZ
+longname2874 => r_
+longname69 => ra
+longname3522 => raa
+longname123 => rb
+longname3576 => rba
+longname177 => rc
+longname3630 => rca
+longname231 => rd
+longname3684 => rda
+longname285 => re
+longname3738 => rea
+longname338 => rf
+longname3792 => rfa
+longname392 => rg
+longname3846 => rga
+longname446 => rh
+longname3900 => rha
+longname500 => ri
+longname3954 => ria
+longname554 => rj
+longname4008 => rja
+longname608 => rk
+longname4062 => rka
+longname662 => rl
+longname4116 => rla
+longname716 => rm
+longname4170 => rma
+longname769 => rn
+longname4224 => rna
+longname822 => ro
+longname4278 => roa
+longname876 => rp
+longname4332 => rpa
+longname930 => rq
+longname4386 => rqa
+longname984 => rr
+longname4440 => rra
+longname1038 => rs
+longname4494 => rsa
+longname1092 => rt
+longname4548 => rta
+longname1146 => ru
+longname4602 => rua
+longname1200 => rv
+longname4656 => rva
+longname1254 => rw
+longname4710 => rwa
+longname1308 => rx
+longname4764 => rxa
+longname1362 => ry
+longname4818 => rya
+longname1416 => rz
+longname4872 => rza
+longname16 => s
+longname2929 => s$
+longname2983 => s0
+longname3037 => s1
+longname3091 => s2
+longname3145 => s3
+longname3199 => s4
+longname3253 => s5
+longname3307 => s6
+longname3361 => s7
+longname3415 => s8
+longname3469 => s9
+longname1471 => sA
+longname4927 => sAa
+longname1525 => sB
+longname4981 => sBa
+longname1579 => sC
+longname1633 => sD
+longname1687 => sE
+longname1741 => sF
+longname1795 => sG
+longname1849 => sH
+longname1903 => sI
+longname1957 => sJ
+longname2011 => sK
+longname2065 => sL
+longname2119 => sM
+longname2173 => sN
+longname2227 => sO
+longname2281 => sP
+longname2335 => sQ
+longname2389 => sR
+longname2443 => sS
+longname2497 => sT
+longname2551 => sU
+longname2605 => sV
+longname2659 => sW
+longname2713 => sX
+longname2767 => sY
+longname2821 => sZ
+longname2875 => s_
+longname70 => sa
+longname3523 => saa
+longname124 => sb
+longname3577 => sba
+longname178 => sc
+longname3631 => sca
+longname232 => sd
+longname3685 => sda
+longname286 => se
+longname3739 => sea
+longname339 => sf
+longname3793 => sfa
+longname393 => sg
+longname3847 => sga
+longname447 => sh
+longname3901 => sha
+longname501 => si
+longname3955 => sia
+longname555 => sj
+longname4009 => sja
+longname609 => sk
+longname4063 => ska
+longname663 => sl
+longname4117 => sla
+longname717 => sm
+longname4171 => sma
+longname770 => sn
+longname4225 => sna
+longname823 => so
+longname4279 => soa
+longname877 => sp
+longname4333 => spa
+longname931 => sq
+longname4387 => sqa
+longname985 => sr
+longname4441 => sra
+longname1039 => ss
+longname4495 => ssa
+longname1093 => st
+longname4549 => sta
+longname1147 => su
+longname4603 => sua
+longname1201 => sv
+longname4657 => sva
+longname1255 => sw
+longname4711 => swa
+longname1309 => sx
+longname4765 => sxa
+longname1363 => sy
+longname4819 => sya
+longname1417 => sz
+longname4873 => sza
+longname17 => t
+longname2930 => t$
+longname2984 => t0
+longname3038 => t1
+longname3092 => t2
+longname3146 => t3
+longname3200 => t4
+longname3254 => t5
+longname3308 => t6
+longname3362 => t7
+longname3416 => t8
+longname3470 => t9
+longname1472 => tA
+longname4928 => tAa
+longname1526 => tB
+longname4982 => tBa
+longname1580 => tC
+longname1634 => tD
+longname1688 => tE
+longname1742 => tF
+longname1796 => tG
+longname1850 => tH
+longname1904 => tI
+longname1958 => tJ
+longname2012 => tK
+longname2066 => tL
+longname2120 => tM
+longname2174 => tN
+longname2228 => tO
+longname2282 => tP
+longname2336 => tQ
+longname2390 => tR
+longname2444 => tS
+longname2498 => tT
+longname2552 => tU
+longname2606 => tV
+longname2660 => tW
+longname2714 => tX
+longname2768 => tY
+longname2822 => tZ
+longname2876 => t_
+longname71 => ta
+longname3524 => taa
+longname125 => tb
+longname3578 => tba
+longname179 => tc
+longname3632 => tca
+longname233 => td
+longname3686 => tda
+longname287 => te
+longname3740 => tea
+longname340 => tf
+longname3794 => tfa
+longname394 => tg
+longname3848 => tga
+longname448 => th
+longname3902 => tha
+longname502 => ti
+longname3956 => tia
+longname556 => tj
+longname4010 => tja
+longname610 => tk
+longname4064 => tka
+longname664 => tl
+longname4118 => tla
+longname718 => tm
+longname4172 => tma
+longname771 => tn
+longname4226 => tna
+longname824 => to
+longname4280 => toa
+longname878 => tp
+longname4334 => tpa
+longname932 => tq
+longname4388 => tqa
+longname986 => tr
+longname4442 => tra
+longname1040 => ts
+longname4496 => tsa
+longname1094 => tt
+longname4550 => tta
+longname1148 => tu
+longname4604 => tua
+longname1202 => tv
+longname4658 => tva
+longname1256 => tw
+longname4712 => twa
+longname1310 => tx
+longname4766 => txa
+longname1364 => ty
+longname4820 => tya
+longname1418 => tz
+longname4874 => tza
+longname18 => u
+longname2931 => u$
+longname2985 => u0
+longname3039 => u1
+longname3093 => u2
+longname3147 => u3
+longname3201 => u4
+longname3255 => u5
+longname3309 => u6
+longname3363 => u7
+longname3417 => u8
+longname3471 => u9
+longname1473 => uA
+longname4929 => uAa
+longname1527 => uB
+longname4983 => uBa
+longname1581 => uC
+longname1635 => uD
+longname1689 => uE
+longname1743 => uF
+longname1797 => uG
+longname1851 => uH
+longname1905 => uI
+longname1959 => uJ
+longname2013 => uK
+longname2067 => uL
+longname2121 => uM
+longname2175 => uN
+longname2229 => uO
+longname2283 => uP
+longname2337 => uQ
+longname2391 => uR
+longname2445 => uS
+longname2499 => uT
+longname2553 => uU
+longname2607 => uV
+longname2661 => uW
+longname2715 => uX
+longname2769 => uY
+longname2823 => uZ
+longname2877 => u_
+longname72 => ua
+longname3525 => uaa
+longname126 => ub
+longname3579 => uba
+longname180 => uc
+longname3633 => uca
+longname234 => ud
+longname3687 => uda
+longname288 => ue
+longname3741 => uea
+longname341 => uf
+longname3795 => ufa
+longname395 => ug
+longname3849 => uga
+longname449 => uh
+longname3903 => uha
+longname503 => ui
+longname3957 => uia
+longname557 => uj
+longname4011 => uja
+longname611 => uk
+longname4065 => uka
+longname665 => ul
+longname4119 => ula
+longname719 => um
+longname4173 => uma
+longname772 => un
+longname4227 => una
+longname825 => uo
+longname4281 => uoa
+longname879 => up
+longname4335 => upa
+longname933 => uq
+longname4389 => uqa
+longname987 => ur
+longname4443 => ura
+longname1041 => us
+longname4497 => usa
+longname1095 => ut
+longname4551 => uta
+longname1149 => uu
+longname4605 => uua
+longname1203 => uv
+longname4659 => uva
+longname1257 => uw
+longname4713 => uwa
+longname1311 => ux
+longname4767 => uxa
+longname1365 => uy
+longname4821 => uya
+longname1419 => uz
+longname4875 => uza
+longname19 => v
+longname2932 => v$
+longname2986 => v0
+longname3040 => v1
+longname3094 => v2
+longname3148 => v3
+longname3202 => v4
+longname3256 => v5
+longname3310 => v6
+longname3364 => v7
+longname3418 => v8
+longname3472 => v9
+longname1474 => vA
+longname4930 => vAa
+longname1528 => vB
+longname4984 => vBa
+longname1582 => vC
+longname1636 => vD
+longname1690 => vE
+longname1744 => vF
+longname1798 => vG
+longname1852 => vH
+longname1906 => vI
+longname1960 => vJ
+longname2014 => vK
+longname2068 => vL
+longname2122 => vM
+longname2176 => vN
+longname2230 => vO
+longname2284 => vP
+longname2338 => vQ
+longname2392 => vR
+longname2446 => vS
+longname2500 => vT
+longname2554 => vU
+longname2608 => vV
+longname2662 => vW
+longname2716 => vX
+longname2770 => vY
+longname2824 => vZ
+longname2878 => v_
+longname73 => va
+longname3526 => vaa
+longname127 => vb
+longname3580 => vba
+longname181 => vc
+longname3634 => vca
+longname235 => vd
+longname3688 => vda
+longname289 => ve
+longname3742 => vea
+longname342 => vf
+longname3796 => vfa
+longname396 => vg
+longname3850 => vga
+longname450 => vh
+longname3904 => vha
+longname504 => vi
+longname3958 => via
+longname558 => vj
+longname4012 => vja
+longname612 => vk
+longname4066 => vka
+longname666 => vl
+longname4120 => vla
+longname720 => vm
+longname4174 => vma
+longname773 => vn
+longname4228 => vna
+longname826 => vo
+longname4282 => voa
+longname880 => vp
+longname4336 => vpa
+longname934 => vq
+longname4390 => vqa
+longname988 => vr
+longname4444 => vra
+longname1042 => vs
+longname4498 => vsa
+longname1096 => vt
+longname4552 => vta
+longname1150 => vu
+longname4606 => vua
+longname1204 => vv
+longname4660 => vva
+longname1258 => vw
+longname4714 => vwa
+longname1312 => vx
+longname4768 => vxa
+longname1366 => vy
+longname4822 => vya
+longname1420 => vz
+longname4876 => vza
+longname20 => w
+longname2933 => w$
+longname2987 => w0
+longname3041 => w1
+longname3095 => w2
+longname3149 => w3
+longname3203 => w4
+longname3257 => w5
+longname3311 => w6
+longname3365 => w7
+longname3419 => w8
+longname3473 => w9
+longname1475 => wA
+longname4931 => wAa
+longname1529 => wB
+longname4985 => wBa
+longname1583 => wC
+longname1637 => wD
+longname1691 => wE
+longname1745 => wF
+longname1799 => wG
+longname1853 => wH
+longname1907 => wI
+longname1961 => wJ
+longname2015 => wK
+longname2069 => wL
+longname2123 => wM
+longname2177 => wN
+longname2231 => wO
+longname2285 => wP
+longname2339 => wQ
+longname2393 => wR
+longname2447 => wS
+longname2501 => wT
+longname2555 => wU
+longname2609 => wV
+longname2663 => wW
+longname2717 => wX
+longname2771 => wY
+longname2825 => wZ
+longname2879 => w_
+longname74 => wa
+longname3527 => waa
+longname128 => wb
+longname3581 => wba
+longname182 => wc
+longname3635 => wca
+longname236 => wd
+longname3689 => wda
+longname290 => we
+longname3743 => wea
+longname343 => wf
+longname3797 => wfa
+longname397 => wg
+longname3851 => wga
+longname451 => wh
+longname3905 => wha
+longname505 => wi
+longname3959 => wia
+longname559 => wj
+longname4013 => wja
+longname613 => wk
+longname4067 => wka
+longname667 => wl
+longname4121 => wla
+longname721 => wm
+longname4175 => wma
+longname774 => wn
+longname4229 => wna
+longname827 => wo
+longname4283 => woa
+longname881 => wp
+longname4337 => wpa
+longname935 => wq
+longname4391 => wqa
+longname989 => wr
+longname4445 => wra
+longname1043 => ws
+longname4499 => wsa
+longname1097 => wt
+longname4553 => wta
+longname1151 => wu
+longname4607 => wua
+longname1205 => wv
+longname4661 => wva
+longname1259 => ww
+longname4715 => wwa
+longname1313 => wx
+longname4769 => wxa
+longname1367 => wy
+longname4823 => wya
+longname1421 => wz
+longname4877 => wza
+longname21 => x
+longname2934 => x$
+longname2988 => x0
+longname3042 => x1
+longname3096 => x2
+longname3150 => x3
+longname3204 => x4
+longname3258 => x5
+longname3312 => x6
+longname3366 => x7
+longname3420 => x8
+longname3474 => x9
+longname1476 => xA
+longname4932 => xAa
+longname1530 => xB
+longname4986 => xBa
+longname1584 => xC
+longname1638 => xD
+longname1692 => xE
+longname1746 => xF
+longname1800 => xG
+longname1854 => xH
+longname1908 => xI
+longname1962 => xJ
+longname2016 => xK
+longname2070 => xL
+longname2124 => xM
+longname2178 => xN
+longname2232 => xO
+longname2286 => xP
+longname2340 => xQ
+longname2394 => xR
+longname2448 => xS
+longname2502 => xT
+longname2556 => xU
+longname2610 => xV
+longname2664 => xW
+longname2718 => xX
+longname2772 => xY
+longname2826 => xZ
+longname2880 => x_
+longname75 => xa
+longname3528 => xaa
+longname129 => xb
+longname3582 => xba
+longname183 => xc
+longname3636 => xca
+longname237 => xd
+longname3690 => xda
+longname291 => xe
+longname3744 => xea
+longname344 => xf
+longname3798 => xfa
+longname398 => xg
+longname3852 => xga
+longname452 => xh
+longname3906 => xha
+longname506 => xi
+longname3960 => xia
+longname560 => xj
+longname4014 => xja
+longname614 => xk
+longname4068 => xka
+longname668 => xl
+longname4122 => xla
+longname722 => xm
+longname4176 => xma
+longname775 => xn
+longname4230 => xna
+longname828 => xo
+longname4284 => xoa
+longname882 => xp
+longname4338 => xpa
+longname936 => xq
+longname4392 => xqa
+longname990 => xr
+longname4446 => xra
+longname1044 => xs
+longname4500 => xsa
+longname1098 => xt
+longname4554 => xta
+longname1152 => xu
+longname4608 => xua
+longname1206 => xv
+longname4662 => xva
+longname1260 => xw
+longname4716 => xwa
+longname1314 => xx
+longname4770 => xxa
+longname1368 => xy
+longname4824 => xya
+longname1422 => xz
+longname4878 => xza
+longname22 => y
+longname2935 => y$
+longname2989 => y0
+longname3043 => y1
+longname3097 => y2
+longname3151 => y3
+longname3205 => y4
+longname3259 => y5
+longname3313 => y6
+longname3367 => y7
+longname3421 => y8
+longname3475 => y9
+longname1477 => yA
+longname4933 => yAa
+longname1531 => yB
+longname4987 => yBa
+longname1585 => yC
+longname1639 => yD
+longname1693 => yE
+longname1747 => yF
+longname1801 => yG
+longname1855 => yH
+longname1909 => yI
+longname1963 => yJ
+longname2017 => yK
+longname2071 => yL
+longname2125 => yM
+longname2179 => yN
+longname2233 => yO
+longname2287 => yP
+longname2341 => yQ
+longname2395 => yR
+longname2449 => yS
+longname2503 => yT
+longname2557 => yU
+longname2611 => yV
+longname2665 => yW
+longname2719 => yX
+longname2773 => yY
+longname2827 => yZ
+longname2881 => y_
+longname76 => ya
+longname3529 => yaa
+longname130 => yb
+longname3583 => yba
+longname184 => yc
+longname3637 => yca
+longname238 => yd
+longname3691 => yda
+longname292 => ye
+longname3745 => yea
+longname345 => yf
+longname3799 => yfa
+longname399 => yg
+longname3853 => yga
+longname453 => yh
+longname3907 => yha
+longname507 => yi
+longname3961 => yia
+longname561 => yj
+longname4015 => yja
+longname615 => yk
+longname4069 => yka
+longname669 => yl
+longname4123 => yla
+longname723 => ym
+longname4177 => yma
+longname776 => yn
+longname4231 => yna
+longname829 => yo
+longname4285 => yoa
+longname883 => yp
+longname4339 => ypa
+longname937 => yq
+longname4393 => yqa
+longname991 => yr
+longname4447 => yra
+longname1045 => ys
+longname4501 => ysa
+longname1099 => yt
+longname4555 => yta
+longname1153 => yu
+longname4609 => yua
+longname1207 => yv
+longname4663 => yva
+longname1261 => yw
+longname4717 => ywa
+longname1315 => yx
+longname4771 => yxa
+longname1369 => yy
+longname4825 => yya
+longname1423 => yz
+longname4879 => yza
+longname23 => z
+longname2936 => z$
+longname2990 => z0
+longname3044 => z1
+longname3098 => z2
+longname3152 => z3
+longname3206 => z4
+longname3260 => z5
+longname3314 => z6
+longname3368 => z7
+longname3422 => z8
+longname3476 => z9
+longname1478 => zA
+longname4934 => zAa
+longname1532 => zB
+longname4988 => zBa
+longname1586 => zC
+longname1640 => zD
+longname1694 => zE
+longname1748 => zF
+longname1802 => zG
+longname1856 => zH
+longname1910 => zI
+longname1964 => zJ
+longname2018 => zK
+longname2072 => zL
+longname2126 => zM
+longname2180 => zN
+longname2234 => zO
+longname2288 => zP
+longname2342 => zQ
+longname2396 => zR
+longname2450 => zS
+longname2504 => zT
+longname2558 => zU
+longname2612 => zV
+longname2666 => zW
+longname2720 => zX
+longname2774 => zY
+longname2828 => zZ
+longname2882 => z_
+longname77 => za
+longname3530 => zaa
+longname131 => zb
+longname3584 => zba
+longname185 => zc
+longname3638 => zca
+longname239 => zd
+longname3692 => zda
+longname293 => ze
+longname3746 => zea
+longname346 => zf
+longname3800 => zfa
+longname400 => zg
+longname3854 => zga
+longname454 => zh
+longname3908 => zha
+longname508 => zi
+longname3962 => zia
+longname562 => zj
+longname4016 => zja
+longname616 => zk
+longname4070 => zka
+longname670 => zl
+longname4124 => zla
+longname724 => zm
+longname4178 => zma
+longname777 => zn
+longname4232 => zna
+longname830 => zo
+longname4286 => zoa
+longname884 => zp
+longname4340 => zpa
+longname938 => zq
+longname4394 => zqa
+longname992 => zr
+longname4448 => zra
+longname1046 => zs
+longname4502 => zsa
+longname1100 => zt
+longname4556 => zta
+longname1154 => zu
+longname4610 => zua
+longname1208 => zv
+longname4664 => zva
+longname1262 => zw
+longname4718 => zwa
+longname1316 => zx
+longname4772 => zxa
+longname1370 => zy
+longname4826 => zya
+longname1424 => zz
+longname4880 => zza
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (import "env" "a" (global $gimport$0 i32))
+ (import "env" "b" (global $gimport$1 i32))
+ (import "env" "c" (global $gimport$2 i32))
+ (import "env" "d" (func $internal1))
+ (import "env" "e" (func $internal2))
+ (import "env" "f" (func $internal3))
+ (import "env" "g" (func $internal4))
+ (import "env" "h" (func $internal5))
+ (import "env" "i" (func $internal6))
+ (import "env" "j" (func $internal7))
+ (import "env" "k" (func $internal8))
+ (import "env" "l" (func $internal9))
+ (import "env" "m" (func $internal10))
+ (import "env" "n" (func $internal11))
+ (import "env" "o" (func $internal12))
+ (import "env" "p" (func $internal13))
+ (import "env" "q" (func $internal14))
+ (import "env" "r" (func $internal15))
+ (import "env" "s" (func $internal16))
+ (import "env" "t" (func $internal17))
+ (import "env" "u" (func $internal18))
+ (import "env" "v" (func $internal19))
+ (import "env" "w" (func $internal20))
+ (import "env" "x" (func $internal21))
+ (import "env" "y" (func $internal22))
+ (import "env" "z" (func $internal23))
+ (import "env" "A" (func $internal24))
+ (import "env" "B" (func $internal25))
+ (import "env" "C" (func $internal26))
+ (import "env" "D" (func $internal27))
+ (import "env" "E" (func $internal28))
+ (import "env" "F" (func $internal29))
+ (import "env" "G" (func $internal30))
+ (import "env" "H" (func $internal31))
+ (import "env" "I" (func $internal32))
+ (import "env" "J" (func $internal33))
+ (import "env" "K" (func $internal34))
+ (import "env" "L" (func $internal35))
+ (import "env" "M" (func $internal36))
+ (import "env" "N" (func $internal37))
+ (import "env" "O" (func $internal38))
+ (import "env" "P" (func $internal39))
+ (import "env" "Q" (func $internal40))
+ (import "env" "R" (func $internal41))
+ (import "env" "S" (func $internal42))
+ (import "env" "T" (func $internal43))
+ (import "env" "U" (func $internal44))
+ (import "env" "V" (func $internal45))
+ (import "env" "W" (func $internal46))
+ (import "env" "X" (func $internal47))
+ (import "env" "Y" (func $internal48))
+ (import "env" "Z" (func $internal49))
+ (import "env" "_" (func $internal50))
+ (import "env" "$" (func $internal51))
+ (import "env" "aa" (func $internal52))
+ (import "env" "ba" (func $internal53))
+ (import "env" "ca" (func $internal54))
+ (import "env" "da" (func $internal55))
+ (import "env" "ea" (func $internal56))
+ (import "env" "fa" (func $internal57))
+ (import "env" "ga" (func $internal58))
+ (import "env" "ha" (func $internal59))
+ (import "env" "ia" (func $internal60))
+ (import "env" "ja" (func $internal61))
+ (import "env" "ka" (func $internal62))
+ (import "env" "la" (func $internal63))
+ (import "env" "ma" (func $internal64))
+ (import "env" "na" (func $internal65))
+ (import "env" "oa" (func $internal66))
+ (import "env" "pa" (func $internal67))
+ (import "env" "qa" (func $internal68))
+ (import "env" "ra" (func $internal69))
+ (import "env" "sa" (func $internal70))
+ (import "env" "ta" (func $internal71))
+ (import "env" "ua" (func $internal72))
+ (import "env" "va" (func $internal73))
+ (import "env" "wa" (func $internal74))
+ (import "env" "xa" (func $internal75))
+ (import "env" "ya" (func $internal76))
+ (import "env" "za" (func $internal77))
+ (import "env" "Aa" (func $internal78))
+ (import "env" "Ba" (func $internal79))
+ (import "env" "Ca" (func $internal80))
+ (import "env" "Da" (func $internal81))
+ (import "env" "Ea" (func $internal82))
+ (import "env" "Fa" (func $internal83))
+ (import "env" "Ga" (func $internal84))
+ (import "env" "Ha" (func $internal85))
+ (import "env" "Ia" (func $internal86))
+ (import "env" "Ja" (func $internal87))
+ (import "env" "Ka" (func $internal88))
+ (import "env" "La" (func $internal89))
+ (import "env" "Ma" (func $internal90))
+ (import "env" "Na" (func $internal91))
+ (import "env" "Oa" (func $internal92))
+ (import "env" "Pa" (func $internal93))
+ (import "env" "Qa" (func $internal94))
+ (import "env" "Ra" (func $internal95))
+ (import "env" "Sa" (func $internal96))
+ (import "env" "Ta" (func $internal97))
+ (import "env" "Ua" (func $internal98))
+ (import "env" "Va" (func $internal99))
+ (import "env" "Wa" (func $internal100))
+ (import "env" "Xa" (func $internal101))
+ (import "env" "Ya" (func $internal102))
+ (import "env" "Za" (func $internal103))
+ (import "env" "_a" (func $internal104))
+ (import "env" "$a" (func $internal105))
+ (import "env" "ab" (func $internal106))
+ (import "env" "bb" (func $internal107))
+ (import "env" "cb" (func $internal108))
+ (import "env" "db" (func $internal109))
+ (import "env" "eb" (func $internal110))
+ (import "env" "fb" (func $internal111))
+ (import "env" "gb" (func $internal112))
+ (import "env" "hb" (func $internal113))
+ (import "env" "ib" (func $internal114))
+ (import "env" "jb" (func $internal115))
+ (import "env" "kb" (func $internal116))
+ (import "env" "lb" (func $internal117))
+ (import "env" "mb" (func $internal118))
+ (import "env" "nb" (func $internal119))
+ (import "env" "ob" (func $internal120))
+ (import "env" "pb" (func $internal121))
+ (import "env" "qb" (func $internal122))
+ (import "env" "rb" (func $internal123))
+ (import "env" "sb" (func $internal124))
+ (import "env" "tb" (func $internal125))
+ (import "env" "ub" (func $internal126))
+ (import "env" "vb" (func $internal127))
+ (import "env" "wb" (func $internal128))
+ (import "env" "xb" (func $internal129))
+ (import "env" "yb" (func $internal130))
+ (import "env" "zb" (func $internal131))
+ (import "env" "Ab" (func $internal132))
+ (import "env" "Bb" (func $internal133))
+ (import "env" "Cb" (func $internal134))
+ (import "env" "Db" (func $internal135))
+ (import "env" "Eb" (func $internal136))
+ (import "env" "Fb" (func $internal137))
+ (import "env" "Gb" (func $internal138))
+ (import "env" "Hb" (func $internal139))
+ (import "env" "Ib" (func $internal140))
+ (import "env" "Jb" (func $internal141))
+ (import "env" "Kb" (func $internal142))
+ (import "env" "Lb" (func $internal143))
+ (import "env" "Mb" (func $internal144))
+ (import "env" "Nb" (func $internal145))
+ (import "env" "Ob" (func $internal146))
+ (import "env" "Pb" (func $internal147))
+ (import "env" "Qb" (func $internal148))
+ (import "env" "Rb" (func $internal149))
+ (import "env" "Sb" (func $internal150))
+ (import "env" "Tb" (func $internal151))
+ (import "env" "Ub" (func $internal152))
+ (import "env" "Vb" (func $internal153))
+ (import "env" "Wb" (func $internal154))
+ (import "env" "Xb" (func $internal155))
+ (import "env" "Yb" (func $internal156))
+ (import "env" "Zb" (func $internal157))
+ (import "env" "_b" (func $internal158))
+ (import "env" "$b" (func $internal159))
+ (import "env" "ac" (func $internal160))
+ (import "env" "bc" (func $internal161))
+ (import "env" "cc" (func $internal162))
+ (import "env" "dc" (func $internal163))
+ (import "env" "ec" (func $internal164))
+ (import "env" "fc" (func $internal165))
+ (import "env" "gc" (func $internal166))
+ (import "env" "hc" (func $internal167))
+ (import "env" "ic" (func $internal168))
+ (import "env" "jc" (func $internal169))
+ (import "env" "kc" (func $internal170))
+ (import "env" "lc" (func $internal171))
+ (import "env" "mc" (func $internal172))
+ (import "env" "nc" (func $internal173))
+ (import "env" "oc" (func $internal174))
+ (import "env" "pc" (func $internal175))
+ (import "env" "qc" (func $internal176))
+ (import "env" "rc" (func $internal177))
+ (import "env" "sc" (func $internal178))
+ (import "env" "tc" (func $internal179))
+ (import "env" "uc" (func $internal180))
+ (import "env" "vc" (func $internal181))
+ (import "env" "wc" (func $internal182))
+ (import "env" "xc" (func $internal183))
+ (import "env" "yc" (func $internal184))
+ (import "env" "zc" (func $internal185))
+ (import "env" "Ac" (func $internal186))
+ (import "env" "Bc" (func $internal187))
+ (import "env" "Cc" (func $internal188))
+ (import "env" "Dc" (func $internal189))
+ (import "env" "Ec" (func $internal190))
+ (import "env" "Fc" (func $internal191))
+ (import "env" "Gc" (func $internal192))
+ (import "env" "Hc" (func $internal193))
+ (import "env" "Ic" (func $internal194))
+ (import "env" "Jc" (func $internal195))
+ (import "env" "Kc" (func $internal196))
+ (import "env" "Lc" (func $internal197))
+ (import "env" "Mc" (func $internal198))
+ (import "env" "Nc" (func $internal199))
+ (import "env" "Oc" (func $internal200))
+ (import "env" "Pc" (func $internal201))
+ (import "env" "Qc" (func $internal202))
+ (import "env" "Rc" (func $internal203))
+ (import "env" "Sc" (func $internal204))
+ (import "env" "Tc" (func $internal205))
+ (import "env" "Uc" (func $internal206))
+ (import "env" "Vc" (func $internal207))
+ (import "env" "Wc" (func $internal208))
+ (import "env" "Xc" (func $internal209))
+ (import "env" "Yc" (func $internal210))
+ (import "env" "Zc" (func $internal211))
+ (import "env" "_c" (func $internal212))
+ (import "env" "$c" (func $internal213))
+ (import "env" "ad" (func $internal214))
+ (import "env" "bd" (func $internal215))
+ (import "env" "cd" (func $internal216))
+ (import "env" "dd" (func $internal217))
+ (import "env" "ed" (func $internal218))
+ (import "env" "fd" (func $internal219))
+ (import "env" "gd" (func $internal220))
+ (import "env" "hd" (func $internal221))
+ (import "env" "id" (func $internal222))
+ (import "env" "jd" (func $internal223))
+ (import "env" "kd" (func $internal224))
+ (import "env" "ld" (func $internal225))
+ (import "env" "md" (func $internal226))
+ (import "env" "nd" (func $internal227))
+ (import "env" "od" (func $internal228))
+ (import "env" "pd" (func $internal229))
+ (import "env" "qd" (func $internal230))
+ (import "env" "rd" (func $internal231))
+ (import "env" "sd" (func $internal232))
+ (import "env" "td" (func $internal233))
+ (import "env" "ud" (func $internal234))
+ (import "env" "vd" (func $internal235))
+ (import "env" "wd" (func $internal236))
+ (import "env" "xd" (func $internal237))
+ (import "env" "yd" (func $internal238))
+ (import "env" "zd" (func $internal239))
+ (import "env" "Ad" (func $internal240))
+ (import "env" "Bd" (func $internal241))
+ (import "env" "Cd" (func $internal242))
+ (import "env" "Dd" (func $internal243))
+ (import "env" "Ed" (func $internal244))
+ (import "env" "Fd" (func $internal245))
+ (import "env" "Gd" (func $internal246))
+ (import "env" "Hd" (func $internal247))
+ (import "env" "Id" (func $internal248))
+ (import "env" "Jd" (func $internal249))
+ (import "env" "Kd" (func $internal250))
+ (import "env" "Ld" (func $internal251))
+ (import "env" "Md" (func $internal252))
+ (import "env" "Nd" (func $internal253))
+ (import "env" "Od" (func $internal254))
+ (import "env" "Pd" (func $internal255))
+ (import "env" "Qd" (func $internal256))
+ (import "env" "Rd" (func $internal257))
+ (import "env" "Sd" (func $internal258))
+ (import "env" "Td" (func $internal259))
+ (import "env" "Ud" (func $internal260))
+ (import "env" "Vd" (func $internal261))
+ (import "env" "Wd" (func $internal262))
+ (import "env" "Xd" (func $internal263))
+ (import "env" "Yd" (func $internal264))
+ (import "env" "Zd" (func $internal265))
+ (import "env" "_d" (func $internal266))
+ (import "env" "$d" (func $internal267))
+ (import "env" "ae" (func $internal268))
+ (import "env" "be" (func $internal269))
+ (import "env" "ce" (func $internal270))
+ (import "env" "de" (func $internal271))
+ (import "env" "ee" (func $internal272))
+ (import "env" "fe" (func $internal273))
+ (import "env" "ge" (func $internal274))
+ (import "env" "he" (func $internal275))
+ (import "env" "ie" (func $internal276))
+ (import "env" "je" (func $internal277))
+ (import "env" "ke" (func $internal278))
+ (import "env" "le" (func $internal279))
+ (import "env" "me" (func $internal280))
+ (import "env" "ne" (func $internal281))
+ (import "env" "oe" (func $internal282))
+ (import "env" "pe" (func $internal283))
+ (import "env" "qe" (func $internal284))
+ (import "env" "re" (func $internal285))
+ (import "env" "se" (func $internal286))
+ (import "env" "te" (func $internal287))
+ (import "env" "ue" (func $internal288))
+ (import "env" "ve" (func $internal289))
+ (import "env" "we" (func $internal290))
+ (import "env" "xe" (func $internal291))
+ (import "env" "ye" (func $internal292))
+ (import "env" "ze" (func $internal293))
+ (import "env" "Ae" (func $internal294))
+ (import "env" "Be" (func $internal295))
+ (import "env" "Ce" (func $internal296))
+ (import "env" "De" (func $internal297))
+ (import "env" "Ee" (func $internal298))
+ (import "env" "Fe" (func $internal299))
+ (import "env" "Ge" (func $internal300))
+ (import "env" "He" (func $internal301))
+ (import "env" "Ie" (func $internal302))
+ (import "env" "Je" (func $internal303))
+ (import "env" "Ke" (func $internal304))
+ (import "env" "Le" (func $internal305))
+ (import "env" "Me" (func $internal306))
+ (import "env" "Ne" (func $internal307))
+ (import "env" "Oe" (func $internal308))
+ (import "env" "Pe" (func $internal309))
+ (import "env" "Qe" (func $internal310))
+ (import "env" "Re" (func $internal311))
+ (import "env" "Se" (func $internal312))
+ (import "env" "Te" (func $internal313))
+ (import "env" "Ue" (func $internal314))
+ (import "env" "Ve" (func $internal315))
+ (import "env" "We" (func $internal316))
+ (import "env" "Xe" (func $internal317))
+ (import "env" "Ye" (func $internal318))
+ (import "env" "Ze" (func $internal319))
+ (import "env" "_e" (func $internal320))
+ (import "env" "$e" (func $internal321))
+ (import "env" "af" (func $internal322))
+ (import "env" "bf" (func $internal323))
+ (import "env" "cf" (func $internal324))
+ (import "env" "df" (func $internal325))
+ (import "env" "ef" (func $internal326))
+ (import "env" "ff" (func $internal327))
+ (import "env" "gf" (func $internal328))
+ (import "env" "hf" (func $internal329))
+ (import "env" "jf" (func $internal330))
+ (import "env" "kf" (func $internal331))
+ (import "env" "lf" (func $internal332))
+ (import "env" "mf" (func $internal333))
+ (import "env" "nf" (func $internal334))
+ (import "env" "of" (func $internal335))
+ (import "env" "pf" (func $internal336))
+ (import "env" "qf" (func $internal337))
+ (import "env" "rf" (func $internal338))
+ (import "env" "sf" (func $internal339))
+ (import "env" "tf" (func $internal340))
+ (import "env" "uf" (func $internal341))
+ (import "env" "vf" (func $internal342))
+ (import "env" "wf" (func $internal343))
+ (import "env" "xf" (func $internal344))
+ (import "env" "yf" (func $internal345))
+ (import "env" "zf" (func $internal346))
+ (import "env" "Af" (func $internal347))
+ (import "env" "Bf" (func $internal348))
+ (import "env" "Cf" (func $internal349))
+ (import "env" "Df" (func $internal350))
+ (import "env" "Ef" (func $internal351))
+ (import "env" "Ff" (func $internal352))
+ (import "env" "Gf" (func $internal353))
+ (import "env" "Hf" (func $internal354))
+ (import "env" "If" (func $internal355))
+ (import "env" "Jf" (func $internal356))
+ (import "env" "Kf" (func $internal357))
+ (import "env" "Lf" (func $internal358))
+ (import "env" "Mf" (func $internal359))
+ (import "env" "Nf" (func $internal360))
+ (import "env" "Of" (func $internal361))
+ (import "env" "Pf" (func $internal362))
+ (import "env" "Qf" (func $internal363))
+ (import "env" "Rf" (func $internal364))
+ (import "env" "Sf" (func $internal365))
+ (import "env" "Tf" (func $internal366))
+ (import "env" "Uf" (func $internal367))
+ (import "env" "Vf" (func $internal368))
+ (import "env" "Wf" (func $internal369))
+ (import "env" "Xf" (func $internal370))
+ (import "env" "Yf" (func $internal371))
+ (import "env" "Zf" (func $internal372))
+ (import "env" "_f" (func $internal373))
+ (import "env" "$f" (func $internal374))
+ (import "env" "ag" (func $internal375))
+ (import "env" "bg" (func $internal376))
+ (import "env" "cg" (func $internal377))
+ (import "env" "dg" (func $internal378))
+ (import "env" "eg" (func $internal379))
+ (import "env" "fg" (func $internal380))
+ (import "env" "gg" (func $internal381))
+ (import "env" "hg" (func $internal382))
+ (import "env" "ig" (func $internal383))
+ (import "env" "jg" (func $internal384))
+ (import "env" "kg" (func $internal385))
+ (import "env" "lg" (func $internal386))
+ (import "env" "mg" (func $internal387))
+ (import "env" "ng" (func $internal388))
+ (import "env" "og" (func $internal389))
+ (import "env" "pg" (func $internal390))
+ (import "env" "qg" (func $internal391))
+ (import "env" "rg" (func $internal392))
+ (import "env" "sg" (func $internal393))
+ (import "env" "tg" (func $internal394))
+ (import "env" "ug" (func $internal395))
+ (import "env" "vg" (func $internal396))
+ (import "env" "wg" (func $internal397))
+ (import "env" "xg" (func $internal398))
+ (import "env" "yg" (func $internal399))
+ (import "env" "zg" (func $internal400))
+ (import "env" "Ag" (func $internal401))
+ (import "env" "Bg" (func $internal402))
+ (import "env" "Cg" (func $internal403))
+ (import "env" "Dg" (func $internal404))
+ (import "env" "Eg" (func $internal405))
+ (import "env" "Fg" (func $internal406))
+ (import "env" "Gg" (func $internal407))
+ (import "env" "Hg" (func $internal408))
+ (import "env" "Ig" (func $internal409))
+ (import "env" "Jg" (func $internal410))
+ (import "env" "Kg" (func $internal411))
+ (import "env" "Lg" (func $internal412))
+ (import "env" "Mg" (func $internal413))
+ (import "env" "Ng" (func $internal414))
+ (import "env" "Og" (func $internal415))
+ (import "env" "Pg" (func $internal416))
+ (import "env" "Qg" (func $internal417))
+ (import "env" "Rg" (func $internal418))
+ (import "env" "Sg" (func $internal419))
+ (import "env" "Tg" (func $internal420))
+ (import "env" "Ug" (func $internal421))
+ (import "env" "Vg" (func $internal422))
+ (import "env" "Wg" (func $internal423))
+ (import "env" "Xg" (func $internal424))
+ (import "env" "Yg" (func $internal425))
+ (import "env" "Zg" (func $internal426))
+ (import "env" "_g" (func $internal427))
+ (import "env" "$g" (func $internal428))
+ (import "env" "ah" (func $internal429))
+ (import "env" "bh" (func $internal430))
+ (import "env" "ch" (func $internal431))
+ (import "env" "dh" (func $internal432))
+ (import "env" "eh" (func $internal433))
+ (import "env" "fh" (func $internal434))
+ (import "env" "gh" (func $internal435))
+ (import "env" "hh" (func $internal436))
+ (import "env" "ih" (func $internal437))
+ (import "env" "jh" (func $internal438))
+ (import "env" "kh" (func $internal439))
+ (import "env" "lh" (func $internal440))
+ (import "env" "mh" (func $internal441))
+ (import "env" "nh" (func $internal442))
+ (import "env" "oh" (func $internal443))
+ (import "env" "ph" (func $internal444))
+ (import "env" "qh" (func $internal445))
+ (import "env" "rh" (func $internal446))
+ (import "env" "sh" (func $internal447))
+ (import "env" "th" (func $internal448))
+ (import "env" "uh" (func $internal449))
+ (import "env" "vh" (func $internal450))
+ (import "env" "wh" (func $internal451))
+ (import "env" "xh" (func $internal452))
+ (import "env" "yh" (func $internal453))
+ (import "env" "zh" (func $internal454))
+ (import "env" "Ah" (func $internal455))
+ (import "env" "Bh" (func $internal456))
+ (import "env" "Ch" (func $internal457))
+ (import "env" "Dh" (func $internal458))
+ (import "env" "Eh" (func $internal459))
+ (import "env" "Fh" (func $internal460))
+ (import "env" "Gh" (func $internal461))
+ (import "env" "Hh" (func $internal462))
+ (import "env" "Ih" (func $internal463))
+ (import "env" "Jh" (func $internal464))
+ (import "env" "Kh" (func $internal465))
+ (import "env" "Lh" (func $internal466))
+ (import "env" "Mh" (func $internal467))
+ (import "env" "Nh" (func $internal468))
+ (import "env" "Oh" (func $internal469))
+ (import "env" "Ph" (func $internal470))
+ (import "env" "Qh" (func $internal471))
+ (import "env" "Rh" (func $internal472))
+ (import "env" "Sh" (func $internal473))
+ (import "env" "Th" (func $internal474))
+ (import "env" "Uh" (func $internal475))
+ (import "env" "Vh" (func $internal476))
+ (import "env" "Wh" (func $internal477))
+ (import "env" "Xh" (func $internal478))
+ (import "env" "Yh" (func $internal479))
+ (import "env" "Zh" (func $internal480))
+ (import "env" "_h" (func $internal481))
+ (import "env" "$h" (func $internal482))
+ (import "env" "ai" (func $internal483))
+ (import "env" "bi" (func $internal484))
+ (import "env" "ci" (func $internal485))
+ (import "env" "di" (func $internal486))
+ (import "env" "ei" (func $internal487))
+ (import "env" "fi" (func $internal488))
+ (import "env" "gi" (func $internal489))
+ (import "env" "hi" (func $internal490))
+ (import "env" "ii" (func $internal491))
+ (import "env" "ji" (func $internal492))
+ (import "env" "ki" (func $internal493))
+ (import "env" "li" (func $internal494))
+ (import "env" "mi" (func $internal495))
+ (import "env" "ni" (func $internal496))
+ (import "env" "oi" (func $internal497))
+ (import "env" "pi" (func $internal498))
+ (import "env" "qi" (func $internal499))
+ (import "env" "ri" (func $internal500))
+ (import "env" "si" (func $internal501))
+ (import "env" "ti" (func $internal502))
+ (import "env" "ui" (func $internal503))
+ (import "env" "vi" (func $internal504))
+ (import "env" "wi" (func $internal505))
+ (import "env" "xi" (func $internal506))
+ (import "env" "yi" (func $internal507))
+ (import "env" "zi" (func $internal508))
+ (import "env" "Ai" (func $internal509))
+ (import "env" "Bi" (func $internal510))
+ (import "env" "Ci" (func $internal511))
+ (import "env" "Di" (func $internal512))
+ (import "env" "Ei" (func $internal513))
+ (import "env" "Fi" (func $internal514))
+ (import "env" "Gi" (func $internal515))
+ (import "env" "Hi" (func $internal516))
+ (import "env" "Ii" (func $internal517))
+ (import "env" "Ji" (func $internal518))
+ (import "env" "Ki" (func $internal519))
+ (import "env" "Li" (func $internal520))
+ (import "env" "Mi" (func $internal521))
+ (import "env" "Ni" (func $internal522))
+ (import "env" "Oi" (func $internal523))
+ (import "env" "Pi" (func $internal524))
+ (import "env" "Qi" (func $internal525))
+ (import "env" "Ri" (func $internal526))
+ (import "env" "Si" (func $internal527))
+ (import "env" "Ti" (func $internal528))
+ (import "env" "Ui" (func $internal529))
+ (import "env" "Vi" (func $internal530))
+ (import "env" "Wi" (func $internal531))
+ (import "env" "Xi" (func $internal532))
+ (import "env" "Yi" (func $internal533))
+ (import "env" "Zi" (func $internal534))
+ (import "env" "_i" (func $internal535))
+ (import "env" "$i" (func $internal536))
+ (import "env" "aj" (func $internal537))
+ (import "env" "bj" (func $internal538))
+ (import "env" "cj" (func $internal539))
+ (import "env" "dj" (func $internal540))
+ (import "env" "ej" (func $internal541))
+ (import "env" "fj" (func $internal542))
+ (import "env" "gj" (func $internal543))
+ (import "env" "hj" (func $internal544))
+ (import "env" "ij" (func $internal545))
+ (import "env" "jj" (func $internal546))
+ (import "env" "kj" (func $internal547))
+ (import "env" "lj" (func $internal548))
+ (import "env" "mj" (func $internal549))
+ (import "env" "nj" (func $internal550))
+ (import "env" "oj" (func $internal551))
+ (import "env" "pj" (func $internal552))
+ (import "env" "qj" (func $internal553))
+ (import "env" "rj" (func $internal554))
+ (import "env" "sj" (func $internal555))
+ (import "env" "tj" (func $internal556))
+ (import "env" "uj" (func $internal557))
+ (import "env" "vj" (func $internal558))
+ (import "env" "wj" (func $internal559))
+ (import "env" "xj" (func $internal560))
+ (import "env" "yj" (func $internal561))
+ (import "env" "zj" (func $internal562))
+ (import "env" "Aj" (func $internal563))
+ (import "env" "Bj" (func $internal564))
+ (import "env" "Cj" (func $internal565))
+ (import "env" "Dj" (func $internal566))
+ (import "env" "Ej" (func $internal567))
+ (import "env" "Fj" (func $internal568))
+ (import "env" "Gj" (func $internal569))
+ (import "env" "Hj" (func $internal570))
+ (import "env" "Ij" (func $internal571))
+ (import "env" "Jj" (func $internal572))
+ (import "env" "Kj" (func $internal573))
+ (import "env" "Lj" (func $internal574))
+ (import "env" "Mj" (func $internal575))
+ (import "env" "Nj" (func $internal576))
+ (import "env" "Oj" (func $internal577))
+ (import "env" "Pj" (func $internal578))
+ (import "env" "Qj" (func $internal579))
+ (import "env" "Rj" (func $internal580))
+ (import "env" "Sj" (func $internal581))
+ (import "env" "Tj" (func $internal582))
+ (import "env" "Uj" (func $internal583))
+ (import "env" "Vj" (func $internal584))
+ (import "env" "Wj" (func $internal585))
+ (import "env" "Xj" (func $internal586))
+ (import "env" "Yj" (func $internal587))
+ (import "env" "Zj" (func $internal588))
+ (import "env" "_j" (func $internal589))
+ (import "env" "$j" (func $internal590))
+ (import "env" "ak" (func $internal591))
+ (import "env" "bk" (func $internal592))
+ (import "env" "ck" (func $internal593))
+ (import "env" "dk" (func $internal594))
+ (import "env" "ek" (func $internal595))
+ (import "env" "fk" (func $internal596))
+ (import "env" "gk" (func $internal597))
+ (import "env" "hk" (func $internal598))
+ (import "env" "ik" (func $internal599))
+ (import "env" "jk" (func $internal600))
+ (import "env" "kk" (func $internal601))
+ (import "env" "lk" (func $internal602))
+ (import "env" "mk" (func $internal603))
+ (import "env" "nk" (func $internal604))
+ (import "env" "ok" (func $internal605))
+ (import "env" "pk" (func $internal606))
+ (import "env" "qk" (func $internal607))
+ (import "env" "rk" (func $internal608))
+ (import "env" "sk" (func $internal609))
+ (import "env" "tk" (func $internal610))
+ (import "env" "uk" (func $internal611))
+ (import "env" "vk" (func $internal612))
+ (import "env" "wk" (func $internal613))
+ (import "env" "xk" (func $internal614))
+ (import "env" "yk" (func $internal615))
+ (import "env" "zk" (func $internal616))
+ (import "env" "Ak" (func $internal617))
+ (import "env" "Bk" (func $internal618))
+ (import "env" "Ck" (func $internal619))
+ (import "env" "Dk" (func $internal620))
+ (import "env" "Ek" (func $internal621))
+ (import "env" "Fk" (func $internal622))
+ (import "env" "Gk" (func $internal623))
+ (import "env" "Hk" (func $internal624))
+ (import "env" "Ik" (func $internal625))
+ (import "env" "Jk" (func $internal626))
+ (import "env" "Kk" (func $internal627))
+ (import "env" "Lk" (func $internal628))
+ (import "env" "Mk" (func $internal629))
+ (import "env" "Nk" (func $internal630))
+ (import "env" "Ok" (func $internal631))
+ (import "env" "Pk" (func $internal632))
+ (import "env" "Qk" (func $internal633))
+ (import "env" "Rk" (func $internal634))
+ (import "env" "Sk" (func $internal635))
+ (import "env" "Tk" (func $internal636))
+ (import "env" "Uk" (func $internal637))
+ (import "env" "Vk" (func $internal638))
+ (import "env" "Wk" (func $internal639))
+ (import "env" "Xk" (func $internal640))
+ (import "env" "Yk" (func $internal641))
+ (import "env" "Zk" (func $internal642))
+ (import "env" "_k" (func $internal643))
+ (import "env" "$k" (func $internal644))
+ (import "env" "al" (func $internal645))
+ (import "env" "bl" (func $internal646))
+ (import "env" "cl" (func $internal647))
+ (import "env" "dl" (func $internal648))
+ (import "env" "el" (func $internal649))
+ (import "env" "fl" (func $internal650))
+ (import "env" "gl" (func $internal651))
+ (import "env" "hl" (func $internal652))
+ (import "env" "il" (func $internal653))
+ (import "env" "jl" (func $internal654))
+ (import "env" "kl" (func $internal655))
+ (import "env" "ll" (func $internal656))
+ (import "env" "ml" (func $internal657))
+ (import "env" "nl" (func $internal658))
+ (import "env" "ol" (func $internal659))
+ (import "env" "pl" (func $internal660))
+ (import "env" "ql" (func $internal661))
+ (import "env" "rl" (func $internal662))
+ (import "env" "sl" (func $internal663))
+ (import "env" "tl" (func $internal664))
+ (import "env" "ul" (func $internal665))
+ (import "env" "vl" (func $internal666))
+ (import "env" "wl" (func $internal667))
+ (import "env" "xl" (func $internal668))
+ (import "env" "yl" (func $internal669))
+ (import "env" "zl" (func $internal670))
+ (import "env" "Al" (func $internal671))
+ (import "env" "Bl" (func $internal672))
+ (import "env" "Cl" (func $internal673))
+ (import "env" "Dl" (func $internal674))
+ (import "env" "El" (func $internal675))
+ (import "env" "Fl" (func $internal676))
+ (import "env" "Gl" (func $internal677))
+ (import "env" "Hl" (func $internal678))
+ (import "env" "Il" (func $internal679))
+ (import "env" "Jl" (func $internal680))
+ (import "env" "Kl" (func $internal681))
+ (import "env" "Ll" (func $internal682))
+ (import "env" "Ml" (func $internal683))
+ (import "env" "Nl" (func $internal684))
+ (import "env" "Ol" (func $internal685))
+ (import "env" "Pl" (func $internal686))
+ (import "env" "Ql" (func $internal687))
+ (import "env" "Rl" (func $internal688))
+ (import "env" "Sl" (func $internal689))
+ (import "env" "Tl" (func $internal690))
+ (import "env" "Ul" (func $internal691))
+ (import "env" "Vl" (func $internal692))
+ (import "env" "Wl" (func $internal693))
+ (import "env" "Xl" (func $internal694))
+ (import "env" "Yl" (func $internal695))
+ (import "env" "Zl" (func $internal696))
+ (import "env" "_l" (func $internal697))
+ (import "env" "$l" (func $internal698))
+ (import "env" "am" (func $internal699))
+ (import "env" "bm" (func $internal700))
+ (import "env" "cm" (func $internal701))
+ (import "env" "dm" (func $internal702))
+ (import "env" "em" (func $internal703))
+ (import "env" "fm" (func $internal704))
+ (import "env" "gm" (func $internal705))
+ (import "env" "hm" (func $internal706))
+ (import "env" "im" (func $internal707))
+ (import "env" "jm" (func $internal708))
+ (import "env" "km" (func $internal709))
+ (import "env" "lm" (func $internal710))
+ (import "env" "mm" (func $internal711))
+ (import "env" "nm" (func $internal712))
+ (import "env" "om" (func $internal713))
+ (import "env" "pm" (func $internal714))
+ (import "env" "qm" (func $internal715))
+ (import "env" "rm" (func $internal716))
+ (import "env" "sm" (func $internal717))
+ (import "env" "tm" (func $internal718))
+ (import "env" "um" (func $internal719))
+ (import "env" "vm" (func $internal720))
+ (import "env" "wm" (func $internal721))
+ (import "env" "xm" (func $internal722))
+ (import "env" "ym" (func $internal723))
+ (import "env" "zm" (func $internal724))
+ (import "env" "Am" (func $internal725))
+ (import "env" "Bm" (func $internal726))
+ (import "env" "Cm" (func $internal727))
+ (import "env" "Dm" (func $internal728))
+ (import "env" "Em" (func $internal729))
+ (import "env" "Fm" (func $internal730))
+ (import "env" "Gm" (func $internal731))
+ (import "env" "Hm" (func $internal732))
+ (import "env" "Im" (func $internal733))
+ (import "env" "Jm" (func $internal734))
+ (import "env" "Km" (func $internal735))
+ (import "env" "Lm" (func $internal736))
+ (import "env" "Mm" (func $internal737))
+ (import "env" "Nm" (func $internal738))
+ (import "env" "Om" (func $internal739))
+ (import "env" "Pm" (func $internal740))
+ (import "env" "Qm" (func $internal741))
+ (import "env" "Rm" (func $internal742))
+ (import "env" "Sm" (func $internal743))
+ (import "env" "Tm" (func $internal744))
+ (import "env" "Um" (func $internal745))
+ (import "env" "Vm" (func $internal746))
+ (import "env" "Wm" (func $internal747))
+ (import "env" "Xm" (func $internal748))
+ (import "env" "Ym" (func $internal749))
+ (import "env" "Zm" (func $internal750))
+ (import "env" "_m" (func $internal751))
+ (import "env" "$m" (func $internal752))
+ (import "env" "an" (func $internal753))
+ (import "env" "bn" (func $internal754))
+ (import "env" "cn" (func $internal755))
+ (import "env" "dn" (func $internal756))
+ (import "env" "en" (func $internal757))
+ (import "env" "fn" (func $internal758))
+ (import "env" "gn" (func $internal759))
+ (import "env" "hn" (func $internal760))
+ (import "env" "jn" (func $internal761))
+ (import "env" "kn" (func $internal762))
+ (import "env" "ln" (func $internal763))
+ (import "env" "mn" (func $internal764))
+ (import "env" "nn" (func $internal765))
+ (import "env" "on" (func $internal766))
+ (import "env" "pn" (func $internal767))
+ (import "env" "qn" (func $internal768))
+ (import "env" "rn" (func $internal769))
+ (import "env" "sn" (func $internal770))
+ (import "env" "tn" (func $internal771))
+ (import "env" "un" (func $internal772))
+ (import "env" "vn" (func $internal773))
+ (import "env" "wn" (func $internal774))
+ (import "env" "xn" (func $internal775))
+ (import "env" "yn" (func $internal776))
+ (import "env" "zn" (func $internal777))
+ (import "env" "An" (func $internal778))
+ (import "env" "Bn" (func $internal779))
+ (import "env" "Cn" (func $internal780))
+ (import "env" "Dn" (func $internal781))
+ (import "env" "En" (func $internal782))
+ (import "env" "Fn" (func $internal783))
+ (import "env" "Gn" (func $internal784))
+ (import "env" "Hn" (func $internal785))
+ (import "env" "In" (func $internal786))
+ (import "env" "Jn" (func $internal787))
+ (import "env" "Kn" (func $internal788))
+ (import "env" "Ln" (func $internal789))
+ (import "env" "Mn" (func $internal790))
+ (import "env" "Nn" (func $internal791))
+ (import "env" "On" (func $internal792))
+ (import "env" "Pn" (func $internal793))
+ (import "env" "Qn" (func $internal794))
+ (import "env" "Rn" (func $internal795))
+ (import "env" "Sn" (func $internal796))
+ (import "env" "Tn" (func $internal797))
+ (import "env" "Un" (func $internal798))
+ (import "env" "Vn" (func $internal799))
+ (import "env" "Wn" (func $internal800))
+ (import "env" "Xn" (func $internal801))
+ (import "env" "Yn" (func $internal802))
+ (import "env" "Zn" (func $internal803))
+ (import "env" "_n" (func $internal804))
+ (import "env" "$n" (func $internal805))
+ (import "env" "ao" (func $internal806))
+ (import "env" "bo" (func $internal807))
+ (import "env" "co" (func $internal808))
+ (import "env" "eo" (func $internal809))
+ (import "env" "fo" (func $internal810))
+ (import "env" "go" (func $internal811))
+ (import "env" "ho" (func $internal812))
+ (import "env" "io" (func $internal813))
+ (import "env" "jo" (func $internal814))
+ (import "env" "ko" (func $internal815))
+ (import "env" "lo" (func $internal816))
+ (import "env" "mo" (func $internal817))
+ (import "env" "no" (func $internal818))
+ (import "env" "oo" (func $internal819))
+ (import "env" "po" (func $internal820))
+ (import "env" "qo" (func $internal821))
+ (import "env" "ro" (func $internal822))
+ (import "env" "so" (func $internal823))
+ (import "env" "to" (func $internal824))
+ (import "env" "uo" (func $internal825))
+ (import "env" "vo" (func $internal826))
+ (import "env" "wo" (func $internal827))
+ (import "env" "xo" (func $internal828))
+ (import "env" "yo" (func $internal829))
+ (import "env" "zo" (func $internal830))
+ (import "env" "Ao" (func $internal831))
+ (import "env" "Bo" (func $internal832))
+ (import "env" "Co" (func $internal833))
+ (import "env" "Do" (func $internal834))
+ (import "env" "Eo" (func $internal835))
+ (import "env" "Fo" (func $internal836))
+ (import "env" "Go" (func $internal837))
+ (import "env" "Ho" (func $internal838))
+ (import "env" "Io" (func $internal839))
+ (import "env" "Jo" (func $internal840))
+ (import "env" "Ko" (func $internal841))
+ (import "env" "Lo" (func $internal842))
+ (import "env" "Mo" (func $internal843))
+ (import "env" "No" (func $internal844))
+ (import "env" "Oo" (func $internal845))
+ (import "env" "Po" (func $internal846))
+ (import "env" "Qo" (func $internal847))
+ (import "env" "Ro" (func $internal848))
+ (import "env" "So" (func $internal849))
+ (import "env" "To" (func $internal850))
+ (import "env" "Uo" (func $internal851))
+ (import "env" "Vo" (func $internal852))
+ (import "env" "Wo" (func $internal853))
+ (import "env" "Xo" (func $internal854))
+ (import "env" "Yo" (func $internal855))
+ (import "env" "Zo" (func $internal856))
+ (import "env" "_o" (func $internal857))
+ (import "env" "$o" (func $internal858))
+ (import "env" "ap" (func $internal859))
+ (import "env" "bp" (func $internal860))
+ (import "env" "cp" (func $internal861))
+ (import "env" "dp" (func $internal862))
+ (import "env" "ep" (func $internal863))
+ (import "env" "fp" (func $internal864))
+ (import "env" "gp" (func $internal865))
+ (import "env" "hp" (func $internal866))
+ (import "env" "ip" (func $internal867))
+ (import "env" "jp" (func $internal868))
+ (import "env" "kp" (func $internal869))
+ (import "env" "lp" (func $internal870))
+ (import "env" "mp" (func $internal871))
+ (import "env" "np" (func $internal872))
+ (import "env" "op" (func $internal873))
+ (import "env" "pp" (func $internal874))
+ (import "env" "qp" (func $internal875))
+ (import "env" "rp" (func $internal876))
+ (import "env" "sp" (func $internal877))
+ (import "env" "tp" (func $internal878))
+ (import "env" "up" (func $internal879))
+ (import "env" "vp" (func $internal880))
+ (import "env" "wp" (func $internal881))
+ (import "env" "xp" (func $internal882))
+ (import "env" "yp" (func $internal883))
+ (import "env" "zp" (func $internal884))
+ (import "env" "Ap" (func $internal885))
+ (import "env" "Bp" (func $internal886))
+ (import "env" "Cp" (func $internal887))
+ (import "env" "Dp" (func $internal888))
+ (import "env" "Ep" (func $internal889))
+ (import "env" "Fp" (func $internal890))
+ (import "env" "Gp" (func $internal891))
+ (import "env" "Hp" (func $internal892))
+ (import "env" "Ip" (func $internal893))
+ (import "env" "Jp" (func $internal894))
+ (import "env" "Kp" (func $internal895))
+ (import "env" "Lp" (func $internal896))
+ (import "env" "Mp" (func $internal897))
+ (import "env" "Np" (func $internal898))
+ (import "env" "Op" (func $internal899))
+ (import "env" "Pp" (func $internal900))
+ (import "env" "Qp" (func $internal901))
+ (import "env" "Rp" (func $internal902))
+ (import "env" "Sp" (func $internal903))
+ (import "env" "Tp" (func $internal904))
+ (import "env" "Up" (func $internal905))
+ (import "env" "Vp" (func $internal906))
+ (import "env" "Wp" (func $internal907))
+ (import "env" "Xp" (func $internal908))
+ (import "env" "Yp" (func $internal909))
+ (import "env" "Zp" (func $internal910))
+ (import "env" "_p" (func $internal911))
+ (import "env" "$p" (func $internal912))
+ (import "env" "aq" (func $internal913))
+ (import "env" "bq" (func $internal914))
+ (import "env" "cq" (func $internal915))
+ (import "env" "dq" (func $internal916))
+ (import "env" "eq" (func $internal917))
+ (import "env" "fq" (func $internal918))
+ (import "env" "gq" (func $internal919))
+ (import "env" "hq" (func $internal920))
+ (import "env" "iq" (func $internal921))
+ (import "env" "jq" (func $internal922))
+ (import "env" "kq" (func $internal923))
+ (import "env" "lq" (func $internal924))
+ (import "env" "mq" (func $internal925))
+ (import "env" "nq" (func $internal926))
+ (import "env" "oq" (func $internal927))
+ (import "env" "pq" (func $internal928))
+ (import "env" "qq" (func $internal929))
+ (import "env" "rq" (func $internal930))
+ (import "env" "sq" (func $internal931))
+ (import "env" "tq" (func $internal932))
+ (import "env" "uq" (func $internal933))
+ (import "env" "vq" (func $internal934))
+ (import "env" "wq" (func $internal935))
+ (import "env" "xq" (func $internal936))
+ (import "env" "yq" (func $internal937))
+ (import "env" "zq" (func $internal938))
+ (import "env" "Aq" (func $internal939))
+ (import "env" "Bq" (func $internal940))
+ (import "env" "Cq" (func $internal941))
+ (import "env" "Dq" (func $internal942))
+ (import "env" "Eq" (func $internal943))
+ (import "env" "Fq" (func $internal944))
+ (import "env" "Gq" (func $internal945))
+ (import "env" "Hq" (func $internal946))
+ (import "env" "Iq" (func $internal947))
+ (import "env" "Jq" (func $internal948))
+ (import "env" "Kq" (func $internal949))
+ (import "env" "Lq" (func $internal950))
+ (import "env" "Mq" (func $internal951))
+ (import "env" "Nq" (func $internal952))
+ (import "env" "Oq" (func $internal953))
+ (import "env" "Pq" (func $internal954))
+ (import "env" "Qq" (func $internal955))
+ (import "env" "Rq" (func $internal956))
+ (import "env" "Sq" (func $internal957))
+ (import "env" "Tq" (func $internal958))
+ (import "env" "Uq" (func $internal959))
+ (import "env" "Vq" (func $internal960))
+ (import "env" "Wq" (func $internal961))
+ (import "env" "Xq" (func $internal962))
+ (import "env" "Yq" (func $internal963))
+ (import "env" "Zq" (func $internal964))
+ (import "env" "_q" (func $internal965))
+ (import "env" "$q" (func $internal966))
+ (import "env" "ar" (func $internal967))
+ (import "env" "br" (func $internal968))
+ (import "env" "cr" (func $internal969))
+ (import "env" "dr" (func $internal970))
+ (import "env" "er" (func $internal971))
+ (import "env" "fr" (func $internal972))
+ (import "env" "gr" (func $internal973))
+ (import "env" "hr" (func $internal974))
+ (import "env" "ir" (func $internal975))
+ (import "env" "jr" (func $internal976))
+ (import "env" "kr" (func $internal977))
+ (import "env" "lr" (func $internal978))
+ (import "env" "mr" (func $internal979))
+ (import "env" "nr" (func $internal980))
+ (import "env" "or" (func $internal981))
+ (import "env" "pr" (func $internal982))
+ (import "env" "qr" (func $internal983))
+ (import "env" "rr" (func $internal984))
+ (import "env" "sr" (func $internal985))
+ (import "env" "tr" (func $internal986))
+ (import "env" "ur" (func $internal987))
+ (import "env" "vr" (func $internal988))
+ (import "env" "wr" (func $internal989))
+ (import "env" "xr" (func $internal990))
+ (import "env" "yr" (func $internal991))
+ (import "env" "zr" (func $internal992))
+ (import "env" "Ar" (func $internal993))
+ (import "env" "Br" (func $internal994))
+ (import "env" "Cr" (func $internal995))
+ (import "env" "Dr" (func $internal996))
+ (import "env" "Er" (func $internal997))
+ (import "env" "Fr" (func $internal998))
+ (import "env" "Gr" (func $internal999))
+ (import "env" "Hr" (func $internal1000))
+ (import "env" "Ir" (func $internal1001))
+ (import "env" "Jr" (func $internal1002))
+ (import "env" "Kr" (func $internal1003))
+ (import "env" "Lr" (func $internal1004))
+ (import "env" "Mr" (func $internal1005))
+ (import "env" "Nr" (func $internal1006))
+ (import "env" "Or" (func $internal1007))
+ (import "env" "Pr" (func $internal1008))
+ (import "env" "Qr" (func $internal1009))
+ (import "env" "Rr" (func $internal1010))
+ (import "env" "Sr" (func $internal1011))
+ (import "env" "Tr" (func $internal1012))
+ (import "env" "Ur" (func $internal1013))
+ (import "env" "Vr" (func $internal1014))
+ (import "env" "Wr" (func $internal1015))
+ (import "env" "Xr" (func $internal1016))
+ (import "env" "Yr" (func $internal1017))
+ (import "env" "Zr" (func $internal1018))
+ (import "env" "_r" (func $internal1019))
+ (import "env" "$r" (func $internal1020))
+ (import "env" "as" (func $internal1021))
+ (import "env" "bs" (func $internal1022))
+ (import "env" "cs" (func $internal1023))
+ (import "env" "ds" (func $internal1024))
+ (import "env" "es" (func $internal1025))
+ (import "env" "fs" (func $internal1026))
+ (import "env" "gs" (func $internal1027))
+ (import "env" "hs" (func $internal1028))
+ (import "env" "is" (func $internal1029))
+ (import "env" "js" (func $internal1030))
+ (import "env" "ks" (func $internal1031))
+ (import "env" "ls" (func $internal1032))
+ (import "env" "ms" (func $internal1033))
+ (import "env" "ns" (func $internal1034))
+ (import "env" "os" (func $internal1035))
+ (import "env" "ps" (func $internal1036))
+ (import "env" "qs" (func $internal1037))
+ (import "env" "rs" (func $internal1038))
+ (import "env" "ss" (func $internal1039))
+ (import "env" "ts" (func $internal1040))
+ (import "env" "us" (func $internal1041))
+ (import "env" "vs" (func $internal1042))
+ (import "env" "ws" (func $internal1043))
+ (import "env" "xs" (func $internal1044))
+ (import "env" "ys" (func $internal1045))
+ (import "env" "zs" (func $internal1046))
+ (import "env" "As" (func $internal1047))
+ (import "env" "Bs" (func $internal1048))
+ (import "env" "Cs" (func $internal1049))
+ (import "env" "Ds" (func $internal1050))
+ (import "env" "Es" (func $internal1051))
+ (import "env" "Fs" (func $internal1052))
+ (import "env" "Gs" (func $internal1053))
+ (import "env" "Hs" (func $internal1054))
+ (import "env" "Is" (func $internal1055))
+ (import "env" "Js" (func $internal1056))
+ (import "env" "Ks" (func $internal1057))
+ (import "env" "Ls" (func $internal1058))
+ (import "env" "Ms" (func $internal1059))
+ (import "env" "Ns" (func $internal1060))
+ (import "env" "Os" (func $internal1061))
+ (import "env" "Ps" (func $internal1062))
+ (import "env" "Qs" (func $internal1063))
+ (import "env" "Rs" (func $internal1064))
+ (import "env" "Ss" (func $internal1065))
+ (import "env" "Ts" (func $internal1066))
+ (import "env" "Us" (func $internal1067))
+ (import "env" "Vs" (func $internal1068))
+ (import "env" "Ws" (func $internal1069))
+ (import "env" "Xs" (func $internal1070))
+ (import "env" "Ys" (func $internal1071))
+ (import "env" "Zs" (func $internal1072))
+ (import "env" "_s" (func $internal1073))
+ (import "env" "$s" (func $internal1074))
+ (import "env" "at" (func $internal1075))
+ (import "env" "bt" (func $internal1076))
+ (import "env" "ct" (func $internal1077))
+ (import "env" "dt" (func $internal1078))
+ (import "env" "et" (func $internal1079))
+ (import "env" "ft" (func $internal1080))
+ (import "env" "gt" (func $internal1081))
+ (import "env" "ht" (func $internal1082))
+ (import "env" "it" (func $internal1083))
+ (import "env" "jt" (func $internal1084))
+ (import "env" "kt" (func $internal1085))
+ (import "env" "lt" (func $internal1086))
+ (import "env" "mt" (func $internal1087))
+ (import "env" "nt" (func $internal1088))
+ (import "env" "ot" (func $internal1089))
+ (import "env" "pt" (func $internal1090))
+ (import "env" "qt" (func $internal1091))
+ (import "env" "rt" (func $internal1092))
+ (import "env" "st" (func $internal1093))
+ (import "env" "tt" (func $internal1094))
+ (import "env" "ut" (func $internal1095))
+ (import "env" "vt" (func $internal1096))
+ (import "env" "wt" (func $internal1097))
+ (import "env" "xt" (func $internal1098))
+ (import "env" "yt" (func $internal1099))
+ (import "env" "zt" (func $internal1100))
+ (import "env" "At" (func $internal1101))
+ (import "env" "Bt" (func $internal1102))
+ (import "env" "Ct" (func $internal1103))
+ (import "env" "Dt" (func $internal1104))
+ (import "env" "Et" (func $internal1105))
+ (import "env" "Ft" (func $internal1106))
+ (import "env" "Gt" (func $internal1107))
+ (import "env" "Ht" (func $internal1108))
+ (import "env" "It" (func $internal1109))
+ (import "env" "Jt" (func $internal1110))
+ (import "env" "Kt" (func $internal1111))
+ (import "env" "Lt" (func $internal1112))
+ (import "env" "Mt" (func $internal1113))
+ (import "env" "Nt" (func $internal1114))
+ (import "env" "Ot" (func $internal1115))
+ (import "env" "Pt" (func $internal1116))
+ (import "env" "Qt" (func $internal1117))
+ (import "env" "Rt" (func $internal1118))
+ (import "env" "St" (func $internal1119))
+ (import "env" "Tt" (func $internal1120))
+ (import "env" "Ut" (func $internal1121))
+ (import "env" "Vt" (func $internal1122))
+ (import "env" "Wt" (func $internal1123))
+ (import "env" "Xt" (func $internal1124))
+ (import "env" "Yt" (func $internal1125))
+ (import "env" "Zt" (func $internal1126))
+ (import "env" "_t" (func $internal1127))
+ (import "env" "$t" (func $internal1128))
+ (import "env" "au" (func $internal1129))
+ (import "env" "bu" (func $internal1130))
+ (import "env" "cu" (func $internal1131))
+ (import "env" "du" (func $internal1132))
+ (import "env" "eu" (func $internal1133))
+ (import "env" "fu" (func $internal1134))
+ (import "env" "gu" (func $internal1135))
+ (import "env" "hu" (func $internal1136))
+ (import "env" "iu" (func $internal1137))
+ (import "env" "ju" (func $internal1138))
+ (import "env" "ku" (func $internal1139))
+ (import "env" "lu" (func $internal1140))
+ (import "env" "mu" (func $internal1141))
+ (import "env" "nu" (func $internal1142))
+ (import "env" "ou" (func $internal1143))
+ (import "env" "pu" (func $internal1144))
+ (import "env" "qu" (func $internal1145))
+ (import "env" "ru" (func $internal1146))
+ (import "env" "su" (func $internal1147))
+ (import "env" "tu" (func $internal1148))
+ (import "env" "uu" (func $internal1149))
+ (import "env" "vu" (func $internal1150))
+ (import "env" "wu" (func $internal1151))
+ (import "env" "xu" (func $internal1152))
+ (import "env" "yu" (func $internal1153))
+ (import "env" "zu" (func $internal1154))
+ (import "env" "Au" (func $internal1155))
+ (import "env" "Bu" (func $internal1156))
+ (import "env" "Cu" (func $internal1157))
+ (import "env" "Du" (func $internal1158))
+ (import "env" "Eu" (func $internal1159))
+ (import "env" "Fu" (func $internal1160))
+ (import "env" "Gu" (func $internal1161))
+ (import "env" "Hu" (func $internal1162))
+ (import "env" "Iu" (func $internal1163))
+ (import "env" "Ju" (func $internal1164))
+ (import "env" "Ku" (func $internal1165))
+ (import "env" "Lu" (func $internal1166))
+ (import "env" "Mu" (func $internal1167))
+ (import "env" "Nu" (func $internal1168))
+ (import "env" "Ou" (func $internal1169))
+ (import "env" "Pu" (func $internal1170))
+ (import "env" "Qu" (func $internal1171))
+ (import "env" "Ru" (func $internal1172))
+ (import "env" "Su" (func $internal1173))
+ (import "env" "Tu" (func $internal1174))
+ (import "env" "Uu" (func $internal1175))
+ (import "env" "Vu" (func $internal1176))
+ (import "env" "Wu" (func $internal1177))
+ (import "env" "Xu" (func $internal1178))
+ (import "env" "Yu" (func $internal1179))
+ (import "env" "Zu" (func $internal1180))
+ (import "env" "_u" (func $internal1181))
+ (import "env" "$u" (func $internal1182))
+ (import "env" "av" (func $internal1183))
+ (import "env" "bv" (func $internal1184))
+ (import "env" "cv" (func $internal1185))
+ (import "env" "dv" (func $internal1186))
+ (import "env" "ev" (func $internal1187))
+ (import "env" "fv" (func $internal1188))
+ (import "env" "gv" (func $internal1189))
+ (import "env" "hv" (func $internal1190))
+ (import "env" "iv" (func $internal1191))
+ (import "env" "jv" (func $internal1192))
+ (import "env" "kv" (func $internal1193))
+ (import "env" "lv" (func $internal1194))
+ (import "env" "mv" (func $internal1195))
+ (import "env" "nv" (func $internal1196))
+ (import "env" "ov" (func $internal1197))
+ (import "env" "pv" (func $internal1198))
+ (import "env" "qv" (func $internal1199))
+ (import "env" "rv" (func $internal1200))
+ (import "env" "sv" (func $internal1201))
+ (import "env" "tv" (func $internal1202))
+ (import "env" "uv" (func $internal1203))
+ (import "env" "vv" (func $internal1204))
+ (import "env" "wv" (func $internal1205))
+ (import "env" "xv" (func $internal1206))
+ (import "env" "yv" (func $internal1207))
+ (import "env" "zv" (func $internal1208))
+ (import "env" "Av" (func $internal1209))
+ (import "env" "Bv" (func $internal1210))
+ (import "env" "Cv" (func $internal1211))
+ (import "env" "Dv" (func $internal1212))
+ (import "env" "Ev" (func $internal1213))
+ (import "env" "Fv" (func $internal1214))
+ (import "env" "Gv" (func $internal1215))
+ (import "env" "Hv" (func $internal1216))
+ (import "env" "Iv" (func $internal1217))
+ (import "env" "Jv" (func $internal1218))
+ (import "env" "Kv" (func $internal1219))
+ (import "env" "Lv" (func $internal1220))
+ (import "env" "Mv" (func $internal1221))
+ (import "env" "Nv" (func $internal1222))
+ (import "env" "Ov" (func $internal1223))
+ (import "env" "Pv" (func $internal1224))
+ (import "env" "Qv" (func $internal1225))
+ (import "env" "Rv" (func $internal1226))
+ (import "env" "Sv" (func $internal1227))
+ (import "env" "Tv" (func $internal1228))
+ (import "env" "Uv" (func $internal1229))
+ (import "env" "Vv" (func $internal1230))
+ (import "env" "Wv" (func $internal1231))
+ (import "env" "Xv" (func $internal1232))
+ (import "env" "Yv" (func $internal1233))
+ (import "env" "Zv" (func $internal1234))
+ (import "env" "_v" (func $internal1235))
+ (import "env" "$v" (func $internal1236))
+ (import "env" "aw" (func $internal1237))
+ (import "env" "bw" (func $internal1238))
+ (import "env" "cw" (func $internal1239))
+ (import "env" "dw" (func $internal1240))
+ (import "env" "ew" (func $internal1241))
+ (import "env" "fw" (func $internal1242))
+ (import "env" "gw" (func $internal1243))
+ (import "env" "hw" (func $internal1244))
+ (import "env" "iw" (func $internal1245))
+ (import "env" "jw" (func $internal1246))
+ (import "env" "kw" (func $internal1247))
+ (import "env" "lw" (func $internal1248))
+ (import "env" "mw" (func $internal1249))
+ (import "env" "nw" (func $internal1250))
+ (import "env" "ow" (func $internal1251))
+ (import "env" "pw" (func $internal1252))
+ (import "env" "qw" (func $internal1253))
+ (import "env" "rw" (func $internal1254))
+ (import "env" "sw" (func $internal1255))
+ (import "env" "tw" (func $internal1256))
+ (import "env" "uw" (func $internal1257))
+ (import "env" "vw" (func $internal1258))
+ (import "env" "ww" (func $internal1259))
+ (import "env" "xw" (func $internal1260))
+ (import "env" "yw" (func $internal1261))
+ (import "env" "zw" (func $internal1262))
+ (import "env" "Aw" (func $internal1263))
+ (import "env" "Bw" (func $internal1264))
+ (import "env" "Cw" (func $internal1265))
+ (import "env" "Dw" (func $internal1266))
+ (import "env" "Ew" (func $internal1267))
+ (import "env" "Fw" (func $internal1268))
+ (import "env" "Gw" (func $internal1269))
+ (import "env" "Hw" (func $internal1270))
+ (import "env" "Iw" (func $internal1271))
+ (import "env" "Jw" (func $internal1272))
+ (import "env" "Kw" (func $internal1273))
+ (import "env" "Lw" (func $internal1274))
+ (import "env" "Mw" (func $internal1275))
+ (import "env" "Nw" (func $internal1276))
+ (import "env" "Ow" (func $internal1277))
+ (import "env" "Pw" (func $internal1278))
+ (import "env" "Qw" (func $internal1279))
+ (import "env" "Rw" (func $internal1280))
+ (import "env" "Sw" (func $internal1281))
+ (import "env" "Tw" (func $internal1282))
+ (import "env" "Uw" (func $internal1283))
+ (import "env" "Vw" (func $internal1284))
+ (import "env" "Ww" (func $internal1285))
+ (import "env" "Xw" (func $internal1286))
+ (import "env" "Yw" (func $internal1287))
+ (import "env" "Zw" (func $internal1288))
+ (import "env" "_w" (func $internal1289))
+ (import "env" "$w" (func $internal1290))
+ (import "env" "ax" (func $internal1291))
+ (import "env" "bx" (func $internal1292))
+ (import "env" "cx" (func $internal1293))
+ (import "env" "dx" (func $internal1294))
+ (import "env" "ex" (func $internal1295))
+ (import "env" "fx" (func $internal1296))
+ (import "env" "gx" (func $internal1297))
+ (import "env" "hx" (func $internal1298))
+ (import "env" "ix" (func $internal1299))
+ (import "env" "jx" (func $internal1300))
+ (import "env" "kx" (func $internal1301))
+ (import "env" "lx" (func $internal1302))
+ (import "env" "mx" (func $internal1303))
+ (import "env" "nx" (func $internal1304))
+ (import "env" "ox" (func $internal1305))
+ (import "env" "px" (func $internal1306))
+ (import "env" "qx" (func $internal1307))
+ (import "env" "rx" (func $internal1308))
+ (import "env" "sx" (func $internal1309))
+ (import "env" "tx" (func $internal1310))
+ (import "env" "ux" (func $internal1311))
+ (import "env" "vx" (func $internal1312))
+ (import "env" "wx" (func $internal1313))
+ (import "env" "xx" (func $internal1314))
+ (import "env" "yx" (func $internal1315))
+ (import "env" "zx" (func $internal1316))
+ (import "env" "Ax" (func $internal1317))
+ (import "env" "Bx" (func $internal1318))
+ (import "env" "Cx" (func $internal1319))
+ (import "env" "Dx" (func $internal1320))
+ (import "env" "Ex" (func $internal1321))
+ (import "env" "Fx" (func $internal1322))
+ (import "env" "Gx" (func $internal1323))
+ (import "env" "Hx" (func $internal1324))
+ (import "env" "Ix" (func $internal1325))
+ (import "env" "Jx" (func $internal1326))
+ (import "env" "Kx" (func $internal1327))
+ (import "env" "Lx" (func $internal1328))
+ (import "env" "Mx" (func $internal1329))
+ (import "env" "Nx" (func $internal1330))
+ (import "env" "Ox" (func $internal1331))
+ (import "env" "Px" (func $internal1332))
+ (import "env" "Qx" (func $internal1333))
+ (import "env" "Rx" (func $internal1334))
+ (import "env" "Sx" (func $internal1335))
+ (import "env" "Tx" (func $internal1336))
+ (import "env" "Ux" (func $internal1337))
+ (import "env" "Vx" (func $internal1338))
+ (import "env" "Wx" (func $internal1339))
+ (import "env" "Xx" (func $internal1340))
+ (import "env" "Yx" (func $internal1341))
+ (import "env" "Zx" (func $internal1342))
+ (import "env" "_x" (func $internal1343))
+ (import "env" "$x" (func $internal1344))
+ (import "env" "ay" (func $internal1345))
+ (import "env" "by" (func $internal1346))
+ (import "env" "cy" (func $internal1347))
+ (import "env" "dy" (func $internal1348))
+ (import "env" "ey" (func $internal1349))
+ (import "env" "fy" (func $internal1350))
+ (import "env" "gy" (func $internal1351))
+ (import "env" "hy" (func $internal1352))
+ (import "env" "iy" (func $internal1353))
+ (import "env" "jy" (func $internal1354))
+ (import "env" "ky" (func $internal1355))
+ (import "env" "ly" (func $internal1356))
+ (import "env" "my" (func $internal1357))
+ (import "env" "ny" (func $internal1358))
+ (import "env" "oy" (func $internal1359))
+ (import "env" "py" (func $internal1360))
+ (import "env" "qy" (func $internal1361))
+ (import "env" "ry" (func $internal1362))
+ (import "env" "sy" (func $internal1363))
+ (import "env" "ty" (func $internal1364))
+ (import "env" "uy" (func $internal1365))
+ (import "env" "vy" (func $internal1366))
+ (import "env" "wy" (func $internal1367))
+ (import "env" "xy" (func $internal1368))
+ (import "env" "yy" (func $internal1369))
+ (import "env" "zy" (func $internal1370))
+ (import "env" "Ay" (func $internal1371))
+ (import "env" "By" (func $internal1372))
+ (import "env" "Cy" (func $internal1373))
+ (import "env" "Dy" (func $internal1374))
+ (import "env" "Ey" (func $internal1375))
+ (import "env" "Fy" (func $internal1376))
+ (import "env" "Gy" (func $internal1377))
+ (import "env" "Hy" (func $internal1378))
+ (import "env" "Iy" (func $internal1379))
+ (import "env" "Jy" (func $internal1380))
+ (import "env" "Ky" (func $internal1381))
+ (import "env" "Ly" (func $internal1382))
+ (import "env" "My" (func $internal1383))
+ (import "env" "Ny" (func $internal1384))
+ (import "env" "Oy" (func $internal1385))
+ (import "env" "Py" (func $internal1386))
+ (import "env" "Qy" (func $internal1387))
+ (import "env" "Ry" (func $internal1388))
+ (import "env" "Sy" (func $internal1389))
+ (import "env" "Ty" (func $internal1390))
+ (import "env" "Uy" (func $internal1391))
+ (import "env" "Vy" (func $internal1392))
+ (import "env" "Wy" (func $internal1393))
+ (import "env" "Xy" (func $internal1394))
+ (import "env" "Yy" (func $internal1395))
+ (import "env" "Zy" (func $internal1396))
+ (import "env" "_y" (func $internal1397))
+ (import "env" "$y" (func $internal1398))
+ (import "env" "az" (func $internal1399))
+ (import "env" "bz" (func $internal1400))
+ (import "env" "cz" (func $internal1401))
+ (import "env" "dz" (func $internal1402))
+ (import "env" "ez" (func $internal1403))
+ (import "env" "fz" (func $internal1404))
+ (import "env" "gz" (func $internal1405))
+ (import "env" "hz" (func $internal1406))
+ (import "env" "iz" (func $internal1407))
+ (import "env" "jz" (func $internal1408))
+ (import "env" "kz" (func $internal1409))
+ (import "env" "lz" (func $internal1410))
+ (import "env" "mz" (func $internal1411))
+ (import "env" "nz" (func $internal1412))
+ (import "env" "oz" (func $internal1413))
+ (import "env" "pz" (func $internal1414))
+ (import "env" "qz" (func $internal1415))
+ (import "env" "rz" (func $internal1416))
+ (import "env" "sz" (func $internal1417))
+ (import "env" "tz" (func $internal1418))
+ (import "env" "uz" (func $internal1419))
+ (import "env" "vz" (func $internal1420))
+ (import "env" "wz" (func $internal1421))
+ (import "env" "xz" (func $internal1422))
+ (import "env" "yz" (func $internal1423))
+ (import "env" "zz" (func $internal1424))
+ (import "env" "Az" (func $internal1425))
+ (import "env" "Bz" (func $internal1426))
+ (import "env" "Cz" (func $internal1427))
+ (import "env" "Dz" (func $internal1428))
+ (import "env" "Ez" (func $internal1429))
+ (import "env" "Fz" (func $internal1430))
+ (import "env" "Gz" (func $internal1431))
+ (import "env" "Hz" (func $internal1432))
+ (import "env" "Iz" (func $internal1433))
+ (import "env" "Jz" (func $internal1434))
+ (import "env" "Kz" (func $internal1435))
+ (import "env" "Lz" (func $internal1436))
+ (import "env" "Mz" (func $internal1437))
+ (import "env" "Nz" (func $internal1438))
+ (import "env" "Oz" (func $internal1439))
+ (import "env" "Pz" (func $internal1440))
+ (import "env" "Qz" (func $internal1441))
+ (import "env" "Rz" (func $internal1442))
+ (import "env" "Sz" (func $internal1443))
+ (import "env" "Tz" (func $internal1444))
+ (import "env" "Uz" (func $internal1445))
+ (import "env" "Vz" (func $internal1446))
+ (import "env" "Wz" (func $internal1447))
+ (import "env" "Xz" (func $internal1448))
+ (import "env" "Yz" (func $internal1449))
+ (import "env" "Zz" (func $internal1450))
+ (import "env" "_z" (func $internal1451))
+ (import "env" "$z" (func $internal1452))
+ (import "env" "aA" (func $internal1453))
+ (import "env" "bA" (func $internal1454))
+ (import "env" "cA" (func $internal1455))
+ (import "env" "dA" (func $internal1456))
+ (import "env" "eA" (func $internal1457))
+ (import "env" "fA" (func $internal1458))
+ (import "env" "gA" (func $internal1459))
+ (import "env" "hA" (func $internal1460))
+ (import "env" "iA" (func $internal1461))
+ (import "env" "jA" (func $internal1462))
+ (import "env" "kA" (func $internal1463))
+ (import "env" "lA" (func $internal1464))
+ (import "env" "mA" (func $internal1465))
+ (import "env" "nA" (func $internal1466))
+ (import "env" "oA" (func $internal1467))
+ (import "env" "pA" (func $internal1468))
+ (import "env" "qA" (func $internal1469))
+ (import "env" "rA" (func $internal1470))
+ (import "env" "sA" (func $internal1471))
+ (import "env" "tA" (func $internal1472))
+ (import "env" "uA" (func $internal1473))
+ (import "env" "vA" (func $internal1474))
+ (import "env" "wA" (func $internal1475))
+ (import "env" "xA" (func $internal1476))
+ (import "env" "yA" (func $internal1477))
+ (import "env" "zA" (func $internal1478))
+ (import "env" "AA" (func $internal1479))
+ (import "env" "BA" (func $internal1480))
+ (import "env" "CA" (func $internal1481))
+ (import "env" "DA" (func $internal1482))
+ (import "env" "EA" (func $internal1483))
+ (import "env" "FA" (func $internal1484))
+ (import "env" "GA" (func $internal1485))
+ (import "env" "HA" (func $internal1486))
+ (import "env" "IA" (func $internal1487))
+ (import "env" "JA" (func $internal1488))
+ (import "env" "KA" (func $internal1489))
+ (import "env" "LA" (func $internal1490))
+ (import "env" "MA" (func $internal1491))
+ (import "env" "NA" (func $internal1492))
+ (import "env" "OA" (func $internal1493))
+ (import "env" "PA" (func $internal1494))
+ (import "env" "QA" (func $internal1495))
+ (import "env" "RA" (func $internal1496))
+ (import "env" "SA" (func $internal1497))
+ (import "env" "TA" (func $internal1498))
+ (import "env" "UA" (func $internal1499))
+ (import "env" "VA" (func $internal1500))
+ (import "env" "WA" (func $internal1501))
+ (import "env" "XA" (func $internal1502))
+ (import "env" "YA" (func $internal1503))
+ (import "env" "ZA" (func $internal1504))
+ (import "env" "_A" (func $internal1505))
+ (import "env" "$A" (func $internal1506))
+ (import "env" "aB" (func $internal1507))
+ (import "env" "bB" (func $internal1508))
+ (import "env" "cB" (func $internal1509))
+ (import "env" "dB" (func $internal1510))
+ (import "env" "eB" (func $internal1511))
+ (import "env" "fB" (func $internal1512))
+ (import "env" "gB" (func $internal1513))
+ (import "env" "hB" (func $internal1514))
+ (import "env" "iB" (func $internal1515))
+ (import "env" "jB" (func $internal1516))
+ (import "env" "kB" (func $internal1517))
+ (import "env" "lB" (func $internal1518))
+ (import "env" "mB" (func $internal1519))
+ (import "env" "nB" (func $internal1520))
+ (import "env" "oB" (func $internal1521))
+ (import "env" "pB" (func $internal1522))
+ (import "env" "qB" (func $internal1523))
+ (import "env" "rB" (func $internal1524))
+ (import "env" "sB" (func $internal1525))
+ (import "env" "tB" (func $internal1526))
+ (import "env" "uB" (func $internal1527))
+ (import "env" "vB" (func $internal1528))
+ (import "env" "wB" (func $internal1529))
+ (import "env" "xB" (func $internal1530))
+ (import "env" "yB" (func $internal1531))
+ (import "env" "zB" (func $internal1532))
+ (import "env" "AB" (func $internal1533))
+ (import "env" "BB" (func $internal1534))
+ (import "env" "CB" (func $internal1535))
+ (import "env" "DB" (func $internal1536))
+ (import "env" "EB" (func $internal1537))
+ (import "env" "FB" (func $internal1538))
+ (import "env" "GB" (func $internal1539))
+ (import "env" "HB" (func $internal1540))
+ (import "env" "IB" (func $internal1541))
+ (import "env" "JB" (func $internal1542))
+ (import "env" "KB" (func $internal1543))
+ (import "env" "LB" (func $internal1544))
+ (import "env" "MB" (func $internal1545))
+ (import "env" "NB" (func $internal1546))
+ (import "env" "OB" (func $internal1547))
+ (import "env" "PB" (func $internal1548))
+ (import "env" "QB" (func $internal1549))
+ (import "env" "RB" (func $internal1550))
+ (import "env" "SB" (func $internal1551))
+ (import "env" "TB" (func $internal1552))
+ (import "env" "UB" (func $internal1553))
+ (import "env" "VB" (func $internal1554))
+ (import "env" "WB" (func $internal1555))
+ (import "env" "XB" (func $internal1556))
+ (import "env" "YB" (func $internal1557))
+ (import "env" "ZB" (func $internal1558))
+ (import "env" "_B" (func $internal1559))
+ (import "env" "$B" (func $internal1560))
+ (import "env" "aC" (func $internal1561))
+ (import "env" "bC" (func $internal1562))
+ (import "env" "cC" (func $internal1563))
+ (import "env" "dC" (func $internal1564))
+ (import "env" "eC" (func $internal1565))
+ (import "env" "fC" (func $internal1566))
+ (import "env" "gC" (func $internal1567))
+ (import "env" "hC" (func $internal1568))
+ (import "env" "iC" (func $internal1569))
+ (import "env" "jC" (func $internal1570))
+ (import "env" "kC" (func $internal1571))
+ (import "env" "lC" (func $internal1572))
+ (import "env" "mC" (func $internal1573))
+ (import "env" "nC" (func $internal1574))
+ (import "env" "oC" (func $internal1575))
+ (import "env" "pC" (func $internal1576))
+ (import "env" "qC" (func $internal1577))
+ (import "env" "rC" (func $internal1578))
+ (import "env" "sC" (func $internal1579))
+ (import "env" "tC" (func $internal1580))
+ (import "env" "uC" (func $internal1581))
+ (import "env" "vC" (func $internal1582))
+ (import "env" "wC" (func $internal1583))
+ (import "env" "xC" (func $internal1584))
+ (import "env" "yC" (func $internal1585))
+ (import "env" "zC" (func $internal1586))
+ (import "env" "AC" (func $internal1587))
+ (import "env" "BC" (func $internal1588))
+ (import "env" "CC" (func $internal1589))
+ (import "env" "DC" (func $internal1590))
+ (import "env" "EC" (func $internal1591))
+ (import "env" "FC" (func $internal1592))
+ (import "env" "GC" (func $internal1593))
+ (import "env" "HC" (func $internal1594))
+ (import "env" "IC" (func $internal1595))
+ (import "env" "JC" (func $internal1596))
+ (import "env" "KC" (func $internal1597))
+ (import "env" "LC" (func $internal1598))
+ (import "env" "MC" (func $internal1599))
+ (import "env" "NC" (func $internal1600))
+ (import "env" "OC" (func $internal1601))
+ (import "env" "PC" (func $internal1602))
+ (import "env" "QC" (func $internal1603))
+ (import "env" "RC" (func $internal1604))
+ (import "env" "SC" (func $internal1605))
+ (import "env" "TC" (func $internal1606))
+ (import "env" "UC" (func $internal1607))
+ (import "env" "VC" (func $internal1608))
+ (import "env" "WC" (func $internal1609))
+ (import "env" "XC" (func $internal1610))
+ (import "env" "YC" (func $internal1611))
+ (import "env" "ZC" (func $internal1612))
+ (import "env" "_C" (func $internal1613))
+ (import "env" "$C" (func $internal1614))
+ (import "env" "aD" (func $internal1615))
+ (import "env" "bD" (func $internal1616))
+ (import "env" "cD" (func $internal1617))
+ (import "env" "dD" (func $internal1618))
+ (import "env" "eD" (func $internal1619))
+ (import "env" "fD" (func $internal1620))
+ (import "env" "gD" (func $internal1621))
+ (import "env" "hD" (func $internal1622))
+ (import "env" "iD" (func $internal1623))
+ (import "env" "jD" (func $internal1624))
+ (import "env" "kD" (func $internal1625))
+ (import "env" "lD" (func $internal1626))
+ (import "env" "mD" (func $internal1627))
+ (import "env" "nD" (func $internal1628))
+ (import "env" "oD" (func $internal1629))
+ (import "env" "pD" (func $internal1630))
+ (import "env" "qD" (func $internal1631))
+ (import "env" "rD" (func $internal1632))
+ (import "env" "sD" (func $internal1633))
+ (import "env" "tD" (func $internal1634))
+ (import "env" "uD" (func $internal1635))
+ (import "env" "vD" (func $internal1636))
+ (import "env" "wD" (func $internal1637))
+ (import "env" "xD" (func $internal1638))
+ (import "env" "yD" (func $internal1639))
+ (import "env" "zD" (func $internal1640))
+ (import "env" "AD" (func $internal1641))
+ (import "env" "BD" (func $internal1642))
+ (import "env" "CD" (func $internal1643))
+ (import "env" "DD" (func $internal1644))
+ (import "env" "ED" (func $internal1645))
+ (import "env" "FD" (func $internal1646))
+ (import "env" "GD" (func $internal1647))
+ (import "env" "HD" (func $internal1648))
+ (import "env" "ID" (func $internal1649))
+ (import "env" "JD" (func $internal1650))
+ (import "env" "KD" (func $internal1651))
+ (import "env" "LD" (func $internal1652))
+ (import "env" "MD" (func $internal1653))
+ (import "env" "ND" (func $internal1654))
+ (import "env" "OD" (func $internal1655))
+ (import "env" "PD" (func $internal1656))
+ (import "env" "QD" (func $internal1657))
+ (import "env" "RD" (func $internal1658))
+ (import "env" "SD" (func $internal1659))
+ (import "env" "TD" (func $internal1660))
+ (import "env" "UD" (func $internal1661))
+ (import "env" "VD" (func $internal1662))
+ (import "env" "WD" (func $internal1663))
+ (import "env" "XD" (func $internal1664))
+ (import "env" "YD" (func $internal1665))
+ (import "env" "ZD" (func $internal1666))
+ (import "env" "_D" (func $internal1667))
+ (import "env" "$D" (func $internal1668))
+ (import "env" "aE" (func $internal1669))
+ (import "env" "bE" (func $internal1670))
+ (import "env" "cE" (func $internal1671))
+ (import "env" "dE" (func $internal1672))
+ (import "env" "eE" (func $internal1673))
+ (import "env" "fE" (func $internal1674))
+ (import "env" "gE" (func $internal1675))
+ (import "env" "hE" (func $internal1676))
+ (import "env" "iE" (func $internal1677))
+ (import "env" "jE" (func $internal1678))
+ (import "env" "kE" (func $internal1679))
+ (import "env" "lE" (func $internal1680))
+ (import "env" "mE" (func $internal1681))
+ (import "env" "nE" (func $internal1682))
+ (import "env" "oE" (func $internal1683))
+ (import "env" "pE" (func $internal1684))
+ (import "env" "qE" (func $internal1685))
+ (import "env" "rE" (func $internal1686))
+ (import "env" "sE" (func $internal1687))
+ (import "env" "tE" (func $internal1688))
+ (import "env" "uE" (func $internal1689))
+ (import "env" "vE" (func $internal1690))
+ (import "env" "wE" (func $internal1691))
+ (import "env" "xE" (func $internal1692))
+ (import "env" "yE" (func $internal1693))
+ (import "env" "zE" (func $internal1694))
+ (import "env" "AE" (func $internal1695))
+ (import "env" "BE" (func $internal1696))
+ (import "env" "CE" (func $internal1697))
+ (import "env" "DE" (func $internal1698))
+ (import "env" "EE" (func $internal1699))
+ (import "env" "FE" (func $internal1700))
+ (import "env" "GE" (func $internal1701))
+ (import "env" "HE" (func $internal1702))
+ (import "env" "IE" (func $internal1703))
+ (import "env" "JE" (func $internal1704))
+ (import "env" "KE" (func $internal1705))
+ (import "env" "LE" (func $internal1706))
+ (import "env" "ME" (func $internal1707))
+ (import "env" "NE" (func $internal1708))
+ (import "env" "OE" (func $internal1709))
+ (import "env" "PE" (func $internal1710))
+ (import "env" "QE" (func $internal1711))
+ (import "env" "RE" (func $internal1712))
+ (import "env" "SE" (func $internal1713))
+ (import "env" "TE" (func $internal1714))
+ (import "env" "UE" (func $internal1715))
+ (import "env" "VE" (func $internal1716))
+ (import "env" "WE" (func $internal1717))
+ (import "env" "XE" (func $internal1718))
+ (import "env" "YE" (func $internal1719))
+ (import "env" "ZE" (func $internal1720))
+ (import "env" "_E" (func $internal1721))
+ (import "env" "$E" (func $internal1722))
+ (import "env" "aF" (func $internal1723))
+ (import "env" "bF" (func $internal1724))
+ (import "env" "cF" (func $internal1725))
+ (import "env" "dF" (func $internal1726))
+ (import "env" "eF" (func $internal1727))
+ (import "env" "fF" (func $internal1728))
+ (import "env" "gF" (func $internal1729))
+ (import "env" "hF" (func $internal1730))
+ (import "env" "iF" (func $internal1731))
+ (import "env" "jF" (func $internal1732))
+ (import "env" "kF" (func $internal1733))
+ (import "env" "lF" (func $internal1734))
+ (import "env" "mF" (func $internal1735))
+ (import "env" "nF" (func $internal1736))
+ (import "env" "oF" (func $internal1737))
+ (import "env" "pF" (func $internal1738))
+ (import "env" "qF" (func $internal1739))
+ (import "env" "rF" (func $internal1740))
+ (import "env" "sF" (func $internal1741))
+ (import "env" "tF" (func $internal1742))
+ (import "env" "uF" (func $internal1743))
+ (import "env" "vF" (func $internal1744))
+ (import "env" "wF" (func $internal1745))
+ (import "env" "xF" (func $internal1746))
+ (import "env" "yF" (func $internal1747))
+ (import "env" "zF" (func $internal1748))
+ (import "env" "AF" (func $internal1749))
+ (import "env" "BF" (func $internal1750))
+ (import "env" "CF" (func $internal1751))
+ (import "env" "DF" (func $internal1752))
+ (import "env" "EF" (func $internal1753))
+ (import "env" "FF" (func $internal1754))
+ (import "env" "GF" (func $internal1755))
+ (import "env" "HF" (func $internal1756))
+ (import "env" "IF" (func $internal1757))
+ (import "env" "JF" (func $internal1758))
+ (import "env" "KF" (func $internal1759))
+ (import "env" "LF" (func $internal1760))
+ (import "env" "MF" (func $internal1761))
+ (import "env" "NF" (func $internal1762))
+ (import "env" "OF" (func $internal1763))
+ (import "env" "PF" (func $internal1764))
+ (import "env" "QF" (func $internal1765))
+ (import "env" "RF" (func $internal1766))
+ (import "env" "SF" (func $internal1767))
+ (import "env" "TF" (func $internal1768))
+ (import "env" "UF" (func $internal1769))
+ (import "env" "VF" (func $internal1770))
+ (import "env" "WF" (func $internal1771))
+ (import "env" "XF" (func $internal1772))
+ (import "env" "YF" (func $internal1773))
+ (import "env" "ZF" (func $internal1774))
+ (import "env" "_F" (func $internal1775))
+ (import "env" "$F" (func $internal1776))
+ (import "env" "aG" (func $internal1777))
+ (import "env" "bG" (func $internal1778))
+ (import "env" "cG" (func $internal1779))
+ (import "env" "dG" (func $internal1780))
+ (import "env" "eG" (func $internal1781))
+ (import "env" "fG" (func $internal1782))
+ (import "env" "gG" (func $internal1783))
+ (import "env" "hG" (func $internal1784))
+ (import "env" "iG" (func $internal1785))
+ (import "env" "jG" (func $internal1786))
+ (import "env" "kG" (func $internal1787))
+ (import "env" "lG" (func $internal1788))
+ (import "env" "mG" (func $internal1789))
+ (import "env" "nG" (func $internal1790))
+ (import "env" "oG" (func $internal1791))
+ (import "env" "pG" (func $internal1792))
+ (import "env" "qG" (func $internal1793))
+ (import "env" "rG" (func $internal1794))
+ (import "env" "sG" (func $internal1795))
+ (import "env" "tG" (func $internal1796))
+ (import "env" "uG" (func $internal1797))
+ (import "env" "vG" (func $internal1798))
+ (import "env" "wG" (func $internal1799))
+ (import "env" "xG" (func $internal1800))
+ (import "env" "yG" (func $internal1801))
+ (import "env" "zG" (func $internal1802))
+ (import "env" "AG" (func $internal1803))
+ (import "env" "BG" (func $internal1804))
+ (import "env" "CG" (func $internal1805))
+ (import "env" "DG" (func $internal1806))
+ (import "env" "EG" (func $internal1807))
+ (import "env" "FG" (func $internal1808))
+ (import "env" "GG" (func $internal1809))
+ (import "env" "HG" (func $internal1810))
+ (import "env" "IG" (func $internal1811))
+ (import "env" "JG" (func $internal1812))
+ (import "env" "KG" (func $internal1813))
+ (import "env" "LG" (func $internal1814))
+ (import "env" "MG" (func $internal1815))
+ (import "env" "NG" (func $internal1816))
+ (import "env" "OG" (func $internal1817))
+ (import "env" "PG" (func $internal1818))
+ (import "env" "QG" (func $internal1819))
+ (import "env" "RG" (func $internal1820))
+ (import "env" "SG" (func $internal1821))
+ (import "env" "TG" (func $internal1822))
+ (import "env" "UG" (func $internal1823))
+ (import "env" "VG" (func $internal1824))
+ (import "env" "WG" (func $internal1825))
+ (import "env" "XG" (func $internal1826))
+ (import "env" "YG" (func $internal1827))
+ (import "env" "ZG" (func $internal1828))
+ (import "env" "_G" (func $internal1829))
+ (import "env" "$G" (func $internal1830))
+ (import "env" "aH" (func $internal1831))
+ (import "env" "bH" (func $internal1832))
+ (import "env" "cH" (func $internal1833))
+ (import "env" "dH" (func $internal1834))
+ (import "env" "eH" (func $internal1835))
+ (import "env" "fH" (func $internal1836))
+ (import "env" "gH" (func $internal1837))
+ (import "env" "hH" (func $internal1838))
+ (import "env" "iH" (func $internal1839))
+ (import "env" "jH" (func $internal1840))
+ (import "env" "kH" (func $internal1841))
+ (import "env" "lH" (func $internal1842))
+ (import "env" "mH" (func $internal1843))
+ (import "env" "nH" (func $internal1844))
+ (import "env" "oH" (func $internal1845))
+ (import "env" "pH" (func $internal1846))
+ (import "env" "qH" (func $internal1847))
+ (import "env" "rH" (func $internal1848))
+ (import "env" "sH" (func $internal1849))
+ (import "env" "tH" (func $internal1850))
+ (import "env" "uH" (func $internal1851))
+ (import "env" "vH" (func $internal1852))
+ (import "env" "wH" (func $internal1853))
+ (import "env" "xH" (func $internal1854))
+ (import "env" "yH" (func $internal1855))
+ (import "env" "zH" (func $internal1856))
+ (import "env" "AH" (func $internal1857))
+ (import "env" "BH" (func $internal1858))
+ (import "env" "CH" (func $internal1859))
+ (import "env" "DH" (func $internal1860))
+ (import "env" "EH" (func $internal1861))
+ (import "env" "FH" (func $internal1862))
+ (import "env" "GH" (func $internal1863))
+ (import "env" "HH" (func $internal1864))
+ (import "env" "IH" (func $internal1865))
+ (import "env" "JH" (func $internal1866))
+ (import "env" "KH" (func $internal1867))
+ (import "env" "LH" (func $internal1868))
+ (import "env" "MH" (func $internal1869))
+ (import "env" "NH" (func $internal1870))
+ (import "env" "OH" (func $internal1871))
+ (import "env" "PH" (func $internal1872))
+ (import "env" "QH" (func $internal1873))
+ (import "env" "RH" (func $internal1874))
+ (import "env" "SH" (func $internal1875))
+ (import "env" "TH" (func $internal1876))
+ (import "env" "UH" (func $internal1877))
+ (import "env" "VH" (func $internal1878))
+ (import "env" "WH" (func $internal1879))
+ (import "env" "XH" (func $internal1880))
+ (import "env" "YH" (func $internal1881))
+ (import "env" "ZH" (func $internal1882))
+ (import "env" "_H" (func $internal1883))
+ (import "env" "$H" (func $internal1884))
+ (import "env" "aI" (func $internal1885))
+ (import "env" "bI" (func $internal1886))
+ (import "env" "cI" (func $internal1887))
+ (import "env" "dI" (func $internal1888))
+ (import "env" "eI" (func $internal1889))
+ (import "env" "fI" (func $internal1890))
+ (import "env" "gI" (func $internal1891))
+ (import "env" "hI" (func $internal1892))
+ (import "env" "iI" (func $internal1893))
+ (import "env" "jI" (func $internal1894))
+ (import "env" "kI" (func $internal1895))
+ (import "env" "lI" (func $internal1896))
+ (import "env" "mI" (func $internal1897))
+ (import "env" "nI" (func $internal1898))
+ (import "env" "oI" (func $internal1899))
+ (import "env" "pI" (func $internal1900))
+ (import "env" "qI" (func $internal1901))
+ (import "env" "rI" (func $internal1902))
+ (import "env" "sI" (func $internal1903))
+ (import "env" "tI" (func $internal1904))
+ (import "env" "uI" (func $internal1905))
+ (import "env" "vI" (func $internal1906))
+ (import "env" "wI" (func $internal1907))
+ (import "env" "xI" (func $internal1908))
+ (import "env" "yI" (func $internal1909))
+ (import "env" "zI" (func $internal1910))
+ (import "env" "AI" (func $internal1911))
+ (import "env" "BI" (func $internal1912))
+ (import "env" "CI" (func $internal1913))
+ (import "env" "DI" (func $internal1914))
+ (import "env" "EI" (func $internal1915))
+ (import "env" "FI" (func $internal1916))
+ (import "env" "GI" (func $internal1917))
+ (import "env" "HI" (func $internal1918))
+ (import "env" "II" (func $internal1919))
+ (import "env" "JI" (func $internal1920))
+ (import "env" "KI" (func $internal1921))
+ (import "env" "LI" (func $internal1922))
+ (import "env" "MI" (func $internal1923))
+ (import "env" "NI" (func $internal1924))
+ (import "env" "OI" (func $internal1925))
+ (import "env" "PI" (func $internal1926))
+ (import "env" "QI" (func $internal1927))
+ (import "env" "RI" (func $internal1928))
+ (import "env" "SI" (func $internal1929))
+ (import "env" "TI" (func $internal1930))
+ (import "env" "UI" (func $internal1931))
+ (import "env" "VI" (func $internal1932))
+ (import "env" "WI" (func $internal1933))
+ (import "env" "XI" (func $internal1934))
+ (import "env" "YI" (func $internal1935))
+ (import "env" "ZI" (func $internal1936))
+ (import "env" "_I" (func $internal1937))
+ (import "env" "$I" (func $internal1938))
+ (import "env" "aJ" (func $internal1939))
+ (import "env" "bJ" (func $internal1940))
+ (import "env" "cJ" (func $internal1941))
+ (import "env" "dJ" (func $internal1942))
+ (import "env" "eJ" (func $internal1943))
+ (import "env" "fJ" (func $internal1944))
+ (import "env" "gJ" (func $internal1945))
+ (import "env" "hJ" (func $internal1946))
+ (import "env" "iJ" (func $internal1947))
+ (import "env" "jJ" (func $internal1948))
+ (import "env" "kJ" (func $internal1949))
+ (import "env" "lJ" (func $internal1950))
+ (import "env" "mJ" (func $internal1951))
+ (import "env" "nJ" (func $internal1952))
+ (import "env" "oJ" (func $internal1953))
+ (import "env" "pJ" (func $internal1954))
+ (import "env" "qJ" (func $internal1955))
+ (import "env" "rJ" (func $internal1956))
+ (import "env" "sJ" (func $internal1957))
+ (import "env" "tJ" (func $internal1958))
+ (import "env" "uJ" (func $internal1959))
+ (import "env" "vJ" (func $internal1960))
+ (import "env" "wJ" (func $internal1961))
+ (import "env" "xJ" (func $internal1962))
+ (import "env" "yJ" (func $internal1963))
+ (import "env" "zJ" (func $internal1964))
+ (import "env" "AJ" (func $internal1965))
+ (import "env" "BJ" (func $internal1966))
+ (import "env" "CJ" (func $internal1967))
+ (import "env" "DJ" (func $internal1968))
+ (import "env" "EJ" (func $internal1969))
+ (import "env" "FJ" (func $internal1970))
+ (import "env" "GJ" (func $internal1971))
+ (import "env" "HJ" (func $internal1972))
+ (import "env" "IJ" (func $internal1973))
+ (import "env" "JJ" (func $internal1974))
+ (import "env" "KJ" (func $internal1975))
+ (import "env" "LJ" (func $internal1976))
+ (import "env" "MJ" (func $internal1977))
+ (import "env" "NJ" (func $internal1978))
+ (import "env" "OJ" (func $internal1979))
+ (import "env" "PJ" (func $internal1980))
+ (import "env" "QJ" (func $internal1981))
+ (import "env" "RJ" (func $internal1982))
+ (import "env" "SJ" (func $internal1983))
+ (import "env" "TJ" (func $internal1984))
+ (import "env" "UJ" (func $internal1985))
+ (import "env" "VJ" (func $internal1986))
+ (import "env" "WJ" (func $internal1987))
+ (import "env" "XJ" (func $internal1988))
+ (import "env" "YJ" (func $internal1989))
+ (import "env" "ZJ" (func $internal1990))
+ (import "env" "_J" (func $internal1991))
+ (import "env" "$J" (func $internal1992))
+ (import "env" "aK" (func $internal1993))
+ (import "env" "bK" (func $internal1994))
+ (import "env" "cK" (func $internal1995))
+ (import "env" "dK" (func $internal1996))
+ (import "env" "eK" (func $internal1997))
+ (import "env" "fK" (func $internal1998))
+ (import "env" "gK" (func $internal1999))
+ (import "env" "hK" (func $internal2000))
+ (import "env" "iK" (func $internal2001))
+ (import "env" "jK" (func $internal2002))
+ (import "env" "kK" (func $internal2003))
+ (import "env" "lK" (func $internal2004))
+ (import "env" "mK" (func $internal2005))
+ (import "env" "nK" (func $internal2006))
+ (import "env" "oK" (func $internal2007))
+ (import "env" "pK" (func $internal2008))
+ (import "env" "qK" (func $internal2009))
+ (import "env" "rK" (func $internal2010))
+ (import "env" "sK" (func $internal2011))
+ (import "env" "tK" (func $internal2012))
+ (import "env" "uK" (func $internal2013))
+ (import "env" "vK" (func $internal2014))
+ (import "env" "wK" (func $internal2015))
+ (import "env" "xK" (func $internal2016))
+ (import "env" "yK" (func $internal2017))
+ (import "env" "zK" (func $internal2018))
+ (import "env" "AK" (func $internal2019))
+ (import "env" "BK" (func $internal2020))
+ (import "env" "CK" (func $internal2021))
+ (import "env" "DK" (func $internal2022))
+ (import "env" "EK" (func $internal2023))
+ (import "env" "FK" (func $internal2024))
+ (import "env" "GK" (func $internal2025))
+ (import "env" "HK" (func $internal2026))
+ (import "env" "IK" (func $internal2027))
+ (import "env" "JK" (func $internal2028))
+ (import "env" "KK" (func $internal2029))
+ (import "env" "LK" (func $internal2030))
+ (import "env" "MK" (func $internal2031))
+ (import "env" "NK" (func $internal2032))
+ (import "env" "OK" (func $internal2033))
+ (import "env" "PK" (func $internal2034))
+ (import "env" "QK" (func $internal2035))
+ (import "env" "RK" (func $internal2036))
+ (import "env" "SK" (func $internal2037))
+ (import "env" "TK" (func $internal2038))
+ (import "env" "UK" (func $internal2039))
+ (import "env" "VK" (func $internal2040))
+ (import "env" "WK" (func $internal2041))
+ (import "env" "XK" (func $internal2042))
+ (import "env" "YK" (func $internal2043))
+ (import "env" "ZK" (func $internal2044))
+ (import "env" "_K" (func $internal2045))
+ (import "env" "$K" (func $internal2046))
+ (import "env" "aL" (func $internal2047))
+ (import "env" "bL" (func $internal2048))
+ (import "env" "cL" (func $internal2049))
+ (import "env" "dL" (func $internal2050))
+ (import "env" "eL" (func $internal2051))
+ (import "env" "fL" (func $internal2052))
+ (import "env" "gL" (func $internal2053))
+ (import "env" "hL" (func $internal2054))
+ (import "env" "iL" (func $internal2055))
+ (import "env" "jL" (func $internal2056))
+ (import "env" "kL" (func $internal2057))
+ (import "env" "lL" (func $internal2058))
+ (import "env" "mL" (func $internal2059))
+ (import "env" "nL" (func $internal2060))
+ (import "env" "oL" (func $internal2061))
+ (import "env" "pL" (func $internal2062))
+ (import "env" "qL" (func $internal2063))
+ (import "env" "rL" (func $internal2064))
+ (import "env" "sL" (func $internal2065))
+ (import "env" "tL" (func $internal2066))
+ (import "env" "uL" (func $internal2067))
+ (import "env" "vL" (func $internal2068))
+ (import "env" "wL" (func $internal2069))
+ (import "env" "xL" (func $internal2070))
+ (import "env" "yL" (func $internal2071))
+ (import "env" "zL" (func $internal2072))
+ (import "env" "AL" (func $internal2073))
+ (import "env" "BL" (func $internal2074))
+ (import "env" "CL" (func $internal2075))
+ (import "env" "DL" (func $internal2076))
+ (import "env" "EL" (func $internal2077))
+ (import "env" "FL" (func $internal2078))
+ (import "env" "GL" (func $internal2079))
+ (import "env" "HL" (func $internal2080))
+ (import "env" "IL" (func $internal2081))
+ (import "env" "JL" (func $internal2082))
+ (import "env" "KL" (func $internal2083))
+ (import "env" "LL" (func $internal2084))
+ (import "env" "ML" (func $internal2085))
+ (import "env" "NL" (func $internal2086))
+ (import "env" "OL" (func $internal2087))
+ (import "env" "PL" (func $internal2088))
+ (import "env" "QL" (func $internal2089))
+ (import "env" "RL" (func $internal2090))
+ (import "env" "SL" (func $internal2091))
+ (import "env" "TL" (func $internal2092))
+ (import "env" "UL" (func $internal2093))
+ (import "env" "VL" (func $internal2094))
+ (import "env" "WL" (func $internal2095))
+ (import "env" "XL" (func $internal2096))
+ (import "env" "YL" (func $internal2097))
+ (import "env" "ZL" (func $internal2098))
+ (import "env" "_L" (func $internal2099))
+ (import "env" "$L" (func $internal2100))
+ (import "env" "aM" (func $internal2101))
+ (import "env" "bM" (func $internal2102))
+ (import "env" "cM" (func $internal2103))
+ (import "env" "dM" (func $internal2104))
+ (import "env" "eM" (func $internal2105))
+ (import "env" "fM" (func $internal2106))
+ (import "env" "gM" (func $internal2107))
+ (import "env" "hM" (func $internal2108))
+ (import "env" "iM" (func $internal2109))
+ (import "env" "jM" (func $internal2110))
+ (import "env" "kM" (func $internal2111))
+ (import "env" "lM" (func $internal2112))
+ (import "env" "mM" (func $internal2113))
+ (import "env" "nM" (func $internal2114))
+ (import "env" "oM" (func $internal2115))
+ (import "env" "pM" (func $internal2116))
+ (import "env" "qM" (func $internal2117))
+ (import "env" "rM" (func $internal2118))
+ (import "env" "sM" (func $internal2119))
+ (import "env" "tM" (func $internal2120))
+ (import "env" "uM" (func $internal2121))
+ (import "env" "vM" (func $internal2122))
+ (import "env" "wM" (func $internal2123))
+ (import "env" "xM" (func $internal2124))
+ (import "env" "yM" (func $internal2125))
+ (import "env" "zM" (func $internal2126))
+ (import "env" "AM" (func $internal2127))
+ (import "env" "BM" (func $internal2128))
+ (import "env" "CM" (func $internal2129))
+ (import "env" "DM" (func $internal2130))
+ (import "env" "EM" (func $internal2131))
+ (import "env" "FM" (func $internal2132))
+ (import "env" "GM" (func $internal2133))
+ (import "env" "HM" (func $internal2134))
+ (import "env" "IM" (func $internal2135))
+ (import "env" "JM" (func $internal2136))
+ (import "env" "KM" (func $internal2137))
+ (import "env" "LM" (func $internal2138))
+ (import "env" "MM" (func $internal2139))
+ (import "env" "NM" (func $internal2140))
+ (import "env" "OM" (func $internal2141))
+ (import "env" "PM" (func $internal2142))
+ (import "env" "QM" (func $internal2143))
+ (import "env" "RM" (func $internal2144))
+ (import "env" "SM" (func $internal2145))
+ (import "env" "TM" (func $internal2146))
+ (import "env" "UM" (func $internal2147))
+ (import "env" "VM" (func $internal2148))
+ (import "env" "WM" (func $internal2149))
+ (import "env" "XM" (func $internal2150))
+ (import "env" "YM" (func $internal2151))
+ (import "env" "ZM" (func $internal2152))
+ (import "env" "_M" (func $internal2153))
+ (import "env" "$M" (func $internal2154))
+ (import "env" "aN" (func $internal2155))
+ (import "env" "bN" (func $internal2156))
+ (import "env" "cN" (func $internal2157))
+ (import "env" "dN" (func $internal2158))
+ (import "env" "eN" (func $internal2159))
+ (import "env" "fN" (func $internal2160))
+ (import "env" "gN" (func $internal2161))
+ (import "env" "hN" (func $internal2162))
+ (import "env" "iN" (func $internal2163))
+ (import "env" "jN" (func $internal2164))
+ (import "env" "kN" (func $internal2165))
+ (import "env" "lN" (func $internal2166))
+ (import "env" "mN" (func $internal2167))
+ (import "env" "nN" (func $internal2168))
+ (import "env" "oN" (func $internal2169))
+ (import "env" "pN" (func $internal2170))
+ (import "env" "qN" (func $internal2171))
+ (import "env" "rN" (func $internal2172))
+ (import "env" "sN" (func $internal2173))
+ (import "env" "tN" (func $internal2174))
+ (import "env" "uN" (func $internal2175))
+ (import "env" "vN" (func $internal2176))
+ (import "env" "wN" (func $internal2177))
+ (import "env" "xN" (func $internal2178))
+ (import "env" "yN" (func $internal2179))
+ (import "env" "zN" (func $internal2180))
+ (import "env" "AN" (func $internal2181))
+ (import "env" "BN" (func $internal2182))
+ (import "env" "CN" (func $internal2183))
+ (import "env" "DN" (func $internal2184))
+ (import "env" "EN" (func $internal2185))
+ (import "env" "FN" (func $internal2186))
+ (import "env" "GN" (func $internal2187))
+ (import "env" "HN" (func $internal2188))
+ (import "env" "IN" (func $internal2189))
+ (import "env" "JN" (func $internal2190))
+ (import "env" "KN" (func $internal2191))
+ (import "env" "LN" (func $internal2192))
+ (import "env" "MN" (func $internal2193))
+ (import "env" "NN" (func $internal2194))
+ (import "env" "ON" (func $internal2195))
+ (import "env" "PN" (func $internal2196))
+ (import "env" "QN" (func $internal2197))
+ (import "env" "RN" (func $internal2198))
+ (import "env" "SN" (func $internal2199))
+ (import "env" "TN" (func $internal2200))
+ (import "env" "UN" (func $internal2201))
+ (import "env" "VN" (func $internal2202))
+ (import "env" "WN" (func $internal2203))
+ (import "env" "XN" (func $internal2204))
+ (import "env" "YN" (func $internal2205))
+ (import "env" "ZN" (func $internal2206))
+ (import "env" "_N" (func $internal2207))
+ (import "env" "$N" (func $internal2208))
+ (import "env" "aO" (func $internal2209))
+ (import "env" "bO" (func $internal2210))
+ (import "env" "cO" (func $internal2211))
+ (import "env" "dO" (func $internal2212))
+ (import "env" "eO" (func $internal2213))
+ (import "env" "fO" (func $internal2214))
+ (import "env" "gO" (func $internal2215))
+ (import "env" "hO" (func $internal2216))
+ (import "env" "iO" (func $internal2217))
+ (import "env" "jO" (func $internal2218))
+ (import "env" "kO" (func $internal2219))
+ (import "env" "lO" (func $internal2220))
+ (import "env" "mO" (func $internal2221))
+ (import "env" "nO" (func $internal2222))
+ (import "env" "oO" (func $internal2223))
+ (import "env" "pO" (func $internal2224))
+ (import "env" "qO" (func $internal2225))
+ (import "env" "rO" (func $internal2226))
+ (import "env" "sO" (func $internal2227))
+ (import "env" "tO" (func $internal2228))
+ (import "env" "uO" (func $internal2229))
+ (import "env" "vO" (func $internal2230))
+ (import "env" "wO" (func $internal2231))
+ (import "env" "xO" (func $internal2232))
+ (import "env" "yO" (func $internal2233))
+ (import "env" "zO" (func $internal2234))
+ (import "env" "AO" (func $internal2235))
+ (import "env" "BO" (func $internal2236))
+ (import "env" "CO" (func $internal2237))
+ (import "env" "DO" (func $internal2238))
+ (import "env" "EO" (func $internal2239))
+ (import "env" "FO" (func $internal2240))
+ (import "env" "GO" (func $internal2241))
+ (import "env" "HO" (func $internal2242))
+ (import "env" "IO" (func $internal2243))
+ (import "env" "JO" (func $internal2244))
+ (import "env" "KO" (func $internal2245))
+ (import "env" "LO" (func $internal2246))
+ (import "env" "MO" (func $internal2247))
+ (import "env" "NO" (func $internal2248))
+ (import "env" "OO" (func $internal2249))
+ (import "env" "PO" (func $internal2250))
+ (import "env" "QO" (func $internal2251))
+ (import "env" "RO" (func $internal2252))
+ (import "env" "SO" (func $internal2253))
+ (import "env" "TO" (func $internal2254))
+ (import "env" "UO" (func $internal2255))
+ (import "env" "VO" (func $internal2256))
+ (import "env" "WO" (func $internal2257))
+ (import "env" "XO" (func $internal2258))
+ (import "env" "YO" (func $internal2259))
+ (import "env" "ZO" (func $internal2260))
+ (import "env" "_O" (func $internal2261))
+ (import "env" "$O" (func $internal2262))
+ (import "env" "aP" (func $internal2263))
+ (import "env" "bP" (func $internal2264))
+ (import "env" "cP" (func $internal2265))
+ (import "env" "dP" (func $internal2266))
+ (import "env" "eP" (func $internal2267))
+ (import "env" "fP" (func $internal2268))
+ (import "env" "gP" (func $internal2269))
+ (import "env" "hP" (func $internal2270))
+ (import "env" "iP" (func $internal2271))
+ (import "env" "jP" (func $internal2272))
+ (import "env" "kP" (func $internal2273))
+ (import "env" "lP" (func $internal2274))
+ (import "env" "mP" (func $internal2275))
+ (import "env" "nP" (func $internal2276))
+ (import "env" "oP" (func $internal2277))
+ (import "env" "pP" (func $internal2278))
+ (import "env" "qP" (func $internal2279))
+ (import "env" "rP" (func $internal2280))
+ (import "env" "sP" (func $internal2281))
+ (import "env" "tP" (func $internal2282))
+ (import "env" "uP" (func $internal2283))
+ (import "env" "vP" (func $internal2284))
+ (import "env" "wP" (func $internal2285))
+ (import "env" "xP" (func $internal2286))
+ (import "env" "yP" (func $internal2287))
+ (import "env" "zP" (func $internal2288))
+ (import "env" "AP" (func $internal2289))
+ (import "env" "BP" (func $internal2290))
+ (import "env" "CP" (func $internal2291))
+ (import "env" "DP" (func $internal2292))
+ (import "env" "EP" (func $internal2293))
+ (import "env" "FP" (func $internal2294))
+ (import "env" "GP" (func $internal2295))
+ (import "env" "HP" (func $internal2296))
+ (import "env" "IP" (func $internal2297))
+ (import "env" "JP" (func $internal2298))
+ (import "env" "KP" (func $internal2299))
+ (import "env" "LP" (func $internal2300))
+ (import "env" "MP" (func $internal2301))
+ (import "env" "NP" (func $internal2302))
+ (import "env" "OP" (func $internal2303))
+ (import "env" "PP" (func $internal2304))
+ (import "env" "QP" (func $internal2305))
+ (import "env" "RP" (func $internal2306))
+ (import "env" "SP" (func $internal2307))
+ (import "env" "TP" (func $internal2308))
+ (import "env" "UP" (func $internal2309))
+ (import "env" "VP" (func $internal2310))
+ (import "env" "WP" (func $internal2311))
+ (import "env" "XP" (func $internal2312))
+ (import "env" "YP" (func $internal2313))
+ (import "env" "ZP" (func $internal2314))
+ (import "env" "_P" (func $internal2315))
+ (import "env" "$P" (func $internal2316))
+ (import "env" "aQ" (func $internal2317))
+ (import "env" "bQ" (func $internal2318))
+ (import "env" "cQ" (func $internal2319))
+ (import "env" "dQ" (func $internal2320))
+ (import "env" "eQ" (func $internal2321))
+ (import "env" "fQ" (func $internal2322))
+ (import "env" "gQ" (func $internal2323))
+ (import "env" "hQ" (func $internal2324))
+ (import "env" "iQ" (func $internal2325))
+ (import "env" "jQ" (func $internal2326))
+ (import "env" "kQ" (func $internal2327))
+ (import "env" "lQ" (func $internal2328))
+ (import "env" "mQ" (func $internal2329))
+ (import "env" "nQ" (func $internal2330))
+ (import "env" "oQ" (func $internal2331))
+ (import "env" "pQ" (func $internal2332))
+ (import "env" "qQ" (func $internal2333))
+ (import "env" "rQ" (func $internal2334))
+ (import "env" "sQ" (func $internal2335))
+ (import "env" "tQ" (func $internal2336))
+ (import "env" "uQ" (func $internal2337))
+ (import "env" "vQ" (func $internal2338))
+ (import "env" "wQ" (func $internal2339))
+ (import "env" "xQ" (func $internal2340))
+ (import "env" "yQ" (func $internal2341))
+ (import "env" "zQ" (func $internal2342))
+ (import "env" "AQ" (func $internal2343))
+ (import "env" "BQ" (func $internal2344))
+ (import "env" "CQ" (func $internal2345))
+ (import "env" "DQ" (func $internal2346))
+ (import "env" "EQ" (func $internal2347))
+ (import "env" "FQ" (func $internal2348))
+ (import "env" "GQ" (func $internal2349))
+ (import "env" "HQ" (func $internal2350))
+ (import "env" "IQ" (func $internal2351))
+ (import "env" "JQ" (func $internal2352))
+ (import "env" "KQ" (func $internal2353))
+ (import "env" "LQ" (func $internal2354))
+ (import "env" "MQ" (func $internal2355))
+ (import "env" "NQ" (func $internal2356))
+ (import "env" "OQ" (func $internal2357))
+ (import "env" "PQ" (func $internal2358))
+ (import "env" "QQ" (func $internal2359))
+ (import "env" "RQ" (func $internal2360))
+ (import "env" "SQ" (func $internal2361))
+ (import "env" "TQ" (func $internal2362))
+ (import "env" "UQ" (func $internal2363))
+ (import "env" "VQ" (func $internal2364))
+ (import "env" "WQ" (func $internal2365))
+ (import "env" "XQ" (func $internal2366))
+ (import "env" "YQ" (func $internal2367))
+ (import "env" "ZQ" (func $internal2368))
+ (import "env" "_Q" (func $internal2369))
+ (import "env" "$Q" (func $internal2370))
+ (import "env" "aR" (func $internal2371))
+ (import "env" "bR" (func $internal2372))
+ (import "env" "cR" (func $internal2373))
+ (import "env" "dR" (func $internal2374))
+ (import "env" "eR" (func $internal2375))
+ (import "env" "fR" (func $internal2376))
+ (import "env" "gR" (func $internal2377))
+ (import "env" "hR" (func $internal2378))
+ (import "env" "iR" (func $internal2379))
+ (import "env" "jR" (func $internal2380))
+ (import "env" "kR" (func $internal2381))
+ (import "env" "lR" (func $internal2382))
+ (import "env" "mR" (func $internal2383))
+ (import "env" "nR" (func $internal2384))
+ (import "env" "oR" (func $internal2385))
+ (import "env" "pR" (func $internal2386))
+ (import "env" "qR" (func $internal2387))
+ (import "env" "rR" (func $internal2388))
+ (import "env" "sR" (func $internal2389))
+ (import "env" "tR" (func $internal2390))
+ (import "env" "uR" (func $internal2391))
+ (import "env" "vR" (func $internal2392))
+ (import "env" "wR" (func $internal2393))
+ (import "env" "xR" (func $internal2394))
+ (import "env" "yR" (func $internal2395))
+ (import "env" "zR" (func $internal2396))
+ (import "env" "AR" (func $internal2397))
+ (import "env" "BR" (func $internal2398))
+ (import "env" "CR" (func $internal2399))
+ (import "env" "DR" (func $internal2400))
+ (import "env" "ER" (func $internal2401))
+ (import "env" "FR" (func $internal2402))
+ (import "env" "GR" (func $internal2403))
+ (import "env" "HR" (func $internal2404))
+ (import "env" "IR" (func $internal2405))
+ (import "env" "JR" (func $internal2406))
+ (import "env" "KR" (func $internal2407))
+ (import "env" "LR" (func $internal2408))
+ (import "env" "MR" (func $internal2409))
+ (import "env" "NR" (func $internal2410))
+ (import "env" "OR" (func $internal2411))
+ (import "env" "PR" (func $internal2412))
+ (import "env" "QR" (func $internal2413))
+ (import "env" "RR" (func $internal2414))
+ (import "env" "SR" (func $internal2415))
+ (import "env" "TR" (func $internal2416))
+ (import "env" "UR" (func $internal2417))
+ (import "env" "VR" (func $internal2418))
+ (import "env" "WR" (func $internal2419))
+ (import "env" "XR" (func $internal2420))
+ (import "env" "YR" (func $internal2421))
+ (import "env" "ZR" (func $internal2422))
+ (import "env" "_R" (func $internal2423))
+ (import "env" "$R" (func $internal2424))
+ (import "env" "aS" (func $internal2425))
+ (import "env" "bS" (func $internal2426))
+ (import "env" "cS" (func $internal2427))
+ (import "env" "dS" (func $internal2428))
+ (import "env" "eS" (func $internal2429))
+ (import "env" "fS" (func $internal2430))
+ (import "env" "gS" (func $internal2431))
+ (import "env" "hS" (func $internal2432))
+ (import "env" "iS" (func $internal2433))
+ (import "env" "jS" (func $internal2434))
+ (import "env" "kS" (func $internal2435))
+ (import "env" "lS" (func $internal2436))
+ (import "env" "mS" (func $internal2437))
+ (import "env" "nS" (func $internal2438))
+ (import "env" "oS" (func $internal2439))
+ (import "env" "pS" (func $internal2440))
+ (import "env" "qS" (func $internal2441))
+ (import "env" "rS" (func $internal2442))
+ (import "env" "sS" (func $internal2443))
+ (import "env" "tS" (func $internal2444))
+ (import "env" "uS" (func $internal2445))
+ (import "env" "vS" (func $internal2446))
+ (import "env" "wS" (func $internal2447))
+ (import "env" "xS" (func $internal2448))
+ (import "env" "yS" (func $internal2449))
+ (import "env" "zS" (func $internal2450))
+ (import "env" "AS" (func $internal2451))
+ (import "env" "BS" (func $internal2452))
+ (import "env" "CS" (func $internal2453))
+ (import "env" "DS" (func $internal2454))
+ (import "env" "ES" (func $internal2455))
+ (import "env" "FS" (func $internal2456))
+ (import "env" "GS" (func $internal2457))
+ (import "env" "HS" (func $internal2458))
+ (import "env" "IS" (func $internal2459))
+ (import "env" "JS" (func $internal2460))
+ (import "env" "KS" (func $internal2461))
+ (import "env" "LS" (func $internal2462))
+ (import "env" "MS" (func $internal2463))
+ (import "env" "NS" (func $internal2464))
+ (import "env" "OS" (func $internal2465))
+ (import "env" "PS" (func $internal2466))
+ (import "env" "QS" (func $internal2467))
+ (import "env" "RS" (func $internal2468))
+ (import "env" "SS" (func $internal2469))
+ (import "env" "TS" (func $internal2470))
+ (import "env" "US" (func $internal2471))
+ (import "env" "VS" (func $internal2472))
+ (import "env" "WS" (func $internal2473))
+ (import "env" "XS" (func $internal2474))
+ (import "env" "YS" (func $internal2475))
+ (import "env" "ZS" (func $internal2476))
+ (import "env" "_S" (func $internal2477))
+ (import "env" "$S" (func $internal2478))
+ (import "env" "aT" (func $internal2479))
+ (import "env" "bT" (func $internal2480))
+ (import "env" "cT" (func $internal2481))
+ (import "env" "dT" (func $internal2482))
+ (import "env" "eT" (func $internal2483))
+ (import "env" "fT" (func $internal2484))
+ (import "env" "gT" (func $internal2485))
+ (import "env" "hT" (func $internal2486))
+ (import "env" "iT" (func $internal2487))
+ (import "env" "jT" (func $internal2488))
+ (import "env" "kT" (func $internal2489))
+ (import "env" "lT" (func $internal2490))
+ (import "env" "mT" (func $internal2491))
+ (import "env" "nT" (func $internal2492))
+ (import "env" "oT" (func $internal2493))
+ (import "env" "pT" (func $internal2494))
+ (import "env" "qT" (func $internal2495))
+ (import "env" "rT" (func $internal2496))
+ (import "env" "sT" (func $internal2497))
+ (import "env" "tT" (func $internal2498))
+ (import "env" "uT" (func $internal2499))
+ (import "env" "vT" (func $internal2500))
+ (import "env" "wT" (func $internal2501))
+ (import "env" "xT" (func $internal2502))
+ (import "env" "yT" (func $internal2503))
+ (import "env" "zT" (func $internal2504))
+ (import "env" "AT" (func $internal2505))
+ (import "env" "BT" (func $internal2506))
+ (import "env" "CT" (func $internal2507))
+ (import "env" "DT" (func $internal2508))
+ (import "env" "ET" (func $internal2509))
+ (import "env" "FT" (func $internal2510))
+ (import "env" "GT" (func $internal2511))
+ (import "env" "HT" (func $internal2512))
+ (import "env" "IT" (func $internal2513))
+ (import "env" "JT" (func $internal2514))
+ (import "env" "KT" (func $internal2515))
+ (import "env" "LT" (func $internal2516))
+ (import "env" "MT" (func $internal2517))
+ (import "env" "NT" (func $internal2518))
+ (import "env" "OT" (func $internal2519))
+ (import "env" "PT" (func $internal2520))
+ (import "env" "QT" (func $internal2521))
+ (import "env" "RT" (func $internal2522))
+ (import "env" "ST" (func $internal2523))
+ (import "env" "TT" (func $internal2524))
+ (import "env" "UT" (func $internal2525))
+ (import "env" "VT" (func $internal2526))
+ (import "env" "WT" (func $internal2527))
+ (import "env" "XT" (func $internal2528))
+ (import "env" "YT" (func $internal2529))
+ (import "env" "ZT" (func $internal2530))
+ (import "env" "_T" (func $internal2531))
+ (import "env" "$T" (func $internal2532))
+ (import "env" "aU" (func $internal2533))
+ (import "env" "bU" (func $internal2534))
+ (import "env" "cU" (func $internal2535))
+ (import "env" "dU" (func $internal2536))
+ (import "env" "eU" (func $internal2537))
+ (import "env" "fU" (func $internal2538))
+ (import "env" "gU" (func $internal2539))
+ (import "env" "hU" (func $internal2540))
+ (import "env" "iU" (func $internal2541))
+ (import "env" "jU" (func $internal2542))
+ (import "env" "kU" (func $internal2543))
+ (import "env" "lU" (func $internal2544))
+ (import "env" "mU" (func $internal2545))
+ (import "env" "nU" (func $internal2546))
+ (import "env" "oU" (func $internal2547))
+ (import "env" "pU" (func $internal2548))
+ (import "env" "qU" (func $internal2549))
+ (import "env" "rU" (func $internal2550))
+ (import "env" "sU" (func $internal2551))
+ (import "env" "tU" (func $internal2552))
+ (import "env" "uU" (func $internal2553))
+ (import "env" "vU" (func $internal2554))
+ (import "env" "wU" (func $internal2555))
+ (import "env" "xU" (func $internal2556))
+ (import "env" "yU" (func $internal2557))
+ (import "env" "zU" (func $internal2558))
+ (import "env" "AU" (func $internal2559))
+ (import "env" "BU" (func $internal2560))
+ (import "env" "CU" (func $internal2561))
+ (import "env" "DU" (func $internal2562))
+ (import "env" "EU" (func $internal2563))
+ (import "env" "FU" (func $internal2564))
+ (import "env" "GU" (func $internal2565))
+ (import "env" "HU" (func $internal2566))
+ (import "env" "IU" (func $internal2567))
+ (import "env" "JU" (func $internal2568))
+ (import "env" "KU" (func $internal2569))
+ (import "env" "LU" (func $internal2570))
+ (import "env" "MU" (func $internal2571))
+ (import "env" "NU" (func $internal2572))
+ (import "env" "OU" (func $internal2573))
+ (import "env" "PU" (func $internal2574))
+ (import "env" "QU" (func $internal2575))
+ (import "env" "RU" (func $internal2576))
+ (import "env" "SU" (func $internal2577))
+ (import "env" "TU" (func $internal2578))
+ (import "env" "UU" (func $internal2579))
+ (import "env" "VU" (func $internal2580))
+ (import "env" "WU" (func $internal2581))
+ (import "env" "XU" (func $internal2582))
+ (import "env" "YU" (func $internal2583))
+ (import "env" "ZU" (func $internal2584))
+ (import "env" "_U" (func $internal2585))
+ (import "env" "$U" (func $internal2586))
+ (import "env" "aV" (func $internal2587))
+ (import "env" "bV" (func $internal2588))
+ (import "env" "cV" (func $internal2589))
+ (import "env" "dV" (func $internal2590))
+ (import "env" "eV" (func $internal2591))
+ (import "env" "fV" (func $internal2592))
+ (import "env" "gV" (func $internal2593))
+ (import "env" "hV" (func $internal2594))
+ (import "env" "iV" (func $internal2595))
+ (import "env" "jV" (func $internal2596))
+ (import "env" "kV" (func $internal2597))
+ (import "env" "lV" (func $internal2598))
+ (import "env" "mV" (func $internal2599))
+ (import "env" "nV" (func $internal2600))
+ (import "env" "oV" (func $internal2601))
+ (import "env" "pV" (func $internal2602))
+ (import "env" "qV" (func $internal2603))
+ (import "env" "rV" (func $internal2604))
+ (import "env" "sV" (func $internal2605))
+ (import "env" "tV" (func $internal2606))
+ (import "env" "uV" (func $internal2607))
+ (import "env" "vV" (func $internal2608))
+ (import "env" "wV" (func $internal2609))
+ (import "env" "xV" (func $internal2610))
+ (import "env" "yV" (func $internal2611))
+ (import "env" "zV" (func $internal2612))
+ (import "env" "AV" (func $internal2613))
+ (import "env" "BV" (func $internal2614))
+ (import "env" "CV" (func $internal2615))
+ (import "env" "DV" (func $internal2616))
+ (import "env" "EV" (func $internal2617))
+ (import "env" "FV" (func $internal2618))
+ (import "env" "GV" (func $internal2619))
+ (import "env" "HV" (func $internal2620))
+ (import "env" "IV" (func $internal2621))
+ (import "env" "JV" (func $internal2622))
+ (import "env" "KV" (func $internal2623))
+ (import "env" "LV" (func $internal2624))
+ (import "env" "MV" (func $internal2625))
+ (import "env" "NV" (func $internal2626))
+ (import "env" "OV" (func $internal2627))
+ (import "env" "PV" (func $internal2628))
+ (import "env" "QV" (func $internal2629))
+ (import "env" "RV" (func $internal2630))
+ (import "env" "SV" (func $internal2631))
+ (import "env" "TV" (func $internal2632))
+ (import "env" "UV" (func $internal2633))
+ (import "env" "VV" (func $internal2634))
+ (import "env" "WV" (func $internal2635))
+ (import "env" "XV" (func $internal2636))
+ (import "env" "YV" (func $internal2637))
+ (import "env" "ZV" (func $internal2638))
+ (import "env" "_V" (func $internal2639))
+ (import "env" "$V" (func $internal2640))
+ (import "env" "aW" (func $internal2641))
+ (import "env" "bW" (func $internal2642))
+ (import "env" "cW" (func $internal2643))
+ (import "env" "dW" (func $internal2644))
+ (import "env" "eW" (func $internal2645))
+ (import "env" "fW" (func $internal2646))
+ (import "env" "gW" (func $internal2647))
+ (import "env" "hW" (func $internal2648))
+ (import "env" "iW" (func $internal2649))
+ (import "env" "jW" (func $internal2650))
+ (import "env" "kW" (func $internal2651))
+ (import "env" "lW" (func $internal2652))
+ (import "env" "mW" (func $internal2653))
+ (import "env" "nW" (func $internal2654))
+ (import "env" "oW" (func $internal2655))
+ (import "env" "pW" (func $internal2656))
+ (import "env" "qW" (func $internal2657))
+ (import "env" "rW" (func $internal2658))
+ (import "env" "sW" (func $internal2659))
+ (import "env" "tW" (func $internal2660))
+ (import "env" "uW" (func $internal2661))
+ (import "env" "vW" (func $internal2662))
+ (import "env" "wW" (func $internal2663))
+ (import "env" "xW" (func $internal2664))
+ (import "env" "yW" (func $internal2665))
+ (import "env" "zW" (func $internal2666))
+ (import "env" "AW" (func $internal2667))
+ (import "env" "BW" (func $internal2668))
+ (import "env" "CW" (func $internal2669))
+ (import "env" "DW" (func $internal2670))
+ (import "env" "EW" (func $internal2671))
+ (import "env" "FW" (func $internal2672))
+ (import "env" "GW" (func $internal2673))
+ (import "env" "HW" (func $internal2674))
+ (import "env" "IW" (func $internal2675))
+ (import "env" "JW" (func $internal2676))
+ (import "env" "KW" (func $internal2677))
+ (import "env" "LW" (func $internal2678))
+ (import "env" "MW" (func $internal2679))
+ (import "env" "NW" (func $internal2680))
+ (import "env" "OW" (func $internal2681))
+ (import "env" "PW" (func $internal2682))
+ (import "env" "QW" (func $internal2683))
+ (import "env" "RW" (func $internal2684))
+ (import "env" "SW" (func $internal2685))
+ (import "env" "TW" (func $internal2686))
+ (import "env" "UW" (func $internal2687))
+ (import "env" "VW" (func $internal2688))
+ (import "env" "WW" (func $internal2689))
+ (import "env" "XW" (func $internal2690))
+ (import "env" "YW" (func $internal2691))
+ (import "env" "ZW" (func $internal2692))
+ (import "env" "_W" (func $internal2693))
+ (import "env" "$W" (func $internal2694))
+ (import "env" "aX" (func $internal2695))
+ (import "env" "bX" (func $internal2696))
+ (import "env" "cX" (func $internal2697))
+ (import "env" "dX" (func $internal2698))
+ (import "env" "eX" (func $internal2699))
+ (import "env" "fX" (func $internal2700))
+ (import "env" "gX" (func $internal2701))
+ (import "env" "hX" (func $internal2702))
+ (import "env" "iX" (func $internal2703))
+ (import "env" "jX" (func $internal2704))
+ (import "env" "kX" (func $internal2705))
+ (import "env" "lX" (func $internal2706))
+ (import "env" "mX" (func $internal2707))
+ (import "env" "nX" (func $internal2708))
+ (import "env" "oX" (func $internal2709))
+ (import "env" "pX" (func $internal2710))
+ (import "env" "qX" (func $internal2711))
+ (import "env" "rX" (func $internal2712))
+ (import "env" "sX" (func $internal2713))
+ (import "env" "tX" (func $internal2714))
+ (import "env" "uX" (func $internal2715))
+ (import "env" "vX" (func $internal2716))
+ (import "env" "wX" (func $internal2717))
+ (import "env" "xX" (func $internal2718))
+ (import "env" "yX" (func $internal2719))
+ (import "env" "zX" (func $internal2720))
+ (import "env" "AX" (func $internal2721))
+ (import "env" "BX" (func $internal2722))
+ (import "env" "CX" (func $internal2723))
+ (import "env" "DX" (func $internal2724))
+ (import "env" "EX" (func $internal2725))
+ (import "env" "FX" (func $internal2726))
+ (import "env" "GX" (func $internal2727))
+ (import "env" "HX" (func $internal2728))
+ (import "env" "IX" (func $internal2729))
+ (import "env" "JX" (func $internal2730))
+ (import "env" "KX" (func $internal2731))
+ (import "env" "LX" (func $internal2732))
+ (import "env" "MX" (func $internal2733))
+ (import "env" "NX" (func $internal2734))
+ (import "env" "OX" (func $internal2735))
+ (import "env" "PX" (func $internal2736))
+ (import "env" "QX" (func $internal2737))
+ (import "env" "RX" (func $internal2738))
+ (import "env" "SX" (func $internal2739))
+ (import "env" "TX" (func $internal2740))
+ (import "env" "UX" (func $internal2741))
+ (import "env" "VX" (func $internal2742))
+ (import "env" "WX" (func $internal2743))
+ (import "env" "XX" (func $internal2744))
+ (import "env" "YX" (func $internal2745))
+ (import "env" "ZX" (func $internal2746))
+ (import "env" "_X" (func $internal2747))
+ (import "env" "$X" (func $internal2748))
+ (import "env" "aY" (func $internal2749))
+ (import "env" "bY" (func $internal2750))
+ (import "env" "cY" (func $internal2751))
+ (import "env" "dY" (func $internal2752))
+ (import "env" "eY" (func $internal2753))
+ (import "env" "fY" (func $internal2754))
+ (import "env" "gY" (func $internal2755))
+ (import "env" "hY" (func $internal2756))
+ (import "env" "iY" (func $internal2757))
+ (import "env" "jY" (func $internal2758))
+ (import "env" "kY" (func $internal2759))
+ (import "env" "lY" (func $internal2760))
+ (import "env" "mY" (func $internal2761))
+ (import "env" "nY" (func $internal2762))
+ (import "env" "oY" (func $internal2763))
+ (import "env" "pY" (func $internal2764))
+ (import "env" "qY" (func $internal2765))
+ (import "env" "rY" (func $internal2766))
+ (import "env" "sY" (func $internal2767))
+ (import "env" "tY" (func $internal2768))
+ (import "env" "uY" (func $internal2769))
+ (import "env" "vY" (func $internal2770))
+ (import "env" "wY" (func $internal2771))
+ (import "env" "xY" (func $internal2772))
+ (import "env" "yY" (func $internal2773))
+ (import "env" "zY" (func $internal2774))
+ (import "env" "AY" (func $internal2775))
+ (import "env" "BY" (func $internal2776))
+ (import "env" "CY" (func $internal2777))
+ (import "env" "DY" (func $internal2778))
+ (import "env" "EY" (func $internal2779))
+ (import "env" "FY" (func $internal2780))
+ (import "env" "GY" (func $internal2781))
+ (import "env" "HY" (func $internal2782))
+ (import "env" "IY" (func $internal2783))
+ (import "env" "JY" (func $internal2784))
+ (import "env" "KY" (func $internal2785))
+ (import "env" "LY" (func $internal2786))
+ (import "env" "MY" (func $internal2787))
+ (import "env" "NY" (func $internal2788))
+ (import "env" "OY" (func $internal2789))
+ (import "env" "PY" (func $internal2790))
+ (import "env" "QY" (func $internal2791))
+ (import "env" "RY" (func $internal2792))
+ (import "env" "SY" (func $internal2793))
+ (import "env" "TY" (func $internal2794))
+ (import "env" "UY" (func $internal2795))
+ (import "env" "VY" (func $internal2796))
+ (import "env" "WY" (func $internal2797))
+ (import "env" "XY" (func $internal2798))
+ (import "env" "YY" (func $internal2799))
+ (import "env" "ZY" (func $internal2800))
+ (import "env" "_Y" (func $internal2801))
+ (import "env" "$Y" (func $internal2802))
+ (import "env" "aZ" (func $internal2803))
+ (import "env" "bZ" (func $internal2804))
+ (import "env" "cZ" (func $internal2805))
+ (import "env" "dZ" (func $internal2806))
+ (import "env" "eZ" (func $internal2807))
+ (import "env" "fZ" (func $internal2808))
+ (import "env" "gZ" (func $internal2809))
+ (import "env" "hZ" (func $internal2810))
+ (import "env" "iZ" (func $internal2811))
+ (import "env" "jZ" (func $internal2812))
+ (import "env" "kZ" (func $internal2813))
+ (import "env" "lZ" (func $internal2814))
+ (import "env" "mZ" (func $internal2815))
+ (import "env" "nZ" (func $internal2816))
+ (import "env" "oZ" (func $internal2817))
+ (import "env" "pZ" (func $internal2818))
+ (import "env" "qZ" (func $internal2819))
+ (import "env" "rZ" (func $internal2820))
+ (import "env" "sZ" (func $internal2821))
+ (import "env" "tZ" (func $internal2822))
+ (import "env" "uZ" (func $internal2823))
+ (import "env" "vZ" (func $internal2824))
+ (import "env" "wZ" (func $internal2825))
+ (import "env" "xZ" (func $internal2826))
+ (import "env" "yZ" (func $internal2827))
+ (import "env" "zZ" (func $internal2828))
+ (import "env" "AZ" (func $internal2829))
+ (import "env" "BZ" (func $internal2830))
+ (import "env" "CZ" (func $internal2831))
+ (import "env" "DZ" (func $internal2832))
+ (import "env" "EZ" (func $internal2833))
+ (import "env" "FZ" (func $internal2834))
+ (import "env" "GZ" (func $internal2835))
+ (import "env" "HZ" (func $internal2836))
+ (import "env" "IZ" (func $internal2837))
+ (import "env" "JZ" (func $internal2838))
+ (import "env" "KZ" (func $internal2839))
+ (import "env" "LZ" (func $internal2840))
+ (import "env" "MZ" (func $internal2841))
+ (import "env" "NZ" (func $internal2842))
+ (import "env" "OZ" (func $internal2843))
+ (import "env" "PZ" (func $internal2844))
+ (import "env" "QZ" (func $internal2845))
+ (import "env" "RZ" (func $internal2846))
+ (import "env" "SZ" (func $internal2847))
+ (import "env" "TZ" (func $internal2848))
+ (import "env" "UZ" (func $internal2849))
+ (import "env" "VZ" (func $internal2850))
+ (import "env" "WZ" (func $internal2851))
+ (import "env" "XZ" (func $internal2852))
+ (import "env" "YZ" (func $internal2853))
+ (import "env" "ZZ" (func $internal2854))
+ (import "env" "_Z" (func $internal2855))
+ (import "env" "$Z" (func $internal2856))
+ (import "env" "a_" (func $internal2857))
+ (import "env" "b_" (func $internal2858))
+ (import "env" "c_" (func $internal2859))
+ (import "env" "d_" (func $internal2860))
+ (import "env" "e_" (func $internal2861))
+ (import "env" "f_" (func $internal2862))
+ (import "env" "g_" (func $internal2863))
+ (import "env" "h_" (func $internal2864))
+ (import "env" "i_" (func $internal2865))
+ (import "env" "j_" (func $internal2866))
+ (import "env" "k_" (func $internal2867))
+ (import "env" "l_" (func $internal2868))
+ (import "env" "m_" (func $internal2869))
+ (import "env" "n_" (func $internal2870))
+ (import "env" "o_" (func $internal2871))
+ (import "env" "p_" (func $internal2872))
+ (import "env" "q_" (func $internal2873))
+ (import "env" "r_" (func $internal2874))
+ (import "env" "s_" (func $internal2875))
+ (import "env" "t_" (func $internal2876))
+ (import "env" "u_" (func $internal2877))
+ (import "env" "v_" (func $internal2878))
+ (import "env" "w_" (func $internal2879))
+ (import "env" "x_" (func $internal2880))
+ (import "env" "y_" (func $internal2881))
+ (import "env" "z_" (func $internal2882))
+ (import "env" "A_" (func $internal2883))
+ (import "env" "B_" (func $internal2884))
+ (import "env" "C_" (func $internal2885))
+ (import "env" "D_" (func $internal2886))
+ (import "env" "E_" (func $internal2887))
+ (import "env" "F_" (func $internal2888))
+ (import "env" "G_" (func $internal2889))
+ (import "env" "H_" (func $internal2890))
+ (import "env" "I_" (func $internal2891))
+ (import "env" "J_" (func $internal2892))
+ (import "env" "K_" (func $internal2893))
+ (import "env" "L_" (func $internal2894))
+ (import "env" "M_" (func $internal2895))
+ (import "env" "N_" (func $internal2896))
+ (import "env" "O_" (func $internal2897))
+ (import "env" "P_" (func $internal2898))
+ (import "env" "Q_" (func $internal2899))
+ (import "env" "R_" (func $internal2900))
+ (import "env" "S_" (func $internal2901))
+ (import "env" "T_" (func $internal2902))
+ (import "env" "U_" (func $internal2903))
+ (import "env" "V_" (func $internal2904))
+ (import "env" "W_" (func $internal2905))
+ (import "env" "X_" (func $internal2906))
+ (import "env" "Y_" (func $internal2907))
+ (import "env" "Z_" (func $internal2908))
+ (import "env" "__" (func $internal2909))
+ (import "env" "$_" (func $internal2910))
+ (import "env" "a$" (func $internal2911))
+ (import "env" "b$" (func $internal2912))
+ (import "env" "c$" (func $internal2913))
+ (import "env" "d$" (func $internal2914))
+ (import "env" "e$" (func $internal2915))
+ (import "env" "f$" (func $internal2916))
+ (import "env" "g$" (func $internal2917))
+ (import "env" "h$" (func $internal2918))
+ (import "env" "i$" (func $internal2919))
+ (import "env" "j$" (func $internal2920))
+ (import "env" "k$" (func $internal2921))
+ (import "env" "l$" (func $internal2922))
+ (import "env" "m$" (func $internal2923))
+ (import "env" "n$" (func $internal2924))
+ (import "env" "o$" (func $internal2925))
+ (import "env" "p$" (func $internal2926))
+ (import "env" "q$" (func $internal2927))
+ (import "env" "r$" (func $internal2928))
+ (import "env" "s$" (func $internal2929))
+ (import "env" "t$" (func $internal2930))
+ (import "env" "u$" (func $internal2931))
+ (import "env" "v$" (func $internal2932))
+ (import "env" "w$" (func $internal2933))
+ (import "env" "x$" (func $internal2934))
+ (import "env" "y$" (func $internal2935))
+ (import "env" "z$" (func $internal2936))
+ (import "env" "A$" (func $internal2937))
+ (import "env" "B$" (func $internal2938))
+ (import "env" "C$" (func $internal2939))
+ (import "env" "D$" (func $internal2940))
+ (import "env" "E$" (func $internal2941))
+ (import "env" "F$" (func $internal2942))
+ (import "env" "G$" (func $internal2943))
+ (import "env" "H$" (func $internal2944))
+ (import "env" "I$" (func $internal2945))
+ (import "env" "J$" (func $internal2946))
+ (import "env" "K$" (func $internal2947))
+ (import "env" "L$" (func $internal2948))
+ (import "env" "M$" (func $internal2949))
+ (import "env" "N$" (func $internal2950))
+ (import "env" "O$" (func $internal2951))
+ (import "env" "P$" (func $internal2952))
+ (import "env" "Q$" (func $internal2953))
+ (import "env" "R$" (func $internal2954))
+ (import "env" "S$" (func $internal2955))
+ (import "env" "T$" (func $internal2956))
+ (import "env" "U$" (func $internal2957))
+ (import "env" "V$" (func $internal2958))
+ (import "env" "W$" (func $internal2959))
+ (import "env" "X$" (func $internal2960))
+ (import "env" "Y$" (func $internal2961))
+ (import "env" "Z$" (func $internal2962))
+ (import "env" "_$" (func $internal2963))
+ (import "env" "$$" (func $internal2964))
+ (import "env" "a0" (func $internal2965))
+ (import "env" "b0" (func $internal2966))
+ (import "env" "c0" (func $internal2967))
+ (import "env" "d0" (func $internal2968))
+ (import "env" "e0" (func $internal2969))
+ (import "env" "f0" (func $internal2970))
+ (import "env" "g0" (func $internal2971))
+ (import "env" "h0" (func $internal2972))
+ (import "env" "i0" (func $internal2973))
+ (import "env" "j0" (func $internal2974))
+ (import "env" "k0" (func $internal2975))
+ (import "env" "l0" (func $internal2976))
+ (import "env" "m0" (func $internal2977))
+ (import "env" "n0" (func $internal2978))
+ (import "env" "o0" (func $internal2979))
+ (import "env" "p0" (func $internal2980))
+ (import "env" "q0" (func $internal2981))
+ (import "env" "r0" (func $internal2982))
+ (import "env" "s0" (func $internal2983))
+ (import "env" "t0" (func $internal2984))
+ (import "env" "u0" (func $internal2985))
+ (import "env" "v0" (func $internal2986))
+ (import "env" "w0" (func $internal2987))
+ (import "env" "x0" (func $internal2988))
+ (import "env" "y0" (func $internal2989))
+ (import "env" "z0" (func $internal2990))
+ (import "env" "A0" (func $internal2991))
+ (import "env" "B0" (func $internal2992))
+ (import "env" "C0" (func $internal2993))
+ (import "env" "D0" (func $internal2994))
+ (import "env" "E0" (func $internal2995))
+ (import "env" "F0" (func $internal2996))
+ (import "env" "G0" (func $internal2997))
+ (import "env" "H0" (func $internal2998))
+ (import "env" "I0" (func $internal2999))
+ (import "env" "J0" (func $internal3000))
+ (import "env" "K0" (func $internal3001))
+ (import "env" "L0" (func $internal3002))
+ (import "env" "M0" (func $internal3003))
+ (import "env" "N0" (func $internal3004))
+ (import "env" "O0" (func $internal3005))
+ (import "env" "P0" (func $internal3006))
+ (import "env" "Q0" (func $internal3007))
+ (import "env" "R0" (func $internal3008))
+ (import "env" "S0" (func $internal3009))
+ (import "env" "T0" (func $internal3010))
+ (import "env" "U0" (func $internal3011))
+ (import "env" "V0" (func $internal3012))
+ (import "env" "W0" (func $internal3013))
+ (import "env" "X0" (func $internal3014))
+ (import "env" "Y0" (func $internal3015))
+ (import "env" "Z0" (func $internal3016))
+ (import "env" "_0" (func $internal3017))
+ (import "env" "$0" (func $internal3018))
+ (import "env" "a1" (func $internal3019))
+ (import "env" "b1" (func $internal3020))
+ (import "env" "c1" (func $internal3021))
+ (import "env" "d1" (func $internal3022))
+ (import "env" "e1" (func $internal3023))
+ (import "env" "f1" (func $internal3024))
+ (import "env" "g1" (func $internal3025))
+ (import "env" "h1" (func $internal3026))
+ (import "env" "i1" (func $internal3027))
+ (import "env" "j1" (func $internal3028))
+ (import "env" "k1" (func $internal3029))
+ (import "env" "l1" (func $internal3030))
+ (import "env" "m1" (func $internal3031))
+ (import "env" "n1" (func $internal3032))
+ (import "env" "o1" (func $internal3033))
+ (import "env" "p1" (func $internal3034))
+ (import "env" "q1" (func $internal3035))
+ (import "env" "r1" (func $internal3036))
+ (import "env" "s1" (func $internal3037))
+ (import "env" "t1" (func $internal3038))
+ (import "env" "u1" (func $internal3039))
+ (import "env" "v1" (func $internal3040))
+ (import "env" "w1" (func $internal3041))
+ (import "env" "x1" (func $internal3042))
+ (import "env" "y1" (func $internal3043))
+ (import "env" "z1" (func $internal3044))
+ (import "env" "A1" (func $internal3045))
+ (import "env" "B1" (func $internal3046))
+ (import "env" "C1" (func $internal3047))
+ (import "env" "D1" (func $internal3048))
+ (import "env" "E1" (func $internal3049))
+ (import "env" "F1" (func $internal3050))
+ (import "env" "G1" (func $internal3051))
+ (import "env" "H1" (func $internal3052))
+ (import "env" "I1" (func $internal3053))
+ (import "env" "J1" (func $internal3054))
+ (import "env" "K1" (func $internal3055))
+ (import "env" "L1" (func $internal3056))
+ (import "env" "M1" (func $internal3057))
+ (import "env" "N1" (func $internal3058))
+ (import "env" "O1" (func $internal3059))
+ (import "env" "P1" (func $internal3060))
+ (import "env" "Q1" (func $internal3061))
+ (import "env" "R1" (func $internal3062))
+ (import "env" "S1" (func $internal3063))
+ (import "env" "T1" (func $internal3064))
+ (import "env" "U1" (func $internal3065))
+ (import "env" "V1" (func $internal3066))
+ (import "env" "W1" (func $internal3067))
+ (import "env" "X1" (func $internal3068))
+ (import "env" "Y1" (func $internal3069))
+ (import "env" "Z1" (func $internal3070))
+ (import "env" "_1" (func $internal3071))
+ (import "env" "$1" (func $internal3072))
+ (import "env" "a2" (func $internal3073))
+ (import "env" "b2" (func $internal3074))
+ (import "env" "c2" (func $internal3075))
+ (import "env" "d2" (func $internal3076))
+ (import "env" "e2" (func $internal3077))
+ (import "env" "f2" (func $internal3078))
+ (import "env" "g2" (func $internal3079))
+ (import "env" "h2" (func $internal3080))
+ (import "env" "i2" (func $internal3081))
+ (import "env" "j2" (func $internal3082))
+ (import "env" "k2" (func $internal3083))
+ (import "env" "l2" (func $internal3084))
+ (import "env" "m2" (func $internal3085))
+ (import "env" "n2" (func $internal3086))
+ (import "env" "o2" (func $internal3087))
+ (import "env" "p2" (func $internal3088))
+ (import "env" "q2" (func $internal3089))
+ (import "env" "r2" (func $internal3090))
+ (import "env" "s2" (func $internal3091))
+ (import "env" "t2" (func $internal3092))
+ (import "env" "u2" (func $internal3093))
+ (import "env" "v2" (func $internal3094))
+ (import "env" "w2" (func $internal3095))
+ (import "env" "x2" (func $internal3096))
+ (import "env" "y2" (func $internal3097))
+ (import "env" "z2" (func $internal3098))
+ (import "env" "A2" (func $internal3099))
+ (import "env" "B2" (func $internal3100))
+ (import "env" "C2" (func $internal3101))
+ (import "env" "D2" (func $internal3102))
+ (import "env" "E2" (func $internal3103))
+ (import "env" "F2" (func $internal3104))
+ (import "env" "G2" (func $internal3105))
+ (import "env" "H2" (func $internal3106))
+ (import "env" "I2" (func $internal3107))
+ (import "env" "J2" (func $internal3108))
+ (import "env" "K2" (func $internal3109))
+ (import "env" "L2" (func $internal3110))
+ (import "env" "M2" (func $internal3111))
+ (import "env" "N2" (func $internal3112))
+ (import "env" "O2" (func $internal3113))
+ (import "env" "P2" (func $internal3114))
+ (import "env" "Q2" (func $internal3115))
+ (import "env" "R2" (func $internal3116))
+ (import "env" "S2" (func $internal3117))
+ (import "env" "T2" (func $internal3118))
+ (import "env" "U2" (func $internal3119))
+ (import "env" "V2" (func $internal3120))
+ (import "env" "W2" (func $internal3121))
+ (import "env" "X2" (func $internal3122))
+ (import "env" "Y2" (func $internal3123))
+ (import "env" "Z2" (func $internal3124))
+ (import "env" "_2" (func $internal3125))
+ (import "env" "$2" (func $internal3126))
+ (import "env" "a3" (func $internal3127))
+ (import "env" "b3" (func $internal3128))
+ (import "env" "c3" (func $internal3129))
+ (import "env" "d3" (func $internal3130))
+ (import "env" "e3" (func $internal3131))
+ (import "env" "f3" (func $internal3132))
+ (import "env" "g3" (func $internal3133))
+ (import "env" "h3" (func $internal3134))
+ (import "env" "i3" (func $internal3135))
+ (import "env" "j3" (func $internal3136))
+ (import "env" "k3" (func $internal3137))
+ (import "env" "l3" (func $internal3138))
+ (import "env" "m3" (func $internal3139))
+ (import "env" "n3" (func $internal3140))
+ (import "env" "o3" (func $internal3141))
+ (import "env" "p3" (func $internal3142))
+ (import "env" "q3" (func $internal3143))
+ (import "env" "r3" (func $internal3144))
+ (import "env" "s3" (func $internal3145))
+ (import "env" "t3" (func $internal3146))
+ (import "env" "u3" (func $internal3147))
+ (import "env" "v3" (func $internal3148))
+ (import "env" "w3" (func $internal3149))
+ (import "env" "x3" (func $internal3150))
+ (import "env" "y3" (func $internal3151))
+ (import "env" "z3" (func $internal3152))
+ (import "env" "A3" (func $internal3153))
+ (import "env" "B3" (func $internal3154))
+ (import "env" "C3" (func $internal3155))
+ (import "env" "D3" (func $internal3156))
+ (import "env" "E3" (func $internal3157))
+ (import "env" "F3" (func $internal3158))
+ (import "env" "G3" (func $internal3159))
+ (import "env" "H3" (func $internal3160))
+ (import "env" "I3" (func $internal3161))
+ (import "env" "J3" (func $internal3162))
+ (import "env" "K3" (func $internal3163))
+ (import "env" "L3" (func $internal3164))
+ (import "env" "M3" (func $internal3165))
+ (import "env" "N3" (func $internal3166))
+ (import "env" "O3" (func $internal3167))
+ (import "env" "P3" (func $internal3168))
+ (import "env" "Q3" (func $internal3169))
+ (import "env" "R3" (func $internal3170))
+ (import "env" "S3" (func $internal3171))
+ (import "env" "T3" (func $internal3172))
+ (import "env" "U3" (func $internal3173))
+ (import "env" "V3" (func $internal3174))
+ (import "env" "W3" (func $internal3175))
+ (import "env" "X3" (func $internal3176))
+ (import "env" "Y3" (func $internal3177))
+ (import "env" "Z3" (func $internal3178))
+ (import "env" "_3" (func $internal3179))
+ (import "env" "$3" (func $internal3180))
+ (import "env" "a4" (func $internal3181))
+ (import "env" "b4" (func $internal3182))
+ (import "env" "c4" (func $internal3183))
+ (import "env" "d4" (func $internal3184))
+ (import "env" "e4" (func $internal3185))
+ (import "env" "f4" (func $internal3186))
+ (import "env" "g4" (func $internal3187))
+ (import "env" "h4" (func $internal3188))
+ (import "env" "i4" (func $internal3189))
+ (import "env" "j4" (func $internal3190))
+ (import "env" "k4" (func $internal3191))
+ (import "env" "l4" (func $internal3192))
+ (import "env" "m4" (func $internal3193))
+ (import "env" "n4" (func $internal3194))
+ (import "env" "o4" (func $internal3195))
+ (import "env" "p4" (func $internal3196))
+ (import "env" "q4" (func $internal3197))
+ (import "env" "r4" (func $internal3198))
+ (import "env" "s4" (func $internal3199))
+ (import "env" "t4" (func $internal3200))
+ (import "env" "u4" (func $internal3201))
+ (import "env" "v4" (func $internal3202))
+ (import "env" "w4" (func $internal3203))
+ (import "env" "x4" (func $internal3204))
+ (import "env" "y4" (func $internal3205))
+ (import "env" "z4" (func $internal3206))
+ (import "env" "A4" (func $internal3207))
+ (import "env" "B4" (func $internal3208))
+ (import "env" "C4" (func $internal3209))
+ (import "env" "D4" (func $internal3210))
+ (import "env" "E4" (func $internal3211))
+ (import "env" "F4" (func $internal3212))
+ (import "env" "G4" (func $internal3213))
+ (import "env" "H4" (func $internal3214))
+ (import "env" "I4" (func $internal3215))
+ (import "env" "J4" (func $internal3216))
+ (import "env" "K4" (func $internal3217))
+ (import "env" "L4" (func $internal3218))
+ (import "env" "M4" (func $internal3219))
+ (import "env" "N4" (func $internal3220))
+ (import "env" "O4" (func $internal3221))
+ (import "env" "P4" (func $internal3222))
+ (import "env" "Q4" (func $internal3223))
+ (import "env" "R4" (func $internal3224))
+ (import "env" "S4" (func $internal3225))
+ (import "env" "T4" (func $internal3226))
+ (import "env" "U4" (func $internal3227))
+ (import "env" "V4" (func $internal3228))
+ (import "env" "W4" (func $internal3229))
+ (import "env" "X4" (func $internal3230))
+ (import "env" "Y4" (func $internal3231))
+ (import "env" "Z4" (func $internal3232))
+ (import "env" "_4" (func $internal3233))
+ (import "env" "$4" (func $internal3234))
+ (import "env" "a5" (func $internal3235))
+ (import "env" "b5" (func $internal3236))
+ (import "env" "c5" (func $internal3237))
+ (import "env" "d5" (func $internal3238))
+ (import "env" "e5" (func $internal3239))
+ (import "env" "f5" (func $internal3240))
+ (import "env" "g5" (func $internal3241))
+ (import "env" "h5" (func $internal3242))
+ (import "env" "i5" (func $internal3243))
+ (import "env" "j5" (func $internal3244))
+ (import "env" "k5" (func $internal3245))
+ (import "env" "l5" (func $internal3246))
+ (import "env" "m5" (func $internal3247))
+ (import "env" "n5" (func $internal3248))
+ (import "env" "o5" (func $internal3249))
+ (import "env" "p5" (func $internal3250))
+ (import "env" "q5" (func $internal3251))
+ (import "env" "r5" (func $internal3252))
+ (import "env" "s5" (func $internal3253))
+ (import "env" "t5" (func $internal3254))
+ (import "env" "u5" (func $internal3255))
+ (import "env" "v5" (func $internal3256))
+ (import "env" "w5" (func $internal3257))
+ (import "env" "x5" (func $internal3258))
+ (import "env" "y5" (func $internal3259))
+ (import "env" "z5" (func $internal3260))
+ (import "env" "A5" (func $internal3261))
+ (import "env" "B5" (func $internal3262))
+ (import "env" "C5" (func $internal3263))
+ (import "env" "D5" (func $internal3264))
+ (import "env" "E5" (func $internal3265))
+ (import "env" "F5" (func $internal3266))
+ (import "env" "G5" (func $internal3267))
+ (import "env" "H5" (func $internal3268))
+ (import "env" "I5" (func $internal3269))
+ (import "env" "J5" (func $internal3270))
+ (import "env" "K5" (func $internal3271))
+ (import "env" "L5" (func $internal3272))
+ (import "env" "M5" (func $internal3273))
+ (import "env" "N5" (func $internal3274))
+ (import "env" "O5" (func $internal3275))
+ (import "env" "P5" (func $internal3276))
+ (import "env" "Q5" (func $internal3277))
+ (import "env" "R5" (func $internal3278))
+ (import "env" "S5" (func $internal3279))
+ (import "env" "T5" (func $internal3280))
+ (import "env" "U5" (func $internal3281))
+ (import "env" "V5" (func $internal3282))
+ (import "env" "W5" (func $internal3283))
+ (import "env" "X5" (func $internal3284))
+ (import "env" "Y5" (func $internal3285))
+ (import "env" "Z5" (func $internal3286))
+ (import "env" "_5" (func $internal3287))
+ (import "env" "$5" (func $internal3288))
+ (import "env" "a6" (func $internal3289))
+ (import "env" "b6" (func $internal3290))
+ (import "env" "c6" (func $internal3291))
+ (import "env" "d6" (func $internal3292))
+ (import "env" "e6" (func $internal3293))
+ (import "env" "f6" (func $internal3294))
+ (import "env" "g6" (func $internal3295))
+ (import "env" "h6" (func $internal3296))
+ (import "env" "i6" (func $internal3297))
+ (import "env" "j6" (func $internal3298))
+ (import "env" "k6" (func $internal3299))
+ (import "env" "l6" (func $internal3300))
+ (import "env" "m6" (func $internal3301))
+ (import "env" "n6" (func $internal3302))
+ (import "env" "o6" (func $internal3303))
+ (import "env" "p6" (func $internal3304))
+ (import "env" "q6" (func $internal3305))
+ (import "env" "r6" (func $internal3306))
+ (import "env" "s6" (func $internal3307))
+ (import "env" "t6" (func $internal3308))
+ (import "env" "u6" (func $internal3309))
+ (import "env" "v6" (func $internal3310))
+ (import "env" "w6" (func $internal3311))
+ (import "env" "x6" (func $internal3312))
+ (import "env" "y6" (func $internal3313))
+ (import "env" "z6" (func $internal3314))
+ (import "env" "A6" (func $internal3315))
+ (import "env" "B6" (func $internal3316))
+ (import "env" "C6" (func $internal3317))
+ (import "env" "D6" (func $internal3318))
+ (import "env" "E6" (func $internal3319))
+ (import "env" "F6" (func $internal3320))
+ (import "env" "G6" (func $internal3321))
+ (import "env" "H6" (func $internal3322))
+ (import "env" "I6" (func $internal3323))
+ (import "env" "J6" (func $internal3324))
+ (import "env" "K6" (func $internal3325))
+ (import "env" "L6" (func $internal3326))
+ (import "env" "M6" (func $internal3327))
+ (import "env" "N6" (func $internal3328))
+ (import "env" "O6" (func $internal3329))
+ (import "env" "P6" (func $internal3330))
+ (import "env" "Q6" (func $internal3331))
+ (import "env" "R6" (func $internal3332))
+ (import "env" "S6" (func $internal3333))
+ (import "env" "T6" (func $internal3334))
+ (import "env" "U6" (func $internal3335))
+ (import "env" "V6" (func $internal3336))
+ (import "env" "W6" (func $internal3337))
+ (import "env" "X6" (func $internal3338))
+ (import "env" "Y6" (func $internal3339))
+ (import "env" "Z6" (func $internal3340))
+ (import "env" "_6" (func $internal3341))
+ (import "env" "$6" (func $internal3342))
+ (import "env" "a7" (func $internal3343))
+ (import "env" "b7" (func $internal3344))
+ (import "env" "c7" (func $internal3345))
+ (import "env" "d7" (func $internal3346))
+ (import "env" "e7" (func $internal3347))
+ (import "env" "f7" (func $internal3348))
+ (import "env" "g7" (func $internal3349))
+ (import "env" "h7" (func $internal3350))
+ (import "env" "i7" (func $internal3351))
+ (import "env" "j7" (func $internal3352))
+ (import "env" "k7" (func $internal3353))
+ (import "env" "l7" (func $internal3354))
+ (import "env" "m7" (func $internal3355))
+ (import "env" "n7" (func $internal3356))
+ (import "env" "o7" (func $internal3357))
+ (import "env" "p7" (func $internal3358))
+ (import "env" "q7" (func $internal3359))
+ (import "env" "r7" (func $internal3360))
+ (import "env" "s7" (func $internal3361))
+ (import "env" "t7" (func $internal3362))
+ (import "env" "u7" (func $internal3363))
+ (import "env" "v7" (func $internal3364))
+ (import "env" "w7" (func $internal3365))
+ (import "env" "x7" (func $internal3366))
+ (import "env" "y7" (func $internal3367))
+ (import "env" "z7" (func $internal3368))
+ (import "env" "A7" (func $internal3369))
+ (import "env" "B7" (func $internal3370))
+ (import "env" "C7" (func $internal3371))
+ (import "env" "D7" (func $internal3372))
+ (import "env" "E7" (func $internal3373))
+ (import "env" "F7" (func $internal3374))
+ (import "env" "G7" (func $internal3375))
+ (import "env" "H7" (func $internal3376))
+ (import "env" "I7" (func $internal3377))
+ (import "env" "J7" (func $internal3378))
+ (import "env" "K7" (func $internal3379))
+ (import "env" "L7" (func $internal3380))
+ (import "env" "M7" (func $internal3381))
+ (import "env" "N7" (func $internal3382))
+ (import "env" "O7" (func $internal3383))
+ (import "env" "P7" (func $internal3384))
+ (import "env" "Q7" (func $internal3385))
+ (import "env" "R7" (func $internal3386))
+ (import "env" "S7" (func $internal3387))
+ (import "env" "T7" (func $internal3388))
+ (import "env" "U7" (func $internal3389))
+ (import "env" "V7" (func $internal3390))
+ (import "env" "W7" (func $internal3391))
+ (import "env" "X7" (func $internal3392))
+ (import "env" "Y7" (func $internal3393))
+ (import "env" "Z7" (func $internal3394))
+ (import "env" "_7" (func $internal3395))
+ (import "env" "$7" (func $internal3396))
+ (import "env" "a8" (func $internal3397))
+ (import "env" "b8" (func $internal3398))
+ (import "env" "c8" (func $internal3399))
+ (import "env" "d8" (func $internal3400))
+ (import "env" "e8" (func $internal3401))
+ (import "env" "f8" (func $internal3402))
+ (import "env" "g8" (func $internal3403))
+ (import "env" "h8" (func $internal3404))
+ (import "env" "i8" (func $internal3405))
+ (import "env" "j8" (func $internal3406))
+ (import "env" "k8" (func $internal3407))
+ (import "env" "l8" (func $internal3408))
+ (import "env" "m8" (func $internal3409))
+ (import "env" "n8" (func $internal3410))
+ (import "env" "o8" (func $internal3411))
+ (import "env" "p8" (func $internal3412))
+ (import "env" "q8" (func $internal3413))
+ (import "env" "r8" (func $internal3414))
+ (import "env" "s8" (func $internal3415))
+ (import "env" "t8" (func $internal3416))
+ (import "env" "u8" (func $internal3417))
+ (import "env" "v8" (func $internal3418))
+ (import "env" "w8" (func $internal3419))
+ (import "env" "x8" (func $internal3420))
+ (import "env" "y8" (func $internal3421))
+ (import "env" "z8" (func $internal3422))
+ (import "env" "A8" (func $internal3423))
+ (import "env" "B8" (func $internal3424))
+ (import "env" "C8" (func $internal3425))
+ (import "env" "D8" (func $internal3426))
+ (import "env" "E8" (func $internal3427))
+ (import "env" "F8" (func $internal3428))
+ (import "env" "G8" (func $internal3429))
+ (import "env" "H8" (func $internal3430))
+ (import "env" "I8" (func $internal3431))
+ (import "env" "J8" (func $internal3432))
+ (import "env" "K8" (func $internal3433))
+ (import "env" "L8" (func $internal3434))
+ (import "env" "M8" (func $internal3435))
+ (import "env" "N8" (func $internal3436))
+ (import "env" "O8" (func $internal3437))
+ (import "env" "P8" (func $internal3438))
+ (import "env" "Q8" (func $internal3439))
+ (import "env" "R8" (func $internal3440))
+ (import "env" "S8" (func $internal3441))
+ (import "env" "T8" (func $internal3442))
+ (import "env" "U8" (func $internal3443))
+ (import "env" "V8" (func $internal3444))
+ (import "env" "W8" (func $internal3445))
+ (import "env" "X8" (func $internal3446))
+ (import "env" "Y8" (func $internal3447))
+ (import "env" "Z8" (func $internal3448))
+ (import "env" "_8" (func $internal3449))
+ (import "env" "$8" (func $internal3450))
+ (import "env" "a9" (func $internal3451))
+ (import "env" "b9" (func $internal3452))
+ (import "env" "c9" (func $internal3453))
+ (import "env" "d9" (func $internal3454))
+ (import "env" "e9" (func $internal3455))
+ (import "env" "f9" (func $internal3456))
+ (import "env" "g9" (func $internal3457))
+ (import "env" "h9" (func $internal3458))
+ (import "env" "i9" (func $internal3459))
+ (import "env" "j9" (func $internal3460))
+ (import "env" "k9" (func $internal3461))
+ (import "env" "l9" (func $internal3462))
+ (import "env" "m9" (func $internal3463))
+ (import "env" "n9" (func $internal3464))
+ (import "env" "o9" (func $internal3465))
+ (import "env" "p9" (func $internal3466))
+ (import "env" "q9" (func $internal3467))
+ (import "env" "r9" (func $internal3468))
+ (import "env" "s9" (func $internal3469))
+ (import "env" "t9" (func $internal3470))
+ (import "env" "u9" (func $internal3471))
+ (import "env" "v9" (func $internal3472))
+ (import "env" "w9" (func $internal3473))
+ (import "env" "x9" (func $internal3474))
+ (import "env" "y9" (func $internal3475))
+ (import "env" "z9" (func $internal3476))
+ (import "env" "A9" (func $internal3477))
+ (import "env" "B9" (func $internal3478))
+ (import "env" "C9" (func $internal3479))
+ (import "env" "D9" (func $internal3480))
+ (import "env" "E9" (func $internal3481))
+ (import "env" "F9" (func $internal3482))
+ (import "env" "G9" (func $internal3483))
+ (import "env" "H9" (func $internal3484))
+ (import "env" "I9" (func $internal3485))
+ (import "env" "J9" (func $internal3486))
+ (import "env" "K9" (func $internal3487))
+ (import "env" "L9" (func $internal3488))
+ (import "env" "M9" (func $internal3489))
+ (import "env" "N9" (func $internal3490))
+ (import "env" "O9" (func $internal3491))
+ (import "env" "P9" (func $internal3492))
+ (import "env" "Q9" (func $internal3493))
+ (import "env" "R9" (func $internal3494))
+ (import "env" "S9" (func $internal3495))
+ (import "env" "T9" (func $internal3496))
+ (import "env" "U9" (func $internal3497))
+ (import "env" "V9" (func $internal3498))
+ (import "env" "W9" (func $internal3499))
+ (import "env" "X9" (func $internal3500))
+ (import "env" "Y9" (func $internal3501))
+ (import "env" "Z9" (func $internal3502))
+ (import "env" "_9" (func $internal3503))
+ (import "env" "$9" (func $internal3504))
+ (import "env" "aaa" (func $internal3505))
+ (import "env" "baa" (func $internal3506))
+ (import "env" "caa" (func $internal3507))
+ (import "env" "daa" (func $internal3508))
+ (import "env" "eaa" (func $internal3509))
+ (import "env" "faa" (func $internal3510))
+ (import "env" "gaa" (func $internal3511))
+ (import "env" "haa" (func $internal3512))
+ (import "env" "iaa" (func $internal3513))
+ (import "env" "jaa" (func $internal3514))
+ (import "env" "kaa" (func $internal3515))
+ (import "env" "laa" (func $internal3516))
+ (import "env" "maa" (func $internal3517))
+ (import "env" "naa" (func $internal3518))
+ (import "env" "oaa" (func $internal3519))
+ (import "env" "paa" (func $internal3520))
+ (import "env" "qaa" (func $internal3521))
+ (import "env" "raa" (func $internal3522))
+ (import "env" "saa" (func $internal3523))
+ (import "env" "taa" (func $internal3524))
+ (import "env" "uaa" (func $internal3525))
+ (import "env" "vaa" (func $internal3526))
+ (import "env" "waa" (func $internal3527))
+ (import "env" "xaa" (func $internal3528))
+ (import "env" "yaa" (func $internal3529))
+ (import "env" "zaa" (func $internal3530))
+ (import "env" "Aaa" (func $internal3531))
+ (import "env" "Baa" (func $internal3532))
+ (import "env" "Caa" (func $internal3533))
+ (import "env" "Daa" (func $internal3534))
+ (import "env" "Eaa" (func $internal3535))
+ (import "env" "Faa" (func $internal3536))
+ (import "env" "Gaa" (func $internal3537))
+ (import "env" "Haa" (func $internal3538))
+ (import "env" "Iaa" (func $internal3539))
+ (import "env" "Jaa" (func $internal3540))
+ (import "env" "Kaa" (func $internal3541))
+ (import "env" "Laa" (func $internal3542))
+ (import "env" "Maa" (func $internal3543))
+ (import "env" "Naa" (func $internal3544))
+ (import "env" "Oaa" (func $internal3545))
+ (import "env" "Paa" (func $internal3546))
+ (import "env" "Qaa" (func $internal3547))
+ (import "env" "Raa" (func $internal3548))
+ (import "env" "Saa" (func $internal3549))
+ (import "env" "Taa" (func $internal3550))
+ (import "env" "Uaa" (func $internal3551))
+ (import "env" "Vaa" (func $internal3552))
+ (import "env" "Waa" (func $internal3553))
+ (import "env" "Xaa" (func $internal3554))
+ (import "env" "Yaa" (func $internal3555))
+ (import "env" "Zaa" (func $internal3556))
+ (import "env" "_aa" (func $internal3557))
+ (import "env" "$aa" (func $internal3558))
+ (import "env" "aba" (func $internal3559))
+ (import "env" "bba" (func $internal3560))
+ (import "env" "cba" (func $internal3561))
+ (import "env" "dba" (func $internal3562))
+ (import "env" "eba" (func $internal3563))
+ (import "env" "fba" (func $internal3564))
+ (import "env" "gba" (func $internal3565))
+ (import "env" "hba" (func $internal3566))
+ (import "env" "iba" (func $internal3567))
+ (import "env" "jba" (func $internal3568))
+ (import "env" "kba" (func $internal3569))
+ (import "env" "lba" (func $internal3570))
+ (import "env" "mba" (func $internal3571))
+ (import "env" "nba" (func $internal3572))
+ (import "env" "oba" (func $internal3573))
+ (import "env" "pba" (func $internal3574))
+ (import "env" "qba" (func $internal3575))
+ (import "env" "rba" (func $internal3576))
+ (import "env" "sba" (func $internal3577))
+ (import "env" "tba" (func $internal3578))
+ (import "env" "uba" (func $internal3579))
+ (import "env" "vba" (func $internal3580))
+ (import "env" "wba" (func $internal3581))
+ (import "env" "xba" (func $internal3582))
+ (import "env" "yba" (func $internal3583))
+ (import "env" "zba" (func $internal3584))
+ (import "env" "Aba" (func $internal3585))
+ (import "env" "Bba" (func $internal3586))
+ (import "env" "Cba" (func $internal3587))
+ (import "env" "Dba" (func $internal3588))
+ (import "env" "Eba" (func $internal3589))
+ (import "env" "Fba" (func $internal3590))
+ (import "env" "Gba" (func $internal3591))
+ (import "env" "Hba" (func $internal3592))
+ (import "env" "Iba" (func $internal3593))
+ (import "env" "Jba" (func $internal3594))
+ (import "env" "Kba" (func $internal3595))
+ (import "env" "Lba" (func $internal3596))
+ (import "env" "Mba" (func $internal3597))
+ (import "env" "Nba" (func $internal3598))
+ (import "env" "Oba" (func $internal3599))
+ (import "env" "Pba" (func $internal3600))
+ (import "env" "Qba" (func $internal3601))
+ (import "env" "Rba" (func $internal3602))
+ (import "env" "Sba" (func $internal3603))
+ (import "env" "Tba" (func $internal3604))
+ (import "env" "Uba" (func $internal3605))
+ (import "env" "Vba" (func $internal3606))
+ (import "env" "Wba" (func $internal3607))
+ (import "env" "Xba" (func $internal3608))
+ (import "env" "Yba" (func $internal3609))
+ (import "env" "Zba" (func $internal3610))
+ (import "env" "_ba" (func $internal3611))
+ (import "env" "$ba" (func $internal3612))
+ (import "env" "aca" (func $internal3613))
+ (import "env" "bca" (func $internal3614))
+ (import "env" "cca" (func $internal3615))
+ (import "env" "dca" (func $internal3616))
+ (import "env" "eca" (func $internal3617))
+ (import "env" "fca" (func $internal3618))
+ (import "env" "gca" (func $internal3619))
+ (import "env" "hca" (func $internal3620))
+ (import "env" "ica" (func $internal3621))
+ (import "env" "jca" (func $internal3622))
+ (import "env" "kca" (func $internal3623))
+ (import "env" "lca" (func $internal3624))
+ (import "env" "mca" (func $internal3625))
+ (import "env" "nca" (func $internal3626))
+ (import "env" "oca" (func $internal3627))
+ (import "env" "pca" (func $internal3628))
+ (import "env" "qca" (func $internal3629))
+ (import "env" "rca" (func $internal3630))
+ (import "env" "sca" (func $internal3631))
+ (import "env" "tca" (func $internal3632))
+ (import "env" "uca" (func $internal3633))
+ (import "env" "vca" (func $internal3634))
+ (import "env" "wca" (func $internal3635))
+ (import "env" "xca" (func $internal3636))
+ (import "env" "yca" (func $internal3637))
+ (import "env" "zca" (func $internal3638))
+ (import "env" "Aca" (func $internal3639))
+ (import "env" "Bca" (func $internal3640))
+ (import "env" "Cca" (func $internal3641))
+ (import "env" "Dca" (func $internal3642))
+ (import "env" "Eca" (func $internal3643))
+ (import "env" "Fca" (func $internal3644))
+ (import "env" "Gca" (func $internal3645))
+ (import "env" "Hca" (func $internal3646))
+ (import "env" "Ica" (func $internal3647))
+ (import "env" "Jca" (func $internal3648))
+ (import "env" "Kca" (func $internal3649))
+ (import "env" "Lca" (func $internal3650))
+ (import "env" "Mca" (func $internal3651))
+ (import "env" "Nca" (func $internal3652))
+ (import "env" "Oca" (func $internal3653))
+ (import "env" "Pca" (func $internal3654))
+ (import "env" "Qca" (func $internal3655))
+ (import "env" "Rca" (func $internal3656))
+ (import "env" "Sca" (func $internal3657))
+ (import "env" "Tca" (func $internal3658))
+ (import "env" "Uca" (func $internal3659))
+ (import "env" "Vca" (func $internal3660))
+ (import "env" "Wca" (func $internal3661))
+ (import "env" "Xca" (func $internal3662))
+ (import "env" "Yca" (func $internal3663))
+ (import "env" "Zca" (func $internal3664))
+ (import "env" "_ca" (func $internal3665))
+ (import "env" "$ca" (func $internal3666))
+ (import "env" "ada" (func $internal3667))
+ (import "env" "bda" (func $internal3668))
+ (import "env" "cda" (func $internal3669))
+ (import "env" "dda" (func $internal3670))
+ (import "env" "eda" (func $internal3671))
+ (import "env" "fda" (func $internal3672))
+ (import "env" "gda" (func $internal3673))
+ (import "env" "hda" (func $internal3674))
+ (import "env" "ida" (func $internal3675))
+ (import "env" "jda" (func $internal3676))
+ (import "env" "kda" (func $internal3677))
+ (import "env" "lda" (func $internal3678))
+ (import "env" "mda" (func $internal3679))
+ (import "env" "nda" (func $internal3680))
+ (import "env" "oda" (func $internal3681))
+ (import "env" "pda" (func $internal3682))
+ (import "env" "qda" (func $internal3683))
+ (import "env" "rda" (func $internal3684))
+ (import "env" "sda" (func $internal3685))
+ (import "env" "tda" (func $internal3686))
+ (import "env" "uda" (func $internal3687))
+ (import "env" "vda" (func $internal3688))
+ (import "env" "wda" (func $internal3689))
+ (import "env" "xda" (func $internal3690))
+ (import "env" "yda" (func $internal3691))
+ (import "env" "zda" (func $internal3692))
+ (import "env" "Ada" (func $internal3693))
+ (import "env" "Bda" (func $internal3694))
+ (import "env" "Cda" (func $internal3695))
+ (import "env" "Dda" (func $internal3696))
+ (import "env" "Eda" (func $internal3697))
+ (import "env" "Fda" (func $internal3698))
+ (import "env" "Gda" (func $internal3699))
+ (import "env" "Hda" (func $internal3700))
+ (import "env" "Ida" (func $internal3701))
+ (import "env" "Jda" (func $internal3702))
+ (import "env" "Kda" (func $internal3703))
+ (import "env" "Lda" (func $internal3704))
+ (import "env" "Mda" (func $internal3705))
+ (import "env" "Nda" (func $internal3706))
+ (import "env" "Oda" (func $internal3707))
+ (import "env" "Pda" (func $internal3708))
+ (import "env" "Qda" (func $internal3709))
+ (import "env" "Rda" (func $internal3710))
+ (import "env" "Sda" (func $internal3711))
+ (import "env" "Tda" (func $internal3712))
+ (import "env" "Uda" (func $internal3713))
+ (import "env" "Vda" (func $internal3714))
+ (import "env" "Wda" (func $internal3715))
+ (import "env" "Xda" (func $internal3716))
+ (import "env" "Yda" (func $internal3717))
+ (import "env" "Zda" (func $internal3718))
+ (import "env" "_da" (func $internal3719))
+ (import "env" "$da" (func $internal3720))
+ (import "env" "aea" (func $internal3721))
+ (import "env" "bea" (func $internal3722))
+ (import "env" "cea" (func $internal3723))
+ (import "env" "dea" (func $internal3724))
+ (import "env" "eea" (func $internal3725))
+ (import "env" "fea" (func $internal3726))
+ (import "env" "gea" (func $internal3727))
+ (import "env" "hea" (func $internal3728))
+ (import "env" "iea" (func $internal3729))
+ (import "env" "jea" (func $internal3730))
+ (import "env" "kea" (func $internal3731))
+ (import "env" "lea" (func $internal3732))
+ (import "env" "mea" (func $internal3733))
+ (import "env" "nea" (func $internal3734))
+ (import "env" "oea" (func $internal3735))
+ (import "env" "pea" (func $internal3736))
+ (import "env" "qea" (func $internal3737))
+ (import "env" "rea" (func $internal3738))
+ (import "env" "sea" (func $internal3739))
+ (import "env" "tea" (func $internal3740))
+ (import "env" "uea" (func $internal3741))
+ (import "env" "vea" (func $internal3742))
+ (import "env" "wea" (func $internal3743))
+ (import "env" "xea" (func $internal3744))
+ (import "env" "yea" (func $internal3745))
+ (import "env" "zea" (func $internal3746))
+ (import "env" "Aea" (func $internal3747))
+ (import "env" "Bea" (func $internal3748))
+ (import "env" "Cea" (func $internal3749))
+ (import "env" "Dea" (func $internal3750))
+ (import "env" "Eea" (func $internal3751))
+ (import "env" "Fea" (func $internal3752))
+ (import "env" "Gea" (func $internal3753))
+ (import "env" "Hea" (func $internal3754))
+ (import "env" "Iea" (func $internal3755))
+ (import "env" "Jea" (func $internal3756))
+ (import "env" "Kea" (func $internal3757))
+ (import "env" "Lea" (func $internal3758))
+ (import "env" "Mea" (func $internal3759))
+ (import "env" "Nea" (func $internal3760))
+ (import "env" "Oea" (func $internal3761))
+ (import "env" "Pea" (func $internal3762))
+ (import "env" "Qea" (func $internal3763))
+ (import "env" "Rea" (func $internal3764))
+ (import "env" "Sea" (func $internal3765))
+ (import "env" "Tea" (func $internal3766))
+ (import "env" "Uea" (func $internal3767))
+ (import "env" "Vea" (func $internal3768))
+ (import "env" "Wea" (func $internal3769))
+ (import "env" "Xea" (func $internal3770))
+ (import "env" "Yea" (func $internal3771))
+ (import "env" "Zea" (func $internal3772))
+ (import "env" "_ea" (func $internal3773))
+ (import "env" "$ea" (func $internal3774))
+ (import "env" "afa" (func $internal3775))
+ (import "env" "bfa" (func $internal3776))
+ (import "env" "cfa" (func $internal3777))
+ (import "env" "dfa" (func $internal3778))
+ (import "env" "efa" (func $internal3779))
+ (import "env" "ffa" (func $internal3780))
+ (import "env" "gfa" (func $internal3781))
+ (import "env" "hfa" (func $internal3782))
+ (import "env" "ifa" (func $internal3783))
+ (import "env" "jfa" (func $internal3784))
+ (import "env" "kfa" (func $internal3785))
+ (import "env" "lfa" (func $internal3786))
+ (import "env" "mfa" (func $internal3787))
+ (import "env" "nfa" (func $internal3788))
+ (import "env" "ofa" (func $internal3789))
+ (import "env" "pfa" (func $internal3790))
+ (import "env" "qfa" (func $internal3791))
+ (import "env" "rfa" (func $internal3792))
+ (import "env" "sfa" (func $internal3793))
+ (import "env" "tfa" (func $internal3794))
+ (import "env" "ufa" (func $internal3795))
+ (import "env" "vfa" (func $internal3796))
+ (import "env" "wfa" (func $internal3797))
+ (import "env" "xfa" (func $internal3798))
+ (import "env" "yfa" (func $internal3799))
+ (import "env" "zfa" (func $internal3800))
+ (import "env" "Afa" (func $internal3801))
+ (import "env" "Bfa" (func $internal3802))
+ (import "env" "Cfa" (func $internal3803))
+ (import "env" "Dfa" (func $internal3804))
+ (import "env" "Efa" (func $internal3805))
+ (import "env" "Ffa" (func $internal3806))
+ (import "env" "Gfa" (func $internal3807))
+ (import "env" "Hfa" (func $internal3808))
+ (import "env" "Ifa" (func $internal3809))
+ (import "env" "Jfa" (func $internal3810))
+ (import "env" "Kfa" (func $internal3811))
+ (import "env" "Lfa" (func $internal3812))
+ (import "env" "Mfa" (func $internal3813))
+ (import "env" "Nfa" (func $internal3814))
+ (import "env" "Ofa" (func $internal3815))
+ (import "env" "Pfa" (func $internal3816))
+ (import "env" "Qfa" (func $internal3817))
+ (import "env" "Rfa" (func $internal3818))
+ (import "env" "Sfa" (func $internal3819))
+ (import "env" "Tfa" (func $internal3820))
+ (import "env" "Ufa" (func $internal3821))
+ (import "env" "Vfa" (func $internal3822))
+ (import "env" "Wfa" (func $internal3823))
+ (import "env" "Xfa" (func $internal3824))
+ (import "env" "Yfa" (func $internal3825))
+ (import "env" "Zfa" (func $internal3826))
+ (import "env" "_fa" (func $internal3827))
+ (import "env" "$fa" (func $internal3828))
+ (import "env" "aga" (func $internal3829))
+ (import "env" "bga" (func $internal3830))
+ (import "env" "cga" (func $internal3831))
+ (import "env" "dga" (func $internal3832))
+ (import "env" "ega" (func $internal3833))
+ (import "env" "fga" (func $internal3834))
+ (import "env" "gga" (func $internal3835))
+ (import "env" "hga" (func $internal3836))
+ (import "env" "iga" (func $internal3837))
+ (import "env" "jga" (func $internal3838))
+ (import "env" "kga" (func $internal3839))
+ (import "env" "lga" (func $internal3840))
+ (import "env" "mga" (func $internal3841))
+ (import "env" "nga" (func $internal3842))
+ (import "env" "oga" (func $internal3843))
+ (import "env" "pga" (func $internal3844))
+ (import "env" "qga" (func $internal3845))
+ (import "env" "rga" (func $internal3846))
+ (import "env" "sga" (func $internal3847))
+ (import "env" "tga" (func $internal3848))
+ (import "env" "uga" (func $internal3849))
+ (import "env" "vga" (func $internal3850))
+ (import "env" "wga" (func $internal3851))
+ (import "env" "xga" (func $internal3852))
+ (import "env" "yga" (func $internal3853))
+ (import "env" "zga" (func $internal3854))
+ (import "env" "Aga" (func $internal3855))
+ (import "env" "Bga" (func $internal3856))
+ (import "env" "Cga" (func $internal3857))
+ (import "env" "Dga" (func $internal3858))
+ (import "env" "Ega" (func $internal3859))
+ (import "env" "Fga" (func $internal3860))
+ (import "env" "Gga" (func $internal3861))
+ (import "env" "Hga" (func $internal3862))
+ (import "env" "Iga" (func $internal3863))
+ (import "env" "Jga" (func $internal3864))
+ (import "env" "Kga" (func $internal3865))
+ (import "env" "Lga" (func $internal3866))
+ (import "env" "Mga" (func $internal3867))
+ (import "env" "Nga" (func $internal3868))
+ (import "env" "Oga" (func $internal3869))
+ (import "env" "Pga" (func $internal3870))
+ (import "env" "Qga" (func $internal3871))
+ (import "env" "Rga" (func $internal3872))
+ (import "env" "Sga" (func $internal3873))
+ (import "env" "Tga" (func $internal3874))
+ (import "env" "Uga" (func $internal3875))
+ (import "env" "Vga" (func $internal3876))
+ (import "env" "Wga" (func $internal3877))
+ (import "env" "Xga" (func $internal3878))
+ (import "env" "Yga" (func $internal3879))
+ (import "env" "Zga" (func $internal3880))
+ (import "env" "_ga" (func $internal3881))
+ (import "env" "$ga" (func $internal3882))
+ (import "env" "aha" (func $internal3883))
+ (import "env" "bha" (func $internal3884))
+ (import "env" "cha" (func $internal3885))
+ (import "env" "dha" (func $internal3886))
+ (import "env" "eha" (func $internal3887))
+ (import "env" "fha" (func $internal3888))
+ (import "env" "gha" (func $internal3889))
+ (import "env" "hha" (func $internal3890))
+ (import "env" "iha" (func $internal3891))
+ (import "env" "jha" (func $internal3892))
+ (import "env" "kha" (func $internal3893))
+ (import "env" "lha" (func $internal3894))
+ (import "env" "mha" (func $internal3895))
+ (import "env" "nha" (func $internal3896))
+ (import "env" "oha" (func $internal3897))
+ (import "env" "pha" (func $internal3898))
+ (import "env" "qha" (func $internal3899))
+ (import "env" "rha" (func $internal3900))
+ (import "env" "sha" (func $internal3901))
+ (import "env" "tha" (func $internal3902))
+ (import "env" "uha" (func $internal3903))
+ (import "env" "vha" (func $internal3904))
+ (import "env" "wha" (func $internal3905))
+ (import "env" "xha" (func $internal3906))
+ (import "env" "yha" (func $internal3907))
+ (import "env" "zha" (func $internal3908))
+ (import "env" "Aha" (func $internal3909))
+ (import "env" "Bha" (func $internal3910))
+ (import "env" "Cha" (func $internal3911))
+ (import "env" "Dha" (func $internal3912))
+ (import "env" "Eha" (func $internal3913))
+ (import "env" "Fha" (func $internal3914))
+ (import "env" "Gha" (func $internal3915))
+ (import "env" "Hha" (func $internal3916))
+ (import "env" "Iha" (func $internal3917))
+ (import "env" "Jha" (func $internal3918))
+ (import "env" "Kha" (func $internal3919))
+ (import "env" "Lha" (func $internal3920))
+ (import "env" "Mha" (func $internal3921))
+ (import "env" "Nha" (func $internal3922))
+ (import "env" "Oha" (func $internal3923))
+ (import "env" "Pha" (func $internal3924))
+ (import "env" "Qha" (func $internal3925))
+ (import "env" "Rha" (func $internal3926))
+ (import "env" "Sha" (func $internal3927))
+ (import "env" "Tha" (func $internal3928))
+ (import "env" "Uha" (func $internal3929))
+ (import "env" "Vha" (func $internal3930))
+ (import "env" "Wha" (func $internal3931))
+ (import "env" "Xha" (func $internal3932))
+ (import "env" "Yha" (func $internal3933))
+ (import "env" "Zha" (func $internal3934))
+ (import "env" "_ha" (func $internal3935))
+ (import "env" "$ha" (func $internal3936))
+ (import "env" "aia" (func $internal3937))
+ (import "env" "bia" (func $internal3938))
+ (import "env" "cia" (func $internal3939))
+ (import "env" "dia" (func $internal3940))
+ (import "env" "eia" (func $internal3941))
+ (import "env" "fia" (func $internal3942))
+ (import "env" "gia" (func $internal3943))
+ (import "env" "hia" (func $internal3944))
+ (import "env" "iia" (func $internal3945))
+ (import "env" "jia" (func $internal3946))
+ (import "env" "kia" (func $internal3947))
+ (import "env" "lia" (func $internal3948))
+ (import "env" "mia" (func $internal3949))
+ (import "env" "nia" (func $internal3950))
+ (import "env" "oia" (func $internal3951))
+ (import "env" "pia" (func $internal3952))
+ (import "env" "qia" (func $internal3953))
+ (import "env" "ria" (func $internal3954))
+ (import "env" "sia" (func $internal3955))
+ (import "env" "tia" (func $internal3956))
+ (import "env" "uia" (func $internal3957))
+ (import "env" "via" (func $internal3958))
+ (import "env" "wia" (func $internal3959))
+ (import "env" "xia" (func $internal3960))
+ (import "env" "yia" (func $internal3961))
+ (import "env" "zia" (func $internal3962))
+ (import "env" "Aia" (func $internal3963))
+ (import "env" "Bia" (func $internal3964))
+ (import "env" "Cia" (func $internal3965))
+ (import "env" "Dia" (func $internal3966))
+ (import "env" "Eia" (func $internal3967))
+ (import "env" "Fia" (func $internal3968))
+ (import "env" "Gia" (func $internal3969))
+ (import "env" "Hia" (func $internal3970))
+ (import "env" "Iia" (func $internal3971))
+ (import "env" "Jia" (func $internal3972))
+ (import "env" "Kia" (func $internal3973))
+ (import "env" "Lia" (func $internal3974))
+ (import "env" "Mia" (func $internal3975))
+ (import "env" "Nia" (func $internal3976))
+ (import "env" "Oia" (func $internal3977))
+ (import "env" "Pia" (func $internal3978))
+ (import "env" "Qia" (func $internal3979))
+ (import "env" "Ria" (func $internal3980))
+ (import "env" "Sia" (func $internal3981))
+ (import "env" "Tia" (func $internal3982))
+ (import "env" "Uia" (func $internal3983))
+ (import "env" "Via" (func $internal3984))
+ (import "env" "Wia" (func $internal3985))
+ (import "env" "Xia" (func $internal3986))
+ (import "env" "Yia" (func $internal3987))
+ (import "env" "Zia" (func $internal3988))
+ (import "env" "_ia" (func $internal3989))
+ (import "env" "$ia" (func $internal3990))
+ (import "env" "aja" (func $internal3991))
+ (import "env" "bja" (func $internal3992))
+ (import "env" "cja" (func $internal3993))
+ (import "env" "dja" (func $internal3994))
+ (import "env" "eja" (func $internal3995))
+ (import "env" "fja" (func $internal3996))
+ (import "env" "gja" (func $internal3997))
+ (import "env" "hja" (func $internal3998))
+ (import "env" "ija" (func $internal3999))
+ (import "env" "jja" (func $internal4000))
+ (import "env" "kja" (func $internal4001))
+ (import "env" "lja" (func $internal4002))
+ (import "env" "mja" (func $internal4003))
+ (import "env" "nja" (func $internal4004))
+ (import "env" "oja" (func $internal4005))
+ (import "env" "pja" (func $internal4006))
+ (import "env" "qja" (func $internal4007))
+ (import "env" "rja" (func $internal4008))
+ (import "env" "sja" (func $internal4009))
+ (import "env" "tja" (func $internal4010))
+ (import "env" "uja" (func $internal4011))
+ (import "env" "vja" (func $internal4012))
+ (import "env" "wja" (func $internal4013))
+ (import "env" "xja" (func $internal4014))
+ (import "env" "yja" (func $internal4015))
+ (import "env" "zja" (func $internal4016))
+ (import "env" "Aja" (func $internal4017))
+ (import "env" "Bja" (func $internal4018))
+ (import "env" "Cja" (func $internal4019))
+ (import "env" "Dja" (func $internal4020))
+ (import "env" "Eja" (func $internal4021))
+ (import "env" "Fja" (func $internal4022))
+ (import "env" "Gja" (func $internal4023))
+ (import "env" "Hja" (func $internal4024))
+ (import "env" "Ija" (func $internal4025))
+ (import "env" "Jja" (func $internal4026))
+ (import "env" "Kja" (func $internal4027))
+ (import "env" "Lja" (func $internal4028))
+ (import "env" "Mja" (func $internal4029))
+ (import "env" "Nja" (func $internal4030))
+ (import "env" "Oja" (func $internal4031))
+ (import "env" "Pja" (func $internal4032))
+ (import "env" "Qja" (func $internal4033))
+ (import "env" "Rja" (func $internal4034))
+ (import "env" "Sja" (func $internal4035))
+ (import "env" "Tja" (func $internal4036))
+ (import "env" "Uja" (func $internal4037))
+ (import "env" "Vja" (func $internal4038))
+ (import "env" "Wja" (func $internal4039))
+ (import "env" "Xja" (func $internal4040))
+ (import "env" "Yja" (func $internal4041))
+ (import "env" "Zja" (func $internal4042))
+ (import "env" "_ja" (func $internal4043))
+ (import "env" "$ja" (func $internal4044))
+ (import "env" "aka" (func $internal4045))
+ (import "env" "bka" (func $internal4046))
+ (import "env" "cka" (func $internal4047))
+ (import "env" "dka" (func $internal4048))
+ (import "env" "eka" (func $internal4049))
+ (import "env" "fka" (func $internal4050))
+ (import "env" "gka" (func $internal4051))
+ (import "env" "hka" (func $internal4052))
+ (import "env" "ika" (func $internal4053))
+ (import "env" "jka" (func $internal4054))
+ (import "env" "kka" (func $internal4055))
+ (import "env" "lka" (func $internal4056))
+ (import "env" "mka" (func $internal4057))
+ (import "env" "nka" (func $internal4058))
+ (import "env" "oka" (func $internal4059))
+ (import "env" "pka" (func $internal4060))
+ (import "env" "qka" (func $internal4061))
+ (import "env" "rka" (func $internal4062))
+ (import "env" "ska" (func $internal4063))
+ (import "env" "tka" (func $internal4064))
+ (import "env" "uka" (func $internal4065))
+ (import "env" "vka" (func $internal4066))
+ (import "env" "wka" (func $internal4067))
+ (import "env" "xka" (func $internal4068))
+ (import "env" "yka" (func $internal4069))
+ (import "env" "zka" (func $internal4070))
+ (import "env" "Aka" (func $internal4071))
+ (import "env" "Bka" (func $internal4072))
+ (import "env" "Cka" (func $internal4073))
+ (import "env" "Dka" (func $internal4074))
+ (import "env" "Eka" (func $internal4075))
+ (import "env" "Fka" (func $internal4076))
+ (import "env" "Gka" (func $internal4077))
+ (import "env" "Hka" (func $internal4078))
+ (import "env" "Ika" (func $internal4079))
+ (import "env" "Jka" (func $internal4080))
+ (import "env" "Kka" (func $internal4081))
+ (import "env" "Lka" (func $internal4082))
+ (import "env" "Mka" (func $internal4083))
+ (import "env" "Nka" (func $internal4084))
+ (import "env" "Oka" (func $internal4085))
+ (import "env" "Pka" (func $internal4086))
+ (import "env" "Qka" (func $internal4087))
+ (import "env" "Rka" (func $internal4088))
+ (import "env" "Ska" (func $internal4089))
+ (import "env" "Tka" (func $internal4090))
+ (import "env" "Uka" (func $internal4091))
+ (import "env" "Vka" (func $internal4092))
+ (import "env" "Wka" (func $internal4093))
+ (import "env" "Xka" (func $internal4094))
+ (import "env" "Yka" (func $internal4095))
+ (import "env" "Zka" (func $internal4096))
+ (import "env" "_ka" (func $internal4097))
+ (import "env" "$ka" (func $internal4098))
+ (import "env" "ala" (func $internal4099))
+ (import "env" "bla" (func $internal4100))
+ (import "env" "cla" (func $internal4101))
+ (import "env" "dla" (func $internal4102))
+ (import "env" "ela" (func $internal4103))
+ (import "env" "fla" (func $internal4104))
+ (import "env" "gla" (func $internal4105))
+ (import "env" "hla" (func $internal4106))
+ (import "env" "ila" (func $internal4107))
+ (import "env" "jla" (func $internal4108))
+ (import "env" "kla" (func $internal4109))
+ (import "env" "lla" (func $internal4110))
+ (import "env" "mla" (func $internal4111))
+ (import "env" "nla" (func $internal4112))
+ (import "env" "ola" (func $internal4113))
+ (import "env" "pla" (func $internal4114))
+ (import "env" "qla" (func $internal4115))
+ (import "env" "rla" (func $internal4116))
+ (import "env" "sla" (func $internal4117))
+ (import "env" "tla" (func $internal4118))
+ (import "env" "ula" (func $internal4119))
+ (import "env" "vla" (func $internal4120))
+ (import "env" "wla" (func $internal4121))
+ (import "env" "xla" (func $internal4122))
+ (import "env" "yla" (func $internal4123))
+ (import "env" "zla" (func $internal4124))
+ (import "env" "Ala" (func $internal4125))
+ (import "env" "Bla" (func $internal4126))
+ (import "env" "Cla" (func $internal4127))
+ (import "env" "Dla" (func $internal4128))
+ (import "env" "Ela" (func $internal4129))
+ (import "env" "Fla" (func $internal4130))
+ (import "env" "Gla" (func $internal4131))
+ (import "env" "Hla" (func $internal4132))
+ (import "env" "Ila" (func $internal4133))
+ (import "env" "Jla" (func $internal4134))
+ (import "env" "Kla" (func $internal4135))
+ (import "env" "Lla" (func $internal4136))
+ (import "env" "Mla" (func $internal4137))
+ (import "env" "Nla" (func $internal4138))
+ (import "env" "Ola" (func $internal4139))
+ (import "env" "Pla" (func $internal4140))
+ (import "env" "Qla" (func $internal4141))
+ (import "env" "Rla" (func $internal4142))
+ (import "env" "Sla" (func $internal4143))
+ (import "env" "Tla" (func $internal4144))
+ (import "env" "Ula" (func $internal4145))
+ (import "env" "Vla" (func $internal4146))
+ (import "env" "Wla" (func $internal4147))
+ (import "env" "Xla" (func $internal4148))
+ (import "env" "Yla" (func $internal4149))
+ (import "env" "Zla" (func $internal4150))
+ (import "env" "_la" (func $internal4151))
+ (import "env" "$la" (func $internal4152))
+ (import "env" "ama" (func $internal4153))
+ (import "env" "bma" (func $internal4154))
+ (import "env" "cma" (func $internal4155))
+ (import "env" "dma" (func $internal4156))
+ (import "env" "ema" (func $internal4157))
+ (import "env" "fma" (func $internal4158))
+ (import "env" "gma" (func $internal4159))
+ (import "env" "hma" (func $internal4160))
+ (import "env" "ima" (func $internal4161))
+ (import "env" "jma" (func $internal4162))
+ (import "env" "kma" (func $internal4163))
+ (import "env" "lma" (func $internal4164))
+ (import "env" "mma" (func $internal4165))
+ (import "env" "nma" (func $internal4166))
+ (import "env" "oma" (func $internal4167))
+ (import "env" "pma" (func $internal4168))
+ (import "env" "qma" (func $internal4169))
+ (import "env" "rma" (func $internal4170))
+ (import "env" "sma" (func $internal4171))
+ (import "env" "tma" (func $internal4172))
+ (import "env" "uma" (func $internal4173))
+ (import "env" "vma" (func $internal4174))
+ (import "env" "wma" (func $internal4175))
+ (import "env" "xma" (func $internal4176))
+ (import "env" "yma" (func $internal4177))
+ (import "env" "zma" (func $internal4178))
+ (import "env" "Ama" (func $internal4179))
+ (import "env" "Bma" (func $internal4180))
+ (import "env" "Cma" (func $internal4181))
+ (import "env" "Dma" (func $internal4182))
+ (import "env" "Ema" (func $internal4183))
+ (import "env" "Fma" (func $internal4184))
+ (import "env" "Gma" (func $internal4185))
+ (import "env" "Hma" (func $internal4186))
+ (import "env" "Ima" (func $internal4187))
+ (import "env" "Jma" (func $internal4188))
+ (import "env" "Kma" (func $internal4189))
+ (import "env" "Lma" (func $internal4190))
+ (import "env" "Mma" (func $internal4191))
+ (import "env" "Nma" (func $internal4192))
+ (import "env" "Oma" (func $internal4193))
+ (import "env" "Pma" (func $internal4194))
+ (import "env" "Qma" (func $internal4195))
+ (import "env" "Rma" (func $internal4196))
+ (import "env" "Sma" (func $internal4197))
+ (import "env" "Tma" (func $internal4198))
+ (import "env" "Uma" (func $internal4199))
+ (import "env" "Vma" (func $internal4200))
+ (import "env" "Wma" (func $internal4201))
+ (import "env" "Xma" (func $internal4202))
+ (import "env" "Yma" (func $internal4203))
+ (import "env" "Zma" (func $internal4204))
+ (import "env" "_ma" (func $internal4205))
+ (import "env" "$ma" (func $internal4206))
+ (import "env" "ana" (func $internal4207))
+ (import "env" "bna" (func $internal4208))
+ (import "env" "cna" (func $internal4209))
+ (import "env" "dna" (func $internal4210))
+ (import "env" "ena" (func $internal4211))
+ (import "env" "fna" (func $internal4212))
+ (import "env" "gna" (func $internal4213))
+ (import "env" "hna" (func $internal4214))
+ (import "env" "ina" (func $internal4215))
+ (import "env" "jna" (func $internal4216))
+ (import "env" "kna" (func $internal4217))
+ (import "env" "lna" (func $internal4218))
+ (import "env" "mna" (func $internal4219))
+ (import "env" "nna" (func $internal4220))
+ (import "env" "ona" (func $internal4221))
+ (import "env" "pna" (func $internal4222))
+ (import "env" "qna" (func $internal4223))
+ (import "env" "rna" (func $internal4224))
+ (import "env" "sna" (func $internal4225))
+ (import "env" "tna" (func $internal4226))
+ (import "env" "una" (func $internal4227))
+ (import "env" "vna" (func $internal4228))
+ (import "env" "wna" (func $internal4229))
+ (import "env" "xna" (func $internal4230))
+ (import "env" "yna" (func $internal4231))
+ (import "env" "zna" (func $internal4232))
+ (import "env" "Ana" (func $internal4233))
+ (import "env" "Bna" (func $internal4234))
+ (import "env" "Cna" (func $internal4235))
+ (import "env" "Dna" (func $internal4236))
+ (import "env" "Ena" (func $internal4237))
+ (import "env" "Fna" (func $internal4238))
+ (import "env" "Gna" (func $internal4239))
+ (import "env" "Hna" (func $internal4240))
+ (import "env" "Ina" (func $internal4241))
+ (import "env" "Jna" (func $internal4242))
+ (import "env" "Kna" (func $internal4243))
+ (import "env" "Lna" (func $internal4244))
+ (import "env" "Mna" (func $internal4245))
+ (import "env" "Nna" (func $internal4246))
+ (import "env" "Ona" (func $internal4247))
+ (import "env" "Pna" (func $internal4248))
+ (import "env" "Qna" (func $internal4249))
+ (import "env" "Rna" (func $internal4250))
+ (import "env" "Sna" (func $internal4251))
+ (import "env" "Tna" (func $internal4252))
+ (import "env" "Una" (func $internal4253))
+ (import "env" "Vna" (func $internal4254))
+ (import "env" "Wna" (func $internal4255))
+ (import "env" "Xna" (func $internal4256))
+ (import "env" "Yna" (func $internal4257))
+ (import "env" "Zna" (func $internal4258))
+ (import "env" "_na" (func $internal4259))
+ (import "env" "$na" (func $internal4260))
+ (import "env" "aoa" (func $internal4261))
+ (import "env" "boa" (func $internal4262))
+ (import "env" "coa" (func $internal4263))
+ (import "env" "doa" (func $internal4264))
+ (import "env" "eoa" (func $internal4265))
+ (import "env" "foa" (func $internal4266))
+ (import "env" "goa" (func $internal4267))
+ (import "env" "hoa" (func $internal4268))
+ (import "env" "ioa" (func $internal4269))
+ (import "env" "joa" (func $internal4270))
+ (import "env" "koa" (func $internal4271))
+ (import "env" "loa" (func $internal4272))
+ (import "env" "moa" (func $internal4273))
+ (import "env" "noa" (func $internal4274))
+ (import "env" "ooa" (func $internal4275))
+ (import "env" "poa" (func $internal4276))
+ (import "env" "qoa" (func $internal4277))
+ (import "env" "roa" (func $internal4278))
+ (import "env" "soa" (func $internal4279))
+ (import "env" "toa" (func $internal4280))
+ (import "env" "uoa" (func $internal4281))
+ (import "env" "voa" (func $internal4282))
+ (import "env" "woa" (func $internal4283))
+ (import "env" "xoa" (func $internal4284))
+ (import "env" "yoa" (func $internal4285))
+ (import "env" "zoa" (func $internal4286))
+ (import "env" "Aoa" (func $internal4287))
+ (import "env" "Boa" (func $internal4288))
+ (import "env" "Coa" (func $internal4289))
+ (import "env" "Doa" (func $internal4290))
+ (import "env" "Eoa" (func $internal4291))
+ (import "env" "Foa" (func $internal4292))
+ (import "env" "Goa" (func $internal4293))
+ (import "env" "Hoa" (func $internal4294))
+ (import "env" "Ioa" (func $internal4295))
+ (import "env" "Joa" (func $internal4296))
+ (import "env" "Koa" (func $internal4297))
+ (import "env" "Loa" (func $internal4298))
+ (import "env" "Moa" (func $internal4299))
+ (import "env" "Noa" (func $internal4300))
+ (import "env" "Ooa" (func $internal4301))
+ (import "env" "Poa" (func $internal4302))
+ (import "env" "Qoa" (func $internal4303))
+ (import "env" "Roa" (func $internal4304))
+ (import "env" "Soa" (func $internal4305))
+ (import "env" "Toa" (func $internal4306))
+ (import "env" "Uoa" (func $internal4307))
+ (import "env" "Voa" (func $internal4308))
+ (import "env" "Woa" (func $internal4309))
+ (import "env" "Xoa" (func $internal4310))
+ (import "env" "Yoa" (func $internal4311))
+ (import "env" "Zoa" (func $internal4312))
+ (import "env" "_oa" (func $internal4313))
+ (import "env" "$oa" (func $internal4314))
+ (import "env" "apa" (func $internal4315))
+ (import "env" "bpa" (func $internal4316))
+ (import "env" "cpa" (func $internal4317))
+ (import "env" "dpa" (func $internal4318))
+ (import "env" "epa" (func $internal4319))
+ (import "env" "fpa" (func $internal4320))
+ (import "env" "gpa" (func $internal4321))
+ (import "env" "hpa" (func $internal4322))
+ (import "env" "ipa" (func $internal4323))
+ (import "env" "jpa" (func $internal4324))
+ (import "env" "kpa" (func $internal4325))
+ (import "env" "lpa" (func $internal4326))
+ (import "env" "mpa" (func $internal4327))
+ (import "env" "npa" (func $internal4328))
+ (import "env" "opa" (func $internal4329))
+ (import "env" "ppa" (func $internal4330))
+ (import "env" "qpa" (func $internal4331))
+ (import "env" "rpa" (func $internal4332))
+ (import "env" "spa" (func $internal4333))
+ (import "env" "tpa" (func $internal4334))
+ (import "env" "upa" (func $internal4335))
+ (import "env" "vpa" (func $internal4336))
+ (import "env" "wpa" (func $internal4337))
+ (import "env" "xpa" (func $internal4338))
+ (import "env" "ypa" (func $internal4339))
+ (import "env" "zpa" (func $internal4340))
+ (import "env" "Apa" (func $internal4341))
+ (import "env" "Bpa" (func $internal4342))
+ (import "env" "Cpa" (func $internal4343))
+ (import "env" "Dpa" (func $internal4344))
+ (import "env" "Epa" (func $internal4345))
+ (import "env" "Fpa" (func $internal4346))
+ (import "env" "Gpa" (func $internal4347))
+ (import "env" "Hpa" (func $internal4348))
+ (import "env" "Ipa" (func $internal4349))
+ (import "env" "Jpa" (func $internal4350))
+ (import "env" "Kpa" (func $internal4351))
+ (import "env" "Lpa" (func $internal4352))
+ (import "env" "Mpa" (func $internal4353))
+ (import "env" "Npa" (func $internal4354))
+ (import "env" "Opa" (func $internal4355))
+ (import "env" "Ppa" (func $internal4356))
+ (import "env" "Qpa" (func $internal4357))
+ (import "env" "Rpa" (func $internal4358))
+ (import "env" "Spa" (func $internal4359))
+ (import "env" "Tpa" (func $internal4360))
+ (import "env" "Upa" (func $internal4361))
+ (import "env" "Vpa" (func $internal4362))
+ (import "env" "Wpa" (func $internal4363))
+ (import "env" "Xpa" (func $internal4364))
+ (import "env" "Ypa" (func $internal4365))
+ (import "env" "Zpa" (func $internal4366))
+ (import "env" "_pa" (func $internal4367))
+ (import "env" "$pa" (func $internal4368))
+ (import "env" "aqa" (func $internal4369))
+ (import "env" "bqa" (func $internal4370))
+ (import "env" "cqa" (func $internal4371))
+ (import "env" "dqa" (func $internal4372))
+ (import "env" "eqa" (func $internal4373))
+ (import "env" "fqa" (func $internal4374))
+ (import "env" "gqa" (func $internal4375))
+ (import "env" "hqa" (func $internal4376))
+ (import "env" "iqa" (func $internal4377))
+ (import "env" "jqa" (func $internal4378))
+ (import "env" "kqa" (func $internal4379))
+ (import "env" "lqa" (func $internal4380))
+ (import "env" "mqa" (func $internal4381))
+ (import "env" "nqa" (func $internal4382))
+ (import "env" "oqa" (func $internal4383))
+ (import "env" "pqa" (func $internal4384))
+ (import "env" "qqa" (func $internal4385))
+ (import "env" "rqa" (func $internal4386))
+ (import "env" "sqa" (func $internal4387))
+ (import "env" "tqa" (func $internal4388))
+ (import "env" "uqa" (func $internal4389))
+ (import "env" "vqa" (func $internal4390))
+ (import "env" "wqa" (func $internal4391))
+ (import "env" "xqa" (func $internal4392))
+ (import "env" "yqa" (func $internal4393))
+ (import "env" "zqa" (func $internal4394))
+ (import "env" "Aqa" (func $internal4395))
+ (import "env" "Bqa" (func $internal4396))
+ (import "env" "Cqa" (func $internal4397))
+ (import "env" "Dqa" (func $internal4398))
+ (import "env" "Eqa" (func $internal4399))
+ (import "env" "Fqa" (func $internal4400))
+ (import "env" "Gqa" (func $internal4401))
+ (import "env" "Hqa" (func $internal4402))
+ (import "env" "Iqa" (func $internal4403))
+ (import "env" "Jqa" (func $internal4404))
+ (import "env" "Kqa" (func $internal4405))
+ (import "env" "Lqa" (func $internal4406))
+ (import "env" "Mqa" (func $internal4407))
+ (import "env" "Nqa" (func $internal4408))
+ (import "env" "Oqa" (func $internal4409))
+ (import "env" "Pqa" (func $internal4410))
+ (import "env" "Qqa" (func $internal4411))
+ (import "env" "Rqa" (func $internal4412))
+ (import "env" "Sqa" (func $internal4413))
+ (import "env" "Tqa" (func $internal4414))
+ (import "env" "Uqa" (func $internal4415))
+ (import "env" "Vqa" (func $internal4416))
+ (import "env" "Wqa" (func $internal4417))
+ (import "env" "Xqa" (func $internal4418))
+ (import "env" "Yqa" (func $internal4419))
+ (import "env" "Zqa" (func $internal4420))
+ (import "env" "_qa" (func $internal4421))
+ (import "env" "$qa" (func $internal4422))
+ (import "env" "ara" (func $internal4423))
+ (import "env" "bra" (func $internal4424))
+ (import "env" "cra" (func $internal4425))
+ (import "env" "dra" (func $internal4426))
+ (import "env" "era" (func $internal4427))
+ (import "env" "fra" (func $internal4428))
+ (import "env" "gra" (func $internal4429))
+ (import "env" "hra" (func $internal4430))
+ (import "env" "ira" (func $internal4431))
+ (import "env" "jra" (func $internal4432))
+ (import "env" "kra" (func $internal4433))
+ (import "env" "lra" (func $internal4434))
+ (import "env" "mra" (func $internal4435))
+ (import "env" "nra" (func $internal4436))
+ (import "env" "ora" (func $internal4437))
+ (import "env" "pra" (func $internal4438))
+ (import "env" "qra" (func $internal4439))
+ (import "env" "rra" (func $internal4440))
+ (import "env" "sra" (func $internal4441))
+ (import "env" "tra" (func $internal4442))
+ (import "env" "ura" (func $internal4443))
+ (import "env" "vra" (func $internal4444))
+ (import "env" "wra" (func $internal4445))
+ (import "env" "xra" (func $internal4446))
+ (import "env" "yra" (func $internal4447))
+ (import "env" "zra" (func $internal4448))
+ (import "env" "Ara" (func $internal4449))
+ (import "env" "Bra" (func $internal4450))
+ (import "env" "Cra" (func $internal4451))
+ (import "env" "Dra" (func $internal4452))
+ (import "env" "Era" (func $internal4453))
+ (import "env" "Fra" (func $internal4454))
+ (import "env" "Gra" (func $internal4455))
+ (import "env" "Hra" (func $internal4456))
+ (import "env" "Ira" (func $internal4457))
+ (import "env" "Jra" (func $internal4458))
+ (import "env" "Kra" (func $internal4459))
+ (import "env" "Lra" (func $internal4460))
+ (import "env" "Mra" (func $internal4461))
+ (import "env" "Nra" (func $internal4462))
+ (import "env" "Ora" (func $internal4463))
+ (import "env" "Pra" (func $internal4464))
+ (import "env" "Qra" (func $internal4465))
+ (import "env" "Rra" (func $internal4466))
+ (import "env" "Sra" (func $internal4467))
+ (import "env" "Tra" (func $internal4468))
+ (import "env" "Ura" (func $internal4469))
+ (import "env" "Vra" (func $internal4470))
+ (import "env" "Wra" (func $internal4471))
+ (import "env" "Xra" (func $internal4472))
+ (import "env" "Yra" (func $internal4473))
+ (import "env" "Zra" (func $internal4474))
+ (import "env" "_ra" (func $internal4475))
+ (import "env" "$ra" (func $internal4476))
+ (import "env" "asa" (func $internal4477))
+ (import "env" "bsa" (func $internal4478))
+ (import "env" "csa" (func $internal4479))
+ (import "env" "dsa" (func $internal4480))
+ (import "env" "esa" (func $internal4481))
+ (import "env" "fsa" (func $internal4482))
+ (import "env" "gsa" (func $internal4483))
+ (import "env" "hsa" (func $internal4484))
+ (import "env" "isa" (func $internal4485))
+ (import "env" "jsa" (func $internal4486))
+ (import "env" "ksa" (func $internal4487))
+ (import "env" "lsa" (func $internal4488))
+ (import "env" "msa" (func $internal4489))
+ (import "env" "nsa" (func $internal4490))
+ (import "env" "osa" (func $internal4491))
+ (import "env" "psa" (func $internal4492))
+ (import "env" "qsa" (func $internal4493))
+ (import "env" "rsa" (func $internal4494))
+ (import "env" "ssa" (func $internal4495))
+ (import "env" "tsa" (func $internal4496))
+ (import "env" "usa" (func $internal4497))
+ (import "env" "vsa" (func $internal4498))
+ (import "env" "wsa" (func $internal4499))
+ (import "env" "xsa" (func $internal4500))
+ (import "env" "ysa" (func $internal4501))
+ (import "env" "zsa" (func $internal4502))
+ (import "env" "Asa" (func $internal4503))
+ (import "env" "Bsa" (func $internal4504))
+ (import "env" "Csa" (func $internal4505))
+ (import "env" "Dsa" (func $internal4506))
+ (import "env" "Esa" (func $internal4507))
+ (import "env" "Fsa" (func $internal4508))
+ (import "env" "Gsa" (func $internal4509))
+ (import "env" "Hsa" (func $internal4510))
+ (import "env" "Isa" (func $internal4511))
+ (import "env" "Jsa" (func $internal4512))
+ (import "env" "Ksa" (func $internal4513))
+ (import "env" "Lsa" (func $internal4514))
+ (import "env" "Msa" (func $internal4515))
+ (import "env" "Nsa" (func $internal4516))
+ (import "env" "Osa" (func $internal4517))
+ (import "env" "Psa" (func $internal4518))
+ (import "env" "Qsa" (func $internal4519))
+ (import "env" "Rsa" (func $internal4520))
+ (import "env" "Ssa" (func $internal4521))
+ (import "env" "Tsa" (func $internal4522))
+ (import "env" "Usa" (func $internal4523))
+ (import "env" "Vsa" (func $internal4524))
+ (import "env" "Wsa" (func $internal4525))
+ (import "env" "Xsa" (func $internal4526))
+ (import "env" "Ysa" (func $internal4527))
+ (import "env" "Zsa" (func $internal4528))
+ (import "env" "_sa" (func $internal4529))
+ (import "env" "$sa" (func $internal4530))
+ (import "env" "ata" (func $internal4531))
+ (import "env" "bta" (func $internal4532))
+ (import "env" "cta" (func $internal4533))
+ (import "env" "dta" (func $internal4534))
+ (import "env" "eta" (func $internal4535))
+ (import "env" "fta" (func $internal4536))
+ (import "env" "gta" (func $internal4537))
+ (import "env" "hta" (func $internal4538))
+ (import "env" "ita" (func $internal4539))
+ (import "env" "jta" (func $internal4540))
+ (import "env" "kta" (func $internal4541))
+ (import "env" "lta" (func $internal4542))
+ (import "env" "mta" (func $internal4543))
+ (import "env" "nta" (func $internal4544))
+ (import "env" "ota" (func $internal4545))
+ (import "env" "pta" (func $internal4546))
+ (import "env" "qta" (func $internal4547))
+ (import "env" "rta" (func $internal4548))
+ (import "env" "sta" (func $internal4549))
+ (import "env" "tta" (func $internal4550))
+ (import "env" "uta" (func $internal4551))
+ (import "env" "vta" (func $internal4552))
+ (import "env" "wta" (func $internal4553))
+ (import "env" "xta" (func $internal4554))
+ (import "env" "yta" (func $internal4555))
+ (import "env" "zta" (func $internal4556))
+ (import "env" "Ata" (func $internal4557))
+ (import "env" "Bta" (func $internal4558))
+ (import "env" "Cta" (func $internal4559))
+ (import "env" "Dta" (func $internal4560))
+ (import "env" "Eta" (func $internal4561))
+ (import "env" "Fta" (func $internal4562))
+ (import "env" "Gta" (func $internal4563))
+ (import "env" "Hta" (func $internal4564))
+ (import "env" "Ita" (func $internal4565))
+ (import "env" "Jta" (func $internal4566))
+ (import "env" "Kta" (func $internal4567))
+ (import "env" "Lta" (func $internal4568))
+ (import "env" "Mta" (func $internal4569))
+ (import "env" "Nta" (func $internal4570))
+ (import "env" "Ota" (func $internal4571))
+ (import "env" "Pta" (func $internal4572))
+ (import "env" "Qta" (func $internal4573))
+ (import "env" "Rta" (func $internal4574))
+ (import "env" "Sta" (func $internal4575))
+ (import "env" "Tta" (func $internal4576))
+ (import "env" "Uta" (func $internal4577))
+ (import "env" "Vta" (func $internal4578))
+ (import "env" "Wta" (func $internal4579))
+ (import "env" "Xta" (func $internal4580))
+ (import "env" "Yta" (func $internal4581))
+ (import "env" "Zta" (func $internal4582))
+ (import "env" "_ta" (func $internal4583))
+ (import "env" "$ta" (func $internal4584))
+ (import "env" "aua" (func $internal4585))
+ (import "env" "bua" (func $internal4586))
+ (import "env" "cua" (func $internal4587))
+ (import "env" "dua" (func $internal4588))
+ (import "env" "eua" (func $internal4589))
+ (import "env" "fua" (func $internal4590))
+ (import "env" "gua" (func $internal4591))
+ (import "env" "hua" (func $internal4592))
+ (import "env" "iua" (func $internal4593))
+ (import "env" "jua" (func $internal4594))
+ (import "env" "kua" (func $internal4595))
+ (import "env" "lua" (func $internal4596))
+ (import "env" "mua" (func $internal4597))
+ (import "env" "nua" (func $internal4598))
+ (import "env" "oua" (func $internal4599))
+ (import "env" "pua" (func $internal4600))
+ (import "env" "qua" (func $internal4601))
+ (import "env" "rua" (func $internal4602))
+ (import "env" "sua" (func $internal4603))
+ (import "env" "tua" (func $internal4604))
+ (import "env" "uua" (func $internal4605))
+ (import "env" "vua" (func $internal4606))
+ (import "env" "wua" (func $internal4607))
+ (import "env" "xua" (func $internal4608))
+ (import "env" "yua" (func $internal4609))
+ (import "env" "zua" (func $internal4610))
+ (import "env" "Aua" (func $internal4611))
+ (import "env" "Bua" (func $internal4612))
+ (import "env" "Cua" (func $internal4613))
+ (import "env" "Dua" (func $internal4614))
+ (import "env" "Eua" (func $internal4615))
+ (import "env" "Fua" (func $internal4616))
+ (import "env" "Gua" (func $internal4617))
+ (import "env" "Hua" (func $internal4618))
+ (import "env" "Iua" (func $internal4619))
+ (import "env" "Jua" (func $internal4620))
+ (import "env" "Kua" (func $internal4621))
+ (import "env" "Lua" (func $internal4622))
+ (import "env" "Mua" (func $internal4623))
+ (import "env" "Nua" (func $internal4624))
+ (import "env" "Oua" (func $internal4625))
+ (import "env" "Pua" (func $internal4626))
+ (import "env" "Qua" (func $internal4627))
+ (import "env" "Rua" (func $internal4628))
+ (import "env" "Sua" (func $internal4629))
+ (import "env" "Tua" (func $internal4630))
+ (import "env" "Uua" (func $internal4631))
+ (import "env" "Vua" (func $internal4632))
+ (import "env" "Wua" (func $internal4633))
+ (import "env" "Xua" (func $internal4634))
+ (import "env" "Yua" (func $internal4635))
+ (import "env" "Zua" (func $internal4636))
+ (import "env" "_ua" (func $internal4637))
+ (import "env" "$ua" (func $internal4638))
+ (import "env" "ava" (func $internal4639))
+ (import "env" "bva" (func $internal4640))
+ (import "env" "cva" (func $internal4641))
+ (import "env" "dva" (func $internal4642))
+ (import "env" "eva" (func $internal4643))
+ (import "env" "fva" (func $internal4644))
+ (import "env" "gva" (func $internal4645))
+ (import "env" "hva" (func $internal4646))
+ (import "env" "iva" (func $internal4647))
+ (import "env" "jva" (func $internal4648))
+ (import "env" "kva" (func $internal4649))
+ (import "env" "lva" (func $internal4650))
+ (import "env" "mva" (func $internal4651))
+ (import "env" "nva" (func $internal4652))
+ (import "env" "ova" (func $internal4653))
+ (import "env" "pva" (func $internal4654))
+ (import "env" "qva" (func $internal4655))
+ (import "env" "rva" (func $internal4656))
+ (import "env" "sva" (func $internal4657))
+ (import "env" "tva" (func $internal4658))
+ (import "env" "uva" (func $internal4659))
+ (import "env" "vva" (func $internal4660))
+ (import "env" "wva" (func $internal4661))
+ (import "env" "xva" (func $internal4662))
+ (import "env" "yva" (func $internal4663))
+ (import "env" "zva" (func $internal4664))
+ (import "env" "Ava" (func $internal4665))
+ (import "env" "Bva" (func $internal4666))
+ (import "env" "Cva" (func $internal4667))
+ (import "env" "Dva" (func $internal4668))
+ (import "env" "Eva" (func $internal4669))
+ (import "env" "Fva" (func $internal4670))
+ (import "env" "Gva" (func $internal4671))
+ (import "env" "Hva" (func $internal4672))
+ (import "env" "Iva" (func $internal4673))
+ (import "env" "Jva" (func $internal4674))
+ (import "env" "Kva" (func $internal4675))
+ (import "env" "Lva" (func $internal4676))
+ (import "env" "Mva" (func $internal4677))
+ (import "env" "Nva" (func $internal4678))
+ (import "env" "Ova" (func $internal4679))
+ (import "env" "Pva" (func $internal4680))
+ (import "env" "Qva" (func $internal4681))
+ (import "env" "Rva" (func $internal4682))
+ (import "env" "Sva" (func $internal4683))
+ (import "env" "Tva" (func $internal4684))
+ (import "env" "Uva" (func $internal4685))
+ (import "env" "Vva" (func $internal4686))
+ (import "env" "Wva" (func $internal4687))
+ (import "env" "Xva" (func $internal4688))
+ (import "env" "Yva" (func $internal4689))
+ (import "env" "Zva" (func $internal4690))
+ (import "env" "_va" (func $internal4691))
+ (import "env" "$va" (func $internal4692))
+ (import "env" "awa" (func $internal4693))
+ (import "env" "bwa" (func $internal4694))
+ (import "env" "cwa" (func $internal4695))
+ (import "env" "dwa" (func $internal4696))
+ (import "env" "ewa" (func $internal4697))
+ (import "env" "fwa" (func $internal4698))
+ (import "env" "gwa" (func $internal4699))
+ (import "env" "hwa" (func $internal4700))
+ (import "env" "iwa" (func $internal4701))
+ (import "env" "jwa" (func $internal4702))
+ (import "env" "kwa" (func $internal4703))
+ (import "env" "lwa" (func $internal4704))
+ (import "env" "mwa" (func $internal4705))
+ (import "env" "nwa" (func $internal4706))
+ (import "env" "owa" (func $internal4707))
+ (import "env" "pwa" (func $internal4708))
+ (import "env" "qwa" (func $internal4709))
+ (import "env" "rwa" (func $internal4710))
+ (import "env" "swa" (func $internal4711))
+ (import "env" "twa" (func $internal4712))
+ (import "env" "uwa" (func $internal4713))
+ (import "env" "vwa" (func $internal4714))
+ (import "env" "wwa" (func $internal4715))
+ (import "env" "xwa" (func $internal4716))
+ (import "env" "ywa" (func $internal4717))
+ (import "env" "zwa" (func $internal4718))
+ (import "env" "Awa" (func $internal4719))
+ (import "env" "Bwa" (func $internal4720))
+ (import "env" "Cwa" (func $internal4721))
+ (import "env" "Dwa" (func $internal4722))
+ (import "env" "Ewa" (func $internal4723))
+ (import "env" "Fwa" (func $internal4724))
+ (import "env" "Gwa" (func $internal4725))
+ (import "env" "Hwa" (func $internal4726))
+ (import "env" "Iwa" (func $internal4727))
+ (import "env" "Jwa" (func $internal4728))
+ (import "env" "Kwa" (func $internal4729))
+ (import "env" "Lwa" (func $internal4730))
+ (import "env" "Mwa" (func $internal4731))
+ (import "env" "Nwa" (func $internal4732))
+ (import "env" "Owa" (func $internal4733))
+ (import "env" "Pwa" (func $internal4734))
+ (import "env" "Qwa" (func $internal4735))
+ (import "env" "Rwa" (func $internal4736))
+ (import "env" "Swa" (func $internal4737))
+ (import "env" "Twa" (func $internal4738))
+ (import "env" "Uwa" (func $internal4739))
+ (import "env" "Vwa" (func $internal4740))
+ (import "env" "Wwa" (func $internal4741))
+ (import "env" "Xwa" (func $internal4742))
+ (import "env" "Ywa" (func $internal4743))
+ (import "env" "Zwa" (func $internal4744))
+ (import "env" "_wa" (func $internal4745))
+ (import "env" "$wa" (func $internal4746))
+ (import "env" "axa" (func $internal4747))
+ (import "env" "bxa" (func $internal4748))
+ (import "env" "cxa" (func $internal4749))
+ (import "env" "dxa" (func $internal4750))
+ (import "env" "exa" (func $internal4751))
+ (import "env" "fxa" (func $internal4752))
+ (import "env" "gxa" (func $internal4753))
+ (import "env" "hxa" (func $internal4754))
+ (import "env" "ixa" (func $internal4755))
+ (import "env" "jxa" (func $internal4756))
+ (import "env" "kxa" (func $internal4757))
+ (import "env" "lxa" (func $internal4758))
+ (import "env" "mxa" (func $internal4759))
+ (import "env" "nxa" (func $internal4760))
+ (import "env" "oxa" (func $internal4761))
+ (import "env" "pxa" (func $internal4762))
+ (import "env" "qxa" (func $internal4763))
+ (import "env" "rxa" (func $internal4764))
+ (import "env" "sxa" (func $internal4765))
+ (import "env" "txa" (func $internal4766))
+ (import "env" "uxa" (func $internal4767))
+ (import "env" "vxa" (func $internal4768))
+ (import "env" "wxa" (func $internal4769))
+ (import "env" "xxa" (func $internal4770))
+ (import "env" "yxa" (func $internal4771))
+ (import "env" "zxa" (func $internal4772))
+ (import "env" "Axa" (func $internal4773))
+ (import "env" "Bxa" (func $internal4774))
+ (import "env" "Cxa" (func $internal4775))
+ (import "env" "Dxa" (func $internal4776))
+ (import "env" "Exa" (func $internal4777))
+ (import "env" "Fxa" (func $internal4778))
+ (import "env" "Gxa" (func $internal4779))
+ (import "env" "Hxa" (func $internal4780))
+ (import "env" "Ixa" (func $internal4781))
+ (import "env" "Jxa" (func $internal4782))
+ (import "env" "Kxa" (func $internal4783))
+ (import "env" "Lxa" (func $internal4784))
+ (import "env" "Mxa" (func $internal4785))
+ (import "env" "Nxa" (func $internal4786))
+ (import "env" "Oxa" (func $internal4787))
+ (import "env" "Pxa" (func $internal4788))
+ (import "env" "Qxa" (func $internal4789))
+ (import "env" "Rxa" (func $internal4790))
+ (import "env" "Sxa" (func $internal4791))
+ (import "env" "Txa" (func $internal4792))
+ (import "env" "Uxa" (func $internal4793))
+ (import "env" "Vxa" (func $internal4794))
+ (import "env" "Wxa" (func $internal4795))
+ (import "env" "Xxa" (func $internal4796))
+ (import "env" "Yxa" (func $internal4797))
+ (import "env" "Zxa" (func $internal4798))
+ (import "env" "_xa" (func $internal4799))
+ (import "env" "$xa" (func $internal4800))
+ (import "env" "aya" (func $internal4801))
+ (import "env" "bya" (func $internal4802))
+ (import "env" "cya" (func $internal4803))
+ (import "env" "dya" (func $internal4804))
+ (import "env" "eya" (func $internal4805))
+ (import "env" "fya" (func $internal4806))
+ (import "env" "gya" (func $internal4807))
+ (import "env" "hya" (func $internal4808))
+ (import "env" "iya" (func $internal4809))
+ (import "env" "jya" (func $internal4810))
+ (import "env" "kya" (func $internal4811))
+ (import "env" "lya" (func $internal4812))
+ (import "env" "mya" (func $internal4813))
+ (import "env" "nya" (func $internal4814))
+ (import "env" "oya" (func $internal4815))
+ (import "env" "pya" (func $internal4816))
+ (import "env" "qya" (func $internal4817))
+ (import "env" "rya" (func $internal4818))
+ (import "env" "sya" (func $internal4819))
+ (import "env" "tya" (func $internal4820))
+ (import "env" "uya" (func $internal4821))
+ (import "env" "vya" (func $internal4822))
+ (import "env" "wya" (func $internal4823))
+ (import "env" "xya" (func $internal4824))
+ (import "env" "yya" (func $internal4825))
+ (import "env" "zya" (func $internal4826))
+ (import "env" "Aya" (func $internal4827))
+ (import "env" "Bya" (func $internal4828))
+ (import "env" "Cya" (func $internal4829))
+ (import "env" "Dya" (func $internal4830))
+ (import "env" "Eya" (func $internal4831))
+ (import "env" "Fya" (func $internal4832))
+ (import "env" "Gya" (func $internal4833))
+ (import "env" "Hya" (func $internal4834))
+ (import "env" "Iya" (func $internal4835))
+ (import "env" "Jya" (func $internal4836))
+ (import "env" "Kya" (func $internal4837))
+ (import "env" "Lya" (func $internal4838))
+ (import "env" "Mya" (func $internal4839))
+ (import "env" "Nya" (func $internal4840))
+ (import "env" "Oya" (func $internal4841))
+ (import "env" "Pya" (func $internal4842))
+ (import "env" "Qya" (func $internal4843))
+ (import "env" "Rya" (func $internal4844))
+ (import "env" "Sya" (func $internal4845))
+ (import "env" "Tya" (func $internal4846))
+ (import "env" "Uya" (func $internal4847))
+ (import "env" "Vya" (func $internal4848))
+ (import "env" "Wya" (func $internal4849))
+ (import "env" "Xya" (func $internal4850))
+ (import "env" "Yya" (func $internal4851))
+ (import "env" "Zya" (func $internal4852))
+ (import "env" "_ya" (func $internal4853))
+ (import "env" "$ya" (func $internal4854))
+ (import "env" "aza" (func $internal4855))
+ (import "env" "bza" (func $internal4856))
+ (import "env" "cza" (func $internal4857))
+ (import "env" "dza" (func $internal4858))
+ (import "env" "eza" (func $internal4859))
+ (import "env" "fza" (func $internal4860))
+ (import "env" "gza" (func $internal4861))
+ (import "env" "hza" (func $internal4862))
+ (import "env" "iza" (func $internal4863))
+ (import "env" "jza" (func $internal4864))
+ (import "env" "kza" (func $internal4865))
+ (import "env" "lza" (func $internal4866))
+ (import "env" "mza" (func $internal4867))
+ (import "env" "nza" (func $internal4868))
+ (import "env" "oza" (func $internal4869))
+ (import "env" "pza" (func $internal4870))
+ (import "env" "qza" (func $internal4871))
+ (import "env" "rza" (func $internal4872))
+ (import "env" "sza" (func $internal4873))
+ (import "env" "tza" (func $internal4874))
+ (import "env" "uza" (func $internal4875))
+ (import "env" "vza" (func $internal4876))
+ (import "env" "wza" (func $internal4877))
+ (import "env" "xza" (func $internal4878))
+ (import "env" "yza" (func $internal4879))
+ (import "env" "zza" (func $internal4880))
+ (import "env" "Aza" (func $internal4881))
+ (import "env" "Bza" (func $internal4882))
+ (import "env" "Cza" (func $internal4883))
+ (import "env" "Dza" (func $internal4884))
+ (import "env" "Eza" (func $internal4885))
+ (import "env" "Fza" (func $internal4886))
+ (import "env" "Gza" (func $internal4887))
+ (import "env" "Hza" (func $internal4888))
+ (import "env" "Iza" (func $internal4889))
+ (import "env" "Jza" (func $internal4890))
+ (import "env" "Kza" (func $internal4891))
+ (import "env" "Lza" (func $internal4892))
+ (import "env" "Mza" (func $internal4893))
+ (import "env" "Nza" (func $internal4894))
+ (import "env" "Oza" (func $internal4895))
+ (import "env" "Pza" (func $internal4896))
+ (import "env" "Qza" (func $internal4897))
+ (import "env" "Rza" (func $internal4898))
+ (import "env" "Sza" (func $internal4899))
+ (import "env" "Tza" (func $internal4900))
+ (import "env" "Uza" (func $internal4901))
+ (import "env" "Vza" (func $internal4902))
+ (import "env" "Wza" (func $internal4903))
+ (import "env" "Xza" (func $internal4904))
+ (import "env" "Yza" (func $internal4905))
+ (import "env" "Zza" (func $internal4906))
+ (import "env" "_za" (func $internal4907))
+ (import "env" "$za" (func $internal4908))
+ (import "env" "aAa" (func $internal4909))
+ (import "env" "bAa" (func $internal4910))
+ (import "env" "cAa" (func $internal4911))
+ (import "env" "dAa" (func $internal4912))
+ (import "env" "eAa" (func $internal4913))
+ (import "env" "fAa" (func $internal4914))
+ (import "env" "gAa" (func $internal4915))
+ (import "env" "hAa" (func $internal4916))
+ (import "env" "iAa" (func $internal4917))
+ (import "env" "jAa" (func $internal4918))
+ (import "env" "kAa" (func $internal4919))
+ (import "env" "lAa" (func $internal4920))
+ (import "env" "mAa" (func $internal4921))
+ (import "env" "nAa" (func $internal4922))
+ (import "env" "oAa" (func $internal4923))
+ (import "env" "pAa" (func $internal4924))
+ (import "env" "qAa" (func $internal4925))
+ (import "env" "rAa" (func $internal4926))
+ (import "env" "sAa" (func $internal4927))
+ (import "env" "tAa" (func $internal4928))
+ (import "env" "uAa" (func $internal4929))
+ (import "env" "vAa" (func $internal4930))
+ (import "env" "wAa" (func $internal4931))
+ (import "env" "xAa" (func $internal4932))
+ (import "env" "yAa" (func $internal4933))
+ (import "env" "zAa" (func $internal4934))
+ (import "env" "AAa" (func $internal4935))
+ (import "env" "BAa" (func $internal4936))
+ (import "env" "CAa" (func $internal4937))
+ (import "env" "DAa" (func $internal4938))
+ (import "env" "EAa" (func $internal4939))
+ (import "env" "FAa" (func $internal4940))
+ (import "env" "GAa" (func $internal4941))
+ (import "env" "HAa" (func $internal4942))
+ (import "env" "IAa" (func $internal4943))
+ (import "env" "JAa" (func $internal4944))
+ (import "env" "KAa" (func $internal4945))
+ (import "env" "LAa" (func $internal4946))
+ (import "env" "MAa" (func $internal4947))
+ (import "env" "NAa" (func $internal4948))
+ (import "env" "OAa" (func $internal4949))
+ (import "env" "PAa" (func $internal4950))
+ (import "env" "QAa" (func $internal4951))
+ (import "env" "RAa" (func $internal4952))
+ (import "env" "SAa" (func $internal4953))
+ (import "env" "TAa" (func $internal4954))
+ (import "env" "UAa" (func $internal4955))
+ (import "env" "VAa" (func $internal4956))
+ (import "env" "WAa" (func $internal4957))
+ (import "env" "XAa" (func $internal4958))
+ (import "env" "YAa" (func $internal4959))
+ (import "env" "ZAa" (func $internal4960))
+ (import "env" "_Aa" (func $internal4961))
+ (import "env" "$Aa" (func $internal4962))
+ (import "env" "aBa" (func $internal4963))
+ (import "env" "bBa" (func $internal4964))
+ (import "env" "cBa" (func $internal4965))
+ (import "env" "dBa" (func $internal4966))
+ (import "env" "eBa" (func $internal4967))
+ (import "env" "fBa" (func $internal4968))
+ (import "env" "gBa" (func $internal4969))
+ (import "env" "hBa" (func $internal4970))
+ (import "env" "iBa" (func $internal4971))
+ (import "env" "jBa" (func $internal4972))
+ (import "env" "kBa" (func $internal4973))
+ (import "env" "lBa" (func $internal4974))
+ (import "env" "mBa" (func $internal4975))
+ (import "env" "nBa" (func $internal4976))
+ (import "env" "oBa" (func $internal4977))
+ (import "env" "pBa" (func $internal4978))
+ (import "env" "qBa" (func $internal4979))
+ (import "env" "rBa" (func $internal4980))
+ (import "env" "sBa" (func $internal4981))
+ (import "env" "tBa" (func $internal4982))
+ (import "env" "uBa" (func $internal4983))
+ (import "env" "vBa" (func $internal4984))
+ (import "env" "wBa" (func $internal4985))
+ (import "env" "xBa" (func $internal4986))
+ (import "env" "yBa" (func $internal4987))
+ (import "env" "zBa" (func $internal4988))
+ (import "env" "ABa" (func $internal4989))
+ (import "env" "BBa" (func $internal4990))
+ (import "env" "CBa" (func $internal4991))
+ (import "env" "DBa" (func $internal4992))
+ (import "env" "EBa" (func $internal4993))
+ (import "env" "FBa" (func $internal4994))
+ (import "env" "GBa" (func $internal4995))
+ (import "env" "HBa" (func $internal4996))
+ (import "env" "IBa" (func $internal4997))
+ (import "env" "JBa" (func $internal4998))
+ (import "env" "KBa" (func $internal4999))
+ (import "other" "anything" (func $internalInfinity))
+ (import "env" "LBa" (event $eventname1 (attr 0) (param i32)))
+ (event $event1 (attr 0) (param i32 i32))
+ (export "foo1" (func $foo1))
+ (export "foo2" (func $foo2))
+ (export "event1" (event $event1))
+ (func $foo1
+  (nop)
+ )
+ (func $foo2
+  (nop)
+ )
+)
diff --git a/binaryen/test/passes/minify-imports_all-features.wast b/binaryen/test/passes/minify-imports_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/minify-imports_all-features.wast
@@ -0,0 +1,5012 @@
+(module
+  (import "env" "longname1" (func $internal1))
+  (import "env" "longname2" (func $internal2))
+  (import "env" "global" (global i32))
+  (import "env" "longname3" (func $internal3))
+  (import "env" "longname4" (func $internal4))
+  (import "env" "longname5" (func $internal5))
+  (import "env" "longname6" (func $internal6))
+  (import "env" "longname7" (func $internal7))
+  (import "env" "longname8" (func $internal8))
+  (import "env" "longname9" (func $internal9))
+  (import "env" "longname10" (func $internal10))
+  (import "env" "longname11" (func $internal11))
+  (import "env" "longname12" (func $internal12))
+  (import "env" "longname13" (func $internal13))
+  (import "env" "longname14" (func $internal14))
+  (import "env" "longname15" (func $internal15))
+  (import "env" "longname16" (func $internal16))
+  (import "env" "longname17" (func $internal17))
+  (import "env" "longname18" (func $internal18))
+  (import "env" "longname19" (func $internal19))
+  (import "env" "longname20" (func $internal20))
+  (import "env" "longname21" (func $internal21))
+  (import "env" "longname22" (func $internal22))
+  (import "env" "longname23" (func $internal23))
+  (import "env" "longname24" (func $internal24))
+  (import "env" "longname25" (func $internal25))
+  (import "env" "longname26" (func $internal26))
+  (import "env" "longname27" (func $internal27))
+  (import "env" "longname28" (func $internal28))
+  (import "env" "longname29" (func $internal29))
+  (import "env" "longname30" (func $internal30))
+  (import "env" "longname31" (func $internal31))
+  (import "env" "longname32" (func $internal32))
+  (import "env" "longname33" (func $internal33))
+  (import "env" "longname34" (func $internal34))
+  (import "env" "longname35" (func $internal35))
+  (import "env" "longname36" (func $internal36))
+  (import "env" "longname37" (func $internal37))
+  (import "env" "longname38" (func $internal38))
+  (import "env" "longname39" (func $internal39))
+  (import "env" "longname40" (func $internal40))
+  (import "env" "longname41" (func $internal41))
+  (import "env" "longname42" (func $internal42))
+  (import "env" "longname43" (func $internal43))
+  (import "env" "longname44" (func $internal44))
+  (import "env" "longname45" (func $internal45))
+  (import "env" "longname46" (func $internal46))
+  (import "env" "longname47" (func $internal47))
+  (import "env" "longname48" (func $internal48))
+  (import "env" "longname49" (func $internal49))
+  (import "env" "longname50" (func $internal50))
+  (import "env" "longname51" (func $internal51))
+  (import "env" "longname52" (func $internal52))
+  (import "env" "longname53" (func $internal53))
+  (import "env" "longname54" (func $internal54))
+  (import "env" "longname55" (func $internal55))
+  (import "env" "longname56" (func $internal56))
+  (import "env" "longname57" (func $internal57))
+  (import "env" "longname58" (func $internal58))
+  (import "env" "longname59" (func $internal59))
+  (import "env" "longname60" (func $internal60))
+  (import "env" "longname61" (func $internal61))
+  (import "env" "longname62" (func $internal62))
+  (import "env" "longname63" (func $internal63))
+  (import "env" "longname64" (func $internal64))
+  (import "env" "longname65" (func $internal65))
+  (import "env" "longname66" (func $internal66))
+  (import "env" "longname67" (func $internal67))
+  (import "env" "longname68" (func $internal68))
+  (import "env" "longname69" (func $internal69))
+  (import "env" "longname70" (func $internal70))
+  (import "env" "longname71" (func $internal71))
+  (import "env" "longname72" (func $internal72))
+  (import "env" "longname73" (func $internal73))
+  (import "env" "longname74" (func $internal74))
+  (import "env" "longname75" (func $internal75))
+  (import "env" "longname76" (func $internal76))
+  (import "env" "longname77" (func $internal77))
+  (import "env" "longname78" (func $internal78))
+  (import "env" "longname79" (func $internal79))
+  (import "env" "longname80" (func $internal80))
+  (import "env" "longname81" (func $internal81))
+  (import "env" "longname82" (func $internal82))
+  (import "env" "longname83" (func $internal83))
+  (import "env" "longname84" (func $internal84))
+  (import "env" "longname85" (func $internal85))
+  (import "env" "longname86" (func $internal86))
+  (import "env" "longname87" (func $internal87))
+  (import "env" "longname88" (func $internal88))
+  (import "env" "longname89" (func $internal89))
+  (import "env" "longname90" (func $internal90))
+  (import "env" "longname91" (func $internal91))
+  (import "env" "longname92" (func $internal92))
+  (import "env" "longname93" (func $internal93))
+  (import "env" "longname94" (func $internal94))
+  (import "env" "longname95" (func $internal95))
+  (import "env" "longname96" (func $internal96))
+  (import "env" "longname97" (func $internal97))
+  (import "env" "longname98" (func $internal98))
+  (import "env" "longname99" (func $internal99))
+  (import "env" "longname100" (func $internal100))
+  (import "env" "longname101" (func $internal101))
+  (import "env" "longname102" (func $internal102))
+  (import "env" "longname103" (func $internal103))
+  (import "env" "longname104" (func $internal104))
+  (import "env" "longname105" (func $internal105))
+  (import "env" "longname106" (func $internal106))
+  (import "env" "longname107" (func $internal107))
+  (import "env" "longname108" (func $internal108))
+  (import "env" "longname109" (func $internal109))
+  (import "env" "longname110" (func $internal110))
+  (import "env" "longname111" (func $internal111))
+  (import "env" "longname112" (func $internal112))
+  (import "env" "longname113" (func $internal113))
+  (import "env" "longname114" (func $internal114))
+  (import "env" "longname115" (func $internal115))
+  (import "env" "longname116" (func $internal116))
+  (import "env" "longname117" (func $internal117))
+  (import "env" "longname118" (func $internal118))
+  (import "env" "longname119" (func $internal119))
+  (import "env" "longname120" (func $internal120))
+  (import "env" "longname121" (func $internal121))
+  (import "env" "longname122" (func $internal122))
+  (import "env" "longname123" (func $internal123))
+  (import "env" "longname124" (func $internal124))
+  (import "env" "longname125" (func $internal125))
+  (import "env" "longname126" (func $internal126))
+  (import "env" "longname127" (func $internal127))
+  (import "env" "longname128" (func $internal128))
+  (import "env" "longname129" (func $internal129))
+  (import "env" "longname130" (func $internal130))
+  (import "env" "longname131" (func $internal131))
+  (import "env" "longname132" (func $internal132))
+  (import "env" "longname133" (func $internal133))
+  (import "env" "longname134" (func $internal134))
+  (import "env" "longname135" (func $internal135))
+  (import "env" "longname136" (func $internal136))
+  (import "env" "longname137" (func $internal137))
+  (import "env" "longname138" (func $internal138))
+  (import "env" "longname139" (func $internal139))
+  (import "env" "longname140" (func $internal140))
+  (import "env" "longname141" (func $internal141))
+  (import "env" "longname142" (func $internal142))
+  (import "env" "longname143" (func $internal143))
+  (import "env" "longname144" (func $internal144))
+  (import "env" "longname145" (func $internal145))
+  (import "env" "longname146" (func $internal146))
+  (import "env" "longname147" (func $internal147))
+  (import "env" "longname148" (func $internal148))
+  (import "env" "longname149" (func $internal149))
+  (import "env" "longname150" (func $internal150))
+  (import "env" "longname151" (func $internal151))
+  (import "env" "longname152" (func $internal152))
+  (import "env" "longname153" (func $internal153))
+  (import "env" "longname154" (func $internal154))
+  (import "env" "longname155" (func $internal155))
+  (import "env" "longname156" (func $internal156))
+  (import "env" "longname157" (func $internal157))
+  (import "env" "longname158" (func $internal158))
+  (import "env" "longname159" (func $internal159))
+  (import "env" "longname160" (func $internal160))
+  (import "env" "longname161" (func $internal161))
+  (import "env" "longname162" (func $internal162))
+  (import "env" "longname163" (func $internal163))
+  (import "env" "longname164" (func $internal164))
+  (import "env" "longname165" (func $internal165))
+  (import "env" "longname166" (func $internal166))
+  (import "env" "longname167" (func $internal167))
+  (import "env" "longname168" (func $internal168))
+  (import "env" "longname169" (func $internal169))
+  (import "env" "longname170" (func $internal170))
+  (import "env" "longname171" (func $internal171))
+  (import "env" "longname172" (func $internal172))
+  (import "env" "longname173" (func $internal173))
+  (import "env" "longname174" (func $internal174))
+  (import "env" "longname175" (func $internal175))
+  (import "env" "longname176" (func $internal176))
+  (import "env" "longname177" (func $internal177))
+  (import "env" "longname178" (func $internal178))
+  (import "env" "longname179" (func $internal179))
+  (import "env" "longname180" (func $internal180))
+  (import "env" "longname181" (func $internal181))
+  (import "env" "longname182" (func $internal182))
+  (import "env" "longname183" (func $internal183))
+  (import "env" "longname184" (func $internal184))
+  (import "env" "longname185" (func $internal185))
+  (import "env" "longname186" (func $internal186))
+  (import "env" "longname187" (func $internal187))
+  (import "env" "longname188" (func $internal188))
+  (import "env" "longname189" (func $internal189))
+  (import "env" "longname190" (func $internal190))
+  (import "env" "longname191" (func $internal191))
+  (import "env" "longname192" (func $internal192))
+  (import "env" "longname193" (func $internal193))
+  (import "env" "longname194" (func $internal194))
+  (import "env" "longname195" (func $internal195))
+  (import "env" "longname196" (func $internal196))
+  (import "env" "longname197" (func $internal197))
+  (import "env" "longname198" (func $internal198))
+  (import "env" "longname199" (func $internal199))
+  (import "env" "longname200" (func $internal200))
+  (import "env" "longname201" (func $internal201))
+  (import "env" "longname202" (func $internal202))
+  (import "env" "longname203" (func $internal203))
+  (import "env" "longname204" (func $internal204))
+  (import "env" "longname205" (func $internal205))
+  (import "env" "longname206" (func $internal206))
+  (import "env" "longname207" (func $internal207))
+  (import "env" "longname208" (func $internal208))
+  (import "env" "longname209" (func $internal209))
+  (import "env" "longname210" (func $internal210))
+  (import "env" "longname211" (func $internal211))
+  (import "env" "longname212" (func $internal212))
+  (import "env" "longname213" (func $internal213))
+  (import "env" "longname214" (func $internal214))
+  (import "env" "longname215" (func $internal215))
+  (import "env" "longname216" (func $internal216))
+  (import "env" "longname217" (func $internal217))
+  (import "env" "longname218" (func $internal218))
+  (import "env" "longname219" (func $internal219))
+  (import "env" "longname220" (func $internal220))
+  (import "env" "longname221" (func $internal221))
+  (import "env" "longname222" (func $internal222))
+  (import "env" "longname223" (func $internal223))
+  (import "env" "longname224" (func $internal224))
+  (import "env" "longname225" (func $internal225))
+  (import "env" "longname226" (func $internal226))
+  (import "env" "longname227" (func $internal227))
+  (import "env" "longname228" (func $internal228))
+  (import "env" "longname229" (func $internal229))
+  (import "env" "longname230" (func $internal230))
+  (import "env" "longname231" (func $internal231))
+  (import "env" "longname232" (func $internal232))
+  (import "env" "longname233" (func $internal233))
+  (import "env" "longname234" (func $internal234))
+  (import "env" "longname235" (func $internal235))
+  (import "env" "longname236" (func $internal236))
+  (import "env" "longname237" (func $internal237))
+  (import "env" "longname238" (func $internal238))
+  (import "env" "longname239" (func $internal239))
+  (import "env" "longname240" (func $internal240))
+  (import "env" "longname241" (func $internal241))
+  (import "env" "longname242" (func $internal242))
+  (import "env" "longname243" (func $internal243))
+  (import "env" "longname244" (func $internal244))
+  (import "env" "longname245" (func $internal245))
+  (import "env" "longname246" (func $internal246))
+  (import "env" "longname247" (func $internal247))
+  (import "env" "longname248" (func $internal248))
+  (import "env" "longname249" (func $internal249))
+  (import "env" "longname250" (func $internal250))
+  (import "env" "longname251" (func $internal251))
+  (import "env" "longname252" (func $internal252))
+  (import "env" "longname253" (func $internal253))
+  (import "env" "longname254" (func $internal254))
+  (import "env" "longname255" (func $internal255))
+  (import "env" "longname256" (func $internal256))
+  (import "env" "longname257" (func $internal257))
+  (import "env" "longname258" (func $internal258))
+  (import "env" "longname259" (func $internal259))
+  (import "env" "longname260" (func $internal260))
+  (import "env" "longname261" (func $internal261))
+  (import "env" "longname262" (func $internal262))
+  (import "env" "longname263" (func $internal263))
+  (import "env" "longname264" (func $internal264))
+  (import "env" "longname265" (func $internal265))
+  (import "env" "longname266" (func $internal266))
+  (import "env" "longname267" (func $internal267))
+  (import "env" "longname268" (func $internal268))
+  (import "env" "longname269" (func $internal269))
+  (import "env" "longname270" (func $internal270))
+  (import "env" "longname271" (func $internal271))
+  (import "env" "longname272" (func $internal272))
+  (import "env" "longname273" (func $internal273))
+  (import "env" "longname274" (func $internal274))
+  (import "env" "longname275" (func $internal275))
+  (import "env" "longname276" (func $internal276))
+  (import "env" "longname277" (func $internal277))
+  (import "env" "longname278" (func $internal278))
+  (import "env" "longname279" (func $internal279))
+  (import "env" "longname280" (func $internal280))
+  (import "env" "longname281" (func $internal281))
+  (import "env" "longname282" (func $internal282))
+  (import "env" "longname283" (func $internal283))
+  (import "env" "longname284" (func $internal284))
+  (import "env" "longname285" (func $internal285))
+  (import "env" "longname286" (func $internal286))
+  (import "env" "longname287" (func $internal287))
+  (import "env" "longname288" (func $internal288))
+  (import "env" "longname289" (func $internal289))
+  (import "env" "longname290" (func $internal290))
+  (import "env" "longname291" (func $internal291))
+  (import "env" "longname292" (func $internal292))
+  (import "env" "longname293" (func $internal293))
+  (import "env" "longname294" (func $internal294))
+  (import "env" "longname295" (func $internal295))
+  (import "env" "longname296" (func $internal296))
+  (import "env" "longname297" (func $internal297))
+  (import "env" "longname298" (func $internal298))
+  (import "env" "longname299" (func $internal299))
+  (import "env" "longname300" (func $internal300))
+  (import "env" "longname301" (func $internal301))
+  (import "env" "longname302" (func $internal302))
+  (import "env" "longname303" (func $internal303))
+  (import "env" "longname304" (func $internal304))
+  (import "env" "longname305" (func $internal305))
+  (import "env" "longname306" (func $internal306))
+  (import "env" "longname307" (func $internal307))
+  (import "env" "longname308" (func $internal308))
+  (import "env" "longname309" (func $internal309))
+  (import "env" "longname310" (func $internal310))
+  (import "env" "longname311" (func $internal311))
+  (import "env" "longname312" (func $internal312))
+  (import "env" "longname313" (func $internal313))
+  (import "env" "longname314" (func $internal314))
+  (import "env" "longname315" (func $internal315))
+  (import "env" "longname316" (func $internal316))
+  (import "env" "longname317" (func $internal317))
+  (import "env" "longname318" (func $internal318))
+  (import "env" "longname319" (func $internal319))
+  (import "env" "longname320" (func $internal320))
+  (import "env" "longname321" (func $internal321))
+  (import "env" "longname322" (func $internal322))
+  (import "env" "longname323" (func $internal323))
+  (import "env" "longname324" (func $internal324))
+  (import "env" "longname325" (func $internal325))
+  (import "env" "longname326" (func $internal326))
+  (import "env" "longname327" (func $internal327))
+  (import "env" "longname328" (func $internal328))
+  (import "env" "longname329" (func $internal329))
+  (import "env" "longname330" (func $internal330))
+  (import "env" "longname331" (func $internal331))
+  (import "env" "longname332" (func $internal332))
+  (import "env" "longname333" (func $internal333))
+  (import "env" "longname334" (func $internal334))
+  (import "env" "longname335" (func $internal335))
+  (import "env" "longname336" (func $internal336))
+  (import "env" "longname337" (func $internal337))
+  (import "env" "longname338" (func $internal338))
+  (import "env" "longname339" (func $internal339))
+  (import "env" "longname340" (func $internal340))
+  (import "env" "longname341" (func $internal341))
+  (import "env" "longname342" (func $internal342))
+  (import "env" "longname343" (func $internal343))
+  (import "env" "longname344" (func $internal344))
+  (import "env" "longname345" (func $internal345))
+  (import "env" "longname346" (func $internal346))
+  (import "env" "longname347" (func $internal347))
+  (import "env" "longname348" (func $internal348))
+  (import "env" "longname349" (func $internal349))
+  (import "env" "longname350" (func $internal350))
+  (import "env" "longname351" (func $internal351))
+  (import "env" "longname352" (func $internal352))
+  (import "env" "longname353" (func $internal353))
+  (import "env" "longname354" (func $internal354))
+  (import "env" "longname355" (func $internal355))
+  (import "env" "longname356" (func $internal356))
+  (import "env" "longname357" (func $internal357))
+  (import "env" "longname358" (func $internal358))
+  (import "env" "longname359" (func $internal359))
+  (import "env" "longname360" (func $internal360))
+  (import "env" "longname361" (func $internal361))
+  (import "env" "longname362" (func $internal362))
+  (import "env" "longname363" (func $internal363))
+  (import "env" "longname364" (func $internal364))
+  (import "env" "longname365" (func $internal365))
+  (import "env" "longname366" (func $internal366))
+  (import "env" "longname367" (func $internal367))
+  (import "env" "longname368" (func $internal368))
+  (import "env" "longname369" (func $internal369))
+  (import "env" "longname370" (func $internal370))
+  (import "env" "longname371" (func $internal371))
+  (import "env" "longname372" (func $internal372))
+  (import "env" "longname373" (func $internal373))
+  (import "env" "longname374" (func $internal374))
+  (import "env" "longname375" (func $internal375))
+  (import "env" "longname376" (func $internal376))
+  (import "env" "longname377" (func $internal377))
+  (import "env" "longname378" (func $internal378))
+  (import "env" "longname379" (func $internal379))
+  (import "env" "longname380" (func $internal380))
+  (import "env" "longname381" (func $internal381))
+  (import "env" "longname382" (func $internal382))
+  (import "env" "longname383" (func $internal383))
+  (import "env" "longname384" (func $internal384))
+  (import "env" "longname385" (func $internal385))
+  (import "env" "longname386" (func $internal386))
+  (import "env" "longname387" (func $internal387))
+  (import "env" "longname388" (func $internal388))
+  (import "env" "longname389" (func $internal389))
+  (import "env" "longname390" (func $internal390))
+  (import "env" "longname391" (func $internal391))
+  (import "env" "longname392" (func $internal392))
+  (import "env" "longname393" (func $internal393))
+  (import "env" "longname394" (func $internal394))
+  (import "env" "longname395" (func $internal395))
+  (import "env" "longname396" (func $internal396))
+  (import "env" "longname397" (func $internal397))
+  (import "env" "longname398" (func $internal398))
+  (import "env" "longname399" (func $internal399))
+  (import "env" "longname400" (func $internal400))
+  (import "env" "longname401" (func $internal401))
+  (import "env" "longname402" (func $internal402))
+  (import "env" "longname403" (func $internal403))
+  (import "env" "longname404" (func $internal404))
+  (import "env" "longname405" (func $internal405))
+  (import "env" "longname406" (func $internal406))
+  (import "env" "longname407" (func $internal407))
+  (import "env" "longname408" (func $internal408))
+  (import "env" "longname409" (func $internal409))
+  (import "env" "longname410" (func $internal410))
+  (import "env" "longname411" (func $internal411))
+  (import "env" "longname412" (func $internal412))
+  (import "env" "longname413" (func $internal413))
+  (import "env" "longname414" (func $internal414))
+  (import "env" "longname415" (func $internal415))
+  (import "env" "longname416" (func $internal416))
+  (import "env" "longname417" (func $internal417))
+  (import "env" "longname418" (func $internal418))
+  (import "env" "longname419" (func $internal419))
+  (import "env" "longname420" (func $internal420))
+  (import "env" "longname421" (func $internal421))
+  (import "env" "longname422" (func $internal422))
+  (import "env" "longname423" (func $internal423))
+  (import "env" "longname424" (func $internal424))
+  (import "env" "longname425" (func $internal425))
+  (import "env" "longname426" (func $internal426))
+  (import "env" "longname427" (func $internal427))
+  (import "env" "longname428" (func $internal428))
+  (import "env" "longname429" (func $internal429))
+  (import "env" "longname430" (func $internal430))
+  (import "env" "longname431" (func $internal431))
+  (import "env" "longname432" (func $internal432))
+  (import "env" "longname433" (func $internal433))
+  (import "env" "longname434" (func $internal434))
+  (import "env" "longname435" (func $internal435))
+  (import "env" "longname436" (func $internal436))
+  (import "env" "longname437" (func $internal437))
+  (import "env" "longname438" (func $internal438))
+  (import "env" "longname439" (func $internal439))
+  (import "env" "longname440" (func $internal440))
+  (import "env" "longname441" (func $internal441))
+  (import "env" "longname442" (func $internal442))
+  (import "env" "longname443" (func $internal443))
+  (import "env" "longname444" (func $internal444))
+  (import "env" "longname445" (func $internal445))
+  (import "env" "longname446" (func $internal446))
+  (import "env" "longname447" (func $internal447))
+  (import "env" "longname448" (func $internal448))
+  (import "env" "longname449" (func $internal449))
+  (import "env" "longname450" (func $internal450))
+  (import "env" "longname451" (func $internal451))
+  (import "env" "longname452" (func $internal452))
+  (import "env" "longname453" (func $internal453))
+  (import "env" "longname454" (func $internal454))
+  (import "env" "longname455" (func $internal455))
+  (import "env" "longname456" (func $internal456))
+  (import "env" "longname457" (func $internal457))
+  (import "env" "longname458" (func $internal458))
+  (import "env" "longname459" (func $internal459))
+  (import "env" "longname460" (func $internal460))
+  (import "env" "longname461" (func $internal461))
+  (import "env" "longname462" (func $internal462))
+  (import "env" "longname463" (func $internal463))
+  (import "env" "longname464" (func $internal464))
+  (import "env" "longname465" (func $internal465))
+  (import "env" "longname466" (func $internal466))
+  (import "env" "longname467" (func $internal467))
+  (import "env" "longname468" (func $internal468))
+  (import "env" "longname469" (func $internal469))
+  (import "env" "longname470" (func $internal470))
+  (import "env" "longname471" (func $internal471))
+  (import "env" "longname472" (func $internal472))
+  (import "env" "longname473" (func $internal473))
+  (import "env" "longname474" (func $internal474))
+  (import "env" "longname475" (func $internal475))
+  (import "env" "longname476" (func $internal476))
+  (import "env" "longname477" (func $internal477))
+  (import "env" "longname478" (func $internal478))
+  (import "env" "longname479" (func $internal479))
+  (import "env" "longname480" (func $internal480))
+  (import "env" "longname481" (func $internal481))
+  (import "env" "longname482" (func $internal482))
+  (import "env" "longname483" (func $internal483))
+  (import "env" "longname484" (func $internal484))
+  (import "env" "longname485" (func $internal485))
+  (import "env" "longname486" (func $internal486))
+  (import "env" "longname487" (func $internal487))
+  (import "env" "longname488" (func $internal488))
+  (import "env" "longname489" (func $internal489))
+  (import "env" "longname490" (func $internal490))
+  (import "env" "longname491" (func $internal491))
+  (import "env" "longname492" (func $internal492))
+  (import "env" "longname493" (func $internal493))
+  (import "env" "longname494" (func $internal494))
+  (import "env" "longname495" (func $internal495))
+  (import "env" "longname496" (func $internal496))
+  (import "env" "longname497" (func $internal497))
+  (import "env" "longname498" (func $internal498))
+  (import "env" "longname499" (func $internal499))
+  (import "env" "longname500" (func $internal500))
+  (import "env" "longname501" (func $internal501))
+  (import "env" "longname502" (func $internal502))
+  (import "env" "longname503" (func $internal503))
+  (import "env" "longname504" (func $internal504))
+  (import "env" "longname505" (func $internal505))
+  (import "env" "longname506" (func $internal506))
+  (import "env" "longname507" (func $internal507))
+  (import "env" "longname508" (func $internal508))
+  (import "env" "longname509" (func $internal509))
+  (import "env" "longname510" (func $internal510))
+  (import "env" "longname511" (func $internal511))
+  (import "env" "longname512" (func $internal512))
+  (import "env" "longname513" (func $internal513))
+  (import "env" "longname514" (func $internal514))
+  (import "env" "longname515" (func $internal515))
+  (import "env" "longname516" (func $internal516))
+  (import "env" "longname517" (func $internal517))
+  (import "env" "longname518" (func $internal518))
+  (import "env" "longname519" (func $internal519))
+  (import "env" "longname520" (func $internal520))
+  (import "env" "longname521" (func $internal521))
+  (import "env" "longname522" (func $internal522))
+  (import "env" "longname523" (func $internal523))
+  (import "env" "longname524" (func $internal524))
+  (import "env" "longname525" (func $internal525))
+  (import "env" "longname526" (func $internal526))
+  (import "env" "longname527" (func $internal527))
+  (import "env" "longname528" (func $internal528))
+  (import "env" "longname529" (func $internal529))
+  (import "env" "longname530" (func $internal530))
+  (import "env" "longname531" (func $internal531))
+  (import "env" "longname532" (func $internal532))
+  (import "env" "longname533" (func $internal533))
+  (import "env" "longname534" (func $internal534))
+  (import "env" "longname535" (func $internal535))
+  (import "env" "longname536" (func $internal536))
+  (import "env" "longname537" (func $internal537))
+  (import "env" "longname538" (func $internal538))
+  (import "env" "longname539" (func $internal539))
+  (import "env" "longname540" (func $internal540))
+  (import "env" "longname541" (func $internal541))
+  (import "env" "longname542" (func $internal542))
+  (import "env" "longname543" (func $internal543))
+  (import "env" "longname544" (func $internal544))
+  (import "env" "longname545" (func $internal545))
+  (import "env" "longname546" (func $internal546))
+  (import "env" "longname547" (func $internal547))
+  (import "env" "longname548" (func $internal548))
+  (import "env" "longname549" (func $internal549))
+  (import "env" "longname550" (func $internal550))
+  (import "env" "longname551" (func $internal551))
+  (import "env" "longname552" (func $internal552))
+  (import "env" "longname553" (func $internal553))
+  (import "env" "longname554" (func $internal554))
+  (import "env" "longname555" (func $internal555))
+  (import "env" "longname556" (func $internal556))
+  (import "env" "longname557" (func $internal557))
+  (import "env" "longname558" (func $internal558))
+  (import "env" "longname559" (func $internal559))
+  (import "env" "longname560" (func $internal560))
+  (import "env" "longname561" (func $internal561))
+  (import "env" "longname562" (func $internal562))
+  (import "env" "longname563" (func $internal563))
+  (import "env" "longname564" (func $internal564))
+  (import "env" "longname565" (func $internal565))
+  (import "env" "longname566" (func $internal566))
+  (import "env" "longname567" (func $internal567))
+  (import "env" "longname568" (func $internal568))
+  (import "env" "longname569" (func $internal569))
+  (import "env" "longname570" (func $internal570))
+  (import "env" "longname571" (func $internal571))
+  (import "env" "longname572" (func $internal572))
+  (import "env" "longname573" (func $internal573))
+  (import "env" "longname574" (func $internal574))
+  (import "env" "longname575" (func $internal575))
+  (import "env" "longname576" (func $internal576))
+  (import "env" "longname577" (func $internal577))
+  (import "env" "longname578" (func $internal578))
+  (import "env" "longname579" (func $internal579))
+  (import "env" "longname580" (func $internal580))
+  (import "env" "longname581" (func $internal581))
+  (import "env" "longname582" (func $internal582))
+  (import "env" "longname583" (func $internal583))
+  (import "env" "longname584" (func $internal584))
+  (import "env" "longname585" (func $internal585))
+  (import "env" "longname586" (func $internal586))
+  (import "env" "longname587" (func $internal587))
+  (import "env" "longname588" (func $internal588))
+  (import "env" "longname589" (func $internal589))
+  (import "env" "longname590" (func $internal590))
+  (import "env" "longname591" (func $internal591))
+  (import "env" "longname592" (func $internal592))
+  (import "env" "longname593" (func $internal593))
+  (import "env" "longname594" (func $internal594))
+  (import "env" "longname595" (func $internal595))
+  (import "env" "longname596" (func $internal596))
+  (import "env" "longname597" (func $internal597))
+  (import "env" "longname598" (func $internal598))
+  (import "env" "longname599" (func $internal599))
+  (import "env" "longname600" (func $internal600))
+  (import "env" "longname601" (func $internal601))
+  (import "env" "longname602" (func $internal602))
+  (import "env" "longname603" (func $internal603))
+  (import "env" "longname604" (func $internal604))
+  (import "env" "longname605" (func $internal605))
+  (import "env" "longname606" (func $internal606))
+  (import "env" "longname607" (func $internal607))
+  (import "env" "longname608" (func $internal608))
+  (import "env" "longname609" (func $internal609))
+  (import "env" "longname610" (func $internal610))
+  (import "env" "longname611" (func $internal611))
+  (import "env" "longname612" (func $internal612))
+  (import "env" "longname613" (func $internal613))
+  (import "env" "longname614" (func $internal614))
+  (import "env" "longname615" (func $internal615))
+  (import "env" "longname616" (func $internal616))
+  (import "env" "longname617" (func $internal617))
+  (import "env" "longname618" (func $internal618))
+  (import "env" "longname619" (func $internal619))
+  (import "env" "longname620" (func $internal620))
+  (import "env" "longname621" (func $internal621))
+  (import "env" "longname622" (func $internal622))
+  (import "env" "longname623" (func $internal623))
+  (import "env" "longname624" (func $internal624))
+  (import "env" "longname625" (func $internal625))
+  (import "env" "longname626" (func $internal626))
+  (import "env" "longname627" (func $internal627))
+  (import "env" "longname628" (func $internal628))
+  (import "env" "longname629" (func $internal629))
+  (import "env" "longname630" (func $internal630))
+  (import "env" "longname631" (func $internal631))
+  (import "env" "longname632" (func $internal632))
+  (import "env" "longname633" (func $internal633))
+  (import "env" "longname634" (func $internal634))
+  (import "env" "longname635" (func $internal635))
+  (import "env" "longname636" (func $internal636))
+  (import "env" "longname637" (func $internal637))
+  (import "env" "longname638" (func $internal638))
+  (import "env" "longname639" (func $internal639))
+  (import "env" "longname640" (func $internal640))
+  (import "env" "longname641" (func $internal641))
+  (import "env" "longname642" (func $internal642))
+  (import "env" "longname643" (func $internal643))
+  (import "env" "longname644" (func $internal644))
+  (import "env" "longname645" (func $internal645))
+  (import "env" "longname646" (func $internal646))
+  (import "env" "longname647" (func $internal647))
+  (import "env" "longname648" (func $internal648))
+  (import "env" "longname649" (func $internal649))
+  (import "env" "longname650" (func $internal650))
+  (import "env" "longname651" (func $internal651))
+  (import "env" "longname652" (func $internal652))
+  (import "env" "longname653" (func $internal653))
+  (import "env" "longname654" (func $internal654))
+  (import "env" "longname655" (func $internal655))
+  (import "env" "longname656" (func $internal656))
+  (import "env" "longname657" (func $internal657))
+  (import "env" "longname658" (func $internal658))
+  (import "env" "longname659" (func $internal659))
+  (import "env" "longname660" (func $internal660))
+  (import "env" "longname661" (func $internal661))
+  (import "env" "longname662" (func $internal662))
+  (import "env" "longname663" (func $internal663))
+  (import "env" "longname664" (func $internal664))
+  (import "env" "longname665" (func $internal665))
+  (import "env" "longname666" (func $internal666))
+  (import "env" "longname667" (func $internal667))
+  (import "env" "longname668" (func $internal668))
+  (import "env" "longname669" (func $internal669))
+  (import "env" "longname670" (func $internal670))
+  (import "env" "longname671" (func $internal671))
+  (import "env" "longname672" (func $internal672))
+  (import "env" "longname673" (func $internal673))
+  (import "env" "longname674" (func $internal674))
+  (import "env" "longname675" (func $internal675))
+  (import "env" "longname676" (func $internal676))
+  (import "env" "longname677" (func $internal677))
+  (import "env" "longname678" (func $internal678))
+  (import "env" "longname679" (func $internal679))
+  (import "env" "longname680" (func $internal680))
+  (import "env" "longname681" (func $internal681))
+  (import "env" "longname682" (func $internal682))
+  (import "env" "longname683" (func $internal683))
+  (import "env" "longname684" (func $internal684))
+  (import "env" "longname685" (func $internal685))
+  (import "env" "longname686" (func $internal686))
+  (import "env" "longname687" (func $internal687))
+  (import "env" "longname688" (func $internal688))
+  (import "env" "longname689" (func $internal689))
+  (import "env" "longname690" (func $internal690))
+  (import "env" "longname691" (func $internal691))
+  (import "env" "longname692" (func $internal692))
+  (import "env" "longname693" (func $internal693))
+  (import "env" "longname694" (func $internal694))
+  (import "env" "longname695" (func $internal695))
+  (import "env" "longname696" (func $internal696))
+  (import "env" "longname697" (func $internal697))
+  (import "env" "longname698" (func $internal698))
+  (import "env" "longname699" (func $internal699))
+  (import "env" "longname700" (func $internal700))
+  (import "env" "longname701" (func $internal701))
+  (import "env" "longname702" (func $internal702))
+  (import "env" "longname703" (func $internal703))
+  (import "env" "longname704" (func $internal704))
+  (import "env" "longname705" (func $internal705))
+  (import "env" "longname706" (func $internal706))
+  (import "env" "longname707" (func $internal707))
+  (import "env" "longname708" (func $internal708))
+  (import "env" "longname709" (func $internal709))
+  (import "env" "longname710" (func $internal710))
+  (import "env" "longname711" (func $internal711))
+  (import "env" "longname712" (func $internal712))
+  (import "env" "longname713" (func $internal713))
+  (import "env" "longname714" (func $internal714))
+  (import "env" "longname715" (func $internal715))
+  (import "env" "longname716" (func $internal716))
+  (import "env" "longname717" (func $internal717))
+  (import "env" "longname718" (func $internal718))
+  (import "env" "longname719" (func $internal719))
+  (import "env" "longname720" (func $internal720))
+  (import "env" "longname721" (func $internal721))
+  (import "env" "longname722" (func $internal722))
+  (import "env" "longname723" (func $internal723))
+  (import "env" "longname724" (func $internal724))
+  (import "env" "longname725" (func $internal725))
+  (import "env" "longname726" (func $internal726))
+  (import "env" "longname727" (func $internal727))
+  (import "env" "longname728" (func $internal728))
+  (import "env" "longname729" (func $internal729))
+  (import "env" "longname730" (func $internal730))
+  (import "env" "longname731" (func $internal731))
+  (import "env" "longname732" (func $internal732))
+  (import "env" "longname733" (func $internal733))
+  (import "env" "longname734" (func $internal734))
+  (import "env" "longname735" (func $internal735))
+  (import "env" "longname736" (func $internal736))
+  (import "env" "longname737" (func $internal737))
+  (import "env" "longname738" (func $internal738))
+  (import "env" "longname739" (func $internal739))
+  (import "env" "longname740" (func $internal740))
+  (import "env" "longname741" (func $internal741))
+  (import "env" "longname742" (func $internal742))
+  (import "env" "longname743" (func $internal743))
+  (import "env" "longname744" (func $internal744))
+  (import "env" "longname745" (func $internal745))
+  (import "env" "longname746" (func $internal746))
+  (import "env" "longname747" (func $internal747))
+  (import "env" "longname748" (func $internal748))
+  (import "env" "longname749" (func $internal749))
+  (import "env" "longname750" (func $internal750))
+  (import "env" "longname751" (func $internal751))
+  (import "env" "longname752" (func $internal752))
+  (import "env" "longname753" (func $internal753))
+  (import "env" "longname754" (func $internal754))
+  (import "env" "longname755" (func $internal755))
+  (import "env" "longname756" (func $internal756))
+  (import "env" "longname757" (func $internal757))
+  (import "env" "longname758" (func $internal758))
+  (import "env" "longname759" (func $internal759))
+  (import "env" "longname760" (func $internal760))
+  (import "env" "longname761" (func $internal761))
+  (import "env" "longname762" (func $internal762))
+  (import "env" "longname763" (func $internal763))
+  (import "env" "longname764" (func $internal764))
+  (import "env" "longname765" (func $internal765))
+  (import "env" "longname766" (func $internal766))
+  (import "env" "longname767" (func $internal767))
+  (import "env" "longname768" (func $internal768))
+  (import "env" "longname769" (func $internal769))
+  (import "env" "longname770" (func $internal770))
+  (import "env" "longname771" (func $internal771))
+  (import "env" "longname772" (func $internal772))
+  (import "env" "longname773" (func $internal773))
+  (import "env" "longname774" (func $internal774))
+  (import "env" "longname775" (func $internal775))
+  (import "env" "longname776" (func $internal776))
+  (import "env" "longname777" (func $internal777))
+  (import "env" "longname778" (func $internal778))
+  (import "env" "longname779" (func $internal779))
+  (import "env" "longname780" (func $internal780))
+  (import "env" "longname781" (func $internal781))
+  (import "env" "longname782" (func $internal782))
+  (import "env" "longname783" (func $internal783))
+  (import "env" "longname784" (func $internal784))
+  (import "env" "longname785" (func $internal785))
+  (import "env" "longname786" (func $internal786))
+  (import "env" "longname787" (func $internal787))
+  (import "env" "longname788" (func $internal788))
+  (import "env" "longname789" (func $internal789))
+  (import "env" "longname790" (func $internal790))
+  (import "env" "longname791" (func $internal791))
+  (import "env" "longname792" (func $internal792))
+  (import "env" "longname793" (func $internal793))
+  (import "env" "longname794" (func $internal794))
+  (import "env" "longname795" (func $internal795))
+  (import "env" "longname796" (func $internal796))
+  (import "env" "longname797" (func $internal797))
+  (import "env" "longname798" (func $internal798))
+  (import "env" "longname799" (func $internal799))
+  (import "env" "longname800" (func $internal800))
+  (import "env" "longname801" (func $internal801))
+  (import "env" "longname802" (func $internal802))
+  (import "env" "longname803" (func $internal803))
+  (import "env" "longname804" (func $internal804))
+  (import "env" "longname805" (func $internal805))
+  (import "env" "longname806" (func $internal806))
+  (import "env" "longname807" (func $internal807))
+  (import "env" "longname808" (func $internal808))
+  (import "env" "longname809" (func $internal809))
+  (import "env" "longname810" (func $internal810))
+  (import "env" "longname811" (func $internal811))
+  (import "env" "longname812" (func $internal812))
+  (import "env" "longname813" (func $internal813))
+  (import "env" "longname814" (func $internal814))
+  (import "env" "longname815" (func $internal815))
+  (import "env" "longname816" (func $internal816))
+  (import "env" "longname817" (func $internal817))
+  (import "env" "longname818" (func $internal818))
+  (import "env" "longname819" (func $internal819))
+  (import "env" "longname820" (func $internal820))
+  (import "env" "longname821" (func $internal821))
+  (import "env" "longname822" (func $internal822))
+  (import "env" "longname823" (func $internal823))
+  (import "env" "longname824" (func $internal824))
+  (import "env" "longname825" (func $internal825))
+  (import "env" "longname826" (func $internal826))
+  (import "env" "longname827" (func $internal827))
+  (import "env" "longname828" (func $internal828))
+  (import "env" "longname829" (func $internal829))
+  (import "env" "longname830" (func $internal830))
+  (import "env" "longname831" (func $internal831))
+  (import "env" "longname832" (func $internal832))
+  (import "env" "longname833" (func $internal833))
+  (import "env" "longname834" (func $internal834))
+  (import "env" "longname835" (func $internal835))
+  (import "env" "longname836" (func $internal836))
+  (import "env" "longname837" (func $internal837))
+  (import "env" "longname838" (func $internal838))
+  (import "env" "longname839" (func $internal839))
+  (import "env" "longname840" (func $internal840))
+  (import "env" "longname841" (func $internal841))
+  (import "env" "longname842" (func $internal842))
+  (import "env" "longname843" (func $internal843))
+  (import "env" "longname844" (func $internal844))
+  (import "env" "longname845" (func $internal845))
+  (import "env" "longname846" (func $internal846))
+  (import "env" "longname847" (func $internal847))
+  (import "env" "longname848" (func $internal848))
+  (import "env" "longname849" (func $internal849))
+  (import "env" "longname850" (func $internal850))
+  (import "env" "longname851" (func $internal851))
+  (import "env" "longname852" (func $internal852))
+  (import "env" "longname853" (func $internal853))
+  (import "env" "longname854" (func $internal854))
+  (import "env" "longname855" (func $internal855))
+  (import "env" "longname856" (func $internal856))
+  (import "env" "longname857" (func $internal857))
+  (import "env" "longname858" (func $internal858))
+  (import "env" "longname859" (func $internal859))
+  (import "env" "longname860" (func $internal860))
+  (import "env" "longname861" (func $internal861))
+  (import "env" "longname862" (func $internal862))
+  (import "env" "longname863" (func $internal863))
+  (import "env" "longname864" (func $internal864))
+  (import "env" "longname865" (func $internal865))
+  (import "env" "longname866" (func $internal866))
+  (import "env" "longname867" (func $internal867))
+  (import "env" "longname868" (func $internal868))
+  (import "env" "longname869" (func $internal869))
+  (import "env" "longname870" (func $internal870))
+  (import "env" "longname871" (func $internal871))
+  (import "env" "longname872" (func $internal872))
+  (import "env" "longname873" (func $internal873))
+  (import "env" "longname874" (func $internal874))
+  (import "env" "longname875" (func $internal875))
+  (import "env" "longname876" (func $internal876))
+  (import "env" "longname877" (func $internal877))
+  (import "env" "longname878" (func $internal878))
+  (import "env" "longname879" (func $internal879))
+  (import "env" "longname880" (func $internal880))
+  (import "env" "longname881" (func $internal881))
+  (import "env" "longname882" (func $internal882))
+  (import "env" "longname883" (func $internal883))
+  (import "env" "longname884" (func $internal884))
+  (import "env" "longname885" (func $internal885))
+  (import "env" "longname886" (func $internal886))
+  (import "env" "longname887" (func $internal887))
+  (import "env" "longname888" (func $internal888))
+  (import "env" "longname889" (func $internal889))
+  (import "env" "longname890" (func $internal890))
+  (import "env" "longname891" (func $internal891))
+  (import "env" "longname892" (func $internal892))
+  (import "env" "longname893" (func $internal893))
+  (import "env" "longname894" (func $internal894))
+  (import "env" "longname895" (func $internal895))
+  (import "env" "longname896" (func $internal896))
+  (import "env" "longname897" (func $internal897))
+  (import "env" "longname898" (func $internal898))
+  (import "env" "longname899" (func $internal899))
+  (import "env" "longname900" (func $internal900))
+  (import "env" "longname901" (func $internal901))
+  (import "env" "longname902" (func $internal902))
+  (import "env" "longname903" (func $internal903))
+  (import "env" "longname904" (func $internal904))
+  (import "env" "longname905" (func $internal905))
+  (import "env" "longname906" (func $internal906))
+  (import "env" "longname907" (func $internal907))
+  (import "env" "longname908" (func $internal908))
+  (import "env" "longname909" (func $internal909))
+  (import "env" "longname910" (func $internal910))
+  (import "env" "longname911" (func $internal911))
+  (import "env" "longname912" (func $internal912))
+  (import "env" "longname913" (func $internal913))
+  (import "env" "longname914" (func $internal914))
+  (import "env" "longname915" (func $internal915))
+  (import "env" "longname916" (func $internal916))
+  (import "env" "longname917" (func $internal917))
+  (import "env" "longname918" (func $internal918))
+  (import "env" "longname919" (func $internal919))
+  (import "env" "longname920" (func $internal920))
+  (import "env" "longname921" (func $internal921))
+  (import "env" "longname922" (func $internal922))
+  (import "env" "longname923" (func $internal923))
+  (import "env" "longname924" (func $internal924))
+  (import "env" "longname925" (func $internal925))
+  (import "env" "longname926" (func $internal926))
+  (import "env" "longname927" (func $internal927))
+  (import "env" "longname928" (func $internal928))
+  (import "env" "longname929" (func $internal929))
+  (import "env" "longname930" (func $internal930))
+  (import "env" "longname931" (func $internal931))
+  (import "env" "longname932" (func $internal932))
+  (import "env" "longname933" (func $internal933))
+  (import "env" "longname934" (func $internal934))
+  (import "env" "longname935" (func $internal935))
+  (import "env" "longname936" (func $internal936))
+  (import "env" "longname937" (func $internal937))
+  (import "env" "longname938" (func $internal938))
+  (import "env" "longname939" (func $internal939))
+  (import "env" "longname940" (func $internal940))
+  (import "env" "longname941" (func $internal941))
+  (import "env" "longname942" (func $internal942))
+  (import "env" "longname943" (func $internal943))
+  (import "env" "longname944" (func $internal944))
+  (import "env" "longname945" (func $internal945))
+  (import "env" "longname946" (func $internal946))
+  (import "env" "longname947" (func $internal947))
+  (import "env" "longname948" (func $internal948))
+  (import "env" "longname949" (func $internal949))
+  (import "env" "longname950" (func $internal950))
+  (import "env" "longname951" (func $internal951))
+  (import "env" "longname952" (func $internal952))
+  (import "env" "longname953" (func $internal953))
+  (import "env" "longname954" (func $internal954))
+  (import "env" "longname955" (func $internal955))
+  (import "env" "longname956" (func $internal956))
+  (import "env" "longname957" (func $internal957))
+  (import "env" "longname958" (func $internal958))
+  (import "env" "longname959" (func $internal959))
+  (import "env" "longname960" (func $internal960))
+  (import "env" "longname961" (func $internal961))
+  (import "env" "longname962" (func $internal962))
+  (import "env" "longname963" (func $internal963))
+  (import "env" "longname964" (func $internal964))
+  (import "env" "longname965" (func $internal965))
+  (import "env" "longname966" (func $internal966))
+  (import "env" "longname967" (func $internal967))
+  (import "env" "longname968" (func $internal968))
+  (import "env" "longname969" (func $internal969))
+  (import "env" "longname970" (func $internal970))
+  (import "env" "longname971" (func $internal971))
+  (import "env" "longname972" (func $internal972))
+  (import "env" "longname973" (func $internal973))
+  (import "env" "longname974" (func $internal974))
+  (import "env" "longname975" (func $internal975))
+  (import "env" "longname976" (func $internal976))
+  (import "env" "longname977" (func $internal977))
+  (import "env" "longname978" (func $internal978))
+  (import "env" "longname979" (func $internal979))
+  (import "env" "longname980" (func $internal980))
+  (import "env" "longname981" (func $internal981))
+  (import "env" "longname982" (func $internal982))
+  (import "env" "longname983" (func $internal983))
+  (import "env" "longname984" (func $internal984))
+  (import "env" "longname985" (func $internal985))
+  (import "env" "longname986" (func $internal986))
+  (import "env" "longname987" (func $internal987))
+  (import "env" "longname988" (func $internal988))
+  (import "env" "longname989" (func $internal989))
+  (import "env" "longname990" (func $internal990))
+  (import "env" "longname991" (func $internal991))
+  (import "env" "longname992" (func $internal992))
+  (import "env" "longname993" (func $internal993))
+  (import "env" "longname994" (func $internal994))
+  (import "env" "longname995" (func $internal995))
+  (import "env" "longname996" (func $internal996))
+  (import "env" "longname997" (func $internal997))
+  (import "env" "longname998" (func $internal998))
+  (import "env" "longname999" (func $internal999))
+  (import "env" "longname1000" (func $internal1000))
+  (import "env" "longname1001" (func $internal1001))
+  (import "env" "longname1002" (func $internal1002))
+  (import "env" "longname1003" (func $internal1003))
+  (import "env" "longname1004" (func $internal1004))
+  (import "env" "longname1005" (func $internal1005))
+  (import "env" "longname1006" (func $internal1006))
+  (import "env" "longname1007" (func $internal1007))
+  (import "env" "longname1008" (func $internal1008))
+  (import "env" "longname1009" (func $internal1009))
+  (import "env" "longname1010" (func $internal1010))
+  (import "env" "longname1011" (func $internal1011))
+  (import "env" "longname1012" (func $internal1012))
+  (import "env" "longname1013" (func $internal1013))
+  (import "env" "longname1014" (func $internal1014))
+  (import "env" "longname1015" (func $internal1015))
+  (import "env" "longname1016" (func $internal1016))
+  (import "env" "longname1017" (func $internal1017))
+  (import "env" "longname1018" (func $internal1018))
+  (import "env" "longname1019" (func $internal1019))
+  (import "env" "longname1020" (func $internal1020))
+  (import "env" "longname1021" (func $internal1021))
+  (import "env" "longname1022" (func $internal1022))
+  (import "env" "longname1023" (func $internal1023))
+  (import "env" "longname1024" (func $internal1024))
+  (import "env" "longname1025" (func $internal1025))
+  (import "env" "longname1026" (func $internal1026))
+  (import "env" "longname1027" (func $internal1027))
+  (import "env" "longname1028" (func $internal1028))
+  (import "env" "longname1029" (func $internal1029))
+  (import "env" "longname1030" (func $internal1030))
+  (import "env" "longname1031" (func $internal1031))
+  (import "env" "longname1032" (func $internal1032))
+  (import "env" "longname1033" (func $internal1033))
+  (import "env" "longname1034" (func $internal1034))
+  (import "env" "longname1035" (func $internal1035))
+  (import "env" "longname1036" (func $internal1036))
+  (import "env" "longname1037" (func $internal1037))
+  (import "env" "longname1038" (func $internal1038))
+  (import "env" "longname1039" (func $internal1039))
+  (import "env" "longname1040" (func $internal1040))
+  (import "env" "longname1041" (func $internal1041))
+  (import "env" "longname1042" (func $internal1042))
+  (import "env" "longname1043" (func $internal1043))
+  (import "env" "longname1044" (func $internal1044))
+  (import "env" "longname1045" (func $internal1045))
+  (import "env" "longname1046" (func $internal1046))
+  (import "env" "longname1047" (func $internal1047))
+  (import "env" "longname1048" (func $internal1048))
+  (import "env" "longname1049" (func $internal1049))
+  (import "env" "longname1050" (func $internal1050))
+  (import "env" "longname1051" (func $internal1051))
+  (import "env" "longname1052" (func $internal1052))
+  (import "env" "longname1053" (func $internal1053))
+  (import "env" "longname1054" (func $internal1054))
+  (import "env" "longname1055" (func $internal1055))
+  (import "env" "longname1056" (func $internal1056))
+  (import "env" "longname1057" (func $internal1057))
+  (import "env" "longname1058" (func $internal1058))
+  (import "env" "longname1059" (func $internal1059))
+  (import "env" "longname1060" (func $internal1060))
+  (import "env" "longname1061" (func $internal1061))
+  (import "env" "longname1062" (func $internal1062))
+  (import "env" "longname1063" (func $internal1063))
+  (import "env" "longname1064" (func $internal1064))
+  (import "env" "longname1065" (func $internal1065))
+  (import "env" "longname1066" (func $internal1066))
+  (import "env" "longname1067" (func $internal1067))
+  (import "env" "longname1068" (func $internal1068))
+  (import "env" "longname1069" (func $internal1069))
+  (import "env" "longname1070" (func $internal1070))
+  (import "env" "longname1071" (func $internal1071))
+  (import "env" "longname1072" (func $internal1072))
+  (import "env" "longname1073" (func $internal1073))
+  (import "env" "longname1074" (func $internal1074))
+  (import "env" "longname1075" (func $internal1075))
+  (import "env" "longname1076" (func $internal1076))
+  (import "env" "longname1077" (func $internal1077))
+  (import "env" "longname1078" (func $internal1078))
+  (import "env" "longname1079" (func $internal1079))
+  (import "env" "longname1080" (func $internal1080))
+  (import "env" "longname1081" (func $internal1081))
+  (import "env" "longname1082" (func $internal1082))
+  (import "env" "longname1083" (func $internal1083))
+  (import "env" "longname1084" (func $internal1084))
+  (import "env" "longname1085" (func $internal1085))
+  (import "env" "longname1086" (func $internal1086))
+  (import "env" "longname1087" (func $internal1087))
+  (import "env" "longname1088" (func $internal1088))
+  (import "env" "longname1089" (func $internal1089))
+  (import "env" "longname1090" (func $internal1090))
+  (import "env" "longname1091" (func $internal1091))
+  (import "env" "longname1092" (func $internal1092))
+  (import "env" "longname1093" (func $internal1093))
+  (import "env" "longname1094" (func $internal1094))
+  (import "env" "longname1095" (func $internal1095))
+  (import "env" "longname1096" (func $internal1096))
+  (import "env" "longname1097" (func $internal1097))
+  (import "env" "longname1098" (func $internal1098))
+  (import "env" "longname1099" (func $internal1099))
+  (import "env" "longname1100" (func $internal1100))
+  (import "env" "longname1101" (func $internal1101))
+  (import "env" "longname1102" (func $internal1102))
+  (import "env" "longname1103" (func $internal1103))
+  (import "env" "longname1104" (func $internal1104))
+  (import "env" "longname1105" (func $internal1105))
+  (import "env" "longname1106" (func $internal1106))
+  (import "env" "longname1107" (func $internal1107))
+  (import "env" "longname1108" (func $internal1108))
+  (import "env" "longname1109" (func $internal1109))
+  (import "env" "longname1110" (func $internal1110))
+  (import "env" "longname1111" (func $internal1111))
+  (import "env" "longname1112" (func $internal1112))
+  (import "env" "longname1113" (func $internal1113))
+  (import "env" "longname1114" (func $internal1114))
+  (import "env" "longname1115" (func $internal1115))
+  (import "env" "longname1116" (func $internal1116))
+  (import "env" "longname1117" (func $internal1117))
+  (import "env" "longname1118" (func $internal1118))
+  (import "env" "longname1119" (func $internal1119))
+  (import "env" "longname1120" (func $internal1120))
+  (import "env" "longname1121" (func $internal1121))
+  (import "env" "longname1122" (func $internal1122))
+  (import "env" "longname1123" (func $internal1123))
+  (import "env" "longname1124" (func $internal1124))
+  (import "env" "longname1125" (func $internal1125))
+  (import "env" "longname1126" (func $internal1126))
+  (import "env" "longname1127" (func $internal1127))
+  (import "env" "longname1128" (func $internal1128))
+  (import "env" "longname1129" (func $internal1129))
+  (import "env" "longname1130" (func $internal1130))
+  (import "env" "longname1131" (func $internal1131))
+  (import "env" "longname1132" (func $internal1132))
+  (import "env" "longname1133" (func $internal1133))
+  (import "env" "longname1134" (func $internal1134))
+  (import "env" "longname1135" (func $internal1135))
+  (import "env" "longname1136" (func $internal1136))
+  (import "env" "longname1137" (func $internal1137))
+  (import "env" "longname1138" (func $internal1138))
+  (import "env" "longname1139" (func $internal1139))
+  (import "env" "longname1140" (func $internal1140))
+  (import "env" "longname1141" (func $internal1141))
+  (import "env" "longname1142" (func $internal1142))
+  (import "env" "longname1143" (func $internal1143))
+  (import "env" "longname1144" (func $internal1144))
+  (import "env" "longname1145" (func $internal1145))
+  (import "env" "longname1146" (func $internal1146))
+  (import "env" "longname1147" (func $internal1147))
+  (import "env" "longname1148" (func $internal1148))
+  (import "env" "longname1149" (func $internal1149))
+  (import "env" "longname1150" (func $internal1150))
+  (import "env" "longname1151" (func $internal1151))
+  (import "env" "longname1152" (func $internal1152))
+  (import "env" "longname1153" (func $internal1153))
+  (import "env" "longname1154" (func $internal1154))
+  (import "env" "longname1155" (func $internal1155))
+  (import "env" "longname1156" (func $internal1156))
+  (import "env" "longname1157" (func $internal1157))
+  (import "env" "longname1158" (func $internal1158))
+  (import "env" "longname1159" (func $internal1159))
+  (import "env" "longname1160" (func $internal1160))
+  (import "env" "longname1161" (func $internal1161))
+  (import "env" "longname1162" (func $internal1162))
+  (import "env" "longname1163" (func $internal1163))
+  (import "env" "longname1164" (func $internal1164))
+  (import "env" "longname1165" (func $internal1165))
+  (import "env" "longname1166" (func $internal1166))
+  (import "env" "longname1167" (func $internal1167))
+  (import "env" "longname1168" (func $internal1168))
+  (import "env" "longname1169" (func $internal1169))
+  (import "env" "longname1170" (func $internal1170))
+  (import "env" "longname1171" (func $internal1171))
+  (import "env" "longname1172" (func $internal1172))
+  (import "env" "longname1173" (func $internal1173))
+  (import "env" "longname1174" (func $internal1174))
+  (import "env" "longname1175" (func $internal1175))
+  (import "env" "longname1176" (func $internal1176))
+  (import "env" "longname1177" (func $internal1177))
+  (import "env" "longname1178" (func $internal1178))
+  (import "env" "longname1179" (func $internal1179))
+  (import "env" "longname1180" (func $internal1180))
+  (import "env" "longname1181" (func $internal1181))
+  (import "env" "longname1182" (func $internal1182))
+  (import "env" "longname1183" (func $internal1183))
+  (import "env" "longname1184" (func $internal1184))
+  (import "env" "longname1185" (func $internal1185))
+  (import "env" "longname1186" (func $internal1186))
+  (import "env" "longname1187" (func $internal1187))
+  (import "env" "longname1188" (func $internal1188))
+  (import "env" "longname1189" (func $internal1189))
+  (import "env" "longname1190" (func $internal1190))
+  (import "env" "longname1191" (func $internal1191))
+  (import "env" "longname1192" (func $internal1192))
+  (import "env" "longname1193" (func $internal1193))
+  (import "env" "longname1194" (func $internal1194))
+  (import "env" "longname1195" (func $internal1195))
+  (import "env" "longname1196" (func $internal1196))
+  (import "env" "longname1197" (func $internal1197))
+  (import "env" "longname1198" (func $internal1198))
+  (import "env" "longname1199" (func $internal1199))
+  (import "env" "longname1200" (func $internal1200))
+  (import "env" "longname1201" (func $internal1201))
+  (import "env" "longname1202" (func $internal1202))
+  (import "env" "longname1203" (func $internal1203))
+  (import "env" "longname1204" (func $internal1204))
+  (import "env" "longname1205" (func $internal1205))
+  (import "env" "longname1206" (func $internal1206))
+  (import "env" "longname1207" (func $internal1207))
+  (import "env" "longname1208" (func $internal1208))
+  (import "env" "longname1209" (func $internal1209))
+  (import "env" "longname1210" (func $internal1210))
+  (import "env" "longname1211" (func $internal1211))
+  (import "env" "longname1212" (func $internal1212))
+  (import "env" "longname1213" (func $internal1213))
+  (import "env" "longname1214" (func $internal1214))
+  (import "env" "longname1215" (func $internal1215))
+  (import "env" "longname1216" (func $internal1216))
+  (import "env" "longname1217" (func $internal1217))
+  (import "env" "longname1218" (func $internal1218))
+  (import "env" "longname1219" (func $internal1219))
+  (import "env" "longname1220" (func $internal1220))
+  (import "env" "longname1221" (func $internal1221))
+  (import "env" "longname1222" (func $internal1222))
+  (import "env" "longname1223" (func $internal1223))
+  (import "env" "longname1224" (func $internal1224))
+  (import "env" "longname1225" (func $internal1225))
+  (import "env" "longname1226" (func $internal1226))
+  (import "env" "longname1227" (func $internal1227))
+  (import "env" "longname1228" (func $internal1228))
+  (import "env" "longname1229" (func $internal1229))
+  (import "env" "longname1230" (func $internal1230))
+  (import "env" "longname1231" (func $internal1231))
+  (import "env" "longname1232" (func $internal1232))
+  (import "env" "longname1233" (func $internal1233))
+  (import "env" "longname1234" (func $internal1234))
+  (import "env" "longname1235" (func $internal1235))
+  (import "env" "longname1236" (func $internal1236))
+  (import "env" "longname1237" (func $internal1237))
+  (import "env" "longname1238" (func $internal1238))
+  (import "env" "longname1239" (func $internal1239))
+  (import "env" "longname1240" (func $internal1240))
+  (import "env" "longname1241" (func $internal1241))
+  (import "env" "longname1242" (func $internal1242))
+  (import "env" "longname1243" (func $internal1243))
+  (import "env" "longname1244" (func $internal1244))
+  (import "env" "longname1245" (func $internal1245))
+  (import "env" "longname1246" (func $internal1246))
+  (import "env" "longname1247" (func $internal1247))
+  (import "env" "longname1248" (func $internal1248))
+  (import "env" "longname1249" (func $internal1249))
+  (import "env" "longname1250" (func $internal1250))
+  (import "env" "longname1251" (func $internal1251))
+  (import "env" "longname1252" (func $internal1252))
+  (import "env" "longname1253" (func $internal1253))
+  (import "env" "longname1254" (func $internal1254))
+  (import "env" "longname1255" (func $internal1255))
+  (import "env" "longname1256" (func $internal1256))
+  (import "env" "longname1257" (func $internal1257))
+  (import "env" "longname1258" (func $internal1258))
+  (import "env" "longname1259" (func $internal1259))
+  (import "env" "longname1260" (func $internal1260))
+  (import "env" "longname1261" (func $internal1261))
+  (import "env" "longname1262" (func $internal1262))
+  (import "env" "longname1263" (func $internal1263))
+  (import "env" "longname1264" (func $internal1264))
+  (import "env" "longname1265" (func $internal1265))
+  (import "env" "longname1266" (func $internal1266))
+  (import "env" "longname1267" (func $internal1267))
+  (import "env" "longname1268" (func $internal1268))
+  (import "env" "longname1269" (func $internal1269))
+  (import "env" "longname1270" (func $internal1270))
+  (import "env" "longname1271" (func $internal1271))
+  (import "env" "longname1272" (func $internal1272))
+  (import "env" "longname1273" (func $internal1273))
+  (import "env" "longname1274" (func $internal1274))
+  (import "env" "longname1275" (func $internal1275))
+  (import "env" "longname1276" (func $internal1276))
+  (import "env" "longname1277" (func $internal1277))
+  (import "env" "longname1278" (func $internal1278))
+  (import "env" "longname1279" (func $internal1279))
+  (import "env" "longname1280" (func $internal1280))
+  (import "env" "longname1281" (func $internal1281))
+  (import "env" "longname1282" (func $internal1282))
+  (import "env" "longname1283" (func $internal1283))
+  (import "env" "longname1284" (func $internal1284))
+  (import "env" "longname1285" (func $internal1285))
+  (import "env" "longname1286" (func $internal1286))
+  (import "env" "longname1287" (func $internal1287))
+  (import "env" "longname1288" (func $internal1288))
+  (import "env" "longname1289" (func $internal1289))
+  (import "env" "longname1290" (func $internal1290))
+  (import "env" "longname1291" (func $internal1291))
+  (import "env" "longname1292" (func $internal1292))
+  (import "env" "longname1293" (func $internal1293))
+  (import "env" "longname1294" (func $internal1294))
+  (import "env" "longname1295" (func $internal1295))
+  (import "env" "longname1296" (func $internal1296))
+  (import "env" "longname1297" (func $internal1297))
+  (import "env" "longname1298" (func $internal1298))
+  (import "env" "longname1299" (func $internal1299))
+  (import "env" "longname1300" (func $internal1300))
+  (import "env" "longname1301" (func $internal1301))
+  (import "env" "longname1302" (func $internal1302))
+  (import "env" "longname1303" (func $internal1303))
+  (import "env" "longname1304" (func $internal1304))
+  (import "env" "longname1305" (func $internal1305))
+  (import "env" "longname1306" (func $internal1306))
+  (import "env" "longname1307" (func $internal1307))
+  (import "env" "longname1308" (func $internal1308))
+  (import "env" "longname1309" (func $internal1309))
+  (import "env" "longname1310" (func $internal1310))
+  (import "env" "longname1311" (func $internal1311))
+  (import "env" "longname1312" (func $internal1312))
+  (import "env" "longname1313" (func $internal1313))
+  (import "env" "longname1314" (func $internal1314))
+  (import "env" "longname1315" (func $internal1315))
+  (import "env" "longname1316" (func $internal1316))
+  (import "env" "longname1317" (func $internal1317))
+  (import "env" "longname1318" (func $internal1318))
+  (import "env" "longname1319" (func $internal1319))
+  (import "env" "longname1320" (func $internal1320))
+  (import "env" "longname1321" (func $internal1321))
+  (import "env" "longname1322" (func $internal1322))
+  (import "env" "longname1323" (func $internal1323))
+  (import "env" "longname1324" (func $internal1324))
+  (import "env" "longname1325" (func $internal1325))
+  (import "env" "longname1326" (func $internal1326))
+  (import "env" "longname1327" (func $internal1327))
+  (import "env" "longname1328" (func $internal1328))
+  (import "env" "longname1329" (func $internal1329))
+  (import "env" "longname1330" (func $internal1330))
+  (import "env" "longname1331" (func $internal1331))
+  (import "env" "longname1332" (func $internal1332))
+  (import "env" "longname1333" (func $internal1333))
+  (import "env" "longname1334" (func $internal1334))
+  (import "env" "longname1335" (func $internal1335))
+  (import "env" "longname1336" (func $internal1336))
+  (import "env" "longname1337" (func $internal1337))
+  (import "env" "longname1338" (func $internal1338))
+  (import "env" "longname1339" (func $internal1339))
+  (import "env" "longname1340" (func $internal1340))
+  (import "env" "longname1341" (func $internal1341))
+  (import "env" "longname1342" (func $internal1342))
+  (import "env" "longname1343" (func $internal1343))
+  (import "env" "longname1344" (func $internal1344))
+  (import "env" "longname1345" (func $internal1345))
+  (import "env" "longname1346" (func $internal1346))
+  (import "env" "longname1347" (func $internal1347))
+  (import "env" "longname1348" (func $internal1348))
+  (import "env" "longname1349" (func $internal1349))
+  (import "env" "longname1350" (func $internal1350))
+  (import "env" "longname1351" (func $internal1351))
+  (import "env" "longname1352" (func $internal1352))
+  (import "env" "longname1353" (func $internal1353))
+  (import "env" "longname1354" (func $internal1354))
+  (import "env" "longname1355" (func $internal1355))
+  (import "env" "longname1356" (func $internal1356))
+  (import "env" "longname1357" (func $internal1357))
+  (import "env" "longname1358" (func $internal1358))
+  (import "env" "longname1359" (func $internal1359))
+  (import "env" "longname1360" (func $internal1360))
+  (import "env" "longname1361" (func $internal1361))
+  (import "env" "longname1362" (func $internal1362))
+  (import "env" "longname1363" (func $internal1363))
+  (import "env" "longname1364" (func $internal1364))
+  (import "env" "longname1365" (func $internal1365))
+  (import "env" "longname1366" (func $internal1366))
+  (import "env" "longname1367" (func $internal1367))
+  (import "env" "longname1368" (func $internal1368))
+  (import "env" "longname1369" (func $internal1369))
+  (import "env" "longname1370" (func $internal1370))
+  (import "env" "longname1371" (func $internal1371))
+  (import "env" "longname1372" (func $internal1372))
+  (import "env" "longname1373" (func $internal1373))
+  (import "env" "longname1374" (func $internal1374))
+  (import "env" "longname1375" (func $internal1375))
+  (import "env" "longname1376" (func $internal1376))
+  (import "env" "longname1377" (func $internal1377))
+  (import "env" "longname1378" (func $internal1378))
+  (import "env" "longname1379" (func $internal1379))
+  (import "env" "longname1380" (func $internal1380))
+  (import "env" "longname1381" (func $internal1381))
+  (import "env" "longname1382" (func $internal1382))
+  (import "env" "longname1383" (func $internal1383))
+  (import "env" "longname1384" (func $internal1384))
+  (import "env" "longname1385" (func $internal1385))
+  (import "env" "longname1386" (func $internal1386))
+  (import "env" "longname1387" (func $internal1387))
+  (import "env" "longname1388" (func $internal1388))
+  (import "env" "longname1389" (func $internal1389))
+  (import "env" "longname1390" (func $internal1390))
+  (import "env" "longname1391" (func $internal1391))
+  (import "env" "longname1392" (func $internal1392))
+  (import "env" "longname1393" (func $internal1393))
+  (import "env" "longname1394" (func $internal1394))
+  (import "env" "longname1395" (func $internal1395))
+  (import "env" "longname1396" (func $internal1396))
+  (import "env" "longname1397" (func $internal1397))
+  (import "env" "longname1398" (func $internal1398))
+  (import "env" "longname1399" (func $internal1399))
+  (import "env" "longname1400" (func $internal1400))
+  (import "env" "longname1401" (func $internal1401))
+  (import "env" "longname1402" (func $internal1402))
+  (import "env" "longname1403" (func $internal1403))
+  (import "env" "longname1404" (func $internal1404))
+  (import "env" "longname1405" (func $internal1405))
+  (import "env" "longname1406" (func $internal1406))
+  (import "env" "longname1407" (func $internal1407))
+  (import "env" "longname1408" (func $internal1408))
+  (import "env" "longname1409" (func $internal1409))
+  (import "env" "longname1410" (func $internal1410))
+  (import "env" "longname1411" (func $internal1411))
+  (import "env" "longname1412" (func $internal1412))
+  (import "env" "longname1413" (func $internal1413))
+  (import "env" "longname1414" (func $internal1414))
+  (import "env" "longname1415" (func $internal1415))
+  (import "env" "longname1416" (func $internal1416))
+  (import "env" "longname1417" (func $internal1417))
+  (import "env" "longname1418" (func $internal1418))
+  (import "env" "longname1419" (func $internal1419))
+  (import "env" "longname1420" (func $internal1420))
+  (import "env" "longname1421" (func $internal1421))
+  (import "env" "longname1422" (func $internal1422))
+  (import "env" "longname1423" (func $internal1423))
+  (import "env" "longname1424" (func $internal1424))
+  (import "env" "longname1425" (func $internal1425))
+  (import "env" "longname1426" (func $internal1426))
+  (import "env" "longname1427" (func $internal1427))
+  (import "env" "longname1428" (func $internal1428))
+  (import "env" "longname1429" (func $internal1429))
+  (import "env" "longname1430" (func $internal1430))
+  (import "env" "longname1431" (func $internal1431))
+  (import "env" "longname1432" (func $internal1432))
+  (import "env" "longname1433" (func $internal1433))
+  (import "env" "longname1434" (func $internal1434))
+  (import "env" "longname1435" (func $internal1435))
+  (import "env" "longname1436" (func $internal1436))
+  (import "env" "longname1437" (func $internal1437))
+  (import "env" "longname1438" (func $internal1438))
+  (import "env" "longname1439" (func $internal1439))
+  (import "env" "longname1440" (func $internal1440))
+  (import "env" "longname1441" (func $internal1441))
+  (import "env" "longname1442" (func $internal1442))
+  (import "env" "longname1443" (func $internal1443))
+  (import "env" "longname1444" (func $internal1444))
+  (import "env" "longname1445" (func $internal1445))
+  (import "env" "longname1446" (func $internal1446))
+  (import "env" "longname1447" (func $internal1447))
+  (import "env" "longname1448" (func $internal1448))
+  (import "env" "longname1449" (func $internal1449))
+  (import "env" "longname1450" (func $internal1450))
+  (import "env" "longname1451" (func $internal1451))
+  (import "env" "longname1452" (func $internal1452))
+  (import "env" "longname1453" (func $internal1453))
+  (import "env" "longname1454" (func $internal1454))
+  (import "env" "longname1455" (func $internal1455))
+  (import "env" "longname1456" (func $internal1456))
+  (import "env" "longname1457" (func $internal1457))
+  (import "env" "longname1458" (func $internal1458))
+  (import "env" "longname1459" (func $internal1459))
+  (import "env" "longname1460" (func $internal1460))
+  (import "env" "longname1461" (func $internal1461))
+  (import "env" "longname1462" (func $internal1462))
+  (import "env" "longname1463" (func $internal1463))
+  (import "env" "longname1464" (func $internal1464))
+  (import "env" "longname1465" (func $internal1465))
+  (import "env" "longname1466" (func $internal1466))
+  (import "env" "longname1467" (func $internal1467))
+  (import "env" "longname1468" (func $internal1468))
+  (import "env" "longname1469" (func $internal1469))
+  (import "env" "longname1470" (func $internal1470))
+  (import "env" "longname1471" (func $internal1471))
+  (import "env" "longname1472" (func $internal1472))
+  (import "env" "longname1473" (func $internal1473))
+  (import "env" "longname1474" (func $internal1474))
+  (import "env" "longname1475" (func $internal1475))
+  (import "env" "longname1476" (func $internal1476))
+  (import "env" "longname1477" (func $internal1477))
+  (import "env" "longname1478" (func $internal1478))
+  (import "env" "longname1479" (func $internal1479))
+  (import "env" "longname1480" (func $internal1480))
+  (import "env" "longname1481" (func $internal1481))
+  (import "env" "longname1482" (func $internal1482))
+  (import "env" "longname1483" (func $internal1483))
+  (import "env" "longname1484" (func $internal1484))
+  (import "env" "longname1485" (func $internal1485))
+  (import "env" "longname1486" (func $internal1486))
+  (import "env" "longname1487" (func $internal1487))
+  (import "env" "longname1488" (func $internal1488))
+  (import "env" "longname1489" (func $internal1489))
+  (import "env" "longname1490" (func $internal1490))
+  (import "env" "longname1491" (func $internal1491))
+  (import "env" "longname1492" (func $internal1492))
+  (import "env" "longname1493" (func $internal1493))
+  (import "env" "longname1494" (func $internal1494))
+  (import "env" "longname1495" (func $internal1495))
+  (import "env" "longname1496" (func $internal1496))
+  (import "env" "longname1497" (func $internal1497))
+  (import "env" "longname1498" (func $internal1498))
+  (import "env" "longname1499" (func $internal1499))
+  (import "env" "longname1500" (func $internal1500))
+  (import "env" "longname1501" (func $internal1501))
+  (import "env" "longname1502" (func $internal1502))
+  (import "env" "longname1503" (func $internal1503))
+  (import "env" "longname1504" (func $internal1504))
+  (import "env" "longname1505" (func $internal1505))
+  (import "env" "longname1506" (func $internal1506))
+  (import "env" "longname1507" (func $internal1507))
+  (import "env" "longname1508" (func $internal1508))
+  (import "env" "longname1509" (func $internal1509))
+  (import "env" "longname1510" (func $internal1510))
+  (import "env" "longname1511" (func $internal1511))
+  (import "env" "longname1512" (func $internal1512))
+  (import "env" "longname1513" (func $internal1513))
+  (import "env" "longname1514" (func $internal1514))
+  (import "env" "longname1515" (func $internal1515))
+  (import "env" "longname1516" (func $internal1516))
+  (import "env" "longname1517" (func $internal1517))
+  (import "env" "longname1518" (func $internal1518))
+  (import "env" "longname1519" (func $internal1519))
+  (import "env" "longname1520" (func $internal1520))
+  (import "env" "longname1521" (func $internal1521))
+  (import "env" "longname1522" (func $internal1522))
+  (import "env" "longname1523" (func $internal1523))
+  (import "env" "longname1524" (func $internal1524))
+  (import "env" "longname1525" (func $internal1525))
+  (import "env" "longname1526" (func $internal1526))
+  (import "env" "longname1527" (func $internal1527))
+  (import "env" "longname1528" (func $internal1528))
+  (import "env" "longname1529" (func $internal1529))
+  (import "env" "longname1530" (func $internal1530))
+  (import "env" "longname1531" (func $internal1531))
+  (import "env" "longname1532" (func $internal1532))
+  (import "env" "longname1533" (func $internal1533))
+  (import "env" "longname1534" (func $internal1534))
+  (import "env" "longname1535" (func $internal1535))
+  (import "env" "longname1536" (func $internal1536))
+  (import "env" "longname1537" (func $internal1537))
+  (import "env" "longname1538" (func $internal1538))
+  (import "env" "longname1539" (func $internal1539))
+  (import "env" "longname1540" (func $internal1540))
+  (import "env" "longname1541" (func $internal1541))
+  (import "env" "longname1542" (func $internal1542))
+  (import "env" "longname1543" (func $internal1543))
+  (import "env" "longname1544" (func $internal1544))
+  (import "env" "longname1545" (func $internal1545))
+  (import "env" "longname1546" (func $internal1546))
+  (import "env" "longname1547" (func $internal1547))
+  (import "env" "longname1548" (func $internal1548))
+  (import "env" "longname1549" (func $internal1549))
+  (import "env" "longname1550" (func $internal1550))
+  (import "env" "longname1551" (func $internal1551))
+  (import "env" "longname1552" (func $internal1552))
+  (import "env" "longname1553" (func $internal1553))
+  (import "env" "longname1554" (func $internal1554))
+  (import "env" "longname1555" (func $internal1555))
+  (import "env" "longname1556" (func $internal1556))
+  (import "env" "longname1557" (func $internal1557))
+  (import "env" "longname1558" (func $internal1558))
+  (import "env" "longname1559" (func $internal1559))
+  (import "env" "longname1560" (func $internal1560))
+  (import "env" "longname1561" (func $internal1561))
+  (import "env" "longname1562" (func $internal1562))
+  (import "env" "longname1563" (func $internal1563))
+  (import "env" "longname1564" (func $internal1564))
+  (import "env" "longname1565" (func $internal1565))
+  (import "env" "longname1566" (func $internal1566))
+  (import "env" "longname1567" (func $internal1567))
+  (import "env" "longname1568" (func $internal1568))
+  (import "env" "longname1569" (func $internal1569))
+  (import "env" "longname1570" (func $internal1570))
+  (import "env" "longname1571" (func $internal1571))
+  (import "env" "longname1572" (func $internal1572))
+  (import "env" "longname1573" (func $internal1573))
+  (import "env" "longname1574" (func $internal1574))
+  (import "env" "longname1575" (func $internal1575))
+  (import "env" "longname1576" (func $internal1576))
+  (import "env" "longname1577" (func $internal1577))
+  (import "env" "longname1578" (func $internal1578))
+  (import "env" "longname1579" (func $internal1579))
+  (import "env" "longname1580" (func $internal1580))
+  (import "env" "longname1581" (func $internal1581))
+  (import "env" "longname1582" (func $internal1582))
+  (import "env" "longname1583" (func $internal1583))
+  (import "env" "longname1584" (func $internal1584))
+  (import "env" "longname1585" (func $internal1585))
+  (import "env" "longname1586" (func $internal1586))
+  (import "env" "longname1587" (func $internal1587))
+  (import "env" "longname1588" (func $internal1588))
+  (import "env" "longname1589" (func $internal1589))
+  (import "env" "longname1590" (func $internal1590))
+  (import "env" "longname1591" (func $internal1591))
+  (import "env" "longname1592" (func $internal1592))
+  (import "env" "longname1593" (func $internal1593))
+  (import "env" "longname1594" (func $internal1594))
+  (import "env" "longname1595" (func $internal1595))
+  (import "env" "longname1596" (func $internal1596))
+  (import "env" "longname1597" (func $internal1597))
+  (import "env" "longname1598" (func $internal1598))
+  (import "env" "longname1599" (func $internal1599))
+  (import "env" "longname1600" (func $internal1600))
+  (import "env" "longname1601" (func $internal1601))
+  (import "env" "longname1602" (func $internal1602))
+  (import "env" "longname1603" (func $internal1603))
+  (import "env" "longname1604" (func $internal1604))
+  (import "env" "longname1605" (func $internal1605))
+  (import "env" "longname1606" (func $internal1606))
+  (import "env" "longname1607" (func $internal1607))
+  (import "env" "longname1608" (func $internal1608))
+  (import "env" "longname1609" (func $internal1609))
+  (import "env" "longname1610" (func $internal1610))
+  (import "env" "longname1611" (func $internal1611))
+  (import "env" "longname1612" (func $internal1612))
+  (import "env" "longname1613" (func $internal1613))
+  (import "env" "longname1614" (func $internal1614))
+  (import "env" "longname1615" (func $internal1615))
+  (import "env" "longname1616" (func $internal1616))
+  (import "env" "longname1617" (func $internal1617))
+  (import "env" "longname1618" (func $internal1618))
+  (import "env" "longname1619" (func $internal1619))
+  (import "env" "longname1620" (func $internal1620))
+  (import "env" "longname1621" (func $internal1621))
+  (import "env" "longname1622" (func $internal1622))
+  (import "env" "longname1623" (func $internal1623))
+  (import "env" "longname1624" (func $internal1624))
+  (import "env" "longname1625" (func $internal1625))
+  (import "env" "longname1626" (func $internal1626))
+  (import "env" "longname1627" (func $internal1627))
+  (import "env" "longname1628" (func $internal1628))
+  (import "env" "longname1629" (func $internal1629))
+  (import "env" "longname1630" (func $internal1630))
+  (import "env" "longname1631" (func $internal1631))
+  (import "env" "longname1632" (func $internal1632))
+  (import "env" "longname1633" (func $internal1633))
+  (import "env" "longname1634" (func $internal1634))
+  (import "env" "longname1635" (func $internal1635))
+  (import "env" "longname1636" (func $internal1636))
+  (import "env" "longname1637" (func $internal1637))
+  (import "env" "longname1638" (func $internal1638))
+  (import "env" "longname1639" (func $internal1639))
+  (import "env" "longname1640" (func $internal1640))
+  (import "env" "longname1641" (func $internal1641))
+  (import "env" "longname1642" (func $internal1642))
+  (import "env" "longname1643" (func $internal1643))
+  (import "env" "longname1644" (func $internal1644))
+  (import "env" "longname1645" (func $internal1645))
+  (import "env" "longname1646" (func $internal1646))
+  (import "env" "longname1647" (func $internal1647))
+  (import "env" "longname1648" (func $internal1648))
+  (import "env" "longname1649" (func $internal1649))
+  (import "env" "longname1650" (func $internal1650))
+  (import "env" "longname1651" (func $internal1651))
+  (import "env" "longname1652" (func $internal1652))
+  (import "env" "longname1653" (func $internal1653))
+  (import "env" "longname1654" (func $internal1654))
+  (import "env" "longname1655" (func $internal1655))
+  (import "env" "longname1656" (func $internal1656))
+  (import "env" "longname1657" (func $internal1657))
+  (import "env" "longname1658" (func $internal1658))
+  (import "env" "longname1659" (func $internal1659))
+  (import "env" "longname1660" (func $internal1660))
+  (import "env" "longname1661" (func $internal1661))
+  (import "env" "longname1662" (func $internal1662))
+  (import "env" "longname1663" (func $internal1663))
+  (import "env" "longname1664" (func $internal1664))
+  (import "env" "longname1665" (func $internal1665))
+  (import "env" "longname1666" (func $internal1666))
+  (import "env" "longname1667" (func $internal1667))
+  (import "env" "longname1668" (func $internal1668))
+  (import "env" "longname1669" (func $internal1669))
+  (import "env" "longname1670" (func $internal1670))
+  (import "env" "longname1671" (func $internal1671))
+  (import "env" "longname1672" (func $internal1672))
+  (import "env" "longname1673" (func $internal1673))
+  (import "env" "longname1674" (func $internal1674))
+  (import "env" "longname1675" (func $internal1675))
+  (import "env" "longname1676" (func $internal1676))
+  (import "env" "longname1677" (func $internal1677))
+  (import "env" "longname1678" (func $internal1678))
+  (import "env" "longname1679" (func $internal1679))
+  (import "env" "longname1680" (func $internal1680))
+  (import "env" "longname1681" (func $internal1681))
+  (import "env" "longname1682" (func $internal1682))
+  (import "env" "longname1683" (func $internal1683))
+  (import "env" "longname1684" (func $internal1684))
+  (import "env" "longname1685" (func $internal1685))
+  (import "env" "longname1686" (func $internal1686))
+  (import "env" "longname1687" (func $internal1687))
+  (import "env" "longname1688" (func $internal1688))
+  (import "env" "longname1689" (func $internal1689))
+  (import "env" "longname1690" (func $internal1690))
+  (import "env" "longname1691" (func $internal1691))
+  (import "env" "longname1692" (func $internal1692))
+  (import "env" "longname1693" (func $internal1693))
+  (import "env" "longname1694" (func $internal1694))
+  (import "env" "longname1695" (func $internal1695))
+  (import "env" "longname1696" (func $internal1696))
+  (import "env" "longname1697" (func $internal1697))
+  (import "env" "longname1698" (func $internal1698))
+  (import "env" "longname1699" (func $internal1699))
+  (import "env" "longname1700" (func $internal1700))
+  (import "env" "longname1701" (func $internal1701))
+  (import "env" "longname1702" (func $internal1702))
+  (import "env" "longname1703" (func $internal1703))
+  (import "env" "longname1704" (func $internal1704))
+  (import "env" "longname1705" (func $internal1705))
+  (import "env" "longname1706" (func $internal1706))
+  (import "env" "longname1707" (func $internal1707))
+  (import "env" "longname1708" (func $internal1708))
+  (import "env" "longname1709" (func $internal1709))
+  (import "env" "longname1710" (func $internal1710))
+  (import "env" "longname1711" (func $internal1711))
+  (import "env" "longname1712" (func $internal1712))
+  (import "env" "longname1713" (func $internal1713))
+  (import "env" "longname1714" (func $internal1714))
+  (import "env" "longname1715" (func $internal1715))
+  (import "env" "longname1716" (func $internal1716))
+  (import "env" "longname1717" (func $internal1717))
+  (import "env" "longname1718" (func $internal1718))
+  (import "env" "longname1719" (func $internal1719))
+  (import "env" "longname1720" (func $internal1720))
+  (import "env" "longname1721" (func $internal1721))
+  (import "env" "longname1722" (func $internal1722))
+  (import "env" "longname1723" (func $internal1723))
+  (import "env" "longname1724" (func $internal1724))
+  (import "env" "longname1725" (func $internal1725))
+  (import "env" "longname1726" (func $internal1726))
+  (import "env" "longname1727" (func $internal1727))
+  (import "env" "longname1728" (func $internal1728))
+  (import "env" "longname1729" (func $internal1729))
+  (import "env" "longname1730" (func $internal1730))
+  (import "env" "longname1731" (func $internal1731))
+  (import "env" "longname1732" (func $internal1732))
+  (import "env" "longname1733" (func $internal1733))
+  (import "env" "longname1734" (func $internal1734))
+  (import "env" "longname1735" (func $internal1735))
+  (import "env" "longname1736" (func $internal1736))
+  (import "env" "longname1737" (func $internal1737))
+  (import "env" "longname1738" (func $internal1738))
+  (import "env" "longname1739" (func $internal1739))
+  (import "env" "longname1740" (func $internal1740))
+  (import "env" "longname1741" (func $internal1741))
+  (import "env" "longname1742" (func $internal1742))
+  (import "env" "longname1743" (func $internal1743))
+  (import "env" "longname1744" (func $internal1744))
+  (import "env" "longname1745" (func $internal1745))
+  (import "env" "longname1746" (func $internal1746))
+  (import "env" "longname1747" (func $internal1747))
+  (import "env" "longname1748" (func $internal1748))
+  (import "env" "longname1749" (func $internal1749))
+  (import "env" "longname1750" (func $internal1750))
+  (import "env" "longname1751" (func $internal1751))
+  (import "env" "longname1752" (func $internal1752))
+  (import "env" "longname1753" (func $internal1753))
+  (import "env" "longname1754" (func $internal1754))
+  (import "env" "longname1755" (func $internal1755))
+  (import "env" "longname1756" (func $internal1756))
+  (import "env" "longname1757" (func $internal1757))
+  (import "env" "longname1758" (func $internal1758))
+  (import "env" "longname1759" (func $internal1759))
+  (import "env" "longname1760" (func $internal1760))
+  (import "env" "longname1761" (func $internal1761))
+  (import "env" "longname1762" (func $internal1762))
+  (import "env" "longname1763" (func $internal1763))
+  (import "env" "longname1764" (func $internal1764))
+  (import "env" "longname1765" (func $internal1765))
+  (import "env" "longname1766" (func $internal1766))
+  (import "env" "longname1767" (func $internal1767))
+  (import "env" "longname1768" (func $internal1768))
+  (import "env" "longname1769" (func $internal1769))
+  (import "env" "longname1770" (func $internal1770))
+  (import "env" "longname1771" (func $internal1771))
+  (import "env" "longname1772" (func $internal1772))
+  (import "env" "longname1773" (func $internal1773))
+  (import "env" "longname1774" (func $internal1774))
+  (import "env" "longname1775" (func $internal1775))
+  (import "env" "longname1776" (func $internal1776))
+  (import "env" "longname1777" (func $internal1777))
+  (import "env" "longname1778" (func $internal1778))
+  (import "env" "longname1779" (func $internal1779))
+  (import "env" "longname1780" (func $internal1780))
+  (import "env" "longname1781" (func $internal1781))
+  (import "env" "longname1782" (func $internal1782))
+  (import "env" "longname1783" (func $internal1783))
+  (import "env" "longname1784" (func $internal1784))
+  (import "env" "longname1785" (func $internal1785))
+  (import "env" "longname1786" (func $internal1786))
+  (import "env" "longname1787" (func $internal1787))
+  (import "env" "longname1788" (func $internal1788))
+  (import "env" "longname1789" (func $internal1789))
+  (import "env" "longname1790" (func $internal1790))
+  (import "env" "longname1791" (func $internal1791))
+  (import "env" "longname1792" (func $internal1792))
+  (import "env" "longname1793" (func $internal1793))
+  (import "env" "longname1794" (func $internal1794))
+  (import "env" "longname1795" (func $internal1795))
+  (import "env" "longname1796" (func $internal1796))
+  (import "env" "longname1797" (func $internal1797))
+  (import "env" "longname1798" (func $internal1798))
+  (import "env" "longname1799" (func $internal1799))
+  (import "env" "longname1800" (func $internal1800))
+  (import "env" "longname1801" (func $internal1801))
+  (import "env" "longname1802" (func $internal1802))
+  (import "env" "longname1803" (func $internal1803))
+  (import "env" "longname1804" (func $internal1804))
+  (import "env" "longname1805" (func $internal1805))
+  (import "env" "longname1806" (func $internal1806))
+  (import "env" "longname1807" (func $internal1807))
+  (import "env" "longname1808" (func $internal1808))
+  (import "env" "longname1809" (func $internal1809))
+  (import "env" "longname1810" (func $internal1810))
+  (import "env" "longname1811" (func $internal1811))
+  (import "env" "longname1812" (func $internal1812))
+  (import "env" "longname1813" (func $internal1813))
+  (import "env" "longname1814" (func $internal1814))
+  (import "env" "longname1815" (func $internal1815))
+  (import "env" "longname1816" (func $internal1816))
+  (import "env" "longname1817" (func $internal1817))
+  (import "env" "longname1818" (func $internal1818))
+  (import "env" "longname1819" (func $internal1819))
+  (import "env" "longname1820" (func $internal1820))
+  (import "env" "longname1821" (func $internal1821))
+  (import "env" "longname1822" (func $internal1822))
+  (import "env" "longname1823" (func $internal1823))
+  (import "env" "longname1824" (func $internal1824))
+  (import "env" "longname1825" (func $internal1825))
+  (import "env" "longname1826" (func $internal1826))
+  (import "env" "longname1827" (func $internal1827))
+  (import "env" "longname1828" (func $internal1828))
+  (import "env" "longname1829" (func $internal1829))
+  (import "env" "longname1830" (func $internal1830))
+  (import "env" "longname1831" (func $internal1831))
+  (import "env" "longname1832" (func $internal1832))
+  (import "env" "longname1833" (func $internal1833))
+  (import "env" "longname1834" (func $internal1834))
+  (import "env" "longname1835" (func $internal1835))
+  (import "env" "longname1836" (func $internal1836))
+  (import "env" "longname1837" (func $internal1837))
+  (import "env" "longname1838" (func $internal1838))
+  (import "env" "longname1839" (func $internal1839))
+  (import "env" "longname1840" (func $internal1840))
+  (import "env" "longname1841" (func $internal1841))
+  (import "env" "longname1842" (func $internal1842))
+  (import "env" "longname1843" (func $internal1843))
+  (import "env" "longname1844" (func $internal1844))
+  (import "env" "longname1845" (func $internal1845))
+  (import "env" "longname1846" (func $internal1846))
+  (import "env" "longname1847" (func $internal1847))
+  (import "env" "longname1848" (func $internal1848))
+  (import "env" "longname1849" (func $internal1849))
+  (import "env" "longname1850" (func $internal1850))
+  (import "env" "longname1851" (func $internal1851))
+  (import "env" "longname1852" (func $internal1852))
+  (import "env" "longname1853" (func $internal1853))
+  (import "env" "longname1854" (func $internal1854))
+  (import "env" "longname1855" (func $internal1855))
+  (import "env" "longname1856" (func $internal1856))
+  (import "env" "longname1857" (func $internal1857))
+  (import "env" "longname1858" (func $internal1858))
+  (import "env" "longname1859" (func $internal1859))
+  (import "env" "longname1860" (func $internal1860))
+  (import "env" "longname1861" (func $internal1861))
+  (import "env" "longname1862" (func $internal1862))
+  (import "env" "longname1863" (func $internal1863))
+  (import "env" "longname1864" (func $internal1864))
+  (import "env" "longname1865" (func $internal1865))
+  (import "env" "longname1866" (func $internal1866))
+  (import "env" "longname1867" (func $internal1867))
+  (import "env" "longname1868" (func $internal1868))
+  (import "env" "longname1869" (func $internal1869))
+  (import "env" "longname1870" (func $internal1870))
+  (import "env" "longname1871" (func $internal1871))
+  (import "env" "longname1872" (func $internal1872))
+  (import "env" "longname1873" (func $internal1873))
+  (import "env" "longname1874" (func $internal1874))
+  (import "env" "longname1875" (func $internal1875))
+  (import "env" "longname1876" (func $internal1876))
+  (import "env" "longname1877" (func $internal1877))
+  (import "env" "longname1878" (func $internal1878))
+  (import "env" "longname1879" (func $internal1879))
+  (import "env" "longname1880" (func $internal1880))
+  (import "env" "longname1881" (func $internal1881))
+  (import "env" "longname1882" (func $internal1882))
+  (import "env" "longname1883" (func $internal1883))
+  (import "env" "longname1884" (func $internal1884))
+  (import "env" "longname1885" (func $internal1885))
+  (import "env" "longname1886" (func $internal1886))
+  (import "env" "longname1887" (func $internal1887))
+  (import "env" "longname1888" (func $internal1888))
+  (import "env" "longname1889" (func $internal1889))
+  (import "env" "longname1890" (func $internal1890))
+  (import "env" "longname1891" (func $internal1891))
+  (import "env" "longname1892" (func $internal1892))
+  (import "env" "longname1893" (func $internal1893))
+  (import "env" "longname1894" (func $internal1894))
+  (import "env" "longname1895" (func $internal1895))
+  (import "env" "longname1896" (func $internal1896))
+  (import "env" "longname1897" (func $internal1897))
+  (import "env" "longname1898" (func $internal1898))
+  (import "env" "longname1899" (func $internal1899))
+  (import "env" "longname1900" (func $internal1900))
+  (import "env" "longname1901" (func $internal1901))
+  (import "env" "longname1902" (func $internal1902))
+  (import "env" "longname1903" (func $internal1903))
+  (import "env" "longname1904" (func $internal1904))
+  (import "env" "longname1905" (func $internal1905))
+  (import "env" "longname1906" (func $internal1906))
+  (import "env" "longname1907" (func $internal1907))
+  (import "env" "longname1908" (func $internal1908))
+  (import "env" "longname1909" (func $internal1909))
+  (import "env" "longname1910" (func $internal1910))
+  (import "env" "longname1911" (func $internal1911))
+  (import "env" "longname1912" (func $internal1912))
+  (import "env" "longname1913" (func $internal1913))
+  (import "env" "longname1914" (func $internal1914))
+  (import "env" "longname1915" (func $internal1915))
+  (import "env" "longname1916" (func $internal1916))
+  (import "env" "longname1917" (func $internal1917))
+  (import "env" "longname1918" (func $internal1918))
+  (import "env" "longname1919" (func $internal1919))
+  (import "env" "longname1920" (func $internal1920))
+  (import "env" "longname1921" (func $internal1921))
+  (import "env" "longname1922" (func $internal1922))
+  (import "env" "longname1923" (func $internal1923))
+  (import "env" "longname1924" (func $internal1924))
+  (import "env" "longname1925" (func $internal1925))
+  (import "env" "longname1926" (func $internal1926))
+  (import "env" "longname1927" (func $internal1927))
+  (import "env" "longname1928" (func $internal1928))
+  (import "env" "longname1929" (func $internal1929))
+  (import "env" "longname1930" (func $internal1930))
+  (import "env" "longname1931" (func $internal1931))
+  (import "env" "longname1932" (func $internal1932))
+  (import "env" "longname1933" (func $internal1933))
+  (import "env" "longname1934" (func $internal1934))
+  (import "env" "longname1935" (func $internal1935))
+  (import "env" "longname1936" (func $internal1936))
+  (import "env" "longname1937" (func $internal1937))
+  (import "env" "longname1938" (func $internal1938))
+  (import "env" "longname1939" (func $internal1939))
+  (import "env" "longname1940" (func $internal1940))
+  (import "env" "longname1941" (func $internal1941))
+  (import "env" "longname1942" (func $internal1942))
+  (import "env" "longname1943" (func $internal1943))
+  (import "env" "longname1944" (func $internal1944))
+  (import "env" "longname1945" (func $internal1945))
+  (import "env" "longname1946" (func $internal1946))
+  (import "env" "longname1947" (func $internal1947))
+  (import "env" "longname1948" (func $internal1948))
+  (import "env" "longname1949" (func $internal1949))
+  (import "env" "longname1950" (func $internal1950))
+  (import "env" "longname1951" (func $internal1951))
+  (import "env" "longname1952" (func $internal1952))
+  (import "env" "longname1953" (func $internal1953))
+  (import "env" "longname1954" (func $internal1954))
+  (import "env" "longname1955" (func $internal1955))
+  (import "env" "longname1956" (func $internal1956))
+  (import "env" "longname1957" (func $internal1957))
+  (import "env" "longname1958" (func $internal1958))
+  (import "env" "longname1959" (func $internal1959))
+  (import "env" "longname1960" (func $internal1960))
+  (import "env" "longname1961" (func $internal1961))
+  (import "env" "longname1962" (func $internal1962))
+  (import "env" "longname1963" (func $internal1963))
+  (import "env" "longname1964" (func $internal1964))
+  (import "env" "longname1965" (func $internal1965))
+  (import "env" "longname1966" (func $internal1966))
+  (import "env" "longname1967" (func $internal1967))
+  (import "env" "longname1968" (func $internal1968))
+  (import "env" "longname1969" (func $internal1969))
+  (import "env" "longname1970" (func $internal1970))
+  (import "env" "longname1971" (func $internal1971))
+  (import "env" "longname1972" (func $internal1972))
+  (import "env" "longname1973" (func $internal1973))
+  (import "env" "longname1974" (func $internal1974))
+  (import "env" "longname1975" (func $internal1975))
+  (import "env" "longname1976" (func $internal1976))
+  (import "env" "longname1977" (func $internal1977))
+  (import "env" "longname1978" (func $internal1978))
+  (import "env" "longname1979" (func $internal1979))
+  (import "env" "longname1980" (func $internal1980))
+  (import "env" "longname1981" (func $internal1981))
+  (import "env" "longname1982" (func $internal1982))
+  (import "env" "longname1983" (func $internal1983))
+  (import "env" "longname1984" (func $internal1984))
+  (import "env" "longname1985" (func $internal1985))
+  (import "env" "longname1986" (func $internal1986))
+  (import "env" "longname1987" (func $internal1987))
+  (import "env" "longname1988" (func $internal1988))
+  (import "env" "longname1989" (func $internal1989))
+  (import "env" "longname1990" (func $internal1990))
+  (import "env" "longname1991" (func $internal1991))
+  (import "env" "longname1992" (func $internal1992))
+  (import "env" "longname1993" (func $internal1993))
+  (import "env" "longname1994" (func $internal1994))
+  (import "env" "longname1995" (func $internal1995))
+  (import "env" "longname1996" (func $internal1996))
+  (import "env" "longname1997" (func $internal1997))
+  (import "env" "longname1998" (func $internal1998))
+  (import "env" "longname1999" (func $internal1999))
+  (import "env" "longname2000" (func $internal2000))
+  (import "env" "longname2001" (func $internal2001))
+  (import "env" "longname2002" (func $internal2002))
+  (import "env" "longname2003" (func $internal2003))
+  (import "env" "longname2004" (func $internal2004))
+  (import "env" "longname2005" (func $internal2005))
+  (import "env" "longname2006" (func $internal2006))
+  (import "env" "longname2007" (func $internal2007))
+  (import "env" "longname2008" (func $internal2008))
+  (import "env" "longname2009" (func $internal2009))
+  (import "env" "longname2010" (func $internal2010))
+  (import "env" "longname2011" (func $internal2011))
+  (import "env" "longname2012" (func $internal2012))
+  (import "env" "longname2013" (func $internal2013))
+  (import "env" "longname2014" (func $internal2014))
+  (import "env" "longname2015" (func $internal2015))
+  (import "env" "longname2016" (func $internal2016))
+  (import "env" "longname2017" (func $internal2017))
+  (import "env" "longname2018" (func $internal2018))
+  (import "env" "longname2019" (func $internal2019))
+  (import "env" "longname2020" (func $internal2020))
+  (import "env" "longname2021" (func $internal2021))
+  (import "env" "longname2022" (func $internal2022))
+  (import "env" "longname2023" (func $internal2023))
+  (import "env" "longname2024" (func $internal2024))
+  (import "env" "longname2025" (func $internal2025))
+  (import "env" "longname2026" (func $internal2026))
+  (import "env" "longname2027" (func $internal2027))
+  (import "env" "longname2028" (func $internal2028))
+  (import "env" "longname2029" (func $internal2029))
+  (import "env" "longname2030" (func $internal2030))
+  (import "env" "longname2031" (func $internal2031))
+  (import "env" "longname2032" (func $internal2032))
+  (import "env" "longname2033" (func $internal2033))
+  (import "env" "longname2034" (func $internal2034))
+  (import "env" "longname2035" (func $internal2035))
+  (import "env" "longname2036" (func $internal2036))
+  (import "env" "longname2037" (func $internal2037))
+  (import "env" "longname2038" (func $internal2038))
+  (import "env" "longname2039" (func $internal2039))
+  (import "env" "longname2040" (func $internal2040))
+  (import "env" "longname2041" (func $internal2041))
+  (import "env" "longname2042" (func $internal2042))
+  (import "env" "longname2043" (func $internal2043))
+  (import "env" "longname2044" (func $internal2044))
+  (import "env" "longname2045" (func $internal2045))
+  (import "env" "longname2046" (func $internal2046))
+  (import "env" "longname2047" (func $internal2047))
+  (import "env" "longname2048" (func $internal2048))
+  (import "env" "longname2049" (func $internal2049))
+  (import "env" "longname2050" (func $internal2050))
+  (import "env" "longname2051" (func $internal2051))
+  (import "env" "longname2052" (func $internal2052))
+  (import "env" "longname2053" (func $internal2053))
+  (import "env" "longname2054" (func $internal2054))
+  (import "env" "longname2055" (func $internal2055))
+  (import "env" "longname2056" (func $internal2056))
+  (import "env" "longname2057" (func $internal2057))
+  (import "env" "longname2058" (func $internal2058))
+  (import "env" "longname2059" (func $internal2059))
+  (import "env" "longname2060" (func $internal2060))
+  (import "env" "longname2061" (func $internal2061))
+  (import "env" "longname2062" (func $internal2062))
+  (import "env" "longname2063" (func $internal2063))
+  (import "env" "longname2064" (func $internal2064))
+  (import "env" "longname2065" (func $internal2065))
+  (import "env" "longname2066" (func $internal2066))
+  (import "env" "longname2067" (func $internal2067))
+  (import "env" "longname2068" (func $internal2068))
+  (import "env" "longname2069" (func $internal2069))
+  (import "env" "longname2070" (func $internal2070))
+  (import "env" "longname2071" (func $internal2071))
+  (import "env" "longname2072" (func $internal2072))
+  (import "env" "longname2073" (func $internal2073))
+  (import "env" "longname2074" (func $internal2074))
+  (import "env" "longname2075" (func $internal2075))
+  (import "env" "longname2076" (func $internal2076))
+  (import "env" "longname2077" (func $internal2077))
+  (import "env" "longname2078" (func $internal2078))
+  (import "env" "longname2079" (func $internal2079))
+  (import "env" "longname2080" (func $internal2080))
+  (import "env" "longname2081" (func $internal2081))
+  (import "env" "longname2082" (func $internal2082))
+  (import "env" "longname2083" (func $internal2083))
+  (import "env" "longname2084" (func $internal2084))
+  (import "env" "longname2085" (func $internal2085))
+  (import "env" "longname2086" (func $internal2086))
+  (import "env" "longname2087" (func $internal2087))
+  (import "env" "longname2088" (func $internal2088))
+  (import "env" "longname2089" (func $internal2089))
+  (import "env" "longname2090" (func $internal2090))
+  (import "env" "longname2091" (func $internal2091))
+  (import "env" "longname2092" (func $internal2092))
+  (import "env" "longname2093" (func $internal2093))
+  (import "env" "longname2094" (func $internal2094))
+  (import "env" "longname2095" (func $internal2095))
+  (import "env" "longname2096" (func $internal2096))
+  (import "env" "longname2097" (func $internal2097))
+  (import "env" "longname2098" (func $internal2098))
+  (import "env" "longname2099" (func $internal2099))
+  (import "env" "longname2100" (func $internal2100))
+  (import "env" "longname2101" (func $internal2101))
+  (import "env" "longname2102" (func $internal2102))
+  (import "env" "longname2103" (func $internal2103))
+  (import "env" "longname2104" (func $internal2104))
+  (import "env" "longname2105" (func $internal2105))
+  (import "env" "longname2106" (func $internal2106))
+  (import "env" "longname2107" (func $internal2107))
+  (import "env" "longname2108" (func $internal2108))
+  (import "env" "longname2109" (func $internal2109))
+  (import "env" "longname2110" (func $internal2110))
+  (import "env" "longname2111" (func $internal2111))
+  (import "env" "longname2112" (func $internal2112))
+  (import "env" "longname2113" (func $internal2113))
+  (import "env" "longname2114" (func $internal2114))
+  (import "env" "longname2115" (func $internal2115))
+  (import "env" "longname2116" (func $internal2116))
+  (import "env" "longname2117" (func $internal2117))
+  (import "env" "longname2118" (func $internal2118))
+  (import "env" "longname2119" (func $internal2119))
+  (import "env" "longname2120" (func $internal2120))
+  (import "env" "longname2121" (func $internal2121))
+  (import "env" "longname2122" (func $internal2122))
+  (import "env" "longname2123" (func $internal2123))
+  (import "env" "longname2124" (func $internal2124))
+  (import "env" "longname2125" (func $internal2125))
+  (import "env" "longname2126" (func $internal2126))
+  (import "env" "longname2127" (func $internal2127))
+  (import "env" "longname2128" (func $internal2128))
+  (import "env" "longname2129" (func $internal2129))
+  (import "env" "longname2130" (func $internal2130))
+  (import "env" "longname2131" (func $internal2131))
+  (import "env" "longname2132" (func $internal2132))
+  (import "env" "longname2133" (func $internal2133))
+  (import "env" "longname2134" (func $internal2134))
+  (import "env" "longname2135" (func $internal2135))
+  (import "env" "longname2136" (func $internal2136))
+  (import "env" "longname2137" (func $internal2137))
+  (import "env" "longname2138" (func $internal2138))
+  (import "env" "longname2139" (func $internal2139))
+  (import "env" "longname2140" (func $internal2140))
+  (import "env" "longname2141" (func $internal2141))
+  (import "env" "longname2142" (func $internal2142))
+  (import "env" "longname2143" (func $internal2143))
+  (import "env" "longname2144" (func $internal2144))
+  (import "env" "longname2145" (func $internal2145))
+  (import "env" "longname2146" (func $internal2146))
+  (import "env" "longname2147" (func $internal2147))
+  (import "env" "longname2148" (func $internal2148))
+  (import "env" "longname2149" (func $internal2149))
+  (import "env" "longname2150" (func $internal2150))
+  (import "env" "longname2151" (func $internal2151))
+  (import "env" "longname2152" (func $internal2152))
+  (import "env" "longname2153" (func $internal2153))
+  (import "env" "longname2154" (func $internal2154))
+  (import "env" "longname2155" (func $internal2155))
+  (import "env" "longname2156" (func $internal2156))
+  (import "env" "longname2157" (func $internal2157))
+  (import "env" "longname2158" (func $internal2158))
+  (import "env" "longname2159" (func $internal2159))
+  (import "env" "longname2160" (func $internal2160))
+  (import "env" "longname2161" (func $internal2161))
+  (import "env" "longname2162" (func $internal2162))
+  (import "env" "longname2163" (func $internal2163))
+  (import "env" "longname2164" (func $internal2164))
+  (import "env" "longname2165" (func $internal2165))
+  (import "env" "longname2166" (func $internal2166))
+  (import "env" "longname2167" (func $internal2167))
+  (import "env" "longname2168" (func $internal2168))
+  (import "env" "longname2169" (func $internal2169))
+  (import "env" "longname2170" (func $internal2170))
+  (import "env" "longname2171" (func $internal2171))
+  (import "env" "longname2172" (func $internal2172))
+  (import "env" "longname2173" (func $internal2173))
+  (import "env" "longname2174" (func $internal2174))
+  (import "env" "longname2175" (func $internal2175))
+  (import "env" "longname2176" (func $internal2176))
+  (import "env" "longname2177" (func $internal2177))
+  (import "env" "longname2178" (func $internal2178))
+  (import "env" "longname2179" (func $internal2179))
+  (import "env" "longname2180" (func $internal2180))
+  (import "env" "longname2181" (func $internal2181))
+  (import "env" "longname2182" (func $internal2182))
+  (import "env" "longname2183" (func $internal2183))
+  (import "env" "longname2184" (func $internal2184))
+  (import "env" "longname2185" (func $internal2185))
+  (import "env" "longname2186" (func $internal2186))
+  (import "env" "longname2187" (func $internal2187))
+  (import "env" "longname2188" (func $internal2188))
+  (import "env" "longname2189" (func $internal2189))
+  (import "env" "longname2190" (func $internal2190))
+  (import "env" "longname2191" (func $internal2191))
+  (import "env" "longname2192" (func $internal2192))
+  (import "env" "longname2193" (func $internal2193))
+  (import "env" "longname2194" (func $internal2194))
+  (import "env" "longname2195" (func $internal2195))
+  (import "env" "longname2196" (func $internal2196))
+  (import "env" "longname2197" (func $internal2197))
+  (import "env" "longname2198" (func $internal2198))
+  (import "env" "longname2199" (func $internal2199))
+  (import "env" "longname2200" (func $internal2200))
+  (import "env" "longname2201" (func $internal2201))
+  (import "env" "longname2202" (func $internal2202))
+  (import "env" "longname2203" (func $internal2203))
+  (import "env" "longname2204" (func $internal2204))
+  (import "env" "longname2205" (func $internal2205))
+  (import "env" "longname2206" (func $internal2206))
+  (import "env" "longname2207" (func $internal2207))
+  (import "env" "longname2208" (func $internal2208))
+  (import "env" "longname2209" (func $internal2209))
+  (import "env" "longname2210" (func $internal2210))
+  (import "env" "longname2211" (func $internal2211))
+  (import "env" "longname2212" (func $internal2212))
+  (import "env" "longname2213" (func $internal2213))
+  (import "env" "longname2214" (func $internal2214))
+  (import "env" "longname2215" (func $internal2215))
+  (import "env" "longname2216" (func $internal2216))
+  (import "env" "longname2217" (func $internal2217))
+  (import "env" "longname2218" (func $internal2218))
+  (import "env" "longname2219" (func $internal2219))
+  (import "env" "longname2220" (func $internal2220))
+  (import "env" "longname2221" (func $internal2221))
+  (import "env" "longname2222" (func $internal2222))
+  (import "env" "longname2223" (func $internal2223))
+  (import "env" "longname2224" (func $internal2224))
+  (import "env" "longname2225" (func $internal2225))
+  (import "env" "longname2226" (func $internal2226))
+  (import "env" "longname2227" (func $internal2227))
+  (import "env" "longname2228" (func $internal2228))
+  (import "env" "longname2229" (func $internal2229))
+  (import "env" "longname2230" (func $internal2230))
+  (import "env" "longname2231" (func $internal2231))
+  (import "env" "longname2232" (func $internal2232))
+  (import "env" "longname2233" (func $internal2233))
+  (import "env" "longname2234" (func $internal2234))
+  (import "env" "longname2235" (func $internal2235))
+  (import "env" "longname2236" (func $internal2236))
+  (import "env" "longname2237" (func $internal2237))
+  (import "env" "longname2238" (func $internal2238))
+  (import "env" "longname2239" (func $internal2239))
+  (import "env" "longname2240" (func $internal2240))
+  (import "env" "longname2241" (func $internal2241))
+  (import "env" "longname2242" (func $internal2242))
+  (import "env" "longname2243" (func $internal2243))
+  (import "env" "longname2244" (func $internal2244))
+  (import "env" "longname2245" (func $internal2245))
+  (import "env" "longname2246" (func $internal2246))
+  (import "env" "longname2247" (func $internal2247))
+  (import "env" "longname2248" (func $internal2248))
+  (import "env" "longname2249" (func $internal2249))
+  (import "env" "longname2250" (func $internal2250))
+  (import "env" "longname2251" (func $internal2251))
+  (import "env" "longname2252" (func $internal2252))
+  (import "env" "longname2253" (func $internal2253))
+  (import "env" "longname2254" (func $internal2254))
+  (import "env" "longname2255" (func $internal2255))
+  (import "env" "longname2256" (func $internal2256))
+  (import "env" "longname2257" (func $internal2257))
+  (import "env" "longname2258" (func $internal2258))
+  (import "env" "longname2259" (func $internal2259))
+  (import "env" "longname2260" (func $internal2260))
+  (import "env" "longname2261" (func $internal2261))
+  (import "env" "longname2262" (func $internal2262))
+  (import "env" "longname2263" (func $internal2263))
+  (import "env" "longname2264" (func $internal2264))
+  (import "env" "longname2265" (func $internal2265))
+  (import "env" "longname2266" (func $internal2266))
+  (import "env" "longname2267" (func $internal2267))
+  (import "env" "longname2268" (func $internal2268))
+  (import "env" "longname2269" (func $internal2269))
+  (import "env" "longname2270" (func $internal2270))
+  (import "env" "longname2271" (func $internal2271))
+  (import "env" "longname2272" (func $internal2272))
+  (import "env" "longname2273" (func $internal2273))
+  (import "env" "longname2274" (func $internal2274))
+  (import "env" "longname2275" (func $internal2275))
+  (import "env" "longname2276" (func $internal2276))
+  (import "env" "longname2277" (func $internal2277))
+  (import "env" "longname2278" (func $internal2278))
+  (import "env" "longname2279" (func $internal2279))
+  (import "env" "longname2280" (func $internal2280))
+  (import "env" "longname2281" (func $internal2281))
+  (import "env" "longname2282" (func $internal2282))
+  (import "env" "longname2283" (func $internal2283))
+  (import "env" "longname2284" (func $internal2284))
+  (import "env" "longname2285" (func $internal2285))
+  (import "env" "longname2286" (func $internal2286))
+  (import "env" "longname2287" (func $internal2287))
+  (import "env" "longname2288" (func $internal2288))
+  (import "env" "longname2289" (func $internal2289))
+  (import "env" "longname2290" (func $internal2290))
+  (import "env" "longname2291" (func $internal2291))
+  (import "env" "longname2292" (func $internal2292))
+  (import "env" "longname2293" (func $internal2293))
+  (import "env" "longname2294" (func $internal2294))
+  (import "env" "longname2295" (func $internal2295))
+  (import "env" "longname2296" (func $internal2296))
+  (import "env" "longname2297" (func $internal2297))
+  (import "env" "longname2298" (func $internal2298))
+  (import "env" "longname2299" (func $internal2299))
+  (import "env" "longname2300" (func $internal2300))
+  (import "env" "longname2301" (func $internal2301))
+  (import "env" "longname2302" (func $internal2302))
+  (import "env" "longname2303" (func $internal2303))
+  (import "env" "longname2304" (func $internal2304))
+  (import "env" "longname2305" (func $internal2305))
+  (import "env" "longname2306" (func $internal2306))
+  (import "env" "longname2307" (func $internal2307))
+  (import "env" "longname2308" (func $internal2308))
+  (import "env" "longname2309" (func $internal2309))
+  (import "env" "longname2310" (func $internal2310))
+  (import "env" "longname2311" (func $internal2311))
+  (import "env" "longname2312" (func $internal2312))
+  (import "env" "longname2313" (func $internal2313))
+  (import "env" "longname2314" (func $internal2314))
+  (import "env" "longname2315" (func $internal2315))
+  (import "env" "longname2316" (func $internal2316))
+  (import "env" "longname2317" (func $internal2317))
+  (import "env" "longname2318" (func $internal2318))
+  (import "env" "longname2319" (func $internal2319))
+  (import "env" "longname2320" (func $internal2320))
+  (import "env" "longname2321" (func $internal2321))
+  (import "env" "longname2322" (func $internal2322))
+  (import "env" "longname2323" (func $internal2323))
+  (import "env" "longname2324" (func $internal2324))
+  (import "env" "longname2325" (func $internal2325))
+  (import "env" "longname2326" (func $internal2326))
+  (import "env" "longname2327" (func $internal2327))
+  (import "env" "longname2328" (func $internal2328))
+  (import "env" "longname2329" (func $internal2329))
+  (import "env" "longname2330" (func $internal2330))
+  (import "env" "longname2331" (func $internal2331))
+  (import "env" "longname2332" (func $internal2332))
+  (import "env" "longname2333" (func $internal2333))
+  (import "env" "longname2334" (func $internal2334))
+  (import "env" "longname2335" (func $internal2335))
+  (import "env" "longname2336" (func $internal2336))
+  (import "env" "longname2337" (func $internal2337))
+  (import "env" "longname2338" (func $internal2338))
+  (import "env" "longname2339" (func $internal2339))
+  (import "env" "longname2340" (func $internal2340))
+  (import "env" "longname2341" (func $internal2341))
+  (import "env" "longname2342" (func $internal2342))
+  (import "env" "longname2343" (func $internal2343))
+  (import "env" "longname2344" (func $internal2344))
+  (import "env" "longname2345" (func $internal2345))
+  (import "env" "longname2346" (func $internal2346))
+  (import "env" "longname2347" (func $internal2347))
+  (import "env" "longname2348" (func $internal2348))
+  (import "env" "longname2349" (func $internal2349))
+  (import "env" "longname2350" (func $internal2350))
+  (import "env" "longname2351" (func $internal2351))
+  (import "env" "longname2352" (func $internal2352))
+  (import "env" "longname2353" (func $internal2353))
+  (import "env" "longname2354" (func $internal2354))
+  (import "env" "longname2355" (func $internal2355))
+  (import "env" "longname2356" (func $internal2356))
+  (import "env" "longname2357" (func $internal2357))
+  (import "env" "longname2358" (func $internal2358))
+  (import "env" "longname2359" (func $internal2359))
+  (import "env" "longname2360" (func $internal2360))
+  (import "env" "longname2361" (func $internal2361))
+  (import "env" "longname2362" (func $internal2362))
+  (import "env" "longname2363" (func $internal2363))
+  (import "env" "longname2364" (func $internal2364))
+  (import "env" "longname2365" (func $internal2365))
+  (import "env" "longname2366" (func $internal2366))
+  (import "env" "longname2367" (func $internal2367))
+  (import "env" "longname2368" (func $internal2368))
+  (import "env" "longname2369" (func $internal2369))
+  (import "env" "longname2370" (func $internal2370))
+  (import "env" "longname2371" (func $internal2371))
+  (import "env" "longname2372" (func $internal2372))
+  (import "env" "longname2373" (func $internal2373))
+  (import "env" "longname2374" (func $internal2374))
+  (import "env" "longname2375" (func $internal2375))
+  (import "env" "longname2376" (func $internal2376))
+  (import "env" "longname2377" (func $internal2377))
+  (import "env" "longname2378" (func $internal2378))
+  (import "env" "longname2379" (func $internal2379))
+  (import "env" "longname2380" (func $internal2380))
+  (import "env" "longname2381" (func $internal2381))
+  (import "env" "longname2382" (func $internal2382))
+  (import "env" "longname2383" (func $internal2383))
+  (import "env" "longname2384" (func $internal2384))
+  (import "env" "longname2385" (func $internal2385))
+  (import "env" "longname2386" (func $internal2386))
+  (import "env" "longname2387" (func $internal2387))
+  (import "env" "longname2388" (func $internal2388))
+  (import "env" "longname2389" (func $internal2389))
+  (import "env" "longname2390" (func $internal2390))
+  (import "env" "longname2391" (func $internal2391))
+  (import "env" "longname2392" (func $internal2392))
+  (import "env" "longname2393" (func $internal2393))
+  (import "env" "longname2394" (func $internal2394))
+  (import "env" "longname2395" (func $internal2395))
+  (import "env" "longname2396" (func $internal2396))
+  (import "env" "longname2397" (func $internal2397))
+  (import "env" "longname2398" (func $internal2398))
+  (import "env" "longname2399" (func $internal2399))
+  (import "env" "longname2400" (func $internal2400))
+  (import "env" "longname2401" (func $internal2401))
+  (import "env" "longname2402" (func $internal2402))
+  (import "env" "longname2403" (func $internal2403))
+  (import "env" "longname2404" (func $internal2404))
+  (import "env" "longname2405" (func $internal2405))
+  (import "env" "longname2406" (func $internal2406))
+  (import "env" "longname2407" (func $internal2407))
+  (import "env" "longname2408" (func $internal2408))
+  (import "env" "longname2409" (func $internal2409))
+  (import "env" "longname2410" (func $internal2410))
+  (import "env" "longname2411" (func $internal2411))
+  (import "env" "longname2412" (func $internal2412))
+  (import "env" "longname2413" (func $internal2413))
+  (import "env" "longname2414" (func $internal2414))
+  (import "env" "longname2415" (func $internal2415))
+  (import "env" "longname2416" (func $internal2416))
+  (import "env" "longname2417" (func $internal2417))
+  (import "env" "longname2418" (func $internal2418))
+  (import "env" "longname2419" (func $internal2419))
+  (import "env" "longname2420" (func $internal2420))
+  (import "env" "longname2421" (func $internal2421))
+  (import "env" "longname2422" (func $internal2422))
+  (import "env" "longname2423" (func $internal2423))
+  (import "env" "longname2424" (func $internal2424))
+  (import "env" "longname2425" (func $internal2425))
+  (import "env" "longname2426" (func $internal2426))
+  (import "env" "longname2427" (func $internal2427))
+  (import "env" "longname2428" (func $internal2428))
+  (import "env" "longname2429" (func $internal2429))
+  (import "env" "longname2430" (func $internal2430))
+  (import "env" "longname2431" (func $internal2431))
+  (import "env" "longname2432" (func $internal2432))
+  (import "env" "longname2433" (func $internal2433))
+  (import "env" "longname2434" (func $internal2434))
+  (import "env" "longname2435" (func $internal2435))
+  (import "env" "longname2436" (func $internal2436))
+  (import "env" "longname2437" (func $internal2437))
+  (import "env" "longname2438" (func $internal2438))
+  (import "env" "longname2439" (func $internal2439))
+  (import "env" "longname2440" (func $internal2440))
+  (import "env" "longname2441" (func $internal2441))
+  (import "env" "longname2442" (func $internal2442))
+  (import "env" "longname2443" (func $internal2443))
+  (import "env" "longname2444" (func $internal2444))
+  (import "env" "longname2445" (func $internal2445))
+  (import "env" "longname2446" (func $internal2446))
+  (import "env" "longname2447" (func $internal2447))
+  (import "env" "longname2448" (func $internal2448))
+  (import "env" "longname2449" (func $internal2449))
+  (import "env" "longname2450" (func $internal2450))
+  (import "env" "longname2451" (func $internal2451))
+  (import "env" "longname2452" (func $internal2452))
+  (import "env" "longname2453" (func $internal2453))
+  (import "env" "longname2454" (func $internal2454))
+  (import "env" "longname2455" (func $internal2455))
+  (import "env" "longname2456" (func $internal2456))
+  (import "env" "longname2457" (func $internal2457))
+  (import "env" "longname2458" (func $internal2458))
+  (import "env" "longname2459" (func $internal2459))
+  (import "env" "longname2460" (func $internal2460))
+  (import "env" "longname2461" (func $internal2461))
+  (import "env" "longname2462" (func $internal2462))
+  (import "env" "longname2463" (func $internal2463))
+  (import "env" "longname2464" (func $internal2464))
+  (import "env" "longname2465" (func $internal2465))
+  (import "env" "longname2466" (func $internal2466))
+  (import "env" "longname2467" (func $internal2467))
+  (import "env" "longname2468" (func $internal2468))
+  (import "env" "longname2469" (func $internal2469))
+  (import "env" "longname2470" (func $internal2470))
+  (import "env" "longname2471" (func $internal2471))
+  (import "env" "longname2472" (func $internal2472))
+  (import "env" "longname2473" (func $internal2473))
+  (import "env" "longname2474" (func $internal2474))
+  (import "env" "longname2475" (func $internal2475))
+  (import "env" "longname2476" (func $internal2476))
+  (import "env" "longname2477" (func $internal2477))
+  (import "env" "longname2478" (func $internal2478))
+  (import "env" "longname2479" (func $internal2479))
+  (import "env" "longname2480" (func $internal2480))
+  (import "env" "longname2481" (func $internal2481))
+  (import "env" "longname2482" (func $internal2482))
+  (import "env" "longname2483" (func $internal2483))
+  (import "env" "longname2484" (func $internal2484))
+  (import "env" "longname2485" (func $internal2485))
+  (import "env" "longname2486" (func $internal2486))
+  (import "env" "longname2487" (func $internal2487))
+  (import "env" "longname2488" (func $internal2488))
+  (import "env" "longname2489" (func $internal2489))
+  (import "env" "longname2490" (func $internal2490))
+  (import "env" "longname2491" (func $internal2491))
+  (import "env" "longname2492" (func $internal2492))
+  (import "env" "longname2493" (func $internal2493))
+  (import "env" "longname2494" (func $internal2494))
+  (import "env" "longname2495" (func $internal2495))
+  (import "env" "longname2496" (func $internal2496))
+  (import "env" "longname2497" (func $internal2497))
+  (import "env" "longname2498" (func $internal2498))
+  (import "env" "longname2499" (func $internal2499))
+  (import "env" "longname2500" (func $internal2500))
+  (import "env" "longname2501" (func $internal2501))
+  (import "env" "longname2502" (func $internal2502))
+  (import "env" "longname2503" (func $internal2503))
+  (import "env" "longname2504" (func $internal2504))
+  (import "env" "longname2505" (func $internal2505))
+  (import "env" "longname2506" (func $internal2506))
+  (import "env" "longname2507" (func $internal2507))
+  (import "env" "longname2508" (func $internal2508))
+  (import "env" "longname2509" (func $internal2509))
+  (import "env" "longname2510" (func $internal2510))
+  (import "env" "longname2511" (func $internal2511))
+  (import "env" "longname2512" (func $internal2512))
+  (import "env" "longname2513" (func $internal2513))
+  (import "env" "longname2514" (func $internal2514))
+  (import "env" "longname2515" (func $internal2515))
+  (import "env" "longname2516" (func $internal2516))
+  (import "env" "longname2517" (func $internal2517))
+  (import "env" "longname2518" (func $internal2518))
+  (import "env" "longname2519" (func $internal2519))
+  (import "env" "longname2520" (func $internal2520))
+  (import "env" "longname2521" (func $internal2521))
+  (import "env" "longname2522" (func $internal2522))
+  (import "env" "longname2523" (func $internal2523))
+  (import "env" "longname2524" (func $internal2524))
+  (import "env" "longname2525" (func $internal2525))
+  (import "env" "longname2526" (func $internal2526))
+  (import "env" "longname2527" (func $internal2527))
+  (import "env" "longname2528" (func $internal2528))
+  (import "env" "longname2529" (func $internal2529))
+  (import "env" "longname2530" (func $internal2530))
+  (import "env" "longname2531" (func $internal2531))
+  (import "env" "longname2532" (func $internal2532))
+  (import "env" "longname2533" (func $internal2533))
+  (import "env" "longname2534" (func $internal2534))
+  (import "env" "longname2535" (func $internal2535))
+  (import "env" "longname2536" (func $internal2536))
+  (import "env" "longname2537" (func $internal2537))
+  (import "env" "longname2538" (func $internal2538))
+  (import "env" "longname2539" (func $internal2539))
+  (import "env" "longname2540" (func $internal2540))
+  (import "env" "longname2541" (func $internal2541))
+  (import "env" "longname2542" (func $internal2542))
+  (import "env" "longname2543" (func $internal2543))
+  (import "env" "longname2544" (func $internal2544))
+  (import "env" "longname2545" (func $internal2545))
+  (import "env" "longname2546" (func $internal2546))
+  (import "env" "longname2547" (func $internal2547))
+  (import "env" "longname2548" (func $internal2548))
+  (import "env" "longname2549" (func $internal2549))
+  (import "env" "longname2550" (func $internal2550))
+  (import "env" "longname2551" (func $internal2551))
+  (import "env" "longname2552" (func $internal2552))
+  (import "env" "longname2553" (func $internal2553))
+  (import "env" "longname2554" (func $internal2554))
+  (import "env" "longname2555" (func $internal2555))
+  (import "env" "longname2556" (func $internal2556))
+  (import "env" "longname2557" (func $internal2557))
+  (import "env" "longname2558" (func $internal2558))
+  (import "env" "longname2559" (func $internal2559))
+  (import "env" "longname2560" (func $internal2560))
+  (import "env" "longname2561" (func $internal2561))
+  (import "env" "longname2562" (func $internal2562))
+  (import "env" "longname2563" (func $internal2563))
+  (import "env" "longname2564" (func $internal2564))
+  (import "env" "longname2565" (func $internal2565))
+  (import "env" "longname2566" (func $internal2566))
+  (import "env" "longname2567" (func $internal2567))
+  (import "env" "longname2568" (func $internal2568))
+  (import "env" "longname2569" (func $internal2569))
+  (import "env" "longname2570" (func $internal2570))
+  (import "env" "longname2571" (func $internal2571))
+  (import "env" "longname2572" (func $internal2572))
+  (import "env" "longname2573" (func $internal2573))
+  (import "env" "longname2574" (func $internal2574))
+  (import "env" "longname2575" (func $internal2575))
+  (import "env" "longname2576" (func $internal2576))
+  (import "env" "longname2577" (func $internal2577))
+  (import "env" "longname2578" (func $internal2578))
+  (import "env" "longname2579" (func $internal2579))
+  (import "env" "longname2580" (func $internal2580))
+  (import "env" "longname2581" (func $internal2581))
+  (import "env" "longname2582" (func $internal2582))
+  (import "env" "longname2583" (func $internal2583))
+  (import "env" "longname2584" (func $internal2584))
+  (import "env" "longname2585" (func $internal2585))
+  (import "env" "longname2586" (func $internal2586))
+  (import "env" "longname2587" (func $internal2587))
+  (import "env" "longname2588" (func $internal2588))
+  (import "env" "longname2589" (func $internal2589))
+  (import "env" "longname2590" (func $internal2590))
+  (import "env" "longname2591" (func $internal2591))
+  (import "env" "longname2592" (func $internal2592))
+  (import "env" "longname2593" (func $internal2593))
+  (import "env" "longname2594" (func $internal2594))
+  (import "env" "longname2595" (func $internal2595))
+  (import "env" "longname2596" (func $internal2596))
+  (import "env" "longname2597" (func $internal2597))
+  (import "env" "longname2598" (func $internal2598))
+  (import "env" "longname2599" (func $internal2599))
+  (import "env" "longname2600" (func $internal2600))
+  (import "env" "longname2601" (func $internal2601))
+  (import "env" "longname2602" (func $internal2602))
+  (import "env" "longname2603" (func $internal2603))
+  (import "env" "longname2604" (func $internal2604))
+  (import "env" "longname2605" (func $internal2605))
+  (import "env" "longname2606" (func $internal2606))
+  (import "env" "longname2607" (func $internal2607))
+  (import "env" "longname2608" (func $internal2608))
+  (import "env" "longname2609" (func $internal2609))
+  (import "env" "longname2610" (func $internal2610))
+  (import "env" "longname2611" (func $internal2611))
+  (import "env" "longname2612" (func $internal2612))
+  (import "env" "longname2613" (func $internal2613))
+  (import "env" "longname2614" (func $internal2614))
+  (import "env" "longname2615" (func $internal2615))
+  (import "env" "longname2616" (func $internal2616))
+  (import "env" "longname2617" (func $internal2617))
+  (import "env" "longname2618" (func $internal2618))
+  (import "env" "longname2619" (func $internal2619))
+  (import "env" "longname2620" (func $internal2620))
+  (import "env" "longname2621" (func $internal2621))
+  (import "env" "longname2622" (func $internal2622))
+  (import "env" "longname2623" (func $internal2623))
+  (import "env" "longname2624" (func $internal2624))
+  (import "env" "longname2625" (func $internal2625))
+  (import "env" "longname2626" (func $internal2626))
+  (import "env" "longname2627" (func $internal2627))
+  (import "env" "longname2628" (func $internal2628))
+  (import "env" "longname2629" (func $internal2629))
+  (import "env" "longname2630" (func $internal2630))
+  (import "env" "longname2631" (func $internal2631))
+  (import "env" "longname2632" (func $internal2632))
+  (import "env" "longname2633" (func $internal2633))
+  (import "env" "longname2634" (func $internal2634))
+  (import "env" "longname2635" (func $internal2635))
+  (import "env" "longname2636" (func $internal2636))
+  (import "env" "longname2637" (func $internal2637))
+  (import "env" "longname2638" (func $internal2638))
+  (import "env" "longname2639" (func $internal2639))
+  (import "env" "longname2640" (func $internal2640))
+  (import "env" "longname2641" (func $internal2641))
+  (import "env" "longname2642" (func $internal2642))
+  (import "env" "longname2643" (func $internal2643))
+  (import "env" "longname2644" (func $internal2644))
+  (import "env" "longname2645" (func $internal2645))
+  (import "env" "longname2646" (func $internal2646))
+  (import "env" "longname2647" (func $internal2647))
+  (import "env" "longname2648" (func $internal2648))
+  (import "env" "longname2649" (func $internal2649))
+  (import "env" "longname2650" (func $internal2650))
+  (import "env" "longname2651" (func $internal2651))
+  (import "env" "longname2652" (func $internal2652))
+  (import "env" "longname2653" (func $internal2653))
+  (import "env" "longname2654" (func $internal2654))
+  (import "env" "longname2655" (func $internal2655))
+  (import "env" "longname2656" (func $internal2656))
+  (import "env" "longname2657" (func $internal2657))
+  (import "env" "longname2658" (func $internal2658))
+  (import "env" "longname2659" (func $internal2659))
+  (import "env" "longname2660" (func $internal2660))
+  (import "env" "longname2661" (func $internal2661))
+  (import "env" "longname2662" (func $internal2662))
+  (import "env" "longname2663" (func $internal2663))
+  (import "env" "longname2664" (func $internal2664))
+  (import "env" "longname2665" (func $internal2665))
+  (import "env" "longname2666" (func $internal2666))
+  (import "env" "longname2667" (func $internal2667))
+  (import "env" "longname2668" (func $internal2668))
+  (import "env" "longname2669" (func $internal2669))
+  (import "env" "longname2670" (func $internal2670))
+  (import "env" "longname2671" (func $internal2671))
+  (import "env" "longname2672" (func $internal2672))
+  (import "env" "longname2673" (func $internal2673))
+  (import "env" "longname2674" (func $internal2674))
+  (import "env" "longname2675" (func $internal2675))
+  (import "env" "longname2676" (func $internal2676))
+  (import "env" "longname2677" (func $internal2677))
+  (import "env" "longname2678" (func $internal2678))
+  (import "env" "longname2679" (func $internal2679))
+  (import "env" "longname2680" (func $internal2680))
+  (import "env" "longname2681" (func $internal2681))
+  (import "env" "longname2682" (func $internal2682))
+  (import "env" "longname2683" (func $internal2683))
+  (import "env" "longname2684" (func $internal2684))
+  (import "env" "longname2685" (func $internal2685))
+  (import "env" "longname2686" (func $internal2686))
+  (import "env" "longname2687" (func $internal2687))
+  (import "env" "longname2688" (func $internal2688))
+  (import "env" "longname2689" (func $internal2689))
+  (import "env" "longname2690" (func $internal2690))
+  (import "env" "longname2691" (func $internal2691))
+  (import "env" "longname2692" (func $internal2692))
+  (import "env" "longname2693" (func $internal2693))
+  (import "env" "longname2694" (func $internal2694))
+  (import "env" "longname2695" (func $internal2695))
+  (import "env" "longname2696" (func $internal2696))
+  (import "env" "longname2697" (func $internal2697))
+  (import "env" "longname2698" (func $internal2698))
+  (import "env" "longname2699" (func $internal2699))
+  (import "env" "longname2700" (func $internal2700))
+  (import "env" "longname2701" (func $internal2701))
+  (import "env" "longname2702" (func $internal2702))
+  (import "env" "longname2703" (func $internal2703))
+  (import "env" "longname2704" (func $internal2704))
+  (import "env" "longname2705" (func $internal2705))
+  (import "env" "longname2706" (func $internal2706))
+  (import "env" "longname2707" (func $internal2707))
+  (import "env" "longname2708" (func $internal2708))
+  (import "env" "longname2709" (func $internal2709))
+  (import "env" "longname2710" (func $internal2710))
+  (import "env" "longname2711" (func $internal2711))
+  (import "env" "longname2712" (func $internal2712))
+  (import "env" "longname2713" (func $internal2713))
+  (import "env" "longname2714" (func $internal2714))
+  (import "env" "longname2715" (func $internal2715))
+  (import "env" "longname2716" (func $internal2716))
+  (import "env" "longname2717" (func $internal2717))
+  (import "env" "longname2718" (func $internal2718))
+  (import "env" "longname2719" (func $internal2719))
+  (import "env" "longname2720" (func $internal2720))
+  (import "env" "longname2721" (func $internal2721))
+  (import "env" "longname2722" (func $internal2722))
+  (import "env" "longname2723" (func $internal2723))
+  (import "env" "longname2724" (func $internal2724))
+  (import "env" "longname2725" (func $internal2725))
+  (import "env" "longname2726" (func $internal2726))
+  (import "env" "longname2727" (func $internal2727))
+  (import "env" "longname2728" (func $internal2728))
+  (import "env" "longname2729" (func $internal2729))
+  (import "env" "longname2730" (func $internal2730))
+  (import "env" "longname2731" (func $internal2731))
+  (import "env" "longname2732" (func $internal2732))
+  (import "env" "longname2733" (func $internal2733))
+  (import "env" "longname2734" (func $internal2734))
+  (import "env" "longname2735" (func $internal2735))
+  (import "env" "longname2736" (func $internal2736))
+  (import "env" "longname2737" (func $internal2737))
+  (import "env" "longname2738" (func $internal2738))
+  (import "env" "longname2739" (func $internal2739))
+  (import "env" "longname2740" (func $internal2740))
+  (import "env" "longname2741" (func $internal2741))
+  (import "env" "longname2742" (func $internal2742))
+  (import "env" "longname2743" (func $internal2743))
+  (import "env" "longname2744" (func $internal2744))
+  (import "env" "longname2745" (func $internal2745))
+  (import "env" "longname2746" (func $internal2746))
+  (import "env" "longname2747" (func $internal2747))
+  (import "env" "longname2748" (func $internal2748))
+  (import "env" "longname2749" (func $internal2749))
+  (import "env" "longname2750" (func $internal2750))
+  (import "env" "longname2751" (func $internal2751))
+  (import "env" "longname2752" (func $internal2752))
+  (import "env" "longname2753" (func $internal2753))
+  (import "env" "longname2754" (func $internal2754))
+  (import "env" "longname2755" (func $internal2755))
+  (import "env" "longname2756" (func $internal2756))
+  (import "env" "longname2757" (func $internal2757))
+  (import "env" "longname2758" (func $internal2758))
+  (import "env" "longname2759" (func $internal2759))
+  (import "env" "longname2760" (func $internal2760))
+  (import "env" "longname2761" (func $internal2761))
+  (import "env" "longname2762" (func $internal2762))
+  (import "env" "longname2763" (func $internal2763))
+  (import "env" "longname2764" (func $internal2764))
+  (import "env" "longname2765" (func $internal2765))
+  (import "env" "longname2766" (func $internal2766))
+  (import "env" "longname2767" (func $internal2767))
+  (import "env" "longname2768" (func $internal2768))
+  (import "env" "longname2769" (func $internal2769))
+  (import "env" "longname2770" (func $internal2770))
+  (import "env" "longname2771" (func $internal2771))
+  (import "env" "longname2772" (func $internal2772))
+  (import "env" "longname2773" (func $internal2773))
+  (import "env" "longname2774" (func $internal2774))
+  (import "env" "longname2775" (func $internal2775))
+  (import "env" "longname2776" (func $internal2776))
+  (import "env" "longname2777" (func $internal2777))
+  (import "env" "longname2778" (func $internal2778))
+  (import "env" "longname2779" (func $internal2779))
+  (import "env" "longname2780" (func $internal2780))
+  (import "env" "longname2781" (func $internal2781))
+  (import "env" "longname2782" (func $internal2782))
+  (import "env" "longname2783" (func $internal2783))
+  (import "env" "longname2784" (func $internal2784))
+  (import "env" "longname2785" (func $internal2785))
+  (import "env" "longname2786" (func $internal2786))
+  (import "env" "longname2787" (func $internal2787))
+  (import "env" "longname2788" (func $internal2788))
+  (import "env" "longname2789" (func $internal2789))
+  (import "env" "longname2790" (func $internal2790))
+  (import "env" "longname2791" (func $internal2791))
+  (import "env" "longname2792" (func $internal2792))
+  (import "env" "longname2793" (func $internal2793))
+  (import "env" "longname2794" (func $internal2794))
+  (import "env" "longname2795" (func $internal2795))
+  (import "env" "longname2796" (func $internal2796))
+  (import "env" "longname2797" (func $internal2797))
+  (import "env" "longname2798" (func $internal2798))
+  (import "env" "longname2799" (func $internal2799))
+  (import "env" "longname2800" (func $internal2800))
+  (import "env" "longname2801" (func $internal2801))
+  (import "env" "longname2802" (func $internal2802))
+  (import "env" "longname2803" (func $internal2803))
+  (import "env" "longname2804" (func $internal2804))
+  (import "env" "longname2805" (func $internal2805))
+  (import "env" "longname2806" (func $internal2806))
+  (import "env" "longname2807" (func $internal2807))
+  (import "env" "longname2808" (func $internal2808))
+  (import "env" "longname2809" (func $internal2809))
+  (import "env" "longname2810" (func $internal2810))
+  (import "env" "longname2811" (func $internal2811))
+  (import "env" "longname2812" (func $internal2812))
+  (import "env" "longname2813" (func $internal2813))
+  (import "env" "longname2814" (func $internal2814))
+  (import "env" "longname2815" (func $internal2815))
+  (import "env" "longname2816" (func $internal2816))
+  (import "env" "longname2817" (func $internal2817))
+  (import "env" "longname2818" (func $internal2818))
+  (import "env" "longname2819" (func $internal2819))
+  (import "env" "longname2820" (func $internal2820))
+  (import "env" "longname2821" (func $internal2821))
+  (import "env" "longname2822" (func $internal2822))
+  (import "env" "longname2823" (func $internal2823))
+  (import "env" "longname2824" (func $internal2824))
+  (import "env" "longname2825" (func $internal2825))
+  (import "env" "longname2826" (func $internal2826))
+  (import "env" "longname2827" (func $internal2827))
+  (import "env" "longname2828" (func $internal2828))
+  (import "env" "longname2829" (func $internal2829))
+  (import "env" "longname2830" (func $internal2830))
+  (import "env" "longname2831" (func $internal2831))
+  (import "env" "longname2832" (func $internal2832))
+  (import "env" "longname2833" (func $internal2833))
+  (import "env" "longname2834" (func $internal2834))
+  (import "env" "longname2835" (func $internal2835))
+  (import "env" "longname2836" (func $internal2836))
+  (import "env" "longname2837" (func $internal2837))
+  (import "env" "longname2838" (func $internal2838))
+  (import "env" "longname2839" (func $internal2839))
+  (import "env" "longname2840" (func $internal2840))
+  (import "env" "longname2841" (func $internal2841))
+  (import "env" "longname2842" (func $internal2842))
+  (import "env" "longname2843" (func $internal2843))
+  (import "env" "longname2844" (func $internal2844))
+  (import "env" "longname2845" (func $internal2845))
+  (import "env" "longname2846" (func $internal2846))
+  (import "env" "longname2847" (func $internal2847))
+  (import "env" "longname2848" (func $internal2848))
+  (import "env" "longname2849" (func $internal2849))
+  (import "env" "longname2850" (func $internal2850))
+  (import "env" "longname2851" (func $internal2851))
+  (import "env" "longname2852" (func $internal2852))
+  (import "env" "longname2853" (func $internal2853))
+  (import "env" "longname2854" (func $internal2854))
+  (import "env" "longname2855" (func $internal2855))
+  (import "env" "longname2856" (func $internal2856))
+  (import "env" "longname2857" (func $internal2857))
+  (import "env" "longname2858" (func $internal2858))
+  (import "env" "longname2859" (func $internal2859))
+  (import "env" "longname2860" (func $internal2860))
+  (import "env" "longname2861" (func $internal2861))
+  (import "env" "longname2862" (func $internal2862))
+  (import "env" "longname2863" (func $internal2863))
+  (import "env" "longname2864" (func $internal2864))
+  (import "env" "longname2865" (func $internal2865))
+  (import "env" "longname2866" (func $internal2866))
+  (import "env" "longname2867" (func $internal2867))
+  (import "env" "longname2868" (func $internal2868))
+  (import "env" "longname2869" (func $internal2869))
+  (import "env" "longname2870" (func $internal2870))
+  (import "env" "longname2871" (func $internal2871))
+  (import "env" "longname2872" (func $internal2872))
+  (import "env" "longname2873" (func $internal2873))
+  (import "env" "longname2874" (func $internal2874))
+  (import "env" "longname2875" (func $internal2875))
+  (import "env" "longname2876" (func $internal2876))
+  (import "env" "longname2877" (func $internal2877))
+  (import "env" "longname2878" (func $internal2878))
+  (import "env" "longname2879" (func $internal2879))
+  (import "env" "longname2880" (func $internal2880))
+  (import "env" "longname2881" (func $internal2881))
+  (import "env" "longname2882" (func $internal2882))
+  (import "env" "longname2883" (func $internal2883))
+  (import "env" "longname2884" (func $internal2884))
+  (import "env" "longname2885" (func $internal2885))
+  (import "env" "longname2886" (func $internal2886))
+  (import "env" "longname2887" (func $internal2887))
+  (import "env" "longname2888" (func $internal2888))
+  (import "env" "longname2889" (func $internal2889))
+  (import "env" "longname2890" (func $internal2890))
+  (import "env" "longname2891" (func $internal2891))
+  (import "env" "longname2892" (func $internal2892))
+  (import "env" "longname2893" (func $internal2893))
+  (import "env" "longname2894" (func $internal2894))
+  (import "env" "longname2895" (func $internal2895))
+  (import "env" "longname2896" (func $internal2896))
+  (import "env" "longname2897" (func $internal2897))
+  (import "env" "longname2898" (func $internal2898))
+  (import "env" "longname2899" (func $internal2899))
+  (import "env" "longname2900" (func $internal2900))
+  (import "env" "longname2901" (func $internal2901))
+  (import "env" "longname2902" (func $internal2902))
+  (import "env" "longname2903" (func $internal2903))
+  (import "env" "longname2904" (func $internal2904))
+  (import "env" "longname2905" (func $internal2905))
+  (import "env" "longname2906" (func $internal2906))
+  (import "env" "longname2907" (func $internal2907))
+  (import "env" "longname2908" (func $internal2908))
+  (import "env" "longname2909" (func $internal2909))
+  (import "env" "longname2910" (func $internal2910))
+  (import "env" "longname2911" (func $internal2911))
+  (import "env" "longname2912" (func $internal2912))
+  (import "env" "longname2913" (func $internal2913))
+  (import "env" "longname2914" (func $internal2914))
+  (import "env" "longname2915" (func $internal2915))
+  (import "env" "longname2916" (func $internal2916))
+  (import "env" "longname2917" (func $internal2917))
+  (import "env" "longname2918" (func $internal2918))
+  (import "env" "longname2919" (func $internal2919))
+  (import "env" "longname2920" (func $internal2920))
+  (import "env" "longname2921" (func $internal2921))
+  (import "env" "longname2922" (func $internal2922))
+  (import "env" "longname2923" (func $internal2923))
+  (import "env" "longname2924" (func $internal2924))
+  (import "env" "longname2925" (func $internal2925))
+  (import "env" "longname2926" (func $internal2926))
+  (import "env" "longname2927" (func $internal2927))
+  (import "env" "longname2928" (func $internal2928))
+  (import "env" "longname2929" (func $internal2929))
+  (import "env" "longname2930" (func $internal2930))
+  (import "env" "longname2931" (func $internal2931))
+  (import "env" "longname2932" (func $internal2932))
+  (import "env" "longname2933" (func $internal2933))
+  (import "env" "longname2934" (func $internal2934))
+  (import "env" "longname2935" (func $internal2935))
+  (import "env" "longname2936" (func $internal2936))
+  (import "env" "longname2937" (func $internal2937))
+  (import "env" "longname2938" (func $internal2938))
+  (import "env" "longname2939" (func $internal2939))
+  (import "env" "longname2940" (func $internal2940))
+  (import "env" "longname2941" (func $internal2941))
+  (import "env" "longname2942" (func $internal2942))
+  (import "env" "longname2943" (func $internal2943))
+  (import "env" "longname2944" (func $internal2944))
+  (import "env" "longname2945" (func $internal2945))
+  (import "env" "longname2946" (func $internal2946))
+  (import "env" "longname2947" (func $internal2947))
+  (import "env" "longname2948" (func $internal2948))
+  (import "env" "longname2949" (func $internal2949))
+  (import "env" "longname2950" (func $internal2950))
+  (import "env" "longname2951" (func $internal2951))
+  (import "env" "longname2952" (func $internal2952))
+  (import "env" "longname2953" (func $internal2953))
+  (import "env" "longname2954" (func $internal2954))
+  (import "env" "longname2955" (func $internal2955))
+  (import "env" "longname2956" (func $internal2956))
+  (import "env" "longname2957" (func $internal2957))
+  (import "env" "longname2958" (func $internal2958))
+  (import "env" "longname2959" (func $internal2959))
+  (import "env" "longname2960" (func $internal2960))
+  (import "env" "longname2961" (func $internal2961))
+  (import "env" "longname2962" (func $internal2962))
+  (import "env" "longname2963" (func $internal2963))
+  (import "env" "longname2964" (func $internal2964))
+  (import "env" "longname2965" (func $internal2965))
+  (import "env" "longname2966" (func $internal2966))
+  (import "env" "longname2967" (func $internal2967))
+  (import "env" "longname2968" (func $internal2968))
+  (import "env" "longname2969" (func $internal2969))
+  (import "env" "longname2970" (func $internal2970))
+  (import "env" "longname2971" (func $internal2971))
+  (import "env" "longname2972" (func $internal2972))
+  (import "env" "longname2973" (func $internal2973))
+  (import "env" "longname2974" (func $internal2974))
+  (import "env" "longname2975" (func $internal2975))
+  (import "env" "longname2976" (func $internal2976))
+  (import "env" "longname2977" (func $internal2977))
+  (import "env" "longname2978" (func $internal2978))
+  (import "env" "longname2979" (func $internal2979))
+  (import "env" "longname2980" (func $internal2980))
+  (import "env" "longname2981" (func $internal2981))
+  (import "env" "longname2982" (func $internal2982))
+  (import "env" "longname2983" (func $internal2983))
+  (import "env" "longname2984" (func $internal2984))
+  (import "env" "longname2985" (func $internal2985))
+  (import "env" "longname2986" (func $internal2986))
+  (import "env" "longname2987" (func $internal2987))
+  (import "env" "longname2988" (func $internal2988))
+  (import "env" "longname2989" (func $internal2989))
+  (import "env" "longname2990" (func $internal2990))
+  (import "env" "longname2991" (func $internal2991))
+  (import "env" "longname2992" (func $internal2992))
+  (import "env" "longname2993" (func $internal2993))
+  (import "env" "longname2994" (func $internal2994))
+  (import "env" "longname2995" (func $internal2995))
+  (import "env" "longname2996" (func $internal2996))
+  (import "env" "longname2997" (func $internal2997))
+  (import "env" "longname2998" (func $internal2998))
+  (import "env" "longname2999" (func $internal2999))
+  (import "env" "longname3000" (func $internal3000))
+  (import "env" "longname3001" (func $internal3001))
+  (import "env" "longname3002" (func $internal3002))
+  (import "env" "longname3003" (func $internal3003))
+  (import "env" "longname3004" (func $internal3004))
+  (import "env" "longname3005" (func $internal3005))
+  (import "env" "longname3006" (func $internal3006))
+  (import "env" "longname3007" (func $internal3007))
+  (import "env" "longname3008" (func $internal3008))
+  (import "env" "longname3009" (func $internal3009))
+  (import "env" "longname3010" (func $internal3010))
+  (import "env" "longname3011" (func $internal3011))
+  (import "env" "longname3012" (func $internal3012))
+  (import "env" "longname3013" (func $internal3013))
+  (import "env" "longname3014" (func $internal3014))
+  (import "env" "longname3015" (func $internal3015))
+  (import "env" "longname3016" (func $internal3016))
+  (import "env" "longname3017" (func $internal3017))
+  (import "env" "longname3018" (func $internal3018))
+  (import "env" "longname3019" (func $internal3019))
+  (import "env" "longname3020" (func $internal3020))
+  (import "env" "longname3021" (func $internal3021))
+  (import "env" "longname3022" (func $internal3022))
+  (import "env" "longname3023" (func $internal3023))
+  (import "env" "longname3024" (func $internal3024))
+  (import "env" "longname3025" (func $internal3025))
+  (import "env" "longname3026" (func $internal3026))
+  (import "env" "longname3027" (func $internal3027))
+  (import "env" "longname3028" (func $internal3028))
+  (import "env" "longname3029" (func $internal3029))
+  (import "env" "longname3030" (func $internal3030))
+  (import "env" "longname3031" (func $internal3031))
+  (import "env" "longname3032" (func $internal3032))
+  (import "env" "longname3033" (func $internal3033))
+  (import "env" "longname3034" (func $internal3034))
+  (import "env" "longname3035" (func $internal3035))
+  (import "env" "longname3036" (func $internal3036))
+  (import "env" "longname3037" (func $internal3037))
+  (import "env" "longname3038" (func $internal3038))
+  (import "env" "longname3039" (func $internal3039))
+  (import "env" "longname3040" (func $internal3040))
+  (import "env" "longname3041" (func $internal3041))
+  (import "env" "longname3042" (func $internal3042))
+  (import "env" "longname3043" (func $internal3043))
+  (import "env" "longname3044" (func $internal3044))
+  (import "env" "longname3045" (func $internal3045))
+  (import "env" "longname3046" (func $internal3046))
+  (import "env" "longname3047" (func $internal3047))
+  (import "env" "longname3048" (func $internal3048))
+  (import "env" "longname3049" (func $internal3049))
+  (import "env" "longname3050" (func $internal3050))
+  (import "env" "longname3051" (func $internal3051))
+  (import "env" "longname3052" (func $internal3052))
+  (import "env" "longname3053" (func $internal3053))
+  (import "env" "longname3054" (func $internal3054))
+  (import "env" "longname3055" (func $internal3055))
+  (import "env" "longname3056" (func $internal3056))
+  (import "env" "longname3057" (func $internal3057))
+  (import "env" "longname3058" (func $internal3058))
+  (import "env" "longname3059" (func $internal3059))
+  (import "env" "longname3060" (func $internal3060))
+  (import "env" "longname3061" (func $internal3061))
+  (import "env" "longname3062" (func $internal3062))
+  (import "env" "longname3063" (func $internal3063))
+  (import "env" "longname3064" (func $internal3064))
+  (import "env" "longname3065" (func $internal3065))
+  (import "env" "longname3066" (func $internal3066))
+  (import "env" "longname3067" (func $internal3067))
+  (import "env" "longname3068" (func $internal3068))
+  (import "env" "longname3069" (func $internal3069))
+  (import "env" "longname3070" (func $internal3070))
+  (import "env" "longname3071" (func $internal3071))
+  (import "env" "longname3072" (func $internal3072))
+  (import "env" "longname3073" (func $internal3073))
+  (import "env" "longname3074" (func $internal3074))
+  (import "env" "longname3075" (func $internal3075))
+  (import "env" "longname3076" (func $internal3076))
+  (import "env" "longname3077" (func $internal3077))
+  (import "env" "longname3078" (func $internal3078))
+  (import "env" "longname3079" (func $internal3079))
+  (import "env" "longname3080" (func $internal3080))
+  (import "env" "longname3081" (func $internal3081))
+  (import "env" "longname3082" (func $internal3082))
+  (import "env" "longname3083" (func $internal3083))
+  (import "env" "longname3084" (func $internal3084))
+  (import "env" "longname3085" (func $internal3085))
+  (import "env" "longname3086" (func $internal3086))
+  (import "env" "longname3087" (func $internal3087))
+  (import "env" "longname3088" (func $internal3088))
+  (import "env" "longname3089" (func $internal3089))
+  (import "env" "longname3090" (func $internal3090))
+  (import "env" "longname3091" (func $internal3091))
+  (import "env" "longname3092" (func $internal3092))
+  (import "env" "longname3093" (func $internal3093))
+  (import "env" "longname3094" (func $internal3094))
+  (import "env" "longname3095" (func $internal3095))
+  (import "env" "longname3096" (func $internal3096))
+  (import "env" "longname3097" (func $internal3097))
+  (import "env" "longname3098" (func $internal3098))
+  (import "env" "longname3099" (func $internal3099))
+  (import "env" "longname3100" (func $internal3100))
+  (import "env" "longname3101" (func $internal3101))
+  (import "env" "longname3102" (func $internal3102))
+  (import "env" "longname3103" (func $internal3103))
+  (import "env" "longname3104" (func $internal3104))
+  (import "env" "longname3105" (func $internal3105))
+  (import "env" "longname3106" (func $internal3106))
+  (import "env" "longname3107" (func $internal3107))
+  (import "env" "longname3108" (func $internal3108))
+  (import "env" "longname3109" (func $internal3109))
+  (import "env" "longname3110" (func $internal3110))
+  (import "env" "longname3111" (func $internal3111))
+  (import "env" "longname3112" (func $internal3112))
+  (import "env" "longname3113" (func $internal3113))
+  (import "env" "longname3114" (func $internal3114))
+  (import "env" "longname3115" (func $internal3115))
+  (import "env" "longname3116" (func $internal3116))
+  (import "env" "longname3117" (func $internal3117))
+  (import "env" "longname3118" (func $internal3118))
+  (import "env" "longname3119" (func $internal3119))
+  (import "env" "longname3120" (func $internal3120))
+  (import "env" "longname3121" (func $internal3121))
+  (import "env" "longname3122" (func $internal3122))
+  (import "env" "longname3123" (func $internal3123))
+  (import "env" "longname3124" (func $internal3124))
+  (import "env" "longname3125" (func $internal3125))
+  (import "env" "longname3126" (func $internal3126))
+  (import "env" "longname3127" (func $internal3127))
+  (import "env" "longname3128" (func $internal3128))
+  (import "env" "longname3129" (func $internal3129))
+  (import "env" "longname3130" (func $internal3130))
+  (import "env" "longname3131" (func $internal3131))
+  (import "env" "longname3132" (func $internal3132))
+  (import "env" "longname3133" (func $internal3133))
+  (import "env" "longname3134" (func $internal3134))
+  (import "env" "longname3135" (func $internal3135))
+  (import "env" "longname3136" (func $internal3136))
+  (import "env" "longname3137" (func $internal3137))
+  (import "env" "longname3138" (func $internal3138))
+  (import "env" "longname3139" (func $internal3139))
+  (import "env" "longname3140" (func $internal3140))
+  (import "env" "longname3141" (func $internal3141))
+  (import "env" "longname3142" (func $internal3142))
+  (import "env" "longname3143" (func $internal3143))
+  (import "env" "longname3144" (func $internal3144))
+  (import "env" "longname3145" (func $internal3145))
+  (import "env" "longname3146" (func $internal3146))
+  (import "env" "longname3147" (func $internal3147))
+  (import "env" "longname3148" (func $internal3148))
+  (import "env" "longname3149" (func $internal3149))
+  (import "env" "longname3150" (func $internal3150))
+  (import "env" "longname3151" (func $internal3151))
+  (import "env" "longname3152" (func $internal3152))
+  (import "env" "longname3153" (func $internal3153))
+  (import "env" "longname3154" (func $internal3154))
+  (import "env" "longname3155" (func $internal3155))
+  (import "env" "longname3156" (func $internal3156))
+  (import "env" "longname3157" (func $internal3157))
+  (import "env" "longname3158" (func $internal3158))
+  (import "env" "longname3159" (func $internal3159))
+  (import "env" "longname3160" (func $internal3160))
+  (import "env" "longname3161" (func $internal3161))
+  (import "env" "longname3162" (func $internal3162))
+  (import "env" "longname3163" (func $internal3163))
+  (import "env" "longname3164" (func $internal3164))
+  (import "env" "longname3165" (func $internal3165))
+  (import "env" "longname3166" (func $internal3166))
+  (import "env" "longname3167" (func $internal3167))
+  (import "env" "longname3168" (func $internal3168))
+  (import "env" "longname3169" (func $internal3169))
+  (import "env" "longname3170" (func $internal3170))
+  (import "env" "longname3171" (func $internal3171))
+  (import "env" "longname3172" (func $internal3172))
+  (import "env" "longname3173" (func $internal3173))
+  (import "env" "longname3174" (func $internal3174))
+  (import "env" "longname3175" (func $internal3175))
+  (import "env" "longname3176" (func $internal3176))
+  (import "env" "longname3177" (func $internal3177))
+  (import "env" "longname3178" (func $internal3178))
+  (import "env" "longname3179" (func $internal3179))
+  (import "env" "longname3180" (func $internal3180))
+  (import "env" "longname3181" (func $internal3181))
+  (import "env" "longname3182" (func $internal3182))
+  (import "env" "longname3183" (func $internal3183))
+  (import "env" "longname3184" (func $internal3184))
+  (import "env" "longname3185" (func $internal3185))
+  (import "env" "longname3186" (func $internal3186))
+  (import "env" "longname3187" (func $internal3187))
+  (import "env" "longname3188" (func $internal3188))
+  (import "env" "longname3189" (func $internal3189))
+  (import "env" "longname3190" (func $internal3190))
+  (import "env" "longname3191" (func $internal3191))
+  (import "env" "longname3192" (func $internal3192))
+  (import "env" "longname3193" (func $internal3193))
+  (import "env" "longname3194" (func $internal3194))
+  (import "env" "longname3195" (func $internal3195))
+  (import "env" "longname3196" (func $internal3196))
+  (import "env" "longname3197" (func $internal3197))
+  (import "env" "longname3198" (func $internal3198))
+  (import "env" "longname3199" (func $internal3199))
+  (import "env" "longname3200" (func $internal3200))
+  (import "env" "longname3201" (func $internal3201))
+  (import "env" "longname3202" (func $internal3202))
+  (import "env" "longname3203" (func $internal3203))
+  (import "env" "longname3204" (func $internal3204))
+  (import "env" "longname3205" (func $internal3205))
+  (import "env" "longname3206" (func $internal3206))
+  (import "env" "longname3207" (func $internal3207))
+  (import "env" "longname3208" (func $internal3208))
+  (import "env" "longname3209" (func $internal3209))
+  (import "env" "longname3210" (func $internal3210))
+  (import "env" "longname3211" (func $internal3211))
+  (import "env" "longname3212" (func $internal3212))
+  (import "env" "longname3213" (func $internal3213))
+  (import "env" "longname3214" (func $internal3214))
+  (import "env" "longname3215" (func $internal3215))
+  (import "env" "longname3216" (func $internal3216))
+  (import "env" "longname3217" (func $internal3217))
+  (import "env" "longname3218" (func $internal3218))
+  (import "env" "longname3219" (func $internal3219))
+  (import "env" "longname3220" (func $internal3220))
+  (import "env" "longname3221" (func $internal3221))
+  (import "env" "longname3222" (func $internal3222))
+  (import "env" "longname3223" (func $internal3223))
+  (import "env" "longname3224" (func $internal3224))
+  (import "env" "longname3225" (func $internal3225))
+  (import "env" "longname3226" (func $internal3226))
+  (import "env" "longname3227" (func $internal3227))
+  (import "env" "longname3228" (func $internal3228))
+  (import "env" "longname3229" (func $internal3229))
+  (import "env" "longname3230" (func $internal3230))
+  (import "env" "longname3231" (func $internal3231))
+  (import "env" "longname3232" (func $internal3232))
+  (import "env" "longname3233" (func $internal3233))
+  (import "env" "longname3234" (func $internal3234))
+  (import "env" "longname3235" (func $internal3235))
+  (import "env" "longname3236" (func $internal3236))
+  (import "env" "longname3237" (func $internal3237))
+  (import "env" "longname3238" (func $internal3238))
+  (import "env" "longname3239" (func $internal3239))
+  (import "env" "longname3240" (func $internal3240))
+  (import "env" "longname3241" (func $internal3241))
+  (import "env" "longname3242" (func $internal3242))
+  (import "env" "longname3243" (func $internal3243))
+  (import "env" "longname3244" (func $internal3244))
+  (import "env" "longname3245" (func $internal3245))
+  (import "env" "longname3246" (func $internal3246))
+  (import "env" "longname3247" (func $internal3247))
+  (import "env" "longname3248" (func $internal3248))
+  (import "env" "longname3249" (func $internal3249))
+  (import "env" "longname3250" (func $internal3250))
+  (import "env" "longname3251" (func $internal3251))
+  (import "env" "longname3252" (func $internal3252))
+  (import "env" "longname3253" (func $internal3253))
+  (import "env" "longname3254" (func $internal3254))
+  (import "env" "longname3255" (func $internal3255))
+  (import "env" "longname3256" (func $internal3256))
+  (import "env" "longname3257" (func $internal3257))
+  (import "env" "longname3258" (func $internal3258))
+  (import "env" "longname3259" (func $internal3259))
+  (import "env" "longname3260" (func $internal3260))
+  (import "env" "longname3261" (func $internal3261))
+  (import "env" "longname3262" (func $internal3262))
+  (import "env" "longname3263" (func $internal3263))
+  (import "env" "longname3264" (func $internal3264))
+  (import "env" "longname3265" (func $internal3265))
+  (import "env" "longname3266" (func $internal3266))
+  (import "env" "longname3267" (func $internal3267))
+  (import "env" "longname3268" (func $internal3268))
+  (import "env" "longname3269" (func $internal3269))
+  (import "env" "longname3270" (func $internal3270))
+  (import "env" "longname3271" (func $internal3271))
+  (import "env" "longname3272" (func $internal3272))
+  (import "env" "longname3273" (func $internal3273))
+  (import "env" "longname3274" (func $internal3274))
+  (import "env" "longname3275" (func $internal3275))
+  (import "env" "longname3276" (func $internal3276))
+  (import "env" "longname3277" (func $internal3277))
+  (import "env" "longname3278" (func $internal3278))
+  (import "env" "longname3279" (func $internal3279))
+  (import "env" "longname3280" (func $internal3280))
+  (import "env" "longname3281" (func $internal3281))
+  (import "env" "longname3282" (func $internal3282))
+  (import "env" "longname3283" (func $internal3283))
+  (import "env" "longname3284" (func $internal3284))
+  (import "env" "longname3285" (func $internal3285))
+  (import "env" "longname3286" (func $internal3286))
+  (import "env" "longname3287" (func $internal3287))
+  (import "env" "longname3288" (func $internal3288))
+  (import "env" "longname3289" (func $internal3289))
+  (import "env" "longname3290" (func $internal3290))
+  (import "env" "longname3291" (func $internal3291))
+  (import "env" "longname3292" (func $internal3292))
+  (import "env" "longname3293" (func $internal3293))
+  (import "env" "longname3294" (func $internal3294))
+  (import "env" "longname3295" (func $internal3295))
+  (import "env" "longname3296" (func $internal3296))
+  (import "env" "longname3297" (func $internal3297))
+  (import "env" "longname3298" (func $internal3298))
+  (import "env" "longname3299" (func $internal3299))
+  (import "env" "longname3300" (func $internal3300))
+  (import "env" "longname3301" (func $internal3301))
+  (import "env" "longname3302" (func $internal3302))
+  (import "env" "longname3303" (func $internal3303))
+  (import "env" "longname3304" (func $internal3304))
+  (import "env" "longname3305" (func $internal3305))
+  (import "env" "longname3306" (func $internal3306))
+  (import "env" "longname3307" (func $internal3307))
+  (import "env" "longname3308" (func $internal3308))
+  (import "env" "longname3309" (func $internal3309))
+  (import "env" "longname3310" (func $internal3310))
+  (import "env" "longname3311" (func $internal3311))
+  (import "env" "longname3312" (func $internal3312))
+  (import "env" "longname3313" (func $internal3313))
+  (import "env" "longname3314" (func $internal3314))
+  (import "env" "longname3315" (func $internal3315))
+  (import "env" "longname3316" (func $internal3316))
+  (import "env" "longname3317" (func $internal3317))
+  (import "env" "longname3318" (func $internal3318))
+  (import "env" "longname3319" (func $internal3319))
+  (import "env" "longname3320" (func $internal3320))
+  (import "env" "longname3321" (func $internal3321))
+  (import "env" "longname3322" (func $internal3322))
+  (import "env" "longname3323" (func $internal3323))
+  (import "env" "longname3324" (func $internal3324))
+  (import "env" "longname3325" (func $internal3325))
+  (import "env" "longname3326" (func $internal3326))
+  (import "env" "longname3327" (func $internal3327))
+  (import "env" "longname3328" (func $internal3328))
+  (import "env" "longname3329" (func $internal3329))
+  (import "env" "longname3330" (func $internal3330))
+  (import "env" "longname3331" (func $internal3331))
+  (import "env" "longname3332" (func $internal3332))
+  (import "env" "longname3333" (func $internal3333))
+  (import "env" "longname3334" (func $internal3334))
+  (import "env" "longname3335" (func $internal3335))
+  (import "env" "longname3336" (func $internal3336))
+  (import "env" "longname3337" (func $internal3337))
+  (import "env" "longname3338" (func $internal3338))
+  (import "env" "longname3339" (func $internal3339))
+  (import "env" "longname3340" (func $internal3340))
+  (import "env" "longname3341" (func $internal3341))
+  (import "env" "longname3342" (func $internal3342))
+  (import "env" "longname3343" (func $internal3343))
+  (import "env" "longname3344" (func $internal3344))
+  (import "env" "longname3345" (func $internal3345))
+  (import "env" "longname3346" (func $internal3346))
+  (import "env" "longname3347" (func $internal3347))
+  (import "env" "longname3348" (func $internal3348))
+  (import "env" "longname3349" (func $internal3349))
+  (import "env" "longname3350" (func $internal3350))
+  (import "env" "longname3351" (func $internal3351))
+  (import "env" "longname3352" (func $internal3352))
+  (import "env" "longname3353" (func $internal3353))
+  (import "env" "longname3354" (func $internal3354))
+  (import "env" "longname3355" (func $internal3355))
+  (import "env" "longname3356" (func $internal3356))
+  (import "env" "longname3357" (func $internal3357))
+  (import "env" "longname3358" (func $internal3358))
+  (import "env" "longname3359" (func $internal3359))
+  (import "env" "longname3360" (func $internal3360))
+  (import "env" "longname3361" (func $internal3361))
+  (import "env" "longname3362" (func $internal3362))
+  (import "env" "longname3363" (func $internal3363))
+  (import "env" "longname3364" (func $internal3364))
+  (import "env" "longname3365" (func $internal3365))
+  (import "env" "longname3366" (func $internal3366))
+  (import "env" "longname3367" (func $internal3367))
+  (import "env" "longname3368" (func $internal3368))
+  (import "env" "longname3369" (func $internal3369))
+  (import "env" "longname3370" (func $internal3370))
+  (import "env" "longname3371" (func $internal3371))
+  (import "env" "longname3372" (func $internal3372))
+  (import "env" "longname3373" (func $internal3373))
+  (import "env" "longname3374" (func $internal3374))
+  (import "env" "longname3375" (func $internal3375))
+  (import "env" "longname3376" (func $internal3376))
+  (import "env" "longname3377" (func $internal3377))
+  (import "env" "longname3378" (func $internal3378))
+  (import "env" "longname3379" (func $internal3379))
+  (import "env" "longname3380" (func $internal3380))
+  (import "env" "longname3381" (func $internal3381))
+  (import "env" "longname3382" (func $internal3382))
+  (import "env" "longname3383" (func $internal3383))
+  (import "env" "longname3384" (func $internal3384))
+  (import "env" "longname3385" (func $internal3385))
+  (import "env" "longname3386" (func $internal3386))
+  (import "env" "longname3387" (func $internal3387))
+  (import "env" "longname3388" (func $internal3388))
+  (import "env" "longname3389" (func $internal3389))
+  (import "env" "longname3390" (func $internal3390))
+  (import "env" "longname3391" (func $internal3391))
+  (import "env" "longname3392" (func $internal3392))
+  (import "env" "longname3393" (func $internal3393))
+  (import "env" "longname3394" (func $internal3394))
+  (import "env" "longname3395" (func $internal3395))
+  (import "env" "longname3396" (func $internal3396))
+  (import "env" "longname3397" (func $internal3397))
+  (import "env" "longname3398" (func $internal3398))
+  (import "env" "longname3399" (func $internal3399))
+  (import "env" "longname3400" (func $internal3400))
+  (import "env" "longname3401" (func $internal3401))
+  (import "env" "longname3402" (func $internal3402))
+  (import "env" "longname3403" (func $internal3403))
+  (import "env" "longname3404" (func $internal3404))
+  (import "env" "longname3405" (func $internal3405))
+  (import "env" "longname3406" (func $internal3406))
+  (import "env" "longname3407" (func $internal3407))
+  (import "env" "longname3408" (func $internal3408))
+  (import "env" "longname3409" (func $internal3409))
+  (import "env" "longname3410" (func $internal3410))
+  (import "env" "longname3411" (func $internal3411))
+  (import "env" "longname3412" (func $internal3412))
+  (import "env" "longname3413" (func $internal3413))
+  (import "env" "longname3414" (func $internal3414))
+  (import "env" "longname3415" (func $internal3415))
+  (import "env" "longname3416" (func $internal3416))
+  (import "env" "longname3417" (func $internal3417))
+  (import "env" "longname3418" (func $internal3418))
+  (import "env" "longname3419" (func $internal3419))
+  (import "env" "longname3420" (func $internal3420))
+  (import "env" "longname3421" (func $internal3421))
+  (import "env" "longname3422" (func $internal3422))
+  (import "env" "longname3423" (func $internal3423))
+  (import "env" "longname3424" (func $internal3424))
+  (import "env" "longname3425" (func $internal3425))
+  (import "env" "longname3426" (func $internal3426))
+  (import "env" "longname3427" (func $internal3427))
+  (import "env" "longname3428" (func $internal3428))
+  (import "env" "longname3429" (func $internal3429))
+  (import "env" "longname3430" (func $internal3430))
+  (import "env" "longname3431" (func $internal3431))
+  (import "env" "longname3432" (func $internal3432))
+  (import "env" "longname3433" (func $internal3433))
+  (import "env" "longname3434" (func $internal3434))
+  (import "env" "longname3435" (func $internal3435))
+  (import "env" "longname3436" (func $internal3436))
+  (import "env" "longname3437" (func $internal3437))
+  (import "env" "longname3438" (func $internal3438))
+  (import "env" "longname3439" (func $internal3439))
+  (import "env" "longname3440" (func $internal3440))
+  (import "env" "longname3441" (func $internal3441))
+  (import "env" "longname3442" (func $internal3442))
+  (import "env" "longname3443" (func $internal3443))
+  (import "env" "longname3444" (func $internal3444))
+  (import "env" "longname3445" (func $internal3445))
+  (import "env" "longname3446" (func $internal3446))
+  (import "env" "longname3447" (func $internal3447))
+  (import "env" "longname3448" (func $internal3448))
+  (import "env" "longname3449" (func $internal3449))
+  (import "env" "longname3450" (func $internal3450))
+  (import "env" "longname3451" (func $internal3451))
+  (import "env" "longname3452" (func $internal3452))
+  (import "env" "longname3453" (func $internal3453))
+  (import "env" "longname3454" (func $internal3454))
+  (import "env" "longname3455" (func $internal3455))
+  (import "env" "longname3456" (func $internal3456))
+  (import "env" "longname3457" (func $internal3457))
+  (import "env" "longname3458" (func $internal3458))
+  (import "env" "longname3459" (func $internal3459))
+  (import "env" "longname3460" (func $internal3460))
+  (import "env" "longname3461" (func $internal3461))
+  (import "env" "longname3462" (func $internal3462))
+  (import "env" "longname3463" (func $internal3463))
+  (import "env" "longname3464" (func $internal3464))
+  (import "env" "longname3465" (func $internal3465))
+  (import "env" "longname3466" (func $internal3466))
+  (import "env" "longname3467" (func $internal3467))
+  (import "env" "longname3468" (func $internal3468))
+  (import "env" "longname3469" (func $internal3469))
+  (import "env" "longname3470" (func $internal3470))
+  (import "env" "longname3471" (func $internal3471))
+  (import "env" "longname3472" (func $internal3472))
+  (import "env" "longname3473" (func $internal3473))
+  (import "env" "longname3474" (func $internal3474))
+  (import "env" "longname3475" (func $internal3475))
+  (import "env" "longname3476" (func $internal3476))
+  (import "env" "longname3477" (func $internal3477))
+  (import "env" "longname3478" (func $internal3478))
+  (import "env" "longname3479" (func $internal3479))
+  (import "env" "longname3480" (func $internal3480))
+  (import "env" "longname3481" (func $internal3481))
+  (import "env" "longname3482" (func $internal3482))
+  (import "env" "longname3483" (func $internal3483))
+  (import "env" "longname3484" (func $internal3484))
+  (import "env" "longname3485" (func $internal3485))
+  (import "env" "longname3486" (func $internal3486))
+  (import "env" "longname3487" (func $internal3487))
+  (import "env" "longname3488" (func $internal3488))
+  (import "env" "longname3489" (func $internal3489))
+  (import "env" "longname3490" (func $internal3490))
+  (import "env" "longname3491" (func $internal3491))
+  (import "env" "longname3492" (func $internal3492))
+  (import "env" "longname3493" (func $internal3493))
+  (import "env" "longname3494" (func $internal3494))
+  (import "env" "longname3495" (func $internal3495))
+  (import "env" "longname3496" (func $internal3496))
+  (import "env" "longname3497" (func $internal3497))
+  (import "env" "longname3498" (func $internal3498))
+  (import "env" "longname3499" (func $internal3499))
+  (import "env" "longname3500" (func $internal3500))
+  (import "env" "longname3501" (func $internal3501))
+  (import "env" "longname3502" (func $internal3502))
+  (import "env" "longname3503" (func $internal3503))
+  (import "env" "longname3504" (func $internal3504))
+  (import "env" "longname3505" (func $internal3505))
+  (import "env" "longname3506" (func $internal3506))
+  (import "env" "longname3507" (func $internal3507))
+  (import "env" "longname3508" (func $internal3508))
+  (import "env" "longname3509" (func $internal3509))
+  (import "env" "longname3510" (func $internal3510))
+  (import "env" "longname3511" (func $internal3511))
+  (import "env" "longname3512" (func $internal3512))
+  (import "env" "longname3513" (func $internal3513))
+  (import "env" "longname3514" (func $internal3514))
+  (import "env" "longname3515" (func $internal3515))
+  (import "env" "longname3516" (func $internal3516))
+  (import "env" "longname3517" (func $internal3517))
+  (import "env" "longname3518" (func $internal3518))
+  (import "env" "longname3519" (func $internal3519))
+  (import "env" "longname3520" (func $internal3520))
+  (import "env" "longname3521" (func $internal3521))
+  (import "env" "longname3522" (func $internal3522))
+  (import "env" "longname3523" (func $internal3523))
+  (import "env" "longname3524" (func $internal3524))
+  (import "env" "longname3525" (func $internal3525))
+  (import "env" "longname3526" (func $internal3526))
+  (import "env" "longname3527" (func $internal3527))
+  (import "env" "longname3528" (func $internal3528))
+  (import "env" "longname3529" (func $internal3529))
+  (import "env" "longname3530" (func $internal3530))
+  (import "env" "longname3531" (func $internal3531))
+  (import "env" "longname3532" (func $internal3532))
+  (import "env" "longname3533" (func $internal3533))
+  (import "env" "longname3534" (func $internal3534))
+  (import "env" "longname3535" (func $internal3535))
+  (import "env" "longname3536" (func $internal3536))
+  (import "env" "longname3537" (func $internal3537))
+  (import "env" "longname3538" (func $internal3538))
+  (import "env" "longname3539" (func $internal3539))
+  (import "env" "longname3540" (func $internal3540))
+  (import "env" "longname3541" (func $internal3541))
+  (import "env" "longname3542" (func $internal3542))
+  (import "env" "longname3543" (func $internal3543))
+  (import "env" "longname3544" (func $internal3544))
+  (import "env" "longname3545" (func $internal3545))
+  (import "env" "longname3546" (func $internal3546))
+  (import "env" "longname3547" (func $internal3547))
+  (import "env" "longname3548" (func $internal3548))
+  (import "env" "longname3549" (func $internal3549))
+  (import "env" "longname3550" (func $internal3550))
+  (import "env" "longname3551" (func $internal3551))
+  (import "env" "longname3552" (func $internal3552))
+  (import "env" "longname3553" (func $internal3553))
+  (import "env" "longname3554" (func $internal3554))
+  (import "env" "longname3555" (func $internal3555))
+  (import "env" "longname3556" (func $internal3556))
+  (import "env" "longname3557" (func $internal3557))
+  (import "env" "longname3558" (func $internal3558))
+  (import "env" "longname3559" (func $internal3559))
+  (import "env" "longname3560" (func $internal3560))
+  (import "env" "longname3561" (func $internal3561))
+  (import "env" "longname3562" (func $internal3562))
+  (import "env" "longname3563" (func $internal3563))
+  (import "env" "longname3564" (func $internal3564))
+  (import "env" "longname3565" (func $internal3565))
+  (import "env" "longname3566" (func $internal3566))
+  (import "env" "longname3567" (func $internal3567))
+  (import "env" "longname3568" (func $internal3568))
+  (import "env" "longname3569" (func $internal3569))
+  (import "env" "longname3570" (func $internal3570))
+  (import "env" "longname3571" (func $internal3571))
+  (import "env" "longname3572" (func $internal3572))
+  (import "env" "longname3573" (func $internal3573))
+  (import "env" "longname3574" (func $internal3574))
+  (import "env" "longname3575" (func $internal3575))
+  (import "env" "longname3576" (func $internal3576))
+  (import "env" "longname3577" (func $internal3577))
+  (import "env" "longname3578" (func $internal3578))
+  (import "env" "longname3579" (func $internal3579))
+  (import "env" "longname3580" (func $internal3580))
+  (import "env" "longname3581" (func $internal3581))
+  (import "env" "longname3582" (func $internal3582))
+  (import "env" "longname3583" (func $internal3583))
+  (import "env" "longname3584" (func $internal3584))
+  (import "env" "longname3585" (func $internal3585))
+  (import "env" "longname3586" (func $internal3586))
+  (import "env" "longname3587" (func $internal3587))
+  (import "env" "longname3588" (func $internal3588))
+  (import "env" "longname3589" (func $internal3589))
+  (import "env" "longname3590" (func $internal3590))
+  (import "env" "longname3591" (func $internal3591))
+  (import "env" "longname3592" (func $internal3592))
+  (import "env" "longname3593" (func $internal3593))
+  (import "env" "longname3594" (func $internal3594))
+  (import "env" "longname3595" (func $internal3595))
+  (import "env" "longname3596" (func $internal3596))
+  (import "env" "longname3597" (func $internal3597))
+  (import "env" "longname3598" (func $internal3598))
+  (import "env" "longname3599" (func $internal3599))
+  (import "env" "longname3600" (func $internal3600))
+  (import "env" "longname3601" (func $internal3601))
+  (import "env" "longname3602" (func $internal3602))
+  (import "env" "longname3603" (func $internal3603))
+  (import "env" "longname3604" (func $internal3604))
+  (import "env" "longname3605" (func $internal3605))
+  (import "env" "longname3606" (func $internal3606))
+  (import "env" "longname3607" (func $internal3607))
+  (import "env" "longname3608" (func $internal3608))
+  (import "env" "longname3609" (func $internal3609))
+  (import "env" "longname3610" (func $internal3610))
+  (import "env" "longname3611" (func $internal3611))
+  (import "env" "longname3612" (func $internal3612))
+  (import "env" "longname3613" (func $internal3613))
+  (import "env" "longname3614" (func $internal3614))
+  (import "env" "longname3615" (func $internal3615))
+  (import "env" "longname3616" (func $internal3616))
+  (import "env" "longname3617" (func $internal3617))
+  (import "env" "longname3618" (func $internal3618))
+  (import "env" "longname3619" (func $internal3619))
+  (import "env" "longname3620" (func $internal3620))
+  (import "env" "longname3621" (func $internal3621))
+  (import "env" "longname3622" (func $internal3622))
+  (import "env" "longname3623" (func $internal3623))
+  (import "env" "longname3624" (func $internal3624))
+  (import "env" "longname3625" (func $internal3625))
+  (import "env" "longname3626" (func $internal3626))
+  (import "env" "longname3627" (func $internal3627))
+  (import "env" "longname3628" (func $internal3628))
+  (import "env" "longname3629" (func $internal3629))
+  (import "env" "longname3630" (func $internal3630))
+  (import "env" "longname3631" (func $internal3631))
+  (import "env" "longname3632" (func $internal3632))
+  (import "env" "longname3633" (func $internal3633))
+  (import "env" "longname3634" (func $internal3634))
+  (import "env" "longname3635" (func $internal3635))
+  (import "env" "longname3636" (func $internal3636))
+  (import "env" "longname3637" (func $internal3637))
+  (import "env" "longname3638" (func $internal3638))
+  (import "env" "longname3639" (func $internal3639))
+  (import "env" "longname3640" (func $internal3640))
+  (import "env" "longname3641" (func $internal3641))
+  (import "env" "longname3642" (func $internal3642))
+  (import "env" "longname3643" (func $internal3643))
+  (import "env" "longname3644" (func $internal3644))
+  (import "env" "longname3645" (func $internal3645))
+  (import "env" "longname3646" (func $internal3646))
+  (import "env" "longname3647" (func $internal3647))
+  (import "env" "longname3648" (func $internal3648))
+  (import "env" "longname3649" (func $internal3649))
+  (import "env" "longname3650" (func $internal3650))
+  (import "env" "longname3651" (func $internal3651))
+  (import "env" "longname3652" (func $internal3652))
+  (import "env" "longname3653" (func $internal3653))
+  (import "env" "longname3654" (func $internal3654))
+  (import "env" "longname3655" (func $internal3655))
+  (import "env" "longname3656" (func $internal3656))
+  (import "env" "longname3657" (func $internal3657))
+  (import "env" "longname3658" (func $internal3658))
+  (import "env" "longname3659" (func $internal3659))
+  (import "env" "longname3660" (func $internal3660))
+  (import "env" "longname3661" (func $internal3661))
+  (import "env" "longname3662" (func $internal3662))
+  (import "env" "longname3663" (func $internal3663))
+  (import "env" "longname3664" (func $internal3664))
+  (import "env" "longname3665" (func $internal3665))
+  (import "env" "longname3666" (func $internal3666))
+  (import "env" "longname3667" (func $internal3667))
+  (import "env" "longname3668" (func $internal3668))
+  (import "env" "longname3669" (func $internal3669))
+  (import "env" "longname3670" (func $internal3670))
+  (import "env" "longname3671" (func $internal3671))
+  (import "env" "longname3672" (func $internal3672))
+  (import "env" "longname3673" (func $internal3673))
+  (import "env" "longname3674" (func $internal3674))
+  (import "env" "longname3675" (func $internal3675))
+  (import "env" "longname3676" (func $internal3676))
+  (import "env" "longname3677" (func $internal3677))
+  (import "env" "longname3678" (func $internal3678))
+  (import "env" "longname3679" (func $internal3679))
+  (import "env" "longname3680" (func $internal3680))
+  (import "env" "longname3681" (func $internal3681))
+  (import "env" "longname3682" (func $internal3682))
+  (import "env" "longname3683" (func $internal3683))
+  (import "env" "longname3684" (func $internal3684))
+  (import "env" "longname3685" (func $internal3685))
+  (import "env" "longname3686" (func $internal3686))
+  (import "env" "longname3687" (func $internal3687))
+  (import "env" "longname3688" (func $internal3688))
+  (import "env" "longname3689" (func $internal3689))
+  (import "env" "longname3690" (func $internal3690))
+  (import "env" "longname3691" (func $internal3691))
+  (import "env" "longname3692" (func $internal3692))
+  (import "env" "longname3693" (func $internal3693))
+  (import "env" "longname3694" (func $internal3694))
+  (import "env" "longname3695" (func $internal3695))
+  (import "env" "longname3696" (func $internal3696))
+  (import "env" "longname3697" (func $internal3697))
+  (import "env" "longname3698" (func $internal3698))
+  (import "env" "longname3699" (func $internal3699))
+  (import "env" "longname3700" (func $internal3700))
+  (import "env" "longname3701" (func $internal3701))
+  (import "env" "longname3702" (func $internal3702))
+  (import "env" "longname3703" (func $internal3703))
+  (import "env" "longname3704" (func $internal3704))
+  (import "env" "longname3705" (func $internal3705))
+  (import "env" "longname3706" (func $internal3706))
+  (import "env" "longname3707" (func $internal3707))
+  (import "env" "longname3708" (func $internal3708))
+  (import "env" "longname3709" (func $internal3709))
+  (import "env" "longname3710" (func $internal3710))
+  (import "env" "longname3711" (func $internal3711))
+  (import "env" "longname3712" (func $internal3712))
+  (import "env" "longname3713" (func $internal3713))
+  (import "env" "longname3714" (func $internal3714))
+  (import "env" "longname3715" (func $internal3715))
+  (import "env" "longname3716" (func $internal3716))
+  (import "env" "longname3717" (func $internal3717))
+  (import "env" "longname3718" (func $internal3718))
+  (import "env" "longname3719" (func $internal3719))
+  (import "env" "longname3720" (func $internal3720))
+  (import "env" "longname3721" (func $internal3721))
+  (import "env" "longname3722" (func $internal3722))
+  (import "env" "longname3723" (func $internal3723))
+  (import "env" "longname3724" (func $internal3724))
+  (import "env" "longname3725" (func $internal3725))
+  (import "env" "longname3726" (func $internal3726))
+  (import "env" "longname3727" (func $internal3727))
+  (import "env" "longname3728" (func $internal3728))
+  (import "env" "longname3729" (func $internal3729))
+  (import "env" "longname3730" (func $internal3730))
+  (import "env" "longname3731" (func $internal3731))
+  (import "env" "longname3732" (func $internal3732))
+  (import "env" "longname3733" (func $internal3733))
+  (import "env" "longname3734" (func $internal3734))
+  (import "env" "longname3735" (func $internal3735))
+  (import "env" "longname3736" (func $internal3736))
+  (import "env" "longname3737" (func $internal3737))
+  (import "env" "longname3738" (func $internal3738))
+  (import "env" "longname3739" (func $internal3739))
+  (import "env" "longname3740" (func $internal3740))
+  (import "env" "longname3741" (func $internal3741))
+  (import "env" "longname3742" (func $internal3742))
+  (import "env" "longname3743" (func $internal3743))
+  (import "env" "longname3744" (func $internal3744))
+  (import "env" "longname3745" (func $internal3745))
+  (import "env" "longname3746" (func $internal3746))
+  (import "env" "longname3747" (func $internal3747))
+  (import "env" "longname3748" (func $internal3748))
+  (import "env" "longname3749" (func $internal3749))
+  (import "env" "longname3750" (func $internal3750))
+  (import "env" "longname3751" (func $internal3751))
+  (import "env" "longname3752" (func $internal3752))
+  (import "env" "longname3753" (func $internal3753))
+  (import "env" "longname3754" (func $internal3754))
+  (import "env" "longname3755" (func $internal3755))
+  (import "env" "longname3756" (func $internal3756))
+  (import "env" "longname3757" (func $internal3757))
+  (import "env" "longname3758" (func $internal3758))
+  (import "env" "longname3759" (func $internal3759))
+  (import "env" "longname3760" (func $internal3760))
+  (import "env" "longname3761" (func $internal3761))
+  (import "env" "longname3762" (func $internal3762))
+  (import "env" "longname3763" (func $internal3763))
+  (import "env" "longname3764" (func $internal3764))
+  (import "env" "longname3765" (func $internal3765))
+  (import "env" "longname3766" (func $internal3766))
+  (import "env" "longname3767" (func $internal3767))
+  (import "env" "longname3768" (func $internal3768))
+  (import "env" "longname3769" (func $internal3769))
+  (import "env" "longname3770" (func $internal3770))
+  (import "env" "longname3771" (func $internal3771))
+  (import "env" "longname3772" (func $internal3772))
+  (import "env" "longname3773" (func $internal3773))
+  (import "env" "longname3774" (func $internal3774))
+  (import "env" "longname3775" (func $internal3775))
+  (import "env" "longname3776" (func $internal3776))
+  (import "env" "longname3777" (func $internal3777))
+  (import "env" "longname3778" (func $internal3778))
+  (import "env" "longname3779" (func $internal3779))
+  (import "env" "longname3780" (func $internal3780))
+  (import "env" "longname3781" (func $internal3781))
+  (import "env" "longname3782" (func $internal3782))
+  (import "env" "longname3783" (func $internal3783))
+  (import "env" "longname3784" (func $internal3784))
+  (import "env" "longname3785" (func $internal3785))
+  (import "env" "longname3786" (func $internal3786))
+  (import "env" "longname3787" (func $internal3787))
+  (import "env" "longname3788" (func $internal3788))
+  (import "env" "longname3789" (func $internal3789))
+  (import "env" "longname3790" (func $internal3790))
+  (import "env" "longname3791" (func $internal3791))
+  (import "env" "longname3792" (func $internal3792))
+  (import "env" "longname3793" (func $internal3793))
+  (import "env" "longname3794" (func $internal3794))
+  (import "env" "longname3795" (func $internal3795))
+  (import "env" "longname3796" (func $internal3796))
+  (import "env" "longname3797" (func $internal3797))
+  (import "env" "longname3798" (func $internal3798))
+  (import "env" "longname3799" (func $internal3799))
+  (import "env" "longname3800" (func $internal3800))
+  (import "env" "longname3801" (func $internal3801))
+  (import "env" "longname3802" (func $internal3802))
+  (import "env" "longname3803" (func $internal3803))
+  (import "env" "longname3804" (func $internal3804))
+  (import "env" "longname3805" (func $internal3805))
+  (import "env" "longname3806" (func $internal3806))
+  (import "env" "longname3807" (func $internal3807))
+  (import "env" "longname3808" (func $internal3808))
+  (import "env" "longname3809" (func $internal3809))
+  (import "env" "longname3810" (func $internal3810))
+  (import "env" "longname3811" (func $internal3811))
+  (import "env" "longname3812" (func $internal3812))
+  (import "env" "longname3813" (func $internal3813))
+  (import "env" "longname3814" (func $internal3814))
+  (import "env" "longname3815" (func $internal3815))
+  (import "env" "longname3816" (func $internal3816))
+  (import "env" "longname3817" (func $internal3817))
+  (import "env" "longname3818" (func $internal3818))
+  (import "env" "longname3819" (func $internal3819))
+  (import "env" "longname3820" (func $internal3820))
+  (import "env" "longname3821" (func $internal3821))
+  (import "env" "longname3822" (func $internal3822))
+  (import "env" "longname3823" (func $internal3823))
+  (import "env" "longname3824" (func $internal3824))
+  (import "env" "longname3825" (func $internal3825))
+  (import "env" "longname3826" (func $internal3826))
+  (import "env" "longname3827" (func $internal3827))
+  (import "env" "longname3828" (func $internal3828))
+  (import "env" "longname3829" (func $internal3829))
+  (import "env" "longname3830" (func $internal3830))
+  (import "env" "longname3831" (func $internal3831))
+  (import "env" "longname3832" (func $internal3832))
+  (import "env" "longname3833" (func $internal3833))
+  (import "env" "longname3834" (func $internal3834))
+  (import "env" "longname3835" (func $internal3835))
+  (import "env" "longname3836" (func $internal3836))
+  (import "env" "longname3837" (func $internal3837))
+  (import "env" "longname3838" (func $internal3838))
+  (import "env" "longname3839" (func $internal3839))
+  (import "env" "longname3840" (func $internal3840))
+  (import "env" "longname3841" (func $internal3841))
+  (import "env" "longname3842" (func $internal3842))
+  (import "env" "longname3843" (func $internal3843))
+  (import "env" "longname3844" (func $internal3844))
+  (import "env" "longname3845" (func $internal3845))
+  (import "env" "longname3846" (func $internal3846))
+  (import "env" "longname3847" (func $internal3847))
+  (import "env" "longname3848" (func $internal3848))
+  (import "env" "longname3849" (func $internal3849))
+  (import "env" "longname3850" (func $internal3850))
+  (import "env" "longname3851" (func $internal3851))
+  (import "env" "longname3852" (func $internal3852))
+  (import "env" "longname3853" (func $internal3853))
+  (import "env" "longname3854" (func $internal3854))
+  (import "env" "longname3855" (func $internal3855))
+  (import "env" "longname3856" (func $internal3856))
+  (import "env" "longname3857" (func $internal3857))
+  (import "env" "longname3858" (func $internal3858))
+  (import "env" "longname3859" (func $internal3859))
+  (import "env" "longname3860" (func $internal3860))
+  (import "env" "longname3861" (func $internal3861))
+  (import "env" "longname3862" (func $internal3862))
+  (import "env" "longname3863" (func $internal3863))
+  (import "env" "longname3864" (func $internal3864))
+  (import "env" "longname3865" (func $internal3865))
+  (import "env" "longname3866" (func $internal3866))
+  (import "env" "longname3867" (func $internal3867))
+  (import "env" "longname3868" (func $internal3868))
+  (import "env" "longname3869" (func $internal3869))
+  (import "env" "longname3870" (func $internal3870))
+  (import "env" "longname3871" (func $internal3871))
+  (import "env" "longname3872" (func $internal3872))
+  (import "env" "longname3873" (func $internal3873))
+  (import "env" "longname3874" (func $internal3874))
+  (import "env" "longname3875" (func $internal3875))
+  (import "env" "longname3876" (func $internal3876))
+  (import "env" "longname3877" (func $internal3877))
+  (import "env" "longname3878" (func $internal3878))
+  (import "env" "longname3879" (func $internal3879))
+  (import "env" "longname3880" (func $internal3880))
+  (import "env" "longname3881" (func $internal3881))
+  (import "env" "longname3882" (func $internal3882))
+  (import "env" "longname3883" (func $internal3883))
+  (import "env" "longname3884" (func $internal3884))
+  (import "env" "longname3885" (func $internal3885))
+  (import "env" "longname3886" (func $internal3886))
+  (import "env" "longname3887" (func $internal3887))
+  (import "env" "longname3888" (func $internal3888))
+  (import "env" "longname3889" (func $internal3889))
+  (import "env" "longname3890" (func $internal3890))
+  (import "env" "longname3891" (func $internal3891))
+  (import "env" "longname3892" (func $internal3892))
+  (import "env" "longname3893" (func $internal3893))
+  (import "env" "longname3894" (func $internal3894))
+  (import "env" "longname3895" (func $internal3895))
+  (import "env" "longname3896" (func $internal3896))
+  (import "env" "longname3897" (func $internal3897))
+  (import "env" "longname3898" (func $internal3898))
+  (import "env" "longname3899" (func $internal3899))
+  (import "env" "longname3900" (func $internal3900))
+  (import "env" "longname3901" (func $internal3901))
+  (import "env" "longname3902" (func $internal3902))
+  (import "env" "longname3903" (func $internal3903))
+  (import "env" "longname3904" (func $internal3904))
+  (import "env" "longname3905" (func $internal3905))
+  (import "env" "longname3906" (func $internal3906))
+  (import "env" "longname3907" (func $internal3907))
+  (import "env" "longname3908" (func $internal3908))
+  (import "env" "longname3909" (func $internal3909))
+  (import "env" "longname3910" (func $internal3910))
+  (import "env" "longname3911" (func $internal3911))
+  (import "env" "longname3912" (func $internal3912))
+  (import "env" "longname3913" (func $internal3913))
+  (import "env" "longname3914" (func $internal3914))
+  (import "env" "longname3915" (func $internal3915))
+  (import "env" "longname3916" (func $internal3916))
+  (import "env" "longname3917" (func $internal3917))
+  (import "env" "longname3918" (func $internal3918))
+  (import "env" "longname3919" (func $internal3919))
+  (import "env" "longname3920" (func $internal3920))
+  (import "env" "longname3921" (func $internal3921))
+  (import "env" "longname3922" (func $internal3922))
+  (import "env" "longname3923" (func $internal3923))
+  (import "env" "longname3924" (func $internal3924))
+  (import "env" "longname3925" (func $internal3925))
+  (import "env" "longname3926" (func $internal3926))
+  (import "env" "longname3927" (func $internal3927))
+  (import "env" "longname3928" (func $internal3928))
+  (import "env" "longname3929" (func $internal3929))
+  (import "env" "longname3930" (func $internal3930))
+  (import "env" "longname3931" (func $internal3931))
+  (import "env" "longname3932" (func $internal3932))
+  (import "env" "longname3933" (func $internal3933))
+  (import "env" "longname3934" (func $internal3934))
+  (import "env" "longname3935" (func $internal3935))
+  (import "env" "longname3936" (func $internal3936))
+  (import "env" "longname3937" (func $internal3937))
+  (import "env" "longname3938" (func $internal3938))
+  (import "env" "longname3939" (func $internal3939))
+  (import "env" "longname3940" (func $internal3940))
+  (import "env" "longname3941" (func $internal3941))
+  (import "env" "longname3942" (func $internal3942))
+  (import "env" "longname3943" (func $internal3943))
+  (import "env" "longname3944" (func $internal3944))
+  (import "env" "longname3945" (func $internal3945))
+  (import "env" "longname3946" (func $internal3946))
+  (import "env" "longname3947" (func $internal3947))
+  (import "env" "longname3948" (func $internal3948))
+  (import "env" "longname3949" (func $internal3949))
+  (import "env" "longname3950" (func $internal3950))
+  (import "env" "longname3951" (func $internal3951))
+  (import "env" "longname3952" (func $internal3952))
+  (import "env" "longname3953" (func $internal3953))
+  (import "env" "longname3954" (func $internal3954))
+  (import "env" "longname3955" (func $internal3955))
+  (import "env" "longname3956" (func $internal3956))
+  (import "env" "longname3957" (func $internal3957))
+  (import "env" "longname3958" (func $internal3958))
+  (import "env" "longname3959" (func $internal3959))
+  (import "env" "longname3960" (func $internal3960))
+  (import "env" "longname3961" (func $internal3961))
+  (import "env" "longname3962" (func $internal3962))
+  (import "env" "longname3963" (func $internal3963))
+  (import "env" "longname3964" (func $internal3964))
+  (import "env" "longname3965" (func $internal3965))
+  (import "env" "longname3966" (func $internal3966))
+  (import "env" "longname3967" (func $internal3967))
+  (import "env" "longname3968" (func $internal3968))
+  (import "env" "longname3969" (func $internal3969))
+  (import "env" "longname3970" (func $internal3970))
+  (import "env" "longname3971" (func $internal3971))
+  (import "env" "longname3972" (func $internal3972))
+  (import "env" "longname3973" (func $internal3973))
+  (import "env" "longname3974" (func $internal3974))
+  (import "env" "longname3975" (func $internal3975))
+  (import "env" "longname3976" (func $internal3976))
+  (import "env" "longname3977" (func $internal3977))
+  (import "env" "longname3978" (func $internal3978))
+  (import "env" "longname3979" (func $internal3979))
+  (import "env" "longname3980" (func $internal3980))
+  (import "env" "longname3981" (func $internal3981))
+  (import "env" "longname3982" (func $internal3982))
+  (import "env" "longname3983" (func $internal3983))
+  (import "env" "longname3984" (func $internal3984))
+  (import "env" "longname3985" (func $internal3985))
+  (import "env" "longname3986" (func $internal3986))
+  (import "env" "longname3987" (func $internal3987))
+  (import "env" "longname3988" (func $internal3988))
+  (import "env" "longname3989" (func $internal3989))
+  (import "env" "longname3990" (func $internal3990))
+  (import "env" "longname3991" (func $internal3991))
+  (import "env" "longname3992" (func $internal3992))
+  (import "env" "longname3993" (func $internal3993))
+  (import "env" "longname3994" (func $internal3994))
+  (import "env" "longname3995" (func $internal3995))
+  (import "env" "longname3996" (func $internal3996))
+  (import "env" "longname3997" (func $internal3997))
+  (import "env" "longname3998" (func $internal3998))
+  (import "env" "longname3999" (func $internal3999))
+  (import "env" "longname4000" (func $internal4000))
+  (import "env" "longname4001" (func $internal4001))
+  (import "env" "longname4002" (func $internal4002))
+  (import "env" "longname4003" (func $internal4003))
+  (import "env" "longname4004" (func $internal4004))
+  (import "env" "longname4005" (func $internal4005))
+  (import "env" "longname4006" (func $internal4006))
+  (import "env" "longname4007" (func $internal4007))
+  (import "env" "longname4008" (func $internal4008))
+  (import "env" "longname4009" (func $internal4009))
+  (import "env" "longname4010" (func $internal4010))
+  (import "env" "longname4011" (func $internal4011))
+  (import "env" "longname4012" (func $internal4012))
+  (import "env" "longname4013" (func $internal4013))
+  (import "env" "longname4014" (func $internal4014))
+  (import "env" "longname4015" (func $internal4015))
+  (import "env" "longname4016" (func $internal4016))
+  (import "env" "longname4017" (func $internal4017))
+  (import "env" "longname4018" (func $internal4018))
+  (import "env" "longname4019" (func $internal4019))
+  (import "env" "longname4020" (func $internal4020))
+  (import "env" "longname4021" (func $internal4021))
+  (import "env" "longname4022" (func $internal4022))
+  (import "env" "longname4023" (func $internal4023))
+  (import "env" "longname4024" (func $internal4024))
+  (import "env" "longname4025" (func $internal4025))
+  (import "env" "longname4026" (func $internal4026))
+  (import "env" "longname4027" (func $internal4027))
+  (import "env" "longname4028" (func $internal4028))
+  (import "env" "longname4029" (func $internal4029))
+  (import "env" "longname4030" (func $internal4030))
+  (import "env" "longname4031" (func $internal4031))
+  (import "env" "longname4032" (func $internal4032))
+  (import "env" "longname4033" (func $internal4033))
+  (import "env" "longname4034" (func $internal4034))
+  (import "env" "longname4035" (func $internal4035))
+  (import "env" "longname4036" (func $internal4036))
+  (import "env" "longname4037" (func $internal4037))
+  (import "env" "longname4038" (func $internal4038))
+  (import "env" "longname4039" (func $internal4039))
+  (import "env" "longname4040" (func $internal4040))
+  (import "env" "longname4041" (func $internal4041))
+  (import "env" "longname4042" (func $internal4042))
+  (import "env" "longname4043" (func $internal4043))
+  (import "env" "longname4044" (func $internal4044))
+  (import "env" "longname4045" (func $internal4045))
+  (import "env" "longname4046" (func $internal4046))
+  (import "env" "longname4047" (func $internal4047))
+  (import "env" "longname4048" (func $internal4048))
+  (import "env" "longname4049" (func $internal4049))
+  (import "env" "longname4050" (func $internal4050))
+  (import "env" "longname4051" (func $internal4051))
+  (import "env" "longname4052" (func $internal4052))
+  (import "env" "longname4053" (func $internal4053))
+  (import "env" "longname4054" (func $internal4054))
+  (import "env" "longname4055" (func $internal4055))
+  (import "env" "longname4056" (func $internal4056))
+  (import "env" "longname4057" (func $internal4057))
+  (import "env" "longname4058" (func $internal4058))
+  (import "env" "longname4059" (func $internal4059))
+  (import "env" "longname4060" (func $internal4060))
+  (import "env" "longname4061" (func $internal4061))
+  (import "env" "longname4062" (func $internal4062))
+  (import "env" "longname4063" (func $internal4063))
+  (import "env" "longname4064" (func $internal4064))
+  (import "env" "longname4065" (func $internal4065))
+  (import "env" "longname4066" (func $internal4066))
+  (import "env" "longname4067" (func $internal4067))
+  (import "env" "longname4068" (func $internal4068))
+  (import "env" "longname4069" (func $internal4069))
+  (import "env" "longname4070" (func $internal4070))
+  (import "env" "longname4071" (func $internal4071))
+  (import "env" "longname4072" (func $internal4072))
+  (import "env" "longname4073" (func $internal4073))
+  (import "env" "longname4074" (func $internal4074))
+  (import "env" "longname4075" (func $internal4075))
+  (import "env" "longname4076" (func $internal4076))
+  (import "env" "longname4077" (func $internal4077))
+  (import "env" "longname4078" (func $internal4078))
+  (import "env" "longname4079" (func $internal4079))
+  (import "env" "longname4080" (func $internal4080))
+  (import "env" "longname4081" (func $internal4081))
+  (import "env" "longname4082" (func $internal4082))
+  (import "env" "longname4083" (func $internal4083))
+  (import "env" "longname4084" (func $internal4084))
+  (import "env" "longname4085" (func $internal4085))
+  (import "env" "longname4086" (func $internal4086))
+  (import "env" "longname4087" (func $internal4087))
+  (import "env" "longname4088" (func $internal4088))
+  (import "env" "longname4089" (func $internal4089))
+  (import "env" "longname4090" (func $internal4090))
+  (import "env" "longname4091" (func $internal4091))
+  (import "env" "longname4092" (func $internal4092))
+  (import "env" "longname4093" (func $internal4093))
+  (import "env" "longname4094" (func $internal4094))
+  (import "env" "longname4095" (func $internal4095))
+  (import "env" "longname4096" (func $internal4096))
+  (import "env" "longname4097" (func $internal4097))
+  (import "env" "longname4098" (func $internal4098))
+  (import "env" "longname4099" (func $internal4099))
+  (import "env" "longname4100" (func $internal4100))
+  (import "env" "longname4101" (func $internal4101))
+  (import "env" "longname4102" (func $internal4102))
+  (import "env" "longname4103" (func $internal4103))
+  (import "env" "longname4104" (func $internal4104))
+  (import "env" "longname4105" (func $internal4105))
+  (import "env" "longname4106" (func $internal4106))
+  (import "env" "longname4107" (func $internal4107))
+  (import "env" "longname4108" (func $internal4108))
+  (import "env" "longname4109" (func $internal4109))
+  (import "env" "longname4110" (func $internal4110))
+  (import "env" "longname4111" (func $internal4111))
+  (import "env" "longname4112" (func $internal4112))
+  (import "env" "longname4113" (func $internal4113))
+  (import "env" "longname4114" (func $internal4114))
+  (import "env" "longname4115" (func $internal4115))
+  (import "env" "longname4116" (func $internal4116))
+  (import "env" "longname4117" (func $internal4117))
+  (import "env" "longname4118" (func $internal4118))
+  (import "env" "longname4119" (func $internal4119))
+  (import "env" "longname4120" (func $internal4120))
+  (import "env" "longname4121" (func $internal4121))
+  (import "env" "longname4122" (func $internal4122))
+  (import "env" "longname4123" (func $internal4123))
+  (import "env" "longname4124" (func $internal4124))
+  (import "env" "longname4125" (func $internal4125))
+  (import "env" "longname4126" (func $internal4126))
+  (import "env" "longname4127" (func $internal4127))
+  (import "env" "longname4128" (func $internal4128))
+  (import "env" "longname4129" (func $internal4129))
+  (import "env" "longname4130" (func $internal4130))
+  (import "env" "longname4131" (func $internal4131))
+  (import "env" "longname4132" (func $internal4132))
+  (import "env" "longname4133" (func $internal4133))
+  (import "env" "longname4134" (func $internal4134))
+  (import "env" "longname4135" (func $internal4135))
+  (import "env" "longname4136" (func $internal4136))
+  (import "env" "longname4137" (func $internal4137))
+  (import "env" "longname4138" (func $internal4138))
+  (import "env" "longname4139" (func $internal4139))
+  (import "env" "longname4140" (func $internal4140))
+  (import "env" "longname4141" (func $internal4141))
+  (import "env" "longname4142" (func $internal4142))
+  (import "env" "longname4143" (func $internal4143))
+  (import "env" "longname4144" (func $internal4144))
+  (import "env" "longname4145" (func $internal4145))
+  (import "env" "longname4146" (func $internal4146))
+  (import "env" "longname4147" (func $internal4147))
+  (import "env" "longname4148" (func $internal4148))
+  (import "env" "longname4149" (func $internal4149))
+  (import "env" "longname4150" (func $internal4150))
+  (import "env" "longname4151" (func $internal4151))
+  (import "env" "longname4152" (func $internal4152))
+  (import "env" "longname4153" (func $internal4153))
+  (import "env" "longname4154" (func $internal4154))
+  (import "env" "longname4155" (func $internal4155))
+  (import "env" "longname4156" (func $internal4156))
+  (import "env" "longname4157" (func $internal4157))
+  (import "env" "longname4158" (func $internal4158))
+  (import "env" "longname4159" (func $internal4159))
+  (import "env" "longname4160" (func $internal4160))
+  (import "env" "longname4161" (func $internal4161))
+  (import "env" "longname4162" (func $internal4162))
+  (import "env" "longname4163" (func $internal4163))
+  (import "env" "longname4164" (func $internal4164))
+  (import "env" "longname4165" (func $internal4165))
+  (import "env" "longname4166" (func $internal4166))
+  (import "env" "longname4167" (func $internal4167))
+  (import "env" "longname4168" (func $internal4168))
+  (import "env" "longname4169" (func $internal4169))
+  (import "env" "longname4170" (func $internal4170))
+  (import "env" "longname4171" (func $internal4171))
+  (import "env" "longname4172" (func $internal4172))
+  (import "env" "longname4173" (func $internal4173))
+  (import "env" "longname4174" (func $internal4174))
+  (import "env" "longname4175" (func $internal4175))
+  (import "env" "longname4176" (func $internal4176))
+  (import "env" "longname4177" (func $internal4177))
+  (import "env" "longname4178" (func $internal4178))
+  (import "env" "longname4179" (func $internal4179))
+  (import "env" "longname4180" (func $internal4180))
+  (import "env" "longname4181" (func $internal4181))
+  (import "env" "longname4182" (func $internal4182))
+  (import "env" "longname4183" (func $internal4183))
+  (import "env" "longname4184" (func $internal4184))
+  (import "env" "longname4185" (func $internal4185))
+  (import "env" "longname4186" (func $internal4186))
+  (import "env" "longname4187" (func $internal4187))
+  (import "env" "longname4188" (func $internal4188))
+  (import "env" "longname4189" (func $internal4189))
+  (import "env" "longname4190" (func $internal4190))
+  (import "env" "longname4191" (func $internal4191))
+  (import "env" "longname4192" (func $internal4192))
+  (import "env" "longname4193" (func $internal4193))
+  (import "env" "longname4194" (func $internal4194))
+  (import "env" "longname4195" (func $internal4195))
+  (import "env" "longname4196" (func $internal4196))
+  (import "env" "longname4197" (func $internal4197))
+  (import "env" "longname4198" (func $internal4198))
+  (import "env" "longname4199" (func $internal4199))
+  (import "env" "longname4200" (func $internal4200))
+  (import "env" "longname4201" (func $internal4201))
+  (import "env" "longname4202" (func $internal4202))
+  (import "env" "longname4203" (func $internal4203))
+  (import "env" "longname4204" (func $internal4204))
+  (import "env" "longname4205" (func $internal4205))
+  (import "env" "longname4206" (func $internal4206))
+  (import "env" "longname4207" (func $internal4207))
+  (import "env" "longname4208" (func $internal4208))
+  (import "env" "longname4209" (func $internal4209))
+  (import "env" "longname4210" (func $internal4210))
+  (import "env" "longname4211" (func $internal4211))
+  (import "env" "longname4212" (func $internal4212))
+  (import "env" "longname4213" (func $internal4213))
+  (import "env" "longname4214" (func $internal4214))
+  (import "env" "longname4215" (func $internal4215))
+  (import "env" "longname4216" (func $internal4216))
+  (import "env" "longname4217" (func $internal4217))
+  (import "env" "longname4218" (func $internal4218))
+  (import "env" "longname4219" (func $internal4219))
+  (import "env" "longname4220" (func $internal4220))
+  (import "env" "longname4221" (func $internal4221))
+  (import "env" "longname4222" (func $internal4222))
+  (import "env" "longname4223" (func $internal4223))
+  (import "env" "longname4224" (func $internal4224))
+  (import "env" "longname4225" (func $internal4225))
+  (import "env" "longname4226" (func $internal4226))
+  (import "env" "longname4227" (func $internal4227))
+  (import "env" "longname4228" (func $internal4228))
+  (import "env" "longname4229" (func $internal4229))
+  (import "env" "longname4230" (func $internal4230))
+  (import "env" "longname4231" (func $internal4231))
+  (import "env" "longname4232" (func $internal4232))
+  (import "env" "longname4233" (func $internal4233))
+  (import "env" "longname4234" (func $internal4234))
+  (import "env" "longname4235" (func $internal4235))
+  (import "env" "longname4236" (func $internal4236))
+  (import "env" "longname4237" (func $internal4237))
+  (import "env" "longname4238" (func $internal4238))
+  (import "env" "longname4239" (func $internal4239))
+  (import "env" "longname4240" (func $internal4240))
+  (import "env" "longname4241" (func $internal4241))
+  (import "env" "longname4242" (func $internal4242))
+  (import "env" "longname4243" (func $internal4243))
+  (import "env" "longname4244" (func $internal4244))
+  (import "env" "longname4245" (func $internal4245))
+  (import "env" "longname4246" (func $internal4246))
+  (import "env" "longname4247" (func $internal4247))
+  (import "env" "longname4248" (func $internal4248))
+  (import "env" "longname4249" (func $internal4249))
+  (import "env" "longname4250" (func $internal4250))
+  (import "env" "longname4251" (func $internal4251))
+  (import "env" "longname4252" (func $internal4252))
+  (import "env" "longname4253" (func $internal4253))
+  (import "env" "longname4254" (func $internal4254))
+  (import "env" "longname4255" (func $internal4255))
+  (import "env" "longname4256" (func $internal4256))
+  (import "env" "longname4257" (func $internal4257))
+  (import "env" "longname4258" (func $internal4258))
+  (import "env" "longname4259" (func $internal4259))
+  (import "env" "longname4260" (func $internal4260))
+  (import "env" "longname4261" (func $internal4261))
+  (import "env" "longname4262" (func $internal4262))
+  (import "env" "longname4263" (func $internal4263))
+  (import "env" "longname4264" (func $internal4264))
+  (import "env" "longname4265" (func $internal4265))
+  (import "env" "longname4266" (func $internal4266))
+  (import "env" "longname4267" (func $internal4267))
+  (import "env" "longname4268" (func $internal4268))
+  (import "env" "longname4269" (func $internal4269))
+  (import "env" "longname4270" (func $internal4270))
+  (import "env" "longname4271" (func $internal4271))
+  (import "env" "longname4272" (func $internal4272))
+  (import "env" "longname4273" (func $internal4273))
+  (import "env" "longname4274" (func $internal4274))
+  (import "env" "longname4275" (func $internal4275))
+  (import "env" "longname4276" (func $internal4276))
+  (import "env" "longname4277" (func $internal4277))
+  (import "env" "longname4278" (func $internal4278))
+  (import "env" "longname4279" (func $internal4279))
+  (import "env" "longname4280" (func $internal4280))
+  (import "env" "longname4281" (func $internal4281))
+  (import "env" "longname4282" (func $internal4282))
+  (import "env" "longname4283" (func $internal4283))
+  (import "env" "longname4284" (func $internal4284))
+  (import "env" "longname4285" (func $internal4285))
+  (import "env" "longname4286" (func $internal4286))
+  (import "env" "longname4287" (func $internal4287))
+  (import "env" "longname4288" (func $internal4288))
+  (import "env" "longname4289" (func $internal4289))
+  (import "env" "longname4290" (func $internal4290))
+  (import "env" "longname4291" (func $internal4291))
+  (import "env" "longname4292" (func $internal4292))
+  (import "env" "longname4293" (func $internal4293))
+  (import "env" "longname4294" (func $internal4294))
+  (import "env" "longname4295" (func $internal4295))
+  (import "env" "longname4296" (func $internal4296))
+  (import "env" "longname4297" (func $internal4297))
+  (import "env" "longname4298" (func $internal4298))
+  (import "env" "longname4299" (func $internal4299))
+  (import "env" "longname4300" (func $internal4300))
+  (import "env" "longname4301" (func $internal4301))
+  (import "env" "longname4302" (func $internal4302))
+  (import "env" "longname4303" (func $internal4303))
+  (import "env" "longname4304" (func $internal4304))
+  (import "env" "longname4305" (func $internal4305))
+  (import "env" "longname4306" (func $internal4306))
+  (import "env" "longname4307" (func $internal4307))
+  (import "env" "longname4308" (func $internal4308))
+  (import "env" "longname4309" (func $internal4309))
+  (import "env" "longname4310" (func $internal4310))
+  (import "env" "longname4311" (func $internal4311))
+  (import "env" "longname4312" (func $internal4312))
+  (import "env" "longname4313" (func $internal4313))
+  (import "env" "longname4314" (func $internal4314))
+  (import "env" "longname4315" (func $internal4315))
+  (import "env" "longname4316" (func $internal4316))
+  (import "env" "longname4317" (func $internal4317))
+  (import "env" "longname4318" (func $internal4318))
+  (import "env" "longname4319" (func $internal4319))
+  (import "env" "longname4320" (func $internal4320))
+  (import "env" "longname4321" (func $internal4321))
+  (import "env" "longname4322" (func $internal4322))
+  (import "env" "longname4323" (func $internal4323))
+  (import "env" "longname4324" (func $internal4324))
+  (import "env" "longname4325" (func $internal4325))
+  (import "env" "longname4326" (func $internal4326))
+  (import "env" "longname4327" (func $internal4327))
+  (import "env" "longname4328" (func $internal4328))
+  (import "env" "longname4329" (func $internal4329))
+  (import "env" "longname4330" (func $internal4330))
+  (import "env" "longname4331" (func $internal4331))
+  (import "env" "longname4332" (func $internal4332))
+  (import "env" "longname4333" (func $internal4333))
+  (import "env" "longname4334" (func $internal4334))
+  (import "env" "longname4335" (func $internal4335))
+  (import "env" "longname4336" (func $internal4336))
+  (import "env" "longname4337" (func $internal4337))
+  (import "env" "longname4338" (func $internal4338))
+  (import "env" "longname4339" (func $internal4339))
+  (import "env" "longname4340" (func $internal4340))
+  (import "env" "longname4341" (func $internal4341))
+  (import "env" "longname4342" (func $internal4342))
+  (import "env" "longname4343" (func $internal4343))
+  (import "env" "longname4344" (func $internal4344))
+  (import "env" "longname4345" (func $internal4345))
+  (import "env" "longname4346" (func $internal4346))
+  (import "env" "longname4347" (func $internal4347))
+  (import "env" "longname4348" (func $internal4348))
+  (import "env" "longname4349" (func $internal4349))
+  (import "env" "longname4350" (func $internal4350))
+  (import "env" "longname4351" (func $internal4351))
+  (import "env" "longname4352" (func $internal4352))
+  (import "env" "longname4353" (func $internal4353))
+  (import "env" "longname4354" (func $internal4354))
+  (import "env" "longname4355" (func $internal4355))
+  (import "env" "longname4356" (func $internal4356))
+  (import "env" "longname4357" (func $internal4357))
+  (import "env" "longname4358" (func $internal4358))
+  (import "env" "longname4359" (func $internal4359))
+  (import "env" "longname4360" (func $internal4360))
+  (import "env" "longname4361" (func $internal4361))
+  (import "env" "longname4362" (func $internal4362))
+  (import "env" "longname4363" (func $internal4363))
+  (import "env" "longname4364" (func $internal4364))
+  (import "env" "longname4365" (func $internal4365))
+  (import "env" "longname4366" (func $internal4366))
+  (import "env" "longname4367" (func $internal4367))
+  (import "env" "longname4368" (func $internal4368))
+  (import "env" "longname4369" (func $internal4369))
+  (import "env" "longname4370" (func $internal4370))
+  (import "env" "longname4371" (func $internal4371))
+  (import "env" "longname4372" (func $internal4372))
+  (import "env" "longname4373" (func $internal4373))
+  (import "env" "longname4374" (func $internal4374))
+  (import "env" "longname4375" (func $internal4375))
+  (import "env" "longname4376" (func $internal4376))
+  (import "env" "longname4377" (func $internal4377))
+  (import "env" "longname4378" (func $internal4378))
+  (import "env" "longname4379" (func $internal4379))
+  (import "env" "longname4380" (func $internal4380))
+  (import "env" "longname4381" (func $internal4381))
+  (import "env" "longname4382" (func $internal4382))
+  (import "env" "longname4383" (func $internal4383))
+  (import "env" "longname4384" (func $internal4384))
+  (import "env" "longname4385" (func $internal4385))
+  (import "env" "longname4386" (func $internal4386))
+  (import "env" "longname4387" (func $internal4387))
+  (import "env" "longname4388" (func $internal4388))
+  (import "env" "longname4389" (func $internal4389))
+  (import "env" "longname4390" (func $internal4390))
+  (import "env" "longname4391" (func $internal4391))
+  (import "env" "longname4392" (func $internal4392))
+  (import "env" "longname4393" (func $internal4393))
+  (import "env" "longname4394" (func $internal4394))
+  (import "env" "longname4395" (func $internal4395))
+  (import "env" "longname4396" (func $internal4396))
+  (import "env" "longname4397" (func $internal4397))
+  (import "env" "longname4398" (func $internal4398))
+  (import "env" "longname4399" (func $internal4399))
+  (import "env" "longname4400" (func $internal4400))
+  (import "env" "longname4401" (func $internal4401))
+  (import "env" "longname4402" (func $internal4402))
+  (import "env" "longname4403" (func $internal4403))
+  (import "env" "longname4404" (func $internal4404))
+  (import "env" "longname4405" (func $internal4405))
+  (import "env" "longname4406" (func $internal4406))
+  (import "env" "longname4407" (func $internal4407))
+  (import "env" "longname4408" (func $internal4408))
+  (import "env" "longname4409" (func $internal4409))
+  (import "env" "longname4410" (func $internal4410))
+  (import "env" "longname4411" (func $internal4411))
+  (import "env" "longname4412" (func $internal4412))
+  (import "env" "longname4413" (func $internal4413))
+  (import "env" "longname4414" (func $internal4414))
+  (import "env" "longname4415" (func $internal4415))
+  (import "env" "longname4416" (func $internal4416))
+  (import "env" "longname4417" (func $internal4417))
+  (import "env" "longname4418" (func $internal4418))
+  (import "env" "longname4419" (func $internal4419))
+  (import "env" "longname4420" (func $internal4420))
+  (import "env" "longname4421" (func $internal4421))
+  (import "env" "longname4422" (func $internal4422))
+  (import "env" "longname4423" (func $internal4423))
+  (import "env" "longname4424" (func $internal4424))
+  (import "env" "longname4425" (func $internal4425))
+  (import "env" "longname4426" (func $internal4426))
+  (import "env" "longname4427" (func $internal4427))
+  (import "env" "longname4428" (func $internal4428))
+  (import "env" "longname4429" (func $internal4429))
+  (import "env" "longname4430" (func $internal4430))
+  (import "env" "longname4431" (func $internal4431))
+  (import "env" "longname4432" (func $internal4432))
+  (import "env" "longname4433" (func $internal4433))
+  (import "env" "longname4434" (func $internal4434))
+  (import "env" "longname4435" (func $internal4435))
+  (import "env" "longname4436" (func $internal4436))
+  (import "env" "longname4437" (func $internal4437))
+  (import "env" "longname4438" (func $internal4438))
+  (import "env" "longname4439" (func $internal4439))
+  (import "env" "longname4440" (func $internal4440))
+  (import "env" "longname4441" (func $internal4441))
+  (import "env" "longname4442" (func $internal4442))
+  (import "env" "longname4443" (func $internal4443))
+  (import "env" "longname4444" (func $internal4444))
+  (import "env" "longname4445" (func $internal4445))
+  (import "env" "longname4446" (func $internal4446))
+  (import "env" "longname4447" (func $internal4447))
+  (import "env" "longname4448" (func $internal4448))
+  (import "env" "longname4449" (func $internal4449))
+  (import "env" "longname4450" (func $internal4450))
+  (import "env" "longname4451" (func $internal4451))
+  (import "env" "longname4452" (func $internal4452))
+  (import "env" "longname4453" (func $internal4453))
+  (import "env" "longname4454" (func $internal4454))
+  (import "env" "longname4455" (func $internal4455))
+  (import "env" "longname4456" (func $internal4456))
+  (import "env" "longname4457" (func $internal4457))
+  (import "env" "longname4458" (func $internal4458))
+  (import "env" "longname4459" (func $internal4459))
+  (import "env" "longname4460" (func $internal4460))
+  (import "env" "longname4461" (func $internal4461))
+  (import "env" "longname4462" (func $internal4462))
+  (import "env" "longname4463" (func $internal4463))
+  (import "env" "longname4464" (func $internal4464))
+  (import "env" "longname4465" (func $internal4465))
+  (import "env" "longname4466" (func $internal4466))
+  (import "env" "longname4467" (func $internal4467))
+  (import "env" "longname4468" (func $internal4468))
+  (import "env" "longname4469" (func $internal4469))
+  (import "env" "longname4470" (func $internal4470))
+  (import "env" "longname4471" (func $internal4471))
+  (import "env" "longname4472" (func $internal4472))
+  (import "env" "longname4473" (func $internal4473))
+  (import "env" "longname4474" (func $internal4474))
+  (import "env" "longname4475" (func $internal4475))
+  (import "env" "longname4476" (func $internal4476))
+  (import "env" "longname4477" (func $internal4477))
+  (import "env" "longname4478" (func $internal4478))
+  (import "env" "longname4479" (func $internal4479))
+  (import "env" "longname4480" (func $internal4480))
+  (import "env" "longname4481" (func $internal4481))
+  (import "env" "longname4482" (func $internal4482))
+  (import "env" "longname4483" (func $internal4483))
+  (import "env" "longname4484" (func $internal4484))
+  (import "env" "longname4485" (func $internal4485))
+  (import "env" "longname4486" (func $internal4486))
+  (import "env" "longname4487" (func $internal4487))
+  (import "env" "longname4488" (func $internal4488))
+  (import "env" "longname4489" (func $internal4489))
+  (import "env" "longname4490" (func $internal4490))
+  (import "env" "longname4491" (func $internal4491))
+  (import "env" "longname4492" (func $internal4492))
+  (import "env" "longname4493" (func $internal4493))
+  (import "env" "longname4494" (func $internal4494))
+  (import "env" "longname4495" (func $internal4495))
+  (import "env" "longname4496" (func $internal4496))
+  (import "env" "longname4497" (func $internal4497))
+  (import "env" "longname4498" (func $internal4498))
+  (import "env" "longname4499" (func $internal4499))
+  (import "env" "longname4500" (func $internal4500))
+  (import "env" "longname4501" (func $internal4501))
+  (import "env" "longname4502" (func $internal4502))
+  (import "env" "longname4503" (func $internal4503))
+  (import "env" "longname4504" (func $internal4504))
+  (import "env" "longname4505" (func $internal4505))
+  (import "env" "longname4506" (func $internal4506))
+  (import "env" "longname4507" (func $internal4507))
+  (import "env" "longname4508" (func $internal4508))
+  (import "env" "longname4509" (func $internal4509))
+  (import "env" "longname4510" (func $internal4510))
+  (import "env" "longname4511" (func $internal4511))
+  (import "env" "longname4512" (func $internal4512))
+  (import "env" "longname4513" (func $internal4513))
+  (import "env" "longname4514" (func $internal4514))
+  (import "env" "longname4515" (func $internal4515))
+  (import "env" "longname4516" (func $internal4516))
+  (import "env" "longname4517" (func $internal4517))
+  (import "env" "longname4518" (func $internal4518))
+  (import "env" "longname4519" (func $internal4519))
+  (import "env" "longname4520" (func $internal4520))
+  (import "env" "longname4521" (func $internal4521))
+  (import "env" "longname4522" (func $internal4522))
+  (import "env" "longname4523" (func $internal4523))
+  (import "env" "longname4524" (func $internal4524))
+  (import "env" "longname4525" (func $internal4525))
+  (import "env" "longname4526" (func $internal4526))
+  (import "env" "longname4527" (func $internal4527))
+  (import "env" "longname4528" (func $internal4528))
+  (import "env" "longname4529" (func $internal4529))
+  (import "env" "longname4530" (func $internal4530))
+  (import "env" "longname4531" (func $internal4531))
+  (import "env" "longname4532" (func $internal4532))
+  (import "env" "longname4533" (func $internal4533))
+  (import "env" "longname4534" (func $internal4534))
+  (import "env" "longname4535" (func $internal4535))
+  (import "env" "longname4536" (func $internal4536))
+  (import "env" "longname4537" (func $internal4537))
+  (import "env" "longname4538" (func $internal4538))
+  (import "env" "longname4539" (func $internal4539))
+  (import "env" "longname4540" (func $internal4540))
+  (import "env" "longname4541" (func $internal4541))
+  (import "env" "longname4542" (func $internal4542))
+  (import "env" "longname4543" (func $internal4543))
+  (import "env" "longname4544" (func $internal4544))
+  (import "env" "longname4545" (func $internal4545))
+  (import "env" "longname4546" (func $internal4546))
+  (import "env" "longname4547" (func $internal4547))
+  (import "env" "longname4548" (func $internal4548))
+  (import "env" "longname4549" (func $internal4549))
+  (import "env" "longname4550" (func $internal4550))
+  (import "env" "longname4551" (func $internal4551))
+  (import "env" "longname4552" (func $internal4552))
+  (import "env" "longname4553" (func $internal4553))
+  (import "env" "longname4554" (func $internal4554))
+  (import "env" "longname4555" (func $internal4555))
+  (import "env" "longname4556" (func $internal4556))
+  (import "env" "longname4557" (func $internal4557))
+  (import "env" "longname4558" (func $internal4558))
+  (import "env" "longname4559" (func $internal4559))
+  (import "env" "longname4560" (func $internal4560))
+  (import "env" "longname4561" (func $internal4561))
+  (import "env" "longname4562" (func $internal4562))
+  (import "env" "longname4563" (func $internal4563))
+  (import "env" "longname4564" (func $internal4564))
+  (import "env" "longname4565" (func $internal4565))
+  (import "env" "longname4566" (func $internal4566))
+  (import "env" "longname4567" (func $internal4567))
+  (import "env" "longname4568" (func $internal4568))
+  (import "env" "longname4569" (func $internal4569))
+  (import "env" "longname4570" (func $internal4570))
+  (import "env" "longname4571" (func $internal4571))
+  (import "env" "longname4572" (func $internal4572))
+  (import "env" "longname4573" (func $internal4573))
+  (import "env" "longname4574" (func $internal4574))
+  (import "env" "longname4575" (func $internal4575))
+  (import "env" "longname4576" (func $internal4576))
+  (import "env" "longname4577" (func $internal4577))
+  (import "env" "longname4578" (func $internal4578))
+  (import "env" "longname4579" (func $internal4579))
+  (import "env" "longname4580" (func $internal4580))
+  (import "env" "longname4581" (func $internal4581))
+  (import "env" "longname4582" (func $internal4582))
+  (import "env" "longname4583" (func $internal4583))
+  (import "env" "longname4584" (func $internal4584))
+  (import "env" "longname4585" (func $internal4585))
+  (import "env" "longname4586" (func $internal4586))
+  (import "env" "longname4587" (func $internal4587))
+  (import "env" "longname4588" (func $internal4588))
+  (import "env" "longname4589" (func $internal4589))
+  (import "env" "longname4590" (func $internal4590))
+  (import "env" "longname4591" (func $internal4591))
+  (import "env" "longname4592" (func $internal4592))
+  (import "env" "longname4593" (func $internal4593))
+  (import "env" "longname4594" (func $internal4594))
+  (import "env" "longname4595" (func $internal4595))
+  (import "env" "longname4596" (func $internal4596))
+  (import "env" "longname4597" (func $internal4597))
+  (import "env" "longname4598" (func $internal4598))
+  (import "env" "longname4599" (func $internal4599))
+  (import "env" "longname4600" (func $internal4600))
+  (import "env" "longname4601" (func $internal4601))
+  (import "env" "longname4602" (func $internal4602))
+  (import "env" "longname4603" (func $internal4603))
+  (import "env" "longname4604" (func $internal4604))
+  (import "env" "longname4605" (func $internal4605))
+  (import "env" "longname4606" (func $internal4606))
+  (import "env" "longname4607" (func $internal4607))
+  (import "env" "longname4608" (func $internal4608))
+  (import "env" "longname4609" (func $internal4609))
+  (import "env" "longname4610" (func $internal4610))
+  (import "env" "longname4611" (func $internal4611))
+  (import "env" "longname4612" (func $internal4612))
+  (import "env" "longname4613" (func $internal4613))
+  (import "env" "longname4614" (func $internal4614))
+  (import "env" "longname4615" (func $internal4615))
+  (import "env" "longname4616" (func $internal4616))
+  (import "env" "longname4617" (func $internal4617))
+  (import "env" "longname4618" (func $internal4618))
+  (import "env" "longname4619" (func $internal4619))
+  (import "env" "longname4620" (func $internal4620))
+  (import "env" "longname4621" (func $internal4621))
+  (import "env" "longname4622" (func $internal4622))
+  (import "env" "longname4623" (func $internal4623))
+  (import "env" "longname4624" (func $internal4624))
+  (import "env" "longname4625" (func $internal4625))
+  (import "env" "longname4626" (func $internal4626))
+  (import "env" "longname4627" (func $internal4627))
+  (import "env" "longname4628" (func $internal4628))
+  (import "env" "longname4629" (func $internal4629))
+  (import "env" "longname4630" (func $internal4630))
+  (import "env" "longname4631" (func $internal4631))
+  (import "env" "longname4632" (func $internal4632))
+  (import "env" "longname4633" (func $internal4633))
+  (import "env" "longname4634" (func $internal4634))
+  (import "env" "longname4635" (func $internal4635))
+  (import "env" "longname4636" (func $internal4636))
+  (import "env" "longname4637" (func $internal4637))
+  (import "env" "longname4638" (func $internal4638))
+  (import "env" "longname4639" (func $internal4639))
+  (import "env" "longname4640" (func $internal4640))
+  (import "env" "longname4641" (func $internal4641))
+  (import "env" "longname4642" (func $internal4642))
+  (import "env" "longname4643" (func $internal4643))
+  (import "env" "longname4644" (func $internal4644))
+  (import "env" "longname4645" (func $internal4645))
+  (import "env" "longname4646" (func $internal4646))
+  (import "env" "longname4647" (func $internal4647))
+  (import "env" "longname4648" (func $internal4648))
+  (import "env" "longname4649" (func $internal4649))
+  (import "env" "longname4650" (func $internal4650))
+  (import "env" "longname4651" (func $internal4651))
+  (import "env" "longname4652" (func $internal4652))
+  (import "env" "longname4653" (func $internal4653))
+  (import "env" "longname4654" (func $internal4654))
+  (import "env" "longname4655" (func $internal4655))
+  (import "env" "longname4656" (func $internal4656))
+  (import "env" "longname4657" (func $internal4657))
+  (import "env" "longname4658" (func $internal4658))
+  (import "env" "longname4659" (func $internal4659))
+  (import "env" "longname4660" (func $internal4660))
+  (import "env" "longname4661" (func $internal4661))
+  (import "env" "longname4662" (func $internal4662))
+  (import "env" "longname4663" (func $internal4663))
+  (import "env" "longname4664" (func $internal4664))
+  (import "env" "longname4665" (func $internal4665))
+  (import "env" "longname4666" (func $internal4666))
+  (import "env" "longname4667" (func $internal4667))
+  (import "env" "longname4668" (func $internal4668))
+  (import "env" "longname4669" (func $internal4669))
+  (import "env" "longname4670" (func $internal4670))
+  (import "env" "longname4671" (func $internal4671))
+  (import "env" "longname4672" (func $internal4672))
+  (import "env" "longname4673" (func $internal4673))
+  (import "env" "longname4674" (func $internal4674))
+  (import "env" "longname4675" (func $internal4675))
+  (import "env" "longname4676" (func $internal4676))
+  (import "env" "longname4677" (func $internal4677))
+  (import "env" "longname4678" (func $internal4678))
+  (import "env" "longname4679" (func $internal4679))
+  (import "env" "longname4680" (func $internal4680))
+  (import "env" "longname4681" (func $internal4681))
+  (import "env" "longname4682" (func $internal4682))
+  (import "env" "longname4683" (func $internal4683))
+  (import "env" "longname4684" (func $internal4684))
+  (import "env" "longname4685" (func $internal4685))
+  (import "env" "longname4686" (func $internal4686))
+  (import "env" "longname4687" (func $internal4687))
+  (import "env" "longname4688" (func $internal4688))
+  (import "env" "longname4689" (func $internal4689))
+  (import "env" "longname4690" (func $internal4690))
+  (import "env" "longname4691" (func $internal4691))
+  (import "env" "longname4692" (func $internal4692))
+  (import "env" "longname4693" (func $internal4693))
+  (import "env" "longname4694" (func $internal4694))
+  (import "env" "longname4695" (func $internal4695))
+  (import "env" "longname4696" (func $internal4696))
+  (import "env" "longname4697" (func $internal4697))
+  (import "env" "longname4698" (func $internal4698))
+  (import "env" "longname4699" (func $internal4699))
+  (import "env" "longname4700" (func $internal4700))
+  (import "env" "longname4701" (func $internal4701))
+  (import "env" "longname4702" (func $internal4702))
+  (import "env" "longname4703" (func $internal4703))
+  (import "env" "longname4704" (func $internal4704))
+  (import "env" "longname4705" (func $internal4705))
+  (import "env" "longname4706" (func $internal4706))
+  (import "env" "longname4707" (func $internal4707))
+  (import "env" "longname4708" (func $internal4708))
+  (import "env" "longname4709" (func $internal4709))
+  (import "env" "longname4710" (func $internal4710))
+  (import "env" "longname4711" (func $internal4711))
+  (import "env" "longname4712" (func $internal4712))
+  (import "env" "longname4713" (func $internal4713))
+  (import "env" "longname4714" (func $internal4714))
+  (import "env" "longname4715" (func $internal4715))
+  (import "env" "longname4716" (func $internal4716))
+  (import "env" "longname4717" (func $internal4717))
+  (import "env" "longname4718" (func $internal4718))
+  (import "env" "longname4719" (func $internal4719))
+  (import "env" "longname4720" (func $internal4720))
+  (import "env" "longname4721" (func $internal4721))
+  (import "env" "longname4722" (func $internal4722))
+  (import "env" "longname4723" (func $internal4723))
+  (import "env" "longname4724" (func $internal4724))
+  (import "env" "longname4725" (func $internal4725))
+  (import "env" "longname4726" (func $internal4726))
+  (import "env" "longname4727" (func $internal4727))
+  (import "env" "longname4728" (func $internal4728))
+  (import "env" "longname4729" (func $internal4729))
+  (import "env" "longname4730" (func $internal4730))
+  (import "env" "longname4731" (func $internal4731))
+  (import "env" "longname4732" (func $internal4732))
+  (import "env" "longname4733" (func $internal4733))
+  (import "env" "longname4734" (func $internal4734))
+  (import "env" "longname4735" (func $internal4735))
+  (import "env" "longname4736" (func $internal4736))
+  (import "env" "longname4737" (func $internal4737))
+  (import "env" "longname4738" (func $internal4738))
+  (import "env" "longname4739" (func $internal4739))
+  (import "env" "longname4740" (func $internal4740))
+  (import "env" "longname4741" (func $internal4741))
+  (import "env" "longname4742" (func $internal4742))
+  (import "env" "longname4743" (func $internal4743))
+  (import "env" "longname4744" (func $internal4744))
+  (import "env" "longname4745" (func $internal4745))
+  (import "env" "longname4746" (func $internal4746))
+  (import "env" "longname4747" (func $internal4747))
+  (import "env" "longname4748" (func $internal4748))
+  (import "env" "longname4749" (func $internal4749))
+  (import "env" "longname4750" (func $internal4750))
+  (import "env" "longname4751" (func $internal4751))
+  (import "env" "longname4752" (func $internal4752))
+  (import "env" "longname4753" (func $internal4753))
+  (import "env" "longname4754" (func $internal4754))
+  (import "env" "longname4755" (func $internal4755))
+  (import "env" "longname4756" (func $internal4756))
+  (import "env" "longname4757" (func $internal4757))
+  (import "env" "longname4758" (func $internal4758))
+  (import "env" "longname4759" (func $internal4759))
+  (import "env" "longname4760" (func $internal4760))
+  (import "env" "longname4761" (func $internal4761))
+  (import "env" "longname4762" (func $internal4762))
+  (import "env" "longname4763" (func $internal4763))
+  (import "env" "longname4764" (func $internal4764))
+  (import "env" "longname4765" (func $internal4765))
+  (import "env" "longname4766" (func $internal4766))
+  (import "env" "longname4767" (func $internal4767))
+  (import "env" "longname4768" (func $internal4768))
+  (import "env" "longname4769" (func $internal4769))
+  (import "env" "longname4770" (func $internal4770))
+  (import "env" "longname4771" (func $internal4771))
+  (import "env" "longname4772" (func $internal4772))
+  (import "env" "longname4773" (func $internal4773))
+  (import "env" "longname4774" (func $internal4774))
+  (import "env" "longname4775" (func $internal4775))
+  (import "env" "longname4776" (func $internal4776))
+  (import "env" "longname4777" (func $internal4777))
+  (import "env" "longname4778" (func $internal4778))
+  (import "env" "longname4779" (func $internal4779))
+  (import "env" "longname4780" (func $internal4780))
+  (import "env" "longname4781" (func $internal4781))
+  (import "env" "longname4782" (func $internal4782))
+  (import "env" "longname4783" (func $internal4783))
+  (import "env" "longname4784" (func $internal4784))
+  (import "env" "longname4785" (func $internal4785))
+  (import "env" "longname4786" (func $internal4786))
+  (import "env" "longname4787" (func $internal4787))
+  (import "env" "longname4788" (func $internal4788))
+  (import "env" "longname4789" (func $internal4789))
+  (import "env" "longname4790" (func $internal4790))
+  (import "env" "longname4791" (func $internal4791))
+  (import "env" "longname4792" (func $internal4792))
+  (import "env" "longname4793" (func $internal4793))
+  (import "env" "longname4794" (func $internal4794))
+  (import "env" "longname4795" (func $internal4795))
+  (import "env" "longname4796" (func $internal4796))
+  (import "env" "longname4797" (func $internal4797))
+  (import "env" "longname4798" (func $internal4798))
+  (import "env" "longname4799" (func $internal4799))
+  (import "env" "longname4800" (func $internal4800))
+  (import "env" "longname4801" (func $internal4801))
+  (import "env" "longname4802" (func $internal4802))
+  (import "env" "longname4803" (func $internal4803))
+  (import "env" "longname4804" (func $internal4804))
+  (import "env" "longname4805" (func $internal4805))
+  (import "env" "longname4806" (func $internal4806))
+  (import "env" "longname4807" (func $internal4807))
+  (import "env" "longname4808" (func $internal4808))
+  (import "env" "longname4809" (func $internal4809))
+  (import "env" "longname4810" (func $internal4810))
+  (import "env" "longname4811" (func $internal4811))
+  (import "env" "longname4812" (func $internal4812))
+  (import "env" "longname4813" (func $internal4813))
+  (import "env" "longname4814" (func $internal4814))
+  (import "env" "longname4815" (func $internal4815))
+  (import "env" "longname4816" (func $internal4816))
+  (import "env" "longname4817" (func $internal4817))
+  (import "env" "longname4818" (func $internal4818))
+  (import "env" "longname4819" (func $internal4819))
+  (import "env" "longname4820" (func $internal4820))
+  (import "env" "longname4821" (func $internal4821))
+  (import "env" "longname4822" (func $internal4822))
+  (import "env" "longname4823" (func $internal4823))
+  (import "env" "longname4824" (func $internal4824))
+  (import "env" "longname4825" (func $internal4825))
+  (import "env" "longname4826" (func $internal4826))
+  (import "env" "longname4827" (func $internal4827))
+  (import "env" "longname4828" (func $internal4828))
+  (import "env" "longname4829" (func $internal4829))
+  (import "env" "longname4830" (func $internal4830))
+  (import "env" "longname4831" (func $internal4831))
+  (import "env" "longname4832" (func $internal4832))
+  (import "env" "longname4833" (func $internal4833))
+  (import "env" "longname4834" (func $internal4834))
+  (import "env" "longname4835" (func $internal4835))
+  (import "env" "longname4836" (func $internal4836))
+  (import "env" "longname4837" (func $internal4837))
+  (import "env" "longname4838" (func $internal4838))
+  (import "env" "longname4839" (func $internal4839))
+  (import "env" "longname4840" (func $internal4840))
+  (import "env" "longname4841" (func $internal4841))
+  (import "env" "longname4842" (func $internal4842))
+  (import "env" "longname4843" (func $internal4843))
+  (import "env" "longname4844" (func $internal4844))
+  (import "env" "longname4845" (func $internal4845))
+  (import "env" "longname4846" (func $internal4846))
+  (import "env" "longname4847" (func $internal4847))
+  (import "env" "longname4848" (func $internal4848))
+  (import "env" "longname4849" (func $internal4849))
+  (import "env" "longname4850" (func $internal4850))
+  (import "env" "longname4851" (func $internal4851))
+  (import "env" "longname4852" (func $internal4852))
+  (import "env" "longname4853" (func $internal4853))
+  (import "env" "longname4854" (func $internal4854))
+  (import "env" "longname4855" (func $internal4855))
+  (import "env" "longname4856" (func $internal4856))
+  (import "env" "longname4857" (func $internal4857))
+  (import "env" "longname4858" (func $internal4858))
+  (import "env" "longname4859" (func $internal4859))
+  (import "env" "longname4860" (func $internal4860))
+  (import "env" "longname4861" (func $internal4861))
+  (import "env" "longname4862" (func $internal4862))
+  (import "env" "longname4863" (func $internal4863))
+  (import "env" "longname4864" (func $internal4864))
+  (import "env" "longname4865" (func $internal4865))
+  (import "env" "longname4866" (func $internal4866))
+  (import "env" "longname4867" (func $internal4867))
+  (import "env" "longname4868" (func $internal4868))
+  (import "env" "longname4869" (func $internal4869))
+  (import "env" "longname4870" (func $internal4870))
+  (import "env" "longname4871" (func $internal4871))
+  (import "env" "longname4872" (func $internal4872))
+  (import "env" "longname4873" (func $internal4873))
+  (import "env" "longname4874" (func $internal4874))
+  (import "env" "longname4875" (func $internal4875))
+  (import "env" "longname4876" (func $internal4876))
+  (import "env" "longname4877" (func $internal4877))
+  (import "env" "longname4878" (func $internal4878))
+  (import "env" "longname4879" (func $internal4879))
+  (import "env" "longname4880" (func $internal4880))
+  (import "env" "longname4881" (func $internal4881))
+  (import "env" "longname4882" (func $internal4882))
+  (import "env" "longname4883" (func $internal4883))
+  (import "env" "longname4884" (func $internal4884))
+  (import "env" "longname4885" (func $internal4885))
+  (import "env" "longname4886" (func $internal4886))
+  (import "env" "longname4887" (func $internal4887))
+  (import "env" "longname4888" (func $internal4888))
+  (import "env" "longname4889" (func $internal4889))
+  (import "env" "longname4890" (func $internal4890))
+  (import "env" "longname4891" (func $internal4891))
+  (import "env" "longname4892" (func $internal4892))
+  (import "env" "longname4893" (func $internal4893))
+  (import "env" "longname4894" (func $internal4894))
+  (import "env" "longname4895" (func $internal4895))
+  (import "env" "longname4896" (func $internal4896))
+  (import "env" "longname4897" (func $internal4897))
+  (import "env" "longname4898" (func $internal4898))
+  (import "env" "longname4899" (func $internal4899))
+  (import "env" "longname4900" (func $internal4900))
+  (import "env" "longname4901" (func $internal4901))
+  (import "env" "longname4902" (func $internal4902))
+  (import "env" "longname4903" (func $internal4903))
+  (import "env" "longname4904" (func $internal4904))
+  (import "env" "longname4905" (func $internal4905))
+  (import "env" "longname4906" (func $internal4906))
+  (import "env" "longname4907" (func $internal4907))
+  (import "env" "longname4908" (func $internal4908))
+  (import "env" "longname4909" (func $internal4909))
+  (import "env" "longname4910" (func $internal4910))
+  (import "env" "longname4911" (func $internal4911))
+  (import "env" "longname4912" (func $internal4912))
+  (import "env" "longname4913" (func $internal4913))
+  (import "env" "longname4914" (func $internal4914))
+  (import "env" "longname4915" (func $internal4915))
+  (import "env" "longname4916" (func $internal4916))
+  (import "env" "longname4917" (func $internal4917))
+  (import "env" "longname4918" (func $internal4918))
+  (import "env" "longname4919" (func $internal4919))
+  (import "env" "longname4920" (func $internal4920))
+  (import "env" "longname4921" (func $internal4921))
+  (import "env" "longname4922" (func $internal4922))
+  (import "env" "longname4923" (func $internal4923))
+  (import "env" "longname4924" (func $internal4924))
+  (import "env" "longname4925" (func $internal4925))
+  (import "env" "longname4926" (func $internal4926))
+  (import "env" "longname4927" (func $internal4927))
+  (import "env" "longname4928" (func $internal4928))
+  (import "env" "longname4929" (func $internal4929))
+  (import "env" "longname4930" (func $internal4930))
+  (import "env" "longname4931" (func $internal4931))
+  (import "env" "longname4932" (func $internal4932))
+  (import "env" "longname4933" (func $internal4933))
+  (import "env" "longname4934" (func $internal4934))
+  (import "env" "longname4935" (func $internal4935))
+  (import "env" "longname4936" (func $internal4936))
+  (import "env" "longname4937" (func $internal4937))
+  (import "env" "longname4938" (func $internal4938))
+  (import "env" "longname4939" (func $internal4939))
+  (import "env" "longname4940" (func $internal4940))
+  (import "env" "longname4941" (func $internal4941))
+  (import "env" "longname4942" (func $internal4942))
+  (import "env" "longname4943" (func $internal4943))
+  (import "env" "longname4944" (func $internal4944))
+  (import "env" "longname4945" (func $internal4945))
+  (import "env" "longname4946" (func $internal4946))
+  (import "env" "longname4947" (func $internal4947))
+  (import "env" "longname4948" (func $internal4948))
+  (import "env" "longname4949" (func $internal4949))
+  (import "env" "longname4950" (func $internal4950))
+  (import "env" "longname4951" (func $internal4951))
+  (import "env" "longname4952" (func $internal4952))
+  (import "env" "longname4953" (func $internal4953))
+  (import "env" "longname4954" (func $internal4954))
+  (import "env" "longname4955" (func $internal4955))
+  (import "env" "longname4956" (func $internal4956))
+  (import "env" "longname4957" (func $internal4957))
+  (import "env" "longname4958" (func $internal4958))
+  (import "env" "longname4959" (func $internal4959))
+  (import "env" "longname4960" (func $internal4960))
+  (import "env" "longname4961" (func $internal4961))
+  (import "env" "longname4962" (func $internal4962))
+  (import "env" "longname4963" (func $internal4963))
+  (import "env" "longname4964" (func $internal4964))
+  (import "env" "longname4965" (func $internal4965))
+  (import "env" "longname4966" (func $internal4966))
+  (import "env" "longname4967" (func $internal4967))
+  (import "env" "longname4968" (func $internal4968))
+  (import "env" "longname4969" (func $internal4969))
+  (import "env" "longname4970" (func $internal4970))
+  (import "env" "longname4971" (func $internal4971))
+  (import "env" "longname4972" (func $internal4972))
+  (import "env" "longname4973" (func $internal4973))
+  (import "env" "longname4974" (func $internal4974))
+  (import "env" "longname4975" (func $internal4975))
+  (import "env" "longname4976" (func $internal4976))
+  (import "env" "longname4977" (func $internal4977))
+  (import "env" "longname4978" (func $internal4978))
+  (import "env" "longname4979" (func $internal4979))
+  (import "env" "longname4980" (func $internal4980))
+  (import "env" "longname4981" (func $internal4981))
+  (import "env" "longname4982" (func $internal4982))
+  (import "env" "longname4983" (func $internal4983))
+  (import "env" "longname4984" (func $internal4984))
+  (import "env" "longname4985" (func $internal4985))
+  (import "env" "longname4986" (func $internal4986))
+  (import "env" "longname4987" (func $internal4987))
+  (import "env" "longname4988" (func $internal4988))
+  (import "env" "longname4989" (func $internal4989))
+  (import "env" "longname4990" (func $internal4990))
+  (import "env" "longname4991" (func $internal4991))
+  (import "env" "longname4992" (func $internal4992))
+  (import "env" "longname4993" (func $internal4993))
+  (import "env" "longname4994" (func $internal4994))
+  (import "env" "longname4995" (func $internal4995))
+  (import "env" "longname4996" (func $internal4996))
+  (import "env" "longname4997" (func $internal4997))
+  (import "env" "longname4998" (func $internal4998))
+  (import "env" "longname4999" (func $internal4999))
+  (import "env" "__memory_base" (global i32))
+  (import "env" "__table_base" (global i32))
+  (import "other" "anything" (func $internalInfinity))
+  (import "env" "eventname1" (event $eventname1 (attr 0) (param i32)))
+  (export "foo1" (func $foo1))
+  (export "foo2" (func $foo2))
+  (export "event1" (event $event1))
+  (func $foo1)
+  (func $foo2)
+  (event $event1 (attr 0) (param i32 i32))
+)
diff --git a/binaryen/test/passes/multi_line_table_dwarf.bin.txt b/binaryen/test/passes/multi_line_table_dwarf.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/multi_line_table_dwarf.bin.txt
@@ -0,0 +1,479 @@
+DWARF debug info
+================
+
+Contains section .debug_info (130 bytes)
+Contains section .debug_abbrev (100 bytes)
+Contains section .debug_line (121 bytes)
+Contains section .debug_str (407 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+[2] DW_TAG_subprogram	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[3] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+Abbrev table for offset: 0x00000032
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+[2] DW_TAG_subprogram	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[3] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x0000003d version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x00000041)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 7fcd9e3f70830a9c4bf631a602c2764180b5c3a8)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000095] = "fourth.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x000000a0] = "/tmp/emscripten_test_wasm0_xkAHBX")
+              DW_AT_low_pc [DW_FORM_addr]	(0x000000000000000a)
+              DW_AT_high_pc [DW_FORM_data4]	(0x0000000b)
+
+0x00000026:   DW_TAG_subprogram [2]  
+                DW_AT_low_pc [DW_FORM_addr]	(0x000000000000000a)
+                DW_AT_high_pc [DW_FORM_data4]	(0x0000000b)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c2] = "sideg")
+                DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm0_xkAHBX/fourth.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(1)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0039 => {0x00000039} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000039:   DW_TAG_base_type [3]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c8] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x00000040:   NULL
+0x00000041: Compile Unit: length = 0x0000003d version = 0x0004 abbr_offset = 0x0032 addr_size = 0x04 (next unit at 0x00000082)
+
+0x0000004c: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x000000cc] = "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 7fcd9e3f70830a9c4bf631a602c2764180b5c3a8)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000161] = "third.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x0000003d)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x0000016b] = "/tmp/emscripten_test_wasm0_xkAHBX")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000016)
+              DW_AT_high_pc [DW_FORM_data4]	(0x0000000b)
+
+0x00000067:   DW_TAG_subprogram [2]  
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000016)
+                DW_AT_high_pc [DW_FORM_data4]	(0x0000000b)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000018d] = "sidef")
+                DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm0_xkAHBX/third.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(1)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0039 => {0x0000007a} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000007a:   DW_TAG_base_type [3]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000193] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x00000081:   NULL
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x00000039
+         version: 4
+ prologue_length: 0x00000022
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "fourth.cpp"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+0x0000002c: 00 DW_LNE_set_address (0x000000000000000a)
+0x00000033: 01 DW_LNS_copy
+            0x000000000000000a      1      0      1   0             0  is_stmt
+
+
+0x00000034: 05 DW_LNS_set_column (26)
+0x00000036: 0a DW_LNS_set_prologue_end
+0x00000037: 74 address += 7,  line += 0
+            0x0000000000000011      1     26      1   0             0  is_stmt prologue_end
+
+0x00000038: 02 DW_LNS_advance_pc (4)
+0x0000003a: 00 DW_LNE_end_sequence
+            0x0000000000000015      1     26      1   0             0  is_stmt end_sequence
+
+debug_line[0x0000003d]
+Line table prologue:
+    total_length: 0x00000038
+         version: 4
+ prologue_length: 0x00000021
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "third.cpp"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000068: 00 DW_LNE_set_address (0x0000000000000016)
+0x0000006f: 01 DW_LNS_copy
+            0x0000000000000016      1      0      1   0             0  is_stmt
+
+
+0x00000070: 05 DW_LNS_set_column (26)
+0x00000072: 0a DW_LNS_set_prologue_end
+0x00000073: 74 address += 7,  line += 0
+            0x000000000000001d      1     26      1   0             0  is_stmt prologue_end
+
+0x00000074: 02 DW_LNS_advance_pc (4)
+0x00000076: 00 DW_LNE_end_sequence
+            0x0000000000000021      1     26      1   0             0  is_stmt end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 7fcd9e3f70830a9c4bf631a602c2764180b5c3a8)"
+0x00000095: "fourth.cpp"
+0x000000a0: "/tmp/emscripten_test_wasm0_xkAHBX"
+0x000000c2: "sideg"
+0x000000c8: "int"
+0x000000cc: "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 7fcd9e3f70830a9c4bf631a602c2764180b5c3a8)"
+0x00000161: "third.cpp"
+0x0000016b: "/tmp/emscripten_test_wasm0_xkAHBX"
+0x0000018d: "sidef"
+0x00000193: "int"
+DWARF debug info
+================
+
+Contains section .debug_info (130 bytes)
+Contains section .debug_abbrev (100 bytes)
+Contains section .debug_line (145 bytes)
+Contains section .debug_str (407 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+[2] DW_TAG_subprogram	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[3] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+Abbrev table for offset: 0x00000032
+[1] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+[2] DW_TAG_subprogram	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[3] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x0000003d version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x00000041)
+
+0x0000000b: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 7fcd9e3f70830a9c4bf631a602c2764180b5c3a8)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000095] = "fourth.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x000000a0] = "/tmp/emscripten_test_wasm0_xkAHBX")
+              DW_AT_low_pc [DW_FORM_addr]	(0x000000000000000a)
+              DW_AT_high_pc [DW_FORM_data4]	(0x0000000b)
+
+0x00000026:   DW_TAG_subprogram [2]  
+                DW_AT_low_pc [DW_FORM_addr]	(0x000000000000000a)
+                DW_AT_high_pc [DW_FORM_data4]	(0x0000000b)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c2] = "sideg")
+                DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm0_xkAHBX/fourth.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(1)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0039 => {0x00000039} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000039:   DW_TAG_base_type [3]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c8] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x00000040:   NULL
+0x00000041: Compile Unit: length = 0x0000003d version = 0x0004 abbr_offset = 0x0032 addr_size = 0x04 (next unit at 0x00000082)
+
+0x0000004c: DW_TAG_compile_unit [1] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x000000cc] = "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 7fcd9e3f70830a9c4bf631a602c2764180b5c3a8)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C_plus_plus)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000161] = "third.cpp")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000049)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x0000016b] = "/tmp/emscripten_test_wasm0_xkAHBX")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000016)
+              DW_AT_high_pc [DW_FORM_data4]	(0x0000000b)
+
+0x00000067:   DW_TAG_subprogram [2]  
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000016)
+                DW_AT_high_pc [DW_FORM_data4]	(0x0000000b)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x0000018d] = "sidef")
+                DW_AT_decl_file [DW_FORM_data1]	("/tmp/emscripten_test_wasm0_xkAHBX/third.cpp")
+                DW_AT_decl_line [DW_FORM_data1]	(1)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0039 => {0x0000007a} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x0000007a:   DW_TAG_base_type [3]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000193] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x00000081:   NULL
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x00000045
+         version: 4
+ prologue_length: 0x00000022
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "fourth.cpp"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+0x0000002c: 00 DW_LNE_set_address (0x000000000000000a)
+0x00000033: 01 DW_LNS_copy
+            0x000000000000000a      1      0      1   0             0  is_stmt
+
+
+0x00000034: 00 DW_LNE_set_address (0x0000000000000011)
+0x0000003b: 05 DW_LNS_set_column (26)
+0x0000003d: 0a DW_LNS_set_prologue_end
+0x0000003e: 01 DW_LNS_copy
+            0x0000000000000011      1     26      1   0             0  is_stmt prologue_end
+
+
+0x0000003f: 00 DW_LNE_set_address (0x0000000000000015)
+0x00000046: 00 DW_LNE_end_sequence
+            0x0000000000000015      1     26      1   0             0  is_stmt end_sequence
+
+debug_line[0x00000049]
+Line table prologue:
+    total_length: 0x00000044
+         version: 4
+ prologue_length: 0x00000021
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+file_names[  1]:
+           name: "third.cpp"
+      dir_index: 0
+       mod_time: 0x00000000
+         length: 0x00000000
+0x00000074: 00 DW_LNE_set_address (0x0000000000000016)
+0x0000007b: 01 DW_LNS_copy
+            0x0000000000000016      1      0      1   0             0  is_stmt
+
+
+0x0000007c: 00 DW_LNE_set_address (0x000000000000001d)
+0x00000083: 05 DW_LNS_set_column (26)
+0x00000085: 0a DW_LNS_set_prologue_end
+0x00000086: 01 DW_LNS_copy
+            0x000000000000001d      1     26      1   0             0  is_stmt prologue_end
+
+
+0x00000087: 00 DW_LNE_set_address (0x0000000000000021)
+0x0000008e: 00 DW_LNE_end_sequence
+            0x0000000000000021      1     26      1   0             0  is_stmt end_sequence
+
+
+.debug_str contents:
+0x00000000: "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 7fcd9e3f70830a9c4bf631a602c2764180b5c3a8)"
+0x00000095: "fourth.cpp"
+0x000000a0: "/tmp/emscripten_test_wasm0_xkAHBX"
+0x000000c2: "sideg"
+0x000000c8: "int"
+0x000000cc: "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 7fcd9e3f70830a9c4bf631a602c2764180b5c3a8)"
+0x00000161: "third.cpp"
+0x0000016b: "/tmp/emscripten_test_wasm0_xkAHBX"
+0x0000018d: "sidef"
+0x00000193: "int"
+(module
+ (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))
+ (global $global$0 i32 (i32.const 0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "__wasm_apply_relocs" (func $__wasm_apply_relocs))
+ (export "sideg" (func $sideg))
+ (export "sidef" (func $sidef))
+ (export "__dso_handle" (global $global$0))
+ (func $__wasm_call_ctors
+  ;; code offset: 0x3
+  (call $__wasm_apply_relocs)
+ )
+ (func $__wasm_apply_relocs
+ )
+ (func $sideg (result i32)
+  (local $0 i32)
+  ;; code offset: 0xf
+  (local.set $0
+   ;; code offset: 0xd
+   (i32.const 17)
+  )
+  ;; code offset: 0x13
+  (return
+   ;; code offset: 0x11
+   (local.get $0)
+  )
+ )
+ (func $sidef (result i32)
+  (local $0 i32)
+  ;; code offset: 0x1b
+  (local.set $0
+   ;; code offset: 0x19
+   (i32.const 36)
+  )
+  ;; code offset: 0x1f
+  (return
+   ;; code offset: 0x1d
+   (local.get $0)
+  )
+ )
+ ;; dylink section
+ ;;   memorysize: 0
+ ;;   memoryalignment: 0
+ ;;   tablesize: 0
+ ;;   tablealignment: 0
+ ;; custom section ".debug_info", size 130
+ ;; custom section ".debug_abbrev", size 100
+ ;; custom section ".debug_line", size 145
+ ;; custom section ".debug_str", size 407
+ ;; custom section "producers", size 180
+)
diff --git a/binaryen/test/passes/multi_line_table_dwarf.passes b/binaryen/test/passes/multi_line_table_dwarf.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/multi_line_table_dwarf.passes
@@ -0,0 +1,1 @@
+g_dwarfdump_roundtrip_dwarfdump_all-features
diff --git a/binaryen/test/passes/multi_line_table_dwarf.wasm b/binaryen/test/passes/multi_line_table_dwarf.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/multi_line_table_dwarf.wasm differ
diff --git a/binaryen/test/passes/multi_unit_abbrev_noprint.bin.txt b/binaryen/test/passes/multi_unit_abbrev_noprint.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/multi_unit_abbrev_noprint.bin.txt
diff --git a/binaryen/test/passes/multi_unit_abbrev_noprint.passes b/binaryen/test/passes/multi_unit_abbrev_noprint.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/multi_unit_abbrev_noprint.passes
@@ -0,0 +1,1 @@
+g_roundtrip_roundtrip_roundtrip
diff --git a/binaryen/test/passes/multi_unit_abbrev_noprint.wasm b/binaryen/test/passes/multi_unit_abbrev_noprint.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/multi_unit_abbrev_noprint.wasm differ
diff --git a/binaryen/test/passes/nm.txt b/binaryen/test/passes/nm.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/nm.txt
@@ -0,0 +1,39 @@
+    a : 1
+    b : 5
+    c : 13
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $a
+  (nop)
+ )
+ (func $b
+  (drop
+   (loop $loop-in1 (result i32)
+    (nop)
+    (i32.const 1000)
+   )
+  )
+ )
+ (func $c
+  (block $top
+   (nop)
+   (drop
+    (i32.const 1000)
+   )
+   (drop
+    (i32.add
+     (i32.add
+      (i32.const 1001)
+      (i32.const 1002)
+     )
+     (i32.add
+      (i32.const 1003)
+      (i32.const 1004)
+     )
+    )
+   )
+   (br $top)
+  )
+ )
+)
diff --git a/binaryen/test/passes/nm.wast b/binaryen/test/passes/nm.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/nm.wast
@@ -0,0 +1,36 @@
+(module
+  (memory 0)
+  (type $0 (func))
+  (func $a (type $0)
+    (nop)
+  )
+  (func $b (type $0)
+    (drop
+      (loop $loop-in1 (result i32)
+        (nop)
+        (i32.const 1000)
+      )
+    )
+  )
+  (func $c (type $0)
+    (block $top
+      (nop)
+      (drop
+        (i32.const 1000)
+      )
+      (drop
+        (i32.add
+          (i32.add
+            (i32.const 1001)
+            (i32.const 1002)
+          )
+          (i32.add
+            (i32.const 1003)
+            (i32.const 1004)
+          )
+        )
+      )
+      (br $top)
+    )
+  )
+)
diff --git a/binaryen/test/passes/no-exit-runtime.txt b/binaryen/test/passes/no-exit-runtime.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/no-exit-runtime.txt
@@ -0,0 +1,166 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "atexit" (func $fimport$0 (param i32 i32) (result i32)))
+ (import "env" "__cxa_atexit" (func $fimport$1 (param i32 i32) (result i32)))
+ (import "env" "_atexit" (func $fimport$2 (param i32 i32) (result i32)))
+ (import "env" "___cxa_atexit" (func $fimport$3 (param i32 i32) (result i32)))
+ (import "env" "other" (func $fimport$4 (param i32 i32) (result i32)))
+ (func $caller
+  (drop
+   (block (result i32)
+    (drop
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 1)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 1)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 1)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 1)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $fimport$4
+    (i32.const 0)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (block
+    (drop
+     (unreachable)
+    )
+    (drop
+     (i32.const 1)
+    )
+    (unreachable)
+   )
+  )
+ )
+ (func $side-effects (result i32)
+  (local $x i32)
+  (drop
+   (block (result i32)
+    (drop
+     (local.tee $x
+      (i32.const 1)
+     )
+    )
+    (drop
+     (i32.const 2)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (i32.const 3)
+    )
+    (drop
+     (local.tee $x
+      (i32.const 4)
+     )
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (local.tee $x
+      (i32.const 5)
+     )
+    )
+    (drop
+     (local.tee $x
+      (i32.const 6)
+     )
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (block
+    (drop
+     (unreachable)
+    )
+    (drop
+     (local.tee $x
+      (i32.const 7)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (drop
+   (block
+    (drop
+     (local.tee $x
+      (i32.const 8)
+     )
+    )
+    (drop
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (drop
+   (block
+    (drop
+     (unreachable)
+    )
+    (drop
+     (i32.const 9)
+    )
+    (unreachable)
+   )
+  )
+  (drop
+   (block
+    (drop
+     (i32.const 10)
+    )
+    (drop
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+  (local.get $x)
+ )
+)
diff --git a/binaryen/test/passes/no-exit-runtime.wast b/binaryen/test/passes/no-exit-runtime.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/no-exit-runtime.wast
@@ -0,0 +1,47 @@
+(module
+  (import "env" "atexit" (func $fimport$0 (param i32 i32) (result i32)))
+  (import "env" "__cxa_atexit" (func $fimport$1 (param i32 i32) (result i32)))
+  (import "env" "_atexit" (func $fimport$2 (param i32 i32) (result i32)))
+  (import "env" "___cxa_atexit" (func $fimport$3 (param i32 i32) (result i32)))
+  (import "env" "other" (func $fimport$4 (param i32 i32) (result i32)))
+  (func $caller
+    (drop (call $fimport$0 (i32.const 0) (i32.const 1)))
+    (drop (call $fimport$1 (i32.const 0) (i32.const 1)))
+    (drop (call $fimport$2 (i32.const 0) (i32.const 1)))
+    (drop (call $fimport$3 (i32.const 0) (i32.const 1)))
+    (drop (call $fimport$4 (i32.const 0) (i32.const 1)))
+    (drop (call $fimport$0 (unreachable) (i32.const 1)))
+  )
+  (func $side-effects (result i32)
+    (local $x i32)
+    (drop (call $fimport$0
+      (local.tee $x (i32.const 1))
+      (i32.const 2)
+    ))
+    (drop (call $fimport$0
+      (i32.const 3)
+      (local.tee $x (i32.const 4))
+    ))
+    (drop (call $fimport$0
+      (local.tee $x (i32.const 5))
+      (local.tee $x (i32.const 6))
+    ))
+    (drop (call $fimport$0
+      (unreachable)
+      (local.tee $x (i32.const 7))
+    ))
+    (drop (call $fimport$0
+      (local.tee $x (i32.const 8))
+      (unreachable)
+    ))
+    (drop (call $fimport$0
+      (unreachable)
+      (i32.const 9)
+    ))
+    (drop (call $fimport$0
+      (i32.const 10)
+      (unreachable)
+    ))
+    (local.get $x)
+  )
+)
diff --git a/binaryen/test/passes/optimize-added-constants-propagate_low-memory-unused.txt b/binaryen/test/passes/optimize-added-constants-propagate_low-memory-unused.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/optimize-added-constants-propagate_low-memory-unused.txt
@@ -0,0 +1,406 @@
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_none (func))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 1 1)
+ (func $consts
+  (drop
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1023)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1023)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1023)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1024)
+   )
+  )
+  (i32.store
+   (i32.const 1)
+   (i32.const 1)
+  )
+ )
+ (func $offsets (param $x i32)
+  (drop
+   (i32.load offset=1
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.load offset=8
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.load offset=1023
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.add
+     (local.get $x)
+     (i32.const 1024)
+    )
+   )
+  )
+  (drop
+   (i32.load
+    (i32.add
+     (local.get $x)
+     (i32.const 2048)
+    )
+   )
+  )
+  (drop
+   (i32.load offset=4
+    (local.get $x)
+   )
+  )
+ )
+ (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=7
+   (local.get $0)
+   (local.get $0)
+  )
+  (i32.store offset=9
+   (local.get $0)
+   (local.get $0)
+  )
+  (i32.store offset=2
+   (i32.add
+    (i32.const -11)
+    (local.get $0)
+   )
+   (local.get $0)
+  )
+  (i32.store offset=2
+   (i32.add
+    (local.get $0)
+    (i32.const -13)
+   )
+   (local.get $0)
+  )
+  (i32.store offset=19
+   (i32.const -15)
+   (local.get $0)
+  )
+  (i32.store offset=21
+   (i32.const -21)
+   (local.get $0)
+  )
+  (i32.store
+   (i32.const 25)
+   (local.get $0)
+  )
+  (i32.store
+   (i32.const -23)
+   (local.get $0)
+  )
+  (drop
+   (i32.load
+    (i32.const 8)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 8)
+   )
+  )
+  (drop
+   (i32.load offset=8
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 10)
+   )
+  )
+  (i32.load offset=12
+   (local.get $0)
+  )
+ )
+ (func $offset-constant
+  (drop
+   (i32.load
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 20)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1023)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1023)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 100511)
+   )
+  )
+ )
+ (func $offset-propagate-param (param $x i32)
+  (local $y i32)
+  (nop)
+  (drop
+   (i32.load offset=1
+    (local.get $y)
+   )
+  )
+ )
+ (func $offset-propagate
+  (local $x i32)
+  (local $y i32)
+  (nop)
+  (drop
+   (i32.load offset=1
+    (local.get $y)
+   )
+  )
+ )
+ (func $offset-propagate2
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.add
+    (local.get $y)
+    (i32.add
+     (i32.const 1)
+     (i32.const 2)
+    )
+   )
+  )
+  (drop
+   (i32.load
+    (local.get $x)
+   )
+  )
+ )
+ (func $offset-propagate3
+  (local $x i32)
+  (local $y i32)
+  (nop)
+  (drop
+   (i32.load offset=1
+    (local.get $y)
+   )
+  )
+ )
+ (func $offset-propagate4
+  (local $x i32)
+  (local $y i32)
+  (local.set $y
+   (i32.const -1)
+  )
+  (nop)
+  (drop
+   (i32.load offset=1
+    (local.get $y)
+   )
+  )
+ )
+ (func $offset-propagate5 (param $z i32)
+  (local $x i32)
+  (local $y i32)
+  (local $3 i32)
+  (if
+   (local.get $z)
+   (local.set $y
+    (i32.const -1)
+   )
+  )
+  (block
+   (local.set $3
+    (local.get $y)
+   )
+   (nop)
+  )
+  (drop
+   (i32.load offset=1
+    (local.get $3)
+   )
+  )
+ )
+ (func $offset-propagate6 (param $z i32)
+  (local $x i32)
+  (local $y i32)
+  (local $3 i32)
+  (local.set $y
+   (local.get $z)
+  )
+  (block
+   (local.set $3
+    (local.get $y)
+   )
+   (nop)
+  )
+  (local.set $y
+   (i32.const -2)
+  )
+  (drop
+   (i32.load offset=1
+    (local.get $3)
+   )
+  )
+ )
+ (func $offset-propagate7 (param $z i32)
+  (local $x i32)
+  (local $y i32)
+  (local.set $y
+   (local.get $z)
+  )
+  (local.set $x
+   (i32.add
+    (i32.const 1)
+    (local.get $y)
+   )
+  )
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.add
+     (i32.const 2)
+     (local.get $y)
+    )
+   )
+  )
+  (drop
+   (i32.load
+    (local.get $x)
+   )
+  )
+ )
+ (func $offset-realistic (param $ptr i32)
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (nop)
+  (nop)
+  (nop)
+  (loop $l
+   (call $offset-realistic
+    (i32.load offset=8
+     (local.get $ptr)
+    )
+   )
+   (call $offset-realistic
+    (i32.load offset=16
+     (local.get $ptr)
+    )
+   )
+   (call $offset-realistic
+    (i32.load offset=16
+     (local.get $ptr)
+    )
+   )
+   (i32.store offset=24
+    (local.get $ptr)
+    (i32.add
+     (i32.load offset=24
+      (local.get $ptr)
+     )
+     (i32.const 1)
+    )
+   )
+   (br_if $l
+    (i32.load offset=24
+     (local.get $ptr)
+    )
+   )
+  )
+ )
+ (func $multiadd (param $sp i32)
+  (local $$vararg_buffer i32)
+  (local $$vararg_ptr1 i32)
+  (nop)
+  (nop)
+  (i32.store offset=20
+   (local.get $sp)
+   (i32.const 1)
+  )
+ )
+ (func $multiadd-extraUse (param $sp i32)
+  (local $$vararg_buffer i32)
+  (local $$vararg_ptr1 i32)
+  (local.set $$vararg_buffer
+   (i32.add
+    (local.get $sp)
+    (i32.const 16)
+   )
+  )
+  (nop)
+  (drop
+   (local.get $$vararg_buffer)
+  )
+  (i32.store offset=4
+   (local.get $$vararg_buffer)
+   (i32.const 1)
+  )
+ )
+)
diff --git a/binaryen/test/passes/optimize-added-constants-propagate_low-memory-unused.wast b/binaryen/test/passes/optimize-added-constants-propagate_low-memory-unused.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/optimize-added-constants-propagate_low-memory-unused.wast
@@ -0,0 +1,459 @@
+(module
+  (memory 1 1)
+  (func $consts
+    (drop
+      (i32.load (i32.const 0))
+    )
+    (drop
+      (i32.load (i32.const 1))
+    )
+    (drop
+      (i32.load (i32.const 1023))
+    )
+    (drop
+      (i32.load (i32.const 1024))
+    )
+    (drop
+      (i32.load offset=0 (i32.const 0))
+    )
+    (drop
+      (i32.load offset=1 (i32.const 0))
+    )
+    (drop
+      (i32.load offset=1023 (i32.const 0))
+    )
+    (drop
+      (i32.load offset=1024 (i32.const 0))
+    )
+    (drop
+      (i32.load offset=512 (i32.const 511))
+    )
+    (drop
+      (i32.load offset=512 (i32.const 512))
+    )
+    (i32.store (i32.const 1) (i32.const 1))
+  )
+  (func $offsets (param $x i32)
+    (drop
+      (i32.load
+        (i32.add
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+    )
+    (drop
+      (i32.load
+        (i32.add
+          (local.get $x)
+          (i32.const 8)
+        )
+      )
+    )
+    (drop
+      (i32.load
+        (i32.add
+          (local.get $x)
+          (i32.const 1023)
+        )
+      )
+    )
+    (drop
+      (i32.load
+        (i32.add
+          (local.get $x)
+          (i32.const 1024)
+        )
+      )
+    )
+    (drop
+      (i32.load
+        (i32.add
+          (local.get $x)
+          (i32.const 2048)
+        )
+      )
+    )
+    (drop
+      (i32.load
+        (i32.add
+          (i32.const 4)
+          (local.get $x)
+        )
+      )
+    )
+  )
+  (func $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 $offset-constant
+    (drop
+      (i32.load offset=10
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.load offset=0
+        (i32.const 10)
+      )
+    )
+    (drop
+      (i32.load offset=10
+        (i32.const 10)
+      )
+    )
+    (drop
+      (i32.load offset=512
+        (i32.const 512)
+      )
+    )
+    (drop
+      (i32.load offset=512
+        (i32.const 511)
+      )
+    )
+    (drop
+      (i32.load offset=511
+        (i32.const 512)
+      )
+    )
+    (drop
+      (i32.load offset=99999
+        (i32.const 512)
+      )
+    )
+  )
+  (func $offset-propagate-param (param $x i32)
+   (local $y i32)
+   (local.set $x
+    (i32.add
+     (local.get $y)
+     (i32.const 1)
+    )
+   )
+   (drop
+    (i32.load
+     (local.get $x)
+    )
+   )
+  )
+  (func $offset-propagate
+   (local $x i32)
+   (local $y i32)
+   (local.set $x
+    (i32.add
+     (local.get $y)
+     (i32.const 1)
+    )
+   )
+   (drop
+    (i32.load
+     (local.get $x)
+    )
+   )
+  )
+  (func $offset-propagate2
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.add
+        (local.get $y)
+        (i32.add
+          (i32.const 1)
+          (i32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.load
+        (local.get $x)
+      )
+    )
+  )
+  (func $offset-propagate3
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.add
+        (i32.const 1)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i32.load
+        (local.get $x)
+      )
+    )
+  )
+  (func $offset-propagate4
+    (local $x i32)
+    (local $y i32)
+    (local.set $y (i32.const -1))
+    (local.set $x
+      (i32.add
+        (i32.const 1)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i32.load
+        (local.get $x)
+      )
+    )
+  )
+  (func $offset-propagate5 (param $z i32)
+    (local $x i32)
+    (local $y i32)
+    (if (local.get $z)
+      (local.set $y (i32.const -1)) ;; y is not ssa
+    )
+    (local.set $x
+      (i32.add
+        (i32.const 1)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i32.load
+        (local.get $x)
+      )
+    )
+  )
+  (func $offset-propagate6 (param $z i32)
+    (local $x i32)
+    (local $y i32)
+    (local.set $y (local.get $z))
+    (local.set $x
+      (i32.add
+        (i32.const 1)
+        (local.get $y)
+      )
+    )
+    (local.set $y (i32.const -2)) ;; y has another set, so not ssa
+    (drop
+      (i32.load
+        (local.get $x)
+      )
+    )
+  )
+  (func $offset-propagate7 (param $z i32)
+    (local $x i32)
+    (local $y i32)
+    (local.set $y (local.get $z))
+    (local.set $x
+      (i32.add
+        (i32.const 1)
+        (local.get $y)
+      )
+    )
+    (if (i32.const 1)
+      (local.set $x ;; x is not ssa
+        (i32.add
+          (i32.const 2)
+          (local.get $y)
+        )
+      )
+    )
+    (drop
+      (i32.load
+        (local.get $x)
+      )
+    )
+  )
+  (func $offset-realistic (param $ptr i32)
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local.set $x
+      (i32.add
+        (local.get $ptr)
+        (i32.const 8)
+      )
+    )
+    (local.set $y
+      (i32.add
+        (local.get $ptr)
+        (i32.const 16)
+      )
+    )
+    (local.set $z
+      (i32.add
+        (local.get $ptr)
+        (i32.const 24)
+      )
+    )
+    (loop $l
+      (call $offset-realistic
+        (i32.load
+          (local.get $x)
+        )
+      )
+      (call $offset-realistic
+        (i32.load
+          (local.get $y)
+        )
+      )
+      (call $offset-realistic
+        (i32.load
+          (local.get $y)
+        )
+      )
+      (i32.store
+        (local.get $z)
+        (i32.add
+          (i32.load
+            (local.get $z)
+          )
+          (i32.const 1)
+        )
+      )
+      (br_if $l
+        (i32.load
+          (local.get $z)
+        )
+      )
+    )
+  )
+  (func $multiadd (param $sp i32)
+    (local $$vararg_buffer i32)
+    (local $$vararg_ptr1 i32)
+    (local.set $$vararg_buffer
+     (i32.add
+      (local.get $sp)
+      (i32.const 16)
+     )
+    )
+    (local.set $$vararg_ptr1
+     (i32.add
+      (local.get $$vararg_buffer)
+      (i32.const 4)
+     )
+    )
+    (i32.store
+     (local.get $$vararg_ptr1)
+     (i32.const 1)
+    )
+  )
+  (func $multiadd-extraUse (param $sp i32)
+    (local $$vararg_buffer i32)
+    (local $$vararg_ptr1 i32)
+    (local.set $$vararg_buffer
+     (i32.add
+      (local.get $sp)
+      (i32.const 16)
+     )
+    )
+    (local.set $$vararg_ptr1
+     (i32.add
+      (local.get $$vararg_buffer)
+      (i32.const 4)
+     )
+    )
+    (drop
+      (local.get $$vararg_buffer)
+    )
+    (i32.store
+     (local.get $$vararg_ptr1)
+     (i32.const 1)
+    )
+  )
+)
+
diff --git a/binaryen/test/passes/optimize-added-constants_low-memory-unused.txt b/binaryen/test/passes/optimize-added-constants_low-memory-unused.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/optimize-added-constants_low-memory-unused.txt
@@ -0,0 +1,384 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 1 1)
+ (func $consts
+  (drop
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1023)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1023)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1023)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1024)
+   )
+  )
+  (i32.store
+   (i32.const 1)
+   (i32.const 1)
+  )
+ )
+ (func $offsets (param $x i32)
+  (drop
+   (i32.load offset=1
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.load offset=8
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.load offset=1023
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.add
+     (local.get $x)
+     (i32.const 1024)
+    )
+   )
+  )
+  (drop
+   (i32.load
+    (i32.add
+     (local.get $x)
+     (i32.const 2048)
+    )
+   )
+  )
+  (drop
+   (i32.load offset=4
+    (local.get $x)
+   )
+  )
+ )
+ (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=7
+   (local.get $0)
+   (local.get $0)
+  )
+  (i32.store offset=9
+   (local.get $0)
+   (local.get $0)
+  )
+  (i32.store offset=2
+   (i32.add
+    (i32.const -11)
+    (local.get $0)
+   )
+   (local.get $0)
+  )
+  (i32.store offset=2
+   (i32.add
+    (local.get $0)
+    (i32.const -13)
+   )
+   (local.get $0)
+  )
+  (i32.store offset=19
+   (i32.const -15)
+   (local.get $0)
+  )
+  (i32.store offset=21
+   (i32.const -21)
+   (local.get $0)
+  )
+  (i32.store
+   (i32.const 25)
+   (local.get $0)
+  )
+  (i32.store
+   (i32.const -23)
+   (local.get $0)
+  )
+  (drop
+   (i32.load
+    (i32.const 8)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 8)
+   )
+  )
+  (drop
+   (i32.load offset=8
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 10)
+   )
+  )
+  (i32.load offset=12
+   (local.get $0)
+  )
+ )
+ (func $offset-constant
+  (drop
+   (i32.load
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 20)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1023)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1023)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 100511)
+   )
+  )
+ )
+ (func $offset-propagate-param (param $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.add
+    (local.get $y)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.load
+    (local.get $x)
+   )
+  )
+ )
+ (func $offset-propagate
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.add
+    (local.get $y)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.load
+    (local.get $x)
+   )
+  )
+ )
+ (func $offset-propagate2
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.add
+    (local.get $y)
+    (i32.add
+     (i32.const 1)
+     (i32.const 2)
+    )
+   )
+  )
+  (drop
+   (i32.load
+    (local.get $x)
+   )
+  )
+ )
+ (func $offset-propagate3
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.add
+    (i32.const 1)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.load
+    (local.get $x)
+   )
+  )
+ )
+ (func $offset-propagate4
+  (local $x i32)
+  (local $y i32)
+  (local.set $y
+   (i32.const -1)
+  )
+  (local.set $x
+   (i32.add
+    (i32.const 1)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.load
+    (local.get $x)
+   )
+  )
+ )
+ (func $offset-propagate5 (param $z i32)
+  (local $x i32)
+  (local $y i32)
+  (if
+   (local.get $z)
+   (local.set $y
+    (i32.const -1)
+   )
+  )
+  (local.set $x
+   (i32.add
+    (i32.const 1)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.load
+    (local.get $x)
+   )
+  )
+ )
+ (func $offset-propagate6 (param $z i32)
+  (local $x i32)
+  (local $y i32)
+  (local.set $y
+   (local.get $z)
+  )
+  (local.set $x
+   (i32.add
+    (i32.const 1)
+    (local.get $y)
+   )
+  )
+  (local.set $y
+   (i32.const -2)
+  )
+  (drop
+   (i32.load
+    (local.get $x)
+   )
+  )
+ )
+ (func $offset-realistic (param $ptr i32)
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (local.set $x
+   (i32.add
+    (local.get $ptr)
+    (i32.const 8)
+   )
+  )
+  (local.set $y
+   (i32.add
+    (local.get $ptr)
+    (i32.const 16)
+   )
+  )
+  (local.set $z
+   (i32.add
+    (local.get $ptr)
+    (i32.const 24)
+   )
+  )
+  (loop $l
+   (call $offset-realistic
+    (i32.load
+     (local.get $x)
+    )
+   )
+   (call $offset-realistic
+    (i32.load
+     (local.get $y)
+    )
+   )
+   (call $offset-realistic
+    (i32.load
+     (local.get $y)
+    )
+   )
+   (i32.store
+    (local.get $z)
+    (i32.add
+     (i32.load
+      (local.get $z)
+     )
+     (i32.const 1)
+    )
+   )
+   (br_if $l
+    (i32.load
+     (local.get $z)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/optimize-added-constants_low-memory-unused.wast b/binaryen/test/passes/optimize-added-constants_low-memory-unused.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/optimize-added-constants_low-memory-unused.wast
@@ -0,0 +1,392 @@
+(module
+  (memory 1 1)
+  (func $consts
+    (drop
+      (i32.load (i32.const 0))
+    )
+    (drop
+      (i32.load (i32.const 1))
+    )
+    (drop
+      (i32.load (i32.const 1023))
+    )
+    (drop
+      (i32.load (i32.const 1024))
+    )
+    (drop
+      (i32.load offset=0 (i32.const 0))
+    )
+    (drop
+      (i32.load offset=1 (i32.const 0))
+    )
+    (drop
+      (i32.load offset=1023 (i32.const 0))
+    )
+    (drop
+      (i32.load offset=1024 (i32.const 0))
+    )
+    (drop
+      (i32.load offset=512 (i32.const 511))
+    )
+    (drop
+      (i32.load offset=512 (i32.const 512))
+    )
+    (i32.store (i32.const 1) (i32.const 1))
+  )
+  (func $offsets (param $x i32)
+    (drop
+      (i32.load
+        (i32.add
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+    )
+    (drop
+      (i32.load
+        (i32.add
+          (local.get $x)
+          (i32.const 8)
+        )
+      )
+    )
+    (drop
+      (i32.load
+        (i32.add
+          (local.get $x)
+          (i32.const 1023)
+        )
+      )
+    )
+    (drop
+      (i32.load
+        (i32.add
+          (local.get $x)
+          (i32.const 1024)
+        )
+      )
+    )
+    (drop
+      (i32.load
+        (i32.add
+          (local.get $x)
+          (i32.const 2048)
+        )
+      )
+    )
+    (drop
+      (i32.load
+        (i32.add
+          (i32.const 4)
+          (local.get $x)
+        )
+      )
+    )
+  )
+  (func $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 $offset-constant
+    (drop
+      (i32.load offset=10
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.load offset=0
+        (i32.const 10)
+      )
+    )
+    (drop
+      (i32.load offset=10
+        (i32.const 10)
+      )
+    )
+    (drop
+      (i32.load offset=512
+        (i32.const 512)
+      )
+    )
+    (drop
+      (i32.load offset=512
+        (i32.const 511)
+      )
+    )
+    (drop
+      (i32.load offset=511
+        (i32.const 512)
+      )
+    )
+    (drop
+      (i32.load offset=99999
+        (i32.const 512)
+      )
+    )
+  )
+  (func $offset-propagate-param (param $x i32)
+   (local $y i32)
+   (local.set $x
+    (i32.add
+     (local.get $y)
+     (i32.const 1)
+    )
+   )
+   (drop
+    (i32.load
+     (local.get $x)
+    )
+   )
+  )
+  (func $offset-propagate
+   (local $x i32)
+   (local $y i32)
+   (local.set $x
+    (i32.add
+     (local.get $y)
+     (i32.const 1)
+    )
+   )
+   (drop
+    (i32.load
+     (local.get $x)
+    )
+   )
+  )
+  (func $offset-propagate2
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.add
+        (local.get $y)
+        (i32.add
+          (i32.const 1)
+          (i32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.load
+        (local.get $x)
+      )
+    )
+  )
+  (func $offset-propagate3
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.add
+        (i32.const 1)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i32.load
+        (local.get $x)
+      )
+    )
+  )
+  (func $offset-propagate4
+    (local $x i32)
+    (local $y i32)
+    (local.set $y (i32.const -1))
+    (local.set $x
+      (i32.add
+        (i32.const 1)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i32.load
+        (local.get $x)
+      )
+    )
+  )
+  (func $offset-propagate5 (param $z i32)
+    (local $x i32)
+    (local $y i32)
+    (if (local.get $z)
+      (local.set $y (i32.const -1))
+    )
+    (local.set $x
+      (i32.add
+        (i32.const 1)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i32.load
+        (local.get $x)
+      )
+    )
+  )
+  (func $offset-propagate6 (param $z i32)
+    (local $x i32)
+    (local $y i32)
+    (local.set $y (local.get $z))
+    (local.set $x
+      (i32.add
+        (i32.const 1)
+        (local.get $y)
+      )
+    )
+    (local.set $y (i32.const -2))
+    (drop
+      (i32.load
+        (local.get $x)
+      )
+    )
+  )
+  (func $offset-realistic (param $ptr i32)
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local.set $x
+      (i32.add
+        (local.get $ptr)
+        (i32.const 8)
+      )
+    )
+    (local.set $y
+      (i32.add
+        (local.get $ptr)
+        (i32.const 16)
+      )
+    )
+    (local.set $z
+      (i32.add
+        (local.get $ptr)
+        (i32.const 24)
+      )
+    )
+    (loop $l
+      (call $offset-realistic
+        (i32.load
+          (local.get $x)
+        )
+      )
+      (call $offset-realistic
+        (i32.load
+          (local.get $y)
+        )
+      )
+      (call $offset-realistic
+        (i32.load
+          (local.get $y)
+        )
+      )
+      (i32.store
+        (local.get $z)
+        (i32.add
+          (i32.load
+            (local.get $z)
+          )
+          (i32.const 1)
+        )
+      )
+      (br_if $l
+        (i32.load
+          (local.get $z)
+        )
+      )
+    )
+  )
+)
+
diff --git a/binaryen/test/passes/optimize-instructions_all-features.txt b/binaryen/test/passes/optimize-instructions_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/optimize-instructions_all-features.txt
@@ -0,0 +1,4664 @@
+(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)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/optimize-instructions_all-features.wast b/binaryen/test/passes/optimize-instructions_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/optimize-instructions_all-features.wast
@@ -0,0 +1,5176 @@
+(module
+  (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)
+    )
+   )
+  )
+)
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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/optimize-instructions_optimize-level=2_all-features_ignore-implicit-traps.txt
@@ -0,0 +1,384 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (type $none_=>_f64 (func (result f64)))
+ (memory $0 0)
+ (func $conditionals (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (loop $while-in
+   (local.set $3
+    (i32.const 0)
+   )
+   (loop $while-in6
+    (local.set $6
+     (i32.add
+      (local.get $0)
+      (i32.const 1)
+     )
+    )
+    (local.set $0
+     (if (result i32)
+      (if (result i32)
+       (i32.rem_s
+        (i32.add
+         (i32.mul
+          (local.get $0)
+          (local.tee $7
+           (i32.add
+            (local.get $0)
+            (i32.const 2)
+           )
+          )
+         )
+         (i32.const 17)
+        )
+        (i32.const 5)
+       )
+       (i32.eqz
+        (i32.rem_u
+         (i32.add
+          (i32.mul
+           (local.get $0)
+           (local.get $0)
+          )
+          (i32.const 11)
+         )
+         (i32.const 3)
+        )
+       )
+       (i32.const 1)
+      )
+      (local.get $7)
+      (local.get $6)
+     )
+    )
+    (br_if $while-in6
+     (i32.lt_s
+      (local.tee $3
+       (i32.add
+        (local.get $3)
+        (i32.const 1)
+       )
+      )
+      (local.get $4)
+     )
+    )
+   )
+   (br_if $while-in
+    (i32.ne
+     (local.tee $1
+      (i32.add
+       (local.get $1)
+       (i32.const 1)
+      )
+     )
+     (i32.const 27000)
+    )
+   )
+  )
+  (return
+   (local.get $5)
+  )
+ )
+ (func $side-effect (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (loop $while-in
+   (local.set $3
+    (i32.const 0)
+   )
+   (loop $while-in6
+    (local.set $6
+     (i32.add
+      (local.get $0)
+      (i32.const 1)
+     )
+    )
+    (local.set $0
+     (if (result i32)
+      (i32.or
+       (i32.eqz
+        (i32.rem_s
+         (i32.add
+          (i32.mul
+           (local.get $0)
+           (local.tee $7
+            (local.get $0)
+           )
+          )
+          (i32.const 17)
+         )
+         (i32.const 5)
+        )
+       )
+       (i32.eqz
+        (i32.rem_u
+         (i32.add
+          (i32.mul
+           (local.get $0)
+           (local.get $0)
+          )
+          (unreachable)
+         )
+         (i32.const 3)
+        )
+       )
+      )
+      (local.get $7)
+      (local.get $6)
+     )
+    )
+    (br_if $while-in6
+     (i32.lt_s
+      (local.tee $3
+       (i32.add
+        (local.get $3)
+        (i32.const 1)
+       )
+      )
+      (local.get $4)
+     )
+    )
+   )
+   (br_if $while-in
+    (i32.ne
+     (local.tee $1
+      (i32.add
+       (local.get $1)
+       (i32.const 1)
+      )
+     )
+     (i32.const 27000)
+    )
+   )
+  )
+  (return
+   (local.get $5)
+  )
+ )
+ (func $flip (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (loop $while-in
+   (local.set $3
+    (i32.const 0)
+   )
+   (loop $while-in6
+    (local.set $6
+     (i32.add
+      (local.get $0)
+      (i32.const 1)
+     )
+    )
+    (local.set $0
+     (if (result i32)
+      (if (result i32)
+       (i32.rem_u
+        (i32.add
+         (i32.mul
+          (local.get $0)
+          (local.get $0)
+         )
+         (i32.const 100)
+        )
+        (i32.const 3)
+       )
+       (i32.eqz
+        (i32.rem_s
+         (i32.add
+          (i32.mul
+           (local.get $0)
+           (i32.eqz
+            (local.get $0)
+           )
+          )
+          (i32.const 17)
+         )
+         (i32.const 5)
+        )
+       )
+       (i32.const 1)
+      )
+      (local.get $7)
+      (local.get $6)
+     )
+    )
+    (br_if $while-in6
+     (i32.lt_s
+      (local.tee $3
+       (i32.add
+        (local.get $3)
+        (i32.const 1)
+       )
+      )
+      (local.get $4)
+     )
+    )
+   )
+   (br_if $while-in
+    (i32.ne
+     (local.tee $1
+      (i32.add
+       (local.get $1)
+       (i32.const 1)
+      )
+     )
+     (i32.const 27000)
+    )
+   )
+  )
+  (return
+   (local.get $5)
+  )
+ )
+ (func $invalidate-conditionalizeExpensiveOnBitwise (param $0 i32) (param $1 i32) (result i32)
+  (if
+   (i32.eqz
+    (i32.and
+     (i32.lt_u
+      (i32.and
+       (i32.shr_s
+        (i32.shl
+         (i32.add
+          (local.get $1)
+          (i32.const -1)
+         )
+         (i32.const 24)
+        )
+        (i32.const 24)
+       )
+       (i32.const 255)
+      )
+      (i32.const 3)
+     )
+     (i32.ne
+      (local.tee $1
+       (i32.const 0)
+      )
+      (i32.const 0)
+     )
+    )
+   )
+   (return
+    (local.get $0)
+   )
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $invalidate-conditionalizeExpensiveOnBitwise-ok (param $0 i32) (param $1 i32) (result i32)
+  (if
+   (i32.eqz
+    (if (result i32)
+     (local.tee $1
+      (i32.const 0)
+     )
+     (i32.lt_u
+      (i32.and
+       (i32.shr_s
+        (i32.shl
+         (i32.add
+          (local.get $0)
+          (i32.const -1)
+         )
+         (i32.const 24)
+        )
+        (i32.const 24)
+       )
+       (i32.const 255)
+      )
+      (i32.const 3)
+     )
+     (i32.const 0)
+    )
+   )
+   (return
+    (local.get $0)
+   )
+  )
+  (return
+   (local.get $1)
+  )
+ )
+ (func $conditionalize-if-type-change (result f64)
+  (local $0 i32)
+  (drop
+   (loop $label$1 (result f32)
+    (block $label$2 (result f32)
+     (drop
+      (block $label$3 (result f32)
+       (br_if $label$1
+        (i32.or
+         (f32.gt
+          (br_if $label$3
+           (f32.const 1)
+           (local.get $0)
+          )
+          (br $label$2
+           (f32.const 71)
+          )
+         )
+         (i64.eqz
+          (select
+           (i64.const 58)
+           (i64.const -982757)
+           (i64.eqz
+            (i64.const 0)
+           )
+          )
+         )
+        )
+       )
+      )
+     )
+     (f32.const 1)
+    )
+   )
+  )
+  (f64.const -nan:0xfffffffffffff)
+ )
+ (func $optimize-bulk-memory-copy (param $dst i32) (param $src i32) (param $sz i32)
+  (block
+   (drop
+    (local.get $dst)
+   )
+   (drop
+    (local.get $dst)
+   )
+   (drop
+    (local.get $sz)
+   )
+  )
+  (block
+   (drop
+    (local.get $dst)
+   )
+   (drop
+    (local.get $src)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/optimize-instructions_optimize-level=2_all-features_ignore-implicit-traps.wast b/binaryen/test/passes/optimize-instructions_optimize-level=2_all-features_ignore-implicit-traps.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/optimize-instructions_optimize-level=2_all-features_ignore-implicit-traps.wast
@@ -0,0 +1,378 @@
+(module
+  (type $0 (func (param i32 i32) (result i32)))
+  (memory $0 0)
+  (func $conditionals (type $0) (param $0 i32) (param $1 i32) (result i32)
+    (local $2 i32)
+    (local $3 i32)
+    (local $4 i32)
+    (local $5 i32)
+    (local $6 i32)
+    (local $7 i32)
+    (local.set $0
+      (i32.const 0)
+    )
+    (loop $while-in
+      (local.set $3
+        (i32.const 0)
+      )
+      (loop $while-in6
+        (local.set $6
+          (i32.add
+            (local.get $0)
+            (i32.const 1)
+          )
+        )
+        (local.set $0
+          (if (result i32)
+            (i32.or ;; this or is very expensive. we should compute one side, then see if we even need the other
+              (i32.eqz
+                (i32.rem_s
+                  (i32.add
+                    (i32.mul
+                      (local.tee $7 ;; side effect, so we can't do this one
+                        (i32.add
+                          (local.get $0)
+                          (i32.const 2)
+                        )
+                      )
+                      (local.get $0)
+                    )
+                    (i32.const 17)
+                  )
+                  (i32.const 5)
+                )
+              )
+              (i32.eqz
+                (i32.rem_u
+                  (i32.add
+                    (i32.mul
+                      (local.get $0)
+                      (local.get $0)
+                    )
+                    (i32.const 11)
+                  )
+                  (i32.const 3)
+                )
+              )
+            )
+            (local.get $7)
+            (local.get $6)
+          )
+        )
+        (br_if $while-in6
+          (i32.lt_s
+            (local.tee $3
+              (i32.add
+                (local.get $3)
+                (i32.const 1)
+              )
+            )
+            (local.get $4)
+          )
+        )
+      )
+      (br_if $while-in
+        (i32.ne
+          (local.tee $1
+            (i32.add
+              (local.get $1)
+              (i32.const 1)
+            )
+          )
+          (i32.const 27000)
+        )
+      )
+    )
+    (return
+      (local.get $5)
+    )
+  )
+  (func $side-effect (type $0) (param $0 i32) (param $1 i32) (result i32)
+    (local $2 i32)
+    (local $3 i32)
+    (local $4 i32)
+    (local $5 i32)
+    (local $6 i32)
+    (local $7 i32)
+    (local.set $0
+      (i32.const 0)
+    )
+    (loop $while-in
+      (local.set $3
+        (i32.const 0)
+      )
+      (loop $while-in6
+        (local.set $6
+          (i32.add
+            (local.get $0)
+            (i32.const 1)
+          )
+        )
+        (local.set $0
+          (if (result i32)
+            (i32.or ;; this or is very expensive, but has a side effect on both sides
+              (i32.eqz
+                (i32.rem_s
+                  (i32.add
+                    (i32.mul
+                      (local.tee $7
+                        (i32.add
+                          (local.get $0)
+                          (i32.const 0)
+                        )
+                      )
+                      (local.get $0)
+                    )
+                    (i32.const 17)
+                  )
+                  (i32.const 5)
+                )
+              )
+              (i32.eqz
+                (i32.rem_u
+                  (i32.add
+                    (i32.mul
+                      (local.get $0)
+                      (local.get $0)
+                    )
+                    (unreachable)
+                  )
+                  (i32.const 3)
+                )
+              )
+            )
+            (local.get $7)
+            (local.get $6)
+          )
+        )
+        (br_if $while-in6
+          (i32.lt_s
+            (local.tee $3
+              (i32.add
+                (local.get $3)
+                (i32.const 1)
+              )
+            )
+            (local.get $4)
+          )
+        )
+      )
+      (br_if $while-in
+        (i32.ne
+          (local.tee $1
+            (i32.add
+              (local.get $1)
+              (i32.const 1)
+            )
+          )
+          (i32.const 27000)
+        )
+      )
+    )
+    (return
+      (local.get $5)
+    )
+  )
+  (func $flip (type $0) (param $0 i32) (param $1 i32) (result i32)
+    (local $2 i32)
+    (local $3 i32)
+    (local $4 i32)
+    (local $5 i32)
+    (local $6 i32)
+    (local $7 i32)
+    (local.set $0
+      (i32.const 0)
+    )
+    (loop $while-in
+      (local.set $3
+        (i32.const 0)
+      )
+      (loop $while-in6
+        (local.set $6
+          (i32.add
+            (local.get $0)
+            (i32.const 1)
+          )
+        )
+        (local.set $0
+          (if (result i32)
+            (i32.or ;; this or is very expensive, and the first side has no side effect
+              (i32.eqz
+                (i32.rem_s
+                  (i32.add
+                    (i32.mul
+                      (i32.eqz
+                        (i32.add
+                          (local.get $0)
+                          (i32.const 0)
+                        )
+                      )
+                      (local.get $0)
+                    )
+                    (i32.const 17)
+                  )
+                  (i32.const 5)
+                )
+              )
+              (i32.eqz
+                (i32.rem_u
+                  (i32.add
+                    (i32.mul
+                      (local.get $0)
+                      (local.get $0)
+                    )
+                    (i32.const 100)
+                  )
+                  (i32.const 3)
+                )
+              )
+            )
+            (local.get $7)
+            (local.get $6)
+          )
+        )
+        (br_if $while-in6
+          (i32.lt_s
+            (local.tee $3
+              (i32.add
+                (local.get $3)
+                (i32.const 1)
+              )
+            )
+            (local.get $4)
+          )
+        )
+      )
+      (br_if $while-in
+        (i32.ne
+          (local.tee $1
+            (i32.add
+              (local.get $1)
+              (i32.const 1)
+            )
+          )
+          (i32.const 27000)
+        )
+      )
+    )
+    (return
+      (local.get $5)
+    )
+  )
+  (func $invalidate-conditionalizeExpensiveOnBitwise (param $0 i32) (param $1 i32) (result i32)
+   (if
+    (i32.eqz
+     (i32.and
+      (i32.lt_s
+       (i32.and
+        (i32.shr_s
+         (i32.shl
+          (i32.add
+           (local.get $1) ;; conflict with tee
+           (i32.const -1)
+          )
+          (i32.const 24)
+         )
+         (i32.const 24)
+        )
+        (i32.const 255)
+       )
+       (i32.const 3)
+      )
+      (i32.ne
+       (local.tee $1
+        (i32.const 0)
+       )
+       (i32.const 0)
+      )
+     )
+    )
+    (return (local.get $0))
+   )
+   (return (local.get $1))
+  )
+  (func $invalidate-conditionalizeExpensiveOnBitwise-ok (param $0 i32) (param $1 i32) (result i32)
+   (if
+    (i32.eqz
+     (i32.and
+      (i32.lt_s
+       (i32.and
+        (i32.shr_s
+         (i32.shl
+          (i32.add
+           (local.get $0) ;; no conflict
+           (i32.const -1)
+          )
+          (i32.const 24)
+         )
+         (i32.const 24)
+        )
+        (i32.const 255)
+       )
+       (i32.const 3)
+      )
+      (i32.ne
+       (local.tee $1
+        (i32.const 0)
+       )
+       (i32.const 0)
+      )
+     )
+    )
+    (return (local.get $0))
+   )
+   (return (local.get $1))
+  )
+
+ (func $conditionalize-if-type-change (result f64)
+  (local $0 i32)
+  (drop
+   (loop $label$1 (result f32)
+    (block $label$2 (result f32)
+     (drop
+      (block $label$3 (result f32)
+       (br_if $label$1
+        (i32.or ;; this turns into an if, but then the if might not be unreachable
+         (f32.gt
+          (br_if $label$3
+           (f32.const 1)
+           (local.get $0)
+          )
+          (br $label$2
+           (f32.const 71)
+          )
+         )
+         (i64.eqz
+          (select
+           (i64.const 58)
+           (i64.const -982757)
+           (i64.eqz
+            (i64.const 0)
+           )
+          )
+         )
+        )
+       )
+      )
+     )
+     (f32.const 1)
+    )
+   )
+  )
+  (f64.const -nan:0xfffffffffffff)
+ )
+ (func $optimize-bulk-memory-copy (param $dst i32) (param $src i32) (param $sz i32)
+  (memory.copy  ;; nop
+    (local.get $dst)
+    (local.get $dst)
+    (local.get $sz)
+  )
+
+  (memory.copy  ;; nop
+    (local.get $dst)
+    (local.get $src)
+    (i32.const 0)
+  )
+ )
+)
+
diff --git a/binaryen/test/passes/pick-load-signs.txt b/binaryen/test/passes/pick-load-signs.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/pick-load-signs.txt
@@ -0,0 +1,279 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 1)
+ (func $a
+  (local $y i32)
+  (local.set $y
+   (i32.load8_u
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $y)
+    (i32.const 255)
+   )
+  )
+ )
+ (func $b
+  (local $y i32)
+  (local.set $y
+   (i32.load16_u
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $y)
+    (i32.const 65535)
+   )
+  )
+ )
+ (func $c
+  (local $y i32)
+  (local.set $y
+   (i32.load8_u
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $y)
+    (i32.const 255)
+   )
+  )
+ )
+ (func $d
+  (local $y i32)
+  (local.set $y
+   (i32.load16_u
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $y)
+    (i32.const 65535)
+   )
+  )
+ )
+ (func $one-of-each
+  (local $y i32)
+  (local.set $y
+   (i32.load8_s
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $y)
+    (i32.const 255)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $y)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+ )
+ (func $more-of-one
+  (local $y i32)
+  (local.set $y
+   (i32.load8_s
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $y)
+    (i32.const 255)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $y)
+    (i32.const 255)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $y)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+ )
+ (func $many-more-of-one
+  (local $y i32)
+  (local.set $y
+   (i32.load8_u
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $y)
+    (i32.const 255)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $y)
+    (i32.const 255)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $y)
+    (i32.const 255)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $y)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+ )
+ (func $a-sign
+  (local $y i32)
+  (local.set $y
+   (i32.load8_s
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $y)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+ )
+ (func $multivar
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.load8_u
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $x)
+    (i32.const 255)
+   )
+  )
+  (local.set $y
+   (i32.load8_s
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $y)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+ )
+ (func $corners
+  (local $y i32)
+  (drop
+   (i32.load8_s
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.load8_u
+    (i32.const 1024)
+   )
+  )
+  (local.set $y
+   (i32.const 1024)
+  )
+ )
+ (func $wrong-size
+  (local $y i32)
+  (local.set $y
+   (i32.load8_s
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $y)
+    (i32.const 65535)
+   )
+  )
+ )
+ (func $wrong-size_s
+  (local $y i32)
+  (local.set $y
+   (i32.load8_u
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $y)
+     (i32.const 16)
+    )
+    (i32.const 16)
+   )
+  )
+ )
+ (func $non-sign-or-unsigned-use
+  (local $y i32)
+  (local.set $y
+   (i32.load8_s
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $y)
+    (i32.const 255)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+ )
+ (func $toplevel-load (result i32)
+  (i32.load8_s
+   (i32.const 1024)
+  )
+ )
+ (func $tees
+  (local $y i32)
+  (drop
+   (local.tee $y
+    (i32.load8_s
+     (i32.const 1024)
+    )
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $y)
+    (i32.const 255)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/pick-load-signs.wast b/binaryen/test/passes/pick-load-signs.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/pick-load-signs.wast
@@ -0,0 +1,277 @@
+(module
+  (memory 1)
+  (func $a ;; load 8s, but use is 8u, so load should be signed
+    (local $y i32)
+    (local.set $y
+      (i32.load8_s
+        (i32.const 1024)
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $y)
+        (i32.const 255)
+      )
+    )
+  )
+  (func $b ;; load 16s, but use is 16u, so load should be signed
+    (local $y i32)
+    (local.set $y
+      (i32.load16_s
+        (i32.const 1024)
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $y)
+        (i32.const 65535)
+      )
+    )
+  )
+  (func $c ;; load 8u, keep
+    (local $y i32)
+    (local.set $y
+      (i32.load8_u
+        (i32.const 1024)
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $y)
+        (i32.const 255)
+      )
+    )
+  )
+  (func $d ;; load 16u, keep
+    (local $y i32)
+    (local.set $y
+      (i32.load16_u
+        (i32.const 1024)
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $y)
+        (i32.const 65535)
+      )
+    )
+  )
+  (func $one-of-each ;; prefer the signed, potential code removal is bigger
+    (local $y i32)
+    (local.set $y
+      (i32.load8_s
+        (i32.const 1024)
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $y)
+        (i32.const 255)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $y)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+  )
+  (func $more-of-one ;; prefer the signed even if 2x more unsigned
+    (local $y i32)
+    (local.set $y
+      (i32.load8_s
+        (i32.const 1024)
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $y)
+        (i32.const 255)
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $y)
+        (i32.const 255)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $y)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+  )
+  (func $many-more-of-one ;; but not 3x
+    (local $y i32)
+    (local.set $y
+      (i32.load8_s
+        (i32.const 1024)
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $y)
+        (i32.const 255)
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $y)
+        (i32.const 255)
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $y)
+        (i32.const 255)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $y)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+  )
+  (func $a-sign ;; load 8s, use is s, so keep
+    (local $y i32)
+    (local.set $y
+      (i32.load8_s
+        (i32.const 1024)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $y)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+  )
+  (func $multivar
+    (local $x i32)
+    (local $y i32)
+    (local.set $x
+      (i32.load8_s
+        (i32.const 1024)
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $x)
+        (i32.const 255)
+      )
+    )
+    (local.set $y
+      (i32.load8_s
+        (i32.const 1024)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $y)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+  )
+  (func $corners
+    (local $y i32)
+    (drop
+      (i32.load8_s ;; not sent into a local.set
+        (i32.const 1024)
+      )
+    )
+    (drop
+      (i32.load8_u ;; not sent into a local.set
+        (i32.const 1024)
+      )
+    )
+    (local.set $y
+      (i32.const 1024) ;; not a load
+    )
+  )
+  (func $wrong-size ;; load 8s, but use is 16
+    (local $y i32)
+    (local.set $y
+      (i32.load8_s
+        (i32.const 1024)
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $y)
+        (i32.const 65535)
+      )
+    )
+  )
+  (func $wrong-size_s ;; load 8s, but use is 16
+    (local $y i32)
+    (local.set $y
+      (i32.load8_u
+        (i32.const 1024)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $y)
+          (i32.const 16)
+        )
+        (i32.const 16)
+      )
+    )
+  )
+  (func $non-sign-or-unsigned-use
+    (local $y i32)
+    (local.set $y
+      (i32.load8_s
+        (i32.const 1024)
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $y)
+        (i32.const 255)
+      )
+    )
+    (drop
+      (local.get $y)
+    )
+  )
+  (func $toplevel-load (result i32)
+    (i32.load8_s
+      (i32.const 1024)
+    )
+  )
+  (func $tees
+    (local $y i32)
+    (drop ;; a "use", so we can't alter the value
+      (local.tee $y
+        (i32.load8_s
+          (i32.const 1024)
+        )
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $y)
+        (i32.const 255)
+      )
+    )
+  )
+)
diff --git a/binaryen/test/passes/post-assemblyscript-finalize.txt b/binaryen/test/passes/post-assemblyscript-finalize.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/post-assemblyscript-finalize.txt
@@ -0,0 +1,40 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (import "rt" "retain" (func $~lib/rt/pure/__retain (param i32) (result i32)))
+ (import "rt" "release" (func $~lib/rt/pure/__release (param i32)))
+ (import "rt" "alloc" (func $~lib/rt/tlsf/__alloc (param i32 i32) (result i32)))
+ (func $eliminates.unnecessaryAllocation
+  (nop)
+ )
+ (func $eliminates.unnecessaryPair (param $0 i32)
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $eliminates.unnecessaryStaticPair
+  (nop)
+ )
+ (func $eliminates.unnecessaryStaticRetain
+  (drop
+   (i32.const 272)
+  )
+ )
+ (func $eliminates.unnecessaryStaticRelease
+  (nop)
+ )
+ (func $keeps.dynamicRetain (param $0 i32)
+  (local.set $0
+   (call $~lib/rt/pure/__retain
+    (local.get $0)
+   )
+  )
+ )
+ (func $keeps.dynamicRelease (param $0 i32)
+  (call $~lib/rt/pure/__release
+   (local.get $0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/post-assemblyscript-finalize.wast b/binaryen/test/passes/post-assemblyscript-finalize.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/post-assemblyscript-finalize.wast
@@ -0,0 +1,54 @@
+;; FinalizeARC part of assemblyscript/tests/compiler/rc/optimize
+(module
+ (import "rt" "retain" (func $~lib/rt/pure/__retain (param i32) (result i32)))
+ (import "rt" "release" (func $~lib/rt/pure/__release (param i32)))
+ (import "rt" "alloc" (func $~lib/rt/tlsf/__alloc (param i32) (param i32) (result i32)))
+ (func $eliminates.unnecessaryAllocation
+  (call $~lib/rt/pure/__release
+   (call $~lib/rt/pure/__retain
+    (call $~lib/rt/tlsf/__alloc
+     (i32.const 1)
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $eliminates.unnecessaryPair (param $0 i32)
+  (call $~lib/rt/pure/__release
+   (call $~lib/rt/pure/__retain
+    (local.get $0)
+   )
+  )
+ )
+ (func $eliminates.unnecessaryStaticPair
+  (call $~lib/rt/pure/__release
+   (call $~lib/rt/pure/__retain
+    (i32.const 272)
+   )
+  )
+ )
+ (func $eliminates.unnecessaryStaticRetain
+  (drop
+   (call $~lib/rt/pure/__retain
+    (i32.const 272)
+   )
+  )
+ )
+ (func $eliminates.unnecessaryStaticRelease
+  (call $~lib/rt/pure/__release
+   (i32.const 272)
+  )
+ )
+ (func $keeps.dynamicRetain (param $0 i32)
+  (local.set $0
+   (call $~lib/rt/pure/__retain
+    (local.get $0)
+   )
+  )
+ )
+ (func $keeps.dynamicRelease (param $0 i32)
+  (call $~lib/rt/pure/__release
+   (local.get $0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/post-assemblyscript.txt b/binaryen/test/passes/post-assemblyscript.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/post-assemblyscript.txt
@@ -0,0 +1,263 @@
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (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 "rt" "retain" (func $~lib/rt/pure/__retain (param i32) (result i32)))
+ (import "rt" "release" (func $~lib/rt/pure/__release (param i32)))
+ (import "rc" "getRetainedRef" (func $getRetainedRef (result i32)))
+ (func $eliminates.linearArgument (param $0 i32)
+  (local.set $0
+   (local.get $0)
+  )
+  (nop)
+ )
+ (func $eliminates.linearLocal (param $0 i32)
+  (local $1 i32)
+  (local.set $1
+   (local.get $0)
+  )
+  (nop)
+ )
+ (func $eliminates.linearChain (param $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local.set $1
+   (local.get $0)
+  )
+  (local.set $2
+   (local.get $1)
+  )
+  (local.set $3
+   (local.get $2)
+  )
+  (nop)
+  (nop)
+  (nop)
+ )
+ (func $eliminates.balancedReleases (param $0 i32) (param $cond i32)
+  (local $2 i32)
+  (local.set $2
+   (local.get $0)
+  )
+  (if
+   (local.get $cond)
+   (nop)
+   (nop)
+  )
+ )
+ (func $eliminates.partialReleases (param $0 i32) (param $cond i32)
+  (local $2 i32)
+  (local.set $2
+   (local.get $0)
+  )
+  (if
+   (local.get $cond)
+   (nop)
+  )
+ )
+ (func $eliminates.balancedRetains (param $0 i32) (param $cond1 i32) (param $cond2 i32)
+  (local $3 i32)
+  (if
+   (local.get $cond1)
+   (if
+    (local.get $cond2)
+    (local.set $3
+     (local.get $0)
+    )
+    (local.set $3
+     (local.get $0)
+    )
+   )
+   (local.set $3
+    (local.get $0)
+   )
+  )
+  (nop)
+ )
+ (func $eliminates.balancedInsideLoop (param $0 i32) (param $cond i32)
+  (local $flat i32)
+  (block $break|0
+   (loop $continue|0
+    (local.set $flat
+     (i32.eqz
+      (local.get $cond)
+     )
+    )
+    (br_if $break|0
+     (local.get $flat)
+    )
+    (local.set $0
+     (local.get $0)
+    )
+    (nop)
+    (br $continue|0)
+   )
+   (unreachable)
+  )
+ )
+ (func $eliminates.balancedOutsideLoop (param $0 i32) (param $cond i32)
+  (local $flat i32)
+  (local.set $0
+   (local.get $0)
+  )
+  (block $break|0
+   (loop $continue|0
+    (local.set $flat
+     (i32.eqz
+      (local.get $cond)
+     )
+    )
+    (br_if $break|0
+     (local.get $flat)
+    )
+    (br $continue|0)
+   )
+   (unreachable)
+  )
+  (nop)
+ )
+ (func $eliminates.balancedInsideOutsideLoop (param $0 i32) (param $cond i32)
+  (local $flat i32)
+  (local.set $0
+   (local.get $0)
+  )
+  (block $break|0
+   (loop $continue|0
+    (local.set $flat
+     (i32.eqz
+      (local.get $cond)
+     )
+    )
+    (br_if $break|0
+     (local.get $flat)
+    )
+    (nop)
+    (local.set $0
+     (local.get $0)
+    )
+    (br $continue|0)
+   )
+   (unreachable)
+  )
+  (nop)
+ )
+ (func $eliminates.balancedInsideOutsideLoopWithBranch (param $0 i32) (param $cond1 i32) (param $cond2 i32)
+  (local $flat i32)
+  (local.set $0
+   (local.get $0)
+  )
+  (block $break|0
+   (loop $continue|0
+    (local.set $flat
+     (i32.eqz
+      (local.get $cond1)
+     )
+    )
+    (br_if $break|0
+     (local.get $flat)
+    )
+    (if
+     (local.get $cond2)
+     (block $block
+      (nop)
+      (return)
+     )
+    )
+    (nop)
+    (local.set $0
+     (local.get $0)
+    )
+    (br $continue|0)
+   )
+   (unreachable)
+  )
+  (nop)
+ )
+ (func $eliminates.replace (param $0 i32) (param $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local.set $0
+   (local.get $0)
+  )
+  (local.set $1
+   (local.get $1)
+  )
+  (local.set $2
+   (local.get $1)
+  )
+  (local.set $3
+   (local.get $0)
+  )
+  (if
+   (i32.ne
+    (local.get $2)
+    (local.get $3)
+   )
+   (local.set $2
+    (local.get $2)
+   )
+   (nop)
+  )
+  (local.set $0
+   (local.get $2)
+  )
+  (nop)
+  (nop)
+ )
+ (func $eliminates.replaceAlreadyRetained (param $0 i32) (result i32)
+  (local $1 i32)
+  (block $block
+   (local.set $0
+    (local.get $0)
+   )
+   (local.set $1
+    (call $getRetainedRef)
+   )
+   (nop)
+   (local.set $0
+    (local.get $1)
+   )
+   (return
+    (local.get $0)
+   )
+  )
+ )
+ (func $keeps.partialRetains (param $0 i32) (param $cond i32)
+  (if
+   (local.get $cond)
+   (local.set $0
+    (call $~lib/rt/pure/__retain
+     (local.get $0)
+    )
+   )
+  )
+  (call $~lib/rt/pure/__release
+   (local.get $0)
+  )
+ )
+ (func $keeps.reachesReturn (param $0 i32) (param $cond i32) (result i32)
+  (block $block
+   (local.set $0
+    (call $~lib/rt/pure/__retain
+     (local.get $0)
+    )
+   )
+   (if
+    (local.get $cond)
+    (return
+     (local.get $0)
+    )
+   )
+   (call $~lib/rt/pure/__release
+    (local.get $0)
+   )
+   (return
+    (i32.const 0)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/post-assemblyscript.wast b/binaryen/test/passes/post-assemblyscript.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/post-assemblyscript.wast
@@ -0,0 +1,342 @@
+;; OptimizeARC part of assemblyscript/tests/compiler/rc/optimize
+;; with flattening applied manually
+(module
+ (import "rt" "retain" (func $~lib/rt/pure/__retain (param i32) (result i32)))
+ (import "rt" "release" (func $~lib/rt/pure/__release (param i32)))
+ (func $eliminates.linearArgument (param $0 i32)
+  (local.set $0
+   (call $~lib/rt/pure/__retain
+    (local.get $0)
+   )
+  )
+  (call $~lib/rt/pure/__release
+   (local.get $0)
+  )
+ )
+ (func $eliminates.linearLocal (param $0 i32)
+  (local $1 i32)
+  (local.set $1
+   (call $~lib/rt/pure/__retain
+    (local.get $0)
+   )
+  )
+  (call $~lib/rt/pure/__release
+   (local.get $1)
+  )
+ )
+ (func $eliminates.linearChain (param $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local.set $1
+   (call $~lib/rt/pure/__retain
+    (local.get $0)
+   )
+  )
+  (local.set $2
+   (call $~lib/rt/pure/__retain
+    (local.get $1)
+   )
+  )
+  (local.set $3
+   (call $~lib/rt/pure/__retain
+    (local.get $2)
+   )
+  )
+  (call $~lib/rt/pure/__release
+   (local.get $3)
+  )
+  (call $~lib/rt/pure/__release
+   (local.get $2)
+  )
+  (call $~lib/rt/pure/__release
+   (local.get $1)
+  )
+ )
+  (func $eliminates.balancedReleases (param $0 i32) (param $cond i32)
+  (local $2 i32)
+  (local.set $2
+   (call $~lib/rt/pure/__retain
+    (local.get $0)
+   )
+  )
+  (if
+   (local.get $cond)
+   (call $~lib/rt/pure/__release
+    (local.get $2)
+   )
+   (call $~lib/rt/pure/__release
+    (local.get $2)
+   )
+  )
+ )
+ (func $eliminates.partialReleases (param $0 i32) (param $cond i32)
+  ;; technically invalid but assumed to be never emitted
+  (local $2 i32)
+  (local.set $2
+   (call $~lib/rt/pure/__retain
+    (local.get $0)
+   )
+  )
+  (if
+   (local.get $cond)
+   (call $~lib/rt/pure/__release
+    (local.get $2)
+   )
+  )
+ )
+ (func $eliminates.balancedRetains (param $0 i32) (param $cond1 i32) (param $cond2 i32)
+  (local $3 i32)
+  (if
+   (local.get $cond1)
+   (if
+    (local.get $cond2)
+    (local.set $3
+     (call $~lib/rt/pure/__retain
+      (local.get $0)
+     )
+    )
+    (local.set $3
+     (call $~lib/rt/pure/__retain
+      (local.get $0)
+     )
+    )
+   )
+   (local.set $3
+    (call $~lib/rt/pure/__retain
+     (local.get $0)
+    )
+   )
+  )
+  (call $~lib/rt/pure/__release
+   (local.get $3)
+  )
+ )
+ (func $eliminates.balancedInsideLoop (param $0 i32) (param $cond i32)
+  (local $flat i32)
+  (block $break|0
+   (loop $continue|0
+    (local.set $flat
+     (i32.eqz
+      (local.get $cond)
+     )
+    )
+    (br_if $break|0
+     (local.get $flat)
+    )
+    (local.set $0
+     (call $~lib/rt/pure/__retain
+      (local.get $0)
+     )
+    )
+    (call $~lib/rt/pure/__release
+     (local.get $0)
+    )
+    (br $continue|0)
+   )
+   (unreachable)
+  )
+ )
+ (func $eliminates.balancedOutsideLoop (param $0 i32) (param $cond i32)
+  (local $flat i32)
+  (local.set $0
+   (call $~lib/rt/pure/__retain
+    (local.get $0)
+   )
+  )
+  (block $break|0
+   (loop $continue|0
+    (local.set $flat
+     (i32.eqz
+      (local.get $cond)
+     )
+    )
+    (br_if $break|0
+     (local.get $flat)
+    )
+    (br $continue|0)
+   )
+   (unreachable)
+  )
+  (call $~lib/rt/pure/__release
+   (local.get $0)
+  )
+ )
+ (func $eliminates.balancedInsideOutsideLoop (param $0 i32) (param $cond i32)
+  (local $flat i32)
+  (local.set $0
+   (call $~lib/rt/pure/__retain
+    (local.get $0)
+   )
+  )
+  (block $break|0
+   (loop $continue|0
+    (local.set $flat
+     (i32.eqz
+      (local.get $cond)
+     )
+    )
+    (br_if $break|0
+     (local.get $flat)
+    )
+    (call $~lib/rt/pure/__release
+     (local.get $0)
+    )
+    (local.set $0
+     (call $~lib/rt/pure/__retain
+      (local.get $0)
+     )
+    )
+    (br $continue|0)
+   )
+   (unreachable)
+  )
+  (call $~lib/rt/pure/__release
+   (local.get $0)
+  )
+ )
+ (func $eliminates.balancedInsideOutsideLoopWithBranch (param $0 i32) (param $cond1 i32) (param $cond2 i32)
+  (local $flat i32)
+  (local.set $0
+   (call $~lib/rt/pure/__retain
+    (local.get $0)
+   )
+  )
+  (block $break|0
+   (loop $continue|0
+    (local.set $flat
+     (i32.eqz
+      (local.get $cond1)
+     )
+    )
+    (br_if $break|0
+     (local.get $flat)
+    )
+    (if
+     (local.get $cond2)
+     (block
+      (call $~lib/rt/pure/__release
+       (local.get $0)
+      )
+      (return)
+     )
+    )
+    (call $~lib/rt/pure/__release
+     (local.get $0)
+    )
+    (local.set $0
+     (call $~lib/rt/pure/__retain
+      (local.get $0)
+     )
+    )
+    (br $continue|0)
+   )
+   (unreachable)
+  )
+  (call $~lib/rt/pure/__release
+   (local.get $0)
+  )
+ )
+ (func $eliminates.replace (param $0 i32) (param $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local.set $0
+   (call $~lib/rt/pure/__retain
+    (local.get $0)
+   )
+  )
+  (local.set $1
+   (call $~lib/rt/pure/__retain
+    (local.get $1)
+   )
+  )
+  ;; flat
+  (local.set $2
+   (local.get $1)
+  )
+  (local.set $3
+   (local.get $0)
+  )
+  ;; /flat
+  (if
+   (i32.ne
+    (local.get $2) ;; flat (local.tee $2 (local.get $1))
+    (local.get $3) ;; flat (local.tee $3 (local.get $0))
+   )
+   (local.set $2
+    (call $~lib/rt/pure/__retain
+     (local.get $2)
+    )
+   )
+   (call $~lib/rt/pure/__release
+    (local.get $3)
+   )
+  )
+  (local.set $0
+   (local.get $2)
+  )
+  (call $~lib/rt/pure/__release
+   (local.get $0)
+  )
+  (call $~lib/rt/pure/__release
+   (local.get $1)
+  )
+ )
+ (import "rc" "getRetainedRef" (func $getRetainedRef (result i32)))
+ (func $eliminates.replaceAlreadyRetained (param $0 i32) (result i32)
+  (local $1 i32)
+  (block
+   (local.set $0
+    (call $~lib/rt/pure/__retain
+     (local.get $0)
+    )
+   )
+   (local.set $1
+    (call $getRetainedRef)
+   )
+   (call $~lib/rt/pure/__release
+    (local.get $0)
+   )
+   (local.set $0
+    (local.get $1)
+   )
+   (return
+    (local.get $0)
+   )
+  )
+ )
+ (func $keeps.partialRetains (param $0 i32) (param $cond i32)
+  (if
+   (local.get $cond)
+   (local.set $0
+    (call $~lib/rt/pure/__retain
+     (local.get $0)
+    )
+   )
+  )
+  (call $~lib/rt/pure/__release
+   (local.get $0)
+  )
+ )
+ (func $keeps.reachesReturn (param $0 i32) (param $cond i32) (result i32)
+  (block
+   (local.set $0
+    (call $~lib/rt/pure/__retain
+     (local.get $0)
+    )
+   )
+   (if
+    (local.get $cond)
+    (return
+     (local.get $0)
+    )
+   )
+   (call $~lib/rt/pure/__release
+    (local.get $0)
+   )
+   (return
+    (i32.const 0)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/post-emscripten.txt b/binaryen/test/passes/post-emscripten.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/post-emscripten.txt
@@ -0,0 +1,178 @@
+(module
+ (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)
+   )
+  )
+ )
+ (func $exc
+  (call $other_safe
+   (i32.const 42)
+   (f32.const 3.141590118408203)
+  )
+  (call $invoke_vif
+   (i32.const 4)
+   (i32.const 55)
+   (f32.const 2.1828181743621826)
+  )
+  (call $deep_safe
+   (i32.const 100)
+   (f32.const 1.1109999418258667)
+  )
+  (call $invoke_vif
+   (i32.const 6)
+   (i32.const 999)
+   (f32.const 1.4140000343322754)
+  )
+  (call $invoke_vif
+   (i32.add
+    (i32.const 1)
+    (i32.const 1)
+   )
+   (i32.const 42)
+   (f32.const 3.141590118408203)
+  )
+ )
+ (func $other_safe (param $0 i32) (param $1 f32)
+  (nop)
+ )
+ (func $other_unsafe (param $0 i32) (param $1 f32)
+  (drop
+   (call $Math_pow
+    (f64.const 1)
+    (f64.const 3)
+   )
+  )
+ )
+ (func $deep_safe (param $0 i32) (param $1 f32)
+  (call $other_safe
+   (unreachable)
+   (unreachable)
+  )
+ )
+ (func $deep_unsafe (param $0 i32) (param $1 f32)
+  (call $other_unsafe
+   (unreachable)
+   (unreachable)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (func $call
+  (call $call)
+ )
+)
+(module
+ (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)
+ (elem (global.get $glob) $other_safe)
+ (func $exc
+  (call $invoke_vif
+   (i32.const 3)
+   (i32.const 42)
+   (f32.const 3.141590118408203)
+  )
+ )
+ (func $other_safe (param $0 i32) (param $1 f32)
+  (nop)
+ )
+)
+(module
+ (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)
+ (elem (i32.const 0) $other_safe)
+ (func $exc
+  (call $invoke_vif
+   (i32.const 0)
+   (i32.const 42)
+   (f32.const 3.141590118408203)
+  )
+ )
+ (func $other_safe (param $0 i32) (param $1 f32)
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/post-emscripten.wast b/binaryen/test/passes/post-emscripten.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/post-emscripten.wast
@@ -0,0 +1,150 @@
+(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)
+      )
+    )
+  )
+  (func $exc
+    (call $invoke_vif
+      (i32.const 3) ;; other_safe()
+      (i32.const 42)
+      (f32.const 3.14159)
+    )
+    (call $invoke_vif
+      (i32.const 4) ;; other_unsafe()
+      (i32.const 55)
+      (f32.const 2.18281828)
+    )
+    (call $invoke_vif
+      (i32.const 5) ;; deep_safe()
+      (i32.const 100)
+      (f32.const 1.111)
+    )
+    (call $invoke_vif
+      (i32.const 6) ;; deep_unsafe()
+      (i32.const 999)
+      (f32.const 1.414)
+    )
+    (call $invoke_vif
+      (i32.add (i32.const 1) (i32.const 1)) ;; nonconstant
+      (i32.const 42)
+      (f32.const 3.14159)
+    )
+  )
+  (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))
+  )
+  (func $deep_unsafe (param i32) (param f32)
+    (call $other_unsafe (unreachable) (unreachable))
+  )
+)
+(module ;; no invokes
+  (func $call
+    (call $call)
+  )
+)
+(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)
+  (table 7 7 funcref)
+  (elem (global.get $glob) $other_safe)
+  (func $exc
+    (call $invoke_vif
+      (i32.const 3) ;; other_safe()
+      (i32.const 42)
+      (f32.const 3.14159)
+    )
+  )
+  (func $other_safe (param i32) (param f32)
+  )
+)
+(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)
+  (table 7 7 funcref)
+  (elem (i32.const 0) $other_safe)
+  (func $exc
+    (call $invoke_vif
+      (i32.const 0) ;; other_safe()
+      (i32.const 42)
+      (f32.const 3.14159)
+    )
+  )
+  (func $other_safe (param i32) (param f32)
+   (call_indirect (type $none_=>_none)
+    (i32.const 0)
+   )
+  )
+)
diff --git a/binaryen/test/passes/precompute-propagate_all-features.txt b/binaryen/test/passes/precompute-propagate_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/precompute-propagate_all-features.txt
@@ -0,0 +1,288 @@
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_i32_i64 (func (result i32 i64)))
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (type $none_=>_v128 (func (result v128)))
+ (memory $0 10 10)
+ (func $basic (param $p i32)
+  (local $x i32)
+  (local.set $x
+   (i32.const 10)
+  )
+  (call $basic
+   (i32.const 20)
+  )
+ )
+ (func $split (param $p i32)
+  (local $x i32)
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.const 10)
+   )
+  )
+  (call $basic
+   (i32.add
+    (local.get $x)
+    (local.get $x)
+   )
+  )
+ )
+ (func $split-but-join (param $p i32)
+  (local $x i32)
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.const 10)
+   )
+   (local.set $x
+    (i32.const 10)
+   )
+  )
+  (call $basic
+   (i32.const 20)
+  )
+ )
+ (func $split-but-join-different (param $p i32)
+  (local $x i32)
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.const 10)
+   )
+   (local.set $x
+    (i32.const 20)
+   )
+  )
+  (call $basic
+   (i32.add
+    (local.get $x)
+    (local.get $x)
+   )
+  )
+ )
+ (func $split-but-join-different-b (param $p i32)
+  (local $x i32)
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.const 10)
+   )
+   (local.set $x
+    (local.get $p)
+   )
+  )
+  (call $basic
+   (i32.add
+    (local.get $x)
+    (local.get $x)
+   )
+  )
+ )
+ (func $split-but-join-init0 (param $p i32)
+  (local $x i32)
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.const 0)
+   )
+  )
+  (call $basic
+   (i32.const 0)
+  )
+ )
+ (func $later (param $p i32)
+  (local $x i32)
+  (local.set $x
+   (i32.const 10)
+  )
+  (call $basic
+   (i32.const 20)
+  )
+  (local.set $x
+   (i32.const 22)
+  )
+  (call $basic
+   (i32.const 44)
+  )
+  (local.set $x
+   (i32.const 39)
+  )
+ )
+ (func $later2 (param $p i32) (result i32)
+  (local $x i32)
+  (local.set $x
+   (i32.const 10)
+  )
+  (local.set $x
+   (i32.const 20)
+  )
+  (i32.const 20)
+ )
+ (func $two-ways-but-identical (param $p i32) (result i32)
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.const 10)
+  )
+  (if
+   (i32.const 1)
+   (local.set $y
+    (i32.const 11)
+   )
+   (local.set $y
+    (i32.const 11)
+   )
+  )
+  (local.set $y
+   (i32.const 21)
+  )
+  (i32.const 21)
+ )
+ (func $two-ways-but-almost-identical (param $p i32) (result i32)
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.const 10)
+  )
+  (if
+   (i32.const 1)
+   (local.set $y
+    (i32.const 12)
+   )
+   (local.set $y
+    (i32.const 11)
+   )
+  )
+  (local.set $y
+   (i32.add
+    (i32.const 10)
+    (local.get $y)
+   )
+  )
+  (local.get $y)
+ )
+ (func $deadloop (param $p i32) (result i32)
+  (local $x i32)
+  (local $y i32)
+  (loop $loop
+   (local.set $x
+    (i32.const 0)
+   )
+   (local.set $y
+    (i32.const 0)
+   )
+   (br $loop)
+  )
+ )
+ (func $deadloop2 (param $p i32)
+  (local $x i32)
+  (local $y i32)
+  (loop $loop
+   (local.set $x
+    (i32.const 0)
+   )
+   (local.set $y
+    (i32.const 0)
+   )
+   (call $deadloop2
+    (i32.const 0)
+   )
+   (call $deadloop2
+    (i32.const 0)
+   )
+   (br $loop)
+  )
+ )
+ (func $deadloop3 (param $p i32)
+  (local $x i32)
+  (local $y i32)
+  (loop $loop
+   (local.set $x
+    (i32.const 0)
+   )
+   (local.set $y
+    (i32.const 0)
+   )
+   (call $deadloop2
+    (i32.const 0)
+   )
+   (call $deadloop2
+    (i32.const 0)
+   )
+   (br $loop)
+  )
+ )
+ (func $through-tee (param $x i32) (param $y i32) (result i32)
+  (local.set $x
+   (local.tee $y
+    (i32.const 7)
+   )
+  )
+  (return
+   (i32.const 14)
+  )
+ )
+ (func $through-tee-more (param $x i32) (param $y i32) (result i32)
+  (local.set $x
+   (i32.eqz
+    (local.tee $y
+     (i32.const 7)
+    )
+   )
+  )
+  (return
+   (i32.const 7)
+  )
+ )
+ (func $multipass (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (nop)
+  (nop)
+  (local.get $2)
+ )
+ (func $through-fallthrough (param $x i32) (param $y i32) (result i32)
+  (local.set $x
+   (block $block (result i32)
+    (nop)
+    (local.tee $y
+     (i32.const 7)
+    )
+   )
+  )
+  (return
+   (i32.const 14)
+  )
+ )
+ (func $simd-load (result v128)
+  (local $x v128)
+  (local.set $x
+   (v8x16.load_splat
+    (i32.const 0)
+   )
+  )
+  (local.get $x)
+ )
+ (func $tuple-local (result i32 i64)
+  (local $i32s (i32 i32))
+  (local $i64s (i64 i64))
+  (local.set $i32s
+   (tuple.make
+    (i32.const 42)
+    (i32.const 0)
+   )
+  )
+  (local.set $i64s
+   (tuple.make
+    (i64.const 42)
+    (i64.const 0)
+   )
+  )
+  (tuple.make
+   (i32.const 42)
+   (i64.const 0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/precompute-propagate_all-features.wast b/binaryen/test/passes/precompute-propagate_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/precompute-propagate_all-features.wast
@@ -0,0 +1,202 @@
+(module
+  (memory 10 10)
+  (func $basic (param $p i32)
+    (local $x i32)
+    (local.set $x (i32.const 10))
+    (call $basic (i32.add (local.get $x) (local.get $x)))
+  )
+  (func $split (param $p i32)
+    (local $x i32)
+    (if (i32.const 1)
+      (local.set $x (i32.const 10))
+    )
+    (call $basic (i32.add (local.get $x) (local.get $x)))
+  )
+  (func $split-but-join (param $p i32)
+    (local $x i32)
+    (if (i32.const 1)
+      (local.set $x (i32.const 10))
+      (local.set $x (i32.const 10))
+    )
+    (call $basic (i32.add (local.get $x) (local.get $x)))
+  )
+  (func $split-but-join-different (param $p i32)
+    (local $x i32)
+    (if (i32.const 1)
+      (local.set $x (i32.const 10))
+      (local.set $x (i32.const 20))
+    )
+    (call $basic (i32.add (local.get $x) (local.get $x)))
+  )
+  (func $split-but-join-different-b (param $p i32)
+    (local $x i32)
+    (if (i32.const 1)
+      (local.set $x (i32.const 10))
+      (local.set $x (local.get $p))
+    )
+    (call $basic (i32.add (local.get $x) (local.get $x)))
+  )
+  (func $split-but-join-init0 (param $p i32)
+    (local $x i32)
+    (if (i32.const 1)
+      (local.set $x (i32.const 0))
+    )
+    (call $basic (i32.add (local.get $x) (local.get $x)))
+  )
+  (func $later (param $p i32)
+    (local $x i32)
+    (local.set $x (i32.const 10))
+    (call $basic (i32.add (local.get $x) (local.get $x)))
+    (local.set $x (i32.const 22))
+    (call $basic (i32.add (local.get $x) (local.get $x)))
+    (local.set $x (i32.const 39))
+  )
+  (func $later2 (param $p i32) (result i32)
+    (local $x i32)
+    (local.set $x (i32.const 10))
+    (local.set $x (i32.add (local.get $x) (local.get $x)))
+    (local.get $x)
+  )
+  (func $two-ways-but-identical (param $p i32) (result i32)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x (i32.const 10))
+    (if (i32.const 1)
+      (local.set $y (i32.const 11))
+      (local.set $y (i32.add (local.get $x) (i32.const 1)))
+    )
+    (local.set $y (i32.add (local.get $x) (local.get $y)))
+    (local.get $y)
+  )
+  (func $two-ways-but-almost-identical (param $p i32) (result i32)
+    (local $x i32)
+    (local $y i32)
+    (local.set $x (i32.const 10))
+    (if (i32.const 1)
+      (local.set $y (i32.const 12)) ;; 12, not 11...
+      (local.set $y (i32.add (local.get $x) (i32.const 1)))
+    )
+    (local.set $y (i32.add (local.get $x) (local.get $y)))
+    (local.get $y)
+  )
+  (func $deadloop (param $p i32) (result i32)
+    (local $x i32)
+    (local $y i32)
+    (loop $loop ;; we look like we depend on the other, but we don't actually
+      (local.set $x (if (result i32) (i32.const 1) (i32.const 0) (local.get $y)))
+      (local.set $y (if (result i32) (i32.const 1) (i32.const 0) (local.get $x)))
+      (br $loop)
+    )
+  )
+  (func $deadloop2 (param $p i32)
+    (local $x i32)
+    (local $y i32)
+    (loop $loop ;; we look like we depend on the other, but we don't actually
+      (local.set $x (if (result i32) (i32.const 1) (i32.const 0) (local.get $y)))
+      (local.set $y (if (result i32) (i32.const 1) (i32.const 0) (local.get $x)))
+      (call $deadloop2 (local.get $x))
+      (call $deadloop2 (local.get $y))
+      (br $loop)
+    )
+  )
+  (func $deadloop3 (param $p i32)
+    (local $x i32)
+    (local $y i32)
+    (loop $loop ;; we look like we depend on the other, but we don't actually
+      (local.set $x (if (result i32) (i32.const 1) (i32.const 0) (local.get $x)))
+      (local.set $y (if (result i32) (i32.const 1) (i32.const 0) (local.get $y)))
+      (call $deadloop2 (local.get $x))
+      (call $deadloop2 (local.get $y))
+      (br $loop)
+    )
+  )
+  (func $through-tee (param $x i32) (param $y i32) (result i32)
+    (local.set $x
+      (local.tee $y
+        (i32.const 7)
+      )
+    )
+    (return
+      (i32.add
+        (local.get $x)
+        (local.get $y)
+      )
+    )
+  )
+  (func $through-tee-more (param $x i32) (param $y i32) (result i32)
+    (local.set $x
+      (i32.eqz
+        (local.tee $y
+          (i32.const 7)
+        )
+      )
+    )
+    (return
+      (i32.add
+        (local.get $x)
+        (local.get $y)
+      )
+    )
+  )
+  (func $multipass (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+   (local $3 i32)
+   (if
+    (local.get $3)
+    (local.set $3 ;; this set is completely removed, allowing later opts
+     (i32.const 24)
+    )
+   )
+   (if
+    (local.get $3)
+    (local.set $2
+     (i32.const 0)
+    )
+   )
+   (local.get $2)
+  )
+  (func $through-fallthrough (param $x i32) (param $y i32) (result i32)
+    (local.set $x
+      (block (result i32)
+        (nop)
+        (local.tee $y
+          (i32.const 7)
+        )
+      )
+    )
+    (return
+      (i32.add
+        (local.get $x)
+        (local.get $y)
+      )
+    )
+  )
+  (func $simd-load (result v128)
+   (local $x v128)
+   (local.set $x (v8x16.load_splat (i32.const 0)))
+   (local.get $x)
+  )
+  (func $tuple-local (result i32 i64)
+   (local $i32s (i32 i32))
+   (local $i64s (i64 i64))
+   (local.set $i32s
+    (tuple.make
+     (i32.const 42)
+     (i32.const 0)
+    )
+   )
+   (local.set $i64s
+    (tuple.make
+     (i64.const 42)
+     (i64.const 0)
+    )
+   )
+   (tuple.make
+    (tuple.extract 0
+     (local.get $i32s)
+    )
+    (tuple.extract 1
+     (local.get $i64s)
+    )
+   )
+  )
+)
diff --git a/binaryen/test/passes/precompute_all-features.txt b/binaryen/test/passes/precompute_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/precompute_all-features.txt
@@ -0,0 +1,327 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (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)))
+ (memory $0 512 512)
+ (data (i32.const 0) "passive")
+ (global $global i32 (i32.const 1))
+ (global $global-mut (mut i32) (i32.const 2))
+ (event $event$0 (attr 0) (param))
+ (func $x (param $x i32)
+  (call $x
+   (i32.const 2300)
+  )
+  (nop)
+  (drop
+   (i32.add
+    (i32.const 1)
+    (local.get $x)
+   )
+  )
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (loop $in
+   (br $in)
+  )
+  (nop)
+  (block $c
+   (nop)
+   (call $x
+    (i32.const 4)
+   )
+   (br $c)
+   (br $c)
+  )
+  (drop
+   (block $val (result i32)
+    (nop)
+    (call $x
+     (i32.const 4)
+    )
+    (br $val
+     (i32.const 101)
+    )
+    (br $val
+     (i32.const 102)
+    )
+   )
+  )
+  (nop)
+  (drop
+   (block $d0 (result i32)
+    (call $x
+     (i32.const 5)
+    )
+    (nop)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (block $d2 (result i32)
+    (call $x
+     (i32.const 6)
+    )
+    (nop)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (block $d4 (result i32)
+    (call $x
+     (i32.const 7)
+    )
+    (nop)
+    (i32.const 2)
+   )
+  )
+  (call $x
+   (i32.const 2)
+  )
+  (call $x
+   (i32.const 1)
+  )
+  (call $x
+   (i32.const 0)
+  )
+  (call $x
+   (i32.const 0)
+  )
+ )
+ (func $ret (result i32)
+  (if
+   (call $ret)
+   (return
+    (i32.const 0)
+   )
+  )
+  (if
+   (call $ret)
+   (return
+    (i32.const 1)
+   )
+  )
+  (i32.const 1)
+ )
+ (func $noret
+  (if
+   (call $ret)
+   (return)
+  )
+ )
+ (func $refinalize-br-condition-unreachable
+  (block $label$1
+   (drop
+    (br_if $label$1
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $br_if-condition-is-block-i32-but-unreachable-so-refinalize-tricky
+  (drop
+   (block $label$1 (result i32)
+    (drop
+     (br_if $label$1
+      (i32.const 100)
+      (block $label$3
+       (unreachable)
+      )
+     )
+    )
+    (i32.const 0)
+   )
+  )
+ )
+ (func $reuse-br-value (result f64)
+  (block $label$0 (result f64)
+   (i32.store8
+    (i32.const 1919623207)
+    (if (result i32)
+     (i32.const 1)
+     (block $label$2
+      (drop
+       (i64.and
+        (i64.trunc_f32_u
+         (f32.const 70847791997969805621592064)
+        )
+        (i64.const 729618461987467893)
+       )
+      )
+      (br $label$0
+       (f64.const 6.134856208230095e-154)
+      )
+     )
+     (i32.load offset=3 align=2
+      (i32.const 169901344)
+     )
+    )
+   )
+   (f64.const 4776014875438170098655851e156)
+  )
+ )
+ (func $refinalize-two-breaks-one-unreachable
+  (drop
+   (block $label$0 (result i64)
+    (block
+     (select
+      (i64.const 1)
+      (block $block
+       (global.set $global-mut
+        (i32.const 1)
+       )
+       (br $label$0
+        (i64.const -22)
+       )
+      )
+      (i32.const 0)
+     )
+     (drop
+      (i32.const 1)
+     )
+    )
+   )
+  )
+ )
+ (func $one-break-value-and-it-is-unreachable (result f64)
+  (local $var$0 i32)
+  (block $label$6
+   (block
+    (unreachable)
+    (drop
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $global-notprecomputable (result i32)
+  (i32.add
+   (i32.const 1)
+   (global.get $global-mut)
+  )
+ )
+ (func $global-precomputable (result i32)
+  (i32.const 2)
+ )
+ (func $global-partiallyprecomputable (result i32)
+  (i32.sub
+   (i32.add
+    (i32.const 1)
+    (global.get $global-mut)
+   )
+   (i32.const 2)
+  )
+ )
+ (func $no-simd-precompute (result v128)
+  (i32x4.splat
+   (i32.const 0)
+  )
+ )
+ (func $no-simd-precompute-if (result v128)
+  (return
+   (i32x4.splat
+    (i32.const 0)
+   )
+  )
+ )
+ (func $no-memory-init-precompute
+  (memory.init 0
+   (i32.const 512)
+   (i32.const 0)
+   (i32.const 12)
+  )
+ )
+ (func $no-data-drop-precompute
+  (data.drop 0)
+ )
+ (func $no-memory-copy-precompute
+  (memory.copy
+   (i32.const 512)
+   (i32.const 0)
+   (i32.const 12)
+  )
+ )
+ (func $no-memory-fill-precompute
+  (memory.fill
+   (i32.const 512)
+   (i32.const 0)
+   (i32.const 12)
+  )
+ )
+ (func $tuple-precompute (result i32 i64)
+  (tuple.make
+   (i32.const 42)
+   (i64.const 42)
+  )
+ )
+ (func $loop-precompute (result i32)
+  (i32.const 1)
+ )
+ (func $reftype-test (result externref)
+  (ref.null extern)
+ )
+ (func $dummy
+  (nop)
+ )
+ (func $br_reuse_node
+  (drop
+   (block $l0 (result f32)
+    (drop
+     (block $l1
+      (global.set $global-mut
+       (i32.const 1)
+      )
+      (br $l0
+       (f32.const 3.5)
+      )
+     )
+    )
+    (f32.const 0)
+   )
+  )
+  (drop
+   (block $l2 (result externref)
+    (drop
+     (block $l3
+      (global.set $global-mut
+       (i32.const 1)
+      )
+      (br $l2
+       (ref.null extern)
+      )
+     )
+    )
+    (ref.null extern)
+   )
+  )
+  (drop
+   (block $l4 (result funcref)
+    (drop
+     (block $l5
+      (global.set $global-mut
+       (i32.const 1)
+      )
+      (br $l4
+       (ref.func $dummy)
+      )
+     )
+    )
+    (ref.null func)
+   )
+  )
+ )
+ (func $unreachable-br_on_exn
+  (block $label$1
+   (drop
+    (loop $label$2
+     (br $label$2)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/precompute_all-features.wast b/binaryen/test/passes/precompute_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/precompute_all-features.wast
@@ -0,0 +1,479 @@
+(module
+  (memory 512 512
+   (data passive "hello!")
+  )
+  (type $0 (func (param i32)))
+  (global $global i32 (i32.const 1))
+  (global $global-mut (mut i32) (i32.const 2))
+  (func $x (type $0) (param $x i32)
+    (call $x
+      (i32.add
+        (i32.const 100)
+        (i32.const 2200)
+      )
+    )
+    (drop
+      (i32.add
+        (i32.const 1)
+        (i32.const 2)
+      )
+    )
+    (drop
+      (i32.add
+        (i32.const 1)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i32.add
+        (i32.const 1)
+        (i32.add
+          (i32.const 2)
+          (i32.const 3)
+        )
+      )
+    )
+    (drop
+      (i32.sub
+        (i32.const 1)
+        (i32.const 2)
+      )
+    )
+    (drop
+      (i32.sub
+        (i32.add
+          (i32.const 0)
+          (i32.const 4)
+        )
+        (i32.const 1)
+      )
+    )
+    (drop
+     (tuple.make
+      (tuple.extract 0
+       (tuple.make
+        (i32.const 42)
+        (i32.const 0)
+       )
+      )
+      (tuple.extract 1
+       (tuple.make
+        (i64.const 0)
+        (i64.const 42)
+       )
+      )
+     )
+    )
+    (loop $in
+      (br $in)
+    )
+    (block $b
+      (br_if $b (i32.const 0))
+      (br_if $b (i32.const 1))
+      (call $x (i32.const 4))
+    )
+    (block $c
+      (br_if $c (i32.const 0))
+      (call $x (i32.const 4))
+      (br_if $c (i32.const 1))
+      (br $c)
+    )
+    (drop
+      (block $val (result i32)
+        (drop (br_if $val (i32.const 100) (i32.const 0)))
+        (call $x (i32.const 4))
+        (drop (br_if $val (i32.const 101) (i32.const 1)))
+        (br $val (i32.const 102))
+      )
+    )
+    (block $d
+      (block $e
+        (br_if $d (br $e))
+        (call $x (i32.const 4))
+        (br_if $e (br $d))
+      )
+    )
+    (drop
+      (block $d (result i32)
+        (call $x (i32.const 5))
+        (block $e
+          (drop (br_if $d (br $e) (i32.const 1)))
+          (drop (br_if $d (br $e) (i32.const 0)))
+          (drop (br_if $d (i32.const 1) (br $e)))
+          (drop (br_if $d (i32.const 0) (br $e)))
+          (unreachable)
+        )
+        (i32.const 1)
+      )
+    )
+    (drop
+      (block $d (result i32)
+        (call $x (i32.const 6))
+        (block $e
+          (drop (br_if $d (br $e) (i32.const 0)))
+          (drop (br_if $d (i32.const 1) (br $e)))
+          (drop (br_if $d (i32.const 0) (br $e)))
+          (unreachable)
+        )
+        (i32.const 1)
+      )
+    )
+    (drop
+      (block $d (result i32)
+        (call $x (i32.const 7))
+        (block $e
+          (drop (br_if $d (i32.const 1) (br $e)))
+        )
+        (i32.const 2)
+      )
+    )
+    (call $x
+      (block $out (result i32)
+        (block $waka1
+          (block $waka2
+            (block $waka3
+              (br_table $waka1 $waka2 $waka3
+                (i32.const 0)
+              )
+            )
+            (br $out (i32.const 0))
+          )
+          (br $out (i32.const 1))
+        )
+        (br $out (i32.const 2))
+      )
+    )
+    (call $x
+      (block $out (result i32)
+        (block $waka1
+          (block $waka2
+            (block $waka3
+              (br_table $waka1 $waka2 $waka3
+                (i32.const 1)
+              )
+            )
+            (br $out (i32.const 0))
+          )
+          (br $out (i32.const 1))
+        )
+        (br $out (i32.const 2))
+      )
+    )
+    (call $x
+      (block $out (result i32)
+        (block $waka1
+          (block $waka2
+            (block $waka3
+              (br_table $waka1 $waka2 $waka3
+                (i32.const 2)
+              )
+            )
+            (br $out (i32.const 0))
+          )
+          (br $out (i32.const 1))
+        )
+        (br $out (i32.const 2))
+      )
+    )
+    (call $x
+      (block $out (result i32)
+        (block $waka1
+          (block $waka2
+            (block $waka3
+              (br_table $waka1 $waka2 $waka3
+                (i32.const 3)
+              )
+            )
+            (br $out (i32.const 0))
+          )
+          (br $out (i32.const 1))
+        )
+        (br $out (i32.const 2))
+      )
+    )
+  )
+  (func $ret (result i32)
+    (if (call $ret)
+      (return (i32.const 0))
+    )
+    (if (call $ret)
+      (return (return (i32.const 1)))
+    )
+    (i32.const 1)
+  )
+  (func $noret
+    (if (call $ret)
+      (return)
+    )
+  )
+  (func $refinalize-br-condition-unreachable
+   (block $label$1
+    (drop
+     (br_if $label$1
+      (unreachable)
+     )
+    )
+   )
+  )
+  (func $br_if-condition-is-block-i32-but-unreachable-so-refinalize-tricky
+   (drop
+    (block $label$1 (result i32)
+     (drop
+      (br_if $label$1
+       (i32.const 100)
+       (block $label$3 (result i32)
+        (unreachable)
+       )
+      )
+     )
+     (i32.const 0)
+    )
+   )
+  )
+  (func $reuse-br-value (result f64)
+   (block $label$0 (result f64)
+    (i32.store8
+     (i32.const 1919623207)
+     (if (result i32)
+      (i32.const 1)
+      (block $label$2 (result i32)
+       (drop
+        (i64.and
+         (i64.trunc_f32_u
+          (f32.const 70847791997969805621592064)
+         )
+         (i64.const 729618461987467893)
+        )
+       )
+       (br_if $label$2
+        (i32.const 2049535349)
+        (f32.eq
+         (f32.demote_f64
+          (f64.mul
+           (br_if $label$0 ;; this br is optimized, and br *and* values reused
+            (f64.const 6.134856208230095e-154)
+            (i32.const 690910817)
+           )
+           (f64.const 1.515470884183969e-152)
+          )
+         )
+         (f32.const 66524025679377434935296)
+        )
+       )
+      )
+      (i32.load offset=3 align=2
+        (i32.const 169901344)
+      )
+     )
+    )
+    (f64.const 4776014875438170098655851e156)
+   )
+  )
+  (func $refinalize-two-breaks-one-unreachable
+   (drop
+    (block $label$0 (result i64)
+     (br_if $label$0
+      (select
+       (i64.const 1)
+       (block (result i64)
+        (global.set $global-mut
+         (i32.const 1)
+        )
+        (br_if $label$0
+         (i64.const -22)
+         (i32.const -1)
+        )
+       )
+       (i32.const 0)
+      )
+      (i32.const 1)
+     )
+    )
+   )
+  )
+  (func $one-break-value-and-it-is-unreachable (result f64)
+   (local $var$0 i32)
+   (block $label$6 (result f64)
+    (br_if $label$6
+     (unreachable)
+     (i32.const 0)
+    )
+   )
+  )
+  (func $global-notprecomputable (result i32)
+   (i32.add
+    (i32.const 1)
+    (global.get $global-mut)
+   )
+  )
+  (func $global-precomputable (result i32)
+   (i32.add
+    (i32.const 1)
+    (global.get $global)
+   )
+  )
+  (func $global-partiallyprecomputable (result i32)
+   (i32.sub
+    (i32.add
+     (i32.const 1)
+     (global.get $global-mut)
+    )
+    (i32.add
+     (i32.const 1)
+     (global.get $global)
+    )
+   )
+  )
+  (func $no-simd-precompute (result v128)
+   (i32x4.splat
+    (i32.const 0)
+   )
+  )
+  (func $no-simd-precompute-if (result v128)
+   (return
+    (i32x4.splat
+     (i32.const 0)
+    )
+   )
+  )
+  (func $no-memory-init-precompute
+   (memory.init 0
+    (i32.const 512)
+    (i32.const 0)
+    (i32.const 12)
+   )
+  )
+  (func $no-data-drop-precompute
+   (data.drop 0)
+  )
+  (func $no-memory-copy-precompute
+   (memory.copy
+    (i32.const 512)
+    (i32.const 0)
+    (i32.const 12)
+   )
+  )
+  (func $no-memory-fill-precompute
+   (memory.fill
+    (i32.const 512)
+    (i32.const 0)
+    (i32.const 12)
+   )
+  )
+  (func $tuple-precompute (result i32 i64)
+   (tuple.make
+    (tuple.extract 0
+     (tuple.make
+      (i32.const 42)
+      (i32.const 0)
+     )
+    )
+    (tuple.extract 1
+     (tuple.make
+      (i64.const 0)
+      (i64.const 42)
+     )
+    )
+   )
+  )
+  (func $loop-precompute (result i32)
+   (block $block (result i32)
+    (loop $loop
+     (br $block (i32.const 1))
+    )
+   )
+  )
+
+  ;; Check if Precompute pass does not crash on reference types
+  (func $reftype-test (result externref)
+    (ref.null extern)
+  )
+
+  ;; Check if constant nodes (const, ref.null, and ref.func) are correctly
+  ;; reused. (We shouldn't reuse a const node for something like ref.null, which
+  ;; will incorrectly cause an expression like 'someref.const'.)
+  (func $dummy)
+  (func $br_reuse_node
+   (drop
+    (block $l0 (result f32)
+     (drop
+      (block $l1 (result i32)
+       (global.set $global-mut
+        (i32.const 1)
+       )
+       (br_if $l1
+        (i32.const 1)
+        (f32.lt
+         (br_if $l0
+          (f32.const 3.5)
+          (i32.const 1)
+         )
+         (f32.const 3)
+        )
+       )
+      )
+     )
+     (f32.const 0)
+    )
+   )
+
+   (drop
+    (block $l2 (result externref)
+     (drop
+      (block $l3 (result i32)
+       (global.set $global-mut
+        (i32.const 1)
+       )
+       (br_if $l3
+        (i32.const 1)
+        (ref.is_null
+         (br_if $l2
+          (ref.null extern)
+          (i32.const 3)
+         )
+        )
+       )
+      )
+     )
+     (ref.null extern)
+    )
+   )
+
+   (drop
+    (block $l4 (result funcref)
+     (drop
+      (block $l5 (result i32)
+       (global.set $global-mut
+        (i32.const 1)
+       )
+       (br_if $l5
+        (i32.const 1)
+        (ref.is_null
+         (br_if $l4
+          (ref.func $dummy)
+          (i32.const 3)
+         )
+        )
+       )
+      )
+     )
+     (ref.null func)
+    )
+   )
+  )
+
+  ;; br_on_exn's argument becomes unreachable, so br_on_exn itself is replaced
+  ;; with its argument in ReFinalize process after precompute.
+  (event $event$0 (attr 0) (param))
+  (func $unreachable-br_on_exn
+    (block $label$1
+      (drop
+        (br_on_exn $label$1 $event$0
+          (loop $label$2 (result exnref)
+            (br $label$2)
+          )
+        )
+      )
+    )
+  )
+)
diff --git a/binaryen/test/passes/precompute_coalesce-locals_vacuum.txt b/binaryen/test/passes/precompute_coalesce-locals_vacuum.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/precompute_coalesce-locals_vacuum.txt
@@ -0,0 +1,8 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $nested-br_if-value (param $0 i32) (result i32)
+  (loop $label$0
+   (br $label$0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/precompute_coalesce-locals_vacuum.wast b/binaryen/test/passes/precompute_coalesce-locals_vacuum.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/precompute_coalesce-locals_vacuum.wast
@@ -0,0 +1,20 @@
+(module
+ (func $nested-br_if-value (param $var$0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (loop $label$0 (result i32)
+   (drop
+    (i32.const 2)
+   )
+   (block (result i32)
+    (local.set $2
+     (i32.const 4)
+    )
+    (br_if $label$0 ;; precomputing this into a br must change the type
+     (i32.const 1)
+    )
+    (local.get $2)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/print-call-graph.txt b/binaryen/test/passes/print-call-graph.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/print-call-graph.txt
@@ -0,0 +1,1497 @@
+digraph call {
+  rankdir = LR;
+  subgraph cluster_key {
+    node [shape=box, fontname=courier, fontsize=10];
+    edge [fontname=courier, fontsize=10];
+    label = "Key";
+    "Import" [style="filled", fillcolor="turquoise"];
+    "Export" [style="filled", fillcolor="gray"];
+    "Indirect Target" [style="filled, rounded", fillcolor="white"];
+    "A" -> "B" [style="filled, rounded", label = "Direct Call"];
+  }
+
+  node [shape=box, fontname=courier, fontsize=10];
+  "stackAlloc" [style="filled", fillcolor="white"];
+  "stackSave" [style="filled", fillcolor="white"];
+  "stackRestore" [style="filled", fillcolor="white"];
+  "establishStackSpace" [style="filled", fillcolor="white"];
+  "setThrew" [style="filled", fillcolor="white"];
+  "setTempRet0" [style="filled", fillcolor="white"];
+  "getTempRet0" [style="filled", fillcolor="white"];
+  "_malloc" [style="filled", fillcolor="white"];
+  "_free" [style="filled", fillcolor="white"];
+  "_main" [style="filled", fillcolor="white"];
+  "___stdio_close" [style="filled", fillcolor="white"];
+  "___stdio_write" [style="filled", fillcolor="white"];
+  "___stdio_seek" [style="filled", fillcolor="white"];
+  "___syscall_ret" [style="filled", fillcolor="white"];
+  "___errno_location" [style="filled", fillcolor="white"];
+  "_cleanup_387" [style="filled", fillcolor="white"];
+  "___stdout_write" [style="filled", fillcolor="white"];
+  "_fflush" [style="filled", fillcolor="white"];
+  "___fflush_unlocked" [style="filled", fillcolor="white"];
+  "__Znwj" [style="filled", fillcolor="white"];
+  "__ZSt15get_new_handlerv" [style="filled", fillcolor="white"];
+  "runPostSets" [style="filled", fillcolor="white"];
+  "_memset" [style="filled", fillcolor="white"];
+  "_memcpy" [style="filled", fillcolor="white"];
+  "_pthread_self" [style="filled", fillcolor="white"];
+  "dynCall_ii" [style="filled", fillcolor="white"];
+  "dynCall_iiii" [style="filled", fillcolor="white"];
+  "dynCall_vi" [style="filled", fillcolor="white"];
+  "dynCall_v" [style="filled", fillcolor="white"];
+  "b0" [style="filled", fillcolor="white"];
+  "b1" [style="filled", fillcolor="white"];
+  "b2" [style="filled", fillcolor="white"];
+  "b3" [style="filled", fillcolor="white"];
+  "abort" [style="filled", fillcolor="turquoise"];
+  "_pthread_cleanup_pop" [style="filled", fillcolor="turquoise"];
+  "___lock" [style="filled", fillcolor="turquoise"];
+  "___syscall6" [style="filled", fillcolor="turquoise"];
+  "_pthread_cleanup_push" [style="filled", fillcolor="turquoise"];
+  "___syscall140" [style="filled", fillcolor="turquoise"];
+  "_emscripten_memcpy_big" [style="filled", fillcolor="turquoise"];
+  "___syscall54" [style="filled", fillcolor="turquoise"];
+  "___unlock" [style="filled", fillcolor="turquoise"];
+  "___syscall146" [style="filled", fillcolor="turquoise"];
+  "_fflush" [style="filled", fillcolor="gray"];
+  "_main" [style="filled", fillcolor="gray"];
+  "_pthread_self" [style="filled", fillcolor="gray"];
+  "_memset" [style="filled", fillcolor="gray"];
+  "_malloc" [style="filled", fillcolor="gray"];
+  "_memcpy" [style="filled", fillcolor="gray"];
+  "_free" [style="filled", fillcolor="gray"];
+  "___errno_location" [style="filled", fillcolor="gray"];
+  "runPostSets" [style="filled", fillcolor="gray"];
+  "stackAlloc" [style="filled", fillcolor="gray"];
+  "stackSave" [style="filled", fillcolor="gray"];
+  "stackRestore" [style="filled", fillcolor="gray"];
+  "establishStackSpace" [style="filled", fillcolor="gray"];
+  "setThrew" [style="filled", fillcolor="gray"];
+  "setTempRet0" [style="filled", fillcolor="gray"];
+  "getTempRet0" [style="filled", fillcolor="gray"];
+  "dynCall_ii" [style="filled", fillcolor="gray"];
+  "dynCall_iiii" [style="filled", fillcolor="gray"];
+  "dynCall_vi" [style="filled", fillcolor="gray"];
+  "dynCall_v" [style="filled", fillcolor="gray"];
+  "_main" -> "__Znwj"; // call
+  "___stdio_close" -> "___syscall6"; // call
+  "___stdio_close" -> "___syscall_ret"; // call
+  "___stdio_write" -> "_pthread_cleanup_push"; // call
+  "___stdio_write" -> "___syscall146"; // call
+  "___stdio_write" -> "___syscall_ret"; // call
+  "___stdio_write" -> "_pthread_cleanup_pop"; // call
+  "___stdio_seek" -> "___syscall140"; // call
+  "___stdio_seek" -> "___syscall_ret"; // call
+  "___syscall_ret" -> "___errno_location"; // call
+  "___errno_location" -> "_pthread_self"; // call
+  "_cleanup_387" -> "_free"; // call
+  "___stdout_write" -> "___syscall54"; // call
+  "___stdout_write" -> "___stdio_write"; // call
+  "_fflush" -> "___fflush_unlocked"; // call
+  "_fflush" -> "_malloc"; // call
+  "_fflush" -> "_free"; // call
+  "_fflush" -> "_fflush"; // call
+  "_fflush" -> "___lock"; // call
+  "_fflush" -> "___unlock"; // call
+  "__Znwj" -> "_malloc"; // call
+  "__Znwj" -> "__ZSt15get_new_handlerv"; // call
+  "_memcpy" -> "_emscripten_memcpy_big"; // call
+  "b0" -> "abort"; // call
+  "b1" -> "abort"; // call
+  "b2" -> "abort"; // call
+  "b3" -> "abort"; // call
+  "b0" [style="filled, rounded"];
+  "___stdio_close" [style="filled, rounded"];
+  "b1" [style="filled, rounded"];
+  "___stdout_write" [style="filled, rounded"];
+  "___stdio_seek" [style="filled, rounded"];
+  "___stdio_write" [style="filled, rounded"];
+  "b2" [style="filled, rounded"];
+  "_cleanup_387" [style="filled, rounded"];
+  "b3" [style="filled, rounded"];
+}
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32) (result i32)))
+ (import "env" "memory" (memory $0 256 256))
+ (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")
+ (import "env" "table" (table $timport$0 9 9 funcref))
+ (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))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (import "env" "abort" (func $abort (param i32)))
+ (import "env" "_pthread_cleanup_pop" (func $_pthread_cleanup_pop (param i32)))
+ (import "env" "___lock" (func $___lock (param i32)))
+ (import "env" "___syscall6" (func $___syscall6 (param i32 i32) (result i32)))
+ (import "env" "_pthread_cleanup_push" (func $_pthread_cleanup_push (param i32 i32)))
+ (import "env" "___syscall140" (func $___syscall140 (param i32 i32) (result i32)))
+ (import "env" "_emscripten_memcpy_big" (func $_emscripten_memcpy_big (param i32 i32 i32) (result i32)))
+ (import "env" "___syscall54" (func $___syscall54 (param i32 i32) (result i32)))
+ (import "env" "___unlock" (func $___unlock (param i32)))
+ (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))
+ (global $setjmpId (mut i32) (i32.const 0))
+ (global $undef (mut i32) (i32.const 0))
+ (global $nan (mut f64) (global.get $nan$asm2wasm$import))
+ (global $inf (mut f64) (global.get $inf$asm2wasm$import))
+ (global $tempInt (mut i32) (i32.const 0))
+ (global $tempBigInt (mut i32) (i32.const 0))
+ (global $tempBigIntP (mut i32) (i32.const 0))
+ (global $tempBigIntS (mut i32) (i32.const 0))
+ (global $tempBigIntR (mut f64) (f64.const 0))
+ (global $tempBigIntI (mut i32) (i32.const 0))
+ (global $tempBigIntD (mut i32) (i32.const 0))
+ (global $tempValue (mut i32) (i32.const 0))
+ (global $tempDouble (mut f64) (f64.const 0))
+ (global $tempRet0 (mut i32) (i32.const 0))
+ (global $tempFloat (mut f32) (f32.const 0))
+ (global $f0 (mut f32) (f32.const 0))
+ (export "_fflush" (func $_fflush))
+ (export "_main" (func $_main))
+ (export "_pthread_self" (func $_pthread_self))
+ (export "_memset" (func $_memset))
+ (export "_malloc" (func $_malloc))
+ (export "_memcpy" (func $_memcpy))
+ (export "_free" (func $_free))
+ (export "___errno_location" (func $___errno_location))
+ (export "runPostSets" (func $runPostSets))
+ (export "stackAlloc" (func $stackAlloc))
+ (export "stackSave" (func $stackSave))
+ (export "stackRestore" (func $stackRestore))
+ (export "establishStackSpace" (func $establishStackSpace))
+ (export "setThrew" (func $setThrew))
+ (export "setTempRet0" (func $setTempRet0))
+ (export "getTempRet0" (func $getTempRet0))
+ (export "dynCall_ii" (func $dynCall_ii))
+ (export "dynCall_iiii" (func $dynCall_iiii))
+ (export "dynCall_vi" (func $dynCall_vi))
+ (export "dynCall_v" (func $dynCall_v))
+ (func $stackAlloc (param $0 i32) (result i32)
+  (local $1 i32)
+  (local.set $1
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (local.get $0)
+   )
+  )
+  (global.set $STACKTOP
+   (i32.and
+    (i32.add
+     (global.get $STACKTOP)
+     (i32.const 15)
+    )
+    (i32.const -16)
+   )
+  )
+  (local.get $1)
+ )
+ (func $stackSave (result i32)
+  (global.get $STACKTOP)
+ )
+ (func $stackRestore (param $0 i32)
+  (global.set $STACKTOP
+   (local.get $0)
+  )
+ )
+ (func $establishStackSpace (param $0 i32) (param $1 i32)
+  (global.set $STACKTOP
+   (local.get $0)
+  )
+  (global.set $STACK_MAX
+   (local.get $1)
+  )
+ )
+ (func $setThrew (param $0 i32) (param $1 i32)
+  (if
+   (i32.eqz
+    (global.get $__THREW__)
+   )
+   (block $block
+    (global.set $__THREW__
+     (local.get $0)
+    )
+    (global.set $threwValue
+     (local.get $1)
+    )
+   )
+  )
+ )
+ (func $setTempRet0 (param $0 i32)
+  (global.set $tempRet0
+   (local.get $0)
+  )
+ )
+ (func $getTempRet0 (result i32)
+  (global.get $tempRet0)
+ )
+ (func $_malloc (param $0 i32) (result i32)
+  (i32.const 0)
+ )
+ (func $_free (param $0 i32)
+  (nop)
+ )
+ (func $_main (result i32)
+  (local $0 i32)
+  (i64.store align=4
+   (local.tee $0
+    (call $__Znwj
+     (i32.const 8)
+    )
+   )
+   (i64.const 0)
+  )
+  (local.get $0)
+ )
+ (func $___stdio_close (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $1
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 16)
+   )
+  )
+  (i32.store
+   (local.tee $2
+    (local.get $1)
+   )
+   (i32.load offset=60
+    (local.get $0)
+   )
+  )
+  (local.set $0
+   (call $___syscall_ret
+    (call $___syscall6
+     (i32.const 6)
+     (local.get $2)
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $1)
+  )
+  (local.get $0)
+ )
+ (func $___stdio_write (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local.set $7
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 48)
+   )
+  )
+  (local.set $8
+   (i32.add
+    (local.get $7)
+    (i32.const 16)
+   )
+  )
+  (local.set $9
+   (local.get $7)
+  )
+  (i32.store
+   (local.tee $3
+    (i32.add
+     (local.get $7)
+     (i32.const 32)
+    )
+   )
+   (local.tee $5
+    (i32.load
+     (local.tee $6
+      (i32.add
+       (local.get $0)
+       (i32.const 28)
+      )
+     )
+    )
+   )
+  )
+  (i32.store offset=4
+   (local.get $3)
+   (local.tee $4
+    (i32.sub
+     (i32.load
+      (local.tee $10
+       (i32.add
+        (local.get $0)
+        (i32.const 20)
+       )
+      )
+     )
+     (local.get $5)
+    )
+   )
+  )
+  (i32.store offset=8
+   (local.get $3)
+   (local.get $1)
+  )
+  (i32.store offset=12
+   (local.get $3)
+   (local.get $2)
+  )
+  (local.set $13
+   (i32.add
+    (local.get $0)
+    (i32.const 60)
+   )
+  )
+  (local.set $14
+   (i32.add
+    (local.get $0)
+    (i32.const 44)
+   )
+  )
+  (local.set $1
+   (local.get $3)
+  )
+  (local.set $5
+   (i32.const 2)
+  )
+  (local.set $11
+   (i32.add
+    (local.get $4)
+    (local.get $2)
+   )
+  )
+  (local.set $0
+   (block $jumpthreading$outer$1 (result i32)
+    (block $jumpthreading$inner$1
+     (block $jumpthreading$inner$0
+      (loop $while-in
+       (br_if $jumpthreading$inner$0
+        (i32.eq
+         (local.get $11)
+         (local.tee $4
+          (if (result i32)
+           (i32.load
+            (i32.const 1140)
+           )
+           (block $block (result i32)
+            (call $_pthread_cleanup_push
+             (i32.const 1)
+             (local.get $0)
+            )
+            (i32.store
+             (local.get $9)
+             (i32.load
+              (local.get $13)
+             )
+            )
+            (i32.store offset=4
+             (local.get $9)
+             (local.get $1)
+            )
+            (i32.store offset=8
+             (local.get $9)
+             (local.get $5)
+            )
+            (local.set $3
+             (call $___syscall_ret
+              (call $___syscall146
+               (i32.const 146)
+               (local.get $9)
+              )
+             )
+            )
+            (call $_pthread_cleanup_pop
+             (i32.const 0)
+            )
+            (local.get $3)
+           )
+           (block $block0 (result i32)
+            (i32.store
+             (local.get $8)
+             (i32.load
+              (local.get $13)
+             )
+            )
+            (i32.store offset=4
+             (local.get $8)
+             (local.get $1)
+            )
+            (i32.store offset=8
+             (local.get $8)
+             (local.get $5)
+            )
+            (call $___syscall_ret
+             (call $___syscall146
+              (i32.const 146)
+              (local.get $8)
+             )
+            )
+           )
+          )
+         )
+        )
+       )
+       (br_if $jumpthreading$inner$1
+        (i32.lt_s
+         (local.get $4)
+         (i32.const 0)
+        )
+       )
+       (local.set $11
+        (i32.sub
+         (local.get $11)
+         (local.get $4)
+        )
+       )
+       (local.set $1
+        (if (result i32)
+         (i32.gt_u
+          (local.get $4)
+          (local.tee $12
+           (i32.load offset=4
+            (local.get $1)
+           )
+          )
+         )
+         (block $block2 (result i32)
+          (i32.store
+           (local.get $6)
+           (local.tee $3
+            (i32.load
+             (local.get $14)
+            )
+           )
+          )
+          (i32.store
+           (local.get $10)
+           (local.get $3)
+          )
+          (local.set $4
+           (i32.sub
+            (local.get $4)
+            (local.get $12)
+           )
+          )
+          (local.set $3
+           (i32.add
+            (local.get $1)
+            (i32.const 8)
+           )
+          )
+          (local.set $5
+           (i32.add
+            (local.get $5)
+            (i32.const -1)
+           )
+          )
+          (i32.load offset=12
+           (local.get $1)
+          )
+         )
+         (if (result i32)
+          (i32.eq
+           (local.get $5)
+           (i32.const 2)
+          )
+          (block $block4 (result i32)
+           (i32.store
+            (local.get $6)
+            (i32.add
+             (i32.load
+              (local.get $6)
+             )
+             (local.get $4)
+            )
+           )
+           (local.set $3
+            (local.get $1)
+           )
+           (local.set $5
+            (i32.const 2)
+           )
+           (local.get $12)
+          )
+          (block $block5 (result i32)
+           (local.set $3
+            (local.get $1)
+           )
+           (local.get $12)
+          )
+         )
+        )
+       )
+       (i32.store
+        (local.get $3)
+        (i32.add
+         (i32.load
+          (local.get $3)
+         )
+         (local.get $4)
+        )
+       )
+       (i32.store offset=4
+        (local.get $3)
+        (i32.sub
+         (local.get $1)
+         (local.get $4)
+        )
+       )
+       (local.set $1
+        (local.get $3)
+       )
+       (br $while-in)
+      )
+     )
+     (i32.store offset=16
+      (local.get $0)
+      (i32.add
+       (local.tee $1
+        (i32.load
+         (local.get $14)
+        )
+       )
+       (i32.load offset=48
+        (local.get $0)
+       )
+      )
+     )
+     (i32.store
+      (local.get $6)
+      (local.tee $0
+       (local.get $1)
+      )
+     )
+     (i32.store
+      (local.get $10)
+      (local.get $0)
+     )
+     (br $jumpthreading$outer$1
+      (local.get $2)
+     )
+    )
+    (i32.store offset=16
+     (local.get $0)
+     (i32.const 0)
+    )
+    (i32.store
+     (local.get $6)
+     (i32.const 0)
+    )
+    (i32.store
+     (local.get $10)
+     (i32.const 0)
+    )
+    (i32.store
+     (local.get $0)
+     (i32.or
+      (i32.load
+       (local.get $0)
+      )
+      (i32.const 32)
+     )
+    )
+    (select
+     (i32.const 0)
+     (i32.sub
+      (local.get $2)
+      (i32.load offset=4
+       (local.get $1)
+      )
+     )
+     (i32.eq
+      (local.get $5)
+      (i32.const 2)
+     )
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $7)
+  )
+  (local.get $0)
+ )
+ (func $___stdio_seek (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local.set $4
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 32)
+   )
+  )
+  (i32.store
+   (local.tee $3
+    (local.get $4)
+   )
+   (i32.load offset=60
+    (local.get $0)
+   )
+  )
+  (i32.store offset=4
+   (local.get $3)
+   (i32.const 0)
+  )
+  (i32.store offset=8
+   (local.get $3)
+   (local.get $1)
+  )
+  (i32.store offset=12
+   (local.get $3)
+   (local.tee $0
+    (i32.add
+     (local.get $4)
+     (i32.const 20)
+    )
+   )
+  )
+  (i32.store offset=16
+   (local.get $3)
+   (local.get $2)
+  )
+  (local.set $0
+   (if (result i32)
+    (i32.lt_s
+     (call $___syscall_ret
+      (call $___syscall140
+       (i32.const 140)
+       (local.get $3)
+      )
+     )
+     (i32.const 0)
+    )
+    (block $block (result i32)
+     (i32.store
+      (local.get $0)
+      (i32.const -1)
+     )
+     (i32.const -1)
+    )
+    (i32.load
+     (local.get $0)
+    )
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $4)
+  )
+  (local.get $0)
+ )
+ (func $___syscall_ret (param $0 i32) (result i32)
+  (if (result i32)
+   (i32.gt_u
+    (local.get $0)
+    (i32.const -4096)
+   )
+   (block $block (result i32)
+    (i32.store
+     (call $___errno_location)
+     (i32.sub
+      (i32.const 0)
+      (local.get $0)
+     )
+    )
+    (i32.const -1)
+   )
+   (local.get $0)
+  )
+ )
+ (func $___errno_location (result i32)
+  (if (result i32)
+   (i32.load
+    (i32.const 1140)
+   )
+   (i32.load offset=64
+    (call $_pthread_self)
+   )
+   (i32.const 1184)
+  )
+ )
+ (func $_cleanup_387 (param $0 i32)
+  (if
+   (i32.eqz
+    (i32.load offset=68
+     (local.get $0)
+    )
+   )
+   (call $_free
+    (local.get $0)
+   )
+  )
+ )
+ (func $___stdout_write (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $4
+   (global.get $STACKTOP)
+  )
+  (global.set $STACKTOP
+   (i32.add
+    (global.get $STACKTOP)
+    (i32.const 80)
+   )
+  )
+  (local.set $3
+   (local.get $4)
+  )
+  (local.set $5
+   (i32.add
+    (local.get $4)
+    (i32.const 12)
+   )
+  )
+  (i32.store offset=36
+   (local.get $0)
+   (i32.const 3)
+  )
+  (if
+   (i32.eqz
+    (i32.and
+     (i32.load
+      (local.get $0)
+     )
+     (i32.const 64)
+    )
+   )
+   (block $block
+    (i32.store
+     (local.get $3)
+     (i32.load offset=60
+      (local.get $0)
+     )
+    )
+    (i32.store offset=4
+     (local.get $3)
+     (i32.const 21505)
+    )
+    (i32.store offset=8
+     (local.get $3)
+     (local.get $5)
+    )
+    (if
+     (call $___syscall54
+      (i32.const 54)
+      (local.get $3)
+     )
+     (i32.store8 offset=75
+      (local.get $0)
+      (i32.const -1)
+     )
+    )
+   )
+  )
+  (local.set $0
+   (call $___stdio_write
+    (local.get $0)
+    (local.get $1)
+    (local.get $2)
+   )
+  )
+  (global.set $STACKTOP
+   (local.get $4)
+  )
+  (local.get $0)
+ )
+ (func $_fflush (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (block $do-once (result i32)
+   (if (result i32)
+    (local.get $0)
+    (block $block (result i32)
+     (if
+      (i32.le_s
+       (i32.load offset=76
+        (local.get $0)
+       )
+       (i32.const -1)
+      )
+      (br $do-once
+       (call $___fflush_unlocked
+        (local.get $0)
+       )
+      )
+     )
+     (local.set $2
+      (i32.eqz
+       (call $_malloc
+        (local.get $0)
+       )
+      )
+     )
+     (local.set $1
+      (call $___fflush_unlocked
+       (local.get $0)
+      )
+     )
+     (if (result i32)
+      (local.get $2)
+      (local.get $1)
+      (block $block9 (result i32)
+       (call $_free
+        (local.get $0)
+       )
+       (local.get $1)
+      )
+     )
+    )
+    (block $block10 (result i32)
+     (local.set $0
+      (if (result i32)
+       (i32.load
+        (i32.const 1136)
+       )
+       (call $_fflush
+        (i32.load
+         (i32.const 1136)
+        )
+       )
+       (i32.const 0)
+      )
+     )
+     (call $___lock
+      (i32.const 1168)
+     )
+     (if
+      (local.tee $1
+       (i32.load
+        (i32.const 1164)
+       )
+      )
+      (loop $while-in
+       (local.set $2
+        (if (result i32)
+         (i32.gt_s
+          (i32.load offset=76
+           (local.get $1)
+          )
+          (i32.const -1)
+         )
+         (call $_malloc
+          (local.get $1)
+         )
+         (i32.const 0)
+        )
+       )
+       (local.set $0
+        (if (result i32)
+         (i32.gt_u
+          (i32.load offset=20
+           (local.get $1)
+          )
+          (i32.load offset=28
+           (local.get $1)
+          )
+         )
+         (i32.or
+          (call $___fflush_unlocked
+           (local.get $1)
+          )
+          (local.get $0)
+         )
+         (local.get $0)
+        )
+       )
+       (if
+        (local.get $2)
+        (call $_free
+         (local.get $1)
+        )
+       )
+       (br_if $while-in
+        (local.tee $1
+         (i32.load offset=56
+          (local.get $1)
+         )
+        )
+       )
+      )
+     )
+     (call $___unlock
+      (i32.const 1168)
+     )
+     (local.get $0)
+    )
+   )
+  )
+ )
+ (func $___fflush_unlocked (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block $jumpthreading$outer$0 (result i32)
+   (block $jumpthreading$inner$0
+    (br_if $jumpthreading$inner$0
+     (i32.le_u
+      (i32.load
+       (local.tee $1
+        (i32.add
+         (local.get $0)
+         (i32.const 20)
+        )
+       )
+      )
+      (i32.load
+       (local.tee $2
+        (i32.add
+         (local.get $0)
+         (i32.const 28)
+        )
+       )
+      )
+     )
+    )
+    (drop
+     (call_indirect (type $i32_i32_i32_=>_i32)
+      (local.get $0)
+      (i32.const 0)
+      (i32.const 0)
+      (i32.add
+       (i32.and
+        (i32.load offset=36
+         (local.get $0)
+        )
+        (i32.const 3)
+       )
+       (i32.const 2)
+      )
+     )
+    )
+    (br_if $jumpthreading$inner$0
+     (i32.load
+      (local.get $1)
+     )
+    )
+    (br $jumpthreading$outer$0
+     (i32.const -1)
+    )
+   )
+   (if
+    (i32.lt_u
+     (local.tee $4
+      (i32.load
+       (local.tee $3
+        (i32.add
+         (local.get $0)
+         (i32.const 4)
+        )
+       )
+      )
+     )
+     (local.tee $6
+      (i32.load
+       (local.tee $5
+        (i32.add
+         (local.get $0)
+         (i32.const 8)
+        )
+       )
+      )
+     )
+    )
+    (drop
+     (call_indirect (type $i32_i32_i32_=>_i32)
+      (local.get $0)
+      (i32.sub
+       (local.get $4)
+       (local.get $6)
+      )
+      (i32.const 1)
+      (i32.add
+       (i32.and
+        (i32.load offset=40
+         (local.get $0)
+        )
+        (i32.const 3)
+       )
+       (i32.const 2)
+      )
+     )
+    )
+   )
+   (i32.store offset=16
+    (local.get $0)
+    (i32.const 0)
+   )
+   (i32.store
+    (local.get $2)
+    (i32.const 0)
+   )
+   (i32.store
+    (local.get $1)
+    (i32.const 0)
+   )
+   (i32.store
+    (local.get $5)
+    (i32.const 0)
+   )
+   (i32.store
+    (local.get $3)
+    (i32.const 0)
+   )
+   (i32.const 0)
+  )
+ )
+ (func $__Znwj (param $0 i32) (result i32)
+  (local $1 i32)
+  (local.set $1
+   (select
+    (local.get $0)
+    (i32.const 1)
+    (local.get $0)
+   )
+  )
+  (loop $while-in
+   (block $while-out
+    (br_if $while-out
+     (local.tee $0
+      (call $_malloc
+       (local.get $1)
+      )
+     )
+    )
+    (if
+     (local.tee $0
+      (call $__ZSt15get_new_handlerv)
+     )
+     (block $block
+      (call_indirect (type $none_=>_none)
+       (i32.add
+        (i32.and
+         (local.get $0)
+         (i32.const 0)
+        )
+        (i32.const 8)
+       )
+      )
+      (br $while-in)
+     )
+     (local.set $0
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $__ZSt15get_new_handlerv (result i32)
+  (local $0 i32)
+  (i32.store
+   (i32.const 1188)
+   (i32.add
+    (local.tee $0
+     (i32.load
+      (i32.const 1188)
+     )
+    )
+    (i32.const 0)
+   )
+  )
+  (local.get $0)
+ )
+ (func $runPostSets
+  (nop)
+ )
+ (func $_memset (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local.set $4
+   (i32.add
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (if
+   (i32.ge_s
+    (local.get $2)
+    (i32.const 20)
+   )
+   (block $block
+    (local.set $5
+     (i32.or
+      (i32.or
+       (i32.or
+        (local.tee $1
+         (i32.and
+          (local.get $1)
+          (i32.const 255)
+         )
+        )
+        (i32.shl
+         (local.get $1)
+         (i32.const 8)
+        )
+       )
+       (i32.shl
+        (local.get $1)
+        (i32.const 16)
+       )
+      )
+      (i32.shl
+       (local.get $1)
+       (i32.const 24)
+      )
+     )
+    )
+    (local.set $6
+     (i32.and
+      (local.get $4)
+      (i32.const -4)
+     )
+    )
+    (if
+     (local.tee $3
+      (i32.and
+       (local.get $0)
+       (i32.const 3)
+      )
+     )
+     (block $block17
+      (local.set $3
+       (i32.sub
+        (i32.add
+         (local.get $0)
+         (i32.const 4)
+        )
+        (local.get $3)
+       )
+      )
+      (loop $while-in
+       (if
+        (i32.lt_s
+         (local.get $0)
+         (local.get $3)
+        )
+        (block $block19
+         (i32.store8
+          (local.get $0)
+          (local.get $1)
+         )
+         (local.set $0
+          (i32.add
+           (local.get $0)
+           (i32.const 1)
+          )
+         )
+         (br $while-in)
+        )
+       )
+      )
+     )
+    )
+    (loop $while-in1
+     (if
+      (i32.lt_s
+       (local.get $0)
+       (local.get $6)
+      )
+      (block $block21
+       (i32.store
+        (local.get $0)
+        (local.get $5)
+       )
+       (local.set $0
+        (i32.add
+         (local.get $0)
+         (i32.const 4)
+        )
+       )
+       (br $while-in1)
+      )
+     )
+    )
+   )
+  )
+  (loop $while-in3
+   (if
+    (i32.lt_s
+     (local.get $0)
+     (local.get $4)
+    )
+    (block $block23
+     (i32.store8
+      (local.get $0)
+      (local.get $1)
+     )
+     (local.set $0
+      (i32.add
+       (local.get $0)
+       (i32.const 1)
+      )
+     )
+     (br $while-in3)
+    )
+   )
+  )
+  (i32.sub
+   (local.get $0)
+   (local.get $2)
+  )
+ )
+ (func $_memcpy (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (if
+   (i32.ge_s
+    (local.get $2)
+    (i32.const 4096)
+   )
+   (return
+    (call $_emscripten_memcpy_big
+     (local.get $0)
+     (local.get $1)
+     (local.get $2)
+    )
+   )
+  )
+  (local.set $3
+   (local.get $0)
+  )
+  (if
+   (i32.eq
+    (i32.and
+     (local.get $0)
+     (i32.const 3)
+    )
+    (i32.and
+     (local.get $1)
+     (i32.const 3)
+    )
+   )
+   (block $block
+    (loop $while-in
+     (block $while-out
+      (br_if $while-out
+       (i32.eqz
+        (i32.and
+         (local.get $0)
+         (i32.const 3)
+        )
+       )
+      )
+      (if
+       (i32.eqz
+        (local.get $2)
+       )
+       (return
+        (local.get $3)
+       )
+      )
+      (i32.store8
+       (local.get $0)
+       (i32.load8_s
+        (local.get $1)
+       )
+      )
+      (local.set $0
+       (i32.add
+        (local.get $0)
+        (i32.const 1)
+       )
+      )
+      (local.set $1
+       (i32.add
+        (local.get $1)
+        (i32.const 1)
+       )
+      )
+      (local.set $2
+       (i32.sub
+        (local.get $2)
+        (i32.const 1)
+       )
+      )
+      (br $while-in)
+     )
+    )
+    (loop $while-in1
+     (if
+      (i32.ge_s
+       (local.get $2)
+       (i32.const 4)
+      )
+      (block $block27
+       (i32.store
+        (local.get $0)
+        (i32.load
+         (local.get $1)
+        )
+       )
+       (local.set $0
+        (i32.add
+         (local.get $0)
+         (i32.const 4)
+        )
+       )
+       (local.set $1
+        (i32.add
+         (local.get $1)
+         (i32.const 4)
+        )
+       )
+       (local.set $2
+        (i32.sub
+         (local.get $2)
+         (i32.const 4)
+        )
+       )
+       (br $while-in1)
+      )
+     )
+    )
+   )
+  )
+  (loop $while-in3
+   (if
+    (i32.gt_s
+     (local.get $2)
+     (i32.const 0)
+    )
+    (block $block29
+     (i32.store8
+      (local.get $0)
+      (i32.load8_s
+       (local.get $1)
+      )
+     )
+     (local.set $0
+      (i32.add
+       (local.get $0)
+       (i32.const 1)
+      )
+     )
+     (local.set $1
+      (i32.add
+       (local.get $1)
+       (i32.const 1)
+      )
+     )
+     (local.set $2
+      (i32.sub
+       (local.get $2)
+       (i32.const 1)
+      )
+     )
+     (br $while-in3)
+    )
+   )
+  )
+  (local.get $3)
+ )
+ (func $_pthread_self (result i32)
+  (i32.const 0)
+ )
+ (func $dynCall_ii (param $0 i32) (param $1 i32) (result i32)
+  (call_indirect (type $i32_=>_i32)
+   (local.get $1)
+   (i32.add
+    (i32.and
+     (local.get $0)
+     (i32.const 1)
+    )
+    (i32.const 0)
+   )
+  )
+ )
+ (func $dynCall_iiii (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
+  (call_indirect (type $i32_i32_i32_=>_i32)
+   (local.get $1)
+   (local.get $2)
+   (local.get $3)
+   (i32.add
+    (i32.and
+     (local.get $0)
+     (i32.const 3)
+    )
+    (i32.const 2)
+   )
+  )
+ )
+ (func $dynCall_vi (param $0 i32) (param $1 i32)
+  (call_indirect (type $i32_=>_none)
+   (local.get $1)
+   (i32.add
+    (i32.and
+     (local.get $0)
+     (i32.const 1)
+    )
+    (i32.const 6)
+   )
+  )
+ )
+ (func $dynCall_v (param $0 i32)
+  (call_indirect (type $none_=>_none)
+   (i32.add
+    (i32.and
+     (local.get $0)
+     (i32.const 0)
+    )
+    (i32.const 8)
+   )
+  )
+ )
+ (func $b0 (param $0 i32) (result i32)
+  (call $abort
+   (i32.const 0)
+  )
+  (i32.const 0)
+ )
+ (func $b1 (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (call $abort
+   (i32.const 1)
+  )
+  (i32.const 0)
+ )
+ (func $b2 (param $0 i32)
+  (call $abort
+   (i32.const 2)
+  )
+ )
+ (func $b3
+  (call $abort
+   (i32.const 3)
+  )
+ )
+)
diff --git a/binaryen/test/passes/print-call-graph.wast b/binaryen/test/passes/print-call-graph.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/print-call-graph.wast
@@ -0,0 +1,1382 @@
+(module
+  (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32)))
+  (type $FUNCSIG$v (func))
+  (type $FUNCSIG$ii (func (param i32) (result i32)))
+  (type $FUNCSIG$vi (func (param i32)))
+  (type $FUNCSIG$iii (func (param i32 i32) (result i32)))
+  (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))
+  (import "env" "abort" (func $abort (param i32)))
+  (import "env" "_pthread_cleanup_pop" (func $_pthread_cleanup_pop (param i32)))
+  (import "env" "___lock" (func $___lock (param i32)))
+  (import "env" "___syscall6" (func $___syscall6 (param i32 i32) (result i32)))
+  (import "env" "_pthread_cleanup_push" (func $_pthread_cleanup_push (param i32 i32)))
+  (import "env" "___syscall140" (func $___syscall140 (param i32 i32) (result i32)))
+  (import "env" "_emscripten_memcpy_big" (func $_emscripten_memcpy_big (param i32 i32 i32) (result i32)))
+  (import "env" "___syscall54" (func $___syscall54 (param i32 i32) (result i32)))
+  (import "env" "___unlock" (func $___unlock (param i32)))
+  (import "env" "___syscall146" (func $___syscall146 (param i32 i32) (result i32)))
+  (import "env" "memory" (memory $0 256 256))
+  (import "env" "table" (table 9 9 funcref))
+  (import "env" "memoryBase" (global $memoryBase i32))
+  (import "env" "tableBase" (global $tableBase i32))
+  (elem (i32.const 0) $b0 $___stdio_close $b1 $___stdout_write $___stdio_seek $___stdio_write $b2 $_cleanup_387 $b3)
+  (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))
+  (global $setjmpId (mut i32) (i32.const 0))
+  (global $undef (mut i32) (i32.const 0))
+  (global $nan (mut f64) (global.get $nan$asm2wasm$import))
+  (global $inf (mut f64) (global.get $inf$asm2wasm$import))
+  (global $tempInt (mut i32) (i32.const 0))
+  (global $tempBigInt (mut i32) (i32.const 0))
+  (global $tempBigIntP (mut i32) (i32.const 0))
+  (global $tempBigIntS (mut i32) (i32.const 0))
+  (global $tempBigIntR (mut f64) (f64.const 0))
+  (global $tempBigIntI (mut i32) (i32.const 0))
+  (global $tempBigIntD (mut i32) (i32.const 0))
+  (global $tempValue (mut i32) (i32.const 0))
+  (global $tempDouble (mut f64) (f64.const 0))
+  (global $tempRet0 (mut i32) (i32.const 0))
+  (global $tempFloat (mut f32) (f32.const 0))
+  (global $f0 (mut f32) (f32.const 0))
+  (export "_fflush" (func $_fflush))
+  (export "_main" (func $_main))
+  (export "_pthread_self" (func $_pthread_self))
+  (export "_memset" (func $_memset))
+  (export "_malloc" (func $_malloc))
+  (export "_memcpy" (func $_memcpy))
+  (export "_free" (func $_free))
+  (export "___errno_location" (func $___errno_location))
+  (export "runPostSets" (func $runPostSets))
+  (export "stackAlloc" (func $stackAlloc))
+  (export "stackSave" (func $stackSave))
+  (export "stackRestore" (func $stackRestore))
+  (export "establishStackSpace" (func $establishStackSpace))
+  (export "setThrew" (func $setThrew))
+  (export "setTempRet0" (func $setTempRet0))
+  (export "getTempRet0" (func $getTempRet0))
+  (export "dynCall_ii" (func $dynCall_ii))
+  (export "dynCall_iiii" (func $dynCall_iiii))
+  (export "dynCall_vi" (func $dynCall_vi))
+  (export "dynCall_v" (func $dynCall_v))
+  (func $stackAlloc (param $0 i32) (result i32)
+    (local $1 i32)
+    (local.set $1
+      (global.get $STACKTOP)
+    )
+    (global.set $STACKTOP
+      (i32.add
+        (global.get $STACKTOP)
+        (local.get $0)
+      )
+    )
+    (global.set $STACKTOP
+      (i32.and
+        (i32.add
+          (global.get $STACKTOP)
+          (i32.const 15)
+        )
+        (i32.const -16)
+      )
+    )
+    (local.get $1)
+  )
+  (func $stackSave (result i32)
+    (global.get $STACKTOP)
+  )
+  (func $stackRestore (param $0 i32)
+    (global.set $STACKTOP
+      (local.get $0)
+    )
+  )
+  (func $establishStackSpace (param $0 i32) (param $1 i32)
+    (global.set $STACKTOP
+      (local.get $0)
+    )
+    (global.set $STACK_MAX
+      (local.get $1)
+    )
+  )
+  (func $setThrew (param $0 i32) (param $1 i32)
+    (if
+      (i32.eqz
+        (global.get $__THREW__)
+      )
+      (block
+        (global.set $__THREW__
+          (local.get $0)
+        )
+        (global.set $threwValue
+          (local.get $1)
+        )
+      )
+    )
+  )
+  (func $setTempRet0 (param $0 i32)
+    (global.set $tempRet0
+      (local.get $0)
+    )
+  )
+  (func $getTempRet0 (result i32)
+    (global.get $tempRet0)
+  )
+  (func $_malloc (param $0 i32) (result i32)
+    (i32.const 0)
+  )
+  (func $_free (param $0 i32)
+    (nop)
+  )
+  (func $_main (result i32)
+    (local $0 i32)
+    (i64.store align=4
+      (local.tee $0
+        (call $__Znwj
+          (i32.const 8)
+        )
+      )
+      (i64.const 0)
+    )
+    (local.get $0)
+  )
+  (func $___stdio_close (param $0 i32) (result i32)
+    (local $1 i32)
+    (local $2 i32)
+    (local.set $1
+      (global.get $STACKTOP)
+    )
+    (global.set $STACKTOP
+      (i32.add
+        (global.get $STACKTOP)
+        (i32.const 16)
+      )
+    )
+    (i32.store
+      (local.tee $2
+        (local.get $1)
+      )
+      (i32.load offset=60
+        (local.get $0)
+      )
+    )
+    (local.set $0
+      (call $___syscall_ret
+        (call $___syscall6
+          (i32.const 6)
+          (local.get $2)
+        )
+      )
+    )
+    (global.set $STACKTOP
+      (local.get $1)
+    )
+    (local.get $0)
+  )
+  (func $___stdio_write (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+    (local $3 i32)
+    (local $4 i32)
+    (local $5 i32)
+    (local $6 i32)
+    (local $7 i32)
+    (local $8 i32)
+    (local $9 i32)
+    (local $10 i32)
+    (local $11 i32)
+    (local $12 i32)
+    (local $13 i32)
+    (local $14 i32)
+    (local.set $7
+      (global.get $STACKTOP)
+    )
+    (global.set $STACKTOP
+      (i32.add
+        (global.get $STACKTOP)
+        (i32.const 48)
+      )
+    )
+    (local.set $8
+      (i32.add
+        (local.get $7)
+        (i32.const 16)
+      )
+    )
+    (local.set $9
+      (local.get $7)
+    )
+    (i32.store
+      (local.tee $3
+        (i32.add
+          (local.get $7)
+          (i32.const 32)
+        )
+      )
+      (local.tee $5
+        (i32.load
+          (local.tee $6
+            (i32.add
+              (local.get $0)
+              (i32.const 28)
+            )
+          )
+        )
+      )
+    )
+    (i32.store offset=4
+      (local.get $3)
+      (local.tee $4
+        (i32.sub
+          (i32.load
+            (local.tee $10
+              (i32.add
+                (local.get $0)
+                (i32.const 20)
+              )
+            )
+          )
+          (local.get $5)
+        )
+      )
+    )
+    (i32.store offset=8
+      (local.get $3)
+      (local.get $1)
+    )
+    (i32.store offset=12
+      (local.get $3)
+      (local.get $2)
+    )
+    (local.set $13
+      (i32.add
+        (local.get $0)
+        (i32.const 60)
+      )
+    )
+    (local.set $14
+      (i32.add
+        (local.get $0)
+        (i32.const 44)
+      )
+    )
+    (local.set $1
+      (local.get $3)
+    )
+    (local.set $5
+      (i32.const 2)
+    )
+    (local.set $11
+      (i32.add
+        (local.get $4)
+        (local.get $2)
+      )
+    )
+    (local.set $0
+      (block $jumpthreading$outer$1 (result i32)
+        (block $jumpthreading$inner$1
+          (block $jumpthreading$inner$0
+            (loop $while-in
+              (br_if $jumpthreading$inner$0
+                (i32.eq
+                  (local.get $11)
+                  (local.tee $4
+                    (if (result i32)
+                      (i32.load
+                        (i32.const 1140)
+                      )
+                      (block (result i32)
+                        (call $_pthread_cleanup_push
+                          (i32.const 1)
+                          (local.get $0)
+                        )
+                        (i32.store
+                          (local.get $9)
+                          (i32.load
+                            (local.get $13)
+                          )
+                        )
+                        (i32.store offset=4
+                          (local.get $9)
+                          (local.get $1)
+                        )
+                        (i32.store offset=8
+                          (local.get $9)
+                          (local.get $5)
+                        )
+                        (local.set $3
+                          (call $___syscall_ret
+                            (call $___syscall146
+                              (i32.const 146)
+                              (local.get $9)
+                            )
+                          )
+                        )
+                        (call $_pthread_cleanup_pop
+                          (i32.const 0)
+                        )
+                        (local.get $3)
+                      )
+                      (block (result i32)
+                        (i32.store
+                          (local.get $8)
+                          (i32.load
+                            (local.get $13)
+                          )
+                        )
+                        (i32.store offset=4
+                          (local.get $8)
+                          (local.get $1)
+                        )
+                        (i32.store offset=8
+                          (local.get $8)
+                          (local.get $5)
+                        )
+                        (call $___syscall_ret
+                          (call $___syscall146
+                            (i32.const 146)
+                            (local.get $8)
+                          )
+                        )
+                      )
+                    )
+                  )
+                )
+              )
+              (br_if $jumpthreading$inner$1
+                (i32.lt_s
+                  (local.get $4)
+                  (i32.const 0)
+                )
+              )
+              (local.set $11
+                (i32.sub
+                  (local.get $11)
+                  (local.get $4)
+                )
+              )
+              (local.set $1
+                (if (result i32)
+                  (i32.gt_u
+                    (local.get $4)
+                    (local.tee $12
+                      (i32.load offset=4
+                        (local.get $1)
+                      )
+                    )
+                  )
+                  (block (result i32)
+                    (i32.store
+                      (local.get $6)
+                      (local.tee $3
+                        (i32.load
+                          (local.get $14)
+                        )
+                      )
+                    )
+                    (i32.store
+                      (local.get $10)
+                      (local.get $3)
+                    )
+                    (local.set $4
+                      (i32.sub
+                        (local.get $4)
+                        (local.get $12)
+                      )
+                    )
+                    (local.set $3
+                      (i32.add
+                        (local.get $1)
+                        (i32.const 8)
+                      )
+                    )
+                    (local.set $5
+                      (i32.add
+                        (local.get $5)
+                        (i32.const -1)
+                      )
+                    )
+                    (i32.load offset=12
+                      (local.get $1)
+                    )
+                  )
+                  (if (result i32)
+                    (i32.eq
+                      (local.get $5)
+                      (i32.const 2)
+                    )
+                    (block (result i32)
+                      (i32.store
+                        (local.get $6)
+                        (i32.add
+                          (i32.load
+                            (local.get $6)
+                          )
+                          (local.get $4)
+                        )
+                      )
+                      (local.set $3
+                        (local.get $1)
+                      )
+                      (local.set $5
+                        (i32.const 2)
+                      )
+                      (local.get $12)
+                    )
+                    (block (result i32)
+                      (local.set $3
+                        (local.get $1)
+                      )
+                      (local.get $12)
+                    )
+                  )
+                )
+              )
+              (i32.store
+                (local.get $3)
+                (i32.add
+                  (i32.load
+                    (local.get $3)
+                  )
+                  (local.get $4)
+                )
+              )
+              (i32.store offset=4
+                (local.get $3)
+                (i32.sub
+                  (local.get $1)
+                  (local.get $4)
+                )
+              )
+              (local.set $1
+                (local.get $3)
+              )
+              (br $while-in)
+            )
+          )
+          (i32.store offset=16
+            (local.get $0)
+            (i32.add
+              (local.tee $1
+                (i32.load
+                  (local.get $14)
+                )
+              )
+              (i32.load offset=48
+                (local.get $0)
+              )
+            )
+          )
+          (i32.store
+            (local.get $6)
+            (local.tee $0
+              (local.get $1)
+            )
+          )
+          (i32.store
+            (local.get $10)
+            (local.get $0)
+          )
+          (br $jumpthreading$outer$1
+            (local.get $2)
+          )
+        )
+        (i32.store offset=16
+          (local.get $0)
+          (i32.const 0)
+        )
+        (i32.store
+          (local.get $6)
+          (i32.const 0)
+        )
+        (i32.store
+          (local.get $10)
+          (i32.const 0)
+        )
+        (i32.store
+          (local.get $0)
+          (i32.or
+            (i32.load
+              (local.get $0)
+            )
+            (i32.const 32)
+          )
+        )
+        (select
+          (i32.const 0)
+          (i32.sub
+            (local.get $2)
+            (i32.load offset=4
+              (local.get $1)
+            )
+          )
+          (i32.eq
+            (local.get $5)
+            (i32.const 2)
+          )
+        )
+      )
+    )
+    (global.set $STACKTOP
+      (local.get $7)
+    )
+    (local.get $0)
+  )
+  (func $___stdio_seek (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+    (local $3 i32)
+    (local $4 i32)
+    (local.set $4
+      (global.get $STACKTOP)
+    )
+    (global.set $STACKTOP
+      (i32.add
+        (global.get $STACKTOP)
+        (i32.const 32)
+      )
+    )
+    (i32.store
+      (local.tee $3
+        (local.get $4)
+      )
+      (i32.load offset=60
+        (local.get $0)
+      )
+    )
+    (i32.store offset=4
+      (local.get $3)
+      (i32.const 0)
+    )
+    (i32.store offset=8
+      (local.get $3)
+      (local.get $1)
+    )
+    (i32.store offset=12
+      (local.get $3)
+      (local.tee $0
+        (i32.add
+          (local.get $4)
+          (i32.const 20)
+        )
+      )
+    )
+    (i32.store offset=16
+      (local.get $3)
+      (local.get $2)
+    )
+    (local.set $0
+      (if (result i32)
+        (i32.lt_s
+          (call $___syscall_ret
+            (call $___syscall140
+              (i32.const 140)
+              (local.get $3)
+            )
+          )
+          (i32.const 0)
+        )
+        (block (result i32)
+          (i32.store
+            (local.get $0)
+            (i32.const -1)
+          )
+          (i32.const -1)
+        )
+        (i32.load
+          (local.get $0)
+        )
+      )
+    )
+    (global.set $STACKTOP
+      (local.get $4)
+    )
+    (local.get $0)
+  )
+  (func $___syscall_ret (param $0 i32) (result i32)
+    (if (result i32)
+      (i32.gt_u
+        (local.get $0)
+        (i32.const -4096)
+      )
+      (block (result i32)
+        (i32.store
+          (call $___errno_location)
+          (i32.sub
+            (i32.const 0)
+            (local.get $0)
+          )
+        )
+        (i32.const -1)
+      )
+      (local.get $0)
+    )
+  )
+  (func $___errno_location (result i32)
+    (if (result i32)
+      (i32.load
+        (i32.const 1140)
+      )
+      (i32.load offset=64
+        (call $_pthread_self)
+      )
+      (i32.const 1184)
+    )
+  )
+  (func $_cleanup_387 (param $0 i32)
+    (if
+      (i32.eqz
+        (i32.load offset=68
+          (local.get $0)
+        )
+      )
+      (call $_free
+        (local.get $0)
+      )
+    )
+  )
+  (func $___stdout_write (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+    (local $3 i32)
+    (local $4 i32)
+    (local $5 i32)
+    (local.set $4
+      (global.get $STACKTOP)
+    )
+    (global.set $STACKTOP
+      (i32.add
+        (global.get $STACKTOP)
+        (i32.const 80)
+      )
+    )
+    (local.set $3
+      (local.get $4)
+    )
+    (local.set $5
+      (i32.add
+        (local.get $4)
+        (i32.const 12)
+      )
+    )
+    (i32.store offset=36
+      (local.get $0)
+      (i32.const 3)
+    )
+    (if
+      (i32.eqz
+        (i32.and
+          (i32.load
+            (local.get $0)
+          )
+          (i32.const 64)
+        )
+      )
+      (block
+        (i32.store
+          (local.get $3)
+          (i32.load offset=60
+            (local.get $0)
+          )
+        )
+        (i32.store offset=4
+          (local.get $3)
+          (i32.const 21505)
+        )
+        (i32.store offset=8
+          (local.get $3)
+          (local.get $5)
+        )
+        (if
+          (call $___syscall54
+            (i32.const 54)
+            (local.get $3)
+          )
+          (i32.store8 offset=75
+            (local.get $0)
+            (i32.const -1)
+          )
+        )
+      )
+    )
+    (local.set $0
+      (call $___stdio_write
+        (local.get $0)
+        (local.get $1)
+        (local.get $2)
+      )
+    )
+    (global.set $STACKTOP
+      (local.get $4)
+    )
+    (local.get $0)
+  )
+  (func $_fflush (param $0 i32) (result i32)
+    (local $1 i32)
+    (local $2 i32)
+    (block $do-once (result i32)
+      (if (result i32)
+        (local.get $0)
+        (block (result i32)
+          (if
+            (i32.le_s
+              (i32.load offset=76
+                (local.get $0)
+              )
+              (i32.const -1)
+            )
+            (br $do-once
+              (call $___fflush_unlocked
+                (local.get $0)
+              )
+            )
+          )
+          (local.set $2
+            (i32.eqz
+              (call $_malloc
+                (local.get $0)
+              )
+            )
+          )
+          (local.set $1
+            (call $___fflush_unlocked
+              (local.get $0)
+            )
+          )
+          (if (result i32)
+            (local.get $2)
+            (local.get $1)
+            (block (result i32)
+              (call $_free
+                (local.get $0)
+              )
+              (local.get $1)
+            )
+          )
+        )
+        (block (result i32)
+          (local.set $0
+            (if (result i32)
+              (i32.load
+                (i32.const 1136)
+              )
+              (call $_fflush
+                (i32.load
+                  (i32.const 1136)
+                )
+              )
+              (i32.const 0)
+            )
+          )
+          (call $___lock
+            (i32.const 1168)
+          )
+          (if
+            (local.tee $1
+              (i32.load
+                (i32.const 1164)
+              )
+            )
+            (loop $while-in
+              (local.set $2
+                (if (result i32)
+                  (i32.gt_s
+                    (i32.load offset=76
+                      (local.get $1)
+                    )
+                    (i32.const -1)
+                  )
+                  (call $_malloc
+                    (local.get $1)
+                  )
+                  (i32.const 0)
+                )
+              )
+              (local.set $0
+                (if (result i32)
+                  (i32.gt_u
+                    (i32.load offset=20
+                      (local.get $1)
+                    )
+                    (i32.load offset=28
+                      (local.get $1)
+                    )
+                  )
+                  (i32.or
+                    (call $___fflush_unlocked
+                      (local.get $1)
+                    )
+                    (local.get $0)
+                  )
+                  (local.get $0)
+                )
+              )
+              (if
+                (local.get $2)
+                (call $_free
+                  (local.get $1)
+                )
+              )
+              (br_if $while-in
+                (local.tee $1
+                  (i32.load offset=56
+                    (local.get $1)
+                  )
+                )
+              )
+            )
+          )
+          (call $___unlock
+            (i32.const 1168)
+          )
+          (local.get $0)
+        )
+      )
+    )
+  )
+  (func $___fflush_unlocked (param $0 i32) (result i32)
+    (local $1 i32)
+    (local $2 i32)
+    (local $3 i32)
+    (local $4 i32)
+    (local $5 i32)
+    (local $6 i32)
+    (block $jumpthreading$outer$0 (result i32)
+      (block $jumpthreading$inner$0
+        (br_if $jumpthreading$inner$0
+          (i32.le_u
+            (i32.load
+              (local.tee $1
+                (i32.add
+                  (local.get $0)
+                  (i32.const 20)
+                )
+              )
+            )
+            (i32.load
+              (local.tee $2
+                (i32.add
+                  (local.get $0)
+                  (i32.const 28)
+                )
+              )
+            )
+          )
+        )
+        (drop
+          (call_indirect (type $FUNCSIG$iiii)
+            (local.get $0)
+            (i32.const 0)
+            (i32.const 0)
+            (i32.add
+              (i32.and
+                (i32.load offset=36
+                  (local.get $0)
+                )
+                (i32.const 3)
+              )
+              (i32.const 2)
+            )
+          )
+        )
+        (br_if $jumpthreading$inner$0
+          (i32.load
+            (local.get $1)
+          )
+        )
+        (br $jumpthreading$outer$0
+          (i32.const -1)
+        )
+      )
+      (if
+        (i32.lt_u
+          (local.tee $4
+            (i32.load
+              (local.tee $3
+                (i32.add
+                  (local.get $0)
+                  (i32.const 4)
+                )
+              )
+            )
+          )
+          (local.tee $6
+            (i32.load
+              (local.tee $5
+                (i32.add
+                  (local.get $0)
+                  (i32.const 8)
+                )
+              )
+            )
+          )
+        )
+        (drop
+          (call_indirect (type $FUNCSIG$iiii)
+            (local.get $0)
+            (i32.sub
+              (local.get $4)
+              (local.get $6)
+            )
+            (i32.const 1)
+            (i32.add
+              (i32.and
+                (i32.load offset=40
+                  (local.get $0)
+                )
+                (i32.const 3)
+              )
+              (i32.const 2)
+            )
+          )
+        )
+      )
+      (i32.store offset=16
+        (local.get $0)
+        (i32.const 0)
+      )
+      (i32.store
+        (local.get $2)
+        (i32.const 0)
+      )
+      (i32.store
+        (local.get $1)
+        (i32.const 0)
+      )
+      (i32.store
+        (local.get $5)
+        (i32.const 0)
+      )
+      (i32.store
+        (local.get $3)
+        (i32.const 0)
+      )
+      (i32.const 0)
+    )
+  )
+  (func $__Znwj (param $0 i32) (result i32)
+    (local $1 i32)
+    (local.set $1
+      (select
+        (local.get $0)
+        (i32.const 1)
+        (local.get $0)
+      )
+    )
+    (loop $while-in
+      (block $while-out
+        (br_if $while-out
+          (local.tee $0
+            (call $_malloc
+              (local.get $1)
+            )
+          )
+        )
+        (if
+          (local.tee $0
+            (call $__ZSt15get_new_handlerv)
+          )
+          (block
+            (call_indirect (type $FUNCSIG$v)
+              (i32.add
+                (i32.and
+                  (local.get $0)
+                  (i32.const 0)
+                )
+                (i32.const 8)
+              )
+            )
+            (br $while-in)
+          )
+          (local.set $0
+            (i32.const 0)
+          )
+        )
+      )
+    )
+    (local.get $0)
+  )
+  (func $__ZSt15get_new_handlerv (result i32)
+    (local $0 i32)
+    (i32.store
+      (i32.const 1188)
+      (i32.add
+        (local.tee $0
+          (i32.load
+            (i32.const 1188)
+          )
+        )
+        (i32.const 0)
+      )
+    )
+    (local.get $0)
+  )
+  (func $runPostSets
+    (nop)
+  )
+  (func $_memset (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+    (local $3 i32)
+    (local $4 i32)
+    (local $5 i32)
+    (local $6 i32)
+    (local.set $4
+      (i32.add
+        (local.get $0)
+        (local.get $2)
+      )
+    )
+    (if
+      (i32.ge_s
+        (local.get $2)
+        (i32.const 20)
+      )
+      (block
+        (local.set $5
+          (i32.or
+            (i32.or
+              (i32.or
+                (local.tee $1
+                  (i32.and
+                    (local.get $1)
+                    (i32.const 255)
+                  )
+                )
+                (i32.shl
+                  (local.get $1)
+                  (i32.const 8)
+                )
+              )
+              (i32.shl
+                (local.get $1)
+                (i32.const 16)
+              )
+            )
+            (i32.shl
+              (local.get $1)
+              (i32.const 24)
+            )
+          )
+        )
+        (local.set $6
+          (i32.and
+            (local.get $4)
+            (i32.const -4)
+          )
+        )
+        (if
+          (local.tee $3
+            (i32.and
+              (local.get $0)
+              (i32.const 3)
+            )
+          )
+          (block
+            (local.set $3
+              (i32.sub
+                (i32.add
+                  (local.get $0)
+                  (i32.const 4)
+                )
+                (local.get $3)
+              )
+            )
+            (loop $while-in
+              (if
+                (i32.lt_s
+                  (local.get $0)
+                  (local.get $3)
+                )
+                (block
+                  (i32.store8
+                    (local.get $0)
+                    (local.get $1)
+                  )
+                  (local.set $0
+                    (i32.add
+                      (local.get $0)
+                      (i32.const 1)
+                    )
+                  )
+                  (br $while-in)
+                )
+              )
+            )
+          )
+        )
+        (loop $while-in1
+          (if
+            (i32.lt_s
+              (local.get $0)
+              (local.get $6)
+            )
+            (block
+              (i32.store
+                (local.get $0)
+                (local.get $5)
+              )
+              (local.set $0
+                (i32.add
+                  (local.get $0)
+                  (i32.const 4)
+                )
+              )
+              (br $while-in1)
+            )
+          )
+        )
+      )
+    )
+    (loop $while-in3
+      (if
+        (i32.lt_s
+          (local.get $0)
+          (local.get $4)
+        )
+        (block
+          (i32.store8
+            (local.get $0)
+            (local.get $1)
+          )
+          (local.set $0
+            (i32.add
+              (local.get $0)
+              (i32.const 1)
+            )
+          )
+          (br $while-in3)
+        )
+      )
+    )
+    (i32.sub
+      (local.get $0)
+      (local.get $2)
+    )
+  )
+  (func $_memcpy (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+    (local $3 i32)
+    (if
+      (i32.ge_s
+        (local.get $2)
+        (i32.const 4096)
+      )
+      (return
+        (call $_emscripten_memcpy_big
+          (local.get $0)
+          (local.get $1)
+          (local.get $2)
+        )
+      )
+    )
+    (local.set $3
+      (local.get $0)
+    )
+    (if
+      (i32.eq
+        (i32.and
+          (local.get $0)
+          (i32.const 3)
+        )
+        (i32.and
+          (local.get $1)
+          (i32.const 3)
+        )
+      )
+      (block
+        (loop $while-in
+          (block $while-out
+            (br_if $while-out
+              (i32.eqz
+                (i32.and
+                  (local.get $0)
+                  (i32.const 3)
+                )
+              )
+            )
+            (if
+              (i32.eqz
+                (local.get $2)
+              )
+              (return
+                (local.get $3)
+              )
+            )
+            (i32.store8
+              (local.get $0)
+              (i32.load8_s
+                (local.get $1)
+              )
+            )
+            (local.set $0
+              (i32.add
+                (local.get $0)
+                (i32.const 1)
+              )
+            )
+            (local.set $1
+              (i32.add
+                (local.get $1)
+                (i32.const 1)
+              )
+            )
+            (local.set $2
+              (i32.sub
+                (local.get $2)
+                (i32.const 1)
+              )
+            )
+            (br $while-in)
+          )
+        )
+        (loop $while-in1
+          (if
+            (i32.ge_s
+              (local.get $2)
+              (i32.const 4)
+            )
+            (block
+              (i32.store
+                (local.get $0)
+                (i32.load
+                  (local.get $1)
+                )
+              )
+              (local.set $0
+                (i32.add
+                  (local.get $0)
+                  (i32.const 4)
+                )
+              )
+              (local.set $1
+                (i32.add
+                  (local.get $1)
+                  (i32.const 4)
+                )
+              )
+              (local.set $2
+                (i32.sub
+                  (local.get $2)
+                  (i32.const 4)
+                )
+              )
+              (br $while-in1)
+            )
+          )
+        )
+      )
+    )
+    (loop $while-in3
+      (if
+        (i32.gt_s
+          (local.get $2)
+          (i32.const 0)
+        )
+        (block
+          (i32.store8
+            (local.get $0)
+            (i32.load8_s
+              (local.get $1)
+            )
+          )
+          (local.set $0
+            (i32.add
+              (local.get $0)
+              (i32.const 1)
+            )
+          )
+          (local.set $1
+            (i32.add
+              (local.get $1)
+              (i32.const 1)
+            )
+          )
+          (local.set $2
+            (i32.sub
+              (local.get $2)
+              (i32.const 1)
+            )
+          )
+          (br $while-in3)
+        )
+      )
+    )
+    (local.get $3)
+  )
+  (func $_pthread_self (result i32)
+    (i32.const 0)
+  )
+  (func $dynCall_ii (param $0 i32) (param $1 i32) (result i32)
+    (call_indirect (type $FUNCSIG$ii)
+      (local.get $1)
+      (i32.add
+        (i32.and
+          (local.get $0)
+          (i32.const 1)
+        )
+        (i32.const 0)
+      )
+    )
+  )
+  (func $dynCall_iiii (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
+    (call_indirect (type $FUNCSIG$iiii)
+      (local.get $1)
+      (local.get $2)
+      (local.get $3)
+      (i32.add
+        (i32.and
+          (local.get $0)
+          (i32.const 3)
+        )
+        (i32.const 2)
+      )
+    )
+  )
+  (func $dynCall_vi (param $0 i32) (param $1 i32)
+    (call_indirect (type $FUNCSIG$vi)
+      (local.get $1)
+      (i32.add
+        (i32.and
+          (local.get $0)
+          (i32.const 1)
+        )
+        (i32.const 6)
+      )
+    )
+  )
+  (func $dynCall_v (param $0 i32)
+    (call_indirect (type $FUNCSIG$v)
+      (i32.add
+        (i32.and
+          (local.get $0)
+          (i32.const 0)
+        )
+        (i32.const 8)
+      )
+    )
+  )
+  (func $b0 (param $0 i32) (result i32)
+    (call $abort
+      (i32.const 0)
+    )
+    (i32.const 0)
+  )
+  (func $b1 (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+    (call $abort
+      (i32.const 1)
+    )
+    (i32.const 0)
+  )
+  (func $b2 (param $0 i32)
+    (call $abort
+      (i32.const 2)
+    )
+  )
+  (func $b3
+    (call $abort
+      (i32.const 3)
+    )
+  )
+)
diff --git a/binaryen/test/passes/print-function-map.txt b/binaryen/test/passes/print-function-map.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/print-function-map.txt
@@ -0,0 +1,13 @@
+0:Foo
+1:bar
+2:baz
+(module
+ (type $none_=>_none (func))
+ (import "env" "foo" (func $Foo))
+ (func $bar
+  (nop)
+ )
+ (func $baz
+  (nop)
+ )
+)
diff --git a/binaryen/test/passes/print-function-map.wast b/binaryen/test/passes/print-function-map.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/print-function-map.wast
@@ -0,0 +1,6 @@
+(module
+  (import "env" "foo" (func $Foo))
+  (func $bar)
+  (func $baz)
+)
+
diff --git a/binaryen/test/passes/print.bin.txt b/binaryen/test/passes/print.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/print.bin.txt
@@ -0,0 +1,182 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (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)))
+ (import "env" "memory" (memory $mimport$0 256 256))
+ (global $global$0 (mut i32) (i32.const 5243904))
+ (global $global$1 i32 (i32.const 1024))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__data_end" (global $global$1))
+ (export "stackSave" (func $stackSave))
+ (export "stackAlloc" (func $stackAlloc))
+ (export "stackRestore" (func $stackRestore))
+ (export "__growWasmMemory" (func $__growWasmMemory))
+ (func $__wasm_call_ctors
+  (nop)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (if
+   (i32.ne
+    (i32.rem_s
+     (local.get $0)
+     (i32.const 120)
+    )
+    (i32.const 55)
+   )
+   (loop $label$2
+    (br_if $label$2
+     (i32.ne
+      (i32.rem_s
+       (local.tee $0
+        (i32.add
+         (i32.add
+          (i32.mul
+           (i32.mul
+            (local.get $0)
+            (local.get $0)
+           )
+           (local.get $0)
+          )
+          (i32.div_s
+           (local.get $0)
+           (i32.const -2)
+          )
+         )
+         (i32.const 13)
+        )
+       )
+       (i32.const 120)
+      )
+      (i32.const 55)
+     )
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $stackSave (result i32)
+  (global.get $global$0)
+ )
+ (func $stackAlloc (param $0 i32) (result i32)
+  (global.set $global$0
+   (local.tee $0
+    (i32.and
+     (i32.sub
+      (global.get $global$0)
+      (local.get $0)
+     )
+     (i32.const -16)
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $stackRestore (param $0 i32)
+  (global.set $global$0
+   (local.get $0)
+  )
+ )
+ (func $__growWasmMemory (param $0 i32) (result i32)
+  (memory.grow
+   (local.get $0)
+  )
+ )
+ ;; custom section ".debug_info", size 105
+ ;; custom section ".debug_abbrev", size 73
+ ;; custom section ".debug_line", size 92
+ ;; custom section ".debug_str", size 205
+)
+(module
+ (type $i32_=>_i32 (func (param i32) (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)))
+ (import "env" "memory" (memory $mimport$0 256 256))
+ (global $global$0 (mut i32) (i32.const 5243904))
+ (global $global$1 i32 (i32.const 1024))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__data_end" (global $global$1))
+ (export "stackSave" (func $stackSave))
+ (export "stackAlloc" (func $stackAlloc))
+ (export "stackRestore" (func $stackRestore))
+ (export "__growWasmMemory" (func $__growWasmMemory))
+ (func $__wasm_call_ctors
+  (nop)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (if
+   (i32.ne
+    (i32.rem_s
+     (local.get $0)
+     (i32.const 120)
+    )
+    (i32.const 55)
+   )
+   (loop $label$2
+    (br_if $label$2
+     (i32.ne
+      (i32.rem_s
+       (local.tee $0
+        (i32.add
+         (i32.add
+          (i32.mul
+           (i32.mul
+            (local.get $0)
+            (local.get $0)
+           )
+           (local.get $0)
+          )
+          (i32.div_s
+           (local.get $0)
+           (i32.const -2)
+          )
+         )
+         (i32.const 13)
+        )
+       )
+       (i32.const 120)
+      )
+      (i32.const 55)
+     )
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $stackSave (result i32)
+  (global.get $global$0)
+ )
+ (func $stackAlloc (param $0 i32) (result i32)
+  (global.set $global$0
+   (local.tee $0
+    (i32.and
+     (i32.sub
+      (global.get $global$0)
+      (local.get $0)
+     )
+     (i32.const -16)
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $stackRestore (param $0 i32)
+  (global.set $global$0
+   (local.get $0)
+  )
+ )
+ (func $__growWasmMemory (param $0 i32) (result i32)
+  (memory.grow
+   (local.get $0)
+  )
+ )
+ ;; custom section ".debug_info", size 105
+ ;; custom section ".debug_abbrev", size 73
+ ;; custom section ".debug_line", size 92
+ ;; custom section ".debug_str", size 205
+)
diff --git a/binaryen/test/passes/print.wasm b/binaryen/test/passes/print.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/print.wasm differ
diff --git a/binaryen/test/passes/print_g.bin.txt b/binaryen/test/passes/print_g.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/print_g.bin.txt
@@ -0,0 +1,260 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (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)))
+ (import "env" "memory" (memory $mimport$0 256 256))
+ (global $global$0 (mut i32) (i32.const 5243904))
+ (global $global$1 i32 (i32.const 1024))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__data_end" (global $global$1))
+ (export "stackSave" (func $stackSave))
+ (export "stackAlloc" (func $stackAlloc))
+ (export "stackRestore" (func $stackRestore))
+ (export "__growWasmMemory" (func $__growWasmMemory))
+ (func $__wasm_call_ctors
+  ;; code offset: 0x3
+  (nop)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  ;; code offset: 0x10
+  (if
+   ;; code offset: 0xf
+   (i32.ne
+    ;; code offset: 0xc
+    (i32.rem_s
+     ;; code offset: 0x7
+     (local.get $0)
+     ;; code offset: 0x9
+     (i32.const 120)
+    )
+    ;; code offset: 0xd
+    (i32.const 55)
+   )
+   ;; code offset: 0x12
+   (loop $label$2
+    ;; code offset: 0x2e
+    (br_if $label$2
+     ;; code offset: 0x2d
+     (i32.ne
+      ;; code offset: 0x2a
+      (i32.rem_s
+       ;; code offset: 0x25
+       (local.tee $0
+        ;; code offset: 0x24
+        (i32.add
+         ;; code offset: 0x21
+         (i32.add
+          ;; code offset: 0x1b
+          (i32.mul
+           ;; code offset: 0x18
+           (i32.mul
+            ;; code offset: 0x14
+            (local.get $0)
+            ;; code offset: 0x16
+            (local.get $0)
+           )
+           ;; code offset: 0x19
+           (local.get $0)
+          )
+          ;; code offset: 0x20
+          (i32.div_s
+           ;; code offset: 0x1c
+           (local.get $0)
+           ;; code offset: 0x1e
+           (i32.const -2)
+          )
+         )
+         ;; code offset: 0x22
+         (i32.const 13)
+        )
+       )
+       ;; code offset: 0x27
+       (i32.const 120)
+      )
+      ;; code offset: 0x2b
+      (i32.const 55)
+     )
+    )
+   )
+  )
+  ;; code offset: 0x32
+  (local.get $0)
+ )
+ (func $stackSave (result i32)
+  ;; code offset: 0x37
+  (global.get $global$0)
+ )
+ (func $stackAlloc (param $0 i32) (result i32)
+  ;; code offset: 0x46
+  (global.set $global$0
+   ;; code offset: 0x44
+   (local.tee $0
+    ;; code offset: 0x43
+    (i32.and
+     ;; code offset: 0x40
+     (i32.sub
+      ;; code offset: 0x3c
+      (global.get $global$0)
+      ;; code offset: 0x3e
+      (local.get $0)
+     )
+     ;; code offset: 0x41
+     (i32.const -16)
+    )
+   )
+  )
+  ;; code offset: 0x48
+  (local.get $0)
+ )
+ (func $stackRestore (param $0 i32)
+  ;; code offset: 0x4f
+  (global.set $global$0
+   ;; code offset: 0x4d
+   (local.get $0)
+  )
+ )
+ (func $__growWasmMemory (param $0 i32) (result i32)
+  ;; code offset: 0x56
+  (memory.grow
+   ;; code offset: 0x54
+   (local.get $0)
+  )
+ )
+ ;; custom section ".debug_info", size 105
+ ;; custom section ".debug_abbrev", size 73
+ ;; custom section ".debug_line", size 92
+ ;; custom section ".debug_str", size 205
+)
+(module
+ (type $i32_=>_i32 (func (param i32) (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)))
+ (import "env" "memory" (memory $mimport$0 256 256))
+ (global $global$0 (mut i32) (i32.const 5243904))
+ (global $global$1 i32 (i32.const 1024))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__data_end" (global $global$1))
+ (export "stackSave" (func $stackSave))
+ (export "stackAlloc" (func $stackAlloc))
+ (export "stackRestore" (func $stackRestore))
+ (export "__growWasmMemory" (func $__growWasmMemory))
+ (func $__wasm_call_ctors
+  ;; code offset: 0x3
+  (nop)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  ;; code offset: 0x10
+  (if
+   ;; code offset: 0xf
+   (i32.ne
+    ;; code offset: 0xc
+    (i32.rem_s
+     ;; code offset: 0x7
+     (local.get $0)
+     ;; code offset: 0x9
+     (i32.const 120)
+    )
+    ;; code offset: 0xd
+    (i32.const 55)
+   )
+   ;; code offset: 0x12
+   (loop $label$2
+    ;; code offset: 0x2e
+    (br_if $label$2
+     ;; code offset: 0x2d
+     (i32.ne
+      ;; code offset: 0x2a
+      (i32.rem_s
+       ;; code offset: 0x25
+       (local.tee $0
+        ;; code offset: 0x24
+        (i32.add
+         ;; code offset: 0x21
+         (i32.add
+          ;; code offset: 0x1b
+          (i32.mul
+           ;; code offset: 0x18
+           (i32.mul
+            ;; code offset: 0x14
+            (local.get $0)
+            ;; code offset: 0x16
+            (local.get $0)
+           )
+           ;; code offset: 0x19
+           (local.get $0)
+          )
+          ;; code offset: 0x20
+          (i32.div_s
+           ;; code offset: 0x1c
+           (local.get $0)
+           ;; code offset: 0x1e
+           (i32.const -2)
+          )
+         )
+         ;; code offset: 0x22
+         (i32.const 13)
+        )
+       )
+       ;; code offset: 0x27
+       (i32.const 120)
+      )
+      ;; code offset: 0x2b
+      (i32.const 55)
+     )
+    )
+   )
+  )
+  ;; code offset: 0x32
+  (local.get $0)
+ )
+ (func $stackSave (result i32)
+  ;; code offset: 0x37
+  (global.get $global$0)
+ )
+ (func $stackAlloc (param $0 i32) (result i32)
+  ;; code offset: 0x46
+  (global.set $global$0
+   ;; code offset: 0x44
+   (local.tee $0
+    ;; code offset: 0x43
+    (i32.and
+     ;; code offset: 0x40
+     (i32.sub
+      ;; code offset: 0x3c
+      (global.get $global$0)
+      ;; code offset: 0x3e
+      (local.get $0)
+     )
+     ;; code offset: 0x41
+     (i32.const -16)
+    )
+   )
+  )
+  ;; code offset: 0x48
+  (local.get $0)
+ )
+ (func $stackRestore (param $0 i32)
+  ;; code offset: 0x4f
+  (global.set $global$0
+   ;; code offset: 0x4d
+   (local.get $0)
+  )
+ )
+ (func $__growWasmMemory (param $0 i32) (result i32)
+  ;; code offset: 0x56
+  (memory.grow
+   ;; code offset: 0x54
+   (local.get $0)
+  )
+ )
+ ;; custom section ".debug_info", size 105
+ ;; custom section ".debug_abbrev", size 73
+ ;; custom section ".debug_line", size 92
+ ;; custom section ".debug_str", size 205
+)
diff --git a/binaryen/test/passes/print_g.wasm b/binaryen/test/passes/print_g.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/print_g.wasm differ
diff --git a/binaryen/test/passes/print_g_metrics.bin.txt b/binaryen/test/passes/print_g_metrics.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/print_g_metrics.bin.txt
@@ -0,0 +1,151 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (global $global$0 (mut i32) (i32.const 5243904))
+ (export "a" (func $__wasm_call_ctors))
+ (export "b" (func $main))
+ (export "c" (func $stackAlloc))
+ (func $stackAlloc (param $0 i32) (result i32)
+  (global.set $global$0
+   (local.tee $0
+    (i32.and
+     (i32.sub
+      (global.get $global$0)
+      (local.get $0)
+     )
+     (i32.const -16)
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (if
+   (i32.ne
+    (i32.rem_s
+     (local.get $0)
+     (i32.const 120)
+    )
+    (i32.const 55)
+   )
+   (loop $label$2
+    (br_if $label$2
+     (i32.ne
+      (i32.rem_s
+       (local.tee $0
+        (i32.add
+         (i32.add
+          (i32.mul
+           (i32.mul
+            (local.get $0)
+            (local.get $0)
+           )
+           (local.get $0)
+          )
+          (i32.div_s
+           (local.get $0)
+           (i32.const -2)
+          )
+         )
+         (i32.const 13)
+        )
+       )
+       (i32.const 120)
+      )
+      (i32.const 55)
+     )
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $__wasm_call_ctors
+  (nop)
+ )
+)
+total
+ [events]       : 0       
+ [exports]      : 3       
+ [funcs]        : 3       
+ [globals]      : 1       
+ [imports]      : 0       
+ [total]        : 37      
+ [vars]         : 0       
+ binary         : 11      
+ block          : 2       
+ break          : 1       
+ const          : 8       
+ global.get     : 1       
+ global.set     : 1       
+ if             : 1       
+ local.get      : 8       
+ local.set      : 2       
+ loop           : 1       
+ nop            : 1       
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (global $global$0 (mut i32) (i32.const 5243904))
+ (export "a" (func $__wasm_call_ctors))
+ (export "b" (func $main))
+ (export "c" (func $stackAlloc))
+ (func $stackAlloc (param $0 i32) (result i32)
+  (global.set $global$0
+   (local.tee $0
+    (i32.and
+     (i32.sub
+      (global.get $global$0)
+      (local.get $0)
+     )
+     (i32.const -16)
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (if
+   (i32.ne
+    (i32.rem_s
+     (local.get $0)
+     (i32.const 120)
+    )
+    (i32.const 55)
+   )
+   (loop $label$2
+    (br_if $label$2
+     (i32.ne
+      (i32.rem_s
+       (local.tee $0
+        (i32.add
+         (i32.add
+          (i32.mul
+           (i32.mul
+            (local.get $0)
+            (local.get $0)
+           )
+           (local.get $0)
+          )
+          (i32.div_s
+           (local.get $0)
+           (i32.const -2)
+          )
+         )
+         (i32.const 13)
+        )
+       )
+       (i32.const 120)
+      )
+      (i32.const 55)
+     )
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $__wasm_call_ctors
+  (nop)
+ )
+)
diff --git a/binaryen/test/passes/print_g_metrics.wasm b/binaryen/test/passes/print_g_metrics.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/print_g_metrics.wasm differ
diff --git a/binaryen/test/passes/print_g_strip-dwarf.bin.txt b/binaryen/test/passes/print_g_strip-dwarf.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/print_g_strip-dwarf.bin.txt
@@ -0,0 +1,178 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (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)))
+ (import "env" "memory" (memory $mimport$0 256 256))
+ (global $global$0 (mut i32) (i32.const 5243904))
+ (global $global$1 i32 (i32.const 1024))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__data_end" (global $global$1))
+ (export "stackSave" (func $stackSave))
+ (export "stackAlloc" (func $stackAlloc))
+ (export "stackRestore" (func $stackRestore))
+ (export "__growWasmMemory" (func $__growWasmMemory))
+ (func $__wasm_call_ctors
+  (nop)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (if
+   (i32.ne
+    (i32.rem_s
+     (local.get $0)
+     (i32.const 120)
+    )
+    (i32.const 55)
+   )
+   (loop $label$2
+    (br_if $label$2
+     (i32.ne
+      (i32.rem_s
+       (local.tee $0
+        (i32.add
+         (i32.add
+          (i32.mul
+           (i32.mul
+            (local.get $0)
+            (local.get $0)
+           )
+           (local.get $0)
+          )
+          (i32.div_s
+           (local.get $0)
+           (i32.const -2)
+          )
+         )
+         (i32.const 13)
+        )
+       )
+       (i32.const 120)
+      )
+      (i32.const 55)
+     )
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $stackSave (result i32)
+  (global.get $global$0)
+ )
+ (func $stackAlloc (param $0 i32) (result i32)
+  (global.set $global$0
+   (local.tee $0
+    (i32.and
+     (i32.sub
+      (global.get $global$0)
+      (local.get $0)
+     )
+     (i32.const -16)
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $stackRestore (param $0 i32)
+  (global.set $global$0
+   (local.get $0)
+  )
+ )
+ (func $__growWasmMemory (param $0 i32) (result i32)
+  (memory.grow
+   (local.get $0)
+  )
+ )
+ ;; custom section ".debug_info", size 105
+ ;; custom section ".debug_abbrev", size 73
+ ;; custom section ".debug_line", size 92
+ ;; custom section ".debug_str", size 205
+)
+(module
+ (type $i32_=>_i32 (func (param i32) (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)))
+ (import "env" "memory" (memory $mimport$0 256 256))
+ (global $global$0 (mut i32) (i32.const 5243904))
+ (global $global$1 i32 (i32.const 1024))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (export "__data_end" (global $global$1))
+ (export "stackSave" (func $stackSave))
+ (export "stackAlloc" (func $stackAlloc))
+ (export "stackRestore" (func $stackRestore))
+ (export "__growWasmMemory" (func $__growWasmMemory))
+ (func $__wasm_call_ctors
+  (nop)
+ )
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (if
+   (i32.ne
+    (i32.rem_s
+     (local.get $0)
+     (i32.const 120)
+    )
+    (i32.const 55)
+   )
+   (loop $label$2
+    (br_if $label$2
+     (i32.ne
+      (i32.rem_s
+       (local.tee $0
+        (i32.add
+         (i32.add
+          (i32.mul
+           (i32.mul
+            (local.get $0)
+            (local.get $0)
+           )
+           (local.get $0)
+          )
+          (i32.div_s
+           (local.get $0)
+           (i32.const -2)
+          )
+         )
+         (i32.const 13)
+        )
+       )
+       (i32.const 120)
+      )
+      (i32.const 55)
+     )
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $stackSave (result i32)
+  (global.get $global$0)
+ )
+ (func $stackAlloc (param $0 i32) (result i32)
+  (global.set $global$0
+   (local.tee $0
+    (i32.and
+     (i32.sub
+      (global.get $global$0)
+      (local.get $0)
+     )
+     (i32.const -16)
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $stackRestore (param $0 i32)
+  (global.set $global$0
+   (local.get $0)
+  )
+ )
+ (func $__growWasmMemory (param $0 i32) (result i32)
+  (memory.grow
+   (local.get $0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/print_g_strip-dwarf.wasm b/binaryen/test/passes/print_g_strip-dwarf.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/print_g_strip-dwarf.wasm differ
diff --git a/binaryen/test/passes/remove-imports.txt b/binaryen/test/passes/remove-imports.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-imports.txt
@@ -0,0 +1,20 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "table" (table $table 1 1 funcref))
+ (elem (i32.const 0) $waka-sneaky)
+ (import "env" "memBase" (global $gimport$0 i32))
+ (import "somewhere" "waka-sneaky" (func $waka-sneaky))
+ (memory $0 1024 1024)
+ (func $nada
+  (nop)
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (f64.const 0)
+  )
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/remove-imports.wast b/binaryen/test/passes/remove-imports.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-imports.wast
@@ -0,0 +1,23 @@
+(module
+  (memory 1024 1024)
+  (type $FUNCSIG$v (func))
+  (type $FUNCSIG$i (func (result i32)))
+  (type $FUNCSIG$d (func (result f64)))
+  (import $waka "somewhere" "waka")
+  (import $waka-ret "somewhere" "waka-ret" (result i32))
+  (import $waka-ret-d "somewhere" "waka-ret-d" (result f64))
+  (import $waka-sneaky "somewhere" "waka-sneaky")
+  (import "env" "memBase" (global i32))
+  (import "env" "table" (table $table 1 1 funcref))
+  (elem (i32.const 0) $waka-sneaky)
+  (func $nada (type $FUNCSIG$v)
+    (call $waka)
+    (drop
+      (call $waka-ret)
+    )
+    (drop
+      (call $waka-ret-d)
+    )
+    (call_indirect (i32.const 0))
+  )
+)
diff --git a/binaryen/test/passes/remove-memory.txt b/binaryen/test/passes/remove-memory.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-memory.txt
@@ -0,0 +1,3 @@
+(module
+ (memory $0 1024 1024)
+)
diff --git a/binaryen/test/passes/remove-memory.wast b/binaryen/test/passes/remove-memory.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-memory.wast
@@ -0,0 +1,6 @@
+(module
+  (memory 1024 1024
+    (segment 10 "123")
+    (segment 20 "149")
+  )
+)
diff --git a/binaryen/test/passes/remove-non-js-ops.txt b/binaryen/test/passes/remove-non-js-ops.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-non-js-ops.txt
@@ -0,0 +1,1142 @@
+(module
+ (type $i64_i64_=>_i64 (func (param i64 i64) (result i64)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $f32_=>_f32 (func (param f32) (result f32)))
+ (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 $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)))
+ (type $none_=>_f32 (func (result f32)))
+ (type $f32_f32_=>_f32 (func (param f32 f32) (result f32)))
+ (type $none_=>_f64 (func (result f64)))
+ (type $f64_f64_=>_f64 (func (param f64 f64) (result f64)))
+ (import "env" "wasm2js_scratch_load_i32" (func $wasm2js_scratch_load_i32 (param i32) (result i32)))
+ (import "env" "wasm2js_scratch_store_i32" (func $wasm2js_scratch_store_i32 (param i32 i32)))
+ (import "env" "wasm2js_scratch_load_f32" (func $wasm2js_scratch_load_f32 (result f32)))
+ (import "env" "wasm2js_scratch_store_f32" (func $wasm2js_scratch_store_f32 (param f32)))
+ (import "env" "wasm2js_scratch_load_f64" (func $wasm2js_scratch_load_f64 (result f64)))
+ (import "env" "wasm2js_scratch_store_f64" (func $wasm2js_scratch_store_f64 (param f64)))
+ (import "env" "wasm2js_memory_init" (func $wasm2js_memory_init (param i32 i32 i32 i32)))
+ (import "env" "wasm2js_memory_fill" (func $wasm2js_memory_fill (param i32 i32 i32)))
+ (import "env" "wasm2js_memory_copy" (func $wasm2js_memory_copy (param i32 i32 i32)))
+ (import "env" "wasm2js_data_drop" (func $wasm2js_data_drop (param i32)))
+ (import "env" "wasm2js_atomic_wait_i32" (func $wasm2js_atomic_wait_i32 (param i32 i32 i32 i32) (result i32)))
+ (import "env" "wasm2js_atomic_rmw_i64" (func $wasm2js_atomic_rmw_i64 (param i32 i32 i32 i32 i32 i32) (result i32)))
+ (import "env" "wasm2js_get_stashed_bits" (func $wasm2js_get_stashed_bits (result i32)))
+ (memory $0 1)
+ (global $__wasm-intrinsics-temp-i64 (mut i64) (i64.const 0))
+ (func $copysign64 (param $0 f64) (param $1 f64) (result f64)
+  (f64.reinterpret_i64
+   (i64.or
+    (i64.and
+     (i64.reinterpret_f64
+      (local.get $0)
+     )
+     (i64.const 9223372036854775807)
+    )
+    (i64.and
+     (i64.reinterpret_f64
+      (local.get $1)
+     )
+     (i64.const -9223372036854775808)
+    )
+   )
+  )
+ )
+ (func $copysign32 (param $0 f32) (param $1 f32) (result f32)
+  (f32.reinterpret_i32
+   (i32.or
+    (i32.and
+     (i32.reinterpret_f32
+      (local.get $0)
+     )
+     (i32.const 2147483647)
+    )
+    (i32.and
+     (i32.reinterpret_f32
+      (local.get $1)
+     )
+     (i32.const -2147483648)
+    )
+   )
+  )
+ )
+ (func $rotl32 (param $0 i32) (param $1 i32) (result i32)
+  (call $__wasm_rotl_i32
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $rotr32 (param $0 i32) (param $1 i32) (result i32)
+  (call $__wasm_rotr_i32
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $rotl64 (param $0 i64) (param $1 i64) (result i64)
+  (call $__wasm_rotl_i64
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $rotr64 (param $0 i64) (param $1 i64) (result i64)
+  (call $__wasm_rotr_i64
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $nearest64 (param $0 f64) (result f64)
+  (call $__wasm_nearest_f64
+   (local.get $0)
+  )
+ )
+ (func $nearest32 (param $0 f32) (result f32)
+  (call $__wasm_nearest_f32
+   (local.get $0)
+  )
+ )
+ (func $trunc64 (param $0 f64) (result f64)
+  (call $__wasm_trunc_f64
+   (local.get $0)
+  )
+ )
+ (func $trunc32 (param $0 f32) (result f32)
+  (call $__wasm_trunc_f32
+   (local.get $0)
+  )
+ )
+ (func $popcnt32 (param $0 i32) (result i32)
+  (call $__wasm_popcnt_i32
+   (local.get $0)
+  )
+ )
+ (func $ctz32 (param $0 i32) (result i32)
+  (call $__wasm_ctz_i32
+   (local.get $0)
+  )
+ )
+ (func $i64_sdiv (param $0 i64) (param $1 i64) (result i64)
+  (call $__wasm_i64_sdiv
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64_udiv (param $0 i64) (param $1 i64) (result i64)
+  (call $__wasm_i64_udiv
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64_srem (param $0 i64) (param $1 i64) (result i64)
+  (call $__wasm_i64_srem
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64_urem (param $0 i64) (param $1 i64) (result i64)
+  (call $__wasm_i64_urem
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64_mul (param $0 i64) (param $1 i64) (result i64)
+  (call $__wasm_i64_mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $_ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $var$2 i32)
+  (local $var$3 i32)
+  (local $var$4 i32)
+  (local $var$5 i32)
+  (local $var$6 i32)
+  (i64.or
+   (i64.shl
+    (i64.extend_i32_u
+     (i32.add
+      (i32.add
+       (i32.add
+        (i32.add
+         (i32.mul
+          (local.tee $var$4
+           (i32.shr_u
+            (local.tee $var$2
+             (i32.wrap_i64
+              (local.get $var$1)
+             )
+            )
+            (i32.const 16)
+           )
+          )
+          (local.tee $var$5
+           (i32.shr_u
+            (local.tee $var$3
+             (i32.wrap_i64
+              (local.get $var$0)
+             )
+            )
+            (i32.const 16)
+           )
+          )
+         )
+         (i32.mul
+          (local.get $var$2)
+          (i32.wrap_i64
+           (i64.shr_u
+            (local.get $var$0)
+            (i64.const 32)
+           )
+          )
+         )
+        )
+        (i32.mul
+         (i32.wrap_i64
+          (i64.shr_u
+           (local.get $var$1)
+           (i64.const 32)
+          )
+         )
+         (local.get $var$3)
+        )
+       )
+       (i32.shr_u
+        (local.tee $var$2
+         (i32.add
+          (i32.shr_u
+           (local.tee $var$6
+            (i32.mul
+             (local.tee $var$2
+              (i32.and
+               (local.get $var$2)
+               (i32.const 65535)
+              )
+             )
+             (local.tee $var$3
+              (i32.and
+               (local.get $var$3)
+               (i32.const 65535)
+              )
+             )
+            )
+           )
+           (i32.const 16)
+          )
+          (i32.mul
+           (local.get $var$2)
+           (local.get $var$5)
+          )
+         )
+        )
+        (i32.const 16)
+       )
+      )
+      (i32.shr_u
+       (local.tee $var$2
+        (i32.add
+         (i32.and
+          (local.get $var$2)
+          (i32.const 65535)
+         )
+         (i32.mul
+          (local.get $var$4)
+          (local.get $var$3)
+         )
+        )
+       )
+       (i32.const 16)
+      )
+     )
+    )
+    (i64.const 32)
+   )
+   (i64.extend_i32_u
+    (i32.or
+     (i32.shl
+      (local.get $var$2)
+      (i32.const 16)
+     )
+     (i32.and
+      (local.get $var$6)
+      (i32.const 65535)
+     )
+    )
+   )
+  )
+ )
+ (func $_ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $var$2 i64)
+  (i64.sub
+   (i64.xor
+    (call $__wasm_i64_udiv
+     (i64.sub
+      (i64.xor
+       (local.tee $var$2
+        (i64.shr_s
+         (local.get $var$0)
+         (i64.const 63)
+        )
+       )
+       (local.get $var$0)
+      )
+      (local.get $var$2)
+     )
+     (i64.sub
+      (i64.xor
+       (local.tee $var$2
+        (i64.shr_s
+         (local.get $var$1)
+         (i64.const 63)
+        )
+       )
+       (local.get $var$1)
+      )
+      (local.get $var$2)
+     )
+    )
+    (local.tee $var$0
+     (i64.shr_s
+      (i64.xor
+       (local.get $var$1)
+       (local.get $var$0)
+      )
+      (i64.const 63)
+     )
+    )
+   )
+   (local.get $var$0)
+  )
+ )
+ (func $_ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $var$2 i64)
+  (i64.sub
+   (i64.xor
+    (call $__wasm_i64_urem
+     (i64.sub
+      (i64.xor
+       (local.tee $var$2
+        (i64.shr_s
+         (local.get $var$0)
+         (i64.const 63)
+        )
+       )
+       (local.get $var$0)
+      )
+      (local.get $var$2)
+     )
+     (i64.sub
+      (i64.xor
+       (local.tee $var$0
+        (i64.shr_s
+         (local.get $var$1)
+         (i64.const 63)
+        )
+       )
+       (local.get $var$1)
+      )
+      (local.get $var$0)
+     )
+    )
+    (local.get $var$2)
+   )
+   (local.get $var$2)
+  )
+ )
+ (func $_ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $var$2 i32)
+  (local $var$3 i32)
+  (local $var$4 i32)
+  (local $var$5 i64)
+  (local $var$6 i64)
+  (local $var$7 i64)
+  (local $var$8 i64)
+  (block $label$1
+   (block $label$2
+    (block $label$3
+     (block $label$4
+      (block $label$5
+       (block $label$6
+        (block $label$7
+         (block $label$8
+          (block $label$9
+           (block $label$10
+            (block $label$11
+             (if
+              (local.tee $var$2
+               (i32.wrap_i64
+                (i64.shr_u
+                 (local.get $var$0)
+                 (i64.const 32)
+                )
+               )
+              )
+              (block $block
+               (br_if $label$11
+                (i32.eqz
+                 (local.tee $var$3
+                  (i32.wrap_i64
+                   (local.get $var$1)
+                  )
+                 )
+                )
+               )
+               (br_if $label$9
+                (i32.eqz
+                 (local.tee $var$4
+                  (i32.wrap_i64
+                   (i64.shr_u
+                    (local.get $var$1)
+                    (i64.const 32)
+                   )
+                  )
+                 )
+                )
+               )
+               (br_if $label$8
+                (i32.le_u
+                 (local.tee $var$2
+                  (i32.sub
+                   (i32.clz
+                    (local.get $var$4)
+                   )
+                   (i32.clz
+                    (local.get $var$2)
+                   )
+                  )
+                 )
+                 (i32.const 31)
+                )
+               )
+               (br $label$2)
+              )
+             )
+             (br_if $label$2
+              (i64.ge_u
+               (local.get $var$1)
+               (i64.const 4294967296)
+              )
+             )
+             (global.set $__wasm-intrinsics-temp-i64
+              (i64.extend_i32_u
+               (i32.sub
+                (local.tee $var$2
+                 (i32.wrap_i64
+                  (local.get $var$0)
+                 )
+                )
+                (i32.mul
+                 (local.tee $var$2
+                  (i32.div_u
+                   (local.get $var$2)
+                   (local.tee $var$3
+                    (i32.wrap_i64
+                     (local.get $var$1)
+                    )
+                   )
+                  )
+                 )
+                 (local.get $var$3)
+                )
+               )
+              )
+             )
+             (return
+              (i64.extend_i32_u
+               (local.get $var$2)
+              )
+             )
+            )
+            (local.set $var$3
+             (i32.wrap_i64
+              (i64.shr_u
+               (local.get $var$1)
+               (i64.const 32)
+              )
+             )
+            )
+            (br_if $label$7
+             (i32.eqz
+              (i32.wrap_i64
+               (local.get $var$0)
+              )
+             )
+            )
+            (br_if $label$6
+             (i32.eqz
+              (local.get $var$3)
+             )
+            )
+            (br_if $label$6
+             (i32.and
+              (local.tee $var$4
+               (i32.add
+                (local.get $var$3)
+                (i32.const -1)
+               )
+              )
+              (local.get $var$3)
+             )
+            )
+            (global.set $__wasm-intrinsics-temp-i64
+             (i64.or
+              (i64.shl
+               (i64.extend_i32_u
+                (i32.and
+                 (local.get $var$4)
+                 (local.get $var$2)
+                )
+               )
+               (i64.const 32)
+              )
+              (i64.and
+               (local.get $var$0)
+               (i64.const 4294967295)
+              )
+             )
+            )
+            (return
+             (i64.extend_i32_u
+              (i32.shr_u
+               (local.get $var$2)
+               (i32.and
+                (call $__wasm_ctz_i32
+                 (local.get $var$3)
+                )
+                (i32.const 31)
+               )
+              )
+             )
+            )
+           )
+           (unreachable)
+          )
+          (br_if $label$5
+           (i32.eqz
+            (i32.and
+             (local.tee $var$4
+              (i32.add
+               (local.get $var$3)
+               (i32.const -1)
+              )
+             )
+             (local.get $var$3)
+            )
+           )
+          )
+          (local.set $var$3
+           (i32.sub
+            (i32.const 0)
+            (local.tee $var$2
+             (i32.sub
+              (i32.add
+               (i32.clz
+                (local.get $var$3)
+               )
+               (i32.const 33)
+              )
+              (i32.clz
+               (local.get $var$2)
+              )
+             )
+            )
+           )
+          )
+          (br $label$3)
+         )
+         (local.set $var$3
+          (i32.sub
+           (i32.const 63)
+           (local.get $var$2)
+          )
+         )
+         (local.set $var$2
+          (i32.add
+           (local.get $var$2)
+           (i32.const 1)
+          )
+         )
+         (br $label$3)
+        )
+        (global.set $__wasm-intrinsics-temp-i64
+         (i64.shl
+          (i64.extend_i32_u
+           (i32.sub
+            (local.get $var$2)
+            (i32.mul
+             (local.tee $var$4
+              (i32.div_u
+               (local.get $var$2)
+               (local.get $var$3)
+              )
+             )
+             (local.get $var$3)
+            )
+           )
+          )
+          (i64.const 32)
+         )
+        )
+        (return
+         (i64.extend_i32_u
+          (local.get $var$4)
+         )
+        )
+       )
+       (br_if $label$4
+        (i32.lt_u
+         (local.tee $var$2
+          (i32.sub
+           (i32.clz
+            (local.get $var$3)
+           )
+           (i32.clz
+            (local.get $var$2)
+           )
+          )
+         )
+         (i32.const 31)
+        )
+       )
+       (br $label$2)
+      )
+      (global.set $__wasm-intrinsics-temp-i64
+       (i64.extend_i32_u
+        (i32.and
+         (local.get $var$4)
+         (i32.wrap_i64
+          (local.get $var$0)
+         )
+        )
+       )
+      )
+      (br_if $label$1
+       (i32.eq
+        (local.get $var$3)
+        (i32.const 1)
+       )
+      )
+      (return
+       (i64.shr_u
+        (local.get $var$0)
+        (i64.extend_i32_u
+         (call $__wasm_ctz_i32
+          (local.get $var$3)
+         )
+        )
+       )
+      )
+     )
+     (local.set $var$3
+      (i32.sub
+       (i32.const 63)
+       (local.get $var$2)
+      )
+     )
+     (local.set $var$2
+      (i32.add
+       (local.get $var$2)
+       (i32.const 1)
+      )
+     )
+    )
+    (local.set $var$5
+     (i64.shr_u
+      (local.get $var$0)
+      (i64.extend_i32_u
+       (i32.and
+        (local.get $var$2)
+        (i32.const 63)
+       )
+      )
+     )
+    )
+    (local.set $var$0
+     (i64.shl
+      (local.get $var$0)
+      (i64.extend_i32_u
+       (i32.and
+        (local.get $var$3)
+        (i32.const 63)
+       )
+      )
+     )
+    )
+    (block $label$13
+     (if
+      (local.get $var$2)
+      (block $block3
+       (local.set $var$8
+        (i64.add
+         (local.get $var$1)
+         (i64.const -1)
+        )
+       )
+       (loop $label$15
+        (local.set $var$5
+         (i64.sub
+          (local.tee $var$5
+           (i64.or
+            (i64.shl
+             (local.get $var$5)
+             (i64.const 1)
+            )
+            (i64.shr_u
+             (local.get $var$0)
+             (i64.const 63)
+            )
+           )
+          )
+          (i64.and
+           (local.tee $var$6
+            (i64.shr_s
+             (i64.sub
+              (local.get $var$8)
+              (local.get $var$5)
+             )
+             (i64.const 63)
+            )
+           )
+           (local.get $var$1)
+          )
+         )
+        )
+        (local.set $var$0
+         (i64.or
+          (i64.shl
+           (local.get $var$0)
+           (i64.const 1)
+          )
+          (local.get $var$7)
+         )
+        )
+        (local.set $var$7
+         (local.tee $var$6
+          (i64.and
+           (local.get $var$6)
+           (i64.const 1)
+          )
+         )
+        )
+        (br_if $label$15
+         (local.tee $var$2
+          (i32.add
+           (local.get $var$2)
+           (i32.const -1)
+          )
+         )
+        )
+       )
+       (br $label$13)
+      )
+     )
+    )
+    (global.set $__wasm-intrinsics-temp-i64
+     (local.get $var$5)
+    )
+    (return
+     (i64.or
+      (i64.shl
+       (local.get $var$0)
+       (i64.const 1)
+      )
+      (local.get $var$6)
+     )
+    )
+   )
+   (global.set $__wasm-intrinsics-temp-i64
+    (local.get $var$0)
+   )
+   (local.set $var$0
+    (i64.const 0)
+   )
+  )
+  (local.get $var$0)
+ )
+ (func $__wasm_ctz_i32 (param $var$0 i32) (result i32)
+  (if
+   (local.get $var$0)
+   (return
+    (i32.sub
+     (i32.const 31)
+     (i32.clz
+      (i32.xor
+       (i32.add
+        (local.get $var$0)
+        (i32.const -1)
+       )
+       (local.get $var$0)
+      )
+     )
+    )
+   )
+  )
+  (i32.const 32)
+ )
+ (func $__wasm_i64_mul (param $var$0 i64) (param $var$1 i64) (result i64)
+  (call $_ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE
+   (local.get $var$0)
+   (local.get $var$1)
+  )
+ )
+ (func $__wasm_i64_sdiv (param $var$0 i64) (param $var$1 i64) (result i64)
+  (call $_ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E
+   (local.get $var$0)
+   (local.get $var$1)
+  )
+ )
+ (func $__wasm_i64_srem (param $var$0 i64) (param $var$1 i64) (result i64)
+  (call $_ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E
+   (local.get $var$0)
+   (local.get $var$1)
+  )
+ )
+ (func $__wasm_i64_udiv (param $var$0 i64) (param $var$1 i64) (result i64)
+  (call $_ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E
+   (local.get $var$0)
+   (local.get $var$1)
+  )
+ )
+ (func $__wasm_i64_urem (param $var$0 i64) (param $var$1 i64) (result i64)
+  (drop
+   (call $_ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E
+    (local.get $var$0)
+    (local.get $var$1)
+   )
+  )
+  (global.get $__wasm-intrinsics-temp-i64)
+ )
+ (func $__wasm_nearest_f32 (param $var$0 f32) (result f32)
+  (local $var$1 f32)
+  (local $var$2 f32)
+  (if
+   (i32.eqz
+    (f32.lt
+     (local.tee $var$2
+      (f32.sub
+       (local.get $var$0)
+       (local.tee $var$1
+        (f32.floor
+         (local.get $var$0)
+        )
+       )
+      )
+     )
+     (f32.const 0.5)
+    )
+   )
+   (block $block
+    (local.set $var$0
+     (f32.ceil
+      (local.get $var$0)
+     )
+    )
+    (if
+     (f32.gt
+      (local.get $var$2)
+      (f32.const 0.5)
+     )
+     (return
+      (local.get $var$0)
+     )
+    )
+    (local.set $var$1
+     (select
+      (local.get $var$1)
+      (local.get $var$0)
+      (f32.eq
+       (f32.sub
+        (local.tee $var$2
+         (f32.mul
+          (local.get $var$1)
+          (f32.const 0.5)
+         )
+        )
+        (f32.floor
+         (local.get $var$2)
+        )
+       )
+       (f32.const 0)
+      )
+     )
+    )
+   )
+  )
+  (local.get $var$1)
+ )
+ (func $__wasm_nearest_f64 (param $var$0 f64) (result f64)
+  (local $var$1 f64)
+  (local $var$2 f64)
+  (if
+   (i32.eqz
+    (f64.lt
+     (local.tee $var$2
+      (f64.sub
+       (local.get $var$0)
+       (local.tee $var$1
+        (f64.floor
+         (local.get $var$0)
+        )
+       )
+      )
+     )
+     (f64.const 0.5)
+    )
+   )
+   (block $block
+    (local.set $var$0
+     (f64.ceil
+      (local.get $var$0)
+     )
+    )
+    (if
+     (f64.gt
+      (local.get $var$2)
+      (f64.const 0.5)
+     )
+     (return
+      (local.get $var$0)
+     )
+    )
+    (local.set $var$1
+     (select
+      (local.get $var$1)
+      (local.get $var$0)
+      (f64.eq
+       (f64.sub
+        (local.tee $var$2
+         (f64.mul
+          (local.get $var$1)
+          (f64.const 0.5)
+         )
+        )
+        (f64.floor
+         (local.get $var$2)
+        )
+       )
+       (f64.const 0)
+      )
+     )
+    )
+   )
+  )
+  (local.get $var$1)
+ )
+ (func $__wasm_popcnt_i32 (param $var$0 i32) (result i32)
+  (local $var$1 i32)
+  (block $label$1 (result i32)
+   (loop $label$2
+    (drop
+     (br_if $label$1
+      (local.get $var$1)
+      (i32.eqz
+       (local.get $var$0)
+      )
+     )
+    )
+    (local.set $var$0
+     (i32.and
+      (local.get $var$0)
+      (i32.sub
+       (local.get $var$0)
+       (i32.const 1)
+      )
+     )
+    )
+    (local.set $var$1
+     (i32.add
+      (local.get $var$1)
+      (i32.const 1)
+     )
+    )
+    (br $label$2)
+   )
+  )
+ )
+ (func $__wasm_rotl_i32 (param $var$0 i32) (param $var$1 i32) (result i32)
+  (local $var$2 i32)
+  (i32.or
+   (i32.shl
+    (i32.and
+     (i32.shr_u
+      (i32.const -1)
+      (local.tee $var$2
+       (i32.and
+        (local.get $var$1)
+        (i32.const 31)
+       )
+      )
+     )
+     (local.get $var$0)
+    )
+    (local.get $var$2)
+   )
+   (i32.shr_u
+    (i32.and
+     (i32.shl
+      (i32.const -1)
+      (local.tee $var$1
+       (i32.and
+        (i32.sub
+         (i32.const 0)
+         (local.get $var$1)
+        )
+        (i32.const 31)
+       )
+      )
+     )
+     (local.get $var$0)
+    )
+    (local.get $var$1)
+   )
+  )
+ )
+ (func $__wasm_rotl_i64 (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $var$2 i64)
+  (i64.or
+   (i64.shl
+    (i64.and
+     (i64.shr_u
+      (i64.const -1)
+      (local.tee $var$2
+       (i64.and
+        (local.get $var$1)
+        (i64.const 63)
+       )
+      )
+     )
+     (local.get $var$0)
+    )
+    (local.get $var$2)
+   )
+   (i64.shr_u
+    (i64.and
+     (i64.shl
+      (i64.const -1)
+      (local.tee $var$1
+       (i64.and
+        (i64.sub
+         (i64.const 0)
+         (local.get $var$1)
+        )
+        (i64.const 63)
+       )
+      )
+     )
+     (local.get $var$0)
+    )
+    (local.get $var$1)
+   )
+  )
+ )
+ (func $__wasm_rotr_i32 (param $var$0 i32) (param $var$1 i32) (result i32)
+  (local $var$2 i32)
+  (i32.or
+   (i32.shr_u
+    (i32.and
+     (i32.shl
+      (i32.const -1)
+      (local.tee $var$2
+       (i32.and
+        (local.get $var$1)
+        (i32.const 31)
+       )
+      )
+     )
+     (local.get $var$0)
+    )
+    (local.get $var$2)
+   )
+   (i32.shl
+    (i32.and
+     (i32.shr_u
+      (i32.const -1)
+      (local.tee $var$1
+       (i32.and
+        (i32.sub
+         (i32.const 0)
+         (local.get $var$1)
+        )
+        (i32.const 31)
+       )
+      )
+     )
+     (local.get $var$0)
+    )
+    (local.get $var$1)
+   )
+  )
+ )
+ (func $__wasm_rotr_i64 (param $var$0 i64) (param $var$1 i64) (result i64)
+  (local $var$2 i64)
+  (i64.or
+   (i64.shr_u
+    (i64.and
+     (i64.shl
+      (i64.const -1)
+      (local.tee $var$2
+       (i64.and
+        (local.get $var$1)
+        (i64.const 63)
+       )
+      )
+     )
+     (local.get $var$0)
+    )
+    (local.get $var$2)
+   )
+   (i64.shl
+    (i64.and
+     (i64.shr_u
+      (i64.const -1)
+      (local.tee $var$1
+       (i64.and
+        (i64.sub
+         (i64.const 0)
+         (local.get $var$1)
+        )
+        (i64.const 63)
+       )
+      )
+     )
+     (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-non-js-ops.wast b/binaryen/test/passes/remove-non-js-ops.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-non-js-ops.wast
@@ -0,0 +1,43 @@
+(module
+ (memory 1)
+ (func $copysign64 (param $0 f64) (param $1 f64) (result f64)
+   (f64.copysign (local.get $0) (local.get $1)))
+ (func $copysign32 (param $0 f32) (param $1 f32) (result f32)
+   (f32.copysign (local.get $0) (local.get $1)))
+
+ (func $rotl32 (param $0 i32) (param $1 i32) (result i32)
+   (i32.rotl (local.get $0) (local.get $1)))
+ (func $rotr32 (param $0 i32) (param $1 i32) (result i32)
+   (i32.rotr (local.get $0) (local.get $1)))
+ (func $rotl64 (param $0 i64) (param $1 i64) (result i64)
+   (i64.rotl (local.get $0) (local.get $1)))
+ (func $rotr64 (param $0 i64) (param $1 i64) (result i64)
+   (i64.rotr (local.get $0) (local.get $1)))
+
+ (func $nearest64 (param $0 f64) (result f64)
+   (f64.nearest (local.get $0)))
+ (func $nearest32 (param $0 f32) (result f32)
+   (f32.nearest (local.get $0)))
+
+ (func $trunc64 (param $0 f64) (result f64)
+   (f64.trunc (local.get $0)))
+ (func $trunc32 (param $0 f32) (result f32)
+   (f32.trunc (local.get $0)))
+
+ (func $popcnt32 (param $0 i32) (result i32)
+   (i32.popcnt (local.get $0)))
+ (func $ctz32 (param $0 i32) (result i32)
+   (i32.ctz (local.get $0)))
+
+ (func $i64_sdiv (param $0 i64) (param $1 i64) (result i64)
+   (i64.div_s (local.get $0) (local.get $1)))
+ (func $i64_udiv (param $0 i64) (param $1 i64) (result i64)
+   (i64.div_u (local.get $0) (local.get $1)))
+ (func $i64_srem (param $0 i64) (param $1 i64) (result i64)
+   (i64.rem_s (local.get $0) (local.get $1)))
+ (func $i64_urem (param $0 i64) (param $1 i64) (result i64)
+   (i64.rem_u (local.get $0) (local.get $1)))
+ (func $i64_mul (param $0 i64) (param $1 i64) (result i64)
+   (i64.mul (local.get $0) (local.get $1)))
+)
+
diff --git a/binaryen/test/passes/remove-unused-brs_enable-multivalue.txt b/binaryen/test/passes/remove-unused-brs_enable-multivalue.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-brs_enable-multivalue.txt
@@ -0,0 +1,2527 @@
+(module
+ (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 (func (param i32) (result i32)))
+ (type $none_=>_i32_i64 (func (result i32 i64)))
+ (type $none_=>_i64 (func (result i64)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_f64_i32_f64_f32_f32_=>_i32 (func (param i32 f64 i32 f64 f32 f32) (result i32)))
+ (type $f32_i32_f32_i32_i32_f64_f32_=>_i32 (func (param f32 i32 f32 i32 i32 f64 f32) (result i32)))
+ (type $i32_=>_i64 (func (param i32) (result i64)))
+ (type $none_=>_f32 (func (result f32)))
+ (type $i32_=>_f32 (func (param i32) (result f32)))
+ (memory $0 256 256)
+ (func $b0-yes (param $i1 i32)
+  (block $topmost
+  )
+ )
+ (func $b1 (param $i1 i32)
+  (block $topmost
+   (block $block
+    (drop
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $b2 (param $i1 i32)
+  (block $topmost
+   (block $inner
+   )
+  )
+ )
+ (func $b3-yes (param $i1 i32)
+  (block $topmost
+   (block $inner
+   )
+  )
+ )
+ (func $b4 (param $i1 i32)
+  (block $topmost
+   (block $inner
+    (block $block
+     (drop
+      (i32.const 0)
+     )
+    )
+   )
+  )
+ )
+ (func $b5 (param $i1 i32)
+  (block $topmost
+   (block $inner
+    (block $block
+     (drop
+      (i32.const 0)
+     )
+    )
+   )
+  )
+ )
+ (func $b6 (param $i1 i32)
+  (block $topmost
+   (br_if $topmost
+    (i32.const 1)
+   )
+  )
+ )
+ (func $b7 (param $i1 i32)
+  (block $topmost
+   (block $block
+    (drop
+     (i32.const 0)
+    )
+    (br_if $topmost
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $b8 (param $i1 i32)
+  (block $topmost
+   (block $inner
+    (br_if $topmost
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $b9 (param $i1 i32)
+  (block $topmost
+   (block $inner
+    (br_if $topmost
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $b10 (param $i1 i32)
+  (block $topmost
+   (block $inner
+    (block $block
+     (drop
+      (i32.const 0)
+     )
+     (br_if $topmost
+      (i32.const 1)
+     )
+    )
+   )
+  )
+ )
+ (func $b11 (param $i1 i32)
+  (block $topmost
+   (block $inner
+    (block $block
+     (drop
+      (i32.const 0)
+     )
+     (br_if $topmost
+      (i32.const 1)
+     )
+    )
+   )
+  )
+ )
+ (func $b12-yes
+  (if
+   (i32.const 1)
+   (block $topmost
+    (block $block1
+     (drop
+      (i32.const 12)
+     )
+     (block $block
+      (drop
+       (i32.const 1)
+      )
+     )
+    )
+   )
+   (block $block3
+    (drop
+     (i32.const 27)
+    )
+    (block $block0
+     (drop
+      (i32.const 2)
+     )
+    )
+   )
+  )
+ )
+ (func $b13 (result i32)
+  (block $topmost (result i32)
+   (if
+    (i32.const 1)
+    (block $block1
+     (drop
+      (i32.const 12)
+     )
+     (drop
+      (br_if $topmost
+       (i32.const 1)
+       (i32.const 1)
+      )
+     )
+    )
+    (block $block3
+     (drop
+      (i32.const 27)
+     )
+     (br $topmost
+      (i32.const 2)
+     )
+    )
+   )
+   (i32.const 3)
+  )
+ )
+ (func $b14 (result i32)
+  (select
+   (block $topmost (result i32)
+    (block $block1 (result i32)
+     (i32.const 12)
+    )
+   )
+   (block $block3 (result i32)
+    (i32.const 27)
+   )
+   (i32.const 1)
+  )
+ )
+ (func $b14-tuple (result i32 i64)
+  (if (result i32 i64)
+   (i32.const 1)
+   (block $topmost (result i32 i64)
+    (block $block1 (result i32 i64)
+     (tuple.make
+      (i32.const 12)
+      (i64.const 12)
+     )
+    )
+   )
+   (block $block3 (result i32 i64)
+    (tuple.make
+     (i32.const 27)
+     (i64.const 27)
+    )
+   )
+  )
+ )
+ (func $b15
+  (block $topmost
+   (br_if $topmost
+    (i32.const 17)
+   )
+  )
+ )
+ (func $b15b
+  (if
+   (i32.const 18)
+   (block $topmost
+    (block $block
+     (drop
+      (i32.const 0)
+     )
+    )
+   )
+  )
+ )
+ (func $b16
+  (block $a
+   (block $b
+    (block $c
+    )
+   )
+  )
+  (block $a1
+   (block $b2
+    (block $c3
+    )
+   )
+  )
+  (block $a4
+   (block $b5
+    (block $c6
+    )
+   )
+  )
+ )
+ (func $b17
+  (if
+   (i32.const 0)
+   (block $a
+    (block $block1
+    )
+   )
+   (block $block3
+   )
+  )
+  (if
+   (i32.const 0)
+   (block $a7
+    (drop
+     (i32.const 1)
+    )
+   )
+   (block $block6
+   )
+  )
+  (if
+   (i32.const 0)
+   (block $a9
+    (block $block8
+    )
+   )
+   (drop
+    (i32.const 1)
+   )
+  )
+  (if
+   (i32.const 0)
+   (block $c
+    (block $b
+     (block $block11
+     )
+    )
+   )
+   (block $block13
+   )
+  )
+ )
+ (func $ret-1
+  (nop)
+ )
+ (func $ret-2
+  (block $block0
+   (block $block1
+   )
+  )
+ )
+ (func $ret-3
+  (if
+   (i32.const 0)
+   (block $block0
+   )
+   (block $block3
+   )
+  )
+ )
+ (func $ret-value (result i32)
+  (block $block0 (result i32)
+   (block $block1 (result i32)
+    (i32.const 1)
+   )
+  )
+ )
+ (func $no-select-but-the-last
+  (block $a
+   (if
+    (i32.const 0)
+    (drop
+     (i32.const 1)
+    )
+    (block $block2
+     (block $block
+      (drop
+       (i32.const 2)
+      )
+      (br $a)
+     )
+     (drop
+      (i32.const 3)
+     )
+    )
+   )
+   (if
+    (i32.const 0)
+    (block $block4
+     (block $block13
+      (drop
+       (i32.const 2)
+      )
+      (br $a)
+     )
+     (drop
+      (i32.const 3)
+     )
+    )
+    (drop
+     (i32.const 1)
+    )
+   )
+   (if
+    (block $block6 (result i32)
+     (block $block15
+      (drop
+       (i32.const 2)
+      )
+      (br $a)
+     )
+     (i32.const 3)
+    )
+    (drop
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 1)
+    )
+   )
+   (if
+    (block $a17 (result i32)
+     (i32.const 0)
+    )
+    (block $a18
+     (block $block19
+      (drop
+       (i32.const 1)
+      )
+     )
+    )
+    (block $a20
+     (block $block21
+      (drop
+       (i32.const 2)
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $side-effects-and-order (result i32)
+  (local $x i32)
+  (block $do-once$0
+   (if
+    (call $b13)
+    (block $block
+     (drop
+      (i32.const 0)
+     )
+     (br $do-once$0)
+    )
+   )
+   (drop
+    (i32.const 1)
+   )
+  )
+  (block $do-once$022
+   (if
+    (call $b13)
+    (block $block24
+     (drop
+      (call $b14)
+     )
+     (br $do-once$022)
+    )
+   )
+   (drop
+    (i32.const 1)
+   )
+  )
+  (block $do-once$025
+   (if
+    (i32.const 0)
+    (block $block27
+     (drop
+      (call $b14)
+     )
+     (br $do-once$025)
+    )
+   )
+   (drop
+    (i32.const 1)
+   )
+  )
+  (block $do-once$028 (result i32)
+   (if
+    (local.tee $x
+     (i32.const 1)
+    )
+    (br $do-once$028
+     (local.tee $x
+      (i32.const 2)
+     )
+    )
+   )
+   (i32.const 1)
+  )
+ )
+ (func $loops
+  (loop $in
+   (block $out
+    (br_if $in
+     (i32.eqz
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (loop $in30
+   (br $in30)
+  )
+  (loop $loop-in
+   (block $out31
+    (br_if $out31
+     (i32.const 0)
+    )
+   )
+  )
+  (loop $in33
+   (block $out34
+    (br_if $out34
+     (i32.const 0)
+    )
+   )
+  )
+  (loop $in36
+   (nop)
+  )
+  (loop $in37
+   (block $out38
+   )
+  )
+  (loop $in39
+   (if
+    (i32.eqz
+     (i32.const 0)
+    )
+    (block $out40
+     (nop)
+     (br_if $in39
+      (i32.const 1)
+     )
+    )
+   )
+  )
+  (loop $in42
+   (block $out43
+    (br_if $in42
+     (i32.const 0)
+    )
+   )
+  )
+  (loop $in45
+   (if
+    (i32.const 0)
+    (block $out46
+     (unreachable)
+    )
+    (br $in45)
+   )
+  )
+  (loop $in48
+   (if
+    (i32.const 0)
+    (block $out49
+     (block $block
+      (call $loops)
+     )
+    )
+    (br $in48)
+   )
+  )
+  (loop $in-todo
+   (if
+    (i32.const 0)
+    (block $out-todo
+    )
+    (block
+     (call $loops)
+     (br $in-todo)
+    )
+   )
+  )
+  (loop $in52
+   (if
+    (i32.const 0)
+    (block $out53
+    )
+    (block
+     (call $loops)
+     (br $in52)
+    )
+   )
+  )
+  (loop $in55
+   (if
+    (i32.const 0)
+    (block
+     (call $loops)
+     (br $in55)
+    )
+    (block $out56
+    )
+   )
+  )
+  (loop $in58
+   (if
+    (i32.const 0)
+    (block
+     (block $block61
+      (drop
+       (i32.const 1)
+      )
+      (call $loops)
+     )
+     (br $in58)
+    )
+    (block $out59
+    )
+   )
+  )
+  (loop $in62
+   (if
+    (i32.const 0)
+    (block $out63
+    )
+    (block
+     (call $loops)
+     (drop
+      (i32.const 100)
+     )
+     (br $in62)
+    )
+   )
+  )
+  (loop $in65
+   (if
+    (i32.const 0)
+    (block
+     (call $loops)
+     (drop
+      (i32.const 101)
+     )
+     (br $in65)
+    )
+    (block $out66
+    )
+   )
+  )
+  (loop $in68
+   (if
+    (i32.const 0)
+    (block
+     (block $block71
+      (drop
+       (i32.const 1)
+      )
+      (call $loops)
+     )
+     (drop
+      (i32.const 102)
+     )
+     (br $in68)
+    )
+    (block $out69
+    )
+   )
+  )
+  (loop $in72
+   (if
+    (i32.eqz
+     (i32.const 0)
+    )
+    (block $out73
+     (nop)
+     (call $loops)
+     (return)
+     (br $in72)
+    )
+   )
+  )
+  (loop $in75
+   (block $out76
+    (br_if $out76
+     (i32.const 0)
+    )
+    (call $loops)
+    (br $out76)
+    (br $in75)
+   )
+  )
+  (loop $in78
+   (if
+    (i32.const 0)
+    (block $out79
+    )
+    (block
+     (call $loops)
+     (drop
+      (block $out2 (result i32)
+       (i32.const 1)
+      )
+     )
+     (br $in78)
+    )
+   )
+  )
+  (loop $in81
+   (block $out82
+    (br_if $in81
+     (i32.eqz
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (loop $in-todo2
+   (if
+    (i32.const 0)
+    (block $out-todo2
+    )
+    (block
+     (call $loops)
+     (br $in-todo2)
+    )
+   )
+  )
+  (loop $in83
+   (block $out84
+    (br $out84)
+    (br $in83)
+   )
+  )
+  (loop $in85
+   (block $out86
+    (drop
+     (i32.const 0)
+    )
+    (br $in85)
+   )
+  )
+  (loop $in-not
+   (block $out-not
+    (br_if $out-not
+     (i32.const -1)
+    )
+    (br_if $out-not
+     (i32.const 0)
+    )
+    (call $loops)
+    (br $in-not)
+   )
+  )
+  (loop $in-todo287
+   (if
+    (i32.const 0)
+    (block $out-todo288
+    )
+    (block
+     (call $loops)
+     (drop
+      (i32.const 1)
+     )
+     (br $in-todo287)
+    )
+   )
+  )
+ )
+ (func $br_if_in_block (result i32)
+  (block $outval (result i32)
+   (block $in
+    (drop
+     (i32.const 1)
+    )
+    (br $in)
+    (drop
+     (i32.const 2)
+    )
+    (br_if $in
+     (i32.eqz
+      (i32.const 3)
+     )
+    )
+    (unreachable)
+    (drop
+     (i32.const 4)
+    )
+    (br_if $in
+     (i32.const 5)
+    )
+    (unreachable)
+    (drop
+     (i32.const 6)
+    )
+   )
+   (select
+    (i32.const 7)
+    (i32.const 8)
+    (i32.const 6)
+   )
+  )
+ )
+ (func $threading
+  (drop
+   (block $value-out (result i32)
+    (block $value-in (result i32)
+     (block $out
+      (block $in
+       (br_if $out
+        (i32.const 1)
+       )
+       (br_if $out
+        (i32.const 2)
+       )
+       (br $value-in
+        (i32.const 3)
+       )
+      )
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (block $stack1
+   (block $stack2
+    (block $stack3
+     (block $stack4
+      (br_if $stack1
+       (i32.const 1)
+      )
+      (unreachable)
+     )
+    )
+   )
+  )
+ )
+ (func $if-to-br_if-conflict (param $x i32) (param $y i32) (result i32)
+  (block $leave
+   (local.set $y
+    (block $out (result i32)
+     (if
+      (local.get $x)
+      (br $out
+       (block $block (result i32)
+        (local.set $x
+         (i32.const 0)
+        )
+        (i32.const 1)
+       )
+      )
+      (br_if $leave
+       (i32.const 1)
+      )
+     )
+     (unreachable)
+    )
+   )
+  )
+  (i32.add
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+ (func $if-to-br_if-conflict2 (param $x i32) (param $y i32) (result i32)
+  (block $leave
+   (local.set $y
+    (block $out (result i32)
+     (if
+      (local.get $x)
+      (br_if $leave
+       (i32.const 1)
+      )
+      (br $out
+       (block $block (result i32)
+        (local.set $x
+         (i32.const 0)
+        )
+        (i32.const 1)
+       )
+      )
+     )
+     (unreachable)
+    )
+   )
+  )
+  (i32.add
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+ (func $if-to-br_if-value-sideeffect (param $x i32) (param $y i32) (result i32)
+  (block $leave
+   (local.set $y
+    (block $out (result i32)
+     (if
+      (local.get $x)
+      (br $out
+       (block $block (result i32)
+        (drop
+         (call $if-to-br_if-value-sideeffect
+          (i32.const 0)
+          (i32.const 1)
+         )
+        )
+        (nop)
+        (i32.const 1)
+       )
+      )
+     )
+     (unreachable)
+    )
+   )
+  )
+  (i32.add
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+ (func $fuzz (param $j i32) (param $g i32)
+  (loop $label$continue$d
+   (block $label$break$c
+    (block $label$break$d
+     (if
+      (i32.lt_s
+       (local.get $j)
+       (i32.const 2147483640)
+      )
+      (block $x
+       (block $y
+        (block $z
+         (br_if $x
+          (local.get $j)
+         )
+        )
+       )
+      )
+      (block $switch$26
+      )
+     )
+     (i32.store
+      (i32.const 5724)
+      (i32.const -254899267)
+     )
+     (br $label$continue$d)
+    )
+   )
+  )
+ )
+ (func $iffify
+  (if
+   (i32.eqz
+    (i32.const 0)
+   )
+   (block $yes
+    (nop)
+    (drop
+     (i32.const 1)
+    )
+    (drop
+     (i32.const 2)
+    )
+   )
+  )
+  (block $no
+   (br_if $no
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 1)
+   )
+   (br $no)
+   (drop
+    (i32.const 2)
+   )
+  )
+  (block $no2
+   (br_if $no2
+    (i32.const 0)
+   )
+  )
+  (block $no3
+   (br $no3)
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 2)
+   )
+  )
+  (block $no5
+   (block $no4
+    (br_if $no5
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 1)
+    )
+    (drop
+     (i32.const 2)
+    )
+   )
+  )
+ )
+ (func $loop-if (result i32)
+  (loop $typed (result i32)
+   (block $outer (result i32)
+    (block (result i32)
+     (br_if $typed
+      (i32.eqz
+       (i32.const 2)
+      )
+     )
+     (block $block (result i32)
+      (drop
+       (call $loop-if)
+      )
+      (i32.const 0)
+     )
+    )
+   )
+  )
+ )
+ (func $block-break (param $0 i32)
+  (block $block$7$break
+   (block $shape$6$continue
+    (call $block-break
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $loop-break (param $0 i32)
+  (loop $shape$6$continue
+   (block $block$7$break
+    (block
+     (call $loop-break
+      (i32.const 1)
+     )
+     (br_if $shape$6$continue
+      (local.get $0)
+     )
+     (nop)
+    )
+   )
+  )
+ )
+ (func $untaken-brs-might-prevent-block-removal (param $0 f32) (param $1 i32) (param $2 f32) (param $3 i32) (param $4 i32) (param $5 f64) (param $6 f32) (result i32)
+  (block $label$0 (result i32)
+   (block $label$1
+    (br_if $label$1
+     (i32.const 607395945)
+    )
+    (br_if $label$1
+     (i32.load offset=3 align=1
+      (select
+       (call $untaken-brs-might-prevent-block-removal
+        (f32.const 1.4904844647389837e-07)
+        (br_if $label$0
+         (i32.store16 offset=4 align=1
+          (i32.const 1900641)
+          (br $label$0
+           (i32.const 1628075109)
+          )
+         )
+         (i32.const 1764950569)
+        )
+        (f32.const 1.1910939690100655e-32)
+        (i32.const 1628057906)
+        (i32.const 859068982)
+        (f64.const 2.524518840347722e-258)
+        (f32.const -nan:0x40a63)
+       )
+       (i32.const 688529440)
+       (i32.const 1751478890)
+      )
+     )
+    )
+   )
+   (i32.const 1935947830)
+  )
+ )
+ (func $unexitable-loops-result (param $0 i32) (result i64)
+  (loop $label$0
+   (loop $label$1
+    (br_if $label$0
+     (i32.load8_s
+      (i32.const 201460482)
+     )
+    )
+    (block
+     (block $label$3
+      (br_if $label$1
+       (local.get $0)
+      )
+     )
+     (br $label$1)
+    )
+   )
+  )
+ )
+ (func $untaken-br-with-concrete-last-element
+  (block $label$8
+   (block $label$11
+    (block $label$14
+     (br_if $label$8
+      (br $label$8)
+     )
+    )
+   )
+  )
+ )
+ (func $untaken-br-with-concrete-last-element2 (result i32)
+  (block $label$8 (result i32)
+   (block $label$11 (result i32)
+    (block $label$14 (result i32)
+     (br_if $label$14
+      (i32.const 102)
+      (br $label$11
+       (i32.const 103)
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $untaken-br_if-then-if
+  (block $label$0
+   (br_if $label$0
+    (unreachable)
+   )
+   (if
+    (i32.const 0)
+    (nop)
+   )
+  )
+ )
+ (func $unreachable-if-that-could-be-a-br_if (result i64)
+  (loop $label$3 (result i64)
+   (drop
+    (if (result f64)
+     (unreachable)
+     (f64.const 1)
+     (br $label$3)
+    )
+   )
+   (i64.const 1)
+  )
+ )
+ (func $nop-br-might-update-type
+  (block $label$39
+   (drop
+    (if (result i32)
+     (unreachable)
+     (if (result i32)
+      (i32.const 1)
+      (br $label$39)
+      (i32.const 0)
+     )
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $no-flow-through-if-without-else (result f32)
+  (local $0 i32)
+  (local $2 f32)
+  (if (result f32)
+   (local.get $0)
+   (block $label$0
+    (block $label$11
+     (return
+      (f32.const 239)
+     )
+     (if
+      (i32.const 0)
+      (return
+       (local.get $2)
+      )
+     )
+    )
+   )
+   (f32.const -9223372036854775808)
+  )
+ )
+ (func $unreachable-return-loop-value (result i64)
+  (loop $loop
+   (if
+    (i32.const 1)
+    (block $block
+     (br_if $block
+      (br $loop)
+     )
+     (br $loop)
+    )
+   )
+   (br $loop)
+  )
+ )
+ (func $obviously-flows-out-maybe (param $var$0 i32) (result f32)
+  (block $label$1 (result f32)
+   (br $label$1
+    (f32.const 1)
+   )
+   (loop $label$5
+    (if
+     (i32.const 11)
+     (block $label$8
+      (br_if $label$8
+       (unreachable)
+      )
+      (br $label$5)
+     )
+    )
+    (br $label$5)
+   )
+  )
+ )
+ (func $br-to-table (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (nop)
+     (nop)
+     (block $tablify|0
+      (br_table $x $y $z $tablify|0
+       (local.get $a)
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $br-to-table-too-few (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (br_if $x
+      (i32.eq
+       (local.get $a)
+       (i32.const 0)
+      )
+     )
+     (br_if $x
+      (i32.eq
+       (local.get $a)
+       (i32.const 1)
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $br-to-table-one-more (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (nop)
+     (nop)
+     (nop)
+     (block $tablify|0
+      (br_table $x $y $z $x $tablify|0
+       (local.get $a)
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $br-to-table-overlap (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (br_if $x
+      (i32.eq
+       (local.get $a)
+       (i32.const 0)
+      )
+     )
+     (br_if $y
+      (i32.eq
+       (local.get $a)
+       (i32.const 1)
+      )
+     )
+     (br_if $z
+      (i32.eq
+       (local.get $a)
+       (i32.const 1)
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $br-to-table-overlap-start (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (br_if $x
+      (i32.eq
+       (local.get $a)
+       (i32.const 0)
+      )
+     )
+     (br_if $y
+      (i32.eq
+       (local.get $a)
+       (i32.const 0)
+      )
+     )
+     (br_if $z
+      (i32.eq
+       (local.get $a)
+       (i32.const 1)
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $br-to-table-offset (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (nop)
+     (nop)
+     (block $tablify|0
+      (br_table $x $y $z $tablify|0
+       (i32.sub
+        (local.get $a)
+        (i32.const 15)
+       )
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $br-to-table-RANGE-high (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (br_if $x
+      (i32.eq
+       (local.get $a)
+       (i32.const 0)
+      )
+     )
+     (br_if $y
+      (i32.eq
+       (local.get $a)
+       (i32.const 1)
+      )
+     )
+     (br_if $z
+      (i32.eq
+       (local.get $a)
+       (i32.const 10)
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $br-to-table-RANGE-low (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (nop)
+     (nop)
+     (block $tablify|0
+      (br_table $x $tablify|0 $tablify|0 $y $tablify|0 $tablify|0 $tablify|0 $tablify|0 $tablify|0 $z $tablify|0
+       (local.get $a)
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $br-to-table-bad (param $a i32) (result i32)
+  (block $value (result i32)
+   (block $x
+    (block $y
+     (block $z
+      (nop)
+      (br $x)
+      (nop)
+      (nop)
+      (block $tablify|0
+       (br_table $x $y $z $tablify|0
+        (local.get $a)
+       )
+      )
+      (unreachable)
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (i32.const 2000)
+  )
+ )
+ (func $br-to-table-bad2 (param $a i32) (result i32)
+  (block $value (result i32)
+   (block $x
+    (block $y
+     (block $z
+      (nop)
+      (drop
+       (br_if $value
+        (i32.const 1000)
+        (i32.eq
+         (local.get $a)
+         (i32.const 0)
+        )
+       )
+      )
+      (nop)
+      (nop)
+      (block $tablify|0
+       (br_table $x $y $z $tablify|0
+        (local.get $a)
+       )
+      )
+      (unreachable)
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (i32.const 2000)
+  )
+ )
+ (func $br-to-table-bad3 (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (br_if $x
+      (i32.eq
+       (i32.const 10)
+       (i32.const 0)
+      )
+     )
+     (nop)
+     (nop)
+     (block $tablify|0
+      (br_table $x $y $z $tablify|0
+       (local.get $a)
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $br-to-table-multi (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (nop)
+     (nop)
+     (block $tablify|0
+      (br_table $z $y $x $tablify|0
+       (i32.sub
+        (i32.const 10)
+        (i32.const 5)
+       )
+      )
+     )
+     (nop)
+     (nop)
+     (block $tablify|00
+      (br_table $x $y $z $tablify|00
+       (local.get $a)
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $br-to-table-bad4 (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (br_if $x
+      (i32.ne
+       (local.get $a)
+       (i32.const 0)
+      )
+     )
+     (br_if $y
+      (i32.eq
+       (local.get $a)
+       (i32.const 1)
+      )
+     )
+     (br_if $z
+      (i32.eq
+       (local.get $a)
+       (i32.const 2)
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $br-to-table-bad5 (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (br_if $x
+      (i32.eq
+       (local.get $a)
+       (local.get $a)
+      )
+     )
+     (br_if $y
+      (i32.eq
+       (local.get $a)
+       (local.get $a)
+      )
+     )
+     (br_if $z
+      (i32.eq
+       (local.get $a)
+       (local.get $a)
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $br-to-table-bad6 (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (br_if $x
+      (i32.eq
+       (call $b13)
+       (i32.const 0)
+      )
+     )
+     (br_if $y
+      (i32.eq
+       (call $b13)
+       (i32.const 1)
+      )
+     )
+     (br_if $z
+      (i32.eq
+       (call $b13)
+       (i32.const 2)
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $br-to-table-bad7 (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (br_if $x
+      (i32.eq
+       (local.get $a)
+       (i32.const -1)
+      )
+     )
+     (br_if $y
+      (i32.eq
+       (local.get $a)
+       (i32.const -1)
+      )
+     )
+     (br_if $z
+      (i32.eq
+       (local.get $a)
+       (i32.const -1)
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $br-to-table-defaultNameOverlaps (param $a i32)
+  (block $x
+   (block $tablify|0
+    (block $z
+     (nop)
+     (nop)
+     (block $tablify|1
+      (br_table $x $tablify|0 $z $tablify|1
+       (local.get $a)
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $br-to-table-unreach (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (br_if $x
+      (i32.eq
+       (unreachable)
+       (i32.const 0)
+      )
+     )
+     (br_if $y
+      (i32.eq
+       (unreachable)
+       (i32.const 1)
+      )
+     )
+     (br_if $z
+      (i32.eq
+       (unreachable)
+       (i32.const 2)
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $br-to-table-overlap-but-later (param $a i32)
+  (block $x
+   (block $y
+    (block $z
+     (br_if $x
+      (i32.eq
+       (local.get $a)
+       (i32.const 0)
+      )
+     )
+     (br_if $y
+      (i32.eq
+       (local.get $a)
+       (i32.const 1)
+      )
+     )
+     (nop)
+     (nop)
+     (block $tablify|0
+      (br_table $z $x $y $tablify|0
+       (i32.sub
+        (local.get $a)
+        (i32.const 1)
+       )
+      )
+     )
+     (unreachable)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+ (func $tiny-switch
+  (if
+   (i32.const 0)
+   (block $y
+   )
+   (block $x
+   )
+  )
+  (block $z
+   (block
+    (drop
+     (i32.const 0)
+    )
+    (nop)
+   )
+  )
+ )
+ (func $trim-switch
+  (block $A
+   (block $y
+    (br_table $A $y $A $y $A $y
+     (i32.sub
+      (i32.const 0)
+      (i32.const 2)
+     )
+    )
+   )
+   (call $trim-switch)
+  )
+ )
+ (func $same-target-br_if-and-br
+  (block $x
+   (drop
+    (i32.const 0)
+   )
+   (br $x)
+   (unreachable)
+  )
+ )
+ (func $simple-switch (result i32)
+  (block $A
+   (block $B
+    (block $y
+     (br_table $A $y $y $y $y $y $A $y $y $y $y $A $y
+      (i32.const 0)
+     )
+     (return
+      (i32.const 0)
+     )
+    )
+    (return
+     (i32.const 1)
+    )
+   )
+   (return
+    (i32.const 2)
+   )
+  )
+  (i32.const 3)
+ )
+ (func $simple-switch-2 (result i32)
+  (block $A
+   (block $B
+    (block $y
+     (br_table $A $y $y $y $y $y $y $y $y $y $y $y $A $y
+      (i32.const 0)
+     )
+     (return
+      (i32.const 0)
+     )
+    )
+    (return
+     (i32.const 1)
+    )
+   )
+   (return
+    (i32.const 2)
+   )
+  )
+  (i32.const 3)
+ )
+ (func $simple-switch-3 (result i32)
+  (block $A
+   (block $B
+    (block $y
+     (br_table $A $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $B $y
+      (i32.const 0)
+     )
+     (return
+      (i32.const 0)
+     )
+    )
+    (return
+     (i32.const 1)
+    )
+   )
+   (return
+    (i32.const 2)
+   )
+  )
+  (i32.const 3)
+ )
+ (func $simple-switch43 (result i32)
+  (local $0 i32)
+  (block $A
+   (block $B
+    (block $y
+     (br_if $A
+      (i32.eqz
+       (local.tee $0
+        (i32.const 0)
+       )
+      )
+     )
+     (br_if $B
+      (i32.eq
+       (local.get $0)
+       (i32.const 127)
+      )
+     )
+     (br $y)
+     (return
+      (i32.const 0)
+     )
+    )
+    (return
+     (i32.const 1)
+    )
+   )
+   (return
+    (i32.const 2)
+   )
+  )
+  (i32.const 3)
+ )
+ (func $simple-switch-5 (result i32)
+  (block $A
+   (block $B
+    (block $y
+     (br_table $A $y $y $y $y $y $A $y $y $y $y $y $A $y
+      (i32.const 0)
+     )
+     (return
+      (i32.const 0)
+     )
+    )
+    (return
+     (i32.const 1)
+    )
+   )
+   (return
+    (i32.const 2)
+   )
+  )
+  (i32.const 3)
+ )
+ (func $undo-if-return (param $p i32) (result i32)
+  (local $x i32)
+  (block $out
+   (block
+    (br_if $out
+     (local.get $p)
+    )
+    (local.set $x
+     (i32.const 1)
+    )
+   )
+   (block
+    (br_if $out
+     (i32.eqz
+      (local.get $p)
+     )
+    )
+    (local.set $x
+     (i32.const 2)
+    )
+   )
+   (local.set $x
+    (if (result i32)
+     (local.get $p)
+     (br $out)
+     (br $out)
+    )
+   )
+  )
+  (local.get $p)
+ )
+ (func $if-unreachable-but-declares-value (param $var$0 i32) (param $var$1 f64) (param $var$2 i32) (param $var$3 f64) (param $var$4 f32) (param $var$5 f32) (result i32)
+  (local $var$6 f64)
+  (if
+   (i32.const 0)
+   (drop
+    (loop $label$3 (result i64)
+     (block $label$4 (result i64)
+      (block $label$5
+       (block $label$6
+        (local.set $var$1
+         (if (result f64)
+          (unreachable)
+          (br $label$5)
+          (f64.const 1)
+         )
+        )
+       )
+      )
+      (i64.const 1)
+     )
+    )
+   )
+  )
+  (i32.const 0)
+ )
+ (func $if-flow-1 (result i32)
+  (select
+   (i32.const 1)
+   (i32.const 2)
+   (i32.const 0)
+  )
+ )
+ (func $if-flow-2 (result i32)
+  (if (result i32)
+   (i32.const 0)
+   (unreachable)
+   (i32.const 2)
+  )
+ )
+ (func $if-flow-3 (result i32)
+  (if (result i32)
+   (i32.const 0)
+   (i32.const 1)
+   (unreachable)
+  )
+ )
+ (func $if-flow-4 (result i32)
+  (if
+   (return
+    (i32.const 0)
+   )
+   (return
+    (i32.const 1)
+   )
+   (return
+    (i32.const 2)
+   )
+  )
+ )
+ (func $iff-flow-fuzz-bug (result i32)
+  (loop $label$1
+   (br_if $label$1
+    (i32.eqz
+     (i32.const 1)
+    )
+   )
+   (loop $label$2
+    (unreachable)
+    (if
+     (i32.const 0)
+     (nop)
+     (return
+      (i32.const 0)
+     )
+    )
+   )
+  )
+ )
+ (func $fuzz-block-unreachable-brs-with-values (result i32)
+  (local $0 i32)
+  (loop $label$1
+   (if
+    (local.get $0)
+    (block $label$2
+     (local.tee $0
+      (loop $label$5
+       (br_if $label$5
+        (block
+         (unreachable)
+         (drop
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+    )
+    (br $label$1)
+   )
+  )
+ )
+ (func $drop-restructure-if (param $x i32) (param $y i32) (result i32)
+  (if (result i32)
+   (local.get $y)
+   (local.get $x)
+   (block $label$2 (result i32)
+    (nop)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $drop-restructure-if-final (param $x i32) (param $y i32) (result i32)
+  (if (result i32)
+   (local.get $y)
+   (local.get $x)
+   (block $label$2 (result i32)
+    (nop)
+    (unreachable)
+   )
+  )
+ )
+ (func $drop-restructure-if-middle (param $x i32) (param $y i32) (result i32)
+  (if (result i32)
+   (local.get $y)
+   (local.get $x)
+   (block $label$2 (result i32)
+    (nop)
+    (nop)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $drop-restructure-if-bad (param $x i32) (param $y i32) (result i32)
+  (block $label$2 (result i32)
+   (drop
+    (br_if $label$2
+     (local.tee $y
+      (local.get $x)
+     )
+     (local.get $y)
+    )
+   )
+   (i32.const 0)
+  )
+ )
+ (func $drop-restructure-if-bad-2 (param $x i32) (param $y i32) (result i32)
+  (block $label$2 (result i32)
+   (drop
+    (br_if $label$2
+     (local.get $y)
+     (local.tee $y
+      (local.get $x)
+     )
+    )
+   )
+   (i32.const 0)
+  )
+ )
+ (func $if-block
+  (if
+   (i32.const 1)
+   (block $label
+    (block $block
+     (drop
+      (i32.const 2)
+     )
+     (drop
+      (i32.const 3)
+     )
+    )
+   )
+  )
+ )
+ (func $if-block-bad
+  (block $label
+   (if
+    (br $label)
+    (block $block
+     (drop
+      (i32.const 2)
+     )
+     (drop
+      (i32.const 3)
+     )
+    )
+   )
+  )
+ )
+ (func $if-block-br
+  (block $label
+   (br_if $label
+    (i32.const 1)
+   )
+  )
+ )
+ (func $if-block-br-1
+  (if
+   (i32.const 1)
+   (block $label
+   )
+   (drop
+    (i32.const 3)
+   )
+  )
+ )
+ (func $if-block-br-2
+  (if
+   (i32.const 1)
+   (block $label
+    (drop
+     (i32.const 3)
+    )
+   )
+   (nop)
+  )
+ )
+ (func $if-block-br-3
+  (if
+   (i32.const 1)
+   (block $label
+   )
+   (nop)
+  )
+ )
+ (func $if-block-br-4-eithre
+  (if
+   (i32.const 1)
+   (block $label
+    (drop
+     (i32.const 2)
+    )
+   )
+   (drop
+    (i32.const 3)
+   )
+  )
+ )
+ (func $if-block-br-5-value (result i32)
+  (select
+   (block $label (result i32)
+    (i32.const 2)
+   )
+   (i32.const 3)
+   (i32.const 1)
+  )
+ )
+ (func $restructure-if-outerType-change
+  (loop $label$1
+   (br_if $label$1
+    (block $label$2
+     (if
+      (block $label$4
+       (unreachable)
+      )
+      (block $label$3
+       (br $label$3)
+      )
+     )
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $if-arm-unreachable
+  (if
+   (unreachable)
+   (block $label$1
+    (nop)
+   )
+   (unreachable)
+  )
+ )
+ (func $propagate-type-if-we-optimize
+  (if
+   (i32.const 1)
+   (nop)
+   (block $block
+    (drop
+     (loop $label$3 (result i64)
+      (br_if $label$3
+       (if
+        (i32.const 0)
+        (block $label$4
+         (unreachable)
+        )
+        (unreachable)
+       )
+      )
+      (i64.const -9)
+     )
+    )
+    (unreachable)
+   )
+  )
+ )
+ (func $switch-to-br
+  (block $A
+   (block $y
+    (block
+     (drop
+      (i32.const 0)
+     )
+     (br $A)
+    )
+   )
+  )
+ )
+ (func $switch-to-br-value (result i32)
+  (block $A (result i32)
+   (block $y (result i32)
+    (block
+     (drop
+      (i32.const 1)
+     )
+     (br $A
+      (i32.const 0)
+     )
+    )
+   )
+  )
+ )
+ (func $switch-threading-multi (param $x i32) (param $y i32) (result i32)
+  (block $block$5$break
+   (block $block$4$break
+    (loop $shape$1$continue
+     (block $block$3$break
+      (block $switch$2$case$5
+       (block $switch$2$case$4
+        (block $switch$2$default
+         (block $switch$2$case$2
+          (br_table $shape$1$continue $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$5$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$3$break $block$4$break $block$3$break
+           (local.get $x)
+          )
+         )
+         (br $shape$1$continue)
+        )
+        (br $block$3$break)
+       )
+       (br $block$4$break)
+      )
+      (br $block$5$break)
+     )
+    )
+    (unreachable)
+   )
+   (local.set $y
+    (i32.const 1)
+   )
+   (unreachable)
+  )
+  (local.set $y
+   (i32.const 2)
+  )
+  (unreachable)
+ )
+ (func $fuzz-type-changes-in-our-cycles (result i32)
+  (loop $label$1
+   (if
+    (i32.const 0)
+    (if
+     (i32.const 0)
+     (block $label$3
+      (block $block
+      )
+     )
+     (return
+      (i32.const -8192)
+     )
+    )
+   )
+   (br $label$1)
+  )
+ )
+ (func $refinalize-need-br-value (result i32)
+  (loop $label$3 (result i32)
+   (block $label$6 (result i32)
+    (block $label$10
+     (unreachable)
+     (block $label$503
+      (br_if $label$3
+       (block $label$530 (result i32)
+        (br_if $label$503
+         (i32.const 0)
+        )
+        (i32.const 0)
+       )
+      )
+      (return
+       (i32.const 127)
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $selectify (param $x i32)
+  (drop
+   (if (result i32)
+    (i32.eq
+     (local.get $x)
+     (i32.const 1)
+    )
+    (i32.mul
+     (i32.const 2)
+     (i32.const 3)
+    )
+    (i32.mul
+     (i32.const 2)
+     (i32.const 3)
+    )
+   )
+  )
+  (drop
+   (select
+    (i32.add
+     (i32.const 2)
+     (i32.const 3)
+    )
+    (i32.add
+     (i32.const 2)
+     (i32.const 3)
+    )
+    (i32.eq
+     (local.get $x)
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $if-one-side (result i32)
+  (local $x i32)
+  (local.set $x
+   (select
+    (i32.const 2)
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (local.get $x)
+ )
+ (func $if-one-side-b (result i32)
+  (local $x i32)
+  (local.set $x
+   (select
+    (local.get $x)
+    (i32.const 2)
+    (i32.const 1)
+   )
+  )
+  (local.get $x)
+ )
+ (func $if-one-side-tee-etc (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (drop
+   (call $if-one-side-tee-etc
+    (local.tee $x
+     (select
+      (i32.const -4)
+      (local.get $x)
+      (i32.const -3)
+     )
+    )
+   )
+  )
+  (i32.const 0)
+ )
+ (func $ifs-copies-recursive (param $20 i32) (result i32)
+  (if
+   (i32.const 1)
+   (local.set $20
+    (select
+     (select
+      (i32.const 4)
+      (local.get $20)
+      (i32.const 3)
+     )
+     (local.get $20)
+     (i32.const 2)
+    )
+   )
+  )
+  (local.get $20)
+ )
+ (func $if-copy1
+  (local $x i32)
+  (local $y i32)
+  (loop $top
+   (local.set $x
+    (select
+     (local.get $x)
+     (local.get $y)
+     (i32.const 1)
+    )
+   )
+   (br $top)
+  )
+ )
+ (func $if-copy3
+  (local $x i32)
+  (local $y i32)
+  (loop $top
+   (if
+    (i32.const 1)
+    (local.tee $x
+     (unreachable)
+    )
+   )
+   (br $top)
+  )
+ )
+ (func $if-copy4
+  (local $x i32)
+  (local $y i32)
+  (loop $top
+   (local.set $x
+    (if (result i32)
+     (i32.const 1)
+     (unreachable)
+     (local.get $y)
+    )
+   )
+   (br $top)
+  )
+ )
+ (func $if-copy-tee
+  (local $x i32)
+  (local $y i32)
+  (loop $top
+   (drop
+    (local.tee $x
+     (select
+      (local.get $x)
+      (i32.const 2)
+      (i32.const 1)
+     )
+    )
+   )
+   (br $top)
+  )
+ )
+ (func $loop-end-set (param $x i32) (result i32)
+  (loop $loop
+   (nop)
+   (br_if $loop
+    (local.get $x)
+   )
+   (local.set $x
+    (i32.const 1)
+   )
+  )
+  (local.get $x)
+ )
+ (func $loop-end-value (param $x i32) (result i32)
+  (loop $loop (result i32)
+   (nop)
+   (br_if $loop
+    (local.get $x)
+   )
+   (i32.const 1)
+  )
+ )
+ (func $do-not-flow-values-through-unreachable-code (result i32)
+  (block $block
+   (unreachable)
+   (if
+    (i32.const 0)
+    (block $A
+     (return
+      (i32.const 0)
+     )
+    )
+    (nop)
+   )
+  )
+ )
+ (func $do-not-flow-values-through-unreachable-code-b (result i32)
+  (loop $loop-in
+   (unreachable)
+   (if
+    (i32.const 0)
+    (block $A
+     (return
+      (i32.const 0)
+     )
+    )
+    (nop)
+   )
+  )
+ )
+ (func $if_br_if
+  (local $0 i32)
+  (block $label$1
+   (br_if $label$1
+    (select
+     (local.tee $0
+      (i32.const 1024)
+     )
+     (i32.const 0)
+     (i32.eqz
+      (i32.const -4)
+     )
+    )
+   )
+   (br_if $label$1
+    (select
+     (i32.const 1025)
+     (i32.const 0)
+     (i32.eqz
+      (i32.const -5)
+     )
+    )
+   )
+   (br_if $label$1
+    (select
+     (local.tee $0
+      (i32.const 1025)
+     )
+     (i32.const 0)
+     (i32.eqz
+      (i32.const -6)
+     )
+    )
+   )
+   (if
+    (i32.const 1026)
+    (br_if $label$1
+     (local.tee $0
+      (i32.const -7)
+     )
+    )
+   )
+   (i32.store
+    (i32.const 1024)
+    (i32.add
+     (local.get $0)
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $unswitch-reordering (param $x i32) (result i32)
+  (block $label$1 (result i32)
+   (br_table $label$1
+    (block $label$2 (result i32)
+     (i32.store
+      (i32.const 1)
+      (i32.const 2)
+     )
+     (i32.const 3)
+    )
+    (block $block (result i32)
+     (if
+      (local.get $x)
+      (return
+       (i32.const 5)
+      )
+     )
+     (i32.const 6)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/remove-unused-brs_enable-multivalue.wast b/binaryen/test/passes/remove-unused-brs_enable-multivalue.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-brs_enable-multivalue.wast
@@ -0,0 +1,2131 @@
+(module
+  (memory 256 256)
+  (type $0 (func (param i32)))
+  (type $1 (func))
+  (type $2 (func (result i32)))
+  (func $b0-yes (type $0) (param $i1 i32)
+    (block $topmost
+      (br $topmost)
+    )
+  )
+  (func $b1 (type $0) (param $i1 i32)
+    (block $topmost
+      (block
+        (drop
+          (i32.const 0)
+        )
+        (br $topmost)
+      )
+    )
+  )
+  (func $b2 (type $0) (param $i1 i32)
+    (block $topmost
+      (block $inner
+        (br $topmost)
+      )
+    )
+  )
+  (func $b3-yes (type $0) (param $i1 i32)
+    (block $topmost
+      (block $inner
+        (br $inner)
+      )
+    )
+  )
+  (func $b4 (type $0) (param $i1 i32)
+    (block $topmost
+      (block $inner
+        (block
+          (drop
+            (i32.const 0)
+          )
+          (br $topmost)
+        )
+      )
+    )
+  )
+  (func $b5 (type $0) (param $i1 i32)
+    (block $topmost
+      (block $inner
+        (block
+          (drop
+            (i32.const 0)
+          )
+          (br $inner)
+        )
+      )
+    )
+  )
+  (func $b6 (type $0) (param $i1 i32)
+    (block $topmost
+      (br_if $topmost
+        (i32.const 1)
+      )
+    )
+  )
+  (func $b7 (type $0) (param $i1 i32)
+    (block $topmost
+      (block
+        (drop
+          (i32.const 0)
+        )
+        (br_if $topmost
+          (i32.const 1)
+        )
+      )
+    )
+  )
+  (func $b8 (type $0) (param $i1 i32)
+    (block $topmost
+      (block $inner
+        (br_if $topmost
+          (i32.const 1)
+        )
+      )
+    )
+  )
+  (func $b9 (type $0) (param $i1 i32)
+    (block $topmost
+      (block $inner
+        (br_if $topmost
+          (i32.const 1)
+        )
+      )
+    )
+  )
+  (func $b10 (type $0) (param $i1 i32)
+    (block $topmost
+      (block $inner
+        (block
+          (drop
+            (i32.const 0)
+          )
+          (br_if $topmost
+            (i32.const 1)
+          )
+        )
+      )
+    )
+  )
+  (func $b11 (type $0) (param $i1 i32)
+    (block $topmost
+      (block $inner
+        (block
+          (drop
+            (i32.const 0)
+          )
+          (br_if $inner
+            (i32.const 1)
+          )
+        )
+      )
+    )
+  )
+  (func $b12-yes (type $1)
+    (block $topmost
+      (if
+        (i32.const 1)
+        (block $block1
+          (drop
+            (i32.const 12)
+          )
+          (block
+            (drop
+              (i32.const 1)
+            )
+            (br $topmost)
+          )
+        )
+        (block $block3
+          (drop
+            (i32.const 27)
+          )
+          (block
+            (drop
+              (i32.const 2)
+            )
+            (br $topmost)
+          )
+        )
+      )
+    )
+  )
+  (func $b13 (type $2) (result i32)
+    (block $topmost (result i32)
+      (if
+        (i32.const 1)
+        (block $block1
+          (drop
+            (i32.const 12)
+          )
+          (drop
+            (br_if $topmost
+              (i32.const 1)
+              (i32.const 1)
+            )
+          )
+        )
+        (block $block3
+          (drop
+            (i32.const 27)
+          )
+          (br $topmost
+            (i32.const 2)
+          )
+        )
+      )
+      (i32.const 3)
+    )
+  )
+  (func $b14 (type $2) (result i32)
+    (block $topmost (result i32)
+      (if (result i32)
+        (i32.const 1)
+        (block $block1 (result i32)
+          (i32.const 12)
+        )
+        (block $block3 (result i32)
+          (i32.const 27)
+        )
+      )
+    )
+  )
+  (func $b14-tuple (result i32 i64)
+    (block $topmost (result i32 i64)
+      (if (result i32 i64)
+        (i32.const 1)
+        (block $block1 (result i32 i64)
+          (tuple.make
+            (i32.const 12)
+            (i64.const 12)
+          )
+        )
+        (block $block3 (result i32 i64)
+          (tuple.make
+            (i32.const 27)
+            (i64.const 27)
+          )
+        )
+      )
+    )
+  )
+  (func $b15 (type $1)
+    (block $topmost
+      (if
+        (i32.const 17)
+        (br $topmost)
+      )
+    )
+  )
+  (func $b15b (type $1)
+    (block $topmost
+      (if
+        (i32.const 18)
+        (block
+          (drop
+            (i32.const 0)
+          )
+          (br $topmost)
+        )
+      )
+    )
+  )
+  (func $b16 (type $1)
+    (block $a
+      (block $b
+        (block $c
+          (br $a)
+        )
+        (br $a)
+      )
+      (br $a)
+    )
+    (block $a
+      (block $b
+        (block $c
+          (br $c)
+        )
+        (br $b)
+      )
+      (br $a)
+    )
+    (block $a
+      (block $b
+        (block $c
+          (br $b)
+        )
+        (br $a)
+      )
+      (br $a)
+    )
+  )
+  (func $b17 (type $1)
+    (block $a
+      (if
+        (i32.const 0)
+        (block $block1
+          (br $a)
+        )
+        (block $block3
+          (br $a)
+        )
+      )
+    )
+    (block $a
+      (if
+        (i32.const 0)
+        (drop
+          (i32.const 1)
+        )
+        (block $block6
+          (br $a)
+        )
+      )
+    )
+    (block $a
+      (if
+        (i32.const 0)
+        (block $block8
+          (br $a)
+        )
+        (drop
+          (i32.const 1)
+        )
+      )
+    )
+    (block $c
+      (block $b
+        (if
+          (i32.const 0)
+          (block $block11
+            (br $b)
+          )
+          (block $block13
+            (br $c)
+          )
+        )
+      )
+    )
+  )
+  (func $ret-1 (type $1)
+    (return)
+  )
+  (func $ret-2 (type $1)
+    (block $block0
+      (block $block1
+        (return)
+      )
+    )
+  )
+  (func $ret-3 (type $1)
+    (block $block0
+      (if
+        (i32.const 0)
+        (return)
+        (block $block3
+          (return)
+        )
+      )
+    )
+  )
+  (func $ret-value (type $2) (result i32)
+    (block $block0
+      (block $block1
+        (return
+          (i32.const 1)
+        )
+      )
+    )
+  )
+  (func $no-select-but-the-last (type $1)
+    (block $a
+      (if
+        (i32.const 0)
+        (drop
+          (i32.const 1)
+        )
+        (block $block2
+          (block
+            (drop
+              (i32.const 2)
+            )
+            (br $a)
+          )
+          (drop
+            (i32.const 3)
+          )
+        )
+      )
+      (if
+        (i32.const 0)
+        (block $block4
+          (block
+            (drop
+              (i32.const 2)
+            )
+            (br $a)
+          )
+          (drop
+            (i32.const 3)
+          )
+        )
+        (drop
+          (i32.const 1)
+        )
+      )
+      (if
+        (block $block6 (result i32)
+          (block
+            (drop
+              (i32.const 2)
+            )
+            (br $a)
+          )
+          (i32.const 3)
+        )
+        (drop
+          (i32.const 0)
+        )
+        (drop
+          (i32.const 1)
+        )
+      )
+      (if
+        (block $a (result i32)
+          (br $a
+            (i32.const 0)
+          )
+        )
+        (block $a
+          (block
+            (drop
+              (i32.const 1)
+            )
+            (br $a)
+          )
+        )
+        (block $a
+          (block
+            (drop
+              (i32.const 2)
+            )
+            (br $a)
+          )
+        )
+      )
+    )
+  )
+  (func $side-effects-and-order (type $2) (result i32)
+    (local $x i32)
+    (block $do-once$0
+      (if
+        (call $b13)
+        (block
+          (drop
+            (i32.const 0)
+          )
+          (br $do-once$0)
+        )
+      )
+      (drop
+        (i32.const 1)
+      )
+    )
+    (block $do-once$0
+      (if
+        (call $b13)
+        (block
+          (drop
+            (call $b14)
+          )
+          (br $do-once$0)
+        )
+      )
+      (drop
+        (i32.const 1)
+      )
+    )
+    (block $do-once$0
+      (if
+        (i32.const 0)
+        (block
+          (drop
+            (call $b14)
+          )
+          (br $do-once$0)
+        )
+      )
+      (drop
+        (i32.const 1)
+      )
+    )
+    (block $do-once$0 (result i32)
+      (if
+        (local.tee $x
+          (i32.const 1)
+        )
+        (br $do-once$0
+          (local.tee $x
+            (i32.const 2)
+          )
+        )
+      )
+      (i32.const 1)
+    )
+  )
+  (func $loops
+    (loop $in
+      (block $out
+        (if (i32.const 0) (br $out))
+        (br $in) ;; we can conditionalize this, and then the br out can vanish
+      )
+    )
+    (loop $in
+      (br $in)
+    )
+    (loop
+      (block $out
+        (if (i32.const 0) (br $out))
+        (br $out)
+      )
+    )
+    (loop $in
+      (block $out
+        (if (i32.const 0) (br $out))
+        (br $out)
+      )
+    )
+    (loop $in)
+    (loop $in
+      (block $out)
+    )
+    (loop $in
+      (block $out
+        (if (i32.const 0) (br $out))
+        (br_if $in (i32.const 1))
+      )
+    )
+    (loop $in
+      (block $out
+        (if (i32.const 0) (br $in))
+        (br $out)
+      )
+    )
+    (loop $in
+      (block $out
+        (if (i32.const 0) (unreachable))
+        (br $in)
+      )
+    )
+    (loop $in
+      (block $out
+        (if (i32.const 0)
+          (block
+            (call $loops)
+            (br $out)
+          )
+        )
+        (br $in)
+      )
+    )
+    (loop $in-todo ;; br_if into if
+      (block $out-todo
+        (if (i32.const 0) (br $out-todo))
+        (call $loops)
+        (br $in-todo)
+      )
+    )
+    (loop $in
+      (block $out
+        (if (i32.const 0)
+          (br $out)
+          (call $loops)
+        )
+        (br $in)
+      )
+    )
+    (loop $in
+      (block $out
+        (if (i32.const 0)
+          (call $loops)
+          (br $out)
+        )
+        (br $in)
+      )
+    )
+    (loop $in
+      (block $out
+        (if (i32.const 0)
+          (block
+            (drop (i32.const 1))
+            (call $loops)
+          )
+          (br $out)
+        )
+        (br $in)
+      )
+    )
+    (loop $in
+      (block $out
+        (if (i32.const 0)
+          (br $out)
+          (call $loops)
+        )
+        (drop (i32.const 100))
+        (br $in)
+      )
+    )
+    (loop $in
+      (block $out
+        (if (i32.const 0)
+          (call $loops)
+          (br $out)
+        )
+        (drop (i32.const 101))
+        (br $in)
+      )
+    )
+    (loop $in
+      (block $out
+        (if (i32.const 0)
+          (block
+            (drop (i32.const 1))
+            (call $loops)
+          )
+          (br $out)
+        )
+        (drop (i32.const 102))
+        (br $in)
+      )
+    )
+    (loop $in
+      (block $out
+        (if (i32.const 0)
+          (br $out)
+          (call $loops)
+        )
+        (return)
+        (br $in)
+      )
+    )
+    (loop $in
+      (block $out
+        (if (i32.const 0)
+          (br $out)
+          (call $loops)
+        )
+        (br $out)
+        (br $in)
+      )
+    )
+    (loop $in
+      (block $out
+        (if (i32.const 0)
+          (br $out)
+          (call $loops)
+        )
+        (drop
+          (block $out2 (result i32)
+            (br $out2 (i32.const 1))
+          )
+        )
+        (br $in)
+      )
+    )
+    (loop $in
+      (block $out
+        (br_if $out (i32.const 0))
+        (br $in)
+      )
+    )
+    (loop $in-todo2 ;; if-ify
+      (block $out-todo2
+        (br_if $out-todo2 (i32.const 0))
+        (call $loops)
+        (br $in-todo2)
+      )
+    )
+    (loop $in
+      (block $out
+        (br $out)
+        (br $in)
+      )
+    )
+    (loop $in
+      (block $out
+        (br_if $in (i32.const 0))
+        (br $in)
+      )
+    )
+    (loop $in-not ;; do NOT if-ify, the block can't be removed
+      (block $out-not
+        (br_if $out-not (i32.const -1))
+        (br_if $out-not (i32.const 0))
+        (call $loops)
+        (br $in-not)
+      )
+    )
+    (loop $in-todo2 ;; if-ify a slice with 2 things
+      (block $out-todo2
+        (br_if $out-todo2 (i32.const 0))
+        (call $loops)
+        (drop (i32.const 1))
+        (br $in-todo2)
+      )
+    )
+  )
+  (func $br_if_in_block (result i32)
+    (block $outval (result i32)
+      (block $in
+        (if (i32.const 1) (br $in) (br $in))
+        (drop (i32.const 2))
+        (if (i32.const 3) (unreachable) (br $in))
+        (drop (i32.const 4))
+        (if (i32.const 5) (br $in) (unreachable))
+        (drop (i32.const 6))
+      )
+      (if (result i32) (i32.const 6) (br $outval (i32.const 7)) (i32.const 8))
+    )
+  )
+  (func $threading
+    (drop
+      (block $value-out (result i32)
+        (block $value-in (result i32)
+          (block $out
+            (block $in
+              (if (i32.const 1)
+                (br $in)
+              )
+              (br_if $in (i32.const 2))
+              (br $value-in (i32.const 3))
+            )
+            (br $out)
+          )
+          (i32.const 4)
+        )
+      )
+    )
+    (block $stack1
+      (block $stack2
+        (block $stack3
+          (block $stack4
+            (if (i32.const 1)
+              (br $stack4)
+            )
+            (unreachable)
+          )
+          (br $stack3)
+        )
+        (br $stack2)
+      )
+      (br $stack1)
+    )
+  )
+  (func $if-to-br_if-conflict (param $x i32) (param $y i32) (result i32)
+    (block $leave
+      (local.set $y
+        (block $out (result i32)
+          (if
+            (local.get $x)
+            (br $out
+              (block (result i32)
+                (local.set $x (i32.const 0))
+                (i32.const 1)
+              )
+            )
+            (br_if $leave (i32.const 1))
+          )
+          (unreachable)
+        )
+      )
+    )
+    (i32.add (local.get $x) (local.get $y))
+  )
+  (func $if-to-br_if-conflict2 (param $x i32) (param $y i32) (result i32)
+    (block $leave
+      (local.set $y
+        (block $out (result i32)
+          (if
+            (local.get $x)
+            (br_if $leave (i32.const 1))
+            (br $out
+              (block (result i32)
+                (local.set $x (i32.const 0))
+                (i32.const 1)
+              )
+            )
+          )
+          (unreachable)
+        )
+      )
+    )
+    (i32.add (local.get $x) (local.get $y))
+  )
+  (func $if-to-br_if-value-sideeffect (param $x i32) (param $y i32) (result i32)
+    (block $leave
+      (local.set $y
+        (block $out (result i32)
+          (if
+            (local.get $x)
+            (br $out
+              (block (result i32)
+                (drop (call $if-to-br_if-value-sideeffect (i32.const 0) (i32.const 1)))
+                (nop)
+                (i32.const 1)
+              )
+            )
+          )
+          (unreachable)
+        )
+      )
+    )
+    (i32.add (local.get $x) (local.get $y))
+  )
+  (func $fuzz (param $j i32) (param $g i32)
+    (block $label$break$c
+      (loop $label$continue$d
+        (block $label$break$d
+          (if
+            (i32.lt_s
+              (local.get $j)
+              (i32.const 2147483640)
+            )
+            (block $x
+              (block $y
+                (block $z
+                  (br_if $y
+                    (local.get $j)
+                  )
+                  (br $x) ;; don't be confused by this
+                )
+                (nop) ;; get me to the store!
+              )
+            )
+            (block $switch$26
+              (nop)
+            )
+          )
+          (i32.store
+            (i32.const 5724)
+            (i32.const -254899267)
+          )
+          (br $label$continue$d)
+        )
+      )
+    )
+  )
+  (func $iffify
+    (block $yes
+      (br_if $yes
+        (i32.const 0)
+      )
+      (drop (i32.const 1))
+      (drop (i32.const 2))
+    )
+    (block $no
+      (br_if $no
+        (i32.const 0)
+      )
+      (drop (i32.const 1))
+      (br $no)
+      (drop (i32.const 2))
+    )
+    (block $no2
+      (br_if $no2
+        (i32.const 0)
+      )
+    )
+    (block $no3
+      (br $no3)
+      (drop (i32.const 1))
+      (drop (i32.const 2))
+    )
+    (block $no5
+      (block $no4
+        (br_if $no5
+          (i32.const 0)
+        )
+        (drop (i32.const 1))
+        (drop (i32.const 2))
+      )
+    )
+  )
+  (func $loop-if (result i32)
+    (block $outer (result i32)
+      (loop $typed (result i32)
+        ;; we can move the br after us into our if-else, which means we are the final
+        ;; element in the block,
+        (if
+          (i32.const 2)
+          (block
+            (drop (call $loop-if))
+            (br $outer (i32.const 0))
+          )
+        )
+        (br $typed)
+      )
+    )
+  )
+  (func $block-break (param $0 i32)
+    (block $block$7$break
+      (block $shape$6$continue
+        (call $block-break (i32.const 1))
+        (br $block$7$break)
+      )
+    )
+  )
+  (func $loop-break (param $0 i32)
+    (block $block$7$break
+      (loop $shape$6$continue
+        (call $loop-break (i32.const 1))
+        (br_if $shape$6$continue
+          (local.get $0)
+        )
+        (br $block$7$break)
+      )
+    )
+  )
+  (func $untaken-brs-might-prevent-block-removal (param $0 f32) (param $1 i32) (param $2 f32) (param $3 i32) (param $4 i32) (param $5 f64) (param $6 f32) (result i32)
+   (block $label$0 (result i32)
+    (block $label$1 ;; this block has no taken brs, but we can't remove it without removing them first
+     (br_if $label$1
+      (i32.const 607395945)
+     )
+     (br_if $label$1
+      (i32.load16_s offset=3 align=1
+       (select
+        (call $untaken-brs-might-prevent-block-removal
+         (f32.const 1.4904844647389837e-07)
+         (br_if $label$0
+          (i32.store16 offset=4 align=1
+           (i32.const 1900641)
+           (br $label$0
+            (i32.const 1628075109)
+           )
+          )
+          (i32.const 1764950569)
+         )
+         (f32.const 1.1910939690100655e-32)
+         (i32.const 1628057906)
+         (i32.const 859068982)
+         (f64.const 2.524518840347722e-258)
+         (f32.const -nan:0x40a63)
+        )
+        (i32.const 688529440)
+        (i32.const 1751478890)
+       )
+      )
+     )
+    )
+    (i32.const 1935947830)
+   )
+  )
+  (func $unexitable-loops-result (param $0 i32) (result i64)
+   (loop $label$0
+    (loop $label$1
+     (if
+      (i32.load8_s
+       (i32.const 201460482)
+      )
+      (br $label$0)
+      (block $label$3
+       (br_if $label$3
+        (local.get $0)
+       )
+      )
+     )
+     (br $label$1)
+    )
+   )
+  )
+  (func $untaken-br-with-concrete-last-element
+   (block $label$8
+    (block $label$11
+     (block $label$14
+      (br_if $label$14
+       (br $label$11
+       )
+      )
+     )
+    )
+   )
+  )
+  (func $untaken-br-with-concrete-last-element2 (result i32)
+   (block $label$8 (result i32)
+    (block $label$11 (result i32)
+     (block $label$14 (result i32)
+      (br_if $label$14
+       (i32.const 102)
+       (br $label$11
+        (i32.const 103)
+       )
+      )
+     )
+    )
+   )
+  )
+  (func $untaken-br_if-then-if
+   (block $label$0
+    (br_if $label$0
+     (unreachable)
+    )
+    (if
+     (i32.const 0)
+     (nop)
+    )
+   )
+  )
+  (func $unreachable-if-that-could-be-a-br_if (result i64)
+   (loop $label$3 (result i64)
+    (drop
+     (if (result f64)
+      (unreachable)
+      (f64.const 1)
+      (br $label$3)
+     )
+    )
+    (i64.const 1)
+   )
+  )
+  (func $nop-br-might-update-type
+   (block $label$39
+    (drop
+     (if (result i32)
+      (unreachable)
+      (if (result i32)
+       (i32.const 1)
+       (br $label$39) ;; if we nop this, then the parent type must change
+       (i32.const 0)
+      )
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (func $no-flow-through-if-without-else (result f32)
+   (local $0 i32)
+   (local $2 f32)
+   (block $label$0
+    (if
+     (local.get $0)
+     (block $label$11
+      (return
+       (f32.const 239)
+      )
+      (if
+       (i32.const 0)
+       (return
+        (local.get $2)
+       )
+      )
+     )
+     (return
+      (f32.const -9223372036854775808)
+     )
+    )
+   )
+  )
+  (func $unreachable-return-loop-value (result i64)
+   (loop $loop
+    (if
+     (i32.const 1)
+     (block $block
+      (br_if $block
+       (br $loop)
+      )
+      (br $loop)
+     )
+    )
+    (br $loop) ;; we 100% go back to the loop top, the loop is never exited. but opts move code around so that is not obvious anymore, and the loop becomes a nop, but the func has a return value
+   )
+  )
+  (func $obviously-flows-out-maybe (param $var$0 i32) (result f32)
+   (block $label$1 (result f32)
+    (br $label$1
+     (f32.const 1)
+    )
+    (loop $label$5
+     (if
+      (i32.const 11)
+      (block $label$8  ;; this block is none - it has a break, even if not taken - and so looks like it might flow out,
+       (br_if $label$8 ;; and so we can't move it outside to be the end of the loop's block
+        (unreachable)
+       )
+       (br $label$5)
+      )
+     )
+     (br $label$5)
+    )
+   )
+  )
+  (func $br-to-table (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $x (i32.eq (local.get $a) (i32.const 0)))
+          (br_if $y (i32.eq (local.get $a) (i32.const 1)))
+          (br_if $z (i32.eq (local.get $a) (i32.const 2)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $br-to-table-too-few (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $x (i32.eq (local.get $a) (i32.const 0)))
+          (br_if $y (i32.eq (local.get $a) (i32.const 1)))
+        )
+      )
+    )
+  )
+  (func $br-to-table-one-more (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $x (i32.eq (local.get $a) (i32.const 0)))
+          (br_if $y (i32.eq (local.get $a) (i32.const 1)))
+          (br_if $z (i32.eq (local.get $a) (i32.const 2)))
+          (br_if $x (i32.eq (local.get $a) (i32.const 3)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $br-to-table-overlap (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $x (i32.eq (local.get $a) (i32.const 0)))
+          (br_if $y (i32.eq (local.get $a) (i32.const 1)))
+          (br_if $z (i32.eq (local.get $a) (i32.const 1)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $br-to-table-overlap-start (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $x (i32.eq (local.get $a) (i32.const 0)))
+          (br_if $y (i32.eq (local.get $a) (i32.const 0)))
+          (br_if $z (i32.eq (local.get $a) (i32.const 1)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $br-to-table-offset (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $x (i32.eq (local.get $a) (i32.const 15)))
+          (br_if $y (i32.eq (local.get $a) (i32.const 16)))
+          (br_if $z (i32.eq (local.get $a) (i32.const 17)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $br-to-table-RANGE-high (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $x (i32.eq (local.get $a) (i32.const 0)))
+          (br_if $y (i32.eq (local.get $a) (i32.const 1)))
+          (br_if $z (i32.eq (local.get $a) (i32.const 10)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $br-to-table-RANGE-low (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $x (i32.eq (local.get $a) (i32.const 0)))
+          (br_if $y (i32.eq (local.get $a) (i32.const 3)))
+          (br_if $z (i32.eq (local.get $a) (i32.const 9)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $br-to-table-bad (param $a i32) (result i32)
+    (block $value (result i32)
+      (block $x
+        (block $y
+          (block $z
+            (nop)
+            (br $x)
+            (br_if $x (i32.eq (local.get $a) (i32.const 0)))
+            (br_if $y (i32.eq (local.get $a) (i32.const 1)))
+            (br_if $z (i32.eq (local.get $a) (i32.const 2)))
+            (unreachable)
+          )
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (i32.const 2000)
+    )
+  )
+  (func $br-to-table-bad2 (param $a i32) (result i32)
+    (block $value (result i32)
+      (block $x
+        (block $y
+          (block $z
+            (nop)
+            (drop (br_if $value (i32.const 1000) (i32.eq (local.get $a) (i32.const 0))))
+            (br_if $x (i32.eq (local.get $a) (i32.const 0)))
+            (br_if $y (i32.eq (local.get $a) (i32.const 1)))
+            (br_if $z (i32.eq (local.get $a) (i32.const 2)))
+            (unreachable)
+          )
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (i32.const 2000)
+    )
+  )
+  (func $br-to-table-bad3 (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $x (i32.eq (i32.const 10) (i32.const 0)))
+          (br_if $x (i32.eq (local.get $a) (i32.const 0)))
+          (br_if $y (i32.eq (local.get $a) (i32.const 1)))
+          (br_if $z (i32.eq (local.get $a) (i32.const 2)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $br-to-table-multi (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $z (i32.eq (i32.const 10) (i32.const 5)))
+          (br_if $y (i32.eq (i32.const 10) (i32.const 6)))
+          (br_if $x (i32.eq (i32.const 10) (i32.const 7)))
+          (br_if $x (i32.eq (local.get $a) (i32.const 0)))
+          (br_if $y (i32.eq (local.get $a) (i32.const 1)))
+          (br_if $z (i32.eq (local.get $a) (i32.const 2)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $br-to-table-bad4 (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $x (i32.ne (local.get $a) (i32.const 0)))
+          (br_if $y (i32.eq (local.get $a) (i32.const 1)))
+          (br_if $z (i32.eq (local.get $a) (i32.const 2)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $br-to-table-bad5 (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $x (i32.eq (local.get $a) (local.get $a)))
+          (br_if $y (i32.eq (local.get $a) (local.get $a)))
+          (br_if $z (i32.eq (local.get $a) (local.get $a)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $br-to-table-bad6 (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $x (i32.eq (call $b13) (i32.const 0)))
+          (br_if $y (i32.eq (call $b13) (i32.const 1)))
+          (br_if $z (i32.eq (call $b13) (i32.const 2)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $br-to-table-bad7 (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $x (i32.eq (local.get $a) (i32.const -1))) ;; negative, we support only positive up to int32_max
+          (br_if $y (i32.eq (local.get $a) (i32.const -1)))
+          (br_if $z (i32.eq (local.get $a) (i32.const -1)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $br-to-table-defaultNameOverlaps (param $a i32)
+    (block $x
+      (block $tablify|0
+        (block $z
+          (br_if $x (i32.eq (local.get $a) (i32.const 0)))
+          (br_if $tablify|0 (i32.eq (local.get $a) (i32.const 1)))
+          (br_if $z (i32.eq (local.get $a) (i32.const 2)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $br-to-table-unreach (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $x (i32.eq (unreachable) (i32.const 0)))
+          (br_if $y (i32.eq (unreachable) (i32.const 1)))
+          (br_if $z (i32.eq (unreachable) (i32.const 2)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $br-to-table-overlap-but-later (param $a i32)
+    (block $x
+      (block $y
+        (block $z
+          (br_if $x (i32.eq (local.get $a) (i32.const 0)))
+          (br_if $y (i32.eq (local.get $a) (i32.const 1)))
+          (br_if $z (i32.eq (local.get $a) (i32.const 1)))
+          (br_if $x (i32.eq (local.get $a) (i32.const 2)))
+          (br_if $y (i32.eq (local.get $a) (i32.const 3)))
+          (unreachable)
+        )
+        (unreachable)
+      )
+      (unreachable)
+    )
+    (unreachable)
+  )
+  (func $tiny-switch
+    (block $x
+      (block $y
+        (br_table $x $y
+          (i32.const 0)
+        )
+      )
+    )
+    (block $z
+      (br_table $z
+        (i32.const 0)
+      )
+    )
+  )
+  (func $trim-switch
+    (block $A
+      (block $y
+        (br_table $y $y $A $y $A $y $A $y $y $y $y $y $y $y $y $y $y $y
+          (i32.const 0)
+        )
+      )
+      (call $trim-switch)
+    )
+  )
+  (func $same-target-br_if-and-br
+    (block $x
+      (br_if $x
+        (i32.const 0)
+      )
+      (br $x)
+      (unreachable)
+    )
+  )
+  (func $simple-switch (result i32)
+    (block $A
+      (block $B
+        (block $y
+          (br_table $A $y $y $y $y $y $A $y $y $y $y $A $y
+            (i32.const 0)
+          )
+          (return (i32.const 0))
+        )
+        (return (i32.const 1))
+      )
+      (return (i32.const 2))
+    )
+    (return (i32.const 3))
+  )
+  (func $simple-switch-2 (result i32)
+    (block $A
+      (block $B
+        (block $y
+          (br_table $A $y $y $y $y $y $y $y $y $y $y $y $A $y
+            (i32.const 0)
+          )
+          (return (i32.const 0))
+        )
+        (return (i32.const 1))
+      )
+      (return (i32.const 2))
+    )
+    (return (i32.const 3))
+  )
+  (func $simple-switch-3 (result i32)
+    (block $A
+      (block $B
+        (block $y
+          (br_table $A $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $B $y
+            (i32.const 0)
+          )
+          (return (i32.const 0))
+        )
+        (return (i32.const 1))
+      )
+      (return (i32.const 2))
+    )
+    (return (i32.const 3))
+  )
+  (func $simple-switch43 (result i32)
+    (block $A
+      (block $B
+        (block $y
+          (br_table $A $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $B $y
+            (i32.const 0)
+          )
+          (return (i32.const 0))
+        )
+        (return (i32.const 1))
+      )
+      (return (i32.const 2))
+    )
+    (return (i32.const 3))
+  )
+  (func $simple-switch-5 (result i32)
+    (block $A
+      (block $B
+        (block $y
+          (br_table $A $y $y $y $y $y $A $y $y $y $y $y $A $y
+            (i32.const 0)
+          )
+          (return (i32.const 0))
+        )
+        (return (i32.const 1))
+      )
+      (return (i32.const 2))
+    )
+    (return (i32.const 3))
+  )
+  (func $undo-if-return (param $p i32) (result i32)
+    (local $x i32)
+    (block $out
+      (local.set $x
+        (if (result i32)
+          (local.get $p)
+          (br $out)
+          (i32.const 1)
+        )
+      )
+      (local.set $x
+        (if (result i32)
+          (local.get $p)
+          (i32.const 2)
+          (br $out)
+        )
+      )
+      (local.set $x
+        (if (result i32)
+          (local.get $p)
+          (br $out)
+          (br $out)
+        )
+      )
+    )
+    (local.get $p)
+  )
+  (func $if-unreachable-but-declares-value (param $var$0 i32) (param $var$1 f64) (param $var$2 i32) (param $var$3 f64) (param $var$4 f32) (param $var$5 f32) (result i32)
+   (local $var$6 f64)
+   (if
+    (i32.const 0)
+    (drop
+     (loop $label$3 (result i64)
+      (block $label$4 (result i64)
+       (block $label$5
+        (block $label$6
+         (local.set $var$1
+          (if (result f64)
+           (unreachable)
+           (br $label$5)
+           (f64.const 1)
+          )
+         )
+        )
+        (nop)
+       )
+       (i64.const 1)
+      )
+     )
+    )
+   )
+   (i32.const 0)
+  )
+  (func $if-flow-1 (result i32)
+    (if
+      (i32.const 0)
+      (return (i32.const 1))
+      (return (i32.const 2))
+    )
+  )
+  (func $if-flow-2 (result i32)
+    (if
+      (i32.const 0)
+      (unreachable)
+      (return (i32.const 2))
+    )
+  )
+  (func $if-flow-3 (result i32)
+    (if
+      (i32.const 0)
+      (return (i32.const 1))
+      (unreachable)
+    )
+  )
+  (func $if-flow-4 (result i32)
+    (if
+      (return (i32.const 0))
+      (return (i32.const 1))
+      (return (i32.const 2))
+    )
+  )
+  (func $iff-flow-fuzz-bug (result i32)
+   (loop $label$1
+    (if
+     (i32.const 1)
+     (loop $label$2
+      (unreachable)
+      (if ;; a loop that is never reached at the end of a loop
+       (i32.const 0)
+       (nop)
+       (return
+        (i32.const 0)
+       )
+      )
+     )
+    )
+    (br $label$1)
+   )
+  )
+  (func $fuzz-block-unreachable-brs-with-values (result i32)
+   (local $0 i32)
+   (loop $label$1 (result i32)
+    (block $label$2 (result i32)
+     (if
+      (local.get $0)
+      (local.set $0
+       (loop $label$5
+        (br_if $label$5
+         (br_if $label$2
+          (unreachable)
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (br $label$1)
+    )
+   )
+  )
+  (func $drop-restructure-if (param $x i32) (param $y i32) (result i32)
+   (block $label$2 (result i32)
+    (drop
+     (br_if $label$2
+      (local.get $x)
+      (local.get $y)
+     )
+    )
+    (i32.const 0)
+   )
+  )
+  (func $drop-restructure-if-final (param $x i32) (param $y i32) (result i32)
+   (block $label$2 (result i32)
+    (drop
+     (br_if $label$2
+      (local.get $x)
+      (local.get $y)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (func $drop-restructure-if-middle (param $x i32) (param $y i32) (result i32)
+   (block $label$2 (result i32)
+    (drop
+     (br_if $label$2
+      (local.get $x)
+      (local.get $y)
+     )
+    )
+    (nop) ;; the middle
+    (i32.const 0)
+   )
+  )
+  (func $drop-restructure-if-bad (param $x i32) (param $y i32) (result i32)
+   (block $label$2 (result i32)
+    (drop
+     (br_if $label$2
+      (local.tee $y (local.get $x))
+      (local.get $y)
+     )
+    )
+    (i32.const 0)
+   )
+  )
+  (func $drop-restructure-if-bad-2 (param $x i32) (param $y i32) (result i32)
+   (block $label$2 (result i32)
+    (drop
+     (br_if $label$2
+      (local.get $y)
+      (local.tee $y (local.get $x))
+     )
+    )
+    (i32.const 0)
+   )
+  )
+  (func $if-block
+   (block $label
+    (if
+     (i32.const 1)
+     (block
+      (drop (i32.const 2))
+      (drop (i32.const 3))
+     )
+    )
+   )
+  )
+  (func $if-block-bad
+   (block $label
+    (if
+     (br $label) ;; use outside of arm
+     (block
+      (drop (i32.const 2))
+      (drop (i32.const 3))
+     )
+    )
+   )
+  )
+  (func $if-block-br
+   (block $label
+    (if
+     (i32.const 1)
+     (br $label)
+    )
+   )
+  )
+  (func $if-block-br-1
+   (block $label
+    (if
+     (i32.const 1)
+     (br $label)
+     (drop (i32.const 3))
+    )
+   )
+  )
+  (func $if-block-br-2
+   (block $label
+    (if
+     (i32.const 1)
+     (drop (i32.const 3))
+     (br $label)
+    )
+   )
+  )
+  (func $if-block-br-3
+   (block $label
+    (if
+     (i32.const 1)
+     (br $label)
+     (br $label)
+    )
+   )
+  )
+  (func $if-block-br-4-eithre
+   (block $label
+    (if
+     (i32.const 1)
+     (drop (i32.const 2))
+     (drop (i32.const 3))
+    )
+   )
+  )
+  (func $if-block-br-5-value (result i32)
+   (block $label (result i32)
+    (if (result i32)
+     (i32.const 1)
+     (i32.const 2)
+     (i32.const 3)
+    )
+   )
+  )
+  (func $restructure-if-outerType-change
+   (loop $label$1
+    (br_if $label$1
+     (block $label$2
+      (block $label$3
+       (if
+        (block $label$4
+         (unreachable)
+        )
+        (br $label$3)
+       )
+      )
+      (unreachable)
+     )
+    )
+   )
+  )
+  (func $if-arm-unreachable
+   (block $label$1
+    (if
+     (unreachable) ;; unreachable condition
+     (nop)
+     (unreachable)
+    )
+   )
+  )
+  (func $propagate-type-if-we-optimize
+   (if
+    (i32.const 1)
+    (nop)
+    (block
+     (drop
+      (loop $label$3 (result i64)
+       (br_if $label$3
+        (block $label$4 (result i32)
+         (if
+          (i32.const 0)
+          (unreachable)
+          (unreachable)
+         )
+        )
+       )
+       (i64.const -9)
+      )
+     )
+     (unreachable)
+    )
+   )
+  )
+  (func $switch-to-br
+    (block $A
+      (block $y
+        (br_table $y $y $A $A
+          (i32.const 0)
+        )
+      )
+    )
+  )
+  (func $switch-to-br-value (result i32)
+    (block $A (result i32)
+      (block $y (result i32)
+        (br_table $A $A $A
+          (i32.const 0)
+          (i32.const 1)
+        )
+      )
+    )
+  )
+  (func $switch-threading-multi (param $x i32) (param $y i32) (result i32)
+   (block $block$5$break
+    (block $block$4$break
+     (loop $shape$1$continue
+      (block $block$3$break
+       (block $switch$2$case$5
+        (block $switch$2$case$4
+         (block $switch$2$default
+          (block $switch$2$case$2
+           (br_table $switch$2$case$2 $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$case$5 $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$default $switch$2$case$4 $switch$2$default
+            (local.get $x)
+           )
+          )
+          (br $shape$1$continue)
+         )
+         (br $block$3$break)
+        ) ;; switch$2$case$4
+        (br $block$4$break)
+       )
+       (br $block$5$break)
+      )
+     )
+     (unreachable)
+    ) ;; block$4$break
+    (local.set $y
+     (i32.const 1)
+    )
+    (unreachable)
+   )
+   (local.set $y
+    (i32.const 2)
+   )
+   (unreachable)
+  )
+  (func $fuzz-type-changes-in-our-cycles (result i32)
+   (loop $label$1
+    (if
+     (i32.const 0)
+     (block $label$3
+      (if
+       (i32.const 0)
+       (block
+        (nop)
+        (br $label$3)
+       )
+       (return
+        (i32.const -8192)
+       )
+      )
+     )
+    )
+    (br $label$1)
+   )
+  )
+  (func $refinalize-need-br-value (result i32)
+   (loop $label$3 (result i32)
+    (block $label$6 (result i32)
+     (block $label$10
+      (unreachable)
+      (block $label$503 ;; this block will get a value flowing out
+       (br_if $label$3
+        (block $label$530 (result i32)
+         (br_if $label$503 ;; while this br does not send a value
+          (i32.const 0)
+         )
+         (i32.const 0)
+        )
+       )
+       (return
+        (i32.const 127)
+       )
+      )
+     )
+    )
+   )
+  )
+  (func $selectify (param $x i32)
+    (drop
+      (if (result i32)
+        (i32.eq
+          (local.get $x)
+          (i32.const 1)
+        )
+        (i32.mul
+          (i32.const 2)
+          (i32.const 3)
+        )
+        (i32.mul
+          (i32.const 2)
+          (i32.const 3)
+        )
+      )
+    )
+    (drop
+      (if (result i32)
+        (i32.eq
+          (local.get $x)
+          (i32.const 1)
+        )
+        (i32.add
+          (i32.const 2)
+          (i32.const 3)
+        )
+        (i32.add
+          (i32.const 2)
+          (i32.const 3)
+        )
+      )
+    )
+  )
+  (func $if-one-side (result i32)
+   (local $x i32)
+   (local.set $x
+    (if (result i32)
+     (i32.const 1)
+     (i32.const 2)
+     (local.get $x)
+    )
+   )
+   (local.get $x)
+  )
+  (func $if-one-side-b (result i32)
+   (local $x i32)
+   (local.set $x
+    (if (result i32)
+     (i32.const 1)
+     (local.get $x)
+     (i32.const 2)
+    )
+   )
+   (local.get $x)
+  )
+  (func $if-one-side-tee-etc (param $0 i32) (result i32)
+   (local $1 i32)
+   (local $2 i32)
+   (local $3 i32)
+   (local $4 i32)
+   (local $x i32)
+   (local $y i32)
+   (local $z i32)
+   (drop
+    (call $if-one-side-tee-etc
+     (local.tee $x
+       (if (result i32)
+         (i32.const -3)
+         (i32.const -4)
+         (local.get $x)
+       )
+     )
+    )
+   )
+   (i32.const 0)
+  )
+  (func $ifs-copies-recursive (param $20 i32) (result i32)
+   (local.set $20
+    (if (result i32)
+     (i32.const 1)
+     (if (result i32)
+      (i32.const 2)
+      (if (result i32)
+       (i32.const 3)
+       (i32.const 4)
+       (local.get $20)
+      )
+      (local.get $20)
+     )
+     (local.get $20)
+    )
+   )
+   (local.get $20)
+  )
+  (func $if-copy1
+    (local $x i32)
+    (local $y i32)
+    (loop $top
+      (local.set $x
+        (if (result i32)
+          (i32.const 1)
+          (local.get $x)
+          (local.get $y)
+        )
+      )
+      (br $top)
+    )
+  )
+  (func $if-copy3
+    (local $x i32)
+    (local $y i32)
+    (loop $top
+      (local.set $x
+        (if (result i32)
+          (i32.const 1)
+          (unreachable)
+          (local.get $x)
+        )
+      )
+      (br $top)
+    )
+  )
+  (func $if-copy4
+    (local $x i32)
+    (local $y i32)
+    (loop $top
+      (local.set $x
+        (if (result i32)
+          (i32.const 1)
+          (unreachable)
+          (local.get $y)
+        )
+      )
+      (br $top)
+    )
+  )
+  (func $if-copy-tee
+    (local $x i32)
+    (local $y i32)
+    (loop $top
+      (drop
+        (local.tee $x
+          (if (result i32)
+            (i32.const 1)
+            (local.get $x)
+            (i32.const 2)
+          )
+        )
+      )
+      (br $top)
+    )
+  )
+  (func $loop-end-set (param $x i32) (result i32)
+    (loop $loop
+      (nop)
+      (if
+        (local.get $x)
+        (br $loop)
+        (local.set $x (i32.const 1))
+      )
+    )
+    (local.get $x)
+  )
+  (func $loop-end-value (param $x i32) (result i32)
+    (loop $loop (result i32)
+      (nop)
+      (if (result i32)
+        (local.get $x)
+        (br $loop)
+        (i32.const 1)
+      )
+    )
+  )
+  (func $do-not-flow-values-through-unreachable-code (result i32)
+   (block
+    (unreachable)
+    (block $A
+     (if
+      (i32.const 0)
+      (return
+       (i32.const 0) ;; seems to flow out, but we are in unreachable code, and do not actually reach anywhere
+      )
+      (br $A) ;; can be a nop
+     )
+    )
+   )
+  )
+  (func $do-not-flow-values-through-unreachable-code-b (result i32)
+   (loop
+    (unreachable)
+    (block $A
+     (if
+      (i32.const 0)
+      (return
+       (i32.const 0)
+      )
+      (br $A)
+     )
+    )
+   )
+  )
+ (func $if_br_if
+  (local $0 i32)
+  (block $label$1
+   (if
+    (local.tee $0 ;; note side effect; it's ok
+     (i32.const 1024)
+    )
+    (br_if $label$1
+     (i32.eqz
+      (i32.const -4)
+     )
+    )
+   )
+   (if
+    (i32.const 1025)
+    (br_if $label$1
+     (i32.eqz
+      (i32.const -5)
+     )
+    )
+   )
+   (if
+    (local.tee $0 ;; note side effect; it's ok
+     (i32.const 1025)
+    )
+    (br_if $label$1
+     (i32.eqz
+      (i32.const -6)
+     )
+    )
+   )
+   (if
+    (i32.const 1026)
+    (br_if $label$1
+     (local.tee $0 ;; but here it is *not* ok
+      (i32.const -7)
+     )
+    )
+   )
+   (i32.store
+    (i32.const 1024)
+    (i32.add
+     (local.get $0)
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $unswitch-reordering (param $x i32) (result i32)
+  (block $label$1 (result i32)
+   (br_table $label$1
+    (block $label$2 (result i32)
+     (i32.store ;; has a possible side effect
+      (i32.const 1)
+      (i32.const 2)
+     )
+     (i32.const 3)
+    )
+    (block (result i32)
+     (if
+      (local.get $x)
+      (return
+       (i32.const 5)
+      )
+     )
+     (i32.const 6)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/remove-unused-brs_generate-stack-ir_print-stack-ir.txt b/binaryen/test/passes/remove-unused-brs_generate-stack-ir_print-stack-ir.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-brs_generate-stack-ir_print-stack-ir.txt
@@ -0,0 +1,36 @@
+(module
+ (type $i64_=>_none (func (param i64)))
+ (func $0 (param $var$0 i64)
+  block $label$1
+   block $label$2
+    loop $label$3
+     block $label$4
+      unreachable
+     end
+     unreachable
+    end
+    unreachable
+   end
+   unreachable
+  end
+ )
+)
+(module
+ (type $i64_=>_none (func (param i64)))
+ (func $0 (; has Stack IR ;) (param $var$0 i64)
+  (block $label$1
+   (br_if $label$1
+    (block $label$2
+     (loop $label$3
+      (local.tee $var$0
+       (block $label$4
+        (unreachable)
+       )
+      )
+     )
+     (unreachable)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/remove-unused-brs_generate-stack-ir_print-stack-ir.wast b/binaryen/test/passes/remove-unused-brs_generate-stack-ir_print-stack-ir.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-brs_generate-stack-ir_print-stack-ir.wast
@@ -0,0 +1,21 @@
+(module
+ (type $0 (func (param i64)))
+ (func $0 (; 0 ;) (type $0) (param $var$0 i64)
+  (block $label$1
+   (br_if $label$1
+    (block $label$2 (result i32)
+     (loop $label$3
+      (local.set $var$0
+       (block $label$4 (result i64)
+        (unreachable)
+       )
+      )
+     )
+     (unreachable)
+    )
+   )
+   (nop)
+  )
+ )
+)
+
diff --git a/binaryen/test/passes/remove-unused-brs_precompute_vacuum_remove-unused-brs.txt b/binaryen/test/passes/remove-unused-brs_precompute_vacuum_remove-unused-brs.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-brs_precompute_vacuum_remove-unused-brs.txt
@@ -0,0 +1,13 @@
+(module
+ (type $i32_=>_f64 (func (param i32) (result f64)))
+ (global $global$3 (mut f64) (f64.const 0))
+ (func $1 (param $x i32) (result f64)
+  (local $var$0 f64)
+  (block $label$0 (result f64)
+   (local.set $var$0
+    (f64.const 0)
+   )
+   (f64.const -3.4)
+  )
+ )
+)
diff --git a/binaryen/test/passes/remove-unused-brs_precompute_vacuum_remove-unused-brs.wast b/binaryen/test/passes/remove-unused-brs_precompute_vacuum_remove-unused-brs.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-brs_precompute_vacuum_remove-unused-brs.wast
@@ -0,0 +1,29 @@
+(module
+ (global $global$3 (mut f64) (f64.const 0))
+ (func $1 (param $x i32) (result f64)
+  (local $var$0 f64)
+  (block $label$0
+   (local.set $var$0
+    (f64.const 0)
+   )
+   (if
+    (i32.gt_s
+     (i32.const 9)
+     (i32.const 0)
+    )
+    (return
+     (f64.const -3.4)
+    )
+   )
+   (if
+    (local.get $x)
+    (return
+     (f64.const 5.6)
+    )
+   )
+   (return
+    (f64.const 1.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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-brs_shrink-level=1.txt
@@ -0,0 +1,270 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (memory $0 256 256)
+ (func $b14 (result i32)
+  (drop
+   (select
+    (block $block1 (result i32)
+     (i32.const 12)
+    )
+    (block $block3 (result i32)
+     (i32.const 27)
+    )
+    (i32.const 1)
+   )
+  )
+  (drop
+   (if (result i32)
+    (i32.const 1)
+    (i32.load
+     (i32.const 10)
+    )
+    (i32.const 27)
+   )
+  )
+  (drop
+   (if (result i32)
+    (i32.const 1)
+    (i32.rem_s
+     (i32.const 11)
+     (i32.const 12)
+    )
+    (i32.const 27)
+   )
+  )
+  (drop
+   (if (result i32)
+    (i32.const 1)
+    (i32.trunc_f64_u
+     (f64.const 12.34)
+    )
+    (i32.const 27)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $join-br_ifs
+  (block $out
+   (br_if $out
+    (i32.or
+     (i32.const 1)
+     (i32.const 2)
+    )
+   )
+   (nop)
+   (br_if $out
+    (i32.const 3)
+   )
+  )
+  (block $out2
+   (block $out3
+    (br_if $out2
+     (i32.const 1)
+    )
+    (br_if $out3
+     (i32.const 2)
+    )
+    (br_if $out2
+     (i32.const 3)
+    )
+   )
+   (unreachable)
+  )
+  (block $out4
+   (block $out5
+    (br_if $out4
+     (i32.const 1)
+    )
+    (br_if $out5
+     (i32.or
+      (i32.const 2)
+      (i32.const 3)
+     )
+    )
+    (nop)
+   )
+   (unreachable)
+  )
+  (block $out6
+   (block $out7
+    (br_if $out6
+     (i32.or
+      (i32.const 1)
+      (i32.const 2)
+     )
+    )
+    (nop)
+    (br_if $out7
+     (i32.const 3)
+    )
+   )
+   (unreachable)
+  )
+  (if
+   (i32.eqz
+    (i32.or
+     (call $b14)
+     (i32.const 0)
+    )
+   )
+   (block $out8
+    (nop)
+    (nop)
+   )
+  )
+  (block $out83
+   (br_if $out83
+    (i32.const 1)
+   )
+   (br_if $out83
+    (call $b14)
+   )
+  )
+ )
+ (func $join-and-it-becomes-unreachable
+  (block $label$1
+   (block $block
+    (br_if $label$1
+     (i32.load8_u
+      (i32.const -93487262)
+     )
+    )
+    (br_if $label$1
+     (loop $label$5
+      (br $label$5)
+     )
+    )
+   )
+  )
+ )
+ (func $br-if-unreachable-pair
+  (block $label$14
+   (br_if $label$14
+    (unreachable)
+   )
+   (br_if $label$14
+    (i32.const 0)
+   )
+  )
+ )
+ (func $br-if-unreachable-pair2
+  (block $label$14
+   (br_if $label$14
+    (i32.const 0)
+   )
+   (br_if $label$14
+    (unreachable)
+   )
+  )
+ )
+ (func $simple-switch (result i32)
+  (block $A
+   (block $B
+    (block $y
+     (br_table $A $y $y $y $y $y $A $y $y $y $y $A $y
+      (i32.const 0)
+     )
+     (return
+      (i32.const 0)
+     )
+    )
+    (return
+     (i32.const 1)
+    )
+   )
+   (return
+    (i32.const 2)
+   )
+  )
+  (i32.const 3)
+ )
+ (func $simple-switch-2 (result i32)
+  (local $0 i32)
+  (block $A
+   (block $B
+    (block $y
+     (br_if $A
+      (i32.or
+       (i32.eqz
+        (local.tee $0
+         (i32.const 0)
+        )
+       )
+       (i32.eq
+        (local.get $0)
+        (i32.const 12)
+       )
+      )
+     )
+     (nop)
+     (br $y)
+     (return
+      (i32.const 0)
+     )
+    )
+    (return
+     (i32.const 1)
+    )
+   )
+   (return
+    (i32.const 2)
+   )
+  )
+  (i32.const 3)
+ )
+ (func $simple-switch-3 (result i32)
+  (local $0 i32)
+  (block $A
+   (block $B
+    (block $y
+     (br_if $A
+      (i32.eqz
+       (local.tee $0
+        (i32.const 0)
+       )
+      )
+     )
+     (br_if $B
+      (i32.eq
+       (local.get $0)
+       (i32.const 1025)
+      )
+     )
+     (br $y)
+     (return
+      (i32.const 0)
+     )
+    )
+    (return
+     (i32.const 1)
+    )
+   )
+   (return
+    (i32.const 2)
+   )
+  )
+  (i32.const 3)
+ )
+ (func $simple-switch-4 (result i32)
+  (block $A
+   (block $B
+    (block $y
+     (br_table $A $y $y $y $y $y $A $y $y $y $y $y $A $y
+      (i32.const 0)
+     )
+     (return
+      (i32.const 0)
+     )
+    )
+    (return
+     (i32.const 1)
+    )
+   )
+   (return
+    (i32.const 2)
+   )
+  )
+  (i32.const 3)
+ )
+)
diff --git a/binaryen/test/passes/remove-unused-brs_shrink-level=1.wast b/binaryen/test/passes/remove-unused-brs_shrink-level=1.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-brs_shrink-level=1.wast
@@ -0,0 +1,177 @@
+(module
+  (memory 256 256)
+  (type $0 (func (param i32)))
+  (type $1 (func))
+  (type $2 (func (result i32)))
+  (func $b14 (type $2)
+    (drop
+      (if (result i32) ;; with shrinking, this can become a select
+        (i32.const 1)
+        (block $block1 (result i32)
+          (i32.const 12)
+        )
+        (block $block3 (result i32)
+          (i32.const 27)
+        )
+      )
+    )
+    (drop
+      (if (result i32)
+        (i32.const 1)
+        (i32.load (i32.const 10)) ;; load may have side effects, unless ignored
+        (i32.const 27)
+      )
+    )
+    (drop
+      (if (result i32)
+        (i32.const 1)
+        (i32.rem_s (i32.const 11) (i32.const 12)) ;; rem may have side effects, unless ignored
+        (i32.const 27)
+      )
+    )
+    (drop
+      (if (result i32)
+        (i32.const 1)
+        (i32.trunc_f64_u (f64.const 12.34)) ;; float to int may have side effects, unless ignored
+        (i32.const 27)
+      )
+    )
+    (i32.const 0)
+  )
+  (func $join-br_ifs
+    (block $out
+      (br_if $out (i32.const 1))
+      (br_if $out (i32.const 2))
+      (br_if $out (i32.const 3))
+    )
+    (block $out2
+      (block $out3
+        (br_if $out2 (i32.const 1))
+        (br_if $out3 (i32.const 2))
+        (br_if $out2 (i32.const 3))
+      )
+      (unreachable)
+    )
+    (block $out4
+      (block $out5
+        (br_if $out4 (i32.const 1))
+        (br_if $out5 (i32.const 2))
+        (br_if $out5 (i32.const 3))
+      )
+      (unreachable)
+    )
+    (block $out6
+      (block $out7
+        (br_if $out6 (i32.const 1))
+        (br_if $out6 (i32.const 2))
+        (br_if $out7 (i32.const 3))
+      )
+      (unreachable)
+    )
+    (block $out8
+      (br_if $out8 (call $b14)) ;; side effect
+      (br_if $out8 (i32.const 0))
+    )
+    (block $out8
+      (br_if $out8 (i32.const 1))
+      (br_if $out8 (call $b14)) ;; side effect
+    )
+  )
+  (func $join-and-it-becomes-unreachable
+   (block $label$1
+    (block
+     (br_if $label$1
+      (i32.load8_u
+       (i32.const -93487262)
+      )
+     )
+     (br_if $label$1
+      (loop $label$5 ;; this is unreachable (infinite loop, no exit)
+       (br $label$5)
+      )
+     )
+    )
+   )
+  )
+  (func $br-if-unreachable-pair
+   (block $label$14
+    (br_if $label$14
+     (unreachable)
+    )
+    (br_if $label$14
+     (i32.const 0)
+    )
+   )
+  )
+  (func $br-if-unreachable-pair2
+   (block $label$14
+    (br_if $label$14
+     (i32.const 0)
+    )
+    (br_if $label$14
+     (unreachable)
+    )
+   )
+  )
+  (func $simple-switch (result i32)
+    (block $A
+      (block $B
+        (block $y
+          (br_table $A $y $y $y $y $y $A $y $y $y $y $A $y
+            (i32.const 0)
+          )
+          (return (i32.const 0))
+        )
+        (return (i32.const 1))
+      )
+      (return (i32.const 2))
+    )
+    (return (i32.const 3))
+  )
+  (func $simple-switch-2 (result i32)
+    (block $A
+      (block $B
+        (block $y
+          (br_table $A $y $y $y $y $y $y $y $y $y $y $y $A $y
+            (i32.const 0)
+          )
+          (return (i32.const 0))
+        )
+        (return (i32.const 1))
+      )
+      (return (i32.const 2))
+    )
+    (return (i32.const 3))
+  )
+  (func $simple-switch-3 (result i32)
+    (block $A
+      (block $B
+        (block $y
+          (br_table $A $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $y $B $y
+            (i32.const 0)
+          )
+          (return (i32.const 0))
+        )
+        (return (i32.const 1))
+      )
+      (return (i32.const 2))
+    )
+    (return (i32.const 3))
+  )
+  (func $simple-switch-4 (result i32)
+    (block $A
+      (block $B
+        (block $y
+          (br_table $A $y $y $y $y $y $A $y $y $y $y $y $A $y
+            (i32.const 0)
+          )
+          (return (i32.const 0))
+        )
+        (return (i32.const 1))
+      )
+      (return (i32.const 2))
+    )
+    (return (i32.const 3))
+  )
+)
+
diff --git a/binaryen/test/passes/remove-unused-brs_shrink-level=1_ignore-implicit-traps.txt b/binaryen/test/passes/remove-unused-brs_shrink-level=1_ignore-implicit-traps.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-brs_shrink-level=1_ignore-implicit-traps.txt
@@ -0,0 +1,125 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 256 256)
+ (func $b14 (result i32)
+  (drop
+   (select
+    (block $block1 (result i32)
+     (i32.const 12)
+    )
+    (block $block3 (result i32)
+     (i32.const 27)
+    )
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select
+    (i32.load
+     (i32.const 10)
+    )
+    (i32.const 27)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select
+    (i32.rem_s
+     (i32.const 11)
+     (i32.const 12)
+    )
+    (i32.const 27)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select
+    (i32.trunc_f64_u
+     (f64.const 12.34)
+    )
+    (i32.const 27)
+    (i32.const 1)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $join-br_ifs
+  (block $out
+   (br_if $out
+    (i32.or
+     (i32.const 1)
+     (i32.const 2)
+    )
+   )
+   (nop)
+   (br_if $out
+    (i32.const 3)
+   )
+  )
+  (block $out2
+   (block $out3
+    (br_if $out2
+     (i32.const 1)
+    )
+    (br_if $out3
+     (i32.const 2)
+    )
+    (br_if $out2
+     (i32.const 3)
+    )
+   )
+   (unreachable)
+  )
+  (block $out4
+   (block $out5
+    (br_if $out4
+     (i32.const 1)
+    )
+    (br_if $out5
+     (i32.or
+      (i32.const 2)
+      (i32.const 3)
+     )
+    )
+    (nop)
+   )
+   (unreachable)
+  )
+  (block $out6
+   (block $out7
+    (br_if $out6
+     (i32.or
+      (i32.const 1)
+      (i32.const 2)
+     )
+    )
+    (nop)
+    (br_if $out7
+     (i32.const 3)
+    )
+   )
+   (unreachable)
+  )
+  (if
+   (i32.eqz
+    (i32.or
+     (call $b14)
+     (i32.const 0)
+    )
+   )
+   (block $out8
+    (nop)
+    (nop)
+   )
+  )
+  (block $out83
+   (br_if $out83
+    (i32.const 1)
+   )
+   (br_if $out83
+    (call $b14)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/remove-unused-brs_shrink-level=1_ignore-implicit-traps.wast b/binaryen/test/passes/remove-unused-brs_shrink-level=1_ignore-implicit-traps.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-brs_shrink-level=1_ignore-implicit-traps.wast
@@ -0,0 +1,81 @@
+(module
+  (memory 256 256)
+  (type $0 (func (param i32)))
+  (type $1 (func))
+  (type $2 (func (result i32)))
+  (func $b14 (type $2)
+    (drop
+      (if (result i32) ;; with shrinking, this can become a select
+        (i32.const 1)
+        (block $block1 (result i32)
+          (i32.const 12)
+        )
+        (block $block3 (result i32)
+          (i32.const 27)
+        )
+      )
+    )
+    (drop
+      (if (result i32)
+        (i32.const 1)
+        (i32.load (i32.const 10)) ;; load may have side effects, unless ignored
+        (i32.const 27)
+      )
+    )
+    (drop
+      (if (result i32)
+        (i32.const 1)
+        (i32.rem_s (i32.const 11) (i32.const 12)) ;; rem may have side effects, unless ignored
+        (i32.const 27)
+      )
+    )
+    (drop
+      (if (result i32)
+        (i32.const 1)
+        (i32.trunc_f64_u (f64.const 12.34)) ;; float to int may have side effects, unless ignored
+        (i32.const 27)
+      )
+    )
+    (i32.const 0)
+  )
+  (func $join-br_ifs
+    (block $out
+      (br_if $out (i32.const 1))
+      (br_if $out (i32.const 2))
+      (br_if $out (i32.const 3))
+    )
+    (block $out2
+      (block $out3
+        (br_if $out2 (i32.const 1))
+        (br_if $out3 (i32.const 2))
+        (br_if $out2 (i32.const 3))
+      )
+      (unreachable)
+    )
+    (block $out4
+      (block $out5
+        (br_if $out4 (i32.const 1))
+        (br_if $out5 (i32.const 2))
+        (br_if $out5 (i32.const 3))
+      )
+      (unreachable)
+    )
+    (block $out6
+      (block $out7
+        (br_if $out6 (i32.const 1))
+        (br_if $out6 (i32.const 2))
+        (br_if $out7 (i32.const 3))
+      )
+      (unreachable)
+    )
+    (block $out8
+      (br_if $out8 (call $b14)) ;; side effect
+      (br_if $out8 (i32.const 0))
+    )
+    (block $out8
+      (br_if $out8 (i32.const 1))
+      (br_if $out8 (call $b14)) ;; side effect
+    )
+  )
+)
+
diff --git a/binaryen/test/passes/remove-unused-module-elements_all-features.txt b/binaryen/test/passes/remove-unused-module-elements_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-module-elements_all-features.txt
@@ -0,0 +1,326 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 0)
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $called_indirect)
+ (export "memory" (memory $0))
+ (export "exported" (func $exported))
+ (export "other1" (func $other1))
+ (export "other2" (func $other2))
+ (start $start)
+ (func $start
+  (call $called0)
+ )
+ (func $called0
+  (call $called1)
+ )
+ (func $called1
+  (nop)
+ )
+ (func $called_indirect
+  (nop)
+ )
+ (func $exported
+  (call $called2)
+ )
+ (func $called2
+  (call $called2)
+  (call $called3)
+ )
+ (func $called3
+  (call $called4)
+ )
+ (func $called4
+  (call $called3)
+ )
+ (func $other1 (param $0 i32)
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+  (call_indirect (type $i32_=>_none)
+   (i32.const 0)
+   (i32.const 0)
+  )
+  (call_indirect (type $i32_=>_none)
+   (i32.const 0)
+   (i32.const 0)
+  )
+  (drop
+   (call_indirect (type $i32_=>_i32)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call_indirect (type $i32_=>_i32)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call_indirect (type $i32_=>_i32)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other2 (param $0 i32)
+  (unreachable)
+ )
+)
+(module
+)
+(module
+)
+(module
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table $timport$0 1 funcref))
+ (export "mem" (memory $0))
+ (export "tab" (table $0))
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "memory" (memory $0 256))
+ (data (i32.const 1) "hello, world!")
+ (import "env" "table" (table $timport$0 1 funcref))
+ (elem (i32.const 0) $waka)
+ (func $waka
+  (nop)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table $timport$0 0 funcref))
+ (export "user" (func $user))
+ (func $user
+  (drop
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 (shared 23 256))
+ (export "user" (func $user))
+ (func $user
+  (i32.store
+   (i32.const 0)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 (shared 23 256))
+ (export "user" (func $user))
+ (func $user (result i32)
+  (i32.atomic.rmw.add
+   (i32.const 0)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 (shared 23 256))
+ (export "user" (func $user))
+ (func $user (result i32)
+  (i32.atomic.rmw8.cmpxchg_u
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 (shared 23 256))
+ (export "user" (func $user))
+ (func $user
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.wait
+    (local.get $0)
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 (shared 23 256))
+ (export "user" (func $user))
+ (func $user (result i32)
+  (atomic.notify
+   (i32.const 0)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 23 256)
+ (export "user" (func $user))
+ (func $user (result i32)
+  (memory.grow
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "memory" (memory $0 256))
+ (export "user" (func $user))
+ (func $user (result i32)
+  (memory.grow
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 23 256)
+ (export "user" (func $user))
+ (func $user (result i32)
+  (memory.size)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "memory" (memory $0 256))
+ (data (global.get $memoryBase) "hello, world!")
+ (import "env" "table" (table $timport$0 0 funcref))
+ (elem (global.get $tableBase) $waka)
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (func $waka
+  (nop)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "imported" (global $imported i32))
+ (import "env" "_puts" (func $_puts (param i32) (result i32)))
+ (global $int (mut i32) (global.get $imported))
+ (global $set (mut i32) (i32.const 100))
+ (global $exp_glob i32 (i32.const 600))
+ (export "one" (func $one))
+ (export "three" (func $three))
+ (export "exp_glob" (global $exp_glob))
+ (func $one (result i32)
+  (call $two)
+ )
+ (func $two (result i32)
+  (global.get $int)
+ )
+ (func $three
+  (call $four)
+ )
+ (func $four
+  (global.set $set
+   (i32.const 200)
+  )
+  (drop
+   (call $_puts
+    (i32.const 300)
+   )
+  )
+ )
+)
+(module
+)
+(module
+ (type $none_=>_none (func))
+ (start $starter)
+ (func $starter
+  (drop
+   (i32.const 0)
+  )
+ )
+)
+(module
+)
+(module
+)
+(module
+ (type $f64_=>_f64 (func (param f64) (result f64)))
+ (import "env" "table" (table $timport$0 6 6 funcref))
+ (elem (i32.const 0) $0)
+ (func $0 (param $var$0 f64) (result f64)
+  (if (result f64)
+   (f64.eq
+    (f64.const 1)
+    (f64.const 1)
+   )
+   (f64.const 1)
+   (f64.const 0)
+  )
+ )
+)
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_none (func))
+ (type $i64_=>_none (func (param i64)))
+ (event $e-export (attr 0) (param i64))
+ (event $e-throw (attr 0) (param i32))
+ (event $e-bronexn (attr 0) (param i32))
+ (export "e-export" (event $e-export))
+ (start $start)
+ (func $start
+  (local $exn exnref)
+  (try
+   (do
+    (throw $e-throw
+     (i32.const 0)
+    )
+   )
+   (catch
+    (local.set $exn
+     (pop exnref)
+    )
+    (drop
+     (block $l0 (result i32)
+      (rethrow
+       (br_on_exn $l0 $e-bronexn
+        (local.get $exn)
+       )
+      )
+     )
+    )
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (export "test" (func $test))
+ (func $foo
+  (nop)
+ )
+ (func $test
+  (drop
+   (ref.func $foo)
+  )
+ )
+)
diff --git a/binaryen/test/passes/remove-unused-module-elements_all-features.wast b/binaryen/test/passes/remove-unused-module-elements_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-module-elements_all-features.wast
@@ -0,0 +1,299 @@
+(module
+  (memory 0)
+  (start $start)
+  (type $0 (func))
+  (type $0-dupe (func))
+  (type $1 (func (param i32)))
+  (type $1-dupe (func (param i32)))
+  (type $2 (func (param i32) (result i32)))
+  (type $2-dupe (func (param i32) (result i32)))
+  (type $2-thrupe (func (param i32) (result i32)))
+  (export "memory" (memory $0))
+  (export "exported" $exported)
+  (export "other1" $other1)
+  (export "other2" $other2)
+  (table 1 1 funcref)
+  (elem (i32.const 0) $called_indirect)
+  (func $start (type $0)
+    (call $called0)
+  )
+  (func $called0 (type $0)
+    (call $called1)
+  )
+  (func $called1 (type $0)
+    (nop)
+  )
+  (func $called_indirect (type $0)
+    (nop)
+  )
+  (func $exported (type $0-dupe)
+    (call $called2)
+  )
+  (func $called2 (type $0-dupe)
+    (call $called2)
+    (call $called3)
+  )
+  (func $called3 (type $0-dupe)
+    (call $called4)
+  )
+  (func $called4 (type $0-dupe)
+    (call $called3)
+  )
+  (func $remove0 (type $0-dupe)
+    (call $remove1)
+  )
+  (func $remove1 (type $0-dupe)
+    (nop)
+  )
+  (func $remove2 (type $0-dupe)
+    (call $remove2)
+  )
+  (func $remove3 (type $0)
+    (call $remove4)
+  )
+  (func $remove4 (type $0)
+    (call $remove3)
+  )
+  (func $other1 (type $1) (param i32)
+    (call_indirect (type $0) (i32.const 0))
+    (call_indirect (type $0) (i32.const 0))
+    (call_indirect (type $0-dupe) (i32.const 0))
+    (call_indirect (type $0-dupe) (i32.const 0))
+    (call_indirect (type $1) (i32.const 0) (i32.const 0))
+    (call_indirect (type $1-dupe) (i32.const 0) (i32.const 0))
+    (drop (call_indirect (type $2) (i32.const 0) (i32.const 0)))
+    (drop (call_indirect (type $2-dupe) (i32.const 0) (i32.const 0)))
+    (drop (call_indirect (type $2-thrupe) (i32.const 0) (i32.const 0)))
+  )
+  (func $other2 (type $1-dupe) (param i32)
+    (unreachable)
+  )
+)
+(module ;; remove the table and memory
+  (import "env" "memory" (memory $0 256))
+  (import "env" "table" (table 0 funcref))
+)
+(module ;; also when not imported
+  (memory 256)
+  (table 1 funcref)
+)
+(module ;; but not when exported
+  (import "env" "memory" (memory $0 256))
+  (import "env" "table" (table 1 funcref))
+  (export "mem" (memory 0))
+  (export "tab" (table 0))
+)
+(module ;; and not when there are segments
+  (import "env" "memory" (memory $0 256))
+  (import "env" "table" (table 1 funcref))
+  (data (i32.const 1) "hello, world!")
+  (elem (i32.const 0) $waka)
+  (func $waka)
+)
+(module ;; and not when used
+  (type $0 (func))
+  (import "env" "memory" (memory $0 256))
+  (import "env" "table" (table 0 funcref))
+  (export "user" $user)
+  (func $user
+    (drop (i32.load (i32.const 0)))
+    (call_indirect (type $0) (i32.const 0))
+  )
+)
+(module ;; more use checks
+  (memory $0 (shared 23 256))
+  (export "user" $user)
+  (func $user
+    (i32.store (i32.const 0) (i32.const 0))
+  )
+)
+(module ;; more use checks
+  (memory $0 (shared 23 256))
+  (export "user" $user)
+  (func $user (result i32)
+    (i32.atomic.rmw.add (i32.const 0) (i32.const 0))
+  )
+)
+(module ;; more use checks
+  (memory $0 (shared 23 256))
+  (export "user" $user)
+  (func $user (result i32)
+    (i32.atomic.rmw8.cmpxchg_u (i32.const 0) (i32.const 0) (i32.const 0))
+  )
+)
+(module ;; more use checks
+  (memory $0 (shared 23 256))
+  (export "user" $user)
+  (func $user
+    (local $0 i32)
+    (local $1 i64)
+    (drop
+     (i32.atomic.wait
+      (local.get $0)
+      (local.get $0)
+      (local.get $1)
+     )
+    )
+  )
+)
+(module ;; more use checks
+  (memory $0 (shared 23 256))
+  (export "user" $user)
+  (func $user (result i32)
+    (atomic.notify (i32.const 0) (i32.const 0))
+  )
+)
+(module ;; more use checks
+  (memory $0 23 256)
+  (export "user" $user)
+  (func $user (result i32)
+    (memory.grow (i32.const 0))
+  )
+)
+(module ;; more use checks
+  (import "env" "memory" (memory $0 256))
+  (export "user" $user)
+  (func $user (result i32)
+    (memory.grow (i32.const 0))
+  )
+)
+(module ;; more use checks
+  (memory $0 23 256)
+  (export "user" $user)
+  (func $user (result i32)
+    (memory.size)
+  )
+)
+(module
+  (import "env" "memory" (memory $0 256))
+  (import "env" "table" (table 0 funcref))
+  (import "env" "memoryBase" (global $memoryBase i32)) ;; used in init
+  (import "env" "tableBase" (global $tableBase i32)) ;; used in init
+  (data (global.get $memoryBase) "hello, world!")
+  (elem (global.get $tableBase) $waka)
+  (func $waka) ;; used in table
+)
+(module ;; one is exported, and one->two->int global, whose init->imported
+  (import "env" "imported" (global $imported i32))
+  (import "env" "forgetme" (global $forgetme i32))
+  (import "env" "_puts" (func $_puts (param i32) (result i32)))
+  (import "env" "forget_puts" (func $forget_puts (param i32) (result i32)))
+  (global $int (mut i32) (global.get $imported))
+  (global $set (mut i32) (i32.const 100))
+  (global $forglobal.get (mut i32) (i32.const 500))
+  (global $exp_glob i32 (i32.const 600))
+  (export "one" (func $one))
+  (export "three" (func $three))
+  (export "exp_glob" (global $exp_glob))
+  (start $starter)
+  (func $one (result i32)
+    (call $two)
+  )
+  (func $two (result i32)
+    (global.get $int)
+  )
+  (func $three
+    (call $four)
+  )
+  (func $four
+    (global.set $set (i32.const 200))
+    (drop (call $_puts (i32.const 300)))
+  )
+  (func $forget_implemented
+    (nop)
+  )
+  (func $starter
+    (nop)
+  )
+)
+(module ;; empty start being removed
+  (start $starter)
+  (func $starter
+    (nop)
+  )
+)
+(module ;; non-empty start being kept
+  (start $starter)
+  (func $starter
+    (drop (i32.const 0))
+  )
+)
+(module ;; the function and the table can be removed
+ (type $0 (func (param f64) (result f64)))
+ (table 6 6 funcref)
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+  (if (result f64)
+   (f64.eq
+    (f64.const 1)
+    (f64.const 1)
+   )
+   (f64.const 1)
+   (f64.const 0)
+  )
+ )
+)
+(module ;; the function uses the table, but all are removeable
+ (type $0 (func (param f64) (result f64)))
+ (table 6 6 funcref)
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+  (if (result f64)
+   (f64.eq
+    (f64.const 1)
+    (f64.const 1)
+   )
+   (call_indirect (type $0) (f64.const 1) (i32.const 0))
+   (f64.const 0)
+  )
+ )
+)
+(module ;; the table is imported - we can't remove it
+ (type $0 (func (param f64) (result f64)))
+ (import "env" "table" (table 6 6 funcref))
+ (elem (i32.const 0) $0)
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+  (if (result f64)
+   (f64.eq
+    (f64.const 1)
+    (f64.const 1)
+   )
+   (f64.const 1)
+   (f64.const 0)
+  )
+ )
+)
+(module ;; non-exported and unused events can be removed
+ (type $0 (func (param i32)))
+ (event $e-remove (attr 0) (type $0))   ;; can be removed
+ (event $e-export (attr 0) (param i64)) ;; cannot be removed (exported)
+ (event $e-throw (attr 0) (type $0))    ;; cannot be removed (used in throw)
+ (event $e-bronexn (attr 0) (type $0))  ;; cannot be removed (used in br_on_exn)
+ (export "e-export" (event $e-export))
+ (import "env" "e" (event $e-import (attr 0) (param i32)))
+ (start $start)
+ (func $start (local $exn exnref) (; 0 ;)
+  (try
+   (do
+    (throw $e-throw (i32.const 0))
+   )
+   (catch
+    (local.set $exn (pop exnref))
+    (drop
+     (block $l0 (result i32)
+      (rethrow
+       (br_on_exn $l0 $e-bronexn (local.get $exn))
+      )
+     )
+    )
+   )
+  )
+ )
+)
+(module ;; functions referenced by ref.func cannot be removed
+ (export "test" $test)
+ (func $foo)
+ (func $test
+  (drop
+   (ref.func $foo)
+  )
+ )
+)
diff --git a/binaryen/test/passes/remove-unused-names.txt b/binaryen/test/passes/remove-unused-names.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names.txt
@@ -0,0 +1,88 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 256 256)
+ (func $b0 (param $i1 i32) (result i32)
+  (i32.const 0)
+ )
+ (func $loops
+  (block $out
+   (loop $in
+    (br $out)
+    (br $in)
+   )
+  )
+  (loop $in0
+   (br $in0)
+  )
+  (nop)
+  (block $out4
+   (loop $in5
+    (br $out4)
+    (br $in5)
+   )
+  )
+  (block $out6
+   (loop $in7
+    (br $out6)
+    (br $in7)
+   )
+  )
+  (loop $in8
+   (block $out9
+    (br $out9)
+    (br $in8)
+   )
+  )
+  (loop $in10
+   (block $out11
+    (br $out11)
+    (br $in10)
+   )
+  )
+  (block $out12
+   (loop $in13
+    (br $out12)
+    (br $in13)
+   )
+  )
+ )
+ (func $merges
+  (block $b
+   (br $b)
+   (br $b)
+  )
+  (block $b15
+   (br_table $b15 $b15
+    (i32.const 3)
+   )
+  )
+  (block $b17
+   (br_table $b17 $b17
+    (i32.const 3)
+   )
+  )
+ )
+ (func $merge-typed-with-unreachable-child (result i32)
+  (local $0 f32)
+  (block $label$1 (result i32)
+   (br_if $label$1
+    (i32.const 1)
+    (br_if $label$1
+     (i32.const 0)
+     (br $label$1
+      (i32.const 0)
+     )
+    )
+   )
+  )
+ )
+ (func $loop-with-child-of-other-type
+  (drop
+   (loop (result i32)
+    (unreachable)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/remove-unused-names.wast b/binaryen/test/passes/remove-unused-names.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names.wast
@@ -0,0 +1,105 @@
+(module
+  (memory 256 256)
+  (type $0 (func (param i32) (result i32)))
+  (type $1 (func))
+  (func $b0 (type $0) (param $i1 i32) (result i32)
+    (block $topmost (result i32)
+      (i32.const 0)
+    )
+  )
+  (func $loops (type $1)
+    (block $out
+      (loop $in
+        (br $out)
+        (br $in)
+      )
+    )
+    (loop $in
+      (br $in)
+    )
+    (loop $in
+      (nop)
+    )
+    (block $out
+      (loop $in
+        (block $out
+          (loop $in
+            (br $out)
+            (br $in)
+          )
+        )
+      )
+    )
+    (block $out
+      (loop $in
+        (br $out)
+        (br $in)
+      )
+    )
+    (loop $in
+      (block $out
+        (br $out)
+        (br $in)
+      )
+    )
+    (loop $in
+      (block $out
+        (br $out)
+        (br $in)
+      )
+    )
+    (block $out
+      (loop $in
+        (br $out)
+        (br $in)
+      )
+    )
+  )
+  (func $merges (type $1)
+    (block $a
+      (block $b
+        (br $a)
+        (br $b)
+      )
+    )
+    (block $a
+      (block $b
+        (br_table $a $b
+          (i32.const 3)
+        )
+      )
+    )
+    (block $a
+      (block $b
+        (br_table $b $a
+          (i32.const 3)
+        )
+      )
+    )
+  )
+  (func $merge-typed-with-unreachable-child (result i32)
+   (local $0 f32)
+   (block $label$0 (result i32)
+    (block $label$1 (result i32)
+     (br_if $label$1
+      (i32.const 1)
+      (br_if $label$0
+       (i32.const 0)
+       (br $label$0
+        (i32.const 0)
+       )
+      )
+     )
+    )
+   )
+  )
+  (func $loop-with-child-of-other-type
+   (drop
+    (loop (result i32) ;; the loop has no name, but can't be replaced by the child
+     (block $l         ;; as the type differs
+      (unreachable)
+     )
+    )
+   )
+  )
+)
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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names_code-folding_all-features.txt
@@ -0,0 +1,1846 @@
+(module
+ (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 $none_=>_exnref (func (result exnref)))
+ (event $e (attr 0) (param))
+ (func $ifs
+  (if
+   (i32.const 0)
+   (nop)
+  )
+  (block
+   (drop
+    (i32.const 0)
+   )
+   (nop)
+  )
+  (if
+   (i32.const 0)
+   (nop)
+   (unreachable)
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (i32.const 0)
+    )
+    (i32.add
+     (i32.const 1)
+     (i32.const 2)
+    )
+   )
+  )
+  (drop
+   (if (result i32)
+    (i32.const 0)
+    (i32.add
+     (i32.const 1)
+     (i32.const 2)
+    )
+    (i32.add
+     (i32.const 1)
+     (i32.const 333333333)
+    )
+   )
+  )
+ )
+ (func $ifs-blocks
+  (block
+   (drop
+    (i32.const 0)
+   )
+   (block
+    (nop)
+   )
+  )
+  (block
+   (if
+    (i32.const 0)
+    (unreachable)
+    (block
+    )
+   )
+   (nop)
+  )
+  (block
+   (if
+    (i32.const 0)
+    (block
+    )
+    (unreachable)
+   )
+   (nop)
+  )
+  (if
+   (i32.const 0)
+   (block
+    (nop)
+    (unreachable)
+   )
+   (nop)
+  )
+  (if
+   (i32.const 0)
+   (nop)
+   (block
+    (nop)
+    (unreachable)
+   )
+  )
+ )
+ (func $ifs-blocks-big
+  (block
+   (drop
+    (i32.const 0)
+   )
+   (block
+    (drop
+     (i32.add
+      (i32.const 1)
+      (i32.const 2)
+     )
+    )
+   )
+  )
+  (block
+   (if
+    (i32.const 0)
+    (unreachable)
+    (block
+    )
+   )
+   (drop
+    (i32.add
+     (i32.const 1)
+     (i32.const 2)
+    )
+   )
+  )
+  (block
+   (if
+    (i32.const 0)
+    (block
+    )
+    (unreachable)
+   )
+   (drop
+    (i32.add
+     (i32.const 1)
+     (i32.const 2)
+    )
+   )
+  )
+  (if
+   (i32.const 0)
+   (block
+    (drop
+     (i32.add
+      (i32.const 1)
+      (i32.const 2)
+     )
+    )
+    (unreachable)
+   )
+   (drop
+    (i32.add
+     (i32.const 1)
+     (i32.const 2)
+    )
+   )
+  )
+  (if
+   (i32.const 0)
+   (drop
+    (i32.add
+     (i32.const 1)
+     (i32.const 2)
+    )
+   )
+   (block
+    (drop
+     (i32.add
+      (i32.const 1)
+      (i32.const 2)
+     )
+    )
+    (unreachable)
+   )
+  )
+ )
+ (func $ifs-blocks-long
+  (block
+   (if
+    (i32.const 1)
+    (block
+     (drop
+      (i32.const -1234)
+     )
+     (drop
+      (i32.const -1000)
+     )
+    )
+    (drop
+     (i32.const 999)
+    )
+   )
+   (drop
+    (i32.const 1)
+   )
+   (nop)
+   (unreachable)
+  )
+  (drop
+   (block (result i32)
+    (if
+     (i32.const 2)
+     (block
+      (drop
+       (i32.const -1234)
+      )
+      (drop
+       (i32.const -1000)
+      )
+     )
+     (drop
+      (i32.const 999)
+     )
+    )
+    (drop
+     (i32.const 1)
+    )
+    (nop)
+    (unreachable)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (block (result i32)
+    (if
+     (i32.const 3)
+     (block
+      (drop
+       (i32.const -1234)
+      )
+      (drop
+       (i32.const -1000)
+      )
+     )
+     (drop
+      (i32.const 999)
+     )
+    )
+    (drop
+     (i32.const 1)
+    )
+    (nop)
+    (i32.const 2)
+   )
+  )
+ )
+ (func $if-worth-it-i-dunno
+  (block $folding-inner0
+   (block
+    (if
+     (i32.const 0)
+     (if
+      (i32.const 0)
+      (block
+       (drop
+        (i32.const -1234)
+       )
+       (drop
+        (i32.const -1000)
+       )
+       (br $folding-inner0)
+      )
+      (block
+       (drop
+        (i32.const 999)
+       )
+       (drop
+        (i32.const 1)
+       )
+       (br $folding-inner0)
+      )
+     )
+    )
+    (if
+     (i32.const 0)
+     (block
+      (if
+       (i32.const 0)
+       (block
+        (drop
+         (i32.const -1234)
+        )
+        (drop
+         (i32.const -1000)
+        )
+       )
+       (block
+        (drop
+         (i32.const 999)
+        )
+        (drop
+         (i32.const 1)
+        )
+       )
+      )
+      (unreachable)
+      (br $folding-inner0)
+     )
+    )
+    (if
+     (i32.const 0)
+     (block
+      (if
+       (i32.const 0)
+       (block
+       )
+       (block
+        (drop
+         (i32.const 999)
+        )
+        (drop
+         (i32.const 1)
+        )
+       )
+      )
+      (br $folding-inner0)
+     )
+    )
+    (if
+     (i32.const 0)
+     (block
+      (if
+       (i32.const 0)
+       (block
+        (drop
+         (i32.const -1234)
+        )
+        (drop
+         (i32.const -1000)
+        )
+       )
+       (block
+       )
+      )
+      (br $folding-inner0)
+     )
+    )
+    (block
+     (block
+      (if
+       (i32.const 9999)
+       (block
+        (drop
+         (i32.const -51234)
+        )
+        (drop
+         (i32.const -51000)
+        )
+       )
+       (block
+        (drop
+         (i32.const 5999)
+        )
+        (drop
+         (i32.const 51)
+        )
+       )
+      )
+      (br $folding-inner0)
+     )
+    )
+    (drop
+     (block (result i32)
+      (block (result i32)
+       (if
+        (i32.const 9999)
+        (block
+         (drop
+          (i32.const -51234)
+         )
+         (drop
+          (i32.const -51000)
+         )
+        )
+        (block
+         (drop
+          (i32.const 5999)
+         )
+         (drop
+          (i32.const 51)
+         )
+        )
+       )
+       (unreachable)
+       (i32.const 10)
+      )
+     )
+    )
+    (block
+     (drop
+      (if (result i32)
+       (i32.const 9999)
+       (block (result i32)
+        (drop
+         (i32.const -51234)
+        )
+        (drop
+         (i32.const -51000)
+        )
+        (unreachable)
+        (i32.const 10)
+       )
+       (block (result i32)
+        (drop
+         (i32.const 5999)
+        )
+        (drop
+         (i32.const 51)
+        )
+        (unreachable)
+        (i32.const 10)
+       )
+      )
+     )
+    )
+   )
+  )
+  (unreachable)
+  (unreachable)
+ )
+ (func $no-grandparent
+  (if
+   (i32.const 9999)
+   (block
+    (drop
+     (i32.const -51234)
+    )
+    (drop
+     (i32.const -51000)
+    )
+    (unreachable)
+    (unreachable)
+   )
+   (block
+    (drop
+     (i32.const 5999)
+    )
+    (drop
+     (i32.const 51)
+    )
+    (unreachable)
+    (unreachable)
+   )
+  )
+ )
+ (func $yes-grandparent
+  (block
+   (if
+    (i32.const 9999)
+    (block
+     (drop
+      (i32.const -51234)
+     )
+     (drop
+      (i32.const -51000)
+     )
+    )
+    (block
+     (drop
+      (i32.const 5999)
+     )
+     (drop
+      (i32.const 51)
+     )
+    )
+   )
+   (unreachable)
+   (unreachable)
+  )
+ )
+ (func $ifs-named-block (param $x i32) (param $y i32) (result i32)
+  (block $out
+   (block $out2
+    (block
+     (drop
+      (local.get $x)
+     )
+     (block
+      (br_if $out
+       (local.get $y)
+      )
+      (nop)
+     )
+    )
+    (block
+     (if
+      (local.get $x)
+      (br_if $out
+       (local.get $y)
+      )
+      (br_if $out2
+       (local.get $y)
+      )
+     )
+     (nop)
+    )
+    (if
+     (i32.const 1234)
+     (if
+      (local.get $x)
+      (block
+       (nop)
+       (br_if $out
+        (local.get $y)
+       )
+       (nop)
+      )
+      (block
+       (nop)
+       (br_if $out2
+        (local.get $y)
+       )
+       (nop)
+      )
+     )
+    )
+    (if
+     (local.get $x)
+     (block $left
+      (br_if $left
+       (local.get $y)
+      )
+      (nop)
+     )
+     (block
+      (br_if $out
+       (local.get $y)
+      )
+      (nop)
+     )
+    )
+    (if
+     (local.get $x)
+     (block
+      (br_if $out
+       (local.get $y)
+      )
+      (nop)
+     )
+     (block $right
+      (br_if $right
+       (local.get $y)
+      )
+      (nop)
+     )
+    )
+   )
+   (return
+    (i32.const 10)
+   )
+  )
+  (return
+   (i32.const 20)
+  )
+ )
+ (func $block
+  (block $x
+   (if
+    (i32.const 0)
+    (br $x)
+   )
+   (if
+    (i32.const 0)
+    (br $x)
+   )
+   (br $x)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 2)
+  )
+ )
+ (func $block2
+  (block $x
+   (if
+    (i32.const 0)
+    (block
+     (drop
+      (i32.const 1)
+     )
+     (drop
+      (i32.const 333333)
+     )
+     (br $x)
+    )
+   )
+   (if
+    (i32.const 0)
+    (block
+     (drop
+      (i32.const 1)
+     )
+     (drop
+      (i32.const 2)
+     )
+     (br $x)
+    )
+   )
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 2)
+   )
+   (br $x)
+  )
+ )
+ (func $block3
+  (block $x
+   (if
+    (i32.const 0)
+    (block
+     (drop
+      (i32.const 1000)
+     )
+     (br $x)
+    )
+   )
+   (if
+    (i32.const 0)
+    (block
+     (drop
+      (i32.const 2000)
+     )
+     (drop
+      (i32.const 3000)
+     )
+     (br $x)
+    )
+   )
+   (drop
+    (i32.const 4000)
+   )
+   (drop
+    (i32.const 5000)
+   )
+   (drop
+    (i32.const 6000)
+   )
+   (br $x)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 2)
+  )
+ )
+ (func $mixture
+  (block $out
+   (block
+    (drop
+     (i32.const 1)
+    )
+    (block
+     (drop
+      (i32.const 2)
+     )
+     (nop)
+     (nop)
+     (nop)
+     (nop)
+     (nop)
+     (nop)
+     (br $out)
+    )
+   )
+  )
+  (block $out2
+   (block
+    (if
+     (i32.const 1)
+     (drop
+      (i32.const 3)
+     )
+     (block
+      (drop
+       (i32.const 4)
+      )
+      (drop
+       (i32.const 5)
+      )
+     )
+    )
+    (drop
+     (i32.const 2)
+    )
+    (nop)
+    (nop)
+    (nop)
+    (nop)
+    (nop)
+    (nop)
+    (br $out2)
+   )
+  )
+  (block
+   (block $out3
+    (block
+     (drop
+      (i32.const 1)
+     )
+     (block
+      (br $out3)
+     )
+    )
+    (block
+     (drop
+      (i32.const 1)
+     )
+     (block
+      (br $out3)
+     )
+    )
+    (br $out3)
+   )
+   (drop
+    (i32.const 2)
+   )
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+  )
+ )
+ (func $block-corners
+  (block
+   (block $x
+    (if
+     (i32.const 0)
+     (br $x)
+    )
+   )
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 2)
+   )
+  )
+  (drop
+   (block $y (result i32)
+    (if
+     (i32.const 0)
+     (block
+      (drop
+       (i32.const 1)
+      )
+      (drop
+       (i32.const 2)
+      )
+      (br $y
+       (i32.const 3)
+      )
+     )
+    )
+    (drop
+     (i32.const 1)
+    )
+    (drop
+     (i32.const 2)
+    )
+    (br $y
+     (i32.const 3)
+    )
+   )
+  )
+  (drop
+   (block $z (result i32)
+    (if
+     (i32.const 0)
+     (block
+      (drop
+       (i32.const 1)
+      )
+      (drop
+       (i32.const 2)
+      )
+      (br $z
+       (i32.const 2)
+      )
+     )
+    )
+    (drop
+     (i32.const 1)
+    )
+    (drop
+     (i32.const 2)
+    )
+    (i32.const 3)
+   )
+  )
+  (block $w
+   (if
+    (i32.const 0)
+    (block
+     (drop
+      (i32.const 1)
+     )
+     (drop
+      (i32.const 2)
+     )
+     (br_if $w
+      (i32.const 3)
+     )
+    )
+   )
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 2)
+   )
+  )
+  (block $x1
+   (if
+    (i32.const 0)
+    (block
+     (drop
+      (i32.const 1)
+     )
+     (drop
+      (i32.const 2)
+     )
+     (br $x1)
+     (nop)
+    )
+   )
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 2)
+   )
+  )
+  (block $side
+   (block $x2
+    (br_table $x2 $side
+     (i32.const 0)
+    )
+    (if
+     (i32.const 0)
+     (block
+      (drop
+       (i32.const 1)
+      )
+      (drop
+       (i32.const 2)
+      )
+      (br $x2)
+     )
+    )
+    (drop
+     (i32.const 1)
+    )
+    (drop
+     (i32.const 2)
+    )
+   )
+   (block $x3
+    (br_table $side $x3
+     (i32.const 0)
+    )
+    (if
+     (i32.const 0)
+     (block
+      (drop
+       (i32.const 1)
+      )
+      (drop
+       (i32.const 2)
+      )
+      (br $x3)
+     )
+    )
+    (drop
+     (i32.const 1)
+    )
+    (drop
+     (i32.const 2)
+    )
+   )
+  )
+ )
+ (func $terminating
+  (block $folding-inner0
+   (block
+    (if
+     (i32.const 1)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 2)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 3)
+     (br $folding-inner0)
+    )
+   )
+   (return)
+  )
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (unreachable)
+ )
+ (func $terminating-unreachable
+  (block $folding-inner0
+   (block
+    (if
+     (i32.const 1)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 2)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 3)
+     (br $folding-inner0)
+    )
+    (unreachable)
+   )
+  )
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (unreachable)
+ )
+ (func $terminating-value (result i32)
+  (block $folding-inner0
+   (return
+    (block (result i32)
+     (if
+      (i32.const 1)
+      (br $folding-inner0)
+     )
+     (if
+      (i32.const 2)
+      (br $folding-inner0)
+     )
+     (if
+      (i32.const 3)
+      (br $folding-inner0)
+     )
+     (i32.const 4)
+    )
+   )
+  )
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (unreachable)
+ )
+ (func $terminating-just-2
+  (block $folding-inner0
+   (block
+    (if
+     (i32.const 1)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 2)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 3)
+     (block
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (drop
+       (i32.const 10)
+      )
+      (unreachable)
+     )
+    )
+   )
+   (return)
+  )
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (unreachable)
+ )
+ (func $terminating-shortness
+  (block $folding-inner1
+   (block
+    (block $folding-inner0
+     (block
+      (if
+       (i32.const 1)
+       (br $folding-inner0)
+      )
+      (if
+       (i32.const 2)
+       (br $folding-inner1)
+      )
+      (if
+       (i32.const 3)
+       (block
+        (drop
+         (i32.const 10)
+        )
+        (br $folding-inner0)
+       )
+      )
+     )
+     (return)
+    )
+    (nop)
+    (br $folding-inner1)
+   )
+  )
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (unreachable)
+ )
+ (func $terminating-multiple-separate
+  (block $folding-inner1
+   (block
+    (block $folding-inner0
+     (block
+      (if
+       (i32.const 1)
+       (br $folding-inner0)
+      )
+      (if
+       (i32.const 1)
+       (br $folding-inner0)
+      )
+      (if
+       (i32.const 1)
+       (br $folding-inner1)
+      )
+      (if
+       (i32.const 1)
+       (br $folding-inner1)
+      )
+     )
+     (return)
+    )
+    (nop)
+    (nop)
+    (nop)
+    (nop)
+    (nop)
+    (nop)
+    (nop)
+    (nop)
+    (nop)
+    (nop)
+    (nop)
+    (drop
+     (i32.const 1)
+    )
+    (unreachable)
+   )
+  )
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (drop
+   (i32.const 2)
+  )
+  (unreachable)
+ )
+ (func $terminating-just-worth-it
+  (block $folding-inner0
+   (block
+    (if
+     (i32.const 1)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 2)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 3)
+     (br $folding-inner0)
+    )
+   )
+   (return)
+  )
+  (nop)
+  (nop)
+  (nop)
+  (unreachable)
+ )
+ (func $terminating-not-worth-it
+  (if
+   (i32.const 1)
+   (block
+    (nop)
+    (nop)
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 2)
+   (block
+    (nop)
+    (nop)
+    (unreachable)
+   )
+  )
+  (if
+   (i32.const 3)
+   (block
+    (nop)
+    (nop)
+    (unreachable)
+   )
+  )
+ )
+ (func $terminating-return
+  (block $folding-inner0
+   (block
+    (if
+     (i32.const 1)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 2)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 3)
+     (br $folding-inner0)
+    )
+   )
+   (return)
+  )
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (return)
+ )
+ (func $terminating-return-value (result i32)
+  (block $folding-inner0
+   (block
+    (if
+     (i32.const 1)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 2)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 3)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 3)
+     (block
+      (nop)
+      (return
+       (i32.add
+        (i32.const 111111111)
+        (i32.const 2222222)
+       )
+      )
+     )
+    )
+    (return
+     (i32.const 1234)
+    )
+   )
+  )
+  (nop)
+  (return
+   (i32.add
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+ )
+ (func $terminating-fallthrough-value (result i32)
+  (block $folding-inner0
+   (return
+    (block (result i32)
+     (if
+      (i32.const 1)
+      (br $folding-inner0)
+     )
+     (if
+      (i32.const 2)
+      (br $folding-inner0)
+     )
+     (if
+      (i32.const 3)
+      (br $folding-inner0)
+     )
+     (if
+      (i32.const 3)
+      (block
+       (nop)
+       (return
+        (i32.add
+         (i32.const 111111111)
+         (i32.const 2222222)
+        )
+       )
+      )
+     )
+     (i32.const 1234)
+    )
+   )
+  )
+  (nop)
+  (return
+   (i32.add
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+ )
+ (func $big-return (result i32)
+  (block $folding-inner0
+   (block
+    (if
+     (i32.const 1)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 2)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 3)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 4)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 5)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 6)
+     (br $folding-inner0)
+    )
+    (unreachable)
+   )
+  )
+  (return
+   (i32.add
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+ )
+ (func $return-mix (result i32)
+  (block $folding-inner0
+   (block
+    (if
+     (i32.const 1)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 2)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 3)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 4)
+     (br $folding-inner0)
+    )
+    (if
+     (i32.const 3)
+     (return
+      (i32.add
+       (i32.const 1)
+       (i32.const 234567)
+      )
+     )
+    )
+    (br $folding-inner0)
+   )
+  )
+  (return
+   (i32.add
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+ )
+ (func $just-unreachable
+  (unreachable)
+ )
+ (func $just-return (result i32)
+  (return
+   (i32.add
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+ )
+ (func $drop-if-with-value-but-unreachable
+  (if
+   (i32.const 0)
+   (nop)
+  )
+  (block
+   (drop
+    (i32.const 0)
+   )
+   (block
+    (nop)
+   )
+  )
+  (if
+   (i32.const 0)
+   (nop)
+   (unreachable)
+  )
+  (nop)
+  (drop
+   (block (result i32)
+    (drop
+     (unreachable)
+    )
+    (block (result i32)
+     (i32.add
+      (i32.const 1)
+      (i32.const 2)
+     )
+    )
+   )
+  )
+  (drop
+   (if (result i32)
+    (i32.const 0)
+    (i32.add
+     (i32.const 1)
+     (i32.const 2)
+    )
+    (i32.add
+     (i32.const 1)
+     (i32.const 333333333)
+    )
+   )
+  )
+ )
+ (func $nested-control-flow
+  (block $out
+   (block
+    (block $x
+     (if
+      (i32.const 0)
+      (br $x)
+     )
+     (if
+      (i32.const 0)
+      (br $x)
+     )
+     (br $x)
+    )
+    (if
+     (i32.const 1)
+     (br $out)
+    )
+    (drop
+     (i32.const 1)
+    )
+    (drop
+     (i32.const 2)
+    )
+   )
+   (drop
+    (i32.const 3)
+   )
+  )
+ )
+ (func $nested-control-flow-dangerous
+  (block $folding-inner0
+   (block $out
+    (block
+     (if
+      (i32.const 0)
+      (block
+       (if
+        (i32.const 1)
+        (br $out)
+       )
+       (br $folding-inner0)
+      )
+     )
+     (if
+      (i32.const 0)
+      (block
+       (if
+        (i32.const 1)
+        (br $out)
+       )
+       (br $folding-inner0)
+      )
+     )
+     (if
+      (i32.const 1)
+      (br $out)
+     )
+     (br $folding-inner0)
+    )
+    (drop
+     (i32.const 3)
+    )
+   )
+   (return)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 2)
+  )
+  (return)
+ )
+ (func $nested-control-flow-dangerous-but-ok
+  (block $folding-inner0
+   (block
+    (block $middle
+     (block
+      (if
+       (i32.const 0)
+       (block
+        (if
+         (i32.add
+          (i32.const 0)
+          (i32.const 1)
+         )
+         (br $middle)
+        )
+        (br $folding-inner0)
+       )
+      )
+      (if
+       (i32.const 0)
+       (block
+        (if
+         (i32.add
+          (i32.const 0)
+          (i32.const 1)
+         )
+         (br $middle)
+        )
+        (br $folding-inner0)
+       )
+      )
+      (if
+       (i32.add
+        (i32.const 0)
+        (i32.const 1)
+       )
+       (br $middle)
+      )
+      (br $folding-inner0)
+     )
+    )
+    (drop
+     (i32.const 3)
+    )
+   )
+   (return)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 2)
+  )
+  (return)
+ )
+ (func $nested-control-flow-dangerous-but-ok-b
+  (block $out
+   (block $middle
+    (block
+     (if
+      (i32.const 0)
+      (block
+       (if
+        (i32.add
+         (i32.const 0)
+         (i32.const 1)
+        )
+        (br $middle)
+       )
+       (br $out)
+      )
+     )
+     (if
+      (i32.const 0)
+      (block
+       (if
+        (i32.add
+         (i32.const 0)
+         (i32.const 1)
+        )
+        (br $middle)
+       )
+       (br $out)
+      )
+     )
+     (if
+      (i32.add
+       (i32.const 0)
+       (i32.const 1)
+      )
+      (br $middle)
+     )
+    )
+   )
+   (unreachable)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 2)
+  )
+  (drop
+   (i32.const 3)
+  )
+  (drop
+   (i32.const 4)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 2)
+  )
+  (drop
+   (i32.const 3)
+  )
+  (drop
+   (i32.const 4)
+  )
+ )
+ (func $nested-control-flow-dangerous-but-ok-c
+  (block $x
+   (block
+    (block $out
+     (block
+      (if
+       (i32.const 0)
+       (br $out)
+      )
+      (if
+       (i32.const 0)
+       (br $out)
+      )
+      (br $out)
+     )
+     (unreachable)
+    )
+    (if
+     (i32.add
+      (i32.const 0)
+      (i32.const 1)
+     )
+     (br $x)
+    )
+    (drop
+     (i32.const 1)
+    )
+    (drop
+     (i32.const 2)
+    )
+   )
+   (unreachable)
+  )
+  (drop
+   (i32.const 5)
+  )
+ )
+ (func $nested-control-flow-dangerous-but-ok-d
+  (block
+   (block $out
+    (block
+     (if
+      (i32.const 0)
+      (br $out)
+     )
+     (if
+      (i32.const 0)
+      (br $out)
+     )
+     (br $out)
+    )
+   )
+   (block $x
+    (if
+     (i32.add
+      (i32.const 0)
+      (i32.const 1)
+     )
+     (br $x)
+    )
+   )
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.const 3)
+  )
+ )
+ (func $if-suffix (param $x i32) (result i32)
+  (block
+   (if
+    (local.get $x)
+    (block
+    )
+    (drop
+     (call $if-suffix
+      (i32.const -1)
+     )
+    )
+   )
+   (local.set $x
+    (i32.const 1)
+   )
+  )
+  (block (result i32)
+   (if
+    (local.get $x)
+    (block
+    )
+    (drop
+     (call $if-suffix
+      (i32.const -2)
+     )
+    )
+   )
+   (i32.const 2)
+  )
+ )
+ (func $exnref_pop-test
+  (local $exn exnref)
+  (block $folding-inner0
+   (try
+    (do
+     (try
+      (do
+       (nop)
+      )
+      (catch
+       (local.set $exn
+        (pop exnref)
+       )
+       (br $folding-inner0)
+      )
+     )
+    )
+    (catch
+     (local.set $exn
+      (pop exnref)
+     )
+     (br $folding-inner0)
+    )
+   )
+   (return)
+  )
+  (drop
+   (i32.const 111)
+  )
+  (drop
+   (i32.const 222)
+  )
+  (drop
+   (i32.const 333)
+  )
+  (unreachable)
+ )
+ (func $br_on_exn-target-block
+  (local $exn exnref)
+  (block $x
+   (if
+    (i32.const 0)
+    (block
+     (drop
+      (i32.const 1)
+     )
+     (drop
+      (i32.const 2)
+     )
+     (br $x)
+    )
+   )
+   (if
+    (i32.const 0)
+    (block
+     (drop
+      (i32.const 1)
+     )
+     (drop
+      (i32.const 2)
+     )
+     (br $x)
+    )
+   )
+   (drop
+    (br_on_exn $x $e
+     (local.get $exn)
+    )
+   )
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 2)
+   )
+   (br $x)
+  )
+ )
+ (func $foo
+  (nop)
+ )
+ (func $try-call-optimize-terminating-tails (result exnref)
+  (try
+   (do
+    (call $foo)
+    (call $foo)
+    (call $foo)
+    (call $foo)
+    (return
+     (ref.null exn)
+    )
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+    (call $foo)
+    (call $foo)
+    (call $foo)
+    (call $foo)
+    (return
+     (ref.null exn)
+    )
+   )
+  )
+  (ref.null exn)
+ )
+ (func $try-call-optimize-expression-tails
+  (local $exn exnref)
+  (block $x
+   (try
+    (do
+     (local.set $exn
+      (pop exnref)
+     )
+     (call $foo)
+     (call $foo)
+     (call $foo)
+     (br $x)
+    )
+    (catch
+     (local.set $exn
+      (pop exnref)
+     )
+     (call $foo)
+     (call $foo)
+     (call $foo)
+     (br $x)
+    )
+   )
+   (unreachable)
+  )
+ )
+)
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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names_code-folding_all-features.wast
@@ -0,0 +1,1293 @@
+(module
+  (func $ifs
+    (if (i32.const 0) (nop))
+    (if (i32.const 0) (nop) (nop))
+    (if (i32.const 0) (nop) (unreachable))
+    (drop
+      (if (result i32) (i32.const 0)
+        (i32.add (i32.const 1) (i32.const 2))
+        (i32.add (i32.const 1) (i32.const 2))
+      )
+    )
+    (drop
+      (if (result i32) (i32.const 0)
+        (i32.add (i32.const 1) (i32.const 2))
+        (i32.add (i32.const 1) (i32.const 333333333))
+      )
+    )
+  )
+  (func $ifs-blocks
+    (if (i32.const 0)
+      (block
+        (nop)
+      )
+      (block
+        (nop)
+      )
+    )
+    (if (i32.const 0)
+      (block
+        (unreachable)
+        (nop)
+      )
+      (block
+        (nop)
+      )
+    )
+    (if (i32.const 0)
+      (block
+        (nop)
+      )
+      (block
+        (unreachable)
+        (nop)
+      )
+    )
+    (if (i32.const 0)
+      (block
+        (nop)
+        (unreachable)
+      )
+      (block
+        (nop)
+      )
+    )
+    (if (i32.const 0)
+      (block
+        (nop)
+      )
+      (block
+        (nop)
+        (unreachable)
+      )
+    )
+  )
+  (func $ifs-blocks-big
+    (if (i32.const 0)
+      (block
+        (drop (i32.add (i32.const 1) (i32.const 2)))
+      )
+      (block
+        (drop (i32.add (i32.const 1) (i32.const 2)))
+      )
+    )
+    (if (i32.const 0)
+      (block
+        (unreachable)
+        (drop (i32.add (i32.const 1) (i32.const 2)))
+      )
+      (block
+        (drop (i32.add (i32.const 1) (i32.const 2)))
+      )
+    )
+    (if (i32.const 0)
+      (block
+        (drop (i32.add (i32.const 1) (i32.const 2)))
+      )
+      (block
+        (unreachable)
+        (drop (i32.add (i32.const 1) (i32.const 2)))
+      )
+    )
+    (if (i32.const 0)
+      (block
+        (drop (i32.add (i32.const 1) (i32.const 2)))
+        (unreachable)
+      )
+      (block
+        (drop (i32.add (i32.const 1) (i32.const 2)))
+      )
+    )
+    (if (i32.const 0)
+      (block
+        (drop (i32.add (i32.const 1) (i32.const 2)))
+      )
+      (block
+        (drop (i32.add (i32.const 1) (i32.const 2)))
+        (unreachable)
+      )
+    )
+  )
+  (func $ifs-blocks-long
+    (if (i32.const 1)
+      (block
+        (drop (i32.const -1234))
+        (drop (i32.const -1000))
+        (drop (i32.const 1))
+        (nop)
+        (unreachable)
+      )
+      (block
+        (drop (i32.const 999))
+        (drop (i32.const 1))
+        (nop)
+        (unreachable)
+      )
+    )
+    (drop
+      (if (result i32) (i32.const 2)
+        (block (result i32)
+          (drop (i32.const -1234))
+          (drop (i32.const -1000))
+          (drop (i32.const 1))
+          (nop)
+          (unreachable)
+          (i32.const 2)
+        )
+        (block (result i32)
+          (drop (i32.const 999))
+          (drop (i32.const 1))
+          (nop)
+          (unreachable)
+          (i32.const 2)
+        )
+      )
+    )
+    (drop
+      (if (result i32) (i32.const 3)
+        (block (result i32)
+          (drop (i32.const -1234))
+          (drop (i32.const -1000))
+          (drop (i32.const 1))
+          (nop)
+          (i32.const 2)
+        )
+        (block (result i32)
+          (drop (i32.const 999))
+          (drop (i32.const 1))
+          (nop)
+          (i32.const 2)
+        )
+      )
+    )
+  )
+  (func $if-worth-it-i-dunno
+    ;; just 2, so not worth it
+    (if (i32.const 0) ;; (put them in ifs, so no block outside which would make us more confident in creating a block in hopes it would vanish)
+      (if (i32.const 0)
+        (block
+          (drop (i32.const -1234))
+          (drop (i32.const -1000))
+          (unreachable)
+          (unreachable)
+        )
+        (block
+          (drop (i32.const 999))
+          (drop (i32.const 1))
+          (unreachable)
+          (unreachable)
+        )
+      )
+    )
+    ;; 3, so why not
+    (if (i32.const 0) ;; (put them in ifs, so no block outside which would make us more confident in creating a block in hopes it would vanish)
+      (if (i32.const 0)
+        (block
+          (drop (i32.const -1234))
+          (drop (i32.const -1000))
+          (unreachable)
+          (unreachable)
+          (unreachable)
+        )
+        (block
+          (drop (i32.const 999))
+          (drop (i32.const 1))
+          (unreachable)
+          (unreachable)
+          (unreachable)
+        )
+      )
+    )
+    ;; just 2, but we'll empty out a block
+    (if (i32.const 0) ;; (put them in ifs, so no block outside which would make us more confident in creating a block in hopes it would vanish)
+      (if (i32.const 0)
+        (block
+          (unreachable)
+          (unreachable)
+        )
+        (block
+          (drop (i32.const 999))
+          (drop (i32.const 1))
+          (unreachable)
+          (unreachable)
+        )
+      )
+    )
+    ;; just 2, but we'll empty out a block
+    (if (i32.const 0) ;; (put them in ifs, so no block outside which would make us more confident in creating a block in hopes it would vanish)
+      (if (i32.const 0)
+        (block
+          (drop (i32.const -1234))
+          (drop (i32.const -1000))
+          (unreachable)
+          (unreachable)
+        )
+        (block
+          (unreachable)
+          (unreachable)
+        )
+      )
+    )
+    ;; just two, but on a block, so we hope to merge, and can optimize here
+    (block $a-holding-block
+      (if (i32.const 9999)
+        (block
+          (drop (i32.const -51234))
+          (drop (i32.const -51000))
+          (unreachable)
+          (unreachable)
+        )
+        (block
+          (drop (i32.const 5999))
+          (drop (i32.const 51))
+          (unreachable)
+          (unreachable)
+        )
+      )
+    )
+    ;; with value
+    (drop
+      (block $b-holding-block (result i32)
+        (if (result i32) (i32.const 9999)
+          (block (result i32)
+            (drop (i32.const -51234))
+            (drop (i32.const -51000))
+            (unreachable)
+            (i32.const 10)
+          )
+          (block (result i32)
+            (drop (i32.const 5999))
+            (drop (i32.const 51))
+            (unreachable)
+            (i32.const 10)
+          )
+        )
+      )
+    )
+    ;; oops, something in between
+    (block $c-holding-block
+      (drop
+        (if (result i32) (i32.const 9999)
+          (block (result i32)
+            (drop (i32.const -51234))
+            (drop (i32.const -51000))
+            (unreachable)
+            (i32.const 10)
+          )
+          (block (result i32)
+            (drop (i32.const 5999))
+            (drop (i32.const 51))
+            (unreachable)
+            (i32.const 10)
+          )
+        )
+      )
+    )
+  )
+  (func $no-grandparent
+    ;; if we had a parent block, we might optimize this
+    (if (i32.const 9999)
+      (block
+        (drop (i32.const -51234))
+        (drop (i32.const -51000))
+        (unreachable)
+        (unreachable)
+      )
+      (block
+        (drop (i32.const 5999))
+        (drop (i32.const 51))
+        (unreachable)
+        (unreachable)
+      )
+    )
+  )
+  (func $yes-grandparent
+    (block
+      (if (i32.const 9999)
+        (block
+          (drop (i32.const -51234))
+          (drop (i32.const -51000))
+          (unreachable)
+          (unreachable)
+        )
+        (block
+          (drop (i32.const 5999))
+          (drop (i32.const 51))
+          (unreachable)
+          (unreachable)
+        )
+      )
+    )
+  )
+  (func $ifs-named-block (param $x i32) (param $y i32) (result i32)
+    (block $out
+      (block $out2
+        (if (local.get $x)
+          (block
+            (br_if $out (local.get $y i32))
+            (nop)
+          )
+          (block
+            (br_if $out (local.get $y i32))
+            (nop)
+          )
+        )
+        (if (local.get $x)
+          (block
+            (br_if $out (local.get $y i32))
+            (nop)
+          )
+          (block
+            (br_if $out2 (local.get $y i32))
+            (nop)
+          )
+        )
+        (if (i32.const 1234)
+          (if (local.get $x)
+            (block
+              (nop)
+              (br_if $out (local.get $y i32))
+              (nop)
+            )
+            (block
+              (nop)
+              (br_if $out2 (local.get $y i32))
+              (nop)
+            )
+          )
+        )
+        (if (local.get $x)
+          (block $left
+            (br_if $left (local.get $y i32))
+            (nop)
+          )
+          (block
+            (br_if $out (local.get $y i32))
+            (nop)
+          )
+        )
+        (if (local.get $x)
+          (block
+            (br_if $out (local.get $y i32))
+            (nop)
+          )
+          (block $right
+            (br_if $right (local.get $y i32))
+            (nop)
+          )
+        )
+      )
+      (return (i32.const 10))
+    )
+    (return (i32.const 20))
+  )
+  (func $block
+    (block $x
+      (if (i32.const 0)
+        (block
+          (drop (i32.const 1))
+          (drop (i32.const 2))
+          (br $x)
+        )
+      )
+      (if (i32.const 0)
+        (block
+          (drop (i32.const 1))
+          (drop (i32.const 2))
+          (br $x)
+        )
+      )
+      ;; no fallthrough, another thing to merge
+      (drop (i32.const 1))
+      (drop (i32.const 2))
+      (br $x)
+    )
+  )
+  (func $block2
+    (block $x
+      (if (i32.const 0)
+        (block
+          (drop (i32.const 1))
+          (drop (i32.const 333333))
+          (br $x)
+        )
+      )
+      (if (i32.const 0)
+        (block
+          (drop (i32.const 1))
+          (drop (i32.const 2))
+          (br $x)
+        )
+      )
+      ;; no fallthrough, another thing to merge
+      (drop (i32.const 1))
+      (drop (i32.const 2))
+      (br $x)
+    )
+  )
+  (func $block3
+    (block $x
+      (if (i32.const 0)
+        (block
+          (drop (i32.const 1000))
+          (drop (i32.const 1))
+          (drop (i32.const 2))
+          (br $x)
+        )
+      )
+      (if (i32.const 0)
+        (block
+          (drop (i32.const 2000))
+          (drop (i32.const 3000))
+          (drop (i32.const 1))
+          (drop (i32.const 2))
+          (br $x)
+        )
+      )
+      (drop (i32.const 4000))
+      (drop (i32.const 5000))
+      (drop (i32.const 6000))
+      ;; no fallthrough, another thing to merge
+      (drop (i32.const 1))
+      (drop (i32.const 2))
+      (br $x)
+    )
+  )
+  (func $mixture
+    (block $out ;; then we reach the block, and the tail infos are stale, should ignore
+      (if (i32.const 1) ;; then we optimize the if, pushing those brs outside!
+        (block
+          (drop (i32.const 2)) ;; first we note the block tails for $out
+          (nop) (nop) (nop) (nop) (nop) (nop) ;; totally worth it
+          (br $out)
+        )
+        (block
+          (drop (i32.const 2))
+          (nop) (nop) (nop) (nop) (nop) (nop)
+          (br $out)
+        )
+      )
+    )
+    (block $out2
+      (if (i32.const 1)
+        (block
+          (drop (i32.const 3)) ;; leave something
+          (drop (i32.const 2))
+          (nop) (nop) (nop) (nop) (nop) (nop)
+          (br $out2)
+        )
+        (block
+          (drop (i32.const 4)) ;; leave something
+          (drop (i32.const 5)) ;; leave something
+          (drop (i32.const 2))
+          (nop) (nop) (nop) (nop) (nop) (nop)
+          (br $out2)
+        )
+      )
+    )
+    ;; now a case where do **do** want to fold for the block (which we can only do in a later pass)
+    (block $out3
+      (if (i32.const 1)
+        (block
+          (drop (i32.const 2))
+          (nop) (nop) (nop) (nop) (nop) (nop)
+          (br $out3)
+        )
+        (block
+          (drop (i32.const 2))
+          (nop) (nop) (nop) (nop) (nop) (nop)
+          (br $out3)
+        )
+      )
+      (if (i32.const 1)
+        (block
+          (drop (i32.const 2))
+          (nop) (nop) (nop) (nop) (nop) (nop)
+          (br $out3)
+        )
+        (block
+          (drop (i32.const 2))
+          (nop) (nop) (nop) (nop) (nop) (nop)
+          (br $out3)
+        )
+      )
+      (drop (i32.const 2))
+      (nop) (nop) (nop) (nop) (nop) (nop)
+      (br $out3)
+    )
+  )
+  (func $block-corners
+    ;; these should be merged
+    (block $x
+      (if (i32.const 0)
+        (block
+          (drop (i32.const 1))
+          (drop (i32.const 2))
+          (br $x)
+        )
+      )
+      (drop (i32.const 1))
+      (drop (i32.const 2))
+    )
+    ;; these should not
+    ;; values
+    (drop
+      (block $y (result i32)
+        (if (i32.const 0)
+          (block
+            (drop (i32.const 1))
+            (drop (i32.const 2))
+            (br $y (i32.const 3))
+          )
+        )
+        (drop (i32.const 1))
+        (drop (i32.const 2))
+        (br $y (i32.const 3))
+      )
+    )
+    (drop
+      (block $z (result i32)
+        (if (i32.const 0)
+          (block
+            (drop (i32.const 1))
+            (drop (i32.const 2))
+            (br $z (i32.const 2))
+          )
+        )
+        (drop (i32.const 1))
+        (drop (i32.const 2))
+        (i32.const 3)
+      )
+    )
+    ;; condition
+    (block $w
+      (if (i32.const 0)
+        (block
+          (drop (i32.const 1))
+          (drop (i32.const 2))
+          (br_if $w (i32.const 3))
+        )
+      )
+      (drop (i32.const 1))
+      (drop (i32.const 2))
+    )
+    ;; not at the end
+    (block $x1
+      (if (i32.const 0)
+        (block
+          (drop (i32.const 1))
+          (drop (i32.const 2))
+          (br $x1)
+          (nop)
+        )
+      )
+      (drop (i32.const 1))
+      (drop (i32.const 2))
+    )
+    ;; switches
+    (block $side
+      (block $x2
+        (br_table $x2 $side (i32.const 0))
+        (if (i32.const 0)
+          (block
+            (drop (i32.const 1))
+            (drop (i32.const 2))
+            (br $x2)
+          )
+        )
+        (drop (i32.const 1))
+        (drop (i32.const 2))
+      )
+      (block $x3
+        (br_table $side $x3 (i32.const 0))
+        (if (i32.const 0)
+          (block
+            (drop (i32.const 1))
+            (drop (i32.const 2))
+            (br $x3)
+          )
+        )
+        (drop (i32.const 1))
+        (drop (i32.const 2))
+      )
+    )
+  )
+  (func $terminating
+    (if (i32.const 1)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+    (if (i32.const 2)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+    (if (i32.const 3)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+  )
+  (func $terminating-unreachable
+    (if (i32.const 1)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+    (if (i32.const 2)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+    (if (i32.const 3)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+    (unreachable)
+  )
+  (func $terminating-value (result i32)
+    (if (i32.const 1)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+    (if (i32.const 2)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+    (if (i32.const 3)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+    (i32.const 4)
+  )
+  (func $terminating-just-2
+    (if (i32.const 1)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+    (if (i32.const 2)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+    (if (i32.const 3)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (drop (i32.const 10))
+        (unreachable)
+      )
+    )
+  )
+  (func $terminating-shortness
+    (if (i32.const 1)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+    (if (i32.const 2)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) ;; shorter. we do the two long ones greedily, then the merged one and this can also be opted
+        (unreachable)
+      )
+    )
+    (if (i32.const 3)
+      (block
+        (drop (i32.const 10))
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+  )
+  (func $terminating-multiple-separate
+    (if (i32.const 1)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (drop (i32.const 1))
+        (unreachable)
+      )
+    )
+    (if (i32.const 1)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (drop (i32.const 1))
+        (unreachable)
+      )
+    )
+    (if (i32.const 1)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (drop (i32.const 2))
+        (unreachable)
+      )
+    )
+    (if (i32.const 1)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (drop (i32.const 2))
+        (unreachable)
+      )
+    )
+  )
+  (func $terminating-just-worth-it
+    (if (i32.const 1)
+      (block
+        (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+    (if (i32.const 2)
+      (block
+        (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+    (if (i32.const 3)
+      (block
+        (nop) (nop) (nop)
+        (unreachable)
+      )
+    )
+  )
+  (func $terminating-not-worth-it
+    (if (i32.const 1)
+      (block
+        (nop) (nop)
+        (unreachable)
+      )
+    )
+    (if (i32.const 2)
+      (block
+        (nop) (nop)
+        (unreachable)
+      )
+    )
+    (if (i32.const 3)
+      (block
+        (nop) (nop)
+        (unreachable)
+      )
+    )
+  )
+  (func $terminating-return
+    (if (i32.const 1)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (return)
+      )
+    )
+    (if (i32.const 2)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (return)
+      )
+    )
+    (if (i32.const 3)
+      (block
+        (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop)
+        (return)
+      )
+    )
+  )
+  (func $terminating-return-value (result i32)
+    (if (i32.const 1)
+      (block
+        (nop)
+        (return (i32.add (i32.const 1) (i32.const 2)))
+      )
+    )
+    (if (i32.const 2)
+      (block
+        (nop)
+        (return (i32.add (i32.const 1) (i32.const 2)))
+      )
+    )
+    (if (i32.const 3)
+      (block
+        (nop)
+        (return (i32.add (i32.const 1) (i32.const 2)))
+      )
+    )
+    (if (i32.const 3)
+      (block
+        (nop)
+        (return (i32.add (i32.const 111111111) (i32.const 2222222)))
+      )
+    )
+    (return (i32.const 1234))
+  )
+  (func $terminating-fallthrough-value (result i32)
+    (if (i32.const 1)
+      (block
+        (nop)
+        (return (i32.add (i32.const 1) (i32.const 2)))
+      )
+    )
+    (if (i32.const 2)
+      (block
+        (nop)
+        (return (i32.add (i32.const 1) (i32.const 2)))
+      )
+    )
+    (if (i32.const 3)
+      (block
+        (nop)
+        (return (i32.add (i32.const 1) (i32.const 2)))
+      )
+    )
+    (if (i32.const 3)
+      (block
+        (nop)
+        (return (i32.add (i32.const 111111111) (i32.const 2222222)))
+      )
+    )
+    (i32.const 1234)
+  )
+  (func $big-return (result i32)
+    (if (i32.const 1) (return (i32.add (i32.const 1) (i32.const 2))))
+    (if (i32.const 2) (return (i32.add (i32.const 1) (i32.const 2))))
+    (if (i32.const 3) (return (i32.add (i32.const 1) (i32.const 2))))
+    (if (i32.const 4) (return (i32.add (i32.const 1) (i32.const 2))))
+    (if (i32.const 5) (return (i32.add (i32.const 1) (i32.const 2))))
+    (if (i32.const 6) (return (i32.add (i32.const 1) (i32.const 2))))
+    (unreachable)
+  )
+  (func $return-mix (result i32)
+    (if (i32.const 1) (return (i32.add (i32.const 1) (i32.const 2))))
+    (if (i32.const 2) (return (i32.add (i32.const 1) (i32.const 2))))
+    (if (i32.const 3) (return (i32.add (i32.const 1) (i32.const 2))))
+    (if (i32.const 4) (return (i32.add (i32.const 1) (i32.const 2))))
+    (if (i32.const 3) (return (i32.add (i32.const 1) (i32.const 234567))))
+    (return (i32.add (i32.const 1) (i32.const 2))) ;; on a block, and the toplevel in fact
+  )
+  (func $just-unreachable
+    (unreachable)
+  )
+  (func $just-return (result i32)
+    (return (i32.add (i32.const 1) (i32.const 2))) ;; on a block, and the toplevel in fact
+  )
+  (func $drop-if-with-value-but-unreachable
+   (block $label$0
+    (if
+     (i32.const 0)
+     (block $label$1
+      (nop)
+     )
+    )
+    (if
+     (i32.const 0)
+     (block $label$2
+      (nop)
+     )
+     (block $label$3
+      (nop)
+     )
+    )
+    (if
+     (i32.const 0)
+     (block $label$4
+      (nop)
+     )
+     (block $label$5
+      (unreachable)
+     )
+    )
+    (nop)
+    (drop
+     (if (result i32) ;; we replace this if, must replace with same type!
+      (unreachable)
+      (block $label$6 (result i32)
+       (i32.add
+        (i32.const 1)
+        (i32.const 2)
+       )
+      )
+      (block $label$7 (result i32)
+       (i32.add
+        (i32.const 1)
+        (i32.const 2)
+       )
+      )
+     )
+    )
+    (drop
+     (if (result i32)
+      (i32.const 0)
+      (block $label$8 (result i32)
+       (i32.add
+        (i32.const 1)
+        (i32.const 2)
+       )
+      )
+      (block $label$9 (result i32)
+       (i32.add
+        (i32.const 1)
+        (i32.const 333333333)
+       )
+      )
+     )
+    )
+   )
+  )
+  (func $nested-control-flow
+    (block $out
+      (block $x
+        (if (i32.const 0)
+          (block
+            (if (i32.const 1)
+              (br $out)
+            )
+            (drop (i32.const 1))
+            (drop (i32.const 2))
+            (br $x)
+          )
+        )
+        (if (i32.const 0)
+          (block
+            (if (i32.const 1)
+              (br $out)
+            )
+            (drop (i32.const 1))
+            (drop (i32.const 2))
+            (br $x)
+          )
+        )
+        ;; no fallthrough, another thing to merge
+        (if (i32.const 1)
+          (br $out)
+        )
+        (drop (i32.const 1))
+        (drop (i32.const 2))
+        (br $x)
+      )
+      (drop (i32.const 3))
+    )
+  )
+  (func $nested-control-flow-dangerous
+    (block $out
+      (block $x
+        (if (i32.const 0)
+          (block
+            (if (i32.const 1)
+              (br $out) ;; this br cannot be moved out of the $out block!
+            )
+            (drop (i32.const 1))
+            (drop (i32.const 2))
+            (return)
+          )
+        )
+        (if (i32.const 0)
+          (block
+            (if (i32.const 1)
+              (br $out)
+            )
+            (drop (i32.const 1))
+            (drop (i32.const 2))
+            (return)
+          )
+        )
+        ;; no fallthrough, another thing to merge
+        (if (i32.const 1)
+          (br $out)
+        )
+        (drop (i32.const 1))
+        (drop (i32.const 2))
+        (return)
+      )
+      (drop (i32.const 3))
+    )
+  )
+  (func $nested-control-flow-dangerous-but-ok
+    (block $out
+      (block $middle
+        (block $x
+          (if (i32.const 0)
+            (block
+              (if (i32.add (i32.const 0) (i32.const 1))
+                (br $middle)
+              )
+              (drop (i32.const 1))
+              (drop (i32.const 2))
+              (return)
+            )
+          )
+          (if (i32.const 0)
+            (block
+              (if (i32.add (i32.const 0) (i32.const 1))
+                (br $middle)
+              )
+              (drop (i32.const 1))
+              (drop (i32.const 2))
+              (return)
+            )
+          )
+          ;; no fallthrough, another thing to merge
+          (if (i32.add (i32.const 0) (i32.const 1))
+            (br $middle)
+          )
+          (drop (i32.const 1))
+          (drop (i32.const 2))
+          (return)
+        )
+      )
+      (drop (i32.const 3))
+    )
+  )
+  (func $nested-control-flow-dangerous-but-ok-b
+    (block $out
+      (block $middle
+        (block $x
+          (if (i32.const 0)
+            (block
+              (if (i32.add (i32.const 0) (i32.const 1))
+                (br $middle) ;; this is dangerous - we branch to middle with is inside out, so we can't move this out of out
+              )
+              (drop (i32.const 1))
+              (drop (i32.const 2))
+              (drop (i32.const 3))
+              (drop (i32.const 4))
+              (drop (i32.const 1))
+              (drop (i32.const 2))
+              (drop (i32.const 3))
+              (drop (i32.const 4))
+              (br $out)
+            )
+          )
+          (if (i32.const 0)
+            (block
+              (if (i32.add (i32.const 0) (i32.const 1))
+                (br $middle)
+              )
+              (drop (i32.const 1))
+              (drop (i32.const 2))
+              (drop (i32.const 3))
+              (drop (i32.const 4))
+              (drop (i32.const 1))
+              (drop (i32.const 2))
+              (drop (i32.const 3))
+              (drop (i32.const 4))
+              (br $out)
+            )
+          )
+          ;; no fallthrough, another thing to merge
+          (if (i32.add (i32.const 0) (i32.const 1))
+            (br $middle)
+          )
+        )
+      )
+      (unreachable) ;; no fallthrough
+    )
+  )
+  (func $nested-control-flow-dangerous-but-ok-c
+    (block $x
+      (block $out
+        (block $middle
+          (if (i32.const 0)
+            (block
+              (if (i32.add (i32.const 0) (i32.const 1))
+                (br $x) ;; this is ok - we branch to x which is outside of out
+              )
+              (drop (i32.const 1))
+              (drop (i32.const 2))
+              (br $out)
+            )
+          )
+          (if (i32.const 0)
+            (block
+              (if (i32.add (i32.const 0) (i32.const 1))
+                (br $x)
+              )
+              (drop (i32.const 1))
+              (drop (i32.const 2))
+              (br $out)
+            )
+          )
+          ;; no fallthrough, another thing to merge
+          (if (i32.add (i32.const 0) (i32.const 1))
+            (br $x)
+          )
+          (drop (i32.const 1))
+          (drop (i32.const 2))
+          (br $out)
+        )
+        (unreachable) ;; no fallthrough
+      )
+      (unreachable) ;; no fallthrough
+    )
+    (drop (i32.const 5))
+  )
+  (func $nested-control-flow-dangerous-but-ok-d
+    (block $out
+      (block $middle
+        (if (i32.const 0)
+          (block
+            (block $x
+              (if (i32.add (i32.const 0) (i32.const 1))
+                (br $x) ;; this is ok - we branch to x which is nested in us
+              )
+            )
+            (drop (i32.const 1))
+            (drop (i32.const 2))
+            (br $out)
+          )
+        )
+        (if (i32.const 0)
+          (block
+            (block $x
+              (if (i32.add (i32.const 0) (i32.const 1))
+                (br $x) ;; this is ok - we branch to x which is nested in us
+              )
+            )
+            (drop (i32.const 1))
+            (drop (i32.const 2))
+            (br $out)
+          )
+        )
+        ;; no fallthrough, another thing to merge
+        (block $x
+          (if (i32.add (i32.const 0) (i32.const 1))
+            (br $x) ;; this is ok - we branch to x which is nested in us
+          )
+        )
+        (drop (i32.const 1))
+        (drop (i32.const 2))
+        (br $out)
+      )
+    )
+    (drop (i32.const 3))
+  )
+  (func $if-suffix (param $x i32) (result i32)
+    (if
+      (local.get $x)
+      (local.set $x (i32.const 1))
+      (block
+        (drop (call $if-suffix (i32.const -1)))
+        (local.set $x (i32.const 1))
+      )
+    )
+    (if (result i32)
+      (local.get $x)
+      (i32.const 2)
+      (block (result i32)
+        (drop (call $if-suffix (i32.const -2)))
+        (i32.const 2)
+      )
+    )
+  )
+
+  (func $exnref_pop-test (local $exn exnref)
+    (try
+      (do
+        (try
+          (do)
+          (catch
+            ;; Expressions containing (pop exnref) should NOT be taken out and
+            ;; folded.
+            (local.set $exn (pop exnref))
+            (drop (i32.const 111))
+            (drop (i32.const 222))
+            (drop (i32.const 333))
+            (unreachable)
+          )
+        )
+      )
+      (catch
+        (local.set $exn (pop exnref))
+        (drop (i32.const 111))
+        (drop (i32.const 222))
+        (drop (i32.const 333))
+        (unreachable)
+      )
+    )
+  )
+
+  (event $e (attr 0)) ;; exception with no param
+  (func $br_on_exn-target-block (local $exn exnref)
+    ;; Here this block $x is targeted by br_on_exn, so code folding out of this
+    ;; block should NOT happen.
+    (block $x
+      (if (i32.const 0)
+        (block
+          (drop (i32.const 1))
+          (drop (i32.const 2))
+          (br $x)
+        )
+      )
+      (if (i32.const 0)
+        (block
+          (drop (i32.const 1))
+          (drop (i32.const 2))
+          (br $x)
+        )
+      )
+      (drop (br_on_exn $x $e (local.get $exn)))
+      ;; no fallthrough, another thing to merge
+      (drop (i32.const 1))
+      (drop (i32.const 2))
+      (br $x)
+    )
+  )
+
+  (func $foo)
+  (func $try-call-optimize-terminating-tails (result exnref)
+    (try
+      (do
+        ;; Expressions that can throw should NOT be taken out of 'try' scope.
+        (call $foo)
+        (call $foo)
+        (call $foo)
+        (call $foo)
+        (return (ref.null exn))
+      )
+      (catch
+        (drop (pop exnref))
+        (call $foo)
+        (call $foo)
+        (call $foo)
+        (call $foo)
+        (return (ref.null exn))
+      )
+    )
+    (ref.null exn)
+  )
+
+  (func $try-call-optimize-expression-tails (local $exn exnref)
+    (block $x
+      (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)
+          (br $x)
+        )
+        (catch
+          (local.set $exn (pop exnref))
+          (call $foo)
+          (call $foo)
+          (call $foo)
+          (br $x)
+        )
+      )
+      (unreachable)
+    )
+  )
+)
diff --git a/binaryen/test/passes/remove-unused-names_merge-blocks_all-features.txt b/binaryen/test/passes/remove-unused-names_merge-blocks_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names_merge-blocks_all-features.txt
@@ -0,0 +1,1746 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (type $none_=>_f64 (func (result f64)))
+ (memory $0 (shared 256 256))
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $call-i)
+ (func $call-i (param $0 i32)
+  (nop)
+ )
+ (func $call-ii (param $0 i32) (param $1 i32)
+  (nop)
+ )
+ (func $call-iii (param $0 i32) (param $1 i32) (param $2 i32)
+  (nop)
+ )
+ (func $b0-yes (param $i1 i32)
+  (drop
+   (i32.const 10)
+  )
+ )
+ (func $b0-no (param $i1 i32)
+  (block $topmost
+   (block $block0
+    (br $block0)
+   )
+   (br $topmost)
+  )
+ )
+ (func $b0-br-but-ok (param $i1 i32)
+  (block $topmost
+   (br $topmost)
+  )
+ )
+ (func $b1-yes (param $i1 i32)
+  (drop
+   (i32.const 10)
+  )
+ )
+ (func $b2-yes (param $i1 i32)
+  (drop
+   (i32.const 5)
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 15)
+  )
+ )
+ (func $b3-yes (param $i1 i32)
+  (drop
+   (i32.const 3)
+  )
+  (drop
+   (i32.const 6)
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 15)
+  )
+  (drop
+   (i32.const 20)
+  )
+ )
+ (func $b4 (param $i1 i32)
+  (block $inner
+   (drop
+    (i32.const 10)
+   )
+   (br $inner)
+  )
+ )
+ (func $b5 (param $i1 i32)
+  (block $middle
+   (drop
+    (i32.const 10)
+   )
+   (block $inner
+    (br $inner)
+   )
+   (br $middle)
+  )
+ )
+ (func $b6 (param $i1 i32)
+  (drop
+   (i32.const 5)
+  )
+  (drop
+   (i32.const 10)
+  )
+  (block $inner
+   (br $inner)
+  )
+  (drop
+   (i32.const 15)
+  )
+ )
+ (func $b7 (param $i1 i32)
+  (drop
+   (i32.const 3)
+  )
+  (drop
+   (i32.const 6)
+  )
+  (drop
+   (i32.const 10)
+  )
+  (block $inner
+   (br $inner)
+  )
+  (drop
+   (i32.const 15)
+  )
+  (block $middle
+   (br $middle)
+  )
+  (drop
+   (i32.const 20)
+  )
+ )
+ (func $unary
+  (local $x i32)
+  (drop
+   (i32.eqz
+    (block (result i32)
+     (i32.const 10)
+    )
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.eqz
+    (i32.const 20)
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 20)
+  )
+  (drop
+   (i32.eqz
+    (i32.const 30)
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (local.set $x
+   (i32.const 20)
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.load
+    (i32.const 20)
+   )
+  )
+  (return
+   (block
+    (drop
+     (i32.const 10)
+    )
+    (unreachable)
+   )
+  )
+ )
+ (func $binary
+  (drop
+   (i32.add
+    (block (result i32)
+     (i32.const 10)
+    )
+    (i32.const 20)
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.add
+    (i32.const 20)
+    (i32.const 30)
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 20)
+  )
+  (drop
+   (i32.add
+    (i32.const 30)
+    (i32.const 40)
+   )
+  )
+  (drop
+   (i32.add
+    (i32.const 10)
+    (block (result i32)
+     (i32.const 20)
+    )
+   )
+  )
+  (drop
+   (i32.const 20)
+  )
+  (drop
+   (i32.add
+    (i32.const 10)
+    (i32.const 30)
+   )
+  )
+  (drop
+   (i32.const 20)
+  )
+  (drop
+   (i32.const 30)
+  )
+  (drop
+   (i32.add
+    (i32.const 10)
+    (i32.const 40)
+   )
+  )
+  (drop
+   (i32.add
+    (block (result i32)
+     (i32.const 10)
+    )
+    (block (result i32)
+     (i32.const 20)
+    )
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 30)
+  )
+  (drop
+   (i32.add
+    (i32.const 20)
+    (i32.const 40)
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 20)
+  )
+  (drop
+   (i32.const 40)
+  )
+  (drop
+   (i32.const 50)
+  )
+  (drop
+   (i32.add
+    (i32.const 30)
+    (i32.const 60)
+   )
+  )
+  (drop
+   (i32.const 20)
+  )
+  (i32.store
+   (i32.const 10)
+   (i32.const 30)
+  )
+  (drop
+   (i32.const 10)
+  )
+  (i32.store
+   (i32.const 20)
+   (i32.const 30)
+  )
+  (drop
+   (block
+    (drop
+     (i32.const 10)
+    )
+    (i32.add
+     (unreachable)
+     (i32.const 20)
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (unreachable)
+    (drop
+     (i32.const 20)
+    )
+    (i32.add
+     (i32.const 10)
+     (i32.const 30)
+    )
+   )
+  )
+ )
+ (func $trinary
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 30)
+  )
+  (drop
+   (i32.const 50)
+  )
+  (drop
+   (select
+    (i32.const 20)
+    (i32.const 40)
+    (i32.const 60)
+   )
+  )
+  (drop
+   (i32.const 20)
+  )
+  (drop
+   (i32.const 40)
+  )
+  (drop
+   (select
+    (block (result i32)
+     (i32.const 10)
+    )
+    (i32.const 30)
+    (i32.const 50)
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 40)
+  )
+  (drop
+   (select
+    (i32.const 20)
+    (block (result i32)
+     (i32.const 30)
+    )
+    (i32.const 50)
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 30)
+  )
+  (drop
+   (select
+    (i32.const 20)
+    (i32.const 40)
+    (block (result i32)
+     (i32.const 50)
+    )
+   )
+  )
+  (drop
+   (i32.const 30)
+  )
+  (drop
+   (select
+    (block (result i32)
+     (i32.const 10)
+    )
+    (block (result i32)
+     (i32.const 20)
+    )
+    (i32.const 40)
+   )
+  )
+  (drop
+   (i32.const 20)
+  )
+  (drop
+   (select
+    (block (result i32)
+     (i32.const 10)
+    )
+    (i32.const 30)
+    (block (result i32)
+     (i32.const 40)
+    )
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (select
+    (i32.const 20)
+    (block (result i32)
+     (i32.const 30)
+    )
+    (block (result i32)
+     (i32.const 40)
+    )
+   )
+  )
+  (drop
+   (select
+    (block (result i32)
+     (unreachable)
+     (i32.const 20)
+    )
+    (block (result i32)
+     (drop
+      (i32.const 30)
+     )
+     (i32.const 40)
+    )
+    (block (result i32)
+     (drop
+      (i32.const 50)
+     )
+     (i32.const 60)
+    )
+   )
+  )
+  (drop
+   (select
+    (block (result i32)
+     (drop
+      (i32.const 10)
+     )
+     (unreachable)
+    )
+    (block (result i32)
+     (drop
+      (i32.const 30)
+     )
+     (i32.const 40)
+    )
+    (block (result i32)
+     (drop
+      (i32.const 50)
+     )
+     (i32.const 60)
+    )
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (select
+    (i32.const 20)
+    (block (result i32)
+     (unreachable)
+     (i32.const 40)
+    )
+    (block (result i32)
+     (drop
+      (i32.const 50)
+     )
+     (i32.const 60)
+    )
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (select
+    (i32.const 20)
+    (block (result i32)
+     (drop
+      (i32.const 30)
+     )
+     (unreachable)
+    )
+    (block (result i32)
+     (drop
+      (i32.const 50)
+     )
+     (i32.const 60)
+    )
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 30)
+  )
+  (drop
+   (select
+    (i32.const 20)
+    (i32.const 40)
+    (block (result i32)
+     (unreachable)
+     (i32.const 60)
+    )
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 30)
+  )
+  (drop
+   (select
+    (i32.const 20)
+    (i32.const 40)
+    (block (result i32)
+     (drop
+      (i32.const 50)
+     )
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $breaks
+  (block $out
+   (drop
+    (i32.const 10)
+   )
+   (drop
+    (i32.const 20)
+   )
+   (br $out)
+   (drop
+    (i32.const 10)
+   )
+   (br_if $out
+    (i32.const 20)
+   )
+   (drop
+    (i32.const 10)
+   )
+   (drop
+    (i32.const 20)
+   )
+   (drop
+    (i32.const 30)
+   )
+   (br_if $out
+    (i32.const 40)
+   )
+   (drop
+    (i32.const 10)
+   )
+   (br_table $out $out
+    (i32.const 20)
+   )
+   (drop
+    (block $out2 (result i32)
+     (drop
+      (i32.const 10)
+     )
+     (drop
+      (i32.const 30)
+     )
+     (br_table $out2 $out2
+      (i32.const 20)
+      (i32.const 40)
+     )
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $calls
+  (call $call-i
+   (block (result i32)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (call $call-i
+   (i32.const 20)
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 20)
+  )
+  (call $call-i
+   (i32.const 30)
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 30)
+  )
+  (call $call-ii
+   (i32.const 20)
+   (i32.const 40)
+  )
+  (call $call-ii
+   (block (result i32)
+    (unreachable)
+    (i32.const 10)
+   )
+   (block (result i32)
+    (drop
+     (i32.const 20)
+    )
+    (i32.const 30)
+   )
+  )
+  (call $call-ii
+   (block (result i32)
+    (drop
+     (i32.const 10)
+    )
+    (unreachable)
+   )
+   (block (result i32)
+    (drop
+     (i32.const 20)
+    )
+    (i32.const 30)
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (call $call-ii
+   (i32.const 20)
+   (block (result i32)
+    (unreachable)
+    (i32.const 30)
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (call $call-ii
+   (i32.const 20)
+   (block (result i32)
+    (drop
+     (i32.const 30)
+    )
+    (unreachable)
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 30)
+  )
+  (drop
+   (i32.const 50)
+  )
+  (call $call-iii
+   (i32.const 20)
+   (i32.const 40)
+   (i32.const 60)
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 40)
+  )
+  (call $call-iii
+   (i32.const 20)
+   (i32.const 30)
+   (i32.const 50)
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 30)
+  )
+  (drop
+   (i32.const 50)
+  )
+  (call_indirect (type $i32_i32_=>_none)
+   (i32.const 20)
+   (i32.const 40)
+   (i32.const 60)
+  )
+  (call_indirect (type $i32_i32_=>_none)
+   (unreachable)
+   (block (result i32)
+    (drop
+     (i32.const 30)
+    )
+    (i32.const 40)
+   )
+   (block (result i32)
+    (drop
+     (i32.const 50)
+    )
+    (i32.const 60)
+   )
+  )
+  (drop
+   (i32.const 31)
+  )
+  (call_indirect (type $i32_i32_=>_none)
+   (i32.const 41)
+   (unreachable)
+   (block (result i32)
+    (drop
+     (i32.const 51)
+    )
+    (i32.const 61)
+   )
+  )
+  (drop
+   (i32.const 32)
+  )
+  (drop
+   (i32.const 52)
+  )
+  (call_indirect (type $i32_i32_=>_none)
+   (i32.const 42)
+   (i32.const 62)
+   (unreachable)
+  )
+ )
+ (func $atomics
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.const 30)
+  )
+  (drop
+   (i32.const 50)
+  )
+  (drop
+   (i32.atomic.rmw.cmpxchg
+    (i32.const 20)
+    (i32.const 40)
+    (i32.const 60)
+   )
+  )
+  (drop
+   (i32.const 10)
+  )
+  (drop
+   (i32.atomic.rmw.add
+    (i32.const 20)
+    (i32.const 30)
+   )
+  )
+ )
+ (func $mix-select (param $x i32)
+  (drop
+   (select
+    (local.get $x)
+    (local.get $x)
+    (block (result i32)
+     (local.set $x
+      (i32.const 1)
+     )
+     (i32.const 2)
+    )
+   )
+  )
+ )
+ (func $block-type-change
+  (local $0 f64)
+  (local $1 f64)
+  (if
+   (block (result i32)
+    (nop)
+    (f64.gt
+     (local.get $0)
+     (local.get $1)
+    )
+   )
+   (nop)
+  )
+ )
+ (func $do-reorder (param $x i32)
+  (local $y i32)
+  (if
+   (i32.const 1)
+   (block
+    (local.set $y
+     (i32.const 5)
+    )
+    (local.set $x
+     (i32.le_u
+      (local.get $x)
+      (i32.const 10)
+     )
+    )
+   )
+  )
+ )
+ (func $do-not-reorder (param $x i32)
+  (local $y i32)
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.le_u
+     (local.get $y)
+     (block (result i32)
+      (local.set $y
+       (i32.const 5)
+      )
+      (i32.const 10)
+     )
+    )
+   )
+  )
+ )
+ (func $return-different-type (result i32)
+  (drop
+   (f64.abs
+    (block
+     (drop
+      (i32.const 2)
+     )
+     (return
+      (i32.const 1)
+     )
+    )
+   )
+  )
+  (unreachable)
+ )
+ (func $drop-unreachable (result i32)
+  (local $0 i32)
+  (drop
+   (block (result i32)
+    (unreachable)
+   )
+  )
+  (unreachable)
+ )
+ (func $concrete_finale_in_unreachable (result f64)
+  (drop
+   (block (result f64)
+    (unreachable)
+    (f64.const 6.322092475576799e-96)
+   )
+  )
+  (f64.const -1)
+ )
+ (func $dont-move-unreachable
+  (loop $label$0
+   (drop
+    (block (result i32)
+     (br $label$0)
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $dont-move-unreachable-last
+  (loop $label$0
+   (drop
+    (block (result i32)
+     (call $dont-move-unreachable-last)
+     (br $label$0)
+    )
+   )
+  )
+ )
+ (func $move-around-unreachable-in-middle
+  (loop $label$0
+   (nop)
+   (drop
+    (block $label$3 (result i32)
+     (drop
+      (br_if $label$3
+       (br $label$0)
+       (i32.const 0)
+      )
+     )
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $drop-unreachable-block-with-concrete-final
+  (drop
+   (block (result i32)
+    (drop
+     (block
+      (drop
+       (return)
+      )
+     )
+    )
+    (i32.const -452)
+   )
+  )
+ )
+ (func $merging-with-unreachable-in-middle (result i32)
+  (block (result i32)
+   (return
+    (i32.const 21536)
+   )
+   (block $label$15
+    (br $label$15)
+   )
+   (i32.const 19299)
+  )
+ )
+ (func $remove-br-after-unreachable
+  (block $label$9
+   (drop
+    (block
+     (block
+      (return)
+      (br $label$9)
+     )
+    )
+   )
+  )
+ )
+ (func $block-tails
+  (block $l1
+   (drop
+    (i32.const -2)
+   )
+   (drop
+    (i32.const -1)
+   )
+   (br $l1)
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 1)
+   )
+  )
+  (block $l2
+   (br_if $l2
+    (i32.const 2)
+   )
+   (drop
+    (i32.const 3)
+   )
+  )
+  (block $l3
+   (br_if $l3
+    (i32.const 4)
+   )
+   (br_if $l3
+    (i32.const 5)
+   )
+   (drop
+    (i32.const 6)
+   )
+  )
+  (block $l4
+   (br_if $l4
+    (i32.const 7)
+   )
+   (br_if $l4
+    (i32.const 8)
+   )
+   (drop
+    (i32.const 9)
+   )
+  )
+  (block $l5
+   (if
+    (i32.const 10)
+    (br_if $l5
+     (i32.const 11)
+    )
+   )
+   (drop
+    (i32.const 12)
+   )
+  )
+  (block $l8
+   (br_if $l8
+    (i32.const 13)
+   )
+   (br_if $l8
+    (i32.const 14)
+   )
+   (br_if $l8
+    (i32.const 15)
+   )
+   (drop
+    (i32.const 16)
+   )
+  )
+  (block $l11
+   (br_if $l11
+    (i32.const 17)
+   )
+   (br_if $l11
+    (i32.const 18)
+   )
+   (br_if $l11
+    (i32.const 19)
+   )
+   (drop
+    (i32.const 20)
+   )
+  )
+  (block $l12
+   (br_if $l12
+    (i32.const 21)
+   )
+   (block $l13
+    (br_if $l13
+     (i32.const 22)
+    )
+    (block $l14
+     (br_if $l14
+      (i32.const 23)
+     )
+     (drop
+      (i32.const 24)
+     )
+    )
+    (drop
+     (i32.const 25)
+    )
+   )
+   (drop
+    (i32.const 26)
+   )
+  )
+  (drop
+   (i32.const 27)
+  )
+  (block $l17
+   (br_if $l17
+    (i32.const 28)
+   )
+   (drop
+    (i32.const 29)
+   )
+  )
+  (block $l16
+   (br_if $l16
+    (i32.const 30)
+   )
+   (drop
+    (i32.const 31)
+   )
+  )
+  (block $l15
+   (br_if $l15
+    (i32.const 32)
+   )
+   (drop
+    (i32.const 33)
+   )
+  )
+ )
+ (func $loop-tails
+  (loop $l1
+   (drop
+    (i32.const -2)
+   )
+   (drop
+    (i32.const -1)
+   )
+   (br $l1)
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 1)
+   )
+  )
+  (loop $l2
+   (br_if $l2
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.const 3)
+  )
+  (block $b1
+   (loop $l3
+    (br_if $b1
+     (i32.const 4)
+    )
+    (br_if $l3
+     (i32.const 5)
+    )
+   )
+   (drop
+    (i32.const 6)
+   )
+  )
+  (loop $l4
+   (br_if $l4
+    (i32.const 7)
+   )
+  )
+  (block $b2
+   (br_if $b2
+    (i32.const 8)
+   )
+   (drop
+    (i32.const 9)
+   )
+  )
+  (loop $l5
+   (if
+    (i32.const 10)
+    (br_if $l5
+     (i32.const 11)
+    )
+   )
+  )
+  (drop
+   (i32.const 12)
+  )
+  (loop $l6
+   (loop $l7
+    (loop $l8
+     (br_if $l6
+      (i32.const 13)
+     )
+     (br_if $l7
+      (i32.const 14)
+     )
+     (br_if $l8
+      (i32.const 15)
+     )
+     (drop
+      (i32.const 16)
+     )
+    )
+   )
+  )
+  (loop $l9
+   (loop $l10
+    (loop $l11
+     (br_if $l11
+      (i32.const 17)
+     )
+     (br_if $l10
+      (i32.const 18)
+     )
+     (br_if $l9
+      (i32.const 19)
+     )
+     (drop
+      (i32.const 20)
+     )
+    )
+   )
+  )
+  (loop $l12
+   (loop $l13
+    (loop $l14
+     (br_if $l12
+      (i32.const 21)
+     )
+     (br_if $l13
+      (i32.const 22)
+     )
+     (br_if $l14
+      (i32.const 23)
+     )
+    )
+   )
+  )
+  (drop
+   (i32.const 24)
+  )
+  (drop
+   (i32.const 25)
+  )
+  (drop
+   (i32.const 26)
+  )
+  (loop $l15
+   (loop $l16
+    (loop $l17
+     (drop
+      (i32.const 27)
+     )
+     (br_if $l17
+      (i32.const 28)
+     )
+    )
+    (drop
+     (i32.const 29)
+    )
+    (br_if $l16
+     (i32.const 30)
+    )
+   )
+   (drop
+    (i32.const 31)
+   )
+   (br_if $l15
+    (i32.const 32)
+   )
+  )
+  (drop
+   (i32.const 33)
+  )
+ )
+ (func $block-tail-one
+  (block $l1
+   (drop
+    (i32.const -2)
+   )
+   (drop
+    (i32.const -1)
+   )
+   (br $l1)
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.const 2)
+  )
+ )
+ (func $loop-tail-one
+  (loop $l1
+   (drop
+    (i32.const -2)
+   )
+   (drop
+    (i32.const -1)
+   )
+   (br $l1)
+   (drop
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.const 2)
+  )
+ )
+ (func $block-tail-value (result i32)
+  (block $l1 (result i32)
+   (drop
+    (i32.const -1)
+   )
+   (br $l1
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 1)
+   )
+   (i32.const 2)
+  )
+ )
+ (func $block-tail-empty
+  (block $l1
+   (drop
+    (i32.const -1)
+   )
+   (br $l1)
+  )
+ )
+ (func $loop-tail-empty
+  (loop $l1
+   (drop
+    (i32.const -1)
+   )
+   (br $l1)
+  )
+ )
+ (func $block-tail-unreachable (result i32)
+  (block $l1 (result i32)
+   (drop
+    (i32.const -1)
+   )
+   (drop
+    (br_if $l1
+     (i32.const 0)
+     (i32.const 1)
+    )
+   )
+   (drop
+    (i32.const 1)
+   )
+   (unreachable)
+  )
+ )
+ (func $loop-tail-unreachable (result i32)
+  (loop $l1
+   (drop
+    (i32.const -1)
+   )
+   (br_if $l1
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.const 1)
+  )
+  (unreachable)
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $f64_i32_=>_i32 (func (param f64 i32) (result i32)))
+ (func $unreachable-in-sub-block (param $0 f64) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $9 i32)
+  (loop $label$1
+   (local.set $9
+    (local.tee $2
+     (block $label$2 (result i32)
+      (drop
+       (br_if $label$2
+        (local.tee $2
+         (i32.const 0)
+        )
+        (i32.const 0)
+       )
+      )
+      (br_if $label$1
+       (i32.const 0)
+      )
+      (block
+       (unreachable)
+       (nop)
+      )
+     )
+    )
+   )
+  )
+  (nop)
+  (local.get $9)
+ )
+ (func $trivial (result i32)
+  (block
+   (unreachable)
+   (nop)
+  )
+ )
+ (func $trivial-more (result i32)
+  (block
+   (nop)
+   (unreachable)
+   (nop)
+   (nop)
+   (nop)
+  )
+  (block
+   (nop)
+   (unreachable)
+   (nop)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (func $merge-some-block
+  (drop
+   (i32.const 1)
+  )
+  (block $b1
+   (br_if $b1
+    (i32.const 0)
+   )
+  )
+  (block $b2
+   (br_if $b2
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.const 3)
+  )
+  (block $b3
+   (br_if $b3
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 4)
+   )
+  )
+  (block $b3-dead-code-so-ignore
+   (drop
+    (i32.const 3)
+   )
+   (br $b3-dead-code-so-ignore)
+   (drop
+    (i32.const 4)
+   )
+  )
+  (drop
+   (i32.const 5)
+  )
+  (block $b4
+   (br_if $b4
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 6)
+   )
+   (br_if $b4
+    (i32.const 0)
+   )
+  )
+  (block $b5
+   (br_if $b5
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 7)
+   )
+   (br_if $b5
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 8)
+   )
+  )
+  (drop
+   (i32.const 9)
+  )
+  (drop
+   (i32.const 10)
+  )
+  (block $b6
+   (br_if $b6
+    (i32.const 0)
+   )
+  )
+ )
+ (func $merge-some-loop
+  (drop
+   (i32.const 1)
+  )
+  (block $b1
+   (br_if $b1
+    (i32.const 0)
+   )
+  )
+  (block $b2
+   (br_if $b2
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.const 3)
+  )
+  (block $b3
+   (br_if $b3
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 4)
+   )
+  )
+  (drop
+   (i32.const 5)
+  )
+  (block $b4
+   (br_if $b4
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 6)
+   )
+   (br_if $b4
+    (i32.const 0)
+   )
+  )
+  (block $b5
+   (br_if $b5
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 7)
+   )
+   (br_if $b5
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 8)
+   )
+  )
+  (drop
+   (i32.const 9)
+  )
+  (drop
+   (i32.const 10)
+  )
+  (block $b6
+   (br_if $b6
+    (i32.const 0)
+   )
+  )
+ )
+ (func $merge-some-loop-taken
+  (loop $l1
+   (block $b1
+    (drop
+     (i32.const 1)
+    )
+    (br_if $l1
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 2)
+    )
+    (br_if $b1
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 3)
+    )
+   )
+  )
+  (loop $l2
+   (block $b2
+    (drop
+     (i32.const 4)
+    )
+    (br_if $b2
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 5)
+    )
+    (br_if $l2
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 6)
+    )
+   )
+  )
+  (loop $l3
+   (block $b3
+    (drop
+     (i32.const 7)
+    )
+    (br_if $b3
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 8)
+    )
+    (br_if $l3
+     (i32.const 0)
+    )
+   )
+  )
+  (loop $l4
+   (block $b4
+    (br_if $l4
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 9)
+    )
+    (br_if $b4
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 10)
+    )
+   )
+  )
+  (loop $l5
+   (block $b5
+    (drop
+     (i32.const 7)
+    )
+    (br_if $b5
+     (i32.const 0)
+    )
+    (br_if $l5
+     (i32.const 0)
+    )
+   )
+  )
+  (loop $l6
+   (block $b6
+    (br_if $l6
+     (i32.const 0)
+    )
+    (br_if $b6
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 10)
+    )
+   )
+  )
+  (loop $l7
+   (block $b7
+    (drop
+     (i32.const 11)
+    )
+    (br_if $l7
+     (i32.const 0)
+    )
+    (br_if $b7
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 13)
+    )
+   )
+  )
+  (loop $l8
+   (block $b8
+    (drop
+     (i32.const 14)
+    )
+    (br_if $b8
+     (i32.const 0)
+    )
+    (br_if $l8
+     (i32.const 0)
+    )
+    (drop
+     (i32.const 16)
+    )
+   )
+  )
+  (loop $l9
+   (drop
+    (i32.const 17)
+   )
+   (br_if $l9
+    (i32.const 0)
+   )
+   (drop
+    (i32.const 18)
+   )
+   (br_if $l9
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.const 19)
+  )
+  (loop $l10
+   (drop
+    (i32.const 20)
+   )
+   (br_if $l10
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.const 21)
+  )
+  (loop $l11
+   (br_if $l11
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.const 23)
+  )
+  (loop $l12
+   (drop
+    (i32.const 24)
+   )
+   (br_if $l12
+    (i32.const 0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (event $e (attr 0) (param i32))
+ (func $foo
+  (nop)
+ )
+ (func $throw
+  (nop)
+  (throw $e
+   (i32.const 3)
+  )
+ )
+ (func $rethrow
+  (local $0 exnref)
+  (call $foo)
+  (rethrow
+   (local.get $0)
+  )
+ )
+ (func $br_on_exn (result i32)
+  (local $0 exnref)
+  (block $label$0 (result i32)
+   (call $foo)
+   (drop
+    (br_on_exn $label$0 $e
+     (local.get $0)
+    )
+   )
+   (i32.const 3)
+  )
+ )
+ (func $cannot_extract_br_on_exn_exnref
+  (local $0 exnref)
+  (drop
+   (block $label$0 (result i32)
+    (drop
+     (br_on_exn $label$0 $e
+      (local.get $0)
+     )
+    )
+    (i32.const 5)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/remove-unused-names_merge-blocks_all-features.wast b/binaryen/test/passes/remove-unused-names_merge-blocks_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names_merge-blocks_all-features.wast
@@ -0,0 +1,1615 @@
+(module
+  (memory (shared 256 256))
+  (type $i (func (param i32)))
+  (type $ii (func (param i32 i32)))
+  (type $iii (func (param i32 i32 i32)))
+  (type $3 (func))
+  (table 1 1 funcref)
+  (elem (i32.const 0) $call-i)
+  (func $call-i (type $i) (param $0 i32)
+    (nop)
+  )
+  (func $call-ii (type $ii) (param $0 i32) (param $1 i32)
+    (nop)
+  )
+  (func $call-iii (type $iii) (param $0 i32) (param $1 i32) (param $2 i32)
+    (nop)
+  )
+  (func $b0-yes (type $i) (param $i1 i32)
+    (block $topmost
+      (block $block0
+        (drop
+          (i32.const 10)
+        )
+      )
+    )
+  )
+  (func $b0-no (type $i) (param $i1 i32)
+    (block $topmost
+      (block $block0
+        (br $block0)
+      )
+      (br $topmost)
+    )
+  )
+  (func $b0-br-but-ok (type $i) (param $i1 i32)
+    (block $topmost
+      (block $block0
+        (br $topmost)
+      )
+    )
+  )
+  (func $b1-yes (type $i) (param $i1 i32)
+    (block $topmost
+      (block $block0
+        (block $block1
+          (drop
+            (i32.const 10)
+          )
+        )
+      )
+    )
+  )
+  (func $b2-yes (type $i) (param $i1 i32)
+    (block $topmost
+      (drop
+        (i32.const 5)
+      )
+      (block $block0
+        (drop
+          (i32.const 10)
+        )
+      )
+      (drop
+        (i32.const 15)
+      )
+    )
+  )
+  (func $b3-yes (type $i) (param $i1 i32)
+    (block $topmost
+      (drop
+        (i32.const 3)
+      )
+      (block $block0
+        (drop
+          (i32.const 6)
+        )
+        (block $block1
+          (drop
+            (i32.const 10)
+          )
+        )
+        (drop
+          (i32.const 15)
+        )
+      )
+      (drop
+        (i32.const 20)
+      )
+    )
+  )
+  (func $b4 (type $i) (param $i1 i32)
+    (block $topmost
+      (block $inner
+        (drop
+          (i32.const 10)
+        )
+        (br $inner)
+      )
+    )
+  )
+  (func $b5 (type $i) (param $i1 i32)
+    (block $topmost
+      (block $middle
+        (block $inner
+          (drop
+            (i32.const 10)
+          )
+          (br $inner)
+        )
+        (br $middle)
+      )
+    )
+  )
+  (func $b6 (type $i) (param $i1 i32)
+    (block $topmost
+      (drop
+        (i32.const 5)
+      )
+      (block $inner
+        (drop
+          (i32.const 10)
+        )
+        (br $inner)
+      )
+      (drop
+        (i32.const 15)
+      )
+    )
+  )
+  (func $b7 (type $i) (param $i1 i32)
+    (block $topmost
+      (drop
+        (i32.const 3)
+      )
+      (block $middle
+        (drop
+          (i32.const 6)
+        )
+        (block $inner
+          (drop
+            (i32.const 10)
+          )
+          (br $inner)
+        )
+        (drop
+          (i32.const 15)
+        )
+        (br $middle)
+      )
+      (drop
+        (i32.const 20)
+      )
+    )
+  )
+  (func $unary (type $3)
+    (local $x i32)
+    (drop
+      (i32.eqz
+        (block $block0 (result i32)
+          (i32.const 10)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (block $block1 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (block $block2 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (drop
+            (i32.const 20)
+          )
+          (i32.const 30)
+        )
+      )
+    )
+    (local.set $x
+      (block $block3 (result i32)
+        (drop
+          (i32.const 10)
+        )
+        (i32.const 20)
+      )
+    )
+    (drop
+      (i32.load
+        (block $block4 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+      )
+    )
+    (return
+      (block $block5
+        (drop
+          (i32.const 10)
+        )
+        (unreachable)
+      )
+    )
+  )
+  (func $binary (type $3)
+    (drop
+      (i32.add
+        (block $block0 (result i32)
+          (i32.const 10)
+        )
+        (i32.const 20)
+      )
+    )
+    (drop
+      (i32.add
+        (block $block1 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+        (i32.const 30)
+      )
+    )
+    (drop
+      (i32.add
+        (block $block2 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (drop
+            (i32.const 20)
+          )
+          (i32.const 30)
+        )
+        (i32.const 40)
+      )
+    )
+    (drop
+      (i32.add
+        (i32.const 10)
+        (block $block3 (result i32)
+          (i32.const 20)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.const 10)
+        (block $block4 (result i32)
+          (drop
+            (i32.const 20)
+          )
+          (i32.const 30)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.const 10)
+        (block $block5 (result i32)
+          (drop
+            (i32.const 20)
+          )
+          (drop
+            (i32.const 30)
+          )
+          (i32.const 40)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (block $block6 (result i32)
+          (i32.const 10)
+        )
+        (block $block7 (result i32)
+          (i32.const 20)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (block $block8 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+        (block $block9 (result i32)
+          (drop
+            (i32.const 30)
+          )
+          (i32.const 40)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (block $block10 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (drop
+            (i32.const 20)
+          )
+          (i32.const 30)
+        )
+        (block $block11 (result i32)
+          (drop
+            (i32.const 40)
+          )
+          (drop
+            (i32.const 50)
+          )
+          (i32.const 60)
+        )
+      )
+    )
+    (i32.store
+      (i32.const 10)
+      (block $block12 (result i32)
+        (drop
+          (i32.const 20)
+        )
+        (i32.const 30)
+      )
+    )
+    (i32.store
+      (block $block13 (result i32)
+        (drop
+          (i32.const 10)
+        )
+        (i32.const 20)
+      )
+      (i32.const 30)
+    )
+    (drop
+      (i32.add
+        (unreachable)
+        (block $block14 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (block $block15 (result i32)
+          (unreachable)
+          (i32.const 10)
+        )
+        (block $block16 (result i32)
+          (drop
+            (i32.const 20)
+          )
+          (i32.const 30)
+        )
+      )
+    )
+  )
+  (func $trinary (type $3)
+    (drop
+      (select
+        (block $block0 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+        (block $block1 (result i32)
+          (drop
+            (i32.const 30)
+          )
+          (i32.const 40)
+        )
+        (block $block2 (result i32)
+          (drop
+            (i32.const 50)
+          )
+          (i32.const 60)
+        )
+      )
+    )
+    (drop
+      (select
+        (block $block3 (result i32)
+          (i32.const 10)
+        )
+        (block $block4 (result i32)
+          (drop
+            (i32.const 20)
+          )
+          (i32.const 30)
+        )
+        (block $block5 (result i32)
+          (drop
+            (i32.const 40)
+          )
+          (i32.const 50)
+        )
+      )
+    )
+    (drop
+      (select
+        (block $block6 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+        (block $block7 (result i32)
+          (i32.const 30)
+        )
+        (block $block8 (result i32)
+          (drop
+            (i32.const 40)
+          )
+          (i32.const 50)
+        )
+      )
+    )
+    (drop
+      (select
+        (block $block9 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+        (block $block10 (result i32)
+          (drop
+            (i32.const 30)
+          )
+          (i32.const 40)
+        )
+        (block $block11 (result i32)
+          (i32.const 50)
+        )
+      )
+    )
+    (drop
+      (select
+        (block $block12 (result i32)
+          (i32.const 10)
+        )
+        (block $block13 (result i32)
+          (i32.const 20)
+        )
+        (block $block14 (result i32)
+          (drop
+            (i32.const 30)
+          )
+          (i32.const 40)
+        )
+      )
+    )
+    (drop
+      (select
+        (block $block15 (result i32)
+          (i32.const 10)
+        )
+        (block $block16 (result i32)
+          (drop
+            (i32.const 20)
+          )
+          (i32.const 30)
+        )
+        (block $block17 (result i32)
+          (i32.const 40)
+        )
+      )
+    )
+    (drop
+      (select
+        (block $block18 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+        (block $block19 (result i32)
+          (i32.const 30)
+        )
+        (block $block20 (result i32)
+          (i32.const 40)
+        )
+      )
+    )
+    (drop
+      (select
+        (block $block21 (result i32)
+          (unreachable)
+          (i32.const 20)
+        )
+        (block $block22 (result i32)
+          (drop
+            (i32.const 30)
+          )
+          (i32.const 40)
+        )
+        (block $block23 (result i32)
+          (drop
+            (i32.const 50)
+          )
+          (i32.const 60)
+        )
+      )
+    )
+    (drop
+      (select
+        (block $block24 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (unreachable)
+        )
+        (block $block25 (result i32)
+          (drop
+            (i32.const 30)
+          )
+          (i32.const 40)
+        )
+        (block $block26 (result i32)
+          (drop
+            (i32.const 50)
+          )
+          (i32.const 60)
+        )
+      )
+    )
+    (drop
+      (select
+        (block $block27 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+        (block $block28 (result i32)
+          (unreachable)
+          (i32.const 40)
+        )
+        (block $block29 (result i32)
+          (drop
+            (i32.const 50)
+          )
+          (i32.const 60)
+        )
+      )
+    )
+    (drop
+      (select
+        (block $block30 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+        (block $block31 (result i32)
+          (drop
+            (i32.const 30)
+          )
+          (unreachable)
+        )
+        (block $block32 (result i32)
+          (drop
+            (i32.const 50)
+          )
+          (i32.const 60)
+        )
+      )
+    )
+    (drop
+      (select
+        (block $block33 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+        (block $block34 (result i32)
+          (drop
+            (i32.const 30)
+          )
+          (i32.const 40)
+        )
+        (block $block35 (result i32)
+          (unreachable)
+          (i32.const 60)
+        )
+      )
+    )
+    (drop
+      (select
+        (block $block36 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+        (block $block37 (result i32)
+          (drop
+            (i32.const 30)
+          )
+          (i32.const 40)
+        )
+        (block $block38 (result i32)
+          (drop
+            (i32.const 50)
+          )
+          (unreachable)
+        )
+      )
+    )
+  )
+  (func $breaks (type $3)
+    (block $out
+      (block
+        (drop
+          (block $block0 (result i32)
+            (drop
+              (i32.const 10)
+            )
+            (i32.const 20)
+          )
+        )
+        (br $out)
+      )
+      (br_if $out
+        (block $block1 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+      )
+      (block
+        (drop
+          (block $block2 (result i32)
+            (drop
+              (i32.const 10)
+            )
+            (i32.const 20)
+          )
+        )
+        (br_if $out
+          (block $block3 (result i32)
+            (drop
+              (i32.const 30)
+            )
+            (i32.const 40)
+          )
+        )
+      )
+      (br_table $out $out
+        (block $block4 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+      )
+      (drop
+        (block $out2 (result i32)
+          (br_table $out2 $out2
+            (block $block5 (result i32)
+              (drop
+                (i32.const 10)
+              )
+              (i32.const 20)
+            )
+            (block $block6 (result i32)
+              (drop
+                (i32.const 30)
+              )
+              (i32.const 40)
+            )
+          )
+        )
+      )
+      (unreachable)
+    )
+  )
+  (func $calls (type $3)
+    (call $call-i
+      (block $block0 (result i32)
+        (i32.const 10)
+      )
+    )
+    (call $call-i
+      (block $block1 (result i32)
+        (drop
+          (i32.const 10)
+        )
+        (i32.const 20)
+      )
+    )
+    (call $call-i
+      (block $block2 (result i32)
+        (drop
+          (i32.const 10)
+        )
+        (drop
+          (i32.const 20)
+        )
+        (i32.const 30)
+      )
+    )
+    (call $call-ii
+      (block $block3 (result i32)
+        (drop
+          (i32.const 10)
+        )
+        (i32.const 20)
+      )
+      (block $block4 (result i32)
+        (drop
+          (i32.const 30)
+        )
+        (i32.const 40)
+      )
+    )
+    (call $call-ii
+      (block $block5 (result i32)
+        (unreachable)
+        (i32.const 10)
+      )
+      (block $block6 (result i32)
+        (drop
+          (i32.const 20)
+        )
+        (i32.const 30)
+      )
+    )
+    (call $call-ii
+      (block $block7 (result i32)
+        (drop
+          (i32.const 10)
+        )
+        (unreachable)
+      )
+      (block $block8 (result i32)
+        (drop
+          (i32.const 20)
+        )
+        (i32.const 30)
+      )
+    )
+    (call $call-ii
+      (block $block9 (result i32)
+        (drop
+          (i32.const 10)
+        )
+        (i32.const 20)
+      )
+      (block $block10 (result i32)
+        (unreachable)
+        (i32.const 30)
+      )
+    )
+    (call $call-ii
+      (block $block11 (result i32)
+        (drop
+          (i32.const 10)
+        )
+        (i32.const 20)
+      )
+      (block $block12 (result i32)
+        (drop
+          (i32.const 30)
+        )
+        (unreachable)
+      )
+    )
+    (call $call-iii
+      (block $block13 (result i32)
+        (drop
+          (i32.const 10)
+        )
+        (i32.const 20)
+      )
+      (block $block14 (result i32)
+        (drop
+          (i32.const 30)
+        )
+        (i32.const 40)
+      )
+      (block $block15 (result i32)
+        (drop
+          (i32.const 50)
+        )
+        (i32.const 60)
+      )
+    )
+    (call $call-iii
+      (block $block16 (result i32)
+        (drop
+          (i32.const 10)
+        )
+        (i32.const 20)
+      )
+      (i32.const 30)
+      (block $block17 (result i32)
+        (drop
+          (i32.const 40)
+        )
+        (i32.const 50)
+      )
+    )
+    (call_indirect (type $ii)
+      (block $block18 (result i32)
+        (drop
+          (i32.const 10)
+        )
+        (i32.const 20)
+      )
+      (block $block19 (result i32)
+        (drop
+          (i32.const 30)
+        )
+        (i32.const 40)
+      )
+      (block $block20 (result i32)
+        (drop
+          (i32.const 50)
+        )
+        (i32.const 60)
+      )
+    )
+    (call_indirect (type $ii)
+      (unreachable)
+      (block $block21 (result i32)
+        (drop
+          (i32.const 30)
+        )
+        (i32.const 40)
+      )
+      (block $block22 (result i32)
+        (drop
+          (i32.const 50)
+        )
+        (i32.const 60)
+      )
+    )
+    (call_indirect (type $ii)
+      (block $block21 (result i32)
+        (drop
+          (i32.const 31)
+        )
+        (i32.const 41)
+      )
+      (unreachable)
+      (block $block22 (result i32)
+        (drop
+          (i32.const 51)
+        )
+        (i32.const 61)
+      )
+    )
+    (call_indirect (type $ii)
+      (block $block21 (result i32)
+        (drop
+          (i32.const 32)
+        )
+        (i32.const 42)
+      )
+      (block $block22 (result i32)
+        (drop
+          (i32.const 52)
+        )
+        (i32.const 62)
+      )
+      (unreachable)
+    )
+  )
+  (func $atomics (type $3)
+    (drop
+      (i32.atomic.rmw.cmpxchg ;; mergeblock logic should be same as select
+        (block $block0 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+        (block $block1 (result i32)
+          (drop
+            (i32.const 30)
+          )
+          (i32.const 40)
+        )
+        (block $block2 (result i32)
+          (drop
+            (i32.const 50)
+          )
+          (i32.const 60)
+        )
+      )
+    )
+    (drop
+      (i32.atomic.rmw.add ;; atomicrmw is like a binary
+        (block $block1 (result i32)
+          (drop
+            (i32.const 10)
+          )
+          (i32.const 20)
+        )
+        (i32.const 30)
+      )
+    )
+  )
+  (func $mix-select (param $x i32)
+    (drop
+      (select
+        (local.get $x)
+        (local.get $x)
+        (block (result i32)
+          (local.set $x ;; cannot be moved before the gets
+            (i32.const 1)
+          )
+          (i32.const 2)
+        )
+      )
+    )
+  )
+  (func $block-type-change (type $3)
+    (local $0 f64)
+    (local $1 f64)
+    (if
+      (f64.gt
+        (local.get $0)
+        (block $block0 (result f64)
+          (nop)
+          (local.get $1)
+        )
+      )
+      (nop)
+    )
+  )
+  (func $do-reorder (param $x i32)
+    (local $y i32)
+    (if (i32.const 1)
+      (block
+        (local.set $x
+          (i32.le_u
+            (local.get $x)
+            (block (result i32)
+              (local.set $y (i32.const 5))
+              (i32.const 10)
+            )
+          )
+        )
+      )
+    )
+  )
+  (func $do-not-reorder (param $x i32)
+    (local $y i32)
+    (if (i32.const 1)
+      (block
+        (local.set $x
+          (i32.le_u
+            (local.get $y)
+            (block (result i32)
+              (local.set $y (i32.const 5))
+              (i32.const 10)
+            )
+          )
+        )
+      )
+    )
+  )
+  (func $return-different-type (result i32)
+    (drop
+      (f64.abs
+        (return
+          (block (result i32) ;; when we flip the block out, it should have an ok type for the (dead) f64 op
+            (drop (i32.const 2))
+            (i32.const 1)
+          )
+        )
+      )
+    )
+    (unreachable)
+  )
+
+ (func $drop-unreachable (result i32)
+  (local $0 i32)
+  (block $label$1 (result i32)
+   (drop
+    (block (result i32)
+     (unreachable)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $concrete_finale_in_unreachable (result f64)
+  (block $label$0 (result f64)
+   (drop
+    (block (result f64)
+     (unreachable)
+     (f64.const 6.322092475576799e-96)
+    )
+   )
+   (f64.const -1)
+  )
+ )
+ (func $dont-move-unreachable
+  (loop $label$0
+   (drop
+    (block $label$3 (result i32)
+     (br $label$0)
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $dont-move-unreachable-last
+  (loop $label$0
+   (drop
+    (block $label$3 (result i32)
+     (call $dont-move-unreachable-last)
+     (br $label$0)
+    )
+   )
+  )
+ )
+ (func $move-around-unreachable-in-middle
+  (loop $label$0
+   (drop
+    (block $label$2 (result i32)
+     (block $block2
+      (nop)
+     )
+     (block $label$3 (result i32)
+      (drop
+       (br_if $label$3
+        (br $label$0)
+        (i32.const 0)
+       )
+      )
+      (i32.const 1)
+     )
+    )
+   )
+  )
+ )
+ (func $drop-unreachable-block-with-concrete-final
+  (drop
+   (block (result i32)
+    (drop
+     (block
+      (drop
+       (return)
+      )
+     )
+    )
+    (i32.const -452)
+   )
+  )
+ )
+ (func $merging-with-unreachable-in-middle (result i32)
+  (block $label$1 (result i32)
+   (block (result i32)
+    (return
+     (i32.const 21536)
+    )
+    (block $label$15
+     (br $label$15)
+    )
+    (i32.const 19299)
+   )
+  )
+ )
+ (func $remove-br-after-unreachable
+  (block $label$9
+   (drop
+    (block
+     (block
+      (return)
+      (br $label$9) ;; removing this leads to the block becoming unreachable
+     )
+    )
+   )
+  )
+ )
+ (func $block-tails
+  (block $l1
+   (drop (i32.const -2))
+   (drop (i32.const -1))
+   (br $l1)
+   (drop (i32.const 0))
+   (drop (i32.const 1))
+  )
+  (block $l2
+   (br_if $l2 (i32.const 2))
+   (drop (i32.const 3))
+  )
+  (block $b1
+   (block $l3
+    (br_if $b1 (i32.const 4))
+    (br_if $l3 (i32.const 5))
+    (drop (i32.const 6))
+   )
+  )
+  (block $b2
+   (block $l4
+    (br_if $l4 (i32.const 7))
+    (br_if $b2 (i32.const 8))
+    (drop (i32.const 9))
+   )
+  )
+  (block $l5
+   (if (i32.const 10)
+    (br_if $l5 (i32.const 11))
+   )
+   (drop (i32.const 12))
+  )
+  (block $l6
+   (block $l7
+    (block $l8
+     (br_if $l6 (i32.const 13))
+     (br_if $l7 (i32.const 14))
+     (br_if $l8 (i32.const 15))
+     (drop (i32.const 16))
+    )
+   )
+  )
+  (block $l9
+   (block $l10
+    (block $l11
+     (br_if $l11 (i32.const 17))
+     (br_if $l10 (i32.const 18))
+     (br_if $l9  (i32.const 19))
+     (drop (i32.const 20))
+    )
+   )
+  )
+  (block $l12
+   (block $l13
+    (block $l14
+     (br_if $l12 (i32.const 21))
+     (br_if $l13 (i32.const 22))
+     (br_if $l14 (i32.const 23))
+     (drop (i32.const 24))
+    )
+    (drop (i32.const 25))
+   )
+   (drop (i32.const 26))
+  )
+  (block $l15
+   (block $l16
+    (block $l17
+     (drop (i32.const 27))
+     (br_if $l17 (i32.const 28))
+     (drop (i32.const 29))
+    )
+    (br_if $l16 (i32.const 30))
+    (drop (i32.const 31))
+   )
+   (br_if $l15 (i32.const 32))
+   (drop (i32.const 33))
+  )
+ )
+ (func $loop-tails
+  (loop $l1
+   (drop (i32.const -2))
+   (drop (i32.const -1))
+   (br $l1)
+   (drop (i32.const 0))
+   (drop (i32.const 1))
+  )
+  (loop $l2
+   (br_if $l2 (i32.const 2))
+   (drop (i32.const 3))
+  )
+  (block $b1
+   (loop $l3
+    (br_if $b1 (i32.const 4))
+    (br_if $l3 (i32.const 5))
+    (drop (i32.const 6))
+   )
+  )
+  (block $b2
+   (loop $l4
+    (br_if $l4 (i32.const 7))
+    (br_if $b2 (i32.const 8))
+    (drop (i32.const 9))
+   )
+  )
+  (loop $l5
+   (if (i32.const 10)
+    (br_if $l5 (i32.const 11))
+   )
+   (drop (i32.const 12))
+  )
+  (loop $l6
+   (loop $l7
+    (loop $l8
+     (br_if $l6 (i32.const 13))
+     (br_if $l7 (i32.const 14))
+     (br_if $l8 (i32.const 15))
+     (drop (i32.const 16))
+    )
+   )
+  )
+  (loop $l9
+   (loop $l10
+    (loop $l11
+     (br_if $l11 (i32.const 17))
+     (br_if $l10 (i32.const 18))
+     (br_if $l9  (i32.const 19))
+     (drop (i32.const 20))
+    )
+   )
+  )
+  (loop $l12
+   (loop $l13
+    (loop $l14
+     (br_if $l12 (i32.const 21))
+     (br_if $l13 (i32.const 22))
+     (br_if $l14 (i32.const 23))
+     (drop (i32.const 24))
+    )
+    (drop (i32.const 25))
+   )
+   (drop (i32.const 26))
+  )
+  (loop $l15
+   (loop $l16
+    (loop $l17
+     (drop (i32.const 27))
+     (br_if $l17 (i32.const 28))
+     (drop (i32.const 29))
+    )
+    (br_if $l16 (i32.const 30))
+    (drop (i32.const 31))
+   )
+   (br_if $l15 (i32.const 32))
+   (drop (i32.const 33))
+  )
+ )
+ (func $block-tail-one
+  (block $outer
+   (block $l1
+    (drop (i32.const -2))
+    (drop (i32.const -1))
+    (br $l1)
+    (drop (i32.const 0))
+    (drop (i32.const 1))
+   )
+   (drop (i32.const 2))
+  )
+ )
+ (func $loop-tail-one
+  (block $outer
+   (loop $l1
+    (drop (i32.const -2))
+    (drop (i32.const -1))
+    (br $l1)
+    (drop (i32.const 0))
+    (drop (i32.const 1))
+   )
+   (drop (i32.const 2))
+  )
+ )
+ (func $block-tail-value (result i32)
+  (block $outer (result i32)
+   (block $l1 (result i32)
+    (drop (i32.const -1))
+    (br $l1 (i32.const 0))
+    (drop (i32.const 1))
+    (i32.const 2)
+   )
+  )
+ )
+ (func $block-tail-empty
+  (block $outer
+   (block $l1
+    (drop (i32.const -1))
+    (br $l1)
+   )
+  )
+ )
+ (func $loop-tail-empty
+  (block $outer
+   (loop $l1
+    (drop (i32.const -1))
+    (br $l1)
+   )
+  )
+ )
+ (func $block-tail-unreachable (result i32)
+  (block $outer (result i32)
+   (block $l1 (result i32)
+    (drop (i32.const -1))
+    (drop (br_if $l1 (i32.const 0) (i32.const 1)))
+    (drop (i32.const 1))
+    (unreachable)
+   )
+  )
+ )
+ (func $loop-tail-unreachable (result i32)
+  (block $outer (result i32)
+   (loop $l1 (result i32)
+    (drop (i32.const -1))
+    (br_if $l1 (i32.const 1))
+    (drop (i32.const 1))
+    (unreachable)
+   )
+  )
+ )
+)
+(module
+ (func $unreachable-in-sub-block (param $0 f64) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $9 i32)
+  (loop $label$1
+   (local.set $9
+    (local.tee $2
+     (block $label$2 (result i32)
+      (block
+       (drop
+        (br_if $label$2
+         (local.tee $2
+          (i32.const 0)
+         )
+         (i32.const 0)
+        )
+       )
+      )
+      (br_if $label$1
+       (i32.const 0)
+      )
+      (block
+       (unreachable)
+       (nop) ;; bad if moved out to the outer block which is i32. current state works since this block is unreachable!
+      )
+     )
+    )
+   )
+  )
+  (nop)
+  (local.get $9)
+ )
+ (func $trivial (result i32)
+   (block (result i32)
+     (block
+       (unreachable)
+       (nop)
+     )
+   )
+ )
+ (func $trivial-more (result i32)
+   (block (result i32)
+     (block
+       (nop)
+       (unreachable)
+       (nop)
+       (nop)
+       (nop)
+     )
+     (block
+       (nop)
+       (unreachable)
+       (nop)
+     )
+   )
+ )
+)
+(module
+ (func $merge-some-block
+  (block $b1
+   (drop (i32.const 1))
+   (br_if $b1 (i32.const 0))
+  )
+  (block $b2
+   (br_if $b2 (i32.const 0))
+   (drop (i32.const 2))
+  )
+  (block $b3
+   (drop (i32.const 3))
+   (br_if $b3 (i32.const 0))
+   (drop (i32.const 4))
+  )
+  (block $b3-dead-code-so-ignore
+   (drop (i32.const 3))
+   (br $b3-dead-code-so-ignore)
+   (drop (i32.const 4))
+  )
+  (block $b4
+   (drop (i32.const 5))
+   (br_if $b4 (i32.const 0))
+   (drop (i32.const 6))
+   (br_if $b4 (i32.const 0))
+  )
+  (block $b5
+   (br_if $b5 (i32.const 0))
+   (drop (i32.const 7))
+   (br_if $b5 (i32.const 0))
+   (drop (i32.const 8))
+  )
+  (block $b6
+   (drop (i32.const 9))
+   (drop (i32.const 10))
+   (br_if $b6 (i32.const 0))
+  )
+ )
+ (func $merge-some-loop
+  (loop $l1
+   (block $b1
+    (drop (i32.const 1))
+    (br_if $b1 (i32.const 0))
+   )
+  )
+  (loop $l2
+   (block $b2
+    (br_if $b2 (i32.const 0))
+    (drop (i32.const 2))
+   )
+  )
+  (loop $l3
+   (block $b3
+    (drop (i32.const 3))
+    (br_if $b3 (i32.const 0))
+    (drop (i32.const 4))
+   )
+  )
+  (loop $l4
+   (block $b4
+    (drop (i32.const 5))
+    (br_if $b4 (i32.const 0))
+    (drop (i32.const 6))
+    (br_if $b4 (i32.const 0))
+   )
+  )
+  (loop $l5
+   (block $b5
+    (br_if $b5 (i32.const 0))
+    (drop (i32.const 7))
+    (br_if $b5 (i32.const 0))
+    (drop (i32.const 8))
+   )
+  )
+  (loop $l6
+   (block $b6
+    (drop (i32.const 9))
+    (drop (i32.const 10))
+    (br_if $b6 (i32.const 0))
+   )
+  )
+ )
+ (func $merge-some-loop-taken
+  (loop $l1
+   (block $b1
+    (drop (i32.const 1))
+    (br_if $l1 (i32.const 0))
+    (drop (i32.const 2))
+    (br_if $b1 (i32.const 0))
+    (drop (i32.const 3))
+   )
+  )
+  (loop $l2
+   (block $b2
+    (drop (i32.const 4))
+    (br_if $b2 (i32.const 0))
+    (drop (i32.const 5))
+    (br_if $l2 (i32.const 0))
+    (drop (i32.const 6))
+   )
+  )
+  (loop $l3
+   (block $b3
+    (drop (i32.const 7))
+    (br_if $b3 (i32.const 0))
+    (drop (i32.const 8))
+    (br_if $l3 (i32.const 0))
+   )
+  )
+  (loop $l4
+   (block $b4
+    (br_if $l4 (i32.const 0))
+    (drop (i32.const 9))
+    (br_if $b4 (i32.const 0))
+    (drop (i32.const 10))
+   )
+  )
+  (loop $l5
+   (block $b5
+    (drop (i32.const 7))
+    (br_if $b5 (i32.const 0))
+    (br_if $l5 (i32.const 0))
+   )
+  )
+  (loop $l6
+   (block $b6
+    (br_if $l6 (i32.const 0))
+    (br_if $b6 (i32.const 0))
+    (drop (i32.const 10))
+   )
+  )
+  (loop $l7
+   (block $b7
+    (drop (i32.const 11))
+    (br_if $l7 (i32.const 0))
+    (br_if $b7 (i32.const 0))
+    (drop (i32.const 13))
+   )
+  )
+  (loop $l8
+   (block $b8
+    (drop (i32.const 14))
+    (br_if $b8 (i32.const 0))
+    (br_if $l8 (i32.const 0))
+    (drop (i32.const 16))
+   )
+  )
+  (loop $l9
+   (block $b9
+    (drop (i32.const 17))
+    (br_if $l9 (i32.const 0))
+    (drop (i32.const 18))
+    (br_if $l9 (i32.const 0))
+    (drop (i32.const 19))
+   )
+  )
+  (loop $l10
+   (block $b10
+    (drop (i32.const 20))
+    (br_if $l10 (i32.const 0))
+    (drop (i32.const 21))
+   )
+  )
+  (loop $l11
+   (block $b11
+    (br_if $l11 (i32.const 0))
+    (drop (i32.const 23))
+   )
+  )
+  (loop $l12
+   (block $b12
+    (drop (i32.const 24))
+    (br_if $l12 (i32.const 0))
+   )
+  )
+ )
+)
+
+(module
+  (event $e (attr 0) (param i32))
+  (func $foo)
+
+  ;; 'nop' within 'block' of `throw' can be hoisted
+  (func $throw
+    (throw $e
+      (block (result i32)
+        (nop)
+        (i32.const 3)
+      )
+    )
+  )
+
+  ;; 'call $foo' within 'block' of `rethrow' can be hoisted
+  (func $rethrow (local $0 exnref)
+    (rethrow
+      (block (result exnref)
+        (call $foo)
+        (local.get $0)
+      )
+    )
+  )
+
+  ;; 'call $foo' within 'block' of `br_on_exn' can be hoisted
+  (func $br_on_exn (result i32) (local $0 exnref)
+    (block $label$0 (result i32)
+      (drop
+        (br_on_exn $label$0 $e
+          (block (result exnref)
+            (call $foo)
+            (local.get $0)
+          )
+        )
+      )
+      (i32.const 3)
+    )
+  )
+
+  ;; Unlike br_if, br_on_exn's exnref argument itself cannot be extracted.
+  ;; Without proper handling for br_on_exn in ProblemFinder, this crashes.
+  (func $cannot_extract_br_on_exn_exnref (local $0 exnref)
+    (block
+      (drop
+        (block $label$0 (result i32)
+          (drop
+            (br_on_exn $label$0 $e
+              (local.get $0)
+            )
+          )
+          (i32.const 5)
+        )
+      )
+    )
+  )
+)
diff --git a/binaryen/test/passes/remove-unused-names_optimize-instructions_all-features.txt b/binaryen/test/passes/remove-unused-names_optimize-instructions_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names_optimize-instructions_all-features.txt
@@ -0,0 +1,110 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (event $e (attr 0) (param i32))
+ (func $dummy
+  (nop)
+ )
+ (func $getFallthrough
+  (local $x0 i32)
+  (local $x1 i32)
+  (local $x2 i32)
+  (local $x3 i32)
+  (local.set $x0
+   (try (result i32)
+    (do
+     (i32.const 1)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (i32.const 3)
+    )
+   )
+  )
+  (drop
+   (local.get $x0)
+  )
+  (local.set $x1
+   (try (result i32)
+    (do
+     (call $dummy)
+     (i32.const 1)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (i32.const 3)
+    )
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $x1)
+    (i32.const 7)
+   )
+  )
+  (local.set $x2
+   (try (result i32)
+    (do
+     (try
+      (do
+       (throw $e
+        (i32.const 0)
+       )
+      )
+      (catch
+       (drop
+        (pop exnref)
+       )
+      )
+     )
+     (i32.const 1)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (i32.const 3)
+    )
+   )
+  )
+  (drop
+   (local.get $x2)
+  )
+  (local.set $x3
+   (try (result i32)
+    (do
+     (try
+      (do
+       (nop)
+      )
+      (catch
+       (drop
+        (pop exnref)
+       )
+       (throw $e
+        (i32.const 0)
+       )
+      )
+     )
+     (i32.const 1)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (i32.const 3)
+    )
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $x3)
+    (i32.const 7)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/remove-unused-names_optimize-instructions_all-features.wast b/binaryen/test/passes/remove-unused-names_optimize-instructions_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names_optimize-instructions_all-features.wast
@@ -0,0 +1,83 @@
+(module
+  (func $dummy)
+  (event $e (attr 0) (param i32))
+
+  (func $getFallthrough ;; unit tests for Properties::getFallthrough
+    (local $x0 i32)
+    (local $x1 i32)
+    (local $x2 i32)
+    (local $x3 i32)
+
+    ;; try - try body does not throw, can
+    (local.set $x0
+      (try (result i32)
+        (do
+          (i32.const 1)
+        )
+        (catch
+          (drop (pop exnref))
+          (i32.const 3)
+        )
+      )
+    )
+    (drop (i32.and (local.get $x0) (i32.const 7)))
+
+    ;; try - try body may throw, can't
+    (local.set $x1
+      (try (result i32)
+        (do
+          (call $dummy)
+          (i32.const 1)
+        )
+        (catch
+          (drop (pop exnref))
+          (i32.const 3)
+        )
+      )
+    )
+    (drop (i32.and (local.get $x1) (i32.const 7)))
+
+    ;; nested try - inner try may throw but will be caught by inner catch, can
+    (local.set $x2
+      (try (result i32)
+        (do
+          (try
+            (do
+              (throw $e (i32.const 0))
+            )
+            (catch
+              (drop (pop exnref))
+            )
+          )
+          (i32.const 1)
+        )
+        (catch
+          (drop (pop exnref))
+          (i32.const 3)
+        )
+      )
+    )
+    (drop (i32.and (local.get $x2) (i32.const 7)))
+
+    ;; nested try - inner catch may throw, can't
+    (local.set $x3
+      (try (result i32)
+        (do
+          (try
+            (do)
+            (catch
+              (drop (pop exnref))
+              (throw $e (i32.const 0))
+            )
+          )
+          (i32.const 1)
+        )
+        (catch
+          (drop (pop exnref))
+          (i32.const 3)
+        )
+      )
+    )
+    (drop (i32.and (local.get $x3) (i32.const 7)))
+  )
+)
diff --git a/binaryen/test/passes/remove-unused-names_precompute.txt b/binaryen/test/passes/remove-unused-names_precompute.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names_precompute.txt
@@ -0,0 +1,25 @@
+(module
+ (type $i32_=>_none (func (param i32)))
+ (memory $0 256 256)
+ (func $__ZN10WasmAssertC2Ev__async_cb (param $$0 i32)
+  (block $switch-default
+   (nop)
+   (block
+    (i32.store
+     (i32.const 12)
+     (i32.const 26)
+    )
+    (return)
+   )
+  )
+  (block
+   (local.set $$0
+    (i32.const 4)
+   )
+   (i32.store
+    (local.get $$0)
+    (i32.const 1)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/remove-unused-names_precompute.wast b/binaryen/test/passes/remove-unused-names_precompute.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names_precompute.wast
@@ -0,0 +1,28 @@
+(module
+ (memory $0 256 256)
+ (func $__ZN10WasmAssertC2Ev__async_cb (param $$0 i32)
+  (block $switch-default
+   (block $switch-case
+    (br_table $switch-case $switch-default
+     (i32.const 0)
+    )
+   )
+   (block
+    (i32.store
+     (i32.const 12)
+     (i32.const 26)
+    )
+    (return)
+   )
+  )
+  (block
+   (local.set $$0
+    (i32.const 4)
+   )
+   (i32.store
+    (local.get $$0)
+    (i32.const 1)
+   )
+  )
+ )
+)
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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names_remove-unused-brs_vacuum.txt
@@ -0,0 +1,119 @@
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32 i32)))
+ (type $f64_=>_i32 (func (param f64) (result i32)))
+ (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))
+ (import "global" "NaN" (global $import$5 f64))
+ (import "global" "Infinity" (global $import$6 f64))
+ (import "env" "memoryBase" (global $import$32 i32))
+ (import "env" "tableBase" (global $import$33 i32))
+ (import "env" "enlargeMemory" (func $import$7 (result i32)))
+ (import "env" "getTotalMemory" (func $import$8 (result i32)))
+ (import "env" "abortOnCannotGrowMemory" (func $import$9 (result i32)))
+ (import "env" "abortStackOverflow" (func $import$10 (param i32)))
+ (import "env" "nullFunc_ii" (func $import$11 (param i32)))
+ (import "env" "nullFunc_iiii" (func $import$12 (param i32)))
+ (import "env" "nullFunc_vi" (func $import$13 (param i32)))
+ (import "env" "_pthread_cleanup_pop" (func $import$14 (param i32)))
+ (import "env" "___lock" (func $import$15 (param i32)))
+ (import "env" "_abort" (func $import$16))
+ (import "env" "___setErrNo" (func $import$17 (param i32)))
+ (import "env" "___syscall6" (func $import$18 (param i32 i32) (result i32)))
+ (import "env" "___syscall140" (func $import$19 (param i32 i32) (result i32)))
+ (import "env" "_pthread_cleanup_push" (func $import$20 (param i32 i32)))
+ (import "env" "_emscripten_memcpy_big" (func $import$21 (param i32 i32 i32) (result i32)))
+ (import "env" "___syscall54" (func $import$22 (param i32 i32) (result i32)))
+ (import "env" "___unlock" (func $import$23 (param i32)))
+ (import "env" "___syscall146" (func $import$24 (param i32 i32) (result i32)))
+ (import "asm2wasm" "f64-to-int" (func $import$25 (param f64) (result i32)))
+ (import "asm2wasm" "i32s-div" (func $import$26 (param i32 i32) (result i32)))
+ (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))
+ (global $global$5 (mut i32) (i32.const 0))
+ (global $global$6 (mut i32) (i32.const 0))
+ (global $global$7 (mut i32) (i32.const 0))
+ (global $global$8 (mut i32) (i32.const 0))
+ (global $global$9 (mut f64) (global.get $import$5))
+ (global $global$10 (mut f64) (global.get $import$6))
+ (global $global$11 (mut i32) (i32.const 0))
+ (global $global$12 (mut i32) (i32.const 0))
+ (global $global$13 (mut i32) (i32.const 0))
+ (global $global$14 (mut i32) (i32.const 0))
+ (global $global$15 (mut f64) (f64.const 0))
+ (global $global$16 (mut i32) (i32.const 0))
+ (global $global$17 (mut i32) (i32.const 0))
+ (global $global$18 (mut i32) (i32.const 0))
+ (global $global$19 (mut f64) (f64.const 0))
+ (global $global$20 (mut i32) (i32.const 0))
+ (global $global$21 (mut f32) (f32.const 0))
+ (global $global$22 (mut f32) (f32.const 0))
+ (func $27 (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (param $var$3 i32) (param $var$4 i32)
+  (local $var$5 i32)
+  (local $var$6 i32)
+  (local $var$7 i32)
+  (local $var$8 i32)
+  (if
+   (local.get $var$4)
+   (block $label$3
+    (block
+     (if
+      (i32.eqz
+       (local.get $var$8)
+      )
+      (if
+       (i32.eqz
+        (local.get $var$6)
+       )
+       (br $label$3)
+      )
+     )
+     (drop
+      (call $23
+       (local.get $var$7)
+       (local.get $var$4)
+       (local.get $var$0)
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $23 (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (unreachable)
+ )
+ (func $unexitable-loops-result (param $0 i32) (result i64)
+  (loop $label$0
+   (loop $label$1
+    (br_if $label$0
+     (i32.load8_s
+      (i32.const 201460482)
+     )
+    )
+    (block
+     (br_if $label$1
+      (local.get $0)
+     )
+     (br $label$1)
+    )
+   )
+  )
+ )
+)
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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names_remove-unused-brs_vacuum.wast
@@ -0,0 +1,149 @@
+(module
+  (type $0 (func (param i32 i32 i32) (result i32)))
+  (type $1 (func (param f64) (result i32)))
+  (type $2 (func (param i32 i32) (result i32)))
+  (type $3 (func (param i32) (result i32)))
+  (type $4 (func (param i32)))
+  (type $5 (func (result i32)))
+  (type $6 (func))
+  (type $7 (func (param i32 i32)))
+  (type $8 (func (param i64 i32 i32)))
+  (type $9 (func (param i64 i64) (result i64)))
+  (type $10 (func (param i32 i32 i32 i32 i32) (result i32)))
+  (type $11 (func (param i32 i32 i32)))
+  (type $12 (func (param i64 i32) (result i32)))
+  (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))
+  (import "global" "NaN" (global $import$5 f64))
+  (import "global" "Infinity" (global $import$6 f64))
+  (import "env" "enlargeMemory" (func $import$7 (result i32)))
+  (import "env" "getTotalMemory" (func $import$8 (result i32)))
+  (import "env" "abortOnCannotGrowMemory" (func $import$9 (result i32)))
+  (import "env" "abortStackOverflow" (func $import$10 (param i32)))
+  (import "env" "nullFunc_ii" (func $import$11 (param i32)))
+  (import "env" "nullFunc_iiii" (func $import$12 (param i32)))
+  (import "env" "nullFunc_vi" (func $import$13 (param i32)))
+  (import "env" "_pthread_cleanup_pop" (func $import$14 (param i32)))
+  (import "env" "___lock" (func $import$15 (param i32)))
+  (import "env" "_abort" (func $import$16))
+  (import "env" "___setErrNo" (func $import$17 (param i32)))
+  (import "env" "___syscall6" (func $import$18 (param i32 i32) (result i32)))
+  (import "env" "___syscall140" (func $import$19 (param i32 i32) (result i32)))
+  (import "env" "_pthread_cleanup_push" (func $import$20 (param i32 i32)))
+  (import "env" "_emscripten_memcpy_big" (func $import$21 (param i32 i32 i32) (result i32)))
+  (import "env" "___syscall54" (func $import$22 (param i32 i32) (result i32)))
+  (import "env" "___unlock" (func $import$23 (param i32)))
+  (import "env" "___syscall146" (func $import$24 (param i32 i32) (result i32)))
+  (import "asm2wasm" "f64-to-int" (func $import$25 (param f64) (result i32)))
+  (import "asm2wasm" "i32s-div" (func $import$26 (param i32 i32) (result i32)))
+  (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)))
+  (import "env" "memory" (memory $0 256))
+  (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))
+  (global $global$5 (mut i32) (i32.const 0))
+  (global $global$6 (mut i32) (i32.const 0))
+  (global $global$7 (mut i32) (i32.const 0))
+  (global $global$8 (mut i32) (i32.const 0))
+  (global $global$9 (mut f64) (global.get $import$5))
+  (global $global$10 (mut f64) (global.get $import$6))
+  (global $global$11 (mut i32) (i32.const 0))
+  (global $global$12 (mut i32) (i32.const 0))
+  (global $global$13 (mut i32) (i32.const 0))
+  (global $global$14 (mut i32) (i32.const 0))
+  (global $global$15 (mut f64) (f64.const 0))
+  (global $global$16 (mut i32) (i32.const 0))
+  (global $global$17 (mut i32) (i32.const 0))
+  (global $global$18 (mut i32) (i32.const 0))
+  (global $global$19 (mut f64) (f64.const 0))
+  (global $global$20 (mut i32) (i32.const 0))
+  (global $global$21 (mut f32) (f32.const 0))
+  (global $global$22 (mut f32) (f32.const 0))
+  (func $27 (type $13) (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (param $var$3 i32) (param $var$4 i32)
+    (local $var$5 i32)
+    (local $var$6 i32)
+    (local $var$7 i32)
+    (local $var$8 i32)
+    (block $label$0
+      (block $label$1
+        (block $label$3
+          (if
+            (local.get $var$4)
+            (block $label$4
+              (if
+                (local.get $var$8)
+                (block $label$7
+                  (loop $label$8
+                    (block $label$9
+                      (if
+                        (local.get $var$3)
+                        (block $label$12 ;; these empty blocks must never be unreachable-typed
+                        )
+                        (block $label$13
+                          (br $label$9)
+                        )
+                      )
+                      (br $label$8)
+                    )
+                  )
+                )
+                (block $label$16
+                  (if
+                    (local.get $var$6)
+                    (block $label$17
+                    )
+                    (block $label$18
+                      (br $label$3)
+                    )
+                  )
+                )
+              )
+              (drop
+                (call $23
+                  (local.get $var$7)
+                  (local.get $var$4)
+                  (local.get $var$0)
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+  (func $23 (param i32) (param i32) (param i32) (result i32)
+    (unreachable)
+  )
+  (func $unexitable-loops-result (param $0 i32) (result i64)
+   (loop $label$0
+    (loop $label$1
+     (if
+      (i32.load8_s
+       (i32.const 201460482)
+      )
+      (br $label$0)
+      (block $label$3
+       (br_if $label$3
+        (local.get $0)
+       )
+      )
+     )
+     (br $label$1)
+    )
+   )
+  )
+)
+
diff --git a/binaryen/test/passes/remove-unused-names_vacuum.txt b/binaryen/test/passes/remove-unused-names_vacuum.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names_vacuum.txt
@@ -0,0 +1,31 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (func $return-i32-but-body-is-unreachable3 (result i32)
+  (local $label i32)
+  (loop $while-in$1
+   (br $while-in$1)
+  )
+ )
+ (func $return-i32-but-body-is-unreachable4 (result i32)
+  (local $label i32)
+  (loop $while-in$1
+   (br $while-in$1)
+  )
+ )
+ (func $to-drop-unreachable
+  (drop
+   (block (result i32)
+    (unreachable)
+   )
+  )
+ )
+ (func $return-i32-but-body-is-unreachable5 (result i32)
+  (local $label i32)
+  (unreachable)
+ )
+ (func $return-i32-but-body-is-unreachable6 (result i32)
+  (local $label i32)
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/passes/remove-unused-names_vacuum.wast b/binaryen/test/passes/remove-unused-names_vacuum.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names_vacuum.wast
@@ -0,0 +1,40 @@
+(module
+  (func $return-i32-but-body-is-unreachable3 (result i32)
+    (local $label i32)
+    (block ;; without a name here, vaccum had a too-eager bug
+      (loop $while-in$1
+        (br $while-in$1)
+      )
+    )
+  )
+  (func $return-i32-but-body-is-unreachable4 (result i32)
+    (local $label i32)
+    (block ;; without a name here, vaccum had a too-eager bug
+      (loop $while-in$1
+        (br $while-in$1)
+      )
+    )
+    (i32.const 0)
+  )
+  (func $to-drop-unreachable
+   (drop
+    (block (result i32)
+     (unreachable)
+    )
+   )
+  )
+  (func $return-i32-but-body-is-unreachable5 (result i32)
+    (local $label i32)
+    (block ;; without a name here, vaccum had a too-eager bug
+      (unreachable)
+    )
+  )
+  (func $return-i32-but-body-is-unreachable6 (result i32)
+    (local $label i32)
+    (block ;; without a name here, vaccum had a too-eager bug
+      (unreachable)
+    )
+    (i32.const 0)
+  )
+)
+
diff --git a/binaryen/test/passes/remove-unused-names_vacuum_ignore-implicit-traps.txt b/binaryen/test/passes/remove-unused-names_vacuum_ignore-implicit-traps.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names_vacuum_ignore-implicit-traps.txt
@@ -0,0 +1,50 @@
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $i64_=>_none (func (param i64)))
+ (type $f32_=>_none (func (param f32)))
+ (type $f64_=>_none (func (param f64)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_i64 (func (result i64)))
+ (type $none_=>_f32 (func (result f32)))
+ (type $none_=>_f64 (func (result f64)))
+ (import "env" "wasm2js_scratch_load_i32" (func $wasm2js_scratch_load_i32 (param i32) (result i32)))
+ (import "env" "wasm2js_scratch_store_i32" (func $wasm2js_scratch_store_i32 (param i32 i32)))
+ (import "env" "wasm2js_scratch_load_f32" (func $wasm2js_scratch_load_f32 (result f32)))
+ (import "env" "wasm2js_scratch_store_f32" (func $wasm2js_scratch_store_f32 (param f32)))
+ (import "env" "wasm2js_scratch_load_f64" (func $wasm2js_scratch_load_f64 (result f64)))
+ (import "env" "wasm2js_scratch_store_f64" (func $wasm2js_scratch_store_f64 (param f64)))
+ (import "env" "getTempRet0" (func $getTempRet0 (result i32)))
+ (import "env" "wasm2js_scratch_load_i64" (func $legalimport$wasm2js_scratch_load_i64 (result i32)))
+ (import "env" "wasm2js_scratch_store_i64" (func $legalimport$wasm2js_scratch_store_i64 (param i32 i32)))
+ (import "env" "wasm2js_scratch_load_i64" (func $wasm2js_scratch_load_i64 (result i64)))
+ (import "env" "wasm2js_scratch_store_i64" (func $wasm2js_scratch_store_i64 (param i64)))
+ (memory $0 1 1)
+ (global $i64toi32_i32$HIGH_BITS (mut i32) (i32.const 0))
+ (func $0
+  (local $0 f64)
+  (local $1 i32)
+  (nop)
+ )
+ (func $legalfunc$wasm2js_scratch_load_i64 (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $1
+   (i32.or
+    (call $legalimport$wasm2js_scratch_load_i64)
+    (i32.const 0)
+   )
+  )
+  (global.set $i64toi32_i32$HIGH_BITS
+   (call $getTempRet0)
+  )
+  (local.get $1)
+ )
+ (func $legalfunc$wasm2js_scratch_store_i64 (param $0 i32) (param $1 i32)
+  (call $legalimport$wasm2js_scratch_store_i64
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
diff --git a/binaryen/test/passes/remove-unused-names_vacuum_ignore-implicit-traps.wast b/binaryen/test/passes/remove-unused-names_vacuum_ignore-implicit-traps.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-names_vacuum_ignore-implicit-traps.wast
@@ -0,0 +1,81 @@
+(module
+ (type $0 (func))
+ (type $FUNCSIG$j (func (result i32)))
+ (type $FUNCSIG$i (func (result i32)))
+ (type $legaltype$wasm2js_scratch_load_i64 (func (result i32)))
+ (type $FUNCSIG$vj (func (param i32 i32)))
+ (type $legaltype$wasm2js_scratch_store_i64 (func (param i32 i32)))
+ (import "env" "wasm2js_scratch_load_i32" (func $wasm2js_scratch_load_i32 (param i32) (result i32)))
+ (import "env" "wasm2js_scratch_store_i32" (func $wasm2js_scratch_store_i32 (param i32 i32)))
+ (import "env" "wasm2js_scratch_load_f32" (func $wasm2js_scratch_load_f32 (result f32)))
+ (import "env" "wasm2js_scratch_store_f32" (func $wasm2js_scratch_store_f32 (param f32)))
+ (import "env" "wasm2js_scratch_load_f64" (func $wasm2js_scratch_load_f64 (result f64)))
+ (import "env" "wasm2js_scratch_store_f64" (func $wasm2js_scratch_store_f64 (param f64)))
+ (import "env" "getTempRet0" (func $getTempRet0 (result i32)))
+ (import "env" "wasm2js_scratch_load_i64" (func $legalimport$wasm2js_scratch_load_i64 (result i32)))
+ (import "env" "wasm2js_scratch_store_i64" (func $legalimport$wasm2js_scratch_store_i64 (param i32 i32)))
+ (import "env" "wasm2js_scratch_load_i64" (func $wasm2js_scratch_load_i64 (result i64)))
+ (import "env" "wasm2js_scratch_store_i64" (func $wasm2js_scratch_store_i64 (param i64)))
+ (memory $0 1 1)
+ (global $i64toi32_i32$HIGH_BITS (mut i32) (i32.const 0))
+ (func $0 (; 11 ;) (type $0)
+  (local $0 f64)
+  (local $1 i32)
+  (block $label$1
+   (block
+    (nop)
+    (drop
+     (if (result f64)
+      (i32.const 1)
+      (block (result f64)
+       (nop)
+       (f64.load
+        (i32.const 19)
+       )
+      )
+      (block
+       (drop
+        (f64.const 1)
+       )
+       (br $label$1)
+       (nop)
+      )
+     )
+    )
+   )
+   (nop)
+  )
+ )
+ (func $legalfunc$wasm2js_scratch_load_i64 (; 12 ;) (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local.set $1
+   (i32.or
+    (call $legalimport$wasm2js_scratch_load_i64)
+    (block (result i32)
+     (nop)
+     (block (result i32)
+      (nop)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (global.set $i64toi32_i32$HIGH_BITS
+   (call $getTempRet0)
+  )
+  (local.get $1)
+ )
+ (func $legalfunc$wasm2js_scratch_store_i64 (; 13 ;) (param $0 i32) (param $1 i32)
+  (call $legalimport$wasm2js_scratch_store_i64
+   (block (result i32)
+    (nop)
+    (local.get $0)
+   )
+   (block (result i32)
+    (nop)
+    (local.get $1)
+   )
+  )
+ )
+)
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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-nonfunction-module-elements_all-features.txt
@@ -0,0 +1,340 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (memory $0 0)
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $called_indirect)
+ (export "memory" (memory $0))
+ (export "exported" (func $exported))
+ (export "other1" (func $other1))
+ (export "other2" (func $other2))
+ (start $start)
+ (func $start
+  (call $called0)
+ )
+ (func $called0
+  (call $called1)
+ )
+ (func $called1
+  (nop)
+ )
+ (func $called_indirect
+  (nop)
+ )
+ (func $exported
+  (call $called2)
+ )
+ (func $called2
+  (call $called2)
+  (call $called3)
+ )
+ (func $called3
+  (call $called4)
+ )
+ (func $called4
+  (call $called3)
+ )
+ (func $remove0
+  (call $remove1)
+ )
+ (func $remove1
+  (nop)
+ )
+ (func $remove2
+  (call $remove2)
+ )
+ (func $remove3
+  (call $remove4)
+ )
+ (func $remove4
+  (call $remove3)
+ )
+ (func $other1 (param $0 i32)
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+  (call_indirect (type $i32_=>_none)
+   (i32.const 0)
+   (i32.const 0)
+  )
+  (call_indirect (type $i32_=>_none)
+   (i32.const 0)
+   (i32.const 0)
+  )
+  (drop
+   (call_indirect (type $i32_=>_i32)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call_indirect (type $i32_=>_i32)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call_indirect (type $i32_=>_i32)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $other2 (param $0 i32)
+  (unreachable)
+ )
+)
+(module
+)
+(module
+)
+(module
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table $timport$0 1 funcref))
+ (export "mem" (memory $0))
+ (export "tab" (table $0))
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "memory" (memory $0 256))
+ (data (i32.const 1) "hello, world!")
+ (import "env" "table" (table $timport$0 1 funcref))
+ (elem (i32.const 0) $waka)
+ (func $waka
+  (nop)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "memory" (memory $0 256))
+ (import "env" "table" (table $timport$0 0 funcref))
+ (export "user" (func $user))
+ (func $user
+  (drop
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 (shared 23 256))
+ (export "user" (func $user))
+ (func $user
+  (i32.store
+   (i32.const 0)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 (shared 23 256))
+ (export "user" (func $user))
+ (func $user (result i32)
+  (i32.atomic.rmw.add
+   (i32.const 0)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 (shared 23 256))
+ (export "user" (func $user))
+ (func $user (result i32)
+  (i32.atomic.rmw8.cmpxchg_u
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 (shared 23 256))
+ (export "user" (func $user))
+ (func $user
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.atomic.wait
+    (local.get $0)
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 (shared 23 256))
+ (export "user" (func $user))
+ (func $user (result i32)
+  (atomic.notify
+   (i32.const 0)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 23 256)
+ (export "user" (func $user))
+ (func $user (result i32)
+  (memory.grow
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "memory" (memory $0 256))
+ (export "user" (func $user))
+ (func $user (result i32)
+  (memory.grow
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 23 256)
+ (export "user" (func $user))
+ (func $user (result i32)
+  (memory.size)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "memory" (memory $0 256))
+ (data (global.get $memoryBase) "hello, world!")
+ (import "env" "table" (table $timport$0 0 funcref))
+ (elem (global.get $tableBase) $waka)
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (func $waka
+  (nop)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "imported" (global $imported i32))
+ (import "env" "_puts" (func $_puts (param i32) (result i32)))
+ (global $int (mut i32) (global.get $imported))
+ (global $set (mut i32) (i32.const 100))
+ (global $exp_glob i32 (i32.const 600))
+ (export "one" (func $one))
+ (export "three" (func $three))
+ (export "exp_glob" (global $exp_glob))
+ (func $one (result i32)
+  (call $two)
+ )
+ (func $two (result i32)
+  (global.get $int)
+ )
+ (func $three
+  (call $four)
+ )
+ (func $four
+  (global.set $set
+   (i32.const 200)
+  )
+  (drop
+   (call $_puts
+    (i32.const 300)
+   )
+  )
+ )
+ (func $forget_implemented
+  (nop)
+ )
+ (func $starter
+  (nop)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (func $starter
+  (nop)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (start $starter)
+ (func $starter
+  (drop
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $f64_=>_f64 (func (param f64) (result f64)))
+ (func $0 (param $var$0 f64) (result f64)
+  (if (result f64)
+   (f64.eq
+    (f64.const 1)
+    (f64.const 1)
+   )
+   (f64.const 1)
+   (f64.const 0)
+  )
+ )
+)
+(module
+ (type $f64_=>_f64 (func (param f64) (result f64)))
+ (table $0 6 6 funcref)
+ (func $0 (param $var$0 f64) (result f64)
+  (if (result f64)
+   (f64.eq
+    (f64.const 1)
+    (f64.const 1)
+   )
+   (call_indirect (type $f64_=>_f64)
+    (f64.const 1)
+    (i32.const 0)
+   )
+   (f64.const 0)
+  )
+ )
+)
+(module
+ (type $f64_=>_f64 (func (param f64) (result f64)))
+ (import "env" "table" (table $timport$0 6 6 funcref))
+ (elem (i32.const 0) $0)
+ (func $0 (param $var$0 f64) (result f64)
+  (if (result f64)
+   (f64.eq
+    (f64.const 1)
+    (f64.const 1)
+   )
+   (f64.const 1)
+   (f64.const 0)
+  )
+ )
+)
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $i64_=>_none (func (param i64)))
+ (event $e1 (attr 0) (param i64))
+ (export "e1" (event $e1))
+ (func $f (param $0 i32)
+  (nop)
+ )
+)
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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/remove-unused-nonfunction-module-elements_all-features.wast
@@ -0,0 +1,271 @@
+(module
+  (memory 0)
+  (start $start)
+  (type $0 (func))
+  (type $0-dupe (func))
+  (type $1 (func (param i32)))
+  (type $1-dupe (func (param i32)))
+  (type $2 (func (param i32) (result i32)))
+  (type $2-dupe (func (param i32) (result i32)))
+  (type $2-thrupe (func (param i32) (result i32)))
+  (export "memory" (memory $0))
+  (export "exported" $exported)
+  (export "other1" $other1)
+  (export "other2" $other2)
+  (table 1 1 funcref)
+  (elem (i32.const 0) $called_indirect)
+  (func $start (type $0)
+    (call $called0)
+  )
+  (func $called0 (type $0)
+    (call $called1)
+  )
+  (func $called1 (type $0)
+    (nop)
+  )
+  (func $called_indirect (type $0)
+    (nop)
+  )
+  (func $exported (type $0-dupe)
+    (call $called2)
+  )
+  (func $called2 (type $0-dupe)
+    (call $called2)
+    (call $called3)
+  )
+  (func $called3 (type $0-dupe)
+    (call $called4)
+  )
+  (func $called4 (type $0-dupe)
+    (call $called3)
+  )
+  (func $remove0 (type $0-dupe)
+    (call $remove1)
+  )
+  (func $remove1 (type $0-dupe)
+    (nop)
+  )
+  (func $remove2 (type $0-dupe)
+    (call $remove2)
+  )
+  (func $remove3 (type $0)
+    (call $remove4)
+  )
+  (func $remove4 (type $0)
+    (call $remove3)
+  )
+  (func $other1 (type $1) (param i32)
+    (call_indirect (type $0) (i32.const 0))
+    (call_indirect (type $0) (i32.const 0))
+    (call_indirect (type $0-dupe) (i32.const 0))
+    (call_indirect (type $0-dupe) (i32.const 0))
+    (call_indirect (type $1) (i32.const 0) (i32.const 0))
+    (call_indirect (type $1-dupe) (i32.const 0) (i32.const 0))
+    (drop (call_indirect (type $2) (i32.const 0) (i32.const 0)))
+    (drop (call_indirect (type $2-dupe) (i32.const 0) (i32.const 0)))
+    (drop (call_indirect (type $2-thrupe) (i32.const 0) (i32.const 0)))
+  )
+  (func $other2 (type $1-dupe) (param i32)
+    (unreachable)
+  )
+)
+(module ;; remove the table and memory
+  (import "env" "memory" (memory $0 256))
+  (import "env" "table" (table 0 funcref))
+)
+(module ;; also when not imported
+  (memory 256)
+  (table 1 funcref)
+)
+(module ;; but not when exported
+  (import "env" "memory" (memory $0 256))
+  (import "env" "table" (table 1 funcref))
+  (export "mem" (memory 0))
+  (export "tab" (table 0))
+)
+(module ;; and not when there are segments
+  (import "env" "memory" (memory $0 256))
+  (import "env" "table" (table 1 funcref))
+  (data (i32.const 1) "hello, world!")
+  (elem (i32.const 0) $waka)
+  (func $waka)
+)
+(module ;; and not when used
+  (type $0 (func))
+  (import "env" "memory" (memory $0 256))
+  (import "env" "table" (table 0 funcref))
+  (export "user" $user)
+  (func $user
+    (drop (i32.load (i32.const 0)))
+    (call_indirect (type $0) (i32.const 0))
+  )
+)
+(module ;; more use checks
+  (memory $0 (shared 23 256))
+  (export "user" $user)
+  (func $user
+    (i32.store (i32.const 0) (i32.const 0))
+  )
+)
+(module ;; more use checks
+  (memory $0 (shared 23 256))
+  (export "user" $user)
+  (func $user (result i32)
+    (i32.atomic.rmw.add (i32.const 0) (i32.const 0))
+  )
+)
+(module ;; more use checks
+  (memory $0 (shared 23 256))
+  (export "user" $user)
+  (func $user (result i32)
+    (i32.atomic.rmw8.cmpxchg_u (i32.const 0) (i32.const 0) (i32.const 0))
+  )
+)
+(module ;; more use checks
+  (memory $0 (shared 23 256))
+  (export "user" $user)
+  (func $user
+    (local $0 i32)
+    (local $1 i64)
+    (drop
+     (i32.atomic.wait
+      (local.get $0)
+      (local.get $0)
+      (local.get $1)
+     )
+    )
+  )
+)
+(module ;; more use checks
+  (memory $0 (shared 23 256))
+  (export "user" $user)
+  (func $user (result i32)
+    (atomic.notify (i32.const 0) (i32.const 0))
+  )
+)
+(module ;; more use checks
+  (memory $0 23 256)
+  (export "user" $user)
+  (func $user (result i32)
+    (memory.grow (i32.const 0))
+  )
+)
+(module ;; more use checks
+  (import "env" "memory" (memory $0 256))
+  (export "user" $user)
+  (func $user (result i32)
+    (memory.grow (i32.const 0))
+  )
+)
+(module ;; more use checks
+  (memory $0 23 256)
+  (export "user" $user)
+  (func $user (result i32)
+    (memory.size)
+  )
+)
+(module
+  (import "env" "memory" (memory $0 256))
+  (import "env" "table" (table 0 funcref))
+  (import "env" "memoryBase" (global $memoryBase i32)) ;; used in init
+  (import "env" "tableBase" (global $tableBase i32)) ;; used in init
+  (data (global.get $memoryBase) "hello, world!")
+  (elem (global.get $tableBase) $waka)
+  (func $waka) ;; used in table
+)
+(module ;; one is exported, and one->two->int global, whose init->imported
+  (import "env" "imported" (global $imported i32))
+  (import "env" "forgetme" (global $forgetme i32))
+  (import "env" "_puts" (func $_puts (param i32) (result i32)))
+  (import "env" "forget_puts" (func $forget_puts (param i32) (result i32)))
+  (global $int (mut i32) (global.get $imported))
+  (global $set (mut i32) (i32.const 100))
+  (global $forglobal.get (mut i32) (i32.const 500))
+  (global $exp_glob i32 (i32.const 600))
+  (export "one" (func $one))
+  (export "three" (func $three))
+  (export "exp_glob" (global $exp_glob))
+  (start $starter)
+  (func $one (result i32)
+    (call $two)
+  )
+  (func $two (result i32)
+    (global.get $int)
+  )
+  (func $three
+    (call $four)
+  )
+  (func $four
+    (global.set $set (i32.const 200))
+    (drop (call $_puts (i32.const 300)))
+  )
+  (func $forget_implemented
+    (nop)
+  )
+  (func $starter
+    (nop)
+  )
+)
+(module ;; empty start being removed
+  (start $starter)
+  (func $starter
+    (nop)
+  )
+)
+(module ;; non-empty start being kept
+  (start $starter)
+  (func $starter
+    (drop (i32.const 0))
+  )
+)
+(module ;; the function stays but the table can be removed
+ (type $0 (func (param f64) (result f64)))
+ (table 6 6 funcref)
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+  (if (result f64)
+   (f64.eq
+    (f64.const 1)
+    (f64.const 1)
+   )
+   (f64.const 1)
+   (f64.const 0)
+  )
+ )
+)
+(module ;; the function keeps the table alive
+ (type $0 (func (param f64) (result f64)))
+ (table 6 6 funcref)
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+  (if (result f64)
+   (f64.eq
+    (f64.const 1)
+    (f64.const 1)
+   )
+   (call_indirect (type $0) (f64.const 1) (i32.const 0))
+   (f64.const 0)
+  )
+ )
+)
+(module ;; the table is imported - we can't remove it
+ (type $0 (func (param f64) (result f64)))
+ (import "env" "table" (table 6 6 funcref))
+ (elem (i32.const 0) $0)
+ (func $0 (; 0 ;) (type $0) (param $var$0 f64) (result f64)
+  (if (result f64)
+   (f64.eq
+    (f64.const 1)
+    (f64.const 1)
+   )
+   (f64.const 1)
+   (f64.const 0)
+  )
+ )
+)
+(module ;; non-exported events can be removed
+ (type $0 (func (param i32)))
+ (event $e0 (attr 0) (type $0))
+ (event $e1 (attr 0) (param i64))
+ (export "e1" (event $e1))
+ (import "env" "e" (event $e2 (attr 0) (param i32)))
+ (func $f (; 0 ;) (type $0))
+)
diff --git a/binaryen/test/passes/reorder-functions.txt b/binaryen/test/passes/reorder-functions.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/reorder-functions.txt
@@ -0,0 +1,16 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 256 256)
+ (func $c
+  (call $c)
+  (call $c)
+  (call $c)
+ )
+ (func $b
+  (call $b)
+  (call $b)
+ )
+ (func $a
+  (call $a)
+ )
+)
diff --git a/binaryen/test/passes/reorder-functions.wast b/binaryen/test/passes/reorder-functions.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/reorder-functions.wast
@@ -0,0 +1,16 @@
+(module
+  (memory 256 256)
+  (type $0 (func))
+  (func $a (type $0)
+    (call $a)
+  )
+  (func $b (type $0)
+    (call $b)
+    (call $b)
+  )
+  (func $c (type $0)
+    (call $c)
+    (call $c)
+    (call $c)
+  )
+)
diff --git a/binaryen/test/passes/reorder-locals.txt b/binaryen/test/passes/reorder-locals.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/reorder-locals.txt
@@ -0,0 +1,55 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (memory $0 256 256)
+ (func $b0-yes (param $a i32) (param $b i32)
+  (local $z i32)
+  (local $y i32)
+  (local $x i32)
+  (local.set $x
+   (local.get $x)
+  )
+  (local.set $y
+   (local.get $y)
+  )
+  (local.set $y
+   (local.get $y)
+  )
+  (local.set $z
+   (local.get $z)
+  )
+  (local.set $z
+   (local.get $z)
+  )
+  (local.set $z
+   (local.get $z)
+  )
+  (local.set $b
+   (local.get $b)
+  )
+  (local.set $b
+   (local.get $b)
+  )
+  (local.set $b
+   (local.get $b)
+  )
+  (local.set $b
+   (local.get $b)
+  )
+  (local.set $b
+   (local.get $b)
+  )
+  (local.set $b
+   (local.get $b)
+  )
+ )
+ (func $zero
+  (local $b i32)
+  (drop
+   (local.get $b)
+  )
+ )
+ (func $null
+  (nop)
+ )
+)
diff --git a/binaryen/test/passes/reorder-locals.wast b/binaryen/test/passes/reorder-locals.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/reorder-locals.wast
@@ -0,0 +1,59 @@
+(module
+  (memory 256 256)
+  (type $0 (func (param i32 i32)))
+  (type $1 (func))
+  (func $b0-yes (type $0) (param $a i32) (param $b i32)
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local.set $x
+      (local.get $x)
+    )
+    (local.set $y
+      (local.get $y)
+    )
+    (local.set $y
+      (local.get $y)
+    )
+    (local.set $z
+      (local.get $z)
+    )
+    (local.set $z
+      (local.get $z)
+    )
+    (local.set $z
+      (local.get $z)
+    )
+    (local.set $b
+      (local.get $b)
+    )
+    (local.set $b
+      (local.get $b)
+    )
+    (local.set $b
+      (local.get $b)
+    )
+    (local.set $b
+      (local.get $b)
+    )
+    (local.set $b
+      (local.get $b)
+    )
+    (local.set $b
+      (local.get $b)
+    )
+  )
+  (func $zero (type $1)
+    (local $a i32)
+    (local $b i32)
+    (local $c i32)
+    (drop
+      (local.get $b)
+    )
+  )
+  (func $null (type $1)
+    (local $a i32)
+    (local $c i32)
+    (nop)
+  )
+)
diff --git a/binaryen/test/passes/reverse_dwarf_abbrevs.bin.txt b/binaryen/test/passes/reverse_dwarf_abbrevs.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/reverse_dwarf_abbrevs.bin.txt
@@ -0,0 +1,2374 @@
+DWARF debug info
+================
+
+Contains section .debug_info (79 bytes)
+Contains section .debug_abbrev (64 bytes)
+Contains section .debug_line (53 bytes)
+Contains section .debug_str (206 bytes)
+
+.debug_abbrev contents:
+Abbrev table for offset: 0x00000000
+[1] DW_TAG_base_type	DW_CHILDREN_no
+	DW_AT_name	DW_FORM_strp
+	DW_AT_encoding	DW_FORM_data1
+	DW_AT_byte_size	DW_FORM_data1
+
+[2] DW_TAG_GNU_call_site	DW_CHILDREN_no
+	DW_AT_low_pc	DW_FORM_addr
+
+[3] DW_TAG_subprogram	DW_CHILDREN_yes
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+	DW_AT_frame_base	DW_FORM_exprloc
+	DW_AT_GNU_all_call_sites	DW_FORM_flag_present
+	DW_AT_name	DW_FORM_strp
+	DW_AT_decl_file	DW_FORM_data1
+	DW_AT_decl_line	DW_FORM_data1
+	DW_AT_type	DW_FORM_ref4
+	DW_AT_external	DW_FORM_flag_present
+
+[4] DW_TAG_compile_unit	DW_CHILDREN_yes
+	DW_AT_producer	DW_FORM_strp
+	DW_AT_language	DW_FORM_data2
+	DW_AT_name	DW_FORM_strp
+	DW_AT_stmt_list	DW_FORM_sec_offset
+	DW_AT_comp_dir	DW_FORM_strp
+	DW_AT_low_pc	DW_FORM_addr
+	DW_AT_high_pc	DW_FORM_data4
+
+
+.debug_info contents:
+0x00000000: Compile Unit: length = 0x0000004b version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x0000004f)
+
+0x0000000b: DW_TAG_compile_unit [4] *
+              DW_AT_producer [DW_FORM_strp]	( .debug_str[0x00000000] = "clang version 12.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 576bd52f778405de08f309678e4fe4f7523bf7c4)")
+              DW_AT_language [DW_FORM_data2]	(DW_LANG_C99)
+              DW_AT_name [DW_FORM_strp]	( .debug_str[0x00000095] = "tests/hello_world.c")
+              DW_AT_stmt_list [DW_FORM_sec_offset]	(0x00000000)
+              DW_AT_comp_dir [DW_FORM_strp]	( .debug_str[0x000000a9] = "/home/azakai/Dev/emscripten")
+              DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+              DW_AT_high_pc [DW_FORM_data4]	(0x00000000)
+
+0x00000026:   DW_TAG_subprogram [3] *
+                DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+                DW_AT_high_pc [DW_FORM_data4]	(0x00000000)
+                DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_WASM_location 0x3 +0, <decoding error> 00 00 9f)
+                DW_AT_GNU_all_call_sites [DW_FORM_flag_present]	(true)
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000c5] = "main")
+                DW_AT_decl_file [DW_FORM_data1]	("/home/azakai/Dev/emscripten/tests/hello_world.c")
+                DW_AT_decl_line [DW_FORM_data1]	(10)
+                DW_AT_type [DW_FORM_ref4]	(cu + 0x0047 => {0x00000047} "int")
+                DW_AT_external [DW_FORM_flag_present]	(true)
+
+0x00000041:     DW_TAG_GNU_call_site [2]  
+                  DW_AT_low_pc [DW_FORM_addr]	(0x0000000000000000)
+
+0x00000046:     NULL
+
+0x00000047:   DW_TAG_base_type [1]  
+                DW_AT_name [DW_FORM_strp]	( .debug_str[0x000000ca] = "int")
+                DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
+                DW_AT_byte_size [DW_FORM_data1]	(0x04)
+
+0x0000004e:   NULL
+
+.debug_line contents:
+debug_line[0x00000000]
+Line table prologue:
+    total_length: 0x00000031
+         version: 4
+ prologue_length: 0x0000002b
+ min_inst_length: 1
+max_ops_per_inst: 1
+ default_is_stmt: 1
+       line_base: -5
+      line_range: 14
+     opcode_base: 13
+standard_opcode_lengths[DW_LNS_copy] = 0
+standard_opcode_lengths[DW_LNS_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_advance_line] = 1
+standard_opcode_lengths[DW_LNS_set_file] = 1
+standard_opcode_lengths[DW_LNS_set_column] = 1
+standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+standard_opcode_lengths[DW_LNS_set_isa] = 1
+include_directories[  1] = "tests"
+file_names[  1]:
+           name: "hello_world.c"
+      dir_index: 1
+       mod_time: 0x00000000
+         length: 0x00000000
+
+.debug_str contents:
+0x00000000: "clang version 12.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 576bd52f778405de08f309678e4fe4f7523bf7c4)"
+0x00000095: "tests/hello_world.c"
+0x000000a9: "/home/azakai/Dev/emscripten"
+0x000000c5: "main"
+0x000000ca: "int"
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (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_=>_i32 (func (param i32 i32 i32 i32) (result i32)))
+ (type $i32_i64_i32_=>_i64 (func (param i32 i64 i32) (result i64)))
+ (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))
+ (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))
+ (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)))
+ (import "env" "setTempRet0" (func $fimport$2 (param i32)))
+ (global $global$0 (mut i32) (i32.const 5245136))
+ (global $global$1 i32 (i32.const 2248))
+ (export "__wasm_call_ctors" (func $0))
+ (export "main" (func $2))
+ (export "__errno_location" (func $3))
+ (export "stackSave" (func $18))
+ (export "stackRestore" (func $19))
+ (export "stackAlloc" (func $20))
+ (export "__data_end" (global $global$1))
+ (export "dynCall_jiji" (func $22))
+ (export "__growWasmMemory" (func $23))
+ (func $0
+  ;; code offset: 0x3
+  (nop)
+ )
+ (func $1 (result i32)
+  ;; code offset: 0xc
+  (drop
+   ;; code offset: 0xa
+   (call $14
+    ;; code offset: 0x7
+    (i32.const 1024)
+   )
+  )
+  ;; code offset: 0xd
+  (i32.const 0)
+ )
+ (func $2 (param $0 i32) (param $1 i32) (result i32)
+  ;; code offset: 0x12
+  (call $1)
+ )
+ (func $3 (result i32)
+  ;; code offset: 0x17
+  (i32.const 1200)
+ )
+ (func $4 (param $0 i32) (result i32)
+  ;; code offset: 0x20
+  (if
+   ;; code offset: 0x1f
+   (i32.eqz
+    ;; code offset: 0x1d
+    (local.get $0)
+   )
+   ;; code offset: 0x24
+   (return
+    ;; code offset: 0x22
+    (i32.const 0)
+   )
+  )
+  ;; code offset: 0x2a
+  (i32.store
+   ;; code offset: 0x26
+   (call $3)
+   ;; code offset: 0x28
+   (local.get $0)
+  )
+  ;; code offset: 0x2d
+  (i32.const -1)
+ )
+ (func $5 (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  ;; code offset: 0x48
+  (global.set $global$0
+   ;; code offset: 0x46
+   (local.tee $3
+    ;; code offset: 0x45
+    (i32.sub
+     ;; code offset: 0x41
+     (global.get $global$0)
+     ;; code offset: 0x43
+     (i32.const 32)
+    )
+   )
+  )
+  ;; code offset: 0x53
+  (i32.store offset=16
+   ;; code offset: 0x4a
+   (local.get $3)
+   ;; code offset: 0x51
+   (local.tee $4
+    ;; code offset: 0x4e
+    (i32.load offset=28
+     ;; code offset: 0x4c
+     (local.get $0)
+    )
+   )
+  )
+  ;; code offset: 0x5b
+  (local.set $5
+   ;; code offset: 0x58
+   (i32.load offset=20
+    ;; code offset: 0x56
+    (local.get $0)
+   )
+  )
+  ;; code offset: 0x61
+  (i32.store offset=28
+   ;; code offset: 0x5d
+   (local.get $3)
+   ;; code offset: 0x5f
+   (local.get $2)
+  )
+  ;; code offset: 0x68
+  (i32.store offset=24
+   ;; code offset: 0x64
+   (local.get $3)
+   ;; code offset: 0x66
+   (local.get $1)
+  )
+  ;; code offset: 0x74
+  (i32.store offset=20
+   ;; code offset: 0x6b
+   (local.get $3)
+   ;; code offset: 0x72
+   (local.tee $1
+    ;; code offset: 0x71
+    (i32.sub
+     ;; code offset: 0x6d
+     (local.get $5)
+     ;; code offset: 0x6f
+     (local.get $4)
+    )
+   )
+  )
+  ;; code offset: 0x7c
+  (local.set $6
+   ;; code offset: 0x7b
+   (i32.add
+    ;; code offset: 0x77
+    (local.get $1)
+    ;; code offset: 0x79
+    (local.get $2)
+   )
+  )
+  ;; code offset: 0x80
+  (local.set $7
+   ;; code offset: 0x7e
+   (i32.const 2)
+  )
+  ;; code offset: 0x87
+  (local.set $1
+   ;; code offset: 0x86
+   (i32.add
+    ;; code offset: 0x82
+    (local.get $3)
+    ;; code offset: 0x84
+    (i32.const 16)
+   )
+  )
+  ;; code offset: 0x18d
+  (local.set $4
+   ;; code offset: 0x89
+   (block $label$1 (result i32)
+    (block $label$2
+     (block $label$3
+      ;; code offset: 0xa5
+      (if
+       ;; code offset: 0xa4
+       (i32.eqz
+        ;; code offset: 0xa2
+        (call $4
+         ;; code offset: 0xa0
+         (call $fimport$0
+          ;; code offset: 0x91
+          (i32.load offset=60
+           ;; code offset: 0x8f
+           (local.get $0)
+          )
+          ;; code offset: 0x98
+          (i32.add
+           ;; code offset: 0x94
+           (local.get $3)
+           ;; code offset: 0x96
+           (i32.const 16)
+          )
+          ;; code offset: 0x99
+          (i32.const 2)
+          ;; code offset: 0x9f
+          (i32.add
+           ;; code offset: 0x9b
+           (local.get $3)
+           ;; code offset: 0x9d
+           (i32.const 12)
+          )
+         )
+        )
+       )
+       ;; code offset: 0xa7
+       (loop $label$5
+        ;; code offset: 0xb3
+        (br_if $label$3
+         ;; code offset: 0xb2
+         (i32.eq
+          ;; code offset: 0xa9
+          (local.get $6)
+          ;; code offset: 0xb0
+          (local.tee $4
+           ;; code offset: 0xad
+           (i32.load offset=12
+            ;; code offset: 0xab
+            (local.get $3)
+           )
+          )
+         )
+        )
+        ;; code offset: 0xba
+        (br_if $label$2
+         ;; code offset: 0xb9
+         (i32.le_s
+          ;; code offset: 0xb5
+          (local.get $4)
+          ;; code offset: 0xb7
+          (i32.const -1)
+         )
+        )
+        ;; code offset: 0xe2
+        (i32.store
+         ;; code offset: 0xce
+         (local.tee $9
+          ;; code offset: 0xcd
+          (i32.add
+           ;; code offset: 0xbc
+           (local.get $1)
+           ;; code offset: 0xcc
+           (i32.shl
+            ;; code offset: 0xc8
+            (local.tee $5
+             ;; code offset: 0xc7
+             (i32.gt_u
+              ;; code offset: 0xbe
+              (local.get $4)
+              ;; code offset: 0xc5
+              (local.tee $8
+               ;; code offset: 0xc2
+               (i32.load offset=4
+                ;; code offset: 0xc0
+                (local.get $1)
+               )
+              )
+             )
+            )
+            ;; code offset: 0xca
+            (i32.const 3)
+           )
+          )
+         )
+         ;; code offset: 0xe1
+         (i32.add
+          ;; code offset: 0xda
+          (local.tee $8
+           ;; code offset: 0xd9
+           (i32.sub
+            ;; code offset: 0xd0
+            (local.get $4)
+            ;; code offset: 0xd8
+            (select
+             ;; code offset: 0xd2
+             (local.get $8)
+             ;; code offset: 0xd4
+             (i32.const 0)
+             ;; code offset: 0xd6
+             (local.get $5)
+            )
+           )
+          )
+          ;; code offset: 0xde
+          (i32.load
+           ;; code offset: 0xdc
+           (local.get $9)
+          )
+         )
+        )
+        ;; code offset: 0xf9
+        (i32.store
+         ;; code offset: 0xef
+         (local.tee $9
+          ;; code offset: 0xee
+          (i32.add
+           ;; code offset: 0xe5
+           (local.get $1)
+           ;; code offset: 0xed
+           (select
+            ;; code offset: 0xe7
+            (i32.const 12)
+            ;; code offset: 0xe9
+            (i32.const 4)
+            ;; code offset: 0xeb
+            (local.get $5)
+           )
+          )
+         )
+         ;; code offset: 0xf8
+         (i32.sub
+          ;; code offset: 0xf3
+          (i32.load
+           ;; code offset: 0xf1
+           (local.get $9)
+          )
+          ;; code offset: 0xf6
+          (local.get $8)
+         )
+        )
+        ;; code offset: 0x101
+        (local.set $6
+         ;; code offset: 0x100
+         (i32.sub
+          ;; code offset: 0xfc
+          (local.get $6)
+          ;; code offset: 0xfe
+          (local.get $4)
+         )
+        )
+        ;; code offset: 0x125
+        (br_if $label$5
+         ;; code offset: 0x124
+         (i32.eqz
+          ;; code offset: 0x122
+          (call $4
+           ;; code offset: 0x120
+           (call $fimport$0
+            ;; code offset: 0x105
+            (i32.load offset=60
+             ;; code offset: 0x103
+             (local.get $0)
+            )
+            ;; code offset: 0x112
+            (local.tee $1
+             ;; code offset: 0x111
+             (select
+              ;; code offset: 0x10c
+              (i32.add
+               ;; code offset: 0x108
+               (local.get $1)
+               ;; code offset: 0x10a
+               (i32.const 8)
+              )
+              ;; code offset: 0x10d
+              (local.get $1)
+              ;; code offset: 0x10f
+              (local.get $5)
+             )
+            )
+            ;; code offset: 0x119
+            (local.tee $7
+             ;; code offset: 0x118
+             (i32.sub
+              ;; code offset: 0x114
+              (local.get $7)
+              ;; code offset: 0x116
+              (local.get $5)
+             )
+            )
+            ;; code offset: 0x11f
+            (i32.add
+             ;; code offset: 0x11b
+             (local.get $3)
+             ;; code offset: 0x11d
+             (i32.const 12)
+            )
+           )
+          )
+         )
+        )
+       )
+      )
+      ;; code offset: 0x12d
+      (i32.store offset=12
+       ;; code offset: 0x129
+       (local.get $3)
+       ;; code offset: 0x12b
+       (i32.const -1)
+      )
+      ;; code offset: 0x135
+      (br_if $label$2
+       ;; code offset: 0x134
+       (i32.ne
+        ;; code offset: 0x130
+        (local.get $6)
+        ;; code offset: 0x132
+        (i32.const -1)
+       )
+      )
+     )
+     ;; code offset: 0x141
+     (i32.store offset=28
+      ;; code offset: 0x138
+      (local.get $0)
+      ;; code offset: 0x13f
+      (local.tee $1
+       ;; code offset: 0x13c
+       (i32.load offset=44
+        ;; code offset: 0x13a
+        (local.get $0)
+       )
+      )
+     )
+     ;; code offset: 0x148
+     (i32.store offset=20
+      ;; code offset: 0x144
+      (local.get $0)
+      ;; code offset: 0x146
+      (local.get $1)
+     )
+     ;; code offset: 0x155
+     (i32.store offset=16
+      ;; code offset: 0x14b
+      (local.get $0)
+      ;; code offset: 0x154
+      (i32.add
+       ;; code offset: 0x14d
+       (local.get $1)
+       ;; code offset: 0x151
+       (i32.load offset=48
+        ;; code offset: 0x14f
+        (local.get $0)
+       )
+      )
+     )
+     ;; code offset: 0x15a
+     (br $label$1
+      ;; code offset: 0x158
+      (local.get $2)
+     )
+    )
+    ;; code offset: 0x161
+    (i32.store offset=28
+     ;; code offset: 0x15d
+     (local.get $0)
+     ;; code offset: 0x15f
+     (i32.const 0)
+    )
+    ;; code offset: 0x168
+    (i64.store offset=16
+     ;; code offset: 0x164
+     (local.get $0)
+     ;; code offset: 0x166
+     (i64.const 0)
+    )
+    ;; code offset: 0x175
+    (i32.store
+     ;; code offset: 0x16b
+     (local.get $0)
+     ;; code offset: 0x174
+     (i32.or
+      ;; code offset: 0x16f
+      (i32.load
+       ;; code offset: 0x16d
+       (local.get $0)
+      )
+      ;; code offset: 0x172
+      (i32.const 32)
+     )
+    )
+    ;; code offset: 0x183
+    (drop
+     ;; code offset: 0x181
+     (br_if $label$1
+      ;; code offset: 0x17a
+      (local.tee $4
+       ;; code offset: 0x178
+       (i32.const 0)
+      )
+      ;; code offset: 0x180
+      (i32.eq
+       ;; code offset: 0x17c
+       (local.get $7)
+       ;; code offset: 0x17e
+       (i32.const 2)
+      )
+     )
+    )
+    ;; code offset: 0x18b
+    (i32.sub
+     ;; code offset: 0x184
+     (local.get $2)
+     ;; code offset: 0x188
+     (i32.load offset=4
+      ;; code offset: 0x186
+      (local.get $1)
+     )
+    )
+   )
+  )
+  ;; code offset: 0x194
+  (global.set $global$0
+   ;; code offset: 0x193
+   (i32.add
+    ;; code offset: 0x18f
+    (local.get $3)
+    ;; code offset: 0x191
+    (i32.const 32)
+   )
+  )
+  ;; code offset: 0x196
+  (local.get $4)
+ )
+ (func $6 (param $0 i32) (result i32)
+  ;; code offset: 0x19b
+  (i32.const 0)
+ )
+ (func $7 (param $0 i32) (param $1 i64) (param $2 i32) (result i64)
+  ;; code offset: 0x1a0
+  (i64.const 0)
+ )
+ (func $8 (param $0 i32) (result i32)
+  (local $1 i32)
+  ;; code offset: 0x1b6
+  (i32.store8 offset=74
+   ;; code offset: 0x1a7
+   (local.get $0)
+   ;; code offset: 0x1b5
+   (i32.or
+    ;; code offset: 0x1b2
+    (i32.add
+     ;; code offset: 0x1ae
+     (local.tee $1
+      ;; code offset: 0x1ab
+      (i32.load8_u offset=74
+       ;; code offset: 0x1a9
+       (local.get $0)
+      )
+     )
+     ;; code offset: 0x1b0
+     (i32.const -1)
+    )
+    ;; code offset: 0x1b3
+    (local.get $1)
+   )
+  )
+  ;; code offset: 0x1c3
+  (if
+   ;; code offset: 0x1c2
+   (i32.and
+    ;; code offset: 0x1be
+    (local.tee $1
+     ;; code offset: 0x1bb
+     (i32.load
+      ;; code offset: 0x1b9
+      (local.get $0)
+     )
+    )
+    ;; code offset: 0x1c0
+    (i32.const 8)
+   )
+   (block
+    ;; code offset: 0x1cc
+    (i32.store
+     ;; code offset: 0x1c5
+     (local.get $0)
+     ;; code offset: 0x1cb
+     (i32.or
+      ;; code offset: 0x1c7
+      (local.get $1)
+      ;; code offset: 0x1c9
+      (i32.const 32)
+     )
+    )
+    ;; code offset: 0x1d1
+    (return
+     ;; code offset: 0x1cf
+     (i32.const -1)
+    )
+   )
+  )
+  ;; code offset: 0x1d7
+  (i64.store offset=4 align=4
+   ;; code offset: 0x1d3
+   (local.get $0)
+   ;; code offset: 0x1d5
+   (i64.const 0)
+  )
+  ;; code offset: 0x1e3
+  (i32.store offset=28
+   ;; code offset: 0x1da
+   (local.get $0)
+   ;; code offset: 0x1e1
+   (local.tee $1
+    ;; code offset: 0x1de
+    (i32.load offset=44
+     ;; code offset: 0x1dc
+     (local.get $0)
+    )
+   )
+  )
+  ;; code offset: 0x1ea
+  (i32.store offset=20
+   ;; code offset: 0x1e6
+   (local.get $0)
+   ;; code offset: 0x1e8
+   (local.get $1)
+  )
+  ;; code offset: 0x1f7
+  (i32.store offset=16
+   ;; code offset: 0x1ed
+   (local.get $0)
+   ;; code offset: 0x1f6
+   (i32.add
+    ;; code offset: 0x1ef
+    (local.get $1)
+    ;; code offset: 0x1f3
+    (i32.load offset=48
+     ;; code offset: 0x1f1
+     (local.get $0)
+    )
+   )
+  )
+  ;; code offset: 0x1fa
+  (i32.const 0)
+ )
+ (func $9 (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  ;; code offset: 0x20c
+  (if
+   ;; code offset: 0x20b
+   (i32.ge_u
+    ;; code offset: 0x206
+    (local.get $2)
+    ;; code offset: 0x208
+    (i32.const 512)
+   )
+   (block
+    ;; code offset: 0x216
+    (drop
+     ;; code offset: 0x214
+     (call $fimport$1
+      ;; code offset: 0x20e
+      (local.get $0)
+      ;; code offset: 0x210
+      (local.get $1)
+      ;; code offset: 0x212
+      (local.get $2)
+     )
+    )
+    ;; code offset: 0x219
+    (return
+     ;; code offset: 0x217
+     (local.get $0)
+    )
+   )
+  )
+  ;; code offset: 0x220
+  (local.set $3
+   ;; code offset: 0x21f
+   (i32.add
+    ;; code offset: 0x21b
+    (local.get $0)
+    ;; code offset: 0x21d
+    (local.get $2)
+   )
+  )
+  ;; code offset: 0x222
+  (block $label$2
+   ;; code offset: 0x22d
+   (if
+    ;; code offset: 0x22c
+    (i32.eqz
+     ;; code offset: 0x22b
+     (i32.and
+      ;; code offset: 0x228
+      (i32.xor
+       ;; code offset: 0x224
+       (local.get $0)
+       ;; code offset: 0x226
+       (local.get $1)
+      )
+      ;; code offset: 0x229
+      (i32.const 3)
+     )
+    )
+    (block
+     ;; code offset: 0x22f
+     (block $label$4
+      ;; code offset: 0x236
+      (if
+       ;; code offset: 0x235
+       (i32.lt_s
+        ;; code offset: 0x231
+        (local.get $2)
+        ;; code offset: 0x233
+        (i32.const 1)
+       )
+       (block
+        ;; code offset: 0x23a
+        (local.set $2
+         ;; code offset: 0x238
+         (local.get $0)
+        )
+        ;; code offset: 0x23c
+        (br $label$4)
+       )
+      )
+      ;; code offset: 0x245
+      (if
+       ;; code offset: 0x244
+       (i32.eqz
+        ;; code offset: 0x243
+        (i32.and
+         ;; code offset: 0x23f
+         (local.get $0)
+         ;; code offset: 0x241
+         (i32.const 3)
+        )
+       )
+       (block
+        ;; code offset: 0x249
+        (local.set $2
+         ;; code offset: 0x247
+         (local.get $0)
+        )
+        ;; code offset: 0x24b
+        (br $label$4)
+       )
+      )
+      ;; code offset: 0x250
+      (local.set $2
+       ;; code offset: 0x24e
+       (local.get $0)
+      )
+      ;; code offset: 0x252
+      (loop $label$7
+       ;; code offset: 0x25b
+       (i32.store8
+        ;; code offset: 0x254
+        (local.get $2)
+        ;; code offset: 0x258
+        (i32.load8_u
+         ;; code offset: 0x256
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x263
+       (local.set $1
+        ;; code offset: 0x262
+        (i32.add
+         ;; code offset: 0x25e
+         (local.get $1)
+         ;; code offset: 0x260
+         (i32.const 1)
+        )
+       )
+       ;; code offset: 0x26f
+       (br_if $label$4
+        ;; code offset: 0x26e
+        (i32.ge_u
+         ;; code offset: 0x26a
+         (local.tee $2
+          ;; code offset: 0x269
+          (i32.add
+           ;; code offset: 0x265
+           (local.get $2)
+           ;; code offset: 0x267
+           (i32.const 1)
+          )
+         )
+         ;; code offset: 0x26c
+         (local.get $3)
+        )
+       )
+       ;; code offset: 0x276
+       (br_if $label$7
+        ;; code offset: 0x275
+        (i32.and
+         ;; code offset: 0x271
+         (local.get $2)
+         ;; code offset: 0x273
+         (i32.const 3)
+        )
+       )
+      )
+     )
+     ;; code offset: 0x27a
+     (block $label$8
+      ;; code offset: 0x287
+      (br_if $label$8
+       ;; code offset: 0x286
+       (i32.lt_u
+        ;; code offset: 0x281
+        (local.tee $4
+         ;; code offset: 0x280
+         (i32.and
+          ;; code offset: 0x27c
+          (local.get $3)
+          ;; code offset: 0x27e
+          (i32.const -4)
+         )
+        )
+        ;; code offset: 0x283
+        (i32.const 64)
+       )
+      )
+      ;; code offset: 0x293
+      (br_if $label$8
+       ;; code offset: 0x292
+       (i32.gt_u
+        ;; code offset: 0x289
+        (local.get $2)
+        ;; code offset: 0x290
+        (local.tee $5
+         ;; code offset: 0x28f
+         (i32.add
+          ;; code offset: 0x28b
+          (local.get $4)
+          ;; code offset: 0x28d
+          (i32.const -64)
+         )
+        )
+       )
+      )
+      ;; code offset: 0x295
+      (loop $label$9
+       ;; code offset: 0x29e
+       (i32.store
+        ;; code offset: 0x297
+        (local.get $2)
+        ;; code offset: 0x29b
+        (i32.load
+         ;; code offset: 0x299
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x2a8
+       (i32.store offset=4
+        ;; code offset: 0x2a1
+        (local.get $2)
+        ;; code offset: 0x2a5
+        (i32.load offset=4
+         ;; code offset: 0x2a3
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x2b2
+       (i32.store offset=8
+        ;; code offset: 0x2ab
+        (local.get $2)
+        ;; code offset: 0x2af
+        (i32.load offset=8
+         ;; code offset: 0x2ad
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x2bc
+       (i32.store offset=12
+        ;; code offset: 0x2b5
+        (local.get $2)
+        ;; code offset: 0x2b9
+        (i32.load offset=12
+         ;; code offset: 0x2b7
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x2c6
+       (i32.store offset=16
+        ;; code offset: 0x2bf
+        (local.get $2)
+        ;; code offset: 0x2c3
+        (i32.load offset=16
+         ;; code offset: 0x2c1
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x2d0
+       (i32.store offset=20
+        ;; code offset: 0x2c9
+        (local.get $2)
+        ;; code offset: 0x2cd
+        (i32.load offset=20
+         ;; code offset: 0x2cb
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x2da
+       (i32.store offset=24
+        ;; code offset: 0x2d3
+        (local.get $2)
+        ;; code offset: 0x2d7
+        (i32.load offset=24
+         ;; code offset: 0x2d5
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x2e4
+       (i32.store offset=28
+        ;; code offset: 0x2dd
+        (local.get $2)
+        ;; code offset: 0x2e1
+        (i32.load offset=28
+         ;; code offset: 0x2df
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x2ee
+       (i32.store offset=32
+        ;; code offset: 0x2e7
+        (local.get $2)
+        ;; code offset: 0x2eb
+        (i32.load offset=32
+         ;; code offset: 0x2e9
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x2f8
+       (i32.store offset=36
+        ;; code offset: 0x2f1
+        (local.get $2)
+        ;; code offset: 0x2f5
+        (i32.load offset=36
+         ;; code offset: 0x2f3
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x302
+       (i32.store offset=40
+        ;; code offset: 0x2fb
+        (local.get $2)
+        ;; code offset: 0x2ff
+        (i32.load offset=40
+         ;; code offset: 0x2fd
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x30c
+       (i32.store offset=44
+        ;; code offset: 0x305
+        (local.get $2)
+        ;; code offset: 0x309
+        (i32.load offset=44
+         ;; code offset: 0x307
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x316
+       (i32.store offset=48
+        ;; code offset: 0x30f
+        (local.get $2)
+        ;; code offset: 0x313
+        (i32.load offset=48
+         ;; code offset: 0x311
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x320
+       (i32.store offset=52
+        ;; code offset: 0x319
+        (local.get $2)
+        ;; code offset: 0x31d
+        (i32.load offset=52
+         ;; code offset: 0x31b
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x32a
+       (i32.store offset=56
+        ;; code offset: 0x323
+        (local.get $2)
+        ;; code offset: 0x327
+        (i32.load offset=56
+         ;; code offset: 0x325
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x334
+       (i32.store offset=60
+        ;; code offset: 0x32d
+        (local.get $2)
+        ;; code offset: 0x331
+        (i32.load offset=60
+         ;; code offset: 0x32f
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x33c
+       (local.set $1
+        ;; code offset: 0x33b
+        (i32.sub
+         ;; code offset: 0x337
+         (local.get $1)
+         ;; code offset: 0x339
+         (i32.const -64)
+        )
+       )
+       ;; code offset: 0x348
+       (br_if $label$9
+        ;; code offset: 0x347
+        (i32.le_u
+         ;; code offset: 0x343
+         (local.tee $2
+          ;; code offset: 0x342
+          (i32.sub
+           ;; code offset: 0x33e
+           (local.get $2)
+           ;; code offset: 0x340
+           (i32.const -64)
+          )
+         )
+         ;; code offset: 0x345
+         (local.get $5)
+        )
+       )
+      )
+     )
+     ;; code offset: 0x351
+     (br_if $label$2
+      ;; code offset: 0x350
+      (i32.ge_u
+       ;; code offset: 0x34c
+       (local.get $2)
+       ;; code offset: 0x34e
+       (local.get $4)
+      )
+     )
+     ;; code offset: 0x353
+     (loop $label$10
+      ;; code offset: 0x35c
+      (i32.store
+       ;; code offset: 0x355
+       (local.get $2)
+       ;; code offset: 0x359
+       (i32.load
+        ;; code offset: 0x357
+        (local.get $1)
+       )
+      )
+      ;; code offset: 0x364
+      (local.set $1
+       ;; code offset: 0x363
+       (i32.add
+        ;; code offset: 0x35f
+        (local.get $1)
+        ;; code offset: 0x361
+        (i32.const 4)
+       )
+      )
+      ;; code offset: 0x370
+      (br_if $label$10
+       ;; code offset: 0x36f
+       (i32.lt_u
+        ;; code offset: 0x36b
+        (local.tee $2
+         ;; code offset: 0x36a
+         (i32.add
+          ;; code offset: 0x366
+          (local.get $2)
+          ;; code offset: 0x368
+          (i32.const 4)
+         )
+        )
+        ;; code offset: 0x36d
+        (local.get $4)
+       )
+      )
+     )
+     ;; code offset: 0x373
+     (br $label$2)
+    )
+   )
+   ;; code offset: 0x37b
+   (if
+    ;; code offset: 0x37a
+    (i32.lt_u
+     ;; code offset: 0x376
+     (local.get $3)
+     ;; code offset: 0x378
+     (i32.const 4)
+    )
+    (block
+     ;; code offset: 0x37f
+     (local.set $2
+      ;; code offset: 0x37d
+      (local.get $0)
+     )
+     ;; code offset: 0x381
+     (br $label$2)
+    )
+   )
+   ;; code offset: 0x38e
+   (if
+    ;; code offset: 0x38d
+    (i32.lt_u
+     ;; code offset: 0x389
+     (local.tee $4
+      ;; code offset: 0x388
+      (i32.add
+       ;; code offset: 0x384
+       (local.get $3)
+       ;; code offset: 0x386
+       (i32.const -4)
+      )
+     )
+     ;; code offset: 0x38b
+     (local.get $0)
+    )
+    (block
+     ;; code offset: 0x392
+     (local.set $2
+      ;; code offset: 0x390
+      (local.get $0)
+     )
+     ;; code offset: 0x394
+     (br $label$2)
+    )
+   )
+   ;; code offset: 0x399
+   (local.set $2
+    ;; code offset: 0x397
+    (local.get $0)
+   )
+   ;; code offset: 0x39b
+   (loop $label$13
+    ;; code offset: 0x3a4
+    (i32.store8
+     ;; code offset: 0x39d
+     (local.get $2)
+     ;; code offset: 0x3a1
+     (i32.load8_u
+      ;; code offset: 0x39f
+      (local.get $1)
+     )
+    )
+    ;; code offset: 0x3ae
+    (i32.store8 offset=1
+     ;; code offset: 0x3a7
+     (local.get $2)
+     ;; code offset: 0x3ab
+     (i32.load8_u offset=1
+      ;; code offset: 0x3a9
+      (local.get $1)
+     )
+    )
+    ;; code offset: 0x3b8
+    (i32.store8 offset=2
+     ;; code offset: 0x3b1
+     (local.get $2)
+     ;; code offset: 0x3b5
+     (i32.load8_u offset=2
+      ;; code offset: 0x3b3
+      (local.get $1)
+     )
+    )
+    ;; code offset: 0x3c2
+    (i32.store8 offset=3
+     ;; code offset: 0x3bb
+     (local.get $2)
+     ;; code offset: 0x3bf
+     (i32.load8_u offset=3
+      ;; code offset: 0x3bd
+      (local.get $1)
+     )
+    )
+    ;; code offset: 0x3ca
+    (local.set $1
+     ;; code offset: 0x3c9
+     (i32.add
+      ;; code offset: 0x3c5
+      (local.get $1)
+      ;; code offset: 0x3c7
+      (i32.const 4)
+     )
+    )
+    ;; code offset: 0x3d6
+    (br_if $label$13
+     ;; code offset: 0x3d5
+     (i32.le_u
+      ;; code offset: 0x3d1
+      (local.tee $2
+       ;; code offset: 0x3d0
+       (i32.add
+        ;; code offset: 0x3cc
+        (local.get $2)
+        ;; code offset: 0x3ce
+        (i32.const 4)
+       )
+      )
+      ;; code offset: 0x3d3
+      (local.get $4)
+     )
+    )
+   )
+  )
+  ;; code offset: 0x3df
+  (if
+   ;; code offset: 0x3de
+   (i32.lt_u
+    ;; code offset: 0x3da
+    (local.get $2)
+    ;; code offset: 0x3dc
+    (local.get $3)
+   )
+   ;; code offset: 0x3e1
+   (loop $label$15
+    ;; code offset: 0x3ea
+    (i32.store8
+     ;; code offset: 0x3e3
+     (local.get $2)
+     ;; code offset: 0x3e7
+     (i32.load8_u
+      ;; code offset: 0x3e5
+      (local.get $1)
+     )
+    )
+    ;; code offset: 0x3f2
+    (local.set $1
+     ;; code offset: 0x3f1
+     (i32.add
+      ;; code offset: 0x3ed
+      (local.get $1)
+      ;; code offset: 0x3ef
+      (i32.const 1)
+     )
+    )
+    ;; code offset: 0x3fe
+    (br_if $label$15
+     ;; code offset: 0x3fd
+     (i32.ne
+      ;; code offset: 0x3f9
+      (local.tee $2
+       ;; code offset: 0x3f8
+       (i32.add
+        ;; code offset: 0x3f4
+        (local.get $2)
+        ;; code offset: 0x3f6
+        (i32.const 1)
+       )
+      )
+      ;; code offset: 0x3fb
+      (local.get $3)
+     )
+    )
+   )
+  )
+  ;; code offset: 0x402
+  (local.get $0)
+ )
+ (func $10 (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  ;; code offset: 0x410
+  (block $label$1
+   ;; code offset: 0x43a
+   (if
+    (block $label$2 (result i32)
+     ;; code offset: 0x41c
+     (if
+      ;; code offset: 0x41b
+      (i32.eqz
+       ;; code offset: 0x419
+       (local.tee $3
+        ;; code offset: 0x416
+        (i32.load offset=16
+         ;; code offset: 0x414
+         (local.get $2)
+        )
+       )
+      )
+      (block
+       ;; code offset: 0x422
+       (br_if $label$1
+        ;; code offset: 0x420
+        (call $8
+         ;; code offset: 0x41e
+         (local.get $2)
+        )
+       )
+       ;; code offset: 0x429
+       (local.set $3
+        ;; code offset: 0x426
+        (i32.load offset=16
+         ;; code offset: 0x424
+         (local.get $2)
+        )
+       )
+      )
+     )
+     ;; code offset: 0x438
+     (i32.lt_u
+      ;; code offset: 0x435
+      (i32.sub
+       ;; code offset: 0x42c
+       (local.get $3)
+       ;; code offset: 0x433
+       (local.tee $5
+        ;; code offset: 0x430
+        (i32.load offset=20
+         ;; code offset: 0x42e
+         (local.get $2)
+        )
+       )
+      )
+      ;; code offset: 0x436
+      (local.get $1)
+     )
+    )
+    ;; code offset: 0x44a
+    (return
+     ;; code offset: 0x447
+     (call_indirect (type $i32_i32_i32_=>_i32)
+      ;; code offset: 0x43c
+      (local.get $2)
+      ;; code offset: 0x43e
+      (local.get $0)
+      ;; code offset: 0x440
+      (local.get $1)
+      ;; code offset: 0x444
+      (i32.load offset=36
+       ;; code offset: 0x442
+       (local.get $2)
+      )
+     )
+    )
+   )
+   ;; code offset: 0x44c
+   (block $label$5
+    ;; code offset: 0x456
+    (br_if $label$5
+     ;; code offset: 0x455
+     (i32.lt_s
+      ;; code offset: 0x450
+      (i32.load8_s offset=75
+       ;; code offset: 0x44e
+       (local.get $2)
+      )
+      ;; code offset: 0x453
+      (i32.const 0)
+     )
+    )
+    ;; code offset: 0x45a
+    (local.set $4
+     ;; code offset: 0x458
+     (local.get $1)
+    )
+    ;; code offset: 0x45c
+    (loop $label$6
+     ;; code offset: 0x463
+     (br_if $label$5
+      ;; code offset: 0x462
+      (i32.eqz
+       ;; code offset: 0x460
+       (local.tee $3
+        ;; code offset: 0x45e
+        (local.get $4)
+       )
+      )
+     )
+     ;; code offset: 0x475
+     (br_if $label$6
+      ;; code offset: 0x474
+      (i32.ne
+       ;; code offset: 0x46f
+       (i32.load8_u
+        ;; code offset: 0x46e
+        (i32.add
+         ;; code offset: 0x465
+         (local.get $0)
+         ;; code offset: 0x46c
+         (local.tee $4
+          ;; code offset: 0x46b
+          (i32.add
+           ;; code offset: 0x467
+           (local.get $3)
+           ;; code offset: 0x469
+           (i32.const -1)
+          )
+         )
+        )
+       )
+       ;; code offset: 0x472
+       (i32.const 10)
+      )
+     )
+    )
+    ;; code offset: 0x48b
+    (br_if $label$1
+     ;; code offset: 0x48a
+     (i32.lt_u
+      ;; code offset: 0x486
+      (local.tee $4
+       ;; code offset: 0x483
+       (call_indirect (type $i32_i32_i32_=>_i32)
+        ;; code offset: 0x478
+        (local.get $2)
+        ;; code offset: 0x47a
+        (local.get $0)
+        ;; code offset: 0x47c
+        (local.get $3)
+        ;; code offset: 0x480
+        (i32.load offset=36
+         ;; code offset: 0x47e
+         (local.get $2)
+        )
+       )
+      )
+      ;; code offset: 0x488
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x492
+    (local.set $0
+     ;; code offset: 0x491
+     (i32.add
+      ;; code offset: 0x48d
+      (local.get $0)
+      ;; code offset: 0x48f
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x499
+    (local.set $1
+     ;; code offset: 0x498
+     (i32.sub
+      ;; code offset: 0x494
+      (local.get $1)
+      ;; code offset: 0x496
+      (local.get $3)
+     )
+    )
+    ;; code offset: 0x4a0
+    (local.set $5
+     ;; code offset: 0x49d
+     (i32.load offset=20
+      ;; code offset: 0x49b
+      (local.get $2)
+     )
+    )
+    ;; code offset: 0x4a4
+    (local.set $6
+     ;; code offset: 0x4a2
+     (local.get $3)
+    )
+   )
+   ;; code offset: 0x4af
+   (drop
+    ;; code offset: 0x4ad
+    (call $9
+     ;; code offset: 0x4a7
+     (local.get $5)
+     ;; code offset: 0x4a9
+     (local.get $0)
+     ;; code offset: 0x4ab
+     (local.get $1)
+    )
+   )
+   ;; code offset: 0x4ba
+   (i32.store offset=20
+    ;; code offset: 0x4b0
+    (local.get $2)
+    ;; code offset: 0x4b9
+    (i32.add
+     ;; code offset: 0x4b4
+     (i32.load offset=20
+      ;; code offset: 0x4b2
+      (local.get $2)
+     )
+     ;; code offset: 0x4b7
+     (local.get $1)
+    )
+   )
+   ;; code offset: 0x4c2
+   (local.set $4
+    ;; code offset: 0x4c1
+    (i32.add
+     ;; code offset: 0x4bd
+     (local.get $1)
+     ;; code offset: 0x4bf
+     (local.get $6)
+    )
+   )
+  )
+  ;; code offset: 0x4c5
+  (local.get $4)
+ )
+ (func $11 (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
+  (local $4 i32)
+  (local $5 i32)
+  ;; code offset: 0x4d3
+  (local.set $4
+   ;; code offset: 0x4d2
+   (i32.mul
+    ;; code offset: 0x4ce
+    (local.get $1)
+    ;; code offset: 0x4d0
+    (local.get $2)
+   )
+  )
+  ;; code offset: 0x4d5
+  (block $label$1
+   ;; code offset: 0x4df
+   (if
+    ;; code offset: 0x4de
+    (i32.le_s
+     ;; code offset: 0x4d9
+     (i32.load offset=76
+      ;; code offset: 0x4d7
+      (local.get $3)
+     )
+     ;; code offset: 0x4dc
+     (i32.const -1)
+    )
+    (block
+     ;; code offset: 0x4e9
+     (local.set $0
+      ;; code offset: 0x4e7
+      (call $10
+       ;; code offset: 0x4e1
+       (local.get $0)
+       ;; code offset: 0x4e3
+       (local.get $4)
+       ;; code offset: 0x4e5
+       (local.get $3)
+      )
+     )
+     ;; code offset: 0x4eb
+     (br $label$1)
+    )
+   )
+   ;; code offset: 0x4f2
+   (local.set $5
+    ;; code offset: 0x4f0
+    (call $15
+     ;; code offset: 0x4ee
+     (local.get $3)
+    )
+   )
+   ;; code offset: 0x4fc
+   (local.set $0
+    ;; code offset: 0x4fa
+    (call $10
+     ;; code offset: 0x4f4
+     (local.get $0)
+     ;; code offset: 0x4f6
+     (local.get $4)
+     ;; code offset: 0x4f8
+     (local.get $3)
+    )
+   )
+   ;; code offset: 0x501
+   (br_if $label$1
+    ;; code offset: 0x500
+    (i32.eqz
+     ;; code offset: 0x4fe
+     (local.get $5)
+    )
+   )
+   ;; code offset: 0x505
+   (call $16
+    ;; code offset: 0x503
+    (local.get $3)
+   )
+  )
+  ;; code offset: 0x50d
+  (if
+   ;; code offset: 0x50c
+   (i32.eq
+    ;; code offset: 0x508
+    (local.get $0)
+    ;; code offset: 0x50a
+    (local.get $4)
+   )
+   ;; code offset: 0x516
+   (return
+    ;; code offset: 0x515
+    (select
+     ;; code offset: 0x50f
+     (local.get $2)
+     ;; code offset: 0x511
+     (i32.const 0)
+     ;; code offset: 0x513
+     (local.get $1)
+    )
+   )
+  )
+  ;; code offset: 0x51c
+  (i32.div_u
+   ;; code offset: 0x518
+   (local.get $0)
+   ;; code offset: 0x51a
+   (local.get $1)
+  )
+ )
+ (func $12 (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  ;; code offset: 0x537
+  (select
+   ;; code offset: 0x522
+   (i32.const -1)
+   ;; code offset: 0x524
+   (i32.const 0)
+   ;; code offset: 0x536
+   (i32.ne
+    ;; code offset: 0x532
+    (call $11
+     ;; code offset: 0x526
+     (local.get $0)
+     ;; code offset: 0x528
+     (i32.const 1)
+     ;; code offset: 0x52e
+     (local.tee $2
+      ;; code offset: 0x52c
+      (call $17
+       ;; code offset: 0x52a
+       (local.get $0)
+      )
+     )
+     ;; code offset: 0x530
+     (local.get $1)
+    )
+    ;; code offset: 0x534
+    (local.get $2)
+   )
+  )
+ )
+ (func $13 (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  ;; code offset: 0x549
+  (global.set $global$0
+   ;; code offset: 0x547
+   (local.tee $3
+    ;; code offset: 0x546
+    (i32.sub
+     ;; code offset: 0x542
+     (global.get $global$0)
+     ;; code offset: 0x544
+     (i32.const 16)
+    )
+   )
+  )
+  ;; code offset: 0x54f
+  (i32.store8 offset=15
+   ;; code offset: 0x54b
+   (local.get $3)
+   ;; code offset: 0x54d
+   (local.get $1)
+  )
+  ;; code offset: 0x552
+  (block $label$1
+   ;; code offset: 0x55c
+   (if
+    ;; code offset: 0x55b
+    (i32.eqz
+     ;; code offset: 0x559
+     (local.tee $2
+      ;; code offset: 0x556
+      (i32.load offset=16
+       ;; code offset: 0x554
+       (local.get $0)
+      )
+     )
+    )
+    (block
+     ;; code offset: 0x560
+     (local.set $2
+      ;; code offset: 0x55e
+      (i32.const -1)
+     )
+     ;; code offset: 0x566
+     (br_if $label$1
+      ;; code offset: 0x564
+      (call $8
+       ;; code offset: 0x562
+       (local.get $0)
+      )
+     )
+     ;; code offset: 0x56d
+     (local.set $2
+      ;; code offset: 0x56a
+      (i32.load offset=16
+       ;; code offset: 0x568
+       (local.get $0)
+      )
+     )
+    )
+   )
+   ;; code offset: 0x570
+   (block $label$3
+    ;; code offset: 0x57c
+    (br_if $label$3
+     ;; code offset: 0x57b
+     (i32.ge_u
+      ;; code offset: 0x577
+      (local.tee $4
+       ;; code offset: 0x574
+       (i32.load offset=20
+        ;; code offset: 0x572
+        (local.get $0)
+       )
+      )
+      ;; code offset: 0x579
+      (local.get $2)
+     )
+    )
+    ;; code offset: 0x58c
+    (br_if $label$3
+     ;; code offset: 0x58b
+     (i32.eq
+      ;; code offset: 0x584
+      (local.tee $2
+       ;; code offset: 0x583
+       (i32.and
+        ;; code offset: 0x57e
+        (local.get $1)
+        ;; code offset: 0x580
+        (i32.const 255)
+       )
+      )
+      ;; code offset: 0x588
+      (i32.load8_s offset=75
+       ;; code offset: 0x586
+       (local.get $0)
+      )
+     )
+    )
+    ;; code offset: 0x595
+    (i32.store offset=20
+     ;; code offset: 0x58e
+     (local.get $0)
+     ;; code offset: 0x594
+     (i32.add
+      ;; code offset: 0x590
+      (local.get $4)
+      ;; code offset: 0x592
+      (i32.const 1)
+     )
+    )
+    ;; code offset: 0x59c
+    (i32.store8
+     ;; code offset: 0x598
+     (local.get $4)
+     ;; code offset: 0x59a
+     (local.get $1)
+    )
+    ;; code offset: 0x59f
+    (br $label$1)
+   )
+   ;; code offset: 0x5a4
+   (local.set $2
+    ;; code offset: 0x5a2
+    (i32.const -1)
+   )
+   ;; code offset: 0x5ba
+   (br_if $label$1
+    ;; code offset: 0x5b9
+    (i32.ne
+     ;; code offset: 0x5b4
+     (call_indirect (type $i32_i32_i32_=>_i32)
+      ;; code offset: 0x5a6
+      (local.get $0)
+      ;; code offset: 0x5ac
+      (i32.add
+       ;; code offset: 0x5a8
+       (local.get $3)
+       ;; code offset: 0x5aa
+       (i32.const 15)
+      )
+      ;; code offset: 0x5ad
+      (i32.const 1)
+      ;; code offset: 0x5b1
+      (i32.load offset=36
+       ;; code offset: 0x5af
+       (local.get $0)
+      )
+     )
+     ;; code offset: 0x5b7
+     (i32.const 1)
+    )
+   )
+   ;; code offset: 0x5c1
+   (local.set $2
+    ;; code offset: 0x5be
+    (i32.load8_u offset=15
+     ;; code offset: 0x5bc
+     (local.get $3)
+    )
+   )
+  )
+  ;; code offset: 0x5c9
+  (global.set $global$0
+   ;; code offset: 0x5c8
+   (i32.add
+    ;; code offset: 0x5c4
+    (local.get $3)
+    ;; code offset: 0x5c6
+    (i32.const 16)
+   )
+  )
+  ;; code offset: 0x5cb
+  (local.get $2)
+ )
+ (func $14 (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  ;; code offset: 0x5e2
+  (if
+   ;; code offset: 0x5e1
+   (i32.ge_s
+    ;; code offset: 0x5dc
+    (i32.load offset=76
+     ;; code offset: 0x5da
+     (local.tee $1
+      ;; code offset: 0x5d7
+      (i32.load
+       ;; code offset: 0x5d4
+       (i32.const 1040)
+      )
+     )
+    )
+    ;; code offset: 0x5df
+    (i32.const 0)
+   )
+   ;; code offset: 0x5e8
+   (local.set $2
+    ;; code offset: 0x5e6
+    (call $15
+     ;; code offset: 0x5e4
+     (local.get $1)
+    )
+   )
+  )
+  ;; code offset: 0x636
+  (local.set $0
+   ;; code offset: 0x5eb
+   (block $label$2 (result i32)
+    ;; code offset: 0x5fa
+    (drop
+     ;; code offset: 0x5f8
+     (br_if $label$2
+      ;; code offset: 0x5ed
+      (i32.const -1)
+      ;; code offset: 0x5f7
+      (i32.lt_s
+       ;; code offset: 0x5f3
+       (call $12
+        ;; code offset: 0x5ef
+        (local.get $0)
+        ;; code offset: 0x5f1
+        (local.get $1)
+       )
+       ;; code offset: 0x5f5
+       (i32.const 0)
+      )
+     )
+    )
+    ;; code offset: 0x5fb
+    (block $label$3
+     ;; code offset: 0x605
+     (br_if $label$3
+      ;; code offset: 0x604
+      (i32.eq
+       ;; code offset: 0x5ff
+       (i32.load8_u offset=75
+        ;; code offset: 0x5fd
+        (local.get $1)
+       )
+       ;; code offset: 0x602
+       (i32.const 10)
+      )
+     )
+     ;; code offset: 0x614
+     (br_if $label$3
+      ;; code offset: 0x613
+      (i32.ge_u
+       ;; code offset: 0x60c
+       (local.tee $0
+        ;; code offset: 0x609
+        (i32.load offset=20
+         ;; code offset: 0x607
+         (local.get $1)
+        )
+       )
+       ;; code offset: 0x610
+       (i32.load offset=16
+        ;; code offset: 0x60e
+        (local.get $1)
+       )
+      )
+     )
+     ;; code offset: 0x61d
+     (i32.store offset=20
+      ;; code offset: 0x616
+      (local.get $1)
+      ;; code offset: 0x61c
+      (i32.add
+       ;; code offset: 0x618
+       (local.get $0)
+       ;; code offset: 0x61a
+       (i32.const 1)
+      )
+     )
+     ;; code offset: 0x624
+     (i32.store8
+      ;; code offset: 0x620
+      (local.get $0)
+      ;; code offset: 0x622
+      (i32.const 10)
+     )
+     ;; code offset: 0x629
+     (br $label$2
+      ;; code offset: 0x627
+      (i32.const 0)
+     )
+    )
+    ;; code offset: 0x634
+    (i32.shr_s
+     ;; code offset: 0x630
+     (call $13
+      ;; code offset: 0x62c
+      (local.get $1)
+      ;; code offset: 0x62e
+      (i32.const 10)
+     )
+     ;; code offset: 0x632
+     (i32.const 31)
+    )
+   )
+  )
+  ;; code offset: 0x63a
+  (if
+   ;; code offset: 0x638
+   (local.get $2)
+   ;; code offset: 0x63e
+   (call $16
+    ;; code offset: 0x63c
+    (local.get $1)
+   )
+  )
+  ;; code offset: 0x641
+  (local.get $0)
+ )
+ (func $15 (param $0 i32) (result i32)
+  ;; code offset: 0x646
+  (i32.const 1)
+ )
+ (func $16 (param $0 i32)
+  ;; code offset: 0x64b
+  (nop)
+ )
+ (func $17 (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  ;; code offset: 0x658
+  (local.set $1
+   ;; code offset: 0x656
+   (local.get $0)
+  )
+  ;; code offset: 0x65a
+  (block $label$1
+   (block $label$2
+    ;; code offset: 0x664
+    (br_if $label$2
+     ;; code offset: 0x663
+     (i32.eqz
+      ;; code offset: 0x662
+      (i32.and
+       ;; code offset: 0x65e
+       (local.get $0)
+       ;; code offset: 0x660
+       (i32.const 3)
+      )
+     )
+    )
+    ;; code offset: 0x66c
+    (if
+     ;; code offset: 0x66b
+     (i32.eqz
+      ;; code offset: 0x668
+      (i32.load8_u
+       ;; code offset: 0x666
+       (local.get $0)
+      )
+     )
+     ;; code offset: 0x670
+     (return
+      ;; code offset: 0x66e
+      (i32.const 0)
+     )
+    )
+    ;; code offset: 0x672
+    (loop $label$4
+     ;; code offset: 0x67f
+     (br_if $label$2
+      ;; code offset: 0x67e
+      (i32.eqz
+       ;; code offset: 0x67d
+       (i32.and
+        ;; code offset: 0x679
+        (local.tee $1
+         ;; code offset: 0x678
+         (i32.add
+          ;; code offset: 0x674
+          (local.get $1)
+          ;; code offset: 0x676
+          (i32.const 1)
+         )
+        )
+        ;; code offset: 0x67b
+        (i32.const 3)
+       )
+      )
+     )
+     ;; code offset: 0x686
+     (br_if $label$4
+      ;; code offset: 0x683
+      (i32.load8_u
+       ;; code offset: 0x681
+       (local.get $1)
+      )
+     )
+    )
+    ;; code offset: 0x689
+    (br $label$1)
+   )
+   ;; code offset: 0x68c
+   (loop $label$5
+    ;; code offset: 0x695
+    (local.set $1
+     ;; code offset: 0x694
+     (i32.add
+      ;; code offset: 0x690
+      (local.tee $2
+       ;; code offset: 0x68e
+       (local.get $1)
+      )
+      ;; code offset: 0x692
+      (i32.const 4)
+     )
+    )
+    ;; code offset: 0x6b2
+    (br_if $label$5
+     ;; code offset: 0x6b1
+     (i32.eqz
+      ;; code offset: 0x6b0
+      (i32.and
+       ;; code offset: 0x6a9
+       (i32.and
+        ;; code offset: 0x6a0
+        (i32.xor
+         ;; code offset: 0x69c
+         (local.tee $3
+          ;; code offset: 0x699
+          (i32.load
+           ;; code offset: 0x697
+           (local.get $2)
+          )
+         )
+         ;; code offset: 0x69e
+         (i32.const -1)
+        )
+        ;; code offset: 0x6a8
+        (i32.add
+         ;; code offset: 0x6a1
+         (local.get $3)
+         ;; code offset: 0x6a3
+         (i32.const -16843009)
+        )
+       )
+       ;; code offset: 0x6aa
+       (i32.const -2139062144)
+      )
+     )
+    )
+   )
+   ;; code offset: 0x6bc
+   (if
+    ;; code offset: 0x6bb
+    (i32.eqz
+     ;; code offset: 0x6ba
+     (i32.and
+      ;; code offset: 0x6b5
+      (local.get $3)
+      ;; code offset: 0x6b7
+      (i32.const 255)
+     )
+    )
+    ;; code offset: 0x6c3
+    (return
+     ;; code offset: 0x6c2
+     (i32.sub
+      ;; code offset: 0x6be
+      (local.get $2)
+      ;; code offset: 0x6c0
+      (local.get $0)
+     )
+    )
+   )
+   ;; code offset: 0x6c5
+   (loop $label$7
+    ;; code offset: 0x6cc
+    (local.set $3
+     ;; code offset: 0x6c9
+     (i32.load8_u offset=1
+      ;; code offset: 0x6c7
+      (local.get $2)
+     )
+    )
+    ;; code offset: 0x6d5
+    (local.set $2
+     ;; code offset: 0x6d3
+     (local.tee $1
+      ;; code offset: 0x6d2
+      (i32.add
+       ;; code offset: 0x6ce
+       (local.get $2)
+       ;; code offset: 0x6d0
+       (i32.const 1)
+      )
+     )
+    )
+    ;; code offset: 0x6d9
+    (br_if $label$7
+     ;; code offset: 0x6d7
+     (local.get $3)
+    )
+   )
+  )
+  ;; code offset: 0x6e1
+  (i32.sub
+   ;; code offset: 0x6dd
+   (local.get $1)
+   ;; code offset: 0x6df
+   (local.get $0)
+  )
+ )
+ (func $18 (result i32)
+  ;; code offset: 0x6e5
+  (global.get $global$0)
+ )
+ (func $19 (param $0 i32)
+  ;; code offset: 0x6ec
+  (global.set $global$0
+   ;; code offset: 0x6ea
+   (local.get $0)
+  )
+ )
+ (func $20 (param $0 i32) (result i32)
+  (local $1 i32)
+  ;; code offset: 0x6fd
+  (global.set $global$0
+   ;; code offset: 0x6fb
+   (local.tee $1
+    ;; code offset: 0x6fa
+    (i32.and
+     ;; code offset: 0x6f7
+     (i32.sub
+      ;; code offset: 0x6f3
+      (global.get $global$0)
+      ;; code offset: 0x6f5
+      (local.get $0)
+     )
+     ;; code offset: 0x6f8
+     (i32.const -16)
+    )
+   )
+  )
+  ;; code offset: 0x6ff
+  (local.get $1)
+ )
+ (func $21 (param $0 i32) (param $1 i32) (param $2 i64) (param $3 i32) (result i64)
+  ;; code offset: 0x70c
+  (call_indirect (type $i32_i64_i32_=>_i64)
+   ;; code offset: 0x704
+   (local.get $1)
+   ;; code offset: 0x706
+   (local.get $2)
+   ;; code offset: 0x708
+   (local.get $3)
+   ;; code offset: 0x70a
+   (local.get $0)
+  )
+ )
+ (func $22 (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (result i32)
+  (local $5 i64)
+  ;; code offset: 0x72c
+  (call $fimport$2
+   ;; code offset: 0x72b
+   (i32.wrap_i64
+    ;; code offset: 0x72a
+    (i64.shr_u
+     ;; code offset: 0x726
+     (local.tee $5
+      ;; code offset: 0x724
+      (call $21
+       ;; code offset: 0x714
+       (local.get $0)
+       ;; code offset: 0x716
+       (local.get $1)
+       ;; code offset: 0x721
+       (i64.or
+        ;; code offset: 0x71a
+        (i64.extend_i32_u
+         ;; code offset: 0x718
+         (local.get $2)
+        )
+        ;; code offset: 0x720
+        (i64.shl
+         ;; code offset: 0x71d
+         (i64.extend_i32_u
+          ;; code offset: 0x71b
+          (local.get $3)
+         )
+         ;; code offset: 0x71e
+         (i64.const 32)
+        )
+       )
+       ;; code offset: 0x722
+       (local.get $4)
+      )
+     )
+     ;; code offset: 0x728
+     (i64.const 32)
+    )
+   )
+  )
+  ;; code offset: 0x730
+  (i32.wrap_i64
+   ;; code offset: 0x72e
+   (local.get $5)
+  )
+ )
+ (func $23 (param $0 i32) (result i32)
+  ;; code offset: 0x736
+  (memory.grow
+   ;; code offset: 0x734
+   (local.get $0)
+  )
+ )
+ ;; custom section ".debug_info", size 79
+ ;; custom section ".debug_abbrev", size 64
+ ;; custom section ".debug_line", size 53
+ ;; custom section ".debug_str", size 206
+)
diff --git a/binaryen/test/passes/reverse_dwarf_abbrevs.passes b/binaryen/test/passes/reverse_dwarf_abbrevs.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/reverse_dwarf_abbrevs.passes
@@ -0,0 +1,1 @@
+roundtrip_dwarfdump_g
diff --git a/binaryen/test/passes/reverse_dwarf_abbrevs.wasm b/binaryen/test/passes/reverse_dwarf_abbrevs.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/reverse_dwarf_abbrevs.wasm differ
diff --git a/binaryen/test/passes/roundtrip.txt b/binaryen/test/passes/roundtrip.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/roundtrip.txt
@@ -0,0 +1,11 @@
+(module
+ (type $none_=>_none (func))
+ (export "foo" (func $0))
+ (func $0
+  (unreachable)
+ )
+)
+(module
+ (memory $0 1 1)
+ (table $0 0 funcref)
+)
diff --git a/binaryen/test/passes/roundtrip.wast b/binaryen/test/passes/roundtrip.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/roundtrip.wast
@@ -0,0 +1,16 @@
+(module
+  (func "foo"
+    ;; binaryen skips unreachable code while reading the binary format
+    (unreachable)
+    (nop)
+    (nop)
+    (nop)
+    (nop)
+    (nop)
+  )
+)
+
+(module
+ (memory 1 1)
+ (table 0 funcref)
+)
diff --git a/binaryen/test/passes/rse_all-features.txt b/binaryen/test/passes/rse_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/rse_all-features.txt
@@ -0,0 +1,610 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_f64_=>_none (func (param i32 f64)))
+ (event $e (attr 0) (param i32))
+ (func $basic (param $x i32) (param $y f64)
+  (local $a f32)
+  (local $b i64)
+  (local.set $x
+   (i32.const 0)
+  )
+  (local.set $y
+   (f64.const 0)
+  )
+  (drop
+   (f32.const 0)
+  )
+  (drop
+   (i64.const 0)
+  )
+ )
+ (func $later-param-use (param $x i32)
+  (local.set $x
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $diff-value (param $x i32)
+  (local $a i32)
+  (local.set $x
+   (i32.const 0)
+  )
+  (local.set $x
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (local.set $a
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (local.set $a
+   (i32.const 0)
+  )
+ )
+ (func $tuple-value
+  (local $x (i32 i64))
+  (local.set $x
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+   )
+  )
+  (drop
+   (tuple.make
+    (i32.const 42)
+    (i64.const 42)
+   )
+  )
+ )
+ (func $unreach
+  (local $a i32)
+  (block $x
+   (drop
+    (i32.const 0)
+   )
+   (local.set $a
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 1)
+   )
+   (br $x)
+   (local.set $a
+    (i32.const 1)
+   )
+   (local.set $a
+    (i32.const 2)
+   )
+   (local.set $a
+    (i32.const 2)
+   )
+  )
+ )
+ (func $loop
+  (local $a i32)
+  (local $b i32)
+  (loop $x
+   (local.set $a
+    (i32.const 0)
+   )
+   (local.set $a
+    (i32.const 1)
+   )
+   (br_if $x
+    (i32.const 1)
+   )
+  )
+  (block $y
+   (drop
+    (i32.const 0)
+   )
+   (local.set $b
+    (i32.const 1)
+   )
+   (br $y)
+  )
+  (drop
+   (i32.const 1)
+  )
+ )
+ (func $if
+  (local $x i32)
+  (if
+   (i32.const 0)
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $x
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.const 1)
+  )
+ )
+ (func $if2
+  (local $x i32)
+  (if
+   (local.tee $x
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.const 1)
+  )
+ )
+ (func $if3
+  (local $x i32)
+  (if
+   (local.tee $x
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 1)
+   )
+   (local.set $x
+    (i32.const 2)
+   )
+  )
+  (local.set $x
+   (i32.const 1)
+  )
+ )
+ (func $copy
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.const 1)
+  )
+  (local.set $y
+   (local.get $x)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (local.set $x
+   (i32.const 2)
+  )
+  (if
+   (i32.const 1)
+   (nop)
+   (nop)
+  )
+  (local.set $y
+   (local.get $x)
+  )
+  (drop
+   (i32.const 2)
+  )
+  (if
+   (i32.const 1)
+   (nop)
+   (nop)
+  )
+  (drop
+   (i32.const 2)
+  )
+  (local.set $x
+   (i32.const 3)
+  )
+  (local.set $y
+   (i32.const 3)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $param-unique (param $x i32)
+  (local $a i32)
+  (local.set $a
+   (local.get $x)
+  )
+  (drop
+   (local.get $x)
+  )
+  (local.set $x
+   (i32.eqz
+    (i32.const 9999)
+   )
+  )
+  (local.set $a
+   (local.get $x)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $set-unique
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (i32.eqz
+    (i32.const 123)
+   )
+  )
+  (local.set $y
+   (local.get $x)
+  )
+  (drop
+   (local.get $x)
+  )
+  (local.set $x
+   (i32.eqz
+    (i32.const 456)
+   )
+  )
+  (local.set $y
+   (local.get $x)
+  )
+  (drop
+   (local.get $x)
+  )
+  (local.set $x
+   (i32.eqz
+    (i32.const 789)
+   )
+  )
+  (if
+   (i32.const 1)
+   (nop)
+   (nop)
+  )
+  (local.set $y
+   (local.get $x)
+  )
+  (drop
+   (local.get $x)
+  )
+  (local.set $x
+   (i32.eqz
+    (i32.const 1000)
+   )
+  )
+  (local.set $y
+   (local.get $x)
+  )
+  (if
+   (i32.const 1)
+   (nop)
+   (nop)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $identical_complex (param $x i32)
+  (local $y i32)
+  (local.set $y
+   (local.get $x)
+  )
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (local.get $y)
+  )
+  (drop
+   (local.get $y)
+  )
+ )
+ (func $merge
+  (local $x i32)
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.const 1)
+   )
+   (local.set $x
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.const 1)
+  )
+  (local.set $x
+   (i32.const 2)
+  )
+  (loop $loop
+   (drop
+    (i32.const 2)
+   )
+   (local.set $x
+    (i32.const 3)
+   )
+   (local.set $x
+    (i32.const 2)
+   )
+   (br_if $loop
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.const 2)
+  )
+ )
+ (func $one-arm (param $1 i32) (param $3 i32)
+  (local.set $1
+   (local.get $3)
+  )
+  (if
+   (i32.const 1)
+   (nop)
+   (drop
+    (local.get $1)
+   )
+  )
+ )
+ (func $one-arm2 (param $1 i32) (param $3 i32)
+  (local.set $1
+   (local.get $3)
+  )
+  (if
+   (i32.const 1)
+   (drop
+    (local.get $1)
+   )
+  )
+ )
+ (func $many-merges
+  (local $0 i32)
+  (local $1 i32)
+  (block $block
+   (br_if $block
+    (i32.const 0)
+   )
+   (loop $loop
+    (local.set $1
+     (local.get $0)
+    )
+    (local.set $0
+     (i32.const 99)
+    )
+    (br_if $loop
+     (i32.const 1)
+    )
+   )
+  )
+  (local.set $0
+   (local.get $1)
+  )
+  (if
+   (i32.const 0)
+   (drop
+    (local.get $0)
+   )
+  )
+ )
+ (func $fuzz
+  (local $x i32)
+  (loop $label$4
+   (block $label$5
+    (if
+     (i32.const 1)
+     (block $block
+      (local.set $x
+       (i32.const 203)
+      )
+      (br $label$5)
+     )
+    )
+    (br_if $label$4
+     (i32.const 2)
+    )
+   )
+  )
+  (loop $label$7
+   (if
+    (if (result i32)
+     (i32.const 3)
+     (i32.const 4)
+     (i32.const 5)
+    )
+    (br $label$7)
+   )
+  )
+ )
+ (func $fuzz2
+  (local $var$1 i32)
+  (if
+   (i32.const 0)
+   (if
+    (i32.const 1)
+    (local.set $var$1
+     (i32.const 2)
+    )
+   )
+  )
+  (loop $label$10
+   (block $label$11
+    (if
+     (i32.const 5)
+     (br_if $label$11
+      (i32.const 6)
+     )
+    )
+    (br $label$10)
+   )
+  )
+ )
+ (func $fuzz-nan
+  (local $0 f64)
+  (local $1 f64)
+  (block $block
+   (br_if $block
+    (i32.const 0)
+   )
+   (loop $loop
+    (local.set $1
+     (local.get $0)
+    )
+    (local.set $0
+     (f64.const -nan:0xfffffffffff87)
+    )
+    (br_if $loop
+     (i32.const 1)
+    )
+   )
+  )
+  (local.set $0
+   (local.get $1)
+  )
+  (if
+   (i32.const 0)
+   (drop
+    (local.get $0)
+   )
+  )
+ )
+ (func $try1
+  (local $x i32)
+  (try
+   (do
+    (nop)
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+    (local.set $x
+     (i32.const 1)
+    )
+   )
+  )
+  (local.set $x
+   (i32.const 1)
+  )
+ )
+ (func $try2
+  (local $x i32)
+  (try
+   (do
+    (throw $e
+     (i32.const 0)
+    )
+    (local.set $x
+     (i32.const 1)
+    )
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+   )
+  )
+  (local.set $x
+   (i32.const 1)
+  )
+ )
+ (func $try3
+  (local $x i32)
+  (try
+   (do
+    (throw $e
+     (i32.const 0)
+    )
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+    (local.set $x
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (i32.const 1)
+  )
+ )
+ (func $foo
+  (nop)
+ )
+ (func $try4
+  (local $x i32)
+  (try
+   (do
+    (call $foo)
+    (local.set $x
+     (i32.const 1)
+    )
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+   )
+  )
+  (local.set $x
+   (i32.const 1)
+  )
+ )
+ (func $try5
+  (local $x i32)
+  (try
+   (do
+    (local.set $x
+     (i32.const 1)
+    )
+    (call $foo)
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+   )
+  )
+  (drop
+   (i32.const 1)
+  )
+ )
+ (func $nested-try
+  (local $x i32)
+  (try
+   (do
+    (try
+     (do
+      (throw $e
+       (i32.const 0)
+      )
+     )
+     (catch
+      (rethrow
+       (pop exnref)
+      )
+     )
+    )
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+    (local.set $x
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (i32.const 1)
+  )
+ )
+)
diff --git a/binaryen/test/passes/rse_all-features.wast b/binaryen/test/passes/rse_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/rse_all-features.wast
@@ -0,0 +1,375 @@
+(module
+  (func $basic (param $x i32) (param $y f64)
+    (local $a f32)
+    (local $b i64)
+    (local.set $x (i32.const 0))
+    (local.set $y (f64.const 0))
+    (local.set $a (f32.const 0))
+    (local.set $b (i64.const 0))
+  )
+  (func $later-param-use (param $x i32)
+    (local.set $x (i32.const 0))
+    (local.set $x (i32.const 0))
+  )
+  (func $diff-value (param $x i32)
+    (local $a i32)
+    (local.set $x (i32.const 0))
+    (local.set $x (i32.const 1))
+    (local.set $x (i32.const 1))
+    (local.set $a (i32.const 1))
+    (local.set $a (i32.const 1))
+    (local.set $a (i32.const 0))
+  )
+  (func $tuple-value
+    (local $x (i32 i64))
+    (local.set $x
+      (tuple.make (i32.const 42) (i64.const 42))
+    )
+    (local.set $x
+      (tuple.make (i32.const 42) (i64.const 42))
+    )
+  )
+  (func $unreach
+    (local $a i32)
+    (block $x
+      (local.set $a (i32.const 0))
+      (local.set $a (i32.const 1))
+      (local.set $a (i32.const 1))
+      (br $x)
+      (local.set $a (i32.const 1)) ;; ignore all these
+      (local.set $a (i32.const 2))
+      (local.set $a (i32.const 2))
+    )
+  )
+  (func $loop
+    (local $a i32)
+    (local $b i32)
+    (loop $x
+      (local.set $a (i32.const 0))
+      (local.set $a (i32.const 1))
+      (br_if $x (i32.const 1))
+    )
+    (block $y
+      (local.set $b (i32.const 0))
+      (local.set $b (i32.const 1))
+      (br $y)
+    )
+    (local.set $b (i32.const 1))
+  )
+  (func $if
+    (local $x i32)
+    (if (local.tee $x (i32.const 0))
+      (local.set $x (i32.const 1))
+      (local.set $x (i32.const 1))
+    )
+    (local.set $x (i32.const 1))
+  )
+  (func $if2
+    (local $x i32)
+    (if (local.tee $x (i32.const 1))
+      (local.set $x (i32.const 1))
+      (local.set $x (i32.const 1))
+    )
+    (local.set $x (i32.const 1))
+  )
+  (func $if3
+    (local $x i32)
+    (if (local.tee $x (i32.const 1))
+      (local.set $x (i32.const 1))
+      (local.set $x (i32.const 2))
+    )
+    (local.set $x (i32.const 1))
+  )
+  (func $copy
+    (local $x i32)
+    (local $y i32)
+    (local.set $x (i32.const 1))
+    (local.set $y (local.get $x))
+    (local.set $y (i32.const 1))
+    (local.set $x (i32.const 2))
+    (if (i32.const 1) (nop) (nop)) ;; control flow
+    (local.set $y (local.get $x))
+    (local.set $y (i32.const 2))
+    (if (i32.const 1) (nop) (nop)) ;; control flow
+    (local.set $y (i32.const 2))
+    ;; flip
+    (local.set $x (i32.const 3))
+    (local.set $y (i32.const 3))
+    (local.set $y (local.get $x)) ;; do this last
+  )
+  (func $param-unique
+    (param $x i32)
+    (local $a i32)
+    (local.set $a (local.get $x))
+    (local.set $a (local.get $x))
+    (local.set $x (i32.eqz (i32.const 9999)))
+    (local.set $a (local.get $x))
+    (local.set $a (local.get $x))
+  )
+  (func $set-unique
+    (local $x i32)
+    (local $y i32)
+    (local.set $x (i32.eqz (i32.const 123)))
+    (local.set $y (local.get $x))
+    (local.set $y (local.get $x))
+    (local.set $x (i32.eqz (i32.const 456)))
+    (local.set $y (local.get $x))
+    (local.set $y (local.get $x))
+    (local.set $x (i32.eqz (i32.const 789)))
+    (if (i32.const 1) (nop) (nop)) ;; control flow
+    (local.set $y (local.get $x))
+    (local.set $y (local.get $x))
+    (local.set $x (i32.eqz (i32.const 1000)))
+    (local.set $y (local.get $x))
+    (if (i32.const 1) (nop) (nop)) ;; control flow
+    (local.set $y (local.get $x))
+  )
+  (func $identical_complex (param $x i32)
+    (local $y i32)
+    (local.set $y (local.get $x))
+    (local.set $y (local.get $x))
+    (local.set $y (local.get $x))
+    (local.set $x (local.get $x))
+    (local.set $y (local.get $y))
+    (local.set $x (local.get $y))
+  )
+  (func $merge
+    (local $x i32)
+    (if (i32.const 1)
+      (local.set $x (i32.const 1))
+      (local.set $x (i32.const 1))
+    )
+    (local.set $x (i32.const 1))
+    (local.set $x (i32.const 2))
+    (loop $loop
+      (local.set $x (i32.const 2))
+      (local.set $x (i32.const 3))
+      (local.set $x (i32.const 2))
+      (br_if $loop (i32.const 2))
+    )
+    (local.set $x (i32.const 2))
+  )
+  (func $one-arm
+   (param $1 i32)
+   (param $3 i32)
+   (local.set $1
+    (local.get $3)
+   )
+   (if
+    (i32.const 1)
+    (nop)
+    (local.set $3
+     (local.get $1)
+    )
+   )
+  )
+  (func $one-arm2
+   (param $1 i32)
+   (param $3 i32)
+   (local.set $1
+    (local.get $3)
+   )
+   (if
+    (i32.const 1)
+    (local.set $3
+     (local.get $1)
+    )
+   )
+  )
+  (func $many-merges
+   (local $0 i32)
+   (local $1 i32)
+   (block $block
+    (br_if $block
+     (i32.const 0)
+    )
+    (loop $loop
+     (local.set $1
+      (local.get $0)
+     )
+     (local.set $0
+      (i32.const 99)
+     )
+     (br_if $loop
+      (i32.const 1)
+     )
+    )
+   )
+   (local.set $0 ;; make them equal
+    (local.get $1)
+   )
+   (if
+    (i32.const 0)
+    (local.set $1 ;; we can drop this
+     (local.get $0)
+    )
+   )
+  )
+  (func $fuzz
+   (local $x i32)
+   (loop $label$4
+    (block $label$5
+     (if
+      (i32.const 1)
+      (block
+       (local.set $x
+        (i32.const 203)
+       )
+       (br $label$5)
+      )
+     )
+     (br_if $label$4
+      (i32.const 2)
+     )
+    )
+   )
+   (loop $label$7
+    (if
+     (if (result i32)
+      (i32.const 3)
+      (i32.const 4)
+      (i32.const 5)
+     )
+     (br $label$7)
+    )
+   )
+  )
+  (func $fuzz2
+   (local $var$1 i32)
+   (if
+    (i32.const 0)
+    (if
+     (i32.const 1)
+     (local.set $var$1
+      (i32.const 2)
+     )
+    )
+   )
+   (loop $label$10
+    (block $label$11
+     (if
+      (i32.const 5)
+      (br_if $label$11
+       (i32.const 6)
+      )
+     )
+     (br $label$10)
+    )
+   )
+  )
+  (func $fuzz-nan
+   (local $0 f64)
+   (local $1 f64)
+   (block $block
+    (br_if $block
+     (i32.const 0)
+    )
+    (loop $loop
+     (local.set $1
+      (local.get $0)
+     )
+     (local.set $0
+      (f64.const -nan:0xfffffffffff87)
+     )
+     (br_if $loop
+      (i32.const 1)
+     )
+    )
+   )
+   (local.set $0 ;; make them equal
+    (local.get $1)
+   )
+   (if
+    (i32.const 0)
+    (local.set $1 ;; we can drop this
+     (local.get $0)
+    )
+   )
+  )
+
+  (event $e (attr 0) (param i32))
+  (func $try1
+    (local $x i32)
+    (try
+      (do)
+      (catch
+        (drop (pop exnref))
+        (local.set $x (i32.const 1))
+      )
+    )
+    (local.set $x (i32.const 1)) ;; should NOT be dropped
+  )
+  (func $try2
+    (local $x i32)
+    (try
+      (do
+        (throw $e (i32.const 0))
+        (local.set $x (i32.const 1))
+      )
+      (catch
+        (drop (pop exnref))
+      )
+    )
+    (local.set $x (i32.const 1)) ;; should NOT be dropped
+  )
+  (func $try3
+    (local $x i32)
+    (try
+      (do
+        (throw $e (i32.const 0))
+      )
+      (catch
+        (drop (pop exnref))
+        (local.set $x (i32.const 1))
+      )
+    )
+    (local.set $x (i32.const 1)) ;; should be dropped
+  )
+  (func $foo)
+  (func $try4
+    (local $x i32)
+    (try
+      (do
+        (call $foo)
+        (local.set $x (i32.const 1))
+      )
+      (catch
+        (drop (pop exnref))
+      )
+    )
+    (local.set $x (i32.const 1)) ;; should NOT be dropped
+  )
+  (func $try5
+    (local $x i32)
+    (try
+      (do
+        (local.set $x (i32.const 1))
+        (call $foo)
+      )
+      (catch
+        (drop (pop exnref))
+      )
+    )
+    (local.set $x (i32.const 1)) ;; should be dropped
+  )
+  (func $nested-try
+    (local $x i32)
+    (try
+      (do
+        (try
+          (do
+            (throw $e (i32.const 0))
+          )
+          (catch
+            (rethrow (pop exnref))
+          )
+        )
+      )
+      (catch
+        (drop (pop exnref))
+        (local.set $x (i32.const 1))
+      )
+    )
+    (local.set $x (i32.const 1)) ;; should be dropped
+  )
+)
diff --git a/binaryen/test/passes/safe-heap_disable-simd.txt b/binaryen/test/passes/safe-heap_disable-simd.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/safe-heap_disable-simd.txt
@@ -0,0 +1,7659 @@
+(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 $emscripten_get_sbrk_ptr (result 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
+      (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)
+  )
+ )
+)
+(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))
+ (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))
+ (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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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" "segfault" (func $segfault))
+ (import "env" "alignfault" (func $alignfault))
+ (memory $0 1 1)
+ (export "emscripten_get_sbrk_ptr" (func $foo))
+ (func $foo (result i32)
+  (drop
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (i32.const 1234)
+ )
+ (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 $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $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
+      (call $foo)
+     )
+    )
+   )
+   (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_disable-simd.wast b/binaryen/test/passes/safe-heap_disable-simd.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/safe-heap_disable-simd.wast
@@ -0,0 +1,19 @@
+(module
+  (memory 1 1)
+)
+(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
+  (memory 1 1)
+  (export "emscripten_get_sbrk_ptr" (func $foo))
+  (func $foo (result i32)
+   (drop (i32.load (i32.const 0))) ;; should not be modified!
+   (i32.const 1234)
+  )
+)
diff --git a/binaryen/test/passes/safe-heap_enable-threads_enable-simd.txt b/binaryen/test/passes/safe-heap_enable-threads_enable-simd.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/safe-heap_enable-threads_enable-simd.txt
@@ -0,0 +1,8413 @@
+(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_v128_=>_none (func (param i32 i32 v128)))
+ (type $i32_i32_=>_v128 (func (param i32 i32) (result v128)))
+ (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 (shared 100 100))
+ (func $loads
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_4
+    (i32.const 1)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_A
+    (i32.const 1)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_4
+    (i32.const 2)
+    (i32.const 31)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_2
+    (i32.const 3)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_1
+    (i32.const 4)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_1_1
+    (i32.const 5)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_2_U_2
+    (i32.const 6)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i64_1_1
+    (i32.const 7)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i64_2_U_2
+    (i32.const 8)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i64_4_4
+    (i32.const 9)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i64_8_4
+    (i32.const 10)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i64_8_8
+    (i32.const 11)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_f32_4_4
+    (i32.const 12)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_f64_8_8
+    (i32.const 13)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_v128_16_16
+    (i32.const 14)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $stores
+  (call $SAFE_HEAP_STORE_i32_4_4
+   (i32.const 1)
+   (i32.const 0)
+   (i32.const 100)
+  )
+  (call $SAFE_HEAP_STORE_i32_4_A
+   (i32.const 1)
+   (i32.const 0)
+   (i32.const 100)
+  )
+  (call $SAFE_HEAP_STORE_i32_4_4
+   (i32.const 2)
+   (i32.const 31)
+   (i32.const 200)
+  )
+  (call $SAFE_HEAP_STORE_i32_4_2
+   (i32.const 3)
+   (i32.const 0)
+   (i32.const 300)
+  )
+  (call $SAFE_HEAP_STORE_i32_4_1
+   (i32.const 4)
+   (i32.const 0)
+   (i32.const 400)
+  )
+  (call $SAFE_HEAP_STORE_i32_1_1
+   (i32.const 5)
+   (i32.const 0)
+   (i32.const 500)
+  )
+  (call $SAFE_HEAP_STORE_i32_2_2
+   (i32.const 6)
+   (i32.const 0)
+   (i32.const 600)
+  )
+  (call $SAFE_HEAP_STORE_i64_1_1
+   (i32.const 7)
+   (i32.const 0)
+   (i64.const 700)
+  )
+  (call $SAFE_HEAP_STORE_i64_2_2
+   (i32.const 8)
+   (i32.const 0)
+   (i64.const 800)
+  )
+  (call $SAFE_HEAP_STORE_i64_4_4
+   (i32.const 9)
+   (i32.const 0)
+   (i64.const 900)
+  )
+  (call $SAFE_HEAP_STORE_i64_8_4
+   (i32.const 10)
+   (i32.const 0)
+   (i64.const 1000)
+  )
+  (call $SAFE_HEAP_STORE_i64_8_8
+   (i32.const 11)
+   (i32.const 0)
+   (i64.const 1100)
+  )
+  (call $SAFE_HEAP_STORE_f32_4_4
+   (i32.const 12)
+   (i32.const 0)
+   (f32.const 1200)
+  )
+  (call $SAFE_HEAP_STORE_f64_8_8
+   (i32.const 13)
+   (i32.const 0)
+   (f64.const 1300)
+  )
+  (call $SAFE_HEAP_STORE_v128_16_16
+   (i32.const 14)
+   (i32.const 0)
+   (v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_A (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.shr_s
+   (i32.shl
+    (i32.atomic.load8_u
+     (local.get $2)
+    )
+    (i32.const 24)
+   )
+   (i32.const 24)
+  )
+ )
+ (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_A (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.atomic.load8_u
+   (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_A (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.shr_s
+   (i32.shl
+    (i32.atomic.load16_u
+     (local.get $2)
+    )
+    (i32.const 16)
+   )
+   (i32.const 16)
+  )
+ )
+ (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_A (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.atomic.load16_u
+   (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_A (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.atomic.load
+   (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_A (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.shr_s
+   (i64.shl
+    (i64.atomic.load8_u
+     (local.get $2)
+    )
+    (i64.const 56)
+   )
+   (i64.const 56)
+  )
+ )
+ (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_A (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.atomic.load8_u
+   (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_A (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.shr_s
+   (i64.shl
+    (i64.atomic.load16_u
+     (local.get $2)
+    )
+    (i64.const 48)
+   )
+   (i64.const 48)
+  )
+ )
+ (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_A (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.atomic.load16_u
+   (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_A (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.shr_s
+   (i64.shl
+    (i64.atomic.load32_u
+     (local.get $2)
+    )
+    (i64.const 32)
+   )
+   (i64.const 32)
+  )
+ )
+ (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_A (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.atomic.load32_u
+   (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_A (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.atomic.load
+   (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_LOAD_v128_16_1 (param $0 i32) (param $1 i32) (result v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_2 (param $0 i32) (param $1 i32) (result v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_4 (param $0 i32) (param $1 i32) (result v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_8 (param $0 i32) (param $1 i32) (result v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=8
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_16 (param $0 i32) (param $1 i32) (result v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_1_A (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.atomic.store8
+   (local.get $3)
+   (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_A (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.atomic.store16
+   (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_A (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.atomic.store
+   (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_A (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.atomic.store8
+   (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_A (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.atomic.store16
+   (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_A (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.atomic.store32
+   (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_A (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.atomic.store
+   (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)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_1 (param $0 i32) (param $1 i32) (param $2 v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_2 (param $0 i32) (param $1 i32) (param $2 v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_4 (param $0 i32) (param $1 i32) (param $2 v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=4
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_8 (param $0 i32) (param $1 i32) (param $2 v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_16 (param $0 i32) (param $1 i32) (param $2 v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.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_v128_=>_none (func (param i32 i32 v128)))
+ (type $i32_i32_=>_v128 (func (param i32 i32) (result v128)))
+ (type $i32_i32_f64_=>_none (func (param i32 i32 f64)))
+ (type $i32_i32_=>_f64 (func (param i32 i32) (result f64)))
+ (type $none_=>_none (func))
+ (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 100 100)
+ (func $loads
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_4
+    (i32.const 1)
+    (i32.const 0)
+   )
+  )
+ )
+ (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_LOAD_v128_16_1 (param $0 i32) (param $1 i32) (result v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_2 (param $0 i32) (param $1 i32) (result v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_4 (param $0 i32) (param $1 i32) (result v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_8 (param $0 i32) (param $1 i32) (result v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=8
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_16 (param $0 i32) (param $1 i32) (result v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.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)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_1 (param $0 i32) (param $1 i32) (param $2 v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_2 (param $0 i32) (param $1 i32) (param $2 v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_4 (param $0 i32) (param $1 i32) (param $2 v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=4
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_8 (param $0 i32) (param $1 i32) (param $2 v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_16 (param $0 i32) (param $1 i32) (param $2 v128)
+  (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 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.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_v128_=>_none (func (param i32 i32 v128)))
+ (type $i32_i32_=>_v128 (func (param i32 i32) (result v128)))
+ (type $i32_i32_f64_=>_none (func (param i32 i32 f64)))
+ (type $i32_i32_=>_f64 (func (param i32 i32) (result f64)))
+ (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))
+ (import "env" "segfault" (func $segfault))
+ (import "env" "alignfault" (func $alignfault))
+ (memory $0 (shared 100 100))
+ (func $actions
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_4
+    (i32.const 1)
+    (i32.const 0)
+   )
+  )
+  (call $SAFE_HEAP_STORE_i32_4_4
+   (i32.const 1)
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.shr_s
+   (i32.shl
+    (i32.atomic.load8_u
+     (local.get $2)
+    )
+    (i32.const 24)
+   )
+   (i32.const 24)
+  )
+ )
+ (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load8_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_U_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.atomic.load8_u
+   (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 $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load16_s align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.shr_s
+   (i32.shl
+    (i32.atomic.load16_u
+     (local.get $2)
+    )
+    (i32.const 16)
+   )
+   (i32.const 16)
+  )
+ )
+ (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 $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load16_u align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_U_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.load16_u
+   (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 $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.load
+   (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 $DYNAMICTOP_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_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.shr_s
+   (i64.shl
+    (i64.atomic.load8_u
+     (local.get $2)
+    )
+    (i64.const 56)
+   )
+   (i64.const 56)
+  )
+ )
+ (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load8_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_1_U_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.atomic.load8_u
+   (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 $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load16_s align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.shr_s
+   (i64.shl
+    (i64.atomic.load16_u
+     (local.get $2)
+    )
+    (i64.const 48)
+   )
+   (i64.const 48)
+  )
+ )
+ (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 $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load16_u align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_U_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.load16_u
+   (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 $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.shr_s
+   (i64.shl
+    (i64.atomic.load32_u
+     (local.get $2)
+    )
+    (i64.const 32)
+   )
+   (i64.const 32)
+  )
+ )
+ (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 $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.load32_u
+   (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 $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.load
+   (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 $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (f64.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_1 (param $0 i32) (param $1 i32) (result v128)
+  (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 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_2 (param $0 i32) (param $1 i32) (result v128)
+  (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 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_4 (param $0 i32) (param $1 i32) (result v128)
+  (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 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_8 (param $0 i32) (param $1 i32) (result v128)
+  (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 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=8
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_16 (param $0 i32) (param $1 i32) (result v128)
+  (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 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_1_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.atomic.store8
+   (local.get $3)
+   (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 $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.store16 align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_2_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.store16
+   (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 $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.store
+   (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 $DYNAMICTOP_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_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.atomic.store8
+   (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 $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.store16 align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_2_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.store16
+   (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 $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.store32
+   (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 $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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_A (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 $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.store
+   (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 $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_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
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (f64.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_1 (param $0 i32) (param $1 i32) (param $2 v128)
+  (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 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_2 (param $0 i32) (param $1 i32) (param $2 v128)
+  (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 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_4 (param $0 i32) (param $1 i32) (param $2 v128)
+  (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 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=4
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_8 (param $0 i32) (param $1 i32) (param $2 v128)
+  (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 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_16 (param $0 i32) (param $1 i32) (param $2 v128)
+  (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 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+)
diff --git a/binaryen/test/passes/safe-heap_enable-threads_enable-simd.wast b/binaryen/test/passes/safe-heap_enable-threads_enable-simd.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/safe-heap_enable-threads_enable-simd.wast
@@ -0,0 +1,56 @@
+(module
+ (memory (shared 100 100))
+ (func $loads
+  (drop (i32.load (i32.const 1)))
+  (drop (i32.atomic.load (i32.const 1)))
+  (drop (i32.load offset=31 (i32.const 2)))
+  (drop (i32.load align=2 (i32.const 3)))
+  (drop (i32.load align=1 (i32.const 4)))
+  (drop (i32.load8_s (i32.const 5)))
+  (drop (i32.load16_u (i32.const 6)))
+  (drop (i64.load8_s (i32.const 7)))
+  (drop (i64.load16_u (i32.const 8)))
+  (drop (i64.load32_s (i32.const 9)))
+  (drop (i64.load align=4 (i32.const 10)))
+  (drop (i64.load (i32.const 11)))
+  (drop (f32.load (i32.const 12)))
+  (drop (f64.load (i32.const 13)))
+  (drop (v128.load (i32.const 14)))
+ )
+ (func $stores
+  (i32.store (i32.const 1) (i32.const 100))
+  (i32.atomic.store (i32.const 1) (i32.const 100))
+  (i32.store offset=31 (i32.const 2) (i32.const 200))
+  (i32.store align=2 (i32.const 3) (i32.const 300))
+  (i32.store align=1 (i32.const 4) (i32.const 400))
+  (i32.store8 (i32.const 5) (i32.const 500))
+  (i32.store16 (i32.const 6) (i32.const 600))
+  (i64.store8 (i32.const 7) (i64.const 700))
+  (i64.store16 (i32.const 8) (i64.const 800))
+  (i64.store32 (i32.const 9) (i64.const 900))
+  (i64.store align=4 (i32.const 10) (i64.const 1000))
+  (i64.store (i32.const 11) (i64.const 1100))
+  (f32.store (i32.const 12) (f32.const 1200))
+  (f64.store (i32.const 13) (f64.const 1300))
+  (v128.store (i32.const 14) (v128.const i32x4 1 2 3 4))
+ )
+)
+;; not shared
+(module
+ (memory 100 100)
+ (func $loads
+  (drop (i32.load (i32.const 1)))
+ )
+)
+;; 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))
+ (func $actions
+  (drop (i32.load (i32.const 1)))
+  (i32.store (i32.const 1) (i32.const 100))
+ )
+)
diff --git a/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.passes b/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.passes
@@ -0,0 +1,1 @@
+safe-heap_enable-threads_enable-simd_enable-memory64
diff --git a/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.txt b/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.txt
@@ -0,0 +1,8705 @@
+(module
+ (type $i64_i64_=>_i64 (func (param i64 i64) (result i64)))
+ (type $i64_i64_i64_=>_none (func (param i64 i64 i64)))
+ (type $i64_i64_=>_i32 (func (param i64 i64) (result i32)))
+ (type $i64_i64_i32_=>_none (func (param i64 i64 i32)))
+ (type $i64_i64_v128_=>_none (func (param i64 i64 v128)))
+ (type $i64_i64_=>_v128 (func (param i64 i64) (result v128)))
+ (type $none_=>_none (func))
+ (type $i64_i64_f64_=>_none (func (param i64 i64 f64)))
+ (type $i64_i64_=>_f64 (func (param i64 i64) (result f64)))
+ (type $i64_i64_f32_=>_none (func (param i64 i64 f32)))
+ (type $i64_i64_=>_f32 (func (param i64 i64) (result f32)))
+ (type $none_=>_i64 (func (result i64)))
+ (import "env" "emscripten_get_sbrk_ptr" (func $emscripten_get_sbrk_ptr (result i64)))
+ (import "env" "segfault" (func $segfault))
+ (import "env" "alignfault" (func $alignfault))
+ (memory $0 (shared i64 100 100))
+ (func $loads
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_4
+    (i64.const 1)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_A
+    (i64.const 1)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_4
+    (i64.const 2)
+    (i64.const 31)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_2
+    (i64.const 3)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_1
+    (i64.const 4)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_1_1
+    (i64.const 5)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_2_U_2
+    (i64.const 6)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i64_1_1
+    (i64.const 7)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i64_2_U_2
+    (i64.const 8)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i64_4_4
+    (i64.const 9)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i64_8_4
+    (i64.const 10)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i64_8_8
+    (i64.const 11)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_f32_4_4
+    (i64.const 12)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_f64_8_8
+    (i64.const 13)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_v128_16_16
+    (i64.const 14)
+    (i64.const 0)
+   )
+  )
+ )
+ (func $stores
+  (call $SAFE_HEAP_STORE_i32_4_4
+   (i64.const 1)
+   (i64.const 0)
+   (i32.const 100)
+  )
+  (call $SAFE_HEAP_STORE_i32_4_A
+   (i64.const 1)
+   (i64.const 0)
+   (i32.const 100)
+  )
+  (call $SAFE_HEAP_STORE_i32_4_4
+   (i64.const 2)
+   (i64.const 31)
+   (i32.const 200)
+  )
+  (call $SAFE_HEAP_STORE_i32_4_2
+   (i64.const 3)
+   (i64.const 0)
+   (i32.const 300)
+  )
+  (call $SAFE_HEAP_STORE_i32_4_1
+   (i64.const 4)
+   (i64.const 0)
+   (i32.const 400)
+  )
+  (call $SAFE_HEAP_STORE_i32_1_1
+   (i64.const 5)
+   (i64.const 0)
+   (i32.const 500)
+  )
+  (call $SAFE_HEAP_STORE_i32_2_2
+   (i64.const 6)
+   (i64.const 0)
+   (i32.const 600)
+  )
+  (call $SAFE_HEAP_STORE_i64_1_1
+   (i64.const 7)
+   (i64.const 0)
+   (i64.const 700)
+  )
+  (call $SAFE_HEAP_STORE_i64_2_2
+   (i64.const 8)
+   (i64.const 0)
+   (i64.const 800)
+  )
+  (call $SAFE_HEAP_STORE_i64_4_4
+   (i64.const 9)
+   (i64.const 0)
+   (i64.const 900)
+  )
+  (call $SAFE_HEAP_STORE_i64_8_4
+   (i64.const 10)
+   (i64.const 0)
+   (i64.const 1000)
+  )
+  (call $SAFE_HEAP_STORE_i64_8_8
+   (i64.const 11)
+   (i64.const 0)
+   (i64.const 1100)
+  )
+  (call $SAFE_HEAP_STORE_f32_4_4
+   (i64.const 12)
+   (i64.const 0)
+   (f32.const 1200)
+  )
+  (call $SAFE_HEAP_STORE_f64_8_8
+   (i64.const 13)
+   (i64.const 0)
+   (f64.const 1300)
+  )
+  (call $SAFE_HEAP_STORE_v128_16_16
+   (i64.const 14)
+   (i64.const 0)
+   (v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_A (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.shr_s
+   (i32.shl
+    (i32.atomic.load8_u
+     (local.get $2)
+    )
+    (i32.const 24)
+   )
+   (i32.const 24)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_1 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load8_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_U_A (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.atomic.load8_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_U_1 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load8_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_1 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load16_s align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_A (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.shr_s
+   (i32.shl
+    (i32.atomic.load16_u
+     (local.get $2)
+    )
+    (i32.const 16)
+   )
+   (i32.const 16)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_2 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.load16_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_U_1 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load16_u align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_U_A (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.load16_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_U_2 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.load16_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_4_1 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_4_2 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_4_A (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_4_4 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i32.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_1_A (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.shr_s
+   (i64.shl
+    (i64.atomic.load8_u
+     (local.get $2)
+    )
+    (i64.const 56)
+   )
+   (i64.const 56)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_1_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load8_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_1_U_A (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.atomic.load8_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_1_U_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load8_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load16_s align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_A (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.shr_s
+   (i64.shl
+    (i64.atomic.load16_u
+     (local.get $2)
+    )
+    (i64.const 48)
+   )
+   (i64.const 48)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_2 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load16_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_U_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load16_u align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_U_A (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.load16_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_U_2 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load16_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.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 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load32_s align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_A (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.shr_s
+   (i64.shl
+    (i64.atomic.load32_u
+     (local.get $2)
+    )
+    (i64.const 32)
+   )
+   (i64.const 32)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_4 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.load32_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_U_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.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 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load32_u align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_U_A (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.load32_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_U_4 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.load32_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_2 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_4 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_A (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_8 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (i64.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f32_4_1 (param $0 i64) (param $1 i64) (result f32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (f32.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f32_4_2 (param $0 i64) (param $1 i64) (result f32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (f32.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f32_4_4 (param $0 i64) (param $1 i64) (result f32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (f32.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_1 (param $0 i64) (param $1 i64) (result f64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (f64.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_2 (param $0 i64) (param $1 i64) (result f64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (f64.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_4 (param $0 i64) (param $1 i64) (result f64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (f64.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_8 (param $0 i64) (param $1 i64) (result f64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (f64.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_1 (param $0 i64) (param $1 i64) (result v128)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_2 (param $0 i64) (param $1 i64) (result v128)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_4 (param $0 i64) (param $1 i64) (result v128)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_8 (param $0 i64) (param $1 i64) (result v128)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=8
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_16 (param $0 i64) (param $1 i64) (result v128)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_1_A (param $0 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 1)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.atomic.store8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_1_1 (param $0 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 1)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.store16 align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_2_A (param $0 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.store16
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_2_2 (param $0 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.store align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_4_A (param $0 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_4_4 (param $0 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i32.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_1_A (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 1)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.atomic.store8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_1_1 (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 1)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.store16 align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_2_A (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.store16
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_2_2 (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.store32 align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_4_A (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.store32
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_4_4 (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.store align=4
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_8_A (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_8_8 (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 f32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 f32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 f32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 f64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 f64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 f64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 f64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (f64.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_1 (param $0 i64) (param $1 i64) (param $2 v128)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_2 (param $0 i64) (param $1 i64) (param $2 v128)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_4 (param $0 i64) (param $1 i64) (param $2 v128)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=4
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_8 (param $0 i64) (param $1 i64) (param $2 v128)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_16 (param $0 i64) (param $1 i64) (param $2 v128)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+)
+(module
+ (type $i64_i64_=>_i64 (func (param i64 i64) (result i64)))
+ (type $i64_i64_i64_=>_none (func (param i64 i64 i64)))
+ (type $i64_i64_=>_i32 (func (param i64 i64) (result i32)))
+ (type $i64_i64_i32_=>_none (func (param i64 i64 i32)))
+ (type $i64_i64_v128_=>_none (func (param i64 i64 v128)))
+ (type $i64_i64_=>_v128 (func (param i64 i64) (result v128)))
+ (type $i64_i64_f64_=>_none (func (param i64 i64 f64)))
+ (type $i64_i64_=>_f64 (func (param i64 i64) (result f64)))
+ (type $none_=>_none (func))
+ (type $i64_i64_f32_=>_none (func (param i64 i64 f32)))
+ (type $i64_i64_=>_f32 (func (param i64 i64) (result f32)))
+ (type $none_=>_i64 (func (result i64)))
+ (import "env" "emscripten_get_sbrk_ptr" (func $emscripten_get_sbrk_ptr (result i64)))
+ (import "env" "segfault" (func $segfault))
+ (import "env" "alignfault" (func $alignfault))
+ (memory $0 i64 100 100)
+ (func $loads
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_4
+    (i64.const 1)
+    (i64.const 0)
+   )
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_1 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load8_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_U_1 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load8_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_1 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.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 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.load16_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_U_1 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.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 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.load16_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_4_1 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_4_2 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_4_4 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i32.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_1_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load8_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_1_U_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load8_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.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 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load16_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_U_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.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 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load16_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.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 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.load32_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_U_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.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 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.load32_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_2 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_4 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_8 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (i64.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f32_4_1 (param $0 i64) (param $1 i64) (result f32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (f32.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f32_4_2 (param $0 i64) (param $1 i64) (result f32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (f32.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f32_4_4 (param $0 i64) (param $1 i64) (result f32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (f32.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_1 (param $0 i64) (param $1 i64) (result f64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (f64.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_2 (param $0 i64) (param $1 i64) (result f64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (f64.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_4 (param $0 i64) (param $1 i64) (result f64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (f64.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_8 (param $0 i64) (param $1 i64) (result f64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (f64.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_1 (param $0 i64) (param $1 i64) (result v128)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_2 (param $0 i64) (param $1 i64) (result v128)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_4 (param $0 i64) (param $1 i64) (result v128)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_8 (param $0 i64) (param $1 i64) (result v128)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=8
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_16 (param $0 i64) (param $1 i64) (result v128)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_1_1 (param $0 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 1)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 1)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 f32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 f32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 f32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 f64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.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 i64) (param $1 i64) (param $2 f64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 f64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 f64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (f64.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_1 (param $0 i64) (param $1 i64) (param $2 v128)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_2 (param $0 i64) (param $1 i64) (param $2 v128)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_4 (param $0 i64) (param $1 i64) (param $2 v128)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=4
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_8 (param $0 i64) (param $1 i64) (param $2 v128)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_16 (param $0 i64) (param $1 i64) (param $2 v128)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 16)
+     )
+     (i64.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+)
+(module
+ (type $i64_i64_=>_i64 (func (param i64 i64) (result i64)))
+ (type $i64_i64_i64_=>_none (func (param i64 i64 i64)))
+ (type $i64_i64_=>_i32 (func (param i64 i64) (result i32)))
+ (type $i64_i64_i32_=>_none (func (param i64 i64 i32)))
+ (type $i64_i64_v128_=>_none (func (param i64 i64 v128)))
+ (type $i64_i64_=>_v128 (func (param i64 i64) (result v128)))
+ (type $i64_i64_f64_=>_none (func (param i64 i64 f64)))
+ (type $i64_i64_=>_f64 (func (param i64 i64) (result f64)))
+ (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))
+ (import "env" "segfault" (func $segfault))
+ (import "env" "alignfault" (func $alignfault))
+ (memory $0 (shared i64 100 100))
+ (func $actions
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_4
+    (i64.const 1)
+    (i64.const 0)
+   )
+  )
+  (call $SAFE_HEAP_STORE_i32_4_4
+   (i64.const 1)
+   (i64.const 0)
+   (i32.const 100)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_A (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.shr_s
+   (i32.shl
+    (i32.atomic.load8_u
+     (local.get $2)
+    )
+    (i32.const 24)
+   )
+   (i32.const 24)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_1 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load8_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_U_A (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.atomic.load8_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_U_1 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load8_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_1 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load16_s align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_A (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.shr_s
+   (i32.shl
+    (i32.atomic.load16_u
+     (local.get $2)
+    )
+    (i32.const 16)
+   )
+   (i32.const 16)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_2 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.load16_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_U_1 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load16_u align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_U_A (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.load16_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_U_2 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.load16_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_4_1 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_4_2 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_4_A (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_4_4 (param $0 i64) (param $1 i64) (result i32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i32.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_1_A (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.shr_s
+   (i64.shl
+    (i64.atomic.load8_u
+     (local.get $2)
+    )
+    (i64.const 56)
+   )
+   (i64.const 56)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_1_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load8_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_1_U_A (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.atomic.load8_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_1_U_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 1)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load8_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load16_s align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_A (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.shr_s
+   (i64.shl
+    (i64.atomic.load16_u
+     (local.get $2)
+    )
+    (i64.const 48)
+   )
+   (i64.const 48)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_2 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load16_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_U_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load16_u align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_U_A (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.load16_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_U_2 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load16_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load32_s align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_2 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load32_s align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_A (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.shr_s
+   (i64.shl
+    (i64.atomic.load32_u
+     (local.get $2)
+    )
+    (i64.const 32)
+   )
+   (i64.const 32)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_4 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.load32_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_U_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load32_u align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_U_2 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load32_u align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_U_A (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.load32_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_U_4 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.load32_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_1 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_2 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_4 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_A (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_8 (param $0 i64) (param $1 i64) (result i64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (i64.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f32_4_1 (param $0 i64) (param $1 i64) (result f32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (f32.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f32_4_2 (param $0 i64) (param $1 i64) (result f32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (f32.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f32_4_4 (param $0 i64) (param $1 i64) (result f32)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (f32.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_1 (param $0 i64) (param $1 i64) (result f64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (f64.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_2 (param $0 i64) (param $1 i64) (result f64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (f64.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_4 (param $0 i64) (param $1 i64) (result f64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (f64.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_8 (param $0 i64) (param $1 i64) (result f64)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (f64.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_1 (param $0 i64) (param $1 i64) (result v128)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 16)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_2 (param $0 i64) (param $1 i64) (result v128)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 16)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_4 (param $0 i64) (param $1 i64) (result v128)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 16)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_8 (param $0 i64) (param $1 i64) (result v128)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 16)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=8
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_16 (param $0 i64) (param $1 i64) (result v128)
+  (local $2 i64)
+  (local.set $2
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $2)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $2)
+      (i64.const 16)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $2)
+    )
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_1_A (param $0 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 1)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.atomic.store8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_1_1 (param $0 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 1)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.store8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_2_1 (param $0 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.store16 align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_2_A (param $0 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.store16
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_2_2 (param $0 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_4_2 (param $0 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.store align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_4_A (param $0 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_4_4 (param $0 i64) (param $1 i64) (param $2 i32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i32.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_1_A (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 1)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.atomic.store8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_1_1 (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 1)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.store8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_2_1 (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.store16 align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_2_A (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.store16
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_2_2 (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 2)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.store32 align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_4_2 (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.store32 align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_4_A (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.store32
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_4_4 (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_8_2 (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.store align=4
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_8_A (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_8_8 (param $0 i64) (param $1 i64) (param $2 i64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 f32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (f32.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_f32_4_2 (param $0 i64) (param $1 i64) (param $2 f32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 f32)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 4)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 f64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (f64.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_f64_8_2 (param $0 i64) (param $1 i64) (param $2 f64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 f64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (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 i64) (param $1 i64) (param $2 f64)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 8)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (f64.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_1 (param $0 i64) (param $1 i64) (param $2 v128)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 16)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_2 (param $0 i64) (param $1 i64) (param $2 v128)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 16)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_4 (param $0 i64) (param $1 i64) (param $2 v128)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 16)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=4
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_8 (param $0 i64) (param $1 i64) (param $2 v128)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 16)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_16 (param $0 i64) (param $1 i64) (param $2 v128)
+  (local $3 i64)
+  (local.set $3
+   (i64.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i64.eq
+     (local.get $3)
+     (i64.const 0)
+    )
+    (i64.gt_u
+     (i64.add
+      (local.get $3)
+      (i64.const 16)
+     )
+     (i64.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (i32.wrap_i64
+     (local.get $3)
+    )
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+)
diff --git a/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.wast b/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.wast
@@ -0,0 +1,56 @@
+(module
+ (memory (shared i64 100 100))
+ (func $loads
+  (drop (i32.load (i64.const 1)))
+  (drop (i32.atomic.load (i64.const 1)))
+  (drop (i32.load offset=31 (i64.const 2)))
+  (drop (i32.load align=2 (i64.const 3)))
+  (drop (i32.load align=1 (i64.const 4)))
+  (drop (i32.load8_s (i64.const 5)))
+  (drop (i32.load16_u (i64.const 6)))
+  (drop (i64.load8_s (i64.const 7)))
+  (drop (i64.load16_u (i64.const 8)))
+  (drop (i64.load32_s (i64.const 9)))
+  (drop (i64.load align=4 (i64.const 10)))
+  (drop (i64.load (i64.const 11)))
+  (drop (f32.load (i64.const 12)))
+  (drop (f64.load (i64.const 13)))
+  (drop (v128.load (i64.const 14)))
+ )
+ (func $stores
+  (i32.store (i64.const 1) (i32.const 100))
+  (i32.atomic.store (i64.const 1) (i32.const 100))
+  (i32.store offset=31 (i64.const 2) (i32.const 200))
+  (i32.store align=2 (i64.const 3) (i32.const 300))
+  (i32.store align=1 (i64.const 4) (i32.const 400))
+  (i32.store8 (i64.const 5) (i32.const 500))
+  (i32.store16 (i64.const 6) (i32.const 600))
+  (i64.store8 (i64.const 7) (i64.const 700))
+  (i64.store16 (i64.const 8) (i64.const 800))
+  (i64.store32 (i64.const 9) (i64.const 900))
+  (i64.store align=4 (i64.const 10) (i64.const 1000))
+  (i64.store (i64.const 11) (i64.const 1100))
+  (f32.store (i64.const 12) (f32.const 1200))
+  (f64.store (i64.const 13) (f64.const 1300))
+  (v128.store (i64.const 14) (v128.const i32x4 1 2 3 4))
+ )
+)
+;; not shared
+(module
+ (memory i64 100 100)
+ (func $loads
+  (drop (i32.load (i64.const 1)))
+ )
+)
+;; 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 i64 100 100))
+ (func $actions
+  (drop (i32.load (i64.const 1)))
+  (i32.store (i64.const 1) (i32.const 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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/safe-heap_low-memory-unused_enable-threads_enable-simd.txt
@@ -0,0 +1,8413 @@
+(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_v128_=>_none (func (param i32 i32 v128)))
+ (type $i32_i32_=>_v128 (func (param i32 i32) (result v128)))
+ (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 (shared 100 100))
+ (func $loads
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_4
+    (i32.const 1)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_A
+    (i32.const 1)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_4
+    (i32.const 2)
+    (i32.const 31)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_2
+    (i32.const 3)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_1
+    (i32.const 4)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_1_1
+    (i32.const 5)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_2_U_2
+    (i32.const 6)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i64_1_1
+    (i32.const 7)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i64_2_U_2
+    (i32.const 8)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i64_4_4
+    (i32.const 9)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i64_8_4
+    (i32.const 10)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_i64_8_8
+    (i32.const 11)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_f32_4_4
+    (i32.const 12)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_f64_8_8
+    (i32.const 13)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $SAFE_HEAP_LOAD_v128_16_16
+    (i32.const 14)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $stores
+  (call $SAFE_HEAP_STORE_i32_4_4
+   (i32.const 1)
+   (i32.const 0)
+   (i32.const 100)
+  )
+  (call $SAFE_HEAP_STORE_i32_4_A
+   (i32.const 1)
+   (i32.const 0)
+   (i32.const 100)
+  )
+  (call $SAFE_HEAP_STORE_i32_4_4
+   (i32.const 2)
+   (i32.const 31)
+   (i32.const 200)
+  )
+  (call $SAFE_HEAP_STORE_i32_4_2
+   (i32.const 3)
+   (i32.const 0)
+   (i32.const 300)
+  )
+  (call $SAFE_HEAP_STORE_i32_4_1
+   (i32.const 4)
+   (i32.const 0)
+   (i32.const 400)
+  )
+  (call $SAFE_HEAP_STORE_i32_1_1
+   (i32.const 5)
+   (i32.const 0)
+   (i32.const 500)
+  )
+  (call $SAFE_HEAP_STORE_i32_2_2
+   (i32.const 6)
+   (i32.const 0)
+   (i32.const 600)
+  )
+  (call $SAFE_HEAP_STORE_i64_1_1
+   (i32.const 7)
+   (i32.const 0)
+   (i64.const 700)
+  )
+  (call $SAFE_HEAP_STORE_i64_2_2
+   (i32.const 8)
+   (i32.const 0)
+   (i64.const 800)
+  )
+  (call $SAFE_HEAP_STORE_i64_4_4
+   (i32.const 9)
+   (i32.const 0)
+   (i64.const 900)
+  )
+  (call $SAFE_HEAP_STORE_i64_8_4
+   (i32.const 10)
+   (i32.const 0)
+   (i64.const 1000)
+  )
+  (call $SAFE_HEAP_STORE_i64_8_8
+   (i32.const 11)
+   (i32.const 0)
+   (i64.const 1100)
+  )
+  (call $SAFE_HEAP_STORE_f32_4_4
+   (i32.const 12)
+   (i32.const 0)
+   (f32.const 1200)
+  )
+  (call $SAFE_HEAP_STORE_f64_8_8
+   (i32.const 13)
+   (i32.const 0)
+   (f64.const 1300)
+  )
+  (call $SAFE_HEAP_STORE_v128_16_16
+   (i32.const 14)
+   (i32.const 0)
+   (v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.shr_s
+   (i32.shl
+    (i32.atomic.load8_u
+     (local.get $2)
+    )
+    (i32.const 24)
+   )
+   (i32.const 24)
+  )
+ )
+ (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.atomic.load8_u
+   (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.shr_s
+   (i32.shl
+    (i32.atomic.load16_u
+     (local.get $2)
+    )
+    (i32.const 16)
+   )
+   (i32.const 16)
+  )
+ )
+ (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.atomic.load16_u
+   (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.atomic.load
+   (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.shr_s
+   (i64.shl
+    (i64.atomic.load8_u
+     (local.get $2)
+    )
+    (i64.const 56)
+   )
+   (i64.const 56)
+  )
+ )
+ (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.atomic.load8_u
+   (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.shr_s
+   (i64.shl
+    (i64.atomic.load16_u
+     (local.get $2)
+    )
+    (i64.const 48)
+   )
+   (i64.const 48)
+  )
+ )
+ (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.atomic.load16_u
+   (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.shr_s
+   (i64.shl
+    (i64.atomic.load32_u
+     (local.get $2)
+    )
+    (i64.const 32)
+   )
+   (i64.const 32)
+  )
+ )
+ (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.atomic.load32_u
+   (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.atomic.load
+   (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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_LOAD_v128_16_1 (param $0 i32) (param $1 i32) (result v128)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_2 (param $0 i32) (param $1 i32) (result v128)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_4 (param $0 i32) (param $1 i32) (result v128)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_8 (param $0 i32) (param $1 i32) (result v128)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=8
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_16 (param $0 i32) (param $1 i32) (result v128)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_1_A (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 1)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.atomic.store8
+   (local.get $3)
+   (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.atomic.store16
+   (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.atomic.store
+   (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 1)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.atomic.store8
+   (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.atomic.store16
+   (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.atomic.store32
+   (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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_A (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.atomic.store
+   (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_1 (param $0 i32) (param $1 i32) (param $2 v128)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_2 (param $0 i32) (param $1 i32) (param $2 v128)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_4 (param $0 i32) (param $1 i32) (param $2 v128)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=4
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_8 (param $0 i32) (param $1 i32) (param $2 v128)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_16 (param $0 i32) (param $1 i32) (param $2 v128)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.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_v128_=>_none (func (param i32 i32 v128)))
+ (type $i32_i32_=>_v128 (func (param i32 i32) (result v128)))
+ (type $i32_i32_f64_=>_none (func (param i32 i32 f64)))
+ (type $i32_i32_=>_f64 (func (param i32 i32) (result f64)))
+ (type $none_=>_none (func))
+ (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 100 100)
+ (func $loads
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_4
+    (i32.const 1)
+    (i32.const 0)
+   )
+  )
+ )
+ (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (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_LOAD_v128_16_1 (param $0 i32) (param $1 i32) (result v128)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_2 (param $0 i32) (param $1 i32) (result v128)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_4 (param $0 i32) (param $1 i32) (result v128)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_8 (param $0 i32) (param $1 i32) (result v128)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=8
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_16 (param $0 i32) (param $1 i32) (result v128)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (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)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_1 (param $0 i32) (param $1 i32) (param $2 v128)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_2 (param $0 i32) (param $1 i32) (param $2 v128)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_4 (param $0 i32) (param $1 i32) (param $2 v128)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=4
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_8 (param $0 i32) (param $1 i32) (param $2 v128)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_16 (param $0 i32) (param $1 i32) (param $2 v128)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 16)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.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_v128_=>_none (func (param i32 i32 v128)))
+ (type $i32_i32_=>_v128 (func (param i32 i32) (result v128)))
+ (type $i32_i32_f64_=>_none (func (param i32 i32 f64)))
+ (type $i32_i32_=>_f64 (func (param i32 i32) (result f64)))
+ (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))
+ (import "env" "segfault" (func $segfault))
+ (import "env" "alignfault" (func $alignfault))
+ (memory $0 (shared 100 100))
+ (func $actions
+  (drop
+   (call $SAFE_HEAP_LOAD_i32_4_4
+    (i32.const 1)
+    (i32.const 0)
+   )
+  )
+  (call $SAFE_HEAP_STORE_i32_4_4
+   (i32.const 1)
+   (i32.const 0)
+   (i32.const 100)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.shr_s
+   (i32.shl
+    (i32.atomic.load8_u
+     (local.get $2)
+    )
+    (i32.const 24)
+   )
+   (i32.const 24)
+  )
+ )
+ (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load8_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_U_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.atomic.load8_u
+   (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load16_s align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.shr_s
+   (i32.shl
+    (i32.atomic.load16_u
+     (local.get $2)
+    )
+    (i32.const 16)
+   )
+   (i32.const 16)
+  )
+ )
+ (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load16_u align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_U_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.load16_u
+   (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.load
+   (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.shr_s
+   (i64.shl
+    (i64.atomic.load8_u
+     (local.get $2)
+    )
+    (i64.const 56)
+   )
+   (i64.const 56)
+  )
+ )
+ (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load8_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_1_U_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.atomic.load8_u
+   (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load16_s align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.shr_s
+   (i64.shl
+    (i64.atomic.load16_u
+     (local.get $2)
+    )
+    (i64.const 48)
+   )
+   (i64.const 48)
+  )
+ )
+ (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load16_u align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_U_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.load16_u
+   (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.shr_s
+   (i64.shl
+    (i64.atomic.load32_u
+     (local.get $2)
+    )
+    (i64.const 32)
+   )
+   (i64.const 32)
+  )
+ )
+ (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.load32_u
+   (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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_A (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.load
+   (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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (f64.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_1 (param $0 i32) (param $1 i32) (result v128)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_2 (param $0 i32) (param $1 i32) (result v128)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_4 (param $0 i32) (param $1 i32) (result v128)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_8 (param $0 i32) (param $1 i32) (result v128)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.load align=8
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_v128_16_16 (param $0 i32) (param $1 i32) (result v128)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $2)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_1_A (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 1)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.atomic.store8
+   (local.get $3)
+   (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 1)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.store16 align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_2_A (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.store16
+   (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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_A (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i32.atomic.store
+   (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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_A (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 1)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.atomic.store8
+   (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 1)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.store16 align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_2_A (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.store16
+   (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 2)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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_A (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.store32
+   (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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_A (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (i64.atomic.store
+   (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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_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.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (f64.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_1 (param $0 i32) (param $1 i32) (param $2 v128)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (v128.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_2 (param $0 i32) (param $1 i32) (param $2 v128)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_4 (param $0 i32) (param $1 i32) (param $2 v128)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=4
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_8 (param $0 i32) (param $1 i32) (param $2 v128)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (v128.store align=8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_v128_16_16 (param $0 i32) (param $1 i32) (param $2 v128)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.lt_u
+     (local.get $3)
+     (i32.const 1024)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 16)
+     )
+     (i32.load
+      (global.get $DYNAMICTOP_PTR)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 15)
+   )
+   (call $alignfault)
+  )
+  (v128.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+)
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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/safe-heap_low-memory-unused_enable-threads_enable-simd.wast
@@ -0,0 +1,56 @@
+(module
+ (memory (shared 100 100))
+ (func $loads
+  (drop (i32.load (i32.const 1)))
+  (drop (i32.atomic.load (i32.const 1)))
+  (drop (i32.load offset=31 (i32.const 2)))
+  (drop (i32.load align=2 (i32.const 3)))
+  (drop (i32.load align=1 (i32.const 4)))
+  (drop (i32.load8_s (i32.const 5)))
+  (drop (i32.load16_u (i32.const 6)))
+  (drop (i64.load8_s (i32.const 7)))
+  (drop (i64.load16_u (i32.const 8)))
+  (drop (i64.load32_s (i32.const 9)))
+  (drop (i64.load align=4 (i32.const 10)))
+  (drop (i64.load (i32.const 11)))
+  (drop (f32.load (i32.const 12)))
+  (drop (f64.load (i32.const 13)))
+  (drop (v128.load (i32.const 14)))
+ )
+ (func $stores
+  (i32.store (i32.const 1) (i32.const 100))
+  (i32.atomic.store (i32.const 1) (i32.const 100))
+  (i32.store offset=31 (i32.const 2) (i32.const 200))
+  (i32.store align=2 (i32.const 3) (i32.const 300))
+  (i32.store align=1 (i32.const 4) (i32.const 400))
+  (i32.store8 (i32.const 5) (i32.const 500))
+  (i32.store16 (i32.const 6) (i32.const 600))
+  (i64.store8 (i32.const 7) (i64.const 700))
+  (i64.store16 (i32.const 8) (i64.const 800))
+  (i64.store32 (i32.const 9) (i64.const 900))
+  (i64.store align=4 (i32.const 10) (i64.const 1000))
+  (i64.store (i32.const 11) (i64.const 1100))
+  (f32.store (i32.const 12) (f32.const 1200))
+  (f64.store (i32.const 13) (f64.const 1300))
+  (v128.store (i32.const 14) (v128.const i32x4 1 2 3 4))
+ )
+)
+;; not shared
+(module
+ (memory 100 100)
+ (func $loads
+  (drop (i32.load (i32.const 1)))
+ )
+)
+;; 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))
+ (func $actions
+  (drop (i32.load (i32.const 1)))
+  (i32.store (i32.const 1) (i32.const 100))
+ )
+)
diff --git a/binaryen/test/passes/simplify-globals-optimizing_enable-mutable-globals.txt b/binaryen/test/passes/simplify-globals-optimizing_enable-mutable-globals.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-globals-optimizing_enable-mutable-globals.txt
@@ -0,0 +1,173 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "global-1" (global $g1 i32))
+ (global $g2 i32 (global.get $g1))
+ (func $foo
+  (drop
+   (global.get $g1)
+  )
+  (drop
+   (global.get $g1)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "global-1" (global $g1 i32))
+ (global $g2 i32 (global.get $g1))
+ (global $g3 i32 (global.get $g2))
+ (global $g4 i32 (global.get $g3))
+ (func $foo
+  (drop
+   (global.get $g1)
+  )
+  (drop
+   (global.get $g1)
+  )
+  (drop
+   (global.get $g1)
+  )
+  (drop
+   (global.get $g1)
+  )
+ )
+)
+(module
+ (import "env" "global-1" (global $g1 (mut i32)))
+ (global $g2 i32 (global.get $g1))
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "global-1" (global $g1 i32))
+ (global $g2 i32 (global.get $g1))
+ (func $foo
+  (unreachable)
+ )
+)
+(module
+ (import "env" "global-1" (global $g1 (mut i32)))
+ (global $g2 (mut i32) (global.get $g1))
+ (export "global-2" (global $g2))
+)
+(module
+ (type $none_=>_none (func))
+ (global $g1 i32 (i32.const 1))
+ (global $g2 i32 (i32.const 1))
+ (global $g3 f64 (f64.const -3.4))
+ (global $g4 f64 (f64.const -2.8))
+ (global $g5 i32 (i32.const 2))
+ (global $g6 i32 (i32.const 2))
+ (global $g7 i32 (i32.const 3))
+ (global $g8 i32 (i32.const 3))
+ (global $g9 i32 (i32.const 4))
+ (global $ga (mut i32) (i32.const 4))
+ (global $gb (mut i32) (i32.const 5))
+ (global $gc i32 (i32.const 5))
+ (func $foo
+  (global.set $ga
+   (i32.const 6)
+  )
+  (global.set $gb
+   (i32.const 7)
+  )
+ )
+)
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (global $g1 (mut i32) (i32.const 1))
+ (global $g2 (mut i32) (i32.const 1))
+ (func $f (param $0 i32) (result i32)
+  (global.set $g1
+   (i32.const 100)
+  )
+  (global.set $g2
+   (local.get $0)
+  )
+  (if
+   (local.get $0)
+   (return
+    (i32.const 0)
+   )
+  )
+  (if
+   (local.tee $0
+    (i32.add
+     (global.get $g1)
+     (global.get $g2)
+    )
+   )
+   (return
+    (i32.const 1)
+   )
+  )
+  (global.set $g1
+   (i32.const 200)
+  )
+  (global.set $g2
+   (local.get $0)
+  )
+  (i32.add
+   (global.get $g2)
+   (i32.const 200)
+  )
+ )
+)
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (global $g1 (mut i32) (i32.const 1))
+ (global $g2 (mut i32) (i32.const 1))
+ (func $f (param $0 i32) (result i32)
+  (global.set $g1
+   (i32.const 100)
+  )
+  (global.set $g2
+   (local.get $0)
+  )
+  (i32.add
+   (global.get $g2)
+   (i32.const 200)
+  )
+ )
+)
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (global $g1 (mut i32) (i32.const 1))
+ (global $g2 i32 (i32.const 1))
+ (func $no (param $x i32) (result i32)
+  (global.set $g1
+   (i32.const 100)
+  )
+  (drop
+   (call $no
+    (i32.const 200)
+   )
+  )
+  (global.get $g1)
+ )
+ (func $no2 (param $x i32) (result i32)
+  (global.set $g1
+   (i32.const 100)
+  )
+  (global.set $g1
+   (local.get $x)
+  )
+  (global.get $g1)
+ )
+ (func $yes (param $0 i32) (result i32)
+  (global.set $g1
+   (i32.const 100)
+  )
+  (i32.const 100)
+ )
+)
+(module
+ (type $none_=>_f64 (func (result f64)))
+ (global $global$0 i32 (i32.const 0))
+ (global $global$1 i32 (i32.const 0))
+ (export "func_9" (func $0))
+ (func $0 (result f64)
+  (drop
+   (unreachable)
+  )
+ )
+)
diff --git a/binaryen/test/passes/simplify-globals-optimizing_enable-mutable-globals.wast b/binaryen/test/passes/simplify-globals-optimizing_enable-mutable-globals.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-globals-optimizing_enable-mutable-globals.wast
@@ -0,0 +1,148 @@
+(module
+  (import "env" "global-1" (global $g1 i32))
+  (global $g2 (mut i32) (global.get $g1))
+  (func $foo
+   (drop (global.get $g1))
+   (drop (global.get $g2))
+  )
+)
+(module
+  (import "env" "global-1" (global $g1 i32))
+  (global $g2 (mut i32) (global.get $g1))
+  (global $g3 (mut i32) (global.get $g2))
+  (global $g4 (mut i32) (global.get $g3))
+  (func $foo
+   (drop (global.get $g1))
+   (drop (global.get $g2))
+   (drop (global.get $g3))
+   (drop (global.get $g4))
+  )
+)
+(module
+  (import "env" "global-1" (global $g1 (mut i32)))
+  (global $g2 (mut i32) (global.get $g1))
+)
+(module
+  (import "env" "global-1" (global $g1 i32))
+  (global $g2 (mut i32) (global.get $g1))
+  (func $foo
+   (global.set $g2 (unreachable))
+  )
+)
+(module
+  (import "env" "global-1" (global $g1 (mut i32)))
+  (global $g2 (mut i32) (global.get $g1))
+  (export "global-2" (global $g2))
+)
+(module
+  (global $g1 i32 (i32.const 1))
+  (global $g2 i32 (global.get $g1))
+  (global $g3 f64 (f64.const -3.4))
+  (global $g4 (mut f64) (f64.const -2.8))
+  (global $g5 i32 (i32.const 2))
+  (global $g6 (mut i32) (global.get $g5))
+  (global $g7 (mut i32) (i32.const 3))
+  (global $g8 i32 (global.get $g7))
+  (global $g9 i32 (i32.const 4))
+  (global $ga (mut i32) (global.get $g9))
+  (global $gb (mut i32) (i32.const 5))
+  (global $gc i32 (global.get $gb))
+  (func $foo
+   (drop (global.get $g1))
+   (drop (global.get $g2))
+   (drop (global.get $g3))
+   (drop (global.get $g4))
+   (drop (global.get $g5))
+   (drop (global.get $g6))
+   (drop (global.get $g7))
+   (drop (global.get $g8))
+   (drop (global.get $g9))
+   (drop (global.get $ga))
+   (drop (global.get $gb))
+   (drop (global.get $gc))
+   (global.set $ga (i32.const 6))
+   (global.set $gb (i32.const 7))
+  )
+)
+(module
+  (global $g1 (mut i32) (i32.const 1))
+  (global $g2 (mut i32) (i32.const 1))
+  (func $f (param $x i32) (result i32)
+    (global.set $g1 (i32.const 100))
+    (global.set $g2 (local.get $x))
+    (if (local.get $x) (return (i32.const 0)))
+    (local.set $x
+      (i32.add
+        (global.get $g1)
+        (global.get $g2)
+      )
+    )
+    (if (local.get $x) (return (i32.const 1)))
+    (global.set $g1 (i32.const 200))
+    (global.set $g2 (local.get $x))
+    (local.set $x
+      (i32.add
+        (global.get $g1)
+        (global.get $g2)
+      )
+    )
+    (local.get $x)
+  )
+)
+(module
+  (global $g1 (mut i32) (i32.const 1))
+  (global $g2 (mut i32) (i32.const 1))
+  (func $f (param $x i32) (result i32)
+    (global.set $g1 (i32.const 100))
+    (global.set $g2 (local.get $x))
+    (local.set $x
+      (i32.add
+        (i32.add
+          (global.get $g1)
+          (global.get $g1)
+        )
+        (global.get $g2)
+      )
+    )
+    (local.get $x)
+  )
+)
+(module
+  (global $g1 (mut i32) (i32.const 1))
+  (global $g2 (mut i32) (i32.const 1))
+  (func $no (param $x i32) (result i32)
+    (global.set $g1 (i32.const 100))
+    (drop (call $no (i32.const 200))) ;; invalidate
+    (global.get $g1)
+  )
+  (func $no2 (param $x i32) (result i32)
+    (global.set $g1 (i32.const 100))
+    (global.set $g1 (local.get $x)) ;; invalidate
+    (global.get $g1)
+  )
+  (func $yes (param $x i32) (result i32)
+    (global.set $g1 (i32.const 100))
+    (global.set $g2 (local.get $x)) ;; almost invalidate
+    (global.get $g1)
+  )
+)
+;; don't remove a value with a side effect
+(module
+ (global $global$0 (mut i32) (i32.const 0))
+ (global $global$1 (mut i32) (i32.const 0))
+ (export "func_9" (func $0))
+ (func $0 (result f64)
+  (global.set $global$0
+   (block $label$1 (result i32)
+    (if
+     (i32.eqz
+      (global.get $global$1)
+     )
+     (unreachable)
+    )
+    (i32.const 2)
+   )
+  )
+  (f64.const 1)
+ )
+)
diff --git a/binaryen/test/passes/simplify-globals_all-features.txt b/binaryen/test/passes/simplify-globals_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-globals_all-features.txt
@@ -0,0 +1,241 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "global-1" (global $g1 i32))
+ (global $g2 i32 (global.get $g1))
+ (func $foo
+  (drop
+   (global.get $g1)
+  )
+  (drop
+   (global.get $g1)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "global-1" (global $g1 i32))
+ (global $g2 i32 (global.get $g1))
+ (global $g3 i32 (global.get $g2))
+ (global $g4 i32 (global.get $g3))
+ (func $foo
+  (drop
+   (global.get $g1)
+  )
+  (drop
+   (global.get $g1)
+  )
+  (drop
+   (global.get $g1)
+  )
+  (drop
+   (global.get $g1)
+  )
+ )
+)
+(module
+ (import "env" "global-1" (global $g1 (mut i32)))
+ (global $g2 i32 (global.get $g1))
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "global-1" (global $g1 i32))
+ (global $g2 i32 (global.get $g1))
+ (func $foo
+  (drop
+   (unreachable)
+  )
+ )
+)
+(module
+ (import "env" "global-1" (global $g1 (mut i32)))
+ (global $g2 (mut i32) (global.get $g1))
+ (export "global-2" (global $g2))
+)
+(module
+ (type $none_=>_none (func))
+ (global $g1 i32 (i32.const 1))
+ (global $g2 i32 (i32.const 1))
+ (global $g3 f64 (f64.const -3.4))
+ (global $g4 f64 (f64.const -2.8))
+ (global $g5 i32 (i32.const 2))
+ (global $g6 i32 (i32.const 2))
+ (global $g7 i32 (i32.const 3))
+ (global $g8 i32 (i32.const 3))
+ (global $g9 i32 (i32.const 4))
+ (global $ga (mut i32) (i32.const 4))
+ (global $gb (mut i32) (i32.const 5))
+ (global $gc i32 (i32.const 5))
+ (func $foo
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (f64.const -3.4)
+  )
+  (drop
+   (f64.const -2.8)
+  )
+  (drop
+   (i32.const 2)
+  )
+  (drop
+   (i32.const 2)
+  )
+  (drop
+   (i32.const 3)
+  )
+  (drop
+   (i32.const 3)
+  )
+  (drop
+   (i32.const 4)
+  )
+  (drop
+   (global.get $ga)
+  )
+  (drop
+   (global.get $gb)
+  )
+  (drop
+   (i32.const 5)
+  )
+  (global.set $ga
+   (i32.const 6)
+  )
+  (global.set $gb
+   (i32.const 7)
+  )
+ )
+)
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (global $g1 (mut i32) (i32.const 1))
+ (global $g2 (mut i32) (i32.const 1))
+ (func $f (param $x i32) (result i32)
+  (global.set $g1
+   (i32.const 100)
+  )
+  (global.set $g2
+   (local.get $x)
+  )
+  (if
+   (local.get $x)
+   (return
+    (i32.const 0)
+   )
+  )
+  (local.set $x
+   (i32.add
+    (global.get $g1)
+    (global.get $g2)
+   )
+  )
+  (if
+   (local.get $x)
+   (return
+    (i32.const 1)
+   )
+  )
+  (global.set $g1
+   (i32.const 200)
+  )
+  (global.set $g2
+   (local.get $x)
+  )
+  (local.set $x
+   (i32.add
+    (i32.const 200)
+    (global.get $g2)
+   )
+  )
+  (local.get $x)
+ )
+)
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (global $g1 (mut i32) (i32.const 1))
+ (global $g2 (mut i32) (i32.const 1))
+ (func $f (param $x i32) (result i32)
+  (global.set $g1
+   (i32.const 100)
+  )
+  (global.set $g2
+   (local.get $x)
+  )
+  (local.set $x
+   (i32.add
+    (i32.add
+     (i32.const 100)
+     (i32.const 100)
+    )
+    (global.get $g2)
+   )
+  )
+  (local.get $x)
+ )
+)
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (global $g1 (mut i32) (i32.const 1))
+ (global $g2 i32 (i32.const 1))
+ (func $no (param $x i32) (result i32)
+  (global.set $g1
+   (i32.const 100)
+  )
+  (drop
+   (call $no
+    (i32.const 200)
+   )
+  )
+  (global.get $g1)
+ )
+ (func $no2 (param $x i32) (result i32)
+  (global.set $g1
+   (i32.const 100)
+  )
+  (global.set $g1
+   (local.get $x)
+  )
+  (global.get $g1)
+ )
+ (func $yes (param $x i32) (result i32)
+  (global.set $g1
+   (i32.const 100)
+  )
+  (drop
+   (local.get $x)
+  )
+  (i32.const 100)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "global-1" (global $g1 externref))
+ (global $g2 externref (global.get $g1))
+ (global $g3 externref (ref.null extern))
+ (func $test1
+  (drop
+   (global.get $g1)
+  )
+  (drop
+   (global.get $g1)
+  )
+ )
+ (func $test2
+  (drop
+   (ref.null extern)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (global $write-only i32 (i32.const 1))
+ (func $foo
+  (drop
+   (i32.const 2)
+  )
+ )
+)
diff --git a/binaryen/test/passes/simplify-globals_all-features.wast b/binaryen/test/passes/simplify-globals_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-globals_all-features.wast
@@ -0,0 +1,148 @@
+(module
+  (import "env" "global-1" (global $g1 i32))
+  (global $g2 (mut i32) (global.get $g1))
+  (func $foo
+   (drop (global.get $g1))
+   (drop (global.get $g2))
+  )
+)
+(module
+  (import "env" "global-1" (global $g1 i32))
+  (global $g2 (mut i32) (global.get $g1))
+  (global $g3 (mut i32) (global.get $g2))
+  (global $g4 (mut i32) (global.get $g3))
+  (func $foo
+   (drop (global.get $g1))
+   (drop (global.get $g2))
+   (drop (global.get $g3))
+   (drop (global.get $g4))
+  )
+)
+(module
+  (import "env" "global-1" (global $g1 (mut i32)))
+  (global $g2 (mut i32) (global.get $g1))
+)
+(module
+  (import "env" "global-1" (global $g1 i32))
+  (global $g2 (mut i32) (global.get $g1))
+  (func $foo
+   (global.set $g2 (unreachable))
+  )
+)
+(module
+  (import "env" "global-1" (global $g1 (mut i32)))
+  (global $g2 (mut i32) (global.get $g1))
+  (export "global-2" (global $g2))
+)
+(module
+  (global $g1 i32 (i32.const 1))
+  (global $g2 i32 (global.get $g1))
+  (global $g3 f64 (f64.const -3.4))
+  (global $g4 (mut f64) (f64.const -2.8))
+  (global $g5 i32 (i32.const 2))
+  (global $g6 (mut i32) (global.get $g5))
+  (global $g7 (mut i32) (i32.const 3))
+  (global $g8 i32 (global.get $g7))
+  (global $g9 i32 (i32.const 4))
+  (global $ga (mut i32) (global.get $g9))
+  (global $gb (mut i32) (i32.const 5))
+  (global $gc i32 (global.get $gb))
+  (func $foo
+   (drop (global.get $g1))
+   (drop (global.get $g2))
+   (drop (global.get $g3))
+   (drop (global.get $g4))
+   (drop (global.get $g5))
+   (drop (global.get $g6))
+   (drop (global.get $g7))
+   (drop (global.get $g8))
+   (drop (global.get $g9))
+   (drop (global.get $ga))
+   (drop (global.get $gb))
+   (drop (global.get $gc))
+   (global.set $ga (i32.const 6))
+   (global.set $gb (i32.const 7))
+  )
+)
+(module
+  (global $g1 (mut i32) (i32.const 1))
+  (global $g2 (mut i32) (i32.const 1))
+  (func $f (param $x i32) (result i32)
+    (global.set $g1 (i32.const 100))
+    (global.set $g2 (local.get $x))
+    (if (local.get $x) (return (i32.const 0)))
+    (local.set $x
+      (i32.add
+        (global.get $g1)
+        (global.get $g2)
+      )
+    )
+    (if (local.get $x) (return (i32.const 1)))
+    (global.set $g1 (i32.const 200))
+    (global.set $g2 (local.get $x))
+    (local.set $x
+      (i32.add
+        (global.get $g1)
+        (global.get $g2)
+      )
+    )
+    (local.get $x)
+  )
+)
+(module
+  (global $g1 (mut i32) (i32.const 1))
+  (global $g2 (mut i32) (i32.const 1))
+  (func $f (param $x i32) (result i32)
+    (global.set $g1 (i32.const 100))
+    (global.set $g2 (local.get $x))
+    (local.set $x
+      (i32.add
+        (i32.add
+          (global.get $g1)
+          (global.get $g1)
+        )
+        (global.get $g2)
+      )
+    )
+    (local.get $x)
+  )
+)
+(module
+  (global $g1 (mut i32) (i32.const 1))
+  (global $g2 (mut i32) (i32.const 1))
+  (func $no (param $x i32) (result i32)
+    (global.set $g1 (i32.const 100))
+    (drop (call $no (i32.const 200))) ;; invalidate
+    (global.get $g1)
+  )
+  (func $no2 (param $x i32) (result i32)
+    (global.set $g1 (i32.const 100))
+    (global.set $g1 (local.get $x)) ;; invalidate
+    (global.get $g1)
+  )
+  (func $yes (param $x i32) (result i32)
+    (global.set $g1 (i32.const 100))
+    (global.set $g2 (local.get $x)) ;; almost invalidate
+    (global.get $g1)
+  )
+)
+;; Reference type tests
+(module
+  (import "env" "global-1" (global $g1 externref))
+  (global $g2 (mut externref) (global.get $g1))
+  (global $g3 externref (ref.null extern))
+  (func $test1
+    (drop (global.get $g1))
+    (drop (global.get $g2))
+  )
+  (func $test2
+    (drop (global.get $g3))
+  )
+)
+;; Global is used by `set` but never `get` can be eliminated.
+(module
+  (global $write-only (mut i32) (i32.const 1))
+  (func $foo
+    (global.set $write-only (i32.const 2))
+  )
+)
diff --git a/binaryen/test/passes/simplify-locals-nonesting.txt b/binaryen/test/passes/simplify-locals-nonesting.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-locals-nonesting.txt
@@ -0,0 +1,202 @@
+(module
+ (type $i64_i64_i64_=>_i32 (func (param i64 i64 i64) (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $figure-1a (param $a i64) (param $x i64) (param $y i64) (result i32)
+  (local $i i32)
+  (local $j i32)
+  (local $r i32)
+  (local $6 i64)
+  (local $7 i64)
+  (local $8 i32)
+  (local $9 i64)
+  (local $10 i64)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (block $block
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (nop)
+   (local.set $12
+    (i64.eq
+     (local.get $a)
+     (local.get $x)
+    )
+   )
+   (local.set $13
+    (i64.ne
+     (local.get $a)
+     (local.get $y)
+    )
+   )
+   (nop)
+   (nop)
+   (nop)
+   (local.set $15
+    (i32.and
+     (local.get $12)
+     (local.get $13)
+    )
+   )
+   (return
+    (local.get $15)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $16)
+  )
+ )
+ (func $figure-1b (param $a i64) (param $x i64) (param $y i64) (result i32)
+  (local $i i32)
+  (local $j i32)
+  (local $r i32)
+  (local $6 i64)
+  (local $7 i64)
+  (local $8 i32)
+  (local $9 i64)
+  (local $10 i64)
+  (local $11 i32)
+  (local $12 i64)
+  (local $13 i64)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (block $block
+   (nop)
+   (nop)
+   (local.set $8
+    (i64.lt_s
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+   (if
+    (local.get $8)
+    (block $block0
+     (block $block1
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (nop)
+      (local.set $15
+       (i64.eq
+        (local.get $a)
+        (local.get $x)
+       )
+      )
+      (local.set $16
+       (i64.ne
+        (local.get $a)
+        (local.get $y)
+       )
+      )
+      (nop)
+      (nop)
+      (nop)
+      (local.set $18
+       (i32.and
+        (local.get $15)
+        (local.get $16)
+       )
+      )
+      (return
+       (local.get $18)
+      )
+      (unreachable)
+     )
+     (unreachable)
+    )
+    (block $block2
+     (unreachable)
+     (unreachable)
+    )
+   )
+  )
+  (unreachable)
+ )
+ (func $figure-3-if (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block $block
+   (block $block3
+    (nop)
+    (local.set $2
+     (i32.and
+      (local.get $x)
+      (i32.const 1)
+     )
+    )
+    (if
+     (local.get $2)
+     (block $block4
+      (nop)
+      (nop)
+      (local.set $x
+       (i32.add
+        (local.get $x)
+        (i32.const 1)
+       )
+      )
+      (nop)
+     )
+     (block $block5
+      (nop)
+      (nop)
+      (local.set $x
+       (i32.add
+        (local.get $x)
+        (i32.const 2)
+       )
+      )
+      (nop)
+     )
+    )
+   )
+   (nop)
+   (nop)
+   (local.set $8
+    (i32.and
+     (local.get $x)
+     (i32.const 1)
+    )
+   )
+   (return
+    (local.get $8)
+   )
+   (unreachable)
+  )
+  (nop)
+  (return
+   (local.get $9)
+  )
+ )
+)
diff --git a/binaryen/test/passes/simplify-locals-nonesting.wast b/binaryen/test/passes/simplify-locals-nonesting.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-locals-nonesting.wast
@@ -0,0 +1,262 @@
+(module
+ (type $0 (func (param i64 i64 i64) (result i32)))
+ (type $1 (func (param i32) (result i32)))
+ (func $figure-1a (; 0 ;) (type $0) (param $a i64) (param $x i64) (param $y i64) (result i32)
+  (local $i i32)
+  (local $j i32)
+  (local $r i32)
+  (local $6 i64)
+  (local $7 i64)
+  (local $8 i32)
+  (local $9 i64)
+  (local $10 i64)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (block
+   (local.set $6
+    (local.get $a)
+   )
+   (local.set $7
+    (local.get $x)
+   )
+   (local.set $8
+    (i64.eq
+     (local.get $6)
+     (local.get $7)
+    )
+   )
+   (local.set $i
+    (local.get $8)
+   )
+   (nop)
+   (local.set $9
+    (local.get $a)
+   )
+   (local.set $10
+    (local.get $y)
+   )
+   (local.set $11
+    (i64.ne
+     (local.get $9)
+     (local.get $10)
+    )
+   )
+   (local.set $j
+    (local.get $11)
+   )
+   (nop)
+   (local.set $12
+    (local.get $i)
+   )
+   (local.set $13
+    (local.get $j)
+   )
+   (local.set $14
+    (i32.and
+     (local.get $12)
+     (local.get $13)
+    )
+   )
+   (local.set $r
+    (local.get $14)
+   )
+   (nop)
+   (local.set $15
+    (local.get $r)
+   )
+   (return
+    (local.get $15)
+   )
+   (unreachable)
+  )
+  (local.set $17
+   (local.get $16)
+  )
+  (return
+   (local.get $17)
+  )
+ )
+ (func $figure-1b (; 1 ;) (type $0) (param $a i64) (param $x i64) (param $y i64) (result i32)
+  (local $i i32)
+  (local $j i32)
+  (local $r i32)
+  (local $6 i64)
+  (local $7 i64)
+  (local $8 i32)
+  (local $9 i64)
+  (local $10 i64)
+  (local $11 i32)
+  (local $12 i64)
+  (local $13 i64)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local $18 i32)
+  (block
+   (local.set $6
+    (local.get $x)
+   )
+   (local.set $7
+    (local.get $y)
+   )
+   (local.set $8
+    (i64.lt_s
+     (local.get $6)
+     (local.get $7)
+    )
+   )
+   (if
+    (local.get $8)
+    (block
+     (block $block
+      (local.set $9
+       (local.get $a)
+      )
+      (local.set $10
+       (local.get $x)
+      )
+      (local.set $11
+       (i64.eq
+        (local.get $9)
+        (local.get $10)
+       )
+      )
+      (local.set $i
+       (local.get $11)
+      )
+      (nop)
+      (local.set $12
+       (local.get $a)
+      )
+      (local.set $13
+       (local.get $y)
+      )
+      (local.set $14
+       (i64.ne
+        (local.get $12)
+        (local.get $13)
+       )
+      )
+      (local.set $j
+       (local.get $14)
+      )
+      (nop)
+      (local.set $15
+       (local.get $i)
+      )
+      (local.set $16
+       (local.get $j)
+      )
+      (local.set $17
+       (i32.and
+        (local.get $15)
+        (local.get $16)
+       )
+      )
+      (local.set $r
+       (local.get $17)
+      )
+      (nop)
+      (local.set $18
+       (local.get $r)
+      )
+      (return
+       (local.get $18)
+      )
+      (unreachable)
+     )
+     (unreachable)
+    )
+    (block
+     (unreachable)
+     (unreachable)
+    )
+   )
+  )
+  (unreachable)
+ )
+ (func $figure-3-if (; 2 ;) (type $1) (param $x i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (block
+   (block
+    (local.set $1
+     (local.get $x)
+    )
+    (local.set $2
+     (i32.and
+      (local.get $1)
+      (i32.const 1)
+     )
+    )
+    (if
+     (local.get $2)
+     (block
+      (local.set $3
+       (local.get $x)
+      )
+      (local.set $4
+       (i32.add
+        (local.get $3)
+        (i32.const 1)
+       )
+      )
+      (local.set $x
+       (local.get $4)
+      )
+      (nop)
+     )
+     (block
+      (local.set $5
+       (local.get $x)
+      )
+      (local.set $6
+       (i32.add
+        (local.get $5)
+        (i32.const 2)
+       )
+      )
+      (local.set $x
+       (local.get $6)
+      )
+      (nop)
+     )
+    )
+   )
+   (nop)
+   (local.set $7
+    (local.get $x)
+   )
+   (local.set $8
+    (i32.and
+     (local.get $7)
+     (i32.const 1)
+    )
+   )
+   (return
+    (local.get $8)
+   )
+   (unreachable)
+  )
+  (local.set $10
+   (local.get $9)
+  )
+  (return
+   (local.get $10)
+  )
+ )
+)
diff --git a/binaryen/test/passes/simplify-locals-nostructure.txt b/binaryen/test/passes/simplify-locals-nostructure.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-locals-nostructure.txt
@@ -0,0 +1,132 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_=>_f64 (func (param i32 i32) (result f64)))
+ (memory $0 1)
+ (func $contrast
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (local $a i32)
+  (local $b i32)
+  (nop)
+  (if
+   (local.tee $x
+    (i32.const 1)
+   )
+   (nop)
+  )
+  (if
+   (local.get $x)
+   (nop)
+  )
+  (nop)
+  (drop
+   (if (result i32)
+    (i32.const 2)
+    (i32.const 3)
+    (i32.const 4)
+   )
+  )
+  (nop)
+  (drop
+   (block $block (result i32)
+    (i32.const 5)
+   )
+  )
+  (if
+   (i32.const 6)
+   (local.set $a
+    (i32.const 7)
+   )
+   (local.set $a
+    (i32.const 8)
+   )
+  )
+  (drop
+   (local.get $a)
+  )
+  (block $val
+   (if
+    (i32.const 10)
+    (block $block4
+     (local.set $b
+      (i32.const 11)
+     )
+     (br $val)
+    )
+   )
+   (local.set $b
+    (i32.const 12)
+   )
+  )
+  (drop
+   (local.get $b)
+  )
+ )
+ (func $no-unreachable
+  (local $x i32)
+  (unreachable)
+ )
+ (func $implicit-trap-and-global-effects
+  (local $var$0 i32)
+  (local.set $var$0
+   (i32.trunc_f64_u
+    (f64.const -nan:0xfffffffffffc3)
+   )
+  )
+  (f32.store align=1
+   (i32.const 22)
+   (f32.const 154)
+  )
+  (drop
+   (local.get $var$0)
+  )
+ )
+ (func $implicit-trap-and-local-effects
+  (local $var$0 i32)
+  (local $other i32)
+  (nop)
+  (local.set $other
+   (i32.const 100)
+  )
+  (drop
+   (i32.trunc_f64_u
+    (f64.const -nan:0xfffffffffffc3)
+   )
+  )
+  (if
+   (i32.const 1)
+   (drop
+    (local.get $other)
+   )
+  )
+ )
+ (func $multi-pass-get-equivs-right (param $var$0 i32) (param $var$1 i32) (result f64)
+  (local $var$2 i32)
+  (nop)
+  (i32.store
+   (local.get $var$0)
+   (i32.const 1)
+  )
+  (f64.promote_f32
+   (f32.load
+    (local.get $var$0)
+   )
+  )
+ )
+ (func $if-value-structure-equivalent (param $x i32) (result i32)
+  (local $y i32)
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.const 2)
+   )
+   (block $block
+    (nop)
+    (nop)
+   )
+  )
+  (local.get $x)
+ )
+)
diff --git a/binaryen/test/passes/simplify-locals-nostructure.wast b/binaryen/test/passes/simplify-locals-nostructure.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-locals-nostructure.wast
@@ -0,0 +1,100 @@
+(module
+  (memory 1)
+  (func $contrast ;; check for tee and structure sinking
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local $a i32)
+    (local $b i32)
+    (local.set $x (i32.const 1))
+    (if (local.get $x) (nop))
+    (if (local.get $x) (nop))
+    (local.set $y (if (result i32) (i32.const 2) (i32.const 3) (i32.const 4)))
+    (drop (local.get $y))
+    (local.set $z (block (result i32) (i32.const 5)))
+    (drop (local.get $z))
+    (if (i32.const 6)
+      (local.set $a (i32.const 7))
+      (local.set $a (i32.const 8))
+    )
+    (drop (local.get $a))
+    (block $val
+      (if (i32.const 10)
+        (block
+          (local.set $b (i32.const 11))
+          (br $val)
+        )
+      )
+      (local.set $b (i32.const 12))
+    )
+    (drop (local.get $b))
+  )
+  (func $no-unreachable
+    (local $x i32)
+    (drop
+      (local.tee $x
+        (unreachable)
+      )
+    )
+  )
+  (func $implicit-trap-and-global-effects
+    (local $var$0 i32)
+    (local.set $var$0
+     (i32.trunc_f64_u
+      (f64.const -nan:0xfffffffffffc3) ;; this implicit trap will actually trap
+     )
+    )
+    (f32.store align=1 ;; and if we move it across this store, the store will execute, having global side effects
+     (i32.const 22)
+     (f32.const 154)
+    )
+    (drop
+     (local.get $var$0)
+    )
+  )
+  (func $implicit-trap-and-local-effects
+    (local $var$0 i32)
+    (local $other i32)
+    (local.set $var$0
+     (i32.trunc_f64_u
+      (f64.const -nan:0xfffffffffffc3) ;; this implicit trap will actually trap
+     )
+    )
+    (local.set $other (i32.const 100)) ;; but it's fine to move it across a local effect, that vanishes anyhow
+    (drop
+     (local.get $var$0)
+    )
+    (if (i32.const 1)
+     (drop
+      (local.get $other)
+     )
+    )
+  )
+  (func $multi-pass-get-equivs-right (param $var$0 i32) (param $var$1 i32) (result f64)
+   (local $var$2 i32)
+   (local.set $var$2
+    (local.get $var$0)
+   )
+   (i32.store
+    (local.get $var$2)
+    (i32.const 1)
+   )
+   (f64.promote_f32
+    (f32.load
+     (local.get $var$2)
+    )
+   )
+  )
+  (func $if-value-structure-equivalent (param $x i32) (result i32)
+    (local $y i32)
+    (if (i32.const 1)
+      (local.set $x (i32.const 2))
+      (block
+        (local.set $y (local.get $x))
+        (local.set $x (local.get $y))
+      )
+    )
+    (local.get $x)
+  )
+)
+
diff --git a/binaryen/test/passes/simplify-locals-notee-nostructure.txt b/binaryen/test/passes/simplify-locals-notee-nostructure.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-locals-notee-nostructure.txt
@@ -0,0 +1,64 @@
+(module
+ (type $none_=>_none (func))
+ (func $contrast
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (local $a i32)
+  (local $b i32)
+  (local.set $x
+   (i32.const 1)
+  )
+  (if
+   (local.get $x)
+   (nop)
+  )
+  (if
+   (local.get $x)
+   (nop)
+  )
+  (nop)
+  (drop
+   (if (result i32)
+    (i32.const 2)
+    (i32.const 3)
+    (i32.const 4)
+   )
+  )
+  (nop)
+  (drop
+   (block $block (result i32)
+    (i32.const 5)
+   )
+  )
+  (if
+   (i32.const 6)
+   (local.set $a
+    (i32.const 7)
+   )
+   (local.set $a
+    (i32.const 8)
+   )
+  )
+  (drop
+   (local.get $a)
+  )
+  (block $val
+   (if
+    (i32.const 10)
+    (block $block4
+     (local.set $b
+      (i32.const 11)
+     )
+     (br $val)
+    )
+   )
+   (local.set $b
+    (i32.const 12)
+   )
+  )
+  (drop
+   (local.get $b)
+  )
+ )
+)
diff --git a/binaryen/test/passes/simplify-locals-notee-nostructure.wast b/binaryen/test/passes/simplify-locals-notee-nostructure.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-locals-notee-nostructure.wast
@@ -0,0 +1,32 @@
+(module
+  (func $contrast ;; check for tee and structure sinking
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local $a i32)
+    (local $b i32)
+    (local.set $x (i32.const 1))
+    (if (local.get $x) (nop))
+    (if (local.get $x) (nop))
+    (local.set $y (if (result i32) (i32.const 2) (i32.const 3) (i32.const 4)))
+    (drop (local.get $y))
+    (local.set $z (block (result i32) (i32.const 5)))
+    (drop (local.get $z))
+    (if (i32.const 6)
+      (local.set $a (i32.const 7))
+      (local.set $a (i32.const 8))
+    )
+    (drop (local.get $a))
+    (block $val
+      (if (i32.const 10)
+        (block
+          (local.set $b (i32.const 11))
+          (br $val)
+        )
+      )
+      (local.set $b (i32.const 12))
+    )
+    (drop (local.get $b))
+  )
+)
+
diff --git a/binaryen/test/passes/simplify-locals-notee.txt b/binaryen/test/passes/simplify-locals-notee.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-locals-notee.txt
@@ -0,0 +1,65 @@
+(module
+ (type $none_=>_none (func))
+ (func $contrast
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (local $a i32)
+  (local $b i32)
+  (local.set $x
+   (i32.const 1)
+  )
+  (if
+   (local.get $x)
+   (nop)
+  )
+  (if
+   (local.get $x)
+   (nop)
+  )
+  (nop)
+  (drop
+   (if (result i32)
+    (i32.const 2)
+    (i32.const 3)
+    (i32.const 4)
+   )
+  )
+  (nop)
+  (drop
+   (block $block (result i32)
+    (i32.const 5)
+   )
+  )
+  (nop)
+  (drop
+   (if (result i32)
+    (i32.const 6)
+    (block (result i32)
+     (nop)
+     (i32.const 7)
+    )
+    (block (result i32)
+     (nop)
+     (i32.const 8)
+    )
+   )
+  )
+  (nop)
+  (drop
+   (block $val (result i32)
+    (if
+     (i32.const 10)
+     (block $block4
+      (nop)
+      (br $val
+       (i32.const 11)
+      )
+     )
+    )
+    (nop)
+    (i32.const 12)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/simplify-locals-notee.wast b/binaryen/test/passes/simplify-locals-notee.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-locals-notee.wast
@@ -0,0 +1,32 @@
+(module
+  (func $contrast ;; check for tee and structure sinking
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local $a i32)
+    (local $b i32)
+    (local.set $x (i32.const 1))
+    (if (local.get $x) (nop))
+    (if (local.get $x) (nop))
+    (local.set $y (if (result i32) (i32.const 2) (i32.const 3) (i32.const 4)))
+    (drop (local.get $y))
+    (local.set $z (block (result i32) (i32.const 5)))
+    (drop (local.get $z))
+    (if (i32.const 6)
+      (local.set $a (i32.const 7))
+      (local.set $a (i32.const 8))
+    )
+    (drop (local.get $a))
+    (block $val
+      (if (i32.const 10)
+        (block
+          (local.set $b (i32.const 11))
+          (br $val)
+        )
+      )
+      (local.set $b (i32.const 12))
+    )
+    (drop (local.get $b))
+  )
+)
+
diff --git a/binaryen/test/passes/simplify-locals.txt b/binaryen/test/passes/simplify-locals.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-locals.txt
@@ -0,0 +1,22 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (func $sink-from-inside (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (nop)
+  (i32.and
+   (select
+    (i32.const 0)
+    (i32.const 1)
+    (i32.const 1)
+   )
+   (block $block (result i32)
+    (nop)
+    (nop)
+    (nop)
+    (i32.const 1)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/simplify-locals.wast b/binaryen/test/passes/simplify-locals.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-locals.wast
@@ -0,0 +1,29 @@
+(module
+ (func $sink-from-inside (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $2
+   (block (result i32)
+    (local.set $0
+     (i32.const 1)
+    )
+    (drop
+     (local.get $0)
+    )
+    (local.set $1 ;; after we sink this, must be careful about sinking the parent, to not reorder other things badly
+     (select
+      (i32.const 0)
+      (i32.const 1)
+      (local.get $0)
+     )
+    )
+    (i32.const 1)
+   )
+  )
+  (i32.and
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+)
diff --git a/binaryen/test/passes/simplify-locals_all-features.txt b/binaryen/test/passes/simplify-locals_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-locals_all-features.txt
@@ -0,0 +1,2042 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32 i32 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)))
+ (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_=>_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)))
+ (import "env" "waka" (func $waka))
+ (import "env" "waka_int" (func $waka_int (result i32)))
+ (import "env" "i64sub" (func $_i64Subtract (param i32 i32 i32 i32) (result i32)))
+ (import "env" "moddi" (func $___udivmoddi4 (param i32 i32 i32 i32 i32) (result i32)))
+ (import "env" "lp" (func $lp (param i32 i32) (result i32)))
+ (import "fuzzing-support" "log-f32" (func $fimport$0 (param f32)))
+ (memory $0 256 256)
+ (global $global$0 (mut i32) (i32.const 10))
+ (func $contrast
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (local $a i32)
+  (local $b i32)
+  (nop)
+  (if
+   (local.tee $x
+    (i32.const 1)
+   )
+   (nop)
+  )
+  (if
+   (local.get $x)
+   (nop)
+  )
+  (nop)
+  (drop
+   (if (result i32)
+    (i32.const 2)
+    (i32.const 3)
+    (i32.const 4)
+   )
+  )
+  (nop)
+  (drop
+   (block $block (result i32)
+    (i32.const 5)
+   )
+  )
+  (nop)
+  (drop
+   (if (result i32)
+    (i32.const 6)
+    (block (result i32)
+     (nop)
+     (i32.const 7)
+    )
+    (block (result i32)
+     (nop)
+     (i32.const 8)
+    )
+   )
+  )
+  (nop)
+  (drop
+   (block $val (result i32)
+    (if
+     (i32.const 10)
+     (block $block4
+      (nop)
+      (br $val
+       (i32.const 11)
+      )
+     )
+    )
+    (nop)
+    (i32.const 12)
+   )
+  )
+ )
+ (func $b0-yes (param $i1 i32)
+  (local $x i32)
+  (local $y i32)
+  (local $a i32)
+  (local $b i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (nop)
+  (drop
+   (i32.const 5)
+  )
+  (block $block0
+   (nop)
+   (drop
+    (i32.const 7)
+   )
+  )
+  (nop)
+  (drop
+   (i32.const 11)
+  )
+  (drop
+   (i32.const 9)
+  )
+  (drop
+   (local.get $y)
+  )
+  (block $block1
+   (drop
+    (i32.const 8)
+   )
+   (drop
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.const 11)
+  )
+  (drop
+   (local.get $y)
+  )
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (block $block2
+   (nop)
+   (nop)
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 2)
+   )
+   (drop
+    (i32.const 3)
+   )
+   (drop
+    (i32.const 4)
+   )
+   (nop)
+   (nop)
+   (drop
+    (i32.const 6)
+   )
+   (drop
+    (i32.const 5)
+   )
+   (drop
+    (i32.const 7)
+   )
+   (drop
+    (i32.const 8)
+   )
+   (local.set $a
+    (i32.const 9)
+   )
+   (local.set $b
+    (i32.const 10)
+   )
+   (call $waka)
+   (drop
+    (local.get $a)
+   )
+   (drop
+    (local.get $b)
+   )
+   (drop
+    (i32.const 11)
+   )
+   (drop
+    (i32.const 12)
+   )
+   (nop)
+   (nop)
+   (drop
+    (i32.load
+     (i32.const 24)
+    )
+   )
+   (drop
+    (i32.const 13)
+   )
+   (drop
+    (i32.const 14)
+   )
+   (drop
+    (i32.const 15)
+   )
+   (drop
+    (i32.const 16)
+   )
+   (nop)
+   (nop)
+   (i32.store
+    (i32.const 48)
+    (i32.const 96)
+   )
+   (local.set $a
+    (i32.const 17)
+   )
+   (local.set $b
+    (i32.const 18)
+   )
+  )
+  (block $block3
+   (nop)
+   (local.set $a
+    (call $waka_int)
+   )
+   (call $waka)
+   (local.set $a
+    (call $waka_int)
+   )
+   (call $waka)
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+   (local.set $a
+    (call $waka_int)
+   )
+   (drop
+    (i32.load
+     (i32.const 1)
+    )
+   )
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+   (local.set $a
+    (call $waka_int)
+   )
+   (i32.store
+    (i32.const 1)
+    (i32.const 2)
+   )
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+   (nop)
+   (local.set $a
+    (i32.load
+     (i32.const 100)
+    )
+   )
+   (call $waka)
+   (nop)
+   (drop
+    (i32.load
+     (i32.const 1)
+    )
+   )
+   (local.set $a
+    (i32.load
+     (i32.const 101)
+    )
+   )
+   (call $waka)
+   (local.set $a
+    (i32.load
+     (i32.const 102)
+    )
+   )
+   (call $waka)
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+   (local.set $a
+    (i32.load
+     (i32.const 103)
+    )
+   )
+   (i32.store
+    (i32.const 1)
+    (i32.const 2)
+   )
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+   (nop)
+   (local.set $a
+    (block $block (result i32)
+     (block $block5
+      (nop)
+      (i32.store
+       (i32.const 104)
+       (local.tee $5
+        (i32.const 105)
+       )
+      )
+     )
+     (local.get $5)
+    )
+   )
+   (call $waka)
+   (local.set $a
+    (block $block6 (result i32)
+     (block $block7
+      (nop)
+      (i32.store
+       (i32.const 106)
+       (local.tee $6
+        (i32.const 107)
+       )
+      )
+     )
+     (local.get $6)
+    )
+   )
+   (call $waka)
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+   (local.set $a
+    (block $block8 (result i32)
+     (block $block9
+      (nop)
+      (i32.store
+       (i32.const 108)
+       (local.tee $7
+        (i32.const 109)
+       )
+      )
+     )
+     (local.get $7)
+    )
+   )
+   (drop
+    (i32.load
+     (i32.const 1)
+    )
+   )
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+   (local.set $a
+    (block $block10 (result i32)
+     (block $block11
+      (nop)
+      (i32.store
+       (i32.const 110)
+       (local.tee $8
+        (i32.const 111)
+       )
+      )
+     )
+     (local.get $8)
+    )
+   )
+   (i32.store
+    (i32.const 1)
+    (i32.const 2)
+   )
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+  )
+  (block $out-of-block
+   (nop)
+   (nop)
+   (drop
+    (block $b (result i32)
+     (block $c
+      (br $b
+       (i32.const 1337)
+      )
+     )
+     (nop)
+     (i32.const 9876)
+    )
+   )
+  )
+  (block $loopey
+   (local.set $a
+    (i32.const 1337)
+   )
+   (drop
+    (loop $loop-in5 (result i32)
+     (drop
+      (local.get $a)
+     )
+     (local.tee $a
+      (i32.const 9876)
+     )
+    )
+   )
+   (drop
+    (local.get $a)
+   )
+  )
+ )
+ (func $Ia (param $a i32) (result i32)
+  (local $b i32)
+  (block $switch$0
+   (block $switch-default$6
+    (nop)
+   )
+  )
+  (return
+   (i32.const 60)
+  )
+ )
+ (func $memories (param $i2 i32) (param $i3 i32) (param $bi2 i32) (param $bi3 i32) (param $ci3 i32) (param $di3 i32)
+  (local $set_with_no_get i32)
+  (nop)
+  (i32.store8
+   (local.get $i2)
+   (i32.const 1)
+  )
+  (nop)
+  (i32.store8
+   (local.tee $bi3
+    (i32.const 1)
+   )
+   (local.get $bi3)
+  )
+  (nop)
+  (i32.store8
+   (local.get $bi3)
+   (local.get $bi3)
+  )
+  (local.set $di3
+   (local.tee $bi3
+    (i32.const 123)
+   )
+  )
+  (i32.store8
+   (local.get $bi3)
+   (local.get $di3)
+  )
+  (nop)
+ )
+ (func $___remdi3 (param $$a$0 i32) (param $$a$1 i32) (param $$b$0 i32) (param $$b$1 i32) (result i32)
+  (local $$1$1 i32)
+  (local $$1$0 i32)
+  (local $$rem i32)
+  (local $__stackBase__ i32)
+  (local $$2$1 i32)
+  (local $$2$0 i32)
+  (local $$4$1 i32)
+  (local $$4$0 i32)
+  (local $$10$1 i32)
+  (local $$10$0 i32)
+  (local $$6$0 i32)
+  (local.set $__stackBase__
+   (i32.load
+    (i32.const 8)
+   )
+  )
+  (i32.store
+   (i32.const 8)
+   (i32.add
+    (i32.load
+     (i32.const 8)
+    )
+    (i32.const 16)
+   )
+  )
+  (local.set $$rem
+   (local.get $__stackBase__)
+  )
+  (local.set $$1$0
+   (i32.or
+    (i32.shr_s
+     (local.get $$a$1)
+     (i32.const 31)
+    )
+    (i32.shl
+     (if (result i32)
+      (i32.lt_s
+       (local.get $$a$1)
+       (i32.const 0)
+      )
+      (i32.const -1)
+      (i32.const 0)
+     )
+     (i32.const 1)
+    )
+   )
+  )
+  (local.set $$1$1
+   (i32.or
+    (i32.shr_s
+     (if (result i32)
+      (i32.lt_s
+       (local.get $$a$1)
+       (i32.const 0)
+      )
+      (i32.const -1)
+      (i32.const 0)
+     )
+     (i32.const 31)
+    )
+    (i32.shl
+     (if (result i32)
+      (i32.lt_s
+       (local.get $$a$1)
+       (i32.const 0)
+      )
+      (i32.const -1)
+      (i32.const 0)
+     )
+     (i32.const 1)
+    )
+   )
+  )
+  (local.set $$2$0
+   (i32.or
+    (i32.shr_s
+     (local.get $$b$1)
+     (i32.const 31)
+    )
+    (i32.shl
+     (if (result i32)
+      (i32.lt_s
+       (local.get $$b$1)
+       (i32.const 0)
+      )
+      (i32.const -1)
+      (i32.const 0)
+     )
+     (i32.const 1)
+    )
+   )
+  )
+  (local.set $$2$1
+   (i32.or
+    (i32.shr_s
+     (if (result i32)
+      (i32.lt_s
+       (local.get $$b$1)
+       (i32.const 0)
+      )
+      (i32.const -1)
+      (i32.const 0)
+     )
+     (i32.const 31)
+    )
+    (i32.shl
+     (if (result i32)
+      (i32.lt_s
+       (local.get $$b$1)
+       (i32.const 0)
+      )
+      (i32.const -1)
+      (i32.const 0)
+     )
+     (i32.const 1)
+    )
+   )
+  )
+  (nop)
+  (nop)
+  (drop
+   (call $___udivmoddi4
+    (call $_i64Subtract
+     (i32.xor
+      (local.get $$1$0)
+      (local.get $$a$0)
+     )
+     (i32.xor
+      (local.get $$1$1)
+      (local.get $$a$1)
+     )
+     (local.get $$1$0)
+     (local.get $$1$1)
+    )
+    (i32.load
+     (i32.const 168)
+    )
+    (call $_i64Subtract
+     (i32.xor
+      (local.get $$2$0)
+      (local.get $$b$0)
+     )
+     (i32.xor
+      (local.get $$2$1)
+      (local.get $$b$1)
+     )
+     (local.get $$2$0)
+     (local.get $$2$1)
+    )
+    (i32.load
+     (i32.const 168)
+    )
+    (local.get $$rem)
+   )
+  )
+  (local.set $$10$0
+   (call $_i64Subtract
+    (i32.xor
+     (i32.load
+      (local.get $$rem)
+     )
+     (local.get $$1$0)
+    )
+    (i32.xor
+     (i32.load offset=4
+      (local.get $$rem)
+     )
+     (local.get $$1$1)
+    )
+    (local.get $$1$0)
+    (local.get $$1$1)
+   )
+  )
+  (local.set $$10$1
+   (i32.load
+    (i32.const 168)
+   )
+  )
+  (i32.store
+   (i32.const 8)
+   (local.get $__stackBase__)
+  )
+  (return
+   (block $block12 (result i32)
+    (i32.store
+     (i32.const 168)
+     (local.get $$10$1)
+    )
+    (local.get $$10$0)
+   )
+  )
+ )
+ (func $block-returns
+  (local $x i32)
+  (local.set $x
+   (block $out (result i32)
+    (nop)
+    (drop
+     (br_if $out
+      (local.tee $x
+       (block $waka (result i32)
+        (nop)
+        (drop
+         (br_if $waka
+          (local.tee $x
+           (i32.const 12)
+          )
+          (i32.const 1)
+         )
+        )
+        (nop)
+        (i32.const 34)
+       )
+      )
+      (i32.const 1)
+     )
+    )
+    (drop
+     (local.get $x)
+    )
+    (block $waka2
+     (local.set $x
+      (if (result i32)
+       (i32.const 1)
+       (block (result i32)
+        (nop)
+        (i32.const 13)
+       )
+       (block (result i32)
+        (nop)
+        (i32.const 24)
+       )
+      )
+     )
+     (nop)
+    )
+    (drop
+     (br_if $out
+      (local.tee $x
+       (if (result i32)
+        (i32.const 1)
+        (block (result i32)
+         (block $block3
+          (nop)
+         )
+         (i32.const 14)
+        )
+        (block (result i32)
+         (block $block5
+          (nop)
+         )
+         (i32.const 25)
+        )
+       )
+      )
+      (i32.const 1)
+     )
+    )
+    (block $sink-out-of-me-i-have-but-one-exit
+     (nop)
+    )
+    (nop)
+    (i32.const 99)
+   )
+  )
+ )
+ (func $multiple (param $s i32) (param $r i32) (param $f i32) (param $p i32) (param $t i32) (param $m i32)
+  (nop)
+  (local.set $r
+   (i32.add
+    (local.get $f)
+    (local.get $p)
+   )
+  )
+  (local.set $t
+   (local.get $p)
+  )
+  (local.set $p
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (i32.store
+   (local.get $r)
+   (local.get $t)
+  )
+  (drop
+   (local.get $m)
+  )
+  (drop
+   (local.get $t)
+  )
+ )
+ (func $switch-def (param $i3 i32) (result i32)
+  (local $i1 i32)
+  (local.set $i1
+   (i32.const 10)
+  )
+  (block $switch$def
+   (block $switch-case$1
+    (br_table $switch-case$1 $switch$def
+     (local.get $i3)
+    )
+   )
+   (local.set $i1
+    (i32.const 1)
+   )
+  )
+  (return
+   (local.get $i1)
+  )
+ )
+ (func $no-out-of-label (param $x i32) (param $y i32)
+  (nop)
+  (local.set $x
+   (loop $moar (result i32)
+    (nop)
+    (block $block (result i32)
+     (br_if $moar
+      (local.get $x)
+     )
+     (i32.const 0)
+    )
+   )
+  )
+  (block $moar18
+   (local.set $y
+    (block $block19 (result i32)
+     (br_if $moar18
+      (local.get $y)
+     )
+     (i32.const 0)
+    )
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+ )
+ (func $freetype-cd (param $a i32) (result i32)
+  (local $e i32)
+  (nop)
+  (local.tee $a
+   (loop $while-in$1 (result i32)
+    (nop)
+    (block $while-out$0 (result i32)
+     (local.set $e
+      (local.get $a)
+     )
+     (nop)
+     (drop
+      (br_if $while-out$0
+       (local.tee $a
+        (i32.const 4)
+       )
+       (local.get $e)
+      )
+     )
+     (nop)
+     (i32.add
+      (local.get $a)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+ )
+ (func $drop-if-value (param $x i32) (param $y i32) (param $z i32) (result i32)
+  (local $temp i32)
+  (drop
+   (if (result i32)
+    (local.get $x)
+    (block $block53 (result i32)
+     (nop)
+     (local.set $temp
+      (local.get $y)
+     )
+     (local.get $z)
+    )
+    (block $block54 (result i32)
+     (nop)
+     (local.set $temp
+      (local.get $y)
+     )
+     (local.get $z)
+    )
+   )
+  )
+  (drop
+   (local.get $temp)
+  )
+  (return
+   (i32.const 0)
+  )
+ )
+ (func $drop-br_if (param $label i32) (param $$cond2 i32) (param $$$0151 i32) (result i32)
+  (nop)
+  (local.tee $label
+   (block $label$break$L4 (result i32)
+    (if
+     (i32.eq
+      (local.get $label)
+      (i32.const 15)
+     )
+     (block $block
+      (nop)
+      (nop)
+      (drop
+       (br_if $label$break$L4
+        (local.tee $label
+         (i32.const 0)
+        )
+        (i32.eqz
+         (i32.eq
+          (local.get $$$0151)
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+    )
+    (nop)
+    (i32.const 1)
+   )
+  )
+ )
+ (func $drop-tee-unreachable
+  (local $x i32)
+  (local.tee $x
+   (unreachable)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $if-return-but-unreachable (param $var$0 i64)
+  (if
+   (unreachable)
+   (drop
+    (local.get $var$0)
+   )
+   (local.set $var$0
+    (i64.const 1)
+   )
+  )
+ )
+ (func $if-one-side (result i32)
+  (local $x i32)
+  (nop)
+  (local.tee $x
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 2)
+    )
+    (local.get $x)
+   )
+  )
+ )
+ (func $if-one-side-undo (result i32)
+  (local $x i32)
+  (local $y i32)
+  (local.set $y
+   (i32.const 0)
+  )
+  (local.set $x
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 2)
+    )
+    (local.get $x)
+   )
+  )
+  (local.get $y)
+ )
+ (func $if-one-side-multi (param $0 i32) (result i32)
+  (nop)
+  (local.tee $0
+   (if (result i32)
+    (i32.lt_s
+     (local.get $0)
+     (i32.const -1073741824)
+    )
+    (block (result i32)
+     (nop)
+     (i32.const -1073741824)
+    )
+    (block (result i32)
+     (nop)
+     (if (result i32)
+      (i32.gt_s
+       (local.get $0)
+       (i32.const 1073741823)
+      )
+      (block (result i32)
+       (nop)
+       (i32.const 1073741823)
+      )
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $if-one-side-undo-but-its-a-tee (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (local.set $x
+   (if (result i32)
+    (i32.const -1)
+    (i32.const -2)
+    (local.get $x)
+   )
+  )
+  (drop
+   (call $if-one-side-undo-but-its-a-tee
+    (local.tee $x
+     (if (result i32)
+      (i32.const -3)
+      (i32.const -4)
+      (local.get $x)
+     )
+    )
+   )
+  )
+  (nop)
+  (drop
+   (i32.eqz
+    (local.tee $y
+     (if (result i32)
+      (i32.const -5)
+      (i32.const -6)
+      (local.get $y)
+     )
+    )
+   )
+  )
+  (nop)
+  (drop
+   (i32.add
+    (local.tee $z
+     (if (result i32)
+      (i32.const -7)
+      (i32.const -8)
+      (local.get $z)
+     )
+    )
+    (local.get $z)
+   )
+  )
+  (if
+   (block $label$1 (result i32)
+    (nop)
+    (nop)
+    (local.tee $4
+     (if (result i32)
+      (local.tee $4
+       (if (result i32)
+        (i32.const 1)
+        (block (result i32)
+         (nop)
+         (i32.const 2)
+        )
+        (local.get $4)
+       )
+      )
+      (block (result i32)
+       (nop)
+       (i32.const 0)
+      )
+      (local.get $4)
+     )
+    )
+   )
+   (unreachable)
+  )
+  (i32.const 0)
+ )
+ (func $splittable-ifs-multicycle (param $20 i32) (result i32)
+  (nop)
+  (local.tee $20
+   (if (result i32)
+    (i32.const 1)
+    (if (result i32)
+     (i32.const 2)
+     (if (result i32)
+      (i32.const 3)
+      (i32.const 4)
+      (local.get $20)
+     )
+     (local.get $20)
+    )
+    (local.get $20)
+   )
+  )
+ )
+ (func $update-getCounter (param $0 i32) (param $1 f64) (param $2 f64) (param $3 f32) (param $4 i32) (result f64)
+  (global.set $global$0
+   (i32.sub
+    (global.get $global$0)
+    (i32.const 1)
+   )
+  )
+  (global.set $global$0
+   (i32.sub
+    (global.get $global$0)
+    (i32.const 1)
+   )
+  )
+  (loop $label$1 (result f64)
+   (global.set $global$0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 1)
+    )
+   )
+   (global.set $global$0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 1)
+    )
+   )
+   (call $fimport$0
+    (local.tee $3
+     (if (result f32)
+      (i32.eqz
+       (local.get $0)
+      )
+      (f32.const 4623408228068004207103214e13)
+      (local.get $3)
+     )
+    )
+   )
+   (global.set $global$0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 1)
+    )
+   )
+   (if (result f64)
+    (global.get $global$0)
+    (block $block
+     (global.set $global$0
+      (i32.sub
+       (global.get $global$0)
+       (i32.const 1)
+      )
+     )
+     (local.set $0
+      (i32.const -65)
+     )
+     (global.set $global$0
+      (i32.sub
+       (global.get $global$0)
+       (i32.const 1)
+      )
+     )
+     (br $label$1)
+    )
+    (f64.const -70)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (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_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_f64 (func (result f64)))
+ (type $i32_i32_=>_f64 (func (param i32 i32) (result f64)))
+ (import "fuzzing-support" "log1" (func $fimport$0 (result i32)))
+ (import "fuzzing-support" "log2" (func $fimport$1 (param i32)))
+ (import "fuzzing-support" "log3" (func $fimport$2 (param f32)))
+ (memory $0 (shared 256 256))
+ (global $global$0 (mut i32) (i32.const 10))
+ (func $nonatomics (result i32)
+  (local $x i32)
+  (nop)
+  (drop
+   (i32.load
+    (i32.const 1028)
+   )
+  )
+  (i32.load
+   (i32.const 1024)
+  )
+ )
+ (func $nonatomic-growmem (result i32)
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (memory.grow
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1028)
+   )
+  )
+  (local.get $x)
+ )
+ (func $atomics
+  (local $x i32)
+  (local.set $x
+   (i32.atomic.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.atomic.load
+    (i32.const 1028)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $one-atomic
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.atomic.load
+    (i32.const 1028)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $other-atomic
+  (local $x i32)
+  (local.set $x
+   (i32.atomic.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1028)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $atomic-growmem (result i32)
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (memory.grow
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (i32.atomic.load
+    (i32.const 1028)
+   )
+  )
+  (local.get $x)
+ )
+ (func $atomicrmw
+  (local $x i32)
+  (local.set $x
+   (i32.atomic.rmw.add
+    (i32.const 1024)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.atomic.load
+    (i32.const 1028)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $atomic-cmpxchg
+  (local $x i32)
+  (local.set $x
+   (i32.atomic.rmw.cmpxchg
+    (i32.const 1024)
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.atomic.load
+    (i32.const 1028)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $br-value-reordering (result i32)
+  (local $temp i32)
+  (block $outside
+   (loop $loop
+    (br_if $outside
+     (block $block (result i32)
+      (br_if $loop
+       (local.get $temp)
+      )
+      (unreachable)
+      (local.set $temp
+       (i32.const -1)
+      )
+      (i32.const 0)
+     )
+    )
+   )
+   (local.set $temp
+    (i32.const -1)
+   )
+  )
+  (unreachable)
+ )
+ (func $br-value-reordering-safe (result i32)
+  (local $temp i32)
+  (local.set $temp
+   (block $outside (result i32)
+    (loop $loop
+     (drop
+      (local.get $temp)
+     )
+     (drop
+      (br_if $outside
+       (local.tee $temp
+        (i32.const -1)
+       )
+       (block $block (result i32)
+        (nop)
+        (i32.const 0)
+       )
+      )
+     )
+    )
+    (nop)
+    (i32.const -1)
+   )
+  )
+  (unreachable)
+ )
+ (func $if-one-side-unreachable
+  (local $x i32)
+  (block $out
+   (drop
+    (if (result i32)
+     (i32.const 1)
+     (block
+      (br $out)
+      (nop)
+     )
+     (block (result i32)
+      (nop)
+      (i32.const 2)
+     )
+    )
+   )
+   (drop
+    (if (result i32)
+     (i32.const 3)
+     (block (result i32)
+      (nop)
+      (i32.const 4)
+     )
+     (block
+      (br $out)
+      (nop)
+     )
+    )
+   )
+   (if
+    (i32.const 5)
+    (br $out)
+    (br $out)
+   )
+  )
+ )
+ (func $if-one-side-unreachable-blocks
+  (local $x i32)
+  (local $y i32)
+  (block $out
+   (drop
+    (if (result i32)
+     (i32.const 1)
+     (block
+      (block $block
+       (nop)
+       (nop)
+       (br $out)
+      )
+      (nop)
+     )
+     (block (result i32)
+      (block $block2
+       (nop)
+       (nop)
+      )
+      (i32.const 4)
+     )
+    )
+   )
+   (drop
+    (if (result i32)
+     (i32.const 6)
+     (block (result i32)
+      (block $block4
+       (nop)
+       (nop)
+      )
+      (i32.const 7)
+     )
+     (block
+      (block $block5
+       (nop)
+       (nop)
+       (br $out)
+      )
+      (nop)
+     )
+    )
+   )
+   (if
+    (i32.const 11)
+    (block $block7
+     (nop)
+     (nop)
+     (br $out)
+    )
+    (block $block8
+     (nop)
+     (nop)
+     (br $out)
+    )
+   )
+  )
+ )
+ (func $loop-value (param $x i32) (result i32)
+  (loop $loopy
+   (unreachable)
+  )
+  (nop)
+  (loop $loopy9 (result i32)
+   (nop)
+   (i32.const 1)
+  )
+ )
+ (func $loop-loop-loopy-value (param $x i32) (result i32)
+  (nop)
+  (loop $loopy1 (result i32)
+   (nop)
+   (loop $loopy2 (result i32)
+    (nop)
+    (loop $loopy3 (result i32)
+     (nop)
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $loop-modified-during-main-pass-be-careful-fuzz (result i32)
+  (local $0 i32)
+  (nop)
+  (if (result i32)
+   (i32.const 0)
+   (block (result i32)
+    (nop)
+    (i32.const 0)
+   )
+   (block
+    (loop $label$4
+     (br $label$4)
+    )
+    (nop)
+   )
+  )
+ )
+ (func $loop-later (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (param $var$3 i32) (param $var$4 i32) (result i32)
+  (nop)
+  (i32.const 0)
+ )
+ (func $pick
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (local.get $y)
+  )
+  (drop
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 1)
+    )
+    (local.get $x)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+  (local.set $x
+   (local.get $y)
+  )
+ )
+ (func $pick-2
+  (local $x i32)
+  (local $y i32)
+  (local.set $y
+   (local.get $x)
+  )
+  (drop
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 1)
+    )
+    (local.get $y)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (local.set $y
+   (local.get $x)
+  )
+ )
+ (func $many
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (local $w i32)
+  (nop)
+  (nop)
+  (local.set $z
+   (local.tee $y
+    (local.get $x)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (local.set $y
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 1)
+    )
+    (local.get $y)
+   )
+  )
+  (local.set $x
+   (local.get $z)
+  )
+  (drop
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 1)
+    )
+    (local.get $y)
+   )
+  )
+  (nop)
+  (nop)
+  (local.set $y
+   (local.get $x)
+  )
+  (nop)
+  (local.set $x
+   (local.tee $z
+    (i32.const 2)
+   )
+  )
+  (drop
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 1)
+    )
+    (local.get $y)
+   )
+  )
+  (nop)
+  (nop)
+  (local.set $y
+   (local.get $x)
+  )
+  (local.set $z
+   (i32.const 2)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $loop-copies (param $x i32) (param $y i32)
+  (loop $loop
+   (nop)
+   (drop
+    (local.get $y)
+   )
+   (br_if $loop
+    (local.get $y)
+   )
+  )
+ )
+ (func $proper-type (result f64)
+  (local $var$0 i32)
+  (local $var$2 f64)
+  (local.set $var$0
+   (select
+    (i32.const 0)
+    (i32.const 1)
+    (local.get $var$0)
+   )
+  )
+  (local.get $var$2)
+ )
+ (func $multi-pass-get-equivs-right (param $var$0 i32) (param $var$1 i32) (result f64)
+  (local $var$2 i32)
+  (nop)
+  (i32.store
+   (local.get $var$0)
+   (i32.const 1)
+  )
+  (f64.promote_f32
+   (f32.load
+    (local.get $var$0)
+   )
+  )
+ )
+ (func $if-value-structure-equivalent (param $x i32) (result i32)
+  (local $y i32)
+  (nop)
+  (local.tee $x
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 2)
+    )
+    (block (result i32)
+     (block $block
+      (nop)
+      (nop)
+     )
+     (local.get $x)
+    )
+   )
+  )
+ )
+ (func $set-tee-need-one-of-them (param $var$0 i32) (param $var$1 i32) (result i32)
+  (local $var$2 i32)
+  (local $var$3 i32)
+  (local.set $var$2
+   (local.get $var$0)
+  )
+  (loop $loop
+   (br_if $loop
+    (local.get $var$1)
+   )
+  )
+  (local.get $var$2)
+ )
+ (func $loop-value-harder (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 f32)
+  (local $4 f32)
+  (local $5 f32)
+  (local $6 f32)
+  (local $7 f32)
+  (local $8 f32)
+  (local $9 f32)
+  (local $10 f32)
+  (block $label$1
+   (nop)
+   (nop)
+   (call $fimport$2
+    (loop $label$2 (result f32)
+     (block $label$3
+      (global.set $global$0
+       (i32.const -1)
+      )
+      (block $label$4
+       (nop)
+       (nop)
+      )
+      (nop)
+      (nop)
+     )
+     (nop)
+     (nop)
+     (if (result f32)
+      (call $fimport$0)
+      (block (result f32)
+       (nop)
+       (f32.const -2048)
+      )
+      (block
+       (block $block
+        (call $fimport$1
+         (i32.const -25732)
+        )
+        (br $label$2)
+       )
+       (nop)
+      )
+     )
+    )
+   )
+   (nop)
+  )
+  (nop)
+  (return
+   (i32.const -5417091)
+  )
+ )
+ (func $tee-chain (param $x i32) (param $z i32) (param $t1 i32) (param $t2 i32) (param $t3 i32) (result i32)
+  (nop)
+  (drop
+   (i32.const 10)
+  )
+  (nop)
+  (local.set $t2
+   (local.tee $t3
+    (local.tee $t1
+     (call $tee-chain
+      (local.get $x)
+      (local.tee $z
+       (i32.const 10)
+      )
+      (local.get $t1)
+      (local.get $t2)
+      (local.get $t3)
+     )
+    )
+   )
+  )
+  (call $tee-chain
+   (local.get $x)
+   (local.get $z)
+   (local.get $t1)
+   (local.get $t2)
+   (local.get $t3)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 256 256)
+ (data passive "hello, there!")
+ (func $memory-init-load
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (memory.init 0
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 5)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-init-store
+  (local $x i32)
+  (local.set $x
+   (block $block (result i32)
+    (i32.store
+     (i32.const 0)
+     (i32.const 42)
+    )
+    (i32.const 0)
+   )
+  )
+  (memory.init 0
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 5)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-copy-load
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (memory.copy
+   (i32.const 0)
+   (i32.const 8)
+   (i32.const 8)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-copy-store
+  (local $x i32)
+  (local.set $x
+   (block $block (result i32)
+    (i32.store
+     (i32.const 0)
+     (i32.const 42)
+    )
+    (i32.const 0)
+   )
+  )
+  (memory.copy
+   (i32.const 0)
+   (i32.const 8)
+   (i32.const 8)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-fill-load
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (memory.fill
+   (i32.const 0)
+   (i32.const 42)
+   (i32.const 8)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-fill-store
+  (local $x i32)
+  (local.set $x
+   (block $block (result i32)
+    (i32.store
+     (i32.const 0)
+     (i32.const 42)
+    )
+    (i32.const 0)
+   )
+  )
+  (memory.fill
+   (i32.const 0)
+   (i32.const 8)
+   (i32.const 8)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $data-drop-load
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (data.drop 0)
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $data-drop-store
+  (local $x i32)
+  (local.set $x
+   (block $block (result i32)
+    (i32.store
+     (i32.const 0)
+     (i32.const 42)
+    )
+    (i32.const 0)
+   )
+  )
+  (data.drop 0)
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $data-drop-memory-init
+  (local $x i32)
+  (local.set $x
+   (block $block (result i32)
+    (memory.init 0
+     (i32.const 0)
+     (i32.const 0)
+     (i32.const 5)
+    )
+    (i32.const 0)
+   )
+  )
+  (data.drop 0)
+  (drop
+   (local.get $x)
+  )
+ )
+)
+(module
+ (type $none_=>_anyref (func (result anyref)))
+ (func $subtype-test (result anyref)
+  (local $0 externref)
+  (local $1 anyref)
+  (local $2 anyref)
+  (block $block
+   (nop)
+  )
+  (nop)
+  (local.get $0)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_exnref_=>_none (func (param i32 exnref)))
+ (type $exnref_=>_none (func (param exnref)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_exnref (func (result exnref)))
+ (event $event$0 (attr 0) (param))
+ (event $event$1 (attr 0) (param exnref))
+ (func $unoptimizable-br_on_exn-block (result exnref)
+  (local $0 exnref)
+  (block $label$0
+   (local.set $0
+    (br_on_exn $label$0 $event$0
+     (ref.null exn)
+    )
+   )
+  )
+  (local.get $0)
+ )
+ (func $br_on_exn-trap
+  (local $0 exnref)
+  (drop
+   (block $label$1 (result exnref)
+    (br_on_exn $label$1 $event$1
+     (ref.null exn)
+    )
+   )
+  )
+ )
+ (func $rethrow-trap
+  (local $0 i32)
+  (drop
+   (block $label$1 (result i32)
+    (try
+     (do
+      (rethrow
+       (ref.null exn)
+      )
+     )
+     (catch
+      (nop)
+     )
+    )
+    (i32.const 0)
+   )
+  )
+ )
+ (func $foo (param $0 i32) (param $1 exnref)
+  (nop)
+ )
+ (func $pop-cannot-be-sinked
+  (local $0 exnref)
+  (try
+   (do
+    (nop)
+   )
+   (catch
+    (local.set $0
+     (pop exnref)
+    )
+    (call $foo
+     (i32.const 3)
+     (local.get $0)
+    )
+   )
+  )
+ )
+ (func $pop-within-catch-can-be-sinked
+  (local $0 exnref)
+  (try
+   (do
+    (nop)
+   )
+   (catch
+    (nop)
+    (call $foo
+     (i32.const 3)
+     (try (result exnref)
+      (do
+       (ref.null exn)
+      )
+      (catch
+       (pop exnref)
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $bar (result i32)
+  (i32.const 3)
+ )
+ (func $call-cannot-be-sinked-into-try
+  (local $0 i32)
+  (local.set $0
+   (call $bar)
+  )
+  (try
+   (do
+    (drop
+     (local.get $0)
+    )
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+   )
+  )
+ )
+ (func $non-call-can-be-sinked-into-try
+  (local $0 i32)
+  (nop)
+  (try
+   (do
+    (drop
+     (i32.const 3)
+    )
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 (shared 1 1))
+ (data passive "data")
+ (export "foo" (func $0))
+ (func $0 (result i32)
+  (local $0 i32)
+  (block $block (result i32)
+   (local.set $0
+    (i32.rem_u
+     (i32.const 0)
+     (i32.const 0)
+    )
+   )
+   (data.drop 0)
+   (local.get $0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/simplify-locals_all-features.wast b/binaryen/test/passes/simplify-locals_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-locals_all-features.wast
@@ -0,0 +1,1802 @@
+(module
+  (memory 256 256)
+  (type $FUNCSIG$v (func))
+  (type $FUNCSIG$i (func (result i32)))
+  (type $FUNCSIG$iiiii (func (param i32 i32 i32 i32) (result i32)))
+  (type $FUNCSIG$iiiiii (func (param i32 i32 i32 i32 i32) (result i32)))
+  (type $4 (func (param i32)))
+  (type $5 (func (param i32) (result i32)))
+  (type $6 (func (param i32 i32 i32 i32 i32 i32)))
+  (import $waka "env" "waka")
+  (import $waka_int "env" "waka_int" (result i32))
+  (import $_i64Subtract "env" "i64sub" (param i32 i32 i32 i32) (result i32))
+  (import $___udivmoddi4 "env" "moddi" (param i32 i32 i32 i32 i32) (result i32))
+  (import $lp "env" "lp" (param i32 i32) (result i32))
+  (import "fuzzing-support" "log-f32" (func $fimport$0 (param f32)))
+  (global $global$0 (mut i32) (i32.const 10))
+  (func $contrast ;; check for tee and structure sinking
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local $a i32)
+    (local $b i32)
+    (local.set $x (i32.const 1))
+    (if (local.get $x) (nop))
+    (if (local.get $x) (nop))
+    (local.set $y (if (result i32) (i32.const 2) (i32.const 3) (i32.const 4)))
+    (drop (local.get $y))
+    (local.set $z (block (result i32) (i32.const 5)))
+    (drop (local.get $z))
+    (if (i32.const 6)
+      (local.set $a (i32.const 7))
+      (local.set $a (i32.const 8))
+    )
+    (drop (local.get $a))
+    (block $val
+      (if (i32.const 10)
+        (block
+          (local.set $b (i32.const 11))
+          (br $val)
+        )
+      )
+      (local.set $b (i32.const 12))
+    )
+    (drop (local.get $b))
+  )
+  (func $b0-yes (type $4) (param $i1 i32)
+    (local $x i32)
+    (local $y i32)
+    (local $a i32)
+    (local $b i32)
+    (local $5 i32)
+    (local $6 i32)
+    (local $7 i32)
+    (local $8 i32)
+    (local.set $x
+      (i32.const 5)
+    )
+    (drop
+      (local.get $x)
+    )
+    (block $block0
+      (local.set $x
+        (i32.const 7)
+      )
+      (drop
+        (local.get $x)
+      )
+    )
+    (local.set $x
+      (i32.const 11)
+    )
+    (drop
+      (local.get $x)
+    )
+    (local.set $x
+      (i32.const 9)
+    )
+    (drop
+      (local.get $y)
+    )
+    (block $block1
+      (local.set $x
+        (i32.const 8)
+      )
+      (drop
+        (local.get $y)
+      )
+    )
+    (local.set $x
+      (i32.const 11)
+    )
+    (drop
+      (local.get $y)
+    )
+    (local.set $x
+      (i32.const 17)
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $x)
+    )
+    (block $block2
+      (local.set $a
+        (i32.const 1)
+      )
+      (local.set $b
+        (i32.const 2)
+      )
+      (drop
+        (local.get $a)
+      )
+      (drop
+        (local.get $b)
+      )
+      (local.set $a
+        (i32.const 3)
+      )
+      (local.set $b
+        (i32.const 4)
+      )
+      (local.set $a
+        (i32.const 5)
+      )
+      (local.set $b
+        (i32.const 6)
+      )
+      (drop
+        (local.get $b)
+      )
+      (drop
+        (local.get $a)
+      )
+      (local.set $a
+        (i32.const 7)
+      )
+      (local.set $b
+        (i32.const 8)
+      )
+      (local.set $a
+        (i32.const 9)
+      )
+      (local.set $b
+        (i32.const 10)
+      )
+      (call $waka)
+      (drop
+        (local.get $a)
+      )
+      (drop
+        (local.get $b)
+      )
+      (local.set $a
+        (i32.const 11)
+      )
+      (local.set $b
+        (i32.const 12)
+      )
+      (local.set $a
+        (i32.const 13)
+      )
+      (local.set $b
+        (i32.const 14)
+      )
+      (drop
+        (i32.load
+          (i32.const 24)
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+      (drop
+        (local.get $b)
+      )
+      (local.set $a
+        (i32.const 15)
+      )
+      (local.set $b
+        (i32.const 16)
+      )
+      (local.set $a
+        (i32.const 17)
+      )
+      (local.set $b
+        (i32.const 18)
+      )
+      (i32.store
+        (i32.const 48)
+        (i32.const 96)
+      )
+      (drop
+        (local.get $a)
+      )
+      (drop
+        (local.get $b)
+      )
+    )
+    (block $block3
+      (local.set $a
+        (call $waka_int)
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (call $waka_int)
+      )
+      (call $waka)
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (call $waka_int)
+      )
+      (drop
+        (i32.load
+          (i32.const 1)
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (call $waka_int)
+      )
+      (i32.store
+        (i32.const 1)
+        (i32.const 2)
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (i32.load
+          (i32.const 100)
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (i32.load
+          (i32.const 101)
+        )
+      )
+      (drop
+        (i32.load
+          (i32.const 1)
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (i32.load
+          (i32.const 102)
+        )
+      )
+      (call $waka)
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (i32.load
+          (i32.const 103)
+        )
+      )
+      (i32.store
+        (i32.const 1)
+        (i32.const 2)
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (block (result i32)
+          (block
+            (local.set $5
+              (i32.const 105)
+            )
+            (i32.store
+              (i32.const 104)
+              (local.get $5)
+            )
+          )
+          (local.get $5)
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (block (result i32)
+          (block
+            (local.set $6
+              (i32.const 107)
+            )
+            (i32.store
+              (i32.const 106)
+              (local.get $6)
+            )
+          )
+          (local.get $6)
+        )
+      )
+      (call $waka)
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (block (result i32)
+          (block
+            (local.set $7
+              (i32.const 109)
+            )
+            (i32.store
+              (i32.const 108)
+              (local.get $7)
+            )
+          )
+          (local.get $7)
+        )
+      )
+      (drop
+        (i32.load
+          (i32.const 1)
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (block (result i32)
+          (block
+            (local.set $8
+              (i32.const 111)
+            )
+            (i32.store
+              (i32.const 110)
+              (local.get $8)
+            )
+          )
+          (local.get $8)
+        )
+      )
+      (i32.store
+        (i32.const 1)
+        (i32.const 2)
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+    )
+    (block $out-of-block
+      (local.set $a
+        (i32.const 1337)
+      )
+      (block $b
+        (block $c
+          (br $b)
+        )
+        (local.set $a
+          (i32.const 9876)
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+    )
+    (block $loopey
+      (local.set $a
+        (i32.const 1337)
+      )
+      (drop
+        (loop $loop-in5 (result i32)
+          (drop
+            (local.get $a)
+          )
+          (local.tee $a
+            (i32.const 9876)
+          )
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+    )
+  )
+  (func $Ia (type $5) (param $a i32) (result i32)
+    (local $b i32)
+    (block $switch$0
+      (block $switch-default$6
+        (local.set $b
+          (i32.const 60)
+        )
+      )
+    )
+    (return
+      (local.get $b)
+    )
+  )
+  (func $memories (type $6) (param $i2 i32) (param $i3 i32) (param $bi2 i32) (param $bi3 i32) (param $ci3 i32) (param $di3 i32)
+    (local $set_with_no_get i32)
+    (local.set $i3
+      (i32.const 1)
+    )
+    (i32.store8
+      (local.get $i2)
+      (local.get $i3)
+    )
+    (local.set $bi3
+      (i32.const 1)
+    )
+    (i32.store8
+      (local.get $bi3)
+      (local.get $bi3)
+    )
+    (local.set $ci3
+      (local.get $bi3)
+    )
+    (i32.store8
+      (local.get $bi3)
+      (local.get $ci3)
+    )
+    (local.set $di3
+      (local.tee $bi3
+        (i32.const 123)
+      )
+    )
+    (i32.store8
+      (local.get $bi3)
+      (local.get $di3)
+    )
+    (local.set $set_with_no_get
+      (i32.const 456)
+    )
+  )
+  (func $___remdi3 (type $FUNCSIG$iiiii) (param $$a$0 i32) (param $$a$1 i32) (param $$b$0 i32) (param $$b$1 i32) (result i32)
+    (local $$1$1 i32)
+    (local $$1$0 i32)
+    (local $$rem i32)
+    (local $__stackBase__ i32)
+    (local $$2$1 i32)
+    (local $$2$0 i32)
+    (local $$4$1 i32)
+    (local $$4$0 i32)
+    (local $$10$1 i32)
+    (local $$10$0 i32)
+    (local $$6$0 i32)
+    (local.set $__stackBase__
+      (i32.load
+        (i32.const 8)
+      )
+    )
+    (i32.store
+      (i32.const 8)
+      (i32.add
+        (i32.load
+          (i32.const 8)
+        )
+        (i32.const 16)
+      )
+    )
+    (local.set $$rem
+      (local.get $__stackBase__)
+    )
+    (local.set $$1$0
+      (i32.or
+        (i32.shr_s
+          (local.get $$a$1)
+          (i32.const 31)
+        )
+        (i32.shl
+          (if (result i32)
+            (i32.lt_s
+              (local.get $$a$1)
+              (i32.const 0)
+            )
+            (i32.const -1)
+            (i32.const 0)
+          )
+          (i32.const 1)
+        )
+      )
+    )
+    (local.set $$1$1
+      (i32.or
+        (i32.shr_s
+          (if (result i32)
+            (i32.lt_s
+              (local.get $$a$1)
+              (i32.const 0)
+            )
+            (i32.const -1)
+            (i32.const 0)
+          )
+          (i32.const 31)
+        )
+        (i32.shl
+          (if (result i32)
+            (i32.lt_s
+              (local.get $$a$1)
+              (i32.const 0)
+            )
+            (i32.const -1)
+            (i32.const 0)
+          )
+          (i32.const 1)
+        )
+      )
+    )
+    (local.set $$2$0
+      (i32.or
+        (i32.shr_s
+          (local.get $$b$1)
+          (i32.const 31)
+        )
+        (i32.shl
+          (if (result i32)
+            (i32.lt_s
+              (local.get $$b$1)
+              (i32.const 0)
+            )
+            (i32.const -1)
+            (i32.const 0)
+          )
+          (i32.const 1)
+        )
+      )
+    )
+    (local.set $$2$1
+      (i32.or
+        (i32.shr_s
+          (if (result i32)
+            (i32.lt_s
+              (local.get $$b$1)
+              (i32.const 0)
+            )
+            (i32.const -1)
+            (i32.const 0)
+          )
+          (i32.const 31)
+        )
+        (i32.shl
+          (if (result i32)
+            (i32.lt_s
+              (local.get $$b$1)
+              (i32.const 0)
+            )
+            (i32.const -1)
+            (i32.const 0)
+          )
+          (i32.const 1)
+        )
+      )
+    )
+    (local.set $$4$0
+      (call $_i64Subtract
+        (i32.xor
+          (local.get $$1$0)
+          (local.get $$a$0)
+        )
+        (i32.xor
+          (local.get $$1$1)
+          (local.get $$a$1)
+        )
+        (local.get $$1$0)
+        (local.get $$1$1)
+      )
+    )
+    (local.set $$4$1
+      (i32.load
+        (i32.const 168)
+      )
+    )
+    (drop
+      (call $___udivmoddi4
+        (local.get $$4$0)
+        (local.get $$4$1)
+        (call $_i64Subtract
+          (i32.xor
+            (local.get $$2$0)
+            (local.get $$b$0)
+          )
+          (i32.xor
+            (local.get $$2$1)
+            (local.get $$b$1)
+          )
+          (local.get $$2$0)
+          (local.get $$2$1)
+        )
+        (i32.load
+          (i32.const 168)
+        )
+        (local.get $$rem)
+      )
+    )
+    (local.set $$10$0
+      (call $_i64Subtract
+        (i32.xor
+          (i32.load
+            (local.get $$rem)
+          )
+          (local.get $$1$0)
+        )
+        (i32.xor
+          (i32.load offset=4
+            (local.get $$rem)
+          )
+          (local.get $$1$1)
+        )
+        (local.get $$1$0)
+        (local.get $$1$1)
+      )
+    )
+    (local.set $$10$1
+      (i32.load
+        (i32.const 168)
+      )
+    )
+    (i32.store
+      (i32.const 8)
+      (local.get $__stackBase__)
+    )
+    (return
+      (block $block12 (result i32)
+        (i32.store
+          (i32.const 168)
+          (local.get $$10$1)
+        )
+        (local.get $$10$0)
+      )
+    )
+  )
+  (func $block-returns (type $FUNCSIG$v)
+    (local $x i32)
+    (block $out
+      (block $waka
+        (local.set $x
+          (i32.const 12)
+        )
+        (br_if $waka
+          (i32.const 1)
+        )
+        (local.set $x
+          (i32.const 34)
+        )
+      )
+      (br_if $out
+        (i32.const 1)
+      )
+      (drop
+        (local.get $x)
+      )
+      (block $waka2
+        (if
+          (i32.const 1)
+          (local.set $x
+            (i32.const 13)
+          )
+          (local.set $x
+            (i32.const 24)
+          )
+        )
+        (if
+          (i32.const 1)
+          (block $block3
+            (local.set $x
+              (i32.const 14)
+            )
+          )
+          (block $block5
+            (local.set $x
+              (i32.const 25)
+            )
+          )
+        )
+      )
+      (br_if $out
+        (i32.const 1)
+      )
+      (block $sink-out-of-me-i-have-but-one-exit
+        (local.set $x
+          (i32.const 99)
+        )
+      )
+      (drop
+        (local.get $x)
+      )
+    )
+  )
+  (func $multiple (type $6) (param $s i32) (param $r i32) (param $f i32) (param $p i32) (param $t i32) (param $m i32)
+    (local.set $s
+      (local.get $m)
+    )
+    (local.set $r
+      (i32.add
+        (local.get $f)
+        (local.get $p)
+      )
+    )
+    (local.set $t
+      (local.get $p)
+    )
+    (local.set $p
+      (i32.load
+        (i32.const 0)
+      )
+    )
+    (i32.store
+      (local.get $r)
+      (local.get $t)
+    )
+    (drop
+      (local.get $s)
+    )
+    (drop
+      (local.get $t)
+    )
+  )
+  (func $switch-def (type $5) (param $i3 i32) (result i32)
+    (local $i1 i32)
+    (local.set $i1
+      (i32.const 10)
+    )
+    (block $switch$def
+      (block $switch-case$1
+        (br_table $switch-case$1 $switch$def
+          (local.get $i3)
+        )
+      )
+      (local.set $i1
+        (i32.const 1)
+      )
+    )
+    (return
+      (local.get $i1)
+    )
+  )
+  (func $no-out-of-label (param $x i32) (param $y i32)
+    (loop $moar
+      (local.set $x
+        (block (result i32)
+          (br_if $moar (local.get $x))
+          (i32.const 0)
+        )
+      )
+    )
+    (drop (local.get $x))
+    (block $moar
+      (local.set $y
+        (block (result i32)
+          (br_if $moar (local.get $y))
+          (i32.const 0)
+        )
+      )
+    )
+    (drop (local.get $y))
+  )
+  (func $freetype-cd (param $a i32) (result i32)
+    (local $e i32)
+    (loop $while-in$1
+      (block $while-out$0
+        (local.set $e
+          (local.get $a)
+        )
+        (local.set $a ;; this set must happen, so that if the br_if does not break, we have the right $a later down - once we use a block return value, the $a set's outside the block
+          (i32.const 4)
+        )
+        (br_if $while-out$0
+          (local.get $e)
+        )
+        (local.set $a
+          (i32.add
+            (local.get $a)
+            (i32.const 0)
+          )
+        )
+      )
+    )
+    (local.get $a)
+  )
+  (func $drop-if-value (param $x i32) (param $y i32) (param $z i32) (result i32)
+    (local $temp i32)
+    (drop
+      (if (result i32)
+        (local.get $x)
+        (block $block53 (result i32)
+          (nop)
+          (local.set $temp
+            (local.get $y)
+          )
+          (local.get $z)
+        )
+        (block $block54 (result i32)
+          (nop)
+          (local.set $temp
+            (local.get $y)
+          )
+          (local.get $z)
+        )
+      )
+    )
+    (drop (local.get $temp))
+    (return
+      (i32.const 0)
+    )
+  )
+  (func $drop-br_if (param $label i32) (param $$cond2 i32) (param $$$0151 i32) (result i32)
+    (block $label$break$L4
+      (if
+        (i32.eq
+          (local.get $label)
+          (i32.const 15)
+        )
+        (block $block
+          (local.set $label
+            (i32.const 0)
+          )
+          (local.set $$cond2
+            (i32.eq
+              (local.get $$$0151)
+              (i32.const 0)
+            )
+          )
+          (br_if $label$break$L4 ;; when we add a value to this, its type changes as it returns the value too, so must be dropped
+            (i32.eqz
+              (local.get $$cond2)
+            )
+          )
+        )
+      )
+      (local.set $label
+        (i32.const 1)
+      )
+    )
+    (local.get $label)
+  )
+  (func $drop-tee-unreachable
+    (local $x i32)
+    (drop
+      (local.tee $x
+        (unreachable)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+  )
+  (func $if-return-but-unreachable (param $var$0 i64)
+   (if
+    (unreachable)
+    (local.set $var$0
+     (local.get $var$0)
+    )
+    (local.set $var$0
+     (i64.const 1)
+    )
+   )
+  )
+  (func $if-one-side (result i32)
+   (local $x i32)
+   (if
+    (i32.const 1)
+    (local.set $x
+     (i32.const 2)
+    )
+   )
+   (local.get  $x)
+  )
+  (func $if-one-side-undo (result i32)
+   (local $x i32)
+   (local $y i32)
+   (local.set $y
+    (i32.const 0)
+   )
+   (if
+    (i32.const 1)
+    (local.set $x
+     (i32.const 2)
+    )
+   )
+   (local.get  $y)
+  )
+  (func $if-one-side-multi (param $0 i32) (result i32)
+   (if
+    (i32.lt_s
+     (local.get $0)
+     (i32.const -1073741824)
+    )
+    (local.set $0
+     (i32.const -1073741824)
+    )
+    (if
+     (i32.gt_s
+      (local.get $0)
+      (i32.const 1073741823)
+     )
+     (local.set $0
+      (i32.const 1073741823)
+     )
+    )
+   )
+   (local.get $0)
+  )
+  (func $if-one-side-undo-but-its-a-tee (param $0 i32) (result i32)
+   (local $1 i32)
+   (local $2 i32)
+   (local $3 i32)
+   (local $4 i32)
+   (local $x i32)
+   (local $y i32)
+   (local $z i32)
+   ;; break these splittable ifs up
+   (local.set $x
+     (if (result i32)
+       (i32.const -1)
+       (i32.const -2)
+       (local.get $x)
+     )
+   )
+   ;; oops, this one is a tee
+   (drop
+    (call $if-one-side-undo-but-its-a-tee
+     (local.tee $x
+       (if (result i32)
+         (i32.const -3)
+         (i32.const -4)
+         (local.get $x)
+       )
+     )
+    )
+   )
+   ;; sinkable
+   (local.set $y
+     (if (result i32)
+       (i32.const -5)
+       (i32.const -6)
+       (local.get $y)
+     )
+   )
+   (drop (i32.eqz (local.get $y)))
+   ;; tee-able at best
+   (local.set $z
+     (if (result i32)
+       (i32.const -7)
+       (i32.const -8)
+       (local.get $z)
+     )
+   )
+   (drop
+    (i32.add
+     (local.get $z)
+     (local.get $z)
+    )
+   )
+   (if
+    (block $label$1 (result i32)
+     (if
+      (i32.const 1)
+      (local.set $4
+       (i32.const 2)
+      )
+     )
+     (if
+      (local.get $4)
+      (local.set $4
+       (i32.const 0)
+      )
+     )
+     (local.get $4)
+    )
+    (unreachable)
+   )
+   (i32.const 0)
+  )
+  (func $splittable-ifs-multicycle (param $20 i32) (result i32)
+   (local.set $20
+    (if (result i32)
+     (i32.const 1)
+     (if (result i32)
+      (i32.const 2)
+      (if (result i32)
+       (i32.const 3)
+       (i32.const 4)
+       (local.get $20)
+      )
+      (local.get $20)
+     )
+     (local.get $20)
+    )
+   )
+   (local.get $20)
+  )
+  (func $update-getCounter (param $0 i32) (param $1 f64) (param $2 f64) (param $3 f32) (param $4 i32) (result f64)
+   (global.set $global$0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 1)
+    )
+   )
+   (global.set $global$0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 1)
+    )
+   )
+   (loop $label$1 (result f64)
+    (global.set $global$0
+     (i32.sub
+      (global.get $global$0)
+      (i32.const 1)
+     )
+    )
+    (global.set $global$0
+     (i32.sub
+      (global.get $global$0)
+      (i32.const 1)
+     )
+    )
+    (call $fimport$0
+     (local.tee $3
+      (if (result f32)
+       (i32.eqz
+        (local.get $0)
+       )
+       (f32.const 4623408228068004207103214e13)
+       (local.get $3)
+      )
+     )
+    )
+    (global.set $global$0
+     (i32.sub
+      (global.get $global$0)
+      (i32.const 1)
+     )
+    )
+    (if (result f64)
+     (global.get $global$0)
+     (block
+      (global.set $global$0
+       (i32.sub
+        (global.get $global$0)
+        (i32.const 1)
+       )
+      )
+      (local.set $0
+       (i32.const -65)
+      )
+      (global.set $global$0
+       (i32.sub
+        (global.get $global$0)
+        (i32.const 1)
+       )
+      )
+      (br $label$1)
+     )
+     (f64.const -70)
+    )
+   )
+  )
+)
+(module
+  (memory (shared 256 256))
+  (type $FUNCSIG$v (func))
+  (type $FUNCSIG$i (func (result i32)))
+  (type $FUNCSIG$iiiii (func (param i32 i32 i32 i32) (result i32)))
+  (type $FUNCSIG$iiiiii (func (param i32 i32 i32 i32 i32) (result i32)))
+  (type $4 (func (param i32)))
+  (type $5 (func (param i32) (result i32)))
+  (type $6 (func (param i32 i32 i32 i32 i32 i32)))
+  (import "fuzzing-support" "log1" (func $fimport$0 (result i32)))
+  (import "fuzzing-support" "log2" (func $fimport$1 (param i32)))
+  (import "fuzzing-support" "log3" (func $fimport$2 (param f32)))
+  (global $global$0 (mut i32) (i32.const 10))
+  (func $nonatomics (result i32) ;; loads are reordered
+    (local $x i32)
+    (local.set $x (i32.load (i32.const 1024)))
+    (drop (i32.load (i32.const 1028)))
+    (local.get $x)
+  )
+  (func $nonatomic-growmem (result i32) ;; memory.grow is modeled as modifying memory
+    (local $x i32)
+    (local.set $x (i32.load (memory.grow (i32.const 1))))
+    (drop (i32.load (i32.const 1028)))
+    (local.get $x)
+  )
+  (func $atomics ;; atomic loads don't pass each other
+    (local $x i32)
+    (local.set $x (i32.atomic.load (i32.const 1024)))
+    (drop (i32.atomic.load (i32.const 1028)))
+    (drop (local.get $x))
+  )
+  (func $one-atomic ;; atomic loads don't pass other loads
+    (local $x i32)
+    (local.set $x (i32.load (i32.const 1024)))
+    (drop (i32.atomic.load (i32.const 1028)))
+    (drop (local.get $x))
+  )
+  (func $other-atomic ;; atomic loads don't pass other loads
+    (local $x i32)
+    (local.set $x (i32.atomic.load (i32.const 1024)))
+    (drop (i32.load (i32.const 1028)))
+    (drop (local.get $x))
+  )
+  (func $atomic-growmem (result i32) ;; memory.grow is modeled as modifying memory
+    (local $x i32)
+    (local.set $x (i32.load (memory.grow (i32.const 1))))
+    (drop (i32.atomic.load (i32.const 1028)))
+    (local.get $x)
+  )
+  (func $atomicrmw ;; atomic rmw don't pass loads
+    (local $x i32)
+    (local.set $x (i32.atomic.rmw.add (i32.const 1024) (i32.const 1)))
+    (drop (i32.atomic.load (i32.const 1028)))
+    (drop (local.get $x))
+  )
+  (func $atomic-cmpxchg ;; cmpxchg don't pass loads
+    (local $x i32)
+    (local.set $x (i32.atomic.rmw.cmpxchg (i32.const 1024) (i32.const 1) (i32.const 2)))
+    (drop (i32.atomic.load (i32.const 1028)))
+    (drop (local.get $x))
+  )
+  (func $br-value-reordering (result i32)
+   (local $temp i32)
+   (block $outside
+    (loop $loop ;; we should exit this loop, hit the unreachable outside
+     ;; loop logic
+     (br_if $outside ;; we should not create a block value that adds a value to a br, if the value&condition of the br cannot be reordered,
+                     ;; as the value comes first
+      (block (result i32)
+       (br_if $loop
+        (local.get $temp) ;; false, don't loop
+       )
+       (unreachable) ;; the end
+       (local.set $temp
+        (i32.const -1)
+       )
+       (i32.const 0)
+      )
+     )
+    )
+    (local.set $temp
+     (i32.const -1)
+    )
+   )
+   (unreachable)
+  )
+  (func $br-value-reordering-safe (result i32)
+   (local $temp i32)
+   (block $outside
+    (loop $loop ;; we should exit this loop, hit the unreachable outside
+     ;; loop logic
+     (drop (local.get $temp)) ;; different from above - add a use here
+     (br_if $outside ;; we should not create a block value that adds a value to a br, if the value&condition of the br cannot be reordered,
+                     ;; as the value comes first
+      (block (result i32)
+       (local.set $temp ;; the use *is* in the condition, but it's ok, no conflicts
+        (i32.const -1)
+       )
+       (i32.const 0)
+      )
+     )
+    )
+    (local.set $temp
+     (i32.const -1)
+    )
+   )
+   (unreachable)
+  )
+  (func $if-one-side-unreachable
+   (local $x i32)
+   (block $out
+    (if
+     (i32.const 1)
+     (br $out)
+     (local.set $x
+      (i32.const 2)
+     )
+    )
+    (if
+     (i32.const 3)
+     (local.set $x
+      (i32.const 4)
+     )
+     (br $out)
+    )
+    (if
+     (i32.const 5)
+     (br $out)
+     (br $out)
+    )
+   )
+  )
+  (func $if-one-side-unreachable-blocks
+   (local $x i32)
+   (local $y i32)
+   (block $out
+    (if
+     (i32.const 1)
+     (block
+      (local.set $x
+       (i32.const 2)
+      )
+      (local.set $y
+       (i32.const 3)
+      )
+      (br $out)
+     )
+     (block
+      (local.set $x
+       (i32.const 4)
+      )
+      (local.set $y
+       (i32.const 5)
+      )
+     )
+    )
+    (if
+     (i32.const 6)
+     (block
+      (local.set $x
+       (i32.const 7)
+      )
+      (local.set $y
+       (i32.const 8)
+      )
+     )
+     (block
+      (local.set $x
+       (i32.const 9)
+      )
+      (local.set $y
+       (i32.const 10)
+      )
+      (br $out)
+     )
+    )
+    (if
+     (i32.const 11)
+     (block
+      (local.set $x
+       (i32.const 12)
+      )
+      (local.set $y
+       (i32.const 13)
+      )
+      (br $out)
+     )
+     (block
+      (local.set $x
+       (i32.const 14)
+      )
+      (local.set $y
+       (i32.const 15)
+      )
+      (br $out)
+     )
+    )
+   )
+  )
+  (func $loop-value (param $x i32) (result i32)
+    (loop $loopy
+      (local.set $x (unreachable))
+    )
+    (loop $loopy
+      (local.set $x (i32.const 1))
+    )
+    (local.get $x)
+  )
+  (func $loop-loop-loopy-value (param $x i32) (result i32)
+    (loop $loopy1
+      (loop $loopy2
+        (loop $loopy3
+          (local.set $x (i32.const 1))
+        )
+      )
+    )
+    (local.get $x)
+  )
+  (func $loop-modified-during-main-pass-be-careful-fuzz (result i32)
+   (local $0 i32)
+   (if
+    (i32.const 0)
+    (local.set $0
+     (i32.const 0)
+    )
+    (loop $label$4
+     (br $label$4)
+    )
+   )
+   (local.get $0)
+  )
+  (func $loop-later (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (param $var$3 i32) (param $var$4 i32) (result i32)
+   (loop $label$1
+    (block $label$2
+     (if
+      (i32.const 0)
+      (block
+       (local.set $var$0
+        (i32.const -1)
+       )
+       (br $label$2)
+      )
+     )
+     (local.set $var$0
+      (i32.const -1)
+     )
+    )
+   )
+   (i32.const 0)
+  )
+  (func $pick
+   (local $x i32)
+   (local $y i32)
+   (local.set $x (local.get $y))
+   (if (i32.const 1)
+    (local.set $x (i32.const 1))
+   )
+   (local.set $x (local.get $y))
+   (local.set $x (local.get $y))
+  )
+  (func $pick-2
+   (local $x i32)
+   (local $y i32)
+   (local.set $y (local.get $x))
+   (if (i32.const 1)
+    (local.set $y (i32.const 1))
+   )
+   (local.set $y (local.get $x))
+   (local.set $y (local.get $x))
+  )
+  (func $many
+   (local $x i32)
+   (local $y i32)
+   (local $z i32)
+   (local $w i32)
+   (local.set $y (local.get $x))
+   (local.set $z (local.get $y))
+   (local.set $w (local.get $z))
+   (local.set $x (local.get $z))
+   (if (i32.const 1)
+    (local.set $y (i32.const 1))
+   )
+   (local.set $x (local.get $z))
+   (if (i32.const 1)
+    (local.set $y (i32.const 1))
+   )
+   (local.set $y (local.get $x))
+   (local.set $z (local.get $y))
+   (local.set $w (local.get $z))
+   (local.set $z (i32.const 2))
+   (local.set $x (local.get $z))
+   (if (i32.const 1)
+    (local.set $y (i32.const 1))
+   )
+   (local.set $y (local.get $x))
+   (local.set $z (local.get $y))
+   (local.set $w (local.get $z))
+   (local.set $z (i32.const 2))
+   (local.set $x (local.get $w))
+  )
+  (func $loop-copies (param $x i32) (param $y i32)
+   (loop $loop
+    (local.set $x (local.get $y))
+    (local.set $y (local.get $x))
+    (br_if $loop (local.get $x))
+   )
+  )
+  (func $proper-type (result f64)
+   (local $var$0 i32)
+   (local $var$2 f64)
+   (local.set $var$0
+    (select
+     (i32.const 0)
+     (i32.const 1)
+     (local.get $var$0)
+    )
+   )
+   (local.tee $var$2
+    (local.get $var$2)
+   )
+  )
+  (func $multi-pass-get-equivs-right (param $var$0 i32) (param $var$1 i32) (result f64)
+   (local $var$2 i32)
+   (local.set $var$2
+    (local.get $var$0)
+   )
+   (i32.store
+    (local.get $var$2)
+    (i32.const 1)
+   )
+   (f64.promote_f32
+    (f32.load
+     (local.get $var$2)
+    )
+   )
+  )
+  (func $if-value-structure-equivalent (param $x i32) (result i32)
+    (local $y i32)
+    (if (i32.const 1)
+      (local.set $x (i32.const 2))
+      (block
+        (local.set $y (local.get $x))
+        (local.set $x (local.get $y))
+      )
+    )
+    (local.get $x)
+  )
+  (func $set-tee-need-one-of-them (param $var$0 i32) (param $var$1 i32) (result i32)
+   (local $var$2 i32)
+   (local $var$3 i32)
+   (local.set $var$0 ;; this is redundant
+    (local.tee $var$2 ;; but this is not - we need this set, we read it at the end
+     (local.get $var$0)
+    )
+   )
+   (loop $loop
+    (br_if $loop
+     (local.get $var$1)
+    )
+   )
+   (local.get $var$2)
+  )
+  (func $loop-value-harder (result i32)
+   (local $0 i32)
+   (local $1 i32)
+   (local $2 i32)
+   (local $3 f32)
+   (local $4 f32)
+   (local $5 f32)
+   (local $6 f32)
+   (local $7 f32)
+   (local $8 f32)
+   (local $9 f32)
+   (local $10 f32)
+   (block $label$1
+    (loop $label$2
+     (block $label$3
+      (global.set $global$0
+       (i32.const -1)
+      )
+      (block $label$4
+       (local.set $0
+        (call $fimport$0)
+       )
+       (if
+        (local.get $0)
+        (local.set $5
+         (f32.const -2048)
+        )
+        (block
+         (call $fimport$1
+          (i32.const -25732)
+         )
+         (br $label$2)
+        )
+       )
+      )
+      (local.set $6
+       (local.get $5)
+      )
+      (local.set $7
+       (local.get $6)
+      )
+     )
+     (local.set $8
+      (local.get $7)
+     )
+     (local.set $9
+      (local.get $8)
+     )
+    )
+    (local.set $10
+     (local.get $9)
+    )
+    (call $fimport$2
+     (local.get $10)
+    )
+    (local.set $1
+     (i32.const -5417091)
+    )
+   )
+   (local.set $2
+    (local.get $1)
+   )
+   (return
+    (local.get $2)
+   )
+  )
+  (func $tee-chain
+    (param $x i32)
+    (param $z i32)
+    (param $t1 i32)
+    (param $t2 i32)
+    (param $t3 i32)
+    (result i32)
+    (local.set $x
+      (local.get $x)
+    )
+    (local.set $z
+      (local.tee $z
+        (i32.const 10)
+      )
+    )
+    (local.set $z
+      (local.tee $z
+        (i32.const 10)
+      )
+    )
+    (local.set $t1
+      (local.tee $t2
+        (local.tee $t3
+          (local.tee $t1
+            (call $tee-chain (local.get $x) (local.get $z) (local.get $t1) (local.get $t2) (local.get $t3))
+          )
+        )
+      )
+    )
+    (call $tee-chain (local.get $x) (local.get $z) (local.get $t1) (local.get $t2) (local.get $t3))
+  )
+)
+(module
+ (memory 256 256)
+ (data passive "hello, there!")
+ (func $memory-init-load
+  (local $x i32)
+  (local.set $x
+   (i32.load (i32.const 0))
+  )
+  (memory.init 0 (i32.const 0) (i32.const 0) (i32.const 5))
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-init-store
+  (local $x i32)
+  (local.set $x
+   (block i32
+    (i32.store (i32.const 0) (i32.const 42))
+    (i32.const 0)
+   )
+  )
+  (memory.init 0 (i32.const 0) (i32.const 0) (i32.const 5))
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-copy-load
+  (local $x i32)
+  (local.set $x
+   (i32.load (i32.const 0))
+  )
+  (memory.copy (i32.const 0) (i32.const 8) (i32.const 8))
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-copy-store
+  (local $x i32)
+  (local.set $x
+   (block i32
+    (i32.store (i32.const 0) (i32.const 42))
+    (i32.const 0)
+   )
+  )
+  (memory.copy (i32.const 0) (i32.const 8) (i32.const 8))
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-fill-load
+  (local $x i32)
+  (local.set $x
+   (i32.load (i32.const 0))
+  )
+  (memory.fill (i32.const 0) (i32.const 42) (i32.const 8))
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-fill-store
+  (local $x i32)
+  (local.set $x
+   (block i32
+    (i32.store (i32.const 0) (i32.const 42))
+    (i32.const 0)
+   )
+  )
+  (memory.fill (i32.const 0) (i32.const 8) (i32.const 8))
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $data-drop-load
+  (local $x i32)
+  (local.set $x
+   (i32.load (i32.const 0))
+  )
+  (data.drop 0)
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $data-drop-store
+  (local $x i32)
+  (local.set $x
+   (block i32
+    (i32.store (i32.const 0) (i32.const 42))
+    (i32.const 0)
+   )
+  )
+  (data.drop 0)
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $data-drop-memory-init
+  (local $x i32)
+  (local.set $x
+   (block i32
+    (memory.init 0 (i32.const 0) (i32.const 0) (i32.const 5))
+    (i32.const 0)
+   )
+  )
+  (data.drop 0)
+  (drop
+   (local.get $x)
+  )
+ )
+)
+(module
+ (func $subtype-test (result anyref)
+  (local $0 externref)
+  (local $1 anyref)
+  (local $2 anyref)
+  (block
+   (local.set $1
+    (local.get $0)
+   )
+  )
+  (local.set $2
+   (local.get $1)
+  )
+  (local.get $1)
+ )
+)
+(module
+  (event $event$0 (attr 0) (param))
+  (func $unoptimizable-br_on_exn-block (result exnref) (local $0 exnref)
+    (block $label$0
+      (local.set $0
+        ;; br_on_exn's target block cannot be optimized to have a return value
+        (br_on_exn $label$0 $event$0
+          (ref.null exn)
+        )
+      )
+    )
+    (local.get $0)
+  )
+
+  (event $event$1 (attr 0) (param exnref))
+  (func $br_on_exn-trap (local $0 exnref)
+    ;; This dead local.set cannot be replaced with a nop because br_on_exn can
+    ;; trap.
+    (local.set $0
+      (block $label$1 (result exnref)
+        (br_on_exn $label$1 $event$1
+          (ref.null exn)
+        )
+      )
+    )
+  )
+
+  (func $rethrow-trap (local $0 i32)
+    ;; This dead local.set cannot be replaced with a nop because rethrow can
+    ;; trap.
+    (local.set $0
+      (block $label$1 (result i32)
+        (try
+          (do (rethrow (ref.null exn)))
+          (catch)
+        )
+        (i32.const 0)
+      )
+    )
+  )
+
+  (func $foo (param i32 exnref))
+  (func $pop-cannot-be-sinked (local $0 exnref)
+    (try
+      (do)
+      (catch
+        ;; This (local.set $0) of (pop exnref) cannot be sinked to
+        ;; (local.get $0) below, because pop exnref should follow right after
+        ;; 'catch'.
+        (local.set $0 (pop exnref))
+        (call $foo
+          (i32.const 3)
+          (local.get $0)
+        )
+      )
+    )
+  )
+
+  (func $pop-within-catch-can-be-sinked (local $0 exnref)
+    (try
+      (do)
+      (catch
+        ;; This whole 'try' body can be sinked to eliminate local.set /
+        ;; local.get. Even though it contains a pop, it is enclosed within
+        ;; try-catch, so it is OK.
+        (local.set $0
+          (try (result exnref)
+            (do (ref.null exn))
+            (catch (pop exnref))
+          )
+        )
+        (call $foo
+          (i32.const 3)
+          (local.get $0)
+        )
+      )
+    )
+  )
+
+  (func $bar (result i32) (i32.const 3))
+  (func $call-cannot-be-sinked-into-try (local $0 i32)
+    (drop
+      ;; This local.tee should NOT be sinked into 'try' below, because it may
+      ;; throw
+      (local.tee $0 (call $bar))
+    )
+    (try
+      (do
+        (drop (local.get $0))
+      )
+      (catch
+        (drop (pop exnref))
+      )
+    )
+  )
+
+  (func $non-call-can-be-sinked-into-try (local $0 i32)
+    (drop
+      ;; This local.tee can be sinked into 'try' below, because it cannot throw
+      (local.tee $0 (i32.const 3))
+    )
+    (try
+      (do
+        (drop (local.get $0))
+      )
+      (catch
+        (drop (pop exnref))
+      )
+    )
+  )
+)
+;; data.drop has global side effects
+(module
+ (memory $0 (shared 1 1))
+ (data passive "data")
+ (func "foo" (result i32)
+  (local $0 i32)
+  (block (result i32)
+   (local.set $0
+    (i32.rem_u     ;; will trap, so cannot be reordered to the end
+     (i32.const 0)
+     (i32.const 0)
+    )
+   )
+   (data.drop 0)   ;; has global side effects that may be noticed later
+   (local.get $0)
+  )
+ )
+)
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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-locals_all-features_disable-exception-handling.txt
@@ -0,0 +1,1890 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i32_i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32 i32 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)))
+ (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_=>_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)))
+ (import "env" "waka" (func $waka))
+ (import "env" "waka_int" (func $waka_int (result i32)))
+ (import "env" "i64sub" (func $_i64Subtract (param i32 i32 i32 i32) (result i32)))
+ (import "env" "moddi" (func $___udivmoddi4 (param i32 i32 i32 i32 i32) (result i32)))
+ (import "env" "lp" (func $lp (param i32 i32) (result i32)))
+ (import "fuzzing-support" "log-f32" (func $fimport$0 (param f32)))
+ (memory $0 256 256)
+ (global $global$0 (mut i32) (i32.const 10))
+ (func $contrast
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (local $a i32)
+  (local $b i32)
+  (nop)
+  (if
+   (local.tee $x
+    (i32.const 1)
+   )
+   (nop)
+  )
+  (if
+   (local.get $x)
+   (nop)
+  )
+  (nop)
+  (drop
+   (if (result i32)
+    (i32.const 2)
+    (i32.const 3)
+    (i32.const 4)
+   )
+  )
+  (nop)
+  (drop
+   (block $block (result i32)
+    (i32.const 5)
+   )
+  )
+  (nop)
+  (drop
+   (if (result i32)
+    (i32.const 6)
+    (block (result i32)
+     (nop)
+     (i32.const 7)
+    )
+    (block (result i32)
+     (nop)
+     (i32.const 8)
+    )
+   )
+  )
+  (nop)
+  (drop
+   (block $val (result i32)
+    (if
+     (i32.const 10)
+     (block $block4
+      (nop)
+      (br $val
+       (i32.const 11)
+      )
+     )
+    )
+    (nop)
+    (i32.const 12)
+   )
+  )
+ )
+ (func $b0-yes (param $i1 i32)
+  (local $x i32)
+  (local $y i32)
+  (local $a i32)
+  (local $b i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (nop)
+  (drop
+   (i32.const 5)
+  )
+  (block $block0
+   (nop)
+   (drop
+    (i32.const 7)
+   )
+  )
+  (nop)
+  (drop
+   (i32.const 11)
+  )
+  (drop
+   (i32.const 9)
+  )
+  (drop
+   (local.get $y)
+  )
+  (block $block1
+   (drop
+    (i32.const 8)
+   )
+   (drop
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.const 11)
+  )
+  (drop
+   (local.get $y)
+  )
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (block $block2
+   (nop)
+   (nop)
+   (drop
+    (i32.const 1)
+   )
+   (drop
+    (i32.const 2)
+   )
+   (drop
+    (i32.const 3)
+   )
+   (drop
+    (i32.const 4)
+   )
+   (nop)
+   (nop)
+   (drop
+    (i32.const 6)
+   )
+   (drop
+    (i32.const 5)
+   )
+   (drop
+    (i32.const 7)
+   )
+   (drop
+    (i32.const 8)
+   )
+   (nop)
+   (nop)
+   (call $waka)
+   (drop
+    (i32.const 9)
+   )
+   (drop
+    (i32.const 10)
+   )
+   (drop
+    (i32.const 11)
+   )
+   (drop
+    (i32.const 12)
+   )
+   (nop)
+   (nop)
+   (drop
+    (i32.load
+     (i32.const 24)
+    )
+   )
+   (drop
+    (i32.const 13)
+   )
+   (drop
+    (i32.const 14)
+   )
+   (drop
+    (i32.const 15)
+   )
+   (drop
+    (i32.const 16)
+   )
+   (nop)
+   (nop)
+   (i32.store
+    (i32.const 48)
+    (i32.const 96)
+   )
+   (drop
+    (i32.const 17)
+   )
+   (nop)
+  )
+  (block $block3
+   (nop)
+   (local.set $a
+    (call $waka_int)
+   )
+   (call $waka)
+   (local.set $a
+    (call $waka_int)
+   )
+   (call $waka)
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+   (local.set $a
+    (call $waka_int)
+   )
+   (drop
+    (i32.load
+     (i32.const 1)
+    )
+   )
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+   (local.set $a
+    (call $waka_int)
+   )
+   (i32.store
+    (i32.const 1)
+    (i32.const 2)
+   )
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+   (nop)
+   (local.set $a
+    (i32.load
+     (i32.const 100)
+    )
+   )
+   (call $waka)
+   (nop)
+   (drop
+    (i32.load
+     (i32.const 1)
+    )
+   )
+   (local.set $a
+    (i32.load
+     (i32.const 101)
+    )
+   )
+   (call $waka)
+   (local.set $a
+    (i32.load
+     (i32.const 102)
+    )
+   )
+   (call $waka)
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+   (local.set $a
+    (i32.load
+     (i32.const 103)
+    )
+   )
+   (i32.store
+    (i32.const 1)
+    (i32.const 2)
+   )
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+   (nop)
+   (local.set $a
+    (block $block (result i32)
+     (block $block5
+      (nop)
+      (i32.store
+       (i32.const 104)
+       (local.tee $5
+        (i32.const 105)
+       )
+      )
+     )
+     (local.get $5)
+    )
+   )
+   (call $waka)
+   (local.set $a
+    (block $block6 (result i32)
+     (block $block7
+      (nop)
+      (i32.store
+       (i32.const 106)
+       (local.tee $6
+        (i32.const 107)
+       )
+      )
+     )
+     (local.get $6)
+    )
+   )
+   (call $waka)
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+   (local.set $a
+    (block $block8 (result i32)
+     (block $block9
+      (nop)
+      (i32.store
+       (i32.const 108)
+       (local.tee $7
+        (i32.const 109)
+       )
+      )
+     )
+     (local.get $7)
+    )
+   )
+   (drop
+    (i32.load
+     (i32.const 1)
+    )
+   )
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+   (local.set $a
+    (block $block10 (result i32)
+     (block $block11
+      (nop)
+      (i32.store
+       (i32.const 110)
+       (local.tee $8
+        (i32.const 111)
+       )
+      )
+     )
+     (local.get $8)
+    )
+   )
+   (i32.store
+    (i32.const 1)
+    (i32.const 2)
+   )
+   (drop
+    (local.get $a)
+   )
+   (call $waka)
+  )
+  (block $out-of-block
+   (nop)
+   (nop)
+   (drop
+    (block $b (result i32)
+     (block $c
+      (br $b
+       (i32.const 1337)
+      )
+     )
+     (nop)
+     (i32.const 9876)
+    )
+   )
+  )
+  (block $loopey
+   (local.set $a
+    (i32.const 1337)
+   )
+   (drop
+    (loop $loop-in5 (result i32)
+     (drop
+      (local.get $a)
+     )
+     (local.tee $a
+      (i32.const 9876)
+     )
+    )
+   )
+   (drop
+    (local.get $a)
+   )
+  )
+ )
+ (func $Ia (param $a i32) (result i32)
+  (local $b i32)
+  (block $switch$0
+   (block $switch-default$6
+    (nop)
+   )
+  )
+  (return
+   (i32.const 60)
+  )
+ )
+ (func $memories (param $i2 i32) (param $i3 i32) (param $bi2 i32) (param $bi3 i32) (param $ci3 i32) (param $di3 i32)
+  (local $set_with_no_get i32)
+  (nop)
+  (i32.store8
+   (local.get $i2)
+   (i32.const 1)
+  )
+  (nop)
+  (i32.store8
+   (local.tee $bi3
+    (i32.const 1)
+   )
+   (local.get $bi3)
+  )
+  (nop)
+  (i32.store8
+   (local.get $bi3)
+   (local.get $bi3)
+  )
+  (local.set $di3
+   (local.tee $bi3
+    (i32.const 123)
+   )
+  )
+  (i32.store8
+   (local.get $bi3)
+   (local.get $di3)
+  )
+  (nop)
+ )
+ (func $___remdi3 (param $$a$0 i32) (param $$a$1 i32) (param $$b$0 i32) (param $$b$1 i32) (result i32)
+  (local $$1$1 i32)
+  (local $$1$0 i32)
+  (local $$rem i32)
+  (local $__stackBase__ i32)
+  (local $$2$1 i32)
+  (local $$2$0 i32)
+  (local $$4$1 i32)
+  (local $$4$0 i32)
+  (local $$10$1 i32)
+  (local $$10$0 i32)
+  (local $$6$0 i32)
+  (local.set $__stackBase__
+   (i32.load
+    (i32.const 8)
+   )
+  )
+  (i32.store
+   (i32.const 8)
+   (i32.add
+    (i32.load
+     (i32.const 8)
+    )
+    (i32.const 16)
+   )
+  )
+  (local.set $$rem
+   (local.get $__stackBase__)
+  )
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (nop)
+  (drop
+   (call $___udivmoddi4
+    (call $_i64Subtract
+     (i32.xor
+      (local.tee $$1$0
+       (i32.or
+        (i32.shr_s
+         (local.get $$a$1)
+         (i32.const 31)
+        )
+        (i32.shl
+         (if (result i32)
+          (i32.lt_s
+           (local.get $$a$1)
+           (i32.const 0)
+          )
+          (i32.const -1)
+          (i32.const 0)
+         )
+         (i32.const 1)
+        )
+       )
+      )
+      (local.get $$a$0)
+     )
+     (i32.xor
+      (local.tee $$1$1
+       (i32.or
+        (i32.shr_s
+         (if (result i32)
+          (i32.lt_s
+           (local.get $$a$1)
+           (i32.const 0)
+          )
+          (i32.const -1)
+          (i32.const 0)
+         )
+         (i32.const 31)
+        )
+        (i32.shl
+         (if (result i32)
+          (i32.lt_s
+           (local.get $$a$1)
+           (i32.const 0)
+          )
+          (i32.const -1)
+          (i32.const 0)
+         )
+         (i32.const 1)
+        )
+       )
+      )
+      (local.get $$a$1)
+     )
+     (local.get $$1$0)
+     (local.get $$1$1)
+    )
+    (i32.load
+     (i32.const 168)
+    )
+    (call $_i64Subtract
+     (i32.xor
+      (local.tee $$2$0
+       (i32.or
+        (i32.shr_s
+         (local.get $$b$1)
+         (i32.const 31)
+        )
+        (i32.shl
+         (if (result i32)
+          (i32.lt_s
+           (local.get $$b$1)
+           (i32.const 0)
+          )
+          (i32.const -1)
+          (i32.const 0)
+         )
+         (i32.const 1)
+        )
+       )
+      )
+      (local.get $$b$0)
+     )
+     (i32.xor
+      (local.tee $$2$1
+       (i32.or
+        (i32.shr_s
+         (if (result i32)
+          (i32.lt_s
+           (local.get $$b$1)
+           (i32.const 0)
+          )
+          (i32.const -1)
+          (i32.const 0)
+         )
+         (i32.const 31)
+        )
+        (i32.shl
+         (if (result i32)
+          (i32.lt_s
+           (local.get $$b$1)
+           (i32.const 0)
+          )
+          (i32.const -1)
+          (i32.const 0)
+         )
+         (i32.const 1)
+        )
+       )
+      )
+      (local.get $$b$1)
+     )
+     (local.get $$2$0)
+     (local.get $$2$1)
+    )
+    (i32.load
+     (i32.const 168)
+    )
+    (local.get $$rem)
+   )
+  )
+  (local.set $$10$0
+   (call $_i64Subtract
+    (i32.xor
+     (i32.load
+      (local.get $$rem)
+     )
+     (local.get $$1$0)
+    )
+    (i32.xor
+     (i32.load offset=4
+      (local.get $$rem)
+     )
+     (local.get $$1$1)
+    )
+    (local.get $$1$0)
+    (local.get $$1$1)
+   )
+  )
+  (local.set $$10$1
+   (i32.load
+    (i32.const 168)
+   )
+  )
+  (i32.store
+   (i32.const 8)
+   (local.get $__stackBase__)
+  )
+  (return
+   (block $block12 (result i32)
+    (i32.store
+     (i32.const 168)
+     (local.get $$10$1)
+    )
+    (local.get $$10$0)
+   )
+  )
+ )
+ (func $block-returns
+  (local $x i32)
+  (local.set $x
+   (block $out (result i32)
+    (nop)
+    (drop
+     (br_if $out
+      (local.tee $x
+       (block $waka (result i32)
+        (nop)
+        (drop
+         (br_if $waka
+          (local.tee $x
+           (i32.const 12)
+          )
+          (i32.const 1)
+         )
+        )
+        (nop)
+        (i32.const 34)
+       )
+      )
+      (i32.const 1)
+     )
+    )
+    (drop
+     (local.get $x)
+    )
+    (block $waka2
+     (local.set $x
+      (if (result i32)
+       (i32.const 1)
+       (block (result i32)
+        (nop)
+        (i32.const 13)
+       )
+       (block (result i32)
+        (nop)
+        (i32.const 24)
+       )
+      )
+     )
+     (nop)
+    )
+    (drop
+     (br_if $out
+      (local.tee $x
+       (if (result i32)
+        (i32.const 1)
+        (block (result i32)
+         (block $block3
+          (nop)
+         )
+         (i32.const 14)
+        )
+        (block (result i32)
+         (block $block5
+          (nop)
+         )
+         (i32.const 25)
+        )
+       )
+      )
+      (i32.const 1)
+     )
+    )
+    (block $sink-out-of-me-i-have-but-one-exit
+     (nop)
+    )
+    (nop)
+    (i32.const 99)
+   )
+  )
+ )
+ (func $multiple (param $s i32) (param $r i32) (param $f i32) (param $p i32) (param $t i32) (param $m i32)
+  (nop)
+  (local.set $r
+   (i32.add
+    (local.get $f)
+    (local.get $p)
+   )
+  )
+  (local.set $t
+   (local.get $p)
+  )
+  (local.set $p
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (i32.store
+   (local.get $r)
+   (local.get $t)
+  )
+  (drop
+   (local.get $m)
+  )
+  (drop
+   (local.get $t)
+  )
+ )
+ (func $switch-def (param $i3 i32) (result i32)
+  (local $i1 i32)
+  (local.set $i1
+   (i32.const 10)
+  )
+  (block $switch$def
+   (block $switch-case$1
+    (br_table $switch-case$1 $switch$def
+     (local.get $i3)
+    )
+   )
+   (local.set $i1
+    (i32.const 1)
+   )
+  )
+  (return
+   (local.get $i1)
+  )
+ )
+ (func $no-out-of-label (param $x i32) (param $y i32)
+  (nop)
+  (local.set $x
+   (loop $moar (result i32)
+    (nop)
+    (block $block (result i32)
+     (br_if $moar
+      (local.get $x)
+     )
+     (i32.const 0)
+    )
+   )
+  )
+  (block $moar18
+   (local.set $y
+    (block $block19 (result i32)
+     (br_if $moar18
+      (local.get $y)
+     )
+     (i32.const 0)
+    )
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+ )
+ (func $freetype-cd (param $a i32) (result i32)
+  (local $e i32)
+  (nop)
+  (local.tee $a
+   (loop $while-in$1 (result i32)
+    (nop)
+    (block $while-out$0 (result i32)
+     (local.set $e
+      (local.get $a)
+     )
+     (nop)
+     (drop
+      (br_if $while-out$0
+       (local.tee $a
+        (i32.const 4)
+       )
+       (local.get $e)
+      )
+     )
+     (nop)
+     (i32.add
+      (local.get $a)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+ )
+ (func $drop-if-value (param $x i32) (param $y i32) (param $z i32) (result i32)
+  (local $temp i32)
+  (drop
+   (if (result i32)
+    (local.get $x)
+    (block $block53 (result i32)
+     (nop)
+     (local.set $temp
+      (local.get $y)
+     )
+     (local.get $z)
+    )
+    (block $block54 (result i32)
+     (nop)
+     (local.set $temp
+      (local.get $y)
+     )
+     (local.get $z)
+    )
+   )
+  )
+  (drop
+   (local.get $temp)
+  )
+  (return
+   (i32.const 0)
+  )
+ )
+ (func $drop-br_if (param $label i32) (param $$cond2 i32) (param $$$0151 i32) (result i32)
+  (nop)
+  (local.tee $label
+   (block $label$break$L4 (result i32)
+    (if
+     (i32.eq
+      (local.get $label)
+      (i32.const 15)
+     )
+     (block $block
+      (nop)
+      (nop)
+      (drop
+       (br_if $label$break$L4
+        (local.tee $label
+         (i32.const 0)
+        )
+        (i32.eqz
+         (i32.eq
+          (local.get $$$0151)
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+    )
+    (nop)
+    (i32.const 1)
+   )
+  )
+ )
+ (func $drop-tee-unreachable
+  (local $x i32)
+  (local.tee $x
+   (unreachable)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $if-return-but-unreachable (param $var$0 i64)
+  (if
+   (unreachable)
+   (drop
+    (local.get $var$0)
+   )
+   (local.set $var$0
+    (i64.const 1)
+   )
+  )
+ )
+ (func $if-one-side (result i32)
+  (local $x i32)
+  (nop)
+  (local.tee $x
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 2)
+    )
+    (local.get $x)
+   )
+  )
+ )
+ (func $if-one-side-undo (result i32)
+  (local $x i32)
+  (local $y i32)
+  (local.set $y
+   (i32.const 0)
+  )
+  (local.set $x
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 2)
+    )
+    (local.get $x)
+   )
+  )
+  (local.get $y)
+ )
+ (func $if-one-side-multi (param $0 i32) (result i32)
+  (nop)
+  (local.tee $0
+   (if (result i32)
+    (i32.lt_s
+     (local.get $0)
+     (i32.const -1073741824)
+    )
+    (block (result i32)
+     (nop)
+     (i32.const -1073741824)
+    )
+    (block (result i32)
+     (nop)
+     (if (result i32)
+      (i32.gt_s
+       (local.get $0)
+       (i32.const 1073741823)
+      )
+      (block (result i32)
+       (nop)
+       (i32.const 1073741823)
+      )
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $if-one-side-undo-but-its-a-tee (param $0 i32) (result i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (local.set $x
+   (if (result i32)
+    (i32.const -1)
+    (i32.const -2)
+    (local.get $x)
+   )
+  )
+  (drop
+   (call $if-one-side-undo-but-its-a-tee
+    (local.tee $x
+     (if (result i32)
+      (i32.const -3)
+      (i32.const -4)
+      (local.get $x)
+     )
+    )
+   )
+  )
+  (nop)
+  (drop
+   (i32.eqz
+    (local.tee $y
+     (if (result i32)
+      (i32.const -5)
+      (i32.const -6)
+      (local.get $y)
+     )
+    )
+   )
+  )
+  (nop)
+  (drop
+   (i32.add
+    (local.tee $z
+     (if (result i32)
+      (i32.const -7)
+      (i32.const -8)
+      (local.get $z)
+     )
+    )
+    (local.get $z)
+   )
+  )
+  (if
+   (block $label$1 (result i32)
+    (nop)
+    (nop)
+    (local.tee $4
+     (if (result i32)
+      (local.tee $4
+       (if (result i32)
+        (i32.const 1)
+        (block (result i32)
+         (nop)
+         (i32.const 2)
+        )
+        (local.get $4)
+       )
+      )
+      (block (result i32)
+       (nop)
+       (i32.const 0)
+      )
+      (local.get $4)
+     )
+    )
+   )
+   (unreachable)
+  )
+  (i32.const 0)
+ )
+ (func $splittable-ifs-multicycle (param $20 i32) (result i32)
+  (nop)
+  (local.tee $20
+   (if (result i32)
+    (i32.const 1)
+    (if (result i32)
+     (i32.const 2)
+     (if (result i32)
+      (i32.const 3)
+      (i32.const 4)
+      (local.get $20)
+     )
+     (local.get $20)
+    )
+    (local.get $20)
+   )
+  )
+ )
+ (func $update-getCounter (param $0 i32) (param $1 f64) (param $2 f64) (param $3 f32) (param $4 i32) (result f64)
+  (global.set $global$0
+   (i32.sub
+    (global.get $global$0)
+    (i32.const 1)
+   )
+  )
+  (global.set $global$0
+   (i32.sub
+    (global.get $global$0)
+    (i32.const 1)
+   )
+  )
+  (loop $label$1 (result f64)
+   (global.set $global$0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 1)
+    )
+   )
+   (global.set $global$0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 1)
+    )
+   )
+   (call $fimport$0
+    (local.tee $3
+     (if (result f32)
+      (i32.eqz
+       (local.get $0)
+      )
+      (f32.const 4623408228068004207103214e13)
+      (local.get $3)
+     )
+    )
+   )
+   (global.set $global$0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 1)
+    )
+   )
+   (if (result f64)
+    (global.get $global$0)
+    (block $block
+     (global.set $global$0
+      (i32.sub
+       (global.get $global$0)
+       (i32.const 1)
+      )
+     )
+     (local.set $0
+      (i32.const -65)
+     )
+     (global.set $global$0
+      (i32.sub
+       (global.get $global$0)
+       (i32.const 1)
+      )
+     )
+     (br $label$1)
+    )
+    (f64.const -70)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (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_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_f64 (func (result f64)))
+ (type $i32_i32_=>_f64 (func (param i32 i32) (result f64)))
+ (import "fuzzing-support" "log1" (func $fimport$0 (result i32)))
+ (import "fuzzing-support" "log2" (func $fimport$1 (param i32)))
+ (import "fuzzing-support" "log3" (func $fimport$2 (param f32)))
+ (memory $0 (shared 256 256))
+ (global $global$0 (mut i32) (i32.const 10))
+ (func $nonatomics (result i32)
+  (local $x i32)
+  (nop)
+  (drop
+   (i32.load
+    (i32.const 1028)
+   )
+  )
+  (i32.load
+   (i32.const 1024)
+  )
+ )
+ (func $nonatomic-growmem (result i32)
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (memory.grow
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1028)
+   )
+  )
+  (local.get $x)
+ )
+ (func $atomics
+  (local $x i32)
+  (local.set $x
+   (i32.atomic.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.atomic.load
+    (i32.const 1028)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $one-atomic
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.atomic.load
+    (i32.const 1028)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $other-atomic
+  (local $x i32)
+  (local.set $x
+   (i32.atomic.load
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 1028)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $atomic-growmem (result i32)
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (memory.grow
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (i32.atomic.load
+    (i32.const 1028)
+   )
+  )
+  (local.get $x)
+ )
+ (func $atomicrmw
+  (local $x i32)
+  (local.set $x
+   (i32.atomic.rmw.add
+    (i32.const 1024)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.atomic.load
+    (i32.const 1028)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $atomic-cmpxchg
+  (local $x i32)
+  (local.set $x
+   (i32.atomic.rmw.cmpxchg
+    (i32.const 1024)
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.atomic.load
+    (i32.const 1028)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $br-value-reordering (result i32)
+  (local $temp i32)
+  (block $outside
+   (loop $loop
+    (br_if $outside
+     (block $block (result i32)
+      (br_if $loop
+       (local.get $temp)
+      )
+      (unreachable)
+      (local.set $temp
+       (i32.const -1)
+      )
+      (i32.const 0)
+     )
+    )
+   )
+   (local.set $temp
+    (i32.const -1)
+   )
+  )
+  (unreachable)
+ )
+ (func $br-value-reordering-safe (result i32)
+  (local $temp i32)
+  (local.set $temp
+   (block $outside (result i32)
+    (loop $loop
+     (drop
+      (local.get $temp)
+     )
+     (drop
+      (br_if $outside
+       (local.tee $temp
+        (i32.const -1)
+       )
+       (block $block (result i32)
+        (nop)
+        (i32.const 0)
+       )
+      )
+     )
+    )
+    (nop)
+    (i32.const -1)
+   )
+  )
+  (unreachable)
+ )
+ (func $if-one-side-unreachable
+  (local $x i32)
+  (block $out
+   (drop
+    (if (result i32)
+     (i32.const 1)
+     (block
+      (br $out)
+      (nop)
+     )
+     (block (result i32)
+      (nop)
+      (i32.const 2)
+     )
+    )
+   )
+   (drop
+    (if (result i32)
+     (i32.const 3)
+     (block (result i32)
+      (nop)
+      (i32.const 4)
+     )
+     (block
+      (br $out)
+      (nop)
+     )
+    )
+   )
+   (if
+    (i32.const 5)
+    (br $out)
+    (br $out)
+   )
+  )
+ )
+ (func $if-one-side-unreachable-blocks
+  (local $x i32)
+  (local $y i32)
+  (block $out
+   (drop
+    (if (result i32)
+     (i32.const 1)
+     (block
+      (block $block
+       (nop)
+       (nop)
+       (br $out)
+      )
+      (nop)
+     )
+     (block (result i32)
+      (block $block2
+       (nop)
+       (nop)
+      )
+      (i32.const 4)
+     )
+    )
+   )
+   (drop
+    (if (result i32)
+     (i32.const 6)
+     (block (result i32)
+      (block $block4
+       (nop)
+       (nop)
+      )
+      (i32.const 7)
+     )
+     (block
+      (block $block5
+       (nop)
+       (nop)
+       (br $out)
+      )
+      (nop)
+     )
+    )
+   )
+   (if
+    (i32.const 11)
+    (block $block7
+     (nop)
+     (nop)
+     (br $out)
+    )
+    (block $block8
+     (nop)
+     (nop)
+     (br $out)
+    )
+   )
+  )
+ )
+ (func $loop-value (param $x i32) (result i32)
+  (loop $loopy
+   (unreachable)
+  )
+  (nop)
+  (loop $loopy9 (result i32)
+   (nop)
+   (i32.const 1)
+  )
+ )
+ (func $loop-loop-loopy-value (param $x i32) (result i32)
+  (nop)
+  (loop $loopy1 (result i32)
+   (nop)
+   (loop $loopy2 (result i32)
+    (nop)
+    (loop $loopy3 (result i32)
+     (nop)
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $loop-modified-during-main-pass-be-careful-fuzz (result i32)
+  (local $0 i32)
+  (nop)
+  (if (result i32)
+   (i32.const 0)
+   (block (result i32)
+    (nop)
+    (i32.const 0)
+   )
+   (block
+    (loop $label$4
+     (br $label$4)
+    )
+    (nop)
+   )
+  )
+ )
+ (func $loop-later (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (param $var$3 i32) (param $var$4 i32) (result i32)
+  (nop)
+  (i32.const 0)
+ )
+ (func $pick
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (local.get $y)
+  )
+  (drop
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 1)
+    )
+    (local.get $x)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+  (local.set $x
+   (local.get $y)
+  )
+ )
+ (func $pick-2
+  (local $x i32)
+  (local $y i32)
+  (local.set $y
+   (local.get $x)
+  )
+  (drop
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 1)
+    )
+    (local.get $y)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (local.set $y
+   (local.get $x)
+  )
+ )
+ (func $many
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (local $w i32)
+  (nop)
+  (nop)
+  (local.set $z
+   (local.tee $y
+    (local.get $x)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (local.set $y
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 1)
+    )
+    (local.get $y)
+   )
+  )
+  (local.set $x
+   (local.get $z)
+  )
+  (drop
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 1)
+    )
+    (local.get $y)
+   )
+  )
+  (nop)
+  (nop)
+  (local.set $y
+   (local.get $x)
+  )
+  (nop)
+  (local.set $x
+   (local.tee $z
+    (i32.const 2)
+   )
+  )
+  (drop
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 1)
+    )
+    (local.get $y)
+   )
+  )
+  (nop)
+  (nop)
+  (local.set $y
+   (local.get $x)
+  )
+  (local.set $z
+   (i32.const 2)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $loop-copies (param $x i32) (param $y i32)
+  (loop $loop
+   (nop)
+   (drop
+    (local.get $y)
+   )
+   (br_if $loop
+    (local.get $y)
+   )
+  )
+ )
+ (func $proper-type (result f64)
+  (local $var$0 i32)
+  (local $var$2 f64)
+  (local.set $var$0
+   (select
+    (i32.const 0)
+    (i32.const 1)
+    (local.get $var$0)
+   )
+  )
+  (local.get $var$2)
+ )
+ (func $multi-pass-get-equivs-right (param $var$0 i32) (param $var$1 i32) (result f64)
+  (local $var$2 i32)
+  (nop)
+  (i32.store
+   (local.get $var$0)
+   (i32.const 1)
+  )
+  (f64.promote_f32
+   (f32.load
+    (local.get $var$0)
+   )
+  )
+ )
+ (func $if-value-structure-equivalent (param $x i32) (result i32)
+  (local $y i32)
+  (nop)
+  (local.tee $x
+   (if (result i32)
+    (i32.const 1)
+    (block (result i32)
+     (nop)
+     (i32.const 2)
+    )
+    (block (result i32)
+     (block $block
+      (nop)
+      (nop)
+     )
+     (local.get $x)
+    )
+   )
+  )
+ )
+ (func $set-tee-need-one-of-them (param $var$0 i32) (param $var$1 i32) (result i32)
+  (local $var$2 i32)
+  (local $var$3 i32)
+  (local.set $var$2
+   (local.get $var$0)
+  )
+  (loop $loop
+   (br_if $loop
+    (local.get $var$1)
+   )
+  )
+  (local.get $var$2)
+ )
+ (func $loop-value-harder (result i32)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 f32)
+  (local $4 f32)
+  (local $5 f32)
+  (local $6 f32)
+  (local $7 f32)
+  (local $8 f32)
+  (local $9 f32)
+  (local $10 f32)
+  (block $label$1
+   (nop)
+   (nop)
+   (call $fimport$2
+    (loop $label$2 (result f32)
+     (block $label$3
+      (global.set $global$0
+       (i32.const -1)
+      )
+      (block $label$4
+       (nop)
+       (nop)
+      )
+      (nop)
+      (nop)
+     )
+     (nop)
+     (nop)
+     (if (result f32)
+      (call $fimport$0)
+      (block (result f32)
+       (nop)
+       (f32.const -2048)
+      )
+      (block
+       (block $block
+        (call $fimport$1
+         (i32.const -25732)
+        )
+        (br $label$2)
+       )
+       (nop)
+      )
+     )
+    )
+   )
+   (nop)
+  )
+  (nop)
+  (return
+   (i32.const -5417091)
+  )
+ )
+ (func $tee-chain (param $x i32) (param $z i32) (param $t1 i32) (param $t2 i32) (param $t3 i32) (result i32)
+  (nop)
+  (drop
+   (i32.const 10)
+  )
+  (nop)
+  (local.set $t2
+   (local.tee $t3
+    (local.tee $t1
+     (call $tee-chain
+      (local.get $x)
+      (local.tee $z
+       (i32.const 10)
+      )
+      (local.get $t1)
+      (local.get $t2)
+      (local.get $t3)
+     )
+    )
+   )
+  )
+  (call $tee-chain
+   (local.get $x)
+   (local.get $z)
+   (local.get $t1)
+   (local.get $t2)
+   (local.get $t3)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 256 256)
+ (data passive "hello, there!")
+ (func $memory-init-load
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (memory.init 0
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 5)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-init-store
+  (local $x i32)
+  (local.set $x
+   (block $block (result i32)
+    (i32.store
+     (i32.const 0)
+     (i32.const 42)
+    )
+    (i32.const 0)
+   )
+  )
+  (memory.init 0
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 5)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-copy-load
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (memory.copy
+   (i32.const 0)
+   (i32.const 8)
+   (i32.const 8)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-copy-store
+  (local $x i32)
+  (local.set $x
+   (block $block (result i32)
+    (i32.store
+     (i32.const 0)
+     (i32.const 42)
+    )
+    (i32.const 0)
+   )
+  )
+  (memory.copy
+   (i32.const 0)
+   (i32.const 8)
+   (i32.const 8)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-fill-load
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (memory.fill
+   (i32.const 0)
+   (i32.const 42)
+   (i32.const 8)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-fill-store
+  (local $x i32)
+  (local.set $x
+   (block $block (result i32)
+    (i32.store
+     (i32.const 0)
+     (i32.const 42)
+    )
+    (i32.const 0)
+   )
+  )
+  (memory.fill
+   (i32.const 0)
+   (i32.const 8)
+   (i32.const 8)
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $data-drop-load
+  (local $x i32)
+  (local.set $x
+   (i32.load
+    (i32.const 0)
+   )
+  )
+  (data.drop 0)
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $data-drop-store
+  (local $x i32)
+  (local.set $x
+   (block $block (result i32)
+    (i32.store
+     (i32.const 0)
+     (i32.const 42)
+    )
+    (i32.const 0)
+   )
+  )
+  (data.drop 0)
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $data-drop-memory-init
+  (local $x i32)
+  (local.set $x
+   (block $block (result i32)
+    (memory.init 0
+     (i32.const 0)
+     (i32.const 0)
+     (i32.const 5)
+    )
+    (i32.const 0)
+   )
+  )
+  (data.drop 0)
+  (drop
+   (local.get $x)
+  )
+ )
+)
+(module
+ (type $none_=>_anyref (func (result anyref)))
+ (func $subtype-test (result anyref)
+  (local $0 funcref)
+  (local $1 anyref)
+  (local $2 anyref)
+  (block $block
+   (nop)
+  )
+  (nop)
+  (local.get $0)
+ )
+)
diff --git a/binaryen/test/passes/simplify-locals_all-features_disable-exception-handling.wast b/binaryen/test/passes/simplify-locals_all-features_disable-exception-handling.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-locals_all-features_disable-exception-handling.wast
@@ -0,0 +1,1673 @@
+(module
+  (memory 256 256)
+  (type $FUNCSIG$v (func))
+  (type $FUNCSIG$i (func (result i32)))
+  (type $FUNCSIG$iiiii (func (param i32 i32 i32 i32) (result i32)))
+  (type $FUNCSIG$iiiiii (func (param i32 i32 i32 i32 i32) (result i32)))
+  (type $4 (func (param i32)))
+  (type $5 (func (param i32) (result i32)))
+  (type $6 (func (param i32 i32 i32 i32 i32 i32)))
+  (import $waka "env" "waka")
+  (import $waka_int "env" "waka_int" (result i32))
+  (import $_i64Subtract "env" "i64sub" (param i32 i32 i32 i32) (result i32))
+  (import $___udivmoddi4 "env" "moddi" (param i32 i32 i32 i32 i32) (result i32))
+  (import $lp "env" "lp" (param i32 i32) (result i32))
+  (import "fuzzing-support" "log-f32" (func $fimport$0 (param f32)))
+  (global $global$0 (mut i32) (i32.const 10))
+  (func $contrast ;; check for tee and structure sinking
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local $a i32)
+    (local $b i32)
+    (local.set $x (i32.const 1))
+    (if (local.get $x) (nop))
+    (if (local.get $x) (nop))
+    (local.set $y (if (result i32) (i32.const 2) (i32.const 3) (i32.const 4)))
+    (drop (local.get $y))
+    (local.set $z (block (result i32) (i32.const 5)))
+    (drop (local.get $z))
+    (if (i32.const 6)
+      (local.set $a (i32.const 7))
+      (local.set $a (i32.const 8))
+    )
+    (drop (local.get $a))
+    (block $val
+      (if (i32.const 10)
+        (block
+          (local.set $b (i32.const 11))
+          (br $val)
+        )
+      )
+      (local.set $b (i32.const 12))
+    )
+    (drop (local.get $b))
+  )
+  (func $b0-yes (type $4) (param $i1 i32)
+    (local $x i32)
+    (local $y i32)
+    (local $a i32)
+    (local $b i32)
+    (local $5 i32)
+    (local $6 i32)
+    (local $7 i32)
+    (local $8 i32)
+    (local.set $x
+      (i32.const 5)
+    )
+    (drop
+      (local.get $x)
+    )
+    (block $block0
+      (local.set $x
+        (i32.const 7)
+      )
+      (drop
+        (local.get $x)
+      )
+    )
+    (local.set $x
+      (i32.const 11)
+    )
+    (drop
+      (local.get $x)
+    )
+    (local.set $x
+      (i32.const 9)
+    )
+    (drop
+      (local.get $y)
+    )
+    (block $block1
+      (local.set $x
+        (i32.const 8)
+      )
+      (drop
+        (local.get $y)
+      )
+    )
+    (local.set $x
+      (i32.const 11)
+    )
+    (drop
+      (local.get $y)
+    )
+    (local.set $x
+      (i32.const 17)
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (local.get $x)
+    )
+    (block $block2
+      (local.set $a
+        (i32.const 1)
+      )
+      (local.set $b
+        (i32.const 2)
+      )
+      (drop
+        (local.get $a)
+      )
+      (drop
+        (local.get $b)
+      )
+      (local.set $a
+        (i32.const 3)
+      )
+      (local.set $b
+        (i32.const 4)
+      )
+      (local.set $a
+        (i32.const 5)
+      )
+      (local.set $b
+        (i32.const 6)
+      )
+      (drop
+        (local.get $b)
+      )
+      (drop
+        (local.get $a)
+      )
+      (local.set $a
+        (i32.const 7)
+      )
+      (local.set $b
+        (i32.const 8)
+      )
+      (local.set $a
+        (i32.const 9)
+      )
+      (local.set $b
+        (i32.const 10)
+      )
+      (call $waka)
+      (drop
+        (local.get $a)
+      )
+      (drop
+        (local.get $b)
+      )
+      (local.set $a
+        (i32.const 11)
+      )
+      (local.set $b
+        (i32.const 12)
+      )
+      (local.set $a
+        (i32.const 13)
+      )
+      (local.set $b
+        (i32.const 14)
+      )
+      (drop
+        (i32.load
+          (i32.const 24)
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+      (drop
+        (local.get $b)
+      )
+      (local.set $a
+        (i32.const 15)
+      )
+      (local.set $b
+        (i32.const 16)
+      )
+      (local.set $a
+        (i32.const 17)
+      )
+      (local.set $b
+        (i32.const 18)
+      )
+      (i32.store
+        (i32.const 48)
+        (i32.const 96)
+      )
+      (drop
+        (local.get $a)
+      )
+      (drop
+        (local.get $b)
+      )
+    )
+    (block $block3
+      (local.set $a
+        (call $waka_int)
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (call $waka_int)
+      )
+      (call $waka)
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (call $waka_int)
+      )
+      (drop
+        (i32.load
+          (i32.const 1)
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (call $waka_int)
+      )
+      (i32.store
+        (i32.const 1)
+        (i32.const 2)
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (i32.load
+          (i32.const 100)
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (i32.load
+          (i32.const 101)
+        )
+      )
+      (drop
+        (i32.load
+          (i32.const 1)
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (i32.load
+          (i32.const 102)
+        )
+      )
+      (call $waka)
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (i32.load
+          (i32.const 103)
+        )
+      )
+      (i32.store
+        (i32.const 1)
+        (i32.const 2)
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (block (result i32)
+          (block
+            (local.set $5
+              (i32.const 105)
+            )
+            (i32.store
+              (i32.const 104)
+              (local.get $5)
+            )
+          )
+          (local.get $5)
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (block (result i32)
+          (block
+            (local.set $6
+              (i32.const 107)
+            )
+            (i32.store
+              (i32.const 106)
+              (local.get $6)
+            )
+          )
+          (local.get $6)
+        )
+      )
+      (call $waka)
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (block (result i32)
+          (block
+            (local.set $7
+              (i32.const 109)
+            )
+            (i32.store
+              (i32.const 108)
+              (local.get $7)
+            )
+          )
+          (local.get $7)
+        )
+      )
+      (drop
+        (i32.load
+          (i32.const 1)
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+      (local.set $a
+        (block (result i32)
+          (block
+            (local.set $8
+              (i32.const 111)
+            )
+            (i32.store
+              (i32.const 110)
+              (local.get $8)
+            )
+          )
+          (local.get $8)
+        )
+      )
+      (i32.store
+        (i32.const 1)
+        (i32.const 2)
+      )
+      (drop
+        (local.get $a)
+      )
+      (call $waka)
+    )
+    (block $out-of-block
+      (local.set $a
+        (i32.const 1337)
+      )
+      (block $b
+        (block $c
+          (br $b)
+        )
+        (local.set $a
+          (i32.const 9876)
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+    )
+    (block $loopey
+      (local.set $a
+        (i32.const 1337)
+      )
+      (drop
+        (loop $loop-in5 (result i32)
+          (drop
+            (local.get $a)
+          )
+          (local.tee $a
+            (i32.const 9876)
+          )
+        )
+      )
+      (drop
+        (local.get $a)
+      )
+    )
+  )
+  (func $Ia (type $5) (param $a i32) (result i32)
+    (local $b i32)
+    (block $switch$0
+      (block $switch-default$6
+        (local.set $b
+          (i32.const 60)
+        )
+      )
+    )
+    (return
+      (local.get $b)
+    )
+  )
+  (func $memories (type $6) (param $i2 i32) (param $i3 i32) (param $bi2 i32) (param $bi3 i32) (param $ci3 i32) (param $di3 i32)
+    (local $set_with_no_get i32)
+    (local.set $i3
+      (i32.const 1)
+    )
+    (i32.store8
+      (local.get $i2)
+      (local.get $i3)
+    )
+    (local.set $bi3
+      (i32.const 1)
+    )
+    (i32.store8
+      (local.get $bi3)
+      (local.get $bi3)
+    )
+    (local.set $ci3
+      (local.get $bi3)
+    )
+    (i32.store8
+      (local.get $bi3)
+      (local.get $ci3)
+    )
+    (local.set $di3
+      (local.tee $bi3
+        (i32.const 123)
+      )
+    )
+    (i32.store8
+      (local.get $bi3)
+      (local.get $di3)
+    )
+    (local.set $set_with_no_get
+      (i32.const 456)
+    )
+  )
+  (func $___remdi3 (type $FUNCSIG$iiiii) (param $$a$0 i32) (param $$a$1 i32) (param $$b$0 i32) (param $$b$1 i32) (result i32)
+    (local $$1$1 i32)
+    (local $$1$0 i32)
+    (local $$rem i32)
+    (local $__stackBase__ i32)
+    (local $$2$1 i32)
+    (local $$2$0 i32)
+    (local $$4$1 i32)
+    (local $$4$0 i32)
+    (local $$10$1 i32)
+    (local $$10$0 i32)
+    (local $$6$0 i32)
+    (local.set $__stackBase__
+      (i32.load
+        (i32.const 8)
+      )
+    )
+    (i32.store
+      (i32.const 8)
+      (i32.add
+        (i32.load
+          (i32.const 8)
+        )
+        (i32.const 16)
+      )
+    )
+    (local.set $$rem
+      (local.get $__stackBase__)
+    )
+    (local.set $$1$0
+      (i32.or
+        (i32.shr_s
+          (local.get $$a$1)
+          (i32.const 31)
+        )
+        (i32.shl
+          (if (result i32)
+            (i32.lt_s
+              (local.get $$a$1)
+              (i32.const 0)
+            )
+            (i32.const -1)
+            (i32.const 0)
+          )
+          (i32.const 1)
+        )
+      )
+    )
+    (local.set $$1$1
+      (i32.or
+        (i32.shr_s
+          (if (result i32)
+            (i32.lt_s
+              (local.get $$a$1)
+              (i32.const 0)
+            )
+            (i32.const -1)
+            (i32.const 0)
+          )
+          (i32.const 31)
+        )
+        (i32.shl
+          (if (result i32)
+            (i32.lt_s
+              (local.get $$a$1)
+              (i32.const 0)
+            )
+            (i32.const -1)
+            (i32.const 0)
+          )
+          (i32.const 1)
+        )
+      )
+    )
+    (local.set $$2$0
+      (i32.or
+        (i32.shr_s
+          (local.get $$b$1)
+          (i32.const 31)
+        )
+        (i32.shl
+          (if (result i32)
+            (i32.lt_s
+              (local.get $$b$1)
+              (i32.const 0)
+            )
+            (i32.const -1)
+            (i32.const 0)
+          )
+          (i32.const 1)
+        )
+      )
+    )
+    (local.set $$2$1
+      (i32.or
+        (i32.shr_s
+          (if (result i32)
+            (i32.lt_s
+              (local.get $$b$1)
+              (i32.const 0)
+            )
+            (i32.const -1)
+            (i32.const 0)
+          )
+          (i32.const 31)
+        )
+        (i32.shl
+          (if (result i32)
+            (i32.lt_s
+              (local.get $$b$1)
+              (i32.const 0)
+            )
+            (i32.const -1)
+            (i32.const 0)
+          )
+          (i32.const 1)
+        )
+      )
+    )
+    (local.set $$4$0
+      (call $_i64Subtract
+        (i32.xor
+          (local.get $$1$0)
+          (local.get $$a$0)
+        )
+        (i32.xor
+          (local.get $$1$1)
+          (local.get $$a$1)
+        )
+        (local.get $$1$0)
+        (local.get $$1$1)
+      )
+    )
+    (local.set $$4$1
+      (i32.load
+        (i32.const 168)
+      )
+    )
+    (drop
+      (call $___udivmoddi4
+        (local.get $$4$0)
+        (local.get $$4$1)
+        (call $_i64Subtract
+          (i32.xor
+            (local.get $$2$0)
+            (local.get $$b$0)
+          )
+          (i32.xor
+            (local.get $$2$1)
+            (local.get $$b$1)
+          )
+          (local.get $$2$0)
+          (local.get $$2$1)
+        )
+        (i32.load
+          (i32.const 168)
+        )
+        (local.get $$rem)
+      )
+    )
+    (local.set $$10$0
+      (call $_i64Subtract
+        (i32.xor
+          (i32.load
+            (local.get $$rem)
+          )
+          (local.get $$1$0)
+        )
+        (i32.xor
+          (i32.load offset=4
+            (local.get $$rem)
+          )
+          (local.get $$1$1)
+        )
+        (local.get $$1$0)
+        (local.get $$1$1)
+      )
+    )
+    (local.set $$10$1
+      (i32.load
+        (i32.const 168)
+      )
+    )
+    (i32.store
+      (i32.const 8)
+      (local.get $__stackBase__)
+    )
+    (return
+      (block $block12 (result i32)
+        (i32.store
+          (i32.const 168)
+          (local.get $$10$1)
+        )
+        (local.get $$10$0)
+      )
+    )
+  )
+  (func $block-returns (type $FUNCSIG$v)
+    (local $x i32)
+    (block $out
+      (block $waka
+        (local.set $x
+          (i32.const 12)
+        )
+        (br_if $waka
+          (i32.const 1)
+        )
+        (local.set $x
+          (i32.const 34)
+        )
+      )
+      (br_if $out
+        (i32.const 1)
+      )
+      (drop
+        (local.get $x)
+      )
+      (block $waka2
+        (if
+          (i32.const 1)
+          (local.set $x
+            (i32.const 13)
+          )
+          (local.set $x
+            (i32.const 24)
+          )
+        )
+        (if
+          (i32.const 1)
+          (block $block3
+            (local.set $x
+              (i32.const 14)
+            )
+          )
+          (block $block5
+            (local.set $x
+              (i32.const 25)
+            )
+          )
+        )
+      )
+      (br_if $out
+        (i32.const 1)
+      )
+      (block $sink-out-of-me-i-have-but-one-exit
+        (local.set $x
+          (i32.const 99)
+        )
+      )
+      (drop
+        (local.get $x)
+      )
+    )
+  )
+  (func $multiple (type $6) (param $s i32) (param $r i32) (param $f i32) (param $p i32) (param $t i32) (param $m i32)
+    (local.set $s
+      (local.get $m)
+    )
+    (local.set $r
+      (i32.add
+        (local.get $f)
+        (local.get $p)
+      )
+    )
+    (local.set $t
+      (local.get $p)
+    )
+    (local.set $p
+      (i32.load
+        (i32.const 0)
+      )
+    )
+    (i32.store
+      (local.get $r)
+      (local.get $t)
+    )
+    (drop
+      (local.get $s)
+    )
+    (drop
+      (local.get $t)
+    )
+  )
+  (func $switch-def (type $5) (param $i3 i32) (result i32)
+    (local $i1 i32)
+    (local.set $i1
+      (i32.const 10)
+    )
+    (block $switch$def
+      (block $switch-case$1
+        (br_table $switch-case$1 $switch$def
+          (local.get $i3)
+        )
+      )
+      (local.set $i1
+        (i32.const 1)
+      )
+    )
+    (return
+      (local.get $i1)
+    )
+  )
+  (func $no-out-of-label (param $x i32) (param $y i32)
+    (loop $moar
+      (local.set $x
+        (block (result i32)
+          (br_if $moar (local.get $x))
+          (i32.const 0)
+        )
+      )
+    )
+    (drop (local.get $x))
+    (block $moar
+      (local.set $y
+        (block (result i32)
+          (br_if $moar (local.get $y))
+          (i32.const 0)
+        )
+      )
+    )
+    (drop (local.get $y))
+  )
+  (func $freetype-cd (param $a i32) (result i32)
+    (local $e i32)
+    (loop $while-in$1
+      (block $while-out$0
+        (local.set $e
+          (local.get $a)
+        )
+        (local.set $a ;; this set must happen, so that if the br_if does not break, we have the right $a later down - once we use a block return value, the $a set's outside the block
+          (i32.const 4)
+        )
+        (br_if $while-out$0
+          (local.get $e)
+        )
+        (local.set $a
+          (i32.add
+            (local.get $a)
+            (i32.const 0)
+          )
+        )
+      )
+    )
+    (local.get $a)
+  )
+  (func $drop-if-value (param $x i32) (param $y i32) (param $z i32) (result i32)
+    (local $temp i32)
+    (drop
+      (if (result i32)
+        (local.get $x)
+        (block $block53 (result i32)
+          (nop)
+          (local.set $temp
+            (local.get $y)
+          )
+          (local.get $z)
+        )
+        (block $block54 (result i32)
+          (nop)
+          (local.set $temp
+            (local.get $y)
+          )
+          (local.get $z)
+        )
+      )
+    )
+    (drop (local.get $temp))
+    (return
+      (i32.const 0)
+    )
+  )
+  (func $drop-br_if (param $label i32) (param $$cond2 i32) (param $$$0151 i32) (result i32)
+    (block $label$break$L4
+      (if
+        (i32.eq
+          (local.get $label)
+          (i32.const 15)
+        )
+        (block $block
+          (local.set $label
+            (i32.const 0)
+          )
+          (local.set $$cond2
+            (i32.eq
+              (local.get $$$0151)
+              (i32.const 0)
+            )
+          )
+          (br_if $label$break$L4 ;; when we add a value to this, its type changes as it returns the value too, so must be dropped
+            (i32.eqz
+              (local.get $$cond2)
+            )
+          )
+        )
+      )
+      (local.set $label
+        (i32.const 1)
+      )
+    )
+    (local.get $label)
+  )
+  (func $drop-tee-unreachable
+    (local $x i32)
+    (drop
+      (local.tee $x
+        (unreachable)
+      )
+    )
+    (drop
+      (local.get $x)
+    )
+  )
+  (func $if-return-but-unreachable (param $var$0 i64)
+   (if
+    (unreachable)
+    (local.set $var$0
+     (local.get $var$0)
+    )
+    (local.set $var$0
+     (i64.const 1)
+    )
+   )
+  )
+  (func $if-one-side (result i32)
+   (local $x i32)
+   (if
+    (i32.const 1)
+    (local.set $x
+     (i32.const 2)
+    )
+   )
+   (local.get  $x)
+  )
+  (func $if-one-side-undo (result i32)
+   (local $x i32)
+   (local $y i32)
+   (local.set $y
+    (i32.const 0)
+   )
+   (if
+    (i32.const 1)
+    (local.set $x
+     (i32.const 2)
+    )
+   )
+   (local.get  $y)
+  )
+  (func $if-one-side-multi (param $0 i32) (result i32)
+   (if
+    (i32.lt_s
+     (local.get $0)
+     (i32.const -1073741824)
+    )
+    (local.set $0
+     (i32.const -1073741824)
+    )
+    (if
+     (i32.gt_s
+      (local.get $0)
+      (i32.const 1073741823)
+     )
+     (local.set $0
+      (i32.const 1073741823)
+     )
+    )
+   )
+   (local.get $0)
+  )
+  (func $if-one-side-undo-but-its-a-tee (param $0 i32) (result i32)
+   (local $1 i32)
+   (local $2 i32)
+   (local $3 i32)
+   (local $4 i32)
+   (local $x i32)
+   (local $y i32)
+   (local $z i32)
+   ;; break these splittable ifs up
+   (local.set $x
+     (if (result i32)
+       (i32.const -1)
+       (i32.const -2)
+       (local.get $x)
+     )
+   )
+   ;; oops, this one is a tee
+   (drop
+    (call $if-one-side-undo-but-its-a-tee
+     (local.tee $x
+       (if (result i32)
+         (i32.const -3)
+         (i32.const -4)
+         (local.get $x)
+       )
+     )
+    )
+   )
+   ;; sinkable
+   (local.set $y
+     (if (result i32)
+       (i32.const -5)
+       (i32.const -6)
+       (local.get $y)
+     )
+   )
+   (drop (i32.eqz (local.get $y)))
+   ;; tee-able at best
+   (local.set $z
+     (if (result i32)
+       (i32.const -7)
+       (i32.const -8)
+       (local.get $z)
+     )
+   )
+   (drop
+    (i32.add
+     (local.get $z)
+     (local.get $z)
+    )
+   )
+   (if
+    (block $label$1 (result i32)
+     (if
+      (i32.const 1)
+      (local.set $4
+       (i32.const 2)
+      )
+     )
+     (if
+      (local.get $4)
+      (local.set $4
+       (i32.const 0)
+      )
+     )
+     (local.get $4)
+    )
+    (unreachable)
+   )
+   (i32.const 0)
+  )
+  (func $splittable-ifs-multicycle (param $20 i32) (result i32)
+   (local.set $20
+    (if (result i32)
+     (i32.const 1)
+     (if (result i32)
+      (i32.const 2)
+      (if (result i32)
+       (i32.const 3)
+       (i32.const 4)
+       (local.get $20)
+      )
+      (local.get $20)
+     )
+     (local.get $20)
+    )
+   )
+   (local.get $20)
+  )
+  (func $update-getCounter (param $0 i32) (param $1 f64) (param $2 f64) (param $3 f32) (param $4 i32) (result f64)
+   (global.set $global$0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 1)
+    )
+   )
+   (global.set $global$0
+    (i32.sub
+     (global.get $global$0)
+     (i32.const 1)
+    )
+   )
+   (loop $label$1 (result f64)
+    (global.set $global$0
+     (i32.sub
+      (global.get $global$0)
+      (i32.const 1)
+     )
+    )
+    (global.set $global$0
+     (i32.sub
+      (global.get $global$0)
+      (i32.const 1)
+     )
+    )
+    (call $fimport$0
+     (local.tee $3
+      (if (result f32)
+       (i32.eqz
+        (local.get $0)
+       )
+       (f32.const 4623408228068004207103214e13)
+       (local.get $3)
+      )
+     )
+    )
+    (global.set $global$0
+     (i32.sub
+      (global.get $global$0)
+      (i32.const 1)
+     )
+    )
+    (if (result f64)
+     (global.get $global$0)
+     (block
+      (global.set $global$0
+       (i32.sub
+        (global.get $global$0)
+        (i32.const 1)
+       )
+      )
+      (local.set $0
+       (i32.const -65)
+      )
+      (global.set $global$0
+       (i32.sub
+        (global.get $global$0)
+        (i32.const 1)
+       )
+      )
+      (br $label$1)
+     )
+     (f64.const -70)
+    )
+   )
+  )
+)
+(module
+  (memory (shared 256 256))
+  (type $FUNCSIG$v (func))
+  (type $FUNCSIG$i (func (result i32)))
+  (type $FUNCSIG$iiiii (func (param i32 i32 i32 i32) (result i32)))
+  (type $FUNCSIG$iiiiii (func (param i32 i32 i32 i32 i32) (result i32)))
+  (type $4 (func (param i32)))
+  (type $5 (func (param i32) (result i32)))
+  (type $6 (func (param i32 i32 i32 i32 i32 i32)))
+  (import "fuzzing-support" "log1" (func $fimport$0 (result i32)))
+  (import "fuzzing-support" "log2" (func $fimport$1 (param i32)))
+  (import "fuzzing-support" "log3" (func $fimport$2 (param f32)))
+  (global $global$0 (mut i32) (i32.const 10))
+  (func $nonatomics (result i32) ;; loads are reordered
+    (local $x i32)
+    (local.set $x (i32.load (i32.const 1024)))
+    (drop (i32.load (i32.const 1028)))
+    (local.get $x)
+  )
+  (func $nonatomic-growmem (result i32) ;; memory.grow is modeled as modifying memory
+    (local $x i32)
+    (local.set $x (i32.load (memory.grow (i32.const 1))))
+    (drop (i32.load (i32.const 1028)))
+    (local.get $x)
+  )
+  (func $atomics ;; atomic loads don't pass each other
+    (local $x i32)
+    (local.set $x (i32.atomic.load (i32.const 1024)))
+    (drop (i32.atomic.load (i32.const 1028)))
+    (drop (local.get $x))
+  )
+  (func $one-atomic ;; atomic loads don't pass other loads
+    (local $x i32)
+    (local.set $x (i32.load (i32.const 1024)))
+    (drop (i32.atomic.load (i32.const 1028)))
+    (drop (local.get $x))
+  )
+  (func $other-atomic ;; atomic loads don't pass other loads
+    (local $x i32)
+    (local.set $x (i32.atomic.load (i32.const 1024)))
+    (drop (i32.load (i32.const 1028)))
+    (drop (local.get $x))
+  )
+  (func $atomic-growmem (result i32) ;; memory.grow is modeled as modifying memory
+    (local $x i32)
+    (local.set $x (i32.load (memory.grow (i32.const 1))))
+    (drop (i32.atomic.load (i32.const 1028)))
+    (local.get $x)
+  )
+  (func $atomicrmw ;; atomic rmw don't pass loads
+    (local $x i32)
+    (local.set $x (i32.atomic.rmw.add (i32.const 1024) (i32.const 1)))
+    (drop (i32.atomic.load (i32.const 1028)))
+    (drop (local.get $x))
+  )
+  (func $atomic-cmpxchg ;; cmpxchg don't pass loads
+    (local $x i32)
+    (local.set $x (i32.atomic.rmw.cmpxchg (i32.const 1024) (i32.const 1) (i32.const 2)))
+    (drop (i32.atomic.load (i32.const 1028)))
+    (drop (local.get $x))
+  )
+  (func $br-value-reordering (result i32)
+   (local $temp i32)
+   (block $outside
+    (loop $loop ;; we should exit this loop, hit the unreachable outside
+     ;; loop logic
+     (br_if $outside ;; we should not create a block value that adds a value to a br, if the value&condition of the br cannot be reordered,
+                     ;; as the value comes first
+      (block (result i32)
+       (br_if $loop
+        (local.get $temp) ;; false, don't loop
+       )
+       (unreachable) ;; the end
+       (local.set $temp
+        (i32.const -1)
+       )
+       (i32.const 0)
+      )
+     )
+    )
+    (local.set $temp
+     (i32.const -1)
+    )
+   )
+   (unreachable)
+  )
+  (func $br-value-reordering-safe (result i32)
+   (local $temp i32)
+   (block $outside
+    (loop $loop ;; we should exit this loop, hit the unreachable outside
+     ;; loop logic
+     (drop (local.get $temp)) ;; different from above - add a use here
+     (br_if $outside ;; we should not create a block value that adds a value to a br, if the value&condition of the br cannot be reordered,
+                     ;; as the value comes first
+      (block (result i32)
+       (local.set $temp ;; the use *is* in the condition, but it's ok, no conflicts
+        (i32.const -1)
+       )
+       (i32.const 0)
+      )
+     )
+    )
+    (local.set $temp
+     (i32.const -1)
+    )
+   )
+   (unreachable)
+  )
+  (func $if-one-side-unreachable
+   (local $x i32)
+   (block $out
+    (if
+     (i32.const 1)
+     (br $out)
+     (local.set $x
+      (i32.const 2)
+     )
+    )
+    (if
+     (i32.const 3)
+     (local.set $x
+      (i32.const 4)
+     )
+     (br $out)
+    )
+    (if
+     (i32.const 5)
+     (br $out)
+     (br $out)
+    )
+   )
+  )
+  (func $if-one-side-unreachable-blocks
+   (local $x i32)
+   (local $y i32)
+   (block $out
+    (if
+     (i32.const 1)
+     (block
+      (local.set $x
+       (i32.const 2)
+      )
+      (local.set $y
+       (i32.const 3)
+      )
+      (br $out)
+     )
+     (block
+      (local.set $x
+       (i32.const 4)
+      )
+      (local.set $y
+       (i32.const 5)
+      )
+     )
+    )
+    (if
+     (i32.const 6)
+     (block
+      (local.set $x
+       (i32.const 7)
+      )
+      (local.set $y
+       (i32.const 8)
+      )
+     )
+     (block
+      (local.set $x
+       (i32.const 9)
+      )
+      (local.set $y
+       (i32.const 10)
+      )
+      (br $out)
+     )
+    )
+    (if
+     (i32.const 11)
+     (block
+      (local.set $x
+       (i32.const 12)
+      )
+      (local.set $y
+       (i32.const 13)
+      )
+      (br $out)
+     )
+     (block
+      (local.set $x
+       (i32.const 14)
+      )
+      (local.set $y
+       (i32.const 15)
+      )
+      (br $out)
+     )
+    )
+   )
+  )
+  (func $loop-value (param $x i32) (result i32)
+    (loop $loopy
+      (local.set $x (unreachable))
+    )
+    (loop $loopy
+      (local.set $x (i32.const 1))
+    )
+    (local.get $x)
+  )
+  (func $loop-loop-loopy-value (param $x i32) (result i32)
+    (loop $loopy1
+      (loop $loopy2
+        (loop $loopy3
+          (local.set $x (i32.const 1))
+        )
+      )
+    )
+    (local.get $x)
+  )
+  (func $loop-modified-during-main-pass-be-careful-fuzz (result i32)
+   (local $0 i32)
+   (if
+    (i32.const 0)
+    (local.set $0
+     (i32.const 0)
+    )
+    (loop $label$4
+     (br $label$4)
+    )
+   )
+   (local.get $0)
+  )
+  (func $loop-later (param $var$0 i32) (param $var$1 i32) (param $var$2 i32) (param $var$3 i32) (param $var$4 i32) (result i32)
+   (loop $label$1
+    (block $label$2
+     (if
+      (i32.const 0)
+      (block
+       (local.set $var$0
+        (i32.const -1)
+       )
+       (br $label$2)
+      )
+     )
+     (local.set $var$0
+      (i32.const -1)
+     )
+    )
+   )
+   (i32.const 0)
+  )
+  (func $pick
+   (local $x i32)
+   (local $y i32)
+   (local.set $x (local.get $y))
+   (if (i32.const 1)
+    (local.set $x (i32.const 1))
+   )
+   (local.set $x (local.get $y))
+   (local.set $x (local.get $y))
+  )
+  (func $pick-2
+   (local $x i32)
+   (local $y i32)
+   (local.set $y (local.get $x))
+   (if (i32.const 1)
+    (local.set $y (i32.const 1))
+   )
+   (local.set $y (local.get $x))
+   (local.set $y (local.get $x))
+  )
+  (func $many
+   (local $x i32)
+   (local $y i32)
+   (local $z i32)
+   (local $w i32)
+   (local.set $y (local.get $x))
+   (local.set $z (local.get $y))
+   (local.set $w (local.get $z))
+   (local.set $x (local.get $z))
+   (if (i32.const 1)
+    (local.set $y (i32.const 1))
+   )
+   (local.set $x (local.get $z))
+   (if (i32.const 1)
+    (local.set $y (i32.const 1))
+   )
+   (local.set $y (local.get $x))
+   (local.set $z (local.get $y))
+   (local.set $w (local.get $z))
+   (local.set $z (i32.const 2))
+   (local.set $x (local.get $z))
+   (if (i32.const 1)
+    (local.set $y (i32.const 1))
+   )
+   (local.set $y (local.get $x))
+   (local.set $z (local.get $y))
+   (local.set $w (local.get $z))
+   (local.set $z (i32.const 2))
+   (local.set $x (local.get $w))
+  )
+  (func $loop-copies (param $x i32) (param $y i32)
+   (loop $loop
+    (local.set $x (local.get $y))
+    (local.set $y (local.get $x))
+    (br_if $loop (local.get $x))
+   )
+  )
+  (func $proper-type (result f64)
+   (local $var$0 i32)
+   (local $var$2 f64)
+   (local.set $var$0
+    (select
+     (i32.const 0)
+     (i32.const 1)
+     (local.get $var$0)
+    )
+   )
+   (local.tee $var$2
+    (local.get $var$2)
+   )
+  )
+  (func $multi-pass-get-equivs-right (param $var$0 i32) (param $var$1 i32) (result f64)
+   (local $var$2 i32)
+   (local.set $var$2
+    (local.get $var$0)
+   )
+   (i32.store
+    (local.get $var$2)
+    (i32.const 1)
+   )
+   (f64.promote_f32
+    (f32.load
+     (local.get $var$2)
+    )
+   )
+  )
+  (func $if-value-structure-equivalent (param $x i32) (result i32)
+    (local $y i32)
+    (if (i32.const 1)
+      (local.set $x (i32.const 2))
+      (block
+        (local.set $y (local.get $x))
+        (local.set $x (local.get $y))
+      )
+    )
+    (local.get $x)
+  )
+  (func $set-tee-need-one-of-them (param $var$0 i32) (param $var$1 i32) (result i32)
+   (local $var$2 i32)
+   (local $var$3 i32)
+   (local.set $var$0 ;; this is redundant
+    (local.tee $var$2 ;; but this is not - we need this set, we read it at the end
+     (local.get $var$0)
+    )
+   )
+   (loop $loop
+    (br_if $loop
+     (local.get $var$1)
+    )
+   )
+   (local.get $var$2)
+  )
+  (func $loop-value-harder (result i32)
+   (local $0 i32)
+   (local $1 i32)
+   (local $2 i32)
+   (local $3 f32)
+   (local $4 f32)
+   (local $5 f32)
+   (local $6 f32)
+   (local $7 f32)
+   (local $8 f32)
+   (local $9 f32)
+   (local $10 f32)
+   (block $label$1
+    (loop $label$2
+     (block $label$3
+      (global.set $global$0
+       (i32.const -1)
+      )
+      (block $label$4
+       (local.set $0
+        (call $fimport$0)
+       )
+       (if
+        (local.get $0)
+        (local.set $5
+         (f32.const -2048)
+        )
+        (block
+         (call $fimport$1
+          (i32.const -25732)
+         )
+         (br $label$2)
+        )
+       )
+      )
+      (local.set $6
+       (local.get $5)
+      )
+      (local.set $7
+       (local.get $6)
+      )
+     )
+     (local.set $8
+      (local.get $7)
+     )
+     (local.set $9
+      (local.get $8)
+     )
+    )
+    (local.set $10
+     (local.get $9)
+    )
+    (call $fimport$2
+     (local.get $10)
+    )
+    (local.set $1
+     (i32.const -5417091)
+    )
+   )
+   (local.set $2
+    (local.get $1)
+   )
+   (return
+    (local.get $2)
+   )
+  )
+  (func $tee-chain
+    (param $x i32)
+    (param $z i32)
+    (param $t1 i32)
+    (param $t2 i32)
+    (param $t3 i32)
+    (result i32)
+    (local.set $x
+      (local.get $x)
+    )
+    (local.set $z
+      (local.tee $z
+        (i32.const 10)
+      )
+    )
+    (local.set $z
+      (local.tee $z
+        (i32.const 10)
+      )
+    )
+    (local.set $t1
+      (local.tee $t2
+        (local.tee $t3
+          (local.tee $t1
+            (call $tee-chain (local.get $x) (local.get $z) (local.get $t1) (local.get $t2) (local.get $t3))
+          )
+        )
+      )
+    )
+    (call $tee-chain (local.get $x) (local.get $z) (local.get $t1) (local.get $t2) (local.get $t3))
+  )
+)
+(module
+ (memory 256 256)
+ (data passive "hello, there!")
+ (func $memory-init-load
+  (local $x i32)
+  (local.set $x
+   (i32.load (i32.const 0))
+  )
+  (memory.init 0 (i32.const 0) (i32.const 0) (i32.const 5))
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-init-store
+  (local $x i32)
+  (local.set $x
+   (block i32
+    (i32.store (i32.const 0) (i32.const 42))
+    (i32.const 0)
+   )
+  )
+  (memory.init 0 (i32.const 0) (i32.const 0) (i32.const 5))
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-copy-load
+  (local $x i32)
+  (local.set $x
+   (i32.load (i32.const 0))
+  )
+  (memory.copy (i32.const 0) (i32.const 8) (i32.const 8))
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-copy-store
+  (local $x i32)
+  (local.set $x
+   (block i32
+    (i32.store (i32.const 0) (i32.const 42))
+    (i32.const 0)
+   )
+  )
+  (memory.copy (i32.const 0) (i32.const 8) (i32.const 8))
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-fill-load
+  (local $x i32)
+  (local.set $x
+   (i32.load (i32.const 0))
+  )
+  (memory.fill (i32.const 0) (i32.const 42) (i32.const 8))
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $memory-fill-store
+  (local $x i32)
+  (local.set $x
+   (block i32
+    (i32.store (i32.const 0) (i32.const 42))
+    (i32.const 0)
+   )
+  )
+  (memory.fill (i32.const 0) (i32.const 8) (i32.const 8))
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $data-drop-load
+  (local $x i32)
+  (local.set $x
+   (i32.load (i32.const 0))
+  )
+  (data.drop 0)
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $data-drop-store
+  (local $x i32)
+  (local.set $x
+   (block i32
+    (i32.store (i32.const 0) (i32.const 42))
+    (i32.const 0)
+   )
+  )
+  (data.drop 0)
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $data-drop-memory-init
+  (local $x i32)
+  (local.set $x
+   (block i32
+    (memory.init 0 (i32.const 0) (i32.const 0) (i32.const 5))
+    (i32.const 0)
+   )
+  )
+  (data.drop 0)
+  (drop
+   (local.get $x)
+  )
+ )
+)
+(module
+ (func $subtype-test (result anyref)
+  (local $0 funcref)
+  (local $1 anyref)
+  (local $2 anyref)
+  (block
+   (local.set $1
+    (local.get $0)
+   )
+  )
+  (local.set $2
+   (local.get $1)
+  )
+  (local.get $1)
+ )
+)
diff --git a/binaryen/test/passes/souperify.txt b/binaryen/test/passes/souperify.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/souperify.txt
@@ -0,0 +1,26 @@
+
+; function: if-loop-test
+
+; start LHS (in if-loop-test)
+%0 = sub 0:i32, 0:i32
+%1 = ne 0:i32, 0:i32
+pc %1 1:i1
+infer %0
+
+(module
+ (type $none_=>_none (func))
+ (func $if-loop-test
+  (local $0 i32)
+  (if
+   (i32.const 0)
+   (loop $label$0
+    (local.set $0
+     (i32.sub
+      (i32.const 0)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/souperify.wast b/binaryen/test/passes/souperify.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/souperify.wast
@@ -0,0 +1,17 @@
+(module
+  ;; This tests if we can create dataflow graph correctly in the presence of
+  ;; loops.
+  (func $if-loop-test (local $0 i32)
+    (if
+      (i32.const 0)
+      (loop $label$0
+        (local.set $0
+          (i32.sub
+            (i32.const 0)
+            (i32.const 0)
+          )
+        )
+      )
+    )
+  )
+)
diff --git a/binaryen/test/passes/spill-pointers.txt b/binaryen/test/passes/spill-pointers.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/spill-pointers.txt
@@ -0,0 +1,1291 @@
+(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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/spill-pointers.wast
@@ -0,0 +1,338 @@
+(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/ssa-nomerge_enable-simd.txt b/binaryen/test/passes/ssa-nomerge_enable-simd.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/ssa-nomerge_enable-simd.txt
@@ -0,0 +1,214 @@
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (memory $0 1 1)
+ (global $global$0 (mut i32) (i32.const 1))
+ (func $basics (param $x i32)
+  (local $y i32)
+  (local $z f32)
+  (local $w i64)
+  (local $t f64)
+  (local $5 i32)
+  (local $6 f64)
+  (local $7 f64)
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (f32.const 0)
+  )
+  (drop
+   (i64.const 0)
+  )
+  (drop
+   (f64.const 0)
+  )
+  (local.set $5
+   (i32.const 100)
+  )
+  (drop
+   (local.get $5)
+  )
+  (local.set $6
+   (f64.const 2)
+  )
+  (drop
+   (local.get $6)
+  )
+  (local.set $7
+   (f64.const 33)
+  )
+  (drop
+   (local.get $7)
+  )
+  (drop
+   (local.get $7)
+  )
+ )
+ (func $if (param $p i32)
+  (local $x i32)
+  (local $y i32)
+  (local $3 i32)
+  (drop
+   (if (result i32)
+    (i32.const 1)
+    (i32.const 0)
+    (i32.const 0)
+   )
+  )
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.const 1)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (if
+   (i32.const 1)
+   (local.set $p
+    (i32.const 1)
+   )
+  )
+  (drop
+   (local.get $p)
+  )
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.const 2)
+   )
+   (nop)
+  )
+  (drop
+   (local.get $x)
+  )
+  (if
+   (i32.const 1)
+   (nop)
+   (local.set $x
+    (i32.const 3)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.const 4)
+   )
+   (local.set $x
+    (i32.const 5)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.const 6)
+   )
+   (block $block
+    (local.set $3
+     (i32.const 7)
+    )
+    (local.set $x
+     (i32.const 8)
+    )
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $if2 (param $x i32)
+  (if
+   (i32.const 1)
+   (block $block
+    (local.set $x
+     (i32.const 1)
+    )
+    (drop
+     (local.get $x)
+    )
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $nomerge (param $p i32) (param $q i32)
+  (local $x i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $3
+   (i32.const 1)
+  )
+  (call $nomerge
+   (local.get $3)
+   (local.get $3)
+  )
+  (local.set $4
+   (i32.const 2)
+  )
+  (call $nomerge
+   (local.get $4)
+   (local.get $4)
+  )
+  (local.set $x
+   (i32.const 3)
+  )
+  (call $nomerge
+   (local.get $x)
+   (local.get $x)
+  )
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.const 4)
+   )
+  )
+  (call $nomerge
+   (local.get $x)
+   (local.get $x)
+  )
+  (local.set $5
+   (i32.const 5)
+  )
+  (call $nomerge
+   (local.get $5)
+   (local.get $5)
+  )
+  (if
+   (i32.const 1)
+   (local.set $x
+    (i32.const 6)
+   )
+   (local.set $x
+    (i32.const 7)
+   )
+  )
+  (call $nomerge
+   (local.get $x)
+   (local.get $x)
+  )
+ )
+ (func $simd-zero
+  (local $0 v128)
+  (v128.store align=4
+   (i32.const 0)
+   (i32x4.splat
+    (i32.const 0)
+   )
+  )
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/passes/ssa-nomerge_enable-simd.wast b/binaryen/test/passes/ssa-nomerge_enable-simd.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/ssa-nomerge_enable-simd.wast
@@ -0,0 +1,110 @@
+(module
+  (memory 1 1)
+  (global $global$0 (mut i32) (i32.const 1))
+  (func $basics (param $x i32)
+    (local $y i32)
+    (local $z f32)
+    (local $w i64)
+    (local $t f64)
+    (drop (local.get $x)) ;; keep as param get
+    (drop (local.get $y)) ;; turn into get of 0-init
+    (drop (local.get $z))
+    (drop (local.get $w))
+    (drop (local.get $t))
+    (local.set $x (i32.const 100)) ;; overwrite param
+    (drop (local.get $x)) ;; no longer a param!
+    (local.set $t (f64.const 2)) ;; overwrite local
+    (drop (local.get $t))
+    (local.set $t (f64.const 33)) ;; overwrite local AGAIN
+    (drop (local.get $t))
+    (drop (local.get $t)) ;; use twice
+  )
+  (func $if (param $p i32)
+    (local $x i32)
+    (local $y i32)
+    (drop
+      (if i32
+        (i32.const 1)
+        (local.get $x)
+        (local.get $y)
+      )
+    )
+    (if
+      (i32.const 1)
+      (local.set $x (i32.const 1))
+    )
+    (drop (local.get $x))
+    ;; same but with param
+    (if
+      (i32.const 1)
+      (local.set $p (i32.const 1))
+    )
+    (drop (local.get $p))
+    ;; if-else
+    (if
+      (i32.const 1)
+      (local.set $x (i32.const 2))
+      (nop)
+    )
+    (drop (local.get $x))
+    (if
+      (i32.const 1)
+      (nop)
+      (local.set $x (i32.const 3))
+    )
+    (drop (local.get $x))
+    (if
+      (i32.const 1)
+      (local.set $x (i32.const 4))
+      (local.set $x (i32.const 5))
+    )
+    (drop (local.get $x))
+    (if
+      (i32.const 1)
+      (local.set $x (i32.const 6))
+      (block
+        (local.set $x (i32.const 7))
+        (local.set $x (i32.const 8))
+      )
+    )
+    (drop (local.get $x))
+  )
+  (func $if2 (param $x i32)
+    (if
+      (i32.const 1)
+      (block
+        (local.set $x (i32.const 1))
+        (drop (local.get $x)) ;; use between phi set and use
+      )
+    )
+    (drop (local.get $x))
+  )
+  (func $nomerge (param $p i32) (param $q i32)
+    (local $x i32)
+    (local.set $x (i32.const 1)) ;; untangle this
+    (call $nomerge (local.get $x) (local.get $x))
+    (local.set $x (i32.const 2)) ;; and this
+    (call $nomerge (local.get $x) (local.get $x))
+    (local.set $x (i32.const 3)) ;; but this reaches a merge later
+    (call $nomerge (local.get $x) (local.get $x))
+    (if (i32.const 1)
+      (local.set $x (i32.const 4))
+    )
+    (call $nomerge (local.get $x) (local.get $x))
+    (local.set $x (i32.const 5)) ;; this is good again
+    (call $nomerge (local.get $x) (local.get $x))
+    (if (i32.const 1)
+      (local.set $x (i32.const 6)) ;; these merge,
+      (local.set $x (i32.const 7)) ;; so no
+    )
+    (call $nomerge (local.get $x) (local.get $x))
+  )
+  (func $simd-zero
+   (local $0 v128)
+   (v128.store align=4
+    (i32.const 0)
+    (local.get $0)
+   )
+   (unreachable)
+  )
+)
diff --git a/binaryen/test/passes/ssa_enable-threads.txt b/binaryen/test/passes/ssa_enable-threads.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/ssa_enable-threads.txt
@@ -0,0 +1,798 @@
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (global $global$0 (mut i32) (i32.const 1))
+ (func $basics (param $x i32)
+  (local $y i32)
+  (local $z f32)
+  (local $w i64)
+  (local $t f64)
+  (local $5 i32)
+  (local $6 f64)
+  (local $7 f64)
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (f32.const 0)
+  )
+  (drop
+   (i64.const 0)
+  )
+  (drop
+   (f64.const 0)
+  )
+  (local.set $5
+   (i32.const 100)
+  )
+  (drop
+   (local.get $5)
+  )
+  (local.set $6
+   (f64.const 2)
+  )
+  (drop
+   (local.get $6)
+  )
+  (local.set $7
+   (f64.const 33)
+  )
+  (drop
+   (local.get $7)
+  )
+  (drop
+   (local.get $7)
+  )
+ )
+ (func $if (param $p i32)
+  (local $x i32)
+  (local $y i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 i32)
+  (local $10 i32)
+  (local $11 i32)
+  (local $12 i32)
+  (local $13 i32)
+  (local $14 i32)
+  (local $15 i32)
+  (local $16 i32)
+  (local $17 i32)
+  (local.set $13
+   (local.get $p)
+  )
+  (block
+   (drop
+    (if (result i32)
+     (i32.const 1)
+     (i32.const 0)
+     (i32.const 0)
+    )
+   )
+   (if
+    (i32.const 1)
+    (local.set $3
+     (local.tee $15
+      (local.tee $14
+       (local.tee $12
+        (i32.const 1)
+       )
+      )
+     )
+    )
+   )
+   (drop
+    (local.get $12)
+   )
+   (if
+    (i32.const 1)
+    (local.set $4
+     (local.tee $13
+      (i32.const 1)
+     )
+    )
+   )
+   (drop
+    (local.get $13)
+   )
+   (if
+    (i32.const 1)
+    (local.set $5
+     (local.tee $15
+      (local.tee $14
+       (i32.const 2)
+      )
+     )
+    )
+    (nop)
+   )
+   (drop
+    (local.get $14)
+   )
+   (if
+    (i32.const 1)
+    (nop)
+    (local.set $6
+     (local.tee $15
+      (i32.const 3)
+     )
+    )
+   )
+   (drop
+    (local.get $15)
+   )
+   (if
+    (i32.const 1)
+    (local.set $7
+     (local.tee $16
+      (i32.const 4)
+     )
+    )
+    (local.set $8
+     (local.tee $16
+      (i32.const 5)
+     )
+    )
+   )
+   (drop
+    (local.get $16)
+   )
+   (if
+    (i32.const 1)
+    (local.set $9
+     (local.tee $17
+      (i32.const 6)
+     )
+    )
+    (block $block
+     (local.set $10
+      (i32.const 7)
+     )
+     (local.set $11
+      (local.tee $17
+       (i32.const 8)
+      )
+     )
+    )
+   )
+   (drop
+    (local.get $17)
+   )
+  )
+ )
+ (func $if2 (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $2
+   (local.get $x)
+  )
+  (block
+   (if
+    (i32.const 1)
+    (block $block
+     (local.set $1
+      (local.tee $2
+       (i32.const 1)
+      )
+     )
+     (drop
+      (local.get $1)
+     )
+    )
+   )
+   (drop
+    (local.get $2)
+   )
+  )
+ )
+ (func $block (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $2
+   (local.get $x)
+  )
+  (block
+   (block $out
+    (br_if $out
+     (i32.const 2)
+    )
+    (local.set $1
+     (local.tee $2
+      (i32.const 1)
+     )
+    )
+   )
+   (drop
+    (local.get $2)
+   )
+  )
+ )
+ (func $block2 (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (block $out
+   (local.set $1
+    (local.tee $6
+     (i32.const 1)
+    )
+   )
+   (drop
+    (local.get $1)
+   )
+   (br_if $out
+    (i32.const 2)
+   )
+   (drop
+    (local.get $1)
+   )
+   (if
+    (i32.const 3)
+    (block $block
+     (local.set $2
+      (local.tee $6
+       (i32.const 1)
+      )
+     )
+     (drop
+      (local.get $2)
+     )
+     (br $out)
+    )
+   )
+   (drop
+    (local.get $1)
+   )
+   (local.set $3
+    (local.tee $6
+     (i32.const 4)
+    )
+   )
+   (drop
+    (local.get $3)
+   )
+   (if
+    (i32.const 5)
+    (br $out)
+   )
+   (drop
+    (local.get $3)
+   )
+   (if
+    (i32.const 6)
+    (nop)
+   )
+   (if
+    (i32.const 7)
+    (nop)
+    (nop)
+   )
+   (block $in
+    (local.set $4
+     (local.tee $6
+      (i32.const 8)
+     )
+    )
+    (drop
+     (local.get $4)
+    )
+    (br_table $in $out
+     (i32.const 9)
+    )
+   )
+   (drop
+    (local.get $4)
+   )
+   (block $in2
+    (local.set $5
+     (local.tee $6
+      (i32.const 10)
+     )
+    )
+    (drop
+     (local.get $5)
+    )
+    (br_table $out $in2
+     (i32.const 11)
+    )
+   )
+   (drop
+    (local.get $5)
+   )
+  )
+  (drop
+   (local.get $6)
+  )
+ )
+ (func $loop (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local.set $2
+   (local.get $x)
+  )
+  (block
+   (drop
+    (local.get $x)
+   )
+   (loop $moar
+    (drop
+     (local.get $2)
+    )
+    (local.set $1
+     (local.tee $2
+      (i32.const 1)
+     )
+    )
+    (br_if $moar
+     (i32.const 2)
+    )
+   )
+   (drop
+    (local.get $1)
+   )
+  )
+ )
+ (func $loop2 (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local.set $4
+   (local.get $x)
+  )
+  (block
+   (drop
+    (local.get $x)
+   )
+   (loop $moar
+    (drop
+     (local.get $4)
+    )
+    (local.set $1
+     (i32.const 1)
+    )
+    (drop
+     (local.get $1)
+    )
+    (local.set $2
+     (local.tee $4
+      (i32.const 123)
+     )
+    )
+    (drop
+     (local.get $2)
+    )
+    (br_if $moar
+     (i32.const 2)
+    )
+    (drop
+     (local.get $2)
+    )
+    (local.set $3
+     (i32.const 3)
+    )
+    (drop
+     (local.get $3)
+    )
+   )
+   (drop
+    (local.get $3)
+   )
+  )
+ )
+ (func $loop2-zeroinit
+  (local $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (drop
+   (i32.const 0)
+  )
+  (loop $moar
+   (drop
+    (local.get $4)
+   )
+   (local.set $1
+    (i32.const 1)
+   )
+   (drop
+    (local.get $1)
+   )
+   (local.set $2
+    (local.tee $4
+     (i32.const 123)
+    )
+   )
+   (drop
+    (local.get $2)
+   )
+   (br_if $moar
+    (i32.const 2)
+   )
+   (drop
+    (local.get $2)
+   )
+   (local.set $3
+    (i32.const 3)
+   )
+   (drop
+    (local.get $3)
+   )
+  )
+  (drop
+   (local.get $3)
+  )
+ )
+ (func $real-loop (param $param i32)
+  (local $loopvar i32)
+  (local $inc i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local.set $3
+   (local.tee $6
+    (local.tee $5
+     (local.get $param)
+    )
+   )
+  )
+  (loop $more
+   (block $stop
+    (if
+     (i32.const 1)
+     (br $stop)
+    )
+    (local.set $inc
+     (i32.add
+      (local.get $5)
+      (i32.const 1)
+     )
+    )
+    (local.set $4
+     (local.tee $6
+      (local.tee $5
+       (local.get $inc)
+      )
+     )
+    )
+    (br $more)
+   )
+  )
+  (drop
+   (local.get $6)
+  )
+ )
+ (func $real-loop-outblock (param $param i32)
+  (local $loopvar i32)
+  (local $inc i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local.set $3
+   (local.tee $6
+    (local.tee $5
+     (local.get $param)
+    )
+   )
+  )
+  (block $stop
+   (loop $more
+    (if
+     (i32.const 1)
+     (br $stop)
+    )
+    (local.set $inc
+     (i32.add
+      (local.get $5)
+      (i32.const 1)
+     )
+    )
+    (local.set $4
+     (local.tee $6
+      (local.tee $5
+       (local.get $inc)
+      )
+     )
+    )
+    (br $more)
+   )
+  )
+  (drop
+   (local.get $6)
+  )
+ )
+ (func $loop-loop-param (param $param i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local.set $3
+   (local.get $param)
+  )
+  (local.set $4
+   (local.get $param)
+  )
+  (block
+   (loop $loop1
+    (block $out1
+     (if
+      (local.get $3)
+      (br $out1)
+     )
+     (local.set $1
+      (local.tee $4
+       (local.tee $3
+        (i32.const 1)
+       )
+      )
+     )
+     (br $loop1)
+    )
+   )
+   (loop $loop2
+    (block $out2
+     (if
+      (local.get $4)
+      (br $out2)
+     )
+     (local.set $2
+      (local.tee $4
+       (i32.const 2)
+      )
+     )
+     (br $loop2)
+    )
+   )
+  )
+ )
+ (func $loop-loop-param-nomerge (param $param i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (loop $loop1
+   (block $out1
+    (local.set $1
+     (local.tee $3
+      (i32.const 1)
+     )
+    )
+    (if
+     (local.get $1)
+     (br $out1)
+    )
+    (br $loop1)
+   )
+  )
+  (loop $loop2
+   (block $out2
+    (if
+     (local.get $3)
+     (br $out2)
+    )
+    (local.set $2
+     (local.tee $3
+      (i32.const 2)
+     )
+    )
+    (br $loop2)
+   )
+  )
+ )
+ (func $loop-nesting (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $3
+   (local.get $x)
+  )
+  (local.set $4
+   (local.get $x)
+  )
+  (local.set $5
+   (local.get $x)
+  )
+  (block
+   (block $out
+    (loop $loop1
+     (if
+      (local.get $3)
+      (br $out)
+     )
+     (loop $loop2
+      (if
+       (local.get $4)
+       (br $out)
+      )
+      (local.set $1
+       (local.tee $5
+        (local.tee $4
+         (i32.const 1)
+        )
+       )
+      )
+      (br $loop2)
+     )
+     (local.set $2
+      (local.tee $5
+       (local.tee $4
+        (local.tee $3
+         (i32.const 2)
+        )
+       )
+      )
+     )
+     (br $loop1)
+    )
+   )
+   (drop
+    (local.get $5)
+   )
+  )
+ )
+ (func $loop-nesting-2 (param $x i32)
+  (local $1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local.set $3
+   (local.get $x)
+  )
+  (local.set $4
+   (local.get $x)
+  )
+  (local.set $5
+   (local.get $x)
+  )
+  (block
+   (block $out
+    (loop $loop1
+     (if
+      (local.get $3)
+      (br $out)
+     )
+     (loop $loop2
+      (if
+       (local.get $4)
+       (br $out)
+      )
+      (local.set $1
+       (local.tee $5
+        (local.tee $4
+         (i32.const 1)
+        )
+       )
+      )
+      (br_if $loop2
+       (i32.const 3)
+      )
+     )
+     (local.set $2
+      (local.tee $5
+       (local.tee $4
+        (local.tee $3
+         (i32.const 2)
+        )
+       )
+      )
+     )
+     (br $loop1)
+    )
+   )
+   (drop
+    (local.get $5)
+   )
+  )
+ )
+ (func $func_6 (result i32)
+  (local $result i32)
+  (local $zero i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (loop $label$1
+   (if
+    (i32.eqz
+     (global.get $global$0)
+    )
+    (return
+     (local.get $4)
+    )
+   )
+   (global.set $global$0
+    (i32.const 0)
+   )
+   (local.set $2
+    (local.tee $4
+     (i32.const 1)
+    )
+   )
+   (br_if $label$1
+    (i32.const 0)
+   )
+   (local.set $3
+    (local.tee $4
+     (i32.const 0)
+    )
+   )
+   (br $label$1)
+  )
+ )
+ (func $ssa-merge-tricky (result i32)
+  (local $var$0 i32)
+  (local $var$1 i32)
+  (local $2 i32)
+  (local $3 i32)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local.set $3
+   (local.tee $8
+    (local.tee $2
+     (local.tee $7
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (loop $label$1
+   (if
+    (i32.eqz
+     (global.get $global$0)
+    )
+    (return
+     (i32.const 12345)
+    )
+   )
+   (global.set $global$0
+    (i32.const 0)
+   )
+   (if
+    (i32.eqz
+     (local.get $7)
+    )
+    (br_if $label$1
+     (i32.eqz
+      (local.tee $4
+       (local.tee $7
+        (i32.const 1)
+       )
+      )
+     )
+    )
+   )
+   (br_if $label$1
+    (i32.eqz
+     (local.tee $6
+      (local.tee $8
+       (local.tee $5
+        (local.tee $7
+         (local.get $8)
+        )
+       )
+      )
+     )
+    )
+   )
+  )
+  (i32.const -54)
+ )
+)
diff --git a/binaryen/test/passes/ssa_enable-threads.wast b/binaryen/test/passes/ssa_enable-threads.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/ssa_enable-threads.wast
@@ -0,0 +1,387 @@
+(module
+  (global $global$0 (mut i32) (i32.const 1))
+  (func $basics (param $x i32)
+    (local $y i32)
+    (local $z f32)
+    (local $w i64)
+    (local $t f64)
+    (drop (local.get $x)) ;; keep as param get
+    (drop (local.get $y)) ;; turn into get of 0-init
+    (drop (local.get $z))
+    (drop (local.get $w))
+    (drop (local.get $t))
+    (local.set $x (i32.const 100)) ;; overwrite param
+    (drop (local.get $x)) ;; no longer a param!
+    (local.set $t (f64.const 2)) ;; overwrite local
+    (drop (local.get $t))
+    (local.set $t (f64.const 33)) ;; overwrite local AGAIN
+    (drop (local.get $t))
+    (drop (local.get $t)) ;; use twice
+  )
+  (func $if (param $p i32)
+    (local $x i32)
+    (local $y i32)
+    (drop
+      (if i32
+        (i32.const 1)
+        (local.get $x)
+        (local.get $y)
+      )
+    )
+    (if
+      (i32.const 1)
+      (local.set $x (i32.const 1))
+    )
+    (drop (local.get $x))
+    ;; same but with param
+    (if
+      (i32.const 1)
+      (local.set $p (i32.const 1))
+    )
+    (drop (local.get $p))
+    ;; if-else
+    (if
+      (i32.const 1)
+      (local.set $x (i32.const 2))
+      (nop)
+    )
+    (drop (local.get $x))
+    (if
+      (i32.const 1)
+      (nop)
+      (local.set $x (i32.const 3))
+    )
+    (drop (local.get $x))
+    (if
+      (i32.const 1)
+      (local.set $x (i32.const 4))
+      (local.set $x (i32.const 5))
+    )
+    (drop (local.get $x))
+    (if
+      (i32.const 1)
+      (local.set $x (i32.const 6))
+      (block
+        (local.set $x (i32.const 7))
+        (local.set $x (i32.const 8))
+      )
+    )
+    (drop (local.get $x))
+  )
+  (func $if2 (param $x i32)
+    (if
+      (i32.const 1)
+      (block
+        (local.set $x (i32.const 1))
+        (drop (local.get $x)) ;; use between phi set and use
+      )
+    )
+    (drop (local.get $x))
+  )
+  (func $block (param $x i32)
+    (block $out
+      (br_if $out (i32.const 2))
+      (local.set $x (i32.const 1))
+    )
+    (drop (local.get $x))
+  )
+  (func $block2 (param $x i32)
+    (block $out
+      (local.set $x (i32.const 1))
+      (drop (local.get $x))
+      (br_if $out (i32.const 2))
+      (drop (local.get $x))
+      (if (i32.const 3)
+        (block
+          (local.set $x (i32.const 1))
+          (drop (local.get $x))
+          (br $out)
+        )
+      )
+      (drop (local.get $x))
+      (local.set $x (i32.const 4))
+      (drop (local.get $x))
+      (if (i32.const 5)
+        (br $out)
+      )
+      (drop (local.get $x))
+      (if (i32.const 6)
+        (nop)
+      )
+      (if (i32.const 7)
+        (nop)
+        (nop)
+      )
+      ;; finally, switching
+      (block $in
+        (local.set $x (i32.const 8))
+        (drop (local.get $x))
+        (br_table $in $out (i32.const 9))
+      )
+      (drop (local.get $x))
+      (block $in2
+        (local.set $x (i32.const 10))
+        (drop (local.get $x))
+        (br_table $out $in2 (i32.const 11))
+      )
+      (drop (local.get $x))
+    )
+    (drop (local.get $x))
+  )
+  (func $loop (param $x i32)
+    (drop (local.get $x))
+    (loop $moar
+      (drop (local.get $x))
+      (local.set $x (i32.const 1))
+      (br_if $moar (i32.const 2))
+    )
+    (drop (local.get $x))
+  )
+  (func $loop2 (param $x i32)
+    (drop (local.get $x))
+    (loop $moar
+      (drop (local.get $x))
+      (local.set $x (i32.const 1))
+      (drop (local.get $x))
+      (local.set $x (i32.const 123))
+      (drop (local.get $x))
+      (br_if $moar (i32.const 2))
+      (drop (local.get $x)) ;; add use in loop before it ends, we should update this to the phi
+      (local.set $x (i32.const 3))
+      (drop (local.get $x)) ;; another use, but should *not* be phi'd
+    )
+    (drop (local.get $x))
+  )
+  (func $loop2-zeroinit
+    (local $x i32)
+    (drop (local.get $x))
+    (loop $moar
+      (drop (local.get $x))
+      (local.set $x (i32.const 1))
+      (drop (local.get $x))
+      (local.set $x (i32.const 123))
+      (drop (local.get $x))
+      (br_if $moar (i32.const 2))
+      (drop (local.get $x)) ;; add use in loop before it ends, we should update this to the phi
+      (local.set $x (i32.const 3))
+      (drop (local.get $x)) ;; another use, but should *not* be phi'd
+    )
+    (drop (local.get $x))
+  )
+  (func $real-loop
+    (param $param i32)
+    (local $loopvar i32)
+    (local $inc i32)
+    (local.set $loopvar
+     (local.get $param)
+    )
+    (loop $more
+     (block $stop
+      (if
+       (i32.const 1)
+       (br $stop)
+      )
+      (local.set $inc
+       (i32.add
+        (local.get $loopvar) ;; this var should be written to from before the loop and the inc at the end
+        (i32.const 1)
+       )
+      )
+      (local.set $loopvar
+       (local.get $inc)
+      )
+      (br $more)
+     )
+    )
+    (drop (local.get $loopvar))
+  )
+  (func $real-loop-outblock
+    (param $param i32)
+    (local $loopvar i32)
+    (local $inc i32)
+    (local.set $loopvar
+     (local.get $param)
+    )
+    (block $stop
+     (loop $more
+      (if
+       (i32.const 1)
+       (br $stop)
+      )
+      (local.set $inc
+       (i32.add
+        (local.get $loopvar) ;; this var should be written to from before the loop and the inc at the end
+        (i32.const 1)
+       )
+      )
+      (local.set $loopvar
+       (local.get $inc)
+      )
+      (br $more)
+     )
+    )
+    (drop (local.get $loopvar))
+  )
+  (func $loop-loop-param
+    (param $param i32)
+    (loop $loop1
+      (block $out1
+        (if
+          (local.get $param)
+          (br $out1)
+        )
+        (local.set $param (i32.const 1))
+        (br $loop1)
+      )
+    )
+    (loop $loop2
+      (block $out2
+        (if
+          (local.get $param)
+          (br $out2)
+        )
+        (local.set $param (i32.const 2))
+        (br $loop2)
+      )
+    )
+  )
+  (func $loop-loop-param-nomerge
+    (param $param i32)
+    (loop $loop1
+      (block $out1
+        (local.set $param (i32.const 1))
+        (if
+          (local.get $param)
+          (br $out1)
+        )
+        (br $loop1)
+      )
+    )
+    (loop $loop2
+      (block $out2
+        (if
+          (local.get $param)
+          (br $out2)
+        )
+        (local.set $param (i32.const 2))
+        (br $loop2)
+      )
+    )
+  )
+  (func $loop-nesting
+    (param $x i32)
+    (block $out
+      (loop $loop1
+        (if
+          (local.get $x)
+          (br $out)
+        )
+        (loop $loop2
+          (if
+            (local.get $x)
+            (br $out)
+          )
+          (local.set $x (i32.const 1))
+          (br $loop2)
+        )
+        (local.set $x (i32.const 2))
+        (br $loop1)
+      )
+    )
+    (drop (local.get $x)) ;; can receive from either set, or input param
+  )
+  (func $loop-nesting-2
+    (param $x i32)
+    (block $out
+      (loop $loop1
+        (if
+          (local.get $x)
+          (br $out)
+        )
+        (loop $loop2
+          (if
+            (local.get $x)
+            (br $out)
+          )
+          (local.set $x (i32.const 1))
+          (br_if $loop2 (i32.const 3)) ;; add fallthrough
+        )
+        (local.set $x (i32.const 2))
+        (br $loop1)
+      )
+    )
+    (drop (local.get $x)) ;; can receive from either set, or input param
+  )
+  (func $func_6 (result i32)
+   (local $result i32)
+   (local $zero i32)
+   (loop $label$1
+    (if
+     (i32.eqz
+      (global.get $global$0)
+     )
+     (return
+      (local.get $result) ;; we eventually reach here
+     )
+    )
+    (global.set $global$0
+     (i32.const 0) ;; tell next iteration to return
+    )
+    (local.set $result
+     (i32.const 1) ;; set the return value to 1, temporarily
+    )
+    (br_if $label$1
+     (i32.const 0) ;; don't do anything here
+    )
+    (local.set $result
+     (local.get $zero) ;; set it to zero instead
+    )
+    (br $label$1) ;; back to the top, where we will return the zero
+   )
+  )
+  (func $ssa-merge-tricky (result i32)
+   (local $var$0 i32)
+   (local $var$1 i32)
+   (local.set $var$1
+    (local.tee $var$0
+     (i32.const 0) ;; both vars start out identical
+    )
+   )
+   (loop $label$1
+    (if
+     (i32.eqz
+      (global.get $global$0)
+     )
+     (return
+      (i32.const 12345)
+     )
+    )
+    (global.set $global$0
+     (i32.const 0)
+    )
+    (if
+     (i32.eqz
+      (local.get $var$0) ;; check $0 here. this will get a phi var
+     )
+     (br_if $label$1
+      (i32.eqz
+       (local.tee $var$0 ;; set $0 to 1. here the two diverge. for the phi, we'll get a set here and above
+        (i32.const 1)
+       )
+      )
+     )
+    )
+    (br_if $label$1
+     (i32.eqz ;; indeed equal, enter loop again, and then hang prevention kicks in
+      (local.tee $var$1 ;; set them all to 0
+       (local.tee $var$0
+        (local.get $var$1) ;; this must get $1, not the phis, as even though the sets appear in both sources, we only execute 1.
+       )
+      )
+     )
+    )
+   )
+   (i32.const -54)
+  )
+)
+
diff --git a/binaryen/test/passes/ssa_fuzz-exec_enable-threads.txt b/binaryen/test/passes/ssa_fuzz-exec_enable-threads.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/ssa_fuzz-exec_enable-threads.txt
@@ -0,0 +1,129 @@
+[fuzz-exec] calling func_0
+[fuzz-exec] note result: func_0 => 16384
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 (shared 1 1))
+ (table $0 0 0 funcref)
+ (export "func_0" (func $0))
+ (func $0 (result i32)
+  (local $var$0 i32)
+  (local $var$1 i32)
+  (local $var$2 i32)
+  (local $var$3 f64)
+  (local $4 i32)
+  (local $5 i32)
+  (local $6 i32)
+  (local $7 i32)
+  (local $8 i32)
+  (local $9 f64)
+  (local $10 i32)
+  (local $11 i32)
+  (block $label$1 (result i32)
+   (if (result i32)
+    (i32.const 0)
+    (unreachable)
+    (block $label$4 (result i32)
+     (loop $label$5
+      (block $label$6
+       (block $label$7
+        (local.set $8
+         (if (result i32)
+          (local.get $10)
+          (select
+           (loop $label$9 (result i32)
+            (if (result i32)
+             (local.tee $4
+              (i32.const 16384)
+             )
+             (i32.const 1)
+             (i32.const 0)
+            )
+           )
+           (br_if $label$4
+            (i32.const 0)
+            (local.tee $var$1
+             (local.tee $5
+              (block $label$12 (result i32)
+               (br_if $label$5
+                (br $label$6)
+               )
+               (unreachable)
+              )
+             )
+            )
+           )
+           (i32.const 1)
+          )
+          (block $block (result i32)
+           (loop $label$15
+            (if
+             (i32.const 0)
+             (return
+              (local.get $11)
+             )
+            )
+            (if
+             (local.tee $var$1
+              (local.tee $6
+               (local.tee $11
+                (i32.const 0)
+               )
+              )
+             )
+             (block $block4
+              (br_if $label$15
+               (i32.const 0)
+              )
+             )
+            )
+            (br_if $label$15
+             (i32.eqz
+              (local.tee $7
+               (local.tee $11
+                (local.tee $10
+                 (i32.const 129)
+                )
+               )
+              )
+             )
+            )
+           )
+           (i32.const -5742806)
+          )
+         )
+        )
+       )
+       (br_if $label$6
+        (if (result i32)
+         (local.get $var$1)
+         (unreachable)
+         (block $label$25 (result i32)
+          (local.set $9
+           (block $label$26 (result f64)
+            (drop
+             (br_if $label$4
+              (br_if $label$25
+               (br $label$5)
+               (i32.const 0)
+              )
+              (i32.const 0)
+             )
+            )
+            (f64.const 1)
+           )
+          )
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (local.get $4)
+    )
+   )
+  )
+ )
+)
+[fuzz-exec] calling func_0
+[fuzz-exec] note result: func_0 => 16384
+[fuzz-exec] comparing func_0
diff --git a/binaryen/test/passes/ssa_fuzz-exec_enable-threads.wast b/binaryen/test/passes/ssa_fuzz-exec_enable-threads.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/ssa_fuzz-exec_enable-threads.wast
@@ -0,0 +1,112 @@
+(module
+ (type $0 (func (result i32)))
+ (type $1 (func))
+ (table 0 0 funcref)
+ (memory $0 (shared 1 1))
+ (export "func_0" (func $0))
+ (func $0 (; 0 ;) (type $0) (result i32)
+  (local $var$0 i32)
+  (local $var$1 i32)
+  (local $var$2 i32)
+  (local $var$3 f64)
+  (block $label$1 (result i32)
+   (if (result i32)
+    (i32.const 0)
+    (unreachable)
+    (block $label$4 (result i32)
+     (loop $label$5
+      (block $label$6
+       (block $label$7
+        (local.set $var$0
+         (if (result i32)
+          (local.get $var$2)
+          (select
+           (loop $label$9 (result i32)
+            (if (result i32)
+             (local.tee $var$2
+              (i32.const 16384)
+             )
+             (i32.const 1)
+             (i32.const 0)
+            )
+           )
+           (br_if $label$4
+            (i32.const 0)
+            (local.tee $var$1
+             (local.tee $var$2
+              (block $label$12 (result i32)
+               (br_if $label$5
+                (br $label$6)
+               )
+               (unreachable)
+              )
+             )
+            )
+           )
+           (i32.const 1)
+          )
+          (block (result i32)
+           (loop $label$15
+            (if
+             (i32.const 0)
+             (return
+              (local.get $var$2)
+             )
+            )
+            (if
+             (local.tee $var$1
+              (local.tee $var$2
+               (i32.const 0)
+              )
+             )
+             (block
+              (br_if $label$15
+               (i32.const 0)
+              )
+             )
+            )
+            (br_if $label$15
+             (i32.eqz
+              (local.tee $var$2
+               (i32.const 129)
+              )
+             )
+            )
+           )
+           (i32.const -5742806)
+          )
+         )
+        )
+       )
+       (br_if $label$6
+        (if (result i32)
+         (local.get $var$1)
+         (unreachable)
+         (block $label$25 (result i32)
+          (local.set $var$3
+           (block $label$26 (result f64)
+            (drop
+             (br_if $label$4
+              (br_if $label$25
+               (br $label$5)
+               (i32.const 0)
+              )
+              (i32.const 0)
+             )
+            )
+            (f64.const 1)
+           )
+          )
+          (i32.const 0)
+         )
+        )
+       )
+      )
+     )
+     (local.get $var$2)
+    )
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/passes/stack-check_enable-mutable-globals.txt b/binaryen/test/passes/stack-check_enable-mutable-globals.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/stack-check_enable-mutable-globals.txt
@@ -0,0 +1,41 @@
+(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))
+ (export "use_stack" (func $0))
+ (export "__set_stack_limits" (func $__set_stack_limits))
+ (func $0 (result i32)
+  (local $0 i32)
+  (block
+   (if
+    (i32.or
+     (i32.gt_u
+      (local.tee $0
+       (i32.const 42)
+      )
+      (global.get $__stack_base)
+     )
+     (i32.lt_u
+      (local.get $0)
+      (global.get $__stack_limit)
+     )
+    )
+    (unreachable)
+   )
+   (global.set $sp
+    (local.get $0)
+   )
+  )
+  (global.get $sp)
+ )
+ (func $__set_stack_limits (param $0 i32) (param $1 i32)
+  (global.set $__stack_base
+   (local.get $0)
+  )
+  (global.set $__stack_limit
+   (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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/stack-check_enable-mutable-globals.wast
@@ -0,0 +1,7 @@
+(module
+ (import "env" "__stack_pointer" (global $sp (mut i32)))
+ (func "use_stack" (result i32)
+  (global.set $sp (i32.const 42))
+  (global.get $sp)
+ )
+)
diff --git a/binaryen/test/passes/strip-debug.bin.txt b/binaryen/test/passes/strip-debug.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/strip-debug.bin.txt
@@ -0,0 +1,15 @@
+(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))
+ (func $0 (result i32)
+  (local $0 i32)
+  (local.set $0
+   (i32.const 1)
+  )
+  (return
+   (local.get $0)
+  )
+ )
+ ;; custom section "zinking", size 28
+)
diff --git a/binaryen/test/passes/strip-debug.wasm b/binaryen/test/passes/strip-debug.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/strip-debug.wasm differ
diff --git a/binaryen/test/passes/strip-dwarf.bin.txt b/binaryen/test/passes/strip-dwarf.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/strip-dwarf.bin.txt
@@ -0,0 +1,32 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (import "env" "__wasm_call_ctors" (func $fimport$0))
+ (import "env" "dlmalloc" (func $fimport$1 (param i32) (result i32)))
+ (import "env" "dlfree" (func $fimport$2 (param i32)))
+ (import "env" "setThrew" (func $fimport$3 (param i32 i32)))
+ (import "env" "stackSave" (func $fimport$4 (result i32)))
+ (import "env" "stackAlloc" (func $fimport$5 (param i32) (result i32)))
+ (import "env" "stackRestore" (func $fimport$6 (param i32)))
+ (import "env" "__growWasmMemory" (func $fimport$7 (param i32) (result i32)))
+ (global $global$0 i32 (i32.const 1532))
+ (export "__wasm_call_ctors" (func $fimport$0))
+ (export "_Z3foov" (func $fimport$0))
+ (export "__errno_location" (func $0))
+ (export "setThrew" (func $fimport$3))
+ (export "malloc" (func $fimport$1))
+ (export "free" (func $fimport$2))
+ (export "__data_end" (global $global$0))
+ (export "stackSave" (func $fimport$4))
+ (export "stackAlloc" (func $fimport$5))
+ (export "stackRestore" (func $fimport$6))
+ (export "__growWasmMemory" (func $fimport$7))
+ (func $0 (result i32)
+  (i32.const 1024)
+ )
+ ;; custom section "sourceMappingURL", size 15
+ ;; custom section "sourceMappingURL", size 15
+)
diff --git a/binaryen/test/passes/strip-dwarf.wasm b/binaryen/test/passes/strip-dwarf.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/strip-dwarf.wasm differ
diff --git a/binaryen/test/passes/strip-producers.bin.txt b/binaryen/test/passes/strip-producers.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/strip-producers.bin.txt
@@ -0,0 +1,22 @@
+(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))
+ (func $0 (result i32)
+  (local $0 i32)
+  (local.set $0
+   (i32.const 1)
+  )
+  (return
+   (local.get $0)
+  )
+ )
+ ;; custom section ".debug_str", size 246
+ ;; custom section ".debug_abbrev", size 52
+ ;; custom section ".debug_info", size 69
+ ;; custom section ".debug_macinfo", size 1
+ ;; custom section ".debug_line", size 56
+ ;; custom section "zinking", size 28
+ ;; custom section "reloc..debug_info", size 47
+ ;; custom section "reloc..debug_line", size 6
+)
diff --git a/binaryen/test/passes/strip-producers.wasm b/binaryen/test/passes/strip-producers.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/strip-producers.wasm differ
diff --git a/binaryen/test/passes/strip-target-features.bin.txt b/binaryen/test/passes/strip-target-features.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/strip-target-features.bin.txt
@@ -0,0 +1,3 @@
+(module
+ ;; custom section "linking", size 1
+)
diff --git a/binaryen/test/passes/strip-target-features.wasm b/binaryen/test/passes/strip-target-features.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/strip-target-features.wasm differ
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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/strip-target-features_roundtrip_print-features_all-features.txt
@@ -0,0 +1,24 @@
+--enable-threads
+--enable-mutable-globals
+--enable-nontrapping-float-to-int
+--enable-simd
+--enable-bulk-memory
+--enable-sign-ext
+--enable-exception-handling
+--enable-tail-call
+--enable-reference-types
+--enable-multivalue
+--enable-gc
+--enable-memory64
+(module
+ (type $none_=>_v128_externref (func (result v128 externref)))
+ (func $foo (result v128 externref)
+  (tuple.make
+   (v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
+   (ref.null extern)
+  )
+ )
+ (func $bar (result v128 externref)
+  (return_call $foo)
+ )
+)
diff --git a/binaryen/test/passes/strip-target-features_roundtrip_print-features_all-features.wast b/binaryen/test/passes/strip-target-features_roundtrip_print-features_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/strip-target-features_roundtrip_print-features_all-features.wast
@@ -0,0 +1,14 @@
+;; Test that features enabled on the IR Module survive a round trip
+;; even if the target features section is stripped first
+
+(module
+  (func $foo (result v128 externref )
+    (tuple.make
+      (v128.const i32x4 0 0 0 0)
+      (ref.null extern)
+    )
+  )
+  (func $bar (result v128 externref)
+    (return_call $foo)
+  )
+)
diff --git a/binaryen/test/passes/stub-unsupported-js.txt b/binaryen/test/passes/stub-unsupported-js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/stub-unsupported-js.txt
@@ -0,0 +1,50 @@
+(module
+ (type $none_=>_f32 (func (result f32)))
+ (type $i32_=>_f32 (func (param i32) (result f32)))
+ (type $i64_=>_f32 (func (param i64) (result f32)))
+ (func $yes (param $x i64) (result f32)
+  (drop
+   (local.get $x)
+  )
+  (f32.const 0)
+ )
+ (func $no (param $x i32) (result f32)
+  (f32.convert_i32_u
+   (local.get $x)
+  )
+ )
+ (func $yes-unreach (result f32)
+  (unreachable)
+ )
+ (func $no-unreach (result f32)
+  (f32.convert_i32_u
+   (unreachable)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_f32 (func (result f32)))
+ (table $0 2 2 funcref)
+ (elem (i32.const 1) $return-f32)
+ (func $return-f32 (result f32)
+  (f32.const 3.141590118408203)
+ )
+ (func $bad-indirect-call
+  (drop
+   (i32.const 1)
+  )
+ )
+ (func $bad-indirect-call-2 (result i32)
+  (block
+   (drop
+    (i64.const 1234)
+   )
+   (drop
+    (i32.const 1)
+   )
+  )
+  (i32.const 0)
+ )
+)
diff --git a/binaryen/test/passes/stub-unsupported-js.wast b/binaryen/test/passes/stub-unsupported-js.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/stub-unsupported-js.wast
@@ -0,0 +1,35 @@
+(module
+ (func $yes (param $x i64) (result f32)
+  (f32.convert_i64_u (local.get $x))
+ )
+ (func $no (param $x i32) (result f32)
+  (f32.convert_i32_u (local.get $x))
+ )
+ (func $yes-unreach (result f32)
+  (f32.convert_i64_u (unreachable))
+ )
+ (func $no-unreach (result f32)
+  (f32.convert_i32_u (unreachable))
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i64_=>_i32 (func (param $foo i64) (result i32)))
+ (table $0 2 2 funcref)
+ (elem (i32.const 1) $return-f32)
+ (func $return-f32 (result f32)
+  (f32.const 3.14159)
+ )
+ (func $bad-indirect-call
+  (call_indirect (type $none_=>_none) ;; note how it's the wrong type
+   (i32.const 1)
+  )
+ )
+ (func $bad-indirect-call-2 (result i32)
+  (call_indirect (type $i64_=>_i32) ;; note how it's the wrong type
+   (i64.const 1234)
+   (i32.const 1)
+  )
+ )
+)
+
diff --git a/binaryen/test/passes/too_much_for_liveness.bin.txt b/binaryen/test/passes/too_much_for_liveness.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/too_much_for_liveness.bin.txt
@@ -0,0 +1,35 @@
+total
+ [events]       : 0       
+ [exports]      : 1       
+ [funcs]        : 1       
+ [globals]      : 0       
+ [imports]      : 0       
+ [total]        : 4       
+ [vars]         : 65536   
+ block          : 1       
+ const          : 1       
+ local.get      : 1       
+ local.set      : 1       
+total
+ [events]       : 0       
+ [exports]      : 1       
+ [funcs]        : 1       
+ [globals]      : 0       
+ [imports]      : 0       
+ [total]        : 4       
+ [vars]         : 65536   
+ block          : 1       
+ const          : 1       
+ local.get      : 1       
+ local.set      : 1       
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (export "foo" (func $0))
+ (func $0 (result i32)
+  (local $0 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (local.get $0)
+ )
+)
diff --git a/binaryen/test/passes/too_much_for_liveness.passes b/binaryen/test/passes/too_much_for_liveness.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/too_much_for_liveness.passes
@@ -0,0 +1,1 @@
+metrics_coalesce-locals_metrics_reorder-locals
diff --git a/binaryen/test/passes/too_much_for_liveness.wasm b/binaryen/test/passes/too_much_for_liveness.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/too_much_for_liveness.wasm differ
diff --git a/binaryen/test/passes/translate-to-fuzz_all-features.txt b/binaryen/test/passes/translate-to-fuzz_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/translate-to-fuzz_all-features.txt
@@ -0,0 +1,1018 @@
+(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)
+  )
+ )
+ (func $hangLimitInitializer
+  (global.set $hangLimit
+   (i32.const 10)
+  )
+ )
+)
diff --git a/binaryen/test/passes/translate-to-fuzz_all-features.wast b/binaryen/test/passes/translate-to-fuzz_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/translate-to-fuzz_all-features.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/trap-mode-clamp.txt b/binaryen/test/passes/trap-mode-clamp.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/trap-mode-clamp.txt
@@ -0,0 +1,437 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i64_i64_=>_i64 (func (param i64 i64) (result i64)))
+ (type $i32_i64_=>_none (func (param i32 i64)))
+ (type $f32_=>_i32 (func (param f32) (result i32)))
+ (type $f64_=>_i32 (func (param f64) (result i32)))
+ (type $f32_=>_i64 (func (param f32) (result i64)))
+ (type $f64_=>_i64 (func (param f64) (result i64)))
+ (type $f32_=>_none (func (param f32)))
+ (type $f64_=>_none (func (param f64)))
+ (func $test_div (param $0 i32) (param $1 i64)
+  (drop
+   (call $i32s-div
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $i32u-div
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $i64s-div
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (call $i64u-div
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $test_rem (param $0 i32) (param $1 i64)
+  (drop
+   (call $i32s-rem
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $i32u-rem
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $i64s-rem
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (call $i64u-rem
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $test_f32_to_int (param $0 f32)
+  (drop
+   (call $f32-to-int
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $f32-to-uint
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $f32-to-int64
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $f32-to-uint64
+    (local.get $0)
+   )
+  )
+ )
+ (func $test_f64_to_int (param $0 f64)
+  (drop
+   (call $f64-to-int
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $f64-to-uint
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $f64-to-int64
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $f64-to-uint64
+    (local.get $0)
+   )
+  )
+ )
+ (func $f32-to-int (param $0 f32) (result i32)
+  (if (result i32)
+   (f32.ne
+    (local.get $0)
+    (local.get $0)
+   )
+   (i32.const -2147483648)
+   (if (result i32)
+    (f32.ge
+     (local.get $0)
+     (f32.const 2147483648)
+    )
+    (i32.const -2147483648)
+    (if (result i32)
+     (f32.le
+      (local.get $0)
+      (f32.const -2147483648)
+     )
+     (i32.const -2147483648)
+     (i32.trunc_f32_s
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $f32-to-int64 (param $0 f32) (result i64)
+  (if (result i64)
+   (f32.ne
+    (local.get $0)
+    (local.get $0)
+   )
+   (i64.const -9223372036854775808)
+   (if (result i64)
+    (f32.ge
+     (local.get $0)
+     (f32.const 9223372036854775808)
+    )
+    (i64.const -9223372036854775808)
+    (if (result i64)
+     (f32.le
+      (local.get $0)
+      (f32.const -9223372036854775808)
+     )
+     (i64.const -9223372036854775808)
+     (i64.trunc_f32_s
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $f32-to-uint (param $0 f32) (result i32)
+  (if (result i32)
+   (f32.ne
+    (local.get $0)
+    (local.get $0)
+   )
+   (i32.const 0)
+   (if (result i32)
+    (f32.ge
+     (local.get $0)
+     (f32.const 4294967296)
+    )
+    (i32.const 0)
+    (if (result i32)
+     (f32.le
+      (local.get $0)
+      (f32.const -1)
+     )
+     (i32.const 0)
+     (i32.trunc_f32_u
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $f32-to-uint64 (param $0 f32) (result i64)
+  (if (result i64)
+   (f32.ne
+    (local.get $0)
+    (local.get $0)
+   )
+   (i64.const 0)
+   (if (result i64)
+    (f32.ge
+     (local.get $0)
+     (f32.const 18446744073709551615)
+    )
+    (i64.const 0)
+    (if (result i64)
+     (f32.le
+      (local.get $0)
+      (f32.const -1)
+     )
+     (i64.const 0)
+     (i64.trunc_f32_u
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $f64-to-int (param $0 f64) (result i32)
+  (if (result i32)
+   (f64.ne
+    (local.get $0)
+    (local.get $0)
+   )
+   (i32.const -2147483648)
+   (if (result i32)
+    (f64.ge
+     (local.get $0)
+     (f64.const 2147483648)
+    )
+    (i32.const -2147483648)
+    (if (result i32)
+     (f64.le
+      (local.get $0)
+      (f64.const -2147483649)
+     )
+     (i32.const -2147483648)
+     (i32.trunc_f64_s
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $f64-to-int64 (param $0 f64) (result i64)
+  (if (result i64)
+   (f64.ne
+    (local.get $0)
+    (local.get $0)
+   )
+   (i64.const -9223372036854775808)
+   (if (result i64)
+    (f64.ge
+     (local.get $0)
+     (f64.const 9223372036854775808)
+    )
+    (i64.const -9223372036854775808)
+    (if (result i64)
+     (f64.le
+      (local.get $0)
+      (f64.const -9223372036854775808)
+     )
+     (i64.const -9223372036854775808)
+     (i64.trunc_f64_s
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $f64-to-uint (param $0 f64) (result i32)
+  (if (result i32)
+   (f64.ne
+    (local.get $0)
+    (local.get $0)
+   )
+   (i32.const 0)
+   (if (result i32)
+    (f64.ge
+     (local.get $0)
+     (f64.const 4294967296)
+    )
+    (i32.const 0)
+    (if (result i32)
+     (f64.le
+      (local.get $0)
+      (f64.const -1)
+     )
+     (i32.const 0)
+     (i32.trunc_f64_u
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $f64-to-uint64 (param $0 f64) (result i64)
+  (if (result i64)
+   (f64.ne
+    (local.get $0)
+    (local.get $0)
+   )
+   (i64.const 0)
+   (if (result i64)
+    (f64.ge
+     (local.get $0)
+     (f64.const 18446744073709551615)
+    )
+    (i64.const 0)
+    (if (result i64)
+     (f64.le
+      (local.get $0)
+      (f64.const -1)
+     )
+     (i64.const 0)
+     (i64.trunc_f64_u
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $i32s-div (param $0 i32) (param $1 i32) (result i32)
+  (if (result i32)
+   (i32.eqz
+    (local.get $1)
+   )
+   (i32.const 0)
+   (if (result i32)
+    (i32.and
+     (i32.eq
+      (local.get $0)
+      (i32.const -2147483648)
+     )
+     (i32.eq
+      (local.get $1)
+      (i32.const -1)
+     )
+    )
+    (i32.const 0)
+    (i32.div_s
+     (local.get $0)
+     (local.get $1)
+    )
+   )
+  )
+ )
+ (func $i32s-rem (param $0 i32) (param $1 i32) (result i32)
+  (if (result i32)
+   (i32.eqz
+    (local.get $1)
+   )
+   (i32.const 0)
+   (i32.rem_s
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+ (func $i32u-div (param $0 i32) (param $1 i32) (result i32)
+  (if (result i32)
+   (i32.eqz
+    (local.get $1)
+   )
+   (i32.const 0)
+   (i32.div_u
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+ (func $i32u-rem (param $0 i32) (param $1 i32) (result i32)
+  (if (result i32)
+   (i32.eqz
+    (local.get $1)
+   )
+   (i32.const 0)
+   (i32.rem_u
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+ (func $i64s-div (param $0 i64) (param $1 i64) (result i64)
+  (if (result i64)
+   (i64.eqz
+    (local.get $1)
+   )
+   (i64.const 0)
+   (if (result i64)
+    (i32.and
+     (i64.eq
+      (local.get $0)
+      (i64.const -9223372036854775808)
+     )
+     (i64.eq
+      (local.get $1)
+      (i64.const -1)
+     )
+    )
+    (i64.const 0)
+    (i64.div_s
+     (local.get $0)
+     (local.get $1)
+    )
+   )
+  )
+ )
+ (func $i64s-rem (param $0 i64) (param $1 i64) (result i64)
+  (if (result i64)
+   (i64.eqz
+    (local.get $1)
+   )
+   (i64.const 0)
+   (i64.rem_s
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+ (func $i64u-div (param $0 i64) (param $1 i64) (result i64)
+  (if (result i64)
+   (i64.eqz
+    (local.get $1)
+   )
+   (i64.const 0)
+   (i64.div_u
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+ (func $i64u-rem (param $0 i64) (param $1 i64) (result i64)
+  (if (result i64)
+   (i64.eqz
+    (local.get $1)
+   )
+   (i64.const 0)
+   (i64.rem_u
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/trap-mode-clamp.wast b/binaryen/test/passes/trap-mode-clamp.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/trap-mode-clamp.wast
@@ -0,0 +1,26 @@
+(module
+ (func $test_div (param $0 i32) (param $1 i64)
+  (drop (i32.div_s (local.get $0) (local.get $0)))
+  (drop (i32.div_u (local.get $0) (local.get $0)))
+  (drop (i64.div_s (local.get $1) (local.get $1)))
+  (drop (i64.div_u (local.get $1) (local.get $1)))
+ )
+ (func $test_rem (param $0 i32) (param $1 i64)
+  (drop (i32.rem_s (local.get $0) (local.get $0)))
+  (drop (i32.rem_u (local.get $0) (local.get $0)))
+  (drop (i64.rem_s (local.get $1) (local.get $1)))
+  (drop (i64.rem_u (local.get $1) (local.get $1)))
+ )
+ (func $test_f32_to_int (param $0 f32)
+  (drop (i32.trunc_f32_s (local.get $0)))
+  (drop (i32.trunc_f32_u (local.get $0)))
+  (drop (i64.trunc_f32_s (local.get $0)))
+  (drop (i64.trunc_f32_u (local.get $0)))
+ )
+ (func $test_f64_to_int (param $0 f64)
+  (drop (i32.trunc_f64_s (local.get $0)))
+  (drop (i32.trunc_f64_u (local.get $0)))
+  (drop (i64.trunc_f64_s (local.get $0)))
+  (drop (i64.trunc_f64_u (local.get $0)))
+ )
+)
diff --git a/binaryen/test/passes/trap-mode-js.txt b/binaryen/test/passes/trap-mode-js.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/trap-mode-js.txt
@@ -0,0 +1,337 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i64_i64_=>_i64 (func (param i64 i64) (result i64)))
+ (type $i32_i64_=>_none (func (param i32 i64)))
+ (type $f32_=>_i64 (func (param f32) (result i64)))
+ (type $f64_=>_i64 (func (param f64) (result i64)))
+ (type $f32_=>_none (func (param f32)))
+ (type $f64_=>_none (func (param f64)))
+ (type $f64_=>_i32 (func (param f64) (result i32)))
+ (import "asm2wasm" "f64-to-int" (func $f64-to-int (param f64) (result i32)))
+ (func $test_div (param $0 i32) (param $1 i64)
+  (drop
+   (call $i32s-div
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $i32u-div
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $i64s-div
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (call $i64u-div
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $test_rem (param $0 i32) (param $1 i64)
+  (drop
+   (call $i32s-rem
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $i32u-rem
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $i64s-rem
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (call $i64u-rem
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+ )
+ (func $test_f32_to_int (param $0 f32)
+  (drop
+   (call $f64-to-int
+    (f64.promote_f32
+     (local.get $0)
+    )
+   )
+  )
+  (drop
+   (call $f64-to-int
+    (f64.promote_f32
+     (local.get $0)
+    )
+   )
+  )
+  (drop
+   (call $f32-to-int64
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $f32-to-uint64
+    (local.get $0)
+   )
+  )
+ )
+ (func $test_f64_to_int (param $0 f64)
+  (drop
+   (call $f64-to-int
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $f64-to-int
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $f64-to-int64
+    (local.get $0)
+   )
+  )
+  (drop
+   (call $f64-to-uint64
+    (local.get $0)
+   )
+  )
+ )
+ (func $f32-to-int64 (param $0 f32) (result i64)
+  (if (result i64)
+   (f32.ne
+    (local.get $0)
+    (local.get $0)
+   )
+   (i64.const -9223372036854775808)
+   (if (result i64)
+    (f32.ge
+     (local.get $0)
+     (f32.const 9223372036854775808)
+    )
+    (i64.const -9223372036854775808)
+    (if (result i64)
+     (f32.le
+      (local.get $0)
+      (f32.const -9223372036854775808)
+     )
+     (i64.const -9223372036854775808)
+     (i64.trunc_f32_s
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $f32-to-uint64 (param $0 f32) (result i64)
+  (if (result i64)
+   (f32.ne
+    (local.get $0)
+    (local.get $0)
+   )
+   (i64.const 0)
+   (if (result i64)
+    (f32.ge
+     (local.get $0)
+     (f32.const 18446744073709551615)
+    )
+    (i64.const 0)
+    (if (result i64)
+     (f32.le
+      (local.get $0)
+      (f32.const -1)
+     )
+     (i64.const 0)
+     (i64.trunc_f32_u
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $f64-to-int64 (param $0 f64) (result i64)
+  (if (result i64)
+   (f64.ne
+    (local.get $0)
+    (local.get $0)
+   )
+   (i64.const -9223372036854775808)
+   (if (result i64)
+    (f64.ge
+     (local.get $0)
+     (f64.const 9223372036854775808)
+    )
+    (i64.const -9223372036854775808)
+    (if (result i64)
+     (f64.le
+      (local.get $0)
+      (f64.const -9223372036854775808)
+     )
+     (i64.const -9223372036854775808)
+     (i64.trunc_f64_s
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $f64-to-uint64 (param $0 f64) (result i64)
+  (if (result i64)
+   (f64.ne
+    (local.get $0)
+    (local.get $0)
+   )
+   (i64.const 0)
+   (if (result i64)
+    (f64.ge
+     (local.get $0)
+     (f64.const 18446744073709551615)
+    )
+    (i64.const 0)
+    (if (result i64)
+     (f64.le
+      (local.get $0)
+      (f64.const -1)
+     )
+     (i64.const 0)
+     (i64.trunc_f64_u
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+ (func $i32s-div (param $0 i32) (param $1 i32) (result i32)
+  (if (result i32)
+   (i32.eqz
+    (local.get $1)
+   )
+   (i32.const 0)
+   (if (result i32)
+    (i32.and
+     (i32.eq
+      (local.get $0)
+      (i32.const -2147483648)
+     )
+     (i32.eq
+      (local.get $1)
+      (i32.const -1)
+     )
+    )
+    (i32.const 0)
+    (i32.div_s
+     (local.get $0)
+     (local.get $1)
+    )
+   )
+  )
+ )
+ (func $i32s-rem (param $0 i32) (param $1 i32) (result i32)
+  (if (result i32)
+   (i32.eqz
+    (local.get $1)
+   )
+   (i32.const 0)
+   (i32.rem_s
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+ (func $i32u-div (param $0 i32) (param $1 i32) (result i32)
+  (if (result i32)
+   (i32.eqz
+    (local.get $1)
+   )
+   (i32.const 0)
+   (i32.div_u
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+ (func $i32u-rem (param $0 i32) (param $1 i32) (result i32)
+  (if (result i32)
+   (i32.eqz
+    (local.get $1)
+   )
+   (i32.const 0)
+   (i32.rem_u
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+ (func $i64s-div (param $0 i64) (param $1 i64) (result i64)
+  (if (result i64)
+   (i64.eqz
+    (local.get $1)
+   )
+   (i64.const 0)
+   (if (result i64)
+    (i32.and
+     (i64.eq
+      (local.get $0)
+      (i64.const -9223372036854775808)
+     )
+     (i64.eq
+      (local.get $1)
+      (i64.const -1)
+     )
+    )
+    (i64.const 0)
+    (i64.div_s
+     (local.get $0)
+     (local.get $1)
+    )
+   )
+  )
+ )
+ (func $i64s-rem (param $0 i64) (param $1 i64) (result i64)
+  (if (result i64)
+   (i64.eqz
+    (local.get $1)
+   )
+   (i64.const 0)
+   (i64.rem_s
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+ (func $i64u-div (param $0 i64) (param $1 i64) (result i64)
+  (if (result i64)
+   (i64.eqz
+    (local.get $1)
+   )
+   (i64.const 0)
+   (i64.div_u
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+ (func $i64u-rem (param $0 i64) (param $1 i64) (result i64)
+  (if (result i64)
+   (i64.eqz
+    (local.get $1)
+   )
+   (i64.const 0)
+   (i64.rem_u
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/trap-mode-js.wast b/binaryen/test/passes/trap-mode-js.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/trap-mode-js.wast
@@ -0,0 +1,26 @@
+(module
+ (func $test_div (param $0 i32) (param $1 i64)
+  (drop (i32.div_s (local.get $0) (local.get $0)))
+  (drop (i32.div_u (local.get $0) (local.get $0)))
+  (drop (i64.div_s (local.get $1) (local.get $1)))
+  (drop (i64.div_u (local.get $1) (local.get $1)))
+ )
+ (func $test_rem (param $0 i32) (param $1 i64)
+  (drop (i32.rem_s (local.get $0) (local.get $0)))
+  (drop (i32.rem_u (local.get $0) (local.get $0)))
+  (drop (i64.rem_s (local.get $1) (local.get $1)))
+  (drop (i64.rem_u (local.get $1) (local.get $1)))
+ )
+ (func $test_f32_to_int (param $0 f32)
+  (drop (i32.trunc_f32_s (local.get $0)))
+  (drop (i32.trunc_f32_u (local.get $0)))
+  (drop (i64.trunc_f32_s (local.get $0)))
+  (drop (i64.trunc_f32_u (local.get $0)))
+ )
+ (func $test_f64_to_int (param $0 f64)
+  (drop (i32.trunc_f64_s (local.get $0)))
+  (drop (i32.trunc_f64_u (local.get $0)))
+  (drop (i64.trunc_f64_s (local.get $0)))
+  (drop (i64.trunc_f64_u (local.get $0)))
+ )
+)
diff --git a/binaryen/test/passes/untee.txt b/binaryen/test/passes/untee.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/untee.txt
@@ -0,0 +1,47 @@
+(module
+ (type $none_=>_none (func))
+ (func $tee
+  (local $x i32)
+  (local $y f64)
+  (drop
+   (block (result i32)
+    (local.set $x
+     (i32.const 1)
+    )
+    (local.get $x)
+   )
+  )
+  (drop
+   (block (result f64)
+    (local.set $y
+     (f64.const 2)
+    )
+    (local.get $y)
+   )
+  )
+  (local.set $x
+   (block (result i32)
+    (local.set $x
+     (i32.const 3)
+    )
+    (local.get $x)
+   )
+  )
+  (local.set $x
+   (block (result i32)
+    (local.set $x
+     (block (result i32)
+      (local.set $x
+       (i32.const 3)
+      )
+      (local.get $x)
+     )
+    )
+    (local.get $x)
+   )
+  )
+  (drop
+   (unreachable)
+  )
+ )
+)
diff --git a/binaryen/test/passes/untee.wast b/binaryen/test/passes/untee.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/untee.wast
@@ -0,0 +1,12 @@
+(module
+  (func $tee
+    (local $x i32)
+    (local $y f64)
+    (drop (local.tee $x (i32.const 1)))
+    (drop (local.tee $y (f64.const 2)))
+    (local.set $x (local.tee $x (i32.const 3)))
+    (local.set $x (local.tee $x (local.tee $x (i32.const 3))))
+    (drop (local.tee $x (unreachable)))
+  )
+)
+
diff --git a/binaryen/test/passes/vacuum_all-features.txt b/binaryen/test/passes/vacuum_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/vacuum_all-features.txt
@@ -0,0 +1,471 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_f32 (func (result f32)))
+ (type $i32_f64_i32_i32_=>_none (func (param i32 f64 i32 i32)))
+ (type $none_=>_f64 (func (result f64)))
+ (import "env" "int" (func $int (result i32)))
+ (memory $0 256 256)
+ (global $Int i32 (i32.const 0))
+ (func $b
+  (nop)
+ )
+ (func $l
+  (local $x i32)
+  (local $y i32)
+  (local.set $x
+   (local.get $x)
+  )
+  (local.set $x
+   (local.get $x)
+  )
+  (local.set $x
+   (local.get $y)
+  )
+ )
+ (func $loopy (param $0 i32)
+  (nop)
+ )
+ (func $unary (result f32)
+  (f32.abs
+   (unreachable)
+  )
+ )
+ (func $binary (result f32)
+  (drop
+   (f32.add
+    (unreachable)
+    (f32.const 3)
+   )
+  )
+ )
+ (func $select (result i32)
+  (drop
+   (select
+    (unreachable)
+    (i32.const 4)
+    (i32.const 5)
+   )
+  )
+ )
+ (func $block-to-one
+  (unreachable)
+ )
+ (func $recurse
+  (nop)
+ )
+ (func $func-block
+  (nop)
+ )
+ (func $Gu (param $b i32) (param $e f64) (param $l i32) (param $d i32)
+  (if
+   (if (result i32)
+    (local.get $d)
+    (f64.ne
+     (f64.promote_f32
+      (f32.load
+       (local.tee $l
+        (i32.add
+         (local.get $b)
+         (i32.const 60)
+        )
+       )
+      )
+     )
+     (local.get $e)
+    )
+    (i32.const 0)
+   )
+   (unreachable)
+  )
+ )
+ (func $if-drop (result i32)
+  (block $out
+   (if
+    (call $if-drop)
+    (drop
+     (call $int)
+    )
+    (br $out)
+   )
+   (if
+    (call $if-drop)
+    (br $out)
+    (drop
+     (call $int)
+    )
+   )
+  )
+  (i32.const 1)
+ )
+ (func $drop-silly
+  (drop
+   (call $int)
+  )
+  (drop
+   (call $int)
+  )
+  (drop
+   (call $int)
+  )
+  (drop
+   (i32.add
+    (call $int)
+    (call $int)
+   )
+  )
+ )
+ (func $drop-get-global
+  (call $drop-get-global)
+ )
+ (func $relooperJumpThreading1
+  (local $$vararg_ptr5 i32)
+  (local $$11 i32)
+  (nop)
+ )
+ (func $relooperJumpThreading2
+  (nop)
+ )
+ (func $relooperJumpThreading3
+  (nop)
+ )
+ (func $if2drops (result i32)
+  (drop
+   (if (result i32)
+    (call $if2drops)
+    (call $if2drops)
+    (call $if2drops)
+   )
+  )
+  (i32.const 2)
+ )
+ (func $if2drops-different (result i32)
+  (if
+   (call $if2drops)
+   (drop
+    (call $if2drops)
+   )
+   (drop
+    (call $unary)
+   )
+  )
+  (i32.const 2)
+ )
+ (func $if-const (param $x i32)
+  (call $if-const
+   (i32.const 3)
+  )
+  (call $if-const
+   (i32.const 5)
+  )
+  (call $if-const
+   (i32.const 7)
+  )
+ )
+ (func $drop-if-both-unreachable (param $0 i32)
+  (block $out
+   (drop
+    (if (result i32)
+     (local.get $0)
+     (br $out)
+     (br $out)
+    )
+   )
+  )
+  (drop
+   (if (result i32)
+    (local.get $0)
+    (unreachable)
+    (unreachable)
+   )
+  )
+ )
+ (func $if-1-block (param $x i32)
+  (block $out
+   (if
+    (local.get $x)
+    (block $block9
+     (local.set $x
+      (local.get $x)
+     )
+     (br $out)
+    )
+   )
+  )
+ )
+ (func $block-resize-br-gone
+  (block $out
+   (block $in
+    (call $block-resize-br-gone)
+    (br $in)
+   )
+   (return)
+  )
+ )
+ (func $block-unreachable-but-last-element-concrete
+  (local $2 i32)
+  (nop)
+ )
+ (func $a
+  (block $block
+   (i32.store
+    (i32.const 1)
+    (i32.const 2)
+   )
+   (f64.div
+    (f64.const -nan:0xfffffffffa361)
+    (loop $label$1
+     (br $label$1)
+    )
+   )
+  )
+ )
+ (func $leave-block-even-if-br-not-taken (result f64)
+  (block $label$0 (result f64)
+   (f64.store align=1
+    (i32.const 879179022)
+    (br_if $label$0
+     (loop $label$9
+      (br $label$9)
+     )
+     (i32.const 677803374)
+    )
+   )
+  )
+ )
+ (func $executed-if-in-block
+  (unreachable)
+ )
+ (func $executed-if-in-block2
+  (unreachable)
+ )
+ (func $executed-if-in-block3
+  (block $label$0
+   (br $label$0)
+  )
+  (unreachable)
+ )
+ (func $load-may-have-side-effects (result i32)
+  (i64.ge_s
+   (block $block (result i64)
+    (drop
+     (i64.load32_s
+      (i32.const 678585719)
+     )
+    )
+    (i64.const 2912825531628789796)
+   )
+   (i64.const 0)
+  )
+ )
+ (func $unary-binary-may-trap
+  (drop
+   (i64.div_s
+    (i64.const -1)
+    (i64.const 729618461987467893)
+   )
+  )
+  (drop
+   (i64.trunc_f32_u
+    (f32.const 70847791997969805621592064)
+   )
+  )
+ )
+ (func $unreachable-if-with-nop-arm-that-leaves-a-concrete-value-if-nop-is-removed
+  (block $label$0
+   (loop $label$1
+    (drop
+     (br_if $label$0
+      (loop $label$9
+       (br $label$9)
+      )
+     )
+    )
+   )
+  )
+ )
+ (func $if-arm-vanishes (result i32)
+  (block $label$0 (result i32)
+   (br $label$0
+    (i32.const 1)
+   )
+  )
+ )
+ (func $if-arm-vanishes-2 (result i32)
+  (block $label$0 (result i32)
+   (br $label$0
+    (i32.const 1)
+   )
+  )
+ )
+ (func $nop-if-type-changes
+  (local $0 i32)
+  (nop)
+ )
+)
+(module
+ (type $i64_=>_none (func (param i64)))
+ (type $f32_i32_=>_i32 (func (param f32 i32) (result i32)))
+ (func $0 (param $0 i64)
+  (nop)
+ )
+ (func $1 (param $0 f32) (param $1 i32) (result i32)
+  (drop
+   (block $label$2 (result i64)
+    (call $0
+     (br_if $label$2
+      (i64.const -137438953472)
+      (i32.const 1)
+     )
+    )
+    (unreachable)
+   )
+  )
+  (unreachable)
+ )
+)
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (memory $0 1 1)
+ (global $global$1 (mut i32) (i32.const 0))
+ (export "compress" (func $3))
+ (func $_deflate (param $0 i32) (result i32)
+  (call $_deflate
+   (local.get $0)
+  )
+ )
+ (func $_deflateInit2_ (param $0 i32) (result i32)
+  (call $_deflateInit2_
+   (local.get $0)
+  )
+ )
+ (func $_deflateEnd (param $0 i32) (result i32)
+  (call $_deflateEnd
+   (local.get $0)
+  )
+ )
+ (func $3 (param $0 i32) (param $1 i32) (param $2 i32)
+  (local $3 i32)
+  (local.set $3
+   (global.get $global$1)
+  )
+  (global.set $global$1
+   (i32.sub
+    (global.get $global$1)
+    (i32.const -64)
+   )
+  )
+  (i32.store
+   (local.get $3)
+   (local.get $2)
+  )
+  (i32.store offset=4
+   (local.get $3)
+   (i32.const 100000)
+  )
+  (i32.store offset=12
+   (local.get $3)
+   (local.get $0)
+  )
+  (i32.store offset=16
+   (local.get $3)
+   (i32.load
+    (local.get $1)
+   )
+  )
+  (i32.store offset=32
+   (local.get $3)
+   (i32.const 0)
+  )
+  (i32.store offset=36
+   (local.get $3)
+   (i32.const 0)
+  )
+  (i32.store offset=40
+   (local.get $3)
+   (i32.const 0)
+  )
+  (if
+   (call $_deflateInit2_
+    (local.get $3)
+   )
+   (block $block
+    (global.set $global$1
+     (local.get $3)
+    )
+    (return)
+   )
+  )
+  (drop
+   (if (result i32)
+    (i32.eq
+     (local.tee $0
+      (call $_deflate
+       (local.get $3)
+      )
+     )
+     (i32.const 1)
+    )
+    (block $block1 (result i32)
+     (i32.store
+      (local.get $1)
+      (i32.load offset=20
+       (local.get $3)
+      )
+     )
+     (local.set $0
+      (call $_deflateEnd
+       (local.get $3)
+      )
+     )
+     (global.set $global$1
+      (local.get $3)
+     )
+     (i32.const 0)
+    )
+    (block $block2 (result i32)
+     (drop
+      (call $_deflateEnd
+       (local.get $3)
+      )
+     )
+     (global.set $global$1
+      (local.get $3)
+     )
+     (i32.const 0)
+    )
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (event $e (attr 0) (param i32))
+ (func $try-test
+  (nop)
+ )
+ (func $inner-try-test
+  (local $0 i32)
+  (try
+   (do
+    (throw $e
+     (i32.const 0)
+    )
+   )
+   (catch
+    (drop
+     (pop exnref)
+    )
+    (local.set $0
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $br-in-catch
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/passes/vacuum_all-features.wast b/binaryen/test/passes/vacuum_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/vacuum_all-features.wast
@@ -0,0 +1,850 @@
+(module
+  (memory 256 256)
+  (type $0 (func))
+  (type $1 (func (param i32)))
+  (type $2 (func (result f32)))
+  (type $3 (func (result i32)))
+  (type $4 (func (param i32 f64 i32 i32)))
+  (import $int "env" "int" (result i32))
+  (global $Int i32 (i32.const 0))
+  (func $b (type $0)
+    (drop
+      (i32.const 50)
+    )
+    (nop)
+    (drop
+      (i32.const 51)
+    )
+    (nop)
+    (nop)
+    (drop
+      (i32.const 52)
+    )
+    (block $waka1
+      (drop
+        (i32.const 53)
+      )
+      (br $waka1)
+      (drop
+        (i32.const 54)
+      )
+    )
+    (block $waka2
+      (nop)
+      (br $waka2)
+      (drop
+        (i32.const 56)
+      )
+    )
+    (block $waka3
+      (br_table $waka3 $waka3 $waka3
+        (i32.const 57)
+      )
+      (drop
+        (i32.const 58)
+      )
+    )
+    (if
+      (i32.const 100)
+      (nop)
+      (drop
+        (i32.const 101)
+      )
+    )
+    (if
+      (i32.const 102)
+      (drop
+        (i32.const 103)
+      )
+      (nop)
+    )
+    (if
+      (i32.const 104)
+      (nop)
+      (nop)
+    )
+  )
+  (func $l (type $0)
+    (local $x i32)
+    (local $y i32)
+    (drop
+      (local.get $x)
+    )
+    (local.set $x
+      (local.get $x)
+    )
+    (block $in-a-block
+      (drop
+        (local.get $x)
+      )
+    )
+    (block $two-in-a-block
+      (drop
+        (local.get $x)
+      )
+      (drop
+        (local.get $y)
+      )
+    )
+    (local.set $x
+      (block $result-used (result i32)
+        (local.get $x)
+      )
+    )
+    (local.set $x
+      (block $two-and-result-used (result i32)
+        (drop
+          (local.get $x)
+        )
+        (local.get $y)
+      )
+    )
+  )
+  (func $loopy (type $1) (param $0 i32)
+    (loop $loop-in1
+      (nop)
+    )
+    (loop $loop-in3
+      (nop)
+      (nop)
+    )
+    (drop
+      (loop $loop-in5 (result i32)
+        (drop
+          (local.get $0)
+        )
+        (i32.const 20)
+      )
+    )
+  )
+  (func $unary (type $2) (result f32)
+    (drop
+      (f32.abs
+        (f32.const 1)
+      )
+    )
+    (f32.abs
+      (unreachable)
+    )
+    (f32.abs
+      (f32.const 2)
+    )
+  )
+  (func $binary (type $2) (result f32)
+    (drop
+      (f32.add
+        (f32.const 1)
+        (f32.const 2)
+      )
+    )
+    (drop
+      (f32.add
+        (unreachable)
+        (f32.const 3)
+      )
+    )
+    (drop
+      (f32.add
+        (f32.const 4)
+        (unreachable)
+      )
+    )
+    (f32.add
+      (unreachable)
+      (unreachable)
+    )
+    (f32.add
+      (f32.const 5)
+      (f32.const 6)
+    )
+  )
+  (func $select (type $3) (result i32)
+    (drop
+      (select
+        (i32.const 1)
+        (i32.const 2)
+        (i32.const 3)
+      )
+    )
+    (drop
+      (select
+        (unreachable)
+        (i32.const 4)
+        (i32.const 5)
+      )
+    )
+    (drop
+      (select
+        (i32.const 6)
+        (unreachable)
+        (i32.const 7)
+      )
+    )
+    (drop
+      (select
+        (i32.const 8)
+        (i32.const 9)
+        (unreachable)
+      )
+    )
+    (select
+      (unreachable)
+      (unreachable)
+      (i32.const 10)
+    )
+    (drop
+      (select
+        (unreachable)
+        (i32.const 11)
+        (unreachable)
+      )
+    )
+    (drop
+      (select
+        (i32.const 12)
+        (unreachable)
+        (unreachable)
+      )
+    )
+    (select
+      (unreachable)
+      (unreachable)
+      (unreachable)
+    )
+    (select
+      (i32.const 13)
+      (i32.const 14)
+      (i32.const 15)
+    )
+  )
+  (func $block-to-one (type $0)
+    (block $block0
+      (nop)
+      (nop)
+    )
+    (block $block1
+      (nop)
+      (unreachable)
+    )
+    (block $block2
+      (nop)
+      (unreachable)
+      (nop)
+    )
+    (block $block3
+      (unreachable)
+      (nop)
+    )
+    (block $block4
+      (unreachable)
+    )
+  )
+  (func $recurse (type $0)
+    (nop)
+    (drop
+      (f32.abs
+        (f32.abs
+          (f32.abs
+            (f32.abs
+              (f32.abs
+                (f32.abs
+                  (f32.const 1)
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+  (func $func-block (type $0)
+    (drop
+      (f32.abs
+        (f32.abs
+          (f32.abs
+            (f32.abs
+              (f32.abs
+                (f32.abs
+                  (f32.const 1)
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+  (func $Gu (type $4) (param $b i32) (param $e f64) (param $l i32) (param $d i32)
+    (if
+      (if (result i32)
+        (local.get $d)
+        (block $block1 (result i32)
+          (nop)
+          (f64.ne
+            (f64.promote_f32
+              (f32.load
+                (local.tee $l
+                  (i32.add
+                    (local.get $b)
+                    (i32.const 60)
+                  )
+                )
+              )
+            )
+            (local.get $e)
+          )
+        )
+        (i32.const 0)
+      )
+      (unreachable)
+    )
+  )
+  (func $if-drop (result i32)
+    (block $out
+      (drop
+        (if (result i32)
+          (call $if-drop)
+          (call $int)
+          (br $out)
+        )
+      )
+      (drop
+        (if (result i32)
+          (call $if-drop)
+          (br $out)
+          (call $int)
+        )
+      )
+    )
+    (i32.const 1)
+  )
+  (func $drop-silly
+    (drop
+      (i32.eqz
+        (i32.eqz
+          (i32.const 1)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (i32.eqz
+          (call $int)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.const 2)
+        (i32.const 3)
+      )
+    )
+    (drop
+      (i32.add
+        (i32.const 4)
+        (call $int)
+      )
+    )
+    (drop
+      (i32.add
+        (call $int)
+        (i32.const 5)
+      )
+    )
+    (drop
+      (i32.add
+        (call $int)
+        (call $int)
+      )
+    )
+  )
+  (func $drop-get-global
+    (drop
+      (block (result i32)
+        (call $drop-get-global)
+        (global.get $Int) ;; this is not needed due to the block being drop'd, but make sure the call is not then dropped either
+      )
+    )
+  )
+  (func $relooperJumpThreading1
+    (local $$vararg_ptr5 i32)
+    (local $$11 i32)
+    (loop $while-in$1
+      (drop
+        (block $jumpthreading$outer$8 (result i32)
+          (block $jumpthreading$inner$8
+            (br $jumpthreading$outer$8 ;; the rest is dead in the outer block, but be careful to leave the return value!
+              (i32.const 0)
+            )
+          )
+          (i32.store
+            (local.get $$vararg_ptr5)
+            (local.get $$11)
+          )
+          (i32.const 0)
+        )
+      )
+    )
+  )
+  (func $relooperJumpThreading2
+    (loop $while-in$1
+      (drop
+        (block $jumpthreading$outer$8 (result i32)
+          (block $jumpthreading$inner$8
+            (br $jumpthreading$outer$8
+              (i32.const 0)
+            )
+          )
+          (i32.const 0)
+        )
+      )
+    )
+  )
+  (func $relooperJumpThreading3
+    (loop $while-in$1
+      (drop
+        (block $jumpthreading$outer$8 (result i32)
+          (br $jumpthreading$outer$8 ;; code after this is dead, can kill it, but preserve the return value at the end!
+            (i32.const 0)
+          )
+          (drop (i32.const 3))
+          (drop (i32.const 2))
+          (drop (i32.const 1))
+          (i32.const 0)
+        )
+      )
+    )
+  )
+  (func $if2drops (result i32)
+    (if
+      (call $if2drops)
+      (drop
+        (call $if2drops)
+      )
+      (drop
+        (call $if2drops)
+      )
+    )
+    (i32.const 2)
+  )
+  (func $if2drops-different (result i32)
+    (if
+      (call $if2drops)
+      (drop
+        (call $if2drops) ;; i32
+      )
+      (drop
+        (call $unary) ;; f32!
+      )
+    )
+    (i32.const 2)
+  )
+  (func $if-const (param $x i32)
+    (if (i32.const 0) (call $if-const (i32.const 1)))
+    (if (i32.const 2) (call $if-const (i32.const 3)))
+    (if (i32.const 0) (call $if-const (i32.const 4)) (call $if-const (i32.const 5)))
+    (if (i32.const 6) (call $if-const (i32.const 7)) (call $if-const (i32.const 8)))
+  )
+  (func $drop-if-both-unreachable (param $0 i32)
+    (block $out
+      (drop
+        (if (result i32)
+          (local.get $0)
+          (br $out)
+          (br $out)
+        )
+      )
+    )
+    (drop
+      (if (result i32)
+        (local.get $0)
+        (unreachable)
+        (unreachable)
+      )
+    )
+  )
+  (func $if-1-block (param $x i32)
+   (block $out
+    (if
+     (local.get $x)
+     (block
+      (if
+       (i32.const 1)
+       (block
+        (local.set $x
+         (local.get $x)
+        )
+        (br $out)
+       )
+      )
+     )
+    )
+   )
+  )
+  (func $block-resize-br-gone
+    (block $out
+      (block $in
+        (call $block-resize-br-gone)
+        (br $in)
+        (br $out)
+      )
+      (return)
+    )
+    (block $out2
+      (block $in2
+        (br $in2)
+        (br $out2)
+      )
+      (return)
+    )
+  )
+  (func $block-unreachable-but-last-element-concrete
+   (local $2 i32)
+   (block $label$0
+    (drop
+     (block (result i32)
+      (br $label$0)
+      (local.get $2)
+     )
+    )
+   )
+  )
+  (func $a
+    (block
+      (i32.store (i32.const 1) (i32.const 2))
+      (f64.div
+        (f64.const -nan:0xfffffffffa361)
+        (loop $label$1 ;; unreachable, so the div is too. keep
+          (br $label$1)
+        )
+      )
+    )
+  )
+  (func $leave-block-even-if-br-not-taken (result f64)
+   (block $label$0 (result f64)
+    (f64.store align=1
+     (i32.const 879179022)
+     (br_if $label$0
+      (loop $label$9
+       (br $label$9)
+      )
+      (i32.const 677803374)
+     )
+    )
+    (f64.const 2097914503796645752267195e31)
+   )
+  )
+  (func $executed-if-in-block
+    (block $label$0
+     (if
+      (i32.const 170996275)
+      (unreachable)
+      (br $label$0)
+     )
+    )
+    (unreachable)
+  )
+  (func $executed-if-in-block2
+    (block $label$0
+     (if
+      (i32.const 170996275)
+      (nop)
+      (br $label$0)
+     )
+    )
+    (unreachable)
+  )
+  (func $executed-if-in-block3
+    (block $label$0
+     (if
+      (i32.const 170996275)
+      (br $label$0)
+      (nop)
+     )
+    )
+    (unreachable)
+  )
+  (func $load-may-have-side-effects (result i32)
+   (i64.ge_s
+    (block (result i64)
+     (drop
+      (i64.eq
+       (i64.load32_s
+        (i32.const 678585719)
+       )
+       (i64.const 8097879367757079605)
+      )
+     )
+     (i64.const 2912825531628789796)
+    )
+    (i64.const 0)
+   )
+  )
+  (func $unary-binary-may-trap
+   (drop
+    (i64.div_s
+     (i64.const -1)
+     (i64.const 729618461987467893)
+    )
+   )
+   (drop
+    (i64.trunc_f32_u
+     (f32.const 70847791997969805621592064)
+    )
+   )
+  )
+  (func $unreachable-if-with-nop-arm-that-leaves-a-concrete-value-if-nop-is-removed
+   (block $label$0
+    (loop $label$1
+     (drop
+      (if (result i32)
+       (br_if $label$0
+        (loop $label$9
+         (br $label$9)
+        )
+       )
+       (unreachable)
+       (i32.const 1920103026)
+      )
+     )
+    )
+   )
+  )
+  (func $if-arm-vanishes (result i32)
+   (block $label$0 (result i32)
+    (block $label$1
+     (if
+      (br $label$0
+       (i32.const 1)
+      )
+      (br $label$1)
+     )
+    )
+    (i32.const 1579493952)
+   )
+  )
+  (func $if-arm-vanishes-2 (result i32)
+   (block $label$0 (result i32)
+    (block $label$1
+     (if
+      (br $label$0
+       (i32.const 1)
+      )
+      (br $label$1)
+     )
+    )
+    (i32.const 1579493952)
+   )
+  )
+  (func $nop-if-type-changes (type $0)
+   (local $0 i32)
+   (block $label$0
+    (if
+     (i32.eqz
+      (local.get $0)
+     )
+     (block $label$1
+      (block
+       (if ;; we nop this if, which has a type change for block $label$1, no more brs to it
+        (i32.const 0)
+        (br_if $label$1
+          (i32.const 1717966400)
+        )
+       )
+       (drop
+        (br $label$0)
+       )
+      )
+     )
+    )
+   )
+  )
+)
+(module ;; a child with a different type, cannot simply replace the parent with it
+ (type $0 (func (param i64)))
+ (type $1 (func (param f32 i32) (result i32)))
+ (func $0 (; 0 ;) (type $0) (param $0 i64)
+  (nop)
+ )
+ (func $1 (; 1 ;) (type $1) (param $0 f32) (param $1 i32) (result i32)
+  (drop
+   (block $label$1 (result i32)
+    (i32.wrap_i64
+     (block $label$2 (result i64)
+      (call $0
+       (br_if $label$2
+        (i64.const -137438953472)
+        (i32.const 1)
+       )
+      )
+      (unreachable)
+     )
+    )
+   )
+  )
+  (unreachable)
+ )
+)
+(module ;; vacuum away a drop on an if where both arms can be vacuumed
+ (memory 1 1)
+ (global $global$1 (mut i32) (i32.const 0))
+ (func $_deflate (param i32) (result i32)
+  (call $_deflate (local.get $0))
+ )
+ (func $_deflateInit2_ (param i32) (result i32)
+  (call $_deflateInit2_ (local.get $0))
+ )
+ (func $_deflateEnd (param i32) (result i32)
+  (call $_deflateEnd (local.get $0))
+ )
+ (func "compress" (param $0 i32) (param $1 i32) (param $2 i32)
+  (local $3 i32)
+  (local.set $3
+   (global.get $global$1)
+  )
+  (global.set $global$1
+   (i32.sub
+    (global.get $global$1)
+    (i32.const -64)
+   )
+  )
+  (i32.store
+   (local.get $3)
+   (local.get $2)
+  )
+  (i32.store offset=4
+   (local.get $3)
+   (i32.const 100000)
+  )
+  (i32.store offset=12
+   (local.get $3)
+   (local.get $0)
+  )
+  (i32.store offset=16
+   (local.get $3)
+   (i32.load
+    (local.get $1)
+   )
+  )
+  (i32.store offset=32
+   (local.get $3)
+   (i32.const 0)
+  )
+  (i32.store offset=36
+   (local.get $3)
+   (i32.const 0)
+  )
+  (i32.store offset=40
+   (local.get $3)
+   (i32.const 0)
+  )
+  (if
+   (call $_deflateInit2_
+    (local.get $3)
+   )
+   (block
+    (global.set $global$1
+     (local.get $3)
+    )
+    (return)
+   )
+  )
+  (drop
+   (if (result i32)
+    (i32.eq
+     (local.tee $0
+      (call $_deflate
+       (local.get $3)
+      )
+     )
+     (i32.const 1)
+    )
+    (block (result i32)
+     (i32.store
+      (local.get $1)
+      (i32.load offset=20
+       (local.get $3)
+      )
+     )
+     (local.set $0
+      (call $_deflateEnd
+       (local.get $3)
+      )
+     )
+     (global.set $global$1
+      (local.get $3)
+     )
+     (local.get $0)
+    )
+    (block (result i32)
+     (drop
+      (call $_deflateEnd
+       (local.get $3)
+      )
+     )
+     (global.set $global$1
+      (local.get $3)
+     )
+     (select
+      (local.get $0)
+      (i32.const -5)
+      (local.get $0)
+     )
+    )
+   )
+  )
+ )
+)
+
+(module
+  (event $e (attr 0) (param i32))
+  ;; When try body does not throw, try-body can be replaced with the try body
+  (func $try-test
+    (try
+      (do
+        (drop (i32.const 0))
+      )
+      (catch
+        (drop (pop exnref))
+      )
+    )
+  )
+
+  ;; The exception thrown in the inner try is caught by the inner catch, so the
+  ;; outer try body does not throw and the outer try-catch can be removed
+  (func $inner-try-test (local $0 i32)
+    (try
+      (do
+        (try
+          (do
+            (throw $e (i32.const 0))
+          )
+          (catch
+            (drop (pop exnref))
+            (local.set $0 (i32.const 1))
+          )
+        )
+      )
+      (catch
+        (drop (pop exnref))
+      )
+    )
+  )
+
+  ;; When catch body is removed, the removal of 'br' inside the catch body
+  ;; should be propagated up to the outer block, so that its type will be
+  ;; correctly updated to unreachable.
+  (func $br-in-catch
+    (block $label$1
+      (try
+        (do
+          (unreachable)
+        )
+        (catch
+          (drop (pop exnref))
+          (br $label$1)
+        )
+      )
+    )
+  )
+)
diff --git a/binaryen/test/passes/vacuum_ignore-implicit-traps.txt b/binaryen/test/passes/vacuum_ignore-implicit-traps.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/vacuum_ignore-implicit-traps.txt
@@ -0,0 +1,14 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 1)
+ (func $load-would-normally-have-side-effects (result i32)
+  (i64.ge_s
+   (i64.const 2912825531628789796)
+   (i64.const 0)
+  )
+ )
+ (func $unary-binary-may-trap
+  (nop)
+ )
+)
diff --git a/binaryen/test/passes/vacuum_ignore-implicit-traps.wast b/binaryen/test/passes/vacuum_ignore-implicit-traps.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/vacuum_ignore-implicit-traps.wast
@@ -0,0 +1,33 @@
+(module
+  (memory 1)
+  (func $load-would-normally-have-side-effects (result i32)
+   (i64.ge_s
+    (block (result i64)
+     (drop
+      (i64.eq
+       (i64.load32_s
+        (i32.const 678585719)
+       )
+       (i64.const 8097879367757079605)
+      )
+     )
+     (i64.const 2912825531628789796)
+    )
+    (i64.const 0)
+   )
+  )
+  (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/passes/vacuum_remove-unused-names_merge-blocks.txt b/binaryen/test/passes/vacuum_remove-unused-names_merge-blocks.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/vacuum_remove-unused-names_merge-blocks.txt
@@ -0,0 +1,11 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $return-block (param $x i32) (result i32)
+  (local.set $x
+   (local.get $x)
+  )
+  (return
+   (local.get $x)
+  )
+ )
+)
diff --git a/binaryen/test/passes/vacuum_remove-unused-names_merge-blocks.wast b/binaryen/test/passes/vacuum_remove-unused-names_merge-blocks.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/vacuum_remove-unused-names_merge-blocks.wast
@@ -0,0 +1,16 @@
+(module
+  ;; vacuum and remove-unused names leave us with a return at the top, and then
+  ;; merge-blocks wants to move the first line of the block into an outer block
+  ;; that then becomes the fallthrough of the function, so it must be properly typed.
+  ;; and here the new last element is a return, with unreachable type, bad for a block
+  ;; in that position
+  (func $return-block (param $x i32) (result i32)
+    (return
+      (block (result i32)
+        (local.set $x (local.get $x))
+        (local.get $x)
+      )
+    )
+  )
+)
+
diff --git a/binaryen/test/polymorphic_stack.wast b/binaryen/test/polymorphic_stack.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/polymorphic_stack.wast
@@ -0,0 +1,133 @@
+(module
+  (type $FUNCSIG$ii (func (param i32) (result i32)))
+  (import "env" "table" (table 9 9 funcref))
+  (func $break-and-binary (result i32)
+    (block $x (result i32)
+      (f32.add
+        (br_if $x
+          (i32.trunc_f64_u
+            (unreachable)
+          )
+          (i32.trunc_f64_u
+            (unreachable)
+          )
+        )
+        (f32.const 1)
+      )
+    )
+  )
+  (func $call-and-unary (param i32) (result i32)
+    (drop
+      (i64.eqz
+        (call $call-and-unary
+          (unreachable)
+        )
+      )
+    )
+    (drop
+      (i64.eqz
+        (i32.eqz
+          (unreachable)
+        )
+      )
+    )
+    (drop
+      (i64.eqz
+        (call_indirect (type $FUNCSIG$ii)
+          (unreachable)
+          (unreachable)
+        )
+      )
+    )
+  )
+  (func $tee (param $x i32)
+    (local $y f32)
+    (drop
+      (i64.eqz
+        (local.tee $x
+          (unreachable)
+        )
+      )
+    )
+    (drop
+      (local.tee $y
+        (i64.eqz
+          (unreachable)
+        )
+      )
+    )
+  )
+  (func $tee2
+    (local $0 f32)
+    (if
+      (i32.const 259)
+      (local.set $0
+        (unreachable)
+      )
+    )
+  )
+  (func $select
+    (drop
+      (i64.eqz
+        (select
+          (unreachable)
+          (i32.const 1)
+          (i32.const 2)
+        )
+      )
+    )
+  )
+  (func $untaken-break-should-have-value (result i32)
+    (block $x (result i32)
+      (block
+        (br_if $x
+          (i32.const 0)
+          (unreachable)
+        )
+      )
+    )
+  )
+  (func $unreachable-in-block-but-code-before (param $0 i32) (result i32)
+   (if
+    (local.get $0)
+    (return
+     (i32.const 127)
+    )
+   )
+   (block $label$0 (result i32)
+    (br_if $label$0
+     (i32.const 0)
+     (return
+      (i32.const -32)
+     )
+    )
+   )
+  )
+  (func $br_table_unreachable_to_also_unreachable (result i32)
+    (block $a (result i32)
+      (block $b (result i32)
+        (br_table $a $b ;; seems to send a value, but is not taken
+          (unreachable)
+          (unreachable)
+        )
+      )
+    )
+  )
+  (func $untaken-br_if (result i32)
+    (block $label$8 (result i32)
+     (block $label$9
+      (drop
+       (if
+        (i32.const 0)
+        (br_if $label$8
+         (unreachable)
+         (i32.const 0)
+        )
+        (unreachable)
+       )
+      )
+     )
+    )
+  )
+)
+
diff --git a/binaryen/test/polymorphic_stack.wast.from-wast b/binaryen/test/polymorphic_stack.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/polymorphic_stack.wast.from-wast
@@ -0,0 +1,135 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (import "env" "table" (table $timport$0 9 9 funcref))
+ (func $break-and-binary (result i32)
+  (block $x (result i32)
+   (f32.add
+    (br_if $x
+     (i32.trunc_f64_u
+      (unreachable)
+     )
+     (i32.trunc_f64_u
+      (unreachable)
+     )
+    )
+    (f32.const 1)
+   )
+  )
+ )
+ (func $call-and-unary (param $0 i32) (result i32)
+  (drop
+   (i64.eqz
+    (call $call-and-unary
+     (unreachable)
+    )
+   )
+  )
+  (drop
+   (i64.eqz
+    (i32.eqz
+     (unreachable)
+    )
+   )
+  )
+  (drop
+   (i64.eqz
+    (call_indirect (type $i32_=>_i32)
+     (unreachable)
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $tee (param $x i32)
+  (local $y f32)
+  (drop
+   (i64.eqz
+    (local.tee $x
+     (unreachable)
+    )
+   )
+  )
+  (drop
+   (local.tee $y
+    (i64.eqz
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $tee2
+  (local $0 f32)
+  (if
+   (i32.const 259)
+   (local.tee $0
+    (unreachable)
+   )
+  )
+ )
+ (func $select
+  (drop
+   (i64.eqz
+    (select
+     (unreachable)
+     (i32.const 1)
+     (i32.const 2)
+    )
+   )
+  )
+ )
+ (func $untaken-break-should-have-value (result i32)
+  (block $x (result i32)
+   (block $block
+    (br_if $x
+     (i32.const 0)
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $unreachable-in-block-but-code-before (param $0 i32) (result i32)
+  (if
+   (local.get $0)
+   (return
+    (i32.const 127)
+   )
+  )
+  (block $label$0 (result i32)
+   (br_if $label$0
+    (i32.const 0)
+    (return
+     (i32.const -32)
+    )
+   )
+  )
+ )
+ (func $br_table_unreachable_to_also_unreachable (result i32)
+  (block $a (result i32)
+   (block $b (result i32)
+    (br_table $a $b
+     (unreachable)
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $untaken-br_if (result i32)
+  (block $label$8 (result i32)
+   (block $label$9
+    (drop
+     (if
+      (i32.const 0)
+      (br_if $label$8
+       (unreachable)
+       (i32.const 0)
+      )
+      (unreachable)
+     )
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/polymorphic_stack.wast.fromBinary b/binaryen/test/polymorphic_stack.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/polymorphic_stack.wast.fromBinary
@@ -0,0 +1,76 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (import "env" "table" (table $timport$0 9 9 funcref))
+ (func $break-and-binary (result i32)
+  (block $label$1 (result i32)
+   (unreachable)
+  )
+ )
+ (func $call-and-unary (param $0 i32) (result i32)
+  (unreachable)
+ )
+ (func $tee (param $x i32)
+  (local $y f32)
+  (unreachable)
+ )
+ (func $tee2
+  (local $0 f32)
+  (if
+   (i32.const 259)
+   (unreachable)
+  )
+ )
+ (func $select
+  (unreachable)
+ )
+ (func $untaken-break-should-have-value (result i32)
+  (block $label$1 (result i32)
+   (block $label$2
+    (drop
+     (i32.const 0)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+ )
+ (func $unreachable-in-block-but-code-before (param $0 i32) (result i32)
+  (if
+   (local.get $0)
+   (return
+    (i32.const 127)
+   )
+  )
+  (block $label$2 (result i32)
+   (drop
+    (i32.const 0)
+   )
+   (return
+    (i32.const -32)
+   )
+  )
+ )
+ (func $br_table_unreachable_to_also_unreachable (result i32)
+  (block $label$1 (result i32)
+   (block $label$2 (result i32)
+    (unreachable)
+   )
+  )
+ )
+ (func $untaken-br_if (result i32)
+  (block $label$1 (result i32)
+   (block $label$2
+    (if
+     (i32.const 0)
+     (unreachable)
+     (unreachable)
+    )
+   )
+   (unreachable)
+  )
+ )
+)
+
diff --git a/binaryen/test/polymorphic_stack.wast.fromBinary.noDebugInfo b/binaryen/test/polymorphic_stack.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/polymorphic_stack.wast.fromBinary.noDebugInfo
@@ -0,0 +1,76 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (import "env" "table" (table $timport$0 9 9 funcref))
+ (func $0 (result i32)
+  (block $label$1 (result i32)
+   (unreachable)
+  )
+ )
+ (func $1 (param $0 i32) (result i32)
+  (unreachable)
+ )
+ (func $2 (param $0 i32)
+  (local $1 f32)
+  (unreachable)
+ )
+ (func $3
+  (local $0 f32)
+  (if
+   (i32.const 259)
+   (unreachable)
+  )
+ )
+ (func $4
+  (unreachable)
+ )
+ (func $5 (result i32)
+  (block $label$1 (result i32)
+   (block $label$2
+    (drop
+     (i32.const 0)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+ )
+ (func $6 (param $0 i32) (result i32)
+  (if
+   (local.get $0)
+   (return
+    (i32.const 127)
+   )
+  )
+  (block $label$2 (result i32)
+   (drop
+    (i32.const 0)
+   )
+   (return
+    (i32.const -32)
+   )
+  )
+ )
+ (func $7 (result i32)
+  (block $label$1 (result i32)
+   (block $label$2 (result i32)
+    (unreachable)
+   )
+  )
+ )
+ (func $8 (result i32)
+  (block $label$1 (result i32)
+   (block $label$2
+    (if
+     (i32.const 0)
+     (unreachable)
+     (unreachable)
+    )
+   )
+   (unreachable)
+  )
+ )
+)
+
diff --git a/binaryen/test/print/memory-import-shared.minified.txt b/binaryen/test/print/memory-import-shared.minified.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/print/memory-import-shared.minified.txt
@@ -0,0 +1,1 @@
+(module(import "env" "memory" (memory $0 (shared 256 256))))
diff --git a/binaryen/test/print/memory-import-shared.txt b/binaryen/test/print/memory-import-shared.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/print/memory-import-shared.txt
@@ -0,0 +1,3 @@
+(module
+ (import "env" "memory" (memory $0 (shared 256 256)))
+)
diff --git a/binaryen/test/print/memory-import-shared.wast b/binaryen/test/print/memory-import-shared.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/print/memory-import-shared.wast
@@ -0,0 +1,3 @@
+(module
+ (import "env" "memory" (memory $0 (shared 256 256)))
+)
diff --git a/binaryen/test/print/memory-shared.minified.txt b/binaryen/test/print/memory-shared.minified.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/print/memory-shared.minified.txt
@@ -0,0 +1,2 @@
+(module(memory $0 (shared 23 256))
+)
diff --git a/binaryen/test/print/memory-shared.txt b/binaryen/test/print/memory-shared.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/print/memory-shared.txt
@@ -0,0 +1,3 @@
+(module
+ (memory $0 (shared 23 256))
+)
diff --git a/binaryen/test/print/memory-shared.wast b/binaryen/test/print/memory-shared.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/print/memory-shared.wast
@@ -0,0 +1,3 @@
+(module
+ (memory $0 (shared 23 256))
+)
diff --git a/binaryen/test/print/min.minified.txt b/binaryen/test/print/min.minified.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/print/min.minified.txt
@@ -0,0 +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)
+(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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/print/min.txt
@@ -0,0 +1,57 @@
+(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)
+ (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.wast b/binaryen/test/print/min.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/print/min.wast
@@ -0,0 +1,57 @@
+(module
+  (type $0 (func (param f32) (result f32)))
+  (type $1 (func (param i32 i32) (result f32)))
+  (type $2 (func (param i32) (result i32)))
+  (type $3 (func (param i32 i32 i32) (result i32)))
+  (memory $0 256 256)
+  (export "floats" (func $floats))
+  (func $floats (type $0) (param $f f32) (result f32)
+    (local $t f32)
+    (f32.add
+      (local.get $t)
+      (local.get $f)
+    )
+  )
+  (func $neg (type $1) (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 (type $2) (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 (type $3) (param $i1 i32) (param $i2 i32) (param $i3 i32) (result i32)
+    (block $topmost (result i32)
+      (local.get $i3)
+    )
+  )
+)
diff --git a/binaryen/test/printf.c b/binaryen/test/printf.c
new file mode 100644
--- /dev/null
+++ b/binaryen/test/printf.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+
+int main() {
+    int a = 12345;
+    unsigned b = 123456;
+    long c = 1234567;
+    unsigned long d = 12345678;
+    long long e = 1234567891011;
+    unsigned long long f = 123456789101112;
+
+    printf(
+        "int a = %d\n"
+        "unsigned b = %u\n"
+        "long c = %ld\n"
+        "unsigned long d = %lu\n"
+        "long long e = %lld\n"
+        "unsigned long long f = %llu\n"
+        , a, b, c, d, e, f);
+    return 0;
+}
diff --git a/binaryen/test/printf.txt b/binaryen/test/printf.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/printf.txt
@@ -0,0 +1,6 @@
+int a = 12345
+unsigned b = 123456
+long c = 1234567
+unsigned long d = 12345678
+long long e = 1234567891011
+unsigned long long f = 123456789101112
diff --git a/binaryen/test/reduce/destructive.wast b/binaryen/test/reduce/destructive.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reduce/destructive.wast
@@ -0,0 +1,10 @@
+(module
+  (export "x" (func $x))
+  (func $x (param $x i32) (result i32)
+    (if (i32.eq (local.get $x) (i32.const 98658746))
+      (unreachable) ;; this can be removed destructively, since we do not sent this param
+    )
+    (i32.const 100)
+  )
+)
+
diff --git a/binaryen/test/reduce/destructive.wast.txt b/binaryen/test/reduce/destructive.wast.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reduce/destructive.wast.txt
@@ -0,0 +1,8 @@
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "x" (func $0))
+ (func $0 (param $0 i32) (result i32)
+  (i32.const 100)
+ )
+)
+
diff --git a/binaryen/test/reduce/imports.wast b/binaryen/test/reduce/imports.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reduce/imports.wast
@@ -0,0 +1,17 @@
+(module
+  (import "env" "func" (func $import))
+  (export "x" (func $x))
+  (func $x (result i32)
+    (nop)
+    (nop)
+    (nop)
+    (call $import)
+    (drop (i32.const 1234))
+    (i32.const 5678) ;; easily reducible
+  )
+  (func $not-exported
+    (nop)
+    (unreachable)
+  )
+)
+
diff --git a/binaryen/test/reduce/imports.wast.txt b/binaryen/test/reduce/imports.wast.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reduce/imports.wast.txt
@@ -0,0 +1,8 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (export "x" (func $0))
+ (func $0 (result i32)
+  (i32.const 5678)
+ )
+)
+
diff --git a/binaryen/test/reduce/memory_table.wast b/binaryen/test/reduce/memory_table.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reduce/memory_table.wast
@@ -0,0 +1,31 @@
+(module
+ (type $i (func (result i32)))
+ (memory $0 256 256)
+ (table 481 481 funcref)
+ (elem (i32.const 0) $f0 $f0 $f1 $f2 $f0 $f3 $f0)
+ (data (i32.const 0) "p\0bflkj")
+ (data (i32.const 10960) "1234hello")
+ (export "f1" (func $f1))
+ (export "f2" (func $f2))
+ (export "f4" (func $f4))
+ (func $f0 (result i32)
+  (i32.const 1234)
+ )
+ (func $f1
+  (i32.store (i32.const 1000) (i32.const 65530)) ;; dead store
+ )
+ (func $f2 (result i32)
+  (i32.store (i32.const 0) (i32.const 65530))
+  (i32.load (i32.const 0)) ;; load the written stuff
+ )
+ (func $f3 (result i32)
+  (i32.load (i32.const 10964)) ;; load the 'hell'
+ )
+ (func $f4 (result i32)
+  (i32.add
+   (call_indirect (type $i) (i32.const 3))
+   (call_indirect (type $i) (i32.const 0))
+  )
+ )
+)
+
diff --git a/binaryen/test/reduce/memory_table.wast.txt b/binaryen/test/reduce/memory_table.wast.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reduce/memory_table.wast.txt
@@ -0,0 +1,27 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (memory $0 256 256)
+ (export "f1" (func $0))
+ (export "f2" (func $1))
+ (export "f4" (func $2))
+ (func $0
+  (nop)
+ )
+ (func $1 (result i32)
+  (i32.store
+   (i32.const 0)
+   (i32.const 65530)
+  )
+  (i32.load
+   (i32.const 0)
+  )
+ )
+ (func $2 (result i32)
+  (i32.add
+   (call $1)
+   (i32.const 1234)
+  )
+ )
+)
+
diff --git a/binaryen/test/reduce/simple.wast b/binaryen/test/reduce/simple.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reduce/simple.wast
@@ -0,0 +1,15 @@
+(module
+  (export "x" (func $x))
+  (func $x (result i32)
+    (nop)
+    (nop)
+    (nop)
+    (drop (i32.const 1234))
+    (i32.const 5678) ;; easily reducible
+  )
+  (func $not-exported
+    (nop)
+    (unreachable)
+  )
+)
+
diff --git a/binaryen/test/reduce/simple.wast.txt b/binaryen/test/reduce/simple.wast.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reduce/simple.wast.txt
@@ -0,0 +1,8 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (export "x" (func $0))
+ (func $0 (result i32)
+  (i32.const 5678)
+ )
+)
+
diff --git a/binaryen/test/reference-types.wast b/binaryen/test/reference-types.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reference-types.wast
@@ -0,0 +1,772 @@
+;; reftype :: externref | funcref | exnref
+
+;; NOTE: the subtyping relationship has been removed from the reference-types proposal but an
+;; `--enable-anyref` feature flag is present in Binaryen that we use below to test subtyping.
+;;
+;; reftype :: reftype | anyref
+;; reftype <: anyref
+
+(module
+  (type $sig_externref (func (param externref)))
+  (type $sig_funcref (func (param funcref)))
+  (type $sig_exnref (func (param exnref)))
+  (type $sig_anyref (func (param anyref)))
+
+  (func $take_externref (param externref))
+  (func $take_funcref (param funcref))
+  (func $take_exnref (param exnref))
+  (func $take_anyref (param anyref))
+  (func $foo)
+
+  (table funcref (elem $take_externref $take_funcref $take_exnref $take_anyref))
+
+  (import "env" "import_func" (func $import_func (param externref) (result funcref)))
+  (import "env" "import_global" (global $import_global externref))
+  (export "export_func" (func $import_func (param externref) (result funcref)))
+  (export "export_global" (global $import_global))
+
+  ;; Test global initializer expressions
+  (global $global_externref (mut externref) (ref.null extern))
+  (global $global_funcref (mut funcref) (ref.null func))
+  (global $global_funcref_func (mut funcref) (ref.func $foo))
+  (global $global_exnref (mut exnref) (ref.null exn))
+  (global $global_anyref (mut anyref) (ref.null any))
+
+  ;; Test subtype relationship in global initializer expressions
+  (global $global_anyref2 (mut anyref) (ref.null extern))
+  (global $global_anyref3 (mut anyref) (ref.null func))
+  (global $global_anyref4 (mut anyref) (ref.func $foo))
+  (global $global_anyref5 (mut anyref) (ref.null exn))
+
+  (func $test
+    (local $local_externref externref)
+    (local $local_funcref funcref)
+    (local $local_exnref exnref)
+    (local $local_anyref anyref)
+
+    ;; Test types for local.get/set
+    (local.set $local_externref (local.get $local_externref))
+    (local.set $local_externref (global.get $global_externref))
+    (local.set $local_externref (ref.null extern))
+    (local.set $local_funcref (local.get $local_funcref))
+    (local.set $local_funcref (global.get $global_funcref))
+    (local.set $local_funcref (ref.null func))
+    (local.set $local_funcref (ref.func $foo))
+    (local.set $local_exnref (local.get $local_exnref))
+    (local.set $local_exnref (global.get $global_exnref))
+    (local.set $local_exnref (ref.null exn))
+    (local.set $local_anyref (local.get $local_anyref))
+    (local.set $local_anyref (global.get $global_anyref))
+    (local.set $local_anyref (ref.null any))
+
+    ;; Test subtype relationship for local.set
+    (local.set $local_anyref (local.get $local_externref))
+    (local.set $local_anyref (global.get $global_externref))
+    (local.set $local_anyref (ref.null extern))
+    (local.set $local_anyref (local.get $local_funcref))
+    (local.set $local_anyref (global.get $global_funcref))
+    (local.set $local_anyref (ref.null func))
+    (local.set $local_anyref (ref.func $foo))
+    (local.set $local_anyref (local.get $local_exnref))
+    (local.set $local_anyref (global.get $global_exnref))
+    (local.set $local_anyref (ref.null exn))
+
+    ;; Test types for global.get/set
+    (global.set $global_externref (global.get $global_externref))
+    (global.set $global_externref (local.get $local_externref))
+    (global.set $global_externref (ref.null extern))
+    (global.set $global_funcref (global.get $global_funcref))
+    (global.set $global_funcref (local.get $local_funcref))
+    (global.set $global_funcref (ref.null func))
+    (global.set $global_funcref (ref.func $foo))
+    (global.set $global_exnref (global.get $global_exnref))
+    (global.set $global_exnref (local.get $local_exnref))
+    (global.set $global_exnref (ref.null exn))
+    (global.set $global_anyref (global.get $global_anyref))
+    (global.set $global_anyref (local.get $local_anyref))
+    (global.set $global_anyref (ref.null any))
+
+    ;; Test subtype relationship for global.set
+    (global.set $global_anyref (global.get $global_externref))
+    (global.set $global_anyref (local.get $local_externref))
+    (global.set $global_anyref (ref.null extern))
+    (global.set $global_anyref (global.get $global_funcref))
+    (global.set $global_anyref (local.get $local_funcref))
+    (global.set $global_anyref (ref.null func))
+    (global.set $global_anyref (ref.func $foo))
+    (global.set $global_anyref (global.get $global_exnref))
+    (global.set $global_anyref (local.get $local_exnref))
+    (global.set $global_anyref (ref.null exn))
+
+    ;; Test function call params
+    (call $take_externref (local.get $local_externref))
+    (call $take_externref (global.get $global_externref))
+    (call $take_externref (ref.null extern))
+    (call $take_funcref (local.get $local_funcref))
+    (call $take_funcref (global.get $global_funcref))
+    (call $take_funcref (ref.null func))
+    (call $take_funcref (ref.func $foo))
+    (call $take_exnref (local.get $local_exnref))
+    (call $take_exnref (global.get $global_exnref))
+    (call $take_exnref (ref.null exn))
+    (call $take_anyref (local.get $local_anyref))
+    (call $take_anyref (global.get $global_anyref))
+    (call $take_anyref (ref.null any))
+
+    ;; Test subtype relationship for function call params
+    (call $take_anyref (local.get $local_externref))
+    (call $take_anyref (global.get $global_externref))
+    (call $take_anyref (ref.null extern))
+    (call $take_anyref (local.get $local_funcref))
+    (call $take_anyref (global.get $global_funcref))
+    (call $take_anyref (ref.null func))
+    (call $take_anyref (ref.func $foo))
+    (call $take_anyref (local.get $local_exnref))
+    (call $take_anyref (global.get $global_exnref))
+    (call $take_anyref (ref.null exn))
+
+    ;; Test call_indirect params
+    (call_indirect (type $sig_externref) (local.get $local_externref) (i32.const 0))
+    (call_indirect (type $sig_externref) (global.get $global_externref) (i32.const 0))
+    (call_indirect (type $sig_externref) (ref.null extern) (i32.const 0))
+    (call_indirect (type $sig_funcref) (local.get $local_funcref) (i32.const 1))
+    (call_indirect (type $sig_funcref) (global.get $global_funcref) (i32.const 1))
+    (call_indirect (type $sig_funcref) (ref.null func) (i32.const 1))
+    (call_indirect (type $sig_funcref) (ref.func $foo) (i32.const 1))
+    (call_indirect (type $sig_exnref) (local.get $local_exnref) (i32.const 2))
+    (call_indirect (type $sig_exnref) (global.get $global_exnref) (i32.const 2))
+    (call_indirect (type $sig_exnref) (ref.null exn) (i32.const 2))
+    (call_indirect (type $sig_anyref) (local.get $local_anyref) (i32.const 3))
+    (call_indirect (type $sig_anyref) (global.get $global_anyref) (i32.const 3))
+    (call_indirect (type $sig_anyref) (ref.null any) (i32.const 3))
+
+    ;; Test subtype relationship for call_indirect params
+    (call_indirect (type $sig_anyref) (local.get $local_externref) (i32.const 3))
+    (call_indirect (type $sig_anyref) (global.get $global_externref) (i32.const 3))
+    (call_indirect (type $sig_anyref) (ref.null extern) (i32.const 3))
+    (call_indirect (type $sig_anyref) (local.get $local_funcref) (i32.const 3))
+    (call_indirect (type $sig_anyref) (global.get $global_funcref) (i32.const 3))
+    (call_indirect (type $sig_anyref) (ref.null func) (i32.const 3))
+    (call_indirect (type $sig_anyref) (ref.func $foo) (i32.const 3))
+    (call_indirect (type $sig_anyref) (local.get $local_exnref) (i32.const 3))
+    (call_indirect (type $sig_anyref) (global.get $global_exnref) (i32.const 3))
+    (call_indirect (type $sig_anyref) (ref.null exn) (i32.const 3))
+
+    ;; Test block return type
+    (drop
+      (block (result externref)
+        (br_if 0 (local.get $local_externref) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result externref)
+        (br_if 0 (global.get $global_externref) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result externref)
+        (br_if 0 (ref.null extern) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result funcref)
+        (br_if 0 (local.get $local_funcref) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result funcref)
+        (br_if 0 (global.get $global_funcref) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result funcref)
+        (br_if 0 (ref.null func) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result funcref)
+        (br_if 0 (ref.func $foo) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result exnref)
+        (br_if 0 (local.get $local_exnref) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result exnref)
+        (br_if 0 (global.get $global_exnref) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result exnref)
+        (br_if 0 (ref.null exn) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result anyref)
+        (br_if 0 (local.get $local_anyref) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result anyref)
+        (br_if 0 (global.get $global_anyref) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result anyref)
+        (br_if 0 (ref.null any) (i32.const 1))
+      )
+    )
+
+    ;; Test subtype relationship for block return type
+    (drop
+      (block (result anyref)
+        (br_if 0 (local.get $local_externref) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result anyref)
+        (br_if 0 (local.get $local_funcref) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result anyref)
+        (br_if 0 (local.get $local_exnref) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result anyref)
+        (br_if 0 (ref.null extern) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result anyref)
+        (br_if 0 (ref.null func) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result anyref)
+        (br_if 0 (ref.func $foo) (i32.const 1))
+      )
+    )
+    (drop
+      (block (result anyref)
+        (br_if 0 (ref.null exn) (i32.const 1))
+      )
+    )
+
+    ;; Test loop return type
+    (drop
+      (loop (result externref)
+        (local.get $local_externref)
+      )
+    )
+    (drop
+      (loop (result externref)
+        (global.get $global_externref)
+      )
+    )
+    (drop
+      (loop (result externref)
+        (ref.null extern)
+      )
+    )
+    (drop
+      (loop (result funcref)
+        (local.get $local_funcref)
+      )
+    )
+    (drop
+      (loop (result funcref)
+        (global.get $global_funcref)
+      )
+    )
+    (drop
+      (loop (result funcref)
+        (ref.null func)
+      )
+    )
+    (drop
+      (loop (result funcref)
+        (ref.func $foo)
+      )
+    )
+    (drop
+      (loop (result exnref)
+        (local.get $local_exnref)
+      )
+    )
+    (drop
+      (loop (result exnref)
+        (global.get $global_exnref)
+      )
+    )
+    (drop
+      (loop (result exnref)
+        (ref.null exn)
+      )
+    )
+    (drop
+      (loop (result anyref)
+        (local.get $local_anyref)
+      )
+    )
+    (drop
+      (loop (result anyref)
+        (global.get $global_anyref)
+      )
+    )
+    (drop
+      (loop (result anyref)
+        (ref.null any)
+      )
+    )
+
+    ;; Test subtype relationship for loop return type
+    (drop
+      (loop (result anyref)
+        (local.get $local_externref)
+      )
+    )
+    (drop
+      (loop (result anyref)
+        (global.get $global_externref)
+      )
+    )
+    (drop
+      (loop (result anyref)
+        (ref.null extern)
+      )
+    )
+    (drop
+      (loop (result anyref)
+        (local.get $local_funcref)
+      )
+    )
+    (drop
+      (loop (result anyref)
+        (global.get $global_funcref)
+      )
+    )
+    (drop
+      (loop (result anyref)
+        (ref.null func)
+      )
+    )
+    (drop
+      (loop (result anyref)
+        (ref.func $foo)
+      )
+    )
+    (drop
+      (loop (result anyref)
+        (local.get $local_exnref)
+      )
+    )
+    (drop
+      (loop (result anyref)
+        (global.get $global_exnref)
+      )
+    )
+    (drop
+      (loop (result anyref)
+        (ref.null exn)
+      )
+    )
+
+    ;; Test if return type
+    (drop
+      (if (result externref)
+        (i32.const 1)
+        (local.get $local_externref)
+        (ref.null extern)
+      )
+    )
+    (drop
+      (if (result funcref)
+        (i32.const 1)
+        (local.get $local_funcref)
+        (ref.null func)
+      )
+    )
+    (drop
+      (if (result exnref)
+        (i32.const 1)
+        (local.get $local_exnref)
+        (ref.null exn)
+      )
+    )
+    (drop
+      (if (result anyref)
+        (i32.const 1)
+        (local.get $local_anyref)
+        (ref.null any)
+      )
+    )
+
+    ;; Test subtype relationship for if return type
+    (drop
+      (if (result anyref)
+        (i32.const 1)
+        (local.get $local_externref)
+        (local.get $local_funcref)
+      )
+    )
+    (drop
+      (if (result anyref)
+        (i32.const 1)
+        (local.get $local_externref)
+        (local.get $local_exnref)
+      )
+    )
+    (drop
+      (if (result anyref)
+        (i32.const 1)
+        (local.get $local_funcref)
+        (local.get $local_exnref)
+      )
+    )
+    (drop
+      (if (result anyref)
+        (i32.const 1)
+        (ref.null extern)
+        (ref.null func)
+      )
+    )
+    (drop
+      (if (result anyref)
+        (i32.const 1)
+        (ref.null extern)
+        (ref.null exn)
+      )
+    )
+    (drop
+      (if (result anyref)
+        (i32.const 1)
+        (ref.null func)
+        (ref.null exn)
+      )
+    )
+    (drop
+      (if (result anyref)
+        (i32.const 1)
+        (ref.func $foo)
+        (ref.null extern)
+      )
+    )
+
+    ;; Test try return type
+    (drop
+      (try (result externref)
+        (do
+          (local.get $local_externref)
+        )
+        (catch
+          (drop (pop exnref))
+          (ref.null extern)
+        )
+      )
+    )
+    (drop
+      (try (result funcref)
+        (do
+          (ref.func $foo)
+        )
+        (catch
+          (drop (pop exnref))
+          (ref.null func)
+        )
+      )
+    )
+    (drop
+      (try (result exnref)
+        (do
+          (ref.null exn)
+        )
+        (catch
+          (pop exnref)
+        )
+      )
+    )
+
+    ;; Test subtype relationship for try return type
+    (drop
+      (try (result anyref)
+        (do
+          (local.get $local_externref)
+        )
+        (catch
+          (drop (pop exnref))
+          (ref.func $foo)
+        )
+      )
+    )
+    (drop
+      (try (result anyref)
+        (do
+          (local.get $local_externref)
+        )
+        (catch
+          (pop exnref)
+        )
+      )
+    )
+    (drop
+      (try (result anyref)
+        (do
+          (ref.func $foo)
+        )
+        (catch
+          (drop (pop exnref))
+          (local.get $local_externref)
+        )
+      )
+    )
+    (drop
+      (try (result anyref)
+        (do
+          (ref.func $foo)
+        )
+        (catch
+          (pop exnref)
+        )
+      )
+    )
+    (drop
+      (try (result anyref)
+        (do
+          (ref.null exn)
+        )
+        (catch
+          (drop (pop exnref))
+          (local.get $local_externref)
+        )
+      )
+    )
+    (drop
+      (try (result anyref)
+        (do
+          (ref.null exn)
+        )
+        (catch
+          (drop (pop exnref))
+          (ref.func $foo)
+        )
+      )
+    )
+
+    ;; Test typed select
+    (drop
+      (select (result externref)
+        (local.get $local_externref)
+        (ref.null extern)
+        (i32.const 1)
+      )
+    )
+    (drop
+      (select (result funcref)
+        (local.get $local_funcref)
+        (ref.null func)
+        (i32.const 1)
+      )
+    )
+    (drop
+      (select (result exnref)
+        (local.get $local_exnref)
+        (ref.null exn)
+        (i32.const 1)
+      )
+    )
+    (drop
+      (select (result i32)
+        (i32.const 0)
+        (i32.const 2)
+        (i32.const 1)
+      )
+    )
+
+    ;; Test subtype relationship for typed select
+    (drop
+      (select (result anyref)
+        (local.get $local_externref)
+        (local.get $local_funcref)
+        (i32.const 1)
+      )
+    )
+    (drop
+      (select (result anyref)
+        (local.get $local_externref)
+        (local.get $local_exnref)
+        (i32.const 1)
+      )
+    )
+    (drop
+      (select (result anyref)
+        (local.get $local_funcref)
+        (local.get $local_externref)
+        (i32.const 1)
+      )
+    )
+    (drop
+      (select (result anyref)
+        (local.get $local_funcref)
+        (local.get $local_exnref)
+        (i32.const 1)
+      )
+    )
+    (drop
+      (select (result anyref)
+        (local.get $local_exnref)
+        (local.get $local_externref)
+        (i32.const 1)
+      )
+    )
+    (drop
+      (select (result anyref)
+        (local.get $local_exnref)
+        (local.get $local_funcref)
+        (i32.const 1)
+      )
+    )
+
+    ;; ref.is_null takes any reference types
+    (drop (ref.is_null (local.get $local_externref)))
+    (drop (ref.is_null (global.get $global_externref)))
+    (drop (ref.is_null (ref.null extern)))
+    (drop (ref.is_null (local.get $local_funcref)))
+    (drop (ref.is_null (global.get $global_funcref)))
+    (drop (ref.is_null (ref.null func)))
+    (drop (ref.is_null (ref.func $foo)))
+    (drop (ref.is_null (local.get $local_exnref)))
+    (drop (ref.is_null (global.get $global_exnref)))
+    (drop (ref.is_null (ref.null exn)))
+    (drop (ref.is_null (local.get $local_anyref)))
+    (drop (ref.is_null (global.get $global_anyref)))
+    (drop (ref.is_null (ref.null any)))
+  )
+
+  ;; Test function return type
+  (func $return_externref_local (result externref)
+    (local $local_externref externref)
+    (local.get $local_externref)
+  )
+  (func $return_externref_global (result externref)
+    (global.get $global_externref)
+  )
+  (func $return_externref_null (result externref)
+    (ref.null extern)
+  )
+  (func $return_funcref_local (result funcref)
+    (local $local_funcref funcref)
+    (local.get $local_funcref)
+  )
+  (func $return_funcref_global (result funcref)
+    (global.get $global_funcref)
+  )
+  (func $return_funcref_null (result funcref)
+    (ref.null func)
+  )
+  (func $return_funcref_func (result funcref)
+    (ref.func $foo)
+  )
+  (func $return_exnref_local (result exnref)
+    (local $local_exnref exnref)
+    (local.get $local_exnref)
+  )
+  (func $return_exnref_global (result exnref)
+    (global.get $global_exnref)
+  )
+  (func $return_exnref_null (result exnref)
+    (ref.null exn)
+  )
+  (func $return_anyref_local (result anyref)
+    (local $local_anyref anyref)
+    (local.get $local_anyref)
+  )
+  (func $return_anyref_global (result anyref)
+    (global.get $global_anyref)
+  )
+  (func $return_anyref_null (result anyref)
+    (ref.null any)
+  )
+
+  ;; Test subtype relationship in function return type
+  (func $return_anyref2 (result anyref)
+    (local $local_externref externref)
+    (local.get $local_externref)
+  )
+  (func $return_anyref3 (result anyref)
+    (global.get $global_externref)
+  )
+  (func $return_anyref4 (result anyref)
+    (ref.null extern)
+  )
+  (func $return_anyref5 (result anyref)
+    (local $local_funcref funcref)
+    (local.get $local_funcref)
+  )
+  (func $return_anyref6 (result anyref)
+    (global.get $global_funcref)
+  )
+  (func $return_anyref7 (result anyref)
+    (ref.null func)
+  )
+  (func $return_anyref8 (result anyref)
+    (ref.func $foo)
+  )
+  (func $return_anyref9 (result anyref)
+    (local $local_exnref exnref)
+    (local.get $local_exnref)
+  )
+  (func $return_anyref10 (result anyref)
+    (global.get $global_exnref)
+  )
+  (func $return_anyref11 (result anyref)
+    (ref.null exn)
+  )
+
+  ;; Test returns
+  (func $returns_externref (result externref)
+    (local $local_externref externref)
+    (return (local.get $local_externref))
+    (return (global.get $global_externref))
+    (return (ref.null extern))
+  )
+  (func $returns_funcref (result funcref)
+    (local $local_funcref funcref)
+    (return (local.get $local_funcref))
+    (return (global.get $global_funcref))
+    (return (ref.func $foo))
+    (return (ref.null func))
+  )
+  (func $returns_exnref (result exnref)
+    (local $local_exnref exnref)
+    (return (local.get $local_exnref))
+    (return (global.get $global_exnref))
+    (return (ref.null exn))
+  )
+  (func $returns_anyref (result anyref)
+    (local $local_anyref anyref)
+    (return (local.get $local_anyref))
+    (return (global.get $global_anyref))
+    (return (ref.null any))
+  )
+
+  ;; Test subtype relationship in returns
+  (func $returns_anyref2 (result anyref)
+    (local $local_externref externref)
+    (local $local_funcref funcref)
+    (local $local_exnref exnref)
+    (return (local.get $local_externref))
+    (return (global.get $global_externref))
+    (return (ref.null extern))
+    (return (local.get $local_funcref))
+    (return (global.get $global_funcref))
+    (return (ref.func $foo))
+    (return (ref.null func))
+    (return (local.get $local_exnref))
+    (return (global.get $global_exnref))
+    (return (ref.null exn))
+  )
+)
diff --git a/binaryen/test/reference-types.wast.from-wast b/binaryen/test/reference-types.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reference-types.wast.from-wast
@@ -0,0 +1,1104 @@
+(module
+ (type $none_=>_anyref (func (result anyref)))
+ (type $anyref_=>_none (func (param anyref)))
+ (type $funcref_=>_none (func (param funcref)))
+ (type $none_=>_funcref (func (result funcref)))
+ (type $externref_=>_none (func (param externref)))
+ (type $exnref_=>_none (func (param exnref)))
+ (type $none_=>_externref (func (result externref)))
+ (type $none_=>_exnref (func (result exnref)))
+ (type $none_=>_none (func))
+ (type $externref_=>_funcref (func (param externref) (result funcref)))
+ (import "env" "import_global" (global $import_global externref))
+ (import "env" "import_func" (func $import_func (param externref) (result funcref)))
+ (table $0 4 4 funcref)
+ (elem (i32.const 0) $take_externref $take_funcref $take_exnref $take_anyref)
+ (global $global_externref (mut externref) (ref.null extern))
+ (global $global_funcref (mut funcref) (ref.null func))
+ (global $global_funcref_func (mut funcref) (ref.func $foo))
+ (global $global_exnref (mut exnref) (ref.null exn))
+ (global $global_anyref (mut anyref) (ref.null any))
+ (global $global_anyref2 (mut anyref) (ref.null extern))
+ (global $global_anyref3 (mut anyref) (ref.null func))
+ (global $global_anyref4 (mut anyref) (ref.func $foo))
+ (global $global_anyref5 (mut anyref) (ref.null exn))
+ (export "export_func" (func $import_func))
+ (export "export_global" (global $import_global))
+ (func $take_externref (param $0 externref)
+  (nop)
+ )
+ (func $take_funcref (param $0 funcref)
+  (nop)
+ )
+ (func $take_exnref (param $0 exnref)
+  (nop)
+ )
+ (func $take_anyref (param $0 anyref)
+  (nop)
+ )
+ (func $foo
+  (nop)
+ )
+ (func $test
+  (local $local_externref externref)
+  (local $local_funcref funcref)
+  (local $local_exnref exnref)
+  (local $local_anyref anyref)
+  (local.set $local_externref
+   (local.get $local_externref)
+  )
+  (local.set $local_externref
+   (global.get $global_externref)
+  )
+  (local.set $local_externref
+   (ref.null extern)
+  )
+  (local.set $local_funcref
+   (local.get $local_funcref)
+  )
+  (local.set $local_funcref
+   (global.get $global_funcref)
+  )
+  (local.set $local_funcref
+   (ref.null func)
+  )
+  (local.set $local_funcref
+   (ref.func $foo)
+  )
+  (local.set $local_exnref
+   (local.get $local_exnref)
+  )
+  (local.set $local_exnref
+   (global.get $global_exnref)
+  )
+  (local.set $local_exnref
+   (ref.null exn)
+  )
+  (local.set $local_anyref
+   (local.get $local_anyref)
+  )
+  (local.set $local_anyref
+   (global.get $global_anyref)
+  )
+  (local.set $local_anyref
+   (ref.null any)
+  )
+  (local.set $local_anyref
+   (local.get $local_externref)
+  )
+  (local.set $local_anyref
+   (global.get $global_externref)
+  )
+  (local.set $local_anyref
+   (ref.null extern)
+  )
+  (local.set $local_anyref
+   (local.get $local_funcref)
+  )
+  (local.set $local_anyref
+   (global.get $global_funcref)
+  )
+  (local.set $local_anyref
+   (ref.null func)
+  )
+  (local.set $local_anyref
+   (ref.func $foo)
+  )
+  (local.set $local_anyref
+   (local.get $local_exnref)
+  )
+  (local.set $local_anyref
+   (global.get $global_exnref)
+  )
+  (local.set $local_anyref
+   (ref.null exn)
+  )
+  (global.set $global_externref
+   (global.get $global_externref)
+  )
+  (global.set $global_externref
+   (local.get $local_externref)
+  )
+  (global.set $global_externref
+   (ref.null extern)
+  )
+  (global.set $global_funcref
+   (global.get $global_funcref)
+  )
+  (global.set $global_funcref
+   (local.get $local_funcref)
+  )
+  (global.set $global_funcref
+   (ref.null func)
+  )
+  (global.set $global_funcref
+   (ref.func $foo)
+  )
+  (global.set $global_exnref
+   (global.get $global_exnref)
+  )
+  (global.set $global_exnref
+   (local.get $local_exnref)
+  )
+  (global.set $global_exnref
+   (ref.null exn)
+  )
+  (global.set $global_anyref
+   (global.get $global_anyref)
+  )
+  (global.set $global_anyref
+   (local.get $local_anyref)
+  )
+  (global.set $global_anyref
+   (ref.null any)
+  )
+  (global.set $global_anyref
+   (global.get $global_externref)
+  )
+  (global.set $global_anyref
+   (local.get $local_externref)
+  )
+  (global.set $global_anyref
+   (ref.null extern)
+  )
+  (global.set $global_anyref
+   (global.get $global_funcref)
+  )
+  (global.set $global_anyref
+   (local.get $local_funcref)
+  )
+  (global.set $global_anyref
+   (ref.null func)
+  )
+  (global.set $global_anyref
+   (ref.func $foo)
+  )
+  (global.set $global_anyref
+   (global.get $global_exnref)
+  )
+  (global.set $global_anyref
+   (local.get $local_exnref)
+  )
+  (global.set $global_anyref
+   (ref.null exn)
+  )
+  (call $take_externref
+   (local.get $local_externref)
+  )
+  (call $take_externref
+   (global.get $global_externref)
+  )
+  (call $take_externref
+   (ref.null extern)
+  )
+  (call $take_funcref
+   (local.get $local_funcref)
+  )
+  (call $take_funcref
+   (global.get $global_funcref)
+  )
+  (call $take_funcref
+   (ref.null func)
+  )
+  (call $take_funcref
+   (ref.func $foo)
+  )
+  (call $take_exnref
+   (local.get $local_exnref)
+  )
+  (call $take_exnref
+   (global.get $global_exnref)
+  )
+  (call $take_exnref
+   (ref.null exn)
+  )
+  (call $take_anyref
+   (local.get $local_anyref)
+  )
+  (call $take_anyref
+   (global.get $global_anyref)
+  )
+  (call $take_anyref
+   (ref.null any)
+  )
+  (call $take_anyref
+   (local.get $local_externref)
+  )
+  (call $take_anyref
+   (global.get $global_externref)
+  )
+  (call $take_anyref
+   (ref.null extern)
+  )
+  (call $take_anyref
+   (local.get $local_funcref)
+  )
+  (call $take_anyref
+   (global.get $global_funcref)
+  )
+  (call $take_anyref
+   (ref.null func)
+  )
+  (call $take_anyref
+   (ref.func $foo)
+  )
+  (call $take_anyref
+   (local.get $local_exnref)
+  )
+  (call $take_anyref
+   (global.get $global_exnref)
+  )
+  (call $take_anyref
+   (ref.null exn)
+  )
+  (call_indirect (type $externref_=>_none)
+   (local.get $local_externref)
+   (i32.const 0)
+  )
+  (call_indirect (type $externref_=>_none)
+   (global.get $global_externref)
+   (i32.const 0)
+  )
+  (call_indirect (type $externref_=>_none)
+   (ref.null extern)
+   (i32.const 0)
+  )
+  (call_indirect (type $funcref_=>_none)
+   (local.get $local_funcref)
+   (i32.const 1)
+  )
+  (call_indirect (type $funcref_=>_none)
+   (global.get $global_funcref)
+   (i32.const 1)
+  )
+  (call_indirect (type $funcref_=>_none)
+   (ref.null func)
+   (i32.const 1)
+  )
+  (call_indirect (type $funcref_=>_none)
+   (ref.func $foo)
+   (i32.const 1)
+  )
+  (call_indirect (type $exnref_=>_none)
+   (local.get $local_exnref)
+   (i32.const 2)
+  )
+  (call_indirect (type $exnref_=>_none)
+   (global.get $global_exnref)
+   (i32.const 2)
+  )
+  (call_indirect (type $exnref_=>_none)
+   (ref.null exn)
+   (i32.const 2)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (local.get $local_anyref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (global.get $global_anyref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (ref.null any)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (local.get $local_externref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (global.get $global_externref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (ref.null extern)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (local.get $local_funcref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (global.get $global_funcref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (ref.null func)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (ref.func $foo)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (local.get $local_exnref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (global.get $global_exnref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (ref.null exn)
+   (i32.const 3)
+  )
+  (drop
+   (block $block (result externref)
+    (br_if $block
+     (local.get $local_externref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block0 (result externref)
+    (br_if $block0
+     (global.get $global_externref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block1 (result externref)
+    (br_if $block1
+     (ref.null extern)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block2 (result funcref)
+    (br_if $block2
+     (local.get $local_funcref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block3 (result funcref)
+    (br_if $block3
+     (global.get $global_funcref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block4 (result funcref)
+    (br_if $block4
+     (ref.null func)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block5 (result funcref)
+    (br_if $block5
+     (ref.func $foo)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block6 (result exnref)
+    (br_if $block6
+     (local.get $local_exnref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block7 (result exnref)
+    (br_if $block7
+     (global.get $global_exnref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block8 (result exnref)
+    (br_if $block8
+     (ref.null exn)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block9 (result anyref)
+    (br_if $block9
+     (local.get $local_anyref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block10 (result anyref)
+    (br_if $block10
+     (global.get $global_anyref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block11 (result anyref)
+    (br_if $block11
+     (ref.null any)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block12 (result anyref)
+    (br_if $block12
+     (local.get $local_externref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block13 (result anyref)
+    (br_if $block13
+     (local.get $local_funcref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block14 (result anyref)
+    (br_if $block14
+     (local.get $local_exnref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block15 (result anyref)
+    (br_if $block15
+     (ref.null extern)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block16 (result anyref)
+    (br_if $block16
+     (ref.null func)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block17 (result anyref)
+    (br_if $block17
+     (ref.func $foo)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $block18 (result anyref)
+    (br_if $block18
+     (ref.null exn)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (loop $loop-in (result externref)
+    (local.get $local_externref)
+   )
+  )
+  (drop
+   (loop $loop-in19 (result externref)
+    (global.get $global_externref)
+   )
+  )
+  (drop
+   (loop $loop-in20 (result externref)
+    (ref.null extern)
+   )
+  )
+  (drop
+   (loop $loop-in21 (result funcref)
+    (local.get $local_funcref)
+   )
+  )
+  (drop
+   (loop $loop-in22 (result funcref)
+    (global.get $global_funcref)
+   )
+  )
+  (drop
+   (loop $loop-in23 (result funcref)
+    (ref.null func)
+   )
+  )
+  (drop
+   (loop $loop-in24 (result funcref)
+    (ref.func $foo)
+   )
+  )
+  (drop
+   (loop $loop-in25 (result exnref)
+    (local.get $local_exnref)
+   )
+  )
+  (drop
+   (loop $loop-in26 (result exnref)
+    (global.get $global_exnref)
+   )
+  )
+  (drop
+   (loop $loop-in27 (result exnref)
+    (ref.null exn)
+   )
+  )
+  (drop
+   (loop $loop-in28 (result anyref)
+    (local.get $local_anyref)
+   )
+  )
+  (drop
+   (loop $loop-in29 (result anyref)
+    (global.get $global_anyref)
+   )
+  )
+  (drop
+   (loop $loop-in30 (result anyref)
+    (ref.null any)
+   )
+  )
+  (drop
+   (loop $loop-in31 (result anyref)
+    (local.get $local_externref)
+   )
+  )
+  (drop
+   (loop $loop-in32 (result anyref)
+    (global.get $global_externref)
+   )
+  )
+  (drop
+   (loop $loop-in33 (result anyref)
+    (ref.null extern)
+   )
+  )
+  (drop
+   (loop $loop-in34 (result anyref)
+    (local.get $local_funcref)
+   )
+  )
+  (drop
+   (loop $loop-in35 (result anyref)
+    (global.get $global_funcref)
+   )
+  )
+  (drop
+   (loop $loop-in36 (result anyref)
+    (ref.null func)
+   )
+  )
+  (drop
+   (loop $loop-in37 (result anyref)
+    (ref.func $foo)
+   )
+  )
+  (drop
+   (loop $loop-in38 (result anyref)
+    (local.get $local_exnref)
+   )
+  )
+  (drop
+   (loop $loop-in39 (result anyref)
+    (global.get $global_exnref)
+   )
+  )
+  (drop
+   (loop $loop-in40 (result anyref)
+    (ref.null exn)
+   )
+  )
+  (drop
+   (if (result externref)
+    (i32.const 1)
+    (local.get $local_externref)
+    (ref.null extern)
+   )
+  )
+  (drop
+   (if (result funcref)
+    (i32.const 1)
+    (local.get $local_funcref)
+    (ref.null func)
+   )
+  )
+  (drop
+   (if (result exnref)
+    (i32.const 1)
+    (local.get $local_exnref)
+    (ref.null exn)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (local.get $local_anyref)
+    (ref.null any)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (local.get $local_externref)
+    (local.get $local_funcref)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (local.get $local_externref)
+    (local.get $local_exnref)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (local.get $local_funcref)
+    (local.get $local_exnref)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (ref.null extern)
+    (ref.null func)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (ref.null extern)
+    (ref.null exn)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (ref.null func)
+    (ref.null exn)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (ref.func $foo)
+    (ref.null extern)
+   )
+  )
+  (drop
+   (try (result externref)
+    (do
+     (local.get $local_externref)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (ref.null extern)
+    )
+   )
+  )
+  (drop
+   (try (result funcref)
+    (do
+     (ref.func $foo)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (ref.null func)
+    )
+   )
+  )
+  (drop
+   (try (result exnref)
+    (do
+     (ref.null exn)
+    )
+    (catch
+     (pop exnref)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (local.get $local_externref)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (ref.func $foo)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (local.get $local_externref)
+    )
+    (catch
+     (pop exnref)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (ref.func $foo)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (local.get $local_externref)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (ref.func $foo)
+    )
+    (catch
+     (pop exnref)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (ref.null exn)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (local.get $local_externref)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (ref.null exn)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (ref.func $foo)
+    )
+   )
+  )
+  (drop
+   (select (result externref)
+    (local.get $local_externref)
+    (ref.null extern)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result funcref)
+    (local.get $local_funcref)
+    (ref.null func)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result exnref)
+    (local.get $local_exnref)
+    (ref.null exn)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 2)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $local_externref)
+    (local.get $local_funcref)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $local_externref)
+    (local.get $local_exnref)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $local_funcref)
+    (local.get $local_externref)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $local_funcref)
+    (local.get $local_exnref)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $local_exnref)
+    (local.get $local_externref)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $local_exnref)
+    (local.get $local_funcref)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (ref.is_null
+    (local.get $local_externref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (global.get $global_externref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (ref.null extern)
+   )
+  )
+  (drop
+   (ref.is_null
+    (local.get $local_funcref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (global.get $global_funcref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (ref.null func)
+   )
+  )
+  (drop
+   (ref.is_null
+    (ref.func $foo)
+   )
+  )
+  (drop
+   (ref.is_null
+    (local.get $local_exnref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (global.get $global_exnref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (ref.null exn)
+   )
+  )
+  (drop
+   (ref.is_null
+    (local.get $local_anyref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (global.get $global_anyref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (ref.null any)
+   )
+  )
+ )
+ (func $return_externref_local (result externref)
+  (local $local_externref externref)
+  (local.get $local_externref)
+ )
+ (func $return_externref_global (result externref)
+  (global.get $global_externref)
+ )
+ (func $return_externref_null (result externref)
+  (ref.null extern)
+ )
+ (func $return_funcref_local (result funcref)
+  (local $local_funcref funcref)
+  (local.get $local_funcref)
+ )
+ (func $return_funcref_global (result funcref)
+  (global.get $global_funcref)
+ )
+ (func $return_funcref_null (result funcref)
+  (ref.null func)
+ )
+ (func $return_funcref_func (result funcref)
+  (ref.func $foo)
+ )
+ (func $return_exnref_local (result exnref)
+  (local $local_exnref exnref)
+  (local.get $local_exnref)
+ )
+ (func $return_exnref_global (result exnref)
+  (global.get $global_exnref)
+ )
+ (func $return_exnref_null (result exnref)
+  (ref.null exn)
+ )
+ (func $return_anyref_local (result anyref)
+  (local $local_anyref anyref)
+  (local.get $local_anyref)
+ )
+ (func $return_anyref_global (result anyref)
+  (global.get $global_anyref)
+ )
+ (func $return_anyref_null (result anyref)
+  (ref.null any)
+ )
+ (func $return_anyref2 (result anyref)
+  (local $local_externref externref)
+  (local.get $local_externref)
+ )
+ (func $return_anyref3 (result anyref)
+  (global.get $global_externref)
+ )
+ (func $return_anyref4 (result anyref)
+  (ref.null extern)
+ )
+ (func $return_anyref5 (result anyref)
+  (local $local_funcref funcref)
+  (local.get $local_funcref)
+ )
+ (func $return_anyref6 (result anyref)
+  (global.get $global_funcref)
+ )
+ (func $return_anyref7 (result anyref)
+  (ref.null func)
+ )
+ (func $return_anyref8 (result anyref)
+  (ref.func $foo)
+ )
+ (func $return_anyref9 (result anyref)
+  (local $local_exnref exnref)
+  (local.get $local_exnref)
+ )
+ (func $return_anyref10 (result anyref)
+  (global.get $global_exnref)
+ )
+ (func $return_anyref11 (result anyref)
+  (ref.null exn)
+ )
+ (func $returns_externref (result externref)
+  (local $local_externref externref)
+  (return
+   (local.get $local_externref)
+  )
+  (return
+   (global.get $global_externref)
+  )
+  (return
+   (ref.null extern)
+  )
+ )
+ (func $returns_funcref (result funcref)
+  (local $local_funcref funcref)
+  (return
+   (local.get $local_funcref)
+  )
+  (return
+   (global.get $global_funcref)
+  )
+  (return
+   (ref.func $foo)
+  )
+  (return
+   (ref.null func)
+  )
+ )
+ (func $returns_exnref (result exnref)
+  (local $local_exnref exnref)
+  (return
+   (local.get $local_exnref)
+  )
+  (return
+   (global.get $global_exnref)
+  )
+  (return
+   (ref.null exn)
+  )
+ )
+ (func $returns_anyref (result anyref)
+  (local $local_anyref anyref)
+  (return
+   (local.get $local_anyref)
+  )
+  (return
+   (global.get $global_anyref)
+  )
+  (return
+   (ref.null any)
+  )
+ )
+ (func $returns_anyref2 (result anyref)
+  (local $local_externref externref)
+  (local $local_funcref funcref)
+  (local $local_exnref exnref)
+  (return
+   (local.get $local_externref)
+  )
+  (return
+   (global.get $global_externref)
+  )
+  (return
+   (ref.null extern)
+  )
+  (return
+   (local.get $local_funcref)
+  )
+  (return
+   (global.get $global_funcref)
+  )
+  (return
+   (ref.func $foo)
+  )
+  (return
+   (ref.null func)
+  )
+  (return
+   (local.get $local_exnref)
+  )
+  (return
+   (global.get $global_exnref)
+  )
+  (return
+   (ref.null exn)
+  )
+ )
+)
diff --git a/binaryen/test/reference-types.wast.fromBinary b/binaryen/test/reference-types.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reference-types.wast.fromBinary
@@ -0,0 +1,1051 @@
+(module
+ (type $none_=>_anyref (func (result anyref)))
+ (type $anyref_=>_none (func (param anyref)))
+ (type $funcref_=>_none (func (param funcref)))
+ (type $none_=>_funcref (func (result funcref)))
+ (type $externref_=>_none (func (param externref)))
+ (type $exnref_=>_none (func (param exnref)))
+ (type $none_=>_externref (func (result externref)))
+ (type $none_=>_exnref (func (result exnref)))
+ (type $none_=>_none (func))
+ (type $externref_=>_funcref (func (param externref) (result funcref)))
+ (import "env" "import_global" (global $import_global externref))
+ (import "env" "import_func" (func $import_func (param externref) (result funcref)))
+ (table $0 4 4 funcref)
+ (elem (i32.const 0) $take_externref $take_funcref $take_exnref $take_anyref)
+ (global $global_externref (mut externref) (ref.null extern))
+ (global $global_funcref (mut funcref) (ref.null func))
+ (global $global_funcref_func (mut funcref) (ref.func $foo))
+ (global $global_exnref (mut exnref) (ref.null exn))
+ (global $global_anyref (mut anyref) (ref.null any))
+ (global $global_anyref2 (mut anyref) (ref.null extern))
+ (global $global_anyref3 (mut anyref) (ref.null func))
+ (global $global_anyref4 (mut anyref) (ref.func $foo))
+ (global $global_anyref5 (mut anyref) (ref.null exn))
+ (export "export_func" (func $import_func))
+ (export "export_global" (global $import_global))
+ (func $take_externref (param $0 externref)
+  (nop)
+ )
+ (func $take_funcref (param $0 funcref)
+  (nop)
+ )
+ (func $take_exnref (param $0 exnref)
+  (nop)
+ )
+ (func $take_anyref (param $0 anyref)
+  (nop)
+ )
+ (func $foo
+  (nop)
+ )
+ (func $test
+  (local $local_externref funcref)
+  (local $local_funcref externref)
+  (local $local_exnref exnref)
+  (local $local_anyref anyref)
+  (local.set $local_funcref
+   (local.get $local_funcref)
+  )
+  (local.set $local_funcref
+   (global.get $global_externref)
+  )
+  (local.set $local_funcref
+   (ref.null extern)
+  )
+  (local.set $local_externref
+   (local.get $local_externref)
+  )
+  (local.set $local_externref
+   (global.get $global_funcref)
+  )
+  (local.set $local_externref
+   (ref.null func)
+  )
+  (local.set $local_externref
+   (ref.func $foo)
+  )
+  (local.set $local_exnref
+   (local.get $local_exnref)
+  )
+  (local.set $local_exnref
+   (global.get $global_exnref)
+  )
+  (local.set $local_exnref
+   (ref.null exn)
+  )
+  (local.set $local_anyref
+   (local.get $local_anyref)
+  )
+  (local.set $local_anyref
+   (global.get $global_anyref)
+  )
+  (local.set $local_anyref
+   (ref.null any)
+  )
+  (local.set $local_anyref
+   (local.get $local_funcref)
+  )
+  (local.set $local_anyref
+   (global.get $global_externref)
+  )
+  (local.set $local_anyref
+   (ref.null extern)
+  )
+  (local.set $local_anyref
+   (local.get $local_externref)
+  )
+  (local.set $local_anyref
+   (global.get $global_funcref)
+  )
+  (local.set $local_anyref
+   (ref.null func)
+  )
+  (local.set $local_anyref
+   (ref.func $foo)
+  )
+  (local.set $local_anyref
+   (local.get $local_exnref)
+  )
+  (local.set $local_anyref
+   (global.get $global_exnref)
+  )
+  (local.set $local_anyref
+   (ref.null exn)
+  )
+  (global.set $global_externref
+   (global.get $global_externref)
+  )
+  (global.set $global_externref
+   (local.get $local_funcref)
+  )
+  (global.set $global_externref
+   (ref.null extern)
+  )
+  (global.set $global_funcref
+   (global.get $global_funcref)
+  )
+  (global.set $global_funcref
+   (local.get $local_externref)
+  )
+  (global.set $global_funcref
+   (ref.null func)
+  )
+  (global.set $global_funcref
+   (ref.func $foo)
+  )
+  (global.set $global_exnref
+   (global.get $global_exnref)
+  )
+  (global.set $global_exnref
+   (local.get $local_exnref)
+  )
+  (global.set $global_exnref
+   (ref.null exn)
+  )
+  (global.set $global_anyref
+   (global.get $global_anyref)
+  )
+  (global.set $global_anyref
+   (local.get $local_anyref)
+  )
+  (global.set $global_anyref
+   (ref.null any)
+  )
+  (global.set $global_anyref
+   (global.get $global_externref)
+  )
+  (global.set $global_anyref
+   (local.get $local_funcref)
+  )
+  (global.set $global_anyref
+   (ref.null extern)
+  )
+  (global.set $global_anyref
+   (global.get $global_funcref)
+  )
+  (global.set $global_anyref
+   (local.get $local_externref)
+  )
+  (global.set $global_anyref
+   (ref.null func)
+  )
+  (global.set $global_anyref
+   (ref.func $foo)
+  )
+  (global.set $global_anyref
+   (global.get $global_exnref)
+  )
+  (global.set $global_anyref
+   (local.get $local_exnref)
+  )
+  (global.set $global_anyref
+   (ref.null exn)
+  )
+  (call $take_externref
+   (local.get $local_funcref)
+  )
+  (call $take_externref
+   (global.get $global_externref)
+  )
+  (call $take_externref
+   (ref.null extern)
+  )
+  (call $take_funcref
+   (local.get $local_externref)
+  )
+  (call $take_funcref
+   (global.get $global_funcref)
+  )
+  (call $take_funcref
+   (ref.null func)
+  )
+  (call $take_funcref
+   (ref.func $foo)
+  )
+  (call $take_exnref
+   (local.get $local_exnref)
+  )
+  (call $take_exnref
+   (global.get $global_exnref)
+  )
+  (call $take_exnref
+   (ref.null exn)
+  )
+  (call $take_anyref
+   (local.get $local_anyref)
+  )
+  (call $take_anyref
+   (global.get $global_anyref)
+  )
+  (call $take_anyref
+   (ref.null any)
+  )
+  (call $take_anyref
+   (local.get $local_funcref)
+  )
+  (call $take_anyref
+   (global.get $global_externref)
+  )
+  (call $take_anyref
+   (ref.null extern)
+  )
+  (call $take_anyref
+   (local.get $local_externref)
+  )
+  (call $take_anyref
+   (global.get $global_funcref)
+  )
+  (call $take_anyref
+   (ref.null func)
+  )
+  (call $take_anyref
+   (ref.func $foo)
+  )
+  (call $take_anyref
+   (local.get $local_exnref)
+  )
+  (call $take_anyref
+   (global.get $global_exnref)
+  )
+  (call $take_anyref
+   (ref.null exn)
+  )
+  (call_indirect (type $externref_=>_none)
+   (local.get $local_funcref)
+   (i32.const 0)
+  )
+  (call_indirect (type $externref_=>_none)
+   (global.get $global_externref)
+   (i32.const 0)
+  )
+  (call_indirect (type $externref_=>_none)
+   (ref.null extern)
+   (i32.const 0)
+  )
+  (call_indirect (type $funcref_=>_none)
+   (local.get $local_externref)
+   (i32.const 1)
+  )
+  (call_indirect (type $funcref_=>_none)
+   (global.get $global_funcref)
+   (i32.const 1)
+  )
+  (call_indirect (type $funcref_=>_none)
+   (ref.null func)
+   (i32.const 1)
+  )
+  (call_indirect (type $funcref_=>_none)
+   (ref.func $foo)
+   (i32.const 1)
+  )
+  (call_indirect (type $exnref_=>_none)
+   (local.get $local_exnref)
+   (i32.const 2)
+  )
+  (call_indirect (type $exnref_=>_none)
+   (global.get $global_exnref)
+   (i32.const 2)
+  )
+  (call_indirect (type $exnref_=>_none)
+   (ref.null exn)
+   (i32.const 2)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (local.get $local_anyref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (global.get $global_anyref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (ref.null any)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (local.get $local_funcref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (global.get $global_externref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (ref.null extern)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (local.get $local_externref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (global.get $global_funcref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (ref.null func)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (ref.func $foo)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (local.get $local_exnref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (global.get $global_exnref)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (ref.null exn)
+   (i32.const 3)
+  )
+  (drop
+   (block $label$1 (result externref)
+    (br_if $label$1
+     (local.get $local_funcref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$2 (result externref)
+    (br_if $label$2
+     (global.get $global_externref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$3 (result externref)
+    (br_if $label$3
+     (ref.null extern)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$4 (result funcref)
+    (br_if $label$4
+     (local.get $local_externref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$5 (result funcref)
+    (br_if $label$5
+     (global.get $global_funcref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$6 (result funcref)
+    (br_if $label$6
+     (ref.null func)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$7 (result funcref)
+    (br_if $label$7
+     (ref.func $foo)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$8 (result exnref)
+    (br_if $label$8
+     (local.get $local_exnref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$9 (result exnref)
+    (br_if $label$9
+     (global.get $global_exnref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$10 (result exnref)
+    (br_if $label$10
+     (ref.null exn)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$11 (result anyref)
+    (br_if $label$11
+     (local.get $local_anyref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$12 (result anyref)
+    (br_if $label$12
+     (global.get $global_anyref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$13 (result anyref)
+    (br_if $label$13
+     (ref.null any)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$14 (result anyref)
+    (br_if $label$14
+     (local.get $local_funcref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$15 (result anyref)
+    (br_if $label$15
+     (local.get $local_externref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$16 (result anyref)
+    (br_if $label$16
+     (local.get $local_exnref)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$17 (result anyref)
+    (br_if $label$17
+     (ref.null extern)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$18 (result anyref)
+    (br_if $label$18
+     (ref.null func)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$19 (result anyref)
+    (br_if $label$19
+     (ref.func $foo)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$20 (result anyref)
+    (br_if $label$20
+     (ref.null exn)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (loop $label$21 (result externref)
+    (local.get $local_funcref)
+   )
+  )
+  (drop
+   (loop $label$22 (result externref)
+    (global.get $global_externref)
+   )
+  )
+  (drop
+   (loop $label$23 (result externref)
+    (ref.null extern)
+   )
+  )
+  (drop
+   (loop $label$24 (result funcref)
+    (local.get $local_externref)
+   )
+  )
+  (drop
+   (loop $label$25 (result funcref)
+    (global.get $global_funcref)
+   )
+  )
+  (drop
+   (loop $label$26 (result funcref)
+    (ref.null func)
+   )
+  )
+  (drop
+   (loop $label$27 (result funcref)
+    (ref.func $foo)
+   )
+  )
+  (drop
+   (loop $label$28 (result exnref)
+    (local.get $local_exnref)
+   )
+  )
+  (drop
+   (loop $label$29 (result exnref)
+    (global.get $global_exnref)
+   )
+  )
+  (drop
+   (loop $label$30 (result exnref)
+    (ref.null exn)
+   )
+  )
+  (drop
+   (loop $label$31 (result anyref)
+    (local.get $local_anyref)
+   )
+  )
+  (drop
+   (loop $label$32 (result anyref)
+    (global.get $global_anyref)
+   )
+  )
+  (drop
+   (loop $label$33 (result anyref)
+    (ref.null any)
+   )
+  )
+  (drop
+   (loop $label$34 (result anyref)
+    (local.get $local_funcref)
+   )
+  )
+  (drop
+   (loop $label$35 (result anyref)
+    (global.get $global_externref)
+   )
+  )
+  (drop
+   (loop $label$36 (result anyref)
+    (ref.null extern)
+   )
+  )
+  (drop
+   (loop $label$37 (result anyref)
+    (local.get $local_externref)
+   )
+  )
+  (drop
+   (loop $label$38 (result anyref)
+    (global.get $global_funcref)
+   )
+  )
+  (drop
+   (loop $label$39 (result anyref)
+    (ref.null func)
+   )
+  )
+  (drop
+   (loop $label$40 (result anyref)
+    (ref.func $foo)
+   )
+  )
+  (drop
+   (loop $label$41 (result anyref)
+    (local.get $local_exnref)
+   )
+  )
+  (drop
+   (loop $label$42 (result anyref)
+    (global.get $global_exnref)
+   )
+  )
+  (drop
+   (loop $label$43 (result anyref)
+    (ref.null exn)
+   )
+  )
+  (drop
+   (if (result externref)
+    (i32.const 1)
+    (local.get $local_funcref)
+    (ref.null extern)
+   )
+  )
+  (drop
+   (if (result funcref)
+    (i32.const 1)
+    (local.get $local_externref)
+    (ref.null func)
+   )
+  )
+  (drop
+   (if (result exnref)
+    (i32.const 1)
+    (local.get $local_exnref)
+    (ref.null exn)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (local.get $local_anyref)
+    (ref.null any)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (local.get $local_funcref)
+    (local.get $local_externref)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (local.get $local_funcref)
+    (local.get $local_exnref)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (local.get $local_externref)
+    (local.get $local_exnref)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (ref.null extern)
+    (ref.null func)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (ref.null extern)
+    (ref.null exn)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (ref.null func)
+    (ref.null exn)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (ref.func $foo)
+    (ref.null extern)
+   )
+  )
+  (drop
+   (try (result externref)
+    (do
+     (local.get $local_funcref)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (ref.null extern)
+    )
+   )
+  )
+  (drop
+   (try (result funcref)
+    (do
+     (ref.func $foo)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (ref.null func)
+    )
+   )
+  )
+  (drop
+   (try (result exnref)
+    (do
+     (ref.null exn)
+    )
+    (catch
+     (pop exnref)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (local.get $local_funcref)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (ref.func $foo)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (local.get $local_funcref)
+    )
+    (catch
+     (pop exnref)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (ref.func $foo)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (local.get $local_funcref)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (ref.func $foo)
+    )
+    (catch
+     (pop exnref)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (ref.null exn)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (local.get $local_funcref)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (ref.null exn)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (ref.func $foo)
+    )
+   )
+  )
+  (drop
+   (select (result externref)
+    (local.get $local_funcref)
+    (ref.null extern)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result funcref)
+    (local.get $local_externref)
+    (ref.null func)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result exnref)
+    (local.get $local_exnref)
+    (ref.null exn)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 2)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $local_funcref)
+    (local.get $local_externref)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $local_funcref)
+    (local.get $local_exnref)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $local_externref)
+    (local.get $local_funcref)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $local_externref)
+    (local.get $local_exnref)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $local_exnref)
+    (local.get $local_funcref)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $local_exnref)
+    (local.get $local_externref)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (ref.is_null
+    (local.get $local_funcref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (global.get $global_externref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (ref.null extern)
+   )
+  )
+  (drop
+   (ref.is_null
+    (local.get $local_externref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (global.get $global_funcref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (ref.null func)
+   )
+  )
+  (drop
+   (ref.is_null
+    (ref.func $foo)
+   )
+  )
+  (drop
+   (ref.is_null
+    (local.get $local_exnref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (global.get $global_exnref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (ref.null exn)
+   )
+  )
+  (drop
+   (ref.is_null
+    (local.get $local_anyref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (global.get $global_anyref)
+   )
+  )
+  (drop
+   (ref.is_null
+    (ref.null any)
+   )
+  )
+ )
+ (func $return_externref_local (result externref)
+  (local $local_externref externref)
+  (local.get $local_externref)
+ )
+ (func $return_externref_global (result externref)
+  (global.get $global_externref)
+ )
+ (func $return_externref_null (result externref)
+  (ref.null extern)
+ )
+ (func $return_funcref_local (result funcref)
+  (local $local_funcref funcref)
+  (local.get $local_funcref)
+ )
+ (func $return_funcref_global (result funcref)
+  (global.get $global_funcref)
+ )
+ (func $return_funcref_null (result funcref)
+  (ref.null func)
+ )
+ (func $return_funcref_func (result funcref)
+  (ref.func $foo)
+ )
+ (func $return_exnref_local (result exnref)
+  (local $local_exnref exnref)
+  (local.get $local_exnref)
+ )
+ (func $return_exnref_global (result exnref)
+  (global.get $global_exnref)
+ )
+ (func $return_exnref_null (result exnref)
+  (ref.null exn)
+ )
+ (func $return_anyref_local (result anyref)
+  (local $local_anyref anyref)
+  (local.get $local_anyref)
+ )
+ (func $return_anyref_global (result anyref)
+  (global.get $global_anyref)
+ )
+ (func $return_anyref_null (result anyref)
+  (ref.null any)
+ )
+ (func $return_anyref2 (result anyref)
+  (local $local_externref externref)
+  (local.get $local_externref)
+ )
+ (func $return_anyref3 (result anyref)
+  (global.get $global_externref)
+ )
+ (func $return_anyref4 (result anyref)
+  (ref.null extern)
+ )
+ (func $return_anyref5 (result anyref)
+  (local $local_funcref funcref)
+  (local.get $local_funcref)
+ )
+ (func $return_anyref6 (result anyref)
+  (global.get $global_funcref)
+ )
+ (func $return_anyref7 (result anyref)
+  (ref.null func)
+ )
+ (func $return_anyref8 (result anyref)
+  (ref.func $foo)
+ )
+ (func $return_anyref9 (result anyref)
+  (local $local_exnref exnref)
+  (local.get $local_exnref)
+ )
+ (func $return_anyref10 (result anyref)
+  (global.get $global_exnref)
+ )
+ (func $return_anyref11 (result anyref)
+  (ref.null exn)
+ )
+ (func $returns_externref (result externref)
+  (local $local_externref externref)
+  (return
+   (local.get $local_externref)
+  )
+ )
+ (func $returns_funcref (result funcref)
+  (local $local_funcref funcref)
+  (return
+   (local.get $local_funcref)
+  )
+ )
+ (func $returns_exnref (result exnref)
+  (local $local_exnref exnref)
+  (return
+   (local.get $local_exnref)
+  )
+ )
+ (func $returns_anyref (result anyref)
+  (local $local_anyref anyref)
+  (return
+   (local.get $local_anyref)
+  )
+ )
+ (func $returns_anyref2 (result anyref)
+  (local $local_externref funcref)
+  (local $local_funcref externref)
+  (local $local_exnref exnref)
+  (return
+   (local.get $local_funcref)
+  )
+ )
+)
+
diff --git a/binaryen/test/reference-types.wast.fromBinary.noDebugInfo b/binaryen/test/reference-types.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reference-types.wast.fromBinary.noDebugInfo
@@ -0,0 +1,1051 @@
+(module
+ (type $none_=>_anyref (func (result anyref)))
+ (type $anyref_=>_none (func (param anyref)))
+ (type $funcref_=>_none (func (param funcref)))
+ (type $none_=>_funcref (func (result funcref)))
+ (type $externref_=>_none (func (param externref)))
+ (type $exnref_=>_none (func (param exnref)))
+ (type $none_=>_externref (func (result externref)))
+ (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_func" (func $fimport$0 (param externref) (result funcref)))
+ (table $0 4 4 funcref)
+ (elem (i32.const 0) $0 $1 $2 $3)
+ (global $global$0 (mut externref) (ref.null extern))
+ (global $global$1 (mut funcref) (ref.null func))
+ (global $global$2 (mut funcref) (ref.func $4))
+ (global $global$3 (mut exnref) (ref.null exn))
+ (global $global$4 (mut anyref) (ref.null any))
+ (global $global$5 (mut anyref) (ref.null extern))
+ (global $global$6 (mut anyref) (ref.null func))
+ (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))
+ (func $0 (param $0 externref)
+  (nop)
+ )
+ (func $1 (param $0 funcref)
+  (nop)
+ )
+ (func $2 (param $0 exnref)
+  (nop)
+ )
+ (func $3 (param $0 anyref)
+  (nop)
+ )
+ (func $4
+  (nop)
+ )
+ (func $5
+  (local $0 funcref)
+  (local $1 externref)
+  (local $2 exnref)
+  (local $3 anyref)
+  (local.set $1
+   (local.get $1)
+  )
+  (local.set $1
+   (global.get $global$0)
+  )
+  (local.set $1
+   (ref.null extern)
+  )
+  (local.set $0
+   (local.get $0)
+  )
+  (local.set $0
+   (global.get $global$1)
+  )
+  (local.set $0
+   (ref.null func)
+  )
+  (local.set $0
+   (ref.func $4)
+  )
+  (local.set $2
+   (local.get $2)
+  )
+  (local.set $2
+   (global.get $global$3)
+  )
+  (local.set $2
+   (ref.null exn)
+  )
+  (local.set $3
+   (local.get $3)
+  )
+  (local.set $3
+   (global.get $global$4)
+  )
+  (local.set $3
+   (ref.null any)
+  )
+  (local.set $3
+   (local.get $1)
+  )
+  (local.set $3
+   (global.get $global$0)
+  )
+  (local.set $3
+   (ref.null extern)
+  )
+  (local.set $3
+   (local.get $0)
+  )
+  (local.set $3
+   (global.get $global$1)
+  )
+  (local.set $3
+   (ref.null func)
+  )
+  (local.set $3
+   (ref.func $4)
+  )
+  (local.set $3
+   (local.get $2)
+  )
+  (local.set $3
+   (global.get $global$3)
+  )
+  (local.set $3
+   (ref.null exn)
+  )
+  (global.set $global$0
+   (global.get $global$0)
+  )
+  (global.set $global$0
+   (local.get $1)
+  )
+  (global.set $global$0
+   (ref.null extern)
+  )
+  (global.set $global$1
+   (global.get $global$1)
+  )
+  (global.set $global$1
+   (local.get $0)
+  )
+  (global.set $global$1
+   (ref.null func)
+  )
+  (global.set $global$1
+   (ref.func $4)
+  )
+  (global.set $global$3
+   (global.get $global$3)
+  )
+  (global.set $global$3
+   (local.get $2)
+  )
+  (global.set $global$3
+   (ref.null exn)
+  )
+  (global.set $global$4
+   (global.get $global$4)
+  )
+  (global.set $global$4
+   (local.get $3)
+  )
+  (global.set $global$4
+   (ref.null any)
+  )
+  (global.set $global$4
+   (global.get $global$0)
+  )
+  (global.set $global$4
+   (local.get $1)
+  )
+  (global.set $global$4
+   (ref.null extern)
+  )
+  (global.set $global$4
+   (global.get $global$1)
+  )
+  (global.set $global$4
+   (local.get $0)
+  )
+  (global.set $global$4
+   (ref.null func)
+  )
+  (global.set $global$4
+   (ref.func $4)
+  )
+  (global.set $global$4
+   (global.get $global$3)
+  )
+  (global.set $global$4
+   (local.get $2)
+  )
+  (global.set $global$4
+   (ref.null exn)
+  )
+  (call $0
+   (local.get $1)
+  )
+  (call $0
+   (global.get $global$0)
+  )
+  (call $0
+   (ref.null extern)
+  )
+  (call $1
+   (local.get $0)
+  )
+  (call $1
+   (global.get $global$1)
+  )
+  (call $1
+   (ref.null func)
+  )
+  (call $1
+   (ref.func $4)
+  )
+  (call $2
+   (local.get $2)
+  )
+  (call $2
+   (global.get $global$3)
+  )
+  (call $2
+   (ref.null exn)
+  )
+  (call $3
+   (local.get $3)
+  )
+  (call $3
+   (global.get $global$4)
+  )
+  (call $3
+   (ref.null any)
+  )
+  (call $3
+   (local.get $1)
+  )
+  (call $3
+   (global.get $global$0)
+  )
+  (call $3
+   (ref.null extern)
+  )
+  (call $3
+   (local.get $0)
+  )
+  (call $3
+   (global.get $global$1)
+  )
+  (call $3
+   (ref.null func)
+  )
+  (call $3
+   (ref.func $4)
+  )
+  (call $3
+   (local.get $2)
+  )
+  (call $3
+   (global.get $global$3)
+  )
+  (call $3
+   (ref.null exn)
+  )
+  (call_indirect (type $externref_=>_none)
+   (local.get $1)
+   (i32.const 0)
+  )
+  (call_indirect (type $externref_=>_none)
+   (global.get $global$0)
+   (i32.const 0)
+  )
+  (call_indirect (type $externref_=>_none)
+   (ref.null extern)
+   (i32.const 0)
+  )
+  (call_indirect (type $funcref_=>_none)
+   (local.get $0)
+   (i32.const 1)
+  )
+  (call_indirect (type $funcref_=>_none)
+   (global.get $global$1)
+   (i32.const 1)
+  )
+  (call_indirect (type $funcref_=>_none)
+   (ref.null func)
+   (i32.const 1)
+  )
+  (call_indirect (type $funcref_=>_none)
+   (ref.func $4)
+   (i32.const 1)
+  )
+  (call_indirect (type $exnref_=>_none)
+   (local.get $2)
+   (i32.const 2)
+  )
+  (call_indirect (type $exnref_=>_none)
+   (global.get $global$3)
+   (i32.const 2)
+  )
+  (call_indirect (type $exnref_=>_none)
+   (ref.null exn)
+   (i32.const 2)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (local.get $3)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (global.get $global$4)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (ref.null any)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (local.get $1)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (global.get $global$0)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (ref.null extern)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (local.get $0)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (global.get $global$1)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (ref.null func)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (ref.func $4)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (local.get $2)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (global.get $global$3)
+   (i32.const 3)
+  )
+  (call_indirect (type $anyref_=>_none)
+   (ref.null exn)
+   (i32.const 3)
+  )
+  (drop
+   (block $label$1 (result externref)
+    (br_if $label$1
+     (local.get $1)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$2 (result externref)
+    (br_if $label$2
+     (global.get $global$0)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$3 (result externref)
+    (br_if $label$3
+     (ref.null extern)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$4 (result funcref)
+    (br_if $label$4
+     (local.get $0)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$5 (result funcref)
+    (br_if $label$5
+     (global.get $global$1)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$6 (result funcref)
+    (br_if $label$6
+     (ref.null func)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$7 (result funcref)
+    (br_if $label$7
+     (ref.func $4)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$8 (result exnref)
+    (br_if $label$8
+     (local.get $2)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$9 (result exnref)
+    (br_if $label$9
+     (global.get $global$3)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$10 (result exnref)
+    (br_if $label$10
+     (ref.null exn)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$11 (result anyref)
+    (br_if $label$11
+     (local.get $3)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$12 (result anyref)
+    (br_if $label$12
+     (global.get $global$4)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$13 (result anyref)
+    (br_if $label$13
+     (ref.null any)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$14 (result anyref)
+    (br_if $label$14
+     (local.get $1)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$15 (result anyref)
+    (br_if $label$15
+     (local.get $0)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$16 (result anyref)
+    (br_if $label$16
+     (local.get $2)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$17 (result anyref)
+    (br_if $label$17
+     (ref.null extern)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$18 (result anyref)
+    (br_if $label$18
+     (ref.null func)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$19 (result anyref)
+    (br_if $label$19
+     (ref.func $4)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block $label$20 (result anyref)
+    (br_if $label$20
+     (ref.null exn)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (loop $label$21 (result externref)
+    (local.get $1)
+   )
+  )
+  (drop
+   (loop $label$22 (result externref)
+    (global.get $global$0)
+   )
+  )
+  (drop
+   (loop $label$23 (result externref)
+    (ref.null extern)
+   )
+  )
+  (drop
+   (loop $label$24 (result funcref)
+    (local.get $0)
+   )
+  )
+  (drop
+   (loop $label$25 (result funcref)
+    (global.get $global$1)
+   )
+  )
+  (drop
+   (loop $label$26 (result funcref)
+    (ref.null func)
+   )
+  )
+  (drop
+   (loop $label$27 (result funcref)
+    (ref.func $4)
+   )
+  )
+  (drop
+   (loop $label$28 (result exnref)
+    (local.get $2)
+   )
+  )
+  (drop
+   (loop $label$29 (result exnref)
+    (global.get $global$3)
+   )
+  )
+  (drop
+   (loop $label$30 (result exnref)
+    (ref.null exn)
+   )
+  )
+  (drop
+   (loop $label$31 (result anyref)
+    (local.get $3)
+   )
+  )
+  (drop
+   (loop $label$32 (result anyref)
+    (global.get $global$4)
+   )
+  )
+  (drop
+   (loop $label$33 (result anyref)
+    (ref.null any)
+   )
+  )
+  (drop
+   (loop $label$34 (result anyref)
+    (local.get $1)
+   )
+  )
+  (drop
+   (loop $label$35 (result anyref)
+    (global.get $global$0)
+   )
+  )
+  (drop
+   (loop $label$36 (result anyref)
+    (ref.null extern)
+   )
+  )
+  (drop
+   (loop $label$37 (result anyref)
+    (local.get $0)
+   )
+  )
+  (drop
+   (loop $label$38 (result anyref)
+    (global.get $global$1)
+   )
+  )
+  (drop
+   (loop $label$39 (result anyref)
+    (ref.null func)
+   )
+  )
+  (drop
+   (loop $label$40 (result anyref)
+    (ref.func $4)
+   )
+  )
+  (drop
+   (loop $label$41 (result anyref)
+    (local.get $2)
+   )
+  )
+  (drop
+   (loop $label$42 (result anyref)
+    (global.get $global$3)
+   )
+  )
+  (drop
+   (loop $label$43 (result anyref)
+    (ref.null exn)
+   )
+  )
+  (drop
+   (if (result externref)
+    (i32.const 1)
+    (local.get $1)
+    (ref.null extern)
+   )
+  )
+  (drop
+   (if (result funcref)
+    (i32.const 1)
+    (local.get $0)
+    (ref.null func)
+   )
+  )
+  (drop
+   (if (result exnref)
+    (i32.const 1)
+    (local.get $2)
+    (ref.null exn)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (local.get $3)
+    (ref.null any)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (local.get $1)
+    (local.get $0)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (local.get $1)
+    (local.get $2)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (local.get $0)
+    (local.get $2)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (ref.null extern)
+    (ref.null func)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (ref.null extern)
+    (ref.null exn)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (ref.null func)
+    (ref.null exn)
+   )
+  )
+  (drop
+   (if (result anyref)
+    (i32.const 1)
+    (ref.func $4)
+    (ref.null extern)
+   )
+  )
+  (drop
+   (try (result externref)
+    (do
+     (local.get $1)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (ref.null extern)
+    )
+   )
+  )
+  (drop
+   (try (result funcref)
+    (do
+     (ref.func $4)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (ref.null func)
+    )
+   )
+  )
+  (drop
+   (try (result exnref)
+    (do
+     (ref.null exn)
+    )
+    (catch
+     (pop exnref)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (local.get $1)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (ref.func $4)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (local.get $1)
+    )
+    (catch
+     (pop exnref)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (ref.func $4)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (local.get $1)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (ref.func $4)
+    )
+    (catch
+     (pop exnref)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (ref.null exn)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (local.get $1)
+    )
+   )
+  )
+  (drop
+   (try (result anyref)
+    (do
+     (ref.null exn)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (ref.func $4)
+    )
+   )
+  )
+  (drop
+   (select (result externref)
+    (local.get $1)
+    (ref.null extern)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result funcref)
+    (local.get $0)
+    (ref.null func)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result exnref)
+    (local.get $2)
+    (ref.null exn)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select
+    (i32.const 0)
+    (i32.const 2)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $1)
+    (local.get $0)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $1)
+    (local.get $2)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $0)
+    (local.get $1)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $0)
+    (local.get $2)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $2)
+    (local.get $1)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select (result anyref)
+    (local.get $2)
+    (local.get $0)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (ref.is_null
+    (local.get $1)
+   )
+  )
+  (drop
+   (ref.is_null
+    (global.get $global$0)
+   )
+  )
+  (drop
+   (ref.is_null
+    (ref.null extern)
+   )
+  )
+  (drop
+   (ref.is_null
+    (local.get $0)
+   )
+  )
+  (drop
+   (ref.is_null
+    (global.get $global$1)
+   )
+  )
+  (drop
+   (ref.is_null
+    (ref.null func)
+   )
+  )
+  (drop
+   (ref.is_null
+    (ref.func $4)
+   )
+  )
+  (drop
+   (ref.is_null
+    (local.get $2)
+   )
+  )
+  (drop
+   (ref.is_null
+    (global.get $global$3)
+   )
+  )
+  (drop
+   (ref.is_null
+    (ref.null exn)
+   )
+  )
+  (drop
+   (ref.is_null
+    (local.get $3)
+   )
+  )
+  (drop
+   (ref.is_null
+    (global.get $global$4)
+   )
+  )
+  (drop
+   (ref.is_null
+    (ref.null any)
+   )
+  )
+ )
+ (func $6 (result externref)
+  (local $0 externref)
+  (local.get $0)
+ )
+ (func $7 (result externref)
+  (global.get $global$0)
+ )
+ (func $8 (result externref)
+  (ref.null extern)
+ )
+ (func $9 (result funcref)
+  (local $0 funcref)
+  (local.get $0)
+ )
+ (func $10 (result funcref)
+  (global.get $global$1)
+ )
+ (func $11 (result funcref)
+  (ref.null func)
+ )
+ (func $12 (result funcref)
+  (ref.func $4)
+ )
+ (func $13 (result exnref)
+  (local $0 exnref)
+  (local.get $0)
+ )
+ (func $14 (result exnref)
+  (global.get $global$3)
+ )
+ (func $15 (result exnref)
+  (ref.null exn)
+ )
+ (func $16 (result anyref)
+  (local $0 anyref)
+  (local.get $0)
+ )
+ (func $17 (result anyref)
+  (global.get $global$4)
+ )
+ (func $18 (result anyref)
+  (ref.null any)
+ )
+ (func $19 (result anyref)
+  (local $0 externref)
+  (local.get $0)
+ )
+ (func $20 (result anyref)
+  (global.get $global$0)
+ )
+ (func $21 (result anyref)
+  (ref.null extern)
+ )
+ (func $22 (result anyref)
+  (local $0 funcref)
+  (local.get $0)
+ )
+ (func $23 (result anyref)
+  (global.get $global$1)
+ )
+ (func $24 (result anyref)
+  (ref.null func)
+ )
+ (func $25 (result anyref)
+  (ref.func $4)
+ )
+ (func $26 (result anyref)
+  (local $0 exnref)
+  (local.get $0)
+ )
+ (func $27 (result anyref)
+  (global.get $global$3)
+ )
+ (func $28 (result anyref)
+  (ref.null exn)
+ )
+ (func $29 (result externref)
+  (local $0 externref)
+  (return
+   (local.get $0)
+  )
+ )
+ (func $30 (result funcref)
+  (local $0 funcref)
+  (return
+   (local.get $0)
+  )
+ )
+ (func $31 (result exnref)
+  (local $0 exnref)
+  (return
+   (local.get $0)
+  )
+ )
+ (func $32 (result anyref)
+  (local $0 anyref)
+  (return
+   (local.get $0)
+  )
+ )
+ (func $33 (result anyref)
+  (local $0 funcref)
+  (local $1 externref)
+  (local $2 exnref)
+  (return
+   (local.get $1)
+  )
+ )
+)
+
diff --git a/binaryen/test/reg_switch.wast b/binaryen/test/reg_switch.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reg_switch.wast
@@ -0,0 +1,14 @@
+(module
+  (type $0 (func))
+  (memory $0 0)
+  (func $0 (type $0)
+    (if
+      (i32.const 0)
+      (block $A
+        (br_table $A
+          (i32.const 0)
+        )
+      )
+    )
+  )
+)
diff --git a/binaryen/test/reg_switch.wast.from-wast b/binaryen/test/reg_switch.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reg_switch.wast.from-wast
@@ -0,0 +1,14 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $0
+  (if
+   (i32.const 0)
+   (block $A
+    (br_table $A
+     (i32.const 0)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/reg_switch.wast.fromBinary b/binaryen/test/reg_switch.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reg_switch.wast.fromBinary
@@ -0,0 +1,15 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $0
+  (if
+   (i32.const 0)
+   (block $label$2
+    (br_table $label$2
+     (i32.const 0)
+    )
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/reg_switch.wast.fromBinary.noDebugInfo b/binaryen/test/reg_switch.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/reg_switch.wast.fromBinary.noDebugInfo
@@ -0,0 +1,15 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 0)
+ (func $0
+  (if
+   (i32.const 0)
+   (block $label$2
+    (br_table $label$2
+     (i32.const 0)
+    )
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/revision b/binaryen/test/revision
new file mode 100644
--- /dev/null
+++ b/binaryen/test/revision
@@ -0,0 +1,1 @@
+13645
diff --git a/binaryen/test/segment-overlap.wast b/binaryen/test/segment-overlap.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/segment-overlap.wast
@@ -0,0 +1,6 @@
+(module
+ (memory $0 10)
+ (data (i32.const 100) "\ff\ff\ff\ff\ff\ff\ff\ff") ;; overlaps with the next
+ (data (i32.const 104) "\00\00\00\00")
+)
+
diff --git a/binaryen/test/segment-overlap.wast.from-wast b/binaryen/test/segment-overlap.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/segment-overlap.wast.from-wast
@@ -0,0 +1,5 @@
+(module
+ (memory $0 10)
+ (data (i32.const 100) "\ff\ff\ff\ff\ff\ff\ff\ff")
+ (data (i32.const 104) "\00\00\00\00")
+)
diff --git a/binaryen/test/segment-overlap.wast.fromBinary b/binaryen/test/segment-overlap.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/segment-overlap.wast.fromBinary
@@ -0,0 +1,6 @@
+(module
+ (memory $0 10)
+ (data (i32.const 100) "\ff\ff\ff\ff\ff\ff\ff\ff")
+ (data (i32.const 104) "\00\00\00\00")
+)
+
diff --git a/binaryen/test/segment-overlap.wast.fromBinary.noDebugInfo b/binaryen/test/segment-overlap.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/segment-overlap.wast.fromBinary.noDebugInfo
@@ -0,0 +1,6 @@
+(module
+ (memory $0 10)
+ (data (i32.const 100) "\ff\ff\ff\ff\ff\ff\ff\ff")
+ (data (i32.const 104) "\00\00\00\00")
+)
+
diff --git a/binaryen/test/signext.wast b/binaryen/test/signext.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/signext.wast
@@ -0,0 +1,12 @@
+(module
+ (type $0 (func))
+ (func $signext  (type $0)
+  (local $0 i32)
+  (local $1 i64)
+  (drop (i32.extend8_s (local.get $0)))
+  (drop (i32.extend16_s (local.get $0)))
+  (drop (i64.extend8_s (local.get $1)))
+  (drop (i64.extend16_s (local.get $1)))
+  (drop (i64.extend32_s (local.get $1)))
+ )
+)
diff --git a/binaryen/test/signext.wast.from-wast b/binaryen/test/signext.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/signext.wast.from-wast
@@ -0,0 +1,32 @@
+(module
+ (type $none_=>_none (func))
+ (func $signext
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.extend8_s
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.extend16_s
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.extend8_s
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.extend16_s
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.extend32_s
+    (local.get $1)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/signext.wast.fromBinary b/binaryen/test/signext.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/signext.wast.fromBinary
@@ -0,0 +1,33 @@
+(module
+ (type $none_=>_none (func))
+ (func $signext
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.extend8_s
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.extend16_s
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.extend8_s
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.extend16_s
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.extend32_s
+    (local.get $1)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/signext.wast.fromBinary.noDebugInfo b/binaryen/test/signext.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/signext.wast.fromBinary.noDebugInfo
@@ -0,0 +1,33 @@
+(module
+ (type $none_=>_none (func))
+ (func $0
+  (local $0 i32)
+  (local $1 i64)
+  (drop
+   (i32.extend8_s
+    (local.get $0)
+   )
+  )
+  (drop
+   (i32.extend16_s
+    (local.get $0)
+   )
+  )
+  (drop
+   (i64.extend8_s
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.extend16_s
+    (local.get $1)
+   )
+  )
+  (drop
+   (i64.extend32_s
+    (local.get $1)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/simd.wast b/binaryen/test/simd.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/simd.wast
@@ -0,0 +1,1163 @@
+(module
+ (memory 1 1)
+ (func $v128.load (param $0 i32) (result v128)
+  (v128.load offset=0 align=16
+    (local.get $0)
+  )
+ )
+ (func $v128.store (param $0 i32) (param $1 v128)
+  (v128.store offset=0 align=16
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.const.i8x16 (result v128)
+  (v128.const i8x16 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16)
+ )
+ (func $v128.const.i16x8 (result v128)
+  (v128.const i16x8 1 2 3 4 5 6 7 8)
+ )
+ (func $v128.const.i32x4 (result v128)
+  (v128.const i32x4 1 2 3 4)
+ )
+ (func $v128.const.i64x2 (result v128)
+  (v128.const i64x2 1 2)
+ )
+ (func $v128.const.f32x4 (result v128)
+  (v128.const f32x4 1.0 2 3 4)
+ )
+ (func $v128.const.f64x2 (result v128)
+  (v128.const f64x2 1.0 2)
+ )
+ (func $v128.shuffle (param $0 v128) (param $1 v128) (result v128)
+  (v8x16.shuffle 0 17 2 19 4 21 6 23 8 25 10 27 12 29 14 31
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.splat (param $0 i32) (result v128)
+  (i8x16.splat
+   (local.get $0)
+  )
+ )
+ (func $i8x16.extract_lane_s (param $0 v128) (result i32)
+  (i8x16.extract_lane_s 0
+   (local.get $0)
+  )
+ )
+ (func $i8x16.extract_lane_u (param $0 v128) (result i32)
+  (i8x16.extract_lane_u 0
+   (local.get $0)
+  )
+ )
+ (func $i8x16.replace_lane (param $0 v128) (param $1 i32) (result v128)
+  (i8x16.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.splat (param $0 i32) (result v128)
+  (i16x8.splat
+   (local.get $0)
+  )
+ )
+ (func $i16x8.extract_lane_s (param $0 v128) (result i32)
+  (i16x8.extract_lane_s 0
+   (local.get $0)
+  )
+ )
+ (func $i16x8.extract_lane_u (param $0 v128) (result i32)
+  (i16x8.extract_lane_u 0
+   (local.get $0)
+  )
+ )
+ (func $i16x8.replace_lane (param $0 v128) (param $1 i32) (result v128)
+  (i16x8.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.splat (param $0 i32) (result v128)
+  (i32x4.splat
+   (local.get $0)
+  )
+ )
+ (func $i32x4.extract_lane (param $0 v128) (result i32)
+  (i32x4.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $i32x4.replace_lane (param $0 v128) (param $1 i32) (result v128)
+  (i32x4.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.extract_lane (param $0 v128) (result i64)
+  (i64x2.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $i64x2.replace_lane (param $0 v128) (param $1 i64) (result v128)
+  (i64x2.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.splat (param $0 f32) (result v128)
+  (f32x4.splat
+   (local.get $0)
+  )
+ )
+ (func $f32x4.extract_lane (param $0 v128) (result f32)
+  (f32x4.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $f32x4.replace_lane (param $0 v128) (param $1 f32) (result v128)
+  (f32x4.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.splat (param $0 f64) (result v128)
+  (f64x2.splat
+   (local.get $0)
+  )
+ )
+ (func $f64x2.extract_lane (param $0 v128) (result f64)
+  (f64x2.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $f64x2.replace_lane (param $0 v128) (param $1 f64) (result v128)
+  (f64x2.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.eq (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.ne (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.lt_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.lt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.lt_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.lt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.gt_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.gt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.gt_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.gt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.le_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.le_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.le_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.le_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.ge_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.ge_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.ge_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.ge_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.eq (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.ne (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.lt_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.lt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.lt_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.lt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.gt_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.gt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.gt_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.gt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.le_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.le_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.le_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.le_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.ge_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.ge_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.ge_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.ge_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.eq (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.ne (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.lt_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.lt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.lt_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.lt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.gt_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.gt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.gt_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.gt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.le_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.le_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.le_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.le_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.ge_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.ge_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.ge_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.ge_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.eq (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.ne (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.lt (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.lt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.gt (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.gt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.le (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.le
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.ge (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.ge
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.eq (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.ne (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.lt (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.lt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.gt (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.gt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.le (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.le
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.ge (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.ge
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.not (param $0 v128) (result v128)
+  (v128.not
+   (local.get $0)
+  )
+ )
+ (func $v128.and (param $0 v128) (param $1 v128) (result v128)
+  (v128.and
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.or (param $0 v128) (param $1 v128) (result v128)
+  (v128.or
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.xor (param $0 v128) (param $1 v128) (result v128)
+  (v128.xor
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.andnot (param $0 v128) (param $1 v128) (result v128)
+  (v128.andnot
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $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 $i8x16.abs (param $0 v128) (result v128)
+  (i8x16.abs
+   (local.get $0)
+  )
+ )
+ (func $i8x16.neg (param $0 v128) (result v128)
+  (i8x16.neg
+   (local.get $0)
+  )
+ )
+ (func $i8x16.any_true (param $0 v128) (result i32)
+  (i8x16.any_true
+   (local.get $0)
+  )
+ )
+ (func $i8x16.all_true (param $0 v128) (result i32)
+  (i8x16.all_true
+   (local.get $0)
+  )
+ )
+ (func $i8x16.bitmask (param $0 v128) (result i32)
+  (i8x16.bitmask
+   (local.get $0)
+  )
+ )
+ (func $i8x16.shl (param $0 v128) (param $1 i32) (result v128)
+  (i8x16.shl
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.shr_s (param $0 v128) (param $1 i32) (result v128)
+  (i8x16.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.shr_u (param $0 v128) (param $1 i32) (result v128)
+  (i8x16.shr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.add (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.add_saturate_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.add_saturate_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.add_saturate_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.add_saturate_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.sub (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.sub_saturate_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.sub_saturate_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.sub_saturate_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.sub_saturate_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.mul (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.min_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.min_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.min_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.min_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.max_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.max_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.max_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.max_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.avgr_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.avgr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.abs (param $0 v128) (result v128)
+  (i16x8.abs
+   (local.get $0)
+  )
+ )
+ (func $i16x8.neg (param $0 v128) (result v128)
+  (i16x8.neg
+   (local.get $0)
+  )
+ )
+ (func $i16x8.any_true (param $0 v128) (result i32)
+  (i16x8.any_true
+   (local.get $0)
+  )
+ )
+ (func $i16x8.all_true (param $0 v128) (result i32)
+  (i16x8.all_true
+   (local.get $0)
+  )
+ )
+ (func $i16x8.bitmask (param $0 v128) (result i32)
+  (i16x8.bitmask
+   (local.get $0)
+  )
+ )
+ (func $i16x8.shl (param $0 v128) (param $1 i32) (result v128)
+  (i16x8.shl
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.shr_s (param $0 v128) (param $1 i32) (result v128)
+  (i16x8.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.shr_u (param $0 v128) (param $1 i32) (result v128)
+  (i16x8.shr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.add (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.add_saturate_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.add_saturate_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.add_saturate_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.add_saturate_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.sub (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.sub_saturate_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.sub_saturate_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.sub_saturate_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.sub_saturate_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.mul (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.min_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.min_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.min_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.min_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.max_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.max_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.max_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.max_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.avgr_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.avgr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.abs (param $0 v128) (result v128)
+  (i32x4.abs
+   (local.get $0)
+  )
+ )
+ (func $i32x4.neg (param $0 v128) (result v128)
+  (i32x4.neg
+   (local.get $0)
+  )
+ )
+ (func $i32x4.any_true (param $0 v128) (result i32)
+  (i32x4.any_true
+   (local.get $0)
+  )
+ )
+ (func $i32x4.all_true (param $0 v128) (result i32)
+  (i32x4.all_true
+   (local.get $0)
+  )
+ )
+ (func $i32x4.bitmask (param $0 v128) (result i32)
+  (i32x4.bitmask
+   (local.get $0)
+  )
+ )
+ (func $i32x4.shl (param $0 v128) (param $1 i32) (result v128)
+  (i32x4.shl
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.shr_s (param $0 v128) (param $1 i32) (result v128)
+  (i32x4.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.shr_u (param $0 v128) (param $1 i32) (result v128)
+  (i32x4.shr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.add (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.sub (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.mul (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.min_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.min_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.min_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.min_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.max_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.max_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.max_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.max_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.dot_i16x8_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.dot_i16x8_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.neg (param $0 v128) (result v128)
+  (i64x2.neg
+   (local.get $0)
+  )
+ )
+ (func $i64x2.any_true (param $0 v128) (result i32)
+  (i64x2.any_true
+   (local.get $0)
+  )
+ )
+ (func $i64x2.all_true (param $0 v128) (result i32)
+  (i64x2.all_true
+   (local.get $0)
+  )
+ )
+ (func $i64x2.shl (param $0 v128) (param $1 i32) (result v128)
+  (i64x2.shl
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.shr_s (param $0 v128) (param $1 i32) (result v128)
+  (i64x2.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.shr_u (param $0 v128) (param $1 i32) (result v128)
+  (i64x2.shr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.add (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.sub (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.mul (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.add (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.sub (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.mul (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.div (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.div
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.min (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.min
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.max (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.max
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.pmin (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.pmin
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.pmax (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.pmax
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.ceil (param $0 v128) (result v128)
+  (f32x4.ceil
+   (local.get $0)
+  )
+ )
+ (func $f32x4.floor (param $0 v128) (result v128)
+  (f32x4.floor
+   (local.get $0)
+  )
+ )
+ (func $f32x4.trunc (param $0 v128) (result v128)
+  (f32x4.trunc
+   (local.get $0)
+  )
+ )
+ (func $f32x4.nearest (param $0 v128) (result v128)
+  (f32x4.nearest
+   (local.get $0)
+  )
+ )
+ (func $f32x4.abs (param $0 v128) (result v128)
+  (f32x4.abs
+   (local.get $0)
+  )
+ )
+ (func $f32x4.neg (param $0 v128) (result v128)
+  (f32x4.neg
+   (local.get $0)
+  )
+ )
+ (func $f32x4.sqrt (param $0 v128) (result v128)
+  (f32x4.sqrt
+   (local.get $0)
+  )
+ )
+ (func $f32x4.qfma (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (f32x4.qfma
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $f32x4.qfms (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (f32x4.qfms
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $f64x2.add (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.sub (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.mul (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.div (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.div
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.min (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.min
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.max (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.max
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.pmin (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.pmin
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.pmax (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.pmax
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.ceil (param $0 v128) (result v128)
+  (f64x2.ceil
+   (local.get $0)
+  )
+ )
+ (func $f64x2.floor (param $0 v128) (result v128)
+  (f64x2.floor
+   (local.get $0)
+  )
+ )
+ (func $f64x2.trunc (param $0 v128) (result v128)
+  (f64x2.trunc
+   (local.get $0)
+  )
+ )
+ (func $f64x2.nearest (param $0 v128) (result v128)
+  (f64x2.nearest
+   (local.get $0)
+  )
+ )
+ (func $f64x2.abs (param $0 v128) (result v128)
+  (f64x2.abs
+   (local.get $0)
+  )
+ )
+ (func $f64x2.neg (param $0 v128) (result v128)
+  (f64x2.neg
+   (local.get $0)
+  )
+ )
+ (func $f64x2.sqrt (param $0 v128) (result v128)
+  (f64x2.sqrt
+   (local.get $0)
+  )
+ )
+ (func $f64x2.qfma (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (f64x2.qfma
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $f64x2.qfms (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (f64x2.qfms
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $i32x4.trunc_sat_f32x4_s (param $0 v128) (result v128)
+  (i32x4.trunc_sat_f32x4_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.trunc_sat_f32x4_u (param $0 v128) (result v128)
+  (i32x4.trunc_sat_f32x4_u
+   (local.get $0)
+  )
+ )
+ (func $i64x2.trunc_sat_f64x2_s (param $0 v128) (result v128)
+  (i64x2.trunc_sat_f64x2_s
+   (local.get $0)
+  )
+ )
+ (func $i64x2.trunc_sat_f64x2_u (param $0 v128) (result v128)
+  (i64x2.trunc_sat_f64x2_u
+   (local.get $0)
+  )
+ )
+ (func $f32x4.convert_i32x4_s (param $0 v128) (result v128)
+  (f32x4.convert_i32x4_s
+   (local.get $0)
+  )
+ )
+ (func $f32x4.convert_i32x4_u (param $0 v128) (result v128)
+  (f32x4.convert_i32x4_u
+   (local.get $0)
+  )
+ )
+ (func $f64x2.convert_i64x2_s (param $0 v128) (result v128)
+  (f64x2.convert_i64x2_s
+   (local.get $0)
+  )
+ )
+ (func $f64x2.convert_i64x2_u (param $0 v128) (result v128)
+  (f64x2.convert_i64x2_u
+   (local.get $0)
+  )
+ )
+ (func $v8x16.load_splat (param $0 i32) (result v128)
+  (v8x16.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v16x8.load_splat (param $0 i32) (result v128)
+  (v16x8.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v32x4.load_splat (param $0 i32) (result v128)
+  (v32x4.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v64x2.load_splat (param $0 i32) (result v128)
+  (v64x2.load_splat
+   (local.get $0)
+  )
+ )
+ (func $i8x16.narrow_i16x8_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.narrow_i16x8_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.narrow_i16x8_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.narrow_i16x8_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.narrow_i32x4_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.narrow_i32x4_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.narrow_i32x4_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.narrow_i32x4_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.widen_low_i8x16_s (param $0 v128) (result v128)
+  (i16x8.widen_low_i8x16_s
+   (local.get $0)
+  )
+ )
+ (func $i16x8.widen_high_i8x16_s (param $0 v128) (result v128)
+  (i16x8.widen_high_i8x16_s
+   (local.get $0)
+  )
+ )
+ (func $i16x8.widen_low_i8x16_u (param $0 v128) (result v128)
+  (i16x8.widen_low_i8x16_u
+   (local.get $0)
+  )
+ )
+ (func $i16x8.widen_high_i8x16_u (param $0 v128) (result v128)
+  (i16x8.widen_high_i8x16_u
+   (local.get $0)
+  )
+ )
+ (func $i32x4.widen_low_i16x8_s (param $0 v128) (result v128)
+  (i32x4.widen_low_i16x8_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.widen_high_i16x8_s (param $0 v128) (result v128)
+  (i32x4.widen_high_i16x8_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.widen_low_i16x8_u (param $0 v128) (result v128)
+  (i32x4.widen_low_i16x8_u
+   (local.get $0)
+  )
+ )
+ (func $i32x4.widen_high_i16x8_u (param $0 v128) (result v128)
+  (i32x4.widen_high_i16x8_u
+   (local.get $0)
+  )
+ )
+ (func $i16x8.load8x8_u (param $0 i32) (result v128)
+  (i16x8.load8x8_u
+   (local.get $0)
+  )
+ )
+ (func $i16x8.load8x8_s (param $0 i32) (result v128)
+  (i16x8.load8x8_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.load16x4_s (param $0 i32) (result v128)
+  (i32x4.load16x4_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.load16x4_u (param $0 i32) (result v128)
+  (i32x4.load16x4_u
+   (local.get $0)
+  )
+ )
+ (func $i64x2.load32x2_s (param $0 i32) (result v128)
+  (i64x2.load32x2_s
+   (local.get $0)
+  )
+ )
+ (func $i64x2.load32x2_u (param $0 i32) (result v128)
+  (i64x2.load32x2_u
+   (local.get $0)
+  )
+ )
+ (func $v128.load32_zero (param $0 i32) (result v128)
+  (v128.load32_zero
+   (local.get $0)
+  )
+ )
+ (func $v128.load64_zero (param $0 i32) (result v128)
+  (v128.load64_zero
+   (local.get $0)
+  )
+ )
+ (func $v8x16.swizzle (param $0 v128) (param $1 v128) (result v128)
+  (v8x16.swizzle
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
diff --git a/binaryen/test/simd.wast.from-wast b/binaryen/test/simd.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/simd.wast.from-wast
@@ -0,0 +1,1179 @@
+(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_=>_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 $v128_=>_i64 (func (param v128) (result i64)))
+ (type $v128_=>_f32 (func (param v128) (result f32)))
+ (type $v128_=>_f64 (func (param v128) (result f64)))
+ (type $f32_=>_v128 (func (param f32) (result v128)))
+ (type $f64_=>_v128 (func (param f64) (result v128)))
+ (type $v128_i64_=>_v128 (func (param v128 i64) (result v128)))
+ (type $v128_f32_=>_v128 (func (param v128 f32) (result v128)))
+ (type $v128_f64_=>_v128 (func (param v128 f64) (result v128)))
+ (memory $0 1 1)
+ (func $v128.load (param $0 i32) (result v128)
+  (v128.load
+   (local.get $0)
+  )
+ )
+ (func $v128.store (param $0 i32) (param $1 v128)
+  (v128.store
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.const.i8x16 (result v128)
+  (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+ )
+ (func $v128.const.i16x8 (result v128)
+  (v128.const i32x4 0x00020001 0x00040003 0x00060005 0x00080007)
+ )
+ (func $v128.const.i32x4 (result v128)
+  (v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004)
+ )
+ (func $v128.const.i64x2 (result v128)
+  (v128.const i32x4 0x00000001 0x00000000 0x00000002 0x00000000)
+ )
+ (func $v128.const.f32x4 (result v128)
+  (v128.const i32x4 0x3f800000 0x40000000 0x40400000 0x40800000)
+ )
+ (func $v128.const.f64x2 (result v128)
+  (v128.const i32x4 0x00000000 0x3ff00000 0x00000000 0x40000000)
+ )
+ (func $v128.shuffle (param $0 v128) (param $1 v128) (result v128)
+  (v8x16.shuffle 0 17 2 19 4 21 6 23 8 25 10 27 12 29 14 31
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.splat (param $0 i32) (result v128)
+  (i8x16.splat
+   (local.get $0)
+  )
+ )
+ (func $i8x16.extract_lane_s (param $0 v128) (result i32)
+  (i8x16.extract_lane_s 0
+   (local.get $0)
+  )
+ )
+ (func $i8x16.extract_lane_u (param $0 v128) (result i32)
+  (i8x16.extract_lane_u 0
+   (local.get $0)
+  )
+ )
+ (func $i8x16.replace_lane (param $0 v128) (param $1 i32) (result v128)
+  (i8x16.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.splat (param $0 i32) (result v128)
+  (i16x8.splat
+   (local.get $0)
+  )
+ )
+ (func $i16x8.extract_lane_s (param $0 v128) (result i32)
+  (i16x8.extract_lane_s 0
+   (local.get $0)
+  )
+ )
+ (func $i16x8.extract_lane_u (param $0 v128) (result i32)
+  (i16x8.extract_lane_u 0
+   (local.get $0)
+  )
+ )
+ (func $i16x8.replace_lane (param $0 v128) (param $1 i32) (result v128)
+  (i16x8.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.splat (param $0 i32) (result v128)
+  (i32x4.splat
+   (local.get $0)
+  )
+ )
+ (func $i32x4.extract_lane (param $0 v128) (result i32)
+  (i32x4.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $i32x4.replace_lane (param $0 v128) (param $1 i32) (result v128)
+  (i32x4.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.extract_lane (param $0 v128) (result i64)
+  (i64x2.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $i64x2.replace_lane (param $0 v128) (param $1 i64) (result v128)
+  (i64x2.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.splat (param $0 f32) (result v128)
+  (f32x4.splat
+   (local.get $0)
+  )
+ )
+ (func $f32x4.extract_lane (param $0 v128) (result f32)
+  (f32x4.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $f32x4.replace_lane (param $0 v128) (param $1 f32) (result v128)
+  (f32x4.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.splat (param $0 f64) (result v128)
+  (f64x2.splat
+   (local.get $0)
+  )
+ )
+ (func $f64x2.extract_lane (param $0 v128) (result f64)
+  (f64x2.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $f64x2.replace_lane (param $0 v128) (param $1 f64) (result v128)
+  (f64x2.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.eq (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.ne (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.lt_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.lt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.lt_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.lt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.gt_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.gt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.gt_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.gt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.le_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.le_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.le_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.le_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.ge_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.ge_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.ge_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.ge_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.eq (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.ne (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.lt_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.lt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.lt_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.lt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.gt_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.gt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.gt_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.gt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.le_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.le_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.le_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.le_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.ge_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.ge_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.ge_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.ge_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.eq (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.ne (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.lt_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.lt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.lt_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.lt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.gt_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.gt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.gt_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.gt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.le_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.le_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.le_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.le_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.ge_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.ge_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.ge_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.ge_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.eq (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.ne (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.lt (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.lt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.gt (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.gt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.le (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.le
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.ge (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.ge
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.eq (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.ne (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.lt (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.lt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.gt (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.gt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.le (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.le
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.ge (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.ge
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.not (param $0 v128) (result v128)
+  (v128.not
+   (local.get $0)
+  )
+ )
+ (func $v128.and (param $0 v128) (param $1 v128) (result v128)
+  (v128.and
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.or (param $0 v128) (param $1 v128) (result v128)
+  (v128.or
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.xor (param $0 v128) (param $1 v128) (result v128)
+  (v128.xor
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.andnot (param $0 v128) (param $1 v128) (result v128)
+  (v128.andnot
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $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 $i8x16.abs (param $0 v128) (result v128)
+  (i8x16.abs
+   (local.get $0)
+  )
+ )
+ (func $i8x16.neg (param $0 v128) (result v128)
+  (i8x16.neg
+   (local.get $0)
+  )
+ )
+ (func $i8x16.any_true (param $0 v128) (result i32)
+  (i8x16.any_true
+   (local.get $0)
+  )
+ )
+ (func $i8x16.all_true (param $0 v128) (result i32)
+  (i8x16.all_true
+   (local.get $0)
+  )
+ )
+ (func $i8x16.bitmask (param $0 v128) (result i32)
+  (i8x16.bitmask
+   (local.get $0)
+  )
+ )
+ (func $i8x16.shl (param $0 v128) (param $1 i32) (result v128)
+  (i8x16.shl
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.shr_s (param $0 v128) (param $1 i32) (result v128)
+  (i8x16.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.shr_u (param $0 v128) (param $1 i32) (result v128)
+  (i8x16.shr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.add (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.add_saturate_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.add_saturate_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.add_saturate_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.add_saturate_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.sub (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.sub_saturate_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.sub_saturate_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.sub_saturate_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.sub_saturate_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.mul (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.min_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.min_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.min_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.min_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.max_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.max_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.max_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.max_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.avgr_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.avgr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.abs (param $0 v128) (result v128)
+  (i16x8.abs
+   (local.get $0)
+  )
+ )
+ (func $i16x8.neg (param $0 v128) (result v128)
+  (i16x8.neg
+   (local.get $0)
+  )
+ )
+ (func $i16x8.any_true (param $0 v128) (result i32)
+  (i16x8.any_true
+   (local.get $0)
+  )
+ )
+ (func $i16x8.all_true (param $0 v128) (result i32)
+  (i16x8.all_true
+   (local.get $0)
+  )
+ )
+ (func $i16x8.bitmask (param $0 v128) (result i32)
+  (i16x8.bitmask
+   (local.get $0)
+  )
+ )
+ (func $i16x8.shl (param $0 v128) (param $1 i32) (result v128)
+  (i16x8.shl
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.shr_s (param $0 v128) (param $1 i32) (result v128)
+  (i16x8.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.shr_u (param $0 v128) (param $1 i32) (result v128)
+  (i16x8.shr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.add (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.add_saturate_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.add_saturate_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.add_saturate_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.add_saturate_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.sub (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.sub_saturate_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.sub_saturate_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.sub_saturate_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.sub_saturate_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.mul (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.min_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.min_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.min_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.min_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.max_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.max_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.max_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.max_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.avgr_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.avgr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.abs (param $0 v128) (result v128)
+  (i32x4.abs
+   (local.get $0)
+  )
+ )
+ (func $i32x4.neg (param $0 v128) (result v128)
+  (i32x4.neg
+   (local.get $0)
+  )
+ )
+ (func $i32x4.any_true (param $0 v128) (result i32)
+  (i32x4.any_true
+   (local.get $0)
+  )
+ )
+ (func $i32x4.all_true (param $0 v128) (result i32)
+  (i32x4.all_true
+   (local.get $0)
+  )
+ )
+ (func $i32x4.bitmask (param $0 v128) (result i32)
+  (i32x4.bitmask
+   (local.get $0)
+  )
+ )
+ (func $i32x4.shl (param $0 v128) (param $1 i32) (result v128)
+  (i32x4.shl
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.shr_s (param $0 v128) (param $1 i32) (result v128)
+  (i32x4.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.shr_u (param $0 v128) (param $1 i32) (result v128)
+  (i32x4.shr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.add (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.sub (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.mul (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.min_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.min_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.min_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.min_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.max_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.max_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.max_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.max_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.dot_i16x8_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.dot_i16x8_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.neg (param $0 v128) (result v128)
+  (i64x2.neg
+   (local.get $0)
+  )
+ )
+ (func $i64x2.any_true (param $0 v128) (result i32)
+  (i64x2.any_true
+   (local.get $0)
+  )
+ )
+ (func $i64x2.all_true (param $0 v128) (result i32)
+  (i64x2.all_true
+   (local.get $0)
+  )
+ )
+ (func $i64x2.shl (param $0 v128) (param $1 i32) (result v128)
+  (i64x2.shl
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.shr_s (param $0 v128) (param $1 i32) (result v128)
+  (i64x2.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.shr_u (param $0 v128) (param $1 i32) (result v128)
+  (i64x2.shr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.add (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.sub (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.mul (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.add (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.sub (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.mul (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.div (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.div
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.min (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.min
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.max (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.max
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.pmin (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.pmin
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.pmax (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.pmax
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.ceil (param $0 v128) (result v128)
+  (f32x4.ceil
+   (local.get $0)
+  )
+ )
+ (func $f32x4.floor (param $0 v128) (result v128)
+  (f32x4.floor
+   (local.get $0)
+  )
+ )
+ (func $f32x4.trunc (param $0 v128) (result v128)
+  (f32x4.trunc
+   (local.get $0)
+  )
+ )
+ (func $f32x4.nearest (param $0 v128) (result v128)
+  (f32x4.nearest
+   (local.get $0)
+  )
+ )
+ (func $f32x4.abs (param $0 v128) (result v128)
+  (f32x4.abs
+   (local.get $0)
+  )
+ )
+ (func $f32x4.neg (param $0 v128) (result v128)
+  (f32x4.neg
+   (local.get $0)
+  )
+ )
+ (func $f32x4.sqrt (param $0 v128) (result v128)
+  (f32x4.sqrt
+   (local.get $0)
+  )
+ )
+ (func $f32x4.qfma (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (f32x4.qfma
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $f32x4.qfms (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (f32x4.qfms
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $f64x2.add (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.sub (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.mul (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.div (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.div
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.min (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.min
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.max (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.max
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.pmin (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.pmin
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.pmax (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.pmax
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.ceil (param $0 v128) (result v128)
+  (f64x2.ceil
+   (local.get $0)
+  )
+ )
+ (func $f64x2.floor (param $0 v128) (result v128)
+  (f64x2.floor
+   (local.get $0)
+  )
+ )
+ (func $f64x2.trunc (param $0 v128) (result v128)
+  (f64x2.trunc
+   (local.get $0)
+  )
+ )
+ (func $f64x2.nearest (param $0 v128) (result v128)
+  (f64x2.nearest
+   (local.get $0)
+  )
+ )
+ (func $f64x2.abs (param $0 v128) (result v128)
+  (f64x2.abs
+   (local.get $0)
+  )
+ )
+ (func $f64x2.neg (param $0 v128) (result v128)
+  (f64x2.neg
+   (local.get $0)
+  )
+ )
+ (func $f64x2.sqrt (param $0 v128) (result v128)
+  (f64x2.sqrt
+   (local.get $0)
+  )
+ )
+ (func $f64x2.qfma (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (f64x2.qfma
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $f64x2.qfms (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (f64x2.qfms
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $i32x4.trunc_sat_f32x4_s (param $0 v128) (result v128)
+  (i32x4.trunc_sat_f32x4_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.trunc_sat_f32x4_u (param $0 v128) (result v128)
+  (i32x4.trunc_sat_f32x4_u
+   (local.get $0)
+  )
+ )
+ (func $i64x2.trunc_sat_f64x2_s (param $0 v128) (result v128)
+  (i64x2.trunc_sat_f64x2_s
+   (local.get $0)
+  )
+ )
+ (func $i64x2.trunc_sat_f64x2_u (param $0 v128) (result v128)
+  (i64x2.trunc_sat_f64x2_u
+   (local.get $0)
+  )
+ )
+ (func $f32x4.convert_i32x4_s (param $0 v128) (result v128)
+  (f32x4.convert_i32x4_s
+   (local.get $0)
+  )
+ )
+ (func $f32x4.convert_i32x4_u (param $0 v128) (result v128)
+  (f32x4.convert_i32x4_u
+   (local.get $0)
+  )
+ )
+ (func $f64x2.convert_i64x2_s (param $0 v128) (result v128)
+  (f64x2.convert_i64x2_s
+   (local.get $0)
+  )
+ )
+ (func $f64x2.convert_i64x2_u (param $0 v128) (result v128)
+  (f64x2.convert_i64x2_u
+   (local.get $0)
+  )
+ )
+ (func $v8x16.load_splat (param $0 i32) (result v128)
+  (v8x16.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v16x8.load_splat (param $0 i32) (result v128)
+  (v16x8.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v32x4.load_splat (param $0 i32) (result v128)
+  (v32x4.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v64x2.load_splat (param $0 i32) (result v128)
+  (v64x2.load_splat
+   (local.get $0)
+  )
+ )
+ (func $i8x16.narrow_i16x8_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.narrow_i16x8_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.narrow_i16x8_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.narrow_i16x8_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.narrow_i32x4_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.narrow_i32x4_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.narrow_i32x4_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.narrow_i32x4_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.widen_low_i8x16_s (param $0 v128) (result v128)
+  (i16x8.widen_low_i8x16_s
+   (local.get $0)
+  )
+ )
+ (func $i16x8.widen_high_i8x16_s (param $0 v128) (result v128)
+  (i16x8.widen_high_i8x16_s
+   (local.get $0)
+  )
+ )
+ (func $i16x8.widen_low_i8x16_u (param $0 v128) (result v128)
+  (i16x8.widen_low_i8x16_u
+   (local.get $0)
+  )
+ )
+ (func $i16x8.widen_high_i8x16_u (param $0 v128) (result v128)
+  (i16x8.widen_high_i8x16_u
+   (local.get $0)
+  )
+ )
+ (func $i32x4.widen_low_i16x8_s (param $0 v128) (result v128)
+  (i32x4.widen_low_i16x8_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.widen_high_i16x8_s (param $0 v128) (result v128)
+  (i32x4.widen_high_i16x8_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.widen_low_i16x8_u (param $0 v128) (result v128)
+  (i32x4.widen_low_i16x8_u
+   (local.get $0)
+  )
+ )
+ (func $i32x4.widen_high_i16x8_u (param $0 v128) (result v128)
+  (i32x4.widen_high_i16x8_u
+   (local.get $0)
+  )
+ )
+ (func $i16x8.load8x8_u (param $0 i32) (result v128)
+  (i16x8.load8x8_u
+   (local.get $0)
+  )
+ )
+ (func $i16x8.load8x8_s (param $0 i32) (result v128)
+  (i16x8.load8x8_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.load16x4_s (param $0 i32) (result v128)
+  (i32x4.load16x4_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.load16x4_u (param $0 i32) (result v128)
+  (i32x4.load16x4_u
+   (local.get $0)
+  )
+ )
+ (func $i64x2.load32x2_s (param $0 i32) (result v128)
+  (i64x2.load32x2_s
+   (local.get $0)
+  )
+ )
+ (func $i64x2.load32x2_u (param $0 i32) (result v128)
+  (i64x2.load32x2_u
+   (local.get $0)
+  )
+ )
+ (func $v128.load32_zero (param $0 i32) (result v128)
+  (v128.load32_zero
+   (local.get $0)
+  )
+ )
+ (func $v128.load64_zero (param $0 i32) (result v128)
+  (v128.load64_zero
+   (local.get $0)
+  )
+ )
+ (func $v8x16.swizzle (param $0 v128) (param $1 v128) (result v128)
+  (v8x16.swizzle
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
diff --git a/binaryen/test/simd.wast.fromBinary b/binaryen/test/simd.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/simd.wast.fromBinary
@@ -0,0 +1,1180 @@
+(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_=>_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 $v128_=>_i64 (func (param v128) (result i64)))
+ (type $v128_=>_f32 (func (param v128) (result f32)))
+ (type $v128_=>_f64 (func (param v128) (result f64)))
+ (type $f32_=>_v128 (func (param f32) (result v128)))
+ (type $f64_=>_v128 (func (param f64) (result v128)))
+ (type $v128_i64_=>_v128 (func (param v128 i64) (result v128)))
+ (type $v128_f32_=>_v128 (func (param v128 f32) (result v128)))
+ (type $v128_f64_=>_v128 (func (param v128 f64) (result v128)))
+ (memory $0 1 1)
+ (func $v128.load (param $0 i32) (result v128)
+  (v128.load
+   (local.get $0)
+  )
+ )
+ (func $v128.store (param $0 i32) (param $1 v128)
+  (v128.store
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.const.i8x16 (result v128)
+  (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+ )
+ (func $v128.const.i16x8 (result v128)
+  (v128.const i32x4 0x00020001 0x00040003 0x00060005 0x00080007)
+ )
+ (func $v128.const.i32x4 (result v128)
+  (v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004)
+ )
+ (func $v128.const.i64x2 (result v128)
+  (v128.const i32x4 0x00000001 0x00000000 0x00000002 0x00000000)
+ )
+ (func $v128.const.f32x4 (result v128)
+  (v128.const i32x4 0x3f800000 0x40000000 0x40400000 0x40800000)
+ )
+ (func $v128.const.f64x2 (result v128)
+  (v128.const i32x4 0x00000000 0x3ff00000 0x00000000 0x40000000)
+ )
+ (func $v128.shuffle (param $0 v128) (param $1 v128) (result v128)
+  (v8x16.shuffle 0 17 2 19 4 21 6 23 8 25 10 27 12 29 14 31
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.splat (param $0 i32) (result v128)
+  (i8x16.splat
+   (local.get $0)
+  )
+ )
+ (func $i8x16.extract_lane_s (param $0 v128) (result i32)
+  (i8x16.extract_lane_s 0
+   (local.get $0)
+  )
+ )
+ (func $i8x16.extract_lane_u (param $0 v128) (result i32)
+  (i8x16.extract_lane_u 0
+   (local.get $0)
+  )
+ )
+ (func $i8x16.replace_lane (param $0 v128) (param $1 i32) (result v128)
+  (i8x16.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.splat (param $0 i32) (result v128)
+  (i16x8.splat
+   (local.get $0)
+  )
+ )
+ (func $i16x8.extract_lane_s (param $0 v128) (result i32)
+  (i16x8.extract_lane_s 0
+   (local.get $0)
+  )
+ )
+ (func $i16x8.extract_lane_u (param $0 v128) (result i32)
+  (i16x8.extract_lane_u 0
+   (local.get $0)
+  )
+ )
+ (func $i16x8.replace_lane (param $0 v128) (param $1 i32) (result v128)
+  (i16x8.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.splat (param $0 i32) (result v128)
+  (i32x4.splat
+   (local.get $0)
+  )
+ )
+ (func $i32x4.extract_lane (param $0 v128) (result i32)
+  (i32x4.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $i32x4.replace_lane (param $0 v128) (param $1 i32) (result v128)
+  (i32x4.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.extract_lane (param $0 v128) (result i64)
+  (i64x2.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $i64x2.replace_lane (param $0 v128) (param $1 i64) (result v128)
+  (i64x2.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.splat (param $0 f32) (result v128)
+  (f32x4.splat
+   (local.get $0)
+  )
+ )
+ (func $f32x4.extract_lane (param $0 v128) (result f32)
+  (f32x4.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $f32x4.replace_lane (param $0 v128) (param $1 f32) (result v128)
+  (f32x4.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.splat (param $0 f64) (result v128)
+  (f64x2.splat
+   (local.get $0)
+  )
+ )
+ (func $f64x2.extract_lane (param $0 v128) (result f64)
+  (f64x2.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $f64x2.replace_lane (param $0 v128) (param $1 f64) (result v128)
+  (f64x2.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.eq (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.ne (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.lt_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.lt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.lt_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.lt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.gt_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.gt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.gt_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.gt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.le_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.le_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.le_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.le_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.ge_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.ge_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.ge_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.ge_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.eq (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.ne (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.lt_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.lt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.lt_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.lt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.gt_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.gt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.gt_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.gt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.le_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.le_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.le_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.le_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.ge_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.ge_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.ge_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.ge_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.eq (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.ne (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.lt_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.lt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.lt_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.lt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.gt_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.gt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.gt_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.gt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.le_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.le_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.le_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.le_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.ge_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.ge_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.ge_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.ge_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.eq (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.ne (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.lt (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.lt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.gt (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.gt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.le (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.le
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.ge (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.ge
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.eq (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.ne (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.lt (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.lt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.gt (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.gt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.le (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.le
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.ge (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.ge
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.not (param $0 v128) (result v128)
+  (v128.not
+   (local.get $0)
+  )
+ )
+ (func $v128.and (param $0 v128) (param $1 v128) (result v128)
+  (v128.and
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.or (param $0 v128) (param $1 v128) (result v128)
+  (v128.or
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.xor (param $0 v128) (param $1 v128) (result v128)
+  (v128.xor
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.andnot (param $0 v128) (param $1 v128) (result v128)
+  (v128.andnot
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $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 $i8x16.abs (param $0 v128) (result v128)
+  (i8x16.abs
+   (local.get $0)
+  )
+ )
+ (func $i8x16.neg (param $0 v128) (result v128)
+  (i8x16.neg
+   (local.get $0)
+  )
+ )
+ (func $i8x16.any_true (param $0 v128) (result i32)
+  (i8x16.any_true
+   (local.get $0)
+  )
+ )
+ (func $i8x16.all_true (param $0 v128) (result i32)
+  (i8x16.all_true
+   (local.get $0)
+  )
+ )
+ (func $i8x16.bitmask (param $0 v128) (result i32)
+  (i8x16.bitmask
+   (local.get $0)
+  )
+ )
+ (func $i8x16.shl (param $0 v128) (param $1 i32) (result v128)
+  (i8x16.shl
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.shr_s (param $0 v128) (param $1 i32) (result v128)
+  (i8x16.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.shr_u (param $0 v128) (param $1 i32) (result v128)
+  (i8x16.shr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.add (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.add_saturate_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.add_saturate_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.add_saturate_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.add_saturate_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.sub (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.sub_saturate_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.sub_saturate_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.sub_saturate_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.sub_saturate_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.mul (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.min_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.min_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.min_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.min_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.max_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.max_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.max_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.max_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.avgr_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.avgr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.abs (param $0 v128) (result v128)
+  (i16x8.abs
+   (local.get $0)
+  )
+ )
+ (func $i16x8.neg (param $0 v128) (result v128)
+  (i16x8.neg
+   (local.get $0)
+  )
+ )
+ (func $i16x8.any_true (param $0 v128) (result i32)
+  (i16x8.any_true
+   (local.get $0)
+  )
+ )
+ (func $i16x8.all_true (param $0 v128) (result i32)
+  (i16x8.all_true
+   (local.get $0)
+  )
+ )
+ (func $i16x8.bitmask (param $0 v128) (result i32)
+  (i16x8.bitmask
+   (local.get $0)
+  )
+ )
+ (func $i16x8.shl (param $0 v128) (param $1 i32) (result v128)
+  (i16x8.shl
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.shr_s (param $0 v128) (param $1 i32) (result v128)
+  (i16x8.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.shr_u (param $0 v128) (param $1 i32) (result v128)
+  (i16x8.shr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.add (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.add_saturate_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.add_saturate_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.add_saturate_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.add_saturate_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.sub (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.sub_saturate_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.sub_saturate_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.sub_saturate_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.sub_saturate_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.mul (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.min_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.min_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.min_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.min_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.max_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.max_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.max_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.max_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.avgr_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.avgr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.abs (param $0 v128) (result v128)
+  (i32x4.abs
+   (local.get $0)
+  )
+ )
+ (func $i32x4.neg (param $0 v128) (result v128)
+  (i32x4.neg
+   (local.get $0)
+  )
+ )
+ (func $i32x4.any_true (param $0 v128) (result i32)
+  (i32x4.any_true
+   (local.get $0)
+  )
+ )
+ (func $i32x4.all_true (param $0 v128) (result i32)
+  (i32x4.all_true
+   (local.get $0)
+  )
+ )
+ (func $i32x4.bitmask (param $0 v128) (result i32)
+  (i32x4.bitmask
+   (local.get $0)
+  )
+ )
+ (func $i32x4.shl (param $0 v128) (param $1 i32) (result v128)
+  (i32x4.shl
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.shr_s (param $0 v128) (param $1 i32) (result v128)
+  (i32x4.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.shr_u (param $0 v128) (param $1 i32) (result v128)
+  (i32x4.shr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.add (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.sub (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.mul (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.min_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.min_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.min_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.min_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.max_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.max_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.max_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.max_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i32x4.dot_i16x8_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.dot_i16x8_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.neg (param $0 v128) (result v128)
+  (i64x2.neg
+   (local.get $0)
+  )
+ )
+ (func $i64x2.any_true (param $0 v128) (result i32)
+  (i64x2.any_true
+   (local.get $0)
+  )
+ )
+ (func $i64x2.all_true (param $0 v128) (result i32)
+  (i64x2.all_true
+   (local.get $0)
+  )
+ )
+ (func $i64x2.shl (param $0 v128) (param $1 i32) (result v128)
+  (i64x2.shl
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.shr_s (param $0 v128) (param $1 i32) (result v128)
+  (i64x2.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.shr_u (param $0 v128) (param $1 i32) (result v128)
+  (i64x2.shr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.add (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.sub (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.mul (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.add (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.sub (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.mul (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.div (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.div
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.min (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.min
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.max (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.max
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.pmin (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.pmin
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.pmax (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.pmax
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f32x4.ceil (param $0 v128) (result v128)
+  (f32x4.ceil
+   (local.get $0)
+  )
+ )
+ (func $f32x4.floor (param $0 v128) (result v128)
+  (f32x4.floor
+   (local.get $0)
+  )
+ )
+ (func $f32x4.trunc (param $0 v128) (result v128)
+  (f32x4.trunc
+   (local.get $0)
+  )
+ )
+ (func $f32x4.nearest (param $0 v128) (result v128)
+  (f32x4.nearest
+   (local.get $0)
+  )
+ )
+ (func $f32x4.abs (param $0 v128) (result v128)
+  (f32x4.abs
+   (local.get $0)
+  )
+ )
+ (func $f32x4.neg (param $0 v128) (result v128)
+  (f32x4.neg
+   (local.get $0)
+  )
+ )
+ (func $f32x4.sqrt (param $0 v128) (result v128)
+  (f32x4.sqrt
+   (local.get $0)
+  )
+ )
+ (func $f32x4.qfma (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (f32x4.qfma
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $f32x4.qfms (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (f32x4.qfms
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $f64x2.add (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.sub (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.mul (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.div (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.div
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.min (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.min
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.max (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.max
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.pmin (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.pmin
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.pmax (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.pmax
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $f64x2.ceil (param $0 v128) (result v128)
+  (f64x2.ceil
+   (local.get $0)
+  )
+ )
+ (func $f64x2.floor (param $0 v128) (result v128)
+  (f64x2.floor
+   (local.get $0)
+  )
+ )
+ (func $f64x2.trunc (param $0 v128) (result v128)
+  (f64x2.trunc
+   (local.get $0)
+  )
+ )
+ (func $f64x2.nearest (param $0 v128) (result v128)
+  (f64x2.nearest
+   (local.get $0)
+  )
+ )
+ (func $f64x2.abs (param $0 v128) (result v128)
+  (f64x2.abs
+   (local.get $0)
+  )
+ )
+ (func $f64x2.neg (param $0 v128) (result v128)
+  (f64x2.neg
+   (local.get $0)
+  )
+ )
+ (func $f64x2.sqrt (param $0 v128) (result v128)
+  (f64x2.sqrt
+   (local.get $0)
+  )
+ )
+ (func $f64x2.qfma (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (f64x2.qfma
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $f64x2.qfms (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (f64x2.qfms
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $i32x4.trunc_sat_f32x4_s (param $0 v128) (result v128)
+  (i32x4.trunc_sat_f32x4_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.trunc_sat_f32x4_u (param $0 v128) (result v128)
+  (i32x4.trunc_sat_f32x4_u
+   (local.get $0)
+  )
+ )
+ (func $i64x2.trunc_sat_f64x2_s (param $0 v128) (result v128)
+  (i64x2.trunc_sat_f64x2_s
+   (local.get $0)
+  )
+ )
+ (func $i64x2.trunc_sat_f64x2_u (param $0 v128) (result v128)
+  (i64x2.trunc_sat_f64x2_u
+   (local.get $0)
+  )
+ )
+ (func $f32x4.convert_i32x4_s (param $0 v128) (result v128)
+  (f32x4.convert_i32x4_s
+   (local.get $0)
+  )
+ )
+ (func $f32x4.convert_i32x4_u (param $0 v128) (result v128)
+  (f32x4.convert_i32x4_u
+   (local.get $0)
+  )
+ )
+ (func $f64x2.convert_i64x2_s (param $0 v128) (result v128)
+  (f64x2.convert_i64x2_s
+   (local.get $0)
+  )
+ )
+ (func $f64x2.convert_i64x2_u (param $0 v128) (result v128)
+  (f64x2.convert_i64x2_u
+   (local.get $0)
+  )
+ )
+ (func $v8x16.load_splat (param $0 i32) (result v128)
+  (v8x16.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v16x8.load_splat (param $0 i32) (result v128)
+  (v16x8.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v32x4.load_splat (param $0 i32) (result v128)
+  (v32x4.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v64x2.load_splat (param $0 i32) (result v128)
+  (v64x2.load_splat
+   (local.get $0)
+  )
+ )
+ (func $i8x16.narrow_i16x8_s (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.narrow_i16x8_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.narrow_i16x8_u (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.narrow_i16x8_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.narrow_i32x4_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.narrow_i32x4_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.narrow_i32x4_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.narrow_i32x4_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.widen_low_i8x16_s (param $0 v128) (result v128)
+  (i16x8.widen_low_i8x16_s
+   (local.get $0)
+  )
+ )
+ (func $i16x8.widen_high_i8x16_s (param $0 v128) (result v128)
+  (i16x8.widen_high_i8x16_s
+   (local.get $0)
+  )
+ )
+ (func $i16x8.widen_low_i8x16_u (param $0 v128) (result v128)
+  (i16x8.widen_low_i8x16_u
+   (local.get $0)
+  )
+ )
+ (func $i16x8.widen_high_i8x16_u (param $0 v128) (result v128)
+  (i16x8.widen_high_i8x16_u
+   (local.get $0)
+  )
+ )
+ (func $i32x4.widen_low_i16x8_s (param $0 v128) (result v128)
+  (i32x4.widen_low_i16x8_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.widen_high_i16x8_s (param $0 v128) (result v128)
+  (i32x4.widen_high_i16x8_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.widen_low_i16x8_u (param $0 v128) (result v128)
+  (i32x4.widen_low_i16x8_u
+   (local.get $0)
+  )
+ )
+ (func $i32x4.widen_high_i16x8_u (param $0 v128) (result v128)
+  (i32x4.widen_high_i16x8_u
+   (local.get $0)
+  )
+ )
+ (func $i16x8.load8x8_u (param $0 i32) (result v128)
+  (i16x8.load8x8_u
+   (local.get $0)
+  )
+ )
+ (func $i16x8.load8x8_s (param $0 i32) (result v128)
+  (i16x8.load8x8_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.load16x4_s (param $0 i32) (result v128)
+  (i32x4.load16x4_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.load16x4_u (param $0 i32) (result v128)
+  (i32x4.load16x4_u
+   (local.get $0)
+  )
+ )
+ (func $i64x2.load32x2_s (param $0 i32) (result v128)
+  (i64x2.load32x2_s
+   (local.get $0)
+  )
+ )
+ (func $i64x2.load32x2_u (param $0 i32) (result v128)
+  (i64x2.load32x2_u
+   (local.get $0)
+  )
+ )
+ (func $v128.load32_zero (param $0 i32) (result v128)
+  (v128.load32_zero
+   (local.get $0)
+  )
+ )
+ (func $v128.load64_zero (param $0 i32) (result v128)
+  (v128.load64_zero
+   (local.get $0)
+  )
+ )
+ (func $v8x16.swizzle (param $0 v128) (param $1 v128) (result v128)
+  (v8x16.swizzle
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
+
diff --git a/binaryen/test/simd.wast.fromBinary.noDebugInfo b/binaryen/test/simd.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/simd.wast.fromBinary.noDebugInfo
@@ -0,0 +1,1180 @@
+(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_=>_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 $v128_=>_i64 (func (param v128) (result i64)))
+ (type $v128_=>_f32 (func (param v128) (result f32)))
+ (type $v128_=>_f64 (func (param v128) (result f64)))
+ (type $f32_=>_v128 (func (param f32) (result v128)))
+ (type $f64_=>_v128 (func (param f64) (result v128)))
+ (type $v128_i64_=>_v128 (func (param v128 i64) (result v128)))
+ (type $v128_f32_=>_v128 (func (param v128 f32) (result v128)))
+ (type $v128_f64_=>_v128 (func (param v128 f64) (result v128)))
+ (memory $0 1 1)
+ (func $0 (param $0 i32) (result v128)
+  (v128.load
+   (local.get $0)
+  )
+ )
+ (func $1 (param $0 i32) (param $1 v128)
+  (v128.store
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $2 (result v128)
+  (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+ )
+ (func $3 (result v128)
+  (v128.const i32x4 0x00020001 0x00040003 0x00060005 0x00080007)
+ )
+ (func $4 (result v128)
+  (v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004)
+ )
+ (func $5 (result v128)
+  (v128.const i32x4 0x00000001 0x00000000 0x00000002 0x00000000)
+ )
+ (func $6 (result v128)
+  (v128.const i32x4 0x3f800000 0x40000000 0x40400000 0x40800000)
+ )
+ (func $7 (result v128)
+  (v128.const i32x4 0x00000000 0x3ff00000 0x00000000 0x40000000)
+ )
+ (func $8 (param $0 v128) (param $1 v128) (result v128)
+  (v8x16.shuffle 0 17 2 19 4 21 6 23 8 25 10 27 12 29 14 31
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $9 (param $0 i32) (result v128)
+  (i8x16.splat
+   (local.get $0)
+  )
+ )
+ (func $10 (param $0 v128) (result i32)
+  (i8x16.extract_lane_s 0
+   (local.get $0)
+  )
+ )
+ (func $11 (param $0 v128) (result i32)
+  (i8x16.extract_lane_u 0
+   (local.get $0)
+  )
+ )
+ (func $12 (param $0 v128) (param $1 i32) (result v128)
+  (i8x16.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $13 (param $0 i32) (result v128)
+  (i16x8.splat
+   (local.get $0)
+  )
+ )
+ (func $14 (param $0 v128) (result i32)
+  (i16x8.extract_lane_s 0
+   (local.get $0)
+  )
+ )
+ (func $15 (param $0 v128) (result i32)
+  (i16x8.extract_lane_u 0
+   (local.get $0)
+  )
+ )
+ (func $16 (param $0 v128) (param $1 i32) (result v128)
+  (i16x8.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $17 (param $0 i32) (result v128)
+  (i32x4.splat
+   (local.get $0)
+  )
+ )
+ (func $18 (param $0 v128) (result i32)
+  (i32x4.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $19 (param $0 v128) (param $1 i32) (result v128)
+  (i32x4.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $20 (param $0 v128) (result i64)
+  (i64x2.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $21 (param $0 v128) (param $1 i64) (result v128)
+  (i64x2.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $22 (param $0 f32) (result v128)
+  (f32x4.splat
+   (local.get $0)
+  )
+ )
+ (func $23 (param $0 v128) (result f32)
+  (f32x4.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $24 (param $0 v128) (param $1 f32) (result v128)
+  (f32x4.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $25 (param $0 f64) (result v128)
+  (f64x2.splat
+   (local.get $0)
+  )
+ )
+ (func $26 (param $0 v128) (result f64)
+  (f64x2.extract_lane 0
+   (local.get $0)
+  )
+ )
+ (func $27 (param $0 v128) (param $1 f64) (result v128)
+  (f64x2.replace_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $28 (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $29 (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $30 (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.lt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $31 (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.lt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $32 (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.gt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $33 (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.gt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $34 (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.le_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $35 (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.le_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $36 (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.ge_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $37 (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.ge_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $38 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $39 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $40 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.lt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $41 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.lt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $42 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.gt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $43 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.gt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $44 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.le_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $45 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.le_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $46 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.ge_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $47 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.ge_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $48 (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $49 (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $50 (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.lt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $51 (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.lt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $52 (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.gt_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $53 (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.gt_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $54 (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.le_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $55 (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.le_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $56 (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.ge_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $57 (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.ge_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $58 (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $59 (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $60 (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.lt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $61 (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.gt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $62 (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.le
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $63 (param $0 v128) (param $1 v128) (result v128)
+  (f32x4.ge
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $64 (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $65 (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.ne
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $66 (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.lt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $67 (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.gt
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $68 (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.le
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $69 (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.ge
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $70 (param $0 v128) (result v128)
+  (v128.not
+   (local.get $0)
+  )
+ )
+ (func $71 (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)
+  (v128.or
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $73 (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)
+  (v128.andnot
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $75 (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)
+  (i8x16.abs
+   (local.get $0)
+  )
+ )
+ (func $77 (param $0 v128) (result v128)
+  (i8x16.neg
+   (local.get $0)
+  )
+ )
+ (func $78 (param $0 v128) (result i32)
+  (i8x16.any_true
+   (local.get $0)
+  )
+ )
+ (func $79 (param $0 v128) (result i32)
+  (i8x16.all_true
+   (local.get $0)
+  )
+ )
+ (func $80 (param $0 v128) (result i32)
+  (i8x16.bitmask
+   (local.get $0)
+  )
+ )
+ (func $81 (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)
+  (i8x16.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $83 (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)
+  (i8x16.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $85 (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)
+  (i8x16.add_saturate_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $87 (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)
+  (i8x16.sub_saturate_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $89 (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)
+  (i8x16.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $91 (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)
+  (i8x16.min_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $93 (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)
+  (i8x16.max_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $95 (param $0 v128) (param $1 v128) (result v128)
+  (i8x16.avgr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $96 (param $0 v128) (result v128)
+  (i16x8.abs
+   (local.get $0)
+  )
+ )
+ (func $97 (param $0 v128) (result v128)
+  (i16x8.neg
+   (local.get $0)
+  )
+ )
+ (func $98 (param $0 v128) (result i32)
+  (i16x8.any_true
+   (local.get $0)
+  )
+ )
+ (func $99 (param $0 v128) (result i32)
+  (i16x8.all_true
+   (local.get $0)
+  )
+ )
+ (func $100 (param $0 v128) (result i32)
+  (i16x8.bitmask
+   (local.get $0)
+  )
+ )
+ (func $101 (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)
+  (i16x8.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $103 (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)
+  (i16x8.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $105 (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)
+  (i16x8.add_saturate_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $107 (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)
+  (i16x8.sub_saturate_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $109 (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)
+  (i16x8.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $111 (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)
+  (i16x8.min_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $113 (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)
+  (i16x8.max_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $115 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.avgr_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $116 (param $0 v128) (result v128)
+  (i32x4.abs
+   (local.get $0)
+  )
+ )
+ (func $117 (param $0 v128) (result v128)
+  (i32x4.neg
+   (local.get $0)
+  )
+ )
+ (func $118 (param $0 v128) (result i32)
+  (i32x4.any_true
+   (local.get $0)
+  )
+ )
+ (func $119 (param $0 v128) (result i32)
+  (i32x4.all_true
+   (local.get $0)
+  )
+ )
+ (func $120 (param $0 v128) (result i32)
+  (i32x4.bitmask
+   (local.get $0)
+  )
+ )
+ (func $121 (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)
+  (i32x4.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $123 (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)
+  (i32x4.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $125 (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)
+  (i32x4.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $127 (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)
+  (i32x4.min_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $129 (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)
+  (i32x4.max_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $131 (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
+   (local.get $0)
+  )
+ )
+ (func $133 (param $0 v128) (result i32)
+  (i64x2.any_true
+   (local.get $0)
+  )
+ )
+ (func $134 (param $0 v128) (result i32)
+  (i64x2.all_true
+   (local.get $0)
+  )
+ )
+ (func $135 (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)
+  (i64x2.shr_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $137 (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)
+  (i64x2.add
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $139 (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)
+  (i64x2.mul
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $141 (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)
+  (f32x4.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $143 (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)
+  (f32x4.div
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $145 (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)
+  (f32x4.max
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $147 (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)
+  (f32x4.pmax
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $149 (param $0 v128) (result v128)
+  (f32x4.ceil
+   (local.get $0)
+  )
+ )
+ (func $150 (param $0 v128) (result v128)
+  (f32x4.floor
+   (local.get $0)
+  )
+ )
+ (func $151 (param $0 v128) (result v128)
+  (f32x4.trunc
+   (local.get $0)
+  )
+ )
+ (func $152 (param $0 v128) (result v128)
+  (f32x4.nearest
+   (local.get $0)
+  )
+ )
+ (func $153 (param $0 v128) (result v128)
+  (f32x4.abs
+   (local.get $0)
+  )
+ )
+ (func $154 (param $0 v128) (result v128)
+  (f32x4.neg
+   (local.get $0)
+  )
+ )
+ (func $155 (param $0 v128) (result v128)
+  (f32x4.sqrt
+   (local.get $0)
+  )
+ )
+ (func $156 (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)
+  (f32x4.qfms
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $158 (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)
+  (f64x2.sub
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $160 (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)
+  (f64x2.div
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $162 (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)
+  (f64x2.max
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $164 (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)
+  (f64x2.pmax
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $166 (param $0 v128) (result v128)
+  (f64x2.ceil
+   (local.get $0)
+  )
+ )
+ (func $167 (param $0 v128) (result v128)
+  (f64x2.floor
+   (local.get $0)
+  )
+ )
+ (func $168 (param $0 v128) (result v128)
+  (f64x2.trunc
+   (local.get $0)
+  )
+ )
+ (func $169 (param $0 v128) (result v128)
+  (f64x2.nearest
+   (local.get $0)
+  )
+ )
+ (func $170 (param $0 v128) (result v128)
+  (f64x2.abs
+   (local.get $0)
+  )
+ )
+ (func $171 (param $0 v128) (result v128)
+  (f64x2.neg
+   (local.get $0)
+  )
+ )
+ (func $172 (param $0 v128) (result v128)
+  (f64x2.sqrt
+   (local.get $0)
+  )
+ )
+ (func $173 (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)
+  (f64x2.qfms
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $175 (param $0 v128) (result v128)
+  (i32x4.trunc_sat_f32x4_s
+   (local.get $0)
+  )
+ )
+ (func $176 (param $0 v128) (result v128)
+  (i32x4.trunc_sat_f32x4_u
+   (local.get $0)
+  )
+ )
+ (func $177 (param $0 v128) (result v128)
+  (i64x2.trunc_sat_f64x2_s
+   (local.get $0)
+  )
+ )
+ (func $178 (param $0 v128) (result v128)
+  (i64x2.trunc_sat_f64x2_u
+   (local.get $0)
+  )
+ )
+ (func $179 (param $0 v128) (result v128)
+  (f32x4.convert_i32x4_s
+   (local.get $0)
+  )
+ )
+ (func $180 (param $0 v128) (result v128)
+  (f32x4.convert_i32x4_u
+   (local.get $0)
+  )
+ )
+ (func $181 (param $0 v128) (result v128)
+  (f64x2.convert_i64x2_s
+   (local.get $0)
+  )
+ )
+ (func $182 (param $0 v128) (result v128)
+  (f64x2.convert_i64x2_u
+   (local.get $0)
+  )
+ )
+ (func $183 (param $0 i32) (result v128)
+  (v8x16.load_splat
+   (local.get $0)
+  )
+ )
+ (func $184 (param $0 i32) (result v128)
+  (v16x8.load_splat
+   (local.get $0)
+  )
+ )
+ (func $185 (param $0 i32) (result v128)
+  (v32x4.load_splat
+   (local.get $0)
+  )
+ )
+ (func $186 (param $0 i32) (result v128)
+  (v64x2.load_splat
+   (local.get $0)
+  )
+ )
+ (func $187 (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)
+  (i8x16.narrow_i16x8_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $189 (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)
+  (i16x8.narrow_i32x4_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $191 (param $0 v128) (result v128)
+  (i16x8.widen_low_i8x16_s
+   (local.get $0)
+  )
+ )
+ (func $192 (param $0 v128) (result v128)
+  (i16x8.widen_high_i8x16_s
+   (local.get $0)
+  )
+ )
+ (func $193 (param $0 v128) (result v128)
+  (i16x8.widen_low_i8x16_u
+   (local.get $0)
+  )
+ )
+ (func $194 (param $0 v128) (result v128)
+  (i16x8.widen_high_i8x16_u
+   (local.get $0)
+  )
+ )
+ (func $195 (param $0 v128) (result v128)
+  (i32x4.widen_low_i16x8_s
+   (local.get $0)
+  )
+ )
+ (func $196 (param $0 v128) (result v128)
+  (i32x4.widen_high_i16x8_s
+   (local.get $0)
+  )
+ )
+ (func $197 (param $0 v128) (result v128)
+  (i32x4.widen_low_i16x8_u
+   (local.get $0)
+  )
+ )
+ (func $198 (param $0 v128) (result v128)
+  (i32x4.widen_high_i16x8_u
+   (local.get $0)
+  )
+ )
+ (func $199 (param $0 i32) (result v128)
+  (i16x8.load8x8_u
+   (local.get $0)
+  )
+ )
+ (func $200 (param $0 i32) (result v128)
+  (i16x8.load8x8_s
+   (local.get $0)
+  )
+ )
+ (func $201 (param $0 i32) (result v128)
+  (i32x4.load16x4_s
+   (local.get $0)
+  )
+ )
+ (func $202 (param $0 i32) (result v128)
+  (i32x4.load16x4_u
+   (local.get $0)
+  )
+ )
+ (func $203 (param $0 i32) (result v128)
+  (i64x2.load32x2_s
+   (local.get $0)
+  )
+ )
+ (func $204 (param $0 i32) (result v128)
+  (i64x2.load32x2_u
+   (local.get $0)
+  )
+ )
+ (func $205 (param $0 i32) (result v128)
+  (v128.load32_zero
+   (local.get $0)
+  )
+ )
+ (func $206 (param $0 i32) (result v128)
+  (v128.load64_zero
+   (local.get $0)
+  )
+ )
+ (func $207 (param $0 v128) (param $1 v128) (result v128)
+  (v8x16.swizzle
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+)
+
diff --git a/binaryen/test/simd64.wast b/binaryen/test/simd64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/simd64.wast
@@ -0,0 +1,74 @@
+(module
+ (memory i64 1 1)
+ (func $v128.load (param $0 i64) (result v128)
+  (v128.load offset=0 align=16
+    (local.get $0)
+  )
+ )
+ (func $v128.store (param $0 i64) (param $1 v128)
+  (v128.store offset=0 align=16
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v8x16.load_splat (param $0 i64) (result v128)
+  (v8x16.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v16x8.load_splat (param $0 i64) (result v128)
+  (v16x8.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v32x4.load_splat (param $0 i64) (result v128)
+  (v32x4.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v64x2.load_splat (param $0 i64) (result v128)
+  (v64x2.load_splat
+   (local.get $0)
+  )
+ )
+ (func $i16x8.load8x8_u (param $0 i64) (result v128)
+  (i16x8.load8x8_u
+   (local.get $0)
+  )
+ )
+ (func $i16x8.load8x8_s (param $0 i64) (result v128)
+  (i16x8.load8x8_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.load16x4_s (param $0 i64) (result v128)
+  (i32x4.load16x4_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.load16x4_u (param $0 i64) (result v128)
+  (i32x4.load16x4_u
+   (local.get $0)
+  )
+ )
+ (func $i64x2.load32x2_s (param $0 i64) (result v128)
+  (i64x2.load32x2_s
+   (local.get $0)
+  )
+ )
+ (func $i64x2.load32x2_u (param $0 i64) (result v128)
+  (i64x2.load32x2_u
+   (local.get $0)
+  )
+ )
+ (func $v128.load32_zero (param $0 i64) (result v128)
+  (v128.load32_zero
+   (local.get $0)
+  )
+ )
+ (func $v128.load64_zero (param $0 i64) (result v128)
+  (v128.load64_zero
+   (local.get $0)
+  )
+ )
+)
diff --git a/binaryen/test/simd64.wast.from-wast b/binaryen/test/simd64.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/simd64.wast.from-wast
@@ -0,0 +1,76 @@
+(module
+ (type $i64_=>_v128 (func (param i64) (result v128)))
+ (type $i64_v128_=>_none (func (param i64 v128)))
+ (memory $0 i64 1 1)
+ (func $v128.load (param $0 i64) (result v128)
+  (v128.load
+   (local.get $0)
+  )
+ )
+ (func $v128.store (param $0 i64) (param $1 v128)
+  (v128.store
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v8x16.load_splat (param $0 i64) (result v128)
+  (v8x16.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v16x8.load_splat (param $0 i64) (result v128)
+  (v16x8.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v32x4.load_splat (param $0 i64) (result v128)
+  (v32x4.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v64x2.load_splat (param $0 i64) (result v128)
+  (v64x2.load_splat
+   (local.get $0)
+  )
+ )
+ (func $i16x8.load8x8_u (param $0 i64) (result v128)
+  (i16x8.load8x8_u
+   (local.get $0)
+  )
+ )
+ (func $i16x8.load8x8_s (param $0 i64) (result v128)
+  (i16x8.load8x8_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.load16x4_s (param $0 i64) (result v128)
+  (i32x4.load16x4_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.load16x4_u (param $0 i64) (result v128)
+  (i32x4.load16x4_u
+   (local.get $0)
+  )
+ )
+ (func $i64x2.load32x2_s (param $0 i64) (result v128)
+  (i64x2.load32x2_s
+   (local.get $0)
+  )
+ )
+ (func $i64x2.load32x2_u (param $0 i64) (result v128)
+  (i64x2.load32x2_u
+   (local.get $0)
+  )
+ )
+ (func $v128.load32_zero (param $0 i64) (result v128)
+  (v128.load32_zero
+   (local.get $0)
+  )
+ )
+ (func $v128.load64_zero (param $0 i64) (result v128)
+  (v128.load64_zero
+   (local.get $0)
+  )
+ )
+)
diff --git a/binaryen/test/simd64.wast.fromBinary b/binaryen/test/simd64.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/simd64.wast.fromBinary
@@ -0,0 +1,77 @@
+(module
+ (type $i64_=>_v128 (func (param i64) (result v128)))
+ (type $i64_v128_=>_none (func (param i64 v128)))
+ (memory $0 i64 1 1)
+ (func $v128.load (param $0 i64) (result v128)
+  (v128.load
+   (local.get $0)
+  )
+ )
+ (func $v128.store (param $0 i64) (param $1 v128)
+  (v128.store
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v8x16.load_splat (param $0 i64) (result v128)
+  (v8x16.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v16x8.load_splat (param $0 i64) (result v128)
+  (v16x8.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v32x4.load_splat (param $0 i64) (result v128)
+  (v32x4.load_splat
+   (local.get $0)
+  )
+ )
+ (func $v64x2.load_splat (param $0 i64) (result v128)
+  (v64x2.load_splat
+   (local.get $0)
+  )
+ )
+ (func $i16x8.load8x8_u (param $0 i64) (result v128)
+  (i16x8.load8x8_u
+   (local.get $0)
+  )
+ )
+ (func $i16x8.load8x8_s (param $0 i64) (result v128)
+  (i16x8.load8x8_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.load16x4_s (param $0 i64) (result v128)
+  (i32x4.load16x4_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.load16x4_u (param $0 i64) (result v128)
+  (i32x4.load16x4_u
+   (local.get $0)
+  )
+ )
+ (func $i64x2.load32x2_s (param $0 i64) (result v128)
+  (i64x2.load32x2_s
+   (local.get $0)
+  )
+ )
+ (func $i64x2.load32x2_u (param $0 i64) (result v128)
+  (i64x2.load32x2_u
+   (local.get $0)
+  )
+ )
+ (func $v128.load32_zero (param $0 i64) (result v128)
+  (v128.load32_zero
+   (local.get $0)
+  )
+ )
+ (func $v128.load64_zero (param $0 i64) (result v128)
+  (v128.load64_zero
+   (local.get $0)
+  )
+ )
+)
+
diff --git a/binaryen/test/simd64.wast.fromBinary.noDebugInfo b/binaryen/test/simd64.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/simd64.wast.fromBinary.noDebugInfo
@@ -0,0 +1,77 @@
+(module
+ (type $i64_=>_v128 (func (param i64) (result v128)))
+ (type $i64_v128_=>_none (func (param i64 v128)))
+ (memory $0 i64 1 1)
+ (func $0 (param $0 i64) (result v128)
+  (v128.load
+   (local.get $0)
+  )
+ )
+ (func $1 (param $0 i64) (param $1 v128)
+  (v128.store
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $2 (param $0 i64) (result v128)
+  (v8x16.load_splat
+   (local.get $0)
+  )
+ )
+ (func $3 (param $0 i64) (result v128)
+  (v16x8.load_splat
+   (local.get $0)
+  )
+ )
+ (func $4 (param $0 i64) (result v128)
+  (v32x4.load_splat
+   (local.get $0)
+  )
+ )
+ (func $5 (param $0 i64) (result v128)
+  (v64x2.load_splat
+   (local.get $0)
+  )
+ )
+ (func $6 (param $0 i64) (result v128)
+  (i16x8.load8x8_u
+   (local.get $0)
+  )
+ )
+ (func $7 (param $0 i64) (result v128)
+  (i16x8.load8x8_s
+   (local.get $0)
+  )
+ )
+ (func $8 (param $0 i64) (result v128)
+  (i32x4.load16x4_s
+   (local.get $0)
+  )
+ )
+ (func $9 (param $0 i64) (result v128)
+  (i32x4.load16x4_u
+   (local.get $0)
+  )
+ )
+ (func $10 (param $0 i64) (result v128)
+  (i64x2.load32x2_s
+   (local.get $0)
+  )
+ )
+ (func $11 (param $0 i64) (result v128)
+  (i64x2.load32x2_u
+   (local.get $0)
+  )
+ )
+ (func $12 (param $0 i64) (result v128)
+  (v128.load32_zero
+   (local.get $0)
+  )
+ )
+ (func $13 (param $0 i64) (result v128)
+  (v128.load64_zero
+   (local.get $0)
+  )
+ )
+)
+
diff --git a/binaryen/test/spec/Contributing.md b/binaryen/test/spec/Contributing.md
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/Contributing.md
@@ -0,0 +1,8 @@
+# Contributing to WebAssembly
+
+Interested in participating? Please follow
+[the same contributing guidelines as the design repository][].
+
+  [the same contributing guidelines as the design repository]: https://github.com/WebAssembly/design/blob/master/Contributing.md
+
+Also, please be sure to read [the README.md](README.md) for this repository.
diff --git a/binaryen/test/spec/LICENSE b/binaryen/test/spec/LICENSE
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/LICENSE
@@ -0,0 +1,202 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   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.
+
diff --git a/binaryen/test/spec/README.md b/binaryen/test/spec/README.md
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/README.md
@@ -0,0 +1,11 @@
+This directory contains tests for the core WebAssembly semantics, as described in [Semantics.md](https://github.com/WebAssembly/design/blob/master/Semantics.md) and specified by the [spec interpreter](https://github.com/WebAssembly/spec/blob/master/interpreter).
+
+Tests are written in the [S-Expression script format](https://github.com/WebAssembly/spec/blob/master/interpreter/README.md#s-expression-syntax) defined by the interpreter.
+
+The test suite can be run with the spec interpreter as follows:
+```
+./run.py --wasm <path-to-wasm-interpreter>
+```
+where the path points to the spec interpreter executable (or a tool that understands similar options). If the binary is in the working directory, this option can be omitted.
+
+In addition, the option `--js <path-to-js-interpreter>` can be given to point to a stand-alone JavaScript interpreter supporting the WebAssembly API. If provided, all tests are also executed in JavaScript.
diff --git a/binaryen/test/spec/address-offset-range.fail.wast b/binaryen/test/spec/address-offset-range.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/address-offset-range.fail.wast
@@ -0,0 +1,4 @@
+(module
+  (memory 1)
+  (func $bad (drop (i32.load offset=4294967296 (i32.const 0))))
+)
diff --git a/binaryen/test/spec/address.wast b/binaryen/test/spec/address.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/address.wast
@@ -0,0 +1,589 @@
+;; Load i32 data with different offset/align arguments
+
+(module
+  (memory 1)
+  (data (i32.const 0) "abcdefghijklmnopqrstuvwxyz")
+
+  (func (export "8u_good1") (param $i i32) (result i32)
+    (i32.load8_u offset=0 (local.get $i))                   ;; 97 'a'
+  )
+  (func (export "8u_good2") (param $i i32) (result i32)
+    (i32.load8_u align=1 (local.get $i))                    ;; 97 'a'
+  )
+  (func (export "8u_good3") (param $i i32) (result i32)
+    (i32.load8_u offset=1 align=1 (local.get $i))           ;; 98 'b'
+  )
+  (func (export "8u_good4") (param $i i32) (result i32)
+    (i32.load8_u offset=2 align=1 (local.get $i))           ;; 99 'c'
+  )
+  (func (export "8u_good5") (param $i i32) (result i32)
+    (i32.load8_u offset=25 align=1 (local.get $i))          ;; 122 'z'
+  )
+
+  (func (export "8s_good1") (param $i i32) (result i32)
+    (i32.load8_s offset=0 (local.get $i))                   ;; 97 'a'
+  )
+  (func (export "8s_good2") (param $i i32) (result i32)
+    (i32.load8_s align=1 (local.get $i))                    ;; 97 'a'
+  )
+  (func (export "8s_good3") (param $i i32) (result i32)
+    (i32.load8_s offset=1 align=1 (local.get $i))           ;; 98 'b'
+  )
+  (func (export "8s_good4") (param $i i32) (result i32)
+    (i32.load8_s offset=2 align=1 (local.get $i))           ;; 99 'c'
+  )
+  (func (export "8s_good5") (param $i i32) (result i32)
+    (i32.load8_s offset=25 align=1 (local.get $i))          ;; 122 'z'
+  )
+
+  (func (export "16u_good1") (param $i i32) (result i32)
+    (i32.load16_u offset=0 (local.get $i))                  ;; 25185 'ab'
+  )
+  (func (export "16u_good2") (param $i i32) (result i32)
+    (i32.load16_u align=1 (local.get $i))                   ;; 25185 'ab'
+  )
+  (func (export "16u_good3") (param $i i32) (result i32)
+    (i32.load16_u offset=1 align=1 (local.get $i))          ;; 25442 'bc'
+  )
+  (func (export "16u_good4") (param $i i32) (result i32)
+    (i32.load16_u offset=2 align=2 (local.get $i))          ;; 25699 'cd'
+  )
+  (func (export "16u_good5") (param $i i32) (result i32)
+    (i32.load16_u offset=25 align=2 (local.get $i))         ;; 122 'z\0'
+  )
+
+  (func (export "16s_good1") (param $i i32) (result i32)
+    (i32.load16_s offset=0 (local.get $i))                  ;; 25185 'ab'
+  )
+  (func (export "16s_good2") (param $i i32) (result i32)
+    (i32.load16_s align=1 (local.get $i))                   ;; 25185 'ab'
+  )
+  (func (export "16s_good3") (param $i i32) (result i32)
+    (i32.load16_s offset=1 align=1 (local.get $i))          ;; 25442 'bc'
+  )
+  (func (export "16s_good4") (param $i i32) (result i32)
+    (i32.load16_s offset=2 align=2 (local.get $i))          ;; 25699 'cd'
+  )
+  (func (export "16s_good5") (param $i i32) (result i32)
+    (i32.load16_s offset=25 align=2 (local.get $i))         ;; 122 'z\0'
+  )
+
+  (func (export "32_good1") (param $i i32) (result i32)
+    (i32.load offset=0 (local.get $i))                      ;; 1684234849 'abcd'
+  )
+  (func (export "32_good2") (param $i i32) (result i32)
+    (i32.load align=1 (local.get $i))                       ;; 1684234849 'abcd'
+  )
+  (func (export "32_good3") (param $i i32) (result i32)
+    (i32.load offset=1 align=1 (local.get $i))              ;; 1701077858 'bcde'
+  )
+  (func (export "32_good4") (param $i i32) (result i32)
+    (i32.load offset=2 align=2 (local.get $i))              ;; 1717920867 'cdef'
+  )
+  (func (export "32_good5") (param $i i32) (result i32)
+    (i32.load offset=25 align=4 (local.get $i))             ;; 122 'z\0\0\0'
+  )
+
+  (func (export "8u_bad") (param $i i32)
+    (drop (i32.load8_u offset=4294967295 (local.get $i)))
+  )
+  (func (export "8s_bad") (param $i i32)
+    (drop (i32.load8_s offset=4294967295 (local.get $i)))
+  )
+  (func (export "16u_bad") (param $i i32)
+    (drop (i32.load16_u offset=4294967295 (local.get $i)))
+  )
+  (func (export "16s_bad") (param $i i32)
+    (drop (i32.load16_s offset=4294967295 (local.get $i)))
+  )
+  (func (export "32_bad") (param $i i32)
+    (drop (i32.load offset=4294967295 (local.get $i)))
+  )
+)
+
+(assert_return (invoke "8u_good1" (i32.const 0)) (i32.const 97))
+(assert_return (invoke "8u_good2" (i32.const 0)) (i32.const 97))
+(assert_return (invoke "8u_good3" (i32.const 0)) (i32.const 98))
+(assert_return (invoke "8u_good4" (i32.const 0)) (i32.const 99))
+(assert_return (invoke "8u_good5" (i32.const 0)) (i32.const 122))
+
+(assert_return (invoke "8s_good1" (i32.const 0)) (i32.const 97))
+(assert_return (invoke "8s_good2" (i32.const 0)) (i32.const 97))
+(assert_return (invoke "8s_good3" (i32.const 0)) (i32.const 98))
+(assert_return (invoke "8s_good4" (i32.const 0)) (i32.const 99))
+(assert_return (invoke "8s_good5" (i32.const 0)) (i32.const 122))
+
+(assert_return (invoke "16u_good1" (i32.const 0)) (i32.const 25185))
+(assert_return (invoke "16u_good2" (i32.const 0)) (i32.const 25185))
+(assert_return (invoke "16u_good3" (i32.const 0)) (i32.const 25442))
+(assert_return (invoke "16u_good4" (i32.const 0)) (i32.const 25699))
+(assert_return (invoke "16u_good5" (i32.const 0)) (i32.const 122))
+
+(assert_return (invoke "16s_good1" (i32.const 0)) (i32.const 25185))
+(assert_return (invoke "16s_good2" (i32.const 0)) (i32.const 25185))
+(assert_return (invoke "16s_good3" (i32.const 0)) (i32.const 25442))
+(assert_return (invoke "16s_good4" (i32.const 0)) (i32.const 25699))
+(assert_return (invoke "16s_good5" (i32.const 0)) (i32.const 122))
+
+(assert_return (invoke "32_good1" (i32.const 0)) (i32.const 1684234849))
+(assert_return (invoke "32_good2" (i32.const 0)) (i32.const 1684234849))
+(assert_return (invoke "32_good3" (i32.const 0)) (i32.const 1701077858))
+(assert_return (invoke "32_good4" (i32.const 0)) (i32.const 1717920867))
+(assert_return (invoke "32_good5" (i32.const 0)) (i32.const 122))
+
+(assert_return (invoke "8u_good1" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "8u_good2" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "8u_good3" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "8u_good4" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "8u_good5" (i32.const 65507)) (i32.const 0))
+
+(assert_return (invoke "8s_good1" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "8s_good2" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "8s_good3" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "8s_good4" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "8s_good5" (i32.const 65507)) (i32.const 0))
+
+(assert_return (invoke "16u_good1" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "16u_good2" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "16u_good3" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "16u_good4" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "16u_good5" (i32.const 65507)) (i32.const 0))
+
+(assert_return (invoke "16s_good1" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "16s_good2" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "16s_good3" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "16s_good4" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "16s_good5" (i32.const 65507)) (i32.const 0))
+
+(assert_return (invoke "32_good1" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "32_good2" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "32_good3" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "32_good4" (i32.const 65507)) (i32.const 0))
+(assert_return (invoke "32_good5" (i32.const 65507)) (i32.const 0))
+
+(assert_return (invoke "8u_good1" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "8u_good2" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "8u_good3" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "8u_good4" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "8u_good5" (i32.const 65508)) (i32.const 0))
+
+(assert_return (invoke "8s_good1" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "8s_good2" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "8s_good3" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "8s_good4" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "8s_good5" (i32.const 65508)) (i32.const 0))
+
+(assert_return (invoke "16u_good1" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "16u_good2" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "16u_good3" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "16u_good4" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "16u_good5" (i32.const 65508)) (i32.const 0))
+
+(assert_return (invoke "16s_good1" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "16s_good2" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "16s_good3" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "16s_good4" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "16s_good5" (i32.const 65508)) (i32.const 0))
+
+(assert_return (invoke "32_good1" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "32_good2" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "32_good3" (i32.const 65508)) (i32.const 0))
+(assert_return (invoke "32_good4" (i32.const 65508)) (i32.const 0))
+(assert_trap (invoke "32_good5" (i32.const 65508)) "out of bounds memory access")
+
+(assert_trap (invoke "8u_bad" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "8s_bad" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "16u_bad" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "16s_bad" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "32_bad" (i32.const 0)) "out of bounds memory access")
+
+(assert_trap (invoke "8u_bad" (i32.const 1)) "out of bounds memory access")
+(assert_trap (invoke "8s_bad" (i32.const 1)) "out of bounds memory access")
+(assert_trap (invoke "16u_bad" (i32.const 1)) "out of bounds memory access")
+(assert_trap (invoke "16s_bad" (i32.const 1)) "out of bounds memory access")
+(assert_trap (invoke "32_bad" (i32.const 1)) "out of bounds memory access")
+
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (drop (i32.load offset=4294967296 (i32.const 0))))"
+  )
+  "i32 constant"
+)
+
+;; Load i64 data with different offset/align arguments
+
+(module
+  (memory 1)
+  (data (i32.const 0) "abcdefghijklmnopqrstuvwxyz")
+
+  (func (export "8u_good1") (param $i i32) (result i64)
+    (i64.load8_u offset=0 (local.get $i))                   ;; 97 'a'
+  )
+  (func (export "8u_good2") (param $i i32) (result i64)
+    (i64.load8_u align=1 (local.get $i))                    ;; 97 'a'
+  )
+  (func (export "8u_good3") (param $i i32) (result i64)
+    (i64.load8_u offset=1 align=1 (local.get $i))           ;; 98 'b'
+  )
+  (func (export "8u_good4") (param $i i32) (result i64)
+    (i64.load8_u offset=2 align=1 (local.get $i))           ;; 99 'c'
+  )
+  (func (export "8u_good5") (param $i i32) (result i64)
+    (i64.load8_u offset=25 align=1 (local.get $i))          ;; 122 'z'
+  )
+
+  (func (export "8s_good1") (param $i i32) (result i64)
+    (i64.load8_s offset=0 (local.get $i))                   ;; 97 'a'
+  )
+  (func (export "8s_good2") (param $i i32) (result i64)
+    (i64.load8_s align=1 (local.get $i))                    ;; 97 'a'
+  )
+  (func (export "8s_good3") (param $i i32) (result i64)
+    (i64.load8_s offset=1 align=1 (local.get $i))           ;; 98 'b'
+  )
+  (func (export "8s_good4") (param $i i32) (result i64)
+    (i64.load8_s offset=2 align=1 (local.get $i))           ;; 99 'c'
+  )
+  (func (export "8s_good5") (param $i i32) (result i64)
+    (i64.load8_s offset=25 align=1 (local.get $i))          ;; 122 'z'
+  )
+
+  (func (export "16u_good1") (param $i i32) (result i64)
+    (i64.load16_u offset=0 (local.get $i))                 ;; 25185 'ab'
+  )
+  (func (export "16u_good2") (param $i i32) (result i64)
+    (i64.load16_u align=1 (local.get $i))                  ;; 25185 'ab'
+  )
+  (func (export "16u_good3") (param $i i32) (result i64)
+    (i64.load16_u offset=1 align=1 (local.get $i))         ;; 25442 'bc'
+  )
+  (func (export "16u_good4") (param $i i32) (result i64)
+    (i64.load16_u offset=2 align=2 (local.get $i))         ;; 25699 'cd'
+  )
+  (func (export "16u_good5") (param $i i32) (result i64)
+    (i64.load16_u offset=25 align=2 (local.get $i))        ;; 122 'z\0'
+  )
+
+  (func (export "16s_good1") (param $i i32) (result i64)
+    (i64.load16_s offset=0 (local.get $i))                 ;; 25185 'ab'
+  )
+  (func (export "16s_good2") (param $i i32) (result i64)
+    (i64.load16_s align=1 (local.get $i))                  ;; 25185 'ab'
+  )
+  (func (export "16s_good3") (param $i i32) (result i64)
+    (i64.load16_s offset=1 align=1 (local.get $i))         ;; 25442 'bc'
+  )
+  (func (export "16s_good4") (param $i i32) (result i64)
+    (i64.load16_s offset=2 align=2 (local.get $i))         ;; 25699 'cd'
+  )
+  (func (export "16s_good5") (param $i i32) (result i64)
+    (i64.load16_s offset=25 align=2 (local.get $i))        ;; 122 'z\0'
+  )
+
+  (func (export "32u_good1") (param $i i32) (result i64)
+    (i64.load32_u offset=0 (local.get $i))                 ;; 1684234849 'abcd'
+  )
+  (func (export "32u_good2") (param $i i32) (result i64)
+    (i64.load32_u align=1 (local.get $i))                  ;; 1684234849 'abcd'
+  )
+  (func (export "32u_good3") (param $i i32) (result i64)
+    (i64.load32_u offset=1 align=1 (local.get $i))         ;; 1701077858 'bcde'
+  )
+  (func (export "32u_good4") (param $i i32) (result i64)
+    (i64.load32_u offset=2 align=2 (local.get $i))         ;; 1717920867 'cdef'
+  )
+  (func (export "32u_good5") (param $i i32) (result i64)
+    (i64.load32_u offset=25 align=4 (local.get $i))        ;; 122 'z\0\0\0'
+  )
+
+  (func (export "32s_good1") (param $i i32) (result i64)
+    (i64.load32_s offset=0 (local.get $i))                 ;; 1684234849 'abcd'
+  )
+  (func (export "32s_good2") (param $i i32) (result i64)
+    (i64.load32_s align=1 (local.get $i))                  ;; 1684234849 'abcd'
+  )
+  (func (export "32s_good3") (param $i i32) (result i64)
+    (i64.load32_s offset=1 align=1 (local.get $i))         ;; 1701077858 'bcde'
+  )
+  (func (export "32s_good4") (param $i i32) (result i64)
+    (i64.load32_s offset=2 align=2 (local.get $i))         ;; 1717920867 'cdef'
+  )
+  (func (export "32s_good5") (param $i i32) (result i64)
+    (i64.load32_s offset=25 align=4 (local.get $i))        ;; 122 'z\0\0\0'
+  )
+
+  (func (export "64_good1") (param $i i32) (result i64)
+    (i64.load offset=0 (local.get $i))                     ;; 0x6867666564636261 'abcdefgh'
+  )
+  (func (export "64_good2") (param $i i32) (result i64)
+    (i64.load align=1 (local.get $i))                      ;; 0x6867666564636261 'abcdefgh'
+  )
+  (func (export "64_good3") (param $i i32) (result i64)
+    (i64.load offset=1 align=1 (local.get $i))             ;; 0x6968676665646362 'bcdefghi'
+  )
+  (func (export "64_good4") (param $i i32) (result i64)
+    (i64.load offset=2 align=2 (local.get $i))             ;; 0x6a69686766656463 'cdefghij'
+  )
+  (func (export "64_good5") (param $i i32) (result i64)
+    (i64.load offset=25 align=8 (local.get $i))            ;; 122 'z\0\0\0\0\0\0\0'
+  )
+
+  (func (export "8u_bad") (param $i i32)
+    (drop (i64.load8_u offset=4294967295 (local.get $i)))
+  )
+  (func (export "8s_bad") (param $i i32)
+    (drop (i64.load8_s offset=4294967295 (local.get $i)))
+  )
+  (func (export "16u_bad") (param $i i32)
+    (drop (i64.load16_u offset=4294967295 (local.get $i)))
+  )
+  (func (export "16s_bad") (param $i i32)
+    (drop (i64.load16_s offset=4294967295 (local.get $i)))
+  )
+  (func (export "32u_bad") (param $i i32)
+    (drop (i64.load32_u offset=4294967295 (local.get $i)))
+  )
+  (func (export "32s_bad") (param $i i32)
+    (drop (i64.load32_s offset=4294967295 (local.get $i)))
+  )
+  (func (export "64_bad") (param $i i32)
+    (drop (i64.load offset=4294967295 (local.get $i)))
+  )
+)
+
+(assert_return (invoke "8u_good1" (i32.const 0)) (i64.const 97))
+(assert_return (invoke "8u_good2" (i32.const 0)) (i64.const 97))
+(assert_return (invoke "8u_good3" (i32.const 0)) (i64.const 98))
+(assert_return (invoke "8u_good4" (i32.const 0)) (i64.const 99))
+(assert_return (invoke "8u_good5" (i32.const 0)) (i64.const 122))
+
+(assert_return (invoke "8s_good1" (i32.const 0)) (i64.const 97))
+(assert_return (invoke "8s_good2" (i32.const 0)) (i64.const 97))
+(assert_return (invoke "8s_good3" (i32.const 0)) (i64.const 98))
+(assert_return (invoke "8s_good4" (i32.const 0)) (i64.const 99))
+(assert_return (invoke "8s_good5" (i32.const 0)) (i64.const 122))
+
+(assert_return (invoke "16u_good1" (i32.const 0)) (i64.const 25185))
+(assert_return (invoke "16u_good2" (i32.const 0)) (i64.const 25185))
+(assert_return (invoke "16u_good3" (i32.const 0)) (i64.const 25442))
+(assert_return (invoke "16u_good4" (i32.const 0)) (i64.const 25699))
+(assert_return (invoke "16u_good5" (i32.const 0)) (i64.const 122))
+
+(assert_return (invoke "16s_good1" (i32.const 0)) (i64.const 25185))
+(assert_return (invoke "16s_good2" (i32.const 0)) (i64.const 25185))
+(assert_return (invoke "16s_good3" (i32.const 0)) (i64.const 25442))
+(assert_return (invoke "16s_good4" (i32.const 0)) (i64.const 25699))
+(assert_return (invoke "16s_good5" (i32.const 0)) (i64.const 122))
+
+(assert_return (invoke "32u_good1" (i32.const 0)) (i64.const 1684234849))
+(assert_return (invoke "32u_good2" (i32.const 0)) (i64.const 1684234849))
+(assert_return (invoke "32u_good3" (i32.const 0)) (i64.const 1701077858))
+(assert_return (invoke "32u_good4" (i32.const 0)) (i64.const 1717920867))
+(assert_return (invoke "32u_good5" (i32.const 0)) (i64.const 122))
+
+(assert_return (invoke "32s_good1" (i32.const 0)) (i64.const 1684234849))
+(assert_return (invoke "32s_good2" (i32.const 0)) (i64.const 1684234849))
+(assert_return (invoke "32s_good3" (i32.const 0)) (i64.const 1701077858))
+(assert_return (invoke "32s_good4" (i32.const 0)) (i64.const 1717920867))
+(assert_return (invoke "32s_good5" (i32.const 0)) (i64.const 122))
+
+(assert_return (invoke "64_good1" (i32.const 0)) (i64.const 0x6867666564636261))
+(assert_return (invoke "64_good2" (i32.const 0)) (i64.const 0x6867666564636261))
+(assert_return (invoke "64_good3" (i32.const 0)) (i64.const 0x6968676665646362))
+(assert_return (invoke "64_good4" (i32.const 0)) (i64.const 0x6a69686766656463))
+(assert_return (invoke "64_good5" (i32.const 0)) (i64.const 122))
+
+(assert_return (invoke "8u_good1" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "8u_good2" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "8u_good3" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "8u_good4" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "8u_good5" (i32.const 65503)) (i64.const 0))
+
+(assert_return (invoke "8s_good1" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "8s_good2" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "8s_good3" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "8s_good4" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "8s_good5" (i32.const 65503)) (i64.const 0))
+
+(assert_return (invoke "16u_good1" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "16u_good2" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "16u_good3" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "16u_good4" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "16u_good5" (i32.const 65503)) (i64.const 0))
+
+(assert_return (invoke "16s_good1" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "16s_good2" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "16s_good3" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "16s_good4" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "16s_good5" (i32.const 65503)) (i64.const 0))
+
+(assert_return (invoke "32u_good1" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "32u_good2" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "32u_good3" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "32u_good4" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "32u_good5" (i32.const 65503)) (i64.const 0))
+
+(assert_return (invoke "32s_good1" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "32s_good2" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "32s_good3" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "32s_good4" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "32s_good5" (i32.const 65503)) (i64.const 0))
+
+(assert_return (invoke "64_good1" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "64_good2" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "64_good3" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "64_good4" (i32.const 65503)) (i64.const 0))
+(assert_return (invoke "64_good5" (i32.const 65503)) (i64.const 0))
+
+(assert_return (invoke "8u_good1" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "8u_good2" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "8u_good3" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "8u_good4" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "8u_good5" (i32.const 65504)) (i64.const 0))
+
+(assert_return (invoke "8s_good1" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "8s_good2" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "8s_good3" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "8s_good4" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "8s_good5" (i32.const 65504)) (i64.const 0))
+
+(assert_return (invoke "16u_good1" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "16u_good2" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "16u_good3" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "16u_good4" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "16u_good5" (i32.const 65504)) (i64.const 0))
+
+(assert_return (invoke "16s_good1" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "16s_good2" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "16s_good3" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "16s_good4" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "16s_good5" (i32.const 65504)) (i64.const 0))
+
+(assert_return (invoke "32u_good1" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "32u_good2" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "32u_good3" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "32u_good4" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "32u_good5" (i32.const 65504)) (i64.const 0))
+
+(assert_return (invoke "32s_good1" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "32s_good2" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "32s_good3" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "32s_good4" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "32s_good5" (i32.const 65504)) (i64.const 0))
+
+(assert_return (invoke "64_good1" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "64_good2" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "64_good3" (i32.const 65504)) (i64.const 0))
+(assert_return (invoke "64_good4" (i32.const 65504)) (i64.const 0))
+(assert_trap (invoke "64_good5" (i32.const 65504)) "out of bounds memory access")
+
+(assert_trap (invoke "8u_bad" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "8s_bad" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "16u_bad" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "16s_bad" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "32u_bad" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "32s_bad" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "64_bad" (i32.const 0)) "out of bounds memory access")
+
+(assert_trap (invoke "8u_bad" (i32.const 1)) "out of bounds memory access")
+(assert_trap (invoke "8s_bad" (i32.const 1)) "out of bounds memory access")
+(assert_trap (invoke "16u_bad" (i32.const 1)) "out of bounds memory access")
+(assert_trap (invoke "16s_bad" (i32.const 1)) "out of bounds memory access")
+(assert_trap (invoke "32u_bad" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "32s_bad" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "64_bad" (i32.const 1)) "out of bounds memory access")
+
+;; Load f32 data with different offset/align arguments
+
+(module
+  (memory 1)
+  (data (i32.const 0) "\00\00\00\00\00\00\a0\7f\01\00\d0\7f")
+
+  (func (export "32_good1") (param $i i32) (result f32)
+    (f32.load offset=0 (local.get $i))                   ;; 0.0 '\00\00\00\00'
+  )
+  (func (export "32_good2") (param $i i32) (result f32)
+    (f32.load align=1 (local.get $i))                    ;; 0.0 '\00\00\00\00'
+  )
+  (func (export "32_good3") (param $i i32) (result f32)
+    (f32.load offset=1 align=1 (local.get $i))           ;; 0.0 '\00\00\00\00'
+  )
+  (func (export "32_good4") (param $i i32) (result f32)
+    (f32.load offset=2 align=2 (local.get $i))           ;; 0.0 '\00\00\00\00'
+  )
+  (func (export "32_good5") (param $i i32) (result f32)
+    (f32.load offset=8 align=4 (local.get $i))           ;; nan:0x500001 '\01\00\d0\7f'
+  )
+  (func (export "32_bad") (param $i i32)
+    (drop (f32.load offset=4294967295 (local.get $i)))
+  )
+)
+
+(assert_return (invoke "32_good1" (i32.const 0)) (f32.const 0.0))
+(assert_return (invoke "32_good2" (i32.const 0)) (f32.const 0.0))
+(assert_return (invoke "32_good3" (i32.const 0)) (f32.const 0.0))
+(assert_return (invoke "32_good4" (i32.const 0)) (f32.const 0.0))
+(assert_return (invoke "32_good5" (i32.const 0)) (f32.const nan:0x500001))
+
+(assert_return (invoke "32_good1" (i32.const 65524)) (f32.const 0.0))
+(assert_return (invoke "32_good2" (i32.const 65524)) (f32.const 0.0))
+(assert_return (invoke "32_good3" (i32.const 65524)) (f32.const 0.0))
+(assert_return (invoke "32_good4" (i32.const 65524)) (f32.const 0.0))
+(assert_return (invoke "32_good5" (i32.const 65524)) (f32.const 0.0))
+
+(assert_return (invoke "32_good1" (i32.const 65525)) (f32.const 0.0))
+(assert_return (invoke "32_good2" (i32.const 65525)) (f32.const 0.0))
+(assert_return (invoke "32_good3" (i32.const 65525)) (f32.const 0.0))
+(assert_return (invoke "32_good4" (i32.const 65525)) (f32.const 0.0))
+(assert_trap (invoke "32_good5" (i32.const 65525)) "out of bounds memory access")
+
+(assert_trap (invoke "32_bad" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "32_bad" (i32.const 1)) "out of bounds memory access")
+
+;; Load f64 data with different offset/align arguments
+
+(module
+  (memory 1)
+  (data (i32.const 0) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\f4\7f\01\00\00\00\00\00\fc\7f")
+
+  (func (export "64_good1") (param $i i32) (result f64)
+    (f64.load offset=0 (local.get $i))                     ;; 0.0 '\00\00\00\00\00\00\00\00'
+  )
+  (func (export "64_good2") (param $i i32) (result f64)
+    (f64.load align=1 (local.get $i))                      ;; 0.0 '\00\00\00\00\00\00\00\00'
+  )
+  (func (export "64_good3") (param $i i32) (result f64)
+    (f64.load offset=1 align=1 (local.get $i))             ;; 0.0 '\00\00\00\00\00\00\00\00'
+  )
+  (func (export "64_good4") (param $i i32) (result f64)
+    (f64.load offset=2 align=2 (local.get $i))             ;; 0.0 '\00\00\00\00\00\00\00\00'
+  )
+  (func (export "64_good5") (param $i i32) (result f64)
+    (f64.load offset=18 align=8 (local.get $i))            ;; nan:0xc000000000001 '\01\00\00\00\00\00\fc\7f'
+  )
+  (func (export "64_bad") (param $i i32)
+    (drop (f64.load offset=4294967295 (local.get $i)))
+  )
+)
+
+(assert_return (invoke "64_good1" (i32.const 0)) (f64.const 0.0))
+(assert_return (invoke "64_good2" (i32.const 0)) (f64.const 0.0))
+(assert_return (invoke "64_good3" (i32.const 0)) (f64.const 0.0))
+(assert_return (invoke "64_good4" (i32.const 0)) (f64.const 0.0))
+(assert_return (invoke "64_good5" (i32.const 0)) (f64.const nan:0xc000000000001))
+
+(assert_return (invoke "64_good1" (i32.const 65510)) (f64.const 0.0))
+(assert_return (invoke "64_good2" (i32.const 65510)) (f64.const 0.0))
+(assert_return (invoke "64_good3" (i32.const 65510)) (f64.const 0.0))
+(assert_return (invoke "64_good4" (i32.const 65510)) (f64.const 0.0))
+(assert_return (invoke "64_good5" (i32.const 65510)) (f64.const 0.0))
+
+(assert_return (invoke "64_good1" (i32.const 65511)) (f64.const 0.0))
+(assert_return (invoke "64_good2" (i32.const 65511)) (f64.const 0.0))
+(assert_return (invoke "64_good3" (i32.const 65511)) (f64.const 0.0))
+(assert_return (invoke "64_good4" (i32.const 65511)) (f64.const 0.0))
+(assert_trap (invoke "64_good5" (i32.const 65511)) "out of bounds memory access")
+
+(assert_trap (invoke "64_bad" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "64_bad" (i32.const 1)) "out of bounds memory access")
diff --git a/binaryen/test/spec/address64.wast b/binaryen/test/spec/address64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/address64.wast
@@ -0,0 +1,589 @@
+;; Load i32 data with different offset/align arguments
+
+(module
+  (memory i64 1)
+  (data (i32.const 0) "abcdefghijklmnopqrstuvwxyz")
+
+  (func (export "8u_good1") (param $i i64) (result i32)
+    (i32.load8_u offset=0 (local.get $i))                   ;; 97 'a'
+  )
+  (func (export "8u_good2") (param $i i64) (result i32)
+    (i32.load8_u align=1 (local.get $i))                    ;; 97 'a'
+  )
+  (func (export "8u_good3") (param $i i64) (result i32)
+    (i32.load8_u offset=1 align=1 (local.get $i))           ;; 98 'b'
+  )
+  (func (export "8u_good4") (param $i i64) (result i32)
+    (i32.load8_u offset=2 align=1 (local.get $i))           ;; 99 'c'
+  )
+  (func (export "8u_good5") (param $i i64) (result i32)
+    (i32.load8_u offset=25 align=1 (local.get $i))          ;; 122 'z'
+  )
+
+  (func (export "8s_good1") (param $i i64) (result i32)
+    (i32.load8_s offset=0 (local.get $i))                   ;; 97 'a'
+  )
+  (func (export "8s_good2") (param $i i64) (result i32)
+    (i32.load8_s align=1 (local.get $i))                    ;; 97 'a'
+  )
+  (func (export "8s_good3") (param $i i64) (result i32)
+    (i32.load8_s offset=1 align=1 (local.get $i))           ;; 98 'b'
+  )
+  (func (export "8s_good4") (param $i i64) (result i32)
+    (i32.load8_s offset=2 align=1 (local.get $i))           ;; 99 'c'
+  )
+  (func (export "8s_good5") (param $i i64) (result i32)
+    (i32.load8_s offset=25 align=1 (local.get $i))          ;; 122 'z'
+  )
+
+  (func (export "16u_good1") (param $i i64) (result i32)
+    (i32.load16_u offset=0 (local.get $i))                  ;; 25185 'ab'
+  )
+  (func (export "16u_good2") (param $i i64) (result i32)
+    (i32.load16_u align=1 (local.get $i))                   ;; 25185 'ab'
+  )
+  (func (export "16u_good3") (param $i i64) (result i32)
+    (i32.load16_u offset=1 align=1 (local.get $i))          ;; 25442 'bc'
+  )
+  (func (export "16u_good4") (param $i i64) (result i32)
+    (i32.load16_u offset=2 align=2 (local.get $i))          ;; 25699 'cd'
+  )
+  (func (export "16u_good5") (param $i i64) (result i32)
+    (i32.load16_u offset=25 align=2 (local.get $i))         ;; 122 'z\0'
+  )
+
+  (func (export "16s_good1") (param $i i64) (result i32)
+    (i32.load16_s offset=0 (local.get $i))                  ;; 25185 'ab'
+  )
+  (func (export "16s_good2") (param $i i64) (result i32)
+    (i32.load16_s align=1 (local.get $i))                   ;; 25185 'ab'
+  )
+  (func (export "16s_good3") (param $i i64) (result i32)
+    (i32.load16_s offset=1 align=1 (local.get $i))          ;; 25442 'bc'
+  )
+  (func (export "16s_good4") (param $i i64) (result i32)
+    (i32.load16_s offset=2 align=2 (local.get $i))          ;; 25699 'cd'
+  )
+  (func (export "16s_good5") (param $i i64) (result i32)
+    (i32.load16_s offset=25 align=2 (local.get $i))         ;; 122 'z\0'
+  )
+
+  (func (export "32_good1") (param $i i64) (result i32)
+    (i32.load offset=0 (local.get $i))                      ;; 1684234849 'abcd'
+  )
+  (func (export "32_good2") (param $i i64) (result i32)
+    (i32.load align=1 (local.get $i))                       ;; 1684234849 'abcd'
+  )
+  (func (export "32_good3") (param $i i64) (result i32)
+    (i32.load offset=1 align=1 (local.get $i))              ;; 1701077858 'bcde'
+  )
+  (func (export "32_good4") (param $i i64) (result i32)
+    (i32.load offset=2 align=2 (local.get $i))              ;; 1717920867 'cdef'
+  )
+  (func (export "32_good5") (param $i i64) (result i32)
+    (i32.load offset=25 align=4 (local.get $i))             ;; 122 'z\0\0\0'
+  )
+
+  (func (export "8u_bad") (param $i i64)
+    (drop (i32.load8_u offset=4294967295 (local.get $i)))
+  )
+  (func (export "8s_bad") (param $i i64)
+    (drop (i32.load8_s offset=4294967295 (local.get $i)))
+  )
+  (func (export "16u_bad") (param $i i64)
+    (drop (i32.load16_u offset=4294967295 (local.get $i)))
+  )
+  (func (export "16s_bad") (param $i i64)
+    (drop (i32.load16_s offset=4294967295 (local.get $i)))
+  )
+  (func (export "32_bad") (param $i i64)
+    (drop (i32.load offset=4294967295 (local.get $i)))
+  )
+)
+
+(assert_return (invoke "8u_good1" (i64.const 0)) (i32.const 97))
+(assert_return (invoke "8u_good2" (i64.const 0)) (i32.const 97))
+(assert_return (invoke "8u_good3" (i64.const 0)) (i32.const 98))
+(assert_return (invoke "8u_good4" (i64.const 0)) (i32.const 99))
+(assert_return (invoke "8u_good5" (i64.const 0)) (i32.const 122))
+
+(assert_return (invoke "8s_good1" (i64.const 0)) (i32.const 97))
+(assert_return (invoke "8s_good2" (i64.const 0)) (i32.const 97))
+(assert_return (invoke "8s_good3" (i64.const 0)) (i32.const 98))
+(assert_return (invoke "8s_good4" (i64.const 0)) (i32.const 99))
+(assert_return (invoke "8s_good5" (i64.const 0)) (i32.const 122))
+
+(assert_return (invoke "16u_good1" (i64.const 0)) (i32.const 25185))
+(assert_return (invoke "16u_good2" (i64.const 0)) (i32.const 25185))
+(assert_return (invoke "16u_good3" (i64.const 0)) (i32.const 25442))
+(assert_return (invoke "16u_good4" (i64.const 0)) (i32.const 25699))
+(assert_return (invoke "16u_good5" (i64.const 0)) (i32.const 122))
+
+(assert_return (invoke "16s_good1" (i64.const 0)) (i32.const 25185))
+(assert_return (invoke "16s_good2" (i64.const 0)) (i32.const 25185))
+(assert_return (invoke "16s_good3" (i64.const 0)) (i32.const 25442))
+(assert_return (invoke "16s_good4" (i64.const 0)) (i32.const 25699))
+(assert_return (invoke "16s_good5" (i64.const 0)) (i32.const 122))
+
+(assert_return (invoke "32_good1" (i64.const 0)) (i32.const 1684234849))
+(assert_return (invoke "32_good2" (i64.const 0)) (i32.const 1684234849))
+(assert_return (invoke "32_good3" (i64.const 0)) (i32.const 1701077858))
+(assert_return (invoke "32_good4" (i64.const 0)) (i32.const 1717920867))
+(assert_return (invoke "32_good5" (i64.const 0)) (i32.const 122))
+
+(assert_return (invoke "8u_good1" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "8u_good2" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "8u_good3" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "8u_good4" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "8u_good5" (i64.const 65507)) (i32.const 0))
+
+(assert_return (invoke "8s_good1" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "8s_good2" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "8s_good3" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "8s_good4" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "8s_good5" (i64.const 65507)) (i32.const 0))
+
+(assert_return (invoke "16u_good1" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "16u_good2" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "16u_good3" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "16u_good4" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "16u_good5" (i64.const 65507)) (i32.const 0))
+
+(assert_return (invoke "16s_good1" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "16s_good2" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "16s_good3" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "16s_good4" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "16s_good5" (i64.const 65507)) (i32.const 0))
+
+(assert_return (invoke "32_good1" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "32_good2" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "32_good3" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "32_good4" (i64.const 65507)) (i32.const 0))
+(assert_return (invoke "32_good5" (i64.const 65507)) (i32.const 0))
+
+(assert_return (invoke "8u_good1" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "8u_good2" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "8u_good3" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "8u_good4" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "8u_good5" (i64.const 65508)) (i32.const 0))
+
+(assert_return (invoke "8s_good1" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "8s_good2" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "8s_good3" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "8s_good4" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "8s_good5" (i64.const 65508)) (i32.const 0))
+
+(assert_return (invoke "16u_good1" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "16u_good2" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "16u_good3" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "16u_good4" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "16u_good5" (i64.const 65508)) (i32.const 0))
+
+(assert_return (invoke "16s_good1" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "16s_good2" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "16s_good3" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "16s_good4" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "16s_good5" (i64.const 65508)) (i32.const 0))
+
+(assert_return (invoke "32_good1" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "32_good2" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "32_good3" (i64.const 65508)) (i32.const 0))
+(assert_return (invoke "32_good4" (i64.const 65508)) (i32.const 0))
+(assert_trap (invoke "32_good5" (i64.const 65508)) "out of bounds memory access")
+
+(assert_trap (invoke "8u_bad" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "8s_bad" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "16u_bad" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "16s_bad" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "32_bad" (i64.const 0)) "out of bounds memory access")
+
+(assert_trap (invoke "8u_bad" (i64.const 1)) "out of bounds memory access")
+(assert_trap (invoke "8s_bad" (i64.const 1)) "out of bounds memory access")
+(assert_trap (invoke "16u_bad" (i64.const 1)) "out of bounds memory access")
+(assert_trap (invoke "16s_bad" (i64.const 1)) "out of bounds memory access")
+(assert_trap (invoke "32_bad" (i64.const 1)) "out of bounds memory access")
+
+(assert_malformed
+  (module quote
+    "(memory i64 1)"
+    "(func (drop (i32.load offset=4294967296 (i64.const 0))))"
+  )
+  "i32 constant"
+)
+
+;; Load i64 data with different offset/align arguments
+
+(module
+  (memory i64 1)
+  (data (i32.const 0) "abcdefghijklmnopqrstuvwxyz")
+
+  (func (export "8u_good1") (param $i i64) (result i64)
+    (i64.load8_u offset=0 (local.get $i))                   ;; 97 'a'
+  )
+  (func (export "8u_good2") (param $i i64) (result i64)
+    (i64.load8_u align=1 (local.get $i))                    ;; 97 'a'
+  )
+  (func (export "8u_good3") (param $i i64) (result i64)
+    (i64.load8_u offset=1 align=1 (local.get $i))           ;; 98 'b'
+  )
+  (func (export "8u_good4") (param $i i64) (result i64)
+    (i64.load8_u offset=2 align=1 (local.get $i))           ;; 99 'c'
+  )
+  (func (export "8u_good5") (param $i i64) (result i64)
+    (i64.load8_u offset=25 align=1 (local.get $i))          ;; 122 'z'
+  )
+
+  (func (export "8s_good1") (param $i i64) (result i64)
+    (i64.load8_s offset=0 (local.get $i))                   ;; 97 'a'
+  )
+  (func (export "8s_good2") (param $i i64) (result i64)
+    (i64.load8_s align=1 (local.get $i))                    ;; 97 'a'
+  )
+  (func (export "8s_good3") (param $i i64) (result i64)
+    (i64.load8_s offset=1 align=1 (local.get $i))           ;; 98 'b'
+  )
+  (func (export "8s_good4") (param $i i64) (result i64)
+    (i64.load8_s offset=2 align=1 (local.get $i))           ;; 99 'c'
+  )
+  (func (export "8s_good5") (param $i i64) (result i64)
+    (i64.load8_s offset=25 align=1 (local.get $i))          ;; 122 'z'
+  )
+
+  (func (export "16u_good1") (param $i i64) (result i64)
+    (i64.load16_u offset=0 (local.get $i))                 ;; 25185 'ab'
+  )
+  (func (export "16u_good2") (param $i i64) (result i64)
+    (i64.load16_u align=1 (local.get $i))                  ;; 25185 'ab'
+  )
+  (func (export "16u_good3") (param $i i64) (result i64)
+    (i64.load16_u offset=1 align=1 (local.get $i))         ;; 25442 'bc'
+  )
+  (func (export "16u_good4") (param $i i64) (result i64)
+    (i64.load16_u offset=2 align=2 (local.get $i))         ;; 25699 'cd'
+  )
+  (func (export "16u_good5") (param $i i64) (result i64)
+    (i64.load16_u offset=25 align=2 (local.get $i))        ;; 122 'z\0'
+  )
+
+  (func (export "16s_good1") (param $i i64) (result i64)
+    (i64.load16_s offset=0 (local.get $i))                 ;; 25185 'ab'
+  )
+  (func (export "16s_good2") (param $i i64) (result i64)
+    (i64.load16_s align=1 (local.get $i))                  ;; 25185 'ab'
+  )
+  (func (export "16s_good3") (param $i i64) (result i64)
+    (i64.load16_s offset=1 align=1 (local.get $i))         ;; 25442 'bc'
+  )
+  (func (export "16s_good4") (param $i i64) (result i64)
+    (i64.load16_s offset=2 align=2 (local.get $i))         ;; 25699 'cd'
+  )
+  (func (export "16s_good5") (param $i i64) (result i64)
+    (i64.load16_s offset=25 align=2 (local.get $i))        ;; 122 'z\0'
+  )
+
+  (func (export "32u_good1") (param $i i64) (result i64)
+    (i64.load32_u offset=0 (local.get $i))                 ;; 1684234849 'abcd'
+  )
+  (func (export "32u_good2") (param $i i64) (result i64)
+    (i64.load32_u align=1 (local.get $i))                  ;; 1684234849 'abcd'
+  )
+  (func (export "32u_good3") (param $i i64) (result i64)
+    (i64.load32_u offset=1 align=1 (local.get $i))         ;; 1701077858 'bcde'
+  )
+  (func (export "32u_good4") (param $i i64) (result i64)
+    (i64.load32_u offset=2 align=2 (local.get $i))         ;; 1717920867 'cdef'
+  )
+  (func (export "32u_good5") (param $i i64) (result i64)
+    (i64.load32_u offset=25 align=4 (local.get $i))        ;; 122 'z\0\0\0'
+  )
+
+  (func (export "32s_good1") (param $i i64) (result i64)
+    (i64.load32_s offset=0 (local.get $i))                 ;; 1684234849 'abcd'
+  )
+  (func (export "32s_good2") (param $i i64) (result i64)
+    (i64.load32_s align=1 (local.get $i))                  ;; 1684234849 'abcd'
+  )
+  (func (export "32s_good3") (param $i i64) (result i64)
+    (i64.load32_s offset=1 align=1 (local.get $i))         ;; 1701077858 'bcde'
+  )
+  (func (export "32s_good4") (param $i i64) (result i64)
+    (i64.load32_s offset=2 align=2 (local.get $i))         ;; 1717920867 'cdef'
+  )
+  (func (export "32s_good5") (param $i i64) (result i64)
+    (i64.load32_s offset=25 align=4 (local.get $i))        ;; 122 'z\0\0\0'
+  )
+
+  (func (export "64_good1") (param $i i64) (result i64)
+    (i64.load offset=0 (local.get $i))                     ;; 0x6867666564636261 'abcdefgh'
+  )
+  (func (export "64_good2") (param $i i64) (result i64)
+    (i64.load align=1 (local.get $i))                      ;; 0x6867666564636261 'abcdefgh'
+  )
+  (func (export "64_good3") (param $i i64) (result i64)
+    (i64.load offset=1 align=1 (local.get $i))             ;; 0x6968676665646362 'bcdefghi'
+  )
+  (func (export "64_good4") (param $i i64) (result i64)
+    (i64.load offset=2 align=2 (local.get $i))             ;; 0x6a69686766656463 'cdefghij'
+  )
+  (func (export "64_good5") (param $i i64) (result i64)
+    (i64.load offset=25 align=8 (local.get $i))            ;; 122 'z\0\0\0\0\0\0\0'
+  )
+
+  (func (export "8u_bad") (param $i i64)
+    (drop (i64.load8_u offset=4294967295 (local.get $i)))
+  )
+  (func (export "8s_bad") (param $i i64)
+    (drop (i64.load8_s offset=4294967295 (local.get $i)))
+  )
+  (func (export "16u_bad") (param $i i64)
+    (drop (i64.load16_u offset=4294967295 (local.get $i)))
+  )
+  (func (export "16s_bad") (param $i i64)
+    (drop (i64.load16_s offset=4294967295 (local.get $i)))
+  )
+  (func (export "32u_bad") (param $i i64)
+    (drop (i64.load32_u offset=4294967295 (local.get $i)))
+  )
+  (func (export "32s_bad") (param $i i64)
+    (drop (i64.load32_s offset=4294967295 (local.get $i)))
+  )
+  (func (export "64_bad") (param $i i64)
+    (drop (i64.load offset=4294967295 (local.get $i)))
+  )
+)
+
+(assert_return (invoke "8u_good1" (i64.const 0)) (i64.const 97))
+(assert_return (invoke "8u_good2" (i64.const 0)) (i64.const 97))
+(assert_return (invoke "8u_good3" (i64.const 0)) (i64.const 98))
+(assert_return (invoke "8u_good4" (i64.const 0)) (i64.const 99))
+(assert_return (invoke "8u_good5" (i64.const 0)) (i64.const 122))
+
+(assert_return (invoke "8s_good1" (i64.const 0)) (i64.const 97))
+(assert_return (invoke "8s_good2" (i64.const 0)) (i64.const 97))
+(assert_return (invoke "8s_good3" (i64.const 0)) (i64.const 98))
+(assert_return (invoke "8s_good4" (i64.const 0)) (i64.const 99))
+(assert_return (invoke "8s_good5" (i64.const 0)) (i64.const 122))
+
+(assert_return (invoke "16u_good1" (i64.const 0)) (i64.const 25185))
+(assert_return (invoke "16u_good2" (i64.const 0)) (i64.const 25185))
+(assert_return (invoke "16u_good3" (i64.const 0)) (i64.const 25442))
+(assert_return (invoke "16u_good4" (i64.const 0)) (i64.const 25699))
+(assert_return (invoke "16u_good5" (i64.const 0)) (i64.const 122))
+
+(assert_return (invoke "16s_good1" (i64.const 0)) (i64.const 25185))
+(assert_return (invoke "16s_good2" (i64.const 0)) (i64.const 25185))
+(assert_return (invoke "16s_good3" (i64.const 0)) (i64.const 25442))
+(assert_return (invoke "16s_good4" (i64.const 0)) (i64.const 25699))
+(assert_return (invoke "16s_good5" (i64.const 0)) (i64.const 122))
+
+(assert_return (invoke "32u_good1" (i64.const 0)) (i64.const 1684234849))
+(assert_return (invoke "32u_good2" (i64.const 0)) (i64.const 1684234849))
+(assert_return (invoke "32u_good3" (i64.const 0)) (i64.const 1701077858))
+(assert_return (invoke "32u_good4" (i64.const 0)) (i64.const 1717920867))
+(assert_return (invoke "32u_good5" (i64.const 0)) (i64.const 122))
+
+(assert_return (invoke "32s_good1" (i64.const 0)) (i64.const 1684234849))
+(assert_return (invoke "32s_good2" (i64.const 0)) (i64.const 1684234849))
+(assert_return (invoke "32s_good3" (i64.const 0)) (i64.const 1701077858))
+(assert_return (invoke "32s_good4" (i64.const 0)) (i64.const 1717920867))
+(assert_return (invoke "32s_good5" (i64.const 0)) (i64.const 122))
+
+(assert_return (invoke "64_good1" (i64.const 0)) (i64.const 0x6867666564636261))
+(assert_return (invoke "64_good2" (i64.const 0)) (i64.const 0x6867666564636261))
+(assert_return (invoke "64_good3" (i64.const 0)) (i64.const 0x6968676665646362))
+(assert_return (invoke "64_good4" (i64.const 0)) (i64.const 0x6a69686766656463))
+(assert_return (invoke "64_good5" (i64.const 0)) (i64.const 122))
+
+(assert_return (invoke "8u_good1" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "8u_good2" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "8u_good3" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "8u_good4" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "8u_good5" (i64.const 65503)) (i64.const 0))
+
+(assert_return (invoke "8s_good1" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "8s_good2" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "8s_good3" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "8s_good4" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "8s_good5" (i64.const 65503)) (i64.const 0))
+
+(assert_return (invoke "16u_good1" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "16u_good2" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "16u_good3" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "16u_good4" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "16u_good5" (i64.const 65503)) (i64.const 0))
+
+(assert_return (invoke "16s_good1" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "16s_good2" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "16s_good3" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "16s_good4" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "16s_good5" (i64.const 65503)) (i64.const 0))
+
+(assert_return (invoke "32u_good1" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "32u_good2" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "32u_good3" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "32u_good4" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "32u_good5" (i64.const 65503)) (i64.const 0))
+
+(assert_return (invoke "32s_good1" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "32s_good2" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "32s_good3" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "32s_good4" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "32s_good5" (i64.const 65503)) (i64.const 0))
+
+(assert_return (invoke "64_good1" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "64_good2" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "64_good3" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "64_good4" (i64.const 65503)) (i64.const 0))
+(assert_return (invoke "64_good5" (i64.const 65503)) (i64.const 0))
+
+(assert_return (invoke "8u_good1" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "8u_good2" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "8u_good3" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "8u_good4" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "8u_good5" (i64.const 65504)) (i64.const 0))
+
+(assert_return (invoke "8s_good1" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "8s_good2" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "8s_good3" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "8s_good4" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "8s_good5" (i64.const 65504)) (i64.const 0))
+
+(assert_return (invoke "16u_good1" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "16u_good2" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "16u_good3" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "16u_good4" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "16u_good5" (i64.const 65504)) (i64.const 0))
+
+(assert_return (invoke "16s_good1" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "16s_good2" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "16s_good3" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "16s_good4" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "16s_good5" (i64.const 65504)) (i64.const 0))
+
+(assert_return (invoke "32u_good1" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "32u_good2" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "32u_good3" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "32u_good4" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "32u_good5" (i64.const 65504)) (i64.const 0))
+
+(assert_return (invoke "32s_good1" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "32s_good2" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "32s_good3" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "32s_good4" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "32s_good5" (i64.const 65504)) (i64.const 0))
+
+(assert_return (invoke "64_good1" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "64_good2" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "64_good3" (i64.const 65504)) (i64.const 0))
+(assert_return (invoke "64_good4" (i64.const 65504)) (i64.const 0))
+(assert_trap (invoke "64_good5" (i64.const 65504)) "out of bounds memory access")
+
+(assert_trap (invoke "8u_bad" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "8s_bad" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "16u_bad" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "16s_bad" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "32u_bad" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "32s_bad" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "64_bad" (i64.const 0)) "out of bounds memory access")
+
+(assert_trap (invoke "8u_bad" (i64.const 1)) "out of bounds memory access")
+(assert_trap (invoke "8s_bad" (i64.const 1)) "out of bounds memory access")
+(assert_trap (invoke "16u_bad" (i64.const 1)) "out of bounds memory access")
+(assert_trap (invoke "16s_bad" (i64.const 1)) "out of bounds memory access")
+(assert_trap (invoke "32u_bad" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "32s_bad" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "64_bad" (i64.const 1)) "out of bounds memory access")
+
+;; Load f32 data with different offset/align arguments
+
+(module
+  (memory i64 1)
+  (data (i32.const 0) "\00\00\00\00\00\00\a0\7f\01\00\d0\7f")
+
+  (func (export "32_good1") (param $i i64) (result f32)
+    (f32.load offset=0 (local.get $i))                   ;; 0.0 '\00\00\00\00'
+  )
+  (func (export "32_good2") (param $i i64) (result f32)
+    (f32.load align=1 (local.get $i))                    ;; 0.0 '\00\00\00\00'
+  )
+  (func (export "32_good3") (param $i i64) (result f32)
+    (f32.load offset=1 align=1 (local.get $i))           ;; 0.0 '\00\00\00\00'
+  )
+  (func (export "32_good4") (param $i i64) (result f32)
+    (f32.load offset=2 align=2 (local.get $i))           ;; 0.0 '\00\00\00\00'
+  )
+  (func (export "32_good5") (param $i i64) (result f32)
+    (f32.load offset=8 align=4 (local.get $i))           ;; nan:0x500001 '\01\00\d0\7f'
+  )
+  (func (export "32_bad") (param $i i64)
+    (drop (f32.load offset=4294967295 (local.get $i)))
+  )
+)
+
+(assert_return (invoke "32_good1" (i64.const 0)) (f32.const 0.0))
+(assert_return (invoke "32_good2" (i64.const 0)) (f32.const 0.0))
+(assert_return (invoke "32_good3" (i64.const 0)) (f32.const 0.0))
+(assert_return (invoke "32_good4" (i64.const 0)) (f32.const 0.0))
+(assert_return (invoke "32_good5" (i64.const 0)) (f32.const nan:0x500001))
+
+(assert_return (invoke "32_good1" (i64.const 65524)) (f32.const 0.0))
+(assert_return (invoke "32_good2" (i64.const 65524)) (f32.const 0.0))
+(assert_return (invoke "32_good3" (i64.const 65524)) (f32.const 0.0))
+(assert_return (invoke "32_good4" (i64.const 65524)) (f32.const 0.0))
+(assert_return (invoke "32_good5" (i64.const 65524)) (f32.const 0.0))
+
+(assert_return (invoke "32_good1" (i64.const 65525)) (f32.const 0.0))
+(assert_return (invoke "32_good2" (i64.const 65525)) (f32.const 0.0))
+(assert_return (invoke "32_good3" (i64.const 65525)) (f32.const 0.0))
+(assert_return (invoke "32_good4" (i64.const 65525)) (f32.const 0.0))
+(assert_trap (invoke "32_good5" (i64.const 65525)) "out of bounds memory access")
+
+(assert_trap (invoke "32_bad" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "32_bad" (i64.const 1)) "out of bounds memory access")
+
+;; Load f64 data with different offset/align arguments
+
+(module
+  (memory i64 1)
+  (data (i32.const 0) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\f4\7f\01\00\00\00\00\00\fc\7f")
+
+  (func (export "64_good1") (param $i i64) (result f64)
+    (f64.load offset=0 (local.get $i))                     ;; 0.0 '\00\00\00\00\00\00\00\00'
+  )
+  (func (export "64_good2") (param $i i64) (result f64)
+    (f64.load align=1 (local.get $i))                      ;; 0.0 '\00\00\00\00\00\00\00\00'
+  )
+  (func (export "64_good3") (param $i i64) (result f64)
+    (f64.load offset=1 align=1 (local.get $i))             ;; 0.0 '\00\00\00\00\00\00\00\00'
+  )
+  (func (export "64_good4") (param $i i64) (result f64)
+    (f64.load offset=2 align=2 (local.get $i))             ;; 0.0 '\00\00\00\00\00\00\00\00'
+  )
+  (func (export "64_good5") (param $i i64) (result f64)
+    (f64.load offset=18 align=8 (local.get $i))            ;; nan:0xc000000000001 '\01\00\00\00\00\00\fc\7f'
+  )
+  (func (export "64_bad") (param $i i64)
+    (drop (f64.load offset=4294967295 (local.get $i)))
+  )
+)
+
+(assert_return (invoke "64_good1" (i64.const 0)) (f64.const 0.0))
+(assert_return (invoke "64_good2" (i64.const 0)) (f64.const 0.0))
+(assert_return (invoke "64_good3" (i64.const 0)) (f64.const 0.0))
+(assert_return (invoke "64_good4" (i64.const 0)) (f64.const 0.0))
+(assert_return (invoke "64_good5" (i64.const 0)) (f64.const nan:0xc000000000001))
+
+(assert_return (invoke "64_good1" (i64.const 65510)) (f64.const 0.0))
+(assert_return (invoke "64_good2" (i64.const 65510)) (f64.const 0.0))
+(assert_return (invoke "64_good3" (i64.const 65510)) (f64.const 0.0))
+(assert_return (invoke "64_good4" (i64.const 65510)) (f64.const 0.0))
+(assert_return (invoke "64_good5" (i64.const 65510)) (f64.const 0.0))
+
+(assert_return (invoke "64_good1" (i64.const 65511)) (f64.const 0.0))
+(assert_return (invoke "64_good2" (i64.const 65511)) (f64.const 0.0))
+(assert_return (invoke "64_good3" (i64.const 65511)) (f64.const 0.0))
+(assert_return (invoke "64_good4" (i64.const 65511)) (f64.const 0.0))
+(assert_trap (invoke "64_good5" (i64.const 65511)) "out of bounds memory access")
+
+(assert_trap (invoke "64_bad" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "64_bad" (i64.const 1)) "out of bounds memory access")
diff --git a/binaryen/test/spec/align.wast b/binaryen/test/spec/align.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/align.wast
@@ -0,0 +1,866 @@
+;; Test alignment annotation rules
+
+(module (memory 0) (func (drop (i32.load8_s align=1 (i32.const 0)))))
+(module (memory 0) (func (drop (i32.load8_u align=1 (i32.const 0)))))
+(module (memory 0) (func (drop (i32.load16_s align=2 (i32.const 0)))))
+(module (memory 0) (func (drop (i32.load16_u align=2 (i32.const 0)))))
+(module (memory 0) (func (drop (i32.load align=4 (i32.const 0)))))
+(module (memory 0) (func (drop (i64.load8_s align=1 (i32.const 0)))))
+(module (memory 0) (func (drop (i64.load8_u align=1 (i32.const 0)))))
+(module (memory 0) (func (drop (i64.load16_s align=2 (i32.const 0)))))
+(module (memory 0) (func (drop (i64.load16_u align=2 (i32.const 0)))))
+(module (memory 0) (func (drop (i64.load32_s align=4 (i32.const 0)))))
+(module (memory 0) (func (drop (i64.load32_u align=4 (i32.const 0)))))
+(module (memory 0) (func (drop (i64.load align=8 (i32.const 0)))))
+(module (memory 0) (func (drop (f32.load align=4 (i32.const 0)))))
+(module (memory 0) (func (drop (f64.load align=8 (i32.const 0)))))
+(module (memory 0) (func (i32.store8 align=1 (i32.const 0) (i32.const 1))))
+(module (memory 0) (func (i32.store16 align=2 (i32.const 0) (i32.const 1))))
+(module (memory 0) (func (i32.store align=4 (i32.const 0) (i32.const 1))))
+(module (memory 0) (func (i64.store8 align=1 (i32.const 0) (i64.const 1))))
+(module (memory 0) (func (i64.store16 align=2 (i32.const 0) (i64.const 1))))
+(module (memory 0) (func (i64.store32 align=4 (i32.const 0) (i64.const 1))))
+(module (memory 0) (func (i64.store align=8 (i32.const 0) (i64.const 1))))
+(module (memory 0) (func (f32.store align=4 (i32.const 0) (f32.const 1.0))))
+(module (memory 0) (func (f64.store align=8 (i32.const 0) (f64.const 1.0))))
+
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i32.load8_s align=0 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i32.load8_s align=7 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i32.load8_u align=0 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i32.load8_u align=7 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i32.load16_s align=0 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i32.load16_s align=7 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i32.load16_u align=0 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i32.load16_u align=7 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i32.load align=0 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i32.load align=7 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i64.load8_s align=0 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i64.load8_s align=7 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i64.load8_u align=0 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i64.load8_u align=7 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i64.load16_s align=0 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i64.load16_s align=7 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i64.load16_u align=0 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i64.load16_u align=7 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i64.load32_s align=0 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i64.load32_s align=7 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i64.load32_u align=0 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i64.load32_u align=7 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i64.load align=0 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (i64.load align=7 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (f32.load align=0 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (f32.load align=7 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (f64.load align=0 (i32.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (drop (f64.load align=7 (i32.const 0)))))"
+  )
+  "alignment"
+)
+
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (i32.store8 align=0 (i32.const 0) (i32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (i32.store8 align=7 (i32.const 0) (i32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (i32.store16 align=0 (i32.const 0) (i32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (i32.store16 align=7 (i32.const 0) (i32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (i32.store align=0 (i32.const 0) (i32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (i32.store align=7 (i32.const 0) (i32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (i64.store8 align=0 (i32.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (i64.store8 align=7 (i32.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (i64.store16 align=0 (i32.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (i64.store16 align=7 (i32.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (i64.store32 align=0 (i32.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (i64.store32 align=7 (i32.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (i64.store align=0 (i32.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (i64.store align=7 (i32.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (f32.store align=0 (i32.const 0) (f32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (f32.store align=7 (i32.const 0) (f32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (f64.store align=0 (i32.const 0) (f32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory 0) (func (f64.store align=7 (i32.const 0) (f32.const 0))))"
+  )
+  "alignment"
+)
+
+(assert_invalid
+  (module (memory 0) (func (drop (i32.load8_s align=2 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i32.load8_u align=2 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i32.load16_s align=4 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i32.load16_u align=4 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i32.load align=8 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i64.load8_s align=2 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i64.load8_u align=2 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i64.load16_s align=4 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i64.load16_u align=4 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i64.load32_s align=8 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i64.load32_u align=8 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i64.load align=16 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (f32.load align=8 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (f64.load align=16 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+
+(assert_invalid
+  (module (memory 0) (func (drop (i32.load8_s align=2 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i32.load8_u align=2 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i32.load16_s align=4 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i32.load16_u align=4 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i32.load align=8 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i64.load8_s align=2 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i64.load8_u align=2 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i64.load16_s align=4 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i64.load16_u align=4 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i64.load32_s align=8 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i64.load32_u align=8 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (i64.load align=16 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (f32.load align=8 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (drop (f64.load align=16 (i32.const 0)))))
+  "alignment must not be larger than natural"
+)
+
+(assert_invalid
+  (module (memory 0) (func (i32.store8 align=2 (i32.const 0) (i32.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (i32.store16 align=4 (i32.const 0) (i32.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (i32.store align=8 (i32.const 0) (i32.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (i64.store8 align=2 (i32.const 0) (i64.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (i64.store16 align=4 (i32.const 0) (i64.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (i64.store32 align=8 (i32.const 0) (i64.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (i64.store align=16 (i32.const 0) (i64.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (f32.store align=8 (i32.const 0) (f32.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory 0) (func (f64.store align=16 (i32.const 0) (f64.const 0))))
+  "alignment must not be larger than natural"
+)
+
+;; Test aligned and unaligned read/write
+
+(module
+  (memory 1)
+
+  ;; $default: natural alignment, $1: align=1, $2: align=2, $4: align=4, $8: align=8
+
+  (func (export "f32_align_switch") (param i32) (result f32)
+    (local f32 f32)
+    (local.set 1 (f32.const 10.0))
+    (block $4
+      (block $2
+        (block $1
+          (block $default
+            (block $0
+              (br_table $0 $default $1 $2 $4 (local.get 0))
+            ) ;; 0
+            (f32.store (i32.const 0) (local.get 1))
+            (local.set 2 (f32.load (i32.const 0)))
+            (br $4)
+          ) ;; default
+          (f32.store align=1 (i32.const 0) (local.get 1))
+          (local.set 2 (f32.load align=1 (i32.const 0)))
+          (br $4)
+        ) ;; 1
+        (f32.store align=2 (i32.const 0) (local.get 1))
+        (local.set 2 (f32.load align=2 (i32.const 0)))
+        (br $4)
+      ) ;; 2
+      (f32.store align=4 (i32.const 0) (local.get 1))
+      (local.set 2 (f32.load align=4 (i32.const 0)))
+    ) ;; 4
+    (local.get 2)
+  )
+
+  (func (export "f64_align_switch") (param i32) (result f64)
+    (local f64 f64)
+    (local.set 1 (f64.const 10.0))
+    (block $8
+      (block $4
+        (block $2
+          (block $1
+            (block $default
+              (block $0
+                (br_table $0 $default $1 $2 $4 $8 (local.get 0))
+              ) ;; 0
+              (f64.store (i32.const 0) (local.get 1))
+              (local.set 2 (f64.load (i32.const 0)))
+              (br $8)
+            ) ;; default
+            (f64.store align=1 (i32.const 0) (local.get 1))
+            (local.set 2 (f64.load align=1 (i32.const 0)))
+            (br $8)
+          ) ;; 1
+          (f64.store align=2 (i32.const 0) (local.get 1))
+          (local.set 2 (f64.load align=2 (i32.const 0)))
+          (br $8)
+        ) ;; 2
+        (f64.store align=4 (i32.const 0) (local.get 1))
+        (local.set 2 (f64.load align=4 (i32.const 0)))
+        (br $8)
+      ) ;; 4
+      (f64.store align=8 (i32.const 0) (local.get 1))
+      (local.set 2 (f64.load align=8 (i32.const 0)))
+    ) ;; 8
+    (local.get 2)
+  )
+
+  ;; $8s: i32/i64.load8_s, $8u: i32/i64.load8_u, $16s: i32/i64.load16_s, $16u: i32/i64.load16_u, $32: i32.load
+  ;; $32s: i64.load32_s, $32u: i64.load32_u, $64: i64.load
+
+  (func (export "i32_align_switch") (param i32 i32) (result i32)
+    (local i32 i32)
+    (local.set 2 (i32.const 10))
+    (block $32
+      (block $16u
+        (block $16s
+          (block $8u
+            (block $8s
+              (block $0
+                (br_table $0 $8s $8u $16s $16u $32 (local.get 0))
+              ) ;; 0
+              (if (i32.eq (local.get 1) (i32.const 0))
+                (then
+                  (i32.store8 (i32.const 0) (local.get 2))
+                  (local.set 3 (i32.load8_s (i32.const 0)))
+                )
+              )
+              (if (i32.eq (local.get 1) (i32.const 1))
+                (then
+                  (i32.store8 align=1 (i32.const 0) (local.get 2))
+                  (local.set 3 (i32.load8_s align=1 (i32.const 0)))
+                )
+              )
+              (br $32)
+            ) ;; 8s
+            (if (i32.eq (local.get 1) (i32.const 0))
+              (then
+                (i32.store8 (i32.const 0) (local.get 2))
+                (local.set 3 (i32.load8_u (i32.const 0)))
+              )
+            )
+            (if (i32.eq (local.get 1) (i32.const 1))
+              (then
+                (i32.store8 align=1 (i32.const 0) (local.get 2))
+                (local.set 3 (i32.load8_u align=1 (i32.const 0)))
+              )
+            )
+            (br $32)
+          ) ;; 8u
+          (if (i32.eq (local.get 1) (i32.const 0))
+            (then
+              (i32.store16 (i32.const 0) (local.get 2))
+              (local.set 3 (i32.load16_s (i32.const 0)))
+            )
+          )
+          (if (i32.eq (local.get 1) (i32.const 1))
+            (then
+              (i32.store16 align=1 (i32.const 0) (local.get 2))
+              (local.set 3 (i32.load16_s align=1 (i32.const 0)))
+            )
+          )
+          (if (i32.eq (local.get 1) (i32.const 2))
+            (then
+              (i32.store16 align=2 (i32.const 0) (local.get 2))
+              (local.set 3 (i32.load16_s align=2 (i32.const 0)))
+            )
+          )
+          (br $32)
+        ) ;; 16s
+        (if (i32.eq (local.get 1) (i32.const 0))
+          (then
+            (i32.store16 (i32.const 0) (local.get 2))
+            (local.set 3 (i32.load16_u (i32.const 0)))
+          )
+        )
+        (if (i32.eq (local.get 1) (i32.const 1))
+          (then
+            (i32.store16 align=1 (i32.const 0) (local.get 2))
+            (local.set 3 (i32.load16_u align=1 (i32.const 0)))
+          )
+        )
+        (if (i32.eq (local.get 1) (i32.const 2))
+          (then
+            (i32.store16 align=2 (i32.const 0) (local.get 2))
+            (local.set 3 (i32.load16_u align=2 (i32.const 0)))
+          )
+        )
+        (br $32)
+      ) ;; 16u
+      (if (i32.eq (local.get 1) (i32.const 0))
+        (then
+          (i32.store (i32.const 0) (local.get 2))
+          (local.set 3 (i32.load (i32.const 0)))
+        )
+      )
+      (if (i32.eq (local.get 1) (i32.const 1))
+        (then
+          (i32.store align=1 (i32.const 0) (local.get 2))
+          (local.set 3 (i32.load align=1 (i32.const 0)))
+        )
+      )
+      (if (i32.eq (local.get 1) (i32.const 2))
+        (then
+          (i32.store align=2 (i32.const 0) (local.get 2))
+          (local.set 3 (i32.load align=2 (i32.const 0)))
+        )
+      )
+      (if (i32.eq (local.get 1) (i32.const 4))
+        (then
+          (i32.store align=4 (i32.const 0) (local.get 2))
+          (local.set 3 (i32.load align=4 (i32.const 0)))
+        )
+      )
+    ) ;; 32
+    (local.get 3)
+  )
+
+  (func (export "i64_align_switch") (param i32 i32) (result i64)
+    (local i64 i64)
+    (local.set 2 (i64.const 10))
+    (block $64
+      (block $32u
+        (block $32s
+          (block $16u
+            (block $16s
+              (block $8u
+                (block $8s
+                  (block $0
+                    (br_table $0 $8s $8u $16s $16u $32s $32u $64 (local.get 0))
+                  ) ;; 0
+                  (if (i32.eq (local.get 1) (i32.const 0))
+                    (then
+                      (i64.store8 (i32.const 0) (local.get 2))
+                      (local.set 3 (i64.load8_s (i32.const 0)))
+                    )
+                  )
+                  (if (i32.eq (local.get 1) (i32.const 1))
+                    (then
+                      (i64.store8 align=1 (i32.const 0) (local.get 2))
+                      (local.set 3 (i64.load8_s align=1 (i32.const 0)))
+                    )
+                  )
+                  (br $64)
+                ) ;; 8s
+                (if (i32.eq (local.get 1) (i32.const 0))
+                  (then
+                    (i64.store8 (i32.const 0) (local.get 2))
+                    (local.set 3 (i64.load8_u (i32.const 0)))
+                  )
+                )
+                (if (i32.eq (local.get 1) (i32.const 1))
+                  (then
+                    (i64.store8 align=1 (i32.const 0) (local.get 2))
+                    (local.set 3 (i64.load8_u align=1 (i32.const 0)))
+                  )
+                )
+                (br $64)
+              ) ;; 8u
+              (if (i32.eq (local.get 1) (i32.const 0))
+                (then
+                  (i64.store16 (i32.const 0) (local.get 2))
+                  (local.set 3 (i64.load16_s (i32.const 0)))
+                )
+              )
+              (if (i32.eq (local.get 1) (i32.const 1))
+                (then
+                  (i64.store16 align=1 (i32.const 0) (local.get 2))
+                  (local.set 3 (i64.load16_s align=1 (i32.const 0)))
+                )
+              )
+              (if (i32.eq (local.get 1) (i32.const 2))
+                (then
+                  (i64.store16 align=2 (i32.const 0) (local.get 2))
+                  (local.set 3 (i64.load16_s align=2 (i32.const 0)))
+                )
+              )
+              (br $64)
+            ) ;; 16s
+            (if (i32.eq (local.get 1) (i32.const 0))
+              (then
+                (i64.store16 (i32.const 0) (local.get 2))
+                (local.set 3 (i64.load16_u (i32.const 0)))
+              )
+            )
+            (if (i32.eq (local.get 1) (i32.const 1))
+              (then
+                (i64.store16 align=1 (i32.const 0) (local.get 2))
+                (local.set 3 (i64.load16_u align=1 (i32.const 0)))
+              )
+            )
+            (if (i32.eq (local.get 1) (i32.const 2))
+              (then
+                (i64.store16 align=2 (i32.const 0) (local.get 2))
+                (local.set 3 (i64.load16_u align=2 (i32.const 0)))
+              )
+            )
+            (br $64)
+          ) ;; 16u
+          (if (i32.eq (local.get 1) (i32.const 0))
+            (then
+              (i64.store32 (i32.const 0) (local.get 2))
+              (local.set 3 (i64.load32_s (i32.const 0)))
+            )
+          )
+          (if (i32.eq (local.get 1) (i32.const 1))
+            (then
+              (i64.store32 align=1 (i32.const 0) (local.get 2))
+              (local.set 3 (i64.load32_s align=1 (i32.const 0)))
+            )
+          )
+          (if (i32.eq (local.get 1) (i32.const 2))
+            (then
+              (i64.store32 align=2 (i32.const 0) (local.get 2))
+              (local.set 3 (i64.load32_s align=2 (i32.const 0)))
+            )
+          )
+          (if (i32.eq (local.get 1) (i32.const 4))
+            (then
+              (i64.store32 align=4 (i32.const 0) (local.get 2))
+              (local.set 3 (i64.load32_s align=4 (i32.const 0)))
+            )
+          )
+          (br $64)
+        ) ;; 32s
+        (if (i32.eq (local.get 1) (i32.const 0))
+          (then
+            (i64.store32 (i32.const 0) (local.get 2))
+            (local.set 3 (i64.load32_u (i32.const 0)))
+          )
+        )
+        (if (i32.eq (local.get 1) (i32.const 1))
+          (then
+            (i64.store32 align=1 (i32.const 0) (local.get 2))
+            (local.set 3 (i64.load32_u align=1 (i32.const 0)))
+          )
+        )
+        (if (i32.eq (local.get 1) (i32.const 2))
+          (then
+            (i64.store32 align=2 (i32.const 0) (local.get 2))
+            (local.set 3 (i64.load32_u align=2 (i32.const 0)))
+          )
+        )
+        (if (i32.eq (local.get 1) (i32.const 4))
+          (then
+            (i64.store32 align=4 (i32.const 0) (local.get 2))
+            (local.set 3 (i64.load32_u align=4 (i32.const 0)))
+          )
+        )
+        (br $64)
+      ) ;; 32u
+      (if (i32.eq (local.get 1) (i32.const 0))
+        (then
+          (i64.store (i32.const 0) (local.get 2))
+          (local.set 3 (i64.load (i32.const 0)))
+        )
+      )
+      (if (i32.eq (local.get 1) (i32.const 1))
+        (then
+          (i64.store align=1 (i32.const 0) (local.get 2))
+          (local.set 3 (i64.load align=1 (i32.const 0)))
+        )
+      )
+      (if (i32.eq (local.get 1) (i32.const 2))
+        (then
+          (i64.store align=2 (i32.const 0) (local.get 2))
+          (local.set 3 (i64.load align=2 (i32.const 0)))
+        )
+      )
+      (if (i32.eq (local.get 1) (i32.const 4))
+        (then
+          (i64.store align=4 (i32.const 0) (local.get 2))
+          (local.set 3 (i64.load align=4 (i32.const 0)))
+        )
+      )
+      (if (i32.eq (local.get 1) (i32.const 8))
+        (then
+          (i64.store align=8 (i32.const 0) (local.get 2))
+          (local.set 3 (i64.load align=8 (i32.const 0)))
+        )
+      )
+    ) ;; 64
+    (local.get 3)
+  )
+)
+
+(assert_return (invoke "f32_align_switch" (i32.const 0)) (f32.const 10.0))
+(assert_return (invoke "f32_align_switch" (i32.const 1)) (f32.const 10.0))
+(assert_return (invoke "f32_align_switch" (i32.const 2)) (f32.const 10.0))
+(assert_return (invoke "f32_align_switch" (i32.const 3)) (f32.const 10.0))
+
+(assert_return (invoke "f64_align_switch" (i32.const 0)) (f64.const 10.0))
+(assert_return (invoke "f64_align_switch" (i32.const 1)) (f64.const 10.0))
+(assert_return (invoke "f64_align_switch" (i32.const 2)) (f64.const 10.0))
+(assert_return (invoke "f64_align_switch" (i32.const 3)) (f64.const 10.0))
+(assert_return (invoke "f64_align_switch" (i32.const 4)) (f64.const 10.0))
+
+(assert_return (invoke "i32_align_switch" (i32.const 0) (i32.const 0)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 0) (i32.const 1)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 1) (i32.const 0)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 1) (i32.const 1)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 2) (i32.const 0)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 2) (i32.const 1)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 2) (i32.const 2)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 3) (i32.const 0)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 3) (i32.const 1)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 3) (i32.const 2)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 4) (i32.const 0)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 4) (i32.const 1)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 4) (i32.const 2)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 4) (i32.const 4)) (i32.const 10))
+
+(assert_return (invoke "i64_align_switch" (i32.const 0) (i32.const 0)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 0) (i32.const 1)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 1) (i32.const 0)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 1) (i32.const 1)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 2) (i32.const 0)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 2) (i32.const 1)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 2) (i32.const 2)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 3) (i32.const 0)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 3) (i32.const 1)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 3) (i32.const 2)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 4) (i32.const 0)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 4) (i32.const 1)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 4) (i32.const 2)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 4) (i32.const 4)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 5) (i32.const 0)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 5) (i32.const 1)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 5) (i32.const 2)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 5) (i32.const 4)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 6) (i32.const 0)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 6) (i32.const 1)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 6) (i32.const 2)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 6) (i32.const 4)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 6) (i32.const 8)) (i64.const 10))
+
+;; Test that an i64 store with 4-byte alignment that's 4 bytes out of bounds traps without storing anything
+
+(module
+  (memory 1)
+  (func (export "store") (param i32 i64)
+    (i64.store align=4 (local.get 0) (local.get 1))
+  )
+  (func (export "load") (param i32) (result i32)
+    (i32.load (local.get 0))
+  )
+)
+
+(assert_trap (invoke "store" (i32.const 65532) (i64.const -1)) "out of bounds memory access")
+;; No memory was changed
+(assert_return (invoke "load" (i32.const 65532)) (i32.const 0))
diff --git a/binaryen/test/spec/align64.wast b/binaryen/test/spec/align64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/align64.wast
@@ -0,0 +1,866 @@
+;; Test alignment annotation rules
+
+(module (memory i64 0) (func (drop (i32.load8_s align=1 (i64.const 0)))))
+(module (memory i64 0) (func (drop (i32.load8_u align=1 (i64.const 0)))))
+(module (memory i64 0) (func (drop (i32.load16_s align=2 (i64.const 0)))))
+(module (memory i64 0) (func (drop (i32.load16_u align=2 (i64.const 0)))))
+(module (memory i64 0) (func (drop (i32.load align=4 (i64.const 0)))))
+(module (memory i64 0) (func (drop (i64.load8_s align=1 (i64.const 0)))))
+(module (memory i64 0) (func (drop (i64.load8_u align=1 (i64.const 0)))))
+(module (memory i64 0) (func (drop (i64.load16_s align=2 (i64.const 0)))))
+(module (memory i64 0) (func (drop (i64.load16_u align=2 (i64.const 0)))))
+(module (memory i64 0) (func (drop (i64.load32_s align=4 (i64.const 0)))))
+(module (memory i64 0) (func (drop (i64.load32_u align=4 (i64.const 0)))))
+(module (memory i64 0) (func (drop (i64.load align=8 (i64.const 0)))))
+(module (memory i64 0) (func (drop (f32.load align=4 (i64.const 0)))))
+(module (memory i64 0) (func (drop (f64.load align=8 (i64.const 0)))))
+(module (memory i64 0) (func (i32.store8 align=1 (i64.const 0) (i32.const 1))))
+(module (memory i64 0) (func (i32.store16 align=2 (i64.const 0) (i32.const 1))))
+(module (memory i64 0) (func (i32.store align=4 (i64.const 0) (i32.const 1))))
+(module (memory i64 0) (func (i64.store8 align=1 (i64.const 0) (i64.const 1))))
+(module (memory i64 0) (func (i64.store16 align=2 (i64.const 0) (i64.const 1))))
+(module (memory i64 0) (func (i64.store32 align=4 (i64.const 0) (i64.const 1))))
+(module (memory i64 0) (func (i64.store align=8 (i64.const 0) (i64.const 1))))
+(module (memory i64 0) (func (f32.store align=4 (i64.const 0) (f32.const 1.0))))
+(module (memory i64 0) (func (f64.store align=8 (i64.const 0) (f64.const 1.0))))
+
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i32.load8_s align=0 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i32.load8_s align=7 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i32.load8_u align=0 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i32.load8_u align=7 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i32.load16_s align=0 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i32.load16_s align=7 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i32.load16_u align=0 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i32.load16_u align=7 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i32.load align=0 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i32.load align=7 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i64.load8_s align=0 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i64.load8_s align=7 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i64.load8_u align=0 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i64.load8_u align=7 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i64.load16_s align=0 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i64.load16_s align=7 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i64.load16_u align=0 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i64.load16_u align=7 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i64.load32_s align=0 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i64.load32_s align=7 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i64.load32_u align=0 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i64.load32_u align=7 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i64.load align=0 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (i64.load align=7 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (f32.load align=0 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (f32.load align=7 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (f64.load align=0 (i64.const 0)))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (drop (f64.load align=7 (i64.const 0)))))"
+  )
+  "alignment"
+)
+
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (i32.store8 align=0 (i64.const 0) (i32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (i32.store8 align=7 (i64.const 0) (i32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (i32.store16 align=0 (i64.const 0) (i32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (i32.store16 align=7 (i64.const 0) (i32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (i32.store align=0 (i64.const 0) (i32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (i32.store align=7 (i64.const 0) (i32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (i64.store8 align=0 (i64.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (i64.store8 align=7 (i64.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (i64.store16 align=0 (i64.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (i64.store16 align=7 (i64.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (i64.store32 align=0 (i64.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (i64.store32 align=7 (i64.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (i64.store align=0 (i64.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (i64.store align=7 (i64.const 0) (i64.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (f32.store align=0 (i64.const 0) (f32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (f32.store align=7 (i64.const 0) (f32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (f64.store align=0 (i64.const 0) (f32.const 0))))"
+  )
+  "alignment"
+)
+(assert_malformed
+  (module quote
+    "(module (memory i64 0) (func (f64.store align=7 (i64.const 0) (f32.const 0))))"
+  )
+  "alignment"
+)
+
+(assert_invalid
+  (module (memory i64 0) (func (drop (i32.load8_s align=2 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i32.load8_u align=2 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i32.load16_s align=4 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i32.load16_u align=4 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i32.load align=8 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i64.load8_s align=2 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i64.load8_u align=2 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i64.load16_s align=4 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i64.load16_u align=4 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i64.load32_s align=8 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i64.load32_u align=8 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i64.load align=16 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (f32.load align=8 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (f64.load align=16 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+
+(assert_invalid
+  (module (memory i64 0) (func (drop (i32.load8_s align=2 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i32.load8_u align=2 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i32.load16_s align=4 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i32.load16_u align=4 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i32.load align=8 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i64.load8_s align=2 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i64.load8_u align=2 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i64.load16_s align=4 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i64.load16_u align=4 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i64.load32_s align=8 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i64.load32_u align=8 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (i64.load align=16 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (f32.load align=8 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (drop (f64.load align=16 (i64.const 0)))))
+  "alignment must not be larger than natural"
+)
+
+(assert_invalid
+  (module (memory i64 0) (func (i32.store8 align=2 (i64.const 0) (i32.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (i32.store16 align=4 (i64.const 0) (i32.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (i32.store align=8 (i64.const 0) (i32.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (i64.store8 align=2 (i64.const 0) (i64.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (i64.store16 align=4 (i64.const 0) (i64.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (i64.store32 align=8 (i64.const 0) (i64.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (i64.store align=16 (i64.const 0) (i64.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (f32.store align=8 (i64.const 0) (f32.const 0))))
+  "alignment must not be larger than natural"
+)
+(assert_invalid
+  (module (memory i64 0) (func (f64.store align=16 (i64.const 0) (f64.const 0))))
+  "alignment must not be larger than natural"
+)
+
+;; Test aligned and unaligned read/write
+
+(module
+  (memory i64 1)
+
+  ;; $default: natural alignment, $1: align=1, $2: align=2, $4: align=4, $8: align=8
+
+  (func (export "f32_align_switch") (param i32) (result f32)
+    (local f32 f32)
+    (local.set 1 (f32.const 10.0))
+    (block $4
+      (block $2
+        (block $1
+          (block $default
+            (block $0
+              (br_table $0 $default $1 $2 $4 (local.get 0))
+            ) ;; 0
+            (f32.store (i64.const 0) (local.get 1))
+            (local.set 2 (f32.load (i64.const 0)))
+            (br $4)
+          ) ;; default
+          (f32.store align=1 (i64.const 0) (local.get 1))
+          (local.set 2 (f32.load align=1 (i64.const 0)))
+          (br $4)
+        ) ;; 1
+        (f32.store align=2 (i64.const 0) (local.get 1))
+        (local.set 2 (f32.load align=2 (i64.const 0)))
+        (br $4)
+      ) ;; 2
+      (f32.store align=4 (i64.const 0) (local.get 1))
+      (local.set 2 (f32.load align=4 (i64.const 0)))
+    ) ;; 4
+    (local.get 2)
+  )
+
+  (func (export "f64_align_switch") (param i32) (result f64)
+    (local f64 f64)
+    (local.set 1 (f64.const 10.0))
+    (block $8
+      (block $4
+        (block $2
+          (block $1
+            (block $default
+              (block $0
+                (br_table $0 $default $1 $2 $4 $8 (local.get 0))
+              ) ;; 0
+              (f64.store (i64.const 0) (local.get 1))
+              (local.set 2 (f64.load (i64.const 0)))
+              (br $8)
+            ) ;; default
+            (f64.store align=1 (i64.const 0) (local.get 1))
+            (local.set 2 (f64.load align=1 (i64.const 0)))
+            (br $8)
+          ) ;; 1
+          (f64.store align=2 (i64.const 0) (local.get 1))
+          (local.set 2 (f64.load align=2 (i64.const 0)))
+          (br $8)
+        ) ;; 2
+        (f64.store align=4 (i64.const 0) (local.get 1))
+        (local.set 2 (f64.load align=4 (i64.const 0)))
+        (br $8)
+      ) ;; 4
+      (f64.store align=8 (i64.const 0) (local.get 1))
+      (local.set 2 (f64.load align=8 (i64.const 0)))
+    ) ;; 8
+    (local.get 2)
+  )
+
+  ;; $8s: i32/i64.load8_s, $8u: i32/i64.load8_u, $16s: i32/i64.load16_s, $16u: i32/i64.load16_u, $32: i32.load
+  ;; $32s: i64.load32_s, $32u: i64.load32_u, $64: i64.load
+
+  (func (export "i32_align_switch") (param i32 i32) (result i32)
+    (local i32 i32)
+    (local.set 2 (i32.const 10))
+    (block $32
+      (block $16u
+        (block $16s
+          (block $8u
+            (block $8s
+              (block $0
+                (br_table $0 $8s $8u $16s $16u $32 (local.get 0))
+              ) ;; 0
+              (if (i32.eq (local.get 1) (i32.const 0))
+                (then
+                  (i32.store8 (i64.const 0) (local.get 2))
+                  (local.set 3 (i32.load8_s (i64.const 0)))
+                )
+              )
+              (if (i32.eq (local.get 1) (i32.const 1))
+                (then
+                  (i32.store8 align=1 (i64.const 0) (local.get 2))
+                  (local.set 3 (i32.load8_s align=1 (i64.const 0)))
+                )
+              )
+              (br $32)
+            ) ;; 8s
+            (if (i32.eq (local.get 1) (i32.const 0))
+              (then
+                (i32.store8 (i64.const 0) (local.get 2))
+                (local.set 3 (i32.load8_u (i64.const 0)))
+              )
+            )
+            (if (i32.eq (local.get 1) (i32.const 1))
+              (then
+                (i32.store8 align=1 (i64.const 0) (local.get 2))
+                (local.set 3 (i32.load8_u align=1 (i64.const 0)))
+              )
+            )
+            (br $32)
+          ) ;; 8u
+          (if (i32.eq (local.get 1) (i32.const 0))
+            (then
+              (i32.store16 (i64.const 0) (local.get 2))
+              (local.set 3 (i32.load16_s (i64.const 0)))
+            )
+          )
+          (if (i32.eq (local.get 1) (i32.const 1))
+            (then
+              (i32.store16 align=1 (i64.const 0) (local.get 2))
+              (local.set 3 (i32.load16_s align=1 (i64.const 0)))
+            )
+          )
+          (if (i32.eq (local.get 1) (i32.const 2))
+            (then
+              (i32.store16 align=2 (i64.const 0) (local.get 2))
+              (local.set 3 (i32.load16_s align=2 (i64.const 0)))
+            )
+          )
+          (br $32)
+        ) ;; 16s
+        (if (i32.eq (local.get 1) (i32.const 0))
+          (then
+            (i32.store16 (i64.const 0) (local.get 2))
+            (local.set 3 (i32.load16_u (i64.const 0)))
+          )
+        )
+        (if (i32.eq (local.get 1) (i32.const 1))
+          (then
+            (i32.store16 align=1 (i64.const 0) (local.get 2))
+            (local.set 3 (i32.load16_u align=1 (i64.const 0)))
+          )
+        )
+        (if (i32.eq (local.get 1) (i32.const 2))
+          (then
+            (i32.store16 align=2 (i64.const 0) (local.get 2))
+            (local.set 3 (i32.load16_u align=2 (i64.const 0)))
+          )
+        )
+        (br $32)
+      ) ;; 16u
+      (if (i32.eq (local.get 1) (i32.const 0))
+        (then
+          (i32.store (i64.const 0) (local.get 2))
+          (local.set 3 (i32.load (i64.const 0)))
+        )
+      )
+      (if (i32.eq (local.get 1) (i32.const 1))
+        (then
+          (i32.store align=1 (i64.const 0) (local.get 2))
+          (local.set 3 (i32.load align=1 (i64.const 0)))
+        )
+      )
+      (if (i32.eq (local.get 1) (i32.const 2))
+        (then
+          (i32.store align=2 (i64.const 0) (local.get 2))
+          (local.set 3 (i32.load align=2 (i64.const 0)))
+        )
+      )
+      (if (i32.eq (local.get 1) (i32.const 4))
+        (then
+          (i32.store align=4 (i64.const 0) (local.get 2))
+          (local.set 3 (i32.load align=4 (i64.const 0)))
+        )
+      )
+    ) ;; 32
+    (local.get 3)
+  )
+
+  (func (export "i64_align_switch") (param i32 i32) (result i64)
+    (local i64 i64)
+    (local.set 2 (i64.const 10))
+    (block $64
+      (block $32u
+        (block $32s
+          (block $16u
+            (block $16s
+              (block $8u
+                (block $8s
+                  (block $0
+                    (br_table $0 $8s $8u $16s $16u $32s $32u $64 (local.get 0))
+                  ) ;; 0
+                  (if (i32.eq (local.get 1) (i32.const 0))
+                    (then
+                      (i64.store8 (i64.const 0) (local.get 2))
+                      (local.set 3 (i64.load8_s (i64.const 0)))
+                    )
+                  )
+                  (if (i32.eq (local.get 1) (i32.const 1))
+                    (then
+                      (i64.store8 align=1 (i64.const 0) (local.get 2))
+                      (local.set 3 (i64.load8_s align=1 (i64.const 0)))
+                    )
+                  )
+                  (br $64)
+                ) ;; 8s
+                (if (i32.eq (local.get 1) (i32.const 0))
+                  (then
+                    (i64.store8 (i64.const 0) (local.get 2))
+                    (local.set 3 (i64.load8_u (i64.const 0)))
+                  )
+                )
+                (if (i32.eq (local.get 1) (i32.const 1))
+                  (then
+                    (i64.store8 align=1 (i64.const 0) (local.get 2))
+                    (local.set 3 (i64.load8_u align=1 (i64.const 0)))
+                  )
+                )
+                (br $64)
+              ) ;; 8u
+              (if (i32.eq (local.get 1) (i32.const 0))
+                (then
+                  (i64.store16 (i64.const 0) (local.get 2))
+                  (local.set 3 (i64.load16_s (i64.const 0)))
+                )
+              )
+              (if (i32.eq (local.get 1) (i32.const 1))
+                (then
+                  (i64.store16 align=1 (i64.const 0) (local.get 2))
+                  (local.set 3 (i64.load16_s align=1 (i64.const 0)))
+                )
+              )
+              (if (i32.eq (local.get 1) (i32.const 2))
+                (then
+                  (i64.store16 align=2 (i64.const 0) (local.get 2))
+                  (local.set 3 (i64.load16_s align=2 (i64.const 0)))
+                )
+              )
+              (br $64)
+            ) ;; 16s
+            (if (i32.eq (local.get 1) (i32.const 0))
+              (then
+                (i64.store16 (i64.const 0) (local.get 2))
+                (local.set 3 (i64.load16_u (i64.const 0)))
+              )
+            )
+            (if (i32.eq (local.get 1) (i32.const 1))
+              (then
+                (i64.store16 align=1 (i64.const 0) (local.get 2))
+                (local.set 3 (i64.load16_u align=1 (i64.const 0)))
+              )
+            )
+            (if (i32.eq (local.get 1) (i32.const 2))
+              (then
+                (i64.store16 align=2 (i64.const 0) (local.get 2))
+                (local.set 3 (i64.load16_u align=2 (i64.const 0)))
+              )
+            )
+            (br $64)
+          ) ;; 16u
+          (if (i32.eq (local.get 1) (i32.const 0))
+            (then
+              (i64.store32 (i64.const 0) (local.get 2))
+              (local.set 3 (i64.load32_s (i64.const 0)))
+            )
+          )
+          (if (i32.eq (local.get 1) (i32.const 1))
+            (then
+              (i64.store32 align=1 (i64.const 0) (local.get 2))
+              (local.set 3 (i64.load32_s align=1 (i64.const 0)))
+            )
+          )
+          (if (i32.eq (local.get 1) (i32.const 2))
+            (then
+              (i64.store32 align=2 (i64.const 0) (local.get 2))
+              (local.set 3 (i64.load32_s align=2 (i64.const 0)))
+            )
+          )
+          (if (i32.eq (local.get 1) (i32.const 4))
+            (then
+              (i64.store32 align=4 (i64.const 0) (local.get 2))
+              (local.set 3 (i64.load32_s align=4 (i64.const 0)))
+            )
+          )
+          (br $64)
+        ) ;; 32s
+        (if (i32.eq (local.get 1) (i32.const 0))
+          (then
+            (i64.store32 (i64.const 0) (local.get 2))
+            (local.set 3 (i64.load32_u (i64.const 0)))
+          )
+        )
+        (if (i32.eq (local.get 1) (i32.const 1))
+          (then
+            (i64.store32 align=1 (i64.const 0) (local.get 2))
+            (local.set 3 (i64.load32_u align=1 (i64.const 0)))
+          )
+        )
+        (if (i32.eq (local.get 1) (i32.const 2))
+          (then
+            (i64.store32 align=2 (i64.const 0) (local.get 2))
+            (local.set 3 (i64.load32_u align=2 (i64.const 0)))
+          )
+        )
+        (if (i32.eq (local.get 1) (i32.const 4))
+          (then
+            (i64.store32 align=4 (i64.const 0) (local.get 2))
+            (local.set 3 (i64.load32_u align=4 (i64.const 0)))
+          )
+        )
+        (br $64)
+      ) ;; 32u
+      (if (i32.eq (local.get 1) (i32.const 0))
+        (then
+          (i64.store (i64.const 0) (local.get 2))
+          (local.set 3 (i64.load (i64.const 0)))
+        )
+      )
+      (if (i32.eq (local.get 1) (i32.const 1))
+        (then
+          (i64.store align=1 (i64.const 0) (local.get 2))
+          (local.set 3 (i64.load align=1 (i64.const 0)))
+        )
+      )
+      (if (i32.eq (local.get 1) (i32.const 2))
+        (then
+          (i64.store align=2 (i64.const 0) (local.get 2))
+          (local.set 3 (i64.load align=2 (i64.const 0)))
+        )
+      )
+      (if (i32.eq (local.get 1) (i32.const 4))
+        (then
+          (i64.store align=4 (i64.const 0) (local.get 2))
+          (local.set 3 (i64.load align=4 (i64.const 0)))
+        )
+      )
+      (if (i32.eq (local.get 1) (i32.const 8))
+        (then
+          (i64.store align=8 (i64.const 0) (local.get 2))
+          (local.set 3 (i64.load align=8 (i64.const 0)))
+        )
+      )
+    ) ;; 64
+    (local.get 3)
+  )
+)
+
+(assert_return (invoke "f32_align_switch" (i32.const 0)) (f32.const 10.0))
+(assert_return (invoke "f32_align_switch" (i32.const 1)) (f32.const 10.0))
+(assert_return (invoke "f32_align_switch" (i32.const 2)) (f32.const 10.0))
+(assert_return (invoke "f32_align_switch" (i32.const 3)) (f32.const 10.0))
+
+(assert_return (invoke "f64_align_switch" (i32.const 0)) (f64.const 10.0))
+(assert_return (invoke "f64_align_switch" (i32.const 1)) (f64.const 10.0))
+(assert_return (invoke "f64_align_switch" (i32.const 2)) (f64.const 10.0))
+(assert_return (invoke "f64_align_switch" (i32.const 3)) (f64.const 10.0))
+(assert_return (invoke "f64_align_switch" (i32.const 4)) (f64.const 10.0))
+
+(assert_return (invoke "i32_align_switch" (i32.const 0) (i32.const 0)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 0) (i32.const 1)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 1) (i32.const 0)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 1) (i32.const 1)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 2) (i32.const 0)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 2) (i32.const 1)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 2) (i32.const 2)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 3) (i32.const 0)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 3) (i32.const 1)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 3) (i32.const 2)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 4) (i32.const 0)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 4) (i32.const 1)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 4) (i32.const 2)) (i32.const 10))
+(assert_return (invoke "i32_align_switch" (i32.const 4) (i32.const 4)) (i32.const 10))
+
+(assert_return (invoke "i64_align_switch" (i32.const 0) (i32.const 0)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 0) (i32.const 1)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 1) (i32.const 0)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 1) (i32.const 1)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 2) (i32.const 0)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 2) (i32.const 1)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 2) (i32.const 2)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 3) (i32.const 0)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 3) (i32.const 1)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 3) (i32.const 2)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 4) (i32.const 0)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 4) (i32.const 1)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 4) (i32.const 2)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 4) (i32.const 4)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 5) (i32.const 0)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 5) (i32.const 1)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 5) (i32.const 2)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 5) (i32.const 4)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 6) (i32.const 0)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 6) (i32.const 1)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 6) (i32.const 2)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 6) (i32.const 4)) (i64.const 10))
+(assert_return (invoke "i64_align_switch" (i32.const 6) (i32.const 8)) (i64.const 10))
+
+;; Test that an i64 store with 4-byte alignment that's 4 bytes out of bounds traps without storing anything
+
+(module
+  (memory i64 1)
+  (func (export "store") (param i64 i64)
+    (i64.store align=4 (local.get 0) (local.get 1))
+  )
+  (func (export "load") (param i64) (result i32)
+    (i32.load (local.get 0))
+  )
+)
+
+(assert_trap (invoke "store" (i64.const 65532) (i64.const -1)) "out of bounds memory access")
+;; No memory was changed
+(assert_return (invoke "load" (i64.const 65532)) (i32.const 0))
diff --git a/binaryen/test/spec/atomics.wast b/binaryen/test/spec/atomics.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/atomics.wast
@@ -0,0 +1,8 @@
+(module
+  (memory $0 (shared 23 256))
+  (func (export "atomic-fence")
+    (atomic.fence)
+  )
+)
+
+(assert_return (invoke "atomic-fence"))
diff --git a/binaryen/test/spec/binary-leb128.wast b/binaryen/test/spec/binary-leb128.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/binary-leb128.wast
@@ -0,0 +1,963 @@
+;; Unsigned LEB128 can have non-minimal length
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\05\04\01"                          ;; Memory section with 1 entry
+  "\00\82\00"                          ;; no max, minimum 2
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\05\07\01"                          ;; Memory section with 1 entry
+  "\00\82\80\80\80\00"                 ;; no max, minimum 2
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\05\06\01"                          ;; Memory section with 1 entry
+  "\01\82\00"                          ;; minimum 2
+  "\82\00"                             ;; max 2
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\05\09\01"                          ;; Memory section with 1 entry
+  "\01\82\00"                          ;; minimum 2
+  "\82\80\80\80\00"                    ;; max 2
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\05\03\01"                          ;; Memory section with 1 entry
+  "\00\00"                             ;; no max, minimum 0
+  "\0b\07\01"                          ;; Data section with 1 entry
+  "\80\00"                             ;; Memory index 0, encoded with 2 bytes
+  "\41\00\0b\00"                       ;; (i32.const 0) with contents ""
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\04\04\01"                          ;; Table section with 1 entry
+  "\70\00\00"                          ;; no max, minimum 0, funcref
+  "\09\07\01"                          ;; Element section with 1 entry
+  "\80\00"                             ;; Table index 0, encoded with 2 bytes
+  "\41\00\0b\00"                       ;; (i32.const 0) with no elements
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\00"                                ;; custom section
+  "\8a\00"                             ;; section size 10, encoded with 2 bytes
+  "\01"                                ;; name byte count
+  "1"                                  ;; name
+  "23456789"                           ;; sequence of bytes
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\00"                                ;; custom section
+  "\0b"                                ;; section size
+  "\88\00"                             ;; name byte count 8, encoded with 2 bytes
+  "12345678"                           ;; name
+  "9"                                  ;; sequence of bytes
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\08\01"                          ;; type section
+  "\60"                                ;; func type
+  "\82\00"                             ;; num params 2, encoded with 2 bytes
+  "\7f\7e"                             ;; param type
+  "\01"                                ;; num results
+  "\7f"                                ;; result type
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\08\01"                          ;; type section
+  "\60"                                ;; func type
+  "\02"                                ;; num params
+  "\7f\7e"                             ;; param type
+  "\81\00"                             ;; num results 1, encoded with 2 bytes
+  "\7f"                                ;; result type
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\05\01"                          ;; type section
+  "\60\01\7f\00"                       ;; function type
+  "\02\17\01"                          ;; import section
+  "\88\00"                             ;; module name length 8, encoded with 2 bytes
+  "\73\70\65\63\74\65\73\74"           ;; module name
+  "\09"                                ;; entity name length
+  "\70\72\69\6e\74\5f\69\33\32"        ;; entity name
+  "\00"                                ;; import kind
+  "\00"                                ;; import signature index
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\05\01"                          ;; type section
+  "\60\01\7f\00"                       ;; function type
+  "\02\17\01"                          ;; import section
+  "\08"                                ;; module name length
+  "\73\70\65\63\74\65\73\74"           ;; module name
+  "\89\00"                             ;; entity name length 9, encoded with 2 bytes
+  "\70\72\69\6e\74\5f\69\33\32"        ;; entity name
+  "\00"                                ;; import kind
+  "\00"                                ;; import signature index
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\05\01"                          ;; type section
+  "\60\01\7f\00"                       ;; function type
+  "\02\17\01"                          ;; import section
+  "\08"                                ;; module name length
+  "\73\70\65\63\74\65\73\74"           ;; module name
+  "\09"                                ;; entity name length 9
+  "\70\72\69\6e\74\5f\69\33\32"        ;; entity name
+  "\00"                                ;; import kind
+  "\80\00"                             ;; import signature index, encoded with 2 bytes
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\04\01"                          ;; type section
+  "\60\00\00"                          ;; function type
+  "\03\03\01"                          ;; function section
+  "\80\00"                             ;; function 0 signature index, encoded with 2 bytes
+  "\0a\04\01"                          ;; code section
+  "\02\00\0b"                          ;; function body
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\04\01"                          ;; type section
+  "\60\00\00"                          ;; fun type
+  "\03\02\01\00"                       ;; function section
+  "\07\07\01"                          ;; export section
+  "\82\00"                             ;; string length 2, encoded with 2 bytes
+  "\66\31"                             ;; export name f1
+  "\00"                                ;; export kind
+  "\00"                                ;; export func index
+  "\0a\04\01"                          ;; code section
+  "\02\00\0b"                          ;; function body
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\04\01"                          ;; type section
+  "\60\00\00"                          ;; fun type
+  "\03\02\01\00"                       ;; function section
+  "\07\07\01"                          ;; export section
+  "\02"                                ;; string length 2
+  "\66\31"                             ;; export name f1
+  "\00"                                ;; export kind
+  "\80\00"                             ;; export func index, encoded with 2 bytes
+  "\0a\04\01"                          ;; code section
+  "\02\00\0b"                          ;; function body
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\04\01"                          ;; type section
+  "\60\00\00"                          ;; fun type
+  "\03\02\01\00"                       ;; function section
+  "\0a"                                ;; code section
+  "\05"                                ;; section size
+  "\81\00"                             ;; num functions, encoded with 2 bytes
+  "\02\00\0b"                          ;; function body
+)
+
+;; Signed LEB128 can have non-minimal length
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\06\07\01"                          ;; Global section with 1 entry
+  "\7f\00"                             ;; i32, immutable
+  "\41\80\00"                          ;; i32.const 0
+  "\0b"                                ;; end
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\06\07\01"                          ;; Global section with 1 entry
+  "\7f\00"                             ;; i32, immutable
+  "\41\ff\7f"                          ;; i32.const -1
+  "\0b"                                ;; end
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\06\0a\01"                          ;; Global section with 1 entry
+  "\7f\00"                             ;; i32, immutable
+  "\41\80\80\80\80\00"                 ;; i32.const 0
+  "\0b"                                ;; end
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\06\0a\01"                          ;; Global section with 1 entry
+  "\7f\00"                             ;; i32, immutable
+  "\41\ff\ff\ff\ff\7f"                 ;; i32.const -1
+  "\0b"                                ;; end
+)
+
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\06\07\01"                          ;; Global section with 1 entry
+  "\7e\00"                             ;; i64, immutable
+  "\42\80\00"                          ;; i64.const 0 with unused bits set
+  "\0b"                                ;; end
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\06\07\01"                          ;; Global section with 1 entry
+  "\7e\00"                             ;; i64, immutable
+  "\42\ff\7f"                          ;; i64.const -1 with unused bits unset
+  "\0b"                                ;; end
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\06\0f\01"                          ;; Global section with 1 entry
+  "\7e\00"                             ;; i64, immutable
+  "\42\80\80\80\80\80\80\80\80\80\00"  ;; i64.const 0 with unused bits set
+  "\0b"                                ;; end
+)
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\06\0f\01"                          ;; Global section with 1 entry
+  "\7e\00"                             ;; i64, immutable
+  "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\7f"  ;; i64.const -1 with unused bits unset
+  "\0b"                                ;; end
+)
+
+;; Unsigned LEB128 must not be overlong
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\05\08\01"                          ;; Memory section with 1 entry
+    "\00\82\80\80\80\80\00"              ;; no max, minimum 2 with one byte too many
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\05\0a\01"                          ;; Memory section with 1 entry
+    "\01\82\00"                          ;; minimum 2
+    "\82\80\80\80\80\00"                 ;; max 2 with one byte too many
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\05\03\01"                          ;; Memory section with 1 entry
+    "\00\00"                             ;; no max, minimum 0
+    "\0b\0b\01"                          ;; Data section with 1 entry
+    "\80\80\80\80\80\00"                 ;; Memory index 0 with one byte too many
+    "\41\00\0b\00"                       ;; (i32.const 0) with contents ""
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\04\04\01"                          ;; Table section with 1 entry
+    "\70\00\00"                          ;; no max, minimum 0, funcref
+    "\09\0b\01"                          ;; Element section with 1 entry
+    "\80\80\80\80\80\00"                 ;; Table index 0 with one byte too many
+    "\41\00\0b\00"                       ;; (i32.const 0) with no elements
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00"                                ;; custom section
+    "\83\80\80\80\80\00"                 ;; section size 3 with one byte too many
+    "\01"                                ;; name byte count
+    "1"                                  ;; name
+    "2"                                  ;; sequence of bytes
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00"                                ;; custom section
+    "\0A"                                ;; section size
+    "\83\80\80\80\80\00"                 ;; name byte count 3 with one byte too many
+    "123"                                ;; name
+    "4"                                  ;; sequence of bytes
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\0c\01"                          ;; type section
+    "\60"                                ;; func type
+    "\82\80\80\80\80\00"                 ;; num params 2 with one byte too many
+    "\7f\7e"                             ;; param type
+    "\01"                                ;; num result
+    "\7f"                                ;; result type
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\08\01"                          ;; type section
+    "\60"                                ;; func type
+    "\02"                                ;; num params
+    "\7f\7e"                             ;; param type
+    "\81\80\80\80\80\00"                 ;; num result 1 with one byte too many
+    "\7f"                                ;; result type
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\05\01"                          ;; type section
+    "\60\01\7f\00"                       ;; function type
+    "\02\1b\01"                          ;; import section
+    "\88\80\80\80\80\00"                 ;; module name length 8 with one byte too many
+    "\73\70\65\63\74\65\73\74"           ;; module name
+    "\09"                                ;; entity name length
+    "\70\72\69\6e\74\5f\69\33\32"        ;; entity name
+    "\00"                                ;; import kind
+    "\00"                                ;; import signature index
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\05\01"                          ;; type section
+    "\60\01\7f\00"                       ;; function type
+    "\02\1b\01"                          ;; import section
+    "\08"                                ;; module name length
+    "\73\70\65\63\74\65\73\74"           ;; module name
+    "\89\80\80\80\80\00"                 ;; entity name length 9 with one byte too many
+    "\70\72\69\6e\74\5f\69\33\32"        ;; entity name
+    "\00"                                ;; import kind
+    "\00"                                ;; import signature index
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\05\01"                          ;; type section
+    "\60\01\7f\00"                       ;; function type
+    "\02\1b\01"                          ;; import section
+    "\08"                                ;; module name length
+    "\73\70\65\63\74\65\73\74"           ;; module name
+    "\09"                                ;; entity name length 9
+    "\70\72\69\6e\74\5f\69\33\32"        ;; entity name
+    "\00"                                ;; import kind
+    "\80\80\80\80\80\00"                 ;; import signature index 0 with one byte too many
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01"                          ;; type section
+    "\60\00\00"                          ;; function type
+    "\03\03\01"                          ;; function section
+    "\80\80\80\80\80\00"                 ;; function 0 signature index with one byte too many
+    "\0a\04\01"                          ;; code section
+    "\02\00\0b"                          ;; function body
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01"                          ;; type section
+    "\60\00\00"                          ;; fun type
+    "\03\02\01\00"                       ;; function section
+    "\07\0b\01"                          ;; export section
+    "\82\80\80\80\80\00"                 ;; string length 2 with one byte too many
+    "\66\31"                             ;; export name f1
+    "\00"                                ;; export kind
+    "\00"                                ;; export func index
+    "\0a\04\01"                          ;; code section
+    "\02\00\0b"                          ;; function body
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01"                          ;; type section
+    "\60\00\00"                          ;; fun type
+    "\03\02\01\00"                       ;; function section
+    "\07\0b\01"                          ;; export section
+    "\02"                                ;; string length 2
+    "\66\31"                             ;; export name f1
+    "\00"                                ;; export kind
+    "\80\80\80\80\80\00"                 ;; export func index 0 with one byte too many
+    "\0a\04\01"                          ;; code section
+    "\02\00\0b"                          ;; function body
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01"                          ;; type section
+    "\60\00\00"                          ;; fun type
+    "\03\02\01\00"                       ;; function section
+    "\0a"                                ;; code section
+    "\05"                                ;; section size
+    "\81\80\80\80\80\00"                 ;; num functions 1 with one byte too many
+    "\02\00\0b"                          ;; function body
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\01"          ;; Memory section
+    "\0a\11\01"                ;; Code section
+    ;; function 0
+    "\0f\01\01"                ;; local type count
+    "\7f"                      ;; i32
+    "\41\00"                   ;; i32.const 0
+    "\28"                      ;; i32.load
+    "\02"                      ;; alignment 2
+    "\82\80\80\80\80\00"       ;; offset 2 with one byte too many
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\01"          ;; Memory section
+    "\0a\11\01"                ;; Code section
+    ;; function 0
+    "\0f\01\01"                ;; local type count
+    "\7f"                      ;; i32
+    "\41\00"                   ;; i32.const 0
+    "\28"                      ;; i32.load
+    "\82\80\80\80\80\00"       ;; alignment 2 with one byte too many
+    "\00"                      ;; offset 0
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\01"          ;; Memory section
+    "\0a\12\01"                ;; Code section
+    ;; function 0
+    "\10\01\01"                ;; local type count
+    "\7f"                      ;; i32
+    "\41\00"                   ;; i32.const 0
+    "\41\03"                   ;; i32.const 3
+    "\36"                      ;; i32.store
+    "\82\80\80\80\80\00"       ;; alignment 2 with one byte too many
+    "\03"                      ;; offset 3
+    "\0b"                      ;; end
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\01"          ;; Memory section
+    "\0a\12\01"                ;; Code section
+    ;; function 0
+    "\10\01\01"                ;; local type count
+    "\7f"                      ;; i32
+    "\41\00"                   ;; i32.const 0
+    "\41\03"                   ;; i32.const 3
+    "\36"                      ;; i32.store
+    "\02"                      ;; alignment 2
+    "\82\80\80\80\80\00"       ;; offset 2 with one byte too many
+    "\0b"                      ;; end
+  )
+  "integer representation too long"
+)
+
+;; Signed LEB128 must not be overlong
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\0b\01"                          ;; Global section with 1 entry
+    "\7f\00"                             ;; i32, immutable
+    "\41\80\80\80\80\80\00"              ;; i32.const 0 with one byte too many
+    "\0b"                                ;; end
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\0b\01"                          ;; Global section with 1 entry
+    "\7f\00"                             ;; i32, immutable
+    "\41\ff\ff\ff\ff\ff\7f"              ;; i32.const -1 with one byte too many
+    "\0b"                                ;; end
+  )
+  "integer representation too long"
+)
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\10\01"                          ;; Global section with 1 entry
+    "\7e\00"                             ;; i64, immutable
+    "\42\80\80\80\80\80\80\80\80\80\80\00"  ;; i64.const 0 with one byte too many
+    "\0b"                                ;; end
+  )
+  "integer representation too long"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\10\01"                          ;; Global section with 1 entry
+    "\7e\00"                             ;; i64, immutable
+    "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\7f"  ;; i64.const -1 with one byte too many
+    "\0b"                                ;; end
+  )
+  "integer representation too long"
+)
+
+;; Unsigned LEB128s zero-extend
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\05\07\01"                          ;; Memory section with 1 entry
+    "\00\82\80\80\80\70"                 ;; no max, minimum 2 with unused bits set
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\05\07\01"                          ;; Memory section with 1 entry
+    "\00\82\80\80\80\40"                 ;; no max, minimum 2 with some unused bits set
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\05\09\01"                          ;; Memory section with 1 entry
+    "\01\82\00"                          ;; minimum 2
+    "\82\80\80\80\10"                    ;; max 2 with unused bits set
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\05\09\01"                          ;; Memory section with 1 entry
+    "\01\82\00"                          ;; minimum 2
+    "\82\80\80\80\40"                    ;; max 2 with some unused bits set
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\05\03\01"                          ;; Memory section with 1 entry
+    "\00\00"                             ;; no max, minimum 0
+    "\0b\0a\01"                          ;; Data section with 1 entry
+    "\80\80\80\80\10"                    ;; Memory index 0 with unused bits set
+    "\41\00\0b\00"                       ;; (i32.const 0) with contents ""
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\04\04\01"                          ;; Table section with 1 entry
+    "\70\00\00"                          ;; no max, minimum 0, funcref
+    "\09\0a\01"                          ;; Element section with 1 entry
+    "\80\80\80\80\10"                    ;; Table index 0 with unused bits set
+    "\41\00\0b\00"                       ;; (i32.const 0) with no elements
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00"                                ;; custom section
+    "\83\80\80\80\10"                    ;; section size 3 with unused bits set
+    "\01"                                ;; name byte count
+    "1"                                  ;; name
+    "2"                                  ;; sequence of bytes
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00"                                ;; custom section
+    "\09"                                ;; section size
+    "\83\80\80\80\40"                    ;; name byte count 3 with unused bits set
+    "123"                                ;; name
+    "4"                                  ;; sequence of bytes
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\0b\01"                          ;; type section
+    "\60"                                ;; func type
+    "\82\80\80\80\10"                    ;; num params 2 with unused bits set
+    "\7f\7e"                             ;; param type
+    "\01"                                ;; num result
+    "\7f"                                ;; result type
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\0b\01"                          ;; type section
+    "\60"                                ;; func type
+    "\02"                                ;; num params
+    "\7f\7e"                             ;; param type
+    "\81\80\80\80\40"                    ;; num result 1 with unused bits set
+    "\7f"                                ;; result type
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\05\01"                          ;; type section
+    "\60\01\7f\00"                       ;; function type
+    "\02\1a\01"                          ;; import section
+    "\88\80\80\80\10"                    ;; module name length 8 with unused bits set
+    "\73\70\65\63\74\65\73\74"           ;; module name
+    "\09"                                ;; entity name length
+    "\70\72\69\6e\74\5f\69\33\32"        ;; entity name
+    "\00"                                ;; import kind
+    "\00"                                ;; import signature index
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\05\01"                          ;; type section
+    "\60\01\7f\00"                       ;; function type
+    "\02\1a\01"                          ;; import section
+    "\08"                                ;; module name length
+    "\73\70\65\63\74\65\73\74"           ;; module name
+    "\89\80\80\80\40"                    ;; entity name length 9 with unused bits set
+    "\70\72\69\6e\74\5f\69\33\32"        ;; entity name
+    "\00"                                ;; import kind
+    "\00"                                ;; import signature index
+  )
+  "integer too large"
+)
+(assert_malformed
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\05\01"                          ;; type section
+  "\60\01\7f\00"                       ;; function type
+  "\02\1a\01"                          ;; import section
+  "\08"                                ;; module name length
+  "\73\70\65\63\74\65\73\74"           ;; module name
+  "\09"                                ;; entity name length 9
+  "\70\72\69\6e\74\5f\69\33\32"        ;; entity name
+  "\00"                                ;; import kind
+  "\80\80\80\80\10"                    ;; import signature index 0 with unused bits set
+)
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01"                          ;; type section
+    "\60\00\00"                          ;; function type
+    "\03\06\01"                          ;; function section
+    "\80\80\80\80\10"                    ;; function 0 signature index with unused bits set
+    "\0a\04\01"                          ;; code section
+    "\02\00\0b"                          ;; function body
+  )
+  "integer too large"
+)
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01"                          ;; type section
+    "\60\00\00"                          ;; fun type
+    "\03\02\01\00"                       ;; function section
+    "\07\0a\01"                          ;; export section
+    "\82\80\80\80\10"                    ;; string length 2 with unused bits set
+    "\66\31"                             ;; export name f1
+    "\00"                                ;; export kind
+    "\00"                                ;; export func index
+    "\0a\04\01"                          ;; code section
+    "\02\00\0b"                          ;; function body
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01"                          ;; type section
+    "\60\00\00"                          ;; fun type
+    "\03\02\01\00"                       ;; function section
+    "\07\0a\01"                          ;; export section
+    "\02"                                ;; string length 2
+    "\66\31"                             ;; export name f1
+    "\00"                                ;; export kind
+    "\80\80\80\80\10"                    ;; export func index with unused bits set
+    "\0a\04\01"                          ;; code section
+    "\02\00\0b"                          ;; function body
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01"                          ;; type section
+    "\60\00\00"                          ;; fun type
+    "\03\02\01\00"                       ;; function section
+    "\0a"                                ;; code section
+    "\08"                                ;; section size
+    "\81\80\80\80\10"                    ;; num functions 1 with unused bits set
+    "\02\00\0b"                          ;; function body
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\01"          ;; Memory section
+    "\0a\10\01"                ;; Code section
+    ;; function 0
+    "\0e\01\01"                ;; local type count
+    "\7f"                      ;; i32
+    "\41\00"                   ;; i32.const 0
+    "\28"                      ;; i32.load
+    "\02"                      ;; alignment 2
+    "\82\80\80\80\10"          ;; offset 2 with unused bits set
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\01"          ;; Memory section
+    "\0a\10\01"                ;; Code section
+    ;; function 0
+    "\0e\01\01"                ;; local type count
+    "\7f"                      ;; i32
+    "\41\00"                   ;; i32.const 0
+    "\28"                      ;; i32.load
+    "\02"                      ;; alignment 2
+    "\82\80\80\80\40"          ;; offset 2 with some unused bits set
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\01"          ;; Memory section
+    "\0a\10\01"                ;; Code section
+    "\0e\01\01"                ;; local type count
+    "\7f"                      ;; i32
+    "\41\00"                   ;; i32.const 0
+    "\28"                      ;; i32.load
+    "\82\80\80\80\10"          ;; alignment 2 with unused bits set
+    "\00"                      ;; offset 0
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\01"          ;; Memory section
+    "\0a\10\01"                ;; Code section
+    ;; function 0
+    "\0e\01\01"                ;; local type count
+    "\7f"                      ;; i32
+    "\41\00"                   ;; i32.const 0
+    "\28"                      ;; i32.load
+    "\82\80\80\80\40"          ;; alignment 2 with some unused bits set
+    "\00"                      ;; offset 0
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\01"          ;; Memory section
+    "\0a\11\01"                ;; Code section
+    ;; function 0
+    "\0f\01\01"                ;; local type count
+    "\7f"                      ;; i32
+    "\41\00"                   ;; i32.const 0
+    "\41\03"                   ;; i32.const 3
+    "\36"                      ;; i32.store
+    "\82\80\80\80\10"          ;; alignment 2 with unused bits set
+    "\03"                      ;; offset 3
+    "\0b"                      ;; end
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\01"          ;; Memory section
+    "\0a\11\01"                ;; Code section
+    ;; function 0
+    "\0f\01\01"                ;; local type count
+    "\7f"                      ;; i32
+    "\41\00"                   ;; i32.const 0
+    "\41\03"                   ;; i32.const 3
+    "\36"                      ;; i32.store
+    "\82\80\80\80\40"          ;; alignment 2 with some unused bits set
+    "\03"                      ;; offset 3
+    "\0b"                      ;; end
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\01"          ;; Memory section
+    "\0a\11\01"                ;; Code section
+    ;; function 0
+    "\0f\01\01"                ;; local type count
+    "\7f"                      ;; i32
+    "\41\00"                   ;; i32.const 0
+    "\41\03"                   ;; i32.const 3
+    "\36"                      ;; i32.store
+    "\03"                      ;; alignment 2
+    "\82\80\80\80\10"          ;; offset 2 with unused bits set
+    "\0b"                      ;; end
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\01"          ;; Memory section
+    "\0a\11\01"                ;; Code section
+
+    ;; function 0
+    "\0f\01\01"                ;; local type count
+    "\7f"                      ;; i32
+    "\41\00"                   ;; i32.const 0
+    "\41\03"                   ;; i32.const 3
+    "\36"                      ;; i32.store
+    "\02"                      ;; alignment 2
+    "\82\80\80\80\40"          ;; offset 2 with some unused bits set
+    "\0b"                      ;; end
+  )
+  "integer too large"
+)
+
+;; Signed LEB128s sign-extend
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\0a\01"                          ;; Global section with 1 entry
+    "\7f\00"                             ;; i32, immutable
+    "\41\80\80\80\80\70"                 ;; i32.const 0 with unused bits set
+    "\0b"                                ;; end
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\0a\01"                          ;; Global section with 1 entry
+    "\7f\00"                             ;; i32, immutable
+    "\41\ff\ff\ff\ff\0f"                 ;; i32.const -1 with unused bits unset
+    "\0b"                                ;; end
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\0a\01"                          ;; Global section with 1 entry
+    "\7f\00"                             ;; i32, immutable
+    "\41\80\80\80\80\1f"                 ;; i32.const 0 with some unused bits set
+    "\0b"                                ;; end
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\0a\01"                          ;; Global section with 1 entry
+    "\7f\00"                             ;; i32, immutable
+    "\41\ff\ff\ff\ff\4f"                 ;; i32.const -1 with some unused bits unset
+    "\0b"                                ;; end
+  )
+  "integer too large"
+)
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\0f\01"                          ;; Global section with 1 entry
+    "\7e\00"                             ;; i64, immutable
+    "\42\80\80\80\80\80\80\80\80\80\7e"  ;; i64.const 0 with unused bits set
+    "\0b"                                ;; end
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\0f\01"                          ;; Global section with 1 entry
+    "\7e\00"                             ;; i64, immutable
+    "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\01"  ;; i64.const -1 with unused bits unset
+    "\0b"                                ;; end
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\0f\01"                          ;; Global section with 1 entry
+    "\7e\00"                             ;; i64, immutable
+    "\42\80\80\80\80\80\80\80\80\80\02"  ;; i64.const 0 with some unused bits set
+    "\0b"                                ;; end
+  )
+  "integer too large"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\0f\01"                          ;; Global section with 1 entry
+    "\7e\00"                             ;; i64, immutable
+    "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\41"  ;; i64.const -1 with some unused bits unset
+    "\0b"                                ;; end
+  )
+  "integer too large"
+)
diff --git a/binaryen/test/spec/binary.wast b/binaryen/test/spec/binary.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/binary.wast
@@ -0,0 +1,811 @@
+(module binary "\00asm\01\00\00\00")
+(module binary "\00asm" "\01\00\00\00")
+(module $M1 binary "\00asm\01\00\00\00")
+(module $M2 binary "\00asm" "\01\00\00\00")
+
+(assert_malformed (module binary "") "unexpected end")
+(assert_malformed (module binary "\01") "unexpected end")
+(assert_malformed (module binary "\00as") "unexpected end")
+(assert_malformed (module binary "asm\00") "magic header not detected")
+(assert_malformed (module binary "msa\00") "magic header not detected")
+(assert_malformed (module binary "msa\00\01\00\00\00") "magic header not detected")
+(assert_malformed (module binary "msa\00\00\00\00\01") "magic header not detected")
+(assert_malformed (module binary "asm\01\00\00\00\00") "magic header not detected")
+(assert_malformed (module binary "wasm\01\00\00\00") "magic header not detected")
+(assert_malformed (module binary "\7fasm\01\00\00\00") "magic header not detected")
+(assert_malformed (module binary "\80asm\01\00\00\00") "magic header not detected")
+(assert_malformed (module binary "\82asm\01\00\00\00") "magic header not detected")
+(assert_malformed (module binary "\ffasm\01\00\00\00") "magic header not detected")
+
+;; 8-byte endian-reversed.
+(assert_malformed (module binary "\00\00\00\01msa\00") "magic header not detected")
+
+;; Middle-endian byte orderings.
+(assert_malformed (module binary "a\00ms\00\01\00\00") "magic header not detected")
+(assert_malformed (module binary "sm\00a\00\00\01\00") "magic header not detected")
+
+;; Upper-cased.
+(assert_malformed (module binary "\00ASM\01\00\00\00") "magic header not detected")
+
+;; EBCDIC-encoded magic.
+(assert_malformed (module binary "\00\81\a2\94\01\00\00\00") "magic header not detected")
+
+;; Leading UTF-8 BOM.
+(assert_malformed (module binary "\ef\bb\bf\00asm\01\00\00\00") "magic header not detected")
+
+;; Malformed binary version.
+(assert_malformed (module binary "\00asm") "unexpected end")
+(assert_malformed (module binary "\00asm\01") "unexpected end")
+(assert_malformed (module binary "\00asm\01\00\00") "unexpected end")
+(assert_malformed (module binary "\00asm\00\00\00\00") "unknown binary version")
+(assert_malformed (module binary "\00asm\0d\00\00\00") "unknown binary version")
+(assert_malformed (module binary "\00asm\0e\00\00\00") "unknown binary version")
+(assert_malformed (module binary "\00asm\00\01\00\00") "unknown binary version")
+(assert_malformed (module binary "\00asm\00\00\01\00") "unknown binary version")
+(assert_malformed (module binary "\00asm\00\00\00\01") "unknown binary version")
+
+
+;; call_indirect reserved byte equal to zero.
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"      ;; Type section
+    "\03\02\01\00"            ;; Function section
+    "\04\04\01\70\00\00"      ;; Table section
+    "\0a\09\01"               ;; Code section
+
+    ;; function 0
+    "\07\00"
+    "\41\00"                   ;; i32.const 0
+    "\11\00"                   ;; call_indirect (type 0)
+    "\01"                      ;; call_indirect reserved byte is not equal to zero!
+    "\0b"                      ;; end
+  )
+  "zero flag expected"
+)
+
+;; call_indirect reserved byte should not be a "long" LEB128 zero.
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"      ;; Type section
+    "\03\02\01\00"            ;; Function section
+    "\04\04\01\70\00\00"      ;; Table section
+    "\0a\0a\01"               ;; Code section
+
+    ;; function 0
+    "\07\00"
+    "\41\00"                   ;; i32.const 0
+    "\11\00"                   ;; call_indirect (type 0)
+    "\80\00"                   ;; call_indirect reserved byte
+    "\0b"                      ;; end
+  )
+  "zero flag expected"
+)
+
+;; Same as above for 3, 4, and 5-byte zero encodings.
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"      ;; Type section
+    "\03\02\01\00"            ;; Function section
+    "\04\04\01\70\00\00"      ;; Table section
+    "\0a\0b\01"               ;; Code section
+
+    ;; function 0
+    "\08\00"
+    "\41\00"                   ;; i32.const 0
+    "\11\00"                   ;; call_indirect (type 0)
+    "\80\80\00"                ;; call_indirect reserved byte
+    "\0b"                      ;; end
+  )
+  "zero flag expected"
+)
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"      ;; Type section
+    "\03\02\01\00"            ;; Function section
+    "\04\04\01\70\00\00"      ;; Table section
+    "\0a\0c\01"               ;; Code section
+
+    ;; function 0
+    "\09\00"
+    "\41\00"                   ;; i32.const 0
+    "\11\00"                   ;; call_indirect (type 0)
+    "\80\80\80\00"             ;; call_indirect reserved byte
+    "\0b"                      ;; end
+  )
+  "zero flag expected"
+)
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"      ;; Type section
+    "\03\02\01\00"            ;; Function section
+    "\04\04\01\70\00\00"      ;; Table section
+    "\0a\0d\01"               ;; Code section
+
+    ;; function 0
+    "\0a\00"
+    "\41\00"                   ;; i32.const 0
+    "\11\00"                   ;; call_indirect (type 0)
+    "\80\80\80\80\00"          ;; call_indirect reserved byte
+    "\0b"                      ;; end
+  )
+  "zero flag expected"
+)
+
+;; memory.grow reserved byte equal to zero.
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\00"          ;; Memory section
+    "\0a\09\01"                ;; Code section
+
+    ;; function 0
+    "\07\00"
+    "\41\00"                   ;; i32.const 0
+    "\40"                      ;; memory.grow
+    "\01"                      ;; memory.grow reserved byte is not equal to zero!
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "zero flag expected"
+)
+
+;; memory.grow reserved byte should not be a "long" LEB128 zero.
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\00"          ;; Memory section
+    "\0a\0a\01"                ;; Code section
+
+    ;; function 0
+    "\08\00"
+    "\41\00"                   ;; i32.const 0
+    "\40"                      ;; memory.grow
+    "\80\00"                   ;; memory.grow reserved byte
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "zero flag expected"
+)
+
+;; Same as above for 3, 4, and 5-byte zero encodings.
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\00"          ;; Memory section
+    "\0a\0b\01"                ;; Code section
+
+    ;; function 0
+    "\09\00"
+    "\41\00"                   ;; i32.const 0
+    "\40"                      ;; memory.grow
+    "\80\80\00"                ;; memory.grow reserved byte
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "zero flag expected"
+)
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\00"          ;; Memory section
+    "\0a\0c\01"                ;; Code section
+
+    ;; function 0
+    "\0a\00"
+    "\41\00"                   ;; i32.const 0
+    "\40"                      ;; memory.grow
+    "\80\80\80\00"             ;; memory.grow reserved byte
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "zero flag expected"
+)
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\00"          ;; Memory section
+    "\0a\0d\01"                ;; Code section
+
+    ;; function 0
+    "\0b\00"
+    "\41\00"                   ;; i32.const 0
+    "\40"                      ;; memory.grow
+    "\80\80\80\80\00"          ;; memory.grow reserved byte
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "zero flag expected"
+)
+
+;; memory.size reserved byte equal to zero.
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\00"          ;; Memory section
+    "\0a\07\01"                ;; Code section
+
+    ;; function 0
+    "\05\00"
+    "\3f"                      ;; memory.size
+    "\01"                      ;; memory.size reserved byte is not equal to zero!
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "zero flag expected"
+)
+
+;; memory.size reserved byte should not be a "long" LEB128 zero.
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\00"          ;; Memory section
+    "\0a\08\01"                ;; Code section
+
+    ;; function 0
+    "\06\00"
+    "\3f"                      ;; memory.size
+    "\80\00"                   ;; memory.size reserved byte
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "zero flag expected"
+)
+
+;; Same as above for 3, 4, and 5-byte zero encodings.
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\00"          ;; Memory section
+    "\0a\09\01"                ;; Code section
+
+    ;; function 0
+    "\07\00"
+    "\3f"                      ;; memory.size
+    "\80\80\00"                ;; memory.size reserved byte
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "zero flag expected"
+)
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\00"          ;; Memory section
+    "\0a\0a\01"                ;; Code section
+
+    ;; function 0
+    "\08\00"
+    "\3f"                      ;; memory.size
+    "\80\80\80\00"             ;; memory.size reserved byte
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "zero flag expected"
+)
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\00"          ;; Memory section
+    "\0a\0b\01"                ;; Code section
+
+    ;; function 0
+    "\09\00"
+    "\3f"                      ;; memory.size
+    "\80\80\80\80\00"          ;; memory.size reserved byte
+    "\1a"                      ;; drop
+    "\0b"                      ;; end
+  )
+  "zero flag expected"
+)
+
+;; No more than 2^32 locals.
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\0a\0c\01"                ;; Code section
+
+    ;; function 0
+    "\0a\02"
+    "\ff\ff\ff\ff\0f\7f"       ;; 0xFFFFFFFF i32
+    "\02\7e"                   ;; 0x00000002 i64
+    "\0b"                      ;; end
+  )
+  "too many locals"
+)
+
+;; Local count can be 0.
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\04\01\60\00\00"     ;; Type section
+  "\03\02\01\00"           ;; Function section
+  "\0a\0a\01"              ;; Code section
+
+  ;; function 0
+  "\08\03"
+  "\00\7f"                 ;; 0 i32
+  "\00\7e"                 ;; 0 i64
+  "\02\7d"                 ;; 2 f32
+  "\0b"                    ;; end
+)
+
+;; Function section has non-zero count, but code section is absent.
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"  ;; Type section
+    "\03\03\02\00\00"     ;; Function section with 2 functions
+  )
+  "function and code section have inconsistent lengths"
+)
+
+;; Code section has non-zero count, but function section is absent.
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\0a\04\01\02\00\0b"  ;; Code section with 1 empty function
+  )
+  "function and code section have inconsistent lengths"
+)
+
+;; Function section count > code section count
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"  ;; Type section
+    "\03\03\02\00\00"     ;; Function section with 2 functions
+    "\0a\04\01\02\00\0b"  ;; Code section with 1 empty function
+  )
+  "function and code section have inconsistent lengths"
+)
+
+;; Function section count < code section count
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"           ;; Type section
+    "\03\02\01\00"                 ;; Function section with 1 function
+    "\0a\07\02\02\00\0b\02\00\0b"  ;; Code section with 2 empty functions
+  )
+  "function and code section have inconsistent lengths"
+)
+
+;; Function section has zero count, and code section is absent.
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\03\01\00"  ;; Function section with 0 functions
+)
+
+;; Code section has zero count, and function section is absent.
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\0a\01\00"  ;; Code section with 0 functions
+)
+
+;; Type count can be zero
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\01\00"                               ;; type count can be zero
+)
+
+;; 2 type declared, 1 given
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\07\02"                             ;; type section with inconsistent count (2 declared, 1 given)
+    "\60\00\00"                             ;; 1st type
+    ;; "\60\00\00"                          ;; 2nd type (missed)
+  )
+  "unexpected end of section or function"
+)
+
+;; 1 type declared, 2 given
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\07\01"                             ;; type section with inconsistent count (1 declared, 2 given)
+    "\60\00\00"                             ;; 1st type
+    "\60\00\00"                             ;; 2nd type (redundant)
+  )
+  "section size mismatch"
+)
+
+;; Import count can be zero
+(module binary
+    "\00asm" "\01\00\00\00"
+    "\01\05\01"                             ;; type section
+    "\60\01\7f\00"                          ;; type 0
+    "\02\01\00"                             ;; import count can be zero
+)
+
+;; 2 import declared, 1 given
+(assert_malformed
+  (module binary
+      "\00asm" "\01\00\00\00"
+      "\01\05\01"                           ;; type section
+      "\60\01\7f\00"                        ;; type 0
+      "\02\16\02"                           ;; import section with inconsistent count (2 declared, 1 given)
+      ;; 1st import
+      "\08"                                 ;; string length
+      "\73\70\65\63\74\65\73\74"            ;; spectest
+      "\09"                                 ;; string length
+      "\70\72\69\6e\74\5f\69\33\32"         ;; print_i32
+      "\00\00"                              ;; import kind, import signature index
+      ;; 2nd import
+      ;; (missed)
+  )
+  "unexpected end of section or function"
+)
+
+;; 1 import declared, 2 given
+(assert_malformed
+  (module binary
+      "\00asm" "\01\00\00\00"
+      "\01\09\02"                           ;; type section
+      "\60\01\7f\00"                        ;; type 0
+      "\60\01\7d\00"                        ;; type 1
+      "\02\2b\01"                           ;; import section with inconsistent count (1 declared, 2 given)
+      ;; 1st import
+      "\08"                                 ;; string length
+      "\73\70\65\63\74\65\73\74"            ;; spectest
+      "\09"                                 ;; string length
+      "\70\72\69\6e\74\5f\69\33\32"         ;; print_i32
+      "\00\00"                              ;; import kind, import signature index
+      ;; 2nd import
+      ;; (redundant)
+      "\08"                                 ;; string length
+      "\73\70\65\63\74\65\73\74"            ;; spectest
+      "\09"                                 ;; string length
+      "\70\72\69\6e\74\5f\66\33\32"         ;; print_f32
+      "\00\01"                              ;; import kind, import signature index
+  )
+  "section size mismatch"
+)
+
+;; Table count can be zero
+(module binary
+    "\00asm" "\01\00\00\00"
+    "\04\01\00"                             ;; table count can be zero
+)
+
+;; 1 table declared, 0 given
+(assert_malformed
+  (module binary
+      "\00asm" "\01\00\00\00"
+      "\04\01\01"                           ;; table section with inconsistent count (1 declared, 0 given)
+      ;; "\70\01\00\00"                     ;; table entity
+  )
+  "unexpected end of section or function"
+)
+
+;; Memory count can be zero
+(module binary
+    "\00asm" "\01\00\00\00"
+    "\05\01\00"                             ;; memory count can be zero
+)
+
+;; 1 memory declared, 0 given
+(assert_malformed
+  (module binary
+      "\00asm" "\01\00\00\00"
+      "\05\01\01"                           ;; memory section with inconsistent count (1 declared, 0 given)
+      ;; "\00\00"                           ;; memory 0 (missed)
+  )
+  "unexpected end of section or function"
+)
+
+;; Global count can be zero
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\06\01\00"                               ;; global count can be zero
+)
+
+;; 2 global declared, 1 given
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\06\02"                             ;; global section with inconsistent count (2 declared, 1 given)
+    "\7f\00\41\00\0b"                       ;; global 0
+    ;; "\7f\00\41\00\0b"                    ;; global 1 (missed)
+  )
+  "unexpected end of section or function"
+)
+
+;; 1 global declared, 2 given
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\0b\01"                             ;; global section with inconsistent count (1 declared, 2 given)
+    "\7f\00\41\00\0b"                       ;; global 0
+    "\7f\00\41\00\0b"                       ;; global 1 (redundant)
+  )
+  "section size mismatch"
+)
+
+;; Export count can be 0
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\04\01"                               ;; type section
+  "\60\00\00"                               ;; type 0
+  "\03\03\02\00\00"                         ;; func section
+  "\07\01\00"                               ;; export count can be zero
+  "\0a\07\02"                               ;; code section
+  "\02\00\0b"                               ;; function body 0
+  "\02\00\0b"                               ;; function body 1
+)
+
+;; 2 export declared, 1 given
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01"                             ;; type section
+    "\60\00\00"                             ;; type 0
+    "\03\03\02\00\00"                       ;; func section
+    "\07\06\02"                             ;; export section with inconsistent count (2 declared, 1 given)
+    "\02"                                   ;; export 0
+    "\66\31"                                ;; export name
+    "\00\00"                                ;; export kind, export func index
+    ;; "\02"                                ;; export 1 (missed)
+    ;; "\66\32"                             ;; export name
+    ;; "\00\01"                             ;; export kind, export func index
+    "\0a\07\02"                             ;; code section
+    "\02\00\0b"                             ;; function body 0
+    "\02\00\0b"                             ;; function body 1
+  )
+  "unexpected end of section or function"
+)
+
+;; 1 export declared, 2 given
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01"                             ;; type section
+    "\60\00\00"                             ;; type 0
+    "\03\03\02\00\00"                       ;; func section
+    "\07\0b\01"                             ;; export section with inconsistent count (1 declared, 2 given)
+    "\02"                                   ;; export 0
+    "\66\31"                                ;; export name
+    "\00\00"                                ;; export kind, export func index
+    "\02"                                   ;; export 1 (redundant)
+    "\66\32"                                ;; export name
+    "\00\01"                                ;; export kind, export func index
+    "\0a\07\02"                             ;; code section
+    "\02\00\0b"                             ;; function body 0
+    "\02\00\0b"                             ;; function body 1
+  )
+  "section size mismatch"
+)
+
+;; elem segment count can be zero
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\04\01"                               ;; type section
+  "\60\00\00"                               ;; type 0
+  "\03\02\01\00"                            ;; func section
+  "\04\04\01"                               ;; table section
+  "\70\00\01"                               ;; table 0
+  "\09\01\00"                               ;; elem segment count can be zero
+  "\0a\04\01"                               ;; code section
+  "\02\00\0b"                               ;; function body
+)
+
+;; 2 elem segment declared, 1 given
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01"                             ;; type section
+    "\60\00\00"                             ;; type 0
+    "\03\02\01\00"                          ;; func section
+    "\04\04\01"                             ;; table section
+    "\70\00\01"                             ;; table 0
+    "\09\07\02"                             ;; elem with inconsistent segment count (2 declared, 1 given)
+    "\00\41\00\0b\01\00"                    ;; elem 0
+    ;; "\00\41\00\0b\01\00"                 ;; elem 1 (missed)
+    "\0a\04\01"                             ;; code section
+    "\02\00\0b"                             ;; function body
+  )
+  "invalid value type"
+)
+
+;; 1 elem segment declared, 2 given
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01"                             ;; type section
+    "\60\00\00"                             ;; type 0
+    "\03\02\01\00"                          ;; func section
+    "\04\04\01"                             ;; table section
+    "\70\00\01"                             ;; table 0
+    "\09\0d\01"                             ;; elem with inconsistent segment count (1 declared, 2 given)
+    "\00\41\00\0b\01\00"                    ;; elem 0
+    "\00\41\00\0b\01\00"                    ;; elem 1 (redundant)
+    "\0a\04\01"                             ;; code section
+    "\02\00\0b"                             ;; function body
+  )
+  "section size mismatch"
+)
+
+;; data segment count can be zero
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\05\03\01"                               ;; memory section
+  "\00\01"                                  ;; memory 0
+  "\0b\01\00"                               ;; data segment count can be zero
+)
+
+;; 2 data segment declared, 1 given
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\05\03\01"                             ;; memory section
+    "\00\01"                                ;; memory 0
+    "\0b\07\02"                             ;; data with inconsistent segment count (2 declared, 1 given)
+    "\00\41\00\0b\01\61"                    ;; data 0
+    ;; "\00\41\01\0b\01\62"                 ;; data 1 (missed)
+  )
+  "unexpected end of section or function"
+)
+
+;; 1 data segment declared, 2 given
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\05\03\01"                             ;; memory section
+    "\00\01"                                ;; memory 0
+    "\0b\0d\01"                             ;; data with inconsistent segment count (1 declared, 2 given)
+    "\00\41\00\0b\01\61"                    ;; data 0
+    "\00\41\01\0b\01\62"                    ;; data 1 (redundant)
+  )
+  "section size mismatch"
+)
+
+;; data segment has 7 bytes declared, but 6 bytes given
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\05\03\01"                             ;; memory section
+    "\00\01"                                ;; memory 0
+    "\0b\0c\01"                             ;; data section
+    "\00\41\03\0b"                          ;; data segment 0
+    "\07"                                   ;; data segment size with inconsistent lengths (7 declared, 6 given)
+    "\61\62\63\64\65\66"                    ;; 6 bytes given
+  )
+  "unexpected end of section or function"
+)
+
+;; data segment has 5 bytes declared, but 6 bytes given
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\05\03\01"                             ;; memory section
+    "\00\01"                                ;; memory 0
+    "\0b\0c\01"                             ;; data section
+    "\00\41\00\0b"                          ;; data segment 0
+    "\05"                                   ;; data segment size with inconsistent lengths (5 declared, 6 given)
+    "\61\62\63\64\65\66"                    ;; 6 bytes given
+  )
+  "section size mismatch"
+)
+
+;; br_table target count can be zero
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\04\01"                               ;; type section
+  "\60\00\00"                               ;; type 0
+  "\03\02\01\00"                            ;; func section
+  "\0a\11\01"                               ;; code section
+  "\0f\00"                                  ;; func 0
+  "\02\40"                                  ;; block 0
+  "\41\01"                                  ;; condition of if 0
+  "\04\40"                                  ;; if 0
+  "\41\01"                                  ;; index of br_table element
+  "\0e\00"                                  ;; br_table target count can be zero
+  "\02"                                     ;; break depth for default
+  "\0b\0b\0b"                               ;; end
+)
+
+;; 2 br_table target declared, 1 given
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01"                             ;; type section
+    "\60\00\00"                             ;; type 0
+    "\03\02\01\00"                          ;; func section
+    "\0a\12\01"                             ;; code section
+    "\10\00"                                ;; func 0
+    "\02\40"                                ;; block 0
+    "\41\01"                                ;; condition of if 0
+    "\04\40"                                ;; if 0
+    "\41\01"                                ;; index of br_table element
+    "\0e\02"                                ;; br_table with inconsistent target count (2 declared, 1 given)
+    "\00"                                   ;; break depth 0
+    ;; "\01"                                ;; break depth 1 (missed)
+    "\02"                                   ;; break depth for default
+    "\0b\0b\0b"                             ;; end
+  )
+  "unexpected end of section or function"
+)
+
+;; 1 br_table target declared, 2 given
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01"                             ;; type section
+    "\60\00\00"                             ;; type 0
+    "\03\02\01\00"                          ;; func section
+    "\0a\12\01"                             ;; code section
+    "\11\00"                                ;; func 0
+    "\02\40"                                ;; block 0
+    "\41\01"                                ;; condition of if 0
+    "\04\40"                                ;; if 0
+    "\41\01"                                ;; index of br_table element
+    "\0e\01"                                ;; br_table with inconsistent target count (1 declared, 2 given)
+    "\00"                                   ;; break depth 0
+    "\01"                                   ;; break depth 1
+    "\02"                                   ;; break depth for default
+    "\0b\0b\0b"                             ;; end
+  )
+  "invalid value type"
+)
+
+;; Start section
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\04\01\60\00\00"       ;; Type section
+  "\03\02\01\00"             ;; Function section
+  "\08\01\00"                ;; Start section: function 0
+
+  "\0a\04\01"                ;; Code section
+  ;; function 0
+  "\02\00"
+  "\0b"                      ;; end
+)
+
+;; Multiple start sections
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\08\01\00"                ;; Start section: function 0
+    "\08\01\00"                ;; Start section: function 0
+
+    "\0a\04\01"                ;; Code section
+    ;; function 0
+    "\02\00"
+    "\0b"                      ;; end
+  )
+  "junk after last section"
+)
diff --git a/binaryen/test/spec/block.wast b/binaryen/test/spec/block.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/block.wast
@@ -0,0 +1,1120 @@
+;; Test `block` operator
+
+(module
+  ;; Auxiliary definition
+  (memory 1)
+
+  (func $dummy)
+
+  (func (export "empty")
+    (block)
+    (block $l)
+  )
+
+  (func (export "singular") (result i32)
+    (block (nop))
+    (block (result i32) (i32.const 7))
+  )
+
+  (func (export "multi") (result i32)
+    (block (call $dummy) (call $dummy) (call $dummy) (call $dummy))
+    (block (result i32) (call $dummy) (call $dummy) (call $dummy) (i32.const 8))
+  )
+
+  (func (export "nested") (result i32)
+    (block (result i32)
+      (block (call $dummy) (block) (nop))
+      (block (result i32) (call $dummy) (i32.const 9))
+    )
+  )
+
+  (func (export "deep") (result i32)
+    (block (result i32) (block (result i32)
+      (block (result i32) (block (result i32)
+        (block (result i32) (block (result i32)
+          (block (result i32) (block (result i32)
+            (block (result i32) (block (result i32)
+              (block (result i32) (block (result i32)
+                (block (result i32) (block (result i32)
+                  (block (result i32) (block (result i32)
+                    (block (result i32) (block (result i32)
+                      (block (result i32) (block (result i32)
+                        (block (result i32) (block (result i32)
+                          (block (result i32) (block (result i32)
+                            (block (result i32) (block (result i32)
+                              (block (result i32) (block (result i32)
+                                (block (result i32) (block (result i32)
+                                  (block (result i32) (block (result i32)
+                                    (block (result i32) (block (result i32)
+                                      (block (result i32) (block (result i32)
+                                        (block (result i32) (block (result i32)
+                                          (call $dummy) (i32.const 150)
+                                        ))
+                                      ))
+                                    ))
+                                  ))
+                                ))
+                              ))
+                            ))
+                          ))
+                        ))
+                      ))
+                    ))
+                  ))
+                ))
+              ))
+            ))
+          ))
+        ))
+      ))
+    ))
+  )
+
+  (func (export "as-select-first") (result i32)
+    (select (block (result i32) (i32.const 1)) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-select-mid") (result i32)
+    (select (i32.const 2) (block (result i32) (i32.const 1)) (i32.const 3))
+  )
+  (func (export "as-select-last") (result i32)
+    (select (i32.const 2) (i32.const 3) (block (result i32) (i32.const 1)))
+  )
+
+  (func (export "as-loop-first") (result i32)
+    (loop (result i32) (block (result i32) (i32.const 1)) (call $dummy) (call $dummy))
+  )
+  (func (export "as-loop-mid") (result i32)
+    (loop (result i32) (call $dummy) (block (result i32) (i32.const 1)) (call $dummy))
+  )
+  (func (export "as-loop-last") (result i32)
+    (loop (result i32) (call $dummy) (call $dummy) (block (result i32) (i32.const 1)))
+  )
+
+  (func (export "as-if-condition")
+    (block (result i32) (i32.const 1)) (if (then (call $dummy)))
+  )
+  (func (export "as-if-then") (result i32)
+    (if (result i32) (i32.const 1) (then (block (result i32) (i32.const 1))) (else (i32.const 2)))
+  )
+  (func (export "as-if-else") (result i32)
+    (if (result i32) (i32.const 1) (then (i32.const 2)) (else (block (result i32) (i32.const 1))))
+  )
+
+  (func (export "as-br_if-first") (result i32)
+    (block (result i32) (br_if 0 (block (result i32) (i32.const 1)) (i32.const 2)))
+  )
+  (func (export "as-br_if-last") (result i32)
+    (block (result i32) (br_if 0 (i32.const 2) (block (result i32) (i32.const 1))))
+  )
+
+  (func (export "as-br_table-first") (result i32)
+    (block (result i32) (block (result i32) (i32.const 1)) (i32.const 2) (br_table 0 0))
+  )
+  (func (export "as-br_table-last") (result i32)
+    (block (result i32) (i32.const 2) (block (result i32) (i32.const 1)) (br_table 0 0))
+  )
+
+  (func $func (param i32 i32) (result i32) (local.get 0))
+  (type $check (func (param i32 i32) (result i32)))
+  (table funcref (elem $func))
+  (func (export "as-call_indirect-first") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (block (result i32) (i32.const 1)) (i32.const 2) (i32.const 0)
+      )
+    )
+  )
+  (func (export "as-call_indirect-mid") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (i32.const 2) (block (result i32) (i32.const 1)) (i32.const 0)
+      )
+    )
+  )
+  (func (export "as-call_indirect-last") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (i32.const 1) (i32.const 2) (block (result i32) (i32.const 0))
+      )
+    )
+  )
+
+  (func (export "as-store-first")
+    (block (result i32) (i32.const 1)) (i32.const 1) (i32.store)
+  )
+  (func (export "as-store-last")
+    (i32.const 10) (block (result i32) (i32.const 1)) (i32.store)
+  )
+
+  (func (export "as-memory.grow-value") (result i32)
+    (memory.grow (block (result i32) (i32.const 1)))
+  )
+
+  (func $f (param i32) (result i32) (local.get 0))
+
+  (func (export "as-call-value") (result i32)
+    (call $f (block (result i32) (i32.const 1)))
+  )
+  (func (export "as-return-value") (result i32)
+    (block (result i32) (i32.const 1)) (return)
+  )
+  (func (export "as-drop-operand")
+    (drop (block (result i32) (i32.const 1)))
+  )
+  (func (export "as-br-value") (result i32)
+    (block (result i32) (br 0 (block (result i32) (i32.const 1))))
+  )
+  (func (export "as-local.set-value") (result i32)
+    (local i32) (local.set 0 (block (result i32) (i32.const 1))) (local.get 0)
+  )
+  (func (export "as-local.tee-value") (result i32)
+    (local i32) (local.tee 0 (block (result i32) (i32.const 1)))
+  )
+  (global $a (mut i32) (i32.const 10))
+  (func (export "as-global.set-value") (result i32)
+    (global.set $a (block (result i32) (i32.const 1)))
+    (global.get $a)
+  )
+
+  (func (export "as-load-operand") (result i32)
+    (i32.load (block (result i32) (i32.const 1)))
+  )
+
+  (func (export "as-unary-operand") (result i32)
+    (i32.ctz (block (result i32) (call $dummy) (i32.const 13)))
+  )
+  (func (export "as-binary-operand") (result i32)
+    (i32.mul
+      (block (result i32) (call $dummy) (i32.const 3))
+      (block (result i32) (call $dummy) (i32.const 4))
+    )
+  )
+  (func (export "as-test-operand") (result i32)
+    (i32.eqz (block (result i32) (call $dummy) (i32.const 13)))
+  )
+  (func (export "as-compare-operand") (result i32)
+    (f32.gt
+      (block (result f32) (call $dummy) (f32.const 3))
+      (block (result f32) (call $dummy) (f32.const 3))
+    )
+  )
+
+  (func (export "break-bare") (result i32)
+    (block (br 0) (unreachable))
+    (block (br_if 0 (i32.const 1)) (unreachable))
+    (block (br_table 0 (i32.const 0)) (unreachable))
+    (block (br_table 0 0 0 (i32.const 1)) (unreachable))
+    (i32.const 19)
+  )
+  (func (export "break-value") (result i32)
+    (block (result i32) (br 0 (i32.const 18)) (i32.const 19))
+  )
+  (func (export "break-repeated") (result i32)
+    (block (result i32)
+      (br 0 (i32.const 18))
+      (br 0 (i32.const 19))
+      (drop (br_if 0 (i32.const 20) (i32.const 0)))
+      (drop (br_if 0 (i32.const 20) (i32.const 1)))
+      (br 0 (i32.const 21))
+      (br_table 0 (i32.const 22) (i32.const 4))
+      (br_table 0 0 0 (i32.const 23) (i32.const 1))
+      (i32.const 21)
+    )
+  )
+  (func (export "break-inner") (result i32)
+    (local i32)
+    (local.set 0 (i32.const 0))
+    (local.set 0 (i32.add (local.get 0) (block (result i32) (block (result i32) (br 1 (i32.const 0x1))))))
+    (local.set 0 (i32.add (local.get 0) (block (result i32) (block (br 0)) (i32.const 0x2))))
+    (local.set 0
+      (i32.add (local.get 0) (block (result i32) (i32.ctz (br 0 (i32.const 0x4)))))
+    )
+    (local.set 0
+      (i32.add (local.get 0) (block (result i32) (i32.ctz (block (result i32) (br 1 (i32.const 0x8))))))
+    )
+    (local.get 0)
+  )
+
+  (func (export "effects") (result i32)
+    (local i32)
+    (block
+      (local.set 0 (i32.const 1))
+      (local.set 0 (i32.mul (local.get 0) (i32.const 3)))
+      (local.set 0 (i32.sub (local.get 0) (i32.const 5)))
+      (local.set 0 (i32.mul (local.get 0) (i32.const 7)))
+      (br 0)
+      (local.set 0 (i32.mul (local.get 0) (i32.const 100)))
+    )
+    (i32.eq (local.get 0) (i32.const -14))
+  )
+)
+
+(assert_return (invoke "empty"))
+(assert_return (invoke "singular") (i32.const 7))
+(assert_return (invoke "multi") (i32.const 8))
+(assert_return (invoke "nested") (i32.const 9))
+(assert_return (invoke "deep") (i32.const 150))
+
+(assert_return (invoke "as-select-first") (i32.const 1))
+(assert_return (invoke "as-select-mid") (i32.const 2))
+(assert_return (invoke "as-select-last") (i32.const 2))
+
+(assert_return (invoke "as-loop-first") (i32.const 1))
+(assert_return (invoke "as-loop-mid") (i32.const 1))
+(assert_return (invoke "as-loop-last") (i32.const 1))
+
+(assert_return (invoke "as-if-condition"))
+(assert_return (invoke "as-if-then") (i32.const 1))
+(assert_return (invoke "as-if-else") (i32.const 2))
+
+(assert_return (invoke "as-br_if-first") (i32.const 1))
+(assert_return (invoke "as-br_if-last") (i32.const 2))
+
+(assert_return (invoke "as-br_table-first") (i32.const 1))
+(assert_return (invoke "as-br_table-last") (i32.const 2))
+
+(assert_return (invoke "as-call_indirect-first") (i32.const 1))
+(assert_return (invoke "as-call_indirect-mid") (i32.const 2))
+(assert_return (invoke "as-call_indirect-last") (i32.const 1))
+
+(assert_return (invoke "as-store-first"))
+(assert_return (invoke "as-store-last"))
+
+(assert_return (invoke "as-memory.grow-value") (i32.const 1))
+(assert_return (invoke "as-call-value") (i32.const 1))
+(assert_return (invoke "as-return-value") (i32.const 1))
+(assert_return (invoke "as-drop-operand"))
+(assert_return (invoke "as-br-value") (i32.const 1))
+(assert_return (invoke "as-local.set-value") (i32.const 1))
+(assert_return (invoke "as-local.tee-value") (i32.const 1))
+(assert_return (invoke "as-global.set-value") (i32.const 1))
+(assert_return (invoke "as-load-operand") (i32.const 1))
+
+(assert_return (invoke "as-unary-operand") (i32.const 0))
+(assert_return (invoke "as-binary-operand") (i32.const 12))
+(assert_return (invoke "as-test-operand") (i32.const 0))
+(assert_return (invoke "as-compare-operand") (i32.const 0))
+
+(assert_return (invoke "break-bare") (i32.const 19))
+(assert_return (invoke "break-value") (i32.const 18))
+(assert_return (invoke "break-repeated") (i32.const 18))
+(assert_return (invoke "break-inner") (i32.const 0xf))
+
+(assert_return (invoke "effects") (i32.const 1))
+
+(assert_invalid
+  (module (func $type-empty-i32 (result i32) (block)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-i64 (result i64) (block)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f32 (result f32) (block)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f64 (result f64) (block)))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-value-i32-vs-void
+    (block (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-i64-vs-void
+    (block (i64.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-f32-vs-void
+    (block (f32.const 1.0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-f64-vs-void
+    (block (f64.const 1.0))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-value-empty-vs-i32 (result i32)
+    (block (result i32))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-empty-vs-i64 (result i64)
+    (block (result i64))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-empty-vs-f32 (result f32)
+    (block (result f32))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-empty-vs-f64 (result f64)
+    (block (result f64))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (func $type-value-empty-in-block
+      (i32.const 0)
+      (block (block (result i32)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-in-loop
+      (i32.const 0)
+      (loop (block (result i32)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-in-then
+      (i32.const 0) (i32.const 0)
+      (if (then (block (result i32)) (drop)))
+    )
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-value-void-vs-i32 (result i32)
+    (block (result i32) (nop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-void-vs-i64 (result i64)
+    (block (result i64) (nop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-void-vs-f32 (result f32)
+    (block (result f32) (nop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-void-vs-f64 (result f64)
+    (block (result f64) (nop))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-value-i32-vs-i64 (result i32)
+    (block (result i32) (i64.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-i32-vs-f32 (result i32)
+    (block (result i32) (f32.const 0.0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-i32-vs-f64 (result i32)
+    (block (result i32) (f64.const 0.0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-i64-vs-i32 (result i64)
+    (block (result i64) (i32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-i64-vs-f32 (result i64)
+    (block (result i64) (f32.const 0.0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-i64-vs-f64 (result i64)
+    (block (result i64) (f64.const 0.0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-f32-vs-i32 (result f32)
+    (block (result f32) (i32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-f32-vs-i64 (result f32)
+    (block (result f32) (i64.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-f32-vs-f64 (result f32)
+    (block (result f32) (f64.const 0.0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-f64-vs-i32 (result f64)
+    (block (result f64) (i32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-f64-vs-i64 (result f64)
+    (block (result f64) (i64.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-f64-vs-f32 (result f32)
+    (block (result f64) (f32.const 0.0))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-value-unreached-select-i32-i64 (result i32)
+    (block (result i64) (select (unreachable) (unreachable) (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-unreached-select-i32-f32 (result i32)
+    (block (result f32) (select (unreachable) (unreachable) (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-unreached-select-i32-f64 (result i32)
+    (block (result f64) (select (unreachable) (unreachable) (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-unreached-select-i64-i32 (result i64)
+    (block (result i32) (select (unreachable) (unreachable) (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-unreached-select-i64-f32 (result i64)
+    (block (result f32) (select (unreachable) (unreachable) (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-unreached-select-i64-f64 (result i64)
+    (block (result f64) (select (unreachable) (unreachable) (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-unreached-select-f32-i32 (result f32)
+    (block (result i32) (select (unreachable) (unreachable) (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-unreached-select-f32-i64 (result f32)
+    (block (result i64) (select (unreachable) (unreachable) (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-unreached-select-f32-f64 (result f32)
+    (block (result f64) (select (unreachable) (unreachable) (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-unreached-select-f64-i32 (result f64)
+    (block (result i32) (select (unreachable) (unreachable) (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-unreached-select-f64-i64 (result f64)
+    (block (result i64) (select (unreachable) (unreachable) (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-unreached-select-f64-f32 (result f64)
+    (block (result f32) (select (unreachable) (unreachable) (unreachable)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-last-void-vs-i32 (result i32)
+    (block (result i32) (br 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-last-void-vs-i64 (result i64)
+    (block (result i64) (br 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-last-void-vs-f32 (result f32)
+    (block (result f32) (br 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-last-void-vs-f64 (result f64)
+    (block (result f64) (br 0))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-empty-vs-i32 (result i32)
+    (block (result i32) (br 0) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-empty-vs-i64 (result i64)
+    (block (result i64) (br 0) (i64.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-empty-vs-f32 (result f32)
+    (block (result f32) (br 0) (f32.const 1.0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-empty-vs-f64 (result f64)
+    (block (result f64) (br 0) (f64.const 1.0))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-void-vs-i32 (result i32)
+    (block (result i32) (br 0 (nop)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-void-vs-i64 (result i64)
+    (block (result i64) (br 0 (nop)) (i64.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-void-vs-f32 (result f32)
+    (block (result f32) (br 0 (nop)) (f32.const 1.0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-void-vs-f64 (result f64)
+    (block (result f64) (br 0 (nop)) (f64.const 1.0))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-i32-vs-i64 (result i32)
+    (block (result i32) (br 0 (i64.const 1)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-i32-vs-f32 (result i32)
+    (block (result i32) (br 0 (f32.const 1.0)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-i32-vs-f64 (result i32)
+    (block (result i32) (br 0 (f64.const 1.0)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-i64-vs-i32 (result i64)
+    (block (result i64) (br 0 (i32.const 1)) (i64.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-i64-vs-f32 (result i64)
+    (block (result i64) (br 0 (f32.const 1.0)) (i64.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-i64-vs-f64 (result i64)
+    (block (result i64) (br 0 (f64.const 1.0)) (i64.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-f32-vs-i32 (result f32)
+    (block (result f32) (br 0 (i32.const 1)) (f32.const 1.0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-f32-vs-i64 (result f32)
+    (block (result f32) (br 0 (i64.const 1)) (f32.const 1.0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-f32-vs-f64 (result f32)
+    (block (result f32) (br 0 (f64.const 1.0)) (f32.const 1.0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-f64-vs-i32 (result f64)
+    (block (result i64) (br 0 (i32.const 1)) (f64.const 1.0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-f64-vs-i64 (result f64)
+    (block (result f64) (br 0 (i64.const 1)) (f64.const 1.0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-f64-vs-f32 (result f64)
+    (block (result f64) (br 0 (f32.const 1.0)) (f64.const 1))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-first-void-vs-i32 (result i32)
+    (block (result i32) (br 0 (nop)) (br 0 (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-void-vs-i64 (result i64)
+    (block (result i64) (br 0 (nop)) (br 0 (i64.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-void-vs-f32 (result f32)
+    (block (result f32) (br 0 (nop)) (br 0 (f32.const 1.0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-void-vs-f64 (result f64)
+    (block (result f64) (br 0 (nop)) (br 0 (f64.const 1.0)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-first-i32-vs-i64 (result i32)
+    (block (result i32) (br 0 (i64.const 1)) (br 0 (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-i32-vs-f32 (result i32)
+    (block (result i32) (br 0 (f32.const 1.0)) (br 0 (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-i32-vs-f64 (result i32)
+    (block (result i32) (br 0 (f64.const 1.0)) (br 0 (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-i64-vs-i32 (result i64)
+    (block (result i64) (br 0 (i32.const 1)) (br 0 (i64.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-i64-vs-f32 (result i64)
+    (block (result i64) (br 0 (f32.const 1.0)) (br 0 (i64.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-i64-vs-f64 (result i64)
+    (block (result i64) (br 0 (f64.const 1.0)) (br 0 (i64.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-f32-vs-i32 (result f32)
+    (block (result f32) (br 0 (i32.const 1)) (br 0 (f32.const 1.0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-f32-vs-i64 (result f32)
+    (block (result f32) (br 0 (i64.const 1)) (br 0 (f32.const 1.0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-f32-vs-f64 (result f32)
+    (block (result f32) (br 0 (f64.const 1.0)) (br 0 (f32.const 1.0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-f64-vs-i32 (result f64)
+    (block (result f64) (br 0 (i32.const 1)) (br 0 (f64.const 1.0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-f64-vs-i64 (result f64)
+    (block (result f64) (br 0 (i64.const 1)) (br 0 (f64.const 1.0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-f64-vs-f32 (result f64)
+    (block (result f64) (br 0 (f32.const 1.0)) (br 0 (f64.const 1.0)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-nested-i32-vs-void
+    (block (result i32) (block (result i32) (br 1 (i32.const 1))) (br 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-i64-vs-void
+    (block (result i64) (block (result i64) (br 1 (i64.const 1))) (br 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-f32-vs-void
+    (block (result f32) (block (result f32) (br 1 (f32.const 1.0))) (br 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-f64-vs-void
+    (block (result f64) (block (result f64) (br 1 (f64.const 1.0))) (br 0))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-nested-empty-vs-i32 (result i32)
+    (block (result i32) (block (br 1)) (br 0 (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-empty-vs-i64 (result i64)
+    (block (result i64) (block (br 1)) (br 0 (i64.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-empty-vs-f32 (result f32)
+    (block (result f32) (block (br 1)) (br 0 (f32.const 1.0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-empty-vs-f64 (result f64)
+    (block (result f64) (block (br 1)) (br 0 (f64.const 1)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-nested-void-vs-i32 (result i32)
+    (block (result i32) (block (result i32) (br 1 (nop))) (br 0 (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-void-vs-i64 (result i64)
+    (block (result i64) (block (result i64) (br 1 (nop))) (br 0 (i64.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-void-vs-f32 (result f32)
+    (block (result f32) (block (result f32) (br 1 (nop))) (br 0 (f32.const 1.0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-void-vs-f64 (result f64)
+    (block (result f64) (block (result f64) (br 1 (nop))) (br 0 (f64.const 1.0)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-nested-i32-vs-i64 (result i32)
+    (block (result i32)
+      (block (result i32) (br 1 (i64.const 1))) (br 0 (i32.const 1))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-i32-vs-f32 (result i32)
+    (block (result i32)
+      (block (result i32) (br 1 (f32.const 1.0))) (br 0 (i32.const 1))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-i32-vs-f64 (result i32)
+    (block (result i32)
+      (block (result i32) (br 1 (f64.const 1.0))) (br 0 (i32.const 1))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-i64-vs-i32 (result i64)
+    (block (result i64)
+      (block (result i64) (br 1 (i32.const 1))) (br 0 (i64.const 1))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-i64-vs-f32 (result i64)
+    (block (result i64)
+      (block (result i64) (br 1 (f32.const 1.0))) (br 0 (i64.const 1))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-i64-vs-f64 (result i64)
+    (block (result i64)
+      (block (result i64) (br 1 (f64.const 1.0))) (br 0 (i64.const 1))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-f32-vs-i32 (result f32)
+    (block (result f32)
+      (block (result f32) (br 1 (i32.const 1))) (br 0 (f32.const 1.0))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-f32-vs-i64 (result f32)
+    (block (result f32)
+      (block (result f32) (br 1 (i64.const 1))) (br 0 (f32.const 1.0))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-f32-vs-f64 (result f32)
+    (block (result f32)
+      (block (result f32) (br 1 (f64.const 1.0))) (br 0 (f32.const 1.0))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-f64-vs-i32 (result f64)
+    (block (result f64)
+      (block (result f64) (br 1 (i32.const 1))) (br 0 (f64.const 1.0))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-f64-vs-i64 (result f64)
+    (block (result f64)
+      (block (result f64) (br 1 (i64.const 1))) (br 0 (f64.const 1.0))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-f64-vs-f32 (result f64)
+    (block (result f64)
+      (block (result f64) (br 1 (f32.const 1.0))) (br 0 (f64.const 1.0))
+    )
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-operand-empty-vs-i32 (result i32)
+    (i32.ctz (block (br 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-empty-vs-i64 (result i64)
+    (i64.ctz (block (br 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-empty-vs-f32 (result f32)
+    (f32.floor (block (br 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-empty-vs-f64 (result f64)
+    (f64.floor (block (br 0)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-operand-void-vs-i32 (result i32)
+    (i32.ctz (block (br 0 (nop))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-void-vs-i64 (result i64)
+    (i64.ctz (block (br 0 (nop))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-void-vs-f32 (result f32)
+    (f32.floor (block (br 0 (nop))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-void-vs-f64 (result f64)
+    (f64.floor (block (br 0 (nop))))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-operand-i32-vs-i64 (result i32)
+    (i64.ctz (block (br 0 (i64.const 9))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-i32-vs-f32 (result i32)
+    (f32.floor (block (br 0 (f32.const 9.0))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-i32-vs-f64 (result i32)
+    (f64.floor (block (br 0 (f64.const 9.0))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-i64-vs-i32 (result i64)
+    (i32.ctz (block (br 0 (i32.const 9))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-i64-vs-f32 (result i64)
+    (f32.floor (block (br 0 (f32.const 9.0))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-i64-vs-f64 (result i64)
+    (f64.floor (block (br 0 (f64.const 9.0))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-f32-vs-i32 (result f32)
+    (i32.ctz (block (br 0 (i32.const 9))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-f32-vs-i64 (result f32)
+    (i64.ctz (block (br 0 (i64.const 9))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-f32-vs-f64 (result f32)
+    (f64.floor (block (br 0 (f64.const 9.0))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-f64-vs-i32 (result f64)
+    (i32.ctz (block (br 0 (i32.const 9))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-f64-vs-i64 (result f64)
+    (i64.ctz (block (br 0 (i64.const 9))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-f64-vs-f32 (result f64)
+    (f32.floor (block (br 0 (f32.const 9.0))))
+  ))
+  "type mismatch"
+)
+
+
+(assert_malformed
+  (module quote "(func block end $l)")
+  "mismatching label"
+)
+(assert_malformed
+  (module quote "(func block $a end $l)")
+  "mismatching label"
+)
diff --git a/binaryen/test/spec/br.wast b/binaryen/test/spec/br.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/br.wast
@@ -0,0 +1,606 @@
+;; Test `br` operator
+
+(module
+  ;; Auxiliary definition
+  (func $dummy)
+
+  (func (export "type-i32") (block (drop (i32.ctz (br 0)))))
+  (func (export "type-i64") (block (drop (i64.ctz (br 0)))))
+  (func (export "type-f32") (block (drop (f32.neg (br 0)))))
+  (func (export "type-f64") (block (drop (f64.neg (br 0)))))
+
+  (func (export "type-i32-value") (result i32)
+    (block (result i32) (i32.ctz (br 0 (i32.const 1))))
+  )
+  (func (export "type-i64-value") (result i64)
+    (block (result i64) (i64.ctz (br 0 (i64.const 2))))
+  )
+  (func (export "type-f32-value") (result f32)
+    (block (result f32) (f32.neg (br 0 (f32.const 3))))
+  )
+  (func (export "type-f64-value") (result f64)
+    (block (result f64) (f64.neg (br 0 (f64.const 4))))
+  )
+
+  (func (export "as-block-first")
+    (block (br 0) (call $dummy))
+  )
+  (func (export "as-block-mid")
+    (block (call $dummy) (br 0) (call $dummy))
+  )
+  (func (export "as-block-last")
+    (block (nop) (call $dummy) (br 0))
+  )
+  (func (export "as-block-value") (result i32)
+    (block (result i32) (nop) (call $dummy) (br 0 (i32.const 2)))
+  )
+
+  (func (export "as-loop-first") (result i32)
+    (block (result i32) (loop (result i32) (br 1 (i32.const 3)) (i32.const 2)))
+  )
+  (func (export "as-loop-mid") (result i32)
+    (block (result i32)
+      (loop (result i32) (call $dummy) (br 1 (i32.const 4)) (i32.const 2))
+    )
+  )
+  (func (export "as-loop-last") (result i32)
+    (block (result i32)
+      (loop (result i32) (nop) (call $dummy) (br 1 (i32.const 5)))
+    )
+  )
+
+  (func (export "as-br-value") (result i32)
+    (block (result i32) (br 0 (br 0 (i32.const 9))))
+  )
+
+  (func (export "as-br_if-cond")
+    (block (br_if 0 (br 0)))
+  )
+  (func (export "as-br_if-value") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (br 0 (i32.const 8)) (i32.const 1))) (i32.const 7)
+    )
+  )
+  (func (export "as-br_if-value-cond") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (i32.const 6) (br 0 (i32.const 9)))) (i32.const 7)
+    )
+  )
+
+  (func (export "as-br_table-index")
+    (block (br_table 0 0 0 (br 0)))
+  )
+  (func (export "as-br_table-value") (result i32)
+    (block (result i32)
+      (br_table 0 0 0 (br 0 (i32.const 10)) (i32.const 1)) (i32.const 7)
+    )
+  )
+  (func (export "as-br_table-value-index") (result i32)
+    (block (result i32)
+      (br_table 0 0 (i32.const 6) (br 0 (i32.const 11))) (i32.const 7)
+    )
+  )
+
+  (func (export "as-return-value") (result i64)
+    (block (result i64) (return (br 0 (i64.const 7))))
+  )
+
+  (func (export "as-if-cond") (result i32)
+    (block (result i32)
+      (if (result i32) (br 0 (i32.const 2))
+        (then (i32.const 0))
+        (else (i32.const 1))
+      )
+    )
+  )
+  (func (export "as-if-then") (param i32 i32) (result i32)
+    (block (result i32)
+      (if (result i32) (local.get 0)
+        (then (br 1 (i32.const 3)))
+        (else (local.get 1))
+      )
+    )
+  )
+  (func (export "as-if-else") (param i32 i32) (result i32)
+    (block (result i32)
+      (if (result i32) (local.get 0)
+        (then (local.get 1))
+        (else (br 1 (i32.const 4)))
+      )
+    )
+  )
+
+  (func (export "as-select-first") (param i32 i32) (result i32)
+    (block (result i32)
+      (select (br 0 (i32.const 5)) (local.get 0) (local.get 1))
+    )
+  )
+  (func (export "as-select-second") (param i32 i32) (result i32)
+    (block (result i32)
+      (select (local.get 0) (br 0 (i32.const 6)) (local.get 1))
+    )
+  )
+  (func (export "as-select-cond") (result i32)
+    (block (result i32)
+      (select (i32.const 0) (i32.const 1) (br 0 (i32.const 7)))
+    )
+  )
+
+  (func $f (param i32 i32 i32) (result i32) (i32.const -1))
+  (func (export "as-call-first") (result i32)
+    (block (result i32)
+      (call $f (br 0 (i32.const 12)) (i32.const 2) (i32.const 3))
+    )
+  )
+  (func (export "as-call-mid") (result i32)
+    (block (result i32)
+      (call $f (i32.const 1) (br 0 (i32.const 13)) (i32.const 3))
+    )
+  )
+  (func (export "as-call-last") (result i32)
+    (block (result i32)
+      (call $f (i32.const 1) (i32.const 2) (br 0 (i32.const 14)))
+    )
+  )
+
+  (type $sig (func (param i32 i32 i32) (result i32)))
+  (table funcref (elem $f))
+  (func (export "as-call_indirect-func") (result i32)
+    (block (result i32)
+      (call_indirect (type $sig)
+        (br 0 (i32.const 20))
+        (i32.const 1) (i32.const 2) (i32.const 3)
+      )
+    )
+  )
+  (func (export "as-call_indirect-first") (result i32)
+    (block (result i32)
+      (call_indirect (type $sig)
+        (i32.const 0)
+        (br 0 (i32.const 21)) (i32.const 2) (i32.const 3)
+      )
+    )
+  )
+  (func (export "as-call_indirect-mid") (result i32)
+    (block (result i32)
+      (call_indirect (type $sig)
+        (i32.const 0)
+        (i32.const 1) (br 0 (i32.const 22)) (i32.const 3)
+      )
+    )
+  )
+  (func (export "as-call_indirect-last") (result i32)
+    (block (result i32)
+      (call_indirect (type $sig)
+        (i32.const 0)
+        (i32.const 1) (i32.const 2) (br 0 (i32.const 23))
+      )
+    )
+  )
+
+  (func (export "as-local.set-value") (result i32) (local f32)
+    (block (result i32) (local.set 0 (br 0 (i32.const 17))) (i32.const -1))
+  )
+  (func (export "as-local.tee-value") (result i32) (local i32)
+    (block (result i32) (local.tee 0 (br 0 (i32.const 1))))
+  )
+  (global $a (mut i32) (i32.const 10))
+  (func (export "as-global.set-value") (result i32)
+    (block (result i32) (global.set $a (br 0 (i32.const 1))))
+  )
+
+  (memory 1)
+  (func (export "as-load-address") (result f32)
+    (block (result f32) (f32.load (br 0 (f32.const 1.7))))
+  )
+  (func (export "as-loadN-address") (result i64)
+    (block (result i64) (i64.load8_s (br 0 (i64.const 30))))
+  )
+
+  (func (export "as-store-address") (result i32)
+    (block (result i32)
+      (f64.store (br 0 (i32.const 30)) (f64.const 7)) (i32.const -1)
+    )
+  )
+  (func (export "as-store-value") (result i32)
+    (block (result i32)
+      (i64.store (i32.const 2) (br 0 (i32.const 31))) (i32.const -1)
+    )
+  )
+
+  (func (export "as-storeN-address") (result i32)
+    (block (result i32)
+      (i32.store8 (br 0 (i32.const 32)) (i32.const 7)) (i32.const -1)
+    )
+  )
+  (func (export "as-storeN-value") (result i32)
+    (block (result i32)
+      (i64.store16 (i32.const 2) (br 0 (i32.const 33))) (i32.const -1)
+    )
+  )
+
+  (func (export "as-unary-operand") (result f32)
+    (block (result f32) (f32.neg (br 0 (f32.const 3.4))))
+  )
+
+  (func (export "as-binary-left") (result i32)
+    (block (result i32) (i32.add (br 0 (i32.const 3)) (i32.const 10)))
+  )
+  (func (export "as-binary-right") (result i64)
+    (block (result i64) (i64.sub (i64.const 10) (br 0 (i64.const 45))))
+  )
+
+  (func (export "as-test-operand") (result i32)
+    (block (result i32) (i32.eqz (br 0 (i32.const 44))))
+  )
+
+  (func (export "as-compare-left") (result i32)
+    (block (result i32) (f64.le (br 0 (i32.const 43)) (f64.const 10)))
+  )
+  (func (export "as-compare-right") (result i32)
+    (block (result i32) (f32.ne (f32.const 10) (br 0 (i32.const 42))))
+  )
+
+  (func (export "as-convert-operand") (result i32)
+    (block (result i32) (i32.wrap_i64 (br 0 (i32.const 41))))
+  )
+
+  (func (export "as-memory.grow-size") (result i32)
+    (block (result i32) (memory.grow (br 0 (i32.const 40))))
+  )
+
+  (func (export "nested-block-value") (result i32)
+    (i32.add
+      (i32.const 1)
+      (block (result i32)
+        (call $dummy)
+        (i32.add (i32.const 4) (br 0 (i32.const 8)))
+      )
+    )
+  )
+
+  (func (export "nested-br-value") (result i32)
+    (i32.add
+      (i32.const 1)
+      (block (result i32)
+        (drop (i32.const 2))
+        (drop
+          (block (result i32)
+            (drop (i32.const 4))
+            (br 0 (br 1 (i32.const 8)))
+          )
+        )
+        (i32.const 16)
+      )
+    )
+  )
+
+  (func (export "nested-br_if-value") (result i32)
+    (i32.add
+      (i32.const 1)
+      (block (result i32)
+        (drop (i32.const 2))
+        (drop
+          (block (result i32)
+            (drop (i32.const 4))
+            (drop (br_if 0 (br 1 (i32.const 8)) (i32.const 1)))
+            (i32.const 32)
+          )
+        )
+        (i32.const 16)
+      )
+    )
+  )
+
+  (func (export "nested-br_if-value-cond") (result i32)
+    (i32.add
+      (i32.const 1)
+      (block (result i32)
+        (drop (i32.const 2))
+        (drop (br_if 0 (i32.const 4) (br 0 (i32.const 8))))
+        (i32.const 16)
+      )
+    )
+  )
+
+  (func (export "nested-br_table-value") (result i32)
+    (i32.add
+      (i32.const 1)
+      (block (result i32)
+        (drop (i32.const 2))
+        (drop
+          (block (result i32)
+            (drop (i32.const 4))
+            (br_table 0 (br 1 (i32.const 8)) (i32.const 1))
+          )
+        )
+        (i32.const 16)
+      )
+    )
+  )
+
+  (func (export "nested-br_table-value-index") (result i32)
+    (i32.add
+      (i32.const 1)
+      (block (result i32)
+        (drop (i32.const 2))
+        (br_table 0 (i32.const 4) (br 0 (i32.const 8)))
+        (i32.const 16)
+      )
+    )
+  )
+)
+
+(assert_return (invoke "type-i32"))
+(assert_return (invoke "type-i64"))
+(assert_return (invoke "type-f32"))
+(assert_return (invoke "type-f64"))
+
+(assert_return (invoke "type-i32-value") (i32.const 1))
+(assert_return (invoke "type-i64-value") (i64.const 2))
+(assert_return (invoke "type-f32-value") (f32.const 3))
+(assert_return (invoke "type-f64-value") (f64.const 4))
+
+(assert_return (invoke "as-block-first"))
+(assert_return (invoke "as-block-mid"))
+(assert_return (invoke "as-block-last"))
+(assert_return (invoke "as-block-value") (i32.const 2))
+
+(assert_return (invoke "as-loop-first") (i32.const 3))
+(assert_return (invoke "as-loop-mid") (i32.const 4))
+(assert_return (invoke "as-loop-last") (i32.const 5))
+
+(assert_return (invoke "as-br-value") (i32.const 9))
+
+(assert_return (invoke "as-br_if-cond"))
+(assert_return (invoke "as-br_if-value") (i32.const 8))
+(assert_return (invoke "as-br_if-value-cond") (i32.const 9))
+
+(assert_return (invoke "as-br_table-index"))
+(assert_return (invoke "as-br_table-value") (i32.const 10))
+(assert_return (invoke "as-br_table-value-index") (i32.const 11))
+
+(assert_return (invoke "as-return-value") (i64.const 7))
+
+(assert_return (invoke "as-if-cond") (i32.const 2))
+(assert_return (invoke "as-if-then" (i32.const 1) (i32.const 6)) (i32.const 3))
+(assert_return (invoke "as-if-then" (i32.const 0) (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-if-else" (i32.const 0) (i32.const 6)) (i32.const 4))
+(assert_return (invoke "as-if-else" (i32.const 1) (i32.const 6)) (i32.const 6))
+
+(assert_return (invoke "as-select-first" (i32.const 0) (i32.const 6)) (i32.const 5))
+(assert_return (invoke "as-select-first" (i32.const 1) (i32.const 6)) (i32.const 5))
+(assert_return (invoke "as-select-second" (i32.const 0) (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-select-second" (i32.const 1) (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-select-cond") (i32.const 7))
+
+(assert_return (invoke "as-call-first") (i32.const 12))
+(assert_return (invoke "as-call-mid") (i32.const 13))
+(assert_return (invoke "as-call-last") (i32.const 14))
+
+(assert_return (invoke "as-call_indirect-func") (i32.const 20))
+(assert_return (invoke "as-call_indirect-first") (i32.const 21))
+(assert_return (invoke "as-call_indirect-mid") (i32.const 22))
+(assert_return (invoke "as-call_indirect-last") (i32.const 23))
+
+(assert_return (invoke "as-local.set-value") (i32.const 17))
+(assert_return (invoke "as-local.tee-value") (i32.const 1))
+(assert_return (invoke "as-global.set-value") (i32.const 1))
+
+(assert_return (invoke "as-load-address") (f32.const 1.7))
+(assert_return (invoke "as-loadN-address") (i64.const 30))
+
+(assert_return (invoke "as-store-address") (i32.const 30))
+(assert_return (invoke "as-store-value") (i32.const 31))
+(assert_return (invoke "as-storeN-address") (i32.const 32))
+(assert_return (invoke "as-storeN-value") (i32.const 33))
+
+(assert_return (invoke "as-unary-operand") (f32.const 3.4))
+
+(assert_return (invoke "as-binary-left") (i32.const 3))
+(assert_return (invoke "as-binary-right") (i64.const 45))
+
+(assert_return (invoke "as-test-operand") (i32.const 44))
+
+(assert_return (invoke "as-compare-left") (i32.const 43))
+(assert_return (invoke "as-compare-right") (i32.const 42))
+
+(assert_return (invoke "as-convert-operand") (i32.const 41))
+
+(assert_return (invoke "as-memory.grow-size") (i32.const 40))
+
+(assert_return (invoke "nested-block-value") (i32.const 9))
+(assert_return (invoke "nested-br-value") (i32.const 9))
+(assert_return (invoke "nested-br_if-value") (i32.const 9))
+(assert_return (invoke "nested-br_if-value-cond") (i32.const 9))
+(assert_return (invoke "nested-br_table-value") (i32.const 9))
+(assert_return (invoke "nested-br_table-value-index") (i32.const 9))
+
+(assert_invalid
+  (module (func $type-arg-empty-vs-num (result i32)
+    (block (result i32) (br 0) (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-arg-void-vs-num (result i32)
+    (block (result i32) (br 0 (nop)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-arg-void-vs-num-nested (result i32)
+    (block (result i32) (i32.const 0) (block (br 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-arg-num-vs-num (result i32)
+    (block (result i32) (br 0 (i64.const 1)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (func $type-arg-empty-in-br
+      (i32.const 0)
+      (block (result i32) (br 0 (br 0))) (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-arg-empty-in-br_if
+      (i32.const 0)
+      (block (result i32) (br_if 0 (br 0) (i32.const 1))) (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-arg-empty-in-br_table
+      (i32.const 0)
+      (block (result i32) (br_table 0 (br 0))) (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-arg-empty-in-return
+      (block (result i32)
+        (return (br 0))
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-arg-empty-in-select
+      (block (result i32)
+        (select (br 0) (i32.const 1) (i32.const 2))
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-arg-empty-in-call
+      (block (result i32)
+        (call 1 (br 0))
+      )
+      (i32.eqz) (drop)
+    )
+    (func (param i32) (result i32) (local.get 0))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $f (param i32) (result i32) (local.get 0))
+    (type $sig (func (param i32) (result i32)))
+    (table funcref (elem $f))
+    (func $type-arg-empty-in-call_indirect
+      (block (result i32)
+        (call_indirect (type $sig)
+          (br 0) (i32.const 0)
+        )
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-arg-empty-in-local.set
+      (local i32)
+      (block (result i32)
+        (local.set 0 (br 0)) (local.get 0)
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-arg-empty-in-local.tee
+      (local i32)
+      (block (result i32)
+        (local.tee 0 (br 0))
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-arg-empty-in-global.set
+      (block (result i32)
+        (global.set $x (br 0)) (global.get $x)
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-arg-empty-in-memory.grow
+      (block (result i32)
+        (memory.grow (br 0))
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-arg-empty-in-load
+      (block (result i32)
+        (i32.load (br 0))
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-arg-empty-in-store
+      (block (result i32)
+        (i32.store (br 0) (i32.const 0))
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $unbound-label (br 1)))
+  "unknown label"
+)
+(assert_invalid
+  (module (func $unbound-nested-label (block (block (br 5)))))
+  "unknown label"
+)
+(assert_invalid
+  (module (func $large-label (br 0x10000001)))
+  "unknown label"
+)
diff --git a/binaryen/test/spec/br_if.wast b/binaryen/test/spec/br_if.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/br_if.wast
@@ -0,0 +1,665 @@
+;; Test `br_if` operator
+
+(module
+  (func $dummy)
+
+  (func (export "type-i32")
+    (block (drop (i32.ctz (br_if 0 (i32.const 0) (i32.const 1)))))
+  )
+  (func (export "type-i64")
+    (block (drop (i64.ctz (br_if 0 (i64.const 0) (i32.const 1)))))
+  )
+  (func (export "type-f32")
+    (block (drop (f32.neg (br_if 0 (f32.const 0) (i32.const 1)))))
+  )
+  (func (export "type-f64")
+    (block (drop (f64.neg (br_if 0 (f64.const 0) (i32.const 1)))))
+  )
+
+  (func (export "type-i32-value") (result i32)
+    (block (result i32) (i32.ctz (br_if 0 (i32.const 1) (i32.const 1))))
+  )
+  (func (export "type-i64-value") (result i64)
+    (block (result i64) (i64.ctz (br_if 0 (i64.const 2) (i32.const 1))))
+  )
+  (func (export "type-f32-value") (result f32)
+    (block (result f32) (f32.neg (br_if 0 (f32.const 3) (i32.const 1))))
+  )
+  (func (export "type-f64-value") (result f64)
+    (block (result f64) (f64.neg (br_if 0 (f64.const 4) (i32.const 1))))
+  )
+
+  (func (export "as-block-first") (param i32) (result i32)
+    (block (br_if 0 (local.get 0)) (return (i32.const 2))) (i32.const 3)
+  )
+  (func (export "as-block-mid") (param i32) (result i32)
+    (block (call $dummy) (br_if 0 (local.get 0)) (return (i32.const 2)))
+    (i32.const 3)
+  )
+  (func (export "as-block-last") (param i32)
+    (block (call $dummy) (call $dummy) (br_if 0 (local.get 0)))
+  )
+  (func (export "as-block-first-value") (param i32) (result i32)
+    (block (result i32)
+      (drop (br_if 0 (i32.const 10) (local.get 0))) (return (i32.const 11))
+    )
+  )
+  (func (export "as-block-mid-value") (param i32) (result i32)
+    (block (result i32)
+      (call $dummy)
+      (drop (br_if 0 (i32.const 20) (local.get 0)))
+      (return (i32.const 21))
+    )
+  )
+  (func (export "as-block-last-value") (param i32) (result i32)
+    (block (result i32)
+      (call $dummy) (call $dummy) (br_if 0 (i32.const 11) (local.get 0))
+    )
+  )
+
+  (func (export "as-loop-first") (param i32) (result i32)
+    (block (loop (br_if 1 (local.get 0)) (return (i32.const 2)))) (i32.const 3)
+  )
+  (func (export "as-loop-mid") (param i32) (result i32)
+    (block (loop (call $dummy) (br_if 1 (local.get 0)) (return (i32.const 2))))
+    (i32.const 4)
+  )
+  (func (export "as-loop-last") (param i32)
+    (loop (call $dummy) (br_if 1 (local.get 0)))
+  )
+
+  (func (export "as-br-value") (result i32)
+    (block (result i32) (br 0 (br_if 0 (i32.const 1) (i32.const 2))))
+  )
+
+  (func (export "as-br_if-cond")
+    (block (br_if 0 (br_if 0 (i32.const 1) (i32.const 1))))
+  )
+  (func (export "as-br_if-value") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (br_if 0 (i32.const 1) (i32.const 2)) (i32.const 3)))
+      (i32.const 4)
+    )
+  )
+  (func (export "as-br_if-value-cond") (param i32) (result i32)
+    (block (result i32)
+      (drop (br_if 0 (i32.const 2) (br_if 0 (i32.const 1) (local.get 0))))
+      (i32.const 4)
+    )
+  )
+
+  (func (export "as-br_table-index")
+    (block (br_table 0 0 0 (br_if 0 (i32.const 1) (i32.const 2))))
+  )
+  (func (export "as-br_table-value") (result i32)
+    (block (result i32)
+      (br_table 0 0 0 (br_if 0 (i32.const 1) (i32.const 2)) (i32.const 3)) (i32.const 4)
+    )
+  )
+  (func (export "as-br_table-value-index") (result i32)
+    (block (result i32)
+      (br_table 0 0 (i32.const 2) (br_if 0 (i32.const 1) (i32.const 3))) (i32.const 4)
+    )
+  )
+  (func (export "as-return-value") (result i64)
+    (block (result i64) (return (br_if 0 (i64.const 1) (i32.const 2))))
+  )
+
+  (func (export "as-if-cond") (param i32) (result i32)
+    (block (result i32)
+      (if (result i32)
+        (br_if 0 (i32.const 1) (local.get 0))
+        (then (i32.const 2))
+        (else (i32.const 3))
+      )
+    )
+  )
+  (func (export "as-if-then") (param i32 i32)
+    (block
+      (if (local.get 0) (then (br_if 1 (local.get 1))) (else (call $dummy)))
+    )
+  )
+  (func (export "as-if-else") (param i32 i32)
+    (block
+      (if (local.get 0) (then (call $dummy)) (else (br_if 1 (local.get 1))))
+    )
+  )
+
+  (func (export "as-select-first") (param i32) (result i32)
+    (block (result i32)
+      (select (br_if 0 (i32.const 3) (i32.const 10)) (i32.const 2) (local.get 0))
+    )
+  )
+  (func (export "as-select-second") (param i32) (result i32)
+    (block (result i32)
+      (select (i32.const 1) (br_if 0 (i32.const 3) (i32.const 10)) (local.get 0))
+    )
+  )
+  (func (export "as-select-cond") (result i32)
+    (block (result i32)
+      (select (i32.const 1) (i32.const 2) (br_if 0 (i32.const 3) (i32.const 10)))
+    )
+  )
+
+ (func $f (param i32 i32 i32) (result i32) (i32.const -1))
+  (func (export "as-call-first") (result i32)
+    (block (result i32)
+      (call $f
+        (br_if 0 (i32.const 12) (i32.const 1)) (i32.const 2) (i32.const 3)
+      )
+    )
+  )
+  (func (export "as-call-mid") (result i32)
+    (block (result i32)
+      (call $f
+        (i32.const 1) (br_if 0 (i32.const 13) (i32.const 1)) (i32.const 3)
+      )
+    )
+  )
+  (func (export "as-call-last") (result i32)
+    (block (result i32)
+      (call $f
+        (i32.const 1) (i32.const 2) (br_if 0 (i32.const 14) (i32.const 1))
+      )
+    )
+  )
+
+  (func $func (param i32 i32 i32) (result i32) (local.get 0))
+  (type $check (func (param i32 i32 i32) (result i32)))
+  (table funcref (elem $func))
+  (func (export "as-call_indirect-func") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (br_if 0 (i32.const 4) (i32.const 10))
+        (i32.const 1) (i32.const 2) (i32.const 0)
+      )
+    )
+  )
+
+  (func (export "as-call_indirect-first") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (i32.const 1) (br_if 0 (i32.const 4) (i32.const 10)) (i32.const 2) (i32.const 0)
+      )
+    )
+  )
+  (func (export "as-call_indirect-mid") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (i32.const 1) (i32.const 2) (br_if 0 (i32.const 4) (i32.const 10)) (i32.const 0)
+      )
+    )
+  )
+  (func (export "as-call_indirect-last") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (i32.const 1) (i32.const 2) (i32.const 3) (br_if 0 (i32.const 4) (i32.const 10))
+      )
+    )
+  )
+
+  (func (export "as-local.set-value") (param i32) (result i32)
+    (local i32)
+    (block (result i32)
+      (local.set 0 (br_if 0 (i32.const 17) (local.get 0)))
+      (i32.const -1)
+    )
+  )
+  (func (export "as-local.tee-value") (param i32) (result i32)
+    (block (result i32)
+      (local.tee 0 (br_if 0 (i32.const 1) (local.get 0)))
+      (return (i32.const -1))
+    )
+  )
+  (global $a (mut i32) (i32.const 10))
+  (func (export "as-global.set-value") (param i32) (result i32)
+    (block (result i32)
+      (global.set $a (br_if 0 (i32.const 1) (local.get 0)))
+      (return (i32.const -1))
+    )
+  )
+
+  (memory 1)
+  (func (export "as-load-address") (result i32)
+    (block (result i32) (i32.load (br_if 0 (i32.const 1) (i32.const 1))))
+  )
+  (func (export "as-loadN-address") (result i32)
+    (block (result i32) (i32.load8_s (br_if 0 (i32.const 30) (i32.const 1))))
+  )
+
+  (func (export "as-store-address") (result i32)
+    (block (result i32)
+      (i32.store (br_if 0 (i32.const 30) (i32.const 1)) (i32.const 7)) (i32.const -1)
+    )
+  )
+  (func (export "as-store-value") (result i32)
+    (block (result i32)
+      (i32.store (i32.const 2) (br_if 0 (i32.const 31) (i32.const 1))) (i32.const -1)
+    )
+  )
+
+  (func (export "as-storeN-address") (result i32)
+    (block (result i32)
+      (i32.store8 (br_if 0 (i32.const 32) (i32.const 1)) (i32.const 7)) (i32.const -1)
+    )
+  )
+  (func (export "as-storeN-value") (result i32)
+    (block (result i32)
+      (i32.store16 (i32.const 2) (br_if 0 (i32.const 33) (i32.const 1))) (i32.const -1)
+    )
+  )
+
+  (func (export "as-unary-operand") (result f64)
+    (block (result f64) (f64.neg (br_if 0 (f64.const 1.0) (i32.const 1))))
+  )
+  (func (export "as-binary-left") (result i32)
+    (block (result i32) (i32.add (br_if 0 (i32.const 1) (i32.const 1)) (i32.const 10)))
+  )
+  (func (export "as-binary-right") (result i32)
+    (block (result i32) (i32.sub (i32.const 10) (br_if 0 (i32.const 1) (i32.const 1))))
+  )
+  (func (export "as-test-operand") (result i32)
+    (block (result i32) (i32.eqz (br_if 0 (i32.const 0) (i32.const 1))))
+  )
+  (func (export "as-compare-left") (result i32)
+    (block (result i32) (i32.le_u (br_if 0 (i32.const 1) (i32.const 1)) (i32.const 10)))
+  )
+  (func (export "as-compare-right") (result i32)
+    (block (result i32) (i32.ne (i32.const 10) (br_if 0 (i32.const 1) (i32.const 42))))
+  )
+
+  (func (export "as-memory.grow-size") (result i32)
+    (block (result i32) (memory.grow (br_if 0 (i32.const 1) (i32.const 1))))
+  )
+
+  (func (export "nested-block-value") (param i32) (result i32)
+    (i32.add
+      (i32.const 1)
+      (block (result i32)
+        (drop (i32.const 2))
+        (i32.add
+          (i32.const 4)
+          (block (result i32)
+            (drop (br_if 1 (i32.const 8) (local.get 0)))
+            (i32.const 16)
+          )
+        )
+      )
+    )
+  )
+
+  (func (export "nested-br-value") (param i32) (result i32)
+    (i32.add
+      (i32.const 1)
+      (block (result i32)
+        (drop (i32.const 2))
+        (br 0
+          (block (result i32)
+            (drop (br_if 1 (i32.const 8) (local.get 0))) (i32.const 4)
+          )
+        )
+        (i32.const 16)
+      )
+    )
+  )
+
+  (func (export "nested-br_if-value") (param i32) (result i32)
+    (i32.add
+      (i32.const 1)
+      (block (result i32)
+        (drop (i32.const 2))
+        (drop (br_if 0
+          (block (result i32)
+            (drop (br_if 1 (i32.const 8) (local.get 0))) (i32.const 4)
+          )
+          (i32.const 1)
+        ))
+        (i32.const 16)
+      )
+    )
+  )
+
+  (func (export "nested-br_if-value-cond") (param i32) (result i32)
+    (i32.add
+      (i32.const 1)
+      (block (result i32)
+        (drop (i32.const 2))
+        (drop (br_if 0
+          (i32.const 4)
+          (block (result i32)
+            (drop (br_if 1 (i32.const 8) (local.get 0))) (i32.const 1)
+          )
+        ))
+        (i32.const 16)
+      )
+    )
+  )
+
+  (func (export "nested-br_table-value") (param i32) (result i32)
+    (i32.add
+      (i32.const 1)
+      (block (result i32)
+        (drop (i32.const 2))
+        (br_table 0
+          (block (result i32)
+            (drop (br_if 1 (i32.const 8) (local.get 0))) (i32.const 4)
+          )
+          (i32.const 1)
+        )
+        (i32.const 16)
+      )
+    )
+  )
+
+  (func (export "nested-br_table-value-index") (param i32) (result i32)
+    (i32.add
+      (i32.const 1)
+      (block (result i32)
+        (drop (i32.const 2))
+        (br_table 0
+          (i32.const 4)
+          (block (result i32)
+            (drop (br_if 1 (i32.const 8) (local.get 0))) (i32.const 1)
+          )
+        )
+        (i32.const 16)
+      )
+    )
+  )
+
+)
+
+(assert_return (invoke "type-i32"))
+(assert_return (invoke "type-i64"))
+(assert_return (invoke "type-f32"))
+(assert_return (invoke "type-f64"))
+
+(assert_return (invoke "type-i32-value") (i32.const 1))
+(assert_return (invoke "type-i64-value") (i64.const 2))
+(assert_return (invoke "type-f32-value") (f32.const 3))
+(assert_return (invoke "type-f64-value") (f64.const 4))
+
+(assert_return (invoke "as-block-first" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-block-first" (i32.const 1)) (i32.const 3))
+(assert_return (invoke "as-block-mid" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-block-mid" (i32.const 1)) (i32.const 3))
+(assert_return (invoke "as-block-last" (i32.const 0)))
+(assert_return (invoke "as-block-last" (i32.const 1)))
+
+(assert_return (invoke "as-block-first-value" (i32.const 0)) (i32.const 11))
+(assert_return (invoke "as-block-first-value" (i32.const 1)) (i32.const 10))
+(assert_return (invoke "as-block-mid-value" (i32.const 0)) (i32.const 21))
+(assert_return (invoke "as-block-mid-value" (i32.const 1)) (i32.const 20))
+(assert_return (invoke "as-block-last-value" (i32.const 0)) (i32.const 11))
+(assert_return (invoke "as-block-last-value" (i32.const 1)) (i32.const 11))
+
+(assert_return (invoke "as-loop-first" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-loop-first" (i32.const 1)) (i32.const 3))
+(assert_return (invoke "as-loop-mid" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-loop-mid" (i32.const 1)) (i32.const 4))
+(assert_return (invoke "as-loop-last" (i32.const 0)))
+(assert_return (invoke "as-loop-last" (i32.const 1)))
+
+(assert_return (invoke "as-br-value") (i32.const 1))
+
+(assert_return (invoke "as-br_if-cond"))
+(assert_return (invoke "as-br_if-value") (i32.const 1))
+(assert_return (invoke "as-br_if-value-cond" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-br_if-value-cond" (i32.const 1)) (i32.const 1))
+
+(assert_return (invoke "as-br_table-index"))
+(assert_return (invoke "as-br_table-value") (i32.const 1))
+(assert_return (invoke "as-br_table-value-index") (i32.const 1))
+
+(assert_return (invoke "as-return-value") (i64.const 1))
+
+(assert_return (invoke "as-if-cond" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-if-cond" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-if-then" (i32.const 0) (i32.const 0)))
+(assert_return (invoke "as-if-then" (i32.const 4) (i32.const 0)))
+(assert_return (invoke "as-if-then" (i32.const 0) (i32.const 1)))
+(assert_return (invoke "as-if-then" (i32.const 4) (i32.const 1)))
+(assert_return (invoke "as-if-else" (i32.const 0) (i32.const 0)))
+(assert_return (invoke "as-if-else" (i32.const 3) (i32.const 0)))
+(assert_return (invoke "as-if-else" (i32.const 0) (i32.const 1)))
+(assert_return (invoke "as-if-else" (i32.const 3) (i32.const 1)))
+
+(assert_return (invoke "as-select-first" (i32.const 0)) (i32.const 3))
+(assert_return (invoke "as-select-first" (i32.const 1)) (i32.const 3))
+(assert_return (invoke "as-select-second" (i32.const 0)) (i32.const 3))
+(assert_return (invoke "as-select-second" (i32.const 1)) (i32.const 3))
+(assert_return (invoke "as-select-cond") (i32.const 3))
+
+(assert_return (invoke "as-call-first") (i32.const 12))
+(assert_return (invoke "as-call-mid") (i32.const 13))
+(assert_return (invoke "as-call-last") (i32.const 14))
+
+(assert_return (invoke "as-call_indirect-func") (i32.const 4))
+(assert_return (invoke "as-call_indirect-first") (i32.const 4))
+(assert_return (invoke "as-call_indirect-mid") (i32.const 4))
+(assert_return (invoke "as-call_indirect-last") (i32.const 4))
+
+(assert_return (invoke "as-local.set-value" (i32.const 0)) (i32.const -1))
+(assert_return (invoke "as-local.set-value" (i32.const 1)) (i32.const 17))
+
+(assert_return (invoke "as-local.tee-value" (i32.const 0)) (i32.const -1))
+(assert_return (invoke "as-local.tee-value" (i32.const 1)) (i32.const 1))
+
+(assert_return (invoke "as-global.set-value" (i32.const 0)) (i32.const -1))
+(assert_return (invoke "as-global.set-value" (i32.const 1)) (i32.const 1))
+
+(assert_return (invoke "as-load-address") (i32.const 1))
+(assert_return (invoke "as-loadN-address") (i32.const 30))
+
+(assert_return (invoke "as-store-address") (i32.const 30))
+(assert_return (invoke "as-store-value") (i32.const 31))
+(assert_return (invoke "as-storeN-address") (i32.const 32))
+(assert_return (invoke "as-storeN-value") (i32.const 33))
+
+(assert_return (invoke "as-unary-operand") (f64.const 1.0))
+(assert_return (invoke "as-binary-left") (i32.const 1))
+(assert_return (invoke "as-binary-right") (i32.const 1))
+(assert_return (invoke "as-test-operand") (i32.const 0))
+(assert_return (invoke "as-compare-left") (i32.const 1))
+(assert_return (invoke "as-compare-right") (i32.const 1))
+(assert_return (invoke "as-memory.grow-size") (i32.const 1))
+
+(assert_return (invoke "nested-block-value" (i32.const 0)) (i32.const 21))
+(assert_return (invoke "nested-block-value" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br-value" (i32.const 0)) (i32.const 5))
+(assert_return (invoke "nested-br-value" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br_if-value" (i32.const 0)) (i32.const 5))
+(assert_return (invoke "nested-br_if-value" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br_if-value-cond" (i32.const 0)) (i32.const 5))
+(assert_return (invoke "nested-br_if-value-cond" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br_table-value" (i32.const 0)) (i32.const 5))
+(assert_return (invoke "nested-br_table-value" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br_table-value-index" (i32.const 0)) (i32.const 5))
+(assert_return (invoke "nested-br_table-value-index" (i32.const 1)) (i32.const 9))
+
+(assert_invalid
+  (module (func $type-false-i32 (block (i32.ctz (br_if 0 (i32.const 0))))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-false-i64 (block (i64.ctz (br_if 0 (i32.const 0))))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-false-f32 (block (f32.neg (br_if 0 (i32.const 0))))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-false-f64 (block (f64.neg (br_if 0 (i32.const 0))))))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-true-i32 (block (i32.ctz (br_if 0 (i32.const 1))))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-true-i64 (block (i64.ctz (br_if 0 (i64.const 1))))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-true-f32 (block (f32.neg (br_if 0 (f32.const 1))))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-true-f64 (block (f64.neg (br_if 0 (i64.const 1))))))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-false-arg-void-vs-num (result i32)
+    (block (result i32) (br_if 0 (i32.const 0)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-true-arg-void-vs-num (result i32)
+    (block (result i32) (br_if 0 (i32.const 1)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-false-arg-num-vs-void
+    (block (br_if 0 (i32.const 0) (i32.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-true-arg-num-vs-void
+    (block (br_if 0 (i32.const 0) (i32.const 1)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-false-arg-void-vs-num (result i32)
+    (block (result i32) (br_if 0 (nop) (i32.const 0)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-true-arg-void-vs-num (result i32)
+    (block (result i32) (br_if 0 (nop) (i32.const 1)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-false-arg-num-vs-num (result i32)
+    (block (result i32)
+      (drop (br_if 0 (i64.const 1) (i32.const 0))) (i32.const 1)
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-true-arg-num-vs-num (result i32)
+    (block (result i32)
+      (drop (br_if 0 (i64.const 1) (i32.const 0))) (i32.const 1)
+    )
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-cond-empty-vs-i32
+    (block (br_if 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-cond-void-vs-i32
+    (block (br_if 0 (nop)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-cond-num-vs-i32
+    (block (br_if 0 (i64.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-arg-cond-void-vs-i32 (result i32)
+    (block (result i32) (br_if 0 (i32.const 0) (nop)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-arg-void-vs-num-nested (result i32)
+    (block (result i32) (i32.const 0) (block (br_if 1 (i32.const 1))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-arg-cond-num-vs-i32 (result i32)
+    (block (result i32) (br_if 0 (i32.const 0) (i64.const 0)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (func $type-1st-cond-empty-in-then
+      (block
+        (i32.const 0) (i32.const 0)
+        (if (result i32) (then (br_if 0)))
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-2nd-cond-empty-in-then
+      (block
+        (i32.const 0) (i32.const 0)
+        (if (result i32) (then (br_if 0 (i32.const 1))))
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-1st-cond-empty-in-return
+      (block (result i32)
+        (return (br_if 0))
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-2nd-cond-empty-in-return
+      (block (result i32)
+        (return (br_if 0 (i32.const 1)))
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+
+
+(assert_invalid
+  (module (func $unbound-label (br_if 1 (i32.const 1))))
+  "unknown label"
+)
+(assert_invalid
+  (module (func $unbound-nested-label (block (block (br_if 5 (i32.const 1))))))
+  "unknown label"
+)
+(assert_invalid
+  (module (func $large-label (br_if 0x10000001 (i32.const 1))))
+  "unknown label"
+)
+
diff --git a/binaryen/test/spec/br_table.wast b/binaryen/test/spec/br_table.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/br_table.wast
@@ -0,0 +1,1593 @@
+;; Test `br_table` operator
+
+(module
+  ;; Auxiliary definition
+  (func $dummy)
+
+  (func (export "type-i32")
+    (block (drop (i32.ctz (br_table 0 0 (i32.const 0)))))
+  )
+  (func (export "type-i64")
+    (block (drop (i64.ctz (br_table 0 0 (i32.const 0)))))
+  )
+  (func (export "type-f32")
+    (block (drop (f32.neg (br_table 0 0 (i32.const 0)))))
+  )
+  (func (export "type-f64")
+    (block (drop (f64.neg (br_table 0 0 (i32.const 0)))))
+  )
+
+  (func (export "type-i32-value") (result i32)
+    (block (result i32) (i32.ctz (br_table 0 0 (i32.const 1) (i32.const 0))))
+  )
+  (func (export "type-i64-value") (result i64)
+    (block (result i64) (i64.ctz (br_table 0 0 (i64.const 2) (i32.const 0))))
+  )
+  (func (export "type-f32-value") (result f32)
+    (block (result f32) (f32.neg (br_table 0 0 (f32.const 3) (i32.const 0))))
+  )
+  (func (export "type-f64-value") (result f64)
+    (block (result f64) (f64.neg (br_table 0 0 (f64.const 4) (i32.const 0))))
+  )
+
+  (func (export "empty") (param i32) (result i32)
+    (block (br_table 0 (local.get 0)) (return (i32.const 21)))
+    (i32.const 22)
+  )
+  (func (export "empty-value") (param i32) (result i32)
+    (block (result i32)
+      (br_table 0 (i32.const 33) (local.get 0)) (i32.const 31)
+    )
+  )
+
+  (func (export "singleton") (param i32) (result i32)
+    (block
+      (block
+        (br_table 1 0 (local.get 0))
+        (return (i32.const 21))
+      )
+      (return (i32.const 20))
+    )
+    (i32.const 22)
+  )
+
+  (func (export "singleton-value") (param i32) (result i32)
+    (block (result i32)
+      (drop
+        (block (result i32)
+          (br_table 0 1 (i32.const 33) (local.get 0))
+          (return (i32.const 31))
+        )
+      )
+      (i32.const 32)
+    )
+  )
+
+  (func (export "multiple") (param i32) (result i32)
+    (block
+      (block
+        (block
+          (block
+            (block
+              (br_table 3 2 1 0 4 (local.get 0))
+              (return (i32.const 99))
+            )
+            (return (i32.const 100))
+          )
+          (return (i32.const 101))
+        )
+        (return (i32.const 102))
+      )
+      (return (i32.const 103))
+    )
+    (i32.const 104)
+  )
+
+  (func (export "multiple-value") (param i32) (result i32)
+    (local i32)
+    (local.set 1 (block (result i32)
+      (local.set 1 (block (result i32)
+        (local.set 1 (block (result i32)
+          (local.set 1 (block (result i32)
+            (local.set 1 (block (result i32)
+              (br_table 3 2 1 0 4 (i32.const 200) (local.get 0))
+              (return (i32.add (local.get 1) (i32.const 99)))
+            ))
+            (return (i32.add (local.get 1) (i32.const 10)))
+          ))
+          (return (i32.add (local.get 1) (i32.const 11)))
+        ))
+        (return (i32.add (local.get 1) (i32.const 12)))
+      ))
+      (return (i32.add (local.get 1) (i32.const 13)))
+    ))
+    (i32.add (local.get 1) (i32.const 14))
+  )
+
+  (func (export "large") (param i32) (result i32)
+    (block
+      (block
+        (br_table
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          (local.get 0)
+        )
+        (return (i32.const -1))
+      )
+      (return (i32.const 0))
+    )
+    (return (i32.const 1))
+  )
+
+  (func (export "as-block-first")
+    (block (br_table 0 0 0 (i32.const 0)) (call $dummy))
+  )
+  (func (export "as-block-mid")
+    (block (call $dummy) (br_table 0 0 0 (i32.const 0)) (call $dummy))
+  )
+  (func (export "as-block-last")
+    (block (nop) (call $dummy) (br_table 0 0 0 (i32.const 0)))
+  )
+  (func (export "as-block-value") (result i32)
+    (block (result i32)
+      (nop) (call $dummy) (br_table 0 0 0 (i32.const 2) (i32.const 0))
+    )
+  )
+
+  (func (export "as-loop-first") (result i32)
+    (loop (result i32) (br_table 1 1 (i32.const 3) (i32.const 0)) (i32.const 1))
+  )
+  (func (export "as-loop-mid") (result i32)
+    (loop (result i32)
+      (call $dummy)
+      (br_table 1 1 1 (i32.const 4) (i32.const -1))
+      (i32.const 2)
+    )
+  )
+  (func (export "as-loop-last") (result i32)
+    (loop (result i32)
+      (nop) (call $dummy) (br_table 1 1 1 (i32.const 5) (i32.const 1))
+    )
+  )
+
+  (func (export "as-br-value") (result i32)
+    (block (result i32) (br 0 (br_table 0 (i32.const 9) (i32.const 0))))
+  )
+
+  (func (export "as-br_if-cond")
+    (block (br_if 0 (br_table 0 0 0 (i32.const 1))))
+  )
+  (func (export "as-br_if-value") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (br_table 0 (i32.const 8) (i32.const 0)) (i32.const 1)))
+      (i32.const 7)
+    )
+  )
+  (func (export "as-br_if-value-cond") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (i32.const 6) (br_table 0 0 (i32.const 9) (i32.const 0))))
+      (i32.const 7)
+    )
+  )
+
+  (func (export "as-br_table-index")
+    (block (br_table 0 0 0 (br_table 0 (i32.const 1))))
+  )
+  (func (export "as-br_table-value") (result i32)
+    (block (result i32)
+      (br_table 0 0 0 (br_table 0 (i32.const 10) (i32.const 0)) (i32.const 1))
+      (i32.const 7)
+    )
+  )
+  (func (export "as-br_table-value-index") (result i32)
+    (block (result i32)
+      (br_table 0 0 (i32.const 6) (br_table 0 (i32.const 11) (i32.const 1)))
+      (i32.const 7)
+    )
+  )
+
+  (func (export "as-return-value") (result i64)
+    (block (result i64) (return (br_table 0 (i64.const 7) (i32.const 0))))
+  )
+
+  (func (export "as-if-cond") (result i32)
+    (block (result i32)
+      (if (result i32)
+        (br_table 0 (i32.const 2) (i32.const 0))
+        (then (i32.const 0))
+        (else (i32.const 1))
+      )
+    )
+  )
+  (func (export "as-if-then") (param i32 i32) (result i32)
+    (block (result i32)
+      (if (result i32)
+        (local.get 0)
+        (then (br_table 1 (i32.const 3) (i32.const 0)))
+        (else (local.get 1))
+      )
+    )
+  )
+  (func (export "as-if-else") (param i32 i32) (result i32)
+    (block (result i32)
+      (if (result i32)
+        (local.get 0)
+        (then (local.get 1))
+        (else (br_table 1 0 (i32.const 4) (i32.const 0)))
+      )
+    )
+  )
+
+  (func (export "as-select-first") (param i32 i32) (result i32)
+    (block (result i32)
+      (select
+        (br_table 0 (i32.const 5) (i32.const 0)) (local.get 0) (local.get 1)
+      )
+    )
+  )
+  (func (export "as-select-second") (param i32 i32) (result i32)
+    (block (result i32)
+      (select
+        (local.get 0) (br_table 0 (i32.const 6) (i32.const 1)) (local.get 1)
+      )
+    )
+  )
+  (func (export "as-select-cond") (result i32)
+    (block (result i32)
+      (select
+        (i32.const 0) (i32.const 1) (br_table 0 (i32.const 7) (i32.const 1))
+      )
+    )
+  )
+
+  (func $f (param i32 i32 i32) (result i32) (i32.const -1))
+  (func (export "as-call-first") (result i32)
+    (block (result i32)
+      (call $f
+        (br_table 0 (i32.const 12) (i32.const 1)) (i32.const 2) (i32.const 3)
+      )
+    )
+  )
+  (func (export "as-call-mid") (result i32)
+    (block (result i32)
+      (call $f
+        (i32.const 1) (br_table 0 (i32.const 13) (i32.const 1)) (i32.const 3)
+      )
+    )
+  )
+  (func (export "as-call-last") (result i32)
+    (block (result i32)
+      (call $f
+        (i32.const 1) (i32.const 2) (br_table 0 (i32.const 14) (i32.const 1))
+      )
+    )
+  )
+
+  (type $sig (func (param i32 i32 i32) (result i32)))
+  (table funcref (elem $f))
+  (func (export "as-call_indirect-first") (result i32)
+    (block (result i32)
+      (call_indirect (type $sig)
+        (br_table 0 (i32.const 20) (i32.const 1)) (i32.const 1) (i32.const 2)
+        (i32.const 3)
+      )
+    )
+  )
+  (func (export "as-call_indirect-mid") (result i32)
+    (block (result i32)
+      (call_indirect (type $sig)
+        (i32.const 0) (br_table 0 (i32.const 21) (i32.const 1)) (i32.const 2)
+        (i32.const 3)
+      )
+    )
+  )
+  (func (export "as-call_indirect-last") (result i32)
+    (block (result i32)
+      (call_indirect (type $sig)
+        (i32.const 0) (i32.const 1) (br_table 0 (i32.const 22) (i32.const 1))
+        (i32.const 3)
+      )
+    )
+  )
+  (func (export "as-call_indirect-func") (result i32)
+    (block (result i32)
+      (call_indirect (type $sig)
+        (i32.const 0) (i32.const 1) (i32.const 2)
+        (br_table 0 (i32.const 23) (i32.const 1))
+      )
+    )
+  )
+
+  (func (export "as-local.set-value") (result i32)
+    (local f32)
+    (block (result i32)
+      (local.set 0 (br_table 0 (i32.const 17) (i32.const 1)))
+      (i32.const -1)
+    )
+  )
+  (func (export "as-local.tee-value") (result i32)
+    (local i32)
+    (block (result i32)
+      (local.set 0 (br_table 0 (i32.const 1) (i32.const 1)))
+      (i32.const -1)
+    )
+  )
+  (global $a (mut i32) (i32.const 10))
+  (func (export "as-global.set-value") (result i32)
+    (block (result i32)
+      (global.set $a (br_table 0 (i32.const 1) (i32.const 1)))
+      (i32.const -1)
+    )
+  )
+
+  (memory 1)
+  (func (export "as-load-address") (result f32)
+    (block (result f32) (f32.load (br_table 0 (f32.const 1.7) (i32.const 1))))
+  )
+  (func (export "as-loadN-address") (result i64)
+    (block (result i64) (i64.load8_s (br_table 0 (i64.const 30) (i32.const 1))))
+  )
+
+  (func (export "as-store-address") (result i32)
+    (block (result i32)
+      (f64.store (br_table 0 (i32.const 30) (i32.const 1)) (f64.const 7))
+      (i32.const -1)
+    )
+  )
+  (func (export "as-store-value") (result i32)
+    (block (result i32)
+      (i64.store (i32.const 2) (br_table 0 (i32.const 31) (i32.const 1)))
+      (i32.const -1)
+     )
+  )
+
+  (func (export "as-storeN-address") (result i32)
+    (block (result i32)
+      (i32.store8 (br_table 0 (i32.const 32) (i32.const 0)) (i32.const 7))
+      (i32.const -1)
+    )
+  )
+  (func (export "as-storeN-value") (result i32)
+    (block (result i32)
+      (i64.store16 (i32.const 2) (br_table 0 (i32.const 33) (i32.const 0)))
+      (i32.const -1)
+    )
+  )
+
+  (func (export "as-unary-operand") (result f32)
+    (block (result f32) (f32.neg (br_table 0 (f32.const 3.4) (i32.const 0))))
+  )
+
+  (func (export "as-binary-left") (result i32)
+    (block (result i32)
+      (i32.add (br_table 0 0 (i32.const 3) (i32.const 0)) (i32.const 10))
+    )
+  )
+  (func (export "as-binary-right") (result i64)
+    (block (result i64)
+      (i64.sub (i64.const 10) (br_table 0 (i64.const 45) (i32.const 0)))
+    )
+  )
+
+  (func (export "as-test-operand") (result i32)
+    (block (result i32) (i32.eqz (br_table 0 (i32.const 44) (i32.const 0))))
+  )
+
+  (func (export "as-compare-left") (result i32)
+    (block (result i32)
+      (f64.le (br_table 0 0 (i32.const 43) (i32.const 0)) (f64.const 10))
+    )
+  )
+  (func (export "as-compare-right") (result i32)
+    (block (result i32)
+      (f32.ne (f32.const 10) (br_table 0 (i32.const 42) (i32.const 0)))
+    )
+  )
+
+  (func (export "as-convert-operand") (result i32)
+    (block (result i32)
+      (i32.wrap_i64 (br_table 0 (i32.const 41) (i32.const 0)))
+    )
+  )
+
+  (func (export "as-memory.grow-size") (result i32)
+    (block (result i32) (memory.grow (br_table 0 (i32.const 40) (i32.const 0))))
+  )
+
+  (func (export "nested-block-value") (param i32) (result i32)
+    (block (result i32)
+      (drop (i32.const -1))
+      (i32.add
+        (i32.const 1)
+        (block (result i32)
+          (i32.add
+            (i32.const 2)
+            (block (result i32)
+              (drop (i32.const 4))
+              (i32.add
+                (i32.const 8)
+                (br_table 0 1 2 (i32.const 16) (local.get 0))
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+
+  (func (export "nested-br-value") (param i32) (result i32)
+    (block (result i32)
+      (i32.add
+        (i32.const 1)
+        (block (result i32)
+          (drop (i32.const 2))
+          (drop
+            (block (result i32)
+              (drop (i32.const 4))
+              (br 0 (br_table 2 1 0 (i32.const 8) (local.get 0)))
+            )
+          )
+          (i32.const 16)
+        )
+      )
+    )
+  )
+
+  (func (export "nested-br_if-value") (param i32) (result i32)
+    (block (result i32)
+      (i32.add
+        (i32.const 1)
+        (block (result i32)
+          (drop (i32.const 2))
+          (drop
+            (block (result i32)
+              (drop (i32.const 4))
+              (drop
+                (br_if 0
+                  (br_table 0 1 2 (i32.const 8) (local.get 0))
+                  (i32.const 1)
+                )
+              )
+              (i32.const 32)
+            )
+          )
+          (i32.const 16)
+        )
+      )
+    )
+  )
+
+  (func (export "nested-br_if-value-cond") (param i32) (result i32)
+    (block (result i32)
+      (i32.add
+        (i32.const 1)
+        (block (result i32)
+          (drop (i32.const 2))
+          (drop
+            (br_if 0 (i32.const 4) (br_table 0 1 0 (i32.const 8) (local.get 0)))
+          )
+          (i32.const 16)
+        )
+      )
+    )
+  )
+
+  (func (export "nested-br_table-value") (param i32) (result i32)
+    (block (result i32)
+      (i32.add
+        (i32.const 1)
+        (block (result i32)
+          (drop (i32.const 2))
+          (drop
+            (block (result i32)
+              (drop (i32.const 4))
+              (br_table 0 (br_table 0 1 2 (i32.const 8) (local.get 0)) (i32.const 1))
+              (i32.const 32)
+            )
+          )
+          (i32.const 16)
+        )
+      )
+    )
+  )
+
+  (func (export "nested-br_table-value-index") (param i32) (result i32)
+    (block (result i32)
+      (i32.add
+        (i32.const 1)
+        (block (result i32)
+          (drop (i32.const 2))
+          (br_table 0 (i32.const 4) (br_table 0 1 0 (i32.const 8) (local.get 0)))
+          (i32.const 16)
+        )
+      )
+    )
+  )
+
+  (func (export "nested-br_table-loop-block") (param i32) (result i32)
+    (local.set 0
+      (loop (result i32)
+        (block
+          (br_table 1 0 0 (local.get 0))
+        )
+        (i32.const 0)
+      )
+    )
+    (loop (result i32)
+      (block
+        (br_table 0 1 1 (local.get 0))
+      )
+      (i32.const 3)
+    )
+  )
+)
+
+(assert_return (invoke "type-i32"))
+(assert_return (invoke "type-i64"))
+(assert_return (invoke "type-f32"))
+(assert_return (invoke "type-f64"))
+
+(assert_return (invoke "type-i32-value") (i32.const 1))
+(assert_return (invoke "type-i64-value") (i64.const 2))
+(assert_return (invoke "type-f32-value") (f32.const 3))
+(assert_return (invoke "type-f64-value") (f64.const 4))
+
+(assert_return (invoke "empty" (i32.const 0)) (i32.const 22))
+(assert_return (invoke "empty" (i32.const 1)) (i32.const 22))
+(assert_return (invoke "empty" (i32.const 11)) (i32.const 22))
+(assert_return (invoke "empty" (i32.const -1)) (i32.const 22))
+(assert_return (invoke "empty" (i32.const -100)) (i32.const 22))
+(assert_return (invoke "empty" (i32.const 0xffffffff)) (i32.const 22))
+
+(assert_return (invoke "empty-value" (i32.const 0)) (i32.const 33))
+(assert_return (invoke "empty-value" (i32.const 1)) (i32.const 33))
+(assert_return (invoke "empty-value" (i32.const 11)) (i32.const 33))
+(assert_return (invoke "empty-value" (i32.const -1)) (i32.const 33))
+(assert_return (invoke "empty-value" (i32.const -100)) (i32.const 33))
+(assert_return (invoke "empty-value" (i32.const 0xffffffff)) (i32.const 33))
+
+(assert_return (invoke "singleton" (i32.const 0)) (i32.const 22))
+(assert_return (invoke "singleton" (i32.const 1)) (i32.const 20))
+(assert_return (invoke "singleton" (i32.const 11)) (i32.const 20))
+(assert_return (invoke "singleton" (i32.const -1)) (i32.const 20))
+(assert_return (invoke "singleton" (i32.const -100)) (i32.const 20))
+(assert_return (invoke "singleton" (i32.const 0xffffffff)) (i32.const 20))
+
+(assert_return (invoke "singleton-value" (i32.const 0)) (i32.const 32))
+(assert_return (invoke "singleton-value" (i32.const 1)) (i32.const 33))
+(assert_return (invoke "singleton-value" (i32.const 11)) (i32.const 33))
+(assert_return (invoke "singleton-value" (i32.const -1)) (i32.const 33))
+(assert_return (invoke "singleton-value" (i32.const -100)) (i32.const 33))
+(assert_return (invoke "singleton-value" (i32.const 0xffffffff)) (i32.const 33))
+
+(assert_return (invoke "multiple" (i32.const 0)) (i32.const 103))
+(assert_return (invoke "multiple" (i32.const 1)) (i32.const 102))
+(assert_return (invoke "multiple" (i32.const 2)) (i32.const 101))
+(assert_return (invoke "multiple" (i32.const 3)) (i32.const 100))
+(assert_return (invoke "multiple" (i32.const 4)) (i32.const 104))
+(assert_return (invoke "multiple" (i32.const 5)) (i32.const 104))
+(assert_return (invoke "multiple" (i32.const 6)) (i32.const 104))
+(assert_return (invoke "multiple" (i32.const 10)) (i32.const 104))
+(assert_return (invoke "multiple" (i32.const -1)) (i32.const 104))
+(assert_return (invoke "multiple" (i32.const 0xffffffff)) (i32.const 104))
+
+(assert_return (invoke "multiple-value" (i32.const 0)) (i32.const 213))
+(assert_return (invoke "multiple-value" (i32.const 1)) (i32.const 212))
+(assert_return (invoke "multiple-value" (i32.const 2)) (i32.const 211))
+(assert_return (invoke "multiple-value" (i32.const 3)) (i32.const 210))
+(assert_return (invoke "multiple-value" (i32.const 4)) (i32.const 214))
+(assert_return (invoke "multiple-value" (i32.const 5)) (i32.const 214))
+(assert_return (invoke "multiple-value" (i32.const 6)) (i32.const 214))
+(assert_return (invoke "multiple-value" (i32.const 10)) (i32.const 214))
+(assert_return (invoke "multiple-value" (i32.const -1)) (i32.const 214))
+(assert_return (invoke "multiple-value" (i32.const 0xffffffff)) (i32.const 214))
+
+(assert_return (invoke "large" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "large" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "large" (i32.const 100)) (i32.const 0))
+(assert_return (invoke "large" (i32.const 101)) (i32.const 1))
+(assert_return (invoke "large" (i32.const 10000)) (i32.const 0))
+(assert_return (invoke "large" (i32.const 10001)) (i32.const 1))
+(assert_return (invoke "large" (i32.const 1000000)) (i32.const 1))
+(assert_return (invoke "large" (i32.const 1000001)) (i32.const 1))
+
+(assert_return (invoke "as-block-first"))
+(assert_return (invoke "as-block-mid"))
+(assert_return (invoke "as-block-last"))
+(assert_return (invoke "as-block-value") (i32.const 2))
+
+(assert_return (invoke "as-loop-first") (i32.const 3))
+(assert_return (invoke "as-loop-mid") (i32.const 4))
+(assert_return (invoke "as-loop-last") (i32.const 5))
+
+(assert_return (invoke "as-br-value") (i32.const 9))
+
+(assert_return (invoke "as-br_if-cond"))
+(assert_return (invoke "as-br_if-value") (i32.const 8))
+(assert_return (invoke "as-br_if-value-cond") (i32.const 9))
+
+(assert_return (invoke "as-br_table-index"))
+(assert_return (invoke "as-br_table-value") (i32.const 10))
+(assert_return (invoke "as-br_table-value-index") (i32.const 11))
+
+(assert_return (invoke "as-return-value") (i64.const 7))
+
+(assert_return (invoke "as-if-cond") (i32.const 2))
+(assert_return (invoke "as-if-then" (i32.const 1) (i32.const 6)) (i32.const 3))
+(assert_return (invoke "as-if-then" (i32.const 0) (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-if-else" (i32.const 0) (i32.const 6)) (i32.const 4))
+(assert_return (invoke "as-if-else" (i32.const 1) (i32.const 6)) (i32.const 6))
+
+(assert_return (invoke "as-select-first" (i32.const 0) (i32.const 6)) (i32.const 5))
+(assert_return (invoke "as-select-first" (i32.const 1) (i32.const 6)) (i32.const 5))
+(assert_return (invoke "as-select-second" (i32.const 0) (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-select-second" (i32.const 1) (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-select-cond") (i32.const 7))
+
+(assert_return (invoke "as-call-first") (i32.const 12))
+(assert_return (invoke "as-call-mid") (i32.const 13))
+(assert_return (invoke "as-call-last") (i32.const 14))
+
+(assert_return (invoke "as-call_indirect-first") (i32.const 20))
+(assert_return (invoke "as-call_indirect-mid") (i32.const 21))
+(assert_return (invoke "as-call_indirect-last") (i32.const 22))
+(assert_return (invoke "as-call_indirect-func") (i32.const 23))
+
+(assert_return (invoke "as-local.set-value") (i32.const 17))
+(assert_return (invoke "as-local.tee-value") (i32.const 1))
+(assert_return (invoke "as-global.set-value") (i32.const 1))
+
+(assert_return (invoke "as-load-address") (f32.const 1.7))
+(assert_return (invoke "as-loadN-address") (i64.const 30))
+
+(assert_return (invoke "as-store-address") (i32.const 30))
+(assert_return (invoke "as-store-value") (i32.const 31))
+(assert_return (invoke "as-storeN-address") (i32.const 32))
+(assert_return (invoke "as-storeN-value") (i32.const 33))
+
+(assert_return (invoke "as-unary-operand") (f32.const 3.4))
+
+(assert_return (invoke "as-binary-left") (i32.const 3))
+(assert_return (invoke "as-binary-right") (i64.const 45))
+
+(assert_return (invoke "as-test-operand") (i32.const 44))
+
+(assert_return (invoke "as-compare-left") (i32.const 43))
+(assert_return (invoke "as-compare-right") (i32.const 42))
+
+(assert_return (invoke "as-convert-operand") (i32.const 41))
+
+(assert_return (invoke "as-memory.grow-size") (i32.const 40))
+
+(assert_return (invoke "nested-block-value" (i32.const 0)) (i32.const 19))
+(assert_return (invoke "nested-block-value" (i32.const 1)) (i32.const 17))
+(assert_return (invoke "nested-block-value" (i32.const 2)) (i32.const 16))
+(assert_return (invoke "nested-block-value" (i32.const 10)) (i32.const 16))
+(assert_return (invoke "nested-block-value" (i32.const -1)) (i32.const 16))
+(assert_return (invoke "nested-block-value" (i32.const 100000)) (i32.const 16))
+
+(assert_return (invoke "nested-br-value" (i32.const 0)) (i32.const 8))
+(assert_return (invoke "nested-br-value" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br-value" (i32.const 2)) (i32.const 17))
+(assert_return (invoke "nested-br-value" (i32.const 11)) (i32.const 17))
+(assert_return (invoke "nested-br-value" (i32.const -4)) (i32.const 17))
+(assert_return (invoke "nested-br-value" (i32.const 10213210)) (i32.const 17))
+
+(assert_return (invoke "nested-br_if-value" (i32.const 0)) (i32.const 17))
+(assert_return (invoke "nested-br_if-value" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br_if-value" (i32.const 2)) (i32.const 8))
+(assert_return (invoke "nested-br_if-value" (i32.const 9)) (i32.const 8))
+(assert_return (invoke "nested-br_if-value" (i32.const -9)) (i32.const 8))
+(assert_return (invoke "nested-br_if-value" (i32.const 999999)) (i32.const 8))
+
+(assert_return (invoke "nested-br_if-value-cond" (i32.const 0)) (i32.const 9))
+(assert_return (invoke "nested-br_if-value-cond" (i32.const 1)) (i32.const 8))
+(assert_return (invoke "nested-br_if-value-cond" (i32.const 2)) (i32.const 9))
+(assert_return (invoke "nested-br_if-value-cond" (i32.const 3)) (i32.const 9))
+(assert_return (invoke "nested-br_if-value-cond" (i32.const -1000000)) (i32.const 9))
+(assert_return (invoke "nested-br_if-value-cond" (i32.const 9423975)) (i32.const 9))
+
+(assert_return (invoke "nested-br_table-value" (i32.const 0)) (i32.const 17))
+(assert_return (invoke "nested-br_table-value" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br_table-value" (i32.const 2)) (i32.const 8))
+(assert_return (invoke "nested-br_table-value" (i32.const 9)) (i32.const 8))
+(assert_return (invoke "nested-br_table-value" (i32.const -9)) (i32.const 8))
+(assert_return (invoke "nested-br_table-value" (i32.const 999999)) (i32.const 8))
+
+(assert_return (invoke "nested-br_table-value-index" (i32.const 0)) (i32.const 9))
+(assert_return (invoke "nested-br_table-value-index" (i32.const 1)) (i32.const 8))
+(assert_return (invoke "nested-br_table-value-index" (i32.const 2)) (i32.const 9))
+(assert_return (invoke "nested-br_table-value-index" (i32.const 3)) (i32.const 9))
+(assert_return (invoke "nested-br_table-value-index" (i32.const -1000000)) (i32.const 9))
+(assert_return (invoke "nested-br_table-value-index" (i32.const 9423975)) (i32.const 9))
+
+(assert_return (invoke "nested-br_table-loop-block" (i32.const 1)) (i32.const 3))
+
+(assert_invalid
+  (module (func $type-arg-void-vs-num (result i32)
+    (block (br_table 0 (i32.const 1)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-arg-empty-vs-num (result i32)
+    (block (br_table 0) (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-arg-void-vs-num (result i32)
+    (block (result i32) (br_table 0 (nop) (i32.const 1)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-arg-num-vs-num (result i32)
+    (block (result i32)
+      (br_table 0 0 0 (i64.const 1) (i32.const 1)) (i32.const 1)
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-arg-num-vs-arg-num
+    (block
+      (block (result f32)
+        (br_table 0 1 (f32.const 0) (i32.const 0))
+      )
+      (drop)
+    )
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-index-void-vs-i32
+    (block (br_table 0 0 0 (nop)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-index-num-vs-i32
+    (block (br_table 0 (i64.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-arg-index-void-vs-i32 (result i32)
+    (block (result i32) (br_table 0 0 (i32.const 0) (nop)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-arg-void-vs-num-nested (result i32)
+    (block (result i32) (i32.const 0) (block (br_table 1 (i32.const 0))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-arg-index-num-vs-i32 (result i32)
+    (block (result i32)
+      (br_table 0 0 (i32.const 0) (i64.const 0)) (i32.const 1)
+    )
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-arg-void-vs-num (result i32)
+    (block (br_table 0 (i32.const 1)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (func $type-arg-index-empty-in-then
+      (block
+        (i32.const 0) (i32.const 0)
+        (if (result i32) (then (br_table 0)))
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-arg-value-empty-in-then
+      (block
+        (i32.const 0) (i32.const 0)
+        (if (result i32) (then (br_table 0 (i32.const 1))))
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-arg-index-empty-in-return
+      (block (result i32)
+        (return (br_table 0))
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-arg-value-empty-in-return
+      (block (result i32)
+        (return (br_table 0 (i32.const 1)))
+      )
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+
+
+(assert_invalid
+  (module (func $unbound-label
+    (block (br_table 2 1 (i32.const 1)))
+  ))
+  "unknown label"
+)
+(assert_invalid
+  (module (func $unbound-nested-label
+    (block (block (br_table 0 5 (i32.const 1))))
+  ))
+  "unknown label"
+)
+(assert_invalid
+  (module (func $large-label
+    (block (br_table 0 0x10000001 0 (i32.const 1)))
+  ))
+  "unknown label"
+)
+
+(assert_invalid
+  (module (func $unbound-label-default
+    (block (br_table 1 2 (i32.const 1)))
+  ))
+  "unknown label"
+)
+(assert_invalid
+  (module (func $unbound-nested-label-default
+    (block (block (br_table 0 5 (i32.const 1))))
+  ))
+  "unknown label"
+)
+(assert_invalid
+  (module (func $large-label-default
+    (block (br_table 0 0 0x10000001 (i32.const 1)))
+  ))
+  "unknown label"
+)
+
diff --git a/binaryen/test/spec/break-drop.wast b/binaryen/test/spec/break-drop.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/break-drop.wast
@@ -0,0 +1,9 @@
+(module
+  (func (export "br") (block (br 0)))
+  (func (export "br_if") (block (br_if 0 (i32.const 1))))
+  (func (export "br_table") (block (br_table 0 (i32.const 0))))
+)
+
+(assert_return (invoke "br"))
+(assert_return (invoke "br_if"))
+(assert_return (invoke "br_table"))
diff --git a/binaryen/test/spec/bulk-memory.wast b/binaryen/test/spec/bulk-memory.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/bulk-memory.wast
@@ -0,0 +1,171 @@
+;; Passive segment syntax
+(module
+  (memory 1)
+  (data passive "foo"))
+
+;; memory.fill
+(module
+  (memory 1)
+
+  (func (export "fill") (param i32 i32 i32)
+    (memory.fill
+      (local.get 0)
+      (local.get 1)
+      (local.get 2)))
+
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0)))
+)
+
+;; Basic fill test.
+(invoke "fill" (i32.const 1) (i32.const 0xff) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xff))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 0xff))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 0xff))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 0))
+
+;; Fill value is stored as a byte.
+(invoke "fill" (i32.const 0) (i32.const 0xbbaa) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xaa))
+
+;; Fill all of memory
+(invoke "fill" (i32.const 0) (i32.const 0) (i32.const 0x10000))
+
+;; Succeed when writing 0 bytes at the end of the region.
+(invoke "fill" (i32.const 0x10000) (i32.const 0) (i32.const 0))
+
+;; Writing 0 bytes outside of memory limit is NOT allowed.
+(assert_trap (invoke "fill" (i32.const 0x10001) (i32.const 0) (i32.const 0)))
+
+;; Negative size
+(assert_trap (invoke "fill" (i32.const 15) (i32.const 14) (i32.const -2)))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 0))
+
+;; memory.copy
+(module
+  (memory 1 1)
+  (data (i32.const 0) "\aa\bb\cc\dd")
+
+  (func (export "copy") (param i32 i32 i32)
+    (memory.copy
+      (local.get 0)
+      (local.get 1)
+      (local.get 2)))
+
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0)))
+)
+
+;; Non-overlapping copy.
+(invoke "copy" (i32.const 10) (i32.const 0) (i32.const 4))
+
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xbb))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xdd))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0))
+
+;; Overlap, source > dest
+(invoke "copy" (i32.const 8) (i32.const 10) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0xbb))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xdd))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xdd))
+
+;; Overlap, source < dest
+(invoke "copy" (i32.const 10) (i32.const 7) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xbb))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0xdd))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 0))
+
+;; Overlap, source < dest but size is out of bounds
+(assert_trap (invoke "copy" (i32.const 13) (i32.const 11) (i32.const -1)))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xbb))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0xdd))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 0))
+
+;; Copy ending at memory limit is ok.
+(invoke "copy" (i32.const 0xff00) (i32.const 0) (i32.const 0x100))
+(invoke "copy" (i32.const 0xfe00) (i32.const 0xff00) (i32.const 0x100))
+
+;; Succeed when copying 0 bytes at the end of the region.
+(invoke "copy" (i32.const 0x10000) (i32.const 0) (i32.const 0))
+(invoke "copy" (i32.const 0) (i32.const 0x10000) (i32.const 0))
+
+;; Copying 0 bytes outside of memory limit is NOT allowed.
+(assert_trap (invoke "copy" (i32.const 0x10001) (i32.const 0) (i32.const 0)))
+(assert_trap (invoke "copy" (i32.const 0) (i32.const 0x10001) (i32.const 0)))
+
+;; memory.init
+(module
+  (memory 1)
+  (data passive "\aa\bb\cc\dd")
+
+  (func (export "init") (param i32 i32 i32)
+    (memory.init 0
+      (local.get 0)
+      (local.get 1)
+      (local.get 2)))
+
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0)))
+)
+
+(invoke "init" (i32.const 0) (i32.const 1) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0xbb))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 0))
+
+;; Init ending at memory limit and segment limit is ok.
+(invoke "init" (i32.const 0xfffc) (i32.const 0) (i32.const 4))
+
+;; Out-of-bounds writes trap, and no partial writes has been made.
+(assert_trap (invoke "init" (i32.const 0xfffe) (i32.const 0) (i32.const 3))
+    "out of bounds memory access")
+(assert_return (invoke "load8_u" (i32.const 0xfffe)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0xdd))
+
+;; Succeed when writing 0 bytes at the end of either region.
+(invoke "init" (i32.const 0x10000) (i32.const 0) (i32.const 0))
+(invoke "init" (i32.const 0) (i32.const 4) (i32.const 0))
+
+;; Writing 0 bytes outside of memory / segment limit is NOT allowed.
+(assert_trap (invoke "init" (i32.const 0x10001) (i32.const 0) (i32.const 0)))
+(assert_trap (invoke "init" (i32.const 0) (i32.const 5) (i32.const 0)))
+
+;; OK to access 0 bytes at offset 0 in a dropped segment.
+(invoke "init" (i32.const 0) (i32.const 0) (i32.const 0))
+
+;; data.drop
+(module
+  (memory 1)
+  (data passive "")
+  (data (i32.const 0) "")
+
+  (func (export "drop_passive") (data.drop 0))
+  (func (export "init_passive")
+    (memory.init 0 (i32.const 0) (i32.const 0) (i32.const 0)))
+
+  (func (export "drop_active") (data.drop 1))
+  (func (export "init_active")
+    (memory.init 1 (i32.const 0) (i32.const 0) (i32.const 0)))
+)
+
+;; OK to drop the same segment multiple times or drop an active segment.
+(invoke "init_passive")
+(invoke "drop_passive")
+(invoke "drop_passive")
+(invoke "drop_active")
diff --git a/binaryen/test/spec/bulk-memory64.wast b/binaryen/test/spec/bulk-memory64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/bulk-memory64.wast
@@ -0,0 +1,171 @@
+;; Passive segment syntax
+(module
+  (memory i64 1)
+  (data passive "foo"))
+
+;; memory.fill
+(module
+  (memory i64 1)
+
+  (func (export "fill") (param i64 i32 i64)
+    (memory.fill
+      (local.get 0)
+      (local.get 1)
+      (local.get 2)))
+
+  (func (export "load8_u") (param i64) (result i32)
+    (i32.load8_u (local.get 0)))
+)
+
+;; Basic fill test.
+(invoke "fill" (i64.const 1) (i32.const 0xff) (i64.const 3))
+(assert_return (invoke "load8_u" (i64.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i64.const 1)) (i32.const 0xff))
+(assert_return (invoke "load8_u" (i64.const 2)) (i32.const 0xff))
+(assert_return (invoke "load8_u" (i64.const 3)) (i32.const 0xff))
+(assert_return (invoke "load8_u" (i64.const 4)) (i32.const 0))
+
+;; Fill value is stored as a byte.
+(invoke "fill" (i64.const 0) (i32.const 0xbbaa) (i64.const 2))
+(assert_return (invoke "load8_u" (i64.const 0)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i64.const 1)) (i32.const 0xaa))
+
+;; Fill all of memory
+(invoke "fill" (i64.const 0) (i32.const 0) (i64.const 0x10000))
+
+;; Succeed when writing 0 bytes at the end of the region.
+(invoke "fill" (i64.const 0x10000) (i32.const 0) (i64.const 0))
+
+;; Writing 0 bytes outside of memory limit is NOT allowed.
+(assert_trap (invoke "fill" (i64.const 0x10001) (i32.const 0) (i64.const 0)))
+
+;; Negative size
+(assert_trap (invoke "fill" (i64.const 15) (i32.const 14) (i64.const -2)))
+(assert_return (invoke "load8_u" (i64.const 15)) (i32.const 0))
+
+;; memory.copy
+(module
+  (memory i64 1 1)
+  (data (i32.const 0) "\aa\bb\cc\dd")
+
+  (func (export "copy") (param i64 i64 i64)
+    (memory.copy
+      (local.get 0)
+      (local.get 1)
+      (local.get 2)))
+
+  (func (export "load8_u") (param i64) (result i32)
+    (i32.load8_u (local.get 0)))
+)
+
+;; Non-overlapping copy.
+(invoke "copy" (i64.const 10) (i64.const 0) (i64.const 4))
+
+(assert_return (invoke "load8_u" (i64.const 9)) (i32.const 0))
+(assert_return (invoke "load8_u" (i64.const 10)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i64.const 11)) (i32.const 0xbb))
+(assert_return (invoke "load8_u" (i64.const 12)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i64.const 13)) (i32.const 0xdd))
+(assert_return (invoke "load8_u" (i64.const 14)) (i32.const 0))
+
+;; Overlap, source > dest
+(invoke "copy" (i64.const 8) (i64.const 10) (i64.const 4))
+(assert_return (invoke "load8_u" (i64.const 8)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i64.const 9)) (i32.const 0xbb))
+(assert_return (invoke "load8_u" (i64.const 10)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i64.const 11)) (i32.const 0xdd))
+(assert_return (invoke "load8_u" (i64.const 12)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i64.const 13)) (i32.const 0xdd))
+
+;; Overlap, source < dest
+(invoke "copy" (i64.const 10) (i64.const 7) (i64.const 6))
+(assert_return (invoke "load8_u" (i64.const 10)) (i32.const 0))
+(assert_return (invoke "load8_u" (i64.const 11)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i64.const 12)) (i32.const 0xbb))
+(assert_return (invoke "load8_u" (i64.const 13)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i64.const 14)) (i32.const 0xdd))
+(assert_return (invoke "load8_u" (i64.const 15)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i64.const 16)) (i32.const 0))
+
+;; Overlap, source < dest but size is out of bounds
+(assert_trap (invoke "copy" (i64.const 13) (i64.const 11) (i64.const -1)))
+(assert_return (invoke "load8_u" (i64.const 10)) (i32.const 0))
+(assert_return (invoke "load8_u" (i64.const 11)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i64.const 12)) (i32.const 0xbb))
+(assert_return (invoke "load8_u" (i64.const 13)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i64.const 14)) (i32.const 0xdd))
+(assert_return (invoke "load8_u" (i64.const 15)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i64.const 16)) (i32.const 0))
+
+;; Copy ending at memory limit is ok.
+(invoke "copy" (i64.const 0xff00) (i64.const 0) (i64.const 0x100))
+(invoke "copy" (i64.const 0xfe00) (i64.const 0xff00) (i64.const 0x100))
+
+;; Succeed when copying 0 bytes at the end of the region.
+(invoke "copy" (i64.const 0x10000) (i64.const 0) (i64.const 0))
+(invoke "copy" (i64.const 0) (i64.const 0x10000) (i64.const 0))
+
+;; Copying 0 bytes outside of memory limit is NOT allowed.
+(assert_trap (invoke "copy" (i64.const 0x10001) (i64.const 0) (i64.const 0)))
+(assert_trap (invoke "copy" (i64.const 0) (i64.const 0x10001) (i64.const 0)))
+
+;; memory.init
+(module
+  (memory i64 1)
+  (data passive "\aa\bb\cc\dd")
+
+  (func (export "init") (param i64 i32 i32)
+    (memory.init 0
+      (local.get 0)
+      (local.get 1)
+      (local.get 2)))
+
+  (func (export "load8_u") (param i64) (result i32)
+    (i32.load8_u (local.get 0)))
+)
+
+(invoke "init" (i64.const 0) (i32.const 1) (i32.const 2))
+(assert_return (invoke "load8_u" (i64.const 0)) (i32.const 0xbb))
+(assert_return (invoke "load8_u" (i64.const 1)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i64.const 2)) (i32.const 0))
+
+;; Init ending at memory limit and segment limit is ok.
+(invoke "init" (i64.const 0xfffc) (i32.const 0) (i32.const 4))
+
+;; Out-of-bounds writes trap, and no partial writes has been made.
+(assert_trap (invoke "init" (i64.const 0xfffe) (i32.const 0) (i32.const 3))
+    "out of bounds memory access")
+(assert_return (invoke "load8_u" (i64.const 0xfffe)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i64.const 0xffff)) (i32.const 0xdd))
+
+;; Succeed when writing 0 bytes at the end of either region.
+(invoke "init" (i64.const 0x10000) (i32.const 0) (i32.const 0))
+(invoke "init" (i64.const 0) (i32.const 4) (i32.const 0))
+
+;; Writing 0 bytes outside of memory / segment limit is NOT allowed.
+(assert_trap (invoke "init" (i64.const 0x10001) (i32.const 0) (i32.const 0)))
+(assert_trap (invoke "init" (i64.const 0) (i32.const 5) (i32.const 0)))
+
+;; OK to access 0 bytes at offset 0 in a dropped segment.
+(invoke "init" (i64.const 0) (i32.const 0) (i32.const 0))
+
+;; data.drop
+(module
+  (memory i64 1)
+  (data passive "")
+  (data (i32.const 0) "")
+
+  (func (export "drop_passive") (data.drop 0))
+  (func (export "init_passive")
+    (memory.init 0 (i64.const 0) (i32.const 0) (i32.const 0)))
+
+  (func (export "drop_active") (data.drop 1))
+  (func (export "init_active")
+    (memory.init 1 (i64.const 0) (i32.const 0) (i32.const 0)))
+)
+
+;; OK to drop the same segment multiple times or drop an active segment.
+(invoke "init_passive")
+(invoke "drop_passive")
+(invoke "drop_passive")
+(invoke "drop_active")
diff --git a/binaryen/test/spec/call.wast b/binaryen/test/spec/call.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/call.wast
@@ -0,0 +1,463 @@
+;; Test `call` operator
+
+(module
+  ;; Auxiliary definitions
+  (func $const-i32 (result i32) (i32.const 0x132))
+  (func $const-i64 (result i64) (i64.const 0x164))
+  (func $const-f32 (result f32) (f32.const 0xf32))
+  (func $const-f64 (result f64) (f64.const 0xf64))
+
+  (func $id-i32 (param i32) (result i32) (local.get 0))
+  (func $id-i64 (param i64) (result i64) (local.get 0))
+  (func $id-f32 (param f32) (result f32) (local.get 0))
+  (func $id-f64 (param f64) (result f64) (local.get 0))
+
+  (func $f32-i32 (param f32 i32) (result i32) (local.get 1))
+  (func $i32-i64 (param i32 i64) (result i64) (local.get 1))
+  (func $f64-f32 (param f64 f32) (result f32) (local.get 1))
+  (func $i64-f64 (param i64 f64) (result f64) (local.get 1))
+
+  ;; Typing
+
+  (func (export "type-i32") (result i32) (call $const-i32))
+  (func (export "type-i64") (result i64) (call $const-i64))
+  (func (export "type-f32") (result f32) (call $const-f32))
+  (func (export "type-f64") (result f64) (call $const-f64))
+
+  (func (export "type-first-i32") (result i32) (call $id-i32 (i32.const 32)))
+  (func (export "type-first-i64") (result i64) (call $id-i64 (i64.const 64)))
+  (func (export "type-first-f32") (result f32) (call $id-f32 (f32.const 1.32)))
+  (func (export "type-first-f64") (result f64) (call $id-f64 (f64.const 1.64)))
+
+  (func (export "type-second-i32") (result i32)
+    (call $f32-i32 (f32.const 32.1) (i32.const 32))
+  )
+  (func (export "type-second-i64") (result i64)
+    (call $i32-i64 (i32.const 32) (i64.const 64))
+  )
+  (func (export "type-second-f32") (result f32)
+    (call $f64-f32 (f64.const 64) (f32.const 32))
+  )
+  (func (export "type-second-f64") (result f64)
+    (call $i64-f64 (i64.const 64) (f64.const 64.1))
+  )
+
+  ;; Recursion
+
+  (func $fac (export "fac") (param i64) (result i64)
+    (if (result i64) (i64.eqz (local.get 0))
+      (then (i64.const 1))
+      (else
+        (i64.mul
+          (local.get 0)
+          (call $fac (i64.sub (local.get 0) (i64.const 1)))
+        )
+      )
+    )
+  )
+
+  (func $fac-acc (export "fac-acc") (param i64 i64) (result i64)
+    (if (result i64) (i64.eqz (local.get 0))
+      (then (local.get 1))
+      (else
+        (call $fac-acc
+          (i64.sub (local.get 0) (i64.const 1))
+          (i64.mul (local.get 0) (local.get 1))
+        )
+      )
+    )
+  )
+
+  (func $fib (export "fib") (param i64) (result i64)
+    (if (result i64) (i64.le_u (local.get 0) (i64.const 1))
+      (then (i64.const 1))
+      (else
+        (i64.add
+          (call $fib (i64.sub (local.get 0) (i64.const 2)))
+          (call $fib (i64.sub (local.get 0) (i64.const 1)))
+        )
+      )
+    )
+  )
+
+  (func $even (export "even") (param i64) (result i32)
+    (if (result i32) (i64.eqz (local.get 0))
+      (then (i32.const 44))
+      (else (call $odd (i64.sub (local.get 0) (i64.const 1))))
+    )
+  )
+  (func $odd (export "odd") (param i64) (result i32)
+    (if (result i32) (i64.eqz (local.get 0))
+      (then (i32.const 99))
+      (else (call $even (i64.sub (local.get 0) (i64.const 1))))
+    )
+  )
+
+  ;; Stack exhaustion
+
+  ;; Implementations are required to have every call consume some abstract
+  ;; resource towards exhausting some abstract finite limit, such that
+  ;; infinitely recursive test cases reliably trap in finite time. This is
+  ;; because otherwise applications could come to depend on it on those
+  ;; implementations and be incompatible with implementations that don't do
+  ;; it (or don't do it under the same circumstances).
+
+  (func $runaway (export "runaway") (call $runaway))
+
+  (func $mutual-runaway1 (export "mutual-runaway") (call $mutual-runaway2))
+  (func $mutual-runaway2 (call $mutual-runaway1))
+
+  ;; As parameter of control constructs and instructions
+
+  (memory 1)
+
+  (func (export "as-select-first") (result i32)
+    (select (call $const-i32) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-select-mid") (result i32)
+    (select (i32.const 2) (call $const-i32) (i32.const 3))
+  )
+  (func (export "as-select-last") (result i32)
+    (select (i32.const 2) (i32.const 3) (call $const-i32))
+  )
+
+  (func (export "as-if-condition") (result i32)
+    (if (result i32) (call $const-i32) (then (i32.const 1)) (else (i32.const 2)))
+  )
+
+  (func (export "as-br_if-first") (result i32)
+    (block (result i32) (br_if 0 (call $const-i32) (i32.const 2)))
+  )
+  (func (export "as-br_if-last") (result i32)
+    (block (result i32) (br_if 0 (i32.const 2) (call $const-i32)))
+  )
+
+  (func (export "as-br_table-first") (result i32)
+    (block (result i32) (call $const-i32) (i32.const 2) (br_table 0 0))
+  )
+  (func (export "as-br_table-last") (result i32)
+    (block (result i32) (i32.const 2) (call $const-i32) (br_table 0 0))
+  )
+
+  (func $func (param i32 i32) (result i32) (local.get 0))
+  (type $check (func (param i32 i32) (result i32)))
+  (table funcref (elem $func))
+  (func (export "as-call_indirect-first") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (call $const-i32) (i32.const 2) (i32.const 0)
+      )
+    )
+  )
+  (func (export "as-call_indirect-mid") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (i32.const 2) (call $const-i32) (i32.const 0)
+      )
+    )
+  )
+  (func (export "as-call_indirect-last") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (i32.const 1) (i32.const 2) (call $const-i32)
+      )
+    )
+  )
+
+  (func (export "as-store-first")
+    (call $const-i32) (i32.const 1) (i32.store)
+  )
+  (func (export "as-store-last")
+    (i32.const 10) (call $const-i32) (i32.store)
+  )
+
+  (func (export "as-memory.grow-value") (result i32)
+    (memory.grow (call $const-i32))
+  )
+  (func (export "as-return-value") (result i32)
+    (call $const-i32) (return)
+  )
+  (func (export "as-drop-operand")
+    (call $const-i32) (drop)
+  )
+  (func (export "as-br-value") (result i32)
+    (block (result i32) (br 0 (call $const-i32)))
+  )
+  (func (export "as-local.set-value") (result i32)
+    (local i32) (local.set 0 (call $const-i32)) (local.get 0)
+  )
+  (func (export "as-local.tee-value") (result i32)
+    (local i32) (local.tee 0 (call $const-i32))
+  )
+  (global $a (mut i32) (i32.const 10))
+  (func (export "as-global.set-value") (result i32)
+    (global.set $a (call $const-i32))
+    (global.get $a)
+  )
+  (func (export "as-load-operand") (result i32)
+    (i32.load (call $const-i32))
+  )
+
+  (func $dummy (param i32) (result i32) (local.get 0))
+  (func $du (param f32) (result f32) (local.get 0))
+  (func (export "as-unary-operand") (result f32)
+    (block (result f32) (f32.sqrt (call $du (f32.const 0x0p+0))))
+  )
+
+  (func (export "as-binary-left") (result i32)
+    (block (result i32) (i32.add (call $dummy (i32.const 1)) (i32.const 10)))
+  )
+  (func (export "as-binary-right") (result i32)
+    (block (result i32) (i32.sub (i32.const 10) (call $dummy (i32.const 1))))
+  )
+
+  (func (export "as-test-operand") (result i32)
+    (block (result i32) (i32.eqz (call $dummy (i32.const 1))))
+  )
+
+  (func (export "as-compare-left") (result i32)
+    (block (result i32) (i32.le_u (call $dummy (i32.const 1)) (i32.const 10)))
+  )
+  (func (export "as-compare-right") (result i32)
+    (block (result i32) (i32.ne (i32.const 10) (call $dummy (i32.const 1))))
+  )
+
+  (func (export "as-convert-operand") (result i64)
+    (block (result i64) (i64.extend_i32_s (call $dummy (i32.const 1))))
+  )
+
+  ;; Test correct argument passing
+
+  (func $return-from-long-argument-list-helper (param f32 i32 i32 f64 f32 f32 f32 f64 f32 i32 i32 f32 f64 i64 i64 i32 i64 i64 f32 i64 i64 i64 i32 f32 f32 f32 f64 f32 i32 i64 f32 f64 f64 f32 i32 f32 f32 f64 i64 f64 i32 i64 f32 f64 i32 i32 i32 i64 f64 i32 i64 i64 f64 f64 f64 f64 f64 f64 i32 f32 f64 f64 i32 i64 f32 f32 f32 i32 f64 f64 f64 f64 f64 f32 i64 i64 i32 i32 i32 f32 f64 i32 i64 f32 f32 f32 i32 i32 f32 f64 i64 f32 f64 f32 f32 f32 i32 f32 i64 i32) (result i32)
+    (local.get 99)
+  )
+
+  (func (export "return-from-long-argument-list") (param i32) (result i32)
+    (call $return-from-long-argument-list-helper (f32.const 0) (i32.const 0) (i32.const 0) (f64.const 0) (f32.const 0) (f32.const 0) (f32.const 0) (f64.const 0) (f32.const 0) (i32.const 0) (i32.const 0) (f32.const 0) (f64.const 0) (i64.const 0) (i64.const 0) (i32.const 0) (i64.const 0) (i64.const 0) (f32.const 0) (i64.const 0) (i64.const 0) (i64.const 0) (i32.const 0) (f32.const 0) (f32.const 0) (f32.const 0) (f64.const 0) (f32.const 0) (i32.const 0) (i64.const 0) (f32.const 0) (f64.const 0) (f64.const 0) (f32.const 0) (i32.const 0) (f32.const 0) (f32.const 0) (f64.const 0) (i64.const 0) (f64.const 0) (i32.const 0) (i64.const 0) (f32.const 0) (f64.const 0) (i32.const 0) (i32.const 0) (i32.const 0) (i64.const 0) (f64.const 0) (i32.const 0) (i64.const 0) (i64.const 0) (f64.const 0) (f64.const 0) (f64.const 0) (f64.const 0) (f64.const 0) (f64.const 0) (i32.const 0) (f32.const 0) (f64.const 0) (f64.const 0) (i32.const 0) (i64.const 0) (f32.const 0) (f32.const 0) (f32.const 0) (i32.const 0) (f64.const 0) (f64.const 0) (f64.const 0) (f64.const 0) (f64.const 0) (f32.const 0) (i64.const 0) (i64.const 0) (i32.const 0) (i32.const 0) (i32.const 0) (f32.const 0) (f64.const 0) (i32.const 0) (i64.const 0) (f32.const 0) (f32.const 0) (f32.const 0) (i32.const 0) (i32.const 0) (f32.const 0) (f64.const 0) (i64.const 0) (f32.const 0) (f64.const 0) (f32.const 0) (f32.const 0) (f32.const 0) (i32.const 0) (f32.const 0) (i64.const 0) (local.get 0))
+  )
+)
+
+(assert_return (invoke "type-i32") (i32.const 0x132))
+(assert_return (invoke "type-i64") (i64.const 0x164))
+(assert_return (invoke "type-f32") (f32.const 0xf32))
+(assert_return (invoke "type-f64") (f64.const 0xf64))
+
+(assert_return (invoke "type-first-i32") (i32.const 32))
+(assert_return (invoke "type-first-i64") (i64.const 64))
+(assert_return (invoke "type-first-f32") (f32.const 1.32))
+(assert_return (invoke "type-first-f64") (f64.const 1.64))
+
+(assert_return (invoke "type-second-i32") (i32.const 32))
+(assert_return (invoke "type-second-i64") (i64.const 64))
+(assert_return (invoke "type-second-f32") (f32.const 32))
+(assert_return (invoke "type-second-f64") (f64.const 64.1))
+
+(assert_return (invoke "fac" (i64.const 0)) (i64.const 1))
+(assert_return (invoke "fac" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fac" (i64.const 5)) (i64.const 120))
+(assert_return (invoke "fac" (i64.const 25)) (i64.const 7034535277573963776))
+(assert_return (invoke "fac-acc" (i64.const 0) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fac-acc" (i64.const 1) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fac-acc" (i64.const 5) (i64.const 1)) (i64.const 120))
+(assert_return
+  (invoke "fac-acc" (i64.const 25) (i64.const 1))
+  (i64.const 7034535277573963776)
+)
+
+(assert_return (invoke "fib" (i64.const 0)) (i64.const 1))
+(assert_return (invoke "fib" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fib" (i64.const 2)) (i64.const 2))
+(assert_return (invoke "fib" (i64.const 5)) (i64.const 8))
+(assert_return (invoke "fib" (i64.const 20)) (i64.const 10946))
+
+(assert_return (invoke "even" (i64.const 0)) (i32.const 44))
+(assert_return (invoke "even" (i64.const 1)) (i32.const 99))
+(assert_return (invoke "even" (i64.const 100)) (i32.const 44))
+(assert_return (invoke "even" (i64.const 77)) (i32.const 99))
+(assert_return (invoke "odd" (i64.const 0)) (i32.const 99))
+(assert_return (invoke "odd" (i64.const 1)) (i32.const 44))
+(assert_return (invoke "odd" (i64.const 200)) (i32.const 99))
+(assert_return (invoke "odd" (i64.const 77)) (i32.const 44))
+
+(assert_exhaustion (invoke "runaway") "call stack exhausted")
+(assert_exhaustion (invoke "mutual-runaway") "call stack exhausted")
+
+(assert_return (invoke "as-select-first") (i32.const 0x132))
+(assert_return (invoke "as-select-mid") (i32.const 2))
+(assert_return (invoke "as-select-last") (i32.const 2))
+
+(assert_return (invoke "as-if-condition") (i32.const 1))
+
+(assert_return (invoke "as-br_if-first") (i32.const 0x132))
+(assert_return (invoke "as-br_if-last") (i32.const 2))
+
+(assert_return (invoke "as-br_table-first") (i32.const 0x132))
+(assert_return (invoke "as-br_table-last") (i32.const 2))
+
+(assert_return (invoke "as-call_indirect-first") (i32.const 0x132))
+(assert_return (invoke "as-call_indirect-mid") (i32.const 2))
+(assert_trap (invoke "as-call_indirect-last") "undefined element")
+
+(assert_return (invoke "as-store-first"))
+(assert_return (invoke "as-store-last"))
+
+(assert_return (invoke "as-memory.grow-value") (i32.const 1))
+(assert_return (invoke "as-return-value") (i32.const 0x132))
+(assert_return (invoke "as-drop-operand"))
+(assert_return (invoke "as-br-value") (i32.const 0x132))
+(assert_return (invoke "as-local.set-value") (i32.const 0x132))
+(assert_return (invoke "as-local.tee-value") (i32.const 0x132))
+(assert_return (invoke "as-global.set-value") (i32.const 0x132))
+(assert_return (invoke "as-load-operand") (i32.const 1))
+
+(assert_return (invoke "as-unary-operand") (f32.const 0x0p+0))
+(assert_return (invoke "as-binary-left") (i32.const 11))
+(assert_return (invoke "as-binary-right") (i32.const 9))
+(assert_return (invoke "as-test-operand") (i32.const 0))
+(assert_return (invoke "as-compare-left") (i32.const 1))
+(assert_return (invoke "as-compare-right") (i32.const 1))
+(assert_return (invoke "as-convert-operand") (i64.const 1))
+
+(assert_return (invoke "return-from-long-argument-list" (i32.const 42)) (i32.const 42))
+
+;; Invalid typing
+
+(assert_invalid
+  (module
+    (func $type-void-vs-num (i32.eqz (call 1)))
+    (func)
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-num-vs-num (i32.eqz (call 1)))
+    (func (result i64) (i64.const 1))
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (func $arity-0-vs-1 (call 1))
+    (func (param i32))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $arity-0-vs-2 (call 1))
+    (func (param f64 i32))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $arity-1-vs-0 (call 1 (i32.const 1)))
+    (func)
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $arity-2-vs-0 (call 1 (f64.const 2) (i32.const 1)))
+    (func)
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (func $type-first-void-vs-num (call 1 (nop) (i32.const 1)))
+    (func (param i32 i32))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-second-void-vs-num (call 1 (i32.const 1) (nop)))
+    (func (param i32 i32))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-first-num-vs-num (call 1 (f64.const 1) (i32.const 1)))
+    (func (param i32 f64))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-second-num-vs-num (call 1 (i32.const 1) (f64.const 1)))
+    (func (param f64 i32))
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (func $type-first-empty-in-block
+      (block (call 1))
+    )
+    (func (param i32))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-second-empty-in-block
+      (block (call 1 (i32.const 0)))
+    )
+    (func (param i32 i32))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-first-empty-in-loop
+      (loop (call 1))
+    )
+    (func (param i32))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-second-empty-in-loop
+      (loop (call 1 (i32.const 0)))
+    )
+    (func (param i32 i32))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-first-empty-in-then
+      (if (i32.const 0) (then (call 1)))
+    )
+    (func (param i32))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-second-empty-in-then
+      (if (i32.const 0) (then (call 1 (i32.const 0))))
+    )
+    (func (param i32 i32))
+  )
+  "type mismatch"
+)
+
+
+;; Unbound function
+
+(assert_invalid
+  (module (func $unbound-func (call 1)))
+  "unknown function"
+)
+(assert_invalid
+  (module (func $large-func (call 1012321300)))
+  "unknown function"
+)
diff --git a/binaryen/test/spec/call_indirect.wast b/binaryen/test/spec/call_indirect.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/call_indirect.wast
@@ -0,0 +1,942 @@
+;; Test `call_indirect` operator
+
+(module
+  ;; Auxiliary definitions
+  (type $proc (func))
+  (type $out-i32 (func (result i32)))
+  (type $out-i64 (func (result i64)))
+  (type $out-f32 (func (result f32)))
+  (type $out-f64 (func (result f64)))
+  (type $over-i32 (func (param i32) (result i32)))
+  (type $over-i64 (func (param i64) (result i64)))
+  (type $over-f32 (func (param f32) (result f32)))
+  (type $over-f64 (func (param f64) (result f64)))
+  (type $f32-i32 (func (param f32 i32) (result i32)))
+  (type $i32-i64 (func (param i32 i64) (result i64)))
+  (type $f64-f32 (func (param f64 f32) (result f32)))
+  (type $i64-f64 (func (param i64 f64) (result f64)))
+  (type $over-i32-duplicate (func (param i32) (result i32)))
+  (type $over-i64-duplicate (func (param i64) (result i64)))
+  (type $over-f32-duplicate (func (param f32) (result f32)))
+  (type $over-f64-duplicate (func (param f64) (result f64)))
+
+  (func $const-i32 (type $out-i32) (i32.const 0x132))
+  (func $const-i64 (type $out-i64) (i64.const 0x164))
+  (func $const-f32 (type $out-f32) (f32.const 0xf32))
+  (func $const-f64 (type $out-f64) (f64.const 0xf64))
+
+  (func $id-i32 (type $over-i32) (local.get 0))
+  (func $id-i64 (type $over-i64) (local.get 0))
+  (func $id-f32 (type $over-f32) (local.get 0))
+  (func $id-f64 (type $over-f64) (local.get 0))
+
+  (func $i32-i64 (type $i32-i64) (local.get 1))
+  (func $i64-f64 (type $i64-f64) (local.get 1))
+  (func $f32-i32 (type $f32-i32) (local.get 1))
+  (func $f64-f32 (type $f64-f32) (local.get 1))
+
+  (func $over-i32-duplicate (type $over-i32-duplicate) (local.get 0))
+  (func $over-i64-duplicate (type $over-i64-duplicate) (local.get 0))
+  (func $over-f32-duplicate (type $over-f32-duplicate) (local.get 0))
+  (func $over-f64-duplicate (type $over-f64-duplicate) (local.get 0))
+
+  (table funcref
+    (elem
+      $const-i32 $const-i64 $const-f32 $const-f64
+      $id-i32 $id-i64 $id-f32 $id-f64
+      $f32-i32 $i32-i64 $f64-f32 $i64-f64
+      $fac-i64 $fib-i64 $even $odd
+      $runaway $mutual-runaway1 $mutual-runaway2
+      $over-i32-duplicate $over-i64-duplicate
+      $over-f32-duplicate $over-f64-duplicate
+      $fac-i32 $fac-f32 $fac-f64
+      $fib-i32 $fib-f32 $fib-f64
+    )
+  )
+
+  ;; Syntax
+
+  (func
+    (call_indirect (i32.const 0))
+    (call_indirect (param i64) (i64.const 0) (i32.const 0))
+    (call_indirect (param i64) (param) (param f64 i32 i64)
+      (i64.const 0) (f64.const 0) (i32.const 0) (i64.const 0) (i32.const 0)
+    )
+    (call_indirect (result) (i32.const 0))
+    (drop (i32.eqz (call_indirect (result i32) (i32.const 0))))
+    (drop (i32.eqz (call_indirect (result i32) (result) (i32.const 0))))
+    (drop (i32.eqz
+      (call_indirect (param i64) (result i32) (i64.const 0) (i32.const 0))
+    ))
+    (drop (i32.eqz
+      (call_indirect
+        (param) (param i64) (param) (param f64 i32 i64) (param) (param)
+        (result) (result i32) (result) (result)
+        (i64.const 0) (f64.const 0) (i32.const 0) (i64.const 0) (i32.const 0)
+      )
+    ))
+    (drop (i64.eqz
+      (call_indirect (type $over-i64) (param i64) (result i64)
+        (i64.const 0) (i32.const 0)
+      )
+    ))
+  )
+
+  ;; Typing
+
+  (func (export "type-i32") (result i32)
+    (call_indirect (type $out-i32) (i32.const 0))
+  )
+  (func (export "type-i64") (result i64)
+    (call_indirect (type $out-i64) (i32.const 1))
+  )
+  (func (export "type-f32") (result f32)
+    (call_indirect (type $out-f32) (i32.const 2))
+  )
+  (func (export "type-f64") (result f64)
+    (call_indirect (type $out-f64) (i32.const 3))
+  )
+
+  (func (export "type-index") (result i64)
+    (call_indirect (type $over-i64) (i64.const 100) (i32.const 5))
+  )
+
+  (func (export "type-first-i32") (result i32)
+    (call_indirect (type $over-i32) (i32.const 32) (i32.const 4))
+  )
+  (func (export "type-first-i64") (result i64)
+    (call_indirect (type $over-i64) (i64.const 64) (i32.const 5))
+  )
+  (func (export "type-first-f32") (result f32)
+    (call_indirect (type $over-f32) (f32.const 1.32) (i32.const 6))
+  )
+  (func (export "type-first-f64") (result f64)
+    (call_indirect (type $over-f64) (f64.const 1.64) (i32.const 7))
+  )
+
+  (func (export "type-second-i32") (result i32)
+    (call_indirect (type $f32-i32) (f32.const 32.1) (i32.const 32) (i32.const 8))
+  )
+  (func (export "type-second-i64") (result i64)
+    (call_indirect (type $i32-i64) (i32.const 32) (i64.const 64) (i32.const 9))
+  )
+  (func (export "type-second-f32") (result f32)
+    (call_indirect (type $f64-f32) (f64.const 64) (f32.const 32) (i32.const 10))
+  )
+  (func (export "type-second-f64") (result f64)
+    (call_indirect (type $i64-f64) (i64.const 64) (f64.const 64.1) (i32.const 11))
+  )
+
+  ;; Dispatch
+
+  (func (export "dispatch") (param i32 i64) (result i64)
+    (call_indirect (type $over-i64) (local.get 1) (local.get 0))
+  )
+
+  (func (export "dispatch-structural-i64") (param i32) (result i64)
+    (call_indirect (type $over-i64-duplicate) (i64.const 9) (local.get 0))
+  )
+  (func (export "dispatch-structural-i32") (param i32) (result i32)
+    (call_indirect (type $over-i32-duplicate) (i32.const 9) (local.get 0))
+  )
+  (func (export "dispatch-structural-f32") (param i32) (result f32)
+    (call_indirect (type $over-f32-duplicate) (f32.const 9.0) (local.get 0))
+  )
+  (func (export "dispatch-structural-f64") (param i32) (result f64)
+    (call_indirect (type $over-f64-duplicate) (f64.const 9.0) (local.get 0))
+  )
+
+  ;; Recursion
+
+  (func $fac-i64 (export "fac-i64") (type $over-i64)
+    (if (result i64) (i64.eqz (local.get 0))
+      (then (i64.const 1))
+      (else
+        (i64.mul
+          (local.get 0)
+          (call_indirect (type $over-i64)
+            (i64.sub (local.get 0) (i64.const 1))
+            (i32.const 12)
+          )
+        )
+      )
+    )
+  )
+
+  (func $fib-i64 (export "fib-i64") (type $over-i64)
+    (if (result i64) (i64.le_u (local.get 0) (i64.const 1))
+      (then (i64.const 1))
+      (else
+        (i64.add
+          (call_indirect (type $over-i64)
+            (i64.sub (local.get 0) (i64.const 2))
+            (i32.const 13)
+          )
+          (call_indirect (type $over-i64)
+            (i64.sub (local.get 0) (i64.const 1))
+            (i32.const 13)
+          )
+        )
+      )
+    )
+  )
+
+  (func $fac-i32 (export "fac-i32") (type $over-i32)
+    (if (result i32) (i32.eqz (local.get 0))
+      (then (i32.const 1))
+      (else
+        (i32.mul
+          (local.get 0)
+          (call_indirect (type $over-i32)
+            (i32.sub (local.get 0) (i32.const 1))
+            (i32.const 23)
+          )
+        )
+      )
+    )
+  )
+
+  (func $fac-f32 (export "fac-f32") (type $over-f32)
+    (if (result f32) (f32.eq (local.get 0) (f32.const 0.0))
+      (then (f32.const 1.0))
+      (else
+        (f32.mul
+          (local.get 0)
+          (call_indirect (type $over-f32)
+            (f32.sub (local.get 0) (f32.const 1.0))
+            (i32.const 24)
+          )
+        )
+      )
+    )
+  )
+
+  (func $fac-f64 (export "fac-f64") (type $over-f64)
+    (if (result f64) (f64.eq (local.get 0) (f64.const 0.0))
+      (then (f64.const 1.0))
+      (else
+        (f64.mul
+          (local.get 0)
+          (call_indirect (type $over-f64)
+            (f64.sub (local.get 0) (f64.const 1.0))
+            (i32.const 25)
+          )
+        )
+      )
+    )
+  )
+
+  (func $fib-i32 (export "fib-i32") (type $over-i32)
+    (if (result i32) (i32.le_u (local.get 0) (i32.const 1))
+      (then (i32.const 1))
+      (else
+        (i32.add
+          (call_indirect (type $over-i32)
+            (i32.sub (local.get 0) (i32.const 2))
+            (i32.const 26)
+          )
+          (call_indirect (type $over-i32)
+            (i32.sub (local.get 0) (i32.const 1))
+            (i32.const 26)
+          )
+        )
+      )
+    )
+  )
+
+  (func $fib-f32 (export "fib-f32") (type $over-f32)
+    (if (result f32) (f32.le (local.get 0) (f32.const 1.0))
+      (then (f32.const 1.0))
+      (else
+        (f32.add
+          (call_indirect (type $over-f32)
+            (f32.sub (local.get 0) (f32.const 2.0))
+            (i32.const 27)
+          )
+          (call_indirect (type $over-f32)
+            (f32.sub (local.get 0) (f32.const 1.0))
+            (i32.const 27)
+          )
+        )
+      )
+    )
+  )
+
+  (func $fib-f64 (export "fib-f64") (type $over-f64)
+    (if (result f64) (f64.le (local.get 0) (f64.const 1.0))
+      (then (f64.const 1.0))
+      (else
+        (f64.add
+          (call_indirect (type $over-f64)
+            (f64.sub (local.get 0) (f64.const 2.0))
+            (i32.const 28)
+          )
+          (call_indirect (type $over-f64)
+            (f64.sub (local.get 0) (f64.const 1.0))
+            (i32.const 28)
+          )
+        )
+      )
+    )
+  )
+
+  (func $even (export "even") (param i32) (result i32)
+    (if (result i32) (i32.eqz (local.get 0))
+      (then (i32.const 44))
+      (else
+        (call_indirect (type $over-i32)
+          (i32.sub (local.get 0) (i32.const 1))
+          (i32.const 15)
+        )
+      )
+    )
+  )
+  (func $odd (export "odd") (param i32) (result i32)
+    (if (result i32) (i32.eqz (local.get 0))
+      (then (i32.const 99))
+      (else
+        (call_indirect (type $over-i32)
+          (i32.sub (local.get 0) (i32.const 1))
+          (i32.const 14)
+        )
+      )
+    )
+  )
+
+  ;; Stack exhaustion
+
+  ;; Implementations are required to have every call consume some abstract
+  ;; resource towards exhausting some abstract finite limit, such that
+  ;; infinitely recursive test cases reliably trap in finite time. This is
+  ;; because otherwise applications could come to depend on it on those
+  ;; implementations and be incompatible with implementations that don't do
+  ;; it (or don't do it under the same circumstances).
+
+  (func $runaway (export "runaway") (call_indirect (type $proc) (i32.const 16)))
+
+  (func $mutual-runaway1 (export "mutual-runaway") (call_indirect (type $proc) (i32.const 18)))
+  (func $mutual-runaway2 (call_indirect (type $proc) (i32.const 17)))
+
+  ;; As parameter of control constructs and instructions
+
+  (memory 1)
+
+  (func (export "as-select-first") (result i32)
+    (select (call_indirect (type $out-i32) (i32.const 0)) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-select-mid") (result i32)
+    (select (i32.const 2) (call_indirect (type $out-i32) (i32.const 0)) (i32.const 3))
+  )
+  (func (export "as-select-last") (result i32)
+    (select (i32.const 2) (i32.const 3) (call_indirect (type $out-i32) (i32.const 0)))
+  )
+
+  (func (export "as-if-condition") (result i32)
+    (if (result i32) (call_indirect (type $out-i32) (i32.const 0)) (then (i32.const 1)) (else (i32.const 2)))
+  )
+
+  (func (export "as-br_if-first") (result i64)
+    (block (result i64) (br_if 0 (call_indirect (type $out-i64) (i32.const 1)) (i32.const 2)))
+  )
+  (func (export "as-br_if-last") (result i32)
+    (block (result i32) (br_if 0 (i32.const 2) (call_indirect (type $out-i32) (i32.const 0))))
+  )
+
+  (func (export "as-br_table-first") (result f32)
+    (block (result f32) (call_indirect (type $out-f32) (i32.const 2)) (i32.const 2) (br_table 0 0))
+  )
+  (func (export "as-br_table-last") (result i32)
+    (block (result i32) (i32.const 2) (call_indirect (type $out-i32) (i32.const 0)) (br_table 0 0))
+  )
+
+  (func (export "as-store-first")
+    (call_indirect (type $out-i32) (i32.const 0)) (i32.const 1) (i32.store)
+  )
+  (func (export "as-store-last")
+    (i32.const 10) (call_indirect (type $out-f64) (i32.const 3)) (f64.store)
+  )
+
+  (func (export "as-memory.grow-value") (result i32)
+    (memory.grow (call_indirect (type $out-i32) (i32.const 0)))
+  )
+  (func (export "as-return-value") (result i32)
+    (call_indirect (type $over-i32) (i32.const 1) (i32.const 4)) (return)
+  )
+  (func (export "as-drop-operand")
+    (call_indirect (type $over-i64) (i64.const 1) (i32.const 5)) (drop)
+  )
+  (func (export "as-br-value") (result f32)
+    (block (result f32) (br 0 (call_indirect (type $over-f32) (f32.const 1) (i32.const 6))))
+  )
+  (func (export "as-local.set-value") (result f64)
+    (local f64) (local.set 0 (call_indirect (type $over-f64) (f64.const 1) (i32.const 7))) (local.get 0)
+  )
+  (func (export "as-local.tee-value") (result f64)
+    (local f64) (local.tee 0 (call_indirect (type $over-f64) (f64.const 1) (i32.const 7)))
+  )
+  (global $a (mut f64) (f64.const 10.0))
+  (func (export "as-global.set-value") (result f64)
+    (global.set $a (call_indirect (type $over-f64) (f64.const 1.0) (i32.const 7)))
+    (global.get $a)
+  )
+
+  (func (export "as-load-operand") (result i32)
+    (i32.load (call_indirect (type $out-i32) (i32.const 0)))
+  )
+
+  (func (export "as-unary-operand") (result f32)
+    (block (result f32)
+      (f32.sqrt
+        (call_indirect (type $over-f32) (f32.const 0x0p+0) (i32.const 6))
+      )
+    )
+  )
+
+  (func (export "as-binary-left") (result i32)
+    (block (result i32)
+      (i32.add
+        (call_indirect (type $over-i32) (i32.const 1) (i32.const 4))
+        (i32.const 10)
+      )
+    )
+  )
+  (func (export "as-binary-right") (result i32)
+    (block (result i32)
+      (i32.sub
+        (i32.const 10)
+        (call_indirect (type $over-i32) (i32.const 1) (i32.const 4))
+      )
+    )
+  )
+
+  (func (export "as-test-operand") (result i32)
+    (block (result i32)
+      (i32.eqz
+        (call_indirect (type $over-i32) (i32.const 1) (i32.const 4))
+      )
+    )
+  )
+
+  (func (export "as-compare-left") (result i32)
+    (block (result i32)
+      (i32.le_u
+        (call_indirect (type $over-i32) (i32.const 1) (i32.const 4))
+        (i32.const 10)
+      )
+    )
+  )
+  (func (export "as-compare-right") (result i32)
+    (block (result i32)
+      (i32.ne
+        (i32.const 10)
+        (call_indirect (type $over-i32) (i32.const 1) (i32.const 4))
+      )
+    )
+  )
+
+  (func (export "as-convert-operand") (result i64)
+    (block (result i64)
+      (i64.extend_i32_s
+        (call_indirect (type $over-i32) (i32.const 1) (i32.const 4))
+      )
+    )
+  )
+
+)
+
+(assert_return (invoke "type-i32") (i32.const 0x132))
+(assert_return (invoke "type-i64") (i64.const 0x164))
+(assert_return (invoke "type-f32") (f32.const 0xf32))
+(assert_return (invoke "type-f64") (f64.const 0xf64))
+
+(assert_return (invoke "type-index") (i64.const 100))
+
+(assert_return (invoke "type-first-i32") (i32.const 32))
+(assert_return (invoke "type-first-i64") (i64.const 64))
+(assert_return (invoke "type-first-f32") (f32.const 1.32))
+(assert_return (invoke "type-first-f64") (f64.const 1.64))
+
+(assert_return (invoke "type-second-i32") (i32.const 32))
+(assert_return (invoke "type-second-i64") (i64.const 64))
+(assert_return (invoke "type-second-f32") (f32.const 32))
+(assert_return (invoke "type-second-f64") (f64.const 64.1))
+
+(assert_return (invoke "dispatch" (i32.const 5) (i64.const 2)) (i64.const 2))
+(assert_return (invoke "dispatch" (i32.const 5) (i64.const 5)) (i64.const 5))
+(assert_return (invoke "dispatch" (i32.const 12) (i64.const 5)) (i64.const 120))
+(assert_return (invoke "dispatch" (i32.const 13) (i64.const 5)) (i64.const 8))
+(assert_return (invoke "dispatch" (i32.const 20) (i64.const 2)) (i64.const 2))
+(assert_trap (invoke "dispatch" (i32.const 0) (i64.const 2)) "indirect call type mismatch")
+(assert_trap (invoke "dispatch" (i32.const 15) (i64.const 2)) "indirect call type mismatch")
+(assert_trap (invoke "dispatch" (i32.const 29) (i64.const 2)) "undefined element")
+(assert_trap (invoke "dispatch" (i32.const -1) (i64.const 2)) "undefined element")
+(assert_trap (invoke "dispatch" (i32.const 1213432423) (i64.const 2)) "undefined element")
+
+(assert_return (invoke "dispatch-structural-i64" (i32.const 5)) (i64.const 9))
+(assert_return (invoke "dispatch-structural-i64" (i32.const 12)) (i64.const 362880))
+(assert_return (invoke "dispatch-structural-i64" (i32.const 13)) (i64.const 55))
+(assert_return (invoke "dispatch-structural-i64" (i32.const 20)) (i64.const 9))
+(assert_trap (invoke "dispatch-structural-i64" (i32.const 11)) "indirect call type mismatch")
+(assert_trap (invoke "dispatch-structural-i64" (i32.const 22)) "indirect call type mismatch")
+
+(assert_return (invoke "dispatch-structural-i32" (i32.const 4)) (i32.const 9))
+(assert_return (invoke "dispatch-structural-i32" (i32.const 23)) (i32.const 362880))
+(assert_return (invoke "dispatch-structural-i32" (i32.const 26)) (i32.const 55))
+(assert_return (invoke "dispatch-structural-i32" (i32.const 19)) (i32.const 9))
+(assert_trap (invoke "dispatch-structural-i32" (i32.const 9)) "indirect call type mismatch")
+(assert_trap (invoke "dispatch-structural-i32" (i32.const 21)) "indirect call type mismatch")
+
+(assert_return (invoke "dispatch-structural-f32" (i32.const 6)) (f32.const 9.0))
+(assert_return (invoke "dispatch-structural-f32" (i32.const 24)) (f32.const 362880.0))
+(assert_return (invoke "dispatch-structural-f32" (i32.const 27)) (f32.const 55.0))
+(assert_return (invoke "dispatch-structural-f32" (i32.const 21)) (f32.const 9.0))
+(assert_trap (invoke "dispatch-structural-f32" (i32.const 8)) "indirect call type mismatch")
+(assert_trap (invoke "dispatch-structural-f32" (i32.const 19)) "indirect call type mismatch")
+
+(assert_return (invoke "dispatch-structural-f64" (i32.const 7)) (f64.const 9.0))
+(assert_return (invoke "dispatch-structural-f64" (i32.const 25)) (f64.const 362880.0))
+(assert_return (invoke "dispatch-structural-f64" (i32.const 28)) (f64.const 55.0))
+(assert_return (invoke "dispatch-structural-f64" (i32.const 22)) (f64.const 9.0))
+(assert_trap (invoke "dispatch-structural-f64" (i32.const 10)) "indirect call type mismatch")
+(assert_trap (invoke "dispatch-structural-f64" (i32.const 18)) "indirect call type mismatch")
+
+(assert_return (invoke "fac-i64" (i64.const 0)) (i64.const 1))
+(assert_return (invoke "fac-i64" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fac-i64" (i64.const 5)) (i64.const 120))
+(assert_return (invoke "fac-i64" (i64.const 25)) (i64.const 7034535277573963776))
+
+(assert_return (invoke "fac-i32" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "fac-i32" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "fac-i32" (i32.const 5)) (i32.const 120))
+(assert_return (invoke "fac-i32" (i32.const 10)) (i32.const 3628800))
+
+(assert_return (invoke "fac-f32" (f32.const 0.0)) (f32.const 1.0))
+(assert_return (invoke "fac-f32" (f32.const 1.0)) (f32.const 1.0))
+(assert_return (invoke "fac-f32" (f32.const 5.0)) (f32.const 120.0))
+(assert_return (invoke "fac-f32" (f32.const 10.0)) (f32.const 3628800.0))
+
+(assert_return (invoke "fac-f64" (f64.const 0.0)) (f64.const 1.0))
+(assert_return (invoke "fac-f64" (f64.const 1.0)) (f64.const 1.0))
+(assert_return (invoke "fac-f64" (f64.const 5.0)) (f64.const 120.0))
+(assert_return (invoke "fac-f64" (f64.const 10.0)) (f64.const 3628800.0))
+
+(assert_return (invoke "fib-i64" (i64.const 0)) (i64.const 1))
+(assert_return (invoke "fib-i64" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fib-i64" (i64.const 2)) (i64.const 2))
+(assert_return (invoke "fib-i64" (i64.const 5)) (i64.const 8))
+(assert_return (invoke "fib-i64" (i64.const 20)) (i64.const 10946))
+
+(assert_return (invoke "fib-i32" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "fib-i32" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "fib-i32" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "fib-i32" (i32.const 5)) (i32.const 8))
+(assert_return (invoke "fib-i32" (i32.const 20)) (i32.const 10946))
+
+(assert_return (invoke "fib-f32" (f32.const 0.0)) (f32.const 1.0))
+(assert_return (invoke "fib-f32" (f32.const 1.0)) (f32.const 1.0))
+(assert_return (invoke "fib-f32" (f32.const 2.0)) (f32.const 2.0))
+(assert_return (invoke "fib-f32" (f32.const 5.0)) (f32.const 8.0))
+(assert_return (invoke "fib-f32" (f32.const 20.0)) (f32.const 10946.0))
+
+(assert_return (invoke "fib-f64" (f64.const 0.0)) (f64.const 1.0))
+(assert_return (invoke "fib-f64" (f64.const 1.0)) (f64.const 1.0))
+(assert_return (invoke "fib-f64" (f64.const 2.0)) (f64.const 2.0))
+(assert_return (invoke "fib-f64" (f64.const 5.0)) (f64.const 8.0))
+(assert_return (invoke "fib-f64" (f64.const 20.0)) (f64.const 10946.0))
+
+(assert_return (invoke "even" (i32.const 0)) (i32.const 44))
+(assert_return (invoke "even" (i32.const 1)) (i32.const 99))
+(assert_return (invoke "even" (i32.const 100)) (i32.const 44))
+(assert_return (invoke "even" (i32.const 77)) (i32.const 99))
+(assert_return (invoke "odd" (i32.const 0)) (i32.const 99))
+(assert_return (invoke "odd" (i32.const 1)) (i32.const 44))
+(assert_return (invoke "odd" (i32.const 200)) (i32.const 99))
+(assert_return (invoke "odd" (i32.const 77)) (i32.const 44))
+
+(assert_exhaustion (invoke "runaway") "call stack exhausted")
+(assert_exhaustion (invoke "mutual-runaway") "call stack exhausted")
+
+(assert_return (invoke "as-select-first") (i32.const 0x132))
+(assert_return (invoke "as-select-mid") (i32.const 2))
+(assert_return (invoke "as-select-last") (i32.const 2))
+
+(assert_return (invoke "as-if-condition") (i32.const 1))
+
+(assert_return (invoke "as-br_if-first") (i64.const 0x164))
+(assert_return (invoke "as-br_if-last") (i32.const 2))
+
+(assert_return (invoke "as-br_table-first") (f32.const 0xf32))
+(assert_return (invoke "as-br_table-last") (i32.const 2))
+
+(assert_return (invoke "as-store-first"))
+(assert_return (invoke "as-store-last"))
+
+(assert_return (invoke "as-memory.grow-value") (i32.const 1))
+(assert_return (invoke "as-return-value") (i32.const 1))
+(assert_return (invoke "as-drop-operand"))
+(assert_return (invoke "as-br-value") (f32.const 1))
+(assert_return (invoke "as-local.set-value") (f64.const 1))
+(assert_return (invoke "as-local.tee-value") (f64.const 1))
+(assert_return (invoke "as-global.set-value") (f64.const 1.0))
+(assert_return (invoke "as-load-operand") (i32.const 1))
+
+(assert_return (invoke "as-unary-operand") (f32.const 0x0p+0))
+(assert_return (invoke "as-binary-left") (i32.const 11))
+(assert_return (invoke "as-binary-right") (i32.const 9))
+(assert_return (invoke "as-test-operand") (i32.const 0))
+(assert_return (invoke "as-compare-left") (i32.const 1))
+(assert_return (invoke "as-compare-right") (i32.const 1))
+(assert_return (invoke "as-convert-operand") (i64.const 1))
+
+;; Invalid syntax
+
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32) (result i32)))"
+    "(table 0 funcref)"
+    "(func (result i32)"
+    "  (call_indirect (type $sig) (result i32) (param i32)"
+    "    (i32.const 0) (i32.const 0)"
+    "  )"
+    ")"
+  )
+  "unexpected token"
+)
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32) (result i32)))"
+    "(table 0 funcref)"
+    "(func (result i32)"
+    "  (call_indirect (param i32) (type $sig) (result i32)"
+    "    (i32.const 0) (i32.const 0)"
+    "  )"
+    ")"
+  )
+  "unexpected token"
+)
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32) (result i32)))"
+    "(table 0 funcref)"
+    "(func (result i32)"
+    "  (call_indirect (param i32) (result i32) (type $sig)"
+    "    (i32.const 0) (i32.const 0)"
+    "  )"
+    ")"
+  )
+  "unexpected token"
+)
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32) (result i32)))"
+    "(table 0 funcref)"
+    "(func (result i32)"
+    "  (call_indirect (result i32) (type $sig) (param i32)"
+    "    (i32.const 0) (i32.const 0)"
+    "  )"
+    ")"
+  )
+  "unexpected token"
+)
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32) (result i32)))"
+    "(table 0 funcref)"
+    "(func (result i32)"
+    "  (call_indirect (result i32) (param i32) (type $sig)"
+    "    (i32.const 0) (i32.const 0)"
+    "  )"
+    ")"
+  )
+  "unexpected token"
+)
+(assert_malformed
+  (module quote
+    "(table 0 funcref)"
+    "(func (result i32)"
+    "  (call_indirect (result i32) (param i32) (i32.const 0) (i32.const 0))"
+    ")"
+  )
+  "unexpected token"
+)
+
+(assert_malformed
+  (module quote
+    "(table 0 funcref)"
+    "(func (call_indirect (param $x i32) (i32.const 0) (i32.const 0)))"
+  )
+  "unexpected token"
+)
+(assert_malformed
+  (module quote
+    "(type $sig (func))"
+    "(table 0 funcref)"
+    "(func (result i32)"
+    "  (call_indirect (type $sig) (result i32) (i32.const 0))"
+    ")"
+  )
+  "inline function type"
+)
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32) (result i32)))"
+    "(table 0 funcref)"
+    "(func (result i32)"
+    "  (call_indirect (type $sig) (result i32) (i32.const 0))"
+    ")"
+  )
+  "inline function type"
+)
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32) (result i32)))"
+    "(table 0 funcref)"
+    "(func"
+    "  (call_indirect (type $sig) (param i32) (i32.const 0) (i32.const 0))"
+    ")"
+  )
+  "inline function type"
+)
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32 i32) (result i32)))"
+    "(table 0 funcref)"
+    "(func (result i32)"
+    "  (call_indirect (type $sig) (param i32) (result i32)"
+    "    (i32.const 0) (i32.const 0)"
+    "  )"
+    ")"
+  )
+  "inline function type"
+)
+
+;; Invalid typing
+
+(assert_invalid
+  (module
+    (type (func))
+    (func $no-table (call_indirect (type 0) (i32.const 0)))
+  )
+  "unknown table"
+)
+
+(assert_invalid
+  (module
+    (type (func))
+    (table 0 funcref)
+    (func $type-void-vs-num (i32.eqz (call_indirect (type 0) (i32.const 0))))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func (result i64)))
+    (table 0 funcref)
+    (func $type-num-vs-num (i32.eqz (call_indirect (type 0) (i32.const 0))))
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (type (func (param i32)))
+    (table 0 funcref)
+    (func $arity-0-vs-1 (call_indirect (type 0) (i32.const 0)))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func (param f64 i32)))
+    (table 0 funcref)
+    (func $arity-0-vs-2 (call_indirect (type 0) (i32.const 0)))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func))
+    (table 0 funcref)
+    (func $arity-1-vs-0 (call_indirect (type 0) (i32.const 1) (i32.const 0)))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func))
+    (table 0 funcref)
+    (func $arity-2-vs-0
+      (call_indirect (type 0) (f64.const 2) (i32.const 1) (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (type (func (param i32)))
+    (table 0 funcref)
+    (func $type-func-void-vs-i32 (call_indirect (type 0) (i32.const 1) (nop)))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func (param i32)))
+    (table 0 funcref)
+    (func $type-func-num-vs-i32 (call_indirect (type 0) (i32.const 0) (i64.const 1)))
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (type (func (param i32 i32)))
+    (table 0 funcref)
+    (func $type-first-void-vs-num
+      (call_indirect (type 0) (nop) (i32.const 1) (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func (param i32 i32)))
+    (table 0 funcref)
+    (func $type-second-void-vs-num
+      (call_indirect (type 0) (i32.const 1) (nop) (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func (param i32 f64)))
+    (table 0 funcref)
+    (func $type-first-num-vs-num
+      (call_indirect (type 0) (f64.const 1) (i32.const 1) (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func (param f64 i32)))
+    (table 0 funcref)
+    (func $type-second-num-vs-num
+      (call_indirect (type 0) (i32.const 1) (f64.const 1) (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (func $f (param i32))
+    (type $sig (func (param i32)))
+    (table funcref (elem $f))
+    (func $type-first-empty-in-block
+      (block
+        (call_indirect (type $sig) (i32.const 0))
+      )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $f (param i32 i32))
+    (type $sig (func (param i32 i32)))
+    (table funcref (elem $f))
+    (func $type-second-empty-in-block
+      (block
+        (call_indirect (type $sig) (i32.const 0) (i32.const 0))
+      )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $f (param i32))
+    (type $sig (func (param i32)))
+    (table funcref (elem $f))
+    (func $type-first-empty-in-loop
+      (loop
+        (call_indirect (type $sig) (i32.const 0))
+      )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $f (param i32 i32))
+    (type $sig (func (param i32 i32)))
+    (table funcref (elem $f))
+    (func $type-second-empty-in-loop
+      (loop
+        (call_indirect (type $sig) (i32.const 0) (i32.const 0))
+      )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $f (param i32))
+    (type $sig (func (param i32)))
+    (table funcref (elem $f))
+    (func $type-first-empty-in-then
+      (i32.const 0) (i32.const 0)
+      (if
+        (then
+          (call_indirect (type $sig) (i32.const 0))
+        )
+      )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $f (param i32 i32))
+    (type $sig (func (param i32 i32)))
+    (table funcref (elem $f))
+    (func $type-second-empty-in-then
+      (i32.const 0) (i32.const 0)
+      (if
+        (then
+          (call_indirect (type $sig) (i32.const 0) (i32.const 0))
+        )
+      )
+    )
+  )
+  "type mismatch"
+)
+
+
+;; Unbound type
+
+(assert_invalid
+  (module
+    (table 0 funcref)
+    (func $unbound-type (call_indirect (type 1) (i32.const 0)))
+  )
+  "unknown type"
+)
+(assert_invalid
+  (module
+    (table 0 funcref)
+    (func $large-type (call_indirect (type 1012321300) (i32.const 0)))
+  )
+  "unknown type"
+)
+
+
+;; Unbound function in table
+
+(assert_invalid
+  (module (table funcref (elem 0 0)))
+  "unknown function"
+)
diff --git a/binaryen/test/spec/call_indirect_sig_mismatch.wast b/binaryen/test/spec/call_indirect_sig_mismatch.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/call_indirect_sig_mismatch.wast
@@ -0,0 +1,14 @@
+(module
+  (type $funcref_=>_none (func (param funcref)))
+  (table funcref (elem $callee))
+  (export "sig_mismatch" (func $sig_mismatch))
+  (func $callee (param $0 exnref))
+  (func $sig_mismatch
+    (call_indirect (type $funcref_=>_none)
+      (ref.null func)
+      (i32.const 0)
+    )
+  )
+)
+
+(assert_trap (invoke "sig_mismatch") "callIndirect: function signatures don't match")
diff --git a/binaryen/test/spec/comments.wast b/binaryen/test/spec/comments.wast
new file mode 100644
Binary files /dev/null and b/binaryen/test/spec/comments.wast differ
diff --git a/binaryen/test/spec/const.wast b/binaryen/test/spec/const.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/const.wast
@@ -0,0 +1,1046 @@
+;; Test t.const instructions
+
+;; Syntax error
+
+(module (func (i32.const 0_123_456_789) drop))
+(module (func (i32.const 0x0_9acf_fBDF) drop))
+(assert_malformed
+  (module quote "(func (i32.const) drop)")
+  "unexpected token"
+)
+(assert_malformed
+  (module quote "(func (i32.const 0x) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (i32.const 1x) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (i32.const 0xg) drop)")
+  "unknown operator"
+)
+
+(module (func (i64.const 0_123_456_789) drop))
+(module (func (i64.const 0x0125_6789_ADEF_bcef) drop))
+(assert_malformed
+  (module quote "(func (i64.const) drop)")
+  "unexpected token"
+)
+(assert_malformed
+  (module quote "(func (i64.const 0x) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (i64.const 1x) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (i64.const 0xg) drop)")
+  "unknown operator"
+)
+
+(module (func (f32.const 0123456789) drop))
+(module (func (f32.const 0123456789e019) drop))
+(module (func (f32.const 0123456789e+019) drop))
+(module (func (f32.const 0123456789e-019) drop))
+(module (func (f32.const 0123456789.) drop))
+(module (func (f32.const 0123456789.e019) drop))
+(module (func (f32.const 0123456789.e+019) drop))
+(module (func (f32.const 0123456789.e-019) drop))
+(module (func (f32.const 0123456789.0123456789) drop))
+(module (func (f32.const 0123456789.0123456789e019) drop))
+(module (func (f32.const 0123456789.0123456789e+019) drop))
+(module (func (f32.const 0123456789.0123456789e-019) drop))
+(module (func (f32.const 0x0123456789ABCDEF) drop))
+(module (func (f32.const 0x0123456789ABCDEFp019) drop))
+(module (func (f32.const 0x0123456789ABCDEFp+019) drop))
+(module (func (f32.const 0x0123456789ABCDEFp-019) drop))
+(module (func (f32.const 0x0123456789ABCDEF.) drop))
+(module (func (f32.const 0x0123456789ABCDEF.p019) drop))
+(module (func (f32.const 0x0123456789ABCDEF.p+019) drop))
+(module (func (f32.const 0x0123456789ABCDEF.p-019) drop))
+(module (func (f32.const 0x0123456789ABCDEF.019aF) drop))
+(module (func (f32.const 0x0123456789ABCDEF.019aFp019) drop))
+(module (func (f32.const 0x0123456789ABCDEF.019aFp+019) drop))
+(module (func (f32.const 0x0123456789ABCDEF.019aFp-019) drop))
+(assert_malformed
+  (module quote "(func (f32.const) drop)")
+  "unexpected token"
+)
+(assert_malformed
+  (module quote "(func (f32.const .0) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const .0e0) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0e) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0e+) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0.0e) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0.0e-) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0x) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 1x) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0xg) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0x.) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0x0.g) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0x0p) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0x0p+) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0x0p-) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0x0.0p) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0x0.0p+) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0x0.0p-) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0x0pA) drop)")
+  "unknown operator"
+)
+
+
+(module (func (f64.const 0123456789) drop))
+(module (func (f64.const 0123456789e019) drop))
+(module (func (f64.const 0123456789e+019) drop))
+(module (func (f64.const 0123456789e-019) drop))
+(module (func (f64.const 0123456789.) drop))
+(module (func (f64.const 0123456789.e019) drop))
+(module (func (f64.const 0123456789.e+019) drop))
+(module (func (f64.const 0123456789.e-019) drop))
+(module (func (f64.const 0123456789.0123456789) drop))
+(module (func (f64.const 0123456789.0123456789e019) drop))
+(module (func (f64.const 0123456789.0123456789e+019) drop))
+(module (func (f64.const 0123456789.0123456789e-019) drop))
+(module (func (f64.const 0x0123456789ABCDEFabcdef) drop))
+(module (func (f64.const 0x0123456789ABCDEFabcdefp019) drop))
+(module (func (f64.const 0x0123456789ABCDEFabcdefp+019) drop))
+(module (func (f64.const 0x0123456789ABCDEFabcdefp-019) drop))
+(module (func (f64.const 0x0123456789ABCDEFabcdef.) drop))
+(module (func (f64.const 0x0123456789ABCDEFabcdef.p019) drop))
+(module (func (f64.const 0x0123456789ABCDEFabcdef.p+019) drop))
+(module (func (f64.const 0x0123456789ABCDEFabcdef.p-019) drop))
+(module (func (f64.const 0x0123456789ABCDEFabcdef.0123456789ABCDEFabcdef) drop))
+(module (func (f64.const 0x0123456789ABCDEFabcdef.0123456789ABCDEFabcdefp019) drop))
+(module (func (f64.const 0x0123456789ABCDEFabcdef.0123456789ABCDEFabcdefp+019) drop))
+(module (func (f64.const 0x0123456789ABCDEFabcdef.0123456789ABCDEFabcdefp-019) drop))
+(assert_malformed
+  (module quote "(func (f64.const) drop)")
+  "unexpected token"
+)
+(assert_malformed
+  (module quote "(func (f64.const .0) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const .0e0) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0e) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0e+) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0.0e) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0.0e-) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0x) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 1x) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0xg) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0x.) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0x0.g) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0x0p) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0x0p+) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0x0p-) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0x0.0p) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0x0.0p+) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0x0.0p-) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0x0pA) drop)")
+  "unknown operator"
+)
+
+
+;; Range error
+
+(module (func (i32.const 0xffffffff) drop))
+(module (func (i32.const -0x80000000) drop))
+(assert_malformed
+  (module quote "(func (i32.const 0x100000000) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (i32.const -0x80000001) drop)")
+  "constant out of range"
+)
+
+(module (func (i32.const 4294967295) drop))
+(module (func (i32.const -2147483648) drop))
+(assert_malformed
+  (module quote "(func (i32.const 4294967296) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (i32.const -2147483649) drop)")
+  "constant out of range"
+)
+
+(module (func (i64.const 0xffffffffffffffff) drop))
+(module (func (i64.const -0x8000000000000000) drop))
+(assert_malformed
+  (module quote "(func (i64.const 0x10000000000000000) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (i64.const -0x8000000000000001) drop)")
+  "constant out of range"
+)
+
+(module (func (i64.const 18446744073709551615) drop))
+(module (func (i64.const -9223372036854775808) drop))
+(assert_malformed
+  (module quote "(func (i64.const 18446744073709551616) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (i64.const -9223372036854775809) drop)")
+  "constant out of range"
+)
+
+(module (func (f32.const 0x1p127) drop))
+(module (func (f32.const -0x1p127) drop))
+(module (func (f32.const 0x1.fffffep127) drop))
+(module (func (f32.const -0x1.fffffep127) drop))
+(module (func (f32.const 0x1.fffffe7p127) drop))
+(module (func (f32.const -0x1.fffffe7p127) drop))
+(module (func (f32.const 0x1.fffffefffffff8000000p127) drop))
+(module (func (f32.const -0x1.fffffefffffff8000000p127) drop))
+(module (func (f32.const 0x1.fffffefffffffffffffp127) drop))
+(module (func (f32.const -0x1.fffffefffffffffffffp127) drop))
+(assert_malformed
+  (module quote "(func (f32.const 0x1p128) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (f32.const -0x1p128) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (f32.const 0x1.ffffffp127) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (f32.const -0x1.ffffffp127) drop)")
+  "constant out of range"
+)
+
+(module (func (f32.const 1e38) drop))
+(module (func (f32.const -1e38) drop))
+(assert_malformed
+  (module quote "(func (f32.const 1e39) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (f32.const -1e39) drop)")
+  "constant out of range"
+)
+
+(module (func (f32.const 340282356779733623858607532500980858880) drop))
+(module (func (f32.const -340282356779733623858607532500980858880) drop))
+(assert_malformed
+  (module quote "(func (f32.const 340282356779733661637539395458142568448) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (f32.const -340282356779733661637539395458142568448) drop)")
+  "constant out of range"
+)
+
+(module (func (f64.const 0x1p1023) drop))
+(module (func (f64.const -0x1p1023) drop))
+(module (func (f64.const 0x1.fffffffffffffp1023) drop))
+(module (func (f64.const -0x1.fffffffffffffp1023) drop))
+(module (func (f64.const 0x1.fffffffffffff7p1023) drop))
+(module (func (f64.const -0x1.fffffffffffff7p1023) drop))
+(module (func (f64.const 0x1.fffffffffffff7ffffffp1023) drop))
+(module (func (f64.const -0x1.fffffffffffff7ffffffp1023) drop))
+(assert_malformed
+  (module quote "(func (f64.const 0x1p1024) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (f64.const -0x1p1024) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (f64.const 0x1.fffffffffffff8p1023) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (f64.const -0x1.fffffffffffff8p1023) drop)")
+  "constant out of range"
+)
+
+(module (func (f64.const 1e308) drop))
+(module (func (f64.const -1e308) drop))
+(assert_malformed
+  (module quote "(func (f64.const 1e309) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (f64.const -1e309) drop)")
+  "constant out of range"
+)
+
+(module (func (f64.const 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368) drop))
+(module (func (f64.const -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368) drop))
+(assert_malformed
+  (module quote "(func (f64.const 269653970229347356221791135597556535197105851288767494898376215204735891170042808140884337949150317257310688430271573696351481990334196274152701320055306275479074865864826923114368235135583993416113802762682700913456874855354834422248712838998185022412196739306217084753107265771378949821875606039276187287552) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (f64.const -269653970229347356221791135597556535197105851288767494898376215204735891170042808140884337949150317257310688430271573696351481990334196274152701320055306275479074865864826923114368235135583993416113802762682700913456874855354834422248712838998185022412196739306217084753107265771378949821875606039276187287552) drop)")
+  "constant out of range"
+)
+
+(module (func (f32.const nan:0x1) drop))
+(module (func (f64.const nan:0x1) drop))
+(module (func (f32.const nan:0x7f_ffff) drop))
+(module (func (f64.const nan:0xf_ffff_ffff_ffff) drop))
+
+(assert_malformed
+  (module quote "(func (f32.const nan:1) drop)")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func (f64.const nan:1) drop)")
+  "unknown operator"
+)
+
+(assert_malformed
+  (module quote "(func (f32.const nan:0x0) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (f64.const nan:0x0) drop)")
+  "constant out of range"
+)
+
+(assert_malformed
+  (module quote "(func (f32.const nan:0x80_0000) drop)")
+  "constant out of range"
+)
+(assert_malformed
+  (module quote "(func (f64.const nan:0x10_0000_0000_0000) drop)")
+  "constant out of range"
+)
+
+
+;; Rounding behaviour
+
+;; f32, small exponent
+(module (func (export "f") (result f32) (f32.const +0x1.00000100000000000p-50)))
+(assert_return (invoke "f") (f32.const +0x1.000000p-50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000100000000000p-50)))
+(assert_return (invoke "f") (f32.const -0x1.000000p-50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000100000000001p-50)))
+(assert_return (invoke "f") (f32.const +0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000100000000001p-50)))
+(assert_return (invoke "f") (f32.const -0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const +0x1.000001fffffffffffp-50)))
+(assert_return (invoke "f") (f32.const +0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const -0x1.000001fffffffffffp-50)))
+(assert_return (invoke "f") (f32.const -0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000200000000000p-50)))
+(assert_return (invoke "f") (f32.const +0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000200000000000p-50)))
+(assert_return (invoke "f") (f32.const -0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000200000000001p-50)))
+(assert_return (invoke "f") (f32.const +0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000200000000001p-50)))
+(assert_return (invoke "f") (f32.const -0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const +0x1.000002fffffffffffp-50)))
+(assert_return (invoke "f") (f32.const +0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const -0x1.000002fffffffffffp-50)))
+(assert_return (invoke "f") (f32.const -0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000300000000000p-50)))
+(assert_return (invoke "f") (f32.const +0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000300000000000p-50)))
+(assert_return (invoke "f") (f32.const -0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000300000000001p-50)))
+(assert_return (invoke "f") (f32.const +0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000300000000001p-50)))
+(assert_return (invoke "f") (f32.const -0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const +0x1.000003fffffffffffp-50)))
+(assert_return (invoke "f") (f32.const +0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const -0x1.000003fffffffffffp-50)))
+(assert_return (invoke "f") (f32.const -0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000400000000000p-50)))
+(assert_return (invoke "f") (f32.const +0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000400000000000p-50)))
+(assert_return (invoke "f") (f32.const -0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000400000000001p-50)))
+(assert_return (invoke "f") (f32.const +0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000400000000001p-50)))
+(assert_return (invoke "f") (f32.const -0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const +0x1.000004fffffffffffp-50)))
+(assert_return (invoke "f") (f32.const +0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const -0x1.000004fffffffffffp-50)))
+(assert_return (invoke "f") (f32.const -0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000500000000000p-50)))
+(assert_return (invoke "f") (f32.const +0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000500000000000p-50)))
+(assert_return (invoke "f") (f32.const -0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000500000000001p-50)))
+(assert_return (invoke "f") (f32.const +0x1.000006p-50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000500000000001p-50)))
+(assert_return (invoke "f") (f32.const -0x1.000006p-50))
+
+(module (func (export "f") (result f32) (f32.const +0x4000.004000000p-64)))
+(assert_return (invoke "f") (f32.const +0x1.000000p-50))
+(module (func (export "f") (result f32) (f32.const -0x4000.004000000p-64)))
+(assert_return (invoke "f") (f32.const -0x1.000000p-50))
+(module (func (export "f") (result f32) (f32.const +0x4000.004000001p-64)))
+(assert_return (invoke "f") (f32.const +0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const -0x4000.004000001p-64)))
+(assert_return (invoke "f") (f32.const -0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const +0x4000.007ffffffp-64)))
+(assert_return (invoke "f") (f32.const +0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const -0x4000.007ffffffp-64)))
+(assert_return (invoke "f") (f32.const -0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const +0x4000.008000000p-64)))
+(assert_return (invoke "f") (f32.const +0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const -0x4000.008000000p-64)))
+(assert_return (invoke "f") (f32.const -0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const +0x4000.008000001p-64)))
+(assert_return (invoke "f") (f32.const +0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const -0x4000.008000001p-64)))
+(assert_return (invoke "f") (f32.const -0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const +0x4000.00bffffffp-64)))
+(assert_return (invoke "f") (f32.const +0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const -0x4000.00bffffffp-64)))
+(assert_return (invoke "f") (f32.const -0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const +0x4000.00c000000p-64)))
+(assert_return (invoke "f") (f32.const +0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const -0x4000.00c000000p-64)))
+(assert_return (invoke "f") (f32.const -0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const +0x4000.00c000001p-64)))
+(assert_return (invoke "f") (f32.const +0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const -0x4000.00c000001p-64)))
+(assert_return (invoke "f") (f32.const -0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const +0x4000.00fffffffp-64)))
+(assert_return (invoke "f") (f32.const +0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const -0x4000.00fffffffp-64)))
+(assert_return (invoke "f") (f32.const -0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const +0x4000.010000001p-64)))
+(assert_return (invoke "f") (f32.const +0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const -0x4000.010000001p-64)))
+(assert_return (invoke "f") (f32.const -0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const +0x4000.013ffffffp-64)))
+(assert_return (invoke "f") (f32.const +0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const -0x4000.013ffffffp-64)))
+(assert_return (invoke "f") (f32.const -0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const +0x4000.014000001p-64)))
+(assert_return (invoke "f") (f32.const +0x1.000006p-50))
+(module (func (export "f") (result f32) (f32.const -0x4000.014000001p-64)))
+(assert_return (invoke "f") (f32.const -0x1.000006p-50))
+
+(module (func (export "f") (result f32) (f32.const +8.8817847263968443573e-16)))
+(assert_return (invoke "f") (f32.const +0x1.000000p-50))
+(module (func (export "f") (result f32) (f32.const -8.8817847263968443573e-16)))
+(assert_return (invoke "f") (f32.const -0x1.000000p-50))
+(module (func (export "f") (result f32) (f32.const +8.8817847263968443574e-16)))
+(assert_return (invoke "f") (f32.const +0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const -8.8817847263968443574e-16)))
+(assert_return (invoke "f") (f32.const -0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const +8.8817857851880284252e-16)))
+(assert_return (invoke "f") (f32.const +0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const -8.8817857851880284252e-16)))
+(assert_return (invoke "f") (f32.const -0x1.000002p-50))
+(module (func (export "f") (result f32) (f32.const +8.8817857851880284253e-16)))
+(assert_return (invoke "f") (f32.const +0x1.000004p-50))
+(module (func (export "f") (result f32) (f32.const -8.8817857851880284253e-16)))
+(assert_return (invoke "f") (f32.const -0x1.000004p-50))
+
+;; f32, large exponent
+(module (func (export "f") (result f32) (f32.const +0x1.00000100000000000p+50)))
+(assert_return (invoke "f") (f32.const +0x1.000000p+50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000100000000000p+50)))
+(assert_return (invoke "f") (f32.const -0x1.000000p+50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000100000000001p+50)))
+(assert_return (invoke "f") (f32.const +0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000100000000001p+50)))
+(assert_return (invoke "f") (f32.const -0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const +0x1.000001fffffffffffp+50)))
+(assert_return (invoke "f") (f32.const +0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const -0x1.000001fffffffffffp+50)))
+(assert_return (invoke "f") (f32.const -0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000200000000000p+50)))
+(assert_return (invoke "f") (f32.const +0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000200000000000p+50)))
+(assert_return (invoke "f") (f32.const -0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000200000000001p+50)))
+(assert_return (invoke "f") (f32.const +0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000200000000001p+50)))
+(assert_return (invoke "f") (f32.const -0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const +0x1.000002fffffffffffp+50)))
+(assert_return (invoke "f") (f32.const +0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const -0x1.000002fffffffffffp+50)))
+(assert_return (invoke "f") (f32.const -0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000300000000000p+50)))
+(assert_return (invoke "f") (f32.const +0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000300000000000p+50)))
+(assert_return (invoke "f") (f32.const -0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000300000000001p+50)))
+(assert_return (invoke "f") (f32.const +0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000300000000001p+50)))
+(assert_return (invoke "f") (f32.const -0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const +0x1.000003fffffffffffp+50)))
+(assert_return (invoke "f") (f32.const +0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const -0x1.000003fffffffffffp+50)))
+(assert_return (invoke "f") (f32.const -0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000400000000000p+50)))
+(assert_return (invoke "f") (f32.const +0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000400000000000p+50)))
+(assert_return (invoke "f") (f32.const -0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000400000000001p+50)))
+(assert_return (invoke "f") (f32.const +0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000400000000001p+50)))
+(assert_return (invoke "f") (f32.const -0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const +0x1.000004fffffffffffp+50)))
+(assert_return (invoke "f") (f32.const +0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const -0x1.000004fffffffffffp+50)))
+(assert_return (invoke "f") (f32.const -0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000500000000000p+50)))
+(assert_return (invoke "f") (f32.const +0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000500000000000p+50)))
+(assert_return (invoke "f") (f32.const -0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const +0x1.00000500000000001p+50)))
+(assert_return (invoke "f") (f32.const +0x1.000006p+50))
+(module (func (export "f") (result f32) (f32.const -0x1.00000500000000001p+50)))
+(assert_return (invoke "f") (f32.const -0x1.000006p+50))
+
+(module (func (export "f") (result f32) (f32.const +0x4000004000000)))
+(assert_return (invoke "f") (f32.const +0x1.000000p+50))
+(module (func (export "f") (result f32) (f32.const -0x4000004000000)))
+(assert_return (invoke "f") (f32.const -0x1.000000p+50))
+(module (func (export "f") (result f32) (f32.const +0x4000004000001)))
+(assert_return (invoke "f") (f32.const +0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const -0x4000004000001)))
+(assert_return (invoke "f") (f32.const -0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const +0x4000007ffffff)))
+(assert_return (invoke "f") (f32.const +0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const -0x4000007ffffff)))
+(assert_return (invoke "f") (f32.const -0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const +0x4000008000000)))
+(assert_return (invoke "f") (f32.const +0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const -0x4000008000000)))
+(assert_return (invoke "f") (f32.const -0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const +0x4000008000001)))
+(assert_return (invoke "f") (f32.const +0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const -0x4000008000001)))
+(assert_return (invoke "f") (f32.const -0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const +0x400000bffffff)))
+(assert_return (invoke "f") (f32.const +0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const -0x400000bffffff)))
+(assert_return (invoke "f") (f32.const -0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const +0x400000c000000)))
+(assert_return (invoke "f") (f32.const +0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const -0x400000c000000)))
+(assert_return (invoke "f") (f32.const -0x1.000004p+50))
+
+(module (func (export "f") (result f32) (f32.const +1125899973951488)))
+(assert_return (invoke "f") (f32.const +0x1.000000p+50))
+(module (func (export "f") (result f32) (f32.const -1125899973951488)))
+(assert_return (invoke "f") (f32.const -0x1.000000p+50))
+(module (func (export "f") (result f32) (f32.const +1125899973951489)))
+(assert_return (invoke "f") (f32.const +0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const -1125899973951489)))
+(assert_return (invoke "f") (f32.const -0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const +1125900108169215)))
+(assert_return (invoke "f") (f32.const +0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const -1125900108169215)))
+(assert_return (invoke "f") (f32.const -0x1.000002p+50))
+(module (func (export "f") (result f32) (f32.const +1125900108169216)))
+(assert_return (invoke "f") (f32.const +0x1.000004p+50))
+(module (func (export "f") (result f32) (f32.const -1125900108169216)))
+(assert_return (invoke "f") (f32.const -0x1.000004p+50))
+
+;; f32, subnormal
+(module (func (export "f") (result f32) (f32.const +0x0.00000100000000000p-126)))
+(assert_return (invoke "f") (f32.const +0x0.000000p-126))
+(module (func (export "f") (result f32) (f32.const -0x0.00000100000000000p-126)))
+(assert_return (invoke "f") (f32.const -0x0.000000p-126))
+(module (func (export "f") (result f32) (f32.const +0x0.00000100000000001p-126)))
+(assert_return (invoke "f") (f32.const +0x0.000002p-126))
+(module (func (export "f") (result f32) (f32.const -0x0.00000100000000001p-126)))
+(assert_return (invoke "f") (f32.const -0x0.000002p-126))
+(module (func (export "f") (result f32) (f32.const +0x0.000001fffffffffffp-126)))
+(assert_return (invoke "f") (f32.const +0x0.000002p-126))
+(module (func (export "f") (result f32) (f32.const -0x0.000001fffffffffffp-126)))
+(assert_return (invoke "f") (f32.const -0x0.000002p-126))
+(module (func (export "f") (result f32) (f32.const +0x0.00000200000000000p-126)))
+(assert_return (invoke "f") (f32.const +0x0.000002p-126))
+(module (func (export "f") (result f32) (f32.const -0x0.00000200000000000p-126)))
+(assert_return (invoke "f") (f32.const -0x0.000002p-126))
+(module (func (export "f") (result f32) (f32.const +0x0.00000200000000001p-126)))
+(assert_return (invoke "f") (f32.const +0x0.000002p-126))
+(module (func (export "f") (result f32) (f32.const -0x0.00000200000000001p-126)))
+(assert_return (invoke "f") (f32.const -0x0.000002p-126))
+(module (func (export "f") (result f32) (f32.const +0x0.000002fffffffffffp-126)))
+(assert_return (invoke "f") (f32.const +0x0.000002p-126))
+(module (func (export "f") (result f32) (f32.const -0x0.000002fffffffffffp-126)))
+(assert_return (invoke "f") (f32.const -0x0.000002p-126))
+(module (func (export "f") (result f32) (f32.const +0x0.00000300000000000p-126)))
+(assert_return (invoke "f") (f32.const +0x0.000004p-126))
+(module (func (export "f") (result f32) (f32.const -0x0.00000300000000000p-126)))
+(assert_return (invoke "f") (f32.const -0x0.000004p-126))
+(module (func (export "f") (result f32) (f32.const +0x0.00000300000000001p-126)))
+(assert_return (invoke "f") (f32.const +0x0.000004p-126))
+(module (func (export "f") (result f32) (f32.const -0x0.00000300000000001p-126)))
+(assert_return (invoke "f") (f32.const -0x0.000004p-126))
+(module (func (export "f") (result f32) (f32.const +0x0.000003fffffffffffp-126)))
+(assert_return (invoke "f") (f32.const +0x0.000004p-126))
+(module (func (export "f") (result f32) (f32.const -0x0.000003fffffffffffp-126)))
+(assert_return (invoke "f") (f32.const -0x0.000004p-126))
+(module (func (export "f") (result f32) (f32.const +0x0.00000400000000000p-126)))
+(assert_return (invoke "f") (f32.const +0x0.000004p-126))
+(module (func (export "f") (result f32) (f32.const -0x0.00000400000000000p-126)))
+(assert_return (invoke "f") (f32.const -0x0.000004p-126))
+(module (func (export "f") (result f32) (f32.const +0x0.00000400000000001p-126)))
+(assert_return (invoke "f") (f32.const +0x0.000004p-126))
+(module (func (export "f") (result f32) (f32.const -0x0.00000400000000001p-126)))
+(assert_return (invoke "f") (f32.const -0x0.000004p-126))
+(module (func (export "f") (result f32) (f32.const +0x0.000004fffffffffffp-126)))
+(assert_return (invoke "f") (f32.const +0x0.000004p-126))
+(module (func (export "f") (result f32) (f32.const -0x0.000004fffffffffffp-126)))
+(assert_return (invoke "f") (f32.const -0x0.000004p-126))
+(module (func (export "f") (result f32) (f32.const +0x0.00000500000000000p-126)))
+(assert_return (invoke "f") (f32.const +0x0.000004p-126))
+(module (func (export "f") (result f32) (f32.const -0x0.00000500000000000p-126)))
+(assert_return (invoke "f") (f32.const -0x0.000004p-126))
+(module (func (export "f") (result f32) (f32.const +0x0.00000500000000001p-126)))
+(assert_return (invoke "f") (f32.const +0x0.000006p-126))
+(module (func (export "f") (result f32) (f32.const -0x0.00000500000000001p-126)))
+(assert_return (invoke "f") (f32.const -0x0.000006p-126))
+
+;; f32, round down at limit to infinity
+(module (func (export "f") (result f32) (f32.const +0x1.fffffe8p127)))
+(assert_return (invoke "f") (f32.const +0x1.fffffep127))
+(module (func (export "f") (result f32) (f32.const -0x1.fffffe8p127)))
+(assert_return (invoke "f") (f32.const -0x1.fffffep127))
+(module (func (export "f") (result f32) (f32.const +0x1.fffffefffffff8p127)))
+(assert_return (invoke "f") (f32.const +0x1.fffffep127))
+(module (func (export "f") (result f32) (f32.const -0x1.fffffefffffff8p127)))
+(assert_return (invoke "f") (f32.const -0x1.fffffep127))
+(module (func (export "f") (result f32) (f32.const +0x1.fffffefffffffffffp127)))
+(assert_return (invoke "f") (f32.const +0x1.fffffep127))
+(module (func (export "f") (result f32) (f32.const -0x1.fffffefffffffffffp127)))
+(assert_return (invoke "f") (f32.const -0x1.fffffep127))
+
+;; f64, small exponent
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000080000000000p-600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000000p-600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000080000000000p-600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000000p-600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000080000000001p-600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000080000000001p-600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const +0x1.0000000000000fffffffffffp-600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const -0x1.0000000000000fffffffffffp-600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000100000000000p-600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000100000000000p-600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000100000000001p-600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000100000000001p-600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const +0x1.00000000000017ffffffffffp-600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const -0x1.00000000000017ffffffffffp-600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000180000000000p-600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000180000000000p-600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000180000000001p-600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000180000000001p-600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const +0x1.0000000000001fffffffffffp-600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const -0x1.0000000000001fffffffffffp-600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000200000000000p-600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000200000000000p-600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000200000000001p-600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000200000000001p-600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const +0x1.00000000000027ffffffffffp-600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const -0x1.00000000000027ffffffffffp-600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000280000000001p-600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000003p-600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000280000000001p-600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000003p-600))
+
+(module (func (export "f") (result f64) (f64.const +0x8000000.000000400000000000p-627)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000000p-600))
+(module (func (export "f") (result f64) (f64.const -0x8000000.000000400000000000p-627)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000000p-600))
+(module (func (export "f") (result f64) (f64.const +0x8000000.000000400000000001p-627)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const -0x8000000.000000400000000001p-627)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const +0x8000000.0000007fffffffffffp-627)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const -0x8000000.0000007fffffffffffp-627)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const +0x8000000.000000800000000000p-627)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const -0x8000000.000000800000000000p-627)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const +0x8000000.000000800000000001p-627)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const -0x8000000.000000800000000001p-627)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const +0x8000000.000000bfffffffffffp-627)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const -0x8000000.000000bfffffffffffp-627)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p-600))
+(module (func (export "f") (result f64) (f64.const +0x8000000.000000c00000000000p-627)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const -0x8000000.000000c00000000000p-627)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const +0x8000000.000000c00000000001p-627)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const -0x8000000.000000c00000000001p-627)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const +0x8000000.000000ffffffffffffp-627)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const -0x8000000.000000ffffffffffffp-627)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const +0x8000000.000001000000000000p-627)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const -0x8000000.000001000000000000p-627)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const +0x8000000.000001000000000001p-627)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const -0x8000000.000001000000000001p-627)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const +0x8000000.0000013fffffffffffp-627)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const -0x8000000.0000013fffffffffffp-627)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p-600))
+(module (func (export "f") (result f64) (f64.const +0x8000000.000001400000000001p-627)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000003p-600))
+(module (func (export "f") (result f64) (f64.const -0x8000000.000001400000000001p-627)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000003p-600))
+
+(module (func (export "f") (result f64) (f64.const +5.3575430359313371995e+300)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000000p+999))
+(module (func (export "f") (result f64) (f64.const -5.3575430359313371995e+300)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000000p+999))
+(module (func (export "f") (result f64) (f64.const +5.3575430359313371996e+300)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p+999))
+(module (func (export "f") (result f64) (f64.const -5.3575430359313371996e+300)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p+999))
+(module (func (export "f") (result f64) (f64.const +5.3575430359313383891e+300)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p+999))
+(module (func (export "f") (result f64) (f64.const -5.3575430359313383891e+300)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p+999))
+(module (func (export "f") (result f64) (f64.const +5.3575430359313383892e+300)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+999))
+(module (func (export "f") (result f64) (f64.const -5.3575430359313383892e+300)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+999))
+
+;; f64, large exponent
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000080000000000p+600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000000p+600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000080000000000p+600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000000p+600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000080000000001p+600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p+600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000080000000001p+600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p+600))
+(module (func (export "f") (result f64) (f64.const +0x1.0000000000000fffffffffffp+600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p+600))
+(module (func (export "f") (result f64) (f64.const -0x1.0000000000000fffffffffffp+600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p+600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000100000000000p+600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p+600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000100000000000p+600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p+600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000100000000001p+600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p+600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000100000000001p+600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p+600))
+(module (func (export "f") (result f64) (f64.const +0x1.00000000000017ffffffffffp+600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p+600))
+(module (func (export "f") (result f64) (f64.const -0x1.00000000000017ffffffffffp+600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p+600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000180000000000p+600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000180000000000p+600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000180000000001p+600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000180000000001p+600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+600))
+(module (func (export "f") (result f64) (f64.const +0x1.0000000000001fffffffffffp+600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+600))
+(module (func (export "f") (result f64) (f64.const -0x1.0000000000001fffffffffffp+600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000200000000000p+600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000200000000000p+600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000200000000001p+600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000200000000001p+600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+600))
+(module (func (export "f") (result f64) (f64.const +0x1.00000000000027ffffffffffp+600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+600))
+(module (func (export "f") (result f64) (f64.const -0x1.00000000000027ffffffffffp+600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000280000000000p+600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000280000000000p+600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+600))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000280000000001p+600)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000003p+600))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000280000000001p+600)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000003p+600))
+
+(module (func (export "f") (result f64) (f64.const +0x2000000000000100000000000)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000000p+97))
+(module (func (export "f") (result f64) (f64.const -0x2000000000000100000000000)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000000p+97))
+(module (func (export "f") (result f64) (f64.const +0x2000000000000100000000001)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p+97))
+(module (func (export "f") (result f64) (f64.const -0x2000000000000100000000001)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p+97))
+(module (func (export "f") (result f64) (f64.const +0x20000000000001fffffffffff)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p+97))
+(module (func (export "f") (result f64) (f64.const -0x20000000000001fffffffffff)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p+97))
+(module (func (export "f") (result f64) (f64.const +0x2000000000000200000000000)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p+97))
+(module (func (export "f") (result f64) (f64.const -0x2000000000000200000000000)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p+97))
+(module (func (export "f") (result f64) (f64.const +0x2000000000000200000000001)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p+97))
+(module (func (export "f") (result f64) (f64.const -0x2000000000000200000000001)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p+97))
+(module (func (export "f") (result f64) (f64.const +0x20000000000002fffffffffff)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p+97))
+(module (func (export "f") (result f64) (f64.const -0x20000000000002fffffffffff)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p+97))
+(module (func (export "f") (result f64) (f64.const +0x2000000000000300000000000)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+97))
+(module (func (export "f") (result f64) (f64.const -0x2000000000000300000000000)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+97))
+(module (func (export "f") (result f64) (f64.const +0x2000000000000300000000001)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+97))
+(module (func (export "f") (result f64) (f64.const -0x2000000000000300000000001)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+97))
+(module (func (export "f") (result f64) (f64.const +0x20000000000003fffffffffff)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+97))
+(module (func (export "f") (result f64) (f64.const -0x20000000000003fffffffffff)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+97))
+(module (func (export "f") (result f64) (f64.const +0x2000000000000400000000000)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+97))
+(module (func (export "f") (result f64) (f64.const -0x2000000000000400000000000)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+97))
+(module (func (export "f") (result f64) (f64.const +0x2000000000000400000000001)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+97))
+(module (func (export "f") (result f64) (f64.const -0x2000000000000400000000001)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+97))
+(module (func (export "f") (result f64) (f64.const +0x20000000000004fffffffffff)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+97))
+(module (func (export "f") (result f64) (f64.const -0x20000000000004fffffffffff)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+97))
+(module (func (export "f") (result f64) (f64.const +0x2000000000000500000000000)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+97))
+(module (func (export "f") (result f64) (f64.const -0x2000000000000500000000000)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+97))
+(module (func (export "f") (result f64) (f64.const +0x2000000000000500000000001)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000003p+97))
+(module (func (export "f") (result f64) (f64.const -0x2000000000000500000000001)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000003p+97))
+
+(module (func (export "f") (result f64) (f64.const +1152921504606847104)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000000p+60))
+(module (func (export "f") (result f64) (f64.const -1152921504606847104)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000000p+60))
+(module (func (export "f") (result f64) (f64.const +1152921504606847105)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p+60))
+(module (func (export "f") (result f64) (f64.const -1152921504606847105)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p+60))
+(module (func (export "f") (result f64) (f64.const +1152921504606847359)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000001p+60))
+(module (func (export "f") (result f64) (f64.const -1152921504606847359)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000001p+60))
+(module (func (export "f") (result f64) (f64.const +1152921504606847360)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000002p+60))
+(module (func (export "f") (result f64) (f64.const -1152921504606847360)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000002p+60))
+
+;; f64, subnormal
+(module (func (export "f") (result f64) (f64.const +0x0.000000000000080000000000p-1022)))
+(assert_return (invoke "f") (f64.const +0x0.0000000000000p-1022))
+(module (func (export "f") (result f64) (f64.const -0x0.000000000000080000000000p-1022)))
+(assert_return (invoke "f") (f64.const -0x0.0000000000000p-1022))
+(module (func (export "f") (result f64) (f64.const +0x0.000000000000080000000001p-1022)))
+(assert_return (invoke "f") (f64.const +0x0.0000000000001p-1022))
+(module (func (export "f") (result f64) (f64.const -0x0.000000000000080000000001p-1022)))
+(assert_return (invoke "f") (f64.const -0x0.0000000000001p-1022))
+(module (func (export "f") (result f64) (f64.const +0x0.0000000000000fffffffffffp-1022)))
+(assert_return (invoke "f") (f64.const +0x0.0000000000001p-1022))
+(module (func (export "f") (result f64) (f64.const -0x0.0000000000000fffffffffffp-1022)))
+(assert_return (invoke "f") (f64.const -0x0.0000000000001p-1022))
+(module (func (export "f") (result f64) (f64.const +0x0.000000000000100000000000p-1022)))
+(assert_return (invoke "f") (f64.const +0x0.0000000000001p-1022))
+(module (func (export "f") (result f64) (f64.const -0x0.000000000000100000000000p-1022)))
+(assert_return (invoke "f") (f64.const -0x0.0000000000001p-1022))
+(module (func (export "f") (result f64) (f64.const +0x0.000000000000100000000001p-1022)))
+(assert_return (invoke "f") (f64.const +0x0.0000000000001p-1022))
+(module (func (export "f") (result f64) (f64.const -0x0.000000000000100000000001p-1022)))
+(assert_return (invoke "f") (f64.const -0x0.0000000000001p-1022))
+(module (func (export "f") (result f64) (f64.const +0x0.00000000000017ffffffffffp-1022)))
+(assert_return (invoke "f") (f64.const +0x0.0000000000001p-1022))
+(module (func (export "f") (result f64) (f64.const -0x0.00000000000017ffffffffffp-1022)))
+(assert_return (invoke "f") (f64.const -0x0.0000000000001p-1022))
+(module (func (export "f") (result f64) (f64.const +0x0.000000000000180000000000p-1022)))
+(assert_return (invoke "f") (f64.const +0x0.0000000000002p-1022))
+(module (func (export "f") (result f64) (f64.const -0x0.000000000000180000000000p-1022)))
+(assert_return (invoke "f") (f64.const -0x0.0000000000002p-1022))
+(module (func (export "f") (result f64) (f64.const +0x0.000000000000180000000001p-1022)))
+(assert_return (invoke "f") (f64.const +0x0.0000000000002p-1022))
+(module (func (export "f") (result f64) (f64.const -0x0.000000000000180000000001p-1022)))
+(assert_return (invoke "f") (f64.const -0x0.0000000000002p-1022))
+(module (func (export "f") (result f64) (f64.const +0x0.0000000000001fffffffffffp-1022)))
+(assert_return (invoke "f") (f64.const +0x0.0000000000002p-1022))
+(module (func (export "f") (result f64) (f64.const -0x0.0000000000001fffffffffffp-1022)))
+(assert_return (invoke "f") (f64.const -0x0.0000000000002p-1022))
+(module (func (export "f") (result f64) (f64.const +0x0.000000000000200000000000p-1022)))
+(assert_return (invoke "f") (f64.const +0x0.0000000000002p-1022))
+(module (func (export "f") (result f64) (f64.const -0x0.000000000000200000000000p-1022)))
+(assert_return (invoke "f") (f64.const -0x0.0000000000002p-1022))
+(module (func (export "f") (result f64) (f64.const +0x0.000000000000200000000001p-1022)))
+(assert_return (invoke "f") (f64.const +0x0.0000000000002p-1022))
+(module (func (export "f") (result f64) (f64.const -0x0.000000000000200000000001p-1022)))
+(assert_return (invoke "f") (f64.const -0x0.0000000000002p-1022))
+(module (func (export "f") (result f64) (f64.const +0x0.00000000000027ffffffffffp-1022)))
+(assert_return (invoke "f") (f64.const +0x0.0000000000002p-1022))
+(module (func (export "f") (result f64) (f64.const -0x0.00000000000027ffffffffffp-1022)))
+(assert_return (invoke "f") (f64.const -0x0.0000000000002p-1022))
+(module (func (export "f") (result f64) (f64.const +0x0.000000000000280000000000p-1022)))
+(assert_return (invoke "f") (f64.const +0x0.0000000000002p-1022))
+(module (func (export "f") (result f64) (f64.const -0x0.000000000000280000000000p-1022)))
+(assert_return (invoke "f") (f64.const -0x0.0000000000002p-1022))
+(module (func (export "f") (result f64) (f64.const +0x1.000000000000280000000001p-1022)))
+(assert_return (invoke "f") (f64.const +0x1.0000000000003p-1022))
+(module (func (export "f") (result f64) (f64.const -0x1.000000000000280000000001p-1022)))
+(assert_return (invoke "f") (f64.const -0x1.0000000000003p-1022))
+
+;; f64, round down at limit to infinity
+(module (func (export "f") (result f64) (f64.const +0x1.fffffffffffff4p1023)))
+(assert_return (invoke "f") (f64.const +0x1.fffffffffffffp1023))
+(module (func (export "f") (result f64) (f64.const -0x1.fffffffffffff4p1023)))
+(assert_return (invoke "f") (f64.const -0x1.fffffffffffffp1023))
+(module (func (export "f") (result f64) (f64.const +0x1.fffffffffffff7ffffffp1023)))
+(assert_return (invoke "f") (f64.const +0x1.fffffffffffffp1023))
+(module (func (export "f") (result f64) (f64.const -0x1.fffffffffffff7ffffffp1023)))
+(assert_return (invoke "f") (f64.const -0x1.fffffffffffffp1023))
diff --git a/binaryen/test/spec/conversions.wast b/binaryen/test/spec/conversions.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/conversions.wast
@@ -0,0 +1,515 @@
+(module
+  (func (export "i64.extend_i32_s") (param $x i32) (result i64) (i64.extend_i32_s (local.get $x)))
+  (func (export "i64.extend_i32_u") (param $x i32) (result i64) (i64.extend_i32_u (local.get $x)))
+  (func (export "i32.wrap_i64") (param $x i64) (result i32) (i32.wrap_i64 (local.get $x)))
+  (func (export "i32.trunc_f32_s") (param $x f32) (result i32) (i32.trunc_f32_s (local.get $x)))
+  (func (export "i32.trunc_f32_u") (param $x f32) (result i32) (i32.trunc_f32_u (local.get $x)))
+  (func (export "i32.trunc_f64_s") (param $x f64) (result i32) (i32.trunc_f64_s (local.get $x)))
+  (func (export "i32.trunc_f64_u") (param $x f64) (result i32) (i32.trunc_f64_u (local.get $x)))
+  (func (export "i64.trunc_f32_s") (param $x f32) (result i64) (i64.trunc_f32_s (local.get $x)))
+  (func (export "i64.trunc_f32_u") (param $x f32) (result i64) (i64.trunc_f32_u (local.get $x)))
+  (func (export "i64.trunc_f64_s") (param $x f64) (result i64) (i64.trunc_f64_s (local.get $x)))
+  (func (export "i64.trunc_f64_u") (param $x f64) (result i64) (i64.trunc_f64_u (local.get $x)))
+  (func (export "f32.convert_i32_s") (param $x i32) (result f32) (f32.convert_i32_s (local.get $x)))
+  (func (export "f32.convert_i64_s") (param $x i64) (result f32) (f32.convert_i64_s (local.get $x)))
+  (func (export "f64.convert_i32_s") (param $x i32) (result f64) (f64.convert_i32_s (local.get $x)))
+  (func (export "f64.convert_i64_s") (param $x i64) (result f64) (f64.convert_i64_s (local.get $x)))
+  (func (export "f32.convert_i32_u") (param $x i32) (result f32) (f32.convert_i32_u (local.get $x)))
+  (func (export "f32.convert_i64_u") (param $x i64) (result f32) (f32.convert_i64_u (local.get $x)))
+  (func (export "f64.convert_i32_u") (param $x i32) (result f64) (f64.convert_i32_u (local.get $x)))
+  (func (export "f64.convert_i64_u") (param $x i64) (result f64) (f64.convert_i64_u (local.get $x)))
+  (func (export "f64.promote_f32") (param $x f32) (result f64) (f64.promote_f32 (local.get $x)))
+  (func (export "f32.demote_f64") (param $x f64) (result f32) (f32.demote_f64 (local.get $x)))
+  (func (export "f32.reinterpret_i32") (param $x i32) (result f32) (f32.reinterpret_i32 (local.get $x)))
+  (func (export "f64.reinterpret_i64") (param $x i64) (result f64) (f64.reinterpret_i64 (local.get $x)))
+  (func (export "i32.reinterpret_f32") (param $x f32) (result i32) (i32.reinterpret_f32 (local.get $x)))
+  (func (export "i64.reinterpret_f64") (param $x f64) (result i64) (i64.reinterpret_f64 (local.get $x)))
+)
+
+(assert_return (invoke "i64.extend_i32_s" (i32.const 0)) (i64.const 0))
+(assert_return (invoke "i64.extend_i32_s" (i32.const 10000)) (i64.const 10000))
+(assert_return (invoke "i64.extend_i32_s" (i32.const -10000)) (i64.const -10000))
+(assert_return (invoke "i64.extend_i32_s" (i32.const -1)) (i64.const -1))
+(assert_return (invoke "i64.extend_i32_s" (i32.const 0x7fffffff)) (i64.const 0x000000007fffffff))
+(assert_return (invoke "i64.extend_i32_s" (i32.const 0x80000000)) (i64.const 0xffffffff80000000))
+
+(assert_return (invoke "i64.extend_i32_u" (i32.const 0)) (i64.const 0))
+(assert_return (invoke "i64.extend_i32_u" (i32.const 10000)) (i64.const 10000))
+(assert_return (invoke "i64.extend_i32_u" (i32.const -10000)) (i64.const 0x00000000ffffd8f0))
+(assert_return (invoke "i64.extend_i32_u" (i32.const -1)) (i64.const 0xffffffff))
+(assert_return (invoke "i64.extend_i32_u" (i32.const 0x7fffffff)) (i64.const 0x000000007fffffff))
+(assert_return (invoke "i64.extend_i32_u" (i32.const 0x80000000)) (i64.const 0x0000000080000000))
+
+(assert_return (invoke "i32.wrap_i64" (i64.const -1)) (i32.const -1))
+(assert_return (invoke "i32.wrap_i64" (i64.const -100000)) (i32.const -100000))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0x80000000)) (i32.const 0x80000000))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0xffffffff7fffffff)) (i32.const 0x7fffffff))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0xffffffff00000000)) (i32.const 0x00000000))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0xfffffffeffffffff)) (i32.const 0xffffffff))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0xffffffff00000001)) (i32.const 0x00000001))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0)) (i32.const 0))
+(assert_return (invoke "i32.wrap_i64" (i64.const 1311768467463790320)) (i32.const 0x9abcdef0))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0x00000000ffffffff)) (i32.const 0xffffffff))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0x0000000100000000)) (i32.const 0x00000000))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0x0000000100000001)) (i32.const 0x00000001))
+
+(assert_return (invoke "i32.trunc_f32_s" (f32.const 0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f32_s" (f32.const -0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f32_s" (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f32_s" (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f32_s" (f32.const 1.0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_f32_s" (f32.const 0x1.19999ap+0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_f32_s" (f32.const 1.5)) (i32.const 1))
+(assert_return (invoke "i32.trunc_f32_s" (f32.const -1.0)) (i32.const -1))
+(assert_return (invoke "i32.trunc_f32_s" (f32.const -0x1.19999ap+0)) (i32.const -1))
+(assert_return (invoke "i32.trunc_f32_s" (f32.const -1.5)) (i32.const -1))
+(assert_return (invoke "i32.trunc_f32_s" (f32.const -1.9)) (i32.const -1))
+(assert_return (invoke "i32.trunc_f32_s" (f32.const -2.0)) (i32.const -2))
+(assert_return (invoke "i32.trunc_f32_s" (f32.const 2147483520.0)) (i32.const 2147483520))
+(assert_return (invoke "i32.trunc_f32_s" (f32.const -2147483648.0)) (i32.const -2147483648))
+(assert_trap (invoke "i32.trunc_f32_s" (f32.const 2147483648.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f32_s" (f32.const -2147483904.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f32_s" (f32.const inf)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f32_s" (f32.const -inf)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f32_s" (f32.const nan)) "invalid conversion to integer")
+(assert_trap (invoke "i32.trunc_f32_s" (f32.const nan:0x200000)) "invalid conversion to integer")
+(assert_trap (invoke "i32.trunc_f32_s" (f32.const -nan)) "invalid conversion to integer")
+(assert_trap (invoke "i32.trunc_f32_s" (f32.const -nan:0x200000)) "invalid conversion to integer")
+
+(assert_return (invoke "i32.trunc_f32_u" (f32.const 0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f32_u" (f32.const -0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f32_u" (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f32_u" (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f32_u" (f32.const 1.0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_f32_u" (f32.const 0x1.19999ap+0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_f32_u" (f32.const 1.5)) (i32.const 1))
+(assert_return (invoke "i32.trunc_f32_u" (f32.const 1.9)) (i32.const 1))
+(assert_return (invoke "i32.trunc_f32_u" (f32.const 2.0)) (i32.const 2))
+(assert_return (invoke "i32.trunc_f32_u" (f32.const 2147483648)) (i32.const -2147483648)) ;; 0x1.00000p+31 -> 8000 0000
+(assert_return (invoke "i32.trunc_f32_u" (f32.const 4294967040.0)) (i32.const -256))
+(assert_return (invoke "i32.trunc_f32_u" (f32.const -0x1.ccccccp-1)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f32_u" (f32.const -0x1.fffffep-1)) (i32.const 0))
+(assert_trap (invoke "i32.trunc_f32_u" (f32.const 4294967296.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f32_u" (f32.const -1.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f32_u" (f32.const inf)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f32_u" (f32.const -inf)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f32_u" (f32.const nan)) "invalid conversion to integer")
+(assert_trap (invoke "i32.trunc_f32_u" (f32.const nan:0x200000)) "invalid conversion to integer")
+(assert_trap (invoke "i32.trunc_f32_u" (f32.const -nan)) "invalid conversion to integer")
+(assert_trap (invoke "i32.trunc_f32_u" (f32.const -nan:0x200000)) "invalid conversion to integer")
+
+(assert_return (invoke "i32.trunc_f64_s" (f64.const 0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f64_s" (f64.const -0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f64_s" (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f64_s" (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f64_s" (f64.const 1.0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_f64_s" (f64.const 0x1.199999999999ap+0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_f64_s" (f64.const 1.5)) (i32.const 1))
+(assert_return (invoke "i32.trunc_f64_s" (f64.const -1.0)) (i32.const -1))
+(assert_return (invoke "i32.trunc_f64_s" (f64.const -0x1.199999999999ap+0)) (i32.const -1))
+(assert_return (invoke "i32.trunc_f64_s" (f64.const -1.5)) (i32.const -1))
+(assert_return (invoke "i32.trunc_f64_s" (f64.const -1.9)) (i32.const -1))
+(assert_return (invoke "i32.trunc_f64_s" (f64.const -2.0)) (i32.const -2))
+(assert_return (invoke "i32.trunc_f64_s" (f64.const 2147483647.0)) (i32.const 2147483647))
+(assert_return (invoke "i32.trunc_f64_s" (f64.const -2147483648.0)) (i32.const -2147483648))
+(assert_trap (invoke "i32.trunc_f64_s" (f64.const 2147483648.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f64_s" (f64.const -2147483649.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f64_s" (f64.const inf)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f64_s" (f64.const -inf)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f64_s" (f64.const nan)) "invalid conversion to integer")
+(assert_trap (invoke "i32.trunc_f64_s" (f64.const nan:0x4000000000000)) "invalid conversion to integer")
+(assert_trap (invoke "i32.trunc_f64_s" (f64.const -nan)) "invalid conversion to integer")
+(assert_trap (invoke "i32.trunc_f64_s" (f64.const -nan:0x4000000000000)) "invalid conversion to integer")
+
+;; f64 -> i32 rounding to the exact i32 limit
+(assert_return (invoke "i32.trunc_f64_s" (f64.const -2147483648.9)) (i32.const -2147483648))
+(assert_return (invoke "i32.trunc_f64_s" (f64.const  2147483647.9)) (i32.const  2147483647))
+(assert_return (invoke "i32.trunc_f64_u" (f64.const -0.9)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f64_u" (f64.const 4294967295.9)) (i32.const 4294967295))
+
+;; f64 -> i32 rounding at the exact boundary + float parsing
+(assert_return (invoke "i32.trunc_f64_s" (f64.const -2147483648.9999997)) (i32.const -2147483648))
+(assert_trap   (invoke "i32.trunc_f64_s" (f64.const -2147483648.9999998)) "integer overflow")
+(assert_return (invoke "i32.trunc_f64_s" (f64.const  2147483647.9999998)) (i32.const 2147483647))
+(assert_trap   (invoke "i32.trunc_f64_s" (f64.const  2147483647.9999999)) "integer overflow")
+(assert_return (invoke "i32.trunc_f64_u" (f64.const -0.99999999999999994)) (i32.const 0))
+(assert_trap   (invoke "i32.trunc_f64_u" (f64.const -0.99999999999999995)) "integer overflow")
+(assert_return (invoke "i32.trunc_f64_u" (f64.const  4294967295.9999997)) (i32.const 4294967295))
+(assert_trap   (invoke "i32.trunc_f64_u" (f64.const  4294967295.9999998)) "integer overflow")
+
+(assert_return (invoke "i32.trunc_f64_u" (f64.const 0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f64_u" (f64.const -0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f64_u" (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f64_u" (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f64_u" (f64.const 1.0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_f64_u" (f64.const 0x1.199999999999ap+0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_f64_u" (f64.const 1.5)) (i32.const 1))
+(assert_return (invoke "i32.trunc_f64_u" (f64.const 1.9)) (i32.const 1))
+(assert_return (invoke "i32.trunc_f64_u" (f64.const 2.0)) (i32.const 2))
+(assert_return (invoke "i32.trunc_f64_u" (f64.const 2147483648)) (i32.const -2147483648)) ;; 0x1.00000p+31 -> 8000 0000
+(assert_return (invoke "i32.trunc_f64_u" (f64.const 4294967295.0)) (i32.const -1))
+(assert_return (invoke "i32.trunc_f64_u" (f64.const -0x1.ccccccccccccdp-1)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f64_u" (f64.const -0x1.fffffffffffffp-1)) (i32.const 0))
+(assert_return (invoke "i32.trunc_f64_u" (f64.const 1e8)) (i32.const 100000000))
+(assert_trap (invoke "i32.trunc_f64_u" (f64.const 4294967296.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f64_u" (f64.const -1.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f64_u" (f64.const 1e16)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f64_u" (f64.const 1e30)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f64_u" (f64.const 9223372036854775808)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f64_u" (f64.const inf)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f64_u" (f64.const -inf)) "integer overflow")
+(assert_trap (invoke "i32.trunc_f64_u" (f64.const nan)) "invalid conversion to integer")
+(assert_trap (invoke "i32.trunc_f64_u" (f64.const nan:0x4000000000000)) "invalid conversion to integer")
+(assert_trap (invoke "i32.trunc_f64_u" (f64.const -nan)) "invalid conversion to integer")
+(assert_trap (invoke "i32.trunc_f64_u" (f64.const -nan:0x4000000000000)) "invalid conversion to integer")
+
+(assert_return (invoke "i64.trunc_f32_s" (f32.const 0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f32_s" (f32.const -0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f32_s" (f32.const 0x1p-149)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f32_s" (f32.const -0x1p-149)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f32_s" (f32.const 1.0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_f32_s" (f32.const 0x1.19999ap+0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_f32_s" (f32.const 1.5)) (i64.const 1))
+(assert_return (invoke "i64.trunc_f32_s" (f32.const -1.0)) (i64.const -1))
+(assert_return (invoke "i64.trunc_f32_s" (f32.const -0x1.19999ap+0)) (i64.const -1))
+(assert_return (invoke "i64.trunc_f32_s" (f32.const -1.5)) (i64.const -1))
+(assert_return (invoke "i64.trunc_f32_s" (f32.const -1.9)) (i64.const -1))
+(assert_return (invoke "i64.trunc_f32_s" (f32.const -2.0)) (i64.const -2))
+(assert_return (invoke "i64.trunc_f32_s" (f32.const 4294967296)) (i64.const 4294967296)) ;; 0x1.00000p+32 -> 1 0000 0000
+(assert_return (invoke "i64.trunc_f32_s" (f32.const -4294967296)) (i64.const -4294967296)) ;; -0x1.00000p+32 -> ffff ffff 0000 0000
+(assert_return (invoke "i64.trunc_f32_s" (f32.const 9223371487098961920.0)) (i64.const 9223371487098961920))
+(assert_return (invoke "i64.trunc_f32_s" (f32.const -9223372036854775808.0)) (i64.const -9223372036854775808))
+(assert_trap (invoke "i64.trunc_f32_s" (f32.const 9223372036854775808.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f32_s" (f32.const -9223373136366403584.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f32_s" (f32.const inf)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f32_s" (f32.const -inf)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f32_s" (f32.const nan)) "invalid conversion to integer")
+(assert_trap (invoke "i64.trunc_f32_s" (f32.const nan:0x200000)) "invalid conversion to integer")
+(assert_trap (invoke "i64.trunc_f32_s" (f32.const -nan)) "invalid conversion to integer")
+(assert_trap (invoke "i64.trunc_f32_s" (f32.const -nan:0x200000)) "invalid conversion to integer")
+
+(assert_return (invoke "i64.trunc_f32_u" (f32.const 0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f32_u" (f32.const -0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f32_u" (f32.const 0x1p-149)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f32_u" (f32.const -0x1p-149)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f32_u" (f32.const 1.0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_f32_u" (f32.const 0x1.19999ap+0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_f32_u" (f32.const 1.5)) (i64.const 1))
+(assert_return (invoke "i64.trunc_f32_u" (f32.const 4294967296)) (i64.const 4294967296))
+(assert_return (invoke "i64.trunc_f32_u" (f32.const 18446742974197923840.0)) (i64.const -1099511627776))
+(assert_return (invoke "i64.trunc_f32_u" (f32.const -0x1.ccccccp-1)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f32_u" (f32.const -0x1.fffffep-1)) (i64.const 0))
+(assert_trap (invoke "i64.trunc_f32_u" (f32.const 18446744073709551616.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f32_u" (f32.const -1.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f32_u" (f32.const inf)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f32_u" (f32.const -inf)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f32_u" (f32.const nan)) "invalid conversion to integer")
+(assert_trap (invoke "i64.trunc_f32_u" (f32.const nan:0x200000)) "invalid conversion to integer")
+(assert_trap (invoke "i64.trunc_f32_u" (f32.const -nan)) "invalid conversion to integer")
+(assert_trap (invoke "i64.trunc_f32_u" (f32.const -nan:0x200000)) "invalid conversion to integer")
+
+(assert_return (invoke "i64.trunc_f64_s" (f64.const 0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f64_s" (f64.const -0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f64_s" (f64.const 0x0.0000000000001p-1022)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f64_s" (f64.const -0x0.0000000000001p-1022)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f64_s" (f64.const 1.0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_f64_s" (f64.const 0x1.199999999999ap+0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_f64_s" (f64.const 1.5)) (i64.const 1))
+(assert_return (invoke "i64.trunc_f64_s" (f64.const -1.0)) (i64.const -1))
+(assert_return (invoke "i64.trunc_f64_s" (f64.const -0x1.199999999999ap+0)) (i64.const -1))
+(assert_return (invoke "i64.trunc_f64_s" (f64.const -1.5)) (i64.const -1))
+(assert_return (invoke "i64.trunc_f64_s" (f64.const -1.9)) (i64.const -1))
+(assert_return (invoke "i64.trunc_f64_s" (f64.const -2.0)) (i64.const -2))
+(assert_return (invoke "i64.trunc_f64_s" (f64.const 4294967296)) (i64.const 4294967296)) ;; 0x1.00000p+32 -> 1 0000 0000
+(assert_return (invoke "i64.trunc_f64_s" (f64.const -4294967296)) (i64.const -4294967296)) ;; -0x1.00000p+32 -> ffff ffff 0000 0000
+(assert_return (invoke "i64.trunc_f64_s" (f64.const 9223372036854774784.0)) (i64.const 9223372036854774784))
+(assert_return (invoke "i64.trunc_f64_s" (f64.const -9223372036854775808.0)) (i64.const -9223372036854775808))
+(assert_trap (invoke "i64.trunc_f64_s" (f64.const 9223372036854775808.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f64_s" (f64.const -9223372036854777856.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f64_s" (f64.const inf)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f64_s" (f64.const -inf)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f64_s" (f64.const nan)) "invalid conversion to integer")
+(assert_trap (invoke "i64.trunc_f64_s" (f64.const nan:0x4000000000000)) "invalid conversion to integer")
+(assert_trap (invoke "i64.trunc_f64_s" (f64.const -nan)) "invalid conversion to integer")
+(assert_trap (invoke "i64.trunc_f64_s" (f64.const -nan:0x4000000000000)) "invalid conversion to integer")
+
+(assert_return (invoke "i64.trunc_f64_u" (f64.const 0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f64_u" (f64.const -0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f64_u" (f64.const 0x0.0000000000001p-1022)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f64_u" (f64.const -0x0.0000000000001p-1022)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f64_u" (f64.const 1.0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_f64_u" (f64.const 0x1.199999999999ap+0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_f64_u" (f64.const 1.5)) (i64.const 1))
+(assert_return (invoke "i64.trunc_f64_u" (f64.const 4294967295)) (i64.const 0xffffffff))
+(assert_return (invoke "i64.trunc_f64_u" (f64.const 4294967296)) (i64.const 0x100000000))
+(assert_return (invoke "i64.trunc_f64_u" (f64.const 18446744073709549568.0)) (i64.const -2048))
+(assert_return (invoke "i64.trunc_f64_u" (f64.const -0x1.ccccccccccccdp-1)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f64_u" (f64.const -0x1.fffffffffffffp-1)) (i64.const 0))
+(assert_return (invoke "i64.trunc_f64_u" (f64.const 1e8)) (i64.const 100000000))
+(assert_return (invoke "i64.trunc_f64_u" (f64.const 1e16)) (i64.const 10000000000000000))
+(assert_return (invoke "i64.trunc_f64_u" (f64.const 9223372036854775808)) (i64.const -9223372036854775808))
+(assert_trap (invoke "i64.trunc_f64_u" (f64.const 18446744073709551616.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f64_u" (f64.const -1.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f64_u" (f64.const inf)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f64_u" (f64.const -inf)) "integer overflow")
+(assert_trap (invoke "i64.trunc_f64_u" (f64.const nan)) "invalid conversion to integer")
+(assert_trap (invoke "i64.trunc_f64_u" (f64.const nan:0x4000000000000)) "invalid conversion to integer")
+(assert_trap (invoke "i64.trunc_f64_u" (f64.const -nan)) "invalid conversion to integer")
+(assert_trap (invoke "i64.trunc_f64_u" (f64.const -nan:0x4000000000000)) "invalid conversion to integer")
+
+(assert_return (invoke "f32.convert_i32_s" (i32.const 1)) (f32.const 1.0))
+(assert_return (invoke "f32.convert_i32_s" (i32.const -1)) (f32.const -1.0))
+(assert_return (invoke "f32.convert_i32_s" (i32.const 0)) (f32.const 0.0))
+(assert_return (invoke "f32.convert_i32_s" (i32.const 2147483647)) (f32.const 2147483648))
+(assert_return (invoke "f32.convert_i32_s" (i32.const -2147483648)) (f32.const -2147483648))
+(assert_return (invoke "f32.convert_i32_s" (i32.const 1234567890)) (f32.const 0x1.26580cp+30))
+;; Test rounding directions.
+(assert_return (invoke "f32.convert_i32_s" (i32.const 16777217)) (f32.const 16777216.0))
+(assert_return (invoke "f32.convert_i32_s" (i32.const -16777217)) (f32.const -16777216.0))
+(assert_return (invoke "f32.convert_i32_s" (i32.const 16777219)) (f32.const 16777220.0))
+(assert_return (invoke "f32.convert_i32_s" (i32.const -16777219)) (f32.const -16777220.0))
+
+(assert_return (invoke "f32.convert_i64_s" (i64.const 1)) (f32.const 1.0))
+(assert_return (invoke "f32.convert_i64_s" (i64.const -1)) (f32.const -1.0))
+(assert_return (invoke "f32.convert_i64_s" (i64.const 0)) (f32.const 0.0))
+(assert_return (invoke "f32.convert_i64_s" (i64.const 9223372036854775807)) (f32.const 9223372036854775807))
+(assert_return (invoke "f32.convert_i64_s" (i64.const -9223372036854775808)) (f32.const -9223372036854775808))
+(assert_return (invoke "f32.convert_i64_s" (i64.const 314159265358979)) (f32.const 0x1.1db9e8p+48)) ;; PI
+;; Test rounding directions.
+(assert_return (invoke "f32.convert_i64_s" (i64.const 16777217)) (f32.const 16777216.0))
+(assert_return (invoke "f32.convert_i64_s" (i64.const -16777217)) (f32.const -16777216.0))
+(assert_return (invoke "f32.convert_i64_s" (i64.const 16777219)) (f32.const 16777220.0))
+(assert_return (invoke "f32.convert_i64_s" (i64.const -16777219)) (f32.const -16777220.0))
+
+(assert_return (invoke "f32.convert_i64_s" (i64.const 0x7fffff4000000001)) (f32.const 0x1.fffffep+62))
+(assert_return (invoke "f32.convert_i64_s" (i64.const 0x8000004000000001)) (f32.const -0x1.fffffep+62))
+(assert_return (invoke "f32.convert_i64_s" (i64.const 0x0020000020000001)) (f32.const 0x1.000002p+53))
+(assert_return (invoke "f32.convert_i64_s" (i64.const 0xffdfffffdfffffff)) (f32.const -0x1.000002p+53))
+
+(assert_return (invoke "f64.convert_i32_s" (i32.const 1)) (f64.const 1.0))
+(assert_return (invoke "f64.convert_i32_s" (i32.const -1)) (f64.const -1.0))
+(assert_return (invoke "f64.convert_i32_s" (i32.const 0)) (f64.const 0.0))
+(assert_return (invoke "f64.convert_i32_s" (i32.const 2147483647)) (f64.const 2147483647))
+(assert_return (invoke "f64.convert_i32_s" (i32.const -2147483648)) (f64.const -2147483648))
+(assert_return (invoke "f64.convert_i32_s" (i32.const 987654321)) (f64.const 987654321))
+
+(assert_return (invoke "f64.convert_i64_s" (i64.const 1)) (f64.const 1.0))
+(assert_return (invoke "f64.convert_i64_s" (i64.const -1)) (f64.const -1.0))
+(assert_return (invoke "f64.convert_i64_s" (i64.const 0)) (f64.const 0.0))
+(assert_return (invoke "f64.convert_i64_s" (i64.const 9223372036854775807)) (f64.const 9223372036854775807))
+(assert_return (invoke "f64.convert_i64_s" (i64.const -9223372036854775808)) (f64.const -9223372036854775808))
+(assert_return (invoke "f64.convert_i64_s" (i64.const 4669201609102990)) (f64.const 4669201609102990)) ;; Feigenbaum
+;; Test rounding directions.
+(assert_return (invoke "f64.convert_i64_s" (i64.const 9007199254740993)) (f64.const 9007199254740992))
+(assert_return (invoke "f64.convert_i64_s" (i64.const -9007199254740993)) (f64.const -9007199254740992))
+(assert_return (invoke "f64.convert_i64_s" (i64.const 9007199254740995)) (f64.const 9007199254740996))
+(assert_return (invoke "f64.convert_i64_s" (i64.const -9007199254740995)) (f64.const -9007199254740996))
+
+(assert_return (invoke "f32.convert_i32_u" (i32.const 1)) (f32.const 1.0))
+(assert_return (invoke "f32.convert_i32_u" (i32.const 0)) (f32.const 0.0))
+(assert_return (invoke "f32.convert_i32_u" (i32.const 2147483647)) (f32.const 2147483648))
+(assert_return (invoke "f32.convert_i32_u" (i32.const -2147483648)) (f32.const 2147483648))
+(assert_return (invoke "f32.convert_i32_u" (i32.const 0x12345678)) (f32.const 0x1.234568p+28))
+(assert_return (invoke "f32.convert_i32_u" (i32.const 0xffffffff)) (f32.const 4294967296.0))
+(assert_return (invoke "f32.convert_i32_u" (i32.const 0x80000080)) (f32.const 0x1.000000p+31))
+(assert_return (invoke "f32.convert_i32_u" (i32.const 0x80000081)) (f32.const 0x1.000002p+31))
+(assert_return (invoke "f32.convert_i32_u" (i32.const 0x80000082)) (f32.const 0x1.000002p+31))
+(assert_return (invoke "f32.convert_i32_u" (i32.const 0xfffffe80)) (f32.const 0x1.fffffcp+31))
+(assert_return (invoke "f32.convert_i32_u" (i32.const 0xfffffe81)) (f32.const 0x1.fffffep+31))
+(assert_return (invoke "f32.convert_i32_u" (i32.const 0xfffffe82)) (f32.const 0x1.fffffep+31))
+;; Test rounding directions.
+(assert_return (invoke "f32.convert_i32_u" (i32.const 16777217)) (f32.const 16777216.0))
+(assert_return (invoke "f32.convert_i32_u" (i32.const 16777219)) (f32.const 16777220.0))
+
+(assert_return (invoke "f32.convert_i64_u" (i64.const 1)) (f32.const 1.0))
+(assert_return (invoke "f32.convert_i64_u" (i64.const 0)) (f32.const 0.0))
+(assert_return (invoke "f32.convert_i64_u" (i64.const 9223372036854775807)) (f32.const 9223372036854775807))
+(assert_return (invoke "f32.convert_i64_u" (i64.const -9223372036854775808)) (f32.const 9223372036854775808))
+(assert_return (invoke "f32.convert_i64_u" (i64.const 0xffffffffffffffff)) (f32.const 18446744073709551616.0))
+;; Test rounding directions.
+(assert_return (invoke "f32.convert_i64_u" (i64.const 16777217)) (f32.const 16777216.0))
+(assert_return (invoke "f32.convert_i64_u" (i64.const 16777219)) (f32.const 16777220.0))
+
+(assert_return (invoke "f32.convert_i64_u" (i64.const 0x0020000020000001)) (f32.const 0x1.000002p+53))
+(assert_return (invoke "f32.convert_i64_u" (i64.const 0x7fffffbfffffffff)) (f32.const 0x1.fffffep+62))
+(assert_return (invoke "f32.convert_i64_u" (i64.const 0x8000008000000001)) (f32.const 0x1.000002p+63))
+(assert_return (invoke "f32.convert_i64_u" (i64.const 0xfffffe8000000001)) (f32.const 0x1.fffffep+63))
+
+(assert_return (invoke "f64.convert_i32_u" (i32.const 1)) (f64.const 1.0))
+(assert_return (invoke "f64.convert_i32_u" (i32.const 0)) (f64.const 0.0))
+(assert_return (invoke "f64.convert_i32_u" (i32.const 2147483647)) (f64.const 2147483647))
+(assert_return (invoke "f64.convert_i32_u" (i32.const -2147483648)) (f64.const 2147483648))
+(assert_return (invoke "f64.convert_i32_u" (i32.const 0xffffffff)) (f64.const 4294967295.0))
+
+(assert_return (invoke "f64.convert_i64_u" (i64.const 1)) (f64.const 1.0))
+(assert_return (invoke "f64.convert_i64_u" (i64.const 0)) (f64.const 0.0))
+(assert_return (invoke "f64.convert_i64_u" (i64.const 9223372036854775807)) (f64.const 9223372036854775807))
+(assert_return (invoke "f64.convert_i64_u" (i64.const -9223372036854775808)) (f64.const 9223372036854775808))
+(assert_return (invoke "f64.convert_i64_u" (i64.const 0xffffffffffffffff)) (f64.const 18446744073709551616.0))
+(assert_return (invoke "f64.convert_i64_u" (i64.const 0x8000000000000400)) (f64.const 0x1.0000000000000p+63))
+(assert_return (invoke "f64.convert_i64_u" (i64.const 0x8000000000000401)) (f64.const 0x1.0000000000001p+63))
+(assert_return (invoke "f64.convert_i64_u" (i64.const 0x8000000000000402)) (f64.const 0x1.0000000000001p+63))
+(assert_return (invoke "f64.convert_i64_u" (i64.const 0xfffffffffffff400)) (f64.const 0x1.ffffffffffffep+63))
+(assert_return (invoke "f64.convert_i64_u" (i64.const 0xfffffffffffff401)) (f64.const 0x1.fffffffffffffp+63))
+(assert_return (invoke "f64.convert_i64_u" (i64.const 0xfffffffffffff402)) (f64.const 0x1.fffffffffffffp+63))
+;; Test rounding directions.
+(assert_return (invoke "f64.convert_i64_u" (i64.const 9007199254740993)) (f64.const 9007199254740992))
+(assert_return (invoke "f64.convert_i64_u" (i64.const 9007199254740995)) (f64.const 9007199254740996))
+
+(assert_return (invoke "f64.promote_f32" (f32.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.promote_f32" (f32.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.promote_f32" (f32.const 0x1p-149)) (f64.const 0x1p-149))
+(assert_return (invoke "f64.promote_f32" (f32.const -0x1p-149)) (f64.const -0x1p-149))
+(assert_return (invoke "f64.promote_f32" (f32.const 1.0)) (f64.const 1.0))
+(assert_return (invoke "f64.promote_f32" (f32.const -1.0)) (f64.const -1.0))
+(assert_return (invoke "f64.promote_f32" (f32.const -0x1.fffffep+127)) (f64.const -0x1.fffffep+127))
+(assert_return (invoke "f64.promote_f32" (f32.const 0x1.fffffep+127)) (f64.const 0x1.fffffep+127))
+;; Generated randomly by picking a random int and reinterpret it to float.
+(assert_return (invoke "f64.promote_f32" (f32.const 0x1p-119)) (f64.const 0x1p-119))
+;; Generated randomly by picking a random float.
+(assert_return (invoke "f64.promote_f32" (f32.const 0x1.8f867ep+125)) (f64.const 6.6382536710104395e+37))
+(assert_return (invoke "f64.promote_f32" (f32.const inf)) (f64.const inf))
+(assert_return (invoke "f64.promote_f32" (f32.const -inf)) (f64.const -inf))
+(assert_return_canonical_nan (invoke "f64.promote_f32" (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "f64.promote_f32" (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "f64.promote_f32" (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "f64.promote_f32" (f32.const -nan:0x200000)))
+
+(assert_return (invoke "f32.demote_f64" (f64.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x0.0000000000001p-1022)) (f32.const 0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x0.0000000000001p-1022)) (f32.const -0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 1.0)) (f32.const 1.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -1.0)) (f32.const -1.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffe0000000p-127)) (f32.const 0x1p-126))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffe0000000p-127)) (f32.const -0x1p-126))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffdfffffffp-127)) (f32.const 0x1.fffffcp-127))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffdfffffffp-127)) (f32.const -0x1.fffffcp-127))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffd0000000p+127)) (f32.const 0x1.fffffcp+127))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffd0000000p+127)) (f32.const -0x1.fffffcp+127))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffd0000001p+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffd0000001p+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffefffffffp+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffefffffffp+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.ffffffp+127)) (f32.const inf))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.ffffffp+127)) (f32.const -inf))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1p-119)) (f32.const 0x1p-119))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.8f867ep+125)) (f32.const 0x1.8f867ep+125))
+(assert_return (invoke "f32.demote_f64" (f64.const inf)) (f32.const inf))
+(assert_return (invoke "f32.demote_f64" (f64.const -inf)) (f32.const -inf))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000000000001p+0)) (f32.const 1.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffffffffffp-1)) (f32.const 1.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000010000000p+0)) (f32.const 0x1.000000p+0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000010000001p+0)) (f32.const 0x1.000002p+0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.000002fffffffp+0)) (f32.const 0x1.000002p+0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000030000000p+0)) (f32.const 0x1.000004p+0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000050000000p+0)) (f32.const 0x1.000004p+0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000010000000p+24)) (f32.const 0x1.0p+24))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000010000001p+24)) (f32.const 0x1.000002p+24))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.000002fffffffp+24)) (f32.const 0x1.000002p+24))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000030000000p+24)) (f32.const 0x1.000004p+24))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.4eae4f7024c7p+108)) (f32.const 0x1.4eae5p+108))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.a12e71e358685p-113)) (f32.const 0x1.a12e72p-113))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.cb98354d521ffp-127)) (f32.const 0x1.cb9834p-127))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.6972b30cfb562p+1)) (f32.const -0x1.6972b4p+1))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.bedbe4819d4c4p+112)) (f32.const -0x1.bedbe4p+112))
+(assert_return_canonical_nan (invoke "f32.demote_f64" (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "f32.demote_f64" (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "f32.demote_f64" (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "f32.demote_f64" (f64.const -nan:0x4000000000000)))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1p-1022)) (f32.const 0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1p-1022)) (f32.const -0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0p-150)) (f32.const 0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.0p-150)) (f32.const -0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000000000001p-150)) (f32.const 0x1p-149))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.0000000000001p-150)) (f32.const -0x1p-149))
+
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0)) (f32.const 0.0))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x80000000)) (f32.const -0.0))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 1)) (f32.const 0x1p-149))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const -1)) (f32.const -nan:0x7fffff))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 123456789)) (f32.const 0x1.b79a2ap-113))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const -2147483647)) (f32.const -0x1p-149))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x7f800000)) (f32.const inf))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0xff800000)) (f32.const -inf))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x7fc00000)) (f32.const nan))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0xffc00000)) (f32.const -nan))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x7fa00000)) (f32.const nan:0x200000))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0xffa00000)) (f32.const -nan:0x200000))
+
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0)) (f64.const 0.0))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 1)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const -1)) (f64.const -nan:0xfffffffffffff))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x8000000000000000)) (f64.const -0.0))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 1234567890)) (f64.const 0x0.00000499602d2p-1022))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const -9223372036854775807)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x7ff0000000000000)) (f64.const inf))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0xfff0000000000000)) (f64.const -inf))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x7ff8000000000000)) (f64.const nan))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0xfff8000000000000)) (f64.const -nan))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x7ff4000000000000)) (f64.const nan:0x4000000000000))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0xfff4000000000000)) (f64.const -nan:0x4000000000000))
+
+(assert_return (invoke "i32.reinterpret_f32" (f32.const 0.0)) (i32.const 0))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -0.0)) (i32.const 0x80000000))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -nan:0x7fffff)) (i32.const -1))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -0x1p-149)) (i32.const 0x80000001))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const 1.0)) (i32.const 1065353216))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const 3.1415926)) (i32.const 1078530010))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const 0x1.fffffep+127)) (i32.const 2139095039))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -0x1.fffffep+127)) (i32.const -8388609))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const inf)) (i32.const 0x7f800000))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -inf)) (i32.const 0xff800000))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const nan)) (i32.const 0x7fc00000))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -nan)) (i32.const 0xffc00000))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const nan:0x200000)) (i32.const 0x7fa00000))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -nan:0x200000)) (i32.const 0xffa00000))
+
+(assert_return (invoke "i64.reinterpret_f64" (f64.const 0.0)) (i64.const 0))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -0.0)) (i64.const 0x8000000000000000))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const 0x0.0000000000001p-1022)) (i64.const 1))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -nan:0xfffffffffffff)) (i64.const -1))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -0x0.0000000000001p-1022)) (i64.const 0x8000000000000001))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const 1.0)) (i64.const 4607182418800017408))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const 3.14159265358979)) (i64.const 4614256656552045841))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const 0x1.fffffffffffffp+1023)) (i64.const 9218868437227405311))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -0x1.fffffffffffffp+1023)) (i64.const -4503599627370497))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const inf)) (i64.const 0x7ff0000000000000))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -inf)) (i64.const 0xfff0000000000000))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const nan)) (i64.const 0x7ff8000000000000))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -nan)) (i64.const 0xfff8000000000000))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const nan:0x4000000000000)) (i64.const 0x7ff4000000000000))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -nan:0x4000000000000)) (i64.const 0xfff4000000000000))
+
+;; Type check
+
+(assert_invalid (module (func (result i32) (i32.wrap_i64 (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.trunc_f32_s (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.trunc_f32_u (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.trunc_f64_s (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.trunc_f64_u (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.reinterpret_f32 (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.extend_i32_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.extend_i32_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.trunc_f32_s (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.trunc_f32_u (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.trunc_f64_s (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.trunc_f64_u (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.reinterpret_f64 (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.convert_i32_s (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.convert_i32_u (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.convert_i64_s (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.convert_i64_u (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.demote_f64 (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.reinterpret_i32 (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.convert_i32_s (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.convert_i32_u (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.convert_i64_s (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.convert_i64_u (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.promote_f32 (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.reinterpret_i64 (i32.const 0)))) "type mismatch")
diff --git a/binaryen/test/spec/custom.wast b/binaryen/test/spec/custom.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/custom.wast
@@ -0,0 +1,120 @@
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\00\24\10" "a custom section" "this is the payload"
+  "\00\20\10" "a custom section" "this is payload"
+  "\00\11\10" "a custom section" ""
+  "\00\10\00" "" "this is payload"
+  "\00\01\00" "" ""
+  "\00\24\10" "\00\00custom sectio\00" "this is the payload"
+  "\00\24\10" "\ef\bb\bfa custom sect" "this is the payload"
+  "\00\24\10" "a custom sect\e2\8c\a3" "this is the payload"
+  "\00\1f\16" "module within a module" "\00asm" "\01\00\00\00"
+)
+
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\01\01\00"  ;; type section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\02\01\00"  ;; import section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\03\01\00"  ;; function section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\04\01\00"  ;; table section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\05\01\00"  ;; memory section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\06\01\00"  ;; global section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\07\01\00"  ;; export section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\09\01\00"  ;; element section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\0a\01\00"  ;; code section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\0b\01\00"  ;; data section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+)
+
+(module binary
+  "\00asm" "\01\00\00\00"
+  "\01\07\01\60\02\7f\7f\01\7f"                ;; type section
+  "\00\1a\06" "custom" "this is the payload"   ;; custom section
+  "\03\02\01\00"                               ;; function section
+  "\07\0a\01\06\61\64\64\54\77\6f\00\00"       ;; export section
+  "\0a\09\01\07\00\20\00\20\01\6a\0b"          ;; code section
+  "\00\1b\07" "custom2" "this is the payload"  ;; custom section
+)
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00"
+  )
+  "unexpected end"
+)
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\00"
+  )
+  "unexpected end"
+)
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\00\00\05\01\00\07\00\00"
+  )
+  "unexpected end"
+)
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\26\10" "a custom section" "this is the payload"
+  )
+  "unexpected end"
+)
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\25\10" "a custom section" "this is the payload"
+    "\00\24\10" "a custom section" "this is the payload"
+  )
+  "invalid section id"
+)
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\01\07\01\60\02\7f\7f\01\7f"                         ;; type section
+    "\00\25\10" "a custom section" "this is the payload"  ;; invalid length!
+    "\03\02\01\00"                                        ;; function section
+    "\0a\09\01\07\00\20\00\20\01\6a\0b"                   ;; code section
+    "\00\1b\07" "custom2" "this is the payload"           ;; custom section
+  )
+  "function and code section have inconsistent lengths"
+)
+
+;; Test concatenated modules.
+(assert_malformed
+  (module binary
+    "\00asm\01\00\00\00"
+    "\00asm\01\00\00\00"
+  )
+  "length out of bounds"
+)
diff --git a/binaryen/test/spec/data.wast b/binaryen/test/spec/data.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/data.wast
@@ -0,0 +1,335 @@
+;; Test the data section
+
+;; Syntax
+
+(module
+  (memory $m 1)
+  (data (i32.const 0))
+  (data (i32.const 1) "a" "" "bcd")
+  (data (offset (i32.const 0)))
+  (data (offset (i32.const 0)) "" "a" "bc" "")
+  (data 0 (i32.const 0))
+  (data 0x0 (i32.const 1) "a" "" "bcd")
+  (data 0x000 (offset (i32.const 0)))
+  (data 0 (offset (i32.const 0)) "" "a" "bc" "")
+  (data $m (i32.const 0))
+  (data $m (i32.const 1) "a" "" "bcd")
+  (data $m (offset (i32.const 0)))
+  (data $m (offset (i32.const 0)) "" "a" "bc" "")
+)
+
+;; Basic use
+
+(module
+  (memory 1)
+  (data (i32.const 0) "a")
+)
+(module
+  (import "spectest" "memory" (memory 1))
+  (data (i32.const 0) "a")
+)
+
+(module
+  (memory 1)
+  (data (i32.const 0) "a")
+  (data (i32.const 3) "b")
+  (data (i32.const 100) "cde")
+  (data (i32.const 5) "x")
+  (data (i32.const 3) "c")
+)
+(module
+  (import "spectest" "memory" (memory 1))
+  (data (i32.const 0) "a")
+  (data (i32.const 1) "b")
+  (data (i32.const 2) "cde")
+  (data (i32.const 3) "f")
+  (data (i32.const 2) "g")
+  (data (i32.const 1) "h")
+)
+
+(module
+  (global (import "spectest" "global_i32") i32)
+  (memory 1)
+  (data (global.get 0) "a")
+)
+(module
+  (global (import "spectest" "global_i32") i32)
+  (import "spectest" "memory" (memory 1))
+  (data (global.get 0) "a")
+)
+
+(module
+  (global $g (import "spectest" "global_i32") i32)
+  (memory 1)
+  (data (global.get $g) "a")
+)
+(module
+  (global $g (import "spectest" "global_i32") i32)
+  (import "spectest" "memory" (memory 1))
+  (data (global.get $g) "a")
+)
+
+;; Use of internal globals in constant expressions is not allowed in MVP.
+;; (module (memory 1) (data (global.get 0) "a") (global i32 (i32.const 0)))
+;; (module (memory 1) (data (global.get $g) "a") (global $g i32 (i32.const 0)))
+
+;; Corner cases
+
+(module
+  (memory 1)
+  (data (i32.const 0) "a")
+  (data (i32.const 0xffff) "b")
+)
+(module
+  (import "spectest" "memory" (memory 1))
+  (data (i32.const 0) "a")
+  (data (i32.const 0xffff) "b")
+)
+
+(module
+  (memory 2)
+  (data (i32.const 0x1_ffff) "a")
+)
+
+(module
+  (memory 0)
+  (data (i32.const 0))
+)
+(module
+  (import "spectest" "memory" (memory 0))
+  (data (i32.const 0))
+)
+
+(module
+  (memory 0 0)
+  (data (i32.const 0))
+)
+
+(module
+  (memory 1)
+  (data (i32.const 0x1_0000) "")
+)
+
+(module
+  (memory 0)
+  (data (i32.const 0) "" "")
+)
+(module
+  (import "spectest" "memory" (memory 0))
+  (data (i32.const 0) "" "")
+)
+
+(module
+  (memory 0 0)
+  (data (i32.const 0) "" "")
+)
+
+(module
+  (import "spectest" "memory" (memory 0))
+  (data (i32.const 0) "a")
+)
+
+(module
+  (import "spectest" "memory" (memory 0 3))
+  (data (i32.const 0) "a")
+)
+
+(module
+  (global (import "spectest" "global_i32") i32)
+  (import "spectest" "memory" (memory 0))
+  (data (global.get 0) "a")
+)
+
+(module
+  (global (import "spectest" "global_i32") i32)
+  (import "spectest" "memory" (memory 0 3))
+  (data (global.get 0) "a")
+)
+
+(module
+  (import "spectest" "memory" (memory 0))
+  (data (i32.const 1) "a")
+)
+
+(module
+  (import "spectest" "memory" (memory 0 3))
+  (data (i32.const 1) "a")
+)
+
+;; Invalid bounds for data
+
+(assert_unlinkable
+  (module
+    (memory 0)
+    (data (i32.const 0) "a")
+  )
+  "data segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (memory 0 0)
+    (data (i32.const 0) "a")
+  )
+  "data segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (memory 0 1)
+    (data (i32.const 0) "a")
+  )
+  "data segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (memory 0)
+    (data (i32.const 1))
+  )
+  "data segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (memory 0 1)
+    (data (i32.const 1))
+  )
+  "data segment does not fit"
+)
+
+;; This seems to cause a time-out on Travis.
+(;assert_unlinkable
+  (module
+    (memory 0x10000)
+    (data (i32.const 0xffffffff) "ab")
+  )
+  ""  ;; either out of memory or segment does not fit
+;)
+
+(assert_unlinkable
+  (module
+    (global (import "spectest" "global_i32") i32)
+    (memory 0)
+    (data (global.get 0) "a")
+  )
+  "data segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (memory 1 2)
+    (data (i32.const 0x1_0000) "a")
+  )
+  "data segment does not fit"
+)
+(assert_unlinkable
+  (module
+    (import "spectest" "memory" (memory 1))
+    (data (i32.const 0x1_0000) "a")
+  )
+  "data segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (memory 2)
+    (data (i32.const 0x2_0000) "a")
+  )
+  "data segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (memory 2 3)
+    (data (i32.const 0x2_0000) "a")
+  )
+  "data segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (memory 1)
+    (data (i32.const -1) "a")
+  )
+  "data segment does not fit"
+)
+(assert_unlinkable
+  (module
+    (import "spectest" "memory" (memory 1))
+    (data (i32.const -1) "a")
+  )
+  "data segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (memory 2)
+    (data (i32.const -100) "a")
+  )
+  "data segment does not fit"
+)
+(assert_unlinkable
+  (module
+    (import "spectest" "memory" (memory 1))
+    (data (i32.const -100) "a")
+  )
+  "data segment does not fit"
+)
+
+;; Data without memory
+
+(assert_invalid
+  (module
+    (data (i32.const 0) "")
+  )
+  "unknown memory"
+)
+
+;; Invalid offsets
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data (i64.const 0))
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data (i32.ctz (i32.const 0)))
+  )
+  "constant expression required"
+)
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data (nop))
+  )
+  "constant expression required"
+)
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data (offset (nop) (i32.const 0)))
+  )
+  "constant expression required"
+)
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data (offset (i32.const 0) (nop)))
+  )
+  "constant expression required"
+)
+
+;; Use of internal globals in constant expressions is not allowed in MVP.
+;; (assert_invalid
+;;   (module (memory 1) (data (global.get $g)) (global $g (mut i32) (i32.const 0)))
+;;   "constant expression required"
+;; )
diff --git a/binaryen/test/spec/elem.wast b/binaryen/test/spec/elem.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/elem.wast
@@ -0,0 +1,381 @@
+;; Test the element section
+
+;; Syntax
+(module
+  (table $t 10 funcref)
+  (func $f)
+  (elem (i32.const 0))
+  (elem (i32.const 0) $f $f)
+  (elem (offset (i32.const 0)))
+  (elem (offset (i32.const 0)) $f $f)
+  (elem 0 (i32.const 0))
+  (elem 0x0 (i32.const 0) $f $f)
+  (elem 0x000 (offset (i32.const 0)))
+  (elem 0 (offset (i32.const 0)) $f $f)
+  (elem $t (i32.const 0))
+  (elem $t (i32.const 0) $f $f)
+  (elem $t (offset (i32.const 0)))
+  (elem $t (offset (i32.const 0)) $f $f)
+)
+
+;; Basic use
+
+(module
+  (table 10 funcref)
+  (func $f)
+  (elem (i32.const 0) $f)
+)
+(module
+  (import "spectest" "table" (table 10 funcref))
+  (func $f)
+  (elem (i32.const 0) $f)
+)
+
+(module
+  (table 10 funcref)
+  (func $f)
+  (elem (i32.const 0) $f)
+  (elem (i32.const 3) $f)
+  (elem (i32.const 7) $f)
+  (elem (i32.const 5) $f)
+  (elem (i32.const 3) $f)
+)
+(module
+  (import "spectest" "table" (table 10 funcref))
+  (func $f)
+  (elem (i32.const 9) $f)
+  (elem (i32.const 3) $f)
+  (elem (i32.const 7) $f)
+  (elem (i32.const 3) $f)
+  (elem (i32.const 5) $f)
+)
+
+(module
+  (global (import "spectest" "global_i32") i32)
+  (table 1000 funcref)
+  (func $f)
+  (elem (global.get 0) $f)
+)
+
+(module
+  (global $g (import "spectest" "global_i32") i32)
+  (table 1000 funcref)
+  (func $f)
+  (elem (global.get $g) $f)
+)
+
+(module
+  (type $out-i32 (func (result i32)))
+  (table 10 funcref)
+  (elem (i32.const 7) $const-i32-a)
+  (elem (i32.const 9) $const-i32-b)
+  (func $const-i32-a (type $out-i32) (i32.const 65))
+  (func $const-i32-b (type $out-i32) (i32.const 66))
+  (func (export "call-7") (type $out-i32)
+    (call_indirect (type $out-i32) (i32.const 7))
+  )
+  (func (export "call-9") (type $out-i32)
+    (call_indirect (type $out-i32) (i32.const 9))
+  )
+)
+(assert_return (invoke "call-7") (i32.const 65))
+(assert_return (invoke "call-9") (i32.const 66))
+
+;; Corner cases
+
+(module
+  (table 10 funcref)
+  (func $f)
+  (elem (i32.const 9) $f)
+)
+(module
+  (import "spectest" "table" (table 10 funcref))
+  (func $f)
+  (elem (i32.const 9) $f)
+)
+
+(module
+  (table 0 funcref)
+  (elem (i32.const 0))
+)
+(module
+  (import "spectest" "table" (table 0 funcref))
+  (elem (i32.const 0))
+)
+
+(module
+  (table 0 0 funcref)
+  (elem (i32.const 0))
+)
+
+(module
+  (table 20 funcref)
+  (elem (i32.const 20))
+)
+
+(module
+  (import "spectest" "table" (table 0 funcref))
+  (func $f)
+  (elem (i32.const 0) $f)
+)
+
+(module
+  (import "spectest" "table" (table 0 100 funcref))
+  (func $f)
+  (elem (i32.const 0) $f)
+)
+
+(module
+  (import "spectest" "table" (table 0 funcref))
+  (func $f)
+  (elem (i32.const 1) $f)
+)
+
+(module
+  (import "spectest" "table" (table 0 30 funcref))
+  (func $f)
+  (elem (i32.const 1) $f)
+)
+
+;; Invalid bounds for elements
+
+(assert_unlinkable
+  (module
+    (table 0 funcref)
+    (func $f)
+    (elem (i32.const 0) $f)
+  )
+  "elements segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (table 0 0 funcref)
+    (func $f)
+    (elem (i32.const 0) $f)
+  )
+  "elements segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (table 0 1 funcref)
+    (func $f)
+    (elem (i32.const 0) $f)
+  )
+  "elements segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (table 0 funcref)
+    (elem (i32.const 1))
+  )
+  "elements segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (table 10 funcref)
+    (func $f)
+    (elem (i32.const 10) $f)
+  )
+  "elements segment does not fit"
+)
+(assert_unlinkable
+  (module
+    (import "spectest" "table" (table 10 funcref))
+    (func $f)
+    (elem (i32.const 10) $f)
+  )
+  "elements segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (table 10 20 funcref)
+    (func $f)
+    (elem (i32.const 10) $f)
+  )
+  "elements segment does not fit"
+)
+(assert_unlinkable
+  (module
+    (import "spectest" "table" (table 10 funcref))
+    (func $f)
+    (elem (i32.const 10) $f)
+  )
+  "elements segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (table 10 funcref)
+    (func $f)
+    (elem (i32.const -1) $f)
+  )
+  "elements segment does not fit"
+)
+(assert_unlinkable
+  (module
+    (import "spectest" "table" (table 10 funcref))
+    (func $f)
+    (elem (i32.const -1) $f)
+  )
+  "elements segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (table 10 funcref)
+    (func $f)
+    (elem (i32.const -10) $f)
+  )
+  "elements segment does not fit"
+)
+(assert_unlinkable
+  (module
+    (import "spectest" "table" (table 10 funcref))
+    (func $f)
+    (elem (i32.const -10) $f)
+  )
+  "elements segment does not fit"
+)
+
+;; Element without table
+
+(assert_invalid
+  (module
+    (func $f)
+    (elem (i32.const 0) $f)
+  )
+  "unknown table"
+)
+
+;; Invalid offsets
+
+(assert_invalid
+  (module
+    (table 1 funcref)
+    (elem (i64.const 0))
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (table 1 funcref)
+    (elem (i32.ctz (i32.const 0)))
+  )
+  "constant expression required"
+)
+
+(assert_invalid
+  (module
+    (table 1 funcref)
+    (elem (nop))
+  )
+  "constant expression required"
+)
+
+(assert_invalid
+  (module
+    (table 1 funcref)
+    (elem (offset (nop) (i32.const 0)))
+  )
+  "constant expression required"
+)
+
+(assert_invalid
+  (module
+    (table 1 funcref)
+    (elem (offset (i32.const 0) (nop)))
+  )
+  "constant expression required"
+)
+
+;; Use of internal globals in constant expressions is not allowed in MVP.
+;; (assert_invalid
+;;   (module (memory 1) (data (global.get $g)) (global $g (mut i32) (i32.const 0)))
+;;   "constant expression required"
+;; )
+
+;; Two elements target the same slot
+
+(module
+  (type $out-i32 (func (result i32)))
+  (table 10 funcref)
+  (elem (i32.const 9) $const-i32-a)
+  (elem (i32.const 9) $const-i32-b)
+  (func $const-i32-a (type $out-i32) (i32.const 65))
+  (func $const-i32-b (type $out-i32) (i32.const 66))
+  (func (export "call-overwritten") (type $out-i32)
+    (call_indirect (type $out-i32) (i32.const 9))
+  )
+)
+(assert_return (invoke "call-overwritten") (i32.const 66))
+
+(module
+  (type $out-i32 (func (result i32)))
+  (import "spectest" "table" (table 10 funcref))
+  (elem (i32.const 9) $const-i32-a)
+  (elem (i32.const 9) $const-i32-b)
+  (func $const-i32-a (type $out-i32) (i32.const 65))
+  (func $const-i32-b (type $out-i32) (i32.const 66))
+  (func (export "call-overwritten-element") (type $out-i32)
+    (call_indirect (type $out-i32) (i32.const 9))
+  )
+)
+(assert_return (invoke "call-overwritten-element") (i32.const 66))
+
+;; Element sections across multiple modules change the same table
+
+(module $module1
+  (type $out-i32 (func (result i32)))
+  (table (export "shared-table") 10 funcref)
+  (elem (i32.const 8) $const-i32-a)
+  (elem (i32.const 9) $const-i32-b)
+  (func $const-i32-a (type $out-i32) (i32.const 65))
+  (func $const-i32-b (type $out-i32) (i32.const 66))
+  (func (export "call-7") (type $out-i32)
+    (call_indirect (type $out-i32) (i32.const 7))
+  )
+  (func (export "call-8") (type $out-i32)
+    (call_indirect (type $out-i32) (i32.const 8))
+  )
+  (func (export "call-9") (type $out-i32)
+    (call_indirect (type $out-i32) (i32.const 9))
+  )
+)
+
+(register "module1" $module1)
+
+(assert_trap (invoke $module1 "call-7") "uninitialized element")
+(assert_return (invoke $module1 "call-8") (i32.const 65))
+(assert_return (invoke $module1 "call-9") (i32.const 66))
+
+(module $module2
+  (type $out-i32 (func (result i32)))
+  (import "module1" "shared-table" (table 10 funcref))
+  (elem (i32.const 7) $const-i32-c)
+  (elem (i32.const 8) $const-i32-d)
+  (func $const-i32-c (type $out-i32) (i32.const 67))
+  (func $const-i32-d (type $out-i32) (i32.const 68))
+)
+
+(assert_return (invoke $module1 "call-7") (i32.const 67))
+(assert_return (invoke $module1 "call-8") (i32.const 68))
+(assert_return (invoke $module1 "call-9") (i32.const 66))
+
+(module $module3
+  (type $out-i32 (func (result i32)))
+  (import "module1" "shared-table" (table 10 funcref))
+  (elem (i32.const 8) $const-i32-e)
+  (elem (i32.const 9) $const-i32-f)
+  (func $const-i32-e (type $out-i32) (i32.const 69))
+  (func $const-i32-f (type $out-i32) (i32.const 70))
+)
+
+(assert_return (invoke $module1 "call-7") (i32.const 67))
+(assert_return (invoke $module1 "call-8") (i32.const 69))
+(assert_return (invoke $module1 "call-9") (i32.const 70))
diff --git a/binaryen/test/spec/endianness.wast b/binaryen/test/spec/endianness.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/endianness.wast
@@ -0,0 +1,217 @@
+(module
+  (memory 1)
+
+  ;; Stores an i16 value in little-endian-format
+  (func $i16_store_little (param $address i32) (param $value i32)
+    (i32.store8 (local.get $address) (local.get $value))
+    (i32.store8 (i32.add (local.get $address) (i32.const 1)) (i32.shr_u (local.get $value) (i32.const 8)))
+  )
+
+  ;; Stores an i32 value in little-endian format
+  (func $i32_store_little (param $address i32) (param $value i32)
+    (call $i16_store_little (local.get $address) (local.get $value))
+    (call $i16_store_little (i32.add (local.get $address) (i32.const 2)) (i32.shr_u (local.get $value) (i32.const 16)))
+  )
+
+  ;; Stores an i64 value in little-endian format
+  (func $i64_store_little (param $address i32) (param $value i64)
+    (call $i32_store_little (local.get $address) (i32.wrap_i64 (local.get $value)))
+    (call $i32_store_little (i32.add (local.get $address) (i32.const 4)) (i32.wrap_i64 (i64.shr_u (local.get $value) (i64.const 32))))
+  )
+
+  ;; Loads an i16 value in little-endian format
+  (func $i16_load_little (param $address i32) (result i32)
+    (i32.or
+      (i32.load8_u (local.get $address))
+      (i32.shl (i32.load8_u (i32.add (local.get $address) (i32.const 1))) (i32.const 8))
+    )
+  )
+
+  ;; Loads an i32 value in little-endian format
+  (func $i32_load_little (param $address i32) (result i32)
+    (i32.or
+      (call $i16_load_little (local.get $address))
+      (i32.shl (call $i16_load_little (i32.add (local.get $address) (i32.const 2))) (i32.const 16))
+    )
+  )
+
+  ;; Loads an i64 value in little-endian format
+  (func $i64_load_little (param $address i32) (result i64)
+    (i64.or
+      (i64.extend_i32_u (call $i32_load_little (local.get $address)))
+      (i64.shl (i64.extend_i32_u (call $i32_load_little (i32.add (local.get $address) (i32.const 4)))) (i64.const 32))
+    )
+  )
+
+  (func (export "i32_load16_s") (param $value i32) (result i32)
+    (call $i16_store_little (i32.const 0) (local.get $value))
+    (i32.load16_s (i32.const 0))
+  )
+
+  (func (export "i32_load16_u") (param $value i32) (result i32)
+    (call $i16_store_little (i32.const 0) (local.get $value))
+    (i32.load16_u (i32.const 0))
+  )
+
+  (func (export "i32_load") (param $value i32) (result i32)
+    (call $i32_store_little (i32.const 0) (local.get $value))
+    (i32.load (i32.const 0))
+  )
+
+  (func (export "i64_load16_s") (param $value i64) (result i64)
+    (call $i16_store_little (i32.const 0) (i32.wrap_i64 (local.get $value)))
+    (i64.load16_s (i32.const 0))
+  )
+
+  (func (export "i64_load16_u") (param $value i64) (result i64)
+    (call $i16_store_little (i32.const 0) (i32.wrap_i64 (local.get $value)))
+    (i64.load16_u (i32.const 0))
+  )
+
+  (func (export "i64_load32_s") (param $value i64) (result i64)
+    (call $i32_store_little (i32.const 0) (i32.wrap_i64 (local.get $value)))
+    (i64.load32_s (i32.const 0))
+  )
+
+  (func (export "i64_load32_u") (param $value i64) (result i64)
+    (call $i32_store_little (i32.const 0) (i32.wrap_i64 (local.get $value)))
+    (i64.load32_u (i32.const 0))
+  )
+
+  (func (export "i64_load") (param $value i64) (result i64)
+    (call $i64_store_little (i32.const 0) (local.get $value))
+    (i64.load (i32.const 0))
+  )
+
+  (func (export "f32_load") (param $value f32) (result f32)
+    (call $i32_store_little (i32.const 0) (i32.reinterpret_f32 (local.get $value)))
+    (f32.load (i32.const 0))
+  )
+
+  (func (export "f64_load") (param $value f64) (result f64)
+    (call $i64_store_little (i32.const 0) (i64.reinterpret_f64 (local.get $value)))
+    (f64.load (i32.const 0))
+  )
+
+
+  (func (export "i32_store16") (param $value i32) (result i32)
+    (i32.store16 (i32.const 0) (local.get $value))
+    (call $i16_load_little (i32.const 0))
+  )
+
+  (func (export "i32_store") (param $value i32) (result i32)
+    (i32.store (i32.const 0) (local.get $value))
+    (call $i32_load_little (i32.const 0))
+  )
+
+  (func (export "i64_store16") (param $value i64) (result i64)
+    (i64.store16 (i32.const 0) (local.get $value))
+    (i64.extend_i32_u (call $i16_load_little (i32.const 0)))
+  )
+
+  (func (export "i64_store32") (param $value i64) (result i64)
+    (i64.store32 (i32.const 0) (local.get $value))
+    (i64.extend_i32_u (call $i32_load_little (i32.const 0)))
+  )
+
+  (func (export "i64_store") (param $value i64) (result i64)
+    (i64.store (i32.const 0) (local.get $value))
+    (call $i64_load_little (i32.const 0))
+  )
+
+  (func (export "f32_store") (param $value f32) (result f32)
+    (f32.store (i32.const 0) (local.get $value))
+    (f32.reinterpret_i32 (call $i32_load_little (i32.const 0)))
+  )
+
+  (func (export "f64_store") (param $value f64) (result f64)
+    (f64.store (i32.const 0) (local.get $value))
+    (f64.reinterpret_i64 (call $i64_load_little (i32.const 0)))
+  )
+)
+
+(assert_return (invoke "i32_load16_s" (i32.const -1)) (i32.const -1))
+(assert_return (invoke "i32_load16_s" (i32.const -4242)) (i32.const -4242))
+(assert_return (invoke "i32_load16_s" (i32.const 42)) (i32.const 42))
+(assert_return (invoke "i32_load16_s" (i32.const 0x3210)) (i32.const 0x3210))
+
+(assert_return (invoke "i32_load16_u" (i32.const -1)) (i32.const 0xFFFF))
+(assert_return (invoke "i32_load16_u" (i32.const -4242)) (i32.const 61294))
+(assert_return (invoke "i32_load16_u" (i32.const 42)) (i32.const 42))
+(assert_return (invoke "i32_load16_u" (i32.const 0xCAFE)) (i32.const 0xCAFE))
+
+(assert_return (invoke "i32_load" (i32.const -1)) (i32.const -1))
+(assert_return (invoke "i32_load" (i32.const -42424242)) (i32.const -42424242))
+(assert_return (invoke "i32_load" (i32.const 42424242)) (i32.const 42424242))
+(assert_return (invoke "i32_load" (i32.const 0xABAD1DEA)) (i32.const 0xABAD1DEA))
+
+(assert_return (invoke "i64_load16_s" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_load16_s" (i64.const -4242)) (i64.const -4242))
+(assert_return (invoke "i64_load16_s" (i64.const 42)) (i64.const 42))
+(assert_return (invoke "i64_load16_s" (i64.const 0x3210)) (i64.const 0x3210))
+
+(assert_return (invoke "i64_load16_u" (i64.const -1)) (i64.const 0xFFFF))
+(assert_return (invoke "i64_load16_u" (i64.const -4242)) (i64.const 61294))
+(assert_return (invoke "i64_load16_u" (i64.const 42)) (i64.const 42))
+(assert_return (invoke "i64_load16_u" (i64.const 0xCAFE)) (i64.const 0xCAFE))
+
+(assert_return (invoke "i64_load32_s" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_load32_s" (i64.const -42424242)) (i64.const -42424242))
+(assert_return (invoke "i64_load32_s" (i64.const 42424242)) (i64.const 42424242))
+(assert_return (invoke "i64_load32_s" (i64.const 0x12345678)) (i64.const 0x12345678))
+
+(assert_return (invoke "i64_load32_u" (i64.const -1)) (i64.const 0xFFFFFFFF))
+(assert_return (invoke "i64_load32_u" (i64.const -42424242)) (i64.const 4252543054))
+(assert_return (invoke "i64_load32_u" (i64.const 42424242)) (i64.const 42424242))
+(assert_return (invoke "i64_load32_u" (i64.const 0xABAD1DEA)) (i64.const 0xABAD1DEA))
+
+(assert_return (invoke "i64_load" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_load" (i64.const -42424242)) (i64.const -42424242))
+(assert_return (invoke "i64_load" (i64.const 0xABAD1DEA)) (i64.const 0xABAD1DEA))
+(assert_return (invoke "i64_load" (i64.const 0xABADCAFEDEAD1DEA)) (i64.const 0xABADCAFEDEAD1DEA))
+
+(assert_return (invoke "f32_load" (f32.const -1)) (f32.const -1))
+(assert_return (invoke "f32_load" (f32.const 1234e-5)) (f32.const 1234e-5))
+(assert_return (invoke "f32_load" (f32.const 4242.4242)) (f32.const 4242.4242))
+(assert_return (invoke "f32_load" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+
+(assert_return (invoke "f64_load" (f64.const -1)) (f64.const -1))
+(assert_return (invoke "f64_load" (f64.const 123456789e-5)) (f64.const 123456789e-5))
+(assert_return (invoke "f64_load" (f64.const 424242.424242)) (f64.const 424242.424242))
+(assert_return (invoke "f64_load" (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+
+
+(assert_return (invoke "i32_store16" (i32.const -1)) (i32.const 0xFFFF))
+(assert_return (invoke "i32_store16" (i32.const -4242)) (i32.const 61294))
+(assert_return (invoke "i32_store16" (i32.const 42)) (i32.const 42))
+(assert_return (invoke "i32_store16" (i32.const 0xCAFE)) (i32.const 0xCAFE))
+
+(assert_return (invoke "i32_store" (i32.const -1)) (i32.const -1))
+(assert_return (invoke "i32_store" (i32.const -4242)) (i32.const -4242))
+(assert_return (invoke "i32_store" (i32.const 42424242)) (i32.const 42424242))
+(assert_return (invoke "i32_store" (i32.const 0xDEADCAFE)) (i32.const 0xDEADCAFE))
+
+(assert_return (invoke "i64_store16" (i64.const -1)) (i64.const 0xFFFF))
+(assert_return (invoke "i64_store16" (i64.const -4242)) (i64.const 61294))
+(assert_return (invoke "i64_store16" (i64.const 42)) (i64.const 42))
+(assert_return (invoke "i64_store16" (i64.const 0xCAFE)) (i64.const 0xCAFE))
+
+(assert_return (invoke "i64_store32" (i64.const -1)) (i64.const 0xFFFFFFFF))
+(assert_return (invoke "i64_store32" (i64.const -4242)) (i64.const 4294963054))
+(assert_return (invoke "i64_store32" (i64.const 42424242)) (i64.const 42424242))
+(assert_return (invoke "i64_store32" (i64.const 0xDEADCAFE)) (i64.const 0xDEADCAFE))
+
+(assert_return (invoke "i64_store" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_store" (i64.const -42424242)) (i64.const -42424242))
+(assert_return (invoke "i64_store" (i64.const 0xABAD1DEA)) (i64.const 0xABAD1DEA))
+(assert_return (invoke "i64_store" (i64.const 0xABADCAFEDEAD1DEA)) (i64.const 0xABADCAFEDEAD1DEA))
+
+(assert_return (invoke "f32_store" (f32.const -1)) (f32.const -1))
+(assert_return (invoke "f32_store" (f32.const 1234e-5)) (f32.const 1234e-5))
+(assert_return (invoke "f32_store" (f32.const 4242.4242)) (f32.const 4242.4242))
+(assert_return (invoke "f32_store" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+
+(assert_return (invoke "f64_store" (f64.const -1)) (f64.const -1))
+(assert_return (invoke "f64_store" (f64.const 123456789e-5)) (f64.const 123456789e-5))
+(assert_return (invoke "f64_store" (f64.const 424242.424242)) (f64.const 424242.424242))
+(assert_return (invoke "f64_store" (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
diff --git a/binaryen/test/spec/endianness64.wast b/binaryen/test/spec/endianness64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/endianness64.wast
@@ -0,0 +1,217 @@
+(module
+  (memory i64 1)
+
+  ;; Stores an i16 value in little-endian-format
+  (func $i16_store_little (param $address i64) (param $value i32)
+    (i32.store8 (local.get $address) (local.get $value))
+    (i32.store8 (i64.add (local.get $address) (i64.const 1)) (i32.shr_u (local.get $value) (i32.const 8)))
+  )
+
+  ;; Stores an i32 value in little-endian format
+  (func $i32_store_little (param $address i64) (param $value i32)
+    (call $i16_store_little (local.get $address) (local.get $value))
+    (call $i16_store_little (i64.add (local.get $address) (i64.const 2)) (i32.shr_u (local.get $value) (i32.const 16)))
+  )
+
+  ;; Stores an i64 value in little-endian format
+  (func $i64_store_little (param $address i64) (param $value i64)
+    (call $i32_store_little (local.get $address) (i32.wrap_i64 (local.get $value)))
+    (call $i32_store_little (i64.add (local.get $address) (i64.const 4)) (i32.wrap_i64 (i64.shr_u (local.get $value) (i64.const 32))))
+  )
+
+  ;; Loads an i16 value in little-endian format
+  (func $i16_load_little (param $address i64) (result i32)
+    (i32.or
+      (i32.load8_u (local.get $address))
+      (i32.shl (i32.load8_u (i64.add (local.get $address) (i64.const 1))) (i32.const 8))
+    )
+  )
+
+  ;; Loads an i32 value in little-endian format
+  (func $i32_load_little (param $address i64) (result i32)
+    (i32.or
+      (call $i16_load_little (local.get $address))
+      (i32.shl (call $i16_load_little (i64.add (local.get $address) (i64.const 2))) (i32.const 16))
+    )
+  )
+
+  ;; Loads an i64 value in little-endian format
+  (func $i64_load_little (param $address i64) (result i64)
+    (i64.or
+      (i64.extend_i32_u (call $i32_load_little (local.get $address)))
+      (i64.shl (i64.extend_i32_u (call $i32_load_little (i64.add (local.get $address) (i64.const 4)))) (i64.const 32))
+    )
+  )
+
+  (func (export "i32_load16_s") (param $value i32) (result i32)
+    (call $i16_store_little (i64.const 0) (local.get $value))
+    (i32.load16_s (i64.const 0))
+  )
+
+  (func (export "i32_load16_u") (param $value i32) (result i32)
+    (call $i16_store_little (i64.const 0) (local.get $value))
+    (i32.load16_u (i64.const 0))
+  )
+
+  (func (export "i32_load") (param $value i32) (result i32)
+    (call $i32_store_little (i64.const 0) (local.get $value))
+    (i32.load (i64.const 0))
+  )
+
+  (func (export "i64_load16_s") (param $value i64) (result i64)
+    (call $i16_store_little (i64.const 0) (i32.wrap_i64 (local.get $value)))
+    (i64.load16_s (i64.const 0))
+  )
+
+  (func (export "i64_load16_u") (param $value i64) (result i64)
+    (call $i16_store_little (i64.const 0) (i32.wrap_i64 (local.get $value)))
+    (i64.load16_u (i64.const 0))
+  )
+
+  (func (export "i64_load32_s") (param $value i64) (result i64)
+    (call $i32_store_little (i64.const 0) (i32.wrap_i64 (local.get $value)))
+    (i64.load32_s (i64.const 0))
+  )
+
+  (func (export "i64_load32_u") (param $value i64) (result i64)
+    (call $i32_store_little (i64.const 0) (i32.wrap_i64 (local.get $value)))
+    (i64.load32_u (i64.const 0))
+  )
+
+  (func (export "i64_load") (param $value i64) (result i64)
+    (call $i64_store_little (i64.const 0) (local.get $value))
+    (i64.load (i64.const 0))
+  )
+
+  (func (export "f32_load") (param $value f32) (result f32)
+    (call $i32_store_little (i64.const 0) (i32.reinterpret_f32 (local.get $value)))
+    (f32.load (i64.const 0))
+  )
+
+  (func (export "f64_load") (param $value f64) (result f64)
+    (call $i64_store_little (i64.const 0) (i64.reinterpret_f64 (local.get $value)))
+    (f64.load (i64.const 0))
+  )
+
+
+  (func (export "i32_store16") (param $value i32) (result i32)
+    (i32.store16 (i64.const 0) (local.get $value))
+    (call $i16_load_little (i64.const 0))
+  )
+
+  (func (export "i32_store") (param $value i32) (result i32)
+    (i32.store (i64.const 0) (local.get $value))
+    (call $i32_load_little (i64.const 0))
+  )
+
+  (func (export "i64_store16") (param $value i64) (result i64)
+    (i64.store16 (i64.const 0) (local.get $value))
+    (i64.extend_i32_u (call $i16_load_little (i64.const 0)))
+  )
+
+  (func (export "i64_store32") (param $value i64) (result i64)
+    (i64.store32 (i64.const 0) (local.get $value))
+    (i64.extend_i32_u (call $i32_load_little (i64.const 0)))
+  )
+
+  (func (export "i64_store") (param $value i64) (result i64)
+    (i64.store (i64.const 0) (local.get $value))
+    (call $i64_load_little (i64.const 0))
+  )
+
+  (func (export "f32_store") (param $value f32) (result f32)
+    (f32.store (i64.const 0) (local.get $value))
+    (f32.reinterpret_i32 (call $i32_load_little (i64.const 0)))
+  )
+
+  (func (export "f64_store") (param $value f64) (result f64)
+    (f64.store (i64.const 0) (local.get $value))
+    (f64.reinterpret_i64 (call $i64_load_little (i64.const 0)))
+  )
+)
+
+(assert_return (invoke "i32_load16_s" (i32.const -1)) (i32.const -1))
+(assert_return (invoke "i32_load16_s" (i32.const -4242)) (i32.const -4242))
+(assert_return (invoke "i32_load16_s" (i32.const 42)) (i32.const 42))
+(assert_return (invoke "i32_load16_s" (i32.const 0x3210)) (i32.const 0x3210))
+
+(assert_return (invoke "i32_load16_u" (i32.const -1)) (i32.const 0xFFFF))
+(assert_return (invoke "i32_load16_u" (i32.const -4242)) (i32.const 61294))
+(assert_return (invoke "i32_load16_u" (i32.const 42)) (i32.const 42))
+(assert_return (invoke "i32_load16_u" (i32.const 0xCAFE)) (i32.const 0xCAFE))
+
+(assert_return (invoke "i32_load" (i32.const -1)) (i32.const -1))
+(assert_return (invoke "i32_load" (i32.const -42424242)) (i32.const -42424242))
+(assert_return (invoke "i32_load" (i32.const 42424242)) (i32.const 42424242))
+(assert_return (invoke "i32_load" (i32.const 0xABAD1DEA)) (i32.const 0xABAD1DEA))
+
+(assert_return (invoke "i64_load16_s" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_load16_s" (i64.const -4242)) (i64.const -4242))
+(assert_return (invoke "i64_load16_s" (i64.const 42)) (i64.const 42))
+(assert_return (invoke "i64_load16_s" (i64.const 0x3210)) (i64.const 0x3210))
+
+(assert_return (invoke "i64_load16_u" (i64.const -1)) (i64.const 0xFFFF))
+(assert_return (invoke "i64_load16_u" (i64.const -4242)) (i64.const 61294))
+(assert_return (invoke "i64_load16_u" (i64.const 42)) (i64.const 42))
+(assert_return (invoke "i64_load16_u" (i64.const 0xCAFE)) (i64.const 0xCAFE))
+
+(assert_return (invoke "i64_load32_s" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_load32_s" (i64.const -42424242)) (i64.const -42424242))
+(assert_return (invoke "i64_load32_s" (i64.const 42424242)) (i64.const 42424242))
+(assert_return (invoke "i64_load32_s" (i64.const 0x12345678)) (i64.const 0x12345678))
+
+(assert_return (invoke "i64_load32_u" (i64.const -1)) (i64.const 0xFFFFFFFF))
+(assert_return (invoke "i64_load32_u" (i64.const -42424242)) (i64.const 4252543054))
+(assert_return (invoke "i64_load32_u" (i64.const 42424242)) (i64.const 42424242))
+(assert_return (invoke "i64_load32_u" (i64.const 0xABAD1DEA)) (i64.const 0xABAD1DEA))
+
+(assert_return (invoke "i64_load" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_load" (i64.const -42424242)) (i64.const -42424242))
+(assert_return (invoke "i64_load" (i64.const 0xABAD1DEA)) (i64.const 0xABAD1DEA))
+(assert_return (invoke "i64_load" (i64.const 0xABADCAFEDEAD1DEA)) (i64.const 0xABADCAFEDEAD1DEA))
+
+(assert_return (invoke "f32_load" (f32.const -1)) (f32.const -1))
+(assert_return (invoke "f32_load" (f32.const 1234e-5)) (f32.const 1234e-5))
+(assert_return (invoke "f32_load" (f32.const 4242.4242)) (f32.const 4242.4242))
+(assert_return (invoke "f32_load" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+
+(assert_return (invoke "f64_load" (f64.const -1)) (f64.const -1))
+(assert_return (invoke "f64_load" (f64.const 123456789e-5)) (f64.const 123456789e-5))
+(assert_return (invoke "f64_load" (f64.const 424242.424242)) (f64.const 424242.424242))
+(assert_return (invoke "f64_load" (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+
+
+(assert_return (invoke "i32_store16" (i32.const -1)) (i32.const 0xFFFF))
+(assert_return (invoke "i32_store16" (i32.const -4242)) (i32.const 61294))
+(assert_return (invoke "i32_store16" (i32.const 42)) (i32.const 42))
+(assert_return (invoke "i32_store16" (i32.const 0xCAFE)) (i32.const 0xCAFE))
+
+(assert_return (invoke "i32_store" (i32.const -1)) (i32.const -1))
+(assert_return (invoke "i32_store" (i32.const -4242)) (i32.const -4242))
+(assert_return (invoke "i32_store" (i32.const 42424242)) (i32.const 42424242))
+(assert_return (invoke "i32_store" (i32.const 0xDEADCAFE)) (i32.const 0xDEADCAFE))
+
+(assert_return (invoke "i64_store16" (i64.const -1)) (i64.const 0xFFFF))
+(assert_return (invoke "i64_store16" (i64.const -4242)) (i64.const 61294))
+(assert_return (invoke "i64_store16" (i64.const 42)) (i64.const 42))
+(assert_return (invoke "i64_store16" (i64.const 0xCAFE)) (i64.const 0xCAFE))
+
+(assert_return (invoke "i64_store32" (i64.const -1)) (i64.const 0xFFFFFFFF))
+(assert_return (invoke "i64_store32" (i64.const -4242)) (i64.const 4294963054))
+(assert_return (invoke "i64_store32" (i64.const 42424242)) (i64.const 42424242))
+(assert_return (invoke "i64_store32" (i64.const 0xDEADCAFE)) (i64.const 0xDEADCAFE))
+
+(assert_return (invoke "i64_store" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_store" (i64.const -42424242)) (i64.const -42424242))
+(assert_return (invoke "i64_store" (i64.const 0xABAD1DEA)) (i64.const 0xABAD1DEA))
+(assert_return (invoke "i64_store" (i64.const 0xABADCAFEDEAD1DEA)) (i64.const 0xABADCAFEDEAD1DEA))
+
+(assert_return (invoke "f32_store" (f32.const -1)) (f32.const -1))
+(assert_return (invoke "f32_store" (f32.const 1234e-5)) (f32.const 1234e-5))
+(assert_return (invoke "f32_store" (f32.const 4242.4242)) (f32.const 4242.4242))
+(assert_return (invoke "f32_store" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+
+(assert_return (invoke "f64_store" (f64.const -1)) (f64.const -1))
+(assert_return (invoke "f64_store" (f64.const 123456789e-5)) (f64.const 123456789e-5))
+(assert_return (invoke "f64_store" (f64.const 424242.424242)) (f64.const 424242.424242))
+(assert_return (invoke "f64_store" (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
diff --git a/binaryen/test/spec/events.wast b/binaryen/test/spec/events.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/events.wast
@@ -0,0 +1,33 @@
+;; Test events
+
+(module
+  (event (attr 0) (param i32))
+  (event $e (attr 0) (param i32 f32))
+
+  (event $e-params0 (attr 0) (param i32 f32))
+  (event $e-params1 (attr 0) (param i32) (param f32))
+
+  (event $e-export (export "ex0") (attr 0) (param i32))
+  (event $e-import (import "env" "im0") (attr 0) (param i32))
+
+  (import "env" "im1" (event (attr 0) (param i32 f32)))
+  (export "ex1" (event $e))
+)
+
+(assert_invalid
+  (module (event $e (attr 0) (param i32) (result i32)))
+  "Event type's result type should be none"
+)
+
+(assert_invalid
+  (module (event $e (attr 1) (param i32)))
+  "Currently only attribute 0 is supported"
+)
+
+(assert_invalid
+  (module
+    (type $t (param i32))
+    (event $e (attr 0) (type $t) (param i32 f32))
+  )
+  "type and param don't match"
+)
diff --git a/binaryen/test/spec/exception-handling.wast b/binaryen/test/spec/exception-handling.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/exception-handling.wast
@@ -0,0 +1,296 @@
+(module
+  (event $e-v (attr 0))
+  (event $e-i32 (attr 0) (param i32))
+  (event $e-i32-f32 (attr 0) (param i32 f32))
+
+  (func $throw_single_value (export "throw_single_value")
+    (throw $e-i32 (i32.const 5))
+  )
+
+  (func (export "throw_multiple_values")
+    (throw $e-i32-f32 (i32.const 3) (f32.const 3.5))
+  )
+
+  (func (export "rethrow_null")
+    (rethrow (ref.null exn))
+  )
+
+  (func (export "try_nothrow") (result i32)
+    (try (result i32)
+      (do
+        (i32.const 3)
+      )
+      (catch
+        (drop (pop exnref))
+        (i32.const 0)
+      )
+    )
+  )
+
+  (func (export "try_throw_catch") (result i32)
+    (try (result i32)
+      (do
+        (throw $e-i32 (i32.const 5))
+      )
+      (catch
+        (drop (pop exnref))
+        (i32.const 3)
+      )
+    )
+  )
+
+  (func (export "try_call_catch") (result i32)
+    (try (result i32)
+      (do
+        (call $throw_single_value)
+        (unreachable)
+      )
+      (catch
+        (drop (pop exnref))
+        (i32.const 3)
+      )
+    )
+  )
+
+  (func (export "try_throw_rethrow")
+    (try
+      (do
+        (throw $e-i32 (i32.const 5))
+      )
+      (catch
+        (rethrow (pop exnref))
+      )
+    )
+  )
+
+  (func $try_call_rethrow (export "try_call_rethrow")
+    (try
+      (do
+        (call $throw_single_value)
+      )
+      (catch
+        (rethrow (pop exnref))
+      )
+    )
+  )
+
+  (func (export "br_on_exn_null") (result i32)
+    (block $l0 (result i32)
+      (drop
+        (br_on_exn $l0 $e-i32 (ref.null exn))
+      )
+      (i32.const 0)
+    )
+  )
+
+  (func (export "br_on_exn_match_no_value") (local $exn exnref)
+    (try
+      (do
+        (throw $e-v)
+      )
+      (catch
+        (local.set $exn (pop exnref))
+        (block $l0
+          (rethrow
+            (br_on_exn $l0 $e-v (local.get $exn))
+          )
+        )
+      )
+    )
+  )
+
+  (func (export "br_on_exn_match_single_value") (result i32) (local $exn exnref)
+    (try (result i32)
+      (do
+        (throw $e-i32 (i32.const 5))
+      )
+      (catch
+        (local.set $exn (pop exnref))
+        (block $l0 (result i32)
+          (rethrow
+            (br_on_exn $l0 $e-i32 (local.get $exn))
+          )
+        )
+      )
+    )
+  )
+
+  (func (export "br_on_exn_match_multiple_values") (result i32 f32)
+        (local $exn exnref)
+    (try (result i32 f32)
+      (do
+        (throw $e-i32-f32 (i32.const 3) (f32.const 3.5))
+      )
+      (catch
+        (local.set $exn (pop exnref))
+        (block $l0 (result i32 f32)
+          (rethrow
+            (br_on_exn $l0 $e-i32-f32 (local.get $exn))
+          )
+        )
+      )
+    )
+  )
+
+  (func (export "br_on_exn_dont_match") (local $exn exnref)
+    (try
+      (do
+        (throw $e-i32 (i32.const 5))
+      )
+      (catch
+        (local.set $exn (pop exnref))
+        (block $l0
+          (rethrow
+            (br_on_exn $l0 $e-v (local.get $exn))
+          )
+        )
+      )
+    )
+  )
+
+  (func (export "call_br_on_exn") (result i32) (local $exn exnref)
+    (try (result i32)
+      (do
+        (call $throw_single_value)
+        (unreachable)
+      )
+      (catch
+        (local.set $exn (pop exnref))
+        (block $l0 (result i32)
+          (rethrow
+            (br_on_exn $l0 $e-i32 (local.get $exn))
+          )
+        )
+      )
+    )
+  )
+
+  (func (export "call_rethrow_br_on_exn") (result i32) (local $exn exnref)
+    (try (result i32)
+      (do
+        (call $try_call_rethrow)
+        (unreachable)
+      )
+      (catch
+        (local.set $exn (pop exnref))
+        (block $l0 (result i32)
+          (rethrow
+            (br_on_exn $l0 $e-i32 (local.get $exn))
+          )
+        )
+      )
+    )
+  )
+)
+
+(assert_trap (invoke "throw_single_value"))
+(assert_trap (invoke "throw_multiple_values"))
+(assert_trap (invoke "rethrow_null"))
+(assert_return (invoke "try_nothrow") (i32.const 3))
+(assert_return (invoke "try_throw_catch") (i32.const 3))
+(assert_return (invoke "try_call_catch") (i32.const 3))
+(assert_trap (invoke "try_throw_rethrow"))
+(assert_trap (invoke "try_call_rethrow"))
+(assert_trap (invoke "br_on_exn_null"))
+(assert_return (invoke "br_on_exn_match_no_value"))
+(assert_return (invoke "br_on_exn_match_single_value") (i32.const 5))
+(assert_return (invoke "br_on_exn_match_multiple_values") (tuple.make (i32.const 3) (f32.const 3.5)))
+(assert_trap (invoke "br_on_exn_dont_match"))
+(assert_return (invoke "call_rethrow_br_on_exn") (i32.const 5))
+
+(assert_invalid
+  (module
+    (func $f0
+      (try
+        (do (nop))
+        (catch (i32.const 0))
+      )
+    )
+  )
+  "try's body type must match catch's body type"
+)
+
+(assert_invalid
+  (module
+    (func $f0
+      (try
+        (do (i32.const 0))
+        (catch (i32.const 0))
+      )
+    )
+  )
+   "try's type does not match try body's type"
+)
+
+(assert_invalid
+  (module
+    (event $e-i32 (attr 0) (param i32))
+    (func $f0
+      (throw $e-i32 (f32.const 0))
+    )
+  )
+  "event param types must match"
+)
+
+(assert_invalid
+  (module
+    (event $e-i32 (attr 0) (param i32 f32))
+    (func $f0
+      (throw $e-i32 (f32.const 0))
+    )
+  )
+  "event's param numbers must match"
+)
+
+(assert_invalid
+  (module
+    (func $f0
+      (rethrow (i32.const 0))
+    )
+  )
+  "rethrow's argument must be exnref type"
+)
+
+(assert_invalid
+  (module
+    (event $e-i32 (attr 0) (param i32))
+    (func $f0 (result i32)
+      (block $l0 (result i32)
+        (drop
+          (br_on_exn $l0 $e-i32 (i32.const 0))
+        )
+        (i32.const 0)
+      )
+    )
+  )
+  "br_on_exn's argument must be unreachable or exnref type"
+)
+
+(assert_invalid
+  (module
+    (event $e-i32 (attr 0) (param i32))
+    (func $f0 (result i32) (local $0 exnref)
+      (block $l0 (result i32)
+        (i32.eqz
+          (br_on_exn $l0 $e-i32 (local.get $0))
+        )
+      )
+    )
+  )
+  "i32.eqz input must be i32"
+)
+
+(assert_invalid
+  (module
+    (event $e-i32 (attr 0) (param i32))
+    (func $f0 (result f32) (local $0 exnref)
+      (block $l0 (result f32)
+        (drop
+          (br_on_exn $l0 $e-i32 (local.get $0))
+        )
+        (f32.const 0)
+      )
+    )
+  )
+  "block+breaks must have right type if breaks return a value"
+)
diff --git a/binaryen/test/spec/expected-output/func_ptrs.wast.log b/binaryen/test/spec/expected-output/func_ptrs.wast.log
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/expected-output/func_ptrs.wast.log
@@ -0,0 +1,1 @@
+83 : i32
diff --git a/binaryen/test/spec/expected-output/names.wast.log b/binaryen/test/spec/expected-output/names.wast.log
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/expected-output/names.wast.log
@@ -0,0 +1,2 @@
+42 : i32
+123 : i32
diff --git a/binaryen/test/spec/expected-output/old_imports.wast.log b/binaryen/test/spec/expected-output/old_imports.wast.log
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/expected-output/old_imports.wast.log
@@ -0,0 +1,10 @@
+13 : i32
+14 : i32
+42 : f32
+13 : i32
+13 : i32
+24 : i64
+25 : i64
+53 : f64
+24 : i64
+24 : i64
diff --git a/binaryen/test/spec/expected-output/old_start.wast.log b/binaryen/test/spec/expected-output/old_start.wast.log
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/expected-output/old_start.wast.log
@@ -0,0 +1,2 @@
+1 : i32
+2 : i32
diff --git a/binaryen/test/spec/exports.wast b/binaryen/test/spec/exports.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/exports.wast
@@ -0,0 +1,198 @@
+;; Functions
+
+(module (func) (export "a" (func 0)))
+(module (func) (export "a" (func 0)) (export "b" (func 0)))
+(module (func) (func) (export "a" (func 0)) (export "b" (func 1)))
+
+(module (func (export "a")))
+(module (func (export "a") (export "b") (export "c")))
+(module (func (export "a") (export "b") (param i32)))
+(module (func) (export "a" (func 0)))
+(module (func $a (export "a")))
+(module (func $a) (export "a" (func $a)))
+(module (export "a" (func 0)) (func))
+(module (export "a" (func $a)) (func $a))
+
+(module $Func
+  (export "e" (func $f))
+  (func $f (param $n i32) (result i32)
+    (return (i32.add (local.get $n) (i32.const 1)))
+  )
+)
+(assert_return (invoke "e" (i32.const 42)) (i32.const 43))
+(assert_return (invoke $Func "e" (i32.const 42)) (i32.const 43))
+(module)
+(module $Other1)
+(assert_return (invoke $Func "e" (i32.const 42)) (i32.const 43))
+
+(assert_invalid
+  (module (func) (export "a" (func 1)))
+  "unknown function"
+)
+(assert_invalid
+  (module (func) (export "a" (func 0)) (export "a" (func 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (func) (func) (export "a" (func 0)) (export "a" (func 1)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (func) (global i32 (i32.const 0)) (export "a" (func 0)) (export "a" (global 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (func) (table 0 funcref) (export "a" (func 0)) (export "a" (table 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (func) (memory 0) (export "a" (func 0)) (export "a" (memory 0)))
+  "duplicate export name"
+)
+
+
+;; Globals
+
+(module (global i32 (i32.const 0)) (export "a" (global 0)))
+(module (global i32 (i32.const 0)) (export "a" (global 0)) (export "b" (global 0)))
+(module (global i32 (i32.const 0)) (global i32 (i32.const 0)) (export "a" (global 0)) (export "b" (global 1)))
+
+(module (global (export "a") i32 (i32.const 0)))
+(module (global i32 (i32.const 0)) (export "a" (global 0)))
+(module (global $a (export "a") i32 (i32.const 0)))
+(module (global $a i32 (i32.const 0)) (export "a" (global $a)))
+(module (export "a" (global 0)) (global i32 (i32.const 0)))
+(module (export "a" (global $a)) (global $a i32 (i32.const 0)))
+
+(module $Global
+  (export "e" (global $g))
+  (global $g i32 (i32.const 42))
+)
+(assert_return (get "e") (i32.const 42))
+(assert_return (get $Global "e") (i32.const 42))
+(module)
+(module $Other2)
+(assert_return (get $Global "e") (i32.const 42))
+
+(assert_invalid
+  (module (global i32 (i32.const 0)) (export "a" (global 1)))
+  "unknown global"
+)
+(assert_invalid
+  (module (global i32 (i32.const 0)) (export "a" (global 0)) (export "a" (global 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (global i32 (i32.const 0)) (global i32 (i32.const 0)) (export "a" (global 0)) (export "a" (global 1)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (global i32 (i32.const 0)) (func) (export "a" (global 0)) (export "a" (func 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (global i32 (i32.const 0)) (table 0 funcref) (export "a" (global 0)) (export "a" (table 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (global i32 (i32.const 0)) (memory 0) (export "a" (global 0)) (export "a" (memory 0)))
+  "duplicate export name"
+)
+
+
+;; Tables
+
+(module (table 0 funcref) (export "a" (table 0)))
+(module (table 0 funcref) (export "a" (table 0)) (export "b" (table 0)))
+;; No multiple tables yet.
+;; (module (table 0 funcref) (table 0 funcref) (export "a" (table 0)) (export "b" (table 1)))
+
+(module (table (export "a") 0 funcref))
+(module (table (export "a") 0 1 funcref))
+(module (table 0 funcref) (export "a" (table 0)))
+(module (table 0 1 funcref) (export "a" (table 0)))
+(module (table $a (export "a") 0 funcref))
+(module (table $a (export "a") 0 1 funcref))
+(module (table $a 0 funcref) (export "a" (table $a)))
+(module (table $a 0 1 funcref) (export "a" (table $a)))
+(module (export "a" (table 0)) (table 0 funcref))
+(module (export "a" (table 0)) (table 0 1 funcref))
+(module (export "a" (table $a)) (table $a 0 funcref))
+(module (export "a" (table $a)) (table $a 0 1 funcref))
+
+(; TODO: access table ;)
+
+(assert_invalid
+  (module (table 0 funcref) (export "a" (table 1)))
+  "unknown table"
+)
+(assert_invalid
+  (module (table 0 funcref) (export "a" (table 0)) (export "a" (table 0)))
+  "duplicate export name"
+)
+;; No multiple tables yet.
+;; (assert_invalid
+;;   (module (table 0 funcref) (table 0 funcref) (export "a" (table 0)) (export "a" (table 1)))
+;;   "duplicate export name"
+;; )
+(assert_invalid
+  (module (table 0 funcref) (func) (export "a" (table 0)) (export "a" (func 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (table 0 funcref) (global i32 (i32.const 0)) (export "a" (table 0)) (export "a" (global 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (table 0 funcref) (memory 0) (export "a" (table 0)) (export "a" (memory 0)))
+  "duplicate export name"
+)
+
+
+;; Memories
+
+(module (memory 0) (export "a" (memory 0)))
+(module (memory 0) (export "a" (memory 0)) (export "b" (memory 0)))
+;; No multiple memories yet.
+;; (module (memory 0) (memory 0) (export "a" (memory 0)) (export "b" (memory 1)))
+
+(module (memory (export "a") 0))
+(module (memory (export "a") 0 1))
+(module (memory 0) (export "a" (memory 0)))
+(module (memory 0 1) (export "a" (memory 0)))
+(module (memory $a (export "a") 0))
+(module (memory $a (export "a") 0 1))
+(module (memory $a 0) (export "a" (memory $a)))
+(module (memory $a 0 1) (export "a" (memory $a)))
+(module (export "a" (memory 0)) (memory 0))
+(module (export "a" (memory 0)) (memory 0 1))
+(module (export "a" (memory $a)) (memory $a 0))
+(module (export "a" (memory $a)) (memory $a 0 1))
+
+(; TODO: access memory ;)
+
+(assert_invalid
+  (module (memory 0) (export "a" (memory 1)))
+  "unknown memory"
+)
+(assert_invalid
+  (module (memory 0) (export "a" (memory 0)) (export "a" (memory 0)))
+  "duplicate export name"
+)
+;; No multiple memories yet.
+;; (assert_invalid
+;;   (module (memory 0) (memory 0) (export "a" (memory 0)) (export "a" (memory 1)))
+;;   "duplicate export name"
+;; )
+(assert_invalid
+  (module (memory 0) (func) (export "a" (memory 0)) (export "a" (func 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (memory 0) (global i32 (i32.const 0)) (export "a" (memory 0)) (export "a" (global 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (memory 0) (table 0 funcref) (export "a" (memory 0)) (export "a" (table 0)))
+  "duplicate export name"
+)
diff --git a/binaryen/test/spec/f32.load32.fail.wast b/binaryen/test/spec/f32.load32.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/f32.load32.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (result f32) (f32.load32 (local.get 0))))
diff --git a/binaryen/test/spec/f32.load64.fail.wast b/binaryen/test/spec/f32.load64.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/f32.load64.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (result f32) (f32.load64 (local.get 0))))
diff --git a/binaryen/test/spec/f32.store32.fail.wast b/binaryen/test/spec/f32.store32.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/f32.store32.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (param f32) (f32.store32 (local.get 0) (local.get 1))))
diff --git a/binaryen/test/spec/f32.store64.fail.wast b/binaryen/test/spec/f32.store64.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/f32.store64.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (param f64) (f32.store64 (local.get 0) (local.get 1))))
diff --git a/binaryen/test/spec/f32.wast b/binaryen/test/spec/f32.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/f32.wast
@@ -0,0 +1,2533 @@
+;; Test all the f32 operators on major boundary values and all special
+;; values (except comparison and bitwise operators, which are tested in
+;; f32_bitwise.wast and f32_cmp.wast).
+
+(module
+  (func (export "add") (param $x f32) (param $y f32) (result f32) (f32.add (local.get $x) (local.get $y)))
+  (func (export "sub") (param $x f32) (param $y f32) (result f32) (f32.sub (local.get $x) (local.get $y)))
+  (func (export "mul") (param $x f32) (param $y f32) (result f32) (f32.mul (local.get $x) (local.get $y)))
+  (func (export "div") (param $x f32) (param $y f32) (result f32) (f32.div (local.get $x) (local.get $y)))
+  (func (export "sqrt") (param $x f32) (result f32) (f32.sqrt (local.get $x)))
+  (func (export "min") (param $x f32) (param $y f32) (result f32) (f32.min (local.get $x) (local.get $y)))
+  (func (export "max") (param $x f32) (param $y f32) (result f32) (f32.max (local.get $x) (local.get $y)))
+  (func (export "ceil") (param $x f32) (result f32) (f32.ceil (local.get $x)))
+  (func (export "floor") (param $x f32) (result f32) (f32.floor (local.get $x)))
+  (func (export "trunc") (param $x f32) (result f32) (f32.trunc (local.get $x)))
+  (func (export "nearest") (param $x f32) (result f32) (f32.nearest (local.get $x)))
+)
+
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const -0x0p+0) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const 0x0p+0) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "add" (f32.const -0x0p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -0x0p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const -0x0p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -0x0p+0) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const 0x0p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const 0x0p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const 0x0p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const 0x0p+0) (f32.const nan:0x200000)))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -0x0p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const 0x0p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -0x0p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const 0x0p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -0x1p-149)) (f32.const -0x1p-148))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const 0x1p-149)) (f32.const 0x1p-148))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -0x1p-126)) (f32.const -0x1.000002p-126))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const 0x1p-126)) (f32.const 0x1.fffffcp-127))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -0x1p-126)) (f32.const -0x1.fffffcp-127))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const 0x1p-126)) (f32.const 0x1.000002p-126))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const -0x1p-149) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const 0x1p-149) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "add" (f32.const -0x1p-149) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -0x1p-149) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const -0x1p-149) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -0x1p-149) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const 0x1p-149) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const 0x1p-149) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const 0x1p-149) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const 0x1p-149) (f32.const nan:0x200000)))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -0x0p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const 0x0p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -0x0p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const 0x0p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -0x1p-149)) (f32.const -0x1.000002p-126))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const 0x1p-149)) (f32.const -0x1.fffffcp-127))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -0x1p-149)) (f32.const 0x1.fffffcp-127))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const 0x1p-149)) (f32.const 0x1.000002p-126))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -0x1p-126)) (f32.const -0x1p-125))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const 0x1p-126)) (f32.const 0x1p-125))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const -0x1p-126) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const 0x1p-126) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "add" (f32.const -0x1p-126) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -0x1p-126) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const -0x1p-126) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -0x1p-126) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const 0x1p-126) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const 0x1p-126) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const 0x1p-126) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const 0x1p-126) (f32.const nan:0x200000)))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -0x0p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const 0x0p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -0x0p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const 0x0p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -0x1p-149)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const 0x1p-149)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -0x1p-149)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const 0x1p-149)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -0x1p-126)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const 0x1p-126)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -0x1p-126)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const 0x1p-126)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -0x1p-1)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const 0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const 0x1p-1)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -0x1p+0)) (f32.const -0x1.8p+0))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const 0x1p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -0x1p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const 0x1p+0)) (f32.const 0x1.8p+0))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.b21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.721fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.721fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.b21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const -0x1p-1) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const 0x1p-1) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "add" (f32.const -0x1p-1) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -0x1p-1) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const -0x1p-1) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -0x1p-1) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const 0x1p-1) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const 0x1p-1) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const 0x1p-1) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const 0x1p-1) (f32.const nan:0x200000)))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -0x0p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const 0x0p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -0x0p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const 0x0p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -0x1p-149)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const 0x1p-149)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -0x1p-149)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const 0x1p-149)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -0x1p-126)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const 0x1p-126)) (f32.const -0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -0x1p-126)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const 0x1p-126)) (f32.const 0x1p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -0x1p-1)) (f32.const -0x1.8p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const 0x1p-1)) (f32.const 0x1.8p+0))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -0x1p+0)) (f32.const -0x1p+1))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const 0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const 0x1p+0)) (f32.const 0x1p+1))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.d21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.521fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.521fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.d21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const -0x1p+0) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const 0x1p+0) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "add" (f32.const -0x1p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -0x1p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const -0x1p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -0x1p+0) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const 0x1p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const 0x1p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const 0x1p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const 0x1p+0) (f32.const nan:0x200000)))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const -0x1.b21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const -0x1.721fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const 0x1.721fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const 0x1.b21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const -0x1.d21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const -0x1.521fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const 0x1.521fb6p+2))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const 0x1.d21fb6p+2))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+3))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+3))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -0x1.921fb6p+2) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const 0x1.921fb6p+2) (f32.const nan:0x200000)))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const -0x1.fffffep+127) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const 0x1.fffffep+127) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -0x1.fffffep+127) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const -0x1.fffffep+127) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -0x1.fffffep+127) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const 0x1.fffffep+127) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const 0x1.fffffep+127) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const 0x1.fffffep+127) (f32.const nan:0x200000)))
+(assert_return (invoke "add" (f32.const -inf) (f32.const -0x0p+0)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const -inf) (f32.const 0x0p+0)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const inf) (f32.const -0x0p+0)) (f32.const inf))
+(assert_return (invoke "add" (f32.const inf) (f32.const 0x0p+0)) (f32.const inf))
+(assert_return (invoke "add" (f32.const -inf) (f32.const -0x1p-149)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const -inf) (f32.const 0x1p-149)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const inf) (f32.const -0x1p-149)) (f32.const inf))
+(assert_return (invoke "add" (f32.const inf) (f32.const 0x1p-149)) (f32.const inf))
+(assert_return (invoke "add" (f32.const -inf) (f32.const -0x1p-126)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const -inf) (f32.const 0x1p-126)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const inf) (f32.const -0x1p-126)) (f32.const inf))
+(assert_return (invoke "add" (f32.const inf) (f32.const 0x1p-126)) (f32.const inf))
+(assert_return (invoke "add" (f32.const -inf) (f32.const -0x1p-1)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const -inf) (f32.const 0x1p-1)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const inf) (f32.const -0x1p-1)) (f32.const inf))
+(assert_return (invoke "add" (f32.const inf) (f32.const 0x1p-1)) (f32.const inf))
+(assert_return (invoke "add" (f32.const -inf) (f32.const -0x1p+0)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const -inf) (f32.const 0x1p+0)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const inf) (f32.const -0x1p+0)) (f32.const inf))
+(assert_return (invoke "add" (f32.const inf) (f32.const 0x1p+0)) (f32.const inf))
+(assert_return (invoke "add" (f32.const -inf) (f32.const -0x1.921fb6p+2)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const -inf) (f32.const 0x1.921fb6p+2)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const inf) (f32.const -0x1.921fb6p+2)) (f32.const inf))
+(assert_return (invoke "add" (f32.const inf) (f32.const 0x1.921fb6p+2)) (f32.const inf))
+(assert_return (invoke "add" (f32.const -inf) (f32.const -0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const -inf) (f32.const 0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "add" (f32.const inf) (f32.const -0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "add" (f32.const inf) (f32.const 0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "add" (f32.const -inf) (f32.const -inf)) (f32.const -inf))
+(assert_return_canonical_nan (invoke "add" (f32.const -inf) (f32.const inf)))
+(assert_return_canonical_nan (invoke "add" (f32.const inf) (f32.const -inf)))
+(assert_return (invoke "add" (f32.const inf) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "add" (f32.const -inf) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -inf) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const -inf) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -inf) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const inf) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const inf) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const inf) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const inf) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const -0x1p-149)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const -0x1p-149)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const 0x1p-149)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const 0x1p-149)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const -0x1p-149)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const -0x1p-149)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const 0x1p-149)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const 0x1p-149)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const -0x1p-126)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const -0x1p-126)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const 0x1p-126)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const 0x1p-126)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const -0x1p-126)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const -0x1p-126)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const 0x1p-126)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const 0x1p-126)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const -0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const -0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const 0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const 0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const -0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const -0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const 0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const 0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const -0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const -0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const 0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const 0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const -0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const -0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const 0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const 0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const -inf)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const inf)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const inf)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const -inf)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const inf)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const inf)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan) (f32.const -nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan) (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const -nan:0x200000) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan) (f32.const -nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "add" (f32.const nan) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan) (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "add" (f32.const nan:0x200000) (f32.const nan:0x200000)))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const 0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const 0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const 0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const 0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const -0x0p+0) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const 0x0p+0) (f32.const inf)) (f32.const -inf))
+(assert_return_canonical_nan (invoke "sub" (f32.const -0x0p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -0x0p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -0x0p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -0x0p+0) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const 0x0p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const 0x0p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const 0x0p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const 0x0p+0) (f32.const nan:0x200000)))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -0x0p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const 0x0p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -0x0p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const 0x0p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const 0x1p-149)) (f32.const -0x1p-148))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -0x1p-149)) (f32.const 0x1p-148))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -0x1p-126)) (f32.const 0x1.fffffcp-127))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const 0x1p-126)) (f32.const -0x1.000002p-126))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -0x1p-126)) (f32.const 0x1.000002p-126))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const 0x1p-126)) (f32.const -0x1.fffffcp-127))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const -0x1p-149) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const 0x1p-149) (f32.const inf)) (f32.const -inf))
+(assert_return_canonical_nan (invoke "sub" (f32.const -0x1p-149) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -0x1p-149) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -0x1p-149) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -0x1p-149) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const 0x1p-149) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const 0x1p-149) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const 0x1p-149) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const 0x1p-149) (f32.const nan:0x200000)))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -0x0p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const 0x0p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -0x0p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const 0x0p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -0x1p-149)) (f32.const -0x1.fffffcp-127))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const 0x1p-149)) (f32.const -0x1.000002p-126))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -0x1p-149)) (f32.const 0x1.000002p-126))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const 0x1p-149)) (f32.const 0x1.fffffcp-127))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const 0x1p-126)) (f32.const -0x1p-125))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -0x1p-126)) (f32.const 0x1p-125))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const -0x1p-126) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const 0x1p-126) (f32.const inf)) (f32.const -inf))
+(assert_return_canonical_nan (invoke "sub" (f32.const -0x1p-126) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -0x1p-126) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -0x1p-126) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -0x1p-126) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const 0x1p-126) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const 0x1p-126) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const 0x1p-126) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const 0x1p-126) (f32.const nan:0x200000)))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -0x0p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const 0x0p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -0x0p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const 0x0p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -0x1p-149)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const 0x1p-149)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -0x1p-149)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const 0x1p-149)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -0x1p-126)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const 0x1p-126)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -0x1p-126)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const 0x1p-126)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const 0x1p-1)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -0x1p-1)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const 0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -0x1p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const 0x1p+0)) (f32.const -0x1.8p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -0x1p+0)) (f32.const 0x1.8p+0))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const 0x1p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.721fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.b21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.b21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.721fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const -0x1p-1) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const 0x1p-1) (f32.const inf)) (f32.const -inf))
+(assert_return_canonical_nan (invoke "sub" (f32.const -0x1p-1) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -0x1p-1) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -0x1p-1) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -0x1p-1) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const 0x1p-1) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const 0x1p-1) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const 0x1p-1) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const 0x1p-1) (f32.const nan:0x200000)))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -0x0p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const 0x0p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -0x0p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const 0x0p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -0x1p-149)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const 0x1p-149)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -0x1p-149)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const 0x1p-149)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -0x1p-126)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const 0x1p-126)) (f32.const -0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -0x1p-126)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const 0x1p-126)) (f32.const 0x1p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const 0x1p-1)) (f32.const -0x1.8p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -0x1p-1)) (f32.const 0x1.8p+0))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const 0x1p+0)) (f32.const -0x1p+1))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -0x1p+0)) (f32.const 0x1p+1))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const 0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.521fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.d21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.d21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.521fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const -0x1p+0) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const 0x1p+0) (f32.const inf)) (f32.const -inf))
+(assert_return_canonical_nan (invoke "sub" (f32.const -0x1p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -0x1p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -0x1p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -0x1p+0) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const 0x1p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const 0x1p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const 0x1p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const 0x1p+0) (f32.const nan:0x200000)))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const -0x1.721fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const -0x1.b21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const 0x1.b21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const 0x1.721fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const -0x1.521fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const -0x1.d21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const 0x1.d21fb6p+2))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const 0x1.521fb6p+2))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+3))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+3))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const inf)) (f32.const -inf))
+(assert_return_canonical_nan (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -0x1.921fb6p+2) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const 0x1.921fb6p+2) (f32.const nan:0x200000)))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const inf)) (f32.const -inf))
+(assert_return_canonical_nan (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -0x1.fffffep+127) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const 0x1.fffffep+127) (f32.const nan:0x200000)))
+(assert_return (invoke "sub" (f32.const -inf) (f32.const -0x0p+0)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const -inf) (f32.const 0x0p+0)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const inf) (f32.const -0x0p+0)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const inf) (f32.const 0x0p+0)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const -inf) (f32.const -0x1p-149)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const -inf) (f32.const 0x1p-149)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const inf) (f32.const -0x1p-149)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const inf) (f32.const 0x1p-149)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const -inf) (f32.const -0x1p-126)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const -inf) (f32.const 0x1p-126)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const inf) (f32.const -0x1p-126)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const inf) (f32.const 0x1p-126)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const -inf) (f32.const -0x1p-1)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const -inf) (f32.const 0x1p-1)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const inf) (f32.const -0x1p-1)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const inf) (f32.const 0x1p-1)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const -inf) (f32.const -0x1p+0)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const -inf) (f32.const 0x1p+0)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const inf) (f32.const -0x1p+0)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const inf) (f32.const 0x1p+0)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const -inf) (f32.const -0x1.921fb6p+2)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const -inf) (f32.const 0x1.921fb6p+2)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const inf) (f32.const -0x1.921fb6p+2)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const inf) (f32.const 0x1.921fb6p+2)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const -inf) (f32.const -0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const -inf) (f32.const 0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const inf) (f32.const -0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "sub" (f32.const inf) (f32.const 0x1.fffffep+127)) (f32.const inf))
+(assert_return_canonical_nan (invoke "sub" (f32.const -inf) (f32.const -inf)))
+(assert_return (invoke "sub" (f32.const -inf) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "sub" (f32.const inf) (f32.const -inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "sub" (f32.const inf) (f32.const inf)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -inf) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -inf) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -inf) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -inf) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const inf) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const inf) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const inf) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const inf) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const -0x1p-149)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const -0x1p-149)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const 0x1p-149)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const 0x1p-149)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const -0x1p-149)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const -0x1p-149)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const 0x1p-149)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const 0x1p-149)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const -0x1p-126)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const -0x1p-126)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const 0x1p-126)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const 0x1p-126)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const -0x1p-126)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const -0x1p-126)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const 0x1p-126)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const 0x1p-126)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const -0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const -0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const 0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const 0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const -0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const -0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const 0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const 0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const -0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const -0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const 0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const 0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const -0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const -0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const 0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const 0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const -inf)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const inf)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const inf)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const -inf)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const inf)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const inf)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan) (f32.const -nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const -nan) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan) (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const -nan:0x200000) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan) (f32.const -nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sub" (f32.const nan) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan) (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "sub" (f32.const nan:0x200000) (f32.const nan:0x200000)))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const -0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const 0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const -0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const -0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const 0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const -0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const -0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const 0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const -0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const 0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const -0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const 0x1p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const -0x1p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const 0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x0p+0) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x0p+0) (f32.const inf)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x0p+0) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x0p+0) (f32.const inf)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x0p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -0x0p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x0p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -0x0p+0) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x0p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const 0x0p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x0p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const 0x0p+0) (f32.const nan:0x200000)))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const 0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const 0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const 0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const 0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -0x1p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const 0x1p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -0x1p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const 0x1p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.8p-147))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.8p-147))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.8p-147))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.8p-147))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -0x1p-149) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1p-149) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x1p-149) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -0x1p-149) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x1p-149) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -0x1p-149) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x1p-149) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const 0x1p-149) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x1p-149) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const 0x1p-149) (f32.const nan:0x200000)))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const 0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const 0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -0x1p-1)) (f32.const 0x1p-127))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const 0x1p-1)) (f32.const -0x1p-127))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -0x1p-1)) (f32.const -0x1p-127))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const 0x1p-1)) (f32.const 0x1p-127))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -0x1p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const 0x1p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -0x1p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const 0x1p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -0x1p-126) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1p-126) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x1p-126) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -0x1p-126) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x1p-126) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -0x1p-126) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x1p-126) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const 0x1p-126) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x1p-126) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const 0x1p-126) (f32.const nan:0x200000)))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const 0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -0x1p-126)) (f32.const 0x1p-127))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const 0x1p-126)) (f32.const -0x1p-127))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -0x1p-126)) (f32.const -0x1p-127))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const 0x1p-126)) (f32.const 0x1p-127))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -0x1p-1)) (f32.const 0x1p-2))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const 0x1p-1)) (f32.const -0x1p-2))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -0x1p-1)) (f32.const -0x1p-2))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const 0x1p-1)) (f32.const 0x1p-2))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -0x1p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const 0x1p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -0x1p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const 0x1p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -0x1p-1) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1p-1) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x1p-1) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -0x1p-1) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x1p-1) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -0x1p-1) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x1p-1) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const 0x1p-1) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x1p-1) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const 0x1p-1) (f32.const nan:0x200000)))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const 0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const 0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -0x1p+0) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1p+0) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x1p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -0x1p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x1p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -0x1p+0) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x1p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const 0x1p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x1p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const 0x1p+0) (f32.const nan:0x200000)))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const 0x1.8p-147))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const -0x1.8p-147))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const -0x1.8p-147))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const 0x1.8p-147))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const 0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const -0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const -0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const 0x1.921fb6p-124))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const 0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const -0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const -0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const 0x1.921fb6p+1))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.3bd3cep+5))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.3bd3cep+5))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.3bd3cep+5))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.3bd3cep+5))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -0x1.921fb6p+2) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const 0x1.921fb6p+2) (f32.const nan:0x200000)))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const 0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const -0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const -0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const 0x1.fffffep-22))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const 0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const -0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const -0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const 0x1.fffffep+1))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const 0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const -0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const -0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const 0x1.fffffep+126))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -0x1.fffffep+127) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const 0x1.fffffep+127) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -inf) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -inf) (f32.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "mul" (f32.const inf) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "mul" (f32.const inf) (f32.const 0x0p+0)))
+(assert_return (invoke "mul" (f32.const -inf) (f32.const -0x1p-149)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -inf) (f32.const 0x1p-149)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const inf) (f32.const -0x1p-149)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const inf) (f32.const 0x1p-149)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -inf) (f32.const -0x1p-126)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -inf) (f32.const 0x1p-126)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const inf) (f32.const -0x1p-126)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const inf) (f32.const 0x1p-126)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -inf) (f32.const -0x1p-1)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -inf) (f32.const 0x1p-1)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const inf) (f32.const -0x1p-1)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const inf) (f32.const 0x1p-1)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -inf) (f32.const -0x1p+0)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -inf) (f32.const 0x1p+0)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const inf) (f32.const -0x1p+0)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const inf) (f32.const 0x1p+0)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -inf) (f32.const -0x1.921fb6p+2)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -inf) (f32.const 0x1.921fb6p+2)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const inf) (f32.const -0x1.921fb6p+2)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const inf) (f32.const 0x1.921fb6p+2)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -inf) (f32.const -0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -inf) (f32.const 0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const inf) (f32.const -0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const inf) (f32.const 0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -inf) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "mul" (f32.const -inf) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const inf) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "mul" (f32.const inf) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "mul" (f32.const -inf) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -inf) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -inf) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -inf) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const inf) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const inf) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const inf) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const inf) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const -0x1p-149)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const -0x1p-149)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const 0x1p-149)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const 0x1p-149)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const -0x1p-149)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const -0x1p-149)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const 0x1p-149)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const 0x1p-149)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const -0x1p-126)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const -0x1p-126)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const 0x1p-126)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const 0x1p-126)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const -0x1p-126)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const -0x1p-126)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const 0x1p-126)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const 0x1p-126)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const -0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const -0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const 0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const 0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const -0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const -0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const 0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const 0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const -0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const -0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const 0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const 0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const -0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const -0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const 0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const 0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const -inf)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const inf)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const inf)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const -inf)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const inf)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const inf)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan) (f32.const -nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const -nan) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan) (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const -nan:0x200000) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan) (f32.const -nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "mul" (f32.const nan) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan) (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "mul" (f32.const nan:0x200000) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x0p+0) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x0p+0) (f32.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x0p+0) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x0p+0) (f32.const 0x0p+0)))
+(assert_return (invoke "div" (f32.const -0x0p+0) (f32.const -0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x0p+0) (f32.const 0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x0p+0) (f32.const -0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x0p+0) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x0p+0) (f32.const -0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x0p+0) (f32.const 0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x0p+0) (f32.const -0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x0p+0) (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x0p+0) (f32.const -0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x0p+0) (f32.const 0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x0p+0) (f32.const -0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x0p+0) (f32.const 0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x0p+0) (f32.const -0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x0p+0) (f32.const 0x1p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x0p+0) (f32.const -0x1p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x0p+0) (f32.const 0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x0p+0) (f32.const -inf)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x0p+0) (f32.const inf)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x0p+0) (f32.const -inf)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x0p+0) (f32.const inf)) (f32.const 0x0p+0))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x0p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -0x0p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x0p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -0x0p+0) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x0p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const 0x0p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x0p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const 0x0p+0) (f32.const nan:0x200000)))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const -0x0p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const 0x0p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const -0x0p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const 0x0p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const -0x1p-149)) (f32.const 0x1p+0))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const 0x1p-149)) (f32.const -0x1p+0))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const -0x1p-149)) (f32.const -0x1p+0))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const 0x1p-149)) (f32.const 0x1p+0))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const -0x1p-126)) (f32.const 0x1p-23))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const 0x1p-126)) (f32.const -0x1p-23))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const -0x1p-126)) (f32.const -0x1p-23))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const 0x1p-126)) (f32.const 0x1p-23))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const -0x1p-1)) (f32.const 0x1p-148))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const 0x1p-1)) (f32.const -0x1p-148))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const -0x1p-1)) (f32.const -0x1p-148))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const 0x1p-1)) (f32.const 0x1p-148))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const -0x1p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const 0x1p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const -0x1p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const 0x1p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const -inf)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x1p-149) (f32.const inf)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const -inf)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1p-149) (f32.const inf)) (f32.const 0x0p+0))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x1p-149) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -0x1p-149) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x1p-149) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -0x1p-149) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x1p-149) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const 0x1p-149) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x1p-149) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const 0x1p-149) (f32.const nan:0x200000)))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const -0x0p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const 0x0p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const -0x0p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const 0x0p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const -0x1p-149)) (f32.const 0x1p+23))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const 0x1p-149)) (f32.const -0x1p+23))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const -0x1p-149)) (f32.const -0x1p+23))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const 0x1p-149)) (f32.const 0x1p+23))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const -0x1p-126)) (f32.const 0x1p+0))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const 0x1p-126)) (f32.const -0x1p+0))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const -0x1p-126)) (f32.const -0x1p+0))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const 0x1p-126)) (f32.const 0x1p+0))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const -0x1p-1)) (f32.const 0x1p-125))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const 0x1p-1)) (f32.const -0x1p-125))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const -0x1p-1)) (f32.const -0x1p-125))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const 0x1p-1)) (f32.const 0x1p-125))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const -0x1p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const 0x1p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const -0x1p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const 0x1p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.45f3p-129))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.45f3p-129))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.45f3p-129))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.45f3p-129))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const -inf)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x1p-126) (f32.const inf)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const -inf)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1p-126) (f32.const inf)) (f32.const 0x0p+0))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x1p-126) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -0x1p-126) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x1p-126) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -0x1p-126) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x1p-126) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const 0x1p-126) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x1p-126) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const 0x1p-126) (f32.const nan:0x200000)))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const -0x0p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const 0x0p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const -0x0p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const 0x0p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const -0x1p-149)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const 0x1p-149)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const -0x1p-149)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const 0x1p-149)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const -0x1p-126)) (f32.const 0x1p+125))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const 0x1p-126)) (f32.const -0x1p+125))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const -0x1p-126)) (f32.const -0x1p+125))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const 0x1p-126)) (f32.const 0x1p+125))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const -0x1p-1)) (f32.const 0x1p+0))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const 0x1p-1)) (f32.const -0x1p+0))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const -0x1p-1)) (f32.const -0x1p+0))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const 0x1p-1)) (f32.const 0x1p+0))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const -0x1p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const 0x1p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const -0x1p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const 0x1p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.45f306p-4))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.45f306p-4))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.45f306p-4))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.45f306p-4))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const 0x1p-129))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const -0x1p-129))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const -0x1p-129))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const 0x1p-129))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const -inf)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x1p-1) (f32.const inf)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const -inf)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1p-1) (f32.const inf)) (f32.const 0x0p+0))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x1p-1) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -0x1p-1) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x1p-1) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -0x1p-1) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x1p-1) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const 0x1p-1) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x1p-1) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const 0x1p-1) (f32.const nan:0x200000)))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const -0x0p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const 0x0p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const -0x0p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const 0x0p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const -0x1p-149)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const 0x1p-149)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const -0x1p-149)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const 0x1p-149)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const -0x1p-126)) (f32.const 0x1p+126))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const 0x1p-126)) (f32.const -0x1p+126))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const -0x1p-126)) (f32.const -0x1p+126))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const 0x1p-126)) (f32.const 0x1p+126))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const -0x1p-1)) (f32.const 0x1p+1))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const 0x1p-1)) (f32.const -0x1p+1))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const -0x1p-1)) (f32.const -0x1p+1))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const 0x1p-1)) (f32.const 0x1p+1))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.45f306p-3))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.45f306p-3))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.45f306p-3))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.45f306p-3))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x1p-128))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x1p-128))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1p-128))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1p-128))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const -inf)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x1p+0) (f32.const inf)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const -inf)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1p+0) (f32.const inf)) (f32.const 0x0p+0))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x1p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -0x1p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x1p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -0x1p+0) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x1p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const 0x1p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x1p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const 0x1p+0) (f32.const nan:0x200000)))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const 0x1.921fb6p+3))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const -0x1.921fb6p+3))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const -0x1.921fb6p+3))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const 0x1.921fb6p+3))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const 0x1p+0))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const -0x1p+0))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const -0x1p+0))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const 0x1p+0))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const 0x1.921fb8p-126))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const -0x1.921fb8p-126))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const -0x1.921fb8p-126))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const 0x1.921fb8p-126))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const -inf)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const inf)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const -inf)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const inf)) (f32.const 0x0p+0))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -0x1.921fb6p+2) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const 0x1.921fb6p+2) (f32.const nan:0x200000)))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.45f304p+125))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.45f304p+125))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.45f304p+125))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.45f304p+125))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const 0x1p+0))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const -0x1p+0))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const -0x1p+0))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const 0x1p+0))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const -inf)) (f32.const 0x0p+0))
+(assert_return (invoke "div" (f32.const -0x1.fffffep+127) (f32.const inf)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const -inf)) (f32.const -0x0p+0))
+(assert_return (invoke "div" (f32.const 0x1.fffffep+127) (f32.const inf)) (f32.const 0x0p+0))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x1.fffffep+127) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -0x1.fffffep+127) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const -0x1.fffffep+127) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -0x1.fffffep+127) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x1.fffffep+127) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const 0x1.fffffep+127) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const 0x1.fffffep+127) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const 0x1.fffffep+127) (f32.const nan:0x200000)))
+(assert_return (invoke "div" (f32.const -inf) (f32.const -0x0p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -inf) (f32.const 0x0p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const inf) (f32.const -0x0p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const inf) (f32.const 0x0p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -inf) (f32.const -0x1p-149)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -inf) (f32.const 0x1p-149)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const inf) (f32.const -0x1p-149)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const inf) (f32.const 0x1p-149)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -inf) (f32.const -0x1p-126)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -inf) (f32.const 0x1p-126)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const inf) (f32.const -0x1p-126)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const inf) (f32.const 0x1p-126)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -inf) (f32.const -0x1p-1)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -inf) (f32.const 0x1p-1)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const inf) (f32.const -0x1p-1)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const inf) (f32.const 0x1p-1)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -inf) (f32.const -0x1p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -inf) (f32.const 0x1p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const inf) (f32.const -0x1p+0)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const inf) (f32.const 0x1p+0)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -inf) (f32.const -0x1.921fb6p+2)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -inf) (f32.const 0x1.921fb6p+2)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const inf) (f32.const -0x1.921fb6p+2)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const inf) (f32.const 0x1.921fb6p+2)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -inf) (f32.const -0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "div" (f32.const -inf) (f32.const 0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const inf) (f32.const -0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "div" (f32.const inf) (f32.const 0x1.fffffep+127)) (f32.const inf))
+(assert_return_canonical_nan (invoke "div" (f32.const -inf) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "div" (f32.const -inf) (f32.const inf)))
+(assert_return_canonical_nan (invoke "div" (f32.const inf) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "div" (f32.const inf) (f32.const inf)))
+(assert_return_canonical_nan (invoke "div" (f32.const -inf) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -inf) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const -inf) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -inf) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const inf) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const inf) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const inf) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const inf) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const -0x1p-149)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const -0x1p-149)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const 0x1p-149)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const 0x1p-149)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const -0x1p-149)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const -0x1p-149)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const 0x1p-149)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const 0x1p-149)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const -0x1p-126)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const -0x1p-126)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const 0x1p-126)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const 0x1p-126)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const -0x1p-126)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const -0x1p-126)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const 0x1p-126)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const 0x1p-126)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const -0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const -0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const 0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const 0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const -0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const -0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const 0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const 0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const -0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const -0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const 0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const 0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const -0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const -0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const 0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const 0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const -inf)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const inf)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const inf)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const -inf)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const inf)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const inf)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan) (f32.const -nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const -nan) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan) (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const -nan:0x200000) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan) (f32.const -nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "div" (f32.const nan) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan) (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "div" (f32.const nan:0x200000) (f32.const nan:0x200000)))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const 0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const 0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const 0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const 0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const 0x1p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const 0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const -0x0p+0) (f32.const inf)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const 0x0p+0) (f32.const inf)) (f32.const 0x0p+0))
+(assert_return_canonical_nan (invoke "min" (f32.const -0x0p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -0x0p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const -0x0p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -0x0p+0) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const 0x0p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const 0x0p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const 0x0p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const 0x0p+0) (f32.const nan:0x200000)))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const -0x0p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const 0x0p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const 0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const 0x1p-126)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const 0x1p-126)) (f32.const 0x1p-149))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const 0x1p-1)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const 0x1p-1)) (f32.const 0x1p-149))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const 0x1p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const 0x1p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const 0x1p-149))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const 0x1p-149))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const -0x1p-149) (f32.const inf)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const 0x1p-149) (f32.const inf)) (f32.const 0x1p-149))
+(assert_return_canonical_nan (invoke "min" (f32.const -0x1p-149) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -0x1p-149) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const -0x1p-149) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -0x1p-149) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const 0x1p-149) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const 0x1p-149) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const 0x1p-149) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const 0x1p-149) (f32.const nan:0x200000)))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const -0x0p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const 0x0p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const -0x1p-149)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const 0x1p-149)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const 0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const 0x1p-1)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const 0x1p-1)) (f32.const 0x1p-126))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const 0x1p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const 0x1p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const 0x1p-126))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const 0x1p-126))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const -0x1p-126) (f32.const inf)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const 0x1p-126) (f32.const inf)) (f32.const 0x1p-126))
+(assert_return_canonical_nan (invoke "min" (f32.const -0x1p-126) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -0x1p-126) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const -0x1p-126) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -0x1p-126) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const 0x1p-126) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const 0x1p-126) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const 0x1p-126) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const 0x1p-126) (f32.const nan:0x200000)))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const -0x0p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const 0x0p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const -0x1p-149)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const 0x1p-149)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const -0x1p-126)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const 0x1p-126)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const 0x1p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const 0x1p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const 0x1p-1))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const 0x1p-1))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const -0x1p-1) (f32.const inf)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const 0x1p-1) (f32.const inf)) (f32.const 0x1p-1))
+(assert_return_canonical_nan (invoke "min" (f32.const -0x1p-1) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -0x1p-1) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const -0x1p-1) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -0x1p-1) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const 0x1p-1) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const 0x1p-1) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const 0x1p-1) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const 0x1p-1) (f32.const nan:0x200000)))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const -0x0p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const 0x0p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const -0x1p-149)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const 0x1p-149)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const -0x1p-126)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const 0x1p-126)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const -0x1p-1)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const 0x1p-1)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1p+0))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1p+0))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const -0x1p+0) (f32.const inf)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const 0x1p+0) (f32.const inf)) (f32.const 0x1p+0))
+(assert_return_canonical_nan (invoke "min" (f32.const -0x1p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -0x1p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const -0x1p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -0x1p+0) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const 0x1p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const 0x1p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const 0x1p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const 0x1p+0) (f32.const nan:0x200000)))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const inf)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const inf)) (f32.const 0x1.921fb6p+2))
+(assert_return_canonical_nan (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -0x1.921fb6p+2) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const 0x1.921fb6p+2) (f32.const nan:0x200000)))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const -0x1.fffffep+127) (f32.const inf)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const 0x1.fffffep+127) (f32.const inf)) (f32.const 0x1.fffffep+127))
+(assert_return_canonical_nan (invoke "min" (f32.const -0x1.fffffep+127) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -0x1.fffffep+127) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const -0x1.fffffep+127) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -0x1.fffffep+127) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const 0x1.fffffep+127) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const 0x1.fffffep+127) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const 0x1.fffffep+127) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const 0x1.fffffep+127) (f32.const nan:0x200000)))
+(assert_return (invoke "min" (f32.const -inf) (f32.const -0x0p+0)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const -inf) (f32.const 0x0p+0)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const inf) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "min" (f32.const inf) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "min" (f32.const -inf) (f32.const -0x1p-149)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const -inf) (f32.const 0x1p-149)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const inf) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "min" (f32.const inf) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "min" (f32.const -inf) (f32.const -0x1p-126)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const -inf) (f32.const 0x1p-126)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const inf) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "min" (f32.const inf) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "min" (f32.const -inf) (f32.const -0x1p-1)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const -inf) (f32.const 0x1p-1)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const inf) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "min" (f32.const inf) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "min" (f32.const -inf) (f32.const -0x1p+0)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const -inf) (f32.const 0x1p+0)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const inf) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "min" (f32.const inf) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "min" (f32.const -inf) (f32.const -0x1.921fb6p+2)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const -inf) (f32.const 0x1.921fb6p+2)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const inf) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const inf) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "min" (f32.const -inf) (f32.const -0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const -inf) (f32.const 0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const inf) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const inf) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "min" (f32.const -inf) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const -inf) (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const inf) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "min" (f32.const inf) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "min" (f32.const -inf) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -inf) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const -inf) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -inf) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const inf) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const inf) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const inf) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const inf) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const -0x1p-149)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const -0x1p-149)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const 0x1p-149)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const 0x1p-149)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const -0x1p-149)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const -0x1p-149)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const 0x1p-149)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const 0x1p-149)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const -0x1p-126)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const -0x1p-126)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const 0x1p-126)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const 0x1p-126)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const -0x1p-126)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const -0x1p-126)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const 0x1p-126)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const 0x1p-126)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const -0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const -0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const 0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const 0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const -0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const -0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const 0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const 0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const -0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const -0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const 0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const 0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const -0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const -0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const 0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const 0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const -inf)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const inf)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const inf)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const -inf)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const inf)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const inf)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan) (f32.const -nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const -nan) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan) (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const -nan:0x200000) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan) (f32.const -nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "min" (f32.const nan) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan) (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "min" (f32.const nan:0x200000) (f32.const nan:0x200000)))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const -0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const -0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const -0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const -0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const -0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const -0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const -0x1p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const -0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x0p+0))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x0p+0))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const -inf)) (f32.const -0x0p+0))
+(assert_return (invoke "max" (f32.const -0x0p+0) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const -inf)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const 0x0p+0) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "max" (f32.const -0x0p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -0x0p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const -0x0p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -0x0p+0) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const 0x0p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const 0x0p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const 0x0p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const 0x0p+0) (f32.const nan:0x200000)))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const -0x0p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const 0x0p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const -0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const -0x1p-126)) (f32.const -0x1p-149))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const -0x1p-126)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const -0x1p-1)) (f32.const -0x1p-149))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const -0x1p-1)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const -0x1p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const -0x1p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const -0x1p-149))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const -0x1p-149))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const -inf)) (f32.const -0x1p-149))
+(assert_return (invoke "max" (f32.const -0x1p-149) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const -inf)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const 0x1p-149) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "max" (f32.const -0x1p-149) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -0x1p-149) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const -0x1p-149) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -0x1p-149) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const 0x1p-149) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const 0x1p-149) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const 0x1p-149) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const 0x1p-149) (f32.const nan:0x200000)))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const -0x0p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const 0x0p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const -0x1p-149)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const 0x1p-149)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const -0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const -0x1p-1)) (f32.const -0x1p-126))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const -0x1p-1)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const -0x1p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const -0x1p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const -0x1p-126))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const -0x1p-126))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const -inf)) (f32.const -0x1p-126))
+(assert_return (invoke "max" (f32.const -0x1p-126) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const -inf)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const 0x1p-126) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "max" (f32.const -0x1p-126) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -0x1p-126) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const -0x1p-126) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -0x1p-126) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const 0x1p-126) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const 0x1p-126) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const 0x1p-126) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const 0x1p-126) (f32.const nan:0x200000)))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const -0x0p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const 0x0p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const -0x1p-149)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const 0x1p-149)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const -0x1p-126)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const 0x1p-126)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const -0x1p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const -0x1p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const -0x1p-1))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const -0x1p-1))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const -inf)) (f32.const -0x1p-1))
+(assert_return (invoke "max" (f32.const -0x1p-1) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const -inf)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const 0x1p-1) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "max" (f32.const -0x1p-1) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -0x1p-1) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const -0x1p-1) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -0x1p-1) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const 0x1p-1) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const 0x1p-1) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const 0x1p-1) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const 0x1p-1) (f32.const nan:0x200000)))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const -0x0p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const 0x0p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const -0x1p-149)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const 0x1p-149)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const -0x1p-126)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const 0x1p-126)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const -0x1p-1)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const 0x1p-1)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1p+0))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1p+0))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const -inf)) (f32.const -0x1p+0))
+(assert_return (invoke "max" (f32.const -0x1p+0) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const -inf)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const 0x1p+0) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "max" (f32.const -0x1p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -0x1p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const -0x1p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -0x1p+0) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const 0x1p+0) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const 0x1p+0) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const 0x1p+0) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const 0x1p+0) (f32.const nan:0x200000)))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const -inf)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const -inf)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -0x1.921fb6p+2) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const 0x1.921fb6p+2) (f32.const nan:0x200000)))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const -inf)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -0x1.fffffep+127) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const -inf)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const 0x1.fffffep+127) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "max" (f32.const -0x1.fffffep+127) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -0x1.fffffep+127) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const -0x1.fffffep+127) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -0x1.fffffep+127) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const 0x1.fffffep+127) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const 0x1.fffffep+127) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const 0x1.fffffep+127) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const 0x1.fffffep+127) (f32.const nan:0x200000)))
+(assert_return (invoke "max" (f32.const -inf) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "max" (f32.const -inf) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "max" (f32.const inf) (f32.const -0x0p+0)) (f32.const inf))
+(assert_return (invoke "max" (f32.const inf) (f32.const 0x0p+0)) (f32.const inf))
+(assert_return (invoke "max" (f32.const -inf) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "max" (f32.const -inf) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "max" (f32.const inf) (f32.const -0x1p-149)) (f32.const inf))
+(assert_return (invoke "max" (f32.const inf) (f32.const 0x1p-149)) (f32.const inf))
+(assert_return (invoke "max" (f32.const -inf) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "max" (f32.const -inf) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "max" (f32.const inf) (f32.const -0x1p-126)) (f32.const inf))
+(assert_return (invoke "max" (f32.const inf) (f32.const 0x1p-126)) (f32.const inf))
+(assert_return (invoke "max" (f32.const -inf) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "max" (f32.const -inf) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "max" (f32.const inf) (f32.const -0x1p-1)) (f32.const inf))
+(assert_return (invoke "max" (f32.const inf) (f32.const 0x1p-1)) (f32.const inf))
+(assert_return (invoke "max" (f32.const -inf) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "max" (f32.const -inf) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "max" (f32.const inf) (f32.const -0x1p+0)) (f32.const inf))
+(assert_return (invoke "max" (f32.const inf) (f32.const 0x1p+0)) (f32.const inf))
+(assert_return (invoke "max" (f32.const -inf) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const -inf) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "max" (f32.const inf) (f32.const -0x1.921fb6p+2)) (f32.const inf))
+(assert_return (invoke "max" (f32.const inf) (f32.const 0x1.921fb6p+2)) (f32.const inf))
+(assert_return (invoke "max" (f32.const -inf) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const -inf) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "max" (f32.const inf) (f32.const -0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "max" (f32.const inf) (f32.const 0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "max" (f32.const -inf) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "max" (f32.const -inf) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "max" (f32.const inf) (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "max" (f32.const inf) (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "max" (f32.const -inf) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -inf) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const -inf) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -inf) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const inf) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const inf) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const inf) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const inf) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const -0x1p-149)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const -0x1p-149)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const 0x1p-149)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const 0x1p-149)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const -0x1p-149)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const -0x1p-149)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const 0x1p-149)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const 0x1p-149)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const -0x1p-126)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const -0x1p-126)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const 0x1p-126)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const 0x1p-126)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const -0x1p-126)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const -0x1p-126)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const 0x1p-126)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const 0x1p-126)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const -0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const -0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const 0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const 0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const -0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const -0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const 0x1.921fb6p+2)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const 0x1.921fb6p+2)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const -0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const -0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const 0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const 0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const -0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const -0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const 0x1.fffffep+127)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const 0x1.fffffep+127)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const -inf)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const inf)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const inf)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const -inf)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const -inf)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const inf)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const inf)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan) (f32.const -nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const -nan) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan) (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const -nan:0x200000) (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan) (f32.const -nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "max" (f32.const nan) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan) (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "max" (f32.const nan:0x200000) (f32.const nan:0x200000)))
+(assert_return (invoke "sqrt" (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "sqrt" (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return_canonical_nan (invoke "sqrt" (f32.const -0x1p-149)))
+(assert_return (invoke "sqrt" (f32.const 0x1p-149)) (f32.const 0x1.6a09e6p-75))
+(assert_return_canonical_nan (invoke "sqrt" (f32.const -0x1p-126)))
+(assert_return (invoke "sqrt" (f32.const 0x1p-126)) (f32.const 0x1p-63))
+(assert_return_canonical_nan (invoke "sqrt" (f32.const -0x1p-1)))
+(assert_return (invoke "sqrt" (f32.const 0x1p-1)) (f32.const 0x1.6a09e6p-1))
+(assert_return_canonical_nan (invoke "sqrt" (f32.const -0x1p+0)))
+(assert_return (invoke "sqrt" (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return_canonical_nan (invoke "sqrt" (f32.const -0x1.921fb6p+2)))
+(assert_return (invoke "sqrt" (f32.const 0x1.921fb6p+2)) (f32.const 0x1.40d932p+1))
+(assert_return_canonical_nan (invoke "sqrt" (f32.const -0x1.fffffep+127)))
+(assert_return (invoke "sqrt" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+63))
+(assert_return_canonical_nan (invoke "sqrt" (f32.const -inf)))
+(assert_return (invoke "sqrt" (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "sqrt" (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "sqrt" (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "sqrt" (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "sqrt" (f32.const nan:0x200000)))
+(assert_return (invoke "floor" (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "floor" (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "floor" (f32.const -0x1p-149)) (f32.const -0x1p+0))
+(assert_return (invoke "floor" (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "floor" (f32.const -0x1p-126)) (f32.const -0x1p+0))
+(assert_return (invoke "floor" (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "floor" (f32.const -0x1p-1)) (f32.const -0x1p+0))
+(assert_return (invoke "floor" (f32.const 0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "floor" (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "floor" (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "floor" (f32.const -0x1.921fb6p+2)) (f32.const -0x1.cp+2))
+(assert_return (invoke "floor" (f32.const 0x1.921fb6p+2)) (f32.const 0x1.8p+2))
+(assert_return (invoke "floor" (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "floor" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "floor" (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "floor" (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "floor" (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "floor" (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "floor" (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "floor" (f32.const nan:0x200000)))
+(assert_return (invoke "ceil" (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "ceil" (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "ceil" (f32.const -0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "ceil" (f32.const 0x1p-149)) (f32.const 0x1p+0))
+(assert_return (invoke "ceil" (f32.const -0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "ceil" (f32.const 0x1p-126)) (f32.const 0x1p+0))
+(assert_return (invoke "ceil" (f32.const -0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "ceil" (f32.const 0x1p-1)) (f32.const 0x1p+0))
+(assert_return (invoke "ceil" (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "ceil" (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "ceil" (f32.const -0x1.921fb6p+2)) (f32.const -0x1.8p+2))
+(assert_return (invoke "ceil" (f32.const 0x1.921fb6p+2)) (f32.const 0x1.cp+2))
+(assert_return (invoke "ceil" (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "ceil" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "ceil" (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "ceil" (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "ceil" (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "ceil" (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "ceil" (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "ceil" (f32.const nan:0x200000)))
+(assert_return (invoke "trunc" (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "trunc" (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "trunc" (f32.const -0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "trunc" (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "trunc" (f32.const -0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "trunc" (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "trunc" (f32.const -0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "trunc" (f32.const 0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "trunc" (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "trunc" (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "trunc" (f32.const -0x1.921fb6p+2)) (f32.const -0x1.8p+2))
+(assert_return (invoke "trunc" (f32.const 0x1.921fb6p+2)) (f32.const 0x1.8p+2))
+(assert_return (invoke "trunc" (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "trunc" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "trunc" (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "trunc" (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "trunc" (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "trunc" (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "trunc" (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "trunc" (f32.const nan:0x200000)))
+(assert_return (invoke "nearest" (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "nearest" (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "nearest" (f32.const -0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "nearest" (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "nearest" (f32.const -0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "nearest" (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "nearest" (f32.const -0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "nearest" (f32.const 0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "nearest" (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "nearest" (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "nearest" (f32.const -0x1.921fb6p+2)) (f32.const -0x1.8p+2))
+(assert_return (invoke "nearest" (f32.const 0x1.921fb6p+2)) (f32.const 0x1.8p+2))
+(assert_return (invoke "nearest" (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "nearest" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "nearest" (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "nearest" (f32.const inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "nearest" (f32.const -nan)))
+(assert_return_arithmetic_nan (invoke "nearest" (f32.const -nan:0x200000)))
+(assert_return_canonical_nan (invoke "nearest" (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "nearest" (f32.const nan:0x200000)))
+
+
+;; Type check
+
+(assert_invalid (module (func (result f32) (f32.add (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.div (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.max (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.min (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.mul (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.sub (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.ceil (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.floor (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.nearest (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.sqrt (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.trunc (i64.const 0)))) "type mismatch")
diff --git a/binaryen/test/spec/f32_bitwise.wast b/binaryen/test/spec/f32_bitwise.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/f32_bitwise.wast
@@ -0,0 +1,376 @@
+;; Test all the f32 bitwise operators on major boundary values and all special
+;; values.
+
+(module
+  (func (export "abs") (param $x f32) (result f32) (f32.abs (local.get $x)))
+  (func (export "neg") (param $x f32) (result f32) (f32.neg (local.get $x)))
+  (func (export "copysign") (param $x f32) (param $y f32) (result f32) (f32.copysign (local.get $x) (local.get $y)))
+)
+
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const -0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const -0x1p-149)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const 0x1p-149)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const -0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const -0x1p-126)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const 0x1p-126)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const -0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const 0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const -0x1p-1)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const 0x1p-1)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const -0x1p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const 0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const -0x1p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const 0x1p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const -inf)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const inf)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const -inf)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const inf)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const -nan)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x0p+0) (f32.const nan)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const -nan)) (f32.const -0x0p+0))
+(assert_return (invoke "copysign" (f32.const 0x0p+0) (f32.const nan)) (f32.const 0x0p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const -0x0p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const 0x0p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const -0x0p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const 0x0p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const -0x1p-126)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const 0x1p-126)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const -0x1p-126)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const 0x1p-126)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const -0x1p-1)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const 0x1p-1)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const -0x1p-1)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const 0x1p-1)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const -0x1p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const 0x1p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const -0x1p+0)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const 0x1p+0)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const -inf)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const inf)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const -inf)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const inf)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const -nan)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-149) (f32.const nan)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const -nan)) (f32.const -0x1p-149))
+(assert_return (invoke "copysign" (f32.const 0x1p-149) (f32.const nan)) (f32.const 0x1p-149))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const -0x0p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const 0x0p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const -0x0p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const 0x0p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const -0x1p-149)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const 0x1p-149)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const -0x1p-149)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const 0x1p-149)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const -0x1p-1)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const 0x1p-1)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const -0x1p-1)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const 0x1p-1)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const -0x1p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const 0x1p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const -0x1p+0)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const 0x1p+0)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const -inf)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const inf)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const -inf)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const inf)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const -nan)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-126) (f32.const nan)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const -nan)) (f32.const -0x1p-126))
+(assert_return (invoke "copysign" (f32.const 0x1p-126) (f32.const nan)) (f32.const 0x1p-126))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const -0x0p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const 0x0p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const -0x0p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const 0x0p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const -0x1p-149)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const 0x1p-149)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const -0x1p-149)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const 0x1p-149)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const -0x1p-126)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const 0x1p-126)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const -0x1p-126)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const 0x1p-126)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const -0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const -0x1p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const 0x1p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const -0x1p+0)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const 0x1p+0)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const -inf)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const inf)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const -inf)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const inf)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const -nan)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p-1) (f32.const nan)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const -nan)) (f32.const -0x1p-1))
+(assert_return (invoke "copysign" (f32.const 0x1p-1) (f32.const nan)) (f32.const 0x1p-1))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const -0x0p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const 0x0p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const -0x0p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const 0x0p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const -0x1p-149)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const 0x1p-149)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const -0x1p-149)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const 0x1p-149)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const -0x1p-126)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const 0x1p-126)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const -0x1p-126)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const 0x1p-126)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const -0x1p-1)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const 0x1p-1)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const -0x1p-1)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const 0x1p-1)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const -0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const -inf)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const inf)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const -inf)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const inf)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const -nan)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1p+0) (f32.const nan)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const -nan)) (f32.const -0x1p+0))
+(assert_return (invoke "copysign" (f32.const 0x1p+0) (f32.const nan)) (f32.const 0x1p+0))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const -inf)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const inf)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const -inf)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const inf)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const -nan)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.921fb6p+2) (f32.const nan)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const -nan)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const 0x1.921fb6p+2) (f32.const nan)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const -inf)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const inf)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const -inf)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const inf)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const -nan)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -0x1.fffffep+127) (f32.const nan)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const -nan)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const 0x1.fffffep+127) (f32.const nan)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const -0x0p+0)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const 0x0p+0)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const -0x0p+0)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const 0x0p+0)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const -0x1p-149)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const 0x1p-149)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const -0x1p-149)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const 0x1p-149)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const -0x1p-126)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const 0x1p-126)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const -0x1p-126)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const 0x1p-126)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const -0x1p-1)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const 0x1p-1)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const -0x1p-1)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const 0x1p-1)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const -0x1p+0)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const 0x1p+0)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const -0x1p+0)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const 0x1p+0)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const -0x1.921fb6p+2)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const 0x1.921fb6p+2)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const -0x1.921fb6p+2)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const 0x1.921fb6p+2)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const -0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const 0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const -0x1.fffffep+127)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const 0x1.fffffep+127)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const inf)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const -nan)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const -inf) (f32.const nan)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const -nan)) (f32.const -inf))
+(assert_return (invoke "copysign" (f32.const inf) (f32.const nan)) (f32.const inf))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const -0x0p+0)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const 0x0p+0)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const -0x0p+0)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const 0x0p+0)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const -0x1p-149)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const 0x1p-149)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const -0x1p-149)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const 0x1p-149)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const -0x1p-126)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const 0x1p-126)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const -0x1p-126)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const 0x1p-126)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const -0x1p-1)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const 0x1p-1)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const -0x1p-1)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const 0x1p-1)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const -0x1p+0)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const 0x1p+0)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const -0x1p+0)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const 0x1p+0)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const -0x1.921fb6p+2)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const 0x1.921fb6p+2)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const -0x1.921fb6p+2)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const 0x1.921fb6p+2)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const -0x1.fffffep+127)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const 0x1.fffffep+127)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const -0x1.fffffep+127)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const 0x1.fffffep+127)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const -inf)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const inf)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const -inf)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const inf)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const -nan) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "copysign" (f32.const nan) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "abs" (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "abs" (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "abs" (f32.const -0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "abs" (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "abs" (f32.const -0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "abs" (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "abs" (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "abs" (f32.const 0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "abs" (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "abs" (f32.const 0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "abs" (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "abs" (f32.const 0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "abs" (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "abs" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "abs" (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "abs" (f32.const inf)) (f32.const inf))
+(assert_return (invoke "abs" (f32.const -nan)) (f32.const nan))
+(assert_return (invoke "abs" (f32.const nan)) (f32.const nan))
+(assert_return (invoke "neg" (f32.const -0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "neg" (f32.const 0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "neg" (f32.const -0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "neg" (f32.const 0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "neg" (f32.const -0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "neg" (f32.const 0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "neg" (f32.const -0x1p-1)) (f32.const 0x1p-1))
+(assert_return (invoke "neg" (f32.const 0x1p-1)) (f32.const -0x1p-1))
+(assert_return (invoke "neg" (f32.const -0x1p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "neg" (f32.const 0x1p+0)) (f32.const -0x1p+0))
+(assert_return (invoke "neg" (f32.const -0x1.921fb6p+2)) (f32.const 0x1.921fb6p+2))
+(assert_return (invoke "neg" (f32.const 0x1.921fb6p+2)) (f32.const -0x1.921fb6p+2))
+(assert_return (invoke "neg" (f32.const -0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "neg" (f32.const 0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "neg" (f32.const -inf)) (f32.const inf))
+(assert_return (invoke "neg" (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "neg" (f32.const -nan)) (f32.const nan))
+(assert_return (invoke "neg" (f32.const nan)) (f32.const -nan))
+
+
+;; Type check
+
+(assert_invalid (module (func (result f32) (f32.copysign (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.abs (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.neg (i64.const 0)))) "type mismatch")
diff --git a/binaryen/test/spec/f32_cmp.wast b/binaryen/test/spec/f32_cmp.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/f32_cmp.wast
@@ -0,0 +1,2422 @@
+;; Test all the f32 comparison operators on major boundary values and all
+;; special values.
+
+(module
+  (func (export "eq") (param $x f32) (param $y f32) (result i32) (f32.eq (local.get $x) (local.get $y)))
+  (func (export "ne") (param $x f32) (param $y f32) (result i32) (f32.ne (local.get $x) (local.get $y)))
+  (func (export "lt") (param $x f32) (param $y f32) (result i32) (f32.lt (local.get $x) (local.get $y)))
+  (func (export "le") (param $x f32) (param $y f32) (result i32) (f32.le (local.get $x) (local.get $y)))
+  (func (export "gt") (param $x f32) (param $y f32) (result i32) (f32.gt (local.get $x) (local.get $y)))
+  (func (export "ge") (param $x f32) (param $y f32) (result i32) (f32.ge (local.get $x) (local.get $y)))
+)
+
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x0p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x0p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-149) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-149) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-126) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-126) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p-1) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p-1) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.921fb6p+2) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.921fb6p+2) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -0x1.fffffep+127) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const 0x1.fffffep+127) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -inf) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const inf) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const -nan:0x200000) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "eq" (f32.const nan:0x200000) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x0p+0) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x0p+0) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-149) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-149) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-126) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-126) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p-1) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p-1) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1p+0) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1p+0) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.921fb6p+2) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.921fb6p+2) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -0x1.fffffep+127) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const 0x1.fffffep+127) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -inf) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const inf) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const -nan:0x200000) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const -nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "ne" (f32.const nan:0x200000) (f32.const nan:0x200000)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x0p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x0p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-149) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-149) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-126) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-126) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p-1) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p-1) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.921fb6p+2) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.921fb6p+2) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -0x1.fffffep+127) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const 0x1.fffffep+127) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const inf) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const inf) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const inf) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const inf) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const inf) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const inf) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const inf) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const inf) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const inf) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const inf) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const inf) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const inf) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const inf) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const inf) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f32.const inf) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const inf) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -inf) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const inf) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const inf) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const inf) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const inf) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const -nan:0x200000) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "lt" (f32.const nan:0x200000) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x0p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x0p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-149) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-149) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-126) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-126) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p-1) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p-1) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.921fb6p+2) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.921fb6p+2) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -0x1.fffffep+127) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const 0x1.fffffep+127) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -inf) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -inf) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const inf) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const inf) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -inf) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -inf) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "le" (f32.const inf) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const inf) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -inf) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -inf) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "le" (f32.const inf) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const inf) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -inf) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -inf) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f32.const inf) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const inf) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -inf) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -inf) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f32.const inf) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const inf) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -inf) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -inf) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "le" (f32.const inf) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const inf) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -inf) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -inf) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "le" (f32.const inf) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const inf) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -inf) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -inf) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const inf) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const inf) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f32.const -inf) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -inf) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -inf) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -inf) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const inf) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const inf) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const inf) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const inf) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const -nan:0x200000) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "le" (f32.const nan:0x200000) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x0p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x0p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-149) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-149) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-126) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-126) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p-1) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p-1) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.921fb6p+2) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.921fb6p+2) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -0x1.fffffep+127) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const 0x1.fffffep+127) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const inf) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const inf) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const inf) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const inf) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const inf) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const inf) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const inf) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const inf) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const inf) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const inf) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const inf) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const inf) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const inf) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const inf) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const inf) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f32.const inf) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -inf) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const inf) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const inf) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const inf) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const inf) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const -nan:0x200000) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "gt" (f32.const nan:0x200000) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x0p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x0p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-149) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-149) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-126) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-126) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p-1) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p-1) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1p+0) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.921fb6p+2) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.921fb6p+2) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -0x1.fffffep+127) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const 0x1.fffffep+127) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const inf) (f32.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const inf) (f32.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const inf) (f32.const -0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const inf) (f32.const 0x1p-149)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const inf) (f32.const -0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const inf) (f32.const 0x1p-126)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const inf) (f32.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const inf) (f32.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const inf) (f32.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const inf) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const inf) (f32.const -0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const inf) (f32.const 0x1.921fb6p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const inf) (f32.const -0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const inf) (f32.const 0x1.fffffep+127)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const inf) (f32.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const inf) (f32.const inf)) (i32.const 1))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -inf) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const inf) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const inf) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const inf) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const inf) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const -0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const 0x1p-126)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const -0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const 0x1.921fb6p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const -0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const 0x1.fffffep+127)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const -inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const -nan:0x200000) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const -nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan) (f32.const nan:0x200000)) (i32.const 0))
+(assert_return (invoke "ge" (f32.const nan:0x200000) (f32.const nan:0x200000)) (i32.const 0))
+
+
+;; Type check
+
+(assert_invalid (module (func (result f32) (f32.eq (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.ge (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.gt (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.le (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.lt (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f32) (f32.ne (i64.const 0) (f64.const 0)))) "type mismatch")
diff --git a/binaryen/test/spec/f64.load32.fail.wast b/binaryen/test/spec/f64.load32.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/f64.load32.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (result f64) (f64.load32 (local.get 0))))
diff --git a/binaryen/test/spec/f64.load64.fail.wast b/binaryen/test/spec/f64.load64.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/f64.load64.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (result f64) (f64.load64 (local.get 0))))
diff --git a/binaryen/test/spec/f64.store32.fail.wast b/binaryen/test/spec/f64.store32.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/f64.store32.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (param f32) (f64.store32 (local.get 0) (local.get 1))))
diff --git a/binaryen/test/spec/f64.store64.fail.wast b/binaryen/test/spec/f64.store64.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/f64.store64.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (param f64) (f64.store64 (local.get 0) (local.get 1))))
diff --git a/binaryen/test/spec/f64.wast b/binaryen/test/spec/f64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/f64.wast
@@ -0,0 +1,2533 @@
+;; Test all the f64 operators on major boundary values and all special
+;; values (except comparison and bitwise operators, which are tested in
+;; f64_bitwise.wast and f64_cmp.wast).
+
+(module
+  (func (export "add") (param $x f64) (param $y f64) (result f64) (f64.add (local.get $x) (local.get $y)))
+  (func (export "sub") (param $x f64) (param $y f64) (result f64) (f64.sub (local.get $x) (local.get $y)))
+  (func (export "mul") (param $x f64) (param $y f64) (result f64) (f64.mul (local.get $x) (local.get $y)))
+  (func (export "div") (param $x f64) (param $y f64) (result f64) (f64.div (local.get $x) (local.get $y)))
+  (func (export "sqrt") (param $x f64) (result f64) (f64.sqrt (local.get $x)))
+  (func (export "min") (param $x f64) (param $y f64) (result f64) (f64.min (local.get $x) (local.get $y)))
+  (func (export "max") (param $x f64) (param $y f64) (result f64) (f64.max (local.get $x) (local.get $y)))
+  (func (export "ceil") (param $x f64) (result f64) (f64.ceil (local.get $x)))
+  (func (export "floor") (param $x f64) (result f64) (f64.floor (local.get $x)))
+  (func (export "trunc") (param $x f64) (result f64) (f64.trunc (local.get $x)))
+  (func (export "nearest") (param $x f64) (result f64) (f64.nearest (local.get $x)))
+)
+
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const -0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const -0x0p+0) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const 0x0p+0) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "add" (f64.const -0x0p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -0x0p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const -0x0p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -0x0p+0) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const 0x0p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const 0x0p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const 0x0p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const 0x0p+0) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000002p-1022))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000002p-1022))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (f64.const -0x1.0000000000001p-1022))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (f64.const 0x0.fffffffffffffp-1022))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (f64.const -0x0.fffffffffffffp-1022))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (f64.const 0x1.0000000000001p-1022))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const 0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const -0x0p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const 0x0p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const -0x0p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const 0x0p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1.0000000000001p-1022))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x0.fffffffffffffp-1022))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0.fffffffffffffp-1022))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1.0000000000001p-1022))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const -0x1p-1022)) (f64.const -0x1p-1021))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const 0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const -0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const 0x1p-1022)) (f64.const 0x1p-1021))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const -0x1p-1022) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const 0x1p-1022) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "add" (f64.const -0x1p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -0x1p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const -0x1p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -0x1p-1022) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const 0x1p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const 0x1p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const 0x1p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const 0x1p-1022) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const -0x0p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const 0x0p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const -0x0p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const 0x0p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const -0x1p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const 0x1p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const -0x1p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const 0x1p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const -0x1p-1)) (f64.const -0x1p+0))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const 0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const -0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const 0x1p-1)) (f64.const 0x1p+0))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const -0x1p+0)) (f64.const -0x1.8p+0))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const 0x1p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const -0x1p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const 0x1p+0)) (f64.const 0x1.8p+0))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.b21fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.721fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.721fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.b21fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const -0x1p-1) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const 0x1p-1) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "add" (f64.const -0x1p-1) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -0x1p-1) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const -0x1p-1) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -0x1p-1) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const 0x1p-1) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const 0x1p-1) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const 0x1p-1) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const 0x1p-1) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const -0x0p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const 0x0p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const -0x0p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const 0x0p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const -0x1p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const 0x1p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const -0x1p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const 0x1p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const -0x1p-1)) (f64.const -0x1.8p+0))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const 0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const -0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const 0x1p-1)) (f64.const 0x1.8p+0))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const -0x1p+0)) (f64.const -0x1p+1))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const 0x1p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const -0x1p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const 0x1p+0)) (f64.const 0x1p+1))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.d21fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.521fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.521fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.d21fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const -0x1p+0) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const 0x1p+0) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "add" (f64.const -0x1p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -0x1p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const -0x1p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -0x1p+0) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const 0x1p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const 0x1p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const 0x1p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const 0x1p+0) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (f64.const -0x1.b21fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (f64.const -0x1.721fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (f64.const 0x1.721fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (f64.const 0x1.b21fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (f64.const -0x1.d21fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (f64.const -0x1.521fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (f64.const 0x1.521fb54442d18p+2))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (f64.const 0x1.d21fb54442d18p+2))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+3))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x0p+0))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x0p+0))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+3))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const 0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "add" (f64.const -inf) (f64.const -0x0p+0)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const -inf) (f64.const 0x0p+0)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const inf) (f64.const -0x0p+0)) (f64.const inf))
+(assert_return (invoke "add" (f64.const inf) (f64.const 0x0p+0)) (f64.const inf))
+(assert_return (invoke "add" (f64.const -inf) (f64.const -0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const -inf) (f64.const 0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const inf) (f64.const -0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "add" (f64.const inf) (f64.const 0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "add" (f64.const -inf) (f64.const -0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const -inf) (f64.const 0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const inf) (f64.const -0x1p-1022)) (f64.const inf))
+(assert_return (invoke "add" (f64.const inf) (f64.const 0x1p-1022)) (f64.const inf))
+(assert_return (invoke "add" (f64.const -inf) (f64.const -0x1p-1)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const -inf) (f64.const 0x1p-1)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const inf) (f64.const -0x1p-1)) (f64.const inf))
+(assert_return (invoke "add" (f64.const inf) (f64.const 0x1p-1)) (f64.const inf))
+(assert_return (invoke "add" (f64.const -inf) (f64.const -0x1p+0)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const -inf) (f64.const 0x1p+0)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const inf) (f64.const -0x1p+0)) (f64.const inf))
+(assert_return (invoke "add" (f64.const inf) (f64.const 0x1p+0)) (f64.const inf))
+(assert_return (invoke "add" (f64.const -inf) (f64.const -0x1.921fb54442d18p+2)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const -inf) (f64.const 0x1.921fb54442d18p+2)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const inf) (f64.const -0x1.921fb54442d18p+2)) (f64.const inf))
+(assert_return (invoke "add" (f64.const inf) (f64.const 0x1.921fb54442d18p+2)) (f64.const inf))
+(assert_return (invoke "add" (f64.const -inf) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const -inf) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "add" (f64.const inf) (f64.const -0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "add" (f64.const inf) (f64.const 0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "add" (f64.const -inf) (f64.const -inf)) (f64.const -inf))
+(assert_return_canonical_nan (invoke "add" (f64.const -inf) (f64.const inf)))
+(assert_return_canonical_nan (invoke "add" (f64.const inf) (f64.const -inf)))
+(assert_return (invoke "add" (f64.const inf) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "add" (f64.const -inf) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -inf) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const -inf) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -inf) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const inf) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const inf) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const inf) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const inf) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const -0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1022)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const 0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1022)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const -0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const -0x1p-1022)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const 0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const 0x1p-1022)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const -inf)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const inf)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const inf)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const -inf)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const inf)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const inf)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan) (f64.const -nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const -nan) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan) (f64.const nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const -nan:0x4000000000000) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan) (f64.const -nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "add" (f64.const nan) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan) (f64.const nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "add" (f64.const nan:0x4000000000000) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const -0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const 0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const -0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const -0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const 0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const -0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const 0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const -0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const 0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const -0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const 0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const -0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const 0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const -0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const 0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const -0x0p+0) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const 0x0p+0) (f64.const inf)) (f64.const -inf))
+(assert_return_canonical_nan (invoke "sub" (f64.const -0x0p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -0x0p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -0x0p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -0x0p+0) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const 0x0p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const 0x0p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const 0x0p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const 0x0p+0) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x0.0000000000002p-1022))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0.0000000000002p-1022))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (f64.const 0x0.fffffffffffffp-1022))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (f64.const -0x1.0000000000001p-1022))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (f64.const 0x1.0000000000001p-1022))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (f64.const -0x0.fffffffffffffp-1022))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const inf)) (f64.const -inf))
+(assert_return_canonical_nan (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const 0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const -0x0p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const 0x0p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const -0x0p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const 0x0p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.fffffffffffffp-1022))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1.0000000000001p-1022))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1.0000000000001p-1022))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.fffffffffffffp-1022))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const -0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const 0x1p-1022)) (f64.const -0x1p-1021))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const -0x1p-1022)) (f64.const 0x1p-1021))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const 0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const -0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const 0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const -0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const 0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const -0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const 0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const -0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const 0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const -0x1p-1022) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const 0x1p-1022) (f64.const inf)) (f64.const -inf))
+(assert_return_canonical_nan (invoke "sub" (f64.const -0x1p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -0x1p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -0x1p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -0x1p-1022) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const 0x1p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const 0x1p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const 0x1p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const 0x1p-1022) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const -0x0p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const 0x0p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const -0x0p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const 0x0p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const -0x1p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const 0x1p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const -0x1p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const 0x1p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const -0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const 0x1p-1)) (f64.const -0x1p+0))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const -0x1p-1)) (f64.const 0x1p+0))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const 0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const -0x1p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const 0x1p+0)) (f64.const -0x1.8p+0))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const -0x1p+0)) (f64.const 0x1.8p+0))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const 0x1p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.721fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.b21fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.b21fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.721fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const -0x1p-1) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const 0x1p-1) (f64.const inf)) (f64.const -inf))
+(assert_return_canonical_nan (invoke "sub" (f64.const -0x1p-1) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -0x1p-1) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -0x1p-1) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -0x1p-1) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const 0x1p-1) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const 0x1p-1) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const 0x1p-1) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const 0x1p-1) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const -0x0p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const 0x0p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const -0x0p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const 0x0p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const -0x1p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const 0x1p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const -0x1p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const 0x1p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const 0x1p-1)) (f64.const -0x1.8p+0))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const -0x1p-1)) (f64.const 0x1.8p+0))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const -0x1p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const 0x1p+0)) (f64.const -0x1p+1))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const -0x1p+0)) (f64.const 0x1p+1))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const 0x1p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.521fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.d21fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.d21fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.521fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const -0x1p+0) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const 0x1p+0) (f64.const inf)) (f64.const -inf))
+(assert_return_canonical_nan (invoke "sub" (f64.const -0x1p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -0x1p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -0x1p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -0x1p+0) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const 0x1p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const 0x1p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const 0x1p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const 0x1p+0) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (f64.const -0x1.721fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (f64.const -0x1.b21fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (f64.const 0x1.b21fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (f64.const 0x1.721fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (f64.const -0x1.521fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (f64.const -0x1.d21fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (f64.const 0x1.d21fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (f64.const 0x1.521fb54442d18p+2))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x0p+0))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+3))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+3))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x0p+0))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const inf)) (f64.const -inf))
+(assert_return_canonical_nan (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const 0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const inf)) (f64.const -inf))
+(assert_return_canonical_nan (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "sub" (f64.const -inf) (f64.const -0x0p+0)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const -inf) (f64.const 0x0p+0)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const inf) (f64.const -0x0p+0)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const inf) (f64.const 0x0p+0)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const -inf) (f64.const -0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const -inf) (f64.const 0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const inf) (f64.const -0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const inf) (f64.const 0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const -inf) (f64.const -0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const -inf) (f64.const 0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const inf) (f64.const -0x1p-1022)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const inf) (f64.const 0x1p-1022)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const -inf) (f64.const -0x1p-1)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const -inf) (f64.const 0x1p-1)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const inf) (f64.const -0x1p-1)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const inf) (f64.const 0x1p-1)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const -inf) (f64.const -0x1p+0)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const -inf) (f64.const 0x1p+0)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const inf) (f64.const -0x1p+0)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const inf) (f64.const 0x1p+0)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const -inf) (f64.const -0x1.921fb54442d18p+2)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const -inf) (f64.const 0x1.921fb54442d18p+2)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const inf) (f64.const -0x1.921fb54442d18p+2)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const inf) (f64.const 0x1.921fb54442d18p+2)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const -inf) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const -inf) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const inf) (f64.const -0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "sub" (f64.const inf) (f64.const 0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return_canonical_nan (invoke "sub" (f64.const -inf) (f64.const -inf)))
+(assert_return (invoke "sub" (f64.const -inf) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "sub" (f64.const inf) (f64.const -inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "sub" (f64.const inf) (f64.const inf)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -inf) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -inf) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -inf) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -inf) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const inf) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const inf) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const inf) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const inf) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const -0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1022)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const 0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1022)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const -0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const -0x1p-1022)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const 0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const 0x1p-1022)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const -inf)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const inf)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const inf)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const -inf)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const inf)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const inf)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan) (f64.const -nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const -nan) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan) (f64.const nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const -nan:0x4000000000000) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan) (f64.const -nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sub" (f64.const nan) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan) (f64.const nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "sub" (f64.const nan:0x4000000000000) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "mul" (f64.const -0x0p+0) (f64.const -0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0p+0) (f64.const 0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0p+0) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0p+0) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0p+0) (f64.const -0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0p+0) (f64.const 0x1p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0p+0) (f64.const -0x1p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0p+0) (f64.const 0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0p+0) (f64.const -0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0p+0) (f64.const 0x1p-1)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0p+0) (f64.const -0x1p-1)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0p+0) (f64.const 0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0p+0) (f64.const -0x1p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0p+0) (f64.const 0x1p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0p+0) (f64.const -0x1p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0p+0) (f64.const 0x1p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x0p+0) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x0p+0) (f64.const inf)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x0p+0) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x0p+0) (f64.const inf)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x0p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -0x0p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x0p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -0x0p+0) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x0p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const 0x0p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x0p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const 0x0p+0) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x0.0000000000006p-1022))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x0.0000000000006p-1022))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x0.0000000000006p-1022))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x0.0000000000006p-1022))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp-51))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp-51))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp-51))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp-51))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const 0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const -0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const 0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const -0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const 0x1p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const -0x1p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const 0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const -0x1p-1)) (f64.const 0x0.8p-1022))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const 0x1p-1)) (f64.const -0x0.8p-1022))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const -0x1p-1)) (f64.const -0x0.8p-1022))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const 0x1p-1)) (f64.const 0x0.8p-1022))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const -0x1p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const 0x1p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const -0x1p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const 0x1p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p-1020))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p-1020))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p-1020))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p-1020))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -0x1p-1022) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1p-1022) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x1p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -0x1p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x1p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -0x1p-1022) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x1p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const 0x1p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x1p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const 0x1p-1022) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const -0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const 0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const -0x1p-1022)) (f64.const 0x0.8p-1022))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const 0x1p-1022)) (f64.const -0x0.8p-1022))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const -0x1p-1022)) (f64.const -0x0.8p-1022))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const 0x1p-1022)) (f64.const 0x0.8p-1022))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const -0x1p-1)) (f64.const 0x1p-2))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const 0x1p-1)) (f64.const -0x1p-2))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const -0x1p-1)) (f64.const -0x1p-2))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const 0x1p-1)) (f64.const 0x1p-2))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const -0x1p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const 0x1p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const -0x1p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const 0x1p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+1))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+1))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+1))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+1))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1022))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1022))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1022))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1022))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -0x1p-1) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1p-1) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x1p-1) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -0x1p-1) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x1p-1) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -0x1p-1) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x1p-1) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const 0x1p-1) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x1p-1) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const 0x1p-1) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const -0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const 0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const -0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const 0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const -0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const 0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const -0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const 0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -0x1p+0) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1p+0) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x1p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -0x1p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x1p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -0x1p+0) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x1p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const 0x1p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x1p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const 0x1p+0) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0.0000000000006p-1022))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x0.0000000000006p-1022))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000006p-1022))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000006p-1022))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (f64.const 0x1.921fb54442d18p-1020))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (f64.const -0x1.921fb54442d18p-1020))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (f64.const -0x1.921fb54442d18p-1020))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (f64.const 0x1.921fb54442d18p-1020))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (f64.const 0x1.921fb54442d18p+1))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (f64.const -0x1.921fb54442d18p+1))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (f64.const -0x1.921fb54442d18p+1))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (f64.const 0x1.921fb54442d18p+1))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.3bd3cc9be45dep+5))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.3bd3cc9be45dep+5))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.3bd3cc9be45dep+5))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.3bd3cc9be45dep+5))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const 0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1.fffffffffffffp-51))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1.fffffffffffffp-51))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1.fffffffffffffp-51))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1.fffffffffffffp-51))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (f64.const 0x1.fffffffffffffp+1))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (f64.const -0x1.fffffffffffffp+1))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (f64.const -0x1.fffffffffffffp+1))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (f64.const 0x1.fffffffffffffp+1))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (f64.const 0x1.fffffffffffffp+1022))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (f64.const -0x1.fffffffffffffp+1022))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (f64.const -0x1.fffffffffffffp+1022))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (f64.const 0x1.fffffffffffffp+1022))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -inf) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -inf) (f64.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "mul" (f64.const inf) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "mul" (f64.const inf) (f64.const 0x0p+0)))
+(assert_return (invoke "mul" (f64.const -inf) (f64.const -0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -inf) (f64.const 0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const inf) (f64.const -0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const inf) (f64.const 0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -inf) (f64.const -0x1p-1022)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -inf) (f64.const 0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const inf) (f64.const -0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const inf) (f64.const 0x1p-1022)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -inf) (f64.const -0x1p-1)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -inf) (f64.const 0x1p-1)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const inf) (f64.const -0x1p-1)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const inf) (f64.const 0x1p-1)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -inf) (f64.const -0x1p+0)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -inf) (f64.const 0x1p+0)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const inf) (f64.const -0x1p+0)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const inf) (f64.const 0x1p+0)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -inf) (f64.const -0x1.921fb54442d18p+2)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -inf) (f64.const 0x1.921fb54442d18p+2)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const inf) (f64.const -0x1.921fb54442d18p+2)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const inf) (f64.const 0x1.921fb54442d18p+2)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -inf) (f64.const -0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -inf) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const inf) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const inf) (f64.const 0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -inf) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "mul" (f64.const -inf) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const inf) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "mul" (f64.const inf) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "mul" (f64.const -inf) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -inf) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -inf) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -inf) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const inf) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const inf) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const inf) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const inf) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const -0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1022)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const 0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1022)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const -0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const -0x1p-1022)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const 0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const 0x1p-1022)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const -inf)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const inf)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const inf)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const -inf)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const inf)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const inf)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan) (f64.const -nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const -nan) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan) (f64.const nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const -nan:0x4000000000000) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan) (f64.const -nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "mul" (f64.const nan) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan) (f64.const nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "mul" (f64.const nan:0x4000000000000) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x0p+0) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x0p+0) (f64.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x0p+0) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x0p+0) (f64.const 0x0p+0)))
+(assert_return (invoke "div" (f64.const -0x0p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0p+0) (f64.const -0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0p+0) (f64.const 0x1p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0p+0) (f64.const -0x1p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0p+0) (f64.const 0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0p+0) (f64.const -0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0p+0) (f64.const 0x1p-1)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0p+0) (f64.const -0x1p-1)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0p+0) (f64.const 0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0p+0) (f64.const -0x1p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0p+0) (f64.const 0x1p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0p+0) (f64.const -0x1p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0p+0) (f64.const 0x1p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0p+0) (f64.const -inf)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0p+0) (f64.const inf)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0p+0) (f64.const -inf)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0p+0) (f64.const inf)) (f64.const 0x0p+0))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x0p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -0x0p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x0p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -0x0p+0) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x0p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const 0x0p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x0p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const 0x0p+0) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (f64.const 0x1p-52))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (f64.const -0x1p-52))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (f64.const -0x1p-52))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (f64.const 0x1p-52))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1)) (f64.const 0x0.0000000000002p-1022))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1)) (f64.const -0x0.0000000000002p-1022))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1)) (f64.const -0x0.0000000000002p-1022))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1)) (f64.const 0x0.0000000000002p-1022))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const -inf)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const inf)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const -inf)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const inf)) (f64.const 0x0p+0))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const 0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const -0x0p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const 0x0p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const -0x0p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const 0x0p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1p+52))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1p+52))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p+52))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p+52))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const -0x1p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const 0x1p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const -0x1p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const 0x1p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const -0x1p-1)) (f64.const 0x1p-1021))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const 0x1p-1)) (f64.const -0x1p-1021))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const -0x1p-1)) (f64.const -0x1p-1021))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const 0x1p-1)) (f64.const 0x1p-1021))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const -0x1p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const 0x1p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const -0x1p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const 0x1p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x0.28be60db9391p-1022))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x0.28be60db9391p-1022))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x0.28be60db9391p-1022))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x0.28be60db9391p-1022))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const -inf)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x1p-1022) (f64.const inf)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const -inf)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x1p-1022) (f64.const inf)) (f64.const 0x0p+0))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x1p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -0x1p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x1p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -0x1p-1022) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x1p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const 0x1p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x1p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const 0x1p-1022) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const -0x0p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const 0x0p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const -0x0p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const 0x0p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const -0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const 0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const -0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const 0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const -0x1p-1022)) (f64.const 0x1p+1021))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const 0x1p-1022)) (f64.const -0x1p+1021))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const -0x1p-1022)) (f64.const -0x1p+1021))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const 0x1p-1022)) (f64.const 0x1p+1021))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const -0x1p-1)) (f64.const 0x1p+0))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const 0x1p-1)) (f64.const -0x1p+0))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const -0x1p-1)) (f64.const -0x1p+0))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const 0x1p-1)) (f64.const 0x1p+0))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const -0x1p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const 0x1p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const -0x1p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const 0x1p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.45f306dc9c883p-4))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.45f306dc9c883p-4))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.45f306dc9c883p-4))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.45f306dc9c883p-4))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x0.2p-1022))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x0.2p-1022))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x0.2p-1022))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0.2p-1022))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const -inf)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x1p-1) (f64.const inf)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const -inf)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x1p-1) (f64.const inf)) (f64.const 0x0p+0))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x1p-1) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -0x1p-1) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x1p-1) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -0x1p-1) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x1p-1) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const 0x1p-1) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x1p-1) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const 0x1p-1) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const -0x0p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const 0x0p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const -0x0p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const 0x0p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const -0x1p-1022)) (f64.const 0x1p+1022))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const 0x1p-1022)) (f64.const -0x1p+1022))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const -0x1p-1022)) (f64.const -0x1p+1022))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const 0x1p-1022)) (f64.const 0x1p+1022))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const -0x1p-1)) (f64.const 0x1p+1))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const 0x1p-1)) (f64.const -0x1p+1))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const -0x1p-1)) (f64.const -0x1p+1))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const 0x1p-1)) (f64.const 0x1p+1))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const -0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const 0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.45f306dc9c883p-3))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.45f306dc9c883p-3))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.45f306dc9c883p-3))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.45f306dc9c883p-3))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x0.4p-1022))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x0.4p-1022))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x0.4p-1022))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0.4p-1022))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const -inf)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x1p+0) (f64.const inf)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const -inf)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x1p+0) (f64.const inf)) (f64.const 0x0p+0))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x1p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -0x1p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x1p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -0x1p+0) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x1p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const 0x1p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x1p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const 0x1p+0) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (f64.const 0x1.921fb54442d18p+3))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (f64.const -0x1.921fb54442d18p+3))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (f64.const -0x1.921fb54442d18p+3))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (f64.const 0x1.921fb54442d18p+3))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1p+0))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1p+0))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1p+0))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1p+0))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.921fb54442d19p-1022))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.921fb54442d19p-1022))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.921fb54442d19p-1022))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.921fb54442d19p-1022))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const -inf)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const inf)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const -inf)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const inf)) (f64.const 0x0p+0))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const 0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.45f306dc9c882p+1021))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.45f306dc9c882p+1021))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.45f306dc9c882p+1021))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.45f306dc9c882p+1021))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1p+0))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1p+0))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1p+0))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1p+0))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const -inf)) (f64.const 0x0p+0))
+(assert_return (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const inf)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const -inf)) (f64.const -0x0p+0))
+(assert_return (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const inf)) (f64.const 0x0p+0))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "div" (f64.const -inf) (f64.const -0x0p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -inf) (f64.const 0x0p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const inf) (f64.const -0x0p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const inf) (f64.const 0x0p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -inf) (f64.const -0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -inf) (f64.const 0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const inf) (f64.const -0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const inf) (f64.const 0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -inf) (f64.const -0x1p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -inf) (f64.const 0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const inf) (f64.const -0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const inf) (f64.const 0x1p-1022)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -inf) (f64.const -0x1p-1)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -inf) (f64.const 0x1p-1)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const inf) (f64.const -0x1p-1)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const inf) (f64.const 0x1p-1)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -inf) (f64.const -0x1p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -inf) (f64.const 0x1p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const inf) (f64.const -0x1p+0)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const inf) (f64.const 0x1p+0)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -inf) (f64.const -0x1.921fb54442d18p+2)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -inf) (f64.const 0x1.921fb54442d18p+2)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const inf) (f64.const -0x1.921fb54442d18p+2)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const inf) (f64.const 0x1.921fb54442d18p+2)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -inf) (f64.const -0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "div" (f64.const -inf) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const inf) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "div" (f64.const inf) (f64.const 0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return_canonical_nan (invoke "div" (f64.const -inf) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "div" (f64.const -inf) (f64.const inf)))
+(assert_return_canonical_nan (invoke "div" (f64.const inf) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "div" (f64.const inf) (f64.const inf)))
+(assert_return_canonical_nan (invoke "div" (f64.const -inf) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -inf) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const -inf) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -inf) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const inf) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const inf) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const inf) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const inf) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const -0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1022)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const 0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1022)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const -0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const -0x1p-1022)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const 0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const 0x1p-1022)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const -inf)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const inf)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const inf)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const -inf)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const inf)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const inf)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan) (f64.const -nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const -nan) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan) (f64.const nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const -nan:0x4000000000000) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan) (f64.const -nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "div" (f64.const nan) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan) (f64.const nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "div" (f64.const nan:0x4000000000000) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const 0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const 0x1p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const 0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const 0x1p-1)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const 0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const 0x1p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const 0x1p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x0p+0))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const -0x0p+0) (f64.const inf)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const 0x0p+0) (f64.const inf)) (f64.const 0x0p+0))
+(assert_return_canonical_nan (invoke "min" (f64.const -0x0p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -0x0p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const -0x0p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -0x0p+0) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const 0x0p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const 0x0p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const 0x0p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const 0x0p+0) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const inf)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const inf)) (f64.const 0x0.0000000000001p-1022))
+(assert_return_canonical_nan (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const 0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const -0x0p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const 0x0p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const 0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const 0x1p-1)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const 0x1p-1)) (f64.const 0x1p-1022))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const 0x1p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const 0x1p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1p-1022))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1p-1022))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const -0x1p-1022) (f64.const inf)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const 0x1p-1022) (f64.const inf)) (f64.const 0x1p-1022))
+(assert_return_canonical_nan (invoke "min" (f64.const -0x1p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -0x1p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const -0x1p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -0x1p-1022) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const 0x1p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const 0x1p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const 0x1p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const 0x1p-1022) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const -0x0p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const 0x0p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const -0x1p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const 0x1p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const 0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const 0x1p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const 0x1p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1p-1))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1p-1))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const -0x1p-1) (f64.const inf)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const 0x1p-1) (f64.const inf)) (f64.const 0x1p-1))
+(assert_return_canonical_nan (invoke "min" (f64.const -0x1p-1) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -0x1p-1) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const -0x1p-1) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -0x1p-1) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const 0x1p-1) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const 0x1p-1) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const 0x1p-1) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const 0x1p-1) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const -0x0p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const 0x0p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const -0x1p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const 0x1p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const -0x1p-1)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const 0x1p-1)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const 0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1p+0))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1p+0))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const -0x1p+0) (f64.const inf)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const 0x1p+0) (f64.const inf)) (f64.const 0x1p+0))
+(assert_return_canonical_nan (invoke "min" (f64.const -0x1p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -0x1p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const -0x1p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -0x1p+0) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const 0x1p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const 0x1p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const 0x1p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const 0x1p+0) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const inf)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const inf)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return_canonical_nan (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const 0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const inf)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const inf)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return_canonical_nan (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "min" (f64.const -inf) (f64.const -0x0p+0)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const -inf) (f64.const 0x0p+0)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const inf) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "min" (f64.const inf) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "min" (f64.const -inf) (f64.const -0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const -inf) (f64.const 0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const inf) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const inf) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "min" (f64.const -inf) (f64.const -0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const -inf) (f64.const 0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const inf) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "min" (f64.const inf) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "min" (f64.const -inf) (f64.const -0x1p-1)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const -inf) (f64.const 0x1p-1)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const inf) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "min" (f64.const inf) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "min" (f64.const -inf) (f64.const -0x1p+0)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const -inf) (f64.const 0x1p+0)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const inf) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "min" (f64.const inf) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "min" (f64.const -inf) (f64.const -0x1.921fb54442d18p+2)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const -inf) (f64.const 0x1.921fb54442d18p+2)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const inf) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const inf) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "min" (f64.const -inf) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const -inf) (f64.const 0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const inf) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const inf) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "min" (f64.const -inf) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const -inf) (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const inf) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "min" (f64.const inf) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "min" (f64.const -inf) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -inf) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const -inf) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -inf) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const inf) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const inf) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const inf) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const inf) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const -0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1022)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const 0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1022)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const -0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const -0x1p-1022)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const 0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const 0x1p-1022)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const -inf)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const inf)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const inf)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const -inf)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const inf)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const inf)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan) (f64.const -nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const -nan) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan) (f64.const nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const -nan:0x4000000000000) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan) (f64.const -nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "min" (f64.const nan) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan) (f64.const nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "min" (f64.const nan:0x4000000000000) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const -0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const -0x1p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const -0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const -0x1p-1)) (f64.const -0x0p+0))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const -0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const -0x1p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const -0x1p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x0p+0))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x0p+0))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const -inf)) (f64.const -0x0p+0))
+(assert_return (invoke "max" (f64.const -0x0p+0) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const -inf)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const 0x0p+0) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "max" (f64.const -0x0p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -0x0p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const -0x0p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -0x0p+0) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const 0x0p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const 0x0p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const 0x0p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const 0x0p+0) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const -inf)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const -inf)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const 0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const -0x0p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const 0x0p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const -0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const -0x1p-1)) (f64.const -0x1p-1022))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const -0x1p-1)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const -0x1p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const -0x1p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1p-1022))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1p-1022))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const -inf)) (f64.const -0x1p-1022))
+(assert_return (invoke "max" (f64.const -0x1p-1022) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const -inf)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const 0x1p-1022) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "max" (f64.const -0x1p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -0x1p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const -0x1p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -0x1p-1022) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const 0x1p-1022) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const 0x1p-1022) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const 0x1p-1022) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const 0x1p-1022) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const -0x0p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const 0x0p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const -0x1p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const 0x1p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const -0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const -0x1p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const -0x1p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1p-1))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1p-1))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const -inf)) (f64.const -0x1p-1))
+(assert_return (invoke "max" (f64.const -0x1p-1) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const -inf)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const 0x1p-1) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "max" (f64.const -0x1p-1) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -0x1p-1) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const -0x1p-1) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -0x1p-1) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const 0x1p-1) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const 0x1p-1) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const 0x1p-1) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const 0x1p-1) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const -0x0p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const 0x0p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const -0x1p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const 0x1p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const -0x1p-1)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const 0x1p-1)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const -0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1p+0))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1p+0))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const -inf)) (f64.const -0x1p+0))
+(assert_return (invoke "max" (f64.const -0x1p+0) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const -inf)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const 0x1p+0) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "max" (f64.const -0x1p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -0x1p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const -0x1p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -0x1p+0) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const 0x1p+0) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const 0x1p+0) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const 0x1p+0) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const 0x1p+0) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const -inf)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const -inf)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const 0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const -inf)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const -inf)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "max" (f64.const -inf) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "max" (f64.const -inf) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "max" (f64.const inf) (f64.const -0x0p+0)) (f64.const inf))
+(assert_return (invoke "max" (f64.const inf) (f64.const 0x0p+0)) (f64.const inf))
+(assert_return (invoke "max" (f64.const -inf) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const -inf) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "max" (f64.const inf) (f64.const -0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "max" (f64.const inf) (f64.const 0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "max" (f64.const -inf) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "max" (f64.const -inf) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "max" (f64.const inf) (f64.const -0x1p-1022)) (f64.const inf))
+(assert_return (invoke "max" (f64.const inf) (f64.const 0x1p-1022)) (f64.const inf))
+(assert_return (invoke "max" (f64.const -inf) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "max" (f64.const -inf) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "max" (f64.const inf) (f64.const -0x1p-1)) (f64.const inf))
+(assert_return (invoke "max" (f64.const inf) (f64.const 0x1p-1)) (f64.const inf))
+(assert_return (invoke "max" (f64.const -inf) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "max" (f64.const -inf) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "max" (f64.const inf) (f64.const -0x1p+0)) (f64.const inf))
+(assert_return (invoke "max" (f64.const inf) (f64.const 0x1p+0)) (f64.const inf))
+(assert_return (invoke "max" (f64.const -inf) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const -inf) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "max" (f64.const inf) (f64.const -0x1.921fb54442d18p+2)) (f64.const inf))
+(assert_return (invoke "max" (f64.const inf) (f64.const 0x1.921fb54442d18p+2)) (f64.const inf))
+(assert_return (invoke "max" (f64.const -inf) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const -inf) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "max" (f64.const inf) (f64.const -0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "max" (f64.const inf) (f64.const 0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "max" (f64.const -inf) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "max" (f64.const -inf) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "max" (f64.const inf) (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "max" (f64.const inf) (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "max" (f64.const -inf) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -inf) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const -inf) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -inf) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const inf) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const inf) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const inf) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const inf) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const -0x0p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const -0x0p+0)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const 0x0p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const 0x0p+0)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const -0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1022)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const 0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1022)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const -0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const -0x1p-1022)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const 0x1p-1022)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const 0x1p-1022)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const -0x1p-1)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const -0x1p-1)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const 0x1p-1)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const 0x1p-1)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const -0x1p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const -0x1p+0)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const 0x1p+0)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const 0x1p+0)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const -inf)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const inf)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const inf)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const -inf)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const -inf)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const inf)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const inf)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan) (f64.const -nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const -nan) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan) (f64.const nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const -nan:0x4000000000000) (f64.const nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan) (f64.const -nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "max" (f64.const nan) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan) (f64.const nan:0x4000000000000)))
+(assert_return_arithmetic_nan (invoke "max" (f64.const nan:0x4000000000000) (f64.const nan:0x4000000000000)))
+(assert_return (invoke "sqrt" (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "sqrt" (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return_canonical_nan (invoke "sqrt" (f64.const -0x0.0000000000001p-1022)))
+(assert_return (invoke "sqrt" (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p-537))
+(assert_return_canonical_nan (invoke "sqrt" (f64.const -0x1p-1022)))
+(assert_return (invoke "sqrt" (f64.const 0x1p-1022)) (f64.const 0x1p-511))
+(assert_return_canonical_nan (invoke "sqrt" (f64.const -0x1p-1)))
+(assert_return (invoke "sqrt" (f64.const 0x1p-1)) (f64.const 0x1.6a09e667f3bcdp-1))
+(assert_return_canonical_nan (invoke "sqrt" (f64.const -0x1p+0)))
+(assert_return (invoke "sqrt" (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return_canonical_nan (invoke "sqrt" (f64.const -0x1.921fb54442d18p+2)))
+(assert_return (invoke "sqrt" (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.40d931ff62705p+1))
+(assert_return_canonical_nan (invoke "sqrt" (f64.const -0x1.fffffffffffffp+1023)))
+(assert_return (invoke "sqrt" (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+511))
+(assert_return_canonical_nan (invoke "sqrt" (f64.const -inf)))
+(assert_return (invoke "sqrt" (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "sqrt" (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "sqrt" (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "sqrt" (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "sqrt" (f64.const nan:0x4000000000000)))
+(assert_return (invoke "floor" (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "floor" (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "floor" (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "floor" (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "floor" (f64.const -0x1p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "floor" (f64.const 0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "floor" (f64.const -0x1p-1)) (f64.const -0x1p+0))
+(assert_return (invoke "floor" (f64.const 0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "floor" (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "floor" (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "floor" (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.cp+2))
+(assert_return (invoke "floor" (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.8p+2))
+(assert_return (invoke "floor" (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "floor" (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "floor" (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "floor" (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "floor" (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "floor" (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "floor" (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "floor" (f64.const nan:0x4000000000000)))
+(assert_return (invoke "ceil" (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "ceil" (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "ceil" (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "ceil" (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "ceil" (f64.const -0x1p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "ceil" (f64.const 0x1p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "ceil" (f64.const -0x1p-1)) (f64.const -0x0p+0))
+(assert_return (invoke "ceil" (f64.const 0x1p-1)) (f64.const 0x1p+0))
+(assert_return (invoke "ceil" (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "ceil" (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "ceil" (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.8p+2))
+(assert_return (invoke "ceil" (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.cp+2))
+(assert_return (invoke "ceil" (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "ceil" (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "ceil" (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "ceil" (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "ceil" (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "ceil" (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "ceil" (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "ceil" (f64.const nan:0x4000000000000)))
+(assert_return (invoke "trunc" (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "trunc" (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "trunc" (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "trunc" (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "trunc" (f64.const -0x1p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "trunc" (f64.const 0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "trunc" (f64.const -0x1p-1)) (f64.const -0x0p+0))
+(assert_return (invoke "trunc" (f64.const 0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "trunc" (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "trunc" (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "trunc" (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.8p+2))
+(assert_return (invoke "trunc" (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.8p+2))
+(assert_return (invoke "trunc" (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "trunc" (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "trunc" (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "trunc" (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "trunc" (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "trunc" (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "trunc" (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "trunc" (f64.const nan:0x4000000000000)))
+(assert_return (invoke "nearest" (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "nearest" (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "nearest" (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "nearest" (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "nearest" (f64.const -0x1p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "nearest" (f64.const 0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "nearest" (f64.const -0x1p-1)) (f64.const -0x0p+0))
+(assert_return (invoke "nearest" (f64.const 0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "nearest" (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "nearest" (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "nearest" (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.8p+2))
+(assert_return (invoke "nearest" (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.8p+2))
+(assert_return (invoke "nearest" (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "nearest" (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "nearest" (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "nearest" (f64.const inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "nearest" (f64.const -nan)))
+(assert_return_arithmetic_nan (invoke "nearest" (f64.const -nan:0x4000000000000)))
+(assert_return_canonical_nan (invoke "nearest" (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "nearest" (f64.const nan:0x4000000000000)))
+
+
+;; Type check
+
+(assert_invalid (module (func (result f64) (f64.add (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.div (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.max (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.min (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.mul (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.sub (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.ceil (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.floor (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.nearest (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.sqrt (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.trunc (i64.const 0)))) "type mismatch")
diff --git a/binaryen/test/spec/f64_bitwise.wast b/binaryen/test/spec/f64_bitwise.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/f64_bitwise.wast
@@ -0,0 +1,376 @@
+;; Test all the f64 bitwise operators on major boundary values and all special
+;; values.
+
+(module
+  (func (export "abs") (param $x f64) (result f64) (f64.abs (local.get $x)))
+  (func (export "neg") (param $x f64) (result f64) (f64.neg (local.get $x)))
+  (func (export "copysign") (param $x f64) (param $y f64) (result f64) (f64.copysign (local.get $x) (local.get $y)))
+)
+
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const -0x1p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const 0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const -0x1p-1022)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const 0x1p-1022)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const -0x1p-1)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const 0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const -0x1p-1)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const 0x1p-1)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const -0x1p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const 0x1p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const -0x1p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const 0x1p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const -inf)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const inf)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const -inf)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const inf)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const -nan)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0p+0) (f64.const nan)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const -nan)) (f64.const -0x0p+0))
+(assert_return (invoke "copysign" (f64.const 0x0p+0) (f64.const nan)) (f64.const 0x0p+0))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p+0)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p+0)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const -inf)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const inf)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const -inf)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const inf)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const -nan)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x0.0000000000001p-1022) (f64.const nan)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const -nan)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const 0x0.0000000000001p-1022) (f64.const nan)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const -0x0p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const 0x0p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const -0x0p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const 0x0p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const -0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const -0x1p-1)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const 0x1p-1)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const -0x1p-1)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const 0x1p-1)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const -0x1p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const 0x1p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const -0x1p+0)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const 0x1p+0)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const -inf)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const inf)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const -inf)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const inf)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const -nan)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1022) (f64.const nan)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const -nan)) (f64.const -0x1p-1022))
+(assert_return (invoke "copysign" (f64.const 0x1p-1022) (f64.const nan)) (f64.const 0x1p-1022))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const -0x0p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const 0x0p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const -0x0p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const 0x0p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const -0x1p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const 0x1p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const -0x1p-1022)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const 0x1p-1022)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const -0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const -0x1p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const 0x1p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const -0x1p+0)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const 0x1p+0)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const -inf)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const inf)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const -inf)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const inf)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const -nan)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p-1) (f64.const nan)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const -nan)) (f64.const -0x1p-1))
+(assert_return (invoke "copysign" (f64.const 0x1p-1) (f64.const nan)) (f64.const 0x1p-1))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const -0x0p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const 0x0p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const -0x0p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const 0x0p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const -0x1p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const 0x1p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const -0x1p-1022)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const 0x1p-1022)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const -0x1p-1)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const 0x1p-1)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const -0x1p-1)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const 0x1p-1)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const -0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const -inf)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const inf)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const -inf)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const inf)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const -nan)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1p+0) (f64.const nan)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const -nan)) (f64.const -0x1p+0))
+(assert_return (invoke "copysign" (f64.const 0x1p+0) (f64.const nan)) (f64.const 0x1p+0))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const -inf)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const inf)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const -inf)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const inf)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.921fb54442d18p+2) (f64.const nan)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const 0x1.921fb54442d18p+2) (f64.const nan)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const -inf)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const inf)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const -inf)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const inf)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const -0x0p+0)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const 0x0p+0)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const -0x0p+0)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const 0x0p+0)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const -0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const 0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const -0x0.0000000000001p-1022)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const 0x0.0000000000001p-1022)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const -0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const 0x1p-1022)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const -0x1p-1022)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const 0x1p-1022)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const -0x1p-1)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const 0x1p-1)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const -0x1p-1)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const 0x1p-1)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const -0x1p+0)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const 0x1p+0)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const -0x1p+0)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const 0x1p+0)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const -0x1.921fb54442d18p+2)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const 0x1.921fb54442d18p+2)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const -0x1.921fb54442d18p+2)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const 0x1.921fb54442d18p+2)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const 0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const 0x1.fffffffffffffp+1023)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const inf)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const -nan)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const -inf) (f64.const nan)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const -nan)) (f64.const -inf))
+(assert_return (invoke "copysign" (f64.const inf) (f64.const nan)) (f64.const inf))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const -0x0p+0)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const 0x0p+0)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const -0x0p+0)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const 0x0p+0)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const -0x0.0000000000001p-1022)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const 0x0.0000000000001p-1022)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const -0x0.0000000000001p-1022)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const 0x0.0000000000001p-1022)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const -0x1p-1022)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const 0x1p-1022)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const -0x1p-1022)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const 0x1p-1022)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const -0x1p-1)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const 0x1p-1)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const -0x1p-1)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const 0x1p-1)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const -0x1p+0)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const 0x1p+0)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const -0x1p+0)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const 0x1p+0)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const -0x1.921fb54442d18p+2)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const 0x1.921fb54442d18p+2)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const -0x1.921fb54442d18p+2)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const 0x1.921fb54442d18p+2)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const 0x1.fffffffffffffp+1023)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const -0x1.fffffffffffffp+1023)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const 0x1.fffffffffffffp+1023)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const -inf)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const inf)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const -inf)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const inf)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const -nan)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const -nan) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const -nan)) (f64.const -nan))
+(assert_return (invoke "copysign" (f64.const nan) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "abs" (f64.const -0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "abs" (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "abs" (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "abs" (f64.const 0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "abs" (f64.const -0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "abs" (f64.const 0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "abs" (f64.const -0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "abs" (f64.const 0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "abs" (f64.const -0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "abs" (f64.const 0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "abs" (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "abs" (f64.const 0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "abs" (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "abs" (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "abs" (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "abs" (f64.const inf)) (f64.const inf))
+(assert_return (invoke "abs" (f64.const -nan)) (f64.const nan))
+(assert_return (invoke "abs" (f64.const nan)) (f64.const nan))
+(assert_return (invoke "neg" (f64.const -0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "neg" (f64.const 0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "neg" (f64.const -0x0.0000000000001p-1022)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "neg" (f64.const 0x0.0000000000001p-1022)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "neg" (f64.const -0x1p-1022)) (f64.const 0x1p-1022))
+(assert_return (invoke "neg" (f64.const 0x1p-1022)) (f64.const -0x1p-1022))
+(assert_return (invoke "neg" (f64.const -0x1p-1)) (f64.const 0x1p-1))
+(assert_return (invoke "neg" (f64.const 0x1p-1)) (f64.const -0x1p-1))
+(assert_return (invoke "neg" (f64.const -0x1p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "neg" (f64.const 0x1p+0)) (f64.const -0x1p+0))
+(assert_return (invoke "neg" (f64.const -0x1.921fb54442d18p+2)) (f64.const 0x1.921fb54442d18p+2))
+(assert_return (invoke "neg" (f64.const 0x1.921fb54442d18p+2)) (f64.const -0x1.921fb54442d18p+2))
+(assert_return (invoke "neg" (f64.const -0x1.fffffffffffffp+1023)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "neg" (f64.const 0x1.fffffffffffffp+1023)) (f64.const -0x1.fffffffffffffp+1023))
+(assert_return (invoke "neg" (f64.const -inf)) (f64.const inf))
+(assert_return (invoke "neg" (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "neg" (f64.const -nan)) (f64.const nan))
+(assert_return (invoke "neg" (f64.const nan)) (f64.const -nan))
+
+
+;; Type check
+
+(assert_invalid (module (func (result f64) (f64.copysign (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.abs (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.neg (i64.const 0)))) "type mismatch")
diff --git a/binaryen/test/spec/f64_cmp.wast b/binaryen/test/spec/f64_cmp.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/f64_cmp.wast
@@ -0,0 +1,2422 @@
+;; Test all the f64 comparison operators on major boundary values and all
+;; special values.
+
+(module
+  (func (export "eq") (param $x f64) (param $y f64) (result i32) (f64.eq (local.get $x) (local.get $y)))
+  (func (export "ne") (param $x f64) (param $y f64) (result i32) (f64.ne (local.get $x) (local.get $y)))
+  (func (export "lt") (param $x f64) (param $y f64) (result i32) (f64.lt (local.get $x) (local.get $y)))
+  (func (export "le") (param $x f64) (param $y f64) (result i32) (f64.le (local.get $x) (local.get $y)))
+  (func (export "gt") (param $x f64) (param $y f64) (result i32) (f64.gt (local.get $x) (local.get $y)))
+  (func (export "ge") (param $x f64) (param $y f64) (result i32) (f64.ge (local.get $x) (local.get $y)))
+)
+
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p-1) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p-1) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -inf) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const inf) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const -nan:0x4000000000000) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (f64.const nan:0x4000000000000) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0p+0) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0p+0) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1022) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1022) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p-1) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p-1) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1p+0) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1p+0) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -inf) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const inf) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const -nan:0x4000000000000) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const -nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const -nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (f64.const nan:0x4000000000000) (f64.const nan:0x4000000000000)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p-1) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p-1) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const inf) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const inf) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const inf) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const inf) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const inf) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const inf) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const inf) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const inf) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const inf) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const inf) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const inf) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const inf) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const inf) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const inf) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "lt" (f64.const inf) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const inf) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -inf) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const inf) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const inf) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const inf) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const inf) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const -nan:0x4000000000000) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "lt" (f64.const nan:0x4000000000000) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p-1) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p-1) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -inf) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -inf) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const inf) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const inf) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -inf) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -inf) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const inf) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const inf) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -inf) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -inf) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "le" (f64.const inf) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const inf) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -inf) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -inf) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "le" (f64.const inf) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const inf) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -inf) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -inf) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "le" (f64.const inf) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const inf) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -inf) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -inf) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "le" (f64.const inf) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const inf) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -inf) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -inf) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "le" (f64.const inf) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const inf) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -inf) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -inf) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const inf) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const inf) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "le" (f64.const -inf) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -inf) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -inf) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -inf) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const inf) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const inf) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const inf) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const inf) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const -nan:0x4000000000000) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "le" (f64.const nan:0x4000000000000) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p-1) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p-1) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const inf) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const inf) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const inf) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const inf) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const inf) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const inf) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const inf) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const inf) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const inf) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const inf) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const inf) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const inf) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const inf) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const inf) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const inf) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "gt" (f64.const inf) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -inf) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const inf) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const inf) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const inf) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const inf) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const -nan:0x4000000000000) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "gt" (f64.const nan:0x4000000000000) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x0.0000000000001p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1022) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p-1) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p-1) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1p+0) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.921fb54442d18p+2) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const 0x1.fffffffffffffp+1023) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const inf) (f64.const -0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const inf) (f64.const 0x0p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const inf) (f64.const -0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const inf) (f64.const 0x0.0000000000001p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const inf) (f64.const -0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const inf) (f64.const 0x1p-1022)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const inf) (f64.const -0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const inf) (f64.const 0x1p-1)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const inf) (f64.const -0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const inf) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const inf) (f64.const -0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const inf) (f64.const 0x1.921fb54442d18p+2)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const inf) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const inf) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const inf) (f64.const -inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const inf) (f64.const inf)) (i32.const 1))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -inf) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const inf) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const inf) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const inf) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const inf) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const -0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const 0x0p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const -0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const 0x1p-1022)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const -0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const 0x1p-1)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const -0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const 0x1p+0)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const -0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const 0x1.921fb54442d18p+2)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const -0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const 0x1.fffffffffffffp+1023)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const -inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const inf)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const -nan:0x4000000000000) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const -nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const -nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan) (f64.const nan:0x4000000000000)) (i32.const 0))
+(assert_return (invoke "ge" (f64.const nan:0x4000000000000) (f64.const nan:0x4000000000000)) (i32.const 0))
+
+
+;; Type check
+
+(assert_invalid (module (func (result f64) (f64.eq (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.ge (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.gt (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.le (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.lt (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result f64) (f64.ne (i64.const 0) (f32.const 0)))) "type mismatch")
diff --git a/binaryen/test/spec/fac.wast b/binaryen/test/spec/fac.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/fac.wast
@@ -0,0 +1,89 @@
+(module
+  ;; Recursive factorial
+  (func (export "fac-rec") (param i64) (result i64)
+    (if (result i64) (i64.eq (local.get 0) (i64.const 0))
+      (then (i64.const 1))
+      (else
+        (i64.mul (local.get 0) (call 0 (i64.sub (local.get 0) (i64.const 1))))
+      )
+    )
+  )
+
+  ;; Recursive factorial named
+  (func $fac-rec-named (export "fac-rec-named") (param $n i64) (result i64)
+    (if (result i64) (i64.eq (local.get $n) (i64.const 0))
+      (then (i64.const 1))
+      (else
+        (i64.mul
+          (local.get $n)
+          (call $fac-rec-named (i64.sub (local.get $n) (i64.const 1)))
+        )
+      )
+    )
+  )
+
+  ;; Iterative factorial
+  (func (export "fac-iter") (param i64) (result i64)
+    (local i64 i64)
+    (local.set 1 (local.get 0))
+    (local.set 2 (i64.const 1))
+    (block
+      (loop
+        (if
+          (i64.eq (local.get 1) (i64.const 0))
+          (then (br 2))
+          (else
+            (local.set 2 (i64.mul (local.get 1) (local.get 2)))
+            (local.set 1 (i64.sub (local.get 1) (i64.const 1)))
+          )
+        )
+        (br 0)
+      )
+    )
+    (local.get 2)
+  )
+
+  ;; Iterative factorial named
+  (func (export "fac-iter-named") (param $n i64) (result i64)
+    (local $i i64)
+    (local $res i64)
+    (local.set $i (local.get $n))
+    (local.set $res (i64.const 1))
+    (block $done
+      (loop $loop
+        (if
+          (i64.eq (local.get $i) (i64.const 0))
+          (then (br $done))
+          (else
+            (local.set $res (i64.mul (local.get $i) (local.get $res)))
+            (local.set $i (i64.sub (local.get $i) (i64.const 1)))
+          )
+        )
+        (br $loop)
+      )
+    )
+    (local.get $res)
+  )
+
+  ;; Optimized factorial.
+  (func (export "fac-opt") (param i64) (result i64)
+    (local i64)
+    (local.set 1 (i64.const 1))
+    (block
+      (br_if 0 (i64.lt_s (local.get 0) (i64.const 2)))
+      (loop
+        (local.set 1 (i64.mul (local.get 1) (local.get 0)))
+        (local.set 0 (i64.add (local.get 0) (i64.const -1)))
+        (br_if 0 (i64.gt_s (local.get 0) (i64.const 1)))
+      )
+    )
+    (local.get 1)
+  )
+)
+
+(assert_return (invoke "fac-rec" (i64.const 25)) (i64.const 7034535277573963776))
+(assert_return (invoke "fac-iter" (i64.const 25)) (i64.const 7034535277573963776))
+(assert_return (invoke "fac-rec-named" (i64.const 25)) (i64.const 7034535277573963776))
+(assert_return (invoke "fac-iter-named" (i64.const 25)) (i64.const 7034535277573963776))
+(assert_return (invoke "fac-opt" (i64.const 25)) (i64.const 7034535277573963776))
+(assert_exhaustion (invoke "fac-rec" (i64.const 1073741824)) "call stack exhausted")
diff --git a/binaryen/test/spec/float_exprs.wast b/binaryen/test/spec/float_exprs.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/float_exprs.wast
@@ -0,0 +1,2570 @@
+;; Test interesting floating-point "expressions". These tests contain code
+;; patterns which tempt common value-changing optimizations.
+
+;; Test that x*y+z is not done with x87-style intermediate precision.
+
+(module
+  (func (export "f64.no_contraction") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.add (f64.mul (local.get $x) (local.get $y)) (local.get $z)))
+)
+
+(assert_return (invoke "f64.no_contraction" (f64.const -0x1.9e87ce14273afp-103) (f64.const 0x1.2515ad31db63ep+664) (f64.const 0x1.868c6685e6185p+533)) (f64.const -0x1.da94885b11493p+561))
+(assert_return (invoke "f64.no_contraction" (f64.const 0x1.da21c460a6f44p+52) (f64.const 0x1.60859d2e7714ap-321) (f64.const 0x1.e63f1b7b660e1p-302)) (f64.const 0x1.4672f256d1794p-268))
+(assert_return (invoke "f64.no_contraction" (f64.const -0x1.f3eaf43f327cp-594) (f64.const 0x1.dfcc009906b57p+533) (f64.const 0x1.5984e03c520a1p-104)) (f64.const -0x1.d4797fb3db166p-60))
+(assert_return (invoke "f64.no_contraction" (f64.const 0x1.dab6c772cb2e2p-69) (f64.const -0x1.d761663679a84p-101) (f64.const 0x1.f22f92c843226p-218)) (f64.const -0x1.b50d72dfcef68p-169))
+(assert_return (invoke "f64.no_contraction" (f64.const -0x1.87c5def1e4d3dp-950) (f64.const -0x1.50cd5dab2207fp+935) (f64.const 0x1.e629bd0da8c5dp-54)) (f64.const 0x1.01b6feb4e78a7p-14))
+
+;; Test that x*y+z is not folded to fma.
+
+(module
+  (func (export "f32.no_fma") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.add (f32.mul (local.get $x) (local.get $y)) (local.get $z)))
+  (func (export "f64.no_fma") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.add (f64.mul (local.get $x) (local.get $y)) (local.get $z)))
+)
+
+(assert_return (invoke "f32.no_fma" (f32.const 0x1.a78402p+124) (f32.const 0x1.cf8548p-23) (f32.const 0x1.992adap+107)) (f32.const 0x1.a5262cp+107))
+(assert_return (invoke "f32.no_fma" (f32.const 0x1.ed15a4p-28) (f32.const -0x1.613c72p-50) (f32.const 0x1.4757bp-88)) (f32.const -0x1.5406b8p-77))
+(assert_return (invoke "f32.no_fma" (f32.const 0x1.ae63a2p+37) (f32.const 0x1.b3a59ap-13) (f32.const 0x1.c16918p+10)) (f32.const 0x1.6e385cp+25))
+(assert_return (invoke "f32.no_fma" (f32.const 0x1.2a77fap-8) (f32.const -0x1.bb7356p+22) (f32.const -0x1.32be2ap+1)) (f32.const -0x1.0286d4p+15))
+(assert_return (invoke "f32.no_fma" (f32.const 0x1.298fb6p+126) (f32.const -0x1.03080cp-70) (f32.const -0x1.418de6p+34)) (f32.const -0x1.2d15c6p+56))
+(assert_return (invoke "f64.no_fma" (f64.const 0x1.ac357ff46eed4p+557) (f64.const 0x1.852c01a5e7297p+430) (f64.const -0x1.05995704eda8ap+987)) (f64.const 0x1.855d905d338ep+987))
+(assert_return (invoke "f64.no_fma" (f64.const 0x1.e2fd6bf32010cp+749) (f64.const 0x1.01c2238d405e4p-130) (f64.const 0x1.2ecc0db4b9f94p+573)) (f64.const 0x1.e64eb07e063bcp+619))
+(assert_return (invoke "f64.no_fma" (f64.const 0x1.92b7c7439ede3p-721) (f64.const -0x1.6aa97586d3de6p+1011) (f64.const 0x1.8de4823f6358ap+237)) (f64.const -0x1.1d4139fd20ecdp+291))
+(assert_return (invoke "f64.no_fma" (f64.const -0x1.466d30bddb453p-386) (f64.const -0x1.185a4d739c7aap+443) (f64.const 0x1.5f9c436fbfc7bp+55)) (f64.const 0x1.bd61a350fcc1ap+57))
+(assert_return (invoke "f64.no_fma" (f64.const 0x1.7e2c44058a799p+52) (f64.const 0x1.c73b71765b8b2p+685) (f64.const -0x1.16c641df0b108p+690)) (f64.const 0x1.53ccb53de0bd1p+738))
+
+;; Test that x+0.0 is not folded to x.
+;; See IEEE 754-2008 10.4 "Literal meaning and value-changing optimizations".
+
+(module
+  (func (export "f32.no_fold_add_zero") (param $x f32) (result f32)
+    (f32.add (local.get $x) (f32.const 0.0)))
+  (func (export "f64.no_fold_add_zero") (param $x f64) (result f64)
+    (f64.add (local.get $x) (f64.const 0.0)))
+)
+
+(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_arithmetic_nan (invoke "f32.no_fold_add_zero" (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "f64.no_fold_add_zero" (f64.const nan:0x4000000000000)))
+
+;; Test that 0.0 - x is not folded to -x.
+
+(module
+  (func (export "f32.no_fold_zero_sub") (param $x f32) (result f32)
+    (f32.sub (f32.const 0.0) (local.get $x)))
+  (func (export "f64.no_fold_zero_sub") (param $x f64) (result f64)
+    (f64.sub (f64.const 0.0) (local.get $x)))
+)
+
+(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_arithmetic_nan (invoke "f32.no_fold_zero_sub" (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "f64.no_fold_zero_sub" (f64.const nan:0x4000000000000)))
+
+;; Test that x - 0.0 is not folded to x.
+
+(module
+  (func (export "f32.no_fold_sub_zero") (param $x f32) (result f32)
+    (f32.sub (local.get $x) (f32.const 0.0)))
+  (func (export "f64.no_fold_sub_zero") (param $x f64) (result f64)
+    (f64.sub (local.get $x) (f64.const 0.0)))
+)
+
+(assert_return_arithmetic_nan (invoke "f32.no_fold_sub_zero" (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "f64.no_fold_sub_zero" (f64.const nan:0x4000000000000)))
+
+;; Test that x*0.0 is not folded to 0.0.
+
+(module
+  (func (export "f32.no_fold_mul_zero") (param $x f32) (result f32)
+    (f32.mul (local.get $x) (f32.const 0.0)))
+  (func (export "f64.no_fold_mul_zero") (param $x f64) (result f64)
+    (f64.mul (local.get $x) (f64.const 0.0)))
+)
+
+(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_arithmetic_nan (invoke "f32.no_fold_mul_zero" (f32.const nan:0x200000)))
+(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_arithmetic_nan (invoke "f64.no_fold_mul_zero" (f64.const nan:0x4000000000000)))
+
+;; Test that x*1.0 is not folded to x.
+;; See IEEE 754-2008 10.4 "Literal meaning and value-changing optimizations".
+
+(module
+  (func (export "f32.no_fold_mul_one") (param $x f32) (result f32)
+    (f32.mul (local.get $x) (f32.const 1.0)))
+  (func (export "f64.no_fold_mul_one") (param $x f64) (result f64)
+    (f64.mul (local.get $x) (f64.const 1.0)))
+)
+
+(assert_return_arithmetic_nan (invoke "f32.no_fold_mul_one" (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "f64.no_fold_mul_one" (f64.const nan:0x4000000000000)))
+
+;; Test that 0.0/x is not folded to 0.0.
+
+(module
+  (func (export "f32.no_fold_zero_div") (param $x f32) (result f32)
+    (f32.div (f32.const 0.0) (local.get $x)))
+  (func (export "f64.no_fold_zero_div") (param $x f64) (result f64)
+    (f64.div (f64.const 0.0) (local.get $x)))
+)
+
+(assert_return_canonical_nan (invoke "f32.no_fold_zero_div" (f32.const 0.0)))
+(assert_return_canonical_nan (invoke "f32.no_fold_zero_div" (f32.const -0.0)))
+(assert_return_canonical_nan (invoke "f32.no_fold_zero_div" (f32.const nan)))
+(assert_return_arithmetic_nan (invoke "f32.no_fold_zero_div" (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "f64.no_fold_zero_div" (f64.const 0.0)))
+(assert_return_canonical_nan (invoke "f64.no_fold_zero_div" (f64.const -0.0)))
+(assert_return_canonical_nan (invoke "f64.no_fold_zero_div" (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "f64.no_fold_zero_div" (f64.const nan:0x4000000000000)))
+
+;; Test that x/1.0 is not folded to x.
+
+(module
+  (func (export "f32.no_fold_div_one") (param $x f32) (result f32)
+    (f32.div (local.get $x) (f32.const 1.0)))
+  (func (export "f64.no_fold_div_one") (param $x f64) (result f64)
+    (f64.div (local.get $x) (f64.const 1.0)))
+)
+
+(assert_return_arithmetic_nan (invoke "f32.no_fold_div_one" (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "f64.no_fold_div_one" (f64.const nan:0x4000000000000)))
+
+;; Test that x/-1.0 is not folded to -x.
+
+(module
+  (func (export "f32.no_fold_div_neg1") (param $x f32) (result f32)
+    (f32.div (local.get $x) (f32.const -1.0)))
+  (func (export "f64.no_fold_div_neg1") (param $x f64) (result f64)
+    (f64.div (local.get $x) (f64.const -1.0)))
+)
+
+(assert_return_arithmetic_nan (invoke "f32.no_fold_div_neg1" (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "f64.no_fold_div_neg1" (f64.const nan:0x4000000000000)))
+
+;; Test that -0.0 - x is not folded to -x.
+
+(module
+  (func (export "f32.no_fold_neg0_sub") (param $x f32) (result f32)
+    (f32.sub (f32.const -0.0) (local.get $x)))
+  (func (export "f64.no_fold_neg0_sub") (param $x f64) (result f64)
+    (f64.sub (f64.const -0.0) (local.get $x)))
+)
+
+(assert_return_arithmetic_nan (invoke "f32.no_fold_neg0_sub" (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "f64.no_fold_neg0_sub" (f64.const nan:0x4000000000000)))
+
+;; Test that -1.0 * x is not folded to -x.
+
+(module
+  (func (export "f32.no_fold_neg1_mul") (param $x f32) (result f32)
+    (f32.mul (f32.const -1.0) (local.get $x)))
+  (func (export "f64.no_fold_neg1_mul") (param $x f64) (result f64)
+    (f64.mul (f64.const -1.0) (local.get $x)))
+)
+
+(assert_return_arithmetic_nan (invoke "f32.no_fold_neg1_mul" (f32.const nan:0x200000)))
+(assert_return_arithmetic_nan (invoke "f64.no_fold_neg1_mul" (f64.const nan:0x4000000000000)))
+
+;; Test that x == x is not folded to true.
+
+(module
+  (func (export "f32.no_fold_eq_self") (param $x f32) (result i32)
+    (f32.eq (local.get $x) (local.get $x)))
+  (func (export "f64.no_fold_eq_self") (param $x f64) (result i32)
+    (f64.eq (local.get $x) (local.get $x)))
+)
+
+(assert_return (invoke "f32.no_fold_eq_self" (f32.const nan)) (i32.const 0))
+(assert_return (invoke "f64.no_fold_eq_self" (f64.const nan)) (i32.const 0))
+
+;; Test that x != x is not folded to false.
+
+(module
+  (func (export "f32.no_fold_ne_self") (param $x f32) (result i32)
+    (f32.ne (local.get $x) (local.get $x)))
+  (func (export "f64.no_fold_ne_self") (param $x f64) (result i32)
+    (f64.ne (local.get $x) (local.get $x)))
+)
+
+(assert_return (invoke "f32.no_fold_ne_self" (f32.const nan)) (i32.const 1))
+(assert_return (invoke "f64.no_fold_ne_self" (f64.const nan)) (i32.const 1))
+
+;; Test that x - x is not folded to 0.0.
+
+(module
+  (func (export "f32.no_fold_sub_self") (param $x f32) (result f32)
+    (f32.sub (local.get $x) (local.get $x)))
+  (func (export "f64.no_fold_sub_self") (param $x f64) (result f64)
+    (f64.sub (local.get $x) (local.get $x)))
+)
+
+(assert_return_canonical_nan (invoke "f32.no_fold_sub_self" (f32.const inf)))
+(assert_return_canonical_nan (invoke "f32.no_fold_sub_self" (f32.const nan)))
+(assert_return_canonical_nan (invoke "f64.no_fold_sub_self" (f64.const inf)))
+(assert_return_canonical_nan (invoke "f64.no_fold_sub_self" (f64.const nan)))
+
+;; Test that x / x is not folded to 1.0.
+
+(module
+  (func (export "f32.no_fold_div_self") (param $x f32) (result f32)
+    (f32.div (local.get $x) (local.get $x)))
+  (func (export "f64.no_fold_div_self") (param $x f64) (result f64)
+    (f64.div (local.get $x) (local.get $x)))
+)
+
+(assert_return_canonical_nan (invoke "f32.no_fold_div_self" (f32.const inf)))
+(assert_return_canonical_nan (invoke "f32.no_fold_div_self" (f32.const nan)))
+(assert_return_canonical_nan (invoke "f32.no_fold_div_self" (f32.const 0.0)))
+(assert_return_canonical_nan (invoke "f32.no_fold_div_self" (f32.const -0.0)))
+(assert_return_canonical_nan (invoke "f64.no_fold_div_self" (f64.const inf)))
+(assert_return_canonical_nan (invoke "f64.no_fold_div_self" (f64.const nan)))
+(assert_return_canonical_nan (invoke "f64.no_fold_div_self" (f64.const 0.0)))
+(assert_return_canonical_nan (invoke "f64.no_fold_div_self" (f64.const -0.0)))
+
+;; Test that x/3 is not folded to x*(1/3).
+
+(module
+  (func (export "f32.no_fold_div_3") (param $x f32) (result f32)
+    (f32.div (local.get $x) (f32.const 3.0)))
+  (func (export "f64.no_fold_div_3") (param $x f64) (result f64)
+    (f64.div (local.get $x) (f64.const 3.0)))
+)
+
+(assert_return (invoke "f32.no_fold_div_3" (f32.const -0x1.359c26p+50)) (f32.const -0x1.9cd032p+48))
+(assert_return (invoke "f32.no_fold_div_3" (f32.const -0x1.e45646p+93)) (f32.const -0x1.42e42ep+92))
+(assert_return (invoke "f32.no_fold_div_3" (f32.const -0x1.2a3916p-83)) (f32.const -0x1.8da172p-85))
+(assert_return (invoke "f32.no_fold_div_3" (f32.const -0x1.1f8b38p-124)) (f32.const -0x1.7f644ap-126))
+(assert_return (invoke "f32.no_fold_div_3" (f32.const -0x1.d64f64p-56)) (f32.const -0x1.398a42p-57))
+(assert_return (invoke "f64.no_fold_div_3" (f64.const -0x1.a8a88d29e2cc3p+632)) (f64.const -0x1.1b1b08c69732dp+631))
+(assert_return (invoke "f64.no_fold_div_3" (f64.const -0x1.bcf52dc950972p-167)) (f64.const -0x1.28a373db8b0f7p-168))
+(assert_return (invoke "f64.no_fold_div_3" (f64.const 0x1.bd3c0d989f7a4p-874)) (f64.const 0x1.28d2b3bb14fc3p-875))
+(assert_return (invoke "f64.no_fold_div_3" (f64.const -0x1.0138bf530a53cp+1007)) (f64.const -0x1.56f6546eb86fbp+1005))
+(assert_return (invoke "f64.no_fold_div_3" (f64.const 0x1.052b87f9d794dp+415)) (f64.const 0x1.5c3a0aa274c67p+413))
+
+;; Test that (x*z)+(y*z) is not folded to (x+y)*z.
+
+(module
+  (func (export "f32.no_factor") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.add (f32.mul (local.get $x) (local.get $z)) (f32.mul (local.get $y) (local.get $z))))
+  (func (export "f64.no_factor") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.add (f64.mul (local.get $x) (local.get $z)) (f64.mul (local.get $y) (local.get $z))))
+)
+
+(assert_return (invoke "f32.no_factor" (f32.const -0x1.4e2352p+40) (f32.const -0x1.842e2cp+49) (f32.const 0x1.eea602p+59)) (f32.const -0x1.77a7dp+109))
+(assert_return (invoke "f32.no_factor" (f32.const -0x1.b4e7f6p-6) (f32.const 0x1.8c990cp-5) (f32.const -0x1.70cc02p-9)) (f32.const -0x1.00a342p-14))
+(assert_return (invoke "f32.no_factor" (f32.const -0x1.06722ep-41) (f32.const 0x1.eed3cep-64) (f32.const 0x1.5c5558p+123)) (f32.const -0x1.651aaep+82))
+(assert_return (invoke "f32.no_factor" (f32.const -0x1.f8c6a4p-64) (f32.const 0x1.08c806p-83) (f32.const 0x1.b5ceccp+118)) (f32.const -0x1.afa15p+55))
+(assert_return (invoke "f32.no_factor" (f32.const -0x1.3aaa1ep-84) (f32.const 0x1.c6d5eep-71) (f32.const 0x1.8d2924p+20)) (f32.const 0x1.60c9cep-50))
+(assert_return (invoke "f64.no_factor" (f64.const 0x1.3adeda9144977p-424) (f64.const 0x1.c15af887049e1p-462) (f64.const -0x1.905179c4c4778p-225)) (f64.const -0x1.ec606bcb87b1ap-649))
+(assert_return (invoke "f64.no_factor" (f64.const 0x1.3c84821c1d348p-662) (f64.const -0x1.4ffd4c77ad037p-1009) (f64.const -0x1.dd275335c6f4p-957)) (f64.const 0x0p+0))
+(assert_return (invoke "f64.no_factor" (f64.const -0x1.074f372347051p-334) (f64.const -0x1.aaeef661f4c96p-282) (f64.const -0x1.9bd34abe8696dp+479)) (f64.const 0x1.5767029593e2p+198))
+(assert_return (invoke "f64.no_factor" (f64.const -0x1.c4ded58a6f389p-289) (f64.const 0x1.ba6fdef5d59c9p-260) (f64.const -0x1.c1201c0470205p-253)) (f64.const -0x1.841ada2e0f184p-512))
+(assert_return (invoke "f64.no_factor" (f64.const 0x1.9d3688f8e375ap-608) (f64.const 0x1.bf91311588256p-579) (f64.const -0x1.1605a6b5d5ff8p+489)) (f64.const -0x1.e6118ca76af53p-90))
+
+;; Test that (x+y)*z is not folded to (x*z)+(y*z).
+
+(module
+  (func (export "f32.no_distribute") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.mul (f32.add (local.get $x) (local.get $y)) (local.get $z)))
+  (func (export "f64.no_distribute") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.mul (f64.add (local.get $x) (local.get $y)) (local.get $z)))
+)
+
+(assert_return (invoke "f32.no_distribute" (f32.const -0x1.4e2352p+40) (f32.const -0x1.842e2cp+49) (f32.const 0x1.eea602p+59)) (f32.const -0x1.77a7d2p+109))
+(assert_return (invoke "f32.no_distribute" (f32.const -0x1.b4e7f6p-6) (f32.const 0x1.8c990cp-5) (f32.const -0x1.70cc02p-9)) (f32.const -0x1.00a34p-14))
+(assert_return (invoke "f32.no_distribute" (f32.const -0x1.06722ep-41) (f32.const 0x1.eed3cep-64) (f32.const 0x1.5c5558p+123)) (f32.const -0x1.651abp+82))
+(assert_return (invoke "f32.no_distribute" (f32.const -0x1.f8c6a4p-64) (f32.const 0x1.08c806p-83) (f32.const 0x1.b5ceccp+118)) (f32.const -0x1.afa14ep+55))
+(assert_return (invoke "f32.no_distribute" (f32.const -0x1.3aaa1ep-84) (f32.const 0x1.c6d5eep-71) (f32.const 0x1.8d2924p+20)) (f32.const 0x1.60c9ccp-50))
+(assert_return (invoke "f64.no_distribute" (f64.const 0x1.3adeda9144977p-424) (f64.const 0x1.c15af887049e1p-462) (f64.const -0x1.905179c4c4778p-225)) (f64.const -0x1.ec606bcb87b1bp-649))
+(assert_return (invoke "f64.no_distribute" (f64.const 0x1.3c84821c1d348p-662) (f64.const -0x1.4ffd4c77ad037p-1009) (f64.const -0x1.dd275335c6f4p-957)) (f64.const -0x0p+0))
+(assert_return (invoke "f64.no_distribute" (f64.const -0x1.074f372347051p-334) (f64.const -0x1.aaeef661f4c96p-282) (f64.const -0x1.9bd34abe8696dp+479)) (f64.const 0x1.5767029593e1fp+198))
+(assert_return (invoke "f64.no_distribute" (f64.const -0x1.c4ded58a6f389p-289) (f64.const 0x1.ba6fdef5d59c9p-260) (f64.const -0x1.c1201c0470205p-253)) (f64.const -0x1.841ada2e0f183p-512))
+(assert_return (invoke "f64.no_distribute" (f64.const 0x1.9d3688f8e375ap-608) (f64.const 0x1.bf91311588256p-579) (f64.const -0x1.1605a6b5d5ff8p+489)) (f64.const -0x1.e6118ca76af52p-90))
+
+;; Test that x*(y/z) is not folded to (x*y)/z.
+
+(module
+  (func (export "f32.no_regroup_div_mul") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.mul (local.get $x) (f32.div (local.get $y) (local.get $z))))
+  (func (export "f64.no_regroup_div_mul") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.mul (local.get $x) (f64.div (local.get $y) (local.get $z))))
+)
+
+(assert_return (invoke "f32.no_regroup_div_mul" (f32.const -0x1.2d14a6p-115) (f32.const -0x1.575a6cp-64) (f32.const 0x1.5cee0ep-116)) (f32.const 0x1.2844cap-63))
+(assert_return (invoke "f32.no_regroup_div_mul" (f32.const -0x1.454738p+91) (f32.const -0x1.b28a66p-115) (f32.const -0x1.f53908p+72)) (f32.const -0x0p+0))
+(assert_return (invoke "f32.no_regroup_div_mul" (f32.const -0x1.6be56ep+16) (f32.const -0x1.b46fc6p-21) (f32.const -0x1.a51df6p-123)) (f32.const -0x1.792258p+118))
+(assert_return (invoke "f32.no_regroup_div_mul" (f32.const -0x1.c343f8p-94) (f32.const 0x1.e4d906p+73) (f32.const 0x1.be69f8p+68)) (f32.const -0x1.ea1df2p-89))
+(assert_return (invoke "f32.no_regroup_div_mul" (f32.const 0x1.c6ae76p+112) (f32.const 0x1.fc953cp+24) (f32.const -0x1.60b3e8p+71)) (f32.const -0x1.47d0eap+66))
+(assert_return (invoke "f64.no_regroup_div_mul" (f64.const 0x1.3c04b815e30bp-423) (f64.const -0x1.379646fd98127p-119) (f64.const 0x1.bddb158506031p-642)) (f64.const -0x1.b9b3301f2dd2dp+99))
+(assert_return (invoke "f64.no_regroup_div_mul" (f64.const 0x1.46b3a402f86d5p+337) (f64.const 0x1.6fbf1b9e1798dp-447) (f64.const -0x1.bd9704a5a6a06p+797)) (f64.const -0x0p+0))
+(assert_return (invoke "f64.no_regroup_div_mul" (f64.const 0x1.6c9765bb4347fp-479) (f64.const 0x1.a4af42e34a141p+902) (f64.const 0x1.d2dde70eb68f9p-448)) (f64.const inf))
+(assert_return (invoke "f64.no_regroup_div_mul" (f64.const -0x1.706023645be72p+480) (f64.const -0x1.6c229f7d9101dp+611) (f64.const -0x1.4d50fa68d3d9ep+836)) (f64.const -0x1.926fa3cacc651p+255))
+(assert_return (invoke "f64.no_regroup_div_mul" (f64.const 0x1.8cc63d8caf4c7p-599) (f64.const 0x1.8671ac4c35753p-878) (f64.const -0x1.ef35b1695e659p-838)) (f64.const -0x1.38d55f56406dp-639))
+
+;; Test that (x*y)/z is not folded to x*(y/z).
+
+(module
+  (func (export "f32.no_regroup_mul_div") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.div (f32.mul (local.get $x) (local.get $y)) (local.get $z)))
+  (func (export "f64.no_regroup_mul_div") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.div (f64.mul (local.get $x) (local.get $y)) (local.get $z)))
+)
+
+(assert_return (invoke "f32.no_regroup_mul_div" (f32.const -0x1.2d14a6p-115) (f32.const -0x1.575a6cp-64) (f32.const 0x1.5cee0ep-116)) (f32.const 0x0p+0))
+(assert_return (invoke "f32.no_regroup_mul_div" (f32.const -0x1.454738p+91) (f32.const -0x1.b28a66p-115) (f32.const -0x1.f53908p+72)) (f32.const -0x1.1a00e8p-96))
+(assert_return (invoke "f32.no_regroup_mul_div" (f32.const -0x1.6be56ep+16) (f32.const -0x1.b46fc6p-21) (f32.const -0x1.a51df6p-123)) (f32.const -0x1.79225ap+118))
+(assert_return (invoke "f32.no_regroup_mul_div" (f32.const -0x1.c343f8p-94) (f32.const 0x1.e4d906p+73) (f32.const 0x1.be69f8p+68)) (f32.const -0x1.ea1df4p-89))
+(assert_return (invoke "f32.no_regroup_mul_div" (f32.const 0x1.c6ae76p+112) (f32.const 0x1.fc953cp+24) (f32.const -0x1.60b3e8p+71)) (f32.const -inf))
+(assert_return (invoke "f64.no_regroup_mul_div" (f64.const 0x1.3c04b815e30bp-423) (f64.const -0x1.379646fd98127p-119) (f64.const 0x1.bddb158506031p-642)) (f64.const -0x1.b9b3301f2dd2ep+99))
+(assert_return (invoke "f64.no_regroup_mul_div" (f64.const 0x1.46b3a402f86d5p+337) (f64.const 0x1.6fbf1b9e1798dp-447) (f64.const -0x1.bd9704a5a6a06p+797)) (f64.const -0x1.0da0b6328e09p-907))
+(assert_return (invoke "f64.no_regroup_mul_div" (f64.const 0x1.6c9765bb4347fp-479) (f64.const 0x1.a4af42e34a141p+902) (f64.const 0x1.d2dde70eb68f9p-448)) (f64.const 0x1.4886b6d9a9a79p+871))
+(assert_return (invoke "f64.no_regroup_mul_div" (f64.const -0x1.706023645be72p+480) (f64.const -0x1.6c229f7d9101dp+611) (f64.const -0x1.4d50fa68d3d9ep+836)) (f64.const -inf))
+(assert_return (invoke "f64.no_regroup_mul_div" (f64.const 0x1.8cc63d8caf4c7p-599) (f64.const 0x1.8671ac4c35753p-878) (f64.const -0x1.ef35b1695e659p-838)) (f64.const -0x0p+0))
+
+;; Test that x+y+z+w is not reassociated.
+
+(module
+  (func (export "f32.no_reassociate_add") (param $x f32) (param $y f32) (param $z f32) (param $w f32) (result f32)
+    (f32.add (f32.add (f32.add (local.get $x) (local.get $y)) (local.get $z)) (local.get $w)))
+  (func (export "f64.no_reassociate_add") (param $x f64) (param $y f64) (param $z f64) (param $w f64) (result f64)
+    (f64.add (f64.add (f64.add (local.get $x) (local.get $y)) (local.get $z)) (local.get $w)))
+)
+
+(assert_return (invoke "f32.no_reassociate_add" (f32.const -0x1.5f7ddcp+44) (f32.const 0x1.854e1p+34) (f32.const -0x1.b2068cp+47) (f32.const -0x1.209692p+41)) (f32.const -0x1.e26c76p+47))
+(assert_return (invoke "f32.no_reassociate_add" (f32.const 0x1.da3b78p-9) (f32.const -0x1.4312fap-7) (f32.const 0x1.0395e6p-4) (f32.const -0x1.6d5ea6p-7)) (f32.const 0x1.78b31ap-5))
+(assert_return (invoke "f32.no_reassociate_add" (f32.const -0x1.fdb93ap+34) (f32.const -0x1.b6fce6p+41) (f32.const 0x1.c131d8p+44) (f32.const 0x1.8835b6p+38)) (f32.const 0x1.8ff3a2p+44))
+(assert_return (invoke "f32.no_reassociate_add" (f32.const 0x1.1739fcp+47) (f32.const 0x1.a4b186p+49) (f32.const -0x1.0c623cp+35) (f32.const 0x1.16a102p+51)) (f32.const 0x1.913ff6p+51))
+(assert_return (invoke "f32.no_reassociate_add" (f32.const 0x1.733cfap+108) (f32.const -0x1.38d30cp+108) (f32.const 0x1.2f5854p+105) (f32.const -0x1.ccb058p+94)) (f32.const 0x1.813716p+106))
+(assert_return (invoke "f64.no_reassociate_add" (f64.const -0x1.697a4d9ff19a6p+841) (f64.const 0x1.b305466238397p+847) (f64.const 0x1.e0b2d9bfb4e72p+855) (f64.const -0x1.6e1f3ae2b06bbp+857)) (f64.const -0x1.eb0e5936f087ap+856))
+(assert_return (invoke "f64.no_reassociate_add" (f64.const 0x1.00ef6746b30e1p-543) (f64.const 0x1.cc1cfafdf3fe1p-544) (f64.const -0x1.f7726df3ecba6p-543) (f64.const -0x1.b26695f99d307p-594)) (f64.const -0x1.074892e3fad76p-547))
+(assert_return (invoke "f64.no_reassociate_add" (f64.const -0x1.e807b3bd6d854p+440) (f64.const 0x1.cedae26c2c5fp+407) (f64.const -0x1.00ab6e1442541p+437) (f64.const 0x1.28538a55997bdp+397)) (f64.const -0x1.040e90bf871ebp+441))
+(assert_return (invoke "f64.no_reassociate_add" (f64.const -0x1.ba2b6f35a2402p-317) (f64.const 0x1.ad1c3fea7cd9ep-307) (f64.const -0x1.93aace2bf1261p-262) (f64.const 0x1.9fddbe472847ep-260)) (f64.const 0x1.3af30abc2c01bp-260))
+(assert_return (invoke "f64.no_reassociate_add" (f64.const -0x1.ccb9c6092fb1dp+641) (f64.const -0x1.4b7c28c108244p+614) (f64.const 0x1.8a7cefef4bde1p+646) (f64.const -0x1.901b28b08b482p+644)) (f64.const 0x1.1810579194126p+646))
+
+;; Test that x*y*z*w is not reassociated.
+
+(module
+  (func (export "f32.no_reassociate_mul") (param $x f32) (param $y f32) (param $z f32) (param $w f32) (result f32)
+    (f32.mul (f32.mul (f32.mul (local.get $x) (local.get $y)) (local.get $z)) (local.get $w)))
+  (func (export "f64.no_reassociate_mul") (param $x f64) (param $y f64) (param $z f64) (param $w f64) (result f64)
+    (f64.mul (f64.mul (f64.mul (local.get $x) (local.get $y)) (local.get $z)) (local.get $w)))
+)
+
+(assert_return (invoke "f32.no_reassociate_mul" (f32.const 0x1.950ba8p-116) (f32.const 0x1.efdacep-33) (f32.const -0x1.5f9bcp+102) (f32.const 0x1.f04508p-56)) (f32.const -0x1.ff356ep-101))
+(assert_return (invoke "f32.no_reassociate_mul" (f32.const 0x1.5990aep-56) (f32.const -0x1.7dfb04p+102) (f32.const -0x1.4f774ap-125) (f32.const -0x1.595fe6p+70)) (f32.const -0x1.c7c8fcp-8))
+(assert_return (invoke "f32.no_reassociate_mul" (f32.const 0x1.6ad9a4p-48) (f32.const -0x1.9138aap+55) (f32.const -0x1.4a774ep-40) (f32.const 0x1.1ff08p+76)) (f32.const 0x1.9cd8ecp+44))
+(assert_return (invoke "f32.no_reassociate_mul" (f32.const 0x1.e1caecp-105) (f32.const 0x1.af0dd2p+77) (f32.const -0x1.016eep+56) (f32.const -0x1.ab70d6p+59)) (f32.const 0x1.54870ep+89))
+(assert_return (invoke "f32.no_reassociate_mul" (f32.const -0x1.3b1dcp-99) (f32.const 0x1.4e5a34p-49) (f32.const -0x1.38ba5ap+3) (f32.const 0x1.7fb8eep+59)) (f32.const 0x1.5bbf98p-85))
+(assert_return (invoke "f64.no_reassociate_mul" (f64.const -0x1.e7842ab7181p-667) (f64.const -0x1.fabf40ceeceafp+990) (f64.const -0x1.1a38a825ab01ap-376) (f64.const -0x1.27e8ea469b14fp+664)) (f64.const 0x1.336eb428af4f3p+613))
+(assert_return (invoke "f64.no_reassociate_mul" (f64.const 0x1.4ca2292a6acbcp+454) (f64.const 0x1.6ffbab850089ap-516) (f64.const -0x1.547c32e1f5b93p-899) (f64.const -0x1.c7571d9388375p+540)) (f64.const 0x1.1ac796954fc1p-419))
+(assert_return (invoke "f64.no_reassociate_mul" (f64.const 0x1.73881a52e0401p-501) (f64.const -0x1.1b68dd9efb1a7p+788) (f64.const 0x1.d1c5e6a3eb27cp-762) (f64.const -0x1.56cb2fcc7546fp+88)) (f64.const 0x1.f508db92c34efp-386))
+(assert_return (invoke "f64.no_reassociate_mul" (f64.const 0x1.2efa87859987cp+692) (f64.const 0x1.68e4373e241p-423) (f64.const 0x1.4e2d0fb383a57p+223) (f64.const -0x1.301d3265c737bp-23)) (f64.const -0x1.4b2b6c393f30cp+470))
+(assert_return (invoke "f64.no_reassociate_mul" (f64.const 0x1.1013f7498b95fp-234) (f64.const 0x1.d2d1c36fff138p-792) (f64.const -0x1.cbf1824ea7bfdp+728) (f64.const -0x1.440da9c8b836dp-599)) (f64.const 0x1.1a16512881c91p-895))
+
+;; Test that x/0 is not folded away.
+
+(module
+  (func (export "f32.no_fold_div_0") (param $x f32) (result f32)
+    (f32.div (local.get $x) (f32.const 0.0)))
+  (func (export "f64.no_fold_div_0") (param $x f64) (result f64)
+    (f64.div (local.get $x) (f64.const 0.0)))
+)
+
+(assert_return (invoke "f32.no_fold_div_0" (f32.const 1.0)) (f32.const inf))
+(assert_return (invoke "f32.no_fold_div_0" (f32.const -1.0)) (f32.const -inf))
+(assert_return (invoke "f32.no_fold_div_0" (f32.const inf)) (f32.const inf))
+(assert_return (invoke "f32.no_fold_div_0" (f32.const -inf)) (f32.const -inf))
+(assert_return_canonical_nan (invoke "f32.no_fold_div_0" (f32.const 0)))
+(assert_return_canonical_nan (invoke "f32.no_fold_div_0" (f32.const -0)))
+(assert_return_arithmetic_nan (invoke "f32.no_fold_div_0" (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "f32.no_fold_div_0" (f32.const nan)))
+(assert_return (invoke "f64.no_fold_div_0" (f64.const 1.0)) (f64.const inf))
+(assert_return (invoke "f64.no_fold_div_0" (f64.const -1.0)) (f64.const -inf))
+(assert_return (invoke "f64.no_fold_div_0" (f64.const inf)) (f64.const inf))
+(assert_return (invoke "f64.no_fold_div_0" (f64.const -inf)) (f64.const -inf))
+(assert_return_canonical_nan (invoke "f64.no_fold_div_0" (f64.const 0)))
+(assert_return_canonical_nan (invoke "f64.no_fold_div_0" (f64.const -0)))
+(assert_return_canonical_nan (invoke "f64.no_fold_div_0" (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "f64.no_fold_div_0" (f64.const nan:0x4000000000000)))
+
+;; Test that x/-0 is not folded away.
+
+(module
+  (func (export "f32.no_fold_div_neg0") (param $x f32) (result f32)
+    (f32.div (local.get $x) (f32.const -0.0)))
+  (func (export "f64.no_fold_div_neg0") (param $x f64) (result f64)
+    (f64.div (local.get $x) (f64.const -0.0)))
+)
+
+(assert_return (invoke "f32.no_fold_div_neg0" (f32.const 1.0)) (f32.const -inf))
+(assert_return (invoke "f32.no_fold_div_neg0" (f32.const -1.0)) (f32.const inf))
+(assert_return (invoke "f32.no_fold_div_neg0" (f32.const inf)) (f32.const -inf))
+(assert_return (invoke "f32.no_fold_div_neg0" (f32.const -inf)) (f32.const inf))
+(assert_return_canonical_nan (invoke "f32.no_fold_div_neg0" (f32.const 0)))
+(assert_return_canonical_nan (invoke "f32.no_fold_div_neg0" (f32.const -0)))
+(assert_return_arithmetic_nan (invoke "f32.no_fold_div_neg0" (f32.const nan:0x200000)))
+(assert_return_canonical_nan (invoke "f32.no_fold_div_neg0" (f32.const nan)))
+(assert_return (invoke "f64.no_fold_div_neg0" (f64.const 1.0)) (f64.const -inf))
+(assert_return (invoke "f64.no_fold_div_neg0" (f64.const -1.0)) (f64.const inf))
+(assert_return (invoke "f64.no_fold_div_neg0" (f64.const inf)) (f64.const -inf))
+(assert_return (invoke "f64.no_fold_div_neg0" (f64.const -inf)) (f64.const inf))
+(assert_return_canonical_nan (invoke "f64.no_fold_div_neg0" (f64.const 0)))
+(assert_return_canonical_nan (invoke "f64.no_fold_div_neg0" (f64.const -0)))
+(assert_return_canonical_nan (invoke "f64.no_fold_div_neg0" (f64.const nan)))
+(assert_return_arithmetic_nan (invoke "f64.no_fold_div_neg0" (f64.const nan:0x4000000000000)))
+
+;; Test that sqrt(x*x+y*y) is not folded to hypot.
+
+(module
+  (func (export "f32.no_fold_to_hypot") (param $x f32) (param $y f32) (result f32)
+    (f32.sqrt (f32.add (f32.mul (local.get $x) (local.get $x))
+                       (f32.mul (local.get $y) (local.get $y)))))
+  (func (export "f64.no_fold_to_hypot") (param $x f64) (param $y f64) (result f64)
+    (f64.sqrt (f64.add (f64.mul (local.get $x) (local.get $x))
+                       (f64.mul (local.get $y) (local.get $y)))))
+)
+
+(assert_return (invoke "f32.no_fold_to_hypot" (f32.const 0x1.c2f338p-81) (f32.const 0x1.401b5ep-68)) (f32.const 0x1.401cccp-68))
+(assert_return (invoke "f32.no_fold_to_hypot" (f32.const -0x1.c38d1p-71) (f32.const -0x1.359ddp-107)) (f32.const 0x1.c36a62p-71))
+(assert_return (invoke "f32.no_fold_to_hypot" (f32.const -0x1.99e0cap-114) (f32.const -0x1.ed0c6cp-69)) (f32.const 0x1.ed0e48p-69))
+(assert_return (invoke "f32.no_fold_to_hypot" (f32.const -0x1.1b6ceap+5) (f32.const 0x1.5440bep+17)) (f32.const 0x1.5440cp+17))
+(assert_return (invoke "f32.no_fold_to_hypot" (f32.const 0x1.8f019ep-76) (f32.const -0x1.182308p-71)) (f32.const 0x1.17e2bcp-71))
+(assert_return (invoke "f64.no_fold_to_hypot" (f64.const 0x1.1a0ac4f7c8711p-636) (f64.const 0x1.1372ebafff551p-534)) (f64.const 0x1.13463fa37014ep-534))
+(assert_return (invoke "f64.no_fold_to_hypot" (f64.const 0x1.b793512167499p+395) (f64.const -0x1.11cbc52af4c36p+410)) (f64.const 0x1.11cbc530783a2p+410))
+(assert_return (invoke "f64.no_fold_to_hypot" (f64.const 0x1.76777f44ff40bp-536) (f64.const -0x1.c3896e4dc1fbp-766)) (f64.const 0x1.8p-536))
+(assert_return (invoke "f64.no_fold_to_hypot" (f64.const -0x1.889ac72cc6b5dp-521) (f64.const 0x1.8d7084e659f3bp-733)) (f64.const 0x1.889ac72ca843ap-521))
+(assert_return (invoke "f64.no_fold_to_hypot" (f64.const 0x1.5ee588c02cb08p-670) (f64.const -0x1.05ce25788d9ecp-514)) (f64.const 0x1.05ce25788d9dfp-514))
+
+;; Test that 1.0/x isn't approximated.
+
+(module
+  (func (export "f32.no_approximate_reciprocal") (param $x f32) (result f32)
+    (f32.div (f32.const 1.0) (local.get $x)))
+)
+
+(assert_return (invoke "f32.no_approximate_reciprocal" (f32.const -0x1.2900b6p-10)) (f32.const -0x1.b950d4p+9))
+(assert_return (invoke "f32.no_approximate_reciprocal" (f32.const 0x1.e7212p+127)) (f32.const 0x1.0d11f8p-128))
+(assert_return (invoke "f32.no_approximate_reciprocal" (f32.const -0x1.42a466p-93)) (f32.const -0x1.963ee6p+92))
+(assert_return (invoke "f32.no_approximate_reciprocal" (f32.const 0x1.5d0c32p+76)) (f32.const 0x1.778362p-77))
+(assert_return (invoke "f32.no_approximate_reciprocal" (f32.const -0x1.601de2p-82)) (f32.const -0x1.743d7ep+81))
+
+;; Test that 1.0/sqrt(x) isn't approximated or fused.
+
+(module
+  (func (export "f32.no_approximate_reciprocal_sqrt") (param $x f32) (result f32)
+    (f32.div (f32.const 1.0) (f32.sqrt (local.get $x))))
+  (func (export "f64.no_fuse_reciprocal_sqrt") (param $x f64) (result f64)
+    (f64.div (f64.const 1.0) (f64.sqrt (local.get $x))))
+)
+
+(assert_return (invoke "f32.no_approximate_reciprocal_sqrt" (f32.const 0x1.6af12ap-43)) (f32.const 0x1.300ed4p+21))
+(assert_return (invoke "f32.no_approximate_reciprocal_sqrt" (f32.const 0x1.e82fc6p-8)) (f32.const 0x1.72c376p+3))
+(assert_return (invoke "f32.no_approximate_reciprocal_sqrt" (f32.const 0x1.b9fa9cp-66)) (f32.const 0x1.85a9bap+32))
+(assert_return (invoke "f32.no_approximate_reciprocal_sqrt" (f32.const 0x1.f4f546p-44)) (f32.const 0x1.6e01c2p+21))
+(assert_return (invoke "f32.no_approximate_reciprocal_sqrt" (f32.const 0x1.5da7aap-86)) (f32.const 0x1.b618cap+42))
+
+(assert_return (invoke "f64.no_fuse_reciprocal_sqrt" (f64.const 0x1.1568a63b55fa3p+889)) (f64.const 0x1.5bc9c74c9952p-445))
+(assert_return (invoke "f64.no_fuse_reciprocal_sqrt" (f64.const 0x1.239fcd0939cafp+311)) (f64.const 0x1.5334a922b4818p-156))
+(assert_return (invoke "f64.no_fuse_reciprocal_sqrt" (f64.const 0x1.6e36a24e11054p+104)) (f64.const 0x1.ac13f20977f29p-53))
+(assert_return (invoke "f64.no_fuse_reciprocal_sqrt" (f64.const 0x1.23ee173219f83p+668)) (f64.const 0x1.df753e055862dp-335))
+(assert_return (invoke "f64.no_fuse_reciprocal_sqrt" (f64.const 0x1.b30f74caf9babp+146)) (f64.const 0x1.88bfc3d1764a9p-74))
+
+;; Test that sqrt(1.0/x) isn't approximated.
+
+(module
+  (func (export "f32.no_approximate_sqrt_reciprocal") (param $x f32) (result f32)
+    (f32.sqrt (f32.div (f32.const 1.0) (local.get $x))))
+)
+
+(assert_return (invoke "f32.no_approximate_sqrt_reciprocal" (f32.const 0x1.a4c986p+60)) (f32.const 0x1.8f5ac6p-31))
+(assert_return (invoke "f32.no_approximate_sqrt_reciprocal" (f32.const 0x1.50511ep-9)) (f32.const 0x1.3bdd46p+4))
+(assert_return (invoke "f32.no_approximate_sqrt_reciprocal" (f32.const 0x1.125ec2p+69)) (f32.const 0x1.5db572p-35))
+(assert_return (invoke "f32.no_approximate_sqrt_reciprocal" (f32.const 0x1.ba4c5p+13)) (f32.const 0x1.136f16p-7))
+(assert_return (invoke "f32.no_approximate_sqrt_reciprocal" (f32.const 0x1.4a5be2p+104)) (f32.const 0x1.c2b5bp-53))
+
+;; Test that converting i32/i64 to f32/f64 and back isn't folded away.
+
+(module
+  (func (export "i32.no_fold_f32_s") (param i32) (result i32)
+    (i32.trunc_f32_s (f32.convert_i32_s (local.get 0))))
+  (func (export "i32.no_fold_f32_u") (param i32) (result i32)
+    (i32.trunc_f32_u (f32.convert_i32_u (local.get 0))))
+  (func (export "i64.no_fold_f64_s") (param i64) (result i64)
+    (i64.trunc_f64_s (f64.convert_i64_s (local.get 0))))
+  (func (export "i64.no_fold_f64_u") (param i64) (result i64)
+    (i64.trunc_f64_u (f64.convert_i64_u (local.get 0))))
+)
+
+(assert_return (invoke "i32.no_fold_f32_s" (i32.const 0x1000000)) (i32.const 0x1000000))
+(assert_return (invoke "i32.no_fold_f32_s" (i32.const 0x1000001)) (i32.const 0x1000000))
+(assert_return (invoke "i32.no_fold_f32_s" (i32.const 0xf0000010)) (i32.const 0xf0000010))
+
+(assert_return (invoke "i32.no_fold_f32_u" (i32.const 0x1000000)) (i32.const 0x1000000))
+(assert_return (invoke "i32.no_fold_f32_u" (i32.const 0x1000001)) (i32.const 0x1000000))
+(assert_return (invoke "i32.no_fold_f32_u" (i32.const 0xf0000010)) (i32.const 0xf0000000))
+
+(assert_return (invoke "i64.no_fold_f64_s" (i64.const 0x20000000000000)) (i64.const 0x20000000000000))
+(assert_return (invoke "i64.no_fold_f64_s" (i64.const 0x20000000000001)) (i64.const 0x20000000000000))
+(assert_return (invoke "i64.no_fold_f64_s" (i64.const 0xf000000000000400)) (i64.const 0xf000000000000400))
+
+(assert_return (invoke "i64.no_fold_f64_u" (i64.const 0x20000000000000)) (i64.const 0x20000000000000))
+(assert_return (invoke "i64.no_fold_f64_u" (i64.const 0x20000000000001)) (i64.const 0x20000000000000))
+(assert_return (invoke "i64.no_fold_f64_u" (i64.const 0xf000000000000400)) (i64.const 0xf000000000000000))
+
+;; Test that x+y-y is not folded to x.
+
+(module
+  (func (export "f32.no_fold_add_sub") (param $x f32) (param $y f32) (result f32)
+    (f32.sub (f32.add (local.get $x) (local.get $y)) (local.get $y)))
+  (func (export "f64.no_fold_add_sub") (param $x f64) (param $y f64) (result f64)
+    (f64.sub (f64.add (local.get $x) (local.get $y)) (local.get $y)))
+)
+
+(assert_return (invoke "f32.no_fold_add_sub" (f32.const 0x1.b553e4p-47) (f32.const -0x1.67db2cp-26)) (f32.const 0x1.cp-47))
+(assert_return (invoke "f32.no_fold_add_sub" (f32.const -0x1.a884dp-23) (f32.const 0x1.f2ae1ep-19)) (f32.const -0x1.a884ep-23))
+(assert_return (invoke "f32.no_fold_add_sub" (f32.const -0x1.fc04fp+82) (f32.const -0x1.65403ap+101)) (f32.const -0x1p+83))
+(assert_return (invoke "f32.no_fold_add_sub" (f32.const 0x1.870fa2p-78) (f32.const 0x1.c54916p-56)) (f32.const 0x1.8p-78))
+(assert_return (invoke "f32.no_fold_add_sub" (f32.const -0x1.17e966p-108) (f32.const -0x1.5fa61ap-84)) (f32.const -0x1p-107))
+
+(assert_return (invoke "f64.no_fold_add_sub" (f64.const -0x1.1053ea172dba8p-874) (f64.const 0x1.113c413408ac8p-857)) (f64.const -0x1.1053ea172p-874))
+(assert_return (invoke "f64.no_fold_add_sub" (f64.const 0x1.e377d54807972p-546) (f64.const 0x1.040a0a4d1ff7p-526)) (f64.const 0x1.e377d548p-546))
+(assert_return (invoke "f64.no_fold_add_sub" (f64.const -0x1.75f53cd926b62p-30) (f64.const -0x1.66b176e602bb5p-3)) (f64.const -0x1.75f53dp-30))
+(assert_return (invoke "f64.no_fold_add_sub" (f64.const -0x1.c450ff28332ap-341) (f64.const 0x1.15a5855023baep-305)) (f64.const -0x1.c451p-341))
+(assert_return (invoke "f64.no_fold_add_sub" (f64.const -0x1.1ad4a596d3ea8p-619) (f64.const -0x1.17d81a41c0ea8p-588)) (f64.const -0x1.1ad4a8p-619))
+
+;; Test that x-y+y is not folded to x.
+
+(module
+  (func (export "f32.no_fold_sub_add") (param $x f32) (param $y f32) (result f32)
+    (f32.add (f32.sub (local.get $x) (local.get $y)) (local.get $y)))
+  (func (export "f64.no_fold_sub_add") (param $x f64) (param $y f64) (result f64)
+    (f64.add (f64.sub (local.get $x) (local.get $y)) (local.get $y)))
+)
+
+(assert_return (invoke "f32.no_fold_sub_add" (f32.const -0x1.523cb8p+9) (f32.const 0x1.93096cp+8)) (f32.const -0x1.523cbap+9))
+(assert_return (invoke "f32.no_fold_sub_add" (f32.const -0x1.a31a1p-111) (f32.const 0x1.745efp-95)) (f32.const -0x1.a4p-111))
+(assert_return (invoke "f32.no_fold_sub_add" (f32.const 0x1.3d5328p+26) (f32.const 0x1.58567p+35)) (f32.const 0x1.3d54p+26))
+(assert_return (invoke "f32.no_fold_sub_add" (f32.const 0x1.374e26p-39) (f32.const -0x1.66a5p-27)) (f32.const 0x1.374p-39))
+(assert_return (invoke "f32.no_fold_sub_add" (f32.const 0x1.320facp-3) (f32.const -0x1.ac069ap+14)) (f32.const 0x1.34p-3))
+
+(assert_return (invoke "f64.no_fold_sub_add" (f64.const 0x1.8f92aad2c9b8dp+255) (f64.const -0x1.08cd4992266cbp+259)) (f64.const 0x1.8f92aad2c9b9p+255))
+(assert_return (invoke "f64.no_fold_sub_add" (f64.const 0x1.5aaff55742c8bp-666) (f64.const 0x1.8f5f47181f46dp-647)) (f64.const 0x1.5aaff5578p-666))
+(assert_return (invoke "f64.no_fold_sub_add" (f64.const 0x1.21bc52967a98dp+251) (f64.const -0x1.fcffaa32d0884p+300)) (f64.const 0x1.2p+251))
+(assert_return (invoke "f64.no_fold_sub_add" (f64.const 0x1.9c78361f47374p-26) (f64.const -0x1.69d69f4edc61cp-13)) (f64.const 0x1.9c78361f48p-26))
+(assert_return (invoke "f64.no_fold_sub_add" (f64.const 0x1.4dbe68e4afab2p-367) (f64.const -0x1.dc24e5b39cd02p-361)) (f64.const 0x1.4dbe68e4afacp-367))
+
+;; Test that x*y/y is not folded to x.
+
+(module
+  (func (export "f32.no_fold_mul_div") (param $x f32) (param $y f32) (result f32)
+    (f32.div (f32.mul (local.get $x) (local.get $y)) (local.get $y)))
+  (func (export "f64.no_fold_mul_div") (param $x f64) (param $y f64) (result f64)
+    (f64.div (f64.mul (local.get $x) (local.get $y)) (local.get $y)))
+)
+
+(assert_return (invoke "f32.no_fold_mul_div" (f32.const -0x1.cd859ap+54) (f32.const 0x1.6ca936p-47)) (f32.const -0x1.cd8598p+54))
+(assert_return (invoke "f32.no_fold_mul_div" (f32.const -0x1.0b56b8p-26) (f32.const 0x1.48264cp-106)) (f32.const -0x1.0b56a4p-26))
+(assert_return (invoke "f32.no_fold_mul_div" (f32.const -0x1.e7555cp-48) (f32.const -0x1.9161cp+48)) (f32.const -0x1.e7555ap-48))
+(assert_return (invoke "f32.no_fold_mul_div" (f32.const 0x1.aaa50ep+52) (f32.const -0x1.dfb39ep+60)) (f32.const 0x1.aaa50cp+52))
+(assert_return (invoke "f32.no_fold_mul_div" (f32.const -0x1.2b7dfap-92) (f32.const -0x1.7c4ca6p-37)) (f32.const -0x1.2b7dfep-92))
+
+(assert_return (invoke "f64.no_fold_mul_div" (f64.const -0x1.3d79ff4118a1ap-837) (f64.const -0x1.b8b5dda31808cp-205)) (f64.const -0x1.3d79ff412263ep-837))
+(assert_return (invoke "f64.no_fold_mul_div" (f64.const 0x1.f894d1ee6b3a4p+384) (f64.const 0x1.8c2606d03d58ap+585)) (f64.const 0x1.f894d1ee6b3a5p+384))
+(assert_return (invoke "f64.no_fold_mul_div" (f64.const -0x1.a022260acc993p+238) (f64.const -0x1.5fbc128fc8e3cp-552)) (f64.const -0x1.a022260acc992p+238))
+(assert_return (invoke "f64.no_fold_mul_div" (f64.const 0x1.9d4b8ed174f54p-166) (f64.const 0x1.ee3d467aeeac6p-906)) (f64.const 0x1.8dcc95a053b2bp-166))
+(assert_return (invoke "f64.no_fold_mul_div" (f64.const -0x1.e95ea897cdcd4p+660) (f64.const -0x1.854d5df085f2ep-327)) (f64.const -0x1.e95ea897cdcd5p+660))
+
+;; Test that x/y*y is not folded to x.
+
+(module
+  (func (export "f32.no_fold_div_mul") (param $x f32) (param $y f32) (result f32)
+    (f32.mul (f32.div (local.get $x) (local.get $y)) (local.get $y)))
+  (func (export "f64.no_fold_div_mul") (param $x f64) (param $y f64) (result f64)
+    (f64.mul (f64.div (local.get $x) (local.get $y)) (local.get $y)))
+)
+
+(assert_return (invoke "f32.no_fold_div_mul" (f32.const -0x1.dc6364p+38) (f32.const 0x1.d630ecp+29)) (f32.const -0x1.dc6362p+38))
+(assert_return (invoke "f32.no_fold_div_mul" (f32.const -0x1.1f9836p-52) (f32.const -0x1.16c4e4p-18)) (f32.const -0x1.1f9838p-52))
+(assert_return (invoke "f32.no_fold_div_mul" (f32.const 0x1.c5972cp-126) (f32.const -0x1.d6659ep+7)) (f32.const 0x1.c5980ep-126))
+(assert_return (invoke "f32.no_fold_div_mul" (f32.const -0x1.2e3a9ep-74) (f32.const -0x1.353994p+59)) (f32.const -0x1.2e3a4p-74))
+(assert_return (invoke "f32.no_fold_div_mul" (f32.const 0x1.d96b82p-98) (f32.const 0x1.95d908p+27)) (f32.const 0x1.d96b84p-98))
+
+(assert_return (invoke "f64.no_fold_div_mul" (f64.const 0x1.d01f913a52481p-876) (f64.const -0x1.2cd0668b28344p+184)) (f64.const 0x1.d020daf71cdcp-876))
+(assert_return (invoke "f64.no_fold_div_mul" (f64.const -0x1.81cb7d400918dp-714) (f64.const 0x1.7caa643586d6ep-53)) (f64.const -0x1.81cb7d400918ep-714))
+(assert_return (invoke "f64.no_fold_div_mul" (f64.const -0x1.66904c97b5c8ep-145) (f64.const 0x1.5c3481592ad4cp+428)) (f64.const -0x1.66904c97b5c8dp-145))
+(assert_return (invoke "f64.no_fold_div_mul" (f64.const -0x1.e75859d2f0765p-278) (f64.const -0x1.5f19b6ab497f9p+283)) (f64.const -0x1.e75859d2f0764p-278))
+(assert_return (invoke "f64.no_fold_div_mul" (f64.const -0x1.515fe9c3b5f5p+620) (f64.const 0x1.36be869c99f7ap+989)) (f64.const -0x1.515fe9c3b5f4fp+620))
+
+;; Test that x/2*2 is not folded to x.
+
+(module
+  (func (export "f32.no_fold_div2_mul2") (param $x f32) (result f32)
+    (f32.mul (f32.div (local.get $x) (f32.const 2.0)) (f32.const 2.0)))
+  (func (export "f64.no_fold_div2_mul2") (param $x f64) (result f64)
+    (f64.mul (f64.div (local.get $x) (f64.const 2.0)) (f64.const 2.0)))
+)
+
+(assert_return (invoke "f32.no_fold_div2_mul2" (f32.const 0x1.fffffep-126)) (f32.const 0x1p-125))
+(assert_return (invoke "f64.no_fold_div2_mul2" (f64.const 0x1.fffffffffffffp-1022)) (f64.const 0x1p-1021))
+
+;; Test that promote(demote(x)) is not folded to x.
+
+(module
+  (func (export "no_fold_demote_promote") (param $x f64) (result f64)
+    (f64.promote_f32 (f32.demote_f64 (local.get $x))))
+)
+
+(assert_return (invoke "no_fold_demote_promote" (f64.const -0x1.dece272390f5dp-133)) (f64.const -0x1.decep-133))
+(assert_return (invoke "no_fold_demote_promote" (f64.const -0x1.19e6c79938a6fp-85)) (f64.const -0x1.19e6c8p-85))
+(assert_return (invoke "no_fold_demote_promote" (f64.const 0x1.49b297ec44dc1p+107)) (f64.const 0x1.49b298p+107))
+(assert_return (invoke "no_fold_demote_promote" (f64.const -0x1.74f5bd865163p-88)) (f64.const -0x1.74f5bep-88))
+(assert_return (invoke "no_fold_demote_promote" (f64.const 0x1.26d675662367ep+104)) (f64.const 0x1.26d676p+104))
+
+;; Test that demote(promote(x)) is not folded to x, and aside from NaN is
+;; bit-preserving.
+
+(module
+  (func (export "no_fold_promote_demote") (param $x f32) (result f32)
+    (f32.demote_f64 (f64.promote_f32 (local.get $x))))
+)
+
+(assert_return_arithmetic_nan (invoke "no_fold_promote_demote" (f32.const nan:0x200000)))
+(assert_return (invoke "no_fold_promote_demote" (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "no_fold_promote_demote" (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "no_fold_promote_demote" (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "no_fold_promote_demote" (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "no_fold_promote_demote" (f32.const 0x1.fffffcp-127)) (f32.const 0x1.fffffcp-127))
+(assert_return (invoke "no_fold_promote_demote" (f32.const -0x1.fffffcp-127)) (f32.const -0x1.fffffcp-127))
+(assert_return (invoke "no_fold_promote_demote" (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "no_fold_promote_demote" (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "no_fold_promote_demote" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "no_fold_promote_demote" (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "no_fold_promote_demote" (f32.const inf)) (f32.const inf))
+(assert_return (invoke "no_fold_promote_demote" (f32.const -inf)) (f32.const -inf))
+
+;; Test that demote(x+promote(y)) is not folded to demote(x)+y.
+
+(module
+  (func (export "no_demote_mixed_add") (param $x f64) (param $y f32) (result f32)
+    (f32.demote_f64 (f64.add (local.get $x) (f64.promote_f32 (local.get $y)))))
+  (func (export "no_demote_mixed_add_commuted") (param $y f32) (param $x f64) (result f32)
+    (f32.demote_f64 (f64.add (f64.promote_f32 (local.get $y)) (local.get $x))))
+)
+
+(assert_return (invoke "no_demote_mixed_add" (f64.const 0x1.f51a9d04854f9p-95) (f32.const 0x1.3f4e9cp-119)) (f32.const 0x1.f51a9ep-95))
+(assert_return (invoke "no_demote_mixed_add" (f64.const 0x1.065b3d81ad8dp+37) (f32.const 0x1.758cd8p+38)) (f32.const 0x1.f8ba76p+38))
+(assert_return (invoke "no_demote_mixed_add" (f64.const 0x1.626c80963bd17p-119) (f32.const -0x1.9bbf86p-121)) (f32.const 0x1.f6f93ep-120))
+(assert_return (invoke "no_demote_mixed_add" (f64.const -0x1.0d5110e3385bbp-20) (f32.const 0x1.096f4ap-29)) (f32.const -0x1.0ccc5ap-20))
+(assert_return (invoke "no_demote_mixed_add" (f64.const -0x1.73852db4e5075p-20) (f32.const -0x1.24e474p-41)) (f32.const -0x1.738536p-20))
+
+(assert_return (invoke "no_demote_mixed_add_commuted" (f32.const 0x1.3f4e9cp-119) (f64.const 0x1.f51a9d04854f9p-95)) (f32.const 0x1.f51a9ep-95))
+(assert_return (invoke "no_demote_mixed_add_commuted" (f32.const 0x1.758cd8p+38) (f64.const 0x1.065b3d81ad8dp+37)) (f32.const 0x1.f8ba76p+38))
+(assert_return (invoke "no_demote_mixed_add_commuted" (f32.const -0x1.9bbf86p-121) (f64.const 0x1.626c80963bd17p-119)) (f32.const 0x1.f6f93ep-120))
+(assert_return (invoke "no_demote_mixed_add_commuted" (f32.const 0x1.096f4ap-29) (f64.const -0x1.0d5110e3385bbp-20)) (f32.const -0x1.0ccc5ap-20))
+(assert_return (invoke "no_demote_mixed_add_commuted" (f32.const -0x1.24e474p-41) (f64.const -0x1.73852db4e5075p-20)) (f32.const -0x1.738536p-20))
+
+;; Test that demote(x-promote(y)) is not folded to demote(x)-y.
+
+(module
+  (func (export "no_demote_mixed_sub") (param $x f64) (param $y f32) (result f32)
+    (f32.demote_f64 (f64.sub (local.get $x) (f64.promote_f32 (local.get $y)))))
+)
+
+(assert_return (invoke "no_demote_mixed_sub" (f64.const 0x1.a0a183220e9b1p+82) (f32.const 0x1.c5acf8p+61)) (f32.const 0x1.a0a174p+82))
+(assert_return (invoke "no_demote_mixed_sub" (f64.const -0x1.6e2c5ac39f63ep+30) (f32.const 0x1.d48ca4p+17)) (f32.const -0x1.6e3bp+30))
+(assert_return (invoke "no_demote_mixed_sub" (f64.const -0x1.98c74350dde6ap+6) (f32.const 0x1.9d69bcp-12)) (f32.const -0x1.98c7aap+6))
+(assert_return (invoke "no_demote_mixed_sub" (f64.const 0x1.0459f34091dbfp-54) (f32.const 0x1.61ad08p-71)) (f32.const 0x1.045942p-54))
+(assert_return (invoke "no_demote_mixed_sub" (f64.const 0x1.a7498dca3fdb7p+14) (f32.const 0x1.ed21c8p+15)) (f32.const -0x1.197d02p+15))
+
+;; Test that converting between integer and float and back isn't folded away.
+
+(module
+  (func (export "f32.i32.no_fold_trunc_s_convert_s") (param $x f32) (result f32)
+    (f32.convert_i32_s (i32.trunc_f32_s (local.get $x))))
+  (func (export "f32.i32.no_fold_trunc_u_convert_s") (param $x f32) (result f32)
+    (f32.convert_i32_s (i32.trunc_f32_u (local.get $x))))
+  (func (export "f32.i32.no_fold_trunc_s_convert_u") (param $x f32) (result f32)
+    (f32.convert_i32_u (i32.trunc_f32_s (local.get $x))))
+  (func (export "f32.i32.no_fold_trunc_u_convert_u") (param $x f32) (result f32)
+    (f32.convert_i32_u (i32.trunc_f32_u (local.get $x))))
+  (func (export "f64.i32.no_fold_trunc_s_convert_s") (param $x f64) (result f64)
+    (f64.convert_i32_s (i32.trunc_f64_s (local.get $x))))
+  (func (export "f64.i32.no_fold_trunc_u_convert_s") (param $x f64) (result f64)
+    (f64.convert_i32_s (i32.trunc_f64_u (local.get $x))))
+  (func (export "f64.i32.no_fold_trunc_s_convert_u") (param $x f64) (result f64)
+    (f64.convert_i32_u (i32.trunc_f64_s (local.get $x))))
+  (func (export "f64.i32.no_fold_trunc_u_convert_u") (param $x f64) (result f64)
+    (f64.convert_i32_u (i32.trunc_f64_u (local.get $x))))
+  (func (export "f32.i64.no_fold_trunc_s_convert_s") (param $x f32) (result f32)
+    (f32.convert_i64_s (i64.trunc_f32_s (local.get $x))))
+  (func (export "f32.i64.no_fold_trunc_u_convert_s") (param $x f32) (result f32)
+    (f32.convert_i64_s (i64.trunc_f32_u (local.get $x))))
+  (func (export "f32.i64.no_fold_trunc_s_convert_u") (param $x f32) (result f32)
+    (f32.convert_i64_u (i64.trunc_f32_s (local.get $x))))
+  (func (export "f32.i64.no_fold_trunc_u_convert_u") (param $x f32) (result f32)
+    (f32.convert_i64_u (i64.trunc_f32_u (local.get $x))))
+  (func (export "f64.i64.no_fold_trunc_s_convert_s") (param $x f64) (result f64)
+    (f64.convert_i64_s (i64.trunc_f64_s (local.get $x))))
+  (func (export "f64.i64.no_fold_trunc_u_convert_s") (param $x f64) (result f64)
+    (f64.convert_i64_s (i64.trunc_f64_u (local.get $x))))
+  (func (export "f64.i64.no_fold_trunc_s_convert_u") (param $x f64) (result f64)
+    (f64.convert_i64_u (i64.trunc_f64_s (local.get $x))))
+  (func (export "f64.i64.no_fold_trunc_u_convert_u") (param $x f64) (result f64)
+    (f64.convert_i64_u (i64.trunc_f64_u (local.get $x))))
+)
+
+(assert_return (invoke "f32.i32.no_fold_trunc_s_convert_s" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i32.no_fold_trunc_s_convert_s" (f32.const -1.5)) (f32.const -1.0))
+(assert_return (invoke "f32.i32.no_fold_trunc_u_convert_s" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i32.no_fold_trunc_u_convert_s" (f32.const -0.5)) (f32.const 0.0))
+(assert_return (invoke "f32.i32.no_fold_trunc_s_convert_u" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i32.no_fold_trunc_s_convert_u" (f32.const -1.5)) (f32.const 0x1p+32))
+(assert_return (invoke "f32.i32.no_fold_trunc_u_convert_u" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i32.no_fold_trunc_u_convert_u" (f32.const -0.5)) (f32.const 0.0))
+
+(assert_return (invoke "f64.i32.no_fold_trunc_s_convert_s" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i32.no_fold_trunc_s_convert_s" (f64.const -1.5)) (f64.const -1.0))
+(assert_return (invoke "f64.i32.no_fold_trunc_u_convert_s" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i32.no_fold_trunc_u_convert_s" (f64.const -0.5)) (f64.const 0.0))
+(assert_return (invoke "f64.i32.no_fold_trunc_s_convert_u" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i32.no_fold_trunc_s_convert_u" (f64.const -1.5)) (f64.const 0x1.fffffffep+31))
+(assert_return (invoke "f64.i32.no_fold_trunc_u_convert_u" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i32.no_fold_trunc_u_convert_u" (f64.const -0.5)) (f64.const 0.0))
+
+(assert_return (invoke "f32.i64.no_fold_trunc_s_convert_s" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i64.no_fold_trunc_s_convert_s" (f32.const -1.5)) (f32.const -1.0))
+(assert_return (invoke "f32.i64.no_fold_trunc_u_convert_s" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i64.no_fold_trunc_u_convert_s" (f32.const -0.5)) (f32.const 0.0))
+(assert_return (invoke "f32.i64.no_fold_trunc_s_convert_u" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i64.no_fold_trunc_s_convert_u" (f32.const -1.5)) (f32.const 0x1p+64))
+(assert_return (invoke "f32.i64.no_fold_trunc_u_convert_u" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i64.no_fold_trunc_u_convert_u" (f32.const -0.5)) (f32.const 0.0))
+
+(assert_return (invoke "f64.i64.no_fold_trunc_s_convert_s" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i64.no_fold_trunc_s_convert_s" (f64.const -1.5)) (f64.const -1.0))
+(assert_return (invoke "f64.i64.no_fold_trunc_u_convert_s" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i64.no_fold_trunc_u_convert_s" (f64.const -0.5)) (f64.const 0.0))
+(assert_return (invoke "f64.i64.no_fold_trunc_s_convert_u" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i64.no_fold_trunc_s_convert_u" (f64.const -1.5)) (f64.const 0x1p+64))
+(assert_return (invoke "f64.i64.no_fold_trunc_u_convert_u" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i64.no_fold_trunc_u_convert_u" (f64.const -0.5)) (f64.const 0.0))
+
+;; Test that dividing by a loop-invariant constant isn't optimized to be a
+;; multiplication by a reciprocal, which would be particularly tempting since
+;; the reciprocal computation could be hoisted.
+
+(module
+  (memory 1 1)
+  (func (export "init") (param $i i32) (param $x f32) (f32.store (local.get $i) (local.get $x)))
+
+  (func (export "run") (param $n i32) (param $z f32)
+    (local $i i32)
+    (block $exit
+      (loop $cont
+        (f32.store
+          (local.get $i)
+          (f32.div (f32.load (local.get $i)) (local.get $z))
+        )
+        (local.set $i (i32.add (local.get $i) (i32.const 4)))
+        (br_if $cont (i32.lt_u (local.get $i) (local.get $n)))
+      )
+    )
+  )
+
+  (func (export "check") (param $i i32) (result f32) (f32.load (local.get $i)))
+)
+
+(invoke "init" (i32.const  0) (f32.const 15.1))
+(invoke "init" (i32.const  4) (f32.const 15.2))
+(invoke "init" (i32.const  8) (f32.const 15.3))
+(invoke "init" (i32.const 12) (f32.const 15.4))
+(assert_return (invoke "check" (i32.const  0)) (f32.const 15.1))
+(assert_return (invoke "check" (i32.const  4)) (f32.const 15.2))
+(assert_return (invoke "check" (i32.const  8)) (f32.const 15.3))
+(assert_return (invoke "check" (i32.const 12)) (f32.const 15.4))
+(invoke "run" (i32.const 16) (f32.const 3.0))
+(assert_return (invoke "check" (i32.const  0)) (f32.const 0x1.422222p+2))
+(assert_return (invoke "check" (i32.const  4)) (f32.const 0x1.444444p+2))
+(assert_return (invoke "check" (i32.const  8)) (f32.const 0x1.466666p+2))
+(assert_return (invoke "check" (i32.const 12)) (f32.const 0x1.488888p+2))
+
+(module
+  (memory 1 1)
+  (func (export "init") (param $i i32) (param $x f64) (f64.store (local.get $i) (local.get $x)))
+
+  (func (export "run") (param $n i32) (param $z f64)
+    (local $i i32)
+    (block $exit
+      (loop $cont
+        (f64.store
+          (local.get $i)
+          (f64.div (f64.load (local.get $i)) (local.get $z))
+        )
+        (local.set $i (i32.add (local.get $i) (i32.const 8)))
+        (br_if $cont (i32.lt_u (local.get $i) (local.get $n)))
+      )
+    )
+  )
+
+  (func (export "check") (param $i i32) (result f64) (f64.load (local.get $i)))
+)
+
+(invoke "init" (i32.const  0) (f64.const 15.1))
+(invoke "init" (i32.const  8) (f64.const 15.2))
+(invoke "init" (i32.const 16) (f64.const 15.3))
+(invoke "init" (i32.const 24) (f64.const 15.4))
+(assert_return (invoke "check" (i32.const  0)) (f64.const 15.1))
+(assert_return (invoke "check" (i32.const  8)) (f64.const 15.2))
+(assert_return (invoke "check" (i32.const 16)) (f64.const 15.3))
+(assert_return (invoke "check" (i32.const 24)) (f64.const 15.4))
+(invoke "run" (i32.const 32) (f64.const 3.0))
+(assert_return (invoke "check" (i32.const 0)) (f64.const 0x1.4222222222222p+2))
+(assert_return (invoke "check" (i32.const 8)) (f64.const 0x1.4444444444444p+2))
+(assert_return (invoke "check" (i32.const 16)) (f64.const 0x1.4666666666667p+2))
+(assert_return (invoke "check" (i32.const 24)) (f64.const 0x1.4888888888889p+2))
+
+;; Test that ult/ugt/etc. aren't folded to olt/ogt/etc.
+
+(module
+  (func (export "f32.ult") (param $x f32) (param $y f32) (result i32) (i32.eqz (f32.ge (local.get $x) (local.get $y))))
+  (func (export "f32.ule") (param $x f32) (param $y f32) (result i32) (i32.eqz (f32.gt (local.get $x) (local.get $y))))
+  (func (export "f32.ugt") (param $x f32) (param $y f32) (result i32) (i32.eqz (f32.le (local.get $x) (local.get $y))))
+  (func (export "f32.uge") (param $x f32) (param $y f32) (result i32) (i32.eqz (f32.lt (local.get $x) (local.get $y))))
+
+  (func (export "f64.ult") (param $x f64) (param $y f64) (result i32) (i32.eqz (f64.ge (local.get $x) (local.get $y))))
+  (func (export "f64.ule") (param $x f64) (param $y f64) (result i32) (i32.eqz (f64.gt (local.get $x) (local.get $y))))
+  (func (export "f64.ugt") (param $x f64) (param $y f64) (result i32) (i32.eqz (f64.le (local.get $x) (local.get $y))))
+  (func (export "f64.uge") (param $x f64) (param $y f64) (result i32) (i32.eqz (f64.lt (local.get $x) (local.get $y))))
+)
+
+(assert_return (invoke "f32.ult" (f32.const 3.0) (f32.const 2.0)) (i32.const 0))
+(assert_return (invoke "f32.ult" (f32.const 2.0) (f32.const 2.0)) (i32.const 0))
+(assert_return (invoke "f32.ult" (f32.const 2.0) (f32.const 3.0)) (i32.const 1))
+(assert_return (invoke "f32.ult" (f32.const 2.0) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "f32.ule" (f32.const 3.0) (f32.const 2.0)) (i32.const 0))
+(assert_return (invoke "f32.ule" (f32.const 2.0) (f32.const 2.0)) (i32.const 1))
+(assert_return (invoke "f32.ule" (f32.const 2.0) (f32.const 3.0)) (i32.const 1))
+(assert_return (invoke "f32.ule" (f32.const 2.0) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "f32.ugt" (f32.const 3.0) (f32.const 2.0)) (i32.const 1))
+(assert_return (invoke "f32.ugt" (f32.const 2.0) (f32.const 2.0)) (i32.const 0))
+(assert_return (invoke "f32.ugt" (f32.const 2.0) (f32.const 3.0)) (i32.const 0))
+(assert_return (invoke "f32.ugt" (f32.const 2.0) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "f32.uge" (f32.const 3.0) (f32.const 2.0)) (i32.const 1))
+(assert_return (invoke "f32.uge" (f32.const 2.0) (f32.const 2.0)) (i32.const 1))
+(assert_return (invoke "f32.uge" (f32.const 2.0) (f32.const 3.0)) (i32.const 0))
+(assert_return (invoke "f32.uge" (f32.const 2.0) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "f64.ult" (f64.const 3.0) (f64.const 2.0)) (i32.const 0))
+(assert_return (invoke "f64.ult" (f64.const 2.0) (f64.const 2.0)) (i32.const 0))
+(assert_return (invoke "f64.ult" (f64.const 2.0) (f64.const 3.0)) (i32.const 1))
+(assert_return (invoke "f64.ult" (f64.const 2.0) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "f64.ule" (f64.const 3.0) (f64.const 2.0)) (i32.const 0))
+(assert_return (invoke "f64.ule" (f64.const 2.0) (f64.const 2.0)) (i32.const 1))
+(assert_return (invoke "f64.ule" (f64.const 2.0) (f64.const 3.0)) (i32.const 1))
+(assert_return (invoke "f64.ule" (f64.const 2.0) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "f64.ugt" (f64.const 3.0) (f64.const 2.0)) (i32.const 1))
+(assert_return (invoke "f64.ugt" (f64.const 2.0) (f64.const 2.0)) (i32.const 0))
+(assert_return (invoke "f64.ugt" (f64.const 2.0) (f64.const 3.0)) (i32.const 0))
+(assert_return (invoke "f64.ugt" (f64.const 2.0) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "f64.uge" (f64.const 3.0) (f64.const 2.0)) (i32.const 1))
+(assert_return (invoke "f64.uge" (f64.const 2.0) (f64.const 2.0)) (i32.const 1))
+(assert_return (invoke "f64.uge" (f64.const 2.0) (f64.const 3.0)) (i32.const 0))
+(assert_return (invoke "f64.uge" (f64.const 2.0) (f64.const nan)) (i32.const 1))
+
+;; Test that x<y?x:y, etc. using select aren't folded to min, etc.
+
+(module
+  (func (export "f32.no_fold_lt_select") (param $x f32) (param $y f32) (result f32) (select (local.get $x) (local.get $y) (f32.lt (local.get $x) (local.get $y))))
+  (func (export "f32.no_fold_le_select") (param $x f32) (param $y f32) (result f32) (select (local.get $x) (local.get $y) (f32.le (local.get $x) (local.get $y))))
+  (func (export "f32.no_fold_gt_select") (param $x f32) (param $y f32) (result f32) (select (local.get $x) (local.get $y) (f32.gt (local.get $x) (local.get $y))))
+  (func (export "f32.no_fold_ge_select") (param $x f32) (param $y f32) (result f32) (select (local.get $x) (local.get $y) (f32.ge (local.get $x) (local.get $y))))
+
+  (func (export "f64.no_fold_lt_select") (param $x f64) (param $y f64) (result f64) (select (local.get $x) (local.get $y) (f64.lt (local.get $x) (local.get $y))))
+  (func (export "f64.no_fold_le_select") (param $x f64) (param $y f64) (result f64) (select (local.get $x) (local.get $y) (f64.le (local.get $x) (local.get $y))))
+  (func (export "f64.no_fold_gt_select") (param $x f64) (param $y f64) (result f64) (select (local.get $x) (local.get $y) (f64.gt (local.get $x) (local.get $y))))
+  (func (export "f64.no_fold_ge_select") (param $x f64) (param $y f64) (result f64) (select (local.get $x) (local.get $y) (f64.ge (local.get $x) (local.get $y))))
+)
+
+(assert_return (invoke "f32.no_fold_lt_select" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_lt_select" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_lt_select" (f32.const 0.0) (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_lt_select" (f32.const -0.0) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_le_select" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_le_select" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_le_select" (f32.const 0.0) (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_le_select" (f32.const -0.0) (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_gt_select" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_gt_select" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_gt_select" (f32.const 0.0) (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_gt_select" (f32.const -0.0) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_select" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_ge_select" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_select" (f32.const 0.0) (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_select" (f32.const -0.0) (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f64.no_fold_lt_select" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_lt_select" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_lt_select" (f64.const 0.0) (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_lt_select" (f64.const -0.0) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_le_select" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_le_select" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_le_select" (f64.const 0.0) (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_le_select" (f64.const -0.0) (f64.const 0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_gt_select" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_gt_select" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_gt_select" (f64.const 0.0) (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_gt_select" (f64.const -0.0) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_select" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_ge_select" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_select" (f64.const 0.0) (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_select" (f64.const -0.0) (f64.const 0.0)) (f64.const -0.0))
+
+;; Test that x<y?x:y, etc. using if and else aren't folded to min, etc.
+
+(module
+  (func (export "f32.no_fold_lt_if") (param $x f32) (param $y f32) (result f32)
+    (if (result f32) (f32.lt (local.get $x) (local.get $y))
+      (then (local.get $x)) (else (local.get $y))
+    )
+  )
+  (func (export "f32.no_fold_le_if") (param $x f32) (param $y f32) (result f32)
+    (if (result f32) (f32.le (local.get $x) (local.get $y))
+      (then (local.get $x)) (else (local.get $y))
+    )
+  )
+  (func (export "f32.no_fold_gt_if") (param $x f32) (param $y f32) (result f32)
+    (if (result f32) (f32.gt (local.get $x) (local.get $y))
+      (then (local.get $x)) (else (local.get $y))
+    )
+  )
+  (func (export "f32.no_fold_ge_if") (param $x f32) (param $y f32) (result f32)
+    (if (result f32) (f32.ge (local.get $x) (local.get $y))
+      (then (local.get $x)) (else (local.get $y))
+    )
+  )
+
+  (func (export "f64.no_fold_lt_if") (param $x f64) (param $y f64) (result f64)
+    (if (result f64) (f64.lt (local.get $x) (local.get $y))
+      (then (local.get $x)) (else (local.get $y))
+    )
+  )
+  (func (export "f64.no_fold_le_if") (param $x f64) (param $y f64) (result f64)
+    (if (result f64) (f64.le (local.get $x) (local.get $y))
+      (then (local.get $x)) (else (local.get $y))
+    )
+  )
+  (func (export "f64.no_fold_gt_if") (param $x f64) (param $y f64) (result f64)
+    (if (result f64) (f64.gt (local.get $x) (local.get $y))
+      (then (local.get $x)) (else (local.get $y))
+    )
+  )
+  (func (export "f64.no_fold_ge_if") (param $x f64) (param $y f64) (result f64)
+    (if (result f64) (f64.ge (local.get $x) (local.get $y))
+      (then (local.get $x)) (else (local.get $y))
+    )
+  )
+)
+
+(assert_return (invoke "f32.no_fold_lt_if" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_lt_if" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_lt_if" (f32.const 0.0) (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_lt_if" (f32.const -0.0) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_le_if" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_le_if" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_le_if" (f32.const 0.0) (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_le_if" (f32.const -0.0) (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_gt_if" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_gt_if" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_gt_if" (f32.const 0.0) (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_gt_if" (f32.const -0.0) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_if" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_ge_if" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_if" (f32.const 0.0) (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_if" (f32.const -0.0) (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f64.no_fold_lt_if" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_lt_if" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_lt_if" (f64.const 0.0) (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_lt_if" (f64.const -0.0) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_le_if" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_le_if" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_le_if" (f64.const 0.0) (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_le_if" (f64.const -0.0) (f64.const 0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_gt_if" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_gt_if" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_gt_if" (f64.const 0.0) (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_gt_if" (f64.const -0.0) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_if" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_ge_if" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_if" (f64.const 0.0) (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_if" (f64.const -0.0) (f64.const 0.0)) (f64.const -0.0))
+
+;; Test that x<0?-x:x, etc. using select aren't folded to abs.
+
+(module
+  (func (export "f32.no_fold_lt_select_to_abs") (param $x f32) (result f32) (select (f32.neg (local.get $x)) (local.get $x) (f32.lt (local.get $x) (f32.const 0.0))))
+  (func (export "f32.no_fold_le_select_to_abs") (param $x f32) (result f32) (select (f32.neg (local.get $x)) (local.get $x) (f32.le (local.get $x) (f32.const -0.0))))
+  (func (export "f32.no_fold_gt_select_to_abs") (param $x f32) (result f32) (select (local.get $x) (f32.neg (local.get $x)) (f32.gt (local.get $x) (f32.const -0.0))))
+  (func (export "f32.no_fold_ge_select_to_abs") (param $x f32) (result f32) (select (local.get $x) (f32.neg (local.get $x)) (f32.ge (local.get $x) (f32.const 0.0))))
+
+  (func (export "f64.no_fold_lt_select_to_abs") (param $x f64) (result f64) (select (f64.neg (local.get $x)) (local.get $x) (f64.lt (local.get $x) (f64.const 0.0))))
+  (func (export "f64.no_fold_le_select_to_abs") (param $x f64) (result f64) (select (f64.neg (local.get $x)) (local.get $x) (f64.le (local.get $x) (f64.const -0.0))))
+  (func (export "f64.no_fold_gt_select_to_abs") (param $x f64) (result f64) (select (local.get $x) (f64.neg (local.get $x)) (f64.gt (local.get $x) (f64.const -0.0))))
+  (func (export "f64.no_fold_ge_select_to_abs") (param $x f64) (result f64) (select (local.get $x) (f64.neg (local.get $x)) (f64.ge (local.get $x) (f64.const 0.0))))
+)
+
+(assert_return (invoke "f32.no_fold_lt_select_to_abs" (f32.const nan:0x200000)) (f32.const nan:0x200000))
+(assert_return (invoke "f32.no_fold_lt_select_to_abs" (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "f32.no_fold_lt_select_to_abs" (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_lt_select_to_abs" (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_le_select_to_abs" (f32.const nan:0x200000)) (f32.const nan:0x200000))
+(assert_return (invoke "f32.no_fold_le_select_to_abs" (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "f32.no_fold_le_select_to_abs" (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_le_select_to_abs" (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_gt_select_to_abs" (f32.const nan:0x200000)) (f32.const -nan:0x200000))
+(assert_return (invoke "f32.no_fold_gt_select_to_abs" (f32.const -nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_gt_select_to_abs" (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_gt_select_to_abs" (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_select_to_abs" (f32.const nan:0x200000)) (f32.const -nan:0x200000))
+(assert_return (invoke "f32.no_fold_ge_select_to_abs" (f32.const -nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_ge_select_to_abs" (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_select_to_abs" (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f64.no_fold_lt_select_to_abs" (f64.const nan:0x4000000000000)) (f64.const nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_lt_select_to_abs" (f64.const -nan)) (f64.const -nan))
+(assert_return (invoke "f64.no_fold_lt_select_to_abs" (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_lt_select_to_abs" (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_le_select_to_abs" (f64.const nan:0x4000000000000)) (f64.const nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_le_select_to_abs" (f64.const -nan)) (f64.const -nan))
+(assert_return (invoke "f64.no_fold_le_select_to_abs" (f64.const 0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_le_select_to_abs" (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_gt_select_to_abs" (f64.const nan:0x4000000000000)) (f64.const -nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_gt_select_to_abs" (f64.const -nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_gt_select_to_abs" (f64.const 0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_gt_select_to_abs" (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_select_to_abs" (f64.const nan:0x4000000000000)) (f64.const -nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_ge_select_to_abs" (f64.const -nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_ge_select_to_abs" (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_select_to_abs" (f64.const -0.0)) (f64.const -0.0))
+
+;; Test that x<0?-x:x, etc. using if aren't folded to abs.
+
+(module
+  (func (export "f32.no_fold_lt_if_to_abs") (param $x f32) (result f32)
+    (if (result f32) (f32.lt (local.get $x) (f32.const 0.0))
+      (then (f32.neg (local.get $x))) (else (local.get $x))
+    )
+  )
+  (func (export "f32.no_fold_le_if_to_abs") (param $x f32) (result f32)
+    (if (result f32) (f32.le (local.get $x) (f32.const -0.0))
+      (then (f32.neg (local.get $x))) (else (local.get $x))
+    )
+  )
+  (func (export "f32.no_fold_gt_if_to_abs") (param $x f32) (result f32)
+    (if (result f32) (f32.gt (local.get $x) (f32.const -0.0))
+      (then (local.get $x)) (else (f32.neg (local.get $x)))
+    )
+  )
+  (func (export "f32.no_fold_ge_if_to_abs") (param $x f32) (result f32)
+    (if (result f32) (f32.ge (local.get $x) (f32.const 0.0))
+      (then (local.get $x)) (else (f32.neg (local.get $x)))
+    )
+  )
+
+  (func (export "f64.no_fold_lt_if_to_abs") (param $x f64) (result f64)
+    (if (result f64) (f64.lt (local.get $x) (f64.const 0.0))
+      (then (f64.neg (local.get $x))) (else (local.get $x))
+    )
+  )
+  (func (export "f64.no_fold_le_if_to_abs") (param $x f64) (result f64)
+    (if (result f64) (f64.le (local.get $x) (f64.const -0.0))
+      (then (f64.neg (local.get $x))) (else (local.get $x))
+    )
+  )
+  (func (export "f64.no_fold_gt_if_to_abs") (param $x f64) (result f64)
+    (if (result f64) (f64.gt (local.get $x) (f64.const -0.0))
+      (then (local.get $x)) (else (f64.neg (local.get $x)))
+    )
+  )
+  (func (export "f64.no_fold_ge_if_to_abs") (param $x f64) (result f64)
+    (if (result f64) (f64.ge (local.get $x) (f64.const 0.0))
+      (then (local.get $x)) (else (f64.neg (local.get $x)))
+    )
+  )
+)
+
+(assert_return (invoke "f32.no_fold_lt_if_to_abs" (f32.const nan:0x200000)) (f32.const nan:0x200000))
+(assert_return (invoke "f32.no_fold_lt_if_to_abs" (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "f32.no_fold_lt_if_to_abs" (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_lt_if_to_abs" (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_le_if_to_abs" (f32.const nan:0x200000)) (f32.const nan:0x200000))
+(assert_return (invoke "f32.no_fold_le_if_to_abs" (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "f32.no_fold_le_if_to_abs" (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_le_if_to_abs" (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_gt_if_to_abs" (f32.const nan:0x200000)) (f32.const -nan:0x200000))
+(assert_return (invoke "f32.no_fold_gt_if_to_abs" (f32.const -nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_gt_if_to_abs" (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_gt_if_to_abs" (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_if_to_abs" (f32.const nan:0x200000)) (f32.const -nan:0x200000))
+(assert_return (invoke "f32.no_fold_ge_if_to_abs" (f32.const -nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_ge_if_to_abs" (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_if_to_abs" (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f64.no_fold_lt_if_to_abs" (f64.const nan:0x4000000000000)) (f64.const nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_lt_if_to_abs" (f64.const -nan)) (f64.const -nan))
+(assert_return (invoke "f64.no_fold_lt_if_to_abs" (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_lt_if_to_abs" (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_le_if_to_abs" (f64.const nan:0x4000000000000)) (f64.const nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_le_if_to_abs" (f64.const -nan)) (f64.const -nan))
+(assert_return (invoke "f64.no_fold_le_if_to_abs" (f64.const 0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_le_if_to_abs" (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_gt_if_to_abs" (f64.const nan:0x4000000000000)) (f64.const -nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_gt_if_to_abs" (f64.const -nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_gt_if_to_abs" (f64.const 0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_gt_if_to_abs" (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_if_to_abs" (f64.const nan:0x4000000000000)) (f64.const -nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_ge_if_to_abs" (f64.const -nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_ge_if_to_abs" (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_if_to_abs" (f64.const -0.0)) (f64.const -0.0))
+
+;; Test for a historic spreadsheet bug.
+;; https://support.microsoft.com/en-us/kb/78113
+
+(module
+  (func (export "f32.incorrect_correction") (result f32)
+    (f32.sub (f32.sub (f32.add (f32.const 1.333) (f32.const 1.225)) (f32.const 1.333)) (f32.const 1.225))
+  )
+  (func (export "f64.incorrect_correction") (result f64)
+    (f64.sub (f64.sub (f64.add (f64.const 1.333) (f64.const 1.225)) (f64.const 1.333)) (f64.const 1.225))
+  )
+)
+
+(assert_return (invoke "f32.incorrect_correction") (f32.const 0x1p-23))
+(assert_return (invoke "f64.incorrect_correction") (f64.const -0x1p-52))
+
+;; Test for a historical calculator bug.
+;; http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=735
+
+(module
+  (func (export "calculate") (result f32)
+    (local $x f32)
+    (local $r f32)
+    (local $q f32)
+    (local $z0 f32)
+    (local $z1 f32)
+    (local.set $x (f32.const 156.25))
+    (local.set $r (f32.const 208.333333334))
+    (local.set $q (f32.const 1.77951304201))
+    (local.set $z0 (f32.div (f32.mul (f32.neg (local.get $r)) (local.get $x)) (f32.sub (f32.mul (local.get $x) (local.get $q)) (local.get $r))))
+    (local.set $z1 (f32.div (f32.mul (f32.neg (local.get $r)) (local.get $x)) (f32.sub (f32.mul (local.get $x) (local.get $q)) (local.get $r))))
+    (block (br_if 0 (f32.eq (local.get $z0) (local.get $z1))) (unreachable))
+    (local.get $z1)
+  )
+)
+
+(assert_return (invoke "calculate") (f32.const -0x1.d2ed46p+8))
+
+(module
+  (func (export "calculate") (result f64)
+    (local $x f64)
+    (local $r f64)
+    (local $q f64)
+    (local $z0 f64)
+    (local $z1 f64)
+    (local.set $x (f64.const 156.25))
+    (local.set $r (f64.const 208.333333334))
+    (local.set $q (f64.const 1.77951304201))
+    (local.set $z0 (f64.div (f64.mul (f64.neg (local.get $r)) (local.get $x)) (f64.sub (f64.mul (local.get $x) (local.get $q)) (local.get $r))))
+    (local.set $z1 (f64.div (f64.mul (f64.neg (local.get $r)) (local.get $x)) (f64.sub (f64.mul (local.get $x) (local.get $q)) (local.get $r))))
+    (block (br_if 0 (f64.eq (local.get $z0) (local.get $z1))) (unreachable))
+    (local.get $z1)
+  )
+)
+
+(assert_return (invoke "calculate") (f64.const -0x1.d2ed4d0218c93p+8))
+
+;; Test that 0 - (-0 - x) is not optimized to x.
+;; https://llvm.org/bugs/show_bug.cgi?id=26746
+
+(module
+  (func (export "llvm_pr26746") (param $x f32) (result f32)
+    (f32.sub (f32.const 0.0) (f32.sub (f32.const -0.0) (local.get $x)))
+  )
+)
+
+(assert_return (invoke "llvm_pr26746" (f32.const -0.0)) (f32.const 0.0))
+
+;; Test for improperly reassociating an addition and a conversion.
+;; https://llvm.org/bugs/show_bug.cgi?id=27153
+
+(module
+  (func (export "llvm_pr27153") (param $x i32) (result f32)
+    (f32.add (f32.convert_i32_s (i32.and (local.get $x) (i32.const 268435455))) (f32.const -8388608.0))
+  )
+)
+
+(assert_return (invoke "llvm_pr27153" (i32.const 33554434)) (f32.const 25165824.000000))
+
+;; Test that (float)x + (float)y is not optimized to (float)(x + y) when unsafe.
+;; https://llvm.org/bugs/show_bug.cgi?id=27036
+
+(module
+  (func (export "llvm_pr27036") (param $x i32) (param $y i32) (result f32)
+    (f32.add (f32.convert_i32_s (i32.or (local.get $x) (i32.const -25034805)))
+             (f32.convert_i32_s (i32.and (local.get $y) (i32.const 14942208))))
+  )
+)
+
+(assert_return (invoke "llvm_pr27036" (i32.const -25034805) (i32.const 14942208)) (f32.const -0x1.340068p+23))
+
+;; Test for bugs in old versions of historic IEEE 754 platforms as reported in:
+;;
+;; N. L. Schryer. 1981. A Test of a Computer's Floating-Point Arithmetic Unit.
+;; Tech. Rep. Computer Science Technical Report 89, AT&T Bell Laboratories, Feb.
+;;
+;; specifically, the appendices describing IEEE systems with "The Past" sections
+;; describing specific bugs. The 0 < 0 bug is omitted here due to being already
+;; covered elsewhere.
+(module
+  (func (export "thepast0") (param $a f64) (param $b f64) (param $c f64) (param $d f64) (result f64)
+    (f64.div (f64.mul (local.get $a) (local.get $b)) (f64.mul (local.get $c) (local.get $d)))
+  )
+
+  (func (export "thepast1") (param $a f64) (param $b f64) (param $c f64) (result f64)
+    (f64.sub (f64.mul (local.get $a) (local.get $b)) (local.get $c))
+  )
+
+  (func (export "thepast2") (param $a f32) (param $b f32) (param $c f32) (result f32)
+    (f32.mul (f32.mul (local.get $a) (local.get $b)) (local.get $c))
+  )
+)
+
+(assert_return (invoke "thepast0" (f64.const 0x1p-1021) (f64.const 0x1.fffffffffffffp-1) (f64.const 0x1p1) (f64.const 0x1p-1)) (f64.const 0x1.fffffffffffffp-1022))
+(assert_return (invoke "thepast1" (f64.const 0x1p-54) (f64.const 0x1.fffffffffffffp-1) (f64.const 0x1p-54)) (f64.const -0x1p-107))
+(assert_return (invoke "thepast2" (f32.const 0x1p-125) (f32.const 0x1p-1) (f32.const 0x1p0)) (f32.const 0x1p-126))
+
+;; Test for floating point tolerances observed in some GPUs.
+;; https://community.amd.com/thread/145582
+
+(module
+  (func (export "inverse") (param $x f32) (result f32)
+    (f32.div (f32.const 1.0) (local.get $x))
+  )
+)
+
+(assert_return (invoke "inverse" (f32.const 96.0)) (f32.const 0x1.555556p-7))
+
+;; Test for incorrect rounding on sqrt(4.0).
+;; http://www.askvg.com/microsoft-windows-calculator-bug/
+
+(module
+  (func (export "f32_sqrt_minus_2") (param $x f32) (result f32)
+    (f32.sub (f32.sqrt (local.get $x)) (f32.const 2.0))
+  )
+
+  (func (export "f64_sqrt_minus_2") (param $x f64) (result f64)
+    (f64.sub (f64.sqrt (local.get $x)) (f64.const 2.0))
+  )
+)
+
+(assert_return (invoke "f32_sqrt_minus_2" (f32.const 4.0)) (f32.const 0.0))
+(assert_return (invoke "f64_sqrt_minus_2" (f64.const 4.0)) (f64.const 0.0))
+
+;; Test that 1.0 / (1.0 / x) is not optimized to x.
+
+(module
+  (func (export "f32.no_fold_recip_recip") (param $x f32) (result f32)
+    (f32.div (f32.const 1.0) (f32.div (f32.const 1.0) (local.get $x))))
+
+  (func (export "f64.no_fold_recip_recip") (param $x f64) (result f64)
+    (f64.div (f64.const 1.0) (f64.div (f64.const 1.0) (local.get $x))))
+)
+
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const -0x1.e8bf18p+65)) (f32.const -0x1.e8bf16p+65))
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const 0x1.e24248p-77)) (f32.const 0x1.e24246p-77))
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const 0x1.caf0e8p-64)) (f32.const 0x1.caf0eap-64))
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const -0x1.e66982p+4)) (f32.const -0x1.e66984p+4))
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const 0x1.f99916p+70)) (f32.const 0x1.f99914p+70))
+
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const -inf)) (f32.const -inf))
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const inf)) (f32.const inf))
+
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const -0x1.d81248dda63dp+148)) (f64.const -0x1.d81248dda63d1p+148))
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const -0x1.f4750312039e3p+66)) (f64.const -0x1.f4750312039e2p+66))
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const 0x1.fa50630eec7f6p+166)) (f64.const 0x1.fa50630eec7f5p+166))
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const 0x1.db0598617ba92p-686)) (f64.const 0x1.db0598617ba91p-686))
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const 0x1.85f1638a0c82bp+902)) (f64.const 0x1.85f1638a0c82ap+902))
+
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const -inf)) (f64.const -inf))
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const inf)) (f64.const inf))
+
+;; Test that (x+y) * (x-y) is not optimized to x*x - y*y.
+
+(module
+  (func (export "f32.no_algebraic_factoring") (param $x f32) (param $y f32) (result f32)
+    (f32.mul (f32.add (local.get $x) (local.get $y))
+             (f32.sub (local.get $x) (local.get $y))))
+
+  (func (export "f64.no_algebraic_factoring") (param $x f64) (param $y f64) (result f64)
+    (f64.mul (f64.add (local.get $x) (local.get $y))
+             (f64.sub (local.get $x) (local.get $y))))
+)
+
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const -0x1.ef678ep-55) (f32.const 0x1.c160b8p-54)) (f32.const -0x1.129402p-107))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const -0x1.2d76bcp+24) (f32.const 0x1.f4089cp+24)) (f32.const -0x1.36d89ap+49))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const 0x1.7ca2b2p+45) (f32.const -0x1.08513cp+47)) (f32.const -0x1.db10dep+93))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const 0x1.7d5e3p+17) (f32.const -0x1.c783b4p+7)) (f32.const 0x1.1c10a6p+35))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const -0x1.daf96p+7) (f32.const -0x1.dac6bp+19)) (f32.const -0x1.b8422ep+39))
+
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const 0x1.e17c0a02ac6b5p-476) (f64.const 0x1.e8f13f1fcdc14p-463)) (f64.const -0x1.d2ec518f62863p-925))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const 0x1.971b55a57e3a3p-377) (f64.const 0x1.edeb4233c1b27p-399)) (f64.const 0x1.43b3f69fb258bp-753))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const -0x1.c3b9dc02472fap-378) (f64.const -0x1.74e9faebaff14p-369)) (f64.const -0x1.0f9c07e8caa25p-737))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const -0x1.afaf4688ed019p+179) (f64.const 0x1.b07171cb49e94p+188)) (f64.const -0x1.6d3f2e2bebcf7p+377))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const 0x1.4377a98948f12p+114) (f64.const -0x1.500c05bd24c97p+90)) (f64.const 0x1.98b72dbf7bf72p+228))
+
+;; Test that x*x - y*y is not optimized to (x+y) * (x-y).
+
+(module
+  (func (export "f32.no_algebraic_factoring") (param $x f32) (param $y f32) (result f32)
+    (f32.sub (f32.mul (local.get $x) (local.get $x))
+             (f32.mul (local.get $y) (local.get $y))))
+
+  (func (export "f64.no_algebraic_factoring") (param $x f64) (param $y f64) (result f64)
+    (f64.sub (f64.mul (local.get $x) (local.get $x))
+             (f64.mul (local.get $y) (local.get $y))))
+)
+
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const 0x1.8e2c14p-46) (f32.const 0x1.bad59ap-39)) (f32.const -0x1.7efe5p-77))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const -0x1.7ef192p+41) (f32.const -0x1.db184ap+33)) (f32.const 0x1.1e6932p+83))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const 0x1.7eb458p-12) (f32.const -0x1.52c498p-13)) (f32.const 0x1.cc0bc6p-24))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const 0x1.2675c6p-44) (f32.const -0x1.edd31ap-46)) (f32.const 0x1.17294cp-88))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const 0x1.9a5f92p+51) (f32.const -0x1.2b0098p+52)) (f32.const -0x1.7189a6p+103))
+
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const 0x1.749a128f18f69p+356) (f64.const -0x1.0bc97ee1354e1p+337)) (f64.const 0x1.0f28115518d74p+713))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const -0x1.2dab01b2215eap+309) (f64.const -0x1.e12b288bff2bdp+331)) (f64.const -0x1.c4319ad25d201p+663))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const 0x1.3ed898431e102p+42) (f64.const -0x1.c409183fa92e6p+39)) (f64.const 0x1.80a611103c71dp+84))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const -0x1.be663e4c0e4b2p+182) (f64.const -0x1.da85703760d25p+166)) (f64.const 0x1.853434f1a2ffep+365))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const -0x1.230e09952df1cp-236) (f64.const -0x1.fa2752adfadc9p-237)) (f64.const 0x1.42e43156bd1b8p-474))
+
+;; Test that platforms where SIMD instructions flush subnormals don't implicitly
+;; optimize using SIMD instructions.
+
+(module
+  (memory (data
+    "\01\00\00\00\01\00\00\80\01\00\00\00\01\00\00\80"
+    "\01\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\00\00\00\00"
+  ))
+
+  (func (export "f32.simple_x4_sum")
+    (param $i i32)
+    (param $j i32)
+    (param $k i32)
+    (local $x0 f32) (local $x1 f32) (local $x2 f32) (local $x3 f32)
+    (local $y0 f32) (local $y1 f32) (local $y2 f32) (local $y3 f32)
+    (local.set $x0 (f32.load offset=0 (local.get $i)))
+    (local.set $x1 (f32.load offset=4 (local.get $i)))
+    (local.set $x2 (f32.load offset=8 (local.get $i)))
+    (local.set $x3 (f32.load offset=12 (local.get $i)))
+    (local.set $y0 (f32.load offset=0 (local.get $j)))
+    (local.set $y1 (f32.load offset=4 (local.get $j)))
+    (local.set $y2 (f32.load offset=8 (local.get $j)))
+    (local.set $y3 (f32.load offset=12 (local.get $j)))
+    (f32.store offset=0 (local.get $k) (f32.add (local.get $x0) (local.get $y0)))
+    (f32.store offset=4 (local.get $k) (f32.add (local.get $x1) (local.get $y1)))
+    (f32.store offset=8 (local.get $k) (f32.add (local.get $x2) (local.get $y2)))
+    (f32.store offset=12 (local.get $k) (f32.add (local.get $x3) (local.get $y3)))
+  )
+
+  (func (export "f32.load")
+    (param $k i32) (result f32)
+    (f32.load (local.get $k))
+  )
+)
+
+(assert_return (invoke "f32.simple_x4_sum" (i32.const 0) (i32.const 16) (i32.const 32)))
+(assert_return (invoke "f32.load" (i32.const 32)) (f32.const 0x1p-148))
+(assert_return (invoke "f32.load" (i32.const 36)) (f32.const 0x0p+0))
+(assert_return (invoke "f32.load" (i32.const 40)) (f32.const 0x1p-149))
+(assert_return (invoke "f32.load" (i32.const 44)) (f32.const -0x1p-149))
+
+(module
+  (memory (data
+    "\01\00\00\00\00\00\00\00\01\00\00\00\00\00\00\80\01\00\00\00\00\00\00\00\01\00\00\00\00\00\00\80"
+    "\01\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"
+    "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"
+  ))
+
+  (func (export "f64.simple_x4_sum")
+    (param $i i32)
+    (param $j i32)
+    (param $k i32)
+    (local $x0 f64) (local $x1 f64) (local $x2 f64) (local $x3 f64)
+    (local $y0 f64) (local $y1 f64) (local $y2 f64) (local $y3 f64)
+    (local.set $x0 (f64.load offset=0 (local.get $i)))
+    (local.set $x1 (f64.load offset=8 (local.get $i)))
+    (local.set $x2 (f64.load offset=16 (local.get $i)))
+    (local.set $x3 (f64.load offset=24 (local.get $i)))
+    (local.set $y0 (f64.load offset=0 (local.get $j)))
+    (local.set $y1 (f64.load offset=8 (local.get $j)))
+    (local.set $y2 (f64.load offset=16 (local.get $j)))
+    (local.set $y3 (f64.load offset=24 (local.get $j)))
+    (f64.store offset=0 (local.get $k) (f64.add (local.get $x0) (local.get $y0)))
+    (f64.store offset=8 (local.get $k) (f64.add (local.get $x1) (local.get $y1)))
+    (f64.store offset=16 (local.get $k) (f64.add (local.get $x2) (local.get $y2)))
+    (f64.store offset=24 (local.get $k) (f64.add (local.get $x3) (local.get $y3)))
+  )
+
+  (func (export "f64.load")
+    (param $k i32) (result f64)
+    (f64.load (local.get $k))
+  )
+)
+
+(assert_return (invoke "f64.simple_x4_sum" (i32.const 0) (i32.const 32) (i32.const 64)))
+(assert_return (invoke "f64.load" (i32.const 64)) (f64.const 0x0.0000000000001p-1021))
+(assert_return (invoke "f64.load" (i32.const 72)) (f64.const 0x0p+0))
+(assert_return (invoke "f64.load" (i32.const 80)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "f64.load" (i32.const 88)) (f64.const -0x0.0000000000001p-1022))
+
+;; Test that plain summation is not reassociated, and that Kahan summation
+;; isn't optimized into plain summation.
+
+(module
+  (memory (data
+    "\c4\c5\57\24\a5\84\c8\0b\6d\b8\4b\2e\f2\76\17\1c\ca\4a\56\1e\1b\6e\71\22"
+    "\5d\17\1e\6e\bf\cd\14\5c\c7\21\55\51\39\9c\1f\b2\51\f0\a3\93\d7\c1\2c\ae"
+    "\7e\a8\28\3a\01\21\f4\0a\58\93\f8\42\77\9f\83\39\6a\5f\ba\f7\0a\d8\51\6a"
+    "\34\ca\ad\c6\34\0e\d8\26\dc\4c\33\1c\ed\29\90\a8\78\0f\d1\ce\76\31\23\83"
+    "\b8\35\e8\f2\44\b0\d3\a1\fc\bb\32\e1\b0\ba\69\44\09\d6\d9\7d\ff\2e\c0\5a"
+    "\36\14\33\14\3e\a9\fa\87\6d\8b\bc\ce\9d\a7\fd\c4\e9\85\3f\dd\d7\e1\18\a6"
+    "\50\26\72\6e\3f\73\0f\f8\12\93\23\34\61\76\12\48\c0\9b\05\93\eb\ac\86\de"
+    "\94\3e\55\e8\8c\e8\dd\e4\fc\95\47\be\56\03\21\20\4c\e6\bf\7b\f6\7f\d5\ba"
+    "\73\1c\c1\14\8f\c4\27\96\b3\bd\33\ff\78\41\5f\c0\5a\ce\f6\67\6e\73\9a\17"
+    "\66\70\03\f8\ce\27\a3\52\b2\9f\3b\bf\fb\ae\ed\d3\5a\f8\37\57\f0\f5\6e\ef"
+    "\b1\4d\70\3d\54\a7\01\9a\85\08\48\91\f5\9d\0c\60\87\5b\d9\54\1e\51\6d\88"
+    "\8e\08\8c\a5\71\3a\56\08\67\46\8f\8f\13\2a\2c\ec\2c\1f\b4\62\2b\6f\41\0a"
+    "\c4\65\42\a2\31\6b\2c\7d\3e\bb\75\ac\86\97\30\d9\48\cd\9a\1f\56\c4\c6\e4"
+    "\12\c0\9d\fb\ee\02\8c\ce\1c\f2\1e\a1\78\23\db\c4\1e\49\03\d3\71\cc\08\50"
+    "\c5\d8\5c\ed\d5\b5\65\ac\b5\c9\21\d2\c9\29\76\de\f0\30\1a\5b\3c\f2\3b\db"
+    "\3a\39\82\3a\16\08\6f\a8\f1\be\69\69\99\71\a6\05\d3\14\93\2a\16\f2\2f\11"
+    "\c7\7e\20\bb\91\44\ee\f8\e4\01\53\c0\b9\7f\f0\bf\f0\03\9c\6d\b1\df\a2\44"
+    "\01\6d\6b\71\2b\5c\b3\21\19\46\5e\8f\db\91\d3\7c\78\6b\b7\12\00\8f\eb\bd"
+    "\8a\f5\d4\2e\c4\c1\1e\df\73\63\59\47\49\03\0a\b7\cf\24\cf\9c\0e\44\7a\9e"
+    "\14\fb\42\bf\9d\39\30\9e\a0\ab\2f\d1\ae\9e\6a\83\43\e3\55\7d\85\bf\63\8a"
+    "\f8\96\10\1f\fe\6d\e7\22\1b\e1\69\46\8a\44\c8\c8\f9\0c\2b\19\07\a5\02\3e"
+    "\f2\30\10\9a\85\8a\5f\ef\81\45\a0\77\b1\03\10\73\4b\ae\98\9d\47\bf\9a\2d"
+    "\3a\d5\0f\03\66\e3\3d\53\d9\40\ce\1f\6f\32\2f\21\2b\23\21\6c\62\d4\a7\3e"
+    "\a8\ce\28\31\2d\00\3d\67\5e\af\a0\cf\2e\d2\b9\6b\84\eb\69\08\3c\62\36\be"
+    "\12\fd\36\7f\88\3e\ad\bc\0b\c0\41\c4\50\b6\e3\50\31\e8\ce\e2\96\65\55\9c"
+    "\16\46\e6\b0\2d\3a\e8\81\05\b0\bf\34\f7\bc\10\1c\fb\cc\3c\f1\85\97\42\9f"
+    "\eb\14\8d\3c\bf\d7\17\88\49\9d\8b\2b\b2\3a\83\d1\4f\04\9e\a1\0f\ad\08\9d"
+    "\54\af\d1\82\c3\ec\32\2f\02\8f\05\21\2d\a2\b7\e4\f4\6f\2e\81\2b\0b\9c\fc"
+    "\cb\fe\74\02\f9\db\f4\f3\ea\00\a8\ec\d1\99\74\26\dd\d6\34\d5\25\b1\46\dd"
+    "\9c\aa\71\f5\60\b0\88\c8\e0\0b\59\5a\25\4f\29\66\f9\e3\2e\fe\e9\da\e5\18"
+    "\4f\27\62\f4\ce\a4\21\95\74\c7\57\64\27\9a\4c\fd\54\7d\61\ce\c3\ac\87\46"
+    "\9c\fa\ff\09\ca\79\97\67\24\74\ca\d4\21\83\26\25\19\12\37\64\19\e5\65\e0"
+    "\74\75\8e\dd\c8\ef\74\c7\d8\21\2b\79\04\51\46\65\60\03\5d\fa\d8\f4\65\a4"
+    "\9e\5d\23\da\d7\8a\92\80\a4\de\78\3c\f1\57\42\6d\cd\c9\2f\d5\a4\9e\ab\40"
+    "\f4\cb\1b\d7\a3\ca\fc\eb\a7\01\b2\9a\69\4e\46\9b\18\4e\dd\79\a7\aa\a6\52"
+    "\39\1e\ef\30\cc\9b\bd\5b\ee\4c\21\6d\30\00\72\b0\46\5f\08\cf\c5\b9\e0\3e"
+    "\c2\b3\0c\dc\8e\64\de\19\42\79\cf\43\ea\43\5d\8e\88\f7\ab\15\dc\3f\c8\67"
+    "\20\db\b8\64\b1\47\1f\de\f2\cb\3f\59\9f\d8\46\90\dc\ae\2f\22\f9\e2\31\89"
+    "\d9\9c\1c\4c\d3\a9\4a\57\84\9c\9f\ea\2c\3c\ae\3c\c3\1e\8b\e5\4e\17\01\25"
+    "\db\34\46\5f\15\ea\05\0c\7c\d9\45\8c\19\d0\73\8a\96\16\dd\44\f9\05\b7\5b"
+    "\71\b0\e6\21\36\5f\75\89\91\73\75\ab\7d\ae\d3\73\ec\37\c6\ea\55\75\ef\ea"
+    "\ab\8b\7b\11\dc\6d\1a\b2\6a\c4\25\cf\aa\e3\9f\49\49\89\cb\37\9b\0a\a7\01"
+    "\60\70\dc\b7\c8\83\e1\42\f5\be\ad\62\94\ad\8d\a1"
+  ))
+
+  (func (export "f32.kahan_sum") (param $p i32) (param $n i32) (result f32)
+    (local $sum f32)
+    (local $c f32)
+    (local $t f32)
+    (block $exit
+      (loop $top
+        (local.set $t
+          (f32.sub
+            (f32.sub
+              (local.tee $sum
+                (f32.add
+                  (local.get $c)
+                  (local.tee $t
+                    (f32.sub (f32.load (local.get $p)) (local.get $t))
+                  )
+                )
+              )
+              (local.get $c)
+            )
+            (local.get $t)
+          )
+        )
+        (local.set $p (i32.add (local.get $p) (i32.const 4)))
+        (local.set $c (local.get $sum))
+        (br_if $top (local.tee $n (i32.add (local.get $n) (i32.const -1))))
+      )
+    )
+    (local.get $sum)
+  )
+
+  (func (export "f32.plain_sum") (param $p i32) (param $n i32) (result f32)
+    (local $sum f32)
+    (block $exit
+      (loop $top
+        (local.set $sum (f32.add (local.get $sum) (f32.load (local.get $p))))
+        (local.set $p (i32.add (local.get $p) (i32.const 4)))
+        (local.set $n (i32.add (local.get $n) (i32.const -1)))
+        (br_if $top (local.get $n))
+      )
+    )
+    (local.get $sum)
+  )
+)
+
+(assert_return (invoke "f32.kahan_sum" (i32.const 0) (i32.const 256)) (f32.const -0x1.101a1ap+104))
+(assert_return (invoke "f32.plain_sum" (i32.const 0) (i32.const 256)) (f32.const -0x1.a0343ap+103))
+
+(module
+  (memory (data "\13\05\84\42\5d\a2\2c\c6\43\db\55\a9\cd\da\55\e3\73\fc\58\d6\ba\d5\00\fd\83\35\42\88\8b\13\5d\38\4a\47\0d\72\73\a1\1a\ef\c4\45\17\57\d8\c9\46\e0\8d\6c\e1\37\70\c8\83\5b\55\5e\5a\2d\73\1e\56\c8\e1\6d\69\14\78\0a\8a\5a\64\3a\09\c7\a8\87\c5\f0\d3\5d\e6\03\fc\93\be\26\ca\d6\a9\91\60\bd\b0\ed\ae\f7\30\7e\92\3a\6f\a7\59\8e\aa\7d\bf\67\58\2a\54\f8\4e\fe\ed\35\58\a6\51\bf\42\e5\4b\66\27\24\6d\7f\42\2d\28\92\18\ec\08\ae\e7\55\da\b1\a6\65\a5\72\50\47\1b\b8\a9\54\d7\a6\06\5b\0f\42\58\83\8a\17\82\c6\10\43\a0\c0\2e\6d\bc\5a\85\53\72\7f\ad\44\bc\30\3c\55\b2\24\9a\74\3a\9e\e1\d8\0f\70\fc\a9\3a\cd\93\4b\ec\e3\7e\dd\5d\27\cd\f8\a0\9d\1c\11\c0\57\2e\fd\c8\13\32\cc\3a\1a\7d\a3\41\55\ed\c3\82\49\2a\04\1e\ef\73\b9\2e\2e\e3\5f\f4\df\e6\b2\33\0c\39\3f\6f\44\6a\03\c1\42\b9\fa\b1\c8\ed\a5\58\99\7f\ed\b4\72\9e\79\eb\fb\43\82\45\aa\bb\95\d2\ff\28\9e\f6\a1\ad\95\d6\55\95\0d\6f\60\11\c7\78\3e\49\f2\7e\48\f4\a2\71\d0\13\8e\b3\de\99\52\e3\45\74\ea\76\0e\1b\2a\c8\ee\14\01\c4\50\5b\36\3c\ef\ba\72\a2\a6\08\f8\7b\36\9d\f9\ef\0b\c7\56\2d\5c\f0\9d\5d\de\fc\b8\ad\0f\64\0e\97\15\32\26\c2\31\e6\05\1e\ef\cb\17\1b\6d\15\0b\74\5d\d3\2e\f8\6b\86\b4\ba\73\52\53\99\a9\76\20\45\c9\40\80\6b\14\ed\a1\fa\80\46\e6\26\d2\e6\98\c4\57\bf\c4\1c\a4\90\7a\36\94\14\ba\15\89\6e\e6\9c\37\8c\f4\de\12\22\5d\a1\79\50\67\0d\3d\7a\e9\d4\aa\2e\7f\2a\7a\30\3d\ea\5d\12\48\fe\e1\18\cd\a4\57\a2\87\3e\b6\9a\8b\db\da\9d\78\9c\cf\8d\b1\4f\90\b4\34\e0\9d\f6\ca\fe\4c\3b\78\6d\0a\5c\18\9f\61\b9\dd\b4\e0\0f\76\e0\1b\69\0d\5e\58\73\70\5e\0e\2d\a1\7d\ff\20\eb\91\34\92\ac\38\72\2a\1f\8e\71\2e\6a\f1\af\c7\27\70\d9\c4\57\f7\d2\3c\1d\b8\f0\f0\64\cf\dc\ae\be\a3\cc\3e\22\7d\4e\69\21\63\17\ed\03\02\54\9a\0f\50\4e\13\5a\35\a1\22\a4\df\86\c2\74\79\16\b8\69\69\a0\52\5d\11\64\bd\5b\93\fc\69\a0\f4\13\d0\81\51\dd\fa\0c\15\c3\7a\c9\62\7a\a9\1d\c9\e6\5a\b3\5b\97\02\3c\64\22\12\3c\22\90\64\2d\30\54\4c\b4\a1\22\09\57\22\5e\8e\38\2b\02\a8\ae\f6\be\0d\2b\f2\03\ad\fa\10\01\71\77\2a\30\02\95\f6\00\3e\d0\c4\8d\34\19\50\21\0a\bc\50\da\3c\30\d6\3a\31\94\8d\3a\fe\ef\14\57\9d\4b\93\00\96\24\0c\6f\fd\bc\23\76\02\6c\eb\52\72\80\11\7e\80\3a\13\12\38\1d\38\49\95\40\27\8a\44\7b\e8\dc\6d\8c\8c\8e\3c\b5\b3\18\0e\f6\08\1a\84\41\35\ff\8b\b8\93\40\ea\e1\51\1d\89\a5\8d\42\68\29\ea\2f\c1\7a\52\eb\90\5d\4d\d6\80\e3\d7\75\48\ce\ed\d3\01\1c\8d\5b\a5\94\0d\78\cf\f1\06\13\2f\98\02\a4\6d\2e\6c\f2\d5\74\29\89\4c\f9\03\f5\c7\18\ad\7a\f0\68\f8\5c\d6\59\87\6e\d6\3f\06\be\86\20\e3\41\91\22\f3\6e\8b\f0\68\1c\57\a7\fc\b0\7c\9e\99\0b\96\1a\89\5f\e6\0d\7c\08\51\a0\a2\67\9a\47\00\93\6b\f9\28\f0\68\db\62\f1\e0\65\2c\53\33\e0\a7\ca\11\42\30\f6\af\01\c1\65\3d\32\01\6f\ab\2e\be\d3\8b\be\14\c3\ff\ec\fb\f0\f9\c5\0c\05\6f\01\09\6b\e3\34\31\0c\1f\66\a6\42\bc\1a\87\49\16\16\8c\b0\90\0d\34\8c\0a\e1\09\5e\10\a4\6b\56\cc\f0\c9\bb\dc\b8\5c\ce\f6\cc\8d\75\7e\b3\07\88\04\2f\b4\5e\c9\e3\4a\23\73\19\62\6c\9a\03\76\44\86\9c\60\fc\db\72\8f\27\a0\dd\b3\c5\da\ff\f9\ec\6a\b1\7b\d3\cf\50\37\c9\7a\78\0c\e4\3a\b6\f5\e6\f4\98\6e\42\7d\35\73\8b\45\c0\56\97\cd\6d\ce\cf\ad\31\b3\c3\54\fa\ef\d5\c0\f4\6a\5f\54\e7\49\3e\33\0a\30\38\fd\d9\05\ff\a5\3f\57\46\14\b5\91\17\ca\6b\98\23\7a\65\b3\6c\02\b4\cc\79\5d\58\d8\b3\d5\94\ae\f4\6d\75\65\f7\92\bf\7e\47\4c\3c\ee\db\ac\f1\32\5d\fb\6f\41\1c\34\c8\83\4f\c2\58\01\be\05\3e\66\16\a6\04\6d\5d\4f\86\09\27\82\25\12\cd\3a\cd\ce\6b\bc\ca\ac\28\9b\ee\6a\25\86\9e\45\70\c6\d2\bd\3b\7d\42\e5\27\af\c7\1d\f4\81\c8\b3\76\8a\a8\36\a3\ae\2a\e6\18\e1\36\22\ad\f6\25\72\b0\39\8b\01\9a\22\7b\84\c3\2d\5f\72\a4\98\ac\15\70\e7\d4\18\e2\7d\d2\30\7c\33\08\cd\ca\c4\22\85\88\75\81\c6\4a\74\58\8d\e0\e8\ac\c5\ab\75\5a\f4\28\12\f0\18\45\52\f2\97\b2\93\41\6f\8d\7f\db\70\fb\a3\5d\1f\a7\8d\98\20\2b\22\9f\3a\01\b5\8b\1b\d2\cb\14\03\0e\14\14\d2\19\5a\1f\ce\5e\cd\81\79\15\01\ca\de\73\74\8c\56\20\9f\77\2d\25\16\f6\61\51\1d\a4\8e\9b\98\a5\c6\ec\a8\45\57\82\59\78\0d\90\b4\df\51\b0\c3\82\94\cc\b3\53\09\15\6d\96\6c\3a\40\47\b7\4a\7a\05\2f\a1\1e\8c\9d\a0\20\88\fb\52\b7\9f\f3\f3\bb\5f\e7\8a\61\a7\21\b1\ac\fa\09\aa\a4\6c\bc\24\80\ba\2a\e9\65\ff\70\ff\cc\fa\65\87\76\f3\c5\15\ce\cb\e8\42\31\00\0c\91\57\d9\e0\9d\35\54\24\ad\a4\d8\f9\08\67\63\c8\cf\81\dd\90\a2\d7\c4\07\4a\e6\10\6f\67\e7\27\d4\23\59\18\f2\a8\9d\5f\d8\94\30\aa\54\86\4f\87\9d\82\b5\26\ca\a6\96\bf\cf\55\f9\9d\37\01\19\48\43\c5\94\6c\f3\74\97\58\4c\3c\9d\08\e8\04\c2\58\30\76\e1\a0\f8\ea\e9\c5\ae\cf\78\9e\a9\0c\ac\b3\44\42\e0\bc\5d\1b\9c\49\58\4a\1c\19\49\c1\3a\ea\f5\eb\3b\81\a9\4b\70\0c\cc\9e\1a\d3\2f\b7\52\2f\20\3b\eb\64\51\1d\a0\2d\b2\3e\be\13\85\48\92\32\2e\db\5c\a1\e7\8c\45\91\35\01\0a\93\c2\eb\09\ce\f3\d2\22\24\d0\8c\cc\1d\9d\38\c8\4d\e3\82\cc\64\15\06\2d\e7\01\2f\ab\bb\b5\04\4c\92\1c\7a\d6\3f\e8\5f\31\15\0c\dc\e4\31\b4\c4\25\3e\2a\aa\00\9e\c8\e5\21\7a\7f\29\f1\c0\af\1d\5e\e8\63\39\ad\f8\7e\6c\c8\c5\7f\c2\a8\97\27\0a\d9\f4\21\6a\ea\03\09\fb\f7\96\3b\83\79\5f\7c\4b\30\9f\56\35\de\b4\73\d4\95\f0\14\c3\74\2f\0d\a3\1d\4e\8d\31\24\b3\1a\84\85\62\5a\7b\3c\14\39\17\e6\6d\eb\37\c2\00\58\5b\0b\e3\3c\8a\62\e1\f8\35\4b\56\e2\87\60\8b\be\a7\38\91\77\54\a9\5a\24\25\90\9f\a5\42\77\f3\5c\39\df\ff\74\07\76\a1\cd\1f\62\0b\81\81\68\af\05\c1\c0\7f\26\ee\c0\91\a3\6a\7d\29\61\45\27\e5\57\88\dc\0d\97\04\1a\33\a9\44\8a\da\02\10\45\3f\8e\55\a6\76\8c\4d\e3\f1\89\83\c8\d0\f8\9b\50\77\9f\47\df\4c\9c\66\0d\aa\18\b8\5f\4f\c4\01\ce\dc\84\ac\46\9e\69\e1\76\45\6b\61\89\e4\5d\94\bb\11\83\9f\78\d8\0a\d2\f5\7e\5d\43\ea\bc\10\f1\3a\c9\e2\64\fb\53\65\d0\c7\b4\a7\fb\d4\05\53\25\d0\cd\29\88\00\56\25\24\7d\5d\b4\f3\41\9f\e9\b5\f7\ae\64\2c\e3\c9\6d\d5\84\3a\72\12\b8\7a\d9\1b\09\e8\38\da\26\4f\04\ce\03\71\6e\8a\44\7b\5c\81\59\9c\d2\e4\c3\ba\59\a6\e5\28\a7\8f\9a\e4\d5\4e\b9\ca\7f\cb\75\b8\2b\43\3e\b3\15\46\b1\a5\bc\9d\9e\38\15\f1\bd\1b\21\aa\f1\82\00\95\fc\a7\77\47\39\a7\33\43\92\d7\52\40\4b\06\81\8a\a0\bd\f1\6b\99\84\42\5b\e2\3b\c5\5e\12\5c\28\4d\b6\0e\4e\c8\5c\e8\01\8a\c5\e7\e4\9d\42\ee\5d\9c\c4\eb\eb\68\09\27\92\95\9a\11\54\73\c4\12\80\fb\7d\fe\c5\08\60\7f\36\41\e0\10\ba\d6\2b\6c\f1\b4\17\fe\26\34\e3\4b\f8\a8\e3\91\be\4f\2a\fc\da\81\b8\e7\fe\d5\26\50\47\f3\1a\65\32\81\e0\05\b8\4f\32\31\26\00\4a\53\97\c2\c3\0e\2e\a1\26\54\ab\05\8e\56\2f\7d\af\22\84\68\a5\8b\97\f6\a4\fd\a8\cc\75\41\96\86\fd\27\3d\29\86\8d\7f\4c\d4\8e\73\41\f4\1e\e2\dd\58\27\97\ce\9c\94\cf\7a\04\2f\dc\ed"
+  ))
+
+  (func (export "f64.kahan_sum") (param $p i32) (param $n i32) (result f64)
+    (local $sum f64)
+    (local $c f64)
+    (local $t f64)
+    (block $exit
+      (loop $top
+        (local.set $t
+          (f64.sub
+            (f64.sub
+              (local.tee $sum
+                (f64.add
+                  (local.get $c)
+                  (local.tee $t
+                    (f64.sub (f64.load (local.get $p)) (local.get $t))
+                  )
+                )
+              )
+              (local.get $c)
+            )
+            (local.get $t)
+          )
+        )
+        (local.set $p (i32.add (local.get $p) (i32.const 8)))
+        (local.set $c (local.get $sum))
+        (br_if $top (local.tee $n (i32.add (local.get $n) (i32.const -1))))
+      )
+    )
+    (local.get $sum)
+  )
+
+  (func (export "f64.plain_sum") (param $p i32) (param $n i32) (result f64)
+    (local $sum f64)
+    (block $exit
+      (loop $top
+        (local.set $sum (f64.add (local.get $sum) (f64.load (local.get $p))))
+        (local.set $p (i32.add (local.get $p) (i32.const 8)))
+        (local.set $n (i32.add (local.get $n) (i32.const -1)))
+        (br_if $top (local.get $n))
+      )
+    )
+    (local.get $sum)
+  )
+)
+
+(assert_return (invoke "f64.kahan_sum" (i32.const 0) (i32.const 256)) (f64.const 0x1.dd7cb2a5ffc88p+998))
+(assert_return (invoke "f64.plain_sum" (i32.const 0) (i32.const 256)) (f64.const 0x1.dd7cb2a63fc87p+998))
+
+;; Test that -(x - y) is not folded to y - x.
+
+(module
+  (func (export "f32.no_fold_neg_sub") (param $x f32) (param $y f32) (result f32)
+    (f32.neg (f32.sub (local.get $x) (local.get $y))))
+
+  (func (export "f64.no_fold_neg_sub") (param $x f64) (param $y f64) (result f64)
+    (f64.neg (f64.sub (local.get $x) (local.get $y))))
+)
+
+(assert_return (invoke "f32.no_fold_neg_sub" (f32.const -0.0) (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_neg_sub" (f32.const 0.0) (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_neg_sub" (f32.const -0.0) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_neg_sub" (f32.const 0.0) (f32.const 0.0)) (f32.const -0.0))
+
+(assert_return (invoke "f64.no_fold_neg_sub" (f64.const -0.0) (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_neg_sub" (f64.const 0.0) (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_neg_sub" (f64.const -0.0) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_neg_sub" (f64.const 0.0) (f64.const 0.0)) (f64.const -0.0))
+
+;; Test that -(x + y) is not folded to (-x + -y).
+
+(module
+  (func (export "f32.no_fold_neg_add") (param $x f32) (param $y f32) (result f32)
+    (f32.neg (f32.add (local.get $x) (local.get $y))))
+
+  (func (export "f64.no_fold_neg_add") (param $x f64) (param $y f64) (result f64)
+    (f64.neg (f64.add (local.get $x) (local.get $y))))
+)
+
+(assert_return (invoke "f32.no_fold_neg_add" (f32.const -0.0) (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_neg_add" (f32.const 0.0) (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_neg_add" (f32.const -0.0) (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_neg_add" (f32.const 0.0) (f32.const 0.0)) (f32.const -0.0))
+
+(assert_return (invoke "f64.no_fold_neg_add" (f64.const -0.0) (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_neg_add" (f64.const 0.0) (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_neg_add" (f64.const -0.0) (f64.const 0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_neg_add" (f64.const 0.0) (f64.const 0.0)) (f64.const -0.0))
+
+;; Test that (-x + -y) is not folded to -(x + y).
+
+(module
+  (func (export "f32.no_fold_add_neg_neg") (param $x f32) (param $y f32) (result f32)
+    (f32.add (f32.neg (local.get $x)) (f32.neg (local.get $y))))
+
+  (func (export "f64.no_fold_add_neg_neg") (param $x f64) (param $y f64) (result f64)
+    (f64.add (f64.neg (local.get $x)) (f64.neg (local.get $y))))
+)
+
+(assert_return (invoke "f32.no_fold_add_neg_neg" (f32.const -0.0) (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_add_neg_neg" (f32.const 0.0) (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_add_neg_neg" (f32.const -0.0) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_add_neg_neg" (f32.const 0.0) (f32.const 0.0)) (f32.const -0.0))
+
+(assert_return (invoke "f64.no_fold_add_neg_neg" (f64.const -0.0) (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_add_neg_neg" (f64.const 0.0) (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_add_neg_neg" (f64.const -0.0) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_add_neg_neg" (f64.const 0.0) (f64.const 0.0)) (f64.const -0.0))
+
+;; Test that -x + x is not folded to 0.0.
+
+(module
+  (func (export "f32.no_fold_add_neg") (param $x f32) (result f32)
+    (f32.add (f32.neg (local.get $x)) (local.get $x)))
+
+  (func (export "f64.no_fold_add_neg") (param $x f64) (result f64)
+    (f64.add (f64.neg (local.get $x)) (local.get $x)))
+)
+
+(assert_return (invoke "f32.no_fold_add_neg" (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_add_neg" (f32.const -0.0)) (f32.const 0.0))
+(assert_return_canonical_nan (invoke "f32.no_fold_add_neg" (f32.const inf)))
+(assert_return_canonical_nan (invoke "f32.no_fold_add_neg" (f32.const -inf)))
+
+(assert_return (invoke "f64.no_fold_add_neg" (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_add_neg" (f64.const -0.0)) (f64.const 0.0))
+(assert_return_canonical_nan (invoke "f64.no_fold_add_neg" (f64.const inf)))
+(assert_return_canonical_nan (invoke "f64.no_fold_add_neg" (f64.const -inf)))
+
+;; Test that x+x+x+x+x+x is not folded to x * 6.
+
+(module
+  (func (export "f32.no_fold_6x_via_add") (param $x f32) (result f32)
+    (f32.add (f32.add (f32.add (f32.add (f32.add
+    (local.get $x)
+    (local.get $x)) (local.get $x)) (local.get $x))
+    (local.get $x)) (local.get $x)))
+
+  (func (export "f64.no_fold_6x_via_add") (param $x f64) (result f64)
+    (f64.add (f64.add (f64.add (f64.add (f64.add
+    (local.get $x)
+    (local.get $x)) (local.get $x)) (local.get $x))
+    (local.get $x)) (local.get $x)))
+)
+
+(assert_return (invoke "f32.no_fold_6x_via_add" (f32.const -0x1.598a0cp+99)) (f32.const -0x1.03278ap+102))
+(assert_return (invoke "f32.no_fold_6x_via_add" (f32.const -0x1.d3e7acp-77)) (f32.const -0x1.5eedc2p-74))
+(assert_return (invoke "f32.no_fold_6x_via_add" (f32.const 0x1.00fa02p-77)) (f32.const 0x1.817702p-75))
+(assert_return (invoke "f32.no_fold_6x_via_add" (f32.const -0x1.51f434p-31)) (f32.const -0x1.faee4cp-29))
+(assert_return (invoke "f32.no_fold_6x_via_add" (f32.const -0x1.00328ap+80)) (f32.const -0x1.804bcep+82))
+
+(assert_return (invoke "f64.no_fold_6x_via_add" (f64.const -0x1.310e15acaffe6p+68)) (f64.const -0x1.c995208307fdap+70))
+(assert_return (invoke "f64.no_fold_6x_via_add" (f64.const -0x1.aad62c78fa9b4p-535)) (f64.const -0x1.4020a15abbf46p-532))
+(assert_return (invoke "f64.no_fold_6x_via_add" (f64.const -0x1.f8fbfa94f6ab2p+271)) (f64.const -0x1.7abcfbefb9005p+274))
+(assert_return (invoke "f64.no_fold_6x_via_add" (f64.const 0x1.756ccc2830a8ep+751)) (f64.const 0x1.1811991e247ebp+754))
+(assert_return (invoke "f64.no_fold_6x_via_add" (f64.const -0x1.8fd1ab1d2402ap+234)) (f64.const -0x1.2bdd4055db01fp+237))
+
+;; Test that (x/y)/z is not optimized to x/(y*z),
+;; which is an "allowable alternative Form" in Fortran.
+
+(module
+  (func (export "f32.no_fold_div_div") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.div (f32.div (local.get $x) (local.get $y)) (local.get $z)))
+
+  (func (export "f64.no_fold_div_div") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.div (f64.div (local.get $x) (local.get $y)) (local.get $z)))
+)
+
+(assert_return (invoke "f32.no_fold_div_div" (f32.const -0x1.f70228p+78) (f32.const -0x1.fbc612p-16) (f32.const -0x1.8c379p+10)) (f32.const -0x1.47b43cp+83))
+(assert_return (invoke "f32.no_fold_div_div" (f32.const 0x1.d29d2ep-70) (f32.const 0x1.f3a17ep+110) (f32.const -0x1.64d41p-112)) (f32.const -0x0p+0))
+(assert_return (invoke "f32.no_fold_div_div" (f32.const 0x1.867f98p+43) (f32.const 0x1.30acfcp-105) (f32.const 0x1.e210d8p+105)) (f32.const inf))
+(assert_return (invoke "f32.no_fold_div_div" (f32.const -0x1.c4001ap-14) (f32.const -0x1.9beb6cp+124) (f32.const -0x1.74f34cp-43)) (f32.const -0x1.819874p-96))
+(assert_return (invoke "f32.no_fold_div_div" (f32.const 0x1.db0e6ep+46) (f32.const 0x1.55eea2p+56) (f32.const -0x1.f3134p+124)) (f32.const -0x1.6cep-135))
+
+(assert_return (invoke "f64.no_fold_div_div" (f64.const 0x1.b4dc8ec3c7777p+337) (f64.const 0x1.9f95ac2d1863p+584) (f64.const -0x1.d4318abba341ep-782)) (f64.const -0x1.2649159d87e02p+534))
+(assert_return (invoke "f64.no_fold_div_div" (f64.const -0x1.ac53af5eb445fp+791) (f64.const 0x1.8549c0a4ceb13p-29) (f64.const 0x1.64e384003c801p+316)) (f64.const -0x1.9417cdccbae91p+503))
+(assert_return (invoke "f64.no_fold_div_div" (f64.const -0x1.d2685afb27327p+2) (f64.const -0x1.abb1eeed3dbebp+880) (f64.const 0x1.a543e2e6968a3p+170)) (f64.const 0x0.0000002a69a5fp-1022))
+(assert_return (invoke "f64.no_fold_div_div" (f64.const -0x1.47ddede78ad1cp+825) (f64.const 0x1.6d932d070a367p-821) (f64.const 0x1.79cf18cc64fp+961)) (f64.const -inf))
+(assert_return (invoke "f64.no_fold_div_div" (f64.const -0x1.f73d4979a9379p-888) (f64.const 0x1.4d83b53e97788p-596) (f64.const -0x1.f8f86c9603b5bp-139)) (f64.const 0x1.87a7bd89c586cp-154))
+
+;; Test that (x/y)*(z/w) is not optimized to (x*z)/(y*w), example from
+;; http://perso.ens-lyon.fr/jean-michel.muller/Handbook.html
+;; section 7.4.1: FORTRAN Floating Point in a Nutshell: Philosophy
+
+(module
+  (func (export "f32.no_fold_mul_divs") (param $x f32) (param $y f32) (param $z f32) (param $w f32) (result f32)
+    (f32.mul (f32.div (local.get $x) (local.get $y)) (f32.div (local.get $z) (local.get $w))))
+
+  (func (export "f64.no_fold_mul_divs") (param $x f64) (param $y f64) (param $z f64) (param $w f64) (result f64)
+    (f64.mul (f64.div (local.get $x) (local.get $y)) (f64.div (local.get $z) (local.get $w))))
+)
+
+(assert_return (invoke "f32.no_fold_mul_divs" (f32.const -0x1.c483bep-109) (f32.const 0x1.ee1c3cp-92) (f32.const 0x1.800756p-88) (f32.const -0x1.95b972p+4)) (f32.const 0x1.bbd30cp-110))
+(assert_return (invoke "f32.no_fold_mul_divs" (f32.const -0x1.0f4262p+102) (f32.const 0x1.248498p+25) (f32.const 0x1.f66a7cp-17) (f32.const 0x1.897fc8p-3)) (f32.const -0x1.2f1aa4p+63))
+(assert_return (invoke "f32.no_fold_mul_divs" (f32.const -0x1.df5f22p+33) (f32.const -0x1.fcee3ep+39) (f32.const -0x1.9ea914p+29) (f32.const -0x1.2c4d3p+10)) (f32.const 0x1.4cf51cp+13))
+(assert_return (invoke "f32.no_fold_mul_divs" (f32.const -0x1.f568bcp+109) (f32.const 0x1.d9963p-34) (f32.const 0x1.37a87ap-16) (f32.const 0x1.a1524ap+78)) (f32.const -inf))
+(assert_return (invoke "f32.no_fold_mul_divs" (f32.const 0x1.3dd592p-53) (f32.const -0x1.332c22p-64) (f32.const 0x1.b01064p-91) (f32.const 0x1.92bb3ap-36)) (f32.const -0x1.1c2dbp-44))
+
+(assert_return (invoke "f64.no_fold_mul_divs" (f64.const -0x1.363d6764f7b12p-819) (f64.const -0x1.ed5471f660b5fp-464) (f64.const -0x1.671b0a7f3a42p+547) (f64.const 0x1.0633be34ba1f2p+186)) (f64.const -0x1.b8fa2b76baeebp+5))
+(assert_return (invoke "f64.no_fold_mul_divs" (f64.const -0x1.37880182e0fa8p+115) (f64.const 0x1.f842631576147p-920) (f64.const -0x1.999372231d156p+362) (f64.const -0x1.d5db481ab9554p+467)) (f64.const -inf))
+(assert_return (invoke "f64.no_fold_mul_divs" (f64.const -0x1.9a747c8d4b541p+308) (f64.const -0x1.99092ad6bbdc8p+192) (f64.const -0x1.cb23755c20101p-140) (f64.const -0x1.de8716f6b0b6ap+732)) (f64.const 0x1.ecf584c8466a5p-757))
+(assert_return (invoke "f64.no_fold_mul_divs" (f64.const -0x1.c424b2ece903dp+129) (f64.const -0x1.568ce281db37fp-347) (f64.const 0x1.53900b99fd3dp-957) (f64.const 0x1.5c33952254dadp+223)) (f64.const 0x0p+0))
+(assert_return (invoke "f64.no_fold_mul_divs" (f64.const 0x1.a8ec2cecb32a9p-18) (f64.const 0x1.58acab0051851p-277) (f64.const 0x1.35e87c9077f7fp-620) (f64.const -0x1.925ee37ffb386p+352)) (f64.const -0x1.e6286970b31bfp-714))
+
+;; Test that (x/z)+(y/z) is not optimized to (x+y)/z.
+
+(module
+  (func (export "f32.no_fold_add_divs") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.add (f32.div (local.get $x) (local.get $z)) (f32.div (local.get $y) (local.get $z))))
+
+  (func (export "f64.no_fold_add_divs") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.add (f64.div (local.get $x) (local.get $z)) (f64.div (local.get $y) (local.get $z))))
+)
+
+(assert_return (invoke "f32.no_fold_add_divs" (f32.const 0x1.795e7p+8) (f32.const -0x1.48a5eep-5) (f32.const -0x1.9a244cp+126)) (f32.const -0x1.d709b6p-119))
+(assert_return (invoke "f32.no_fold_add_divs" (f32.const -0x1.ae89e8p-63) (f32.const -0x1.e9903ep-49) (f32.const -0x1.370a8cp+47)) (f32.const 0x1.92f3f6p-96))
+(assert_return (invoke "f32.no_fold_add_divs" (f32.const -0x1.626408p-46) (f32.const 0x1.2ee5b2p-64) (f32.const -0x1.ecefaap+48)) (f32.const 0x1.701864p-95))
+(assert_return (invoke "f32.no_fold_add_divs" (f32.const -0x1.061d3p-101) (f32.const 0x1.383492p-98) (f32.const -0x1.1d92d2p+88)) (f32.const 0x0p+0))
+(assert_return (invoke "f32.no_fold_add_divs" (f32.const 0x1.1ea39ep-10) (f32.const 0x1.a7fffep-3) (f32.const 0x1.6fc574p-123)) (f32.const 0x1.28b2dep+120))
+
+(assert_return (invoke "f64.no_fold_add_divs" (f64.const -0x1.c5fcc3273b136p+430) (f64.const 0x1.892a09eed8f6fp+434) (f64.const 0x1.8258b71e64397p+911)) (f64.const 0x1.e36eb9706ad82p-478))
+(assert_return (invoke "f64.no_fold_add_divs" (f64.const -0x1.2215d4061b5b3p+53) (f64.const 0x1.fb6184d97f27cp+5) (f64.const -0x1.f3bb59dacc0ebp-957)) (f64.const 0x1.2934eb0118be3p+1009))
+(assert_return (invoke "f64.no_fold_add_divs" (f64.const -0x1.e7a4533741d8ep-967) (f64.const 0x1.a519bb7feb802p-976) (f64.const 0x1.1f8a43454e51ap+504)) (f64.const 0x0p+0))
+(assert_return (invoke "f64.no_fold_add_divs" (f64.const 0x1.991c6cf93e2b4p+313) (f64.const -0x1.f2f7432698d11p+329) (f64.const 0x1.0d8c1b2453617p-126)) (f64.const -0x1.d9e1d84ddd1d4p+455))
+(assert_return (invoke "f64.no_fold_add_divs" (f64.const -0x1.d436849dc1271p-728) (f64.const 0x1.19d1c1450e52dp-755) (f64.const 0x1.fa1be69ea06fep-70)) (f64.const -0x1.d9a9b1c2f5623p-659))
+
+;; Test that sqrt(x*x) is not optimized to abs(x).
+
+(module
+  (func (export "f32.no_fold_sqrt_square") (param $x f32) (result f32)
+    (f32.sqrt (f32.mul (local.get $x) (local.get $x))))
+
+  (func (export "f64.no_fold_sqrt_square") (param $x f64) (result f64)
+    (f64.sqrt (f64.mul (local.get $x) (local.get $x))))
+)
+
+(assert_return (invoke "f32.no_fold_sqrt_square" (f32.const -0x1.5cb316p-66)) (f32.const 0x1.5cb322p-66))
+(assert_return (invoke "f32.no_fold_sqrt_square" (f32.const -0x1.b0f9e4p-73)) (f32.const 0x1.b211b2p-73))
+(assert_return (invoke "f32.no_fold_sqrt_square" (f32.const -0x1.de417cp-71)) (f32.const 0x1.de65b8p-71))
+(assert_return (invoke "f32.no_fold_sqrt_square" (f32.const 0x1.64c872p-86)) (f32.const 0x0p+0))
+(assert_return (invoke "f32.no_fold_sqrt_square" (f32.const 0x1.e199e4p+108)) (f32.const inf))
+
+(assert_return (invoke "f64.no_fold_sqrt_square" (f64.const 0x1.1759d657203fdp-529)) (f64.const 0x1.1759dd57545f3p-529))
+(assert_return (invoke "f64.no_fold_sqrt_square" (f64.const -0x1.4c68de1c78d83p-514)) (f64.const 0x1.4c68de1c78d81p-514))
+(assert_return (invoke "f64.no_fold_sqrt_square" (f64.const -0x1.214736edb6e1ep-521)) (f64.const 0x1.214736ed9cf8dp-521))
+(assert_return (invoke "f64.no_fold_sqrt_square" (f64.const -0x1.0864b9f68457p-616)) (f64.const 0x0p+0))
+(assert_return (invoke "f64.no_fold_sqrt_square" (f64.const 0x1.b2a9855995abap+856)) (f64.const inf))
+
+;; Test that sqrt(x)*sqrt(y) is not optimized to sqrt(x*y).
+
+(module
+  (func (export "f32.no_fold_mul_sqrts") (param $x f32) (param $y f32) (result f32)
+    (f32.mul (f32.sqrt (local.get $x)) (f32.sqrt (local.get $y))))
+
+  (func (export "f64.no_fold_mul_sqrts") (param $x f64) (param $y f64) (result f64)
+    (f64.mul (f64.sqrt (local.get $x)) (f64.sqrt (local.get $y))))
+)
+
+(assert_return_canonical_nan (invoke "f32.no_fold_mul_sqrts" (f32.const 0x1.dddda8p-125) (f32.const -0x1.25d22ap-83)))
+(assert_return (invoke "f32.no_fold_mul_sqrts" (f32.const 0x1.418d14p-92) (f32.const 0x1.c6535cp-32)) (f32.const 0x1.7e373ap-62))
+(assert_return (invoke "f32.no_fold_mul_sqrts" (f32.const 0x1.4de7ep-88) (f32.const 0x1.84ff18p+6)) (f32.const 0x1.686668p-41))
+(assert_return (invoke "f32.no_fold_mul_sqrts" (f32.const 0x1.78091ep+101) (f32.const 0x1.81feb8p-9)) (f32.const 0x1.7cfb98p+46))
+(assert_return (invoke "f32.no_fold_mul_sqrts" (f32.const 0x1.583ap-56) (f32.const 0x1.14ba2ap-9)) (f32.const 0x1.b47a8ep-33))
+
+(assert_return_canonical_nan (invoke "f64.no_fold_mul_sqrts" (f64.const -0x1.d1144cc28cdbep-635) (f64.const -0x1.bf9bc373d3b6ap-8)))
+(assert_return (invoke "f64.no_fold_mul_sqrts" (f64.const 0x1.5a7eb976bebc9p-643) (f64.const 0x1.f30cb8865a4cap-404)) (f64.const 0x1.260a1032d6e76p-523))
+(assert_return (invoke "f64.no_fold_mul_sqrts" (f64.const 0x1.711a0c1707935p-89) (f64.const 0x1.6fb5de51a20d3p-913)) (f64.const 0x1.7067ca28e31ecp-501))
+(assert_return (invoke "f64.no_fold_mul_sqrts" (f64.const 0x1.fb0bbea33b076p-363) (f64.const 0x1.d963b34894158p-573)) (f64.const 0x1.e9edc1fa624afp-468))
+(assert_return (invoke "f64.no_fold_mul_sqrts" (f64.const 0x1.8676eab7a4d0dp+24) (f64.const 0x1.75a58231ba7a5p+513)) (f64.const 0x1.0e16aebe203b3p+269))
+
+;; Test that sqrt(x)/sqrt(y) is not optimized to sqrt(x/y).
+
+(module
+  (func (export "f32.no_fold_div_sqrts") (param $x f32) (param $y f32) (result f32)
+    (f32.div (f32.sqrt (local.get $x)) (f32.sqrt (local.get $y))))
+
+  (func (export "f64.no_fold_div_sqrts") (param $x f64) (param $y f64) (result f64)
+    (f64.div (f64.sqrt (local.get $x)) (f64.sqrt (local.get $y))))
+)
+
+(assert_return_canonical_nan (invoke "f32.no_fold_div_sqrts" (f32.const -0x1.bea9bap+25) (f32.const -0x1.db776ep-58)))
+(assert_return (invoke "f32.no_fold_div_sqrts" (f32.const 0x1.b983b6p+32) (f32.const 0x1.901f1ep+27)) (f32.const 0x1.7c4df6p+2))
+(assert_return (invoke "f32.no_fold_div_sqrts" (f32.const 0x1.d45e72p-120) (f32.const 0x1.ab49ccp+15)) (f32.const 0x1.7b0b04p-68))
+(assert_return (invoke "f32.no_fold_div_sqrts" (f32.const 0x1.b2e444p+59) (f32.const 0x1.5b8b16p-30)) (f32.const 0x1.94fca8p+44))
+(assert_return (invoke "f32.no_fold_div_sqrts" (f32.const 0x1.835aa6p-112) (f32.const 0x1.d17128p-103)) (f32.const 0x1.4a468p-5))
+
+(assert_return_canonical_nan (invoke "f64.no_fold_div_sqrts" (f64.const -0x1.509fc16411167p-711) (f64.const -0x1.9c4255f5d6517p-187)))
+(assert_return (invoke "f64.no_fold_div_sqrts" (f64.const 0x1.b6897bddac76p-587) (f64.const 0x1.104578b4c91f3p+541)) (f64.const 0x1.44e4f21f26cc9p-564))
+(assert_return (invoke "f64.no_fold_div_sqrts" (f64.const 0x1.ac83451b08989p+523) (f64.const 0x1.8da575c6d12b8p-109)) (f64.const 0x1.09c003991ce17p+316))
+(assert_return (invoke "f64.no_fold_div_sqrts" (f64.const 0x1.bab7836456417p-810) (f64.const 0x1.1ff60d03ba607p+291)) (f64.const 0x1.c0e6c833bf657p-551))
+(assert_return (invoke "f64.no_fold_div_sqrts" (f64.const 0x1.a957816ad9515p-789) (f64.const 0x1.8c18a3a222ab1p+945)) (f64.const 0x1.0948539781e92p-867))
+
+;; Test that (x*sqrt(y))/y is not optimized to x/sqrt(y).
+
+(module
+  (func (export "f32.no_fold_mul_sqrt_div") (param $x f32) (param $y f32) (result f32)
+    (f32.div (f32.mul (local.get $x) (f32.sqrt (local.get $y))) (local.get $y)))
+
+  (func (export "f64.no_fold_mul_sqrt_div") (param $x f64) (param $y f64) (result f64)
+    (f64.div (f64.mul (local.get $x) (f64.sqrt (local.get $y))) (local.get $y)))
+)
+
+(assert_return (invoke "f32.no_fold_mul_sqrt_div" (f32.const -0x1.f4a7cap+81) (f32.const 0x1.c09adep+92)) (f32.const -inf))
+(assert_return (invoke "f32.no_fold_mul_sqrt_div" (f32.const -0x1.90bf1cp-120) (f32.const 0x1.8dbe88p-97)) (f32.const -0x0p+0))
+(assert_return (invoke "f32.no_fold_mul_sqrt_div" (f32.const 0x1.8570e8p+29) (f32.const 0x1.217d3p-128)) (f32.const 0x1.6e391ap+93))
+(assert_return (invoke "f32.no_fold_mul_sqrt_div" (f32.const -0x1.5b4652p+43) (f32.const 0x1.a9d71cp+112)) (f32.const -0x1.0d423ap-13))
+(assert_return (invoke "f32.no_fold_mul_sqrt_div" (f32.const -0x1.910604p+8) (f32.const 0x1.0ca912p+7)) (f32.const -0x1.14cdecp+5))
+
+(assert_return (invoke "f64.no_fold_mul_sqrt_div" (f64.const 0x1.1dcdeb857305fp+698) (f64.const 0x1.a066171c40eb9p+758)) (f64.const inf))
+(assert_return (invoke "f64.no_fold_mul_sqrt_div" (f64.const -0x1.8b4f1c218e2abp-827) (f64.const 0x1.5e1ee65953b0bp-669)) (f64.const -0x0p+0))
+(assert_return (invoke "f64.no_fold_mul_sqrt_div" (f64.const 0x1.74ee531ddba38p-425) (f64.const 0x1.f370f758857f3p+560)) (f64.const 0x1.0aff34269583ep-705))
+(assert_return (invoke "f64.no_fold_mul_sqrt_div" (f64.const -0x1.27f216b0da6c5p+352) (f64.const 0x1.8e0b4e0b9fd7ep-483)) (f64.const -0x1.4fa558aad514ep+593))
+(assert_return (invoke "f64.no_fold_mul_sqrt_div" (f64.const 0x1.4c6955df9912bp+104) (f64.const 0x1.0cca42c9d371ep+842)) (f64.const 0x1.4468072f54294p-317))
+
+;; Test that subnormals are not flushed even in an intermediate value in an
+;; expression with a normal result.
+
+(module
+  (func (export "f32.no_flush_intermediate_subnormal") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.mul (f32.mul (local.get $x) (local.get $y)) (local.get $z)))
+
+  (func (export "f64.no_flush_intermediate_subnormal") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.mul (f64.mul (local.get $x) (local.get $y)) (local.get $z)))
+)
+
+(assert_return (invoke "f32.no_flush_intermediate_subnormal" (f32.const 0x1p-126) (f32.const 0x1p-23) (f32.const 0x1p23)) (f32.const 0x1p-126))
+(assert_return (invoke "f64.no_flush_intermediate_subnormal" (f64.const 0x1p-1022) (f64.const 0x1p-52) (f64.const 0x1p52)) (f64.const 0x1p-1022))
+
+;; Test corner cases of John Hauser's microarchitectural recoding scheme.
+;; https://github.com/riscv/riscv-tests/blob/695b86a6fcbe06ffbed8891af7e6fe7bf2062543/isa/rv64uf/recoding.S
+
+(module
+  (func (export "f32.recoding_eq") (param $x f32) (param $y f32) (result i32)
+    (f32.eq (f32.mul (local.get $x) (local.get $y)) (local.get $x)))
+
+  (func (export "f32.recoding_le") (param $x f32) (param $y f32) (result i32)
+    (f32.le (f32.mul (local.get $x) (local.get $y)) (local.get $x)))
+
+  (func (export "f32.recoding_lt") (param $x f32) (param $y f32) (result i32)
+    (f32.lt (f32.mul (local.get $x) (local.get $y)) (local.get $x)))
+
+  (func (export "f64.recoding_eq") (param $x f64) (param $y f64) (result i32)
+    (f64.eq (f64.mul (local.get $x) (local.get $y)) (local.get $x)))
+
+  (func (export "f64.recoding_le") (param $x f64) (param $y f64) (result i32)
+    (f64.le (f64.mul (local.get $x) (local.get $y)) (local.get $x)))
+
+  (func (export "f64.recoding_lt") (param $x f64) (param $y f64) (result i32)
+    (f64.lt (f64.mul (local.get $x) (local.get $y)) (local.get $x)))
+
+  (func (export "recoding_demote") (param $x f64) (param $y f32) (result f32)
+    (f32.mul (f32.demote_f64 (local.get $x)) (local.get $y)))
+)
+
+(assert_return (invoke "f32.recoding_eq" (f32.const -inf) (f32.const 3.0)) (i32.const 1))
+(assert_return (invoke "f32.recoding_le" (f32.const -inf) (f32.const 3.0)) (i32.const 1))
+(assert_return (invoke "f32.recoding_lt" (f32.const -inf) (f32.const 3.0)) (i32.const 0))
+
+(assert_return (invoke "f32.recoding_eq" (f32.const 0x0p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "f32.recoding_le" (f32.const 0x0p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "f32.recoding_lt" (f32.const 0x0p+0) (f32.const 0x1p+0)) (i32.const 0))
+
+(assert_return (invoke "f64.recoding_eq" (f64.const -inf) (f64.const 3.0)) (i32.const 1))
+(assert_return (invoke "f64.recoding_le" (f64.const -inf) (f64.const 3.0)) (i32.const 1))
+(assert_return (invoke "f64.recoding_lt" (f64.const -inf) (f64.const 3.0)) (i32.const 0))
+
+(assert_return (invoke "f64.recoding_eq" (f64.const 0x0p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "f64.recoding_le" (f64.const 0x0p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "f64.recoding_lt" (f64.const 0x0p+0) (f64.const 0x1p+0)) (i32.const 0))
+
+(assert_return (invoke "recoding_demote" (f64.const 0x1.4c8f8p-132) (f32.const 1221)) (f32.const 0x1.8c8a1cp-122))
+
+;; Test that division is not done as on an extended-base system.
+;; http://www.ucbtest.org/goldberg/addendum.html
+
+(module
+  (func (export "f32.no_extended_precision_div") (param $x f32) (param $y f32) (param $z f32) (result i32)
+    (f32.eq (f32.div (local.get $x) (local.get $y)) (local.get $z)))
+
+  (func (export "f64.no_extended_precision_div") (param $x f64) (param $y f64) (param $z f64) (result i32)
+    (f64.eq (f64.div (local.get $x) (local.get $y)) (local.get $z)))
+)
+
+(assert_return (invoke "f32.no_extended_precision_div" (f32.const 3.0) (f32.const 7.0) (f32.const 0x1.b6db6ep-2)) (i32.const 1))
+(assert_return (invoke "f64.no_extended_precision_div" (f64.const 3.0) (f64.const 7.0) (f64.const 0x1.b6db6db6db6dbp-2)) (i32.const 1))
+
+;; a*x + b*x == (a+b)*x for all x only if the operations a*x, b*x, and (a+b)
+;; are all exact operations, which is true only if a and b are exact powers of
+;; 2. Even then, if a==-b and x==-0, then a*x+b*x==0.0, (a+b)*x==-0.0.
+;; https://dlang.org/d-floating-point.html
+
+(module
+  (func (export "f32.no_distribute_exact") (param $x f32) (result f32)
+    (f32.add (f32.mul (f32.const -8.0) (local.get $x)) (f32.mul (f32.const 8.0) (local.get $x))))
+
+  (func (export "f64.no_distribute_exact") (param $x f64) (result f64)
+    (f64.add (f64.mul (f64.const -8.0) (local.get $x)) (f64.mul (f64.const 8.0) (local.get $x))))
+)
+
+(assert_return (invoke "f32.no_distribute_exact" (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f64.no_distribute_exact" (f64.const -0.0)) (f64.const 0.0))
+
+;; Test that various approximations of sqrt(2), sqrt(3), and sqrt(5) compute the
+;; expected approximation.
+;; https://xkcd.com/1047/
+(module
+  (func (export "f32.sqrt") (param f32) (result f32)
+    (f32.sqrt (local.get 0)))
+
+  (func (export "f32.xkcd_sqrt_2") (param f32) (param f32) (param f32) (param f32) (result f32)
+    (f32.add (f32.div (local.get 0) (local.get 1)) (f32.div (local.get 2) (f32.sub (local.get 3) (local.get 2)))))
+
+  (func (export "f32.xkcd_sqrt_3") (param f32) (param f32) (param f32) (result f32)
+    (f32.div (f32.mul (local.get 0) (local.get 1)) (local.get 2)))
+
+  (func (export "f32.xkcd_sqrt_5") (param f32) (param f32) (param f32) (result f32)
+    (f32.add (f32.div (local.get 0) (local.get 1)) (f32.div (local.get 2) (local.get 0))))
+
+  (func (export "f32.xkcd_better_sqrt_5") (param f32) (param f32) (param f32) (param f32) (result f32)
+    (f32.div (f32.add (local.get 0) (f32.mul (local.get 1) (local.get 2))) (f32.sub (local.get 3) (f32.mul (local.get 1) (local.get 2)))))
+
+  (func (export "f64.sqrt") (param f64) (result f64)
+    (f64.sqrt (local.get 0)))
+
+  (func (export "f64.xkcd_sqrt_2") (param f64) (param f64) (param f64) (param f64) (result f64)
+    (f64.add (f64.div (local.get 0) (local.get 1)) (f64.div (local.get 2) (f64.sub (local.get 3) (local.get 2)))))
+
+  (func (export "f64.xkcd_sqrt_3") (param f64) (param f64) (param f64) (result f64)
+    (f64.div (f64.mul (local.get 0) (local.get 1)) (local.get 2)))
+
+  (func (export "f64.xkcd_sqrt_5") (param f64) (param f64) (param f64) (result f64)
+    (f64.add (f64.div (local.get 0) (local.get 1)) (f64.div (local.get 2) (local.get 0))))
+
+  (func (export "f64.xkcd_better_sqrt_5") (param f64) (param f64) (param f64) (param f64) (result f64)
+    (f64.div (f64.add (local.get 0) (f64.mul (local.get 1) (local.get 2))) (f64.sub (local.get 3) (f64.mul (local.get 1) (local.get 2)))))
+)
+
+(assert_return (invoke "f32.sqrt" (f32.const 2.0)) (f32.const 0x1.6a09e6p+0))
+(assert_return (invoke "f32.xkcd_sqrt_2" (f32.const 3.0) (f32.const 5.0) (f32.const 0x1.921fb6p+1) (f32.const 7.0)) (f32.const 0x1.6a0a54p+0))
+(assert_return (invoke "f32.sqrt" (f32.const 3.0)) (f32.const 0x1.bb67aep+0))
+(assert_return (invoke "f32.xkcd_sqrt_3" (f32.const 2.0) (f32.const 0x1.5bf0a8p+1) (f32.const 0x1.921fb6p+1)) (f32.const 0x1.bb02d4p+0))
+(assert_return (invoke "f32.sqrt" (f32.const 5.0)) (f32.const 0x1.1e377ap+1))
+(assert_return (invoke "f32.xkcd_sqrt_5" (f32.const 2.0) (f32.const 0x1.5bf0a8p+1) (f32.const 3.0)) (f32.const 0x1.1e2d58p+1))
+(assert_return (invoke "f32.xkcd_better_sqrt_5" (f32.const 13.0) (f32.const 4.0) (f32.const 0x1.921fb6p+1) (f32.const 24.0)) (f32.const 0x1.1e377ap+1))
+
+(assert_return (invoke "f64.sqrt" (f64.const 2.0)) (f64.const 0x1.6a09e667f3bcdp+0))
+(assert_return (invoke "f64.xkcd_sqrt_2" (f64.const 3.0) (f64.const 5.0) (f64.const 0x1.921fb54442d18p+1) (f64.const 7.0)) (f64.const 0x1.6a0a5362b055fp+0))
+(assert_return (invoke "f64.sqrt" (f64.const 3.0)) (f64.const 0x1.bb67ae8584caap+0))
+(assert_return (invoke "f64.xkcd_sqrt_3" (f64.const 2.0) (f64.const 0x1.5bf0a8b145769p+1) (f64.const 0x1.921fb54442d18p+1)) (f64.const 0x1.bb02d4eca8f95p+0))
+(assert_return (invoke "f64.sqrt" (f64.const 5.0)) (f64.const 0x1.1e3779b97f4a8p+1))
+(assert_return (invoke "f64.xkcd_sqrt_5" (f64.const 2.0) (f64.const 0x1.5bf0a8b145769p+1) (f64.const 3.0)) (f64.const 0x1.1e2d58d8b3bcep+1))
+(assert_return (invoke "f64.xkcd_better_sqrt_5" (f64.const 13.0) (f64.const 4.0) (f64.const 0x1.921fb54442d18p+1) (f64.const 24.0)) (f64.const 0x1.1e3778509a5a3p+1))
+
+;; Compute the floating-point radix.
+;; M. A. Malcom. Algorithms to reveal properties of floating-point arithmetic.
+;; Communications of the ACM, 15(11):949-951, November 1972.
+(module
+  (func (export "f32.compute_radix") (param $0 f32) (param $1 f32) (result f32)
+    (loop $label$0
+      (br_if $label$0
+        (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)
+        )
+      )
+    )
+    (loop $label$2
+      (br_if $label$2
+        (f32.ne
+          (f32.sub
+            (f32.sub
+              (f32.add
+                (local.get $0)
+                (local.tee $1 (f32.add (local.get $1) (f32.const 1)))
+              )
+              (local.get $0)
+            )
+            (local.get $1)
+          )
+          (f32.const 0)
+        )
+      )
+    )
+    (local.get $1)
+  )
+
+  (func (export "f64.compute_radix") (param $0 f64) (param $1 f64) (result f64)
+    (loop $label$0
+      (br_if $label$0
+        (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$2
+      (br_if $label$2
+        (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)
+  )
+)
+
+(assert_return (invoke "f32.compute_radix" (f32.const 1.0) (f32.const 1.0)) (f32.const 2.0))
+(assert_return (invoke "f64.compute_radix" (f64.const 1.0) (f64.const 1.0)) (f64.const 2.0))
+
+;; Test that (x - 1) * y + y is not optimized to x * y.
+;; http://blog.frama-c.com/index.php?post/2013/05/14/Contrarianism
+
+(module
+  (func (export "f32.no_fold_sub1_mul_add") (param $x f32) (param $y f32) (result f32)
+    (f32.add (f32.mul (f32.sub (local.get $x) (f32.const 1.0)) (local.get $y)) (local.get $y)))
+
+  (func (export "f64.no_fold_sub1_mul_add") (param $x f64) (param $y f64) (result f64)
+    (f64.add (f64.mul (f64.sub (local.get $x) (f64.const 1.0)) (local.get $y)) (local.get $y)))
+)
+
+(assert_return (invoke "f32.no_fold_sub1_mul_add" (f32.const 0x1p-32) (f32.const 1.0)) (f32.const 0x0p+0))
+(assert_return (invoke "f64.no_fold_sub1_mul_add" (f64.const 0x1p-64) (f64.const 1.0)) (f64.const 0x0p+0))
+
+;; Test that x+z >= y+z is not optimized to x >= y (monotonicity).
+;; http://cs.nyu.edu/courses/spring13/CSCI-UA.0201-003/lecture6.pdf
+
+(module
+  (func (export "f32.no_fold_add_le_monotonicity") (param $x f32) (param $y f32) (param $z f32) (result i32)
+    (f32.le (f32.add (local.get $x) (local.get $z)) (f32.add (local.get $y) (local.get $z))))
+
+  (func (export "f32.no_fold_add_ge_monotonicity") (param $x f32) (param $y f32) (param $z f32) (result i32)
+    (f32.ge (f32.add (local.get $x) (local.get $z)) (f32.add (local.get $y) (local.get $z))))
+
+  (func (export "f64.no_fold_add_le_monotonicity") (param $x f64) (param $y f64) (param $z f64) (result i32)
+    (f64.le (f64.add (local.get $x) (local.get $z)) (f64.add (local.get $y) (local.get $z))))
+
+  (func (export "f64.no_fold_add_ge_monotonicity") (param $x f64) (param $y f64) (param $z f64) (result i32)
+    (f64.ge (f64.add (local.get $x) (local.get $z)) (f64.add (local.get $y) (local.get $z))))
+)
+
+(assert_return (invoke "f32.no_fold_add_le_monotonicity" (f32.const 0.0) (f32.const 0.0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "f32.no_fold_add_le_monotonicity" (f32.const inf) (f32.const -inf) (f32.const inf)) (i32.const 0))
+(assert_return (invoke "f64.no_fold_add_le_monotonicity" (f64.const 0.0) (f64.const 0.0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "f64.no_fold_add_le_monotonicity" (f64.const inf) (f64.const -inf) (f64.const inf)) (i32.const 0))
+
+;; Test that !(x < y) and friends are not optimized to x >= y and friends.
+
+(module
+  (func (export "f32.not_lt") (param $x f32) (param $y f32) (result i32)
+    (i32.eqz (f32.lt (local.get $x) (local.get $y))))
+
+  (func (export "f32.not_le") (param $x f32) (param $y f32) (result i32)
+    (i32.eqz (f32.le (local.get $x) (local.get $y))))
+
+  (func (export "f32.not_gt") (param $x f32) (param $y f32) (result i32)
+    (i32.eqz (f32.gt (local.get $x) (local.get $y))))
+
+  (func (export "f32.not_ge") (param $x f32) (param $y f32) (result i32)
+    (i32.eqz (f32.ge (local.get $x) (local.get $y))))
+
+  (func (export "f64.not_lt") (param $x f64) (param $y f64) (result i32)
+    (i32.eqz (f64.lt (local.get $x) (local.get $y))))
+
+  (func (export "f64.not_le") (param $x f64) (param $y f64) (result i32)
+    (i32.eqz (f64.le (local.get $x) (local.get $y))))
+
+  (func (export "f64.not_gt") (param $x f64) (param $y f64) (result i32)
+    (i32.eqz (f64.gt (local.get $x) (local.get $y))))
+
+  (func (export "f64.not_ge") (param $x f64) (param $y f64) (result i32)
+    (i32.eqz (f64.ge (local.get $x) (local.get $y))))
+)
+
+(assert_return (invoke "f32.not_lt" (f32.const nan) (f32.const 0.0)) (i32.const 1))
+(assert_return (invoke "f32.not_le" (f32.const nan) (f32.const 0.0)) (i32.const 1))
+(assert_return (invoke "f32.not_gt" (f32.const nan) (f32.const 0.0)) (i32.const 1))
+(assert_return (invoke "f32.not_ge" (f32.const nan) (f32.const 0.0)) (i32.const 1))
+(assert_return (invoke "f64.not_lt" (f64.const nan) (f64.const 0.0)) (i32.const 1))
+(assert_return (invoke "f64.not_le" (f64.const nan) (f64.const 0.0)) (i32.const 1))
+(assert_return (invoke "f64.not_gt" (f64.const nan) (f64.const 0.0)) (i32.const 1))
+(assert_return (invoke "f64.not_ge" (f64.const nan) (f64.const 0.0)) (i32.const 1))
+
+;; Test that a method for approximating a "machine epsilon" produces the expected
+;; approximation.
+;; http://blogs.mathworks.com/cleve/2014/07/07/floating-point-numbers/#24cb4f4d-b8a9-4c19-b22b-9d2a9f7f3812
+
+(module
+  (func (export "f32.epsilon") (result f32)
+    (f32.sub (f32.const 1.0) (f32.mul (f32.const 3.0) (f32.sub (f32.div (f32.const 4.0) (f32.const 3.0)) (f32.const 1.0)))))
+
+  (func (export "f64.epsilon") (result f64)
+    (f64.sub (f64.const 1.0) (f64.mul (f64.const 3.0) (f64.sub (f64.div (f64.const 4.0) (f64.const 3.0)) (f64.const 1.0)))))
+)
+
+(assert_return (invoke "f32.epsilon") (f32.const -0x1p-23))
+(assert_return (invoke "f64.epsilon") (f64.const 0x1p-52))
+
+;; Test that a method for computing a "machine epsilon" produces the expected
+;; result.
+;; https://www.math.utah.edu/~beebe/software/ieee/
+
+(module
+  (func (export "f32.epsilon") (result f32)
+    (local $x f32)
+    (local $result f32)
+    (local.set $x (f32.const 1))
+    (loop $loop
+      (br_if $loop
+        (f32.gt
+          (f32.add
+            (local.tee $x
+              (f32.mul
+                (local.tee $result (local.get $x))
+                (f32.const 0.5)
+              )
+            )
+            (f32.const 1)
+          )
+          (f32.const 1)
+        )
+      )
+    )
+    (local.get $result)
+  )
+
+  (func (export "f64.epsilon") (result f64)
+    (local $x f64)
+    (local $result f64)
+    (local.set $x (f64.const 1))
+    (loop $loop
+      (br_if $loop
+        (f64.gt
+          (f64.add
+            (local.tee $x
+              (f64.mul
+                (local.tee $result (local.get $x))
+                (f64.const 0.5)
+              )
+            )
+            (f64.const 1)
+          )
+          (f64.const 1)
+        )
+      )
+    )
+    (local.get $result)
+  )
+)
+
+(assert_return (invoke "f32.epsilon") (f32.const 0x1p-23))
+(assert_return (invoke "f64.epsilon") (f64.const 0x1p-52))
+
+;; Test that floating-point numbers are not optimized as if they form a
+;; trichotomy.
+
+(module
+  (func (export "f32.no_trichotomy_lt") (param $x f32) (param $y f32) (result i32)
+    (i32.or (f32.lt (local.get $x) (local.get $y)) (f32.ge (local.get $x) (local.get $y))))
+  (func (export "f32.no_trichotomy_le") (param $x f32) (param $y f32) (result i32)
+    (i32.or (f32.le (local.get $x) (local.get $y)) (f32.gt (local.get $x) (local.get $y))))
+  (func (export "f32.no_trichotomy_gt") (param $x f32) (param $y f32) (result i32)
+    (i32.or (f32.gt (local.get $x) (local.get $y)) (f32.le (local.get $x) (local.get $y))))
+  (func (export "f32.no_trichotomy_ge") (param $x f32) (param $y f32) (result i32)
+    (i32.or (f32.ge (local.get $x) (local.get $y)) (f32.lt (local.get $x) (local.get $y))))
+
+  (func (export "f64.no_trichotomy_lt") (param $x f64) (param $y f64) (result i32)
+    (i32.or (f64.lt (local.get $x) (local.get $y)) (f64.ge (local.get $x) (local.get $y))))
+  (func (export "f64.no_trichotomy_le") (param $x f64) (param $y f64) (result i32)
+    (i32.or (f64.le (local.get $x) (local.get $y)) (f64.gt (local.get $x) (local.get $y))))
+  (func (export "f64.no_trichotomy_gt") (param $x f64) (param $y f64) (result i32)
+    (i32.or (f64.gt (local.get $x) (local.get $y)) (f64.le (local.get $x) (local.get $y))))
+  (func (export "f64.no_trichotomy_ge") (param $x f64) (param $y f64) (result i32)
+    (i32.or (f64.ge (local.get $x) (local.get $y)) (f64.lt (local.get $x) (local.get $y))))
+)
+
+(assert_return (invoke "f32.no_trichotomy_lt" (f32.const 0.0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "f32.no_trichotomy_le" (f32.const 0.0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "f32.no_trichotomy_gt" (f32.const 0.0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "f32.no_trichotomy_ge" (f32.const 0.0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "f64.no_trichotomy_lt" (f64.const 0.0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "f64.no_trichotomy_le" (f64.const 0.0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "f64.no_trichotomy_gt" (f64.const 0.0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "f64.no_trichotomy_ge" (f64.const 0.0) (f64.const nan)) (i32.const 0))
+
+;; Some test harnesses which can run this testsuite are unable to perform tests
+;; of NaN bitpatterns. The following tests whether the underlying platform is
+;; generally producing the kinds of NaNs expected.
+(module
+  (func (export "f32.arithmetic_nan_bitpattern")
+        (param $x i32) (param $y i32) (result i32)
+    (i32.and (i32.reinterpret_f32
+               (f32.div
+                 (f32.reinterpret_i32 (local.get $x))
+                 (f32.reinterpret_i32 (local.get $y))))
+             (i32.const 0x7fc00000)))
+  (func (export "f32.canonical_nan_bitpattern")
+        (param $x i32) (param $y i32) (result i32)
+    (i32.and (i32.reinterpret_f32
+               (f32.div
+                 (f32.reinterpret_i32 (local.get $x))
+                 (f32.reinterpret_i32 (local.get $y))))
+             (i32.const 0x7fffffff)))
+  (func (export "f32.nonarithmetic_nan_bitpattern")
+        (param $x i32) (result i32)
+    (i32.reinterpret_f32 (f32.neg (f32.reinterpret_i32 (local.get $x)))))
+
+  (func (export "f64.arithmetic_nan_bitpattern")
+        (param $x i64) (param $y i64) (result i64)
+    (i64.and (i64.reinterpret_f64
+               (f64.div
+                 (f64.reinterpret_i64 (local.get $x))
+                 (f64.reinterpret_i64 (local.get $y))))
+             (i64.const 0x7ff8000000000000)))
+  (func (export "f64.canonical_nan_bitpattern")
+        (param $x i64) (param $y i64) (result i64)
+    (i64.and (i64.reinterpret_f64
+               (f64.div
+                 (f64.reinterpret_i64 (local.get $x))
+                 (f64.reinterpret_i64 (local.get $y))))
+             (i64.const 0x7fffffffffffffff)))
+  (func (export "f64.nonarithmetic_nan_bitpattern")
+        (param $x i64) (result i64)
+    (i64.reinterpret_f64 (f64.neg (f64.reinterpret_i64 (local.get $x)))))
+
+  ;; Versions of no_fold testcases that only care about NaN bitpatterns.
+  (func (export "f32.no_fold_sub_zero") (param $x i32) (result i32)
+    (i32.and (i32.reinterpret_f32 (f32.sub (f32.reinterpret_i32 (local.get $x)) (f32.const 0.0)))
+             (i32.const 0x7fc00000)))
+  (func (export "f32.no_fold_neg0_sub") (param $x i32) (result i32)
+    (i32.and (i32.reinterpret_f32 (f32.sub (f32.const -0.0) (f32.reinterpret_i32 (local.get $x))))
+             (i32.const 0x7fc00000)))
+  (func (export "f32.no_fold_mul_one") (param $x i32) (result i32)
+    (i32.and (i32.reinterpret_f32 (f32.mul (f32.reinterpret_i32 (local.get $x)) (f32.const 1.0)))
+             (i32.const 0x7fc00000)))
+  (func (export "f32.no_fold_neg1_mul") (param $x i32) (result i32)
+    (i32.and (i32.reinterpret_f32 (f32.mul (f32.const -1.0) (f32.reinterpret_i32 (local.get $x))))
+             (i32.const 0x7fc00000)))
+  (func (export "f32.no_fold_div_one") (param $x i32) (result i32)
+    (i32.and (i32.reinterpret_f32 (f32.div (f32.reinterpret_i32 (local.get $x)) (f32.const 1.0)))
+             (i32.const 0x7fc00000)))
+  (func (export "f32.no_fold_div_neg1") (param $x i32) (result i32)
+    (i32.and (i32.reinterpret_f32 (f32.div (f32.reinterpret_i32 (local.get $x)) (f32.const -1.0)))
+             (i32.const 0x7fc00000)))
+  (func (export "f64.no_fold_sub_zero") (param $x i64) (result i64)
+    (i64.and (i64.reinterpret_f64 (f64.sub (f64.reinterpret_i64 (local.get $x)) (f64.const 0.0)))
+             (i64.const 0x7ff8000000000000)))
+  (func (export "f64.no_fold_neg0_sub") (param $x i64) (result i64)
+    (i64.and (i64.reinterpret_f64 (f64.sub (f64.const -0.0) (f64.reinterpret_i64 (local.get $x))))
+             (i64.const 0x7ff8000000000000)))
+  (func (export "f64.no_fold_mul_one") (param $x i64) (result i64)
+    (i64.and (i64.reinterpret_f64 (f64.mul (f64.reinterpret_i64 (local.get $x)) (f64.const 1.0)))
+             (i64.const 0x7ff8000000000000)))
+  (func (export "f64.no_fold_neg1_mul") (param $x i64) (result i64)
+    (i64.and (i64.reinterpret_f64 (f64.mul (f64.const -1.0) (f64.reinterpret_i64 (local.get $x))))
+             (i64.const 0x7ff8000000000000)))
+  (func (export "f64.no_fold_div_one") (param $x i64) (result i64)
+    (i64.and (i64.reinterpret_f64 (f64.div (f64.reinterpret_i64 (local.get $x)) (f64.const 1.0)))
+             (i64.const 0x7ff8000000000000)))
+  (func (export "f64.no_fold_div_neg1") (param $x i64) (result i64)
+    (i64.and (i64.reinterpret_f64 (f64.div (f64.reinterpret_i64 (local.get $x)) (f64.const -1.0)))
+             (i64.const 0x7ff8000000000000)))
+  (func (export "no_fold_promote_demote") (param $x i32) (result i32)
+    (i32.and (i32.reinterpret_f32 (f32.demote_f64 (f64.promote_f32 (f32.reinterpret_i32 (local.get $x)))))
+             (i32.const 0x7fc00000)))
+)
+
+(assert_return (invoke "f32.arithmetic_nan_bitpattern" (i32.const 0x7f803210) (i32.const 0x7f803210)) (i32.const 0x7fc00000))
+(assert_return (invoke "f32.canonical_nan_bitpattern" (i32.const 0) (i32.const 0)) (i32.const 0x7fc00000))
+(assert_return (invoke "f32.canonical_nan_bitpattern" (i32.const 0x7fc00000) (i32.const 0x7fc00000)) (i32.const 0x7fc00000))
+(assert_return (invoke "f32.canonical_nan_bitpattern" (i32.const 0xffc00000) (i32.const 0x7fc00000)) (i32.const 0x7fc00000))
+(assert_return (invoke "f32.canonical_nan_bitpattern" (i32.const 0x7fc00000) (i32.const 0xffc00000)) (i32.const 0x7fc00000))
+(assert_return (invoke "f32.canonical_nan_bitpattern" (i32.const 0xffc00000) (i32.const 0xffc00000)) (i32.const 0x7fc00000))
+(assert_return (invoke "f32.nonarithmetic_nan_bitpattern" (i32.const 0x7fc03210)) (i32.const 0xffc03210))
+(assert_return (invoke "f32.nonarithmetic_nan_bitpattern" (i32.const 0xffc03210)) (i32.const 0x7fc03210))
+(assert_return (invoke "f32.nonarithmetic_nan_bitpattern" (i32.const 0x7f803210)) (i32.const 0xff803210))
+(assert_return (invoke "f32.nonarithmetic_nan_bitpattern" (i32.const 0xff803210)) (i32.const 0x7f803210))
+(assert_return (invoke "f64.arithmetic_nan_bitpattern" (i64.const 0x7ff0000000003210) (i64.const 0x7ff0000000003210)) (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.canonical_nan_bitpattern" (i64.const 0) (i64.const 0)) (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.canonical_nan_bitpattern" (i64.const 0x7ff8000000000000) (i64.const 0x7ff8000000000000)) (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.canonical_nan_bitpattern" (i64.const 0xfff8000000000000) (i64.const 0x7ff8000000000000)) (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.canonical_nan_bitpattern" (i64.const 0x7ff8000000000000) (i64.const 0xfff8000000000000)) (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.canonical_nan_bitpattern" (i64.const 0xfff8000000000000) (i64.const 0xfff8000000000000)) (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.nonarithmetic_nan_bitpattern" (i64.const 0x7ff8000000003210)) (i64.const 0xfff8000000003210))
+(assert_return (invoke "f64.nonarithmetic_nan_bitpattern" (i64.const 0xfff8000000003210)) (i64.const 0x7ff8000000003210))
+(assert_return (invoke "f64.nonarithmetic_nan_bitpattern" (i64.const 0x7ff0000000003210)) (i64.const 0xfff0000000003210))
+(assert_return (invoke "f64.nonarithmetic_nan_bitpattern" (i64.const 0xfff0000000003210)) (i64.const 0x7ff0000000003210))
+(assert_return (invoke "f32.no_fold_sub_zero" (i32.const 0x7fa00000)) (i32.const 0x7fc00000))
+(assert_return (invoke "f32.no_fold_neg0_sub" (i32.const 0x7fa00000)) (i32.const 0x7fc00000))
+(assert_return (invoke "f32.no_fold_mul_one" (i32.const 0x7fa00000)) (i32.const 0x7fc00000))
+(assert_return (invoke "f32.no_fold_neg1_mul" (i32.const 0x7fa00000)) (i32.const 0x7fc00000))
+(assert_return (invoke "f32.no_fold_div_one" (i32.const 0x7fa00000)) (i32.const 0x7fc00000))
+(assert_return (invoke "f32.no_fold_div_neg1" (i32.const 0x7fa00000)) (i32.const 0x7fc00000))
+(assert_return (invoke "f64.no_fold_sub_zero" (i64.const 0x7ff4000000000000)) (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.no_fold_neg0_sub" (i64.const 0x7ff4000000000000)) (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.no_fold_mul_one" (i64.const 0x7ff4000000000000)) (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.no_fold_neg1_mul" (i64.const 0x7ff4000000000000)) (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.no_fold_div_one" (i64.const 0x7ff4000000000000)) (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.no_fold_div_neg1" (i64.const 0x7ff4000000000000)) (i64.const 0x7ff8000000000000))
+(assert_return (invoke "no_fold_promote_demote" (i32.const 0x7fa00000)) (i32.const 0x7fc00000))
+
+;; Test that IEEE 754 double precision does, in fact, compute a certain dot
+;; product correctly.
+
+(module
+  (func (export "dot_product_example")
+        (param $x0 f64) (param $x1 f64) (param $x2 f64) (param $x3 f64)
+        (param $y0 f64) (param $y1 f64) (param $y2 f64) (param $y3 f64)
+        (result f64)
+    (f64.add (f64.add (f64.add
+      (f64.mul (local.get $x0) (local.get $y0))
+      (f64.mul (local.get $x1) (local.get $y1)))
+      (f64.mul (local.get $x2) (local.get $y2)))
+      (f64.mul (local.get $x3) (local.get $y3)))
+  )
+
+  (func (export "with_binary_sum_collapse")
+        (param $x0 f64) (param $x1 f64) (param $x2 f64) (param $x3 f64)
+        (param $y0 f64) (param $y1 f64) (param $y2 f64) (param $y3 f64)
+        (result f64)
+      (f64.add (f64.add (f64.mul (local.get $x0) (local.get $y0))
+                        (f64.mul (local.get $x1) (local.get $y1)))
+               (f64.add (f64.mul (local.get $x2) (local.get $y2))
+                        (f64.mul (local.get $x3) (local.get $y3))))
+  )
+)
+
+(assert_return (invoke "dot_product_example"
+    (f64.const 3.2e7) (f64.const 1.0) (f64.const -1.0) (f64.const 8.0e7)
+    (f64.const 4.0e7) (f64.const 1.0) (f64.const -1.0) (f64.const -1.6e7))
+  (f64.const 2.0))
+(assert_return (invoke "with_binary_sum_collapse"
+    (f64.const 3.2e7) (f64.const 1.0) (f64.const -1.0) (f64.const 8.0e7)
+    (f64.const 4.0e7) (f64.const 1.0) (f64.const -1.0) (f64.const -1.6e7))
+  (f64.const 2.0))
+
+;; http://www.vinc17.org/research/fptest.en.html#contract2fma
+
+(module
+  (func (export "f32.contract2fma")
+        (param $x f32) (param $y f32) (result f32)
+    (f32.sqrt (f32.sub (f32.mul (local.get $x) (local.get $x))
+                       (f32.mul (local.get $y) (local.get $y)))))
+  (func (export "f64.contract2fma")
+        (param $x f64) (param $y f64) (result f64)
+    (f64.sqrt (f64.sub (f64.mul (local.get $x) (local.get $x))
+                       (f64.mul (local.get $y) (local.get $y)))))
+)
+
+(assert_return (invoke "f32.contract2fma" (f32.const 1.0) (f32.const 1.0)) (f32.const 0.0))
+(assert_return (invoke "f32.contract2fma" (f32.const 0x1.19999ap+0) (f32.const 0x1.19999ap+0)) (f32.const 0.0))
+(assert_return (invoke "f32.contract2fma" (f32.const 0x1.333332p+0) (f32.const 0x1.333332p+0)) (f32.const 0.0))
+(assert_return (invoke "f64.contract2fma" (f64.const 1.0) (f64.const 1.0)) (f64.const 0.0))
+(assert_return (invoke "f64.contract2fma" (f64.const 0x1.199999999999ap+0) (f64.const 0x1.199999999999ap+0)) (f64.const 0.0))
+(assert_return (invoke "f64.contract2fma" (f64.const 0x1.3333333333333p+0) (f64.const 0x1.3333333333333p+0)) (f64.const 0.0))
+
+;; Test that floating-point isn't implemented with QuickBasic for MS-DOS.
+;; https://support.microsoft.com/en-us/help/42980/-complete-tutorial-to-understand-ieee-floating-point-errors
+
+(module
+  (func (export "f32.division_by_small_number")
+        (param $a f32) (param $b f32) (param $c f32) (result f32)
+    (f32.sub (local.get $a) (f32.div (local.get $b) (local.get $c))))
+  (func (export "f64.division_by_small_number")
+        (param $a f64) (param $b f64) (param $c f64) (result f64)
+    (f64.sub (local.get $a) (f64.div (local.get $b) (local.get $c))))
+)
+
+(assert_return (invoke "f32.division_by_small_number" (f32.const 112000000) (f32.const 100000) (f32.const 0.0009)) (f32.const 888888))
+(assert_return (invoke "f64.division_by_small_number" (f64.const 112000000) (f64.const 100000) (f64.const 0.0009)) (f64.const 888888.8888888806))
+
+;; Test a simple golden ratio computation.
+;; http://mathworld.wolfram.com/GoldenRatio.html
+
+(module
+  (func (export "f32.golden_ratio") (param $a f32) (param $b f32) (param $c f32) (result f32)
+    (f32.mul (local.get 0) (f32.add (local.get 1) (f32.sqrt (local.get 2)))))
+  (func (export "f64.golden_ratio") (param $a f64) (param $b f64) (param $c f64) (result f64)
+    (f64.mul (local.get 0) (f64.add (local.get 1) (f64.sqrt (local.get 2)))))
+)
+
+(assert_return (invoke "f32.golden_ratio" (f32.const 0.5) (f32.const 1.0) (f32.const 5.0)) (f32.const 1.618034))
+(assert_return (invoke "f64.golden_ratio" (f64.const 0.5) (f64.const 1.0) (f64.const 5.0)) (f64.const 1.618033988749895))
+
+;; Test some silver means computations.
+;; http://mathworld.wolfram.com/SilverRatio.html
+
+(module
+  (func (export "f32.silver_means") (param $n f32) (result f32)
+    (f32.mul (f32.const 0.5)
+             (f32.add (local.get $n)
+                      (f32.sqrt (f32.add (f32.mul (local.get $n) (local.get $n))
+                                         (f32.const 4.0))))))
+  (func (export "f64.silver_means") (param $n f64) (result f64)
+    (f64.mul (f64.const 0.5)
+             (f64.add (local.get $n)
+                      (f64.sqrt (f64.add (f64.mul (local.get $n) (local.get $n))
+                                         (f64.const 4.0))))))
+)
+
+(assert_return (invoke "f32.silver_means" (f32.const 0.0)) (f32.const 1.0))
+(assert_return (invoke "f32.silver_means" (f32.const 1.0)) (f32.const 1.6180340))
+(assert_return (invoke "f32.silver_means" (f32.const 2.0)) (f32.const 2.4142136))
+(assert_return (invoke "f32.silver_means" (f32.const 3.0)) (f32.const 3.3027756))
+(assert_return (invoke "f32.silver_means" (f32.const 4.0)) (f32.const 4.2360680))
+(assert_return (invoke "f32.silver_means" (f32.const 5.0)) (f32.const 5.1925821))
+(assert_return (invoke "f64.silver_means" (f64.const 0.0)) (f64.const 1.0))
+(assert_return (invoke "f64.silver_means" (f64.const 1.0)) (f64.const 1.618033988749895))
+(assert_return (invoke "f64.silver_means" (f64.const 2.0)) (f64.const 2.414213562373095))
+(assert_return (invoke "f64.silver_means" (f64.const 3.0)) (f64.const 3.302775637731995))
+(assert_return (invoke "f64.silver_means" (f64.const 4.0)) (f64.const 4.236067977499790))
+(assert_return (invoke "f64.silver_means" (f64.const 5.0)) (f64.const 5.192582403567252))
+
+;; Test that an f64 0.4 isn't double-rounded as via extended precision.
+;; https://bugs.llvm.org/show_bug.cgi?id=11200
+
+(module
+  (func (export "point_four") (param $four f64) (param $ten f64) (result i32)
+    (f64.lt (f64.div (local.get $four) (local.get $ten)) (f64.const 0.4)))
+)
+
+(assert_return (invoke "point_four" (f64.const 4.0) (f64.const 10.0)) (i32.const 0))
+
+;; Test an approximation function for tau; it should produces the correctly
+;; rounded result after (and only after) the expected number of iterations.
+
+(module
+  (func (export "tau") (param i32) (result f64)
+    (local f64 f64 f64 f64)
+    f64.const 0x0p+0
+    local.set 1
+    block
+      local.get 0
+      i32.const 1
+      i32.lt_s
+      br_if 0
+      f64.const 0x1p+0
+      local.set 2
+      f64.const 0x0p+0
+      local.set 3
+      loop
+        local.get 1
+        local.get 2
+        f64.const 0x1p+3
+        local.get 3
+        f64.const 0x1p+3
+        f64.mul
+        local.tee 4
+        f64.const 0x1p+0
+        f64.add
+        f64.div
+        f64.const 0x1p+2
+        local.get 4
+        f64.const 0x1p+2
+        f64.add
+        f64.div
+        f64.sub
+        f64.const 0x1p+1
+        local.get 4
+        f64.const 0x1.4p+2
+        f64.add
+        f64.div
+        f64.sub
+        f64.const 0x1p+1
+        local.get 4
+        f64.const 0x1.8p+2
+        f64.add
+        f64.div
+        f64.sub
+        f64.mul
+        f64.add
+        local.set 1
+        local.get 3
+        f64.const 0x1p+0
+        f64.add
+        local.set 3
+        local.get 2
+        f64.const 0x1p-4
+        f64.mul
+        local.set 2
+        local.get 0
+        i32.const -1
+        i32.add
+        local.tee 0
+        br_if 0
+      end
+    end
+    local.get 1
+  )
+)
+
+(assert_return (invoke "tau" (i32.const 10)) (f64.const 0x1.921fb54442d14p+2))
+(assert_return (invoke "tau" (i32.const 11)) (f64.const 0x1.921fb54442d18p+2))
+
+;; Test that y < 0 ? x : (x + 1) is not folded to x + (y < 0).
+
+(module
+  (func (export "f32.no_fold_conditional_inc") (param $x f32) (param $y f32) (result f32)
+    (select (local.get $x)
+            (f32.add (local.get $x) (f32.const 1.0))
+            (f32.lt (local.get $y) (f32.const 0.0))))
+  (func (export "f64.no_fold_conditional_inc") (param $x f64) (param $y f64) (result f64)
+    (select (local.get $x)
+            (f64.add (local.get $x) (f64.const 1.0))
+            (f64.lt (local.get $y) (f64.const 0.0))))
+)
+
+(assert_return (invoke "f32.no_fold_conditional_inc" (f32.const -0.0) (f32.const -1.0)) (f32.const -0.0))
+(assert_return (invoke "f64.no_fold_conditional_inc" (f64.const -0.0) (f64.const -1.0)) (f64.const -0.0))
diff --git a/binaryen/test/spec/float_literals.wast b/binaryen/test/spec/float_literals.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/float_literals.wast
@@ -0,0 +1,507 @@
+;; Test floating-point literal parsing.
+
+(module
+  ;; f32 special values
+  (func (export "f32.nan") (result i32) (i32.reinterpret_f32 (f32.const nan)))
+  (func (export "f32.positive_nan") (result i32) (i32.reinterpret_f32 (f32.const +nan)))
+  (func (export "f32.negative_nan") (result i32) (i32.reinterpret_f32 (f32.const -nan)))
+  (func (export "f32.plain_nan") (result i32) (i32.reinterpret_f32 (f32.const nan:0x400000)))
+  (func (export "f32.informally_known_as_plain_snan") (result i32) (i32.reinterpret_f32 (f32.const nan:0x200000)))
+  (func (export "f32.all_ones_nan") (result i32) (i32.reinterpret_f32 (f32.const -nan:0x7fffff)))
+  (func (export "f32.misc_nan") (result i32) (i32.reinterpret_f32 (f32.const nan:0x012345)))
+  (func (export "f32.misc_positive_nan") (result i32) (i32.reinterpret_f32 (f32.const +nan:0x304050)))
+  (func (export "f32.misc_negative_nan") (result i32) (i32.reinterpret_f32 (f32.const -nan:0x2abcde)))
+  (func (export "f32.infinity") (result i32) (i32.reinterpret_f32 (f32.const inf)))
+  (func (export "f32.positive_infinity") (result i32) (i32.reinterpret_f32 (f32.const +inf)))
+  (func (export "f32.negative_infinity") (result i32) (i32.reinterpret_f32 (f32.const -inf)))
+
+  ;; f32 numbers
+  (func (export "f32.zero") (result i32) (i32.reinterpret_f32 (f32.const 0x0.0p0)))
+  (func (export "f32.positive_zero") (result i32) (i32.reinterpret_f32 (f32.const +0x0.0p0)))
+  (func (export "f32.negative_zero") (result i32) (i32.reinterpret_f32 (f32.const -0x0.0p0)))
+  (func (export "f32.misc") (result i32) (i32.reinterpret_f32 (f32.const 0x1.921fb6p+2)))
+  (func (export "f32.min_positive") (result i32) (i32.reinterpret_f32 (f32.const 0x1p-149)))
+  (func (export "f32.min_normal") (result i32) (i32.reinterpret_f32 (f32.const 0x1p-126)))
+  (func (export "f32.max_finite") (result i32) (i32.reinterpret_f32 (f32.const 0x1.fffffep+127)))
+  (func (export "f32.max_subnormal") (result i32) (i32.reinterpret_f32 (f32.const 0x1.fffffcp-127)))
+  (func (export "f32.trailing_dot") (result i32) (i32.reinterpret_f32 (f32.const 0x1.p10)))
+
+  ;; f32 in decimal format
+  (func (export "f32_dec.zero") (result i32) (i32.reinterpret_f32 (f32.const 0.0e0)))
+  (func (export "f32_dec.positive_zero") (result i32) (i32.reinterpret_f32 (f32.const +0.0e0)))
+  (func (export "f32_dec.negative_zero") (result i32) (i32.reinterpret_f32 (f32.const -0.0e0)))
+  (func (export "f32_dec.misc") (result i32) (i32.reinterpret_f32 (f32.const 6.28318548202514648)))
+  (func (export "f32_dec.min_positive") (result i32) (i32.reinterpret_f32 (f32.const 1.4013e-45)))
+  (func (export "f32_dec.min_normal") (result i32) (i32.reinterpret_f32 (f32.const 1.1754944e-38)))
+  (func (export "f32_dec.max_subnormal") (result i32) (i32.reinterpret_f32 (f32.const 1.1754942e-38)))
+  (func (export "f32_dec.max_finite") (result i32) (i32.reinterpret_f32 (f32.const 3.4028234e+38)))
+  (func (export "f32_dec.trailing_dot") (result i32) (i32.reinterpret_f32 (f32.const 1.e10)))
+
+  ;; https://twitter.com/Archivd/status/994637336506912768
+  (func (export "f32_dec.root_beer_float") (result i32) (i32.reinterpret_f32 (f32.const 1.000000119)))
+
+  ;; f64 special values
+  (func (export "f64.nan") (result i64) (i64.reinterpret_f64 (f64.const nan)))
+  (func (export "f64.positive_nan") (result i64) (i64.reinterpret_f64 (f64.const +nan)))
+  (func (export "f64.negative_nan") (result i64) (i64.reinterpret_f64 (f64.const -nan)))
+  (func (export "f64.plain_nan") (result i64) (i64.reinterpret_f64 (f64.const nan:0x8000000000000)))
+  (func (export "f64.informally_known_as_plain_snan") (result i64) (i64.reinterpret_f64 (f64.const nan:0x4000000000000)))
+  (func (export "f64.all_ones_nan") (result i64) (i64.reinterpret_f64 (f64.const -nan:0xfffffffffffff)))
+  (func (export "f64.misc_nan") (result i64) (i64.reinterpret_f64 (f64.const nan:0x0123456789abc)))
+  (func (export "f64.misc_positive_nan") (result i64) (i64.reinterpret_f64 (f64.const +nan:0x3040506070809)))
+  (func (export "f64.misc_negative_nan") (result i64) (i64.reinterpret_f64 (f64.const -nan:0x2abcdef012345)))
+  (func (export "f64.infinity") (result i64) (i64.reinterpret_f64 (f64.const inf)))
+  (func (export "f64.positive_infinity") (result i64) (i64.reinterpret_f64 (f64.const +inf)))
+  (func (export "f64.negative_infinity") (result i64) (i64.reinterpret_f64 (f64.const -inf)))
+
+  ;; f64 numbers
+  (func (export "f64.zero") (result i64) (i64.reinterpret_f64 (f64.const 0x0.0p0)))
+  (func (export "f64.positive_zero") (result i64) (i64.reinterpret_f64 (f64.const +0x0.0p0)))
+  (func (export "f64.negative_zero") (result i64) (i64.reinterpret_f64 (f64.const -0x0.0p0)))
+  (func (export "f64.misc") (result i64) (i64.reinterpret_f64 (f64.const 0x1.921fb54442d18p+2)))
+  (func (export "f64.min_positive") (result i64) (i64.reinterpret_f64 (f64.const 0x0.0000000000001p-1022)))
+  (func (export "f64.min_normal") (result i64) (i64.reinterpret_f64 (f64.const 0x1p-1022)))
+  (func (export "f64.max_subnormal") (result i64) (i64.reinterpret_f64 (f64.const 0x0.fffffffffffffp-1022)))
+  (func (export "f64.max_finite") (result i64) (i64.reinterpret_f64 (f64.const 0x1.fffffffffffffp+1023)))
+  (func (export "f64.trailing_dot") (result i64) (i64.reinterpret_f64 (f64.const 0x1.p100)))
+
+  ;; f64 numbers in decimal format
+  (func (export "f64_dec.zero") (result i64) (i64.reinterpret_f64 (f64.const 0.0e0)))
+  (func (export "f64_dec.positive_zero") (result i64) (i64.reinterpret_f64 (f64.const +0.0e0)))
+  (func (export "f64_dec.negative_zero") (result i64) (i64.reinterpret_f64 (f64.const -0.0e0)))
+  (func (export "f64_dec.misc") (result i64) (i64.reinterpret_f64 (f64.const 6.28318530717958623)))
+  (func (export "f64_dec.min_positive") (result i64) (i64.reinterpret_f64 (f64.const 4.94066e-324)))
+  (func (export "f64_dec.min_normal") (result i64) (i64.reinterpret_f64 (f64.const 2.2250738585072012e-308)))
+  (func (export "f64_dec.max_subnormal") (result i64) (i64.reinterpret_f64 (f64.const 2.2250738585072011e-308)))
+  (func (export "f64_dec.max_finite") (result i64) (i64.reinterpret_f64 (f64.const 1.7976931348623157e+308)))
+  (func (export "f64_dec.trailing_dot") (result i64) (i64.reinterpret_f64 (f64.const 1.e100)))
+
+  ;; https://twitter.com/Archivd/status/994637336506912768
+  (func (export "f64_dec.root_beer_float") (result i64) (i64.reinterpret_f64 (f64.const 1.000000119)))
+
+  (func (export "f32-dec-sep1") (result f32) (f32.const 1_000_000))
+  (func (export "f32-dec-sep2") (result f32) (f32.const 1_0_0_0))
+  (func (export "f32-dec-sep3") (result f32) (f32.const 100_3.141_592))
+  (func (export "f32-dec-sep4") (result f32) (f32.const 99e+1_3))
+  (func (export "f32-dec-sep5") (result f32) (f32.const 122_000.11_3_54E0_2_3))
+  (func (export "f32-hex-sep1") (result f32) (f32.const 0xa_0f_00_99))
+  (func (export "f32-hex-sep2") (result f32) (f32.const 0x1_a_A_0_f))
+  (func (export "f32-hex-sep3") (result f32) (f32.const 0xa0_ff.f141_a59a))
+  (func (export "f32-hex-sep4") (result f32) (f32.const 0xf0P+1_3))
+  (func (export "f32-hex-sep5") (result f32) (f32.const 0x2a_f00a.1f_3_eep2_3))
+
+  (func (export "f64-dec-sep1") (result f64) (f64.const 1_000_000))
+  (func (export "f64-dec-sep2") (result f64) (f64.const 1_0_0_0))
+  (func (export "f64-dec-sep3") (result f64) (f64.const 100_3.141_592))
+  (func (export "f64-dec-sep4") (result f64) (f64.const 99e-1_23))
+  (func (export "f64-dec-sep5") (result f64) (f64.const 122_000.11_3_54e0_2_3))
+  (func (export "f64-hex-sep1") (result f64) (f64.const 0xa_f00f_0000_9999))
+  (func (export "f64-hex-sep2") (result f64) (f64.const 0x1_a_A_0_f))
+  (func (export "f64-hex-sep3") (result f64) (f64.const 0xa0_ff.f141_a59a))
+  (func (export "f64-hex-sep4") (result f64) (f64.const 0xf0P+1_3))
+  (func (export "f64-hex-sep5") (result f64) (f64.const 0x2a_f00a.1f_3_eep2_3))
+)
+
+(assert_return (invoke "f32.nan") (i32.const 0x7fc00000))
+(assert_return (invoke "f32.positive_nan") (i32.const 0x7fc00000))
+(assert_return (invoke "f32.negative_nan") (i32.const 0xffc00000))
+(assert_return (invoke "f32.plain_nan") (i32.const 0x7fc00000))
+(assert_return (invoke "f32.informally_known_as_plain_snan") (i32.const 0x7fa00000))
+(assert_return (invoke "f32.all_ones_nan") (i32.const 0xffffffff))
+(assert_return (invoke "f32.misc_nan") (i32.const 0x7f812345))
+(assert_return (invoke "f32.misc_positive_nan") (i32.const 0x7fb04050))
+(assert_return (invoke "f32.misc_negative_nan") (i32.const 0xffaabcde))
+(assert_return (invoke "f32.infinity") (i32.const 0x7f800000))
+(assert_return (invoke "f32.positive_infinity") (i32.const 0x7f800000))
+(assert_return (invoke "f32.negative_infinity") (i32.const 0xff800000))
+(assert_return (invoke "f32.zero") (i32.const 0))
+(assert_return (invoke "f32.positive_zero") (i32.const 0))
+(assert_return (invoke "f32.negative_zero") (i32.const 0x80000000))
+(assert_return (invoke "f32.misc") (i32.const 0x40c90fdb))
+(assert_return (invoke "f32.min_positive") (i32.const 1))
+(assert_return (invoke "f32.min_normal") (i32.const 0x800000))
+(assert_return (invoke "f32.max_subnormal") (i32.const 0x7fffff))
+(assert_return (invoke "f32.max_finite") (i32.const 0x7f7fffff))
+(assert_return (invoke "f32.trailing_dot") (i32.const 0x44800000))
+(assert_return (invoke "f32_dec.zero") (i32.const 0))
+(assert_return (invoke "f32_dec.positive_zero") (i32.const 0))
+(assert_return (invoke "f32_dec.negative_zero") (i32.const 0x80000000))
+(assert_return (invoke "f32_dec.misc") (i32.const 0x40c90fdb))
+(assert_return (invoke "f32_dec.min_positive") (i32.const 1))
+(assert_return (invoke "f32_dec.min_normal") (i32.const 0x800000))
+(assert_return (invoke "f32_dec.max_subnormal") (i32.const 0x7fffff))
+(assert_return (invoke "f32_dec.max_finite") (i32.const 0x7f7fffff))
+(assert_return (invoke "f32_dec.trailing_dot") (i32.const 0x501502f9))
+(assert_return (invoke "f32_dec.root_beer_float") (i32.const 0x3f800001))
+
+(assert_return (invoke "f64.nan") (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.positive_nan") (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.negative_nan") (i64.const 0xfff8000000000000))
+(assert_return (invoke "f64.plain_nan") (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.informally_known_as_plain_snan") (i64.const 0x7ff4000000000000))
+(assert_return (invoke "f64.all_ones_nan") (i64.const 0xffffffffffffffff))
+(assert_return (invoke "f64.misc_nan") (i64.const 0x7ff0123456789abc))
+(assert_return (invoke "f64.misc_positive_nan") (i64.const 0x7ff3040506070809))
+(assert_return (invoke "f64.misc_negative_nan") (i64.const 0xfff2abcdef012345))
+(assert_return (invoke "f64.infinity") (i64.const 0x7ff0000000000000))
+(assert_return (invoke "f64.positive_infinity") (i64.const 0x7ff0000000000000))
+(assert_return (invoke "f64.negative_infinity") (i64.const 0xfff0000000000000))
+(assert_return (invoke "f64.zero") (i64.const 0))
+(assert_return (invoke "f64.positive_zero") (i64.const 0))
+(assert_return (invoke "f64.negative_zero") (i64.const 0x8000000000000000))
+(assert_return (invoke "f64.misc") (i64.const 0x401921fb54442d18))
+(assert_return (invoke "f64.min_positive") (i64.const 1))
+(assert_return (invoke "f64.min_normal") (i64.const 0x10000000000000))
+(assert_return (invoke "f64.max_subnormal") (i64.const 0xfffffffffffff))
+(assert_return (invoke "f64.max_finite") (i64.const 0x7fefffffffffffff))
+(assert_return (invoke "f64.trailing_dot") (i64.const 0x4630000000000000))
+(assert_return (invoke "f64_dec.zero") (i64.const 0))
+(assert_return (invoke "f64_dec.positive_zero") (i64.const 0))
+(assert_return (invoke "f64_dec.negative_zero") (i64.const 0x8000000000000000))
+(assert_return (invoke "f64_dec.misc") (i64.const 0x401921fb54442d18))
+(assert_return (invoke "f64_dec.min_positive") (i64.const 1))
+(assert_return (invoke "f64_dec.min_normal") (i64.const 0x10000000000000))
+(assert_return (invoke "f64_dec.max_subnormal") (i64.const 0xfffffffffffff))
+(assert_return (invoke "f64_dec.max_finite") (i64.const 0x7fefffffffffffff))
+(assert_return (invoke "f64_dec.trailing_dot") (i64.const 0x54b249ad2594c37d))
+(assert_return (invoke "f64_dec.root_beer_float") (i64.const 0x3ff000001ff19e24))
+
+(assert_return (invoke "f32-dec-sep1") (f32.const 1000000))
+(assert_return (invoke "f32-dec-sep2") (f32.const 1000))
+(assert_return (invoke "f32-dec-sep3") (f32.const 1003.141592))
+(assert_return (invoke "f32-dec-sep4") (f32.const 99e+13))
+(assert_return (invoke "f32-dec-sep5") (f32.const 122000.11354e23))
+(assert_return (invoke "f32-hex-sep1") (f32.const 0xa0f0099))
+(assert_return (invoke "f32-hex-sep2") (f32.const 0x1aa0f))
+(assert_return (invoke "f32-hex-sep3") (f32.const 0xa0ff.f141a59a))
+(assert_return (invoke "f32-hex-sep4") (f32.const 0xf0P+13))
+(assert_return (invoke "f32-hex-sep5") (f32.const 0x2af00a.1f3eep23))
+
+(assert_return (invoke "f64-dec-sep1") (f64.const 1000000))
+(assert_return (invoke "f64-dec-sep2") (f64.const 1000))
+(assert_return (invoke "f64-dec-sep3") (f64.const 1003.141592))
+(assert_return (invoke "f64-dec-sep4") (f64.const 99e-123))
+(assert_return (invoke "f64-dec-sep5") (f64.const 122000.11354e23))
+(assert_return (invoke "f64-hex-sep1") (f64.const 0xaf00f00009999))
+(assert_return (invoke "f64-hex-sep2") (f64.const 0x1aa0f))
+(assert_return (invoke "f64-hex-sep3") (f64.const 0xa0ff.f141a59a))
+(assert_return (invoke "f64-hex-sep4") (f64.const 0xf0P+13))
+(assert_return (invoke "f64-hex-sep5") (f64.const 0x2af00a.1f3eep23))
+
+;; Test parsing a float from binary
+(module binary
+  ;; (func (export "4294967249") (result f64) (f64.const 4294967249))
+  "\00\61\73\6d\01\00\00\00\01\85\80\80\80\00\01\60"
+  "\00\01\7c\03\82\80\80\80\00\01\00\07\8e\80\80\80"
+  "\00\01\0a\34\32\39\34\39\36\37\32\34\39\00\00\0a"
+  "\91\80\80\80\00\01\8b\80\80\80\00\00\44\00\00\20"
+  "\fa\ff\ff\ef\41\0b"
+)
+
+(assert_return (invoke "4294967249") (f64.const 4294967249))
+
+(assert_malformed
+  (module quote "(global f32 (f32.const _100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const +_100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const -_100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 99_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 1__000))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const _1.0))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 1.0_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 1_.0))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 1._0))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const _1e1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 1e1_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 1_e1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 1e_1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const _1.0e1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 1.0e1_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 1.0_e1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 1.0e_1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 1.0e+_1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 1.0e_+1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const _0x100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0_x100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x_100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x00_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0xff__ffff))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x_1.0))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x1.0_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x1_.0))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x1._0))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x_1p1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x1p1_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x1_p1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x1p_1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x_1.0p1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x1.0p1_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x1.0_p1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x1.0p_1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x1.0p+_1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f32 (f32.const 0x1.0p_+1))")
+  "unknown operator"
+)
+
+(assert_malformed
+  (module quote "(global f64 (f64.const _100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const +_100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const -_100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 99_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 1__000))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const _1.0))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 1.0_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 1_.0))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 1._0))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const _1e1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 1e1_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 1_e1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 1e_1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const _1.0e1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 1.0e1_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 1.0_e1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 1.0e_1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 1.0e+_1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 1.0e_+1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const _0x100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0_x100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x_100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x00_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0xff__ffff))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x_1.0))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x1.0_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x1_.0))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x1._0))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x_1p1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x1p1_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x1_p1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x1p_1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x_1.0p1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x1.0p1_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x1.0_p1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x1.0p_1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x1.0p+_1))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global f64 (f64.const 0x1.0p_+1))")
+  "unknown operator"
+)
diff --git a/binaryen/test/spec/float_memory.wast b/binaryen/test/spec/float_memory.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/float_memory.wast
@@ -0,0 +1,157 @@
+;; Test that floating-point load and store are bit-preserving.
+
+;; Test that load and store do not canonicalize NaNs as x87 does.
+
+(module
+  (memory (data "\00\00\a0\7f"))
+
+  (func (export "f32.load") (result f32) (f32.load (i32.const 0)))
+  (func (export "i32.load") (result i32) (i32.load (i32.const 0)))
+  (func (export "f32.store") (f32.store (i32.const 0) (f32.const nan:0x200000)))
+  (func (export "i32.store") (i32.store (i32.const 0) (i32.const 0x7fa00000)))
+  (func (export "reset") (i32.store (i32.const 0) (i32.const 0)))
+)
+
+(assert_return (invoke "i32.load") (i32.const 0x7fa00000))
+(assert_return (invoke "f32.load") (f32.const nan:0x200000))
+(invoke "reset")
+(assert_return (invoke "i32.load") (i32.const 0x0))
+(assert_return (invoke "f32.load") (f32.const 0.0))
+(invoke "f32.store")
+(assert_return (invoke "i32.load") (i32.const 0x7fa00000))
+(assert_return (invoke "f32.load") (f32.const nan:0x200000))
+(invoke "reset")
+(assert_return (invoke "i32.load") (i32.const 0x0))
+(assert_return (invoke "f32.load") (f32.const 0.0))
+(invoke "i32.store")
+(assert_return (invoke "i32.load") (i32.const 0x7fa00000))
+(assert_return (invoke "f32.load") (f32.const nan:0x200000))
+
+(module
+  (memory (data "\00\00\00\00\00\00\f4\7f"))
+
+  (func (export "f64.load") (result f64) (f64.load (i32.const 0)))
+  (func (export "i64.load") (result i64) (i64.load (i32.const 0)))
+  (func (export "f64.store") (f64.store (i32.const 0) (f64.const nan:0x4000000000000)))
+  (func (export "i64.store") (i64.store (i32.const 0) (i64.const 0x7ff4000000000000)))
+  (func (export "reset") (i64.store (i32.const 0) (i64.const 0)))
+)
+
+(assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000))
+(assert_return (invoke "f64.load") (f64.const nan:0x4000000000000))
+(invoke "reset")
+(assert_return (invoke "i64.load") (i64.const 0x0))
+(assert_return (invoke "f64.load") (f64.const 0.0))
+(invoke "f64.store")
+(assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000))
+(assert_return (invoke "f64.load") (f64.const nan:0x4000000000000))
+(invoke "reset")
+(assert_return (invoke "i64.load") (i64.const 0x0))
+(assert_return (invoke "f64.load") (f64.const 0.0))
+(invoke "i64.store")
+(assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000))
+(assert_return (invoke "f64.load") (f64.const nan:0x4000000000000))
+
+;; Test that unaligned load and store do not canonicalize NaNs.
+
+(module
+  (memory (data "\00\00\00\a0\7f"))
+
+  (func (export "f32.load") (result f32) (f32.load (i32.const 1)))
+  (func (export "i32.load") (result i32) (i32.load (i32.const 1)))
+  (func (export "f32.store") (f32.store (i32.const 1) (f32.const nan:0x200000)))
+  (func (export "i32.store") (i32.store (i32.const 1) (i32.const 0x7fa00000)))
+  (func (export "reset") (i32.store (i32.const 1) (i32.const 0)))
+)
+
+(assert_return (invoke "i32.load") (i32.const 0x7fa00000))
+(assert_return (invoke "f32.load") (f32.const nan:0x200000))
+(invoke "reset")
+(assert_return (invoke "i32.load") (i32.const 0x0))
+(assert_return (invoke "f32.load") (f32.const 0.0))
+(invoke "f32.store")
+(assert_return (invoke "i32.load") (i32.const 0x7fa00000))
+(assert_return (invoke "f32.load") (f32.const nan:0x200000))
+(invoke "reset")
+(assert_return (invoke "i32.load") (i32.const 0x0))
+(assert_return (invoke "f32.load") (f32.const 0.0))
+(invoke "i32.store")
+(assert_return (invoke "i32.load") (i32.const 0x7fa00000))
+(assert_return (invoke "f32.load") (f32.const nan:0x200000))
+
+(module
+  (memory (data "\00\00\00\00\00\00\00\f4\7f"))
+
+  (func (export "f64.load") (result f64) (f64.load (i32.const 1)))
+  (func (export "i64.load") (result i64) (i64.load (i32.const 1)))
+  (func (export "f64.store") (f64.store (i32.const 1) (f64.const nan:0x4000000000000)))
+  (func (export "i64.store") (i64.store (i32.const 1) (i64.const 0x7ff4000000000000)))
+  (func (export "reset") (i64.store (i32.const 1) (i64.const 0)))
+)
+
+(assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000))
+(assert_return (invoke "f64.load") (f64.const nan:0x4000000000000))
+(invoke "reset")
+(assert_return (invoke "i64.load") (i64.const 0x0))
+(assert_return (invoke "f64.load") (f64.const 0.0))
+(invoke "f64.store")
+(assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000))
+(assert_return (invoke "f64.load") (f64.const nan:0x4000000000000))
+(invoke "reset")
+(assert_return (invoke "i64.load") (i64.const 0x0))
+(assert_return (invoke "f64.load") (f64.const 0.0))
+(invoke "i64.store")
+(assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000))
+(assert_return (invoke "f64.load") (f64.const nan:0x4000000000000))
+
+;; Test that load and store do not canonicalize NaNs as some JS engines do.
+
+(module
+  (memory (data "\01\00\d0\7f"))
+
+  (func (export "f32.load") (result f32) (f32.load (i32.const 0)))
+  (func (export "i32.load") (result i32) (i32.load (i32.const 0)))
+  (func (export "f32.store") (f32.store (i32.const 0) (f32.const nan:0x500001)))
+  (func (export "i32.store") (i32.store (i32.const 0) (i32.const 0x7fd00001)))
+  (func (export "reset") (i32.store (i32.const 0) (i32.const 0)))
+)
+
+(assert_return (invoke "i32.load") (i32.const 0x7fd00001))
+(assert_return (invoke "f32.load") (f32.const nan:0x500001))
+(invoke "reset")
+(assert_return (invoke "i32.load") (i32.const 0x0))
+(assert_return (invoke "f32.load") (f32.const 0.0))
+(invoke "f32.store")
+(assert_return (invoke "i32.load") (i32.const 0x7fd00001))
+(assert_return (invoke "f32.load") (f32.const nan:0x500001))
+(invoke "reset")
+(assert_return (invoke "i32.load") (i32.const 0x0))
+(assert_return (invoke "f32.load") (f32.const 0.0))
+(invoke "i32.store")
+(assert_return (invoke "i32.load") (i32.const 0x7fd00001))
+(assert_return (invoke "f32.load") (f32.const nan:0x500001))
+
+(module
+  (memory (data "\01\00\00\00\00\00\fc\7f"))
+
+  (func (export "f64.load") (result f64) (f64.load (i32.const 0)))
+  (func (export "i64.load") (result i64) (i64.load (i32.const 0)))
+  (func (export "f64.store") (f64.store (i32.const 0) (f64.const nan:0xc000000000001)))
+  (func (export "i64.store") (i64.store (i32.const 0) (i64.const 0x7ffc000000000001)))
+  (func (export "reset") (i64.store (i32.const 0) (i64.const 0)))
+)
+
+(assert_return (invoke "i64.load") (i64.const 0x7ffc000000000001))
+(assert_return (invoke "f64.load") (f64.const nan:0xc000000000001))
+(invoke "reset")
+(assert_return (invoke "i64.load") (i64.const 0x0))
+(assert_return (invoke "f64.load") (f64.const 0.0))
+(invoke "f64.store")
+(assert_return (invoke "i64.load") (i64.const 0x7ffc000000000001))
+(assert_return (invoke "f64.load") (f64.const nan:0xc000000000001))
+(invoke "reset")
+(assert_return (invoke "i64.load") (i64.const 0x0))
+(assert_return (invoke "f64.load") (f64.const 0.0))
+(invoke "i64.store")
+(assert_return (invoke "i64.load") (i64.const 0x7ffc000000000001))
+(assert_return (invoke "f64.load") (f64.const nan:0xc000000000001))
diff --git a/binaryen/test/spec/float_memory64.wast b/binaryen/test/spec/float_memory64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/float_memory64.wast
@@ -0,0 +1,157 @@
+;; Test that floating-point load and store are bit-preserving.
+
+;; Test that load and store do not canonicalize NaNs as x87 does.
+
+(module
+  (memory (data i64 "\00\00\a0\7f"))
+
+  (func (export "f32.load") (result f32) (f32.load (i64.const 0)))
+  (func (export "i32.load") (result i32) (i32.load (i64.const 0)))
+  (func (export "f32.store") (f32.store (i64.const 0) (f32.const nan:0x200000)))
+  (func (export "i32.store") (i32.store (i64.const 0) (i32.const 0x7fa00000)))
+  (func (export "reset") (i32.store (i64.const 0) (i32.const 0)))
+)
+
+(assert_return (invoke "i32.load") (i32.const 0x7fa00000))
+(assert_return (invoke "f32.load") (f32.const nan:0x200000))
+(invoke "reset")
+(assert_return (invoke "i32.load") (i32.const 0x0))
+(assert_return (invoke "f32.load") (f32.const 0.0))
+(invoke "f32.store")
+(assert_return (invoke "i32.load") (i32.const 0x7fa00000))
+(assert_return (invoke "f32.load") (f32.const nan:0x200000))
+(invoke "reset")
+(assert_return (invoke "i32.load") (i32.const 0x0))
+(assert_return (invoke "f32.load") (f32.const 0.0))
+(invoke "i32.store")
+(assert_return (invoke "i32.load") (i32.const 0x7fa00000))
+(assert_return (invoke "f32.load") (f32.const nan:0x200000))
+
+(module
+  (memory (data i64 "\00\00\00\00\00\00\f4\7f"))
+
+  (func (export "f64.load") (result f64) (f64.load (i64.const 0)))
+  (func (export "i64.load") (result i64) (i64.load (i64.const 0)))
+  (func (export "f64.store") (f64.store (i64.const 0) (f64.const nan:0x4000000000000)))
+  (func (export "i64.store") (i64.store (i64.const 0) (i64.const 0x7ff4000000000000)))
+  (func (export "reset") (i64.store (i64.const 0) (i64.const 0)))
+)
+
+(assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000))
+(assert_return (invoke "f64.load") (f64.const nan:0x4000000000000))
+(invoke "reset")
+(assert_return (invoke "i64.load") (i64.const 0x0))
+(assert_return (invoke "f64.load") (f64.const 0.0))
+(invoke "f64.store")
+(assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000))
+(assert_return (invoke "f64.load") (f64.const nan:0x4000000000000))
+(invoke "reset")
+(assert_return (invoke "i64.load") (i64.const 0x0))
+(assert_return (invoke "f64.load") (f64.const 0.0))
+(invoke "i64.store")
+(assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000))
+(assert_return (invoke "f64.load") (f64.const nan:0x4000000000000))
+
+;; Test that unaligned load and store do not canonicalize NaNs.
+
+(module
+  (memory (data i64 "\00\00\00\a0\7f"))
+
+  (func (export "f32.load") (result f32) (f32.load (i64.const 1)))
+  (func (export "i32.load") (result i32) (i32.load (i64.const 1)))
+  (func (export "f32.store") (f32.store (i64.const 1) (f32.const nan:0x200000)))
+  (func (export "i32.store") (i32.store (i64.const 1) (i32.const 0x7fa00000)))
+  (func (export "reset") (i32.store (i64.const 1) (i32.const 0)))
+)
+
+(assert_return (invoke "i32.load") (i32.const 0x7fa00000))
+(assert_return (invoke "f32.load") (f32.const nan:0x200000))
+(invoke "reset")
+(assert_return (invoke "i32.load") (i32.const 0x0))
+(assert_return (invoke "f32.load") (f32.const 0.0))
+(invoke "f32.store")
+(assert_return (invoke "i32.load") (i32.const 0x7fa00000))
+(assert_return (invoke "f32.load") (f32.const nan:0x200000))
+(invoke "reset")
+(assert_return (invoke "i32.load") (i32.const 0x0))
+(assert_return (invoke "f32.load") (f32.const 0.0))
+(invoke "i32.store")
+(assert_return (invoke "i32.load") (i32.const 0x7fa00000))
+(assert_return (invoke "f32.load") (f32.const nan:0x200000))
+
+(module
+  (memory (data i64 "\00\00\00\00\00\00\00\f4\7f"))
+
+  (func (export "f64.load") (result f64) (f64.load (i64.const 1)))
+  (func (export "i64.load") (result i64) (i64.load (i64.const 1)))
+  (func (export "f64.store") (f64.store (i64.const 1) (f64.const nan:0x4000000000000)))
+  (func (export "i64.store") (i64.store (i64.const 1) (i64.const 0x7ff4000000000000)))
+  (func (export "reset") (i64.store (i64.const 1) (i64.const 0)))
+)
+
+(assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000))
+(assert_return (invoke "f64.load") (f64.const nan:0x4000000000000))
+(invoke "reset")
+(assert_return (invoke "i64.load") (i64.const 0x0))
+(assert_return (invoke "f64.load") (f64.const 0.0))
+(invoke "f64.store")
+(assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000))
+(assert_return (invoke "f64.load") (f64.const nan:0x4000000000000))
+(invoke "reset")
+(assert_return (invoke "i64.load") (i64.const 0x0))
+(assert_return (invoke "f64.load") (f64.const 0.0))
+(invoke "i64.store")
+(assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000))
+(assert_return (invoke "f64.load") (f64.const nan:0x4000000000000))
+
+;; Test that load and store do not canonicalize NaNs as some JS engines do.
+
+(module
+  (memory (data i64 "\01\00\d0\7f"))
+
+  (func (export "f32.load") (result f32) (f32.load (i64.const 0)))
+  (func (export "i32.load") (result i32) (i32.load (i64.const 0)))
+  (func (export "f32.store") (f32.store (i64.const 0) (f32.const nan:0x500001)))
+  (func (export "i32.store") (i32.store (i64.const 0) (i32.const 0x7fd00001)))
+  (func (export "reset") (i32.store (i64.const 0) (i32.const 0)))
+)
+
+(assert_return (invoke "i32.load") (i32.const 0x7fd00001))
+(assert_return (invoke "f32.load") (f32.const nan:0x500001))
+(invoke "reset")
+(assert_return (invoke "i32.load") (i32.const 0x0))
+(assert_return (invoke "f32.load") (f32.const 0.0))
+(invoke "f32.store")
+(assert_return (invoke "i32.load") (i32.const 0x7fd00001))
+(assert_return (invoke "f32.load") (f32.const nan:0x500001))
+(invoke "reset")
+(assert_return (invoke "i32.load") (i32.const 0x0))
+(assert_return (invoke "f32.load") (f32.const 0.0))
+(invoke "i32.store")
+(assert_return (invoke "i32.load") (i32.const 0x7fd00001))
+(assert_return (invoke "f32.load") (f32.const nan:0x500001))
+
+(module
+  (memory (data i64 "\01\00\00\00\00\00\fc\7f"))
+
+  (func (export "f64.load") (result f64) (f64.load (i64.const 0)))
+  (func (export "i64.load") (result i64) (i64.load (i64.const 0)))
+  (func (export "f64.store") (f64.store (i64.const 0) (f64.const nan:0xc000000000001)))
+  (func (export "i64.store") (i64.store (i64.const 0) (i64.const 0x7ffc000000000001)))
+  (func (export "reset") (i64.store (i64.const 0) (i64.const 0)))
+)
+
+(assert_return (invoke "i64.load") (i64.const 0x7ffc000000000001))
+(assert_return (invoke "f64.load") (f64.const nan:0xc000000000001))
+(invoke "reset")
+(assert_return (invoke "i64.load") (i64.const 0x0))
+(assert_return (invoke "f64.load") (f64.const 0.0))
+(invoke "f64.store")
+(assert_return (invoke "i64.load") (i64.const 0x7ffc000000000001))
+(assert_return (invoke "f64.load") (f64.const nan:0xc000000000001))
+(invoke "reset")
+(assert_return (invoke "i64.load") (i64.const 0x0))
+(assert_return (invoke "f64.load") (f64.const 0.0))
+(invoke "i64.store")
+(assert_return (invoke "i64.load") (i64.const 0x7ffc000000000001))
+(assert_return (invoke "f64.load") (f64.const nan:0xc000000000001))
diff --git a/binaryen/test/spec/float_misc.wast b/binaryen/test/spec/float_misc.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/float_misc.wast
@@ -0,0 +1,678 @@
+;; Platforms intended to run WebAssembly must support IEEE 754 arithmetic.
+;; This testsuite is not currently sufficient for full IEEE 754 conformance
+;; testing; platforms are currently expected to meet these requirements in
+;; their own way (widely-used hardware platforms already do this).
+;;
+;; What this testsuite does test is that (a) the platform is basically IEEE 754
+;; rather than something else entirely, (b) it's configured correctly for
+;; WebAssembly (rounding direction, exception masks, precision level, subnormal
+;; mode, etc.), (c) the WebAssembly implementation doesn't perform any common
+;; value-changing optimizations, and (d) that the WebAssembly implementation
+;; doesn't exhibit any known implementation bugs.
+;;
+;; This file supplements f32.wast, f64.wast, f32_bitwise.wast, f64_bitwise.wast,
+;; f32_cmp.wast, and f64_cmp.wast with additional single-instruction tests
+;; covering additional miscellaneous interesting cases.
+
+(module
+  (func (export "f32.add") (param $x f32) (param $y f32) (result f32) (f32.add (local.get $x) (local.get $y)))
+  (func (export "f32.sub") (param $x f32) (param $y f32) (result f32) (f32.sub (local.get $x) (local.get $y)))
+  (func (export "f32.mul") (param $x f32) (param $y f32) (result f32) (f32.mul (local.get $x) (local.get $y)))
+  (func (export "f32.div") (param $x f32) (param $y f32) (result f32) (f32.div (local.get $x) (local.get $y)))
+  (func (export "f32.sqrt") (param $x f32) (result f32) (f32.sqrt (local.get $x)))
+  (func (export "f32.abs") (param $x f32) (result f32) (f32.abs (local.get $x)))
+  (func (export "f32.neg") (param $x f32) (result f32) (f32.neg (local.get $x)))
+  (func (export "f32.copysign") (param $x f32) (param $y f32) (result f32) (f32.copysign (local.get $x) (local.get $y)))
+  (func (export "f32.ceil") (param $x f32) (result f32) (f32.ceil (local.get $x)))
+  (func (export "f32.floor") (param $x f32) (result f32) (f32.floor (local.get $x)))
+  (func (export "f32.trunc") (param $x f32) (result f32) (f32.trunc (local.get $x)))
+  (func (export "f32.nearest") (param $x f32) (result f32) (f32.nearest (local.get $x)))
+  (func (export "f32.min") (param $x f32) (param $y f32) (result f32) (f32.min (local.get $x) (local.get $y)))
+  (func (export "f32.max") (param $x f32) (param $y f32) (result f32) (f32.max (local.get $x) (local.get $y)))
+
+  (func (export "f64.add") (param $x f64) (param $y f64) (result f64) (f64.add (local.get $x) (local.get $y)))
+  (func (export "f64.sub") (param $x f64) (param $y f64) (result f64) (f64.sub (local.get $x) (local.get $y)))
+  (func (export "f64.mul") (param $x f64) (param $y f64) (result f64) (f64.mul (local.get $x) (local.get $y)))
+  (func (export "f64.div") (param $x f64) (param $y f64) (result f64) (f64.div (local.get $x) (local.get $y)))
+  (func (export "f64.sqrt") (param $x f64) (result f64) (f64.sqrt (local.get $x)))
+  (func (export "f64.abs") (param $x f64) (result f64) (f64.abs (local.get $x)))
+  (func (export "f64.neg") (param $x f64) (result f64) (f64.neg (local.get $x)))
+  (func (export "f64.copysign") (param $x f64) (param $y f64) (result f64) (f64.copysign (local.get $x) (local.get $y)))
+  (func (export "f64.ceil") (param $x f64) (result f64) (f64.ceil (local.get $x)))
+  (func (export "f64.floor") (param $x f64) (result f64) (f64.floor (local.get $x)))
+  (func (export "f64.trunc") (param $x f64) (result f64) (f64.trunc (local.get $x)))
+  (func (export "f64.nearest") (param $x f64) (result f64) (f64.nearest (local.get $x)))
+  (func (export "f64.min") (param $x f64) (param $y f64) (result f64) (f64.min (local.get $x) (local.get $y)))
+  (func (export "f64.max") (param $x f64) (param $y f64) (result f64) (f64.max (local.get $x) (local.get $y)))
+)
+
+;; Miscellaneous values.
+(assert_return (invoke "f32.add" (f32.const 1.1234567890) (f32.const 1.2345e-10)) (f32.const 1.123456789))
+(assert_return (invoke "f64.add" (f64.const 1.1234567890) (f64.const 1.2345e-10)) (f64.const 0x1.1f9add37c11f7p+0))
+
+;; Test adding the greatest value to 1.0 that rounds back to 1.0, and the
+;; least that rounds to something greater.
+(assert_return (invoke "f32.add" (f32.const 1.0) (f32.const 0x1p-24)) (f32.const 0x1.0p+0))
+(assert_return (invoke "f32.add" (f32.const 1.0) (f32.const 0x1.000002p-24)) (f32.const 0x1.000002p+0))
+(assert_return (invoke "f64.add" (f64.const 1.0) (f64.const 0x1p-53)) (f64.const 0x1.0p+0))
+(assert_return (invoke "f64.add" (f64.const 1.0) (f64.const 0x1.0000000000001p-53)) (f64.const 0x1.0000000000001p+0))
+
+;; Max subnormal + min subnormal = min normal.
+(assert_return (invoke "f32.add" (f32.const 0x1p-149) (f32.const 0x1.fffffcp-127)) (f32.const 0x1p-126))
+(assert_return (invoke "f64.add" (f64.const 0x0.0000000000001p-1022) (f64.const 0x0.fffffffffffffp-1022)) (f64.const 0x1p-1022))
+
+;; Test for a case of double rounding, example from:
+;; http://perso.ens-lyon.fr/jean-michel.muller/Handbook.html
+;; section 3.3.1: A typical problem: "double rounding"
+(assert_return (invoke "f32.add" (f32.const 0x1p+31) (f32.const 1024.25)) (f32.const 0x1.000008p+31))
+(assert_return (invoke "f64.add" (f64.const 0x1p+63) (f64.const 1024.25)) (f64.const 0x1.0000000000001p+63))
+
+;; Test a case that was "tricky" on MMIX.
+;; http://mmix.cs.hm.edu/bugs/bug_rounding.html
+(assert_return (invoke "f64.add" (f64.const -0x1p-1008) (f64.const 0x0.0000000001716p-1022)) (f64.const -0x1.fffffffffffffp-1009))
+
+;; http://www.vinc17.org/software/tst-ieee754.xsl
+(assert_return (invoke "f64.add" (f64.const 9007199254740992) (f64.const 1.00001)) (f64.const 9007199254740994))
+
+;; http://www.vinc17.org/software/test.java
+(assert_return (invoke "f64.add" (f64.const 9007199254740994) (f64.const 0x1.fffep-1)) (f64.const 9007199254740994))
+
+;; Computations that round differently in ties-to-odd mode.
+(assert_return (invoke "f32.add" (f32.const 0x1p23) (f32.const 0x1p-1)) (f32.const 0x1p23))
+(assert_return (invoke "f32.add" (f32.const 0x1.000002p+23) (f32.const 0x1p-1)) (f32.const 0x1.000004p+23))
+(assert_return (invoke "f64.add" (f64.const 0x1p52) (f64.const 0x1p-1)) (f64.const 0x1p52))
+(assert_return (invoke "f64.add" (f64.const 0x1.0000000000001p+52) (f64.const 0x1p-1)) (f64.const 0x1.0000000000002p+52))
+
+;; Computations that round differently in round-upward mode.
+(assert_return (invoke "f32.add" (f32.const -0x1.39675ap+102) (f32.const 0x1.76c94cp-99)) (f32.const -0x1.39675ap+102))
+(assert_return (invoke "f32.add" (f32.const 0x1.6c0f24p+67) (f32.const -0x1.2b92dp+52)) (f32.const 0x1.6c0cccp+67))
+(assert_return (invoke "f32.add" (f32.const 0x1.e62318p-83) (f32.const 0x1.f74abep-125)) (f32.const 0x1.e62318p-83))
+(assert_return (invoke "f32.add" (f32.const 0x1.2a71d4p+39) (f32.const -0x1.c9f10cp+55)) (f32.const -0x1.c9efe2p+55))
+(assert_return (invoke "f32.add" (f32.const 0x1.f8f736p-15) (f32.const 0x1.7bd45ep+106)) (f32.const 0x1.7bd45ep+106))
+(assert_return (invoke "f64.add" (f64.const 0x1.f33e1fbca27aap-413) (f64.const -0x1.6b192891ed61p+249)) (f64.const -0x1.6b192891ed61p+249))
+(assert_return (invoke "f64.add" (f64.const -0x1.46f75d130eeb1p+76) (f64.const 0x1.25275d6f7a4acp-184)) (f64.const -0x1.46f75d130eeb1p+76))
+(assert_return (invoke "f64.add" (f64.const 0x1.04dec9265a731p-148) (f64.const -0x1.11eed4e8c127cp-12)) (f64.const -0x1.11eed4e8c127cp-12))
+(assert_return (invoke "f64.add" (f64.const 0x1.05773b7166b0ap+497) (f64.const 0x1.134022f2da37bp+66)) (f64.const 0x1.05773b7166b0ap+497))
+(assert_return (invoke "f64.add" (f64.const 0x1.ef4f794282a82p+321) (f64.const 0x1.14a82266badep+394)) (f64.const 0x1.14a82266badep+394))
+
+;; Computations that round differently in round-downward mode.
+(assert_return (invoke "f32.add" (f32.const 0x1.1bf976p+72) (f32.const -0x1.7f5868p+20)) (f32.const 0x1.1bf976p+72))
+(assert_return (invoke "f32.add" (f32.const 0x1.7f9c6cp-45) (f32.const -0x1.b9bb0ep-78)) (f32.const 0x1.7f9c6cp-45))
+(assert_return (invoke "f32.add" (f32.const -0x1.32d1bcp-42) (f32.const 0x1.f7d214p+125)) (f32.const 0x1.f7d214p+125))
+(assert_return (invoke "f32.add" (f32.const -0x1.8e5c0ep-44) (f32.const -0x1.3afa4cp-106)) (f32.const -0x1.8e5c0ep-44))
+(assert_return (invoke "f32.add" (f32.const 0x1.13cd78p-10) (f32.const -0x1.3af316p-107)) (f32.const 0x1.13cd78p-10))
+(assert_return (invoke "f64.add" (f64.const 0x1.f8dd15ca97d4ap+179) (f64.const -0x1.367317d1fe8bfp-527)) (f64.const 0x1.f8dd15ca97d4ap+179))
+(assert_return (invoke "f64.add" (f64.const 0x1.5db08d739228cp+155) (f64.const -0x1.fb316fa147dcbp-61)) (f64.const 0x1.5db08d739228cp+155))
+(assert_return (invoke "f64.add" (f64.const 0x1.bbb403cb85c07p-404) (f64.const -0x1.7e44046b8bbf3p-979)) (f64.const 0x1.bbb403cb85c07p-404))
+(assert_return (invoke "f64.add" (f64.const -0x1.34d38af291831p+147) (f64.const -0x1.9890b47439953p+139)) (f64.const -0x1.366c1ba705bcap+147))
+(assert_return (invoke "f64.add" (f64.const -0x1.b61dedf4e0306p+3) (f64.const 0x1.09e2f31773c4ap+290)) (f64.const 0x1.09e2f31773c4ap+290))
+
+;; Computations that round differently in round-toward-zero mode.
+(assert_return (invoke "f32.add" (f32.const -0x1.129bd8p-117) (f32.const 0x1.c75012p-43)) (f32.const 0x1.c75012p-43))
+(assert_return (invoke "f32.add" (f32.const -0x1.c204a2p-16) (f32.const 0x1.80b132p-27)) (f32.const -0x1.c1d48cp-16))
+(assert_return (invoke "f32.add" (f32.const -0x1.decc1cp+36) (f32.const 0x1.c688dap-109)) (f32.const -0x1.decc1cp+36))
+(assert_return (invoke "f32.add" (f32.const 0x1.61ce6ap-118) (f32.const -0x1.772892p+30)) (f32.const -0x1.772892p+30))
+(assert_return (invoke "f32.add" (f32.const -0x1.3dc826p-120) (f32.const 0x1.fc3f66p+95)) (f32.const 0x1.fc3f66p+95))
+(assert_return (invoke "f64.add" (f64.const 0x1.bf68acc263a0fp-777) (f64.const -0x1.5f9352965e5a6p+1004)) (f64.const -0x1.5f9352965e5a6p+1004))
+(assert_return (invoke "f64.add" (f64.const -0x1.76eaa70911f51p+516) (f64.const -0x1.2d746324ce47ap+493)) (f64.const -0x1.76eaa963fabb6p+516))
+(assert_return (invoke "f64.add" (f64.const -0x1.b637d82c15a7ap-967) (f64.const 0x1.cc654ccab4152p-283)) (f64.const 0x1.cc654ccab4152p-283))
+(assert_return (invoke "f64.add" (f64.const -0x1.a5b1fb66e846ep-509) (f64.const 0x1.4bdd36f0bb5ccp-860)) (f64.const -0x1.a5b1fb66e846ep-509))
+(assert_return (invoke "f64.add" (f64.const -0x1.14108da880f9ep+966) (f64.const 0x1.417f35701e89fp+800)) (f64.const -0x1.14108da880f9ep+966))
+
+;; Computations that round differently on x87.
+(assert_return (invoke "f64.add" (f64.const -0x1.fa0caf21ffebcp+804) (f64.const 0x1.4ca8fdcff89f9p+826)) (f64.const 0x1.4ca8f5e7c5e31p+826))
+(assert_return (invoke "f64.add" (f64.const 0x1.016f1fcbdfd38p+784) (f64.const 0x1.375dffcbc9a2cp+746)) (f64.const 0x1.016f1fcbe4b0fp+784))
+(assert_return (invoke "f64.add" (f64.const -0x1.dffda6d5bff3ap+624) (f64.const 0x1.f9e8cc2dff782p+674)) (f64.const 0x1.f9e8cc2dff77bp+674))
+(assert_return (invoke "f64.add" (f64.const 0x1.fff4b43687dfbp+463) (f64.const 0x1.0fd5617c4a809p+517)) (f64.const 0x1.0fd5617c4a809p+517))
+(assert_return (invoke "f64.add" (f64.const 0x1.535d380035da2p-995) (f64.const 0x1.cce37dddbb73bp-963)) (f64.const 0x1.cce37ddf0ed0fp-963))
+
+;; Computations that round differently when computed via f32.
+(assert_return (invoke "f64.add" (f64.const -0x1.d91cd3fc0c66fp+752) (f64.const -0x1.4e18c80229734p+952)) (f64.const -0x1.4e18c80229734p+952))
+(assert_return (invoke "f64.add" (f64.const 0x1.afc70fd36e372p+193) (f64.const -0x1.bd10a9b377b46p+273)) (f64.const -0x1.bd10a9b377b46p+273))
+(assert_return (invoke "f64.add" (f64.const -0x1.2abd570b078b2p+302) (f64.const 0x1.b3c1ad759cb5bp-423)) (f64.const -0x1.2abd570b078b2p+302))
+(assert_return (invoke "f64.add" (f64.const -0x1.5b2ae84c0686cp-317) (f64.const -0x1.dba7a1c022823p+466)) (f64.const -0x1.dba7a1c022823p+466))
+(assert_return (invoke "f64.add" (f64.const -0x1.ac627bd7cbf38p-198) (f64.const 0x1.2312e265b8d59p-990)) (f64.const -0x1.ac627bd7cbf38p-198))
+
+;; Computations that utilize the maximum exponent value to avoid overflow.
+(assert_return (invoke "f32.add" (f32.const 0x1.2b91ap+116) (f32.const 0x1.cbcd52p+127)) (f32.const 0x1.cbf2c4p+127))
+(assert_return (invoke "f32.add" (f32.const 0x1.96f392p+127) (f32.const -0x1.6b3fecp+107)) (f32.const 0x1.96f37cp+127))
+(assert_return (invoke "f32.add" (f32.const 0x1.132f1cp+118) (f32.const -0x1.63d632p+127)) (f32.const -0x1.634c9ap+127))
+(assert_return (invoke "f32.add" (f32.const -0x1.1dda64p+120) (f32.const -0x1.ef02ep+127)) (f32.const -0x1.f13e94p+127))
+(assert_return (invoke "f32.add" (f32.const -0x1.4ad8dap+127) (f32.const -0x1.eae082p+125)) (f32.const -0x1.c590fap+127))
+(assert_return (invoke "f64.add" (f64.const 0x1.017099f2a4b8bp+1023) (f64.const 0x1.1f63b28f05454p+981)) (f64.const 0x1.017099f2a5009p+1023))
+(assert_return (invoke "f64.add" (f64.const 0x1.d88b6c74984efp+1023) (f64.const 0x1.33b444775eabcp+990)) (f64.const 0x1.d88b6c7532291p+1023))
+(assert_return (invoke "f64.add" (f64.const -0x1.84576422fdf5p+1023) (f64.const 0x1.60ee6aa12fb9cp+1012)) (f64.const -0x1.842b4655a9cf1p+1023))
+(assert_return (invoke "f64.add" (f64.const -0x1.9aaace3e79f7dp+1001) (f64.const 0x1.e4068af295cb6p+1023)) (f64.const 0x1.e4068487ea926p+1023))
+(assert_return (invoke "f64.add" (f64.const 0x1.06cdae79f27b9p+1023) (f64.const -0x1.e05cb0c96f975p+991)) (f64.const 0x1.06cdae78121eep+1023))
+
+;; Computations that utilize the minimum exponent value.
+(assert_return (invoke "f32.add" (f32.const 0x1.6a1a2p-127) (f32.const 0x1.378p-140)) (f32.const 0x1.6a23dcp-127))
+(assert_return (invoke "f32.add" (f32.const 0x1.28p-144) (f32.const -0x1p-148)) (f32.const 0x1.18p-144))
+(assert_return (invoke "f32.add" (f32.const -0x1p-146) (f32.const 0x1.c3cap-128)) (f32.const 0x1.c3c9cp-128))
+(assert_return (invoke "f32.add" (f32.const -0x1.4p-145) (f32.const 0x1.424052p-122)) (f32.const 0x1.42405p-122))
+(assert_return (invoke "f32.add" (f32.const 0x1.c5p-141) (f32.const -0x1.72f8p-135)) (f32.const -0x1.6be4p-135))
+(assert_return (invoke "f64.add" (f64.const 0x1.4774c681d1e21p-1022) (f64.const -0x1.271e58e9f58cap-1021)) (f64.const -0x1.06c7eb5219373p-1022))
+(assert_return (invoke "f64.add" (f64.const 0x1.10b3a75e31916p-1021) (f64.const -0x1.ffb82b0e868a7p-1021)) (f64.const -0x1.de090760a9f22p-1022))
+(assert_return (invoke "f64.add" (f64.const -0x0.6b58448b8098ap-1022) (f64.const -0x1.579796ed04cbep-1022)) (f64.const -0x1.c2efdb7885648p-1022))
+(assert_return (invoke "f64.add" (f64.const 0x1.9eb9e7baae8d1p-1020) (f64.const -0x1.d58e136f8c6eep-1020)) (f64.const -0x0.db50aed377874p-1022))
+(assert_return (invoke "f64.add" (f64.const -0x1.f1115deeafa0bp-1022) (f64.const 0x1.221b1c87dca29p-1022)) (f64.const -0x0.cef64166d2fe2p-1022))
+
+;; Test an add of the second-greatest finite value with the distance to greatest
+;; finite value.
+(assert_return (invoke "f32.add" (f32.const 0x1.fffffcp+127) (f32.const 0x1p+104)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "f64.add" (f64.const 0x1.ffffffffffffep+1023) (f64.const 0x1p+971)) (f64.const 0x1.fffffffffffffp+1023))
+
+;; http://news.harvard.edu/gazette/story/2013/09/dawn-of-a-revolution/
+(assert_return (invoke "f32.add" (f32.const 2.0) (f32.const 2.0)) (f32.const 4.0))
+(assert_return (invoke "f64.add" (f64.const 2.0) (f64.const 2.0)) (f64.const 4.0))
+
+;; Test rounding above the greatest finite value.
+(assert_return (invoke "f32.add" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+102)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "f32.add" (f32.const 0x1.fffffep+127) (f32.const 0x1p+103)) (f32.const inf))
+(assert_return (invoke "f64.add" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+969)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "f64.add" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p+970)) (f64.const inf))
+
+;; Test for a historic spreadsheet bug.
+;; https://blogs.office.com/2007/09/25/calculation-issue-update/
+(assert_return (invoke "f32.sub" (f32.const 65536.0) (f32.const 0x1p-37)) (f32.const 65536.0))
+(assert_return (invoke "f64.sub" (f64.const 65536.0) (f64.const 0x1p-37)) (f64.const 0x1.fffffffffffffp+15))
+
+;; Test subtracting the greatest value from 1.0 that rounds back to 1.0, and the
+;; least that rounds to something less.
+(assert_return (invoke "f32.sub" (f32.const 1.0) (f32.const 0x1p-25)) (f32.const 0x1.0p+0))
+(assert_return (invoke "f32.sub" (f32.const 1.0) (f32.const 0x1.000002p-25)) (f32.const 0x1.fffffep-1))
+(assert_return (invoke "f64.sub" (f64.const 1.0) (f64.const 0x1p-54)) (f64.const 0x1.0p+0))
+(assert_return (invoke "f64.sub" (f64.const 1.0) (f64.const 0x1.0000000000001p-54)) (f64.const 0x1.fffffffffffffp-1))
+
+;; Computations that round differently in round-upward mode.
+(assert_return (invoke "f32.sub" (f32.const 0x1.ee2466p-106) (f32.const -0x1.16277ep+119)) (f32.const 0x1.16277ep+119))
+(assert_return (invoke "f32.sub" (f32.const -0x1.446f9ep+119) (f32.const -0x1.4396a4p+43)) (f32.const -0x1.446f9ep+119))
+(assert_return (invoke "f32.sub" (f32.const 0x1.74773cp+0) (f32.const -0x1.a25512p-82)) (f32.const 0x1.74773cp+0))
+(assert_return (invoke "f32.sub" (f32.const 0x1.9345c4p-117) (f32.const 0x1.6792c2p-76)) (f32.const -0x1.6792c2p-76))
+(assert_return (invoke "f32.sub" (f32.const 0x1.9ecfa4p-18) (f32.const -0x1.864b44p-107)) (f32.const 0x1.9ecfa4p-18))
+(assert_return (invoke "f64.sub" (f64.const -0x1.5b798875e7845p-333) (f64.const -0x1.b5147117452fep-903)) (f64.const -0x1.5b798875e7845p-333))
+(assert_return (invoke "f64.sub" (f64.const -0x1.6c87baeb6d72dp+552) (f64.const -0x1.64fb35d4b5571p-158)) (f64.const -0x1.6c87baeb6d72dp+552))
+(assert_return (invoke "f64.sub" (f64.const 0x1.b3d369fcf74bp-461) (f64.const -0x1.ea1668c0dec93p-837)) (f64.const 0x1.b3d369fcf74bp-461))
+(assert_return (invoke "f64.sub" (f64.const 0x1.0abd449353eadp-1005) (f64.const -0x1.0422ea3e82ee9p+154)) (f64.const 0x1.0422ea3e82ee9p+154))
+(assert_return (invoke "f64.sub" (f64.const -0x1.aadbc6b43cc3dp-143) (f64.const -0x1.e7f922ef1ee58p-539)) (f64.const -0x1.aadbc6b43cc3dp-143))
+
+;; Computations that round differently in round-downward mode.
+(assert_return (invoke "f32.sub" (f32.const -0x1.61e262p+108) (f32.const -0x1.baf3e4p+112)) (f32.const 0x1.a4d5bep+112))
+(assert_return (invoke "f32.sub" (f32.const -0x1.62c2f6p+109) (f32.const 0x1.6e514ap+6)) (f32.const -0x1.62c2f6p+109))
+(assert_return (invoke "f32.sub" (f32.const -0x1.287c94p-83) (f32.const 0x1.0f2f9cp-24)) (f32.const -0x1.0f2f9cp-24))
+(assert_return (invoke "f32.sub" (f32.const -0x1.c8825cp-77) (f32.const -0x1.4aead6p-12)) (f32.const 0x1.4aead6p-12))
+(assert_return (invoke "f32.sub" (f32.const -0x1.2976a4p+99) (f32.const 0x1.c6e3b8p-59)) (f32.const -0x1.2976a4p+99))
+(assert_return (invoke "f64.sub" (f64.const -0x1.76cb28ae6c045p+202) (f64.const -0x1.0611f2af4e9b9p+901)) (f64.const 0x1.0611f2af4e9b9p+901))
+(assert_return (invoke "f64.sub" (f64.const 0x1.baf35eff22e9ep-368) (f64.const 0x1.5c3e08ecf73ecp-451)) (f64.const 0x1.baf35eff22e9ep-368))
+(assert_return (invoke "f64.sub" (f64.const -0x1.8fd354b376f1fp-200) (f64.const 0x1.513c860f386ffp-508)) (f64.const -0x1.8fd354b376f1fp-200))
+(assert_return (invoke "f64.sub" (f64.const -0x1.760d447230ae6p-992) (f64.const -0x1.16f788438ae3ep-328)) (f64.const 0x1.16f788438ae3ep-328))
+(assert_return (invoke "f64.sub" (f64.const -0x1.73aab4fcfc7ap+112) (f64.const 0x1.7c589f990b884p+171)) (f64.const -0x1.7c589f990b884p+171))
+
+;; Computations that round differently in round-toward-zero mode.
+(assert_return (invoke "f32.sub" (f32.const 0x1.ea264cp+95) (f32.const 0x1.852988p-15)) (f32.const 0x1.ea264cp+95))
+(assert_return (invoke "f32.sub" (f32.const -0x1.14ec7cp+19) (f32.const -0x1.0ad3fep-35)) (f32.const -0x1.14ec7cp+19))
+(assert_return (invoke "f32.sub" (f32.const -0x1.3251dap-36) (f32.const -0x1.49c97ep-56)) (f32.const -0x1.3251c6p-36))
+(assert_return (invoke "f32.sub" (f32.const -0x1.13565ep-14) (f32.const 0x1.2f89a8p-13)) (f32.const -0x1.b934d8p-13))
+(assert_return (invoke "f32.sub" (f32.const -0x1.6032b6p-33) (f32.const -0x1.bb5196p-104)) (f32.const -0x1.6032b6p-33))
+(assert_return (invoke "f64.sub" (f64.const -0x1.b5b0797af491p-157) (f64.const -0x1.694b8348189e8p+722)) (f64.const 0x1.694b8348189e8p+722))
+(assert_return (invoke "f64.sub" (f64.const -0x1.72b142826ed73p+759) (f64.const -0x1.010477bc9afbdp+903)) (f64.const 0x1.010477bc9afbdp+903))
+(assert_return (invoke "f64.sub" (f64.const 0x1.83273b6bb94cfp-796) (f64.const 0x1.1a93f948a2abbp+181)) (f64.const -0x1.1a93f948a2abbp+181))
+(assert_return (invoke "f64.sub" (f64.const -0x1.207e7156cbf2p-573) (f64.const 0x1.cf3f12fd3814dp-544)) (f64.const -0x1.cf3f13063c086p-544))
+(assert_return (invoke "f64.sub" (f64.const -0x1.837e6844f1718p-559) (f64.const -0x1.1c29b757f98abp-14)) (f64.const 0x1.1c29b757f98abp-14))
+
+;; Computations that round differently on x87.
+(assert_return (invoke "f64.sub" (f64.const 0x1.c21151a709b6cp-78) (f64.const 0x1.0a12fff8910f6p-115)) (f64.const 0x1.c21151a701663p-78))
+(assert_return (invoke "f64.sub" (f64.const 0x1.c57912aae2f64p-982) (f64.const 0x1.dbfbd4800b7cfp-1010)) (f64.const 0x1.c579128d2338fp-982))
+(assert_return (invoke "f64.sub" (f64.const 0x1.ffef4399af9c6p-254) (f64.const 0x1.edb96dfaea8b1p-200)) (f64.const -0x1.edb96dfaea8b1p-200))
+(assert_return (invoke "f64.sub" (f64.const -0x1.363eee391cde2p-39) (f64.const -0x1.a65462000265fp-69)) (f64.const -0x1.363eee32838c9p-39))
+(assert_return (invoke "f64.sub" (f64.const 0x1.59016dba002a1p-25) (f64.const 0x1.5d4374f124cccp-3)) (f64.const -0x1.5d436f8d1f15dp-3))
+
+;; Computations that round differently when computed via f32.
+(assert_return (invoke "f64.sub" (f64.const -0x1.18196bca005cfp-814) (f64.const -0x1.db7b01ce3f52fp-766)) (f64.const 0x1.db7b01ce3f51dp-766))
+(assert_return (invoke "f64.sub" (f64.const -0x1.d17b3528d219p+33) (f64.const 0x1.fd739d4ea220ap+367)) (f64.const -0x1.fd739d4ea220ap+367))
+(assert_return (invoke "f64.sub" (f64.const 0x1.dea46994de319p+114) (f64.const 0x1.b5b19cd55c7d3p-590)) (f64.const 0x1.dea46994de319p+114))
+(assert_return (invoke "f64.sub" (f64.const 0x1.b60f9b2fbd9ecp-489) (f64.const -0x1.6f81c59ec5b8ep-694)) (f64.const 0x1.b60f9b2fbd9ecp-489))
+(assert_return (invoke "f64.sub" (f64.const 0x1.5e423fe8571f4p-57) (f64.const 0x1.9624ed7c162dfp-618)) (f64.const 0x1.5e423fe8571f4p-57))
+
+;; pow(e, π) - π
+;; https://xkcd.com/217/
+(assert_return (invoke "f32.sub" (f32.const 0x1.724046p+4) (f32.const 0x1.921fb6p+1)) (f32.const 0x1.3ffc5p+4))
+(assert_return (invoke "f64.sub" (f64.const 0x1.724046eb0933ap+4) (f64.const 0x1.921fb54442d18p+1)) (f64.const 0x1.3ffc504280d97p+4))
+
+;; https://www.cnet.com/news/googles-calculator-muffs-some-math-problems/
+(assert_return (invoke "f32.sub" (f32.const 2999999) (f32.const 2999998)) (f32.const 1.0))
+(assert_return (invoke "f32.sub" (f32.const 1999999) (f32.const 1999995)) (f32.const 4.0))
+(assert_return (invoke "f32.sub" (f32.const 1999999) (f32.const 1999993)) (f32.const 6.0))
+(assert_return (invoke "f32.sub" (f32.const 400002) (f32.const 400001)) (f32.const 1.0))
+(assert_return (invoke "f32.sub" (f32.const 400002) (f32.const 400000)) (f32.const 2.0))
+(assert_return (invoke "f64.sub" (f64.const 2999999999999999) (f64.const 2999999999999998)) (f64.const 1.0))
+(assert_return (invoke "f64.sub" (f64.const 1999999999999999) (f64.const 1999999999999995)) (f64.const 4.0))
+(assert_return (invoke "f64.sub" (f64.const 1999999999999999) (f64.const 1999999999999993)) (f64.const 6.0))
+(assert_return (invoke "f64.sub" (f64.const 400000000000002) (f64.const 400000000000001)) (f64.const 1.0))
+(assert_return (invoke "f64.sub" (f64.const 400000000000002) (f64.const 400000000000000)) (f64.const 2.0))
+
+;; Min normal - max subnormal = min subnormal.
+(assert_return (invoke "f32.sub" (f32.const 0x1p-126) (f32.const 0x1.fffffcp-127)) (f32.const 0x1p-149))
+(assert_return (invoke "f64.sub" (f64.const 0x1p-1022) (f64.const 0x0.fffffffffffffp-1022)) (f64.const 0x0.0000000000001p-1022))
+
+;; Test subtraction of numbers very close to 1.
+(assert_return (invoke "f32.sub" (f32.const 0x1.000002p+0) (f32.const 0x1.fffffep-1)) (f32.const 0x1.8p-23))
+(assert_return (invoke "f32.sub" (f32.const 0x1.000002p+0) (f32.const 0x1.0p+0)) (f32.const 0x1p-23))
+(assert_return (invoke "f32.sub" (f32.const 0x1p+0) (f32.const 0x1.fffffep-1)) (f32.const 0x1p-24))
+(assert_return (invoke "f64.sub" (f64.const 0x1.0000000000001p+0) (f64.const 0x1.fffffffffffffp-1)) (f64.const 0x1.8p-52))
+(assert_return (invoke "f64.sub" (f64.const 0x1.0000000000001p+0) (f64.const 0x1.0p+0)) (f64.const 0x1p-52))
+(assert_return (invoke "f64.sub" (f64.const 0x1p+0) (f64.const 0x1.fffffffffffffp-1)) (f64.const 0x1p-53))
+
+;; Test the least value that can be subtracted from the max value to produce a
+;; different value.
+(assert_return (invoke "f32.sub" (f32.const 0x1.fffffep+127) (f32.const 0x1.fffffep+102)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "f32.sub" (f32.const 0x1.fffffep+127) (f32.const 0x1p+103)) (f32.const 0x1.fffffcp+127))
+(assert_return (invoke "f64.sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1.fffffffffffffp+969)) (f64.const 0x1.fffffffffffffp+1023))
+(assert_return (invoke "f64.sub" (f64.const 0x1.fffffffffffffp+1023) (f64.const 0x1p+970)) (f64.const 0x1.ffffffffffffep+1023))
+
+;; Miscellaneous values.
+(assert_return (invoke "f32.mul" (f32.const 1e15) (f32.const 1e15)) (f32.const 0x1.93e592p+99))
+(assert_return (invoke "f32.mul" (f32.const 1e20) (f32.const 1e20)) (f32.const inf))
+(assert_return (invoke "f32.mul" (f32.const 1e25) (f32.const 1e25)) (f32.const inf))
+(assert_return (invoke "f64.mul" (f64.const 1e15) (f64.const 1e15)) (f64.const 0x1.93e5939a08ceap+99))
+(assert_return (invoke "f64.mul" (f64.const 1e20) (f64.const 1e20)) (f64.const 0x1.d6329f1c35ca5p+132))
+(assert_return (invoke "f64.mul" (f64.const 1e25) (f64.const 1e25)) (f64.const 0x1.11b0ec57e649bp+166))
+
+;; Test for a case of double rounding, example from:
+;; http://perso.ens-lyon.fr/jean-michel.muller/Handbook.html
+;; section 3.3.1: A typical problem: "double rounding"
+(assert_return (invoke "f32.mul" (f32.const 1848874880.0) (f32.const 19954563072.0)) (f32.const 0x1.000002p+65))
+(assert_return (invoke "f64.mul" (f64.const 1848874847.0) (f64.const 19954562207.0)) (f64.const 3.6893488147419111424e+19))
+
+;; Test for a historic spreadsheet bug.
+;; http://www.joelonsoftware.com/items/2007/09/26b.html
+(assert_return (invoke "f32.mul" (f32.const 77.1) (f32.const 850)) (f32.const 65535))
+(assert_return (invoke "f64.mul" (f64.const 77.1) (f64.const 850)) (f64.const 65534.99999999999272404))
+
+;; Computations that round differently in round-upward mode.
+(assert_return (invoke "f32.mul" (f32.const -0x1.14df2ep+61) (f32.const 0x1.748878p-36)) (f32.const -0x1.92e7e8p+25))
+(assert_return (invoke "f32.mul" (f32.const -0x1.5629e2p+102) (f32.const -0x1.c33012p-102)) (f32.const 0x1.2d8604p+1))
+(assert_return (invoke "f32.mul" (f32.const -0x1.b17694p+92) (f32.const -0x1.e4b56ap-97)) (f32.const 0x1.9a5baep-4))
+(assert_return (invoke "f32.mul" (f32.const -0x1.1626a6p+79) (f32.const -0x1.c57d7p-75)) (f32.const 0x1.ecbaaep+4))
+(assert_return (invoke "f32.mul" (f32.const 0x1.7acf72p+53) (f32.const 0x1.6c89acp+5)) (f32.const 0x1.0db556p+59))
+(assert_return (invoke "f64.mul" (f64.const -0x1.25c293f6f37e4p+425) (f64.const 0x1.f5fd4fa41c6d8p+945)) (f64.const -inf))
+(assert_return (invoke "f64.mul" (f64.const -0x1.cc1ae79fffc5bp-986) (f64.const -0x1.c36ccc2861ca6p-219)) (f64.const 0x0p+0))
+(assert_return (invoke "f64.mul" (f64.const 0x1.c0232b3e64b56p+606) (f64.const -0x1.f6939cf3affaap+106)) (f64.const -0x1.b7e3aedf190d3p+713))
+(assert_return (invoke "f64.mul" (f64.const -0x1.60f289966b271p-313) (f64.const 0x1.28a5497f0c259p+583)) (f64.const -0x1.98fc50bcec259p+270))
+(assert_return (invoke "f64.mul" (f64.const 0x1.37dab12d3afa2p+795) (f64.const 0x1.81e156bd393f1p-858)) (f64.const 0x1.d6126554b8298p-63))
+
+;; Computations that round differently in round-downward mode.
+(assert_return (invoke "f32.mul" (f32.const -0x1.3f57a2p-89) (f32.const -0x1.041d68p+92)) (f32.const 0x1.4479bp+3))
+(assert_return (invoke "f32.mul" (f32.const 0x1.4d0582p+73) (f32.const 0x1.6e043ap+19)) (f32.const 0x1.dc236p+92))
+(assert_return (invoke "f32.mul" (f32.const -0x1.2fdap-32) (f32.const -0x1.e1731cp+74)) (f32.const 0x1.1db89ep+43))
+(assert_return (invoke "f32.mul" (f32.const 0x1.7bc8fep+67) (f32.const -0x1.3ad592p+15)) (f32.const -0x1.d3115ep+82))
+(assert_return (invoke "f32.mul" (f32.const 0x1.936742p+30) (f32.const -0x1.a7a19p+66)) (f32.const -0x1.4dc71ap+97))
+(assert_return (invoke "f64.mul" (f64.const -0x1.ba737b4ca3b13p-639) (f64.const 0x1.8923309857438p-314)) (f64.const -0x1.53bc0d07baa37p-952))
+(assert_return (invoke "f64.mul" (f64.const 0x1.7c1932e610219p-276) (f64.const -0x1.2605db646489fp-635)) (f64.const -0x1.b48da2b0d2ae3p-911))
+(assert_return (invoke "f64.mul" (f64.const -0x1.e43cdf3b2108p+329) (f64.const -0x1.99d96abbd61d1p+835)) (f64.const inf))
+(assert_return (invoke "f64.mul" (f64.const 0x1.4c19466551da3p+947) (f64.const 0x1.0bdcd6c7646e9p-439)) (f64.const 0x1.5b7cd8c3f638ap+508))
+(assert_return (invoke "f64.mul" (f64.const 0x1.ff1da1726e3dfp+339) (f64.const -0x1.043c44f52b158p+169)) (f64.const -0x1.03c9364bb585cp+509))
+
+;; Computations that round differently in round-toward-zero mode.
+(assert_return (invoke "f32.mul" (f32.const -0x1.907e8ap+46) (f32.const -0x1.5d3668p+95)) (f32.const inf))
+(assert_return (invoke "f32.mul" (f32.const -0x1.8c9f74p-3) (f32.const 0x1.e2b452p-99)) (f32.const -0x1.75edccp-101))
+(assert_return (invoke "f32.mul" (f32.const -0x1.cc605ap-19) (f32.const 0x1.ec321ap+105)) (f32.const -0x1.ba91a4p+87))
+(assert_return (invoke "f32.mul" (f32.const -0x1.5fbb7ap+56) (f32.const 0x1.a8965ep-96)) (f32.const -0x1.23ae8ep-39))
+(assert_return (invoke "f32.mul" (f32.const -0x1.fb7f12p+16) (f32.const 0x1.3a701ap-119)) (f32.const -0x1.37ac0cp-102))
+(assert_return (invoke "f64.mul" (f64.const -0x1.5b0266454c26bp-496) (f64.const -0x1.af5787e3e0399p+433)) (f64.const 0x1.2457d81949e0bp-62))
+(assert_return (invoke "f64.mul" (f64.const 0x1.0d54a82393d45p+478) (f64.const -0x1.425760807ceaep-764)) (f64.const -0x1.532068c8d0d5dp-286))
+(assert_return (invoke "f64.mul" (f64.const -0x1.b532af981786p+172) (f64.const 0x1.ada95085ba36fp+359)) (f64.const -0x1.6ee38c1e01864p+532))
+(assert_return (invoke "f64.mul" (f64.const 0x1.e132f4d49d1cep+768) (f64.const -0x1.a75afe9a7d864p+374)) (f64.const -inf))
+(assert_return (invoke "f64.mul" (f64.const 0x1.68bbf1cfff90ap+81) (f64.const 0x1.09cd17d652c5p+70)) (f64.const 0x1.768b8d67d794p+151))
+
+;; Computations that round differently on x87.
+(assert_return (invoke "f64.mul" (f64.const 0x1.f99fb602c89b7p-341) (f64.const 0x1.6caab46a31a2ep-575)) (f64.const 0x1.68201f986e9d7p-915))
+(assert_return (invoke "f64.mul" (f64.const -0x1.86999c5eee379p-9) (f64.const 0x1.6e3b9e0d53e0dp+723)) (f64.const -0x1.17654a0ef35f5p+715))
+(assert_return (invoke "f64.mul" (f64.const -0x1.069571b176f9p+367) (f64.const -0x1.e248b6ab0a0e3p-652)) (f64.const 0x1.eeaff575cae1dp-285))
+(assert_return (invoke "f64.mul" (f64.const 0x1.c217645777dd2p+775) (f64.const 0x1.d93f5715dd646p+60)) (f64.const 0x1.a0064aa1d920dp+836))
+(assert_return (invoke "f64.mul" (f64.const -0x1.848981b6e694ap-276) (f64.const 0x1.f5aacb64a0d19p+896)) (f64.const -0x1.7cb2296e6c2e5p+621))
+
+;; Computations that round differently on x87 in double-precision mode.
+(assert_return (invoke "f64.mul" (f64.const 0x1.db3bd2a286944p-599) (f64.const 0x1.ce910af1d55cap-425)) (f64.const 0x0.d6accdd538a39p-1022))
+(assert_return (invoke "f64.mul" (f64.const -0x1.aca223916012p-57) (f64.const -0x1.2b2b4958dd228p-966)) (f64.const 0x0.fa74eccae5615p-1022))
+(assert_return (invoke "f64.mul" (f64.const -0x1.bd062def16cffp-488) (f64.const -0x1.7ddd91a0c4c0ep-536)) (f64.const 0x0.a5f4d7769d90dp-1022))
+(assert_return (invoke "f64.mul" (f64.const -0x1.c6a56169e9cep-772) (f64.const 0x1.517d55a474122p-255)) (f64.const -0x0.12baf260afb77p-1022))
+(assert_return (invoke "f64.mul" (f64.const -0x1.08951b0b41705p-516) (f64.const -0x1.102dc27168d09p-507)) (f64.const 0x0.8ca6dbf3f592bp-1022))
+
+;; Computations that round differently when computed via f32.
+(assert_return (invoke "f64.mul" (f64.const 0x1.8d0dea50c8c9bp+852) (f64.const 0x1.21cac31d87a24p-881)) (f64.const 0x1.c177311f7cd73p-29))
+(assert_return (invoke "f64.mul" (f64.const 0x1.98049118e3063p-7) (f64.const 0x1.6362525151b58p-149)) (f64.const 0x1.1b358514103f9p-155))
+(assert_return (invoke "f64.mul" (f64.const -0x1.ea65cb0631323p+1) (f64.const 0x1.fce683201a19bp-41)) (f64.const -0x1.e76dc8c223667p-39))
+(assert_return (invoke "f64.mul" (f64.const 0x1.e4d235961d543p-373) (f64.const 0x1.bc56f20ef9a48p-205)) (f64.const 0x1.a4c09efcb71d6p-577))
+(assert_return (invoke "f64.mul" (f64.const -0x1.b9612e66faba8p+77) (f64.const 0x1.e2bc6aa782273p-348)) (f64.const -0x1.a026ea4f81db1p-270))
+
+;; Test the least positive value with a positive square.
+(assert_return (invoke "f32.mul" (f32.const 0x1p-75) (f32.const 0x1p-75)) (f32.const 0x0p+0))
+(assert_return (invoke "f32.mul" (f32.const 0x1.000002p-75) (f32.const 0x1.000002p-75)) (f32.const 0x1p-149))
+(assert_return (invoke "f64.mul" (f64.const 0x1.6a09e667f3bccp-538) (f64.const 0x1.6a09e667f3bccp-538)) (f64.const 0x0p+0))
+(assert_return (invoke "f64.mul" (f64.const 0x1.6a09e667f3bcdp-538) (f64.const 0x1.6a09e667f3bcdp-538)) (f64.const 0x0.0000000000001p-1022))
+
+;; Test the greatest positive value with a finite square.
+(assert_return (invoke "f32.mul" (f32.const 0x1.fffffep+63) (f32.const 0x1.fffffep+63)) (f32.const 0x1.fffffcp+127))
+(assert_return (invoke "f32.mul" (f32.const 0x1p+64) (f32.const 0x1p+64)) (f32.const inf))
+(assert_return (invoke "f64.mul" (f64.const 0x1.fffffffffffffp+511) (f64.const 0x1.fffffffffffffp+511)) (f64.const 0x1.ffffffffffffep+1023))
+(assert_return (invoke "f64.mul" (f64.const 0x1p+512) (f64.const 0x1p+512)) (f64.const inf))
+
+;; Test the squares of values very close to 1.
+(assert_return (invoke "f32.mul" (f32.const 0x1.000002p+0) (f32.const 0x1.000002p+0)) (f32.const 0x1.000004p+0))
+(assert_return (invoke "f32.mul" (f32.const 0x1.fffffep-1) (f32.const 0x1.fffffep-1)) (f32.const 0x1.fffffcp-1))
+(assert_return (invoke "f64.mul" (f64.const 0x1.0000000000001p+0) (f64.const 0x1.0000000000001p+0)) (f64.const 0x1.0000000000002p+0))
+(assert_return (invoke "f64.mul" (f64.const 0x1.fffffffffffffp-1) (f64.const 0x1.fffffffffffffp-1)) (f64.const 0x1.ffffffffffffep-1))
+
+;; Test multiplication of numbers very close to 1.
+(assert_return (invoke "f32.mul" (f32.const 0x1.000002p+0) (f32.const 0x1.fffffep-1)) (f32.const 0x1p+0))
+(assert_return (invoke "f32.mul" (f32.const 0x1.000004p+0) (f32.const 0x1.fffffcp-1)) (f32.const 0x1.000002p+0))
+(assert_return (invoke "f64.mul" (f64.const 0x1.0000000000001p+0) (f64.const 0x1.fffffffffffffp-1)) (f64.const 0x1p+0))
+(assert_return (invoke "f64.mul" (f64.const 0x1.0000000000002p+0) (f64.const 0x1.ffffffffffffep-1)) (f64.const 0x1.0000000000001p+0))
+
+;; Test MIN * EPSILON.
+;; http://www.mpfr.org/mpfr-2.0.1/patch2
+(assert_return (invoke "f32.mul" (f32.const 0x1p-126) (f32.const 0x1p-23)) (f32.const 0x1p-149))
+(assert_return (invoke "f64.mul" (f64.const 0x1p-1022) (f64.const 0x1p-52)) (f64.const 0x0.0000000000001p-1022))
+
+;; http://opencores.org/bug,view,2454
+(assert_return (invoke "f32.mul" (f32.const -0x1.0006p+4) (f32.const 0x1.ap-132)) (f32.const -0x1.a009cp-128))
+
+;; Miscellaneous values.
+(assert_return (invoke "f32.div" (f32.const 1.123456789) (f32.const 100)) (f32.const 0x1.702264p-7))
+(assert_return (invoke "f32.div" (f32.const 8391667.0) (f32.const 12582905.0)) (f32.const 0x1.55754p-1))
+(assert_return (invoke "f32.div" (f32.const 65536.0) (f32.const 0x1p-37)) (f32.const 0x1p+53))
+(assert_return (invoke "f32.div" (f32.const 0x1.dcbf6ap+0) (f32.const 0x1.fffffep+127)) (f32.const 0x1.dcbf68p-128))
+(assert_return (invoke "f32.div" (f32.const 4) (f32.const 3)) (f32.const 0x1.555556p+0))
+(assert_return (invoke "f64.div" (f64.const 1.123456789) (f64.const 100)) (f64.const 0.01123456789))
+(assert_return (invoke "f64.div" (f64.const 8391667.0) (f64.const 12582905.0)) (f64.const 0x1.55753f1d9ba27p-1))
+(assert_return (invoke "f64.div" (f64.const 65536.0) (f64.const 0x1p-37)) (f64.const 0x1p+53))
+(assert_return (invoke "f64.div" (f64.const 0x1.dcbf6ap+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0.772fda8p-1022))
+(assert_return (invoke "f64.div" (f64.const 4) (f64.const 3)) (f64.const 0x1.5555555555555p+0))
+
+;; Test for a historic hardware bug.
+;; https://en.wikipedia.org/wiki/Pentium_FDIV_bug
+(assert_return (invoke "f32.div" (f32.const 4195835) (f32.const 3145727)) (f32.const 0x1.557542p+0))
+(assert_return (invoke "f64.div" (f64.const 4195835) (f64.const 3145727)) (f64.const 0x1.557541c7c6b43p+0))
+
+;; Computations that round differently in round-upward mode.
+(assert_return (invoke "f32.div" (f32.const 0x1.6a6c5ap-48) (f32.const 0x1.fa0b7p+127)) (f32.const 0x0p+0))
+(assert_return (invoke "f32.div" (f32.const 0x1.616fb2p-87) (f32.const 0x1.332172p+68)) (f32.const 0x0p+0))
+(assert_return (invoke "f32.div" (f32.const -0x1.96e778p+16) (f32.const 0x1.eb0c56p-80)) (f32.const -0x1.a8440ap+95))
+(assert_return (invoke "f32.div" (f32.const -0x1.e2624p-76) (f32.const -0x1.ed236ep-122)) (f32.const 0x1.f4d584p+45))
+(assert_return (invoke "f32.div" (f32.const -0x1.e2374ep+41) (f32.const 0x1.71fcdcp-80)) (f32.const -0x1.4da706p+121))
+(assert_return (invoke "f64.div" (f64.const 0x1.163c09d0c38c1p+147) (f64.const 0x1.e04cc737348e6p+223)) (f64.const 0x1.289921caeed23p-77))
+(assert_return (invoke "f64.div" (f64.const 0x1.d6867e741e0a9p-626) (f64.const 0x1.335eb19a9aae4p-972)) (f64.const 0x1.87e342d11f519p+346))
+(assert_return (invoke "f64.div" (f64.const -0x1.d5edf648aeb98p+298) (f64.const 0x1.0dda15b079355p+640)) (f64.const -0x1.bdceaf9734b5cp-342))
+(assert_return (invoke "f64.div" (f64.const -0x1.b683e3934aedap+691) (f64.const 0x1.c364e1df00dffp+246)) (f64.const -0x1.f16456e7afe3bp+444))
+(assert_return (invoke "f64.div" (f64.const -0x1.44ca7539cc851p+540) (f64.const 0x1.58501bccc58fep+453)) (f64.const -0x1.e2f8657e0924ep+86))
+
+;; Computations that round differently in round-downward mode.
+(assert_return (invoke "f32.div" (f32.const -0x1.c2c54ap+69) (f32.const -0x1.00d142p-86)) (f32.const inf))
+(assert_return (invoke "f32.div" (f32.const 0x1.e35abep-46) (f32.const 0x1.c69dfp+44)) (f32.const 0x1.102eb4p-90))
+(assert_return (invoke "f32.div" (f32.const 0x1.45ff2ap+0) (f32.const -0x1.1e8754p+89)) (f32.const -0x1.23434ep-89))
+(assert_return (invoke "f32.div" (f32.const 0x1.8db18ap-51) (f32.const 0x1.47c678p-128)) (f32.const 0x1.369b96p+77))
+(assert_return (invoke "f32.div" (f32.const 0x1.78599p+90) (f32.const 0x1.534144p+87)) (f32.const 0x1.1bfddcp+3))
+(assert_return (invoke "f64.div" (f64.const 0x0.f331c4f47eb51p-1022) (f64.const -0x1.c7ff45bf6f03ap+362)) (f64.const -0x0p+0))
+(assert_return (invoke "f64.div" (f64.const -0x1.0fc8707b9d19cp-987) (f64.const 0x1.77524d5f4a563p-536)) (f64.const -0x1.72c1a937d231p-452))
+(assert_return (invoke "f64.div" (f64.const -0x1.edb3aa64bb338p-403) (f64.const -0x1.1c7c164320e4p+45)) (f64.const 0x1.bc44cc1c5ae63p-448))
+(assert_return (invoke "f64.div" (f64.const -0x1.6534b34e8686bp+80) (f64.const 0x1.c34a7fc59e3c3p-791)) (f64.const -0x1.95421bf291b66p+870))
+(assert_return (invoke "f64.div" (f64.const -0x1.91f58d7ed1237p+236) (f64.const -0x1.f190d808383c8p+55)) (f64.const 0x1.9d9eb0836f906p+180))
+
+;; Computations that round differently in round-toward-zero mode.
+(assert_return (invoke "f32.div" (f32.const 0x1.64b2a4p+26) (f32.const 0x1.e95752p-119)) (f32.const inf))
+(assert_return (invoke "f32.div" (f32.const -0x1.53c9b6p+77) (f32.const 0x1.d689ap+27)) (f32.const -0x1.71baa4p+49))
+(assert_return (invoke "f32.div" (f32.const 0x1.664a8ap+38) (f32.const -0x1.59dba2p+96)) (f32.const -0x1.0933f4p-58))
+(assert_return (invoke "f32.div" (f32.const -0x1.99e0fap+111) (f32.const -0x1.c2b5a8p+9)) (f32.const 0x1.d19de6p+101))
+(assert_return (invoke "f32.div" (f32.const -0x1.5a815ap+92) (f32.const -0x1.b5820ap+13)) (f32.const 0x1.9580b8p+78))
+(assert_return (invoke "f64.div" (f64.const -0x1.81fd1e2af7bebp-655) (f64.const 0x1.edefc4eae536cp-691)) (f64.const -0x1.901abdd91b661p+35))
+(assert_return (invoke "f64.div" (f64.const -0x1.47cf932953c43p+782) (f64.const -0x1.bc40496b1f2a1p-553)) (f64.const inf))
+(assert_return (invoke "f64.div" (f64.const -0x1.2bd2e8fbdcad7p-746) (f64.const 0x1.b115674cc476ep-65)) (f64.const -0x1.62752bf19fa81p-682))
+(assert_return (invoke "f64.div" (f64.const -0x1.f923e3fea9efep+317) (f64.const -0x1.8044c74d27a39p-588)) (f64.const 0x1.5086518cc7186p+905))
+(assert_return (invoke "f64.div" (f64.const 0x1.516ed2051d6bbp+181) (f64.const -0x1.c9f455eb9c2eep+214)) (f64.const -0x1.79414d67f2889p-34))
+
+;; Computations that round differently on x87.
+(assert_return (invoke "f64.div" (f64.const -0x1.9c52726aed366p+585) (f64.const -0x1.7d0568c75660fp+195)) (f64.const 0x1.1507ca2a65f23p+390))
+(assert_return (invoke "f64.div" (f64.const -0x1.522672f461667p+546) (f64.const -0x1.36d36572c9f71p+330)) (f64.const 0x1.1681369370619p+216))
+(assert_return (invoke "f64.div" (f64.const 0x1.01051b4e8cd61p+185) (f64.const -0x1.2cbb5ca3d33ebp+965)) (f64.const -0x1.b59471598a2f3p-781))
+(assert_return (invoke "f64.div" (f64.const 0x1.5f93bb80fc2cbp+217) (f64.const 0x1.7e051aae9f0edp+427)) (f64.const 0x1.d732fa926ba4fp-211))
+(assert_return (invoke "f64.div" (f64.const -0x1.e251d762163ccp+825) (f64.const 0x1.3ee63581e1796p+349)) (f64.const -0x1.8330077d90a07p+476))
+
+;; Computations that round differently on x87 in double-precision mode.
+(assert_return (invoke "f64.div" (f64.const 0x1.dcbf69f10006dp+0) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0.772fda7c4001bp-1022))
+(assert_return (invoke "f64.div" (f64.const 0x1.e14169442fbcap-1011) (f64.const 0x1.505451d62ff7dp+12)) (f64.const 0x0.b727e85f38b39p-1022))
+(assert_return (invoke "f64.div" (f64.const -0x1.d3ebe726ec964p-144) (f64.const -0x1.4a7bfc0b83608p+880)) (f64.const 0x0.5a9d8c50cbf87p-1022))
+(assert_return (invoke "f64.div" (f64.const -0x1.6c3def770aee1p-393) (f64.const -0x1.8b84724347598p+631)) (f64.const 0x0.3af0707fcd0c7p-1022))
+(assert_return (invoke "f64.div" (f64.const 0x1.16abda1bb3cb3p-856) (f64.const 0x1.6c9c7198eb1e6p+166)) (f64.const 0x0.c3a8fd6741649p-1022))
+(assert_return (invoke "f64.div" (f64.const 0x1.7057d6ab553cap-1005) (f64.const -0x1.2abf1e98660ebp+23)) (f64.const -0x0.04ee8d8ec01cdp-1022))
+
+;; Computations that round differently when div is mul by reciprocal.
+(assert_return (invoke "f32.div" (f32.const 0x1.ada9aap+89) (f32.const 0x1.69884cp+42)) (f32.const 0x1.303e2ep+47))
+(assert_return (invoke "f32.div" (f32.const 0x1.8281c8p+90) (f32.const -0x1.62883cp+106)) (f32.const -0x1.17169cp-16))
+(assert_return (invoke "f32.div" (f32.const 0x1.5c6be2p+81) (f32.const 0x1.d01dfep-1)) (f32.const 0x1.805e32p+81))
+(assert_return (invoke "f32.div" (f32.const -0x1.bbd252p+19) (f32.const -0x1.fba95p+33)) (f32.const 0x1.bf9d56p-15))
+(assert_return (invoke "f32.div" (f32.const -0x1.0f41d6p-42) (f32.const -0x1.3f2dbep+56)) (f32.const 0x1.b320d8p-99))
+(assert_return (invoke "f64.div" (f64.const 0x1.b2348a1c81899p+61) (f64.const -0x1.4a58aad903dd3p-861)) (f64.const -0x1.507c1e2a41b35p+922))
+(assert_return (invoke "f64.div" (f64.const 0x1.23fa5137a918ap-130) (f64.const -0x1.7268db1951263p-521)) (f64.const -0x1.93965e0d896bep+390))
+(assert_return (invoke "f64.div" (f64.const 0x1.dcb3915d82deep+669) (f64.const 0x1.50caaa1dc6b19p+638)) (f64.const 0x1.6a58ec814b09dp+31))
+(assert_return (invoke "f64.div" (f64.const -0x1.046e378c0cc46p+182) (f64.const 0x1.ac925009a922bp+773)) (f64.const -0x1.3720aa94dab18p-592))
+(assert_return (invoke "f64.div" (f64.const -0x1.8945fd69d8e11p-871) (f64.const -0x1.0a37870af809ap-646)) (f64.const 0x1.7a2e286c62382p-225))
+
+;; Computations that round differently when computed via f32.
+(assert_return (invoke "f64.div" (f64.const 0x1.82002af0ea1f3p-57) (f64.const 0x1.d0a9b0c2fa339p+0)) (f64.const 0x1.a952fbd1fc17cp-58))
+(assert_return (invoke "f64.div" (f64.const 0x1.1e12b515db471p-102) (f64.const -0x1.41fc3c94fba5p-42)) (f64.const -0x1.c6e50cccb7cb6p-61))
+(assert_return (invoke "f64.div" (f64.const 0x1.aba5adcd6f583p-41) (f64.const 0x1.17dfac639ce0fp-112)) (f64.const 0x1.872b0a008c326p+71))
+(assert_return (invoke "f64.div" (f64.const 0x1.cf82510d0ae6bp+89) (f64.const 0x1.0207d86498053p+97)) (f64.const 0x1.cbdc804e2cf14p-8))
+(assert_return (invoke "f64.div" (f64.const 0x1.4c82cbb508e21p-11) (f64.const -0x1.6b57208c2d5d5p+52)) (f64.const -0x1.d48e8b369129ap-64))
+
+;; Division involving the maximum subnormal value and the minimum normal value.
+(assert_return (invoke "f32.div" (f32.const 0x1p-126) (f32.const 0x1.fffffcp-127)) (f32.const 0x1.000002p+0))
+(assert_return (invoke "f32.div" (f32.const 0x1.fffffcp-127) (f32.const 0x1p-126)) (f32.const 0x1.fffffcp-1))
+(assert_return (invoke "f64.div" (f64.const 0x1p-1022) (f64.const 0x0.fffffffffffffp-1022)) (f64.const 0x1.0000000000001p+0))
+(assert_return (invoke "f64.div" (f64.const 0x0.fffffffffffffp-1022) (f64.const 0x1p-1022)) (f64.const 0x1.ffffffffffffep-1))
+
+;; Test the least positive value with a positive quotient with the maximum value.
+(assert_return (invoke "f32.div" (f32.const 0x1.fffffep-23) (f32.const 0x1.fffffep+127)) (f32.const 0x0p+0))
+(assert_return (invoke "f32.div" (f32.const 0x1p-22) (f32.const 0x1.fffffep+127)) (f32.const 0x1p-149))
+(assert_return (invoke "f64.div" (f64.const 0x1.fffffffffffffp-52) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0p+0))
+(assert_return (invoke "f64.div" (f64.const 0x1p-51) (f64.const 0x1.fffffffffffffp+1023)) (f64.const 0x0.0000000000001p-1022))
+
+;; Test the least positive value with a finite reciprocal.
+(assert_return (invoke "f32.div" (f32.const 1.0) (f32.const 0x1p-128)) (f32.const inf))
+(assert_return (invoke "f32.div" (f32.const 1.0) (f32.const 0x1.000008p-128)) (f32.const 0x1.fffffp+127))
+(assert_return (invoke "f64.div" (f64.const 1.0) (f64.const 0x0.4p-1022)) (f64.const inf))
+(assert_return (invoke "f64.div" (f64.const 1.0) (f64.const 0x0.4000000000001p-1022)) (f64.const 0x1.ffffffffffff8p+1023))
+
+;; Test the least positive value that has a subnormal reciprocal.
+(assert_return (invoke "f32.div" (f32.const 1.0) (f32.const 0x1.000002p+126)) (f32.const 0x1.fffffcp-127))
+(assert_return (invoke "f32.div" (f32.const 1.0) (f32.const 0x1p+126)) (f32.const 0x1p-126))
+(assert_return (invoke "f64.div" (f64.const 1.0) (f64.const 0x1.0000000000001p+1022)) (f64.const 0x0.fffffffffffffp-1022))
+(assert_return (invoke "f64.div" (f64.const 1.0) (f64.const 0x1p+1022)) (f64.const 0x1p-1022))
+
+;; Test that the last binary digit of 1.0/3.0 is even in f32,
+;; https://en.wikipedia.org/wiki/Single-precision_floating-point_format#Single-precision_examples
+;;
+;; and odd in f64,
+;; https://en.wikipedia.org/wiki/Double-precision_floating-point_format#Double-precision_examples
+;;
+;; and that 1.0/3.0, 3.0/9.0, and 9.0/27.0 all agree.
+;; http://www.netlib.org/paranoia
+(assert_return (invoke "f32.div" (f32.const 0x1p+0) (f32.const 0x1.8p+1)) (f32.const 0x1.555556p-2))
+(assert_return (invoke "f32.div" (f32.const 0x3p+0) (f32.const 0x1.2p+3)) (f32.const 0x1.555556p-2))
+(assert_return (invoke "f32.div" (f32.const 0x1.2p+3) (f32.const 0x1.bp+4)) (f32.const 0x1.555556p-2))
+(assert_return (invoke "f64.div" (f64.const 0x1p+0) (f64.const 0x1.8p+1)) (f64.const 0x1.5555555555555p-2))
+(assert_return (invoke "f64.div" (f64.const 0x3p+0) (f64.const 0x1.2p+3)) (f64.const 0x1.5555555555555p-2))
+(assert_return (invoke "f64.div" (f64.const 0x1.2p+3) (f64.const 0x1.bp+4)) (f64.const 0x1.5555555555555p-2))
+
+;; Test division of numbers very close to 1.
+(assert_return (invoke "f32.div" (f32.const 0x1.000002p+0) (f32.const 0x1.fffffep-1)) (f32.const 0x1.000004p+0))
+(assert_return (invoke "f32.div" (f32.const 0x1.fffffep-1) (f32.const 0x1.000002p+0)) (f32.const 0x1.fffffap-1))
+(assert_return (invoke "f32.div" (f32.const 0x1.0p+0) (f32.const 0x1.fffffep-1)) (f32.const 0x1.000002p+0))
+(assert_return (invoke "f32.div" (f32.const 0x1.0p+0) (f32.const 0x1.000002p+0)) (f32.const 0x1.fffffcp-1))
+(assert_return (invoke "f64.div" (f64.const 0x1.0000000000001p+0) (f64.const 0x1.fffffffffffffp-1)) (f64.const 0x1.0000000000002p+0))
+(assert_return (invoke "f64.div" (f64.const 0x1.fffffffffffffp-1) (f64.const 0x1.0000000000001p+0)) (f64.const 0x1.ffffffffffffdp-1))
+(assert_return (invoke "f64.div" (f64.const 0x1.0p+0) (f64.const 0x1.fffffffffffffp-1)) (f64.const 0x1.0000000000001p+0))
+(assert_return (invoke "f64.div" (f64.const 0x1.0p+0) (f64.const 0x1.0000000000001p+0)) (f64.const 0x1.ffffffffffffep-1))
+
+;; Test for bugs found in an early RISC-V implementation.
+;; https://github.com/riscv/riscv-tests/pull/8
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.56p+7)) (f32.const 0x1.a2744cp+3))
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.594dfcp-23)) (f32.const 0x1.a4789cp-12))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.56p+7)) (f64.const 0x1.a2744ce9674f5p+3))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.594dfc70aa105p-23)) (f64.const 0x1.a4789c0e37f99p-12))
+
+;; Computations that round differently on x87.
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.0263fcc94f259p-164)) (f64.const 0x1.0131485de579fp-82))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.352dfa278c43dp+338)) (f64.const 0x1.195607dac5417p+169))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.b15daa23924fap+402)) (f64.const 0x1.4d143db561493p+201))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.518c8e68cb753p-37)) (f64.const 0x1.9fb8ef1ad5bfdp-19))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.86d8b6518078ep-370)) (f64.const 0x1.3c5142a48fcadp-185))
+
+;; Test another sqrt case on x87.
+;; https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52593
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.fffffffffffffp-1)) (f64.const 0x1.fffffffffffffp-1))
+
+;; Computations that round differently in round-upward mode.
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.098064p-3)) (f32.const 0x1.70b23p-2))
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.d9befp+100)) (f32.const 0x1.5c4052p+50))
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.42b5b6p-4)) (f32.const 0x1.1f6d0ep-2))
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.3684dp-71)) (f32.const 0x1.8ebae2p-36))
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.d8bc4ep-11)) (f32.const 0x1.ebf9eap-6))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.5c39f220d5704p-924)) (f64.const 0x1.2a92bc24ceae9p-462))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.53521a635745cp+727)) (f64.const 0x1.a0cfdc4ef8ff1p+363))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.dfd5bbc9f4678p+385)) (f64.const 0x1.efa817117c94cp+192))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.33f9640811cd4p+105)) (f64.const 0x1.8d17c9243baa3p+52))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.6c0ef0267ff45p+999)) (f64.const 0x1.afbcfae3f2b4p+499))
+
+;; Computations that round differently in round-downward mode.
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.26a62ep+27)) (f32.const 0x1.84685p+13))
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.166002p-113)) (f32.const 0x1.798762p-57))
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.3dfb5p-15)) (f32.const 0x1.937e38p-8))
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.30eb2cp-120)) (f32.const 0x1.176406p-60))
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.cb705cp-123)) (f32.const 0x1.e5020ap-62))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.edae8aea0543p+695)) (f64.const 0x1.f6c1ea4fc8dd2p+347))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.f7ee4bda5c9c3p-763)) (f64.const 0x1.fbf30bdaf11c5p-382))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.a48f348266ad1p-30)) (f64.const 0x1.481ee7540baf7p-15))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.feb5a1ce3ed9cp-242)) (f64.const 0x1.6995060c20d46p-121))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.957d9796e3834p+930)) (f64.const 0x1.42305213157bap+465))
+
+;; Computations that round differently in round-toward-zero mode.
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.65787cp+118)) (f32.const 0x1.2e82a4p+59))
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.736044p+15)) (f32.const 0x1.b40e4p+7))
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.a00edp-1)) (f32.const 0x1.cd8aecp-1))
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.7a4c8p-87)) (f32.const 0x1.b819e4p-44))
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.5d24d4p-94)) (f32.const 0x1.2af75ep-47))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.a008948ead274p+738)) (f64.const 0x1.4659b37c39b19p+369))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.70f6199ed21f5p-381)) (f64.const 0x1.b2a2bddf3300dp-191))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.35c1d49f2a352p+965)) (f64.const 0x1.8e3d9f01a9716p+482))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.3fbdcfb2b2a15p-45)) (f64.const 0x1.949ba4feca42ap-23))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.c201b94757145p-492)) (f64.const 0x1.5369ee6bf2967p-246))
+
+;; Computations that round differently when computed via f32.
+(assert_return_canonical_nan (invoke "f64.sqrt" (f64.const -0x1.360e8d0032adp-963)))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.d9a6f5eef0503p+103)) (f64.const 0x1.ec73f56c166f6p+51))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.aa051a5c4ec27p-760)) (f64.const 0x1.4a3e771ff5149p-380))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.e5522a741babep-276)) (f64.const 0x1.607ae2b6feb7dp-138))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.4832badc0c061p+567)) (f64.const 0x1.99ec7934139b2p+283))
+
+;; Test the least value with a sqrt that rounds to one.
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.000002p+0)) (f32.const 0x1p+0))
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.000004p+0)) (f32.const 0x1.000002p+0))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.0000000000001p+0)) (f64.const 0x1p+0))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.0000000000002p+0)) (f64.const 0x1.0000000000001p+0))
+
+;; Test the greatest value less than one for which sqrt is not an identity.
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.fffffcp-1)) (f32.const 0x1.fffffep-1))
+(assert_return (invoke "f32.sqrt" (f32.const 0x1.fffffap-1)) (f32.const 0x1.fffffcp-1))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.ffffffffffffep-1)) (f64.const 0x1.fffffffffffffp-1))
+(assert_return (invoke "f64.sqrt" (f64.const 0x1.ffffffffffffdp-1)) (f64.const 0x1.ffffffffffffep-1))
+
+;; Test that the bitwise floating point operators are bitwise on NaN.
+
+(assert_return (invoke "f32.abs" (f32.const nan:0x0f1e2)) (f32.const nan:0x0f1e2))
+(assert_return (invoke "f32.abs" (f32.const -nan:0x0f1e2)) (f32.const nan:0x0f1e2))
+(assert_return (invoke "f64.abs" (f64.const nan:0x0f1e27a6b)) (f64.const nan:0x0f1e27a6b))
+(assert_return (invoke "f64.abs" (f64.const -nan:0x0f1e27a6b)) (f64.const nan:0x0f1e27a6b))
+
+(assert_return (invoke "f32.neg" (f32.const nan:0x0f1e2)) (f32.const -nan:0x0f1e2))
+(assert_return (invoke "f32.neg" (f32.const -nan:0x0f1e2)) (f32.const nan:0x0f1e2))
+(assert_return (invoke "f64.neg" (f64.const nan:0x0f1e27a6b)) (f64.const -nan:0x0f1e27a6b))
+(assert_return (invoke "f64.neg" (f64.const -nan:0x0f1e27a6b)) (f64.const nan:0x0f1e27a6b))
+
+(assert_return (invoke "f32.copysign" (f32.const nan:0x0f1e2) (f32.const nan)) (f32.const nan:0x0f1e2))
+(assert_return (invoke "f32.copysign" (f32.const nan:0x0f1e2) (f32.const -nan)) (f32.const -nan:0x0f1e2))
+(assert_return (invoke "f32.copysign" (f32.const -nan:0x0f1e2) (f32.const nan)) (f32.const nan:0x0f1e2))
+(assert_return (invoke "f32.copysign" (f32.const -nan:0x0f1e2) (f32.const -nan)) (f32.const -nan:0x0f1e2))
+(assert_return (invoke "f64.copysign" (f64.const nan:0x0f1e27a6b) (f64.const nan)) (f64.const nan:0x0f1e27a6b))
+(assert_return (invoke "f64.copysign" (f64.const nan:0x0f1e27a6b) (f64.const -nan)) (f64.const -nan:0x0f1e27a6b))
+(assert_return (invoke "f64.copysign" (f64.const -nan:0x0f1e27a6b) (f64.const nan)) (f64.const nan:0x0f1e27a6b))
+(assert_return (invoke "f64.copysign" (f64.const -nan:0x0f1e27a6b) (f64.const -nan)) (f64.const -nan:0x0f1e27a6b))
+
+;; Test values close to 1.0.
+(assert_return (invoke "f32.ceil" (f32.const 0x1.fffffep-1)) (f32.const 1.0))
+(assert_return (invoke "f32.ceil" (f32.const 0x1.000002p+0)) (f32.const 2.0))
+(assert_return (invoke "f64.ceil" (f64.const 0x1.fffffffffffffp-1)) (f64.const 1.0))
+(assert_return (invoke "f64.ceil" (f64.const 0x1.0000000000001p+0)) (f64.const 2.0))
+
+;; Test the maximum and minimum value for which ceil is not an identity operator.
+(assert_return (invoke "f32.ceil" (f32.const 0x1.fffffep+22)) (f32.const 0x1p+23))
+(assert_return (invoke "f32.ceil" (f32.const -0x1.fffffep+22)) (f32.const -0x1.fffffcp+22))
+(assert_return (invoke "f64.ceil" (f64.const 0x1.fffffffffffffp+51)) (f64.const 0x1p+52))
+(assert_return (invoke "f64.ceil" (f64.const -0x1.fffffffffffffp+51)) (f64.const -0x1.ffffffffffffep+51))
+
+;; Test that implementations don't do the x+0x1p52-0x1p52 trick outside the
+;; range where it's safe.
+(assert_return (invoke "f32.ceil" (f32.const 0x1.fffffep+23)) (f32.const 0x1.fffffep+23))
+(assert_return (invoke "f32.ceil" (f32.const -0x1.fffffep+23)) (f32.const -0x1.fffffep+23))
+(assert_return (invoke "f64.ceil" (f64.const 0x1.fffffffffffffp+52)) (f64.const 0x1.fffffffffffffp+52))
+(assert_return (invoke "f64.ceil" (f64.const -0x1.fffffffffffffp+52)) (f64.const -0x1.fffffffffffffp+52))
+
+;; Test values close to -1.0.
+(assert_return (invoke "f32.floor" (f32.const -0x1.fffffep-1)) (f32.const -1.0))
+(assert_return (invoke "f32.floor" (f32.const -0x1.000002p+0)) (f32.const -2.0))
+(assert_return (invoke "f64.floor" (f64.const -0x1.fffffffffffffp-1)) (f64.const -1.0))
+(assert_return (invoke "f64.floor" (f64.const -0x1.0000000000001p+0)) (f64.const -2.0))
+
+;; Test the maximum and minimum value for which floor is not an identity operator.
+(assert_return (invoke "f32.floor" (f32.const -0x1.fffffep+22)) (f32.const -0x1p+23))
+(assert_return (invoke "f32.floor" (f32.const 0x1.fffffep+22)) (f32.const 0x1.fffffcp+22))
+(assert_return (invoke "f64.floor" (f64.const -0x1.fffffffffffffp+51)) (f64.const -0x1p+52))
+(assert_return (invoke "f64.floor" (f64.const 0x1.fffffffffffffp+51)) (f64.const 0x1.ffffffffffffep+51))
+
+;; Test that floor isn't implemented as XMVectorFloor.
+;; http://dss.stephanierct.com/DevBlog/?p=8#comment-4
+(assert_return (invoke "f32.floor" (f32.const 88607.0)) (f32.const 88607.0))
+(assert_return (invoke "f64.floor" (f64.const 88607.0)) (f64.const 88607.0))
+
+;; Test the maximum and minimum value for which trunc is not an identity operator.
+(assert_return (invoke "f32.trunc" (f32.const -0x1.fffffep+22)) (f32.const -0x1.fffffcp+22))
+(assert_return (invoke "f32.trunc" (f32.const 0x1.fffffep+22)) (f32.const 0x1.fffffcp+22))
+(assert_return (invoke "f64.trunc" (f64.const -0x1.fffffffffffffp+51)) (f64.const -0x1.ffffffffffffep+51))
+(assert_return (invoke "f64.trunc" (f64.const 0x1.fffffffffffffp+51)) (f64.const 0x1.ffffffffffffep+51))
+
+;; Test that nearest isn't implemented naively.
+;; http://blog.frama-c.com/index.php?post/2013/05/02/nearbyintf1
+;; http://blog.frama-c.com/index.php?post/2013/05/04/nearbyintf3
+(assert_return (invoke "f32.nearest" (f32.const 0x1.000002p+23)) (f32.const 0x1.000002p+23))
+(assert_return (invoke "f32.nearest" (f32.const 0x1.000004p+23)) (f32.const 0x1.000004p+23))
+(assert_return (invoke "f32.nearest" (f32.const 0x1.fffffep-2)) (f32.const 0.0))
+(assert_return (invoke "f32.nearest" (f32.const 0x1.fffffep+47)) (f32.const 0x1.fffffep+47))
+(assert_return (invoke "f64.nearest" (f64.const 0x1.0000000000001p+52)) (f64.const 0x1.0000000000001p+52))
+(assert_return (invoke "f64.nearest" (f64.const 0x1.0000000000002p+52)) (f64.const 0x1.0000000000002p+52))
+(assert_return (invoke "f64.nearest" (f64.const 0x1.fffffffffffffp-2)) (f64.const 0.0))
+(assert_return (invoke "f64.nearest" (f64.const 0x1.fffffffffffffp+105)) (f64.const 0x1.fffffffffffffp+105))
+
+;; Nearest should not round halfway cases away from zero (as C's round(3) does)
+;; or up (as JS's Math.round does).
+(assert_return (invoke "f32.nearest" (f32.const 4.5)) (f32.const 4.0))
+(assert_return (invoke "f32.nearest" (f32.const -4.5)) (f32.const -4.0))
+(assert_return (invoke "f32.nearest" (f32.const -3.5)) (f32.const -4.0))
+(assert_return (invoke "f64.nearest" (f64.const 4.5)) (f64.const 4.0))
+(assert_return (invoke "f64.nearest" (f64.const -4.5)) (f64.const -4.0))
+(assert_return (invoke "f64.nearest" (f64.const -3.5)) (f64.const -4.0))
+
+;; Test the maximum and minimum value for which nearest is not an identity operator.
+(assert_return (invoke "f32.nearest" (f32.const -0x1.fffffep+22)) (f32.const -0x1p+23))
+(assert_return (invoke "f32.nearest" (f32.const 0x1.fffffep+22)) (f32.const 0x1p+23))
+(assert_return (invoke "f64.nearest" (f64.const -0x1.fffffffffffffp+51)) (f64.const -0x1p+52))
+(assert_return (invoke "f64.nearest" (f64.const 0x1.fffffffffffffp+51)) (f64.const 0x1p+52))
diff --git a/binaryen/test/spec/forward.wast b/binaryen/test/spec/forward.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/forward.wast
@@ -0,0 +1,20 @@
+(module
+  (func $even (export "even") (param $n i32) (result i32)
+    (if (result i32) (i32.eq (local.get $n) (i32.const 0))
+      (then (i32.const 1))
+      (else (call $odd (i32.sub (local.get $n) (i32.const 1))))
+    )
+  )
+
+  (func $odd (export "odd") (param $n i32) (result i32)
+    (if (result i32) (i32.eq (local.get $n) (i32.const 0))
+      (then (i32.const 0))
+      (else (call $even (i32.sub (local.get $n) (i32.const 1))))
+    )
+  )
+)
+
+(assert_return (invoke "even" (i32.const 13)) (i32.const 0))
+(assert_return (invoke "even" (i32.const 20)) (i32.const 1))
+(assert_return (invoke "odd" (i32.const 13)) (i32.const 1))
+(assert_return (invoke "odd" (i32.const 20)) (i32.const 0))
diff --git a/binaryen/test/spec/func-local-after-body.fail.wast b/binaryen/test/spec/func-local-after-body.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/func-local-after-body.fail.wast
@@ -0,0 +1,1 @@
+(module (func (nop) (local i32)))
diff --git a/binaryen/test/spec/func-local-before-param.fail.wast b/binaryen/test/spec/func-local-before-param.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/func-local-before-param.fail.wast
@@ -0,0 +1,1 @@
+(module (func (local i32) (param i32)))
diff --git a/binaryen/test/spec/func-local-before-result.fail.wast b/binaryen/test/spec/func-local-before-result.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/func-local-before-result.fail.wast
@@ -0,0 +1,1 @@
+(module (func (local i32) (result i32) (local.get 0)))
diff --git a/binaryen/test/spec/func-param-after-body.fail.wast b/binaryen/test/spec/func-param-after-body.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/func-param-after-body.fail.wast
@@ -0,0 +1,1 @@
+(module (func (nop) (param i32)))
diff --git a/binaryen/test/spec/func-result-after-body.fail.wast b/binaryen/test/spec/func-result-after-body.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/func-result-after-body.fail.wast
@@ -0,0 +1,1 @@
+(module (func (nop) (result i32)))
diff --git a/binaryen/test/spec/func-result-before-param.fail.wast b/binaryen/test/spec/func-result-before-param.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/func-result-before-param.fail.wast
@@ -0,0 +1,1 @@
+(module (func (result i32) (param i32) (local.get 0)))
diff --git a/binaryen/test/spec/func.wast b/binaryen/test/spec/func.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/func.wast
@@ -0,0 +1,661 @@
+;; Test `func` declarations, i.e. functions
+
+(module
+  ;; Auxiliary definition
+  (type $sig (func))
+  (func $dummy)
+
+  ;; Syntax
+
+  (func)
+  (func (export "f"))
+  (func $f)
+  (func $h (export "g"))
+
+  (func (local))
+  (func (local) (local))
+  (func (local i32))
+  (func (local $x i32))
+  (func (local i32 f64 i64))
+  (func (local i32) (local f64))
+  (func (local i32 f32) (local $x i64) (local) (local i32 f64))
+
+  (func (param))
+  (func (param) (param))
+  (func (param i32))
+  (func (param $x i32))
+  (func (param i32 f64 i64))
+  (func (param i32) (param f64))
+  (func (param i32 f32) (param $x i64) (param) (param i32 f64))
+
+  (func (result i32) (unreachable))
+
+  (type $sig-1 (func))
+  (type $sig-2 (func (result i32)))
+  (type $sig-3 (func (param $x i32)))
+  (type $sig-4 (func (param i32 f64 i32) (result i32)))
+
+  (func (export "type-use-1") (type $sig-1))
+  (func (export "type-use-2") (type $sig-2) (i32.const 0))
+  (func (export "type-use-3") (type $sig-3))
+  (func (export "type-use-4") (type $sig-4) (i32.const 0))
+  (func (export "type-use-5") (type $sig-2) (result i32) (i32.const 0))
+  (func (export "type-use-6") (type $sig-3) (param i32))
+  (func (export "type-use-7")
+    (type $sig-4) (param i32) (param f64 i32) (result i32) (i32.const 0)
+  )
+
+  (func (type $sig))
+  (func (type $forward))  ;; forward reference
+
+  (func $complex
+    (param i32 f32) (param $x i64) (param) (param i32)
+    (result) (result i32) (result)
+    (local f32) (local $y i32) (local i64 i32) (local) (local f64 i32)
+    (unreachable) (unreachable)
+  )
+  (func $complex-sig
+    (type $sig)
+    (local f32) (local $y i32) (local i64 i32) (local) (local f64 i32)
+    (unreachable) (unreachable)
+  )
+
+  (type $forward (func))
+
+  ;; Typing of locals
+
+  (func (export "local-first-i32") (result i32) (local i32 i32) (local.get 0))
+  (func (export "local-first-i64") (result i64) (local i64 i64) (local.get 0))
+  (func (export "local-first-f32") (result f32) (local f32 f32) (local.get 0))
+  (func (export "local-first-f64") (result f64) (local f64 f64) (local.get 0))
+  (func (export "local-second-i32") (result i32) (local i32 i32) (local.get 1))
+  (func (export "local-second-i64") (result i64) (local i64 i64) (local.get 1))
+  (func (export "local-second-f32") (result f32) (local f32 f32) (local.get 1))
+  (func (export "local-second-f64") (result f64) (local f64 f64) (local.get 1))
+  (func (export "local-mixed") (result f64)
+    (local f32) (local $x i32) (local i64 i32) (local) (local f64 i32)
+    (drop (f32.neg (local.get 0)))
+    (drop (i32.eqz (local.get 1)))
+    (drop (i64.eqz (local.get 2)))
+    (drop (i32.eqz (local.get 3)))
+    (drop (f64.neg (local.get 4)))
+    (drop (i32.eqz (local.get 5)))
+    (local.get 4)
+  )
+
+  ;; Typing of parameters
+
+  (func (export "param-first-i32") (param i32 i32) (result i32) (local.get 0))
+  (func (export "param-first-i64") (param i64 i64) (result i64) (local.get 0))
+  (func (export "param-first-f32") (param f32 f32) (result f32) (local.get 0))
+  (func (export "param-first-f64") (param f64 f64) (result f64) (local.get 0))
+  (func (export "param-second-i32") (param i32 i32) (result i32) (local.get 1))
+  (func (export "param-second-i64") (param i64 i64) (result i64) (local.get 1))
+  (func (export "param-second-f32") (param f32 f32) (result f32) (local.get 1))
+  (func (export "param-second-f64") (param f64 f64) (result f64) (local.get 1))
+  (func (export "param-mixed") (param f32 i32) (param) (param $x i64) (param i32 f64 i32)
+    (result f64)
+    (drop (f32.neg (local.get 0)))
+    (drop (i32.eqz (local.get 1)))
+    (drop (i64.eqz (local.get 2)))
+    (drop (i32.eqz (local.get 3)))
+    (drop (f64.neg (local.get 4)))
+    (drop (i32.eqz (local.get 5)))
+    (local.get 4)
+  )
+
+  ;; Typing of result
+
+  (func (export "empty"))
+  (func (export "value-void") (call $dummy))
+  (func (export "value-i32") (result i32) (i32.const 77))
+  (func (export "value-i64") (result i64) (i64.const 7777))
+  (func (export "value-f32") (result f32) (f32.const 77.7))
+  (func (export "value-f64") (result f64) (f64.const 77.77))
+  (func (export "value-block-void") (block (call $dummy) (call $dummy)))
+  (func (export "value-block-i32") (result i32)
+    (block (result i32) (call $dummy) (i32.const 77))
+  )
+
+  (func (export "return-empty") (return))
+  (func (export "return-i32") (result i32) (return (i32.const 78)))
+  (func (export "return-i64") (result i64) (return (i64.const 7878)))
+  (func (export "return-f32") (result f32) (return (f32.const 78.7)))
+  (func (export "return-f64") (result f64) (return (f64.const 78.78)))
+  (func (export "return-block-i32") (result i32)
+    (return (block (result i32) (call $dummy) (i32.const 77)))
+  )
+
+  (func (export "break-empty") (br 0))
+  (func (export "break-i32") (result i32) (br 0 (i32.const 79)))
+  (func (export "break-i64") (result i64) (br 0 (i64.const 7979)))
+  (func (export "break-f32") (result f32) (br 0 (f32.const 79.9)))
+  (func (export "break-f64") (result f64) (br 0 (f64.const 79.79)))
+  (func (export "break-block-i32") (result i32)
+    (br 0 (block (result i32) (call $dummy) (i32.const 77)))
+  )
+
+  (func (export "break-br_if-empty") (param i32)
+    (br_if 0 (local.get 0))
+  )
+  (func (export "break-br_if-num") (param i32) (result i32)
+    (drop (br_if 0 (i32.const 50) (local.get 0))) (i32.const 51)
+  )
+
+  (func (export "break-br_table-empty") (param i32)
+    (br_table 0 0 0 (local.get 0))
+  )
+  (func (export "break-br_table-num") (param i32) (result i32)
+    (br_table 0 0 (i32.const 50) (local.get 0)) (i32.const 51)
+  )
+  (func (export "break-br_table-nested-empty") (param i32)
+    (block (br_table 0 1 0 (local.get 0)))
+  )
+  (func (export "break-br_table-nested-num") (param i32) (result i32)
+    (i32.add
+      (block (result i32)
+        (br_table 0 1 0 (i32.const 50) (local.get 0)) (i32.const 51)
+      )
+      (i32.const 2)
+    )
+  )
+
+  ;; Default initialization of locals
+
+  (func (export "init-local-i32") (result i32) (local i32) (local.get 0))
+  (func (export "init-local-i64") (result i64) (local i64) (local.get 0))
+  (func (export "init-local-f32") (result f32) (local f32) (local.get 0))
+  (func (export "init-local-f64") (result f64) (local f64) (local.get 0))
+)
+
+(assert_return (invoke "type-use-1"))
+(assert_return (invoke "type-use-2") (i32.const 0))
+(assert_return (invoke "type-use-3" (i32.const 1)))
+(assert_return
+  (invoke "type-use-4" (i32.const 1) (f64.const 1) (i32.const 1))
+  (i32.const 0)
+)
+(assert_return (invoke "type-use-5") (i32.const 0))
+(assert_return (invoke "type-use-6" (i32.const 1)))
+(assert_return
+  (invoke "type-use-7" (i32.const 1) (f64.const 1) (i32.const 1))
+  (i32.const 0)
+)
+
+(assert_return (invoke "local-first-i32") (i32.const 0))
+(assert_return (invoke "local-first-i64") (i64.const 0))
+(assert_return (invoke "local-first-f32") (f32.const 0))
+(assert_return (invoke "local-first-f64") (f64.const 0))
+(assert_return (invoke "local-second-i32") (i32.const 0))
+(assert_return (invoke "local-second-i64") (i64.const 0))
+(assert_return (invoke "local-second-f32") (f32.const 0))
+(assert_return (invoke "local-second-f64") (f64.const 0))
+(assert_return (invoke "local-mixed") (f64.const 0))
+
+(assert_return
+  (invoke "param-first-i32" (i32.const 2) (i32.const 3)) (i32.const 2)
+)
+(assert_return
+  (invoke "param-first-i64" (i64.const 2) (i64.const 3)) (i64.const 2)
+)
+(assert_return
+  (invoke "param-first-f32" (f32.const 2) (f32.const 3)) (f32.const 2)
+)
+(assert_return
+  (invoke "param-first-f64" (f64.const 2) (f64.const 3)) (f64.const 2)
+)
+(assert_return
+  (invoke "param-second-i32" (i32.const 2) (i32.const 3)) (i32.const 3)
+)
+(assert_return
+  (invoke "param-second-i64" (i64.const 2) (i64.const 3)) (i64.const 3)
+)
+(assert_return
+  (invoke "param-second-f32" (f32.const 2) (f32.const 3)) (f32.const 3)
+)
+(assert_return
+  (invoke "param-second-f64" (f64.const 2) (f64.const 3)) (f64.const 3)
+)
+
+(assert_return
+  (invoke "param-mixed"
+    (f32.const 1) (i32.const 2) (i64.const 3)
+    (i32.const 4) (f64.const 5.5) (i32.const 6)
+  )
+  (f64.const 5.5)
+)
+
+(assert_return (invoke "empty"))
+(assert_return (invoke "value-void"))
+(assert_return (invoke "value-i32") (i32.const 77))
+(assert_return (invoke "value-i64") (i64.const 7777))
+(assert_return (invoke "value-f32") (f32.const 77.7))
+(assert_return (invoke "value-f64") (f64.const 77.77))
+(assert_return (invoke "value-block-void"))
+(assert_return (invoke "value-block-i32") (i32.const 77))
+
+(assert_return (invoke "return-empty"))
+(assert_return (invoke "return-i32") (i32.const 78))
+(assert_return (invoke "return-i64") (i64.const 7878))
+(assert_return (invoke "return-f32") (f32.const 78.7))
+(assert_return (invoke "return-f64") (f64.const 78.78))
+(assert_return (invoke "return-block-i32") (i32.const 77))
+
+(assert_return (invoke "break-empty"))
+(assert_return (invoke "break-i32") (i32.const 79))
+(assert_return (invoke "break-i64") (i64.const 7979))
+(assert_return (invoke "break-f32") (f32.const 79.9))
+(assert_return (invoke "break-f64") (f64.const 79.79))
+(assert_return (invoke "break-block-i32") (i32.const 77))
+
+(assert_return (invoke "break-br_if-empty" (i32.const 0)))
+(assert_return (invoke "break-br_if-empty" (i32.const 2)))
+(assert_return (invoke "break-br_if-num" (i32.const 0)) (i32.const 51))
+(assert_return (invoke "break-br_if-num" (i32.const 1)) (i32.const 50))
+
+(assert_return (invoke "break-br_table-empty" (i32.const 0)))
+(assert_return (invoke "break-br_table-empty" (i32.const 1)))
+(assert_return (invoke "break-br_table-empty" (i32.const 5)))
+(assert_return (invoke "break-br_table-empty" (i32.const -1)))
+(assert_return (invoke "break-br_table-num" (i32.const 0)) (i32.const 50))
+(assert_return (invoke "break-br_table-num" (i32.const 1)) (i32.const 50))
+(assert_return (invoke "break-br_table-num" (i32.const 10)) (i32.const 50))
+(assert_return (invoke "break-br_table-num" (i32.const -100)) (i32.const 50))
+(assert_return (invoke "break-br_table-nested-empty" (i32.const 0)))
+(assert_return (invoke "break-br_table-nested-empty" (i32.const 1)))
+(assert_return (invoke "break-br_table-nested-empty" (i32.const 3)))
+(assert_return (invoke "break-br_table-nested-empty" (i32.const -2)))
+(assert_return
+  (invoke "break-br_table-nested-num" (i32.const 0)) (i32.const 52)
+)
+(assert_return
+  (invoke "break-br_table-nested-num" (i32.const 1)) (i32.const 50)
+)
+(assert_return
+  (invoke "break-br_table-nested-num" (i32.const 2)) (i32.const 52)
+)
+(assert_return
+  (invoke "break-br_table-nested-num" (i32.const -3)) (i32.const 52)
+)
+
+(assert_return (invoke "init-local-i32") (i32.const 0))
+(assert_return (invoke "init-local-i64") (i64.const 0))
+(assert_return (invoke "init-local-f32") (f32.const 0))
+(assert_return (invoke "init-local-f64") (f64.const 0))
+
+
+;; Expansion of inline function types
+
+(module
+  (func $f (result f64) (f64.const 0))  ;; adds implicit type definition
+  (func $g (param i32))                 ;; reuses explicit type definition
+  (type $t (func (param i32)))
+
+  (func $i32->void (type 0))                ;; (param i32)
+  (func $void->f64 (type 1) (f64.const 0))  ;; (result f64)
+  (func $check
+    (call $i32->void (i32.const 0))
+    (drop (call $void->f64))
+  )
+)
+
+(assert_invalid
+  (module
+    (func $f (result f64) (f64.const 0))  ;; adds implicit type definition
+    (func $g (param i32))                 ;; reuses explicit type definition
+    (func $h (result f64) (f64.const 1))  ;; reuses implicit type definition
+    (type $t (func (param i32)))
+
+    (func (type 2))  ;; does not exist
+  )
+  "unknown type"
+)
+
+
+(module
+  (type $sig (func))
+
+  (func $empty-sig-1)  ;; should be assigned type $sig
+  (func $complex-sig-1 (param f64 i64 f64 i64 f64 i64 f32 i32))
+  (func $empty-sig-2)  ;; should be assigned type $sig
+  (func $complex-sig-2 (param f64 i64 f64 i64 f64 i64 f32 i32))
+  (func $complex-sig-3 (param f64 i64 f64 i64 f64 i64 f32 i32))
+  (func $complex-sig-4 (param i64 i64 f64 i64 f64 i64 f32 i32))
+  (func $complex-sig-5 (param i64 i64 f64 i64 f64 i64 f32 i32))
+
+  (type $empty-sig-duplicate (func))
+  (type $complex-sig-duplicate (func (param i64 i64 f64 i64 f64 i64 f32 i32)))
+  (table funcref
+    (elem
+      $complex-sig-3 $empty-sig-2 $complex-sig-1 $complex-sig-3 $empty-sig-1
+      $complex-sig-4 $complex-sig-5
+    )
+  )
+
+  (func (export "signature-explicit-reused")
+    (call_indirect (type $sig) (i32.const 1))
+    (call_indirect (type $sig) (i32.const 4))
+  )
+
+  (func (export "signature-implicit-reused")
+    ;; The implicit index 3 in this test depends on the function and
+    ;; type definitions, and may need adapting if they change.
+    (call_indirect (type 3)
+      (f64.const 0) (i64.const 0) (f64.const 0) (i64.const 0)
+      (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0)
+      (i32.const 0)
+    )
+    (call_indirect (type 3)
+      (f64.const 0) (i64.const 0) (f64.const 0) (i64.const 0)
+      (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0)
+      (i32.const 2)
+    )
+    (call_indirect (type 3)
+      (f64.const 0) (i64.const 0) (f64.const 0) (i64.const 0)
+      (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0)
+      (i32.const 3)
+    )
+  )
+
+  (func (export "signature-explicit-duplicate")
+    (call_indirect (type $empty-sig-duplicate) (i32.const 1))
+  )
+
+  (func (export "signature-implicit-duplicate")
+    (call_indirect (type $complex-sig-duplicate)
+      (i64.const 0) (i64.const 0) (f64.const 0) (i64.const 0)
+      (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0)
+      (i32.const 5)
+    )
+    (call_indirect (type $complex-sig-duplicate)
+      (i64.const 0) (i64.const 0) (f64.const 0) (i64.const 0)
+      (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0)
+      (i32.const 6)
+    )
+  )
+)
+
+(assert_return (invoke "signature-explicit-reused"))
+(assert_return (invoke "signature-implicit-reused"))
+(assert_return (invoke "signature-explicit-duplicate"))
+(assert_return (invoke "signature-implicit-duplicate"))
+
+
+;; Malformed type use
+
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32) (result i32)))"
+    "(func (type $sig) (result i32) (param i32) (i32.const 0))"
+  )
+  "unexpected token"
+)
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32) (result i32)))"
+    "(func (param i32) (type $sig) (result i32) (i32.const 0))"
+  )
+  "unexpected token"
+)
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32) (result i32)))"
+    "(func (param i32) (result i32) (type $sig) (i32.const 0))"
+  )
+  "unexpected token"
+)
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32) (result i32)))"
+    "(func (result i32) (type $sig) (param i32) (i32.const 0))"
+  )
+  "unexpected token"
+)
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32) (result i32)))"
+    "(func (result i32) (param i32) (type $sig) (i32.const 0))"
+  )
+  "unexpected token"
+)
+(assert_malformed
+  (module quote
+    "(func (result i32) (param i32) (i32.const 0))"
+  )
+  "unexpected token"
+)
+
+(assert_malformed
+  (module quote
+    "(type $sig (func))"
+    "(func (type $sig) (result i32) (i32.const 0))"
+  )
+  "inline function type"
+)
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32) (result i32)))"
+    "(func (type $sig) (result i32) (i32.const 0))"
+  )
+  "inline function type"
+)
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32) (result i32)))"
+    "(func (type $sig) (param i32) (i32.const 0))"
+  )
+  "inline function type"
+)
+(assert_malformed
+  (module quote
+    "(type $sig (func (param i32 i32) (result i32)))"
+    "(func (type $sig) (param i32) (result i32) (unreachable))"
+  )
+  "inline function type"
+)
+
+
+;; Invalid typing of locals
+
+(assert_invalid
+  (module (func $type-local-num-vs-num (result i64) (local i32) (local.get 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-num-vs-num (local f32) (i32.eqz (local.get 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-num-vs-num (local f64 i64) (f64.neg (local.get 1))))
+  "type mismatch"
+)
+
+
+;; Invalid typing of parameters
+
+(assert_invalid
+  (module (func $type-param-num-vs-num (param i32) (result i64) (local.get 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-num-vs-num (param f32) (i32.eqz (local.get 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-num-vs-num (param f64 i64) (f64.neg (local.get 1))))
+  "type mismatch"
+)
+
+
+;; Invalid typing of result
+
+(assert_invalid
+  (module (func $type-multiple-result (result i32 i32) (unreachable)))
+  "invalid result arity"
+)
+(assert_invalid
+  (module
+    (type (func (result i32 i32)))
+    (func $type-multiple-result (type 0) (unreachable))
+  )
+  "invalid result arity"
+)
+
+
+(assert_invalid
+  (module (func $type-empty-i32 (result i32)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-i64 (result i64)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f32 (result f32)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f64 (result f64)))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-value-void-vs-num (result i32)
+    (nop)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-num-vs-void
+    (i32.const 0)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-num-vs-num (result i32)
+    (f32.const 0)
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-return-last-empty-vs-num (result i32)
+    (return)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-return-last-void-vs-num (result i32)
+    (return (nop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-return-last-num-vs-num (result i32)
+    (return (i64.const 0))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-return-empty-vs-num (result i32)
+    (return) (i32.const 1)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-return-void-vs-num (result i32)
+    (return (nop)) (i32.const 1)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-return-num-vs-num (result i32)
+    (return (i64.const 1)) (i32.const 1)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-return-first-num-vs-num (result i32)
+    (return (i64.const 1)) (return (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-last-void-vs-num (result i32)
+    (br 0)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-last-num-vs-num (result i32)
+    (br 0 (f32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-void-vs-num (result i32)
+    (br 0) (i32.const 1)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-num-vs-num (result i32)
+    (br 0 (i64.const 1)) (i32.const 1)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-num-vs-num (result i32)
+    (br 0 (i64.const 1)) (br 0 (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-nested-empty-vs-num (result i32)
+    (block (br 1)) (br 0 (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-void-vs-num (result i32)
+    (block (br 1 (nop))) (br 0 (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-num-vs-num (result i32)
+    (block (br 1 (i64.const 1))) (br 0 (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+
+;; Syntax errors
+
+(assert_malformed
+  (module quote "(func (nop) (local i32))")
+  "unexpected token"
+)
+(assert_malformed
+  (module quote "(func (nop) (param i32))")
+  "unexpected token"
+)
+(assert_malformed
+  (module quote "(func (nop) (result i32))")
+  "unexpected token"
+)
+(assert_malformed
+  (module quote "(func (local i32) (param i32))")
+  "unexpected token"
+)
+(assert_malformed
+  (module quote "(func (local i32) (result i32) (local.get 0))")
+  "unexpected token"
+)
+(assert_malformed
+  (module quote "(func (result i32) (param i32) (local.get 0))")
+  "unexpected token"
+)
diff --git a/binaryen/test/spec/func_ptrs.wast b/binaryen/test/spec/func_ptrs.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/func_ptrs.wast
@@ -0,0 +1,106 @@
+(module
+  (type    (func))                           ;; 0: void -> void
+  (type $S (func))                           ;; 1: void -> void
+  (type    (func (param)))                   ;; 2: void -> void
+  (type    (func (result i32)))              ;; 3: void -> i32
+  (type    (func (param) (result i32)))      ;; 4: void -> i32
+  (type $T (func (param i32) (result i32)))  ;; 5: i32 -> i32
+  (type $U (func (param i32)))               ;; 6: i32 -> void
+
+  (func $print (import "spectest" "print_i32") (type 6))
+
+  (func (type 0))
+  (func (type $S))
+
+  (func (export "one") (type 4) (i32.const 13))
+  (func (export "two") (type $T) (i32.add (local.get 0) (i32.const 1)))
+
+  ;; Both signature and parameters are allowed (and required to match)
+  ;; since this allows the naming of parameters.
+  (func (export "three") (type $T) (param $a i32) (result i32)
+    (i32.sub (local.get 0) (i32.const 2))
+  )
+
+  (func (export "four") (type $U) (call $print (local.get 0)))
+)
+
+(assert_return (invoke "one") (i32.const 13))
+(assert_return (invoke "two" (i32.const 13)) (i32.const 14))
+(assert_return (invoke "three" (i32.const 13)) (i32.const 11))
+(invoke "four" (i32.const 83))
+
+(assert_invalid (module (elem (i32.const 0))) "unknown table")
+(assert_invalid (module (elem (i32.const 0) 0) (func)) "unknown table")
+
+(assert_invalid
+  (module (table 1 funcref) (elem (i64.const 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (table 1 funcref) (elem (i32.ctz (i32.const 0))))
+  "constant expression required"
+)
+(assert_invalid
+  (module (table 1 funcref) (elem (nop)))
+  "constant expression required"
+)
+
+(assert_invalid (module (func (type 42))) "unknown type")
+(assert_invalid (module (import "spectest" "print_i32" (func (type 43)))) "unknown type")
+
+(module
+  (type $T (func (param) (result i32)))
+  (type $U (func (param) (result i32)))
+  (table funcref (elem $t1 $t2 $t3 $u1 $u2 $t1 $t3))
+
+  (func $t1 (type $T) (i32.const 1))
+  (func $t2 (type $T) (i32.const 2))
+  (func $t3 (type $T) (i32.const 3))
+  (func $u1 (type $U) (i32.const 4))
+  (func $u2 (type $U) (i32.const 5))
+
+  (func (export "callt") (param $i i32) (result i32)
+    (call_indirect (type $T) (local.get $i))
+  )
+
+  (func (export "callu") (param $i i32) (result i32)
+    (call_indirect (type $U) (local.get $i))
+  )
+)
+
+(assert_return (invoke "callt" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "callt" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "callt" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "callt" (i32.const 3)) (i32.const 4))
+(assert_return (invoke "callt" (i32.const 4)) (i32.const 5))
+(assert_return (invoke "callt" (i32.const 5)) (i32.const 1))
+(assert_return (invoke "callt" (i32.const 6)) (i32.const 3))
+(assert_trap (invoke "callt" (i32.const 7)) "undefined element")
+(assert_trap (invoke "callt" (i32.const 100)) "undefined element")
+(assert_trap (invoke "callt" (i32.const -1)) "undefined element")
+
+(assert_return (invoke "callu" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "callu" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "callu" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "callu" (i32.const 3)) (i32.const 4))
+(assert_return (invoke "callu" (i32.const 4)) (i32.const 5))
+(assert_return (invoke "callu" (i32.const 5)) (i32.const 1))
+(assert_return (invoke "callu" (i32.const 6)) (i32.const 3))
+(assert_trap (invoke "callu" (i32.const 7)) "undefined element")
+(assert_trap (invoke "callu" (i32.const 100)) "undefined element")
+(assert_trap (invoke "callu" (i32.const -1)) "undefined element")
+
+(module
+  (type $T (func (result i32)))
+  (table funcref (elem 0 1))
+
+  (func $t1 (type $T) (i32.const 1))
+  (func $t2 (type $T) (i32.const 2))
+
+  (func (export "callt") (param $i i32) (result i32)
+    (call_indirect (type $T) (local.get $i))
+  )
+)
+
+(assert_return (invoke "callt" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "callt" (i32.const 1)) (i32.const 2))
diff --git a/binaryen/test/spec/get_local.wast b/binaryen/test/spec/get_local.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/get_local.wast
@@ -0,0 +1,148 @@
+;; Test `local.get` operator
+
+(module
+  ;; Typing
+
+  (func (export "type-local-i32") (result i32) (local i32) (local.get 0))
+  (func (export "type-local-i64") (result i64) (local i64) (local.get 0))
+  (func (export "type-local-f32") (result f32) (local f32) (local.get 0))
+  (func (export "type-local-f64") (result f64) (local f64) (local.get 0))
+
+  (func (export "type-param-i32") (param i32) (result i32) (local.get 0))
+  (func (export "type-param-i64") (param i64) (result i64) (local.get 0))
+  (func (export "type-param-f32") (param f32) (result f32) (local.get 0))
+  (func (export "type-param-f64") (param f64) (result f64) (local.get 0))
+
+  (func (export "type-mixed") (param i64 f32 f64 i32 i32)
+    (local f32 i64 i64 f64)
+    (drop (i64.eqz (local.get 0)))
+    (drop (f32.neg (local.get 1)))
+    (drop (f64.neg (local.get 2)))
+    (drop (i32.eqz (local.get 3)))
+    (drop (i32.eqz (local.get 4)))
+    (drop (f32.neg (local.get 5)))
+    (drop (i64.eqz (local.get 6)))
+    (drop (i64.eqz (local.get 7)))
+    (drop (f64.neg (local.get 8)))
+  )
+
+  ;; Reading
+
+  (func (export "read") (param i64 f32 f64 i32 i32) (result f64)
+    (local f32 i64 i64 f64)
+    (local.set 5 (f32.const 5.5))
+    (local.set 6 (i64.const 6))
+    (local.set 8 (f64.const 8))
+    (f64.add
+      (f64.convert_i64_u (local.get 0))
+      (f64.add
+        (f64.promote_f32 (local.get 1))
+        (f64.add
+          (local.get 2)
+          (f64.add
+            (f64.convert_i32_u (local.get 3))
+            (f64.add
+              (f64.convert_i32_s (local.get 4))
+              (f64.add
+                (f64.promote_f32 (local.get 5))
+                (f64.add
+                  (f64.convert_i64_u (local.get 6))
+                  (f64.add
+                    (f64.convert_i64_u (local.get 7))
+                    (local.get 8)
+                  )
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+)
+
+(assert_return (invoke "type-local-i32") (i32.const 0))
+(assert_return (invoke "type-local-i64") (i64.const 0))
+(assert_return (invoke "type-local-f32") (f32.const 0))
+(assert_return (invoke "type-local-f64") (f64.const 0))
+
+(assert_return (invoke "type-param-i32" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "type-param-i64" (i64.const 3)) (i64.const 3))
+(assert_return (invoke "type-param-f32" (f32.const 4.4)) (f32.const 4.4))
+(assert_return (invoke "type-param-f64" (f64.const 5.5)) (f64.const 5.5))
+
+(assert_return
+  (invoke "type-mixed"
+    (i64.const 1) (f32.const 2.2) (f64.const 3.3) (i32.const 4) (i32.const 5)
+  )
+)
+
+(assert_return
+  (invoke "read"
+    (i64.const 1) (f32.const 2) (f64.const 3.3) (i32.const 4) (i32.const 5)
+  )
+  (f64.const 34.8)
+)
+
+
+;; Invalid typing of access to locals
+
+(assert_invalid
+  (module (func $type-local-num-vs-num (result i64) (local i32) (local.get 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-num-vs-num (local f32) (i32.eqz (local.get 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-num-vs-num (local f64 i64) (f64.neg (local.get 1))))
+  "type mismatch"
+)
+
+
+;; Invalid typing of access to parameters
+
+(assert_invalid
+  (module (func $type-param-num-vs-num (param i32) (result i64) (local.get 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-num-vs-num (param f32) (i32.eqz (local.get 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-num-vs-num (param f64 i64) (f64.neg (local.get 1))))
+  "type mismatch"
+)
+
+
+;; Invalid local index
+
+(assert_invalid
+  (module (func $unbound-local (local i32 i64) (local.get 3)))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-local (local i32 i64) (local.get 14324343)))
+  "unknown local"
+)
+
+(assert_invalid
+  (module (func $unbound-param (param i32 i64) (local.get 2)))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-param (local i32 i64) (local.get 714324343)))
+  "unknown local"
+)
+
+(assert_invalid
+  (module (func $unbound-mixed (param i32) (local i32 i64) (local.get 3)))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-mixed (param i64) (local i32 i64) (local.get 214324343)))
+  "unknown local"
+)
+
diff --git a/binaryen/test/spec/globals.wast b/binaryen/test/spec/globals.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/globals.wast
@@ -0,0 +1,482 @@
+;; Test globals
+
+(module
+  (global $a i32 (i32.const -2))
+  (global (;1;) f32 (f32.const -3))
+  (global (;2;) f64 (f64.const -4))
+  (global $b i64 (i64.const -5))
+
+  (global $x (mut i32) (i32.const -12))
+  (global (;5;) (mut f32) (f32.const -13))
+  (global (;6;) (mut f64) (f64.const -14))
+  (global $y (mut i64) (i64.const -15))
+
+  (func (export "get-a") (result i32) (global.get $a))
+  (func (export "get-b") (result i64) (global.get $b))
+  (func (export "get-x") (result i32) (global.get $x))
+  (func (export "get-y") (result i64) (global.get $y))
+  (func (export "set-x") (param i32) (global.set $x (local.get 0)))
+  (func (export "set-y") (param i64) (global.set $y (local.get 0)))
+
+  (func (export "get-1") (result f32) (global.get 1))
+  (func (export "get-2") (result f64) (global.get 2))
+  (func (export "get-5") (result f32) (global.get 5))
+  (func (export "get-6") (result f64) (global.get 6))
+  (func (export "set-5") (param f32) (global.set 5 (local.get 0)))
+  (func (export "set-6") (param f64) (global.set 6 (local.get 0)))
+
+  ;; As the argument of control constructs and instructions
+
+  (memory 1)
+
+  (func $dummy)
+
+  (func (export "as-select-first") (result i32)
+    (select (global.get $x) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-select-mid") (result i32)
+    (select (i32.const 2) (global.get $x) (i32.const 3))
+  )
+  (func (export "as-select-last") (result i32)
+    (select (i32.const 2) (i32.const 3) (global.get $x))
+  )
+
+  (func (export "as-loop-first") (result i32)
+    (loop (result i32)
+      (global.get $x) (call $dummy) (call $dummy)
+    )
+  )
+  (func (export "as-loop-mid") (result i32)
+    (loop (result i32)
+      (call $dummy) (global.get $x) (call $dummy)
+    )
+  )
+  (func (export "as-loop-last") (result i32)
+    (loop (result i32)
+      (call $dummy) (call $dummy) (global.get $x)
+    )
+  )
+
+  (func (export "as-if-condition") (result i32)
+    (if (result i32) (global.get $x)
+      (then (call $dummy) (i32.const 2))
+      (else (call $dummy) (i32.const 3))
+    )
+  )
+  (func (export "as-if-then") (result i32)
+    (if (result i32) (i32.const 1)
+      (then (global.get $x)) (else (i32.const 2))
+    )
+  )
+  (func (export "as-if-else") (result i32)
+    (if (result i32) (i32.const 0)
+      (then (i32.const 2)) (else (global.get $x))
+    )
+  )
+
+  (func (export "as-br_if-first") (result i32)
+    (block (result i32)
+      (br_if 0 (global.get $x) (i32.const 2))
+      (return (i32.const 3))
+    )
+  )
+  (func (export "as-br_if-last") (result i32)
+    (block (result i32)
+      (br_if 0 (i32.const 2) (global.get $x))
+      (return (i32.const 3))
+    )
+  )
+
+  (func (export "as-br_table-first") (result i32)
+    (block (result i32)
+      (global.get $x) (i32.const 2) (br_table 0 0)
+    )
+  )
+  (func (export "as-br_table-last") (result i32)
+    (block (result i32)
+      (i32.const 2) (global.get $x) (br_table 0 0)
+    )
+  )
+
+  (func $func (param i32 i32) (result i32) (local.get 0))
+  (type $check (func (param i32 i32) (result i32)))
+  (table funcref (elem $func))
+  (func (export "as-call_indirect-first") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (global.get $x) (i32.const 2) (i32.const 0)
+      )
+    )
+  )
+  (func (export "as-call_indirect-mid") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (i32.const 2) (global.get $x) (i32.const 0)
+      )
+    )
+  )
+ (func (export "as-call_indirect-last") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (i32.const 2) (i32.const 0) (global.get $x)
+      )
+    )
+  )
+
+  (func (export "as-store-first")
+    (global.get $x) (i32.const 1) (i32.store)
+  )
+  (func (export "as-store-last")
+    (i32.const 0) (global.get $x) (i32.store)
+  )
+  (func (export "as-load-operand") (result i32)
+    (i32.load (global.get $x))
+  )
+  (func (export "as-memory.grow-value") (result i32)
+    (memory.grow (global.get $x))
+  )
+
+  (func $f (param i32) (result i32) (local.get 0))
+  (func (export "as-call-value") (result i32)
+    (call $f (global.get $x))
+  )
+
+  (func (export "as-return-value") (result i32)
+    (global.get $x) (return)
+  )
+  (func (export "as-drop-operand")
+    (drop (global.get $x))
+  )
+  (func (export "as-br-value") (result i32)
+    (block (result i32) (br 0 (global.get $x)))
+  )
+
+  (func (export "as-local.set-value") (param i32) (result i32)
+    (local.set 0 (global.get $x))
+    (local.get 0)
+  )
+  (func (export "as-local.tee-value") (param i32) (result i32)
+    (local.tee 0 (global.get $x))
+  )
+  (func (export "as-global.set-value") (result i32)
+    (global.set $x (global.get $x))
+    (global.get $x)
+  )
+
+  (func (export "as-unary-operand") (result i32)
+    (i32.eqz (global.get $x))
+  )
+  (func (export "as-binary-operand") (result i32)
+    (i32.mul
+      (global.get $x) (global.get $x)
+    )
+  )
+  (func (export "as-compare-operand") (result i32)
+    (i32.gt_u
+      (global.get 0) (i32.const 1)
+    )
+  )
+)
+
+(assert_return (invoke "get-a") (i32.const -2))
+(assert_return (invoke "get-b") (i64.const -5))
+(assert_return (invoke "get-x") (i32.const -12))
+(assert_return (invoke "get-y") (i64.const -15))
+
+(assert_return (invoke "get-1") (f32.const -3))
+(assert_return (invoke "get-2") (f64.const -4))
+(assert_return (invoke "get-5") (f32.const -13))
+(assert_return (invoke "get-6") (f64.const -14))
+
+(assert_return (invoke "set-x" (i32.const 6)))
+(assert_return (invoke "set-y" (i64.const 7)))
+(assert_return (invoke "set-5" (f32.const 8)))
+(assert_return (invoke "set-6" (f64.const 9)))
+
+(assert_return (invoke "get-x") (i32.const 6))
+(assert_return (invoke "get-y") (i64.const 7))
+(assert_return (invoke "get-5") (f32.const 8))
+(assert_return (invoke "get-6") (f64.const 9))
+
+(assert_return (invoke "as-select-first") (i32.const 6))
+(assert_return (invoke "as-select-mid") (i32.const 2))
+(assert_return (invoke "as-select-last") (i32.const 2))
+
+(assert_return (invoke "as-loop-first") (i32.const 6))
+(assert_return (invoke "as-loop-mid") (i32.const 6))
+(assert_return (invoke "as-loop-last") (i32.const 6))
+
+(assert_return (invoke "as-if-condition") (i32.const 2))
+(assert_return (invoke "as-if-then") (i32.const 6))
+(assert_return (invoke "as-if-else") (i32.const 6))
+
+(assert_return (invoke "as-br_if-first") (i32.const 6))
+(assert_return (invoke "as-br_if-last") (i32.const 2))
+
+(assert_return (invoke "as-br_table-first") (i32.const 6))
+(assert_return (invoke "as-br_table-last") (i32.const 2))
+
+(assert_return (invoke "as-call_indirect-first") (i32.const 6))
+(assert_return (invoke "as-call_indirect-mid") (i32.const 2))
+(assert_trap (invoke "as-call_indirect-last") "undefined element")
+
+(assert_return (invoke "as-store-first"))
+(assert_return (invoke "as-store-last"))
+(assert_return (invoke "as-load-operand") (i32.const 1))
+(assert_return (invoke "as-memory.grow-value") (i32.const 1))
+
+(assert_return (invoke "as-call-value") (i32.const 6))
+
+(assert_return (invoke "as-return-value") (i32.const 6))
+(assert_return (invoke "as-drop-operand"))
+(assert_return (invoke "as-br-value") (i32.const 6))
+
+(assert_return (invoke "as-local.set-value" (i32.const 1)) (i32.const 6))
+(assert_return (invoke "as-local.tee-value" (i32.const 1)) (i32.const 6))
+(assert_return (invoke "as-global.set-value") (i32.const 6))
+
+(assert_return (invoke "as-unary-operand") (i32.const 0))
+(assert_return (invoke "as-binary-operand") (i32.const 36))
+(assert_return (invoke "as-compare-operand") (i32.const 1))
+
+(assert_invalid
+  (module (global f32 (f32.const 0)) (func (global.set 0 (f32.const 1))))
+  "global is immutable"
+)
+
+;; mutable globals can be exported
+(module (global (mut f32) (f32.const 0)) (export "a" (global 0)))
+(module (global (export "a") (mut f32) (f32.const 0)))
+
+(assert_invalid
+  (module (global f32 (f32.neg (f32.const 0))))
+  "constant expression required"
+)
+
+(assert_invalid
+  (module (global f32 (local.get 0)))
+  "constant expression required"
+)
+
+(assert_invalid
+  (module (global f32 (f32.neg (f32.const 1))))
+  "constant expression required"
+)
+
+(assert_invalid
+  (module (global i32 (i32.const 0) (nop)))
+  "constant expression required"
+)
+
+(assert_invalid
+  (module (global i32 (nop)))
+  "constant expression required"
+)
+
+(assert_invalid
+  (module (global i32 (f32.const 0)))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (global i32 (i32.const 0) (i32.const 0)))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (global i32 (;empty instruction sequence;)))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (global i32 (global.get 0)))
+  "unknown global"
+)
+
+(assert_invalid
+  (module (global i32 (global.get 1)) (global i32 (i32.const 0)))
+  "unknown global"
+)
+
+(module
+  (import "spectest" "global_i32" (global i32))
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\98\80\80\80\00"             ;; import section
+      "\01"                          ;; length 1
+      "\08\73\70\65\63\74\65\73\74"  ;; "spectest"
+      "\0a\67\6c\6f\62\61\6c\5f\69\33\32" ;; "global_i32"
+      "\03"                          ;; GlobalImport
+      "\7f"                          ;; i32
+      "\02"                          ;; invalid mutability
+  )
+  "invalid mutability"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\98\80\80\80\00"             ;; import section
+      "\01"                          ;; length 1
+      "\08\73\70\65\63\74\65\73\74"  ;; "spectest"
+      "\0a\67\6c\6f\62\61\6c\5f\69\33\32" ;; "global_i32"
+      "\03"                          ;; GlobalImport
+      "\7f"                          ;; i32
+      "\ff"                          ;; invalid mutability
+  )
+  "invalid mutability"
+)
+
+(module
+  (global i32 (i32.const 0))
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\86\80\80\80\00"  ;; global section
+      "\01"               ;; length 1
+      "\7f"               ;; i32
+      "\02"               ;; invalid mutability
+      "\41\00"            ;; i32.const 0
+      "\0b"               ;; end
+  )
+  "invalid mutability"
+)
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\06\86\80\80\80\00"  ;; global section
+      "\01"               ;; length 1
+      "\7f"               ;; i32
+      "\ff"               ;; invalid mutability
+      "\41\00"            ;; i32.const 0
+      "\0b"               ;; end
+  )
+  "invalid mutability"
+)
+
+
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-global.set-value-empty
+      (global.set $x)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-global.set-value-empty-in-block
+      (i32.const 0)
+      (block (global.set $x))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-global.set-value-empty-in-loop
+      (i32.const 0)
+      (loop (global.set $x))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-global.set-value-empty-in-then
+      (i32.const 0) (i32.const 0)
+      (if (then (global.set $x)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-global.set-value-empty-in-else
+      (i32.const 0) (i32.const 0)
+      (if (result i32) (then (i32.const 0)) (else (global.set $x)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-global.set-value-empty-in-br
+      (i32.const 0)
+      (block (br 0 (global.set $x)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-global.set-value-empty-in-br_if
+      (i32.const 0)
+      (block (br_if 0 (global.set $x)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-global.set-value-empty-in-br_table
+      (i32.const 0)
+      (block (br_table 0 (global.set $x)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-global.set-value-empty-in-return
+      (return (global.set $x))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-global.set-value-empty-in-select
+      (select (global.set $x) (i32.const 1) (i32.const 2))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-global.set-value-empty-in-call
+      (call 1 (global.set $x))
+    )
+    (func (param i32) (result i32) (local.get 0))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $f (param i32) (result i32) (local.get 0))
+    (type $sig (func (param i32) (result i32)))
+    (table funcref (elem $f))
+    (func $type-global.set-value-empty-in-call_indirect
+      (block (result i32)
+        (call_indirect (type $sig)
+          (global.set $x) (i32.const 0)
+        )
+      )
+    )
+  )
+  "type mismatch"
+)
diff --git a/binaryen/test/spec/i32.load32_s.fail.wast b/binaryen/test/spec/i32.load32_s.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/i32.load32_s.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (result i32) (i32.load32_s (local.get 0))))
diff --git a/binaryen/test/spec/i32.load32_u.fail.wast b/binaryen/test/spec/i32.load32_u.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/i32.load32_u.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (result i32) (i32.load32_u (local.get 0))))
diff --git a/binaryen/test/spec/i32.load64_s.fail.wast b/binaryen/test/spec/i32.load64_s.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/i32.load64_s.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (result i32) (i32.load64_s (local.get 0))))
diff --git a/binaryen/test/spec/i32.load64_u.fail.wast b/binaryen/test/spec/i32.load64_u.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/i32.load64_u.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (result i32) (i32.load64_u (local.get 0))))
diff --git a/binaryen/test/spec/i32.store32.fail.wast b/binaryen/test/spec/i32.store32.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/i32.store32.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (param i32) (i32.store32 (local.get 0) (local.get 1))))
diff --git a/binaryen/test/spec/i32.store64.fail.wast b/binaryen/test/spec/i32.store64.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/i32.store64.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (param i64) (i32.store64 (local.get 0) (local.get 1))))
diff --git a/binaryen/test/spec/i32.wast b/binaryen/test/spec/i32.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/i32.wast
@@ -0,0 +1,958 @@
+;; i32 operations
+
+(module
+  (func (export "add") (param $x i32) (param $y i32) (result i32) (i32.add (local.get $x) (local.get $y)))
+  (func (export "sub") (param $x i32) (param $y i32) (result i32) (i32.sub (local.get $x) (local.get $y)))
+  (func (export "mul") (param $x i32) (param $y i32) (result i32) (i32.mul (local.get $x) (local.get $y)))
+  (func (export "div_s") (param $x i32) (param $y i32) (result i32) (i32.div_s (local.get $x) (local.get $y)))
+  (func (export "div_u") (param $x i32) (param $y i32) (result i32) (i32.div_u (local.get $x) (local.get $y)))
+  (func (export "rem_s") (param $x i32) (param $y i32) (result i32) (i32.rem_s (local.get $x) (local.get $y)))
+  (func (export "rem_u") (param $x i32) (param $y i32) (result i32) (i32.rem_u (local.get $x) (local.get $y)))
+  (func (export "and") (param $x i32) (param $y i32) (result i32) (i32.and (local.get $x) (local.get $y)))
+  (func (export "or") (param $x i32) (param $y i32) (result i32) (i32.or (local.get $x) (local.get $y)))
+  (func (export "xor") (param $x i32) (param $y i32) (result i32) (i32.xor (local.get $x) (local.get $y)))
+  (func (export "shl") (param $x i32) (param $y i32) (result i32) (i32.shl (local.get $x) (local.get $y)))
+  (func (export "shr_s") (param $x i32) (param $y i32) (result i32) (i32.shr_s (local.get $x) (local.get $y)))
+  (func (export "shr_u") (param $x i32) (param $y i32) (result i32) (i32.shr_u (local.get $x) (local.get $y)))
+  (func (export "rotl") (param $x i32) (param $y i32) (result i32) (i32.rotl (local.get $x) (local.get $y)))
+  (func (export "rotr") (param $x i32) (param $y i32) (result i32) (i32.rotr (local.get $x) (local.get $y)))
+  (func (export "clz") (param $x i32) (result i32) (i32.clz (local.get $x)))
+  (func (export "ctz") (param $x i32) (result i32) (i32.ctz (local.get $x)))
+  (func (export "popcnt") (param $x i32) (result i32) (i32.popcnt (local.get $x)))
+  (func (export "eqz") (param $x i32) (result i32) (i32.eqz (local.get $x)))
+  (func (export "eq") (param $x i32) (param $y i32) (result i32) (i32.eq (local.get $x) (local.get $y)))
+  (func (export "ne") (param $x i32) (param $y i32) (result i32) (i32.ne (local.get $x) (local.get $y)))
+  (func (export "lt_s") (param $x i32) (param $y i32) (result i32) (i32.lt_s (local.get $x) (local.get $y)))
+  (func (export "lt_u") (param $x i32) (param $y i32) (result i32) (i32.lt_u (local.get $x) (local.get $y)))
+  (func (export "le_s") (param $x i32) (param $y i32) (result i32) (i32.le_s (local.get $x) (local.get $y)))
+  (func (export "le_u") (param $x i32) (param $y i32) (result i32) (i32.le_u (local.get $x) (local.get $y)))
+  (func (export "gt_s") (param $x i32) (param $y i32) (result i32) (i32.gt_s (local.get $x) (local.get $y)))
+  (func (export "gt_u") (param $x i32) (param $y i32) (result i32) (i32.gt_u (local.get $x) (local.get $y)))
+  (func (export "ge_s") (param $x i32) (param $y i32) (result i32) (i32.ge_s (local.get $x) (local.get $y)))
+  (func (export "ge_u") (param $x i32) (param $y i32) (result i32) (i32.ge_u (local.get $x) (local.get $y)))
+)
+
+(assert_return (invoke "add" (i32.const 1) (i32.const 1)) (i32.const 2))
+(assert_return (invoke "add" (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "add" (i32.const -1) (i32.const -1)) (i32.const -2))
+(assert_return (invoke "add" (i32.const -1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "add" (i32.const 0x7fffffff) (i32.const 1)) (i32.const 0x80000000))
+(assert_return (invoke "add" (i32.const 0x80000000) (i32.const -1)) (i32.const 0x7fffffff))
+(assert_return (invoke "add" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "add" (i32.const 0x3fffffff) (i32.const 1)) (i32.const 0x40000000))
+
+(assert_return (invoke "sub" (i32.const 1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "sub" (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "sub" (i32.const -1) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "sub" (i32.const 0x7fffffff) (i32.const -1)) (i32.const 0x80000000))
+(assert_return (invoke "sub" (i32.const 0x80000000) (i32.const 1)) (i32.const 0x7fffffff))
+(assert_return (invoke "sub" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "sub" (i32.const 0x3fffffff) (i32.const -1)) (i32.const 0x40000000))
+
+(assert_return (invoke "mul" (i32.const 1) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "mul" (i32.const 1) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "mul" (i32.const -1) (i32.const -1)) (i32.const 1))
+(assert_return (invoke "mul" (i32.const 0x10000000) (i32.const 4096)) (i32.const 0))
+(assert_return (invoke "mul" (i32.const 0x80000000) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "mul" (i32.const 0x80000000) (i32.const -1)) (i32.const 0x80000000))
+(assert_return (invoke "mul" (i32.const 0x7fffffff) (i32.const -1)) (i32.const 0x80000001))
+(assert_return (invoke "mul" (i32.const 0x01234567) (i32.const 0x76543210)) (i32.const 0x358e7470))
+(assert_return (invoke "mul" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 1))
+
+(assert_trap (invoke "div_s" (i32.const 1) (i32.const 0)) "integer divide by zero")
+(assert_trap (invoke "div_s" (i32.const 0) (i32.const 0)) "integer divide by zero")
+(assert_trap (invoke "div_s" (i32.const 0x80000000) (i32.const -1)) "integer overflow")
+(assert_trap (invoke "div_s" (i32.const 0x80000000) (i32.const 0)) "integer divide by zero")
+(assert_return (invoke "div_s" (i32.const 1) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "div_s" (i32.const 0) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "div_s" (i32.const 0) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "div_s" (i32.const -1) (i32.const -1)) (i32.const 1))
+(assert_return (invoke "div_s" (i32.const 0x80000000) (i32.const 2)) (i32.const 0xc0000000))
+(assert_return (invoke "div_s" (i32.const 0x80000001) (i32.const 1000)) (i32.const 0xffdf3b65))
+(assert_return (invoke "div_s" (i32.const 5) (i32.const 2)) (i32.const 2))
+(assert_return (invoke "div_s" (i32.const -5) (i32.const 2)) (i32.const -2))
+(assert_return (invoke "div_s" (i32.const 5) (i32.const -2)) (i32.const -2))
+(assert_return (invoke "div_s" (i32.const -5) (i32.const -2)) (i32.const 2))
+(assert_return (invoke "div_s" (i32.const 7) (i32.const 3)) (i32.const 2))
+(assert_return (invoke "div_s" (i32.const -7) (i32.const 3)) (i32.const -2))
+(assert_return (invoke "div_s" (i32.const 7) (i32.const -3)) (i32.const -2))
+(assert_return (invoke "div_s" (i32.const -7) (i32.const -3)) (i32.const 2))
+(assert_return (invoke "div_s" (i32.const 11) (i32.const 5)) (i32.const 2))
+(assert_return (invoke "div_s" (i32.const 17) (i32.const 7)) (i32.const 2))
+
+(assert_trap (invoke "div_u" (i32.const 1) (i32.const 0)) "integer divide by zero")
+(assert_trap (invoke "div_u" (i32.const 0) (i32.const 0)) "integer divide by zero")
+(assert_return (invoke "div_u" (i32.const 1) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "div_u" (i32.const 0) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "div_u" (i32.const -1) (i32.const -1)) (i32.const 1))
+(assert_return (invoke "div_u" (i32.const 0x80000000) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "div_u" (i32.const 0x80000000) (i32.const 2)) (i32.const 0x40000000))
+(assert_return (invoke "div_u" (i32.const 0x8ff00ff0) (i32.const 0x10001)) (i32.const 0x8fef))
+(assert_return (invoke "div_u" (i32.const 0x80000001) (i32.const 1000)) (i32.const 0x20c49b))
+(assert_return (invoke "div_u" (i32.const 5) (i32.const 2)) (i32.const 2))
+(assert_return (invoke "div_u" (i32.const -5) (i32.const 2)) (i32.const 0x7ffffffd))
+(assert_return (invoke "div_u" (i32.const 5) (i32.const -2)) (i32.const 0))
+(assert_return (invoke "div_u" (i32.const -5) (i32.const -2)) (i32.const 0))
+(assert_return (invoke "div_u" (i32.const 7) (i32.const 3)) (i32.const 2))
+(assert_return (invoke "div_u" (i32.const 11) (i32.const 5)) (i32.const 2))
+(assert_return (invoke "div_u" (i32.const 17) (i32.const 7)) (i32.const 2))
+
+(assert_trap (invoke "rem_s" (i32.const 1) (i32.const 0)) "integer divide by zero")
+(assert_trap (invoke "rem_s" (i32.const 0) (i32.const 0)) "integer divide by zero")
+(assert_return (invoke "rem_s" (i32.const 0x7fffffff) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "rem_s" (i32.const 1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "rem_s" (i32.const 0) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "rem_s" (i32.const 0) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "rem_s" (i32.const -1) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "rem_s" (i32.const 0x80000000) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "rem_s" (i32.const 0x80000000) (i32.const 2)) (i32.const 0))
+(assert_return (invoke "rem_s" (i32.const 0x80000001) (i32.const 1000)) (i32.const -647))
+(assert_return (invoke "rem_s" (i32.const 5) (i32.const 2)) (i32.const 1))
+(assert_return (invoke "rem_s" (i32.const -5) (i32.const 2)) (i32.const -1))
+(assert_return (invoke "rem_s" (i32.const 5) (i32.const -2)) (i32.const 1))
+(assert_return (invoke "rem_s" (i32.const -5) (i32.const -2)) (i32.const -1))
+(assert_return (invoke "rem_s" (i32.const 7) (i32.const 3)) (i32.const 1))
+(assert_return (invoke "rem_s" (i32.const -7) (i32.const 3)) (i32.const -1))
+(assert_return (invoke "rem_s" (i32.const 7) (i32.const -3)) (i32.const 1))
+(assert_return (invoke "rem_s" (i32.const -7) (i32.const -3)) (i32.const -1))
+(assert_return (invoke "rem_s" (i32.const 11) (i32.const 5)) (i32.const 1))
+(assert_return (invoke "rem_s" (i32.const 17) (i32.const 7)) (i32.const 3))
+
+(assert_trap (invoke "rem_u" (i32.const 1) (i32.const 0)) "integer divide by zero")
+(assert_trap (invoke "rem_u" (i32.const 0) (i32.const 0)) "integer divide by zero")
+(assert_return (invoke "rem_u" (i32.const 1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "rem_u" (i32.const 0) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "rem_u" (i32.const -1) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "rem_u" (i32.const 0x80000000) (i32.const -1)) (i32.const 0x80000000))
+(assert_return (invoke "rem_u" (i32.const 0x80000000) (i32.const 2)) (i32.const 0))
+(assert_return (invoke "rem_u" (i32.const 0x8ff00ff0) (i32.const 0x10001)) (i32.const 0x8001))
+(assert_return (invoke "rem_u" (i32.const 0x80000001) (i32.const 1000)) (i32.const 649))
+(assert_return (invoke "rem_u" (i32.const 5) (i32.const 2)) (i32.const 1))
+(assert_return (invoke "rem_u" (i32.const -5) (i32.const 2)) (i32.const 1))
+(assert_return (invoke "rem_u" (i32.const 5) (i32.const -2)) (i32.const 5))
+(assert_return (invoke "rem_u" (i32.const -5) (i32.const -2)) (i32.const -5))
+(assert_return (invoke "rem_u" (i32.const 7) (i32.const 3)) (i32.const 1))
+(assert_return (invoke "rem_u" (i32.const 11) (i32.const 5)) (i32.const 1))
+(assert_return (invoke "rem_u" (i32.const 17) (i32.const 7)) (i32.const 3))
+
+(assert_return (invoke "and" (i32.const 1) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "and" (i32.const 0) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "and" (i32.const 1) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "and" (i32.const 0) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "and" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "and" (i32.const 0x7fffffff) (i32.const -1)) (i32.const 0x7fffffff))
+(assert_return (invoke "and" (i32.const 0xf0f0ffff) (i32.const 0xfffff0f0)) (i32.const 0xf0f0f0f0))
+(assert_return (invoke "and" (i32.const 0xffffffff) (i32.const 0xffffffff)) (i32.const 0xffffffff))
+
+(assert_return (invoke "or" (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "or" (i32.const 0) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "or" (i32.const 1) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "or" (i32.const 0) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "or" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const -1))
+(assert_return (invoke "or" (i32.const 0x80000000) (i32.const 0)) (i32.const 0x80000000))
+(assert_return (invoke "or" (i32.const 0xf0f0ffff) (i32.const 0xfffff0f0)) (i32.const 0xffffffff))
+(assert_return (invoke "or" (i32.const 0xffffffff) (i32.const 0xffffffff)) (i32.const 0xffffffff))
+
+(assert_return (invoke "xor" (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "xor" (i32.const 0) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "xor" (i32.const 1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "xor" (i32.const 0) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "xor" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const -1))
+(assert_return (invoke "xor" (i32.const 0x80000000) (i32.const 0)) (i32.const 0x80000000))
+(assert_return (invoke "xor" (i32.const -1) (i32.const 0x80000000)) (i32.const 0x7fffffff))
+(assert_return (invoke "xor" (i32.const -1) (i32.const 0x7fffffff)) (i32.const 0x80000000))
+(assert_return (invoke "xor" (i32.const 0xf0f0ffff) (i32.const 0xfffff0f0)) (i32.const 0x0f0f0f0f))
+(assert_return (invoke "xor" (i32.const 0xffffffff) (i32.const 0xffffffff)) (i32.const 0))
+
+(assert_return (invoke "shl" (i32.const 1) (i32.const 1)) (i32.const 2))
+(assert_return (invoke "shl" (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "shl" (i32.const 0x7fffffff) (i32.const 1)) (i32.const 0xfffffffe))
+(assert_return (invoke "shl" (i32.const 0xffffffff) (i32.const 1)) (i32.const 0xfffffffe))
+(assert_return (invoke "shl" (i32.const 0x80000000) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "shl" (i32.const 0x40000000) (i32.const 1)) (i32.const 0x80000000))
+(assert_return (invoke "shl" (i32.const 1) (i32.const 31)) (i32.const 0x80000000))
+(assert_return (invoke "shl" (i32.const 1) (i32.const 32)) (i32.const 1))
+(assert_return (invoke "shl" (i32.const 1) (i32.const 33)) (i32.const 2))
+(assert_return (invoke "shl" (i32.const 1) (i32.const -1)) (i32.const 0x80000000))
+(assert_return (invoke "shl" (i32.const 1) (i32.const 0x7fffffff)) (i32.const 0x80000000))
+
+(assert_return (invoke "shr_s" (i32.const 1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "shr_s" (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "shr_s" (i32.const -1) (i32.const 1)) (i32.const -1))
+(assert_return (invoke "shr_s" (i32.const 0x7fffffff) (i32.const 1)) (i32.const 0x3fffffff))
+(assert_return (invoke "shr_s" (i32.const 0x80000000) (i32.const 1)) (i32.const 0xc0000000))
+(assert_return (invoke "shr_s" (i32.const 0x40000000) (i32.const 1)) (i32.const 0x20000000))
+(assert_return (invoke "shr_s" (i32.const 1) (i32.const 32)) (i32.const 1))
+(assert_return (invoke "shr_s" (i32.const 1) (i32.const 33)) (i32.const 0))
+(assert_return (invoke "shr_s" (i32.const 1) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "shr_s" (i32.const 1) (i32.const 0x7fffffff)) (i32.const 0))
+(assert_return (invoke "shr_s" (i32.const 1) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "shr_s" (i32.const 0x80000000) (i32.const 31)) (i32.const -1))
+(assert_return (invoke "shr_s" (i32.const -1) (i32.const 32)) (i32.const -1))
+(assert_return (invoke "shr_s" (i32.const -1) (i32.const 33)) (i32.const -1))
+(assert_return (invoke "shr_s" (i32.const -1) (i32.const -1)) (i32.const -1))
+(assert_return (invoke "shr_s" (i32.const -1) (i32.const 0x7fffffff)) (i32.const -1))
+(assert_return (invoke "shr_s" (i32.const -1) (i32.const 0x80000000)) (i32.const -1))
+
+(assert_return (invoke "shr_u" (i32.const 1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "shr_u" (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "shr_u" (i32.const -1) (i32.const 1)) (i32.const 0x7fffffff))
+(assert_return (invoke "shr_u" (i32.const 0x7fffffff) (i32.const 1)) (i32.const 0x3fffffff))
+(assert_return (invoke "shr_u" (i32.const 0x80000000) (i32.const 1)) (i32.const 0x40000000))
+(assert_return (invoke "shr_u" (i32.const 0x40000000) (i32.const 1)) (i32.const 0x20000000))
+(assert_return (invoke "shr_u" (i32.const 1) (i32.const 32)) (i32.const 1))
+(assert_return (invoke "shr_u" (i32.const 1) (i32.const 33)) (i32.const 0))
+(assert_return (invoke "shr_u" (i32.const 1) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "shr_u" (i32.const 1) (i32.const 0x7fffffff)) (i32.const 0))
+(assert_return (invoke "shr_u" (i32.const 1) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "shr_u" (i32.const 0x80000000) (i32.const 31)) (i32.const 1))
+(assert_return (invoke "shr_u" (i32.const -1) (i32.const 32)) (i32.const -1))
+(assert_return (invoke "shr_u" (i32.const -1) (i32.const 33)) (i32.const 0x7fffffff))
+(assert_return (invoke "shr_u" (i32.const -1) (i32.const -1)) (i32.const 1))
+(assert_return (invoke "shr_u" (i32.const -1) (i32.const 0x7fffffff)) (i32.const 1))
+(assert_return (invoke "shr_u" (i32.const -1) (i32.const 0x80000000)) (i32.const -1))
+
+(assert_return (invoke "rotl" (i32.const 1) (i32.const 1)) (i32.const 2))
+(assert_return (invoke "rotl" (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "rotl" (i32.const -1) (i32.const 1)) (i32.const -1))
+(assert_return (invoke "rotl" (i32.const 1) (i32.const 32)) (i32.const 1))
+(assert_return (invoke "rotl" (i32.const 0xabcd9876) (i32.const 1)) (i32.const 0x579b30ed))
+(assert_return (invoke "rotl" (i32.const 0xfe00dc00) (i32.const 4)) (i32.const 0xe00dc00f))
+(assert_return (invoke "rotl" (i32.const 0xb0c1d2e3) (i32.const 5)) (i32.const 0x183a5c76))
+(assert_return (invoke "rotl" (i32.const 0x00008000) (i32.const 37)) (i32.const 0x00100000))
+(assert_return (invoke "rotl" (i32.const 0xb0c1d2e3) (i32.const 0xff05)) (i32.const 0x183a5c76))
+(assert_return (invoke "rotl" (i32.const 0x769abcdf) (i32.const 0xffffffed)) (i32.const 0x579beed3))
+(assert_return (invoke "rotl" (i32.const 0x769abcdf) (i32.const 0x8000000d)) (i32.const 0x579beed3))
+(assert_return (invoke "rotl" (i32.const 1) (i32.const 31)) (i32.const 0x80000000))
+(assert_return (invoke "rotl" (i32.const 0x80000000) (i32.const 1)) (i32.const 1))
+
+(assert_return (invoke "rotr" (i32.const 1) (i32.const 1)) (i32.const 0x80000000))
+(assert_return (invoke "rotr" (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "rotr" (i32.const -1) (i32.const 1)) (i32.const -1))
+(assert_return (invoke "rotr" (i32.const 1) (i32.const 32)) (i32.const 1))
+(assert_return (invoke "rotr" (i32.const 0xff00cc00) (i32.const 1)) (i32.const 0x7f806600))
+(assert_return (invoke "rotr" (i32.const 0x00080000) (i32.const 4)) (i32.const 0x00008000))
+(assert_return (invoke "rotr" (i32.const 0xb0c1d2e3) (i32.const 5)) (i32.const 0x1d860e97))
+(assert_return (invoke "rotr" (i32.const 0x00008000) (i32.const 37)) (i32.const 0x00000400))
+(assert_return (invoke "rotr" (i32.const 0xb0c1d2e3) (i32.const 0xff05)) (i32.const 0x1d860e97))
+(assert_return (invoke "rotr" (i32.const 0x769abcdf) (i32.const 0xffffffed)) (i32.const 0xe6fbb4d5))
+(assert_return (invoke "rotr" (i32.const 0x769abcdf) (i32.const 0x8000000d)) (i32.const 0xe6fbb4d5))
+(assert_return (invoke "rotr" (i32.const 1) (i32.const 31)) (i32.const 2))
+(assert_return (invoke "rotr" (i32.const 0x80000000) (i32.const 31)) (i32.const 1))
+
+(assert_return (invoke "clz" (i32.const 0xffffffff)) (i32.const 0))
+(assert_return (invoke "clz" (i32.const 0)) (i32.const 32))
+(assert_return (invoke "clz" (i32.const 0x00008000)) (i32.const 16))
+(assert_return (invoke "clz" (i32.const 0xff)) (i32.const 24))
+(assert_return (invoke "clz" (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "clz" (i32.const 1)) (i32.const 31))
+(assert_return (invoke "clz" (i32.const 2)) (i32.const 30))
+(assert_return (invoke "clz" (i32.const 0x7fffffff)) (i32.const 1))
+
+(assert_return (invoke "ctz" (i32.const -1)) (i32.const 0))
+(assert_return (invoke "ctz" (i32.const 0)) (i32.const 32))
+(assert_return (invoke "ctz" (i32.const 0x00008000)) (i32.const 15))
+(assert_return (invoke "ctz" (i32.const 0x00010000)) (i32.const 16))
+(assert_return (invoke "ctz" (i32.const 0x80000000)) (i32.const 31))
+(assert_return (invoke "ctz" (i32.const 0x7fffffff)) (i32.const 0))
+
+(assert_return (invoke "popcnt" (i32.const -1)) (i32.const 32))
+(assert_return (invoke "popcnt" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "popcnt" (i32.const 0x00008000)) (i32.const 1))
+(assert_return (invoke "popcnt" (i32.const 0x80008000)) (i32.const 2))
+(assert_return (invoke "popcnt" (i32.const 0x7fffffff)) (i32.const 31))
+(assert_return (invoke "popcnt" (i32.const 0xAAAAAAAA)) (i32.const 16))
+(assert_return (invoke "popcnt" (i32.const 0x55555555)) (i32.const 16))
+(assert_return (invoke "popcnt" (i32.const 0xDEADBEEF)) (i32.const 24))
+
+(assert_return (invoke "eqz" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "eqz" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "eqz" (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "eqz" (i32.const 0x7fffffff)) (i32.const 0))
+(assert_return (invoke "eqz" (i32.const 0xffffffff)) (i32.const 0))
+
+(assert_return (invoke "eq" (i32.const 0) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "eq" (i32.const 1) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "eq" (i32.const -1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "eq" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "eq" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 1))
+(assert_return (invoke "eq" (i32.const -1) (i32.const -1)) (i32.const 1))
+(assert_return (invoke "eq" (i32.const 1) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "eq" (i32.const 0) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "eq" (i32.const 0x80000000) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "eq" (i32.const 0) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "eq" (i32.const 0x80000000) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "eq" (i32.const -1) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "eq" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 0))
+(assert_return (invoke "eq" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 0))
+
+(assert_return (invoke "ne" (i32.const 0) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "ne" (i32.const 1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "ne" (i32.const -1) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "ne" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "ne" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 0))
+(assert_return (invoke "ne" (i32.const -1) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "ne" (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "ne" (i32.const 0) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "ne" (i32.const 0x80000000) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "ne" (i32.const 0) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "ne" (i32.const 0x80000000) (i32.const -1)) (i32.const 1))
+(assert_return (invoke "ne" (i32.const -1) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "ne" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 1))
+(assert_return (invoke "ne" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 1))
+
+(assert_return (invoke "lt_s" (i32.const 0) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "lt_s" (i32.const 1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "lt_s" (i32.const -1) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "lt_s" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "lt_s" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 0))
+(assert_return (invoke "lt_s" (i32.const -1) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "lt_s" (i32.const 1) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "lt_s" (i32.const 0) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "lt_s" (i32.const 0x80000000) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "lt_s" (i32.const 0) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "lt_s" (i32.const 0x80000000) (i32.const -1)) (i32.const 1))
+(assert_return (invoke "lt_s" (i32.const -1) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "lt_s" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 1))
+(assert_return (invoke "lt_s" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 0))
+
+(assert_return (invoke "lt_u" (i32.const 0) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "lt_u" (i32.const 1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "lt_u" (i32.const -1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "lt_u" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "lt_u" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 0))
+(assert_return (invoke "lt_u" (i32.const -1) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "lt_u" (i32.const 1) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "lt_u" (i32.const 0) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "lt_u" (i32.const 0x80000000) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "lt_u" (i32.const 0) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "lt_u" (i32.const 0x80000000) (i32.const -1)) (i32.const 1))
+(assert_return (invoke "lt_u" (i32.const -1) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "lt_u" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 0))
+(assert_return (invoke "lt_u" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 1))
+
+(assert_return (invoke "le_s" (i32.const 0) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "le_s" (i32.const 1) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "le_s" (i32.const -1) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "le_s" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "le_s" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 1))
+(assert_return (invoke "le_s" (i32.const -1) (i32.const -1)) (i32.const 1))
+(assert_return (invoke "le_s" (i32.const 1) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "le_s" (i32.const 0) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "le_s" (i32.const 0x80000000) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "le_s" (i32.const 0) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "le_s" (i32.const 0x80000000) (i32.const -1)) (i32.const 1))
+(assert_return (invoke "le_s" (i32.const -1) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "le_s" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 1))
+(assert_return (invoke "le_s" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 0))
+
+(assert_return (invoke "le_u" (i32.const 0) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "le_u" (i32.const 1) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "le_u" (i32.const -1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "le_u" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "le_u" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 1))
+(assert_return (invoke "le_u" (i32.const -1) (i32.const -1)) (i32.const 1))
+(assert_return (invoke "le_u" (i32.const 1) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "le_u" (i32.const 0) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "le_u" (i32.const 0x80000000) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "le_u" (i32.const 0) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "le_u" (i32.const 0x80000000) (i32.const -1)) (i32.const 1))
+(assert_return (invoke "le_u" (i32.const -1) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "le_u" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 0))
+(assert_return (invoke "le_u" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 1))
+
+(assert_return (invoke "gt_s" (i32.const 0) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "gt_s" (i32.const 1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "gt_s" (i32.const -1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "gt_s" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "gt_s" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 0))
+(assert_return (invoke "gt_s" (i32.const -1) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "gt_s" (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "gt_s" (i32.const 0) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "gt_s" (i32.const 0x80000000) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "gt_s" (i32.const 0) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "gt_s" (i32.const 0x80000000) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "gt_s" (i32.const -1) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "gt_s" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 0))
+(assert_return (invoke "gt_s" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 1))
+
+(assert_return (invoke "gt_u" (i32.const 0) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "gt_u" (i32.const 1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "gt_u" (i32.const -1) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "gt_u" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "gt_u" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 0))
+(assert_return (invoke "gt_u" (i32.const -1) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "gt_u" (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "gt_u" (i32.const 0) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "gt_u" (i32.const 0x80000000) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "gt_u" (i32.const 0) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "gt_u" (i32.const 0x80000000) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "gt_u" (i32.const -1) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "gt_u" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 1))
+(assert_return (invoke "gt_u" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 0))
+
+(assert_return (invoke "ge_s" (i32.const 0) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "ge_s" (i32.const 1) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "ge_s" (i32.const -1) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "ge_s" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "ge_s" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 1))
+(assert_return (invoke "ge_s" (i32.const -1) (i32.const -1)) (i32.const 1))
+(assert_return (invoke "ge_s" (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "ge_s" (i32.const 0) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "ge_s" (i32.const 0x80000000) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "ge_s" (i32.const 0) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "ge_s" (i32.const 0x80000000) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "ge_s" (i32.const -1) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "ge_s" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 0))
+(assert_return (invoke "ge_s" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 1))
+
+(assert_return (invoke "ge_u" (i32.const 0) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "ge_u" (i32.const 1) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "ge_u" (i32.const -1) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "ge_u" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "ge_u" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 1))
+(assert_return (invoke "ge_u" (i32.const -1) (i32.const -1)) (i32.const 1))
+(assert_return (invoke "ge_u" (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "ge_u" (i32.const 0) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "ge_u" (i32.const 0x80000000) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "ge_u" (i32.const 0) (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "ge_u" (i32.const 0x80000000) (i32.const -1)) (i32.const 0))
+(assert_return (invoke "ge_u" (i32.const -1) (i32.const 0x80000000)) (i32.const 1))
+(assert_return (invoke "ge_u" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 1))
+(assert_return (invoke "ge_u" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 0))
+
+
+(assert_invalid
+  (module
+    (func $type-unary-operand-empty
+      (i32.eqz) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-unary-operand-empty-in-block
+      (i32.const 0)
+      (block (i32.eqz) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-unary-operand-empty-in-loop
+      (i32.const 0)
+      (loop (i32.eqz) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-unary-operand-empty-in-if
+      (i32.const 0) (i32.const 0)
+      (if (then (i32.eqz) (drop)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-unary-operand-empty-in-else
+      (i32.const 0) (i32.const 0)
+      (if (result i32) (then (i32.const 0)) (else (i32.eqz))) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-unary-operand-empty-in-br
+      (i32.const 0)
+      (block (br 0 (i32.eqz)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-unary-operand-empty-in-br_if
+      (i32.const 0)
+      (block (br_if 0 (i32.eqz) (i32.const 1)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-unary-operand-empty-in-br_table
+      (i32.const 0)
+      (block (br_table 0 (i32.eqz)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-unary-operand-empty-in-return
+      (return (i32.eqz)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-unary-operand-empty-in-select
+      (select (i32.eqz) (i32.const 1) (i32.const 2)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-unary-operand-empty-in-call
+      (call 1 (i32.eqz)) (drop)
+    )
+    (func (param i32) (result i32) (local.get 0))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $f (param i32) (result i32) (local.get 0))
+    (type $sig (func (param i32) (result i32)))
+    (table funcref (elem $f))
+    (func $type-unary-operand-empty-in-call_indirect
+      (block (result i32)
+        (call_indirect (type $sig)
+          (i32.eqz) (i32.const 0)
+        )
+        (drop)
+      )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-unary-operand-empty-in-local.set
+      (local i32)
+      (local.set 0 (i32.eqz)) (local.get 0) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-unary-operand-empty-in-local.tee
+      (local i32)
+      (local.tee 0 (i32.eqz)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-unary-operand-empty-in-global.set
+      (global.set $x (i32.eqz)) (global.get $x) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-unary-operand-empty-in-memory.grow
+      (memory.grow (i32.eqz)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-unary-operand-empty-in-load
+      (i32.load (i32.eqz)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-unary-operand-empty-in-store
+      (i32.store (i32.eqz) (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (func $type-binary-1st-operand-empty
+      (i32.add) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-2nd-operand-empty
+      (i32.const 0) (i32.add) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-1st-operand-empty-in-block
+      (i32.const 0) (i32.const 0)
+      (block (i32.add) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-2nd-operand-empty-in-block
+      (i32.const 0)
+      (block (i32.const 0) (i32.add) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-1st-operand-empty-in-loop
+      (i32.const 0) (i32.const 0)
+      (loop (i32.add) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-2nd-operand-empty-in-loop
+      (i32.const 0)
+      (loop (i32.const 0) (i32.add) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-1st-operand-empty-in-if
+      (i32.const 0) (i32.const 0) (i32.const 0)
+      (if (i32.add) (then (drop)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-2nd-operand-empty-in-if
+      (i32.const 0) (i32.const 0)
+      (if (i32.const 0) (then (i32.add)) (else (drop)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-1st-operand-empty-in-else
+      (i32.const 0) (i32.const 0) (i32.const 0)
+      (if (result i32) (then (i32.const 0)) (else (i32.add) (i32.const 0)))
+      (drop) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-2nd-operand-empty-in-else
+      (i32.const 0) (i32.const 0)
+      (if (result i32) (then (i32.const 0)) (else (i32.add)))
+      (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-1st-operand-empty-in-br
+      (i32.const 0) (i32.const 0)
+      (block (br 0 (i32.add)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-2nd-operand-empty-in-br
+      (i32.const 0)
+      (block (br 0 (i32.const 0) (i32.add)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-1st-operand-empty-in-br_if
+      (i32.const 0) (i32.const 0)
+      (block (br_if 0 (i32.add) (i32.const 1)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-2nd-operand-empty-in-br_if
+      (i32.const 0)
+      (block (br_if 0 (i32.const 0) (i32.add) (i32.const 1)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-1st-operand-empty-in-br_table
+      (i32.const 0) (i32.const 0)
+      (block (br_table 0 (i32.add)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-2nd-operand-empty-in-br_table
+      (i32.const 0)
+      (block (br_table 0 (i32.const 0) (i32.add)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-1st-operand-empty-in-return
+      (return (i32.add)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-2nd-operand-empty-in-return
+      (return (i32.const 0) (i32.add)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-1st-operand-empty-in-select
+      (select (i32.add) (i32.const 1) (i32.const 2)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-2nd-operand-empty-in-select
+      (select (i32.const 0) (i32.add) (i32.const 1) (i32.const 2)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-1st-operand-empty-in-call
+      (call 1 (i32.add)) (drop)
+    )
+    (func (param i32 i32) (result i32) (local.get 0))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-2nd-operand-empty-in-call
+      (call 1 (i32.const 0) (i32.add)) (drop)
+    )
+    (func (param i32 i32) (result i32) (local.get 0))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $f (param i32) (result i32) (local.get 0))
+    (type $sig (func (param i32) (result i32)))
+    (table funcref (elem $f))
+    (func $type-binary-1st-operand-empty-in-call_indirect
+      (block (result i32)
+        (call_indirect (type $sig)
+          (i32.add) (i32.const 0)
+        )
+        (drop)
+      )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $f (param i32) (result i32) (local.get 0))
+    (type $sig (func (param i32) (result i32)))
+    (table funcref (elem $f))
+    (func $type-binary-2nd-operand-empty-in-call_indirect
+      (block (result i32)
+        (call_indirect (type $sig)
+          (i32.const 0) (i32.add) (i32.const 0)
+        )
+        (drop)
+      )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-1st-operand-empty-in-local.set
+      (local i32)
+      (local.set 0 (i32.add)) (local.get 0) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-2nd-operand-empty-in-local.set
+      (local i32)
+      (local.set 0 (i32.const 0) (i32.add)) (local.get 0) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-1st-operand-empty-in-local.tee
+      (local i32)
+      (local.tee 0 (i32.add)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-binary-2nd-operand-empty-in-local.tee
+      (local i32)
+      (local.tee 0 (i32.const 0) (i32.add)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-binary-1st-operand-empty-in-global.set
+      (global.set $x (i32.add)) (global.get $x) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-binary-2nd-operand-empty-in-global.set
+      (global.set $x (i32.const 0) (i32.add)) (global.get $x) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-binary-1st-operand-empty-in-memory.grow
+      (memory.grow (i32.add)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-binary-2nd-operand-empty-in-memory.grow
+      (memory.grow (i32.const 0) (i32.add)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-binary-1st-operand-empty-in-load
+      (i32.load (i32.add)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-binary-2nd-operand-empty-in-load
+      (i32.load (i32.const 0) (i32.add)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-binary-1st-operand-empty-in-store
+      (i32.store (i32.add) (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-binary-2nd-operand-empty-in-store
+      (i32.store (i32.const 1) (i32.add) (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
+
+
+;; Type check
+
+(assert_invalid (module (func (result i32) (i32.add (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.and (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.div_s (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.div_u (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.mul (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.or (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.rem_s (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.rem_u (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.rotl (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.rotr (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.shl (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.shr_s (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.shr_u (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.sub (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.xor (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.eqz (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.clz (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.ctz (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.popcnt (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.eq (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.ge_s (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.ge_u (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.gt_s (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.gt_u (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.le_s (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.le_u (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.lt_s (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.lt_u (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i32) (i32.ne (i64.const 0) (f32.const 0)))) "type mismatch")
diff --git a/binaryen/test/spec/i64.load64_s.fail.wast b/binaryen/test/spec/i64.load64_s.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/i64.load64_s.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (result i64) (i64.load64_s (local.get 0))))
diff --git a/binaryen/test/spec/i64.load64_u.fail.wast b/binaryen/test/spec/i64.load64_u.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/i64.load64_u.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (result i64) (i64.load64_u (local.get 0))))
diff --git a/binaryen/test/spec/i64.store64.fail.wast b/binaryen/test/spec/i64.store64.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/i64.store64.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 1) (func (param i32) (param i64) (i64.store64 (local.get 0) (local.get 1))))
diff --git a/binaryen/test/spec/i64.wast b/binaryen/test/spec/i64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/i64.wast
@@ -0,0 +1,455 @@
+;; i64 operations
+
+(module
+  (func (export "add") (param $x i64) (param $y i64) (result i64) (i64.add (local.get $x) (local.get $y)))
+  (func (export "sub") (param $x i64) (param $y i64) (result i64) (i64.sub (local.get $x) (local.get $y)))
+  (func (export "mul") (param $x i64) (param $y i64) (result i64) (i64.mul (local.get $x) (local.get $y)))
+  (func (export "div_s") (param $x i64) (param $y i64) (result i64) (i64.div_s (local.get $x) (local.get $y)))
+  (func (export "div_u") (param $x i64) (param $y i64) (result i64) (i64.div_u (local.get $x) (local.get $y)))
+  (func (export "rem_s") (param $x i64) (param $y i64) (result i64) (i64.rem_s (local.get $x) (local.get $y)))
+  (func (export "rem_u") (param $x i64) (param $y i64) (result i64) (i64.rem_u (local.get $x) (local.get $y)))
+  (func (export "and") (param $x i64) (param $y i64) (result i64) (i64.and (local.get $x) (local.get $y)))
+  (func (export "or") (param $x i64) (param $y i64) (result i64) (i64.or (local.get $x) (local.get $y)))
+  (func (export "xor") (param $x i64) (param $y i64) (result i64) (i64.xor (local.get $x) (local.get $y)))
+  (func (export "shl") (param $x i64) (param $y i64) (result i64) (i64.shl (local.get $x) (local.get $y)))
+  (func (export "shr_s") (param $x i64) (param $y i64) (result i64) (i64.shr_s (local.get $x) (local.get $y)))
+  (func (export "shr_u") (param $x i64) (param $y i64) (result i64) (i64.shr_u (local.get $x) (local.get $y)))
+  (func (export "rotl") (param $x i64) (param $y i64) (result i64) (i64.rotl (local.get $x) (local.get $y)))
+  (func (export "rotr") (param $x i64) (param $y i64) (result i64) (i64.rotr (local.get $x) (local.get $y)))
+  (func (export "clz") (param $x i64) (result i64) (i64.clz (local.get $x)))
+  (func (export "ctz") (param $x i64) (result i64) (i64.ctz (local.get $x)))
+  (func (export "popcnt") (param $x i64) (result i64) (i64.popcnt (local.get $x)))
+  (func (export "eqz") (param $x i64) (result i32) (i64.eqz (local.get $x)))
+  (func (export "eq") (param $x i64) (param $y i64) (result i32) (i64.eq (local.get $x) (local.get $y)))
+  (func (export "ne") (param $x i64) (param $y i64) (result i32) (i64.ne (local.get $x) (local.get $y)))
+  (func (export "lt_s") (param $x i64) (param $y i64) (result i32) (i64.lt_s (local.get $x) (local.get $y)))
+  (func (export "lt_u") (param $x i64) (param $y i64) (result i32) (i64.lt_u (local.get $x) (local.get $y)))
+  (func (export "le_s") (param $x i64) (param $y i64) (result i32) (i64.le_s (local.get $x) (local.get $y)))
+  (func (export "le_u") (param $x i64) (param $y i64) (result i32) (i64.le_u (local.get $x) (local.get $y)))
+  (func (export "gt_s") (param $x i64) (param $y i64) (result i32) (i64.gt_s (local.get $x) (local.get $y)))
+  (func (export "gt_u") (param $x i64) (param $y i64) (result i32) (i64.gt_u (local.get $x) (local.get $y)))
+  (func (export "ge_s") (param $x i64) (param $y i64) (result i32) (i64.ge_s (local.get $x) (local.get $y)))
+  (func (export "ge_u") (param $x i64) (param $y i64) (result i32) (i64.ge_u (local.get $x) (local.get $y)))
+)
+
+(assert_return (invoke "add" (i64.const 1) (i64.const 1)) (i64.const 2))
+(assert_return (invoke "add" (i64.const 1) (i64.const 0)) (i64.const 1))
+(assert_return (invoke "add" (i64.const -1) (i64.const -1)) (i64.const -2))
+(assert_return (invoke "add" (i64.const -1) (i64.const 1)) (i64.const 0))
+(assert_return (invoke "add" (i64.const 0x7fffffffffffffff) (i64.const 1)) (i64.const 0x8000000000000000))
+(assert_return (invoke "add" (i64.const 0x8000000000000000) (i64.const -1)) (i64.const 0x7fffffffffffffff))
+(assert_return (invoke "add" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i64.const 0))
+(assert_return (invoke "add" (i64.const 0x3fffffff) (i64.const 1)) (i64.const 0x40000000))
+
+(assert_return (invoke "sub" (i64.const 1) (i64.const 1)) (i64.const 0))
+(assert_return (invoke "sub" (i64.const 1) (i64.const 0)) (i64.const 1))
+(assert_return (invoke "sub" (i64.const -1) (i64.const -1)) (i64.const 0))
+(assert_return (invoke "sub" (i64.const 0x7fffffffffffffff) (i64.const -1)) (i64.const 0x8000000000000000))
+(assert_return (invoke "sub" (i64.const 0x8000000000000000) (i64.const 1)) (i64.const 0x7fffffffffffffff))
+(assert_return (invoke "sub" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i64.const 0))
+(assert_return (invoke "sub" (i64.const 0x3fffffff) (i64.const -1)) (i64.const 0x40000000))
+
+(assert_return (invoke "mul" (i64.const 1) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "mul" (i64.const 1) (i64.const 0)) (i64.const 0))
+(assert_return (invoke "mul" (i64.const -1) (i64.const -1)) (i64.const 1))
+(assert_return (invoke "mul" (i64.const 0x1000000000000000) (i64.const 4096)) (i64.const 0))
+(assert_return (invoke "mul" (i64.const 0x8000000000000000) (i64.const 0)) (i64.const 0))
+(assert_return (invoke "mul" (i64.const 0x8000000000000000) (i64.const -1)) (i64.const 0x8000000000000000))
+(assert_return (invoke "mul" (i64.const 0x7fffffffffffffff) (i64.const -1)) (i64.const 0x8000000000000001))
+(assert_return (invoke "mul" (i64.const 0x0123456789abcdef) (i64.const 0xfedcba9876543210)) (i64.const 0x2236d88fe5618cf0))
+(assert_return (invoke "mul" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i64.const 1))
+
+(assert_trap (invoke "div_s" (i64.const 1) (i64.const 0)) "integer divide by zero")
+(assert_trap (invoke "div_s" (i64.const 0) (i64.const 0)) "integer divide by zero")
+(assert_trap (invoke "div_s" (i64.const 0x8000000000000000) (i64.const -1)) "integer overflow")
+(assert_trap (invoke "div_s" (i64.const 0x8000000000000000) (i64.const 0)) "integer divide by zero")
+(assert_return (invoke "div_s" (i64.const 1) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "div_s" (i64.const 0) (i64.const 1)) (i64.const 0))
+(assert_return (invoke "div_s" (i64.const 0) (i64.const -1)) (i64.const 0))
+(assert_return (invoke "div_s" (i64.const -1) (i64.const -1)) (i64.const 1))
+(assert_return (invoke "div_s" (i64.const 0x8000000000000000) (i64.const 2)) (i64.const 0xc000000000000000))
+(assert_return (invoke "div_s" (i64.const 0x8000000000000001) (i64.const 1000)) (i64.const 0xffdf3b645a1cac09))
+(assert_return (invoke "div_s" (i64.const 5) (i64.const 2)) (i64.const 2))
+(assert_return (invoke "div_s" (i64.const -5) (i64.const 2)) (i64.const -2))
+(assert_return (invoke "div_s" (i64.const 5) (i64.const -2)) (i64.const -2))
+(assert_return (invoke "div_s" (i64.const -5) (i64.const -2)) (i64.const 2))
+(assert_return (invoke "div_s" (i64.const 7) (i64.const 3)) (i64.const 2))
+(assert_return (invoke "div_s" (i64.const -7) (i64.const 3)) (i64.const -2))
+(assert_return (invoke "div_s" (i64.const 7) (i64.const -3)) (i64.const -2))
+(assert_return (invoke "div_s" (i64.const -7) (i64.const -3)) (i64.const 2))
+(assert_return (invoke "div_s" (i64.const 11) (i64.const 5)) (i64.const 2))
+(assert_return (invoke "div_s" (i64.const 17) (i64.const 7)) (i64.const 2))
+
+(assert_trap (invoke "div_u" (i64.const 1) (i64.const 0)) "integer divide by zero")
+(assert_trap (invoke "div_u" (i64.const 0) (i64.const 0)) "integer divide by zero")
+(assert_return (invoke "div_u" (i64.const 1) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "div_u" (i64.const 0) (i64.const 1)) (i64.const 0))
+(assert_return (invoke "div_u" (i64.const -1) (i64.const -1)) (i64.const 1))
+(assert_return (invoke "div_u" (i64.const 0x8000000000000000) (i64.const -1)) (i64.const 0))
+(assert_return (invoke "div_u" (i64.const 0x8000000000000000) (i64.const 2)) (i64.const 0x4000000000000000))
+(assert_return (invoke "div_u" (i64.const 0x8ff00ff00ff00ff0) (i64.const 0x100000001)) (i64.const 0x8ff00fef))
+(assert_return (invoke "div_u" (i64.const 0x8000000000000001) (i64.const 1000)) (i64.const 0x20c49ba5e353f7))
+(assert_return (invoke "div_u" (i64.const 5) (i64.const 2)) (i64.const 2))
+(assert_return (invoke "div_u" (i64.const -5) (i64.const 2)) (i64.const 0x7ffffffffffffffd))
+(assert_return (invoke "div_u" (i64.const 5) (i64.const -2)) (i64.const 0))
+(assert_return (invoke "div_u" (i64.const -5) (i64.const -2)) (i64.const 0))
+(assert_return (invoke "div_u" (i64.const 7) (i64.const 3)) (i64.const 2))
+(assert_return (invoke "div_u" (i64.const 11) (i64.const 5)) (i64.const 2))
+(assert_return (invoke "div_u" (i64.const 17) (i64.const 7)) (i64.const 2))
+
+(assert_trap (invoke "rem_s" (i64.const 1) (i64.const 0)) "integer divide by zero")
+(assert_trap (invoke "rem_s" (i64.const 0) (i64.const 0)) "integer divide by zero")
+(assert_return (invoke "rem_s" (i64.const 0x7fffffffffffffff) (i64.const -1)) (i64.const 0))
+(assert_return (invoke "rem_s" (i64.const 1) (i64.const 1)) (i64.const 0))
+(assert_return (invoke "rem_s" (i64.const 0) (i64.const 1)) (i64.const 0))
+(assert_return (invoke "rem_s" (i64.const 0) (i64.const -1)) (i64.const 0))
+(assert_return (invoke "rem_s" (i64.const -1) (i64.const -1)) (i64.const 0))
+(assert_return (invoke "rem_s" (i64.const 0x8000000000000000) (i64.const -1)) (i64.const 0))
+(assert_return (invoke "rem_s" (i64.const 0x8000000000000000) (i64.const 2)) (i64.const 0))
+(assert_return (invoke "rem_s" (i64.const 0x8000000000000001) (i64.const 1000)) (i64.const -807))
+(assert_return (invoke "rem_s" (i64.const 5) (i64.const 2)) (i64.const 1))
+(assert_return (invoke "rem_s" (i64.const -5) (i64.const 2)) (i64.const -1))
+(assert_return (invoke "rem_s" (i64.const 5) (i64.const -2)) (i64.const 1))
+(assert_return (invoke "rem_s" (i64.const -5) (i64.const -2)) (i64.const -1))
+(assert_return (invoke "rem_s" (i64.const 7) (i64.const 3)) (i64.const 1))
+(assert_return (invoke "rem_s" (i64.const -7) (i64.const 3)) (i64.const -1))
+(assert_return (invoke "rem_s" (i64.const 7) (i64.const -3)) (i64.const 1))
+(assert_return (invoke "rem_s" (i64.const -7) (i64.const -3)) (i64.const -1))
+(assert_return (invoke "rem_s" (i64.const 11) (i64.const 5)) (i64.const 1))
+(assert_return (invoke "rem_s" (i64.const 17) (i64.const 7)) (i64.const 3))
+
+(assert_trap (invoke "rem_u" (i64.const 1) (i64.const 0)) "integer divide by zero")
+(assert_trap (invoke "rem_u" (i64.const 0) (i64.const 0)) "integer divide by zero")
+(assert_return (invoke "rem_u" (i64.const 1) (i64.const 1)) (i64.const 0))
+(assert_return (invoke "rem_u" (i64.const 0) (i64.const 1)) (i64.const 0))
+(assert_return (invoke "rem_u" (i64.const -1) (i64.const -1)) (i64.const 0))
+(assert_return (invoke "rem_u" (i64.const 0x8000000000000000) (i64.const -1)) (i64.const 0x8000000000000000))
+(assert_return (invoke "rem_u" (i64.const 0x8000000000000000) (i64.const 2)) (i64.const 0))
+(assert_return (invoke "rem_u" (i64.const 0x8ff00ff00ff00ff0) (i64.const 0x100000001)) (i64.const 0x80000001))
+(assert_return (invoke "rem_u" (i64.const 0x8000000000000001) (i64.const 1000)) (i64.const 809))
+(assert_return (invoke "rem_u" (i64.const 5) (i64.const 2)) (i64.const 1))
+(assert_return (invoke "rem_u" (i64.const -5) (i64.const 2)) (i64.const 1))
+(assert_return (invoke "rem_u" (i64.const 5) (i64.const -2)) (i64.const 5))
+(assert_return (invoke "rem_u" (i64.const -5) (i64.const -2)) (i64.const -5))
+(assert_return (invoke "rem_u" (i64.const 7) (i64.const 3)) (i64.const 1))
+(assert_return (invoke "rem_u" (i64.const 11) (i64.const 5)) (i64.const 1))
+(assert_return (invoke "rem_u" (i64.const 17) (i64.const 7)) (i64.const 3))
+
+(assert_return (invoke "and" (i64.const 1) (i64.const 0)) (i64.const 0))
+(assert_return (invoke "and" (i64.const 0) (i64.const 1)) (i64.const 0))
+(assert_return (invoke "and" (i64.const 1) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "and" (i64.const 0) (i64.const 0)) (i64.const 0))
+(assert_return (invoke "and" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i64.const 0))
+(assert_return (invoke "and" (i64.const 0x7fffffffffffffff) (i64.const -1)) (i64.const 0x7fffffffffffffff))
+(assert_return (invoke "and" (i64.const 0xf0f0ffff) (i64.const 0xfffff0f0)) (i64.const 0xf0f0f0f0))
+(assert_return (invoke "and" (i64.const 0xffffffffffffffff) (i64.const 0xffffffffffffffff)) (i64.const 0xffffffffffffffff))
+
+(assert_return (invoke "or" (i64.const 1) (i64.const 0)) (i64.const 1))
+(assert_return (invoke "or" (i64.const 0) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "or" (i64.const 1) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "or" (i64.const 0) (i64.const 0)) (i64.const 0))
+(assert_return (invoke "or" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i64.const -1))
+(assert_return (invoke "or" (i64.const 0x8000000000000000) (i64.const 0)) (i64.const 0x8000000000000000))
+(assert_return (invoke "or" (i64.const 0xf0f0ffff) (i64.const 0xfffff0f0)) (i64.const 0xffffffff))
+(assert_return (invoke "or" (i64.const 0xffffffffffffffff) (i64.const 0xffffffffffffffff)) (i64.const 0xffffffffffffffff))
+
+(assert_return (invoke "xor" (i64.const 1) (i64.const 0)) (i64.const 1))
+(assert_return (invoke "xor" (i64.const 0) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "xor" (i64.const 1) (i64.const 1)) (i64.const 0))
+(assert_return (invoke "xor" (i64.const 0) (i64.const 0)) (i64.const 0))
+(assert_return (invoke "xor" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i64.const -1))
+(assert_return (invoke "xor" (i64.const 0x8000000000000000) (i64.const 0)) (i64.const 0x8000000000000000))
+(assert_return (invoke "xor" (i64.const -1) (i64.const 0x8000000000000000)) (i64.const 0x7fffffffffffffff))
+(assert_return (invoke "xor" (i64.const -1) (i64.const 0x7fffffffffffffff)) (i64.const 0x8000000000000000))
+(assert_return (invoke "xor" (i64.const 0xf0f0ffff) (i64.const 0xfffff0f0)) (i64.const 0x0f0f0f0f))
+(assert_return (invoke "xor" (i64.const 0xffffffffffffffff) (i64.const 0xffffffffffffffff)) (i64.const 0))
+
+(assert_return (invoke "shl" (i64.const 1) (i64.const 1)) (i64.const 2))
+(assert_return (invoke "shl" (i64.const 1) (i64.const 0)) (i64.const 1))
+(assert_return (invoke "shl" (i64.const 0x7fffffffffffffff) (i64.const 1)) (i64.const 0xfffffffffffffffe))
+(assert_return (invoke "shl" (i64.const 0xffffffffffffffff) (i64.const 1)) (i64.const 0xfffffffffffffffe))
+(assert_return (invoke "shl" (i64.const 0x8000000000000000) (i64.const 1)) (i64.const 0))
+(assert_return (invoke "shl" (i64.const 0x4000000000000000) (i64.const 1)) (i64.const 0x8000000000000000))
+(assert_return (invoke "shl" (i64.const 1) (i64.const 63)) (i64.const 0x8000000000000000))
+(assert_return (invoke "shl" (i64.const 1) (i64.const 64)) (i64.const 1))
+(assert_return (invoke "shl" (i64.const 1) (i64.const 65)) (i64.const 2))
+(assert_return (invoke "shl" (i64.const 1) (i64.const -1)) (i64.const 0x8000000000000000))
+(assert_return (invoke "shl" (i64.const 1) (i64.const 0x7fffffffffffffff)) (i64.const 0x8000000000000000))
+
+(assert_return (invoke "shr_s" (i64.const 1) (i64.const 1)) (i64.const 0))
+(assert_return (invoke "shr_s" (i64.const 1) (i64.const 0)) (i64.const 1))
+(assert_return (invoke "shr_s" (i64.const -1) (i64.const 1)) (i64.const -1))
+(assert_return (invoke "shr_s" (i64.const 0x7fffffffffffffff) (i64.const 1)) (i64.const 0x3fffffffffffffff))
+(assert_return (invoke "shr_s" (i64.const 0x8000000000000000) (i64.const 1)) (i64.const 0xc000000000000000))
+(assert_return (invoke "shr_s" (i64.const 0x4000000000000000) (i64.const 1)) (i64.const 0x2000000000000000))
+(assert_return (invoke "shr_s" (i64.const 1) (i64.const 64)) (i64.const 1))
+(assert_return (invoke "shr_s" (i64.const 1) (i64.const 65)) (i64.const 0))
+(assert_return (invoke "shr_s" (i64.const 1) (i64.const -1)) (i64.const 0))
+(assert_return (invoke "shr_s" (i64.const 1) (i64.const 0x7fffffffffffffff)) (i64.const 0))
+(assert_return (invoke "shr_s" (i64.const 1) (i64.const 0x8000000000000000)) (i64.const 1))
+(assert_return (invoke "shr_s" (i64.const 0x8000000000000000) (i64.const 63)) (i64.const -1))
+(assert_return (invoke "shr_s" (i64.const -1) (i64.const 64)) (i64.const -1))
+(assert_return (invoke "shr_s" (i64.const -1) (i64.const 65)) (i64.const -1))
+(assert_return (invoke "shr_s" (i64.const -1) (i64.const -1)) (i64.const -1))
+(assert_return (invoke "shr_s" (i64.const -1) (i64.const 0x7fffffffffffffff)) (i64.const -1))
+(assert_return (invoke "shr_s" (i64.const -1) (i64.const 0x8000000000000000)) (i64.const -1))
+
+(assert_return (invoke "shr_u" (i64.const 1) (i64.const 1)) (i64.const 0))
+(assert_return (invoke "shr_u" (i64.const 1) (i64.const 0)) (i64.const 1))
+(assert_return (invoke "shr_u" (i64.const -1) (i64.const 1)) (i64.const 0x7fffffffffffffff))
+(assert_return (invoke "shr_u" (i64.const 0x7fffffffffffffff) (i64.const 1)) (i64.const 0x3fffffffffffffff))
+(assert_return (invoke "shr_u" (i64.const 0x8000000000000000) (i64.const 1)) (i64.const 0x4000000000000000))
+(assert_return (invoke "shr_u" (i64.const 0x4000000000000000) (i64.const 1)) (i64.const 0x2000000000000000))
+(assert_return (invoke "shr_u" (i64.const 1) (i64.const 64)) (i64.const 1))
+(assert_return (invoke "shr_u" (i64.const 1) (i64.const 65)) (i64.const 0))
+(assert_return (invoke "shr_u" (i64.const 1) (i64.const -1)) (i64.const 0))
+(assert_return (invoke "shr_u" (i64.const 1) (i64.const 0x7fffffffffffffff)) (i64.const 0))
+(assert_return (invoke "shr_u" (i64.const 1) (i64.const 0x8000000000000000)) (i64.const 1))
+(assert_return (invoke "shr_u" (i64.const 0x8000000000000000) (i64.const 63)) (i64.const 1))
+(assert_return (invoke "shr_u" (i64.const -1) (i64.const 64)) (i64.const -1))
+(assert_return (invoke "shr_u" (i64.const -1) (i64.const 65)) (i64.const 0x7fffffffffffffff))
+(assert_return (invoke "shr_u" (i64.const -1) (i64.const -1)) (i64.const 1))
+(assert_return (invoke "shr_u" (i64.const -1) (i64.const 0x7fffffffffffffff)) (i64.const 1))
+(assert_return (invoke "shr_u" (i64.const -1) (i64.const 0x8000000000000000)) (i64.const -1))
+
+(assert_return (invoke "rotl" (i64.const 1) (i64.const 1)) (i64.const 2))
+(assert_return (invoke "rotl" (i64.const 1) (i64.const 0)) (i64.const 1))
+(assert_return (invoke "rotl" (i64.const -1) (i64.const 1)) (i64.const -1))
+(assert_return (invoke "rotl" (i64.const 1) (i64.const 64)) (i64.const 1))
+(assert_return (invoke "rotl" (i64.const 0xabcd987602468ace) (i64.const 1)) (i64.const 0x579b30ec048d159d))
+(assert_return (invoke "rotl" (i64.const 0xfe000000dc000000) (i64.const 4)) (i64.const 0xe000000dc000000f))
+(assert_return (invoke "rotl" (i64.const 0xabcd1234ef567809) (i64.const 53)) (i64.const 0x013579a2469deacf))
+(assert_return (invoke "rotl" (i64.const 0xabd1234ef567809c) (i64.const 63)) (i64.const 0x55e891a77ab3c04e))
+(assert_return (invoke "rotl" (i64.const 0xabcd1234ef567809) (i64.const 0xf5)) (i64.const 0x013579a2469deacf))
+(assert_return (invoke "rotl" (i64.const 0xabcd7294ef567809) (i64.const 0xffffffffffffffed)) (i64.const 0xcf013579ae529dea))
+(assert_return (invoke "rotl" (i64.const 0xabd1234ef567809c) (i64.const 0x800000000000003f)) (i64.const 0x55e891a77ab3c04e))
+(assert_return (invoke "rotl" (i64.const 1) (i64.const 63)) (i64.const 0x8000000000000000))
+(assert_return (invoke "rotl" (i64.const 0x8000000000000000) (i64.const 1)) (i64.const 1))
+
+(assert_return (invoke "rotr" (i64.const 1) (i64.const 1)) (i64.const 0x8000000000000000))
+(assert_return (invoke "rotr" (i64.const 1) (i64.const 0)) (i64.const 1))
+(assert_return (invoke "rotr" (i64.const -1) (i64.const 1)) (i64.const -1))
+(assert_return (invoke "rotr" (i64.const 1) (i64.const 64)) (i64.const 1))
+(assert_return (invoke "rotr" (i64.const 0xabcd987602468ace) (i64.const 1)) (i64.const 0x55e6cc3b01234567))
+(assert_return (invoke "rotr" (i64.const 0xfe000000dc000000) (i64.const 4)) (i64.const 0x0fe000000dc00000))
+(assert_return (invoke "rotr" (i64.const 0xabcd1234ef567809) (i64.const 53)) (i64.const 0x6891a77ab3c04d5e))
+(assert_return (invoke "rotr" (i64.const 0xabd1234ef567809c) (i64.const 63)) (i64.const 0x57a2469deacf0139))
+(assert_return (invoke "rotr" (i64.const 0xabcd1234ef567809) (i64.const 0xf5)) (i64.const 0x6891a77ab3c04d5e))
+(assert_return (invoke "rotr" (i64.const 0xabcd7294ef567809) (i64.const 0xffffffffffffffed)) (i64.const 0x94a77ab3c04d5e6b))
+(assert_return (invoke "rotr" (i64.const 0xabd1234ef567809c) (i64.const 0x800000000000003f)) (i64.const 0x57a2469deacf0139))
+(assert_return (invoke "rotr" (i64.const 1) (i64.const 63)) (i64.const 2))
+(assert_return (invoke "rotr" (i64.const 0x8000000000000000) (i64.const 63)) (i64.const 1))
+
+(assert_return (invoke "clz" (i64.const 0xffffffffffffffff)) (i64.const 0))
+(assert_return (invoke "clz" (i64.const 0)) (i64.const 64))
+(assert_return (invoke "clz" (i64.const 0x00008000)) (i64.const 48))
+(assert_return (invoke "clz" (i64.const 0xff)) (i64.const 56))
+(assert_return (invoke "clz" (i64.const 0x8000000000000000)) (i64.const 0))
+(assert_return (invoke "clz" (i64.const 1)) (i64.const 63))
+(assert_return (invoke "clz" (i64.const 2)) (i64.const 62))
+(assert_return (invoke "clz" (i64.const 0x7fffffffffffffff)) (i64.const 1))
+
+(assert_return (invoke "ctz" (i64.const -1)) (i64.const 0))
+(assert_return (invoke "ctz" (i64.const 0)) (i64.const 64))
+(assert_return (invoke "ctz" (i64.const 0x00008000)) (i64.const 15))
+(assert_return (invoke "ctz" (i64.const 0x00010000)) (i64.const 16))
+(assert_return (invoke "ctz" (i64.const 0x8000000000000000)) (i64.const 63))
+(assert_return (invoke "ctz" (i64.const 0x7fffffffffffffff)) (i64.const 0))
+
+(assert_return (invoke "popcnt" (i64.const -1)) (i64.const 64))
+(assert_return (invoke "popcnt" (i64.const 0)) (i64.const 0))
+(assert_return (invoke "popcnt" (i64.const 0x00008000)) (i64.const 1))
+(assert_return (invoke "popcnt" (i64.const 0x8000800080008000)) (i64.const 4))
+(assert_return (invoke "popcnt" (i64.const 0x7fffffffffffffff)) (i64.const 63))
+(assert_return (invoke "popcnt" (i64.const 0xAAAAAAAA55555555)) (i64.const 32))
+(assert_return (invoke "popcnt" (i64.const 0x99999999AAAAAAAA)) (i64.const 32))
+(assert_return (invoke "popcnt" (i64.const 0xDEADBEEFDEADBEEF)) (i64.const 48))
+
+(assert_return (invoke "eqz" (i64.const 0)) (i32.const 1))
+(assert_return (invoke "eqz" (i64.const 1)) (i32.const 0))
+(assert_return (invoke "eqz" (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "eqz" (i64.const 0x7fffffffffffffff)) (i32.const 0))
+(assert_return (invoke "eqz" (i64.const 0xffffffffffffffff)) (i32.const 0))
+
+(assert_return (invoke "eq" (i64.const 0) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "eq" (i64.const 1) (i64.const 1)) (i32.const 1))
+(assert_return (invoke "eq" (i64.const -1) (i64.const 1)) (i32.const 0))
+(assert_return (invoke "eq" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 1))
+(assert_return (invoke "eq" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 1))
+(assert_return (invoke "eq" (i64.const -1) (i64.const -1)) (i32.const 1))
+(assert_return (invoke "eq" (i64.const 1) (i64.const 0)) (i32.const 0))
+(assert_return (invoke "eq" (i64.const 0) (i64.const 1)) (i32.const 0))
+(assert_return (invoke "eq" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 0))
+(assert_return (invoke "eq" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 0))
+(assert_return (invoke "eq" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "eq" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 0))
+(assert_return (invoke "eq" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 0))
+
+(assert_return (invoke "ne" (i64.const 0) (i64.const 0)) (i32.const 0))
+(assert_return (invoke "ne" (i64.const 1) (i64.const 1)) (i32.const 0))
+(assert_return (invoke "ne" (i64.const -1) (i64.const 1)) (i32.const 1))
+(assert_return (invoke "ne" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "ne" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 0))
+(assert_return (invoke "ne" (i64.const -1) (i64.const -1)) (i32.const 0))
+(assert_return (invoke "ne" (i64.const 1) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "ne" (i64.const 0) (i64.const 1)) (i32.const 1))
+(assert_return (invoke "ne" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "ne" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 1))
+(assert_return (invoke "ne" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 1))
+(assert_return (invoke "ne" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 1))
+(assert_return (invoke "ne" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 1))
+
+(assert_return (invoke "lt_s" (i64.const 0) (i64.const 0)) (i32.const 0))
+(assert_return (invoke "lt_s" (i64.const 1) (i64.const 1)) (i32.const 0))
+(assert_return (invoke "lt_s" (i64.const -1) (i64.const 1)) (i32.const 1))
+(assert_return (invoke "lt_s" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "lt_s" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 0))
+(assert_return (invoke "lt_s" (i64.const -1) (i64.const -1)) (i32.const 0))
+(assert_return (invoke "lt_s" (i64.const 1) (i64.const 0)) (i32.const 0))
+(assert_return (invoke "lt_s" (i64.const 0) (i64.const 1)) (i32.const 1))
+(assert_return (invoke "lt_s" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "lt_s" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "lt_s" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 1))
+(assert_return (invoke "lt_s" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "lt_s" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 1))
+(assert_return (invoke "lt_s" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 0))
+
+(assert_return (invoke "lt_u" (i64.const 0) (i64.const 0)) (i32.const 0))
+(assert_return (invoke "lt_u" (i64.const 1) (i64.const 1)) (i32.const 0))
+(assert_return (invoke "lt_u" (i64.const -1) (i64.const 1)) (i32.const 0))
+(assert_return (invoke "lt_u" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "lt_u" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 0))
+(assert_return (invoke "lt_u" (i64.const -1) (i64.const -1)) (i32.const 0))
+(assert_return (invoke "lt_u" (i64.const 1) (i64.const 0)) (i32.const 0))
+(assert_return (invoke "lt_u" (i64.const 0) (i64.const 1)) (i32.const 1))
+(assert_return (invoke "lt_u" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 0))
+(assert_return (invoke "lt_u" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 1))
+(assert_return (invoke "lt_u" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 1))
+(assert_return (invoke "lt_u" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "lt_u" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 0))
+(assert_return (invoke "lt_u" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 1))
+
+(assert_return (invoke "le_s" (i64.const 0) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "le_s" (i64.const 1) (i64.const 1)) (i32.const 1))
+(assert_return (invoke "le_s" (i64.const -1) (i64.const 1)) (i32.const 1))
+(assert_return (invoke "le_s" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 1))
+(assert_return (invoke "le_s" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 1))
+(assert_return (invoke "le_s" (i64.const -1) (i64.const -1)) (i32.const 1))
+(assert_return (invoke "le_s" (i64.const 1) (i64.const 0)) (i32.const 0))
+(assert_return (invoke "le_s" (i64.const 0) (i64.const 1)) (i32.const 1))
+(assert_return (invoke "le_s" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "le_s" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "le_s" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 1))
+(assert_return (invoke "le_s" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "le_s" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 1))
+(assert_return (invoke "le_s" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 0))
+
+(assert_return (invoke "le_u" (i64.const 0) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "le_u" (i64.const 1) (i64.const 1)) (i32.const 1))
+(assert_return (invoke "le_u" (i64.const -1) (i64.const 1)) (i32.const 0))
+(assert_return (invoke "le_u" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 1))
+(assert_return (invoke "le_u" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 1))
+(assert_return (invoke "le_u" (i64.const -1) (i64.const -1)) (i32.const 1))
+(assert_return (invoke "le_u" (i64.const 1) (i64.const 0)) (i32.const 0))
+(assert_return (invoke "le_u" (i64.const 0) (i64.const 1)) (i32.const 1))
+(assert_return (invoke "le_u" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 0))
+(assert_return (invoke "le_u" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 1))
+(assert_return (invoke "le_u" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 1))
+(assert_return (invoke "le_u" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "le_u" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 0))
+(assert_return (invoke "le_u" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 1))
+
+(assert_return (invoke "gt_s" (i64.const 0) (i64.const 0)) (i32.const 0))
+(assert_return (invoke "gt_s" (i64.const 1) (i64.const 1)) (i32.const 0))
+(assert_return (invoke "gt_s" (i64.const -1) (i64.const 1)) (i32.const 0))
+(assert_return (invoke "gt_s" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "gt_s" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 0))
+(assert_return (invoke "gt_s" (i64.const -1) (i64.const -1)) (i32.const 0))
+(assert_return (invoke "gt_s" (i64.const 1) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "gt_s" (i64.const 0) (i64.const 1)) (i32.const 0))
+(assert_return (invoke "gt_s" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 0))
+(assert_return (invoke "gt_s" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 1))
+(assert_return (invoke "gt_s" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 0))
+(assert_return (invoke "gt_s" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 1))
+(assert_return (invoke "gt_s" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 0))
+(assert_return (invoke "gt_s" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 1))
+
+(assert_return (invoke "gt_u" (i64.const 0) (i64.const 0)) (i32.const 0))
+(assert_return (invoke "gt_u" (i64.const 1) (i64.const 1)) (i32.const 0))
+(assert_return (invoke "gt_u" (i64.const -1) (i64.const 1)) (i32.const 1))
+(assert_return (invoke "gt_u" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "gt_u" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 0))
+(assert_return (invoke "gt_u" (i64.const -1) (i64.const -1)) (i32.const 0))
+(assert_return (invoke "gt_u" (i64.const 1) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "gt_u" (i64.const 0) (i64.const 1)) (i32.const 0))
+(assert_return (invoke "gt_u" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "gt_u" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "gt_u" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 0))
+(assert_return (invoke "gt_u" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 1))
+(assert_return (invoke "gt_u" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 1))
+(assert_return (invoke "gt_u" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 0))
+
+(assert_return (invoke "ge_s" (i64.const 0) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "ge_s" (i64.const 1) (i64.const 1)) (i32.const 1))
+(assert_return (invoke "ge_s" (i64.const -1) (i64.const 1)) (i32.const 0))
+(assert_return (invoke "ge_s" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 1))
+(assert_return (invoke "ge_s" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 1))
+(assert_return (invoke "ge_s" (i64.const -1) (i64.const -1)) (i32.const 1))
+(assert_return (invoke "ge_s" (i64.const 1) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "ge_s" (i64.const 0) (i64.const 1)) (i32.const 0))
+(assert_return (invoke "ge_s" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 0))
+(assert_return (invoke "ge_s" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 1))
+(assert_return (invoke "ge_s" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 0))
+(assert_return (invoke "ge_s" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 1))
+(assert_return (invoke "ge_s" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 0))
+(assert_return (invoke "ge_s" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 1))
+
+(assert_return (invoke "ge_u" (i64.const 0) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "ge_u" (i64.const 1) (i64.const 1)) (i32.const 1))
+(assert_return (invoke "ge_u" (i64.const -1) (i64.const 1)) (i32.const 1))
+(assert_return (invoke "ge_u" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 1))
+(assert_return (invoke "ge_u" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 1))
+(assert_return (invoke "ge_u" (i64.const -1) (i64.const -1)) (i32.const 1))
+(assert_return (invoke "ge_u" (i64.const 1) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "ge_u" (i64.const 0) (i64.const 1)) (i32.const 0))
+(assert_return (invoke "ge_u" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "ge_u" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 0))
+(assert_return (invoke "ge_u" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 0))
+(assert_return (invoke "ge_u" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 1))
+(assert_return (invoke "ge_u" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 1))
+(assert_return (invoke "ge_u" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 0))
+
+
+;; Type check
+
+(assert_invalid (module (func (result i64) (i64.add (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.and (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.div_s (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.div_u (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.mul (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.or (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.rem_s (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.rem_u (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.rotl (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.rotr (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.shl (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.shr_s (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.shr_u (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.sub (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.xor (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.eqz (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.clz (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.ctz (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.popcnt (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.eq (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.ge_s (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.ge_u (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.gt_s (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.gt_u (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.le_s (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.le_u (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.lt_s (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.lt_u (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (result i64) (i64.ne (i32.const 0) (f32.const 0)))) "type mismatch")
diff --git a/binaryen/test/spec/if.wast b/binaryen/test/spec/if.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/if.wast
@@ -0,0 +1,933 @@
+;; Test `if` operator
+
+(module
+  ;; Auxiliary definition
+  (memory 1)
+
+  (func $dummy)
+
+  (func (export "empty") (param i32)
+    (if (local.get 0) (then))
+    (if (local.get 0) (then) (else))
+    (if $l (local.get 0) (then))
+    (if $l (local.get 0) (then) (else))
+  )
+
+  (func (export "singular") (param i32) (result i32)
+    (if (local.get 0) (then (nop)))
+    (if (local.get 0) (then (nop)) (else (nop)))
+    (if (result i32) (local.get 0) (then (i32.const 7)) (else (i32.const 8)))
+  )
+
+  (func (export "multi") (param i32) (result i32)
+    (if (local.get 0) (then (call $dummy) (call $dummy) (call $dummy)))
+    (if (local.get 0) (then) (else (call $dummy) (call $dummy) (call $dummy)))
+    (if (result i32) (local.get 0)
+      (then (call $dummy) (call $dummy) (i32.const 8))
+      (else (call $dummy) (call $dummy) (i32.const 9))
+    )
+  )
+
+  (func (export "nested") (param i32 i32) (result i32)
+    (if (result i32) (local.get 0)
+      (then
+        (if (local.get 1) (then (call $dummy) (block) (nop)))
+        (if (local.get 1) (then) (else (call $dummy) (block) (nop)))
+        (if (result i32) (local.get 1)
+          (then (call $dummy) (i32.const 9))
+          (else (call $dummy) (i32.const 10))
+        )
+      )
+      (else
+        (if (local.get 1) (then (call $dummy) (block) (nop)))
+        (if (local.get 1) (then) (else (call $dummy) (block) (nop)))
+        (if (result i32) (local.get 1)
+          (then (call $dummy) (i32.const 10))
+          (else (call $dummy) (i32.const 11))
+        )
+      )
+    )
+  )
+
+  (func (export "as-select-first") (param i32) (result i32)
+    (select
+      (if (result i32) (local.get 0)
+        (then (call $dummy) (i32.const 1))
+        (else (call $dummy) (i32.const 0))
+      )
+      (i32.const 2) (i32.const 3)
+    )
+  )
+  (func (export "as-select-mid") (param i32) (result i32)
+    (select
+      (i32.const 2)
+      (if (result i32) (local.get 0)
+        (then (call $dummy) (i32.const 1))
+        (else (call $dummy) (i32.const 0))
+      )
+      (i32.const 3)
+    )
+  )
+  (func (export "as-select-last") (param i32) (result i32)
+    (select
+      (i32.const 2) (i32.const 3)
+      (if (result i32) (local.get 0)
+        (then (call $dummy) (i32.const 1))
+        (else (call $dummy) (i32.const 0))
+      )
+    )
+  )
+
+  (func (export "as-loop-first") (param i32) (result i32)
+    (loop (result i32)
+      (if (result i32) (local.get 0)
+        (then (call $dummy) (i32.const 1))
+        (else (call $dummy) (i32.const 0))
+      )
+      (call $dummy) (call $dummy)
+    )
+  )
+  (func (export "as-loop-mid") (param i32) (result i32)
+    (loop (result i32)
+      (call $dummy)
+      (if (result i32) (local.get 0)
+        (then (call $dummy) (i32.const 1))
+        (else (call $dummy) (i32.const 0))
+      )
+      (call $dummy)
+    )
+  )
+  (func (export "as-loop-last") (param i32) (result i32)
+    (loop (result i32)
+      (call $dummy) (call $dummy)
+      (if (result i32) (local.get 0)
+        (then (call $dummy) (i32.const 1))
+        (else (call $dummy) (i32.const 0))
+      )
+    )
+  )
+
+  (func (export "as-if-condition") (param i32) (result i32)
+    (if (result i32)
+      (if (result i32) (local.get 0)
+        (then (i32.const 1)) (else (i32.const 0))
+      )
+      (then (call $dummy) (i32.const 2))
+      (else (call $dummy) (i32.const 3))
+    )
+  )
+
+  (func (export "as-br_if-first") (param i32) (result i32)
+    (block (result i32)
+      (br_if 0
+        (if (result i32) (local.get 0)
+          (then (call $dummy) (i32.const 1))
+          (else (call $dummy) (i32.const 0))
+        )
+        (i32.const 2)
+      )
+      (return (i32.const 3))
+    )
+  )
+  (func (export "as-br_if-last") (param i32) (result i32)
+    (block (result i32)
+      (br_if 0
+        (i32.const 2)
+        (if (result i32) (local.get 0)
+          (then (call $dummy) (i32.const 1))
+          (else (call $dummy) (i32.const 0))
+        )
+      )
+      (return (i32.const 3))
+    )
+  )
+
+  (func (export "as-br_table-first") (param i32) (result i32)
+    (block (result i32)
+      (if (result i32) (local.get 0)
+        (then (call $dummy) (i32.const 1))
+        (else (call $dummy) (i32.const 0))
+      )
+      (i32.const 2)
+      (br_table 0 0)
+    )
+  )
+  (func (export "as-br_table-last") (param i32) (result i32)
+    (block (result i32)
+      (i32.const 2)
+      (if (result i32) (local.get 0)
+        (then (call $dummy) (i32.const 1))
+        (else (call $dummy) (i32.const 0))
+      )
+      (br_table 0 0)
+    )
+  )
+
+  (func $func (param i32 i32) (result i32) (local.get 0))
+  (type $check (func (param i32 i32) (result i32)))
+  (table funcref (elem $func))
+  (func (export "as-call_indirect-first") (param i32) (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (if (result i32) (local.get 0)
+          (then (call $dummy) (i32.const 1))
+          (else (call $dummy) (i32.const 0))
+        )
+        (i32.const 2) (i32.const 0)
+      )
+    )
+  )
+  (func (export "as-call_indirect-mid") (param i32) (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (i32.const 2)
+        (if (result i32) (local.get 0)
+          (then (call $dummy) (i32.const 1))
+          (else (call $dummy) (i32.const 0))
+        )
+        (i32.const 0)
+      )
+    )
+  )
+  (func (export "as-call_indirect-last") (param i32) (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (i32.const 2) (i32.const 0)
+        (if (result i32) (local.get 0)
+          (then (call $dummy) (i32.const 1))
+          (else (call $dummy) (i32.const 0))
+        )
+      )
+    )
+  )
+
+  (func (export "as-store-first") (param i32)
+    (if (result i32) (local.get 0)
+      (then (call $dummy) (i32.const 1))
+      (else (call $dummy) (i32.const 0))
+    )
+    (i32.const 2)
+    (i32.store)
+  )
+  (func (export "as-store-last") (param i32)
+    (i32.const 2)
+    (if (result i32) (local.get 0)
+      (then (call $dummy) (i32.const 1))
+      (else (call $dummy) (i32.const 0))
+    )
+    (i32.store)
+  )
+
+  (func (export "as-memory.grow-value") (param i32) (result i32)
+    (memory.grow
+      (if (result i32) (local.get 0)
+        (then (i32.const 1))
+        (else (i32.const 0))
+      )
+    )
+  )
+
+  (func $f (param i32) (result i32) (local.get 0))
+
+  (func (export "as-call-value") (param i32) (result i32)
+    (call $f
+      (if (result i32) (local.get 0)
+        (then (i32.const 1))
+        (else (i32.const 0))
+      )
+    )
+  )
+  (func (export "as-return-value") (param i32) (result i32)
+    (if (result i32) (local.get 0)
+      (then (i32.const 1))
+      (else (i32.const 0)))
+    (return)
+  )
+  (func (export "as-drop-operand") (param i32)
+    (drop
+      (if (result i32) (local.get 0)
+        (then (i32.const 1))
+        (else (i32.const 0))
+      )
+    )
+  )
+  (func (export "as-br-value") (param i32) (result i32)
+    (block (result i32)
+      (br 0
+        (if (result i32) (local.get 0)
+          (then (i32.const 1))
+          (else (i32.const 0))
+        )
+      )
+    )
+  )
+  (func (export "as-local.set-value") (param i32) (result i32)
+    (local i32)
+    (local.set 0
+      (if (result i32) (local.get 0)
+        (then (i32.const 1))
+        (else (i32.const 0))
+      )
+    )
+    (local.get 0)
+  )
+  (func (export "as-local.tee-value") (param i32) (result i32)
+    (local.tee 0
+      (if (result i32) (local.get 0)
+        (then (i32.const 1))
+        (else (i32.const 0))
+      )
+    )
+  )
+  (global $a (mut i32) (i32.const 10))
+  (func (export "as-global.set-value") (param i32) (result i32)
+    (global.set $a
+      (if (result i32) (local.get 0)
+        (then (i32.const 1))
+        (else (i32.const 0))
+      )
+    ) (global.get $a)
+  )
+  (func (export "as-load-operand") (param i32) (result i32)
+    (i32.load
+      (if (result i32) (local.get 0)
+        (then (i32.const 11))
+        (else (i32.const 10))
+      )
+    )
+  )
+
+  (func (export "as-unary-operand") (param i32) (result i32)
+    (i32.ctz
+      (if (result i32) (local.get 0)
+        (then (call $dummy) (i32.const 13))
+        (else (call $dummy) (i32.const -13))
+      )
+    )
+  )
+  (func (export "as-binary-operand") (param i32 i32) (result i32)
+    (i32.mul
+      (if (result i32) (local.get 0)
+        (then (call $dummy) (i32.const 3))
+        (else (call $dummy) (i32.const -3))
+      )
+      (if (result i32) (local.get 1)
+        (then (call $dummy) (i32.const 4))
+        (else (call $dummy) (i32.const -5))
+      )
+    )
+  )
+  (func (export "as-test-operand") (param i32) (result i32)
+    (i32.eqz
+      (if (result i32) (local.get 0)
+        (then (call $dummy) (i32.const 13))
+        (else (call $dummy) (i32.const 0))
+      )
+    )
+  )
+  (func (export "as-compare-operand") (param i32 i32) (result i32)
+    (f32.gt
+      (if (result f32) (local.get 0)
+        (then (call $dummy) (f32.const 3))
+        (else (call $dummy) (f32.const -3))
+      )
+      (if (result f32) (local.get 1)
+        (then (call $dummy) (f32.const 4))
+        (else (call $dummy) (f32.const -4))
+      )
+    )
+  )
+
+  (func (export "break-bare") (result i32)
+    (if (i32.const 1) (then (br 0) (unreachable)))
+    (if (i32.const 1) (then (br 0) (unreachable)) (else (unreachable)))
+    (if (i32.const 0) (then (unreachable)) (else (br 0) (unreachable)))
+    (if (i32.const 1) (then (br_if 0 (i32.const 1)) (unreachable)))
+    (if (i32.const 1) (then (br_if 0 (i32.const 1)) (unreachable)) (else (unreachable)))
+    (if (i32.const 0) (then (unreachable)) (else (br_if 0 (i32.const 1)) (unreachable)))
+    (if (i32.const 1) (then (br_table 0 (i32.const 0)) (unreachable)))
+    (if (i32.const 1) (then (br_table 0 (i32.const 0)) (unreachable)) (else (unreachable)))
+    (if (i32.const 0) (then (unreachable)) (else (br_table 0 (i32.const 0)) (unreachable)))
+    (i32.const 19)
+  )
+
+  (func (export "break-value") (param i32) (result i32)
+    (if (result i32) (local.get 0)
+      (then (br 0 (i32.const 18)) (i32.const 19))
+      (else (br 0 (i32.const 21)) (i32.const 20))
+    )
+  )
+
+  (func (export "effects") (param i32) (result i32)
+    (local i32)
+    (if
+      (block (result i32) (local.set 1 (i32.const 1)) (local.get 0))
+      (then
+        (local.set 1 (i32.mul (local.get 1) (i32.const 3)))
+        (local.set 1 (i32.sub (local.get 1) (i32.const 5)))
+        (local.set 1 (i32.mul (local.get 1) (i32.const 7)))
+        (br 0)
+        (local.set 1 (i32.mul (local.get 1) (i32.const 100)))
+      )
+      (else
+        (local.set 1 (i32.mul (local.get 1) (i32.const 5)))
+        (local.set 1 (i32.sub (local.get 1) (i32.const 7)))
+        (local.set 1 (i32.mul (local.get 1) (i32.const 3)))
+        (br 0)
+        (local.set 1 (i32.mul (local.get 1) (i32.const 1000)))
+      )
+    )
+    (local.get 1)
+  )
+)
+
+(assert_return (invoke "empty" (i32.const 0)))
+(assert_return (invoke "empty" (i32.const 1)))
+(assert_return (invoke "empty" (i32.const 100)))
+(assert_return (invoke "empty" (i32.const -2)))
+
+(assert_return (invoke "singular" (i32.const 0)) (i32.const 8))
+(assert_return (invoke "singular" (i32.const 1)) (i32.const 7))
+(assert_return (invoke "singular" (i32.const 10)) (i32.const 7))
+(assert_return (invoke "singular" (i32.const -10)) (i32.const 7))
+
+(assert_return (invoke "multi" (i32.const 0)) (i32.const 9))
+(assert_return (invoke "multi" (i32.const 1)) (i32.const 8))
+(assert_return (invoke "multi" (i32.const 13)) (i32.const 8))
+(assert_return (invoke "multi" (i32.const -5)) (i32.const 8))
+
+(assert_return (invoke "nested" (i32.const 0) (i32.const 0)) (i32.const 11))
+(assert_return (invoke "nested" (i32.const 1) (i32.const 0)) (i32.const 10))
+(assert_return (invoke "nested" (i32.const 0) (i32.const 1)) (i32.const 10))
+(assert_return (invoke "nested" (i32.const 3) (i32.const 2)) (i32.const 9))
+(assert_return (invoke "nested" (i32.const 0) (i32.const -100)) (i32.const 10))
+(assert_return (invoke "nested" (i32.const 10) (i32.const 10)) (i32.const 9))
+(assert_return (invoke "nested" (i32.const 0) (i32.const -1)) (i32.const 10))
+(assert_return (invoke "nested" (i32.const -111) (i32.const -2)) (i32.const 9))
+
+(assert_return (invoke "as-select-first" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-select-first" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-select-mid" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-select-mid" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "as-select-last" (i32.const 0)) (i32.const 3))
+(assert_return (invoke "as-select-last" (i32.const 1)) (i32.const 2))
+
+(assert_return (invoke "as-loop-first" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-loop-first" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-loop-mid" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-loop-mid" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-loop-last" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-loop-last" (i32.const 1)) (i32.const 1))
+
+(assert_return (invoke "as-if-condition" (i32.const 0)) (i32.const 3))
+(assert_return (invoke "as-if-condition" (i32.const 1)) (i32.const 2))
+
+(assert_return (invoke "as-br_if-first" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-br_if-first" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-br_if-last" (i32.const 0)) (i32.const 3))
+(assert_return (invoke "as-br_if-last" (i32.const 1)) (i32.const 2))
+
+(assert_return (invoke "as-br_table-first" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-br_table-first" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-br_table-last" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-br_table-last" (i32.const 1)) (i32.const 2))
+
+(assert_return (invoke "as-call_indirect-first" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-call_indirect-first" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-call_indirect-mid" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-call_indirect-mid" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "as-call_indirect-last" (i32.const 0)) (i32.const 2))
+(assert_trap (invoke "as-call_indirect-last" (i32.const 1)) "undefined element")
+
+(assert_return (invoke "as-store-first" (i32.const 0)))
+(assert_return (invoke "as-store-first" (i32.const 1)))
+(assert_return (invoke "as-store-last" (i32.const 0)))
+(assert_return (invoke "as-store-last" (i32.const 1)))
+
+(assert_return (invoke "as-memory.grow-value" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-memory.grow-value" (i32.const 1)) (i32.const 1))
+
+(assert_return (invoke "as-call-value" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-call-value" (i32.const 1)) (i32.const 1))
+
+(assert_return (invoke "as-return-value" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-return-value" (i32.const 1)) (i32.const 1))
+
+(assert_return (invoke "as-drop-operand" (i32.const 0)))
+(assert_return (invoke "as-drop-operand" (i32.const 1)))
+
+(assert_return (invoke "as-br-value" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-br-value" (i32.const 1)) (i32.const 1))
+
+(assert_return (invoke "as-local.set-value" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-local.set-value" (i32.const 1)) (i32.const 1))
+
+(assert_return (invoke "as-local.tee-value" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-local.tee-value" (i32.const 1)) (i32.const 1))
+
+(assert_return (invoke "as-global.set-value" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-global.set-value" (i32.const 1)) (i32.const 1))
+
+(assert_return (invoke "as-load-operand" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-load-operand" (i32.const 1)) (i32.const 0))
+
+(assert_return (invoke "as-unary-operand" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-unary-operand" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "as-unary-operand" (i32.const -1)) (i32.const 0))
+
+(assert_return (invoke "as-binary-operand" (i32.const 0) (i32.const 0)) (i32.const 15))
+(assert_return (invoke "as-binary-operand" (i32.const 0) (i32.const 1)) (i32.const -12))
+(assert_return (invoke "as-binary-operand" (i32.const 1) (i32.const 0)) (i32.const -15))
+(assert_return (invoke "as-binary-operand" (i32.const 1) (i32.const 1)) (i32.const 12))
+
+(assert_return (invoke "as-test-operand" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-test-operand" (i32.const 1)) (i32.const 0))
+
+(assert_return (invoke "as-compare-operand" (i32.const 0) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-compare-operand" (i32.const 0) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "as-compare-operand" (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-compare-operand" (i32.const 1) (i32.const 1)) (i32.const 0))
+
+(assert_return (invoke "break-bare") (i32.const 19))
+(assert_return (invoke "break-value" (i32.const 1)) (i32.const 18))
+(assert_return (invoke "break-value" (i32.const 0)) (i32.const 21))
+
+(assert_return (invoke "effects" (i32.const 1)) (i32.const -14))
+(assert_return (invoke "effects" (i32.const 0)) (i32.const -6))
+
+(assert_invalid
+  (module (func $type-empty-i32 (result i32) (if (i32.const 0) (then))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-i64 (result i64) (if (i32.const 0) (then))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f32 (result f32) (if (i32.const 0) (then))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f64 (result f64) (if (i32.const 0) (then))))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-empty-i32 (result i32) (if (i32.const 0) (then) (else))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-i64 (result i64) (if (i32.const 0) (then) (else))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f32 (result f32) (if (i32.const 0) (then) (else))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f64 (result f64) (if (i32.const 0) (then) (else))))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-then-value-num-vs-void
+    (if (i32.const 1) (then (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-then-value-num-vs-void
+    (if (i32.const 1) (then (i32.const 1)) (else))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-else-value-num-vs-void
+    (if (i32.const 1) (then) (else (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-both-value-num-vs-void
+    (if (i32.const 1) (then (i32.const 1)) (else (i32.const 1)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-then-value-empty-vs-num (result i32)
+    (if (result i32) (i32.const 1) (then) (else (i32.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-then-value-empty-vs-num (result i32)
+    (if (result i32) (i32.const 1) (then (i32.const 0)) (else))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-both-value-empty-vs-num (result i32)
+    (if (result i32) (i32.const 1) (then) (else))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-no-else-vs-num (result i32)
+    (if (result i32) (i32.const 1) (then (i32.const 1)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-then-value-void-vs-num (result i32)
+    (if (result i32) (i32.const 1) (then (nop)) (else (i32.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-then-value-void-vs-num (result i32)
+    (if (result i32) (i32.const 1) (then (i32.const 0)) (else (nop)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-both-value-void-vs-num (result i32)
+    (if (result i32) (i32.const 1) (then (nop)) (else (nop)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-then-value-num-vs-num (result i32)
+    (if (result i32) (i32.const 1) (then (i64.const 1)) (else (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-then-value-num-vs-num (result i32)
+    (if (result i32) (i32.const 1) (then (i32.const 1)) (else (i64.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-both-value-num-vs-num (result i32)
+    (if (result i32) (i32.const 1) (then (i64.const 1)) (else (i64.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-both-different-value-num-vs-num (result i32)
+    (if (result i32) (i32.const 1) (then (i64.const 1)) (else (f64.const 1)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-then-value-unreached-select (result i32)
+    (if (result i64)
+      (i32.const 0)
+      (then (select (unreachable) (unreachable) (unreachable)))
+      (else (i64.const 0))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-else-value-unreached-select (result i32)
+    (if (result i64)
+      (i32.const 1)
+      (then (i64.const 0))
+      (else (select (unreachable) (unreachable) (unreachable)))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-else-value-unreached-select (result i32)
+    (if (result i64)
+      (i32.const 1)
+      (then (select (unreachable) (unreachable) (unreachable)))
+      (else (select (unreachable) (unreachable) (unreachable)))
+    )
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-then-break-last-void-vs-num (result i32)
+    (if (result i32) (i32.const 1) (then (br 0)) (else (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-else-break-last-void-vs-num (result i32)
+    (if (result i32) (i32.const 1) (then (i32.const 1)) (else (br 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-then-break-empty-vs-num (result i32)
+    (if (result i32) (i32.const 1)
+      (then (br 0) (i32.const 1))
+      (else (i32.const 1))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-else-break-empty-vs-num (result i32)
+    (if (result i32) (i32.const 1)
+      (then (i32.const 1))
+      (else (br 0) (i32.const 1))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-then-break-void-vs-num (result i32)
+    (if (result i32) (i32.const 1)
+      (then (br 0 (nop)) (i32.const 1))
+      (else (i32.const 1))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-else-break-void-vs-num (result i32)
+    (if (result i32) (i32.const 1)
+      (then (i32.const 1))
+      (else (br 0 (nop)) (i32.const 1))
+    )
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-then-break-num-vs-num (result i32)
+    (if (result i32) (i32.const 1)
+      (then (br 0 (i64.const 1)) (i32.const 1))
+      (else (i32.const 1))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-else-break-num-vs-num (result i32)
+    (if (result i32) (i32.const 1)
+      (then (i32.const 1))
+      (else (br 0 (i64.const 1)) (i32.const 1))
+    )
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (func $type-condition-empty
+      (if (then))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-condition-empty-in-block
+      (i32.const 0)
+      (block (if (then)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-condition-empty-in-loop
+      (i32.const 0)
+      (loop (if (then)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-condition-empty-in-then
+      (i32.const 0) (i32.const 0)
+      (if (then (if (then))))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-condition-empty-in-else
+      (i32.const 0) (i32.const 0)
+      (if (result i32) (then (i32.const 0)) (else (if (then)) (i32.const 0)))
+      (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-condition-empty-in-br
+      (i32.const 0)
+      (block (br 0 (if(then))) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-condition-empty-in-br_if
+      (i32.const 0)
+      (block (br_if 0 (if(then)) (i32.const 1)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-condition-empty-in-br_table
+      (i32.const 0)
+      (block (br_table 0 (if(then))) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-condition-empty-in-return
+      (return (if(then))) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-condition-empty-in-select
+      (select (if(then)) (i32.const 1) (i32.const 2)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-condition-empty-in-call
+      (call 1 (if(then))) (drop)
+    )
+    (func (param i32) (result i32) (local.get 0))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $f (param i32) (result i32) (local.get 0))
+    (type $sig (func (param i32) (result i32)))
+    (table funcref (elem $f))
+    (func $type-condition-empty-in-call_indirect
+      (block (result i32)
+        (call_indirect (type $sig)
+          (if(then)) (i32.const 0)
+        )
+        (drop)
+      )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-condition-empty-in-local.set
+      (local i32)
+      (local.set 0 (if(then))) (local.get 0) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-condition-empty-in-local.tee
+      (local i32)
+      (local.tee 0 (if(then))) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-condition-empty-in-global.set
+      (global.set $x (if(then))) (global.get $x) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-condition-empty-in-memory.grow
+      (memory.grow (if(then))) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-condition-empty-in-load
+      (i32.load (if(then))) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-condition-empty-in-store
+      (i32.store (if(then)) (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
+
+
+(assert_malformed
+  (module quote "(func i32.const 0 if end $l)")
+  "mismatching label"
+)
+(assert_malformed
+  (module quote "(func i32.const 0 if $a end $l)")
+  "mismatching label"
+)
+(assert_malformed
+  (module quote "(func i32.const 0 if else $l end)")
+  "mismatching label"
+)
+(assert_malformed
+  (module quote "(func i32.const 0 if $a else $l end)")
+  "mismatching label"
+)
+(assert_malformed
+  (module quote "(func i32.const 0 if else end $l)")
+  "mismatching label"
+)
+(assert_malformed
+  (module quote "(func i32.const 0 if else $l end $l)")
+  "mismatching label"
+)
+(assert_malformed
+  (module quote "(func i32.const 0 if else $l1 end $l2)")
+  "mismatching label"
+)
+(assert_malformed
+  (module quote "(func i32.const 0 if $a else end $l)")
+  "mismatching label"
+)
+(assert_malformed
+  (module quote "(func i32.const 0 if $a else $a end $l)")
+  "mismatching label"
+)
+(assert_malformed
+  (module quote "(func i32.const 0 if $a else $l end $l)")
+  "mismatching label"
+)
diff --git a/binaryen/test/spec/import-after-func.fail.wast b/binaryen/test/spec/import-after-func.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/import-after-func.fail.wast
@@ -0,0 +1,1 @@
+(module (func) (import "" "" (memory 0)))
diff --git a/binaryen/test/spec/import-after-global.fail.wast b/binaryen/test/spec/import-after-global.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/import-after-global.fail.wast
@@ -0,0 +1,1 @@
+(module (global i64) (import "" "" (table 0 funcref)))
diff --git a/binaryen/test/spec/import-after-memory.fail.wast b/binaryen/test/spec/import-after-memory.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/import-after-memory.fail.wast
@@ -0,0 +1,1 @@
+(module (memory 0) (import "" "" (global i32)))
diff --git a/binaryen/test/spec/import-after-table.fail.wast b/binaryen/test/spec/import-after-table.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/import-after-table.fail.wast
@@ -0,0 +1,1 @@
+(module (table 0 funcref) (import "" "" (func)))
diff --git a/binaryen/test/spec/imports.wast b/binaryen/test/spec/imports.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/imports.wast
@@ -0,0 +1,593 @@
+;; Auxiliary module to import from
+
+(module
+  (func (export "func"))
+  (func (export "func-i32") (param i32))
+  (func (export "func-f32") (param f32))
+  (func (export "func->i32") (result i32) (i32.const 22))
+  (func (export "func->f32") (result f32) (f32.const 11))
+  (func (export "func-i32->i32") (param i32) (result i32) (local.get 0))
+  (func (export "func-i64->i64") (param i64) (result i64) (local.get 0))
+  (global (export "global-i32") i32 (i32.const 55))
+  (global (export "global-f32") f32 (f32.const 44))
+  (table (export "table-10-inf") 10 funcref)
+  ;; (table (export "table-10-20") 10 20 funcref)
+  (memory (export "memory-2-inf") 2)
+  ;; (memory (export "memory-2-4") 2 4)
+)
+
+(register "test")
+
+
+;; Functions
+
+(module
+  (type $func_i32 (func (param i32)))
+  (type $func_i64 (func (param i64)))
+  (type $func_f32 (func (param f32)))
+  (type $func_f64 (func (param f64)))
+
+  (import "spectest" "print_i32" (func (param i32)))
+  ;; JavaScript can't handle i64 yet.
+  ;; (func (import "spectest" "print_i64") (param i64))
+  (import "spectest" "print_i32" (func $print_i32 (param i32)))
+  ;; JavaScript can't handle i64 yet.
+  ;; (import "spectest" "print_i64" (func $print_i64 (param i64)))
+  (import "spectest" "print_f32" (func $print_f32 (param f32)))
+  (import "spectest" "print_f64" (func $print_f64 (param f64)))
+  (import "spectest" "print_i32_f32" (func $print_i32_f32 (param i32 f32)))
+  (import "spectest" "print_f64_f64" (func $print_f64_f64 (param f64 f64)))
+  (func $print_i32-2 (import "spectest" "print_i32") (param i32))
+  (func $print_f64-2 (import "spectest" "print_f64") (param f64))
+  (import "test" "func-i64->i64" (func $i64->i64 (param i64) (result i64)))
+
+  (func (export "p1") (import "spectest" "print_i32") (param i32))
+  (func $p (export "p2") (import "spectest" "print_i32") (param i32))
+  (func (export "p3") (export "p4") (import "spectest" "print_i32") (param i32))
+  (func (export "p5") (import "spectest" "print_i32") (type 0))
+  (func (export "p6") (import "spectest" "print_i32") (type 0) (param i32) (result))
+
+  (import "spectest" "print_i32" (func (type $forward)))
+  (func (import "spectest" "print_i32") (type $forward))
+  (type $forward (func (param i32)))
+
+  (table funcref (elem $print_i32 $print_f64))
+
+  (func (export "print32") (param $i i32)
+    (local $x f32)
+    (local.set $x (f32.convert_i32_s (local.get $i)))
+    (call 0 (local.get $i))
+    (call $print_i32_f32
+      (i32.add (local.get $i) (i32.const 1))
+      (f32.const 42)
+    )
+    (call $print_i32 (local.get $i))
+    (call $print_i32-2 (local.get $i))
+    (call $print_f32 (local.get $x))
+    (call_indirect (type $func_i32) (local.get $i) (i32.const 0))
+  )
+
+  (func (export "print64") (param $i i64)
+    (local $x f64)
+    (local.set $x (f64.convert_i64_s (call $i64->i64 (local.get $i))))
+    ;; JavaScript can't handle i64 yet.
+    ;; (call 1 (local.get $i))
+    (call $print_f64_f64
+      (f64.add (local.get $x) (f64.const 1))
+      (f64.const 53)
+    )
+    ;; JavaScript can't handle i64 yet.
+    ;; (call $print_i64 (local.get $i))
+    (call $print_f64 (local.get $x))
+    (call $print_f64-2 (local.get $x))
+    (call_indirect (type $func_f64) (local.get $x) (i32.const 1))
+  )
+)
+
+(assert_return (invoke "print32" (i32.const 13)))
+(assert_return (invoke "print64" (i64.const 24)))
+
+(assert_invalid
+  (module 
+    (type (func (result i32)))
+    (import "test" "func" (func (type 1)))
+  )
+  "unknown type"
+)
+
+(module (import "test" "func" (func)))
+(module (import "test" "func-i32" (func (param i32))))
+(module (import "test" "func-f32" (func (param f32))))
+(module (import "test" "func->i32" (func (result i32))))
+(module (import "test" "func->f32" (func (result f32))))
+(module (import "test" "func-i32->i32" (func (param i32) (result i32))))
+(module (import "test" "func-i64->i64" (func (param i64) (result i64))))
+
+(assert_unlinkable
+  (module (import "test" "unknown" (func)))
+  "unknown import"
+)
+(assert_unlinkable
+  (module (import "spectest" "unknown" (func)))
+  "unknown import"
+)
+
+(assert_unlinkable
+  (module (import "test" "func" (func (param i32))))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "func" (func (result i32))))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "func" (func (param i32) (result i32))))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "func-i32" (func)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "func-i32" (func (result i32))))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "func-i32" (func (param f32))))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "func-i32" (func (param i64))))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "func-i32" (func (param i32) (result i32))))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "func->i32" (func)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "func->i32" (func (param i32))))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "func->i32" (func (result f32))))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "func->i32" (func (result i64))))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "func->i32" (func (param i32) (result i32))))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "func-i32->i32" (func)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "func-i32->i32" (func (param i32))))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "func-i32->i32" (func (result i32))))
+  "incompatible import type"
+)
+
+(assert_unlinkable
+  (module (import "test" "global-i32" (func (result i32))))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "table-10-inf" (func)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "memory-2-inf" (func)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "spectest" "global_i32" (func)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "spectest" "table" (func)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "spectest" "memory" (func)))
+  "incompatible import type"
+)
+
+
+;; Globals
+
+(module
+  (import "spectest" "global_i32" (global i32))
+  (global (import "spectest" "global_i32") i32)
+
+  (import "spectest" "global_i32" (global $x i32))
+  (global $y (import "spectest" "global_i32") i32)
+
+  ;; JavaScript can't handle i64 yet.
+  ;; (import "spectest" "global_i64" (global i64))
+  (import "spectest" "global_f32" (global f32))
+  (import "spectest" "global_f64" (global f64))
+
+  (func (export "get-0") (result i32) (global.get 0))
+  (func (export "get-1") (result i32) (global.get 1))
+  (func (export "get-x") (result i32) (global.get $x))
+  (func (export "get-y") (result i32) (global.get $y))
+)
+
+(assert_return (invoke "get-0") (i32.const 666))
+(assert_return (invoke "get-1") (i32.const 666))
+(assert_return (invoke "get-x") (i32.const 666))
+(assert_return (invoke "get-y") (i32.const 666))
+
+(module (import "test" "global-i32" (global i32)))
+(module (import "test" "global-f32" (global f32)))
+
+(assert_unlinkable
+  (module (import "test" "unknown" (global i32)))
+  "unknown import"
+)
+(assert_unlinkable
+  (module (import "spectest" "unknown" (global i32)))
+  "unknown import"
+)
+
+(assert_unlinkable
+  (module (import "test" "func" (global i32)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "table-10-inf" (global i32)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "memory-2-inf" (global i32)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "spectest" "print_i32" (global i32)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "spectest" "table" (global i32)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "spectest" "memory" (global i32)))
+  "incompatible import type"
+)
+
+
+;; Tables
+
+(module
+  (type (func (result i32)))
+  (import "spectest" "table" (table 10 20 funcref))
+  (elem 0 (i32.const 1) $f $g)
+
+  (func (export "call") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0))
+  )
+  (func $f (result i32) (i32.const 11))
+  (func $g (result i32) (i32.const 22))
+)
+
+(assert_trap (invoke "call" (i32.const 0)) "uninitialized element")
+(assert_return (invoke "call" (i32.const 1)) (i32.const 11))
+(assert_return (invoke "call" (i32.const 2)) (i32.const 22))
+(assert_trap (invoke "call" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "call" (i32.const 100)) "undefined element")
+
+
+(module
+  (type (func (result i32)))
+  (table (import "spectest" "table") 10 20 funcref)
+  (elem 0 (i32.const 1) $f $g)
+
+  (func (export "call") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0))
+  )
+  (func $f (result i32) (i32.const 11))
+  (func $g (result i32) (i32.const 22))
+)
+
+(assert_trap (invoke "call" (i32.const 0)) "uninitialized element")
+(assert_return (invoke "call" (i32.const 1)) (i32.const 11))
+(assert_return (invoke "call" (i32.const 2)) (i32.const 22))
+(assert_trap (invoke "call" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "call" (i32.const 100)) "undefined element")
+
+
+(assert_invalid
+  (module (import "" "" (table 10 funcref)) (import "" "" (table 10 funcref)))
+  "multiple tables"
+)
+(assert_invalid
+  (module (import "" "" (table 10 funcref)) (table 10 funcref))
+  "multiple tables"
+)
+(assert_invalid
+  (module (table 10 funcref) (table 10 funcref))
+  "multiple tables"
+)
+
+(module (import "test" "table-10-inf" (table 10 funcref)))
+(module (import "test" "table-10-inf" (table 5 funcref)))
+(module (import "test" "table-10-inf" (table 0 funcref)))
+(module (import "spectest" "table" (table 10 funcref)))
+(module (import "spectest" "table" (table 5 funcref)))
+(module (import "spectest" "table" (table 0 funcref)))
+(module (import "spectest" "table" (table 10 20 funcref)))
+(module (import "spectest" "table" (table 5 20 funcref)))
+(module (import "spectest" "table" (table 0 20 funcref)))
+(module (import "spectest" "table" (table 10 25 funcref)))
+(module (import "spectest" "table" (table 5 25 funcref)))
+
+(assert_unlinkable
+  (module (import "test" "unknown" (table 10 funcref)))
+  "unknown import"
+)
+(assert_unlinkable
+  (module (import "spectest" "unknown" (table 10 funcref)))
+  "unknown import"
+)
+
+(assert_unlinkable
+  (module (import "test" "table-10-inf" (table 12 funcref)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "table-10-inf" (table 10 20 funcref)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "spectest" "table" (table 12 funcref)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "spectest" "table" (table 10 15 funcref)))
+  "incompatible import type"
+)
+
+(assert_unlinkable
+  (module (import "test" "func" (table 10 funcref)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "global-i32" (table 10 funcref)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "memory-2-inf" (table 10 funcref)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "spectest" "print_i32" (table 10 funcref)))
+  "incompatible import type"
+)
+
+
+
+;; Memories
+
+(module
+  (import "spectest" "memory" (memory 1 2))
+  (data 0 (i32.const 10) "\10")
+
+  (func (export "load") (param i32) (result i32) (i32.load (local.get 0)))
+)
+
+(assert_return (invoke "load" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load" (i32.const 10)) (i32.const 16))
+(assert_return (invoke "load" (i32.const 8)) (i32.const 0x100000))
+(assert_trap (invoke "load" (i32.const 1000000)) "out of bounds memory access")
+
+(module
+  (memory (import "spectest" "memory") 1 2)
+  (data 0 (i32.const 10) "\10")
+
+  (func (export "load") (param i32) (result i32) (i32.load (local.get 0)))
+)
+(assert_return (invoke "load" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load" (i32.const 10)) (i32.const 16))
+(assert_return (invoke "load" (i32.const 8)) (i32.const 0x100000))
+(assert_trap (invoke "load" (i32.const 1000000)) "out of bounds memory access")
+
+(assert_invalid
+  (module (import "" "" (memory 1)) (import "" "" (memory 1)))
+  "multiple memories"
+)
+(assert_invalid
+  (module (import "" "" (memory 1)) (memory 0))
+  "multiple memories"
+)
+(assert_invalid
+  (module (memory 0) (memory 0))
+  "multiple memories"
+)
+
+(module (import "test" "memory-2-inf" (memory 2)))
+(module (import "test" "memory-2-inf" (memory 1)))
+(module (import "test" "memory-2-inf" (memory 0)))
+(module (import "spectest" "memory" (memory 1)))
+(module (import "spectest" "memory" (memory 0)))
+(module (import "spectest" "memory" (memory 1 2)))
+(module (import "spectest" "memory" (memory 0 2)))
+(module (import "spectest" "memory" (memory 1 3)))
+(module (import "spectest" "memory" (memory 0 3)))
+
+(assert_unlinkable
+  (module (import "test" "unknown" (memory 1)))
+  "unknown import"
+)
+(assert_unlinkable
+  (module (import "spectest" "unknown" (memory 1)))
+  "unknown import"
+)
+
+(assert_unlinkable
+  (module (import "test" "memory-2-inf" (memory 3)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "memory-2-inf" (memory 2 3)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "spectest" "memory" (memory 2)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "spectest" "memory" (memory 1 1)))
+  "incompatible import type"
+)
+
+(assert_unlinkable
+  (module (import "test" "func-i32" (memory 1)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "global-i32" (memory 1)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "test" "table-10-inf" (memory 1)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "spectest" "print_i32" (memory 1)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "spectest" "global_i32" (memory 1)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "spectest" "table" (memory 1)))
+  "incompatible import type"
+)
+
+(assert_unlinkable
+  (module (import "spectest" "memory" (memory 2)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "spectest" "memory" (memory 1 1)))
+  "incompatible import type"
+)
+
+(module
+  (import "spectest" "memory" (memory 0 3))  ;; actual has max size 2
+  (func (export "grow") (param i32) (result i32) (memory.grow (local.get 0)))
+)
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const -1))
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 2))
+
+
+;; Syntax errors
+
+(assert_malformed
+  (module quote "(func) (import \"\" \"\" (func))")
+  "import after function"
+)
+(assert_malformed
+  (module quote "(func) (import \"\" \"\" (global i64))")
+  "import after function"
+)
+(assert_malformed
+  (module quote "(func) (import \"\" \"\" (table 0 funcref))")
+  "import after function"
+)
+(assert_malformed
+  (module quote "(func) (import \"\" \"\" (memory 0))")
+  "import after function"
+)
+
+(assert_malformed
+  (module quote "(global i64 (i64.const 0)) (import \"\" \"\" (func))")
+  "import after global"
+)
+(assert_malformed
+  (module quote "(global i64 (i64.const 0)) (import \"\" \"\" (global f32))")
+  "import after global"
+)
+(assert_malformed
+  (module quote "(global i64 (i64.const 0)) (import \"\" \"\" (table 0 funcref))")
+  "import after global"
+)
+(assert_malformed
+  (module quote "(global i64 (i64.const 0)) (import \"\" \"\" (memory 0))")
+  "import after global"
+)
+
+(assert_malformed
+  (module quote "(table 0 funcref) (import \"\" \"\" (func))")
+  "import after table"
+)
+(assert_malformed
+  (module quote "(table 0 funcref) (import \"\" \"\" (global i32))")
+  "import after table"
+)
+(assert_malformed
+  (module quote "(table 0 funcref) (import \"\" \"\" (table 0 funcref))")
+  "import after table"
+)
+(assert_malformed
+  (module quote "(table 0 funcref) (import \"\" \"\" (memory 0))")
+  "import after table"
+)
+
+(assert_malformed
+  (module quote "(memory 0) (import \"\" \"\" (func))")
+  "import after memory"
+)
+(assert_malformed
+  (module quote "(memory 0) (import \"\" \"\" (global i32))")
+  "import after memory"
+)
+(assert_malformed
+  (module quote "(memory 0) (import \"\" \"\" (table 1 3 funcref))")
+  "import after memory"
+)
+(assert_malformed
+  (module quote "(memory 0) (import \"\" \"\" (memory 1 2))")
+  "import after memory"
+)
+
+;; This module is required to validate, regardless of whether it can be
+;; linked. Overloading is not possible in wasm itself, but it is possible
+;; in modules from which wasm can import.
+(module)
+(register "not wasm")
+(assert_unlinkable
+  (module
+    (import "not wasm" "overloaded" (func))
+    (import "not wasm" "overloaded" (func (param i32)))
+    (import "not wasm" "overloaded" (func (param i32 i32)))
+    (import "not wasm" "overloaded" (func (param i64)))
+    (import "not wasm" "overloaded" (func (param f32)))
+    (import "not wasm" "overloaded" (func (param f64)))
+    (import "not wasm" "overloaded" (func (result i32)))
+    (import "not wasm" "overloaded" (func (result i64)))
+    (import "not wasm" "overloaded" (func (result f32)))
+    (import "not wasm" "overloaded" (func (result f64)))
+    (import "not wasm" "overloaded" (global i32))
+    (import "not wasm" "overloaded" (global i64))
+    (import "not wasm" "overloaded" (global f32))
+    (import "not wasm" "overloaded" (global f64))
+    (import "not wasm" "overloaded" (table 0 funcref))
+    (import "not wasm" "overloaded" (memory 0))
+  )
+  "unknown import"
+)
diff --git a/binaryen/test/spec/inline-module.wast b/binaryen/test/spec/inline-module.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/inline-module.wast
@@ -0,0 +1,1 @@
+(func) (memory 0) (func (export "f"))
diff --git a/binaryen/test/spec/int_exprs.wast b/binaryen/test/spec/int_exprs.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/int_exprs.wast
@@ -0,0 +1,350 @@
+;; Test interesting integer "expressions". These tests contain code
+;; patterns which tempt common value-changing optimizations.
+
+;; Test that x+1<y+1 is not folded to x<y.
+
+(module
+  (func (export "i32.no_fold_cmp_s_offset") (param $x i32) (param $y i32) (result i32)
+    (i32.lt_s (i32.add (local.get $x) (i32.const 1)) (i32.add (local.get $y) (i32.const 1))))
+  (func (export "i32.no_fold_cmp_u_offset") (param $x i32) (param $y i32) (result i32)
+    (i32.lt_u (i32.add (local.get $x) (i32.const 1)) (i32.add (local.get $y) (i32.const 1))))
+
+  (func (export "i64.no_fold_cmp_s_offset") (param $x i64) (param $y i64) (result i32)
+    (i64.lt_s (i64.add (local.get $x) (i64.const 1)) (i64.add (local.get $y) (i64.const 1))))
+  (func (export "i64.no_fold_cmp_u_offset") (param $x i64) (param $y i64) (result i32)
+    (i64.lt_u (i64.add (local.get $x) (i64.const 1)) (i64.add (local.get $y) (i64.const 1))))
+)
+
+(assert_return (invoke "i32.no_fold_cmp_s_offset" (i32.const 0x7fffffff) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "i32.no_fold_cmp_u_offset" (i32.const 0xffffffff) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "i64.no_fold_cmp_s_offset" (i64.const 0x7fffffffffffffff) (i64.const 0)) (i32.const 1))
+(assert_return (invoke "i64.no_fold_cmp_u_offset" (i64.const 0xffffffffffffffff) (i64.const 0)) (i32.const 1))
+
+;; Test that wrap(extend_s(x)) is not folded to x.
+
+(module
+  (func (export "i64.no_fold_wrap_extend_s") (param $x i64) (result i64)
+    (i64.extend_i32_s (i32.wrap_i64 (local.get $x))))
+)
+
+(assert_return (invoke "i64.no_fold_wrap_extend_s" (i64.const 0x0010203040506070)) (i64.const 0x0000000040506070))
+(assert_return (invoke "i64.no_fold_wrap_extend_s" (i64.const 0x00a0b0c0d0e0f0a0)) (i64.const 0xffffffffd0e0f0a0))
+
+;; Test that wrap(extend_u(x)) is not folded to x.
+
+(module
+  (func (export "i64.no_fold_wrap_extend_u") (param $x i64) (result i64)
+    (i64.extend_i32_u (i32.wrap_i64 (local.get $x))))
+)
+
+(assert_return (invoke "i64.no_fold_wrap_extend_u" (i64.const 0x0010203040506070)) (i64.const 0x0000000040506070))
+
+;; Test that x<<n>>n is not folded to x.
+
+(module
+  (func (export "i32.no_fold_shl_shr_s") (param $x i32) (result i32)
+    (i32.shr_s (i32.shl (local.get $x) (i32.const 1)) (i32.const 1)))
+  (func (export "i32.no_fold_shl_shr_u") (param $x i32) (result i32)
+    (i32.shr_u (i32.shl (local.get $x) (i32.const 1)) (i32.const 1)))
+
+  (func (export "i64.no_fold_shl_shr_s") (param $x i64) (result i64)
+    (i64.shr_s (i64.shl (local.get $x) (i64.const 1)) (i64.const 1)))
+  (func (export "i64.no_fold_shl_shr_u") (param $x i64) (result i64)
+    (i64.shr_u (i64.shl (local.get $x) (i64.const 1)) (i64.const 1)))
+)
+
+(assert_return (invoke "i32.no_fold_shl_shr_s" (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "i32.no_fold_shl_shr_u" (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "i64.no_fold_shl_shr_s" (i64.const 0x8000000000000000)) (i64.const 0))
+(assert_return (invoke "i64.no_fold_shl_shr_u" (i64.const 0x8000000000000000)) (i64.const 0))
+
+;; Test that x>>n<<n is not folded to x.
+
+(module
+  (func (export "i32.no_fold_shr_s_shl") (param $x i32) (result i32)
+    (i32.shl (i32.shr_s (local.get $x) (i32.const 1)) (i32.const 1)))
+  (func (export "i32.no_fold_shr_u_shl") (param $x i32) (result i32)
+    (i32.shl (i32.shr_u (local.get $x) (i32.const 1)) (i32.const 1)))
+
+  (func (export "i64.no_fold_shr_s_shl") (param $x i64) (result i64)
+    (i64.shl (i64.shr_s (local.get $x) (i64.const 1)) (i64.const 1)))
+  (func (export "i64.no_fold_shr_u_shl") (param $x i64) (result i64)
+    (i64.shl (i64.shr_u (local.get $x) (i64.const 1)) (i64.const 1)))
+)
+
+(assert_return (invoke "i32.no_fold_shr_s_shl" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "i32.no_fold_shr_u_shl" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "i64.no_fold_shr_s_shl" (i64.const 1)) (i64.const 0))
+(assert_return (invoke "i64.no_fold_shr_u_shl" (i64.const 1)) (i64.const 0))
+
+;; Test that x/n*n is not folded to x.
+
+(module
+  (func (export "i32.no_fold_div_s_mul") (param $x i32) (result i32)
+    (i32.mul (i32.div_s (local.get $x) (i32.const 6)) (i32.const 6)))
+  (func (export "i32.no_fold_div_u_mul") (param $x i32) (result i32)
+    (i32.mul (i32.div_u (local.get $x) (i32.const 6)) (i32.const 6)))
+
+  (func (export "i64.no_fold_div_s_mul") (param $x i64) (result i64)
+    (i64.mul (i64.div_s (local.get $x) (i64.const 6)) (i64.const 6)))
+  (func (export "i64.no_fold_div_u_mul") (param $x i64) (result i64)
+    (i64.mul (i64.div_u (local.get $x) (i64.const 6)) (i64.const 6)))
+)
+
+(assert_return (invoke "i32.no_fold_div_s_mul" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "i32.no_fold_div_u_mul" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "i64.no_fold_div_s_mul" (i64.const 1)) (i64.const 0))
+(assert_return (invoke "i64.no_fold_div_u_mul" (i64.const 1)) (i64.const 0))
+
+;; Test that x/x is not folded to 1.
+
+(module
+  (func (export "i32.no_fold_div_s_self") (param $x i32) (result i32)
+    (i32.div_s (local.get $x) (local.get $x)))
+  (func (export "i32.no_fold_div_u_self") (param $x i32) (result i32)
+    (i32.div_u (local.get $x) (local.get $x)))
+
+  (func (export "i64.no_fold_div_s_self") (param $x i64) (result i64)
+    (i64.div_s (local.get $x) (local.get $x)))
+  (func (export "i64.no_fold_div_u_self") (param $x i64) (result i64)
+    (i64.div_u (local.get $x) (local.get $x)))
+)
+
+(assert_trap (invoke "i32.no_fold_div_s_self" (i32.const 0)) "integer divide by zero")
+(assert_trap (invoke "i32.no_fold_div_u_self" (i32.const 0)) "integer divide by zero")
+(assert_trap (invoke "i64.no_fold_div_s_self" (i64.const 0)) "integer divide by zero")
+(assert_trap (invoke "i64.no_fold_div_u_self" (i64.const 0)) "integer divide by zero")
+
+;; Test that x%x is not folded to 0.
+
+(module
+  (func (export "i32.no_fold_rem_s_self") (param $x i32) (result i32)
+    (i32.rem_s (local.get $x) (local.get $x)))
+  (func (export "i32.no_fold_rem_u_self") (param $x i32) (result i32)
+    (i32.rem_u (local.get $x) (local.get $x)))
+
+  (func (export "i64.no_fold_rem_s_self") (param $x i64) (result i64)
+    (i64.rem_s (local.get $x) (local.get $x)))
+  (func (export "i64.no_fold_rem_u_self") (param $x i64) (result i64)
+    (i64.rem_u (local.get $x) (local.get $x)))
+)
+
+(assert_trap (invoke "i32.no_fold_rem_s_self" (i32.const 0)) "integer divide by zero")
+(assert_trap (invoke "i32.no_fold_rem_u_self" (i32.const 0)) "integer divide by zero")
+(assert_trap (invoke "i64.no_fold_rem_s_self" (i64.const 0)) "integer divide by zero")
+(assert_trap (invoke "i64.no_fold_rem_u_self" (i64.const 0)) "integer divide by zero")
+
+;; Test that x*n/n is not folded to x.
+
+(module
+  (func (export "i32.no_fold_mul_div_s") (param $x i32) (result i32)
+    (i32.div_s (i32.mul (local.get $x) (i32.const 6)) (i32.const 6)))
+  (func (export "i32.no_fold_mul_div_u") (param $x i32) (result i32)
+    (i32.div_u (i32.mul (local.get $x) (i32.const 6)) (i32.const 6)))
+
+  (func (export "i64.no_fold_mul_div_s") (param $x i64) (result i64)
+    (i64.div_s (i64.mul (local.get $x) (i64.const 6)) (i64.const 6)))
+  (func (export "i64.no_fold_mul_div_u") (param $x i64) (result i64)
+    (i64.div_u (i64.mul (local.get $x) (i64.const 6)) (i64.const 6)))
+)
+
+(assert_return (invoke "i32.no_fold_mul_div_s" (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "i32.no_fold_mul_div_u" (i32.const 0x80000000)) (i32.const 0))
+(assert_return (invoke "i64.no_fold_mul_div_s" (i64.const 0x8000000000000000)) (i64.const 0))
+(assert_return (invoke "i64.no_fold_mul_div_u" (i64.const 0x8000000000000000)) (i64.const 0))
+
+;; Test that x/n where n is a known power of 2 is not folded to shr_s.
+
+(module
+  (func (export "i32.no_fold_div_s_2") (param $x i32) (result i32)
+    (i32.div_s (local.get $x) (i32.const 2)))
+
+  (func (export "i64.no_fold_div_s_2") (param $x i64) (result i64)
+    (i64.div_s (local.get $x) (i64.const 2)))
+)
+
+(assert_return (invoke "i32.no_fold_div_s_2" (i32.const -11)) (i32.const -5))
+(assert_return (invoke "i64.no_fold_div_s_2" (i64.const -11)) (i64.const -5))
+
+;; Test that x%n where n is a known power of 2 is not folded to and.
+
+(module
+  (func (export "i32.no_fold_rem_s_2") (param $x i32) (result i32)
+    (i32.rem_s (local.get $x) (i32.const 2)))
+
+  (func (export "i64.no_fold_rem_s_2") (param $x i64) (result i64)
+    (i64.rem_s (local.get $x) (i64.const 2)))
+)
+
+(assert_return (invoke "i32.no_fold_rem_s_2" (i32.const -11)) (i32.const -1))
+(assert_return (invoke "i64.no_fold_rem_s_2" (i64.const -11)) (i64.const -1))
+
+;; Test that x/0 works.
+
+(module
+  (func (export "i32.div_s_0") (param $x i32) (result i32)
+    (i32.div_s (local.get $x) (i32.const 0)))
+  (func (export "i32.div_u_0") (param $x i32) (result i32)
+    (i32.div_u (local.get $x) (i32.const 0)))
+
+  (func (export "i64.div_s_0") (param $x i64) (result i64)
+    (i64.div_s (local.get $x) (i64.const 0)))
+  (func (export "i64.div_u_0") (param $x i64) (result i64)
+    (i64.div_u (local.get $x) (i64.const 0)))
+)
+
+(assert_trap (invoke "i32.div_s_0" (i32.const 71)) "integer divide by zero")
+(assert_trap (invoke "i32.div_u_0" (i32.const 71)) "integer divide by zero")
+(assert_trap (invoke "i64.div_s_0" (i64.const 71)) "integer divide by zero")
+(assert_trap (invoke "i64.div_u_0" (i64.const 71)) "integer divide by zero")
+
+;; Test that x/3 works.
+
+(module
+  (func (export "i32.div_s_3") (param $x i32) (result i32)
+    (i32.div_s (local.get $x) (i32.const 3)))
+  (func (export "i32.div_u_3") (param $x i32) (result i32)
+    (i32.div_u (local.get $x) (i32.const 3)))
+
+  (func (export "i64.div_s_3") (param $x i64) (result i64)
+    (i64.div_s (local.get $x) (i64.const 3)))
+  (func (export "i64.div_u_3") (param $x i64) (result i64)
+    (i64.div_u (local.get $x) (i64.const 3)))
+)
+
+(assert_return (invoke "i32.div_s_3" (i32.const 71)) (i32.const 23))
+(assert_return (invoke "i32.div_s_3" (i32.const 0x60000000)) (i32.const 0x20000000))
+(assert_return (invoke "i32.div_u_3" (i32.const 71)) (i32.const 23))
+(assert_return (invoke "i32.div_u_3" (i32.const 0xc0000000)) (i32.const 0x40000000))
+(assert_return (invoke "i64.div_s_3" (i64.const 71)) (i64.const 23))
+(assert_return (invoke "i64.div_s_3" (i64.const 0x3000000000000000)) (i64.const 0x1000000000000000))
+(assert_return (invoke "i64.div_u_3" (i64.const 71)) (i64.const 23))
+(assert_return (invoke "i64.div_u_3" (i64.const 0xc000000000000000)) (i64.const 0x4000000000000000))
+
+;; Test that x/5 works.
+
+(module
+  (func (export "i32.div_s_5") (param $x i32) (result i32)
+    (i32.div_s (local.get $x) (i32.const 5)))
+  (func (export "i32.div_u_5") (param $x i32) (result i32)
+    (i32.div_u (local.get $x) (i32.const 5)))
+
+  (func (export "i64.div_s_5") (param $x i64) (result i64)
+    (i64.div_s (local.get $x) (i64.const 5)))
+  (func (export "i64.div_u_5") (param $x i64) (result i64)
+    (i64.div_u (local.get $x) (i64.const 5)))
+)
+
+(assert_return (invoke "i32.div_s_5" (i32.const 71)) (i32.const 14))
+(assert_return (invoke "i32.div_s_5" (i32.const 0x50000000)) (i32.const 0x10000000))
+(assert_return (invoke "i32.div_u_5" (i32.const 71)) (i32.const 14))
+(assert_return (invoke "i32.div_u_5" (i32.const 0xa0000000)) (i32.const 0x20000000))
+(assert_return (invoke "i64.div_s_5" (i64.const 71)) (i64.const 14))
+(assert_return (invoke "i64.div_s_5" (i64.const 0x5000000000000000)) (i64.const 0x1000000000000000))
+(assert_return (invoke "i64.div_u_5" (i64.const 71)) (i64.const 14))
+(assert_return (invoke "i64.div_u_5" (i64.const 0xa000000000000000)) (i64.const 0x2000000000000000))
+
+;; Test that x/7 works.
+
+(module
+  (func (export "i32.div_s_7") (param $x i32) (result i32)
+    (i32.div_s (local.get $x) (i32.const 7)))
+  (func (export "i32.div_u_7") (param $x i32) (result i32)
+    (i32.div_u (local.get $x) (i32.const 7)))
+
+  (func (export "i64.div_s_7") (param $x i64) (result i64)
+    (i64.div_s (local.get $x) (i64.const 7)))
+  (func (export "i64.div_u_7") (param $x i64) (result i64)
+    (i64.div_u (local.get $x) (i64.const 7)))
+)
+
+(assert_return (invoke "i32.div_s_7" (i32.const 71)) (i32.const 10))
+(assert_return (invoke "i32.div_s_7" (i32.const 0x70000000)) (i32.const 0x10000000))
+(assert_return (invoke "i32.div_u_7" (i32.const 71)) (i32.const 10))
+(assert_return (invoke "i32.div_u_7" (i32.const 0xe0000000)) (i32.const 0x20000000))
+(assert_return (invoke "i64.div_s_7" (i64.const 71)) (i64.const 10))
+(assert_return (invoke "i64.div_s_7" (i64.const 0x7000000000000000)) (i64.const 0x1000000000000000))
+(assert_return (invoke "i64.div_u_7" (i64.const 71)) (i64.const 10))
+(assert_return (invoke "i64.div_u_7" (i64.const 0xe000000000000000)) (i64.const 0x2000000000000000))
+
+;; Test that x%3 works.
+
+(module
+  (func (export "i32.rem_s_3") (param $x i32) (result i32)
+    (i32.rem_s (local.get $x) (i32.const 3)))
+  (func (export "i32.rem_u_3") (param $x i32) (result i32)
+    (i32.rem_u (local.get $x) (i32.const 3)))
+
+  (func (export "i64.rem_s_3") (param $x i64) (result i64)
+    (i64.rem_s (local.get $x) (i64.const 3)))
+  (func (export "i64.rem_u_3") (param $x i64) (result i64)
+    (i64.rem_u (local.get $x) (i64.const 3)))
+)
+
+(assert_return (invoke "i32.rem_s_3" (i32.const 71)) (i32.const 2))
+(assert_return (invoke "i32.rem_s_3" (i32.const 0x60000000)) (i32.const 0))
+(assert_return (invoke "i32.rem_u_3" (i32.const 71)) (i32.const 2))
+(assert_return (invoke "i32.rem_u_3" (i32.const 0xc0000000)) (i32.const 0))
+(assert_return (invoke "i64.rem_s_3" (i64.const 71)) (i64.const 2))
+(assert_return (invoke "i64.rem_s_3" (i64.const 0x3000000000000000)) (i64.const 0))
+(assert_return (invoke "i64.rem_u_3" (i64.const 71)) (i64.const 2))
+(assert_return (invoke "i64.rem_u_3" (i64.const 0xc000000000000000)) (i64.const 0))
+
+;; Test that x%5 works.
+
+(module
+  (func (export "i32.rem_s_5") (param $x i32) (result i32)
+    (i32.rem_s (local.get $x) (i32.const 5)))
+  (func (export "i32.rem_u_5") (param $x i32) (result i32)
+    (i32.rem_u (local.get $x) (i32.const 5)))
+
+  (func (export "i64.rem_s_5") (param $x i64) (result i64)
+    (i64.rem_s (local.get $x) (i64.const 5)))
+  (func (export "i64.rem_u_5") (param $x i64) (result i64)
+    (i64.rem_u (local.get $x) (i64.const 5)))
+)
+
+(assert_return (invoke "i32.rem_s_5" (i32.const 71)) (i32.const 1))
+(assert_return (invoke "i32.rem_s_5" (i32.const 0x50000000)) (i32.const 0))
+(assert_return (invoke "i32.rem_u_5" (i32.const 71)) (i32.const 1))
+(assert_return (invoke "i32.rem_u_5" (i32.const 0xa0000000)) (i32.const 0))
+(assert_return (invoke "i64.rem_s_5" (i64.const 71)) (i64.const 1))
+(assert_return (invoke "i64.rem_s_5" (i64.const 0x5000000000000000)) (i64.const 0))
+(assert_return (invoke "i64.rem_u_5" (i64.const 71)) (i64.const 1))
+(assert_return (invoke "i64.rem_u_5" (i64.const 0xa000000000000000)) (i64.const 0))
+
+;; Test that x%7 works.
+
+(module
+  (func (export "i32.rem_s_7") (param $x i32) (result i32)
+    (i32.rem_s (local.get $x) (i32.const 7)))
+  (func (export "i32.rem_u_7") (param $x i32) (result i32)
+    (i32.rem_u (local.get $x) (i32.const 7)))
+
+  (func (export "i64.rem_s_7") (param $x i64) (result i64)
+    (i64.rem_s (local.get $x) (i64.const 7)))
+  (func (export "i64.rem_u_7") (param $x i64) (result i64)
+    (i64.rem_u (local.get $x) (i64.const 7)))
+)
+
+(assert_return (invoke "i32.rem_s_7" (i32.const 71)) (i32.const 1))
+(assert_return (invoke "i32.rem_s_7" (i32.const 0x70000000)) (i32.const 0))
+(assert_return (invoke "i32.rem_u_7" (i32.const 71)) (i32.const 1))
+(assert_return (invoke "i32.rem_u_7" (i32.const 0xe0000000)) (i32.const 0))
+(assert_return (invoke "i64.rem_s_7" (i64.const 71)) (i64.const 1))
+(assert_return (invoke "i64.rem_s_7" (i64.const 0x7000000000000000)) (i64.const 0))
+(assert_return (invoke "i64.rem_u_7" (i64.const 71)) (i64.const 1))
+(assert_return (invoke "i64.rem_u_7" (i64.const 0xe000000000000000)) (i64.const 0))
+
+;; Test that x/-1 is not folded to -x.
+
+(module
+  (func (export "i32.no_fold_div_neg1") (param $x i32) (result i32)
+    (i32.div_s (local.get $x) (i32.const -1)))
+
+  (func (export "i64.no_fold_div_neg1") (param $x i64) (result i64)
+    (i64.div_s (local.get $x) (i64.const -1)))
+)
+
+(assert_trap (invoke "i32.no_fold_div_neg1" (i32.const 0x80000000)) "integer overflow")
+(assert_trap (invoke "i64.no_fold_div_neg1" (i64.const 0x8000000000000000)) "integer overflow")
diff --git a/binaryen/test/spec/int_literals.wast b/binaryen/test/spec/int_literals.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/int_literals.wast
@@ -0,0 +1,151 @@
+(module
+  (func (export "i32.test") (result i32) (return (i32.const 0x0bAdD00D)))
+  (func (export "i32.umax") (result i32) (return (i32.const 0xffffffff)))
+  (func (export "i32.smax") (result i32) (return (i32.const 0x7fffffff)))
+  (func (export "i32.neg_smax") (result i32) (return (i32.const -0x7fffffff)))
+  (func (export "i32.smin") (result i32) (return (i32.const -0x80000000)))
+  (func (export "i32.alt_smin") (result i32) (return (i32.const 0x80000000)))
+  (func (export "i32.inc_smin") (result i32) (return (i32.add (i32.const -0x80000000) (i32.const 1))))
+  (func (export "i32.neg_zero") (result i32) (return (i32.const -0x0)))
+  (func (export "i32.not_octal") (result i32) (return (i32.const 010)))
+  (func (export "i32.unsigned_decimal") (result i32) (return (i32.const 4294967295)))
+  (func (export "i32.plus_sign") (result i32) (return (i32.const +42)))
+
+  (func (export "i64.test") (result i64) (return (i64.const 0x0CABBA6E0ba66a6e)))
+  (func (export "i64.umax") (result i64) (return (i64.const 0xffffffffffffffff)))
+  (func (export "i64.smax") (result i64) (return (i64.const 0x7fffffffffffffff)))
+  (func (export "i64.neg_smax") (result i64) (return (i64.const -0x7fffffffffffffff)))
+  (func (export "i64.smin") (result i64) (return (i64.const -0x8000000000000000)))
+  (func (export "i64.alt_smin") (result i64) (return (i64.const 0x8000000000000000)))
+  (func (export "i64.inc_smin") (result i64) (return (i64.add (i64.const -0x8000000000000000) (i64.const 1))))
+  (func (export "i64.neg_zero") (result i64) (return (i64.const -0x0)))
+  (func (export "i64.not_octal") (result i64) (return (i64.const 010)))
+  (func (export "i64.unsigned_decimal") (result i64) (return (i64.const 18446744073709551615)))
+  (func (export "i64.plus_sign") (result i64) (return (i64.const +42)))
+
+  (func (export "i32-dec-sep1") (result i32) (i32.const 1_000_000))
+  (func (export "i32-dec-sep2") (result i32) (i32.const 1_0_0_0))
+  (func (export "i32-hex-sep1") (result i32) (i32.const 0xa_0f_00_99))
+  (func (export "i32-hex-sep2") (result i32) (i32.const 0x1_a_A_0_f))
+
+  (func (export "i64-dec-sep1") (result i64) (i64.const 1_000_000))
+  (func (export "i64-dec-sep2") (result i64) (i64.const 1_0_0_0))
+  (func (export "i64-hex-sep1") (result i64) (i64.const 0xa_f00f_0000_9999))
+  (func (export "i64-hex-sep2") (result i64) (i64.const 0x1_a_A_0_f))
+)
+
+(assert_return (invoke "i32.test") (i32.const 195940365))
+(assert_return (invoke "i32.umax") (i32.const -1))
+(assert_return (invoke "i32.smax") (i32.const 2147483647))
+(assert_return (invoke "i32.neg_smax") (i32.const -2147483647))
+(assert_return (invoke "i32.smin") (i32.const -2147483648))
+(assert_return (invoke "i32.alt_smin") (i32.const -2147483648))
+(assert_return (invoke "i32.inc_smin") (i32.const -2147483647))
+(assert_return (invoke "i32.neg_zero") (i32.const 0))
+(assert_return (invoke "i32.not_octal") (i32.const 10))
+(assert_return (invoke "i32.unsigned_decimal") (i32.const -1))
+(assert_return (invoke "i32.plus_sign") (i32.const 42))
+
+(assert_return (invoke "i64.test") (i64.const 913028331277281902))
+(assert_return (invoke "i64.umax") (i64.const -1))
+(assert_return (invoke "i64.smax") (i64.const 9223372036854775807))
+(assert_return (invoke "i64.neg_smax") (i64.const -9223372036854775807))
+(assert_return (invoke "i64.smin") (i64.const -9223372036854775808))
+(assert_return (invoke "i64.alt_smin") (i64.const -9223372036854775808))
+(assert_return (invoke "i64.inc_smin") (i64.const -9223372036854775807))
+(assert_return (invoke "i64.neg_zero") (i64.const 0))
+(assert_return (invoke "i64.not_octal") (i64.const 10))
+(assert_return (invoke "i64.unsigned_decimal") (i64.const -1))
+(assert_return (invoke "i64.plus_sign") (i64.const 42))
+
+(assert_return (invoke "i32-dec-sep1") (i32.const 1000000))
+(assert_return (invoke "i32-dec-sep2") (i32.const 1000))
+(assert_return (invoke "i32-hex-sep1") (i32.const 0xa0f0099))
+(assert_return (invoke "i32-hex-sep2") (i32.const 0x1aa0f))
+
+(assert_return (invoke "i64-dec-sep1") (i64.const 1000000))
+(assert_return (invoke "i64-dec-sep2") (i64.const 1000))
+(assert_return (invoke "i64-hex-sep1") (i64.const 0xaf00f00009999))
+(assert_return (invoke "i64-hex-sep2") (i64.const 0x1aa0f))
+
+(assert_malformed
+  (module quote "(global i32 (i32.const _100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i32 (i32.const +_100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i32 (i32.const -_100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i32 (i32.const 99_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i32 (i32.const 1__000))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i32 (i32.const _0x100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i32 (i32.const 0_x100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i32 (i32.const 0x_100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i32 (i32.const 0x00_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i32 (i32.const 0xff__ffff))")
+  "unknown operator"
+)
+
+(assert_malformed
+  (module quote "(global i64 (i64.const _100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i64 (i64.const +_100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i64 (i64.const -_100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i64 (i64.const 99_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i64 (i64.const 1__000))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i64 (i64.const _0x100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i64 (i64.const 0_x100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i64 (i64.const 0x_100))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i64 (i64.const 0x00_))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(global i64 (i64.const 0xff__ffff))")
+  "unknown operator"
+)
diff --git a/binaryen/test/spec/labels.wast b/binaryen/test/spec/labels.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/labels.wast
@@ -0,0 +1,328 @@
+(module
+  (func (export "block") (result i32)
+    (block $exit (result i32)
+      (br $exit (i32.const 1))
+      (i32.const 0)
+    )
+  )
+
+  (func (export "loop1") (result i32)
+    (local $i i32)
+    (local.set $i (i32.const 0))
+    (block $exit (result i32)
+      (loop $cont (result i32)
+        (local.set $i (i32.add (local.get $i) (i32.const 1)))
+        (if (i32.eq (local.get $i) (i32.const 5))
+          (then (br $exit (local.get $i)))
+        )
+        (br $cont)
+      )
+    )
+  )
+
+  (func (export "loop2") (result i32)
+    (local $i i32)
+    (local.set $i (i32.const 0))
+    (block $exit (result i32)
+      (loop $cont (result i32)
+        (local.set $i (i32.add (local.get $i) (i32.const 1)))
+        (if (i32.eq (local.get $i) (i32.const 5))
+          (then (br $cont))
+        )
+        (if (i32.eq (local.get $i) (i32.const 8))
+          (then (br $exit (local.get $i)))
+        )
+        (local.set $i (i32.add (local.get $i) (i32.const 1)))
+        (br $cont)
+      )
+    )
+  )
+
+  (func (export "loop3") (result i32)
+    (local $i i32)
+    (local.set $i (i32.const 0))
+    (block $exit (result i32)
+      (loop $cont (result i32)
+        (local.set $i (i32.add (local.get $i) (i32.const 1)))
+        (if (i32.eq (local.get $i) (i32.const 5))
+          (then (br $exit (local.get $i)))
+        )
+        (local.get $i)
+      )
+    )
+  )
+
+  (func (export "loop4") (param $max i32) (result i32)
+    (local $i i32)
+    (local.set $i (i32.const 1))
+    (block $exit (result i32)
+      (loop $cont (result i32)
+        (local.set $i (i32.add (local.get $i) (local.get $i)))
+        (if (i32.gt_u (local.get $i) (local.get $max))
+          (then (br $exit (local.get $i)))
+        )
+        (br $cont)
+      )
+    )
+  )
+
+  (func (export "loop5") (result i32)
+    (i32.add
+      (loop $l (result i32) (i32.const 1))
+      (i32.const 1)
+    )
+  )
+
+  (func (export "loop6") (result i32)
+    (loop (result i32)
+      (br_if 0 (i32.const 0))
+      (i32.const 3)
+    )
+  )
+
+  (func (export "if") (result i32)
+    (local $i i32)
+    (local.set $i (i32.const 0))
+    (block
+      (if $l
+        (i32.const 1)
+        (then (br $l) (local.set $i (i32.const 666)))
+      )
+      (local.set $i (i32.add (local.get $i) (i32.const 1)))
+      (if $l
+        (i32.const 1)
+        (then (br $l) (local.set $i (i32.const 666)))
+        (else (local.set $i (i32.const 888)))
+      )
+      (local.set $i (i32.add (local.get $i) (i32.const 1)))
+      (if $l
+        (i32.const 1)
+        (then (br $l) (local.set $i (i32.const 666)))
+        (else (local.set $i (i32.const 888)))
+      )
+      (local.set $i (i32.add (local.get $i) (i32.const 1)))
+      (if $l
+        (i32.const 0)
+        (then (local.set $i (i32.const 888)))
+        (else (br $l) (local.set $i (i32.const 666)))
+      )
+      (local.set $i (i32.add (local.get $i) (i32.const 1)))
+      (if $l
+        (i32.const 0)
+        (then (local.set $i (i32.const 888)))
+        (else (br $l) (local.set $i (i32.const 666)))
+      )
+      (local.set $i (i32.add (local.get $i) (i32.const 1)))
+    )
+    (local.get $i)
+  )
+
+  (func (export "if2") (result i32)
+    (local $i i32)
+    (local.set $i (i32.const 0))
+    (block
+      (if
+        (i32.const 1)
+        (then (br 0) (local.set $i (i32.const 666)))
+      )
+      (local.set $i (i32.add (local.get $i) (i32.const 1)))
+      (if
+        (i32.const 1)
+        (then (br 0) (local.set $i (i32.const 666)))
+        (else (local.set $i (i32.const 888)))
+      )
+      (local.set $i (i32.add (local.get $i) (i32.const 1)))
+      (if
+        (i32.const 1)
+        (then (br 0) (local.set $i (i32.const 666)))
+        (else (local.set $i (i32.const 888)))
+      )
+      (local.set $i (i32.add (local.get $i) (i32.const 1)))
+      (if
+        (i32.const 0)
+        (then (local.set $i (i32.const 888)))
+        (else (br 0) (local.set $i (i32.const 666)))
+      )
+      (local.set $i (i32.add (local.get $i) (i32.const 1)))
+      (if
+        (i32.const 0)
+        (then (local.set $i (i32.const 888)))
+        (else (br 0) (local.set $i (i32.const 666)))
+      )
+      (local.set $i (i32.add (local.get $i) (i32.const 1)))
+    )
+    (local.get $i)
+  )
+
+  (func (export "switch") (param i32) (result i32)
+    (block $ret (result i32)
+      (i32.mul (i32.const 10)
+        (block $exit (result i32)
+          (block $0
+            (block $default
+              (block $3
+                (block $2
+                  (block $1
+                    (br_table $0 $1 $2 $3 $default (local.get 0))
+                  ) ;; 1
+                ) ;; 2
+                (br $exit (i32.const 2))
+              ) ;; 3
+              (br $ret (i32.const 3))
+            ) ;; default
+          ) ;; 0
+          (i32.const 5)
+        )
+      )
+    )
+  )
+
+  (func (export "return") (param i32) (result i32)
+    (block $default
+      (block $1
+        (block $0
+          (br_table $0 $1 (local.get 0))
+          (br $default)
+        ) ;; 0
+        (return (i32.const 0))
+      ) ;; 1
+    ) ;; default
+    (i32.const 2)
+  )
+
+  (func (export "br_if0") (result i32)
+    (local $i i32)
+    (local.set $i (i32.const 0))
+    (block $outer (result i32)
+      (block $inner
+        (br_if $inner (i32.const 0))
+        (local.set $i (i32.or (local.get $i) (i32.const 0x1)))
+        (br_if $inner (i32.const 1))
+        (local.set $i (i32.or (local.get $i) (i32.const 0x2)))
+      )
+      (drop (br_if $outer
+        (block (result i32)
+          (local.set $i (i32.or (local.get $i) (i32.const 0x4)))
+          (local.get $i)
+        )
+        (i32.const 0)
+      ))
+      (local.set $i (i32.or (local.get $i) (i32.const 0x8)))
+      (drop (br_if $outer
+        (block (result i32)
+          (local.set $i (i32.or (local.get $i) (i32.const 0x10)))
+          (local.get $i)
+        )
+        (i32.const 1)
+      ))
+      (local.set $i (i32.or (local.get $i) (i32.const 0x20))) (local.get $i)
+    )
+  )
+
+  (func (export "br_if1") (result i32)
+    (block $l0 (result i32)
+      (drop
+        (br_if $l0
+          (block $l1 (result i32) (br $l1 (i32.const 1)))
+          (i32.const 1)
+        )
+      )
+      (i32.const 0)
+    )
+  )
+
+  (func (export "br_if2") (result i32)
+    (block $l0 (result i32)
+      (if (i32.const 1)
+        (then
+          (drop
+            (br_if $l0
+              (block $l1 (result i32) (br $l1 (i32.const 1)))
+              (i32.const 1)
+            )
+          )
+        )
+      )
+      (i32.const 0)
+    )
+  )
+
+  (func (export "br_if3") (result i32)
+    (local $i1 i32)
+    (drop
+      (i32.add
+        (block $l0 (result i32)
+          (drop (br_if $l0
+            (block (result i32) (local.set $i1 (i32.const 1)) (local.get $i1))
+            (block (result i32) (local.set $i1 (i32.const 2)) (local.get $i1))
+          ))
+          (i32.const 0)
+        )
+        (i32.const 0)
+      )
+    )
+    (local.get $i1)
+  )
+
+  (func (export "br") (result i32)
+    (block $l0 (result i32)
+      (if (i32.const 1)
+        (then (br $l0 (block $l1 (result i32) (br $l1 (i32.const 1)))))
+        (else (block (drop (block $l1 (result i32) (br $l1 (i32.const 1))))))
+      )
+      (i32.const 1)
+    )
+  )
+
+  (func (export "shadowing") (result i32)
+    (block $l1 (result i32) (i32.xor (br $l1 (i32.const 1)) (i32.const 2)))
+  )
+
+  (func (export "redefinition") (result i32)
+    (block $l1 (result i32)
+      (i32.add
+        (block $l1 (result i32) (i32.const 2))
+        (block $l1 (result i32) (br $l1 (i32.const 3)))
+      )
+    )
+  )
+)
+
+(assert_return (invoke "block") (i32.const 1))
+(assert_return (invoke "loop1") (i32.const 5))
+(assert_return (invoke "loop2") (i32.const 8))
+(assert_return (invoke "loop3") (i32.const 1))
+(assert_return (invoke "loop4" (i32.const 8)) (i32.const 16))
+(assert_return (invoke "loop5") (i32.const 2))
+(assert_return (invoke "loop6") (i32.const 3))
+(assert_return (invoke "if") (i32.const 5))
+(assert_return (invoke "if2") (i32.const 5))
+(assert_return (invoke "switch" (i32.const 0)) (i32.const 50))
+(assert_return (invoke "switch" (i32.const 1)) (i32.const 20))
+(assert_return (invoke "switch" (i32.const 2)) (i32.const 20))
+(assert_return (invoke "switch" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "switch" (i32.const 4)) (i32.const 50))
+(assert_return (invoke "switch" (i32.const 5)) (i32.const 50))
+(assert_return (invoke "return" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "return" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "return" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "br_if0") (i32.const 0x1d))
+(assert_return (invoke "br_if1") (i32.const 1))
+(assert_return (invoke "br_if2") (i32.const 1))
+(assert_return (invoke "br_if3") (i32.const 2))
+(assert_return (invoke "br") (i32.const 1))
+(assert_return (invoke "shadowing") (i32.const 1))
+(assert_return (invoke "redefinition") (i32.const 5))
+
+(assert_invalid
+  (module (func (block $l (f32.neg (br_if $l (i32.const 1))) (nop))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func (block $l (br_if $l (f32.const 0) (i32.const 1)))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func (block $l (br_if $l (f32.const 0) (i32.const 1)))))
+  "type mismatch"
+)
diff --git a/binaryen/test/spec/left-to-right.wast b/binaryen/test/spec/left-to-right.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/left-to-right.wast
@@ -0,0 +1,233 @@
+(module
+  (memory 1)
+
+  (type $i32_T (func (param i32 i32) (result i32)))
+  (type $i64_T (func (param i64 i64) (result i32)))
+  (type $f32_T (func (param f32 f32) (result i32)))
+  (type $f64_T (func (param f64 f64) (result i32)))
+  (table funcref
+    (elem $i32_t0 $i32_t1 $i64_t0 $i64_t1 $f32_t0 $f32_t1 $f64_t0 $f64_t1)
+  )
+
+  (func $i32_t0 (type $i32_T) (i32.const -1))
+  (func $i32_t1 (type $i32_T) (i32.const -2))
+  (func $i64_t0 (type $i64_T) (i32.const -1))
+  (func $i64_t1 (type $i64_T) (i32.const -2))
+  (func $f32_t0 (type $f32_T) (i32.const -1))
+  (func $f32_t1 (type $f32_T) (i32.const -2))
+  (func $f64_t0 (type $f64_T) (i32.const -1))
+  (func $f64_t1 (type $f64_T) (i32.const -2))
+
+  ;; The idea is: We reset the memory, then the instruction call $*_left,
+  ;; $*_right, $*_another, $*_callee (for indirect calls), and $*_bool (when a
+  ;; boolean value is needed). These functions all call bump, which shifts the
+  ;; memory starting at address 8 up a byte, and then store a unique value at
+  ;; address 8. Then we read the 4-byte value at address 8. It should contain
+  ;; the correct sequence of unique values if the calls were evaluated in the
+  ;; correct order.
+
+  (func $reset (i32.store (i32.const 8) (i32.const 0)))
+
+  (func $bump
+    (i32.store8 (i32.const 11) (i32.load8_u (i32.const 10)))
+    (i32.store8 (i32.const 10) (i32.load8_u (i32.const 9)))
+    (i32.store8 (i32.const 9) (i32.load8_u (i32.const 8)))
+    (i32.store8 (i32.const 8) (i32.const -3)))
+
+  (func $get (result i32) (i32.load (i32.const 8)))
+
+  (func $i32_left (result i32) (call $bump) (i32.store8 (i32.const 8) (i32.const 1)) (i32.const 0))
+  (func $i32_right (result i32) (call $bump) (i32.store8 (i32.const 8) (i32.const 2)) (i32.const 1))
+  (func $i32_another (result i32) (call $bump) (i32.store8 (i32.const 8) (i32.const 3)) (i32.const 1))
+  (func $i32_callee (result i32) (call $bump) (i32.store8 (i32.const 8) (i32.const 4)) (i32.const 0))
+  (func $i32_bool (result i32) (call $bump) (i32.store8 (i32.const 8) (i32.const 5)) (i32.const 0))
+  (func $i64_left (result i64) (call $bump) (i32.store8 (i32.const 8) (i32.const 1)) (i64.const 0))
+  (func $i64_right (result i64) (call $bump) (i32.store8 (i32.const 8) (i32.const 2)) (i64.const 1))
+  (func $i64_another (result i64) (call $bump) (i32.store8 (i32.const 8) (i32.const 3)) (i64.const 1))
+  (func $i64_callee (result i32) (call $bump) (i32.store8 (i32.const 8) (i32.const 4)) (i32.const 2))
+  (func $i64_bool (result i32) (call $bump) (i32.store8 (i32.const 8) (i32.const 5)) (i32.const 0))
+  (func $f32_left (result f32) (call $bump) (i32.store8 (i32.const 8) (i32.const 1)) (f32.const 0))
+  (func $f32_right (result f32) (call $bump) (i32.store8 (i32.const 8) (i32.const 2)) (f32.const 1))
+  (func $f32_another (result f32) (call $bump) (i32.store8 (i32.const 8) (i32.const 3)) (f32.const 1))
+  (func $f32_callee (result i32) (call $bump) (i32.store8 (i32.const 8) (i32.const 4)) (i32.const 4))
+  (func $f32_bool (result i32) (call $bump) (i32.store8 (i32.const 8) (i32.const 5)) (i32.const 0))
+  (func $f64_left (result f64) (call $bump) (i32.store8 (i32.const 8) (i32.const 1)) (f64.const 0))
+  (func $f64_right (result f64) (call $bump) (i32.store8 (i32.const 8) (i32.const 2)) (f64.const 1))
+  (func $f64_another (result f64) (call $bump) (i32.store8 (i32.const 8) (i32.const 3)) (f64.const 1))
+  (func $f64_callee (result i32) (call $bump) (i32.store8 (i32.const 8) (i32.const 4)) (i32.const 6))
+  (func $f64_bool (result i32) (call $bump) (i32.store8 (i32.const 8) (i32.const 5)) (i32.const 0))
+  (func $i32_dummy (param i32 i32))
+  (func $i64_dummy (param i64 i64))
+  (func $f32_dummy (param f32 f32))
+  (func $f64_dummy (param f64 f64))
+
+  (func (export "i32_add") (result i32) (call $reset) (drop (i32.add (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_sub") (result i32) (call $reset) (drop (i32.sub (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_mul") (result i32) (call $reset) (drop (i32.mul (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_div_s") (result i32) (call $reset) (drop (i32.div_s (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_div_u") (result i32) (call $reset) (drop (i32.div_u (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_rem_s") (result i32) (call $reset) (drop (i32.rem_s (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_rem_u") (result i32) (call $reset) (drop (i32.rem_u (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_and") (result i32) (call $reset) (drop (i32.and (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_or") (result i32) (call $reset) (drop (i32.or (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_xor") (result i32) (call $reset) (drop (i32.xor (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_shl") (result i32) (call $reset) (drop (i32.shl (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_shr_u") (result i32) (call $reset) (drop (i32.shr_u (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_shr_s") (result i32) (call $reset) (drop (i32.shr_s (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_eq") (result i32) (call $reset) (drop (i32.eq (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_ne") (result i32) (call $reset) (drop (i32.ne (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_lt_s") (result i32) (call $reset) (drop (i32.lt_s (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_le_s") (result i32) (call $reset) (drop (i32.le_s (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_lt_u") (result i32) (call $reset) (drop (i32.lt_u (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_le_u") (result i32) (call $reset) (drop (i32.le_u (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_gt_s") (result i32) (call $reset) (drop (i32.gt_s (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_ge_s") (result i32) (call $reset) (drop (i32.ge_s (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_gt_u") (result i32) (call $reset) (drop (i32.gt_u (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_ge_u") (result i32) (call $reset) (drop (i32.ge_u (call $i32_left) (call $i32_right))) (call $get))
+  (func (export "i32_store") (result i32) (call $reset) (i32.store (call $i32_left) (call $i32_right)) (call $get))
+  (func (export "i32_store8") (result i32) (call $reset) (i32.store8 (call $i32_left) (call $i32_right)) (call $get))
+  (func (export "i32_store16") (result i32) (call $reset) (i32.store16 (call $i32_left) (call $i32_right)) (call $get))
+  (func (export "i32_call") (result i32) (call $reset) (call $i32_dummy (call $i32_left) (call $i32_right)) (call $get))
+  (func (export "i32_call_indirect") (result i32) (call $reset) (drop (call_indirect (type $i32_T) (call $i32_left) (call $i32_right) (call $i32_callee))) (call $get))
+  (func (export "i32_select") (result i32) (call $reset) (drop (select (call $i32_left) (call $i32_right) (call $i32_bool))) (call $get))
+
+  (func (export "i64_add") (result i32) (call $reset) (drop (i64.add (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_sub") (result i32) (call $reset) (drop (i64.sub (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_mul") (result i32) (call $reset) (drop (i64.mul (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_div_s") (result i32) (call $reset) (drop (i64.div_s (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_div_u") (result i32) (call $reset) (drop (i64.div_u (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_rem_s") (result i32) (call $reset) (drop (i64.rem_s (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_rem_u") (result i32) (call $reset) (drop (i64.rem_u (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_and") (result i32) (call $reset) (drop (i64.and (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_or") (result i32) (call $reset) (drop (i64.or (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_xor") (result i32) (call $reset) (drop (i64.xor (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_shl") (result i32) (call $reset) (drop (i64.shl (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_shr_u") (result i32) (call $reset) (drop (i64.shr_u (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_shr_s") (result i32) (call $reset) (drop (i64.shr_s (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_eq") (result i32) (call $reset) (drop (i64.eq (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_ne") (result i32) (call $reset) (drop (i64.ne (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_lt_s") (result i32) (call $reset) (drop (i64.lt_s (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_le_s") (result i32) (call $reset) (drop (i64.le_s (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_lt_u") (result i32) (call $reset) (drop (i64.lt_u (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_le_u") (result i32) (call $reset) (drop (i64.le_u (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_gt_s") (result i32) (call $reset) (drop (i64.gt_s (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_ge_s") (result i32) (call $reset) (drop (i64.ge_s (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_gt_u") (result i32) (call $reset) (drop (i64.gt_u (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_ge_u") (result i32) (call $reset) (drop (i64.ge_u (call $i64_left) (call $i64_right))) (call $get))
+  (func (export "i64_store") (result i32) (call $reset) (i64.store (call $i32_left) (call $i64_right)) (call $get))
+  (func (export "i64_store8") (result i32) (call $reset) (i64.store8 (call $i32_left) (call $i64_right)) (call $get))
+  (func (export "i64_store16") (result i32) (call $reset) (i64.store16 (call $i32_left) (call $i64_right)) (call $get))
+  (func (export "i64_store32") (result i32) (call $reset) (i64.store32 (call $i32_left) (call $i64_right)) (call $get))
+  (func (export "i64_call") (result i32) (call $reset) (call $i64_dummy (call $i64_left) (call $i64_right)) (call $get))
+  (func (export "i64_call_indirect") (result i32) (call $reset) (drop (call_indirect (type $i64_T) (call $i64_left) (call $i64_right) (call $i64_callee))) (call $get))
+  (func (export "i64_select") (result i32) (call $reset) (drop (select (call $i64_left) (call $i64_right) (call $i64_bool))) (call $get))
+
+  (func (export "f32_add") (result i32) (call $reset) (drop (f32.add (call $f32_left) (call $f32_right))) (call $get))
+  (func (export "f32_sub") (result i32) (call $reset) (drop (f32.sub (call $f32_left) (call $f32_right))) (call $get))
+  (func (export "f32_mul") (result i32) (call $reset) (drop (f32.mul (call $f32_left) (call $f32_right))) (call $get))
+  (func (export "f32_div") (result i32) (call $reset) (drop (f32.div (call $f32_left) (call $f32_right))) (call $get))
+  (func (export "f32_copysign") (result i32) (call $reset) (drop (f32.copysign (call $f32_left) (call $f32_right))) (call $get))
+  (func (export "f32_eq") (result i32) (call $reset) (drop (f32.eq (call $f32_left) (call $f32_right))) (call $get))
+  (func (export "f32_ne") (result i32) (call $reset) (drop (f32.ne (call $f32_left) (call $f32_right))) (call $get))
+  (func (export "f32_lt") (result i32) (call $reset) (drop (f32.lt (call $f32_left) (call $f32_right))) (call $get))
+  (func (export "f32_le") (result i32) (call $reset) (drop (f32.le (call $f32_left) (call $f32_right))) (call $get))
+  (func (export "f32_gt") (result i32) (call $reset) (drop (f32.gt (call $f32_left) (call $f32_right))) (call $get))
+  (func (export "f32_ge") (result i32) (call $reset) (drop (f32.ge (call $f32_left) (call $f32_right))) (call $get))
+  (func (export "f32_min") (result i32) (call $reset) (drop (f32.min (call $f32_left) (call $f32_right))) (call $get))
+  (func (export "f32_max") (result i32) (call $reset) (drop (f32.max (call $f32_left) (call $f32_right))) (call $get))
+  (func (export "f32_store") (result i32) (call $reset) (f32.store (call $i32_left) (call $f32_right)) (call $get))
+  (func (export "f32_call") (result i32) (call $reset) (call $f32_dummy (call $f32_left) (call $f32_right)) (call $get))
+  (func (export "f32_call_indirect") (result i32) (call $reset) (drop (call_indirect (type $f32_T) (call $f32_left) (call $f32_right) (call $f32_callee))) (call $get))
+  (func (export "f32_select") (result i32) (call $reset) (drop (select (call $f32_left) (call $f32_right) (call $f32_bool))) (call $get))
+
+  (func (export "f64_add") (result i32) (call $reset) (drop (f64.add (call $f64_left) (call $f64_right))) (call $get))
+  (func (export "f64_sub") (result i32) (call $reset) (drop (f64.sub (call $f64_left) (call $f64_right))) (call $get))
+  (func (export "f64_mul") (result i32) (call $reset) (drop (f64.mul (call $f64_left) (call $f64_right))) (call $get))
+  (func (export "f64_div") (result i32) (call $reset) (drop (f64.div (call $f64_left) (call $f64_right))) (call $get))
+  (func (export "f64_copysign") (result i32) (call $reset) (drop (f64.copysign (call $f64_left) (call $f64_right))) (call $get))
+  (func (export "f64_eq") (result i32) (call $reset) (drop (f64.eq (call $f64_left) (call $f64_right))) (call $get))
+  (func (export "f64_ne") (result i32) (call $reset) (drop (f64.ne (call $f64_left) (call $f64_right))) (call $get))
+  (func (export "f64_lt") (result i32) (call $reset) (drop (f64.lt (call $f64_left) (call $f64_right))) (call $get))
+  (func (export "f64_le") (result i32) (call $reset) (drop (f64.le (call $f64_left) (call $f64_right))) (call $get))
+  (func (export "f64_gt") (result i32) (call $reset) (drop (f64.gt (call $f64_left) (call $f64_right))) (call $get))
+  (func (export "f64_ge") (result i32) (call $reset) (drop (f64.ge (call $f64_left) (call $f64_right))) (call $get))
+  (func (export "f64_min") (result i32) (call $reset) (drop (f64.min (call $f64_left) (call $f64_right))) (call $get))
+  (func (export "f64_max") (result i32) (call $reset) (drop (f64.max (call $f64_left) (call $f64_right))) (call $get))
+  (func (export "f64_store") (result i32) (call $reset) (f64.store (call $i32_left) (call $f64_right)) (call $get))
+  (func (export "f64_call") (result i32) (call $reset) (call $f64_dummy (call $f64_left) (call $f64_right)) (call $get))
+  (func (export "f64_call_indirect") (result i32) (call $reset) (drop (call_indirect (type $f64_T) (call $f64_left) (call $f64_right) (call $f64_callee))) (call $get))
+  (func (export "f64_select") (result i32) (call $reset) (drop (select (call $f64_left) (call $f64_right) (call $f64_bool))) (call $get))
+
+  (func (export "br_if") (result i32)
+    (block (result i32)
+      (call $reset)
+      (drop (br_if 0 (call $i32_left) (i32.and (call $i32_right) (i32.const 0))))
+      (call $get)
+    )
+  )
+  (func (export "br_table") (result i32)
+    (block $a (result i32)
+      (call $reset)
+      (drop
+        (block $b (result i32)
+          (br_table $a $b (call $i32_left) (call $i32_right))
+        )
+      )
+      (call $get)
+    )
+  )
+)
+
+(assert_return (invoke "i32_add") (i32.const 0x0102))     (assert_return (invoke "i64_add") (i32.const 0x0102))
+(assert_return (invoke "i32_sub") (i32.const 0x0102))     (assert_return (invoke "i64_sub") (i32.const 0x0102))
+(assert_return (invoke "i32_mul") (i32.const 0x0102))     (assert_return (invoke "i64_mul") (i32.const 0x0102))
+(assert_return (invoke "i32_div_s") (i32.const 0x0102))   (assert_return (invoke "i64_div_s") (i32.const 0x0102))
+(assert_return (invoke "i32_div_u") (i32.const 0x0102))   (assert_return (invoke "i64_div_u") (i32.const 0x0102))
+(assert_return (invoke "i32_rem_s") (i32.const 0x0102))   (assert_return (invoke "i64_rem_s") (i32.const 0x0102))
+(assert_return (invoke "i32_rem_u") (i32.const 0x0102))   (assert_return (invoke "i64_rem_u") (i32.const 0x0102))
+(assert_return (invoke "i32_and") (i32.const 0x0102))     (assert_return (invoke "i64_and") (i32.const 0x0102))
+(assert_return (invoke "i32_or") (i32.const 0x0102))      (assert_return (invoke "i64_or") (i32.const 0x0102))
+(assert_return (invoke "i32_xor") (i32.const 0x0102))     (assert_return (invoke "i64_xor") (i32.const 0x0102))
+(assert_return (invoke "i32_shl") (i32.const 0x0102))     (assert_return (invoke "i64_shl") (i32.const 0x0102))
+(assert_return (invoke "i32_shr_u") (i32.const 0x0102))   (assert_return (invoke "i64_shr_u") (i32.const 0x0102))
+(assert_return (invoke "i32_shr_s") (i32.const 0x0102))   (assert_return (invoke "i64_shr_s") (i32.const 0x0102))
+(assert_return (invoke "i32_eq") (i32.const 0x0102))      (assert_return (invoke "i64_eq") (i32.const 0x0102))
+(assert_return (invoke "i32_ne") (i32.const 0x0102))      (assert_return (invoke "i64_ne") (i32.const 0x0102))
+(assert_return (invoke "i32_lt_s") (i32.const 0x0102))    (assert_return (invoke "i64_lt_s") (i32.const 0x0102))
+(assert_return (invoke "i32_le_s") (i32.const 0x0102))    (assert_return (invoke "i64_le_s") (i32.const 0x0102))
+(assert_return (invoke "i32_lt_u") (i32.const 0x0102))    (assert_return (invoke "i64_lt_u") (i32.const 0x0102))
+(assert_return (invoke "i32_le_u") (i32.const 0x0102))    (assert_return (invoke "i64_le_u") (i32.const 0x0102))
+(assert_return (invoke "i32_gt_s") (i32.const 0x0102))    (assert_return (invoke "i64_gt_s") (i32.const 0x0102))
+(assert_return (invoke "i32_ge_s") (i32.const 0x0102))    (assert_return (invoke "i64_ge_s") (i32.const 0x0102))
+(assert_return (invoke "i32_gt_u") (i32.const 0x0102))    (assert_return (invoke "i64_gt_u") (i32.const 0x0102))
+(assert_return (invoke "i32_ge_u") (i32.const 0x0102))    (assert_return (invoke "i64_ge_u") (i32.const 0x0102))
+(assert_return (invoke "i32_store") (i32.const 0x0102))   (assert_return (invoke "i64_store") (i32.const 0x0102))
+(assert_return (invoke "i32_store8") (i32.const 0x0102))  (assert_return (invoke "i64_store8") (i32.const 0x0102))
+(assert_return (invoke "i32_store16") (i32.const 0x0102)) (assert_return (invoke "i64_store16") (i32.const 0x0102))
+(assert_return (invoke "i64_store32") (i32.const 0x0102))
+(assert_return (invoke "i32_call") (i32.const 0x0102))    (assert_return (invoke "i64_call") (i32.const 0x0102))
+(assert_return (invoke "i32_call_indirect") (i32.const 0x010204))
+(assert_return (invoke "i64_call_indirect") (i32.const 0x010204))
+(assert_return (invoke "i32_select") (i32.const 0x010205))  (assert_return (invoke "i64_select") (i32.const 0x010205))
+
+(assert_return (invoke "f32_add") (i32.const 0x0102))     (assert_return (invoke "f64_add") (i32.const 0x0102))
+(assert_return (invoke "f32_sub") (i32.const 0x0102))     (assert_return (invoke "f64_sub") (i32.const 0x0102))
+(assert_return (invoke "f32_mul") (i32.const 0x0102))     (assert_return (invoke "f64_mul") (i32.const 0x0102))
+(assert_return (invoke "f32_div") (i32.const 0x0102))     (assert_return (invoke "f64_div") (i32.const 0x0102))
+(assert_return (invoke "f32_copysign") (i32.const 0x0102))(assert_return (invoke "f64_copysign") (i32.const 0x0102))
+(assert_return (invoke "f32_eq") (i32.const 0x0102))      (assert_return (invoke "f64_eq") (i32.const 0x0102))
+(assert_return (invoke "f32_ne") (i32.const 0x0102))      (assert_return (invoke "f64_ne") (i32.const 0x0102))
+(assert_return (invoke "f32_lt") (i32.const 0x0102))      (assert_return (invoke "f64_lt") (i32.const 0x0102))
+(assert_return (invoke "f32_le") (i32.const 0x0102))      (assert_return (invoke "f64_le") (i32.const 0x0102))
+(assert_return (invoke "f32_gt") (i32.const 0x0102))      (assert_return (invoke "f64_gt") (i32.const 0x0102))
+(assert_return (invoke "f32_ge") (i32.const 0x0102))      (assert_return (invoke "f64_ge") (i32.const 0x0102))
+(assert_return (invoke "f32_min") (i32.const 0x0102))     (assert_return (invoke "f64_min") (i32.const 0x0102))
+(assert_return (invoke "f32_max") (i32.const 0x0102))     (assert_return (invoke "f64_max") (i32.const 0x0102))
+(assert_return (invoke "f32_store") (i32.const 0x0102))   (assert_return (invoke "f64_store") (i32.const 0x0102))
+(assert_return (invoke "f32_call") (i32.const 0x0102))    (assert_return (invoke "f64_call") (i32.const 0x0102))
+(assert_return (invoke "f32_call_indirect") (i32.const 0x010204))
+(assert_return (invoke "f64_call_indirect") (i32.const 0x010204))
+(assert_return (invoke "f32_select") (i32.const 0x010205))  (assert_return (invoke "f64_select") (i32.const 0x010205))
+
+(assert_return (invoke "br_if") (i32.const 0x0102))
+(assert_return (invoke "br_table") (i32.const 0x0102))
diff --git a/binaryen/test/spec/linking.wast b/binaryen/test/spec/linking.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/linking.wast
@@ -0,0 +1,388 @@
+;; Functions
+
+(module $Mf
+  (func (export "call") (result i32) (call $g))
+  (func $g (result i32) (i32.const 2))
+)
+(register "Mf" $Mf)
+
+(module $Nf
+  (func $f (import "Mf" "call") (result i32))
+  (export "Mf.call" (func $f))
+  (func (export "call Mf.call") (result i32) (call $f))
+  (func (export "call") (result i32) (call $g))
+  (func $g (result i32) (i32.const 3))
+)
+
+(assert_return (invoke $Mf "call") (i32.const 2))
+(assert_return (invoke $Nf "Mf.call") (i32.const 2))
+(assert_return (invoke $Nf "call") (i32.const 3))
+(assert_return (invoke $Nf "call Mf.call") (i32.const 2))
+
+(module
+  (import "spectest" "print_i32" (func $f (param i32)))
+  (export "print" (func $f))
+)
+(register "reexport_f")
+(assert_unlinkable
+  (module (import "reexport_f" "print" (func (param i64))))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "reexport_f" "print" (func (param i32) (result i32))))
+  "incompatible import type"
+)
+
+
+;; Globals
+
+(module $Mg
+  (global $glob (export "glob") i32 (i32.const 42))
+  (func (export "get") (result i32) (global.get $glob))
+
+  ;; export mutable globals
+  (global $mut_glob (export "mut_glob") (mut i32) (i32.const 142))
+  (func (export "get_mut") (result i32) (global.get $mut_glob))
+  (func (export "set_mut") (param i32) (global.set $mut_glob (local.get 0)))
+)
+(register "Mg" $Mg)
+
+(module $Ng
+  (global $x (import "Mg" "glob") i32)
+  (global $mut_glob (import "Mg" "mut_glob") (mut i32))
+  (func $f (import "Mg" "get") (result i32))
+  (func $get_mut (import "Mg" "get_mut") (result i32))
+  (func $set_mut (import "Mg" "set_mut") (param i32))
+
+  (export "Mg.glob" (global $x))
+  (export "Mg.get" (func $f))
+  (global $glob (export "glob") i32 (i32.const 43))
+  (func (export "get") (result i32) (global.get $glob))
+
+  (export "Mg.mut_glob" (global $mut_glob))
+  (export "Mg.get_mut" (func $get_mut))
+  (export "Mg.set_mut" (func $set_mut))
+)
+
+(assert_return (get $Mg "glob") (i32.const 42))
+(assert_return (get $Ng "Mg.glob") (i32.const 42))
+(assert_return (get $Ng "glob") (i32.const 43))
+(assert_return (invoke $Mg "get") (i32.const 42))
+(assert_return (invoke $Ng "Mg.get") (i32.const 42))
+(assert_return (invoke $Ng "get") (i32.const 43))
+
+(assert_return (get $Mg "mut_glob") (i32.const 142))
+(assert_return (get $Ng "Mg.mut_glob") (i32.const 142))
+(assert_return (invoke $Mg "get_mut") (i32.const 142))
+(assert_return (invoke $Ng "Mg.get_mut") (i32.const 142))
+
+(assert_return (invoke $Mg "set_mut" (i32.const 241)))
+(assert_return (get $Mg "mut_glob") (i32.const 241))
+(assert_return (get $Ng "Mg.mut_glob") (i32.const 241))
+(assert_return (invoke $Mg "get_mut") (i32.const 241))
+(assert_return (invoke $Ng "Mg.get_mut") (i32.const 241))
+
+
+(assert_unlinkable
+  (module (import "Mg" "mut_glob" (global i32)))
+  "incompatible import type"
+)
+(assert_unlinkable
+  (module (import "Mg" "glob" (global (mut i32))))
+  "incompatible import type"
+)
+
+;; Tables
+
+(module $Mt
+  (type (func (result i32)))
+  (type (func))
+
+  (table (export "tab") 10 funcref)
+  (elem (i32.const 2) $g $g $g $g)
+  (func $g (result i32) (i32.const 4))
+  (func (export "h") (result i32) (i32.const -4))
+
+  (func (export "call") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0))
+  )
+)
+(register "Mt" $Mt)
+
+(module $Nt
+  (type (func))
+  (type (func (result i32)))
+
+  (func $f (import "Mt" "call") (param i32) (result i32))
+  (func $h (import "Mt" "h") (result i32))
+
+  (table funcref (elem $g $g $g $h $f))
+  (func $g (result i32) (i32.const 5))
+
+  (export "Mt.call" (func $f))
+  (func (export "call Mt.call") (param i32) (result i32)
+    (call $f (local.get 0))
+  )
+  (func (export "call") (param i32) (result i32)
+    (call_indirect (type 1) (local.get 0))
+  )
+)
+
+(assert_return (invoke $Mt "call" (i32.const 2)) (i32.const 4))
+(assert_return (invoke $Nt "Mt.call" (i32.const 2)) (i32.const 4))
+(assert_return (invoke $Nt "call" (i32.const 2)) (i32.const 5))
+(assert_return (invoke $Nt "call Mt.call" (i32.const 2)) (i32.const 4))
+
+(assert_trap (invoke $Mt "call" (i32.const 1)) "uninitialized")
+(assert_trap (invoke $Nt "Mt.call" (i32.const 1)) "uninitialized")
+(assert_return (invoke $Nt "call" (i32.const 1)) (i32.const 5))
+(assert_trap (invoke $Nt "call Mt.call" (i32.const 1)) "uninitialized")
+
+(assert_trap (invoke $Mt "call" (i32.const 0)) "uninitialized")
+(assert_trap (invoke $Nt "Mt.call" (i32.const 0)) "uninitialized")
+(assert_return (invoke $Nt "call" (i32.const 0)) (i32.const 5))
+(assert_trap (invoke $Nt "call Mt.call" (i32.const 0)) "uninitialized")
+
+(assert_trap (invoke $Mt "call" (i32.const 20)) "undefined")
+(assert_trap (invoke $Nt "Mt.call" (i32.const 20)) "undefined")
+(assert_trap (invoke $Nt "call" (i32.const 7)) "undefined")
+(assert_trap (invoke $Nt "call Mt.call" (i32.const 20)) "undefined")
+
+(assert_return (invoke $Nt "call" (i32.const 3)) (i32.const -4))
+(assert_trap (invoke $Nt "call" (i32.const 4)) "indirect call")
+
+(module $Ot
+  (type (func (result i32)))
+
+  (func $h (import "Mt" "h") (result i32))
+  (table (import "Mt" "tab") 5 funcref)
+  (elem (i32.const 1) $i $h)
+  (func $i (result i32) (i32.const 6))
+
+  (func (export "call") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0))
+  )
+)
+
+(assert_return (invoke $Mt "call" (i32.const 3)) (i32.const 4))
+(assert_return (invoke $Nt "Mt.call" (i32.const 3)) (i32.const 4))
+(assert_return (invoke $Nt "call Mt.call" (i32.const 3)) (i32.const 4))
+(assert_return (invoke $Ot "call" (i32.const 3)) (i32.const 4))
+
+(assert_return (invoke $Mt "call" (i32.const 2)) (i32.const -4))
+(assert_return (invoke $Nt "Mt.call" (i32.const 2)) (i32.const -4))
+(assert_return (invoke $Nt "call" (i32.const 2)) (i32.const 5))
+(assert_return (invoke $Nt "call Mt.call" (i32.const 2)) (i32.const -4))
+(assert_return (invoke $Ot "call" (i32.const 2)) (i32.const -4))
+
+(assert_return (invoke $Mt "call" (i32.const 1)) (i32.const 6))
+(assert_return (invoke $Nt "Mt.call" (i32.const 1)) (i32.const 6))
+(assert_return (invoke $Nt "call" (i32.const 1)) (i32.const 5))
+(assert_return (invoke $Nt "call Mt.call" (i32.const 1)) (i32.const 6))
+(assert_return (invoke $Ot "call" (i32.const 1)) (i32.const 6))
+
+(assert_trap (invoke $Mt "call" (i32.const 0)) "uninitialized")
+(assert_trap (invoke $Nt "Mt.call" (i32.const 0)) "uninitialized")
+(assert_return (invoke $Nt "call" (i32.const 0)) (i32.const 5))
+(assert_trap (invoke $Nt "call Mt.call" (i32.const 0)) "uninitialized")
+(assert_trap (invoke $Ot "call" (i32.const 0)) "uninitialized")
+
+(assert_trap (invoke $Ot "call" (i32.const 20)) "undefined")
+
+(module
+  (table (import "Mt" "tab") 0 funcref)
+  (elem (i32.const 9) $f)
+  (func $f)
+)
+
+(module $G1 (global (export "g") i32 (i32.const 5)))
+(register "G1" $G1)
+(module $G2
+  (global (import "G1" "g") i32)
+  (global (export "g") i32 (global.get 0))
+)
+(assert_return (get $G2 "g") (i32.const 5))
+
+(assert_unlinkable
+  (module
+    (table (import "Mt" "tab") 0 funcref)
+    (elem (i32.const 10) $f)
+    (func $f)
+  )
+  "elements segment does not fit"
+)
+
+(assert_unlinkable
+  (module
+    (table (import "Mt" "tab") 10 funcref)
+    (memory (import "Mt" "mem") 1)  ;; does not exist
+    (func $f (result i32) (i32.const 0))
+    (elem (i32.const 7) $f)
+    (elem (i32.const 9) $f)
+  )
+  "unknown import"
+)
+(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized")
+
+(assert_unlinkable
+  (module
+    (table (import "Mt" "tab") 10 funcref)
+    (func $f (result i32) (i32.const 0))
+    (elem (i32.const 7) $f)
+    (elem (i32.const 12) $f)  ;; out of bounds
+  )
+  "elements segment does not fit"
+)
+(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized")
+
+(assert_unlinkable
+  (module
+    (table (import "Mt" "tab") 10 funcref)
+    (func $f (result i32) (i32.const 0))
+    (elem (i32.const 7) $f)
+    (memory 1)
+    (data (i32.const 0x10000) "d") ;; out of bounds
+  )
+  "data segment does not fit"
+)
+(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized")
+
+
+;; Memories
+
+(module $Mm
+  (memory (export "mem") 1 5)
+  (data (i32.const 10) "\00\01\02\03\04\05\06\07\08\09")
+
+  (func (export "load") (param $a i32) (result i32)
+    (i32.load8_u (local.get 0))
+  )
+)
+(register "Mm" $Mm)
+
+(module $Nm
+  (func $loadM (import "Mm" "load") (param i32) (result i32))
+
+  (memory 1)
+  (data (i32.const 10) "\f0\f1\f2\f3\f4\f5")
+
+  (export "Mm.load" (func $loadM))
+  (func (export "load") (param $a i32) (result i32)
+    (i32.load8_u (local.get 0))
+  )
+)
+
+(assert_return (invoke $Mm "load" (i32.const 12)) (i32.const 2))
+(assert_return (invoke $Nm "Mm.load" (i32.const 12)) (i32.const 2))
+(assert_return (invoke $Nm "load" (i32.const 12)) (i32.const 0xf2))
+
+(module $Om
+  (memory (import "Mm" "mem") 1)
+  (data (i32.const 5) "\a0\a1\a2\a3\a4\a5\a6\a7")
+
+  (func (export "load") (param $a i32) (result i32)
+    (i32.load8_u (local.get 0))
+  )
+)
+
+(assert_return (invoke $Mm "load" (i32.const 12)) (i32.const 0xa7))
+(assert_return (invoke $Nm "Mm.load" (i32.const 12)) (i32.const 0xa7))
+(assert_return (invoke $Nm "load" (i32.const 12)) (i32.const 0xf2))
+(assert_return (invoke $Om "load" (i32.const 12)) (i32.const 0xa7))
+
+(module
+  (memory (import "Mm" "mem") 0)
+  (data (i32.const 0xffff) "a")
+)
+
+(assert_unlinkable
+  (module
+    (memory (import "Mm" "mem") 0)
+    (data (i32.const 0x10000) "a")
+  )
+  "data segment does not fit"
+)
+
+(module $Pm
+  (memory (import "Mm" "mem") 1 8)
+
+  (func (export "grow") (param $a i32) (result i32)
+    (memory.grow (local.get 0))
+  )
+)
+
+(assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 1))
+(assert_return (invoke $Pm "grow" (i32.const 2)) (i32.const 1))
+(assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 3))
+(assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const 3))
+(assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const 4))
+(assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 5))
+(assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const -1))
+(assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 5))
+
+(assert_unlinkable
+  (module
+    (func $host (import "spectest" "print"))
+    (memory (import "Mm" "mem") 1)
+    (table (import "Mm" "tab") 0 funcref)  ;; does not exist
+    (data (i32.const 0) "abc")
+  )
+  "unknown import"
+)
+(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0))
+
+(assert_unlinkable
+  (module
+    (memory (import "Mm" "mem") 1)
+    (data (i32.const 0) "abc")
+    (data (i32.const 0x50000) "d") ;; out of bounds
+  )
+  "data segment does not fit"
+)
+(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0))
+
+(assert_unlinkable
+  (module
+    (memory (import "Mm" "mem") 1)
+    (data (i32.const 0) "abc")
+    (table 0 funcref)
+    (func)
+    (elem (i32.const 0) 0) ;; out of bounds
+  )
+  "elements segment does not fit"
+)
+(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0))
+
+;; Store is modified if the start function traps.
+(module $Ms
+  (type $t (func (result i32)))
+  (memory (export "memory") 1)
+  (table (export "table") 1 funcref)
+  (func (export "get memory[0]") (type $t)
+    (i32.load8_u (i32.const 0))
+  )
+  (func (export "get table[0]") (type $t)
+    (call_indirect (type $t) (i32.const 0))
+  )
+)
+(register "Ms" $Ms)
+
+(assert_trap
+  (module
+    (import "Ms" "memory" (memory 1))
+    (import "Ms" "table" (table 1 funcref))
+    (data (i32.const 0) "hello")
+    (elem (i32.const 0) $f)
+    (func $f (result i32)
+      (i32.const 0xdead)
+    )
+    (func $main
+      (unreachable)
+    )
+    (start $main)
+  )
+  "unreachable"
+)
+
+(assert_return (invoke $Ms "get memory[0]") (i32.const 104))  ;; 'h'
+(assert_return (invoke $Ms "get table[0]") (i32.const 0xdead))
diff --git a/binaryen/test/spec/load.wast b/binaryen/test/spec/load.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/load.wast
@@ -0,0 +1,567 @@
+;; Load operator as the argument of control constructs and instructions
+
+(module
+  (memory 1)
+
+  (func (export "as-br-value") (result i32)
+    (block (result i32) (br 0 (i32.load (i32.const 0))))
+  )
+
+  (func (export "as-br_if-cond")
+    (block (br_if 0 (i32.load (i32.const 0))))
+  )
+  (func (export "as-br_if-value") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (i32.load (i32.const 0)) (i32.const 1))) (i32.const 7)
+    )
+  )
+  (func (export "as-br_if-value-cond") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (i32.const 6) (i32.load (i32.const 0)))) (i32.const 7)
+    )
+  )
+
+  (func (export "as-br_table-index")
+    (block (br_table 0 0 0 (i32.load (i32.const 0))))
+  )
+  (func (export "as-br_table-value") (result i32)
+    (block (result i32)
+      (br_table 0 0 0 (i32.load (i32.const 0)) (i32.const 1)) (i32.const 7)
+    )
+  )
+  (func (export "as-br_table-value-index") (result i32)
+    (block (result i32)
+      (br_table 0 0 (i32.const 6) (i32.load (i32.const 0))) (i32.const 7)
+    )
+  )
+
+  (func (export "as-return-value") (result i32)
+    (return (i32.load (i32.const 0)))
+  )
+
+  (func (export "as-if-cond") (result i32)
+    (if (result i32) (i32.load (i32.const 0))
+      (then (i32.const 0)) (else (i32.const 1))
+    )
+  )
+  (func (export "as-if-then") (result i32)
+    (if (result i32) (i32.const 1)
+      (then (i32.load (i32.const 0))) (else (i32.const 0))
+    )
+  )
+  (func (export "as-if-else") (result i32)
+    (if (result i32) (i32.const 0)
+      (then (i32.const 0)) (else (i32.load (i32.const 0)))
+    )
+  )
+
+  (func (export "as-select-first") (param i32 i32) (result i32)
+    (select (i32.load (i32.const 0)) (local.get 0) (local.get 1))
+  )
+  (func (export "as-select-second") (param i32 i32) (result i32)
+    (select (local.get 0) (i32.load (i32.const 0)) (local.get 1))
+  )
+  (func (export "as-select-cond") (result i32)
+    (select (i32.const 0) (i32.const 1) (i32.load (i32.const 0)))
+  )
+
+  (func $f (param i32 i32 i32) (result i32) (i32.const -1))
+  (func (export "as-call-first") (result i32)
+    (call $f (i32.load (i32.const 0)) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-call-mid") (result i32)
+    (call $f (i32.const 1) (i32.load (i32.const 0)) (i32.const 3))
+  )
+  (func (export "as-call-last") (result i32)
+    (call $f (i32.const 1) (i32.const 2) (i32.load (i32.const 0)))
+  )
+
+  (type $sig (func (param i32 i32 i32) (result i32)))
+  (table funcref (elem $f))
+  (func (export "as-call_indirect-first") (result i32)
+    (call_indirect (type $sig)
+      (i32.load (i32.const 0)) (i32.const 2) (i32.const 3) (i32.const 0)
+    )
+  )
+  (func (export "as-call_indirect-mid") (result i32)
+    (call_indirect (type $sig)
+      (i32.const 1) (i32.load (i32.const 0)) (i32.const 3) (i32.const 0)
+    )
+  )
+  (func (export "as-call_indirect-last") (result i32)
+    (call_indirect (type $sig)
+      (i32.const 1) (i32.const 2) (i32.load (i32.const 0)) (i32.const 0)
+    )
+  )
+  (func (export "as-call_indirect-index") (result i32)
+    (call_indirect (type $sig)
+      (i32.const 1) (i32.const 2) (i32.const 3) (i32.load (i32.const 0))
+    )
+  )
+
+  (func (export "as-local.set-value") (local i32)
+    (local.set 0 (i32.load (i32.const 0)))
+  )
+  (func (export "as-local.tee-value") (result i32) (local i32)
+    (local.tee 0 (i32.load (i32.const 0)))
+  )
+  (global $g (mut i32) (i32.const 0))
+  (func (export "as-global.set-value") (local i32)
+    (global.set $g (i32.load (i32.const 0)))
+  )
+
+  (func (export "as-load-address") (result i32)
+    (i32.load (i32.load (i32.const 0)))
+  )
+  (func (export "as-loadN-address") (result i32)
+    (i32.load8_s (i32.load (i32.const 0)))
+  )
+
+  (func (export "as-store-address")
+    (i32.store (i32.load (i32.const 0)) (i32.const 7))
+  )
+  (func (export "as-store-value")
+    (i32.store (i32.const 2) (i32.load (i32.const 0)))
+  )
+
+  (func (export "as-storeN-address")
+    (i32.store8 (i32.load8_s (i32.const 0)) (i32.const 7))
+  )
+  (func (export "as-storeN-value")
+    (i32.store16 (i32.const 2) (i32.load (i32.const 0)))
+  )
+
+  (func (export "as-unary-operand") (result i32)
+    (i32.clz (i32.load (i32.const 100)))
+  )
+
+  (func (export "as-binary-left") (result i32)
+    (i32.add (i32.load (i32.const 100)) (i32.const 10))
+  )
+  (func (export "as-binary-right") (result i32)
+    (i32.sub (i32.const 10) (i32.load (i32.const 100)))
+  )
+
+  (func (export "as-test-operand") (result i32)
+    (i32.eqz (i32.load (i32.const 100)))
+  )
+
+  (func (export "as-compare-left") (result i32)
+    (i32.le_s (i32.load (i32.const 100)) (i32.const 10))
+  )
+  (func (export "as-compare-right") (result i32)
+    (i32.ne (i32.const 10) (i32.load (i32.const 100)))
+  )
+
+  (func (export "as-memory.grow-size") (result i32)
+    (memory.grow (i32.load (i32.const 100)))
+  )
+)
+
+(assert_return (invoke "as-br-value") (i32.const 0))
+
+(assert_return (invoke "as-br_if-cond"))
+(assert_return (invoke "as-br_if-value") (i32.const 0))
+(assert_return (invoke "as-br_if-value-cond") (i32.const 7))
+
+(assert_return (invoke "as-br_table-index"))
+(assert_return (invoke "as-br_table-value") (i32.const 0))
+(assert_return (invoke "as-br_table-value-index") (i32.const 6))
+
+(assert_return (invoke "as-return-value") (i32.const 0))
+
+(assert_return (invoke "as-if-cond") (i32.const 1))
+(assert_return (invoke "as-if-then") (i32.const 0))
+(assert_return (invoke "as-if-else") (i32.const 0))
+
+(assert_return (invoke "as-select-first" (i32.const 0) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "as-select-second" (i32.const 0) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-select-cond") (i32.const 1))
+
+(assert_return (invoke "as-call-first") (i32.const -1))
+(assert_return (invoke "as-call-mid") (i32.const -1))
+(assert_return (invoke "as-call-last") (i32.const -1))
+
+(assert_return (invoke "as-call_indirect-first") (i32.const -1))
+(assert_return (invoke "as-call_indirect-mid") (i32.const -1))
+(assert_return (invoke "as-call_indirect-last") (i32.const -1))
+(assert_return (invoke "as-call_indirect-index") (i32.const -1))
+
+(assert_return (invoke "as-local.set-value"))
+(assert_return (invoke "as-local.tee-value") (i32.const 0))
+(assert_return (invoke "as-global.set-value"))
+
+(assert_return (invoke "as-load-address") (i32.const 0))
+(assert_return (invoke "as-loadN-address") (i32.const 0))
+(assert_return (invoke "as-store-address"))
+(assert_return (invoke "as-store-value"))
+(assert_return (invoke "as-storeN-address"))
+(assert_return (invoke "as-storeN-value"))
+
+(assert_return (invoke "as-unary-operand") (i32.const 32))
+
+(assert_return (invoke "as-binary-left") (i32.const 10))
+(assert_return (invoke "as-binary-right") (i32.const 10))
+
+(assert_return (invoke "as-test-operand") (i32.const 1))
+
+(assert_return (invoke "as-compare-left") (i32.const 1))
+(assert_return (invoke "as-compare-right") (i32.const 1))
+
+(assert_return (invoke "as-memory.grow-size") (i32.const 1))
+
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (result i32) (i32.load32 (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (result i32) (i32.load32_u (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (result i32) (i32.load32_s (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (result i32) (i32.load64 (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (result i32) (i32.load64_u (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (result i32) (i32.load64_s (local.get 0)))"
+  )
+  "unknown operator"
+)
+
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (result i64) (i64.load64 (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (result i64) (i64.load64_u (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (result i64) (i64.load64_s (local.get 0)))"
+  )
+  "unknown operator"
+)
+
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (result f32) (f32.load32 (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (result f32) (f32.load64 (local.get 0)))"
+  )
+  "unknown operator"
+)
+
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (result f64) (f64.load32 (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (result f64) (f64.load64 (local.get 0)))"
+  )
+  "unknown operator"
+)
+
+
+;; load should have retval
+
+(assert_invalid
+  (module (memory 1) (func $load_i32 (i32.load (i32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func $load8_s_i32 (i32.load8_s (i32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func $load8_u_i32 (i32.load8_u (i32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func $load16_s_i32 (i32.load16_s (i32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func $load16_u_i32 (i32.load16_u (i32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func $load_i64 (i64.load (i32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func $load8_s_i64 (i64.load8_s (i32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func $load8_u_i64 (i64.load8_u (i32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func $load16_s_i64 (i64.load16_s (i32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func $load16_u_i64 (i64.load16_u (i32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func $load32_s_i64 (i64.load32_s (i32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func $load32_u_i64 (i64.load32_u (i32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func $load_f32 (f32.load (i32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func $load_f64 (f64.load (i32.const 0))))
+  "type mismatch"
+)
+
+
+;; Type check
+
+(assert_invalid (module (memory 1) (func (result i32) (i32.load (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (result i32) (i32.load8_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (result i32) (i32.load8_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (result i32) (i32.load16_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (result i32) (i32.load16_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (result i64) (i64.load (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (result i64) (i64.load8_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (result i64) (i64.load8_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (result i64) (i64.load16_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (result i64) (i64.load16_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (result i64) (i64.load32_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (result i64) (i64.load32_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (result f32) (f32.load (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (result f64) (f64.load (f32.const 0)))) "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-address-empty
+      (i32.load) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-address-empty-in-block
+      (i32.const 0)
+      (block (i32.load) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-address-empty-in-loop
+      (i32.const 0)
+      (loop (i32.load) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-address-empty-in-then
+      (i32.const 0) (i32.const 0)
+      (if (then (i32.load) (drop)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-address-empty-in-else
+      (i32.const 0) (i32.const 0)
+      (if (result i32) (then (i32.const 0)) (else (i32.load))) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-address-empty-in-br
+      (i32.const 0)
+      (block (br 0 (i32.load)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-address-empty-in-br_if
+      (i32.const 0)
+      (block (br_if 0 (i32.load) (i32.const 1)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-address-empty-in-br_table
+      (i32.const 0)
+      (block (br_table 0 (i32.load)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-address-empty-in-return
+      (return (i32.load)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-address-empty-in-select
+      (select (i32.load) (i32.const 1) (i32.const 2)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-address-empty-in-call
+      (call 1 (i32.load)) (drop)
+    )
+    (func (param i32) (result i32) (local.get 0))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $f (param i32) (result i32) (local.get 0))
+    (type $sig (func (param i32) (result i32)))
+    (table funcref (elem $f))
+    (func $type-address-empty-in-call_indirect
+      (block (result i32)
+        (call_indirect (type $sig)
+          (i32.load) (i32.const 0)
+        )
+        (drop)
+      )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-address-empty-in-local.set
+      (local i32)
+      (local.set 0 (i32.load)) (local.get 0) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-address-empty-in-local.tee
+      (local i32)
+      (local.tee 0 (i32.load)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (global $x (mut i32) (i32.const 0))
+    (func $type-address-empty-in-global.set
+      (global.set $x (i32.load)) (global.get $x) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-address-empty-in-memory.grow
+      (memory.grow (i32.load)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-address-empty-in-load
+      (i32.load (i32.load)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-address-empty-in-store
+      (i32.store (i32.load) (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
diff --git a/binaryen/test/spec/load64.wast b/binaryen/test/spec/load64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/load64.wast
@@ -0,0 +1,567 @@
+;; Load operator as the argument of control constructs and instructions
+
+(module
+  (memory i64 1)
+
+  (func (export "as-br-value") (result i32)
+    (block (result i32) (br 0 (i32.load (i64.const 0))))
+  )
+
+  (func (export "as-br_if-cond")
+    (block (br_if 0 (i32.load (i64.const 0))))
+  )
+  (func (export "as-br_if-value") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (i32.load (i64.const 0)) (i32.const 1))) (i32.const 7)
+    )
+  )
+  (func (export "as-br_if-value-cond") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (i32.const 6) (i32.load (i64.const 0)))) (i32.const 7)
+    )
+  )
+
+  (func (export "as-br_table-index")
+    (block (br_table 0 0 0 (i32.load (i64.const 0))))
+  )
+  (func (export "as-br_table-value") (result i32)
+    (block (result i32)
+      (br_table 0 0 0 (i32.load (i64.const 0)) (i32.const 1)) (i32.const 7)
+    )
+  )
+  (func (export "as-br_table-value-index") (result i32)
+    (block (result i32)
+      (br_table 0 0 (i32.const 6) (i32.load (i64.const 0))) (i32.const 7)
+    )
+  )
+
+  (func (export "as-return-value") (result i32)
+    (return (i32.load (i64.const 0)))
+  )
+
+  (func (export "as-if-cond") (result i32)
+    (if (result i32) (i32.load (i64.const 0))
+      (then (i32.const 0)) (else (i32.const 1))
+    )
+  )
+  (func (export "as-if-then") (result i32)
+    (if (result i32) (i32.const 1)
+      (then (i32.load (i64.const 0))) (else (i32.const 0))
+    )
+  )
+  (func (export "as-if-else") (result i32)
+    (if (result i32) (i32.const 0)
+      (then (i32.const 0)) (else (i32.load (i64.const 0)))
+    )
+  )
+
+  (func (export "as-select-first") (param i32 i32) (result i32)
+    (select (i32.load (i64.const 0)) (local.get 0) (local.get 1))
+  )
+  (func (export "as-select-second") (param i32 i32) (result i32)
+    (select (local.get 0) (i32.load (i64.const 0)) (local.get 1))
+  )
+  (func (export "as-select-cond") (result i32)
+    (select (i32.const 0) (i32.const 1) (i32.load (i64.const 0)))
+  )
+
+  (func $f (param i32 i32 i32) (result i32) (i32.const -1))
+  (func (export "as-call-first") (result i32)
+    (call $f (i32.load (i64.const 0)) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-call-mid") (result i32)
+    (call $f (i32.const 1) (i32.load (i64.const 0)) (i32.const 3))
+  )
+  (func (export "as-call-last") (result i32)
+    (call $f (i32.const 1) (i32.const 2) (i32.load (i64.const 0)))
+  )
+
+  (type $sig (func (param i32 i32 i32) (result i32)))
+  (table funcref (elem $f))
+  (func (export "as-call_indirect-first") (result i32)
+    (call_indirect (type $sig)
+      (i32.load (i64.const 0)) (i32.const 2) (i32.const 3) (i32.const 0)
+    )
+  )
+  (func (export "as-call_indirect-mid") (result i32)
+    (call_indirect (type $sig)
+      (i32.const 1) (i32.load (i64.const 0)) (i32.const 3) (i32.const 0)
+    )
+  )
+  (func (export "as-call_indirect-last") (result i32)
+    (call_indirect (type $sig)
+      (i32.const 1) (i32.const 2) (i32.load (i64.const 0)) (i32.const 0)
+    )
+  )
+  (func (export "as-call_indirect-index") (result i32)
+    (call_indirect (type $sig)
+      (i32.const 1) (i32.const 2) (i32.const 3) (i32.load (i64.const 0))
+    )
+  )
+
+  (func (export "as-local.set-value") (local i32)
+    (local.set 0 (i32.load (i64.const 0)))
+  )
+  (func (export "as-local.tee-value") (result i32) (local i32)
+    (local.tee 0 (i32.load (i64.const 0)))
+  )
+  (global $g (mut i32) (i32.const 0))
+  (func (export "as-global.set-value") (local i32)
+    (global.set $g (i32.load (i64.const 0)))
+  )
+
+  (func (export "as-load-address") (result i32)
+    (i32.load (i64.load (i64.const 0)))
+  )
+  (func (export "as-loadN-address") (result i32)
+    (i32.load8_s (i64.load (i64.const 0)))
+  )
+
+  (func (export "as-store-address")
+    (i32.store (i64.load (i64.const 0)) (i32.const 7))
+  )
+  (func (export "as-store-value")
+    (i32.store (i64.const 2) (i32.load (i64.const 0)))
+  )
+
+  (func (export "as-storeN-address")
+    (i32.store8 (i64.load8_s (i64.const 0)) (i32.const 7))
+  )
+  (func (export "as-storeN-value")
+    (i32.store16 (i64.const 2) (i32.load (i64.const 0)))
+  )
+
+  (func (export "as-unary-operand") (result i32)
+    (i32.clz (i32.load (i64.const 100)))
+  )
+
+  (func (export "as-binary-left") (result i32)
+    (i32.add (i32.load (i64.const 100)) (i32.const 10))
+  )
+  (func (export "as-binary-right") (result i32)
+    (i32.sub (i32.const 10) (i32.load (i64.const 100)))
+  )
+
+  (func (export "as-test-operand") (result i32)
+    (i32.eqz (i32.load (i64.const 100)))
+  )
+
+  (func (export "as-compare-left") (result i32)
+    (i32.le_s (i32.load (i64.const 100)) (i32.const 10))
+  )
+  (func (export "as-compare-right") (result i32)
+    (i32.ne (i32.const 10) (i32.load (i64.const 100)))
+  )
+
+  (func (export "as-memory.grow-size") (result i64)
+    (memory.grow (i64.load (i64.const 100)))
+  )
+)
+
+(assert_return (invoke "as-br-value") (i32.const 0))
+
+(assert_return (invoke "as-br_if-cond"))
+(assert_return (invoke "as-br_if-value") (i32.const 0))
+(assert_return (invoke "as-br_if-value-cond") (i32.const 7))
+
+(assert_return (invoke "as-br_table-index"))
+(assert_return (invoke "as-br_table-value") (i32.const 0))
+(assert_return (invoke "as-br_table-value-index") (i32.const 6))
+
+(assert_return (invoke "as-return-value") (i32.const 0))
+
+(assert_return (invoke "as-if-cond") (i32.const 1))
+(assert_return (invoke "as-if-then") (i32.const 0))
+(assert_return (invoke "as-if-else") (i32.const 0))
+
+(assert_return (invoke "as-select-first" (i32.const 0) (i32.const 1)) (i32.const 0))
+(assert_return (invoke "as-select-second" (i32.const 0) (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-select-cond") (i32.const 1))
+
+(assert_return (invoke "as-call-first") (i32.const -1))
+(assert_return (invoke "as-call-mid") (i32.const -1))
+(assert_return (invoke "as-call-last") (i32.const -1))
+
+(assert_return (invoke "as-call_indirect-first") (i32.const -1))
+(assert_return (invoke "as-call_indirect-mid") (i32.const -1))
+(assert_return (invoke "as-call_indirect-last") (i32.const -1))
+(assert_return (invoke "as-call_indirect-index") (i32.const -1))
+
+(assert_return (invoke "as-local.set-value"))
+(assert_return (invoke "as-local.tee-value") (i32.const 0))
+(assert_return (invoke "as-global.set-value"))
+
+(assert_return (invoke "as-load-address") (i32.const 0))
+(assert_return (invoke "as-loadN-address") (i32.const 0))
+(assert_return (invoke "as-store-address"))
+(assert_return (invoke "as-store-value"))
+(assert_return (invoke "as-storeN-address"))
+(assert_return (invoke "as-storeN-value"))
+
+(assert_return (invoke "as-unary-operand") (i32.const 32))
+
+(assert_return (invoke "as-binary-left") (i32.const 10))
+(assert_return (invoke "as-binary-right") (i32.const 10))
+
+(assert_return (invoke "as-test-operand") (i32.const 1))
+
+(assert_return (invoke "as-compare-left") (i32.const 1))
+(assert_return (invoke "as-compare-right") (i32.const 1))
+
+(assert_return (invoke "as-memory.grow-size") (i64.const 1))
+
+(assert_malformed
+  (module quote
+    "(memory i64 1)"
+    "(func (param i64) (result i32) (i32.load32 (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory i64 1)"
+    "(func (param i64) (result i32) (i32.load32_u (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory i64 1)"
+    "(func (param i64) (result i32) (i32.load32_s (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory i64 1)"
+    "(func (param i64) (result i32) (i32.load64 (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory i64 1)"
+    "(func (param i64) (result i32) (i32.load64_u (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory i64 1)"
+    "(func (param i64) (result i32) (i32.load64_s (local.get 0)))"
+  )
+  "unknown operator"
+)
+
+(assert_malformed
+  (module quote
+    "(memory i64 1)"
+    "(func (param i64) (result i64) (i64.load64 (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory i64 1)"
+    "(func (param i64) (result i64) (i64.load64_u (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory i64 1)"
+    "(func (param i64) (result i64) (i64.load64_s (local.get 0)))"
+  )
+  "unknown operator"
+)
+
+(assert_malformed
+  (module quote
+    "(memory i64 1)"
+    "(func (param i64) (result f32) (f32.load32 (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory i64 1)"
+    "(func (param i64) (result f32) (f32.load64 (local.get 0)))"
+  )
+  "unknown operator"
+)
+
+(assert_malformed
+  (module quote
+    "(memory i64 1)"
+    "(func (param i64) (result f64) (f64.load32 (local.get 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory i64 1)"
+    "(func (param i64) (result f64) (f64.load64 (local.get 0)))"
+  )
+  "unknown operator"
+)
+
+
+;; load should have retval
+
+(assert_invalid
+  (module (memory i64 1) (func $load_i32 (i32.load (i64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory i64 1) (func $load8_s_i32 (i32.load8_s (i64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory i64 1) (func $load8_u_i32 (i32.load8_u (i64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory i64 1) (func $load16_s_i32 (i32.load16_s (i64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory i64 1) (func $load16_u_i32 (i32.load16_u (i64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory i64 1) (func $load_i64 (i64.load (i64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory i64 1) (func $load8_s_i64 (i64.load8_s (i64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory i64 1) (func $load8_u_i64 (i64.load8_u (i64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory i64 1) (func $load16_s_i64 (i64.load16_s (i64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory i64 1) (func $load16_u_i64 (i64.load16_u (i64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory i64 1) (func $load32_s_i64 (i64.load32_s (i64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory i64 1) (func $load32_u_i64 (i64.load32_u (i64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory i64 1) (func $load_f32 (f32.load (i64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory i64 1) (func $load_f64 (f64.load (i64.const 0))))
+  "type mismatch"
+)
+
+
+;; Type check
+
+(assert_invalid (module (memory i64 1) (func (result i32) (i32.load (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory i64 1) (func (result i32) (i32.load8_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory i64 1) (func (result i32) (i32.load8_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory i64 1) (func (result i32) (i32.load16_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory i64 1) (func (result i32) (i32.load16_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory i64 1) (func (result i64) (i64.load (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory i64 1) (func (result i64) (i64.load8_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory i64 1) (func (result i64) (i64.load8_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory i64 1) (func (result i64) (i64.load16_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory i64 1) (func (result i64) (i64.load16_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory i64 1) (func (result i64) (i64.load32_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory i64 1) (func (result i64) (i64.load32_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory i64 1) (func (result f32) (f32.load (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory i64 1) (func (result f64) (f64.load (f32.const 0)))) "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $type-address-empty
+      (i32.load) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $type-address-empty-in-block
+      (i32.const 0)
+      (block (i32.load) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $type-address-empty-in-loop
+      (i32.const 0)
+      (loop (i32.load) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $type-address-empty-in-then
+      (i32.const 0) (i32.const 0)
+      (if (then (i32.load) (drop)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $type-address-empty-in-else
+      (i32.const 0) (i32.const 0)
+      (if (result i32) (then (i32.const 0)) (else (i32.load))) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $type-address-empty-in-br
+      (i32.const 0)
+      (block (br 0 (i32.load)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $type-address-empty-in-br_if
+      (i32.const 0)
+      (block (br_if 0 (i32.load) (i32.const 1)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $type-address-empty-in-br_table
+      (i32.const 0)
+      (block (br_table 0 (i32.load)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $type-address-empty-in-return
+      (return (i32.load)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $type-address-empty-in-select
+      (select (i32.load) (i32.const 1) (i32.const 2)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $type-address-empty-in-call
+      (call 1 (i32.load)) (drop)
+    )
+    (func (param i32) (result i32) (local.get 0))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $f (param i32) (result i32) (local.get 0))
+    (type $sig (func (param i32) (result i32)))
+    (table funcref (elem $f))
+    (func $type-address-empty-in-call_indirect
+      (block (result i32)
+        (call_indirect (type $sig)
+          (i32.load) (i32.const 0)
+        )
+        (drop)
+      )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $type-address-empty-in-local.set
+      (local i32)
+      (local.set 0 (i32.load)) (local.get 0) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $type-address-empty-in-local.tee
+      (local i32)
+      (local.tee 0 (i32.load)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (global $x (mut i32) (i32.const 0))
+    (func $type-address-empty-in-global.set
+      (global.set $x (i32.load)) (global.get $x) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $type-address-empty-in-memory.grow
+      (memory.grow (i64.load)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 0)
+    (func $type-address-empty-in-load
+      (i32.load (i32.load)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory i64 1)
+    (func $type-address-empty-in-store
+      (i32.store (i32.load) (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
diff --git a/binaryen/test/spec/local_get.wast b/binaryen/test/spec/local_get.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/local_get.wast
@@ -0,0 +1,226 @@
+;; Test `local.get` operator
+
+(module
+  ;; Typing
+
+  (func (export "type-local-i32") (result i32) (local i32) (local.get 0))
+  (func (export "type-local-i64") (result i64) (local i64) (local.get 0))
+  (func (export "type-local-f32") (result f32) (local f32) (local.get 0))
+  (func (export "type-local-f64") (result f64) (local f64) (local.get 0))
+
+  (func (export "type-param-i32") (param i32) (result i32) (local.get 0))
+  (func (export "type-param-i64") (param i64) (result i64) (local.get 0))
+  (func (export "type-param-f32") (param f32) (result f32) (local.get 0))
+  (func (export "type-param-f64") (param f64) (result f64) (local.get 0))
+
+  (func (export "type-mixed") (param i64 f32 f64 i32 i32)
+    (local f32 i64 i64 f64)
+    (drop (i64.eqz (local.get 0)))
+    (drop (f32.neg (local.get 1)))
+    (drop (f64.neg (local.get 2)))
+    (drop (i32.eqz (local.get 3)))
+    (drop (i32.eqz (local.get 4)))
+    (drop (f32.neg (local.get 5)))
+    (drop (i64.eqz (local.get 6)))
+    (drop (i64.eqz (local.get 7)))
+    (drop (f64.neg (local.get 8)))
+  )
+
+  ;; Reading
+
+  (func (export "read") (param i64 f32 f64 i32 i32) (result f64)
+    (local f32 i64 i64 f64)
+    (local.set 5 (f32.const 5.5))
+    (local.set 6 (i64.const 6))
+    (local.set 8 (f64.const 8))
+    (f64.add
+      (f64.convert_i64_u (local.get 0))
+      (f64.add
+        (f64.promote_f32 (local.get 1))
+        (f64.add
+          (local.get 2)
+          (f64.add
+            (f64.convert_i32_u (local.get 3))
+            (f64.add
+              (f64.convert_i32_s (local.get 4))
+              (f64.add
+                (f64.promote_f32 (local.get 5))
+                (f64.add
+                  (f64.convert_i64_u (local.get 6))
+                  (f64.add
+                    (f64.convert_i64_u (local.get 7))
+                    (local.get 8)
+                  )
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+
+  ;; As parameter of control constructs and instructions
+
+  (func (export "as-block-value") (param i32) (result i32)
+    (block (result i32) (local.get 0))
+  )
+  (func (export "as-loop-value") (param i32) (result i32)
+    (loop (result i32) (local.get 0))
+  )
+  (func (export "as-br-value") (param i32) (result i32)
+    (block (result i32) (br 0 (local.get 0)))
+  )
+  (func (export "as-br_if-value") (param i32) (result i32)
+    (block $l0 (result i32) (br_if $l0 (local.get 0) (i32.const 1)))
+  )
+
+  (func (export "as-br_if-value-cond") (param i32) (result i32)
+    (block (result i32)
+      (br_if 0 (local.get 0) (local.get 0))
+    )
+  )
+  (func (export "as-br_table-value") (param i32) (result i32)
+    (block
+      (block
+        (block
+          (br_table 0 1 2 (local.get 0))
+          (return (i32.const 0))
+        )
+        (return (i32.const 1))
+      )
+      (return (i32.const 2))
+    )
+    (i32.const 3)
+  )
+
+  (func (export "as-return-value") (param i32) (result i32)
+    (return (local.get 0))
+  )
+
+  (func (export "as-if-then") (param i32) (result i32)
+    (if (result i32) (local.get 0) (then (local.get 0)) (else (i32.const 0)))
+  )
+  (func (export "as-if-else") (param i32) (result i32)
+    (if (result i32) (local.get 0) (then (i32.const 1)) (else (local.get 0)))
+  )
+)
+
+(assert_return (invoke "type-local-i32") (i32.const 0))
+(assert_return (invoke "type-local-i64") (i64.const 0))
+(assert_return (invoke "type-local-f32") (f32.const 0))
+(assert_return (invoke "type-local-f64") (f64.const 0))
+
+(assert_return (invoke "type-param-i32" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "type-param-i64" (i64.const 3)) (i64.const 3))
+(assert_return (invoke "type-param-f32" (f32.const 4.4)) (f32.const 4.4))
+(assert_return (invoke "type-param-f64" (f64.const 5.5)) (f64.const 5.5))
+
+(assert_return (invoke "as-block-value" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-loop-value" (i32.const 7)) (i32.const 7))
+
+(assert_return (invoke "as-br-value" (i32.const 8)) (i32.const 8))
+(assert_return (invoke "as-br_if-value" (i32.const 9)) (i32.const 9))
+(assert_return (invoke "as-br_if-value-cond" (i32.const 10)) (i32.const 10))
+(assert_return (invoke "as-br_table-value" (i32.const 1)) (i32.const 2))
+
+(assert_return (invoke "as-return-value" (i32.const 0)) (i32.const 0))
+
+(assert_return (invoke "as-if-then" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-if-else" (i32.const 0)) (i32.const 0))
+
+(assert_return
+  (invoke "type-mixed"
+    (i64.const 1) (f32.const 2.2) (f64.const 3.3) (i32.const 4) (i32.const 5)
+  )
+)
+
+(assert_return
+  (invoke "read"
+    (i64.const 1) (f32.const 2) (f64.const 3.3) (i32.const 4) (i32.const 5)
+  )
+  (f64.const 34.8)
+)
+
+
+;; Invalid typing of access to locals
+
+(assert_invalid
+  (module (func $type-local-num-vs-num (result i64) (local i32) (local.get 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-num-vs-num (result i32) (local f32) (i32.eqz (local.get 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-num-vs-num (result f64) (local f64 i64) (f64.neg (local.get 1))))
+  "type mismatch"
+)
+
+
+;; Invalid typing of access to parameters
+
+(assert_invalid
+  (module (func $type-param-num-vs-num (param i32) (result i64) (local.get 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-num-vs-num (param f32) (result i32) (i32.eqz (local.get 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-num-vs-num (param f64 i64) (result f64) (f64.neg (local.get 1))))
+  "type mismatch"
+)
+
+
+;; local.set should have retval
+
+(assert_invalid
+  (module (func $type-empty-vs-i32 (local i32) (local.get 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-vs-i64 (local i64) (local.get 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-vs-f32 (local f32) (local.get 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-vs-f64 (local f64) (local.get 0)))
+  "type mismatch"
+)
+
+
+;; Invalid local index
+
+(assert_invalid
+  (module (func $unbound-local (local i32 i64) (local.get 3)))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-local (local i32 i64) (local.get 14324343)))
+  "unknown local"
+)
+
+(assert_invalid
+  (module (func $unbound-param (param i32 i64) (local.get 2)))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-param (param i32 i64) (local.get 714324343)))
+  "unknown local"
+)
+
+(assert_invalid
+  (module (func $unbound-mixed (param i32) (local i32 i64) (local.get 3)))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-mixed (param i64) (local i32 i64) (local.get 214324343)))
+  "unknown local"
+)
+
diff --git a/binaryen/test/spec/local_set.wast b/binaryen/test/spec/local_set.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/local_set.wast
@@ -0,0 +1,362 @@
+;; Test `local.set` operator
+
+(module
+  ;; Typing
+
+  (func (export "type-local-i32") (local i32) (local.set 0 (i32.const 0)))
+  (func (export "type-local-i64") (local i64) (local.set 0 (i64.const 0)))
+  (func (export "type-local-f32") (local f32) (local.set 0 (f32.const 0)))
+  (func (export "type-local-f64") (local f64) (local.set 0 (f64.const 0)))
+
+  (func (export "type-param-i32") (param i32) (local.set 0 (i32.const 10)))
+  (func (export "type-param-i64") (param i64) (local.set 0 (i64.const 11)))
+  (func (export "type-param-f32") (param f32) (local.set 0 (f32.const 11.1)))
+  (func (export "type-param-f64") (param f64) (local.set 0 (f64.const 12.2)))
+
+  (func (export "type-mixed") (param i64 f32 f64 i32 i32) (local f32 i64 i64 f64)
+    (local.set 0 (i64.const 0))
+    (local.set 1 (f32.const 0))
+    (local.set 2 (f64.const 0))
+    (local.set 3 (i32.const 0))
+    (local.set 4 (i32.const 0))
+    (local.set 5 (f32.const 0))
+    (local.set 6 (i64.const 0))
+    (local.set 7 (i64.const 0))
+    (local.set 8 (f64.const 0))
+  )
+
+  ;; Writing
+
+  (func (export "write") (param i64 f32 f64 i32 i32) (result i64)
+    (local f32 i64 i64 f64)
+    (local.set 1 (f32.const -0.3))
+    (local.set 3 (i32.const 40))
+    (local.set 4 (i32.const -7))
+    (local.set 5 (f32.const 5.5))
+    (local.set 6 (i64.const 6))
+    (local.set 8 (f64.const 8))
+    (i64.trunc_f64_s
+      (f64.add
+        (f64.convert_i64_u (local.get 0))
+        (f64.add
+          (f64.promote_f32 (local.get 1))
+          (f64.add
+            (local.get 2)
+            (f64.add
+              (f64.convert_i32_u (local.get 3))
+              (f64.add
+                (f64.convert_i32_s (local.get 4))
+                (f64.add
+                  (f64.promote_f32 (local.get 5))
+                  (f64.add
+                    (f64.convert_i64_u (local.get 6))
+                    (f64.add
+                      (f64.convert_i64_u (local.get 7))
+                      (local.get 8)
+                    )
+                  )
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+
+  ;; As parameter of control constructs and instructions
+
+  (func (export "as-block-value") (param i32)
+    (block (local.set 0 (i32.const 1)))
+  )
+  (func (export "as-loop-value") (param i32)
+    (loop (local.set 0 (i32.const 3)))
+  )
+
+  (func (export "as-br-value") (param i32)
+    (block (br 0 (local.set 0 (i32.const 9))))
+  )
+  (func (export "as-br_if-value") (param i32)
+    (block
+      (br_if 0 (local.set 0 (i32.const 8)) (i32.const 1))
+    )
+  )
+  (func (export "as-br_if-value-cond") (param i32)
+    (block
+      (br_if 0 (i32.const 6) (local.set 0 (i32.const 9)))
+    )
+  )
+  (func (export "as-br_table-value") (param i32)
+    (block
+      (br_table 0 (local.set 0 (i32.const 10)) (i32.const 1))
+    )
+  )
+
+  (func (export "as-return-value") (param i32)
+    (return (local.set 0 (i32.const 7)))
+  )
+
+  (func (export "as-if-then") (param i32)
+    (if (local.get 0) (then (local.set 0 (i32.const 3))))
+  )
+  (func (export "as-if-else") (param i32)
+    (if (local.get 0) (then) (else (local.set 0 (i32.const 1))))
+  )
+)
+
+(assert_return (invoke "type-local-i32"))
+(assert_return (invoke "type-local-i64"))
+(assert_return (invoke "type-local-f32"))
+(assert_return (invoke "type-local-f64"))
+
+(assert_return (invoke "type-param-i32" (i32.const 2)))
+(assert_return (invoke "type-param-i64" (i64.const 3)))
+(assert_return (invoke "type-param-f32" (f32.const 4.4)))
+(assert_return (invoke "type-param-f64" (f64.const 5.5)))
+
+(assert_return (invoke "as-block-value" (i32.const 0)))
+(assert_return (invoke "as-loop-value" (i32.const 0)))
+
+(assert_return (invoke "as-br-value" (i32.const 0)))
+(assert_return (invoke "as-br_if-value" (i32.const 0)))
+(assert_return (invoke "as-br_if-value-cond" (i32.const 0)))
+(assert_return (invoke "as-br_table-value" (i32.const 0)))
+
+(assert_return (invoke "as-return-value" (i32.const 0)))
+
+(assert_return (invoke "as-if-then" (i32.const 1)))
+(assert_return (invoke "as-if-else" (i32.const 0)))
+
+(assert_return
+  (invoke "type-mixed"
+    (i64.const 1) (f32.const 2.2) (f64.const 3.3) (i32.const 4) (i32.const 5)
+  )
+)
+
+(assert_return
+  (invoke "write"
+    (i64.const 1) (f32.const 2) (f64.const 3.3) (i32.const 4) (i32.const 5)
+  )
+  (i64.const 56)
+)
+
+
+;; Invalid typing of access to locals
+
+
+(assert_invalid
+  (module (func $type-local-arg-void-vs-num (local i32) (local.set 0 (nop))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-arg-num-vs-num (local i32) (local.set 0 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-arg-num-vs-num (local f32) (local.set 0 (f64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-arg-num-vs-num (local f64 i64) (local.set 1 (f64.const 0))))
+  "type mismatch"
+)
+
+
+;; Invalid typing of access to parameters
+
+
+(assert_invalid
+  (module (func $type-param-arg-void-vs-num (param i32) (local.set 0 (nop))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-arg-num-vs-num (param i32) (local.set 0 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-arg-num-vs-num (param f32) (local.set 0 (f64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-arg-num-vs-num (param f64 i64) (local.set 1 (f64.const 0))))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num (param i32)
+      (local.set 0)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-block (param i32)
+      (i32.const 0)
+      (block (local.set 0))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-loop (param i32)
+      (i32.const 0)
+      (loop (local.set 0))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-then (param i32)
+      (i32.const 0)
+      (if (i32.const 1) (then (local.set 0)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-else (param i32)
+      (i32.const 0)
+      (if (result i32) (i32.const 0) (then (i32.const 0)) (else (local.set 0)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-br (param i32)
+      (i32.const 0)
+      (block (br 0 (local.set 0)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-br_if (param i32)
+      (i32.const 0)
+      (block (br_if 0 (local.set 0)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-br_table (param i32)
+      (i32.const 0)
+      (block (br_table 0 (local.set 0)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-return (param i32)
+      (return (local.set 0))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-select (param i32)
+      (select (local.set 0) (i32.const 1) (i32.const 2))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-call (param i32)
+      (call 1 (local.set 0))
+    )
+    (func (param i32) (result i32) (local.get 0))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $f (param i32) (result i32) (local.get 0))
+    (type $sig (func (param i32) (result i32)))
+    (table funcref (elem $f))
+    (func $type-param-arg-empty-vs-num-in-call_indirect (param i32)
+      (block (result i32)
+        (call_indirect (type $sig)
+          (local.set 0) (i32.const 0)
+        )
+      )
+    )
+  )
+  "type mismatch"
+)
+
+
+;; Invalid typing of access to mixed args
+
+(assert_invalid
+  (module (func $type-mixed-arg-num-vs-num (param f32) (local i32) (local.set 1 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-mixed-arg-num-vs-num (param i64 i32) (local f32) (local.set 1 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-mixed-arg-num-vs-num (param i64) (local f64 i64) (local.set 1 (i64.const 0))))
+  "type mismatch"
+)
+
+
+;; local.set should have no retval
+
+(assert_invalid
+  (module (func $type-empty-vs-i32 (param i32) (result i32) (local.set 0 (i32.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-vs-i64 (param i64) (result i64) (local.set 0 (i64.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-vs-f32 (param f32) (result f32) (local.set 0 (f32.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-vs-f64 (param f64) (result f64) (local.set 0 (f64.const 1))))
+  "type mismatch"
+)
+
+
+;; Invalid local index
+
+(assert_invalid
+  (module (func $unbound-local (local i32 i64) (local.set 3 (i32.const 0))))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-local (local i32 i64) (local.set 14324343 (i32.const 0))))
+  "unknown local"
+)
+
+(assert_invalid
+  (module (func $unbound-param (param i32 i64) (local.set 2 (i32.const 0))))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-param (param i32 i64) (local.set 714324343 (i32.const 0))))
+  "unknown local"
+)
+
+(assert_invalid
+  (module (func $unbound-mixed (param i32) (local i32 i64) (local.set 3 (i32.const 0))))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-mixed (param i64) (local i32 i64) (local.set 214324343 (i32.const 0))))
+  "unknown local"
+)
+
diff --git a/binaryen/test/spec/local_tee.wast b/binaryen/test/spec/local_tee.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/local_tee.wast
@@ -0,0 +1,639 @@
+;; Test `local.tee` operator
+
+(module
+  ;; Typing
+
+  (func (export "type-local-i32") (result i32) (local i32) (local.tee 0 (i32.const 0)))
+  (func (export "type-local-i64") (result i64) (local i64) (local.tee 0 (i64.const 0)))
+  (func (export "type-local-f32") (result f32) (local f32) (local.tee 0 (f32.const 0)))
+  (func (export "type-local-f64") (result f64) (local f64) (local.tee 0 (f64.const 0)))
+
+  (func (export "type-param-i32") (param i32) (result i32) (local.tee 0 (i32.const 10)))
+  (func (export "type-param-i64") (param i64) (result i64) (local.tee 0 (i64.const 11)))
+  (func (export "type-param-f32") (param f32) (result f32) (local.tee 0 (f32.const 11.1)))
+  (func (export "type-param-f64") (param f64) (result f64) (local.tee 0 (f64.const 12.2)))
+
+  (func (export "type-mixed") (param i64 f32 f64 i32 i32) (local f32 i64 i64 f64)
+    (drop (i64.eqz (local.tee 0 (i64.const 0))))
+    (drop (f32.neg (local.tee 1 (f32.const 0))))
+    (drop (f64.neg (local.tee 2 (f64.const 0))))
+    (drop (i32.eqz (local.tee 3 (i32.const 0))))
+    (drop (i32.eqz (local.tee 4 (i32.const 0))))
+    (drop (f32.neg (local.tee 5 (f32.const 0))))
+    (drop (i64.eqz (local.tee 6 (i64.const 0))))
+    (drop (i64.eqz (local.tee 7 (i64.const 0))))
+    (drop (f64.neg (local.tee 8 (f64.const 0))))
+  )
+
+  ;; Writing
+
+  (func (export "write") (param i64 f32 f64 i32 i32) (result i64) (local f32 i64 i64 f64)
+    (drop (local.tee 1 (f32.const -0.3)))
+    (drop (local.tee 3 (i32.const 40)))
+    (drop (local.tee 4 (i32.const -7)))
+    (drop (local.tee 5 (f32.const 5.5)))
+    (drop (local.tee 6 (i64.const 6)))
+    (drop (local.tee 8 (f64.const 8)))
+    (i64.trunc_f64_s
+      (f64.add
+        (f64.convert_i64_u (local.get 0))
+        (f64.add
+          (f64.promote_f32 (local.get 1))
+          (f64.add
+            (local.get 2)
+            (f64.add
+              (f64.convert_i32_u (local.get 3))
+              (f64.add
+                (f64.convert_i32_s (local.get 4))
+                (f64.add
+                  (f64.promote_f32 (local.get 5))
+                  (f64.add
+                    (f64.convert_i64_u (local.get 6))
+                    (f64.add
+                      (f64.convert_i64_u (local.get 7))
+                      (local.get 8)
+                    )
+                  )
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+
+  ;; Result
+
+  (func (export "result") (param i64 f32 f64 i32 i32) (result f64)
+    (local f32 i64 i64 f64)
+    (f64.add
+      (f64.convert_i64_u (local.tee 0 (i64.const 1)))
+      (f64.add
+        (f64.promote_f32 (local.tee 1 (f32.const 2)))
+        (f64.add
+          (local.tee 2 (f64.const 3.3))
+          (f64.add
+            (f64.convert_i32_u (local.tee 3 (i32.const 4)))
+            (f64.add
+              (f64.convert_i32_s (local.tee 4 (i32.const 5)))
+              (f64.add
+                (f64.promote_f32 (local.tee 5 (f32.const 5.5)))
+                (f64.add
+                  (f64.convert_i64_u (local.tee 6 (i64.const 6)))
+                  (f64.add
+                    (f64.convert_i64_u (local.tee 7 (i64.const 0)))
+                    (local.tee 8 (f64.const 8))
+                  )
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+
+  (func $dummy)
+
+  (func (export "as-block-first") (param i32) (result i32)
+    (block (result i32) (local.tee 0 (i32.const 1)) (call $dummy))
+  )
+  (func (export "as-block-mid") (param i32) (result i32)
+    (block (result i32) (call $dummy) (local.tee 0 (i32.const 1)) (call $dummy))
+  )
+  (func (export "as-block-last") (param i32) (result i32)
+    (block (result i32) (call $dummy) (call $dummy) (local.tee 0 (i32.const 1)))
+  )
+
+  (func (export "as-loop-first") (param i32) (result i32)
+    (loop (result i32) (local.tee 0 (i32.const 3)) (call $dummy))
+  )
+  (func (export "as-loop-mid") (param i32) (result i32)
+    (loop (result i32) (call $dummy) (local.tee 0 (i32.const 4)) (call $dummy))
+  )
+  (func (export "as-loop-last") (param i32) (result i32)
+    (loop (result i32) (call $dummy) (call $dummy) (local.tee 0 (i32.const 5)))
+  )
+
+  (func (export "as-br-value") (param i32) (result i32)
+    (block (result i32) (br 0 (local.tee 0 (i32.const 9))))
+  )
+
+  (func (export "as-br_if-cond") (param i32)
+    (block (br_if 0 (local.tee 0 (i32.const 1))))
+  )
+  (func (export "as-br_if-value") (param i32) (result i32)
+    (block (result i32)
+      (drop (br_if 0 (local.tee 0 (i32.const 8)) (i32.const 1))) (i32.const 7)
+    )
+  )
+  (func (export "as-br_if-value-cond") (param i32) (result i32)
+    (block (result i32)
+      (drop (br_if 0 (i32.const 6) (local.tee 0 (i32.const 9)))) (i32.const 7)
+    )
+  )
+
+  (func (export "as-br_table-index") (param i32)
+    (block (br_table 0 0 0 (local.tee 0 (i32.const 0))))
+  )
+  (func (export "as-br_table-value") (param i32) (result i32)
+    (block (result i32)
+      (br_table 0 0 0 (local.tee 0 (i32.const 10)) (i32.const 1)) (i32.const 7)
+    )
+  )
+  (func (export "as-br_table-value-index") (param i32) (result i32)
+    (block (result i32)
+      (br_table 0 0 (i32.const 6) (local.tee 0 (i32.const 11))) (i32.const 7)
+    )
+  )
+
+  (func (export "as-return-value") (param i32) (result i32)
+    (return (local.tee 0 (i32.const 7)))
+  )
+
+  (func (export "as-if-cond") (param i32) (result i32)
+    (if (result i32) (local.tee 0 (i32.const 2))
+      (then (i32.const 0)) (else (i32.const 1))
+    )
+  )
+  (func (export "as-if-then") (param i32) (result i32)
+    (if (result i32) (local.get 0)
+      (then (local.tee 0 (i32.const 3))) (else (local.get 0))
+    )
+  )
+  (func (export "as-if-else") (param i32) (result i32)
+    (if (result i32) (local.get 0)
+      (then (local.get 0)) (else (local.tee 0 (i32.const 4)))
+    )
+  )
+
+  (func (export "as-select-first") (param i32 i32) (result i32)
+    (select (local.tee 0 (i32.const 5)) (local.get 0) (local.get 1))
+  )
+  (func (export "as-select-second") (param i32 i32) (result i32)
+    (select (local.get 0) (local.tee 0 (i32.const 6)) (local.get 1))
+  )
+  (func (export "as-select-cond") (param i32) (result i32)
+    (select (i32.const 0) (i32.const 1) (local.tee 0 (i32.const 7)))
+  )
+
+  (func $f (param i32 i32 i32) (result i32) (i32.const -1))
+  (func (export "as-call-first") (param i32) (result i32)
+    (call $f (local.tee 0 (i32.const 12)) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-call-mid") (param i32) (result i32)
+    (call $f (i32.const 1) (local.tee 0 (i32.const 13)) (i32.const 3))
+  )
+  (func (export "as-call-last") (param i32) (result i32)
+    (call $f (i32.const 1) (i32.const 2) (local.tee 0 (i32.const 14)))
+  )
+
+  (type $sig (func (param i32 i32 i32) (result i32)))
+  (table funcref (elem $f))
+  (func (export "as-call_indirect-first") (param i32) (result i32)
+    (call_indirect (type $sig)
+      (local.tee 0 (i32.const 1)) (i32.const 2) (i32.const 3) (i32.const 0)
+    )
+  )
+  (func (export "as-call_indirect-mid") (param i32) (result i32)
+    (call_indirect (type $sig)
+      (i32.const 1) (local.tee 0 (i32.const 2)) (i32.const 3) (i32.const 0)
+    )
+  )
+  (func (export "as-call_indirect-last") (param i32) (result i32)
+    (call_indirect (type $sig)
+      (i32.const 1) (i32.const 2) (local.tee 0 (i32.const 3)) (i32.const 0)
+    )
+  )
+  (func (export "as-call_indirect-index") (param i32) (result i32)
+    (call_indirect (type $sig)
+      (i32.const 1) (i32.const 2) (i32.const 3) (local.tee 0 (i32.const 0))
+    )
+  )
+
+  (func (export "as-local.set-value") (local i32)
+    (local.set 0 (local.tee 0 (i32.const 1)))
+  )
+  (func (export "as-local.tee-value") (param i32) (result i32)
+    (local.tee 0 (local.tee 0 (i32.const 1)))
+  )
+  (global $g (mut i32) (i32.const 0))
+  (func (export "as-global.set-value") (local i32)
+    (global.set $g (local.tee 0 (i32.const 1)))
+  )
+
+  (memory 1)
+  (func (export "as-load-address") (param i32) (result i32)
+    (i32.load (local.tee 0 (i32.const 1)))
+  )
+  (func (export "as-loadN-address") (param i32) (result i32)
+    (i32.load8_s (local.tee 0 (i32.const 3)))
+  )
+
+  (func (export "as-store-address") (param i32)
+    (i32.store (local.tee 0 (i32.const 30)) (i32.const 7))
+  )
+  (func (export "as-store-value") (param i32)
+    (i32.store (i32.const 2) (local.tee 0 (i32.const 1)))
+  )
+
+  (func (export "as-storeN-address") (param i32)
+    (i32.store8 (local.tee 0 (i32.const 1)) (i32.const 7))
+  )
+  (func (export "as-storeN-value") (param i32)
+    (i32.store16 (i32.const 2) (local.tee 0 (i32.const 1)))
+  )
+
+  (func (export "as-unary-operand") (param f32) (result f32)
+    (f32.neg (local.tee 0 (f32.const nan:0x0f1e2)))
+  )
+
+  (func (export "as-binary-left") (param i32) (result i32)
+    (i32.add (local.tee 0 (i32.const 3)) (i32.const 10))
+  )
+  (func (export "as-binary-right") (param i32) (result i32)
+    (i32.sub (i32.const 10) (local.tee 0 (i32.const 4)))
+  )
+
+  (func (export "as-test-operand") (param i32) (result i32)
+    (i32.eqz (local.tee 0 (i32.const 0)))
+  )
+
+  (func (export "as-compare-left") (param i32) (result i32)
+    (i32.le_s (local.tee 0 (i32.const 43)) (i32.const 10))
+  )
+  (func (export "as-compare-right") (param i32) (result i32)
+    (i32.ne (i32.const 10) (local.tee 0 (i32.const 42)))
+  )
+
+  (func (export "as-convert-operand") (param i64) (result i32)
+    (i32.wrap_i64 (local.tee 0 (i64.const 41)))
+  )
+
+  (func (export "as-memory.grow-size") (param i32) (result i32)
+    (memory.grow (local.tee 0 (i32.const 40)))
+  )
+
+)
+
+(assert_return (invoke "type-local-i32") (i32.const 0))
+(assert_return (invoke "type-local-i64") (i64.const 0))
+(assert_return (invoke "type-local-f32") (f32.const 0))
+(assert_return (invoke "type-local-f64") (f64.const 0))
+
+(assert_return (invoke "type-param-i32" (i32.const 2)) (i32.const 10))
+(assert_return (invoke "type-param-i64" (i64.const 3)) (i64.const 11))
+(assert_return (invoke "type-param-f32" (f32.const 4.4)) (f32.const 11.1))
+(assert_return (invoke "type-param-f64" (f64.const 5.5)) (f64.const 12.2))
+
+(assert_return (invoke "as-block-first" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-block-mid" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-block-last" (i32.const 0)) (i32.const 1))
+
+(assert_return (invoke "as-loop-first" (i32.const 0)) (i32.const 3))
+(assert_return (invoke "as-loop-mid" (i32.const 0)) (i32.const 4))
+(assert_return (invoke "as-loop-last" (i32.const 0)) (i32.const 5))
+
+(assert_return (invoke "as-br-value" (i32.const 0)) (i32.const 9))
+
+(assert_return (invoke "as-br_if-cond" (i32.const 0)))
+(assert_return (invoke "as-br_if-value" (i32.const 0)) (i32.const 8))
+(assert_return (invoke "as-br_if-value-cond" (i32.const 0)) (i32.const 6))
+
+(assert_return (invoke "as-br_table-index" (i32.const 0)))
+(assert_return (invoke "as-br_table-value" (i32.const 0)) (i32.const 10))
+(assert_return (invoke "as-br_table-value-index" (i32.const 0)) (i32.const 6))
+
+(assert_return (invoke "as-return-value" (i32.const 0)) (i32.const 7))
+
+(assert_return (invoke "as-if-cond" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-if-then" (i32.const 1)) (i32.const 3))
+(assert_return (invoke "as-if-else" (i32.const 0)) (i32.const 4))
+
+(assert_return (invoke "as-select-first" (i32.const 0) (i32.const 1)) (i32.const 5))
+(assert_return (invoke "as-select-second" (i32.const 0) (i32.const 0)) (i32.const 6))
+(assert_return (invoke "as-select-cond" (i32.const 0)) (i32.const 0))
+
+(assert_return (invoke "as-call-first" (i32.const 0)) (i32.const -1))
+(assert_return (invoke "as-call-mid" (i32.const 0)) (i32.const -1))
+(assert_return (invoke "as-call-last" (i32.const 0)) (i32.const -1))
+
+(assert_return (invoke "as-call_indirect-first" (i32.const 0)) (i32.const -1))
+(assert_return (invoke "as-call_indirect-mid" (i32.const 0)) (i32.const -1))
+(assert_return (invoke "as-call_indirect-last" (i32.const 0)) (i32.const -1))
+(assert_return (invoke "as-call_indirect-index" (i32.const 0)) (i32.const -1))
+
+(assert_return (invoke "as-local.set-value"))
+(assert_return (invoke "as-local.tee-value" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-global.set-value"))
+
+(assert_return (invoke "as-load-address" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-loadN-address" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-store-address" (i32.const 0)))
+(assert_return (invoke "as-store-value" (i32.const 0)))
+(assert_return (invoke "as-storeN-address" (i32.const 0)))
+(assert_return (invoke "as-storeN-value" (i32.const 0)))
+
+(assert_return (invoke "as-unary-operand" (f32.const 0)) (f32.const -nan:0x0f1e2))
+(assert_return (invoke "as-binary-left" (i32.const 0)) (i32.const 13))
+(assert_return (invoke "as-binary-right" (i32.const 0)) (i32.const 6))
+(assert_return (invoke "as-test-operand" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-compare-left" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-compare-right" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-convert-operand" (i64.const 0)) (i32.const 41))
+(assert_return (invoke "as-memory.grow-size" (i32.const 0)) (i32.const 1))
+
+(assert_return
+  (invoke "type-mixed"
+    (i64.const 1) (f32.const 2.2) (f64.const 3.3) (i32.const 4) (i32.const 5)
+  )
+)
+
+(assert_return
+  (invoke "write"
+    (i64.const 1) (f32.const 2) (f64.const 3.3) (i32.const 4) (i32.const 5)
+  )
+  (i64.const 56)
+)
+
+(assert_return
+  (invoke "result"
+    (i64.const -1) (f32.const -2) (f64.const -3.3) (i32.const -4) (i32.const -5)
+  )
+  (f64.const 34.8)
+)
+
+
+;; Invalid typing of access to locals
+
+(assert_invalid
+  (module (func $type-local-num-vs-num (result i64) (local i32) (local.tee 0 (i32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-num-vs-num (local f32) (i32.eqz (local.tee 0 (f32.const 0)))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-num-vs-num (local f64 i64) (f64.neg (local.tee 1 (i64.const 0)))))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-local-arg-void-vs-num (local i32) (local.tee 0 (nop))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-arg-num-vs-num (local i32) (local.tee 0 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-arg-num-vs-num (local f32) (local.tee 0 (f64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-arg-num-vs-num (local f64 i64) (local.tee 1 (f64.const 0))))
+  "type mismatch"
+)
+
+
+;; Invalid typing of access to parameters
+
+(assert_invalid
+  (module (func $type-param-num-vs-num (param i32) (result i64) (local.get 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-num-vs-num (param f32) (i32.eqz (local.get 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-num-vs-num (param f64 i64) (f64.neg (local.get 1))))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-param-arg-void-vs-num (param i32) (local.tee 0 (nop))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-arg-num-vs-num (param i32) (local.tee 0 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-arg-num-vs-num (param f32) (local.tee 0 (f64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-arg-num-vs-num (param f64 i64) (local.tee 1 (f64.const 0))))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num (param i32)
+      (local.tee 0) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-block (param i32)
+      (i32.const 0)
+      (block (local.tee 0) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-loop (param i32)
+      (i32.const 0)
+      (loop (local.tee 0) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-then (param i32)
+      (i32.const 0) (i32.const 0)
+      (if (then (local.tee 0) (drop)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-else (param i32)
+      (i32.const 0) (i32.const 0)
+      (if (result i32) (then (i32.const 0)) (else (local.tee 0))) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-br (param i32)
+      (i32.const 0)
+      (block (br 0 (local.tee 0)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-br_if (param i32)
+      (i32.const 0)
+      (block (br_if 0 (local.tee 0) (i32.const 1)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-br_table (param i32)
+      (i32.const 0)
+      (block (br_table 0 (local.tee 0)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-return (param i32)
+      (return (local.tee 0)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-select (param i32)
+      (select (local.tee 0) (i32.const 1) (i32.const 2)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-call (param i32)
+      (call 1 (local.tee 0)) (drop)
+    )
+    (func (param i32) (result i32) (local.get 0))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $f (param i32) (result i32) (local.get 0))
+    (type $sig (func (param i32) (result i32)))
+    (table funcref (elem $f))
+    (func $type-param-arg-empty-vs-num-in-call_indirect (param i32)
+      (block (result i32)
+        (call_indirect (type $sig)
+          (local.tee 0) (i32.const 0)
+        )
+        (drop)
+      )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-local.set (param i32)
+      (local.set 0 (local.tee 0)) (local.get 0) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-param-arg-empty-vs-num-in-local.tee (param i32)
+      (local.tee 0 (local.tee 0)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-param-arg-empty-vs-num-in-global.set (param i32)
+      (global.set $x (local.tee 0)) (global.get $x) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-param-arg-empty-vs-num-in-memory.grow (param i32)
+      (memory.grow (local.tee 0)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-param-arg-empty-vs-num-in-load (param i32)
+      (i32.load (local.tee 0)) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-param-arg-empty-vs-num-in-store (param i32)
+      (i32.store (local.tee 0) (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
+
+
+;; Invalid local index
+
+(assert_invalid
+  (module (func $unbound-local (local i32 i64) (local.get 3)))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-local (local i32 i64) (local.get 14324343)))
+  "unknown local"
+)
+
+(assert_invalid
+  (module (func $unbound-param (param i32 i64) (local.get 2)))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-param (local i32 i64) (local.get 714324343)))
+  "unknown local"
+)
+
+(assert_invalid
+  (module (func $unbound-mixed (param i32) (local i32 i64) (local.get 3)))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-mixed (param i64) (local i32 i64) (local.get 214324343)))
+  "unknown local"
+)
+
+(assert_invalid
+  (module (func $type-mixed-arg-num-vs-num (param f32) (local i32) (local.tee 1 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-mixed-arg-num-vs-num (param i64 i32) (local f32) (local.tee 1 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-mixed-arg-num-vs-num (param i64) (local f64 i64) (local.tee 1 (i64.const 0))))
+  "type mismatch"
+)
diff --git a/binaryen/test/spec/loop.wast b/binaryen/test/spec/loop.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/loop.wast
@@ -0,0 +1,469 @@
+;; Test `loop` opcode
+
+(module
+  (memory 1)
+
+  (func $dummy)
+
+  (func (export "empty")
+    (loop)
+    (loop $l)
+  )
+
+  (func (export "singular") (result i32)
+    (loop (nop))
+    (loop (result i32) (i32.const 7))
+  )
+
+  (func (export "multi") (result i32)
+    (loop (call $dummy) (call $dummy) (call $dummy) (call $dummy))
+    (loop (result i32) (call $dummy) (call $dummy) (call $dummy) (i32.const 8))
+  )
+
+  (func (export "nested") (result i32)
+    (loop (result i32)
+      (loop (call $dummy) (block) (nop))
+      (loop (result i32) (call $dummy) (i32.const 9))
+    )
+  )
+
+  (func (export "deep") (result i32)
+    (loop (result i32) (block (result i32)
+      (loop (result i32) (block (result i32)
+        (loop (result i32) (block (result i32)
+          (loop (result i32) (block (result i32)
+            (loop (result i32) (block (result i32)
+              (loop (result i32) (block (result i32)
+                (loop (result i32) (block (result i32)
+                  (loop (result i32) (block (result i32)
+                    (loop (result i32) (block (result i32)
+                      (loop (result i32) (block (result i32)
+                        (loop (result i32) (block (result i32)
+                          (loop (result i32) (block (result i32)
+                            (loop (result i32) (block (result i32)
+                              (loop (result i32) (block (result i32)
+                                (loop (result i32) (block (result i32)
+                                  (loop (result i32) (block (result i32)
+                                    (loop (result i32) (block (result i32)
+                                      (loop (result i32) (block (result i32)
+                                        (loop (result i32) (block (result i32)
+                                          (loop (result i32) (block (result i32)
+                                            (call $dummy) (i32.const 150)
+                                          ))
+                                        ))
+                                      ))
+                                    ))
+                                  ))
+                                ))
+                              ))
+                            ))
+                          ))
+                        ))
+                      ))
+                    ))
+                  ))
+                ))
+              ))
+            ))
+          ))
+        ))
+      ))
+    ))
+  )
+
+  (func (export "as-select-first") (result i32)
+    (select (loop (result i32) (i32.const 1)) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-select-mid") (result i32)
+    (select (i32.const 2) (loop (result i32) (i32.const 1)) (i32.const 3))
+  )
+  (func (export "as-select-last") (result i32)
+    (select (i32.const 2) (i32.const 3) (loop (result i32) (i32.const 1)))
+  )
+
+  (func (export "as-if-condition")
+    (loop (result i32) (i32.const 1)) (if (then (call $dummy)))
+  )
+  (func (export "as-if-then") (result i32)
+    (if (result i32) (i32.const 1) (then (loop (result i32) (i32.const 1))) (else (i32.const 2)))
+  )
+  (func (export "as-if-else") (result i32)
+    (if (result i32) (i32.const 1) (then (i32.const 2)) (else (loop (result i32) (i32.const 1))))
+  )
+
+  (func (export "as-br_if-first") (result i32)
+    (block (result i32) (br_if 0 (loop (result i32) (i32.const 1)) (i32.const 2)))
+  )
+  (func (export "as-br_if-last") (result i32)
+    (block (result i32) (br_if 0 (i32.const 2) (loop (result i32) (i32.const 1))))
+  )
+
+  (func (export "as-br_table-first") (result i32)
+    (block (result i32) (loop (result i32) (i32.const 1)) (i32.const 2) (br_table 0 0))
+  )
+  (func (export "as-br_table-last") (result i32)
+    (block (result i32) (i32.const 2) (loop (result i32) (i32.const 1)) (br_table 0 0))
+  )
+
+  (func $func (param i32 i32) (result i32) (local.get 0))
+  (type $check (func (param i32 i32) (result i32)))
+  (table funcref (elem $func))
+  (func (export "as-call_indirect-first") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (loop (result i32) (i32.const 1)) (i32.const 2) (i32.const 0)
+      )
+    )
+  )
+  (func (export "as-call_indirect-mid") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (i32.const 2) (loop (result i32) (i32.const 1)) (i32.const 0)
+      )
+    )
+  )
+  (func (export "as-call_indirect-last") (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (i32.const 1) (i32.const 2) (loop (result i32) (i32.const 0))
+      )
+    )
+  )
+
+  (func (export "as-store-first")
+    (loop (result i32) (i32.const 1)) (i32.const 1) (i32.store)
+  )
+  (func (export "as-store-last")
+    (i32.const 10) (loop (result i32) (i32.const 1)) (i32.store)
+  )
+
+  (func (export "as-memory.grow-value") (result i32)
+    (memory.grow (loop (result i32) (i32.const 1)))
+  )
+
+  (func $f (param i32) (result i32) (local.get 0))
+
+  (func (export "as-call-value") (result i32)
+    (call $f (loop (result i32) (i32.const 1)))
+  )
+  (func (export "as-return-value") (result i32)
+    (loop (result i32) (i32.const 1)) (return)
+  )
+  (func (export "as-drop-operand")
+    (drop (loop (result i32) (i32.const 1)))
+  )
+  (func (export "as-br-value") (result i32)
+    (block (result i32) (br 0 (loop (result i32) (i32.const 1))))
+  )
+  (func (export "as-local.set-value") (result i32)
+    (local i32) (local.set 0 (loop (result i32) (i32.const 1))) (local.get 0)
+  )
+  (func (export "as-local.tee-value") (result i32)
+    (local i32) (local.tee 0 (loop (result i32) (i32.const 1)))
+  )
+  (global $a (mut i32) (i32.const 0))
+  (func (export "as-global.set-value") (result i32)
+    (global.set $a (loop (result i32) (i32.const 1)))
+    (global.get $a)
+  )
+  (func (export "as-load-operand") (result i32)
+    (i32.load (loop (result i32) (i32.const 1)))
+  )
+
+  (func (export "as-unary-operand") (result i32)
+    (i32.ctz (loop (result i32) (call $dummy) (i32.const 13)))
+  )
+  (func (export "as-binary-operand") (result i32)
+    (i32.mul
+      (loop (result i32) (call $dummy) (i32.const 3))
+      (loop (result i32) (call $dummy) (i32.const 4))
+    )
+  )
+  (func (export "as-test-operand") (result i32)
+    (i32.eqz (loop (result i32) (call $dummy) (i32.const 13)))
+  )
+  (func (export "as-compare-operand") (result i32)
+    (f32.gt
+      (loop (result f32) (call $dummy) (f32.const 3))
+      (loop (result f32) (call $dummy) (f32.const 3))
+    )
+  )
+
+  (func (export "break-bare") (result i32)
+    (block (loop (br 1) (br 0) (unreachable)))
+    (block (loop (br_if 1 (i32.const 1)) (unreachable)))
+    (block (loop (br_table 1 (i32.const 0)) (unreachable)))
+    (block (loop (br_table 1 1 1 (i32.const 1)) (unreachable)))
+    (i32.const 19)
+  )
+  (func (export "break-value") (result i32)
+    (block (result i32)
+      (loop (result i32) (br 1 (i32.const 18)) (br 0) (i32.const 19))
+    )
+  )
+  (func (export "break-repeated") (result i32)
+    (block (result i32)
+      (loop (result i32)
+        (br 1 (i32.const 18))
+        (br 1 (i32.const 19))
+        (drop (br_if 1 (i32.const 20) (i32.const 0)))
+        (drop (br_if 1 (i32.const 20) (i32.const 1)))
+        (br 1 (i32.const 21))
+        (br_table 1 (i32.const 22) (i32.const 0))
+        (br_table 1 1 1 (i32.const 23) (i32.const 1))
+        (i32.const 21)
+      )
+    )
+  )
+  (func (export "break-inner") (result i32)
+    (local i32)
+    (local.set 0 (i32.const 0))
+    (local.set 0 (i32.add (local.get 0) (block (result i32) (loop (result i32) (block (result i32) (br 2 (i32.const 0x1)))))))
+    (local.set 0 (i32.add (local.get 0) (block (result i32) (loop (result i32) (loop (result i32) (br 2 (i32.const 0x2)))))))
+    (local.set 0 (i32.add (local.get 0) (block (result i32) (loop (result i32) (block (result i32) (loop (result i32) (br 1 (i32.const 0x4))))))))
+    (local.set 0 (i32.add (local.get 0) (block (result i32) (loop (result i32) (i32.ctz (br 1 (i32.const 0x8)))))))
+    (local.set 0 (i32.add (local.get 0) (block (result i32) (loop (result i32) (i32.ctz (loop (result i32) (br 2 (i32.const 0x10))))))))
+    (local.get 0)
+  )
+  (func (export "cont-inner") (result i32)
+    (local i32)
+    (local.set 0 (i32.const 0))
+    (local.set 0 (i32.add (local.get 0) (loop (result i32) (loop (result i32) (br 1)))))
+    (local.set 0 (i32.add (local.get 0) (loop (result i32) (i32.ctz (br 0)))))
+    (local.set 0 (i32.add (local.get 0) (loop (result i32) (i32.ctz (loop (result i32) (br 1))))))
+    (local.get 0)
+  )
+
+  (func $fx (export "effects") (result i32)
+    (local i32)
+    (block
+      (loop
+        (local.set 0 (i32.const 1))
+        (local.set 0 (i32.mul (local.get 0) (i32.const 3)))
+        (local.set 0 (i32.sub (local.get 0) (i32.const 5)))
+        (local.set 0 (i32.mul (local.get 0) (i32.const 7)))
+        (br 1)
+        (local.set 0 (i32.mul (local.get 0) (i32.const 100)))
+      )
+    )
+    (i32.eq (local.get 0) (i32.const -14))
+  )
+
+  (func (export "while") (param i64) (result i64)
+    (local i64)
+    (local.set 1 (i64.const 1))
+    (block
+      (loop
+        (br_if 1 (i64.eqz (local.get 0)))
+        (local.set 1 (i64.mul (local.get 0) (local.get 1)))
+        (local.set 0 (i64.sub (local.get 0) (i64.const 1)))
+        (br 0)
+      )
+    )
+    (local.get 1)
+  )
+
+  (func (export "for") (param i64) (result i64)
+    (local i64 i64)
+    (local.set 1 (i64.const 1))
+    (local.set 2 (i64.const 2))
+    (block
+      (loop
+        (br_if 1 (i64.gt_u (local.get 2) (local.get 0)))
+        (local.set 1 (i64.mul (local.get 1) (local.get 2)))
+        (local.set 2 (i64.add (local.get 2) (i64.const 1)))
+        (br 0)
+      )
+    )
+    (local.get 1)
+  )
+
+  (func (export "nesting") (param f32 f32) (result f32)
+    (local f32 f32)
+    (block
+      (loop
+        (br_if 1 (f32.eq (local.get 0) (f32.const 0)))
+        (local.set 2 (local.get 1))
+        (block
+          (loop
+            (br_if 1 (f32.eq (local.get 2) (f32.const 0)))
+            (br_if 3 (f32.lt (local.get 2) (f32.const 0)))
+            (local.set 3 (f32.add (local.get 3) (local.get 2)))
+            (local.set 2 (f32.sub (local.get 2) (f32.const 2)))
+            (br 0)
+          )
+        )
+        (local.set 3 (f32.div (local.get 3) (local.get 0)))
+        (local.set 0 (f32.sub (local.get 0) (f32.const 1)))
+        (br 0)
+      )
+    )
+    (local.get 3)
+  )
+)
+
+(assert_return (invoke "empty"))
+(assert_return (invoke "singular") (i32.const 7))
+(assert_return (invoke "multi") (i32.const 8))
+(assert_return (invoke "nested") (i32.const 9))
+(assert_return (invoke "deep") (i32.const 150))
+
+(assert_return (invoke "as-select-first") (i32.const 1))
+(assert_return (invoke "as-select-mid") (i32.const 2))
+(assert_return (invoke "as-select-last") (i32.const 2))
+
+(assert_return (invoke "as-if-condition"))
+(assert_return (invoke "as-if-then") (i32.const 1))
+(assert_return (invoke "as-if-else") (i32.const 2))
+
+(assert_return (invoke "as-br_if-first") (i32.const 1))
+(assert_return (invoke "as-br_if-last") (i32.const 2))
+
+(assert_return (invoke "as-br_table-first") (i32.const 1))
+(assert_return (invoke "as-br_table-last") (i32.const 2))
+
+(assert_return (invoke "as-call_indirect-first") (i32.const 1))
+(assert_return (invoke "as-call_indirect-mid") (i32.const 2))
+(assert_return (invoke "as-call_indirect-last") (i32.const 1))
+
+(assert_return (invoke "as-store-first"))
+(assert_return (invoke "as-store-last"))
+
+(assert_return (invoke "as-memory.grow-value") (i32.const 1))
+(assert_return (invoke "as-call-value") (i32.const 1))
+(assert_return (invoke "as-return-value") (i32.const 1))
+(assert_return (invoke "as-drop-operand"))
+(assert_return (invoke "as-br-value") (i32.const 1))
+(assert_return (invoke "as-local.set-value") (i32.const 1))
+(assert_return (invoke "as-local.tee-value") (i32.const 1))
+(assert_return (invoke "as-global.set-value") (i32.const 1))
+(assert_return (invoke "as-load-operand") (i32.const 1))
+
+(assert_return (invoke "as-unary-operand") (i32.const 0))
+(assert_return (invoke "as-binary-operand") (i32.const 12))
+(assert_return (invoke "as-test-operand") (i32.const 0))
+(assert_return (invoke "as-compare-operand") (i32.const 0))
+
+(assert_return (invoke "break-bare") (i32.const 19))
+(assert_return (invoke "break-value") (i32.const 18))
+(assert_return (invoke "break-repeated") (i32.const 18))
+(assert_return (invoke "break-inner") (i32.const 0x1f))
+
+(assert_return (invoke "effects") (i32.const 1))
+
+(assert_return (invoke "while" (i64.const 0)) (i64.const 1))
+(assert_return (invoke "while" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "while" (i64.const 2)) (i64.const 2))
+(assert_return (invoke "while" (i64.const 3)) (i64.const 6))
+(assert_return (invoke "while" (i64.const 5)) (i64.const 120))
+(assert_return (invoke "while" (i64.const 20)) (i64.const 2432902008176640000))
+
+(assert_return (invoke "for" (i64.const 0)) (i64.const 1))
+(assert_return (invoke "for" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "for" (i64.const 2)) (i64.const 2))
+(assert_return (invoke "for" (i64.const 3)) (i64.const 6))
+(assert_return (invoke "for" (i64.const 5)) (i64.const 120))
+(assert_return (invoke "for" (i64.const 20)) (i64.const 2432902008176640000))
+
+(assert_return (invoke "nesting" (f32.const 0) (f32.const 7)) (f32.const 0))
+(assert_return (invoke "nesting" (f32.const 7) (f32.const 0)) (f32.const 0))
+(assert_return (invoke "nesting" (f32.const 1) (f32.const 1)) (f32.const 1))
+(assert_return (invoke "nesting" (f32.const 1) (f32.const 2)) (f32.const 2))
+(assert_return (invoke "nesting" (f32.const 1) (f32.const 3)) (f32.const 4))
+(assert_return (invoke "nesting" (f32.const 1) (f32.const 4)) (f32.const 6))
+(assert_return (invoke "nesting" (f32.const 1) (f32.const 100)) (f32.const 2550))
+(assert_return (invoke "nesting" (f32.const 1) (f32.const 101)) (f32.const 2601))
+(assert_return (invoke "nesting" (f32.const 2) (f32.const 1)) (f32.const 1))
+(assert_return (invoke "nesting" (f32.const 3) (f32.const 1)) (f32.const 1))
+(assert_return (invoke "nesting" (f32.const 10) (f32.const 1)) (f32.const 1))
+(assert_return (invoke "nesting" (f32.const 2) (f32.const 2)) (f32.const 3))
+(assert_return (invoke "nesting" (f32.const 2) (f32.const 3)) (f32.const 4))
+(assert_return (invoke "nesting" (f32.const 7) (f32.const 4)) (f32.const 10.3095235825))
+(assert_return (invoke "nesting" (f32.const 7) (f32.const 100)) (f32.const 4381.54785156))
+(assert_return (invoke "nesting" (f32.const 7) (f32.const 101)) (f32.const 2601))
+
+(assert_invalid
+  (module (func $type-empty-i32 (result i32) (loop)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-i64 (result i64) (loop)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f32 (result f32) (loop)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f64 (result f64) (loop)))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-value-num-vs-void
+    (loop (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-empty-vs-num (result i32)
+    (loop (result i32))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-void-vs-num (result i32)
+    (loop (result i32) (nop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-num-vs-num (result i32)
+    (loop (result i32) (f32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-unreached-select (result i32)
+    (loop (result i64) (select (unreachable) (unreachable) (unreachable)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (func $type-value-empty-in-block
+      (i32.const 0)
+      (block (loop (result i32)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-in-loop
+      (i32.const 0)
+      (loop (loop (result i32)) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-in-then
+      (i32.const 0) (i32.const 0)
+      (if (then (loop (result i32)) (drop)))
+    )
+  )
+  "type mismatch"
+)
+
+
+(assert_malformed
+  (module quote "(func loop end $l)")
+  "mismatching label"
+)
+(assert_malformed
+  (module quote "(func loop $a end $l)")
+  "mismatching label"
+)
diff --git a/binaryen/test/spec/memory.wast b/binaryen/test/spec/memory.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/memory.wast
@@ -0,0 +1,212 @@
+;; Test memory section structure
+
+(module (memory 0 0))
+(module (memory 0 1))
+(module (memory 1 256))
+(module (memory 0 65536))
+
+(assert_invalid (module (memory 0) (memory 0)) "multiple memories")
+(assert_invalid (module (memory (import "spectest" "memory") 0) (memory 0)) "multiple memories")
+
+(module (memory (data)) (func (export "memsize") (result i32) (memory.size)))
+(assert_return (invoke "memsize") (i32.const 0))
+(module (memory (data "")) (func (export "memsize") (result i32) (memory.size)))
+(assert_return (invoke "memsize") (i32.const 0))
+(module (memory (data "x")) (func (export "memsize") (result i32) (memory.size)))
+(assert_return (invoke "memsize") (i32.const 1))
+
+(assert_invalid (module (data (i32.const 0))) "unknown memory")
+(assert_invalid (module (data (i32.const 0) "")) "unknown memory")
+(assert_invalid (module (data (i32.const 0) "x")) "unknown memory")
+
+(assert_invalid
+  (module (func (drop (f32.load (i32.const 0)))))
+  "unknown memory"
+)
+(assert_invalid
+  (module (func (f32.store (i32.const 0) (f32.const 0))))
+  "unknown memory"
+)
+(assert_invalid
+  (module (func (drop (i32.load8_s (i32.const 0)))))
+  "unknown memory"
+)
+(assert_invalid
+  (module (func (i32.store8 (i32.const 0) (i32.const 0))))
+  "unknown memory"
+)
+(assert_invalid
+  (module (func (drop (memory.size))))
+  "unknown memory"
+)
+(assert_invalid
+  (module (func (drop (memory.grow (i32.const 0)))))
+  "unknown memory"
+)
+
+
+(assert_invalid
+  (module (memory 1 0))
+  "size minimum must not be greater than maximum"
+)
+(assert_invalid
+  (module (memory 65537))
+  "memory size must be at most 65536 pages (4GiB)"
+)
+(assert_invalid
+  (module (memory 2147483648))
+  "memory size must be at most 65536 pages (4GiB)"
+)
+(assert_invalid
+  (module (memory 4294967295))
+  "memory size must be at most 65536 pages (4GiB)"
+)
+(assert_invalid
+  (module (memory 0 65537))
+  "memory size must be at most 65536 pages (4GiB)"
+)
+(assert_invalid
+  (module (memory 0 2147483648))
+  "memory size must be at most 65536 pages (4GiB)"
+)
+(assert_invalid
+  (module (memory 0 4294967295))
+  "memory size must be at most 65536 pages (4GiB)"
+)
+
+(module
+  (memory 1)
+  (data (i32.const 0) "ABC\a7D") (data (i32.const 20) "WASM")
+
+  ;; Data section
+  (func (export "data") (result i32)
+    (i32.and
+      (i32.and
+        (i32.and
+          (i32.eq (i32.load8_u (i32.const 0)) (i32.const 65))
+          (i32.eq (i32.load8_u (i32.const 3)) (i32.const 167))
+        )
+        (i32.and
+          (i32.eq (i32.load8_u (i32.const 6)) (i32.const 0))
+          (i32.eq (i32.load8_u (i32.const 19)) (i32.const 0))
+        )
+      )
+      (i32.and
+        (i32.and
+          (i32.eq (i32.load8_u (i32.const 20)) (i32.const 87))
+          (i32.eq (i32.load8_u (i32.const 23)) (i32.const 77))
+        )
+        (i32.and
+          (i32.eq (i32.load8_u (i32.const 24)) (i32.const 0))
+          (i32.eq (i32.load8_u (i32.const 1023)) (i32.const 0))
+        )
+      )
+    )
+  )
+
+  ;; Memory cast
+  (func (export "cast") (result f64)
+    (i64.store (i32.const 8) (i64.const -12345))
+    (if
+      (f64.eq
+        (f64.load (i32.const 8))
+        (f64.reinterpret_i64 (i64.const -12345))
+      )
+      (then (return (f64.const 0)))
+    )
+    (i64.store align=1 (i32.const 9) (i64.const 0))
+    (i32.store16 align=1 (i32.const 15) (i32.const 16453))
+    (f64.load align=1 (i32.const 9))
+  )
+
+  ;; Sign and zero extending memory loads
+  (func (export "i32_load8_s") (param $i i32) (result i32)
+	(i32.store8 (i32.const 8) (local.get $i))
+	(i32.load8_s (i32.const 8))
+  )
+  (func (export "i32_load8_u") (param $i i32) (result i32)
+	(i32.store8 (i32.const 8) (local.get $i))
+	(i32.load8_u (i32.const 8))
+  )
+  (func (export "i32_load16_s") (param $i i32) (result i32)
+	(i32.store16 (i32.const 8) (local.get $i))
+	(i32.load16_s (i32.const 8))
+  )
+  (func (export "i32_load16_u") (param $i i32) (result i32)
+	(i32.store16 (i32.const 8) (local.get $i))
+	(i32.load16_u (i32.const 8))
+  )
+  (func (export "i64_load8_s") (param $i i64) (result i64)
+	(i64.store8 (i32.const 8) (local.get $i))
+	(i64.load8_s (i32.const 8))
+  )
+  (func (export "i64_load8_u") (param $i i64) (result i64)
+	(i64.store8 (i32.const 8) (local.get $i))
+	(i64.load8_u (i32.const 8))
+  )
+  (func (export "i64_load16_s") (param $i i64) (result i64)
+	(i64.store16 (i32.const 8) (local.get $i))
+	(i64.load16_s (i32.const 8))
+  )
+  (func (export "i64_load16_u") (param $i i64) (result i64)
+	(i64.store16 (i32.const 8) (local.get $i))
+	(i64.load16_u (i32.const 8))
+  )
+  (func (export "i64_load32_s") (param $i i64) (result i64)
+	(i64.store32 (i32.const 8) (local.get $i))
+	(i64.load32_s (i32.const 8))
+  )
+  (func (export "i64_load32_u") (param $i i64) (result i64)
+	(i64.store32 (i32.const 8) (local.get $i))
+	(i64.load32_u (i32.const 8))
+  )
+)
+
+(assert_return (invoke "data") (i32.const 1))
+(assert_return (invoke "cast") (f64.const 42.0))
+
+(assert_return (invoke "i32_load8_s" (i32.const -1)) (i32.const -1))
+(assert_return (invoke "i32_load8_u" (i32.const -1)) (i32.const 255))
+(assert_return (invoke "i32_load16_s" (i32.const -1)) (i32.const -1))
+(assert_return (invoke "i32_load16_u" (i32.const -1)) (i32.const 65535))
+
+(assert_return (invoke "i32_load8_s" (i32.const 100)) (i32.const 100))
+(assert_return (invoke "i32_load8_u" (i32.const 200)) (i32.const 200))
+(assert_return (invoke "i32_load16_s" (i32.const 20000)) (i32.const 20000))
+(assert_return (invoke "i32_load16_u" (i32.const 40000)) (i32.const 40000))
+
+(assert_return (invoke "i32_load8_s" (i32.const 0xfedc6543)) (i32.const 0x43))
+(assert_return (invoke "i32_load8_s" (i32.const 0x3456cdef)) (i32.const 0xffffffef))
+(assert_return (invoke "i32_load8_u" (i32.const 0xfedc6543)) (i32.const 0x43))
+(assert_return (invoke "i32_load8_u" (i32.const 0x3456cdef)) (i32.const 0xef))
+(assert_return (invoke "i32_load16_s" (i32.const 0xfedc6543)) (i32.const 0x6543))
+(assert_return (invoke "i32_load16_s" (i32.const 0x3456cdef)) (i32.const 0xffffcdef))
+(assert_return (invoke "i32_load16_u" (i32.const 0xfedc6543)) (i32.const 0x6543))
+(assert_return (invoke "i32_load16_u" (i32.const 0x3456cdef)) (i32.const 0xcdef))
+
+(assert_return (invoke "i64_load8_s" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_load8_u" (i64.const -1)) (i64.const 255))
+(assert_return (invoke "i64_load16_s" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_load16_u" (i64.const -1)) (i64.const 65535))
+(assert_return (invoke "i64_load32_s" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_load32_u" (i64.const -1)) (i64.const 4294967295))
+
+(assert_return (invoke "i64_load8_s" (i64.const 100)) (i64.const 100))
+(assert_return (invoke "i64_load8_u" (i64.const 200)) (i64.const 200))
+(assert_return (invoke "i64_load16_s" (i64.const 20000)) (i64.const 20000))
+(assert_return (invoke "i64_load16_u" (i64.const 40000)) (i64.const 40000))
+(assert_return (invoke "i64_load32_s" (i64.const 20000)) (i64.const 20000))
+(assert_return (invoke "i64_load32_u" (i64.const 40000)) (i64.const 40000))
+
+(assert_return (invoke "i64_load8_s" (i64.const 0xfedcba9856346543)) (i64.const 0x43))
+(assert_return (invoke "i64_load8_s" (i64.const 0x3456436598bacdef)) (i64.const 0xffffffffffffffef))
+(assert_return (invoke "i64_load8_u" (i64.const 0xfedcba9856346543)) (i64.const 0x43))
+(assert_return (invoke "i64_load8_u" (i64.const 0x3456436598bacdef)) (i64.const 0xef))
+(assert_return (invoke "i64_load16_s" (i64.const 0xfedcba9856346543)) (i64.const 0x6543))
+(assert_return (invoke "i64_load16_s" (i64.const 0x3456436598bacdef)) (i64.const 0xffffffffffffcdef))
+(assert_return (invoke "i64_load16_u" (i64.const 0xfedcba9856346543)) (i64.const 0x6543))
+(assert_return (invoke "i64_load16_u" (i64.const 0x3456436598bacdef)) (i64.const 0xcdef))
+(assert_return (invoke "i64_load32_s" (i64.const 0xfedcba9856346543)) (i64.const 0x56346543))
+(assert_return (invoke "i64_load32_s" (i64.const 0x3456436598bacdef)) (i64.const 0xffffffff98bacdef))
+(assert_return (invoke "i64_load32_u" (i64.const 0xfedcba9856346543)) (i64.const 0x56346543))
+(assert_return (invoke "i64_load32_u" (i64.const 0x3456436598bacdef)) (i64.const 0x98bacdef))
diff --git a/binaryen/test/spec/memory64.wast b/binaryen/test/spec/memory64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/memory64.wast
@@ -0,0 +1,188 @@
+;; Test memory section structure
+
+(module (memory i64 0 0))
+(module (memory i64 0 1))
+(module (memory i64 1 256))
+(module (memory i64 0 65536))
+
+(assert_invalid (module (memory i64 0) (memory i64 0)) "multiple memories")
+(assert_invalid (module (memory (import "spectest" "memory") i64 0) (memory i64 0)) "multiple memories")
+
+(module (memory i64 (data)) (func (export "memsize") (result i64) (memory.size)))
+(assert_return (invoke "memsize") (i64.const 0))
+(module (memory i64 (data "")) (func (export "memsize") (result i64) (memory.size)))
+(assert_return (invoke "memsize") (i64.const 0))
+(module (memory i64 (data "x")) (func (export "memsize") (result i64) (memory.size)))
+(assert_return (invoke "memsize") (i64.const 1))
+
+(assert_invalid (module (data (i32.const 0))) "unknown memory")
+(assert_invalid (module (data (i32.const 0) "")) "unknown memory")
+(assert_invalid (module (data (i32.const 0) "x")) "unknown memory")
+
+(assert_invalid
+  (module (func (drop (f32.load (i64.const 0)))))
+  "unknown memory"
+)
+(assert_invalid
+  (module (func (f32.store (i64.const 0) (f32.const 0))))
+  "unknown memory"
+)
+(assert_invalid
+  (module (func (drop (i32.load8_s (i64.const 0)))))
+  "unknown memory"
+)
+(assert_invalid
+  (module (func (i32.store8 (i64.const 0) (i32.const 0))))
+  "unknown memory"
+)
+(assert_invalid
+  (module (func (drop (memory.size))))
+  "unknown memory"
+)
+(assert_invalid
+  (module (func (drop (memory.grow (i64.const 0)))))
+  "unknown memory"
+)
+
+
+(assert_invalid
+  (module (memory i64 1 0))
+  "size minimum must not be greater than maximum"
+)
+
+(module
+  (memory i64 1)
+  (data (i32.const 0) "ABC\a7D") (data (i32.const 20) "WASM")
+
+  ;; Data section
+  (func (export "data") (result i32)
+    (i32.and
+      (i32.and
+        (i32.and
+          (i32.eq (i32.load8_u (i64.const 0)) (i32.const 65))
+          (i32.eq (i32.load8_u (i64.const 3)) (i32.const 167))
+        )
+        (i32.and
+          (i32.eq (i32.load8_u (i64.const 6)) (i32.const 0))
+          (i32.eq (i32.load8_u (i64.const 19)) (i32.const 0))
+        )
+      )
+      (i32.and
+        (i32.and
+          (i32.eq (i32.load8_u (i64.const 20)) (i32.const 87))
+          (i32.eq (i32.load8_u (i64.const 23)) (i32.const 77))
+        )
+        (i32.and
+          (i32.eq (i32.load8_u (i64.const 24)) (i32.const 0))
+          (i32.eq (i32.load8_u (i64.const 1023)) (i32.const 0))
+        )
+      )
+    )
+  )
+
+  ;; Memory cast
+  (func (export "cast") (result f64)
+    (i64.store (i64.const 8) (i64.const -12345))
+    (if
+      (f64.eq
+        (f64.load (i64.const 8))
+        (f64.reinterpret_i64 (i64.const -12345))
+      )
+      (then (return (f64.const 0)))
+    )
+    (i64.store align=1 (i64.const 9) (i64.const 0))
+    (i32.store16 align=1 (i64.const 15) (i32.const 16453))
+    (f64.load align=1 (i64.const 9))
+  )
+
+  ;; Sign and zero extending memory loads
+  (func (export "i32_load8_s") (param $i i32) (result i32)
+	(i32.store8 (i64.const 8) (local.get $i))
+	(i32.load8_s (i64.const 8))
+  )
+  (func (export "i32_load8_u") (param $i i32) (result i32)
+	(i32.store8 (i64.const 8) (local.get $i))
+	(i32.load8_u (i64.const 8))
+  )
+  (func (export "i32_load16_s") (param $i i32) (result i32)
+	(i32.store16 (i64.const 8) (local.get $i))
+	(i32.load16_s (i64.const 8))
+  )
+  (func (export "i32_load16_u") (param $i i32) (result i32)
+	(i32.store16 (i64.const 8) (local.get $i))
+	(i32.load16_u (i64.const 8))
+  )
+  (func (export "i64_load8_s") (param $i i64) (result i64)
+	(i64.store8 (i64.const 8) (local.get $i))
+	(i64.load8_s (i64.const 8))
+  )
+  (func (export "i64_load8_u") (param $i i64) (result i64)
+	(i64.store8 (i64.const 8) (local.get $i))
+	(i64.load8_u (i64.const 8))
+  )
+  (func (export "i64_load16_s") (param $i i64) (result i64)
+	(i64.store16 (i64.const 8) (local.get $i))
+	(i64.load16_s (i64.const 8))
+  )
+  (func (export "i64_load16_u") (param $i i64) (result i64)
+	(i64.store16 (i64.const 8) (local.get $i))
+	(i64.load16_u (i64.const 8))
+  )
+  (func (export "i64_load32_s") (param $i i64) (result i64)
+	(i64.store32 (i64.const 8) (local.get $i))
+	(i64.load32_s (i64.const 8))
+  )
+  (func (export "i64_load32_u") (param $i i64) (result i64)
+	(i64.store32 (i64.const 8) (local.get $i))
+	(i64.load32_u (i64.const 8))
+  )
+)
+
+(assert_return (invoke "data") (i32.const 1))
+(assert_return (invoke "cast") (f64.const 42.0))
+
+(assert_return (invoke "i32_load8_s" (i32.const -1)) (i32.const -1))
+(assert_return (invoke "i32_load8_u" (i32.const -1)) (i32.const 255))
+(assert_return (invoke "i32_load16_s" (i32.const -1)) (i32.const -1))
+(assert_return (invoke "i32_load16_u" (i32.const -1)) (i32.const 65535))
+
+(assert_return (invoke "i32_load8_s" (i32.const 100)) (i32.const 100))
+(assert_return (invoke "i32_load8_u" (i32.const 200)) (i32.const 200))
+(assert_return (invoke "i32_load16_s" (i32.const 20000)) (i32.const 20000))
+(assert_return (invoke "i32_load16_u" (i32.const 40000)) (i32.const 40000))
+
+(assert_return (invoke "i32_load8_s" (i32.const 0xfedc6543)) (i32.const 0x43))
+(assert_return (invoke "i32_load8_s" (i32.const 0x3456cdef)) (i32.const 0xffffffef))
+(assert_return (invoke "i32_load8_u" (i32.const 0xfedc6543)) (i32.const 0x43))
+(assert_return (invoke "i32_load8_u" (i32.const 0x3456cdef)) (i32.const 0xef))
+(assert_return (invoke "i32_load16_s" (i32.const 0xfedc6543)) (i32.const 0x6543))
+(assert_return (invoke "i32_load16_s" (i32.const 0x3456cdef)) (i32.const 0xffffcdef))
+(assert_return (invoke "i32_load16_u" (i32.const 0xfedc6543)) (i32.const 0x6543))
+(assert_return (invoke "i32_load16_u" (i32.const 0x3456cdef)) (i32.const 0xcdef))
+
+(assert_return (invoke "i64_load8_s" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_load8_u" (i64.const -1)) (i64.const 255))
+(assert_return (invoke "i64_load16_s" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_load16_u" (i64.const -1)) (i64.const 65535))
+(assert_return (invoke "i64_load32_s" (i64.const -1)) (i64.const -1))
+(assert_return (invoke "i64_load32_u" (i64.const -1)) (i64.const 4294967295))
+
+(assert_return (invoke "i64_load8_s" (i64.const 100)) (i64.const 100))
+(assert_return (invoke "i64_load8_u" (i64.const 200)) (i64.const 200))
+(assert_return (invoke "i64_load16_s" (i64.const 20000)) (i64.const 20000))
+(assert_return (invoke "i64_load16_u" (i64.const 40000)) (i64.const 40000))
+(assert_return (invoke "i64_load32_s" (i64.const 20000)) (i64.const 20000))
+(assert_return (invoke "i64_load32_u" (i64.const 40000)) (i64.const 40000))
+
+(assert_return (invoke "i64_load8_s" (i64.const 0xfedcba9856346543)) (i64.const 0x43))
+(assert_return (invoke "i64_load8_s" (i64.const 0x3456436598bacdef)) (i64.const 0xffffffffffffffef))
+(assert_return (invoke "i64_load8_u" (i64.const 0xfedcba9856346543)) (i64.const 0x43))
+(assert_return (invoke "i64_load8_u" (i64.const 0x3456436598bacdef)) (i64.const 0xef))
+(assert_return (invoke "i64_load16_s" (i64.const 0xfedcba9856346543)) (i64.const 0x6543))
+(assert_return (invoke "i64_load16_s" (i64.const 0x3456436598bacdef)) (i64.const 0xffffffffffffcdef))
+(assert_return (invoke "i64_load16_u" (i64.const 0xfedcba9856346543)) (i64.const 0x6543))
+(assert_return (invoke "i64_load16_u" (i64.const 0x3456436598bacdef)) (i64.const 0xcdef))
+(assert_return (invoke "i64_load32_s" (i64.const 0xfedcba9856346543)) (i64.const 0x56346543))
+(assert_return (invoke "i64_load32_s" (i64.const 0x3456436598bacdef)) (i64.const 0xffffffff98bacdef))
+(assert_return (invoke "i64_load32_u" (i64.const 0xfedcba9856346543)) (i64.const 0x56346543))
+(assert_return (invoke "i64_load32_u" (i64.const 0x3456436598bacdef)) (i64.const 0x98bacdef))
diff --git a/binaryen/test/spec/memory_grow.wast b/binaryen/test/spec/memory_grow.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/memory_grow.wast
@@ -0,0 +1,355 @@
+(module
+    (memory 0)
+
+    (func (export "load_at_zero") (result i32) (i32.load (i32.const 0)))
+    (func (export "store_at_zero") (i32.store (i32.const 0) (i32.const 2)))
+
+    (func (export "load_at_page_size") (result i32) (i32.load (i32.const 0x10000)))
+    (func (export "store_at_page_size") (i32.store (i32.const 0x10000) (i32.const 3)))
+
+    (func (export "grow") (param $sz i32) (result i32) (memory.grow (local.get $sz)))
+    (func (export "size") (result i32) (memory.size))
+)
+
+(assert_return (invoke "size") (i32.const 0))
+(assert_trap (invoke "store_at_zero") "out of bounds memory access")
+(assert_trap (invoke "load_at_zero") "out of bounds memory access")
+(assert_trap (invoke "store_at_page_size") "out of bounds memory access")
+(assert_trap (invoke "load_at_page_size") "out of bounds memory access")
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "size") (i32.const 1))
+(assert_return (invoke "load_at_zero") (i32.const 0))
+(assert_return (invoke "store_at_zero"))
+(assert_return (invoke "load_at_zero") (i32.const 2))
+(assert_trap (invoke "store_at_page_size") "out of bounds memory access")
+(assert_trap (invoke "load_at_page_size") "out of bounds memory access")
+(assert_return (invoke "grow" (i32.const 4)) (i32.const 1))
+(assert_return (invoke "size") (i32.const 5))
+(assert_return (invoke "load_at_zero") (i32.const 2))
+(assert_return (invoke "store_at_zero"))
+(assert_return (invoke "load_at_zero") (i32.const 2))
+(assert_return (invoke "load_at_page_size") (i32.const 0))
+(assert_return (invoke "store_at_page_size"))
+(assert_return (invoke "load_at_page_size") (i32.const 3))
+
+
+(module
+  (memory 0)
+  (func (export "grow") (param i32) (result i32) (memory.grow (local.get 0)))
+)
+
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 2)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 800)) (i32.const 3))
+(assert_return (invoke "grow" (i32.const 0x10000)) (i32.const -1))
+(assert_return (invoke "grow" (i32.const 64736)) (i32.const -1))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 803))
+
+(module
+  (memory 0 10)
+  (func (export "grow") (param i32) (result i32) (memory.grow (local.get 0)))
+)
+
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "grow" (i32.const 6)) (i32.const 4))
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 10))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const -1))
+(assert_return (invoke "grow" (i32.const 0x10000)) (i32.const -1))
+
+;; Test that newly allocated memory (program start and memory.grow) is zeroed
+
+(module
+  (memory 1)
+  (func (export "grow") (param i32) (result i32)
+    (memory.grow (local.get 0))
+  )
+  (func (export "check-memory-zero") (param i32 i32) (result i32)
+    (local i32)
+    (local.set 2 (i32.const 1))
+    (block
+      (loop
+        (local.set 2 (i32.load8_u (local.get 0)))
+        (br_if 1 (i32.ne (local.get 2) (i32.const 0)))
+        (br_if 1 (i32.ge_u (local.get 0) (local.get 1)))
+        (local.set 0 (i32.add (local.get 0) (i32.const 1)))
+        (br_if 0 (i32.le_u (local.get 0) (local.get 1)))
+      )
+    )
+    (local.get 2)
+  )
+)
+
+(assert_return (invoke "check-memory-zero" (i32.const 0) (i32.const 0xffff)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "check-memory-zero" (i32.const 0x10000) (i32.const 0x1_ffff)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "check-memory-zero" (i32.const 0x20000) (i32.const 0x2_ffff)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 3))
+(assert_return (invoke "check-memory-zero" (i32.const 0x30000) (i32.const 0x3_ffff)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 4))
+(assert_return (invoke "check-memory-zero" (i32.const 0x40000) (i32.const 0x4_ffff)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 5))
+(assert_return (invoke "check-memory-zero" (i32.const 0x50000) (i32.const 0x5_ffff)) (i32.const 0))
+
+;; As the argument of control constructs and instructions
+
+(module
+  (memory 1)
+
+  (func (export "as-br-value") (result i32)
+    (block (result i32) (br 0 (memory.grow (i32.const 0))))
+  )
+
+  (func (export "as-br_if-cond")
+    (block (br_if 0 (memory.grow (i32.const 0))))
+  )
+  (func (export "as-br_if-value") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (memory.grow (i32.const 0)) (i32.const 1))) (i32.const 7)
+    )
+  )
+  (func (export "as-br_if-value-cond") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (i32.const 6) (memory.grow (i32.const 0)))) (i32.const 7)
+    )
+  )
+
+  (func (export "as-br_table-index")
+    (block (br_table 0 0 0 (memory.grow (i32.const 0))))
+  )
+  (func (export "as-br_table-value") (result i32)
+    (block (result i32)
+      (br_table 0 0 0 (memory.grow (i32.const 0)) (i32.const 1)) (i32.const 7)
+    )
+  )
+  (func (export "as-br_table-value-index") (result i32)
+    (block (result i32)
+      (br_table 0 0 (i32.const 6) (memory.grow (i32.const 0))) (i32.const 7)
+    )
+  )
+
+  (func (export "as-return-value") (result i32)
+    (return (memory.grow (i32.const 0)))
+  )
+
+  (func (export "as-if-cond") (result i32)
+    (if (result i32) (memory.grow (i32.const 0))
+      (then (i32.const 0)) (else (i32.const 1))
+    )
+  )
+  (func (export "as-if-then") (result i32)
+    (if (result i32) (i32.const 1)
+      (then (memory.grow (i32.const 0))) (else (i32.const 0))
+    )
+  )
+  (func (export "as-if-else") (result i32)
+    (if (result i32) (i32.const 0)
+      (then (i32.const 0)) (else (memory.grow (i32.const 0)))
+    )
+  )
+
+  (func (export "as-select-first") (param i32 i32) (result i32)
+    (select (memory.grow (i32.const 0)) (local.get 0) (local.get 1))
+  )
+  (func (export "as-select-second") (param i32 i32) (result i32)
+    (select (local.get 0) (memory.grow (i32.const 0)) (local.get 1))
+  )
+  (func (export "as-select-cond") (result i32)
+    (select (i32.const 0) (i32.const 1) (memory.grow (i32.const 0)))
+  )
+
+  (func $f (param i32 i32 i32) (result i32) (i32.const -1))
+  (func (export "as-call-first") (result i32)
+    (call $f (memory.grow (i32.const 0)) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-call-mid") (result i32)
+    (call $f (i32.const 1) (memory.grow (i32.const 0)) (i32.const 3))
+  )
+  (func (export "as-call-last") (result i32)
+    (call $f (i32.const 1) (i32.const 2) (memory.grow (i32.const 0)))
+  )
+
+  (type $sig (func (param i32 i32 i32) (result i32)))
+  (table funcref (elem $f))
+  (func (export "as-call_indirect-first") (result i32)
+    (call_indirect (type $sig)
+      (memory.grow (i32.const 0)) (i32.const 2) (i32.const 3) (i32.const 0)
+    )
+  )
+  (func (export "as-call_indirect-mid") (result i32)
+    (call_indirect (type $sig)
+      (i32.const 1) (memory.grow (i32.const 0)) (i32.const 3) (i32.const 0)
+    )
+  )
+  (func (export "as-call_indirect-last") (result i32)
+    (call_indirect (type $sig)
+      (i32.const 1) (i32.const 2) (memory.grow (i32.const 0)) (i32.const 0)
+    )
+  )
+  (func (export "as-call_indirect-index") (result i32)
+    (call_indirect (type $sig)
+      (i32.const 1) (i32.const 2) (i32.const 3) (memory.grow (i32.const 0))
+    )
+  )
+
+  (func (export "as-local.set-value") (local i32)
+    (local.set 0 (memory.grow (i32.const 0)))
+  )
+  (func (export "as-local.tee-value") (result i32) (local i32)
+    (local.tee 0 (memory.grow (i32.const 0)))
+  )
+  (global $g (mut i32) (i32.const 0))
+  (func (export "as-global.set-value") (local i32)
+    (global.set $g (memory.grow (i32.const 0)))
+  )
+
+  (func (export "as-load-address") (result i32)
+    (i32.load (memory.grow (i32.const 0)))
+  )
+  (func (export "as-loadN-address") (result i32)
+    (i32.load8_s (memory.grow (i32.const 0)))
+  )
+
+  (func (export "as-store-address")
+    (i32.store (memory.grow (i32.const 0)) (i32.const 7))
+  )
+  (func (export "as-store-value")
+    (i32.store (i32.const 2) (memory.grow (i32.const 0)))
+  )
+
+  (func (export "as-storeN-address")
+    (i32.store8 (memory.grow (i32.const 0)) (i32.const 7))
+  )
+  (func (export "as-storeN-value")
+    (i32.store16 (i32.const 2) (memory.grow (i32.const 0)))
+  )
+
+  (func (export "as-unary-operand") (result i32)
+    (i32.clz (memory.grow (i32.const 0)))
+  )
+
+  (func (export "as-binary-left") (result i32)
+    (i32.add (memory.grow (i32.const 0)) (i32.const 10))
+  )
+  (func (export "as-binary-right") (result i32)
+    (i32.sub (i32.const 10) (memory.grow (i32.const 0)))
+  )
+
+  (func (export "as-test-operand") (result i32)
+    (i32.eqz (memory.grow (i32.const 0)))
+  )
+
+  (func (export "as-compare-left") (result i32)
+    (i32.le_s (memory.grow (i32.const 0)) (i32.const 10))
+  )
+  (func (export "as-compare-right") (result i32)
+    (i32.ne (i32.const 10) (memory.grow (i32.const 0)))
+  )
+
+  (func (export "as-memory.grow-size") (result i32)
+    (memory.grow (memory.grow (i32.const 0)))
+  )
+)
+
+(assert_return (invoke "as-br-value") (i32.const 1))
+
+(assert_return (invoke "as-br_if-cond"))
+(assert_return (invoke "as-br_if-value") (i32.const 1))
+(assert_return (invoke "as-br_if-value-cond") (i32.const 6))
+
+(assert_return (invoke "as-br_table-index"))
+(assert_return (invoke "as-br_table-value") (i32.const 1))
+(assert_return (invoke "as-br_table-value-index") (i32.const 6))
+
+(assert_return (invoke "as-return-value") (i32.const 1))
+
+(assert_return (invoke "as-if-cond") (i32.const 0))
+(assert_return (invoke "as-if-then") (i32.const 1))
+(assert_return (invoke "as-if-else") (i32.const 1))
+
+(assert_return (invoke "as-select-first" (i32.const 0) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-select-second" (i32.const 0) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-select-cond") (i32.const 0))
+
+(assert_return (invoke "as-call-first") (i32.const -1))
+(assert_return (invoke "as-call-mid") (i32.const -1))
+(assert_return (invoke "as-call-last") (i32.const -1))
+
+(assert_return (invoke "as-call_indirect-first") (i32.const -1))
+(assert_return (invoke "as-call_indirect-mid") (i32.const -1))
+(assert_return (invoke "as-call_indirect-last") (i32.const -1))
+(assert_trap (invoke "as-call_indirect-index") "undefined element")
+
+(assert_return (invoke "as-local.set-value"))
+(assert_return (invoke "as-local.tee-value") (i32.const 1))
+(assert_return (invoke "as-global.set-value"))
+
+(assert_return (invoke "as-load-address") (i32.const 0))
+(assert_return (invoke "as-loadN-address") (i32.const 0))
+(assert_return (invoke "as-store-address"))
+(assert_return (invoke "as-store-value"))
+(assert_return (invoke "as-storeN-address"))
+(assert_return (invoke "as-storeN-value"))
+
+(assert_return (invoke "as-unary-operand") (i32.const 31))
+
+(assert_return (invoke "as-binary-left") (i32.const 11))
+(assert_return (invoke "as-binary-right") (i32.const 9))
+
+(assert_return (invoke "as-test-operand") (i32.const 0))
+
+(assert_return (invoke "as-compare-left") (i32.const 1))
+(assert_return (invoke "as-compare-right") (i32.const 1))
+
+(assert_return (invoke "as-memory.grow-size") (i32.const 1))
+
+
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-size-empty
+      (memory.grow) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-size-empty-in-block
+      (i32.const 0)
+      (block (memory.grow) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-size-empty-in-loop
+      (i32.const 0)
+      (loop (memory.grow) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-size-empty-in-then
+      (i32.const 0) (i32.const 0)
+      (if (then (memory.grow) (drop)))
+    )
+  )
+  "type mismatch"
+)
+
+
+;; Type check
+
+(assert_invalid (module (memory 1) (func (result i32) (memory.grow (f32.const 0)))) "type mismatch")
diff --git a/binaryen/test/spec/memory_grow64.wast b/binaryen/test/spec/memory_grow64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/memory_grow64.wast
@@ -0,0 +1,95 @@
+(module
+    (memory i64 0)
+
+    (func (export "load_at_zero") (result i32) (i32.load (i64.const 0)))
+    (func (export "store_at_zero") (i32.store (i64.const 0) (i32.const 2)))
+
+    (func (export "load_at_page_size") (result i32) (i32.load (i64.const 0x10000)))
+    (func (export "store_at_page_size") (i32.store (i64.const 0x10000) (i32.const 3)))
+
+    (func (export "grow") (param $sz i64) (result i64) (memory.grow (local.get $sz)))
+    (func (export "size") (result i64) (memory.size))
+)
+
+(assert_return (invoke "size") (i64.const 0))
+(assert_trap (invoke "store_at_zero") "out of bounds memory access")
+(assert_trap (invoke "load_at_zero") "out of bounds memory access")
+(assert_trap (invoke "store_at_page_size") "out of bounds memory access")
+(assert_trap (invoke "load_at_page_size") "out of bounds memory access")
+(assert_return (invoke "grow" (i64.const 1)) (i64.const 0))
+(assert_return (invoke "size") (i64.const 1))
+(assert_return (invoke "load_at_zero") (i32.const 0))
+(assert_return (invoke "store_at_zero"))
+(assert_return (invoke "load_at_zero") (i32.const 2))
+(assert_trap (invoke "store_at_page_size") "out of bounds memory access")
+(assert_trap (invoke "load_at_page_size") "out of bounds memory access")
+(assert_return (invoke "grow" (i64.const 4)) (i64.const 1))
+(assert_return (invoke "size") (i64.const 5))
+(assert_return (invoke "load_at_zero") (i32.const 2))
+(assert_return (invoke "store_at_zero"))
+(assert_return (invoke "load_at_zero") (i32.const 2))
+(assert_return (invoke "load_at_page_size") (i32.const 0))
+(assert_return (invoke "store_at_page_size"))
+(assert_return (invoke "load_at_page_size") (i32.const 3))
+
+
+(module
+  (memory i64 0)
+  (func (export "grow") (param i64) (result i64) (memory.grow (local.get 0)))
+)
+
+(assert_return (invoke "grow" (i64.const 0)) (i64.const 0))
+(assert_return (invoke "grow" (i64.const 1)) (i64.const 0))
+(assert_return (invoke "grow" (i64.const 0)) (i64.const 1))
+(assert_return (invoke "grow" (i64.const 2)) (i64.const 1))
+(assert_return (invoke "grow" (i64.const 800)) (i64.const 3))
+(assert_return (invoke "grow" (i64.const 1)) (i64.const 803))
+
+(module
+  (memory i64 0 10)
+  (func (export "grow") (param i64) (result i64) (memory.grow (local.get 0)))
+)
+
+(assert_return (invoke "grow" (i64.const 0)) (i64.const 0))
+(assert_return (invoke "grow" (i64.const 1)) (i64.const 0))
+(assert_return (invoke "grow" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "grow" (i64.const 2)) (i64.const 2))
+(assert_return (invoke "grow" (i64.const 6)) (i64.const 4))
+(assert_return (invoke "grow" (i64.const 0)) (i64.const 10))
+(assert_return (invoke "grow" (i64.const 1)) (i64.const -1))
+(assert_return (invoke "grow" (i64.const 0x10000)) (i64.const -1))
+
+;; Test that newly allocated memory (program start and memory.grow) is zeroed
+
+(module
+  (memory i64 1)
+  (func (export "grow") (param i64) (result i64)
+    (memory.grow (local.get 0))
+  )
+  (func (export "check-memory-zero") (param i64 i64) (result i32)
+    (local i32)
+    (local.set 2 (i32.const 1))
+    (block
+      (loop
+        (local.set 2 (i32.load8_u (local.get 0)))
+        (br_if 1 (i32.ne (local.get 2) (i32.const 0)))
+        (br_if 1 (i64.ge_u (local.get 0) (local.get 1)))
+        (local.set 0 (i64.add (local.get 0) (i64.const 1)))
+        (br_if 0 (i64.le_u (local.get 0) (local.get 1)))
+      )
+    )
+    (local.get 2)
+  )
+)
+
+(assert_return (invoke "check-memory-zero" (i64.const 0) (i64.const 0xffff)) (i32.const 0))
+(assert_return (invoke "grow" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "check-memory-zero" (i64.const 0x10000) (i64.const 0x1_ffff)) (i32.const 0))
+(assert_return (invoke "grow" (i64.const 1)) (i64.const 2))
+(assert_return (invoke "check-memory-zero" (i64.const 0x20000) (i64.const 0x2_ffff)) (i32.const 0))
+(assert_return (invoke "grow" (i64.const 1)) (i64.const 3))
+(assert_return (invoke "check-memory-zero" (i64.const 0x30000) (i64.const 0x3_ffff)) (i32.const 0))
+(assert_return (invoke "grow" (i64.const 1)) (i64.const 4))
+(assert_return (invoke "check-memory-zero" (i64.const 0x40000) (i64.const 0x4_ffff)) (i32.const 0))
+(assert_return (invoke "grow" (i64.const 1)) (i64.const 5))
+(assert_return (invoke "check-memory-zero" (i64.const 0x50000) (i64.const 0x5_ffff)) (i32.const 0))
diff --git a/binaryen/test/spec/memory_redundancy.wast b/binaryen/test/spec/memory_redundancy.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/memory_redundancy.wast
@@ -0,0 +1,65 @@
+;; Test that optimizers don't do redundant-load, store-to-load, or dead-store
+;; optimizations when there are interfering stores, even of different types
+;; and to non-identical addresses.
+
+(module
+  (memory 1 1)
+
+  (func (export "zero_everything")
+    (i32.store (i32.const 0) (i32.const 0))
+    (i32.store (i32.const 4) (i32.const 0))
+    (i32.store (i32.const 8) (i32.const 0))
+    (i32.store (i32.const 12) (i32.const 0))
+  )
+
+  (func (export "test_store_to_load") (result i32)
+    (i32.store (i32.const 8) (i32.const 0))
+    (f32.store (i32.const 5) (f32.const -0.0))
+    (i32.load (i32.const 8))
+  )
+
+  (func (export "test_redundant_load") (result i32)
+    (local $t i32)
+    (local $s i32)
+    (local.set $t (i32.load (i32.const 8)))
+    (i32.store (i32.const 5) (i32.const 0x80000000))
+    (local.set $s (i32.load (i32.const 8)))
+    (i32.add (local.get $t) (local.get $s))
+  )
+
+  (func (export "test_dead_store") (result f32)
+    (local $t f32)
+    (i32.store (i32.const 8) (i32.const 0x23232323))
+    (local.set $t (f32.load (i32.const 11)))
+    (i32.store (i32.const 8) (i32.const 0))
+    (local.get $t)
+  )
+
+  ;; A function named "malloc" which implementations nonetheless shouldn't
+  ;; assume behaves like C malloc.
+  (func $malloc (export "malloc")
+     (param $size i32)
+     (result i32)
+     (i32.const 16)
+  )
+
+  ;; Call malloc twice, but unlike C malloc, we don't get non-aliasing pointers.
+  (func (export "malloc_aliasing")
+     (result i32)
+     (local $x i32)
+     (local $y i32)
+     (local.set $x (call $malloc (i32.const 4)))
+     (local.set $y (call $malloc (i32.const 4)))
+     (i32.store (local.get $x) (i32.const 42))
+     (i32.store (local.get $y) (i32.const 43))
+     (i32.load (local.get $x))
+  )
+)
+
+(assert_return (invoke "test_store_to_load") (i32.const 0x00000080))
+(invoke "zero_everything")
+(assert_return (invoke "test_redundant_load") (i32.const 0x00000080))
+(invoke "zero_everything")
+(assert_return (invoke "test_dead_store") (f32.const 0x1.18p-144))
+(invoke "zero_everything")
+(assert_return (invoke "malloc_aliasing") (i32.const 43))
diff --git a/binaryen/test/spec/memory_redundancy64.wast b/binaryen/test/spec/memory_redundancy64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/memory_redundancy64.wast
@@ -0,0 +1,65 @@
+;; Test that optimizers don't do redundant-load, store-to-load, or dead-store
+;; optimizations when there are interfering stores, even of different types
+;; and to non-identical addresses.
+
+(module
+  (memory i64 1 1)
+
+  (func (export "zero_everything")
+    (i32.store (i64.const 0) (i32.const 0))
+    (i32.store (i64.const 4) (i32.const 0))
+    (i32.store (i64.const 8) (i32.const 0))
+    (i32.store (i64.const 12) (i32.const 0))
+  )
+
+  (func (export "test_store_to_load") (result i32)
+    (i32.store (i64.const 8) (i32.const 0))
+    (f32.store (i64.const 5) (f32.const -0.0))
+    (i32.load (i64.const 8))
+  )
+
+  (func (export "test_redundant_load") (result i32)
+    (local $t i32)
+    (local $s i32)
+    (local.set $t (i32.load (i64.const 8)))
+    (i32.store (i64.const 5) (i32.const 0x80000000))
+    (local.set $s (i32.load (i64.const 8)))
+    (i32.add (local.get $t) (local.get $s))
+  )
+
+  (func (export "test_dead_store") (result f32)
+    (local $t f32)
+    (i32.store (i64.const 8) (i32.const 0x23232323))
+    (local.set $t (f32.load (i64.const 11)))
+    (i32.store (i64.const 8) (i32.const 0))
+    (local.get $t)
+  )
+
+  ;; A function named "malloc" which implementations nonetheless shouldn't
+  ;; assume behaves like C malloc.
+  (func $malloc (export "malloc")
+     (param $size i64)
+     (result i64)
+     (i64.const 16)
+  )
+
+  ;; Call malloc twice, but unlike C malloc, we don't get non-aliasing pointers.
+  (func (export "malloc_aliasing")
+     (result i32)
+     (local $x i64)
+     (local $y i64)
+     (local.set $x (call $malloc (i64.const 4)))
+     (local.set $y (call $malloc (i64.const 4)))
+     (i32.store (local.get $x) (i32.const 42))
+     (i32.store (local.get $y) (i32.const 43))
+     (i32.load (local.get $x))
+  )
+)
+
+(assert_return (invoke "test_store_to_load") (i32.const 0x00000080))
+(invoke "zero_everything")
+(assert_return (invoke "test_redundant_load") (i32.const 0x00000080))
+(invoke "zero_everything")
+(assert_return (invoke "test_dead_store") (f32.const 0x1.18p-144))
+(invoke "zero_everything")
+(assert_return (invoke "malloc_aliasing") (i32.const 43))
diff --git a/binaryen/test/spec/memory_size.wast b/binaryen/test/spec/memory_size.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/memory_size.wast
@@ -0,0 +1,85 @@
+(module
+  (memory 0)
+  (func (export "size") (result i32) (memory.size))
+  (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz))))
+)
+
+(assert_return (invoke "size") (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)))
+(assert_return (invoke "size") (i32.const 1))
+(assert_return (invoke "grow" (i32.const 4)))
+(assert_return (invoke "size") (i32.const 5))
+(assert_return (invoke "grow" (i32.const 0)))
+(assert_return (invoke "size") (i32.const 5))
+
+(module
+  (memory 1)
+  (func (export "size") (result i32) (memory.size))
+  (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz))))
+)
+
+(assert_return (invoke "size") (i32.const 1))
+(assert_return (invoke "grow" (i32.const 1)))
+(assert_return (invoke "size") (i32.const 2))
+(assert_return (invoke "grow" (i32.const 4)))
+(assert_return (invoke "size") (i32.const 6))
+(assert_return (invoke "grow" (i32.const 0)))
+(assert_return (invoke "size") (i32.const 6))
+
+(module
+  (memory 0 2)
+  (func (export "size") (result i32) (memory.size))
+  (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz))))
+)
+
+(assert_return (invoke "size") (i32.const 0))
+(assert_return (invoke "grow" (i32.const 3)))
+(assert_return (invoke "size") (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)))
+(assert_return (invoke "size") (i32.const 1))
+(assert_return (invoke "grow" (i32.const 0)))
+(assert_return (invoke "size") (i32.const 1))
+(assert_return (invoke "grow" (i32.const 4)))
+(assert_return (invoke "size") (i32.const 1))
+(assert_return (invoke "grow" (i32.const 1)))
+(assert_return (invoke "size") (i32.const 2))
+
+(module
+  (memory 3 8)
+  (func (export "size") (result i32) (memory.size))
+  (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz))))
+)
+
+(assert_return (invoke "size") (i32.const 3))
+(assert_return (invoke "grow" (i32.const 1)))
+(assert_return (invoke "size") (i32.const 4))
+(assert_return (invoke "grow" (i32.const 3)))
+(assert_return (invoke "size") (i32.const 7))
+(assert_return (invoke "grow" (i32.const 0)))
+(assert_return (invoke "size") (i32.const 7))
+(assert_return (invoke "grow" (i32.const 2)))
+(assert_return (invoke "size") (i32.const 7))
+(assert_return (invoke "grow" (i32.const 1)))
+(assert_return (invoke "size") (i32.const 8))
+
+
+;; Type errors
+
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-result-i32-vs-empty
+      (memory.size)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-result-i32-vs-f32 (result f32)
+      (memory.size)
+    )
+  )
+  "type mismatch"
+)
diff --git a/binaryen/test/spec/memory_trap.wast b/binaryen/test/spec/memory_trap.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/memory_trap.wast
@@ -0,0 +1,270 @@
+(module
+    (memory 1)
+
+    (func $addr_limit (result i32)
+      (i32.mul (memory.size) (i32.const 0x10000))
+    )
+
+    (func (export "store") (param $i i32) (param $v i32)
+      (i32.store (i32.add (call $addr_limit) (local.get $i)) (local.get $v))
+    )
+
+    (func (export "load") (param $i i32) (result i32)
+      (i32.load (i32.add (call $addr_limit) (local.get $i)))
+    )
+
+    (func (export "memory.grow") (param i32) (result i32)
+      (memory.grow (local.get 0))
+    )
+)
+
+(assert_return (invoke "store" (i32.const -4) (i32.const 42)))
+(assert_return (invoke "load" (i32.const -4)) (i32.const 42))
+(assert_trap (invoke "store" (i32.const -3) (i32.const 13)) "out of bounds memory access")
+(assert_trap (invoke "load" (i32.const -3)) "out of bounds memory access")
+(assert_trap (invoke "store" (i32.const -2) (i32.const 13)) "out of bounds memory access")
+(assert_trap (invoke "load" (i32.const -2)) "out of bounds memory access")
+(assert_trap (invoke "store" (i32.const -1) (i32.const 13)) "out of bounds memory access")
+(assert_trap (invoke "load" (i32.const -1)) "out of bounds memory access")
+(assert_trap (invoke "store" (i32.const 0) (i32.const 13)) "out of bounds memory access")
+(assert_trap (invoke "load" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "store" (i32.const 0x80000000) (i32.const 13)) "out of bounds memory access")
+(assert_trap (invoke "load" (i32.const 0x80000000)) "out of bounds memory access")
+(assert_return (invoke "memory.grow" (i32.const 0x10001)) (i32.const -1))
+
+(module
+  (memory 1)
+  (data (i32.const 0) "abcdefgh")
+  (data (i32.const 0xfff8) "abcdefgh")
+
+  (func (export "i32.load") (param $a i32) (result i32)
+    (i32.load (local.get $a))
+  )
+  (func (export "i64.load") (param $a i32) (result i64)
+    (i64.load (local.get $a))
+  )
+  (func (export "f32.load") (param $a i32) (result f32)
+    (f32.load (local.get $a))
+  )
+  (func (export "f64.load") (param $a i32) (result f64)
+    (f64.load (local.get $a))
+  )
+  (func (export "i32.load8_s") (param $a i32) (result i32)
+    (i32.load8_s (local.get $a))
+  )
+  (func (export "i32.load8_u") (param $a i32) (result i32)
+    (i32.load8_u (local.get $a))
+  )
+  (func (export "i32.load16_s") (param $a i32) (result i32)
+    (i32.load16_s (local.get $a))
+  )
+  (func (export "i32.load16_u") (param $a i32) (result i32)
+    (i32.load16_u (local.get $a))
+  )
+  (func (export "i64.load8_s") (param $a i32) (result i64)
+    (i64.load8_s (local.get $a))
+  )
+  (func (export "i64.load8_u") (param $a i32) (result i64)
+    (i64.load8_u (local.get $a))
+  )
+  (func (export "i64.load16_s") (param $a i32) (result i64)
+    (i64.load16_s (local.get $a))
+  )
+  (func (export "i64.load16_u") (param $a i32) (result i64)
+    (i64.load16_u (local.get $a))
+  )
+  (func (export "i64.load32_s") (param $a i32) (result i64)
+    (i64.load32_s (local.get $a))
+  )
+  (func (export "i64.load32_u") (param $a i32) (result i64)
+    (i64.load32_u (local.get $a))
+  )
+  (func (export "i32.store") (param $a i32) (param $v i32)
+    (i32.store (local.get $a) (local.get $v))
+  )
+  (func (export "i64.store") (param $a i32) (param $v i64)
+    (i64.store (local.get $a) (local.get $v))
+  )
+  (func (export "f32.store") (param $a i32) (param $v f32)
+    (f32.store (local.get $a) (local.get $v))
+  )
+  (func (export "f64.store") (param $a i32) (param $v f64)
+    (f64.store (local.get $a) (local.get $v))
+  )
+  (func (export "i32.store8") (param $a i32) (param $v i32)
+    (i32.store8 (local.get $a) (local.get $v))
+  )
+  (func (export "i32.store16") (param $a i32) (param $v i32)
+    (i32.store16 (local.get $a) (local.get $v))
+  )
+  (func (export "i64.store8") (param $a i32) (param $v i64)
+    (i64.store8 (local.get $a) (local.get $v))
+  )
+  (func (export "i64.store16") (param $a i32) (param $v i64)
+    (i64.store16 (local.get $a) (local.get $v))
+  )
+  (func (export "i64.store32") (param $a i32) (param $v i64)
+    (i64.store32 (local.get $a) (local.get $v))
+  )
+)
+
+(assert_trap (invoke "i32.store" (i32.const 0x10000) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store" (i32.const 0xffff) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store" (i32.const 0xfffe) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store" (i32.const 0xfffd) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store" (i32.const -1) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store" (i32.const -2) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store" (i32.const -3) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store" (i32.const -4) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const 0x10000) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const 0xffff) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const 0xfffe) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const 0xfffd) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const 0xfffc) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const 0xfffb) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const 0xfffa) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const 0xfff9) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const -1) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const -2) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const -3) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const -4) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const -5) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const -6) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const -7) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i32.const -8) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i32.const 0x10000) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i32.const 0xffff) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i32.const 0xfffe) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i32.const 0xfffd) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i32.const -1) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i32.const -2) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i32.const -3) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i32.const -4) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const 0x10000) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const 0xffff) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const 0xfffe) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const 0xfffd) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const 0xfffc) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const 0xfffb) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const 0xfffa) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const 0xfff9) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const -1) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const -2) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const -3) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const -4) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const -5) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const -6) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const -7) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i32.const -8) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store8" (i32.const 0x10000) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store8" (i32.const -1) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store16" (i32.const 0x10000) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store16" (i32.const 0xffff) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store16" (i32.const -1) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store16" (i32.const -2) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store8" (i32.const 0x10000) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store8" (i32.const -1) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store16" (i32.const 0x10000) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store16" (i32.const 0xffff) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store16" (i32.const -1) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store16" (i32.const -2) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i32.const 0x10000) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i32.const 0xffff) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i32.const 0xfffe) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i32.const 0xfffd) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i32.const -1) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i32.const -2) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i32.const -3) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i32.const -4) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i32.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i32.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i32.const 0xfffe)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i32.const 0xfffd)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i32.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i32.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i32.const -3)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i32.const -4)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const 0xfffe)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const 0xfffd)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const 0xfffc)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const 0xfffb)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const 0xfffa)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const 0xfff9)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const -3)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const -4)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const -5)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const -6)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const -7)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i32.const -8)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i32.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i32.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i32.const 0xfffe)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i32.const 0xfffd)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i32.const -1)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i32.const -2)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i32.const -3)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i32.const -4)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const 0xfffe)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const 0xfffd)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const 0xfffc)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const 0xfffb)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const 0xfffa)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const 0xfff9)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const -1)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const -2)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const -3)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const -4)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const -5)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const -6)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const -7)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i32.const -8)) "out of bounds memory access")
+(assert_trap (invoke "i32.load8_s" (i32.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i32.load8_s" (i32.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i32.load8_u" (i32.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i32.load8_u" (i32.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_s" (i32.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_s" (i32.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_s" (i32.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_s" (i32.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_u" (i32.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_u" (i32.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_u" (i32.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_u" (i32.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i64.load8_s" (i32.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i64.load8_s" (i32.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i64.load8_u" (i32.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i64.load8_u" (i32.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_s" (i32.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_s" (i32.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_s" (i32.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_s" (i32.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_u" (i32.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_u" (i32.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_u" (i32.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_u" (i32.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i32.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i32.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i32.const 0xfffe)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i32.const 0xfffd)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i32.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i32.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i32.const -3)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i32.const -4)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i32.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i32.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i32.const 0xfffe)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i32.const 0xfffd)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i32.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i32.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i32.const -3)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i32.const -4)) "out of bounds memory access")
+
+;; No memory was changed
+(assert_return (invoke "i64.load" (i32.const 0xfff8)) (i64.const 0x6867666564636261))
+(assert_return (invoke "i64.load" (i32.const 0)) (i64.const 0x6867666564636261))
diff --git a/binaryen/test/spec/memory_trap64.wast b/binaryen/test/spec/memory_trap64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/memory_trap64.wast
@@ -0,0 +1,269 @@
+(module
+    (memory i64 1)
+
+    (func $addr_limit (result i64)
+      (i64.mul (memory.size) (i64.const 0x10000))
+    )
+
+    (func (export "store") (param $i i64) (param $v i32)
+      (i32.store (i64.add (call $addr_limit) (local.get $i)) (local.get $v))
+    )
+
+    (func (export "load") (param $i i64) (result i32)
+      (i32.load (i64.add (call $addr_limit) (local.get $i)))
+    )
+
+    (func (export "memory.grow") (param i64) (result i64)
+      (memory.grow (local.get 0))
+    )
+)
+
+(assert_return (invoke "store" (i64.const -4) (i32.const 42)))
+(assert_return (invoke "load" (i64.const -4)) (i32.const 42))
+(assert_trap (invoke "store" (i64.const -3) (i32.const 13)) "out of bounds memory access")
+(assert_trap (invoke "load" (i64.const -3)) "out of bounds memory access")
+(assert_trap (invoke "store" (i64.const -2) (i32.const 13)) "out of bounds memory access")
+(assert_trap (invoke "load" (i64.const -2)) "out of bounds memory access")
+(assert_trap (invoke "store" (i64.const -1) (i32.const 13)) "out of bounds memory access")
+(assert_trap (invoke "load" (i64.const -1)) "out of bounds memory access")
+(assert_trap (invoke "store" (i64.const 0) (i32.const 13)) "out of bounds memory access")
+(assert_trap (invoke "load" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "store" (i64.const 0x80000000) (i32.const 13)) "out of bounds memory access")
+(assert_trap (invoke "load" (i64.const 0x80000000)) "out of bounds memory access")
+
+(module
+  (memory i64 1)
+  (data (i32.const 0) "abcdefgh")
+  (data (i32.const 0xfff8) "abcdefgh")
+
+  (func (export "i32.load") (param $a i64) (result i32)
+    (i32.load (local.get $a))
+  )
+  (func (export "i64.load") (param $a i64) (result i64)
+    (i64.load (local.get $a))
+  )
+  (func (export "f32.load") (param $a i64) (result f32)
+    (f32.load (local.get $a))
+  )
+  (func (export "f64.load") (param $a i64) (result f64)
+    (f64.load (local.get $a))
+  )
+  (func (export "i32.load8_s") (param $a i64) (result i32)
+    (i32.load8_s (local.get $a))
+  )
+  (func (export "i32.load8_u") (param $a i64) (result i32)
+    (i32.load8_u (local.get $a))
+  )
+  (func (export "i32.load16_s") (param $a i64) (result i32)
+    (i32.load16_s (local.get $a))
+  )
+  (func (export "i32.load16_u") (param $a i64) (result i32)
+    (i32.load16_u (local.get $a))
+  )
+  (func (export "i64.load8_s") (param $a i64) (result i64)
+    (i64.load8_s (local.get $a))
+  )
+  (func (export "i64.load8_u") (param $a i64) (result i64)
+    (i64.load8_u (local.get $a))
+  )
+  (func (export "i64.load16_s") (param $a i64) (result i64)
+    (i64.load16_s (local.get $a))
+  )
+  (func (export "i64.load16_u") (param $a i64) (result i64)
+    (i64.load16_u (local.get $a))
+  )
+  (func (export "i64.load32_s") (param $a i64) (result i64)
+    (i64.load32_s (local.get $a))
+  )
+  (func (export "i64.load32_u") (param $a i64) (result i64)
+    (i64.load32_u (local.get $a))
+  )
+  (func (export "i32.store") (param $a i64) (param $v i32)
+    (i32.store (local.get $a) (local.get $v))
+  )
+  (func (export "i64.store") (param $a i64) (param $v i64)
+    (i64.store (local.get $a) (local.get $v))
+  )
+  (func (export "f32.store") (param $a i64) (param $v f32)
+    (f32.store (local.get $a) (local.get $v))
+  )
+  (func (export "f64.store") (param $a i64) (param $v f64)
+    (f64.store (local.get $a) (local.get $v))
+  )
+  (func (export "i32.store8") (param $a i64) (param $v i32)
+    (i32.store8 (local.get $a) (local.get $v))
+  )
+  (func (export "i32.store16") (param $a i64) (param $v i32)
+    (i32.store16 (local.get $a) (local.get $v))
+  )
+  (func (export "i64.store8") (param $a i64) (param $v i64)
+    (i64.store8 (local.get $a) (local.get $v))
+  )
+  (func (export "i64.store16") (param $a i64) (param $v i64)
+    (i64.store16 (local.get $a) (local.get $v))
+  )
+  (func (export "i64.store32") (param $a i64) (param $v i64)
+    (i64.store32 (local.get $a) (local.get $v))
+  )
+)
+
+(assert_trap (invoke "i32.store" (i64.const 0x10000) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store" (i64.const 0xffff) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store" (i64.const 0xfffe) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store" (i64.const 0xfffd) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store" (i64.const -1) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store" (i64.const -2) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store" (i64.const -3) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store" (i64.const -4) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const 0x10000) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const 0xffff) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const 0xfffe) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const 0xfffd) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const 0xfffc) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const 0xfffb) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const 0xfffa) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const 0xfff9) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const -1) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const -2) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const -3) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const -4) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const -5) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const -6) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const -7) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store" (i64.const -8) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i64.const 0x10000) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i64.const 0xffff) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i64.const 0xfffe) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i64.const 0xfffd) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i64.const -1) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i64.const -2) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i64.const -3) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f32.store" (i64.const -4) (f32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const 0x10000) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const 0xffff) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const 0xfffe) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const 0xfffd) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const 0xfffc) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const 0xfffb) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const 0xfffa) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const 0xfff9) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const -1) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const -2) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const -3) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const -4) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const -5) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const -6) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const -7) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "f64.store" (i64.const -8) (f64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store8" (i64.const 0x10000) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store8" (i64.const -1) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store16" (i64.const 0x10000) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store16" (i64.const 0xffff) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store16" (i64.const -1) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.store16" (i64.const -2) (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store8" (i64.const 0x10000) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store8" (i64.const -1) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store16" (i64.const 0x10000) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store16" (i64.const 0xffff) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store16" (i64.const -1) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store16" (i64.const -2) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i64.const 0x10000) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i64.const 0xffff) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i64.const 0xfffe) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i64.const 0xfffd) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i64.const -1) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i64.const -2) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i64.const -3) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i64.store32" (i64.const -4) (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i64.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i64.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i64.const 0xfffe)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i64.const 0xfffd)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i64.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i64.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i64.const -3)) "out of bounds memory access")
+(assert_trap (invoke "i32.load" (i64.const -4)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const 0xfffe)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const 0xfffd)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const 0xfffc)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const 0xfffb)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const 0xfffa)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const 0xfff9)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const -3)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const -4)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const -5)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const -6)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const -7)) "out of bounds memory access")
+(assert_trap (invoke "i64.load" (i64.const -8)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i64.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i64.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i64.const 0xfffe)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i64.const 0xfffd)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i64.const -1)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i64.const -2)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i64.const -3)) "out of bounds memory access")
+(assert_trap (invoke "f32.load" (i64.const -4)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const 0xfffe)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const 0xfffd)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const 0xfffc)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const 0xfffb)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const 0xfffa)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const 0xfff9)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const -1)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const -2)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const -3)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const -4)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const -5)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const -6)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const -7)) "out of bounds memory access")
+(assert_trap (invoke "f64.load" (i64.const -8)) "out of bounds memory access")
+(assert_trap (invoke "i32.load8_s" (i64.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i32.load8_s" (i64.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i32.load8_u" (i64.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i32.load8_u" (i64.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_s" (i64.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_s" (i64.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_s" (i64.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_s" (i64.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_u" (i64.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_u" (i64.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_u" (i64.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i32.load16_u" (i64.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i64.load8_s" (i64.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i64.load8_s" (i64.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i64.load8_u" (i64.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i64.load8_u" (i64.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_s" (i64.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_s" (i64.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_s" (i64.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_s" (i64.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_u" (i64.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_u" (i64.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_u" (i64.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i64.load16_u" (i64.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i64.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i64.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i64.const 0xfffe)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i64.const 0xfffd)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i64.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i64.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i64.const -3)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_s" (i64.const -4)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i64.const 0x10000)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i64.const 0xffff)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i64.const 0xfffe)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i64.const 0xfffd)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i64.const -1)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i64.const -2)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i64.const -3)) "out of bounds memory access")
+(assert_trap (invoke "i64.load32_u" (i64.const -4)) "out of bounds memory access")
+
+;; No memory was changed
+(assert_return (invoke "i64.load" (i64.const 0xfff8)) (i64.const 0x6867666564636261))
+(assert_return (invoke "i64.load" (i64.const 0)) (i64.const 0x6867666564636261))
diff --git a/binaryen/test/spec/multivalue.wast b/binaryen/test/spec/multivalue.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/multivalue.wast
@@ -0,0 +1,35 @@
+(module
+ (global $global_pair (mut (i32 i64)) (tuple.make (i32.const 0) (i64.const 0)))
+ (func $pair (export "pair") (result i32 i64)
+  (tuple.make
+   (i32.const 42)
+   (i64.const 7)
+  )
+ )
+ (func (export "tuple-local") (result i32 i64)
+  (local $x (i32 i64))
+  (local.get $x)
+ )
+ (func (export "tuple-global-get") (result i32 i64)
+  (global.get $global_pair)
+ )
+ (func (export "tuple-global-set")
+  (global.set $global_pair
+   (tuple.make
+    (i32.const 42)
+    (i64.const 7)
+   )
+  )
+ )
+ (func (export "tail-call") (result i32 i64)
+  (return_call $pair)
+  (unreachable)
+ )
+)
+
+(assert_return (invoke "pair") (tuple.make (i32.const 42) (i64.const 7)))
+(assert_return (invoke "tuple-local") (tuple.make (i32.const 0) (i64.const 0)))
+(assert_return (invoke "tuple-global-get") (tuple.make (i32.const 0) (i64.const 0)))
+(assert_return (invoke "tuple-global-set"))
+(assert_return (invoke "tuple-global-get") (tuple.make (i32.const 42) (i64.const 7)))
+(assert_return (invoke "tail-call") (tuple.make (i32.const 42) (i64.const 7)))
diff --git a/binaryen/test/spec/names.wast b/binaryen/test/spec/names.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/names.wast
@@ -0,0 +1,1107 @@
+;; Test files can define multiple modules. Test that implementations treat
+;; each module independently from the other.
+
+(module
+  (func (export "foo") (result i32) (i32.const 0))
+)
+
+(assert_return (invoke "foo") (i32.const 0))
+
+;; Another module, same function name, different contents.
+
+(module
+  (func (export "foo") (result i32) (i32.const 1))
+)
+
+(assert_return (invoke "foo") (i32.const 1))
+
+
+(module
+  ;; Test that we can use the empty string as a symbol.
+  (func (export "") (result i32) (i32.const 0))
+
+  ;; Test that we can use names beginning with a digit.
+  (func (export "0") (result i32) (i32.const 1))
+
+  ;; Test that we can use names beginning with a dash.
+  (func (export "-0") (result i32) (i32.const 2))
+
+  ;; Test that we can use names beginning with an underscore.
+  (func (export "_") (result i32) (i32.const 3))
+
+  ;; Test that we can use names beginning with a dollar sign.
+  (func (export "$") (result i32) (i32.const 4))
+
+  ;; Test that we can use names beginning with an at sign.
+  (func (export "@") (result i32) (i32.const 5))
+
+  ;; Test that we can use non-alphanumeric names.
+  (func (export "~!@#$%^&*()_+`-={}|[]\\:\";'<>?,./ ") (result i32) (i32.const 6))
+
+  ;; Test that we can use names that have special meaning in JS.
+  (func (export "NaN") (result i32) (i32.const 7))
+  (func (export "Infinity") (result i32) (i32.const 8))
+  (func (export "if") (result i32) (i32.const 9))
+
+  ;; Test that we can use common libc names without conflict.
+  (func (export "malloc") (result i32) (i32.const 10))
+
+  ;; Test that we can use some libc hidden names without conflict.
+  (func (export "_malloc") (result i32) (i32.const 11))
+  (func (export "__malloc") (result i32) (i32.const 12))
+
+  ;; Test that names are case-sensitive.
+  (func (export "a") (result i32) (i32.const 13))
+  (func (export "A") (result i32) (i32.const 14))
+
+  ;; Test that UTF-8 BOM code points can appear in identifiers.
+  (func (export "﻿") (result i32) (i32.const 15))
+
+  ;; Test that Unicode normalization is not applied. These function names
+  ;; contain different codepoints which normalize to the same thing under
+  ;; NFC or NFD.
+  (func (export "Å") (result i32) (i32.const 16))
+  (func (export "Å") (result i32) (i32.const 17))
+  (func (export "Å") (result i32) (i32.const 18))
+
+  ;; Test that Unicode compatibility normalization is not applied. These
+  ;; function names contain different codepoints which normalize to the
+  ;; same thing under NFKC or NFKD.
+  (func (export "ﬃ") (result i32) (i32.const 19))
+  (func (export "fﬁ") (result i32) (i32.const 20))
+  (func (export "ffi") (result i32) (i32.const 21))
+
+  ;; Test the C0 control codes.
+  (func (export "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f") (result i32) (i32.const 22))
+  (func (export "\10\11\12\13\14\15\16\17\18\19\1a\1b\1c\1d\1e\1f") (result i32) (i32.const 23))
+  ;; Test miscellaneous control codes.
+  (func (export " \7f") (result i32) (i32.const 24))
+  ;; Test the C1 control codes.
+  (func (export "\c2\80\c2\81\c2\82\c2\83\c2\84\c2\85\c2\86\c2\87\c2\88\c2\89\c2\8a\c2\8b\c2\8c\c2\8d\c2\8e\c2\8f") (result i32) (i32.const 25))
+  (func (export "\c2\90\c2\91\c2\92\c2\93\c2\94\c2\95\c2\96\c2\97\c2\98\c2\99\c2\9a\c2\9b\c2\9c\c2\9d\c2\9e\c2\9f") (result i32) (i32.const 26))
+  ;; Test the Unicode Specials.
+  (func (export "\ef\bf\b0\ef\bf\b1\ef\bf\b2\ef\bf\b3\ef\bf\b4\ef\bf\b5\ef\bf\b6\ef\bf\b7") (result i32) (i32.const 27))
+  (func (export "\ef\bf\b8\ef\bf\b9\ef\bf\ba\ef\bf\bb\ef\bf\bc\ef\bf\bd\ef\bf\be\ef\bf\bf") (result i32) (i32.const 28))
+
+  ;; Test that the control pictures are distinct from the control codes they
+  ;; depict. These correspond to the C0 and miscellaneous control code tests
+  ;; above.
+  (func (export "␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏") (result i32) (i32.const 29))
+  (func (export "␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟") (result i32) (i32.const 30))
+  (func (export "␠␡") (result i32) (i32.const 31))
+
+  ;; Test the Unicode Specials in non-escaped form (excluding U+FFFE and
+  ;; U+FFFF, so that generic tools don't detect this file as non-UTF-8).
+  (func (export "￰￱￲￳￴￵￶￷￸￹￺￻￼�") (result i32) (i32.const 32))
+
+  ;; Test a bare ZWJ code point.
+  (func (export "‍") (result i32) (i32.const 33))
+  ;; Test a bare ZWNJ code point.
+  (func (export "‌") (result i32) (i32.const 34))
+
+  ;; Test various bare joiner code points.
+  (func (export "͏") (result i32) (i32.const 35))
+  (func (export "⁠") (result i32) (i32.const 36))
+  (func (export "⵿") (result i32) (i32.const 37))
+  (func (export "𑁿") (result i32) (i32.const 38))
+  (func (export "᠎") (result i32) (i32.const 39))
+
+  ;; Test various interesting code points: reverse BOM, zero-width space,
+  ;; no-break space, soft hyphen, word joiner, ogham space mark,
+  ;; right-to-left override, left-to-right override.
+  (func (export "￯​ ­⁠ ‮‭") (result i32) (i32.const 40))
+
+  ;; Test more interesting code points: left-to-right mark, right-to-left mark,
+  ;; non-breaking hyphen, line separator, paragraph separator,
+  ;; left-to-right embedding, right-to-left embedding,
+  ;; pop directional formatting, narrow no-break space, left-to-right isolate,
+  ;; right-to-left isolate, first strong isolate, pop directional isolate.
+  (func (export "‎‏‑  ‪‫‬ ⁦⁧⁨⁩") (result i32) (i32.const 41))
+
+  ;; Test some deprecated code points: inhibit symmetric swapping,
+  ;; activate symmetric swapping, inhibit arabic form shaping,
+  ;; activate arabic form shaping, national digit shapes, nominal digit shapes.
+  (func (export "⁪⁫⁬⁭⁮⁯") (result i32) (i32.const 42))
+
+  ;; Test "invisible" operator code points.
+  (func (export "⁡⁢⁣⁤") (result i32) (i32.const 43))
+
+  ;; Test that code points outside the BMP are supported.
+  (func (export "𐀀󟿿􏿿") (result i32) (i32.const 44))
+
+  ;; Test that WebAssembly implementations cope in the presence of Zalgo.
+  (func (export "Z̴͇̫̥̪͓͈͔͎̗̞̺̯̱̞̙̱̜̖̠̏͆̆͛͌͘͞ḁ̶̰̳̭͙̲̱̹̝͎̼͗ͨ̎̄̆͗̿̀́͟͡l̶̷͉̩̹̫̝͖̙̲̼͇͚͍̮͎̥̞̈́͊͗ͦ̈́ͫ̇́̚ͅͅg̶͕͔͚̩̓̐̅ͮ̔̐̎̂̏̾͊̍͋͊ͧ́̆ͦ͞o̡͋̔͐ͪͩ͏̢̧̫̙̤̮͖͙͓̺̜̩̼̘̠́") (result i32) (i32.const 45))
+
+  ;; Test Hangul filler code points.
+  (func (export "ᅟᅠㅤﾠ") (result i32) (i32.const 46))
+
+  ;; Test variation selectors (which are also ID_Continue code points).
+  (func (export "︀") (result i32) (i32.const 47))
+  (func (export "︄") (result i32) (i32.const 48))
+  (func (export "󠄀") (result i32) (i32.const 49))
+  (func (export "󠇯") (result i32) (i32.const 50))
+
+  ;; Test an uncombined combining code point.
+  (func (export "̈") (result i32) (i32.const 51))
+
+  ;; Test that numerous different present and historical representations of the
+  ;; "newline" concept are distinct. Tests largely inspired by:
+  ;;   https://en.wikipedia.org/wiki/Newline#Representations
+  ;;   https://en.wikipedia.org/wiki/Newline#Unicode and
+  ;;   https://en.wikipedia.org/wiki/Newline#Reverse_and_partial_line_feeds
+  (func (export "\0a") (result i32) (i32.const 52))
+  (func (export "␤") (result i32) (i32.const 53))
+  (func (export " ") (result i32) (i32.const 54))
+  (func (export "\0d") (result i32) (i32.const 55))
+  (func (export "\0d\0a") (result i32) (i32.const 56))
+  (func (export "\0a\0d") (result i32) (i32.const 57))
+  (func (export "\1e") (result i32) (i32.const 58))
+  (func (export "\0b") (result i32) (i32.const 59))
+  (func (export "\0c") (result i32) (i32.const 60))
+  (func (export "\c2\85") (result i32) (i32.const 61))
+  (func (export " ") (result i32) (i32.const 62))
+  (func (export "…") (result i32) (i32.const 63))
+  (func (export "⏎") (result i32) (i32.const 64))
+  (func (export "\c2\8b") (result i32) (i32.const 65))
+  (func (export "\c2\8c") (result i32) (i32.const 66))
+  (func (export "\c2\8d") (result i32) (i32.const 67))
+  (func (export "↵") (result i32) (i32.const 68))
+  (func (export "↩") (result i32) (i32.const 69))
+  (func (export "⌤") (result i32) (i32.const 70))
+  (func (export "⤶") (result i32) (i32.const 71))
+  (func (export "↲") (result i32) (i32.const 72))
+  (func (export "⮨") (result i32) (i32.const 73))
+  (func (export "⮰") (result i32) (i32.const 74))
+
+  ;; Test that non-characters are not replaced by the replacement character.
+  (func (export "�") (result i32) (i32.const 75))
+  (func (export "\ef\b7\90") (result i32) (i32.const 76))
+  (func (export "\ef\b7\91") (result i32) (i32.const 77))
+  (func (export "\ef\b7\92") (result i32) (i32.const 78))
+  (func (export "\ef\b7\93") (result i32) (i32.const 79))
+  (func (export "\ef\b7\94") (result i32) (i32.const 80))
+  (func (export "\ef\b7\95") (result i32) (i32.const 81))
+  (func (export "\ef\b7\96") (result i32) (i32.const 82))
+  (func (export "\ef\b7\97") (result i32) (i32.const 83))
+  (func (export "\ef\b7\98") (result i32) (i32.const 84))
+  (func (export "\ef\b7\99") (result i32) (i32.const 85))
+  (func (export "\ef\b7\9a") (result i32) (i32.const 86))
+  (func (export "\ef\b7\9b") (result i32) (i32.const 87))
+  (func (export "\ef\b7\9c") (result i32) (i32.const 88))
+  (func (export "\ef\b7\9d") (result i32) (i32.const 89))
+  (func (export "\ef\b7\9e") (result i32) (i32.const 90))
+  (func (export "\ef\b7\9f") (result i32) (i32.const 91))
+  (func (export "\ef\b7\a0") (result i32) (i32.const 92))
+  (func (export "\ef\b7\a1") (result i32) (i32.const 93))
+  (func (export "\ef\b7\a2") (result i32) (i32.const 94))
+  (func (export "\ef\b7\a3") (result i32) (i32.const 95))
+  (func (export "\ef\b7\a4") (result i32) (i32.const 96))
+  (func (export "\ef\b7\a5") (result i32) (i32.const 97))
+  (func (export "\ef\b7\a6") (result i32) (i32.const 98))
+  (func (export "\ef\b7\a7") (result i32) (i32.const 99))
+  (func (export "\ef\b7\a8") (result i32) (i32.const 100))
+  (func (export "\ef\b7\a9") (result i32) (i32.const 101))
+  (func (export "\ef\b7\aa") (result i32) (i32.const 102))
+  (func (export "\ef\b7\ab") (result i32) (i32.const 103))
+  (func (export "\ef\b7\ac") (result i32) (i32.const 104))
+  (func (export "\ef\b7\ad") (result i32) (i32.const 105))
+  (func (export "\ef\b7\ae") (result i32) (i32.const 106))
+  (func (export "\ef\b7\af") (result i32) (i32.const 107))
+  (func (export "\ef\bf\be") (result i32) (i32.const 108))
+  (func (export "\ef\bf\bf") (result i32) (i32.const 109))
+  (func (export "\f0\9f\bf\be") (result i32) (i32.const 110))
+  (func (export "\f0\9f\bf\bf") (result i32) (i32.const 111))
+  (func (export "\f0\af\bf\be") (result i32) (i32.const 112))
+  (func (export "\f0\af\bf\bf") (result i32) (i32.const 113))
+  (func (export "\f0\bf\bf\be") (result i32) (i32.const 114))
+  (func (export "\f0\bf\bf\bf") (result i32) (i32.const 115))
+  (func (export "\f1\8f\bf\be") (result i32) (i32.const 116))
+  (func (export "\f1\8f\bf\bf") (result i32) (i32.const 117))
+  (func (export "\f1\9f\bf\be") (result i32) (i32.const 118))
+  (func (export "\f1\9f\bf\bf") (result i32) (i32.const 119))
+  (func (export "\f1\af\bf\be") (result i32) (i32.const 120))
+  (func (export "\f1\af\bf\bf") (result i32) (i32.const 121))
+  (func (export "\f1\bf\bf\be") (result i32) (i32.const 122))
+  (func (export "\f1\bf\bf\bf") (result i32) (i32.const 123))
+  (func (export "\f2\8f\bf\be") (result i32) (i32.const 124))
+  (func (export "\f2\8f\bf\bf") (result i32) (i32.const 125))
+  (func (export "\f2\9f\bf\be") (result i32) (i32.const 126))
+  (func (export "\f2\9f\bf\bf") (result i32) (i32.const 127))
+  (func (export "\f2\af\bf\be") (result i32) (i32.const 128))
+  (func (export "\f2\af\bf\bf") (result i32) (i32.const 129))
+  (func (export "\f2\bf\bf\be") (result i32) (i32.const 130))
+  (func (export "\f2\bf\bf\bf") (result i32) (i32.const 131))
+  (func (export "\f3\8f\bf\be") (result i32) (i32.const 132))
+  (func (export "\f3\8f\bf\bf") (result i32) (i32.const 133))
+  (func (export "\f3\9f\bf\be") (result i32) (i32.const 134))
+  (func (export "\f3\9f\bf\bf") (result i32) (i32.const 135))
+  (func (export "\f3\af\bf\be") (result i32) (i32.const 136))
+  (func (export "\f3\af\bf\bf") (result i32) (i32.const 137))
+  (func (export "\f3\bf\bf\be") (result i32) (i32.const 138))
+  (func (export "\f3\bf\bf\bf") (result i32) (i32.const 139))
+  (func (export "\f4\8f\bf\be") (result i32) (i32.const 140))
+  (func (export "\f4\8f\bf\bf") (result i32) (i32.const 141))
+
+  ;; Test an interrobang with combining diacritical marks above.
+  ;; https://xkcd.com/1209/
+  (func (export "̈‽̈̉") (result i32) (i32.const 142))
+
+  ;; Test that RLM/LRM don't change the logical byte order.
+  (func (export "abc") (result i32) (i32.const 143))
+  (func (export "‭abc") (result i32) (i32.const 144))
+  (func (export "‮cba") (result i32) (i32.const 145))
+  (func (export "‭abc‮") (result i32) (i32.const 146))
+  (func (export "‮cba‭") (result i32) (i32.const 147))
+
+  ;; Test that Unicode font variations are preserved.
+  (func (export "𝑨") (result i32) (i32.const 148))
+  (func (export "𝐴") (result i32) (i32.const 149))
+  (func (export "𝘈") (result i32) (i32.const 150))
+  (func (export "𝘼") (result i32) (i32.const 151))
+  (func (export "𝐀") (result i32) (i32.const 152))
+  (func (export "𝓐") (result i32) (i32.const 153))
+  (func (export "𝕬") (result i32) (i32.const 154))
+  (func (export "𝗔") (result i32) (i32.const 155))
+  (func (export "𝒜") (result i32) (i32.const 156))
+  (func (export "𝔄") (result i32) (i32.const 157))
+  (func (export "𝔸") (result i32) (i32.const 158))
+  (func (export "𝖠") (result i32) (i32.const 159))
+  (func (export "𝙰") (result i32) (i32.const 160))
+  (func (export "ᴀ") (result i32) (i32.const 161))
+
+  ;; Test that various additional letter variations are preserved.
+  ;; (U+0040, U+0061, U+0041, U+00C5, U+0041 U+030A, U+212B, and the font
+  ;; variations are covered above.)
+  (func (export "ᴬ") (result i32) (i32.const 162))
+  (func (export "Ⓐ") (result i32) (i32.const 163))
+  (func (export "Ａ") (result i32) (i32.const 164))
+  (func (export "🄐") (result i32) (i32.const 165))
+  (func (export "🄰") (result i32) (i32.const 166))
+  (func (export "󠁁") (result i32) (i32.const 167))
+  (func (export "U+0041") (result i32) (i32.const 168))
+  (func (export "A​") (result i32) (i32.const 169))
+  (func (export "А") (result i32) (i32.const 170))
+  (func (export "Ꙗ") (result i32) (i32.const 171))
+  (func (export "ⷼ") (result i32) (i32.const 172))
+  (func (export "ⷶ") (result i32) (i32.const 173))
+  (func (export "Ɐ") (result i32) (i32.const 174))
+  (func (export "🅐") (result i32) (i32.const 175))
+  (func (export "🅰") (result i32) (i32.const 176))
+  (func (export "Ⱝ") (result i32) (i32.const 177))
+  (func (export "𐐂") (result i32) (i32.const 178))
+  (func (export "𐐈") (result i32) (i32.const 179))
+  (func (export "𐒰") (result i32) (i32.const 180))
+  (func (export "À") (result i32) (i32.const 181))
+  (func (export "Á") (result i32) (i32.const 182))
+  (func (export "Â") (result i32) (i32.const 183))
+  (func (export "Ã") (result i32) (i32.const 184))
+  (func (export "Ä") (result i32) (i32.const 185))
+  (func (export "Ā") (result i32) (i32.const 186))
+  (func (export "Ă") (result i32) (i32.const 187))
+  (func (export "Ą") (result i32) (i32.const 188))
+  (func (export "Ǎ") (result i32) (i32.const 189))
+  (func (export "Ǟ") (result i32) (i32.const 190))
+  (func (export "Ǡ") (result i32) (i32.const 191))
+  (func (export "Ǻ") (result i32) (i32.const 192))
+  (func (export "Ȁ") (result i32) (i32.const 193))
+  (func (export "Ȃ") (result i32) (i32.const 194))
+  (func (export "Ȧ") (result i32) (i32.const 195))
+  (func (export "Ⱥ") (result i32) (i32.const 196))
+  (func (export "Ӑ") (result i32) (i32.const 197))
+  (func (export "Ӓ") (result i32) (i32.const 198))
+  (func (export "ߊ") (result i32) (i32.const 199))
+  (func (export "ࠡ") (result i32) (i32.const 200))
+  (func (export "ࠢ") (result i32) (i32.const 201))
+  (func (export "ࠣ") (result i32) (i32.const 202))
+  (func (export "ࠤ") (result i32) (i32.const 203))
+  (func (export "ࠥ") (result i32) (i32.const 204))
+  (func (export "ऄ") (result i32) (i32.const 205))
+  (func (export "अ") (result i32) (i32.const 206))
+  (func (export "ॲ") (result i32) (i32.const 207))
+  (func (export "অ") (result i32) (i32.const 208))
+  (func (export "ਅ") (result i32) (i32.const 209))
+  (func (export "અ") (result i32) (i32.const 210))
+  (func (export "ଅ") (result i32) (i32.const 211))
+  (func (export "அ") (result i32) (i32.const 212))
+  (func (export "అ") (result i32) (i32.const 213))
+  (func (export "ಅ") (result i32) (i32.const 214))
+  (func (export "അ") (result i32) (i32.const 215))
+  (func (export "ะ") (result i32) (i32.const 216))
+  (func (export "ະ") (result i32) (i32.const 217))
+  (func (export "༁") (result i32) (i32.const 218))
+  (func (export "ཨ") (result i32) (i32.const 219))
+  (func (export "ྸ") (result i32) (i32.const 220))
+  (func (export "အ") (result i32) (i32.const 221))
+  (func (export "ဢ") (result i32) (i32.const 222))
+  (func (export "ႜ") (result i32) (i32.const 223))
+  (func (export "ᅡ") (result i32) (i32.const 224))
+  (func (export "አ") (result i32) (i32.const 225))
+  (func (export "ዐ") (result i32) (i32.const 226))
+  (func (export "Ꭰ") (result i32) (i32.const 227))
+  (func (export "ᐊ") (result i32) (i32.const 228))
+  (func (export "ᖳ") (result i32) (i32.const 229))
+  (func (export "ᚨ") (result i32) (i32.const 230))
+  (func (export "ᚪ") (result i32) (i32.const 231))
+  (func (export "ᛆ") (result i32) (i32.const 232))
+  (func (export "ᜀ") (result i32) (i32.const 233))
+  (func (export "ᜠ") (result i32) (i32.const 234))
+  (func (export "ᝀ") (result i32) (i32.const 235))
+  (func (export "ᝠ") (result i32) (i32.const 236))
+  (func (export "ᠠ") (result i32) (i32.const 237))
+  (func (export "ᢇ") (result i32) (i32.const 238))
+  (func (export "ᤠ") (result i32) (i32.const 239))
+  (func (export "ᥣ") (result i32) (i32.const 240))
+  (func (export "ᨕ") (result i32) (i32.const 241))
+  (func (export "ᩋ") (result i32) (i32.const 242))
+  (func (export "ᩡ") (result i32) (i32.const 243))
+  (func (export "ᮃ") (result i32) (i32.const 244))
+  (func (export "ᯀ") (result i32) (i32.const 245))
+  (func (export "ᯁ") (result i32) (i32.const 246))
+  (func (export "ᰣ") (result i32) (i32.const 247))
+  (func (export "Ḁ") (result i32) (i32.const 248))
+  (func (export "Ạ") (result i32) (i32.const 249))
+  (func (export "Ả") (result i32) (i32.const 250))
+  (func (export "Ấ") (result i32) (i32.const 251))
+  (func (export "Ầ") (result i32) (i32.const 252))
+  (func (export "Ẩ") (result i32) (i32.const 253))
+  (func (export "Ẫ") (result i32) (i32.const 254))
+  (func (export "Ậ") (result i32) (i32.const 255))
+  (func (export "Ắ") (result i32) (i32.const 256))
+  (func (export "Ằ") (result i32) (i32.const 257))
+  (func (export "Ẳ") (result i32) (i32.const 258))
+  (func (export "Ẵ") (result i32) (i32.const 259))
+  (func (export "Ặ") (result i32) (i32.const 260))
+  (func (export "あ") (result i32) (i32.const 261))
+  (func (export "ア") (result i32) (i32.const 262))
+  (func (export "ㄚ") (result i32) (i32.const 263))
+  (func (export "ㅏ") (result i32) (i32.const 264))
+  (func (export "㈎") (result i32) (i32.const 265))
+  (func (export "㈏") (result i32) (i32.const 266))
+  (func (export "㈐") (result i32) (i32.const 267))
+  (func (export "㈑") (result i32) (i32.const 268))
+  (func (export "㈒") (result i32) (i32.const 269))
+  (func (export "㈓") (result i32) (i32.const 270))
+  (func (export "㈔") (result i32) (i32.const 271))
+  (func (export "㈕") (result i32) (i32.const 272))
+  (func (export "㈖") (result i32) (i32.const 273))
+  (func (export "㈗") (result i32) (i32.const 274))
+  (func (export "㈘") (result i32) (i32.const 275))
+  (func (export "㈙") (result i32) (i32.const 276))
+  (func (export "㈚") (result i32) (i32.const 277))
+  (func (export "㈛") (result i32) (i32.const 278))
+  (func (export "㉮") (result i32) (i32.const 279))
+  (func (export "㉯") (result i32) (i32.const 280))
+  (func (export "㉰") (result i32) (i32.const 281))
+  (func (export "㉱") (result i32) (i32.const 282))
+  (func (export "㉲") (result i32) (i32.const 283))
+  (func (export "㉳") (result i32) (i32.const 284))
+  (func (export "㉴") (result i32) (i32.const 285))
+  (func (export "㉵") (result i32) (i32.const 286))
+  (func (export "㉶") (result i32) (i32.const 287))
+  (func (export "㉷") (result i32) (i32.const 288))
+  (func (export "㉸") (result i32) (i32.const 289))
+  (func (export "㉹") (result i32) (i32.const 290))
+  (func (export "㉺") (result i32) (i32.const 291))
+  (func (export "㉻") (result i32) (i32.const 292))
+  (func (export "㋐") (result i32) (i32.const 293))
+  (func (export "ꀊ") (result i32) (i32.const 294))
+  (func (export "ꓮ") (result i32) (i32.const 295))
+  (func (export "ꕉ") (result i32) (i32.const 296))
+  (func (export "ꚠ") (result i32) (i32.const 297))
+  (func (export "ꠀ") (result i32) (i32.const 298))
+  (func (export "ꠣ") (result i32) (i32.const 299))
+  (func (export "ꡝ") (result i32) (i32.const 300))
+  (func (export "ꢂ") (result i32) (i32.const 301))
+  (func (export "꣪") (result i32) (i32.const 302))
+  (func (export "ꤢ") (result i32) (i32.const 303))
+  (func (export "ꥆ") (result i32) (i32.const 304))
+  (func (export "ꦄ") (result i32) (i32.const 305))
+  (func (export "ꨀ") (result i32) (i32.const 306))
+  (func (export "ｱ") (result i32) (i32.const 307))
+  (func (export "ￂ") (result i32) (i32.const 308))
+  (func (export "𐀀") (result i32) (i32.const 309))
+  (func (export "𐊀") (result i32) (i32.const 310))
+  (func (export "𐊠") (result i32) (i32.const 311))
+  (func (export "𐌀") (result i32) (i32.const 312))
+  (func (export "𐎠") (result i32) (i32.const 313))
+  (func (export "𐒖") (result i32) (i32.const 314))
+  (func (export "𐔀") (result i32) (i32.const 315))
+  (func (export "𐝀") (result i32) (i32.const 316))
+  (func (export "𐠀") (result i32) (i32.const 317))
+  (func (export "𐤠") (result i32) (i32.const 318))
+  (func (export "𐦀") (result i32) (i32.const 319))
+  (func (export "𐦠") (result i32) (i32.const 320))
+  (func (export "𐨀") (result i32) (i32.const 321))
+  (func (export "𐬀") (result i32) (i32.const 322))
+  (func (export "𐰀") (result i32) (i32.const 323))
+  (func (export "𐰁") (result i32) (i32.const 324))
+  (func (export "𐲀") (result i32) (i32.const 325))
+  (func (export "𑀅") (result i32) (i32.const 326))
+  (func (export "𑂃") (result i32) (i32.const 327))
+  (func (export "𑄧") (result i32) (i32.const 328))
+  (func (export "𑅐") (result i32) (i32.const 329))
+  (func (export "𑆃") (result i32) (i32.const 330))
+  (func (export "𑈀") (result i32) (i32.const 331))
+  (func (export "𑊀") (result i32) (i32.const 332))
+  (func (export "𑊰") (result i32) (i32.const 333))
+  (func (export "𑌅") (result i32) (i32.const 334))
+  (func (export "𑍰") (result i32) (i32.const 335))
+  (func (export "𑐀") (result i32) (i32.const 336))
+  (func (export "𑒁") (result i32) (i32.const 337))
+  (func (export "𑖀") (result i32) (i32.const 338))
+  (func (export "𑘀") (result i32) (i32.const 339))
+  (func (export "𑚀") (result i32) (i32.const 340))
+  (func (export "𑜒") (result i32) (i32.const 341))
+  (func (export "𑜠") (result i32) (i32.const 342))
+  (func (export "𑢡") (result i32) (i32.const 343))
+  (func (export "𑫕") (result i32) (i32.const 344))
+  (func (export "𑰀") (result i32) (i32.const 345))
+  (func (export "𑲏") (result i32) (i32.const 346))
+  (func (export "𑲯") (result i32) (i32.const 347))
+  (func (export "𒀀") (result i32) (i32.const 348))
+  (func (export "𖧕") (result i32) (i32.const 349))
+  (func (export "𖩆") (result i32) (i32.const 350))
+  (func (export "𖫧") (result i32) (i32.const 351))
+  (func (export "𖽔") (result i32) (i32.const 352))
+  (func (export "𛱁") (result i32) (i32.const 353))
+  (func (export "𛱤") (result i32) (i32.const 354))
+  (func (export "𞠣") (result i32) (i32.const 355))
+  (func (export "🇦") (result i32) (i32.const 356))
+  (func (export "Ɑ") (result i32) (i32.const 357))
+  (func (export "Λ") (result i32) (i32.const 358))
+  (func (export "Ɒ") (result i32) (i32.const 359))
+  (func (export "ª") (result i32) (i32.const 360))
+  (func (export "∀") (result i32) (i32.const 361))
+  (func (export "₳") (result i32) (i32.const 362))
+  (func (export "𐤀") (result i32) (i32.const 363))
+  (func (export "Ⲁ") (result i32) (i32.const 364))
+  (func (export "𐌰") (result i32) (i32.const 365))
+  (func (export "Ά") (result i32) (i32.const 366))
+  (func (export "Α") (result i32) (i32.const 367))
+  (func (export "Ἀ") (result i32) (i32.const 368))
+  (func (export "Ἁ") (result i32) (i32.const 369))
+  (func (export "Ἂ") (result i32) (i32.const 370))
+  (func (export "Ἃ") (result i32) (i32.const 371))
+  (func (export "Ἄ") (result i32) (i32.const 372))
+  (func (export "Ἅ") (result i32) (i32.const 373))
+  (func (export "Ἆ") (result i32) (i32.const 374))
+  (func (export "Ἇ") (result i32) (i32.const 375))
+  (func (export "ᾈ") (result i32) (i32.const 376))
+  (func (export "ᾉ") (result i32) (i32.const 377))
+  (func (export "ᾊ") (result i32) (i32.const 378))
+  (func (export "ᾋ") (result i32) (i32.const 379))
+  (func (export "ᾌ") (result i32) (i32.const 380))
+  (func (export "ᾍ") (result i32) (i32.const 381))
+  (func (export "ᾎ") (result i32) (i32.const 382))
+  (func (export "ᾏ") (result i32) (i32.const 383))
+  (func (export "Ᾰ") (result i32) (i32.const 384))
+  (func (export "Ᾱ") (result i32) (i32.const 385))
+  (func (export "Ὰ") (result i32) (i32.const 386))
+  (func (export "Ά") (result i32) (i32.const 387))
+  (func (export "ᾼ") (result i32) (i32.const 388))
+  (func (export "𝚨") (result i32) (i32.const 389))
+  (func (export "𝛢") (result i32) (i32.const 390))
+  (func (export "𝜜") (result i32) (i32.const 391))
+  (func (export "𝝖") (result i32) (i32.const 392))
+  (func (export "𝞐") (result i32) (i32.const 393))
+  (func (export "⍶") (result i32) (i32.const 394))
+  (func (export "⍺") (result i32) (i32.const 395))
+  (func (export "⩜") (result i32) (i32.const 396))
+  (func (export "ᗅ") (result i32) (i32.const 397))
+  (func (export "Ꭺ") (result i32) (i32.const 398))
+
+  ;; Test unmatched "closing" and "opening" code points.
+  (func (export ")˺˼𔗏𝅴𝅶𝅸𝅺⁾₎❩❫⟯﴿︶﹚）｠󠀩❳❵⟧⟩⟫⟭⦈⦊⦖⸣⸥︘︸︺︼︾﹀﹂﹄﹈﹜﹞］｝｣󠁝󠁽»’”›❯") (result i32) (i32.const 399))
+  (func (export "(˹˻𔗎𝅳𝅵𝅷𝅹⁽₍❨❪⟮﴾︵﹙（｟󠀨❲❴⟦⟨⟪⟬⦇⦉⦕⸢⸤︗︷︹︻︽︿﹁﹃﹇﹛﹝［｛｢󠁛󠁻«‘“‹❮") (result i32) (i32.const 400))
+  (func (export "𝪋𝪤") (result i32) (i32.const 401))
+  (func (export "𝪋") (result i32) (i32.const 402))
+
+  ;; Test that Unicode fraction normalization is not applied.
+  (func (export "½") (result i32) (i32.const 403))
+  (func (export "1⁄2") (result i32) (i32.const 404))
+  (func (export "1/2") (result i32) (i32.const 405))
+  (func (export "୳") (result i32) (i32.const 406))
+  (func (export "൴") (result i32) (i32.const 407))
+  (func (export "⳽") (result i32) (i32.const 408))
+  (func (export "꠱") (result i32) (i32.const 409))
+  (func (export "𐅁") (result i32) (i32.const 410))
+  (func (export "𐅵") (result i32) (i32.const 411))
+  (func (export "𐅶") (result i32) (i32.const 412))
+  (func (export "𐦽") (result i32) (i32.const 413))
+  (func (export "𐹻") (result i32) (i32.const 414))
+
+  ;; Test a full-width quote.
+  (func (export "＂") (result i32) (i32.const 415))
+
+  ;; Test that different present and historical representations of the "delete"
+  ;; concept are distinct.
+  (func (export "\7f") (result i32) (i32.const 416))
+  (func (export "\08") (result i32) (i32.const 417))
+  (func (export "⌫") (result i32) (i32.const 418))
+  (func (export "⌦") (result i32) (i32.const 419))
+  (func (export "␈") (result i32) (i32.const 420))
+  (func (export "␡") (result i32) (i32.const 421))
+  (func (export "᷻") (result i32) (i32.const 422))
+  (func (export "\0f") (result i32) (i32.const 423))
+  (func (export "←") (result i32) (i32.const 424))
+  (func (export "⌧") (result i32) (i32.const 425))
+  (func (export "⍒") (result i32) (i32.const 426))
+  (func (export "⍔") (result i32) (i32.const 427))
+  (func (export "⍢") (result i32) (i32.const 428))
+  (func (export "⍫") (result i32) (i32.const 429))
+
+  ;; Test that different representations of the "substitute" concept are
+  ;; distinct. (U+FFFD is covered above.)
+  (func (export "\1a") (result i32) (i32.const 430))
+  (func (export "␦") (result i32) (i32.const 431))
+  (func (export "␚") (result i32) (i32.const 432))
+  (func (export "￼") (result i32) (i32.const 433))
+  (func (export "?") (result i32) (i32.const 434))
+  (func (export "¿") (result i32) (i32.const 435))
+  (func (export "᥅") (result i32) (i32.const 436))
+  (func (export ";") (result i32) (i32.const 437))
+  (func (export "՞") (result i32) (i32.const 438))
+  (func (export "؟") (result i32) (i32.const 439))
+  (func (export "፧") (result i32) (i32.const 440))
+  (func (export "⁇") (result i32) (i32.const 441))
+  (func (export "⍰") (result i32) (i32.const 442))
+  (func (export "❓") (result i32) (i32.const 443))
+  (func (export "❔") (result i32) (i32.const 444))
+  (func (export "⳺") (result i32) (i32.const 445))
+  (func (export "⳻") (result i32) (i32.const 446))
+  (func (export "⸮") (result i32) (i32.const 447))
+  (func (export "㉄") (result i32) (i32.const 448))
+  (func (export "꘏") (result i32) (i32.const 449))
+  (func (export "꛷") (result i32) (i32.const 450))
+  (func (export "︖") (result i32) (i32.const 451))
+  (func (export "﹖") (result i32) (i32.const 452))
+  (func (export "？") (result i32) (i32.const 453))
+  (func (export "𑅃") (result i32) (i32.const 454))
+  (func (export "𞥟") (result i32) (i32.const 455))
+  (func (export "󠀿") (result i32) (i32.const 456))
+  (func (export "𖡄") (result i32) (i32.const 457))
+  (func (export "⯑") (result i32) (i32.const 458))
+
+  ;; Test that different present and historical representations of the
+  ;; "paragraph" concept are distinct. (U+2029 is covered above).
+  (func (export "¶") (result i32) (i32.const 459))
+  (func (export "⁋") (result i32) (i32.const 460))
+  (func (export "܀") (result i32) (i32.const 461))
+  (func (export "჻") (result i32) (i32.const 462))
+  (func (export "፨") (result i32) (i32.const 463))
+  (func (export "〷") (result i32) (i32.const 464))
+  (func (export "❡") (result i32) (i32.const 465))
+  (func (export "⸏") (result i32) (i32.const 466))
+  (func (export "⸐") (result i32) (i32.const 467))
+  (func (export "⸑") (result i32) (i32.const 468))
+  (func (export "⸎") (result i32) (i32.const 469))
+  (func (export "\14") (result i32) (i32.const 470)) ;; ¶ in CP437
+  (func (export "☙") (result i32) (i32.const 471))
+  (func (export "⸿") (result i32) (i32.const 472))
+  (func (export "〇") (result i32) (i32.const 473))
+  (func (export "๛") (result i32) (i32.const 474))
+
+  ;; Test an unusual character.
+  (func (export "ꙮ") (result i32) (i32.const 475))
+
+  ;; Test the three characters whose normalization forms under NFC, NFD, NFKC,
+  ;; and NFKD are all different.
+  ;; http://unicode.org/faq/normalization.html#6
+  (func (export "ϓ") (result i32) (i32.const 476))
+  (func (export "ϔ") (result i32) (i32.const 477))
+  (func (export "ẛ") (result i32) (i32.const 478))
+)
+
+(assert_return (invoke "") (i32.const 0))
+(assert_return (invoke "0") (i32.const 1))
+(assert_return (invoke "-0") (i32.const 2))
+(assert_return (invoke "_") (i32.const 3))
+(assert_return (invoke "$") (i32.const 4))
+(assert_return (invoke "@") (i32.const 5))
+(assert_return (invoke "~!@#$%^&*()_+`-={}|[]\\:\";'<>?,./ ") (i32.const 6))
+(assert_return (invoke "NaN") (i32.const 7))
+(assert_return (invoke "Infinity") (i32.const 8))
+(assert_return (invoke "if") (i32.const 9))
+(assert_return (invoke "malloc") (i32.const 10))
+(assert_return (invoke "_malloc") (i32.const 11))
+(assert_return (invoke "__malloc") (i32.const 12))
+(assert_return (invoke "a") (i32.const 13))
+(assert_return (invoke "A") (i32.const 14))
+(assert_return (invoke "﻿") (i32.const 15))
+(assert_return (invoke "Å") (i32.const 16))
+(assert_return (invoke "Å") (i32.const 17))
+(assert_return (invoke "Å") (i32.const 18))
+(assert_return (invoke "ﬃ") (i32.const 19))
+(assert_return (invoke "fﬁ") (i32.const 20))
+(assert_return (invoke "ffi") (i32.const 21))
+(assert_return (invoke "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f") (i32.const 22))
+(assert_return (invoke "\10\11\12\13\14\15\16\17\18\19\1a\1b\1c\1d\1e\1f") (i32.const 23))
+(assert_return (invoke " \7f") (i32.const 24))
+(assert_return (invoke "\c2\80\c2\81\c2\82\c2\83\c2\84\c2\85\c2\86\c2\87\c2\88\c2\89\c2\8a\c2\8b\c2\8c\c2\8d\c2\8e\c2\8f") (i32.const 25))
+(assert_return (invoke "\c2\90\c2\91\c2\92\c2\93\c2\94\c2\95\c2\96\c2\97\c2\98\c2\99\c2\9a\c2\9b\c2\9c\c2\9d\c2\9e\c2\9f") (i32.const 26))
+(assert_return (invoke "\ef\bf\b0\ef\bf\b1\ef\bf\b2\ef\bf\b3\ef\bf\b4\ef\bf\b5\ef\bf\b6\ef\bf\b7") (i32.const 27))
+(assert_return (invoke "\ef\bf\b8\ef\bf\b9\ef\bf\ba\ef\bf\bb\ef\bf\bc\ef\bf\bd\ef\bf\be\ef\bf\bf") (i32.const 28))
+(assert_return (invoke "␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏") (i32.const 29))
+(assert_return (invoke "␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟") (i32.const 30))
+(assert_return (invoke "␠␡") (i32.const 31))
+(assert_return (invoke "￰￱￲￳￴￵￶￷￸￹￺￻￼�") (i32.const 32))
+(assert_return (invoke "‍") (i32.const 33))
+(assert_return (invoke "‌") (i32.const 34))
+(assert_return (invoke "͏") (i32.const 35))
+(assert_return (invoke "⁠") (i32.const 36))
+(assert_return (invoke "⵿") (i32.const 37))
+(assert_return (invoke "𑁿") (i32.const 38))
+(assert_return (invoke "᠎") (i32.const 39))
+(assert_return (invoke "￯​ ­⁠ ‮‭") (i32.const 40))
+(assert_return (invoke "‎‏‑  ‪‫‬ ⁦⁧⁨⁩") (i32.const 41))
+(assert_return (invoke "⁪⁫⁬⁭⁮⁯") (i32.const 42))
+(assert_return (invoke "⁡⁢⁣⁤") (i32.const 43))
+(assert_return (invoke "𐀀󟿿􏿿") (i32.const 44))
+(assert_return (invoke "Z̴͇̫̥̪͓͈͔͎̗̞̺̯̱̞̙̱̜̖̠̏͆̆͛͌͘͞ḁ̶̰̳̭͙̲̱̹̝͎̼͗ͨ̎̄̆͗̿̀́͟͡l̶̷͉̩̹̫̝͖̙̲̼͇͚͍̮͎̥̞̈́͊͗ͦ̈́ͫ̇́̚ͅͅg̶͕͔͚̩̓̐̅ͮ̔̐̎̂̏̾͊̍͋͊ͧ́̆ͦ͞o̡͋̔͐ͪͩ͏̢̧̫̙̤̮͖͙͓̺̜̩̼̘̠́") (i32.const 45))
+(assert_return (invoke "ᅟᅠㅤﾠ") (i32.const 46))
+(assert_return (invoke "︀") (i32.const 47))
+(assert_return (invoke "︄") (i32.const 48))
+(assert_return (invoke "󠄀") (i32.const 49))
+(assert_return (invoke "󠇯") (i32.const 50))
+(assert_return (invoke "̈") (i32.const 51))
+(assert_return (invoke "\0a") (i32.const 52))
+(assert_return (invoke "␤") (i32.const 53))
+(assert_return (invoke " ") (i32.const 54))
+(assert_return (invoke "\0d") (i32.const 55))
+(assert_return (invoke "\0d\0a") (i32.const 56))
+(assert_return (invoke "\0a\0d") (i32.const 57))
+(assert_return (invoke "\1e") (i32.const 58))
+(assert_return (invoke "\0b") (i32.const 59))
+(assert_return (invoke "\0c") (i32.const 60))
+(assert_return (invoke "\c2\85") (i32.const 61))
+(assert_return (invoke " ") (i32.const 62))
+(assert_return (invoke "…") (i32.const 63))
+(assert_return (invoke "⏎") (i32.const 64))
+(assert_return (invoke "\c2\8b") (i32.const 65))
+(assert_return (invoke "\c2\8c") (i32.const 66))
+(assert_return (invoke "\c2\8d") (i32.const 67))
+(assert_return (invoke "↵") (i32.const 68))
+(assert_return (invoke "↩") (i32.const 69))
+(assert_return (invoke "⌤") (i32.const 70))
+(assert_return (invoke "⤶") (i32.const 71))
+(assert_return (invoke "↲") (i32.const 72))
+(assert_return (invoke "⮨") (i32.const 73))
+(assert_return (invoke "⮰") (i32.const 74))
+(assert_return (invoke "�") (i32.const 75))
+(assert_return (invoke "\ef\b7\90") (i32.const 76))
+(assert_return (invoke "\ef\b7\91") (i32.const 77))
+(assert_return (invoke "\ef\b7\92") (i32.const 78))
+(assert_return (invoke "\ef\b7\93") (i32.const 79))
+(assert_return (invoke "\ef\b7\94") (i32.const 80))
+(assert_return (invoke "\ef\b7\95") (i32.const 81))
+(assert_return (invoke "\ef\b7\96") (i32.const 82))
+(assert_return (invoke "\ef\b7\97") (i32.const 83))
+(assert_return (invoke "\ef\b7\98") (i32.const 84))
+(assert_return (invoke "\ef\b7\99") (i32.const 85))
+(assert_return (invoke "\ef\b7\9a") (i32.const 86))
+(assert_return (invoke "\ef\b7\9b") (i32.const 87))
+(assert_return (invoke "\ef\b7\9c") (i32.const 88))
+(assert_return (invoke "\ef\b7\9d") (i32.const 89))
+(assert_return (invoke "\ef\b7\9e") (i32.const 90))
+(assert_return (invoke "\ef\b7\9f") (i32.const 91))
+(assert_return (invoke "\ef\b7\a0") (i32.const 92))
+(assert_return (invoke "\ef\b7\a1") (i32.const 93))
+(assert_return (invoke "\ef\b7\a2") (i32.const 94))
+(assert_return (invoke "\ef\b7\a3") (i32.const 95))
+(assert_return (invoke "\ef\b7\a4") (i32.const 96))
+(assert_return (invoke "\ef\b7\a5") (i32.const 97))
+(assert_return (invoke "\ef\b7\a6") (i32.const 98))
+(assert_return (invoke "\ef\b7\a7") (i32.const 99))
+(assert_return (invoke "\ef\b7\a8") (i32.const 100))
+(assert_return (invoke "\ef\b7\a9") (i32.const 101))
+(assert_return (invoke "\ef\b7\aa") (i32.const 102))
+(assert_return (invoke "\ef\b7\ab") (i32.const 103))
+(assert_return (invoke "\ef\b7\ac") (i32.const 104))
+(assert_return (invoke "\ef\b7\ad") (i32.const 105))
+(assert_return (invoke "\ef\b7\ae") (i32.const 106))
+(assert_return (invoke "\ef\b7\af") (i32.const 107))
+(assert_return (invoke "\ef\bf\be") (i32.const 108))
+(assert_return (invoke "\ef\bf\bf") (i32.const 109))
+(assert_return (invoke "\f0\9f\bf\be") (i32.const 110))
+(assert_return (invoke "\f0\9f\bf\bf") (i32.const 111))
+(assert_return (invoke "\f0\af\bf\be") (i32.const 112))
+(assert_return (invoke "\f0\af\bf\bf") (i32.const 113))
+(assert_return (invoke "\f0\bf\bf\be") (i32.const 114))
+(assert_return (invoke "\f0\bf\bf\bf") (i32.const 115))
+(assert_return (invoke "\f1\8f\bf\be") (i32.const 116))
+(assert_return (invoke "\f1\8f\bf\bf") (i32.const 117))
+(assert_return (invoke "\f1\9f\bf\be") (i32.const 118))
+(assert_return (invoke "\f1\9f\bf\bf") (i32.const 119))
+(assert_return (invoke "\f1\af\bf\be") (i32.const 120))
+(assert_return (invoke "\f1\af\bf\bf") (i32.const 121))
+(assert_return (invoke "\f1\bf\bf\be") (i32.const 122))
+(assert_return (invoke "\f1\bf\bf\bf") (i32.const 123))
+(assert_return (invoke "\f2\8f\bf\be") (i32.const 124))
+(assert_return (invoke "\f2\8f\bf\bf") (i32.const 125))
+(assert_return (invoke "\f2\9f\bf\be") (i32.const 126))
+(assert_return (invoke "\f2\9f\bf\bf") (i32.const 127))
+(assert_return (invoke "\f2\af\bf\be") (i32.const 128))
+(assert_return (invoke "\f2\af\bf\bf") (i32.const 129))
+(assert_return (invoke "\f2\bf\bf\be") (i32.const 130))
+(assert_return (invoke "\f2\bf\bf\bf") (i32.const 131))
+(assert_return (invoke "\f3\8f\bf\be") (i32.const 132))
+(assert_return (invoke "\f3\8f\bf\bf") (i32.const 133))
+(assert_return (invoke "\f3\9f\bf\be") (i32.const 134))
+(assert_return (invoke "\f3\9f\bf\bf") (i32.const 135))
+(assert_return (invoke "\f3\af\bf\be") (i32.const 136))
+(assert_return (invoke "\f3\af\bf\bf") (i32.const 137))
+(assert_return (invoke "\f3\bf\bf\be") (i32.const 138))
+(assert_return (invoke "\f3\bf\bf\bf") (i32.const 139))
+(assert_return (invoke "\f4\8f\bf\be") (i32.const 140))
+(assert_return (invoke "\f4\8f\bf\bf") (i32.const 141))
+(assert_return (invoke "̈‽̈̉") (i32.const 142))
+(assert_return (invoke "abc") (i32.const 143))
+(assert_return (invoke "‭abc") (i32.const 144))
+(assert_return (invoke "‮cba") (i32.const 145))
+(assert_return (invoke "‭abc‮") (i32.const 146))
+(assert_return (invoke "‮cba‭") (i32.const 147))
+(assert_return (invoke "𝑨") (i32.const 148))
+(assert_return (invoke "𝐴") (i32.const 149))
+(assert_return (invoke "𝘈") (i32.const 150))
+(assert_return (invoke "𝘼") (i32.const 151))
+(assert_return (invoke "𝐀") (i32.const 152))
+(assert_return (invoke "𝓐") (i32.const 153))
+(assert_return (invoke "𝕬") (i32.const 154))
+(assert_return (invoke "𝗔") (i32.const 155))
+(assert_return (invoke "𝒜") (i32.const 156))
+(assert_return (invoke "𝔄") (i32.const 157))
+(assert_return (invoke "𝔸") (i32.const 158))
+(assert_return (invoke "𝖠") (i32.const 159))
+(assert_return (invoke "𝙰") (i32.const 160))
+(assert_return (invoke "ᴀ") (i32.const 161))
+(assert_return (invoke "ᴬ") (i32.const 162))
+(assert_return (invoke "Ⓐ") (i32.const 163))
+(assert_return (invoke "Ａ") (i32.const 164))
+(assert_return (invoke "🄐") (i32.const 165))
+(assert_return (invoke "🄰") (i32.const 166))
+(assert_return (invoke "󠁁") (i32.const 167))
+(assert_return (invoke "U+0041") (i32.const 168))
+(assert_return (invoke "A​") (i32.const 169))
+(assert_return (invoke "А") (i32.const 170))
+(assert_return (invoke "Ꙗ") (i32.const 171))
+(assert_return (invoke "ⷼ") (i32.const 172))
+(assert_return (invoke "ⷶ") (i32.const 173))
+(assert_return (invoke "Ɐ") (i32.const 174))
+(assert_return (invoke "🅐") (i32.const 175))
+(assert_return (invoke "🅰") (i32.const 176))
+(assert_return (invoke "Ⱝ") (i32.const 177))
+(assert_return (invoke "𐐂") (i32.const 178))
+(assert_return (invoke "𐐈") (i32.const 179))
+(assert_return (invoke "𐒰") (i32.const 180))
+(assert_return (invoke "À") (i32.const 181))
+(assert_return (invoke "Á") (i32.const 182))
+(assert_return (invoke "Â") (i32.const 183))
+(assert_return (invoke "Ã") (i32.const 184))
+(assert_return (invoke "Ä") (i32.const 185))
+(assert_return (invoke "Ā") (i32.const 186))
+(assert_return (invoke "Ă") (i32.const 187))
+(assert_return (invoke "Ą") (i32.const 188))
+(assert_return (invoke "Ǎ") (i32.const 189))
+(assert_return (invoke "Ǟ") (i32.const 190))
+(assert_return (invoke "Ǡ") (i32.const 191))
+(assert_return (invoke "Ǻ") (i32.const 192))
+(assert_return (invoke "Ȁ") (i32.const 193))
+(assert_return (invoke "Ȃ") (i32.const 194))
+(assert_return (invoke "Ȧ") (i32.const 195))
+(assert_return (invoke "Ⱥ") (i32.const 196))
+(assert_return (invoke "Ӑ") (i32.const 197))
+(assert_return (invoke "Ӓ") (i32.const 198))
+(assert_return (invoke "ߊ") (i32.const 199))
+(assert_return (invoke "ࠡ") (i32.const 200))
+(assert_return (invoke "ࠢ") (i32.const 201))
+(assert_return (invoke "ࠣ") (i32.const 202))
+(assert_return (invoke "ࠤ") (i32.const 203))
+(assert_return (invoke "ࠥ") (i32.const 204))
+(assert_return (invoke "ऄ") (i32.const 205))
+(assert_return (invoke "अ") (i32.const 206))
+(assert_return (invoke "ॲ") (i32.const 207))
+(assert_return (invoke "অ") (i32.const 208))
+(assert_return (invoke "ਅ") (i32.const 209))
+(assert_return (invoke "અ") (i32.const 210))
+(assert_return (invoke "ଅ") (i32.const 211))
+(assert_return (invoke "அ") (i32.const 212))
+(assert_return (invoke "అ") (i32.const 213))
+(assert_return (invoke "ಅ") (i32.const 214))
+(assert_return (invoke "അ") (i32.const 215))
+(assert_return (invoke "ะ") (i32.const 216))
+(assert_return (invoke "ະ") (i32.const 217))
+(assert_return (invoke "༁") (i32.const 218))
+(assert_return (invoke "ཨ") (i32.const 219))
+(assert_return (invoke "ྸ") (i32.const 220))
+(assert_return (invoke "အ") (i32.const 221))
+(assert_return (invoke "ဢ") (i32.const 222))
+(assert_return (invoke "ႜ") (i32.const 223))
+(assert_return (invoke "ᅡ") (i32.const 224))
+(assert_return (invoke "አ") (i32.const 225))
+(assert_return (invoke "ዐ") (i32.const 226))
+(assert_return (invoke "Ꭰ") (i32.const 227))
+(assert_return (invoke "ᐊ") (i32.const 228))
+(assert_return (invoke "ᖳ") (i32.const 229))
+(assert_return (invoke "ᚨ") (i32.const 230))
+(assert_return (invoke "ᚪ") (i32.const 231))
+(assert_return (invoke "ᛆ") (i32.const 232))
+(assert_return (invoke "ᜀ") (i32.const 233))
+(assert_return (invoke "ᜠ") (i32.const 234))
+(assert_return (invoke "ᝀ") (i32.const 235))
+(assert_return (invoke "ᝠ") (i32.const 236))
+(assert_return (invoke "ᠠ") (i32.const 237))
+(assert_return (invoke "ᢇ") (i32.const 238))
+(assert_return (invoke "ᤠ") (i32.const 239))
+(assert_return (invoke "ᥣ") (i32.const 240))
+(assert_return (invoke "ᨕ") (i32.const 241))
+(assert_return (invoke "ᩋ") (i32.const 242))
+(assert_return (invoke "ᩡ") (i32.const 243))
+(assert_return (invoke "ᮃ") (i32.const 244))
+(assert_return (invoke "ᯀ") (i32.const 245))
+(assert_return (invoke "ᯁ") (i32.const 246))
+(assert_return (invoke "ᰣ") (i32.const 247))
+(assert_return (invoke "Ḁ") (i32.const 248))
+(assert_return (invoke "Ạ") (i32.const 249))
+(assert_return (invoke "Ả") (i32.const 250))
+(assert_return (invoke "Ấ") (i32.const 251))
+(assert_return (invoke "Ầ") (i32.const 252))
+(assert_return (invoke "Ẩ") (i32.const 253))
+(assert_return (invoke "Ẫ") (i32.const 254))
+(assert_return (invoke "Ậ") (i32.const 255))
+(assert_return (invoke "Ắ") (i32.const 256))
+(assert_return (invoke "Ằ") (i32.const 257))
+(assert_return (invoke "Ẳ") (i32.const 258))
+(assert_return (invoke "Ẵ") (i32.const 259))
+(assert_return (invoke "Ặ") (i32.const 260))
+(assert_return (invoke "あ") (i32.const 261))
+(assert_return (invoke "ア") (i32.const 262))
+(assert_return (invoke "ㄚ") (i32.const 263))
+(assert_return (invoke "ㅏ") (i32.const 264))
+(assert_return (invoke "㈎") (i32.const 265))
+(assert_return (invoke "㈏") (i32.const 266))
+(assert_return (invoke "㈐") (i32.const 267))
+(assert_return (invoke "㈑") (i32.const 268))
+(assert_return (invoke "㈒") (i32.const 269))
+(assert_return (invoke "㈓") (i32.const 270))
+(assert_return (invoke "㈔") (i32.const 271))
+(assert_return (invoke "㈕") (i32.const 272))
+(assert_return (invoke "㈖") (i32.const 273))
+(assert_return (invoke "㈗") (i32.const 274))
+(assert_return (invoke "㈘") (i32.const 275))
+(assert_return (invoke "㈙") (i32.const 276))
+(assert_return (invoke "㈚") (i32.const 277))
+(assert_return (invoke "㈛") (i32.const 278))
+(assert_return (invoke "㉮") (i32.const 279))
+(assert_return (invoke "㉯") (i32.const 280))
+(assert_return (invoke "㉰") (i32.const 281))
+(assert_return (invoke "㉱") (i32.const 282))
+(assert_return (invoke "㉲") (i32.const 283))
+(assert_return (invoke "㉳") (i32.const 284))
+(assert_return (invoke "㉴") (i32.const 285))
+(assert_return (invoke "㉵") (i32.const 286))
+(assert_return (invoke "㉶") (i32.const 287))
+(assert_return (invoke "㉷") (i32.const 288))
+(assert_return (invoke "㉸") (i32.const 289))
+(assert_return (invoke "㉹") (i32.const 290))
+(assert_return (invoke "㉺") (i32.const 291))
+(assert_return (invoke "㉻") (i32.const 292))
+(assert_return (invoke "㋐") (i32.const 293))
+(assert_return (invoke "ꀊ") (i32.const 294))
+(assert_return (invoke "ꓮ") (i32.const 295))
+(assert_return (invoke "ꕉ") (i32.const 296))
+(assert_return (invoke "ꚠ") (i32.const 297))
+(assert_return (invoke "ꠀ") (i32.const 298))
+(assert_return (invoke "ꠣ") (i32.const 299))
+(assert_return (invoke "ꡝ") (i32.const 300))
+(assert_return (invoke "ꢂ") (i32.const 301))
+(assert_return (invoke "꣪") (i32.const 302))
+(assert_return (invoke "ꤢ") (i32.const 303))
+(assert_return (invoke "ꥆ") (i32.const 304))
+(assert_return (invoke "ꦄ") (i32.const 305))
+(assert_return (invoke "ꨀ") (i32.const 306))
+(assert_return (invoke "ｱ") (i32.const 307))
+(assert_return (invoke "ￂ") (i32.const 308))
+(assert_return (invoke "𐀀") (i32.const 309))
+(assert_return (invoke "𐊀") (i32.const 310))
+(assert_return (invoke "𐊠") (i32.const 311))
+(assert_return (invoke "𐌀") (i32.const 312))
+(assert_return (invoke "𐎠") (i32.const 313))
+(assert_return (invoke "𐒖") (i32.const 314))
+(assert_return (invoke "𐔀") (i32.const 315))
+(assert_return (invoke "𐝀") (i32.const 316))
+(assert_return (invoke "𐠀") (i32.const 317))
+(assert_return (invoke "𐤠") (i32.const 318))
+(assert_return (invoke "𐦀") (i32.const 319))
+(assert_return (invoke "𐦠") (i32.const 320))
+(assert_return (invoke "𐨀") (i32.const 321))
+(assert_return (invoke "𐬀") (i32.const 322))
+(assert_return (invoke "𐰀") (i32.const 323))
+(assert_return (invoke "𐰁") (i32.const 324))
+(assert_return (invoke "𐲀") (i32.const 325))
+(assert_return (invoke "𑀅") (i32.const 326))
+(assert_return (invoke "𑂃") (i32.const 327))
+(assert_return (invoke "𑄧") (i32.const 328))
+(assert_return (invoke "𑅐") (i32.const 329))
+(assert_return (invoke "𑆃") (i32.const 330))
+(assert_return (invoke "𑈀") (i32.const 331))
+(assert_return (invoke "𑊀") (i32.const 332))
+(assert_return (invoke "𑊰") (i32.const 333))
+(assert_return (invoke "𑌅") (i32.const 334))
+(assert_return (invoke "𑍰") (i32.const 335))
+(assert_return (invoke "𑐀") (i32.const 336))
+(assert_return (invoke "𑒁") (i32.const 337))
+(assert_return (invoke "𑖀") (i32.const 338))
+(assert_return (invoke "𑘀") (i32.const 339))
+(assert_return (invoke "𑚀") (i32.const 340))
+(assert_return (invoke "𑜒") (i32.const 341))
+(assert_return (invoke "𑜠") (i32.const 342))
+(assert_return (invoke "𑢡") (i32.const 343))
+(assert_return (invoke "𑫕") (i32.const 344))
+(assert_return (invoke "𑰀") (i32.const 345))
+(assert_return (invoke "𑲏") (i32.const 346))
+(assert_return (invoke "𑲯") (i32.const 347))
+(assert_return (invoke "𒀀") (i32.const 348))
+(assert_return (invoke "𖧕") (i32.const 349))
+(assert_return (invoke "𖩆") (i32.const 350))
+(assert_return (invoke "𖫧") (i32.const 351))
+(assert_return (invoke "𖽔") (i32.const 352))
+(assert_return (invoke "𛱁") (i32.const 353))
+(assert_return (invoke "𛱤") (i32.const 354))
+(assert_return (invoke "𞠣") (i32.const 355))
+(assert_return (invoke "🇦") (i32.const 356))
+(assert_return (invoke "Ɑ") (i32.const 357))
+(assert_return (invoke "Λ") (i32.const 358))
+(assert_return (invoke "Ɒ") (i32.const 359))
+(assert_return (invoke "ª") (i32.const 360))
+(assert_return (invoke "∀") (i32.const 361))
+(assert_return (invoke "₳") (i32.const 362))
+(assert_return (invoke "𐤀") (i32.const 363))
+(assert_return (invoke "Ⲁ") (i32.const 364))
+(assert_return (invoke "𐌰") (i32.const 365))
+(assert_return (invoke "Ά") (i32.const 366))
+(assert_return (invoke "Α") (i32.const 367))
+(assert_return (invoke "Ἀ") (i32.const 368))
+(assert_return (invoke "Ἁ") (i32.const 369))
+(assert_return (invoke "Ἂ") (i32.const 370))
+(assert_return (invoke "Ἃ") (i32.const 371))
+(assert_return (invoke "Ἄ") (i32.const 372))
+(assert_return (invoke "Ἅ") (i32.const 373))
+(assert_return (invoke "Ἆ") (i32.const 374))
+(assert_return (invoke "Ἇ") (i32.const 375))
+(assert_return (invoke "ᾈ") (i32.const 376))
+(assert_return (invoke "ᾉ") (i32.const 377))
+(assert_return (invoke "ᾊ") (i32.const 378))
+(assert_return (invoke "ᾋ") (i32.const 379))
+(assert_return (invoke "ᾌ") (i32.const 380))
+(assert_return (invoke "ᾍ") (i32.const 381))
+(assert_return (invoke "ᾎ") (i32.const 382))
+(assert_return (invoke "ᾏ") (i32.const 383))
+(assert_return (invoke "Ᾰ") (i32.const 384))
+(assert_return (invoke "Ᾱ") (i32.const 385))
+(assert_return (invoke "Ὰ") (i32.const 386))
+(assert_return (invoke "Ά") (i32.const 387))
+(assert_return (invoke "ᾼ") (i32.const 388))
+(assert_return (invoke "𝚨") (i32.const 389))
+(assert_return (invoke "𝛢") (i32.const 390))
+(assert_return (invoke "𝜜") (i32.const 391))
+(assert_return (invoke "𝝖") (i32.const 392))
+(assert_return (invoke "𝞐") (i32.const 393))
+(assert_return (invoke "⍶") (i32.const 394))
+(assert_return (invoke "⍺") (i32.const 395))
+(assert_return (invoke "⩜") (i32.const 396))
+(assert_return (invoke "ᗅ") (i32.const 397))
+(assert_return (invoke "Ꭺ") (i32.const 398))
+(assert_return (invoke ")˺˼𔗏𝅴𝅶𝅸𝅺⁾₎❩❫⟯﴿︶﹚）｠󠀩❳❵⟧⟩⟫⟭⦈⦊⦖⸣⸥︘︸︺︼︾﹀﹂﹄﹈﹜﹞］｝｣󠁝󠁽»’”›❯") (i32.const 399))
+(assert_return (invoke "(˹˻𔗎𝅳𝅵𝅷𝅹⁽₍❨❪⟮﴾︵﹙（｟󠀨❲❴⟦⟨⟪⟬⦇⦉⦕⸢⸤︗︷︹︻︽︿﹁﹃﹇﹛﹝［｛｢󠁛󠁻«‘“‹❮") (i32.const 400))
+(assert_return (invoke "𝪋𝪤") (i32.const 401))
+(assert_return (invoke "𝪋") (i32.const 402))
+(assert_return (invoke "½") (i32.const 403))
+(assert_return (invoke "1⁄2") (i32.const 404))
+(assert_return (invoke "1/2") (i32.const 405))
+(assert_return (invoke "୳") (i32.const 406))
+(assert_return (invoke "൴") (i32.const 407))
+(assert_return (invoke "⳽") (i32.const 408))
+(assert_return (invoke "꠱") (i32.const 409))
+(assert_return (invoke "𐅁") (i32.const 410))
+(assert_return (invoke "𐅵") (i32.const 411))
+(assert_return (invoke "𐅶") (i32.const 412))
+(assert_return (invoke "𐦽") (i32.const 413))
+(assert_return (invoke "𐹻") (i32.const 414))
+(assert_return (invoke "＂") (i32.const 415))
+(assert_return (invoke "\7f") (i32.const 416))
+(assert_return (invoke "\08") (i32.const 417))
+(assert_return (invoke "⌫") (i32.const 418))
+(assert_return (invoke "⌦") (i32.const 419))
+(assert_return (invoke "␈") (i32.const 420))
+(assert_return (invoke "␡") (i32.const 421))
+(assert_return (invoke "᷻") (i32.const 422))
+(assert_return (invoke "\0f") (i32.const 423))
+(assert_return (invoke "←") (i32.const 424))
+(assert_return (invoke "⌧") (i32.const 425))
+(assert_return (invoke "⍒") (i32.const 426))
+(assert_return (invoke "⍔") (i32.const 427))
+(assert_return (invoke "⍢") (i32.const 428))
+(assert_return (invoke "⍫") (i32.const 429))
+(assert_return (invoke "\1a") (i32.const 430))
+(assert_return (invoke "␦") (i32.const 431))
+(assert_return (invoke "␚") (i32.const 432))
+(assert_return (invoke "￼") (i32.const 433))
+(assert_return (invoke "?") (i32.const 434))
+(assert_return (invoke "¿") (i32.const 435))
+(assert_return (invoke "᥅") (i32.const 436))
+(assert_return (invoke ";") (i32.const 437))
+(assert_return (invoke "՞") (i32.const 438))
+(assert_return (invoke "؟") (i32.const 439))
+(assert_return (invoke "፧") (i32.const 440))
+(assert_return (invoke "⁇") (i32.const 441))
+(assert_return (invoke "⍰") (i32.const 442))
+(assert_return (invoke "❓") (i32.const 443))
+(assert_return (invoke "❔") (i32.const 444))
+(assert_return (invoke "⳺") (i32.const 445))
+(assert_return (invoke "⳻") (i32.const 446))
+(assert_return (invoke "⸮") (i32.const 447))
+(assert_return (invoke "㉄") (i32.const 448))
+(assert_return (invoke "꘏") (i32.const 449))
+(assert_return (invoke "꛷") (i32.const 450))
+(assert_return (invoke "︖") (i32.const 451))
+(assert_return (invoke "﹖") (i32.const 452))
+(assert_return (invoke "？") (i32.const 453))
+(assert_return (invoke "𑅃") (i32.const 454))
+(assert_return (invoke "𞥟") (i32.const 455))
+(assert_return (invoke "󠀿") (i32.const 456))
+(assert_return (invoke "𖡄") (i32.const 457))
+(assert_return (invoke "⯑") (i32.const 458))
+(assert_return (invoke "¶") (i32.const 459))
+(assert_return (invoke "⁋") (i32.const 460))
+(assert_return (invoke "܀") (i32.const 461))
+(assert_return (invoke "჻") (i32.const 462))
+(assert_return (invoke "፨") (i32.const 463))
+(assert_return (invoke "〷") (i32.const 464))
+(assert_return (invoke "❡") (i32.const 465))
+(assert_return (invoke "⸏") (i32.const 466))
+(assert_return (invoke "⸐") (i32.const 467))
+(assert_return (invoke "⸑") (i32.const 468))
+(assert_return (invoke "⸎") (i32.const 469))
+(assert_return (invoke "\14") (i32.const 470))
+(assert_return (invoke "☙") (i32.const 471))
+(assert_return (invoke "⸿") (i32.const 472))
+(assert_return (invoke "〇") (i32.const 473))
+(assert_return (invoke "๛") (i32.const 474))
+(assert_return (invoke "ꙮ") (i32.const 475))
+(assert_return (invoke "ϓ") (i32.const 476))
+(assert_return (invoke "ϔ") (i32.const 477))
+(assert_return (invoke "ẛ") (i32.const 478))
+
+(module
+  ;; Test that we can use indices instead of names to reference imports,
+  ;; exports, functions and parameters.
+  (import "spectest" "print_i32" (func (param i32)))
+  (func (import "spectest" "print_i32") (param i32))
+  (func (param i32) (param i32)
+    (call 0 (local.get 0))
+    (call 1 (local.get 1))
+  )
+  (export "print32" (func 2))
+)
+
+(assert_return (invoke "print32" (i32.const 42) (i32.const 123)))
diff --git a/binaryen/test/spec/nop.wast b/binaryen/test/spec/nop.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/nop.wast
@@ -0,0 +1,426 @@
+;; Test `nop` operator.
+
+(module
+  ;; Auxiliary definitions
+  (func $dummy)
+  (func $3-ary (param i32 i32 i32) (result i32)
+    local.get 0 local.get 1 local.get 2 i32.sub i32.add
+  )
+  (memory 1)
+
+  (func (export "as-func-first") (result i32)
+    (nop) (i32.const 1)
+  )
+  (func (export "as-func-mid") (result i32)
+    (call $dummy) (nop) (i32.const 2)
+  )
+  (func (export "as-func-last") (result i32)
+    (call $dummy) (i32.const 3) (nop)
+  )
+  (func (export "as-func-everywhere") (result i32)
+    (nop) (nop) (call $dummy) (nop) (i32.const 4) (nop) (nop)
+  )
+
+  (func (export "as-drop-first") (param i32)
+    (nop) (local.get 0) (drop)
+  )
+  (func (export "as-drop-last") (param i32)
+    (local.get 0) (nop) (drop)
+  )
+  (func (export "as-drop-everywhere") (param i32)
+    (nop) (nop) (local.get 0) (nop) (nop) (drop)
+  )
+
+  (func (export "as-select-first") (param i32) (result i32)
+    (nop) (local.get 0) (local.get 0) (local.get 0) (select)
+  )
+  (func (export "as-select-mid1") (param i32) (result i32)
+    (local.get 0) (nop) (local.get 0) (local.get 0) (select)
+  )
+  (func (export "as-select-mid2") (param i32) (result i32)
+    (local.get 0) (local.get 0) (nop) (local.get 0) (select)
+  )
+  (func (export "as-select-last") (param i32) (result i32)
+    (local.get 0) (local.get 0) (local.get 0) (nop) (select)
+  )
+  (func (export "as-select-everywhere") (param i32) (result i32)
+    (nop) (local.get 0) (nop) (nop) (local.get 0)
+    (nop) (nop) (local.get 0) (nop) (nop) (select)
+  )
+
+  (func (export "as-block-first") (result i32)
+    (block (result i32) (nop) (i32.const 2))
+  )
+  (func (export "as-block-mid") (result i32)
+    (block (result i32) (call $dummy) (nop) (i32.const 2))
+  )
+  (func (export "as-block-last") (result i32)
+    (block (result i32) (nop) (call $dummy) (i32.const 3) (nop))
+  )
+  (func (export "as-block-everywhere") (result i32)
+    (block (result i32)
+      (nop) (nop) (call $dummy) (nop) (i32.const 4) (nop) (nop)
+    )
+  )
+
+  (func (export "as-loop-first") (result i32)
+    (loop (result i32) (nop) (i32.const 2))
+  )
+  (func (export "as-loop-mid") (result i32)
+    (loop (result i32) (call $dummy) (nop) (i32.const 2))
+  )
+  (func (export "as-loop-last") (result i32)
+    (loop (result i32) (call $dummy) (i32.const 3) (nop))
+  )
+  (func (export "as-loop-everywhere") (result i32)
+    (loop (result i32)
+      (nop) (nop) (call $dummy) (nop) (i32.const 4) (nop) (nop)
+    )
+  )
+
+  (func (export "as-if-condition") (param i32)
+    (local.get 0) (nop) (if (then (call $dummy)))
+  )
+  (func (export "as-if-then") (param i32)
+    (if (local.get 0) (then (nop)) (else (call $dummy)))
+  )
+  (func (export "as-if-else") (param i32)
+    (if (local.get 0) (then (call $dummy)) (else (nop)))
+  )
+
+  (func (export "as-br-first") (param i32) (result i32)
+    (block (result i32) (nop) (local.get 0) (br 0))
+  )
+  (func (export "as-br-last") (param i32) (result i32)
+    (block (result i32) (local.get 0) (nop) (br 0))
+  )
+  (func (export "as-br-everywhere") (param i32) (result i32)
+    (block (result i32) (nop) (nop) (local.get 0) (nop) (nop) (br 0))
+  )
+
+  (func (export "as-br_if-first") (param i32) (result i32)
+    (block (result i32) (nop) (local.get 0) (local.get 0) (br_if 0))
+  )
+  (func (export "as-br_if-mid") (param i32) (result i32)
+    (block (result i32) (local.get 0) (nop) (local.get 0) (br_if 0))
+  )
+  (func (export "as-br_if-last") (param i32) (result i32)
+    (block (result i32) (local.get 0) (local.get 0) (nop) (br_if 0))
+  )
+  (func (export "as-br_if-everywhere") (param i32) (result i32)
+    (block (result i32)
+      (nop) (nop) (local.get 0) (nop) (nop) (local.get 0) (nop) (nop)
+      (br_if 0)
+    )
+  )
+
+  (func (export "as-br_table-first") (param i32) (result i32)
+    (block (result i32) (nop) (local.get 0) (local.get 0) (br_table 0 0))
+  )
+  (func (export "as-br_table-mid") (param i32) (result i32)
+    (block (result i32) (local.get 0) (nop) (local.get 0) (br_table 0 0))
+  )
+  (func (export "as-br_table-last") (param i32) (result i32)
+    (block (result i32) (local.get 0) (local.get 0) (nop) (br_table 0 0))
+  )
+  (func (export "as-br_table-everywhere") (param i32) (result i32)
+    (block (result i32)
+      (nop) (nop) (local.get 0) (nop) (nop) (local.get 0) (nop) (nop)
+      (br_table 0 0)
+    )
+  )
+
+  (func (export "as-return-first") (param i32) (result i32)
+    (nop) (local.get 0) (return)
+  )
+  (func (export "as-return-last") (param i32) (result i32)
+    (local.get 0) (nop) (return)
+  )
+  (func (export "as-return-everywhere") (param i32) (result i32)
+    (nop) (nop) (local.get 0) (nop) (nop) (return)
+  )
+
+  (func (export "as-call-first") (param i32 i32 i32) (result i32)
+    (nop) (local.get 0) (local.get 1) (local.get 2) (call $3-ary)
+  )
+  (func (export "as-call-mid1") (param i32 i32 i32) (result i32)
+    (local.get 0) (nop) (local.get 1) (local.get 2) (call $3-ary)
+  )
+  (func (export "as-call-mid2") (param i32 i32 i32) (result i32)
+    (local.get 0) (local.get 1) (nop) (local.get 2) (call $3-ary)
+  )
+  (func (export "as-call-last") (param i32 i32 i32) (result i32)
+    (local.get 0) (local.get 1) (local.get 2) (nop) (call $3-ary)
+  )
+  (func (export "as-call-everywhere") (param i32 i32 i32) (result i32)
+    (nop) (nop) (local.get 0) (nop) (nop) (local.get 1)
+    (nop) (nop) (local.get 2) (nop) (nop) (call $3-ary)
+  )
+
+  (func (export "as-unary-first") (param i32) (result i32)
+    (nop) (local.get 0) (i32.ctz)
+  )
+  (func (export "as-unary-last") (param i32) (result i32)
+    (local.get 0) (nop) (i32.ctz)
+  )
+  (func (export "as-unary-everywhere") (param i32) (result i32)
+    (nop) (nop) (local.get 0) (nop) (nop) (i32.ctz)
+  )
+
+  (func (export "as-binary-first") (param i32) (result i32)
+    (nop) (local.get 0) (local.get 0) (i32.add)
+  )
+  (func (export "as-binary-mid") (param i32) (result i32)
+    (local.get 0) (nop) (local.get 0) (i32.add)
+  )
+  (func (export "as-binary-last") (param i32) (result i32)
+    (local.get 0) (local.get 0) (nop) (i32.add)
+  )
+  (func (export "as-binary-everywhere") (param i32) (result i32)
+    (nop) (local.get 0) (nop) (nop) (local.get 0) (nop) (nop) (i32.add)
+  )
+
+  (func (export "as-test-first") (param i32) (result i32)
+    (nop) (local.get 0) (i32.eqz)
+  )
+  (func (export "as-test-last") (param i32) (result i32)
+    (local.get 0) (nop) (i32.eqz)
+  )
+  (func (export "as-test-everywhere") (param i32) (result i32)
+    (nop) (nop) (local.get 0) (nop) (nop) i32.eqz
+  )
+
+  (func (export "as-compare-first") (param i32) (result i32)
+    (nop) (local.get 0) (local.get 0) (i32.ne)
+  )
+  (func (export "as-compare-mid") (param i32) (result i32)
+    (local.get 0) (nop) (local.get 0) (i32.ne)
+  )
+  (func (export "as-compare-last") (param i32) (result i32)
+    (local.get 0) (local.get 0) (nop) (i32.lt_u)
+  )
+  (func (export "as-compare-everywhere") (param i32) (result i32)
+    (nop) (local.get 0) (nop) (nop) (local.get 0) (nop) (nop) (i32.le_s)
+  )
+
+  (func (export "as-memory.grow-first") (param i32) (result i32)
+    (nop) (local.get 0) (memory.grow)
+  )
+  (func (export "as-memory.grow-last") (param i32) (result i32)
+    (local.get 0) (nop) (memory.grow)
+  )
+  (func (export "as-memory.grow-everywhere") (param i32) (result i32)
+    (nop) (nop) (local.get 0) (nop) (nop) (memory.grow)
+  )
+
+  (func $func (param i32 i32) (result i32) (local.get 0))
+  (type $check (func (param i32 i32) (result i32)))
+  (table funcref (elem $func))
+  (func (export "as-call_indirect-first") (result i32)
+    (block (result i32)
+      (nop) (i32.const 1) (i32.const 2) (i32.const 0)
+      (call_indirect (type $check))
+    )
+  )
+  (func (export "as-call_indirect-mid1") (result i32)
+    (block (result i32)
+      (i32.const 1) (nop) (i32.const 2) (i32.const 0)
+      (call_indirect (type $check))
+    )
+  )
+  (func (export "as-call_indirect-mid2") (result i32)
+    (block (result i32)
+      (i32.const 1) (i32.const 2) (nop) (i32.const 0)
+      (call_indirect (type $check))
+    )
+  )
+  (func (export "as-call_indirect-last") (result i32)
+    (block (result i32)
+      (i32.const 1) (i32.const 2) (i32.const 0) (nop)
+      (call_indirect (type $check))
+    )
+  )
+  (func (export "as-call_indirect-everywhere") (result i32)
+    (block (result i32)
+      (nop) (nop) (i32.const 1) (nop) (nop) (i32.const 2) (nop) (nop) (i32.const 0) (nop) (nop)
+      (call_indirect (type $check))
+    )
+  )
+
+  (func (export "as-local.set-first") (param i32) (result i32)
+    (nop) (i32.const 2) (local.set 0) (local.get 0)
+  )
+  (func (export "as-local.set-last") (param i32) (result i32)
+    (i32.const 2) (nop) (local.set 0) (local.get 0)
+  )
+  (func (export "as-local.set-everywhere") (param i32) (result i32)
+    (nop) (nop) (i32.const 2) (nop) (nop) (local.set 0) (local.get 0)
+  )
+
+  (func (export "as-local.tee-first") (param i32) (result i32)
+    (nop) (i32.const 2) (local.tee 0)
+  )
+  (func (export "as-local.tee-last") (param i32) (result i32)
+    (i32.const 2) (nop) (local.tee 0)
+  )
+  (func (export "as-local.tee-everywhere") (param i32) (result i32)
+    (nop) (nop) (i32.const 2) (nop) (nop) (local.tee 0)
+  )
+
+  (global $a (mut i32) (i32.const 0))
+  (func (export "as-global.set-first") (result i32)
+    (nop) (i32.const 2) (global.set $a) (global.get $a)
+  )
+  (func (export "as-global.set-last") (result i32)
+    (i32.const 2) (nop) (global.set $a) (global.get $a)
+  )
+  (func (export "as-global.set-everywhere") (result i32)
+    (nop) (nop) (i32.const 2) (nop) (nop) (global.set 0)
+    (global.get $a)
+  )
+
+  (func (export "as-load-first") (param i32) (result i32)
+    (nop) (local.get 0) (i32.load)
+  )
+  (func (export "as-load-last") (param i32) (result i32)
+    (local.get 0) (nop) (i32.load)
+  )
+  (func (export "as-load-everywhere") (param i32) (result i32)
+    (nop) (nop) (local.get 0) (nop) (nop) (i32.load)
+  )
+
+  (func (export "as-store-first") (param i32 i32)
+    (nop) (local.get 0) (local.get 1) (i32.store)
+  )
+  (func (export "as-store-mid") (param i32 i32)
+    (local.get 0) (nop) (local.get 1) (i32.store)
+  )
+  (func (export "as-store-last") (param i32 i32)
+    (local.get 0) (local.get 1) (nop) (i32.store)
+  )
+  (func (export "as-store-everywhere") (param i32 i32)
+    (nop) (nop) (local.get 0) (nop) (nop) (local.get 1) (nop) (nop) (i32.store)
+  )
+)
+
+(assert_return (invoke "as-func-first") (i32.const 1))
+(assert_return (invoke "as-func-mid") (i32.const 2))
+(assert_return (invoke "as-func-last") (i32.const 3))
+(assert_return (invoke "as-func-everywhere") (i32.const 4))
+
+(assert_return (invoke "as-drop-first" (i32.const 0)))
+(assert_return (invoke "as-drop-last" (i32.const 0)))
+(assert_return (invoke "as-drop-everywhere" (i32.const 0)))
+
+(assert_return (invoke "as-select-first" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "as-select-mid1" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "as-select-mid2" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "as-select-last" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "as-select-everywhere" (i32.const 3)) (i32.const 3))
+
+(assert_return (invoke "as-block-first") (i32.const 2))
+(assert_return (invoke "as-block-mid") (i32.const 2))
+(assert_return (invoke "as-block-last") (i32.const 3))
+(assert_return (invoke "as-block-everywhere") (i32.const 4))
+
+(assert_return (invoke "as-loop-first") (i32.const 2))
+(assert_return (invoke "as-loop-mid") (i32.const 2))
+(assert_return (invoke "as-loop-last") (i32.const 3))
+(assert_return (invoke "as-loop-everywhere") (i32.const 4))
+
+(assert_return (invoke "as-if-condition" (i32.const 0)))
+(assert_return (invoke "as-if-condition" (i32.const -1)))
+(assert_return (invoke "as-if-then" (i32.const 0)))
+(assert_return (invoke "as-if-then" (i32.const 4)))
+(assert_return (invoke "as-if-else" (i32.const 0)))
+(assert_return (invoke "as-if-else" (i32.const 3)))
+
+(assert_return (invoke "as-br-first" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "as-br-last" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-br-everywhere" (i32.const 7)) (i32.const 7))
+
+(assert_return (invoke "as-br_if-first" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "as-br_if-mid" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "as-br_if-last" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-br_if-everywhere" (i32.const 7)) (i32.const 7))
+
+(assert_return (invoke "as-br_table-first" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "as-br_table-mid" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "as-br_table-last" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-br_table-everywhere" (i32.const 7)) (i32.const 7))
+
+(assert_return (invoke "as-return-first" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "as-return-last" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-return-everywhere" (i32.const 7)) (i32.const 7))
+
+(assert_return (invoke "as-call-first" (i32.const 3) (i32.const 1) (i32.const 2)) (i32.const 2))
+(assert_return (invoke "as-call-mid1" (i32.const 3) (i32.const 1) (i32.const 2)) (i32.const 2))
+(assert_return (invoke "as-call-mid2" (i32.const 0) (i32.const 3) (i32.const 1)) (i32.const 2))
+(assert_return (invoke "as-call-last" (i32.const 10) (i32.const 9) (i32.const -1)) (i32.const 20))
+(assert_return (invoke "as-call-everywhere" (i32.const 2) (i32.const 1) (i32.const 5)) (i32.const -2))
+
+(assert_return (invoke "as-unary-first" (i32.const 30)) (i32.const 1))
+(assert_return (invoke "as-unary-last" (i32.const 30)) (i32.const 1))
+(assert_return (invoke "as-unary-everywhere" (i32.const 12)) (i32.const 2))
+
+(assert_return (invoke "as-binary-first" (i32.const 3)) (i32.const 6))
+(assert_return (invoke "as-binary-mid" (i32.const 3)) (i32.const 6))
+(assert_return (invoke "as-binary-last" (i32.const 3)) (i32.const 6))
+(assert_return (invoke "as-binary-everywhere" (i32.const 3)) (i32.const 6))
+
+(assert_return (invoke "as-test-first" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-test-last" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-test-everywhere" (i32.const 0)) (i32.const 1))
+
+(assert_return (invoke "as-compare-first" (i32.const 3)) (i32.const 0))
+(assert_return (invoke "as-compare-mid" (i32.const 3)) (i32.const 0))
+(assert_return (invoke "as-compare-last" (i32.const 3)) (i32.const 0))
+(assert_return (invoke "as-compare-everywhere" (i32.const 3)) (i32.const 1))
+
+(assert_return (invoke "as-memory.grow-first" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-memory.grow-last" (i32.const 2)) (i32.const 1))
+(assert_return (invoke "as-memory.grow-everywhere" (i32.const 12)) (i32.const 3))
+
+(assert_return (invoke "as-call_indirect-first") (i32.const 1))
+(assert_return (invoke "as-call_indirect-mid1") (i32.const 1))
+(assert_return (invoke "as-call_indirect-mid2") (i32.const 1))
+(assert_return (invoke "as-call_indirect-last") (i32.const 1))
+(assert_return (invoke "as-call_indirect-everywhere") (i32.const 1))
+
+(assert_return (invoke "as-local.set-first" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "as-local.set-last" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "as-local.set-everywhere" (i32.const 1)) (i32.const 2))
+
+(assert_return (invoke "as-local.tee-first" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "as-local.tee-last" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "as-local.tee-everywhere" (i32.const 1)) (i32.const 2))
+
+(assert_return (invoke "as-global.set-first") (i32.const 2))
+(assert_return (invoke "as-global.set-last") (i32.const 2))
+(assert_return (invoke "as-global.set-everywhere") (i32.const 2))
+
+(assert_return (invoke "as-load-first" (i32.const 100)) (i32.const 0))
+(assert_return (invoke "as-load-last" (i32.const 100)) (i32.const 0))
+(assert_return (invoke "as-load-everywhere" (i32.const 100)) (i32.const 0))
+
+(assert_return (invoke "as-store-first" (i32.const 0) (i32.const 1)))
+(assert_return (invoke "as-store-mid" (i32.const 0) (i32.const 2)))
+(assert_return (invoke "as-store-last" (i32.const 0) (i32.const 3)))
+(assert_return (invoke "as-store-everywhere" (i32.const 0) (i32.const 4)))
+
+(assert_invalid
+  (module (func $type-i32 (result i32) (nop)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-i64 (result i64) (nop)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-f32 (result f32) (nop)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-f64 (result f64) (nop)))
+  "type mismatch"
+)
diff --git a/binaryen/test/spec/of_string-overflow-hex-u32.fail.wast b/binaryen/test/spec/of_string-overflow-hex-u32.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/of_string-overflow-hex-u32.fail.wast
@@ -0,0 +1,1 @@
+(module (func (i32.const 0x100000000)))
diff --git a/binaryen/test/spec/of_string-overflow-hex-u64.fail.wast b/binaryen/test/spec/of_string-overflow-hex-u64.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/of_string-overflow-hex-u64.fail.wast
@@ -0,0 +1,1 @@
+(module (func (i64.const 0x10000000000000000)))
diff --git a/binaryen/test/spec/of_string-overflow-s32.fail.wast b/binaryen/test/spec/of_string-overflow-s32.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/of_string-overflow-s32.fail.wast
@@ -0,0 +1,1 @@
+(module (func (i32.const -2147483649)))
diff --git a/binaryen/test/spec/of_string-overflow-s64.fail.wast b/binaryen/test/spec/of_string-overflow-s64.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/of_string-overflow-s64.fail.wast
@@ -0,0 +1,1 @@
+(module (func (i64.const -9223372036854775809)))
diff --git a/binaryen/test/spec/of_string-overflow-u32.fail.wast b/binaryen/test/spec/of_string-overflow-u32.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/of_string-overflow-u32.fail.wast
@@ -0,0 +1,1 @@
+(module (func (i32.const 4294967296)))
diff --git a/binaryen/test/spec/of_string-overflow-u64.fail.wast b/binaryen/test/spec/of_string-overflow-u64.fail.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/of_string-overflow-u64.fail.wast
@@ -0,0 +1,1 @@
+(module (func (i64.const 18446744073709551616)))
diff --git a/binaryen/test/spec/old_address.wast b/binaryen/test/spec/old_address.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_address.wast
@@ -0,0 +1,34 @@
+(module
+  (import "spectest" "print" (func $print (param i32)))
+
+  (memory 1)
+  (data (i32.const 0) "abcdefghijklmnopqrstuvwxyz")
+
+  (func (export "good") (param $i i32)
+    (call $print (i32.load8_u offset=0 (local.get $i)))  ;; 97 'a'
+    (call $print (i32.load8_u offset=1 (local.get $i)))  ;; 98 'b'
+    (call $print (i32.load8_u offset=2 (local.get $i)))  ;; 99 'c'
+    (call $print (i32.load8_u offset=25 (local.get $i))) ;; 122 'z'
+
+    (call $print (i32.load16_u offset=0 (local.get $i)))          ;; 25185 'ab'
+    (call $print (i32.load16_u align=1 (local.get $i)))           ;; 25185 'ab'
+    (call $print (i32.load16_u offset=1 align=1 (local.get $i)))  ;; 25442 'bc'
+    (call $print (i32.load16_u offset=2 (local.get $i)))          ;; 25699 'cd'
+    (call $print (i32.load16_u offset=25 align=1 (local.get $i))) ;; 122 'z\0'
+
+    (call $print (i32.load offset=0 (local.get $i)))          ;; 1684234849 'abcd'
+    (call $print (i32.load offset=1 align=1 (local.get $i)))  ;; 1701077858 'bcde'
+    (call $print (i32.load offset=2 align=2 (local.get $i)))  ;; 1717920867 'cdef'
+    (call $print (i32.load offset=25 align=1 (local.get $i))) ;; 122 'z\0\0\0'
+  )
+
+  (func (export "bad") (param $i i32)
+    (drop (i32.load offset=4294967295 (local.get $i)))
+  )
+)
+
+(invoke "good" (i32.const 0))
+(invoke "good" (i32.const 65507))
+(assert_trap (invoke "good" (i32.const 65508)) "out of bounds memory access")
+(assert_trap (invoke "bad" (i32.const 0)) "out of bounds memory access")
+(assert_trap (invoke "bad" (i32.const 1)) "out of bounds memory access")
diff --git a/binaryen/test/spec/old_address64.wast b/binaryen/test/spec/old_address64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_address64.wast
@@ -0,0 +1,34 @@
+(module
+  (import "spectest" "print" (func $print (param i32)))
+
+  (memory i64 1)
+  (data (i32.const 0) "abcdefghijklmnopqrstuvwxyz")
+
+  (func (export "good") (param $i i64)
+    (call $print (i32.load8_u offset=0 (local.get $i)))  ;; 97 'a'
+    (call $print (i32.load8_u offset=1 (local.get $i)))  ;; 98 'b'
+    (call $print (i32.load8_u offset=2 (local.get $i)))  ;; 99 'c'
+    (call $print (i32.load8_u offset=25 (local.get $i))) ;; 122 'z'
+
+    (call $print (i32.load16_u offset=0 (local.get $i)))          ;; 25185 'ab'
+    (call $print (i32.load16_u align=1 (local.get $i)))           ;; 25185 'ab'
+    (call $print (i32.load16_u offset=1 align=1 (local.get $i)))  ;; 25442 'bc'
+    (call $print (i32.load16_u offset=2 (local.get $i)))          ;; 25699 'cd'
+    (call $print (i32.load16_u offset=25 align=1 (local.get $i))) ;; 122 'z\0'
+
+    (call $print (i32.load offset=0 (local.get $i)))          ;; 1684234849 'abcd'
+    (call $print (i32.load offset=1 align=1 (local.get $i)))  ;; 1701077858 'bcde'
+    (call $print (i32.load offset=2 align=2 (local.get $i)))  ;; 1717920867 'cdef'
+    (call $print (i32.load offset=25 align=1 (local.get $i))) ;; 122 'z\0\0\0'
+  )
+
+  (func (export "bad") (param $i i64)
+    (drop (i32.load offset=4294967295 (local.get $i)))
+  )
+)
+
+(invoke "good" (i64.const 0))
+(invoke "good" (i64.const 65507))
+(assert_trap (invoke "good" (i64.const 65508)) "out of bounds memory access")
+(assert_trap (invoke "bad" (i64.const 0)) "out of bounds memory access")
+(assert_trap (invoke "bad" (i64.const 1)) "out of bounds memory access")
diff --git a/binaryen/test/spec/old_block.wast b/binaryen/test/spec/old_block.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_block.wast
@@ -0,0 +1,284 @@
+;; Test `block` operator
+
+(module
+  ;; Auxiliary definition
+  (func $dummy)
+
+  (func (export "empty")
+    (block)
+    (block $l)
+  )
+
+  (func (export "singular") (result i32)
+    (block (nop))
+    (block i32 (i32.const 7))
+  )
+
+  (func (export "multi") (result i32)
+    (block (call $dummy) (call $dummy) (call $dummy) (call $dummy))
+    (block i32 (call $dummy) (call $dummy) (call $dummy) (i32.const 8))
+  )
+
+  (func (export "nested") (result i32)
+    (block i32
+      (block (call $dummy) (block) (nop))
+      (block i32 (call $dummy) (i32.const 9))
+    )
+  )
+
+  (func (export "deep") (result i32)
+    (block i32 (block i32 (block i32 (block i32 (block i32 (block i32
+      (block i32 (block i32 (block i32 (block i32 (block i32 (block i32
+        (block i32 (block i32 (block i32 (block i32 (block i32 (block i32
+          (block i32 (block i32 (block i32 (block i32 (block i32 (block i32
+            (block i32 (block i32 (block i32 (block i32 (block i32 (block i32
+              (block i32 (block i32 (block i32 (block i32 (block i32 (block i32
+                (block i32 (block i32 (call $dummy) (i32.const 150)))
+              ))))))
+            ))))))
+          ))))))
+        ))))))
+      ))))))
+    ))))))
+  )
+
+  (func (export "as-unary-operand") (result i32)
+    (i32.ctz (block i32 (call $dummy) (i32.const 13)))
+  )
+  (func (export "as-binary-operand") (result i32)
+    (i32.mul
+      (block i32 (call $dummy) (i32.const 3))
+      (block i32 (call $dummy) (i32.const 4))
+    )
+  )
+  (func (export "as-test-operand") (result i32)
+    (i32.eqz (block i32 (call $dummy) (i32.const 13)))
+  )
+  (func (export "as-compare-operand") (result i32)
+    (f32.gt
+      (block f32 (call $dummy) (f32.const 3))
+      (block f32 (call $dummy) (f32.const 3))
+    )
+  )
+
+  (func (export "break-bare") (result i32)
+    (block (br 0) (unreachable))
+    (block (br_if 0 (i32.const 1)) (unreachable))
+    (block (br_table 0 (i32.const 0)) (unreachable))
+    (block (br_table 0 0 0 (i32.const 1)) (unreachable))
+    (i32.const 19)
+  )
+  (func (export "break-value") (result i32)
+    (block i32 (br 0 (i32.const 18)) (i32.const 19))
+  )
+  (func (export "break-repeated") (result i32)
+    (block i32
+      (br 0 (i32.const 18))
+      (br 0 (i32.const 19))
+      (drop (br_if 0 (i32.const 20) (i32.const 0)))
+      (drop (br_if 0 (i32.const 20) (i32.const 1)))
+      (br 0 (i32.const 21))
+      (br_table 0 (i32.const 22) (i32.const 4))
+      (br_table 0 0 0 (i32.const 23) (i32.const 1))
+      (i32.const 21)
+    )
+  )
+  (func (export "break-inner") (result i32)
+    (local i32)
+    (local.set 0 (i32.const 0))
+    (local.set 0 (i32.add (local.get 0) (block i32 (block i32 (br 1 (i32.const 0x1))))))
+    (local.set 0 (i32.add (local.get 0) (block i32 (block (br 0)) (i32.const 0x2))))
+    (local.set 0
+      (i32.add (local.get 0) (block i32 (i32.ctz (br 0 (i32.const 0x4)))))
+    )
+    (local.set 0
+      (i32.add (local.get 0) (block i32 (i32.ctz (block i32 (br 1 (i32.const 0x8))))))
+    )
+    (local.get 0)
+  )
+
+  (func (export "effects") (result i32)
+    (local i32)
+    (block
+      (local.set 0 (i32.const 1))
+      (local.set 0 (i32.mul (local.get 0) (i32.const 3)))
+      (local.set 0 (i32.sub (local.get 0) (i32.const 5)))
+      (local.set 0 (i32.mul (local.get 0) (i32.const 7)))
+      (br 0)
+      (local.set 0 (i32.mul (local.get 0) (i32.const 100)))
+    )
+    (i32.eq (local.get 0) (i32.const -14))
+  )
+)
+
+(assert_return (invoke "empty"))
+(assert_return (invoke "singular") (i32.const 7))
+(assert_return (invoke "multi") (i32.const 8))
+(assert_return (invoke "nested") (i32.const 9))
+(assert_return (invoke "deep") (i32.const 150))
+
+(assert_return (invoke "as-unary-operand") (i32.const 0))
+(assert_return (invoke "as-binary-operand") (i32.const 12))
+(assert_return (invoke "as-test-operand") (i32.const 0))
+(assert_return (invoke "as-compare-operand") (i32.const 0))
+
+(assert_return (invoke "break-bare") (i32.const 19))
+(assert_return (invoke "break-value") (i32.const 18))
+(assert_return (invoke "break-repeated") (i32.const 18))
+(assert_return (invoke "break-inner") (i32.const 0xf))
+
+(assert_return (invoke "effects") (i32.const 1))
+
+(assert_invalid
+  (module (func $type-empty-i32 (result i32) (block)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-i64 (result i64) (block)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f32 (result f32) (block)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f64 (result f64) (block)))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-value-num-vs-void
+    (block (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-void-vs-num (result i32)
+    (block (nop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-num-vs-num (result i32)
+    (block (f32.const 0))
+  ))
+  "type mismatch"
+)
+
+(; TODO(stack): soft failure
+(assert_invalid
+  (module (func $type-value-num-vs-void-after-break
+    (block (br 0) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-void-vs-num-after-break (result i32)
+    (block (i32.const 1) (br 0) (nop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-num-vs-num-after-break (result i32)
+    (block (i32.const 1) (br 0) (f32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-second-void-vs-num (result i32)
+    (block i32 (br 0 (i32.const 1)) (br 0 (nop)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-second-num-vs-num (result i32)
+    (block i32 (br 0 (i32.const 1)) (br 0 (f64.const 1)))
+  ))
+  "type mismatch"
+)
+;)
+
+(assert_invalid
+  (module (func $type-break-last-void-vs-num (result i32)
+    (block i32 (br 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-void-vs-num (result i32)
+    (block i32 (br 0) (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-void-vs-num (result i32)
+    (block (br 0 (nop)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-num-vs-num (result i32)
+    (block (br 0 (i64.const 1)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-void-vs-num (result i32)
+    (block (br 0 (nop)) (br 0 (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-num-vs-num (result i32)
+    (block (br 0 (i64.const 1)) (br 0 (i32.const 1)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-nested-num-vs-void
+    (block i32 (block i32 (br 1 (i32.const 1))) (br 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-empty-vs-num (result i32)
+    (block (block (br 1)) (br 0 (i32.const 1)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-nested-void-vs-num (result i32)
+    (block (block (br 1 (nop))) (br 0 (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-num-vs-num (result i32)
+    (block (block (br 1 (i64.const 1))) (br 0 (i32.const 1)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-operand-empty-vs-num (result i32)
+    (i32.ctz (block (br 0)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-break-operand-void-vs-num (result i32)
+    (i64.ctz (block (br 0 (nop))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-operand-num-vs-num (result i32)
+    (i64.ctz (block (br 0 (i64.const 9))))
+  ))
+  "type mismatch"
+)
+
diff --git a/binaryen/test/spec/old_br_if.wast b/binaryen/test/spec/old_br_if.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_br_if.wast
@@ -0,0 +1,306 @@
+;; Test `br_if` operator
+
+(module
+  (func $dummy)
+
+  (func (export "as-block-first") (param i32) (result i32)
+    (block (br_if 0 (local.get 0)) (return (i32.const 2))) (i32.const 3)
+  )
+  (func (export "as-block-mid") (param i32) (result i32)
+    (block (call $dummy) (br_if 0 (local.get 0)) (return (i32.const 2)))
+    (i32.const 3)
+  )
+  (func (export "as-block-last") (param i32)
+    (block (call $dummy) (call $dummy) (br_if 0 (local.get 0)))
+  )
+  (func (export "as-block-first-value") (param i32) (result i32)
+    (block i32 (drop (br_if 0 (i32.const 10) (local.get 0))) (return (i32.const 11)))
+  )
+  (func (export "as-block-mid-value") (param i32) (result i32)
+    (block i32 (call $dummy) (drop (br_if 0 (i32.const 20) (local.get 0))) (return (i32.const 21)))
+  )
+  (func (export "as-block-last-value") (param i32) (result i32)
+    (block i32
+      (call $dummy) (call $dummy) (br_if 0 (i32.const 11) (local.get 0))
+    )
+  )
+
+  (func (export "as-loop-first") (param i32) (result i32)
+    (block (loop (br_if 1 (local.get 0)) (return (i32.const 2)))) (i32.const 3)
+  )
+  (func (export "as-loop-mid") (param i32) (result i32)
+    (block (loop (call $dummy) (br_if 1 (local.get 0)) (return (i32.const 2))))
+    (i32.const 4)
+  )
+  (func (export "as-loop-last") (param i32)
+    (loop (call $dummy) (br_if 1 (local.get 0)))
+  )
+
+  (func (export "as-if-then") (param i32 i32)
+    (block (if (local.get 0) (br_if 1 (local.get 1)) (call $dummy)))
+  )
+  (func (export "as-if-else") (param i32 i32)
+    (block (if (local.get 0) (call $dummy) (br_if 1 (local.get 1))))
+  )
+
+  (func (export "nested-block-value") (param i32) (result i32)
+    (i32.add
+      (i32.const 1)
+      (block i32
+        (drop (i32.const 2))
+        (i32.add
+          (i32.const 4)
+          (block i32
+            (drop (br_if 1 (i32.const 8) (local.get 0)))
+            (i32.const 16)
+          )
+        )
+      )
+    )
+  )
+
+  (func (export "nested-br-value") (param i32) (result i32)
+    (i32.add
+      (i32.const 1)
+      (block i32
+        (drop (i32.const 2))
+        (br 0
+          (block i32 (drop (br_if 1 (i32.const 8) (local.get 0))) (i32.const 4))
+        )
+        (i32.const 16)
+      )
+    )
+  )
+
+  (func (export "nested-br_if-value") (param i32) (result i32)
+    (i32.add
+      (i32.const 1)
+      (block i32
+        (drop (i32.const 2))
+        (drop (br_if 0
+          (block i32 (drop (br_if 1 (i32.const 8) (local.get 0))) (i32.const 4))
+          (i32.const 1)
+        ))
+        (i32.const 16)
+      )
+    )
+  )
+
+  (func (export "nested-br_if-value-cond") (param i32) (result i32)
+    (i32.add
+      (i32.const 1)
+      (block i32
+        (drop (i32.const 2))
+        (drop (br_if 0
+          (i32.const 4)
+          (block i32 (drop (br_if 1 (i32.const 8) (local.get 0))) (i32.const 1))
+        ))
+        (i32.const 16)
+      )
+    )
+  )
+
+  (func (export "nested-br_table-value") (param i32) (result i32)
+    (i32.add
+      (i32.const 1)
+      (block i32
+        (drop (i32.const 2))
+        (br_table 0
+          (block i32 (drop (br_if 1 (i32.const 8) (local.get 0))) (i32.const 4))
+          (i32.const 1)
+        )
+        (i32.const 16)
+      )
+    )
+  )
+
+  (func (export "nested-br_table-value-index") (param i32) (result i32)
+    (i32.add
+      (i32.const 1)
+      (block i32
+        (drop (i32.const 2))
+        (br_table 0
+          (i32.const 4)
+          (block i32 (drop (br_if 1 (i32.const 8) (local.get 0))) (i32.const 1))
+        )
+        (i32.const 16)
+      )
+    )
+  )
+)
+
+(assert_return (invoke "as-block-first" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-block-first" (i32.const 1)) (i32.const 3))
+(assert_return (invoke "as-block-mid" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-block-mid" (i32.const 1)) (i32.const 3))
+(assert_return (invoke "as-block-last" (i32.const 0)))
+(assert_return (invoke "as-block-last" (i32.const 1)))
+(assert_return (invoke "as-block-last-value" (i32.const 0)) (i32.const 11))
+(assert_return (invoke "as-block-last-value" (i32.const 1)) (i32.const 11))
+
+(assert_return (invoke "as-loop-first" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-loop-first" (i32.const 1)) (i32.const 3))
+(assert_return (invoke "as-loop-mid" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-loop-mid" (i32.const 1)) (i32.const 4))
+(assert_return (invoke "as-loop-last" (i32.const 0)))
+(assert_return (invoke "as-loop-last" (i32.const 1)))
+
+(assert_return (invoke "as-if-then" (i32.const 0) (i32.const 0)))
+(assert_return (invoke "as-if-then" (i32.const 4) (i32.const 0)))
+(assert_return (invoke "as-if-then" (i32.const 0) (i32.const 1)))
+(assert_return (invoke "as-if-then" (i32.const 4) (i32.const 1)))
+(assert_return (invoke "as-if-else" (i32.const 0) (i32.const 0)))
+(assert_return (invoke "as-if-else" (i32.const 3) (i32.const 0)))
+(assert_return (invoke "as-if-else" (i32.const 0) (i32.const 1)))
+(assert_return (invoke "as-if-else" (i32.const 3) (i32.const 1)))
+
+(assert_return (invoke "nested-block-value" (i32.const 0)) (i32.const 21))
+(assert_return (invoke "nested-block-value" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br-value" (i32.const 0)) (i32.const 5))
+(assert_return (invoke "nested-br-value" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br_if-value" (i32.const 0)) (i32.const 5))
+(assert_return (invoke "nested-br_if-value" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br_if-value-cond" (i32.const 0)) (i32.const 5))
+(assert_return (invoke "nested-br_if-value-cond" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br_table-value" (i32.const 0)) (i32.const 5))
+(assert_return (invoke "nested-br_table-value" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br_table-value-index" (i32.const 0)) (i32.const 5))
+(assert_return (invoke "nested-br_table-value-index" (i32.const 1)) (i32.const 9))
+
+(assert_invalid
+  (module (func $type-false-i32 (block (i32.ctz (br_if 0 (i32.const 0))))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-false-i64 (block (i64.ctz (br_if 0 (i32.const 0))))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-false-f32 (block (f32.neg (br_if 0 (i32.const 0))))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-false-f64 (block (f64.neg (br_if 0 (i32.const 0))))))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-true-i32 (block (i32.ctz (br_if 0 (i32.const 1))))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-true-i64 (block (i64.ctz (br_if 0 (i64.const 1))))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-true-f32 (block (f32.neg (br_if 0 (f32.const 1))))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-true-f64 (block (f64.neg (br_if 0 (i64.const 1))))))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-false-arg-void-vs-num (result i32)
+    (block i32 (br_if 0 (i32.const 0)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-true-arg-void-vs-num (result i32)
+    (block i32 (br_if 0 (i32.const 1)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-false-arg-num-vs-void
+    (block (br_if 0 (i32.const 0) (i32.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-true-arg-num-vs-void
+    (block (br_if 0 (i32.const 0) (i32.const 1)))
+  ))
+  "type mismatch"
+)
+
+(; TODO(stack): soft failure
+(assert_invalid
+  (module (func $type-false-arg-poly-vs-empty
+    (block (br_if 0 (unreachable) (i32.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-true-arg-poly-vs-empty
+    (block (br_if 0 (unreachable) (i32.const 1)))
+  ))
+  "type mismatch"
+)
+;)
+
+(assert_invalid
+  (module (func $type-false-arg-void-vs-num (result i32)
+    (block i32 (br_if 0 (nop) (i32.const 0)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-true-arg-void-vs-num (result i32)
+    (block i32 (br_if 0 (nop) (i32.const 1)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-false-arg-num-vs-num (result i32)
+    (block i32 (drop (br_if 0 (i64.const 1) (i32.const 0))) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-true-arg-num-vs-num (result i32)
+    (block i32 (drop (br_if 0 (i64.const 1) (i32.const 0))) (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-cond-void-vs-i32
+    (block (br_if 0 (nop)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-cond-num-vs-i32
+    (block (br_if 0 (i64.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-arg-cond-void-vs-i32 (result i32)
+    (block i32 (br_if 0 (i32.const 0) (nop)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-arg-cond-num-vs-i32 (result i32)
+    (block i32 (br_if 0 (i32.const 0) (i64.const 0)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $unbound-label (br_if 1 (i32.const 1))))
+  "unknown label"
+)
+(assert_invalid
+  (module (func $unbound-nested-label (block (block (br_if 5 (i32.const 1))))))
+  "unknown label"
+)
+(assert_invalid
+  (module (func $large-label (br_if 0x10000001 (i32.const 1))))
+  "unknown label"
+)
+
diff --git a/binaryen/test/spec/old_call.wast b/binaryen/test/spec/old_call.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_call.wast
@@ -0,0 +1,233 @@
+;; Test `call` operator
+
+(module
+  ;; Auxiliary definitions
+  (func $const-i32 (result i32) (i32.const 0x132))
+  (func $const-i64 (result i64) (i64.const 0x164))
+  (func $const-f32 (result f32) (f32.const 0xf32))
+  (func $const-f64 (result f64) (f64.const 0xf64))
+
+  (func $id-i32 (param i32) (result i32) (local.get 0))
+  (func $id-i64 (param i64) (result i64) (local.get 0))
+  (func $id-f32 (param f32) (result f32) (local.get 0))
+  (func $id-f64 (param f64) (result f64) (local.get 0))
+
+  (func $f32-i32 (param f32 i32) (result i32) (local.get 1))
+  (func $i32-i64 (param i32 i64) (result i64) (local.get 1))
+  (func $f64-f32 (param f64 f32) (result f32) (local.get 1))
+  (func $i64-f64 (param i64 f64) (result f64) (local.get 1))
+
+  ;; Typing
+
+  (func (export "type-i32") (result i32) (call $const-i32))
+  (func (export "type-i64") (result i64) (call $const-i64))
+  (func (export "type-f32") (result f32) (call $const-f32))
+  (func (export "type-f64") (result f64) (call $const-f64))
+
+  (func (export "type-first-i32") (result i32) (call $id-i32 (i32.const 32)))
+  (func (export "type-first-i64") (result i64) (call $id-i64 (i64.const 64)))
+  (func (export "type-first-f32") (result f32) (call $id-f32 (f32.const 1.32)))
+  (func (export "type-first-f64") (result f64) (call $id-f64 (f64.const 1.64)))
+
+  (func (export "type-second-i32") (result i32)
+    (call $f32-i32 (f32.const 32.1) (i32.const 32))
+  )
+  (func (export "type-second-i64") (result i64)
+    (call $i32-i64 (i32.const 32) (i64.const 64))
+  )
+  (func (export "type-second-f32") (result f32)
+    (call $f64-f32 (f64.const 64) (f32.const 32))
+  )
+  (func (export "type-second-f64") (result f64)
+    (call $i64-f64 (i64.const 64) (f64.const 64.1))
+  )
+
+  ;; Recursion
+
+  (func $fac (export "fac") (param i64) (result i64)
+    (if i64 (i64.eqz (local.get 0))
+      (i64.const 1)
+      (i64.mul (local.get 0) (call $fac (i64.sub (local.get 0) (i64.const 1))))
+    )
+  )
+
+  (func $fac-acc (export "fac-acc") (param i64 i64) (result i64)
+    (if i64 (i64.eqz (local.get 0))
+      (local.get 1)
+      (call $fac-acc
+        (i64.sub (local.get 0) (i64.const 1))
+        (i64.mul (local.get 0) (local.get 1))
+      )
+    )
+  )
+
+  (func $fib (export "fib") (param i64) (result i64)
+    (if i64 (i64.le_u (local.get 0) (i64.const 1))
+      (i64.const 1)
+      (i64.add
+        (call $fib (i64.sub (local.get 0) (i64.const 2)))
+        (call $fib (i64.sub (local.get 0) (i64.const 1)))
+      )
+    )
+  )
+
+  (func $even (export "even") (param i64) (result i32)
+    (if i32 (i64.eqz (local.get 0))
+      (i32.const 44)
+      (call $odd (i64.sub (local.get 0) (i64.const 1)))
+    )
+  )
+  (func $odd (export "odd") (param i64) (result i32)
+    (if i32 (i64.eqz (local.get 0))
+      (i32.const 99)
+      (call $even (i64.sub (local.get 0) (i64.const 1)))
+    )
+  )
+
+  ;; Stack exhaustion
+
+  ;; Implementations are required to have every call consume some abstract
+  ;; resource towards exhausting some abstract finite limit, such that
+  ;; infinitely recursive test cases reliably trap in finite time. This is
+  ;; because otherwise applications could come to depend on it on those
+  ;; implementations and be incompatible with implementations that don't do
+  ;; it (or don't do it under the same circumstances).
+
+  (func $runaway (export "runaway") (call $runaway))
+
+  (func $mutual-runaway1 (export "mutual-runaway") (call $mutual-runaway2))
+  (func $mutual-runaway2 (call $mutual-runaway1))
+)
+
+(assert_return (invoke "type-i32") (i32.const 0x132))
+(assert_return (invoke "type-i64") (i64.const 0x164))
+(assert_return (invoke "type-f32") (f32.const 0xf32))
+(assert_return (invoke "type-f64") (f64.const 0xf64))
+
+(assert_return (invoke "type-first-i32") (i32.const 32))
+(assert_return (invoke "type-first-i64") (i64.const 64))
+(assert_return (invoke "type-first-f32") (f32.const 1.32))
+(assert_return (invoke "type-first-f64") (f64.const 1.64))
+
+(assert_return (invoke "type-second-i32") (i32.const 32))
+(assert_return (invoke "type-second-i64") (i64.const 64))
+(assert_return (invoke "type-second-f32") (f32.const 32))
+(assert_return (invoke "type-second-f64") (f64.const 64.1))
+
+(assert_return (invoke "fac" (i64.const 0)) (i64.const 1))
+(assert_return (invoke "fac" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fac" (i64.const 5)) (i64.const 120))
+(assert_return (invoke "fac" (i64.const 25)) (i64.const 7034535277573963776))
+(assert_return (invoke "fac-acc" (i64.const 0) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fac-acc" (i64.const 1) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fac-acc" (i64.const 5) (i64.const 1)) (i64.const 120))
+(assert_return
+  (invoke "fac-acc" (i64.const 25) (i64.const 1))
+  (i64.const 7034535277573963776)
+)
+
+(assert_return (invoke "fib" (i64.const 0)) (i64.const 1))
+(assert_return (invoke "fib" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fib" (i64.const 2)) (i64.const 2))
+(assert_return (invoke "fib" (i64.const 5)) (i64.const 8))
+(assert_return (invoke "fib" (i64.const 20)) (i64.const 10946))
+
+(assert_return (invoke "even" (i64.const 0)) (i32.const 44))
+(assert_return (invoke "even" (i64.const 1)) (i32.const 99))
+(assert_return (invoke "even" (i64.const 10)) (i32.const 44))
+(assert_return (invoke "even" (i64.const 7)) (i32.const 99))
+(assert_return (invoke "odd" (i64.const 0)) (i32.const 99))
+(assert_return (invoke "odd" (i64.const 1)) (i32.const 44))
+(assert_return (invoke "odd" (i64.const 20)) (i32.const 99))
+(assert_return (invoke "odd" (i64.const 7)) (i32.const 44))
+
+(assert_trap (invoke "runaway") "call stack exhausted")
+(assert_trap (invoke "mutual-runaway") "call stack exhausted")
+
+
+;; Invalid typing
+
+(assert_invalid
+  (module
+    (func $type-void-vs-num (i32.eqz (call 1)))
+    (func)
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-num-vs-num (i32.eqz (call 1)))
+    (func (result i64) (i64.const 1))
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (func $arity-0-vs-1 (call 1))
+    (func (param i32))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $arity-0-vs-2 (call 1))
+    (func (param f64 i32))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $arity-1-vs-0 (call 1 (i32.const 1)))
+    (func)
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $arity-2-vs-0 (call 1 (f64.const 2) (i32.const 1)))
+    (func)
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (func $type-first-void-vs-num (call 1 (nop) (i32.const 1)))
+    (func (param i32 i32))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-second-void-vs-num (call 1 (i32.const 1) (nop)))
+    (func (param i32 i32))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-first-num-vs-num (call 1 (f64.const 1) (i32.const 1)))
+    (func (param i32 f64))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-second-num-vs-num (call 1 (i32.const 1) (f64.const 1)))
+    (func (param f64 i32))
+  )
+  "type mismatch"
+)
+
+
+;; Unbound function
+
+(assert_invalid
+  (module (func $unbound-func (call 1)))
+  "unknown function"
+)
+(assert_invalid
+  (module (func $large-func (call 1012321300)))
+  "unknown function"
+)
diff --git a/binaryen/test/spec/old_call_indirect.wast b/binaryen/test/spec/old_call_indirect.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_call_indirect.wast
@@ -0,0 +1,362 @@
+;; Test `call_indirect` operator
+
+(module
+  ;; Auxiliary definitions
+  (type $proc (func))
+  (type $out-i32 (func (result i32)))
+  (type $out-i64 (func (result i64)))
+  (type $out-f32 (func (result f32)))
+  (type $out-f64 (func (result f64)))
+  (type $over-i32 (func (param i32) (result i32)))
+  (type $over-i64 (func (param i64) (result i64)))
+  (type $over-f32 (func (param f32) (result f32)))
+  (type $over-f64 (func (param f64) (result f64)))
+  (type $f32-i32 (func (param f32 i32) (result i32)))
+  (type $i32-i64 (func (param i32 i64) (result i64)))
+  (type $f64-f32 (func (param f64 f32) (result f32)))
+  (type $i64-f64 (func (param i64 f64) (result f64)))
+  (type $over-i32-duplicate (func (param i32) (result i32)))
+  (type $over-i64-duplicate (func (param i64) (result i64)))
+  (type $over-f32-duplicate (func (param f32) (result f32)))
+  (type $over-f64-duplicate (func (param f64) (result f64)))
+
+  (func $const-i32 (type $out-i32) (i32.const 0x132))
+  (func $const-i64 (type $out-i64) (i64.const 0x164))
+  (func $const-f32 (type $out-f32) (f32.const 0xf32))
+  (func $const-f64 (type $out-f64) (f64.const 0xf64))
+
+  (func $id-i32 (type $over-i32) (local.get 0))
+  (func $id-i64 (type $over-i64) (local.get 0))
+  (func $id-f32 (type $over-f32) (local.get 0))
+  (func $id-f64 (type $over-f64) (local.get 0))
+
+  (func $i32-i64 (type $i32-i64) (local.get 1))
+  (func $i64-f64 (type $i64-f64) (local.get 1))
+  (func $f32-i32 (type $f32-i32) (local.get 1))
+  (func $f64-f32 (type $f64-f32) (local.get 1))
+
+  (func $over-i32-duplicate (type $over-i32-duplicate) (local.get 0))
+  (func $over-i64-duplicate (type $over-i64-duplicate) (local.get 0))
+  (func $over-f32-duplicate (type $over-f32-duplicate) (local.get 0))
+  (func $over-f64-duplicate (type $over-f64-duplicate) (local.get 0))
+
+  (table funcref
+    (elem
+      $const-i32 $const-i64 $const-f32 $const-f64
+      $id-i32 $id-i64 $id-f32 $id-f64
+      $f32-i32 $i32-i64 $f64-f32 $i64-f64
+      $fac $fib $even $odd
+      $runaway $mutual-runaway1 $mutual-runaway2
+      $over-i32-duplicate $over-i64-duplicate
+      $over-f32-duplicate $over-f64-duplicate
+    )
+  )
+
+  ;; Typing
+
+  (func (export "type-i32") (result i32) (call_indirect (type $out-i32) (i32.const 0)))
+  (func (export "type-i64") (result i64) (call_indirect (type $out-i64) (i32.const 1)))
+  (func (export "type-f32") (result f32) (call_indirect (type $out-f32) (i32.const 2)))
+  (func (export "type-f64") (result f64) (call_indirect (type $out-f64) (i32.const 3)))
+
+  (func (export "type-index") (result i64)
+    (call_indirect (type $over-i64) (i64.const 100) (i32.const 5))
+  )
+
+  (func (export "type-first-i32") (result i32)
+    (call_indirect (type $over-i32) (i32.const 32) (i32.const 4))
+  )
+  (func (export "type-first-i64") (result i64)
+    (call_indirect (type $over-i64) (i64.const 64) (i32.const 5))
+  )
+  (func (export "type-first-f32") (result f32)
+    (call_indirect (type $over-f32) (f32.const 1.32) (i32.const 6))
+  )
+  (func (export "type-first-f64") (result f64)
+    (call_indirect (type $over-f64) (f64.const 1.64) (i32.const 7))
+  )
+
+  (func (export "type-second-i32") (result i32)
+    (call_indirect (type $f32-i32) (f32.const 32.1) (i32.const 32) (i32.const 8))
+  )
+  (func (export "type-second-i64") (result i64)
+    (call_indirect (type $i32-i64) (i32.const 32) (i64.const 64) (i32.const 9))
+  )
+  (func (export "type-second-f32") (result f32)
+    (call_indirect (type $f64-f32) (f64.const 64) (f32.const 32) (i32.const 10))
+  )
+  (func (export "type-second-f64") (result f64)
+    (call_indirect (type $i64-f64) (i64.const 64) (f64.const 64.1) (i32.const 11))
+  )
+
+  ;; Dispatch
+
+  (func (export "dispatch") (param i32 i64) (result i64)
+    (call_indirect (type $over-i64) (local.get 1) (local.get 0))
+  )
+
+  (func (export "dispatch-structural") (param i32) (result i64)
+    (call_indirect (type $over-i64-duplicate) (i64.const 9) (local.get 0))
+  )
+
+  ;; Recursion
+
+  (func $fac (export "fac") (type $over-i64)
+    (if i64 (i64.eqz (local.get 0))
+      (i64.const 1)
+      (i64.mul
+        (local.get 0)
+        (call_indirect (type $over-i64)
+          (i64.sub (local.get 0) (i64.const 1))
+          (i32.const 12)
+        )
+      )
+    )
+  )
+
+  (func $fib (export "fib") (type $over-i64)
+    (if i64 (i64.le_u (local.get 0) (i64.const 1))
+      (i64.const 1)
+      (i64.add
+        (call_indirect (type $over-i64)
+          (i64.sub (local.get 0) (i64.const 2))
+          (i32.const 13)
+        )
+        (call_indirect (type $over-i64)
+          (i64.sub (local.get 0) (i64.const 1))
+          (i32.const 13)
+        )
+      )
+    )
+  )
+
+  (func $even (export "even") (param i32) (result i32)
+    (if i32 (i32.eqz (local.get 0))
+      (i32.const 44)
+      (call_indirect (type $over-i32)
+        (i32.sub (local.get 0) (i32.const 1))
+        (i32.const 15)
+      )
+    )
+  )
+  (func $odd (export "odd") (param i32) (result i32)
+    (if i32 (i32.eqz (local.get 0))
+      (i32.const 99)
+      (call_indirect (type $over-i32)
+        (i32.sub (local.get 0) (i32.const 1))
+        (i32.const 14)
+      )
+    )
+  )
+
+  ;; Stack exhaustion
+
+  ;; Implementations are required to have every call consume some abstract
+  ;; resource towards exhausting some abstract finite limit, such that
+  ;; infinitely recursive test cases reliably trap in finite time. This is
+  ;; because otherwise applications could come to depend on it on those
+  ;; implementations and be incompatible with implementations that don't do
+  ;; it (or don't do it under the same circumstances).
+
+  (func $runaway (export "runaway") (call_indirect (type $proc) (i32.const 16)))
+
+  (func $mutual-runaway1 (export "mutual-runaway") (call_indirect (type $proc) (i32.const 18)))
+  (func $mutual-runaway2 (call_indirect (type $proc) (i32.const 17)))
+)
+
+(assert_return (invoke "type-i32") (i32.const 0x132))
+(assert_return (invoke "type-i64") (i64.const 0x164))
+(assert_return (invoke "type-f32") (f32.const 0xf32))
+(assert_return (invoke "type-f64") (f64.const 0xf64))
+
+(assert_return (invoke "type-index") (i64.const 100))
+
+(assert_return (invoke "type-first-i32") (i32.const 32))
+(assert_return (invoke "type-first-i64") (i64.const 64))
+(assert_return (invoke "type-first-f32") (f32.const 1.32))
+(assert_return (invoke "type-first-f64") (f64.const 1.64))
+
+(assert_return (invoke "type-second-i32") (i32.const 32))
+(assert_return (invoke "type-second-i64") (i64.const 64))
+(assert_return (invoke "type-second-f32") (f32.const 32))
+(assert_return (invoke "type-second-f64") (f64.const 64.1))
+
+(assert_return (invoke "dispatch" (i32.const 5) (i64.const 2)) (i64.const 2))
+(assert_return (invoke "dispatch" (i32.const 5) (i64.const 5)) (i64.const 5))
+(assert_return (invoke "dispatch" (i32.const 12) (i64.const 5)) (i64.const 120))
+(assert_return (invoke "dispatch" (i32.const 13) (i64.const 5)) (i64.const 8))
+(assert_return (invoke "dispatch" (i32.const 20) (i64.const 2)) (i64.const 2))
+(assert_trap (invoke "dispatch" (i32.const 0) (i64.const 2)) "indirect call signature mismatch")
+(assert_trap (invoke "dispatch" (i32.const 15) (i64.const 2)) "indirect call signature mismatch")
+(assert_trap (invoke "dispatch" (i32.const 23) (i64.const 2)) "undefined element")
+(assert_trap (invoke "dispatch" (i32.const -1) (i64.const 2)) "undefined element")
+(assert_trap (invoke "dispatch" (i32.const 1213432423) (i64.const 2)) "undefined element")
+
+(assert_return (invoke "dispatch-structural" (i32.const 5)) (i64.const 9))
+(assert_return (invoke "dispatch-structural" (i32.const 5)) (i64.const 9))
+(assert_return (invoke "dispatch-structural" (i32.const 12)) (i64.const 362880))
+(assert_return (invoke "dispatch-structural" (i32.const 20)) (i64.const 9))
+(assert_trap (invoke "dispatch-structural" (i32.const 11)) "indirect call signature mismatch")
+(assert_trap (invoke "dispatch-structural" (i32.const 22)) "indirect call signature mismatch")
+
+(assert_return (invoke "fac" (i64.const 0)) (i64.const 1))
+(assert_return (invoke "fac" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fac" (i64.const 5)) (i64.const 120))
+(assert_return (invoke "fac" (i64.const 25)) (i64.const 7034535277573963776))
+
+(assert_return (invoke "fib" (i64.const 0)) (i64.const 1))
+(assert_return (invoke "fib" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fib" (i64.const 2)) (i64.const 2))
+(assert_return (invoke "fib" (i64.const 5)) (i64.const 8))
+(assert_return (invoke "fib" (i64.const 20)) (i64.const 10946))
+
+(assert_return (invoke "even" (i32.const 0)) (i32.const 44))
+(assert_return (invoke "even" (i32.const 1)) (i32.const 99))
+(assert_return (invoke "even" (i32.const 10)) (i32.const 44))
+(assert_return (invoke "even" (i32.const 7)) (i32.const 99))
+(assert_return (invoke "odd" (i32.const 0)) (i32.const 99))
+(assert_return (invoke "odd" (i32.const 1)) (i32.const 44))
+(assert_return (invoke "odd" (i32.const 20)) (i32.const 99))
+(assert_return (invoke "odd" (i32.const 7)) (i32.const 44))
+
+(assert_trap (invoke "runaway") "call stack exhausted")
+(assert_trap (invoke "mutual-runaway") "call stack exhausted")
+
+
+;; Invalid typing
+
+(assert_invalid
+  (module
+    (type (func))
+    (func $no-table (call_indirect (type 0) (i32.const 0)))
+  )
+  "unknown table"
+)
+
+(assert_invalid
+  (module
+    (type (func))
+    (table 0 funcref)
+    (func $type-void-vs-num (i32.eqz (call_indirect (type 0) (i32.const 0))))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func (result i64)))
+    (table 0 funcref)
+    (func $type-num-vs-num (i32.eqz (call_indirect (type 0) (i32.const 0))))
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (type (func (param i32)))
+    (table 0 funcref)
+    (func $arity-0-vs-1 (call_indirect (type 0) (i32.const 0)))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func (param f64 i32)))
+    (table 0 funcref)
+    (func $arity-0-vs-2 (call_indirect (type 0) (i32.const 0)))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func))
+    (table 0 funcref)
+    (func $arity-1-vs-0 (call_indirect (type 0) (i32.const 1) (i32.const 0)))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func))
+    (table 0 funcref)
+    (func $arity-2-vs-0
+      (call_indirect (type 0) (f64.const 2) (i32.const 1) (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (type (func (param i32)))
+    (table 0 funcref)
+    (func $type-func-void-vs-i32 (call_indirect (type 0) (i32.const 1) (nop)))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func (param i32)))
+    (table 0 funcref)
+    (func $type-func-num-vs-i32 (call_indirect (type 0) (i32.const 0) (i64.const 1)))
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (type (func (param i32 i32)))
+    (table 0 funcref)
+    (func $type-first-void-vs-num
+      (call_indirect (type 0) (nop) (i32.const 1) (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func (param i32 i32)))
+    (table 0 funcref)
+    (func $type-second-void-vs-num
+      (call_indirect (type 0) (i32.const 1) (nop) (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func (param i32 f64)))
+    (table 0 funcref)
+    (func $type-first-num-vs-num
+      (call_indirect (type 0) (f64.const 1) (i32.const 1) (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (type (func (param f64 i32)))
+    (table 0 funcref)
+    (func $type-second-num-vs-num
+      (call_indirect (type 0) (i32.const 1) (f64.const 1) (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
+
+
+;; Unbound type
+
+(assert_invalid
+  (module
+    (table 0 funcref)
+    (func $unbound-type (call_indirect (type 1) (i32.const 0)))
+  )
+  "unknown type"
+)
+(assert_invalid
+  (module
+    (table 0 funcref)
+    (func $large-type (call_indirect (type 1012321300) (i32.const 0)))
+  )
+  "unknown type"
+)
diff --git a/binaryen/test/spec/old_exports.wast b/binaryen/test/spec/old_exports.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_exports.wast
@@ -0,0 +1,172 @@
+;; Functions
+
+(module (func) (export "a" (func 0)))
+(module (func) (export "a" (func 0)) (export "b" (func 0)))
+(module (func) (func) (export "a" (func 0)) (export "b" (func 1)))
+
+(module (func (export "a")))
+(module (func $a (export "a")))
+
+(module $Func
+  (export "e" (func $f))
+  (func $f (param $n i32) (result i32)
+    (return (i32.add (local.get $n) (i32.const 1)))
+  )
+)
+(assert_return (invoke "e" (i32.const 42)) (i32.const 43))
+(assert_return (invoke $Func "e" (i32.const 42)) (i32.const 43))
+(module)
+(module $Other1)
+(assert_return (invoke $Func "e" (i32.const 42)) (i32.const 43))
+
+(assert_invalid
+  (module (func) (export "a" (func 1)))
+  "unknown function"
+)
+(assert_invalid
+  (module (func) (export "a" (func 0)) (export "a" (func 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (func) (func) (export "a" (func 0)) (export "a" (func 1)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (func) (global i32 (i32.const 0)) (export "a" (func 0)) (export "a" (global 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (func) (table 0 funcref) (export "a" (func 0)) (export "a" (table 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (func) (memory 0) (export "a" (func 0)) (export "a" (memory 0)))
+  "duplicate export name"
+)
+
+
+;; Globals
+
+(module (global i32 (i32.const 0)) (export "a" (global 0)))
+(module (global i32 (i32.const 0)) (export "a" (global 0)) (export "b" (global 0)))
+(module (global i32 (i32.const 0)) (global i32 (i32.const 0)) (export "a" (global 0)) (export "b" (global 1)))
+
+(module (global (export "a") i32 (i32.const 0)))
+(module (global $a (export "a") i32 (i32.const 0)))
+
+(module $Global
+  (export "e" (global $g))
+  (global $g i32 (i32.const 42))
+)
+(assert_return (get "e") (i32.const 42))
+(assert_return (get $Global "e") (i32.const 42))
+(module)
+(module $Other2)
+(assert_return (get $Global "e") (i32.const 42))
+
+(assert_invalid
+  (module (global i32 (i32.const 0)) (export "a" (global 1)))
+  "unknown global"
+)
+(assert_invalid
+  (module (global i32 (i32.const 0)) (export "a" (global 0)) (export "a" (global 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (global i32 (i32.const 0)) (global i32 (i32.const 0)) (export "a" (global 0)) (export "a" (global 1)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (global i32 (i32.const 0)) (func) (export "a" (global 0)) (export "a" (func 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (global i32 (i32.const 0)) (table 0 funcref) (export "a" (global 0)) (export "a" (table 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (global i32 (i32.const 0)) (memory 0) (export "a" (global 0)) (export "a" (memory 0)))
+  "duplicate export name"
+)
+
+
+;; Tables
+
+(module (table 0 funcref) (export "a" (table 0)))
+(module (table 0 funcref) (export "a" (table 0)) (export "b" (table 0)))
+;; No multiple tables yet.
+;; (module (table 0 funcref) (table 0 funcref) (export "a" (table 0)) (export "b" (table 1)))
+
+(module (table (export "a") 0 funcref))
+(module (table (export "a") 0 1 funcref))
+(module (table $a (export "a") 0 funcref))
+(module (table $a (export "a") 0 1 funcref))
+
+(; TODO: access table ;)
+
+(assert_invalid
+  (module (table 0 funcref) (export "a" (table 1)))
+  "unknown table"
+)
+(assert_invalid
+  (module (table 0 funcref) (export "a" (table 0)) (export "a" (table 0)))
+  "duplicate export name"
+)
+;; No multiple tables yet.
+;; (assert_invalid
+;;   (module (table 0 funcref) (table 0 funcref) (export "a" (table 0)) (export "a" (table 1)))
+;;   "duplicate export name"
+;; )
+(assert_invalid
+  (module (table 0 funcref) (func) (export "a" (table 0)) (export "a" (func 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (table 0 funcref) (global i32 (i32.const 0)) (export "a" (table 0)) (export "a" (global 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (table 0 funcref) (memory 0) (export "a" (table 0)) (export "a" (memory 0)))
+  "duplicate export name"
+)
+
+
+;; Memories
+
+(module (memory 0) (export "a" (memory 0)))
+(module (memory 0) (export "a" (memory 0)) (export "b" (memory 0)))
+;; No multiple memories yet.
+;; (module (memory 0) (memory 0) (export "a" (memory 0)) (export "b" (memory 1)))
+
+(module (memory (export "a") 0))
+(module (memory (export "a") 0 1))
+(module (memory $a (export "a") 0))
+(module (memory $a (export "a") 0 1))
+
+(; TODO: access memory ;)
+
+(assert_invalid
+  (module (memory 0) (export "a" (memory 1)))
+  "unknown memory"
+)
+(assert_invalid
+  (module (memory 0) (export "a" (memory 0)) (export "a" (memory 0)))
+  "duplicate export name"
+)
+;; No multiple memories yet.
+;; (assert_invalid
+;;   (module (memory 0) (memory 0) (export "a" (memory 0)) (export "a" (memory 1)))
+;;   "duplicate export name"
+;; )
+(assert_invalid
+  (module (memory 0) (func) (export "a" (memory 0)) (export "a" (func 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (memory 0) (global i32 (i32.const 0)) (export "a" (memory 0)) (export "a" (global 0)))
+  "duplicate export name"
+)
+(assert_invalid
+  (module (memory 0) (table 0 funcref) (export "a" (memory 0)) (export "a" (table 0)))
+  "duplicate export name"
+)
diff --git a/binaryen/test/spec/old_float_exprs.wast b/binaryen/test/spec/old_float_exprs.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_float_exprs.wast
@@ -0,0 +1,1979 @@
+;; Test interesting floating-point "expressions". These tests contain code
+;; patterns which tempt common value-changing optimizations.
+
+;; Test that x*y+z is not done with x87-style intermediate precision.
+
+(module
+  (func (export "f64.no_contraction") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.add (f64.mul (local.get $x) (local.get $y)) (local.get $z)))
+)
+
+(assert_return (invoke "f64.no_contraction" (f64.const -0x1.9e87ce14273afp-103) (f64.const 0x1.2515ad31db63ep+664) (f64.const 0x1.868c6685e6185p+533)) (f64.const -0x1.da94885b11493p+561))
+(assert_return (invoke "f64.no_contraction" (f64.const 0x1.da21c460a6f44p+52) (f64.const 0x1.60859d2e7714ap-321) (f64.const 0x1.e63f1b7b660e1p-302)) (f64.const 0x1.4672f256d1794p-268))
+(assert_return (invoke "f64.no_contraction" (f64.const -0x1.f3eaf43f327cp-594) (f64.const 0x1.dfcc009906b57p+533) (f64.const 0x1.5984e03c520a1p-104)) (f64.const -0x1.d4797fb3db166p-60))
+(assert_return (invoke "f64.no_contraction" (f64.const 0x1.dab6c772cb2e2p-69) (f64.const -0x1.d761663679a84p-101) (f64.const 0x1.f22f92c843226p-218)) (f64.const -0x1.b50d72dfcef68p-169))
+(assert_return (invoke "f64.no_contraction" (f64.const -0x1.87c5def1e4d3dp-950) (f64.const -0x1.50cd5dab2207fp+935) (f64.const 0x1.e629bd0da8c5dp-54)) (f64.const 0x1.01b6feb4e78a7p-14))
+
+;; Test that x*y+z is not folded to fma.
+
+(module
+  (func (export "f32.no_fma") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.add (f32.mul (local.get $x) (local.get $y)) (local.get $z)))
+  (func (export "f64.no_fma") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.add (f64.mul (local.get $x) (local.get $y)) (local.get $z)))
+)
+
+(assert_return (invoke "f32.no_fma" (f32.const 0x1.a78402p+124) (f32.const 0x1.cf8548p-23) (f32.const 0x1.992adap+107)) (f32.const 0x1.a5262cp+107))
+(assert_return (invoke "f32.no_fma" (f32.const 0x1.ed15a4p-28) (f32.const -0x1.613c72p-50) (f32.const 0x1.4757bp-88)) (f32.const -0x1.5406b8p-77))
+(assert_return (invoke "f32.no_fma" (f32.const 0x1.ae63a2p+37) (f32.const 0x1.b3a59ap-13) (f32.const 0x1.c16918p+10)) (f32.const 0x1.6e385cp+25))
+(assert_return (invoke "f32.no_fma" (f32.const 0x1.2a77fap-8) (f32.const -0x1.bb7356p+22) (f32.const -0x1.32be2ap+1)) (f32.const -0x1.0286d4p+15))
+(assert_return (invoke "f32.no_fma" (f32.const 0x1.298fb6p+126) (f32.const -0x1.03080cp-70) (f32.const -0x1.418de6p+34)) (f32.const -0x1.2d15c6p+56))
+(assert_return (invoke "f64.no_fma" (f64.const 0x1.ac357ff46eed4p+557) (f64.const 0x1.852c01a5e7297p+430) (f64.const -0x1.05995704eda8ap+987)) (f64.const 0x1.855d905d338ep+987))
+(assert_return (invoke "f64.no_fma" (f64.const 0x1.e2fd6bf32010cp+749) (f64.const 0x1.01c2238d405e4p-130) (f64.const 0x1.2ecc0db4b9f94p+573)) (f64.const 0x1.e64eb07e063bcp+619))
+(assert_return (invoke "f64.no_fma" (f64.const 0x1.92b7c7439ede3p-721) (f64.const -0x1.6aa97586d3de6p+1011) (f64.const 0x1.8de4823f6358ap+237)) (f64.const -0x1.1d4139fd20ecdp+291))
+(assert_return (invoke "f64.no_fma" (f64.const -0x1.466d30bddb453p-386) (f64.const -0x1.185a4d739c7aap+443) (f64.const 0x1.5f9c436fbfc7bp+55)) (f64.const 0x1.bd61a350fcc1ap+57))
+(assert_return (invoke "f64.no_fma" (f64.const 0x1.7e2c44058a799p+52) (f64.const 0x1.c73b71765b8b2p+685) (f64.const -0x1.16c641df0b108p+690)) (f64.const 0x1.53ccb53de0bd1p+738))
+
+;; Test that x+0.0 is not folded to x.
+;; See IEEE 754-2008 10.4 "Literal meaning and value-changing optimizations".
+
+(module
+  (func (export "f32.no_fold_add_zero") (param $x f32) (result f32)
+    (f32.add (local.get $x) (f32.const 0.0)))
+  (func (export "f64.no_fold_add_zero") (param $x f64) (result f64)
+    (f64.add (local.get $x) (f64.const 0.0)))
+)
+
+(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))
+
+;; Test that 0.0 - x is not folded to -x.
+
+(module
+  (func (export "f32.no_fold_zero_sub") (param $x f32) (result f32)
+    (f32.sub (f32.const 0.0) (local.get $x)))
+  (func (export "f64.no_fold_zero_sub") (param $x f64) (result f64)
+    (f64.sub (f64.const 0.0) (local.get $x)))
+)
+
+(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))
+
+;; Test that x - 0.0 is not folded to x.
+
+(module
+  (func (export "f32.no_fold_sub_zero") (param $x f32) (result f32)
+    (f32.sub (local.get $x) (f32.const 0.0)))
+  (func (export "f64.no_fold_sub_zero") (param $x f64) (result f64)
+    (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))
+
+;; Test that x*0.0 is not folded to 0.0.
+
+(module
+  (func (export "f32.no_fold_mul_zero") (param $x f32) (result f32)
+    (f32.mul (local.get $x) (f32.const 0.0)))
+  (func (export "f64.no_fold_mul_zero") (param $x f64) (result f64)
+    (f64.mul (local.get $x) (f64.const 0.0)))
+)
+
+(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 "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))
+
+;; Test that x*1.0 is not folded to x.
+;; See IEEE 754-2008 10.4 "Literal meaning and value-changing optimizations".
+
+(module
+  (func (export "f32.no_fold_mul_one") (param $x f32) (result f32)
+    (f32.mul (local.get $x) (f32.const 1.0)))
+  (func (export "f64.no_fold_mul_one") (param $x f64) (result f64)
+    (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))
+
+;; Test that 0.0/x is not folded to 0.0.
+
+(module
+  (func (export "f32.no_fold_zero_div") (param $x f32) (result f32)
+    (f32.div (f32.const 0.0) (local.get $x)))
+  (func (export "f64.no_fold_zero_div") (param $x f64) (result f64)
+    (f64.div (f64.const 0.0) (local.get $x)))
+)
+
+(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_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))
+
+;; Test that x/1.0 is not folded to x.
+
+(module
+  (func (export "f32.no_fold_div_one") (param $x f32) (result f32)
+    (f32.div (local.get $x) (f32.const 1.0)))
+  (func (export "f64.no_fold_div_one") (param $x f64) (result f64)
+    (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))
+
+;; Test that x/-1.0 is not folded to -x.
+
+(module
+  (func (export "f32.no_fold_div_neg1") (param $x f32) (result f32)
+    (f32.div (local.get $x) (f32.const -1.0)))
+  (func (export "f64.no_fold_div_neg1") (param $x f64) (result f64)
+    (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))
+
+;; Test that -0.0 - x is not folded to -x.
+
+(module
+  (func (export "f32.no_fold_neg0_sub") (param $x f32) (result f32)
+    (f32.sub (f32.const -0.0) (local.get $x)))
+  (func (export "f64.no_fold_neg0_sub") (param $x f64) (result f64)
+    (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))
+
+;; Test that -1.0 * x is not folded to -x.
+
+(module
+  (func (export "f32.no_fold_neg1_mul") (param $x f32) (result f32)
+    (f32.mul (f32.const -1.0) (local.get $x)))
+  (func (export "f64.no_fold_neg1_mul") (param $x f64) (result f64)
+    (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))
+
+;; Test that x == x is not folded to true.
+
+(module
+  (func (export "f32.no_fold_eq_self") (param $x f32) (result i32)
+    (f32.eq (local.get $x) (local.get $x)))
+  (func (export "f64.no_fold_eq_self") (param $x f64) (result i32)
+    (f64.eq (local.get $x) (local.get $x)))
+)
+
+(assert_return (invoke "f32.no_fold_eq_self" (f32.const nan)) (i32.const 0))
+(assert_return (invoke "f64.no_fold_eq_self" (f64.const nan)) (i32.const 0))
+
+;; Test that x != x is not folded to false.
+
+(module
+  (func (export "f32.no_fold_ne_self") (param $x f32) (result i32)
+    (f32.ne (local.get $x) (local.get $x)))
+  (func (export "f64.no_fold_ne_self") (param $x f64) (result i32)
+    (f64.ne (local.get $x) (local.get $x)))
+)
+
+(assert_return (invoke "f32.no_fold_ne_self" (f32.const nan)) (i32.const 1))
+(assert_return (invoke "f64.no_fold_ne_self" (f64.const nan)) (i32.const 1))
+
+;; Test that x - x is not folded to 0.0.
+
+(module
+  (func (export "f32.no_fold_sub_self") (param $x f32) (result f32)
+    (f32.sub (local.get $x) (local.get $x)))
+  (func (export "f64.no_fold_sub_self") (param $x f64) (result f64)
+    (f64.sub (local.get $x) (local.get $x)))
+)
+
+(assert_return_nan (invoke "f32.no_fold_sub_self" (f32.const infinity)))
+(assert_return (invoke "f32.no_fold_sub_self" (f32.const nan)) (f32.const nan))
+(assert_return_nan (invoke "f64.no_fold_sub_self" (f64.const infinity)))
+(assert_return (invoke "f64.no_fold_sub_self" (f64.const nan)) (f64.const nan))
+
+;; Test that x/3 is not folded to x*(1/3).
+
+(module
+  (func (export "f32.no_fold_div_3") (param $x f32) (result f32)
+    (f32.div (local.get $x) (f32.const 3.0)))
+  (func (export "f64.no_fold_div_3") (param $x f64) (result f64)
+    (f64.div (local.get $x) (f64.const 3.0)))
+)
+
+(assert_return (invoke "f32.no_fold_div_3" (f32.const -0x1.359c26p+50)) (f32.const -0x1.9cd032p+48))
+(assert_return (invoke "f32.no_fold_div_3" (f32.const -0x1.e45646p+93)) (f32.const -0x1.42e42ep+92))
+(assert_return (invoke "f32.no_fold_div_3" (f32.const -0x1.2a3916p-83)) (f32.const -0x1.8da172p-85))
+(assert_return (invoke "f32.no_fold_div_3" (f32.const -0x1.1f8b38p-124)) (f32.const -0x1.7f644ap-126))
+(assert_return (invoke "f32.no_fold_div_3" (f32.const -0x1.d64f64p-56)) (f32.const -0x1.398a42p-57))
+(assert_return (invoke "f64.no_fold_div_3" (f64.const -0x1.a8a88d29e2cc3p+632)) (f64.const -0x1.1b1b08c69732dp+631))
+(assert_return (invoke "f64.no_fold_div_3" (f64.const -0x1.bcf52dc950972p-167)) (f64.const -0x1.28a373db8b0f7p-168))
+(assert_return (invoke "f64.no_fold_div_3" (f64.const 0x1.bd3c0d989f7a4p-874)) (f64.const 0x1.28d2b3bb14fc3p-875))
+(assert_return (invoke "f64.no_fold_div_3" (f64.const -0x1.0138bf530a53cp+1007)) (f64.const -0x1.56f6546eb86fbp+1005))
+(assert_return (invoke "f64.no_fold_div_3" (f64.const 0x1.052b87f9d794dp+415)) (f64.const 0x1.5c3a0aa274c67p+413))
+
+;; Test that (x*z)+(y*z) is not folded to (x+y)*z
+
+(module
+  (func (export "f32.no_factor") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.add (f32.mul (local.get $x) (local.get $z)) (f32.mul (local.get $y) (local.get $z))))
+  (func (export "f64.no_factor") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.add (f64.mul (local.get $x) (local.get $z)) (f64.mul (local.get $y) (local.get $z))))
+)
+
+(assert_return (invoke "f32.no_factor" (f32.const -0x1.4e2352p+40) (f32.const -0x1.842e2cp+49) (f32.const 0x1.eea602p+59)) (f32.const -0x1.77a7dp+109))
+(assert_return (invoke "f32.no_factor" (f32.const -0x1.b4e7f6p-6) (f32.const 0x1.8c990cp-5) (f32.const -0x1.70cc02p-9)) (f32.const -0x1.00a342p-14))
+(assert_return (invoke "f32.no_factor" (f32.const -0x1.06722ep-41) (f32.const 0x1.eed3cep-64) (f32.const 0x1.5c5558p+123)) (f32.const -0x1.651aaep+82))
+(assert_return (invoke "f32.no_factor" (f32.const -0x1.f8c6a4p-64) (f32.const 0x1.08c806p-83) (f32.const 0x1.b5ceccp+118)) (f32.const -0x1.afa15p+55))
+(assert_return (invoke "f32.no_factor" (f32.const -0x1.3aaa1ep-84) (f32.const 0x1.c6d5eep-71) (f32.const 0x1.8d2924p+20)) (f32.const 0x1.60c9cep-50))
+(assert_return (invoke "f64.no_factor" (f64.const 0x1.3adeda9144977p-424) (f64.const 0x1.c15af887049e1p-462) (f64.const -0x1.905179c4c4778p-225)) (f64.const -0x1.ec606bcb87b1ap-649))
+(assert_return (invoke "f64.no_factor" (f64.const 0x1.3c84821c1d348p-662) (f64.const -0x1.4ffd4c77ad037p-1009) (f64.const -0x1.dd275335c6f4p-957)) (f64.const 0x0p+0))
+(assert_return (invoke "f64.no_factor" (f64.const -0x1.074f372347051p-334) (f64.const -0x1.aaeef661f4c96p-282) (f64.const -0x1.9bd34abe8696dp+479)) (f64.const 0x1.5767029593e2p+198))
+(assert_return (invoke "f64.no_factor" (f64.const -0x1.c4ded58a6f389p-289) (f64.const 0x1.ba6fdef5d59c9p-260) (f64.const -0x1.c1201c0470205p-253)) (f64.const -0x1.841ada2e0f184p-512))
+(assert_return (invoke "f64.no_factor" (f64.const 0x1.9d3688f8e375ap-608) (f64.const 0x1.bf91311588256p-579) (f64.const -0x1.1605a6b5d5ff8p+489)) (f64.const -0x1.e6118ca76af53p-90))
+
+;; Test that (x+y)*z is not folded to (x*z)+(y*z)
+
+(module
+  (func (export "f32.no_distribute") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.mul (f32.add (local.get $x) (local.get $y)) (local.get $z)))
+  (func (export "f64.no_distribute") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.mul (f64.add (local.get $x) (local.get $y)) (local.get $z)))
+)
+
+(assert_return (invoke "f32.no_distribute" (f32.const -0x1.4e2352p+40) (f32.const -0x1.842e2cp+49) (f32.const 0x1.eea602p+59)) (f32.const -0x1.77a7d2p+109))
+(assert_return (invoke "f32.no_distribute" (f32.const -0x1.b4e7f6p-6) (f32.const 0x1.8c990cp-5) (f32.const -0x1.70cc02p-9)) (f32.const -0x1.00a34p-14))
+(assert_return (invoke "f32.no_distribute" (f32.const -0x1.06722ep-41) (f32.const 0x1.eed3cep-64) (f32.const 0x1.5c5558p+123)) (f32.const -0x1.651abp+82))
+(assert_return (invoke "f32.no_distribute" (f32.const -0x1.f8c6a4p-64) (f32.const 0x1.08c806p-83) (f32.const 0x1.b5ceccp+118)) (f32.const -0x1.afa14ep+55))
+(assert_return (invoke "f32.no_distribute" (f32.const -0x1.3aaa1ep-84) (f32.const 0x1.c6d5eep-71) (f32.const 0x1.8d2924p+20)) (f32.const 0x1.60c9ccp-50))
+(assert_return (invoke "f64.no_distribute" (f64.const 0x1.3adeda9144977p-424) (f64.const 0x1.c15af887049e1p-462) (f64.const -0x1.905179c4c4778p-225)) (f64.const -0x1.ec606bcb87b1bp-649))
+(assert_return (invoke "f64.no_distribute" (f64.const 0x1.3c84821c1d348p-662) (f64.const -0x1.4ffd4c77ad037p-1009) (f64.const -0x1.dd275335c6f4p-957)) (f64.const -0x0p+0))
+(assert_return (invoke "f64.no_distribute" (f64.const -0x1.074f372347051p-334) (f64.const -0x1.aaeef661f4c96p-282) (f64.const -0x1.9bd34abe8696dp+479)) (f64.const 0x1.5767029593e1fp+198))
+(assert_return (invoke "f64.no_distribute" (f64.const -0x1.c4ded58a6f389p-289) (f64.const 0x1.ba6fdef5d59c9p-260) (f64.const -0x1.c1201c0470205p-253)) (f64.const -0x1.841ada2e0f183p-512))
+(assert_return (invoke "f64.no_distribute" (f64.const 0x1.9d3688f8e375ap-608) (f64.const 0x1.bf91311588256p-579) (f64.const -0x1.1605a6b5d5ff8p+489)) (f64.const -0x1.e6118ca76af52p-90))
+
+;; Test that x*(y/z) is not folded to (x*y)/z
+
+(module
+  (func (export "f32.no_regroup_div_mul") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.mul (local.get $x) (f32.div (local.get $y) (local.get $z))))
+  (func (export "f64.no_regroup_div_mul") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.mul (local.get $x) (f64.div (local.get $y) (local.get $z))))
+)
+
+(assert_return (invoke "f32.no_regroup_div_mul" (f32.const -0x1.2d14a6p-115) (f32.const -0x1.575a6cp-64) (f32.const 0x1.5cee0ep-116)) (f32.const 0x1.2844cap-63))
+(assert_return (invoke "f32.no_regroup_div_mul" (f32.const -0x1.454738p+91) (f32.const -0x1.b28a66p-115) (f32.const -0x1.f53908p+72)) (f32.const -0x0p+0))
+(assert_return (invoke "f32.no_regroup_div_mul" (f32.const -0x1.6be56ep+16) (f32.const -0x1.b46fc6p-21) (f32.const -0x1.a51df6p-123)) (f32.const -0x1.792258p+118))
+(assert_return (invoke "f32.no_regroup_div_mul" (f32.const -0x1.c343f8p-94) (f32.const 0x1.e4d906p+73) (f32.const 0x1.be69f8p+68)) (f32.const -0x1.ea1df2p-89))
+(assert_return (invoke "f32.no_regroup_div_mul" (f32.const 0x1.c6ae76p+112) (f32.const 0x1.fc953cp+24) (f32.const -0x1.60b3e8p+71)) (f32.const -0x1.47d0eap+66))
+(assert_return (invoke "f64.no_regroup_div_mul" (f64.const 0x1.3c04b815e30bp-423) (f64.const -0x1.379646fd98127p-119) (f64.const 0x1.bddb158506031p-642)) (f64.const -0x1.b9b3301f2dd2dp+99))
+(assert_return (invoke "f64.no_regroup_div_mul" (f64.const 0x1.46b3a402f86d5p+337) (f64.const 0x1.6fbf1b9e1798dp-447) (f64.const -0x1.bd9704a5a6a06p+797)) (f64.const -0x0p+0))
+(assert_return (invoke "f64.no_regroup_div_mul" (f64.const 0x1.6c9765bb4347fp-479) (f64.const 0x1.a4af42e34a141p+902) (f64.const 0x1.d2dde70eb68f9p-448)) (f64.const infinity))
+(assert_return (invoke "f64.no_regroup_div_mul" (f64.const -0x1.706023645be72p+480) (f64.const -0x1.6c229f7d9101dp+611) (f64.const -0x1.4d50fa68d3d9ep+836)) (f64.const -0x1.926fa3cacc651p+255))
+(assert_return (invoke "f64.no_regroup_div_mul" (f64.const 0x1.8cc63d8caf4c7p-599) (f64.const 0x1.8671ac4c35753p-878) (f64.const -0x1.ef35b1695e659p-838)) (f64.const -0x1.38d55f56406dp-639))
+
+;; Test that (x*y)/z is not folded to x*(y/z)
+
+(module
+  (func (export "f32.no_regroup_mul_div") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.div (f32.mul (local.get $x) (local.get $y)) (local.get $z)))
+  (func (export "f64.no_regroup_mul_div") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.div (f64.mul (local.get $x) (local.get $y)) (local.get $z)))
+)
+
+(assert_return (invoke "f32.no_regroup_mul_div" (f32.const -0x1.2d14a6p-115) (f32.const -0x1.575a6cp-64) (f32.const 0x1.5cee0ep-116)) (f32.const 0x0p+0))
+(assert_return (invoke "f32.no_regroup_mul_div" (f32.const -0x1.454738p+91) (f32.const -0x1.b28a66p-115) (f32.const -0x1.f53908p+72)) (f32.const -0x1.1a00e8p-96))
+(assert_return (invoke "f32.no_regroup_mul_div" (f32.const -0x1.6be56ep+16) (f32.const -0x1.b46fc6p-21) (f32.const -0x1.a51df6p-123)) (f32.const -0x1.79225ap+118))
+(assert_return (invoke "f32.no_regroup_mul_div" (f32.const -0x1.c343f8p-94) (f32.const 0x1.e4d906p+73) (f32.const 0x1.be69f8p+68)) (f32.const -0x1.ea1df4p-89))
+(assert_return (invoke "f32.no_regroup_mul_div" (f32.const 0x1.c6ae76p+112) (f32.const 0x1.fc953cp+24) (f32.const -0x1.60b3e8p+71)) (f32.const -infinity))
+(assert_return (invoke "f64.no_regroup_mul_div" (f64.const 0x1.3c04b815e30bp-423) (f64.const -0x1.379646fd98127p-119) (f64.const 0x1.bddb158506031p-642)) (f64.const -0x1.b9b3301f2dd2ep+99))
+(assert_return (invoke "f64.no_regroup_mul_div" (f64.const 0x1.46b3a402f86d5p+337) (f64.const 0x1.6fbf1b9e1798dp-447) (f64.const -0x1.bd9704a5a6a06p+797)) (f64.const -0x1.0da0b6328e09p-907))
+(assert_return (invoke "f64.no_regroup_mul_div" (f64.const 0x1.6c9765bb4347fp-479) (f64.const 0x1.a4af42e34a141p+902) (f64.const 0x1.d2dde70eb68f9p-448)) (f64.const 0x1.4886b6d9a9a79p+871))
+(assert_return (invoke "f64.no_regroup_mul_div" (f64.const -0x1.706023645be72p+480) (f64.const -0x1.6c229f7d9101dp+611) (f64.const -0x1.4d50fa68d3d9ep+836)) (f64.const -infinity))
+(assert_return (invoke "f64.no_regroup_mul_div" (f64.const 0x1.8cc63d8caf4c7p-599) (f64.const 0x1.8671ac4c35753p-878) (f64.const -0x1.ef35b1695e659p-838)) (f64.const -0x0p+0))
+
+;; Test that x+y+z+w is not reassociated.
+
+(module
+  (func (export "f32.no_reassociate_add") (param $x f32) (param $y f32) (param $z f32) (param $w f32) (result f32)
+    (f32.add (f32.add (f32.add (local.get $x) (local.get $y)) (local.get $z)) (local.get $w)))
+  (func (export "f64.no_reassociate_add") (param $x f64) (param $y f64) (param $z f64) (param $w f64) (result f64)
+    (f64.add (f64.add (f64.add (local.get $x) (local.get $y)) (local.get $z)) (local.get $w)))
+)
+
+(assert_return (invoke "f32.no_reassociate_add" (f32.const -0x1.5f7ddcp+44) (f32.const 0x1.854e1p+34) (f32.const -0x1.b2068cp+47) (f32.const -0x1.209692p+41)) (f32.const -0x1.e26c76p+47))
+(assert_return (invoke "f32.no_reassociate_add" (f32.const 0x1.da3b78p-9) (f32.const -0x1.4312fap-7) (f32.const 0x1.0395e6p-4) (f32.const -0x1.6d5ea6p-7)) (f32.const 0x1.78b31ap-5))
+(assert_return (invoke "f32.no_reassociate_add" (f32.const -0x1.fdb93ap+34) (f32.const -0x1.b6fce6p+41) (f32.const 0x1.c131d8p+44) (f32.const 0x1.8835b6p+38)) (f32.const 0x1.8ff3a2p+44))
+(assert_return (invoke "f32.no_reassociate_add" (f32.const 0x1.1739fcp+47) (f32.const 0x1.a4b186p+49) (f32.const -0x1.0c623cp+35) (f32.const 0x1.16a102p+51)) (f32.const 0x1.913ff6p+51))
+(assert_return (invoke "f32.no_reassociate_add" (f32.const 0x1.733cfap+108) (f32.const -0x1.38d30cp+108) (f32.const 0x1.2f5854p+105) (f32.const -0x1.ccb058p+94)) (f32.const 0x1.813716p+106))
+(assert_return (invoke "f64.no_reassociate_add" (f64.const -0x1.697a4d9ff19a6p+841) (f64.const 0x1.b305466238397p+847) (f64.const 0x1.e0b2d9bfb4e72p+855) (f64.const -0x1.6e1f3ae2b06bbp+857)) (f64.const -0x1.eb0e5936f087ap+856))
+(assert_return (invoke "f64.no_reassociate_add" (f64.const 0x1.00ef6746b30e1p-543) (f64.const 0x1.cc1cfafdf3fe1p-544) (f64.const -0x1.f7726df3ecba6p-543) (f64.const -0x1.b26695f99d307p-594)) (f64.const -0x1.074892e3fad76p-547))
+(assert_return (invoke "f64.no_reassociate_add" (f64.const -0x1.e807b3bd6d854p+440) (f64.const 0x1.cedae26c2c5fp+407) (f64.const -0x1.00ab6e1442541p+437) (f64.const 0x1.28538a55997bdp+397)) (f64.const -0x1.040e90bf871ebp+441))
+(assert_return (invoke "f64.no_reassociate_add" (f64.const -0x1.ba2b6f35a2402p-317) (f64.const 0x1.ad1c3fea7cd9ep-307) (f64.const -0x1.93aace2bf1261p-262) (f64.const 0x1.9fddbe472847ep-260)) (f64.const 0x1.3af30abc2c01bp-260))
+(assert_return (invoke "f64.no_reassociate_add" (f64.const -0x1.ccb9c6092fb1dp+641) (f64.const -0x1.4b7c28c108244p+614) (f64.const 0x1.8a7cefef4bde1p+646) (f64.const -0x1.901b28b08b482p+644)) (f64.const 0x1.1810579194126p+646))
+
+;; Test that x*y*z*w is not reassociated.
+
+(module
+  (func (export "f32.no_reassociate_mul") (param $x f32) (param $y f32) (param $z f32) (param $w f32) (result f32)
+    (f32.mul (f32.mul (f32.mul (local.get $x) (local.get $y)) (local.get $z)) (local.get $w)))
+  (func (export "f64.no_reassociate_mul") (param $x f64) (param $y f64) (param $z f64) (param $w f64) (result f64)
+    (f64.mul (f64.mul (f64.mul (local.get $x) (local.get $y)) (local.get $z)) (local.get $w)))
+)
+
+(assert_return (invoke "f32.no_reassociate_mul" (f32.const 0x1.950ba8p-116) (f32.const 0x1.efdacep-33) (f32.const -0x1.5f9bcp+102) (f32.const 0x1.f04508p-56)) (f32.const -0x1.ff356ep-101))
+(assert_return (invoke "f32.no_reassociate_mul" (f32.const 0x1.5990aep-56) (f32.const -0x1.7dfb04p+102) (f32.const -0x1.4f774ap-125) (f32.const -0x1.595fe6p+70)) (f32.const -0x1.c7c8fcp-8))
+(assert_return (invoke "f32.no_reassociate_mul" (f32.const 0x1.6ad9a4p-48) (f32.const -0x1.9138aap+55) (f32.const -0x1.4a774ep-40) (f32.const 0x1.1ff08p+76)) (f32.const 0x1.9cd8ecp+44))
+(assert_return (invoke "f32.no_reassociate_mul" (f32.const 0x1.e1caecp-105) (f32.const 0x1.af0dd2p+77) (f32.const -0x1.016eep+56) (f32.const -0x1.ab70d6p+59)) (f32.const 0x1.54870ep+89))
+(assert_return (invoke "f32.no_reassociate_mul" (f32.const -0x1.3b1dcp-99) (f32.const 0x1.4e5a34p-49) (f32.const -0x1.38ba5ap+3) (f32.const 0x1.7fb8eep+59)) (f32.const 0x1.5bbf98p-85))
+(assert_return (invoke "f64.no_reassociate_mul" (f64.const -0x1.e7842ab7181p-667) (f64.const -0x1.fabf40ceeceafp+990) (f64.const -0x1.1a38a825ab01ap-376) (f64.const -0x1.27e8ea469b14fp+664)) (f64.const 0x1.336eb428af4f3p+613))
+(assert_return (invoke "f64.no_reassociate_mul" (f64.const 0x1.4ca2292a6acbcp+454) (f64.const 0x1.6ffbab850089ap-516) (f64.const -0x1.547c32e1f5b93p-899) (f64.const -0x1.c7571d9388375p+540)) (f64.const 0x1.1ac796954fc1p-419))
+(assert_return (invoke "f64.no_reassociate_mul" (f64.const 0x1.73881a52e0401p-501) (f64.const -0x1.1b68dd9efb1a7p+788) (f64.const 0x1.d1c5e6a3eb27cp-762) (f64.const -0x1.56cb2fcc7546fp+88)) (f64.const 0x1.f508db92c34efp-386))
+(assert_return (invoke "f64.no_reassociate_mul" (f64.const 0x1.2efa87859987cp+692) (f64.const 0x1.68e4373e241p-423) (f64.const 0x1.4e2d0fb383a57p+223) (f64.const -0x1.301d3265c737bp-23)) (f64.const -0x1.4b2b6c393f30cp+470))
+(assert_return (invoke "f64.no_reassociate_mul" (f64.const 0x1.1013f7498b95fp-234) (f64.const 0x1.d2d1c36fff138p-792) (f64.const -0x1.cbf1824ea7bfdp+728) (f64.const -0x1.440da9c8b836dp-599)) (f64.const 0x1.1a16512881c91p-895))
+
+;; Test that x/0 is not folded away.
+
+(module
+  (func (export "f32.no_fold_div_0") (param $x f32) (result f32)
+    (f32.div (local.get $x) (f32.const 0.0)))
+  (func (export "f64.no_fold_div_0") (param $x f64) (result f64)
+    (f64.div (local.get $x) (f64.const 0.0)))
+)
+
+(assert_return (invoke "f32.no_fold_div_0" (f32.const 1.0)) (f32.const infinity))
+(assert_return (invoke "f32.no_fold_div_0" (f32.const -1.0)) (f32.const -infinity))
+(assert_return (invoke "f32.no_fold_div_0" (f32.const infinity)) (f32.const infinity))
+(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)) (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))
+(assert_return (invoke "f64.no_fold_div_0" (f64.const infinity)) (f64.const infinity))
+(assert_return (invoke "f64.no_fold_div_0" (f64.const -infinity)) (f64.const -infinity))
+(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))
+
+;; Test that x/-0 is not folded away.
+
+(module
+  (func (export "f32.no_fold_div_neg0") (param $x f32) (result f32)
+    (f32.div (local.get $x) (f32.const -0.0)))
+  (func (export "f64.no_fold_div_neg0") (param $x f64) (result f64)
+    (f64.div (local.get $x) (f64.const -0.0)))
+)
+
+(assert_return (invoke "f32.no_fold_div_neg0" (f32.const 1.0)) (f32.const -infinity))
+(assert_return (invoke "f32.no_fold_div_neg0" (f32.const -1.0)) (f32.const infinity))
+(assert_return (invoke "f32.no_fold_div_neg0" (f32.const infinity)) (f32.const -infinity))
+(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)) (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))
+(assert_return (invoke "f64.no_fold_div_neg0" (f64.const infinity)) (f64.const -infinity))
+(assert_return (invoke "f64.no_fold_div_neg0" (f64.const -infinity)) (f64.const infinity))
+(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))
+
+;; Test that sqrt(x*x+y*y) is not folded to hypot.
+
+(module
+  (func (export "f32.no_fold_to_hypot") (param $x f32) (param $y f32) (result f32)
+    (f32.sqrt (f32.add (f32.mul (local.get $x) (local.get $x))
+                       (f32.mul (local.get $y) (local.get $y)))))
+  (func (export "f64.no_fold_to_hypot") (param $x f64) (param $y f64) (result f64)
+    (f64.sqrt (f64.add (f64.mul (local.get $x) (local.get $x))
+                       (f64.mul (local.get $y) (local.get $y)))))
+)
+
+(assert_return (invoke "f32.no_fold_to_hypot" (f32.const 0x1.c2f338p-81) (f32.const 0x1.401b5ep-68)) (f32.const 0x1.401cccp-68))
+(assert_return (invoke "f32.no_fold_to_hypot" (f32.const -0x1.c38d1p-71) (f32.const -0x1.359ddp-107)) (f32.const 0x1.c36a62p-71))
+(assert_return (invoke "f32.no_fold_to_hypot" (f32.const -0x1.99e0cap-114) (f32.const -0x1.ed0c6cp-69)) (f32.const 0x1.ed0e48p-69))
+(assert_return (invoke "f32.no_fold_to_hypot" (f32.const -0x1.1b6ceap+5) (f32.const 0x1.5440bep+17)) (f32.const 0x1.5440cp+17))
+(assert_return (invoke "f32.no_fold_to_hypot" (f32.const 0x1.8f019ep-76) (f32.const -0x1.182308p-71)) (f32.const 0x1.17e2bcp-71))
+(assert_return (invoke "f64.no_fold_to_hypot" (f64.const 0x1.1a0ac4f7c8711p-636) (f64.const 0x1.1372ebafff551p-534)) (f64.const 0x1.13463fa37014ep-534))
+(assert_return (invoke "f64.no_fold_to_hypot" (f64.const 0x1.b793512167499p+395) (f64.const -0x1.11cbc52af4c36p+410)) (f64.const 0x1.11cbc530783a2p+410))
+(assert_return (invoke "f64.no_fold_to_hypot" (f64.const 0x1.76777f44ff40bp-536) (f64.const -0x1.c3896e4dc1fbp-766)) (f64.const 0x1.8p-536))
+(assert_return (invoke "f64.no_fold_to_hypot" (f64.const -0x1.889ac72cc6b5dp-521) (f64.const 0x1.8d7084e659f3bp-733)) (f64.const 0x1.889ac72ca843ap-521))
+(assert_return (invoke "f64.no_fold_to_hypot" (f64.const 0x1.5ee588c02cb08p-670) (f64.const -0x1.05ce25788d9ecp-514)) (f64.const 0x1.05ce25788d9dfp-514))
+
+;; Test that 1.0/x isn't approximated.
+
+(module
+  (func (export "f32.no_approximate_reciprocal") (param $x f32) (result f32)
+    (f32.div (f32.const 1.0) (local.get $x)))
+)
+
+(assert_return (invoke "f32.no_approximate_reciprocal" (f32.const -0x1.2900b6p-10)) (f32.const -0x1.b950d4p+9))
+(assert_return (invoke "f32.no_approximate_reciprocal" (f32.const 0x1.e7212p+127)) (f32.const 0x1.0d11f8p-128))
+(assert_return (invoke "f32.no_approximate_reciprocal" (f32.const -0x1.42a466p-93)) (f32.const -0x1.963ee6p+92))
+(assert_return (invoke "f32.no_approximate_reciprocal" (f32.const 0x1.5d0c32p+76)) (f32.const 0x1.778362p-77))
+(assert_return (invoke "f32.no_approximate_reciprocal" (f32.const -0x1.601de2p-82)) (f32.const -0x1.743d7ep+81))
+
+;; Test that 1.0/sqrt(x) isn't approximated or fused.
+
+(module
+  (func (export "f32.no_approximate_reciprocal_sqrt") (param $x f32) (result f32)
+    (f32.div (f32.const 1.0) (f32.sqrt (local.get $x))))
+  (func (export "f64.no_fuse_reciprocal_sqrt") (param $x f64) (result f64)
+    (f64.div (f64.const 1.0) (f64.sqrt (local.get $x))))
+)
+
+(assert_return (invoke "f32.no_approximate_reciprocal_sqrt" (f32.const 0x1.6af12ap-43)) (f32.const 0x1.300ed4p+21))
+(assert_return (invoke "f32.no_approximate_reciprocal_sqrt" (f32.const 0x1.e82fc6p-8)) (f32.const 0x1.72c376p+3))
+(assert_return (invoke "f32.no_approximate_reciprocal_sqrt" (f32.const 0x1.b9fa9cp-66)) (f32.const 0x1.85a9bap+32))
+(assert_return (invoke "f32.no_approximate_reciprocal_sqrt" (f32.const 0x1.f4f546p-44)) (f32.const 0x1.6e01c2p+21))
+(assert_return (invoke "f32.no_approximate_reciprocal_sqrt" (f32.const 0x1.5da7aap-86)) (f32.const 0x1.b618cap+42))
+
+(assert_return (invoke "f64.no_fuse_reciprocal_sqrt" (f64.const 0x1.1568a63b55fa3p+889)) (f64.const 0x1.5bc9c74c9952p-445))
+(assert_return (invoke "f64.no_fuse_reciprocal_sqrt" (f64.const 0x1.239fcd0939cafp+311)) (f64.const 0x1.5334a922b4818p-156))
+(assert_return (invoke "f64.no_fuse_reciprocal_sqrt" (f64.const 0x1.6e36a24e11054p+104)) (f64.const 0x1.ac13f20977f29p-53))
+(assert_return (invoke "f64.no_fuse_reciprocal_sqrt" (f64.const 0x1.23ee173219f83p+668)) (f64.const 0x1.df753e055862dp-335))
+(assert_return (invoke "f64.no_fuse_reciprocal_sqrt" (f64.const 0x1.b30f74caf9babp+146)) (f64.const 0x1.88bfc3d1764a9p-74))
+
+;; Test that sqrt(1.0/x) isn't approximated.
+
+(module
+  (func (export "f32.no_approximate_sqrt_reciprocal") (param $x f32) (result f32)
+    (f32.sqrt (f32.div (f32.const 1.0) (local.get $x))))
+)
+
+(assert_return (invoke "f32.no_approximate_sqrt_reciprocal" (f32.const 0x1.a4c986p+60)) (f32.const 0x1.8f5ac6p-31))
+(assert_return (invoke "f32.no_approximate_sqrt_reciprocal" (f32.const 0x1.50511ep-9)) (f32.const 0x1.3bdd46p+4))
+(assert_return (invoke "f32.no_approximate_sqrt_reciprocal" (f32.const 0x1.125ec2p+69)) (f32.const 0x1.5db572p-35))
+(assert_return (invoke "f32.no_approximate_sqrt_reciprocal" (f32.const 0x1.ba4c5p+13)) (f32.const 0x1.136f16p-7))
+(assert_return (invoke "f32.no_approximate_sqrt_reciprocal" (f32.const 0x1.4a5be2p+104)) (f32.const 0x1.c2b5bp-53))
+
+;; Test that converting i32/i64 to f32/f64 and back isn't folded away
+
+(module
+  (func (export "i32.no_fold_f32_s") (param i32) (result i32)
+    (i32.trunc_f32_s (f32.convert_i32_s (local.get 0))))
+  (func (export "i32.no_fold_f32_u") (param i32) (result i32)
+    (i32.trunc_f32_u (f32.convert_i32_u (local.get 0))))
+  (func (export "i64.no_fold_f64_s") (param i64) (result i64)
+    (i64.trunc_f64_s (f64.convert_i64_s (local.get 0))))
+  (func (export "i64.no_fold_f64_u") (param i64) (result i64)
+    (i64.trunc_f64_u (f64.convert_i64_u (local.get 0))))
+)
+
+(assert_return (invoke "i32.no_fold_f32_s" (i32.const 0x1000000)) (i32.const 0x1000000))
+(assert_return (invoke "i32.no_fold_f32_s" (i32.const 0x1000001)) (i32.const 0x1000000))
+(assert_return (invoke "i32.no_fold_f32_s" (i32.const 0xf0000010)) (i32.const 0xf0000010))
+
+(assert_return (invoke "i32.no_fold_f32_u" (i32.const 0x1000000)) (i32.const 0x1000000))
+(assert_return (invoke "i32.no_fold_f32_u" (i32.const 0x1000001)) (i32.const 0x1000000))
+(assert_return (invoke "i32.no_fold_f32_u" (i32.const 0xf0000010)) (i32.const 0xf0000000))
+
+(assert_return (invoke "i64.no_fold_f64_s" (i64.const 0x20000000000000)) (i64.const 0x20000000000000))
+(assert_return (invoke "i64.no_fold_f64_s" (i64.const 0x20000000000001)) (i64.const 0x20000000000000))
+(assert_return (invoke "i64.no_fold_f64_s" (i64.const 0xf000000000000400)) (i64.const 0xf000000000000400))
+
+(assert_return (invoke "i64.no_fold_f64_u" (i64.const 0x20000000000000)) (i64.const 0x20000000000000))
+(assert_return (invoke "i64.no_fold_f64_u" (i64.const 0x20000000000001)) (i64.const 0x20000000000000))
+(assert_return (invoke "i64.no_fold_f64_u" (i64.const 0xf000000000000400)) (i64.const 0xf000000000000000))
+
+;; Test that x+y-y is not folded to x.
+
+(module
+  (func (export "f32.no_fold_add_sub") (param $x f32) (param $y f32) (result f32)
+    (f32.sub (f32.add (local.get $x) (local.get $y)) (local.get $y)))
+  (func (export "f64.no_fold_add_sub") (param $x f64) (param $y f64) (result f64)
+    (f64.sub (f64.add (local.get $x) (local.get $y)) (local.get $y)))
+)
+
+(assert_return (invoke "f32.no_fold_add_sub" (f32.const 0x1.b553e4p-47) (f32.const -0x1.67db2cp-26)) (f32.const 0x1.cp-47))
+(assert_return (invoke "f32.no_fold_add_sub" (f32.const -0x1.a884dp-23) (f32.const 0x1.f2ae1ep-19)) (f32.const -0x1.a884ep-23))
+(assert_return (invoke "f32.no_fold_add_sub" (f32.const -0x1.fc04fp+82) (f32.const -0x1.65403ap+101)) (f32.const -0x1p+83))
+(assert_return (invoke "f32.no_fold_add_sub" (f32.const 0x1.870fa2p-78) (f32.const 0x1.c54916p-56)) (f32.const 0x1.8p-78))
+(assert_return (invoke "f32.no_fold_add_sub" (f32.const -0x1.17e966p-108) (f32.const -0x1.5fa61ap-84)) (f32.const -0x1p-107))
+
+(assert_return (invoke "f64.no_fold_add_sub" (f64.const -0x1.1053ea172dba8p-874) (f64.const 0x1.113c413408ac8p-857)) (f64.const -0x1.1053ea172p-874))
+(assert_return (invoke "f64.no_fold_add_sub" (f64.const 0x1.e377d54807972p-546) (f64.const 0x1.040a0a4d1ff7p-526)) (f64.const 0x1.e377d548p-546))
+(assert_return (invoke "f64.no_fold_add_sub" (f64.const -0x1.75f53cd926b62p-30) (f64.const -0x1.66b176e602bb5p-3)) (f64.const -0x1.75f53dp-30))
+(assert_return (invoke "f64.no_fold_add_sub" (f64.const -0x1.c450ff28332ap-341) (f64.const 0x1.15a5855023baep-305)) (f64.const -0x1.c451p-341))
+(assert_return (invoke "f64.no_fold_add_sub" (f64.const -0x1.1ad4a596d3ea8p-619) (f64.const -0x1.17d81a41c0ea8p-588)) (f64.const -0x1.1ad4a8p-619))
+
+;; Test that x-y+y is not folded to x.
+
+(module
+  (func (export "f32.no_fold_sub_add") (param $x f32) (param $y f32) (result f32)
+    (f32.add (f32.sub (local.get $x) (local.get $y)) (local.get $y)))
+  (func (export "f64.no_fold_sub_add") (param $x f64) (param $y f64) (result f64)
+    (f64.add (f64.sub (local.get $x) (local.get $y)) (local.get $y)))
+)
+
+(assert_return (invoke "f32.no_fold_sub_add" (f32.const -0x1.523cb8p+9) (f32.const 0x1.93096cp+8)) (f32.const -0x1.523cbap+9))
+(assert_return (invoke "f32.no_fold_sub_add" (f32.const -0x1.a31a1p-111) (f32.const 0x1.745efp-95)) (f32.const -0x1.a4p-111))
+(assert_return (invoke "f32.no_fold_sub_add" (f32.const 0x1.3d5328p+26) (f32.const 0x1.58567p+35)) (f32.const 0x1.3d54p+26))
+(assert_return (invoke "f32.no_fold_sub_add" (f32.const 0x1.374e26p-39) (f32.const -0x1.66a5p-27)) (f32.const 0x1.374p-39))
+(assert_return (invoke "f32.no_fold_sub_add" (f32.const 0x1.320facp-3) (f32.const -0x1.ac069ap+14)) (f32.const 0x1.34p-3))
+
+(assert_return (invoke "f64.no_fold_sub_add" (f64.const 0x1.8f92aad2c9b8dp+255) (f64.const -0x1.08cd4992266cbp+259)) (f64.const 0x1.8f92aad2c9b9p+255))
+(assert_return (invoke "f64.no_fold_sub_add" (f64.const 0x1.5aaff55742c8bp-666) (f64.const 0x1.8f5f47181f46dp-647)) (f64.const 0x1.5aaff5578p-666))
+(assert_return (invoke "f64.no_fold_sub_add" (f64.const 0x1.21bc52967a98dp+251) (f64.const -0x1.fcffaa32d0884p+300)) (f64.const 0x1.2p+251))
+(assert_return (invoke "f64.no_fold_sub_add" (f64.const 0x1.9c78361f47374p-26) (f64.const -0x1.69d69f4edc61cp-13)) (f64.const 0x1.9c78361f48p-26))
+(assert_return (invoke "f64.no_fold_sub_add" (f64.const 0x1.4dbe68e4afab2p-367) (f64.const -0x1.dc24e5b39cd02p-361)) (f64.const 0x1.4dbe68e4afacp-367))
+
+;; Test that x*y/y is not folded to x.
+
+(module
+  (func (export "f32.no_fold_mul_div") (param $x f32) (param $y f32) (result f32)
+    (f32.div (f32.mul (local.get $x) (local.get $y)) (local.get $y)))
+  (func (export "f64.no_fold_mul_div") (param $x f64) (param $y f64) (result f64)
+    (f64.div (f64.mul (local.get $x) (local.get $y)) (local.get $y)))
+)
+
+(assert_return (invoke "f32.no_fold_mul_div" (f32.const -0x1.cd859ap+54) (f32.const 0x1.6ca936p-47)) (f32.const -0x1.cd8598p+54))
+(assert_return (invoke "f32.no_fold_mul_div" (f32.const -0x1.0b56b8p-26) (f32.const 0x1.48264cp-106)) (f32.const -0x1.0b56a4p-26))
+(assert_return (invoke "f32.no_fold_mul_div" (f32.const -0x1.e7555cp-48) (f32.const -0x1.9161cp+48)) (f32.const -0x1.e7555ap-48))
+(assert_return (invoke "f32.no_fold_mul_div" (f32.const 0x1.aaa50ep+52) (f32.const -0x1.dfb39ep+60)) (f32.const 0x1.aaa50cp+52))
+(assert_return (invoke "f32.no_fold_mul_div" (f32.const -0x1.2b7dfap-92) (f32.const -0x1.7c4ca6p-37)) (f32.const -0x1.2b7dfep-92))
+
+(assert_return (invoke "f64.no_fold_mul_div" (f64.const -0x1.3d79ff4118a1ap-837) (f64.const -0x1.b8b5dda31808cp-205)) (f64.const -0x1.3d79ff412263ep-837))
+(assert_return (invoke "f64.no_fold_mul_div" (f64.const 0x1.f894d1ee6b3a4p+384) (f64.const 0x1.8c2606d03d58ap+585)) (f64.const 0x1.f894d1ee6b3a5p+384))
+(assert_return (invoke "f64.no_fold_mul_div" (f64.const -0x1.a022260acc993p+238) (f64.const -0x1.5fbc128fc8e3cp-552)) (f64.const -0x1.a022260acc992p+238))
+(assert_return (invoke "f64.no_fold_mul_div" (f64.const 0x1.9d4b8ed174f54p-166) (f64.const 0x1.ee3d467aeeac6p-906)) (f64.const 0x1.8dcc95a053b2bp-166))
+(assert_return (invoke "f64.no_fold_mul_div" (f64.const -0x1.e95ea897cdcd4p+660) (f64.const -0x1.854d5df085f2ep-327)) (f64.const -0x1.e95ea897cdcd5p+660))
+
+;; Test that x/y*y is not folded to x.
+
+(module
+  (func (export "f32.no_fold_div_mul") (param $x f32) (param $y f32) (result f32)
+    (f32.mul (f32.div (local.get $x) (local.get $y)) (local.get $y)))
+  (func (export "f64.no_fold_div_mul") (param $x f64) (param $y f64) (result f64)
+    (f64.mul (f64.div (local.get $x) (local.get $y)) (local.get $y)))
+)
+
+(assert_return (invoke "f32.no_fold_div_mul" (f32.const -0x1.dc6364p+38) (f32.const 0x1.d630ecp+29)) (f32.const -0x1.dc6362p+38))
+(assert_return (invoke "f32.no_fold_div_mul" (f32.const -0x1.1f9836p-52) (f32.const -0x1.16c4e4p-18)) (f32.const -0x1.1f9838p-52))
+(assert_return (invoke "f32.no_fold_div_mul" (f32.const 0x1.c5972cp-126) (f32.const -0x1.d6659ep+7)) (f32.const 0x1.c5980ep-126))
+(assert_return (invoke "f32.no_fold_div_mul" (f32.const -0x1.2e3a9ep-74) (f32.const -0x1.353994p+59)) (f32.const -0x1.2e3a4p-74))
+(assert_return (invoke "f32.no_fold_div_mul" (f32.const 0x1.d96b82p-98) (f32.const 0x1.95d908p+27)) (f32.const 0x1.d96b84p-98))
+
+(assert_return (invoke "f64.no_fold_div_mul" (f64.const 0x1.d01f913a52481p-876) (f64.const -0x1.2cd0668b28344p+184)) (f64.const 0x1.d020daf71cdcp-876))
+(assert_return (invoke "f64.no_fold_div_mul" (f64.const -0x1.81cb7d400918dp-714) (f64.const 0x1.7caa643586d6ep-53)) (f64.const -0x1.81cb7d400918ep-714))
+(assert_return (invoke "f64.no_fold_div_mul" (f64.const -0x1.66904c97b5c8ep-145) (f64.const 0x1.5c3481592ad4cp+428)) (f64.const -0x1.66904c97b5c8dp-145))
+(assert_return (invoke "f64.no_fold_div_mul" (f64.const -0x1.e75859d2f0765p-278) (f64.const -0x1.5f19b6ab497f9p+283)) (f64.const -0x1.e75859d2f0764p-278))
+(assert_return (invoke "f64.no_fold_div_mul" (f64.const -0x1.515fe9c3b5f5p+620) (f64.const 0x1.36be869c99f7ap+989)) (f64.const -0x1.515fe9c3b5f4fp+620))
+
+;; Test that promote(demote(x)) is not folded to x.
+
+(module
+  (func (export "no_fold_demote_promote") (param $x f64) (result f64)
+    (f64.promote_f32 (f32.demote_f64 (local.get $x))))
+)
+
+(assert_return (invoke "no_fold_demote_promote" (f64.const -0x1.dece272390f5dp-133)) (f64.const -0x1.decep-133))
+(assert_return (invoke "no_fold_demote_promote" (f64.const -0x1.19e6c79938a6fp-85)) (f64.const -0x1.19e6c8p-85))
+(assert_return (invoke "no_fold_demote_promote" (f64.const 0x1.49b297ec44dc1p+107)) (f64.const 0x1.49b298p+107))
+(assert_return (invoke "no_fold_demote_promote" (f64.const -0x1.74f5bd865163p-88)) (f64.const -0x1.74f5bep-88))
+(assert_return (invoke "no_fold_demote_promote" (f64.const 0x1.26d675662367ep+104)) (f64.const 0x1.26d676p+104))
+
+;; Test that demote(promote(x)) is not folded to x, and aside from NaN is
+;; bit-preserving.
+
+(module
+  (func (export "no_fold_promote_demote") (param $x f32) (result f32)
+    (f32.demote_f64 (f64.promote_f32 (local.get $x))))
+)
+
+(assert_return (invoke "no_fold_promote_demote" (f32.const nan:0x200000)) (f32.const nan:0x600000))
+(assert_return (invoke "no_fold_promote_demote" (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "no_fold_promote_demote" (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "no_fold_promote_demote" (f32.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "no_fold_promote_demote" (f32.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "no_fold_promote_demote" (f32.const 0x1.fffffcp-127)) (f32.const 0x1.fffffcp-127))
+(assert_return (invoke "no_fold_promote_demote" (f32.const -0x1.fffffcp-127)) (f32.const -0x1.fffffcp-127))
+(assert_return (invoke "no_fold_promote_demote" (f32.const 0x1p-126)) (f32.const 0x1p-126))
+(assert_return (invoke "no_fold_promote_demote" (f32.const -0x1p-126)) (f32.const -0x1p-126))
+(assert_return (invoke "no_fold_promote_demote" (f32.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "no_fold_promote_demote" (f32.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "no_fold_promote_demote" (f32.const infinity)) (f32.const infinity))
+(assert_return (invoke "no_fold_promote_demote" (f32.const -infinity)) (f32.const -infinity))
+
+;; Test that demote(x+promote(y)) is not folded to demote(x)+y.
+
+(module
+  (func (export "no_demote_mixed_add") (param $x f64) (param $y f32) (result f32)
+    (f32.demote_f64 (f64.add (local.get $x) (f64.promote_f32 (local.get $y)))))
+  (func (export "no_demote_mixed_add_commuted") (param $y f32) (param $x f64) (result f32)
+    (f32.demote_f64 (f64.add (f64.promote_f32 (local.get $y)) (local.get $x))))
+)
+
+(assert_return (invoke "no_demote_mixed_add" (f64.const 0x1.f51a9d04854f9p-95) (f32.const 0x1.3f4e9cp-119)) (f32.const 0x1.f51a9ep-95))
+(assert_return (invoke "no_demote_mixed_add" (f64.const 0x1.065b3d81ad8dp+37) (f32.const 0x1.758cd8p+38)) (f32.const 0x1.f8ba76p+38))
+(assert_return (invoke "no_demote_mixed_add" (f64.const 0x1.626c80963bd17p-119) (f32.const -0x1.9bbf86p-121)) (f32.const 0x1.f6f93ep-120))
+(assert_return (invoke "no_demote_mixed_add" (f64.const -0x1.0d5110e3385bbp-20) (f32.const 0x1.096f4ap-29)) (f32.const -0x1.0ccc5ap-20))
+(assert_return (invoke "no_demote_mixed_add" (f64.const -0x1.73852db4e5075p-20) (f32.const -0x1.24e474p-41)) (f32.const -0x1.738536p-20))
+
+(assert_return (invoke "no_demote_mixed_add_commuted" (f32.const 0x1.3f4e9cp-119) (f64.const 0x1.f51a9d04854f9p-95)) (f32.const 0x1.f51a9ep-95))
+(assert_return (invoke "no_demote_mixed_add_commuted" (f32.const 0x1.758cd8p+38) (f64.const 0x1.065b3d81ad8dp+37)) (f32.const 0x1.f8ba76p+38))
+(assert_return (invoke "no_demote_mixed_add_commuted" (f32.const -0x1.9bbf86p-121) (f64.const 0x1.626c80963bd17p-119)) (f32.const 0x1.f6f93ep-120))
+(assert_return (invoke "no_demote_mixed_add_commuted" (f32.const 0x1.096f4ap-29) (f64.const -0x1.0d5110e3385bbp-20)) (f32.const -0x1.0ccc5ap-20))
+(assert_return (invoke "no_demote_mixed_add_commuted" (f32.const -0x1.24e474p-41) (f64.const -0x1.73852db4e5075p-20)) (f32.const -0x1.738536p-20))
+
+;; Test that demote(x-promote(y)) is not folded to demote(x)-y.
+
+(module
+  (func (export "no_demote_mixed_sub") (param $x f64) (param $y f32) (result f32)
+    (f32.demote_f64 (f64.sub (local.get $x) (f64.promote_f32 (local.get $y)))))
+)
+
+(assert_return (invoke "no_demote_mixed_sub" (f64.const 0x1.a0a183220e9b1p+82) (f32.const 0x1.c5acf8p+61)) (f32.const 0x1.a0a174p+82))
+(assert_return (invoke "no_demote_mixed_sub" (f64.const -0x1.6e2c5ac39f63ep+30) (f32.const 0x1.d48ca4p+17)) (f32.const -0x1.6e3bp+30))
+(assert_return (invoke "no_demote_mixed_sub" (f64.const -0x1.98c74350dde6ap+6) (f32.const 0x1.9d69bcp-12)) (f32.const -0x1.98c7aap+6))
+(assert_return (invoke "no_demote_mixed_sub" (f64.const 0x1.0459f34091dbfp-54) (f32.const 0x1.61ad08p-71)) (f32.const 0x1.045942p-54))
+(assert_return (invoke "no_demote_mixed_sub" (f64.const 0x1.a7498dca3fdb7p+14) (f32.const 0x1.ed21c8p+15)) (f32.const -0x1.197d02p+15))
+
+;; Test that converting between integer and float and back isn't folded away.
+
+(module
+  (func (export "f32.i32.no_fold_trunc_s_convert_s") (param $x f32) (result f32)
+    (f32.convert_i32_s (i32.trunc_f32_s (local.get $x))))
+  (func (export "f32.i32.no_fold_trunc_u_convert_s") (param $x f32) (result f32)
+    (f32.convert_i32_s (i32.trunc_f32_u (local.get $x))))
+  (func (export "f32.i32.no_fold_trunc_s_convert_u") (param $x f32) (result f32)
+    (f32.convert_i32_u (i32.trunc_f32_s (local.get $x))))
+  (func (export "f32.i32.no_fold_trunc_u_convert_u") (param $x f32) (result f32)
+    (f32.convert_i32_u (i32.trunc_f32_u (local.get $x))))
+  (func (export "f64.i32.no_fold_trunc_s_convert_s") (param $x f64) (result f64)
+    (f64.convert_i32_s (i32.trunc_f64_s (local.get $x))))
+  (func (export "f64.i32.no_fold_trunc_u_convert_s") (param $x f64) (result f64)
+    (f64.convert_i32_s (i32.trunc_f64_u (local.get $x))))
+  (func (export "f64.i32.no_fold_trunc_s_convert_u") (param $x f64) (result f64)
+    (f64.convert_i32_u (i32.trunc_f64_s (local.get $x))))
+  (func (export "f64.i32.no_fold_trunc_u_convert_u") (param $x f64) (result f64)
+    (f64.convert_i32_u (i32.trunc_f64_u (local.get $x))))
+  (func (export "f32.i64.no_fold_trunc_s_convert_s") (param $x f32) (result f32)
+    (f32.convert_i64_s (i64.trunc_f32_s (local.get $x))))
+  (func (export "f32.i64.no_fold_trunc_u_convert_s") (param $x f32) (result f32)
+    (f32.convert_i64_s (i64.trunc_f32_u (local.get $x))))
+  (func (export "f32.i64.no_fold_trunc_s_convert_u") (param $x f32) (result f32)
+    (f32.convert_i64_u (i64.trunc_f32_s (local.get $x))))
+  (func (export "f32.i64.no_fold_trunc_u_convert_u") (param $x f32) (result f32)
+    (f32.convert_i64_u (i64.trunc_f32_u (local.get $x))))
+  (func (export "f64.i64.no_fold_trunc_s_convert_s") (param $x f64) (result f64)
+    (f64.convert_i64_s (i64.trunc_f64_s (local.get $x))))
+  (func (export "f64.i64.no_fold_trunc_u_convert_s") (param $x f64) (result f64)
+    (f64.convert_i64_s (i64.trunc_f64_u (local.get $x))))
+  (func (export "f64.i64.no_fold_trunc_s_convert_u") (param $x f64) (result f64)
+    (f64.convert_i64_u (i64.trunc_f64_s (local.get $x))))
+  (func (export "f64.i64.no_fold_trunc_u_convert_u") (param $x f64) (result f64)
+    (f64.convert_i64_u (i64.trunc_f64_u (local.get $x))))
+)
+
+(assert_return (invoke "f32.i32.no_fold_trunc_s_convert_s" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i32.no_fold_trunc_s_convert_s" (f32.const -1.5)) (f32.const -1.0))
+(assert_return (invoke "f32.i32.no_fold_trunc_u_convert_s" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i32.no_fold_trunc_u_convert_s" (f32.const -0.5)) (f32.const 0.0))
+(assert_return (invoke "f32.i32.no_fold_trunc_s_convert_u" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i32.no_fold_trunc_s_convert_u" (f32.const -1.5)) (f32.const 0x1p+32))
+(assert_return (invoke "f32.i32.no_fold_trunc_u_convert_u" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i32.no_fold_trunc_u_convert_u" (f32.const -0.5)) (f32.const 0.0))
+
+(assert_return (invoke "f64.i32.no_fold_trunc_s_convert_s" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i32.no_fold_trunc_s_convert_s" (f64.const -1.5)) (f64.const -1.0))
+(assert_return (invoke "f64.i32.no_fold_trunc_u_convert_s" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i32.no_fold_trunc_u_convert_s" (f64.const -0.5)) (f64.const 0.0))
+(assert_return (invoke "f64.i32.no_fold_trunc_s_convert_u" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i32.no_fold_trunc_s_convert_u" (f64.const -1.5)) (f64.const 0x1.fffffffep+31))
+(assert_return (invoke "f64.i32.no_fold_trunc_u_convert_u" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i32.no_fold_trunc_u_convert_u" (f64.const -0.5)) (f64.const 0.0))
+
+(assert_return (invoke "f32.i64.no_fold_trunc_s_convert_s" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i64.no_fold_trunc_s_convert_s" (f32.const -1.5)) (f32.const -1.0))
+(assert_return (invoke "f32.i64.no_fold_trunc_u_convert_s" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i64.no_fold_trunc_u_convert_s" (f32.const -0.5)) (f32.const 0.0))
+(assert_return (invoke "f32.i64.no_fold_trunc_s_convert_u" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i64.no_fold_trunc_s_convert_u" (f32.const -1.5)) (f32.const 0x1p+64))
+(assert_return (invoke "f32.i64.no_fold_trunc_u_convert_u" (f32.const 1.5)) (f32.const 1.0))
+(assert_return (invoke "f32.i64.no_fold_trunc_u_convert_u" (f32.const -0.5)) (f32.const 0.0))
+
+(assert_return (invoke "f64.i64.no_fold_trunc_s_convert_s" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i64.no_fold_trunc_s_convert_s" (f64.const -1.5)) (f64.const -1.0))
+(assert_return (invoke "f64.i64.no_fold_trunc_u_convert_s" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i64.no_fold_trunc_u_convert_s" (f64.const -0.5)) (f64.const 0.0))
+(assert_return (invoke "f64.i64.no_fold_trunc_s_convert_u" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i64.no_fold_trunc_s_convert_u" (f64.const -1.5)) (f64.const 0x1p+64))
+(assert_return (invoke "f64.i64.no_fold_trunc_u_convert_u" (f64.const 1.5)) (f64.const 1.0))
+(assert_return (invoke "f64.i64.no_fold_trunc_u_convert_u" (f64.const -0.5)) (f64.const 0.0))
+
+;; Test that dividing by a loop-invariant constant isn't optimized to be a
+;; multiplication by a reciprocal, which would be particularly tempting since
+;; the reciprocal computation could be hoisted.
+
+(module
+  (memory 1 1)
+  (func (export "init") (param $i i32) (param $x f32) (f32.store (local.get $i) (local.get $x)))
+
+  (func (export "run") (param $n i32) (param $z f32)
+    (local $i i32)
+    (block $exit
+      (loop $cont
+        (f32.store
+          (local.get $i)
+          (f32.div (f32.load (local.get $i)) (local.get $z))
+        )
+        (local.set $i (i32.add (local.get $i) (i32.const 4)))
+        (br_if $cont (i32.lt_u (local.get $i) (local.get $n)))
+      )
+    )
+  )
+
+  (func (export "check") (param $i i32) (result f32) (f32.load (local.get $i)))
+)
+
+(invoke "init" (i32.const  0) (f32.const 15.1))
+(invoke "init" (i32.const  4) (f32.const 15.2))
+(invoke "init" (i32.const  8) (f32.const 15.3))
+(invoke "init" (i32.const 12) (f32.const 15.4))
+(assert_return (invoke "check" (i32.const  0)) (f32.const 15.1))
+(assert_return (invoke "check" (i32.const  4)) (f32.const 15.2))
+(assert_return (invoke "check" (i32.const  8)) (f32.const 15.3))
+(assert_return (invoke "check" (i32.const 12)) (f32.const 15.4))
+(invoke "run" (i32.const 16) (f32.const 3.0))
+(assert_return (invoke "check" (i32.const  0)) (f32.const 0x1.422222p+2))
+(assert_return (invoke "check" (i32.const  4)) (f32.const 0x1.444444p+2))
+(assert_return (invoke "check" (i32.const  8)) (f32.const 0x1.466666p+2))
+(assert_return (invoke "check" (i32.const 12)) (f32.const 0x1.488888p+2))
+
+(module
+  (memory 1 1)
+  (func (export "init") (param $i i32) (param $x f64) (f64.store (local.get $i) (local.get $x)))
+
+  (func (export "run") (param $n i32) (param $z f64)
+    (local $i i32)
+    (block $exit
+      (loop $cont
+        (f64.store
+          (local.get $i)
+          (f64.div (f64.load (local.get $i)) (local.get $z))
+        )
+        (local.set $i (i32.add (local.get $i) (i32.const 8)))
+        (br_if $cont (i32.lt_u (local.get $i) (local.get $n)))
+      )
+    )
+  )
+
+  (func (export "check") (param $i i32) (result f64) (f64.load (local.get $i)))
+)
+
+(invoke "init" (i32.const  0) (f64.const 15.1))
+(invoke "init" (i32.const  8) (f64.const 15.2))
+(invoke "init" (i32.const 16) (f64.const 15.3))
+(invoke "init" (i32.const 24) (f64.const 15.4))
+(assert_return (invoke "check" (i32.const  0)) (f64.const 15.1))
+(assert_return (invoke "check" (i32.const  8)) (f64.const 15.2))
+(assert_return (invoke "check" (i32.const 16)) (f64.const 15.3))
+(assert_return (invoke "check" (i32.const 24)) (f64.const 15.4))
+(invoke "run" (i32.const 32) (f64.const 3.0))
+(assert_return (invoke "check" (i32.const  0)) (f64.const 0x1.4222222222222p+2))
+(assert_return (invoke "check" (i32.const  8)) (f64.const 0x1.4444444444444p+2))
+(assert_return (invoke "check" (i32.const 16)) (f64.const 0x1.4666666666667p+2))
+(assert_return (invoke "check" (i32.const 24)) (f64.const 0x1.4888888888889p+2))
+
+;; Test that ult/ugt/etc. aren't folded to olt/ogt/etc.
+
+(module
+  (func (export "f32.ult") (param $x f32) (param $y f32) (result i32) (i32.eqz (f32.ge (local.get $x) (local.get $y))))
+  (func (export "f32.ule") (param $x f32) (param $y f32) (result i32) (i32.eqz (f32.gt (local.get $x) (local.get $y))))
+  (func (export "f32.ugt") (param $x f32) (param $y f32) (result i32) (i32.eqz (f32.le (local.get $x) (local.get $y))))
+  (func (export "f32.uge") (param $x f32) (param $y f32) (result i32) (i32.eqz (f32.lt (local.get $x) (local.get $y))))
+
+  (func (export "f64.ult") (param $x f64) (param $y f64) (result i32) (i32.eqz (f64.ge (local.get $x) (local.get $y))))
+  (func (export "f64.ule") (param $x f64) (param $y f64) (result i32) (i32.eqz (f64.gt (local.get $x) (local.get $y))))
+  (func (export "f64.ugt") (param $x f64) (param $y f64) (result i32) (i32.eqz (f64.le (local.get $x) (local.get $y))))
+  (func (export "f64.uge") (param $x f64) (param $y f64) (result i32) (i32.eqz (f64.lt (local.get $x) (local.get $y))))
+)
+
+(assert_return (invoke "f32.ult" (f32.const 3.0) (f32.const 2.0)) (i32.const 0))
+(assert_return (invoke "f32.ult" (f32.const 2.0) (f32.const 2.0)) (i32.const 0))
+(assert_return (invoke "f32.ult" (f32.const 2.0) (f32.const 3.0)) (i32.const 1))
+(assert_return (invoke "f32.ult" (f32.const 2.0) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "f32.ule" (f32.const 3.0) (f32.const 2.0)) (i32.const 0))
+(assert_return (invoke "f32.ule" (f32.const 2.0) (f32.const 2.0)) (i32.const 1))
+(assert_return (invoke "f32.ule" (f32.const 2.0) (f32.const 3.0)) (i32.const 1))
+(assert_return (invoke "f32.ule" (f32.const 2.0) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "f32.ugt" (f32.const 3.0) (f32.const 2.0)) (i32.const 1))
+(assert_return (invoke "f32.ugt" (f32.const 2.0) (f32.const 2.0)) (i32.const 0))
+(assert_return (invoke "f32.ugt" (f32.const 2.0) (f32.const 3.0)) (i32.const 0))
+(assert_return (invoke "f32.ugt" (f32.const 2.0) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "f32.uge" (f32.const 3.0) (f32.const 2.0)) (i32.const 1))
+(assert_return (invoke "f32.uge" (f32.const 2.0) (f32.const 2.0)) (i32.const 1))
+(assert_return (invoke "f32.uge" (f32.const 2.0) (f32.const 3.0)) (i32.const 0))
+(assert_return (invoke "f32.uge" (f32.const 2.0) (f32.const nan)) (i32.const 1))
+(assert_return (invoke "f64.ult" (f64.const 3.0) (f64.const 2.0)) (i32.const 0))
+(assert_return (invoke "f64.ult" (f64.const 2.0) (f64.const 2.0)) (i32.const 0))
+(assert_return (invoke "f64.ult" (f64.const 2.0) (f64.const 3.0)) (i32.const 1))
+(assert_return (invoke "f64.ult" (f64.const 2.0) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "f64.ule" (f64.const 3.0) (f64.const 2.0)) (i32.const 0))
+(assert_return (invoke "f64.ule" (f64.const 2.0) (f64.const 2.0)) (i32.const 1))
+(assert_return (invoke "f64.ule" (f64.const 2.0) (f64.const 3.0)) (i32.const 1))
+(assert_return (invoke "f64.ule" (f64.const 2.0) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "f64.ugt" (f64.const 3.0) (f64.const 2.0)) (i32.const 1))
+(assert_return (invoke "f64.ugt" (f64.const 2.0) (f64.const 2.0)) (i32.const 0))
+(assert_return (invoke "f64.ugt" (f64.const 2.0) (f64.const 3.0)) (i32.const 0))
+(assert_return (invoke "f64.ugt" (f64.const 2.0) (f64.const nan)) (i32.const 1))
+(assert_return (invoke "f64.uge" (f64.const 3.0) (f64.const 2.0)) (i32.const 1))
+(assert_return (invoke "f64.uge" (f64.const 2.0) (f64.const 2.0)) (i32.const 1))
+(assert_return (invoke "f64.uge" (f64.const 2.0) (f64.const 3.0)) (i32.const 0))
+(assert_return (invoke "f64.uge" (f64.const 2.0) (f64.const nan)) (i32.const 1))
+
+;; Test that x<y?x:y, etc. using select aren't folded to min, etc.
+
+(module
+  (func (export "f32.no_fold_lt_select") (param $x f32) (param $y f32) (result f32) (select (local.get $x) (local.get $y) (f32.lt (local.get $x) (local.get $y))))
+  (func (export "f32.no_fold_le_select") (param $x f32) (param $y f32) (result f32) (select (local.get $x) (local.get $y) (f32.le (local.get $x) (local.get $y))))
+  (func (export "f32.no_fold_gt_select") (param $x f32) (param $y f32) (result f32) (select (local.get $x) (local.get $y) (f32.gt (local.get $x) (local.get $y))))
+  (func (export "f32.no_fold_ge_select") (param $x f32) (param $y f32) (result f32) (select (local.get $x) (local.get $y) (f32.ge (local.get $x) (local.get $y))))
+
+  (func (export "f64.no_fold_lt_select") (param $x f64) (param $y f64) (result f64) (select (local.get $x) (local.get $y) (f64.lt (local.get $x) (local.get $y))))
+  (func (export "f64.no_fold_le_select") (param $x f64) (param $y f64) (result f64) (select (local.get $x) (local.get $y) (f64.le (local.get $x) (local.get $y))))
+  (func (export "f64.no_fold_gt_select") (param $x f64) (param $y f64) (result f64) (select (local.get $x) (local.get $y) (f64.gt (local.get $x) (local.get $y))))
+  (func (export "f64.no_fold_ge_select") (param $x f64) (param $y f64) (result f64) (select (local.get $x) (local.get $y) (f64.ge (local.get $x) (local.get $y))))
+)
+
+(assert_return (invoke "f32.no_fold_lt_select" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_lt_select" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_lt_select" (f32.const 0.0) (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_lt_select" (f32.const -0.0) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_le_select" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_le_select" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_le_select" (f32.const 0.0) (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_le_select" (f32.const -0.0) (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_gt_select" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_gt_select" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_gt_select" (f32.const 0.0) (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_gt_select" (f32.const -0.0) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_select" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_ge_select" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_select" (f32.const 0.0) (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_select" (f32.const -0.0) (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f64.no_fold_lt_select" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_lt_select" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_lt_select" (f64.const 0.0) (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_lt_select" (f64.const -0.0) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_le_select" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_le_select" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_le_select" (f64.const 0.0) (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_le_select" (f64.const -0.0) (f64.const 0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_gt_select" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_gt_select" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_gt_select" (f64.const 0.0) (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_gt_select" (f64.const -0.0) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_select" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_ge_select" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_select" (f64.const 0.0) (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_select" (f64.const -0.0) (f64.const 0.0)) (f64.const -0.0))
+
+;; Test that x<y?x:y, etc. using if and else aren't folded to min, etc.
+
+(module
+  (func (export "f32.no_fold_lt_if") (param $x f32) (param $y f32) (result f32) (if f32 (f32.lt (local.get $x) (local.get $y)) (local.get $x) (local.get $y)))
+  (func (export "f32.no_fold_le_if") (param $x f32) (param $y f32) (result f32) (if f32 (f32.le (local.get $x) (local.get $y)) (local.get $x) (local.get $y)))
+  (func (export "f32.no_fold_gt_if") (param $x f32) (param $y f32) (result f32) (if f32 (f32.gt (local.get $x) (local.get $y)) (local.get $x) (local.get $y)))
+  (func (export "f32.no_fold_ge_if") (param $x f32) (param $y f32) (result f32) (if f32 (f32.ge (local.get $x) (local.get $y)) (local.get $x) (local.get $y)))
+
+  (func (export "f64.no_fold_lt_if") (param $x f64) (param $y f64) (result f64) (if f64 (f64.lt (local.get $x) (local.get $y)) (local.get $x) (local.get $y)))
+  (func (export "f64.no_fold_le_if") (param $x f64) (param $y f64) (result f64) (if f64 (f64.le (local.get $x) (local.get $y)) (local.get $x) (local.get $y)))
+  (func (export "f64.no_fold_gt_if") (param $x f64) (param $y f64) (result f64) (if f64 (f64.gt (local.get $x) (local.get $y)) (local.get $x) (local.get $y)))
+  (func (export "f64.no_fold_ge_if") (param $x f64) (param $y f64) (result f64) (if f64 (f64.ge (local.get $x) (local.get $y)) (local.get $x) (local.get $y)))
+)
+
+(assert_return (invoke "f32.no_fold_lt_if" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_lt_if" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_lt_if" (f32.const 0.0) (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_lt_if" (f32.const -0.0) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_le_if" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_le_if" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_le_if" (f32.const 0.0) (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_le_if" (f32.const -0.0) (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_gt_if" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_gt_if" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_gt_if" (f32.const 0.0) (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_gt_if" (f32.const -0.0) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_if" (f32.const 0.0) (f32.const nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_ge_if" (f32.const nan) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_if" (f32.const 0.0) (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_if" (f32.const -0.0) (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f64.no_fold_lt_if" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_lt_if" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_lt_if" (f64.const 0.0) (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_lt_if" (f64.const -0.0) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_le_if" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_le_if" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_le_if" (f64.const 0.0) (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_le_if" (f64.const -0.0) (f64.const 0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_gt_if" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_gt_if" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_gt_if" (f64.const 0.0) (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_gt_if" (f64.const -0.0) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_if" (f64.const 0.0) (f64.const nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_ge_if" (f64.const nan) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_if" (f64.const 0.0) (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_if" (f64.const -0.0) (f64.const 0.0)) (f64.const -0.0))
+
+;; Test that x<0?-x:0, etc. using select aren't folded to abs
+
+(module
+  (func (export "f32.no_fold_lt_select_to_abs") (param $x f32) (result f32) (select (f32.neg (local.get $x)) (local.get $x) (f32.lt (local.get $x) (f32.const 0.0))))
+  (func (export "f32.no_fold_le_select_to_abs") (param $x f32) (result f32) (select (f32.neg (local.get $x)) (local.get $x) (f32.le (local.get $x) (f32.const -0.0))))
+  (func (export "f32.no_fold_gt_select_to_abs") (param $x f32) (result f32) (select (local.get $x) (f32.neg (local.get $x)) (f32.gt (local.get $x) (f32.const -0.0))))
+  (func (export "f32.no_fold_ge_select_to_abs") (param $x f32) (result f32) (select (local.get $x) (f32.neg (local.get $x)) (f32.ge (local.get $x) (f32.const 0.0))))
+
+  (func (export "f64.no_fold_lt_select_to_abs") (param $x f64) (result f64) (select (f64.neg (local.get $x)) (local.get $x) (f64.lt (local.get $x) (f64.const 0.0))))
+  (func (export "f64.no_fold_le_select_to_abs") (param $x f64) (result f64) (select (f64.neg (local.get $x)) (local.get $x) (f64.le (local.get $x) (f64.const -0.0))))
+  (func (export "f64.no_fold_gt_select_to_abs") (param $x f64) (result f64) (select (local.get $x) (f64.neg (local.get $x)) (f64.gt (local.get $x) (f64.const -0.0))))
+  (func (export "f64.no_fold_ge_select_to_abs") (param $x f64) (result f64) (select (local.get $x) (f64.neg (local.get $x)) (f64.ge (local.get $x) (f64.const 0.0))))
+)
+
+(assert_return (invoke "f32.no_fold_lt_select_to_abs" (f32.const nan:0x200000)) (f32.const nan:0x200000))
+(assert_return (invoke "f32.no_fold_lt_select_to_abs" (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "f32.no_fold_lt_select_to_abs" (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_lt_select_to_abs" (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_le_select_to_abs" (f32.const nan:0x200000)) (f32.const nan:0x200000))
+(assert_return (invoke "f32.no_fold_le_select_to_abs" (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "f32.no_fold_le_select_to_abs" (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_le_select_to_abs" (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_gt_select_to_abs" (f32.const nan:0x200000)) (f32.const -nan:0x200000))
+(assert_return (invoke "f32.no_fold_gt_select_to_abs" (f32.const -nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_gt_select_to_abs" (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_gt_select_to_abs" (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_select_to_abs" (f32.const nan:0x200000)) (f32.const -nan:0x200000))
+(assert_return (invoke "f32.no_fold_ge_select_to_abs" (f32.const -nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_ge_select_to_abs" (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_select_to_abs" (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f64.no_fold_lt_select_to_abs" (f64.const nan:0x4000000000000)) (f64.const nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_lt_select_to_abs" (f64.const -nan)) (f64.const -nan))
+(assert_return (invoke "f64.no_fold_lt_select_to_abs" (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_lt_select_to_abs" (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_le_select_to_abs" (f64.const nan:0x4000000000000)) (f64.const nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_le_select_to_abs" (f64.const -nan)) (f64.const -nan))
+(assert_return (invoke "f64.no_fold_le_select_to_abs" (f64.const 0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_le_select_to_abs" (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_gt_select_to_abs" (f64.const nan:0x4000000000000)) (f64.const -nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_gt_select_to_abs" (f64.const -nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_gt_select_to_abs" (f64.const 0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_gt_select_to_abs" (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_select_to_abs" (f64.const nan:0x4000000000000)) (f64.const -nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_ge_select_to_abs" (f64.const -nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_ge_select_to_abs" (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_select_to_abs" (f64.const -0.0)) (f64.const -0.0))
+
+;; Test that x<0?-x:0, etc. using if aren't folded to abs
+
+(module
+  (func (export "f32.no_fold_lt_if_to_abs") (param $x f32) (result f32) (if f32 (f32.lt (local.get $x) (f32.const 0.0)) (f32.neg (local.get $x)) (local.get $x)))
+  (func (export "f32.no_fold_le_if_to_abs") (param $x f32) (result f32) (if f32 (f32.le (local.get $x) (f32.const -0.0)) (f32.neg (local.get $x)) (local.get $x)))
+  (func (export "f32.no_fold_gt_if_to_abs") (param $x f32) (result f32) (if f32 (f32.gt (local.get $x) (f32.const -0.0)) (local.get $x) (f32.neg (local.get $x))))
+  (func (export "f32.no_fold_ge_if_to_abs") (param $x f32) (result f32) (if f32 (f32.ge (local.get $x) (f32.const 0.0)) (local.get $x) (f32.neg (local.get $x))))
+
+  (func (export "f64.no_fold_lt_if_to_abs") (param $x f64) (result f64) (if f64 (f64.lt (local.get $x) (f64.const 0.0)) (f64.neg (local.get $x)) (local.get $x)))
+  (func (export "f64.no_fold_le_if_to_abs") (param $x f64) (result f64) (if f64 (f64.le (local.get $x) (f64.const -0.0)) (f64.neg (local.get $x)) (local.get $x)))
+  (func (export "f64.no_fold_gt_if_to_abs") (param $x f64) (result f64) (if f64 (f64.gt (local.get $x) (f64.const -0.0)) (local.get $x) (f64.neg (local.get $x))))
+  (func (export "f64.no_fold_ge_if_to_abs") (param $x f64) (result f64) (if f64 (f64.ge (local.get $x) (f64.const 0.0)) (local.get $x) (f64.neg (local.get $x))))
+)
+
+(assert_return (invoke "f32.no_fold_lt_if_to_abs" (f32.const nan:0x200000)) (f32.const nan:0x200000))
+(assert_return (invoke "f32.no_fold_lt_if_to_abs" (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "f32.no_fold_lt_if_to_abs" (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_lt_if_to_abs" (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_le_if_to_abs" (f32.const nan:0x200000)) (f32.const nan:0x200000))
+(assert_return (invoke "f32.no_fold_le_if_to_abs" (f32.const -nan)) (f32.const -nan))
+(assert_return (invoke "f32.no_fold_le_if_to_abs" (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_le_if_to_abs" (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_gt_if_to_abs" (f32.const nan:0x200000)) (f32.const -nan:0x200000))
+(assert_return (invoke "f32.no_fold_gt_if_to_abs" (f32.const -nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_gt_if_to_abs" (f32.const 0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_gt_if_to_abs" (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_if_to_abs" (f32.const nan:0x200000)) (f32.const -nan:0x200000))
+(assert_return (invoke "f32.no_fold_ge_if_to_abs" (f32.const -nan)) (f32.const nan))
+(assert_return (invoke "f32.no_fold_ge_if_to_abs" (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_ge_if_to_abs" (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f64.no_fold_lt_if_to_abs" (f64.const nan:0x4000000000000)) (f64.const nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_lt_if_to_abs" (f64.const -nan)) (f64.const -nan))
+(assert_return (invoke "f64.no_fold_lt_if_to_abs" (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_lt_if_to_abs" (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_le_if_to_abs" (f64.const nan:0x4000000000000)) (f64.const nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_le_if_to_abs" (f64.const -nan)) (f64.const -nan))
+(assert_return (invoke "f64.no_fold_le_if_to_abs" (f64.const 0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_le_if_to_abs" (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_gt_if_to_abs" (f64.const nan:0x4000000000000)) (f64.const -nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_gt_if_to_abs" (f64.const -nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_gt_if_to_abs" (f64.const 0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_gt_if_to_abs" (f64.const -0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_if_to_abs" (f64.const nan:0x4000000000000)) (f64.const -nan:0x4000000000000))
+(assert_return (invoke "f64.no_fold_ge_if_to_abs" (f64.const -nan)) (f64.const nan))
+(assert_return (invoke "f64.no_fold_ge_if_to_abs" (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_ge_if_to_abs" (f64.const -0.0)) (f64.const -0.0))
+
+;; Test for a historic spreadsheet bug.
+;; https://support.microsoft.com/en-us/kb/78113
+
+(module
+  (func (export "incorrect_correction") (result f32)
+    (f32.sub (f32.sub (f32.add (f32.const 1.333) (f32.const 1.225)) (f32.const 1.333)) (f32.const 1.225))
+  )
+)
+
+(assert_return (invoke "incorrect_correction") (f32.const 0x1p-23))
+
+(module
+  (func (export "incorrect_correction") (result f64)
+    (f64.sub (f64.sub (f64.add (f64.const 1.333) (f64.const 1.225)) (f64.const 1.333)) (f64.const 1.225))
+  )
+)
+
+(assert_return (invoke "incorrect_correction") (f64.const -0x1p-52))
+
+;; Test for a historical calculator bug.
+;; http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=735
+
+(module
+  (func (export "calculate") (result f32)
+    (local $x f32)
+    (local $r f32)
+    (local $q f32)
+    (local $z0 f32)
+    (local $z1 f32)
+    (local.set $x (f32.const 156.25))
+    (local.set $r (f32.const 208.333333334))
+    (local.set $q (f32.const 1.77951304201))
+    (local.set $z0 (f32.div (f32.mul (f32.neg (local.get $r)) (local.get $x)) (f32.sub (f32.mul (local.get $x) (local.get $q)) (local.get $r))))
+    (local.set $z1 (f32.div (f32.mul (f32.neg (local.get $r)) (local.get $x)) (f32.sub (f32.mul (local.get $x) (local.get $q)) (local.get $r))))
+    (block (br_if 0 (f32.eq (local.get $z0) (local.get $z1))) (unreachable))
+    (local.get $z1)
+  )
+)
+
+(assert_return (invoke "calculate") (f32.const -0x1.d2ed46p+8))
+
+(module
+  (func (export "calculate") (result f64)
+    (local $x f64)
+    (local $r f64)
+    (local $q f64)
+    (local $z0 f64)
+    (local $z1 f64)
+    (local.set $x (f64.const 156.25))
+    (local.set $r (f64.const 208.333333334))
+    (local.set $q (f64.const 1.77951304201))
+    (local.set $z0 (f64.div (f64.mul (f64.neg (local.get $r)) (local.get $x)) (f64.sub (f64.mul (local.get $x) (local.get $q)) (local.get $r))))
+    (local.set $z1 (f64.div (f64.mul (f64.neg (local.get $r)) (local.get $x)) (f64.sub (f64.mul (local.get $x) (local.get $q)) (local.get $r))))
+    (block (br_if 0 (f64.eq (local.get $z0) (local.get $z1))) (unreachable))
+    (local.get $z1)
+  )
+)
+
+(assert_return (invoke "calculate") (f64.const -0x1.d2ed4d0218c93p+8))
+
+;; Test that 0 - (-0 - x) is not optimized to x.
+;; https://llvm.org/bugs/show_bug.cgi?id=26746
+
+(module
+  (func (export "llvm_pr26746") (param $x f32) (result f32)
+    (f32.sub (f32.const 0.0) (f32.sub (f32.const -0.0) (local.get $x)))
+  )
+)
+
+(assert_return (invoke "llvm_pr26746" (f32.const -0.0)) (f32.const 0.0))
+
+;; Test for improperly reassociating an addition and a conversion.
+;; https://llvm.org/bugs/show_bug.cgi?id=27153
+
+(module
+  (func (export "llvm_pr27153") (param $x i32) (result f32)
+    (f32.add (f32.convert_i32_s (i32.and (local.get $x) (i32.const 268435455))) (f32.const -8388608.0))
+  )
+)
+
+(assert_return (invoke "llvm_pr27153" (i32.const 33554434)) (f32.const 25165824.000000))
+
+;; Test that (float)x + (float)y is not optimized to (float)(x + y) when unsafe.
+;; https://llvm.org/bugs/show_bug.cgi?id=27036
+
+(module
+  (func (export "llvm_pr27036") (param $x i32) (param $y i32) (result f32)
+    (f32.add (f32.convert_i32_s (i32.or (local.get $x) (i32.const -25034805)))
+             (f32.convert_i32_s (i32.and (local.get $y) (i32.const 14942208))))
+  )
+)
+
+(assert_return (invoke "llvm_pr27036" (i32.const -25034805) (i32.const 14942208)) (f32.const -0x1.340068p+23))
+
+;; Test for bugs in old versions of historic IEEE 754 platforms as reported in:
+;;
+;; N. L. Schryer. 1981. A Test of a Computer's Floating-Point Arithmetic Unit.
+;; Tech. Rep. Computer Science Technical Report 89, AT&T Bell Laboratories, Feb.
+;;
+;; specifically, the appendices describing IEEE systems with "The Past" sections
+;; describing specific bugs. The 0 < 0 bug is omitted here due to being already
+;; covered elsewhere.
+(module
+  (func (export "thepast0") (param $a f64) (param $b f64) (param $c f64) (param $d f64) (result f64)
+    (f64.div (f64.mul (local.get $a) (local.get $b)) (f64.mul (local.get $c) (local.get $d)))
+  )
+
+  (func (export "thepast1") (param $a f64) (param $b f64) (param $c f64) (result f64)
+    (f64.sub (f64.mul (local.get $a) (local.get $b)) (local.get $c))
+  )
+
+  (func (export "thepast2") (param $a f32) (param $b f32) (param $c f32) (result f32)
+    (f32.mul (f32.mul (local.get $a) (local.get $b)) (local.get $c))
+  )
+)
+
+(assert_return (invoke "thepast0" (f64.const 0x1p-1021) (f64.const 0x1.fffffffffffffp-1) (f64.const 0x1p1) (f64.const 0x1p-1)) (f64.const 0x1.fffffffffffffp-1022))
+(assert_return (invoke "thepast1" (f64.const 0x1p-54) (f64.const 0x1.fffffffffffffp-1) (f64.const 0x1p-54)) (f64.const -0x1p-107))
+(assert_return (invoke "thepast2" (f32.const 0x1p-125) (f32.const 0x1p-1) (f32.const 0x1p0)) (f32.const 0x1p-126))
+
+;; Test for floating point tolerances observed in some GPUs.
+;; https://community.amd.com/thread/145582
+
+(module
+  (func (export "inverse") (param $x f32) (result f32)
+    (f32.div (f32.const 1.0) (local.get $x))
+  )
+)
+
+(assert_return (invoke "inverse" (f32.const 96.0)) (f32.const 0x1.555556p-7))
+
+;; Test for incorrect rounding on sqrt(4.0).
+;; http://www.askvg.com/microsoft-windows-calculator-bug/
+
+(module
+  (func (export "f32_sqrt_minus_2") (param $x f32) (result f32)
+    (f32.sub (f32.sqrt (local.get $x)) (f32.const 2.0))
+  )
+
+  (func (export "f64_sqrt_minus_2") (param $x f64) (result f64)
+    (f64.sub (f64.sqrt (local.get $x)) (f64.const 2.0))
+  )
+)
+
+(assert_return (invoke "f32_sqrt_minus_2" (f32.const 4.0)) (f32.const 0.0))
+(assert_return (invoke "f64_sqrt_minus_2" (f64.const 4.0)) (f64.const 0.0))
+
+;; Test that 1.0 / (1.0 / x) is not optimized to x.
+
+(module
+  (func (export "f32.no_fold_recip_recip") (param $x f32) (result f32)
+    (f32.div (f32.const 1.0) (f32.div (f32.const 1.0) (local.get $x))))
+
+  (func (export "f64.no_fold_recip_recip") (param $x f64) (result f64)
+    (f64.div (f64.const 1.0) (f64.div (f64.const 1.0) (local.get $x))))
+)
+
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const -0x1.e8bf18p+65)) (f32.const -0x1.e8bf16p+65))
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const 0x1.e24248p-77)) (f32.const 0x1.e24246p-77))
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const 0x1.caf0e8p-64)) (f32.const 0x1.caf0eap-64))
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const -0x1.e66982p+4)) (f32.const -0x1.e66984p+4))
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const 0x1.f99916p+70)) (f32.const 0x1.f99914p+70))
+
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const -0x0p+0)) (f32.const -0x0p+0))
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const 0x0p+0)) (f32.const 0x0p+0))
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "f32.no_fold_recip_recip" (f32.const infinity)) (f32.const infinity))
+
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const -0x1.d81248dda63dp+148)) (f64.const -0x1.d81248dda63d1p+148))
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const -0x1.f4750312039e3p+66)) (f64.const -0x1.f4750312039e2p+66))
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const 0x1.fa50630eec7f6p+166)) (f64.const 0x1.fa50630eec7f5p+166))
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const 0x1.db0598617ba92p-686)) (f64.const 0x1.db0598617ba91p-686))
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const 0x1.85f1638a0c82bp+902)) (f64.const 0x1.85f1638a0c82ap+902))
+
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const -0x0p+0)) (f64.const -0x0p+0))
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const 0x0p+0)) (f64.const 0x0p+0))
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const -infinity)) (f64.const -infinity))
+(assert_return (invoke "f64.no_fold_recip_recip" (f64.const infinity)) (f64.const infinity))
+
+;; Test that (x+y) * (x-y) is not optimized to x*x - y*y.
+
+(module
+  (func (export "f32.no_algebraic_factoring") (param $x f32) (param $y f32) (result f32)
+    (f32.mul (f32.add (local.get $x) (local.get $y))
+             (f32.sub (local.get $x) (local.get $y))))
+
+  (func (export "f64.no_algebraic_factoring") (param $x f64) (param $y f64) (result f64)
+    (f64.mul (f64.add (local.get $x) (local.get $y))
+             (f64.sub (local.get $x) (local.get $y))))
+)
+
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const -0x1.ef678ep-55) (f32.const 0x1.c160b8p-54)) (f32.const -0x1.129402p-107))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const -0x1.2d76bcp+24) (f32.const 0x1.f4089cp+24)) (f32.const -0x1.36d89ap+49))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const 0x1.7ca2b2p+45) (f32.const -0x1.08513cp+47)) (f32.const -0x1.db10dep+93))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const 0x1.7d5e3p+17) (f32.const -0x1.c783b4p+7)) (f32.const 0x1.1c10a6p+35))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const -0x1.daf96p+7) (f32.const -0x1.dac6bp+19)) (f32.const -0x1.b8422ep+39))
+
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const 0x1.e17c0a02ac6b5p-476) (f64.const 0x1.e8f13f1fcdc14p-463)) (f64.const -0x1.d2ec518f62863p-925))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const 0x1.971b55a57e3a3p-377) (f64.const 0x1.edeb4233c1b27p-399)) (f64.const 0x1.43b3f69fb258bp-753))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const -0x1.c3b9dc02472fap-378) (f64.const -0x1.74e9faebaff14p-369)) (f64.const -0x1.0f9c07e8caa25p-737))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const -0x1.afaf4688ed019p+179) (f64.const 0x1.b07171cb49e94p+188)) (f64.const -0x1.6d3f2e2bebcf7p+377))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const 0x1.4377a98948f12p+114) (f64.const -0x1.500c05bd24c97p+90)) (f64.const 0x1.98b72dbf7bf72p+228))
+
+;; Test that x*x - y*y is not optimized to (x+y) * (x-y).
+
+(module
+  (func (export "f32.no_algebraic_factoring") (param $x f32) (param $y f32) (result f32)
+    (f32.sub (f32.mul (local.get $x) (local.get $x))
+             (f32.mul (local.get $y) (local.get $y))))
+
+  (func (export "f64.no_algebraic_factoring") (param $x f64) (param $y f64) (result f64)
+    (f64.sub (f64.mul (local.get $x) (local.get $x))
+             (f64.mul (local.get $y) (local.get $y))))
+)
+
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const 0x1.8e2c14p-46) (f32.const 0x1.bad59ap-39)) (f32.const -0x1.7efe5p-77))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const -0x1.7ef192p+41) (f32.const -0x1.db184ap+33)) (f32.const 0x1.1e6932p+83))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const 0x1.7eb458p-12) (f32.const -0x1.52c498p-13)) (f32.const 0x1.cc0bc6p-24))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const 0x1.2675c6p-44) (f32.const -0x1.edd31ap-46)) (f32.const 0x1.17294cp-88))
+(assert_return (invoke "f32.no_algebraic_factoring" (f32.const 0x1.9a5f92p+51) (f32.const -0x1.2b0098p+52)) (f32.const -0x1.7189a6p+103))
+
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const 0x1.749a128f18f69p+356) (f64.const -0x1.0bc97ee1354e1p+337)) (f64.const 0x1.0f28115518d74p+713))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const -0x1.2dab01b2215eap+309) (f64.const -0x1.e12b288bff2bdp+331)) (f64.const -0x1.c4319ad25d201p+663))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const 0x1.3ed898431e102p+42) (f64.const -0x1.c409183fa92e6p+39)) (f64.const 0x1.80a611103c71dp+84))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const -0x1.be663e4c0e4b2p+182) (f64.const -0x1.da85703760d25p+166)) (f64.const 0x1.853434f1a2ffep+365))
+(assert_return (invoke "f64.no_algebraic_factoring" (f64.const -0x1.230e09952df1cp-236) (f64.const -0x1.fa2752adfadc9p-237)) (f64.const 0x1.42e43156bd1b8p-474))
+
+;; Test that plain summation is not reassociated, and that Kahan summation
+;; isn't optimized into plain summation.
+
+(module
+  (memory (data
+    "\c4\c5\57\24\a5\84\c8\0b\6d\b8\4b\2e\f2\76\17\1c\ca\4a\56\1e\1b\6e\71\22"
+    "\5d\17\1e\6e\bf\cd\14\5c\c7\21\55\51\39\9c\1f\b2\51\f0\a3\93\d7\c1\2c\ae"
+    "\7e\a8\28\3a\01\21\f4\0a\58\93\f8\42\77\9f\83\39\6a\5f\ba\f7\0a\d8\51\6a"
+    "\34\ca\ad\c6\34\0e\d8\26\dc\4c\33\1c\ed\29\90\a8\78\0f\d1\ce\76\31\23\83"
+    "\b8\35\e8\f2\44\b0\d3\a1\fc\bb\32\e1\b0\ba\69\44\09\d6\d9\7d\ff\2e\c0\5a"
+    "\36\14\33\14\3e\a9\fa\87\6d\8b\bc\ce\9d\a7\fd\c4\e9\85\3f\dd\d7\e1\18\a6"
+    "\50\26\72\6e\3f\73\0f\f8\12\93\23\34\61\76\12\48\c0\9b\05\93\eb\ac\86\de"
+    "\94\3e\55\e8\8c\e8\dd\e4\fc\95\47\be\56\03\21\20\4c\e6\bf\7b\f6\7f\d5\ba"
+    "\73\1c\c1\14\8f\c4\27\96\b3\bd\33\ff\78\41\5f\c0\5a\ce\f6\67\6e\73\9a\17"
+    "\66\70\03\f8\ce\27\a3\52\b2\9f\3b\bf\fb\ae\ed\d3\5a\f8\37\57\f0\f5\6e\ef"
+    "\b1\4d\70\3d\54\a7\01\9a\85\08\48\91\f5\9d\0c\60\87\5b\d9\54\1e\51\6d\88"
+    "\8e\08\8c\a5\71\3a\56\08\67\46\8f\8f\13\2a\2c\ec\2c\1f\b4\62\2b\6f\41\0a"
+    "\c4\65\42\a2\31\6b\2c\7d\3e\bb\75\ac\86\97\30\d9\48\cd\9a\1f\56\c4\c6\e4"
+    "\12\c0\9d\fb\ee\02\8c\ce\1c\f2\1e\a1\78\23\db\c4\1e\49\03\d3\71\cc\08\50"
+    "\c5\d8\5c\ed\d5\b5\65\ac\b5\c9\21\d2\c9\29\76\de\f0\30\1a\5b\3c\f2\3b\db"
+    "\3a\39\82\3a\16\08\6f\a8\f1\be\69\69\99\71\a6\05\d3\14\93\2a\16\f2\2f\11"
+    "\c7\7e\20\bb\91\44\ee\f8\e4\01\53\c0\b9\7f\f0\bf\f0\03\9c\6d\b1\df\a2\44"
+    "\01\6d\6b\71\2b\5c\b3\21\19\46\5e\8f\db\91\d3\7c\78\6b\b7\12\00\8f\eb\bd"
+    "\8a\f5\d4\2e\c4\c1\1e\df\73\63\59\47\49\03\0a\b7\cf\24\cf\9c\0e\44\7a\9e"
+    "\14\fb\42\bf\9d\39\30\9e\a0\ab\2f\d1\ae\9e\6a\83\43\e3\55\7d\85\bf\63\8a"
+    "\f8\96\10\1f\fe\6d\e7\22\1b\e1\69\46\8a\44\c8\c8\f9\0c\2b\19\07\a5\02\3e"
+    "\f2\30\10\9a\85\8a\5f\ef\81\45\a0\77\b1\03\10\73\4b\ae\98\9d\47\bf\9a\2d"
+    "\3a\d5\0f\03\66\e3\3d\53\d9\40\ce\1f\6f\32\2f\21\2b\23\21\6c\62\d4\a7\3e"
+    "\a8\ce\28\31\2d\00\3d\67\5e\af\a0\cf\2e\d2\b9\6b\84\eb\69\08\3c\62\36\be"
+    "\12\fd\36\7f\88\3e\ad\bc\0b\c0\41\c4\50\b6\e3\50\31\e8\ce\e2\96\65\55\9c"
+    "\16\46\e6\b0\2d\3a\e8\81\05\b0\bf\34\f7\bc\10\1c\fb\cc\3c\f1\85\97\42\9f"
+    "\eb\14\8d\3c\bf\d7\17\88\49\9d\8b\2b\b2\3a\83\d1\4f\04\9e\a1\0f\ad\08\9d"
+    "\54\af\d1\82\c3\ec\32\2f\02\8f\05\21\2d\a2\b7\e4\f4\6f\2e\81\2b\0b\9c\fc"
+    "\cb\fe\74\02\f9\db\f4\f3\ea\00\a8\ec\d1\99\74\26\dd\d6\34\d5\25\b1\46\dd"
+    "\9c\aa\71\f5\60\b0\88\c8\e0\0b\59\5a\25\4f\29\66\f9\e3\2e\fe\e9\da\e5\18"
+    "\4f\27\62\f4\ce\a4\21\95\74\c7\57\64\27\9a\4c\fd\54\7d\61\ce\c3\ac\87\46"
+    "\9c\fa\ff\09\ca\79\97\67\24\74\ca\d4\21\83\26\25\19\12\37\64\19\e5\65\e0"
+    "\74\75\8e\dd\c8\ef\74\c7\d8\21\2b\79\04\51\46\65\60\03\5d\fa\d8\f4\65\a4"
+    "\9e\5d\23\da\d7\8a\92\80\a4\de\78\3c\f1\57\42\6d\cd\c9\2f\d5\a4\9e\ab\40"
+    "\f4\cb\1b\d7\a3\ca\fc\eb\a7\01\b2\9a\69\4e\46\9b\18\4e\dd\79\a7\aa\a6\52"
+    "\39\1e\ef\30\cc\9b\bd\5b\ee\4c\21\6d\30\00\72\b0\46\5f\08\cf\c5\b9\e0\3e"
+    "\c2\b3\0c\dc\8e\64\de\19\42\79\cf\43\ea\43\5d\8e\88\f7\ab\15\dc\3f\c8\67"
+    "\20\db\b8\64\b1\47\1f\de\f2\cb\3f\59\9f\d8\46\90\dc\ae\2f\22\f9\e2\31\89"
+    "\d9\9c\1c\4c\d3\a9\4a\57\84\9c\9f\ea\2c\3c\ae\3c\c3\1e\8b\e5\4e\17\01\25"
+    "\db\34\46\5f\15\ea\05\0c\7c\d9\45\8c\19\d0\73\8a\96\16\dd\44\f9\05\b7\5b"
+    "\71\b0\e6\21\36\5f\75\89\91\73\75\ab\7d\ae\d3\73\ec\37\c6\ea\55\75\ef\ea"
+    "\ab\8b\7b\11\dc\6d\1a\b2\6a\c4\25\cf\aa\e3\9f\49\49\89\cb\37\9b\0a\a7\01"
+    "\60\70\dc\b7\c8\83\e1\42\f5\be\ad\62\94\ad\8d\a1"
+  ))
+
+  (func (export "f32.kahan_sum") (param $p i32) (param $n i32) (result f32)
+    (local $sum f32)
+    (local $c f32)
+    (local $t f32)
+    (block $exit
+      (loop $top
+        (local.set $t
+          (f32.sub
+            (f32.sub
+              (local.tee $sum
+                (f32.add
+                  (local.get $c)
+                  (local.tee $t
+                    (f32.sub (f32.load (local.get $p)) (local.get $t))
+                  )
+                )
+              )
+              (local.get $c)
+            )
+            (local.get $t)
+          )
+        )
+        (local.set $p (i32.add (local.get $p) (i32.const 4)))
+        (local.set $c (local.get $sum))
+        (br_if $top (local.tee $n (i32.add (local.get $n) (i32.const -1))))
+      )
+    )
+    (local.get $sum)
+  )
+
+  (func (export "f32.plain_sum") (param $p i32) (param $n i32) (result f32)
+    (local $sum f32)
+    (block $exit
+      (loop $top
+        (local.set $sum (f32.add (local.get $sum) (f32.load (local.get $p))))
+        (local.set $p (i32.add (local.get $p) (i32.const 4)))
+        (local.set $n (i32.add (local.get $n) (i32.const -1)))
+        (br_if $top (local.get $n))
+      )
+    )
+    (local.get $sum)
+  )
+)
+
+(assert_return (invoke "f32.kahan_sum" (i32.const 0) (i32.const 256)) (f32.const -0x1.101a1ap+104))
+(assert_return (invoke "f32.plain_sum" (i32.const 0) (i32.const 256)) (f32.const -0x1.a0343ap+103))
+
+(module
+  (memory (data "\13\05\84\42\5d\a2\2c\c6\43\db\55\a9\cd\da\55\e3\73\fc\58\d6\ba\d5\00\fd\83\35\42\88\8b\13\5d\38\4a\47\0d\72\73\a1\1a\ef\c4\45\17\57\d8\c9\46\e0\8d\6c\e1\37\70\c8\83\5b\55\5e\5a\2d\73\1e\56\c8\e1\6d\69\14\78\0a\8a\5a\64\3a\09\c7\a8\87\c5\f0\d3\5d\e6\03\fc\93\be\26\ca\d6\a9\91\60\bd\b0\ed\ae\f7\30\7e\92\3a\6f\a7\59\8e\aa\7d\bf\67\58\2a\54\f8\4e\fe\ed\35\58\a6\51\bf\42\e5\4b\66\27\24\6d\7f\42\2d\28\92\18\ec\08\ae\e7\55\da\b1\a6\65\a5\72\50\47\1b\b8\a9\54\d7\a6\06\5b\0f\42\58\83\8a\17\82\c6\10\43\a0\c0\2e\6d\bc\5a\85\53\72\7f\ad\44\bc\30\3c\55\b2\24\9a\74\3a\9e\e1\d8\0f\70\fc\a9\3a\cd\93\4b\ec\e3\7e\dd\5d\27\cd\f8\a0\9d\1c\11\c0\57\2e\fd\c8\13\32\cc\3a\1a\7d\a3\41\55\ed\c3\82\49\2a\04\1e\ef\73\b9\2e\2e\e3\5f\f4\df\e6\b2\33\0c\39\3f\6f\44\6a\03\c1\42\b9\fa\b1\c8\ed\a5\58\99\7f\ed\b4\72\9e\79\eb\fb\43\82\45\aa\bb\95\d2\ff\28\9e\f6\a1\ad\95\d6\55\95\0d\6f\60\11\c7\78\3e\49\f2\7e\48\f4\a2\71\d0\13\8e\b3\de\99\52\e3\45\74\ea\76\0e\1b\2a\c8\ee\14\01\c4\50\5b\36\3c\ef\ba\72\a2\a6\08\f8\7b\36\9d\f9\ef\0b\c7\56\2d\5c\f0\9d\5d\de\fc\b8\ad\0f\64\0e\97\15\32\26\c2\31\e6\05\1e\ef\cb\17\1b\6d\15\0b\74\5d\d3\2e\f8\6b\86\b4\ba\73\52\53\99\a9\76\20\45\c9\40\80\6b\14\ed\a1\fa\80\46\e6\26\d2\e6\98\c4\57\bf\c4\1c\a4\90\7a\36\94\14\ba\15\89\6e\e6\9c\37\8c\f4\de\12\22\5d\a1\79\50\67\0d\3d\7a\e9\d4\aa\2e\7f\2a\7a\30\3d\ea\5d\12\48\fe\e1\18\cd\a4\57\a2\87\3e\b6\9a\8b\db\da\9d\78\9c\cf\8d\b1\4f\90\b4\34\e0\9d\f6\ca\fe\4c\3b\78\6d\0a\5c\18\9f\61\b9\dd\b4\e0\0f\76\e0\1b\69\0d\5e\58\73\70\5e\0e\2d\a1\7d\ff\20\eb\91\34\92\ac\38\72\2a\1f\8e\71\2e\6a\f1\af\c7\27\70\d9\c4\57\f7\d2\3c\1d\b8\f0\f0\64\cf\dc\ae\be\a3\cc\3e\22\7d\4e\69\21\63\17\ed\03\02\54\9a\0f\50\4e\13\5a\35\a1\22\a4\df\86\c2\74\79\16\b8\69\69\a0\52\5d\11\64\bd\5b\93\fc\69\a0\f4\13\d0\81\51\dd\fa\0c\15\c3\7a\c9\62\7a\a9\1d\c9\e6\5a\b3\5b\97\02\3c\64\22\12\3c\22\90\64\2d\30\54\4c\b4\a1\22\09\57\22\5e\8e\38\2b\02\a8\ae\f6\be\0d\2b\f2\03\ad\fa\10\01\71\77\2a\30\02\95\f6\00\3e\d0\c4\8d\34\19\50\21\0a\bc\50\da\3c\30\d6\3a\31\94\8d\3a\fe\ef\14\57\9d\4b\93\00\96\24\0c\6f\fd\bc\23\76\02\6c\eb\52\72\80\11\7e\80\3a\13\12\38\1d\38\49\95\40\27\8a\44\7b\e8\dc\6d\8c\8c\8e\3c\b5\b3\18\0e\f6\08\1a\84\41\35\ff\8b\b8\93\40\ea\e1\51\1d\89\a5\8d\42\68\29\ea\2f\c1\7a\52\eb\90\5d\4d\d6\80\e3\d7\75\48\ce\ed\d3\01\1c\8d\5b\a5\94\0d\78\cf\f1\06\13\2f\98\02\a4\6d\2e\6c\f2\d5\74\29\89\4c\f9\03\f5\c7\18\ad\7a\f0\68\f8\5c\d6\59\87\6e\d6\3f\06\be\86\20\e3\41\91\22\f3\6e\8b\f0\68\1c\57\a7\fc\b0\7c\9e\99\0b\96\1a\89\5f\e6\0d\7c\08\51\a0\a2\67\9a\47\00\93\6b\f9\28\f0\68\db\62\f1\e0\65\2c\53\33\e0\a7\ca\11\42\30\f6\af\01\c1\65\3d\32\01\6f\ab\2e\be\d3\8b\be\14\c3\ff\ec\fb\f0\f9\c5\0c\05\6f\01\09\6b\e3\34\31\0c\1f\66\a6\42\bc\1a\87\49\16\16\8c\b0\90\0d\34\8c\0a\e1\09\5e\10\a4\6b\56\cc\f0\c9\bb\dc\b8\5c\ce\f6\cc\8d\75\7e\b3\07\88\04\2f\b4\5e\c9\e3\4a\23\73\19\62\6c\9a\03\76\44\86\9c\60\fc\db\72\8f\27\a0\dd\b3\c5\da\ff\f9\ec\6a\b1\7b\d3\cf\50\37\c9\7a\78\0c\e4\3a\b6\f5\e6\f4\98\6e\42\7d\35\73\8b\45\c0\56\97\cd\6d\ce\cf\ad\31\b3\c3\54\fa\ef\d5\c0\f4\6a\5f\54\e7\49\3e\33\0a\30\38\fd\d9\05\ff\a5\3f\57\46\14\b5\91\17\ca\6b\98\23\7a\65\b3\6c\02\b4\cc\79\5d\58\d8\b3\d5\94\ae\f4\6d\75\65\f7\92\bf\7e\47\4c\3c\ee\db\ac\f1\32\5d\fb\6f\41\1c\34\c8\83\4f\c2\58\01\be\05\3e\66\16\a6\04\6d\5d\4f\86\09\27\82\25\12\cd\3a\cd\ce\6b\bc\ca\ac\28\9b\ee\6a\25\86\9e\45\70\c6\d2\bd\3b\7d\42\e5\27\af\c7\1d\f4\81\c8\b3\76\8a\a8\36\a3\ae\2a\e6\18\e1\36\22\ad\f6\25\72\b0\39\8b\01\9a\22\7b\84\c3\2d\5f\72\a4\98\ac\15\70\e7\d4\18\e2\7d\d2\30\7c\33\08\cd\ca\c4\22\85\88\75\81\c6\4a\74\58\8d\e0\e8\ac\c5\ab\75\5a\f4\28\12\f0\18\45\52\f2\97\b2\93\41\6f\8d\7f\db\70\fb\a3\5d\1f\a7\8d\98\20\2b\22\9f\3a\01\b5\8b\1b\d2\cb\14\03\0e\14\14\d2\19\5a\1f\ce\5e\cd\81\79\15\01\ca\de\73\74\8c\56\20\9f\77\2d\25\16\f6\61\51\1d\a4\8e\9b\98\a5\c6\ec\a8\45\57\82\59\78\0d\90\b4\df\51\b0\c3\82\94\cc\b3\53\09\15\6d\96\6c\3a\40\47\b7\4a\7a\05\2f\a1\1e\8c\9d\a0\20\88\fb\52\b7\9f\f3\f3\bb\5f\e7\8a\61\a7\21\b1\ac\fa\09\aa\a4\6c\bc\24\80\ba\2a\e9\65\ff\70\ff\cc\fa\65\87\76\f3\c5\15\ce\cb\e8\42\31\00\0c\91\57\d9\e0\9d\35\54\24\ad\a4\d8\f9\08\67\63\c8\cf\81\dd\90\a2\d7\c4\07\4a\e6\10\6f\67\e7\27\d4\23\59\18\f2\a8\9d\5f\d8\94\30\aa\54\86\4f\87\9d\82\b5\26\ca\a6\96\bf\cf\55\f9\9d\37\01\19\48\43\c5\94\6c\f3\74\97\58\4c\3c\9d\08\e8\04\c2\58\30\76\e1\a0\f8\ea\e9\c5\ae\cf\78\9e\a9\0c\ac\b3\44\42\e0\bc\5d\1b\9c\49\58\4a\1c\19\49\c1\3a\ea\f5\eb\3b\81\a9\4b\70\0c\cc\9e\1a\d3\2f\b7\52\2f\20\3b\eb\64\51\1d\a0\2d\b2\3e\be\13\85\48\92\32\2e\db\5c\a1\e7\8c\45\91\35\01\0a\93\c2\eb\09\ce\f3\d2\22\24\d0\8c\cc\1d\9d\38\c8\4d\e3\82\cc\64\15\06\2d\e7\01\2f\ab\bb\b5\04\4c\92\1c\7a\d6\3f\e8\5f\31\15\0c\dc\e4\31\b4\c4\25\3e\2a\aa\00\9e\c8\e5\21\7a\7f\29\f1\c0\af\1d\5e\e8\63\39\ad\f8\7e\6c\c8\c5\7f\c2\a8\97\27\0a\d9\f4\21\6a\ea\03\09\fb\f7\96\3b\83\79\5f\7c\4b\30\9f\56\35\de\b4\73\d4\95\f0\14\c3\74\2f\0d\a3\1d\4e\8d\31\24\b3\1a\84\85\62\5a\7b\3c\14\39\17\e6\6d\eb\37\c2\00\58\5b\0b\e3\3c\8a\62\e1\f8\35\4b\56\e2\87\60\8b\be\a7\38\91\77\54\a9\5a\24\25\90\9f\a5\42\77\f3\5c\39\df\ff\74\07\76\a1\cd\1f\62\0b\81\81\68\af\05\c1\c0\7f\26\ee\c0\91\a3\6a\7d\29\61\45\27\e5\57\88\dc\0d\97\04\1a\33\a9\44\8a\da\02\10\45\3f\8e\55\a6\76\8c\4d\e3\f1\89\83\c8\d0\f8\9b\50\77\9f\47\df\4c\9c\66\0d\aa\18\b8\5f\4f\c4\01\ce\dc\84\ac\46\9e\69\e1\76\45\6b\61\89\e4\5d\94\bb\11\83\9f\78\d8\0a\d2\f5\7e\5d\43\ea\bc\10\f1\3a\c9\e2\64\fb\53\65\d0\c7\b4\a7\fb\d4\05\53\25\d0\cd\29\88\00\56\25\24\7d\5d\b4\f3\41\9f\e9\b5\f7\ae\64\2c\e3\c9\6d\d5\84\3a\72\12\b8\7a\d9\1b\09\e8\38\da\26\4f\04\ce\03\71\6e\8a\44\7b\5c\81\59\9c\d2\e4\c3\ba\59\a6\e5\28\a7\8f\9a\e4\d5\4e\b9\ca\7f\cb\75\b8\2b\43\3e\b3\15\46\b1\a5\bc\9d\9e\38\15\f1\bd\1b\21\aa\f1\82\00\95\fc\a7\77\47\39\a7\33\43\92\d7\52\40\4b\06\81\8a\a0\bd\f1\6b\99\84\42\5b\e2\3b\c5\5e\12\5c\28\4d\b6\0e\4e\c8\5c\e8\01\8a\c5\e7\e4\9d\42\ee\5d\9c\c4\eb\eb\68\09\27\92\95\9a\11\54\73\c4\12\80\fb\7d\fe\c5\08\60\7f\36\41\e0\10\ba\d6\2b\6c\f1\b4\17\fe\26\34\e3\4b\f8\a8\e3\91\be\4f\2a\fc\da\81\b8\e7\fe\d5\26\50\47\f3\1a\65\32\81\e0\05\b8\4f\32\31\26\00\4a\53\97\c2\c3\0e\2e\a1\26\54\ab\05\8e\56\2f\7d\af\22\84\68\a5\8b\97\f6\a4\fd\a8\cc\75\41\96\86\fd\27\3d\29\86\8d\7f\4c\d4\8e\73\41\f4\1e\e2\dd\58\27\97\ce\9c\94\cf\7a\04\2f\dc\ed"
+  ))
+
+  (func (export "f64.kahan_sum") (param $p i32) (param $n i32) (result f64)
+    (local $sum f64)
+    (local $c f64)
+    (local $t f64)
+    (block $exit
+      (loop $top
+        (local.set $t
+          (f64.sub
+            (f64.sub
+              (local.tee $sum
+                (f64.add
+                  (local.get $c)
+                  (local.tee $t
+                    (f64.sub (f64.load (local.get $p)) (local.get $t))
+                  )
+                )
+              )
+              (local.get $c)
+            )
+            (local.get $t)
+          )
+        )
+        (local.set $p (i32.add (local.get $p) (i32.const 8)))
+        (local.set $c (local.get $sum))
+        (br_if $top (local.tee $n (i32.add (local.get $n) (i32.const -1))))
+      )
+    )
+    (local.get $sum)
+  )
+
+  (func (export "f64.plain_sum") (param $p i32) (param $n i32) (result f64)
+    (local $sum f64)
+    (block $exit
+      (loop $top
+        (local.set $sum (f64.add (local.get $sum) (f64.load (local.get $p))))
+        (local.set $p (i32.add (local.get $p) (i32.const 8)))
+        (local.set $n (i32.add (local.get $n) (i32.const -1)))
+        (br_if $top (local.get $n))
+      )
+    )
+    (local.get $sum)
+  )
+)
+
+(assert_return (invoke "f64.kahan_sum" (i32.const 0) (i32.const 256)) (f64.const 0x1.dd7cb2a5ffc88p+998))
+(assert_return (invoke "f64.plain_sum" (i32.const 0) (i32.const 256)) (f64.const 0x1.dd7cb2a63fc87p+998))
+
+;; Test that -(x - y) is not folded to y - x.
+
+(module
+  (func (export "f32.no_fold_neg_sub") (param $x f32) (param $y f32) (result f32)
+    (f32.neg (f32.sub (local.get $x) (local.get $y))))
+
+  (func (export "f64.no_fold_neg_sub") (param $x f64) (param $y f64) (result f64)
+    (f64.neg (f64.sub (local.get $x) (local.get $y))))
+)
+
+(assert_return (invoke "f32.no_fold_neg_sub" (f32.const -0.0) (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_neg_sub" (f32.const 0.0) (f32.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.no_fold_neg_sub" (f32.const -0.0) (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_neg_sub" (f32.const 0.0) (f32.const 0.0)) (f32.const -0.0))
+
+(assert_return (invoke "f64.no_fold_neg_sub" (f64.const -0.0) (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_neg_sub" (f64.const 0.0) (f64.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.no_fold_neg_sub" (f64.const -0.0) (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_neg_sub" (f64.const 0.0) (f64.const 0.0)) (f64.const -0.0))
+
+;; Test that -x + x is not folded to 0.0.
+
+(module
+  (func (export "f32.no_fold_add_neg") (param $x f32) (result f32)
+    (f32.add (f32.neg (local.get $x)) (local.get $x)))
+
+  (func (export "f64.no_fold_add_neg") (param $x f64) (result f64)
+    (f64.add (f64.neg (local.get $x)) (local.get $x)))
+)
+
+(assert_return (invoke "f32.no_fold_add_neg" (f32.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.no_fold_add_neg" (f32.const -0.0)) (f32.const 0.0))
+(assert_return_nan (invoke "f32.no_fold_add_neg" (f32.const infinity)))
+(assert_return_nan (invoke "f32.no_fold_add_neg" (f32.const -infinity)))
+
+(assert_return (invoke "f64.no_fold_add_neg" (f64.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.no_fold_add_neg" (f64.const -0.0)) (f64.const 0.0))
+(assert_return_nan (invoke "f64.no_fold_add_neg" (f64.const infinity)))
+(assert_return_nan (invoke "f64.no_fold_add_neg" (f64.const -infinity)))
+
+;; Test that x+x+x+x+x+x is not folded to x * 6.
+
+(module
+  (func (export "f32.no_fold_6x_via_add") (param $x f32) (result f32)
+    (f32.add (f32.add (f32.add (f32.add (f32.add
+    (local.get $x)
+    (local.get $x)) (local.get $x)) (local.get $x))
+    (local.get $x)) (local.get $x)))
+
+  (func (export "f64.no_fold_6x_via_add") (param $x f64) (result f64)
+    (f64.add (f64.add (f64.add (f64.add (f64.add
+    (local.get $x)
+    (local.get $x)) (local.get $x)) (local.get $x))
+    (local.get $x)) (local.get $x)))
+)
+
+(assert_return (invoke "f32.no_fold_6x_via_add" (f32.const -0x1.598a0cp+99)) (f32.const -0x1.03278ap+102))
+(assert_return (invoke "f32.no_fold_6x_via_add" (f32.const -0x1.d3e7acp-77)) (f32.const -0x1.5eedc2p-74))
+(assert_return (invoke "f32.no_fold_6x_via_add" (f32.const 0x1.00fa02p-77)) (f32.const 0x1.817702p-75))
+(assert_return (invoke "f32.no_fold_6x_via_add" (f32.const -0x1.51f434p-31)) (f32.const -0x1.faee4cp-29))
+(assert_return (invoke "f32.no_fold_6x_via_add" (f32.const -0x1.00328ap+80)) (f32.const -0x1.804bcep+82))
+
+(assert_return (invoke "f64.no_fold_6x_via_add" (f64.const -0x1.310e15acaffe6p+68)) (f64.const -0x1.c995208307fdap+70))
+(assert_return (invoke "f64.no_fold_6x_via_add" (f64.const -0x1.aad62c78fa9b4p-535)) (f64.const -0x1.4020a15abbf46p-532))
+(assert_return (invoke "f64.no_fold_6x_via_add" (f64.const -0x1.f8fbfa94f6ab2p+271)) (f64.const -0x1.7abcfbefb9005p+274))
+(assert_return (invoke "f64.no_fold_6x_via_add" (f64.const 0x1.756ccc2830a8ep+751)) (f64.const 0x1.1811991e247ebp+754))
+(assert_return (invoke "f64.no_fold_6x_via_add" (f64.const -0x1.8fd1ab1d2402ap+234)) (f64.const -0x1.2bdd4055db01fp+237))
+
+;; Test that (x/y)/z is not optimized to x/(y*z),
+;; which is an "allowable alternative Form" in Fortran.
+
+(module
+  (func (export "f32.no_fold_div_div") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.div (f32.div (local.get $x) (local.get $y)) (local.get $z)))
+
+  (func (export "f64.no_fold_div_div") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.div (f64.div (local.get $x) (local.get $y)) (local.get $z)))
+)
+
+(assert_return (invoke "f32.no_fold_div_div" (f32.const -0x1.f70228p+78) (f32.const -0x1.fbc612p-16) (f32.const -0x1.8c379p+10)) (f32.const -0x1.47b43cp+83))
+(assert_return (invoke "f32.no_fold_div_div" (f32.const 0x1.d29d2ep-70) (f32.const 0x1.f3a17ep+110) (f32.const -0x1.64d41p-112)) (f32.const -0x0p+0))
+(assert_return (invoke "f32.no_fold_div_div" (f32.const 0x1.867f98p+43) (f32.const 0x1.30acfcp-105) (f32.const 0x1.e210d8p+105)) (f32.const infinity))
+(assert_return (invoke "f32.no_fold_div_div" (f32.const -0x1.c4001ap-14) (f32.const -0x1.9beb6cp+124) (f32.const -0x1.74f34cp-43)) (f32.const -0x1.819874p-96))
+(assert_return (invoke "f32.no_fold_div_div" (f32.const 0x1.db0e6ep+46) (f32.const 0x1.55eea2p+56) (f32.const -0x1.f3134p+124)) (f32.const -0x1.6cep-135))
+
+(assert_return (invoke "f64.no_fold_div_div" (f64.const 0x1.b4dc8ec3c7777p+337) (f64.const 0x1.9f95ac2d1863p+584) (f64.const -0x1.d4318abba341ep-782)) (f64.const -0x1.2649159d87e02p+534))
+(assert_return (invoke "f64.no_fold_div_div" (f64.const -0x1.ac53af5eb445fp+791) (f64.const 0x1.8549c0a4ceb13p-29) (f64.const 0x1.64e384003c801p+316)) (f64.const -0x1.9417cdccbae91p+503))
+(assert_return (invoke "f64.no_fold_div_div" (f64.const -0x1.d2685afb27327p+2) (f64.const -0x1.abb1eeed3dbebp+880) (f64.const 0x1.a543e2e6968a3p+170)) (f64.const 0x0.0000002a69a5fp-1022))
+(assert_return (invoke "f64.no_fold_div_div" (f64.const -0x1.47ddede78ad1cp+825) (f64.const 0x1.6d932d070a367p-821) (f64.const 0x1.79cf18cc64fp+961)) (f64.const -infinity))
+(assert_return (invoke "f64.no_fold_div_div" (f64.const -0x1.f73d4979a9379p-888) (f64.const 0x1.4d83b53e97788p-596) (f64.const -0x1.f8f86c9603b5bp-139)) (f64.const 0x1.87a7bd89c586cp-154))
+
+;; Test that (x/y)*(z/w) is not optimized to (x*z)/(y*w), example from
+;; http://perso.ens-lyon.fr/jean-michel.muller/Handbook.html
+;; section 7.4.1: FORTRAN Floating Point in a Nutshell: Philosophy
+
+(module
+  (func (export "f32.no_fold_mul_divs") (param $x f32) (param $y f32) (param $z f32) (param $w f32) (result f32)
+    (f32.mul (f32.div (local.get $x) (local.get $y)) (f32.div (local.get $z) (local.get $w))))
+
+  (func (export "f64.no_fold_mul_divs") (param $x f64) (param $y f64) (param $z f64) (param $w f64) (result f64)
+    (f64.mul (f64.div (local.get $x) (local.get $y)) (f64.div (local.get $z) (local.get $w))))
+)
+
+(assert_return (invoke "f32.no_fold_mul_divs" (f32.const -0x1.c483bep-109) (f32.const 0x1.ee1c3cp-92) (f32.const 0x1.800756p-88) (f32.const -0x1.95b972p+4)) (f32.const 0x1.bbd30cp-110))
+(assert_return (invoke "f32.no_fold_mul_divs" (f32.const -0x1.0f4262p+102) (f32.const 0x1.248498p+25) (f32.const 0x1.f66a7cp-17) (f32.const 0x1.897fc8p-3)) (f32.const -0x1.2f1aa4p+63))
+(assert_return (invoke "f32.no_fold_mul_divs" (f32.const -0x1.df5f22p+33) (f32.const -0x1.fcee3ep+39) (f32.const -0x1.9ea914p+29) (f32.const -0x1.2c4d3p+10)) (f32.const 0x1.4cf51cp+13))
+(assert_return (invoke "f32.no_fold_mul_divs" (f32.const -0x1.f568bcp+109) (f32.const 0x1.d9963p-34) (f32.const 0x1.37a87ap-16) (f32.const 0x1.a1524ap+78)) (f32.const -infinity))
+(assert_return (invoke "f32.no_fold_mul_divs" (f32.const 0x1.3dd592p-53) (f32.const -0x1.332c22p-64) (f32.const 0x1.b01064p-91) (f32.const 0x1.92bb3ap-36)) (f32.const -0x1.1c2dbp-44))
+
+(assert_return (invoke "f64.no_fold_mul_divs" (f64.const -0x1.363d6764f7b12p-819) (f64.const -0x1.ed5471f660b5fp-464) (f64.const -0x1.671b0a7f3a42p+547) (f64.const 0x1.0633be34ba1f2p+186)) (f64.const -0x1.b8fa2b76baeebp+5))
+(assert_return (invoke "f64.no_fold_mul_divs" (f64.const -0x1.37880182e0fa8p+115) (f64.const 0x1.f842631576147p-920) (f64.const -0x1.999372231d156p+362) (f64.const -0x1.d5db481ab9554p+467)) (f64.const -infinity))
+(assert_return (invoke "f64.no_fold_mul_divs" (f64.const -0x1.9a747c8d4b541p+308) (f64.const -0x1.99092ad6bbdc8p+192) (f64.const -0x1.cb23755c20101p-140) (f64.const -0x1.de8716f6b0b6ap+732)) (f64.const 0x1.ecf584c8466a5p-757))
+(assert_return (invoke "f64.no_fold_mul_divs" (f64.const -0x1.c424b2ece903dp+129) (f64.const -0x1.568ce281db37fp-347) (f64.const 0x1.53900b99fd3dp-957) (f64.const 0x1.5c33952254dadp+223)) (f64.const 0x0p+0))
+(assert_return (invoke "f64.no_fold_mul_divs" (f64.const 0x1.a8ec2cecb32a9p-18) (f64.const 0x1.58acab0051851p-277) (f64.const 0x1.35e87c9077f7fp-620) (f64.const -0x1.925ee37ffb386p+352)) (f64.const -0x1.e6286970b31bfp-714))
+
+;; Test that (x/z)+(y/z) is not optimized to (x+y)/z.
+
+(module
+  (func (export "f32.no_fold_add_divs") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.add (f32.div (local.get $x) (local.get $z)) (f32.div (local.get $y) (local.get $z))))
+
+  (func (export "f64.no_fold_add_divs") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.add (f64.div (local.get $x) (local.get $z)) (f64.div (local.get $y) (local.get $z))))
+)
+
+(assert_return (invoke "f32.no_fold_add_divs" (f32.const 0x1.795e7p+8) (f32.const -0x1.48a5eep-5) (f32.const -0x1.9a244cp+126)) (f32.const -0x1.d709b6p-119))
+(assert_return (invoke "f32.no_fold_add_divs" (f32.const -0x1.ae89e8p-63) (f32.const -0x1.e9903ep-49) (f32.const -0x1.370a8cp+47)) (f32.const 0x1.92f3f6p-96))
+(assert_return (invoke "f32.no_fold_add_divs" (f32.const -0x1.626408p-46) (f32.const 0x1.2ee5b2p-64) (f32.const -0x1.ecefaap+48)) (f32.const 0x1.701864p-95))
+(assert_return (invoke "f32.no_fold_add_divs" (f32.const -0x1.061d3p-101) (f32.const 0x1.383492p-98) (f32.const -0x1.1d92d2p+88)) (f32.const 0x0p+0))
+(assert_return (invoke "f32.no_fold_add_divs" (f32.const 0x1.1ea39ep-10) (f32.const 0x1.a7fffep-3) (f32.const 0x1.6fc574p-123)) (f32.const 0x1.28b2dep+120))
+
+(assert_return (invoke "f64.no_fold_add_divs" (f64.const -0x1.c5fcc3273b136p+430) (f64.const 0x1.892a09eed8f6fp+434) (f64.const 0x1.8258b71e64397p+911)) (f64.const 0x1.e36eb9706ad82p-478))
+(assert_return (invoke "f64.no_fold_add_divs" (f64.const -0x1.2215d4061b5b3p+53) (f64.const 0x1.fb6184d97f27cp+5) (f64.const -0x1.f3bb59dacc0ebp-957)) (f64.const 0x1.2934eb0118be3p+1009))
+(assert_return (invoke "f64.no_fold_add_divs" (f64.const -0x1.e7a4533741d8ep-967) (f64.const 0x1.a519bb7feb802p-976) (f64.const 0x1.1f8a43454e51ap+504)) (f64.const 0x0p+0))
+(assert_return (invoke "f64.no_fold_add_divs" (f64.const 0x1.991c6cf93e2b4p+313) (f64.const -0x1.f2f7432698d11p+329) (f64.const 0x1.0d8c1b2453617p-126)) (f64.const -0x1.d9e1d84ddd1d4p+455))
+(assert_return (invoke "f64.no_fold_add_divs" (f64.const -0x1.d436849dc1271p-728) (f64.const 0x1.19d1c1450e52dp-755) (f64.const 0x1.fa1be69ea06fep-70)) (f64.const -0x1.d9a9b1c2f5623p-659))
+
+;; Test that sqrt(x*x) is not optimized to abs(x).
+
+(module
+  (func (export "f32.no_fold_sqrt_square") (param $x f32) (result f32)
+    (f32.sqrt (f32.mul (local.get $x) (local.get $x))))
+
+  (func (export "f64.no_fold_sqrt_square") (param $x f64) (result f64)
+    (f64.sqrt (f64.mul (local.get $x) (local.get $x))))
+)
+
+(assert_return (invoke "f32.no_fold_sqrt_square" (f32.const -0x1.5cb316p-66)) (f32.const 0x1.5cb322p-66))
+(assert_return (invoke "f32.no_fold_sqrt_square" (f32.const -0x1.b0f9e4p-73)) (f32.const 0x1.b211b2p-73))
+(assert_return (invoke "f32.no_fold_sqrt_square" (f32.const -0x1.de417cp-71)) (f32.const 0x1.de65b8p-71))
+(assert_return (invoke "f32.no_fold_sqrt_square" (f32.const 0x1.64c872p-86)) (f32.const 0x0p+0))
+(assert_return (invoke "f32.no_fold_sqrt_square" (f32.const 0x1.e199e4p+108)) (f32.const infinity))
+
+(assert_return (invoke "f64.no_fold_sqrt_square" (f64.const 0x1.1759d657203fdp-529)) (f64.const 0x1.1759dd57545f3p-529))
+(assert_return (invoke "f64.no_fold_sqrt_square" (f64.const -0x1.4c68de1c78d83p-514)) (f64.const 0x1.4c68de1c78d81p-514))
+(assert_return (invoke "f64.no_fold_sqrt_square" (f64.const -0x1.214736edb6e1ep-521)) (f64.const 0x1.214736ed9cf8dp-521))
+(assert_return (invoke "f64.no_fold_sqrt_square" (f64.const -0x1.0864b9f68457p-616)) (f64.const 0x0p+0))
+(assert_return (invoke "f64.no_fold_sqrt_square" (f64.const 0x1.b2a9855995abap+856)) (f64.const infinity))
+
+;; Test that sqrt(x)*sqrt(y) is not optimized to sqrt(x*y).
+
+(module
+  (func (export "f32.no_fold_mul_sqrts") (param $x f32) (param $y f32) (result f32)
+    (f32.mul (f32.sqrt (local.get $x)) (f32.sqrt (local.get $y))))
+
+  (func (export "f64.no_fold_mul_sqrts") (param $x f64) (param $y f64) (result f64)
+    (f64.mul (f64.sqrt (local.get $x)) (f64.sqrt (local.get $y))))
+)
+
+(assert_return_nan (invoke "f32.no_fold_mul_sqrts" (f32.const 0x1.dddda8p-125) (f32.const -0x1.25d22ap-83)))
+(assert_return (invoke "f32.no_fold_mul_sqrts" (f32.const 0x1.418d14p-92) (f32.const 0x1.c6535cp-32)) (f32.const 0x1.7e373ap-62))
+(assert_return (invoke "f32.no_fold_mul_sqrts" (f32.const 0x1.4de7ep-88) (f32.const 0x1.84ff18p+6)) (f32.const 0x1.686668p-41))
+(assert_return (invoke "f32.no_fold_mul_sqrts" (f32.const 0x1.78091ep+101) (f32.const 0x1.81feb8p-9)) (f32.const 0x1.7cfb98p+46))
+(assert_return (invoke "f32.no_fold_mul_sqrts" (f32.const 0x1.583ap-56) (f32.const 0x1.14ba2ap-9)) (f32.const 0x1.b47a8ep-33))
+
+(assert_return_nan (invoke "f64.no_fold_mul_sqrts" (f64.const -0x1.d1144cc28cdbep-635) (f64.const -0x1.bf9bc373d3b6ap-8)))
+(assert_return (invoke "f64.no_fold_mul_sqrts" (f64.const 0x1.5a7eb976bebc9p-643) (f64.const 0x1.f30cb8865a4cap-404)) (f64.const 0x1.260a1032d6e76p-523))
+(assert_return (invoke "f64.no_fold_mul_sqrts" (f64.const 0x1.711a0c1707935p-89) (f64.const 0x1.6fb5de51a20d3p-913)) (f64.const 0x1.7067ca28e31ecp-501))
+(assert_return (invoke "f64.no_fold_mul_sqrts" (f64.const 0x1.fb0bbea33b076p-363) (f64.const 0x1.d963b34894158p-573)) (f64.const 0x1.e9edc1fa624afp-468))
+(assert_return (invoke "f64.no_fold_mul_sqrts" (f64.const 0x1.8676eab7a4d0dp+24) (f64.const 0x1.75a58231ba7a5p+513)) (f64.const 0x1.0e16aebe203b3p+269))
+
+;; Test that sqrt(x)/sqrt(y) is not optimized to sqrt(x/y).
+
+(module
+  (func (export "f32.no_fold_div_sqrts") (param $x f32) (param $y f32) (result f32)
+    (f32.div (f32.sqrt (local.get $x)) (f32.sqrt (local.get $y))))
+
+  (func (export "f64.no_fold_div_sqrts") (param $x f64) (param $y f64) (result f64)
+    (f64.div (f64.sqrt (local.get $x)) (f64.sqrt (local.get $y))))
+)
+
+(assert_return_nan (invoke "f32.no_fold_div_sqrts" (f32.const -0x1.bea9bap+25) (f32.const -0x1.db776ep-58)))
+(assert_return (invoke "f32.no_fold_div_sqrts" (f32.const 0x1.b983b6p+32) (f32.const 0x1.901f1ep+27)) (f32.const 0x1.7c4df6p+2))
+(assert_return (invoke "f32.no_fold_div_sqrts" (f32.const 0x1.d45e72p-120) (f32.const 0x1.ab49ccp+15)) (f32.const 0x1.7b0b04p-68))
+(assert_return (invoke "f32.no_fold_div_sqrts" (f32.const 0x1.b2e444p+59) (f32.const 0x1.5b8b16p-30)) (f32.const 0x1.94fca8p+44))
+(assert_return (invoke "f32.no_fold_div_sqrts" (f32.const 0x1.835aa6p-112) (f32.const 0x1.d17128p-103)) (f32.const 0x1.4a468p-5))
+
+(assert_return_nan (invoke "f64.no_fold_div_sqrts" (f64.const -0x1.509fc16411167p-711) (f64.const -0x1.9c4255f5d6517p-187)))
+(assert_return (invoke "f64.no_fold_div_sqrts" (f64.const 0x1.b6897bddac76p-587) (f64.const 0x1.104578b4c91f3p+541)) (f64.const 0x1.44e4f21f26cc9p-564))
+(assert_return (invoke "f64.no_fold_div_sqrts" (f64.const 0x1.ac83451b08989p+523) (f64.const 0x1.8da575c6d12b8p-109)) (f64.const 0x1.09c003991ce17p+316))
+(assert_return (invoke "f64.no_fold_div_sqrts" (f64.const 0x1.bab7836456417p-810) (f64.const 0x1.1ff60d03ba607p+291)) (f64.const 0x1.c0e6c833bf657p-551))
+(assert_return (invoke "f64.no_fold_div_sqrts" (f64.const 0x1.a957816ad9515p-789) (f64.const 0x1.8c18a3a222ab1p+945)) (f64.const 0x1.0948539781e92p-867))
+
+;; Test that (x*sqrt(y))/y is not optimized to x/sqrt(y).
+
+(module
+  (func (export "f32.no_fold_mul_sqrt_div") (param $x f32) (param $y f32) (result f32)
+    (f32.div (f32.mul (local.get $x) (f32.sqrt (local.get $y))) (local.get $y)))
+
+  (func (export "f64.no_fold_mul_sqrt_div") (param $x f64) (param $y f64) (result f64)
+    (f64.div (f64.mul (local.get $x) (f64.sqrt (local.get $y))) (local.get $y)))
+)
+
+(assert_return (invoke "f32.no_fold_mul_sqrt_div" (f32.const -0x1.f4a7cap+81) (f32.const 0x1.c09adep+92)) (f32.const -infinity))
+(assert_return (invoke "f32.no_fold_mul_sqrt_div" (f32.const -0x1.90bf1cp-120) (f32.const 0x1.8dbe88p-97)) (f32.const -0x0p+0))
+(assert_return (invoke "f32.no_fold_mul_sqrt_div" (f32.const 0x1.8570e8p+29) (f32.const 0x1.217d3p-128)) (f32.const 0x1.6e391ap+93))
+(assert_return (invoke "f32.no_fold_mul_sqrt_div" (f32.const -0x1.5b4652p+43) (f32.const 0x1.a9d71cp+112)) (f32.const -0x1.0d423ap-13))
+(assert_return (invoke "f32.no_fold_mul_sqrt_div" (f32.const -0x1.910604p+8) (f32.const 0x1.0ca912p+7)) (f32.const -0x1.14cdecp+5))
+
+(assert_return (invoke "f64.no_fold_mul_sqrt_div" (f64.const 0x1.1dcdeb857305fp+698) (f64.const 0x1.a066171c40eb9p+758)) (f64.const infinity))
+(assert_return (invoke "f64.no_fold_mul_sqrt_div" (f64.const -0x1.8b4f1c218e2abp-827) (f64.const 0x1.5e1ee65953b0bp-669)) (f64.const -0x0p+0))
+(assert_return (invoke "f64.no_fold_mul_sqrt_div" (f64.const 0x1.74ee531ddba38p-425) (f64.const 0x1.f370f758857f3p+560)) (f64.const 0x1.0aff34269583ep-705))
+(assert_return (invoke "f64.no_fold_mul_sqrt_div" (f64.const -0x1.27f216b0da6c5p+352) (f64.const 0x1.8e0b4e0b9fd7ep-483)) (f64.const -0x1.4fa558aad514ep+593))
+(assert_return (invoke "f64.no_fold_mul_sqrt_div" (f64.const 0x1.4c6955df9912bp+104) (f64.const 0x1.0cca42c9d371ep+842)) (f64.const 0x1.4468072f54294p-317))
+
+;; Test that subnormals are not flushed even in an intermediate value in an
+;; expression with a normal result.
+
+(module
+  (func (export "f32.no_flush_intermediate_subnormal") (param $x f32) (param $y f32) (param $z f32) (result f32)
+    (f32.mul (f32.mul (local.get $x) (local.get $y)) (local.get $z)))
+
+  (func (export "f64.no_flush_intermediate_subnormal") (param $x f64) (param $y f64) (param $z f64) (result f64)
+    (f64.mul (f64.mul (local.get $x) (local.get $y)) (local.get $z)))
+)
+
+(assert_return (invoke "f32.no_flush_intermediate_subnormal" (f32.const 0x1p-126) (f32.const 0x1p-23) (f32.const 0x1p23)) (f32.const 0x1p-126))
+(assert_return (invoke "f64.no_flush_intermediate_subnormal" (f64.const 0x1p-1022) (f64.const 0x1p-52) (f64.const 0x1p52)) (f64.const 0x1p-1022))
+
+;; Test corner cases of John Hauser's microarchitectural recoding scheme.
+;; https://github.com/riscv/riscv-tests/blob/695b86a6fcbe06ffbed8891af7e6fe7bf2062543/isa/rv64uf/recoding.S
+
+(module
+  (func (export "f32.recoding_eq") (param $x f32) (param $y f32) (result i32)
+    (f32.eq (f32.mul (local.get $x) (local.get $y)) (local.get $x)))
+
+  (func (export "f32.recoding_le") (param $x f32) (param $y f32) (result i32)
+    (f32.le (f32.mul (local.get $x) (local.get $y)) (local.get $x)))
+
+  (func (export "f32.recoding_lt") (param $x f32) (param $y f32) (result i32)
+    (f32.lt (f32.mul (local.get $x) (local.get $y)) (local.get $x)))
+
+  (func (export "f64.recoding_eq") (param $x f64) (param $y f64) (result i32)
+    (f64.eq (f64.mul (local.get $x) (local.get $y)) (local.get $x)))
+
+  (func (export "f64.recoding_le") (param $x f64) (param $y f64) (result i32)
+    (f64.le (f64.mul (local.get $x) (local.get $y)) (local.get $x)))
+
+  (func (export "f64.recoding_lt") (param $x f64) (param $y f64) (result i32)
+    (f64.lt (f64.mul (local.get $x) (local.get $y)) (local.get $x)))
+
+  (func (export "recoding_demote") (param $x f64) (param $y f32) (result f32)
+    (f32.mul (f32.demote_f64 (local.get $x)) (local.get $y)))
+)
+
+(assert_return (invoke "f32.recoding_eq" (f32.const -infinity) (f32.const 3.0)) (i32.const 1))
+(assert_return (invoke "f32.recoding_le" (f32.const -infinity) (f32.const 3.0)) (i32.const 1))
+(assert_return (invoke "f32.recoding_lt" (f32.const -infinity) (f32.const 3.0)) (i32.const 0))
+
+(assert_return (invoke "f32.recoding_eq" (f32.const 0x0p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "f32.recoding_le" (f32.const 0x0p+0) (f32.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "f32.recoding_lt" (f32.const 0x0p+0) (f32.const 0x1p+0)) (i32.const 0))
+
+(assert_return (invoke "f64.recoding_eq" (f64.const -infinity) (f64.const 3.0)) (i32.const 1))
+(assert_return (invoke "f64.recoding_le" (f64.const -infinity) (f64.const 3.0)) (i32.const 1))
+(assert_return (invoke "f64.recoding_lt" (f64.const -infinity) (f64.const 3.0)) (i32.const 0))
+
+(assert_return (invoke "f64.recoding_eq" (f64.const 0x0p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "f64.recoding_le" (f64.const 0x0p+0) (f64.const 0x1p+0)) (i32.const 1))
+(assert_return (invoke "f64.recoding_lt" (f64.const 0x0p+0) (f64.const 0x1p+0)) (i32.const 0))
+
+(assert_return (invoke "recoding_demote" (f64.const 0x1.4c8f8p-132) (f32.const 1221)) (f32.const 0x1.8c8a1cp-122))
+
+;; Test that division is not done as on an extended-base system.
+;; http://www.ucbtest.org/goldberg/addendum.html
+
+(module
+  (func (export "f32.no_extended_precision_div") (param $x f32) (param $y f32) (param $z f32) (result i32)
+    (f32.eq (f32.div (local.get $x) (local.get $y)) (local.get $z)))
+
+  (func (export "f64.no_extended_precision_div") (param $x f64) (param $y f64) (param $z f64) (result i32)
+    (f64.eq (f64.div (local.get $x) (local.get $y)) (local.get $z)))
+)
+
+(assert_return (invoke "f32.no_extended_precision_div" (f32.const 3.0) (f32.const 7.0) (f32.const 0x1.b6db6ep-2)) (i32.const 1))
+(assert_return (invoke "f64.no_extended_precision_div" (f64.const 3.0) (f64.const 7.0) (f64.const 0x1.b6db6db6db6dbp-2)) (i32.const 1))
+
+;; a*x + b*x == (a+b)*x for all x only if the operations a*x, b*x, and (a+b)
+;; are all exact operations, which is true only if a and b are exact powers of
+;; 2. Even then, if a==-b and x==-0, then a*x+b*x==0.0, (a+b)*x==-0.0.
+;; https://dlang.org/d-floating-point.html
+
+(module
+  (func (export "f32.no_distribute_exact") (param $x f32) (result f32)
+    (f32.add (f32.mul (f32.const -8.0) (local.get $x)) (f32.mul (f32.const 8.0) (local.get $x))))
+
+  (func (export "f64.no_distribute_exact") (param $x f64) (result f64)
+    (f64.add (f64.mul (f64.const -8.0) (local.get $x)) (f64.mul (f64.const 8.0) (local.get $x))))
+)
+
+(assert_return (invoke "f32.no_distribute_exact" (f32.const -0.0)) (f32.const 0.0))
+(assert_return (invoke "f64.no_distribute_exact" (f64.const -0.0)) (f64.const 0.0))
+
+;; Test that various approximations of sqrt(2), sqrt(3), and sqrt(5) compute the
+;; expected approximation.
+;; https://xkcd.com/1047/
+(module
+  (func (export "f32.sqrt") (param f32) (result f32)
+    (f32.sqrt (local.get 0)))
+
+  (func (export "f32.xkcd_sqrt_2") (param f32) (param f32) (param f32) (param f32) (result f32)
+    (f32.add (f32.div (local.get 0) (local.get 1)) (f32.div (local.get 2) (f32.sub (local.get 3) (local.get 2)))))
+
+  (func (export "f32.xkcd_sqrt_3") (param f32) (param f32) (param f32) (result f32)
+    (f32.div (f32.mul (local.get 0) (local.get 1)) (local.get 2)))
+
+  (func (export "f32.xkcd_sqrt_5") (param f32) (param f32) (param f32) (result f32)
+    (f32.add (f32.div (local.get 0) (local.get 1)) (f32.div (local.get 2) (local.get 0))))
+
+  (func (export "f32.xkcd_better_sqrt_5") (param f32) (param f32) (param f32) (param f32) (result f32)
+    (f32.div (f32.add (local.get 0) (f32.mul (local.get 1) (local.get 2))) (f32.sub (local.get 3) (f32.mul (local.get 1) (local.get 2)))))
+
+  (func (export "f64.sqrt") (param f64) (result f64)
+    (f64.sqrt (local.get 0)))
+
+  (func (export "f64.xkcd_sqrt_2") (param f64) (param f64) (param f64) (param f64) (result f64)
+    (f64.add (f64.div (local.get 0) (local.get 1)) (f64.div (local.get 2) (f64.sub (local.get 3) (local.get 2)))))
+
+  (func (export "f64.xkcd_sqrt_3") (param f64) (param f64) (param f64) (result f64)
+    (f64.div (f64.mul (local.get 0) (local.get 1)) (local.get 2)))
+
+  (func (export "f64.xkcd_sqrt_5") (param f64) (param f64) (param f64) (result f64)
+    (f64.add (f64.div (local.get 0) (local.get 1)) (f64.div (local.get 2) (local.get 0))))
+
+  (func (export "f64.xkcd_better_sqrt_5") (param f64) (param f64) (param f64) (param f64) (result f64)
+    (f64.div (f64.add (local.get 0) (f64.mul (local.get 1) (local.get 2))) (f64.sub (local.get 3) (f64.mul (local.get 1) (local.get 2)))))
+)
+
+(assert_return (invoke "f32.sqrt" (f32.const 2.0)) (f32.const 0x1.6a09e6p+0))
+(assert_return (invoke "f32.xkcd_sqrt_2" (f32.const 3.0) (f32.const 5.0) (f32.const 0x1.921fb6p+1) (f32.const 7.0)) (f32.const 0x1.6a0a54p+0))
+(assert_return (invoke "f32.sqrt" (f32.const 3.0)) (f32.const 0x1.bb67aep+0))
+(assert_return (invoke "f32.xkcd_sqrt_3" (f32.const 2.0) (f32.const 0x1.5bf0a8p+1) (f32.const 0x1.921fb6p+1)) (f32.const 0x1.bb02d4p+0))
+(assert_return (invoke "f32.sqrt" (f32.const 5.0)) (f32.const 0x1.1e377ap+1))
+(assert_return (invoke "f32.xkcd_sqrt_5" (f32.const 2.0) (f32.const 0x1.5bf0a8p+1) (f32.const 3.0)) (f32.const 0x1.1e2d58p+1))
+(assert_return (invoke "f32.xkcd_better_sqrt_5" (f32.const 13.0) (f32.const 4.0) (f32.const 0x1.921fb6p+1) (f32.const 24.0)) (f32.const 0x1.1e377ap+1))
+
+(assert_return (invoke "f64.sqrt" (f64.const 2.0)) (f64.const 0x1.6a09e667f3bcdp+0))
+(assert_return (invoke "f64.xkcd_sqrt_2" (f64.const 3.0) (f64.const 5.0) (f64.const 0x1.921fb54442d18p+1) (f64.const 7.0)) (f64.const 0x1.6a0a5362b055fp+0))
+(assert_return (invoke "f64.sqrt" (f64.const 3.0)) (f64.const 0x1.bb67ae8584caap+0))
+(assert_return (invoke "f64.xkcd_sqrt_3" (f64.const 2.0) (f64.const 0x1.5bf0a8b145769p+1) (f64.const 0x1.921fb54442d18p+1)) (f64.const 0x1.bb02d4eca8f95p+0))
+(assert_return (invoke "f64.sqrt" (f64.const 5.0)) (f64.const 0x1.1e3779b97f4a8p+1))
+(assert_return (invoke "f64.xkcd_sqrt_5" (f64.const 2.0) (f64.const 0x1.5bf0a8b145769p+1) (f64.const 3.0)) (f64.const 0x1.1e2d58d8b3bcep+1))
+(assert_return (invoke "f64.xkcd_better_sqrt_5" (f64.const 13.0) (f64.const 4.0) (f64.const 0x1.921fb54442d18p+1) (f64.const 24.0)) (f64.const 0x1.1e3778509a5a3p+1))
+
+;; Compute the floating-point radix.
+;; M. A. Malcom. Algorithms to reveal properties of floating-point arithmetic.
+;; Communications of the ACM, 15(11):949-951, November 1972.
+(module
+  (func (export "f32.compute_radix") (param $0 f32) (param $1 f32) (result f32)
+    (loop $label$0
+      (br_if $label$0
+        (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)
+        )
+      )
+    )
+    (loop $label$2
+      (br_if $label$2
+        (f32.ne
+          (f32.sub
+            (f32.sub
+              (f32.add
+                (local.get $0)
+                (local.tee $1 (f32.add (local.get $1) (f32.const 1)))
+              )
+              (local.get $0)
+            )
+            (local.get $1)
+          )
+          (f32.const 0)
+        )
+      )
+    )
+    (local.get $1)
+  )
+
+  (func (export "f64.compute_radix") (param $0 f64) (param $1 f64) (result f64)
+    (loop $label$0
+      (br_if $label$0
+        (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$2
+      (br_if $label$2
+        (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)
+  )
+)
+
+(assert_return (invoke "f32.compute_radix" (f32.const 1.0) (f32.const 1.0)) (f32.const 2.0))
+(assert_return (invoke "f64.compute_radix" (f64.const 1.0) (f64.const 1.0)) (f64.const 2.0))
+
+;; Test that (x - 1) * y + y is not optimized to x * y.
+;; http://blog.frama-c.com/index.php?post/2013/05/14/Contrarianism
+
+(module
+  (func (export "f32.no_fold_sub1_mul_add") (param $x f32) (param $y f32) (result f32)
+    (f32.add (f32.mul (f32.sub (local.get $x) (f32.const 1.0)) (local.get $y)) (local.get $y)))
+
+  (func (export "f64.no_fold_sub1_mul_add") (param $x f64) (param $y f64) (result f64)
+    (f64.add (f64.mul (f64.sub (local.get $x) (f64.const 1.0)) (local.get $y)) (local.get $y)))
+)
+
+(assert_return (invoke "f32.no_fold_sub1_mul_add" (f32.const 0x1p-32) (f32.const 1.0)) (f32.const 0x0p+0))
+(assert_return (invoke "f64.no_fold_sub1_mul_add" (f64.const 0x1p-64) (f64.const 1.0)) (f64.const 0x0p+0))
+
+;; Test that x+z >= y+z is not optimized to x >= y (monotonicity).
+;; http://cs.nyu.edu/courses/spring13/CSCI-UA.0201-003/lecture6.pdf
+
+(module
+  (func (export "f32.no_fold_add_le_monotonicity") (param $x f32) (param $y f32) (param $z f32) (result i32)
+    (f32.le (f32.add (local.get $x) (local.get $z)) (f32.add (local.get $y) (local.get $z))))
+
+  (func (export "f32.no_fold_add_ge_monotonicity") (param $x f32) (param $y f32) (param $z f32) (result i32)
+    (f32.ge (f32.add (local.get $x) (local.get $z)) (f32.add (local.get $y) (local.get $z))))
+
+  (func (export "f64.no_fold_add_le_monotonicity") (param $x f64) (param $y f64) (param $z f64) (result i32)
+    (f64.le (f64.add (local.get $x) (local.get $z)) (f64.add (local.get $y) (local.get $z))))
+
+  (func (export "f64.no_fold_add_ge_monotonicity") (param $x f64) (param $y f64) (param $z f64) (result i32)
+    (f64.ge (f64.add (local.get $x) (local.get $z)) (f64.add (local.get $y) (local.get $z))))
+)
+
+(assert_return (invoke "f32.no_fold_add_le_monotonicity" (f32.const 0.0) (f32.const 0.0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "f32.no_fold_add_le_monotonicity" (f32.const infinity) (f32.const -infinity) (f32.const infinity)) (i32.const 0))
+(assert_return (invoke "f64.no_fold_add_le_monotonicity" (f64.const 0.0) (f64.const 0.0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "f64.no_fold_add_le_monotonicity" (f64.const infinity) (f64.const -infinity) (f64.const infinity)) (i32.const 0))
+
+;; Test that !(x < y) and friends are not optimized to x >= y and friends.
+
+(module
+  (func (export "f32.not_lt") (param $x f32) (param $y f32) (result i32)
+    (i32.eqz (f32.lt (local.get $x) (local.get $y))))
+
+  (func (export "f32.not_le") (param $x f32) (param $y f32) (result i32)
+    (i32.eqz (f32.le (local.get $x) (local.get $y))))
+
+  (func (export "f32.not_gt") (param $x f32) (param $y f32) (result i32)
+    (i32.eqz (f32.gt (local.get $x) (local.get $y))))
+
+  (func (export "f32.not_ge") (param $x f32) (param $y f32) (result i32)
+    (i32.eqz (f32.ge (local.get $x) (local.get $y))))
+
+  (func (export "f64.not_lt") (param $x f64) (param $y f64) (result i32)
+    (i32.eqz (f64.lt (local.get $x) (local.get $y))))
+
+  (func (export "f64.not_le") (param $x f64) (param $y f64) (result i32)
+    (i32.eqz (f64.le (local.get $x) (local.get $y))))
+
+  (func (export "f64.not_gt") (param $x f64) (param $y f64) (result i32)
+    (i32.eqz (f64.gt (local.get $x) (local.get $y))))
+
+  (func (export "f64.not_ge") (param $x f64) (param $y f64) (result i32)
+    (i32.eqz (f64.ge (local.get $x) (local.get $y))))
+)
+
+(assert_return (invoke "f32.not_lt" (f32.const nan) (f32.const 0.0)) (i32.const 1))
+(assert_return (invoke "f32.not_le" (f32.const nan) (f32.const 0.0)) (i32.const 1))
+(assert_return (invoke "f32.not_gt" (f32.const nan) (f32.const 0.0)) (i32.const 1))
+(assert_return (invoke "f32.not_ge" (f32.const nan) (f32.const 0.0)) (i32.const 1))
+(assert_return (invoke "f64.not_lt" (f64.const nan) (f64.const 0.0)) (i32.const 1))
+(assert_return (invoke "f64.not_le" (f64.const nan) (f64.const 0.0)) (i32.const 1))
+(assert_return (invoke "f64.not_gt" (f64.const nan) (f64.const 0.0)) (i32.const 1))
+(assert_return (invoke "f64.not_ge" (f64.const nan) (f64.const 0.0)) (i32.const 1))
+
+;; Test that a method for approximating a "machine epsilon" produces the expected
+;; approximation.
+;; http://blogs.mathworks.com/cleve/2014/07/07/floating-point-numbers/#24cb4f4d-b8a9-4c19-b22b-9d2a9f7f3812
+
+(module
+  (func (export "f32.epsilon") (result f32)
+    (f32.sub (f32.const 1.0) (f32.mul (f32.const 3.0) (f32.sub (f32.div (f32.const 4.0) (f32.const 3.0)) (f32.const 1.0)))))
+
+  (func (export "f64.epsilon") (result f64)
+    (f64.sub (f64.const 1.0) (f64.mul (f64.const 3.0) (f64.sub (f64.div (f64.const 4.0) (f64.const 3.0)) (f64.const 1.0)))))
+)
+
+(assert_return (invoke "f32.epsilon") (f32.const -0x1p-23))
+(assert_return (invoke "f64.epsilon") (f64.const 0x1p-52))
+
+;; Test that floating-point numbers are not optimized as if they form a
+;; trichotomy.
+
+(module
+  (func (export "f32.no_trichotomy_lt") (param $x f32) (param $y f32) (result i32)
+    (i32.or (f32.lt (local.get $x) (local.get $y)) (f32.ge (local.get $x) (local.get $y))))
+  (func (export "f32.no_trichotomy_le") (param $x f32) (param $y f32) (result i32)
+    (i32.or (f32.le (local.get $x) (local.get $y)) (f32.gt (local.get $x) (local.get $y))))
+  (func (export "f32.no_trichotomy_gt") (param $x f32) (param $y f32) (result i32)
+    (i32.or (f32.gt (local.get $x) (local.get $y)) (f32.le (local.get $x) (local.get $y))))
+  (func (export "f32.no_trichotomy_ge") (param $x f32) (param $y f32) (result i32)
+    (i32.or (f32.ge (local.get $x) (local.get $y)) (f32.lt (local.get $x) (local.get $y))))
+
+  (func (export "f64.no_trichotomy_lt") (param $x f64) (param $y f64) (result i32)
+    (i32.or (f64.lt (local.get $x) (local.get $y)) (f64.ge (local.get $x) (local.get $y))))
+  (func (export "f64.no_trichotomy_le") (param $x f64) (param $y f64) (result i32)
+    (i32.or (f64.le (local.get $x) (local.get $y)) (f64.gt (local.get $x) (local.get $y))))
+  (func (export "f64.no_trichotomy_gt") (param $x f64) (param $y f64) (result i32)
+    (i32.or (f64.gt (local.get $x) (local.get $y)) (f64.le (local.get $x) (local.get $y))))
+  (func (export "f64.no_trichotomy_ge") (param $x f64) (param $y f64) (result i32)
+    (i32.or (f64.ge (local.get $x) (local.get $y)) (f64.lt (local.get $x) (local.get $y))))
+)
+
+(assert_return (invoke "f32.no_trichotomy_lt" (f32.const 0.0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "f32.no_trichotomy_le" (f32.const 0.0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "f32.no_trichotomy_gt" (f32.const 0.0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "f32.no_trichotomy_ge" (f32.const 0.0) (f32.const nan)) (i32.const 0))
+(assert_return (invoke "f64.no_trichotomy_lt" (f64.const 0.0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "f64.no_trichotomy_le" (f64.const 0.0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "f64.no_trichotomy_gt" (f64.const 0.0) (f64.const nan)) (i32.const 0))
+(assert_return (invoke "f64.no_trichotomy_ge" (f64.const 0.0) (f64.const nan)) (i32.const 0))
diff --git a/binaryen/test/spec/old_float_literals.wast b/binaryen/test/spec/old_float_literals.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_float_literals.wast
@@ -0,0 +1,137 @@
+;; Test floating-point literal parsing.
+
+(module
+  ;; f32 special values
+  (func (export "f32.nan") (result i32) (i32.reinterpret_f32 (f32.const nan)))
+  (func (export "f32.positive_nan") (result i32) (i32.reinterpret_f32 (f32.const +nan)))
+  (func (export "f32.negative_nan") (result i32) (i32.reinterpret_f32 (f32.const -nan)))
+  (func (export "f32.plain_nan") (result i32) (i32.reinterpret_f32 (f32.const nan:0x400000)))
+  (func (export "f32.informally_known_as_plain_snan") (result i32) (i32.reinterpret_f32 (f32.const nan:0x200000)))
+  (func (export "f32.all_ones_nan") (result i32) (i32.reinterpret_f32 (f32.const -nan:0x7fffff)))
+  (func (export "f32.misc_nan") (result i32) (i32.reinterpret_f32 (f32.const nan:0x012345)))
+  (func (export "f32.misc_positive_nan") (result i32) (i32.reinterpret_f32 (f32.const +nan:0x304050)))
+  (func (export "f32.misc_negative_nan") (result i32) (i32.reinterpret_f32 (f32.const -nan:0x2abcde)))
+  (func (export "f32.infinity") (result i32) (i32.reinterpret_f32 (f32.const infinity)))
+  (func (export "f32.positive_infinity") (result i32) (i32.reinterpret_f32 (f32.const +infinity)))
+  (func (export "f32.negative_infinity") (result i32) (i32.reinterpret_f32 (f32.const -infinity)))
+
+  ;; f32 numbers
+  (func (export "f32.zero") (result i32) (i32.reinterpret_f32 (f32.const 0x0.0p0)))
+  (func (export "f32.positive_zero") (result i32) (i32.reinterpret_f32 (f32.const +0x0.0p0)))
+  (func (export "f32.negative_zero") (result i32) (i32.reinterpret_f32 (f32.const -0x0.0p0)))
+  (func (export "f32.misc") (result i32) (i32.reinterpret_f32 (f32.const 0x1.921fb6p+2)))
+  (func (export "f32.min_positive") (result i32) (i32.reinterpret_f32 (f32.const 0x1p-149)))
+  (func (export "f32.min_normal") (result i32) (i32.reinterpret_f32 (f32.const 0x1p-126)))
+  (func (export "f32.max_finite") (result i32) (i32.reinterpret_f32 (f32.const 0x1.fffffep+127)))
+  (func (export "f32.max_subnormal") (result i32) (i32.reinterpret_f32 (f32.const 0x1.fffffcp-127)))
+  (func (export "f32.trailing_dot") (result i32) (i32.reinterpret_f32 (f32.const 0x1.p10)))
+
+  ;; f32 in decimal format
+  (func (export "f32_dec.zero") (result i32) (i32.reinterpret_f32 (f32.const 0.0e0)))
+  (func (export "f32_dec.positive_zero") (result i32) (i32.reinterpret_f32 (f32.const +0.0e0)))
+  (func (export "f32_dec.negative_zero") (result i32) (i32.reinterpret_f32 (f32.const -0.0e0)))
+  (func (export "f32_dec.misc") (result i32) (i32.reinterpret_f32 (f32.const 6.28318548202514648)))
+  (func (export "f32_dec.min_positive") (result i32) (i32.reinterpret_f32 (f32.const 1.4013e-45)))
+  (func (export "f32_dec.min_normal") (result i32) (i32.reinterpret_f32 (f32.const 1.1754944e-38)))
+  (func (export "f32_dec.max_subnormal") (result i32) (i32.reinterpret_f32 (f32.const 1.1754942e-38)))
+  (func (export "f32_dec.max_finite") (result i32) (i32.reinterpret_f32 (f32.const 3.4028234e+38)))
+  (func (export "f32_dec.trailing_dot") (result i32) (i32.reinterpret_f32 (f32.const 1.e10)))
+
+  ;; f64 special values
+  (func (export "f64.nan") (result i64) (i64.reinterpret_f64 (f64.const nan)))
+  (func (export "f64.positive_nan") (result i64) (i64.reinterpret_f64 (f64.const +nan)))
+  (func (export "f64.negative_nan") (result i64) (i64.reinterpret_f64 (f64.const -nan)))
+  (func (export "f64.plain_nan") (result i64) (i64.reinterpret_f64 (f64.const nan:0x8000000000000)))
+  (func (export "f64.informally_known_as_plain_snan") (result i64) (i64.reinterpret_f64 (f64.const nan:0x4000000000000)))
+  (func (export "f64.all_ones_nan") (result i64) (i64.reinterpret_f64 (f64.const -nan:0xfffffffffffff)))
+  (func (export "f64.misc_nan") (result i64) (i64.reinterpret_f64 (f64.const nan:0x0123456789abc)))
+  (func (export "f64.misc_positive_nan") (result i64) (i64.reinterpret_f64 (f64.const +nan:0x3040506070809)))
+  (func (export "f64.misc_negative_nan") (result i64) (i64.reinterpret_f64 (f64.const -nan:0x2abcdef012345)))
+  (func (export "f64.infinity") (result i64) (i64.reinterpret_f64 (f64.const infinity)))
+  (func (export "f64.positive_infinity") (result i64) (i64.reinterpret_f64 (f64.const +infinity)))
+  (func (export "f64.negative_infinity") (result i64) (i64.reinterpret_f64 (f64.const -infinity)))
+
+  ;; f64 numbers
+  (func (export "f64.zero") (result i64) (i64.reinterpret_f64 (f64.const 0x0.0p0)))
+  (func (export "f64.positive_zero") (result i64) (i64.reinterpret_f64 (f64.const +0x0.0p0)))
+  (func (export "f64.negative_zero") (result i64) (i64.reinterpret_f64 (f64.const -0x0.0p0)))
+  (func (export "f64.misc") (result i64) (i64.reinterpret_f64 (f64.const 0x1.921fb54442d18p+2)))
+  (func (export "f64.min_positive") (result i64) (i64.reinterpret_f64 (f64.const 0x0.0000000000001p-1022)))
+  (func (export "f64.min_normal") (result i64) (i64.reinterpret_f64 (f64.const 0x1p-1022)))
+  (func (export "f64.max_subnormal") (result i64) (i64.reinterpret_f64 (f64.const 0x0.fffffffffffffp-1022)))
+  (func (export "f64.max_finite") (result i64) (i64.reinterpret_f64 (f64.const 0x1.fffffffffffffp+1023)))
+  (func (export "f64.trailing_dot") (result i64) (i64.reinterpret_f64 (f64.const 0x1.p100)))
+
+  ;; f64 numbers in decimal format
+  (func (export "f64_dec.zero") (result i64) (i64.reinterpret_f64 (f64.const 0.0e0)))
+  (func (export "f64_dec.positive_zero") (result i64) (i64.reinterpret_f64 (f64.const +0.0e0)))
+  (func (export "f64_dec.negative_zero") (result i64) (i64.reinterpret_f64 (f64.const -0.0e0)))
+  (func (export "f64_dec.misc") (result i64) (i64.reinterpret_f64 (f64.const 6.28318530717958623)))
+  (func (export "f64_dec.min_positive") (result i64) (i64.reinterpret_f64 (f64.const 4.94066e-324)))
+  (func (export "f64_dec.min_normal") (result i64) (i64.reinterpret_f64 (f64.const 2.2250738585072012e-308)))
+  (func (export "f64_dec.max_subnormal") (result i64) (i64.reinterpret_f64 (f64.const 2.2250738585072011e-308)))
+  (func (export "f64_dec.max_finite") (result i64) (i64.reinterpret_f64 (f64.const 1.7976931348623157e+308)))
+  (func (export "f64_dec.trailing_dot") (result i64) (i64.reinterpret_f64 (f64.const 1.e100)))
+)
+
+(assert_return (invoke "f32.nan") (i32.const 0x7fc00000))
+(assert_return (invoke "f32.positive_nan") (i32.const 0x7fc00000))
+(assert_return (invoke "f32.negative_nan") (i32.const 0xffc00000))
+(assert_return (invoke "f32.plain_nan") (i32.const 0x7fc00000))
+(assert_return (invoke "f32.informally_known_as_plain_snan") (i32.const 0x7fa00000))
+(assert_return (invoke "f32.all_ones_nan") (i32.const 0xffffffff))
+(assert_return (invoke "f32.misc_nan") (i32.const 0x7f812345))
+(assert_return (invoke "f32.misc_positive_nan") (i32.const 0x7fb04050))
+(assert_return (invoke "f32.misc_negative_nan") (i32.const 0xffaabcde))
+(assert_return (invoke "f32.infinity") (i32.const 0x7f800000))
+(assert_return (invoke "f32.positive_infinity") (i32.const 0x7f800000))
+(assert_return (invoke "f32.negative_infinity") (i32.const 0xff800000))
+(assert_return (invoke "f32.zero") (i32.const 0))
+(assert_return (invoke "f32.positive_zero") (i32.const 0))
+(assert_return (invoke "f32.negative_zero") (i32.const 0x80000000))
+(assert_return (invoke "f32.misc") (i32.const 0x40c90fdb))
+(assert_return (invoke "f32.min_positive") (i32.const 1))
+(assert_return (invoke "f32.min_normal") (i32.const 0x800000))
+(assert_return (invoke "f32.max_subnormal") (i32.const 0x7fffff))
+(assert_return (invoke "f32.max_finite") (i32.const 0x7f7fffff))
+(assert_return (invoke "f32.trailing_dot") (i32.const 0x44800000))
+(assert_return (invoke "f32_dec.zero") (i32.const 0))
+(assert_return (invoke "f32_dec.positive_zero") (i32.const 0))
+(assert_return (invoke "f32_dec.negative_zero") (i32.const 0x80000000))
+(assert_return (invoke "f32_dec.misc") (i32.const 0x40c90fdb))
+(assert_return (invoke "f32_dec.min_positive") (i32.const 1))
+(assert_return (invoke "f32_dec.min_normal") (i32.const 0x800000))
+(assert_return (invoke "f32_dec.max_subnormal") (i32.const 0x7fffff))
+(assert_return (invoke "f32_dec.max_finite") (i32.const 0x7f7fffff))
+(assert_return (invoke "f32_dec.trailing_dot") (i32.const 0x501502f9))
+
+(assert_return (invoke "f64.nan") (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.positive_nan") (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.negative_nan") (i64.const 0xfff8000000000000))
+(assert_return (invoke "f64.plain_nan") (i64.const 0x7ff8000000000000))
+(assert_return (invoke "f64.informally_known_as_plain_snan") (i64.const 0x7ff4000000000000))
+(assert_return (invoke "f64.all_ones_nan") (i64.const 0xffffffffffffffff))
+(assert_return (invoke "f64.misc_nan") (i64.const 0x7ff0123456789abc))
+(assert_return (invoke "f64.misc_positive_nan") (i64.const 0x7ff3040506070809))
+(assert_return (invoke "f64.misc_negative_nan") (i64.const 0xfff2abcdef012345))
+(assert_return (invoke "f64.infinity") (i64.const 0x7ff0000000000000))
+(assert_return (invoke "f64.positive_infinity") (i64.const 0x7ff0000000000000))
+(assert_return (invoke "f64.negative_infinity") (i64.const 0xfff0000000000000))
+(assert_return (invoke "f64.zero") (i64.const 0))
+(assert_return (invoke "f64.positive_zero") (i64.const 0))
+(assert_return (invoke "f64.negative_zero") (i64.const 0x8000000000000000))
+(assert_return (invoke "f64.misc") (i64.const 0x401921fb54442d18))
+(assert_return (invoke "f64.min_positive") (i64.const 1))
+(assert_return (invoke "f64.min_normal") (i64.const 0x10000000000000))
+(assert_return (invoke "f64.max_subnormal") (i64.const 0xfffffffffffff))
+(assert_return (invoke "f64.max_finite") (i64.const 0x7fefffffffffffff))
+(assert_return (invoke "f64.trailing_dot") (i64.const 0x4630000000000000))
+(assert_return (invoke "f64_dec.zero") (i64.const 0))
+(assert_return (invoke "f64_dec.positive_zero") (i64.const 0))
+(assert_return (invoke "f64_dec.negative_zero") (i64.const 0x8000000000000000))
+(assert_return (invoke "f64_dec.misc") (i64.const 0x401921fb54442d18))
+(assert_return (invoke "f64_dec.min_positive") (i64.const 1))
+(assert_return (invoke "f64_dec.min_normal") (i64.const 0x10000000000000))
+(assert_return (invoke "f64_dec.max_subnormal") (i64.const 0xfffffffffffff))
+(assert_return (invoke "f64_dec.max_finite") (i64.const 0x7fefffffffffffff))
+(assert_return (invoke "f64_dec.trailing_dot") (i64.const 0x54b249ad2594c37d))
diff --git a/binaryen/test/spec/old_func.wast b/binaryen/test/spec/old_func.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_func.wast
@@ -0,0 +1,518 @@
+;; Test `func` declarations, i.e. functions
+
+(module
+  ;; Auxiliary definition
+  (type $sig (func))
+  (func $dummy)
+
+  ;; Syntax
+
+  (func)
+  (func (export "f"))
+  (func $f)
+  (func $h (export "g"))
+
+  (func (local))
+  (func (local) (local))
+  (func (local i32))
+  (func (local $x i32))
+  (func (local i32 f64 i64))
+  (func (local i32) (local f64))
+  (func (local i32 f32) (local $x i64) (local) (local i32 f64))
+
+  (func (param))
+  (func (param) (param))
+  (func (param i32))
+  (func (param $x i32))
+  (func (param i32 f64 i64))
+  (func (param i32) (param f64))
+  (func (param i32 f32) (param $x i64) (param) (param i32 f64))
+
+  (func (result i32) (unreachable))
+
+  (func (type $sig))
+
+  (func $complex
+    (param i32 f32) (param $x i64) (param) (param i32)
+    (result i32)
+    (local f32) (local $y i32) (local i64 i32) (local) (local f64 i32)
+    (unreachable) (unreachable)
+  )
+  (func $complex-sig
+    (type $sig)
+    (local f32) (local $y i32) (local i64 i32) (local) (local f64 i32)
+    (unreachable) (unreachable)
+  )
+
+
+  ;; Typing of locals
+
+  (func (export "local-first-i32") (result i32) (local i32 i32) (local.get 0))
+  (func (export "local-first-i64") (result i64) (local i64 i64) (local.get 0))
+  (func (export "local-first-f32") (result f32) (local f32 f32) (local.get 0))
+  (func (export "local-first-f64") (result f64) (local f64 f64) (local.get 0))
+  (func (export "local-second-i32") (result i32) (local i32 i32) (local.get 1))
+  (func (export "local-second-i64") (result i64) (local i64 i64) (local.get 1))
+  (func (export "local-second-f32") (result f32) (local f32 f32) (local.get 1))
+  (func (export "local-second-f64") (result f64) (local f64 f64) (local.get 1))
+  (func (export "local-mixed") (result f64)
+    (local f32) (local $x i32) (local i64 i32) (local) (local f64 i32)
+    (drop (f32.neg (local.get 0)))
+    (drop (i32.eqz (local.get 1)))
+    (drop (i64.eqz (local.get 2)))
+    (drop (i32.eqz (local.get 3)))
+    (drop (f64.neg (local.get 4)))
+    (drop (i32.eqz (local.get 5)))
+    (local.get 4)
+  )
+
+  ;; Typing of parameters
+
+  (func (export "param-first-i32") (param i32 i32) (result i32) (local.get 0))
+  (func (export "param-first-i64") (param i64 i64) (result i64) (local.get 0))
+  (func (export "param-first-f32") (param f32 f32) (result f32) (local.get 0))
+  (func (export "param-first-f64") (param f64 f64) (result f64) (local.get 0))
+  (func (export "param-second-i32") (param i32 i32) (result i32) (local.get 1))
+  (func (export "param-second-i64") (param i64 i64) (result i64) (local.get 1))
+  (func (export "param-second-f32") (param f32 f32) (result f32) (local.get 1))
+  (func (export "param-second-f64") (param f64 f64) (result f64) (local.get 1))
+  (func (export "param-mixed") (param f32 i32) (param) (param $x i64) (param i32 f64 i32)
+    (result f64)
+    (drop (f32.neg (local.get 0)))
+    (drop (i32.eqz (local.get 1)))
+    (drop (i64.eqz (local.get 2)))
+    (drop (i32.eqz (local.get 3)))
+    (drop (f64.neg (local.get 4)))
+    (drop (i32.eqz (local.get 5)))
+    (local.get 4)
+  )
+
+  ;; Typing of result
+
+  (func (export "empty"))
+  (func (export "value-void") (call $dummy))
+  (func (export "value-i32") (result i32) (i32.const 77))
+  (func (export "value-i64") (result i64) (i64.const 7777))
+  (func (export "value-f32") (result f32) (f32.const 77.7))
+  (func (export "value-f64") (result f64) (f64.const 77.77))
+  (func (export "value-block-void") (block (call $dummy) (call $dummy)))
+  (func (export "value-block-i32") (result i32)
+    (block i32 (call $dummy) (i32.const 77))
+  )
+
+  (func (export "return-empty") (return))
+  (func (export "return-i32") (result i32) (return (i32.const 78)))
+  (func (export "return-i64") (result i64) (return (i64.const 7878)))
+  (func (export "return-f32") (result f32) (return (f32.const 78.7)))
+  (func (export "return-f64") (result f64) (return (f64.const 78.78)))
+  (func (export "return-block-i32") (result i32)
+    (return (block i32 (call $dummy) (i32.const 77)))
+  )
+
+  (func (export "break-empty") (br 0))
+  (func (export "break-i32") (result i32) (br 0 (i32.const 79)))
+  (func (export "break-i64") (result i64) (br 0 (i64.const 7979)))
+  (func (export "break-f32") (result f32) (br 0 (f32.const 79.9)))
+  (func (export "break-f64") (result f64) (br 0 (f64.const 79.79)))
+  (func (export "break-block-i32") (result i32)
+    (br 0 (block i32 (call $dummy) (i32.const 77)))
+  )
+
+  (func (export "break-br_if-empty") (param i32)
+    (br_if 0 (local.get 0))
+  )
+  (func (export "break-br_if-num") (param i32) (result i32)
+    (drop (br_if 0 (i32.const 50) (local.get 0))) (i32.const 51)
+  )
+
+  (func (export "break-br_table-empty") (param i32)
+    (br_table 0 0 0 (local.get 0))
+  )
+  (func (export "break-br_table-num") (param i32) (result i32)
+    (br_table 0 0 (i32.const 50) (local.get 0)) (i32.const 51)
+  )
+  (func (export "break-br_table-nested-empty") (param i32)
+    (block (br_table 0 1 0 (local.get 0)))
+  )
+  (func (export "break-br_table-nested-num") (param i32) (result i32)
+    (i32.add
+      (block i32 (br_table 0 1 0 (i32.const 50) (local.get 0)) (i32.const 51))
+      (i32.const 2)
+    )
+  )
+
+  ;; Default initialization of locals
+
+  (func (export "init-local-i32") (result i32) (local i32) (local.get 0))
+  (func (export "init-local-i64") (result i64) (local i64) (local.get 0))
+  (func (export "init-local-f32") (result f32) (local f32) (local.get 0))
+  (func (export "init-local-f64") (result f64) (local f64) (local.get 0))
+
+
+  ;; Desugaring of implicit type signature
+  (func $empty-sig-1)  ;; should be assigned type $sig
+  (func $complex-sig-1 (param f64 i64 f64 i64 f64 i64 f32 i32))
+  (func $empty-sig-2)  ;; should be assigned type $sig
+  (func $complex-sig-2 (param f64 i64 f64 i64 f64 i64 f32 i32))
+  (func $complex-sig-3 (param f64 i64 f64 i64 f64 i64 f32 i32))
+
+  (type $empty-sig-duplicate (func))
+  (type $complex-sig-duplicate (func (param f64 i64 f64 i64 f64 i64 f32 i32)))
+  (table funcref
+    (elem
+      $complex-sig-3 $empty-sig-2 $complex-sig-1 $complex-sig-3 $empty-sig-1
+    )
+  )
+
+  (func (export "signature-explicit-reused")
+    (call_indirect (type $sig) (i32.const 1))
+    (call_indirect (type $sig) (i32.const 4))
+  )
+
+  (func (export "signature-implicit-reused")
+    ;; The implicit index 16 in this test depends on the function and
+    ;; type definitions, and may need adapting if they change.
+    (call_indirect (type 16)
+      (f64.const 0) (i64.const 0) (f64.const 0) (i64.const 0)
+      (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0)
+      (i32.const 0)
+    )
+    (call_indirect (type 16)
+      (f64.const 0) (i64.const 0) (f64.const 0) (i64.const 0)
+      (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0)
+      (i32.const 2)
+    )
+    (call_indirect (type 16)
+      (f64.const 0) (i64.const 0) (f64.const 0) (i64.const 0)
+      (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0)
+      (i32.const 3)
+    )
+  )
+
+  (func (export "signature-explicit-duplicate")
+    (call_indirect (type $empty-sig-duplicate) (i32.const 1))
+  )
+
+  (func (export "signature-implicit-duplicate")
+    (call_indirect (type $complex-sig-duplicate)
+      (f64.const 0) (i64.const 0) (f64.const 0) (i64.const 0)
+      (f64.const 0) (i64.const 0) (f32.const 0) (i32.const 0)
+      (i32.const 0)
+    )
+  )
+)
+
+(assert_return (invoke "local-first-i32") (i32.const 0))
+(assert_return (invoke "local-first-i64") (i64.const 0))
+(assert_return (invoke "local-first-f32") (f32.const 0))
+(assert_return (invoke "local-first-f64") (f64.const 0))
+(assert_return (invoke "local-second-i32") (i32.const 0))
+(assert_return (invoke "local-second-i64") (i64.const 0))
+(assert_return (invoke "local-second-f32") (f32.const 0))
+(assert_return (invoke "local-second-f64") (f64.const 0))
+(assert_return (invoke "local-mixed") (f64.const 0))
+
+(assert_return
+  (invoke "param-first-i32" (i32.const 2) (i32.const 3)) (i32.const 2)
+)
+(assert_return
+  (invoke "param-first-i64" (i64.const 2) (i64.const 3)) (i64.const 2)
+)
+(assert_return
+  (invoke "param-first-f32" (f32.const 2) (f32.const 3)) (f32.const 2)
+)
+(assert_return
+  (invoke "param-first-f64" (f64.const 2) (f64.const 3)) (f64.const 2)
+)
+(assert_return
+  (invoke "param-second-i32" (i32.const 2) (i32.const 3)) (i32.const 3)
+)
+(assert_return
+  (invoke "param-second-i64" (i64.const 2) (i64.const 3)) (i64.const 3)
+)
+(assert_return
+  (invoke "param-second-f32" (f32.const 2) (f32.const 3)) (f32.const 3)
+)
+(assert_return
+  (invoke "param-second-f64" (f64.const 2) (f64.const 3)) (f64.const 3)
+)
+
+(assert_return
+  (invoke "param-mixed"
+    (f32.const 1) (i32.const 2) (i64.const 3)
+    (i32.const 4) (f64.const 5.5) (i32.const 6)
+  )
+  (f64.const 5.5)
+)
+
+(assert_return (invoke "empty"))
+(assert_return (invoke "value-void"))
+(assert_return (invoke "value-i32") (i32.const 77))
+(assert_return (invoke "value-i64") (i64.const 7777))
+(assert_return (invoke "value-f32") (f32.const 77.7))
+(assert_return (invoke "value-f64") (f64.const 77.77))
+(assert_return (invoke "value-block-void"))
+(assert_return (invoke "value-block-i32") (i32.const 77))
+
+(assert_return (invoke "return-empty"))
+(assert_return (invoke "return-i32") (i32.const 78))
+(assert_return (invoke "return-i64") (i64.const 7878))
+(assert_return (invoke "return-f32") (f32.const 78.7))
+(assert_return (invoke "return-f64") (f64.const 78.78))
+(assert_return (invoke "return-block-i32") (i32.const 77))
+
+(assert_return (invoke "break-empty"))
+(assert_return (invoke "break-i32") (i32.const 79))
+(assert_return (invoke "break-i64") (i64.const 7979))
+(assert_return (invoke "break-f32") (f32.const 79.9))
+(assert_return (invoke "break-f64") (f64.const 79.79))
+(assert_return (invoke "break-block-i32") (i32.const 77))
+
+(assert_return (invoke "break-br_if-empty" (i32.const 0)))
+(assert_return (invoke "break-br_if-empty" (i32.const 2)))
+(assert_return (invoke "break-br_if-num" (i32.const 0)) (i32.const 51))
+(assert_return (invoke "break-br_if-num" (i32.const 1)) (i32.const 50))
+
+(assert_return (invoke "break-br_table-empty" (i32.const 0)))
+(assert_return (invoke "break-br_table-empty" (i32.const 1)))
+(assert_return (invoke "break-br_table-empty" (i32.const 5)))
+(assert_return (invoke "break-br_table-empty" (i32.const -1)))
+(assert_return (invoke "break-br_table-num" (i32.const 0)) (i32.const 50))
+(assert_return (invoke "break-br_table-num" (i32.const 1)) (i32.const 50))
+(assert_return (invoke "break-br_table-num" (i32.const 10)) (i32.const 50))
+(assert_return (invoke "break-br_table-num" (i32.const -100)) (i32.const 50))
+(assert_return (invoke "break-br_table-nested-empty" (i32.const 0)))
+(assert_return (invoke "break-br_table-nested-empty" (i32.const 1)))
+(assert_return (invoke "break-br_table-nested-empty" (i32.const 3)))
+(assert_return (invoke "break-br_table-nested-empty" (i32.const -2)))
+(assert_return
+  (invoke "break-br_table-nested-num" (i32.const 0)) (i32.const 52)
+)
+(assert_return
+  (invoke "break-br_table-nested-num" (i32.const 1)) (i32.const 50)
+)
+(assert_return
+  (invoke "break-br_table-nested-num" (i32.const 2)) (i32.const 52)
+)
+(assert_return
+  (invoke "break-br_table-nested-num" (i32.const -3)) (i32.const 52)
+)
+
+(assert_return (invoke "init-local-i32") (i32.const 0))
+(assert_return (invoke "init-local-i64") (i64.const 0))
+(assert_return (invoke "init-local-f32") (f32.const 0))
+(assert_return (invoke "init-local-f64") (f64.const 0))
+
+(assert_return (invoke "signature-explicit-reused"))
+(assert_return (invoke "signature-implicit-reused"))
+(assert_return (invoke "signature-explicit-duplicate"))
+(assert_return (invoke "signature-implicit-duplicate"))
+
+
+;; Invalid typing of locals
+
+(assert_invalid
+  (module (func $type-local-num-vs-num (result i64) (local i32) (local.get 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-num-vs-num (local f32) (i32.eqz (local.get 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-num-vs-num (local f64 i64) (f64.neg (local.get 1))))
+  "type mismatch"
+)
+
+
+;; Invalid typing of parameters
+
+(assert_invalid
+  (module (func $type-param-num-vs-num (param i32) (result i64) (local.get 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-num-vs-num (param f32) (i32.eqz (local.get 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-num-vs-num (param f64 i64) (f64.neg (local.get 1))))
+  "type mismatch"
+)
+
+
+;; Invalid typing of result
+
+(assert_invalid
+  (module (func $type-empty-i32 (result i32)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-i64 (result i64)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f32 (result f32)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f64 (result f64)))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-value-void-vs-num (result i32)
+    (nop)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-num-vs-void
+    (i32.const 0)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-num-vs-num (result i32)
+    (f32.const 0)
+  ))
+  "type mismatch"
+)
+
+(; TODO(stack): Should these become legal?
+(assert_invalid
+  (module (func $type-value-void-vs-num-after-return (result i32)
+    (return (i32.const 1)) (nop)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-num-vs-num-after-return (result i32)
+    (return (i32.const 1)) (f32.const 0)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-void-vs-num-after-break (result i32)
+    (br 0 (i32.const 1)) (nop)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-num-vs-num-after-break (result i32)
+    (br 0 (i32.const 1)) (f32.const 0)
+  ))
+  "arity mismatch"
+)
+;)
+
+(assert_invalid
+  (module (func $type-return-last-empty-vs-num (result i32)
+    (return)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-return-last-void-vs-num (result i32)
+    (return (nop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-return-last-num-vs-num (result i32)
+    (return (i64.const 0))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-return-empty-vs-num (result i32)
+    (return) (i32.const 1)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-return-void-vs-num (result i32)
+    (return (nop)) (i32.const 1)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-return-num-vs-num (result i32)
+    (return (i64.const 1)) (i32.const 1)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-return-first-num-vs-num (result i32)
+    (return (i64.const 1)) (return (i32.const 1))
+  ))
+  "type mismatch"
+)
+(; TODO(stack): Should this become legal?
+(assert_invalid
+  (module (func $type-return-second-num-vs-num (result i32)
+    (return (i32.const 1)) (return (f64.const 1))
+  ))
+  "type mismatch"
+)
+;)
+
+(assert_invalid
+  (module (func $type-break-last-void-vs-num (result i32)
+    (br 0)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-last-num-vs-num (result i32)
+    (br 0 (f32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-void-vs-num (result i32)
+    (br 0) (i32.const 1)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-num-vs-num (result i32)
+    (br 0 (i64.const 1)) (i32.const 1)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-first-num-vs-num (result i32)
+    (br 0 (i64.const 1)) (br 0 (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+(; TODO(stack): soft failure
+(assert_invalid
+  (module (func $type-break-second-num-vs-num (result i32)
+    (br 0 (i32.const 1)) (br 0 (f64.const 1))
+  ))
+  "type mismatch"
+)
+;)
+
+(assert_invalid
+  (module (func $type-break-nested-empty-vs-num (result i32)
+    (block (br 1)) (br 0 (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-void-vs-num (result i32)
+    (block (br 1 (nop))) (br 0 (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-break-nested-num-vs-num (result i32)
+    (block (br 1 (i64.const 1))) (br 0 (i32.const 1))
+  ))
+  "type mismatch"
+)
diff --git a/binaryen/test/spec/old_globals.wast b/binaryen/test/spec/old_globals.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_globals.wast
@@ -0,0 +1,72 @@
+;; Test globals
+
+(module
+  (global $a i32 (i32.const -2))
+  (global (;1;) f32 (f32.const -3))
+  (global (;2;) f64 (f64.const -4))
+  (global $b i64 (i64.const -5))
+
+  (global $x (mut i32) (i32.const -12))
+  (global (;5;) (mut f32) (f32.const -13))
+  (global (;6;) (mut f64) (f64.const -14))
+  (global $y (mut i64) (i64.const -15))
+
+  (func (export "get-a") (result i32) (global.get $a))
+  (func (export "get-b") (result i64) (global.get $b))
+  (func (export "get-x") (result i32) (global.get $x))
+  (func (export "get-y") (result i64) (global.get $y))
+  (func (export "set-x") (param i32) (global.set $x (local.get 0)))
+  (func (export "set-y") (param i64) (global.set $y (local.get 0)))
+
+  (func (export "get-1") (result f32) (global.get 1))
+  (func (export "get-2") (result f64) (global.get 2))
+  (func (export "get-5") (result f32) (global.get 5))
+  (func (export "get-6") (result f64) (global.get 6))
+  (func (export "set-5") (param f32) (global.set 5 (local.get 0)))
+  (func (export "set-6") (param f64) (global.set 6 (local.get 0)))
+)
+
+(assert_return (invoke "get-a") (i32.const -2))
+(assert_return (invoke "get-b") (i64.const -5))
+(assert_return (invoke "get-x") (i32.const -12))
+(assert_return (invoke "get-y") (i64.const -15))
+
+(assert_return (invoke "get-1") (f32.const -3))
+(assert_return (invoke "get-2") (f64.const -4))
+(assert_return (invoke "get-5") (f32.const -13))
+(assert_return (invoke "get-6") (f64.const -14))
+
+(assert_return (invoke "set-x" (i32.const 6)))
+(assert_return (invoke "set-y" (i64.const 7)))
+(assert_return (invoke "set-5" (f32.const 8)))
+(assert_return (invoke "set-6" (f64.const 9)))
+
+(assert_return (invoke "get-x") (i32.const 6))
+(assert_return (invoke "get-y") (i64.const 7))
+(assert_return (invoke "get-5") (f32.const 8))
+(assert_return (invoke "get-6") (f64.const 9))
+
+(assert_invalid
+  (module (global f32 (f32.const 0)) (func (global.set 0 (i32.const 1))))
+  "global is immutable"
+)
+
+(assert_invalid
+  (module (global f32 (f32.neg (f32.const 0))))
+  "constant expression required"
+)
+
+(assert_invalid
+  (module (global f32 (local.get 0)))
+  "constant expression required"
+)
+
+(assert_invalid
+  (module (global i32 (f32.const 0)))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (global i32 (global.get 0)))
+  "unknown global"
+)
diff --git a/binaryen/test/spec/old_import.wast b/binaryen/test/spec/old_import.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_import.wast
@@ -0,0 +1,224 @@
+;; Functions
+
+(module
+  (import "spectest" "print" (func (param i32)))
+  (func (import "spectest" "print") (param i64))
+
+  (import "spectest" "print" (func $print_i32 (param i32)))
+  (import "spectest" "print" (func $print_i64 (param i64)))
+  (import "spectest" "print" (func $print_i32_f32 (param i32 f32)))
+  (import "spectest" "print" (func $print_i64_f64 (param i64 f64)))
+
+  (func $print_i32-2 (import "spectest" "print") (param i32))
+  (func $print_i64-2 (import "spectest" "print") (param i64))
+
+  (func (export "print32") (param $i i32)
+    (call 0 (local.get $i))
+    (call $print_i32_f32
+      (i32.add (local.get $i) (i32.const 1))
+      (f32.const 42)
+    )
+    (call $print_i32 (local.get $i))
+    (call $print_i32-2 (local.get $i))
+  )
+
+  (func (export "print64") (param $i i64)
+    (call 1 (local.get $i))
+    (call $print_i64_f64
+      (i64.add (local.get $i) (i64.const 1))
+      (f64.const 53)
+    )
+    (call $print_i64 (local.get $i))
+    (call $print_i64-2 (local.get $i))
+  )
+)
+
+(assert_return (invoke "print32" (i32.const 13)))
+(assert_return (invoke "print64" (i64.const 24)))
+
+(assert_unlinkable
+  (module (import "spectest" "unknown" (func)))
+  "unknown import"
+)
+(assert_unlinkable
+  (module (import "spectest" "table" (func)))
+  "type mismatch"
+)
+
+(assert_unlinkable
+  (module (import "spectest" "print" (func)) (table funcref (elem 0)))
+  "invalid use of host function"
+)
+
+
+;; Globals
+
+(module
+  (import "spectest" "global" (global i32))
+  (global (import "spectest" "global") i32)
+
+  (import "spectest" "global" (global $x i32))
+  (global $y (import "spectest" "global") i32)
+
+  (func (export "get-0") (result i32) (global.get 0))
+  (func (export "get-1") (result i32) (global.get 1))
+  (func (export "get-x") (result i32) (global.get $x))
+  (func (export "get-y") (result i32) (global.get $y))
+
+  ;; TODO: mutable globals
+  ;; (func (export "set-0") (param i32) (global.set 0 (local.get 0)))
+  ;; (func (export "set-1") (param i32) (global.set 1 (local.get 0)))
+  ;; (func (export "set-x") (param i32) (global.set $x (local.get 0)))
+  ;; (func (export "set-y") (param i32) (global.set $y (local.get 0)))
+)
+
+(assert_return (invoke "get-0") (i32.const 666))
+(assert_return (invoke "get-1") (i32.const 666))
+(assert_return (invoke "get-x") (i32.const 666))
+(assert_return (invoke "get-y") (i32.const 666))
+
+(assert_unlinkable
+  (module (import "spectest" "unknown" (global i32)))
+  "unknown import"
+)
+(assert_unlinkable
+  (module (import "spectest" "print" (global i32)))
+  "type mismatch"
+)
+
+(module (import "spectest" "global" (global i64)))
+(module (import "spectest" "global" (global f32)))
+(module (import "spectest" "global" (global f64)))
+
+
+;; Tables
+
+(module
+  (type (func (result i32)))
+  (import "spectest" "table" (table 10 20 funcref))
+  (elem 0 (i32.const 1) $f $g)
+
+  (func (export "call") (param i32) (result i32) (call_indirect (type 0) (local.get 0)))
+  (func $f (result i32) (i32.const 11))
+  (func $g (result i32) (i32.const 22))
+)
+
+(assert_trap (invoke "call" (i32.const 0)) "uninitialized element")
+(assert_return (invoke "call" (i32.const 1)) (i32.const 11))
+(assert_return (invoke "call" (i32.const 2)) (i32.const 22))
+(assert_trap (invoke "call" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "call" (i32.const 100)) "undefined element")
+
+
+(module
+  (type (func (result i32)))
+  (table (import "spectest" "table") 10 20 funcref)
+  (elem 0 (i32.const 1) $f $g)
+
+  (func (export "call") (param i32) (result i32) (call_indirect (type 0) (local.get 0)))
+  (func $f (result i32) (i32.const 11))
+  (func $g (result i32) (i32.const 22))
+)
+
+(assert_trap (invoke "call" (i32.const 0)) "uninitialized element")
+(assert_return (invoke "call" (i32.const 1)) (i32.const 11))
+(assert_return (invoke "call" (i32.const 2)) (i32.const 22))
+(assert_trap (invoke "call" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "call" (i32.const 100)) "undefined element")
+
+
+(assert_invalid
+  (module (import "" "" (table 10 funcref)) (import "" "" (table 10 funcref)))
+  "multiple tables"
+)
+(assert_invalid
+  (module (import "" "" (table 10 funcref)) (table 10 funcref))
+  "multiple tables"
+)
+(assert_invalid
+  (module (table 10 funcref) (table 10 funcref))
+  "multiple tables"
+)
+
+(assert_unlinkable
+  (module (import "spectest" "unknown" (table 10 funcref)))
+  "unknown import"
+)
+(assert_unlinkable
+  (module (import "spectest" "print" (table 10 funcref)))
+  "type mismatch"
+)
+(assert_unlinkable
+  (module (import "spectest" "table" (table 12 funcref)))
+  "actual size smaller than declared"
+)
+(assert_unlinkable
+  (module (import "spectest" "table" (table 10 15 funcref)))
+  "maximum size larger than declared"
+)
+
+
+;; Memories
+
+(module
+  (import "spectest" "memory" (memory 1 2))
+  (data 0 (i32.const 10) "\10")
+
+  (func (export "load") (param i32) (result i32) (i32.load (local.get 0)))
+)
+
+(assert_return (invoke "load" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load" (i32.const 10)) (i32.const 16))
+(assert_return (invoke "load" (i32.const 8)) (i32.const 0x100000))
+(assert_trap (invoke "load" (i32.const 1000000)) "out of bounds memory access")
+
+(module
+  (memory (import "spectest" "memory") 1 2)
+  (data 0 (i32.const 10) "\10")
+
+  (func (export "load") (param i32) (result i32) (i32.load (local.get 0)))
+)
+(assert_return (invoke "load" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load" (i32.const 10)) (i32.const 16))
+(assert_return (invoke "load" (i32.const 8)) (i32.const 0x100000))
+(assert_trap (invoke "load" (i32.const 1000000)) "out of bounds memory access")
+
+(assert_invalid
+  (module (import "" "" (memory 1)) (import "" "" (memory 1)))
+  "multiple memories"
+)
+(assert_invalid
+  (module (import "" "" (memory 1)) (memory 0))
+  "multiple memories"
+)
+(assert_invalid
+  (module (memory 0) (memory 0))
+  "multiple memories"
+)
+
+(assert_unlinkable
+  (module (import "spectest" "unknown" (memory 1)))
+  "unknown import"
+)
+(assert_unlinkable
+  (module (import "spectest" "print" (memory 1)))
+  "type mismatch"
+)
+(assert_unlinkable
+  (module (import "spectest" "memory" (memory 2)))
+  "actual size smaller than declared"
+)
+(assert_unlinkable
+  (module (import "spectest" "memory" (memory 1 1)))
+  "maximum size larger than declared"
+)
+
+(module
+  (import "spectest" "memory" (memory 0 3))  ;; actual has max size 2
+  (func (export "grow") (param i32) (result i32) (memory.grow (local.get 0)))
+)
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const -1))
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 2))
diff --git a/binaryen/test/spec/old_int_literals.wast b/binaryen/test/spec/old_int_literals.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_int_literals.wast
@@ -0,0 +1,49 @@
+(module
+  (func (export "i32.test") (result i32) (return (i32.const 0x0bAdD00D)))
+  (func (export "i32.umax") (result i32) (return (i32.const 0xffffffff)))
+  (func (export "i32.smax") (result i32) (return (i32.const 0x7fffffff)))
+  (func (export "i32.neg_smax") (result i32) (return (i32.const -0x7fffffff)))
+  (func (export "i32.smin") (result i32) (return (i32.const -0x80000000)))
+  (func (export "i32.alt_smin") (result i32) (return (i32.const 0x80000000)))
+  (func (export "i32.inc_smin") (result i32) (return (i32.add (i32.const -0x80000000) (i32.const 1))))
+  (func (export "i32.neg_zero") (result i32) (return (i32.const -0x0)))
+  (func (export "i32.not_octal") (result i32) (return (i32.const 010)))
+  (func (export "i32.unsigned_decimal") (result i32) (return (i32.const 4294967295)))
+  (func (export "i32.plus_sign") (result i32) (return (i32.const +42)))
+
+  (func (export "i64.test") (result i64) (return (i64.const 0x0CABBA6E0ba66a6e)))
+  (func (export "i64.umax") (result i64) (return (i64.const 0xffffffffffffffff)))
+  (func (export "i64.smax") (result i64) (return (i64.const 0x7fffffffffffffff)))
+  (func (export "i64.neg_smax") (result i64) (return (i64.const -0x7fffffffffffffff)))
+  (func (export "i64.smin") (result i64) (return (i64.const -0x8000000000000000)))
+  (func (export "i64.alt_smin") (result i64) (return (i64.const 0x8000000000000000)))
+  (func (export "i64.inc_smin") (result i64) (return (i64.add (i64.const -0x8000000000000000) (i64.const 1))))
+  (func (export "i64.neg_zero") (result i64) (return (i64.const -0x0)))
+  (func (export "i64.not_octal") (result i64) (return (i64.const 010)))
+  (func (export "i64.unsigned_decimal") (result i64) (return (i64.const 18446744073709551615)))
+  (func (export "i64.plus_sign") (result i64) (return (i64.const +42)))
+)
+
+(assert_return (invoke "i32.test") (i32.const 195940365))
+(assert_return (invoke "i32.umax") (i32.const -1))
+(assert_return (invoke "i32.smax") (i32.const 2147483647))
+(assert_return (invoke "i32.neg_smax") (i32.const -2147483647))
+(assert_return (invoke "i32.smin") (i32.const -2147483648))
+(assert_return (invoke "i32.alt_smin") (i32.const -2147483648))
+(assert_return (invoke "i32.inc_smin") (i32.const -2147483647))
+(assert_return (invoke "i32.neg_zero") (i32.const 0))
+(assert_return (invoke "i32.not_octal") (i32.const 10))
+(assert_return (invoke "i32.unsigned_decimal") (i32.const -1))
+(assert_return (invoke "i32.plus_sign") (i32.const 42))
+
+(assert_return (invoke "i64.test") (i64.const 913028331277281902))
+(assert_return (invoke "i64.umax") (i64.const -1))
+(assert_return (invoke "i64.smax") (i64.const 9223372036854775807))
+(assert_return (invoke "i64.neg_smax") (i64.const -9223372036854775807))
+(assert_return (invoke "i64.smin") (i64.const -9223372036854775808))
+(assert_return (invoke "i64.alt_smin") (i64.const -9223372036854775808))
+(assert_return (invoke "i64.inc_smin") (i64.const -9223372036854775807))
+(assert_return (invoke "i64.neg_zero") (i64.const 0))
+(assert_return (invoke "i64.not_octal") (i64.const 10))
+(assert_return (invoke "i64.unsigned_decimal") (i64.const -1))
+(assert_return (invoke "i64.plus_sign") (i64.const 42))
diff --git a/binaryen/test/spec/old_loop.wast b/binaryen/test/spec/old_loop.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_loop.wast
@@ -0,0 +1,282 @@
+;; Test `loop` opcode
+
+(module
+  (func $dummy)
+
+  (func (export "empty")
+    (loop)
+    (loop $l)
+  )
+
+  (func (export "singular") (result i32)
+    (loop (nop))
+    (loop i32 (i32.const 7))
+  )
+
+  (func (export "multi") (result i32)
+    (loop (call $dummy) (call $dummy) (call $dummy) (call $dummy))
+    (loop i32 (call $dummy) (call $dummy) (call $dummy) (i32.const 8))
+  )
+
+  (func (export "nested") (result i32)
+    (loop i32
+      (loop (call $dummy) (block) (nop))
+      (loop i32 (call $dummy) (i32.const 9))
+    )
+  )
+
+  (func (export "deep") (result i32)
+    (loop i32 (block i32 (loop i32 (block i32 (loop i32 (block i32
+      (loop i32 (block i32 (loop i32 (block i32 (loop i32 (block i32
+        (loop i32 (block i32 (loop i32 (block i32 (loop i32 (block i32
+          (loop i32 (block i32 (loop i32 (block i32 (loop i32 (block i32
+            (loop i32 (block i32 (loop i32 (block i32 (loop i32 (block i32
+              (loop i32 (block i32 (loop i32 (block i32 (loop i32 (block i32
+                (loop i32 (block i32 (loop i32 (block i32 (loop i32 (block i32
+                  (loop i32 (block i32 (call $dummy) (i32.const 150)))
+                ))))))
+              ))))))
+            ))))))
+          ))))))
+        ))))))
+      ))))))
+    ))))))
+  )
+
+  (func (export "as-unary-operand") (result i32)
+    (i32.ctz (loop i32 (call $dummy) (i32.const 13)))
+  )
+  (func (export "as-binary-operand") (result i32)
+    (i32.mul
+      (loop i32 (call $dummy) (i32.const 3))
+      (loop i32 (call $dummy) (i32.const 4))
+    )
+  )
+  (func (export "as-test-operand") (result i32)
+    (i32.eqz (loop i32 (call $dummy) (i32.const 13)))
+  )
+  (func (export "as-compare-operand") (result i32)
+    (f32.gt
+      (loop f32 (call $dummy) (f32.const 3))
+      (loop f32 (call $dummy) (f32.const 3))
+    )
+  )
+
+  (func (export "break-bare") (result i32)
+    (block (loop (br 1) (br 0) (unreachable)))
+    (block (loop (br_if 1 (i32.const 1)) (unreachable)))
+    (block (loop (br_table 1 (i32.const 0)) (unreachable)))
+    (block (loop (br_table 1 1 1 (i32.const 1)) (unreachable)))
+    (i32.const 19)
+  )
+  (func (export "break-value") (result i32)
+    (block i32 (loop i32 (br 1 (i32.const 18)) (br 0) (i32.const 19)))
+  )
+  (func (export "break-repeated") (result i32)
+    (block i32
+      (loop i32
+        (br 1 (i32.const 18))
+        (br 1 (i32.const 19))
+        (drop (br_if 1 (i32.const 20) (i32.const 0)))
+        (drop (br_if 1 (i32.const 20) (i32.const 1)))
+        (br 1 (i32.const 21))
+        (br_table 1 (i32.const 22) (i32.const 0))
+        (br_table 1 1 1 (i32.const 23) (i32.const 1))
+        (i32.const 21)
+      )
+    )
+  )
+  (func (export "break-inner") (result i32)
+    (local i32)
+    (local.set 0 (i32.const 0))
+    (local.set 0 (i32.add (local.get 0) (block i32 (loop i32 (block i32 (br 2 (i32.const 0x1)))))))
+    (local.set 0 (i32.add (local.get 0) (block i32 (loop i32 (loop i32 (br 2 (i32.const 0x2)))))))
+    (local.set 0 (i32.add (local.get 0) (block i32 (loop i32 (block i32 (loop i32 (br 1 (i32.const 0x4))))))))
+    (local.set 0 (i32.add (local.get 0) (block i32 (loop i32 (i32.ctz (br 1 (i32.const 0x8)))))))
+    (local.set 0 (i32.add (local.get 0) (block i32 (loop i32 (i32.ctz (loop i32 (br 2 (i32.const 0x10))))))))
+    (local.get 0)
+  )
+  (func (export "cont-inner") (result i32)
+    (local i32)
+    (local.set 0 (i32.const 0))
+    (local.set 0 (i32.add (local.get 0) (loop i32 (loop i32 (br 1)))))
+    (local.set 0 (i32.add (local.get 0) (loop i32 (i32.ctz (br 0)))))
+    (local.set 0 (i32.add (local.get 0) (loop i32 (i32.ctz (loop i32 (br 1))))))
+    (local.get 0)
+  )
+
+  (func $fx (export "effects") (result i32)
+    (local i32)
+    (block
+      (loop
+        (local.set 0 (i32.const 1))
+        (local.set 0 (i32.mul (local.get 0) (i32.const 3)))
+        (local.set 0 (i32.sub (local.get 0) (i32.const 5)))
+        (local.set 0 (i32.mul (local.get 0) (i32.const 7)))
+        (br 1)
+        (local.set 0 (i32.mul (local.get 0) (i32.const 100)))
+      )
+    )
+    (i32.eq (local.get 0) (i32.const -14))
+  )
+
+  (func (export "while") (param i64) (result i64)
+    (local i64)
+    (local.set 1 (i64.const 1))
+    (block
+      (loop
+        (br_if 1 (i64.eqz (local.get 0)))
+        (local.set 1 (i64.mul (local.get 0) (local.get 1)))
+        (local.set 0 (i64.sub (local.get 0) (i64.const 1)))
+        (br 0)
+      )
+    )
+    (local.get 1)
+  )
+
+  (func (export "for") (param i64) (result i64)
+    (local i64 i64)
+    (local.set 1 (i64.const 1))
+    (local.set 2 (i64.const 2))
+    (block
+      (loop
+        (br_if 1 (i64.gt_u (local.get 2) (local.get 0)))
+        (local.set 1 (i64.mul (local.get 1) (local.get 2)))
+        (local.set 2 (i64.add (local.get 2) (i64.const 1)))
+        (br 0)
+      )
+    )
+    (local.get 1)
+  )
+
+  (func (export "nesting") (param f32 f32) (result f32)
+    (local f32 f32)
+    (block
+      (loop
+        (br_if 1 (f32.eq (local.get 0) (f32.const 0)))
+        (local.set 2 (local.get 1))
+        (block
+          (loop
+            (br_if 1 (f32.eq (local.get 2) (f32.const 0)))
+            (br_if 3 (f32.lt (local.get 2) (f32.const 0)))
+            (local.set 3 (f32.add (local.get 3) (local.get 2)))
+            (local.set 2 (f32.sub (local.get 2) (f32.const 2)))
+            (br 0)
+          )
+        )
+        (local.set 3 (f32.div (local.get 3) (local.get 0)))
+        (local.set 0 (f32.sub (local.get 0) (f32.const 1)))
+        (br 0)
+      )
+    )
+    (local.get 3)
+  )
+)
+
+(assert_return (invoke "empty"))
+(assert_return (invoke "singular") (i32.const 7))
+(assert_return (invoke "multi") (i32.const 8))
+(assert_return (invoke "nested") (i32.const 9))
+(assert_return (invoke "deep") (i32.const 150))
+
+(assert_return (invoke "as-unary-operand") (i32.const 0))
+(assert_return (invoke "as-binary-operand") (i32.const 12))
+(assert_return (invoke "as-test-operand") (i32.const 0))
+(assert_return (invoke "as-compare-operand") (i32.const 0))
+
+(assert_return (invoke "break-bare") (i32.const 19))
+(assert_return (invoke "break-value") (i32.const 18))
+(assert_return (invoke "break-repeated") (i32.const 18))
+(assert_return (invoke "break-inner") (i32.const 0x1f))
+
+(assert_return (invoke "effects") (i32.const 1))
+
+(assert_return (invoke "while" (i64.const 0)) (i64.const 1))
+(assert_return (invoke "while" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "while" (i64.const 2)) (i64.const 2))
+(assert_return (invoke "while" (i64.const 3)) (i64.const 6))
+(assert_return (invoke "while" (i64.const 5)) (i64.const 120))
+(assert_return (invoke "while" (i64.const 20)) (i64.const 2432902008176640000))
+
+(assert_return (invoke "for" (i64.const 0)) (i64.const 1))
+(assert_return (invoke "for" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "for" (i64.const 2)) (i64.const 2))
+(assert_return (invoke "for" (i64.const 3)) (i64.const 6))
+(assert_return (invoke "for" (i64.const 5)) (i64.const 120))
+(assert_return (invoke "for" (i64.const 20)) (i64.const 2432902008176640000))
+
+(assert_return (invoke "nesting" (f32.const 0) (f32.const 7)) (f32.const 0))
+(assert_return (invoke "nesting" (f32.const 7) (f32.const 0)) (f32.const 0))
+(assert_return (invoke "nesting" (f32.const 1) (f32.const 1)) (f32.const 1))
+(assert_return (invoke "nesting" (f32.const 1) (f32.const 2)) (f32.const 2))
+(assert_return (invoke "nesting" (f32.const 1) (f32.const 3)) (f32.const 4))
+(assert_return (invoke "nesting" (f32.const 1) (f32.const 4)) (f32.const 6))
+(assert_return (invoke "nesting" (f32.const 1) (f32.const 100)) (f32.const 2550))
+(assert_return (invoke "nesting" (f32.const 1) (f32.const 101)) (f32.const 2601))
+(assert_return (invoke "nesting" (f32.const 2) (f32.const 1)) (f32.const 1))
+(assert_return (invoke "nesting" (f32.const 3) (f32.const 1)) (f32.const 1))
+(assert_return (invoke "nesting" (f32.const 10) (f32.const 1)) (f32.const 1))
+(assert_return (invoke "nesting" (f32.const 2) (f32.const 2)) (f32.const 3))
+(assert_return (invoke "nesting" (f32.const 2) (f32.const 3)) (f32.const 4))
+(assert_return (invoke "nesting" (f32.const 7) (f32.const 4)) (f32.const 10.3095235825))
+(assert_return (invoke "nesting" (f32.const 7) (f32.const 100)) (f32.const 4381.54785156))
+(assert_return (invoke "nesting" (f32.const 7) (f32.const 101)) (f32.const 2601))
+
+(assert_invalid
+  (module (func $type-empty-i32 (result i32) (loop)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-i64 (result i64) (loop)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f32 (result f32) (loop)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-empty-f64 (result f64) (loop)))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-value-void-vs-num (result i32)
+    (loop (nop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-num-vs-num (result i32)
+    (loop (f32.const 0))
+  ))
+  "type mismatch"
+)
+
+(; TODO(stack): soft failure
+(assert_invalid
+  (module (func $type-value-void-vs-num-after-break (result i32)
+    (loop (br 1 (i32.const 1)) (nop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-num-vs-num-after-break (result i32)
+    (loop (br 1 (i32.const 1)) (f32.const 0))
+  ))
+  "type mismatch"
+)
+;)
+
+(assert_invalid
+  (module (func $type-cont-last-void-vs-empty (result i32)
+    (loop (br 0 (nop)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-cont-last-num-vs-empty (result i32)
+    (loop (br 0 (i32.const 0)))
+  ))
+  "type mismatch"
+)
+
diff --git a/binaryen/test/spec/old_select.wast b/binaryen/test/spec/old_select.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_select.wast
@@ -0,0 +1,109 @@
+(module
+  (func $dummy)
+
+  (func (export "select_i32") (param $lhs i32) (param $rhs i32) (param $cond i32) (result i32)
+   (select (local.get $lhs) (local.get $rhs) (local.get $cond)))
+  (func (export "select_i64") (param $lhs i64) (param $rhs i64) (param $cond i32) (result i64)
+   (select (local.get $lhs) (local.get $rhs) (local.get $cond)))
+  (func (export "select_f32") (param $lhs f32) (param $rhs f32) (param $cond i32) (result f32)
+   (select (local.get $lhs) (local.get $rhs) (local.get $cond)))
+  (func (export "select_f64") (param $lhs f64) (param $rhs f64) (param $cond i32) (result f64)
+   (select (local.get $lhs) (local.get $rhs) (local.get $cond)))
+
+  (func (export "select-i32-t") (param i32 i32 i32) (result i32)
+    (select (result i32) (local.get 0) (local.get 1) (local.get 2))
+  )
+  (func (export "select-i64-t") (param i64 i64 i32) (result i64)
+    (select (result i64) (local.get 0) (local.get 1) (local.get 2))
+  )
+  (func (export "select-f32-t") (param f32 f32 i32) (result f32)
+    (select (result f32) (local.get 0) (local.get 1) (local.get 2))
+  )
+  (func (export "select-f64-t") (param f64 f64 i32) (result f64)
+    (select (result f64) (local.get 0) (local.get 1) (local.get 2))
+  )
+
+  (func (export "select-funcref") (param funcref funcref i32) (result funcref)
+    (select (result funcref) (local.get 0) (local.get 1) (local.get 2))
+  )
+  (func (export "select-externref") (param externref externref i32) (result externref)
+    (select (result externref) (local.get 0) (local.get 1) (local.get 2))
+  )
+
+  ;; Check that both sides of the select are evaluated
+  (func (export "select_trap_l") (param $cond i32) (result i32)
+   (select (unreachable) (i32.const 0) (local.get $cond)))
+  (func (export "select_trap_r") (param $cond i32) (result i32)
+   (select (i32.const 0) (unreachable) (local.get $cond)))
+)
+
+(assert_return (invoke "select_i32" (i32.const 1) (i32.const 2) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "select_i64" (i64.const 2) (i64.const 1) (i32.const 1)) (i64.const 2))
+(assert_return (invoke "select_f32" (f32.const 1) (f32.const 2) (i32.const 1)) (f32.const 1))
+(assert_return (invoke "select_f64" (f64.const 1) (f64.const 2) (i32.const 1)) (f64.const 1))
+
+(assert_return (invoke "select_i32" (i32.const 1) (i32.const 2) (i32.const 0)) (i32.const 2))
+(assert_return (invoke "select_i32" (i32.const 2) (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "select_i64" (i64.const 2) (i64.const 1) (i32.const -1)) (i64.const 2))
+(assert_return (invoke "select_i64" (i64.const 2) (i64.const 1) (i32.const 0xf0f0f0f0)) (i64.const 2))
+
+(assert_return (invoke "select_f32" (f32.const nan) (f32.const 1) (i32.const 1)) (f32.const nan))
+(assert_return (invoke "select_f32" (f32.const nan:0x20304) (f32.const 1) (i32.const 1)) (f32.const nan:0x20304))
+(assert_return (invoke "select_f32" (f32.const nan) (f32.const 1) (i32.const 0)) (f32.const 1))
+(assert_return (invoke "select_f32" (f32.const nan:0x20304) (f32.const 1) (i32.const 0)) (f32.const 1))
+(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan) (i32.const 1)) (f32.const 2))
+(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan:0x20304) (i32.const 1)) (f32.const 2))
+(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan) (i32.const 0)) (f32.const nan))
+(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan:0x20304) (i32.const 0)) (f32.const nan:0x20304))
+
+(assert_return (invoke "select_f64" (f64.const nan) (f64.const 1) (i32.const 1)) (f64.const nan))
+(assert_return (invoke "select_f64" (f64.const nan:0x20304) (f64.const 1) (i32.const 1)) (f64.const nan:0x20304))
+(assert_return (invoke "select_f64" (f64.const nan) (f64.const 1) (i32.const 0)) (f64.const 1))
+(assert_return (invoke "select_f64" (f64.const nan:0x20304) (f64.const 1) (i32.const 0)) (f64.const 1))
+(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan) (i32.const 1)) (f64.const 2))
+(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan:0x20304) (i32.const 1)) (f64.const 2))
+(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan) (i32.const 0)) (f64.const nan))
+(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan:0x20304) (i32.const 0)) (f64.const nan:0x20304))
+
+(assert_return (invoke "select-i32-t" (i32.const 1) (i32.const 2) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const 1)) (i64.const 2))
+(assert_return (invoke "select-f32-t" (f32.const 1) (f32.const 2) (i32.const 1)) (f32.const 1))
+(assert_return (invoke "select-f64-t" (f64.const 1) (f64.const 2) (i32.const 1)) (f64.const 1))
+
+(assert_return (invoke "select-i32-t" (i32.const 1) (i32.const 2) (i32.const 0)) (i32.const 2))
+(assert_return (invoke "select-i32-t" (i32.const 2) (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const -1)) (i64.const 2))
+(assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const 0xf0f0f0f0)) (i64.const 2))
+
+(assert_return (invoke "select-f32-t" (f32.const nan) (f32.const 1) (i32.const 1)) (f32.const nan))
+(assert_return (invoke "select-f32-t" (f32.const nan:0x20304) (f32.const 1) (i32.const 1)) (f32.const nan:0x20304))
+(assert_return (invoke "select-f32-t" (f32.const nan) (f32.const 1) (i32.const 0)) (f32.const 1))
+(assert_return (invoke "select-f32-t" (f32.const nan:0x20304) (f32.const 1) (i32.const 0)) (f32.const 1))
+(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan) (i32.const 1)) (f32.const 2))
+(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan:0x20304) (i32.const 1)) (f32.const 2))
+(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan) (i32.const 0)) (f32.const nan))
+(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan:0x20304) (i32.const 0)) (f32.const nan:0x20304))
+
+(assert_return (invoke "select-f64-t" (f64.const nan) (f64.const 1) (i32.const 1)) (f64.const nan))
+(assert_return (invoke "select-f64-t" (f64.const nan:0x20304) (f64.const 1) (i32.const 1)) (f64.const nan:0x20304))
+(assert_return (invoke "select-f64-t" (f64.const nan) (f64.const 1) (i32.const 0)) (f64.const 1))
+(assert_return (invoke "select-f64-t" (f64.const nan:0x20304) (f64.const 1) (i32.const 0)) (f64.const 1))
+(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan) (i32.const 1)) (f64.const 2))
+(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan:0x20304) (i32.const 1)) (f64.const 2))
+(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan) (i32.const 0)) (f64.const nan))
+(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan:0x20304) (i32.const 0)) (f64.const nan:0x20304))
+
+(assert_return (invoke "select-funcref" (ref.func "dummy") (ref.null func) (i32.const 1)) (ref.func "dummy"))
+(assert_return (invoke "select-funcref" (ref.func "dummy") (ref.null func) (i32.const 0)) (ref.null func))
+(assert_return (invoke "select-externref" (ref.null extern) (ref.null extern) (i32.const 1)) (ref.null extern))
+(assert_return (invoke "select-externref" (ref.null extern) (ref.null extern) (i32.const 0)) (ref.null extern))
+
+(assert_trap (invoke "select_trap_l" (i32.const 1)) "unreachable executed")
+(assert_trap (invoke "select_trap_l" (i32.const 0)) "unreachable executed")
+(assert_trap (invoke "select_trap_r" (i32.const 1)) "unreachable executed")
+(assert_trap (invoke "select_trap_r" (i32.const 0)) "unreachable executed")
+
+(assert_invalid
+  (module (func $arity-0 (select (nop) (nop) (i32.const 1))))
+  "type mismatch"
+)
diff --git a/binaryen/test/spec/old_start.wast b/binaryen/test/spec/old_start.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_start.wast
@@ -0,0 +1,88 @@
+(assert_invalid
+  (module (func) (start 1))
+  "unknown function"
+)
+(assert_invalid
+  (module
+    (func $main (result i32) (return (i32.const 0)))
+    (start $main)
+  )
+  "start function"
+)
+(assert_invalid
+  (module
+    (func $main (param $a i32))
+    (start $main)
+  )
+  "start function"
+)
+(module
+  (memory (data "A"))
+  (func $inc
+    (i32.store8
+      (i32.const 0)
+      (i32.add
+        (i32.load8_u (i32.const 0))
+        (i32.const 1)
+      )
+    )
+  )
+  (func $get (result i32)
+    (return (i32.load8_u (i32.const 0)))
+  )
+  (func $main
+    (call $inc)
+    (call $inc)
+    (call $inc)
+  )
+
+  (start $main)
+  (export "inc" (func $inc))
+  (export "get" (func $get))
+)
+(assert_return (invoke "get") (i32.const 68))
+(invoke "inc")
+(assert_return (invoke "get") (i32.const 69))
+(invoke "inc")
+(assert_return (invoke "get") (i32.const 70))
+
+(module
+  (memory (data "A"))
+  (func $inc
+    (i32.store8
+      (i32.const 0)
+      (i32.add
+        (i32.load8_u (i32.const 0))
+        (i32.const 1)
+      )
+    )
+  )
+  (func $get (result i32)
+    (return (i32.load8_u (i32.const 0)))
+  )
+  (func $main
+    (call $inc)
+    (call $inc)
+    (call $inc)
+  )
+  (start 2)
+  (export "inc" (func $inc))
+  (export "get" (func $get))
+)
+(assert_return (invoke "get") (i32.const 68))
+(invoke "inc")
+(assert_return (invoke "get") (i32.const 69))
+(invoke "inc")
+(assert_return (invoke "get") (i32.const 70))
+
+(module
+  (func $print_i32 (import "spectest" "print") (param i32))
+  (func $main (call $print_i32 (i32.const 1)))
+  (start 1)
+)
+
+(module
+  (func $print_i32 (import "spectest" "print") (param i32))
+  (func $main (call $print_i32 (i32.const 2)))
+  (start $main)
+)
diff --git a/binaryen/test/spec/old_unreachable.wast b/binaryen/test/spec/old_unreachable.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/old_unreachable.wast
@@ -0,0 +1,262 @@
+;; Test `unreachable` operator
+
+(module
+  ;; Auxiliary definitions
+  (func $dummy)
+  (func $dummy3 (param i32 i32 i32))
+
+  (func (export "type-i32") (result i32) (unreachable))
+  (func (export "type-i64") (result i32) (unreachable))
+  (func (export "type-f32") (result f64) (unreachable))
+  (func (export "type-f64") (result f64) (unreachable))
+
+  (func (export "as-func-first") (result i32)
+    (unreachable) (i32.const -1)
+  )
+  (func (export "as-func-mid") (result i32)
+    (call $dummy) (unreachable) (i32.const -1)
+  )
+  (func (export "as-func-last")
+    (call $dummy) (unreachable)
+  )
+  (func (export "as-func-value") (result i32)
+    (call $dummy) (unreachable)
+  )
+
+  (func (export "as-block-first") (result i32)
+    (block i32 (unreachable) (i32.const 2))
+  )
+  (func (export "as-block-mid") (result i32)
+    (block i32 (call $dummy) (unreachable) (i32.const 2))
+  )
+  (func (export "as-block-last")
+    (block (nop) (call $dummy) (unreachable))
+  )
+  (func (export "as-block-value") (result i32)
+    (block i32 (nop) (call $dummy) (unreachable))
+  )
+  (func (export "as-block-broke") (result i32)
+    (block i32 (call $dummy) (br 0 (i32.const 1)) (unreachable))
+  )
+
+  (func (export "as-loop-first") (result i32)
+    (loop i32 (unreachable) (i32.const 2))
+  )
+  (func (export "as-loop-mid") (result i32)
+    (loop i32 (call $dummy) (unreachable) (i32.const 2))
+  )
+  (func (export "as-loop-last")
+    (loop (nop) (call $dummy) (unreachable))
+  )
+  (func (export "as-loop-broke") (result i32)
+    (block i32 (loop i32 (call $dummy) (br 1 (i32.const 1)) (unreachable)))
+  )
+
+  (func (export "as-br-value") (result i32)
+    (block i32 (br 0 (unreachable)))
+  )
+
+  (func (export "as-br_if-cond")
+    (block (br_if 0 (unreachable)))
+  )
+  (func (export "as-br_if-value") (result i32)
+    (block i32 (br_if 0 (unreachable) (i32.const 1)) (i32.const 7))
+  )
+  (func (export "as-br_if-value-cond") (result i32)
+    (block i32 (drop (br_if 0 (i32.const 6) (unreachable))) (i32.const 7))
+  )
+
+  (func (export "as-br_table-index")
+    (block (br_table 0 0 0 (unreachable)))
+  )
+  (func (export "as-br_table-value") (result i32)
+    (block i32 (br_table 0 0 0 (unreachable) (i32.const 1)) (i32.const 7))
+  )
+  (func (export "as-br_table-value-index") (result i32)
+    (block i32 (br_table 0 0 (i32.const 6) (unreachable)) (i32.const 7))
+  )
+
+  (func (export "as-return-value") (result i64)
+    (return (unreachable))
+  )
+
+  (func (export "as-if-cond") (result i32)
+    (if i32 (unreachable) (i32.const 0) (i32.const 1))
+  )
+  (func (export "as-if-then") (param i32 i32) (result i32)
+    (if i32 (local.get 0) (unreachable) (local.get 1))
+  )
+  (func (export "as-if-else") (param i32 i32) (result i32)
+    (if i32 (local.get 0) (local.get 1) (unreachable))
+  )
+
+  (func (export "as-select-first") (param i32 i32) (result i32)
+    (select (unreachable) (local.get 0) (local.get 1))
+  )
+  (func (export "as-select-second") (param i32 i32) (result i32)
+    (select (local.get 0) (unreachable) (local.get 1))
+  )
+  (func (export "as-select-cond") (result i32)
+    (select (i32.const 0) (i32.const 1) (unreachable))
+  )
+
+  (func (export "as-call-first")
+    (call $dummy3 (unreachable) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-call-mid")
+    (call $dummy3 (i32.const 1) (unreachable) (i32.const 3))
+  )
+  (func (export "as-call-last")
+    (call $dummy3 (i32.const 1) (i32.const 2) (unreachable))
+  )
+
+  (type $sig (func (param i32 i32 i32)))
+  (table funcref (elem $dummy3))
+  (func (export "as-call_indirect-func")
+    (call_indirect (type $sig) (unreachable) (i32.const 1) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-call_indirect-first")
+    (call_indirect (type $sig) (i32.const 0) (unreachable) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-call_indirect-mid")
+    (call_indirect (type $sig) (i32.const 0) (i32.const 1) (unreachable) (i32.const 3))
+  )
+  (func (export "as-call_indirect-last")
+    (call_indirect (type $sig) (i32.const 0) (i32.const 1) (i32.const 2) (unreachable))
+  )
+
+  (func (export "as-local.set-value") (local f32)
+    (local.set 0 (unreachable))
+  )
+
+  (memory 1)
+  (func (export "as-load-address") (result f32)
+    (f32.load (unreachable))
+  )
+  (func (export "as-loadN-address") (result i64)
+    (i64.load8_s (unreachable))
+  )
+
+  (func (export "as-store-address")
+    (f64.store (unreachable) (f64.const 7))
+  )
+  (func (export "as-store-value")
+    (i64.store (i32.const 2) (unreachable))
+  )
+
+  (func (export "as-storeN-address")
+    (i32.store8 (unreachable) (i32.const 7))
+  )
+  (func (export "as-storeN-value")
+    (i64.store16 (i32.const 2) (unreachable))
+  )
+
+  (func (export "as-unary-operand") (result f32)
+    (f32.neg (unreachable))
+  )
+
+  (func (export "as-binary-left") (result i32)
+    (i32.add (unreachable) (i32.const 10))
+  )
+  (func (export "as-binary-right") (result i64)
+    (i64.sub (i64.const 10) (unreachable))
+  )
+
+  (func (export "as-test-operand") (result i32)
+    (i32.eqz (unreachable))
+  )
+
+  (func (export "as-compare-left") (result i32)
+    (f64.le (unreachable) (f64.const 10))
+  )
+  (func (export "as-compare-right") (result i32)
+    (f32.ne (f32.const 10) (unreachable))
+  )
+
+  (func (export "as-convert-operand") (result i32)
+    (i32.wrap_i64 (unreachable))
+  )
+
+  (func (export "as-memory.grow-size") (result i32)
+    (memory.grow (unreachable))
+  )
+)
+
+(assert_trap (invoke "type-i32") "unreachable")
+(assert_trap (invoke "type-i64") "unreachable")
+(assert_trap (invoke "type-f32") "unreachable")
+(assert_trap (invoke "type-f64") "unreachable")
+
+(assert_trap (invoke "as-func-first") "unreachable")
+(assert_trap (invoke "as-func-mid") "unreachable")
+(assert_trap (invoke "as-func-last") "unreachable")
+(assert_trap (invoke "as-func-value") "unreachable")
+
+(assert_trap (invoke "as-block-first") "unreachable")
+(assert_trap (invoke "as-block-mid") "unreachable")
+(assert_trap (invoke "as-block-last") "unreachable")
+(assert_trap (invoke "as-block-value") "unreachable")
+(assert_return (invoke "as-block-broke") (i32.const 1))
+
+(assert_trap (invoke "as-loop-first") "unreachable")
+(assert_trap (invoke "as-loop-mid") "unreachable")
+(assert_trap (invoke "as-loop-last") "unreachable")
+(assert_return (invoke "as-loop-broke") (i32.const 1))
+
+(assert_trap (invoke "as-br-value") "unreachable")
+
+(assert_trap (invoke "as-br_if-cond") "unreachable")
+(assert_trap (invoke "as-br_if-value") "unreachable")
+(assert_trap (invoke "as-br_if-value-cond") "unreachable")
+
+(assert_trap (invoke "as-br_table-index") "unreachable")
+(assert_trap (invoke "as-br_table-value") "unreachable")
+(assert_trap (invoke "as-br_table-value-index") "unreachable")
+
+(assert_trap (invoke "as-return-value") "unreachable")
+
+(assert_trap (invoke "as-if-cond") "unreachable")
+(assert_trap (invoke "as-if-then" (i32.const 1) (i32.const 6)) "unreachable")
+(assert_return (invoke "as-if-then" (i32.const 0) (i32.const 6)) (i32.const 6))
+(assert_trap (invoke "as-if-else" (i32.const 0) (i32.const 6)) "unreachable")
+(assert_return (invoke "as-if-else" (i32.const 1) (i32.const 6)) (i32.const 6))
+
+(assert_trap (invoke "as-select-first" (i32.const 0) (i32.const 6)) "unreachable")
+(assert_trap (invoke "as-select-first" (i32.const 1) (i32.const 6)) "unreachable")
+(assert_trap (invoke "as-select-second" (i32.const 0) (i32.const 6)) "unreachable")
+(assert_trap (invoke "as-select-second" (i32.const 1) (i32.const 6)) "unreachable")
+(assert_trap (invoke "as-select-cond") "unreachable")
+
+(assert_trap (invoke "as-call-first") "unreachable")
+(assert_trap (invoke "as-call-mid") "unreachable")
+(assert_trap (invoke "as-call-last") "unreachable")
+
+(assert_trap (invoke "as-call_indirect-func") "unreachable")
+(assert_trap (invoke "as-call_indirect-first") "unreachable")
+(assert_trap (invoke "as-call_indirect-mid") "unreachable")
+(assert_trap (invoke "as-call_indirect-last") "unreachable")
+
+(assert_trap (invoke "as-local.set-value") "unreachable")
+
+(assert_trap (invoke "as-load-address") "unreachable")
+(assert_trap (invoke "as-loadN-address") "unreachable")
+
+(assert_trap (invoke "as-store-address") "unreachable")
+(assert_trap (invoke "as-store-value") "unreachable")
+(assert_trap (invoke "as-storeN-address") "unreachable")
+(assert_trap (invoke "as-storeN-value") "unreachable")
+
+(assert_trap (invoke "as-unary-operand") "unreachable")
+
+(assert_trap (invoke "as-binary-left") "unreachable")
+(assert_trap (invoke "as-binary-right") "unreachable")
+
+(assert_trap (invoke "as-test-operand") "unreachable")
+
+(assert_trap (invoke "as-compare-left") "unreachable")
+(assert_trap (invoke "as-compare-right") "unreachable")
+
+(assert_trap (invoke "as-convert-operand") "unreachable")
+
+(assert_trap (invoke "as-memory.grow-size") "unreachable")
+
diff --git a/binaryen/test/spec/ref_func.wast b/binaryen/test/spec/ref_func.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/ref_func.wast
@@ -0,0 +1,43 @@
+(module
+  (func (export "f") (param $x i32) (result i32) (local.get $x))
+)
+(module
+  (func $f (import "M" "f") (param i32) (result i32))
+  (func $g (param $x i32) (result i32) (i32.add (local.get $x) (i32.const 1)))
+
+  (global externref (ref.null extern))
+  (global funcref (ref.func $f))
+  (global funcref (ref.func $g))
+  (global $v (mut funcref) (ref.func $f))
+
+  (func (export "is_null-f") (result i32)
+    (ref.is_null (ref.func $f))
+  )
+  (func (export "is_null-g") (result i32)
+    (ref.is_null (ref.func $g))
+  )
+  (func (export "is_null-v") (result i32)
+    (ref.is_null (global.get $v))
+  )
+
+  (func (export "set-f") (global.set $v (ref.func $f)))
+  (func (export "set-g") (global.set $v (ref.func $g)))
+
+  (table $t 1 funcref)
+)
+
+(assert_return (invoke "is_null-f") (i32.const 0))
+(assert_return (invoke "is_null-g") (i32.const 0))
+(assert_return (invoke "is_null-v") (i32.const 0))
+
+(invoke "set-g")
+(invoke "set-f")
+
+(assert_invalid
+  (module
+    (func $f (import "M" "f") (param i32) (result i32))
+    (func $g (import "M" "g") (param i32) (result i32))
+    (global funcref (ref.func 7))
+  )
+  "unknown function 7"
+)
diff --git a/binaryen/test/spec/ref_is_null.wast b/binaryen/test/spec/ref_is_null.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/ref_is_null.wast
@@ -0,0 +1,11 @@
+(module
+  (func $f1 (export "externref") (param $x externref) (result i32)
+    (ref.is_null (local.get $x))
+  )
+  (func $f2 (export "funcref") (param $x funcref) (result i32)
+    (ref.is_null (local.get $x))
+  )
+)
+
+(assert_return (invoke "externref" (ref.null extern)) (i32.const 1))
+(assert_return (invoke "funcref" (ref.null func)) (i32.const 1))
diff --git a/binaryen/test/spec/ref_null.wast b/binaryen/test/spec/ref_null.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/ref_null.wast
@@ -0,0 +1,10 @@
+(module
+  (func (export "externref") (result externref) (ref.null extern))
+  (func (export "funcref") (result funcref) (ref.null func))
+
+  (global externref (ref.null extern))
+  (global funcref (ref.null func))
+)
+
+(assert_return (invoke "externref") (ref.null extern))
+(assert_return (invoke "funcref") (ref.null func))
diff --git a/binaryen/test/spec/resizing.wast b/binaryen/test/spec/resizing.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/resizing.wast
@@ -0,0 +1,58 @@
+(module
+    (memory 0)
+
+    (func (export "load_at_zero") (result i32) (i32.load (i32.const 0)))
+    (func (export "store_at_zero") (i32.store (i32.const 0) (i32.const 2)))
+
+    (func (export "load_at_page_size") (result i32) (i32.load (i32.const 0x10000)))
+    (func (export "store_at_page_size") (i32.store (i32.const 0x10000) (i32.const 3)))
+
+    (func (export "grow") (param $sz i32) (result i32) (memory.grow (local.get $sz)))
+    (func (export "size") (result i32) (memory.size))
+)
+
+(assert_return (invoke "size") (i32.const 0))
+(assert_trap (invoke "store_at_zero") "out of bounds memory access")
+(assert_trap (invoke "load_at_zero") "out of bounds memory access")
+(assert_trap (invoke "store_at_page_size") "out of bounds memory access")
+(assert_trap (invoke "load_at_page_size") "out of bounds memory access")
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "size") (i32.const 1))
+(assert_return (invoke "load_at_zero") (i32.const 0))
+(assert_return (invoke "store_at_zero"))
+(assert_return (invoke "load_at_zero") (i32.const 2))
+(assert_trap (invoke "store_at_page_size") "out of bounds memory access")
+(assert_trap (invoke "load_at_page_size") "out of bounds memory access")
+(assert_return (invoke "grow" (i32.const 4)) (i32.const 1))
+(assert_return (invoke "size") (i32.const 5))
+(assert_return (invoke "load_at_zero") (i32.const 2))
+(assert_return (invoke "store_at_zero"))
+(assert_return (invoke "load_at_zero") (i32.const 2))
+(assert_return (invoke "load_at_page_size") (i32.const 0))
+(assert_return (invoke "store_at_page_size"))
+(assert_return (invoke "load_at_page_size") (i32.const 3))
+
+
+(module
+  (memory 0)
+  (func (export "grow") (param i32) (result i32) (memory.grow (local.get 0)))
+)
+
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 2)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 10000)) (i32.const 3))
+
+(module
+  (memory 0 10)
+  (func (export "grow") (param i32) (result i32) (memory.grow (local.get 0)))
+)
+
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "grow" (i32.const 6)) (i32.const 4))
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 10))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const -1))
diff --git a/binaryen/test/spec/resizing64.wast b/binaryen/test/spec/resizing64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/resizing64.wast
@@ -0,0 +1,58 @@
+(module
+    (memory i64 0)
+
+    (func (export "load_at_zero") (result i32) (i32.load (i64.const 0)))
+    (func (export "store_at_zero") (i32.store (i64.const 0) (i32.const 2)))
+
+    (func (export "load_at_page_size") (result i32) (i32.load (i64.const 0x10000)))
+    (func (export "store_at_page_size") (i32.store (i64.const 0x10000) (i32.const 3)))
+
+    (func (export "grow") (param $sz i64) (result i64) (memory.grow (local.get $sz)))
+    (func (export "size") (result i64) (memory.size))
+)
+
+(assert_return (invoke "size") (i64.const 0))
+(assert_trap (invoke "store_at_zero") "out of bounds memory access")
+(assert_trap (invoke "load_at_zero") "out of bounds memory access")
+(assert_trap (invoke "store_at_page_size") "out of bounds memory access")
+(assert_trap (invoke "load_at_page_size") "out of bounds memory access")
+(assert_return (invoke "grow" (i64.const 1)) (i64.const 0))
+(assert_return (invoke "size") (i64.const 1))
+(assert_return (invoke "load_at_zero") (i32.const 0))
+(assert_return (invoke "store_at_zero"))
+(assert_return (invoke "load_at_zero") (i32.const 2))
+(assert_trap (invoke "store_at_page_size") "out of bounds memory access")
+(assert_trap (invoke "load_at_page_size") "out of bounds memory access")
+(assert_return (invoke "grow" (i64.const 4)) (i64.const 1))
+(assert_return (invoke "size") (i64.const 5))
+(assert_return (invoke "load_at_zero") (i32.const 2))
+(assert_return (invoke "store_at_zero"))
+(assert_return (invoke "load_at_zero") (i32.const 2))
+(assert_return (invoke "load_at_page_size") (i32.const 0))
+(assert_return (invoke "store_at_page_size"))
+(assert_return (invoke "load_at_page_size") (i32.const 3))
+
+
+(module
+  (memory i64 0)
+  (func (export "grow") (param i64) (result i64) (memory.grow (local.get 0)))
+)
+
+(assert_return (invoke "grow" (i64.const 0)) (i64.const 0))
+(assert_return (invoke "grow" (i64.const 1)) (i64.const 0))
+(assert_return (invoke "grow" (i64.const 0)) (i64.const 1))
+(assert_return (invoke "grow" (i64.const 2)) (i64.const 1))
+(assert_return (invoke "grow" (i64.const 10000)) (i64.const 3))
+
+(module
+  (memory i64 0 10)
+  (func (export "grow") (param i64) (result i64) (memory.grow (local.get 0)))
+)
+
+(assert_return (invoke "grow" (i64.const 0)) (i64.const 0))
+(assert_return (invoke "grow" (i64.const 1)) (i64.const 0))
+(assert_return (invoke "grow" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "grow" (i64.const 2)) (i64.const 2))
+(assert_return (invoke "grow" (i64.const 6)) (i64.const 4))
+(assert_return (invoke "grow" (i64.const 0)) (i64.const 10))
+(assert_return (invoke "grow" (i64.const 1)) (i64.const -1))
diff --git a/binaryen/test/spec/return.wast b/binaryen/test/spec/return.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/return.wast
@@ -0,0 +1,479 @@
+;; Test `return` operator
+
+(module
+  ;; Auxiliary definition
+  (func $dummy)
+
+  (func (export "type-i32") (drop (i32.ctz (return))))
+  (func (export "type-i64") (drop (i64.ctz (return))))
+  (func (export "type-f32") (drop (f32.neg (return))))
+  (func (export "type-f64") (drop (f64.neg (return))))
+
+  (func (export "type-i32-value") (result i32)
+    (block (result i32) (i32.ctz (return (i32.const 1))))
+  )
+  (func (export "type-i64-value") (result i64)
+    (block (result i64) (i64.ctz (return (i64.const 2))))
+  )
+  (func (export "type-f32-value") (result f32)
+    (block (result f32) (f32.neg (return (f32.const 3))))
+  )
+  (func (export "type-f64-value") (result f64)
+    (block (result f64) (f64.neg (return (f64.const 4))))
+  )
+
+  (func (export "nullary") (return))
+  (func (export "unary") (result f64) (return (f64.const 3)))
+
+  (func (export "as-func-first") (result i32)
+    (return (i32.const 1)) (i32.const 2)
+  )
+  (func (export "as-func-mid") (result i32)
+    (call $dummy) (return (i32.const 2)) (i32.const 3)
+  )
+  (func (export "as-func-last")
+    (nop) (call $dummy) (return)
+  )
+  (func (export "as-func-value") (result i32)
+    (nop) (call $dummy) (return (i32.const 3))
+  )
+
+  (func (export "as-block-first")
+    (block (return) (call $dummy))
+  )
+  (func (export "as-block-mid")
+    (block (call $dummy) (return) (call $dummy))
+  )
+  (func (export "as-block-last")
+    (block (nop) (call $dummy) (return))
+  )
+  (func (export "as-block-value") (result i32)
+    (block (result i32) (nop) (call $dummy) (return (i32.const 2)))
+  )
+
+  (func (export "as-loop-first") (result i32)
+    (loop (result i32) (return (i32.const 3)) (i32.const 2))
+  )
+  (func (export "as-loop-mid") (result i32)
+    (loop (result i32) (call $dummy) (return (i32.const 4)) (i32.const 2))
+  )
+  (func (export "as-loop-last") (result i32)
+    (loop (result i32) (nop) (call $dummy) (return (i32.const 5)))
+  )
+
+  (func (export "as-br-value") (result i32)
+    (block (result i32) (br 0 (return (i32.const 9))))
+  )
+
+  (func (export "as-br_if-cond")
+    (block (br_if 0 (return)))
+  )
+  (func (export "as-br_if-value") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (return (i32.const 8)) (i32.const 1))) (i32.const 7)
+    )
+  )
+  (func (export "as-br_if-value-cond") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (i32.const 6) (return (i32.const 9)))) (i32.const 7)
+    )
+  )
+
+  (func (export "as-br_table-index") (result i64)
+    (block (br_table 0 0 0 (return (i64.const 9)))) (i64.const -1)
+  )
+  (func (export "as-br_table-value") (result i32)
+    (block (result i32)
+      (br_table 0 0 0 (return (i32.const 10)) (i32.const 1)) (i32.const 7)
+    )
+  )
+  (func (export "as-br_table-value-index") (result i32)
+    (block (result i32)
+      (br_table 0 0 (i32.const 6) (return (i32.const 11))) (i32.const 7)
+    )
+  )
+
+  (func (export "as-return-value") (result i64)
+    (return (return (i64.const 7)))
+  )
+
+  (func (export "as-if-cond") (result i32)
+    (if (result i32)
+      (return (i32.const 2)) (then (i32.const 0)) (else (i32.const 1))
+    )
+  )
+  (func (export "as-if-then") (param i32 i32) (result i32)
+    (if (result i32)
+      (local.get 0) (then (return (i32.const 3))) (else (local.get 1))
+    )
+  )
+  (func (export "as-if-else") (param i32 i32) (result i32)
+    (if (result i32)
+      (local.get 0) (then (local.get 1)) (else (return (i32.const 4)))
+    )
+  )
+
+  (func (export "as-select-first") (param i32 i32) (result i32)
+    (select (return (i32.const 5)) (local.get 0) (local.get 1))
+  )
+  (func (export "as-select-second") (param i32 i32) (result i32)
+    (select (local.get 0) (return (i32.const 6)) (local.get 1))
+  )
+  (func (export "as-select-cond") (result i32)
+    (select (i32.const 0) (i32.const 1) (return (i32.const 7)))
+  )
+
+  (func $f (param i32 i32 i32) (result i32) (i32.const -1))
+  (func (export "as-call-first") (result i32)
+    (call $f (return (i32.const 12)) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-call-mid") (result i32)
+    (call $f (i32.const 1) (return (i32.const 13)) (i32.const 3))
+  )
+  (func (export "as-call-last") (result i32)
+    (call $f (i32.const 1) (i32.const 2) (return (i32.const 14)))
+  )
+
+  (type $sig (func (param i32 i32 i32) (result i32)))
+  (table funcref (elem $f))
+  (func (export "as-call_indirect-func") (result i32)
+    (call_indirect (type $sig)
+      (return (i32.const 20)) (i32.const 1) (i32.const 2) (i32.const 3)
+    )
+  )
+  (func (export "as-call_indirect-first") (result i32)
+    (call_indirect (type $sig)
+      (i32.const 0) (return (i32.const 21)) (i32.const 2) (i32.const 3)
+    )
+  )
+  (func (export "as-call_indirect-mid") (result i32)
+    (call_indirect (type $sig)
+      (i32.const 0) (i32.const 1) (return (i32.const 22)) (i32.const 3)
+    )
+  )
+  (func (export "as-call_indirect-last") (result i32)
+    (call_indirect (type $sig)
+      (i32.const 0) (i32.const 1) (i32.const 2) (return (i32.const 23))
+    )
+  )
+
+  (func (export "as-local.set-value") (result i32) (local f32)
+    (local.set 0 (return (i32.const 17))) (i32.const -1)
+  )
+  (func (export "as-local.tee-value") (result i32) (local i32)
+    (local.tee 0 (return (i32.const 1)))
+  )
+  (global $a (mut i32) (i32.const 0))
+  (func (export "as-global.set-value") (result i32)
+    (global.set $a (return (i32.const 1)))
+  )
+
+  (memory 1)
+  (func (export "as-load-address") (result f32)
+    (f32.load (return (f32.const 1.7)))
+  )
+  (func (export "as-loadN-address") (result i64)
+    (i64.load8_s (return (i64.const 30)))
+  )
+
+  (func (export "as-store-address") (result i32)
+    (f64.store (return (i32.const 30)) (f64.const 7)) (i32.const -1)
+  )
+  (func (export "as-store-value") (result i32)
+    (i64.store (i32.const 2) (return (i32.const 31))) (i32.const -1)
+  )
+
+  (func (export "as-storeN-address") (result i32)
+    (i32.store8 (return (i32.const 32)) (i32.const 7)) (i32.const -1)
+  )
+  (func (export "as-storeN-value") (result i32)
+    (i64.store16 (i32.const 2) (return (i32.const 33))) (i32.const -1)
+  )
+
+  (func (export "as-unary-operand") (result f32)
+    (f32.neg (return (f32.const 3.4)))
+  )
+
+  (func (export "as-binary-left") (result i32)
+    (i32.add (return (i32.const 3)) (i32.const 10))
+  )
+  (func (export "as-binary-right") (result i64)
+    (i64.sub (i64.const 10) (return (i64.const 45)))
+  )
+
+  (func (export "as-test-operand") (result i32)
+    (i32.eqz (return (i32.const 44)))
+  )
+
+  (func (export "as-compare-left") (result i32)
+    (f64.le (return (i32.const 43)) (f64.const 10))
+  )
+  (func (export "as-compare-right") (result i32)
+    (f32.ne (f32.const 10) (return (i32.const 42)))
+  )
+
+  (func (export "as-convert-operand") (result i32)
+    (i32.wrap_i64 (return (i32.const 41)))
+  )
+
+  (func (export "as-memory.grow-size") (result i32)
+    (memory.grow (return (i32.const 40)))
+  )
+)
+
+(assert_return (invoke "type-i32"))
+(assert_return (invoke "type-i64"))
+(assert_return (invoke "type-f32"))
+(assert_return (invoke "type-f64"))
+
+(assert_return (invoke "type-i32-value") (i32.const 1))
+(assert_return (invoke "type-i64-value") (i64.const 2))
+(assert_return (invoke "type-f32-value") (f32.const 3))
+(assert_return (invoke "type-f64-value") (f64.const 4))
+
+(assert_return (invoke "nullary"))
+(assert_return (invoke "unary") (f64.const 3))
+
+(assert_return (invoke "as-func-first") (i32.const 1))
+(assert_return (invoke "as-func-mid") (i32.const 2))
+(assert_return (invoke "as-func-last"))
+(assert_return (invoke "as-func-value") (i32.const 3))
+
+(assert_return (invoke "as-block-first"))
+(assert_return (invoke "as-block-mid"))
+(assert_return (invoke "as-block-last"))
+(assert_return (invoke "as-block-value") (i32.const 2))
+
+(assert_return (invoke "as-loop-first") (i32.const 3))
+(assert_return (invoke "as-loop-mid") (i32.const 4))
+(assert_return (invoke "as-loop-last") (i32.const 5))
+
+(assert_return (invoke "as-br-value") (i32.const 9))
+
+(assert_return (invoke "as-br_if-cond"))
+(assert_return (invoke "as-br_if-value") (i32.const 8))
+(assert_return (invoke "as-br_if-value-cond") (i32.const 9))
+
+(assert_return (invoke "as-br_table-index") (i64.const 9))
+(assert_return (invoke "as-br_table-value") (i32.const 10))
+(assert_return (invoke "as-br_table-value-index") (i32.const 11))
+
+(assert_return (invoke "as-return-value") (i64.const 7))
+
+(assert_return (invoke "as-if-cond") (i32.const 2))
+(assert_return (invoke "as-if-then" (i32.const 1) (i32.const 6)) (i32.const 3))
+(assert_return (invoke "as-if-then" (i32.const 0) (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-if-else" (i32.const 0) (i32.const 6)) (i32.const 4))
+(assert_return (invoke "as-if-else" (i32.const 1) (i32.const 6)) (i32.const 6))
+
+(assert_return (invoke "as-select-first" (i32.const 0) (i32.const 6)) (i32.const 5))
+(assert_return (invoke "as-select-first" (i32.const 1) (i32.const 6)) (i32.const 5))
+(assert_return (invoke "as-select-second" (i32.const 0) (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-select-second" (i32.const 1) (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-select-cond") (i32.const 7))
+
+(assert_return (invoke "as-call-first") (i32.const 12))
+(assert_return (invoke "as-call-mid") (i32.const 13))
+(assert_return (invoke "as-call-last") (i32.const 14))
+
+(assert_return (invoke "as-call_indirect-func") (i32.const 20))
+(assert_return (invoke "as-call_indirect-first") (i32.const 21))
+(assert_return (invoke "as-call_indirect-mid") (i32.const 22))
+(assert_return (invoke "as-call_indirect-last") (i32.const 23))
+
+(assert_return (invoke "as-local.set-value") (i32.const 17))
+(assert_return (invoke "as-local.tee-value") (i32.const 1))
+(assert_return (invoke "as-global.set-value") (i32.const 1))
+
+(assert_return (invoke "as-load-address") (f32.const 1.7))
+(assert_return (invoke "as-loadN-address") (i64.const 30))
+
+(assert_return (invoke "as-store-address") (i32.const 30))
+(assert_return (invoke "as-store-value") (i32.const 31))
+(assert_return (invoke "as-storeN-address") (i32.const 32))
+(assert_return (invoke "as-storeN-value") (i32.const 33))
+
+(assert_return (invoke "as-unary-operand") (f32.const 3.4))
+
+(assert_return (invoke "as-binary-left") (i32.const 3))
+(assert_return (invoke "as-binary-right") (i64.const 45))
+
+(assert_return (invoke "as-test-operand") (i32.const 44))
+
+(assert_return (invoke "as-compare-left") (i32.const 43))
+(assert_return (invoke "as-compare-right") (i32.const 42))
+
+(assert_return (invoke "as-convert-operand") (i32.const 41))
+
+(assert_return (invoke "as-memory.grow-size") (i32.const 40))
+
+(assert_invalid
+  (module (func $type-value-empty-vs-num (result i32) (return)))
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-vs-num-in-block (result i32)
+      (i32.const 0)
+      (block (return))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-vs-num-in-loop (result i32)
+      (i32.const 0)
+      (loop (return))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-vs-num-in-then (result i32)
+      (i32.const 0) (i32.const 0)
+      (if (then (return)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-vs-num-in-else (result i32)
+      (i32.const 0) (i32.const 0)
+      (if (result i32) (then (i32.const 0)) (else (return))) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-vs-num-in-br (result i32)
+      (i32.const 0)
+      (block (br 0 (return)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-vs-num-in-br_if (result i32)
+      (i32.const 0)
+      (block (br_if 0 (return) (i32.const 1)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-vs-num-in-br_table (result i32)
+      (i32.const 0)
+      (block (br_table 0 (return)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-vs-num-in-return (result i32)
+      (return (return))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-vs-num-in-select (result i32)
+      (select (return) (i32.const 1) (i32.const 2))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-vs-num-in-call (result i32)
+      (call 1 (return))
+    )
+    (func (param i32) (result i32) (local.get 0))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $f (param i32) (result i32) (local.get 0))
+    (type $sig (func (param i32) (result i32)))
+    (table funcref (elem $f))
+    (func $type-value-empty-vs-num-in-call_indirect (result i32)
+      (block (result i32)
+        (call_indirect (type $sig)
+          (return) (i32.const 0)
+        )
+      )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-vs-num-in-local.set (result i32)
+      (local i32)
+      (local.set 0 (return)) (local.get 0)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-value-empty-vs-num-in-local.tee (result i32)
+      (local i32)
+      (local.tee 0 (return))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (global $x (mut i32) (i32.const 0))
+    (func $type-value-empty-vs-num-in-global.set (result i32)
+      (global.set $x (return)) (global.get $x)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-value-empty-vs-num-in-memory.grow (result i32)
+      (memory.grow (return))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 0)
+    (func $type-value-empty-vs-num-in-load (result i32)
+      (i32.load (return))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-value-empty-vs-num-in-store (result i32)
+      (i32.store (return) (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-void-vs-num (result f64) (return (nop))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-value-num-vs-num (result f64) (return (i64.const 1))))
+  "type mismatch"
+)
+
diff --git a/binaryen/test/spec/run.py b/binaryen/test/spec/run.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/run.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python3
+
+from __future__ import print_function
+import argparse
+import os
+import os.path
+import unittest
+import subprocess
+import glob
+import sys
+
+
+ownDir = os.path.dirname(os.path.abspath(sys.argv[0]))
+inputDir = ownDir
+outputDir = os.path.join(inputDir, "_output")
+
+parser = argparse.ArgumentParser()
+parser.add_argument("--wasm", metavar="<wasm-command>", default=os.path.join(os.getcwd(), "wasm"))
+parser.add_argument("--js", metavar="<js-command>")
+parser.add_argument("--out", metavar="<out-dir>", default=outputDir)
+parser.add_argument("file", nargs='*')
+arguments = parser.parse_args()
+sys.argv = sys.argv[:1]
+
+wasmCommand = arguments.wasm
+jsCommand = arguments.js
+outputDir = arguments.out
+inputFiles = arguments.file if arguments.file else glob.glob(os.path.join(inputDir, "*.wast"))
+
+if not os.path.exists(wasmCommand):
+  sys.stderr.write("""\
+Error: The executable '%s' does not exist.
+Provide the correct path with the '--wasm' flag.
+
+""" % (wasmCommand))
+  parser.print_help()
+  sys.exit(1)
+
+
+class RunTests(unittest.TestCase):
+  def _runCommand(self, command, logPath, expectedExitCode = 0):
+    with open(logPath, 'w+') as out:
+      exitCode = subprocess.call(command, shell=True, stdout=out, stderr=subprocess.STDOUT)
+      self.assertEqual(expectedExitCode, exitCode, "failed with exit code %i (expected %i) for %s" % (exitCode, expectedExitCode, command))
+
+  def _auxFile(self, path):
+    if os.path.exists(path):
+      os.remove(path)
+    return path
+
+  def _compareFile(self, expectFile, actualFile):
+    if os.path.exists(expectFile):
+      with open(expectFile) as expect:
+        with open(actualFile) as actual:
+          expectText = expect.read()
+          actualText = actual.read()
+          self.assertEqual(expectText, actualText)
+
+  def _runTestFile(self, inputPath):
+    dir, inputFile = os.path.split(inputPath)
+    outputPath = os.path.join(outputDir, inputFile)
+
+    # Run original file
+    expectedExitCode = 1 if ".fail." in inputFile else 0
+    logPath = self._auxFile(outputPath + ".log")
+    self._runCommand(('%s "%s"') % (wasmCommand, inputPath), logPath, expectedExitCode)
+
+    if expectedExitCode != 0:
+      return
+
+    # Convert to binary and run again
+    wasmPath = self._auxFile(outputPath + ".bin.wast")
+    logPath = self._auxFile(wasmPath + ".log")
+    self._runCommand(('%s -d "%s" -o "%s"') % (wasmCommand, inputPath, wasmPath), logPath)
+    self._runCommand(('%s "%s"') % (wasmCommand, wasmPath), logPath)
+
+    # Convert back to text and run again
+    wastPath = self._auxFile(wasmPath + ".wast")
+    logPath = self._auxFile(wastPath + ".log")
+    self._runCommand(('%s -d "%s" -o "%s"') % (wasmCommand, wasmPath, wastPath), logPath)
+    self._runCommand(('%s "%s"') % (wasmCommand, wastPath), logPath)
+
+    # Convert back to binary once more and compare
+    wasm2Path = self._auxFile(wastPath + ".bin.wast")
+    logPath = self._auxFile(wasm2Path + ".log")
+    self._runCommand(('%s -d "%s" -o "%s"') % (wasmCommand, wastPath, wasm2Path), logPath)
+    self._compareFile(wasmPath, wasm2Path)
+
+    # Convert back to text once more and compare
+    wast2Path = self._auxFile(wasm2Path + ".wast")
+    logPath = self._auxFile(wast2Path + ".log")
+    self._runCommand(('%s -d "%s" -o "%s"') % (wasmCommand, wasm2Path, wast2Path), logPath)
+    self._compareFile(wastPath, wast2Path)
+
+    # Convert to JavaScript
+    jsPath = self._auxFile(outputPath.replace(".wast", ".js"))
+    logPath = self._auxFile(jsPath + ".log")
+    self._runCommand(('%s -d "%s" -o "%s"') % (wasmCommand, inputPath, jsPath), logPath)
+    if jsCommand != None:
+      self._runCommand(('%s "%s"') % (jsCommand, jsPath), logPath)
+
+
+if __name__ == "__main__":
+  if not os.path.exists(outputDir):
+    os.makedirs(outputDir)
+  for fileName in inputFiles:
+    testName = 'test ' + os.path.basename(fileName)
+    setattr(RunTests, testName, lambda self, file=fileName: self._runTestFile(file))
+  unittest.main()
diff --git a/binaryen/test/spec/select.wast b/binaryen/test/spec/select.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/select.wast
@@ -0,0 +1,414 @@
+(module
+
+  (memory 1)
+
+  (func $dummy)
+
+  (func (export "select_i32") (param $lhs i32) (param $rhs i32) (param $cond i32) (result i32)
+   (select (local.get $lhs) (local.get $rhs) (local.get $cond)))
+
+  (func (export "select_i64") (param $lhs i64) (param $rhs i64) (param $cond i32) (result i64)
+   (select (local.get $lhs) (local.get $rhs) (local.get $cond)))
+
+  (func (export "select_f32") (param $lhs f32) (param $rhs f32) (param $cond i32) (result f32)
+   (select (local.get $lhs) (local.get $rhs) (local.get $cond)))
+
+  (func (export "select_f64") (param $lhs f64) (param $rhs f64) (param $cond i32) (result f64)
+   (select (local.get $lhs) (local.get $rhs) (local.get $cond)))
+
+  ;; Check that both sides of the select are evaluated
+  (func (export "select_trap_l") (param $cond i32) (result i32)
+    (select (unreachable) (i32.const 0) (local.get $cond))
+  )
+  (func (export "select_trap_r") (param $cond i32) (result i32)
+    (select (i32.const 0) (unreachable) (local.get $cond))
+  )
+
+  (func (export "select_unreached")
+    (unreachable) (select)
+    (unreachable) (i32.const 0) (select)
+    (unreachable) (i32.const 0) (i32.const 0) (select)
+    (unreachable) (f32.const 0) (i32.const 0) (select)
+    (unreachable)
+  )
+
+  ;; As the argument of control constructs and instructions
+
+  (func (export "as-select-first") (param i32) (result i32)
+    (select (select (i32.const 0) (i32.const 1) (local.get 0)) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-select-mid") (param i32) (result i32)
+    (select (i32.const 2) (select (i32.const 0) (i32.const 1) (local.get 0)) (i32.const 3))
+  )
+  (func (export "as-select-last") (param i32) (result i32)
+    (select (i32.const 2) (i32.const 3) (select (i32.const 0) (i32.const 1) (local.get 0)))
+  )
+
+  (func (export "as-loop-first") (param i32) (result i32)
+    (loop (result i32) (select (i32.const 2) (i32.const 3) (local.get 0)) (call $dummy) (call $dummy))
+  )
+  (func (export "as-loop-mid") (param i32) (result i32)
+    (loop (result i32) (call $dummy) (select (i32.const 2) (i32.const 3) (local.get 0)) (call $dummy))
+  )
+  (func (export "as-loop-last") (param i32) (result i32)
+    (loop (result i32) (call $dummy) (call $dummy) (select (i32.const 2) (i32.const 3) (local.get 0)))
+  )
+
+  (func (export "as-if-condition") (param i32)
+    (select (i32.const 2) (i32.const 3) (local.get 0)) (if (then (call $dummy)))
+  )
+  (func (export "as-if-then") (param i32) (result i32)
+    (if (result i32) (i32.const 1) (then (select (i32.const 2) (i32.const 3) (local.get 0))) (else (i32.const 4)))
+  )
+  (func (export "as-if-else") (param i32) (result i32)
+    (if (result i32) (i32.const 0) (then (i32.const 2)) (else (select (i32.const 2) (i32.const 3) (local.get 0))))
+  )
+
+  (func (export "as-br_if-first") (param i32) (result i32)
+    (block (result i32) (br_if 0 (select (i32.const 2) (i32.const 3) (local.get 0)) (i32.const 4)))
+  )
+  (func (export "as-br_if-last") (param i32) (result i32)
+    (block (result i32) (br_if 0 (i32.const 2) (select (i32.const 2) (i32.const 3) (local.get 0))))
+  )
+
+  (func (export "as-br_table-first") (param i32) (result i32)
+    (block (result i32) (select (i32.const 2) (i32.const 3) (local.get 0)) (i32.const 2) (br_table 0 0))
+  )
+  (func (export "as-br_table-last") (param i32) (result i32)
+    (block (result i32) (i32.const 2) (select (i32.const 2) (i32.const 3) (local.get 0)) (br_table 0 0))
+  )
+
+  (func $func (param i32 i32) (result i32) (local.get 0))
+  (type $check (func (param i32 i32) (result i32)))
+  (table funcref (elem $func))
+  (func (export "as-call_indirect-first") (param i32) (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (select (i32.const 2) (i32.const 3) (local.get 0)) (i32.const 1) (i32.const 0)
+      )
+    )
+  )
+  (func (export "as-call_indirect-mid") (param i32) (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (i32.const 1) (select (i32.const 2) (i32.const 3) (local.get 0)) (i32.const 0)
+      )
+    )
+  )
+  (func (export "as-call_indirect-last") (param i32) (result i32)
+    (block (result i32)
+      (call_indirect (type $check)
+        (i32.const 1) (i32.const 4) (select (i32.const 2) (i32.const 3) (local.get 0))
+      )
+    )
+  )
+
+  (func (export "as-store-first") (param i32)
+    (select (i32.const 0) (i32.const 4) (local.get 0)) (i32.const 1) (i32.store)
+  )
+  (func (export "as-store-last") (param i32)
+    (i32.const 8) (select (i32.const 1) (i32.const 2) (local.get 0)) (i32.store)
+  )
+
+  (func (export "as-memory.grow-value") (param i32) (result i32)
+    (memory.grow (select (i32.const 1) (i32.const 2) (local.get 0)))
+  )
+
+  (func $f (param i32) (result i32) (local.get 0))
+
+  (func (export "as-call-value") (param i32) (result i32)
+    (call $f (select (i32.const 1) (i32.const 2) (local.get 0)))
+  )
+  (func (export "as-return-value") (param i32) (result i32)
+    (select (i32.const 1) (i32.const 2) (local.get 0)) (return)
+  )
+  (func (export "as-drop-operand") (param i32)
+    (drop (select (i32.const 1) (i32.const 2) (local.get 0)))
+  )
+  (func (export "as-br-value") (param i32) (result i32)
+    (block (result i32) (br 0 (select (i32.const 1) (i32.const 2) (local.get 0))))
+  )
+  (func (export "as-local.set-value") (param i32) (result i32)
+    (local i32) (local.set 0 (select (i32.const 1) (i32.const 2) (local.get 0))) (local.get 0)
+  )
+  (func (export "as-local.tee-value") (param i32) (result i32)
+    (local.tee 0 (select (i32.const 1) (i32.const 2) (local.get 0)))
+  )
+  (global $a (mut i32) (i32.const 10))
+  (func (export "as-global.set-value") (param i32) (result i32)
+    (global.set $a (select (i32.const 1) (i32.const 2) (local.get 0)))
+    (global.get $a)
+  )
+  (func (export "as-load-operand") (param i32) (result i32)
+    (i32.load (select (i32.const 0) (i32.const 4) (local.get 0)))
+  )
+
+  (func (export "as-unary-operand") (param i32) (result i32)
+    (i32.eqz (select (i32.const 0) (i32.const 1) (local.get 0)))
+  )
+  (func (export "as-binary-operand") (param i32) (result i32)
+    (i32.mul
+      (select (i32.const 1) (i32.const 2) (local.get 0))
+      (select (i32.const 1) (i32.const 2) (local.get 0))
+    )
+  )
+  (func (export "as-test-operand") (param i32) (result i32)
+    (block (result i32)
+      (i32.eqz (select (i32.const 0) (i32.const 1) (local.get 0)))
+    )
+  )
+
+  (func (export "as-compare-left") (param i32) (result i32)
+    (block (result i32)
+      (i32.le_s (select (i32.const 1) (i32.const 2) (local.get 0)) (i32.const 1))
+    )
+  )
+  (func (export "as-compare-right") (param i32) (result i32)
+    (block (result i32)
+      (i32.ne (i32.const 1) (select (i32.const 0) (i32.const 1) (local.get 0)))
+    )
+  )
+
+  (func (export "as-convert-operand") (param i32) (result i32)
+    (block (result i32)
+      (i32.wrap_i64 (select (i64.const 1) (i64.const 0) (local.get 0)))
+    )
+  )
+
+)
+
+(assert_return (invoke "select_i32" (i32.const 1) (i32.const 2) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "select_i64" (i64.const 2) (i64.const 1) (i32.const 1)) (i64.const 2))
+(assert_return (invoke "select_f32" (f32.const 1) (f32.const 2) (i32.const 1)) (f32.const 1))
+(assert_return (invoke "select_f64" (f64.const 1) (f64.const 2) (i32.const 1)) (f64.const 1))
+
+(assert_return (invoke "select_i32" (i32.const 1) (i32.const 2) (i32.const 0)) (i32.const 2))
+(assert_return (invoke "select_i32" (i32.const 2) (i32.const 1) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "select_i64" (i64.const 2) (i64.const 1) (i32.const -1)) (i64.const 2))
+(assert_return (invoke "select_i64" (i64.const 2) (i64.const 1) (i32.const 0xf0f0f0f0)) (i64.const 2))
+
+(assert_return (invoke "select_f32" (f32.const nan) (f32.const 1) (i32.const 1)) (f32.const nan))
+(assert_return (invoke "select_f32" (f32.const nan:0x20304) (f32.const 1) (i32.const 1)) (f32.const nan:0x20304))
+(assert_return (invoke "select_f32" (f32.const nan) (f32.const 1) (i32.const 0)) (f32.const 1))
+(assert_return (invoke "select_f32" (f32.const nan:0x20304) (f32.const 1) (i32.const 0)) (f32.const 1))
+(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan) (i32.const 1)) (f32.const 2))
+(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan:0x20304) (i32.const 1)) (f32.const 2))
+(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan) (i32.const 0)) (f32.const nan))
+(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan:0x20304) (i32.const 0)) (f32.const nan:0x20304))
+
+(assert_return (invoke "select_f64" (f64.const nan) (f64.const 1) (i32.const 1)) (f64.const nan))
+(assert_return (invoke "select_f64" (f64.const nan:0x20304) (f64.const 1) (i32.const 1)) (f64.const nan:0x20304))
+(assert_return (invoke "select_f64" (f64.const nan) (f64.const 1) (i32.const 0)) (f64.const 1))
+(assert_return (invoke "select_f64" (f64.const nan:0x20304) (f64.const 1) (i32.const 0)) (f64.const 1))
+(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan) (i32.const 1)) (f64.const 2))
+(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan:0x20304) (i32.const 1)) (f64.const 2))
+(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan) (i32.const 0)) (f64.const nan))
+(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan:0x20304) (i32.const 0)) (f64.const nan:0x20304))
+
+(assert_trap (invoke "select_trap_l" (i32.const 1)) "unreachable")
+(assert_trap (invoke "select_trap_l" (i32.const 0)) "unreachable")
+(assert_trap (invoke "select_trap_r" (i32.const 1)) "unreachable")
+(assert_trap (invoke "select_trap_r" (i32.const 0)) "unreachable")
+
+(assert_return (invoke "as-select-first" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-select-first" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "as-select-mid" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-select-mid" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "as-select-last" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-select-last" (i32.const 1)) (i32.const 3))
+
+(assert_return (invoke "as-loop-first" (i32.const 0)) (i32.const 3))
+(assert_return (invoke "as-loop-first" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "as-loop-mid" (i32.const 0)) (i32.const 3))
+(assert_return (invoke "as-loop-mid" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "as-loop-last" (i32.const 0)) (i32.const 3))
+(assert_return (invoke "as-loop-last" (i32.const 1)) (i32.const 2))
+
+(assert_return (invoke "as-if-condition" (i32.const 0)))
+(assert_return (invoke "as-if-condition" (i32.const 1)))
+(assert_return (invoke "as-if-then" (i32.const 0)) (i32.const 3))
+(assert_return (invoke "as-if-then" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "as-if-else" (i32.const 0)) (i32.const 3))
+(assert_return (invoke "as-if-else" (i32.const 1)) (i32.const 2))
+
+(assert_return (invoke "as-br_if-first" (i32.const 0)) (i32.const 3))
+(assert_return (invoke "as-br_if-first" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "as-br_if-last" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-br_if-last" (i32.const 1)) (i32.const 2))
+
+(assert_return (invoke "as-br_table-first" (i32.const 0)) (i32.const 3))
+(assert_return (invoke "as-br_table-first" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "as-br_table-last" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-br_table-last" (i32.const 1)) (i32.const 2))
+
+(assert_return (invoke "as-call_indirect-first" (i32.const 0)) (i32.const 3))
+(assert_return (invoke "as-call_indirect-first" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "as-call_indirect-mid" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-call_indirect-mid" (i32.const 1)) (i32.const 1))
+(assert_trap (invoke "as-call_indirect-last" (i32.const 0)) "undefined element")
+(assert_trap (invoke "as-call_indirect-last" (i32.const 1)) "undefined element")
+
+(assert_return (invoke "as-store-first" (i32.const 0)))
+(assert_return (invoke "as-store-first" (i32.const 1)))
+(assert_return (invoke "as-store-last" (i32.const 0)))
+(assert_return (invoke "as-store-last" (i32.const 1)))
+
+(assert_return (invoke "as-memory.grow-value" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-memory.grow-value" (i32.const 1)) (i32.const 3))
+
+(assert_return (invoke "as-call-value" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-call-value" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-return-value" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-return-value" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-drop-operand" (i32.const 0)))
+(assert_return (invoke "as-drop-operand" (i32.const 1)))
+(assert_return (invoke "as-br-value" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-br-value" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-local.set-value" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-local.set-value" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-local.tee-value" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-local.tee-value" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-global.set-value" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "as-global.set-value" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-load-operand" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-load-operand" (i32.const 1)) (i32.const 1))
+
+(assert_return (invoke "as-unary-operand" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-unary-operand" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-binary-operand" (i32.const 0)) (i32.const 4))
+(assert_return (invoke "as-binary-operand" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-test-operand" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-test-operand" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-compare-left" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-compare-left" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-compare-right" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-compare-right" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-convert-operand" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "as-convert-operand" (i32.const 1)) (i32.const 1))
+
+(assert_invalid
+  (module (func $arity-0 (select (nop) (nop) (i32.const 1))))
+  "type mismatch"
+)
+
+;; The first two operands should have the same type as each other
+
+(assert_invalid
+  (module (func $type-num-vs-num (select (i32.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-num-vs-num (select (i32.const 1) (f32.const 1.0) (i32.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-num-vs-num (select (i32.const 1) (f64.const 1.0) (i32.const 1))))
+  "type mismatch"
+)
+
+
+(assert_invalid
+  (module
+    (func $type-1st-operand-empty
+      (select) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-2nd-operand-empty
+      (i32.const 0) (select) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-3rd-operand-empty
+      (i32.const 0) (i32.const 0) (select) (drop)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-1st-operand-empty-in-block
+      (i32.const 0) (i32.const 0) (i32.const 0)
+      (block (select) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-2nd-operand-empty-in-block
+      (i32.const 0) (i32.const 0)
+      (block (i32.const 0) (select) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-3rd-operand-empty-in-block
+      (i32.const 0)
+      (block (i32.const 0) (i32.const 0) (select) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-1st-operand-empty-in-loop
+      (i32.const 0) (i32.const 0) (i32.const 0)
+      (loop (select) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-2nd-operand-empty-in-loop
+      (i32.const 0) (i32.const 0)
+      (loop (i32.const 0) (select) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-3rd-operand-empty-in-loop
+      (i32.const 0)
+      (loop (i32.const 0) (i32.const 0) (select) (drop))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-1st-operand-empty-in-then
+      (i32.const 0) (i32.const 0) (i32.const 0)
+      (if (then (select) (drop)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-2nd-operand-empty-in-then
+      (i32.const 0) (i32.const 0)
+      (if (then (i32.const 0) (select) (drop)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (func $type-3rd-operand-empty-in-then
+      (i32.const 0)
+      (if (then (i32.const 0) (i32.const 0) (select) (drop)))
+    )
+  )
+  "type mismatch"
+)
diff --git a/binaryen/test/spec/set_local.wast b/binaryen/test/spec/set_local.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/set_local.wast
@@ -0,0 +1,205 @@
+;; Test `local.set` operator
+
+(module
+  ;; Typing
+
+  (func (export "type-local-i32") (local i32) (local.set 0 (i32.const 0)))
+  (func (export "type-local-i64") (local i64) (local.set 0 (i64.const 0)))
+  (func (export "type-local-f32") (local f32) (local.set 0 (f32.const 0)))
+  (func (export "type-local-f64") (local f64) (local.set 0 (f64.const 0)))
+
+  (func (export "type-param-i32") (param i32) (local.set 0 (i32.const 10)))
+  (func (export "type-param-i64") (param i64) (local.set 0 (i64.const 11)))
+  (func (export "type-param-f32") (param f32) (local.set 0 (f32.const 11.1)))
+  (func (export "type-param-f64") (param f64) (local.set 0 (f64.const 12.2)))
+
+  (func (export "type-mixed") (param i64 f32 f64 i32 i32) (local f32 i64 i64 f64)
+    (local.set 0 (i64.const 0))
+    (local.set 1 (f32.const 0))
+    (local.set 2 (f64.const 0))
+    (local.set 3 (i32.const 0))
+    (local.set 4 (i32.const 0))
+    (local.set 5 (f32.const 0))
+    (local.set 6 (i64.const 0))
+    (local.set 7 (i64.const 0))
+    (local.set 8 (f64.const 0))
+  )
+
+  ;; Writing
+
+  (func (export "write") (param i64 f32 f64 i32 i32) (result i64)
+    (local f32 i64 i64 f64)
+    (local.set 1 (f32.const -0.3))
+    (local.set 3 (i32.const 40))
+    (local.set 4 (i32.const -7))
+    (local.set 5 (f32.const 5.5))
+    (local.set 6 (i64.const 6))
+    (local.set 8 (f64.const 8))
+    (i64.trunc_f64_s
+      (f64.add
+        (f64.convert_i64_u (local.get 0))
+        (f64.add
+          (f64.promote_f32 (local.get 1))
+          (f64.add
+            (local.get 2)
+            (f64.add
+              (f64.convert_i32_u (local.get 3))
+              (f64.add
+                (f64.convert_i32_s (local.get 4))
+                (f64.add
+                  (f64.promote_f32 (local.get 5))
+                  (f64.add
+                    (f64.convert_i64_u (local.get 6))
+                    (f64.add
+                      (f64.convert_i64_u (local.get 7))
+                      (local.get 8)
+                    )
+                  )
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+)
+
+(assert_return (invoke "type-local-i32"))
+(assert_return (invoke "type-local-i64"))
+(assert_return (invoke "type-local-f32"))
+(assert_return (invoke "type-local-f64"))
+
+(assert_return (invoke "type-param-i32" (i32.const 2)))
+(assert_return (invoke "type-param-i64" (i64.const 3)))
+(assert_return (invoke "type-param-f32" (f32.const 4.4)))
+(assert_return (invoke "type-param-f64" (f64.const 5.5)))
+
+(assert_return
+  (invoke "type-mixed"
+    (i64.const 1) (f32.const 2.2) (f64.const 3.3) (i32.const 4) (i32.const 5)
+  )
+)
+
+(assert_return
+  (invoke "write"
+    (i64.const 1) (f32.const 2) (f64.const 3.3) (i32.const 4) (i32.const 5)
+  )
+  (i64.const 56)
+)
+
+
+;; Invalid typing of access to locals
+
+(assert_invalid
+  (module (func $type-local-num-vs-num (result i64) (local i32)
+    (local.set 0 (i32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-num-vs-num (local f32)
+    (i32.eqz (local.set 0 (f32.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-num-vs-num (local f64 i64)
+    (f64.neg (local.set 1 (i64.const 0)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-local-arg-void-vs-num (local i32) (local.set 0 (nop))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-arg-num-vs-num (local i32) (local.set 0 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-arg-num-vs-num (local f32) (local.set 0 (f64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-arg-num-vs-num (local f64 i64) (local.set 1 (f64.const 0))))
+  "type mismatch"
+)
+
+
+;; Invalid typing of access to parameters
+
+(assert_invalid
+  (module (func $type-param-num-vs-num (param i32) (result i64) (local.get 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-num-vs-num (param f32) (i32.eqz (local.get 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-num-vs-num (param f64 i64) (f64.neg (local.get 1))))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-param-arg-void-vs-num (param i32) (local.set 0 (nop))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-arg-num-vs-num (param i32) (local.set 0 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-arg-num-vs-num (param f32) (local.set 0 (f64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-arg-num-vs-num (param f64 i64) (local.set 1 (f64.const 0))))
+  "type mismatch"
+)
+
+
+;; Invalid local index
+
+(assert_invalid
+  (module (func $unbound-local (local i32 i64) (local.get 3)))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-local (local i32 i64) (local.get 14324343)))
+  "unknown local"
+)
+
+(assert_invalid
+  (module (func $unbound-param (param i32 i64) (local.get 2)))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-param (local i32 i64) (local.get 714324343)))
+  "unknown local"
+)
+
+(assert_invalid
+  (module (func $unbound-mixed (param i32) (local i32 i64) (local.get 3)))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-mixed (param i64) (local i32 i64) (local.get 214324343)))
+  "unknown local"
+)
+
+(assert_invalid
+  (module (func $type-mixed-arg-num-vs-num (param f32) (local i32) (local.set 1 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-mixed-arg-num-vs-num (param i64 i32) (local f32) (local.set 1 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-mixed-arg-num-vs-num (param i64) (local f64 i64) (local.set 1 (i64.const 0))))
+  "type mismatch"
+)
+
diff --git a/binaryen/test/spec/simd.wast b/binaryen/test/spec/simd.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/simd.wast
@@ -0,0 +1,957 @@
+(module
+ (memory 1)
+ (data (i32.const 128) "WASMSIMDGOESFAST")
+ (data (i32.const 256) "\80\90\a0\b0\c0\d0\e0\f0")
+ (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))
+   (v128.load (local.get $0))
+ )
+ (func (export "v128.const.i8x16") (result v128) (v128.const i8x16 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16))
+ (func (export "v128.const.i16x8") (result v128) (v128.const i16x8 1 2 3 4 5 6 7 8))
+ (func (export "v128.const.i32x4") (result v128) (v128.const i32x4 1 2 3 4))
+ (func (export "v128.const.i64x2") (result v128) (v128.const i64x2 1 2))
+ (func (export "v128.const.f32x4") (result v128) (v128.const f32x4 1.0 2 3 4))
+ (func (export "v128.const.f64x2") (result v128) (v128.const f64x2 1.0 2))
+ (func (export "v128.shuffle_interleave_bytes") (param $0 v128) (param $1 v128) (result v128)
+   (v8x16.shuffle 0 17 2 19 4 21 6 23 8 25 10 27 12 29 14 31 (local.get $0) (local.get $1))
+ )
+ (func (export "v128.shuffle_reverse_i32s") (param $0 v128) (result v128)
+   (v8x16.shuffle 12 13 14 15 8 9 10 11 4 5 6 7 0 1 2 3 (local.get $0) (local.get $0))
+ )
+ (func (export "i8x16.splat") (param $0 i32) (result v128) (i8x16.splat (local.get $0)))
+ (func (export "i8x16.extract_lane_s_first") (param $0 v128) (result i32) (i8x16.extract_lane_s 0 (local.get $0)))
+ (func (export "i8x16.extract_lane_s_last") (param $0 v128) (result i32) (i8x16.extract_lane_s 15 (local.get $0)))
+ (func (export "i8x16.extract_lane_u_first") (param $0 v128) (result i32) (i8x16.extract_lane_u 0 (local.get $0)))
+ (func (export "i8x16.extract_lane_u_last") (param $0 v128) (result i32) (i8x16.extract_lane_u 15 (local.get $0)))
+ (func (export "i8x16.replace_lane_first") (param $0 v128) (param $1 i32) (result v128) (i8x16.replace_lane 0 (local.get $0) (local.get $1)))
+ (func (export "i8x16.replace_lane_last") (param $0 v128) (param $1 i32) (result v128) (i8x16.replace_lane 15 (local.get $0) (local.get $1)))
+ (func (export "i16x8.splat") (param $0 i32) (result v128) (i16x8.splat (local.get $0)))
+ (func (export "i16x8.extract_lane_s_first") (param $0 v128) (result i32) (i16x8.extract_lane_s 0 (local.get $0)))
+ (func (export "i16x8.extract_lane_s_last") (param $0 v128) (result i32) (i16x8.extract_lane_s 7 (local.get $0)))
+ (func (export "i16x8.extract_lane_u_first") (param $0 v128) (result i32) (i16x8.extract_lane_u 0 (local.get $0)))
+ (func (export "i16x8.extract_lane_u_last") (param $0 v128) (result i32) (i16x8.extract_lane_u 7 (local.get $0)))
+ (func (export "i16x8.replace_lane_first") (param $0 v128) (param $1 i32) (result v128) (i16x8.replace_lane 0 (local.get $0) (local.get $1)))
+ (func (export "i16x8.replace_lane_last") (param $0 v128) (param $1 i32) (result v128) (i16x8.replace_lane 7 (local.get $0) (local.get $1)))
+ (func (export "i32x4.splat") (param $0 i32) (result v128) (i32x4.splat (local.get $0)))
+ (func (export "i32x4.extract_lane_first") (param $0 v128) (result i32) (i32x4.extract_lane 0 (local.get $0)))
+ (func (export "i32x4.extract_lane_last") (param $0 v128) (result i32) (i32x4.extract_lane 3 (local.get $0)))
+ (func (export "i32x4.replace_lane_first") (param $0 v128) (param $1 i32) (result v128) (i32x4.replace_lane 0 (local.get $0) (local.get $1)))
+ (func (export "i32x4.replace_lane_last") (param $0 v128) (param $1 i32) (result v128) (i32x4.replace_lane 3 (local.get $0) (local.get $1)))
+ (func (export "i64x2.splat") (param $0 i64) (result v128) (i64x2.splat (local.get $0)))
+ (func (export "i64x2.extract_lane_first") (param $0 v128) (result i64) (i64x2.extract_lane 0 (local.get $0)))
+ (func (export "i64x2.extract_lane_last") (param $0 v128) (result i64) (i64x2.extract_lane 1 (local.get $0)))
+ (func (export "i64x2.replace_lane_first") (param $0 v128) (param $1 i64) (result v128) (i64x2.replace_lane 0 (local.get $0) (local.get $1)))
+ (func (export "i64x2.replace_lane_last") (param $0 v128) (param $1 i64) (result v128) (i64x2.replace_lane 1 (local.get $0) (local.get $1)))
+ (func (export "f32x4.splat") (param $0 f32) (result v128) (f32x4.splat (local.get $0)))
+ (func (export "f32x4.extract_lane_first") (param $0 v128) (result f32) (f32x4.extract_lane 0 (local.get $0)))
+ (func (export "f32x4.extract_lane_last") (param $0 v128) (result f32) (f32x4.extract_lane 3 (local.get $0)))
+ (func (export "f32x4.replace_lane_first") (param $0 v128) (param $1 f32) (result v128) (f32x4.replace_lane 0 (local.get $0) (local.get $1)))
+ (func (export "f32x4.replace_lane_last") (param $0 v128) (param $1 f32) (result v128) (f32x4.replace_lane 3 (local.get $0) (local.get $1)))
+ (func (export "f64x2.splat") (param $0 f64) (result v128) (f64x2.splat (local.get $0)))
+ (func (export "f64x2.extract_lane_first") (param $0 v128) (result f64) (f64x2.extract_lane 0 (local.get $0)))
+ (func (export "f64x2.extract_lane_last") (param $0 v128) (result f64) (f64x2.extract_lane 1 (local.get $0)))
+ (func (export "f64x2.replace_lane_first") (param $0 v128) (param $1 f64) (result v128) (f64x2.replace_lane 0 (local.get $0) (local.get $1)))
+ (func (export "f64x2.replace_lane_last") (param $0 v128) (param $1 f64) (result v128) (f64x2.replace_lane 1 (local.get $0) (local.get $1)))
+ (func (export "i8x16.eq") (param $0 v128) (param $1 v128) (result v128) (i8x16.eq (local.get $0) (local.get $1)))
+ (func (export "i8x16.ne") (param $0 v128) (param $1 v128) (result v128) (i8x16.ne (local.get $0) (local.get $1)))
+ (func (export "i8x16.lt_s") (param $0 v128) (param $1 v128) (result v128) (i8x16.lt_s (local.get $0) (local.get $1)))
+ (func (export "i8x16.lt_u") (param $0 v128) (param $1 v128) (result v128) (i8x16.lt_u (local.get $0) (local.get $1)))
+ (func (export "i8x16.gt_s") (param $0 v128) (param $1 v128) (result v128) (i8x16.gt_s (local.get $0) (local.get $1)))
+ (func (export "i8x16.gt_u") (param $0 v128) (param $1 v128) (result v128) (i8x16.gt_u (local.get $0) (local.get $1)))
+ (func (export "i8x16.le_s") (param $0 v128) (param $1 v128) (result v128) (i8x16.le_s (local.get $0) (local.get $1)))
+ (func (export "i8x16.le_u") (param $0 v128) (param $1 v128) (result v128) (i8x16.le_u (local.get $0) (local.get $1)))
+ (func (export "i8x16.ge_s") (param $0 v128) (param $1 v128) (result v128) (i8x16.ge_s (local.get $0) (local.get $1)))
+ (func (export "i8x16.ge_u") (param $0 v128) (param $1 v128) (result v128) (i8x16.ge_u (local.get $0) (local.get $1)))
+ (func (export "i16x8.eq") (param $0 v128) (param $1 v128) (result v128) (i16x8.eq (local.get $0) (local.get $1)))
+ (func (export "i16x8.ne") (param $0 v128) (param $1 v128) (result v128) (i16x8.ne (local.get $0) (local.get $1)))
+ (func (export "i16x8.lt_s") (param $0 v128) (param $1 v128) (result v128) (i16x8.lt_s (local.get $0) (local.get $1)))
+ (func (export "i16x8.lt_u") (param $0 v128) (param $1 v128) (result v128) (i16x8.lt_u (local.get $0) (local.get $1)))
+ (func (export "i16x8.gt_s") (param $0 v128) (param $1 v128) (result v128) (i16x8.gt_s (local.get $0) (local.get $1)))
+ (func (export "i16x8.gt_u") (param $0 v128) (param $1 v128) (result v128) (i16x8.gt_u (local.get $0) (local.get $1)))
+ (func (export "i16x8.le_s") (param $0 v128) (param $1 v128) (result v128) (i16x8.le_s (local.get $0) (local.get $1)))
+ (func (export "i16x8.le_u") (param $0 v128) (param $1 v128) (result v128) (i16x8.le_u (local.get $0) (local.get $1)))
+ (func (export "i16x8.ge_s") (param $0 v128) (param $1 v128) (result v128) (i16x8.ge_s (local.get $0) (local.get $1)))
+ (func (export "i16x8.ge_u") (param $0 v128) (param $1 v128) (result v128) (i16x8.ge_u (local.get $0) (local.get $1)))
+ (func (export "i32x4.eq") (param $0 v128) (param $1 v128) (result v128) (i32x4.eq (local.get $0) (local.get $1)))
+ (func (export "i32x4.ne") (param $0 v128) (param $1 v128) (result v128) (i32x4.ne (local.get $0) (local.get $1)))
+ (func (export "i32x4.lt_s") (param $0 v128) (param $1 v128) (result v128) (i32x4.lt_s (local.get $0) (local.get $1)))
+ (func (export "i32x4.lt_u") (param $0 v128) (param $1 v128) (result v128) (i32x4.lt_u (local.get $0) (local.get $1)))
+ (func (export "i32x4.gt_s") (param $0 v128) (param $1 v128) (result v128) (i32x4.gt_s (local.get $0) (local.get $1)))
+ (func (export "i32x4.gt_u") (param $0 v128) (param $1 v128) (result v128) (i32x4.gt_u (local.get $0) (local.get $1)))
+ (func (export "i32x4.le_s") (param $0 v128) (param $1 v128) (result v128) (i32x4.le_s (local.get $0) (local.get $1)))
+ (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 "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)))
+ (func (export "f32x4.gt") (param $0 v128) (param $1 v128) (result v128) (f32x4.gt (local.get $0) (local.get $1)))
+ (func (export "f32x4.le") (param $0 v128) (param $1 v128) (result v128) (f32x4.le (local.get $0) (local.get $1)))
+ (func (export "f32x4.ge") (param $0 v128) (param $1 v128) (result v128) (f32x4.ge (local.get $0) (local.get $1)))
+ (func (export "f64x2.eq") (param $0 v128) (param $1 v128) (result v128) (f64x2.eq (local.get $0) (local.get $1)))
+ (func (export "f64x2.ne") (param $0 v128) (param $1 v128) (result v128) (f64x2.ne (local.get $0) (local.get $1)))
+ (func (export "f64x2.lt") (param $0 v128) (param $1 v128) (result v128) (f64x2.lt (local.get $0) (local.get $1)))
+ (func (export "f64x2.gt") (param $0 v128) (param $1 v128) (result v128) (f64x2.gt (local.get $0) (local.get $1)))
+ (func (export "f64x2.le") (param $0 v128) (param $1 v128) (result v128) (f64x2.le (local.get $0) (local.get $1)))
+ (func (export "f64x2.ge") (param $0 v128) (param $1 v128) (result v128) (f64x2.ge (local.get $0) (local.get $1)))
+ (func (export "v128.not") (param $0 v128) (result v128) (v128.not (local.get $0)))
+ (func (export "v128.and") (param $0 v128) (param $1 v128) (result v128) (v128.and (local.get $0) (local.get $1)))
+ (func (export "v128.or") (param $0 v128) (param $1 v128) (result v128) (v128.or (local.get $0) (local.get $1)))
+ (func (export "v128.xor") (param $0 v128) (param $1 v128) (result v128) (v128.xor (local.get $0) (local.get $1)))
+ (func (export "v128.andnot") (param $0 v128) (param $1 v128) (result v128) (v128.andnot (local.get $0) (local.get $1)))
+ (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 "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)))
+ (func (export "i8x16.all_true") (param $0 v128) (result i32) (i8x16.all_true (local.get $0)))
+ (func (export "i8x16.bitmask") (param $0 v128) (result i32) (i8x16.bitmask (local.get $0)))
+ (func (export "i8x16.shl") (param $0 v128) (param $1 i32) (result v128) (i8x16.shl (local.get $0) (local.get $1)))
+ (func (export "i8x16.shr_s") (param $0 v128) (param $1 i32) (result v128) (i8x16.shr_s (local.get $0) (local.get $1)))
+ (func (export "i8x16.shr_u") (param $0 v128) (param $1 i32) (result v128) (i8x16.shr_u (local.get $0) (local.get $1)))
+ (func (export "i8x16.add") (param $0 v128) (param $1 v128) (result v128) (i8x16.add (local.get $0) (local.get $1)))
+ (func (export "i8x16.add_saturate_s") (param $0 v128) (param $1 v128) (result v128) (i8x16.add_saturate_s (local.get $0) (local.get $1)))
+ (func (export "i8x16.add_saturate_u") (param $0 v128) (param $1 v128) (result v128) (i8x16.add_saturate_u (local.get $0) (local.get $1)))
+ (func (export "i8x16.sub") (param $0 v128) (param $1 v128) (result v128) (i8x16.sub (local.get $0) (local.get $1)))
+ (func (export "i8x16.sub_saturate_s") (param $0 v128) (param $1 v128) (result v128) (i8x16.sub_saturate_s (local.get $0) (local.get $1)))
+ (func (export "i8x16.sub_saturate_u") (param $0 v128) (param $1 v128) (result v128) (i8x16.sub_saturate_u (local.get $0) (local.get $1)))
+ (func (export "i8x16.mul") (param $0 v128) (param $1 v128) (result v128) (i8x16.mul (local.get $0) (local.get $1)))
+ (func (export "i8x16.min_s") (param $0 v128) (param $1 v128) (result v128) (i8x16.min_s (local.get $0) (local.get $1)))
+ (func (export "i8x16.min_u") (param $0 v128) (param $1 v128) (result v128) (i8x16.min_u (local.get $0) (local.get $1)))
+ (func (export "i8x16.max_s") (param $0 v128) (param $1 v128) (result v128) (i8x16.max_s (local.get $0) (local.get $1)))
+ (func (export "i8x16.max_u") (param $0 v128) (param $1 v128) (result v128) (i8x16.max_u (local.get $0) (local.get $1)))
+ (func (export "i8x16.avgr_u") (param $0 v128) (param $1 v128) (result v128) (i8x16.avgr_u (local.get $0) (local.get $1)))
+ (func (export "i16x8.abs") (param $0 v128) (result v128) (i16x8.abs (local.get $0)))
+ (func (export "i16x8.neg") (param $0 v128) (result v128) (i16x8.neg (local.get $0)))
+ (func (export "i16x8.any_true") (param $0 v128) (result i32) (i16x8.any_true (local.get $0)))
+ (func (export "i16x8.all_true") (param $0 v128) (result i32) (i16x8.all_true (local.get $0)))
+ (func (export "i16x8.bitmask") (param $0 v128) (result i32) (i16x8.bitmask (local.get $0)))
+ (func (export "i16x8.shl") (param $0 v128) (param $1 i32) (result v128) (i16x8.shl (local.get $0) (local.get $1)))
+ (func (export "i16x8.shr_s") (param $0 v128) (param $1 i32) (result v128) (i16x8.shr_s (local.get $0) (local.get $1)))
+ (func (export "i16x8.shr_u") (param $0 v128) (param $1 i32) (result v128) (i16x8.shr_u (local.get $0) (local.get $1)))
+ (func (export "i16x8.add") (param $0 v128) (param $1 v128) (result v128) (i16x8.add (local.get $0) (local.get $1)))
+ (func (export "i16x8.add_saturate_s") (param $0 v128) (param $1 v128) (result v128) (i16x8.add_saturate_s (local.get $0) (local.get $1)))
+ (func (export "i16x8.add_saturate_u") (param $0 v128) (param $1 v128) (result v128) (i16x8.add_saturate_u (local.get $0) (local.get $1)))
+ (func (export "i16x8.sub") (param $0 v128) (param $1 v128) (result v128) (i16x8.sub (local.get $0) (local.get $1)))
+ (func (export "i16x8.sub_saturate_s") (param $0 v128) (param $1 v128) (result v128) (i16x8.sub_saturate_s (local.get $0) (local.get $1)))
+ (func (export "i16x8.sub_saturate_u") (param $0 v128) (param $1 v128) (result v128) (i16x8.sub_saturate_u (local.get $0) (local.get $1)))
+ (func (export "i16x8.mul") (param $0 v128) (param $1 v128) (result v128) (i16x8.mul (local.get $0) (local.get $1)))
+ (func (export "i16x8.min_s") (param $0 v128) (param $1 v128) (result v128) (i16x8.min_s (local.get $0) (local.get $1)))
+ (func (export "i16x8.min_u") (param $0 v128) (param $1 v128) (result v128) (i16x8.min_u (local.get $0) (local.get $1)))
+ (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)))
+ (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)))
+ (func (export "i32x4.all_true") (param $0 v128) (result i32) (i32x4.all_true (local.get $0)))
+ (func (export "i32x4.bitmask") (param $0 v128) (result i32) (i32x4.bitmask (local.get $0)))
+ (func (export "i32x4.shl") (param $0 v128) (param $1 i32) (result v128) (i32x4.shl (local.get $0) (local.get $1)))
+ (func (export "i32x4.shr_s") (param $0 v128) (param $1 i32) (result v128) (i32x4.shr_s (local.get $0) (local.get $1)))
+ (func (export "i32x4.shr_u") (param $0 v128) (param $1 i32) (result v128) (i32x4.shr_u (local.get $0) (local.get $1)))
+ (func (export "i32x4.add") (param $0 v128) (param $1 v128) (result v128) (i32x4.add (local.get $0) (local.get $1)))
+ (func (export "i32x4.sub") (param $0 v128) (param $1 v128) (result v128) (i32x4.sub (local.get $0) (local.get $1)))
+ (func (export "i32x4.mul") (param $0 v128) (param $1 v128) (result v128) (i32x4.mul (local.get $0) (local.get $1)))
+ (func (export "i32x4.min_s") (param $0 v128) (param $1 v128) (result v128) (i32x4.min_s (local.get $0) (local.get $1)))
+ (func (export "i32x4.min_u") (param $0 v128) (param $1 v128) (result v128) (i32x4.min_u (local.get $0) (local.get $1)))
+ (func (export "i32x4.max_s") (param $0 v128) (param $1 v128) (result v128) (i32x4.max_s (local.get $0) (local.get $1)))
+ (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.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)))
+ (func (export "i64x2.add") (param $0 v128) (param $1 v128) (result v128) (i64x2.add (local.get $0) (local.get $1)))
+ (func (export "i64x2.sub") (param $0 v128) (param $1 v128) (result v128) (i64x2.sub (local.get $0) (local.get $1)))
+ (func (export "i64x2.mul") (param $0 v128) (param $1 v128) (result v128) (i64x2.mul (local.get $0) (local.get $1)))
+ (func (export "f32x4.abs") (param $0 v128) (result v128) (f32x4.abs (local.get $0)))
+ (func (export "f32x4.neg") (param $0 v128) (result v128) (f32x4.neg (local.get $0)))
+ (func (export "f32x4.sqrt") (param $0 v128) (result v128) (f32x4.sqrt (local.get $0)))
+ (func (export "f32x4.qfma") (param $0 v128) (param $1 v128) (param $2 v128) (result v128) (f32x4.qfma (local.get $0) (local.get $1) (local.get $2)))
+ (func (export "f32x4.qfms") (param $0 v128) (param $1 v128) (param $2 v128) (result v128) (f32x4.qfms (local.get $0) (local.get $1) (local.get $2)))
+ (func (export "f32x4.add") (param $0 v128) (param $1 v128) (result v128) (f32x4.add (local.get $0) (local.get $1)))
+ (func (export "f32x4.sub") (param $0 v128) (param $1 v128) (result v128) (f32x4.sub (local.get $0) (local.get $1)))
+ (func (export "f32x4.mul") (param $0 v128) (param $1 v128) (result v128) (f32x4.mul (local.get $0) (local.get $1)))
+ (func (export "f32x4.div") (param $0 v128) (param $1 v128) (result v128) (f32x4.div (local.get $0) (local.get $1)))
+ (func (export "f32x4.min") (param $0 v128) (param $1 v128) (result v128) (f32x4.min (local.get $0) (local.get $1)))
+ (func (export "f32x4.max") (param $0 v128) (param $1 v128) (result v128) (f32x4.max (local.get $0) (local.get $1)))
+ (func (export "f32x4.pmin") (param $0 v128) (param $1 v128) (result v128) (f32x4.pmin (local.get $0) (local.get $1)))
+ (func (export "f32x4.pmax") (param $0 v128) (param $1 v128) (result v128) (f32x4.pmax (local.get $0) (local.get $1)))
+ (func (export "f32x4.ceil") (param $0 v128) (result v128) (f32x4.ceil (local.get $0)))
+ (func (export "f32x4.floor") (param $0 v128) (result v128) (f32x4.floor (local.get $0)))
+ (func (export "f32x4.trunc") (param $0 v128) (result v128) (f32x4.trunc (local.get $0)))
+ (func (export "f32x4.nearest") (param $0 v128) (result v128) (f32x4.nearest (local.get $0)))
+ (func (export "f64x2.abs") (param $0 v128) (result v128) (f64x2.abs (local.get $0)))
+ (func (export "f64x2.neg") (param $0 v128) (result v128) (f64x2.neg (local.get $0)))
+ (func (export "f64x2.sqrt") (param $0 v128) (result v128) (f64x2.sqrt (local.get $0)))
+ (func (export "f64x2.qfma") (param $0 v128) (param $1 v128) (param $2 v128) (result v128) (f64x2.qfma (local.get $0) (local.get $1) (local.get $2)))
+ (func (export "f64x2.qfms") (param $0 v128) (param $1 v128) (param $2 v128) (result v128) (f64x2.qfms (local.get $0) (local.get $1) (local.get $2)))
+ (func (export "f64x2.add") (param $0 v128) (param $1 v128) (result v128) (f64x2.add (local.get $0) (local.get $1)))
+ (func (export "f64x2.sub") (param $0 v128) (param $1 v128) (result v128) (f64x2.sub (local.get $0) (local.get $1)))
+ (func (export "f64x2.mul") (param $0 v128) (param $1 v128) (result v128) (f64x2.mul (local.get $0) (local.get $1)))
+ (func (export "f64x2.div") (param $0 v128) (param $1 v128) (result v128) (f64x2.div (local.get $0) (local.get $1)))
+ (func (export "f64x2.min") (param $0 v128) (param $1 v128) (result v128) (f64x2.min (local.get $0) (local.get $1)))
+ (func (export "f64x2.max") (param $0 v128) (param $1 v128) (result v128) (f64x2.max (local.get $0) (local.get $1)))
+ (func (export "f64x2.pmin") (param $0 v128) (param $1 v128) (result v128) (f64x2.pmin (local.get $0) (local.get $1)))
+ (func (export "f64x2.pmax") (param $0 v128) (param $1 v128) (result v128) (f64x2.pmax (local.get $0) (local.get $1)))
+ (func (export "f64x2.ceil") (param $0 v128) (result v128) (f64x2.ceil (local.get $0)))
+ (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)))
+ (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)))
+ (func (export "i64x2.trunc_sat_f64x2_u") (param $0 v128) (result v128) (i64x2.trunc_sat_f64x2_u (local.get $0)))
+ (func (export "f32x4.convert_i32x4_s") (param $0 v128) (result v128) (f32x4.convert_i32x4_s (local.get $0)))
+ (func (export "f32x4.convert_i32x4_u") (param $0 v128) (result v128) (f32x4.convert_i32x4_u (local.get $0)))
+ (func (export "f64x2.convert_i64x2_s") (param $0 v128) (result v128) (f64x2.convert_i64x2_s (local.get $0)))
+ (func (export "f64x2.convert_i64x2_u") (param $0 v128) (result v128) (f64x2.convert_i64x2_u (local.get $0)))
+ (func (export "v8x16.load_splat") (param $0 i32) (result v128) (v8x16.load_splat (local.get $0)))
+ (func (export "v16x8.load_splat") (param $0 i32) (result v128) (v16x8.load_splat (local.get $0)))
+ (func (export "v32x4.load_splat") (param $0 i32) (result v128) (v32x4.load_splat (local.get $0)))
+ (func (export "v64x2.load_splat") (param $0 i32) (result v128) (v64x2.load_splat (local.get $0)))
+ (func (export "i8x16.narrow_i16x8_s") (param $0 v128) (param $1 v128) (result v128) (i8x16.narrow_i16x8_s (local.get $0) (local.get $1)))
+ (func (export "i8x16.narrow_i16x8_u") (param $0 v128) (param $1 v128) (result v128) (i8x16.narrow_i16x8_u (local.get $0) (local.get $1)))
+ (func (export "i16x8.narrow_i32x4_s") (param $0 v128) (param $1 v128) (result v128) (i16x8.narrow_i32x4_s (local.get $0) (local.get $1)))
+ (func (export "i16x8.narrow_i32x4_u") (param $0 v128) (param $1 v128) (result v128) (i16x8.narrow_i32x4_u (local.get $0) (local.get $1)))
+ (func (export "i16x8.widen_low_i8x16_s") (param $0 v128) (result v128) (i16x8.widen_low_i8x16_s (local.get $0)))
+ (func (export "i16x8.widen_high_i8x16_s") (param $0 v128) (result v128) (i16x8.widen_high_i8x16_s (local.get $0)))
+ (func (export "i16x8.widen_low_i8x16_u") (param $0 v128) (result v128) (i16x8.widen_low_i8x16_u (local.get $0)))
+ (func (export "i16x8.widen_high_i8x16_u") (param $0 v128) (result v128) (i16x8.widen_high_i8x16_u (local.get $0)))
+ (func (export "i32x4.widen_low_i16x8_s") (param $0 v128) (result v128) (i32x4.widen_low_i16x8_s (local.get $0)))
+ (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 "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)))
+ (func (export "i32x4.load16x4_s") (param $0 i32) (result v128) (i32x4.load16x4_s (local.get $0)))
+ (func (export "i64x2.load32x2_u") (param $0 i32) (result v128) (i64x2.load32x2_u (local.get $0)))
+ (func (export "i64x2.load32x2_s") (param $0 i32) (result v128) (i64x2.load32x2_s (local.get $0)))
+ (func (export "v128.load32_zero") (param $0 i32) (result v128) (v128.load32_zero (local.get $0)))
+ (func (export "v128.load64_zero") (param $0 i32) (result v128) (v128.load64_zero (local.get $0)))
+ (func (export "v8x16.swizzle") (param $0 v128) (param $1 v128) (result v128) (v8x16.swizzle (local.get $0) (local.get $1)))
+)
+
+;; Basic v128 manipulation
+(assert_return (invoke "v128.load" (i32.const 128)) (v128.const i8x16 87 65 83 77 83 73 77 68 71 79 69 83 70 65 83 84))
+(assert_return (invoke "v128.store" (i32.const 16) (v128.const i32x4 1 2 3 4)) (v128.const i32x4 1 2 3 4))
+(assert_return (invoke "v8x16.load_splat" (i32.const 128)) (v128.const i8x16 87 87 87 87 87 87 87 87 87 87 87 87 87 87 87 87))
+(assert_return (invoke "v16x8.load_splat" (i32.const 128)) (v128.const i8x16 87 65 87 65 87 65 87 65 87 65 87 65 87 65 87 65))
+(assert_return (invoke "v32x4.load_splat" (i32.const 128)) (v128.const i8x16 87 65 83 77 87 65 83 77 87 65 83 77 87 65 83 77))
+(assert_return (invoke "v64x2.load_splat" (i32.const 128)) (v128.const i8x16 87 65 83 77 83 73 77 68 87 65 83 77 83 73 77 68))
+(assert_return (invoke "v128.const.i8x16") (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d))
+(assert_return (invoke "v128.const.i16x8") (v128.const i8x16 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00))
+(assert_return (invoke "v128.const.i32x4") (v128.const i8x16 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00))
+(assert_return (invoke "v128.const.i64x2") (v128.const i8x16 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00))
+(assert_return (invoke "v128.const.f32x4") (v128.const f32x4 1 2 3 4))
+(assert_return (invoke "v128.const.f64x2") (v128.const f64x2 1 2))
+(assert_return
+  (invoke "v128.shuffle_interleave_bytes"
+    (v128.const i8x16 1 0 3 0 5 0 7 0 9 0 11 0 13 0 15 0)
+    (v128.const i8x16 0 2 0 4 0 6 0 8 0 10 0 12 0 14 0 16)
+  )
+  (v128.const i8x16 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16)
+)
+(assert_return (invoke "v128.shuffle_reverse_i32s" (v128.const i32x4 1 2 3 4)) (v128.const i32x4 4 3 2 1))
+
+;; i8x16 lane accesses
+(assert_return (invoke "i8x16.splat" (i32.const 5)) (v128.const i8x16 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5))
+(assert_return (invoke "i8x16.splat" (i32.const 257)) (v128.const i8x16 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1))
+(assert_return (invoke "i8x16.extract_lane_s_first" (v128.const i8x16 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)) (i32.const -1))
+(assert_return (invoke "i8x16.extract_lane_s_last" (v128.const i8x16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255)) (i32.const -1))
+(assert_return (invoke "i8x16.extract_lane_u_first" (v128.const i8x16 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)) (i32.const 255))
+(assert_return (invoke "i8x16.extract_lane_u_last" (v128.const i8x16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255)) (i32.const 255))
+(assert_return (invoke "i8x16.replace_lane_first" (v128.const i64x2 0 0) (i32.const 7)) (v128.const i8x16 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0))
+(assert_return (invoke "i8x16.replace_lane_last" (v128.const i64x2 0 0) (i32.const 7)) (v128.const i8x16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7))
+
+;; i16x8 lane accesses
+(assert_return (invoke "i16x8.splat" (i32.const 5)) (v128.const i16x8 5 5 5 5 5 5 5 5))
+(assert_return (invoke "i16x8.splat" (i32.const 65537)) (v128.const i32x4 1 1 1 1 1 1 1 1))
+(assert_return (invoke "i16x8.extract_lane_s_first" (v128.const i32x4 65535 0 0 0 0 0 0 0)) (i32.const -1))
+(assert_return (invoke "i16x8.extract_lane_s_last" (v128.const i32x4 0 0 0 0 0 0 0 65535)) (i32.const -1))
+(assert_return (invoke "i16x8.extract_lane_u_first" (v128.const i32x4 65535 0 0 0 0 0 0 0)) (i32.const 65535))
+(assert_return (invoke "i16x8.extract_lane_u_last" (v128.const i32x4 0 0 0 0 0 0 0 65535)) (i32.const 65535))
+(assert_return (invoke "i16x8.replace_lane_first" (v128.const i64x2 0 0) (i32.const 7)) (v128.const i32x4 7 0 0 0 0 0 0 0))
+(assert_return (invoke "i16x8.replace_lane_last" (v128.const i64x2 0 0) (i32.const 7)) (v128.const i32x4 0 0 0 0 0 0 0 7))
+
+;; i32x4 lane accesses
+(assert_return (invoke "i32x4.splat" (i32.const -5)) (v128.const i32x4 -5 -5 -5 -5))
+(assert_return (invoke "i32x4.extract_lane_first" (v128.const i32x4 -5 0 0 0)) (i32.const -5))
+(assert_return (invoke "i32x4.extract_lane_last" (v128.const i32x4 0 0 0 -5)) (i32.const -5))
+(assert_return (invoke "i32x4.replace_lane_first" (v128.const i64x2 0 0) (i32.const 53)) (v128.const i32x4 53 0 0 0))
+(assert_return (invoke "i32x4.replace_lane_last" (v128.const i64x2 0 0) (i32.const 53)) (v128.const i32x4 0 0 0 53))
+
+;; i64x2 lane accesses
+(assert_return (invoke "i64x2.splat" (i64.const -5)) (v128.const i64x2 -5 -5))
+(assert_return (invoke "i64x2.extract_lane_first" (v128.const i64x2 -5 0)) (i64.const -5))
+(assert_return (invoke "i64x2.extract_lane_last" (v128.const i64x2 0 -5)) (i64.const -5))
+(assert_return (invoke "i64x2.replace_lane_first" (v128.const i64x2 0 0) (i64.const 53)) (v128.const i64x2 53 0))
+(assert_return (invoke "i64x2.replace_lane_last" (v128.const i64x2 0 0) (i64.const 53)) (v128.const i64x2 0 53))
+
+;; f32x4 lane accesses
+(assert_return (invoke "f32x4.splat" (f32.const -5)) (v128.const f32x4 -5 -5 -5 -5))
+(assert_return (invoke "f32x4.extract_lane_first" (v128.const f32x4 -5 0 0 0)) (f32.const -5))
+(assert_return (invoke "f32x4.extract_lane_last" (v128.const f32x4 0 0 0 -5)) (f32.const -5))
+(assert_return (invoke "f32x4.replace_lane_first" (v128.const i64x2 0 0) (f32.const 53)) (v128.const f32x4 53 0 0 0))
+(assert_return (invoke "f32x4.replace_lane_last" (v128.const i64x2 0 0) (f32.const 53)) (v128.const f32x4 0 0 0 53))
+
+;; f64x2 lane accesses
+(assert_return (invoke "f64x2.splat" (f64.const -5)) (v128.const f64x2 -5 -5))
+(assert_return (invoke "f64x2.extract_lane_first" (v128.const f64x2 -5 0)) (f64.const -5))
+(assert_return (invoke "f64x2.extract_lane_last" (v128.const f64x2 0 -5)) (f64.const -5))
+(assert_return (invoke "f64x2.replace_lane_first" (v128.const f64x2 0 0) (f64.const 53)) (v128.const f64x2 53 0))
+(assert_return (invoke "f64x2.replace_lane_last" (v128.const f64x2 0 0) (f64.const 53)) (v128.const f64x2 0 53))
+
+;; i8x16 comparisons
+(assert_return
+  (invoke "i8x16.eq"
+    (v128.const i32x4 0 127 13 128 1   13  129 42  0 127 255 42  1   13  129 42)
+    (v128.const i32x4 0 255 13 42  129 127 0   128 0 255 13  42  129 127 0   128)
+  )
+  (v128.const i32x4 -1 0 -1 0 0 0 0 0 -1 0 0 -1 0 0 0 0)
+)
+(assert_return
+  (invoke "i8x16.ne"
+    (v128.const i32x4 0 127 13 128 1   13  129 42  0 127 255 42  1   13  129 42)
+    (v128.const i32x4 0 255 13 42  129 127 0   128 0 255 13  42  129 127 0   128)
+  )
+  (v128.const i32x4 0 -1 0 -1 -1 -1 -1 -1 0 -1 -1 0 -1 -1 -1 -1)
+)
+(assert_return
+  (invoke "i8x16.lt_s"
+    (v128.const i32x4 0 127 13 128 1   13  129 42  0 127 255 42  1   13  129 42)
+    (v128.const i32x4 0 255 13 42  129 127 0   128 0 255 13  42  129 127 0   128)
+  )
+  (v128.const i32x4 0 0 0 -1 0 -1 -1 0 0 0 -1 0 0 -1 -1 0)
+)
+(assert_return
+  (invoke "i8x16.lt_u"
+    (v128.const i32x4 0 127 13 128 1   13  129 42  0 127 255 42  1   13  129 42)
+    (v128.const i32x4 0 255 13 42  129 127 0   128 0 255 13  42  129 127 0   128)
+  )
+  (v128.const i32x4 0 -1 0 0 -1 -1 0 -1 0 -1 0 0 -1 -1 0 -1)
+)
+(assert_return
+  (invoke "i8x16.gt_s"
+    (v128.const i32x4 0 127 13 128 1   13  129 42  0 127 255 42  1   13  129 42)
+    (v128.const i32x4 0 255 13 42  129 127 0   128 0 255 13  42  129 127 0   128)
+  )
+  (v128.const i32x4 0 -1 0 0 -1 0 0 -1 0 -1 0 0 -1 0 0 -1)
+)
+(assert_return
+  (invoke "i8x16.gt_u"
+    (v128.const i32x4 0 127 13 128 1   13  129 42  0 127 255 42  1   13  129 42)
+    (v128.const i32x4 0 255 13 42  129 127 0   128 0 255 13  42  129 127 0   128)
+  )
+  (v128.const i32x4 0 0 0 -1 0 0 -1 0 0 0 -1 0 0 0 -1 0)
+)
+(assert_return
+  (invoke "i8x16.le_s"
+    (v128.const i32x4 0 127 13 128 1   13  129 42  0 127 255 42  1   13  129 42)
+    (v128.const i32x4 0 255 13 42  129 127 0   128 0 255 13  42  129 127 0   128)
+  )
+  (v128.const i32x4 -1 0 -1 -1 0 -1 -1 0 -1 0 -1 -1 0 -1 -1 0)
+)
+(assert_return
+  (invoke "i8x16.le_u"
+    (v128.const i32x4 0 127 13 128 1   13  129 42  0 127 255 42  1   13  129 42)
+    (v128.const i32x4 0 255 13 42  129 127 0   128 0 255 13  42  129 127 0   128)
+  )
+  (v128.const i32x4 -1 -1 -1 0 -1 -1 0 -1 -1 -1 0 -1 -1 -1 0 -1)
+)
+(assert_return
+  (invoke "i8x16.ge_s"
+    (v128.const i32x4 0 127 13 128 1   13  129 42  0 127 255 42  1   13  129 42)
+    (v128.const i32x4 0 255 13 42  129 127 0   128 0 255 13  42  129 127 0   128)
+  )
+  (v128.const i32x4 -1 -1 -1 0 -1 0 0 -1 -1 -1 0 -1 -1 0 0 -1)
+)
+(assert_return
+  (invoke "i8x16.ge_u"
+    (v128.const i32x4 0 127 13 128 1   13  129 42  0 127 255 42  1   13  129 42)
+    (v128.const i32x4 0 255 13 42  129 127 0   128 0 255 13  42  129 127 0   128)
+  )
+  (v128.const i32x4 -1 0 -1 -1 0 0 -1 0 -1 0 -1 -1 0 0 -1 0)
+)
+
+;; i16x8 comparisons
+(assert_return (invoke "i16x8.eq"
+    (v128.const i32x4 0 32767 13 32768 1     32769 42    40000)
+    (v128.const i32x4 0 13    1  32767 32769 42    40000 32767)
+  )
+  (v128.const i32x4 -1 0 0 0 0 0 0 0)
+)
+(assert_return
+  (invoke "i16x8.ne"
+    (v128.const i32x4 0 32767 13 32768 1     32769 42    40000)
+    (v128.const i32x4 0 13    1  32767 32769 42    40000 32767)
+  )
+  (v128.const i32x4 0 -1 -1 -1 -1 -1 -1 -1)
+)
+(assert_return
+  (invoke "i16x8.lt_s"
+    (v128.const i32x4 0 32767 13 32768 1     32769 42    40000)
+    (v128.const i32x4 0 13    1  32767 32769 42    40000 32767)
+  )
+  (v128.const i32x4 0 0 0 -1 0 -1 0 -1)
+)
+(assert_return
+  (invoke "i16x8.lt_u"
+    (v128.const i32x4 0 32767 13 32768 1     32769 42    40000)
+    (v128.const i32x4 0 13    1  32767 32769 42    40000 32767)
+  )
+  (v128.const i32x4 0 0 0 0 -1 0 -1 0)
+)
+(assert_return
+  (invoke "i16x8.gt_s"
+    (v128.const i32x4 0 32767 13 32768 1     32769 42    40000)
+    (v128.const i32x4 0 13    1  32767 32769 42    40000 32767)
+  )
+  (v128.const i32x4 0 -1 -1 0 -1 0 -1 0)
+)
+(assert_return
+  (invoke "i16x8.gt_u"
+    (v128.const i32x4 0 32767 13 32768 1     32769 42    40000)
+    (v128.const i32x4 0 13    1  32767 32769 42    40000 32767)
+  )
+  (v128.const i32x4 0 -1 -1 -1 0 -1 0 -1)
+)
+(assert_return
+  (invoke "i16x8.le_s"
+    (v128.const i32x4 0 32767 13 32768 1     32769 42    40000)
+    (v128.const i32x4 0 13    1  32767 32769 42    40000 32767)
+  )
+  (v128.const i32x4 -1 0 0 -1 0 -1 0 -1)
+)
+(assert_return
+  (invoke "i16x8.le_u"
+    (v128.const i32x4 0 32767 13 32768 1     32769 42    40000)
+    (v128.const i32x4 0 13    1  32767 32769 42    40000 32767)
+  )
+  (v128.const i32x4 -1 0 0 0 -1 0 -1 0)
+)
+(assert_return
+  (invoke "i16x8.ge_s"
+    (v128.const i32x4 0 32767 13 32768 1     32769 42    40000)
+    (v128.const i32x4 0 13    1  32767 32769 42    40000 32767)
+  )
+  (v128.const i32x4 -1 -1 -1 0 -1 0 -1 0)
+)
+(assert_return
+  (invoke "i16x8.ge_u"
+    (v128.const i32x4 0 32767 13 32768 1     32769 42    40000)
+    (v128.const i32x4 0 13    1  32767 32769 42    40000 32767)
+  )
+  (v128.const i32x4 -1 -1 -1 -1 0 -1 0 -1)
+)
+
+;; i32x4 comparisons
+(assert_return (invoke "i32x4.eq" (v128.const i32x4 0 -1 53 -7) (v128.const i32x4 0 53 -7 -1)) (v128.const i32x4 -1 0 0 0))
+(assert_return (invoke "i32x4.ne" (v128.const i32x4 0 -1 53 -7) (v128.const i32x4 0 53 -7 -1)) (v128.const i32x4 0 -1 -1 -1))
+(assert_return (invoke "i32x4.lt_s" (v128.const i32x4 0 -1 53 -7) (v128.const i32x4 0 53 -7 -1)) (v128.const i32x4 0 -1 0 -1))
+(assert_return (invoke "i32x4.lt_u" (v128.const i32x4 0 -1 53 -7) (v128.const i32x4 0 53 -7 -1)) (v128.const i32x4 0 0 -1 -1))
+(assert_return (invoke "i32x4.gt_s" (v128.const i32x4 0 -1 53 -7) (v128.const i32x4 0 53 -7 -1)) (v128.const i32x4 0 0 -1 0))
+(assert_return (invoke "i32x4.gt_u" (v128.const i32x4 0 -1 53 -7) (v128.const i32x4 0 53 -7 -1)) (v128.const i32x4 0 -1 0 0))
+(assert_return (invoke "i32x4.le_s" (v128.const i32x4 0 -1 53 -7) (v128.const i32x4 0 53 -7 -1)) (v128.const i32x4 -1 -1 0 -1))
+(assert_return (invoke "i32x4.le_u" (v128.const i32x4 0 -1 53 -7) (v128.const i32x4 0 53 -7 -1)) (v128.const i32x4 -1 0 -1 -1))
+(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))
+
+;; 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))
+(assert_return (invoke "f32x4.lt" (v128.const f32x4 0 -1 1 0) (v128.const f32x4 0 0 -1 1)) (v128.const i32x4 0 -1 0 -1))
+(assert_return (invoke "f32x4.gt" (v128.const f32x4 0 -1 1 0) (v128.const f32x4 0 0 -1 1)) (v128.const i32x4 0 0 -1 0))
+(assert_return (invoke "f32x4.le" (v128.const f32x4 0 -1 1 0) (v128.const f32x4 0 0 -1 1)) (v128.const i32x4 -1 -1 0 -1))
+(assert_return (invoke "f32x4.ge" (v128.const f32x4 0 -1 1 0) (v128.const f32x4 0 0 -1 1)) (v128.const i32x4 -1 0 -1 0))
+(assert_return (invoke "f32x4.eq" (v128.const f32x4 nan 0 nan infinity) (v128.const f32x4 0 nan nan infinity)) (v128.const i32x4 0 0 0 -1))
+(assert_return (invoke "f32x4.ne" (v128.const f32x4 nan 0 nan infinity) (v128.const f32x4 0 nan nan infinity)) (v128.const i32x4 -1 -1 -1 0))
+(assert_return (invoke "f32x4.lt" (v128.const f32x4 nan 0 nan infinity) (v128.const f32x4 0 nan nan infinity)) (v128.const i32x4 0 0 0 0))
+(assert_return (invoke "f32x4.gt" (v128.const f32x4 nan 0 nan infinity) (v128.const f32x4 0 nan nan infinity)) (v128.const i32x4 0 0 0 0))
+(assert_return (invoke "f32x4.le" (v128.const f32x4 nan 0 nan infinity) (v128.const f32x4 0 nan nan infinity)) (v128.const i32x4 0 0 0 -1))
+(assert_return (invoke "f32x4.ge" (v128.const f32x4 nan 0 nan infinity) (v128.const f32x4 0 nan nan infinity)) (v128.const i32x4 0 0 0 -1))
+(assert_return (invoke "f32x4.eq" (v128.const f32x4 -infinity 0 nan -infinity) (v128.const f32x4 0 infinity infinity nan)) (v128.const i32x4 0 0 0 0))
+(assert_return (invoke "f32x4.ne" (v128.const f32x4 -infinity 0 nan -infinity) (v128.const f32x4 0 infinity infinity nan)) (v128.const i32x4 -1 -1 -1 -1))
+(assert_return (invoke "f32x4.lt" (v128.const f32x4 -infinity 0 nan -infinity) (v128.const f32x4 0 infinity infinity nan)) (v128.const i32x4 -1 -1 0 0))
+(assert_return (invoke "f32x4.gt" (v128.const f32x4 -infinity 0 nan -infinity) (v128.const f32x4 0 infinity infinity nan)) (v128.const i32x4 0 0 0 0))
+(assert_return (invoke "f32x4.le" (v128.const f32x4 -infinity 0 nan -infinity) (v128.const f32x4 0 infinity infinity nan)) (v128.const i32x4 -1 -1 0 0))
+(assert_return (invoke "f32x4.ge" (v128.const f32x4 -infinity 0 nan -infinity) (v128.const f32x4 0 infinity infinity nan)) (v128.const i32x4 0 0 0 0))
+
+;; f64x2 comparisons
+(assert_return (invoke "f64x2.eq" (v128.const f64x2 0 1) (v128.const f64x2 0 0)) (v128.const i64x2 -1 0))
+(assert_return (invoke "f64x2.ne" (v128.const f64x2 0 1) (v128.const f64x2 0 0)) (v128.const i64x2 0 -1))
+(assert_return (invoke "f64x2.lt" (v128.const f64x2 0 1) (v128.const f64x2 0 0)) (v128.const i64x2 0 0))
+(assert_return (invoke "f64x2.gt" (v128.const f64x2 0 1) (v128.const f64x2 0 0)) (v128.const i64x2 0 -1))
+(assert_return (invoke "f64x2.le" (v128.const f64x2 0 1) (v128.const f64x2 0 0)) (v128.const i64x2 -1 0))
+(assert_return (invoke "f64x2.ge" (v128.const f64x2 0 1) (v128.const f64x2 0 0)) (v128.const i64x2 -1 -1))
+(assert_return (invoke "f64x2.eq" (v128.const f64x2 nan 0) (v128.const f64x2 infinity infinity)) (v128.const i64x2 0 0))
+(assert_return (invoke "f64x2.ne" (v128.const f64x2 nan 0) (v128.const f64x2 infinity infinity)) (v128.const i64x2 -1 -1))
+(assert_return (invoke "f64x2.lt" (v128.const f64x2 nan 0) (v128.const f64x2 infinity infinity)) (v128.const i64x2 0 -1))
+(assert_return (invoke "f64x2.gt" (v128.const f64x2 nan 0) (v128.const f64x2 infinity infinity)) (v128.const i64x2 0 0))
+(assert_return (invoke "f64x2.le" (v128.const f64x2 nan 0) (v128.const f64x2 infinity infinity)) (v128.const i64x2 0 -1))
+(assert_return (invoke "f64x2.ge" (v128.const f64x2 nan 0) (v128.const f64x2 infinity infinity)) (v128.const i64x2 0 0))
+
+;; bitwise operations
+(assert_return (invoke "v128.not" (v128.const i32x4 0 -1 0 -1)) (v128.const i32x4 -1 0 -1 0))
+(assert_return (invoke "v128.and" (v128.const i32x4 0 0 -1 -1) (v128.const i32x4 0 -1 0 -1)) (v128.const i32x4 0 0 0 -1))
+(assert_return (invoke "v128.or" (v128.const i32x4 0 0 -1 -1) (v128.const i32x4 0 -1 0 -1)) (v128.const i32x4 0 -1 -1 -1))
+(assert_return (invoke "v128.xor" (v128.const i32x4 0 0 -1 -1) (v128.const i32x4 0 -1 0 -1)) (v128.const i32x4 0 -1 -1 0))
+(assert_return (invoke "v128.andnot" (v128.const i32x4 0 0 -1 -1) (v128.const i32x4 0 -1 0 -1)) (v128.const i32x4 0 0 -1 0))
+(assert_return (invoke "v128.bitselect"
+    (v128.const i32x4 0xAAAAAAAA 0xAAAAAAAA 0xAAAAAAAA 0xAAAAAAAA)
+    (v128.const i32x4 0xBBBBBBBB 0xBBBBBBBB 0xBBBBBBBB 0xBBBBBBBB)
+    (v128.const i32x4 0xF0F0F0F0 0xFFFFFFFF 0x00000000 0xFF00FF00)
+  )
+  (v128.const i32x4 0xABABABAB 0xAAAAAAAA 0xBBBBBBBB 0xAABBAABB)
+)
+
+;; i8x16 arithmetic
+(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)
+)
+(assert_return (invoke "i8x16.neg" (v128.const i32x4 0 1 42 -3 -56 127 -128 -126 0 -1 -42 3 56 -127 -128 126))
+  (v128.const i32x4 0 -1 -42 3 56 -127 -128 126 0 1 42 -3 -56 127 -128 -126)
+)
+(assert_return (invoke "i8x16.any_true" (v128.const i32x4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)) (i32.const 0))
+(assert_return (invoke "i8x16.any_true" (v128.const i32x4 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0)) (i32.const 1))
+(assert_return (invoke "i8x16.any_true" (v128.const i32x4 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1)) (i32.const 1))
+(assert_return (invoke "i8x16.any_true" (v128.const i32x4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)) (i32.const 1))
+(assert_return (invoke "i8x16.all_true" (v128.const i32x4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)) (i32.const 0))
+(assert_return (invoke "i8x16.all_true" (v128.const i32x4 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0)) (i32.const 0))
+(assert_return (invoke "i8x16.all_true" (v128.const i32x4 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1)) (i32.const 0))
+(assert_return (invoke "i8x16.all_true" (v128.const i32x4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)) (i32.const 1))
+(assert_return (invoke "i8x16.bitmask" (v128.const i8x16 -1 0 1 -128 127 -127 0 128 -1 0 1 -128 127 -127 0 128)) (i32.const 43433))
+(assert_return (invoke "i8x16.shl" (v128.const i32x4 0 1 2 4 8 16 32 64 -128 3 6 12 24 48 96 -64) (i32.const 1))
+  (v128.const i32x4 0 2 4 8 16 32 64 -128 0 6 12 24 48 96 -64 -128)
+)
+(assert_return (invoke "i8x16.shl" (v128.const i32x4 0 1 2 4 8 16 32 64 -128 3 6 12 24 48 96 -64) (i32.const 8))
+  (v128.const i32x4 0 1 2 4 8 16 32 64 -128 3 6 12 24 48 96 -64)
+)
+(assert_return (invoke "i8x16.shr_u" (v128.const i32x4 0 1 2 4 8 16 32 64 -128 3 6 12 24 48 96 -64) (i32.const 1))
+  (v128.const i32x4 0 0 1 2 4 8 16 32 64 1 3 6 12 24 48 96)
+)
+(assert_return (invoke "i8x16.shr_u" (v128.const i32x4 0 1 2 4 8 16 32 64 -128 3 6 12 24 48 96 -64) (i32.const 8))
+  (v128.const i32x4 0 1 2 4 8 16 32 64 -128 3 6 12 24 48 96 -64)
+)
+(assert_return (invoke "i8x16.shr_s" (v128.const i32x4 0 1 2 4 8 16 32 64 -128 3 6 12 24 48 96 -64) (i32.const 1))
+  (v128.const i32x4 0 0 1 2 4 8 16 32 -64 1 3 6 12 24 48 -32)
+)
+(assert_return (invoke "i8x16.shr_s" (v128.const i32x4 0 1 2 4 8 16 32 64 -128 3 6 12 24 48 96 -64) (i32.const 8))
+  (v128.const i32x4 0 1 2 4 8 16 32 64 -128 3 6 12 24 48 96 -64)
+)
+(assert_return
+  (invoke "i8x16.add"
+    (v128.const i32x4 0  42 255 128 127 129   6 29 103 196 231 142 17 250   1  73)
+    (v128.const i32x4 3 231   1 128 129 6   103 17  42  29  73  42  0 255 127 142)
+  )
+  (v128.const i32x4 3 17 0 0 0 135 109 46 145 225 48 184 17 249 128 215)
+)
+(assert_return
+  (invoke "i8x16.add_saturate_s"
+    (v128.const i32x4 0  42 255 128 127 129   6 29 103 196 231 142 17 250   1  73)
+    (v128.const i32x4 3 231   1 128 129 6   103 17  42  29  73  42  0 255 127 142)
+  )
+  (v128.const i32x4 3 17 0 128 0 135 109 46 127 225 48 184 17 249 127 215)
+)
+(assert_return
+  (invoke "i8x16.add_saturate_u"
+    (v128.const i32x4 0  42 255 128 127 129   6 29 103 196 231 142 17 250   1  73)
+    (v128.const i32x4 3 231   1 128 129 6   103 17  42  29  73  42  0 255 127 142)
+  )
+  (v128.const i32x4 3 255 255 255 255 135 109 46 145 225 255 184 17 255 128 215)
+)
+(assert_return
+  (invoke "i8x16.sub"
+    (v128.const i32x4 0  42 255 128 127 129   6 29 103 196 231 142 17 250   1  73)
+    (v128.const i32x4 3 231   1 128 129 6   103 17  42  29  73  42  0 255 127 142)
+  )
+  (v128.const i32x4 253 67 254 0 254 123 159 12 61 167 158 100 17 251 130 187)
+)
+(assert_return
+  (invoke "i8x16.sub_saturate_s"
+    (v128.const i32x4 0  42 255 128 127 129   6 29 103 196 231 142 17 250   1  73)
+    (v128.const i32x4 3 231   1 128 129 6   103 17  42  29  73  42  0 255 127 142)
+  )
+  (v128.const i32x4 253 67 254 0 127 128 159 12 61 167 158 128 17 251 130 127)
+)
+(assert_return
+  (invoke "i8x16.sub_saturate_u"
+    (v128.const i32x4 0  42 255 128 127 129   6 29 103 196 231 142 17 250   1  73)
+    (v128.const i32x4 3 231   1 128 129 6   103 17  42  29  73  42  0 255 127 142)
+  )
+  (v128.const i32x4 0 0 254 0 0 123 0 12 61 167 158 100 17 0 0 0)
+)
+(assert_return
+  (invoke "i8x16.mul"
+    (v128.const i32x4 0  42 255 128 127 129   6 29 103 196 231 142 17 250   1  73)
+    (v128.const i32x4 3 231   1 128 129 6   103 17  42  29  73  42  0 255 127 142)
+  )
+  (v128.const i32x4 0 230 255 0 255 6 106 237 230 52 223 76 0 6 127 126)
+)
+(assert_return
+  (invoke "i8x16.min_s"
+    (v128.const i32x4 0  42 255 128 127 129   6 29 103 196 231 142 17 250   1  73)
+    (v128.const i32x4 3 231   1 128 129 6   103 17  42  29  73  42  0 255 127 142)
+  )
+  (v128.const i8x16 0 231 255 128 129 129 6 17 42 196 231 142 0 250 1 142)
+)
+(assert_return
+  (invoke "i8x16.min_u"
+    (v128.const i32x4 0  42 255 128 127 129   6 29 103 196 231 142 17 250   1  73)
+    (v128.const i32x4 3 231   1 128 129 6   103 17  42  29  73  42  0 255 127 142)
+  )
+  (v128.const i8x16 0 42 1 128 127 6 6 17 42 29 73 42 0 250 1 73)
+)
+(assert_return
+  (invoke "i8x16.max_s"
+    (v128.const i32x4 0  42 255 128 127 129   6 29 103 196 231 142 17 250   1  73)
+    (v128.const i32x4 3 231   1 128 129 6   103 17  42  29  73  42  0 255 127 142)
+  )
+  (v128.const i8x16 3 42 1 128 127 6 103 29 103 29 73 42 17 255 127 73)
+)
+(assert_return
+  (invoke "i8x16.max_u"
+    (v128.const i32x4 0  42 255 128 127 129   6 29 103 196 231 142 17 250   1  73)
+    (v128.const i32x4 3 231   1 128 129 6   103 17  42  29  73  42  0 255 127 142)
+  )
+  (v128.const i8x16 3 231 255 128 129 129 103 29 103 196 231 142 17 255 127 142)
+)
+(assert_return
+  (invoke "i8x16.avgr_u"
+    (v128.const i8x16 0  42 255 128 127 129   6 29 103 196 231 142 17 250   1  73)
+    (v128.const i8x16 3 231   1 128 129 6   103 17  42  29  73  42  0 255 127 142)
+  )
+  (v128.const i8x16 2 137 128 128 128 68 55 23 73 113 152 92 9 253 64 108)
+)
+
+;; i16x8 arithmetic
+(assert_return (invoke "i16x8.abs" (v128.const i16x8 0 1 42 -3 -56 32767 -32768 32766))
+  (v128.const i16x8 0 1 42 3 56 32767 -32768 32766)
+)
+(assert_return (invoke "i16x8.neg" (v128.const i32x4 0 1 42 -3 -56 32767 -32768 32766))
+  (v128.const i32x4 0 -1 -42 3 56 -32767 -32768 -32766)
+)
+(assert_return (invoke "i16x8.any_true" (v128.const i32x4 0 0 0 0 0 0 0 0)) (i32.const 0))
+(assert_return (invoke "i16x8.any_true" (v128.const i32x4 0 0 1 0 0 0 0 0)) (i32.const 1))
+(assert_return (invoke "i16x8.any_true" (v128.const i32x4 1 1 1 1 1 0 1 1)) (i32.const 1))
+(assert_return (invoke "i16x8.any_true" (v128.const i32x4 1 1 1 1 1 1 1 1)) (i32.const 1))
+(assert_return (invoke "i16x8.all_true" (v128.const i32x4 0 0 0 0 0 0 0 0)) (i32.const 0))
+(assert_return (invoke "i16x8.all_true" (v128.const i32x4 0 0 1 0 0 0 0 0)) (i32.const 0))
+(assert_return (invoke "i16x8.all_true" (v128.const i32x4 1 1 1 1 1 0 1 1)) (i32.const 0))
+(assert_return (invoke "i16x8.all_true" (v128.const i32x4 1 1 1 1 1 1 1 1)) (i32.const 1))
+(assert_return (invoke "i16x8.bitmask" (v128.const i16x8 -1 0 1 -32768 32767 -32767 0 32768)) (i32.const 169))
+(assert_return (invoke "i16x8.shl" (v128.const i32x4 0 8 16 128 256 2048 4096 -32768) (i32.const 1)) (v128.const i32x4 0 16 32 256 512 4096 8192 0))
+(assert_return (invoke "i16x8.shl" (v128.const i32x4 0 8 16 128 256 2048 4096 -32768) (i32.const 16)) (v128.const i32x4 0 8 16 128 256 2048 4096 -32768))
+(assert_return (invoke "i16x8.shr_u" (v128.const i32x4 0 8 16 128 256 2048 4096 -32768) (i32.const 1)) (v128.const i32x4 0 4 8 64 128 1024 2048 16384))
+(assert_return (invoke "i16x8.shr_u" (v128.const i32x4 0 8 16 128 256 2048 4096 -32768) (i32.const 16)) (v128.const i32x4 0 8 16 128 256 2048 4096 -32768))
+(assert_return (invoke "i16x8.shr_s" (v128.const i32x4 0 8 16 128 256 2048 4096 -32768) (i32.const 1)) (v128.const i32x4 0 4 8 64 128 1024 2048 -16384))
+(assert_return (invoke "i16x8.shr_s" (v128.const i32x4 0 8 16 128 256 2048 4096 -32768) (i32.const 16)) (v128.const i32x4 0 8 16 128 256 2048 4096 -32768))
+(assert_return
+  (invoke "i16x8.add"
+    (v128.const i32x4 0   65280 32768 32512 33024 59136 64000 32766)
+    (v128.const i32x4 768     1 32768 33024  1536 18688 65280     2)
+  )
+  (v128.const i32x4 768 65281 0 0 34560 12288 63744 32768)
+)
+(assert_return
+  (invoke "i16x8.add_saturate_s"
+    (v128.const i32x4 0   65280 32768 32512 33024 59136 64000 32766)
+    (v128.const i32x4 768     1 32768 33024  1536 18688 65280     2)
+  )
+  (v128.const i32x4 768 65281 32768 0 34560 12288 63744 32767)
+)
+(assert_return
+  (invoke "i16x8.add_saturate_u"
+    (v128.const i32x4 0   65280 32768 32512 33024 59136 64000 32766)
+    (v128.const i32x4 768     1 32768 33024  1536 18688 65280     2)
+  )
+  (v128.const i32x4 768 65281 65535 65535 34560 65535 65535 32768)
+)
+(assert_return
+  (invoke "i16x8.sub"
+    (v128.const i32x4 0   65280 32768 32512 33024 59136 64000 32766)
+    (v128.const i32x4 768     1 32768 33024  1536 18688 65280     2)
+  )
+  (v128.const i32x4 64768 65279 0 65024 31488 40448 64256 32764)
+)
+(assert_return
+  (invoke "i16x8.sub_saturate_s"
+    (v128.const i32x4 0   65280 32768 32512 33024 59136 64000 32766)
+    (v128.const i32x4 768     1 32768 33024  1536 18688 65280     2)
+  )
+  (v128.const i32x4 64768 65279 0 32767 32768 40448 64256 32764)
+)
+(assert_return
+  (invoke "i16x8.sub_saturate_u"
+    (v128.const i32x4 0   65280 32768 32512 33024 59136 64000 32766)
+    (v128.const i32x4 768     1 32768 33024  1536 18688 65280     2)
+  )
+  (v128.const i32x4 0 65279 0 0 31488 40448 0 32764)
+)
+(assert_return
+  (invoke "i16x8.mul"
+    (v128.const i32x4 0   65280 32768 32512 33024 59136 64000 32766)
+    (v128.const i32x4 768     1 32768 33024  1536 18688 65280     2)
+  )
+  (v128.const i32x4 0 65280 0 0 0 0 0 65532)
+)
+(assert_return
+  (invoke "i16x8.min_s"
+    (v128.const i32x4 0   65280 32768 32512 33024 59136 64000 32766)
+    (v128.const i32x4 768     1 32768 33024  1536 18688 65280     2)
+  )
+  (v128.const i32x4 0 65280 32768 33024 33024 59136 64000 2)
+)
+(assert_return
+  (invoke "i16x8.min_u"
+    (v128.const i32x4 0   65280 32768 32512 33024 59136 64000 32766)
+    (v128.const i32x4 768     1 32768 33024  1536 18688 65280     2)
+  )
+  (v128.const i32x4 0 1 32768 32512 1536 18688 64000 2)
+)
+(assert_return
+  (invoke "i16x8.max_s"
+    (v128.const i32x4 0   65280 32768 32512 33024 59136 64000 32766)
+    (v128.const i32x4 768     1 32768 33024  1536 18688 65280     2)
+  )
+  (v128.const i32x4 768 1 32768 32512 1536 18688 65280 32766)
+)
+(assert_return
+  (invoke "i16x8.max_u"
+    (v128.const i32x4 0   65280 32768 32512 33024 59136 64000 32766)
+    (v128.const i32x4 768     1 32768 33024  1536 18688 65280     2)
+  )
+  (v128.const i32x4 768 65280 32768 33024 33024 59136 65280 32766)
+)
+(assert_return
+  (invoke "i16x8.avgr_u"
+    (v128.const i16x8 0   65280 32768 32512 33024 59136 64000 32766)
+    (v128.const i16x8 768     1 32768 33024  1536 18688 65280     2)
+  )
+  (v128.const i16x8 384 32641 32768 32768 17280 38912 64640 16384)
+)
+
+;; i32x4 arithmetic
+(assert_return (invoke "i32x4.abs" (v128.const i32x4 0 1 0x80000000 0x80000001)) (v128.const i32x4 0 1 0x80000000 0x7fffffff))
+(assert_return (invoke "i32x4.neg" (v128.const i32x4 0 1 0x80000000 0x80000001)) (v128.const i32x4 0 -1 0x80000000 0x7fffffff))
+(assert_return (invoke "i32x4.any_true" (v128.const i32x4 0 0 0 0)) (i32.const 0))
+(assert_return (invoke "i32x4.any_true" (v128.const i32x4 0 0 1 0)) (i32.const 1))
+(assert_return (invoke "i32x4.any_true" (v128.const i32x4 1 0 1 1)) (i32.const 1))
+(assert_return (invoke "i32x4.any_true" (v128.const i32x4 1 1 1 1)) (i32.const 1))
+(assert_return (invoke "i32x4.all_true" (v128.const i32x4 0 0 0 0)) (i32.const 0))
+(assert_return (invoke "i32x4.all_true" (v128.const i32x4 0 0 1 0)) (i32.const 0))
+(assert_return (invoke "i32x4.all_true" (v128.const i32x4 1 0 1 1)) (i32.const 0))
+(assert_return (invoke "i32x4.all_true" (v128.const i32x4 1 1 1 1)) (i32.const 1))
+(assert_return (invoke "i32x4.bitmask" (v128.const i32x4 -1 0 -128 127)) (i32.const 5))
+(assert_return (invoke "i32x4.shl" (v128.const i32x4 1 0x40000000 0x80000000 -1) (i32.const 1)) (v128.const i32x4 2 0x80000000 0 -2))
+(assert_return (invoke "i32x4.shl" (v128.const i32x4 1 0x40000000 0x80000000 -1) (i32.const 32)) (v128.const i32x4 1 0x40000000 0x80000000 -1))
+(assert_return (invoke "i32x4.shr_s" (v128.const i32x4 1 0x40000000 0x80000000 -1) (i32.const 1)) (v128.const i32x4 0 0x20000000 0xc0000000 -1))
+(assert_return (invoke "i32x4.shr_s" (v128.const i32x4 1 0x40000000 0x80000000 -1) (i32.const 32)) (v128.const i32x4 1 0x40000000 0x80000000 -1))
+(assert_return (invoke "i32x4.shr_u" (v128.const i32x4 1 0x40000000 0x80000000 -1) (i32.const 1)) (v128.const i32x4 0 0x20000000 0x40000000 0x7fffffff))
+(assert_return (invoke "i32x4.shr_u" (v128.const i32x4 1 0x40000000 0x80000000 -1) (i32.const 32)) (v128.const i32x4 1 0x40000000 0x80000000 -1))
+(assert_return (invoke "i32x4.add" (v128.const i32x4 0 0x80000001 42 5) (v128.const i32x4 0 0x80000001 5 42)) (v128.const i32x4 0 2 47 47))
+(assert_return (invoke "i32x4.sub" (v128.const i32x4 0 2 47 47) (v128.const i32x4 0 0x80000001 42 5)) (v128.const i32x4 0 0x80000001 5 42))
+(assert_return (invoke "i32x4.mul" (v128.const i32x4 0 0x80000001 42 5) (v128.const i32x4 0 0x80000001 42 5)) (v128.const i32x4 0 1 1764 25))
+(assert_return
+  (invoke "i32x4.min_s" (v128.const i32x4 0 0x80000001 42 0xc0000000) (v128.const i32x4 0xffffffff 42 0 0xb0000000))
+  (v128.const i32x4 0xffffffff 0x80000001 0 0xb0000000)
+)
+(assert_return
+  (invoke "i32x4.min_u" (v128.const i32x4 0 0x80000001 42 0xc0000000) (v128.const i32x4 0xffffffff 42 0 0xb0000000))
+  (v128.const i32x4 0 42 0 0xb0000000)
+)
+(assert_return
+  (invoke "i32x4.max_s" (v128.const i32x4 0 0x80000001 42 0xc0000000) (v128.const i32x4 0xffffffff 42 0 0xb0000000))
+  (v128.const i32x4 0 42 42 0xc0000000)
+)
+(assert_return
+  (invoke "i32x4.max_u" (v128.const i32x4 0 0x80000001 42 0xc0000000) (v128.const i32x4 0xffffffff 42 0 0xb0000000))
+  (v128.const i32x4 0xffffffff 0x80000001 42 0xc0000000)
+)
+(assert_return
+  (invoke "i32x4.dot_i16x8_s" (v128.const i32x4 0 1 2 3 4 5 6 7) (v128.const i32x4 -1 2 -3 4 5 6 -7 -8))
+  (v128.const i32x4 2 6 50 -98)
+)
+
+;; 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))
+(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))
+(assert_return (invoke "i64x2.shr_s" (v128.const i64x2 1 0x8000000000000000) (i32.const 64)) (v128.const i64x2 1 0x8000000000000000))
+(assert_return (invoke "i64x2.shr_u" (v128.const i64x2 1 0x8000000000000000) (i32.const 1)) (v128.const i64x2 0 0x4000000000000000))
+(assert_return (invoke "i64x2.shr_u" (v128.const i64x2 1 0x8000000000000000) (i32.const 64)) (v128.const i64x2 1 0x8000000000000000))
+(assert_return (invoke "i64x2.add" (v128.const i64x2 0x8000000000000001 42) (v128.const i64x2 0x8000000000000001 0)) (v128.const i64x2 2 42))
+(assert_return (invoke "i64x2.sub" (v128.const i64x2 2 42) (v128.const i64x2 0x8000000000000001 0)) (v128.const i64x2 0x8000000000000001 42))
+(assert_return (invoke "i64x2.mul" (v128.const i64x2 2 42) (v128.const i64x2 0x8000000000000001 0)) (v128.const i64x2 2 0))
+
+;; f32x4 arithmetic
+(assert_return (invoke "f32x4.abs" (v128.const f32x4 -0 nan -infinity 5)) (v128.const f32x4 0 nan infinity 5))
+(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.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))
+(assert_return (invoke "f32x4.pmax" (v128.const f32x4 -0 0 nan 5) (v128.const f32x4 0 -0 5 nan)) (v128.const f32x4 -0 0 nan 5))
+(assert_return (invoke "f32x4.ceil" (v128.const f32x4 -0 0 infinity -infinity)) (v128.const f32x4 -0 0 infinity -infinity))
+(assert_return (invoke "f32x4.ceil" (v128.const f32x4 nan 42 0.5 -0.5)) (v128.const f32x4 nan 42 1 -0))
+(assert_return (invoke "f32x4.ceil" (v128.const f32x4 1.5 -1.5 4.2 -4.2)) (v128.const f32x4 2 -1 5 -4))
+(assert_return (invoke "f32x4.floor" (v128.const f32x4 -0 0 infinity -infinity)) (v128.const f32x4 -0 0 infinity -infinity))
+(assert_return (invoke "f32x4.floor" (v128.const f32x4 nan 42 0.5 -0.5)) (v128.const f32x4 nan 42 0 -1))
+(assert_return (invoke "f32x4.floor" (v128.const f32x4 1.5 -1.5 4.2 -4.2)) (v128.const f32x4 1 -2 4 -5))
+(assert_return (invoke "f32x4.trunc" (v128.const f32x4 -0 0 infinity -infinity)) (v128.const f32x4 -0 0 infinity -infinity))
+(assert_return (invoke "f32x4.trunc" (v128.const f32x4 nan 42 0.5 -0.5)) (v128.const f32x4 nan 42 0 -0))
+(assert_return (invoke "f32x4.trunc" (v128.const f32x4 1.5 -1.5 4.2 -4.2)) (v128.const f32x4 1 -1 4 -4))
+(assert_return (invoke "f32x4.nearest" (v128.const f32x4 -0 0 infinity -infinity)) (v128.const f32x4 -0 0 infinity -infinity))
+(assert_return (invoke "f32x4.nearest" (v128.const f32x4 nan 42 0.5 -0.5)) (v128.const f32x4 nan 42 0 -0))
+(assert_return (invoke "f32x4.nearest" (v128.const f32x4 1.5 -1.5 4.2 -4.2)) (v128.const f32x4 2 -2 4 -4))
+
+;; f64x2 arithmetic
+(assert_return (invoke "f64x2.abs" (v128.const f64x2 -0 nan)) (v128.const f64x2 0 nan))
+(assert_return (invoke "f64x2.abs" (v128.const f64x2 -infinity 5)) (v128.const f64x2 infinity 5))
+(assert_return (invoke "f64x2.neg" (v128.const f64x2 -0 nan)) (v128.const f64x2 0 -nan))
+(assert_return (invoke "f64x2.neg" (v128.const f64x2 -infinity 5)) (v128.const f64x2 infinity -5))
+(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 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 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 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 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))
+(assert_return (invoke "f64x2.max" (v128.const f64x2 -0 0) (v128.const f64x2 0 -0)) (v128.const f64x2 0 0))
+(assert_return (invoke "f64x2.max" (v128.const f64x2 nan 5) (v128.const f64x2 5 nan)) (v128.const f64x2 nan nan))
+(assert_return (invoke "f64x2.pmin" (v128.const f64x2 -0 0) (v128.const f64x2 0 -0)) (v128.const f64x2 -0 0))
+(assert_return (invoke "f64x2.pmin" (v128.const f64x2 nan 5) (v128.const f64x2 5 nan)) (v128.const f64x2 nan 5))
+(assert_return (invoke "f64x2.pmax" (v128.const f64x2 -0 0) (v128.const f64x2 0 -0)) (v128.const f64x2 -0 0))
+(assert_return (invoke "f64x2.pmax" (v128.const f64x2 nan 5) (v128.const f64x2 5 nan)) (v128.const f64x2 nan 5))
+(assert_return (invoke "f64x2.ceil" (v128.const f64x2 -0 0)) (v128.const f64x2 -0 0))
+(assert_return (invoke "f64x2.ceil" (v128.const f64x2 infinity -infinity)) (v128.const f64x2 infinity -infinity))
+(assert_return (invoke "f64x2.ceil" (v128.const f64x2 nan 42)) (v128.const f64x2 nan 42))
+(assert_return (invoke "f64x2.ceil" (v128.const f64x2 0.5 -0.5)) (v128.const f64x2 1 -0))
+(assert_return (invoke "f64x2.ceil" (v128.const f64x2 1.5 -1.5)) (v128.const f64x2 2 -1))
+(assert_return (invoke "f64x2.ceil" (v128.const f64x2 4.2 -4.2)) (v128.const f64x2 5 -4))
+(assert_return (invoke "f64x2.floor" (v128.const f64x2 -0 0)) (v128.const f64x2 -0 0))
+(assert_return (invoke "f64x2.floor" (v128.const f64x2 infinity -infinity)) (v128.const f64x2 infinity -infinity))
+(assert_return (invoke "f64x2.floor" (v128.const f64x2 nan 42)) (v128.const f64x2 nan 42))
+(assert_return (invoke "f64x2.floor" (v128.const f64x2 0.5 -0.5)) (v128.const f64x2 0 -1))
+(assert_return (invoke "f64x2.floor" (v128.const f64x2 1.5 -1.5)) (v128.const f64x2 1 -2))
+(assert_return (invoke "f64x2.floor" (v128.const f64x2 4.2 -4.2)) (v128.const f64x2 4 -5))
+(assert_return (invoke "f64x2.trunc" (v128.const f64x2 -0 0)) (v128.const f64x2 -0 0))
+(assert_return (invoke "f64x2.trunc" (v128.const f64x2 infinity -infinity)) (v128.const f64x2 infinity -infinity))
+(assert_return (invoke "f64x2.trunc" (v128.const f64x2 nan 42)) (v128.const f64x2 nan 42))
+(assert_return (invoke "f64x2.trunc" (v128.const f64x2 0.5 -0.5)) (v128.const f64x2 0 -0))
+(assert_return (invoke "f64x2.trunc" (v128.const f64x2 1.5 -1.5)) (v128.const f64x2 1 -1))
+(assert_return (invoke "f64x2.trunc" (v128.const f64x2 4.2 -4.2)) (v128.const f64x2 4 -4))
+(assert_return (invoke "f64x2.nearest" (v128.const f64x2 -0 0)) (v128.const f64x2 -0 0))
+(assert_return (invoke "f64x2.nearest" (v128.const f64x2 infinity -infinity)) (v128.const f64x2 infinity -infinity))
+(assert_return (invoke "f64x2.nearest" (v128.const f64x2 nan 42)) (v128.const f64x2 nan 42))
+(assert_return (invoke "f64x2.nearest" (v128.const f64x2 0.5 -0.5)) (v128.const f64x2 0 -0))
+(assert_return (invoke "f64x2.nearest" (v128.const f64x2 1.5 -1.5)) (v128.const f64x2 2 -2))
+(assert_return (invoke "f64x2.nearest" (v128.const f64x2 4.2 -4.2)) (v128.const f64x2 4 -4))
+
+;; conversions
+(assert_return (invoke "i32x4.trunc_sat_f32x4_s" (v128.const f32x4 42 nan infinity -infinity)) (v128.const i32x4 42 0 2147483647 -2147483648))
+(assert_return (invoke "i32x4.trunc_sat_f32x4_u" (v128.const f32x4 42 nan infinity -infinity)) (v128.const i32x4 42 0 4294967295 0))
+(assert_return (invoke "i64x2.trunc_sat_f64x2_s" (v128.const f64x2 42 nan)) (v128.const i64x2 42 0))
+(assert_return (invoke "i64x2.trunc_sat_f64x2_s" (v128.const f64x2 infinity -infinity)) (v128.const i64x2 9223372036854775807 -9223372036854775808))
+(assert_return (invoke "i64x2.trunc_sat_f64x2_u" (v128.const f64x2 42 nan)) (v128.const i64x2 42 0))
+(assert_return (invoke "i64x2.trunc_sat_f64x2_u" (v128.const f64x2 infinity -infinity)) (v128.const i64x2 18446744073709551615 0))
+(assert_return (invoke "f32x4.convert_i32x4_s" (v128.const i32x4 0 -1 2147483647 -2147483648)) (v128.const f32x4 0 -1 2147483648 -2147483648))
+(assert_return (invoke "f32x4.convert_i32x4_u" (v128.const i32x4 0 -1 2147483647 -2147483648)) (v128.const f32x4 0 4294967296 2147483648 2147483648))
+(assert_return (invoke "f64x2.convert_i64x2_s" (v128.const i64x2 0 -1)) (v128.const f64x2 0 -1))
+(assert_return (invoke "f64x2.convert_i64x2_s" (v128.const i64x2 9223372036854775807 -9223372036854775808)) (v128.const f64x2 9223372036854775807 -9223372036854775808))
+(assert_return (invoke "f64x2.convert_i64x2_u" (v128.const i64x2 0 -1)) (v128.const f64x2 0 18446744073709551616))
+(assert_return (invoke "f64x2.convert_i64x2_u" (v128.const i64x2 9223372036854775807 -9223372036854775808)) (v128.const f64x2 9223372036854775807 9223372036854775808))
+(assert_return
+  (invoke "i8x16.narrow_i16x8_s"
+    (v128.const i16x8 129 127 -32767 32767 -32768 -1 1 0)
+    (v128.const i16x8 0 1 -1 -32768 32767 -32767 127 129)
+  )
+  (v128.const i8x16 127 127 -128 127 -128 -1 1 0 0 1 -1 -128 127 -128 127 127)
+)
+(assert_return
+  (invoke "i8x16.narrow_i16x8_u"
+    (v128.const i16x8 129 127 -32767 32767 -32768 -1 1 0)
+    (v128.const i16x8 0 1 -1 -32768 32767 -32767 127 129)
+  )
+  (v128.const i8x16 129 127 0 255 0 0 1 0 0 1 0 0 255 0 127 129)
+)
+(assert_return
+  (invoke "i16x8.narrow_i32x4_s"
+    (v128.const i32x4 32769 32767 -2147483647 2147483647)
+    (v128.const i32x4 0 1 -1 -2147483648)
+  )
+  (v128.const i16x8 32767 32767 -32768 32767 0 1 -1 -32768)
+)
+(assert_return
+  (invoke "i16x8.narrow_i32x4_u"
+    (v128.const i32x4 32769 32767 -2147483647 2147483647)
+    (v128.const i32x4 0 1 -1 -2147483648)
+  )
+  (v128.const i16x8 32769 32767 0 65535 0 1 0 0)
+)
+(assert_return
+  (invoke "i16x8.widen_low_i8x16_s"
+    (v128.const i8x16 0 1 -1 -128 127 129 64 -64 -64 64 129 127 -128 -1 1 0)
+  )
+  (v128.const i16x8 0 1 -1 -128 127 -127 64 -64)
+)
+(assert_return
+  (invoke "i16x8.widen_high_i8x16_s"
+    (v128.const i8x16 0 1 -1 -128 127 129 64 -64 -64 64 129 127 -128 -1 1 0)
+  )
+  (v128.const i16x8 -64 64 -127 127 -128 -1 1 0)
+)
+(assert_return
+  (invoke "i16x8.widen_low_i8x16_u"
+    (v128.const i8x16 0 1 -1 -128 127 129 64 -64 -64 64 129 127 -128 -1 1 0)
+  )
+  (v128.const i16x8 0 1 255 128 127 129 64 192)
+)
+(assert_return
+  (invoke "i16x8.widen_high_i8x16_u"
+    (v128.const i8x16 0 1 -1 -128 127 129 64 -64 -64 64 129 127 -128 -1 1 0)
+  )
+  (v128.const i16x8 192 64 129 127 128 255 1 0)
+)
+(assert_return (invoke "i32x4.widen_low_i16x8_s" (v128.const i16x8 0 1 -1 32768 32767 32769 16384 -16384)) (v128.const i32x4 0 1 -1 -32768))
+(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))
+(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))
+(assert_return (invoke "i32x4.load16x4_u" (i32.const 256)) (v128.const i32x4 0x00009080 0x0000b0a0 0x0000d0c0 0x0000f0e0))
+(assert_return (invoke "i64x2.load32x2_s" (i32.const 256)) (v128.const i64x2 0xffffffffb0a09080 0xfffffffff0e0d0c0))
+(assert_return (invoke "i64x2.load32x2_u" (i32.const 256)) (v128.const i64x2 0x00000000b0a09080 0x00000000f0e0d0c0))
+(assert_return (invoke "v128.load32_zero" (i32.const 256)) (v128.const i32x4 0xb0a09080 0 0 0))
+(assert_return (invoke "v128.load64_zero" (i32.const 256)) (v128.const i64x2 0xf0e0d0c0b0a09080 0))
+(assert_return
+  (invoke "v8x16.swizzle"
+    (v128.const i8x16 0xf0 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7 0xf8 0xf9 0xfa 0xfb 0xfc 0xfd 0xfe 0xff)
+    (v128.const i8x16 0 4 8 12 16 255 129 128 127 17 15 13 12 8 4 0)
+  )
+  (v128.const i8x16 0xf0 0xf4 0xf8 0xfc 0x00 0x00 0x00 0x00 0x00 0x00 0xff 0xfd 0xfc 0xf8 0xf4 0xf0)
+)
diff --git a/binaryen/test/spec/skip-stack-guard-page.wast b/binaryen/test/spec/skip-stack-guard-page.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/skip-stack-guard-page.wast
@@ -0,0 +1,2284 @@
+;; This tests that the stack overflow guard page can't be skipped by a function with more than a page of locals.
+(module
+  (memory 1)
+  (export "test-guard-page-skip" (func $test-guard-page-skip))
+
+  (func $test-guard-page-skip
+    (param $depth i32)
+    (if (i32.eq (local.get $depth) (i32.const 0))
+      (then (call $function-with-many-locals))
+      (else (call $test-guard-page-skip (i32.sub (local.get $depth) (i32.const 1))))
+    )
+  )
+
+  (func $function-with-many-locals
+
+    ;; 1056 i64 = 8448 bytes of locals
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x000-0x007
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x008-0x00f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x010-0x017
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x018-0x01f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x020-0x027
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x028-0x02f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x030-0x037
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x038-0x03f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x040-0x047
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x048-0x04f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x050-0x057
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x058-0x05f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x060-0x067
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x068-0x06f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x070-0x077
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x078-0x07f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x080-0x087
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x088-0x08f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x090-0x097
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x098-0x09f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0a0-0x0a7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0a8-0x0af
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0b0-0x0b7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0b8-0x0bf
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0c0-0x0c7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0c8-0x0cf
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0d0-0x0d7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0d8-0x0df
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0e0-0x0e7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0e8-0x0ef
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0f0-0x0f7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0f8-0x0ff
+
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x100-0x107
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x108-0x10f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x110-0x117
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x118-0x11f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x120-0x127
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x128-0x12f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x130-0x137
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x138-0x13f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x140-0x147
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x148-0x14f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x150-0x157
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x158-0x15f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x160-0x167
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x168-0x16f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x170-0x177
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x178-0x17f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x180-0x187
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x188-0x18f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x190-0x197
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x198-0x19f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1a0-0x1a7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1a8-0x1af
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1b0-0x1b7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1b8-0x1bf
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1c0-0x1c7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1c8-0x1cf
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1d0-0x1d7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1d8-0x1df
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1e0-0x1e7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1e8-0x1ef
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1f0-0x1f7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1f8-0x1ff
+
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x200-0x207
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x208-0x20f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x210-0x217
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x218-0x21f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x220-0x227
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x228-0x22f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x230-0x237
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x238-0x23f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x240-0x247
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x248-0x24f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x250-0x257
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x258-0x25f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x260-0x267
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x268-0x26f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x270-0x277
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x278-0x27f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x280-0x287
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x288-0x28f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x290-0x297
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x298-0x29f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2a0-0x2a7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2a8-0x2af
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2b0-0x2b7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2b8-0x2bf
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2c0-0x2c7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2c8-0x2cf
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2d0-0x2d7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2d8-0x2df
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2e0-0x2e7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2e8-0x2ef
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2f0-0x2f7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2f8-0x2ff
+
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x300-0x307
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x308-0x30f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x310-0x317
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x318-0x31f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x320-0x327
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x328-0x32f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x330-0x337
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x338-0x33f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x340-0x347
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x348-0x34f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x350-0x357
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x358-0x35f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x360-0x367
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x368-0x36f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x370-0x377
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x378-0x37f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x380-0x387
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x388-0x38f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x390-0x397
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x398-0x39f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3a0-0x3a7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3a8-0x3af
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3b0-0x3b7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3b8-0x3bf
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3c0-0x3c7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3c8-0x3cf
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3d0-0x3d7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3d8-0x3df
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3e0-0x3e7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3e8-0x3ef
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3f0-0x3f7
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3f8-0x3ff
+
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x400-0x407
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x408-0x40f
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x410-0x417
+    (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x418-0x41f
+
+    ;; recurse first to try to make the callee access the stack below the space allocated for the locals before the locals themselves have been initialized.
+    (call $function-with-many-locals)
+
+    ;; load from memory into the locals
+    (local.set 0x000 (i64.load offset=0x000 align=1 (i32.const 0)))
+    (local.set 0x001 (i64.load offset=0x001 align=1 (i32.const 0)))
+    (local.set 0x002 (i64.load offset=0x002 align=1 (i32.const 0)))
+    (local.set 0x003 (i64.load offset=0x003 align=1 (i32.const 0)))
+    (local.set 0x004 (i64.load offset=0x004 align=1 (i32.const 0)))
+    (local.set 0x005 (i64.load offset=0x005 align=1 (i32.const 0)))
+    (local.set 0x006 (i64.load offset=0x006 align=1 (i32.const 0)))
+    (local.set 0x007 (i64.load offset=0x007 align=1 (i32.const 0)))
+    (local.set 0x008 (i64.load offset=0x008 align=1 (i32.const 0)))
+    (local.set 0x009 (i64.load offset=0x009 align=1 (i32.const 0)))
+    (local.set 0x00a (i64.load offset=0x00a align=1 (i32.const 0)))
+    (local.set 0x00b (i64.load offset=0x00b align=1 (i32.const 0)))
+    (local.set 0x00c (i64.load offset=0x00c align=1 (i32.const 0)))
+    (local.set 0x00d (i64.load offset=0x00d align=1 (i32.const 0)))
+    (local.set 0x00e (i64.load offset=0x00e align=1 (i32.const 0)))
+    (local.set 0x00f (i64.load offset=0x00f align=1 (i32.const 0)))
+    (local.set 0x010 (i64.load offset=0x010 align=1 (i32.const 0)))
+    (local.set 0x011 (i64.load offset=0x011 align=1 (i32.const 0)))
+    (local.set 0x012 (i64.load offset=0x012 align=1 (i32.const 0)))
+    (local.set 0x013 (i64.load offset=0x013 align=1 (i32.const 0)))
+    (local.set 0x014 (i64.load offset=0x014 align=1 (i32.const 0)))
+    (local.set 0x015 (i64.load offset=0x015 align=1 (i32.const 0)))
+    (local.set 0x016 (i64.load offset=0x016 align=1 (i32.const 0)))
+    (local.set 0x017 (i64.load offset=0x017 align=1 (i32.const 0)))
+    (local.set 0x018 (i64.load offset=0x018 align=1 (i32.const 0)))
+    (local.set 0x019 (i64.load offset=0x019 align=1 (i32.const 0)))
+    (local.set 0x01a (i64.load offset=0x01a align=1 (i32.const 0)))
+    (local.set 0x01b (i64.load offset=0x01b align=1 (i32.const 0)))
+    (local.set 0x01c (i64.load offset=0x01c align=1 (i32.const 0)))
+    (local.set 0x01d (i64.load offset=0x01d align=1 (i32.const 0)))
+    (local.set 0x01e (i64.load offset=0x01e align=1 (i32.const 0)))
+    (local.set 0x01f (i64.load offset=0x01f align=1 (i32.const 0)))
+    (local.set 0x020 (i64.load offset=0x020 align=1 (i32.const 0)))
+    (local.set 0x021 (i64.load offset=0x021 align=1 (i32.const 0)))
+    (local.set 0x022 (i64.load offset=0x022 align=1 (i32.const 0)))
+    (local.set 0x023 (i64.load offset=0x023 align=1 (i32.const 0)))
+    (local.set 0x024 (i64.load offset=0x024 align=1 (i32.const 0)))
+    (local.set 0x025 (i64.load offset=0x025 align=1 (i32.const 0)))
+    (local.set 0x026 (i64.load offset=0x026 align=1 (i32.const 0)))
+    (local.set 0x027 (i64.load offset=0x027 align=1 (i32.const 0)))
+    (local.set 0x028 (i64.load offset=0x028 align=1 (i32.const 0)))
+    (local.set 0x029 (i64.load offset=0x029 align=1 (i32.const 0)))
+    (local.set 0x02a (i64.load offset=0x02a align=1 (i32.const 0)))
+    (local.set 0x02b (i64.load offset=0x02b align=1 (i32.const 0)))
+    (local.set 0x02c (i64.load offset=0x02c align=1 (i32.const 0)))
+    (local.set 0x02d (i64.load offset=0x02d align=1 (i32.const 0)))
+    (local.set 0x02e (i64.load offset=0x02e align=1 (i32.const 0)))
+    (local.set 0x02f (i64.load offset=0x02f align=1 (i32.const 0)))
+    (local.set 0x030 (i64.load offset=0x030 align=1 (i32.const 0)))
+    (local.set 0x031 (i64.load offset=0x031 align=1 (i32.const 0)))
+    (local.set 0x032 (i64.load offset=0x032 align=1 (i32.const 0)))
+    (local.set 0x033 (i64.load offset=0x033 align=1 (i32.const 0)))
+    (local.set 0x034 (i64.load offset=0x034 align=1 (i32.const 0)))
+    (local.set 0x035 (i64.load offset=0x035 align=1 (i32.const 0)))
+    (local.set 0x036 (i64.load offset=0x036 align=1 (i32.const 0)))
+    (local.set 0x037 (i64.load offset=0x037 align=1 (i32.const 0)))
+    (local.set 0x038 (i64.load offset=0x038 align=1 (i32.const 0)))
+    (local.set 0x039 (i64.load offset=0x039 align=1 (i32.const 0)))
+    (local.set 0x03a (i64.load offset=0x03a align=1 (i32.const 0)))
+    (local.set 0x03b (i64.load offset=0x03b align=1 (i32.const 0)))
+    (local.set 0x03c (i64.load offset=0x03c align=1 (i32.const 0)))
+    (local.set 0x03d (i64.load offset=0x03d align=1 (i32.const 0)))
+    (local.set 0x03e (i64.load offset=0x03e align=1 (i32.const 0)))
+    (local.set 0x03f (i64.load offset=0x03f align=1 (i32.const 0)))
+    (local.set 0x040 (i64.load offset=0x040 align=1 (i32.const 0)))
+    (local.set 0x041 (i64.load offset=0x041 align=1 (i32.const 0)))
+    (local.set 0x042 (i64.load offset=0x042 align=1 (i32.const 0)))
+    (local.set 0x043 (i64.load offset=0x043 align=1 (i32.const 0)))
+    (local.set 0x044 (i64.load offset=0x044 align=1 (i32.const 0)))
+    (local.set 0x045 (i64.load offset=0x045 align=1 (i32.const 0)))
+    (local.set 0x046 (i64.load offset=0x046 align=1 (i32.const 0)))
+    (local.set 0x047 (i64.load offset=0x047 align=1 (i32.const 0)))
+    (local.set 0x048 (i64.load offset=0x048 align=1 (i32.const 0)))
+    (local.set 0x049 (i64.load offset=0x049 align=1 (i32.const 0)))
+    (local.set 0x04a (i64.load offset=0x04a align=1 (i32.const 0)))
+    (local.set 0x04b (i64.load offset=0x04b align=1 (i32.const 0)))
+    (local.set 0x04c (i64.load offset=0x04c align=1 (i32.const 0)))
+    (local.set 0x04d (i64.load offset=0x04d align=1 (i32.const 0)))
+    (local.set 0x04e (i64.load offset=0x04e align=1 (i32.const 0)))
+    (local.set 0x04f (i64.load offset=0x04f align=1 (i32.const 0)))
+    (local.set 0x050 (i64.load offset=0x050 align=1 (i32.const 0)))
+    (local.set 0x051 (i64.load offset=0x051 align=1 (i32.const 0)))
+    (local.set 0x052 (i64.load offset=0x052 align=1 (i32.const 0)))
+    (local.set 0x053 (i64.load offset=0x053 align=1 (i32.const 0)))
+    (local.set 0x054 (i64.load offset=0x054 align=1 (i32.const 0)))
+    (local.set 0x055 (i64.load offset=0x055 align=1 (i32.const 0)))
+    (local.set 0x056 (i64.load offset=0x056 align=1 (i32.const 0)))
+    (local.set 0x057 (i64.load offset=0x057 align=1 (i32.const 0)))
+    (local.set 0x058 (i64.load offset=0x058 align=1 (i32.const 0)))
+    (local.set 0x059 (i64.load offset=0x059 align=1 (i32.const 0)))
+    (local.set 0x05a (i64.load offset=0x05a align=1 (i32.const 0)))
+    (local.set 0x05b (i64.load offset=0x05b align=1 (i32.const 0)))
+    (local.set 0x05c (i64.load offset=0x05c align=1 (i32.const 0)))
+    (local.set 0x05d (i64.load offset=0x05d align=1 (i32.const 0)))
+    (local.set 0x05e (i64.load offset=0x05e align=1 (i32.const 0)))
+    (local.set 0x05f (i64.load offset=0x05f align=1 (i32.const 0)))
+    (local.set 0x060 (i64.load offset=0x060 align=1 (i32.const 0)))
+    (local.set 0x061 (i64.load offset=0x061 align=1 (i32.const 0)))
+    (local.set 0x062 (i64.load offset=0x062 align=1 (i32.const 0)))
+    (local.set 0x063 (i64.load offset=0x063 align=1 (i32.const 0)))
+    (local.set 0x064 (i64.load offset=0x064 align=1 (i32.const 0)))
+    (local.set 0x065 (i64.load offset=0x065 align=1 (i32.const 0)))
+    (local.set 0x066 (i64.load offset=0x066 align=1 (i32.const 0)))
+    (local.set 0x067 (i64.load offset=0x067 align=1 (i32.const 0)))
+    (local.set 0x068 (i64.load offset=0x068 align=1 (i32.const 0)))
+    (local.set 0x069 (i64.load offset=0x069 align=1 (i32.const 0)))
+    (local.set 0x06a (i64.load offset=0x06a align=1 (i32.const 0)))
+    (local.set 0x06b (i64.load offset=0x06b align=1 (i32.const 0)))
+    (local.set 0x06c (i64.load offset=0x06c align=1 (i32.const 0)))
+    (local.set 0x06d (i64.load offset=0x06d align=1 (i32.const 0)))
+    (local.set 0x06e (i64.load offset=0x06e align=1 (i32.const 0)))
+    (local.set 0x06f (i64.load offset=0x06f align=1 (i32.const 0)))
+    (local.set 0x070 (i64.load offset=0x070 align=1 (i32.const 0)))
+    (local.set 0x071 (i64.load offset=0x071 align=1 (i32.const 0)))
+    (local.set 0x072 (i64.load offset=0x072 align=1 (i32.const 0)))
+    (local.set 0x073 (i64.load offset=0x073 align=1 (i32.const 0)))
+    (local.set 0x074 (i64.load offset=0x074 align=1 (i32.const 0)))
+    (local.set 0x075 (i64.load offset=0x075 align=1 (i32.const 0)))
+    (local.set 0x076 (i64.load offset=0x076 align=1 (i32.const 0)))
+    (local.set 0x077 (i64.load offset=0x077 align=1 (i32.const 0)))
+    (local.set 0x078 (i64.load offset=0x078 align=1 (i32.const 0)))
+    (local.set 0x079 (i64.load offset=0x079 align=1 (i32.const 0)))
+    (local.set 0x07a (i64.load offset=0x07a align=1 (i32.const 0)))
+    (local.set 0x07b (i64.load offset=0x07b align=1 (i32.const 0)))
+    (local.set 0x07c (i64.load offset=0x07c align=1 (i32.const 0)))
+    (local.set 0x07d (i64.load offset=0x07d align=1 (i32.const 0)))
+    (local.set 0x07e (i64.load offset=0x07e align=1 (i32.const 0)))
+    (local.set 0x07f (i64.load offset=0x07f align=1 (i32.const 0)))
+    (local.set 0x080 (i64.load offset=0x080 align=1 (i32.const 0)))
+    (local.set 0x081 (i64.load offset=0x081 align=1 (i32.const 0)))
+    (local.set 0x082 (i64.load offset=0x082 align=1 (i32.const 0)))
+    (local.set 0x083 (i64.load offset=0x083 align=1 (i32.const 0)))
+    (local.set 0x084 (i64.load offset=0x084 align=1 (i32.const 0)))
+    (local.set 0x085 (i64.load offset=0x085 align=1 (i32.const 0)))
+    (local.set 0x086 (i64.load offset=0x086 align=1 (i32.const 0)))
+    (local.set 0x087 (i64.load offset=0x087 align=1 (i32.const 0)))
+    (local.set 0x088 (i64.load offset=0x088 align=1 (i32.const 0)))
+    (local.set 0x089 (i64.load offset=0x089 align=1 (i32.const 0)))
+    (local.set 0x08a (i64.load offset=0x08a align=1 (i32.const 0)))
+    (local.set 0x08b (i64.load offset=0x08b align=1 (i32.const 0)))
+    (local.set 0x08c (i64.load offset=0x08c align=1 (i32.const 0)))
+    (local.set 0x08d (i64.load offset=0x08d align=1 (i32.const 0)))
+    (local.set 0x08e (i64.load offset=0x08e align=1 (i32.const 0)))
+    (local.set 0x08f (i64.load offset=0x08f align=1 (i32.const 0)))
+    (local.set 0x090 (i64.load offset=0x090 align=1 (i32.const 0)))
+    (local.set 0x091 (i64.load offset=0x091 align=1 (i32.const 0)))
+    (local.set 0x092 (i64.load offset=0x092 align=1 (i32.const 0)))
+    (local.set 0x093 (i64.load offset=0x093 align=1 (i32.const 0)))
+    (local.set 0x094 (i64.load offset=0x094 align=1 (i32.const 0)))
+    (local.set 0x095 (i64.load offset=0x095 align=1 (i32.const 0)))
+    (local.set 0x096 (i64.load offset=0x096 align=1 (i32.const 0)))
+    (local.set 0x097 (i64.load offset=0x097 align=1 (i32.const 0)))
+    (local.set 0x098 (i64.load offset=0x098 align=1 (i32.const 0)))
+    (local.set 0x099 (i64.load offset=0x099 align=1 (i32.const 0)))
+    (local.set 0x09a (i64.load offset=0x09a align=1 (i32.const 0)))
+    (local.set 0x09b (i64.load offset=0x09b align=1 (i32.const 0)))
+    (local.set 0x09c (i64.load offset=0x09c align=1 (i32.const 0)))
+    (local.set 0x09d (i64.load offset=0x09d align=1 (i32.const 0)))
+    (local.set 0x09e (i64.load offset=0x09e align=1 (i32.const 0)))
+    (local.set 0x09f (i64.load offset=0x09f align=1 (i32.const 0)))
+    (local.set 0x0a0 (i64.load offset=0x0a0 align=1 (i32.const 0)))
+    (local.set 0x0a1 (i64.load offset=0x0a1 align=1 (i32.const 0)))
+    (local.set 0x0a2 (i64.load offset=0x0a2 align=1 (i32.const 0)))
+    (local.set 0x0a3 (i64.load offset=0x0a3 align=1 (i32.const 0)))
+    (local.set 0x0a4 (i64.load offset=0x0a4 align=1 (i32.const 0)))
+    (local.set 0x0a5 (i64.load offset=0x0a5 align=1 (i32.const 0)))
+    (local.set 0x0a6 (i64.load offset=0x0a6 align=1 (i32.const 0)))
+    (local.set 0x0a7 (i64.load offset=0x0a7 align=1 (i32.const 0)))
+    (local.set 0x0a8 (i64.load offset=0x0a8 align=1 (i32.const 0)))
+    (local.set 0x0a9 (i64.load offset=0x0a9 align=1 (i32.const 0)))
+    (local.set 0x0aa (i64.load offset=0x0aa align=1 (i32.const 0)))
+    (local.set 0x0ab (i64.load offset=0x0ab align=1 (i32.const 0)))
+    (local.set 0x0ac (i64.load offset=0x0ac align=1 (i32.const 0)))
+    (local.set 0x0ad (i64.load offset=0x0ad align=1 (i32.const 0)))
+    (local.set 0x0ae (i64.load offset=0x0ae align=1 (i32.const 0)))
+    (local.set 0x0af (i64.load offset=0x0af align=1 (i32.const 0)))
+    (local.set 0x0b0 (i64.load offset=0x0b0 align=1 (i32.const 0)))
+    (local.set 0x0b1 (i64.load offset=0x0b1 align=1 (i32.const 0)))
+    (local.set 0x0b2 (i64.load offset=0x0b2 align=1 (i32.const 0)))
+    (local.set 0x0b3 (i64.load offset=0x0b3 align=1 (i32.const 0)))
+    (local.set 0x0b4 (i64.load offset=0x0b4 align=1 (i32.const 0)))
+    (local.set 0x0b5 (i64.load offset=0x0b5 align=1 (i32.const 0)))
+    (local.set 0x0b6 (i64.load offset=0x0b6 align=1 (i32.const 0)))
+    (local.set 0x0b7 (i64.load offset=0x0b7 align=1 (i32.const 0)))
+    (local.set 0x0b8 (i64.load offset=0x0b8 align=1 (i32.const 0)))
+    (local.set 0x0b9 (i64.load offset=0x0b9 align=1 (i32.const 0)))
+    (local.set 0x0ba (i64.load offset=0x0ba align=1 (i32.const 0)))
+    (local.set 0x0bb (i64.load offset=0x0bb align=1 (i32.const 0)))
+    (local.set 0x0bc (i64.load offset=0x0bc align=1 (i32.const 0)))
+    (local.set 0x0bd (i64.load offset=0x0bd align=1 (i32.const 0)))
+    (local.set 0x0be (i64.load offset=0x0be align=1 (i32.const 0)))
+    (local.set 0x0bf (i64.load offset=0x0bf align=1 (i32.const 0)))
+    (local.set 0x0c0 (i64.load offset=0x0c0 align=1 (i32.const 0)))
+    (local.set 0x0c1 (i64.load offset=0x0c1 align=1 (i32.const 0)))
+    (local.set 0x0c2 (i64.load offset=0x0c2 align=1 (i32.const 0)))
+    (local.set 0x0c3 (i64.load offset=0x0c3 align=1 (i32.const 0)))
+    (local.set 0x0c4 (i64.load offset=0x0c4 align=1 (i32.const 0)))
+    (local.set 0x0c5 (i64.load offset=0x0c5 align=1 (i32.const 0)))
+    (local.set 0x0c6 (i64.load offset=0x0c6 align=1 (i32.const 0)))
+    (local.set 0x0c7 (i64.load offset=0x0c7 align=1 (i32.const 0)))
+    (local.set 0x0c8 (i64.load offset=0x0c8 align=1 (i32.const 0)))
+    (local.set 0x0c9 (i64.load offset=0x0c9 align=1 (i32.const 0)))
+    (local.set 0x0ca (i64.load offset=0x0ca align=1 (i32.const 0)))
+    (local.set 0x0cb (i64.load offset=0x0cb align=1 (i32.const 0)))
+    (local.set 0x0cc (i64.load offset=0x0cc align=1 (i32.const 0)))
+    (local.set 0x0cd (i64.load offset=0x0cd align=1 (i32.const 0)))
+    (local.set 0x0ce (i64.load offset=0x0ce align=1 (i32.const 0)))
+    (local.set 0x0cf (i64.load offset=0x0cf align=1 (i32.const 0)))
+    (local.set 0x0d0 (i64.load offset=0x0d0 align=1 (i32.const 0)))
+    (local.set 0x0d1 (i64.load offset=0x0d1 align=1 (i32.const 0)))
+    (local.set 0x0d2 (i64.load offset=0x0d2 align=1 (i32.const 0)))
+    (local.set 0x0d3 (i64.load offset=0x0d3 align=1 (i32.const 0)))
+    (local.set 0x0d4 (i64.load offset=0x0d4 align=1 (i32.const 0)))
+    (local.set 0x0d5 (i64.load offset=0x0d5 align=1 (i32.const 0)))
+    (local.set 0x0d6 (i64.load offset=0x0d6 align=1 (i32.const 0)))
+    (local.set 0x0d7 (i64.load offset=0x0d7 align=1 (i32.const 0)))
+    (local.set 0x0d8 (i64.load offset=0x0d8 align=1 (i32.const 0)))
+    (local.set 0x0d9 (i64.load offset=0x0d9 align=1 (i32.const 0)))
+    (local.set 0x0da (i64.load offset=0x0da align=1 (i32.const 0)))
+    (local.set 0x0db (i64.load offset=0x0db align=1 (i32.const 0)))
+    (local.set 0x0dc (i64.load offset=0x0dc align=1 (i32.const 0)))
+    (local.set 0x0dd (i64.load offset=0x0dd align=1 (i32.const 0)))
+    (local.set 0x0de (i64.load offset=0x0de align=1 (i32.const 0)))
+    (local.set 0x0df (i64.load offset=0x0df align=1 (i32.const 0)))
+    (local.set 0x0e0 (i64.load offset=0x0e0 align=1 (i32.const 0)))
+    (local.set 0x0e1 (i64.load offset=0x0e1 align=1 (i32.const 0)))
+    (local.set 0x0e2 (i64.load offset=0x0e2 align=1 (i32.const 0)))
+    (local.set 0x0e3 (i64.load offset=0x0e3 align=1 (i32.const 0)))
+    (local.set 0x0e4 (i64.load offset=0x0e4 align=1 (i32.const 0)))
+    (local.set 0x0e5 (i64.load offset=0x0e5 align=1 (i32.const 0)))
+    (local.set 0x0e6 (i64.load offset=0x0e6 align=1 (i32.const 0)))
+    (local.set 0x0e7 (i64.load offset=0x0e7 align=1 (i32.const 0)))
+    (local.set 0x0e8 (i64.load offset=0x0e8 align=1 (i32.const 0)))
+    (local.set 0x0e9 (i64.load offset=0x0e9 align=1 (i32.const 0)))
+    (local.set 0x0ea (i64.load offset=0x0ea align=1 (i32.const 0)))
+    (local.set 0x0eb (i64.load offset=0x0eb align=1 (i32.const 0)))
+    (local.set 0x0ec (i64.load offset=0x0ec align=1 (i32.const 0)))
+    (local.set 0x0ed (i64.load offset=0x0ed align=1 (i32.const 0)))
+    (local.set 0x0ee (i64.load offset=0x0ee align=1 (i32.const 0)))
+    (local.set 0x0ef (i64.load offset=0x0ef align=1 (i32.const 0)))
+    (local.set 0x0f0 (i64.load offset=0x0f0 align=1 (i32.const 0)))
+    (local.set 0x0f1 (i64.load offset=0x0f1 align=1 (i32.const 0)))
+    (local.set 0x0f2 (i64.load offset=0x0f2 align=1 (i32.const 0)))
+    (local.set 0x0f3 (i64.load offset=0x0f3 align=1 (i32.const 0)))
+    (local.set 0x0f4 (i64.load offset=0x0f4 align=1 (i32.const 0)))
+    (local.set 0x0f5 (i64.load offset=0x0f5 align=1 (i32.const 0)))
+    (local.set 0x0f6 (i64.load offset=0x0f6 align=1 (i32.const 0)))
+    (local.set 0x0f7 (i64.load offset=0x0f7 align=1 (i32.const 0)))
+    (local.set 0x0f8 (i64.load offset=0x0f8 align=1 (i32.const 0)))
+    (local.set 0x0f9 (i64.load offset=0x0f9 align=1 (i32.const 0)))
+    (local.set 0x0fa (i64.load offset=0x0fa align=1 (i32.const 0)))
+    (local.set 0x0fb (i64.load offset=0x0fb align=1 (i32.const 0)))
+    (local.set 0x0fc (i64.load offset=0x0fc align=1 (i32.const 0)))
+    (local.set 0x0fd (i64.load offset=0x0fd align=1 (i32.const 0)))
+    (local.set 0x0fe (i64.load offset=0x0fe align=1 (i32.const 0)))
+    (local.set 0x0ff (i64.load offset=0x0ff align=1 (i32.const 0)))
+    (local.set 0x100 (i64.load offset=0x100 align=1 (i32.const 0)))
+    (local.set 0x101 (i64.load offset=0x101 align=1 (i32.const 0)))
+    (local.set 0x102 (i64.load offset=0x102 align=1 (i32.const 0)))
+    (local.set 0x103 (i64.load offset=0x103 align=1 (i32.const 0)))
+    (local.set 0x104 (i64.load offset=0x104 align=1 (i32.const 0)))
+    (local.set 0x105 (i64.load offset=0x105 align=1 (i32.const 0)))
+    (local.set 0x106 (i64.load offset=0x106 align=1 (i32.const 0)))
+    (local.set 0x107 (i64.load offset=0x107 align=1 (i32.const 0)))
+    (local.set 0x108 (i64.load offset=0x108 align=1 (i32.const 0)))
+    (local.set 0x109 (i64.load offset=0x109 align=1 (i32.const 0)))
+    (local.set 0x10a (i64.load offset=0x10a align=1 (i32.const 0)))
+    (local.set 0x10b (i64.load offset=0x10b align=1 (i32.const 0)))
+    (local.set 0x10c (i64.load offset=0x10c align=1 (i32.const 0)))
+    (local.set 0x10d (i64.load offset=0x10d align=1 (i32.const 0)))
+    (local.set 0x10e (i64.load offset=0x10e align=1 (i32.const 0)))
+    (local.set 0x10f (i64.load offset=0x10f align=1 (i32.const 0)))
+    (local.set 0x110 (i64.load offset=0x110 align=1 (i32.const 0)))
+    (local.set 0x111 (i64.load offset=0x111 align=1 (i32.const 0)))
+    (local.set 0x112 (i64.load offset=0x112 align=1 (i32.const 0)))
+    (local.set 0x113 (i64.load offset=0x113 align=1 (i32.const 0)))
+    (local.set 0x114 (i64.load offset=0x114 align=1 (i32.const 0)))
+    (local.set 0x115 (i64.load offset=0x115 align=1 (i32.const 0)))
+    (local.set 0x116 (i64.load offset=0x116 align=1 (i32.const 0)))
+    (local.set 0x117 (i64.load offset=0x117 align=1 (i32.const 0)))
+    (local.set 0x118 (i64.load offset=0x118 align=1 (i32.const 0)))
+    (local.set 0x119 (i64.load offset=0x119 align=1 (i32.const 0)))
+    (local.set 0x11a (i64.load offset=0x11a align=1 (i32.const 0)))
+    (local.set 0x11b (i64.load offset=0x11b align=1 (i32.const 0)))
+    (local.set 0x11c (i64.load offset=0x11c align=1 (i32.const 0)))
+    (local.set 0x11d (i64.load offset=0x11d align=1 (i32.const 0)))
+    (local.set 0x11e (i64.load offset=0x11e align=1 (i32.const 0)))
+    (local.set 0x11f (i64.load offset=0x11f align=1 (i32.const 0)))
+    (local.set 0x120 (i64.load offset=0x120 align=1 (i32.const 0)))
+    (local.set 0x121 (i64.load offset=0x121 align=1 (i32.const 0)))
+    (local.set 0x122 (i64.load offset=0x122 align=1 (i32.const 0)))
+    (local.set 0x123 (i64.load offset=0x123 align=1 (i32.const 0)))
+    (local.set 0x124 (i64.load offset=0x124 align=1 (i32.const 0)))
+    (local.set 0x125 (i64.load offset=0x125 align=1 (i32.const 0)))
+    (local.set 0x126 (i64.load offset=0x126 align=1 (i32.const 0)))
+    (local.set 0x127 (i64.load offset=0x127 align=1 (i32.const 0)))
+    (local.set 0x128 (i64.load offset=0x128 align=1 (i32.const 0)))
+    (local.set 0x129 (i64.load offset=0x129 align=1 (i32.const 0)))
+    (local.set 0x12a (i64.load offset=0x12a align=1 (i32.const 0)))
+    (local.set 0x12b (i64.load offset=0x12b align=1 (i32.const 0)))
+    (local.set 0x12c (i64.load offset=0x12c align=1 (i32.const 0)))
+    (local.set 0x12d (i64.load offset=0x12d align=1 (i32.const 0)))
+    (local.set 0x12e (i64.load offset=0x12e align=1 (i32.const 0)))
+    (local.set 0x12f (i64.load offset=0x12f align=1 (i32.const 0)))
+    (local.set 0x130 (i64.load offset=0x130 align=1 (i32.const 0)))
+    (local.set 0x131 (i64.load offset=0x131 align=1 (i32.const 0)))
+    (local.set 0x132 (i64.load offset=0x132 align=1 (i32.const 0)))
+    (local.set 0x133 (i64.load offset=0x133 align=1 (i32.const 0)))
+    (local.set 0x134 (i64.load offset=0x134 align=1 (i32.const 0)))
+    (local.set 0x135 (i64.load offset=0x135 align=1 (i32.const 0)))
+    (local.set 0x136 (i64.load offset=0x136 align=1 (i32.const 0)))
+    (local.set 0x137 (i64.load offset=0x137 align=1 (i32.const 0)))
+    (local.set 0x138 (i64.load offset=0x138 align=1 (i32.const 0)))
+    (local.set 0x139 (i64.load offset=0x139 align=1 (i32.const 0)))
+    (local.set 0x13a (i64.load offset=0x13a align=1 (i32.const 0)))
+    (local.set 0x13b (i64.load offset=0x13b align=1 (i32.const 0)))
+    (local.set 0x13c (i64.load offset=0x13c align=1 (i32.const 0)))
+    (local.set 0x13d (i64.load offset=0x13d align=1 (i32.const 0)))
+    (local.set 0x13e (i64.load offset=0x13e align=1 (i32.const 0)))
+    (local.set 0x13f (i64.load offset=0x13f align=1 (i32.const 0)))
+    (local.set 0x140 (i64.load offset=0x140 align=1 (i32.const 0)))
+    (local.set 0x141 (i64.load offset=0x141 align=1 (i32.const 0)))
+    (local.set 0x142 (i64.load offset=0x142 align=1 (i32.const 0)))
+    (local.set 0x143 (i64.load offset=0x143 align=1 (i32.const 0)))
+    (local.set 0x144 (i64.load offset=0x144 align=1 (i32.const 0)))
+    (local.set 0x145 (i64.load offset=0x145 align=1 (i32.const 0)))
+    (local.set 0x146 (i64.load offset=0x146 align=1 (i32.const 0)))
+    (local.set 0x147 (i64.load offset=0x147 align=1 (i32.const 0)))
+    (local.set 0x148 (i64.load offset=0x148 align=1 (i32.const 0)))
+    (local.set 0x149 (i64.load offset=0x149 align=1 (i32.const 0)))
+    (local.set 0x14a (i64.load offset=0x14a align=1 (i32.const 0)))
+    (local.set 0x14b (i64.load offset=0x14b align=1 (i32.const 0)))
+    (local.set 0x14c (i64.load offset=0x14c align=1 (i32.const 0)))
+    (local.set 0x14d (i64.load offset=0x14d align=1 (i32.const 0)))
+    (local.set 0x14e (i64.load offset=0x14e align=1 (i32.const 0)))
+    (local.set 0x14f (i64.load offset=0x14f align=1 (i32.const 0)))
+    (local.set 0x150 (i64.load offset=0x150 align=1 (i32.const 0)))
+    (local.set 0x151 (i64.load offset=0x151 align=1 (i32.const 0)))
+    (local.set 0x152 (i64.load offset=0x152 align=1 (i32.const 0)))
+    (local.set 0x153 (i64.load offset=0x153 align=1 (i32.const 0)))
+    (local.set 0x154 (i64.load offset=0x154 align=1 (i32.const 0)))
+    (local.set 0x155 (i64.load offset=0x155 align=1 (i32.const 0)))
+    (local.set 0x156 (i64.load offset=0x156 align=1 (i32.const 0)))
+    (local.set 0x157 (i64.load offset=0x157 align=1 (i32.const 0)))
+    (local.set 0x158 (i64.load offset=0x158 align=1 (i32.const 0)))
+    (local.set 0x159 (i64.load offset=0x159 align=1 (i32.const 0)))
+    (local.set 0x15a (i64.load offset=0x15a align=1 (i32.const 0)))
+    (local.set 0x15b (i64.load offset=0x15b align=1 (i32.const 0)))
+    (local.set 0x15c (i64.load offset=0x15c align=1 (i32.const 0)))
+    (local.set 0x15d (i64.load offset=0x15d align=1 (i32.const 0)))
+    (local.set 0x15e (i64.load offset=0x15e align=1 (i32.const 0)))
+    (local.set 0x15f (i64.load offset=0x15f align=1 (i32.const 0)))
+    (local.set 0x160 (i64.load offset=0x160 align=1 (i32.const 0)))
+    (local.set 0x161 (i64.load offset=0x161 align=1 (i32.const 0)))
+    (local.set 0x162 (i64.load offset=0x162 align=1 (i32.const 0)))
+    (local.set 0x163 (i64.load offset=0x163 align=1 (i32.const 0)))
+    (local.set 0x164 (i64.load offset=0x164 align=1 (i32.const 0)))
+    (local.set 0x165 (i64.load offset=0x165 align=1 (i32.const 0)))
+    (local.set 0x166 (i64.load offset=0x166 align=1 (i32.const 0)))
+    (local.set 0x167 (i64.load offset=0x167 align=1 (i32.const 0)))
+    (local.set 0x168 (i64.load offset=0x168 align=1 (i32.const 0)))
+    (local.set 0x169 (i64.load offset=0x169 align=1 (i32.const 0)))
+    (local.set 0x16a (i64.load offset=0x16a align=1 (i32.const 0)))
+    (local.set 0x16b (i64.load offset=0x16b align=1 (i32.const 0)))
+    (local.set 0x16c (i64.load offset=0x16c align=1 (i32.const 0)))
+    (local.set 0x16d (i64.load offset=0x16d align=1 (i32.const 0)))
+    (local.set 0x16e (i64.load offset=0x16e align=1 (i32.const 0)))
+    (local.set 0x16f (i64.load offset=0x16f align=1 (i32.const 0)))
+    (local.set 0x170 (i64.load offset=0x170 align=1 (i32.const 0)))
+    (local.set 0x171 (i64.load offset=0x171 align=1 (i32.const 0)))
+    (local.set 0x172 (i64.load offset=0x172 align=1 (i32.const 0)))
+    (local.set 0x173 (i64.load offset=0x173 align=1 (i32.const 0)))
+    (local.set 0x174 (i64.load offset=0x174 align=1 (i32.const 0)))
+    (local.set 0x175 (i64.load offset=0x175 align=1 (i32.const 0)))
+    (local.set 0x176 (i64.load offset=0x176 align=1 (i32.const 0)))
+    (local.set 0x177 (i64.load offset=0x177 align=1 (i32.const 0)))
+    (local.set 0x178 (i64.load offset=0x178 align=1 (i32.const 0)))
+    (local.set 0x179 (i64.load offset=0x179 align=1 (i32.const 0)))
+    (local.set 0x17a (i64.load offset=0x17a align=1 (i32.const 0)))
+    (local.set 0x17b (i64.load offset=0x17b align=1 (i32.const 0)))
+    (local.set 0x17c (i64.load offset=0x17c align=1 (i32.const 0)))
+    (local.set 0x17d (i64.load offset=0x17d align=1 (i32.const 0)))
+    (local.set 0x17e (i64.load offset=0x17e align=1 (i32.const 0)))
+    (local.set 0x17f (i64.load offset=0x17f align=1 (i32.const 0)))
+    (local.set 0x180 (i64.load offset=0x180 align=1 (i32.const 0)))
+    (local.set 0x181 (i64.load offset=0x181 align=1 (i32.const 0)))
+    (local.set 0x182 (i64.load offset=0x182 align=1 (i32.const 0)))
+    (local.set 0x183 (i64.load offset=0x183 align=1 (i32.const 0)))
+    (local.set 0x184 (i64.load offset=0x184 align=1 (i32.const 0)))
+    (local.set 0x185 (i64.load offset=0x185 align=1 (i32.const 0)))
+    (local.set 0x186 (i64.load offset=0x186 align=1 (i32.const 0)))
+    (local.set 0x187 (i64.load offset=0x187 align=1 (i32.const 0)))
+    (local.set 0x188 (i64.load offset=0x188 align=1 (i32.const 0)))
+    (local.set 0x189 (i64.load offset=0x189 align=1 (i32.const 0)))
+    (local.set 0x18a (i64.load offset=0x18a align=1 (i32.const 0)))
+    (local.set 0x18b (i64.load offset=0x18b align=1 (i32.const 0)))
+    (local.set 0x18c (i64.load offset=0x18c align=1 (i32.const 0)))
+    (local.set 0x18d (i64.load offset=0x18d align=1 (i32.const 0)))
+    (local.set 0x18e (i64.load offset=0x18e align=1 (i32.const 0)))
+    (local.set 0x18f (i64.load offset=0x18f align=1 (i32.const 0)))
+    (local.set 0x190 (i64.load offset=0x190 align=1 (i32.const 0)))
+    (local.set 0x191 (i64.load offset=0x191 align=1 (i32.const 0)))
+    (local.set 0x192 (i64.load offset=0x192 align=1 (i32.const 0)))
+    (local.set 0x193 (i64.load offset=0x193 align=1 (i32.const 0)))
+    (local.set 0x194 (i64.load offset=0x194 align=1 (i32.const 0)))
+    (local.set 0x195 (i64.load offset=0x195 align=1 (i32.const 0)))
+    (local.set 0x196 (i64.load offset=0x196 align=1 (i32.const 0)))
+    (local.set 0x197 (i64.load offset=0x197 align=1 (i32.const 0)))
+    (local.set 0x198 (i64.load offset=0x198 align=1 (i32.const 0)))
+    (local.set 0x199 (i64.load offset=0x199 align=1 (i32.const 0)))
+    (local.set 0x19a (i64.load offset=0x19a align=1 (i32.const 0)))
+    (local.set 0x19b (i64.load offset=0x19b align=1 (i32.const 0)))
+    (local.set 0x19c (i64.load offset=0x19c align=1 (i32.const 0)))
+    (local.set 0x19d (i64.load offset=0x19d align=1 (i32.const 0)))
+    (local.set 0x19e (i64.load offset=0x19e align=1 (i32.const 0)))
+    (local.set 0x19f (i64.load offset=0x19f align=1 (i32.const 0)))
+    (local.set 0x1a0 (i64.load offset=0x1a0 align=1 (i32.const 0)))
+    (local.set 0x1a1 (i64.load offset=0x1a1 align=1 (i32.const 0)))
+    (local.set 0x1a2 (i64.load offset=0x1a2 align=1 (i32.const 0)))
+    (local.set 0x1a3 (i64.load offset=0x1a3 align=1 (i32.const 0)))
+    (local.set 0x1a4 (i64.load offset=0x1a4 align=1 (i32.const 0)))
+    (local.set 0x1a5 (i64.load offset=0x1a5 align=1 (i32.const 0)))
+    (local.set 0x1a6 (i64.load offset=0x1a6 align=1 (i32.const 0)))
+    (local.set 0x1a7 (i64.load offset=0x1a7 align=1 (i32.const 0)))
+    (local.set 0x1a8 (i64.load offset=0x1a8 align=1 (i32.const 0)))
+    (local.set 0x1a9 (i64.load offset=0x1a9 align=1 (i32.const 0)))
+    (local.set 0x1aa (i64.load offset=0x1aa align=1 (i32.const 0)))
+    (local.set 0x1ab (i64.load offset=0x1ab align=1 (i32.const 0)))
+    (local.set 0x1ac (i64.load offset=0x1ac align=1 (i32.const 0)))
+    (local.set 0x1ad (i64.load offset=0x1ad align=1 (i32.const 0)))
+    (local.set 0x1ae (i64.load offset=0x1ae align=1 (i32.const 0)))
+    (local.set 0x1af (i64.load offset=0x1af align=1 (i32.const 0)))
+    (local.set 0x1b0 (i64.load offset=0x1b0 align=1 (i32.const 0)))
+    (local.set 0x1b1 (i64.load offset=0x1b1 align=1 (i32.const 0)))
+    (local.set 0x1b2 (i64.load offset=0x1b2 align=1 (i32.const 0)))
+    (local.set 0x1b3 (i64.load offset=0x1b3 align=1 (i32.const 0)))
+    (local.set 0x1b4 (i64.load offset=0x1b4 align=1 (i32.const 0)))
+    (local.set 0x1b5 (i64.load offset=0x1b5 align=1 (i32.const 0)))
+    (local.set 0x1b6 (i64.load offset=0x1b6 align=1 (i32.const 0)))
+    (local.set 0x1b7 (i64.load offset=0x1b7 align=1 (i32.const 0)))
+    (local.set 0x1b8 (i64.load offset=0x1b8 align=1 (i32.const 0)))
+    (local.set 0x1b9 (i64.load offset=0x1b9 align=1 (i32.const 0)))
+    (local.set 0x1ba (i64.load offset=0x1ba align=1 (i32.const 0)))
+    (local.set 0x1bb (i64.load offset=0x1bb align=1 (i32.const 0)))
+    (local.set 0x1bc (i64.load offset=0x1bc align=1 (i32.const 0)))
+    (local.set 0x1bd (i64.load offset=0x1bd align=1 (i32.const 0)))
+    (local.set 0x1be (i64.load offset=0x1be align=1 (i32.const 0)))
+    (local.set 0x1bf (i64.load offset=0x1bf align=1 (i32.const 0)))
+    (local.set 0x1c0 (i64.load offset=0x1c0 align=1 (i32.const 0)))
+    (local.set 0x1c1 (i64.load offset=0x1c1 align=1 (i32.const 0)))
+    (local.set 0x1c2 (i64.load offset=0x1c2 align=1 (i32.const 0)))
+    (local.set 0x1c3 (i64.load offset=0x1c3 align=1 (i32.const 0)))
+    (local.set 0x1c4 (i64.load offset=0x1c4 align=1 (i32.const 0)))
+    (local.set 0x1c5 (i64.load offset=0x1c5 align=1 (i32.const 0)))
+    (local.set 0x1c6 (i64.load offset=0x1c6 align=1 (i32.const 0)))
+    (local.set 0x1c7 (i64.load offset=0x1c7 align=1 (i32.const 0)))
+    (local.set 0x1c8 (i64.load offset=0x1c8 align=1 (i32.const 0)))
+    (local.set 0x1c9 (i64.load offset=0x1c9 align=1 (i32.const 0)))
+    (local.set 0x1ca (i64.load offset=0x1ca align=1 (i32.const 0)))
+    (local.set 0x1cb (i64.load offset=0x1cb align=1 (i32.const 0)))
+    (local.set 0x1cc (i64.load offset=0x1cc align=1 (i32.const 0)))
+    (local.set 0x1cd (i64.load offset=0x1cd align=1 (i32.const 0)))
+    (local.set 0x1ce (i64.load offset=0x1ce align=1 (i32.const 0)))
+    (local.set 0x1cf (i64.load offset=0x1cf align=1 (i32.const 0)))
+    (local.set 0x1d0 (i64.load offset=0x1d0 align=1 (i32.const 0)))
+    (local.set 0x1d1 (i64.load offset=0x1d1 align=1 (i32.const 0)))
+    (local.set 0x1d2 (i64.load offset=0x1d2 align=1 (i32.const 0)))
+    (local.set 0x1d3 (i64.load offset=0x1d3 align=1 (i32.const 0)))
+    (local.set 0x1d4 (i64.load offset=0x1d4 align=1 (i32.const 0)))
+    (local.set 0x1d5 (i64.load offset=0x1d5 align=1 (i32.const 0)))
+    (local.set 0x1d6 (i64.load offset=0x1d6 align=1 (i32.const 0)))
+    (local.set 0x1d7 (i64.load offset=0x1d7 align=1 (i32.const 0)))
+    (local.set 0x1d8 (i64.load offset=0x1d8 align=1 (i32.const 0)))
+    (local.set 0x1d9 (i64.load offset=0x1d9 align=1 (i32.const 0)))
+    (local.set 0x1da (i64.load offset=0x1da align=1 (i32.const 0)))
+    (local.set 0x1db (i64.load offset=0x1db align=1 (i32.const 0)))
+    (local.set 0x1dc (i64.load offset=0x1dc align=1 (i32.const 0)))
+    (local.set 0x1dd (i64.load offset=0x1dd align=1 (i32.const 0)))
+    (local.set 0x1de (i64.load offset=0x1de align=1 (i32.const 0)))
+    (local.set 0x1df (i64.load offset=0x1df align=1 (i32.const 0)))
+    (local.set 0x1e0 (i64.load offset=0x1e0 align=1 (i32.const 0)))
+    (local.set 0x1e1 (i64.load offset=0x1e1 align=1 (i32.const 0)))
+    (local.set 0x1e2 (i64.load offset=0x1e2 align=1 (i32.const 0)))
+    (local.set 0x1e3 (i64.load offset=0x1e3 align=1 (i32.const 0)))
+    (local.set 0x1e4 (i64.load offset=0x1e4 align=1 (i32.const 0)))
+    (local.set 0x1e5 (i64.load offset=0x1e5 align=1 (i32.const 0)))
+    (local.set 0x1e6 (i64.load offset=0x1e6 align=1 (i32.const 0)))
+    (local.set 0x1e7 (i64.load offset=0x1e7 align=1 (i32.const 0)))
+    (local.set 0x1e8 (i64.load offset=0x1e8 align=1 (i32.const 0)))
+    (local.set 0x1e9 (i64.load offset=0x1e9 align=1 (i32.const 0)))
+    (local.set 0x1ea (i64.load offset=0x1ea align=1 (i32.const 0)))
+    (local.set 0x1eb (i64.load offset=0x1eb align=1 (i32.const 0)))
+    (local.set 0x1ec (i64.load offset=0x1ec align=1 (i32.const 0)))
+    (local.set 0x1ed (i64.load offset=0x1ed align=1 (i32.const 0)))
+    (local.set 0x1ee (i64.load offset=0x1ee align=1 (i32.const 0)))
+    (local.set 0x1ef (i64.load offset=0x1ef align=1 (i32.const 0)))
+    (local.set 0x1f0 (i64.load offset=0x1f0 align=1 (i32.const 0)))
+    (local.set 0x1f1 (i64.load offset=0x1f1 align=1 (i32.const 0)))
+    (local.set 0x1f2 (i64.load offset=0x1f2 align=1 (i32.const 0)))
+    (local.set 0x1f3 (i64.load offset=0x1f3 align=1 (i32.const 0)))
+    (local.set 0x1f4 (i64.load offset=0x1f4 align=1 (i32.const 0)))
+    (local.set 0x1f5 (i64.load offset=0x1f5 align=1 (i32.const 0)))
+    (local.set 0x1f6 (i64.load offset=0x1f6 align=1 (i32.const 0)))
+    (local.set 0x1f7 (i64.load offset=0x1f7 align=1 (i32.const 0)))
+    (local.set 0x1f8 (i64.load offset=0x1f8 align=1 (i32.const 0)))
+    (local.set 0x1f9 (i64.load offset=0x1f9 align=1 (i32.const 0)))
+    (local.set 0x1fa (i64.load offset=0x1fa align=1 (i32.const 0)))
+    (local.set 0x1fb (i64.load offset=0x1fb align=1 (i32.const 0)))
+    (local.set 0x1fc (i64.load offset=0x1fc align=1 (i32.const 0)))
+    (local.set 0x1fd (i64.load offset=0x1fd align=1 (i32.const 0)))
+    (local.set 0x1fe (i64.load offset=0x1fe align=1 (i32.const 0)))
+    (local.set 0x1ff (i64.load offset=0x1ff align=1 (i32.const 0)))
+    (local.set 0x200 (i64.load offset=0x200 align=1 (i32.const 0)))
+    (local.set 0x201 (i64.load offset=0x201 align=1 (i32.const 0)))
+    (local.set 0x202 (i64.load offset=0x202 align=1 (i32.const 0)))
+    (local.set 0x203 (i64.load offset=0x203 align=1 (i32.const 0)))
+    (local.set 0x204 (i64.load offset=0x204 align=1 (i32.const 0)))
+    (local.set 0x205 (i64.load offset=0x205 align=1 (i32.const 0)))
+    (local.set 0x206 (i64.load offset=0x206 align=1 (i32.const 0)))
+    (local.set 0x207 (i64.load offset=0x207 align=1 (i32.const 0)))
+    (local.set 0x208 (i64.load offset=0x208 align=1 (i32.const 0)))
+    (local.set 0x209 (i64.load offset=0x209 align=1 (i32.const 0)))
+    (local.set 0x20a (i64.load offset=0x20a align=1 (i32.const 0)))
+    (local.set 0x20b (i64.load offset=0x20b align=1 (i32.const 0)))
+    (local.set 0x20c (i64.load offset=0x20c align=1 (i32.const 0)))
+    (local.set 0x20d (i64.load offset=0x20d align=1 (i32.const 0)))
+    (local.set 0x20e (i64.load offset=0x20e align=1 (i32.const 0)))
+    (local.set 0x20f (i64.load offset=0x20f align=1 (i32.const 0)))
+    (local.set 0x210 (i64.load offset=0x210 align=1 (i32.const 0)))
+    (local.set 0x211 (i64.load offset=0x211 align=1 (i32.const 0)))
+    (local.set 0x212 (i64.load offset=0x212 align=1 (i32.const 0)))
+    (local.set 0x213 (i64.load offset=0x213 align=1 (i32.const 0)))
+    (local.set 0x214 (i64.load offset=0x214 align=1 (i32.const 0)))
+    (local.set 0x215 (i64.load offset=0x215 align=1 (i32.const 0)))
+    (local.set 0x216 (i64.load offset=0x216 align=1 (i32.const 0)))
+    (local.set 0x217 (i64.load offset=0x217 align=1 (i32.const 0)))
+    (local.set 0x218 (i64.load offset=0x218 align=1 (i32.const 0)))
+    (local.set 0x219 (i64.load offset=0x219 align=1 (i32.const 0)))
+    (local.set 0x21a (i64.load offset=0x21a align=1 (i32.const 0)))
+    (local.set 0x21b (i64.load offset=0x21b align=1 (i32.const 0)))
+    (local.set 0x21c (i64.load offset=0x21c align=1 (i32.const 0)))
+    (local.set 0x21d (i64.load offset=0x21d align=1 (i32.const 0)))
+    (local.set 0x21e (i64.load offset=0x21e align=1 (i32.const 0)))
+    (local.set 0x21f (i64.load offset=0x21f align=1 (i32.const 0)))
+    (local.set 0x220 (i64.load offset=0x220 align=1 (i32.const 0)))
+    (local.set 0x221 (i64.load offset=0x221 align=1 (i32.const 0)))
+    (local.set 0x222 (i64.load offset=0x222 align=1 (i32.const 0)))
+    (local.set 0x223 (i64.load offset=0x223 align=1 (i32.const 0)))
+    (local.set 0x224 (i64.load offset=0x224 align=1 (i32.const 0)))
+    (local.set 0x225 (i64.load offset=0x225 align=1 (i32.const 0)))
+    (local.set 0x226 (i64.load offset=0x226 align=1 (i32.const 0)))
+    (local.set 0x227 (i64.load offset=0x227 align=1 (i32.const 0)))
+    (local.set 0x228 (i64.load offset=0x228 align=1 (i32.const 0)))
+    (local.set 0x229 (i64.load offset=0x229 align=1 (i32.const 0)))
+    (local.set 0x22a (i64.load offset=0x22a align=1 (i32.const 0)))
+    (local.set 0x22b (i64.load offset=0x22b align=1 (i32.const 0)))
+    (local.set 0x22c (i64.load offset=0x22c align=1 (i32.const 0)))
+    (local.set 0x22d (i64.load offset=0x22d align=1 (i32.const 0)))
+    (local.set 0x22e (i64.load offset=0x22e align=1 (i32.const 0)))
+    (local.set 0x22f (i64.load offset=0x22f align=1 (i32.const 0)))
+    (local.set 0x230 (i64.load offset=0x230 align=1 (i32.const 0)))
+    (local.set 0x231 (i64.load offset=0x231 align=1 (i32.const 0)))
+    (local.set 0x232 (i64.load offset=0x232 align=1 (i32.const 0)))
+    (local.set 0x233 (i64.load offset=0x233 align=1 (i32.const 0)))
+    (local.set 0x234 (i64.load offset=0x234 align=1 (i32.const 0)))
+    (local.set 0x235 (i64.load offset=0x235 align=1 (i32.const 0)))
+    (local.set 0x236 (i64.load offset=0x236 align=1 (i32.const 0)))
+    (local.set 0x237 (i64.load offset=0x237 align=1 (i32.const 0)))
+    (local.set 0x238 (i64.load offset=0x238 align=1 (i32.const 0)))
+    (local.set 0x239 (i64.load offset=0x239 align=1 (i32.const 0)))
+    (local.set 0x23a (i64.load offset=0x23a align=1 (i32.const 0)))
+    (local.set 0x23b (i64.load offset=0x23b align=1 (i32.const 0)))
+    (local.set 0x23c (i64.load offset=0x23c align=1 (i32.const 0)))
+    (local.set 0x23d (i64.load offset=0x23d align=1 (i32.const 0)))
+    (local.set 0x23e (i64.load offset=0x23e align=1 (i32.const 0)))
+    (local.set 0x23f (i64.load offset=0x23f align=1 (i32.const 0)))
+    (local.set 0x240 (i64.load offset=0x240 align=1 (i32.const 0)))
+    (local.set 0x241 (i64.load offset=0x241 align=1 (i32.const 0)))
+    (local.set 0x242 (i64.load offset=0x242 align=1 (i32.const 0)))
+    (local.set 0x243 (i64.load offset=0x243 align=1 (i32.const 0)))
+    (local.set 0x244 (i64.load offset=0x244 align=1 (i32.const 0)))
+    (local.set 0x245 (i64.load offset=0x245 align=1 (i32.const 0)))
+    (local.set 0x246 (i64.load offset=0x246 align=1 (i32.const 0)))
+    (local.set 0x247 (i64.load offset=0x247 align=1 (i32.const 0)))
+    (local.set 0x248 (i64.load offset=0x248 align=1 (i32.const 0)))
+    (local.set 0x249 (i64.load offset=0x249 align=1 (i32.const 0)))
+    (local.set 0x24a (i64.load offset=0x24a align=1 (i32.const 0)))
+    (local.set 0x24b (i64.load offset=0x24b align=1 (i32.const 0)))
+    (local.set 0x24c (i64.load offset=0x24c align=1 (i32.const 0)))
+    (local.set 0x24d (i64.load offset=0x24d align=1 (i32.const 0)))
+    (local.set 0x24e (i64.load offset=0x24e align=1 (i32.const 0)))
+    (local.set 0x24f (i64.load offset=0x24f align=1 (i32.const 0)))
+    (local.set 0x250 (i64.load offset=0x250 align=1 (i32.const 0)))
+    (local.set 0x251 (i64.load offset=0x251 align=1 (i32.const 0)))
+    (local.set 0x252 (i64.load offset=0x252 align=1 (i32.const 0)))
+    (local.set 0x253 (i64.load offset=0x253 align=1 (i32.const 0)))
+    (local.set 0x254 (i64.load offset=0x254 align=1 (i32.const 0)))
+    (local.set 0x255 (i64.load offset=0x255 align=1 (i32.const 0)))
+    (local.set 0x256 (i64.load offset=0x256 align=1 (i32.const 0)))
+    (local.set 0x257 (i64.load offset=0x257 align=1 (i32.const 0)))
+    (local.set 0x258 (i64.load offset=0x258 align=1 (i32.const 0)))
+    (local.set 0x259 (i64.load offset=0x259 align=1 (i32.const 0)))
+    (local.set 0x25a (i64.load offset=0x25a align=1 (i32.const 0)))
+    (local.set 0x25b (i64.load offset=0x25b align=1 (i32.const 0)))
+    (local.set 0x25c (i64.load offset=0x25c align=1 (i32.const 0)))
+    (local.set 0x25d (i64.load offset=0x25d align=1 (i32.const 0)))
+    (local.set 0x25e (i64.load offset=0x25e align=1 (i32.const 0)))
+    (local.set 0x25f (i64.load offset=0x25f align=1 (i32.const 0)))
+    (local.set 0x260 (i64.load offset=0x260 align=1 (i32.const 0)))
+    (local.set 0x261 (i64.load offset=0x261 align=1 (i32.const 0)))
+    (local.set 0x262 (i64.load offset=0x262 align=1 (i32.const 0)))
+    (local.set 0x263 (i64.load offset=0x263 align=1 (i32.const 0)))
+    (local.set 0x264 (i64.load offset=0x264 align=1 (i32.const 0)))
+    (local.set 0x265 (i64.load offset=0x265 align=1 (i32.const 0)))
+    (local.set 0x266 (i64.load offset=0x266 align=1 (i32.const 0)))
+    (local.set 0x267 (i64.load offset=0x267 align=1 (i32.const 0)))
+    (local.set 0x268 (i64.load offset=0x268 align=1 (i32.const 0)))
+    (local.set 0x269 (i64.load offset=0x269 align=1 (i32.const 0)))
+    (local.set 0x26a (i64.load offset=0x26a align=1 (i32.const 0)))
+    (local.set 0x26b (i64.load offset=0x26b align=1 (i32.const 0)))
+    (local.set 0x26c (i64.load offset=0x26c align=1 (i32.const 0)))
+    (local.set 0x26d (i64.load offset=0x26d align=1 (i32.const 0)))
+    (local.set 0x26e (i64.load offset=0x26e align=1 (i32.const 0)))
+    (local.set 0x26f (i64.load offset=0x26f align=1 (i32.const 0)))
+    (local.set 0x270 (i64.load offset=0x270 align=1 (i32.const 0)))
+    (local.set 0x271 (i64.load offset=0x271 align=1 (i32.const 0)))
+    (local.set 0x272 (i64.load offset=0x272 align=1 (i32.const 0)))
+    (local.set 0x273 (i64.load offset=0x273 align=1 (i32.const 0)))
+    (local.set 0x274 (i64.load offset=0x274 align=1 (i32.const 0)))
+    (local.set 0x275 (i64.load offset=0x275 align=1 (i32.const 0)))
+    (local.set 0x276 (i64.load offset=0x276 align=1 (i32.const 0)))
+    (local.set 0x277 (i64.load offset=0x277 align=1 (i32.const 0)))
+    (local.set 0x278 (i64.load offset=0x278 align=1 (i32.const 0)))
+    (local.set 0x279 (i64.load offset=0x279 align=1 (i32.const 0)))
+    (local.set 0x27a (i64.load offset=0x27a align=1 (i32.const 0)))
+    (local.set 0x27b (i64.load offset=0x27b align=1 (i32.const 0)))
+    (local.set 0x27c (i64.load offset=0x27c align=1 (i32.const 0)))
+    (local.set 0x27d (i64.load offset=0x27d align=1 (i32.const 0)))
+    (local.set 0x27e (i64.load offset=0x27e align=1 (i32.const 0)))
+    (local.set 0x27f (i64.load offset=0x27f align=1 (i32.const 0)))
+    (local.set 0x280 (i64.load offset=0x280 align=1 (i32.const 0)))
+    (local.set 0x281 (i64.load offset=0x281 align=1 (i32.const 0)))
+    (local.set 0x282 (i64.load offset=0x282 align=1 (i32.const 0)))
+    (local.set 0x283 (i64.load offset=0x283 align=1 (i32.const 0)))
+    (local.set 0x284 (i64.load offset=0x284 align=1 (i32.const 0)))
+    (local.set 0x285 (i64.load offset=0x285 align=1 (i32.const 0)))
+    (local.set 0x286 (i64.load offset=0x286 align=1 (i32.const 0)))
+    (local.set 0x287 (i64.load offset=0x287 align=1 (i32.const 0)))
+    (local.set 0x288 (i64.load offset=0x288 align=1 (i32.const 0)))
+    (local.set 0x289 (i64.load offset=0x289 align=1 (i32.const 0)))
+    (local.set 0x28a (i64.load offset=0x28a align=1 (i32.const 0)))
+    (local.set 0x28b (i64.load offset=0x28b align=1 (i32.const 0)))
+    (local.set 0x28c (i64.load offset=0x28c align=1 (i32.const 0)))
+    (local.set 0x28d (i64.load offset=0x28d align=1 (i32.const 0)))
+    (local.set 0x28e (i64.load offset=0x28e align=1 (i32.const 0)))
+    (local.set 0x28f (i64.load offset=0x28f align=1 (i32.const 0)))
+    (local.set 0x290 (i64.load offset=0x290 align=1 (i32.const 0)))
+    (local.set 0x291 (i64.load offset=0x291 align=1 (i32.const 0)))
+    (local.set 0x292 (i64.load offset=0x292 align=1 (i32.const 0)))
+    (local.set 0x293 (i64.load offset=0x293 align=1 (i32.const 0)))
+    (local.set 0x294 (i64.load offset=0x294 align=1 (i32.const 0)))
+    (local.set 0x295 (i64.load offset=0x295 align=1 (i32.const 0)))
+    (local.set 0x296 (i64.load offset=0x296 align=1 (i32.const 0)))
+    (local.set 0x297 (i64.load offset=0x297 align=1 (i32.const 0)))
+    (local.set 0x298 (i64.load offset=0x298 align=1 (i32.const 0)))
+    (local.set 0x299 (i64.load offset=0x299 align=1 (i32.const 0)))
+    (local.set 0x29a (i64.load offset=0x29a align=1 (i32.const 0)))
+    (local.set 0x29b (i64.load offset=0x29b align=1 (i32.const 0)))
+    (local.set 0x29c (i64.load offset=0x29c align=1 (i32.const 0)))
+    (local.set 0x29d (i64.load offset=0x29d align=1 (i32.const 0)))
+    (local.set 0x29e (i64.load offset=0x29e align=1 (i32.const 0)))
+    (local.set 0x29f (i64.load offset=0x29f align=1 (i32.const 0)))
+    (local.set 0x2a0 (i64.load offset=0x2a0 align=1 (i32.const 0)))
+    (local.set 0x2a1 (i64.load offset=0x2a1 align=1 (i32.const 0)))
+    (local.set 0x2a2 (i64.load offset=0x2a2 align=1 (i32.const 0)))
+    (local.set 0x2a3 (i64.load offset=0x2a3 align=1 (i32.const 0)))
+    (local.set 0x2a4 (i64.load offset=0x2a4 align=1 (i32.const 0)))
+    (local.set 0x2a5 (i64.load offset=0x2a5 align=1 (i32.const 0)))
+    (local.set 0x2a6 (i64.load offset=0x2a6 align=1 (i32.const 0)))
+    (local.set 0x2a7 (i64.load offset=0x2a7 align=1 (i32.const 0)))
+    (local.set 0x2a8 (i64.load offset=0x2a8 align=1 (i32.const 0)))
+    (local.set 0x2a9 (i64.load offset=0x2a9 align=1 (i32.const 0)))
+    (local.set 0x2aa (i64.load offset=0x2aa align=1 (i32.const 0)))
+    (local.set 0x2ab (i64.load offset=0x2ab align=1 (i32.const 0)))
+    (local.set 0x2ac (i64.load offset=0x2ac align=1 (i32.const 0)))
+    (local.set 0x2ad (i64.load offset=0x2ad align=1 (i32.const 0)))
+    (local.set 0x2ae (i64.load offset=0x2ae align=1 (i32.const 0)))
+    (local.set 0x2af (i64.load offset=0x2af align=1 (i32.const 0)))
+    (local.set 0x2b0 (i64.load offset=0x2b0 align=1 (i32.const 0)))
+    (local.set 0x2b1 (i64.load offset=0x2b1 align=1 (i32.const 0)))
+    (local.set 0x2b2 (i64.load offset=0x2b2 align=1 (i32.const 0)))
+    (local.set 0x2b3 (i64.load offset=0x2b3 align=1 (i32.const 0)))
+    (local.set 0x2b4 (i64.load offset=0x2b4 align=1 (i32.const 0)))
+    (local.set 0x2b5 (i64.load offset=0x2b5 align=1 (i32.const 0)))
+    (local.set 0x2b6 (i64.load offset=0x2b6 align=1 (i32.const 0)))
+    (local.set 0x2b7 (i64.load offset=0x2b7 align=1 (i32.const 0)))
+    (local.set 0x2b8 (i64.load offset=0x2b8 align=1 (i32.const 0)))
+    (local.set 0x2b9 (i64.load offset=0x2b9 align=1 (i32.const 0)))
+    (local.set 0x2ba (i64.load offset=0x2ba align=1 (i32.const 0)))
+    (local.set 0x2bb (i64.load offset=0x2bb align=1 (i32.const 0)))
+    (local.set 0x2bc (i64.load offset=0x2bc align=1 (i32.const 0)))
+    (local.set 0x2bd (i64.load offset=0x2bd align=1 (i32.const 0)))
+    (local.set 0x2be (i64.load offset=0x2be align=1 (i32.const 0)))
+    (local.set 0x2bf (i64.load offset=0x2bf align=1 (i32.const 0)))
+    (local.set 0x2c0 (i64.load offset=0x2c0 align=1 (i32.const 0)))
+    (local.set 0x2c1 (i64.load offset=0x2c1 align=1 (i32.const 0)))
+    (local.set 0x2c2 (i64.load offset=0x2c2 align=1 (i32.const 0)))
+    (local.set 0x2c3 (i64.load offset=0x2c3 align=1 (i32.const 0)))
+    (local.set 0x2c4 (i64.load offset=0x2c4 align=1 (i32.const 0)))
+    (local.set 0x2c5 (i64.load offset=0x2c5 align=1 (i32.const 0)))
+    (local.set 0x2c6 (i64.load offset=0x2c6 align=1 (i32.const 0)))
+    (local.set 0x2c7 (i64.load offset=0x2c7 align=1 (i32.const 0)))
+    (local.set 0x2c8 (i64.load offset=0x2c8 align=1 (i32.const 0)))
+    (local.set 0x2c9 (i64.load offset=0x2c9 align=1 (i32.const 0)))
+    (local.set 0x2ca (i64.load offset=0x2ca align=1 (i32.const 0)))
+    (local.set 0x2cb (i64.load offset=0x2cb align=1 (i32.const 0)))
+    (local.set 0x2cc (i64.load offset=0x2cc align=1 (i32.const 0)))
+    (local.set 0x2cd (i64.load offset=0x2cd align=1 (i32.const 0)))
+    (local.set 0x2ce (i64.load offset=0x2ce align=1 (i32.const 0)))
+    (local.set 0x2cf (i64.load offset=0x2cf align=1 (i32.const 0)))
+    (local.set 0x2d0 (i64.load offset=0x2d0 align=1 (i32.const 0)))
+    (local.set 0x2d1 (i64.load offset=0x2d1 align=1 (i32.const 0)))
+    (local.set 0x2d2 (i64.load offset=0x2d2 align=1 (i32.const 0)))
+    (local.set 0x2d3 (i64.load offset=0x2d3 align=1 (i32.const 0)))
+    (local.set 0x2d4 (i64.load offset=0x2d4 align=1 (i32.const 0)))
+    (local.set 0x2d5 (i64.load offset=0x2d5 align=1 (i32.const 0)))
+    (local.set 0x2d6 (i64.load offset=0x2d6 align=1 (i32.const 0)))
+    (local.set 0x2d7 (i64.load offset=0x2d7 align=1 (i32.const 0)))
+    (local.set 0x2d8 (i64.load offset=0x2d8 align=1 (i32.const 0)))
+    (local.set 0x2d9 (i64.load offset=0x2d9 align=1 (i32.const 0)))
+    (local.set 0x2da (i64.load offset=0x2da align=1 (i32.const 0)))
+    (local.set 0x2db (i64.load offset=0x2db align=1 (i32.const 0)))
+    (local.set 0x2dc (i64.load offset=0x2dc align=1 (i32.const 0)))
+    (local.set 0x2dd (i64.load offset=0x2dd align=1 (i32.const 0)))
+    (local.set 0x2de (i64.load offset=0x2de align=1 (i32.const 0)))
+    (local.set 0x2df (i64.load offset=0x2df align=1 (i32.const 0)))
+    (local.set 0x2e0 (i64.load offset=0x2e0 align=1 (i32.const 0)))
+    (local.set 0x2e1 (i64.load offset=0x2e1 align=1 (i32.const 0)))
+    (local.set 0x2e2 (i64.load offset=0x2e2 align=1 (i32.const 0)))
+    (local.set 0x2e3 (i64.load offset=0x2e3 align=1 (i32.const 0)))
+    (local.set 0x2e4 (i64.load offset=0x2e4 align=1 (i32.const 0)))
+    (local.set 0x2e5 (i64.load offset=0x2e5 align=1 (i32.const 0)))
+    (local.set 0x2e6 (i64.load offset=0x2e6 align=1 (i32.const 0)))
+    (local.set 0x2e7 (i64.load offset=0x2e7 align=1 (i32.const 0)))
+    (local.set 0x2e8 (i64.load offset=0x2e8 align=1 (i32.const 0)))
+    (local.set 0x2e9 (i64.load offset=0x2e9 align=1 (i32.const 0)))
+    (local.set 0x2ea (i64.load offset=0x2ea align=1 (i32.const 0)))
+    (local.set 0x2eb (i64.load offset=0x2eb align=1 (i32.const 0)))
+    (local.set 0x2ec (i64.load offset=0x2ec align=1 (i32.const 0)))
+    (local.set 0x2ed (i64.load offset=0x2ed align=1 (i32.const 0)))
+    (local.set 0x2ee (i64.load offset=0x2ee align=1 (i32.const 0)))
+    (local.set 0x2ef (i64.load offset=0x2ef align=1 (i32.const 0)))
+    (local.set 0x2f0 (i64.load offset=0x2f0 align=1 (i32.const 0)))
+    (local.set 0x2f1 (i64.load offset=0x2f1 align=1 (i32.const 0)))
+    (local.set 0x2f2 (i64.load offset=0x2f2 align=1 (i32.const 0)))
+    (local.set 0x2f3 (i64.load offset=0x2f3 align=1 (i32.const 0)))
+    (local.set 0x2f4 (i64.load offset=0x2f4 align=1 (i32.const 0)))
+    (local.set 0x2f5 (i64.load offset=0x2f5 align=1 (i32.const 0)))
+    (local.set 0x2f6 (i64.load offset=0x2f6 align=1 (i32.const 0)))
+    (local.set 0x2f7 (i64.load offset=0x2f7 align=1 (i32.const 0)))
+    (local.set 0x2f8 (i64.load offset=0x2f8 align=1 (i32.const 0)))
+    (local.set 0x2f9 (i64.load offset=0x2f9 align=1 (i32.const 0)))
+    (local.set 0x2fa (i64.load offset=0x2fa align=1 (i32.const 0)))
+    (local.set 0x2fb (i64.load offset=0x2fb align=1 (i32.const 0)))
+    (local.set 0x2fc (i64.load offset=0x2fc align=1 (i32.const 0)))
+    (local.set 0x2fd (i64.load offset=0x2fd align=1 (i32.const 0)))
+    (local.set 0x2fe (i64.load offset=0x2fe align=1 (i32.const 0)))
+    (local.set 0x2ff (i64.load offset=0x2ff align=1 (i32.const 0)))
+    (local.set 0x300 (i64.load offset=0x300 align=1 (i32.const 0)))
+    (local.set 0x301 (i64.load offset=0x301 align=1 (i32.const 0)))
+    (local.set 0x302 (i64.load offset=0x302 align=1 (i32.const 0)))
+    (local.set 0x303 (i64.load offset=0x303 align=1 (i32.const 0)))
+    (local.set 0x304 (i64.load offset=0x304 align=1 (i32.const 0)))
+    (local.set 0x305 (i64.load offset=0x305 align=1 (i32.const 0)))
+    (local.set 0x306 (i64.load offset=0x306 align=1 (i32.const 0)))
+    (local.set 0x307 (i64.load offset=0x307 align=1 (i32.const 0)))
+    (local.set 0x308 (i64.load offset=0x308 align=1 (i32.const 0)))
+    (local.set 0x309 (i64.load offset=0x309 align=1 (i32.const 0)))
+    (local.set 0x30a (i64.load offset=0x30a align=1 (i32.const 0)))
+    (local.set 0x30b (i64.load offset=0x30b align=1 (i32.const 0)))
+    (local.set 0x30c (i64.load offset=0x30c align=1 (i32.const 0)))
+    (local.set 0x30d (i64.load offset=0x30d align=1 (i32.const 0)))
+    (local.set 0x30e (i64.load offset=0x30e align=1 (i32.const 0)))
+    (local.set 0x30f (i64.load offset=0x30f align=1 (i32.const 0)))
+    (local.set 0x310 (i64.load offset=0x310 align=1 (i32.const 0)))
+    (local.set 0x311 (i64.load offset=0x311 align=1 (i32.const 0)))
+    (local.set 0x312 (i64.load offset=0x312 align=1 (i32.const 0)))
+    (local.set 0x313 (i64.load offset=0x313 align=1 (i32.const 0)))
+    (local.set 0x314 (i64.load offset=0x314 align=1 (i32.const 0)))
+    (local.set 0x315 (i64.load offset=0x315 align=1 (i32.const 0)))
+    (local.set 0x316 (i64.load offset=0x316 align=1 (i32.const 0)))
+    (local.set 0x317 (i64.load offset=0x317 align=1 (i32.const 0)))
+    (local.set 0x318 (i64.load offset=0x318 align=1 (i32.const 0)))
+    (local.set 0x319 (i64.load offset=0x319 align=1 (i32.const 0)))
+    (local.set 0x31a (i64.load offset=0x31a align=1 (i32.const 0)))
+    (local.set 0x31b (i64.load offset=0x31b align=1 (i32.const 0)))
+    (local.set 0x31c (i64.load offset=0x31c align=1 (i32.const 0)))
+    (local.set 0x31d (i64.load offset=0x31d align=1 (i32.const 0)))
+    (local.set 0x31e (i64.load offset=0x31e align=1 (i32.const 0)))
+    (local.set 0x31f (i64.load offset=0x31f align=1 (i32.const 0)))
+    (local.set 0x320 (i64.load offset=0x320 align=1 (i32.const 0)))
+    (local.set 0x321 (i64.load offset=0x321 align=1 (i32.const 0)))
+    (local.set 0x322 (i64.load offset=0x322 align=1 (i32.const 0)))
+    (local.set 0x323 (i64.load offset=0x323 align=1 (i32.const 0)))
+    (local.set 0x324 (i64.load offset=0x324 align=1 (i32.const 0)))
+    (local.set 0x325 (i64.load offset=0x325 align=1 (i32.const 0)))
+    (local.set 0x326 (i64.load offset=0x326 align=1 (i32.const 0)))
+    (local.set 0x327 (i64.load offset=0x327 align=1 (i32.const 0)))
+    (local.set 0x328 (i64.load offset=0x328 align=1 (i32.const 0)))
+    (local.set 0x329 (i64.load offset=0x329 align=1 (i32.const 0)))
+    (local.set 0x32a (i64.load offset=0x32a align=1 (i32.const 0)))
+    (local.set 0x32b (i64.load offset=0x32b align=1 (i32.const 0)))
+    (local.set 0x32c (i64.load offset=0x32c align=1 (i32.const 0)))
+    (local.set 0x32d (i64.load offset=0x32d align=1 (i32.const 0)))
+    (local.set 0x32e (i64.load offset=0x32e align=1 (i32.const 0)))
+    (local.set 0x32f (i64.load offset=0x32f align=1 (i32.const 0)))
+    (local.set 0x330 (i64.load offset=0x330 align=1 (i32.const 0)))
+    (local.set 0x331 (i64.load offset=0x331 align=1 (i32.const 0)))
+    (local.set 0x332 (i64.load offset=0x332 align=1 (i32.const 0)))
+    (local.set 0x333 (i64.load offset=0x333 align=1 (i32.const 0)))
+    (local.set 0x334 (i64.load offset=0x334 align=1 (i32.const 0)))
+    (local.set 0x335 (i64.load offset=0x335 align=1 (i32.const 0)))
+    (local.set 0x336 (i64.load offset=0x336 align=1 (i32.const 0)))
+    (local.set 0x337 (i64.load offset=0x337 align=1 (i32.const 0)))
+    (local.set 0x338 (i64.load offset=0x338 align=1 (i32.const 0)))
+    (local.set 0x339 (i64.load offset=0x339 align=1 (i32.const 0)))
+    (local.set 0x33a (i64.load offset=0x33a align=1 (i32.const 0)))
+    (local.set 0x33b (i64.load offset=0x33b align=1 (i32.const 0)))
+    (local.set 0x33c (i64.load offset=0x33c align=1 (i32.const 0)))
+    (local.set 0x33d (i64.load offset=0x33d align=1 (i32.const 0)))
+    (local.set 0x33e (i64.load offset=0x33e align=1 (i32.const 0)))
+    (local.set 0x33f (i64.load offset=0x33f align=1 (i32.const 0)))
+    (local.set 0x340 (i64.load offset=0x340 align=1 (i32.const 0)))
+    (local.set 0x341 (i64.load offset=0x341 align=1 (i32.const 0)))
+    (local.set 0x342 (i64.load offset=0x342 align=1 (i32.const 0)))
+    (local.set 0x343 (i64.load offset=0x343 align=1 (i32.const 0)))
+    (local.set 0x344 (i64.load offset=0x344 align=1 (i32.const 0)))
+    (local.set 0x345 (i64.load offset=0x345 align=1 (i32.const 0)))
+    (local.set 0x346 (i64.load offset=0x346 align=1 (i32.const 0)))
+    (local.set 0x347 (i64.load offset=0x347 align=1 (i32.const 0)))
+    (local.set 0x348 (i64.load offset=0x348 align=1 (i32.const 0)))
+    (local.set 0x349 (i64.load offset=0x349 align=1 (i32.const 0)))
+    (local.set 0x34a (i64.load offset=0x34a align=1 (i32.const 0)))
+    (local.set 0x34b (i64.load offset=0x34b align=1 (i32.const 0)))
+    (local.set 0x34c (i64.load offset=0x34c align=1 (i32.const 0)))
+    (local.set 0x34d (i64.load offset=0x34d align=1 (i32.const 0)))
+    (local.set 0x34e (i64.load offset=0x34e align=1 (i32.const 0)))
+    (local.set 0x34f (i64.load offset=0x34f align=1 (i32.const 0)))
+    (local.set 0x350 (i64.load offset=0x350 align=1 (i32.const 0)))
+    (local.set 0x351 (i64.load offset=0x351 align=1 (i32.const 0)))
+    (local.set 0x352 (i64.load offset=0x352 align=1 (i32.const 0)))
+    (local.set 0x353 (i64.load offset=0x353 align=1 (i32.const 0)))
+    (local.set 0x354 (i64.load offset=0x354 align=1 (i32.const 0)))
+    (local.set 0x355 (i64.load offset=0x355 align=1 (i32.const 0)))
+    (local.set 0x356 (i64.load offset=0x356 align=1 (i32.const 0)))
+    (local.set 0x357 (i64.load offset=0x357 align=1 (i32.const 0)))
+    (local.set 0x358 (i64.load offset=0x358 align=1 (i32.const 0)))
+    (local.set 0x359 (i64.load offset=0x359 align=1 (i32.const 0)))
+    (local.set 0x35a (i64.load offset=0x35a align=1 (i32.const 0)))
+    (local.set 0x35b (i64.load offset=0x35b align=1 (i32.const 0)))
+    (local.set 0x35c (i64.load offset=0x35c align=1 (i32.const 0)))
+    (local.set 0x35d (i64.load offset=0x35d align=1 (i32.const 0)))
+    (local.set 0x35e (i64.load offset=0x35e align=1 (i32.const 0)))
+    (local.set 0x35f (i64.load offset=0x35f align=1 (i32.const 0)))
+    (local.set 0x360 (i64.load offset=0x360 align=1 (i32.const 0)))
+    (local.set 0x361 (i64.load offset=0x361 align=1 (i32.const 0)))
+    (local.set 0x362 (i64.load offset=0x362 align=1 (i32.const 0)))
+    (local.set 0x363 (i64.load offset=0x363 align=1 (i32.const 0)))
+    (local.set 0x364 (i64.load offset=0x364 align=1 (i32.const 0)))
+    (local.set 0x365 (i64.load offset=0x365 align=1 (i32.const 0)))
+    (local.set 0x366 (i64.load offset=0x366 align=1 (i32.const 0)))
+    (local.set 0x367 (i64.load offset=0x367 align=1 (i32.const 0)))
+    (local.set 0x368 (i64.load offset=0x368 align=1 (i32.const 0)))
+    (local.set 0x369 (i64.load offset=0x369 align=1 (i32.const 0)))
+    (local.set 0x36a (i64.load offset=0x36a align=1 (i32.const 0)))
+    (local.set 0x36b (i64.load offset=0x36b align=1 (i32.const 0)))
+    (local.set 0x36c (i64.load offset=0x36c align=1 (i32.const 0)))
+    (local.set 0x36d (i64.load offset=0x36d align=1 (i32.const 0)))
+    (local.set 0x36e (i64.load offset=0x36e align=1 (i32.const 0)))
+    (local.set 0x36f (i64.load offset=0x36f align=1 (i32.const 0)))
+    (local.set 0x370 (i64.load offset=0x370 align=1 (i32.const 0)))
+    (local.set 0x371 (i64.load offset=0x371 align=1 (i32.const 0)))
+    (local.set 0x372 (i64.load offset=0x372 align=1 (i32.const 0)))
+    (local.set 0x373 (i64.load offset=0x373 align=1 (i32.const 0)))
+    (local.set 0x374 (i64.load offset=0x374 align=1 (i32.const 0)))
+    (local.set 0x375 (i64.load offset=0x375 align=1 (i32.const 0)))
+    (local.set 0x376 (i64.load offset=0x376 align=1 (i32.const 0)))
+    (local.set 0x377 (i64.load offset=0x377 align=1 (i32.const 0)))
+    (local.set 0x378 (i64.load offset=0x378 align=1 (i32.const 0)))
+    (local.set 0x379 (i64.load offset=0x379 align=1 (i32.const 0)))
+    (local.set 0x37a (i64.load offset=0x37a align=1 (i32.const 0)))
+    (local.set 0x37b (i64.load offset=0x37b align=1 (i32.const 0)))
+    (local.set 0x37c (i64.load offset=0x37c align=1 (i32.const 0)))
+    (local.set 0x37d (i64.load offset=0x37d align=1 (i32.const 0)))
+    (local.set 0x37e (i64.load offset=0x37e align=1 (i32.const 0)))
+    (local.set 0x37f (i64.load offset=0x37f align=1 (i32.const 0)))
+    (local.set 0x380 (i64.load offset=0x380 align=1 (i32.const 0)))
+    (local.set 0x381 (i64.load offset=0x381 align=1 (i32.const 0)))
+    (local.set 0x382 (i64.load offset=0x382 align=1 (i32.const 0)))
+    (local.set 0x383 (i64.load offset=0x383 align=1 (i32.const 0)))
+    (local.set 0x384 (i64.load offset=0x384 align=1 (i32.const 0)))
+    (local.set 0x385 (i64.load offset=0x385 align=1 (i32.const 0)))
+    (local.set 0x386 (i64.load offset=0x386 align=1 (i32.const 0)))
+    (local.set 0x387 (i64.load offset=0x387 align=1 (i32.const 0)))
+    (local.set 0x388 (i64.load offset=0x388 align=1 (i32.const 0)))
+    (local.set 0x389 (i64.load offset=0x389 align=1 (i32.const 0)))
+    (local.set 0x38a (i64.load offset=0x38a align=1 (i32.const 0)))
+    (local.set 0x38b (i64.load offset=0x38b align=1 (i32.const 0)))
+    (local.set 0x38c (i64.load offset=0x38c align=1 (i32.const 0)))
+    (local.set 0x38d (i64.load offset=0x38d align=1 (i32.const 0)))
+    (local.set 0x38e (i64.load offset=0x38e align=1 (i32.const 0)))
+    (local.set 0x38f (i64.load offset=0x38f align=1 (i32.const 0)))
+    (local.set 0x390 (i64.load offset=0x390 align=1 (i32.const 0)))
+    (local.set 0x391 (i64.load offset=0x391 align=1 (i32.const 0)))
+    (local.set 0x392 (i64.load offset=0x392 align=1 (i32.const 0)))
+    (local.set 0x393 (i64.load offset=0x393 align=1 (i32.const 0)))
+    (local.set 0x394 (i64.load offset=0x394 align=1 (i32.const 0)))
+    (local.set 0x395 (i64.load offset=0x395 align=1 (i32.const 0)))
+    (local.set 0x396 (i64.load offset=0x396 align=1 (i32.const 0)))
+    (local.set 0x397 (i64.load offset=0x397 align=1 (i32.const 0)))
+    (local.set 0x398 (i64.load offset=0x398 align=1 (i32.const 0)))
+    (local.set 0x399 (i64.load offset=0x399 align=1 (i32.const 0)))
+    (local.set 0x39a (i64.load offset=0x39a align=1 (i32.const 0)))
+    (local.set 0x39b (i64.load offset=0x39b align=1 (i32.const 0)))
+    (local.set 0x39c (i64.load offset=0x39c align=1 (i32.const 0)))
+    (local.set 0x39d (i64.load offset=0x39d align=1 (i32.const 0)))
+    (local.set 0x39e (i64.load offset=0x39e align=1 (i32.const 0)))
+    (local.set 0x39f (i64.load offset=0x39f align=1 (i32.const 0)))
+    (local.set 0x3a0 (i64.load offset=0x3a0 align=1 (i32.const 0)))
+    (local.set 0x3a1 (i64.load offset=0x3a1 align=1 (i32.const 0)))
+    (local.set 0x3a2 (i64.load offset=0x3a2 align=1 (i32.const 0)))
+    (local.set 0x3a3 (i64.load offset=0x3a3 align=1 (i32.const 0)))
+    (local.set 0x3a4 (i64.load offset=0x3a4 align=1 (i32.const 0)))
+    (local.set 0x3a5 (i64.load offset=0x3a5 align=1 (i32.const 0)))
+    (local.set 0x3a6 (i64.load offset=0x3a6 align=1 (i32.const 0)))
+    (local.set 0x3a7 (i64.load offset=0x3a7 align=1 (i32.const 0)))
+    (local.set 0x3a8 (i64.load offset=0x3a8 align=1 (i32.const 0)))
+    (local.set 0x3a9 (i64.load offset=0x3a9 align=1 (i32.const 0)))
+    (local.set 0x3aa (i64.load offset=0x3aa align=1 (i32.const 0)))
+    (local.set 0x3ab (i64.load offset=0x3ab align=1 (i32.const 0)))
+    (local.set 0x3ac (i64.load offset=0x3ac align=1 (i32.const 0)))
+    (local.set 0x3ad (i64.load offset=0x3ad align=1 (i32.const 0)))
+    (local.set 0x3ae (i64.load offset=0x3ae align=1 (i32.const 0)))
+    (local.set 0x3af (i64.load offset=0x3af align=1 (i32.const 0)))
+    (local.set 0x3b0 (i64.load offset=0x3b0 align=1 (i32.const 0)))
+    (local.set 0x3b1 (i64.load offset=0x3b1 align=1 (i32.const 0)))
+    (local.set 0x3b2 (i64.load offset=0x3b2 align=1 (i32.const 0)))
+    (local.set 0x3b3 (i64.load offset=0x3b3 align=1 (i32.const 0)))
+    (local.set 0x3b4 (i64.load offset=0x3b4 align=1 (i32.const 0)))
+    (local.set 0x3b5 (i64.load offset=0x3b5 align=1 (i32.const 0)))
+    (local.set 0x3b6 (i64.load offset=0x3b6 align=1 (i32.const 0)))
+    (local.set 0x3b7 (i64.load offset=0x3b7 align=1 (i32.const 0)))
+    (local.set 0x3b8 (i64.load offset=0x3b8 align=1 (i32.const 0)))
+    (local.set 0x3b9 (i64.load offset=0x3b9 align=1 (i32.const 0)))
+    (local.set 0x3ba (i64.load offset=0x3ba align=1 (i32.const 0)))
+    (local.set 0x3bb (i64.load offset=0x3bb align=1 (i32.const 0)))
+    (local.set 0x3bc (i64.load offset=0x3bc align=1 (i32.const 0)))
+    (local.set 0x3bd (i64.load offset=0x3bd align=1 (i32.const 0)))
+    (local.set 0x3be (i64.load offset=0x3be align=1 (i32.const 0)))
+    (local.set 0x3bf (i64.load offset=0x3bf align=1 (i32.const 0)))
+    (local.set 0x3c0 (i64.load offset=0x3c0 align=1 (i32.const 0)))
+    (local.set 0x3c1 (i64.load offset=0x3c1 align=1 (i32.const 0)))
+    (local.set 0x3c2 (i64.load offset=0x3c2 align=1 (i32.const 0)))
+    (local.set 0x3c3 (i64.load offset=0x3c3 align=1 (i32.const 0)))
+    (local.set 0x3c4 (i64.load offset=0x3c4 align=1 (i32.const 0)))
+    (local.set 0x3c5 (i64.load offset=0x3c5 align=1 (i32.const 0)))
+    (local.set 0x3c6 (i64.load offset=0x3c6 align=1 (i32.const 0)))
+    (local.set 0x3c7 (i64.load offset=0x3c7 align=1 (i32.const 0)))
+    (local.set 0x3c8 (i64.load offset=0x3c8 align=1 (i32.const 0)))
+    (local.set 0x3c9 (i64.load offset=0x3c9 align=1 (i32.const 0)))
+    (local.set 0x3ca (i64.load offset=0x3ca align=1 (i32.const 0)))
+    (local.set 0x3cb (i64.load offset=0x3cb align=1 (i32.const 0)))
+    (local.set 0x3cc (i64.load offset=0x3cc align=1 (i32.const 0)))
+    (local.set 0x3cd (i64.load offset=0x3cd align=1 (i32.const 0)))
+    (local.set 0x3ce (i64.load offset=0x3ce align=1 (i32.const 0)))
+    (local.set 0x3cf (i64.load offset=0x3cf align=1 (i32.const 0)))
+    (local.set 0x3d0 (i64.load offset=0x3d0 align=1 (i32.const 0)))
+    (local.set 0x3d1 (i64.load offset=0x3d1 align=1 (i32.const 0)))
+    (local.set 0x3d2 (i64.load offset=0x3d2 align=1 (i32.const 0)))
+    (local.set 0x3d3 (i64.load offset=0x3d3 align=1 (i32.const 0)))
+    (local.set 0x3d4 (i64.load offset=0x3d4 align=1 (i32.const 0)))
+    (local.set 0x3d5 (i64.load offset=0x3d5 align=1 (i32.const 0)))
+    (local.set 0x3d6 (i64.load offset=0x3d6 align=1 (i32.const 0)))
+    (local.set 0x3d7 (i64.load offset=0x3d7 align=1 (i32.const 0)))
+    (local.set 0x3d8 (i64.load offset=0x3d8 align=1 (i32.const 0)))
+    (local.set 0x3d9 (i64.load offset=0x3d9 align=1 (i32.const 0)))
+    (local.set 0x3da (i64.load offset=0x3da align=1 (i32.const 0)))
+    (local.set 0x3db (i64.load offset=0x3db align=1 (i32.const 0)))
+    (local.set 0x3dc (i64.load offset=0x3dc align=1 (i32.const 0)))
+    (local.set 0x3dd (i64.load offset=0x3dd align=1 (i32.const 0)))
+    (local.set 0x3de (i64.load offset=0x3de align=1 (i32.const 0)))
+    (local.set 0x3df (i64.load offset=0x3df align=1 (i32.const 0)))
+    (local.set 0x3e0 (i64.load offset=0x3e0 align=1 (i32.const 0)))
+    (local.set 0x3e1 (i64.load offset=0x3e1 align=1 (i32.const 0)))
+    (local.set 0x3e2 (i64.load offset=0x3e2 align=1 (i32.const 0)))
+    (local.set 0x3e3 (i64.load offset=0x3e3 align=1 (i32.const 0)))
+    (local.set 0x3e4 (i64.load offset=0x3e4 align=1 (i32.const 0)))
+    (local.set 0x3e5 (i64.load offset=0x3e5 align=1 (i32.const 0)))
+    (local.set 0x3e6 (i64.load offset=0x3e6 align=1 (i32.const 0)))
+    (local.set 0x3e7 (i64.load offset=0x3e7 align=1 (i32.const 0)))
+    (local.set 0x3e8 (i64.load offset=0x3e8 align=1 (i32.const 0)))
+    (local.set 0x3e9 (i64.load offset=0x3e9 align=1 (i32.const 0)))
+    (local.set 0x3ea (i64.load offset=0x3ea align=1 (i32.const 0)))
+    (local.set 0x3eb (i64.load offset=0x3eb align=1 (i32.const 0)))
+    (local.set 0x3ec (i64.load offset=0x3ec align=1 (i32.const 0)))
+    (local.set 0x3ed (i64.load offset=0x3ed align=1 (i32.const 0)))
+    (local.set 0x3ee (i64.load offset=0x3ee align=1 (i32.const 0)))
+    (local.set 0x3ef (i64.load offset=0x3ef align=1 (i32.const 0)))
+    (local.set 0x3f0 (i64.load offset=0x3f0 align=1 (i32.const 0)))
+    (local.set 0x3f1 (i64.load offset=0x3f1 align=1 (i32.const 0)))
+    (local.set 0x3f2 (i64.load offset=0x3f2 align=1 (i32.const 0)))
+    (local.set 0x3f3 (i64.load offset=0x3f3 align=1 (i32.const 0)))
+    (local.set 0x3f4 (i64.load offset=0x3f4 align=1 (i32.const 0)))
+    (local.set 0x3f5 (i64.load offset=0x3f5 align=1 (i32.const 0)))
+    (local.set 0x3f6 (i64.load offset=0x3f6 align=1 (i32.const 0)))
+    (local.set 0x3f7 (i64.load offset=0x3f7 align=1 (i32.const 0)))
+    (local.set 0x3f8 (i64.load offset=0x3f8 align=1 (i32.const 0)))
+    (local.set 0x3f9 (i64.load offset=0x3f9 align=1 (i32.const 0)))
+    (local.set 0x3fa (i64.load offset=0x3fa align=1 (i32.const 0)))
+    (local.set 0x3fb (i64.load offset=0x3fb align=1 (i32.const 0)))
+    (local.set 0x3fc (i64.load offset=0x3fc align=1 (i32.const 0)))
+    (local.set 0x3fd (i64.load offset=0x3fd align=1 (i32.const 0)))
+    (local.set 0x3fe (i64.load offset=0x3fe align=1 (i32.const 0)))
+    (local.set 0x3ff (i64.load offset=0x3ff align=1 (i32.const 0)))
+    (local.set 0x400 (i64.load offset=0x400 align=1 (i32.const 0)))
+    (local.set 0x401 (i64.load offset=0x401 align=1 (i32.const 0)))
+    (local.set 0x402 (i64.load offset=0x402 align=1 (i32.const 0)))
+    (local.set 0x403 (i64.load offset=0x403 align=1 (i32.const 0)))
+    (local.set 0x404 (i64.load offset=0x404 align=1 (i32.const 0)))
+    (local.set 0x405 (i64.load offset=0x405 align=1 (i32.const 0)))
+    (local.set 0x406 (i64.load offset=0x406 align=1 (i32.const 0)))
+    (local.set 0x407 (i64.load offset=0x407 align=1 (i32.const 0)))
+    (local.set 0x408 (i64.load offset=0x408 align=1 (i32.const 0)))
+    (local.set 0x409 (i64.load offset=0x409 align=1 (i32.const 0)))
+    (local.set 0x40a (i64.load offset=0x40a align=1 (i32.const 0)))
+    (local.set 0x40b (i64.load offset=0x40b align=1 (i32.const 0)))
+    (local.set 0x40c (i64.load offset=0x40c align=1 (i32.const 0)))
+    (local.set 0x40d (i64.load offset=0x40d align=1 (i32.const 0)))
+    (local.set 0x40e (i64.load offset=0x40e align=1 (i32.const 0)))
+    (local.set 0x40f (i64.load offset=0x40f align=1 (i32.const 0)))
+    (local.set 0x410 (i64.load offset=0x410 align=1 (i32.const 0)))
+    (local.set 0x411 (i64.load offset=0x411 align=1 (i32.const 0)))
+    (local.set 0x412 (i64.load offset=0x412 align=1 (i32.const 0)))
+    (local.set 0x413 (i64.load offset=0x413 align=1 (i32.const 0)))
+    (local.set 0x414 (i64.load offset=0x414 align=1 (i32.const 0)))
+    (local.set 0x415 (i64.load offset=0x415 align=1 (i32.const 0)))
+    (local.set 0x416 (i64.load offset=0x416 align=1 (i32.const 0)))
+    (local.set 0x417 (i64.load offset=0x417 align=1 (i32.const 0)))
+    (local.set 0x418 (i64.load offset=0x418 align=1 (i32.const 0)))
+    (local.set 0x419 (i64.load offset=0x419 align=1 (i32.const 0)))
+    (local.set 0x41a (i64.load offset=0x41a align=1 (i32.const 0)))
+    (local.set 0x41b (i64.load offset=0x41b align=1 (i32.const 0)))
+    (local.set 0x41c (i64.load offset=0x41c align=1 (i32.const 0)))
+    (local.set 0x41d (i64.load offset=0x41d align=1 (i32.const 0)))
+    (local.set 0x41e (i64.load offset=0x41e align=1 (i32.const 0)))
+    (local.set 0x41f (i64.load offset=0x41f align=1 (i32.const 0)))
+
+    ;; store the locals back to memory
+    (i64.store offset=0x000 align=1 (i32.const 0) (local.get 0x000))
+    (i64.store offset=0x001 align=1 (i32.const 0) (local.get 0x001))
+    (i64.store offset=0x002 align=1 (i32.const 0) (local.get 0x002))
+    (i64.store offset=0x003 align=1 (i32.const 0) (local.get 0x003))
+    (i64.store offset=0x004 align=1 (i32.const 0) (local.get 0x004))
+    (i64.store offset=0x005 align=1 (i32.const 0) (local.get 0x005))
+    (i64.store offset=0x006 align=1 (i32.const 0) (local.get 0x006))
+    (i64.store offset=0x007 align=1 (i32.const 0) (local.get 0x007))
+    (i64.store offset=0x008 align=1 (i32.const 0) (local.get 0x008))
+    (i64.store offset=0x009 align=1 (i32.const 0) (local.get 0x009))
+    (i64.store offset=0x00a align=1 (i32.const 0) (local.get 0x00a))
+    (i64.store offset=0x00b align=1 (i32.const 0) (local.get 0x00b))
+    (i64.store offset=0x00c align=1 (i32.const 0) (local.get 0x00c))
+    (i64.store offset=0x00d align=1 (i32.const 0) (local.get 0x00d))
+    (i64.store offset=0x00e align=1 (i32.const 0) (local.get 0x00e))
+    (i64.store offset=0x00f align=1 (i32.const 0) (local.get 0x00f))
+    (i64.store offset=0x010 align=1 (i32.const 0) (local.get 0x010))
+    (i64.store offset=0x011 align=1 (i32.const 0) (local.get 0x011))
+    (i64.store offset=0x012 align=1 (i32.const 0) (local.get 0x012))
+    (i64.store offset=0x013 align=1 (i32.const 0) (local.get 0x013))
+    (i64.store offset=0x014 align=1 (i32.const 0) (local.get 0x014))
+    (i64.store offset=0x015 align=1 (i32.const 0) (local.get 0x015))
+    (i64.store offset=0x016 align=1 (i32.const 0) (local.get 0x016))
+    (i64.store offset=0x017 align=1 (i32.const 0) (local.get 0x017))
+    (i64.store offset=0x018 align=1 (i32.const 0) (local.get 0x018))
+    (i64.store offset=0x019 align=1 (i32.const 0) (local.get 0x019))
+    (i64.store offset=0x01a align=1 (i32.const 0) (local.get 0x01a))
+    (i64.store offset=0x01b align=1 (i32.const 0) (local.get 0x01b))
+    (i64.store offset=0x01c align=1 (i32.const 0) (local.get 0x01c))
+    (i64.store offset=0x01d align=1 (i32.const 0) (local.get 0x01d))
+    (i64.store offset=0x01e align=1 (i32.const 0) (local.get 0x01e))
+    (i64.store offset=0x01f align=1 (i32.const 0) (local.get 0x01f))
+    (i64.store offset=0x020 align=1 (i32.const 0) (local.get 0x020))
+    (i64.store offset=0x021 align=1 (i32.const 0) (local.get 0x021))
+    (i64.store offset=0x022 align=1 (i32.const 0) (local.get 0x022))
+    (i64.store offset=0x023 align=1 (i32.const 0) (local.get 0x023))
+    (i64.store offset=0x024 align=1 (i32.const 0) (local.get 0x024))
+    (i64.store offset=0x025 align=1 (i32.const 0) (local.get 0x025))
+    (i64.store offset=0x026 align=1 (i32.const 0) (local.get 0x026))
+    (i64.store offset=0x027 align=1 (i32.const 0) (local.get 0x027))
+    (i64.store offset=0x028 align=1 (i32.const 0) (local.get 0x028))
+    (i64.store offset=0x029 align=1 (i32.const 0) (local.get 0x029))
+    (i64.store offset=0x02a align=1 (i32.const 0) (local.get 0x02a))
+    (i64.store offset=0x02b align=1 (i32.const 0) (local.get 0x02b))
+    (i64.store offset=0x02c align=1 (i32.const 0) (local.get 0x02c))
+    (i64.store offset=0x02d align=1 (i32.const 0) (local.get 0x02d))
+    (i64.store offset=0x02e align=1 (i32.const 0) (local.get 0x02e))
+    (i64.store offset=0x02f align=1 (i32.const 0) (local.get 0x02f))
+    (i64.store offset=0x030 align=1 (i32.const 0) (local.get 0x030))
+    (i64.store offset=0x031 align=1 (i32.const 0) (local.get 0x031))
+    (i64.store offset=0x032 align=1 (i32.const 0) (local.get 0x032))
+    (i64.store offset=0x033 align=1 (i32.const 0) (local.get 0x033))
+    (i64.store offset=0x034 align=1 (i32.const 0) (local.get 0x034))
+    (i64.store offset=0x035 align=1 (i32.const 0) (local.get 0x035))
+    (i64.store offset=0x036 align=1 (i32.const 0) (local.get 0x036))
+    (i64.store offset=0x037 align=1 (i32.const 0) (local.get 0x037))
+    (i64.store offset=0x038 align=1 (i32.const 0) (local.get 0x038))
+    (i64.store offset=0x039 align=1 (i32.const 0) (local.get 0x039))
+    (i64.store offset=0x03a align=1 (i32.const 0) (local.get 0x03a))
+    (i64.store offset=0x03b align=1 (i32.const 0) (local.get 0x03b))
+    (i64.store offset=0x03c align=1 (i32.const 0) (local.get 0x03c))
+    (i64.store offset=0x03d align=1 (i32.const 0) (local.get 0x03d))
+    (i64.store offset=0x03e align=1 (i32.const 0) (local.get 0x03e))
+    (i64.store offset=0x03f align=1 (i32.const 0) (local.get 0x03f))
+    (i64.store offset=0x040 align=1 (i32.const 0) (local.get 0x040))
+    (i64.store offset=0x041 align=1 (i32.const 0) (local.get 0x041))
+    (i64.store offset=0x042 align=1 (i32.const 0) (local.get 0x042))
+    (i64.store offset=0x043 align=1 (i32.const 0) (local.get 0x043))
+    (i64.store offset=0x044 align=1 (i32.const 0) (local.get 0x044))
+    (i64.store offset=0x045 align=1 (i32.const 0) (local.get 0x045))
+    (i64.store offset=0x046 align=1 (i32.const 0) (local.get 0x046))
+    (i64.store offset=0x047 align=1 (i32.const 0) (local.get 0x047))
+    (i64.store offset=0x048 align=1 (i32.const 0) (local.get 0x048))
+    (i64.store offset=0x049 align=1 (i32.const 0) (local.get 0x049))
+    (i64.store offset=0x04a align=1 (i32.const 0) (local.get 0x04a))
+    (i64.store offset=0x04b align=1 (i32.const 0) (local.get 0x04b))
+    (i64.store offset=0x04c align=1 (i32.const 0) (local.get 0x04c))
+    (i64.store offset=0x04d align=1 (i32.const 0) (local.get 0x04d))
+    (i64.store offset=0x04e align=1 (i32.const 0) (local.get 0x04e))
+    (i64.store offset=0x04f align=1 (i32.const 0) (local.get 0x04f))
+    (i64.store offset=0x050 align=1 (i32.const 0) (local.get 0x050))
+    (i64.store offset=0x051 align=1 (i32.const 0) (local.get 0x051))
+    (i64.store offset=0x052 align=1 (i32.const 0) (local.get 0x052))
+    (i64.store offset=0x053 align=1 (i32.const 0) (local.get 0x053))
+    (i64.store offset=0x054 align=1 (i32.const 0) (local.get 0x054))
+    (i64.store offset=0x055 align=1 (i32.const 0) (local.get 0x055))
+    (i64.store offset=0x056 align=1 (i32.const 0) (local.get 0x056))
+    (i64.store offset=0x057 align=1 (i32.const 0) (local.get 0x057))
+    (i64.store offset=0x058 align=1 (i32.const 0) (local.get 0x058))
+    (i64.store offset=0x059 align=1 (i32.const 0) (local.get 0x059))
+    (i64.store offset=0x05a align=1 (i32.const 0) (local.get 0x05a))
+    (i64.store offset=0x05b align=1 (i32.const 0) (local.get 0x05b))
+    (i64.store offset=0x05c align=1 (i32.const 0) (local.get 0x05c))
+    (i64.store offset=0x05d align=1 (i32.const 0) (local.get 0x05d))
+    (i64.store offset=0x05e align=1 (i32.const 0) (local.get 0x05e))
+    (i64.store offset=0x05f align=1 (i32.const 0) (local.get 0x05f))
+    (i64.store offset=0x060 align=1 (i32.const 0) (local.get 0x060))
+    (i64.store offset=0x061 align=1 (i32.const 0) (local.get 0x061))
+    (i64.store offset=0x062 align=1 (i32.const 0) (local.get 0x062))
+    (i64.store offset=0x063 align=1 (i32.const 0) (local.get 0x063))
+    (i64.store offset=0x064 align=1 (i32.const 0) (local.get 0x064))
+    (i64.store offset=0x065 align=1 (i32.const 0) (local.get 0x065))
+    (i64.store offset=0x066 align=1 (i32.const 0) (local.get 0x066))
+    (i64.store offset=0x067 align=1 (i32.const 0) (local.get 0x067))
+    (i64.store offset=0x068 align=1 (i32.const 0) (local.get 0x068))
+    (i64.store offset=0x069 align=1 (i32.const 0) (local.get 0x069))
+    (i64.store offset=0x06a align=1 (i32.const 0) (local.get 0x06a))
+    (i64.store offset=0x06b align=1 (i32.const 0) (local.get 0x06b))
+    (i64.store offset=0x06c align=1 (i32.const 0) (local.get 0x06c))
+    (i64.store offset=0x06d align=1 (i32.const 0) (local.get 0x06d))
+    (i64.store offset=0x06e align=1 (i32.const 0) (local.get 0x06e))
+    (i64.store offset=0x06f align=1 (i32.const 0) (local.get 0x06f))
+    (i64.store offset=0x070 align=1 (i32.const 0) (local.get 0x070))
+    (i64.store offset=0x071 align=1 (i32.const 0) (local.get 0x071))
+    (i64.store offset=0x072 align=1 (i32.const 0) (local.get 0x072))
+    (i64.store offset=0x073 align=1 (i32.const 0) (local.get 0x073))
+    (i64.store offset=0x074 align=1 (i32.const 0) (local.get 0x074))
+    (i64.store offset=0x075 align=1 (i32.const 0) (local.get 0x075))
+    (i64.store offset=0x076 align=1 (i32.const 0) (local.get 0x076))
+    (i64.store offset=0x077 align=1 (i32.const 0) (local.get 0x077))
+    (i64.store offset=0x078 align=1 (i32.const 0) (local.get 0x078))
+    (i64.store offset=0x079 align=1 (i32.const 0) (local.get 0x079))
+    (i64.store offset=0x07a align=1 (i32.const 0) (local.get 0x07a))
+    (i64.store offset=0x07b align=1 (i32.const 0) (local.get 0x07b))
+    (i64.store offset=0x07c align=1 (i32.const 0) (local.get 0x07c))
+    (i64.store offset=0x07d align=1 (i32.const 0) (local.get 0x07d))
+    (i64.store offset=0x07e align=1 (i32.const 0) (local.get 0x07e))
+    (i64.store offset=0x07f align=1 (i32.const 0) (local.get 0x07f))
+    (i64.store offset=0x080 align=1 (i32.const 0) (local.get 0x080))
+    (i64.store offset=0x081 align=1 (i32.const 0) (local.get 0x081))
+    (i64.store offset=0x082 align=1 (i32.const 0) (local.get 0x082))
+    (i64.store offset=0x083 align=1 (i32.const 0) (local.get 0x083))
+    (i64.store offset=0x084 align=1 (i32.const 0) (local.get 0x084))
+    (i64.store offset=0x085 align=1 (i32.const 0) (local.get 0x085))
+    (i64.store offset=0x086 align=1 (i32.const 0) (local.get 0x086))
+    (i64.store offset=0x087 align=1 (i32.const 0) (local.get 0x087))
+    (i64.store offset=0x088 align=1 (i32.const 0) (local.get 0x088))
+    (i64.store offset=0x089 align=1 (i32.const 0) (local.get 0x089))
+    (i64.store offset=0x08a align=1 (i32.const 0) (local.get 0x08a))
+    (i64.store offset=0x08b align=1 (i32.const 0) (local.get 0x08b))
+    (i64.store offset=0x08c align=1 (i32.const 0) (local.get 0x08c))
+    (i64.store offset=0x08d align=1 (i32.const 0) (local.get 0x08d))
+    (i64.store offset=0x08e align=1 (i32.const 0) (local.get 0x08e))
+    (i64.store offset=0x08f align=1 (i32.const 0) (local.get 0x08f))
+    (i64.store offset=0x090 align=1 (i32.const 0) (local.get 0x090))
+    (i64.store offset=0x091 align=1 (i32.const 0) (local.get 0x091))
+    (i64.store offset=0x092 align=1 (i32.const 0) (local.get 0x092))
+    (i64.store offset=0x093 align=1 (i32.const 0) (local.get 0x093))
+    (i64.store offset=0x094 align=1 (i32.const 0) (local.get 0x094))
+    (i64.store offset=0x095 align=1 (i32.const 0) (local.get 0x095))
+    (i64.store offset=0x096 align=1 (i32.const 0) (local.get 0x096))
+    (i64.store offset=0x097 align=1 (i32.const 0) (local.get 0x097))
+    (i64.store offset=0x098 align=1 (i32.const 0) (local.get 0x098))
+    (i64.store offset=0x099 align=1 (i32.const 0) (local.get 0x099))
+    (i64.store offset=0x09a align=1 (i32.const 0) (local.get 0x09a))
+    (i64.store offset=0x09b align=1 (i32.const 0) (local.get 0x09b))
+    (i64.store offset=0x09c align=1 (i32.const 0) (local.get 0x09c))
+    (i64.store offset=0x09d align=1 (i32.const 0) (local.get 0x09d))
+    (i64.store offset=0x09e align=1 (i32.const 0) (local.get 0x09e))
+    (i64.store offset=0x09f align=1 (i32.const 0) (local.get 0x09f))
+    (i64.store offset=0x0a0 align=1 (i32.const 0) (local.get 0x0a0))
+    (i64.store offset=0x0a1 align=1 (i32.const 0) (local.get 0x0a1))
+    (i64.store offset=0x0a2 align=1 (i32.const 0) (local.get 0x0a2))
+    (i64.store offset=0x0a3 align=1 (i32.const 0) (local.get 0x0a3))
+    (i64.store offset=0x0a4 align=1 (i32.const 0) (local.get 0x0a4))
+    (i64.store offset=0x0a5 align=1 (i32.const 0) (local.get 0x0a5))
+    (i64.store offset=0x0a6 align=1 (i32.const 0) (local.get 0x0a6))
+    (i64.store offset=0x0a7 align=1 (i32.const 0) (local.get 0x0a7))
+    (i64.store offset=0x0a8 align=1 (i32.const 0) (local.get 0x0a8))
+    (i64.store offset=0x0a9 align=1 (i32.const 0) (local.get 0x0a9))
+    (i64.store offset=0x0aa align=1 (i32.const 0) (local.get 0x0aa))
+    (i64.store offset=0x0ab align=1 (i32.const 0) (local.get 0x0ab))
+    (i64.store offset=0x0ac align=1 (i32.const 0) (local.get 0x0ac))
+    (i64.store offset=0x0ad align=1 (i32.const 0) (local.get 0x0ad))
+    (i64.store offset=0x0ae align=1 (i32.const 0) (local.get 0x0ae))
+    (i64.store offset=0x0af align=1 (i32.const 0) (local.get 0x0af))
+    (i64.store offset=0x0b0 align=1 (i32.const 0) (local.get 0x0b0))
+    (i64.store offset=0x0b1 align=1 (i32.const 0) (local.get 0x0b1))
+    (i64.store offset=0x0b2 align=1 (i32.const 0) (local.get 0x0b2))
+    (i64.store offset=0x0b3 align=1 (i32.const 0) (local.get 0x0b3))
+    (i64.store offset=0x0b4 align=1 (i32.const 0) (local.get 0x0b4))
+    (i64.store offset=0x0b5 align=1 (i32.const 0) (local.get 0x0b5))
+    (i64.store offset=0x0b6 align=1 (i32.const 0) (local.get 0x0b6))
+    (i64.store offset=0x0b7 align=1 (i32.const 0) (local.get 0x0b7))
+    (i64.store offset=0x0b8 align=1 (i32.const 0) (local.get 0x0b8))
+    (i64.store offset=0x0b9 align=1 (i32.const 0) (local.get 0x0b9))
+    (i64.store offset=0x0ba align=1 (i32.const 0) (local.get 0x0ba))
+    (i64.store offset=0x0bb align=1 (i32.const 0) (local.get 0x0bb))
+    (i64.store offset=0x0bc align=1 (i32.const 0) (local.get 0x0bc))
+    (i64.store offset=0x0bd align=1 (i32.const 0) (local.get 0x0bd))
+    (i64.store offset=0x0be align=1 (i32.const 0) (local.get 0x0be))
+    (i64.store offset=0x0bf align=1 (i32.const 0) (local.get 0x0bf))
+    (i64.store offset=0x0c0 align=1 (i32.const 0) (local.get 0x0c0))
+    (i64.store offset=0x0c1 align=1 (i32.const 0) (local.get 0x0c1))
+    (i64.store offset=0x0c2 align=1 (i32.const 0) (local.get 0x0c2))
+    (i64.store offset=0x0c3 align=1 (i32.const 0) (local.get 0x0c3))
+    (i64.store offset=0x0c4 align=1 (i32.const 0) (local.get 0x0c4))
+    (i64.store offset=0x0c5 align=1 (i32.const 0) (local.get 0x0c5))
+    (i64.store offset=0x0c6 align=1 (i32.const 0) (local.get 0x0c6))
+    (i64.store offset=0x0c7 align=1 (i32.const 0) (local.get 0x0c7))
+    (i64.store offset=0x0c8 align=1 (i32.const 0) (local.get 0x0c8))
+    (i64.store offset=0x0c9 align=1 (i32.const 0) (local.get 0x0c9))
+    (i64.store offset=0x0ca align=1 (i32.const 0) (local.get 0x0ca))
+    (i64.store offset=0x0cb align=1 (i32.const 0) (local.get 0x0cb))
+    (i64.store offset=0x0cc align=1 (i32.const 0) (local.get 0x0cc))
+    (i64.store offset=0x0cd align=1 (i32.const 0) (local.get 0x0cd))
+    (i64.store offset=0x0ce align=1 (i32.const 0) (local.get 0x0ce))
+    (i64.store offset=0x0cf align=1 (i32.const 0) (local.get 0x0cf))
+    (i64.store offset=0x0d0 align=1 (i32.const 0) (local.get 0x0d0))
+    (i64.store offset=0x0d1 align=1 (i32.const 0) (local.get 0x0d1))
+    (i64.store offset=0x0d2 align=1 (i32.const 0) (local.get 0x0d2))
+    (i64.store offset=0x0d3 align=1 (i32.const 0) (local.get 0x0d3))
+    (i64.store offset=0x0d4 align=1 (i32.const 0) (local.get 0x0d4))
+    (i64.store offset=0x0d5 align=1 (i32.const 0) (local.get 0x0d5))
+    (i64.store offset=0x0d6 align=1 (i32.const 0) (local.get 0x0d6))
+    (i64.store offset=0x0d7 align=1 (i32.const 0) (local.get 0x0d7))
+    (i64.store offset=0x0d8 align=1 (i32.const 0) (local.get 0x0d8))
+    (i64.store offset=0x0d9 align=1 (i32.const 0) (local.get 0x0d9))
+    (i64.store offset=0x0da align=1 (i32.const 0) (local.get 0x0da))
+    (i64.store offset=0x0db align=1 (i32.const 0) (local.get 0x0db))
+    (i64.store offset=0x0dc align=1 (i32.const 0) (local.get 0x0dc))
+    (i64.store offset=0x0dd align=1 (i32.const 0) (local.get 0x0dd))
+    (i64.store offset=0x0de align=1 (i32.const 0) (local.get 0x0de))
+    (i64.store offset=0x0df align=1 (i32.const 0) (local.get 0x0df))
+    (i64.store offset=0x0e0 align=1 (i32.const 0) (local.get 0x0e0))
+    (i64.store offset=0x0e1 align=1 (i32.const 0) (local.get 0x0e1))
+    (i64.store offset=0x0e2 align=1 (i32.const 0) (local.get 0x0e2))
+    (i64.store offset=0x0e3 align=1 (i32.const 0) (local.get 0x0e3))
+    (i64.store offset=0x0e4 align=1 (i32.const 0) (local.get 0x0e4))
+    (i64.store offset=0x0e5 align=1 (i32.const 0) (local.get 0x0e5))
+    (i64.store offset=0x0e6 align=1 (i32.const 0) (local.get 0x0e6))
+    (i64.store offset=0x0e7 align=1 (i32.const 0) (local.get 0x0e7))
+    (i64.store offset=0x0e8 align=1 (i32.const 0) (local.get 0x0e8))
+    (i64.store offset=0x0e9 align=1 (i32.const 0) (local.get 0x0e9))
+    (i64.store offset=0x0ea align=1 (i32.const 0) (local.get 0x0ea))
+    (i64.store offset=0x0eb align=1 (i32.const 0) (local.get 0x0eb))
+    (i64.store offset=0x0ec align=1 (i32.const 0) (local.get 0x0ec))
+    (i64.store offset=0x0ed align=1 (i32.const 0) (local.get 0x0ed))
+    (i64.store offset=0x0ee align=1 (i32.const 0) (local.get 0x0ee))
+    (i64.store offset=0x0ef align=1 (i32.const 0) (local.get 0x0ef))
+    (i64.store offset=0x0f0 align=1 (i32.const 0) (local.get 0x0f0))
+    (i64.store offset=0x0f1 align=1 (i32.const 0) (local.get 0x0f1))
+    (i64.store offset=0x0f2 align=1 (i32.const 0) (local.get 0x0f2))
+    (i64.store offset=0x0f3 align=1 (i32.const 0) (local.get 0x0f3))
+    (i64.store offset=0x0f4 align=1 (i32.const 0) (local.get 0x0f4))
+    (i64.store offset=0x0f5 align=1 (i32.const 0) (local.get 0x0f5))
+    (i64.store offset=0x0f6 align=1 (i32.const 0) (local.get 0x0f6))
+    (i64.store offset=0x0f7 align=1 (i32.const 0) (local.get 0x0f7))
+    (i64.store offset=0x0f8 align=1 (i32.const 0) (local.get 0x0f8))
+    (i64.store offset=0x0f9 align=1 (i32.const 0) (local.get 0x0f9))
+    (i64.store offset=0x0fa align=1 (i32.const 0) (local.get 0x0fa))
+    (i64.store offset=0x0fb align=1 (i32.const 0) (local.get 0x0fb))
+    (i64.store offset=0x0fc align=1 (i32.const 0) (local.get 0x0fc))
+    (i64.store offset=0x0fd align=1 (i32.const 0) (local.get 0x0fd))
+    (i64.store offset=0x0fe align=1 (i32.const 0) (local.get 0x0fe))
+    (i64.store offset=0x0ff align=1 (i32.const 0) (local.get 0x0ff))
+    (i64.store offset=0x100 align=1 (i32.const 0) (local.get 0x100))
+    (i64.store offset=0x101 align=1 (i32.const 0) (local.get 0x101))
+    (i64.store offset=0x102 align=1 (i32.const 0) (local.get 0x102))
+    (i64.store offset=0x103 align=1 (i32.const 0) (local.get 0x103))
+    (i64.store offset=0x104 align=1 (i32.const 0) (local.get 0x104))
+    (i64.store offset=0x105 align=1 (i32.const 0) (local.get 0x105))
+    (i64.store offset=0x106 align=1 (i32.const 0) (local.get 0x106))
+    (i64.store offset=0x107 align=1 (i32.const 0) (local.get 0x107))
+    (i64.store offset=0x108 align=1 (i32.const 0) (local.get 0x108))
+    (i64.store offset=0x109 align=1 (i32.const 0) (local.get 0x109))
+    (i64.store offset=0x10a align=1 (i32.const 0) (local.get 0x10a))
+    (i64.store offset=0x10b align=1 (i32.const 0) (local.get 0x10b))
+    (i64.store offset=0x10c align=1 (i32.const 0) (local.get 0x10c))
+    (i64.store offset=0x10d align=1 (i32.const 0) (local.get 0x10d))
+    (i64.store offset=0x10e align=1 (i32.const 0) (local.get 0x10e))
+    (i64.store offset=0x10f align=1 (i32.const 0) (local.get 0x10f))
+    (i64.store offset=0x110 align=1 (i32.const 0) (local.get 0x110))
+    (i64.store offset=0x111 align=1 (i32.const 0) (local.get 0x111))
+    (i64.store offset=0x112 align=1 (i32.const 0) (local.get 0x112))
+    (i64.store offset=0x113 align=1 (i32.const 0) (local.get 0x113))
+    (i64.store offset=0x114 align=1 (i32.const 0) (local.get 0x114))
+    (i64.store offset=0x115 align=1 (i32.const 0) (local.get 0x115))
+    (i64.store offset=0x116 align=1 (i32.const 0) (local.get 0x116))
+    (i64.store offset=0x117 align=1 (i32.const 0) (local.get 0x117))
+    (i64.store offset=0x118 align=1 (i32.const 0) (local.get 0x118))
+    (i64.store offset=0x119 align=1 (i32.const 0) (local.get 0x119))
+    (i64.store offset=0x11a align=1 (i32.const 0) (local.get 0x11a))
+    (i64.store offset=0x11b align=1 (i32.const 0) (local.get 0x11b))
+    (i64.store offset=0x11c align=1 (i32.const 0) (local.get 0x11c))
+    (i64.store offset=0x11d align=1 (i32.const 0) (local.get 0x11d))
+    (i64.store offset=0x11e align=1 (i32.const 0) (local.get 0x11e))
+    (i64.store offset=0x11f align=1 (i32.const 0) (local.get 0x11f))
+    (i64.store offset=0x120 align=1 (i32.const 0) (local.get 0x120))
+    (i64.store offset=0x121 align=1 (i32.const 0) (local.get 0x121))
+    (i64.store offset=0x122 align=1 (i32.const 0) (local.get 0x122))
+    (i64.store offset=0x123 align=1 (i32.const 0) (local.get 0x123))
+    (i64.store offset=0x124 align=1 (i32.const 0) (local.get 0x124))
+    (i64.store offset=0x125 align=1 (i32.const 0) (local.get 0x125))
+    (i64.store offset=0x126 align=1 (i32.const 0) (local.get 0x126))
+    (i64.store offset=0x127 align=1 (i32.const 0) (local.get 0x127))
+    (i64.store offset=0x128 align=1 (i32.const 0) (local.get 0x128))
+    (i64.store offset=0x129 align=1 (i32.const 0) (local.get 0x129))
+    (i64.store offset=0x12a align=1 (i32.const 0) (local.get 0x12a))
+    (i64.store offset=0x12b align=1 (i32.const 0) (local.get 0x12b))
+    (i64.store offset=0x12c align=1 (i32.const 0) (local.get 0x12c))
+    (i64.store offset=0x12d align=1 (i32.const 0) (local.get 0x12d))
+    (i64.store offset=0x12e align=1 (i32.const 0) (local.get 0x12e))
+    (i64.store offset=0x12f align=1 (i32.const 0) (local.get 0x12f))
+    (i64.store offset=0x130 align=1 (i32.const 0) (local.get 0x130))
+    (i64.store offset=0x131 align=1 (i32.const 0) (local.get 0x131))
+    (i64.store offset=0x132 align=1 (i32.const 0) (local.get 0x132))
+    (i64.store offset=0x133 align=1 (i32.const 0) (local.get 0x133))
+    (i64.store offset=0x134 align=1 (i32.const 0) (local.get 0x134))
+    (i64.store offset=0x135 align=1 (i32.const 0) (local.get 0x135))
+    (i64.store offset=0x136 align=1 (i32.const 0) (local.get 0x136))
+    (i64.store offset=0x137 align=1 (i32.const 0) (local.get 0x137))
+    (i64.store offset=0x138 align=1 (i32.const 0) (local.get 0x138))
+    (i64.store offset=0x139 align=1 (i32.const 0) (local.get 0x139))
+    (i64.store offset=0x13a align=1 (i32.const 0) (local.get 0x13a))
+    (i64.store offset=0x13b align=1 (i32.const 0) (local.get 0x13b))
+    (i64.store offset=0x13c align=1 (i32.const 0) (local.get 0x13c))
+    (i64.store offset=0x13d align=1 (i32.const 0) (local.get 0x13d))
+    (i64.store offset=0x13e align=1 (i32.const 0) (local.get 0x13e))
+    (i64.store offset=0x13f align=1 (i32.const 0) (local.get 0x13f))
+    (i64.store offset=0x140 align=1 (i32.const 0) (local.get 0x140))
+    (i64.store offset=0x141 align=1 (i32.const 0) (local.get 0x141))
+    (i64.store offset=0x142 align=1 (i32.const 0) (local.get 0x142))
+    (i64.store offset=0x143 align=1 (i32.const 0) (local.get 0x143))
+    (i64.store offset=0x144 align=1 (i32.const 0) (local.get 0x144))
+    (i64.store offset=0x145 align=1 (i32.const 0) (local.get 0x145))
+    (i64.store offset=0x146 align=1 (i32.const 0) (local.get 0x146))
+    (i64.store offset=0x147 align=1 (i32.const 0) (local.get 0x147))
+    (i64.store offset=0x148 align=1 (i32.const 0) (local.get 0x148))
+    (i64.store offset=0x149 align=1 (i32.const 0) (local.get 0x149))
+    (i64.store offset=0x14a align=1 (i32.const 0) (local.get 0x14a))
+    (i64.store offset=0x14b align=1 (i32.const 0) (local.get 0x14b))
+    (i64.store offset=0x14c align=1 (i32.const 0) (local.get 0x14c))
+    (i64.store offset=0x14d align=1 (i32.const 0) (local.get 0x14d))
+    (i64.store offset=0x14e align=1 (i32.const 0) (local.get 0x14e))
+    (i64.store offset=0x14f align=1 (i32.const 0) (local.get 0x14f))
+    (i64.store offset=0x150 align=1 (i32.const 0) (local.get 0x150))
+    (i64.store offset=0x151 align=1 (i32.const 0) (local.get 0x151))
+    (i64.store offset=0x152 align=1 (i32.const 0) (local.get 0x152))
+    (i64.store offset=0x153 align=1 (i32.const 0) (local.get 0x153))
+    (i64.store offset=0x154 align=1 (i32.const 0) (local.get 0x154))
+    (i64.store offset=0x155 align=1 (i32.const 0) (local.get 0x155))
+    (i64.store offset=0x156 align=1 (i32.const 0) (local.get 0x156))
+    (i64.store offset=0x157 align=1 (i32.const 0) (local.get 0x157))
+    (i64.store offset=0x158 align=1 (i32.const 0) (local.get 0x158))
+    (i64.store offset=0x159 align=1 (i32.const 0) (local.get 0x159))
+    (i64.store offset=0x15a align=1 (i32.const 0) (local.get 0x15a))
+    (i64.store offset=0x15b align=1 (i32.const 0) (local.get 0x15b))
+    (i64.store offset=0x15c align=1 (i32.const 0) (local.get 0x15c))
+    (i64.store offset=0x15d align=1 (i32.const 0) (local.get 0x15d))
+    (i64.store offset=0x15e align=1 (i32.const 0) (local.get 0x15e))
+    (i64.store offset=0x15f align=1 (i32.const 0) (local.get 0x15f))
+    (i64.store offset=0x160 align=1 (i32.const 0) (local.get 0x160))
+    (i64.store offset=0x161 align=1 (i32.const 0) (local.get 0x161))
+    (i64.store offset=0x162 align=1 (i32.const 0) (local.get 0x162))
+    (i64.store offset=0x163 align=1 (i32.const 0) (local.get 0x163))
+    (i64.store offset=0x164 align=1 (i32.const 0) (local.get 0x164))
+    (i64.store offset=0x165 align=1 (i32.const 0) (local.get 0x165))
+    (i64.store offset=0x166 align=1 (i32.const 0) (local.get 0x166))
+    (i64.store offset=0x167 align=1 (i32.const 0) (local.get 0x167))
+    (i64.store offset=0x168 align=1 (i32.const 0) (local.get 0x168))
+    (i64.store offset=0x169 align=1 (i32.const 0) (local.get 0x169))
+    (i64.store offset=0x16a align=1 (i32.const 0) (local.get 0x16a))
+    (i64.store offset=0x16b align=1 (i32.const 0) (local.get 0x16b))
+    (i64.store offset=0x16c align=1 (i32.const 0) (local.get 0x16c))
+    (i64.store offset=0x16d align=1 (i32.const 0) (local.get 0x16d))
+    (i64.store offset=0x16e align=1 (i32.const 0) (local.get 0x16e))
+    (i64.store offset=0x16f align=1 (i32.const 0) (local.get 0x16f))
+    (i64.store offset=0x170 align=1 (i32.const 0) (local.get 0x170))
+    (i64.store offset=0x171 align=1 (i32.const 0) (local.get 0x171))
+    (i64.store offset=0x172 align=1 (i32.const 0) (local.get 0x172))
+    (i64.store offset=0x173 align=1 (i32.const 0) (local.get 0x173))
+    (i64.store offset=0x174 align=1 (i32.const 0) (local.get 0x174))
+    (i64.store offset=0x175 align=1 (i32.const 0) (local.get 0x175))
+    (i64.store offset=0x176 align=1 (i32.const 0) (local.get 0x176))
+    (i64.store offset=0x177 align=1 (i32.const 0) (local.get 0x177))
+    (i64.store offset=0x178 align=1 (i32.const 0) (local.get 0x178))
+    (i64.store offset=0x179 align=1 (i32.const 0) (local.get 0x179))
+    (i64.store offset=0x17a align=1 (i32.const 0) (local.get 0x17a))
+    (i64.store offset=0x17b align=1 (i32.const 0) (local.get 0x17b))
+    (i64.store offset=0x17c align=1 (i32.const 0) (local.get 0x17c))
+    (i64.store offset=0x17d align=1 (i32.const 0) (local.get 0x17d))
+    (i64.store offset=0x17e align=1 (i32.const 0) (local.get 0x17e))
+    (i64.store offset=0x17f align=1 (i32.const 0) (local.get 0x17f))
+    (i64.store offset=0x180 align=1 (i32.const 0) (local.get 0x180))
+    (i64.store offset=0x181 align=1 (i32.const 0) (local.get 0x181))
+    (i64.store offset=0x182 align=1 (i32.const 0) (local.get 0x182))
+    (i64.store offset=0x183 align=1 (i32.const 0) (local.get 0x183))
+    (i64.store offset=0x184 align=1 (i32.const 0) (local.get 0x184))
+    (i64.store offset=0x185 align=1 (i32.const 0) (local.get 0x185))
+    (i64.store offset=0x186 align=1 (i32.const 0) (local.get 0x186))
+    (i64.store offset=0x187 align=1 (i32.const 0) (local.get 0x187))
+    (i64.store offset=0x188 align=1 (i32.const 0) (local.get 0x188))
+    (i64.store offset=0x189 align=1 (i32.const 0) (local.get 0x189))
+    (i64.store offset=0x18a align=1 (i32.const 0) (local.get 0x18a))
+    (i64.store offset=0x18b align=1 (i32.const 0) (local.get 0x18b))
+    (i64.store offset=0x18c align=1 (i32.const 0) (local.get 0x18c))
+    (i64.store offset=0x18d align=1 (i32.const 0) (local.get 0x18d))
+    (i64.store offset=0x18e align=1 (i32.const 0) (local.get 0x18e))
+    (i64.store offset=0x18f align=1 (i32.const 0) (local.get 0x18f))
+    (i64.store offset=0x190 align=1 (i32.const 0) (local.get 0x190))
+    (i64.store offset=0x191 align=1 (i32.const 0) (local.get 0x191))
+    (i64.store offset=0x192 align=1 (i32.const 0) (local.get 0x192))
+    (i64.store offset=0x193 align=1 (i32.const 0) (local.get 0x193))
+    (i64.store offset=0x194 align=1 (i32.const 0) (local.get 0x194))
+    (i64.store offset=0x195 align=1 (i32.const 0) (local.get 0x195))
+    (i64.store offset=0x196 align=1 (i32.const 0) (local.get 0x196))
+    (i64.store offset=0x197 align=1 (i32.const 0) (local.get 0x197))
+    (i64.store offset=0x198 align=1 (i32.const 0) (local.get 0x198))
+    (i64.store offset=0x199 align=1 (i32.const 0) (local.get 0x199))
+    (i64.store offset=0x19a align=1 (i32.const 0) (local.get 0x19a))
+    (i64.store offset=0x19b align=1 (i32.const 0) (local.get 0x19b))
+    (i64.store offset=0x19c align=1 (i32.const 0) (local.get 0x19c))
+    (i64.store offset=0x19d align=1 (i32.const 0) (local.get 0x19d))
+    (i64.store offset=0x19e align=1 (i32.const 0) (local.get 0x19e))
+    (i64.store offset=0x19f align=1 (i32.const 0) (local.get 0x19f))
+    (i64.store offset=0x1a0 align=1 (i32.const 0) (local.get 0x1a0))
+    (i64.store offset=0x1a1 align=1 (i32.const 0) (local.get 0x1a1))
+    (i64.store offset=0x1a2 align=1 (i32.const 0) (local.get 0x1a2))
+    (i64.store offset=0x1a3 align=1 (i32.const 0) (local.get 0x1a3))
+    (i64.store offset=0x1a4 align=1 (i32.const 0) (local.get 0x1a4))
+    (i64.store offset=0x1a5 align=1 (i32.const 0) (local.get 0x1a5))
+    (i64.store offset=0x1a6 align=1 (i32.const 0) (local.get 0x1a6))
+    (i64.store offset=0x1a7 align=1 (i32.const 0) (local.get 0x1a7))
+    (i64.store offset=0x1a8 align=1 (i32.const 0) (local.get 0x1a8))
+    (i64.store offset=0x1a9 align=1 (i32.const 0) (local.get 0x1a9))
+    (i64.store offset=0x1aa align=1 (i32.const 0) (local.get 0x1aa))
+    (i64.store offset=0x1ab align=1 (i32.const 0) (local.get 0x1ab))
+    (i64.store offset=0x1ac align=1 (i32.const 0) (local.get 0x1ac))
+    (i64.store offset=0x1ad align=1 (i32.const 0) (local.get 0x1ad))
+    (i64.store offset=0x1ae align=1 (i32.const 0) (local.get 0x1ae))
+    (i64.store offset=0x1af align=1 (i32.const 0) (local.get 0x1af))
+    (i64.store offset=0x1b0 align=1 (i32.const 0) (local.get 0x1b0))
+    (i64.store offset=0x1b1 align=1 (i32.const 0) (local.get 0x1b1))
+    (i64.store offset=0x1b2 align=1 (i32.const 0) (local.get 0x1b2))
+    (i64.store offset=0x1b3 align=1 (i32.const 0) (local.get 0x1b3))
+    (i64.store offset=0x1b4 align=1 (i32.const 0) (local.get 0x1b4))
+    (i64.store offset=0x1b5 align=1 (i32.const 0) (local.get 0x1b5))
+    (i64.store offset=0x1b6 align=1 (i32.const 0) (local.get 0x1b6))
+    (i64.store offset=0x1b7 align=1 (i32.const 0) (local.get 0x1b7))
+    (i64.store offset=0x1b8 align=1 (i32.const 0) (local.get 0x1b8))
+    (i64.store offset=0x1b9 align=1 (i32.const 0) (local.get 0x1b9))
+    (i64.store offset=0x1ba align=1 (i32.const 0) (local.get 0x1ba))
+    (i64.store offset=0x1bb align=1 (i32.const 0) (local.get 0x1bb))
+    (i64.store offset=0x1bc align=1 (i32.const 0) (local.get 0x1bc))
+    (i64.store offset=0x1bd align=1 (i32.const 0) (local.get 0x1bd))
+    (i64.store offset=0x1be align=1 (i32.const 0) (local.get 0x1be))
+    (i64.store offset=0x1bf align=1 (i32.const 0) (local.get 0x1bf))
+    (i64.store offset=0x1c0 align=1 (i32.const 0) (local.get 0x1c0))
+    (i64.store offset=0x1c1 align=1 (i32.const 0) (local.get 0x1c1))
+    (i64.store offset=0x1c2 align=1 (i32.const 0) (local.get 0x1c2))
+    (i64.store offset=0x1c3 align=1 (i32.const 0) (local.get 0x1c3))
+    (i64.store offset=0x1c4 align=1 (i32.const 0) (local.get 0x1c4))
+    (i64.store offset=0x1c5 align=1 (i32.const 0) (local.get 0x1c5))
+    (i64.store offset=0x1c6 align=1 (i32.const 0) (local.get 0x1c6))
+    (i64.store offset=0x1c7 align=1 (i32.const 0) (local.get 0x1c7))
+    (i64.store offset=0x1c8 align=1 (i32.const 0) (local.get 0x1c8))
+    (i64.store offset=0x1c9 align=1 (i32.const 0) (local.get 0x1c9))
+    (i64.store offset=0x1ca align=1 (i32.const 0) (local.get 0x1ca))
+    (i64.store offset=0x1cb align=1 (i32.const 0) (local.get 0x1cb))
+    (i64.store offset=0x1cc align=1 (i32.const 0) (local.get 0x1cc))
+    (i64.store offset=0x1cd align=1 (i32.const 0) (local.get 0x1cd))
+    (i64.store offset=0x1ce align=1 (i32.const 0) (local.get 0x1ce))
+    (i64.store offset=0x1cf align=1 (i32.const 0) (local.get 0x1cf))
+    (i64.store offset=0x1d0 align=1 (i32.const 0) (local.get 0x1d0))
+    (i64.store offset=0x1d1 align=1 (i32.const 0) (local.get 0x1d1))
+    (i64.store offset=0x1d2 align=1 (i32.const 0) (local.get 0x1d2))
+    (i64.store offset=0x1d3 align=1 (i32.const 0) (local.get 0x1d3))
+    (i64.store offset=0x1d4 align=1 (i32.const 0) (local.get 0x1d4))
+    (i64.store offset=0x1d5 align=1 (i32.const 0) (local.get 0x1d5))
+    (i64.store offset=0x1d6 align=1 (i32.const 0) (local.get 0x1d6))
+    (i64.store offset=0x1d7 align=1 (i32.const 0) (local.get 0x1d7))
+    (i64.store offset=0x1d8 align=1 (i32.const 0) (local.get 0x1d8))
+    (i64.store offset=0x1d9 align=1 (i32.const 0) (local.get 0x1d9))
+    (i64.store offset=0x1da align=1 (i32.const 0) (local.get 0x1da))
+    (i64.store offset=0x1db align=1 (i32.const 0) (local.get 0x1db))
+    (i64.store offset=0x1dc align=1 (i32.const 0) (local.get 0x1dc))
+    (i64.store offset=0x1dd align=1 (i32.const 0) (local.get 0x1dd))
+    (i64.store offset=0x1de align=1 (i32.const 0) (local.get 0x1de))
+    (i64.store offset=0x1df align=1 (i32.const 0) (local.get 0x1df))
+    (i64.store offset=0x1e0 align=1 (i32.const 0) (local.get 0x1e0))
+    (i64.store offset=0x1e1 align=1 (i32.const 0) (local.get 0x1e1))
+    (i64.store offset=0x1e2 align=1 (i32.const 0) (local.get 0x1e2))
+    (i64.store offset=0x1e3 align=1 (i32.const 0) (local.get 0x1e3))
+    (i64.store offset=0x1e4 align=1 (i32.const 0) (local.get 0x1e4))
+    (i64.store offset=0x1e5 align=1 (i32.const 0) (local.get 0x1e5))
+    (i64.store offset=0x1e6 align=1 (i32.const 0) (local.get 0x1e6))
+    (i64.store offset=0x1e7 align=1 (i32.const 0) (local.get 0x1e7))
+    (i64.store offset=0x1e8 align=1 (i32.const 0) (local.get 0x1e8))
+    (i64.store offset=0x1e9 align=1 (i32.const 0) (local.get 0x1e9))
+    (i64.store offset=0x1ea align=1 (i32.const 0) (local.get 0x1ea))
+    (i64.store offset=0x1eb align=1 (i32.const 0) (local.get 0x1eb))
+    (i64.store offset=0x1ec align=1 (i32.const 0) (local.get 0x1ec))
+    (i64.store offset=0x1ed align=1 (i32.const 0) (local.get 0x1ed))
+    (i64.store offset=0x1ee align=1 (i32.const 0) (local.get 0x1ee))
+    (i64.store offset=0x1ef align=1 (i32.const 0) (local.get 0x1ef))
+    (i64.store offset=0x1f0 align=1 (i32.const 0) (local.get 0x1f0))
+    (i64.store offset=0x1f1 align=1 (i32.const 0) (local.get 0x1f1))
+    (i64.store offset=0x1f2 align=1 (i32.const 0) (local.get 0x1f2))
+    (i64.store offset=0x1f3 align=1 (i32.const 0) (local.get 0x1f3))
+    (i64.store offset=0x1f4 align=1 (i32.const 0) (local.get 0x1f4))
+    (i64.store offset=0x1f5 align=1 (i32.const 0) (local.get 0x1f5))
+    (i64.store offset=0x1f6 align=1 (i32.const 0) (local.get 0x1f6))
+    (i64.store offset=0x1f7 align=1 (i32.const 0) (local.get 0x1f7))
+    (i64.store offset=0x1f8 align=1 (i32.const 0) (local.get 0x1f8))
+    (i64.store offset=0x1f9 align=1 (i32.const 0) (local.get 0x1f9))
+    (i64.store offset=0x1fa align=1 (i32.const 0) (local.get 0x1fa))
+    (i64.store offset=0x1fb align=1 (i32.const 0) (local.get 0x1fb))
+    (i64.store offset=0x1fc align=1 (i32.const 0) (local.get 0x1fc))
+    (i64.store offset=0x1fd align=1 (i32.const 0) (local.get 0x1fd))
+    (i64.store offset=0x1fe align=1 (i32.const 0) (local.get 0x1fe))
+    (i64.store offset=0x1ff align=1 (i32.const 0) (local.get 0x1ff))
+    (i64.store offset=0x200 align=1 (i32.const 0) (local.get 0x200))
+    (i64.store offset=0x201 align=1 (i32.const 0) (local.get 0x201))
+    (i64.store offset=0x202 align=1 (i32.const 0) (local.get 0x202))
+    (i64.store offset=0x203 align=1 (i32.const 0) (local.get 0x203))
+    (i64.store offset=0x204 align=1 (i32.const 0) (local.get 0x204))
+    (i64.store offset=0x205 align=1 (i32.const 0) (local.get 0x205))
+    (i64.store offset=0x206 align=1 (i32.const 0) (local.get 0x206))
+    (i64.store offset=0x207 align=1 (i32.const 0) (local.get 0x207))
+    (i64.store offset=0x208 align=1 (i32.const 0) (local.get 0x208))
+    (i64.store offset=0x209 align=1 (i32.const 0) (local.get 0x209))
+    (i64.store offset=0x20a align=1 (i32.const 0) (local.get 0x20a))
+    (i64.store offset=0x20b align=1 (i32.const 0) (local.get 0x20b))
+    (i64.store offset=0x20c align=1 (i32.const 0) (local.get 0x20c))
+    (i64.store offset=0x20d align=1 (i32.const 0) (local.get 0x20d))
+    (i64.store offset=0x20e align=1 (i32.const 0) (local.get 0x20e))
+    (i64.store offset=0x20f align=1 (i32.const 0) (local.get 0x20f))
+    (i64.store offset=0x210 align=1 (i32.const 0) (local.get 0x210))
+    (i64.store offset=0x211 align=1 (i32.const 0) (local.get 0x211))
+    (i64.store offset=0x212 align=1 (i32.const 0) (local.get 0x212))
+    (i64.store offset=0x213 align=1 (i32.const 0) (local.get 0x213))
+    (i64.store offset=0x214 align=1 (i32.const 0) (local.get 0x214))
+    (i64.store offset=0x215 align=1 (i32.const 0) (local.get 0x215))
+    (i64.store offset=0x216 align=1 (i32.const 0) (local.get 0x216))
+    (i64.store offset=0x217 align=1 (i32.const 0) (local.get 0x217))
+    (i64.store offset=0x218 align=1 (i32.const 0) (local.get 0x218))
+    (i64.store offset=0x219 align=1 (i32.const 0) (local.get 0x219))
+    (i64.store offset=0x21a align=1 (i32.const 0) (local.get 0x21a))
+    (i64.store offset=0x21b align=1 (i32.const 0) (local.get 0x21b))
+    (i64.store offset=0x21c align=1 (i32.const 0) (local.get 0x21c))
+    (i64.store offset=0x21d align=1 (i32.const 0) (local.get 0x21d))
+    (i64.store offset=0x21e align=1 (i32.const 0) (local.get 0x21e))
+    (i64.store offset=0x21f align=1 (i32.const 0) (local.get 0x21f))
+    (i64.store offset=0x220 align=1 (i32.const 0) (local.get 0x220))
+    (i64.store offset=0x221 align=1 (i32.const 0) (local.get 0x221))
+    (i64.store offset=0x222 align=1 (i32.const 0) (local.get 0x222))
+    (i64.store offset=0x223 align=1 (i32.const 0) (local.get 0x223))
+    (i64.store offset=0x224 align=1 (i32.const 0) (local.get 0x224))
+    (i64.store offset=0x225 align=1 (i32.const 0) (local.get 0x225))
+    (i64.store offset=0x226 align=1 (i32.const 0) (local.get 0x226))
+    (i64.store offset=0x227 align=1 (i32.const 0) (local.get 0x227))
+    (i64.store offset=0x228 align=1 (i32.const 0) (local.get 0x228))
+    (i64.store offset=0x229 align=1 (i32.const 0) (local.get 0x229))
+    (i64.store offset=0x22a align=1 (i32.const 0) (local.get 0x22a))
+    (i64.store offset=0x22b align=1 (i32.const 0) (local.get 0x22b))
+    (i64.store offset=0x22c align=1 (i32.const 0) (local.get 0x22c))
+    (i64.store offset=0x22d align=1 (i32.const 0) (local.get 0x22d))
+    (i64.store offset=0x22e align=1 (i32.const 0) (local.get 0x22e))
+    (i64.store offset=0x22f align=1 (i32.const 0) (local.get 0x22f))
+    (i64.store offset=0x230 align=1 (i32.const 0) (local.get 0x230))
+    (i64.store offset=0x231 align=1 (i32.const 0) (local.get 0x231))
+    (i64.store offset=0x232 align=1 (i32.const 0) (local.get 0x232))
+    (i64.store offset=0x233 align=1 (i32.const 0) (local.get 0x233))
+    (i64.store offset=0x234 align=1 (i32.const 0) (local.get 0x234))
+    (i64.store offset=0x235 align=1 (i32.const 0) (local.get 0x235))
+    (i64.store offset=0x236 align=1 (i32.const 0) (local.get 0x236))
+    (i64.store offset=0x237 align=1 (i32.const 0) (local.get 0x237))
+    (i64.store offset=0x238 align=1 (i32.const 0) (local.get 0x238))
+    (i64.store offset=0x239 align=1 (i32.const 0) (local.get 0x239))
+    (i64.store offset=0x23a align=1 (i32.const 0) (local.get 0x23a))
+    (i64.store offset=0x23b align=1 (i32.const 0) (local.get 0x23b))
+    (i64.store offset=0x23c align=1 (i32.const 0) (local.get 0x23c))
+    (i64.store offset=0x23d align=1 (i32.const 0) (local.get 0x23d))
+    (i64.store offset=0x23e align=1 (i32.const 0) (local.get 0x23e))
+    (i64.store offset=0x23f align=1 (i32.const 0) (local.get 0x23f))
+    (i64.store offset=0x240 align=1 (i32.const 0) (local.get 0x240))
+    (i64.store offset=0x241 align=1 (i32.const 0) (local.get 0x241))
+    (i64.store offset=0x242 align=1 (i32.const 0) (local.get 0x242))
+    (i64.store offset=0x243 align=1 (i32.const 0) (local.get 0x243))
+    (i64.store offset=0x244 align=1 (i32.const 0) (local.get 0x244))
+    (i64.store offset=0x245 align=1 (i32.const 0) (local.get 0x245))
+    (i64.store offset=0x246 align=1 (i32.const 0) (local.get 0x246))
+    (i64.store offset=0x247 align=1 (i32.const 0) (local.get 0x247))
+    (i64.store offset=0x248 align=1 (i32.const 0) (local.get 0x248))
+    (i64.store offset=0x249 align=1 (i32.const 0) (local.get 0x249))
+    (i64.store offset=0x24a align=1 (i32.const 0) (local.get 0x24a))
+    (i64.store offset=0x24b align=1 (i32.const 0) (local.get 0x24b))
+    (i64.store offset=0x24c align=1 (i32.const 0) (local.get 0x24c))
+    (i64.store offset=0x24d align=1 (i32.const 0) (local.get 0x24d))
+    (i64.store offset=0x24e align=1 (i32.const 0) (local.get 0x24e))
+    (i64.store offset=0x24f align=1 (i32.const 0) (local.get 0x24f))
+    (i64.store offset=0x250 align=1 (i32.const 0) (local.get 0x250))
+    (i64.store offset=0x251 align=1 (i32.const 0) (local.get 0x251))
+    (i64.store offset=0x252 align=1 (i32.const 0) (local.get 0x252))
+    (i64.store offset=0x253 align=1 (i32.const 0) (local.get 0x253))
+    (i64.store offset=0x254 align=1 (i32.const 0) (local.get 0x254))
+    (i64.store offset=0x255 align=1 (i32.const 0) (local.get 0x255))
+    (i64.store offset=0x256 align=1 (i32.const 0) (local.get 0x256))
+    (i64.store offset=0x257 align=1 (i32.const 0) (local.get 0x257))
+    (i64.store offset=0x258 align=1 (i32.const 0) (local.get 0x258))
+    (i64.store offset=0x259 align=1 (i32.const 0) (local.get 0x259))
+    (i64.store offset=0x25a align=1 (i32.const 0) (local.get 0x25a))
+    (i64.store offset=0x25b align=1 (i32.const 0) (local.get 0x25b))
+    (i64.store offset=0x25c align=1 (i32.const 0) (local.get 0x25c))
+    (i64.store offset=0x25d align=1 (i32.const 0) (local.get 0x25d))
+    (i64.store offset=0x25e align=1 (i32.const 0) (local.get 0x25e))
+    (i64.store offset=0x25f align=1 (i32.const 0) (local.get 0x25f))
+    (i64.store offset=0x260 align=1 (i32.const 0) (local.get 0x260))
+    (i64.store offset=0x261 align=1 (i32.const 0) (local.get 0x261))
+    (i64.store offset=0x262 align=1 (i32.const 0) (local.get 0x262))
+    (i64.store offset=0x263 align=1 (i32.const 0) (local.get 0x263))
+    (i64.store offset=0x264 align=1 (i32.const 0) (local.get 0x264))
+    (i64.store offset=0x265 align=1 (i32.const 0) (local.get 0x265))
+    (i64.store offset=0x266 align=1 (i32.const 0) (local.get 0x266))
+    (i64.store offset=0x267 align=1 (i32.const 0) (local.get 0x267))
+    (i64.store offset=0x268 align=1 (i32.const 0) (local.get 0x268))
+    (i64.store offset=0x269 align=1 (i32.const 0) (local.get 0x269))
+    (i64.store offset=0x26a align=1 (i32.const 0) (local.get 0x26a))
+    (i64.store offset=0x26b align=1 (i32.const 0) (local.get 0x26b))
+    (i64.store offset=0x26c align=1 (i32.const 0) (local.get 0x26c))
+    (i64.store offset=0x26d align=1 (i32.const 0) (local.get 0x26d))
+    (i64.store offset=0x26e align=1 (i32.const 0) (local.get 0x26e))
+    (i64.store offset=0x26f align=1 (i32.const 0) (local.get 0x26f))
+    (i64.store offset=0x270 align=1 (i32.const 0) (local.get 0x270))
+    (i64.store offset=0x271 align=1 (i32.const 0) (local.get 0x271))
+    (i64.store offset=0x272 align=1 (i32.const 0) (local.get 0x272))
+    (i64.store offset=0x273 align=1 (i32.const 0) (local.get 0x273))
+    (i64.store offset=0x274 align=1 (i32.const 0) (local.get 0x274))
+    (i64.store offset=0x275 align=1 (i32.const 0) (local.get 0x275))
+    (i64.store offset=0x276 align=1 (i32.const 0) (local.get 0x276))
+    (i64.store offset=0x277 align=1 (i32.const 0) (local.get 0x277))
+    (i64.store offset=0x278 align=1 (i32.const 0) (local.get 0x278))
+    (i64.store offset=0x279 align=1 (i32.const 0) (local.get 0x279))
+    (i64.store offset=0x27a align=1 (i32.const 0) (local.get 0x27a))
+    (i64.store offset=0x27b align=1 (i32.const 0) (local.get 0x27b))
+    (i64.store offset=0x27c align=1 (i32.const 0) (local.get 0x27c))
+    (i64.store offset=0x27d align=1 (i32.const 0) (local.get 0x27d))
+    (i64.store offset=0x27e align=1 (i32.const 0) (local.get 0x27e))
+    (i64.store offset=0x27f align=1 (i32.const 0) (local.get 0x27f))
+    (i64.store offset=0x280 align=1 (i32.const 0) (local.get 0x280))
+    (i64.store offset=0x281 align=1 (i32.const 0) (local.get 0x281))
+    (i64.store offset=0x282 align=1 (i32.const 0) (local.get 0x282))
+    (i64.store offset=0x283 align=1 (i32.const 0) (local.get 0x283))
+    (i64.store offset=0x284 align=1 (i32.const 0) (local.get 0x284))
+    (i64.store offset=0x285 align=1 (i32.const 0) (local.get 0x285))
+    (i64.store offset=0x286 align=1 (i32.const 0) (local.get 0x286))
+    (i64.store offset=0x287 align=1 (i32.const 0) (local.get 0x287))
+    (i64.store offset=0x288 align=1 (i32.const 0) (local.get 0x288))
+    (i64.store offset=0x289 align=1 (i32.const 0) (local.get 0x289))
+    (i64.store offset=0x28a align=1 (i32.const 0) (local.get 0x28a))
+    (i64.store offset=0x28b align=1 (i32.const 0) (local.get 0x28b))
+    (i64.store offset=0x28c align=1 (i32.const 0) (local.get 0x28c))
+    (i64.store offset=0x28d align=1 (i32.const 0) (local.get 0x28d))
+    (i64.store offset=0x28e align=1 (i32.const 0) (local.get 0x28e))
+    (i64.store offset=0x28f align=1 (i32.const 0) (local.get 0x28f))
+    (i64.store offset=0x290 align=1 (i32.const 0) (local.get 0x290))
+    (i64.store offset=0x291 align=1 (i32.const 0) (local.get 0x291))
+    (i64.store offset=0x292 align=1 (i32.const 0) (local.get 0x292))
+    (i64.store offset=0x293 align=1 (i32.const 0) (local.get 0x293))
+    (i64.store offset=0x294 align=1 (i32.const 0) (local.get 0x294))
+    (i64.store offset=0x295 align=1 (i32.const 0) (local.get 0x295))
+    (i64.store offset=0x296 align=1 (i32.const 0) (local.get 0x296))
+    (i64.store offset=0x297 align=1 (i32.const 0) (local.get 0x297))
+    (i64.store offset=0x298 align=1 (i32.const 0) (local.get 0x298))
+    (i64.store offset=0x299 align=1 (i32.const 0) (local.get 0x299))
+    (i64.store offset=0x29a align=1 (i32.const 0) (local.get 0x29a))
+    (i64.store offset=0x29b align=1 (i32.const 0) (local.get 0x29b))
+    (i64.store offset=0x29c align=1 (i32.const 0) (local.get 0x29c))
+    (i64.store offset=0x29d align=1 (i32.const 0) (local.get 0x29d))
+    (i64.store offset=0x29e align=1 (i32.const 0) (local.get 0x29e))
+    (i64.store offset=0x29f align=1 (i32.const 0) (local.get 0x29f))
+    (i64.store offset=0x2a0 align=1 (i32.const 0) (local.get 0x2a0))
+    (i64.store offset=0x2a1 align=1 (i32.const 0) (local.get 0x2a1))
+    (i64.store offset=0x2a2 align=1 (i32.const 0) (local.get 0x2a2))
+    (i64.store offset=0x2a3 align=1 (i32.const 0) (local.get 0x2a3))
+    (i64.store offset=0x2a4 align=1 (i32.const 0) (local.get 0x2a4))
+    (i64.store offset=0x2a5 align=1 (i32.const 0) (local.get 0x2a5))
+    (i64.store offset=0x2a6 align=1 (i32.const 0) (local.get 0x2a6))
+    (i64.store offset=0x2a7 align=1 (i32.const 0) (local.get 0x2a7))
+    (i64.store offset=0x2a8 align=1 (i32.const 0) (local.get 0x2a8))
+    (i64.store offset=0x2a9 align=1 (i32.const 0) (local.get 0x2a9))
+    (i64.store offset=0x2aa align=1 (i32.const 0) (local.get 0x2aa))
+    (i64.store offset=0x2ab align=1 (i32.const 0) (local.get 0x2ab))
+    (i64.store offset=0x2ac align=1 (i32.const 0) (local.get 0x2ac))
+    (i64.store offset=0x2ad align=1 (i32.const 0) (local.get 0x2ad))
+    (i64.store offset=0x2ae align=1 (i32.const 0) (local.get 0x2ae))
+    (i64.store offset=0x2af align=1 (i32.const 0) (local.get 0x2af))
+    (i64.store offset=0x2b0 align=1 (i32.const 0) (local.get 0x2b0))
+    (i64.store offset=0x2b1 align=1 (i32.const 0) (local.get 0x2b1))
+    (i64.store offset=0x2b2 align=1 (i32.const 0) (local.get 0x2b2))
+    (i64.store offset=0x2b3 align=1 (i32.const 0) (local.get 0x2b3))
+    (i64.store offset=0x2b4 align=1 (i32.const 0) (local.get 0x2b4))
+    (i64.store offset=0x2b5 align=1 (i32.const 0) (local.get 0x2b5))
+    (i64.store offset=0x2b6 align=1 (i32.const 0) (local.get 0x2b6))
+    (i64.store offset=0x2b7 align=1 (i32.const 0) (local.get 0x2b7))
+    (i64.store offset=0x2b8 align=1 (i32.const 0) (local.get 0x2b8))
+    (i64.store offset=0x2b9 align=1 (i32.const 0) (local.get 0x2b9))
+    (i64.store offset=0x2ba align=1 (i32.const 0) (local.get 0x2ba))
+    (i64.store offset=0x2bb align=1 (i32.const 0) (local.get 0x2bb))
+    (i64.store offset=0x2bc align=1 (i32.const 0) (local.get 0x2bc))
+    (i64.store offset=0x2bd align=1 (i32.const 0) (local.get 0x2bd))
+    (i64.store offset=0x2be align=1 (i32.const 0) (local.get 0x2be))
+    (i64.store offset=0x2bf align=1 (i32.const 0) (local.get 0x2bf))
+    (i64.store offset=0x2c0 align=1 (i32.const 0) (local.get 0x2c0))
+    (i64.store offset=0x2c1 align=1 (i32.const 0) (local.get 0x2c1))
+    (i64.store offset=0x2c2 align=1 (i32.const 0) (local.get 0x2c2))
+    (i64.store offset=0x2c3 align=1 (i32.const 0) (local.get 0x2c3))
+    (i64.store offset=0x2c4 align=1 (i32.const 0) (local.get 0x2c4))
+    (i64.store offset=0x2c5 align=1 (i32.const 0) (local.get 0x2c5))
+    (i64.store offset=0x2c6 align=1 (i32.const 0) (local.get 0x2c6))
+    (i64.store offset=0x2c7 align=1 (i32.const 0) (local.get 0x2c7))
+    (i64.store offset=0x2c8 align=1 (i32.const 0) (local.get 0x2c8))
+    (i64.store offset=0x2c9 align=1 (i32.const 0) (local.get 0x2c9))
+    (i64.store offset=0x2ca align=1 (i32.const 0) (local.get 0x2ca))
+    (i64.store offset=0x2cb align=1 (i32.const 0) (local.get 0x2cb))
+    (i64.store offset=0x2cc align=1 (i32.const 0) (local.get 0x2cc))
+    (i64.store offset=0x2cd align=1 (i32.const 0) (local.get 0x2cd))
+    (i64.store offset=0x2ce align=1 (i32.const 0) (local.get 0x2ce))
+    (i64.store offset=0x2cf align=1 (i32.const 0) (local.get 0x2cf))
+    (i64.store offset=0x2d0 align=1 (i32.const 0) (local.get 0x2d0))
+    (i64.store offset=0x2d1 align=1 (i32.const 0) (local.get 0x2d1))
+    (i64.store offset=0x2d2 align=1 (i32.const 0) (local.get 0x2d2))
+    (i64.store offset=0x2d3 align=1 (i32.const 0) (local.get 0x2d3))
+    (i64.store offset=0x2d4 align=1 (i32.const 0) (local.get 0x2d4))
+    (i64.store offset=0x2d5 align=1 (i32.const 0) (local.get 0x2d5))
+    (i64.store offset=0x2d6 align=1 (i32.const 0) (local.get 0x2d6))
+    (i64.store offset=0x2d7 align=1 (i32.const 0) (local.get 0x2d7))
+    (i64.store offset=0x2d8 align=1 (i32.const 0) (local.get 0x2d8))
+    (i64.store offset=0x2d9 align=1 (i32.const 0) (local.get 0x2d9))
+    (i64.store offset=0x2da align=1 (i32.const 0) (local.get 0x2da))
+    (i64.store offset=0x2db align=1 (i32.const 0) (local.get 0x2db))
+    (i64.store offset=0x2dc align=1 (i32.const 0) (local.get 0x2dc))
+    (i64.store offset=0x2dd align=1 (i32.const 0) (local.get 0x2dd))
+    (i64.store offset=0x2de align=1 (i32.const 0) (local.get 0x2de))
+    (i64.store offset=0x2df align=1 (i32.const 0) (local.get 0x2df))
+    (i64.store offset=0x2e0 align=1 (i32.const 0) (local.get 0x2e0))
+    (i64.store offset=0x2e1 align=1 (i32.const 0) (local.get 0x2e1))
+    (i64.store offset=0x2e2 align=1 (i32.const 0) (local.get 0x2e2))
+    (i64.store offset=0x2e3 align=1 (i32.const 0) (local.get 0x2e3))
+    (i64.store offset=0x2e4 align=1 (i32.const 0) (local.get 0x2e4))
+    (i64.store offset=0x2e5 align=1 (i32.const 0) (local.get 0x2e5))
+    (i64.store offset=0x2e6 align=1 (i32.const 0) (local.get 0x2e6))
+    (i64.store offset=0x2e7 align=1 (i32.const 0) (local.get 0x2e7))
+    (i64.store offset=0x2e8 align=1 (i32.const 0) (local.get 0x2e8))
+    (i64.store offset=0x2e9 align=1 (i32.const 0) (local.get 0x2e9))
+    (i64.store offset=0x2ea align=1 (i32.const 0) (local.get 0x2ea))
+    (i64.store offset=0x2eb align=1 (i32.const 0) (local.get 0x2eb))
+    (i64.store offset=0x2ec align=1 (i32.const 0) (local.get 0x2ec))
+    (i64.store offset=0x2ed align=1 (i32.const 0) (local.get 0x2ed))
+    (i64.store offset=0x2ee align=1 (i32.const 0) (local.get 0x2ee))
+    (i64.store offset=0x2ef align=1 (i32.const 0) (local.get 0x2ef))
+    (i64.store offset=0x2f0 align=1 (i32.const 0) (local.get 0x2f0))
+    (i64.store offset=0x2f1 align=1 (i32.const 0) (local.get 0x2f1))
+    (i64.store offset=0x2f2 align=1 (i32.const 0) (local.get 0x2f2))
+    (i64.store offset=0x2f3 align=1 (i32.const 0) (local.get 0x2f3))
+    (i64.store offset=0x2f4 align=1 (i32.const 0) (local.get 0x2f4))
+    (i64.store offset=0x2f5 align=1 (i32.const 0) (local.get 0x2f5))
+    (i64.store offset=0x2f6 align=1 (i32.const 0) (local.get 0x2f6))
+    (i64.store offset=0x2f7 align=1 (i32.const 0) (local.get 0x2f7))
+    (i64.store offset=0x2f8 align=1 (i32.const 0) (local.get 0x2f8))
+    (i64.store offset=0x2f9 align=1 (i32.const 0) (local.get 0x2f9))
+    (i64.store offset=0x2fa align=1 (i32.const 0) (local.get 0x2fa))
+    (i64.store offset=0x2fb align=1 (i32.const 0) (local.get 0x2fb))
+    (i64.store offset=0x2fc align=1 (i32.const 0) (local.get 0x2fc))
+    (i64.store offset=0x2fd align=1 (i32.const 0) (local.get 0x2fd))
+    (i64.store offset=0x2fe align=1 (i32.const 0) (local.get 0x2fe))
+    (i64.store offset=0x2ff align=1 (i32.const 0) (local.get 0x2ff))
+    (i64.store offset=0x300 align=1 (i32.const 0) (local.get 0x300))
+    (i64.store offset=0x301 align=1 (i32.const 0) (local.get 0x301))
+    (i64.store offset=0x302 align=1 (i32.const 0) (local.get 0x302))
+    (i64.store offset=0x303 align=1 (i32.const 0) (local.get 0x303))
+    (i64.store offset=0x304 align=1 (i32.const 0) (local.get 0x304))
+    (i64.store offset=0x305 align=1 (i32.const 0) (local.get 0x305))
+    (i64.store offset=0x306 align=1 (i32.const 0) (local.get 0x306))
+    (i64.store offset=0x307 align=1 (i32.const 0) (local.get 0x307))
+    (i64.store offset=0x308 align=1 (i32.const 0) (local.get 0x308))
+    (i64.store offset=0x309 align=1 (i32.const 0) (local.get 0x309))
+    (i64.store offset=0x30a align=1 (i32.const 0) (local.get 0x30a))
+    (i64.store offset=0x30b align=1 (i32.const 0) (local.get 0x30b))
+    (i64.store offset=0x30c align=1 (i32.const 0) (local.get 0x30c))
+    (i64.store offset=0x30d align=1 (i32.const 0) (local.get 0x30d))
+    (i64.store offset=0x30e align=1 (i32.const 0) (local.get 0x30e))
+    (i64.store offset=0x30f align=1 (i32.const 0) (local.get 0x30f))
+    (i64.store offset=0x310 align=1 (i32.const 0) (local.get 0x310))
+    (i64.store offset=0x311 align=1 (i32.const 0) (local.get 0x311))
+    (i64.store offset=0x312 align=1 (i32.const 0) (local.get 0x312))
+    (i64.store offset=0x313 align=1 (i32.const 0) (local.get 0x313))
+    (i64.store offset=0x314 align=1 (i32.const 0) (local.get 0x314))
+    (i64.store offset=0x315 align=1 (i32.const 0) (local.get 0x315))
+    (i64.store offset=0x316 align=1 (i32.const 0) (local.get 0x316))
+    (i64.store offset=0x317 align=1 (i32.const 0) (local.get 0x317))
+    (i64.store offset=0x318 align=1 (i32.const 0) (local.get 0x318))
+    (i64.store offset=0x319 align=1 (i32.const 0) (local.get 0x319))
+    (i64.store offset=0x31a align=1 (i32.const 0) (local.get 0x31a))
+    (i64.store offset=0x31b align=1 (i32.const 0) (local.get 0x31b))
+    (i64.store offset=0x31c align=1 (i32.const 0) (local.get 0x31c))
+    (i64.store offset=0x31d align=1 (i32.const 0) (local.get 0x31d))
+    (i64.store offset=0x31e align=1 (i32.const 0) (local.get 0x31e))
+    (i64.store offset=0x31f align=1 (i32.const 0) (local.get 0x31f))
+    (i64.store offset=0x320 align=1 (i32.const 0) (local.get 0x320))
+    (i64.store offset=0x321 align=1 (i32.const 0) (local.get 0x321))
+    (i64.store offset=0x322 align=1 (i32.const 0) (local.get 0x322))
+    (i64.store offset=0x323 align=1 (i32.const 0) (local.get 0x323))
+    (i64.store offset=0x324 align=1 (i32.const 0) (local.get 0x324))
+    (i64.store offset=0x325 align=1 (i32.const 0) (local.get 0x325))
+    (i64.store offset=0x326 align=1 (i32.const 0) (local.get 0x326))
+    (i64.store offset=0x327 align=1 (i32.const 0) (local.get 0x327))
+    (i64.store offset=0x328 align=1 (i32.const 0) (local.get 0x328))
+    (i64.store offset=0x329 align=1 (i32.const 0) (local.get 0x329))
+    (i64.store offset=0x32a align=1 (i32.const 0) (local.get 0x32a))
+    (i64.store offset=0x32b align=1 (i32.const 0) (local.get 0x32b))
+    (i64.store offset=0x32c align=1 (i32.const 0) (local.get 0x32c))
+    (i64.store offset=0x32d align=1 (i32.const 0) (local.get 0x32d))
+    (i64.store offset=0x32e align=1 (i32.const 0) (local.get 0x32e))
+    (i64.store offset=0x32f align=1 (i32.const 0) (local.get 0x32f))
+    (i64.store offset=0x330 align=1 (i32.const 0) (local.get 0x330))
+    (i64.store offset=0x331 align=1 (i32.const 0) (local.get 0x331))
+    (i64.store offset=0x332 align=1 (i32.const 0) (local.get 0x332))
+    (i64.store offset=0x333 align=1 (i32.const 0) (local.get 0x333))
+    (i64.store offset=0x334 align=1 (i32.const 0) (local.get 0x334))
+    (i64.store offset=0x335 align=1 (i32.const 0) (local.get 0x335))
+    (i64.store offset=0x336 align=1 (i32.const 0) (local.get 0x336))
+    (i64.store offset=0x337 align=1 (i32.const 0) (local.get 0x337))
+    (i64.store offset=0x338 align=1 (i32.const 0) (local.get 0x338))
+    (i64.store offset=0x339 align=1 (i32.const 0) (local.get 0x339))
+    (i64.store offset=0x33a align=1 (i32.const 0) (local.get 0x33a))
+    (i64.store offset=0x33b align=1 (i32.const 0) (local.get 0x33b))
+    (i64.store offset=0x33c align=1 (i32.const 0) (local.get 0x33c))
+    (i64.store offset=0x33d align=1 (i32.const 0) (local.get 0x33d))
+    (i64.store offset=0x33e align=1 (i32.const 0) (local.get 0x33e))
+    (i64.store offset=0x33f align=1 (i32.const 0) (local.get 0x33f))
+    (i64.store offset=0x340 align=1 (i32.const 0) (local.get 0x340))
+    (i64.store offset=0x341 align=1 (i32.const 0) (local.get 0x341))
+    (i64.store offset=0x342 align=1 (i32.const 0) (local.get 0x342))
+    (i64.store offset=0x343 align=1 (i32.const 0) (local.get 0x343))
+    (i64.store offset=0x344 align=1 (i32.const 0) (local.get 0x344))
+    (i64.store offset=0x345 align=1 (i32.const 0) (local.get 0x345))
+    (i64.store offset=0x346 align=1 (i32.const 0) (local.get 0x346))
+    (i64.store offset=0x347 align=1 (i32.const 0) (local.get 0x347))
+    (i64.store offset=0x348 align=1 (i32.const 0) (local.get 0x348))
+    (i64.store offset=0x349 align=1 (i32.const 0) (local.get 0x349))
+    (i64.store offset=0x34a align=1 (i32.const 0) (local.get 0x34a))
+    (i64.store offset=0x34b align=1 (i32.const 0) (local.get 0x34b))
+    (i64.store offset=0x34c align=1 (i32.const 0) (local.get 0x34c))
+    (i64.store offset=0x34d align=1 (i32.const 0) (local.get 0x34d))
+    (i64.store offset=0x34e align=1 (i32.const 0) (local.get 0x34e))
+    (i64.store offset=0x34f align=1 (i32.const 0) (local.get 0x34f))
+    (i64.store offset=0x350 align=1 (i32.const 0) (local.get 0x350))
+    (i64.store offset=0x351 align=1 (i32.const 0) (local.get 0x351))
+    (i64.store offset=0x352 align=1 (i32.const 0) (local.get 0x352))
+    (i64.store offset=0x353 align=1 (i32.const 0) (local.get 0x353))
+    (i64.store offset=0x354 align=1 (i32.const 0) (local.get 0x354))
+    (i64.store offset=0x355 align=1 (i32.const 0) (local.get 0x355))
+    (i64.store offset=0x356 align=1 (i32.const 0) (local.get 0x356))
+    (i64.store offset=0x357 align=1 (i32.const 0) (local.get 0x357))
+    (i64.store offset=0x358 align=1 (i32.const 0) (local.get 0x358))
+    (i64.store offset=0x359 align=1 (i32.const 0) (local.get 0x359))
+    (i64.store offset=0x35a align=1 (i32.const 0) (local.get 0x35a))
+    (i64.store offset=0x35b align=1 (i32.const 0) (local.get 0x35b))
+    (i64.store offset=0x35c align=1 (i32.const 0) (local.get 0x35c))
+    (i64.store offset=0x35d align=1 (i32.const 0) (local.get 0x35d))
+    (i64.store offset=0x35e align=1 (i32.const 0) (local.get 0x35e))
+    (i64.store offset=0x35f align=1 (i32.const 0) (local.get 0x35f))
+    (i64.store offset=0x360 align=1 (i32.const 0) (local.get 0x360))
+    (i64.store offset=0x361 align=1 (i32.const 0) (local.get 0x361))
+    (i64.store offset=0x362 align=1 (i32.const 0) (local.get 0x362))
+    (i64.store offset=0x363 align=1 (i32.const 0) (local.get 0x363))
+    (i64.store offset=0x364 align=1 (i32.const 0) (local.get 0x364))
+    (i64.store offset=0x365 align=1 (i32.const 0) (local.get 0x365))
+    (i64.store offset=0x366 align=1 (i32.const 0) (local.get 0x366))
+    (i64.store offset=0x367 align=1 (i32.const 0) (local.get 0x367))
+    (i64.store offset=0x368 align=1 (i32.const 0) (local.get 0x368))
+    (i64.store offset=0x369 align=1 (i32.const 0) (local.get 0x369))
+    (i64.store offset=0x36a align=1 (i32.const 0) (local.get 0x36a))
+    (i64.store offset=0x36b align=1 (i32.const 0) (local.get 0x36b))
+    (i64.store offset=0x36c align=1 (i32.const 0) (local.get 0x36c))
+    (i64.store offset=0x36d align=1 (i32.const 0) (local.get 0x36d))
+    (i64.store offset=0x36e align=1 (i32.const 0) (local.get 0x36e))
+    (i64.store offset=0x36f align=1 (i32.const 0) (local.get 0x36f))
+    (i64.store offset=0x370 align=1 (i32.const 0) (local.get 0x370))
+    (i64.store offset=0x371 align=1 (i32.const 0) (local.get 0x371))
+    (i64.store offset=0x372 align=1 (i32.const 0) (local.get 0x372))
+    (i64.store offset=0x373 align=1 (i32.const 0) (local.get 0x373))
+    (i64.store offset=0x374 align=1 (i32.const 0) (local.get 0x374))
+    (i64.store offset=0x375 align=1 (i32.const 0) (local.get 0x375))
+    (i64.store offset=0x376 align=1 (i32.const 0) (local.get 0x376))
+    (i64.store offset=0x377 align=1 (i32.const 0) (local.get 0x377))
+    (i64.store offset=0x378 align=1 (i32.const 0) (local.get 0x378))
+    (i64.store offset=0x379 align=1 (i32.const 0) (local.get 0x379))
+    (i64.store offset=0x37a align=1 (i32.const 0) (local.get 0x37a))
+    (i64.store offset=0x37b align=1 (i32.const 0) (local.get 0x37b))
+    (i64.store offset=0x37c align=1 (i32.const 0) (local.get 0x37c))
+    (i64.store offset=0x37d align=1 (i32.const 0) (local.get 0x37d))
+    (i64.store offset=0x37e align=1 (i32.const 0) (local.get 0x37e))
+    (i64.store offset=0x37f align=1 (i32.const 0) (local.get 0x37f))
+    (i64.store offset=0x380 align=1 (i32.const 0) (local.get 0x380))
+    (i64.store offset=0x381 align=1 (i32.const 0) (local.get 0x381))
+    (i64.store offset=0x382 align=1 (i32.const 0) (local.get 0x382))
+    (i64.store offset=0x383 align=1 (i32.const 0) (local.get 0x383))
+    (i64.store offset=0x384 align=1 (i32.const 0) (local.get 0x384))
+    (i64.store offset=0x385 align=1 (i32.const 0) (local.get 0x385))
+    (i64.store offset=0x386 align=1 (i32.const 0) (local.get 0x386))
+    (i64.store offset=0x387 align=1 (i32.const 0) (local.get 0x387))
+    (i64.store offset=0x388 align=1 (i32.const 0) (local.get 0x388))
+    (i64.store offset=0x389 align=1 (i32.const 0) (local.get 0x389))
+    (i64.store offset=0x38a align=1 (i32.const 0) (local.get 0x38a))
+    (i64.store offset=0x38b align=1 (i32.const 0) (local.get 0x38b))
+    (i64.store offset=0x38c align=1 (i32.const 0) (local.get 0x38c))
+    (i64.store offset=0x38d align=1 (i32.const 0) (local.get 0x38d))
+    (i64.store offset=0x38e align=1 (i32.const 0) (local.get 0x38e))
+    (i64.store offset=0x38f align=1 (i32.const 0) (local.get 0x38f))
+    (i64.store offset=0x390 align=1 (i32.const 0) (local.get 0x390))
+    (i64.store offset=0x391 align=1 (i32.const 0) (local.get 0x391))
+    (i64.store offset=0x392 align=1 (i32.const 0) (local.get 0x392))
+    (i64.store offset=0x393 align=1 (i32.const 0) (local.get 0x393))
+    (i64.store offset=0x394 align=1 (i32.const 0) (local.get 0x394))
+    (i64.store offset=0x395 align=1 (i32.const 0) (local.get 0x395))
+    (i64.store offset=0x396 align=1 (i32.const 0) (local.get 0x396))
+    (i64.store offset=0x397 align=1 (i32.const 0) (local.get 0x397))
+    (i64.store offset=0x398 align=1 (i32.const 0) (local.get 0x398))
+    (i64.store offset=0x399 align=1 (i32.const 0) (local.get 0x399))
+    (i64.store offset=0x39a align=1 (i32.const 0) (local.get 0x39a))
+    (i64.store offset=0x39b align=1 (i32.const 0) (local.get 0x39b))
+    (i64.store offset=0x39c align=1 (i32.const 0) (local.get 0x39c))
+    (i64.store offset=0x39d align=1 (i32.const 0) (local.get 0x39d))
+    (i64.store offset=0x39e align=1 (i32.const 0) (local.get 0x39e))
+    (i64.store offset=0x39f align=1 (i32.const 0) (local.get 0x39f))
+    (i64.store offset=0x3a0 align=1 (i32.const 0) (local.get 0x3a0))
+    (i64.store offset=0x3a1 align=1 (i32.const 0) (local.get 0x3a1))
+    (i64.store offset=0x3a2 align=1 (i32.const 0) (local.get 0x3a2))
+    (i64.store offset=0x3a3 align=1 (i32.const 0) (local.get 0x3a3))
+    (i64.store offset=0x3a4 align=1 (i32.const 0) (local.get 0x3a4))
+    (i64.store offset=0x3a5 align=1 (i32.const 0) (local.get 0x3a5))
+    (i64.store offset=0x3a6 align=1 (i32.const 0) (local.get 0x3a6))
+    (i64.store offset=0x3a7 align=1 (i32.const 0) (local.get 0x3a7))
+    (i64.store offset=0x3a8 align=1 (i32.const 0) (local.get 0x3a8))
+    (i64.store offset=0x3a9 align=1 (i32.const 0) (local.get 0x3a9))
+    (i64.store offset=0x3aa align=1 (i32.const 0) (local.get 0x3aa))
+    (i64.store offset=0x3ab align=1 (i32.const 0) (local.get 0x3ab))
+    (i64.store offset=0x3ac align=1 (i32.const 0) (local.get 0x3ac))
+    (i64.store offset=0x3ad align=1 (i32.const 0) (local.get 0x3ad))
+    (i64.store offset=0x3ae align=1 (i32.const 0) (local.get 0x3ae))
+    (i64.store offset=0x3af align=1 (i32.const 0) (local.get 0x3af))
+    (i64.store offset=0x3b0 align=1 (i32.const 0) (local.get 0x3b0))
+    (i64.store offset=0x3b1 align=1 (i32.const 0) (local.get 0x3b1))
+    (i64.store offset=0x3b2 align=1 (i32.const 0) (local.get 0x3b2))
+    (i64.store offset=0x3b3 align=1 (i32.const 0) (local.get 0x3b3))
+    (i64.store offset=0x3b4 align=1 (i32.const 0) (local.get 0x3b4))
+    (i64.store offset=0x3b5 align=1 (i32.const 0) (local.get 0x3b5))
+    (i64.store offset=0x3b6 align=1 (i32.const 0) (local.get 0x3b6))
+    (i64.store offset=0x3b7 align=1 (i32.const 0) (local.get 0x3b7))
+    (i64.store offset=0x3b8 align=1 (i32.const 0) (local.get 0x3b8))
+    (i64.store offset=0x3b9 align=1 (i32.const 0) (local.get 0x3b9))
+    (i64.store offset=0x3ba align=1 (i32.const 0) (local.get 0x3ba))
+    (i64.store offset=0x3bb align=1 (i32.const 0) (local.get 0x3bb))
+    (i64.store offset=0x3bc align=1 (i32.const 0) (local.get 0x3bc))
+    (i64.store offset=0x3bd align=1 (i32.const 0) (local.get 0x3bd))
+    (i64.store offset=0x3be align=1 (i32.const 0) (local.get 0x3be))
+    (i64.store offset=0x3bf align=1 (i32.const 0) (local.get 0x3bf))
+    (i64.store offset=0x3c0 align=1 (i32.const 0) (local.get 0x3c0))
+    (i64.store offset=0x3c1 align=1 (i32.const 0) (local.get 0x3c1))
+    (i64.store offset=0x3c2 align=1 (i32.const 0) (local.get 0x3c2))
+    (i64.store offset=0x3c3 align=1 (i32.const 0) (local.get 0x3c3))
+    (i64.store offset=0x3c4 align=1 (i32.const 0) (local.get 0x3c4))
+    (i64.store offset=0x3c5 align=1 (i32.const 0) (local.get 0x3c5))
+    (i64.store offset=0x3c6 align=1 (i32.const 0) (local.get 0x3c6))
+    (i64.store offset=0x3c7 align=1 (i32.const 0) (local.get 0x3c7))
+    (i64.store offset=0x3c8 align=1 (i32.const 0) (local.get 0x3c8))
+    (i64.store offset=0x3c9 align=1 (i32.const 0) (local.get 0x3c9))
+    (i64.store offset=0x3ca align=1 (i32.const 0) (local.get 0x3ca))
+    (i64.store offset=0x3cb align=1 (i32.const 0) (local.get 0x3cb))
+    (i64.store offset=0x3cc align=1 (i32.const 0) (local.get 0x3cc))
+    (i64.store offset=0x3cd align=1 (i32.const 0) (local.get 0x3cd))
+    (i64.store offset=0x3ce align=1 (i32.const 0) (local.get 0x3ce))
+    (i64.store offset=0x3cf align=1 (i32.const 0) (local.get 0x3cf))
+    (i64.store offset=0x3d0 align=1 (i32.const 0) (local.get 0x3d0))
+    (i64.store offset=0x3d1 align=1 (i32.const 0) (local.get 0x3d1))
+    (i64.store offset=0x3d2 align=1 (i32.const 0) (local.get 0x3d2))
+    (i64.store offset=0x3d3 align=1 (i32.const 0) (local.get 0x3d3))
+    (i64.store offset=0x3d4 align=1 (i32.const 0) (local.get 0x3d4))
+    (i64.store offset=0x3d5 align=1 (i32.const 0) (local.get 0x3d5))
+    (i64.store offset=0x3d6 align=1 (i32.const 0) (local.get 0x3d6))
+    (i64.store offset=0x3d7 align=1 (i32.const 0) (local.get 0x3d7))
+    (i64.store offset=0x3d8 align=1 (i32.const 0) (local.get 0x3d8))
+    (i64.store offset=0x3d9 align=1 (i32.const 0) (local.get 0x3d9))
+    (i64.store offset=0x3da align=1 (i32.const 0) (local.get 0x3da))
+    (i64.store offset=0x3db align=1 (i32.const 0) (local.get 0x3db))
+    (i64.store offset=0x3dc align=1 (i32.const 0) (local.get 0x3dc))
+    (i64.store offset=0x3dd align=1 (i32.const 0) (local.get 0x3dd))
+    (i64.store offset=0x3de align=1 (i32.const 0) (local.get 0x3de))
+    (i64.store offset=0x3df align=1 (i32.const 0) (local.get 0x3df))
+    (i64.store offset=0x3e0 align=1 (i32.const 0) (local.get 0x3e0))
+    (i64.store offset=0x3e1 align=1 (i32.const 0) (local.get 0x3e1))
+    (i64.store offset=0x3e2 align=1 (i32.const 0) (local.get 0x3e2))
+    (i64.store offset=0x3e3 align=1 (i32.const 0) (local.get 0x3e3))
+    (i64.store offset=0x3e4 align=1 (i32.const 0) (local.get 0x3e4))
+    (i64.store offset=0x3e5 align=1 (i32.const 0) (local.get 0x3e5))
+    (i64.store offset=0x3e6 align=1 (i32.const 0) (local.get 0x3e6))
+    (i64.store offset=0x3e7 align=1 (i32.const 0) (local.get 0x3e7))
+    (i64.store offset=0x3e8 align=1 (i32.const 0) (local.get 0x3e8))
+    (i64.store offset=0x3e9 align=1 (i32.const 0) (local.get 0x3e9))
+    (i64.store offset=0x3ea align=1 (i32.const 0) (local.get 0x3ea))
+    (i64.store offset=0x3eb align=1 (i32.const 0) (local.get 0x3eb))
+    (i64.store offset=0x3ec align=1 (i32.const 0) (local.get 0x3ec))
+    (i64.store offset=0x3ed align=1 (i32.const 0) (local.get 0x3ed))
+    (i64.store offset=0x3ee align=1 (i32.const 0) (local.get 0x3ee))
+    (i64.store offset=0x3ef align=1 (i32.const 0) (local.get 0x3ef))
+    (i64.store offset=0x3f0 align=1 (i32.const 0) (local.get 0x3f0))
+    (i64.store offset=0x3f1 align=1 (i32.const 0) (local.get 0x3f1))
+    (i64.store offset=0x3f2 align=1 (i32.const 0) (local.get 0x3f2))
+    (i64.store offset=0x3f3 align=1 (i32.const 0) (local.get 0x3f3))
+    (i64.store offset=0x3f4 align=1 (i32.const 0) (local.get 0x3f4))
+    (i64.store offset=0x3f5 align=1 (i32.const 0) (local.get 0x3f5))
+    (i64.store offset=0x3f6 align=1 (i32.const 0) (local.get 0x3f6))
+    (i64.store offset=0x3f7 align=1 (i32.const 0) (local.get 0x3f7))
+    (i64.store offset=0x3f8 align=1 (i32.const 0) (local.get 0x3f8))
+    (i64.store offset=0x3f9 align=1 (i32.const 0) (local.get 0x3f9))
+    (i64.store offset=0x3fa align=1 (i32.const 0) (local.get 0x3fa))
+    (i64.store offset=0x3fb align=1 (i32.const 0) (local.get 0x3fb))
+    (i64.store offset=0x3fc align=1 (i32.const 0) (local.get 0x3fc))
+    (i64.store offset=0x3fd align=1 (i32.const 0) (local.get 0x3fd))
+    (i64.store offset=0x3fe align=1 (i32.const 0) (local.get 0x3fe))
+    (i64.store offset=0x3ff align=1 (i32.const 0) (local.get 0x3ff))
+    (i64.store offset=0x400 align=1 (i32.const 0) (local.get 0x400))
+    (i64.store offset=0x401 align=1 (i32.const 0) (local.get 0x401))
+    (i64.store offset=0x402 align=1 (i32.const 0) (local.get 0x402))
+    (i64.store offset=0x403 align=1 (i32.const 0) (local.get 0x403))
+    (i64.store offset=0x404 align=1 (i32.const 0) (local.get 0x404))
+    (i64.store offset=0x405 align=1 (i32.const 0) (local.get 0x405))
+    (i64.store offset=0x406 align=1 (i32.const 0) (local.get 0x406))
+    (i64.store offset=0x407 align=1 (i32.const 0) (local.get 0x407))
+    (i64.store offset=0x408 align=1 (i32.const 0) (local.get 0x408))
+    (i64.store offset=0x409 align=1 (i32.const 0) (local.get 0x409))
+    (i64.store offset=0x40a align=1 (i32.const 0) (local.get 0x40a))
+    (i64.store offset=0x40b align=1 (i32.const 0) (local.get 0x40b))
+    (i64.store offset=0x40c align=1 (i32.const 0) (local.get 0x40c))
+    (i64.store offset=0x40d align=1 (i32.const 0) (local.get 0x40d))
+    (i64.store offset=0x40e align=1 (i32.const 0) (local.get 0x40e))
+    (i64.store offset=0x40f align=1 (i32.const 0) (local.get 0x40f))
+    (i64.store offset=0x410 align=1 (i32.const 0) (local.get 0x410))
+    (i64.store offset=0x411 align=1 (i32.const 0) (local.get 0x411))
+    (i64.store offset=0x412 align=1 (i32.const 0) (local.get 0x412))
+    (i64.store offset=0x413 align=1 (i32.const 0) (local.get 0x413))
+    (i64.store offset=0x414 align=1 (i32.const 0) (local.get 0x414))
+    (i64.store offset=0x415 align=1 (i32.const 0) (local.get 0x415))
+    (i64.store offset=0x416 align=1 (i32.const 0) (local.get 0x416))
+    (i64.store offset=0x417 align=1 (i32.const 0) (local.get 0x417))
+    (i64.store offset=0x418 align=1 (i32.const 0) (local.get 0x418))
+    (i64.store offset=0x419 align=1 (i32.const 0) (local.get 0x419))
+    (i64.store offset=0x41a align=1 (i32.const 0) (local.get 0x41a))
+    (i64.store offset=0x41b align=1 (i32.const 0) (local.get 0x41b))
+    (i64.store offset=0x41c align=1 (i32.const 0) (local.get 0x41c))
+    (i64.store offset=0x41d align=1 (i32.const 0) (local.get 0x41d))
+    (i64.store offset=0x41e align=1 (i32.const 0) (local.get 0x41e))
+    (i64.store offset=0x41f align=1 (i32.const 0) (local.get 0x41f))
+  )
+)
+
+(assert_exhaustion (invoke "test-guard-page-skip" (i32.const 0)) "call stack exhausted")
+(assert_exhaustion (invoke "test-guard-page-skip" (i32.const 100)) "call stack exhausted")
+(assert_exhaustion (invoke "test-guard-page-skip" (i32.const 200)) "call stack exhausted")
+(assert_exhaustion (invoke "test-guard-page-skip" (i32.const 300)) "call stack exhausted")
+(assert_exhaustion (invoke "test-guard-page-skip" (i32.const 400)) "call stack exhausted")
+(assert_exhaustion (invoke "test-guard-page-skip" (i32.const 500)) "call stack exhausted")
+(assert_exhaustion (invoke "test-guard-page-skip" (i32.const 600)) "call stack exhausted")
+(assert_exhaustion (invoke "test-guard-page-skip" (i32.const 700)) "call stack exhausted")
+(assert_exhaustion (invoke "test-guard-page-skip" (i32.const 800)) "call stack exhausted")
+(assert_exhaustion (invoke "test-guard-page-skip" (i32.const 900)) "call stack exhausted")
diff --git a/binaryen/test/spec/stack.wast b/binaryen/test/spec/stack.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/stack.wast
@@ -0,0 +1,220 @@
+(module
+  (func (export "fac-expr") (param $n i64) (result i64)
+    (local $i i64)
+    (local $res i64)
+    (local.set $i (local.get $n))
+    (local.set $res (i64.const 1))
+    (block $done
+      (loop $loop
+        (if
+          (i64.eq (local.get $i) (i64.const 0))
+          (then (br $done))
+          (else
+            (local.set $res (i64.mul (local.get $i) (local.get $res)))
+            (local.set $i (i64.sub (local.get $i) (i64.const 1)))
+          )
+        )
+        (br $loop)
+      )
+    )
+    (local.get $res)
+  )
+
+  (func (export "fac-stack") (param $n i64) (result i64)
+    (local $i i64)
+    (local $res i64)
+    (local.get $n)
+    (local.set $i)
+    (i64.const 1)
+    (local.set $res)
+    (block $done
+      (loop $loop
+        (local.get $i)
+        (i64.const 0)
+        (i64.eq)
+        (if
+          (then (br $done))
+          (else
+            (local.get $i)
+            (local.get $res)
+            (i64.mul)
+            (local.set $res)
+            (local.get $i)
+            (i64.const 1)
+            (i64.sub)
+            (local.set $i)
+          )
+        )
+        (br $loop)
+      )
+    )
+    (local.get $res)
+  )
+
+  (func (export "fac-stack-raw") (param $n i64) (result i64)
+    (local $i i64)
+    (local $res i64)
+    local.get $n
+    local.set $i
+    i64.const 1
+    local.set $res
+    block $done
+      loop $loop
+        local.get $i
+        i64.const 0
+        i64.eq
+        if $body
+          br $done
+        else $body
+          local.get $i
+          local.get $res
+          i64.mul
+          local.set $res
+          local.get $i
+          i64.const 1
+          i64.sub
+          local.set $i
+        end $body
+        br $loop
+      end $loop
+    end $done
+    local.get $res
+  )
+
+  (func (export "fac-mixed") (param $n i64) (result i64)
+    (local $i i64)
+    (local $res i64)
+    (local.set $i (local.get $n))
+    (local.set $res (i64.const 1))
+    (block $done
+      (loop $loop
+        (i64.eq (local.get $i) (i64.const 0))
+        (if
+          (then (br $done))
+          (else
+            (i64.mul (local.get $i) (local.get $res))
+            (local.set $res)
+            (i64.sub (local.get $i) (i64.const 1))
+            (local.set $i)
+          )
+        )
+        (br $loop)
+      )
+    )
+    (local.get $res)
+  )
+
+  (func (export "fac-mixed-raw") (param $n i64) (result i64)
+    (local $i i64)
+    (local $res i64)
+    (local.set $i (local.get $n))
+    (local.set $res (i64.const 1))
+    block $done
+      loop $loop
+        (i64.eq (local.get $i) (i64.const 0))
+        if
+          br $done
+        else
+          (i64.mul (local.get $i) (local.get $res))
+          local.set $res
+          (i64.sub (local.get $i) (i64.const 1))
+          local.set $i
+        end
+        br $loop
+      end
+    end
+    local.get $res
+  )
+)
+
+(assert_return (invoke "fac-expr" (i64.const 25)) (i64.const 7034535277573963776))
+(assert_return (invoke "fac-stack" (i64.const 25)) (i64.const 7034535277573963776))
+(assert_return (invoke "fac-mixed" (i64.const 25)) (i64.const 7034535277573963776))
+
+
+;; Syntax of flat call_indirect
+
+(module
+  (type $proc (func))
+  (table 1 funcref)
+
+  (func
+    (block i32.const 0 call_indirect)
+    (loop i32.const 0 call_indirect)
+    (if (i32.const 0) (then i32.const 0 call_indirect))
+    (if (i32.const 0)
+      (then i32.const 0 call_indirect)
+      (else i32.const 0 call_indirect)
+    )
+    (block i32.const 0 call_indirect (type $proc))
+    (loop i32.const 0 call_indirect (type $proc))
+    (if (i32.const 0) (then i32.const 0 call_indirect (type $proc)))
+    (if (i32.const 0)
+      (then i32.const 0 call_indirect (type $proc))
+      (else i32.const 0 call_indirect (type $proc))
+    )
+    (block i32.const 0 i32.const 0 call_indirect (param i32))
+    (loop i32.const 0 i32.const 0 call_indirect (param i32))
+    (if (i32.const 0) (then i32.const 0 i32.const 0 call_indirect (param i32)))
+    (if (i32.const 0)
+      (then i32.const 0 i32.const 0 call_indirect (param i32))
+      (else i32.const 0 i32.const 0 call_indirect (param i32))
+    )
+    (block (result i32) i32.const 0 call_indirect (result i32)) (drop)
+    (loop (result i32) i32.const 0 call_indirect (result i32)) (drop)
+    (if (result i32) (i32.const 0)
+      (then i32.const 0 call_indirect (result i32))
+      (else i32.const 0 call_indirect (result i32))
+    ) (drop)
+    (block i32.const 0 call_indirect (type $proc) (param) (result))
+    (loop i32.const 0 call_indirect (type $proc) (param) (result))
+    (if (i32.const 0)
+      (then i32.const 0 call_indirect (type $proc) (param) (result))
+    )
+    (if (i32.const 0)
+      (then i32.const 0 call_indirect (type $proc) (param) (param) (result))
+      (else i32.const 0 call_indirect (type $proc) (param) (result) (result))
+    )
+
+    block i32.const 0 call_indirect end
+    loop i32.const 0 call_indirect end
+    i32.const 0 if i32.const 0 call_indirect end
+    i32.const 0 if i32.const 0 call_indirect else i32.const 0 call_indirect end
+    block i32.const 0 call_indirect (type $proc) end
+    loop i32.const 0 call_indirect (type $proc) end
+    i32.const 0 if i32.const 0 call_indirect (type $proc) end
+    i32.const 0
+    if
+      i32.const 0 call_indirect (type $proc)
+    else
+      i32.const 0 call_indirect (type $proc)
+    end
+    block i32.const 0 i32.const 0 call_indirect (param i32) end
+    loop i32.const 0 i32.const 0 call_indirect (param i32) end
+    i32.const 0 if i32.const 0 i32.const 0 call_indirect (param i32) end
+    i32.const 0
+    if
+      i32.const 0 i32.const 0 call_indirect (param i32)
+    else
+      i32.const 0 i32.const 0 call_indirect (param i32)
+    end
+    block (result i32) i32.const 0 call_indirect (result i32) end drop
+    loop (result i32) i32.const 0 call_indirect (result i32) end drop
+    i32.const 0
+    if (result i32)
+      i32.const 0 call_indirect (result i32)
+    else
+      i32.const 0 call_indirect (result i32)
+    end drop
+    block i32.const 0 call_indirect (type $proc) (param) (result) end
+    loop i32.const 0 call_indirect (type $proc) (param) (result) end
+    i32.const 0 if i32.const 0 call_indirect (type $proc) (param) (result) end
+    i32.const 0
+    if
+      i32.const 0 call_indirect (type $proc) (param) (result)
+    else
+      i32.const 0 call_indirect (type $proc) (param) (param) (result) (result)
+    end
+    i32.const 0 call_indirect
+  )
+)
diff --git a/binaryen/test/spec/start.wast b/binaryen/test/spec/start.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/start.wast
@@ -0,0 +1,105 @@
+(assert_invalid
+  (module (func) (start 1))
+  "unknown function"
+)
+
+(assert_invalid
+  (module
+    (func $main (result i32) (return (i32.const 0)))
+    (start $main)
+  )
+  "start function"
+)
+(assert_invalid
+  (module
+    (func $main (param $a i32))
+    (start $main)
+  )
+  "start function"
+)
+
+(module
+  (memory (data "A"))
+  (func $inc
+    (i32.store8
+      (i32.const 0)
+      (i32.add
+        (i32.load8_u (i32.const 0))
+        (i32.const 1)
+      )
+    )
+  )
+  (func $get (result i32)
+    (return (i32.load8_u (i32.const 0)))
+  )
+  (func $main
+    (call $inc)
+    (call $inc)
+    (call $inc)
+  )
+
+  (start $main)
+  (export "inc" (func $inc))
+  (export "get" (func $get))
+)
+(assert_return (invoke "get") (i32.const 68))
+(invoke "inc")
+(assert_return (invoke "get") (i32.const 69))
+(invoke "inc")
+(assert_return (invoke "get") (i32.const 70))
+
+(module
+  (memory (data "A"))
+  (func $inc
+    (i32.store8
+      (i32.const 0)
+      (i32.add
+        (i32.load8_u (i32.const 0))
+        (i32.const 1)
+      )
+    )
+  )
+  (func $get (result i32)
+    (return (i32.load8_u (i32.const 0)))
+  )
+  (func $main
+    (call $inc)
+    (call $inc)
+    (call $inc)
+  )
+  (start 2)
+  (export "inc" (func $inc))
+  (export "get" (func $get))
+)
+(assert_return (invoke "get") (i32.const 68))
+(invoke "inc")
+(assert_return (invoke "get") (i32.const 69))
+(invoke "inc")
+(assert_return (invoke "get") (i32.const 70))
+
+(module
+  (func $print_i32 (import "spectest" "print_i32") (param i32))
+  (func $main (call $print_i32 (i32.const 1)))
+  (start 1)
+)
+
+(module
+  (func $print_i32 (import "spectest" "print_i32") (param i32))
+  (func $main (call $print_i32 (i32.const 2)))
+  (start $main)
+)
+
+(module
+  (func $print (import "spectest" "print"))
+  (start $print)
+)
+
+(assert_trap
+  (module (func $main (unreachable)) (start $main))
+  "unreachable"
+)
+
+(assert_malformed
+  (module quote "(module (func $a (unreachable)) (func $b (unreachable)) (start $a) (start $b))")
+  "multiple start sections"
+)
diff --git a/binaryen/test/spec/store.wast b/binaryen/test/spec/store.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/store.wast
@@ -0,0 +1,417 @@
+;; Store operator as the argument of control constructs and instructions
+
+(module
+  (memory 1)
+
+  (func (export "as-block-value")
+    (block (i32.store (i32.const 0) (i32.const 1)))
+  )
+  (func (export "as-loop-value")
+    (loop (i32.store (i32.const 0) (i32.const 1)))
+  )
+
+  (func (export "as-br-value")
+    (block (br 0 (i32.store (i32.const 0) (i32.const 1))))
+  )
+  (func (export "as-br_if-value")
+    (block
+      (br_if 0 (i32.store (i32.const 0) (i32.const 1)) (i32.const 1))
+    )
+  )
+  (func (export "as-br_if-value-cond")
+    (block
+      (br_if 0 (i32.const 6) (i32.store (i32.const 0) (i32.const 1)))
+    )
+  )
+  (func (export "as-br_table-value")
+    (block
+      (br_table 0 (i32.store (i32.const 0) (i32.const 1)) (i32.const 1))
+    )
+  )
+
+  (func (export "as-return-value")
+    (return (i32.store (i32.const 0) (i32.const 1)))
+  )
+
+  (func (export "as-if-then")
+    (if (i32.const 1) (then (i32.store (i32.const 0) (i32.const 1))))
+  )
+  (func (export "as-if-else")
+    (if (i32.const 0) (then) (else (i32.store (i32.const 0) (i32.const 1))))
+  )
+)
+
+(assert_return (invoke "as-block-value"))
+(assert_return (invoke "as-loop-value"))
+
+(assert_return (invoke "as-br-value"))
+(assert_return (invoke "as-br_if-value"))
+(assert_return (invoke "as-br_if-value-cond"))
+(assert_return (invoke "as-br_table-value"))
+
+(assert_return (invoke "as-return-value"))
+
+(assert_return (invoke "as-if-then"))
+(assert_return (invoke "as-if-else"))
+
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (i32.store32 (local.get 0) (i32.const 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (i32.store64 (local.get 0) (i64.const 0)))"
+  )
+  "unknown operator"
+)
+
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (i64.store64 (local.get 0) (i64.const 0)))"
+  )
+  "unknown operator"
+)
+
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (f32.store32 (local.get 0) (f32.const 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (f32.store64 (local.get 0) (f64.const 0)))"
+  )
+  "unknown operator"
+)
+
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (f64.store32 (local.get 0) (f32.const 0)))"
+  )
+  "unknown operator"
+)
+(assert_malformed
+  (module quote
+    "(memory 1)"
+    "(func (param i32) (f64.store64 (local.get 0) (f64.const 0)))"
+  )
+  "unknown operator"
+)
+;; store should have no retval
+
+(assert_invalid
+  (module (memory 1) (func (param i32) (result i32) (i32.store (i32.const 0) (i32.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func (param i64) (result i64) (i64.store (i32.const 0) (i64.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func (param f32) (result f32) (f32.store (i32.const 0) (f32.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func (param f64) (result f64) (f64.store (i32.const 0) (f64.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func (param i32) (result i32) (i32.store8 (i32.const 0) (i32.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func (param i32) (result i32) (i32.store16 (i32.const 0) (i32.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func (param i64) (result i64) (i64.store8 (i32.const 0) (i64.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func (param i64) (result i64) (i64.store16 (i32.const 0) (i64.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func (param i64) (result i64) (i64.store32 (i32.const 0) (i64.const 1))))
+  "type mismatch"
+)
+
+
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-address-empty
+      (i32.store)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-value-empty
+     (i32.const 0) (i32.store)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-address-empty-in-block
+      (i32.const 0) (i32.const 0)
+      (block (i32.store))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-value-empty-in-block
+      (i32.const 0)
+      (block (i32.const 0) (i32.store))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-address-empty-in-loop
+      (i32.const 0) (i32.const 0)
+      (loop (i32.store))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-value-empty-in-loop
+      (i32.const 0)
+      (loop (i32.const 0) (i32.store))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-address-empty-in-then
+      (i32.const 0) (i32.const 0)
+      (if (then (i32.store)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-value-empty-in-then
+      (i32.const 0)
+      (if (then (i32.const 0) (i32.store)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-address-empty-in-else
+      (i32.const 0) (i32.const 0)
+      (if (result i32) (then (i32.const 0)) (else (i32.store)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-value-empty-in-else
+      (i32.const 0)
+      (if (result i32) (then (i32.const 0)) (else (i32.const 0) (i32.store)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-address-empty-in-br
+      (i32.const 0) (i32.const 0)
+      (block (br 0 (i32.store)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-value-empty-in-br
+      (i32.const 0)
+      (block (br 0 (i32.const 0) (i32.store)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-address-empty-in-br_if
+      (i32.const 0) (i32.const 0)
+      (block (br_if 0 (i32.store) (i32.const 1)) )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-value-empty-in-br_if
+      (i32.const 0)
+      (block (br_if 0 (i32.const 0) (i32.store) (i32.const 1)) )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-address-empty-in-br_table
+      (i32.const 0) (i32.const 0)
+      (block (br_table 0 (i32.store)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-value-empty-in-br_table
+      (i32.const 0)
+      (block (br_table 0 (i32.const 0) (i32.store)))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-address-empty-in-return
+      (return (i32.store))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-value-empty-in-return
+      (return (i32.const 0) (i32.store))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-address-empty-in-select
+      (select (i32.store) (i32.const 1) (i32.const 2))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-value-empty-in-select
+      (select (i32.const 0) (i32.store) (i32.const 1) (i32.const 2))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-address-empty-in-call
+      (call 1 (i32.store))
+    )
+    (func (param i32) (result i32) (local.get 0))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-value-empty-in-call
+      (call 1 (i32.const 0) (i32.store))
+    )
+    (func (param i32) (result i32) (local.get 0))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $f (param i32) (result i32) (local.get 0))
+    (type $sig (func (param i32) (result i32)))
+    (table funcref (elem $f))
+    (func $type-address-empty-in-call_indirect
+      (block (result i32)
+        (call_indirect (type $sig)
+          (i32.store) (i32.const 0)
+        )
+      )
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $f (param i32) (result i32) (local.get 0))
+    (type $sig (func (param i32) (result i32)))
+    (table funcref (elem $f))
+    (func $type-value-empty-in-call_indirect
+      (block (result i32)
+        (call_indirect (type $sig)
+          (i32.const 0) (i32.store) (i32.const 0)
+        )
+      )
+    )
+  )
+  "type mismatch"
+)
+
+
+;; Type check
+
+(assert_invalid (module (memory 1) (func (i32.store (f32.const 0) (i32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i32.store8 (f32.const 0) (i32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i32.store16 (f32.const 0) (i32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store (f32.const 0) (i32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store8 (f32.const 0) (i64.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store16 (f32.const 0) (i64.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store32 (f32.const 0) (i64.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (f32.store (f32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (f64.store (f32.const 0) (f64.const 0)))) "type mismatch")
+
+(assert_invalid (module (memory 1) (func (i32.store (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i32.store8 (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i32.store16 (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store8 (i32.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store16 (i32.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store32 (i32.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (f32.store (i32.const 0) (i32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (f64.store (i32.const 0) (i64.const 0)))) "type mismatch")
diff --git a/binaryen/test/spec/store_retval.wast b/binaryen/test/spec/store_retval.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/store_retval.wast
@@ -0,0 +1,55 @@
+(assert_invalid
+  (module (func (param i32) (result i32) (local.set 0 (i32.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func (param i64) (result i64) (local.set 0 (i64.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func (param f32) (result f32) (local.set 0 (f32.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func (param f64) (result f64) (local.set 0 (f64.const 1))))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (memory 1) (func (param i32) (result i32) (i32.store (i32.const 0) (i32.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func (param i64) (result i64) (i64.store (i32.const 0) (i64.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func (param f32) (result f32) (f32.store (i32.const 0) (f32.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func (param f64) (result f64) (f64.store (i32.const 0) (f64.const 1))))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (memory 1) (func (param i32) (result i32) (i32.store8 (i32.const 0) (i32.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func (param i32) (result i32) (i32.store16 (i32.const 0) (i32.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func (param i64) (result i64) (i64.store8 (i32.const 0) (i64.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func (param i64) (result i64) (i64.store16 (i32.const 0) (i64.const 1))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (memory 1) (func (param i64) (result i64) (i64.store32 (i32.const 0) (i64.const 1))))
+  "type mismatch"
+)
+
diff --git a/binaryen/test/spec/switch.wast b/binaryen/test/spec/switch.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/switch.wast
@@ -0,0 +1,150 @@
+(module
+  ;; Statement switch
+  (func (export "stmt") (param $i i32) (result i32)
+    (local $j i32)
+    (local.set $j (i32.const 100))
+    (block $switch
+      (block $7
+        (block $default
+          (block $6
+            (block $5
+              (block $4
+                (block $3
+                  (block $2
+                    (block $1
+                      (block $0
+                        (br_table $0 $1 $2 $3 $4 $5 $6 $7 $default
+                          (local.get $i)
+                        )
+                      ) ;; 0
+                      (return (local.get $i))
+                    ) ;; 1
+                    (nop)
+                    ;; fallthrough
+                  ) ;; 2
+                  ;; fallthrough
+                ) ;; 3
+                (local.set $j (i32.sub (i32.const 0) (local.get $i)))
+                (br $switch)
+              ) ;; 4
+              (br $switch)
+            ) ;; 5
+            (local.set $j (i32.const 101))
+            (br $switch)
+          ) ;; 6
+          (local.set $j (i32.const 101))
+          ;; fallthrough
+        ) ;; default
+        (local.set $j (i32.const 102))
+      ) ;; 7
+      ;; fallthrough
+    )
+    (return (local.get $j))
+  )
+
+  ;; Expression switch
+  (func (export "expr") (param $i i64) (result i64)
+    (local $j i64)
+    (local.set $j (i64.const 100))
+    (return
+      (block $switch (result i64)
+        (block $7
+          (block $default
+            (block $4
+              (block $5
+                (block $6
+                  (block $3
+                    (block $2
+                      (block $1
+                        (block $0
+                          (br_table $0 $1 $2 $3 $4 $5 $6 $7 $default
+                            (i32.wrap_i64 (local.get $i))
+                          )
+                        ) ;; 0
+                        (return (local.get $i))
+                      ) ;; 1
+                      (nop)
+                      ;; fallthrough
+                    ) ;; 2
+                    ;; fallthrough
+                  ) ;; 3
+                  (br $switch (i64.sub (i64.const 0) (local.get $i)))
+                ) ;; 6
+                (local.set $j (i64.const 101))
+                ;; fallthrough
+              ) ;; 4
+              ;; fallthrough
+            ) ;; 5
+            ;; fallthrough
+          ) ;; default
+          (br $switch (local.get $j))
+        ) ;; 7
+        (i64.const -5)
+      )
+    )
+  )
+
+  ;; Argument switch
+  (func (export "arg") (param $i i32) (result i32)
+    (return
+      (block $2 (result i32)
+        (i32.add (i32.const 10)
+          (block $1 (result i32)
+            (i32.add (i32.const 100)
+              (block $0 (result i32)
+                (i32.add (i32.const 1000)
+                  (block $default (result i32)
+                    (br_table $0 $1 $2 $default
+                      (i32.mul (i32.const 2) (local.get $i))
+                      (i32.and (i32.const 3) (local.get $i))
+                    )
+                  )
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+
+  ;; Corner cases
+  (func (export "corner") (result i32)
+    (block
+      (br_table 0 (i32.const 0))
+    )
+    (i32.const 1)
+  )
+)
+
+(assert_return (invoke "stmt" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "stmt" (i32.const 1)) (i32.const -1))
+(assert_return (invoke "stmt" (i32.const 2)) (i32.const -2))
+(assert_return (invoke "stmt" (i32.const 3)) (i32.const -3))
+(assert_return (invoke "stmt" (i32.const 4)) (i32.const 100))
+(assert_return (invoke "stmt" (i32.const 5)) (i32.const 101))
+(assert_return (invoke "stmt" (i32.const 6)) (i32.const 102))
+(assert_return (invoke "stmt" (i32.const 7)) (i32.const 100))
+(assert_return (invoke "stmt" (i32.const -10)) (i32.const 102))
+
+(assert_return (invoke "expr" (i64.const 0)) (i64.const 0))
+(assert_return (invoke "expr" (i64.const 1)) (i64.const -1))
+(assert_return (invoke "expr" (i64.const 2)) (i64.const -2))
+(assert_return (invoke "expr" (i64.const 3)) (i64.const -3))
+(assert_return (invoke "expr" (i64.const 6)) (i64.const 101))
+(assert_return (invoke "expr" (i64.const 7)) (i64.const -5))
+(assert_return (invoke "expr" (i64.const -10)) (i64.const 100))
+
+(assert_return (invoke "arg" (i32.const 0)) (i32.const 110))
+(assert_return (invoke "arg" (i32.const 1)) (i32.const 12))
+(assert_return (invoke "arg" (i32.const 2)) (i32.const 4))
+(assert_return (invoke "arg" (i32.const 3)) (i32.const 1116))
+(assert_return (invoke "arg" (i32.const 4)) (i32.const 118))
+(assert_return (invoke "arg" (i32.const 5)) (i32.const 20))
+(assert_return (invoke "arg" (i32.const 6)) (i32.const 12))
+(assert_return (invoke "arg" (i32.const 7)) (i32.const 1124))
+(assert_return (invoke "arg" (i32.const 8)) (i32.const 126))
+
+(assert_return (invoke "corner") (i32.const 1))
+
+(assert_invalid (module (func (br_table 3 (i32.const 0)))) "unknown label")
diff --git a/binaryen/test/spec/tee_local.wast b/binaryen/test/spec/tee_local.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/tee_local.wast
@@ -0,0 +1,236 @@
+;; Test `local.tee` operator
+
+(module
+  ;; Typing
+
+  (func (export "type-local-i32") (result i32) (local i32) (local.tee 0 (i32.const 0)))
+  (func (export "type-local-i64") (result i64) (local i64) (local.tee 0 (i64.const 0)))
+  (func (export "type-local-f32") (result f32) (local f32) (local.tee 0 (f32.const 0)))
+  (func (export "type-local-f64") (result f64) (local f64) (local.tee 0 (f64.const 0)))
+
+  (func (export "type-param-i32") (param i32) (result i32) (local.tee 0 (i32.const 10)))
+  (func (export "type-param-i64") (param i64) (result i64) (local.tee 0 (i64.const 11)))
+  (func (export "type-param-f32") (param f32) (result f32) (local.tee 0 (f32.const 11.1)))
+  (func (export "type-param-f64") (param f64) (result f64) (local.tee 0 (f64.const 12.2)))
+
+  (func (export "type-mixed") (param i64 f32 f64 i32 i32) (local f32 i64 i64 f64)
+    (drop (i64.eqz (local.tee 0 (i64.const 0))))
+    (drop (f32.neg (local.tee 1 (f32.const 0))))
+    (drop (f64.neg (local.tee 2 (f64.const 0))))
+    (drop (i32.eqz (local.tee 3 (i32.const 0))))
+    (drop (i32.eqz (local.tee 4 (i32.const 0))))
+    (drop (f32.neg (local.tee 5 (f32.const 0))))
+    (drop (i64.eqz (local.tee 6 (i64.const 0))))
+    (drop (i64.eqz (local.tee 7 (i64.const 0))))
+    (drop (f64.neg (local.tee 8 (f64.const 0))))
+  )
+
+  ;; Writing
+
+  (func (export "write") (param i64 f32 f64 i32 i32) (result i64) (local f32 i64 i64 f64)
+    (drop (local.tee 1 (f32.const -0.3)))
+    (drop (local.tee 3 (i32.const 40)))
+    (drop (local.tee 4 (i32.const -7)))
+    (drop (local.tee 5 (f32.const 5.5)))
+    (drop (local.tee 6 (i64.const 6)))
+    (drop (local.tee 8 (f64.const 8)))
+    (i64.trunc_f64_s
+      (f64.add
+        (f64.convert_i64_u (local.get 0))
+        (f64.add
+          (f64.promote_f32 (local.get 1))
+          (f64.add
+            (local.get 2)
+            (f64.add
+              (f64.convert_i32_u (local.get 3))
+              (f64.add
+                (f64.convert_i32_s (local.get 4))
+                (f64.add
+                  (f64.promote_f32 (local.get 5))
+                  (f64.add
+                    (f64.convert_i64_u (local.get 6))
+                    (f64.add
+                      (f64.convert_i64_u (local.get 7))
+                      (local.get 8)
+                    )
+                  )
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+
+  ;; Result
+
+  (func (export "result") (param i64 f32 f64 i32 i32) (result f64)
+    (local f32 i64 i64 f64)
+    (f64.add
+      (f64.convert_i64_u (local.tee 0 (i64.const 1)))
+      (f64.add
+        (f64.promote_f32 (local.tee 1 (f32.const 2)))
+        (f64.add
+          (local.tee 2 (f64.const 3.3))
+          (f64.add
+            (f64.convert_i32_u (local.tee 3 (i32.const 4)))
+            (f64.add
+              (f64.convert_i32_s (local.tee 4 (i32.const 5)))
+              (f64.add
+                (f64.promote_f32 (local.tee 5 (f32.const 5.5)))
+                (f64.add
+                  (f64.convert_i64_u (local.tee 6 (i64.const 6)))
+                  (f64.add
+                    (f64.convert_i64_u (local.tee 7 (i64.const 0)))
+                    (local.tee 8 (f64.const 8))
+                  )
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+)
+
+(assert_return (invoke "type-local-i32") (i32.const 0))
+(assert_return (invoke "type-local-i64") (i64.const 0))
+(assert_return (invoke "type-local-f32") (f32.const 0))
+(assert_return (invoke "type-local-f64") (f64.const 0))
+
+(assert_return (invoke "type-param-i32" (i32.const 2)) (i32.const 10))
+(assert_return (invoke "type-param-i64" (i64.const 3)) (i64.const 11))
+(assert_return (invoke "type-param-f32" (f32.const 4.4)) (f32.const 11.1))
+(assert_return (invoke "type-param-f64" (f64.const 5.5)) (f64.const 12.2))
+
+(assert_return
+  (invoke "type-mixed"
+    (i64.const 1) (f32.const 2.2) (f64.const 3.3) (i32.const 4) (i32.const 5)
+  )
+)
+
+(assert_return
+  (invoke "write"
+    (i64.const 1) (f32.const 2) (f64.const 3.3) (i32.const 4) (i32.const 5)
+  )
+  (i64.const 56)
+)
+
+(assert_return
+  (invoke "result"
+    (i64.const -1) (f32.const -2) (f64.const -3.3) (i32.const -4) (i32.const -5)
+  )
+  (f64.const 34.8)
+)
+
+
+;; Invalid typing of access to locals
+
+(assert_invalid
+  (module (func $type-local-num-vs-num (result i64) (local i32) (local.tee 0 (i32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-num-vs-num (local f32) (i32.eqz (local.tee 0 (f32.const 0)))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-num-vs-num (local f64 i64) (f64.neg (local.tee 1 (i64.const 0)))))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-local-arg-void-vs-num (local i32) (local.tee 0 (nop))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-arg-num-vs-num (local i32) (local.tee 0 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-arg-num-vs-num (local f32) (local.tee 0 (f64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-local-arg-num-vs-num (local f64 i64) (local.tee 1 (f64.const 0))))
+  "type mismatch"
+)
+
+
+;; Invalid typing of access to parameters
+
+(assert_invalid
+  (module (func $type-param-num-vs-num (param i32) (result i64) (local.get 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-num-vs-num (param f32) (i32.eqz (local.get 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-num-vs-num (param f64 i64) (f64.neg (local.get 1))))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-param-arg-void-vs-num (param i32) (local.tee 0 (nop))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-arg-num-vs-num (param i32) (local.tee 0 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-arg-num-vs-num (param f32) (local.tee 0 (f64.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-param-arg-num-vs-num (param f64 i64) (local.tee 1 (f64.const 0))))
+  "type mismatch"
+)
+
+
+;; Invalid local index
+
+(assert_invalid
+  (module (func $unbound-local (local i32 i64) (local.get 3)))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-local (local i32 i64) (local.get 14324343)))
+  "unknown local"
+)
+
+(assert_invalid
+  (module (func $unbound-param (param i32 i64) (local.get 2)))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-param (local i32 i64) (local.get 714324343)))
+  "unknown local"
+)
+
+(assert_invalid
+  (module (func $unbound-mixed (param i32) (local i32 i64) (local.get 3)))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $large-mixed (param i64) (local i32 i64) (local.get 214324343)))
+  "unknown local"
+)
+
+(assert_invalid
+  (module (func $type-mixed-arg-num-vs-num (param f32) (local i32) (local.tee 1 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-mixed-arg-num-vs-num (param i64 i32) (local f32) (local.tee 1 (f32.const 0))))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-mixed-arg-num-vs-num (param i64) (local f64 i64) (local.tee 1 (i64.const 0))))
+  "type mismatch"
+)
+
diff --git a/binaryen/test/spec/token.wast b/binaryen/test/spec/token.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/token.wast
@@ -0,0 +1,10 @@
+;; Test tokenization
+
+(assert_malformed
+  (module quote "(func (drop (i32.const0)))")
+  "unknown operator"
+)
+(assert_malformed
+  (module quote "(func br 0drop)")
+  "unknown operator"
+)
diff --git a/binaryen/test/spec/traps.wast b/binaryen/test/spec/traps.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/traps.wast
@@ -0,0 +1,91 @@
+;; Test that traps are preserved even in instructions which might otherwise
+;; be dead-code-eliminated. These functions all perform an operation and
+;; discard its return value.
+
+(module
+  (func (export "no_dce.i32.div_s") (param $x i32) (param $y i32)
+    (drop (i32.div_s (local.get $x) (local.get $y))))
+  (func (export "no_dce.i32.div_u") (param $x i32) (param $y i32)
+    (drop (i32.div_u (local.get $x) (local.get $y))))
+  (func (export "no_dce.i64.div_s") (param $x i64) (param $y i64)
+    (drop (i64.div_s (local.get $x) (local.get $y))))
+  (func (export "no_dce.i64.div_u") (param $x i64) (param $y i64)
+    (drop (i64.div_u (local.get $x) (local.get $y))))
+)
+
+(assert_trap (invoke "no_dce.i32.div_s" (i32.const 1) (i32.const 0)) "integer divide by zero")
+(assert_trap (invoke "no_dce.i32.div_u" (i32.const 1) (i32.const 0)) "integer divide by zero")
+(assert_trap (invoke "no_dce.i64.div_s" (i64.const 1) (i64.const 0)) "integer divide by zero")
+(assert_trap (invoke "no_dce.i64.div_u" (i64.const 1) (i64.const 0)) "integer divide by zero")
+(assert_trap (invoke "no_dce.i32.div_s" (i32.const 0x80000000) (i32.const -1)) "integer overflow")
+(assert_trap (invoke "no_dce.i64.div_s" (i64.const 0x8000000000000000) (i64.const -1)) "integer overflow")
+
+(module
+  (func (export "no_dce.i32.rem_s") (param $x i32) (param $y i32)
+    (drop (i32.rem_s (local.get $x) (local.get $y))))
+  (func (export "no_dce.i32.rem_u") (param $x i32) (param $y i32)
+    (drop (i32.rem_u (local.get $x) (local.get $y))))
+  (func (export "no_dce.i64.rem_s") (param $x i64) (param $y i64)
+    (drop (i64.rem_s (local.get $x) (local.get $y))))
+  (func (export "no_dce.i64.rem_u") (param $x i64) (param $y i64)
+    (drop (i64.rem_u (local.get $x) (local.get $y))))
+)
+
+(assert_trap (invoke "no_dce.i32.rem_s" (i32.const 1) (i32.const 0)) "integer divide by zero")
+(assert_trap (invoke "no_dce.i32.rem_u" (i32.const 1) (i32.const 0)) "integer divide by zero")
+(assert_trap (invoke "no_dce.i64.rem_s" (i64.const 1) (i64.const 0)) "integer divide by zero")
+(assert_trap (invoke "no_dce.i64.rem_u" (i64.const 1) (i64.const 0)) "integer divide by zero")
+
+(module
+  (func (export "no_dce.i32.trunc_f32_s") (param $x f32) (drop (i32.trunc_f32_s (local.get $x))))
+  (func (export "no_dce.i32.trunc_f32_u") (param $x f32) (drop (i32.trunc_f32_u (local.get $x))))
+  (func (export "no_dce.i32.trunc_f64_s") (param $x f64) (drop (i32.trunc_f64_s (local.get $x))))
+  (func (export "no_dce.i32.trunc_f64_u") (param $x f64) (drop (i32.trunc_f64_u (local.get $x))))
+  (func (export "no_dce.i64.trunc_f32_s") (param $x f32) (drop (i64.trunc_f32_s (local.get $x))))
+  (func (export "no_dce.i64.trunc_f32_u") (param $x f32) (drop (i64.trunc_f32_u (local.get $x))))
+  (func (export "no_dce.i64.trunc_f64_s") (param $x f64) (drop (i64.trunc_f64_s (local.get $x))))
+  (func (export "no_dce.i64.trunc_f64_u") (param $x f64) (drop (i64.trunc_f64_u (local.get $x))))
+)
+
+(assert_trap (invoke "no_dce.i32.trunc_f32_s" (f32.const nan)) "invalid conversion to integer")
+(assert_trap (invoke "no_dce.i32.trunc_f32_u" (f32.const nan)) "invalid conversion to integer")
+(assert_trap (invoke "no_dce.i32.trunc_f64_s" (f64.const nan)) "invalid conversion to integer")
+(assert_trap (invoke "no_dce.i32.trunc_f64_u" (f64.const nan)) "invalid conversion to integer")
+(assert_trap (invoke "no_dce.i64.trunc_f32_s" (f32.const nan)) "invalid conversion to integer")
+(assert_trap (invoke "no_dce.i64.trunc_f32_u" (f32.const nan)) "invalid conversion to integer")
+(assert_trap (invoke "no_dce.i64.trunc_f64_s" (f64.const nan)) "invalid conversion to integer")
+(assert_trap (invoke "no_dce.i64.trunc_f64_u" (f64.const nan)) "invalid conversion to integer")
+
+(module
+    (memory 1)
+
+    (func (export "no_dce.i32.load") (param $i i32) (drop (i32.load (local.get $i))))
+    (func (export "no_dce.i32.load16_s") (param $i i32) (drop (i32.load16_s (local.get $i))))
+    (func (export "no_dce.i32.load16_u") (param $i i32) (drop (i32.load16_u (local.get $i))))
+    (func (export "no_dce.i32.load8_s") (param $i i32) (drop (i32.load8_s (local.get $i))))
+    (func (export "no_dce.i32.load8_u") (param $i i32) (drop (i32.load8_u (local.get $i))))
+    (func (export "no_dce.i64.load") (param $i i32) (drop (i64.load (local.get $i))))
+    (func (export "no_dce.i64.load32_s") (param $i i32) (drop (i64.load32_s (local.get $i))))
+    (func (export "no_dce.i64.load32_u") (param $i i32) (drop (i64.load32_u (local.get $i))))
+    (func (export "no_dce.i64.load16_s") (param $i i32) (drop (i64.load16_s (local.get $i))))
+    (func (export "no_dce.i64.load16_u") (param $i i32) (drop (i64.load16_u (local.get $i))))
+    (func (export "no_dce.i64.load8_s") (param $i i32) (drop (i64.load8_s (local.get $i))))
+    (func (export "no_dce.i64.load8_u") (param $i i32) (drop (i64.load8_u (local.get $i))))
+    (func (export "no_dce.f32.load") (param $i i32) (drop (f32.load (local.get $i))))
+    (func (export "no_dce.f64.load") (param $i i32) (drop (f64.load (local.get $i))))
+)
+
+(assert_trap (invoke "no_dce.i32.load" (i32.const 65536)) "out of bounds memory access")
+(assert_trap (invoke "no_dce.i32.load16_s" (i32.const 65536)) "out of bounds memory access")
+(assert_trap (invoke "no_dce.i32.load16_u" (i32.const 65536)) "out of bounds memory access")
+(assert_trap (invoke "no_dce.i32.load8_s" (i32.const 65536)) "out of bounds memory access")
+(assert_trap (invoke "no_dce.i32.load8_u" (i32.const 65536)) "out of bounds memory access")
+(assert_trap (invoke "no_dce.i64.load" (i32.const 65536)) "out of bounds memory access")
+(assert_trap (invoke "no_dce.i64.load32_s" (i32.const 65536)) "out of bounds memory access")
+(assert_trap (invoke "no_dce.i64.load32_u" (i32.const 65536)) "out of bounds memory access")
+(assert_trap (invoke "no_dce.i64.load16_s" (i32.const 65536)) "out of bounds memory access")
+(assert_trap (invoke "no_dce.i64.load16_u" (i32.const 65536)) "out of bounds memory access")
+(assert_trap (invoke "no_dce.i64.load8_s" (i32.const 65536)) "out of bounds memory access")
+(assert_trap (invoke "no_dce.i64.load8_u" (i32.const 65536)) "out of bounds memory access")
+(assert_trap (invoke "no_dce.f32.load" (i32.const 65536)) "out of bounds memory access")
+(assert_trap (invoke "no_dce.f64.load" (i32.const 65536)) "out of bounds memory access")
diff --git a/binaryen/test/spec/type.wast b/binaryen/test/spec/type.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/type.wast
@@ -0,0 +1,59 @@
+;; Test type definitions
+
+(module
+  (type (func))
+  (type $t (func))
+
+  (type (func (param i32)))
+  (type (func (param $x i32)))
+  (type (func (result i32)))
+  (type (func (param i32) (result i32)))
+  (type (func (param $x i32) (result i32)))
+
+  (type (func (param f32 f64)))
+  ;; (type (func (result i64 f32)))
+  ;; (type (func (param i32 i64) (result f32 f64)))
+
+  (type (func (param f32) (param f64)))
+  (type (func (param $x f32) (param f64)))
+  (type (func (param f32) (param $y f64)))
+  (type (func (param $x f32) (param $y f64)))
+  ;; (type (func (result i64) (result f32)))
+  ;; (type (func (param i32) (param i64) (result f32) (result f64)))
+  ;; (type (func (param $x i32) (param $y i64) (result f32) (result f64)))
+
+  (type (func (param f32 f64) (param $x i32) (param f64 i32 i32)))
+  ;; (type (func (result i64 i64 f32) (result f32 i32)))
+  ;; (type
+  ;;   (func (param i32 i32) (param i64 i32) (result f32 f64) (result f64 i32))
+  ;; )
+
+  (type (func (param) (param $x f32) (param) (param) (param f64 i32) (param)))
+  ;; (type
+  ;;   (func (result) (result) (result i64 i64) (result) (result f32) (result))
+  ;; )
+  ;; (type
+  ;;   (func
+  ;;     (param i32 i32) (param i64 i32) (param) (param $x i32) (param)
+  ;;     (result) (result f32 f64) (result f64 i32) (result)
+  ;;   )
+  ;; )
+)
+
+(assert_malformed
+  (module quote "(type (func (result i32) (param i32)))")
+  "result before parameter"
+)
+(assert_malformed
+  (module quote "(type (func (result $x i32)))")
+  "unexpected token"
+)
+
+(assert_invalid
+  (module (type (func (result i32 i32))))
+  "invalid result arity"
+)
+(assert_invalid
+  (module (type (func (result i32) (result i32))))
+  "invalid result arity"
+)
diff --git a/binaryen/test/spec/typecheck.wast b/binaryen/test/spec/typecheck.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/typecheck.wast
@@ -0,0 +1,433 @@
+;; TODO: move all tests in this file to appropriate operator-specific files.
+
+(assert_invalid
+  (module (func $type-unary-operand-missing
+    (i32.eqz) (drop)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unary-operand-missing-in-block
+    (i32.const 0)
+    (block (i32.eqz) (drop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unary-operand-missing-in-loop
+   (i32.const 0)
+   (loop (i32.eqz) (drop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unary-operand-missing-in-if
+    (i32.const 0) (i32.const 0)
+    (if (then (i32.eqz) (drop)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unary-operand-missing-in-else
+    (i32.const 0) (i32.const 0)
+    (if i32 (then (i32.const 0)) (else (i32.eqz))) (drop)
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-binary-1st-operand-missing
+    (i32.add) (drop)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-2nd-operand-missing
+    (i32.const 0) (i32.add) (drop)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-1st-operand-missing-in-block
+    (i32.const 0) (i32.const 0)
+    (block (i32.add) (drop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-2nd-operand-missing-in-block
+    (i32.const 0)
+    (block (i32.const 0) (i32.add) (drop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-1st-operand-missing-in-loop
+    (i32.const 0) (i32.const 0)
+    (loop (i32.add) (drop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-2nd-operand-missing-in-loop
+    (i32.const 0)
+    (loop (i32.const 0) (i32.add) (drop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-1st-operand-missing-in-if
+    (i32.const 0) (i32.const 0) (i32.const 0)
+    (if (i32.add) (drop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-2nd-operand-missing-in-if
+    (i32.const 0) (i32.const 0)
+    (if (i32.const 0) (i32.add) (drop))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-1st-operand-missing-in-else
+    (i32.const 0) (i32.const 0) (i32.const 0)
+    (if i32 (then (i32.const 0)) (else (i32.add) (i32.const 0)))
+    (drop) (drop)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-2nd-operand-missing-in-else
+    (i32.const 0) (i32.const 0)
+    (if i32 (then (i32.const 0)) (else (i32.add)))
+    (drop)
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-if-operand-missing
+    (if (then))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-if-operand-missing-in-block
+    (i32.const 0)
+    (block (if (then)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-if-operand-missing-in-loop
+    (i32.const 0)
+    (loop (if (then)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-if-operand-missing-in-if
+    (i32.const 0) (i32.const 0)
+    (if (then (if (then))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-if-operand-missing-in-else
+    (i32.const 0) (i32.const 0)
+    (if i32 (then (i32.const 0)) (else (if (then)) (i32.const 0)))
+    (drop)
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-br-operand-missing
+    (block i32 (br 0))
+    (i32.eqz) (drop)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-br-operand-missing-in-block
+    (i32.const 0)
+    (block i32 (br 0))
+    (i32.eqz) (drop)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-br-operand-missing-in-loop
+    (i32.const 0)
+    (loop i32 (br 0))
+    (i32.eqz) (drop)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-br-operand-missing-in-if
+    (block
+      (i32.const 0) (i32.const 0)
+      (if i32 (then (br 0)))
+    )
+    (i32.eqz) (drop)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-br-operand-missing-in-else
+    (block
+      (i32.const 0) (i32.const 0)
+      (if i32 (then (i32.const 0)) (else (br 0)))
+    )
+    (i32.eqz) (drop)
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-return-operand-missing (result i32)
+    (return)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-return-operand-missing-in-block (result i32)
+    (i32.const 0)
+    (block (return))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-return-operand-missing-in-loop (result i32)
+    (i32.const 0)
+    (loop (return))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-return-operand-missing-in-if (result i32)
+    (i32.const 0) (i32.const 0)
+    (if (then (return)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-return-operand-missing-in-else (result i32)
+    (i32.const 0) (i32.const 0)
+    (if i32 (then (i32.const 0)) (else (return))) (drop)
+  ))
+  "type mismatch"
+)
+
+;; TODO(stack): more of the above
+
+;; if condition
+(assert_invalid (module (func (if (f32.const 0) (nop) (nop)))) "type mismatch")
+
+;; br_if condition
+(assert_invalid (module (func (block (br_if 0 (f32.const 0))))) "type mismatch")
+
+;; br_table key
+(assert_invalid
+  (module (func (block (br_table 0 (f32.const 0)))))
+  "type mismatch")
+
+;; call params
+(assert_invalid (module (func (param i32)) (func (call 0 (f32.const 0)))) "type mismatch")
+(assert_invalid
+  (module
+    (type (func (param i32)))
+    (func (type 0))
+    (table 0 funcref)
+    (func
+      (call_indirect (type 0) (i32.const 0) (f32.const 0))))
+  "type mismatch")
+
+;; call_indirect (type index)
+(assert_invalid
+  (module
+    (type (func))
+    (func (type 0))
+    (table 0 funcref)
+    (func (call_indirect (type 0) (f32.const 0))))
+  "type mismatch")
+
+;; return
+(assert_invalid (module (func (result i32) (return (f32.const 0)))) "type mismatch")
+
+;; local.set
+(assert_invalid (module (func (local i32) (local.set 0 (f32.const 0)))) "type mismatch")
+
+;; load index
+(assert_invalid (module (memory 1) (func (i32.load (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i32.load8_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i32.load8_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i32.load16_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i32.load16_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.load (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.load8_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.load8_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.load16_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.load16_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.load32_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.load32_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (f32.load (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (f64.load (f32.const 0)))) "type mismatch")
+
+;; store index
+(assert_invalid (module (memory 1) (func (i32.store (f32.const 0) (i32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i32.store8 (f32.const 0) (i32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i32.store16 (f32.const 0) (i32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store (f32.const 0) (i32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store8 (f32.const 0) (i64.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store16 (f32.const 0) (i64.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store32 (f32.const 0) (i64.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (f32.store (f32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (f64.store (f32.const 0) (f64.const 0)))) "type mismatch")
+
+;; store value
+(assert_invalid (module (memory 1) (func (i32.store (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i32.store8 (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i32.store16 (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store8 (i32.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store16 (i32.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (i64.store32 (i32.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (f32.store (i32.const 0) (i32.const 0)))) "type mismatch")
+(assert_invalid (module (memory 1) (func (f64.store (i32.const 0) (i64.const 0)))) "type mismatch")
+
+;; binary
+(assert_invalid (module (func (i32.add (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.and (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.div_s (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.div_u (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.mul (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.or (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.rem_s (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.rem_u (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.rotl (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.rotr (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.shl (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.shr_s (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.shr_u (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.sub (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.xor (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.add (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.and (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.div_s (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.div_u (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.mul (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.or (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.rem_s (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.rem_u (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.rotl (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.rotr (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.shl (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.shr_s (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.shr_u (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.sub (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.xor (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.add (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.copysign (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.div (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.max (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.min (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.mul (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.sub (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.add (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.copysign (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.div (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.max (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.min (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.mul (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.sub (i64.const 0) (f32.const 0)))) "type mismatch")
+
+;; unary
+(assert_invalid (module (func (i32.eqz (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.clz (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.ctz (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.popcnt (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.eqz (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.clz (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.ctz (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.popcnt (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.abs (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.ceil (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.floor (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.nearest (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.neg (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.sqrt (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.trunc (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.abs (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.ceil (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.floor (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.nearest (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.neg (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.sqrt (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.trunc (i64.const 0)))) "type mismatch")
+
+;; compare
+(assert_invalid (module (func (i32.eq (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.ge_s (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.ge_u (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.gt_s (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.gt_u (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.le_s (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.le_u (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.lt_s (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.lt_u (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.ne (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.eq (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.ge_s (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.ge_u (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.gt_s (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.gt_u (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.le_s (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.le_u (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.lt_s (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.lt_u (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.ne (i32.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.eq (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.ge (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.gt (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.le (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.lt (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.ne (i64.const 0) (f64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.eq (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.ge (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.gt (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.le (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.lt (i64.const 0) (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.ne (i64.const 0) (f32.const 0)))) "type mismatch")
+
+;; convert
+(assert_invalid (module (func (i32.wrap_i64 (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.trunc_f32_s (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.trunc_f32_u (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.trunc_f64_s (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.trunc_f64_u (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (i32.reinterpret_f32 (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.extend_i32_s (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.extend_i32_u (f32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.trunc_f32_s (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.trunc_f32_u (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.trunc_f64_s (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.trunc_f64_u (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (i64.reinterpret_f64 (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.convert_i32_s (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.convert_i32_u (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.convert_i64_s (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.convert_i64_u (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.demote_f64 (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f32.reinterpret_i32 (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.convert_i32_s (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.convert_i32_u (i64.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.convert_i64_s (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.convert_i64_u (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.promote_f32 (i32.const 0)))) "type mismatch")
+(assert_invalid (module (func (f64.reinterpret_i64 (i32.const 0)))) "type mismatch")
+
+;; memory.grow
+(assert_invalid (module (memory 1) (func (memory.grow (f32.const 0)))) "type mismatch")
diff --git a/binaryen/test/spec/unreachable.wast b/binaryen/test/spec/unreachable.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/unreachable.wast
@@ -0,0 +1,304 @@
+;; Test `unreachable` operator
+
+(module
+  ;; Auxiliary definitions
+  (func $dummy)
+  (func $dummy3 (param i32 i32 i32))
+
+  (func (export "type-i32") (result i32) (unreachable))
+  (func (export "type-i64") (result i32) (unreachable))
+  (func (export "type-f32") (result f64) (unreachable))
+  (func (export "type-f64") (result f64) (unreachable))
+
+  (func (export "as-func-first") (result i32)
+    (unreachable) (i32.const -1)
+  )
+  (func (export "as-func-mid") (result i32)
+    (call $dummy) (unreachable) (i32.const -1)
+  )
+  (func (export "as-func-last")
+    (call $dummy) (unreachable)
+  )
+  (func (export "as-func-value") (result i32)
+    (call $dummy) (unreachable)
+  )
+
+  (func (export "as-block-first") (result i32)
+    (block (result i32) (unreachable) (i32.const 2))
+  )
+  (func (export "as-block-mid") (result i32)
+    (block (result i32) (call $dummy) (unreachable) (i32.const 2))
+  )
+  (func (export "as-block-last")
+    (block (nop) (call $dummy) (unreachable))
+  )
+  (func (export "as-block-value") (result i32)
+    (block (result i32) (nop) (call $dummy) (unreachable))
+  )
+  (func (export "as-block-broke") (result i32)
+    (block (result i32) (call $dummy) (br 0 (i32.const 1)) (unreachable))
+  )
+
+  (func (export "as-loop-first") (result i32)
+    (loop (result i32) (unreachable) (i32.const 2))
+  )
+  (func (export "as-loop-mid") (result i32)
+    (loop (result i32) (call $dummy) (unreachable) (i32.const 2))
+  )
+  (func (export "as-loop-last")
+    (loop (nop) (call $dummy) (unreachable))
+  )
+  (func (export "as-loop-broke") (result i32)
+    (block (result i32)
+      (loop (result i32) (call $dummy) (br 1 (i32.const 1)) (unreachable))
+    )
+  )
+
+  (func (export "as-br-value") (result i32)
+    (block (result i32) (br 0 (unreachable)))
+  )
+
+  (func (export "as-br_if-cond")
+    (block (br_if 0 (unreachable)))
+  )
+  (func (export "as-br_if-value") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (unreachable) (i32.const 1))) (i32.const 7)
+    )
+  )
+  (func (export "as-br_if-value-cond") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (i32.const 6) (unreachable))) (i32.const 7)
+    )
+  )
+
+  (func (export "as-br_table-index")
+    (block (br_table 0 0 0 (unreachable)))
+  )
+  (func (export "as-br_table-value") (result i32)
+    (block (result i32)
+      (br_table 0 0 0 (unreachable) (i32.const 1)) (i32.const 7)
+    )
+  )
+  (func (export "as-br_table-value-2") (result i32)
+    (block (result i32)
+      (block (result i32) (br_table 0 1 (unreachable) (i32.const 1)))
+    )
+  )
+  (func (export "as-br_table-value-index") (result i32)
+    (block (result i32)
+      (br_table 0 0 (i32.const 6) (unreachable)) (i32.const 7)
+    )
+  )
+  (func (export "as-br_table-value-and-index") (result i32)
+    (block (result i32) (br_table 0 0 (unreachable)) (i32.const 8))
+  )
+
+  (func (export "as-return-value") (result i64)
+    (return (unreachable))
+  )
+
+  (func (export "as-if-cond") (result i32)
+    (if (result i32) (unreachable) (then (i32.const 0)) (else (i32.const 1)))
+  )
+  (func (export "as-if-then") (param i32 i32) (result i32)
+    (if (result i32) (local.get 0) (then (unreachable)) (else (local.get 1)))
+  )
+  (func (export "as-if-else") (param i32 i32) (result i32)
+    (if (result i32) (local.get 0) (then (local.get 1)) (else (unreachable)))
+  )
+  (func (export "as-if-then-no-else") (param i32 i32) (result i32)
+    (if (local.get 0) (then (unreachable))) (local.get 1)
+  )
+
+  (func (export "as-select-first") (param i32 i32) (result i32)
+    (select (unreachable) (local.get 0) (local.get 1))
+  )
+  (func (export "as-select-second") (param i32 i32) (result i32)
+    (select (local.get 0) (unreachable) (local.get 1))
+  )
+  (func (export "as-select-cond") (result i32)
+    (select (i32.const 0) (i32.const 1) (unreachable))
+  )
+
+  (func (export "as-call-first")
+    (call $dummy3 (unreachable) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-call-mid")
+    (call $dummy3 (i32.const 1) (unreachable) (i32.const 3))
+  )
+  (func (export "as-call-last")
+    (call $dummy3 (i32.const 1) (i32.const 2) (unreachable))
+  )
+
+  (type $sig (func (param i32 i32 i32)))
+  (table funcref (elem $dummy3))
+  (func (export "as-call_indirect-func")
+    (call_indirect (type $sig)
+      (unreachable) (i32.const 1) (i32.const 2) (i32.const 3)
+    )
+  )
+  (func (export "as-call_indirect-first")
+    (call_indirect (type $sig)
+      (i32.const 0) (unreachable) (i32.const 2) (i32.const 3)
+    )
+  )
+  (func (export "as-call_indirect-mid")
+    (call_indirect (type $sig)
+      (i32.const 0) (i32.const 1) (unreachable) (i32.const 3)
+    )
+  )
+  (func (export "as-call_indirect-last")
+    (call_indirect (type $sig)
+      (i32.const 0) (i32.const 1) (i32.const 2) (unreachable)
+    )
+  )
+
+  (func (export "as-local.set-value") (local f32)
+    (local.set 0 (unreachable))
+  )
+  (func (export "as-local.tee-value") (result f32) (local f32)
+    (local.tee 0 (unreachable))
+  )
+  (global $a (mut f32) (f32.const 0))
+  (func (export "as-global.set-value") (result f32)
+    (global.set $a (unreachable))
+  )
+
+  (memory 1)
+  (func (export "as-load-address") (result f32)
+    (f32.load (unreachable))
+  )
+  (func (export "as-loadN-address") (result i64)
+    (i64.load8_s (unreachable))
+  )
+
+  (func (export "as-store-address")
+    (f64.store (unreachable) (f64.const 7))
+  )
+  (func (export "as-store-value")
+    (i64.store (i32.const 2) (unreachable))
+  )
+
+  (func (export "as-storeN-address")
+    (i32.store8 (unreachable) (i32.const 7))
+  )
+  (func (export "as-storeN-value")
+    (i64.store16 (i32.const 2) (unreachable))
+  )
+
+  (func (export "as-unary-operand") (result f32)
+    (f32.neg (unreachable))
+  )
+
+  (func (export "as-binary-left") (result i32)
+    (i32.add (unreachable) (i32.const 10))
+  )
+  (func (export "as-binary-right") (result i64)
+    (i64.sub (i64.const 10) (unreachable))
+  )
+
+  (func (export "as-test-operand") (result i32)
+    (i32.eqz (unreachable))
+  )
+
+  (func (export "as-compare-left") (result i32)
+    (f64.le (unreachable) (f64.const 10))
+  )
+  (func (export "as-compare-right") (result i32)
+    (f32.ne (f32.const 10) (unreachable))
+  )
+
+  (func (export "as-convert-operand") (result i32)
+    (i32.wrap_i64 (unreachable))
+  )
+
+  (func (export "as-memory.grow-size") (result i32)
+    (memory.grow (unreachable))
+  )
+)
+
+(assert_trap (invoke "type-i32") "unreachable")
+(assert_trap (invoke "type-i64") "unreachable")
+(assert_trap (invoke "type-f32") "unreachable")
+(assert_trap (invoke "type-f64") "unreachable")
+
+(assert_trap (invoke "as-func-first") "unreachable")
+(assert_trap (invoke "as-func-mid") "unreachable")
+(assert_trap (invoke "as-func-last") "unreachable")
+(assert_trap (invoke "as-func-value") "unreachable")
+
+(assert_trap (invoke "as-block-first") "unreachable")
+(assert_trap (invoke "as-block-mid") "unreachable")
+(assert_trap (invoke "as-block-last") "unreachable")
+(assert_trap (invoke "as-block-value") "unreachable")
+(assert_return (invoke "as-block-broke") (i32.const 1))
+
+(assert_trap (invoke "as-loop-first") "unreachable")
+(assert_trap (invoke "as-loop-mid") "unreachable")
+(assert_trap (invoke "as-loop-last") "unreachable")
+(assert_return (invoke "as-loop-broke") (i32.const 1))
+
+(assert_trap (invoke "as-br-value") "unreachable")
+
+(assert_trap (invoke "as-br_if-cond") "unreachable")
+(assert_trap (invoke "as-br_if-value") "unreachable")
+(assert_trap (invoke "as-br_if-value-cond") "unreachable")
+
+(assert_trap (invoke "as-br_table-index") "unreachable")
+(assert_trap (invoke "as-br_table-value") "unreachable")
+(assert_trap (invoke "as-br_table-value-2") "unreachable")
+(assert_trap (invoke "as-br_table-value-index") "unreachable")
+(assert_trap (invoke "as-br_table-value-and-index") "unreachable")
+
+(assert_trap (invoke "as-return-value") "unreachable")
+
+(assert_trap (invoke "as-if-cond") "unreachable")
+(assert_trap (invoke "as-if-then" (i32.const 1) (i32.const 6)) "unreachable")
+(assert_return (invoke "as-if-then" (i32.const 0) (i32.const 6)) (i32.const 6))
+(assert_trap (invoke "as-if-else" (i32.const 0) (i32.const 6)) "unreachable")
+(assert_return (invoke "as-if-else" (i32.const 1) (i32.const 6)) (i32.const 6))
+(assert_trap (invoke "as-if-then-no-else" (i32.const 1) (i32.const 6)) "unreachable")
+(assert_return (invoke "as-if-then-no-else" (i32.const 0) (i32.const 6)) (i32.const 6))
+
+(assert_trap (invoke "as-select-first" (i32.const 0) (i32.const 6)) "unreachable")
+(assert_trap (invoke "as-select-first" (i32.const 1) (i32.const 6)) "unreachable")
+(assert_trap (invoke "as-select-second" (i32.const 0) (i32.const 6)) "unreachable")
+(assert_trap (invoke "as-select-second" (i32.const 1) (i32.const 6)) "unreachable")
+(assert_trap (invoke "as-select-cond") "unreachable")
+
+(assert_trap (invoke "as-call-first") "unreachable")
+(assert_trap (invoke "as-call-mid") "unreachable")
+(assert_trap (invoke "as-call-last") "unreachable")
+
+(assert_trap (invoke "as-call_indirect-func") "unreachable")
+(assert_trap (invoke "as-call_indirect-first") "unreachable")
+(assert_trap (invoke "as-call_indirect-mid") "unreachable")
+(assert_trap (invoke "as-call_indirect-last") "unreachable")
+
+(assert_trap (invoke "as-local.set-value") "unreachable")
+(assert_trap (invoke "as-local.tee-value") "unreachable")
+(assert_trap (invoke "as-global.set-value") "unreachable")
+
+(assert_trap (invoke "as-load-address") "unreachable")
+(assert_trap (invoke "as-loadN-address") "unreachable")
+
+(assert_trap (invoke "as-store-address") "unreachable")
+(assert_trap (invoke "as-store-value") "unreachable")
+(assert_trap (invoke "as-storeN-address") "unreachable")
+(assert_trap (invoke "as-storeN-value") "unreachable")
+
+(assert_trap (invoke "as-unary-operand") "unreachable")
+
+(assert_trap (invoke "as-binary-left") "unreachable")
+(assert_trap (invoke "as-binary-right") "unreachable")
+
+(assert_trap (invoke "as-test-operand") "unreachable")
+
+(assert_trap (invoke "as-compare-left") "unreachable")
+(assert_trap (invoke "as-compare-right") "unreachable")
+
+(assert_trap (invoke "as-convert-operand") "unreachable")
+
+(assert_trap (invoke "as-memory.grow-size") "unreachable")
+
diff --git a/binaryen/test/spec/unreached-invalid.wast b/binaryen/test/spec/unreached-invalid.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/unreached-invalid.wast
@@ -0,0 +1,709 @@
+;; Failures in unreachable code.
+
+(assert_invalid
+  (module (func $local-index (unreachable) (drop (local.get 0))))
+  "unknown local"
+)
+(assert_invalid
+  (module (func $global-index (unreachable) (drop (global.get 0))))
+  "unknown global"
+)
+(assert_invalid
+  (module (func $func-index (unreachable) (call 1)))
+  "unknown function"
+)
+(assert_invalid
+  (module (func $label-index (unreachable) (br 1)))
+  "unknown label"
+)
+
+(assert_invalid
+  (module (func $type-num-vs-num
+    (unreachable) (drop (i64.eqz (i32.const 0))))
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-poly-num-vs-num (result i32)
+    (unreachable) (i64.const 0) (i32.const 0) (select)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-poly-transitive-num-vs-num (result i32)
+    (unreachable)
+    (i64.const 0) (i32.const 0) (select)
+    (i32.const 0) (i32.const 0) (select)
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-unconsumed-const (unreachable) (i32.const 0)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unconsumed-result (unreachable) (i32.eqz)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unconsumed-result2
+    (unreachable) (i32.const 0) (i32.add)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unconsumed-poly0 (unreachable) (select)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unconsumed-poly1 (unreachable) (i32.const 0) (select)))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unconsumed-poly2
+    (unreachable) (i32.const 0) (i32.const 0) (select)
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-unary-num-vs-void-after-break
+    (block (br 0) (block (drop (i32.eqz (nop)))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unary-num-vs-num-after-break
+    (block (br 0) (drop (i32.eqz (f32.const 1))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-num-vs-void-after-break
+    (block (br 0) (block (drop (f32.eq (i32.const 1)))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-num-vs-num-after-break
+    (block (br 0) (drop (f32.eq (i32.const 1) (f32.const 0))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-num-vs-void-after-break
+    (block (br 0) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-num-vs-num-after-break (result i32)
+    (block (result i32) (i32.const 1) (br 0) (f32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-loop-value-num-vs-void-after-break
+    (block (loop (br 1) (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-loop-value-num-vs-num-after-break (result i32)
+    (loop (result i32) (br 1 (i32.const 1)) (f32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-func-value-num-vs-void-after-break
+    (br 0) (i32.const 1)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-func-value-num-vs-num-after-break (result i32)
+    (br 0 (i32.const 1)) (f32.const 0)
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-unary-num-vs-void-after-return
+    (return) (block (drop (i32.eqz (nop))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unary-num-vs-num-after-return
+    (return) (drop (i32.eqz (f32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-num-vs-void-after-return
+    (return) (block (drop (f32.eq (i32.const 1))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-num-vs-num-after-return
+    (return) (drop (f32.eq (i32.const 1) (f32.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-num-vs-void-after-return
+    (block (return) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-num-vs-num-after-return (result i32)
+    (block (result i32) (i32.const 1) (return (i32.const 0)) (f32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-loop-value-num-vs-void-after-return
+    (block (loop (return) (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-loop-value-num-vs-num-after-return (result i32)
+    (loop (result i32) (return (i32.const 1)) (f32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-func-value-num-vs-void-after-return
+    (return) (i32.const 1)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-func-value-num-vs-num-after-return (result i32)
+    (return (i32.const 1)) (f32.const 0)
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-unary-num-vs-void-after-unreachable
+    (unreachable) (block (drop (i32.eqz (nop))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unary-num-vs-void-in-loop-after-unreachable
+    (unreachable) (loop (drop (i32.eqz (nop))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unary-num-vs-void-in-i32-loop-after-unreachable
+    (unreachable) (loop (result i32) (i32.eqz (nop)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unary-num-vs-num-after-unreachable
+    (unreachable) (drop (i32.eqz (f32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-num-vs-void-after-unreachable
+    (unreachable) (block (drop (f32.eq (i32.const 1))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-num-vs-num-after-unreachable
+    (unreachable) (drop (f32.eq (i32.const 1) (f32.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-num-vs-void-after-unreachable
+    (block (unreachable) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-num-vs-num-after-unreachable (result i32)
+    (block (result i32) (i32.const 1) (unreachable) (f32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-loop-value-num-vs-void-after-unreachable
+    (block (loop (unreachable) (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-loop-value-num-vs-num-after-unreachable (result i32)
+    (loop (result i32) (unreachable) (f32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-func-value-num-vs-void-after-unreachable
+    (unreachable) (i32.const 1)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-func-value-num-vs-num-after-unreachable (result i32)
+    (unreachable) (f32.const 0)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unary-num-vs-void-in-if-after-unreachable
+    (unreachable) (if (i32.const 0) (then (drop (i32.eqz (nop)))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unary-num-vs-void-in-else-after-unreachable
+    (unreachable) (if (i32.const 0) (then (nop)) (else (drop (i32.eqz (nop)))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unary-num-vs-void-in-else-after-unreachable-if
+    (if (i32.const 0) (then (unreachable)) (else (drop (i32.eqz (nop)))))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-unary-num-vs-void-after-nested-unreachable
+    (block (unreachable)) (block (drop (i32.eqz (nop))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unary-num-vs-num-after-nested-unreachable
+    (block (unreachable)) (drop (i32.eqz (f32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-num-vs-void-after-nested-unreachable
+    (block (unreachable)) (block (drop (f32.eq (i32.const 1))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-num-vs-num-after-nested-unreachable
+    (block (unreachable)) (drop (f32.eq (i32.const 1) (f32.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-num-vs-void-after-nested-unreachable
+    (block (block (unreachable)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-num-vs-num-after-nested-unreachable
+    (result i32)
+    (block (result i32) (i32.const 1) (block (unreachable)) (f32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-loop-value-num-vs-void-after-nested-unreachable
+    (block (loop (block (unreachable)) (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-loop-value-num-vs-num-after-nested-unreachable
+    (result i32)
+    (loop (result i32) (block (unreachable)) (f32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-func-value-num-vs-void-after-nested-unreachable
+    (block (unreachable)) (i32.const 1)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-func-value-num-vs-num-after-nested-unreachable
+    (result i32)
+    (block (unreachable)) (f32.const 0)
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-unary-num-vs-void-after-infinite-loop
+    (loop (br 0)) (block (drop (i32.eqz (nop))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unary-num-vs-num-after-infinite-loop
+    (loop (br 0)) (drop (i32.eqz (f32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-num-vs-void-after-infinite-loop
+    (loop (br 0)) (block (drop (f32.eq (i32.const 1))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-num-vs-num-after-infinite-loop
+    (loop (br 0)) (drop (f32.eq (i32.const 1) (f32.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-num-vs-void-after-infinite-loop
+    (block (loop (br 0)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-num-vs-num-after-infinite-loop (result i32)
+    (block (result i32) (i32.const 1) (loop (br 0)) (f32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-loop-value-num-vs-void-after-infinite-loop
+    (block (loop (loop (br 0)) (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-loop-value-num-vs-num-after-infinite-loop (result i32)
+    (loop (result i32) (loop (br 0)) (f32.const 0))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-func-value-num-vs-void-after-infinite-loop
+    (loop (br 0)) (i32.const 1)
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-func-value-num-vs-num-after-infinite-loop (result i32)
+    (loop (br 0)) (f32.const 0)
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-unary-num-vs-void-in-dead-body
+    (if (i32.const 0) (then (drop (i32.eqz (nop)))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-unary-num-vs-num-in-dead-body
+    (if (i32.const 0) (then (drop (i32.eqz (f32.const 1)))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-num-vs-void-in-dead-body
+    (if (i32.const 0) (then (drop (f32.eq (i32.const 1)))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-binary-num-vs-num-in-dead-body
+    (if (i32.const 0) (then (drop (f32.eq (i32.const 1) (f32.const 0)))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-if-value-num-vs-void-in-dead-body
+    (if (i32.const 0) (then (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-if-value-num-vs-num-in-dead-body (result i32)
+    (if (result i32) (i32.const 0) (then (f32.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-num-vs-void-in-dead-body
+    (if (i32.const 0) (then (block (i32.const 1))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-num-vs-num-in-dead-body (result i32)
+    (if (result i32) (i32.const 0) (then (block (result i32) (f32.const 0))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-num-vs-void-in-dead-body
+    (if (i32.const 0) (then (loop (i32.const 1))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-num-vs-num-in-dead-body (result i32)
+    (if (result i32) (i32.const 0) (then (loop (result i32) (f32.const 0))))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-return-second-num-vs-num (result i32)
+    (return (i32.const 1)) (return (f64.const 1))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-br-second-num-vs-num (result i32)
+    (block (result i32) (br 0 (i32.const 1)) (br 0 (f64.const 1)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-br_if-cond-num-vs-num-after-unreachable
+    (block (br_if 0 (unreachable) (f32.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-br_if-num-vs-void-after-unreachable (result i32)
+    (block (result i32)
+      (block (unreachable) (br_if 1 (i32.const 0) (i32.const 0)))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-br_if-num-vs-num-after-unreachable (result i32)
+    (block (result i32)
+      (block (result f32) (unreachable) (br_if 1 (i32.const 0) (i32.const 0)))
+      (drop) (i32.const 0)
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-br_if-num2-vs-num-after-unreachable (result i32)
+    (block (result i32)
+      (unreachable) (br_if 0 (i32.const 0) (i32.const 0)) (i32.const 0)
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-br_table-num-vs-num-after-unreachable
+    (block (br_table 0 (unreachable) (f32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-br_table-label-num-vs-num-after-unreachable (result i32)
+    (block (result i32) (unreachable) (br_table 0 (f32.const 0) (i32.const 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-br_table-label-num-vs-label-void-after-unreachable
+    (block
+      (block (result f32)
+        (unreachable)
+        (br_table 0 1 0 (i32.const 1))
+      )
+      (drop)
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-br_table-label-num-vs-label-num-after-unreachable
+    (block (result f64)
+      (block (result f32)
+        (unreachable)
+        (br_table 0 1 1 (i32.const 1))
+      )
+      (drop)
+      (f64.const 0)
+    )
+    (drop)
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-block-value-nested-unreachable-num-vs-void
+    (block (i32.const 3) (block (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-nested-unreachable-void-vs-num (result i32)
+    (block (block (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-nested-unreachable-num-vs-num (result i32)
+    (block (result i64) (i64.const 0) (block (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-nested-unreachable-num2-vs-void (result i32)
+    (block (i32.const 3) (block (i64.const 1) (unreachable))) (i32.const 9)
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-block-value-nested-br-num-vs-void
+    (block (i32.const 3) (block (br 1)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-nested-br-void-vs-num (result i32)
+    (block (result i32) (block (br 1 (i32.const 0))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-nested-br-num-vs-num (result i32)
+    (block (result i32) (i64.const 0) (block (br 1 (i32.const 0))))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-block-value-nested2-br-num-vs-void
+    (block (block (i32.const 3) (block (br 2))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-nested2-br-void-vs-num (result i32)
+    (block (result i32) (block (block (br 2 (i32.const 0)))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-nested2-br-num-vs-num (result i32)
+    (block (result i32)
+      (block (result i64) (i64.const 0) (block (br 2 (i32.const 0))))
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-nested2-br-num2-vs-void (result i32)
+    (block (i32.const 3) (block (i64.const 1) (br 1))) (i32.const 9)
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-block-value-nested-return-num-vs-void
+    (block (i32.const 3) (block (return)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-nested-return-void-vs-num (result i32)
+    (block (block (return (i32.const 0))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-nested-return-num-vs-num (result i32)
+    (block (result i64) (i64.const 0) (block (return (i32.const 0))))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-block-value-nested-return-num2-vs-void (result i32)
+    (block (i32.const 3) (block (i64.const 1) (return (i32.const 0))))
+    (i32.const 9)
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-loop-value-nested-unreachable-num-vs-void
+    (loop (i32.const 3) (block (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-loop-value-nested-unreachable-void-vs-num (result i32)
+    (loop (block (unreachable)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-loop-value-nested-unreachable-num-vs-num (result i32)
+    (loop (result i64) (i64.const 0) (block (unreachable)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-cont-last-void-vs-empty (result i32)
+    (loop (br 0 (nop)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-cont-last-num-vs-empty (result i32)
+    (loop (br 0 (i32.const 0)))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $tee-local-unreachable-value
+    (local i32)
+    (local.tee 0 (unreachable))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $br_if-unreachable (result i32)
+    (block (result i32)
+      (block
+        (br_if 1 (unreachable) (i32.const 0))
+      )
+      (i32.const 0)
+    )
+  ))
+  "type mismatch"
+)
+(assert_invalid 
+  (module
+    (func $type-br_if-after-unreachable (result i64)
+      unreachable
+      br_if 0
+      i64.extend_i32_u
+    )
+  )
+ "type mismatch"
+)
diff --git a/binaryen/test/spec/unwind.wast b/binaryen/test/spec/unwind.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/unwind.wast
@@ -0,0 +1,267 @@
+;; Test that control-flow transfer unwinds stack and it can be anything after.
+
+(module
+  (func (export "func-unwind-by-unreachable")
+    (i32.const 3) (i64.const 1) (unreachable)
+  )
+  (func (export "func-unwind-by-br")
+    (i32.const 3) (i64.const 1) (br 0)
+  )
+  (func (export "func-unwind-by-br-value") (result i32)
+    (i32.const 3) (i64.const 1) (br 0 (i32.const 9))
+  )
+  (func (export "func-unwind-by-br_if")
+    (i32.const 3) (i64.const 1) (drop (drop (br_if 0 (i32.const 1))))
+  )
+  (func (export "func-unwind-by-br_if-value") (result i32)
+    (i32.const 3) (i64.const 1) (drop (drop (br_if 0 (i32.const 9) (i32.const 1))))
+  )
+  (func (export "func-unwind-by-br_table")
+    (i32.const 3) (i64.const 1) (br_table 0 (i32.const 0))
+  )
+  (func (export "func-unwind-by-br_table-value") (result i32)
+    (i32.const 3) (i64.const 1) (br_table 0 (i32.const 9) (i32.const 0))
+  )
+  (func (export "func-unwind-by-return") (result i32)
+    (i32.const 3) (i64.const 1) (return (i32.const 9))
+  )
+
+  (func (export "block-unwind-by-unreachable")
+    (block (i32.const 3) (i64.const 1) (unreachable))
+  )
+  (func (export "block-unwind-by-br") (result i32)
+    (block (i32.const 3) (i64.const 1) (br 0)) (i32.const 9)
+  )
+  (func (export "block-unwind-by-br-value") (result i32)
+    (block (result i32) (i32.const 3) (i64.const 1) (br 0 (i32.const 9)))
+  )
+  (func (export "block-unwind-by-br_if") (result i32)
+    (block (i32.const 3) (i64.const 1) (drop (drop (br_if 0 (i32.const 1))))) (i32.const 9)
+  )
+  (func (export "block-unwind-by-br_if-value") (result i32)
+    (block (result i32)
+      (i32.const 3) (i64.const 1) (drop (drop (br_if 0 (i32.const 9) (i32.const 1))))
+    )
+  )
+  (func (export "block-unwind-by-br_table") (result i32)
+    (block (i32.const 3) (i64.const 1) (br_table 0 (i32.const 0))) (i32.const 9)
+  )
+  (func (export "block-unwind-by-br_table-value") (result i32)
+    (block (result i32)
+      (i32.const 3) (i64.const 1) (br_table 0 (i32.const 9) (i32.const 0))
+    )
+  )
+  (func (export "block-unwind-by-return") (result i32)
+    (block (result i32) (i32.const 3) (i64.const 1) (return (i32.const 9)))
+  )
+
+  (func (export "block-nested-unwind-by-unreachable") (result i32)
+    (block (result i32) (i32.const 3) (block (i64.const 1) (unreachable)))
+  )
+  (func (export "block-nested-unwind-by-br") (result i32)
+    (block (i32.const 3) (block (i64.const 1) (br 1)) (drop)) (i32.const 9)
+  )
+  (func (export "block-nested-unwind-by-br-value") (result i32)
+    (block (result i32)
+      (i32.const 3) (block (i64.const 1) (br 1 (i32.const 9)))
+    )
+  )
+  (func (export "block-nested-unwind-by-br_if") (result i32)
+    (block (i32.const 3) (block (i64.const 1) (drop (br_if 1 (i32.const 1)))) (drop)) (i32.const 9)
+  )
+  (func (export "block-nested-unwind-by-br_if-value") (result i32)
+    (block (result i32)
+      (i32.const 3) (block (i64.const 1) (drop (drop (br_if 1 (i32.const 9) (i32.const 1)))))
+    )
+  )
+  (func (export "block-nested-unwind-by-br_table") (result i32)
+    (block
+      (i32.const 3) (block (i64.const 1) (br_table 1 (i32.const 1)))
+      (drop)
+    )
+    (i32.const 9)
+  )
+  (func (export "block-nested-unwind-by-br_table-value") (result i32)
+    (block (result i32)
+      (i32.const 3)
+      (block (i64.const 1) (br_table 1 (i32.const 9) (i32.const 1)))
+    )
+  )
+  (func (export "block-nested-unwind-by-return") (result i32)
+    (block (result i32)
+      (i32.const 3) (block (i64.const 1) (return (i32.const 9)))
+    )
+  )
+
+  (func (export "unary-after-unreachable") (result i32)
+    (f32.const 0) (unreachable) (i64.eqz)
+  )
+  (func (export "unary-after-br") (result i32)
+    (block (result i32) (f32.const 0) (br 0 (i32.const 9)) (i64.eqz))
+  )
+  (func (export "unary-after-br_if") (result i32)
+    (block (result i32)
+      (i64.const 0) (drop (br_if 0 (i32.const 9) (i32.const 1))) (i64.eqz)
+    )
+  )
+  (func (export "unary-after-br_table") (result i32)
+    (block (result i32)
+      (f32.const 0) (br_table 0 0 (i32.const 9) (i32.const 0)) (i64.eqz)
+    )
+  )
+  (func (export "unary-after-return") (result i32)
+    (f32.const 0) (return (i32.const 9)) (i64.eqz)
+  )
+
+  (func (export "binary-after-unreachable") (result i32)
+    (f32.const 0) (f64.const 1) (unreachable) (i64.eq)
+  )
+  (func (export "binary-after-br") (result i32)
+    (block (result i32)
+      (f32.const 0) (f64.const 1) (br 0 (i32.const 9)) (i64.eq)
+    )
+  )
+  (func (export "binary-after-br_if") (result i32)
+    (block (result i32)
+      (i64.const 0) (i64.const 1) (drop (br_if 0 (i32.const 9) (i32.const 1)))
+      (i64.eq)
+    )
+  )
+  (func (export "binary-after-br_table") (result i32)
+    (block (result i32)
+      (f32.const 0) (f64.const 1) (br_table 0 (i32.const 9) (i32.const 0))
+      (i64.eq)
+    )
+  )
+  (func (export "binary-after-return") (result i32)
+    (f32.const 0) (f64.const 1) (return (i32.const 9)) (i64.eq)
+  )
+
+  (func (export "select-after-unreachable") (result i32)
+    (f32.const 0) (f64.const 1) (i64.const 0) (unreachable) (select)
+  )
+  (func (export "select-after-br") (result i32)
+    (block (result i32)
+      (f32.const 0) (f64.const 1) (i64.const 0) (br 0 (i32.const 9)) (select)
+    )
+  )
+  (func (export "select-after-br_if") (result i32)
+    (block (result i32)
+      (i32.const 0) (i32.const 1) (i32.const 0)
+      (drop (br_if 0 (i32.const 9) (i32.const 1)))
+      (select)
+    )
+  )
+  (func (export "select-after-br_table") (result i32)
+    (block (result i32)
+      (f32.const 0) (f64.const 1) (i64.const 0)
+      (br_table 0 (i32.const 9) (i32.const 0))
+      (select)
+    )
+  )
+  (func (export "select-after-return") (result i32)
+    (f32.const 0) (f64.const 1) (i64.const 1) (return (i32.const 9)) (select)
+  )
+
+  (func (export "block-value-after-unreachable") (result i32)
+    (block (result i32) (f32.const 0) (unreachable))
+  )
+  (func (export "block-value-after-br") (result i32)
+    (block (result i32) (f32.const 0) (br 0 (i32.const 9)))
+  )
+  (func (export "block-value-after-br_if") (result i32)
+    (block (result i32)
+      (i32.const 0) (drop (br_if 0 (i32.const 9) (i32.const 1)))
+    )
+  )
+  (func (export "block-value-after-br_table") (result i32)
+    (block (result i32)
+      (f32.const 0) (br_table 0 0 (i32.const 9) (i32.const 0))
+    )
+  )
+  (func (export "block-value-after-return") (result i32)
+    (block (result i32) (f32.const 0) (return (i32.const 9)))
+  )
+
+  (func (export "loop-value-after-unreachable") (result i32)
+    (loop (result i32) (f32.const 0) (unreachable))
+  )
+  (func (export "loop-value-after-br") (result i32)
+    (block (result i32) (loop (result i32) (f32.const 0) (br 1 (i32.const 9))))
+  )
+  (func (export "loop-value-after-br_if") (result i32)
+    (block (result i32)
+      (loop (result i32)
+        (i32.const 0) (drop (br_if 1 (i32.const 9) (i32.const 1)))
+      )
+    )
+  )
+
+  (func (export "loop-value-after-br_table") (result i32)
+    (block (result i32)
+      (loop (result i32)
+        (f32.const 0) (br_table 1 1 (i32.const 9) (i32.const 0))
+      )
+    )
+  )
+  (func (export "loop-value-after-return") (result i32)
+    (loop (result i32) (f32.const 0) (return (i32.const 9)))
+  )
+)
+
+(assert_trap (invoke "func-unwind-by-unreachable") "unreachable")
+(assert_return (invoke "func-unwind-by-br"))
+(assert_return (invoke "func-unwind-by-br-value") (i32.const 9))
+(assert_return (invoke "func-unwind-by-br_if"))
+(assert_return (invoke "func-unwind-by-br_if-value") (i32.const 9))
+(assert_return (invoke "func-unwind-by-br_table"))
+(assert_return (invoke "func-unwind-by-br_table-value") (i32.const 9))
+(assert_return (invoke "func-unwind-by-return") (i32.const 9))
+
+(assert_trap (invoke "block-unwind-by-unreachable") "unreachable")
+(assert_return (invoke "block-unwind-by-br") (i32.const 9))
+(assert_return (invoke "block-unwind-by-br-value") (i32.const 9))
+(assert_return (invoke "block-unwind-by-br_if") (i32.const 9))
+(assert_return (invoke "block-unwind-by-br_if-value") (i32.const 9))
+(assert_return (invoke "block-unwind-by-br_table") (i32.const 9))
+(assert_return (invoke "block-unwind-by-br_table-value") (i32.const 9))
+(assert_return (invoke "block-unwind-by-return") (i32.const 9))
+
+(assert_trap (invoke "block-nested-unwind-by-unreachable") "unreachable")
+(assert_return (invoke "block-nested-unwind-by-br") (i32.const 9))
+(assert_return (invoke "block-nested-unwind-by-br-value") (i32.const 9))
+(assert_return (invoke "block-nested-unwind-by-br_if") (i32.const 9))
+(assert_return (invoke "block-nested-unwind-by-br_if-value") (i32.const 9))
+(assert_return (invoke "block-nested-unwind-by-br_table") (i32.const 9))
+(assert_return (invoke "block-nested-unwind-by-br_table-value") (i32.const 9))
+(assert_return (invoke "block-nested-unwind-by-return") (i32.const 9))
+
+(assert_trap (invoke "unary-after-unreachable") "unreachable")
+(assert_return (invoke "unary-after-br") (i32.const 9))
+(assert_return (invoke "unary-after-br_if") (i32.const 9))
+(assert_return (invoke "unary-after-br_table") (i32.const 9))
+(assert_return (invoke "unary-after-return") (i32.const 9))
+
+(assert_trap (invoke "binary-after-unreachable") "unreachable")
+(assert_return (invoke "binary-after-br") (i32.const 9))
+(assert_return (invoke "binary-after-br_if") (i32.const 9))
+(assert_return (invoke "binary-after-br_table") (i32.const 9))
+(assert_return (invoke "binary-after-return") (i32.const 9))
+
+(assert_trap (invoke "select-after-unreachable") "unreachable")
+(assert_return (invoke "select-after-br") (i32.const 9))
+(assert_return (invoke "select-after-br_if") (i32.const 9))
+(assert_return (invoke "select-after-br_table") (i32.const 9))
+(assert_return (invoke "select-after-return") (i32.const 9))
+
+(assert_trap (invoke "block-value-after-unreachable") "unreachable")
+(assert_return (invoke "block-value-after-br") (i32.const 9))
+(assert_return (invoke "block-value-after-br_if") (i32.const 9))
+(assert_return (invoke "block-value-after-br_table") (i32.const 9))
+(assert_return (invoke "block-value-after-return") (i32.const 9))
+
+(assert_trap (invoke "loop-value-after-unreachable") "unreachable")
+(assert_return (invoke "loop-value-after-br") (i32.const 9))
+(assert_return (invoke "loop-value-after-br_if") (i32.const 9))
+(assert_return (invoke "loop-value-after-br_table") (i32.const 9))
+(assert_return (invoke "loop-value-after-return") (i32.const 9))
diff --git a/binaryen/test/spec/utf8-custom-section-id.wast b/binaryen/test/spec/utf8-custom-section-id.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/utf8-custom-section-id.wast
@@ -0,0 +1,1792 @@
+;;;;;; Invalid UTF-8 custom section names
+
+;;;; Continuation bytes not preceded by prefixes
+
+;; encoding starts with (first) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\02"                       ;; custom section
+    "\01\80"                       ;; "\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; encoding starts with (0x8f) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\02"                       ;; custom section
+    "\01\8f"                       ;; "\8f"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; encoding starts with (0x90) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\02"                       ;; custom section
+    "\01\90"                       ;; "\90"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; encoding starts with (0x9f) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\02"                       ;; custom section
+    "\01\9f"                       ;; "\9f"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; encoding starts with (0xa0) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\02"                       ;; custom section
+    "\01\a0"                       ;; "\a0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; encoding starts with (last) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\02"                       ;; custom section
+    "\01\bf"                       ;; "\bf"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 2-byte sequences
+
+;; 2-byte sequence contains 3 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\c2\80\80"                 ;; "\c2\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 2-byte sequence contains 1 byte at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\02"                       ;; custom section
+    "\01\c2"                       ;; "\c2"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 2-byte sequence contains 1 byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\c2\2e"                    ;; "\c2."
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 2-byte sequence contents
+
+;; overlong encoding after 0xc0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\c0\80"                    ;; "\c0\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xc0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\c0\bf"                    ;; "\c0\bf"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xc1 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\c1\80"                    ;; "\c1\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xc1 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\c1\bf"                    ;; "\c1\bf"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (first) 2-byte prefix not a contination byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\c2\00"                    ;; "\c2\00"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (first) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\c2\7f"                    ;; "\c2\7f"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (first) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\c2\c0"                    ;; "\c2\c0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (first) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\c2\fd"                    ;; "\c2\fd"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (last) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\df\00"                    ;; "\df\00"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (last) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\df\7f"                    ;; "\df\7f"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (last) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\df\c0"                    ;; "\df\c0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (last) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\df\fd"                    ;; "\df\fd"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 3-byte sequences
+
+;; 3-byte sequence contains 4 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\e1\80\80\80"              ;; "\e1\80\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 3-byte sequence contains 2 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\e1\80"                    ;; "\e1\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 3-byte sequence contains 2 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e1\80\2e"                 ;; "\e1\80."
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 3-byte sequence contains 1 byte at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\02"                       ;; custom section
+    "\01\e1"                       ;; "\e1"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 3-byte sequence contains 1 byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\e1\2e"                    ;; "\e1."
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 3-byte sequence contents
+
+;; first byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e0\00\a0"                 ;; "\e0\00\a0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e0\7f\a0"                 ;; "\e0\7f\a0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xe0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e0\80\80"                 ;; "\e0\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xe0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e0\80\a0"                 ;; "\e0\80\a0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xe0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e0\9f\a0"                 ;; "\e0\9f\a0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xe0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e0\9f\bf"                 ;; "\e0\9f\bf"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e0\c0\a0"                 ;; "\e0\c0\a0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e0\fd\a0"                 ;; "\e0\fd\a0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e1\00\80"                 ;; "\e1\00\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e1\7f\80"                 ;; "\e1\7f\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e1\c0\80"                 ;; "\e1\c0\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e1\fd\80"                 ;; "\e1\fd\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ec\00\80"                 ;; "\ec\00\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ec\7f\80"                 ;; "\ec\7f\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ec\c0\80"                 ;; "\ec\c0\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ec\fd\80"                 ;; "\ec\fd\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ed\00\80"                 ;; "\ed\00\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ed\7f\80"                 ;; "\ed\7f\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte sequence reserved for UTF-16 surrogate half
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ed\a0\80"                 ;; "\ed\a0\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte sequence reserved for UTF-16 surrogate half
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ed\a0\bf"                 ;; "\ed\a0\bf"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte sequence reserved for UTF-16 surrogate half
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ed\bf\80"                 ;; "\ed\bf\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte sequence reserved for UTF-16 surrogate half
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ed\bf\bf"                 ;; "\ed\bf\bf"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ed\c0\80"                 ;; "\ed\c0\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ed\fd\80"                 ;; "\ed\fd\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ee\00\80"                 ;; "\ee\00\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ee\7f\80"                 ;; "\ee\7f\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ee\c0\80"                 ;; "\ee\c0\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ee\fd\80"                 ;; "\ee\fd\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ef\00\80"                 ;; "\ef\00\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ef\7f\80"                 ;; "\ef\7f\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ef\c0\80"                 ;; "\ef\c0\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ef\fd\80"                 ;; "\ef\fd\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 3-byte sequence contents (third byte)
+
+;; second byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e0\a0\00"                 ;; "\e0\a0\00"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e0\a0\7f"                 ;; "\e0\a0\7f"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e0\a0\c0"                 ;; "\e0\a0\c0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e0\a0\fd"                 ;; "\e0\a0\fd"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e1\80\00"                 ;; "\e1\80\00"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e1\80\7f"                 ;; "\e1\80\7f"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e1\80\c0"                 ;; "\e1\80\c0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\e1\80\fd"                 ;; "\e1\80\fd"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ec\80\00"                 ;; "\ec\80\00"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ec\80\7f"                 ;; "\ec\80\7f"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ec\80\c0"                 ;; "\ec\80\c0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ec\80\fd"                 ;; "\ec\80\fd"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ed\80\00"                 ;; "\ed\80\00"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ed\80\7f"                 ;; "\ed\80\7f"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ed\80\c0"                 ;; "\ed\80\c0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ed\80\fd"                 ;; "\ed\80\fd"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ee\80\00"                 ;; "\ee\80\00"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ee\80\7f"                 ;; "\ee\80\7f"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ee\80\c0"                 ;; "\ee\80\c0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ee\80\fd"                 ;; "\ee\80\fd"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ef\80\00"                 ;; "\ef\80\00"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ef\80\7f"                 ;; "\ef\80\7f"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ef\80\c0"                 ;; "\ef\80\c0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\ef\80\fd"                 ;; "\ef\80\fd"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 4-byte sequences
+
+;; 4-byte sequence contains 5 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\06"                       ;; custom section
+    "\05\f1\80\80\80\80"           ;; "\f1\80\80\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 3 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\f1\80\80"                 ;; "\f1\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 3 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f1\80\80\23"              ;; "\f1\80\80#"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 2 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\f1\80"                    ;; "\f1\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 2 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\f1\80\23"                 ;; "\f1\80#"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 1 byte at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\02"                       ;; custom section
+    "\01\f1"                       ;; "\f1"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 1 byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\f1\23"                    ;; "\f1#"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 4-byte sequence contents
+
+;; first byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\00\90\90"              ;; "\f0\00\90\90"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\7f\90\90"              ;; "\f0\7f\90\90"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xf0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\80\80\80"              ;; "\f0\80\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xf0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\80\90\90"              ;; "\f0\80\90\90"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xf0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\8f\90\90"              ;; "\f0\8f\90\90"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xf0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\8f\bf\bf"              ;; "\f0\8f\bf\bf"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\c0\90\90"              ;; "\f0\c0\90\90"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\fd\90\90"              ;; "\f0\fd\90\90"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f1\00\80\80"              ;; "\f1\00\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f1\7f\80\80"              ;; "\f1\7f\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f1\c0\80\80"              ;; "\f1\c0\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f1\fd\80\80"              ;; "\f1\fd\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f3\00\80\80"              ;; "\f3\00\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f3\7f\80\80"              ;; "\f3\7f\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f3\c0\80\80"              ;; "\f3\c0\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f3\fd\80\80"              ;; "\f3\fd\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f4\00\80\80"              ;; "\f4\00\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f4\7f\80\80"              ;; "\f4\7f\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (first) invalid code point
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f4\90\80\80"              ;; "\f4\90\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; invalid code point
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f4\bf\80\80"              ;; "\f4\bf\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f4\c0\80\80"              ;; "\f4\c0\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f4\fd\80\80"              ;; "\f4\fd\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (first) invalid 4-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f5\80\80\80"              ;; "\f5\80\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (last) invalid 4-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f7\80\80\80"              ;; "\f7\80\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (last) invalid 4-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f7\bf\bf\bf"              ;; "\f7\bf\bf\bf"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 4-byte sequence contents (third byte)
+
+;; second byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\90\00\90"              ;; "\f0\90\00\90"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\90\7f\90"              ;; "\f0\90\7f\90"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\90\c0\90"              ;; "\f0\90\c0\90"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\90\fd\90"              ;; "\f0\90\fd\90"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f1\80\00\80"              ;; "\f1\80\00\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f1\80\7f\80"              ;; "\f1\80\7f\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f1\80\c0\80"              ;; "\f1\80\c0\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f1\80\fd\80"              ;; "\f1\80\fd\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f3\80\00\80"              ;; "\f3\80\00\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f3\80\7f\80"              ;; "\f3\80\7f\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f3\80\c0\80"              ;; "\f3\80\c0\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f3\80\fd\80"              ;; "\f3\80\fd\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f4\80\00\80"              ;; "\f4\80\00\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f4\80\7f\80"              ;; "\f4\80\7f\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f4\80\c0\80"              ;; "\f4\80\c0\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f4\80\fd\80"              ;; "\f4\80\fd\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 4-byte sequence contents (fourth byte)
+
+;; third byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\90\90\00"              ;; "\f0\90\90\00"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\90\90\7f"              ;; "\f0\90\90\7f"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\90\90\c0"              ;; "\f0\90\90\c0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f0\90\90\fd"              ;; "\f0\90\90\fd"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f1\80\80\00"              ;; "\f1\80\80\00"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f1\80\80\7f"              ;; "\f1\80\80\7f"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f1\80\80\c0"              ;; "\f1\80\80\c0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f1\80\80\fd"              ;; "\f1\80\80\fd"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f3\80\80\00"              ;; "\f3\80\80\00"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f3\80\80\7f"              ;; "\f3\80\80\7f"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f3\80\80\c0"              ;; "\f3\80\80\c0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f3\80\80\fd"              ;; "\f3\80\80\fd"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f4\80\80\00"              ;; "\f4\80\80\00"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f4\80\80\7f"              ;; "\f4\80\80\7f"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f4\80\80\c0"              ;; "\f4\80\80\c0"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f4\80\80\fd"              ;; "\f4\80\80\fd"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 5-byte sequences
+
+;; 5-byte sequence contains 6 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\07"                       ;; custom section
+    "\06\f8\80\80\80\80\80"        ;; "\f8\80\80\80\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 4 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f8\80\80\80"              ;; "\f8\80\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 4 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\06"                       ;; custom section
+    "\05\f8\80\80\80\23"           ;; "\f8\80\80\80#"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 3 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\f8\80\80"                 ;; "\f8\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 3 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\f8\80\80\23"              ;; "\f8\80\80#"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 2 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\f8\80"                    ;; "\f8\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 2 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\f8\80\23"                 ;; "\f8\80#"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 1 byte at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\02"                       ;; custom section
+    "\01\f8"                       ;; "\f8"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 1 byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\f8\23"                    ;; "\f8#"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 5-byte sequence contents
+
+;; (first) invalid 5-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\06"                       ;; custom section
+    "\05\f8\80\80\80\80"           ;; "\f8\80\80\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (last) invalid 5-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\06"                       ;; custom section
+    "\05\fb\bf\bf\bf\bf"           ;; "\fb\bf\bf\bf\bf"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 6-byte sequences
+
+;; 6-byte sequence contains 7 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\08"                       ;; custom section
+    "\07\fc\80\80\80\80\80\80"     ;; "\fc\80\80\80\80\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 5 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\06"                       ;; custom section
+    "\05\fc\80\80\80\80"           ;; "\fc\80\80\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 5 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\07"                       ;; custom section
+    "\06\fc\80\80\80\80\23"        ;; "\fc\80\80\80\80#"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 4 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\fc\80\80\80"              ;; "\fc\80\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 4 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\06"                       ;; custom section
+    "\05\fc\80\80\80\23"           ;; "\fc\80\80\80#"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 3 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\fc\80\80"                 ;; "\fc\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 3 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\fc\80\80\23"              ;; "\fc\80\80#"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 2 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\fc\80"                    ;; "\fc\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 2 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\04"                       ;; custom section
+    "\03\fc\80\23"                 ;; "\fc\80#"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 1 byte at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\02"                       ;; custom section
+    "\01\fc"                       ;; "\fc"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 1 byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\fc\23"                    ;; "\fc#"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 6-byte sequence contents
+
+;; (first) invalid 6-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\07"                       ;; custom section
+    "\06\fc\80\80\80\80\80"        ;; "\fc\80\80\80\80\80"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (last) invalid 6-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\07"                       ;; custom section
+    "\06\fd\bf\bf\bf\bf\bf"        ;; "\fd\bf\bf\bf\bf\bf"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; Miscellaneous invalid bytes
+
+;; invalid byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\02"                       ;; custom section
+    "\01\fe"                       ;; "\fe"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; invalid byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\02"                       ;; custom section
+    "\01\ff"                       ;; "\ff"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; UTF-16BE BOM
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\fe\ff"                    ;; "\fe\ff"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; UTF-32BE BOM
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\00\00\fe\ff"              ;; "\00\00\fe\ff"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; UTF-16LE BOM
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\03"                       ;; custom section
+    "\02\ff\fe"                    ;; "\ff\fe"
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; UTF-32LE BOM
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\00\05"                       ;; custom section
+    "\04\ff\fe\00\00"              ;; "\ff\fe\00\00"
+  )
+  "invalid UTF-8 encoding"
+)
+
diff --git a/binaryen/test/spec/utf8-import-field.wast b/binaryen/test/spec/utf8-import-field.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/utf8-import-field.wast
@@ -0,0 +1,2672 @@
+;;;;;; Invalid UTF-8 import field names
+
+;;;; Continuation bytes not preceded by prefixes
+
+;; encoding starts with (first) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\01\80"                       ;; "\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; encoding starts with (0x8f) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\01\8f"                       ;; "\8f"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; encoding starts with (0x90) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\01\90"                       ;; "\90"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; encoding starts with (0x9f) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\01\9f"                       ;; "\9f"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; encoding starts with (0xa0) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\01\a0"                       ;; "\a0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; encoding starts with (last) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\01\bf"                       ;; "\bf"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 2-byte sequences
+
+;; 2-byte sequence contains 3 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\c2\80\80"                 ;; "\c2\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 2-byte sequence contains 1 byte at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\01\c2"                       ;; "\c2"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 2-byte sequence contains 1 byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\c2\2e"                    ;; "\c2."
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 2-byte sequence contents
+
+;; overlong encoding after 0xc0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\c0\80"                    ;; "\c0\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xc0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\c0\bf"                    ;; "\c0\bf"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xc1 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\c1\80"                    ;; "\c1\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xc1 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\c1\bf"                    ;; "\c1\bf"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (first) 2-byte prefix not a contination byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\c2\00"                    ;; "\c2\00"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (first) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\c2\7f"                    ;; "\c2\7f"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (first) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\c2\c0"                    ;; "\c2\c0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (first) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\c2\fd"                    ;; "\c2\fd"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (last) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\df\00"                    ;; "\df\00"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (last) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\df\7f"                    ;; "\df\7f"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (last) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\df\c0"                    ;; "\df\c0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (last) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\df\fd"                    ;; "\df\fd"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 3-byte sequences
+
+;; 3-byte sequence contains 4 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\e1\80\80\80"              ;; "\e1\80\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 3-byte sequence contains 2 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\e1\80"                    ;; "\e1\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 3-byte sequence contains 2 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e1\80\2e"                 ;; "\e1\80."
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 3-byte sequence contains 1 byte at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\01\e1"                       ;; "\e1"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 3-byte sequence contains 1 byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\e1\2e"                    ;; "\e1."
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 3-byte sequence contents
+
+;; first byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e0\00\a0"                 ;; "\e0\00\a0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e0\7f\a0"                 ;; "\e0\7f\a0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xe0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e0\80\80"                 ;; "\e0\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xe0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e0\80\a0"                 ;; "\e0\80\a0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xe0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e0\9f\a0"                 ;; "\e0\9f\a0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xe0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e0\9f\bf"                 ;; "\e0\9f\bf"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e0\c0\a0"                 ;; "\e0\c0\a0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e0\fd\a0"                 ;; "\e0\fd\a0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e1\00\80"                 ;; "\e1\00\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e1\7f\80"                 ;; "\e1\7f\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e1\c0\80"                 ;; "\e1\c0\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e1\fd\80"                 ;; "\e1\fd\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ec\00\80"                 ;; "\ec\00\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ec\7f\80"                 ;; "\ec\7f\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ec\c0\80"                 ;; "\ec\c0\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ec\fd\80"                 ;; "\ec\fd\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ed\00\80"                 ;; "\ed\00\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ed\7f\80"                 ;; "\ed\7f\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte sequence reserved for UTF-16 surrogate half
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ed\a0\80"                 ;; "\ed\a0\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte sequence reserved for UTF-16 surrogate half
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ed\a0\bf"                 ;; "\ed\a0\bf"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte sequence reserved for UTF-16 surrogate half
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ed\bf\80"                 ;; "\ed\bf\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte sequence reserved for UTF-16 surrogate half
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ed\bf\bf"                 ;; "\ed\bf\bf"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ed\c0\80"                 ;; "\ed\c0\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ed\fd\80"                 ;; "\ed\fd\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ee\00\80"                 ;; "\ee\00\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ee\7f\80"                 ;; "\ee\7f\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ee\c0\80"                 ;; "\ee\c0\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ee\fd\80"                 ;; "\ee\fd\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ef\00\80"                 ;; "\ef\00\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ef\7f\80"                 ;; "\ef\7f\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ef\c0\80"                 ;; "\ef\c0\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ef\fd\80"                 ;; "\ef\fd\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 3-byte sequence contents (third byte)
+
+;; second byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e0\a0\00"                 ;; "\e0\a0\00"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e0\a0\7f"                 ;; "\e0\a0\7f"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e0\a0\c0"                 ;; "\e0\a0\c0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e0\a0\fd"                 ;; "\e0\a0\fd"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e1\80\00"                 ;; "\e1\80\00"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e1\80\7f"                 ;; "\e1\80\7f"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e1\80\c0"                 ;; "\e1\80\c0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\e1\80\fd"                 ;; "\e1\80\fd"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ec\80\00"                 ;; "\ec\80\00"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ec\80\7f"                 ;; "\ec\80\7f"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ec\80\c0"                 ;; "\ec\80\c0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ec\80\fd"                 ;; "\ec\80\fd"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ed\80\00"                 ;; "\ed\80\00"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ed\80\7f"                 ;; "\ed\80\7f"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ed\80\c0"                 ;; "\ed\80\c0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ed\80\fd"                 ;; "\ed\80\fd"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ee\80\00"                 ;; "\ee\80\00"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ee\80\7f"                 ;; "\ee\80\7f"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ee\80\c0"                 ;; "\ee\80\c0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ee\80\fd"                 ;; "\ee\80\fd"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ef\80\00"                 ;; "\ef\80\00"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ef\80\7f"                 ;; "\ef\80\7f"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ef\80\c0"                 ;; "\ef\80\c0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\ef\80\fd"                 ;; "\ef\80\fd"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 4-byte sequences
+
+;; 4-byte sequence contains 5 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0f"                       ;; import section
+    "\01"                          ;; length 1
+    "\05\f1\80\80\80\80"           ;; "\f1\80\80\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 3 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\f1\80\80"                 ;; "\f1\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 3 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f1\80\80\23"              ;; "\f1\80\80#"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 2 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\f1\80"                    ;; "\f1\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 2 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\f1\80\23"                 ;; "\f1\80#"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 1 byte at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\01\f1"                       ;; "\f1"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 1 byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\f1\23"                    ;; "\f1#"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 4-byte sequence contents
+
+;; first byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\00\90\90"              ;; "\f0\00\90\90"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\7f\90\90"              ;; "\f0\7f\90\90"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xf0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\80\80\80"              ;; "\f0\80\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xf0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\80\90\90"              ;; "\f0\80\90\90"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xf0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\8f\90\90"              ;; "\f0\8f\90\90"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xf0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\8f\bf\bf"              ;; "\f0\8f\bf\bf"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\c0\90\90"              ;; "\f0\c0\90\90"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\fd\90\90"              ;; "\f0\fd\90\90"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f1\00\80\80"              ;; "\f1\00\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f1\7f\80\80"              ;; "\f1\7f\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f1\c0\80\80"              ;; "\f1\c0\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f1\fd\80\80"              ;; "\f1\fd\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f3\00\80\80"              ;; "\f3\00\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f3\7f\80\80"              ;; "\f3\7f\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f3\c0\80\80"              ;; "\f3\c0\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f3\fd\80\80"              ;; "\f3\fd\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f4\00\80\80"              ;; "\f4\00\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f4\7f\80\80"              ;; "\f4\7f\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (first) invalid code point
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f4\90\80\80"              ;; "\f4\90\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; invalid code point
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f4\bf\80\80"              ;; "\f4\bf\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f4\c0\80\80"              ;; "\f4\c0\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f4\fd\80\80"              ;; "\f4\fd\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (first) invalid 4-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f5\80\80\80"              ;; "\f5\80\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (last) invalid 4-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f7\80\80\80"              ;; "\f7\80\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (last) invalid 4-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f7\bf\bf\bf"              ;; "\f7\bf\bf\bf"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 4-byte sequence contents (third byte)
+
+;; second byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\90\00\90"              ;; "\f0\90\00\90"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\90\7f\90"              ;; "\f0\90\7f\90"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\90\c0\90"              ;; "\f0\90\c0\90"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\90\fd\90"              ;; "\f0\90\fd\90"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f1\80\00\80"              ;; "\f1\80\00\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f1\80\7f\80"              ;; "\f1\80\7f\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f1\80\c0\80"              ;; "\f1\80\c0\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f1\80\fd\80"              ;; "\f1\80\fd\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f3\80\00\80"              ;; "\f3\80\00\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f3\80\7f\80"              ;; "\f3\80\7f\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f3\80\c0\80"              ;; "\f3\80\c0\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f3\80\fd\80"              ;; "\f3\80\fd\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f4\80\00\80"              ;; "\f4\80\00\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f4\80\7f\80"              ;; "\f4\80\7f\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f4\80\c0\80"              ;; "\f4\80\c0\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f4\80\fd\80"              ;; "\f4\80\fd\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 4-byte sequence contents (fourth byte)
+
+;; third byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\90\90\00"              ;; "\f0\90\90\00"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\90\90\7f"              ;; "\f0\90\90\7f"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\90\90\c0"              ;; "\f0\90\90\c0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f0\90\90\fd"              ;; "\f0\90\90\fd"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f1\80\80\00"              ;; "\f1\80\80\00"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f1\80\80\7f"              ;; "\f1\80\80\7f"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f1\80\80\c0"              ;; "\f1\80\80\c0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f1\80\80\fd"              ;; "\f1\80\80\fd"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f3\80\80\00"              ;; "\f3\80\80\00"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f3\80\80\7f"              ;; "\f3\80\80\7f"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f3\80\80\c0"              ;; "\f3\80\80\c0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f3\80\80\fd"              ;; "\f3\80\80\fd"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f4\80\80\00"              ;; "\f4\80\80\00"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f4\80\80\7f"              ;; "\f4\80\80\7f"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f4\80\80\c0"              ;; "\f4\80\80\c0"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f4\80\80\fd"              ;; "\f4\80\80\fd"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 5-byte sequences
+
+;; 5-byte sequence contains 6 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\10"                       ;; import section
+    "\01"                          ;; length 1
+    "\06\f8\80\80\80\80\80"        ;; "\f8\80\80\80\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 4 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f8\80\80\80"              ;; "\f8\80\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 4 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0f"                       ;; import section
+    "\01"                          ;; length 1
+    "\05\f8\80\80\80\23"           ;; "\f8\80\80\80#"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 3 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\f8\80\80"                 ;; "\f8\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 3 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\f8\80\80\23"              ;; "\f8\80\80#"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 2 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\f8\80"                    ;; "\f8\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 2 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\f8\80\23"                 ;; "\f8\80#"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 1 byte at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\01\f8"                       ;; "\f8"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 1 byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\f8\23"                    ;; "\f8#"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 5-byte sequence contents
+
+;; (first) invalid 5-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0f"                       ;; import section
+    "\01"                          ;; length 1
+    "\05\f8\80\80\80\80"           ;; "\f8\80\80\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (last) invalid 5-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0f"                       ;; import section
+    "\01"                          ;; length 1
+    "\05\fb\bf\bf\bf\bf"           ;; "\fb\bf\bf\bf\bf"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 6-byte sequences
+
+;; 6-byte sequence contains 7 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\11"                       ;; import section
+    "\01"                          ;; length 1
+    "\07\fc\80\80\80\80\80\80"     ;; "\fc\80\80\80\80\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 5 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0f"                       ;; import section
+    "\01"                          ;; length 1
+    "\05\fc\80\80\80\80"           ;; "\fc\80\80\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 5 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\10"                       ;; import section
+    "\01"                          ;; length 1
+    "\06\fc\80\80\80\80\23"        ;; "\fc\80\80\80\80#"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 4 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\fc\80\80\80"              ;; "\fc\80\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 4 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0f"                       ;; import section
+    "\01"                          ;; length 1
+    "\05\fc\80\80\80\23"           ;; "\fc\80\80\80#"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 3 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\fc\80\80"                 ;; "\fc\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 3 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\fc\80\80\23"              ;; "\fc\80\80#"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 2 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\fc\80"                    ;; "\fc\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 2 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\03\fc\80\23"                 ;; "\fc\80#"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 1 byte at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\01\fc"                       ;; "\fc"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 1 byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\fc\23"                    ;; "\fc#"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 6-byte sequence contents
+
+;; (first) invalid 6-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\10"                       ;; import section
+    "\01"                          ;; length 1
+    "\06\fc\80\80\80\80\80"        ;; "\fc\80\80\80\80\80"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (last) invalid 6-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\10"                       ;; import section
+    "\01"                          ;; length 1
+    "\06\fd\bf\bf\bf\bf\bf"        ;; "\fd\bf\bf\bf\bf\bf"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; Miscellaneous invalid bytes
+
+;; invalid byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\01\fe"                       ;; "\fe"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; invalid byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\01\ff"                       ;; "\ff"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; UTF-16BE BOM
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\fe\ff"                    ;; "\fe\ff"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; UTF-32BE BOM
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\00\00\fe\ff"              ;; "\00\00\fe\ff"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; UTF-16LE BOM
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\02\ff\fe"                    ;; "\ff\fe"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; UTF-32LE BOM
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\ff\fe\00\00"              ;; "\ff\fe\00\00"
+    "\04\74\65\73\74"              ;; "test"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
diff --git a/binaryen/test/spec/utf8-import-module.wast b/binaryen/test/spec/utf8-import-module.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/utf8-import-module.wast
@@ -0,0 +1,2672 @@
+;;;;;; Invalid UTF-8 import module names
+
+;;;; Continuation bytes not preceded by prefixes
+
+;; encoding starts with (first) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\01\80"                       ;; "\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; encoding starts with (0x8f) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\01\8f"                       ;; "\8f"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; encoding starts with (0x90) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\01\90"                       ;; "\90"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; encoding starts with (0x9f) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\01\9f"                       ;; "\9f"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; encoding starts with (0xa0) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\01\a0"                       ;; "\a0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; encoding starts with (last) continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\01\bf"                       ;; "\bf"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 2-byte sequences
+
+;; 2-byte sequence contains 3 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\c2\80\80"                 ;; "\c2\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 2-byte sequence contains 1 byte at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\01\c2"                       ;; "\c2"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 2-byte sequence contains 1 byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\c2\2e"                    ;; "\c2."
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 2-byte sequence contents
+
+;; overlong encoding after 0xc0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\c0\80"                    ;; "\c0\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xc0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\c0\bf"                    ;; "\c0\bf"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xc1 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\c1\80"                    ;; "\c1\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xc1 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\c1\bf"                    ;; "\c1\bf"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (first) 2-byte prefix not a contination byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\c2\00"                    ;; "\c2\00"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (first) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\c2\7f"                    ;; "\c2\7f"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (first) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\c2\c0"                    ;; "\c2\c0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (first) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\c2\fd"                    ;; "\c2\fd"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (last) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\df\00"                    ;; "\df\00"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (last) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\df\7f"                    ;; "\df\7f"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (last) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\df\c0"                    ;; "\df\c0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte after (last) 2-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\df\fd"                    ;; "\df\fd"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 3-byte sequences
+
+;; 3-byte sequence contains 4 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\e1\80\80\80"              ;; "\e1\80\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 3-byte sequence contains 2 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\e1\80"                    ;; "\e1\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 3-byte sequence contains 2 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e1\80\2e"                 ;; "\e1\80."
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 3-byte sequence contains 1 byte at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\01\e1"                       ;; "\e1"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 3-byte sequence contains 1 byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\e1\2e"                    ;; "\e1."
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 3-byte sequence contents
+
+;; first byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e0\00\a0"                 ;; "\e0\00\a0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e0\7f\a0"                 ;; "\e0\7f\a0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xe0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e0\80\80"                 ;; "\e0\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xe0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e0\80\a0"                 ;; "\e0\80\a0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xe0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e0\9f\a0"                 ;; "\e0\9f\a0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xe0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e0\9f\bf"                 ;; "\e0\9f\bf"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e0\c0\a0"                 ;; "\e0\c0\a0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e0\fd\a0"                 ;; "\e0\fd\a0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e1\00\80"                 ;; "\e1\00\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e1\7f\80"                 ;; "\e1\7f\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e1\c0\80"                 ;; "\e1\c0\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e1\fd\80"                 ;; "\e1\fd\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ec\00\80"                 ;; "\ec\00\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ec\7f\80"                 ;; "\ec\7f\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ec\c0\80"                 ;; "\ec\c0\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ec\fd\80"                 ;; "\ec\fd\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ed\00\80"                 ;; "\ed\00\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ed\7f\80"                 ;; "\ed\7f\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte sequence reserved for UTF-16 surrogate half
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ed\a0\80"                 ;; "\ed\a0\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte sequence reserved for UTF-16 surrogate half
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ed\a0\bf"                 ;; "\ed\a0\bf"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte sequence reserved for UTF-16 surrogate half
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ed\bf\80"                 ;; "\ed\bf\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; byte sequence reserved for UTF-16 surrogate half
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ed\bf\bf"                 ;; "\ed\bf\bf"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ed\c0\80"                 ;; "\ed\c0\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ed\fd\80"                 ;; "\ed\fd\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ee\00\80"                 ;; "\ee\00\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ee\7f\80"                 ;; "\ee\7f\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ee\c0\80"                 ;; "\ee\c0\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ee\fd\80"                 ;; "\ee\fd\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ef\00\80"                 ;; "\ef\00\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ef\7f\80"                 ;; "\ef\7f\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ef\c0\80"                 ;; "\ef\c0\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ef\fd\80"                 ;; "\ef\fd\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 3-byte sequence contents (third byte)
+
+;; second byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e0\a0\00"                 ;; "\e0\a0\00"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e0\a0\7f"                 ;; "\e0\a0\7f"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e0\a0\c0"                 ;; "\e0\a0\c0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xe0) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e0\a0\fd"                 ;; "\e0\a0\fd"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e1\80\00"                 ;; "\e1\80\00"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e1\80\7f"                 ;; "\e1\80\7f"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e1\80\c0"                 ;; "\e1\80\c0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\e1\80\fd"                 ;; "\e1\80\fd"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ec\80\00"                 ;; "\ec\80\00"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ec\80\7f"                 ;; "\ec\80\7f"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ec\80\c0"                 ;; "\ec\80\c0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ec\80\fd"                 ;; "\ec\80\fd"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ed\80\00"                 ;; "\ed\80\00"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ed\80\7f"                 ;; "\ed\80\7f"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ed\80\c0"                 ;; "\ed\80\c0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xed) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ed\80\fd"                 ;; "\ed\80\fd"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ee\80\00"                 ;; "\ee\80\00"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ee\80\7f"                 ;; "\ee\80\7f"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ee\80\c0"                 ;; "\ee\80\c0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ee\80\fd"                 ;; "\ee\80\fd"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ef\80\00"                 ;; "\ef\80\00"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ef\80\7f"                 ;; "\ef\80\7f"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ef\80\c0"                 ;; "\ef\80\c0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 3-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\ef\80\fd"                 ;; "\ef\80\fd"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 4-byte sequences
+
+;; 4-byte sequence contains 5 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0f"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\05\f1\80\80\80\80"           ;; "\f1\80\80\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 3 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\f1\80\80"                 ;; "\f1\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 3 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f1\80\80\23"              ;; "\f1\80\80#"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 2 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\f1\80"                    ;; "\f1\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 2 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\f1\80\23"                 ;; "\f1\80#"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 1 byte at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\01\f1"                       ;; "\f1"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 4-byte sequence contains 1 byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\f1\23"                    ;; "\f1#"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 4-byte sequence contents
+
+;; first byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\00\90\90"              ;; "\f0\00\90\90"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\7f\90\90"              ;; "\f0\7f\90\90"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xf0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\80\80\80"              ;; "\f0\80\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xf0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\80\90\90"              ;; "\f0\80\90\90"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xf0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\8f\90\90"              ;; "\f0\8f\90\90"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; overlong encoding after 0xf0 prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\8f\bf\bf"              ;; "\f0\8f\bf\bf"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\c0\90\90"              ;; "\f0\c0\90\90"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\fd\90\90"              ;; "\f0\fd\90\90"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f1\00\80\80"              ;; "\f1\00\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f1\7f\80\80"              ;; "\f1\7f\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f1\c0\80\80"              ;; "\f1\c0\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f1\fd\80\80"              ;; "\f1\fd\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f3\00\80\80"              ;; "\f3\00\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f3\7f\80\80"              ;; "\f3\7f\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f3\c0\80\80"              ;; "\f3\c0\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f3\fd\80\80"              ;; "\f3\fd\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f4\00\80\80"              ;; "\f4\00\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f4\7f\80\80"              ;; "\f4\7f\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (first) invalid code point
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f4\90\80\80"              ;; "\f4\90\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; invalid code point
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f4\bf\80\80"              ;; "\f4\bf\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f4\c0\80\80"              ;; "\f4\c0\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; first byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f4\fd\80\80"              ;; "\f4\fd\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (first) invalid 4-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f5\80\80\80"              ;; "\f5\80\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (last) invalid 4-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f7\80\80\80"              ;; "\f7\80\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (last) invalid 4-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f7\bf\bf\bf"              ;; "\f7\bf\bf\bf"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 4-byte sequence contents (third byte)
+
+;; second byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\90\00\90"              ;; "\f0\90\00\90"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\90\7f\90"              ;; "\f0\90\7f\90"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\90\c0\90"              ;; "\f0\90\c0\90"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\90\fd\90"              ;; "\f0\90\fd\90"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f1\80\00\80"              ;; "\f1\80\00\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f1\80\7f\80"              ;; "\f1\80\7f\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f1\80\c0\80"              ;; "\f1\80\c0\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f1\80\fd\80"              ;; "\f1\80\fd\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f3\80\00\80"              ;; "\f3\80\00\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f3\80\7f\80"              ;; "\f3\80\7f\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f3\80\c0\80"              ;; "\f3\80\c0\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f3\80\fd\80"              ;; "\f3\80\fd\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f4\80\00\80"              ;; "\f4\80\00\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f4\80\7f\80"              ;; "\f4\80\7f\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f4\80\c0\80"              ;; "\f4\80\c0\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; second byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f4\80\fd\80"              ;; "\f4\80\fd\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 4-byte sequence contents (fourth byte)
+
+;; third byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\90\90\00"              ;; "\f0\90\90\00"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\90\90\7f"              ;; "\f0\90\90\7f"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\90\90\c0"              ;; "\f0\90\90\c0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf0) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f0\90\90\fd"              ;; "\f0\90\90\fd"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f1\80\80\00"              ;; "\f1\80\80\00"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f1\80\80\7f"              ;; "\f1\80\80\7f"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f1\80\80\c0"              ;; "\f1\80\80\c0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (first normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f1\80\80\fd"              ;; "\f1\80\80\fd"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f3\80\80\00"              ;; "\f3\80\80\00"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f3\80\80\7f"              ;; "\f3\80\80\7f"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f3\80\80\c0"              ;; "\f3\80\80\c0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (last normal) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f3\80\80\fd"              ;; "\f3\80\80\fd"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f4\80\80\00"              ;; "\f4\80\80\00"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f4\80\80\7f"              ;; "\f4\80\80\7f"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f4\80\80\c0"              ;; "\f4\80\80\c0"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; third byte after (0xf4) 4-byte prefix not a continuation byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f4\80\80\fd"              ;; "\f4\80\80\fd"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 5-byte sequences
+
+;; 5-byte sequence contains 6 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\10"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\06\f8\80\80\80\80\80"        ;; "\f8\80\80\80\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 4 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f8\80\80\80"              ;; "\f8\80\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 4 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0f"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\05\f8\80\80\80\23"           ;; "\f8\80\80\80#"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 3 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\f8\80\80"                 ;; "\f8\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 3 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\f8\80\80\23"              ;; "\f8\80\80#"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 2 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\f8\80"                    ;; "\f8\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 2 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\f8\80\23"                 ;; "\f8\80#"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 1 byte at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\01\f8"                       ;; "\f8"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 5-byte sequence contains 1 byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\f8\23"                    ;; "\f8#"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 5-byte sequence contents
+
+;; (first) invalid 5-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0f"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\05\f8\80\80\80\80"           ;; "\f8\80\80\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (last) invalid 5-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0f"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\05\fb\bf\bf\bf\bf"           ;; "\fb\bf\bf\bf\bf"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 6-byte sequences
+
+;; 6-byte sequence contains 7 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\11"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\07\fc\80\80\80\80\80\80"     ;; "\fc\80\80\80\80\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 5 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0f"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\05\fc\80\80\80\80"           ;; "\fc\80\80\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 5 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\10"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\06\fc\80\80\80\80\23"        ;; "\fc\80\80\80\80#"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 4 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\fc\80\80\80"              ;; "\fc\80\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 4 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0f"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\05\fc\80\80\80\23"           ;; "\fc\80\80\80#"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 3 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\fc\80\80"                 ;; "\fc\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 3 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\fc\80\80\23"              ;; "\fc\80\80#"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 2 bytes at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\fc\80"                    ;; "\fc\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 2 bytes
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0d"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\03\fc\80\23"                 ;; "\fc\80#"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 1 byte at end of string
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\01\fc"                       ;; "\fc"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; 6-byte sequence contains 1 byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\fc\23"                    ;; "\fc#"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; 6-byte sequence contents
+
+;; (first) invalid 6-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\10"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\06\fc\80\80\80\80\80"        ;; "\fc\80\80\80\80\80"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; (last) invalid 6-byte prefix
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\10"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\06\fd\bf\bf\bf\bf\bf"        ;; "\fd\bf\bf\bf\bf\bf"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;;;; Miscellaneous invalid bytes
+
+;; invalid byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\01\fe"                       ;; "\fe"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; invalid byte
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0b"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\01\ff"                       ;; "\ff"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; UTF-16BE BOM
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\fe\ff"                    ;; "\fe\ff"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; UTF-32BE BOM
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\00\00\fe\ff"              ;; "\00\00\fe\ff"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; UTF-16LE BOM
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0c"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\02\ff\fe"                    ;; "\ff\fe"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
+;; UTF-32LE BOM
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\02\0e"                       ;; import section
+    "\01"                          ;; length 1
+    "\04\74\65\73\74"              ;; "test"
+    "\04\ff\fe\00\00"              ;; "\ff\fe\00\00"
+    "\03"                          ;; GlobalImport
+    "\7f"                          ;; i32
+    "\00"                          ;; immutable
+  )
+  "invalid UTF-8 encoding"
+)
+
diff --git a/binaryen/test/spec/utf8-invalid-encoding.wast b/binaryen/test/spec/utf8-invalid-encoding.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/spec/utf8-invalid-encoding.wast
@@ -0,0 +1,176 @@
+(assert_malformed (module quote "(func (export \"\\00\\00\\fe\\ff\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\8f\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\90\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\9f\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\a0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\bf\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\c0\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\c0\\bf\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\c1\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\c1\\bf\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\c2\\00\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\c2\\2e\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\c2\\7f\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\c2\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\c2\\c0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\c2\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\c2\\fd\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\df\\00\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\df\\7f\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\df\\c0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\df\\fd\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e0\\00\\a0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e0\\7f\\a0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e0\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e0\\80\\a0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e0\\9f\\a0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e0\\9f\\bf\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e0\\a0\\00\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e0\\a0\\7f\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e0\\a0\\c0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e0\\a0\\fd\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e0\\c0\\a0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e0\\fd\\a0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e1\\00\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e1\\2e\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e1\\7f\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e1\\80\\00\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e1\\80\\2e\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e1\\80\\7f\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e1\\80\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e1\\80\\c0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e1\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e1\\80\\fd\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e1\\c0\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e1\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\e1\\fd\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ec\\00\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ec\\7f\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ec\\80\\00\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ec\\80\\7f\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ec\\80\\c0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ec\\80\\fd\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ec\\c0\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ec\\fd\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ed\\00\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ed\\7f\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ed\\80\\00\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ed\\80\\7f\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ed\\80\\c0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ed\\80\\fd\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ed\\a0\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ed\\a0\\bf\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ed\\bf\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ed\\bf\\bf\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ed\\c0\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ed\\fd\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ee\\00\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ee\\7f\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ee\\80\\00\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ee\\80\\7f\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ee\\80\\c0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ee\\80\\fd\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ee\\c0\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ee\\fd\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ef\\00\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ef\\7f\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ef\\80\\00\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ef\\80\\7f\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ef\\80\\c0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ef\\80\\fd\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ef\\c0\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ef\\fd\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\00\\90\\90\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\7f\\90\\90\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\80\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\80\\90\\90\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\8f\\90\\90\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\8f\\bf\\bf\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\90\\00\\90\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\90\\7f\\90\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\90\\90\\00\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\90\\90\\7f\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\90\\90\\c0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\90\\90\\fd\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\90\\c0\\90\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\90\\fd\\90\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\c0\\90\\90\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f0\\fd\\90\\90\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\00\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\23\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\7f\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\80\\00\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\80\\23\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\80\\7f\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\80\\80\\00\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\80\\80\\23\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\80\\80\\7f\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\80\\80\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\80\\80\\c0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\80\\80\\fd\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\80\\c0\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\80\\fd\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\c0\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f1\\fd\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f3\\00\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f3\\7f\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f3\\80\\00\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f3\\80\\7f\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f3\\80\\80\\00\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f3\\80\\80\\7f\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f3\\80\\80\\c0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f3\\80\\80\\fd\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f3\\80\\c0\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f3\\80\\fd\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f3\\c0\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f3\\fd\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f4\\00\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f4\\7f\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f4\\80\\00\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f4\\80\\7f\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f4\\80\\80\\00\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f4\\80\\80\\7f\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f4\\80\\80\\c0\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f4\\80\\80\\fd\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f4\\80\\c0\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f4\\80\\fd\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f4\\90\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f4\\bf\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f4\\c0\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f4\\fd\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f5\\80\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f7\\80\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f7\\bf\\bf\\bf\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f8\\23\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f8\\80\\23\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f8\\80\\80\\23\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f8\\80\\80\\80\\23\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f8\\80\\80\\80\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f8\\80\\80\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f8\\80\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f8\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f8\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\f8\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fb\\bf\\bf\\bf\\bf\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fc\\23\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fc\\80\\23\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fc\\80\\80\\23\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fc\\80\\80\\80\\23\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fc\\80\\80\\80\\80\\23\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fc\\80\\80\\80\\80\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fc\\80\\80\\80\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fc\\80\\80\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fc\\80\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fc\\80\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fc\\80\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fc\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fd\\bf\\bf\\bf\\bf\\bf\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fe\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\fe\\ff\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ff\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ff\\fe\\00\\00\"))") "invalid UTF-8 encoding")
+(assert_malformed (module quote "(func (export \"\\ff\\fe\"))") "invalid UTF-8 encoding")
diff --git a/binaryen/test/stacky.wasm b/binaryen/test/stacky.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/stacky.wasm differ
diff --git a/binaryen/test/stacky.wasm.fromBinary b/binaryen/test/stacky.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/stacky.wasm.fromBinary
@@ -0,0 +1,21 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (memory $0 256 256)
+ (export "add" (func $0))
+ (func $0 (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (i32.add
+   (block (result i32)
+    (local.set $2
+     (local.get $0)
+    )
+    (local.set $0
+     (i32.const 100)
+    )
+    (local.get $2)
+   )
+   (local.get $1)
+  )
+ )
+)
+
diff --git a/binaryen/test/table-import.wast b/binaryen/test/table-import.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/table-import.wast
@@ -0,0 +1,9 @@
+(module
+  (type $0 (func))
+  (import "env" "table" (table 1 1 funcref))
+  (elem (i32.const 0) $foo)
+  (memory $0 0)
+  (func $foo (type $0)
+    (nop)
+  )
+)
diff --git a/binaryen/test/table-import.wast.from-wast b/binaryen/test/table-import.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/table-import.wast.from-wast
@@ -0,0 +1,9 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "table" (table $timport$0 1 1 funcref))
+ (elem (i32.const 0) $foo)
+ (memory $0 0)
+ (func $foo
+  (nop)
+ )
+)
diff --git a/binaryen/test/table-import.wast.fromBinary b/binaryen/test/table-import.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/table-import.wast.fromBinary
@@ -0,0 +1,10 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "table" (table $timport$0 1 1 funcref))
+ (elem (i32.const 0) $foo)
+ (memory $0 0)
+ (func $foo
+  (nop)
+ )
+)
+
diff --git a/binaryen/test/table-import.wast.fromBinary.noDebugInfo b/binaryen/test/table-import.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/table-import.wast.fromBinary.noDebugInfo
@@ -0,0 +1,10 @@
+(module
+ (type $none_=>_none (func))
+ (import "env" "table" (table $timport$0 1 1 funcref))
+ (elem (i32.const 0) $0)
+ (memory $0 0)
+ (func $0
+  (nop)
+ )
+)
+
diff --git a/binaryen/test/tail-call.wast b/binaryen/test/tail-call.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/tail-call.wast
@@ -0,0 +1,11 @@
+(module
+ (type $void (func))
+ (table 1 1 funcref)
+ (elem (i32.const 0) $foo)
+ (func $foo
+  (return_call $bar)
+ )
+ (func $bar
+  (return_call_indirect (type $void) (i32.const 0))
+ )
+)
diff --git a/binaryen/test/tail-call.wast.from-wast b/binaryen/test/tail-call.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/tail-call.wast.from-wast
@@ -0,0 +1,13 @@
+(module
+ (type $none_=>_none (func))
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $foo)
+ (func $foo
+  (return_call $bar)
+ )
+ (func $bar
+  (return_call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+)
diff --git a/binaryen/test/tail-call.wast.fromBinary b/binaryen/test/tail-call.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/tail-call.wast.fromBinary
@@ -0,0 +1,14 @@
+(module
+ (type $none_=>_none (func))
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $foo)
+ (func $foo
+  (return_call $bar)
+ )
+ (func $bar
+  (return_call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+)
+
diff --git a/binaryen/test/tail-call.wast.fromBinary.noDebugInfo b/binaryen/test/tail-call.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/tail-call.wast.fromBinary.noDebugInfo
@@ -0,0 +1,14 @@
+(module
+ (type $none_=>_none (func))
+ (table $0 1 1 funcref)
+ (elem (i32.const 0) $0)
+ (func $0
+  (return_call $1)
+ )
+ (func $1
+  (return_call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+)
+
diff --git a/binaryen/test/threads.asm.js b/binaryen/test/threads.asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/threads.asm.js
@@ -0,0 +1,147 @@
+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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/threads.wasm-only.asm.js
@@ -0,0 +1,48 @@
+//
+// 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
new file mode 100644
Binary files /dev/null and b/binaryen/test/try-body-multiple-insts.wasm differ
diff --git a/binaryen/test/try-body-multiple-insts.wasm.fromBinary b/binaryen/test/try-body-multiple-insts.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/try-body-multiple-insts.wasm.fromBinary
@@ -0,0 +1,26 @@
+(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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/two_sides.asm.js
@@ -0,0 +1,30 @@
+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/unit.asm.js b/binaryen/test/unit.asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit.asm.js
@@ -0,0 +1,811 @@
+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.wast.from-wast b/binaryen/test/unit.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit.wast.from-wast
@@ -0,0 +1,619 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $f32_=>_none (func (param f32)))
+ (type $none_=>_f64 (func (result f64)))
+ (type $f64_f64_=>_f64 (func (param f64 f64) (result f64)))
+ (type $i32_i64_=>_none (func (param i32 i64)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $f64_=>_i32 (func (param f64) (result i32)))
+ (type $none_=>_i64 (func (result i64)))
+ (type $f64_=>_f64 (func (param f64) (result f64)))
+ (import "env" "_emscripten_asm_const_vi" (func $_emscripten_asm_const_vi))
+ (import "asm2wasm" "f64-to-int" (func $f64-to-int (param f64) (result i32)))
+ (import "asm2wasm" "f64-rem" (func $f64-rem (param f64 f64) (result f64)))
+ (memory $0 4096 4096)
+ (data (i32.const 1026) "\14\00")
+ (table $0 10 funcref)
+ (elem (i32.const 0) $z $big_negative $z $z $w $w $importedDoubles $w $z $cneg)
+ (export "big_negative" (func $big_negative))
+ (func $big_negative (; 3 ;)
+  (local $temp f64)
+  (block $block0
+   (local.set $temp
+    (f64.const -2147483648)
+   )
+   (local.set $temp
+    (f64.const -2147483648)
+   )
+   (local.set $temp
+    (f64.const -21474836480)
+   )
+   (local.set $temp
+    (f64.const 0.039625)
+   )
+   (local.set $temp
+    (f64.const -0.039625)
+   )
+  )
+ )
+ (func $importedDoubles (; 4 ;) (result f64)
+  (local $temp f64)
+  (block $topmost (result f64)
+   (local.set $temp
+    (f64.add
+     (f64.add
+      (f64.add
+       (f64.load
+        (i32.const 8)
+       )
+       (f64.load
+        (i32.const 16)
+       )
+      )
+      (f64.neg
+       (f64.load
+        (i32.const 16)
+       )
+      )
+     )
+     (f64.neg
+      (f64.load
+       (i32.const 8)
+      )
+     )
+    )
+   )
+   (if
+    (i32.gt_s
+     (i32.load
+      (i32.const 24)
+     )
+     (i32.const 0)
+    )
+    (br $topmost
+     (f64.const -3.4)
+    )
+   )
+   (if
+    (f64.gt
+     (f64.load
+      (i32.const 32)
+     )
+     (f64.const 0)
+    )
+    (br $topmost
+     (f64.const 5.6)
+    )
+   )
+   (f64.const 1.2)
+  )
+ )
+ (func $doubleCompares (; 5 ;) (param $x f64) (param $y f64) (result f64)
+  (local $t f64)
+  (local $Int f64)
+  (local $Double i32)
+  (block $topmost (result f64)
+   (if
+    (f64.gt
+     (local.get $x)
+     (f64.const 0)
+    )
+    (br $topmost
+     (f64.const 1.2)
+    )
+   )
+   (if
+    (f64.gt
+     (local.get $Int)
+     (f64.const 0)
+    )
+    (br $topmost
+     (f64.const -3.4)
+    )
+   )
+   (if
+    (i32.gt_s
+     (local.get $Double)
+     (i32.const 0)
+    )
+    (br $topmost
+     (f64.const 5.6)
+    )
+   )
+   (if
+    (f64.lt
+     (local.get $x)
+     (local.get $y)
+    )
+    (br $topmost
+     (local.get $x)
+    )
+   )
+   (local.get $y)
+  )
+ )
+ (func $intOps (; 6 ;) (result i32)
+  (local $x i32)
+  (i32.eq
+   (local.get $x)
+   (i32.const 0)
+  )
+ )
+ (func $hexLiterals (; 7 ;)
+  (drop
+   (i32.add
+    (i32.add
+     (i32.const 0)
+     (i32.const 313249263)
+    )
+    (i32.const -19088752)
+   )
+  )
+ )
+ (func $conversions (; 8 ;)
+  (local $i i32)
+  (local $d f64)
+  (block $block0
+   (local.set $i
+    (call $f64-to-int
+     (local.get $d)
+    )
+   )
+   (local.set $d
+    (f64.convert_i32_s
+     (local.get $i)
+    )
+   )
+   (local.set $d
+    (f64.convert_i32_u
+     (i32.shr_u
+      (local.get $i)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+ )
+ (func $seq (; 9 ;)
+  (local $J f64)
+  (local.set $J
+   (f64.sub
+    (block $block0 (result f64)
+     (drop
+      (f64.const 0.1)
+     )
+     (f64.const 5.1)
+    )
+    (block $block1 (result f64)
+     (drop
+      (f64.const 3.2)
+     )
+     (f64.const 4.2)
+    )
+   )
+  )
+ )
+ (func $switcher (; 10 ;) (param $x i32) (result i32)
+  (block $topmost (result i32)
+   (block $switch$0
+    (block $switch-default$3
+     (block $switch-case$2
+      (block $switch-case$1
+       (br_table $switch-case$1 $switch-case$2 $switch-default$3
+        (i32.sub
+         (local.get $x)
+         (i32.const 1)
+        )
+       )
+      )
+      (br $topmost
+       (i32.const 1)
+      )
+     )
+     (br $topmost
+      (i32.const 2)
+     )
+    )
+    (nop)
+   )
+   (block $switch$4
+    (block $switch-default$7
+     (block $switch-case$6
+      (block $switch-case$5
+       (br_table $switch-case$6 $switch-default$7 $switch-default$7 $switch-default$7 $switch-default$7 $switch-default$7 $switch-default$7 $switch-case$5 $switch-default$7
+        (i32.sub
+         (local.get $x)
+         (i32.const 5)
+        )
+       )
+      )
+      (br $topmost
+       (i32.const 121)
+      )
+     )
+     (br $topmost
+      (i32.const 51)
+     )
+    )
+    (nop)
+   )
+   (block $label$break$Lout
+    (block $switch-default$16
+     (block $switch-case$15
+      (block $switch-case$12
+       (block $switch-case$9
+        (block $switch-case$8
+         (br_table $switch-case$15 $switch-default$16 $switch-default$16 $switch-case$12 $switch-default$16 $switch-default$16 $switch-default$16 $switch-default$16 $switch-case$9 $switch-default$16 $switch-case$8 $switch-default$16
+          (i32.sub
+           (local.get $x)
+           (i32.const 2)
+          )
+         )
+        )
+        (br $label$break$Lout)
+       )
+       (br $label$break$Lout)
+      )
+      (block $while-out$10
+       (loop $while-in$11
+        (block $block1
+         (br $while-out$10)
+         (br $while-in$11)
+        )
+       )
+       (br $label$break$Lout)
+      )
+     )
+     (block $while-out$13
+      (loop $while-in$14
+       (block $block3
+        (br $label$break$Lout)
+        (br $while-in$14)
+       )
+      )
+      (br $label$break$Lout)
+     )
+    )
+    (nop)
+   )
+   (i32.const 0)
+  )
+ )
+ (func $blocker (; 11 ;)
+  (block $label$break$L
+   (br $label$break$L)
+  )
+ )
+ (func $frem (; 12 ;) (result f64)
+  (call $f64-rem
+   (f64.const 5.5)
+   (f64.const 1.2)
+  )
+ )
+ (func $big_uint_div_u (; 13 ;) (result i32)
+  (local $x i32)
+  (block $topmost (result i32)
+   (local.set $x
+    (i32.and
+     (i32.div_u
+      (i32.const -1)
+      (i32.const 2)
+     )
+     (i32.const -1)
+    )
+   )
+   (local.get $x)
+  )
+ )
+ (func $fr (; 14 ;) (param $x f32)
+  (local $y f32)
+  (local $z f64)
+  (block $block0
+   (drop
+    (f32.demote_f64
+     (local.get $z)
+    )
+   )
+   (drop
+    (local.get $y)
+   )
+   (drop
+    (f32.const 5)
+   )
+   (drop
+    (f32.const 0)
+   )
+   (drop
+    (f32.const 5)
+   )
+   (drop
+    (f32.const 0)
+   )
+  )
+ )
+ (func $negZero (; 15 ;) (result f64)
+  (f64.const -0)
+ )
+ (func $abs (; 16 ;)
+  (local $x i32)
+  (local $y f64)
+  (local $z f32)
+  (local $asm2wasm_i32_temp i32)
+  (block $block0
+   (local.set $x
+    (block $block1 (result i32)
+     (local.set $asm2wasm_i32_temp
+      (i32.const 0)
+     )
+     (select
+      (i32.sub
+       (i32.const 0)
+       (local.get $asm2wasm_i32_temp)
+      )
+      (local.get $asm2wasm_i32_temp)
+      (i32.lt_s
+       (local.get $asm2wasm_i32_temp)
+       (i32.const 0)
+      )
+     )
+    )
+   )
+   (local.set $y
+    (f64.abs
+     (f64.const 0)
+    )
+   )
+   (local.set $z
+    (f32.abs
+     (f32.const 0)
+    )
+   )
+  )
+ )
+ (func $neg (; 17 ;)
+  (local $x f32)
+  (block $block0
+   (local.set $x
+    (f32.neg
+     (local.get $x)
+    )
+   )
+   (call_indirect (type $f32_=>_none)
+    (local.get $x)
+    (i32.add
+     (i32.and
+      (i32.const 1)
+      (i32.const 7)
+     )
+     (i32.const 8)
+    )
+   )
+  )
+ )
+ (func $cneg (; 18 ;) (param $x f32)
+  (call_indirect (type $f32_=>_none)
+   (local.get $x)
+   (i32.add
+    (i32.and
+     (i32.const 1)
+     (i32.const 7)
+    )
+    (i32.const 8)
+   )
+  )
+ )
+ (func $___syscall_ret (; 19 ;)
+  (local $$0 i32)
+  (drop
+   (i32.gt_u
+    (i32.shr_u
+     (local.get $$0)
+     (i32.const 0)
+    )
+    (i32.const -4096)
+   )
+  )
+ )
+ (func $z (; 20 ;)
+  (nop)
+ )
+ (func $w (; 21 ;)
+  (nop)
+ )
+ (func $block_and_after (; 22 ;) (result i32)
+  (block $waka
+   (drop
+    (i32.const 1)
+   )
+   (br $waka)
+  )
+  (i32.const 0)
+ )
+ (func $loop-roundtrip (; 23 ;) (param $0 f64) (result f64)
+  (loop $loop-in1 (result f64)
+   (drop
+    (local.get $0)
+   )
+   (local.get $0)
+  )
+ )
+ (func $big-i64 (; 24 ;) (result i64)
+  (i64.const -9218868437227405313)
+ )
+ (func $i64-store32 (; 25 ;) (param $0 i32) (param $1 i64)
+  (i64.store32
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $return-unreachable (; 26 ;) (result i32)
+  (return
+   (i32.const 1)
+  )
+ )
+ (func $unreachable-block (; 27 ;) (result i32)
+  (f64.abs
+   (block $block
+    (drop
+     (i32.const 1)
+    )
+    (return
+     (i32.const 2)
+    )
+   )
+  )
+ )
+ (func $unreachable-block-toplevel (; 28 ;) (result i32)
+  (block $block
+   (drop
+    (i32.const 1)
+   )
+   (return
+    (i32.const 2)
+   )
+  )
+ )
+ (func $unreachable-block0 (; 29 ;) (result i32)
+  (f64.abs
+   (block $block
+    (return
+     (i32.const 2)
+    )
+   )
+  )
+ )
+ (func $unreachable-block0-toplevel (; 30 ;) (result i32)
+  (block $block
+   (return
+    (i32.const 2)
+   )
+  )
+ )
+ (func $unreachable-block-with-br (; 31 ;) (result i32)
+  (block $block
+   (drop
+    (i32.const 1)
+   )
+   (br $block)
+  )
+  (i32.const 1)
+ )
+ (func $unreachable-if (; 32 ;) (result i32)
+  (f64.abs
+   (if
+    (i32.const 3)
+    (return
+     (i32.const 2)
+    )
+    (return
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $unreachable-if-toplevel (; 33 ;) (result i32)
+  (if
+   (i32.const 3)
+   (return
+    (i32.const 2)
+   )
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $unreachable-loop (; 34 ;) (result i32)
+  (f64.abs
+   (loop $loop-in
+    (nop)
+    (return
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $unreachable-loop0 (; 35 ;) (result i32)
+  (f64.abs
+   (loop $loop-in
+    (return
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $unreachable-loop-toplevel (; 36 ;) (result i32)
+  (loop $loop-in
+   (nop)
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $unreachable-loop0-toplevel (; 37 ;) (result i32)
+  (loop $loop-in
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $unreachable-ifs (; 38 ;)
+  (if
+   (unreachable)
+   (nop)
+  )
+  (if
+   (unreachable)
+   (unreachable)
+  )
+  (if
+   (unreachable)
+   (nop)
+   (nop)
+  )
+  (if
+   (unreachable)
+   (unreachable)
+   (nop)
+  )
+  (if
+   (unreachable)
+   (nop)
+   (unreachable)
+  )
+  (if
+   (unreachable)
+   (unreachable)
+   (unreachable)
+  )
+  (if
+   (i32.const 1)
+   (unreachable)
+   (nop)
+  )
+  (if
+   (i32.const 1)
+   (nop)
+   (unreachable)
+  )
+  (if
+   (i32.const 1)
+   (unreachable)
+   (unreachable)
+  )
+ )
+ (func $unreachable-if-arm (; 39 ;)
+  (if
+   (i32.const 1)
+   (block $block
+    (nop)
+   )
+   (block $block12
+    (unreachable)
+    (drop
+     (i32.const 1)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/unit.wast.fromBinary b/binaryen/test/unit.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit.wast.fromBinary
@@ -0,0 +1,537 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $f32_=>_none (func (param f32)))
+ (type $none_=>_f64 (func (result f64)))
+ (type $f64_f64_=>_f64 (func (param f64 f64) (result f64)))
+ (type $i32_i64_=>_none (func (param i32 i64)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $f64_=>_i32 (func (param f64) (result i32)))
+ (type $none_=>_i64 (func (result i64)))
+ (type $f64_=>_f64 (func (param f64) (result f64)))
+ (import "env" "_emscripten_asm_const_vi" (func $_emscripten_asm_const_vi))
+ (import "asm2wasm" "f64-to-int" (func $f64-to-int (param f64) (result i32)))
+ (import "asm2wasm" "f64-rem" (func $f64-rem (param f64 f64) (result f64)))
+ (memory $0 4096 4096)
+ (data (i32.const 1026) "\14\00")
+ (table $0 10 funcref)
+ (elem (i32.const 0) $z $big_negative $z $z $w $w $importedDoubles $w $z $cneg)
+ (export "big_negative" (func $big_negative))
+ (func $big_negative (; 3 ;)
+  (local $0 f64)
+  (local.set $0
+   (f64.const -2147483648)
+  )
+  (local.set $0
+   (f64.const -2147483648)
+  )
+  (local.set $0
+   (f64.const -21474836480)
+  )
+  (local.set $0
+   (f64.const 0.039625)
+  )
+  (local.set $0
+   (f64.const -0.039625)
+  )
+ )
+ (func $importedDoubles (; 4 ;) (result f64)
+  (local $0 f64)
+  (block $label$1 (result f64)
+   (local.set $0
+    (f64.add
+     (f64.add
+      (f64.add
+       (f64.load
+        (i32.const 8)
+       )
+       (f64.load
+        (i32.const 16)
+       )
+      )
+      (f64.neg
+       (f64.load
+        (i32.const 16)
+       )
+      )
+     )
+     (f64.neg
+      (f64.load
+       (i32.const 8)
+      )
+     )
+    )
+   )
+   (if
+    (i32.gt_s
+     (i32.load
+      (i32.const 24)
+     )
+     (i32.const 0)
+    )
+    (br $label$1
+     (f64.const -3.4)
+    )
+   )
+   (if
+    (f64.gt
+     (f64.load
+      (i32.const 32)
+     )
+     (f64.const 0)
+    )
+    (br $label$1
+     (f64.const 5.6)
+    )
+   )
+   (f64.const 1.2)
+  )
+ )
+ (func $doubleCompares (; 5 ;) (param $0 f64) (param $1 f64) (result f64)
+  (local $2 i32)
+  (local $3 f64)
+  (local $4 f64)
+  (block $label$1 (result f64)
+   (if
+    (f64.gt
+     (local.get $0)
+     (f64.const 0)
+    )
+    (br $label$1
+     (f64.const 1.2)
+    )
+   )
+   (if
+    (f64.gt
+     (local.get $4)
+     (f64.const 0)
+    )
+    (br $label$1
+     (f64.const -3.4)
+    )
+   )
+   (if
+    (i32.gt_s
+     (local.get $2)
+     (i32.const 0)
+    )
+    (br $label$1
+     (f64.const 5.6)
+    )
+   )
+   (if
+    (f64.lt
+     (local.get $0)
+     (local.get $1)
+    )
+    (br $label$1
+     (local.get $0)
+    )
+   )
+   (local.get $1)
+  )
+ )
+ (func $intOps (; 6 ;) (result i32)
+  (local $0 i32)
+  (i32.eq
+   (local.get $0)
+   (i32.const 0)
+  )
+ )
+ (func $hexLiterals (; 7 ;)
+  (drop
+   (i32.add
+    (i32.add
+     (i32.const 0)
+     (i32.const 313249263)
+    )
+    (i32.const -19088752)
+   )
+  )
+ )
+ (func $conversions (; 8 ;)
+  (local $0 i32)
+  (local $1 f64)
+  (local.set $0
+   (call $f64-to-int
+    (local.get $1)
+   )
+  )
+  (local.set $1
+   (f64.convert_i32_s
+    (local.get $0)
+   )
+  )
+  (local.set $1
+   (f64.convert_i32_u
+    (i32.shr_u
+     (local.get $0)
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $seq (; 9 ;)
+  (local $0 f64)
+  (local.set $0
+   (f64.sub
+    (block $label$1 (result f64)
+     (drop
+      (f64.const 0.1)
+     )
+     (f64.const 5.1)
+    )
+    (block $label$2 (result f64)
+     (drop
+      (f64.const 3.2)
+     )
+     (f64.const 4.2)
+    )
+   )
+  )
+ )
+ (func $switcher (; 10 ;) (param $0 i32) (result i32)
+  (block $label$1 (result i32)
+   (block $label$2
+    (block $label$3
+     (block $label$4
+      (block $label$5
+       (br_table $label$5 $label$4 $label$3
+        (i32.sub
+         (local.get $0)
+         (i32.const 1)
+        )
+       )
+      )
+      (br $label$1
+       (i32.const 1)
+      )
+     )
+     (br $label$1
+      (i32.const 2)
+     )
+    )
+    (nop)
+   )
+   (block $label$6
+    (block $label$7
+     (block $label$8
+      (block $label$9
+       (br_table $label$8 $label$7 $label$7 $label$7 $label$7 $label$7 $label$7 $label$9 $label$7
+        (i32.sub
+         (local.get $0)
+         (i32.const 5)
+        )
+       )
+      )
+      (br $label$1
+       (i32.const 121)
+      )
+     )
+     (br $label$1
+      (i32.const 51)
+     )
+    )
+    (nop)
+   )
+   (block $label$10
+    (block $label$11
+     (block $label$12
+      (block $label$13
+       (block $label$14
+        (block $label$15
+         (br_table $label$12 $label$11 $label$11 $label$13 $label$11 $label$11 $label$11 $label$11 $label$14 $label$11 $label$15 $label$11
+          (i32.sub
+           (local.get $0)
+           (i32.const 2)
+          )
+         )
+        )
+        (br $label$10)
+       )
+       (br $label$10)
+      )
+      (block $label$16
+       (loop $label$17
+        (br $label$16)
+       )
+      )
+     )
+     (block $label$18
+      (loop $label$19
+       (br $label$10)
+      )
+     )
+    )
+    (nop)
+   )
+   (i32.const 0)
+  )
+ )
+ (func $blocker (; 11 ;)
+  (block $label$1
+   (br $label$1)
+  )
+ )
+ (func $frem (; 12 ;) (result f64)
+  (call $f64-rem
+   (f64.const 5.5)
+   (f64.const 1.2)
+  )
+ )
+ (func $big_uint_div_u (; 13 ;) (result i32)
+  (local $0 i32)
+  (local.set $0
+   (i32.and
+    (i32.div_u
+     (i32.const -1)
+     (i32.const 2)
+    )
+    (i32.const -1)
+   )
+  )
+  (local.get $0)
+ )
+ (func $fr (; 14 ;) (param $0 f32)
+  (local $1 f32)
+  (local $2 f64)
+  (drop
+   (f32.demote_f64
+    (local.get $2)
+   )
+  )
+  (drop
+   (local.get $1)
+  )
+  (drop
+   (f32.const 5)
+  )
+  (drop
+   (f32.const 0)
+  )
+  (drop
+   (f32.const 5)
+  )
+  (drop
+   (f32.const 0)
+  )
+ )
+ (func $negZero (; 15 ;) (result f64)
+  (f64.const -0)
+ )
+ (func $abs (; 16 ;)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 f32)
+  (local $3 f64)
+  (local.set $0
+   (block $label$1 (result i32)
+    (local.set $1
+     (i32.const 0)
+    )
+    (select
+     (i32.sub
+      (i32.const 0)
+      (local.get $1)
+     )
+     (local.get $1)
+     (i32.lt_s
+      (local.get $1)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (local.set $3
+   (f64.abs
+    (f64.const 0)
+   )
+  )
+  (local.set $2
+   (f32.abs
+    (f32.const 0)
+   )
+  )
+ )
+ (func $neg (; 17 ;)
+  (local $0 f32)
+  (local.set $0
+   (f32.neg
+    (local.get $0)
+   )
+  )
+  (call_indirect (type $f32_=>_none)
+   (local.get $0)
+   (i32.add
+    (i32.and
+     (i32.const 1)
+     (i32.const 7)
+    )
+    (i32.const 8)
+   )
+  )
+ )
+ (func $cneg (; 18 ;) (param $0 f32)
+  (call_indirect (type $f32_=>_none)
+   (local.get $0)
+   (i32.add
+    (i32.and
+     (i32.const 1)
+     (i32.const 7)
+    )
+    (i32.const 8)
+   )
+  )
+ )
+ (func $___syscall_ret (; 19 ;)
+  (local $0 i32)
+  (drop
+   (i32.gt_u
+    (i32.shr_u
+     (local.get $0)
+     (i32.const 0)
+    )
+    (i32.const -4096)
+   )
+  )
+ )
+ (func $z (; 20 ;)
+  (nop)
+ )
+ (func $w (; 21 ;)
+  (nop)
+ )
+ (func $block_and_after (; 22 ;) (result i32)
+  (block $label$1
+   (drop
+    (i32.const 1)
+   )
+   (br $label$1)
+  )
+  (i32.const 0)
+ )
+ (func $loop-roundtrip (; 23 ;) (param $0 f64) (result f64)
+  (loop $label$1 (result f64)
+   (drop
+    (local.get $0)
+   )
+   (local.get $0)
+  )
+ )
+ (func $big-i64 (; 24 ;) (result i64)
+  (i64.const -9218868437227405313)
+ )
+ (func $i64-store32 (; 25 ;) (param $0 i32) (param $1 i64)
+  (i64.store32
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $return-unreachable (; 26 ;) (result i32)
+  (return
+   (i32.const 1)
+  )
+ )
+ (func $unreachable-block (; 27 ;) (result i32)
+  (block $label$1
+   (drop
+    (i32.const 1)
+   )
+   (return
+    (i32.const 2)
+   )
+  )
+ )
+ (func $unreachable-block-toplevel (; 28 ;) (result i32)
+  (drop
+   (i32.const 1)
+  )
+  (return
+   (i32.const 2)
+  )
+ )
+ (func $unreachable-block0 (; 29 ;) (result i32)
+  (block $label$1
+   (return
+    (i32.const 2)
+   )
+  )
+ )
+ (func $unreachable-block0-toplevel (; 30 ;) (result i32)
+  (return
+   (i32.const 2)
+  )
+ )
+ (func $unreachable-block-with-br (; 31 ;) (result i32)
+  (block $label$1
+   (drop
+    (i32.const 1)
+   )
+   (br $label$1)
+  )
+  (i32.const 1)
+ )
+ (func $unreachable-if (; 32 ;) (result i32)
+  (if
+   (i32.const 3)
+   (return
+    (i32.const 2)
+   )
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $unreachable-if-toplevel (; 33 ;) (result i32)
+  (if
+   (i32.const 3)
+   (return
+    (i32.const 2)
+   )
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $unreachable-loop (; 34 ;) (result i32)
+  (loop $label$1
+   (nop)
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $unreachable-loop0 (; 35 ;) (result i32)
+  (loop $label$1
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $unreachable-loop-toplevel (; 36 ;) (result i32)
+  (loop $label$1
+   (nop)
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $unreachable-loop0-toplevel (; 37 ;) (result i32)
+  (loop $label$1
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $unreachable-ifs (; 38 ;)
+  (unreachable)
+ )
+ (func $unreachable-if-arm (; 39 ;)
+  (if
+   (i32.const 1)
+   (nop)
+   (unreachable)
+  )
+ )
+)
+
diff --git a/binaryen/test/unit.wast.fromBinary.noDebugInfo b/binaryen/test/unit.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit.wast.fromBinary.noDebugInfo
@@ -0,0 +1,537 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (type $f32_=>_none (func (param f32)))
+ (type $none_=>_f64 (func (result f64)))
+ (type $f64_f64_=>_f64 (func (param f64 f64) (result f64)))
+ (type $i32_i64_=>_none (func (param i32 i64)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $f64_=>_i32 (func (param f64) (result i32)))
+ (type $none_=>_i64 (func (result i64)))
+ (type $f64_=>_f64 (func (param f64) (result f64)))
+ (import "env" "_emscripten_asm_const_vi" (func $fimport$0))
+ (import "asm2wasm" "f64-to-int" (func $fimport$1 (param f64) (result i32)))
+ (import "asm2wasm" "f64-rem" (func $fimport$2 (param f64 f64) (result f64)))
+ (memory $0 4096 4096)
+ (data (i32.const 1026) "\14\00")
+ (table $0 10 funcref)
+ (elem (i32.const 0) $17 $0 $17 $17 $18 $18 $1 $18 $17 $15)
+ (export "big_negative" (func $0))
+ (func $0 (; 3 ;)
+  (local $0 f64)
+  (local.set $0
+   (f64.const -2147483648)
+  )
+  (local.set $0
+   (f64.const -2147483648)
+  )
+  (local.set $0
+   (f64.const -21474836480)
+  )
+  (local.set $0
+   (f64.const 0.039625)
+  )
+  (local.set $0
+   (f64.const -0.039625)
+  )
+ )
+ (func $1 (; 4 ;) (result f64)
+  (local $0 f64)
+  (block $label$1 (result f64)
+   (local.set $0
+    (f64.add
+     (f64.add
+      (f64.add
+       (f64.load
+        (i32.const 8)
+       )
+       (f64.load
+        (i32.const 16)
+       )
+      )
+      (f64.neg
+       (f64.load
+        (i32.const 16)
+       )
+      )
+     )
+     (f64.neg
+      (f64.load
+       (i32.const 8)
+      )
+     )
+    )
+   )
+   (if
+    (i32.gt_s
+     (i32.load
+      (i32.const 24)
+     )
+     (i32.const 0)
+    )
+    (br $label$1
+     (f64.const -3.4)
+    )
+   )
+   (if
+    (f64.gt
+     (f64.load
+      (i32.const 32)
+     )
+     (f64.const 0)
+    )
+    (br $label$1
+     (f64.const 5.6)
+    )
+   )
+   (f64.const 1.2)
+  )
+ )
+ (func $2 (; 5 ;) (param $0 f64) (param $1 f64) (result f64)
+  (local $2 i32)
+  (local $3 f64)
+  (local $4 f64)
+  (block $label$1 (result f64)
+   (if
+    (f64.gt
+     (local.get $0)
+     (f64.const 0)
+    )
+    (br $label$1
+     (f64.const 1.2)
+    )
+   )
+   (if
+    (f64.gt
+     (local.get $4)
+     (f64.const 0)
+    )
+    (br $label$1
+     (f64.const -3.4)
+    )
+   )
+   (if
+    (i32.gt_s
+     (local.get $2)
+     (i32.const 0)
+    )
+    (br $label$1
+     (f64.const 5.6)
+    )
+   )
+   (if
+    (f64.lt
+     (local.get $0)
+     (local.get $1)
+    )
+    (br $label$1
+     (local.get $0)
+    )
+   )
+   (local.get $1)
+  )
+ )
+ (func $3 (; 6 ;) (result i32)
+  (local $0 i32)
+  (i32.eq
+   (local.get $0)
+   (i32.const 0)
+  )
+ )
+ (func $4 (; 7 ;)
+  (drop
+   (i32.add
+    (i32.add
+     (i32.const 0)
+     (i32.const 313249263)
+    )
+    (i32.const -19088752)
+   )
+  )
+ )
+ (func $5 (; 8 ;)
+  (local $0 i32)
+  (local $1 f64)
+  (local.set $0
+   (call $fimport$1
+    (local.get $1)
+   )
+  )
+  (local.set $1
+   (f64.convert_i32_s
+    (local.get $0)
+   )
+  )
+  (local.set $1
+   (f64.convert_i32_u
+    (i32.shr_u
+     (local.get $0)
+     (i32.const 0)
+    )
+   )
+  )
+ )
+ (func $6 (; 9 ;)
+  (local $0 f64)
+  (local.set $0
+   (f64.sub
+    (block $label$1 (result f64)
+     (drop
+      (f64.const 0.1)
+     )
+     (f64.const 5.1)
+    )
+    (block $label$2 (result f64)
+     (drop
+      (f64.const 3.2)
+     )
+     (f64.const 4.2)
+    )
+   )
+  )
+ )
+ (func $7 (; 10 ;) (param $0 i32) (result i32)
+  (block $label$1 (result i32)
+   (block $label$2
+    (block $label$3
+     (block $label$4
+      (block $label$5
+       (br_table $label$5 $label$4 $label$3
+        (i32.sub
+         (local.get $0)
+         (i32.const 1)
+        )
+       )
+      )
+      (br $label$1
+       (i32.const 1)
+      )
+     )
+     (br $label$1
+      (i32.const 2)
+     )
+    )
+    (nop)
+   )
+   (block $label$6
+    (block $label$7
+     (block $label$8
+      (block $label$9
+       (br_table $label$8 $label$7 $label$7 $label$7 $label$7 $label$7 $label$7 $label$9 $label$7
+        (i32.sub
+         (local.get $0)
+         (i32.const 5)
+        )
+       )
+      )
+      (br $label$1
+       (i32.const 121)
+      )
+     )
+     (br $label$1
+      (i32.const 51)
+     )
+    )
+    (nop)
+   )
+   (block $label$10
+    (block $label$11
+     (block $label$12
+      (block $label$13
+       (block $label$14
+        (block $label$15
+         (br_table $label$12 $label$11 $label$11 $label$13 $label$11 $label$11 $label$11 $label$11 $label$14 $label$11 $label$15 $label$11
+          (i32.sub
+           (local.get $0)
+           (i32.const 2)
+          )
+         )
+        )
+        (br $label$10)
+       )
+       (br $label$10)
+      )
+      (block $label$16
+       (loop $label$17
+        (br $label$16)
+       )
+      )
+     )
+     (block $label$18
+      (loop $label$19
+       (br $label$10)
+      )
+     )
+    )
+    (nop)
+   )
+   (i32.const 0)
+  )
+ )
+ (func $8 (; 11 ;)
+  (block $label$1
+   (br $label$1)
+  )
+ )
+ (func $9 (; 12 ;) (result f64)
+  (call $fimport$2
+   (f64.const 5.5)
+   (f64.const 1.2)
+  )
+ )
+ (func $10 (; 13 ;) (result i32)
+  (local $0 i32)
+  (local.set $0
+   (i32.and
+    (i32.div_u
+     (i32.const -1)
+     (i32.const 2)
+    )
+    (i32.const -1)
+   )
+  )
+  (local.get $0)
+ )
+ (func $11 (; 14 ;) (param $0 f32)
+  (local $1 f32)
+  (local $2 f64)
+  (drop
+   (f32.demote_f64
+    (local.get $2)
+   )
+  )
+  (drop
+   (local.get $1)
+  )
+  (drop
+   (f32.const 5)
+  )
+  (drop
+   (f32.const 0)
+  )
+  (drop
+   (f32.const 5)
+  )
+  (drop
+   (f32.const 0)
+  )
+ )
+ (func $12 (; 15 ;) (result f64)
+  (f64.const -0)
+ )
+ (func $13 (; 16 ;)
+  (local $0 i32)
+  (local $1 i32)
+  (local $2 f32)
+  (local $3 f64)
+  (local.set $0
+   (block $label$1 (result i32)
+    (local.set $1
+     (i32.const 0)
+    )
+    (select
+     (i32.sub
+      (i32.const 0)
+      (local.get $1)
+     )
+     (local.get $1)
+     (i32.lt_s
+      (local.get $1)
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (local.set $3
+   (f64.abs
+    (f64.const 0)
+   )
+  )
+  (local.set $2
+   (f32.abs
+    (f32.const 0)
+   )
+  )
+ )
+ (func $14 (; 17 ;)
+  (local $0 f32)
+  (local.set $0
+   (f32.neg
+    (local.get $0)
+   )
+  )
+  (call_indirect (type $f32_=>_none)
+   (local.get $0)
+   (i32.add
+    (i32.and
+     (i32.const 1)
+     (i32.const 7)
+    )
+    (i32.const 8)
+   )
+  )
+ )
+ (func $15 (; 18 ;) (param $0 f32)
+  (call_indirect (type $f32_=>_none)
+   (local.get $0)
+   (i32.add
+    (i32.and
+     (i32.const 1)
+     (i32.const 7)
+    )
+    (i32.const 8)
+   )
+  )
+ )
+ (func $16 (; 19 ;)
+  (local $0 i32)
+  (drop
+   (i32.gt_u
+    (i32.shr_u
+     (local.get $0)
+     (i32.const 0)
+    )
+    (i32.const -4096)
+   )
+  )
+ )
+ (func $17 (; 20 ;)
+  (nop)
+ )
+ (func $18 (; 21 ;)
+  (nop)
+ )
+ (func $19 (; 22 ;) (result i32)
+  (block $label$1
+   (drop
+    (i32.const 1)
+   )
+   (br $label$1)
+  )
+  (i32.const 0)
+ )
+ (func $20 (; 23 ;) (param $0 f64) (result f64)
+  (loop $label$1 (result f64)
+   (drop
+    (local.get $0)
+   )
+   (local.get $0)
+  )
+ )
+ (func $21 (; 24 ;) (result i64)
+  (i64.const -9218868437227405313)
+ )
+ (func $22 (; 25 ;) (param $0 i32) (param $1 i64)
+  (i64.store32
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $23 (; 26 ;) (result i32)
+  (return
+   (i32.const 1)
+  )
+ )
+ (func $24 (; 27 ;) (result i32)
+  (block $label$1
+   (drop
+    (i32.const 1)
+   )
+   (return
+    (i32.const 2)
+   )
+  )
+ )
+ (func $25 (; 28 ;) (result i32)
+  (drop
+   (i32.const 1)
+  )
+  (return
+   (i32.const 2)
+  )
+ )
+ (func $26 (; 29 ;) (result i32)
+  (block $label$1
+   (return
+    (i32.const 2)
+   )
+  )
+ )
+ (func $27 (; 30 ;) (result i32)
+  (return
+   (i32.const 2)
+  )
+ )
+ (func $28 (; 31 ;) (result i32)
+  (block $label$1
+   (drop
+    (i32.const 1)
+   )
+   (br $label$1)
+  )
+  (i32.const 1)
+ )
+ (func $29 (; 32 ;) (result i32)
+  (if
+   (i32.const 3)
+   (return
+    (i32.const 2)
+   )
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $30 (; 33 ;) (result i32)
+  (if
+   (i32.const 3)
+   (return
+    (i32.const 2)
+   )
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $31 (; 34 ;) (result i32)
+  (loop $label$1
+   (nop)
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $32 (; 35 ;) (result i32)
+  (loop $label$1
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $33 (; 36 ;) (result i32)
+  (loop $label$1
+   (nop)
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $34 (; 37 ;) (result i32)
+  (loop $label$1
+   (return
+    (i32.const 1)
+   )
+  )
+ )
+ (func $35 (; 38 ;)
+  (unreachable)
+ )
+ (func $36 (; 39 ;)
+  (if
+   (i32.const 1)
+   (nop)
+   (unreachable)
+  )
+ )
+)
+
diff --git a/binaryen/test/unit.wat b/binaryen/test/unit.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit.wat
@@ -0,0 +1,554 @@
+(module
+  (type $FUNCSIG$vf (func (param f32)))
+  (type $FUNCSIG$v (func))
+  (type $FUNCSIG$id (func (param f64) (result i32)))
+  (type $FUNCSIG$ddd (func (param f64 f64) (result f64)))
+  (type $4 (func (result f64)))
+  (type $5 (func (result i32)))
+  (type $6 (func (param i32) (result i32)))
+  (type $7 (func (param f64) (result f64)))
+  (type $8 (func (result i64)))
+  (type $9 (func (param i32 i64)))
+  (import "env" "_emscripten_asm_const_vi" (func $_emscripten_asm_const_vi))
+  (import "asm2wasm" "f64-to-int" (func $f64-to-int (param f64) (result i32)))
+  (import "asm2wasm" "f64-rem" (func $f64-rem (param f64 f64) (result f64)))
+  (table 10 funcref)
+  (elem (i32.const 0) $z $big_negative $z $z $w $w $importedDoubles $w $z $cneg)
+  (memory $0 4096 4096)
+  (data (i32.const 1026) "\14\00")
+  (export "big_negative" (func $big_negative))
+  (func $big_negative (type $FUNCSIG$v)
+    (local $temp f64)
+    (block $block0
+      (local.set $temp
+        (f64.const -2147483648)
+      )
+      (local.set $temp
+        (f64.const -2147483648)
+      )
+      (local.set $temp
+        (f64.const -21474836480)
+      )
+      (local.set $temp
+        (f64.const 0.039625)
+      )
+      (local.set $temp
+        (f64.const -0.039625)
+      )
+    )
+  )
+  (func $importedDoubles (type $4) (result f64)
+    (local $temp f64)
+    (block $topmost (result f64)
+      (local.set $temp
+        (f64.add
+          (f64.add
+            (f64.add
+              (f64.load
+                (i32.const 8)
+              )
+              (f64.load
+                (i32.const 16)
+              )
+            )
+            (f64.neg
+              (f64.load
+                (i32.const 16)
+              )
+            )
+          )
+          (f64.neg
+            (f64.load
+              (i32.const 8)
+            )
+          )
+        )
+      )
+      (if
+        (i32.gt_s
+          (i32.load
+            (i32.const 24)
+          )
+          (i32.const 0)
+        )
+        (br $topmost
+          (f64.const -3.4)
+        )
+      )
+      (if
+        (f64.gt
+          (f64.load
+            (i32.const 32)
+          )
+          (f64.const 0)
+        )
+        (br $topmost
+          (f64.const 5.6)
+        )
+      )
+      (f64.const 1.2)
+    )
+  )
+  (func $doubleCompares (type $FUNCSIG$ddd) (param $x f64) (param $y f64) (result f64)
+    (local $t f64)
+    (local $Int f64)
+    (local $Double i32)
+    (block $topmost (result f64)
+      (if
+        (f64.gt
+          (local.get $x)
+          (f64.const 0)
+        )
+        (br $topmost
+          (f64.const 1.2)
+        )
+      )
+      (if
+        (f64.gt
+          (local.get $Int)
+          (f64.const 0)
+        )
+        (br $topmost
+          (f64.const -3.4)
+        )
+      )
+      (if
+        (i32.gt_s
+          (local.get $Double)
+          (i32.const 0)
+        )
+        (br $topmost
+          (f64.const 5.6)
+        )
+      )
+      (if
+        (f64.lt
+          (local.get $x)
+          (local.get $y)
+        )
+        (br $topmost
+          (local.get $x)
+        )
+      )
+      (local.get $y)
+    )
+  )
+  (func $intOps (type $5) (result i32)
+    (local $x i32)
+    (i32.eq
+      (local.get $x)
+      (i32.const 0)
+    )
+  )
+  (func $hexLiterals (type $FUNCSIG$v)
+    (drop
+      (i32.add
+        (i32.add
+          (i32.const 0)
+          (i32.const 313249263)
+        )
+        (i32.const -19088752)
+      )
+    )
+  )
+  (func $conversions (type $FUNCSIG$v)
+    (local $i i32)
+    (local $d f64)
+    (block $block0
+      (local.set $i
+        (call $f64-to-int
+          (local.get $d)
+        )
+      )
+      (local.set $d
+        (f64.convert_i32_s
+          (local.get $i)
+        )
+      )
+      (local.set $d
+        (f64.convert_i32_u
+          (i32.shr_u
+            (local.get $i)
+            (i32.const 0)
+          )
+        )
+      )
+    )
+  )
+  (func $seq (type $FUNCSIG$v)
+    (local $J f64)
+    (local.set $J
+      (f64.sub
+        (block $block0 (result f64)
+          (drop
+            (f64.const 0.1)
+          )
+          (f64.const 5.1)
+        )
+        (block $block1 (result f64)
+          (drop
+            (f64.const 3.2)
+          )
+          (f64.const 4.2)
+        )
+      )
+    )
+  )
+  (func $switcher (type $6) (param $x i32) (result i32)
+    (block $topmost (result i32)
+      (block $switch$0
+        (block $switch-default$3
+          (block $switch-case$2
+            (block $switch-case$1
+              (br_table $switch-case$1 $switch-case$2 $switch-default$3
+                (i32.sub
+                  (local.get $x)
+                  (i32.const 1)
+                )
+              )
+            )
+            (br $topmost
+              (i32.const 1)
+            )
+          )
+          (br $topmost
+            (i32.const 2)
+          )
+        )
+        (nop)
+      )
+      (block $switch$4
+        (block $switch-default$7
+          (block $switch-case$6
+            (block $switch-case$5
+              (br_table $switch-case$6 $switch-default$7 $switch-default$7 $switch-default$7 $switch-default$7 $switch-default$7 $switch-default$7 $switch-case$5 $switch-default$7
+                (i32.sub
+                  (local.get $x)
+                  (i32.const 5)
+                )
+              )
+            )
+            (br $topmost
+              (i32.const 121)
+            )
+          )
+          (br $topmost
+            (i32.const 51)
+          )
+        )
+        (nop)
+      )
+      (block $label$break$Lout
+        (block $switch-default$16
+          (block $switch-case$15
+            (block $switch-case$12
+              (block $switch-case$9
+                (block $switch-case$8
+                  (br_table $switch-case$15 $switch-default$16 $switch-default$16 $switch-case$12 $switch-default$16 $switch-default$16 $switch-default$16 $switch-default$16 $switch-case$9 $switch-default$16 $switch-case$8 $switch-default$16
+                    (i32.sub
+                      (local.get $x)
+                      (i32.const 2)
+                    )
+                  )
+                )
+                (br $label$break$Lout)
+              )
+              (br $label$break$Lout)
+            )
+            (block $while-out$10
+              (loop $while-in$11
+                (block $block1
+                  (br $while-out$10)
+                  (br $while-in$11)
+                )
+              )
+              (br $label$break$Lout)
+            )
+          )
+          (block $while-out$13
+            (loop $while-in$14
+              (block $block3
+                (br $label$break$Lout)
+                (br $while-in$14)
+              )
+            )
+            (br $label$break$Lout)
+          )
+        )
+        (nop)
+      )
+      (i32.const 0)
+    )
+  )
+  (func $blocker (type $FUNCSIG$v)
+    (block $label$break$L
+      (br $label$break$L)
+    )
+  )
+  (func $frem (type $4) (result f64)
+    (call $f64-rem
+      (f64.const 5.5)
+      (f64.const 1.2)
+    )
+  )
+  (func $big_uint_div_u (type $5) (result i32)
+    (local $x i32)
+    (block $topmost (result i32)
+      (local.set $x
+        (i32.and
+          (i32.div_u
+            (i32.const -1)
+            (i32.const 2)
+          )
+          (i32.const -1)
+        )
+      )
+      (local.get $x)
+    )
+  )
+  (func $fr (type $FUNCSIG$vf) (param $x f32)
+    (local $y f32)
+    (local $z f64)
+    (block $block0
+      (drop
+        (f32.demote_f64
+          (local.get $z)
+        )
+      )
+      (drop
+        (local.get $y)
+      )
+      (drop
+        (f32.const 5)
+      )
+      (drop
+        (f32.const 0)
+      )
+      (drop
+        (f32.const 5)
+      )
+      (drop
+        (f32.const 0)
+      )
+    )
+  )
+  (func $negZero (type $4) (result f64)
+    (f64.const -0)
+  )
+  (func $abs (type $FUNCSIG$v)
+    (local $x i32)
+    (local $y f64)
+    (local $z f32)
+    (local $asm2wasm_i32_temp i32)
+    (block $block0
+      (local.set $x
+        (block $block1 (result i32)
+          (local.set $asm2wasm_i32_temp
+            (i32.const 0)
+          )
+          (select
+            (i32.sub
+              (i32.const 0)
+              (local.get $asm2wasm_i32_temp)
+            )
+            (local.get $asm2wasm_i32_temp)
+            (i32.lt_s
+              (local.get $asm2wasm_i32_temp)
+              (i32.const 0)
+            )
+          )
+        )
+      )
+      (local.set $y
+        (f64.abs
+          (f64.const 0)
+        )
+      )
+      (local.set $z
+        (f32.abs
+          (f32.const 0)
+        )
+      )
+    )
+  )
+  (func $neg (type $FUNCSIG$v)
+    (local $x f32)
+    (block $block0
+      (local.set $x
+        (f32.neg
+          (local.get $x)
+        )
+      )
+      (call_indirect (type $FUNCSIG$vf)
+        (local.get $x)
+        (i32.add
+          (i32.and
+            (i32.const 1)
+            (i32.const 7)
+          )
+          (i32.const 8)
+        )
+      )
+    )
+  )
+  (func $cneg (type $FUNCSIG$vf) (param $x f32)
+    (call_indirect (type $FUNCSIG$vf)
+      (local.get $x)
+      (i32.add
+        (i32.and
+          (i32.const 1)
+          (i32.const 7)
+        )
+        (i32.const 8)
+      )
+    )
+  )
+  (func $___syscall_ret (type $FUNCSIG$v)
+    (local $$0 i32)
+    (drop
+      (i32.gt_u
+        (i32.shr_u
+          (local.get $$0)
+          (i32.const 0)
+        )
+        (i32.const -4096)
+      )
+    )
+  )
+  (func $z (type $FUNCSIG$v)
+    (nop)
+  )
+  (func $w (type $FUNCSIG$v)
+    (nop)
+  )
+  (func $block_and_after (type $5) (result i32)
+    (block $waka
+      (drop
+        (i32.const 1)
+      )
+      (br $waka)
+    )
+    (i32.const 0)
+  )
+  (func $loop-roundtrip (type $7) (param $0 f64) (result f64)
+    (loop $loop-in1 (result f64)
+      (drop
+        (local.get $0)
+      )
+      (local.get $0)
+    )
+  )
+  (func $big-i64 (type $8) (result i64)
+    (i64.const -9218868437227405313)
+  )
+  (func $i64-store32 (type $9) (param $0 i32) (param $1 i64)
+    (i64.store32
+      (local.get $0)
+      (local.get $1)
+    )
+  )
+  (func $return-unreachable (result i32)
+    (return (i32.const 1))
+  )
+  (func $unreachable-block (result i32)
+    (f64.abs
+      (block ;; note no type - valid in binaryen IR, in wasm must be i32
+        (drop (i32.const 1))
+        (return (i32.const 2))
+      )
+    )
+  )
+  (func $unreachable-block-toplevel (result i32)
+    (block ;; note no type - valid in binaryen IR, in wasm must be i32
+      (drop (i32.const 1))
+      (return (i32.const 2))
+    )
+  )
+  (func $unreachable-block0 (result i32)
+    (f64.abs
+      (block ;; note no type - valid in binaryen IR, in wasm must be i32
+        (return (i32.const 2))
+      )
+    )
+  )
+  (func $unreachable-block0-toplevel (result i32)
+    (block ;; note no type - valid in binaryen IR, in wasm must be i32
+      (return (i32.const 2))
+    )
+  )
+  (func $unreachable-block-with-br (result i32)
+    (block $block ;; unreachable type due to last element having that type, but the block is exitable
+      (drop (i32.const 1))
+      (br $block)
+    )
+    (i32.const 1)
+  )
+  (func $unreachable-if (result i32)
+    (f64.abs
+      (if ;; note no type - valid in binaryen IR, in wasm must be i32
+        (i32.const 3)
+        (return (i32.const 2))
+        (return (i32.const 1))
+      )
+    )
+  )
+  (func $unreachable-if-toplevel (result i32)
+    (if ;; note no type - valid in binaryen IR, in wasm must be i32
+      (i32.const 3)
+      (return (i32.const 2))
+      (return (i32.const 1))
+    )
+  )
+  (func $unreachable-loop (result i32)
+    (f64.abs
+      (loop ;; note no type - valid in binaryen IR, in wasm must be i32
+        (nop)
+        (return (i32.const 1))
+      )
+    )
+  )
+  (func $unreachable-loop0 (result i32)
+    (f64.abs
+      (loop ;; note no type - valid in binaryen IR, in wasm must be i32
+        (return (i32.const 1))
+      )
+    )
+  )
+  (func $unreachable-loop-toplevel (result i32)
+    (loop ;; note no type - valid in binaryen IR, in wasm must be i32
+      (nop)
+      (return (i32.const 1))
+    )
+  )
+  (func $unreachable-loop0-toplevel (result i32)
+    (loop ;; note no type - valid in binaryen IR, in wasm must be i32
+      (return (i32.const 1))
+    )
+  )
+  (func $unreachable-ifs
+    (if (unreachable) (nop))
+    (if (unreachable) (unreachable))
+    (if (unreachable) (nop) (nop))
+    (if (unreachable) (unreachable) (nop))
+    (if (unreachable) (nop) (unreachable))
+    (if (unreachable) (unreachable) (unreachable))
+    ;;
+    (if (i32.const 1) (unreachable) (nop))
+    (if (i32.const 1) (nop) (unreachable))
+    (if (i32.const 1) (unreachable) (unreachable))
+  )
+  (func $unreachable-if-arm
+    (if
+      (i32.const 1)
+      (block
+        (nop)
+      )
+      (block
+        (unreachable)
+        (drop
+          (i32.const 1)
+        )
+      )
+    )
+  )
+)
diff --git a/binaryen/test/unit/__init__.py b/binaryen/test/unit/__init__.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/__init__.py
diff --git a/binaryen/test/unit/input/asyncify-coroutine.wat b/binaryen/test/unit/input/asyncify-coroutine.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/input/asyncify-coroutine.wat
@@ -0,0 +1,44 @@
+(module
+  (memory 1 2)
+  ;; import a "yield" function that receives the current value,
+  ;; then pauses execution until it is resumed later.
+  (import "env" "yield" (func $yield (param i32)))
+  (export "memory" (memory 0))
+  ;; simple linear progression in a loop
+  (func "linear" (result i32)
+    (local $x i32)
+    (loop $l
+      (call $yield (local.get $x))
+      (local.set $x
+        (i32.add (local.get $x) (i32.const 10))
+      )
+      (br $l)
+    )
+  )
+  ;; exponential in a loop
+  (func "exponential" (result i32)
+    (local $x i32)
+    (local.set $x
+      (i32.const 1)
+    )
+    (loop $l
+      (call $yield (local.get $x))
+      (local.set $x
+        (i32.mul (local.get $x) (i32.const 2))
+      )
+      (br $l)
+    )
+  )
+  ;; just some weird numbers, no loop
+  (func "weird" (result i32)
+    (call $yield (i32.const 42))
+    (call $yield (i32.const 1337))
+    (call $yield (i32.const 0))
+    (call $yield (i32.const -1000))
+    (call $yield (i32.const 42))
+    (call $yield (i32.const 314159))
+    (call $yield (i32.const 21828))
+    (unreachable)
+  )
+)
+
diff --git a/binaryen/test/unit/input/asyncify-pure.txt b/binaryen/test/unit/input/asyncify-pure.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/input/asyncify-pure.txt
@@ -0,0 +1,17 @@
+100 : i32
+10 : i32
+1 : i32
+20 : i32
+1000 : i32
+2000 : i32
+4000 : i32
+200 : i32
+300 : i32
+400 : i32
+1000 : i32
+3000 : i32
+4000 : i32
+30 : i32
+2 : i32
+40 : i32
+500 : i32
diff --git a/binaryen/test/unit/input/asyncify-pure.wat b/binaryen/test/unit/input/asyncify-pure.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/input/asyncify-pure.wat
@@ -0,0 +1,62 @@
+(module
+  (memory 1 1)
+  (import "spectest" "print" (func $print (param i32)))
+  (import "asyncify" "start_unwind" (func $asyncify_start_unwind (param i32)))
+  (import "asyncify" "stop_unwind" (func $asyncify_stop_unwind))
+  (import "asyncify" "start_rewind" (func $asyncify_start_rewind (param i32)))
+  (import "asyncify" "stop_rewind" (func $asyncify_stop_rewind))
+  (global $sleeping (mut i32) (i32.const 0))
+  (start $runtime)
+  (func $main
+    (call $print (i32.const 10))
+    (call $before)
+    (call $print (i32.const 20))
+    (call $sleep)
+    (call $print (i32.const 30))
+    (call $after)
+    (call $print (i32.const 40))
+  )
+  (func $before
+    (call $print (i32.const 1))
+  )
+  (func $sleep
+    (call $print (i32.const 1000))
+    (if
+      (i32.eqz (global.get $sleeping))
+      (block
+        (call $print (i32.const 2000))
+        (global.set $sleeping (i32.const 1))
+        (i32.store (i32.const 16) (i32.const 24))
+        (i32.store (i32.const 20) (i32.const 1024))
+        (call $asyncify_start_unwind (i32.const 16))
+      )
+      (block
+        (call $print (i32.const 3000))
+        (call $asyncify_stop_rewind)
+        (global.set $sleeping (i32.const 0))
+      )
+    )
+    (call $print (i32.const 4000))
+  )
+  (func $after
+    (call $print (i32.const 2))
+  )
+  (func $runtime
+    (call $print (i32.const 100))
+    ;; call main the first time, let the stack unwind
+    (call $main)
+    (call $print (i32.const 200))
+    (call $asyncify_stop_unwind)
+    (call $print (i32.const 300))
+    ;; ...can do some async stuff around here...
+    ;; set the rewind in motion
+    (call $asyncify_start_rewind (i32.const 16))
+    (call $print (i32.const 400))
+    (call $main)
+    (call $print (i32.const 500))
+  )
+  ;; interesting escaped name
+  (func $DOS_ReadFile\28unsigned\20short\2c\20unsigned\20char*\2c\20unsigned\20short*\2c\20bool\29 (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
+  )
+)
+
diff --git a/binaryen/test/unit/input/asyncify-sleep.wat b/binaryen/test/unit/input/asyncify-sleep.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/input/asyncify-sleep.wat
@@ -0,0 +1,200 @@
+(module
+  (memory 1 2)
+  (type $ii (func (param i32) (result i32)))
+  (import "env" "sleep" (func $sleep))
+  (import "env" "tunnel" (func $tunnel (param $x i32) (result i32)))
+  (export "memory" (memory 0))
+  (export "factorial-recursive" (func $factorial-recursive))
+  (global $temp (mut i32) (i32.const 0))
+  (table 10 funcref)
+  (elem (i32.const 5) $tablefunc)
+  (func "minimal" (result i32)
+    (call $sleep)
+    (i32.const 21)
+  )
+  (func "repeat" (result i32)
+    ;; sleep twice, then return 42
+    (call $sleep)
+    (call $sleep)
+    (i32.const 42)
+  )
+  (func "local" (result i32)
+    (local $x i32)
+    (local.set $x (i32.load (i32.const 0))) ;; a zero that the optimizer won't see
+    (local.set $x
+      (i32.add (local.get $x) (i32.const 10)) ;; add 10
+    )
+    (call $sleep)
+    (local.get $x)
+  )
+  (func "local2" (result i32)
+    (local $x i32)
+    (local.set $x (i32.load (i32.const 0))) ;; a zero that the optimizer won't see
+    (local.set $x
+      (i32.add (local.get $x) (i32.const 10)) ;; add 10
+    )
+    (call $sleep)
+    (local.set $x
+      (i32.add (local.get $x) (i32.const 12)) ;; add 12 more
+    )
+    (local.get $x)
+  )
+  (func "params" (param $x i32) (param $y i32) (result i32)
+    (local.set $x
+      (i32.add (local.get $x) (i32.const 17)) ;; add 10
+    )
+    (local.set $y
+      (i32.add (local.get $y) (i32.const 1)) ;; add 12 more
+    )
+    (call $sleep)
+    (i32.add (local.get $x) (local.get $y))
+  )
+  (func $pre
+    (global.set $temp (i32.const 1))
+  )
+  (func $inner (param $x i32)
+    (if (i32.eqz (local.get $x)) (call $post))
+    (if (local.get $x) (call $sleep))
+    (if (i32.eqz (local.get $x)) (call $post))
+  )
+  (func $post
+    (global.set $temp
+      (i32.mul
+        (global.get $temp)
+        (i32.const 3)
+      )
+    )
+  )
+  (func "deeper" (param $x i32) (result i32)
+    (call $pre)
+    (call $inner (local.get $x))
+    (call $post)
+    (global.get $temp)
+  )
+  (func $factorial-recursive (param $x i32) (result i32)
+    (if
+      (i32.eq
+        (local.get $x)
+        (i32.const 1)
+      )
+      (return (i32.const 1))
+    )
+    (call $sleep)
+    (return
+      (i32.mul
+        (local.get $x)
+        (call $factorial-recursive
+          (i32.sub
+            (local.get $x)
+            (i32.const 1)
+          )
+        )
+      )
+    )
+  )
+  (func "factorial-loop" (param $x i32) (result i32)
+    (local $i i32)
+    (local $ret i32)
+    (local.set $ret (i32.const 1))
+    (local.set $i (i32.const 2))
+    (loop $l
+      (if
+        (i32.gt_u
+          (local.get $i)
+          (local.get $x)
+        )
+        (return (local.get $ret))
+      )
+      (local.set $ret
+        (i32.mul
+          (local.get $ret)
+          (local.get $i)
+        )
+      )
+      (call $sleep)
+      (local.set $i
+        (i32.add
+          (local.get $i)
+          (i32.const 1)
+        )
+      )
+      (br $l)
+    )
+  )
+  (func "end_tunnel" (param $x i32) (result i32)
+    (local.set $x
+      (i32.add (local.get $x) (i32.const 22))
+    )
+    (call $sleep)
+    (i32.add (local.get $x) (i32.const 5))
+  )
+  (func "do_tunnel" (param $x i32) (result i32)
+    (local.set $x
+      (i32.add (local.get $x) (i32.const 11))
+    )
+    (local.set $x
+      (call $tunnel (local.get $x)) ;; calls js which calls back into wasm for end_tunnel
+    )
+    (call $sleep)
+    (i32.add (local.get $x) (i32.const 33))
+  )
+  (func $tablefunc (param $y i32) (result i32)
+    (local.set $y
+      (i32.add (local.get $y) (i32.const 10))
+    )
+    (call $sleep)
+    (i32.add (local.get $y) (i32.const 30))
+  )
+  (func "call_indirect" (param $x i32) (param $y i32) (result i32)
+    (local.set $x
+      (i32.add (local.get $x) (i32.const 1))
+    )
+    (call $sleep)
+    (local.set $x
+      (i32.add (local.get $x) (i32.const 3))
+    )
+    (local.set $y
+      (call_indirect (type $ii) (local.get $y) (local.get $x)) ;; call function pointer x + 4, which will be 5
+    )
+    (local.set $y
+      (i32.add (local.get $y) (i32.const 90))
+    )
+    (call $sleep)
+    (i32.add (local.get $y) (i32.const 300)) ;; total is 10+30+90+300=430 + y's original value
+  )
+  (func "if_else" (param $x i32) (param $y i32) (result i32)
+    (if (i32.eq (local.get $x) (i32.const 1))
+      (local.set $y
+        (i32.add (local.get $y) (i32.const 10))
+      )
+      (local.set $y
+        (i32.add (local.get $y) (i32.const 20))
+      )
+    )
+    (if (i32.eq (local.get $x) (i32.const 1))
+      (local.set $y
+        (i32.add (local.get $y) (i32.const 40))
+      )
+      (call $sleep)
+    )
+    (if (i32.eq (local.get $x) (i32.const 1))
+      (call $sleep)
+      (local.set $y
+        (i32.add (local.get $y) (i32.const 90))
+      )
+    )
+    (if (i32.eq (local.get $x) (i32.const 1))
+      (call $sleep)
+      (call $sleep)
+    )
+    (local.set $y
+      (i32.add (local.get $y) (i32.const 160))
+    )
+    (call $sleep)
+    (local.set $y
+      (i32.add (local.get $y) (i32.const 250))
+    )
+    (local.get $y)
+  )
+)
+
diff --git a/binaryen/test/unit/input/asyncify-stackOverflow.wat b/binaryen/test/unit/input/asyncify-stackOverflow.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/input/asyncify-stackOverflow.wat
@@ -0,0 +1,22 @@
+(module
+  (memory 1 2)
+  (import "env" "sleep" (func $sleep))
+  (export "memory" (memory 0))
+  (func "many_locals" (param $x i32) (result i32)
+    (local $y i32)
+    (local $z i32)
+    (local.set $y
+      (i32.add (local.get $x) (i32.const 10))
+    )
+    (local.set $z
+      (i32.add (local.get $y) (i32.const 20))
+    )
+    (call $sleep)
+    (select
+      (local.get $y)
+      (local.get $z)
+      (local.get $x)
+    )
+  )
+)
+
diff --git a/binaryen/test/unit/input/asyncify.js b/binaryen/test/unit/input/asyncify.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/input/asyncify.js
@@ -0,0 +1,304 @@
+
+function assert(x, y) {
+  if (!x) throw (y || 'assertion failed') + '\n' + new Error().stack;
+}
+
+var fs = require('fs');
+
+function sleepTests() {
+  console.log('\nsleep tests\n\n');
+
+  // Get and compile the wasm.
+
+  var binary = fs.readFileSync('a.wasm');
+
+  var module = new WebAssembly.Module(binary);
+
+  var DATA_ADDR = 4;
+
+  var sleeps = 0;
+
+  var sleeping = false;
+
+  var instance = new WebAssembly.Instance(module, {
+    env: {
+      sleep: function() {
+        logMemory();
+        if (!sleeping) {
+          // We are called in order to start a sleep/unwind.
+          console.log('sleep...');
+          sleeps++;
+          sleeping = true;
+          // Unwinding.
+          // Fill in the data structure. The first value has the stack location,
+          // which for simplicity we can start right after the data structure itself.
+          view[DATA_ADDR >> 2] = DATA_ADDR + 8;
+          // The end of the stack will not be reached here anyhow.
+          view[DATA_ADDR + 4 >> 2] = 1024;
+          exports.asyncify_start_unwind(DATA_ADDR);
+        } else {
+          // We are called as part of a resume/rewind. Stop sleeping.
+          console.log('resume...');
+          exports.asyncify_stop_rewind();
+          // The stack should have been all used up, and so returned to the original state.
+          assert(view[DATA_ADDR >> 2] == DATA_ADDR + 8);
+          assert(view[DATA_ADDR + 4 >> 2] == 1024);
+          sleeping = false;
+        }
+        logMemory();
+      },
+      tunnel: function(x) {
+        console.log('tunneling, sleep == ' + sleeping);
+        return exports.end_tunnel(x);
+      }
+    }
+  });
+
+  var exports = instance.exports;
+  var view = new Int32Array(exports.memory.buffer);
+
+  function logMemory() {
+    // Log the relevant memory locations for debugging purposes.
+    console.log('memory: ', view[0 >> 2], view[4 >> 2], view[8 >> 2], view[12 >> 2], view[16 >> 2], view[20 >> 2], view[24 >> 2]);
+  }
+
+  function runTest(name, expectedSleeps, expectedResult, params) {
+    params = params || [];
+
+    console.log('\n==== testing ' + name + ' ====');
+
+    sleeps = 0;
+
+    logMemory();
+
+    // Run until the sleep.
+    var result = exports[name].apply(null, params);
+    logMemory();
+
+    if (expectedSleeps > 0) {
+      assert(!result, 'results during sleep are meaningless, just 0');
+      exports.asyncify_stop_unwind();
+
+      for (var i = 0; i < expectedSleeps - 1; i++) {
+        console.log('rewind, run until the next sleep');
+        exports.asyncify_start_rewind(DATA_ADDR);
+        result = exports[name](); // no need for params on later times
+        assert(!result, 'results during sleep are meaningless, just 0');
+        logMemory();
+        exports.asyncify_stop_unwind();
+      }
+
+      console.log('rewind and run til the end.');
+      exports.asyncify_start_rewind(DATA_ADDR);
+      result = exports[name]();
+    }
+
+    console.log('final result: ' + result);
+    assert(result == expectedResult, 'bad final result');
+    logMemory();
+
+    assert(sleeps == expectedSleeps, 'expectedSleeps');
+  }
+
+  //================
+  // Tests
+  //================
+
+  // A minimal single sleep.
+  runTest('minimal', 1, 21);
+
+  // Two sleeps.
+  runTest('repeat', 2, 42);
+
+  // A value in a local is preserved across a sleep.
+  runTest('local', 1, 10);
+
+  // A local with more operations done on it.
+  runTest('local2', 1, 22);
+
+  // A local with more operations done on it.
+  runTest('params', 1, 18);
+  runTest('params', 1, 21, [1, 2]);
+
+  // Calls to multiple other functions, only one of whom
+  // sleeps, and keep locals and globals valid throughout.
+  runTest('deeper', 0, 27, [0]);
+  runTest('deeper', 1,  3, [1]);
+
+  // A recursive factorial, that sleeps on each iteration
+  // above 1.
+  runTest('factorial-recursive', 0,   1, [1]);
+  runTest('factorial-recursive', 1,   2, [2]);
+  runTest('factorial-recursive', 2,   6, [3]);
+  runTest('factorial-recursive', 3,  24, [4]);
+  runTest('factorial-recursive', 4, 120, [5]);
+
+  // A looping factorial, that sleeps on each iteration
+  // above 1.
+  runTest('factorial-loop', 0,   1, [1]);
+  runTest('factorial-loop', 1,   2, [2]);
+  runTest('factorial-loop', 2,   6, [3]);
+  runTest('factorial-loop', 3,  24, [4]);
+  runTest('factorial-loop', 4, 120, [5]);
+
+  // Test calling into JS in the middle (which can work if
+  // the JS just forwards the call and has no side effects or
+  // state of its own that needs to be saved).
+  runTest('do_tunnel', 2, 72, [1]);
+
+  // Test indirect function calls.
+  runTest('call_indirect', 3, 432, [1, 2]);
+
+  // Test indirect function calls.
+  runTest('if_else', 3, 1460, [1, 1000]);
+  runTest('if_else', 3, 2520, [2, 2000]);
+}
+
+function coroutineTests() {
+  console.log('\ncoroutine tests\n\n');
+
+  // Get and compile the wasm.
+
+  var binary = fs.readFileSync('b.wasm');
+
+  var module = new WebAssembly.Module(binary);
+
+  // Create a coroutine, for a specific export to
+  // call, and whose unwind/rewind data is in
+  // a specific range.
+  function Coroutine(name, dataStart, dataEnd) {
+    this.name = name;
+    this.start = function() {
+      exports[name]();
+    };
+    this.startUnwind = function() {
+      // Initialize the data.
+      view[dataStart >> 2] = dataStart + 8;
+      view[dataStart + 4 >> 2] = dataEnd;
+      exports.asyncify_start_unwind(dataStart);
+      // (With C etc. coroutines we would also have
+      // a C stack to pause and resume here.)
+    };
+    this.stopUnwind = function() {
+      exports.asyncify_stop_unwind();
+    };
+    this.startRewind = function() {
+      exports.asyncify_start_rewind(dataStart);
+      exports[name]();
+    };
+    this.stopRewind = function() {
+      exports.asyncify_stop_rewind();
+    };
+  }
+
+  var Runtime = {
+    coroutines: [
+      new Coroutine('linear',      1000, 2000),
+      new Coroutine('exponential', 2000, 3000),
+      new Coroutine('weird',       3000, 4000)
+    ],
+    active: null,
+    rewinding: false,
+    run: function(iters) {
+      Runtime.coroutines.forEach(function(coroutine) {
+        console.log('starting ' + coroutine.name);
+        Runtime.active = coroutine;
+        coroutine.start();
+        coroutine.stopUnwind();
+        Runtime.active = null;
+      });
+      for (var i = 0; i < iters; i++) {
+        Runtime.coroutines.forEach(function(coroutine) {
+          console.log('resuming ' + coroutine.name);
+          Runtime.active = coroutine;
+          Runtime.rewinding = true;
+          coroutine.startRewind();
+          Runtime.active = null;
+        });
+      }
+    },
+    values: [],
+    yield: function(value) {
+      console.log('yield reached', Runtime.rewinding, value); 
+      var coroutine = Runtime.active;
+      if (Runtime.rewinding) {
+        coroutine.stopRewind();
+        Runtime.rewinding = false;
+      } else {
+        Runtime.values.push(value);
+        coroutine.startUnwind();
+        console.log('pausing ' + coroutine.name);
+      }
+    },
+  };
+
+  var instance = new WebAssembly.Instance(module, {
+    env: {
+      yield: Runtime.yield
+    }
+  });
+
+  var exports = instance.exports;
+  var view = new Int32Array(exports.memory.buffer);
+
+  Runtime.run(4);
+  console.log(Runtime.values);
+  assert(JSON.stringify(Runtime.values) === JSON.stringify([
+     0,  1,    42,
+    10,  2,  1337,
+    20,  4,     0,
+    30,  8, -1000,
+    40, 16,    42
+  ]), 'check yielded values')
+}
+
+function stackOverflowAssertTests() {
+  console.log('\nstack overflow assertion tests\n\n');
+
+  // Get and compile the wasm.
+
+  var binary = fs.readFileSync('c.wasm');
+
+  var module = new WebAssembly.Module(binary);
+
+  var DATA_ADDR = 4;
+
+  var instance = new WebAssembly.Instance(module, {
+    env: {
+      sleep: function() {
+        console.log('sleep...');
+        exports.asyncify_start_unwind(DATA_ADDR);
+        view[DATA_ADDR >> 2] = DATA_ADDR + 8;
+        // The end of the stack will be reached as the stack is tiny.
+        view[DATA_ADDR + 4 >> 2] = view[DATA_ADDR >> 2] + 1;
+      }
+    }
+  });
+
+  var exports = instance.exports;
+  var view = new Int32Array(exports.memory.buffer);
+  exports.many_locals();
+  assert(view[DATA_ADDR >> 2] > view[DATA_ADDR + 4 >> 2], 'should have wrote past the end of the stack');
+  // All API calls should now fail, since we wrote past the end of the
+  // stack
+  var fails = 0;
+  ['asyncify_stop_unwind', 'asyncify_start_rewind', 'asyncify_stop_rewind', 'asyncify_start_unwind'].forEach(function(name) {
+    try {
+      exports[name](DATA_ADDR);
+      console.log('no fail on', name);
+    } catch (e) {
+      console.log('expected fail on', name);
+      fails++;
+    }
+  });
+  assert(fails == 4, 'all 4 should have failed');
+}
+
+// Main
+
+sleepTests();
+coroutineTests();
+stackOverflowAssertTests();
+
+console.log('\ntests completed successfully');
+
diff --git a/binaryen/test/unit/input/atomics_target_feature.wasm b/binaryen/test/unit/input/atomics_target_feature.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unit/input/atomics_target_feature.wasm differ
diff --git a/binaryen/test/unit/input/bulkmem_bad_datacount.wasm b/binaryen/test/unit/input/bulkmem_bad_datacount.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unit/input/bulkmem_bad_datacount.wasm differ
diff --git a/binaryen/test/unit/input/bulkmem_data.wasm b/binaryen/test/unit/input/bulkmem_data.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unit/input/bulkmem_data.wasm differ
diff --git a/binaryen/test/unit/input/bulkmem_target_feature.wasm b/binaryen/test/unit/input/bulkmem_target_feature.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unit/input/bulkmem_target_feature.wasm differ
diff --git a/binaryen/test/unit/input/dwarf/cubescript.wasm b/binaryen/test/unit/input/dwarf/cubescript.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unit/input/dwarf/cubescript.wasm differ
diff --git a/binaryen/test/unit/input/dwarf/zlib.wasm b/binaryen/test/unit/input/dwarf/zlib.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unit/input/dwarf/zlib.wasm differ
diff --git a/binaryen/test/unit/input/em_asm_mangled_string.wat b/binaryen/test/unit/input/em_asm_mangled_string.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/input/em_asm_mangled_string.wat
@@ -0,0 +1,11 @@
+(module
+ (import "env" "emscripten_asm_const_int" (func $emscripten_asm_const_int (param i32 i32 i32) (result i32)))
+ (global $global$0 (mut i32) (i32.const 66192))
+ (global $global$1 i32 (i32.const 652))
+ (export "__data_end" (global $global$1))
+ (export "main" (func $main))
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (drop (call $emscripten_asm_const_int (local.get $0) (i32.const 0) (i32.const 0)))
+  (i32.const 0)
+ )
+)
diff --git a/binaryen/test/unit/input/empty.wasm b/binaryen/test/unit/input/empty.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unit/input/empty.wasm differ
diff --git a/binaryen/test/unit/input/empty_lld.wat b/binaryen/test/unit/input/empty_lld.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/input/empty_lld.wat
@@ -0,0 +1,9 @@
+(module
+ (global $global$0 (mut i32) (i32.const 66192))
+ (global $global$1 i32 (i32.const 652))
+ (export "__data_end" (global $global$1))
+ (export "main" (func $main))
+ (func $main (param $0 i32) (param $1 i32) (result i32)
+  (i32.const 0)
+ )
+)
diff --git a/binaryen/test/unit/input/exception_handling_target_feature.wasm b/binaryen/test/unit/input/exception_handling_target_feature.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unit/input/exception_handling_target_feature.wasm differ
diff --git a/binaryen/test/unit/input/gc_target_feature.wasm b/binaryen/test/unit/input/gc_target_feature.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unit/input/gc_target_feature.wasm differ
diff --git a/binaryen/test/unit/input/mutable_globals_target_feature.wasm b/binaryen/test/unit/input/mutable_globals_target_feature.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unit/input/mutable_globals_target_feature.wasm differ
diff --git a/binaryen/test/unit/input/reference_types_target_feature.wasm b/binaryen/test/unit/input/reference_types_target_feature.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unit/input/reference_types_target_feature.wasm differ
diff --git a/binaryen/test/unit/input/signext_target_feature.wasm b/binaryen/test/unit/input/signext_target_feature.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unit/input/signext_target_feature.wasm differ
diff --git a/binaryen/test/unit/input/simd_target_feature.wasm b/binaryen/test/unit/input/simd_target_feature.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unit/input/simd_target_feature.wasm differ
diff --git a/binaryen/test/unit/input/stack_ir.wat b/binaryen/test/unit/input/stack_ir.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/input/stack_ir.wat
@@ -0,0 +1,12 @@
+(module
+  (import "env" "bar" (func $bar (param i32) (result i32)))
+  (func "foo1" (result i32)
+    (local $x i32)
+    (local.set $x (call $bar (i32.const 0)))
+    (drop
+     (call $bar (i32.const 1))
+    )
+    (local.get $x) ;; local2stack can help here
+  )
+)
+
diff --git a/binaryen/test/unit/input/tail_call_target_feature.wasm b/binaryen/test/unit/input/tail_call_target_feature.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unit/input/tail_call_target_feature.wasm differ
diff --git a/binaryen/test/unit/input/truncsat_target_feature.wasm b/binaryen/test/unit/input/truncsat_target_feature.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unit/input/truncsat_target_feature.wasm differ
diff --git a/binaryen/test/unit/input/update.sh b/binaryen/test/unit/input/update.sh
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/input/update.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# This file updates the target_feature tests in the rare but unfortunate case
+# that their roundtripped binary representations do not match the input anymore
+# due to otherwise unrelated binary format changes.
+
+WASM_OPT="../../../bin/wasm-opt" # edit when building out of tree
+
+$WASM_OPT atomics_target_feature.wasm --enable-threads -g --emit-target-features -o atomics_target_feature.wasm
+$WASM_OPT bulkmem_data.wasm --enable-bulk-memory -g --emit-target-features -o bulkmem_data.wasm
+$WASM_OPT bulkmem_target_feature.wasm --enable-bulk-memory -g --emit-target-features -o bulkmem_target_feature.wasm
+$WASM_OPT exception_handling_target_feature.wasm --enable-exception-handling --enable-reference-types -g --emit-target-features -o exception_handling_target_feature.wasm
+$WASM_OPT gc_target_feature.wasm --enable-reference-types --enable-gc -g --emit-target-features -o gc_target_feature.wasm
+$WASM_OPT mutable_globals_target_feature.wasm --enable-mutable-globals -g --emit-target-features -o mutable_globals_target_feature.wasm
+$WASM_OPT reference_types_target_feature.wasm --enable-reference-types -g --emit-target-features -o reference_types_target_feature.wasm
+$WASM_OPT signext_target_feature.wasm --enable-sign-ext -g --emit-target-features -o signext_target_feature.wasm
+$WASM_OPT simd_target_feature.wasm --enable-simd -g --emit-target-features -o simd_target_feature.wasm
+$WASM_OPT truncsat_target_feature.wasm --enable-nontrapping-float-to-int -g --emit-target-features -o truncsat_target_feature.wasm
+$WASM_OPT tail_call_target_feature.wasm --enable-tail-call -g --emit-target-features -o tail_call_target_feature.wasm
diff --git a/binaryen/test/unit/test_asyncify.py b/binaryen/test/unit/test_asyncify.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/test_asyncify.py
@@ -0,0 +1,89 @@
+import os
+import subprocess
+import tempfile
+
+from scripts.test import shared
+from . import utils
+
+
+class AsyncifyTest(utils.BinaryenTestCase):
+    def test_asyncify_js(self):
+        def test(args):
+            print(args)
+            shared.run_process(shared.WASM_OPT + args + [self.input_path('asyncify-sleep.wat'), '--asyncify', '-o', 'a.wasm'])
+            shared.run_process(shared.WASM_OPT + args + [self.input_path('asyncify-coroutine.wat'), '--asyncify', '-o', 'b.wasm'])
+            shared.run_process(shared.WASM_OPT + args + [self.input_path('asyncify-stackOverflow.wat'), '--asyncify', '-o', 'c.wasm'])
+            print('  file size: %d' % os.path.getsize('a.wasm'))
+            if shared.NODEJS:
+                shared.run_process([shared.NODEJS, self.input_path('asyncify.js')])
+
+        test(['-g'])
+        test([])
+        test(['-O1'])
+        test(['--optimize-level=1'])
+        test(['-O3'])
+        test(['-Os', '-g'])
+
+    def test_asyncify_pure_wasm(self):
+        def test(input_file):
+            shared.run_process(shared.WASM_OPT + [input_file, '--asyncify', '-o', 'a.wasm'])
+            shared.run_process(shared.WASM_DIS + ['a.wasm', '-o', 'a.wat'])
+            output = shared.run_process(shared.WASM_SHELL + ['a.wat'], capture_output=True).stdout
+            with open(self.input_path('asyncify-pure.txt'), 'r') as f:
+                self.assert_equal_ignoring_line_endings(f.read(), output)
+
+        # test wat input
+        wat = self.input_path('asyncify-pure.wat')
+        test(wat)
+
+        # test wasm input
+        shared.run_process(shared.WASM_AS + [wat, '-o', 'a.wasm'])
+        test('a.wasm')
+
+    def test_asyncify_list_bad(self):
+        for arg, warning in [
+            ('--pass-arg=asyncify-removelist@nonexistent', 'nonexistent'),
+            ('--pass-arg=asyncify-onlylist@nonexistent', 'nonexistent'),
+            ('--pass-arg=asyncify-removelist@main', None),
+            ('--pass-arg=asyncify-onlylist@main', None),
+            ('--pass-arg=asyncify-removelist@m*n', None),
+            ('--pass-arg=asyncify-onlylist@m*n', None),
+            ('--pass-arg=asyncify-onlylist@main*', None),
+            ('--pass-arg=asyncify-onlylist@*main', None),
+            ('--pass-arg=asyncify-removelist@non*existent', 'non*existent'),
+            ('--pass-arg=asyncify-onlylist@non*existent', 'non*existent'),
+            ('--pass-arg=asyncify-onlylist@DOS_ReadFile(unsigned short, unsigned char*, unsigned short*, bool)', None),
+        ]:
+            print(arg, warning)
+            err = shared.run_process(shared.WASM_OPT + ['-q', self.input_path('asyncify-pure.wat'), '--asyncify', arg], stdout=subprocess.PIPE, stderr=subprocess.PIPE).stderr.strip()
+            if warning:
+                self.assertIn('warning', err)
+                self.assertIn(warning, err)
+            else:
+                self.assertNotIn('warning', err)
+
+    def test_asyncify_onlylist_and_other(self):
+        def test(list_name):
+            args = shared.WASM_OPT + [self.input_path('asyncify-pure.wat'),
+                                      '--asyncify',
+                                      '--pass-arg=asyncify-onlylist@main',
+                                      '--pass-arg=asyncify-%slist@main' % list_name]
+            proc = shared.run_process(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False)
+            self.assertNotEqual(proc.returncode, 0, 'must error on using both lists at once')
+            self.assertIn('It makes no sense to use both an asyncify only-list together with another list', proc.stdout)
+
+        test('remove')
+        test('add')
+
+    def test_asyncify_imports(self):
+        def test(args):
+            return shared.run_process(shared.WASM_OPT + [self.input_path('asyncify-sleep.wat'), '--asyncify', '--print'] + args, stdout=subprocess.PIPE).stdout
+
+        normal = test(['--pass-arg=asyncify-imports@env.sleep'])
+        temp = tempfile.NamedTemporaryFile().name
+        with open(temp, 'w') as f:
+            f.write('env.sleep')
+        response = test(['--pass-arg=asyncify-imports@@%s' % temp])
+        self.assertEqual(normal, response)
+        without = test(['--pass-arg=asyncify-imports@without.anything'])
+        self.assertNotEqual(normal, without)
diff --git a/binaryen/test/unit/test_datacount.py b/binaryen/test/unit/test_datacount.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/test_datacount.py
@@ -0,0 +1,15 @@
+from scripts.test import shared
+from . import utils
+
+
+class DataCountTest(utils.BinaryenTestCase):
+    def test_datacount(self):
+        self.roundtrip('bulkmem_data.wasm')
+
+    def test_bad_datacount(self):
+        path = self.input_path('bulkmem_bad_datacount.wasm')
+        p = shared.run_process(shared.WASM_OPT + ['-g', '-o', '-', path],
+                               check=False, capture_output=True)
+        self.assertNotEqual(p.returncode, 0)
+        self.assertIn('Number of segments does not agree with DataCount section',
+                      p.stderr)
diff --git a/binaryen/test/unit/test_dwarf.py b/binaryen/test/unit/test_dwarf.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/test_dwarf.py
@@ -0,0 +1,16 @@
+import os
+
+from scripts.test import shared
+from . import utils
+
+
+class DWARFTest(utils.BinaryenTestCase):
+    def test_no_crash(self):
+        # run dwarf processing on some interesting large files, too big to be
+        # worth putting in passes where the text output would be massive. We
+        # just check that no assertion are hit.
+        path = self.input_path('dwarf')
+        for name in os.listdir(path):
+            args = [os.path.join(path, name)] + \
+                   ['-g', '--dwarfdump', '--roundtrip', '--dwarfdump']
+            shared.run_process(shared.WASM_OPT + args, capture_output=True)
diff --git a/binaryen/test/unit/test_errors.py b/binaryen/test/unit/test_errors.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/test_errors.py
@@ -0,0 +1,40 @@
+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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/test_features.py
@@ -0,0 +1,412 @@
+import os
+
+from scripts.test import shared
+from . import utils
+
+
+class FeatureValidationTest(utils.BinaryenTestCase):
+    def check_feature(self, module, error, flag, const_flags=[]):
+        p = shared.run_process(shared.WASM_OPT +
+                               ['--mvp-features', '--print', '-o', os.devnull] +
+                               const_flags,
+                               input=module, check=False, capture_output=True)
+        self.assertIn(error, p.stderr)
+        self.assertIn('Fatal: error validating input', p.stderr)
+        self.assertNotEqual(p.returncode, 0)
+        p = shared.run_process(
+            shared.WASM_OPT + ['--mvp-features', '--print', '-o', os.devnull] +
+            const_flags + [flag],
+            input=module,
+            check=False,
+            capture_output=True)
+        self.assertEqual(p.returncode, 0)
+
+    def check_simd(self, module, error):
+        self.check_feature(module, error, '--enable-simd')
+
+    def check_sign_ext(self, module, error):
+        self.check_feature(module, error, '--enable-sign-ext')
+
+    def check_bulk_mem(self, module, error):
+        self.check_feature(module, error, '--enable-bulk-memory')
+
+    def check_exception_handling(self, module, error):
+        # Exception handling implies reference types
+        self.check_feature(module, error, '--enable-exception-handling',
+                           ['--enable-reference-types'])
+
+    def check_tail_call(self, module, error):
+        self.check_feature(module, error, '--enable-tail-call')
+
+    def check_reference_types(self, module, error):
+        self.check_feature(module, error, '--enable-reference-types')
+
+    def check_multivalue(self, module, error):
+        self.check_feature(module, error, '--enable-multivalue')
+
+    def check_multivalue_exception_handling(self, module, error):
+        self.check_feature(module, error, '--enable-multivalue',
+                           ['--enable-exception-handling',
+                            '--enable-reference-types'])
+
+    def check_gc(self, module, error):
+        # GC implies reference types
+        self.check_feature(module, error, '--enable-gc',
+                           ['--enable-reference-types'])
+
+    def test_v128_signature(self):
+        module = '''
+        (module
+         (func $foo (param $0 v128) (result v128)
+            (local.get $0)
+         )
+        )
+        '''
+        self.check_simd(module, 'all used types should be allowed')
+
+    def test_v128_global(self):
+        module = '''
+        (module
+         (global $foo (mut v128) (v128.const i32x4 0 0 0 0))
+        )
+        '''
+        self.check_simd(module, 'all used types should be allowed')
+
+    def test_v128_local(self):
+        module = '''
+        (module
+         (func $foo
+            (local v128)
+         )
+        )
+        '''
+        self.check_simd(module, 'all used types should be allowed')
+
+    def test_simd_const(self):
+        module = '''
+        (module
+         (func $foo
+            (drop (v128.const i32x4 0 0 0 0))
+         )
+        )
+        '''
+        self.check_simd(module, 'all used features should be allowed')
+
+    def test_simd_load(self):
+        module = '''
+        (module
+         (memory 1 1)
+         (func $foo
+            (drop (v128.load (i32.const 0)))
+         )
+        )
+        '''
+        self.check_simd(module, 'SIMD operation (SIMD is disabled)')
+
+    def test_simd_splat(self):
+        module = '''
+        (module
+         (func $foo
+            (drop (i32x4.splat (i32.const 0)))
+         )
+        )
+        '''
+        self.check_simd(module, 'all used features should be allowed')
+
+    def test_sign_ext(self):
+        module = '''
+        (module
+         (func $foo
+            (drop (i32.extend8_s (i32.const 7)))
+         )
+        )
+        '''
+        self.check_sign_ext(module, 'all used features should be allowed')
+
+    def test_bulk_mem_inst(self):
+        module = '''
+        (module
+         (memory 1 1)
+         (func $foo
+            (memory.copy (i32.const 0) (i32.const 8) (i32.const 8))
+         )
+        )
+        '''
+        self.check_bulk_mem(module,
+                            'Bulk memory operation (bulk memory is disabled')
+
+    def test_bulk_mem_segment(self):
+        module = '''
+        (module
+         (memory 256 256)
+         (data passive "42")
+        )
+        '''
+        self.check_bulk_mem(module, 'nonzero segment flags (bulk memory is disabled)')
+
+    def test_tail_call(self):
+        module = '''
+        (module
+         (func $bar)
+         (func $foo
+            (return_call $bar)
+         )
+        )
+        '''
+        self.check_tail_call(module, 'return_call requires tail calls to be enabled')
+
+    def test_tail_call_indirect(self):
+        module = '''
+        (module
+         (type $T (func))
+         (table $0 1 1 funcref)
+         (func $foo
+            (return_call_indirect (type $T)
+             (i32.const 0)
+            )
+         )
+        )
+        '''
+        self.check_tail_call(module, 'return_call_indirect requires tail calls to be enabled')
+
+    def test_reference_types_externref(self):
+        module = '''
+        (module
+         (import "env" "test1" (func $test1 (param externref) (result externref)))
+         (import "env" "test2" (global $test2 externref))
+         (export "test1" (func $test1 (param externref) (result externref)))
+         (export "test2" (global $test2))
+         (func $externref_test (param $0 externref) (result externref)
+          (return
+           (call $test1
+            (local.get $0)
+           )
+          )
+         )
+        )
+        '''
+        self.check_reference_types(module, 'all used types should be allowed')
+
+    def test_exnref_local(self):
+        module = '''
+        (module
+         (func $foo
+            (local exnref)
+         )
+        )
+        '''
+        self.check_exception_handling(module, 'all used types should be allowed')
+
+    def test_event(self):
+        module = '''
+        (module
+         (event $e (attr 0) (param i32))
+         (func $foo
+            (throw $e (i32.const 0))
+         )
+        )
+        '''
+        self.check_exception_handling(module, 'Module has events')
+
+    def test_multivalue_import(self):
+        module = '''
+        (module
+         (import "env" "foo" (func $foo (result i32 i64)))
+        )
+        '''
+        self.check_multivalue(module, 'Imported multivalue function ' +
+                              '(multivalue is not enabled)')
+
+    def test_multivalue_function(self):
+        module = '''
+        (module
+         (func $foo (result i32 i64)
+          (tuple.make
+           (i32.const 42)
+           (i64.const 42)
+          )
+         )
+        )
+        '''
+        self.check_multivalue(module, 'Multivalue function results ' +
+                              '(multivalue is not enabled)')
+
+    def test_multivalue_event(self):
+        module = '''
+        (module
+         (event $foo (attr 0) (param i32 i64))
+        )
+        '''
+        self.check_multivalue_exception_handling(module, 'Multivalue event type ' +
+                                                 '(multivalue is not enabled)')
+
+    def test_multivalue_block(self):
+        module = '''
+        (module
+         (func $foo
+          (drop
+           (block (result i32 i64)
+            (tuple.make
+             (i32.const 42)
+             (i64.const 42)
+            )
+           )
+          )
+         )
+        )
+        '''
+        self.check_multivalue(module, 'Multivalue block type ' +
+                              '(multivalue is not enabled)')
+
+    def test_anyref_global(self):
+        module = '''
+        (module
+         (global $foo anyref (ref.null any))
+        )
+        '''
+        self.check_gc(module, 'all used types should be allowed')
+
+    def test_anyref_local(self):
+        module = '''
+        (module
+         (func $foo
+          (local $0 anyref)
+         )
+        )
+        '''
+        self.check_gc(module, 'all used types should be allowed')
+
+    def test_eqref_global(self):
+        module = '''
+        (module
+         (global $foo eqref (ref.null eq))
+        )
+        '''
+        self.check_gc(module, 'all used types should be allowed')
+
+    def test_eqref_local(self):
+        module = '''
+        (module
+         (func $foo
+          (local $0 eqref)
+         )
+        )
+        '''
+        self.check_gc(module, 'all used types should be allowed')
+
+
+class TargetFeaturesSectionTest(utils.BinaryenTestCase):
+    def test_atomics(self):
+        filename = 'atomics_target_feature.wasm'
+        self.roundtrip(filename)
+        self.check_features(filename, ['threads'])
+        self.assertIn('i32.atomic.rmw.add', self.disassemble(filename))
+
+    def test_bulk_memory(self):
+        filename = 'bulkmem_target_feature.wasm'
+        self.roundtrip(filename)
+        self.check_features(filename, ['bulk-memory'])
+        self.assertIn('memory.copy', self.disassemble(filename))
+
+    def test_nontrapping_fptoint(self):
+        filename = 'truncsat_target_feature.wasm'
+        self.roundtrip(filename)
+        self.check_features(filename, ['nontrapping-float-to-int'])
+        self.assertIn('i32.trunc_sat_f32_u', self.disassemble(filename))
+
+    def test_mutable_globals(self):
+        filename = 'mutable_globals_target_feature.wasm'
+        self.roundtrip(filename)
+        self.check_features(filename, ['mutable-globals'])
+        self.assertIn('(import "env" "global-mut" (global $gimport$0 (mut i32)))',
+                      self.disassemble(filename))
+
+    def test_sign_ext(self):
+        filename = 'signext_target_feature.wasm'
+        self.roundtrip(filename)
+        self.check_features(filename, ['sign-ext'])
+        self.assertIn('i32.extend8_s', self.disassemble(filename))
+
+    def test_simd(self):
+        filename = 'simd_target_feature.wasm'
+        self.roundtrip(filename)
+        self.check_features(filename, ['simd'])
+        self.assertIn('i32x4.splat', self.disassemble(filename))
+
+    def test_tailcall(self):
+        filename = 'tail_call_target_feature.wasm'
+        self.roundtrip(filename)
+        self.check_features(filename, ['tail-call'])
+        self.assertIn('return_call', self.disassemble(filename))
+
+    def test_reference_types(self):
+        filename = 'reference_types_target_feature.wasm'
+        self.roundtrip(filename)
+        self.check_features(filename, ['reference-types'])
+        self.assertIn('externref', self.disassemble(filename))
+
+    def test_exception_handling(self):
+        filename = 'exception_handling_target_feature.wasm'
+        self.roundtrip(filename)
+        self.check_features(filename, ['exception-handling', 'reference-types'])
+        self.assertIn('throw', self.disassemble(filename))
+
+    def test_gc(self):
+        filename = 'gc_target_feature.wasm'
+        self.roundtrip(filename)
+        self.check_features(filename, ['reference-types', 'gc'])
+        disassembly = self.disassemble(filename)
+        self.assertIn('anyref', disassembly)
+        self.assertIn('eqref', disassembly)
+
+    def test_incompatible_features(self):
+        path = self.input_path('signext_target_feature.wasm')
+        p = shared.run_process(
+            shared.WASM_OPT + ['--print', '--enable-simd', '-o', os.devnull,
+                               path],
+            check=False, capture_output=True
+        )
+        self.assertNotEqual(p.returncode, 0)
+        self.assertIn('Fatal: module features do not match specified features. ' +
+                      'Use --detect-features to resolve.',
+                      p.stderr)
+
+    def test_incompatible_features_forced(self):
+        path = self.input_path('signext_target_feature.wasm')
+        p = shared.run_process(
+            shared.WASM_OPT + ['--print', '--detect-features', '-mvp',
+                               '--enable-simd', '-o', os.devnull, path],
+            check=False, capture_output=True
+        )
+        self.assertNotEqual(p.returncode, 0)
+        self.assertIn('all used features should be allowed', p.stderr)
+
+    def test_explicit_detect_features(self):
+        self.check_features('signext_target_feature.wasm', ['simd', 'sign-ext'],
+                            opts=['-mvp', '--detect-features', '--enable-simd'])
+
+    def test_emit_all_features(self):
+        p = shared.run_process(shared.WASM_OPT +
+                               ['--emit-target-features', '-all', '-o', '-'],
+                               input="(module)", check=False,
+                               capture_output=True, decode_output=False)
+        self.assertEqual(p.returncode, 0)
+        p2 = shared.run_process(shared.WASM_OPT +
+                                ['--print-features', '-o', os.devnull],
+                                input=p.stdout, check=False,
+                                capture_output=True)
+        self.assertEqual(p2.returncode, 0)
+        self.assertEqual([
+            '--enable-threads',
+            '--enable-mutable-globals',
+            '--enable-nontrapping-float-to-int',
+            '--enable-simd',
+            '--enable-bulk-memory',
+            '--enable-sign-ext',
+            '--enable-exception-handling',
+            '--enable-tail-call',
+            '--enable-reference-types',
+            '--enable-multivalue',
+            '--enable-gc',
+            '--enable-memory64'
+        ], p2.stdout.splitlines())
diff --git a/binaryen/test/unit/test_finalize.py b/binaryen/test/unit/test_finalize.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/test_finalize.py
@@ -0,0 +1,35 @@
+import os
+
+from scripts.test import shared
+from . import utils
+
+
+class EmscriptenFinalizeTest(utils.BinaryenTestCase):
+    def test_em_asm_mangled_string(self):
+        p = shared.run_process(shared.WASM_EMSCRIPTEN_FINALIZE + [
+            self.input_path('em_asm_mangled_string.wat'), '-o', os.devnull, '--global-base=1024'
+        ], check=False, capture_output=True)
+        self.assertNotEqual(p.returncode, 0)
+        self.assertIn('Fatal: local.get of unknown in arg0 of call to emscripten_asm_const_int (used by EM_ASM* macros) in function main.', p.stderr)
+        self.assertIn('This might be caused by aggressive compiler transformations. Consider using EM_JS instead.', p.stderr)
+
+    def do_output_test(self, args):
+        # without any output file specified, don't error, don't write the wasm,
+        # but do emit metadata
+        p = shared.run_process(shared.WASM_EMSCRIPTEN_FINALIZE + [
+            self.input_path('empty_lld.wat'), '--global-base=1024'
+        ] + args, capture_output=True)
+        # metadata is always present
+        self.assertIn('{', p.stdout)
+        self.assertIn('}', p.stdout)
+        return p.stdout
+
+    def test_no_output(self):
+        stdout = self.do_output_test([])
+        # module is not present
+        self.assertNotIn('(module', stdout)
+
+    def test_text_output(self):
+        stdout = self.do_output_test(['-S'])
+        # module is present
+        self.assertIn('(module', stdout)
diff --git a/binaryen/test/unit/test_memory_packing.py b/binaryen/test/unit/test_memory_packing.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/test_memory_packing.py
@@ -0,0 +1,41 @@
+import os
+
+from scripts.test import shared
+from . import utils
+
+"""Test that MemoryPacking correctly respects the web limitations by not
+generating more than 100K data segments"""
+
+
+class MemoryPackingTest(utils.BinaryenTestCase):
+    def test_large_segment(self):
+        data = '"' + (('A' + ('\\00' * 9)) * 100001) + '"'
+        module = '''
+        (module
+         (memory 256 256)
+         (data (i32.const 0) %s)
+        )
+        ''' % data
+        opts = ['--memory-packing', '--disable-bulk-memory', '--print',
+                '-o', os.devnull]
+        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")'
+        ]
+        self.assertEqual(p.returncode, 0)
+        for line in output:
+            self.assertIn(line, p.stdout)
+
+    def test_large_segment_unmergeable(self):
+        data = '\n'.join('(data (i32.const %i) "A")' % i for i in range(100001))
+        module = '(module (memory 256 256) %s)' % data
+        opts = ['--memory-packing', '--enable-bulk-memory', '--print',
+                '-o', os.devnull]
+        p = shared.run_process(shared.WASM_OPT + opts, input=module,
+                               check=False, capture_output=True)
+        self.assertEqual(p.returncode, 0)
+        self.assertIn('Some VMs may not accept this binary', p.stderr)
+        self.assertIn('Run the limit-segments pass to merge segments.', p.stderr)
diff --git a/binaryen/test/unit/test_poppy_validation.py b/binaryen/test/unit/test_poppy_validation.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/test_poppy_validation.py
@@ -0,0 +1,203 @@
+import os
+
+from scripts.test import shared
+from . import utils
+
+
+class PoppyValidationTest(utils.BinaryenTestCase):
+    def check_invalid(self, module, error):
+        p = shared.run_process(shared.WASM_OPT +
+                               ['--experimental-poppy', '--print', '-o', os.devnull],
+                               input=module, check=False, capture_output=True)
+        self.assertIn(error, p.stderr)
+        self.assertIn('Fatal: error validating input', p.stderr)
+        self.assertNotEqual(p.returncode, 0)
+
+    def check_valid(self, module):
+        p = shared.run_process(shared.WASM_OPT +
+                               ['--experimental-poppy', '--print', '-o', os.devnull],
+                               input=module, check=False, capture_output=True)
+        self.assertEqual(p.stderr, "")
+        self.assertEqual(p.returncode, 0)
+
+    def test_top_level_pop(self):
+        module = '''
+        (module
+          (func $foo (result i32)
+            (block (result i32)
+              (i32.const 0)
+              (pop i32)
+            )
+          )
+        )
+        '''
+        self.check_invalid(module, "Unexpected top-level pop in block")
+
+    def test_top_level_pop_fixed(self):
+        module = '''
+        (module
+          (func $foo (result i32)
+            (block (result i32)
+              (i32.const 0)
+            )
+          )
+        )
+        '''
+        self.check_valid(module)
+
+    def test_incompatible_type(self):
+        module = '''
+        (module
+          (func $foo (result i32)
+            (f32.const 42)
+            (i32.const 42)
+            (i32.add
+              (pop i32)
+              (pop i32)
+            )
+          )
+        )
+        '''
+        self.check_invalid(module, "block element has incompatible type")
+        self.check_invalid(module, "required: (i32 i32), available: (f32 i32)")
+
+    def test_incorrect_pop_type(self):
+        module = '''
+        (module
+          (func $foo (result i32)
+            (i32.const 42)
+            (i32.const 42)
+            (i32.add
+              (pop i32)
+              (pop f32)
+            )
+          )
+        )
+        '''
+        self.check_invalid(module, "binary child types must be equal")
+
+    def test_incompatible_type_fixed(self):
+        module = '''
+        (module
+          (func $foo (result i32)
+            (i32.const 42)
+            (i32.const 42)
+            (i32.add
+              (pop i32)
+              (pop i32)
+            )
+          )
+        )
+        '''
+        self.check_valid(module)
+
+    def test_incorrect_block_type(self):
+        module = '''
+        (module
+          (func $foo (result i32)
+            (f32.const 42)
+            (nop)
+          )
+        )
+        '''
+        self.check_invalid(module, "block contents should satisfy block type")
+
+    def test_nonblock_body(self):
+        module = '''
+        (module
+          (func $foo (result f32)
+            (f32.const 42)
+          )
+        )
+        '''
+        self.check_invalid(module, "Function body must be a block")
+
+    def test_nonpop_if_condition(self):
+        module = '''
+        (module
+          (func $foo
+            (nop)
+            (i32.const 1)
+            (if
+              (i32.const 42)
+              (block)
+            )
+          )
+        )
+        '''
+        self.check_invalid(module, "Expected condition to be a Pop")
+
+    def test_nonblock_if_true(self):
+        module = '''
+        (module
+          (func $foo
+            (nop)
+            (i32.const 1)
+            (if
+              (pop i32)
+              (nop)
+            )
+          )
+        )
+        '''
+        self.check_invalid(module, "Expected control flow child to be a block")
+
+    def test_nonblock_if_false(self):
+        module = '''
+        (module
+          (func $foo
+            (nop)
+            (i32.const 1)
+            (if
+              (pop i32)
+              (block)
+              (nop)
+            )
+          )
+        )
+        '''
+        self.check_invalid(module, "Expected control flow child to be a block")
+
+    def test_nonblock_if_fixed(self):
+        module = '''
+        (module
+          (func $foo
+            (nop)
+            (i32.const 1)
+            (if
+              (pop i32)
+              (block)
+              (block)
+            )
+          )
+        )
+        '''
+        self.check_valid(module)
+
+    def test_nonblock_loop_body(self):
+        module = '''
+        (module
+          (func $foo
+            (nop)
+            (loop
+              (nop)
+            )
+          )
+        )
+        '''
+        self.check_invalid(module, "Expected control flow child to be a block")
+
+    def test_nonpop_child(self):
+        module = '''
+        (module
+          (func $foo (result i32)
+            (i32.const 42)
+            (i32.const 5)
+            (i32.add
+              (pop i32)
+              (i32.const -1)
+            )
+          )
+        )
+        '''
+        self.check_invalid(module, "Unexpected non-Pop child")
diff --git a/binaryen/test/unit/test_stack_ir.py b/binaryen/test/unit/test_stack_ir.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/test_stack_ir.py
@@ -0,0 +1,19 @@
+import os
+from scripts.test import shared
+from . import utils
+
+
+class StackIRTest(utils.BinaryenTestCase):
+    # test that stack IR opts make a difference.
+    def test_stack_ir_opts(self):
+        path = self.input_path('stack_ir.wat')
+        opt = shared.run_process(shared.WASM_OPT + [path, '-O', '--generate-stack-ir', '--optimize-stack-ir', '--print-stack-ir', '-o', 'a.wasm'], capture_output=True).stdout
+        nonopt = shared.run_process(shared.WASM_OPT + [path, '-O', '--generate-stack-ir', '--print-stack-ir', '-o', 'b.wasm'], capture_output=True).stdout
+        # see a difference in the printed stack IR (the optimizations let us
+        # remove a pair of local.set/get)
+        self.assertNotEqual(opt, nonopt)
+        self.assertLess(len(opt), len(nonopt))
+        # see a difference in the actual emitted wasm binary.
+        opt_size = os.path.getsize('a.wasm')
+        nonopt_size = os.path.getsize('b.wasm')
+        self.assertLess(opt_size, nonopt_size)
diff --git a/binaryen/test/unit/test_tail_call_type.py b/binaryen/test/unit/test_tail_call_type.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/test_tail_call_type.py
@@ -0,0 +1,45 @@
+import os
+
+from scripts.test import shared
+from . import utils
+
+
+class TailCallTypeTest(utils.BinaryenTestCase):
+    def test_return_call(self):
+        module = '''
+    (module
+     (func $foo (result f32)
+      (return_call $bar)
+     )
+     (func $bar (result i32)
+      (i32.const 1)
+     )
+    )
+'''
+        p = shared.run_process(shared.WASM_OPT +
+                               ['--enable-tail-call', '-o', os.devnull],
+                               input=module, check=False, capture_output=True)
+        self.assertNotEqual(p.returncode, 0)
+        self.assertIn(
+            'return_call callee return type must match caller return type',
+            p.stderr)
+
+    def test_return_call_indirect(self):
+        module = '''
+    (module
+     (type $T (func (result i32)))
+     (table $0 1 1 funcref)
+     (func $foo (result f32)
+      (return_call_indirect (type $T)
+       (i32.const 0)
+      )
+     )
+    )
+'''
+        p = shared.run_process(shared.WASM_OPT +
+                               ['--enable-tail-call', '-o', os.devnull],
+                               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',
+            p.stderr)
diff --git a/binaryen/test/unit/test_warnings.py b/binaryen/test/unit/test_warnings.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/test_warnings.py
@@ -0,0 +1,18 @@
+import subprocess
+
+from scripts.test import shared
+from . import utils
+
+
+class WarningsText(utils.BinaryenTestCase):
+    def test_warn_on_no_passes(self):
+        err = shared.run_process(shared.WASM_OPT + [self.input_path('asyncify-pure.wat'), '-o', 'a.wasm'], stderr=subprocess.PIPE).stderr
+        self.assertIn('warning: no passes specified, not doing any work', err)
+
+    def test_warn_on_no_output(self):
+        err = shared.run_process(shared.WASM_OPT + [self.input_path('asyncify-pure.wat'), '-O1'], stderr=subprocess.PIPE).stderr
+        self.assertIn('warning: no output file specified, not emitting output', err)
+
+    def test_quiet_suppresses_warnings(self):
+        err = shared.run_process(shared.WASM_OPT + [self.input_path('asyncify-pure.wat'), '-q'], stderr=subprocess.PIPE).stderr
+        self.assertNotIn('warning', err)
diff --git a/binaryen/test/unit/test_wasm2c.py b/binaryen/test/unit/test_wasm2c.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/test_wasm2c.py
@@ -0,0 +1,21 @@
+from scripts.test import shared
+from . import utils
+
+
+class Wasm2CTest(utils.BinaryenTestCase):
+    def test_wrapper(self):
+        # the wrapper C code should only call the hang limit initializer if
+        # that is present.
+        empty_wasm = self.input_path('empty.wasm')
+        args = [empty_wasm, '--emit-wasm2c-wrapper=output.c']
+        shared.run_process(shared.WASM_OPT + args)
+        with open('output.c') as f:
+            normal_output = f.read()
+        # running with ttf generates a new wasm for fuzzing, which always
+        # includes the hang limit initializer function
+        shared.run_process(shared.WASM_OPT + args + ['-ttf'])
+        with open('output.c') as f:
+            ttf_output = f.read()
+        hang_limit_name = 'hangLimitInitializer'
+        self.assertIn(hang_limit_name, ttf_output)
+        self.assertNotIn(hang_limit_name, normal_output)
diff --git a/binaryen/test/unit/utils.py b/binaryen/test/unit/utils.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/utils.py
@@ -0,0 +1,45 @@
+import os
+import unittest
+
+from scripts.test import shared
+
+
+class BinaryenTestCase(unittest.TestCase):
+    def input_path(self, filename):
+        return os.path.join(shared.options.binaryen_test, 'unit', 'input',
+                            filename)
+
+    def roundtrip(self, filename, opts=[]):
+        path = self.input_path(filename)
+        p = shared.run_process(shared.WASM_OPT + ['-g', '-o', 'a.wasm', path] +
+                               opts)
+        self.assertEqual(p.returncode, 0)
+        with open(path, 'rb') as f:
+            with open('a.wasm', 'rb') as g:
+                self.assertEqual(g.read(), f.read())
+
+    def disassemble(self, filename):
+        path = self.input_path(filename)
+        p = shared.run_process(shared.WASM_OPT +
+                               ['--print', '-o', os.devnull, path],
+                               check=False, capture_output=True)
+        self.assertEqual(p.returncode, 0)
+        self.assertEqual(p.stderr, '')
+        return p.stdout
+
+    def check_features(self, filename, features, opts=[]):
+        path = self.input_path(filename)
+        cmd = shared.WASM_OPT + \
+            ['--print-features', '-o', os.devnull, path] + opts
+        p = shared.run_process(cmd, check=False, capture_output=True)
+        self.assertEqual(p.returncode, 0)
+        self.assertEqual(p.stderr, '')
+        self.assertEqual(p.stdout.splitlines(),
+                         ['--enable-' + f for f in features])
+
+    # similar to assertEqual, but while ignoring line ending differences such
+    # as those between windows and unix
+    def assert_equal_ignoring_line_endings(self, left, right):
+        left = left.replace('\r\n', '\n')
+        right = right.replace('\r\n', '\n')
+        self.assertEqual(left, right)
diff --git a/binaryen/test/unreachable-code.wast b/binaryen/test/unreachable-code.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unreachable-code.wast
@@ -0,0 +1,85 @@
+(module
+  (func $a
+    (if (i32.const 1)
+      (unreachable)
+    )
+  )
+  (func $b
+    (if (i32.const 1)
+      (unreachable)
+      (unreachable)
+    )
+  )
+  (func $a-block
+    (block
+      (if (i32.const 1)
+        (unreachable)
+      )
+    )
+  )
+  (func $b-block
+    (block
+      (if (i32.const 1)
+        (unreachable)
+        (unreachable)
+      )
+    )
+  )
+  (func $a-prepost
+    (nop)
+    (if (i32.const 1)
+      (unreachable)
+    )
+    (nop)
+  )
+  (func $b-prepost
+    (nop)
+    (if (i32.const 1)
+      (unreachable)
+      (unreachable)
+    )
+    (nop)
+  )
+  (func $a-block-prepost
+    (nop)
+    (block
+      (if (i32.const 1)
+        (unreachable)
+      )
+    )
+    (nop)
+  )
+  (func $b-block-prepost
+    (nop)
+    (block
+      (if (i32.const 1)
+        (unreachable)
+        (unreachable)
+      )
+    )
+    (nop)
+  )
+  (func $recurse
+    (block $a
+      (nop)
+      (block $b
+        (nop)
+        (br $b)
+        (nop)
+      )
+      (nop)
+    )
+  )
+  (func $recurse-b
+    (block $a
+      (nop)
+      (block $b
+        (nop)
+        (br $a)
+        (nop)
+      )
+      (nop)
+    )
+  )
+)
+
diff --git a/binaryen/test/unreachable-code.wast.from-wast b/binaryen/test/unreachable-code.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unreachable-code.wast.from-wast
@@ -0,0 +1,93 @@
+(module
+ (type $none_=>_none (func))
+ (func $a
+  (if
+   (i32.const 1)
+   (unreachable)
+  )
+ )
+ (func $b
+  (if
+   (i32.const 1)
+   (unreachable)
+   (unreachable)
+  )
+ )
+ (func $a-block
+  (block $block
+   (if
+    (i32.const 1)
+    (unreachable)
+   )
+  )
+ )
+ (func $b-block
+  (block $block
+   (if
+    (i32.const 1)
+    (unreachable)
+    (unreachable)
+   )
+  )
+ )
+ (func $a-prepost
+  (nop)
+  (if
+   (i32.const 1)
+   (unreachable)
+  )
+  (nop)
+ )
+ (func $b-prepost
+  (nop)
+  (if
+   (i32.const 1)
+   (unreachable)
+   (unreachable)
+  )
+  (nop)
+ )
+ (func $a-block-prepost
+  (nop)
+  (block $block
+   (if
+    (i32.const 1)
+    (unreachable)
+   )
+  )
+  (nop)
+ )
+ (func $b-block-prepost
+  (nop)
+  (block $block
+   (if
+    (i32.const 1)
+    (unreachable)
+    (unreachable)
+   )
+  )
+  (nop)
+ )
+ (func $recurse
+  (block $a
+   (nop)
+   (block $b
+    (nop)
+    (br $b)
+    (nop)
+   )
+   (nop)
+  )
+ )
+ (func $recurse-b
+  (block $a
+   (nop)
+   (block $b
+    (nop)
+    (br $a)
+    (nop)
+   )
+   (nop)
+  )
+ )
+)
diff --git a/binaryen/test/unreachable-code.wast.fromBinary b/binaryen/test/unreachable-code.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unreachable-code.wast.fromBinary
@@ -0,0 +1,83 @@
+(module
+ (type $none_=>_none (func))
+ (func $a
+  (if
+   (i32.const 1)
+   (unreachable)
+  )
+ )
+ (func $b
+  (if
+   (i32.const 1)
+   (unreachable)
+   (unreachable)
+  )
+ )
+ (func $a-block
+  (if
+   (i32.const 1)
+   (unreachable)
+  )
+ )
+ (func $b-block
+  (if
+   (i32.const 1)
+   (unreachable)
+   (unreachable)
+  )
+ )
+ (func $a-prepost
+  (nop)
+  (if
+   (i32.const 1)
+   (unreachable)
+  )
+  (nop)
+ )
+ (func $b-prepost
+  (nop)
+  (if
+   (i32.const 1)
+   (unreachable)
+   (unreachable)
+  )
+ )
+ (func $a-block-prepost
+  (nop)
+  (block $label$1
+   (if
+    (i32.const 1)
+    (unreachable)
+   )
+  )
+  (nop)
+ )
+ (func $b-block-prepost
+  (nop)
+  (block $label$1
+   (if
+    (i32.const 1)
+    (unreachable)
+    (unreachable)
+   )
+  )
+ )
+ (func $recurse
+  (nop)
+  (block $label$1
+   (nop)
+   (br $label$1)
+  )
+  (nop)
+ )
+ (func $recurse-b
+  (block $label$1
+   (nop)
+   (block $label$2
+    (nop)
+    (br $label$1)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/unreachable-code.wast.fromBinary.noDebugInfo b/binaryen/test/unreachable-code.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unreachable-code.wast.fromBinary.noDebugInfo
@@ -0,0 +1,83 @@
+(module
+ (type $none_=>_none (func))
+ (func $0
+  (if
+   (i32.const 1)
+   (unreachable)
+  )
+ )
+ (func $1
+  (if
+   (i32.const 1)
+   (unreachable)
+   (unreachable)
+  )
+ )
+ (func $2
+  (if
+   (i32.const 1)
+   (unreachable)
+  )
+ )
+ (func $3
+  (if
+   (i32.const 1)
+   (unreachable)
+   (unreachable)
+  )
+ )
+ (func $4
+  (nop)
+  (if
+   (i32.const 1)
+   (unreachable)
+  )
+  (nop)
+ )
+ (func $5
+  (nop)
+  (if
+   (i32.const 1)
+   (unreachable)
+   (unreachable)
+  )
+ )
+ (func $6
+  (nop)
+  (block $label$1
+   (if
+    (i32.const 1)
+    (unreachable)
+   )
+  )
+  (nop)
+ )
+ (func $7
+  (nop)
+  (block $label$1
+   (if
+    (i32.const 1)
+    (unreachable)
+    (unreachable)
+   )
+  )
+ )
+ (func $8
+  (nop)
+  (block $label$1
+   (nop)
+   (br $label$1)
+  )
+  (nop)
+ )
+ (func $9
+  (block $label$1
+   (nop)
+   (block $label$2
+    (nop)
+    (br $label$1)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/unreachable-import_wasm-only.asm.js b/binaryen/test/unreachable-import_wasm-only.asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unreachable-import_wasm-only.asm.js
@@ -0,0 +1,107 @@
+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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unreachable-instr-type.wast
@@ -0,0 +1,28 @@
+(module
+  (memory (shared 1 1))
+  (func $test
+    (f32.load (unreachable))
+
+    (f32.store
+      (unreachable)
+      (f32.const 0)
+    )
+
+    (i64.atomic.rmw.add
+      (unreachable)
+      (i64.const 0)
+    )
+
+    (i64.atomic.rmw.cmpxchg
+      (unreachable)
+      (i64.const 0)
+      (i64.const 1)
+    )
+
+    (i64.atomic.wait
+      (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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unreachable-instr-type.wast.from-wast
@@ -0,0 +1,27 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 (shared 1 1))
+ (func $test
+  (i32.load
+   (unreachable)
+  )
+  (f32.store
+   (unreachable)
+   (f32.const 0)
+  )
+  (i32.atomic.rmw.add
+   (unreachable)
+   (i64.const 0)
+  )
+  (i32.atomic.rmw.cmpxchg
+   (unreachable)
+   (i64.const 0)
+   (i64.const 1)
+  )
+  (i64.atomic.wait
+   (unreachable)
+   (i64.const 0)
+   (i64.const 0)
+  )
+ )
+)
diff --git a/binaryen/test/unreachable-instr-type.wast.fromBinary b/binaryen/test/unreachable-instr-type.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unreachable-instr-type.wast.fromBinary
@@ -0,0 +1,8 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 (shared 1 1))
+ (func $test
+  (unreachable)
+ )
+)
+
diff --git a/binaryen/test/unreachable-instr-type.wast.fromBinary.noDebugInfo b/binaryen/test/unreachable-instr-type.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unreachable-instr-type.wast.fromBinary.noDebugInfo
@@ -0,0 +1,8 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 (shared 1 1))
+ (func $0
+  (unreachable)
+ )
+)
+
diff --git a/binaryen/test/unreachable-pops.wasm b/binaryen/test/unreachable-pops.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/unreachable-pops.wasm differ
diff --git a/binaryen/test/unreachable-pops.wasm.fromBinary b/binaryen/test/unreachable-pops.wasm.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unreachable-pops.wasm.fromBinary
@@ -0,0 +1,9 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (func $0 (result i32)
+  (block $label$1 (result i32)
+   (unreachable)
+  )
+ )
+)
+
diff --git a/binaryen/test/untaken-br_if.wast b/binaryen/test/untaken-br_if.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/untaken-br_if.wast
@@ -0,0 +1,14 @@
+(module
+ (func $binaryify-untaken-br_if (result f32)
+  (if (result f32)
+   (i32.const 1)
+   (unreachable)
+   (block $label$1 (result f32)
+    (br_if $label$1
+     (f32.const 1)
+     (unreachable)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/untaken-br_if.wast.from-wast b/binaryen/test/untaken-br_if.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/untaken-br_if.wast.from-wast
@@ -0,0 +1,15 @@
+(module
+ (type $none_=>_f32 (func (result f32)))
+ (func $binaryify-untaken-br_if (result f32)
+  (if (result f32)
+   (i32.const 1)
+   (unreachable)
+   (block $label$1 (result f32)
+    (br_if $label$1
+     (f32.const 1)
+     (unreachable)
+    )
+   )
+  )
+ )
+)
diff --git a/binaryen/test/untaken-br_if.wast.fromBinary b/binaryen/test/untaken-br_if.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/untaken-br_if.wast.fromBinary
@@ -0,0 +1,16 @@
+(module
+ (type $none_=>_f32 (func (result f32)))
+ (func $binaryify-untaken-br_if (result f32)
+  (if (result f32)
+   (i32.const 1)
+   (unreachable)
+   (block $label$3 (result f32)
+    (drop
+     (f32.const 1)
+    )
+    (unreachable)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/untaken-br_if.wast.fromBinary.noDebugInfo b/binaryen/test/untaken-br_if.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/untaken-br_if.wast.fromBinary.noDebugInfo
@@ -0,0 +1,16 @@
+(module
+ (type $none_=>_f32 (func (result f32)))
+ (func $0 (result f32)
+  (if (result f32)
+   (i32.const 1)
+   (unreachable)
+   (block $label$3 (result f32)
+    (drop
+     (f32.const 1)
+    )
+    (unreachable)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/use-import-and-drop.asm.js b/binaryen/test/use-import-and-drop.asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/use-import-and-drop.asm.js
@@ -0,0 +1,19 @@
+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/validator/invalid_export.wast b/binaryen/test/validator/invalid_export.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/validator/invalid_export.wast
@@ -0,0 +1,1 @@
+(module (func $export64 (result i64) (i64.const 1)) (export "a" $export64))
diff --git a/binaryen/test/validator/invalid_import.wast b/binaryen/test/validator/invalid_import.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/validator/invalid_import.wast
@@ -0,0 +1,1 @@
+(module (import $bad "test" "bad" (param i64)))
diff --git a/binaryen/test/validator/invalid_number.wast b/binaryen/test/validator/invalid_number.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/validator/invalid_number.wast
@@ -0,0 +1,6 @@
+(module
+  (func $invalid_number
+   (i64.const 70847791997969805621592064)
+  )
+)
+
diff --git a/binaryen/test/validator/invalid_return.wast b/binaryen/test/validator/invalid_return.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/validator/invalid_return.wast
@@ -0,0 +1,2 @@
+(module
+ (func $foo (result i32) (i64.const 1)))
diff --git a/binaryen/test/wasm-only.asm.js b/binaryen/test/wasm-only.asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm-only.asm.js
@@ -0,0 +1,484 @@
+//
+// 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/wasm2asm.asserts.js b/binaryen/test/wasm2asm.asserts.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2asm.asserts.js
@@ -0,0 +1,122 @@
+function asmFunc(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 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0() {
+  
+ }
+ 
+ function $1(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x + y | 0 | 0;
+ }
+ 
+ function $2(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x | 0) / (y | 0) | 0 | 0;
+ }
+ 
+ function __wasm_fetch_high_bits() {
+  return i64toi32_i32$HIGH_BITS | 0;
+ }
+ 
+ return {
+  empty: $0, 
+  add: $1, 
+  div_s: $2, 
+  __wasm_fetch_high_bits: __wasm_fetch_high_bits
+ };
+}
+
+
+      var __array_buffer = new ArrayBuffer(65536)
+      var HEAP32 = new Int32Array(__array_buffer);
+      var HEAPF32 = new Float32Array(__array_buffer);
+      var HEAPF64 = new Float64Array(__array_buffer);
+      var nan = NaN;
+      var infinity = Infinity;
+    ;
+
+      function f32Equal(a, b) {
+         var i = new Int32Array(1);
+         var f = new Float32Array(i.buffer);
+         f[0] = a;
+         var ai = f[0];
+         f[0] = b;
+         var bi = f[0];
+
+         return (isNaN(a) && isNaN(b)) || a == b;
+      }
+
+      function f64Equal(a, b) {
+         var i = new Int32Array(2);
+         var f = new Float64Array(i.buffer);
+         f[0] = a;
+         var ai1 = i[0];
+         var ai2 = i[1];
+         f[0] = b;
+         var bi1 = i[0];
+         var bi2 = i[1];
+
+         return (isNaN(a) && isNaN(b)) || (ai1 == bi1 && ai2 == bi2);
+      }
+    ;
+var asmModule = asmFunc({
+ Math: Math, 
+ Int8Array: Int8Array, 
+ Int16Array: Int16Array, 
+ Int32Array: Int32Array, 
+ Uint8Array: Uint8Array, 
+ Uint16Array: Uint16Array, 
+ Uint32Array: Uint32Array, 
+ Float32Array: Float32Array, 
+ Float64Array: Float64Array, 
+ Infinity: Infinity, 
+ NaN: NaN
+}, {
+ abort: function abort() {
+  unreachable();
+  console_log();
+ }
+ , 
+ print: function print() {}
+}, __array_buffer);
+
+    function i64Equal(actual_lo, actual_hi, expected_lo, expected_hi) {
+       return actual_lo == (expected_lo | 0) && actual_hi == (expected_hi | 0);
+    }
+  ;
+function check1() {
+ var wasm2asm_i32$0 = 0;
+ asmModule.empty();
+ wasm2asm_i32$0 = 1;
+ return wasm2asm_i32$0 | 0;
+}
+
+if (!check1()) fail1();
+function check2() {
+ return (asmModule.add(1 | 0, 1 | 0) | 0 | 0) == (2 | 0) | 0;
+}
+
+if (!check2()) fail2();
diff --git a/binaryen/test/wasm2asm.traps.js b/binaryen/test/wasm2asm.traps.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2asm.traps.js
@@ -0,0 +1,150 @@
+function asmFunc(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 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0() {
+  
+ }
+ 
+ function $1(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x + y | 0 | 0;
+ }
+ 
+ function $2(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x | 0) / (y | 0) | 0 | 0;
+ }
+ 
+ function __wasm_fetch_high_bits() {
+  return i64toi32_i32$HIGH_BITS | 0;
+ }
+ 
+ return {
+  empty: $0, 
+  add: $1, 
+  div_s: $2, 
+  __wasm_fetch_high_bits: __wasm_fetch_high_bits
+ };
+}
+
+
+      var __array_buffer = new ArrayBuffer(65536)
+      var HEAP32 = new Int32Array(__array_buffer);
+      var HEAPF32 = new Float32Array(__array_buffer);
+      var HEAPF64 = new Float64Array(__array_buffer);
+      var nan = NaN;
+      var infinity = Infinity;
+    ;
+
+      function f32Equal(a, b) {
+         var i = new Int32Array(1);
+         var f = new Float32Array(i.buffer);
+         f[0] = a;
+         var ai = f[0];
+         f[0] = b;
+         var bi = f[0];
+
+         return (isNaN(a) && isNaN(b)) || a == b;
+      }
+
+      function f64Equal(a, b) {
+         var i = new Int32Array(2);
+         var f = new Float64Array(i.buffer);
+         f[0] = a;
+         var ai1 = i[0];
+         var ai2 = i[1];
+         f[0] = b;
+         var bi1 = i[0];
+         var bi2 = i[1];
+
+         return (isNaN(a) && isNaN(b)) || (ai1 == bi1 && ai2 == bi2);
+      }
+    ;
+var asmModule = asmFunc({
+ Math: Math, 
+ Int8Array: Int8Array, 
+ Int16Array: Int16Array, 
+ Int32Array: Int32Array, 
+ Uint8Array: Uint8Array, 
+ Uint16Array: Uint16Array, 
+ Uint32Array: Uint32Array, 
+ Float32Array: Float32Array, 
+ Float64Array: Float64Array, 
+ Infinity: Infinity, 
+ NaN: NaN
+}, {
+ abort: function abort() {
+  unreachable();
+  console_log();
+ }
+ , 
+ print: function print() {}
+}, __array_buffer);
+
+    function i64Equal(actual_lo, actual_hi, expected_lo, expected_hi) {
+       return actual_lo == (expected_lo | 0) && actual_hi == (expected_hi | 0);
+    }
+  ;
+function check1() {
+ var wasm2asm_i32$0 = 0;
+ asmModule.empty();
+ wasm2asm_i32$0 = 1;
+ return wasm2asm_i32$0 | 0;
+}
+
+if (!check1()) fail1();
+function check2() {
+ return (asmModule.add(1 | 0, 1 | 0) | 0 | 0) == (2 | 0) | 0;
+}
+
+if (!check2()) fail2();
+function check3() {
+ function f() {
+  asmModule.div_s(0 | 0, 0 | 0);
+ }
+ 
+ try {
+  f();
+ } catch (e) {
+  return e.message.includes("integer divide by zero");
+ };
+ return 0;
+}
+
+if (!check3()) fail3();
+function check4() {
+ function f() {
+  asmModule.div_s(2147483648 | 0, 4294967295 | 0);
+ }
+ 
+ try {
+  f();
+ } catch (e) {
+  return e.message.includes("integer overflow");
+ };
+ return 0;
+}
+
+if (!check4()) fail4();
diff --git a/binaryen/test/wasm2js.asserts.js b/binaryen/test/wasm2js.asserts.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js.asserts.js
@@ -0,0 +1,94 @@
+
+    var nan = NaN;
+    var infinity = Infinity;
+  
+    function f32Equal(a, b) {
+       var i = new Int32Array(1);
+       var f = new Float32Array(i.buffer);
+       f[0] = a;
+       var ai = f[0];
+       f[0] = b;
+       var bi = f[0];
+
+       return (isNaN(a) && isNaN(b)) || a == b;
+    }
+
+    function f64Equal(a, b) {
+       var i = new Int32Array(2);
+       var f = new Float64Array(i.buffer);
+       f[0] = a;
+       var ai1 = i[0];
+       var ai2 = i[1];
+       f[0] = b;
+       var bi1 = i[0];
+       var bi2 = i[1];
+
+       return (isNaN(a) && isNaN(b)) || (ai1 == bi1 && ai2 == bi2);
+    }
+
+    function i64Equal(actual_lo, actual_hi, expected_lo, expected_hi) {
+       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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  
+ }
+ 
+ function $1(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x + y | 0 | 0;
+ }
+ 
+ function $2(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x | 0) / (y | 0) | 0 | 0;
+ }
+ 
+ return {
+  "empty": $0, 
+  "add": $1, 
+  "div_s": $2
+ };
+}
+
+var retasmFunc0 = asmFunc0({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+function check1() {
+ retasmFunc0.empty();
+ return 1 | 0;
+}
+
+if (!check1()) throw 'assertion failed: ( assert_return ( call empty ) )';
+function check2() {
+ return (retasmFunc0.add(1 | 0, 1 | 0) | 0 | 0) == (2 | 0) | 0;
+}
+
+if (!check2()) throw 'assertion failed: ( assert_return ( call add ( i32.const 1 ) ( i32.const 1 ) ) ( i32.const 2 ) )';
diff --git a/binaryen/test/wasm2js.traps.js b/binaryen/test/wasm2js.traps.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js.traps.js
@@ -0,0 +1,122 @@
+
+    var nan = NaN;
+    var infinity = Infinity;
+  
+    function f32Equal(a, b) {
+       var i = new Int32Array(1);
+       var f = new Float32Array(i.buffer);
+       f[0] = a;
+       var ai = f[0];
+       f[0] = b;
+       var bi = f[0];
+
+       return (isNaN(a) && isNaN(b)) || a == b;
+    }
+
+    function f64Equal(a, b) {
+       var i = new Int32Array(2);
+       var f = new Float64Array(i.buffer);
+       f[0] = a;
+       var ai1 = i[0];
+       var ai2 = i[1];
+       f[0] = b;
+       var bi1 = i[0];
+       var bi2 = i[1];
+
+       return (isNaN(a) && isNaN(b)) || (ai1 == bi1 && ai2 == bi2);
+    }
+
+    function i64Equal(actual_lo, actual_hi, expected_lo, expected_hi) {
+       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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  
+ }
+ 
+ function $1(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x + y | 0 | 0;
+ }
+ 
+ function $2(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x | 0) / (y | 0) | 0 | 0;
+ }
+ 
+ return {
+  "empty": $0, 
+  "add": $1, 
+  "div_s": $2
+ };
+}
+
+var retasmFunc0 = asmFunc0({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+function check1() {
+ retasmFunc0.empty();
+ return 1 | 0;
+}
+
+if (!check1()) throw 'assertion failed: ( assert_return ( call empty ) )';
+function check2() {
+ return (retasmFunc0.add(1 | 0, 1 | 0) | 0 | 0) == (2 | 0) | 0;
+}
+
+if (!check2()) throw 'assertion failed: ( assert_return ( call add ( i32.const 1 ) ( i32.const 1 ) ) ( i32.const 2 ) )';
+function check3() {
+ function f() {
+  retasmFunc0.div_s(0 | 0, 0 | 0);
+ }
+ 
+ try {
+  f();
+ } catch (e) {
+  return e.message.includes("integer divide by zero");
+ };
+ return 0;
+}
+
+if (!check3()) throw 'assertion failed: ( assert_trap ( call div_s ( i32.const 0 ) ( i32.const 0 ) ) integer divide by zero )';
+function check4() {
+ function f() {
+  retasmFunc0.div_s(-2147483648 | 0, -1 | 0);
+ }
+ 
+ try {
+  f();
+ } catch (e) {
+  return e.message.includes("integer overflow");
+ };
+ return 0;
+}
+
+if (!check4()) throw 'assertion failed: ( assert_trap ( call div_s ( i32.const 0x80000000 ) ( i32.const -1 ) ) integer overflow )';
diff --git a/binaryen/test/wasm2js/add_div.2asm.js b/binaryen/test/wasm2js/add_div.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/add_div.2asm.js
@@ -0,0 +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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function foo($0) {
+  $0 = $0 | 0;
+  return (($0 >>> 0) / (100 >>> 0) | 0) + (($0 | 0) / (-100 | 0) | 0) | 0 | 0;
+ }
+ 
+ return {
+  "foo": foo
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/add_div.2asm.js.opt
@@ -0,0 +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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function foo($0) {
+  $0 = $0 | 0;
+  return (($0 | 0) / -100 | 0) + (($0 >>> 0) / 100 | 0) | 0;
+ }
+ 
+ return {
+  "foo": foo
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var foo = retasmFunc.foo;
diff --git a/binaryen/test/wasm2js/add_div.wast b/binaryen/test/wasm2js/add_div.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/add_div.wast
@@ -0,0 +1,15 @@
+(module
+ (export "foo" (func $foo (param i32) (result i32)))
+ (func $foo (param $0 i32) (result i32)
+  (i32.add
+   (i32.div_u
+    (local.get $0)
+    (i32.const 100)
+   )
+   (i32.div_s
+    (local.get $0)
+    (i32.const -100)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/wasm2js/atomic_fence.2asm.js b/binaryen/test/wasm2js/atomic_fence.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/atomic_fence.2asm.js
@@ -0,0 +1,77 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "atomic_fence": $0
+ };
+}
+
+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
+);
+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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/atomic_fence.2asm.js.opt
@@ -0,0 +1,39 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  
+ }
+ 
+ return {
+  "atomic_fence": $0
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var atomic_fence = retasmFunc.atomic_fence;
diff --git a/binaryen/test/wasm2js/atomic_fence.wast b/binaryen/test/wasm2js/atomic_fence.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/atomic_fence.wast
@@ -0,0 +1,6 @@
+(module
+  (memory $0 (shared 23 256))
+  (func (export "atomic-fence")
+    (atomic.fence)
+  )
+)
diff --git a/binaryen/test/wasm2js/atomics_32.2asm.js b/binaryen/test/wasm2js/atomics_32.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/atomics_32.2asm.js
@@ -0,0 +1,171 @@
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_atomic_wait_i32(ptr, expected, timeoutLow, timeoutHigh) {
+    if (timeoutLow != -1 || timeoutHigh != -1) throw 'unsupported timeout';
+    var view = new Int32Array(bufferView.buffer); // TODO cache
+    var result = Atomics.wait(view, ptr, expected);
+    if (result == 'ok') return 0;
+    if (result == 'not-equal') return 1;
+    if (result == 'timed-out') return 2;
+    throw 'bad result ' + result;
+  }
+      
+  function wasm2js_atomic_rmw_i64(op, bytes, offset, ptr, valueLow, valueHigh) {
+    assert(bytes == 8); // TODO: support 1, 2, 4 as well
+    var view = new BigInt64Array(bufferView.buffer); // TODO cache
+    ptr = (ptr + offset) >> 3;
+    var value = BigInt(valueLow >>> 0) | (BigInt(valueHigh >>> 0) << BigInt(32));
+    var result;
+    switch (op) {
+      case 0: { // Add
+        result = Atomics.add(view, ptr, value);
+        break;
+      }
+      case 1: { // Sub
+        result = Atomics.sub(view, ptr, value);
+        break;
+      }
+      case 2: { // And
+        result = Atomics.and(view, ptr, value);
+        break;
+      }
+      case 3: { // Or
+        result = Atomics.or(view, ptr, value);
+        break;
+      }
+      case 4: { // Xor
+        result = Atomics.xor(view, ptr, value);
+        break;
+      }
+      case 5: { // Xchg
+        result = Atomics.exchange(view, ptr, value);
+        break;
+      }
+      default: throw 'bad op';
+    }
+    var low = Number(result & BigInt(0xffffffff)) | 0;
+    var high = Number((result >> BigInt(32)) & BigInt(0xffffffff)) | 0;
+    stashedBits = high;
+    return low;
+  }
+      
+  var stashedBits = 0;
+
+  function wasm2js_get_stashed_bits() {
+    return stashedBits;
+  }
+      
+  function wasm2js_memory_init(segment, dest, offset, size) {
+    // TODO: traps on invalid things
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0;
+  Atomics.compareExchange(HEAP8, 1024, 1, 2) | 0;
+  Atomics.compareExchange(HEAP16, 1024 >> 1, 1, 2) | 0;
+  Atomics.compareExchange(HEAP32, 1024 >> 2, 1, 2) | 0;
+  Atomics.load(HEAPU8, 1028 >> 0) | 0;
+  Atomics.load(HEAPU16, 1028 >> 1) | 0;
+  Atomics.load(HEAP32, 1028 >> 2) | 0;
+  Atomics.store(HEAP32, 100 >> 2, 200);
+  i64toi32_i32$0 = -1;
+  wasm2js_atomic_wait_i32(4 | 0, 8 | 0, -1 | 0, i64toi32_i32$0 | 0) | 0;
+  wasm2js_memory_init(0, 512, 0, 4);
+  wasm2js_memory_init(1, 1024, 4, 2);
+  Atomics.notify(HEAP32, 4 >> 2, 2);
+  Atomics.notify(HEAP32, (4 + 20 | 0) >> 2, 2);
+  Atomics.add(HEAP32, 8 >> 2, 12);
+  Atomics.sub(HEAP32, 8 >> 2, 12);
+  Atomics.and(HEAP32, 8 >> 2, 12);
+  Atomics.or(HEAP32, 8 >> 2, 12);
+  Atomics.xor(HEAP32, 8 >> 2, 12);
+  Atomics.exchange(HEAP32, 8 >> 2, 12);
+  Atomics.add(HEAP8, 8, 12);
+  Atomics.sub(HEAP16, 8 >> 1, 12);
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$1 = wasm2js_atomic_rmw_i64(0 | 0, 8 | 0, 0 | 0, 8 | 0, 16 | 0, i64toi32_i32$0 | 0) | 0;
+  i64toi32_i32$2 = wasm2js_get_stashed_bits() | 0;
+  i64toi32_i32$2 = -1;
+  i64toi32_i32$1 = wasm2js_atomic_rmw_i64(4 | 0, 8 | 0, 32 | 0, 8 | 0, -1 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = wasm2js_get_stashed_bits() | 0;
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "test": $0
+ };
+}
+
+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
+);
+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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/atomics_32.2asm.js.opt
@@ -0,0 +1,167 @@
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_atomic_wait_i32(ptr, expected, timeoutLow, timeoutHigh) {
+    if (timeoutLow != -1 || timeoutHigh != -1) throw 'unsupported timeout';
+    var view = new Int32Array(bufferView.buffer); // TODO cache
+    var result = Atomics.wait(view, ptr, expected);
+    if (result == 'ok') return 0;
+    if (result == 'not-equal') return 1;
+    if (result == 'timed-out') return 2;
+    throw 'bad result ' + result;
+  }
+      
+  function wasm2js_atomic_rmw_i64(op, bytes, offset, ptr, valueLow, valueHigh) {
+    assert(bytes == 8); // TODO: support 1, 2, 4 as well
+    var view = new BigInt64Array(bufferView.buffer); // TODO cache
+    ptr = (ptr + offset) >> 3;
+    var value = BigInt(valueLow >>> 0) | (BigInt(valueHigh >>> 0) << BigInt(32));
+    var result;
+    switch (op) {
+      case 0: { // Add
+        result = Atomics.add(view, ptr, value);
+        break;
+      }
+      case 1: { // Sub
+        result = Atomics.sub(view, ptr, value);
+        break;
+      }
+      case 2: { // And
+        result = Atomics.and(view, ptr, value);
+        break;
+      }
+      case 3: { // Or
+        result = Atomics.or(view, ptr, value);
+        break;
+      }
+      case 4: { // Xor
+        result = Atomics.xor(view, ptr, value);
+        break;
+      }
+      case 5: { // Xchg
+        result = Atomics.exchange(view, ptr, value);
+        break;
+      }
+      default: throw 'bad op';
+    }
+    var low = Number(result & BigInt(0xffffffff)) | 0;
+    var high = Number((result >> BigInt(32)) & BigInt(0xffffffff)) | 0;
+    stashedBits = high;
+    return low;
+  }
+      
+  var stashedBits = 0;
+
+  function wasm2js_get_stashed_bits() {
+    return stashedBits;
+  }
+      
+  function wasm2js_memory_init(segment, dest, offset, size) {
+    // TODO: traps on invalid things
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  Atomics.compareExchange(HEAP8, 1024, 1, 2) | 0;
+  Atomics.compareExchange(HEAP16, 512, 1, 2) | 0;
+  Atomics.compareExchange(HEAP32, 256, 1, 2) | 0;
+  Atomics.load(HEAPU8, 1028);
+  Atomics.load(HEAPU16, 514);
+  Atomics.load(HEAP32, 257);
+  Atomics.store(HEAP32, 25, 200);
+  wasm2js_atomic_wait_i32(4, 8, -1, -1) | 0;
+  wasm2js_memory_init(0, 512, 0, 4);
+  wasm2js_memory_init(1, 1024, 4, 2);
+  Atomics.notify(HEAP32, 1, 2);
+  Atomics.notify(HEAP32, 4 + 20 >> 2, 2);
+  Atomics.add(HEAP32, 2, 12);
+  Atomics.sub(HEAP32, 2, 12);
+  Atomics.and(HEAP32, 2, 12);
+  Atomics.or(HEAP32, 2, 12);
+  Atomics.xor(HEAP32, 2, 12);
+  Atomics.exchange(HEAP32, 2, 12);
+  Atomics.add(HEAP8, 8, 12);
+  Atomics.sub(HEAP16, 4, 12);
+  wasm2js_atomic_rmw_i64(0, 8, 0, 8, 16, 0) | 0;
+  wasm2js_get_stashed_bits() | 0;
+  wasm2js_atomic_rmw_i64(4, 8, 32, 8, -1, -1) | 0;
+  wasm2js_get_stashed_bits() | 0;
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "test": $0
+ };
+}
+
+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
+);
+export var test = retasmFunc.test;
diff --git a/binaryen/test/wasm2js/atomics_32.wast b/binaryen/test/wasm2js/atomics_32.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/atomics_32.wast
@@ -0,0 +1,31 @@
+(module
+  (memory (shared 256 256))
+  (data passive "hello,")
+  (data passive "world!")
+  (func "test"
+    (local $x i32)
+    (local $y i64)
+    (local.set $x (i32.atomic.rmw8.cmpxchg_u (i32.const 1024) (i32.const 1) (i32.const 2)))
+    (local.set $x (i32.atomic.rmw16.cmpxchg_u (i32.const 1024) (i32.const 1) (i32.const 2)))
+    (local.set $x (i32.atomic.rmw.cmpxchg (i32.const 1024) (i32.const 1) (i32.const 2)))
+    (local.set $x (i32.atomic.load8_u (i32.const 1028)))
+    (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)))
+    (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 (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)))
+    (local.set $x (i32.atomic.rmw.or (i32.const 8) (i32.const 12)))
+    (local.set $x (i32.atomic.rmw.xor (i32.const 8) (i32.const 12)))
+    (local.set $x (i32.atomic.rmw.xchg (i32.const 8) (i32.const 12)))
+    (local.set $x (i32.atomic.rmw8.add_u (i32.const 8) (i32.const 12)))
+    (local.set $x (i32.atomic.rmw16.sub_u (i32.const 8) (i32.const 12)))
+    (local.set $y (i64.atomic.rmw.add (i32.const 8) (i64.const 16)))
+    (local.set $y (i64.atomic.rmw.xor offset=32 (i32.const 8) (i64.const -1)))
+  )
+)
diff --git a/binaryen/test/wasm2js/base64.2asm.js b/binaryen/test/wasm2js/base64.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/base64.2asm.js
@@ -0,0 +1,34 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ return {
+  
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
diff --git a/binaryen/test/wasm2js/base64.2asm.js.opt b/binaryen/test/wasm2js/base64.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/base64.2asm.js.opt
@@ -0,0 +1,34 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ return {
+  
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
diff --git a/binaryen/test/wasm2js/base64.wast b/binaryen/test/wasm2js/base64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/base64.wast
@@ -0,0 +1,4 @@
+(module
+  (memory $memory 1 1)
+  (data (i32.const 2) "\00\fe\ff")
+)
diff --git a/binaryen/test/wasm2js/br.2asm.js b/binaryen/test/wasm2js/br.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/br.2asm.js
@@ -0,0 +1,786 @@
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function dummy() {
+  
+ }
+ 
+ function $1() {
+  
+ }
+ 
+ function $2() {
+  
+ }
+ 
+ function $3() {
+  
+ }
+ 
+ function $4() {
+  
+ }
+ 
+ function $5() {
+  var $0 = 0;
+  block : {
+   $0 = 1;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $6() {
+  var i64toi32_i32$0 = 0, $0 = 0, $0$hi = 0;
+  block : {
+   i64toi32_i32$0 = 0;
+   $0 = 2;
+   $0$hi = i64toi32_i32$0;
+   break block;
+  }
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return $0 | 0;
+ }
+ 
+ function $7() {
+  var $0 = Math_fround(0);
+  block : {
+   $0 = Math_fround(3.0);
+   break block;
+  }
+  return Math_fround($0);
+ }
+ 
+ function $8() {
+  var $0 = 0.0;
+  block : {
+   $0 = 4.0;
+   break block;
+  }
+  return +$0;
+ }
+ 
+ function $9() {
+  
+ }
+ 
+ function $10() {
+  block : {
+   dummy();
+   break block;
+  }
+ }
+ 
+ function $11() {
+  block : {
+   dummy();
+   break block;
+  }
+ }
+ 
+ function $12() {
+  var $0 = 0;
+  block : {
+   dummy();
+   $0 = 2;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $13() {
+  var $0 = 0, $1_1 = 0, $3_1 = 0;
+  block : {
+   $0 = 3;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $14() {
+  var $0 = 0, $1_1 = 0, $3_1 = 0;
+  block : {
+   dummy();
+   $0 = 4;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $15() {
+  var $0 = 0;
+  block : {
+   dummy();
+   $0 = 5;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $16() {
+  var $0 = 0;
+  block : {
+   $0 = 9;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $17() {
+  
+ }
+ 
+ function $18() {
+  var $0 = 0;
+  block : {
+   $0 = 8;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $19() {
+  var $0 = 0;
+  block : {
+   $0 = 9;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $20() {
+  
+ }
+ 
+ function $21() {
+  var $0 = 0;
+  block : {
+   $0 = 10;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $22() {
+  var $0 = 0;
+  block : {
+   $0 = 11;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $23() {
+  var i64toi32_i32$0 = 0, $0 = 0, $0$hi = 0;
+  block : {
+   i64toi32_i32$0 = 0;
+   $0 = 7;
+   $0$hi = i64toi32_i32$0;
+   break block;
+  }
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return $0 | 0;
+ }
+ 
+ function $24() {
+  var $0 = 0, $5_1 = 0;
+  if_ : {
+   $0 = 2;
+   break if_;
+  }
+  return $0 | 0;
+ }
+ 
+ function $25($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var $3_1 = 0, $7_1 = 0;
+  block : {
+   if ($0) {
+    $3_1 = 3;
+    break block;
+   } else {
+    $7_1 = $1_1
+   }
+   $3_1 = $7_1;
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $26($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var $6_1 = 0, $7_1 = 0;
+  block : {
+   if ($0) {
+    $7_1 = $1_1
+   } else {
+    $6_1 = 4;
+    break block;
+   }
+   $6_1 = $7_1;
+  }
+  return $6_1 | 0;
+ }
+ 
+ function $27($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var $2_1 = 0, $3_1 = 0, $4_1 = 0;
+  block : {
+   $2_1 = 5;
+   break block;
+  }
+  return $2_1 | 0;
+ }
+ 
+ function $28($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var $2_1 = 0, $3_1 = 0, $4_1 = 0;
+  block : {
+   $2_1 = $0;
+   $3_1 = 6;
+   break block;
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $29() {
+  var $0 = 0;
+  block : {
+   $0 = 7;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function f($0, $1_1, $2_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  return -1 | 0;
+ }
+ 
+ function $31() {
+  var $0 = 0;
+  block : {
+   $0 = 12;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $32() {
+  var $0 = 0;
+  block : {
+   $0 = 13;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $33() {
+  var $0 = 0;
+  block : {
+   $0 = 14;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $34() {
+  var $0 = 0;
+  block : {
+   $0 = 20;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $35() {
+  var $0 = 0;
+  block : {
+   $0 = 21;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $36() {
+  var $0 = 0;
+  block : {
+   $0 = 22;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $37() {
+  var $0 = 0;
+  block : {
+   $0 = 23;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $38() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 17;
+   break block;
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $39() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 1;
+   break block;
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $40() {
+  var $0 = 0;
+  block : {
+   $0 = 1;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $41() {
+  var $0 = Math_fround(0);
+  block : {
+   $0 = Math_fround(1.7000000476837158);
+   break block;
+  }
+  return Math_fround($0);
+ }
+ 
+ function $42() {
+  var i64toi32_i32$0 = 0, $0 = 0, $0$hi = 0;
+  block : {
+   i64toi32_i32$0 = 0;
+   $0 = 30;
+   $0$hi = i64toi32_i32$0;
+   break block;
+  }
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return $0 | 0;
+ }
+ 
+ function $43() {
+  var $0 = 0;
+  block : {
+   $0 = 30;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $44() {
+  var $0 = 0;
+  block : {
+   $0 = 31;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $45() {
+  var $0 = 0;
+  block : {
+   $0 = 32;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $46() {
+  var $0 = 0;
+  block : {
+   $0 = 33;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $47() {
+  var $0 = Math_fround(0);
+  block : {
+   $0 = Math_fround(3.4000000953674316);
+   break block;
+  }
+  return Math_fround($0);
+ }
+ 
+ function $48() {
+  var $0 = 0;
+  block : {
+   $0 = 3;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $49() {
+  var $0 = 0, $0$hi = 0, i64toi32_i32$1 = 0;
+  block : {
+   $0 = 45;
+   $0$hi = 0;
+   break block;
+  }
+  i64toi32_i32$1 = $0$hi;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return $0 | 0;
+ }
+ 
+ function $50() {
+  var $0 = 0;
+  block : {
+   $0 = 44;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $51() {
+  var $0 = 0;
+  block : {
+   $0 = 43;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $52() {
+  var $0 = 0;
+  block : {
+   $0 = 42;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $53() {
+  var $0 = 0;
+  block : {
+   $0 = 41;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $54() {
+  var $0 = 0;
+  block : {
+   $0 = 40;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $55() {
+  var $0 = 0;
+  block : {
+   dummy();
+   $0 = 8;
+   break block;
+  }
+  return 1 + $0 | 0 | 0;
+ }
+ 
+ function $56() {
+  var $0 = 0;
+  block : {
+   block0 : {
+    $0 = 8;
+    break block;
+   }
+  }
+  return 1 + $0 | 0 | 0;
+ }
+ 
+ function $57() {
+  var $0 = 0, $1_1 = 0;
+  block : {
+   $0 = 8;
+   break block;
+  }
+  return 1 + $0 | 0 | 0;
+ }
+ 
+ function $58() {
+  var $0 = 0;
+  block : {
+   $0 = 8;
+   break block;
+  }
+  return 1 + $0 | 0 | 0;
+ }
+ 
+ function $59() {
+  var $0 = 0;
+  block : {
+   $0 = 8;
+   break block;
+  }
+  return 1 + $0 | 0 | 0;
+ }
+ 
+ function $60() {
+  var $0 = 0;
+  block : {
+   $0 = 8;
+   break block;
+  }
+  return 1 + $0 | 0 | 0;
+ }
+ 
+ function legalstub$6() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $6() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0 | 0;
+ }
+ 
+ function legalstub$23() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $23() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0 | 0;
+ }
+ 
+ function legalstub$42() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $42() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0 | 0;
+ }
+ 
+ function legalstub$49() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $49() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0 | 0;
+ }
+ 
+ return {
+  "type_i32": $1, 
+  "type_i64": $2, 
+  "type_f32": $3, 
+  "type_f64": $4, 
+  "type_i32_value": $5, 
+  "type_i64_value": legalstub$6, 
+  "type_f32_value": $7, 
+  "type_f64_value": $8, 
+  "as_block_first": $9, 
+  "as_block_mid": $10, 
+  "as_block_last": $11, 
+  "as_block_value": $12, 
+  "as_loop_first": $13, 
+  "as_loop_mid": $14, 
+  "as_loop_last": $15, 
+  "as_br_value": $16, 
+  "as_br_if_cond": $17, 
+  "as_br_if_value": $18, 
+  "as_br_if_value_cond": $19, 
+  "as_br_table_index": $20, 
+  "as_br_table_value": $21, 
+  "as_br_table_value_index": $22, 
+  "as_return_value": legalstub$23, 
+  "as_if_cond": $24, 
+  "as_if_then": $25, 
+  "as_if_else": $26, 
+  "as_select_first": $27, 
+  "as_select_second": $28, 
+  "as_select_cond": $29, 
+  "as_call_first": $31, 
+  "as_call_mid": $32, 
+  "as_call_last": $33, 
+  "as_call_indirect_func": $34, 
+  "as_call_indirect_first": $35, 
+  "as_call_indirect_mid": $36, 
+  "as_call_indirect_last": $37, 
+  "as_local_set_value": $38, 
+  "as_local_tee_value": $39, 
+  "as_global_set_value": $40, 
+  "as_load_address": $41, 
+  "as_loadN_address": legalstub$42, 
+  "as_store_address": $43, 
+  "as_store_value": $44, 
+  "as_storeN_address": $45, 
+  "as_storeN_value": $46, 
+  "as_unary_operand": $47, 
+  "as_binary_left": $48, 
+  "as_binary_right": legalstub$49, 
+  "as_test_operand": $50, 
+  "as_compare_left": $51, 
+  "as_compare_right": $52, 
+  "as_convert_operand": $53, 
+  "as_memory_grow_size": $54, 
+  "nested_block_value": $55, 
+  "nested_br_value": $56, 
+  "nested_br_if_value": $57, 
+  "nested_br_if_value_cond": $58, 
+  "nested_br_table_value": $59, 
+  "nested_br_table_value_index": $60
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var type_i32 = retasmFunc.type_i32;
+export var type_i64 = retasmFunc.type_i64;
+export var type_f32 = retasmFunc.type_f32;
+export var type_f64 = retasmFunc.type_f64;
+export var type_i32_value = retasmFunc.type_i32_value;
+export var type_i64_value = retasmFunc.type_i64_value;
+export var type_f32_value = retasmFunc.type_f32_value;
+export var type_f64_value = retasmFunc.type_f64_value;
+export var as_block_first = retasmFunc.as_block_first;
+export var as_block_mid = retasmFunc.as_block_mid;
+export var as_block_last = retasmFunc.as_block_last;
+export var as_block_value = retasmFunc.as_block_value;
+export var as_loop_first = retasmFunc.as_loop_first;
+export var as_loop_mid = retasmFunc.as_loop_mid;
+export var as_loop_last = retasmFunc.as_loop_last;
+export var as_br_value = retasmFunc.as_br_value;
+export var as_br_if_cond = retasmFunc.as_br_if_cond;
+export var as_br_if_value = retasmFunc.as_br_if_value;
+export var as_br_if_value_cond = retasmFunc.as_br_if_value_cond;
+export var as_br_table_index = retasmFunc.as_br_table_index;
+export var as_br_table_value = retasmFunc.as_br_table_value;
+export var as_br_table_value_index = retasmFunc.as_br_table_value_index;
+export var as_return_value = retasmFunc.as_return_value;
+export var as_if_cond = retasmFunc.as_if_cond;
+export var as_if_then = retasmFunc.as_if_then;
+export var as_if_else = retasmFunc.as_if_else;
+export var as_select_first = retasmFunc.as_select_first;
+export var as_select_second = retasmFunc.as_select_second;
+export var as_select_cond = retasmFunc.as_select_cond;
+export var as_call_first = retasmFunc.as_call_first;
+export var as_call_mid = retasmFunc.as_call_mid;
+export var as_call_last = retasmFunc.as_call_last;
+export var as_call_indirect_func = retasmFunc.as_call_indirect_func;
+export var as_call_indirect_first = retasmFunc.as_call_indirect_first;
+export var as_call_indirect_mid = retasmFunc.as_call_indirect_mid;
+export var as_call_indirect_last = retasmFunc.as_call_indirect_last;
+export var as_local_set_value = retasmFunc.as_local_set_value;
+export var as_local_tee_value = retasmFunc.as_local_tee_value;
+export var as_global_set_value = retasmFunc.as_global_set_value;
+export var as_load_address = retasmFunc.as_load_address;
+export var as_loadN_address = retasmFunc.as_loadN_address;
+export var as_store_address = retasmFunc.as_store_address;
+export var as_store_value = retasmFunc.as_store_value;
+export var as_storeN_address = retasmFunc.as_storeN_address;
+export var as_storeN_value = retasmFunc.as_storeN_value;
+export var as_unary_operand = retasmFunc.as_unary_operand;
+export var as_binary_left = retasmFunc.as_binary_left;
+export var as_binary_right = retasmFunc.as_binary_right;
+export var as_test_operand = retasmFunc.as_test_operand;
+export var as_compare_left = retasmFunc.as_compare_left;
+export var as_compare_right = retasmFunc.as_compare_right;
+export var as_convert_operand = retasmFunc.as_convert_operand;
+export var as_memory_grow_size = retasmFunc.as_memory_grow_size;
+export var nested_block_value = retasmFunc.nested_block_value;
+export var nested_br_value = retasmFunc.nested_br_value;
+export var nested_br_if_value = retasmFunc.nested_br_if_value;
+export var nested_br_if_value_cond = retasmFunc.nested_br_if_value_cond;
+export var nested_br_table_value = retasmFunc.nested_br_table_value;
+export var nested_br_table_value_index = retasmFunc.nested_br_table_value_index;
diff --git a/binaryen/test/wasm2js/br_table.2asm.js b/binaryen/test/wasm2js/br_table.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/br_table.2asm.js
@@ -0,0 +1,13499 @@
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function dummy() {
+  
+ }
+ 
+ function $1() {
+  
+ }
+ 
+ function $2() {
+  
+ }
+ 
+ function $3() {
+  
+ }
+ 
+ function $4() {
+  
+ }
+ 
+ function $5() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 1;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $6() {
+  var i64toi32_i32$0 = 0, $1_1 = 0, $1$hi = 0;
+  block : {
+   i64toi32_i32$0 = 0;
+   $1_1 = 2;
+   $1$hi = i64toi32_i32$0;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return $1_1 | 0;
+ }
+ 
+ function $7() {
+  var $1_1 = Math_fround(0);
+  block : {
+   $1_1 = Math_fround(3.0);
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return Math_fround($1_1);
+ }
+ 
+ function $8() {
+  var $1_1 = 0.0;
+  block : {
+   $1_1 = 4.0;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return +$1_1;
+ }
+ 
+ function $9($0) {
+  $0 = $0 | 0;
+  return 22 | 0;
+ }
+ 
+ function $10($0) {
+  $0 = $0 | 0;
+  var $3_1 = 0;
+  block : {
+   $3_1 = 33;
+   switch ($0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $11($0) {
+  $0 = $0 | 0;
+  block : {
+   switch ($0 | 0) {
+   default:
+    return 20 | 0;
+   case 0:
+    break block;
+   };
+  }
+  return 22 | 0;
+ }
+ 
+ function $12($0) {
+  $0 = $0 | 0;
+  var $2_1 = 0, $3_1 = 0, $4_1 = 0;
+  block : {
+   block1 : {
+    $2_1 = 33;
+    $3_1 = $2_1;
+    $4_1 = $2_1;
+    switch ($0 | 0) {
+    case 0:
+     break block1;
+    default:
+     break block;
+    };
+   }
+   $3_1 = 32;
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $13($0) {
+  $0 = $0 | 0;
+  block : {
+   switch ($0 | 0) {
+   case 3:
+    return 100 | 0;
+   case 2:
+    return 101 | 0;
+   case 1:
+    return 102 | 0;
+   case 0:
+    return 103 | 0;
+   default:
+    break block;
+   };
+  }
+  return 104 | 0;
+ }
+ 
+ function $14($0) {
+  $0 = $0 | 0;
+  var $1_1 = 0, $3_1 = 0, $4_1 = 0, $5_1 = 0, $6_1 = 0, $7_1 = 0, $8_1 = 0;
+  block : {
+   block6 : {
+    block7 : {
+     block8 : {
+      block9 : {
+       $3_1 = 200;
+       $4_1 = $3_1;
+       $5_1 = $3_1;
+       $6_1 = $3_1;
+       $7_1 = $3_1;
+       $8_1 = $3_1;
+       switch ($0 | 0) {
+       case 0:
+        break block6;
+       case 1:
+        break block7;
+       case 2:
+        break block8;
+       case 3:
+        break block9;
+       default:
+        break block;
+       };
+      }
+      $1_1 = $8_1;
+      return $1_1 + 10 | 0 | 0;
+     }
+     $1_1 = $7_1;
+     return $1_1 + 11 | 0 | 0;
+    }
+    $1_1 = $6_1;
+    return $1_1 + 12 | 0 | 0;
+   }
+   $1_1 = $5_1;
+   return $1_1 + 13 | 0 | 0;
+  }
+  $1_1 = $4_1;
+  return $1_1 + 14 | 0 | 0;
+ }
+ 
+ function $15($0) {
+  $0 = $0 | 0;
+  block : {
+   switch ($0 | 0) {
+   case 0:
+   case 2:
+   case 4:
+   case 6:
+   case 8:
+   case 10:
+   case 12:
+   case 14:
+   case 16:
+   case 18:
+   case 20:
+   case 22:
+   case 24:
+   case 26:
+   case 28:
+   case 30:
+   case 32:
+   case 34:
+   case 36:
+   case 38:
+   case 40:
+   case 42:
+   case 44:
+   case 46:
+   case 48:
+   case 50:
+   case 52:
+   case 54:
+   case 56:
+   case 58:
+   case 60:
+   case 62:
+   case 64:
+   case 66:
+   case 68:
+   case 70:
+   case 72:
+   case 74:
+   case 76:
+   case 78:
+   case 80:
+   case 82:
+   case 84:
+   case 86:
+   case 88:
+   case 90:
+   case 92:
+   case 94:
+   case 96:
+   case 98:
+   case 100:
+   case 102:
+   case 104:
+   case 106:
+   case 108:
+   case 110:
+   case 112:
+   case 114:
+   case 116:
+   case 118:
+   case 120:
+   case 122:
+   case 124:
+   case 126:
+   case 128:
+   case 130:
+   case 132:
+   case 134:
+   case 136:
+   case 138:
+   case 140:
+   case 142:
+   case 144:
+   case 146:
+   case 148:
+   case 150:
+   case 152:
+   case 154:
+   case 156:
+   case 158:
+   case 160:
+   case 162:
+   case 164:
+   case 166:
+   case 168:
+   case 170:
+   case 172:
+   case 174:
+   case 176:
+   case 178:
+   case 180:
+   case 182:
+   case 184:
+   case 186:
+   case 188:
+   case 190:
+   case 192:
+   case 194:
+   case 196:
+   case 198:
+   case 200:
+   case 202:
+   case 204:
+   case 206:
+   case 208:
+   case 210:
+   case 212:
+   case 214:
+   case 216:
+   case 218:
+   case 220:
+   case 222:
+   case 224:
+   case 226:
+   case 228:
+   case 230:
+   case 232:
+   case 234:
+   case 236:
+   case 238:
+   case 240:
+   case 242:
+   case 244:
+   case 246:
+   case 248:
+   case 250:
+   case 252:
+   case 254:
+   case 256:
+   case 258:
+   case 260:
+   case 262:
+   case 264:
+   case 266:
+   case 268:
+   case 270:
+   case 272:
+   case 274:
+   case 276:
+   case 278:
+   case 280:
+   case 282:
+   case 284:
+   case 286:
+   case 288:
+   case 290:
+   case 292:
+   case 294:
+   case 296:
+   case 298:
+   case 300:
+   case 302:
+   case 304:
+   case 306:
+   case 308:
+   case 310:
+   case 312:
+   case 314:
+   case 316:
+   case 318:
+   case 320:
+   case 322:
+   case 324:
+   case 326:
+   case 328:
+   case 330:
+   case 332:
+   case 334:
+   case 336:
+   case 338:
+   case 340:
+   case 342:
+   case 344:
+   case 346:
+   case 348:
+   case 350:
+   case 352:
+   case 354:
+   case 356:
+   case 358:
+   case 360:
+   case 362:
+   case 364:
+   case 366:
+   case 368:
+   case 370:
+   case 372:
+   case 374:
+   case 376:
+   case 378:
+   case 380:
+   case 382:
+   case 384:
+   case 386:
+   case 388:
+   case 390:
+   case 392:
+   case 394:
+   case 396:
+   case 398:
+   case 400:
+   case 402:
+   case 404:
+   case 406:
+   case 408:
+   case 410:
+   case 412:
+   case 414:
+   case 416:
+   case 418:
+   case 420:
+   case 422:
+   case 424:
+   case 426:
+   case 428:
+   case 430:
+   case 432:
+   case 434:
+   case 436:
+   case 438:
+   case 440:
+   case 442:
+   case 444:
+   case 446:
+   case 448:
+   case 450:
+   case 452:
+   case 454:
+   case 456:
+   case 458:
+   case 460:
+   case 462:
+   case 464:
+   case 466:
+   case 468:
+   case 470:
+   case 472:
+   case 474:
+   case 476:
+   case 478:
+   case 480:
+   case 482:
+   case 484:
+   case 486:
+   case 488:
+   case 490:
+   case 492:
+   case 494:
+   case 496:
+   case 498:
+   case 500:
+   case 502:
+   case 504:
+   case 506:
+   case 508:
+   case 510:
+   case 512:
+   case 514:
+   case 516:
+   case 518:
+   case 520:
+   case 522:
+   case 524:
+   case 526:
+   case 528:
+   case 530:
+   case 532:
+   case 534:
+   case 536:
+   case 538:
+   case 540:
+   case 542:
+   case 544:
+   case 546:
+   case 548:
+   case 550:
+   case 552:
+   case 554:
+   case 556:
+   case 558:
+   case 560:
+   case 562:
+   case 564:
+   case 566:
+   case 568:
+   case 570:
+   case 572:
+   case 574:
+   case 576:
+   case 578:
+   case 580:
+   case 582:
+   case 584:
+   case 586:
+   case 588:
+   case 590:
+   case 592:
+   case 594:
+   case 596:
+   case 598:
+   case 600:
+   case 602:
+   case 604:
+   case 606:
+   case 608:
+   case 610:
+   case 612:
+   case 614:
+   case 616:
+   case 618:
+   case 620:
+   case 622:
+   case 624:
+   case 626:
+   case 628:
+   case 630:
+   case 632:
+   case 634:
+   case 636:
+   case 638:
+   case 640:
+   case 642:
+   case 644:
+   case 646:
+   case 648:
+   case 650:
+   case 652:
+   case 654:
+   case 656:
+   case 658:
+   case 660:
+   case 662:
+   case 664:
+   case 666:
+   case 668:
+   case 670:
+   case 672:
+   case 674:
+   case 676:
+   case 678:
+   case 680:
+   case 682:
+   case 684:
+   case 686:
+   case 688:
+   case 690:
+   case 692:
+   case 694:
+   case 696:
+   case 698:
+   case 700:
+   case 702:
+   case 704:
+   case 706:
+   case 708:
+   case 710:
+   case 712:
+   case 714:
+   case 716:
+   case 718:
+   case 720:
+   case 722:
+   case 724:
+   case 726:
+   case 728:
+   case 730:
+   case 732:
+   case 734:
+   case 736:
+   case 738:
+   case 740:
+   case 742:
+   case 744:
+   case 746:
+   case 748:
+   case 750:
+   case 752:
+   case 754:
+   case 756:
+   case 758:
+   case 760:
+   case 762:
+   case 764:
+   case 766:
+   case 768:
+   case 770:
+   case 772:
+   case 774:
+   case 776:
+   case 778:
+   case 780:
+   case 782:
+   case 784:
+   case 786:
+   case 788:
+   case 790:
+   case 792:
+   case 794:
+   case 796:
+   case 798:
+   case 800:
+   case 802:
+   case 804:
+   case 806:
+   case 808:
+   case 810:
+   case 812:
+   case 814:
+   case 816:
+   case 818:
+   case 820:
+   case 822:
+   case 824:
+   case 826:
+   case 828:
+   case 830:
+   case 832:
+   case 834:
+   case 836:
+   case 838:
+   case 840:
+   case 842:
+   case 844:
+   case 846:
+   case 848:
+   case 850:
+   case 852:
+   case 854:
+   case 856:
+   case 858:
+   case 860:
+   case 862:
+   case 864:
+   case 866:
+   case 868:
+   case 870:
+   case 872:
+   case 874:
+   case 876:
+   case 878:
+   case 880:
+   case 882:
+   case 884:
+   case 886:
+   case 888:
+   case 890:
+   case 892:
+   case 894:
+   case 896:
+   case 898:
+   case 900:
+   case 902:
+   case 904:
+   case 906:
+   case 908:
+   case 910:
+   case 912:
+   case 914:
+   case 916:
+   case 918:
+   case 920:
+   case 922:
+   case 924:
+   case 926:
+   case 928:
+   case 930:
+   case 932:
+   case 934:
+   case 936:
+   case 938:
+   case 940:
+   case 942:
+   case 944:
+   case 946:
+   case 948:
+   case 950:
+   case 952:
+   case 954:
+   case 956:
+   case 958:
+   case 960:
+   case 962:
+   case 964:
+   case 966:
+   case 968:
+   case 970:
+   case 972:
+   case 974:
+   case 976:
+   case 978:
+   case 980:
+   case 982:
+   case 984:
+   case 986:
+   case 988:
+   case 990:
+   case 992:
+   case 994:
+   case 996:
+   case 998:
+   case 1e3:
+   case 1002:
+   case 1004:
+   case 1006:
+   case 1008:
+   case 1010:
+   case 1012:
+   case 1014:
+   case 1016:
+   case 1018:
+   case 1020:
+   case 1022:
+   case 1024:
+   case 1026:
+   case 1028:
+   case 1030:
+   case 1032:
+   case 1034:
+   case 1036:
+   case 1038:
+   case 1040:
+   case 1042:
+   case 1044:
+   case 1046:
+   case 1048:
+   case 1050:
+   case 1052:
+   case 1054:
+   case 1056:
+   case 1058:
+   case 1060:
+   case 1062:
+   case 1064:
+   case 1066:
+   case 1068:
+   case 1070:
+   case 1072:
+   case 1074:
+   case 1076:
+   case 1078:
+   case 1080:
+   case 1082:
+   case 1084:
+   case 1086:
+   case 1088:
+   case 1090:
+   case 1092:
+   case 1094:
+   case 1096:
+   case 1098:
+   case 1100:
+   case 1102:
+   case 1104:
+   case 1106:
+   case 1108:
+   case 1110:
+   case 1112:
+   case 1114:
+   case 1116:
+   case 1118:
+   case 1120:
+   case 1122:
+   case 1124:
+   case 1126:
+   case 1128:
+   case 1130:
+   case 1132:
+   case 1134:
+   case 1136:
+   case 1138:
+   case 1140:
+   case 1142:
+   case 1144:
+   case 1146:
+   case 1148:
+   case 1150:
+   case 1152:
+   case 1154:
+   case 1156:
+   case 1158:
+   case 1160:
+   case 1162:
+   case 1164:
+   case 1166:
+   case 1168:
+   case 1170:
+   case 1172:
+   case 1174:
+   case 1176:
+   case 1178:
+   case 1180:
+   case 1182:
+   case 1184:
+   case 1186:
+   case 1188:
+   case 1190:
+   case 1192:
+   case 1194:
+   case 1196:
+   case 1198:
+   case 1200:
+   case 1202:
+   case 1204:
+   case 1206:
+   case 1208:
+   case 1210:
+   case 1212:
+   case 1214:
+   case 1216:
+   case 1218:
+   case 1220:
+   case 1222:
+   case 1224:
+   case 1226:
+   case 1228:
+   case 1230:
+   case 1232:
+   case 1234:
+   case 1236:
+   case 1238:
+   case 1240:
+   case 1242:
+   case 1244:
+   case 1246:
+   case 1248:
+   case 1250:
+   case 1252:
+   case 1254:
+   case 1256:
+   case 1258:
+   case 1260:
+   case 1262:
+   case 1264:
+   case 1266:
+   case 1268:
+   case 1270:
+   case 1272:
+   case 1274:
+   case 1276:
+   case 1278:
+   case 1280:
+   case 1282:
+   case 1284:
+   case 1286:
+   case 1288:
+   case 1290:
+   case 1292:
+   case 1294:
+   case 1296:
+   case 1298:
+   case 1300:
+   case 1302:
+   case 1304:
+   case 1306:
+   case 1308:
+   case 1310:
+   case 1312:
+   case 1314:
+   case 1316:
+   case 1318:
+   case 1320:
+   case 1322:
+   case 1324:
+   case 1326:
+   case 1328:
+   case 1330:
+   case 1332:
+   case 1334:
+   case 1336:
+   case 1338:
+   case 1340:
+   case 1342:
+   case 1344:
+   case 1346:
+   case 1348:
+   case 1350:
+   case 1352:
+   case 1354:
+   case 1356:
+   case 1358:
+   case 1360:
+   case 1362:
+   case 1364:
+   case 1366:
+   case 1368:
+   case 1370:
+   case 1372:
+   case 1374:
+   case 1376:
+   case 1378:
+   case 1380:
+   case 1382:
+   case 1384:
+   case 1386:
+   case 1388:
+   case 1390:
+   case 1392:
+   case 1394:
+   case 1396:
+   case 1398:
+   case 1400:
+   case 1402:
+   case 1404:
+   case 1406:
+   case 1408:
+   case 1410:
+   case 1412:
+   case 1414:
+   case 1416:
+   case 1418:
+   case 1420:
+   case 1422:
+   case 1424:
+   case 1426:
+   case 1428:
+   case 1430:
+   case 1432:
+   case 1434:
+   case 1436:
+   case 1438:
+   case 1440:
+   case 1442:
+   case 1444:
+   case 1446:
+   case 1448:
+   case 1450:
+   case 1452:
+   case 1454:
+   case 1456:
+   case 1458:
+   case 1460:
+   case 1462:
+   case 1464:
+   case 1466:
+   case 1468:
+   case 1470:
+   case 1472:
+   case 1474:
+   case 1476:
+   case 1478:
+   case 1480:
+   case 1482:
+   case 1484:
+   case 1486:
+   case 1488:
+   case 1490:
+   case 1492:
+   case 1494:
+   case 1496:
+   case 1498:
+   case 1500:
+   case 1502:
+   case 1504:
+   case 1506:
+   case 1508:
+   case 1510:
+   case 1512:
+   case 1514:
+   case 1516:
+   case 1518:
+   case 1520:
+   case 1522:
+   case 1524:
+   case 1526:
+   case 1528:
+   case 1530:
+   case 1532:
+   case 1534:
+   case 1536:
+   case 1538:
+   case 1540:
+   case 1542:
+   case 1544:
+   case 1546:
+   case 1548:
+   case 1550:
+   case 1552:
+   case 1554:
+   case 1556:
+   case 1558:
+   case 1560:
+   case 1562:
+   case 1564:
+   case 1566:
+   case 1568:
+   case 1570:
+   case 1572:
+   case 1574:
+   case 1576:
+   case 1578:
+   case 1580:
+   case 1582:
+   case 1584:
+   case 1586:
+   case 1588:
+   case 1590:
+   case 1592:
+   case 1594:
+   case 1596:
+   case 1598:
+   case 1600:
+   case 1602:
+   case 1604:
+   case 1606:
+   case 1608:
+   case 1610:
+   case 1612:
+   case 1614:
+   case 1616:
+   case 1618:
+   case 1620:
+   case 1622:
+   case 1624:
+   case 1626:
+   case 1628:
+   case 1630:
+   case 1632:
+   case 1634:
+   case 1636:
+   case 1638:
+   case 1640:
+   case 1642:
+   case 1644:
+   case 1646:
+   case 1648:
+   case 1650:
+   case 1652:
+   case 1654:
+   case 1656:
+   case 1658:
+   case 1660:
+   case 1662:
+   case 1664:
+   case 1666:
+   case 1668:
+   case 1670:
+   case 1672:
+   case 1674:
+   case 1676:
+   case 1678:
+   case 1680:
+   case 1682:
+   case 1684:
+   case 1686:
+   case 1688:
+   case 1690:
+   case 1692:
+   case 1694:
+   case 1696:
+   case 1698:
+   case 1700:
+   case 1702:
+   case 1704:
+   case 1706:
+   case 1708:
+   case 1710:
+   case 1712:
+   case 1714:
+   case 1716:
+   case 1718:
+   case 1720:
+   case 1722:
+   case 1724:
+   case 1726:
+   case 1728:
+   case 1730:
+   case 1732:
+   case 1734:
+   case 1736:
+   case 1738:
+   case 1740:
+   case 1742:
+   case 1744:
+   case 1746:
+   case 1748:
+   case 1750:
+   case 1752:
+   case 1754:
+   case 1756:
+   case 1758:
+   case 1760:
+   case 1762:
+   case 1764:
+   case 1766:
+   case 1768:
+   case 1770:
+   case 1772:
+   case 1774:
+   case 1776:
+   case 1778:
+   case 1780:
+   case 1782:
+   case 1784:
+   case 1786:
+   case 1788:
+   case 1790:
+   case 1792:
+   case 1794:
+   case 1796:
+   case 1798:
+   case 1800:
+   case 1802:
+   case 1804:
+   case 1806:
+   case 1808:
+   case 1810:
+   case 1812:
+   case 1814:
+   case 1816:
+   case 1818:
+   case 1820:
+   case 1822:
+   case 1824:
+   case 1826:
+   case 1828:
+   case 1830:
+   case 1832:
+   case 1834:
+   case 1836:
+   case 1838:
+   case 1840:
+   case 1842:
+   case 1844:
+   case 1846:
+   case 1848:
+   case 1850:
+   case 1852:
+   case 1854:
+   case 1856:
+   case 1858:
+   case 1860:
+   case 1862:
+   case 1864:
+   case 1866:
+   case 1868:
+   case 1870:
+   case 1872:
+   case 1874:
+   case 1876:
+   case 1878:
+   case 1880:
+   case 1882:
+   case 1884:
+   case 1886:
+   case 1888:
+   case 1890:
+   case 1892:
+   case 1894:
+   case 1896:
+   case 1898:
+   case 1900:
+   case 1902:
+   case 1904:
+   case 1906:
+   case 1908:
+   case 1910:
+   case 1912:
+   case 1914:
+   case 1916:
+   case 1918:
+   case 1920:
+   case 1922:
+   case 1924:
+   case 1926:
+   case 1928:
+   case 1930:
+   case 1932:
+   case 1934:
+   case 1936:
+   case 1938:
+   case 1940:
+   case 1942:
+   case 1944:
+   case 1946:
+   case 1948:
+   case 1950:
+   case 1952:
+   case 1954:
+   case 1956:
+   case 1958:
+   case 1960:
+   case 1962:
+   case 1964:
+   case 1966:
+   case 1968:
+   case 1970:
+   case 1972:
+   case 1974:
+   case 1976:
+   case 1978:
+   case 1980:
+   case 1982:
+   case 1984:
+   case 1986:
+   case 1988:
+   case 1990:
+   case 1992:
+   case 1994:
+   case 1996:
+   case 1998:
+   case 2e3:
+   case 2002:
+   case 2004:
+   case 2006:
+   case 2008:
+   case 2010:
+   case 2012:
+   case 2014:
+   case 2016:
+   case 2018:
+   case 2020:
+   case 2022:
+   case 2024:
+   case 2026:
+   case 2028:
+   case 2030:
+   case 2032:
+   case 2034:
+   case 2036:
+   case 2038:
+   case 2040:
+   case 2042:
+   case 2044:
+   case 2046:
+   case 2048:
+   case 2050:
+   case 2052:
+   case 2054:
+   case 2056:
+   case 2058:
+   case 2060:
+   case 2062:
+   case 2064:
+   case 2066:
+   case 2068:
+   case 2070:
+   case 2072:
+   case 2074:
+   case 2076:
+   case 2078:
+   case 2080:
+   case 2082:
+   case 2084:
+   case 2086:
+   case 2088:
+   case 2090:
+   case 2092:
+   case 2094:
+   case 2096:
+   case 2098:
+   case 2100:
+   case 2102:
+   case 2104:
+   case 2106:
+   case 2108:
+   case 2110:
+   case 2112:
+   case 2114:
+   case 2116:
+   case 2118:
+   case 2120:
+   case 2122:
+   case 2124:
+   case 2126:
+   case 2128:
+   case 2130:
+   case 2132:
+   case 2134:
+   case 2136:
+   case 2138:
+   case 2140:
+   case 2142:
+   case 2144:
+   case 2146:
+   case 2148:
+   case 2150:
+   case 2152:
+   case 2154:
+   case 2156:
+   case 2158:
+   case 2160:
+   case 2162:
+   case 2164:
+   case 2166:
+   case 2168:
+   case 2170:
+   case 2172:
+   case 2174:
+   case 2176:
+   case 2178:
+   case 2180:
+   case 2182:
+   case 2184:
+   case 2186:
+   case 2188:
+   case 2190:
+   case 2192:
+   case 2194:
+   case 2196:
+   case 2198:
+   case 2200:
+   case 2202:
+   case 2204:
+   case 2206:
+   case 2208:
+   case 2210:
+   case 2212:
+   case 2214:
+   case 2216:
+   case 2218:
+   case 2220:
+   case 2222:
+   case 2224:
+   case 2226:
+   case 2228:
+   case 2230:
+   case 2232:
+   case 2234:
+   case 2236:
+   case 2238:
+   case 2240:
+   case 2242:
+   case 2244:
+   case 2246:
+   case 2248:
+   case 2250:
+   case 2252:
+   case 2254:
+   case 2256:
+   case 2258:
+   case 2260:
+   case 2262:
+   case 2264:
+   case 2266:
+   case 2268:
+   case 2270:
+   case 2272:
+   case 2274:
+   case 2276:
+   case 2278:
+   case 2280:
+   case 2282:
+   case 2284:
+   case 2286:
+   case 2288:
+   case 2290:
+   case 2292:
+   case 2294:
+   case 2296:
+   case 2298:
+   case 2300:
+   case 2302:
+   case 2304:
+   case 2306:
+   case 2308:
+   case 2310:
+   case 2312:
+   case 2314:
+   case 2316:
+   case 2318:
+   case 2320:
+   case 2322:
+   case 2324:
+   case 2326:
+   case 2328:
+   case 2330:
+   case 2332:
+   case 2334:
+   case 2336:
+   case 2338:
+   case 2340:
+   case 2342:
+   case 2344:
+   case 2346:
+   case 2348:
+   case 2350:
+   case 2352:
+   case 2354:
+   case 2356:
+   case 2358:
+   case 2360:
+   case 2362:
+   case 2364:
+   case 2366:
+   case 2368:
+   case 2370:
+   case 2372:
+   case 2374:
+   case 2376:
+   case 2378:
+   case 2380:
+   case 2382:
+   case 2384:
+   case 2386:
+   case 2388:
+   case 2390:
+   case 2392:
+   case 2394:
+   case 2396:
+   case 2398:
+   case 2400:
+   case 2402:
+   case 2404:
+   case 2406:
+   case 2408:
+   case 2410:
+   case 2412:
+   case 2414:
+   case 2416:
+   case 2418:
+   case 2420:
+   case 2422:
+   case 2424:
+   case 2426:
+   case 2428:
+   case 2430:
+   case 2432:
+   case 2434:
+   case 2436:
+   case 2438:
+   case 2440:
+   case 2442:
+   case 2444:
+   case 2446:
+   case 2448:
+   case 2450:
+   case 2452:
+   case 2454:
+   case 2456:
+   case 2458:
+   case 2460:
+   case 2462:
+   case 2464:
+   case 2466:
+   case 2468:
+   case 2470:
+   case 2472:
+   case 2474:
+   case 2476:
+   case 2478:
+   case 2480:
+   case 2482:
+   case 2484:
+   case 2486:
+   case 2488:
+   case 2490:
+   case 2492:
+   case 2494:
+   case 2496:
+   case 2498:
+   case 2500:
+   case 2502:
+   case 2504:
+   case 2506:
+   case 2508:
+   case 2510:
+   case 2512:
+   case 2514:
+   case 2516:
+   case 2518:
+   case 2520:
+   case 2522:
+   case 2524:
+   case 2526:
+   case 2528:
+   case 2530:
+   case 2532:
+   case 2534:
+   case 2536:
+   case 2538:
+   case 2540:
+   case 2542:
+   case 2544:
+   case 2546:
+   case 2548:
+   case 2550:
+   case 2552:
+   case 2554:
+   case 2556:
+   case 2558:
+   case 2560:
+   case 2562:
+   case 2564:
+   case 2566:
+   case 2568:
+   case 2570:
+   case 2572:
+   case 2574:
+   case 2576:
+   case 2578:
+   case 2580:
+   case 2582:
+   case 2584:
+   case 2586:
+   case 2588:
+   case 2590:
+   case 2592:
+   case 2594:
+   case 2596:
+   case 2598:
+   case 2600:
+   case 2602:
+   case 2604:
+   case 2606:
+   case 2608:
+   case 2610:
+   case 2612:
+   case 2614:
+   case 2616:
+   case 2618:
+   case 2620:
+   case 2622:
+   case 2624:
+   case 2626:
+   case 2628:
+   case 2630:
+   case 2632:
+   case 2634:
+   case 2636:
+   case 2638:
+   case 2640:
+   case 2642:
+   case 2644:
+   case 2646:
+   case 2648:
+   case 2650:
+   case 2652:
+   case 2654:
+   case 2656:
+   case 2658:
+   case 2660:
+   case 2662:
+   case 2664:
+   case 2666:
+   case 2668:
+   case 2670:
+   case 2672:
+   case 2674:
+   case 2676:
+   case 2678:
+   case 2680:
+   case 2682:
+   case 2684:
+   case 2686:
+   case 2688:
+   case 2690:
+   case 2692:
+   case 2694:
+   case 2696:
+   case 2698:
+   case 2700:
+   case 2702:
+   case 2704:
+   case 2706:
+   case 2708:
+   case 2710:
+   case 2712:
+   case 2714:
+   case 2716:
+   case 2718:
+   case 2720:
+   case 2722:
+   case 2724:
+   case 2726:
+   case 2728:
+   case 2730:
+   case 2732:
+   case 2734:
+   case 2736:
+   case 2738:
+   case 2740:
+   case 2742:
+   case 2744:
+   case 2746:
+   case 2748:
+   case 2750:
+   case 2752:
+   case 2754:
+   case 2756:
+   case 2758:
+   case 2760:
+   case 2762:
+   case 2764:
+   case 2766:
+   case 2768:
+   case 2770:
+   case 2772:
+   case 2774:
+   case 2776:
+   case 2778:
+   case 2780:
+   case 2782:
+   case 2784:
+   case 2786:
+   case 2788:
+   case 2790:
+   case 2792:
+   case 2794:
+   case 2796:
+   case 2798:
+   case 2800:
+   case 2802:
+   case 2804:
+   case 2806:
+   case 2808:
+   case 2810:
+   case 2812:
+   case 2814:
+   case 2816:
+   case 2818:
+   case 2820:
+   case 2822:
+   case 2824:
+   case 2826:
+   case 2828:
+   case 2830:
+   case 2832:
+   case 2834:
+   case 2836:
+   case 2838:
+   case 2840:
+   case 2842:
+   case 2844:
+   case 2846:
+   case 2848:
+   case 2850:
+   case 2852:
+   case 2854:
+   case 2856:
+   case 2858:
+   case 2860:
+   case 2862:
+   case 2864:
+   case 2866:
+   case 2868:
+   case 2870:
+   case 2872:
+   case 2874:
+   case 2876:
+   case 2878:
+   case 2880:
+   case 2882:
+   case 2884:
+   case 2886:
+   case 2888:
+   case 2890:
+   case 2892:
+   case 2894:
+   case 2896:
+   case 2898:
+   case 2900:
+   case 2902:
+   case 2904:
+   case 2906:
+   case 2908:
+   case 2910:
+   case 2912:
+   case 2914:
+   case 2916:
+   case 2918:
+   case 2920:
+   case 2922:
+   case 2924:
+   case 2926:
+   case 2928:
+   case 2930:
+   case 2932:
+   case 2934:
+   case 2936:
+   case 2938:
+   case 2940:
+   case 2942:
+   case 2944:
+   case 2946:
+   case 2948:
+   case 2950:
+   case 2952:
+   case 2954:
+   case 2956:
+   case 2958:
+   case 2960:
+   case 2962:
+   case 2964:
+   case 2966:
+   case 2968:
+   case 2970:
+   case 2972:
+   case 2974:
+   case 2976:
+   case 2978:
+   case 2980:
+   case 2982:
+   case 2984:
+   case 2986:
+   case 2988:
+   case 2990:
+   case 2992:
+   case 2994:
+   case 2996:
+   case 2998:
+   case 3e3:
+   case 3002:
+   case 3004:
+   case 3006:
+   case 3008:
+   case 3010:
+   case 3012:
+   case 3014:
+   case 3016:
+   case 3018:
+   case 3020:
+   case 3022:
+   case 3024:
+   case 3026:
+   case 3028:
+   case 3030:
+   case 3032:
+   case 3034:
+   case 3036:
+   case 3038:
+   case 3040:
+   case 3042:
+   case 3044:
+   case 3046:
+   case 3048:
+   case 3050:
+   case 3052:
+   case 3054:
+   case 3056:
+   case 3058:
+   case 3060:
+   case 3062:
+   case 3064:
+   case 3066:
+   case 3068:
+   case 3070:
+   case 3072:
+   case 3074:
+   case 3076:
+   case 3078:
+   case 3080:
+   case 3082:
+   case 3084:
+   case 3086:
+   case 3088:
+   case 3090:
+   case 3092:
+   case 3094:
+   case 3096:
+   case 3098:
+   case 3100:
+   case 3102:
+   case 3104:
+   case 3106:
+   case 3108:
+   case 3110:
+   case 3112:
+   case 3114:
+   case 3116:
+   case 3118:
+   case 3120:
+   case 3122:
+   case 3124:
+   case 3126:
+   case 3128:
+   case 3130:
+   case 3132:
+   case 3134:
+   case 3136:
+   case 3138:
+   case 3140:
+   case 3142:
+   case 3144:
+   case 3146:
+   case 3148:
+   case 3150:
+   case 3152:
+   case 3154:
+   case 3156:
+   case 3158:
+   case 3160:
+   case 3162:
+   case 3164:
+   case 3166:
+   case 3168:
+   case 3170:
+   case 3172:
+   case 3174:
+   case 3176:
+   case 3178:
+   case 3180:
+   case 3182:
+   case 3184:
+   case 3186:
+   case 3188:
+   case 3190:
+   case 3192:
+   case 3194:
+   case 3196:
+   case 3198:
+   case 3200:
+   case 3202:
+   case 3204:
+   case 3206:
+   case 3208:
+   case 3210:
+   case 3212:
+   case 3214:
+   case 3216:
+   case 3218:
+   case 3220:
+   case 3222:
+   case 3224:
+   case 3226:
+   case 3228:
+   case 3230:
+   case 3232:
+   case 3234:
+   case 3236:
+   case 3238:
+   case 3240:
+   case 3242:
+   case 3244:
+   case 3246:
+   case 3248:
+   case 3250:
+   case 3252:
+   case 3254:
+   case 3256:
+   case 3258:
+   case 3260:
+   case 3262:
+   case 3264:
+   case 3266:
+   case 3268:
+   case 3270:
+   case 3272:
+   case 3274:
+   case 3276:
+   case 3278:
+   case 3280:
+   case 3282:
+   case 3284:
+   case 3286:
+   case 3288:
+   case 3290:
+   case 3292:
+   case 3294:
+   case 3296:
+   case 3298:
+   case 3300:
+   case 3302:
+   case 3304:
+   case 3306:
+   case 3308:
+   case 3310:
+   case 3312:
+   case 3314:
+   case 3316:
+   case 3318:
+   case 3320:
+   case 3322:
+   case 3324:
+   case 3326:
+   case 3328:
+   case 3330:
+   case 3332:
+   case 3334:
+   case 3336:
+   case 3338:
+   case 3340:
+   case 3342:
+   case 3344:
+   case 3346:
+   case 3348:
+   case 3350:
+   case 3352:
+   case 3354:
+   case 3356:
+   case 3358:
+   case 3360:
+   case 3362:
+   case 3364:
+   case 3366:
+   case 3368:
+   case 3370:
+   case 3372:
+   case 3374:
+   case 3376:
+   case 3378:
+   case 3380:
+   case 3382:
+   case 3384:
+   case 3386:
+   case 3388:
+   case 3390:
+   case 3392:
+   case 3394:
+   case 3396:
+   case 3398:
+   case 3400:
+   case 3402:
+   case 3404:
+   case 3406:
+   case 3408:
+   case 3410:
+   case 3412:
+   case 3414:
+   case 3416:
+   case 3418:
+   case 3420:
+   case 3422:
+   case 3424:
+   case 3426:
+   case 3428:
+   case 3430:
+   case 3432:
+   case 3434:
+   case 3436:
+   case 3438:
+   case 3440:
+   case 3442:
+   case 3444:
+   case 3446:
+   case 3448:
+   case 3450:
+   case 3452:
+   case 3454:
+   case 3456:
+   case 3458:
+   case 3460:
+   case 3462:
+   case 3464:
+   case 3466:
+   case 3468:
+   case 3470:
+   case 3472:
+   case 3474:
+   case 3476:
+   case 3478:
+   case 3480:
+   case 3482:
+   case 3484:
+   case 3486:
+   case 3488:
+   case 3490:
+   case 3492:
+   case 3494:
+   case 3496:
+   case 3498:
+   case 3500:
+   case 3502:
+   case 3504:
+   case 3506:
+   case 3508:
+   case 3510:
+   case 3512:
+   case 3514:
+   case 3516:
+   case 3518:
+   case 3520:
+   case 3522:
+   case 3524:
+   case 3526:
+   case 3528:
+   case 3530:
+   case 3532:
+   case 3534:
+   case 3536:
+   case 3538:
+   case 3540:
+   case 3542:
+   case 3544:
+   case 3546:
+   case 3548:
+   case 3550:
+   case 3552:
+   case 3554:
+   case 3556:
+   case 3558:
+   case 3560:
+   case 3562:
+   case 3564:
+   case 3566:
+   case 3568:
+   case 3570:
+   case 3572:
+   case 3574:
+   case 3576:
+   case 3578:
+   case 3580:
+   case 3582:
+   case 3584:
+   case 3586:
+   case 3588:
+   case 3590:
+   case 3592:
+   case 3594:
+   case 3596:
+   case 3598:
+   case 3600:
+   case 3602:
+   case 3604:
+   case 3606:
+   case 3608:
+   case 3610:
+   case 3612:
+   case 3614:
+   case 3616:
+   case 3618:
+   case 3620:
+   case 3622:
+   case 3624:
+   case 3626:
+   case 3628:
+   case 3630:
+   case 3632:
+   case 3634:
+   case 3636:
+   case 3638:
+   case 3640:
+   case 3642:
+   case 3644:
+   case 3646:
+   case 3648:
+   case 3650:
+   case 3652:
+   case 3654:
+   case 3656:
+   case 3658:
+   case 3660:
+   case 3662:
+   case 3664:
+   case 3666:
+   case 3668:
+   case 3670:
+   case 3672:
+   case 3674:
+   case 3676:
+   case 3678:
+   case 3680:
+   case 3682:
+   case 3684:
+   case 3686:
+   case 3688:
+   case 3690:
+   case 3692:
+   case 3694:
+   case 3696:
+   case 3698:
+   case 3700:
+   case 3702:
+   case 3704:
+   case 3706:
+   case 3708:
+   case 3710:
+   case 3712:
+   case 3714:
+   case 3716:
+   case 3718:
+   case 3720:
+   case 3722:
+   case 3724:
+   case 3726:
+   case 3728:
+   case 3730:
+   case 3732:
+   case 3734:
+   case 3736:
+   case 3738:
+   case 3740:
+   case 3742:
+   case 3744:
+   case 3746:
+   case 3748:
+   case 3750:
+   case 3752:
+   case 3754:
+   case 3756:
+   case 3758:
+   case 3760:
+   case 3762:
+   case 3764:
+   case 3766:
+   case 3768:
+   case 3770:
+   case 3772:
+   case 3774:
+   case 3776:
+   case 3778:
+   case 3780:
+   case 3782:
+   case 3784:
+   case 3786:
+   case 3788:
+   case 3790:
+   case 3792:
+   case 3794:
+   case 3796:
+   case 3798:
+   case 3800:
+   case 3802:
+   case 3804:
+   case 3806:
+   case 3808:
+   case 3810:
+   case 3812:
+   case 3814:
+   case 3816:
+   case 3818:
+   case 3820:
+   case 3822:
+   case 3824:
+   case 3826:
+   case 3828:
+   case 3830:
+   case 3832:
+   case 3834:
+   case 3836:
+   case 3838:
+   case 3840:
+   case 3842:
+   case 3844:
+   case 3846:
+   case 3848:
+   case 3850:
+   case 3852:
+   case 3854:
+   case 3856:
+   case 3858:
+   case 3860:
+   case 3862:
+   case 3864:
+   case 3866:
+   case 3868:
+   case 3870:
+   case 3872:
+   case 3874:
+   case 3876:
+   case 3878:
+   case 3880:
+   case 3882:
+   case 3884:
+   case 3886:
+   case 3888:
+   case 3890:
+   case 3892:
+   case 3894:
+   case 3896:
+   case 3898:
+   case 3900:
+   case 3902:
+   case 3904:
+   case 3906:
+   case 3908:
+   case 3910:
+   case 3912:
+   case 3914:
+   case 3916:
+   case 3918:
+   case 3920:
+   case 3922:
+   case 3924:
+   case 3926:
+   case 3928:
+   case 3930:
+   case 3932:
+   case 3934:
+   case 3936:
+   case 3938:
+   case 3940:
+   case 3942:
+   case 3944:
+   case 3946:
+   case 3948:
+   case 3950:
+   case 3952:
+   case 3954:
+   case 3956:
+   case 3958:
+   case 3960:
+   case 3962:
+   case 3964:
+   case 3966:
+   case 3968:
+   case 3970:
+   case 3972:
+   case 3974:
+   case 3976:
+   case 3978:
+   case 3980:
+   case 3982:
+   case 3984:
+   case 3986:
+   case 3988:
+   case 3990:
+   case 3992:
+   case 3994:
+   case 3996:
+   case 3998:
+   case 4e3:
+   case 4002:
+   case 4004:
+   case 4006:
+   case 4008:
+   case 4010:
+   case 4012:
+   case 4014:
+   case 4016:
+   case 4018:
+   case 4020:
+   case 4022:
+   case 4024:
+   case 4026:
+   case 4028:
+   case 4030:
+   case 4032:
+   case 4034:
+   case 4036:
+   case 4038:
+   case 4040:
+   case 4042:
+   case 4044:
+   case 4046:
+   case 4048:
+   case 4050:
+   case 4052:
+   case 4054:
+   case 4056:
+   case 4058:
+   case 4060:
+   case 4062:
+   case 4064:
+   case 4066:
+   case 4068:
+   case 4070:
+   case 4072:
+   case 4074:
+   case 4076:
+   case 4078:
+   case 4080:
+   case 4082:
+   case 4084:
+   case 4086:
+   case 4088:
+   case 4090:
+   case 4092:
+   case 4094:
+   case 4096:
+   case 4098:
+   case 4100:
+   case 4102:
+   case 4104:
+   case 4106:
+   case 4108:
+   case 4110:
+   case 4112:
+   case 4114:
+   case 4116:
+   case 4118:
+   case 4120:
+   case 4122:
+   case 4124:
+   case 4126:
+   case 4128:
+   case 4130:
+   case 4132:
+   case 4134:
+   case 4136:
+   case 4138:
+   case 4140:
+   case 4142:
+   case 4144:
+   case 4146:
+   case 4148:
+   case 4150:
+   case 4152:
+   case 4154:
+   case 4156:
+   case 4158:
+   case 4160:
+   case 4162:
+   case 4164:
+   case 4166:
+   case 4168:
+   case 4170:
+   case 4172:
+   case 4174:
+   case 4176:
+   case 4178:
+   case 4180:
+   case 4182:
+   case 4184:
+   case 4186:
+   case 4188:
+   case 4190:
+   case 4192:
+   case 4194:
+   case 4196:
+   case 4198:
+   case 4200:
+   case 4202:
+   case 4204:
+   case 4206:
+   case 4208:
+   case 4210:
+   case 4212:
+   case 4214:
+   case 4216:
+   case 4218:
+   case 4220:
+   case 4222:
+   case 4224:
+   case 4226:
+   case 4228:
+   case 4230:
+   case 4232:
+   case 4234:
+   case 4236:
+   case 4238:
+   case 4240:
+   case 4242:
+   case 4244:
+   case 4246:
+   case 4248:
+   case 4250:
+   case 4252:
+   case 4254:
+   case 4256:
+   case 4258:
+   case 4260:
+   case 4262:
+   case 4264:
+   case 4266:
+   case 4268:
+   case 4270:
+   case 4272:
+   case 4274:
+   case 4276:
+   case 4278:
+   case 4280:
+   case 4282:
+   case 4284:
+   case 4286:
+   case 4288:
+   case 4290:
+   case 4292:
+   case 4294:
+   case 4296:
+   case 4298:
+   case 4300:
+   case 4302:
+   case 4304:
+   case 4306:
+   case 4308:
+   case 4310:
+   case 4312:
+   case 4314:
+   case 4316:
+   case 4318:
+   case 4320:
+   case 4322:
+   case 4324:
+   case 4326:
+   case 4328:
+   case 4330:
+   case 4332:
+   case 4334:
+   case 4336:
+   case 4338:
+   case 4340:
+   case 4342:
+   case 4344:
+   case 4346:
+   case 4348:
+   case 4350:
+   case 4352:
+   case 4354:
+   case 4356:
+   case 4358:
+   case 4360:
+   case 4362:
+   case 4364:
+   case 4366:
+   case 4368:
+   case 4370:
+   case 4372:
+   case 4374:
+   case 4376:
+   case 4378:
+   case 4380:
+   case 4382:
+   case 4384:
+   case 4386:
+   case 4388:
+   case 4390:
+   case 4392:
+   case 4394:
+   case 4396:
+   case 4398:
+   case 4400:
+   case 4402:
+   case 4404:
+   case 4406:
+   case 4408:
+   case 4410:
+   case 4412:
+   case 4414:
+   case 4416:
+   case 4418:
+   case 4420:
+   case 4422:
+   case 4424:
+   case 4426:
+   case 4428:
+   case 4430:
+   case 4432:
+   case 4434:
+   case 4436:
+   case 4438:
+   case 4440:
+   case 4442:
+   case 4444:
+   case 4446:
+   case 4448:
+   case 4450:
+   case 4452:
+   case 4454:
+   case 4456:
+   case 4458:
+   case 4460:
+   case 4462:
+   case 4464:
+   case 4466:
+   case 4468:
+   case 4470:
+   case 4472:
+   case 4474:
+   case 4476:
+   case 4478:
+   case 4480:
+   case 4482:
+   case 4484:
+   case 4486:
+   case 4488:
+   case 4490:
+   case 4492:
+   case 4494:
+   case 4496:
+   case 4498:
+   case 4500:
+   case 4502:
+   case 4504:
+   case 4506:
+   case 4508:
+   case 4510:
+   case 4512:
+   case 4514:
+   case 4516:
+   case 4518:
+   case 4520:
+   case 4522:
+   case 4524:
+   case 4526:
+   case 4528:
+   case 4530:
+   case 4532:
+   case 4534:
+   case 4536:
+   case 4538:
+   case 4540:
+   case 4542:
+   case 4544:
+   case 4546:
+   case 4548:
+   case 4550:
+   case 4552:
+   case 4554:
+   case 4556:
+   case 4558:
+   case 4560:
+   case 4562:
+   case 4564:
+   case 4566:
+   case 4568:
+   case 4570:
+   case 4572:
+   case 4574:
+   case 4576:
+   case 4578:
+   case 4580:
+   case 4582:
+   case 4584:
+   case 4586:
+   case 4588:
+   case 4590:
+   case 4592:
+   case 4594:
+   case 4596:
+   case 4598:
+   case 4600:
+   case 4602:
+   case 4604:
+   case 4606:
+   case 4608:
+   case 4610:
+   case 4612:
+   case 4614:
+   case 4616:
+   case 4618:
+   case 4620:
+   case 4622:
+   case 4624:
+   case 4626:
+   case 4628:
+   case 4630:
+   case 4632:
+   case 4634:
+   case 4636:
+   case 4638:
+   case 4640:
+   case 4642:
+   case 4644:
+   case 4646:
+   case 4648:
+   case 4650:
+   case 4652:
+   case 4654:
+   case 4656:
+   case 4658:
+   case 4660:
+   case 4662:
+   case 4664:
+   case 4666:
+   case 4668:
+   case 4670:
+   case 4672:
+   case 4674:
+   case 4676:
+   case 4678:
+   case 4680:
+   case 4682:
+   case 4684:
+   case 4686:
+   case 4688:
+   case 4690:
+   case 4692:
+   case 4694:
+   case 4696:
+   case 4698:
+   case 4700:
+   case 4702:
+   case 4704:
+   case 4706:
+   case 4708:
+   case 4710:
+   case 4712:
+   case 4714:
+   case 4716:
+   case 4718:
+   case 4720:
+   case 4722:
+   case 4724:
+   case 4726:
+   case 4728:
+   case 4730:
+   case 4732:
+   case 4734:
+   case 4736:
+   case 4738:
+   case 4740:
+   case 4742:
+   case 4744:
+   case 4746:
+   case 4748:
+   case 4750:
+   case 4752:
+   case 4754:
+   case 4756:
+   case 4758:
+   case 4760:
+   case 4762:
+   case 4764:
+   case 4766:
+   case 4768:
+   case 4770:
+   case 4772:
+   case 4774:
+   case 4776:
+   case 4778:
+   case 4780:
+   case 4782:
+   case 4784:
+   case 4786:
+   case 4788:
+   case 4790:
+   case 4792:
+   case 4794:
+   case 4796:
+   case 4798:
+   case 4800:
+   case 4802:
+   case 4804:
+   case 4806:
+   case 4808:
+   case 4810:
+   case 4812:
+   case 4814:
+   case 4816:
+   case 4818:
+   case 4820:
+   case 4822:
+   case 4824:
+   case 4826:
+   case 4828:
+   case 4830:
+   case 4832:
+   case 4834:
+   case 4836:
+   case 4838:
+   case 4840:
+   case 4842:
+   case 4844:
+   case 4846:
+   case 4848:
+   case 4850:
+   case 4852:
+   case 4854:
+   case 4856:
+   case 4858:
+   case 4860:
+   case 4862:
+   case 4864:
+   case 4866:
+   case 4868:
+   case 4870:
+   case 4872:
+   case 4874:
+   case 4876:
+   case 4878:
+   case 4880:
+   case 4882:
+   case 4884:
+   case 4886:
+   case 4888:
+   case 4890:
+   case 4892:
+   case 4894:
+   case 4896:
+   case 4898:
+   case 4900:
+   case 4902:
+   case 4904:
+   case 4906:
+   case 4908:
+   case 4910:
+   case 4912:
+   case 4914:
+   case 4916:
+   case 4918:
+   case 4920:
+   case 4922:
+   case 4924:
+   case 4926:
+   case 4928:
+   case 4930:
+   case 4932:
+   case 4934:
+   case 4936:
+   case 4938:
+   case 4940:
+   case 4942:
+   case 4944:
+   case 4946:
+   case 4948:
+   case 4950:
+   case 4952:
+   case 4954:
+   case 4956:
+   case 4958:
+   case 4960:
+   case 4962:
+   case 4964:
+   case 4966:
+   case 4968:
+   case 4970:
+   case 4972:
+   case 4974:
+   case 4976:
+   case 4978:
+   case 4980:
+   case 4982:
+   case 4984:
+   case 4986:
+   case 4988:
+   case 4990:
+   case 4992:
+   case 4994:
+   case 4996:
+   case 4998:
+   case 5e3:
+   case 5002:
+   case 5004:
+   case 5006:
+   case 5008:
+   case 5010:
+   case 5012:
+   case 5014:
+   case 5016:
+   case 5018:
+   case 5020:
+   case 5022:
+   case 5024:
+   case 5026:
+   case 5028:
+   case 5030:
+   case 5032:
+   case 5034:
+   case 5036:
+   case 5038:
+   case 5040:
+   case 5042:
+   case 5044:
+   case 5046:
+   case 5048:
+   case 5050:
+   case 5052:
+   case 5054:
+   case 5056:
+   case 5058:
+   case 5060:
+   case 5062:
+   case 5064:
+   case 5066:
+   case 5068:
+   case 5070:
+   case 5072:
+   case 5074:
+   case 5076:
+   case 5078:
+   case 5080:
+   case 5082:
+   case 5084:
+   case 5086:
+   case 5088:
+   case 5090:
+   case 5092:
+   case 5094:
+   case 5096:
+   case 5098:
+   case 5100:
+   case 5102:
+   case 5104:
+   case 5106:
+   case 5108:
+   case 5110:
+   case 5112:
+   case 5114:
+   case 5116:
+   case 5118:
+   case 5120:
+   case 5122:
+   case 5124:
+   case 5126:
+   case 5128:
+   case 5130:
+   case 5132:
+   case 5134:
+   case 5136:
+   case 5138:
+   case 5140:
+   case 5142:
+   case 5144:
+   case 5146:
+   case 5148:
+   case 5150:
+   case 5152:
+   case 5154:
+   case 5156:
+   case 5158:
+   case 5160:
+   case 5162:
+   case 5164:
+   case 5166:
+   case 5168:
+   case 5170:
+   case 5172:
+   case 5174:
+   case 5176:
+   case 5178:
+   case 5180:
+   case 5182:
+   case 5184:
+   case 5186:
+   case 5188:
+   case 5190:
+   case 5192:
+   case 5194:
+   case 5196:
+   case 5198:
+   case 5200:
+   case 5202:
+   case 5204:
+   case 5206:
+   case 5208:
+   case 5210:
+   case 5212:
+   case 5214:
+   case 5216:
+   case 5218:
+   case 5220:
+   case 5222:
+   case 5224:
+   case 5226:
+   case 5228:
+   case 5230:
+   case 5232:
+   case 5234:
+   case 5236:
+   case 5238:
+   case 5240:
+   case 5242:
+   case 5244:
+   case 5246:
+   case 5248:
+   case 5250:
+   case 5252:
+   case 5254:
+   case 5256:
+   case 5258:
+   case 5260:
+   case 5262:
+   case 5264:
+   case 5266:
+   case 5268:
+   case 5270:
+   case 5272:
+   case 5274:
+   case 5276:
+   case 5278:
+   case 5280:
+   case 5282:
+   case 5284:
+   case 5286:
+   case 5288:
+   case 5290:
+   case 5292:
+   case 5294:
+   case 5296:
+   case 5298:
+   case 5300:
+   case 5302:
+   case 5304:
+   case 5306:
+   case 5308:
+   case 5310:
+   case 5312:
+   case 5314:
+   case 5316:
+   case 5318:
+   case 5320:
+   case 5322:
+   case 5324:
+   case 5326:
+   case 5328:
+   case 5330:
+   case 5332:
+   case 5334:
+   case 5336:
+   case 5338:
+   case 5340:
+   case 5342:
+   case 5344:
+   case 5346:
+   case 5348:
+   case 5350:
+   case 5352:
+   case 5354:
+   case 5356:
+   case 5358:
+   case 5360:
+   case 5362:
+   case 5364:
+   case 5366:
+   case 5368:
+   case 5370:
+   case 5372:
+   case 5374:
+   case 5376:
+   case 5378:
+   case 5380:
+   case 5382:
+   case 5384:
+   case 5386:
+   case 5388:
+   case 5390:
+   case 5392:
+   case 5394:
+   case 5396:
+   case 5398:
+   case 5400:
+   case 5402:
+   case 5404:
+   case 5406:
+   case 5408:
+   case 5410:
+   case 5412:
+   case 5414:
+   case 5416:
+   case 5418:
+   case 5420:
+   case 5422:
+   case 5424:
+   case 5426:
+   case 5428:
+   case 5430:
+   case 5432:
+   case 5434:
+   case 5436:
+   case 5438:
+   case 5440:
+   case 5442:
+   case 5444:
+   case 5446:
+   case 5448:
+   case 5450:
+   case 5452:
+   case 5454:
+   case 5456:
+   case 5458:
+   case 5460:
+   case 5462:
+   case 5464:
+   case 5466:
+   case 5468:
+   case 5470:
+   case 5472:
+   case 5474:
+   case 5476:
+   case 5478:
+   case 5480:
+   case 5482:
+   case 5484:
+   case 5486:
+   case 5488:
+   case 5490:
+   case 5492:
+   case 5494:
+   case 5496:
+   case 5498:
+   case 5500:
+   case 5502:
+   case 5504:
+   case 5506:
+   case 5508:
+   case 5510:
+   case 5512:
+   case 5514:
+   case 5516:
+   case 5518:
+   case 5520:
+   case 5522:
+   case 5524:
+   case 5526:
+   case 5528:
+   case 5530:
+   case 5532:
+   case 5534:
+   case 5536:
+   case 5538:
+   case 5540:
+   case 5542:
+   case 5544:
+   case 5546:
+   case 5548:
+   case 5550:
+   case 5552:
+   case 5554:
+   case 5556:
+   case 5558:
+   case 5560:
+   case 5562:
+   case 5564:
+   case 5566:
+   case 5568:
+   case 5570:
+   case 5572:
+   case 5574:
+   case 5576:
+   case 5578:
+   case 5580:
+   case 5582:
+   case 5584:
+   case 5586:
+   case 5588:
+   case 5590:
+   case 5592:
+   case 5594:
+   case 5596:
+   case 5598:
+   case 5600:
+   case 5602:
+   case 5604:
+   case 5606:
+   case 5608:
+   case 5610:
+   case 5612:
+   case 5614:
+   case 5616:
+   case 5618:
+   case 5620:
+   case 5622:
+   case 5624:
+   case 5626:
+   case 5628:
+   case 5630:
+   case 5632:
+   case 5634:
+   case 5636:
+   case 5638:
+   case 5640:
+   case 5642:
+   case 5644:
+   case 5646:
+   case 5648:
+   case 5650:
+   case 5652:
+   case 5654:
+   case 5656:
+   case 5658:
+   case 5660:
+   case 5662:
+   case 5664:
+   case 5666:
+   case 5668:
+   case 5670:
+   case 5672:
+   case 5674:
+   case 5676:
+   case 5678:
+   case 5680:
+   case 5682:
+   case 5684:
+   case 5686:
+   case 5688:
+   case 5690:
+   case 5692:
+   case 5694:
+   case 5696:
+   case 5698:
+   case 5700:
+   case 5702:
+   case 5704:
+   case 5706:
+   case 5708:
+   case 5710:
+   case 5712:
+   case 5714:
+   case 5716:
+   case 5718:
+   case 5720:
+   case 5722:
+   case 5724:
+   case 5726:
+   case 5728:
+   case 5730:
+   case 5732:
+   case 5734:
+   case 5736:
+   case 5738:
+   case 5740:
+   case 5742:
+   case 5744:
+   case 5746:
+   case 5748:
+   case 5750:
+   case 5752:
+   case 5754:
+   case 5756:
+   case 5758:
+   case 5760:
+   case 5762:
+   case 5764:
+   case 5766:
+   case 5768:
+   case 5770:
+   case 5772:
+   case 5774:
+   case 5776:
+   case 5778:
+   case 5780:
+   case 5782:
+   case 5784:
+   case 5786:
+   case 5788:
+   case 5790:
+   case 5792:
+   case 5794:
+   case 5796:
+   case 5798:
+   case 5800:
+   case 5802:
+   case 5804:
+   case 5806:
+   case 5808:
+   case 5810:
+   case 5812:
+   case 5814:
+   case 5816:
+   case 5818:
+   case 5820:
+   case 5822:
+   case 5824:
+   case 5826:
+   case 5828:
+   case 5830:
+   case 5832:
+   case 5834:
+   case 5836:
+   case 5838:
+   case 5840:
+   case 5842:
+   case 5844:
+   case 5846:
+   case 5848:
+   case 5850:
+   case 5852:
+   case 5854:
+   case 5856:
+   case 5858:
+   case 5860:
+   case 5862:
+   case 5864:
+   case 5866:
+   case 5868:
+   case 5870:
+   case 5872:
+   case 5874:
+   case 5876:
+   case 5878:
+   case 5880:
+   case 5882:
+   case 5884:
+   case 5886:
+   case 5888:
+   case 5890:
+   case 5892:
+   case 5894:
+   case 5896:
+   case 5898:
+   case 5900:
+   case 5902:
+   case 5904:
+   case 5906:
+   case 5908:
+   case 5910:
+   case 5912:
+   case 5914:
+   case 5916:
+   case 5918:
+   case 5920:
+   case 5922:
+   case 5924:
+   case 5926:
+   case 5928:
+   case 5930:
+   case 5932:
+   case 5934:
+   case 5936:
+   case 5938:
+   case 5940:
+   case 5942:
+   case 5944:
+   case 5946:
+   case 5948:
+   case 5950:
+   case 5952:
+   case 5954:
+   case 5956:
+   case 5958:
+   case 5960:
+   case 5962:
+   case 5964:
+   case 5966:
+   case 5968:
+   case 5970:
+   case 5972:
+   case 5974:
+   case 5976:
+   case 5978:
+   case 5980:
+   case 5982:
+   case 5984:
+   case 5986:
+   case 5988:
+   case 5990:
+   case 5992:
+   case 5994:
+   case 5996:
+   case 5998:
+   case 6e3:
+   case 6002:
+   case 6004:
+   case 6006:
+   case 6008:
+   case 6010:
+   case 6012:
+   case 6014:
+   case 6016:
+   case 6018:
+   case 6020:
+   case 6022:
+   case 6024:
+   case 6026:
+   case 6028:
+   case 6030:
+   case 6032:
+   case 6034:
+   case 6036:
+   case 6038:
+   case 6040:
+   case 6042:
+   case 6044:
+   case 6046:
+   case 6048:
+   case 6050:
+   case 6052:
+   case 6054:
+   case 6056:
+   case 6058:
+   case 6060:
+   case 6062:
+   case 6064:
+   case 6066:
+   case 6068:
+   case 6070:
+   case 6072:
+   case 6074:
+   case 6076:
+   case 6078:
+   case 6080:
+   case 6082:
+   case 6084:
+   case 6086:
+   case 6088:
+   case 6090:
+   case 6092:
+   case 6094:
+   case 6096:
+   case 6098:
+   case 6100:
+   case 6102:
+   case 6104:
+   case 6106:
+   case 6108:
+   case 6110:
+   case 6112:
+   case 6114:
+   case 6116:
+   case 6118:
+   case 6120:
+   case 6122:
+   case 6124:
+   case 6126:
+   case 6128:
+   case 6130:
+   case 6132:
+   case 6134:
+   case 6136:
+   case 6138:
+   case 6140:
+   case 6142:
+   case 6144:
+   case 6146:
+   case 6148:
+   case 6150:
+   case 6152:
+   case 6154:
+   case 6156:
+   case 6158:
+   case 6160:
+   case 6162:
+   case 6164:
+   case 6166:
+   case 6168:
+   case 6170:
+   case 6172:
+   case 6174:
+   case 6176:
+   case 6178:
+   case 6180:
+   case 6182:
+   case 6184:
+   case 6186:
+   case 6188:
+   case 6190:
+   case 6192:
+   case 6194:
+   case 6196:
+   case 6198:
+   case 6200:
+   case 6202:
+   case 6204:
+   case 6206:
+   case 6208:
+   case 6210:
+   case 6212:
+   case 6214:
+   case 6216:
+   case 6218:
+   case 6220:
+   case 6222:
+   case 6224:
+   case 6226:
+   case 6228:
+   case 6230:
+   case 6232:
+   case 6234:
+   case 6236:
+   case 6238:
+   case 6240:
+   case 6242:
+   case 6244:
+   case 6246:
+   case 6248:
+   case 6250:
+   case 6252:
+   case 6254:
+   case 6256:
+   case 6258:
+   case 6260:
+   case 6262:
+   case 6264:
+   case 6266:
+   case 6268:
+   case 6270:
+   case 6272:
+   case 6274:
+   case 6276:
+   case 6278:
+   case 6280:
+   case 6282:
+   case 6284:
+   case 6286:
+   case 6288:
+   case 6290:
+   case 6292:
+   case 6294:
+   case 6296:
+   case 6298:
+   case 6300:
+   case 6302:
+   case 6304:
+   case 6306:
+   case 6308:
+   case 6310:
+   case 6312:
+   case 6314:
+   case 6316:
+   case 6318:
+   case 6320:
+   case 6322:
+   case 6324:
+   case 6326:
+   case 6328:
+   case 6330:
+   case 6332:
+   case 6334:
+   case 6336:
+   case 6338:
+   case 6340:
+   case 6342:
+   case 6344:
+   case 6346:
+   case 6348:
+   case 6350:
+   case 6352:
+   case 6354:
+   case 6356:
+   case 6358:
+   case 6360:
+   case 6362:
+   case 6364:
+   case 6366:
+   case 6368:
+   case 6370:
+   case 6372:
+   case 6374:
+   case 6376:
+   case 6378:
+   case 6380:
+   case 6382:
+   case 6384:
+   case 6386:
+   case 6388:
+   case 6390:
+   case 6392:
+   case 6394:
+   case 6396:
+   case 6398:
+   case 6400:
+   case 6402:
+   case 6404:
+   case 6406:
+   case 6408:
+   case 6410:
+   case 6412:
+   case 6414:
+   case 6416:
+   case 6418:
+   case 6420:
+   case 6422:
+   case 6424:
+   case 6426:
+   case 6428:
+   case 6430:
+   case 6432:
+   case 6434:
+   case 6436:
+   case 6438:
+   case 6440:
+   case 6442:
+   case 6444:
+   case 6446:
+   case 6448:
+   case 6450:
+   case 6452:
+   case 6454:
+   case 6456:
+   case 6458:
+   case 6460:
+   case 6462:
+   case 6464:
+   case 6466:
+   case 6468:
+   case 6470:
+   case 6472:
+   case 6474:
+   case 6476:
+   case 6478:
+   case 6480:
+   case 6482:
+   case 6484:
+   case 6486:
+   case 6488:
+   case 6490:
+   case 6492:
+   case 6494:
+   case 6496:
+   case 6498:
+   case 6500:
+   case 6502:
+   case 6504:
+   case 6506:
+   case 6508:
+   case 6510:
+   case 6512:
+   case 6514:
+   case 6516:
+   case 6518:
+   case 6520:
+   case 6522:
+   case 6524:
+   case 6526:
+   case 6528:
+   case 6530:
+   case 6532:
+   case 6534:
+   case 6536:
+   case 6538:
+   case 6540:
+   case 6542:
+   case 6544:
+   case 6546:
+   case 6548:
+   case 6550:
+   case 6552:
+   case 6554:
+   case 6556:
+   case 6558:
+   case 6560:
+   case 6562:
+   case 6564:
+   case 6566:
+   case 6568:
+   case 6570:
+   case 6572:
+   case 6574:
+   case 6576:
+   case 6578:
+   case 6580:
+   case 6582:
+   case 6584:
+   case 6586:
+   case 6588:
+   case 6590:
+   case 6592:
+   case 6594:
+   case 6596:
+   case 6598:
+   case 6600:
+   case 6602:
+   case 6604:
+   case 6606:
+   case 6608:
+   case 6610:
+   case 6612:
+   case 6614:
+   case 6616:
+   case 6618:
+   case 6620:
+   case 6622:
+   case 6624:
+   case 6626:
+   case 6628:
+   case 6630:
+   case 6632:
+   case 6634:
+   case 6636:
+   case 6638:
+   case 6640:
+   case 6642:
+   case 6644:
+   case 6646:
+   case 6648:
+   case 6650:
+   case 6652:
+   case 6654:
+   case 6656:
+   case 6658:
+   case 6660:
+   case 6662:
+   case 6664:
+   case 6666:
+   case 6668:
+   case 6670:
+   case 6672:
+   case 6674:
+   case 6676:
+   case 6678:
+   case 6680:
+   case 6682:
+   case 6684:
+   case 6686:
+   case 6688:
+   case 6690:
+   case 6692:
+   case 6694:
+   case 6696:
+   case 6698:
+   case 6700:
+   case 6702:
+   case 6704:
+   case 6706:
+   case 6708:
+   case 6710:
+   case 6712:
+   case 6714:
+   case 6716:
+   case 6718:
+   case 6720:
+   case 6722:
+   case 6724:
+   case 6726:
+   case 6728:
+   case 6730:
+   case 6732:
+   case 6734:
+   case 6736:
+   case 6738:
+   case 6740:
+   case 6742:
+   case 6744:
+   case 6746:
+   case 6748:
+   case 6750:
+   case 6752:
+   case 6754:
+   case 6756:
+   case 6758:
+   case 6760:
+   case 6762:
+   case 6764:
+   case 6766:
+   case 6768:
+   case 6770:
+   case 6772:
+   case 6774:
+   case 6776:
+   case 6778:
+   case 6780:
+   case 6782:
+   case 6784:
+   case 6786:
+   case 6788:
+   case 6790:
+   case 6792:
+   case 6794:
+   case 6796:
+   case 6798:
+   case 6800:
+   case 6802:
+   case 6804:
+   case 6806:
+   case 6808:
+   case 6810:
+   case 6812:
+   case 6814:
+   case 6816:
+   case 6818:
+   case 6820:
+   case 6822:
+   case 6824:
+   case 6826:
+   case 6828:
+   case 6830:
+   case 6832:
+   case 6834:
+   case 6836:
+   case 6838:
+   case 6840:
+   case 6842:
+   case 6844:
+   case 6846:
+   case 6848:
+   case 6850:
+   case 6852:
+   case 6854:
+   case 6856:
+   case 6858:
+   case 6860:
+   case 6862:
+   case 6864:
+   case 6866:
+   case 6868:
+   case 6870:
+   case 6872:
+   case 6874:
+   case 6876:
+   case 6878:
+   case 6880:
+   case 6882:
+   case 6884:
+   case 6886:
+   case 6888:
+   case 6890:
+   case 6892:
+   case 6894:
+   case 6896:
+   case 6898:
+   case 6900:
+   case 6902:
+   case 6904:
+   case 6906:
+   case 6908:
+   case 6910:
+   case 6912:
+   case 6914:
+   case 6916:
+   case 6918:
+   case 6920:
+   case 6922:
+   case 6924:
+   case 6926:
+   case 6928:
+   case 6930:
+   case 6932:
+   case 6934:
+   case 6936:
+   case 6938:
+   case 6940:
+   case 6942:
+   case 6944:
+   case 6946:
+   case 6948:
+   case 6950:
+   case 6952:
+   case 6954:
+   case 6956:
+   case 6958:
+   case 6960:
+   case 6962:
+   case 6964:
+   case 6966:
+   case 6968:
+   case 6970:
+   case 6972:
+   case 6974:
+   case 6976:
+   case 6978:
+   case 6980:
+   case 6982:
+   case 6984:
+   case 6986:
+   case 6988:
+   case 6990:
+   case 6992:
+   case 6994:
+   case 6996:
+   case 6998:
+   case 7e3:
+   case 7002:
+   case 7004:
+   case 7006:
+   case 7008:
+   case 7010:
+   case 7012:
+   case 7014:
+   case 7016:
+   case 7018:
+   case 7020:
+   case 7022:
+   case 7024:
+   case 7026:
+   case 7028:
+   case 7030:
+   case 7032:
+   case 7034:
+   case 7036:
+   case 7038:
+   case 7040:
+   case 7042:
+   case 7044:
+   case 7046:
+   case 7048:
+   case 7050:
+   case 7052:
+   case 7054:
+   case 7056:
+   case 7058:
+   case 7060:
+   case 7062:
+   case 7064:
+   case 7066:
+   case 7068:
+   case 7070:
+   case 7072:
+   case 7074:
+   case 7076:
+   case 7078:
+   case 7080:
+   case 7082:
+   case 7084:
+   case 7086:
+   case 7088:
+   case 7090:
+   case 7092:
+   case 7094:
+   case 7096:
+   case 7098:
+   case 7100:
+   case 7102:
+   case 7104:
+   case 7106:
+   case 7108:
+   case 7110:
+   case 7112:
+   case 7114:
+   case 7116:
+   case 7118:
+   case 7120:
+   case 7122:
+   case 7124:
+   case 7126:
+   case 7128:
+   case 7130:
+   case 7132:
+   case 7134:
+   case 7136:
+   case 7138:
+   case 7140:
+   case 7142:
+   case 7144:
+   case 7146:
+   case 7148:
+   case 7150:
+   case 7152:
+   case 7154:
+   case 7156:
+   case 7158:
+   case 7160:
+   case 7162:
+   case 7164:
+   case 7166:
+   case 7168:
+   case 7170:
+   case 7172:
+   case 7174:
+   case 7176:
+   case 7178:
+   case 7180:
+   case 7182:
+   case 7184:
+   case 7186:
+   case 7188:
+   case 7190:
+   case 7192:
+   case 7194:
+   case 7196:
+   case 7198:
+   case 7200:
+   case 7202:
+   case 7204:
+   case 7206:
+   case 7208:
+   case 7210:
+   case 7212:
+   case 7214:
+   case 7216:
+   case 7218:
+   case 7220:
+   case 7222:
+   case 7224:
+   case 7226:
+   case 7228:
+   case 7230:
+   case 7232:
+   case 7234:
+   case 7236:
+   case 7238:
+   case 7240:
+   case 7242:
+   case 7244:
+   case 7246:
+   case 7248:
+   case 7250:
+   case 7252:
+   case 7254:
+   case 7256:
+   case 7258:
+   case 7260:
+   case 7262:
+   case 7264:
+   case 7266:
+   case 7268:
+   case 7270:
+   case 7272:
+   case 7274:
+   case 7276:
+   case 7278:
+   case 7280:
+   case 7282:
+   case 7284:
+   case 7286:
+   case 7288:
+   case 7290:
+   case 7292:
+   case 7294:
+   case 7296:
+   case 7298:
+   case 7300:
+   case 7302:
+   case 7304:
+   case 7306:
+   case 7308:
+   case 7310:
+   case 7312:
+   case 7314:
+   case 7316:
+   case 7318:
+   case 7320:
+   case 7322:
+   case 7324:
+   case 7326:
+   case 7328:
+   case 7330:
+   case 7332:
+   case 7334:
+   case 7336:
+   case 7338:
+   case 7340:
+   case 7342:
+   case 7344:
+   case 7346:
+   case 7348:
+   case 7350:
+   case 7352:
+   case 7354:
+   case 7356:
+   case 7358:
+   case 7360:
+   case 7362:
+   case 7364:
+   case 7366:
+   case 7368:
+   case 7370:
+   case 7372:
+   case 7374:
+   case 7376:
+   case 7378:
+   case 7380:
+   case 7382:
+   case 7384:
+   case 7386:
+   case 7388:
+   case 7390:
+   case 7392:
+   case 7394:
+   case 7396:
+   case 7398:
+   case 7400:
+   case 7402:
+   case 7404:
+   case 7406:
+   case 7408:
+   case 7410:
+   case 7412:
+   case 7414:
+   case 7416:
+   case 7418:
+   case 7420:
+   case 7422:
+   case 7424:
+   case 7426:
+   case 7428:
+   case 7430:
+   case 7432:
+   case 7434:
+   case 7436:
+   case 7438:
+   case 7440:
+   case 7442:
+   case 7444:
+   case 7446:
+   case 7448:
+   case 7450:
+   case 7452:
+   case 7454:
+   case 7456:
+   case 7458:
+   case 7460:
+   case 7462:
+   case 7464:
+   case 7466:
+   case 7468:
+   case 7470:
+   case 7472:
+   case 7474:
+   case 7476:
+   case 7478:
+   case 7480:
+   case 7482:
+   case 7484:
+   case 7486:
+   case 7488:
+   case 7490:
+   case 7492:
+   case 7494:
+   case 7496:
+   case 7498:
+   case 7500:
+   case 7502:
+   case 7504:
+   case 7506:
+   case 7508:
+   case 7510:
+   case 7512:
+   case 7514:
+   case 7516:
+   case 7518:
+   case 7520:
+   case 7522:
+   case 7524:
+   case 7526:
+   case 7528:
+   case 7530:
+   case 7532:
+   case 7534:
+   case 7536:
+   case 7538:
+   case 7540:
+   case 7542:
+   case 7544:
+   case 7546:
+   case 7548:
+   case 7550:
+   case 7552:
+   case 7554:
+   case 7556:
+   case 7558:
+   case 7560:
+   case 7562:
+   case 7564:
+   case 7566:
+   case 7568:
+   case 7570:
+   case 7572:
+   case 7574:
+   case 7576:
+   case 7578:
+   case 7580:
+   case 7582:
+   case 7584:
+   case 7586:
+   case 7588:
+   case 7590:
+   case 7592:
+   case 7594:
+   case 7596:
+   case 7598:
+   case 7600:
+   case 7602:
+   case 7604:
+   case 7606:
+   case 7608:
+   case 7610:
+   case 7612:
+   case 7614:
+   case 7616:
+   case 7618:
+   case 7620:
+   case 7622:
+   case 7624:
+   case 7626:
+   case 7628:
+   case 7630:
+   case 7632:
+   case 7634:
+   case 7636:
+   case 7638:
+   case 7640:
+   case 7642:
+   case 7644:
+   case 7646:
+   case 7648:
+   case 7650:
+   case 7652:
+   case 7654:
+   case 7656:
+   case 7658:
+   case 7660:
+   case 7662:
+   case 7664:
+   case 7666:
+   case 7668:
+   case 7670:
+   case 7672:
+   case 7674:
+   case 7676:
+   case 7678:
+   case 7680:
+   case 7682:
+   case 7684:
+   case 7686:
+   case 7688:
+   case 7690:
+   case 7692:
+   case 7694:
+   case 7696:
+   case 7698:
+   case 7700:
+   case 7702:
+   case 7704:
+   case 7706:
+   case 7708:
+   case 7710:
+   case 7712:
+   case 7714:
+   case 7716:
+   case 7718:
+   case 7720:
+   case 7722:
+   case 7724:
+   case 7726:
+   case 7728:
+   case 7730:
+   case 7732:
+   case 7734:
+   case 7736:
+   case 7738:
+   case 7740:
+   case 7742:
+   case 7744:
+   case 7746:
+   case 7748:
+   case 7750:
+   case 7752:
+   case 7754:
+   case 7756:
+   case 7758:
+   case 7760:
+   case 7762:
+   case 7764:
+   case 7766:
+   case 7768:
+   case 7770:
+   case 7772:
+   case 7774:
+   case 7776:
+   case 7778:
+   case 7780:
+   case 7782:
+   case 7784:
+   case 7786:
+   case 7788:
+   case 7790:
+   case 7792:
+   case 7794:
+   case 7796:
+   case 7798:
+   case 7800:
+   case 7802:
+   case 7804:
+   case 7806:
+   case 7808:
+   case 7810:
+   case 7812:
+   case 7814:
+   case 7816:
+   case 7818:
+   case 7820:
+   case 7822:
+   case 7824:
+   case 7826:
+   case 7828:
+   case 7830:
+   case 7832:
+   case 7834:
+   case 7836:
+   case 7838:
+   case 7840:
+   case 7842:
+   case 7844:
+   case 7846:
+   case 7848:
+   case 7850:
+   case 7852:
+   case 7854:
+   case 7856:
+   case 7858:
+   case 7860:
+   case 7862:
+   case 7864:
+   case 7866:
+   case 7868:
+   case 7870:
+   case 7872:
+   case 7874:
+   case 7876:
+   case 7878:
+   case 7880:
+   case 7882:
+   case 7884:
+   case 7886:
+   case 7888:
+   case 7890:
+   case 7892:
+   case 7894:
+   case 7896:
+   case 7898:
+   case 7900:
+   case 7902:
+   case 7904:
+   case 7906:
+   case 7908:
+   case 7910:
+   case 7912:
+   case 7914:
+   case 7916:
+   case 7918:
+   case 7920:
+   case 7922:
+   case 7924:
+   case 7926:
+   case 7928:
+   case 7930:
+   case 7932:
+   case 7934:
+   case 7936:
+   case 7938:
+   case 7940:
+   case 7942:
+   case 7944:
+   case 7946:
+   case 7948:
+   case 7950:
+   case 7952:
+   case 7954:
+   case 7956:
+   case 7958:
+   case 7960:
+   case 7962:
+   case 7964:
+   case 7966:
+   case 7968:
+   case 7970:
+   case 7972:
+   case 7974:
+   case 7976:
+   case 7978:
+   case 7980:
+   case 7982:
+   case 7984:
+   case 7986:
+   case 7988:
+   case 7990:
+   case 7992:
+   case 7994:
+   case 7996:
+   case 7998:
+   case 8e3:
+   case 8002:
+   case 8004:
+   case 8006:
+   case 8008:
+   case 8010:
+   case 8012:
+   case 8014:
+   case 8016:
+   case 8018:
+   case 8020:
+   case 8022:
+   case 8024:
+   case 8026:
+   case 8028:
+   case 8030:
+   case 8032:
+   case 8034:
+   case 8036:
+   case 8038:
+   case 8040:
+   case 8042:
+   case 8044:
+   case 8046:
+   case 8048:
+   case 8050:
+   case 8052:
+   case 8054:
+   case 8056:
+   case 8058:
+   case 8060:
+   case 8062:
+   case 8064:
+   case 8066:
+   case 8068:
+   case 8070:
+   case 8072:
+   case 8074:
+   case 8076:
+   case 8078:
+   case 8080:
+   case 8082:
+   case 8084:
+   case 8086:
+   case 8088:
+   case 8090:
+   case 8092:
+   case 8094:
+   case 8096:
+   case 8098:
+   case 8100:
+   case 8102:
+   case 8104:
+   case 8106:
+   case 8108:
+   case 8110:
+   case 8112:
+   case 8114:
+   case 8116:
+   case 8118:
+   case 8120:
+   case 8122:
+   case 8124:
+   case 8126:
+   case 8128:
+   case 8130:
+   case 8132:
+   case 8134:
+   case 8136:
+   case 8138:
+   case 8140:
+   case 8142:
+   case 8144:
+   case 8146:
+   case 8148:
+   case 8150:
+   case 8152:
+   case 8154:
+   case 8156:
+   case 8158:
+   case 8160:
+   case 8162:
+   case 8164:
+   case 8166:
+   case 8168:
+   case 8170:
+   case 8172:
+   case 8174:
+   case 8176:
+   case 8178:
+   case 8180:
+   case 8182:
+   case 8184:
+   case 8186:
+   case 8188:
+   case 8190:
+   case 8192:
+   case 8194:
+   case 8196:
+   case 8198:
+   case 8200:
+   case 8202:
+   case 8204:
+   case 8206:
+   case 8208:
+   case 8210:
+   case 8212:
+   case 8214:
+   case 8216:
+   case 8218:
+   case 8220:
+   case 8222:
+   case 8224:
+   case 8226:
+   case 8228:
+   case 8230:
+   case 8232:
+   case 8234:
+   case 8236:
+   case 8238:
+   case 8240:
+   case 8242:
+   case 8244:
+   case 8246:
+   case 8248:
+   case 8250:
+   case 8252:
+   case 8254:
+   case 8256:
+   case 8258:
+   case 8260:
+   case 8262:
+   case 8264:
+   case 8266:
+   case 8268:
+   case 8270:
+   case 8272:
+   case 8274:
+   case 8276:
+   case 8278:
+   case 8280:
+   case 8282:
+   case 8284:
+   case 8286:
+   case 8288:
+   case 8290:
+   case 8292:
+   case 8294:
+   case 8296:
+   case 8298:
+   case 8300:
+   case 8302:
+   case 8304:
+   case 8306:
+   case 8308:
+   case 8310:
+   case 8312:
+   case 8314:
+   case 8316:
+   case 8318:
+   case 8320:
+   case 8322:
+   case 8324:
+   case 8326:
+   case 8328:
+   case 8330:
+   case 8332:
+   case 8334:
+   case 8336:
+   case 8338:
+   case 8340:
+   case 8342:
+   case 8344:
+   case 8346:
+   case 8348:
+   case 8350:
+   case 8352:
+   case 8354:
+   case 8356:
+   case 8358:
+   case 8360:
+   case 8362:
+   case 8364:
+   case 8366:
+   case 8368:
+   case 8370:
+   case 8372:
+   case 8374:
+   case 8376:
+   case 8378:
+   case 8380:
+   case 8382:
+   case 8384:
+   case 8386:
+   case 8388:
+   case 8390:
+   case 8392:
+   case 8394:
+   case 8396:
+   case 8398:
+   case 8400:
+   case 8402:
+   case 8404:
+   case 8406:
+   case 8408:
+   case 8410:
+   case 8412:
+   case 8414:
+   case 8416:
+   case 8418:
+   case 8420:
+   case 8422:
+   case 8424:
+   case 8426:
+   case 8428:
+   case 8430:
+   case 8432:
+   case 8434:
+   case 8436:
+   case 8438:
+   case 8440:
+   case 8442:
+   case 8444:
+   case 8446:
+   case 8448:
+   case 8450:
+   case 8452:
+   case 8454:
+   case 8456:
+   case 8458:
+   case 8460:
+   case 8462:
+   case 8464:
+   case 8466:
+   case 8468:
+   case 8470:
+   case 8472:
+   case 8474:
+   case 8476:
+   case 8478:
+   case 8480:
+   case 8482:
+   case 8484:
+   case 8486:
+   case 8488:
+   case 8490:
+   case 8492:
+   case 8494:
+   case 8496:
+   case 8498:
+   case 8500:
+   case 8502:
+   case 8504:
+   case 8506:
+   case 8508:
+   case 8510:
+   case 8512:
+   case 8514:
+   case 8516:
+   case 8518:
+   case 8520:
+   case 8522:
+   case 8524:
+   case 8526:
+   case 8528:
+   case 8530:
+   case 8532:
+   case 8534:
+   case 8536:
+   case 8538:
+   case 8540:
+   case 8542:
+   case 8544:
+   case 8546:
+   case 8548:
+   case 8550:
+   case 8552:
+   case 8554:
+   case 8556:
+   case 8558:
+   case 8560:
+   case 8562:
+   case 8564:
+   case 8566:
+   case 8568:
+   case 8570:
+   case 8572:
+   case 8574:
+   case 8576:
+   case 8578:
+   case 8580:
+   case 8582:
+   case 8584:
+   case 8586:
+   case 8588:
+   case 8590:
+   case 8592:
+   case 8594:
+   case 8596:
+   case 8598:
+   case 8600:
+   case 8602:
+   case 8604:
+   case 8606:
+   case 8608:
+   case 8610:
+   case 8612:
+   case 8614:
+   case 8616:
+   case 8618:
+   case 8620:
+   case 8622:
+   case 8624:
+   case 8626:
+   case 8628:
+   case 8630:
+   case 8632:
+   case 8634:
+   case 8636:
+   case 8638:
+   case 8640:
+   case 8642:
+   case 8644:
+   case 8646:
+   case 8648:
+   case 8650:
+   case 8652:
+   case 8654:
+   case 8656:
+   case 8658:
+   case 8660:
+   case 8662:
+   case 8664:
+   case 8666:
+   case 8668:
+   case 8670:
+   case 8672:
+   case 8674:
+   case 8676:
+   case 8678:
+   case 8680:
+   case 8682:
+   case 8684:
+   case 8686:
+   case 8688:
+   case 8690:
+   case 8692:
+   case 8694:
+   case 8696:
+   case 8698:
+   case 8700:
+   case 8702:
+   case 8704:
+   case 8706:
+   case 8708:
+   case 8710:
+   case 8712:
+   case 8714:
+   case 8716:
+   case 8718:
+   case 8720:
+   case 8722:
+   case 8724:
+   case 8726:
+   case 8728:
+   case 8730:
+   case 8732:
+   case 8734:
+   case 8736:
+   case 8738:
+   case 8740:
+   case 8742:
+   case 8744:
+   case 8746:
+   case 8748:
+   case 8750:
+   case 8752:
+   case 8754:
+   case 8756:
+   case 8758:
+   case 8760:
+   case 8762:
+   case 8764:
+   case 8766:
+   case 8768:
+   case 8770:
+   case 8772:
+   case 8774:
+   case 8776:
+   case 8778:
+   case 8780:
+   case 8782:
+   case 8784:
+   case 8786:
+   case 8788:
+   case 8790:
+   case 8792:
+   case 8794:
+   case 8796:
+   case 8798:
+   case 8800:
+   case 8802:
+   case 8804:
+   case 8806:
+   case 8808:
+   case 8810:
+   case 8812:
+   case 8814:
+   case 8816:
+   case 8818:
+   case 8820:
+   case 8822:
+   case 8824:
+   case 8826:
+   case 8828:
+   case 8830:
+   case 8832:
+   case 8834:
+   case 8836:
+   case 8838:
+   case 8840:
+   case 8842:
+   case 8844:
+   case 8846:
+   case 8848:
+   case 8850:
+   case 8852:
+   case 8854:
+   case 8856:
+   case 8858:
+   case 8860:
+   case 8862:
+   case 8864:
+   case 8866:
+   case 8868:
+   case 8870:
+   case 8872:
+   case 8874:
+   case 8876:
+   case 8878:
+   case 8880:
+   case 8882:
+   case 8884:
+   case 8886:
+   case 8888:
+   case 8890:
+   case 8892:
+   case 8894:
+   case 8896:
+   case 8898:
+   case 8900:
+   case 8902:
+   case 8904:
+   case 8906:
+   case 8908:
+   case 8910:
+   case 8912:
+   case 8914:
+   case 8916:
+   case 8918:
+   case 8920:
+   case 8922:
+   case 8924:
+   case 8926:
+   case 8928:
+   case 8930:
+   case 8932:
+   case 8934:
+   case 8936:
+   case 8938:
+   case 8940:
+   case 8942:
+   case 8944:
+   case 8946:
+   case 8948:
+   case 8950:
+   case 8952:
+   case 8954:
+   case 8956:
+   case 8958:
+   case 8960:
+   case 8962:
+   case 8964:
+   case 8966:
+   case 8968:
+   case 8970:
+   case 8972:
+   case 8974:
+   case 8976:
+   case 8978:
+   case 8980:
+   case 8982:
+   case 8984:
+   case 8986:
+   case 8988:
+   case 8990:
+   case 8992:
+   case 8994:
+   case 8996:
+   case 8998:
+   case 9e3:
+   case 9002:
+   case 9004:
+   case 9006:
+   case 9008:
+   case 9010:
+   case 9012:
+   case 9014:
+   case 9016:
+   case 9018:
+   case 9020:
+   case 9022:
+   case 9024:
+   case 9026:
+   case 9028:
+   case 9030:
+   case 9032:
+   case 9034:
+   case 9036:
+   case 9038:
+   case 9040:
+   case 9042:
+   case 9044:
+   case 9046:
+   case 9048:
+   case 9050:
+   case 9052:
+   case 9054:
+   case 9056:
+   case 9058:
+   case 9060:
+   case 9062:
+   case 9064:
+   case 9066:
+   case 9068:
+   case 9070:
+   case 9072:
+   case 9074:
+   case 9076:
+   case 9078:
+   case 9080:
+   case 9082:
+   case 9084:
+   case 9086:
+   case 9088:
+   case 9090:
+   case 9092:
+   case 9094:
+   case 9096:
+   case 9098:
+   case 9100:
+   case 9102:
+   case 9104:
+   case 9106:
+   case 9108:
+   case 9110:
+   case 9112:
+   case 9114:
+   case 9116:
+   case 9118:
+   case 9120:
+   case 9122:
+   case 9124:
+   case 9126:
+   case 9128:
+   case 9130:
+   case 9132:
+   case 9134:
+   case 9136:
+   case 9138:
+   case 9140:
+   case 9142:
+   case 9144:
+   case 9146:
+   case 9148:
+   case 9150:
+   case 9152:
+   case 9154:
+   case 9156:
+   case 9158:
+   case 9160:
+   case 9162:
+   case 9164:
+   case 9166:
+   case 9168:
+   case 9170:
+   case 9172:
+   case 9174:
+   case 9176:
+   case 9178:
+   case 9180:
+   case 9182:
+   case 9184:
+   case 9186:
+   case 9188:
+   case 9190:
+   case 9192:
+   case 9194:
+   case 9196:
+   case 9198:
+   case 9200:
+   case 9202:
+   case 9204:
+   case 9206:
+   case 9208:
+   case 9210:
+   case 9212:
+   case 9214:
+   case 9216:
+   case 9218:
+   case 9220:
+   case 9222:
+   case 9224:
+   case 9226:
+   case 9228:
+   case 9230:
+   case 9232:
+   case 9234:
+   case 9236:
+   case 9238:
+   case 9240:
+   case 9242:
+   case 9244:
+   case 9246:
+   case 9248:
+   case 9250:
+   case 9252:
+   case 9254:
+   case 9256:
+   case 9258:
+   case 9260:
+   case 9262:
+   case 9264:
+   case 9266:
+   case 9268:
+   case 9270:
+   case 9272:
+   case 9274:
+   case 9276:
+   case 9278:
+   case 9280:
+   case 9282:
+   case 9284:
+   case 9286:
+   case 9288:
+   case 9290:
+   case 9292:
+   case 9294:
+   case 9296:
+   case 9298:
+   case 9300:
+   case 9302:
+   case 9304:
+   case 9306:
+   case 9308:
+   case 9310:
+   case 9312:
+   case 9314:
+   case 9316:
+   case 9318:
+   case 9320:
+   case 9322:
+   case 9324:
+   case 9326:
+   case 9328:
+   case 9330:
+   case 9332:
+   case 9334:
+   case 9336:
+   case 9338:
+   case 9340:
+   case 9342:
+   case 9344:
+   case 9346:
+   case 9348:
+   case 9350:
+   case 9352:
+   case 9354:
+   case 9356:
+   case 9358:
+   case 9360:
+   case 9362:
+   case 9364:
+   case 9366:
+   case 9368:
+   case 9370:
+   case 9372:
+   case 9374:
+   case 9376:
+   case 9378:
+   case 9380:
+   case 9382:
+   case 9384:
+   case 9386:
+   case 9388:
+   case 9390:
+   case 9392:
+   case 9394:
+   case 9396:
+   case 9398:
+   case 9400:
+   case 9402:
+   case 9404:
+   case 9406:
+   case 9408:
+   case 9410:
+   case 9412:
+   case 9414:
+   case 9416:
+   case 9418:
+   case 9420:
+   case 9422:
+   case 9424:
+   case 9426:
+   case 9428:
+   case 9430:
+   case 9432:
+   case 9434:
+   case 9436:
+   case 9438:
+   case 9440:
+   case 9442:
+   case 9444:
+   case 9446:
+   case 9448:
+   case 9450:
+   case 9452:
+   case 9454:
+   case 9456:
+   case 9458:
+   case 9460:
+   case 9462:
+   case 9464:
+   case 9466:
+   case 9468:
+   case 9470:
+   case 9472:
+   case 9474:
+   case 9476:
+   case 9478:
+   case 9480:
+   case 9482:
+   case 9484:
+   case 9486:
+   case 9488:
+   case 9490:
+   case 9492:
+   case 9494:
+   case 9496:
+   case 9498:
+   case 9500:
+   case 9502:
+   case 9504:
+   case 9506:
+   case 9508:
+   case 9510:
+   case 9512:
+   case 9514:
+   case 9516:
+   case 9518:
+   case 9520:
+   case 9522:
+   case 9524:
+   case 9526:
+   case 9528:
+   case 9530:
+   case 9532:
+   case 9534:
+   case 9536:
+   case 9538:
+   case 9540:
+   case 9542:
+   case 9544:
+   case 9546:
+   case 9548:
+   case 9550:
+   case 9552:
+   case 9554:
+   case 9556:
+   case 9558:
+   case 9560:
+   case 9562:
+   case 9564:
+   case 9566:
+   case 9568:
+   case 9570:
+   case 9572:
+   case 9574:
+   case 9576:
+   case 9578:
+   case 9580:
+   case 9582:
+   case 9584:
+   case 9586:
+   case 9588:
+   case 9590:
+   case 9592:
+   case 9594:
+   case 9596:
+   case 9598:
+   case 9600:
+   case 9602:
+   case 9604:
+   case 9606:
+   case 9608:
+   case 9610:
+   case 9612:
+   case 9614:
+   case 9616:
+   case 9618:
+   case 9620:
+   case 9622:
+   case 9624:
+   case 9626:
+   case 9628:
+   case 9630:
+   case 9632:
+   case 9634:
+   case 9636:
+   case 9638:
+   case 9640:
+   case 9642:
+   case 9644:
+   case 9646:
+   case 9648:
+   case 9650:
+   case 9652:
+   case 9654:
+   case 9656:
+   case 9658:
+   case 9660:
+   case 9662:
+   case 9664:
+   case 9666:
+   case 9668:
+   case 9670:
+   case 9672:
+   case 9674:
+   case 9676:
+   case 9678:
+   case 9680:
+   case 9682:
+   case 9684:
+   case 9686:
+   case 9688:
+   case 9690:
+   case 9692:
+   case 9694:
+   case 9696:
+   case 9698:
+   case 9700:
+   case 9702:
+   case 9704:
+   case 9706:
+   case 9708:
+   case 9710:
+   case 9712:
+   case 9714:
+   case 9716:
+   case 9718:
+   case 9720:
+   case 9722:
+   case 9724:
+   case 9726:
+   case 9728:
+   case 9730:
+   case 9732:
+   case 9734:
+   case 9736:
+   case 9738:
+   case 9740:
+   case 9742:
+   case 9744:
+   case 9746:
+   case 9748:
+   case 9750:
+   case 9752:
+   case 9754:
+   case 9756:
+   case 9758:
+   case 9760:
+   case 9762:
+   case 9764:
+   case 9766:
+   case 9768:
+   case 9770:
+   case 9772:
+   case 9774:
+   case 9776:
+   case 9778:
+   case 9780:
+   case 9782:
+   case 9784:
+   case 9786:
+   case 9788:
+   case 9790:
+   case 9792:
+   case 9794:
+   case 9796:
+   case 9798:
+   case 9800:
+   case 9802:
+   case 9804:
+   case 9806:
+   case 9808:
+   case 9810:
+   case 9812:
+   case 9814:
+   case 9816:
+   case 9818:
+   case 9820:
+   case 9822:
+   case 9824:
+   case 9826:
+   case 9828:
+   case 9830:
+   case 9832:
+   case 9834:
+   case 9836:
+   case 9838:
+   case 9840:
+   case 9842:
+   case 9844:
+   case 9846:
+   case 9848:
+   case 9850:
+   case 9852:
+   case 9854:
+   case 9856:
+   case 9858:
+   case 9860:
+   case 9862:
+   case 9864:
+   case 9866:
+   case 9868:
+   case 9870:
+   case 9872:
+   case 9874:
+   case 9876:
+   case 9878:
+   case 9880:
+   case 9882:
+   case 9884:
+   case 9886:
+   case 9888:
+   case 9890:
+   case 9892:
+   case 9894:
+   case 9896:
+   case 9898:
+   case 9900:
+   case 9902:
+   case 9904:
+   case 9906:
+   case 9908:
+   case 9910:
+   case 9912:
+   case 9914:
+   case 9916:
+   case 9918:
+   case 9920:
+   case 9922:
+   case 9924:
+   case 9926:
+   case 9928:
+   case 9930:
+   case 9932:
+   case 9934:
+   case 9936:
+   case 9938:
+   case 9940:
+   case 9942:
+   case 9944:
+   case 9946:
+   case 9948:
+   case 9950:
+   case 9952:
+   case 9954:
+   case 9956:
+   case 9958:
+   case 9960:
+   case 9962:
+   case 9964:
+   case 9966:
+   case 9968:
+   case 9970:
+   case 9972:
+   case 9974:
+   case 9976:
+   case 9978:
+   case 9980:
+   case 9982:
+   case 9984:
+   case 9986:
+   case 9988:
+   case 9990:
+   case 9992:
+   case 9994:
+   case 9996:
+   case 9998:
+   case 1e4:
+   case 10002:
+   case 10004:
+   case 10006:
+   case 10008:
+   case 10010:
+   case 10012:
+   case 10014:
+   case 10016:
+   case 10018:
+   case 10020:
+   case 10022:
+   case 10024:
+   case 10026:
+   case 10028:
+   case 10030:
+   case 10032:
+   case 10034:
+   case 10036:
+   case 10038:
+   case 10040:
+   case 10042:
+   case 10044:
+   case 10046:
+   case 10048:
+   case 10050:
+   case 10052:
+   case 10054:
+   case 10056:
+   case 10058:
+   case 10060:
+   case 10062:
+   case 10064:
+   case 10066:
+   case 10068:
+   case 10070:
+   case 10072:
+   case 10074:
+   case 10076:
+   case 10078:
+   case 10080:
+   case 10082:
+   case 10084:
+   case 10086:
+   case 10088:
+   case 10090:
+   case 10092:
+   case 10094:
+   case 10096:
+   case 10098:
+   case 10100:
+   case 10102:
+   case 10104:
+   case 10106:
+   case 10108:
+   case 10110:
+   case 10112:
+   case 10114:
+   case 10116:
+   case 10118:
+   case 10120:
+   case 10122:
+   case 10124:
+   case 10126:
+   case 10128:
+   case 10130:
+   case 10132:
+   case 10134:
+   case 10136:
+   case 10138:
+   case 10140:
+   case 10142:
+   case 10144:
+   case 10146:
+   case 10148:
+   case 10150:
+   case 10152:
+   case 10154:
+   case 10156:
+   case 10158:
+   case 10160:
+   case 10162:
+   case 10164:
+   case 10166:
+   case 10168:
+   case 10170:
+   case 10172:
+   case 10174:
+   case 10176:
+   case 10178:
+   case 10180:
+   case 10182:
+   case 10184:
+   case 10186:
+   case 10188:
+   case 10190:
+   case 10192:
+   case 10194:
+   case 10196:
+   case 10198:
+   case 10200:
+   case 10202:
+   case 10204:
+   case 10206:
+   case 10208:
+   case 10210:
+   case 10212:
+   case 10214:
+   case 10216:
+   case 10218:
+   case 10220:
+   case 10222:
+   case 10224:
+   case 10226:
+   case 10228:
+   case 10230:
+   case 10232:
+   case 10234:
+   case 10236:
+   case 10238:
+   case 10240:
+   case 10242:
+   case 10244:
+   case 10246:
+   case 10248:
+   case 10250:
+   case 10252:
+   case 10254:
+   case 10256:
+   case 10258:
+   case 10260:
+   case 10262:
+   case 10264:
+   case 10266:
+   case 10268:
+   case 10270:
+   case 10272:
+   case 10274:
+   case 10276:
+   case 10278:
+   case 10280:
+   case 10282:
+   case 10284:
+   case 10286:
+   case 10288:
+   case 10290:
+   case 10292:
+   case 10294:
+   case 10296:
+   case 10298:
+   case 10300:
+   case 10302:
+   case 10304:
+   case 10306:
+   case 10308:
+   case 10310:
+   case 10312:
+   case 10314:
+   case 10316:
+   case 10318:
+   case 10320:
+   case 10322:
+   case 10324:
+   case 10326:
+   case 10328:
+   case 10330:
+   case 10332:
+   case 10334:
+   case 10336:
+   case 10338:
+   case 10340:
+   case 10342:
+   case 10344:
+   case 10346:
+   case 10348:
+   case 10350:
+   case 10352:
+   case 10354:
+   case 10356:
+   case 10358:
+   case 10360:
+   case 10362:
+   case 10364:
+   case 10366:
+   case 10368:
+   case 10370:
+   case 10372:
+   case 10374:
+   case 10376:
+   case 10378:
+   case 10380:
+   case 10382:
+   case 10384:
+   case 10386:
+   case 10388:
+   case 10390:
+   case 10392:
+   case 10394:
+   case 10396:
+   case 10398:
+   case 10400:
+   case 10402:
+   case 10404:
+   case 10406:
+   case 10408:
+   case 10410:
+   case 10412:
+   case 10414:
+   case 10416:
+   case 10418:
+   case 10420:
+   case 10422:
+   case 10424:
+   case 10426:
+   case 10428:
+   case 10430:
+   case 10432:
+   case 10434:
+   case 10436:
+   case 10438:
+   case 10440:
+   case 10442:
+   case 10444:
+   case 10446:
+   case 10448:
+   case 10450:
+   case 10452:
+   case 10454:
+   case 10456:
+   case 10458:
+   case 10460:
+   case 10462:
+   case 10464:
+   case 10466:
+   case 10468:
+   case 10470:
+   case 10472:
+   case 10474:
+   case 10476:
+   case 10478:
+   case 10480:
+   case 10482:
+   case 10484:
+   case 10486:
+   case 10488:
+   case 10490:
+   case 10492:
+   case 10494:
+   case 10496:
+   case 10498:
+   case 10500:
+   case 10502:
+   case 10504:
+   case 10506:
+   case 10508:
+   case 10510:
+   case 10512:
+   case 10514:
+   case 10516:
+   case 10518:
+   case 10520:
+   case 10522:
+   case 10524:
+   case 10526:
+   case 10528:
+   case 10530:
+   case 10532:
+   case 10534:
+   case 10536:
+   case 10538:
+   case 10540:
+   case 10542:
+   case 10544:
+   case 10546:
+   case 10548:
+   case 10550:
+   case 10552:
+   case 10554:
+   case 10556:
+   case 10558:
+   case 10560:
+   case 10562:
+   case 10564:
+   case 10566:
+   case 10568:
+   case 10570:
+   case 10572:
+   case 10574:
+   case 10576:
+   case 10578:
+   case 10580:
+   case 10582:
+   case 10584:
+   case 10586:
+   case 10588:
+   case 10590:
+   case 10592:
+   case 10594:
+   case 10596:
+   case 10598:
+   case 10600:
+   case 10602:
+   case 10604:
+   case 10606:
+   case 10608:
+   case 10610:
+   case 10612:
+   case 10614:
+   case 10616:
+   case 10618:
+   case 10620:
+   case 10622:
+   case 10624:
+   case 10626:
+   case 10628:
+   case 10630:
+   case 10632:
+   case 10634:
+   case 10636:
+   case 10638:
+   case 10640:
+   case 10642:
+   case 10644:
+   case 10646:
+   case 10648:
+   case 10650:
+   case 10652:
+   case 10654:
+   case 10656:
+   case 10658:
+   case 10660:
+   case 10662:
+   case 10664:
+   case 10666:
+   case 10668:
+   case 10670:
+   case 10672:
+   case 10674:
+   case 10676:
+   case 10678:
+   case 10680:
+   case 10682:
+   case 10684:
+   case 10686:
+   case 10688:
+   case 10690:
+   case 10692:
+   case 10694:
+   case 10696:
+   case 10698:
+   case 10700:
+   case 10702:
+   case 10704:
+   case 10706:
+   case 10708:
+   case 10710:
+   case 10712:
+   case 10714:
+   case 10716:
+   case 10718:
+   case 10720:
+   case 10722:
+   case 10724:
+   case 10726:
+   case 10728:
+   case 10730:
+   case 10732:
+   case 10734:
+   case 10736:
+   case 10738:
+   case 10740:
+   case 10742:
+   case 10744:
+   case 10746:
+   case 10748:
+   case 10750:
+   case 10752:
+   case 10754:
+   case 10756:
+   case 10758:
+   case 10760:
+   case 10762:
+   case 10764:
+   case 10766:
+   case 10768:
+   case 10770:
+   case 10772:
+   case 10774:
+   case 10776:
+   case 10778:
+   case 10780:
+   case 10782:
+   case 10784:
+   case 10786:
+   case 10788:
+   case 10790:
+   case 10792:
+   case 10794:
+   case 10796:
+   case 10798:
+   case 10800:
+   case 10802:
+   case 10804:
+   case 10806:
+   case 10808:
+   case 10810:
+   case 10812:
+   case 10814:
+   case 10816:
+   case 10818:
+   case 10820:
+   case 10822:
+   case 10824:
+   case 10826:
+   case 10828:
+   case 10830:
+   case 10832:
+   case 10834:
+   case 10836:
+   case 10838:
+   case 10840:
+   case 10842:
+   case 10844:
+   case 10846:
+   case 10848:
+   case 10850:
+   case 10852:
+   case 10854:
+   case 10856:
+   case 10858:
+   case 10860:
+   case 10862:
+   case 10864:
+   case 10866:
+   case 10868:
+   case 10870:
+   case 10872:
+   case 10874:
+   case 10876:
+   case 10878:
+   case 10880:
+   case 10882:
+   case 10884:
+   case 10886:
+   case 10888:
+   case 10890:
+   case 10892:
+   case 10894:
+   case 10896:
+   case 10898:
+   case 10900:
+   case 10902:
+   case 10904:
+   case 10906:
+   case 10908:
+   case 10910:
+   case 10912:
+   case 10914:
+   case 10916:
+   case 10918:
+   case 10920:
+   case 10922:
+   case 10924:
+   case 10926:
+   case 10928:
+   case 10930:
+   case 10932:
+   case 10934:
+   case 10936:
+   case 10938:
+   case 10940:
+   case 10942:
+   case 10944:
+   case 10946:
+   case 10948:
+   case 10950:
+   case 10952:
+   case 10954:
+   case 10956:
+   case 10958:
+   case 10960:
+   case 10962:
+   case 10964:
+   case 10966:
+   case 10968:
+   case 10970:
+   case 10972:
+   case 10974:
+   case 10976:
+   case 10978:
+   case 10980:
+   case 10982:
+   case 10984:
+   case 10986:
+   case 10988:
+   case 10990:
+   case 10992:
+   case 10994:
+   case 10996:
+   case 10998:
+   case 11e3:
+   case 11002:
+   case 11004:
+   case 11006:
+   case 11008:
+   case 11010:
+   case 11012:
+   case 11014:
+   case 11016:
+   case 11018:
+   case 11020:
+   case 11022:
+   case 11024:
+   case 11026:
+   case 11028:
+   case 11030:
+   case 11032:
+   case 11034:
+   case 11036:
+   case 11038:
+   case 11040:
+   case 11042:
+   case 11044:
+   case 11046:
+   case 11048:
+   case 11050:
+   case 11052:
+   case 11054:
+   case 11056:
+   case 11058:
+   case 11060:
+   case 11062:
+   case 11064:
+   case 11066:
+   case 11068:
+   case 11070:
+   case 11072:
+   case 11074:
+   case 11076:
+   case 11078:
+   case 11080:
+   case 11082:
+   case 11084:
+   case 11086:
+   case 11088:
+   case 11090:
+   case 11092:
+   case 11094:
+   case 11096:
+   case 11098:
+   case 11100:
+   case 11102:
+   case 11104:
+   case 11106:
+   case 11108:
+   case 11110:
+   case 11112:
+   case 11114:
+   case 11116:
+   case 11118:
+   case 11120:
+   case 11122:
+   case 11124:
+   case 11126:
+   case 11128:
+   case 11130:
+   case 11132:
+   case 11134:
+   case 11136:
+   case 11138:
+   case 11140:
+   case 11142:
+   case 11144:
+   case 11146:
+   case 11148:
+   case 11150:
+   case 11152:
+   case 11154:
+   case 11156:
+   case 11158:
+   case 11160:
+   case 11162:
+   case 11164:
+   case 11166:
+   case 11168:
+   case 11170:
+   case 11172:
+   case 11174:
+   case 11176:
+   case 11178:
+   case 11180:
+   case 11182:
+   case 11184:
+   case 11186:
+   case 11188:
+   case 11190:
+   case 11192:
+   case 11194:
+   case 11196:
+   case 11198:
+   case 11200:
+   case 11202:
+   case 11204:
+   case 11206:
+   case 11208:
+   case 11210:
+   case 11212:
+   case 11214:
+   case 11216:
+   case 11218:
+   case 11220:
+   case 11222:
+   case 11224:
+   case 11226:
+   case 11228:
+   case 11230:
+   case 11232:
+   case 11234:
+   case 11236:
+   case 11238:
+   case 11240:
+   case 11242:
+   case 11244:
+   case 11246:
+   case 11248:
+   case 11250:
+   case 11252:
+   case 11254:
+   case 11256:
+   case 11258:
+   case 11260:
+   case 11262:
+   case 11264:
+   case 11266:
+   case 11268:
+   case 11270:
+   case 11272:
+   case 11274:
+   case 11276:
+   case 11278:
+   case 11280:
+   case 11282:
+   case 11284:
+   case 11286:
+   case 11288:
+   case 11290:
+   case 11292:
+   case 11294:
+   case 11296:
+   case 11298:
+   case 11300:
+   case 11302:
+   case 11304:
+   case 11306:
+   case 11308:
+   case 11310:
+   case 11312:
+   case 11314:
+   case 11316:
+   case 11318:
+   case 11320:
+   case 11322:
+   case 11324:
+   case 11326:
+   case 11328:
+   case 11330:
+   case 11332:
+   case 11334:
+   case 11336:
+   case 11338:
+   case 11340:
+   case 11342:
+   case 11344:
+   case 11346:
+   case 11348:
+   case 11350:
+   case 11352:
+   case 11354:
+   case 11356:
+   case 11358:
+   case 11360:
+   case 11362:
+   case 11364:
+   case 11366:
+   case 11368:
+   case 11370:
+   case 11372:
+   case 11374:
+   case 11376:
+   case 11378:
+   case 11380:
+   case 11382:
+   case 11384:
+   case 11386:
+   case 11388:
+   case 11390:
+   case 11392:
+   case 11394:
+   case 11396:
+   case 11398:
+   case 11400:
+   case 11402:
+   case 11404:
+   case 11406:
+   case 11408:
+   case 11410:
+   case 11412:
+   case 11414:
+   case 11416:
+   case 11418:
+   case 11420:
+   case 11422:
+   case 11424:
+   case 11426:
+   case 11428:
+   case 11430:
+   case 11432:
+   case 11434:
+   case 11436:
+   case 11438:
+   case 11440:
+   case 11442:
+   case 11444:
+   case 11446:
+   case 11448:
+   case 11450:
+   case 11452:
+   case 11454:
+   case 11456:
+   case 11458:
+   case 11460:
+   case 11462:
+   case 11464:
+   case 11466:
+   case 11468:
+   case 11470:
+   case 11472:
+   case 11474:
+   case 11476:
+   case 11478:
+   case 11480:
+   case 11482:
+   case 11484:
+   case 11486:
+   case 11488:
+   case 11490:
+   case 11492:
+   case 11494:
+   case 11496:
+   case 11498:
+   case 11500:
+   case 11502:
+   case 11504:
+   case 11506:
+   case 11508:
+   case 11510:
+   case 11512:
+   case 11514:
+   case 11516:
+   case 11518:
+   case 11520:
+   case 11522:
+   case 11524:
+   case 11526:
+   case 11528:
+   case 11530:
+   case 11532:
+   case 11534:
+   case 11536:
+   case 11538:
+   case 11540:
+   case 11542:
+   case 11544:
+   case 11546:
+   case 11548:
+   case 11550:
+   case 11552:
+   case 11554:
+   case 11556:
+   case 11558:
+   case 11560:
+   case 11562:
+   case 11564:
+   case 11566:
+   case 11568:
+   case 11570:
+   case 11572:
+   case 11574:
+   case 11576:
+   case 11578:
+   case 11580:
+   case 11582:
+   case 11584:
+   case 11586:
+   case 11588:
+   case 11590:
+   case 11592:
+   case 11594:
+   case 11596:
+   case 11598:
+   case 11600:
+   case 11602:
+   case 11604:
+   case 11606:
+   case 11608:
+   case 11610:
+   case 11612:
+   case 11614:
+   case 11616:
+   case 11618:
+   case 11620:
+   case 11622:
+   case 11624:
+   case 11626:
+   case 11628:
+   case 11630:
+   case 11632:
+   case 11634:
+   case 11636:
+   case 11638:
+   case 11640:
+   case 11642:
+   case 11644:
+   case 11646:
+   case 11648:
+   case 11650:
+   case 11652:
+   case 11654:
+   case 11656:
+   case 11658:
+   case 11660:
+   case 11662:
+   case 11664:
+   case 11666:
+   case 11668:
+   case 11670:
+   case 11672:
+   case 11674:
+   case 11676:
+   case 11678:
+   case 11680:
+   case 11682:
+   case 11684:
+   case 11686:
+   case 11688:
+   case 11690:
+   case 11692:
+   case 11694:
+   case 11696:
+   case 11698:
+   case 11700:
+   case 11702:
+   case 11704:
+   case 11706:
+   case 11708:
+   case 11710:
+   case 11712:
+   case 11714:
+   case 11716:
+   case 11718:
+   case 11720:
+   case 11722:
+   case 11724:
+   case 11726:
+   case 11728:
+   case 11730:
+   case 11732:
+   case 11734:
+   case 11736:
+   case 11738:
+   case 11740:
+   case 11742:
+   case 11744:
+   case 11746:
+   case 11748:
+   case 11750:
+   case 11752:
+   case 11754:
+   case 11756:
+   case 11758:
+   case 11760:
+   case 11762:
+   case 11764:
+   case 11766:
+   case 11768:
+   case 11770:
+   case 11772:
+   case 11774:
+   case 11776:
+   case 11778:
+   case 11780:
+   case 11782:
+   case 11784:
+   case 11786:
+   case 11788:
+   case 11790:
+   case 11792:
+   case 11794:
+   case 11796:
+   case 11798:
+   case 11800:
+   case 11802:
+   case 11804:
+   case 11806:
+   case 11808:
+   case 11810:
+   case 11812:
+   case 11814:
+   case 11816:
+   case 11818:
+   case 11820:
+   case 11822:
+   case 11824:
+   case 11826:
+   case 11828:
+   case 11830:
+   case 11832:
+   case 11834:
+   case 11836:
+   case 11838:
+   case 11840:
+   case 11842:
+   case 11844:
+   case 11846:
+   case 11848:
+   case 11850:
+   case 11852:
+   case 11854:
+   case 11856:
+   case 11858:
+   case 11860:
+   case 11862:
+   case 11864:
+   case 11866:
+   case 11868:
+   case 11870:
+   case 11872:
+   case 11874:
+   case 11876:
+   case 11878:
+   case 11880:
+   case 11882:
+   case 11884:
+   case 11886:
+   case 11888:
+   case 11890:
+   case 11892:
+   case 11894:
+   case 11896:
+   case 11898:
+   case 11900:
+   case 11902:
+   case 11904:
+   case 11906:
+   case 11908:
+   case 11910:
+   case 11912:
+   case 11914:
+   case 11916:
+   case 11918:
+   case 11920:
+   case 11922:
+   case 11924:
+   case 11926:
+   case 11928:
+   case 11930:
+   case 11932:
+   case 11934:
+   case 11936:
+   case 11938:
+   case 11940:
+   case 11942:
+   case 11944:
+   case 11946:
+   case 11948:
+   case 11950:
+   case 11952:
+   case 11954:
+   case 11956:
+   case 11958:
+   case 11960:
+   case 11962:
+   case 11964:
+   case 11966:
+   case 11968:
+   case 11970:
+   case 11972:
+   case 11974:
+   case 11976:
+   case 11978:
+   case 11980:
+   case 11982:
+   case 11984:
+   case 11986:
+   case 11988:
+   case 11990:
+   case 11992:
+   case 11994:
+   case 11996:
+   case 11998:
+   case 12e3:
+   case 12002:
+   case 12004:
+   case 12006:
+   case 12008:
+   case 12010:
+   case 12012:
+   case 12014:
+   case 12016:
+   case 12018:
+   case 12020:
+   case 12022:
+   case 12024:
+   case 12026:
+   case 12028:
+   case 12030:
+   case 12032:
+   case 12034:
+   case 12036:
+   case 12038:
+   case 12040:
+   case 12042:
+   case 12044:
+   case 12046:
+   case 12048:
+   case 12050:
+   case 12052:
+   case 12054:
+   case 12056:
+   case 12058:
+   case 12060:
+   case 12062:
+   case 12064:
+   case 12066:
+   case 12068:
+   case 12070:
+   case 12072:
+   case 12074:
+   case 12076:
+   case 12078:
+   case 12080:
+   case 12082:
+   case 12084:
+   case 12086:
+   case 12088:
+   case 12090:
+   case 12092:
+   case 12094:
+   case 12096:
+   case 12098:
+   case 12100:
+   case 12102:
+   case 12104:
+   case 12106:
+   case 12108:
+   case 12110:
+   case 12112:
+   case 12114:
+   case 12116:
+   case 12118:
+   case 12120:
+   case 12122:
+   case 12124:
+   case 12126:
+   case 12128:
+   case 12130:
+   case 12132:
+   case 12134:
+   case 12136:
+   case 12138:
+   case 12140:
+   case 12142:
+   case 12144:
+   case 12146:
+   case 12148:
+   case 12150:
+   case 12152:
+   case 12154:
+   case 12156:
+   case 12158:
+   case 12160:
+   case 12162:
+   case 12164:
+   case 12166:
+   case 12168:
+   case 12170:
+   case 12172:
+   case 12174:
+   case 12176:
+   case 12178:
+   case 12180:
+   case 12182:
+   case 12184:
+   case 12186:
+   case 12188:
+   case 12190:
+   case 12192:
+   case 12194:
+   case 12196:
+   case 12198:
+   case 12200:
+   case 12202:
+   case 12204:
+   case 12206:
+   case 12208:
+   case 12210:
+   case 12212:
+   case 12214:
+   case 12216:
+   case 12218:
+   case 12220:
+   case 12222:
+   case 12224:
+   case 12226:
+   case 12228:
+   case 12230:
+   case 12232:
+   case 12234:
+   case 12236:
+   case 12238:
+   case 12240:
+   case 12242:
+   case 12244:
+   case 12246:
+   case 12248:
+   case 12250:
+   case 12252:
+   case 12254:
+   case 12256:
+   case 12258:
+   case 12260:
+   case 12262:
+   case 12264:
+   case 12266:
+   case 12268:
+   case 12270:
+   case 12272:
+   case 12274:
+   case 12276:
+   case 12278:
+   case 12280:
+   case 12282:
+   case 12284:
+   case 12286:
+   case 12288:
+   case 12290:
+   case 12292:
+   case 12294:
+   case 12296:
+   case 12298:
+   case 12300:
+   case 12302:
+   case 12304:
+   case 12306:
+   case 12308:
+   case 12310:
+   case 12312:
+   case 12314:
+   case 12316:
+   case 12318:
+   case 12320:
+   case 12322:
+   case 12324:
+   case 12326:
+   case 12328:
+   case 12330:
+   case 12332:
+   case 12334:
+   case 12336:
+   case 12338:
+   case 12340:
+   case 12342:
+   case 12344:
+   case 12346:
+   case 12348:
+   case 12350:
+   case 12352:
+   case 12354:
+   case 12356:
+   case 12358:
+   case 12360:
+   case 12362:
+   case 12364:
+   case 12366:
+   case 12368:
+   case 12370:
+   case 12372:
+   case 12374:
+   case 12376:
+   case 12378:
+   case 12380:
+   case 12382:
+   case 12384:
+   case 12386:
+   case 12388:
+   case 12390:
+   case 12392:
+   case 12394:
+   case 12396:
+   case 12398:
+   case 12400:
+   case 12402:
+   case 12404:
+   case 12406:
+   case 12408:
+   case 12410:
+   case 12412:
+   case 12414:
+   case 12416:
+   case 12418:
+   case 12420:
+   case 12422:
+   case 12424:
+   case 12426:
+   case 12428:
+   case 12430:
+   case 12432:
+   case 12434:
+   case 12436:
+   case 12438:
+   case 12440:
+   case 12442:
+   case 12444:
+   case 12446:
+   case 12448:
+   case 12450:
+   case 12452:
+   case 12454:
+   case 12456:
+   case 12458:
+   case 12460:
+   case 12462:
+   case 12464:
+   case 12466:
+   case 12468:
+   case 12470:
+   case 12472:
+   case 12474:
+   case 12476:
+   case 12478:
+   case 12480:
+   case 12482:
+   case 12484:
+   case 12486:
+   case 12488:
+   case 12490:
+   case 12492:
+   case 12494:
+   case 12496:
+   case 12498:
+   case 12500:
+   case 12502:
+   case 12504:
+   case 12506:
+   case 12508:
+   case 12510:
+   case 12512:
+   case 12514:
+   case 12516:
+   case 12518:
+   case 12520:
+   case 12522:
+   case 12524:
+   case 12526:
+   case 12528:
+   case 12530:
+   case 12532:
+   case 12534:
+   case 12536:
+   case 12538:
+   case 12540:
+   case 12542:
+   case 12544:
+   case 12546:
+   case 12548:
+   case 12550:
+   case 12552:
+   case 12554:
+   case 12556:
+   case 12558:
+   case 12560:
+   case 12562:
+   case 12564:
+   case 12566:
+   case 12568:
+   case 12570:
+   case 12572:
+   case 12574:
+   case 12576:
+   case 12578:
+   case 12580:
+   case 12582:
+   case 12584:
+   case 12586:
+   case 12588:
+   case 12590:
+   case 12592:
+   case 12594:
+   case 12596:
+   case 12598:
+   case 12600:
+   case 12602:
+   case 12604:
+   case 12606:
+   case 12608:
+   case 12610:
+   case 12612:
+   case 12614:
+   case 12616:
+   case 12618:
+   case 12620:
+   case 12622:
+   case 12624:
+   case 12626:
+   case 12628:
+   case 12630:
+   case 12632:
+   case 12634:
+   case 12636:
+   case 12638:
+   case 12640:
+   case 12642:
+   case 12644:
+   case 12646:
+   case 12648:
+   case 12650:
+   case 12652:
+   case 12654:
+   case 12656:
+   case 12658:
+   case 12660:
+   case 12662:
+   case 12664:
+   case 12666:
+   case 12668:
+   case 12670:
+   case 12672:
+   case 12674:
+   case 12676:
+   case 12678:
+   case 12680:
+   case 12682:
+   case 12684:
+   case 12686:
+   case 12688:
+   case 12690:
+   case 12692:
+   case 12694:
+   case 12696:
+   case 12698:
+   case 12700:
+   case 12702:
+   case 12704:
+   case 12706:
+   case 12708:
+   case 12710:
+   case 12712:
+   case 12714:
+   case 12716:
+   case 12718:
+   case 12720:
+   case 12722:
+   case 12724:
+   case 12726:
+   case 12728:
+   case 12730:
+   case 12732:
+   case 12734:
+   case 12736:
+   case 12738:
+   case 12740:
+   case 12742:
+   case 12744:
+   case 12746:
+   case 12748:
+   case 12750:
+   case 12752:
+   case 12754:
+   case 12756:
+   case 12758:
+   case 12760:
+   case 12762:
+   case 12764:
+   case 12766:
+   case 12768:
+   case 12770:
+   case 12772:
+   case 12774:
+   case 12776:
+   case 12778:
+   case 12780:
+   case 12782:
+   case 12784:
+   case 12786:
+   case 12788:
+   case 12790:
+   case 12792:
+   case 12794:
+   case 12796:
+   case 12798:
+   case 12800:
+   case 12802:
+   case 12804:
+   case 12806:
+   case 12808:
+   case 12810:
+   case 12812:
+   case 12814:
+   case 12816:
+   case 12818:
+   case 12820:
+   case 12822:
+   case 12824:
+   case 12826:
+   case 12828:
+   case 12830:
+   case 12832:
+   case 12834:
+   case 12836:
+   case 12838:
+   case 12840:
+   case 12842:
+   case 12844:
+   case 12846:
+   case 12848:
+   case 12850:
+   case 12852:
+   case 12854:
+   case 12856:
+   case 12858:
+   case 12860:
+   case 12862:
+   case 12864:
+   case 12866:
+   case 12868:
+   case 12870:
+   case 12872:
+   case 12874:
+   case 12876:
+   case 12878:
+   case 12880:
+   case 12882:
+   case 12884:
+   case 12886:
+   case 12888:
+   case 12890:
+   case 12892:
+   case 12894:
+   case 12896:
+   case 12898:
+   case 12900:
+   case 12902:
+   case 12904:
+   case 12906:
+   case 12908:
+   case 12910:
+   case 12912:
+   case 12914:
+   case 12916:
+   case 12918:
+   case 12920:
+   case 12922:
+   case 12924:
+   case 12926:
+   case 12928:
+   case 12930:
+   case 12932:
+   case 12934:
+   case 12936:
+   case 12938:
+   case 12940:
+   case 12942:
+   case 12944:
+   case 12946:
+   case 12948:
+   case 12950:
+   case 12952:
+   case 12954:
+   case 12956:
+   case 12958:
+   case 12960:
+   case 12962:
+   case 12964:
+   case 12966:
+   case 12968:
+   case 12970:
+   case 12972:
+   case 12974:
+   case 12976:
+   case 12978:
+   case 12980:
+   case 12982:
+   case 12984:
+   case 12986:
+   case 12988:
+   case 12990:
+   case 12992:
+   case 12994:
+   case 12996:
+   case 12998:
+   case 13e3:
+   case 13002:
+   case 13004:
+   case 13006:
+   case 13008:
+   case 13010:
+   case 13012:
+   case 13014:
+   case 13016:
+   case 13018:
+   case 13020:
+   case 13022:
+   case 13024:
+   case 13026:
+   case 13028:
+   case 13030:
+   case 13032:
+   case 13034:
+   case 13036:
+   case 13038:
+   case 13040:
+   case 13042:
+   case 13044:
+   case 13046:
+   case 13048:
+   case 13050:
+   case 13052:
+   case 13054:
+   case 13056:
+   case 13058:
+   case 13060:
+   case 13062:
+   case 13064:
+   case 13066:
+   case 13068:
+   case 13070:
+   case 13072:
+   case 13074:
+   case 13076:
+   case 13078:
+   case 13080:
+   case 13082:
+   case 13084:
+   case 13086:
+   case 13088:
+   case 13090:
+   case 13092:
+   case 13094:
+   case 13096:
+   case 13098:
+   case 13100:
+   case 13102:
+   case 13104:
+   case 13106:
+   case 13108:
+   case 13110:
+   case 13112:
+   case 13114:
+   case 13116:
+   case 13118:
+   case 13120:
+   case 13122:
+   case 13124:
+   case 13126:
+   case 13128:
+   case 13130:
+   case 13132:
+   case 13134:
+   case 13136:
+   case 13138:
+   case 13140:
+   case 13142:
+   case 13144:
+   case 13146:
+   case 13148:
+   case 13150:
+   case 13152:
+   case 13154:
+   case 13156:
+   case 13158:
+   case 13160:
+   case 13162:
+   case 13164:
+   case 13166:
+   case 13168:
+   case 13170:
+   case 13172:
+   case 13174:
+   case 13176:
+   case 13178:
+   case 13180:
+   case 13182:
+   case 13184:
+   case 13186:
+   case 13188:
+   case 13190:
+   case 13192:
+   case 13194:
+   case 13196:
+   case 13198:
+   case 13200:
+   case 13202:
+   case 13204:
+   case 13206:
+   case 13208:
+   case 13210:
+   case 13212:
+   case 13214:
+   case 13216:
+   case 13218:
+   case 13220:
+   case 13222:
+   case 13224:
+   case 13226:
+   case 13228:
+   case 13230:
+   case 13232:
+   case 13234:
+   case 13236:
+   case 13238:
+   case 13240:
+   case 13242:
+   case 13244:
+   case 13246:
+   case 13248:
+   case 13250:
+   case 13252:
+   case 13254:
+   case 13256:
+   case 13258:
+   case 13260:
+   case 13262:
+   case 13264:
+   case 13266:
+   case 13268:
+   case 13270:
+   case 13272:
+   case 13274:
+   case 13276:
+   case 13278:
+   case 13280:
+   case 13282:
+   case 13284:
+   case 13286:
+   case 13288:
+   case 13290:
+   case 13292:
+   case 13294:
+   case 13296:
+   case 13298:
+   case 13300:
+   case 13302:
+   case 13304:
+   case 13306:
+   case 13308:
+   case 13310:
+   case 13312:
+   case 13314:
+   case 13316:
+   case 13318:
+   case 13320:
+   case 13322:
+   case 13324:
+   case 13326:
+   case 13328:
+   case 13330:
+   case 13332:
+   case 13334:
+   case 13336:
+   case 13338:
+   case 13340:
+   case 13342:
+   case 13344:
+   case 13346:
+   case 13348:
+   case 13350:
+   case 13352:
+   case 13354:
+   case 13356:
+   case 13358:
+   case 13360:
+   case 13362:
+   case 13364:
+   case 13366:
+   case 13368:
+   case 13370:
+   case 13372:
+   case 13374:
+   case 13376:
+   case 13378:
+   case 13380:
+   case 13382:
+   case 13384:
+   case 13386:
+   case 13388:
+   case 13390:
+   case 13392:
+   case 13394:
+   case 13396:
+   case 13398:
+   case 13400:
+   case 13402:
+   case 13404:
+   case 13406:
+   case 13408:
+   case 13410:
+   case 13412:
+   case 13414:
+   case 13416:
+   case 13418:
+   case 13420:
+   case 13422:
+   case 13424:
+   case 13426:
+   case 13428:
+   case 13430:
+   case 13432:
+   case 13434:
+   case 13436:
+   case 13438:
+   case 13440:
+   case 13442:
+   case 13444:
+   case 13446:
+   case 13448:
+   case 13450:
+   case 13452:
+   case 13454:
+   case 13456:
+   case 13458:
+   case 13460:
+   case 13462:
+   case 13464:
+   case 13466:
+   case 13468:
+   case 13470:
+   case 13472:
+   case 13474:
+   case 13476:
+   case 13478:
+   case 13480:
+   case 13482:
+   case 13484:
+   case 13486:
+   case 13488:
+   case 13490:
+   case 13492:
+   case 13494:
+   case 13496:
+   case 13498:
+   case 13500:
+   case 13502:
+   case 13504:
+   case 13506:
+   case 13508:
+   case 13510:
+   case 13512:
+   case 13514:
+   case 13516:
+   case 13518:
+   case 13520:
+   case 13522:
+   case 13524:
+   case 13526:
+   case 13528:
+   case 13530:
+   case 13532:
+   case 13534:
+   case 13536:
+   case 13538:
+   case 13540:
+   case 13542:
+   case 13544:
+   case 13546:
+   case 13548:
+   case 13550:
+   case 13552:
+   case 13554:
+   case 13556:
+   case 13558:
+   case 13560:
+   case 13562:
+   case 13564:
+   case 13566:
+   case 13568:
+   case 13570:
+   case 13572:
+   case 13574:
+   case 13576:
+   case 13578:
+   case 13580:
+   case 13582:
+   case 13584:
+   case 13586:
+   case 13588:
+   case 13590:
+   case 13592:
+   case 13594:
+   case 13596:
+   case 13598:
+   case 13600:
+   case 13602:
+   case 13604:
+   case 13606:
+   case 13608:
+   case 13610:
+   case 13612:
+   case 13614:
+   case 13616:
+   case 13618:
+   case 13620:
+   case 13622:
+   case 13624:
+   case 13626:
+   case 13628:
+   case 13630:
+   case 13632:
+   case 13634:
+   case 13636:
+   case 13638:
+   case 13640:
+   case 13642:
+   case 13644:
+   case 13646:
+   case 13648:
+   case 13650:
+   case 13652:
+   case 13654:
+   case 13656:
+   case 13658:
+   case 13660:
+   case 13662:
+   case 13664:
+   case 13666:
+   case 13668:
+   case 13670:
+   case 13672:
+   case 13674:
+   case 13676:
+   case 13678:
+   case 13680:
+   case 13682:
+   case 13684:
+   case 13686:
+   case 13688:
+   case 13690:
+   case 13692:
+   case 13694:
+   case 13696:
+   case 13698:
+   case 13700:
+   case 13702:
+   case 13704:
+   case 13706:
+   case 13708:
+   case 13710:
+   case 13712:
+   case 13714:
+   case 13716:
+   case 13718:
+   case 13720:
+   case 13722:
+   case 13724:
+   case 13726:
+   case 13728:
+   case 13730:
+   case 13732:
+   case 13734:
+   case 13736:
+   case 13738:
+   case 13740:
+   case 13742:
+   case 13744:
+   case 13746:
+   case 13748:
+   case 13750:
+   case 13752:
+   case 13754:
+   case 13756:
+   case 13758:
+   case 13760:
+   case 13762:
+   case 13764:
+   case 13766:
+   case 13768:
+   case 13770:
+   case 13772:
+   case 13774:
+   case 13776:
+   case 13778:
+   case 13780:
+   case 13782:
+   case 13784:
+   case 13786:
+   case 13788:
+   case 13790:
+   case 13792:
+   case 13794:
+   case 13796:
+   case 13798:
+   case 13800:
+   case 13802:
+   case 13804:
+   case 13806:
+   case 13808:
+   case 13810:
+   case 13812:
+   case 13814:
+   case 13816:
+   case 13818:
+   case 13820:
+   case 13822:
+   case 13824:
+   case 13826:
+   case 13828:
+   case 13830:
+   case 13832:
+   case 13834:
+   case 13836:
+   case 13838:
+   case 13840:
+   case 13842:
+   case 13844:
+   case 13846:
+   case 13848:
+   case 13850:
+   case 13852:
+   case 13854:
+   case 13856:
+   case 13858:
+   case 13860:
+   case 13862:
+   case 13864:
+   case 13866:
+   case 13868:
+   case 13870:
+   case 13872:
+   case 13874:
+   case 13876:
+   case 13878:
+   case 13880:
+   case 13882:
+   case 13884:
+   case 13886:
+   case 13888:
+   case 13890:
+   case 13892:
+   case 13894:
+   case 13896:
+   case 13898:
+   case 13900:
+   case 13902:
+   case 13904:
+   case 13906:
+   case 13908:
+   case 13910:
+   case 13912:
+   case 13914:
+   case 13916:
+   case 13918:
+   case 13920:
+   case 13922:
+   case 13924:
+   case 13926:
+   case 13928:
+   case 13930:
+   case 13932:
+   case 13934:
+   case 13936:
+   case 13938:
+   case 13940:
+   case 13942:
+   case 13944:
+   case 13946:
+   case 13948:
+   case 13950:
+   case 13952:
+   case 13954:
+   case 13956:
+   case 13958:
+   case 13960:
+   case 13962:
+   case 13964:
+   case 13966:
+   case 13968:
+   case 13970:
+   case 13972:
+   case 13974:
+   case 13976:
+   case 13978:
+   case 13980:
+   case 13982:
+   case 13984:
+   case 13986:
+   case 13988:
+   case 13990:
+   case 13992:
+   case 13994:
+   case 13996:
+   case 13998:
+   case 14e3:
+   case 14002:
+   case 14004:
+   case 14006:
+   case 14008:
+   case 14010:
+   case 14012:
+   case 14014:
+   case 14016:
+   case 14018:
+   case 14020:
+   case 14022:
+   case 14024:
+   case 14026:
+   case 14028:
+   case 14030:
+   case 14032:
+   case 14034:
+   case 14036:
+   case 14038:
+   case 14040:
+   case 14042:
+   case 14044:
+   case 14046:
+   case 14048:
+   case 14050:
+   case 14052:
+   case 14054:
+   case 14056:
+   case 14058:
+   case 14060:
+   case 14062:
+   case 14064:
+   case 14066:
+   case 14068:
+   case 14070:
+   case 14072:
+   case 14074:
+   case 14076:
+   case 14078:
+   case 14080:
+   case 14082:
+   case 14084:
+   case 14086:
+   case 14088:
+   case 14090:
+   case 14092:
+   case 14094:
+   case 14096:
+   case 14098:
+   case 14100:
+   case 14102:
+   case 14104:
+   case 14106:
+   case 14108:
+   case 14110:
+   case 14112:
+   case 14114:
+   case 14116:
+   case 14118:
+   case 14120:
+   case 14122:
+   case 14124:
+   case 14126:
+   case 14128:
+   case 14130:
+   case 14132:
+   case 14134:
+   case 14136:
+   case 14138:
+   case 14140:
+   case 14142:
+   case 14144:
+   case 14146:
+   case 14148:
+   case 14150:
+   case 14152:
+   case 14154:
+   case 14156:
+   case 14158:
+   case 14160:
+   case 14162:
+   case 14164:
+   case 14166:
+   case 14168:
+   case 14170:
+   case 14172:
+   case 14174:
+   case 14176:
+   case 14178:
+   case 14180:
+   case 14182:
+   case 14184:
+   case 14186:
+   case 14188:
+   case 14190:
+   case 14192:
+   case 14194:
+   case 14196:
+   case 14198:
+   case 14200:
+   case 14202:
+   case 14204:
+   case 14206:
+   case 14208:
+   case 14210:
+   case 14212:
+   case 14214:
+   case 14216:
+   case 14218:
+   case 14220:
+   case 14222:
+   case 14224:
+   case 14226:
+   case 14228:
+   case 14230:
+   case 14232:
+   case 14234:
+   case 14236:
+   case 14238:
+   case 14240:
+   case 14242:
+   case 14244:
+   case 14246:
+   case 14248:
+   case 14250:
+   case 14252:
+   case 14254:
+   case 14256:
+   case 14258:
+   case 14260:
+   case 14262:
+   case 14264:
+   case 14266:
+   case 14268:
+   case 14270:
+   case 14272:
+   case 14274:
+   case 14276:
+   case 14278:
+   case 14280:
+   case 14282:
+   case 14284:
+   case 14286:
+   case 14288:
+   case 14290:
+   case 14292:
+   case 14294:
+   case 14296:
+   case 14298:
+   case 14300:
+   case 14302:
+   case 14304:
+   case 14306:
+   case 14308:
+   case 14310:
+   case 14312:
+   case 14314:
+   case 14316:
+   case 14318:
+   case 14320:
+   case 14322:
+   case 14324:
+   case 14326:
+   case 14328:
+   case 14330:
+   case 14332:
+   case 14334:
+   case 14336:
+   case 14338:
+   case 14340:
+   case 14342:
+   case 14344:
+   case 14346:
+   case 14348:
+   case 14350:
+   case 14352:
+   case 14354:
+   case 14356:
+   case 14358:
+   case 14360:
+   case 14362:
+   case 14364:
+   case 14366:
+   case 14368:
+   case 14370:
+   case 14372:
+   case 14374:
+   case 14376:
+   case 14378:
+   case 14380:
+   case 14382:
+   case 14384:
+   case 14386:
+   case 14388:
+   case 14390:
+   case 14392:
+   case 14394:
+   case 14396:
+   case 14398:
+   case 14400:
+   case 14402:
+   case 14404:
+   case 14406:
+   case 14408:
+   case 14410:
+   case 14412:
+   case 14414:
+   case 14416:
+   case 14418:
+   case 14420:
+   case 14422:
+   case 14424:
+   case 14426:
+   case 14428:
+   case 14430:
+   case 14432:
+   case 14434:
+   case 14436:
+   case 14438:
+   case 14440:
+   case 14442:
+   case 14444:
+   case 14446:
+   case 14448:
+   case 14450:
+   case 14452:
+   case 14454:
+   case 14456:
+   case 14458:
+   case 14460:
+   case 14462:
+   case 14464:
+   case 14466:
+   case 14468:
+   case 14470:
+   case 14472:
+   case 14474:
+   case 14476:
+   case 14478:
+   case 14480:
+   case 14482:
+   case 14484:
+   case 14486:
+   case 14488:
+   case 14490:
+   case 14492:
+   case 14494:
+   case 14496:
+   case 14498:
+   case 14500:
+   case 14502:
+   case 14504:
+   case 14506:
+   case 14508:
+   case 14510:
+   case 14512:
+   case 14514:
+   case 14516:
+   case 14518:
+   case 14520:
+   case 14522:
+   case 14524:
+   case 14526:
+   case 14528:
+   case 14530:
+   case 14532:
+   case 14534:
+   case 14536:
+   case 14538:
+   case 14540:
+   case 14542:
+   case 14544:
+   case 14546:
+   case 14548:
+   case 14550:
+   case 14552:
+   case 14554:
+   case 14556:
+   case 14558:
+   case 14560:
+   case 14562:
+   case 14564:
+   case 14566:
+   case 14568:
+   case 14570:
+   case 14572:
+   case 14574:
+   case 14576:
+   case 14578:
+   case 14580:
+   case 14582:
+   case 14584:
+   case 14586:
+   case 14588:
+   case 14590:
+   case 14592:
+   case 14594:
+   case 14596:
+   case 14598:
+   case 14600:
+   case 14602:
+   case 14604:
+   case 14606:
+   case 14608:
+   case 14610:
+   case 14612:
+   case 14614:
+   case 14616:
+   case 14618:
+   case 14620:
+   case 14622:
+   case 14624:
+   case 14626:
+   case 14628:
+   case 14630:
+   case 14632:
+   case 14634:
+   case 14636:
+   case 14638:
+   case 14640:
+   case 14642:
+   case 14644:
+   case 14646:
+   case 14648:
+   case 14650:
+   case 14652:
+   case 14654:
+   case 14656:
+   case 14658:
+   case 14660:
+   case 14662:
+   case 14664:
+   case 14666:
+   case 14668:
+   case 14670:
+   case 14672:
+   case 14674:
+   case 14676:
+   case 14678:
+   case 14680:
+   case 14682:
+   case 14684:
+   case 14686:
+   case 14688:
+   case 14690:
+   case 14692:
+   case 14694:
+   case 14696:
+   case 14698:
+   case 14700:
+   case 14702:
+   case 14704:
+   case 14706:
+   case 14708:
+   case 14710:
+   case 14712:
+   case 14714:
+   case 14716:
+   case 14718:
+   case 14720:
+   case 14722:
+   case 14724:
+   case 14726:
+   case 14728:
+   case 14730:
+   case 14732:
+   case 14734:
+   case 14736:
+   case 14738:
+   case 14740:
+   case 14742:
+   case 14744:
+   case 14746:
+   case 14748:
+   case 14750:
+   case 14752:
+   case 14754:
+   case 14756:
+   case 14758:
+   case 14760:
+   case 14762:
+   case 14764:
+   case 14766:
+   case 14768:
+   case 14770:
+   case 14772:
+   case 14774:
+   case 14776:
+   case 14778:
+   case 14780:
+   case 14782:
+   case 14784:
+   case 14786:
+   case 14788:
+   case 14790:
+   case 14792:
+   case 14794:
+   case 14796:
+   case 14798:
+   case 14800:
+   case 14802:
+   case 14804:
+   case 14806:
+   case 14808:
+   case 14810:
+   case 14812:
+   case 14814:
+   case 14816:
+   case 14818:
+   case 14820:
+   case 14822:
+   case 14824:
+   case 14826:
+   case 14828:
+   case 14830:
+   case 14832:
+   case 14834:
+   case 14836:
+   case 14838:
+   case 14840:
+   case 14842:
+   case 14844:
+   case 14846:
+   case 14848:
+   case 14850:
+   case 14852:
+   case 14854:
+   case 14856:
+   case 14858:
+   case 14860:
+   case 14862:
+   case 14864:
+   case 14866:
+   case 14868:
+   case 14870:
+   case 14872:
+   case 14874:
+   case 14876:
+   case 14878:
+   case 14880:
+   case 14882:
+   case 14884:
+   case 14886:
+   case 14888:
+   case 14890:
+   case 14892:
+   case 14894:
+   case 14896:
+   case 14898:
+   case 14900:
+   case 14902:
+   case 14904:
+   case 14906:
+   case 14908:
+   case 14910:
+   case 14912:
+   case 14914:
+   case 14916:
+   case 14918:
+   case 14920:
+   case 14922:
+   case 14924:
+   case 14926:
+   case 14928:
+   case 14930:
+   case 14932:
+   case 14934:
+   case 14936:
+   case 14938:
+   case 14940:
+   case 14942:
+   case 14944:
+   case 14946:
+   case 14948:
+   case 14950:
+   case 14952:
+   case 14954:
+   case 14956:
+   case 14958:
+   case 14960:
+   case 14962:
+   case 14964:
+   case 14966:
+   case 14968:
+   case 14970:
+   case 14972:
+   case 14974:
+   case 14976:
+   case 14978:
+   case 14980:
+   case 14982:
+   case 14984:
+   case 14986:
+   case 14988:
+   case 14990:
+   case 14992:
+   case 14994:
+   case 14996:
+   case 14998:
+   case 15e3:
+   case 15002:
+   case 15004:
+   case 15006:
+   case 15008:
+   case 15010:
+   case 15012:
+   case 15014:
+   case 15016:
+   case 15018:
+   case 15020:
+   case 15022:
+   case 15024:
+   case 15026:
+   case 15028:
+   case 15030:
+   case 15032:
+   case 15034:
+   case 15036:
+   case 15038:
+   case 15040:
+   case 15042:
+   case 15044:
+   case 15046:
+   case 15048:
+   case 15050:
+   case 15052:
+   case 15054:
+   case 15056:
+   case 15058:
+   case 15060:
+   case 15062:
+   case 15064:
+   case 15066:
+   case 15068:
+   case 15070:
+   case 15072:
+   case 15074:
+   case 15076:
+   case 15078:
+   case 15080:
+   case 15082:
+   case 15084:
+   case 15086:
+   case 15088:
+   case 15090:
+   case 15092:
+   case 15094:
+   case 15096:
+   case 15098:
+   case 15100:
+   case 15102:
+   case 15104:
+   case 15106:
+   case 15108:
+   case 15110:
+   case 15112:
+   case 15114:
+   case 15116:
+   case 15118:
+   case 15120:
+   case 15122:
+   case 15124:
+   case 15126:
+   case 15128:
+   case 15130:
+   case 15132:
+   case 15134:
+   case 15136:
+   case 15138:
+   case 15140:
+   case 15142:
+   case 15144:
+   case 15146:
+   case 15148:
+   case 15150:
+   case 15152:
+   case 15154:
+   case 15156:
+   case 15158:
+   case 15160:
+   case 15162:
+   case 15164:
+   case 15166:
+   case 15168:
+   case 15170:
+   case 15172:
+   case 15174:
+   case 15176:
+   case 15178:
+   case 15180:
+   case 15182:
+   case 15184:
+   case 15186:
+   case 15188:
+   case 15190:
+   case 15192:
+   case 15194:
+   case 15196:
+   case 15198:
+   case 15200:
+   case 15202:
+   case 15204:
+   case 15206:
+   case 15208:
+   case 15210:
+   case 15212:
+   case 15214:
+   case 15216:
+   case 15218:
+   case 15220:
+   case 15222:
+   case 15224:
+   case 15226:
+   case 15228:
+   case 15230:
+   case 15232:
+   case 15234:
+   case 15236:
+   case 15238:
+   case 15240:
+   case 15242:
+   case 15244:
+   case 15246:
+   case 15248:
+   case 15250:
+   case 15252:
+   case 15254:
+   case 15256:
+   case 15258:
+   case 15260:
+   case 15262:
+   case 15264:
+   case 15266:
+   case 15268:
+   case 15270:
+   case 15272:
+   case 15274:
+   case 15276:
+   case 15278:
+   case 15280:
+   case 15282:
+   case 15284:
+   case 15286:
+   case 15288:
+   case 15290:
+   case 15292:
+   case 15294:
+   case 15296:
+   case 15298:
+   case 15300:
+   case 15302:
+   case 15304:
+   case 15306:
+   case 15308:
+   case 15310:
+   case 15312:
+   case 15314:
+   case 15316:
+   case 15318:
+   case 15320:
+   case 15322:
+   case 15324:
+   case 15326:
+   case 15328:
+   case 15330:
+   case 15332:
+   case 15334:
+   case 15336:
+   case 15338:
+   case 15340:
+   case 15342:
+   case 15344:
+   case 15346:
+   case 15348:
+   case 15350:
+   case 15352:
+   case 15354:
+   case 15356:
+   case 15358:
+   case 15360:
+   case 15362:
+   case 15364:
+   case 15366:
+   case 15368:
+   case 15370:
+   case 15372:
+   case 15374:
+   case 15376:
+   case 15378:
+   case 15380:
+   case 15382:
+   case 15384:
+   case 15386:
+   case 15388:
+   case 15390:
+   case 15392:
+   case 15394:
+   case 15396:
+   case 15398:
+   case 15400:
+   case 15402:
+   case 15404:
+   case 15406:
+   case 15408:
+   case 15410:
+   case 15412:
+   case 15414:
+   case 15416:
+   case 15418:
+   case 15420:
+   case 15422:
+   case 15424:
+   case 15426:
+   case 15428:
+   case 15430:
+   case 15432:
+   case 15434:
+   case 15436:
+   case 15438:
+   case 15440:
+   case 15442:
+   case 15444:
+   case 15446:
+   case 15448:
+   case 15450:
+   case 15452:
+   case 15454:
+   case 15456:
+   case 15458:
+   case 15460:
+   case 15462:
+   case 15464:
+   case 15466:
+   case 15468:
+   case 15470:
+   case 15472:
+   case 15474:
+   case 15476:
+   case 15478:
+   case 15480:
+   case 15482:
+   case 15484:
+   case 15486:
+   case 15488:
+   case 15490:
+   case 15492:
+   case 15494:
+   case 15496:
+   case 15498:
+   case 15500:
+   case 15502:
+   case 15504:
+   case 15506:
+   case 15508:
+   case 15510:
+   case 15512:
+   case 15514:
+   case 15516:
+   case 15518:
+   case 15520:
+   case 15522:
+   case 15524:
+   case 15526:
+   case 15528:
+   case 15530:
+   case 15532:
+   case 15534:
+   case 15536:
+   case 15538:
+   case 15540:
+   case 15542:
+   case 15544:
+   case 15546:
+   case 15548:
+   case 15550:
+   case 15552:
+   case 15554:
+   case 15556:
+   case 15558:
+   case 15560:
+   case 15562:
+   case 15564:
+   case 15566:
+   case 15568:
+   case 15570:
+   case 15572:
+   case 15574:
+   case 15576:
+   case 15578:
+   case 15580:
+   case 15582:
+   case 15584:
+   case 15586:
+   case 15588:
+   case 15590:
+   case 15592:
+   case 15594:
+   case 15596:
+   case 15598:
+   case 15600:
+   case 15602:
+   case 15604:
+   case 15606:
+   case 15608:
+   case 15610:
+   case 15612:
+   case 15614:
+   case 15616:
+   case 15618:
+   case 15620:
+   case 15622:
+   case 15624:
+   case 15626:
+   case 15628:
+   case 15630:
+   case 15632:
+   case 15634:
+   case 15636:
+   case 15638:
+   case 15640:
+   case 15642:
+   case 15644:
+   case 15646:
+   case 15648:
+   case 15650:
+   case 15652:
+   case 15654:
+   case 15656:
+   case 15658:
+   case 15660:
+   case 15662:
+   case 15664:
+   case 15666:
+   case 15668:
+   case 15670:
+   case 15672:
+   case 15674:
+   case 15676:
+   case 15678:
+   case 15680:
+   case 15682:
+   case 15684:
+   case 15686:
+   case 15688:
+   case 15690:
+   case 15692:
+   case 15694:
+   case 15696:
+   case 15698:
+   case 15700:
+   case 15702:
+   case 15704:
+   case 15706:
+   case 15708:
+   case 15710:
+   case 15712:
+   case 15714:
+   case 15716:
+   case 15718:
+   case 15720:
+   case 15722:
+   case 15724:
+   case 15726:
+   case 15728:
+   case 15730:
+   case 15732:
+   case 15734:
+   case 15736:
+   case 15738:
+   case 15740:
+   case 15742:
+   case 15744:
+   case 15746:
+   case 15748:
+   case 15750:
+   case 15752:
+   case 15754:
+   case 15756:
+   case 15758:
+   case 15760:
+   case 15762:
+   case 15764:
+   case 15766:
+   case 15768:
+   case 15770:
+   case 15772:
+   case 15774:
+   case 15776:
+   case 15778:
+   case 15780:
+   case 15782:
+   case 15784:
+   case 15786:
+   case 15788:
+   case 15790:
+   case 15792:
+   case 15794:
+   case 15796:
+   case 15798:
+   case 15800:
+   case 15802:
+   case 15804:
+   case 15806:
+   case 15808:
+   case 15810:
+   case 15812:
+   case 15814:
+   case 15816:
+   case 15818:
+   case 15820:
+   case 15822:
+   case 15824:
+   case 15826:
+   case 15828:
+   case 15830:
+   case 15832:
+   case 15834:
+   case 15836:
+   case 15838:
+   case 15840:
+   case 15842:
+   case 15844:
+   case 15846:
+   case 15848:
+   case 15850:
+   case 15852:
+   case 15854:
+   case 15856:
+   case 15858:
+   case 15860:
+   case 15862:
+   case 15864:
+   case 15866:
+   case 15868:
+   case 15870:
+   case 15872:
+   case 15874:
+   case 15876:
+   case 15878:
+   case 15880:
+   case 15882:
+   case 15884:
+   case 15886:
+   case 15888:
+   case 15890:
+   case 15892:
+   case 15894:
+   case 15896:
+   case 15898:
+   case 15900:
+   case 15902:
+   case 15904:
+   case 15906:
+   case 15908:
+   case 15910:
+   case 15912:
+   case 15914:
+   case 15916:
+   case 15918:
+   case 15920:
+   case 15922:
+   case 15924:
+   case 15926:
+   case 15928:
+   case 15930:
+   case 15932:
+   case 15934:
+   case 15936:
+   case 15938:
+   case 15940:
+   case 15942:
+   case 15944:
+   case 15946:
+   case 15948:
+   case 15950:
+   case 15952:
+   case 15954:
+   case 15956:
+   case 15958:
+   case 15960:
+   case 15962:
+   case 15964:
+   case 15966:
+   case 15968:
+   case 15970:
+   case 15972:
+   case 15974:
+   case 15976:
+   case 15978:
+   case 15980:
+   case 15982:
+   case 15984:
+   case 15986:
+   case 15988:
+   case 15990:
+   case 15992:
+   case 15994:
+   case 15996:
+   case 15998:
+   case 16e3:
+   case 16002:
+   case 16004:
+   case 16006:
+   case 16008:
+   case 16010:
+   case 16012:
+   case 16014:
+   case 16016:
+   case 16018:
+   case 16020:
+   case 16022:
+   case 16024:
+   case 16026:
+   case 16028:
+   case 16030:
+   case 16032:
+   case 16034:
+   case 16036:
+   case 16038:
+   case 16040:
+   case 16042:
+   case 16044:
+   case 16046:
+   case 16048:
+   case 16050:
+   case 16052:
+   case 16054:
+   case 16056:
+   case 16058:
+   case 16060:
+   case 16062:
+   case 16064:
+   case 16066:
+   case 16068:
+   case 16070:
+   case 16072:
+   case 16074:
+   case 16076:
+   case 16078:
+   case 16080:
+   case 16082:
+   case 16084:
+   case 16086:
+   case 16088:
+   case 16090:
+   case 16092:
+   case 16094:
+   case 16096:
+   case 16098:
+   case 16100:
+   case 16102:
+   case 16104:
+   case 16106:
+   case 16108:
+   case 16110:
+   case 16112:
+   case 16114:
+   case 16116:
+   case 16118:
+   case 16120:
+   case 16122:
+   case 16124:
+   case 16126:
+   case 16128:
+   case 16130:
+   case 16132:
+   case 16134:
+   case 16136:
+   case 16138:
+   case 16140:
+   case 16142:
+   case 16144:
+   case 16146:
+   case 16148:
+   case 16150:
+   case 16152:
+   case 16154:
+   case 16156:
+   case 16158:
+   case 16160:
+   case 16162:
+   case 16164:
+   case 16166:
+   case 16168:
+   case 16170:
+   case 16172:
+   case 16174:
+   case 16176:
+   case 16178:
+   case 16180:
+   case 16182:
+   case 16184:
+   case 16186:
+   case 16188:
+   case 16190:
+   case 16192:
+   case 16194:
+   case 16196:
+   case 16198:
+   case 16200:
+   case 16202:
+   case 16204:
+   case 16206:
+   case 16208:
+   case 16210:
+   case 16212:
+   case 16214:
+   case 16216:
+   case 16218:
+   case 16220:
+   case 16222:
+   case 16224:
+   case 16226:
+   case 16228:
+   case 16230:
+   case 16232:
+   case 16234:
+   case 16236:
+   case 16238:
+   case 16240:
+   case 16242:
+   case 16244:
+   case 16246:
+   case 16248:
+   case 16250:
+   case 16252:
+   case 16254:
+   case 16256:
+   case 16258:
+   case 16260:
+   case 16262:
+   case 16264:
+   case 16266:
+   case 16268:
+   case 16270:
+   case 16272:
+   case 16274:
+   case 16276:
+   case 16278:
+   case 16280:
+   case 16282:
+   case 16284:
+   case 16286:
+   case 16288:
+   case 16290:
+   case 16292:
+   case 16294:
+   case 16296:
+   case 16298:
+   case 16300:
+   case 16302:
+   case 16304:
+   case 16306:
+   case 16308:
+   case 16310:
+   case 16312:
+   case 16314:
+   case 16316:
+   case 16318:
+   case 16320:
+   case 16322:
+   case 16324:
+   case 16326:
+   case 16328:
+   case 16330:
+   case 16332:
+   case 16334:
+   case 16336:
+   case 16338:
+   case 16340:
+   case 16342:
+   case 16344:
+   case 16346:
+   case 16348:
+   case 16350:
+   case 16352:
+   case 16354:
+   case 16356:
+   case 16358:
+   case 16360:
+   case 16362:
+   case 16364:
+   case 16366:
+   case 16368:
+   case 16370:
+   case 16372:
+   case 16374:
+   case 16376:
+   case 16378:
+   case 16380:
+   case 16382:
+   case 16384:
+   case 16386:
+   case 16388:
+   case 16390:
+   case 16392:
+   case 16394:
+   case 16396:
+   case 16398:
+   case 16400:
+   case 16402:
+   case 16404:
+   case 16406:
+   case 16408:
+   case 16410:
+   case 16412:
+   case 16414:
+   case 16416:
+   case 16418:
+   case 16420:
+   case 16422:
+   case 16424:
+   case 16426:
+   case 16428:
+   case 16430:
+   case 16432:
+   case 16434:
+   case 16436:
+   case 16438:
+   case 16440:
+   case 16442:
+   case 16444:
+   case 16446:
+   case 16448:
+   case 16450:
+   case 16452:
+   case 16454:
+   case 16456:
+   case 16458:
+   case 16460:
+   case 16462:
+   case 16464:
+   case 16466:
+   case 16468:
+   case 16470:
+   case 16472:
+   case 16474:
+   case 16476:
+   case 16478:
+   case 16480:
+   case 16482:
+   case 16484:
+   case 16486:
+   case 16488:
+   case 16490:
+   case 16492:
+   case 16494:
+   case 16496:
+   case 16498:
+   case 16500:
+   case 16502:
+   case 16504:
+   case 16506:
+   case 16508:
+   case 16510:
+   case 16512:
+   case 16514:
+   case 16516:
+   case 16518:
+   case 16520:
+   case 16522:
+   case 16524:
+   case 16526:
+   case 16528:
+   case 16530:
+   case 16532:
+   case 16534:
+   case 16536:
+   case 16538:
+   case 16540:
+   case 16542:
+   case 16544:
+   case 16546:
+   case 16548:
+   case 16550:
+   case 16552:
+   case 16554:
+   case 16556:
+   case 16558:
+   case 16560:
+   case 16562:
+   case 16564:
+   case 16566:
+   case 16568:
+   case 16570:
+   case 16572:
+   case 16574:
+   case 16576:
+   case 16578:
+   case 16580:
+   case 16582:
+   case 16584:
+   case 16586:
+   case 16588:
+   case 16590:
+   case 16592:
+   case 16594:
+   case 16596:
+   case 16598:
+   case 16600:
+   case 16602:
+   case 16604:
+   case 16606:
+   case 16608:
+   case 16610:
+   case 16612:
+   case 16614:
+   case 16616:
+   case 16618:
+   case 16620:
+   case 16622:
+   case 16624:
+   case 16626:
+   case 16628:
+   case 16630:
+   case 16632:
+   case 16634:
+   case 16636:
+   case 16638:
+   case 16640:
+   case 16642:
+   case 16644:
+   case 16646:
+   case 16648:
+   case 16650:
+   case 16652:
+   case 16654:
+   case 16656:
+   case 16658:
+   case 16660:
+   case 16662:
+   case 16664:
+   case 16666:
+   case 16668:
+   case 16670:
+   case 16672:
+   case 16674:
+   case 16676:
+   case 16678:
+   case 16680:
+   case 16682:
+   case 16684:
+   case 16686:
+   case 16688:
+   case 16690:
+   case 16692:
+   case 16694:
+   case 16696:
+   case 16698:
+   case 16700:
+   case 16702:
+   case 16704:
+   case 16706:
+   case 16708:
+   case 16710:
+   case 16712:
+   case 16714:
+   case 16716:
+   case 16718:
+   case 16720:
+   case 16722:
+   case 16724:
+   case 16726:
+   case 16728:
+   case 16730:
+   case 16732:
+   case 16734:
+   case 16736:
+   case 16738:
+   case 16740:
+   case 16742:
+   case 16744:
+   case 16746:
+   case 16748:
+   case 16750:
+   case 16752:
+   case 16754:
+   case 16756:
+   case 16758:
+   case 16760:
+   case 16762:
+   case 16764:
+   case 16766:
+   case 16768:
+   case 16770:
+   case 16772:
+   case 16774:
+   case 16776:
+   case 16778:
+   case 16780:
+   case 16782:
+   case 16784:
+   case 16786:
+   case 16788:
+   case 16790:
+   case 16792:
+   case 16794:
+   case 16796:
+   case 16798:
+   case 16800:
+   case 16802:
+   case 16804:
+   case 16806:
+   case 16808:
+   case 16810:
+   case 16812:
+   case 16814:
+   case 16816:
+   case 16818:
+   case 16820:
+   case 16822:
+   case 16824:
+   case 16826:
+   case 16828:
+   case 16830:
+   case 16832:
+   case 16834:
+   case 16836:
+   case 16838:
+   case 16840:
+   case 16842:
+   case 16844:
+   case 16846:
+   case 16848:
+   case 16850:
+   case 16852:
+   case 16854:
+   case 16856:
+   case 16858:
+   case 16860:
+   case 16862:
+   case 16864:
+   case 16866:
+   case 16868:
+   case 16870:
+   case 16872:
+   case 16874:
+   case 16876:
+   case 16878:
+   case 16880:
+   case 16882:
+   case 16884:
+   case 16886:
+   case 16888:
+   case 16890:
+   case 16892:
+   case 16894:
+   case 16896:
+   case 16898:
+   case 16900:
+   case 16902:
+   case 16904:
+   case 16906:
+   case 16908:
+   case 16910:
+   case 16912:
+   case 16914:
+   case 16916:
+   case 16918:
+   case 16920:
+   case 16922:
+   case 16924:
+   case 16926:
+   case 16928:
+   case 16930:
+   case 16932:
+   case 16934:
+   case 16936:
+   case 16938:
+   case 16940:
+   case 16942:
+   case 16944:
+   case 16946:
+   case 16948:
+   case 16950:
+   case 16952:
+   case 16954:
+   case 16956:
+   case 16958:
+   case 16960:
+   case 16962:
+   case 16964:
+   case 16966:
+   case 16968:
+   case 16970:
+   case 16972:
+   case 16974:
+   case 16976:
+   case 16978:
+   case 16980:
+   case 16982:
+   case 16984:
+   case 16986:
+   case 16988:
+   case 16990:
+   case 16992:
+   case 16994:
+   case 16996:
+   case 16998:
+   case 17e3:
+   case 17002:
+   case 17004:
+   case 17006:
+   case 17008:
+   case 17010:
+   case 17012:
+   case 17014:
+   case 17016:
+   case 17018:
+   case 17020:
+   case 17022:
+   case 17024:
+   case 17026:
+   case 17028:
+   case 17030:
+   case 17032:
+   case 17034:
+   case 17036:
+   case 17038:
+   case 17040:
+   case 17042:
+   case 17044:
+   case 17046:
+   case 17048:
+   case 17050:
+   case 17052:
+   case 17054:
+   case 17056:
+   case 17058:
+   case 17060:
+   case 17062:
+   case 17064:
+   case 17066:
+   case 17068:
+   case 17070:
+   case 17072:
+   case 17074:
+   case 17076:
+   case 17078:
+   case 17080:
+   case 17082:
+   case 17084:
+   case 17086:
+   case 17088:
+   case 17090:
+   case 17092:
+   case 17094:
+   case 17096:
+   case 17098:
+   case 17100:
+   case 17102:
+   case 17104:
+   case 17106:
+   case 17108:
+   case 17110:
+   case 17112:
+   case 17114:
+   case 17116:
+   case 17118:
+   case 17120:
+   case 17122:
+   case 17124:
+   case 17126:
+   case 17128:
+   case 17130:
+   case 17132:
+   case 17134:
+   case 17136:
+   case 17138:
+   case 17140:
+   case 17142:
+   case 17144:
+   case 17146:
+   case 17148:
+   case 17150:
+   case 17152:
+   case 17154:
+   case 17156:
+   case 17158:
+   case 17160:
+   case 17162:
+   case 17164:
+   case 17166:
+   case 17168:
+   case 17170:
+   case 17172:
+   case 17174:
+   case 17176:
+   case 17178:
+   case 17180:
+   case 17182:
+   case 17184:
+   case 17186:
+   case 17188:
+   case 17190:
+   case 17192:
+   case 17194:
+   case 17196:
+   case 17198:
+   case 17200:
+   case 17202:
+   case 17204:
+   case 17206:
+   case 17208:
+   case 17210:
+   case 17212:
+   case 17214:
+   case 17216:
+   case 17218:
+   case 17220:
+   case 17222:
+   case 17224:
+   case 17226:
+   case 17228:
+   case 17230:
+   case 17232:
+   case 17234:
+   case 17236:
+   case 17238:
+   case 17240:
+   case 17242:
+   case 17244:
+   case 17246:
+   case 17248:
+   case 17250:
+   case 17252:
+   case 17254:
+   case 17256:
+   case 17258:
+   case 17260:
+   case 17262:
+   case 17264:
+   case 17266:
+   case 17268:
+   case 17270:
+   case 17272:
+   case 17274:
+   case 17276:
+   case 17278:
+   case 17280:
+   case 17282:
+   case 17284:
+   case 17286:
+   case 17288:
+   case 17290:
+   case 17292:
+   case 17294:
+   case 17296:
+   case 17298:
+   case 17300:
+   case 17302:
+   case 17304:
+   case 17306:
+   case 17308:
+   case 17310:
+   case 17312:
+   case 17314:
+   case 17316:
+   case 17318:
+   case 17320:
+   case 17322:
+   case 17324:
+   case 17326:
+   case 17328:
+   case 17330:
+   case 17332:
+   case 17334:
+   case 17336:
+   case 17338:
+   case 17340:
+   case 17342:
+   case 17344:
+   case 17346:
+   case 17348:
+   case 17350:
+   case 17352:
+   case 17354:
+   case 17356:
+   case 17358:
+   case 17360:
+   case 17362:
+   case 17364:
+   case 17366:
+   case 17368:
+   case 17370:
+   case 17372:
+   case 17374:
+   case 17376:
+   case 17378:
+   case 17380:
+   case 17382:
+   case 17384:
+   case 17386:
+   case 17388:
+   case 17390:
+   case 17392:
+   case 17394:
+   case 17396:
+   case 17398:
+   case 17400:
+   case 17402:
+   case 17404:
+   case 17406:
+   case 17408:
+   case 17410:
+   case 17412:
+   case 17414:
+   case 17416:
+   case 17418:
+   case 17420:
+   case 17422:
+   case 17424:
+   case 17426:
+   case 17428:
+   case 17430:
+   case 17432:
+   case 17434:
+   case 17436:
+   case 17438:
+   case 17440:
+   case 17442:
+   case 17444:
+   case 17446:
+   case 17448:
+   case 17450:
+   case 17452:
+   case 17454:
+   case 17456:
+   case 17458:
+   case 17460:
+   case 17462:
+   case 17464:
+   case 17466:
+   case 17468:
+   case 17470:
+   case 17472:
+   case 17474:
+   case 17476:
+   case 17478:
+   case 17480:
+   case 17482:
+   case 17484:
+   case 17486:
+   case 17488:
+   case 17490:
+   case 17492:
+   case 17494:
+   case 17496:
+   case 17498:
+   case 17500:
+   case 17502:
+   case 17504:
+   case 17506:
+   case 17508:
+   case 17510:
+   case 17512:
+   case 17514:
+   case 17516:
+   case 17518:
+   case 17520:
+   case 17522:
+   case 17524:
+   case 17526:
+   case 17528:
+   case 17530:
+   case 17532:
+   case 17534:
+   case 17536:
+   case 17538:
+   case 17540:
+   case 17542:
+   case 17544:
+   case 17546:
+   case 17548:
+   case 17550:
+   case 17552:
+   case 17554:
+   case 17556:
+   case 17558:
+   case 17560:
+   case 17562:
+   case 17564:
+   case 17566:
+   case 17568:
+   case 17570:
+   case 17572:
+   case 17574:
+   case 17576:
+   case 17578:
+   case 17580:
+   case 17582:
+   case 17584:
+   case 17586:
+   case 17588:
+   case 17590:
+   case 17592:
+   case 17594:
+   case 17596:
+   case 17598:
+   case 17600:
+   case 17602:
+   case 17604:
+   case 17606:
+   case 17608:
+   case 17610:
+   case 17612:
+   case 17614:
+   case 17616:
+   case 17618:
+   case 17620:
+   case 17622:
+   case 17624:
+   case 17626:
+   case 17628:
+   case 17630:
+   case 17632:
+   case 17634:
+   case 17636:
+   case 17638:
+   case 17640:
+   case 17642:
+   case 17644:
+   case 17646:
+   case 17648:
+   case 17650:
+   case 17652:
+   case 17654:
+   case 17656:
+   case 17658:
+   case 17660:
+   case 17662:
+   case 17664:
+   case 17666:
+   case 17668:
+   case 17670:
+   case 17672:
+   case 17674:
+   case 17676:
+   case 17678:
+   case 17680:
+   case 17682:
+   case 17684:
+   case 17686:
+   case 17688:
+   case 17690:
+   case 17692:
+   case 17694:
+   case 17696:
+   case 17698:
+   case 17700:
+   case 17702:
+   case 17704:
+   case 17706:
+   case 17708:
+   case 17710:
+   case 17712:
+   case 17714:
+   case 17716:
+   case 17718:
+   case 17720:
+   case 17722:
+   case 17724:
+   case 17726:
+   case 17728:
+   case 17730:
+   case 17732:
+   case 17734:
+   case 17736:
+   case 17738:
+   case 17740:
+   case 17742:
+   case 17744:
+   case 17746:
+   case 17748:
+   case 17750:
+   case 17752:
+   case 17754:
+   case 17756:
+   case 17758:
+   case 17760:
+   case 17762:
+   case 17764:
+   case 17766:
+   case 17768:
+   case 17770:
+   case 17772:
+   case 17774:
+   case 17776:
+   case 17778:
+   case 17780:
+   case 17782:
+   case 17784:
+   case 17786:
+   case 17788:
+   case 17790:
+   case 17792:
+   case 17794:
+   case 17796:
+   case 17798:
+   case 17800:
+   case 17802:
+   case 17804:
+   case 17806:
+   case 17808:
+   case 17810:
+   case 17812:
+   case 17814:
+   case 17816:
+   case 17818:
+   case 17820:
+   case 17822:
+   case 17824:
+   case 17826:
+   case 17828:
+   case 17830:
+   case 17832:
+   case 17834:
+   case 17836:
+   case 17838:
+   case 17840:
+   case 17842:
+   case 17844:
+   case 17846:
+   case 17848:
+   case 17850:
+   case 17852:
+   case 17854:
+   case 17856:
+   case 17858:
+   case 17860:
+   case 17862:
+   case 17864:
+   case 17866:
+   case 17868:
+   case 17870:
+   case 17872:
+   case 17874:
+   case 17876:
+   case 17878:
+   case 17880:
+   case 17882:
+   case 17884:
+   case 17886:
+   case 17888:
+   case 17890:
+   case 17892:
+   case 17894:
+   case 17896:
+   case 17898:
+   case 17900:
+   case 17902:
+   case 17904:
+   case 17906:
+   case 17908:
+   case 17910:
+   case 17912:
+   case 17914:
+   case 17916:
+   case 17918:
+   case 17920:
+   case 17922:
+   case 17924:
+   case 17926:
+   case 17928:
+   case 17930:
+   case 17932:
+   case 17934:
+   case 17936:
+   case 17938:
+   case 17940:
+   case 17942:
+   case 17944:
+   case 17946:
+   case 17948:
+   case 17950:
+   case 17952:
+   case 17954:
+   case 17956:
+   case 17958:
+   case 17960:
+   case 17962:
+   case 17964:
+   case 17966:
+   case 17968:
+   case 17970:
+   case 17972:
+   case 17974:
+   case 17976:
+   case 17978:
+   case 17980:
+   case 17982:
+   case 17984:
+   case 17986:
+   case 17988:
+   case 17990:
+   case 17992:
+   case 17994:
+   case 17996:
+   case 17998:
+   case 18e3:
+   case 18002:
+   case 18004:
+   case 18006:
+   case 18008:
+   case 18010:
+   case 18012:
+   case 18014:
+   case 18016:
+   case 18018:
+   case 18020:
+   case 18022:
+   case 18024:
+   case 18026:
+   case 18028:
+   case 18030:
+   case 18032:
+   case 18034:
+   case 18036:
+   case 18038:
+   case 18040:
+   case 18042:
+   case 18044:
+   case 18046:
+   case 18048:
+   case 18050:
+   case 18052:
+   case 18054:
+   case 18056:
+   case 18058:
+   case 18060:
+   case 18062:
+   case 18064:
+   case 18066:
+   case 18068:
+   case 18070:
+   case 18072:
+   case 18074:
+   case 18076:
+   case 18078:
+   case 18080:
+   case 18082:
+   case 18084:
+   case 18086:
+   case 18088:
+   case 18090:
+   case 18092:
+   case 18094:
+   case 18096:
+   case 18098:
+   case 18100:
+   case 18102:
+   case 18104:
+   case 18106:
+   case 18108:
+   case 18110:
+   case 18112:
+   case 18114:
+   case 18116:
+   case 18118:
+   case 18120:
+   case 18122:
+   case 18124:
+   case 18126:
+   case 18128:
+   case 18130:
+   case 18132:
+   case 18134:
+   case 18136:
+   case 18138:
+   case 18140:
+   case 18142:
+   case 18144:
+   case 18146:
+   case 18148:
+   case 18150:
+   case 18152:
+   case 18154:
+   case 18156:
+   case 18158:
+   case 18160:
+   case 18162:
+   case 18164:
+   case 18166:
+   case 18168:
+   case 18170:
+   case 18172:
+   case 18174:
+   case 18176:
+   case 18178:
+   case 18180:
+   case 18182:
+   case 18184:
+   case 18186:
+   case 18188:
+   case 18190:
+   case 18192:
+   case 18194:
+   case 18196:
+   case 18198:
+   case 18200:
+   case 18202:
+   case 18204:
+   case 18206:
+   case 18208:
+   case 18210:
+   case 18212:
+   case 18214:
+   case 18216:
+   case 18218:
+   case 18220:
+   case 18222:
+   case 18224:
+   case 18226:
+   case 18228:
+   case 18230:
+   case 18232:
+   case 18234:
+   case 18236:
+   case 18238:
+   case 18240:
+   case 18242:
+   case 18244:
+   case 18246:
+   case 18248:
+   case 18250:
+   case 18252:
+   case 18254:
+   case 18256:
+   case 18258:
+   case 18260:
+   case 18262:
+   case 18264:
+   case 18266:
+   case 18268:
+   case 18270:
+   case 18272:
+   case 18274:
+   case 18276:
+   case 18278:
+   case 18280:
+   case 18282:
+   case 18284:
+   case 18286:
+   case 18288:
+   case 18290:
+   case 18292:
+   case 18294:
+   case 18296:
+   case 18298:
+   case 18300:
+   case 18302:
+   case 18304:
+   case 18306:
+   case 18308:
+   case 18310:
+   case 18312:
+   case 18314:
+   case 18316:
+   case 18318:
+   case 18320:
+   case 18322:
+   case 18324:
+   case 18326:
+   case 18328:
+   case 18330:
+   case 18332:
+   case 18334:
+   case 18336:
+   case 18338:
+   case 18340:
+   case 18342:
+   case 18344:
+   case 18346:
+   case 18348:
+   case 18350:
+   case 18352:
+   case 18354:
+   case 18356:
+   case 18358:
+   case 18360:
+   case 18362:
+   case 18364:
+   case 18366:
+   case 18368:
+   case 18370:
+   case 18372:
+   case 18374:
+   case 18376:
+   case 18378:
+   case 18380:
+   case 18382:
+   case 18384:
+   case 18386:
+   case 18388:
+   case 18390:
+   case 18392:
+   case 18394:
+   case 18396:
+   case 18398:
+   case 18400:
+   case 18402:
+   case 18404:
+   case 18406:
+   case 18408:
+   case 18410:
+   case 18412:
+   case 18414:
+   case 18416:
+   case 18418:
+   case 18420:
+   case 18422:
+   case 18424:
+   case 18426:
+   case 18428:
+   case 18430:
+   case 18432:
+   case 18434:
+   case 18436:
+   case 18438:
+   case 18440:
+   case 18442:
+   case 18444:
+   case 18446:
+   case 18448:
+   case 18450:
+   case 18452:
+   case 18454:
+   case 18456:
+   case 18458:
+   case 18460:
+   case 18462:
+   case 18464:
+   case 18466:
+   case 18468:
+   case 18470:
+   case 18472:
+   case 18474:
+   case 18476:
+   case 18478:
+   case 18480:
+   case 18482:
+   case 18484:
+   case 18486:
+   case 18488:
+   case 18490:
+   case 18492:
+   case 18494:
+   case 18496:
+   case 18498:
+   case 18500:
+   case 18502:
+   case 18504:
+   case 18506:
+   case 18508:
+   case 18510:
+   case 18512:
+   case 18514:
+   case 18516:
+   case 18518:
+   case 18520:
+   case 18522:
+   case 18524:
+   case 18526:
+   case 18528:
+   case 18530:
+   case 18532:
+   case 18534:
+   case 18536:
+   case 18538:
+   case 18540:
+   case 18542:
+   case 18544:
+   case 18546:
+   case 18548:
+   case 18550:
+   case 18552:
+   case 18554:
+   case 18556:
+   case 18558:
+   case 18560:
+   case 18562:
+   case 18564:
+   case 18566:
+   case 18568:
+   case 18570:
+   case 18572:
+   case 18574:
+   case 18576:
+   case 18578:
+   case 18580:
+   case 18582:
+   case 18584:
+   case 18586:
+   case 18588:
+   case 18590:
+   case 18592:
+   case 18594:
+   case 18596:
+   case 18598:
+   case 18600:
+   case 18602:
+   case 18604:
+   case 18606:
+   case 18608:
+   case 18610:
+   case 18612:
+   case 18614:
+   case 18616:
+   case 18618:
+   case 18620:
+   case 18622:
+   case 18624:
+   case 18626:
+   case 18628:
+   case 18630:
+   case 18632:
+   case 18634:
+   case 18636:
+   case 18638:
+   case 18640:
+   case 18642:
+   case 18644:
+   case 18646:
+   case 18648:
+   case 18650:
+   case 18652:
+   case 18654:
+   case 18656:
+   case 18658:
+   case 18660:
+   case 18662:
+   case 18664:
+   case 18666:
+   case 18668:
+   case 18670:
+   case 18672:
+   case 18674:
+   case 18676:
+   case 18678:
+   case 18680:
+   case 18682:
+   case 18684:
+   case 18686:
+   case 18688:
+   case 18690:
+   case 18692:
+   case 18694:
+   case 18696:
+   case 18698:
+   case 18700:
+   case 18702:
+   case 18704:
+   case 18706:
+   case 18708:
+   case 18710:
+   case 18712:
+   case 18714:
+   case 18716:
+   case 18718:
+   case 18720:
+   case 18722:
+   case 18724:
+   case 18726:
+   case 18728:
+   case 18730:
+   case 18732:
+   case 18734:
+   case 18736:
+   case 18738:
+   case 18740:
+   case 18742:
+   case 18744:
+   case 18746:
+   case 18748:
+   case 18750:
+   case 18752:
+   case 18754:
+   case 18756:
+   case 18758:
+   case 18760:
+   case 18762:
+   case 18764:
+   case 18766:
+   case 18768:
+   case 18770:
+   case 18772:
+   case 18774:
+   case 18776:
+   case 18778:
+   case 18780:
+   case 18782:
+   case 18784:
+   case 18786:
+   case 18788:
+   case 18790:
+   case 18792:
+   case 18794:
+   case 18796:
+   case 18798:
+   case 18800:
+   case 18802:
+   case 18804:
+   case 18806:
+   case 18808:
+   case 18810:
+   case 18812:
+   case 18814:
+   case 18816:
+   case 18818:
+   case 18820:
+   case 18822:
+   case 18824:
+   case 18826:
+   case 18828:
+   case 18830:
+   case 18832:
+   case 18834:
+   case 18836:
+   case 18838:
+   case 18840:
+   case 18842:
+   case 18844:
+   case 18846:
+   case 18848:
+   case 18850:
+   case 18852:
+   case 18854:
+   case 18856:
+   case 18858:
+   case 18860:
+   case 18862:
+   case 18864:
+   case 18866:
+   case 18868:
+   case 18870:
+   case 18872:
+   case 18874:
+   case 18876:
+   case 18878:
+   case 18880:
+   case 18882:
+   case 18884:
+   case 18886:
+   case 18888:
+   case 18890:
+   case 18892:
+   case 18894:
+   case 18896:
+   case 18898:
+   case 18900:
+   case 18902:
+   case 18904:
+   case 18906:
+   case 18908:
+   case 18910:
+   case 18912:
+   case 18914:
+   case 18916:
+   case 18918:
+   case 18920:
+   case 18922:
+   case 18924:
+   case 18926:
+   case 18928:
+   case 18930:
+   case 18932:
+   case 18934:
+   case 18936:
+   case 18938:
+   case 18940:
+   case 18942:
+   case 18944:
+   case 18946:
+   case 18948:
+   case 18950:
+   case 18952:
+   case 18954:
+   case 18956:
+   case 18958:
+   case 18960:
+   case 18962:
+   case 18964:
+   case 18966:
+   case 18968:
+   case 18970:
+   case 18972:
+   case 18974:
+   case 18976:
+   case 18978:
+   case 18980:
+   case 18982:
+   case 18984:
+   case 18986:
+   case 18988:
+   case 18990:
+   case 18992:
+   case 18994:
+   case 18996:
+   case 18998:
+   case 19e3:
+   case 19002:
+   case 19004:
+   case 19006:
+   case 19008:
+   case 19010:
+   case 19012:
+   case 19014:
+   case 19016:
+   case 19018:
+   case 19020:
+   case 19022:
+   case 19024:
+   case 19026:
+   case 19028:
+   case 19030:
+   case 19032:
+   case 19034:
+   case 19036:
+   case 19038:
+   case 19040:
+   case 19042:
+   case 19044:
+   case 19046:
+   case 19048:
+   case 19050:
+   case 19052:
+   case 19054:
+   case 19056:
+   case 19058:
+   case 19060:
+   case 19062:
+   case 19064:
+   case 19066:
+   case 19068:
+   case 19070:
+   case 19072:
+   case 19074:
+   case 19076:
+   case 19078:
+   case 19080:
+   case 19082:
+   case 19084:
+   case 19086:
+   case 19088:
+   case 19090:
+   case 19092:
+   case 19094:
+   case 19096:
+   case 19098:
+   case 19100:
+   case 19102:
+   case 19104:
+   case 19106:
+   case 19108:
+   case 19110:
+   case 19112:
+   case 19114:
+   case 19116:
+   case 19118:
+   case 19120:
+   case 19122:
+   case 19124:
+   case 19126:
+   case 19128:
+   case 19130:
+   case 19132:
+   case 19134:
+   case 19136:
+   case 19138:
+   case 19140:
+   case 19142:
+   case 19144:
+   case 19146:
+   case 19148:
+   case 19150:
+   case 19152:
+   case 19154:
+   case 19156:
+   case 19158:
+   case 19160:
+   case 19162:
+   case 19164:
+   case 19166:
+   case 19168:
+   case 19170:
+   case 19172:
+   case 19174:
+   case 19176:
+   case 19178:
+   case 19180:
+   case 19182:
+   case 19184:
+   case 19186:
+   case 19188:
+   case 19190:
+   case 19192:
+   case 19194:
+   case 19196:
+   case 19198:
+   case 19200:
+   case 19202:
+   case 19204:
+   case 19206:
+   case 19208:
+   case 19210:
+   case 19212:
+   case 19214:
+   case 19216:
+   case 19218:
+   case 19220:
+   case 19222:
+   case 19224:
+   case 19226:
+   case 19228:
+   case 19230:
+   case 19232:
+   case 19234:
+   case 19236:
+   case 19238:
+   case 19240:
+   case 19242:
+   case 19244:
+   case 19246:
+   case 19248:
+   case 19250:
+   case 19252:
+   case 19254:
+   case 19256:
+   case 19258:
+   case 19260:
+   case 19262:
+   case 19264:
+   case 19266:
+   case 19268:
+   case 19270:
+   case 19272:
+   case 19274:
+   case 19276:
+   case 19278:
+   case 19280:
+   case 19282:
+   case 19284:
+   case 19286:
+   case 19288:
+   case 19290:
+   case 19292:
+   case 19294:
+   case 19296:
+   case 19298:
+   case 19300:
+   case 19302:
+   case 19304:
+   case 19306:
+   case 19308:
+   case 19310:
+   case 19312:
+   case 19314:
+   case 19316:
+   case 19318:
+   case 19320:
+   case 19322:
+   case 19324:
+   case 19326:
+   case 19328:
+   case 19330:
+   case 19332:
+   case 19334:
+   case 19336:
+   case 19338:
+   case 19340:
+   case 19342:
+   case 19344:
+   case 19346:
+   case 19348:
+   case 19350:
+   case 19352:
+   case 19354:
+   case 19356:
+   case 19358:
+   case 19360:
+   case 19362:
+   case 19364:
+   case 19366:
+   case 19368:
+   case 19370:
+   case 19372:
+   case 19374:
+   case 19376:
+   case 19378:
+   case 19380:
+   case 19382:
+   case 19384:
+   case 19386:
+   case 19388:
+   case 19390:
+   case 19392:
+   case 19394:
+   case 19396:
+   case 19398:
+   case 19400:
+   case 19402:
+   case 19404:
+   case 19406:
+   case 19408:
+   case 19410:
+   case 19412:
+   case 19414:
+   case 19416:
+   case 19418:
+   case 19420:
+   case 19422:
+   case 19424:
+   case 19426:
+   case 19428:
+   case 19430:
+   case 19432:
+   case 19434:
+   case 19436:
+   case 19438:
+   case 19440:
+   case 19442:
+   case 19444:
+   case 19446:
+   case 19448:
+   case 19450:
+   case 19452:
+   case 19454:
+   case 19456:
+   case 19458:
+   case 19460:
+   case 19462:
+   case 19464:
+   case 19466:
+   case 19468:
+   case 19470:
+   case 19472:
+   case 19474:
+   case 19476:
+   case 19478:
+   case 19480:
+   case 19482:
+   case 19484:
+   case 19486:
+   case 19488:
+   case 19490:
+   case 19492:
+   case 19494:
+   case 19496:
+   case 19498:
+   case 19500:
+   case 19502:
+   case 19504:
+   case 19506:
+   case 19508:
+   case 19510:
+   case 19512:
+   case 19514:
+   case 19516:
+   case 19518:
+   case 19520:
+   case 19522:
+   case 19524:
+   case 19526:
+   case 19528:
+   case 19530:
+   case 19532:
+   case 19534:
+   case 19536:
+   case 19538:
+   case 19540:
+   case 19542:
+   case 19544:
+   case 19546:
+   case 19548:
+   case 19550:
+   case 19552:
+   case 19554:
+   case 19556:
+   case 19558:
+   case 19560:
+   case 19562:
+   case 19564:
+   case 19566:
+   case 19568:
+   case 19570:
+   case 19572:
+   case 19574:
+   case 19576:
+   case 19578:
+   case 19580:
+   case 19582:
+   case 19584:
+   case 19586:
+   case 19588:
+   case 19590:
+   case 19592:
+   case 19594:
+   case 19596:
+   case 19598:
+   case 19600:
+   case 19602:
+   case 19604:
+   case 19606:
+   case 19608:
+   case 19610:
+   case 19612:
+   case 19614:
+   case 19616:
+   case 19618:
+   case 19620:
+   case 19622:
+   case 19624:
+   case 19626:
+   case 19628:
+   case 19630:
+   case 19632:
+   case 19634:
+   case 19636:
+   case 19638:
+   case 19640:
+   case 19642:
+   case 19644:
+   case 19646:
+   case 19648:
+   case 19650:
+   case 19652:
+   case 19654:
+   case 19656:
+   case 19658:
+   case 19660:
+   case 19662:
+   case 19664:
+   case 19666:
+   case 19668:
+   case 19670:
+   case 19672:
+   case 19674:
+   case 19676:
+   case 19678:
+   case 19680:
+   case 19682:
+   case 19684:
+   case 19686:
+   case 19688:
+   case 19690:
+   case 19692:
+   case 19694:
+   case 19696:
+   case 19698:
+   case 19700:
+   case 19702:
+   case 19704:
+   case 19706:
+   case 19708:
+   case 19710:
+   case 19712:
+   case 19714:
+   case 19716:
+   case 19718:
+   case 19720:
+   case 19722:
+   case 19724:
+   case 19726:
+   case 19728:
+   case 19730:
+   case 19732:
+   case 19734:
+   case 19736:
+   case 19738:
+   case 19740:
+   case 19742:
+   case 19744:
+   case 19746:
+   case 19748:
+   case 19750:
+   case 19752:
+   case 19754:
+   case 19756:
+   case 19758:
+   case 19760:
+   case 19762:
+   case 19764:
+   case 19766:
+   case 19768:
+   case 19770:
+   case 19772:
+   case 19774:
+   case 19776:
+   case 19778:
+   case 19780:
+   case 19782:
+   case 19784:
+   case 19786:
+   case 19788:
+   case 19790:
+   case 19792:
+   case 19794:
+   case 19796:
+   case 19798:
+   case 19800:
+   case 19802:
+   case 19804:
+   case 19806:
+   case 19808:
+   case 19810:
+   case 19812:
+   case 19814:
+   case 19816:
+   case 19818:
+   case 19820:
+   case 19822:
+   case 19824:
+   case 19826:
+   case 19828:
+   case 19830:
+   case 19832:
+   case 19834:
+   case 19836:
+   case 19838:
+   case 19840:
+   case 19842:
+   case 19844:
+   case 19846:
+   case 19848:
+   case 19850:
+   case 19852:
+   case 19854:
+   case 19856:
+   case 19858:
+   case 19860:
+   case 19862:
+   case 19864:
+   case 19866:
+   case 19868:
+   case 19870:
+   case 19872:
+   case 19874:
+   case 19876:
+   case 19878:
+   case 19880:
+   case 19882:
+   case 19884:
+   case 19886:
+   case 19888:
+   case 19890:
+   case 19892:
+   case 19894:
+   case 19896:
+   case 19898:
+   case 19900:
+   case 19902:
+   case 19904:
+   case 19906:
+   case 19908:
+   case 19910:
+   case 19912:
+   case 19914:
+   case 19916:
+   case 19918:
+   case 19920:
+   case 19922:
+   case 19924:
+   case 19926:
+   case 19928:
+   case 19930:
+   case 19932:
+   case 19934:
+   case 19936:
+   case 19938:
+   case 19940:
+   case 19942:
+   case 19944:
+   case 19946:
+   case 19948:
+   case 19950:
+   case 19952:
+   case 19954:
+   case 19956:
+   case 19958:
+   case 19960:
+   case 19962:
+   case 19964:
+   case 19966:
+   case 19968:
+   case 19970:
+   case 19972:
+   case 19974:
+   case 19976:
+   case 19978:
+   case 19980:
+   case 19982:
+   case 19984:
+   case 19986:
+   case 19988:
+   case 19990:
+   case 19992:
+   case 19994:
+   case 19996:
+   case 19998:
+   case 2e4:
+   case 20002:
+   case 20004:
+   case 20006:
+   case 20008:
+   case 20010:
+   case 20012:
+   case 20014:
+   case 20016:
+   case 20018:
+   case 20020:
+   case 20022:
+   case 20024:
+   case 20026:
+   case 20028:
+   case 20030:
+   case 20032:
+   case 20034:
+   case 20036:
+   case 20038:
+   case 20040:
+   case 20042:
+   case 20044:
+   case 20046:
+   case 20048:
+   case 20050:
+   case 20052:
+   case 20054:
+   case 20056:
+   case 20058:
+   case 20060:
+   case 20062:
+   case 20064:
+   case 20066:
+   case 20068:
+   case 20070:
+   case 20072:
+   case 20074:
+   case 20076:
+   case 20078:
+   case 20080:
+   case 20082:
+   case 20084:
+   case 20086:
+   case 20088:
+   case 20090:
+   case 20092:
+   case 20094:
+   case 20096:
+   case 20098:
+   case 20100:
+   case 20102:
+   case 20104:
+   case 20106:
+   case 20108:
+   case 20110:
+   case 20112:
+   case 20114:
+   case 20116:
+   case 20118:
+   case 20120:
+   case 20122:
+   case 20124:
+   case 20126:
+   case 20128:
+   case 20130:
+   case 20132:
+   case 20134:
+   case 20136:
+   case 20138:
+   case 20140:
+   case 20142:
+   case 20144:
+   case 20146:
+   case 20148:
+   case 20150:
+   case 20152:
+   case 20154:
+   case 20156:
+   case 20158:
+   case 20160:
+   case 20162:
+   case 20164:
+   case 20166:
+   case 20168:
+   case 20170:
+   case 20172:
+   case 20174:
+   case 20176:
+   case 20178:
+   case 20180:
+   case 20182:
+   case 20184:
+   case 20186:
+   case 20188:
+   case 20190:
+   case 20192:
+   case 20194:
+   case 20196:
+   case 20198:
+   case 20200:
+   case 20202:
+   case 20204:
+   case 20206:
+   case 20208:
+   case 20210:
+   case 20212:
+   case 20214:
+   case 20216:
+   case 20218:
+   case 20220:
+   case 20222:
+   case 20224:
+   case 20226:
+   case 20228:
+   case 20230:
+   case 20232:
+   case 20234:
+   case 20236:
+   case 20238:
+   case 20240:
+   case 20242:
+   case 20244:
+   case 20246:
+   case 20248:
+   case 20250:
+   case 20252:
+   case 20254:
+   case 20256:
+   case 20258:
+   case 20260:
+   case 20262:
+   case 20264:
+   case 20266:
+   case 20268:
+   case 20270:
+   case 20272:
+   case 20274:
+   case 20276:
+   case 20278:
+   case 20280:
+   case 20282:
+   case 20284:
+   case 20286:
+   case 20288:
+   case 20290:
+   case 20292:
+   case 20294:
+   case 20296:
+   case 20298:
+   case 20300:
+   case 20302:
+   case 20304:
+   case 20306:
+   case 20308:
+   case 20310:
+   case 20312:
+   case 20314:
+   case 20316:
+   case 20318:
+   case 20320:
+   case 20322:
+   case 20324:
+   case 20326:
+   case 20328:
+   case 20330:
+   case 20332:
+   case 20334:
+   case 20336:
+   case 20338:
+   case 20340:
+   case 20342:
+   case 20344:
+   case 20346:
+   case 20348:
+   case 20350:
+   case 20352:
+   case 20354:
+   case 20356:
+   case 20358:
+   case 20360:
+   case 20362:
+   case 20364:
+   case 20366:
+   case 20368:
+   case 20370:
+   case 20372:
+   case 20374:
+   case 20376:
+   case 20378:
+   case 20380:
+   case 20382:
+   case 20384:
+   case 20386:
+   case 20388:
+   case 20390:
+   case 20392:
+   case 20394:
+   case 20396:
+   case 20398:
+   case 20400:
+   case 20402:
+   case 20404:
+   case 20406:
+   case 20408:
+   case 20410:
+   case 20412:
+   case 20414:
+   case 20416:
+   case 20418:
+   case 20420:
+   case 20422:
+   case 20424:
+   case 20426:
+   case 20428:
+   case 20430:
+   case 20432:
+   case 20434:
+   case 20436:
+   case 20438:
+   case 20440:
+   case 20442:
+   case 20444:
+   case 20446:
+   case 20448:
+   case 20450:
+   case 20452:
+   case 20454:
+   case 20456:
+   case 20458:
+   case 20460:
+   case 20462:
+   case 20464:
+   case 20466:
+   case 20468:
+   case 20470:
+   case 20472:
+   case 20474:
+   case 20476:
+   case 20478:
+   case 20480:
+   case 20482:
+   case 20484:
+   case 20486:
+   case 20488:
+   case 20490:
+   case 20492:
+   case 20494:
+   case 20496:
+   case 20498:
+   case 20500:
+   case 20502:
+   case 20504:
+   case 20506:
+   case 20508:
+   case 20510:
+   case 20512:
+   case 20514:
+   case 20516:
+   case 20518:
+   case 20520:
+   case 20522:
+   case 20524:
+   case 20526:
+   case 20528:
+   case 20530:
+   case 20532:
+   case 20534:
+   case 20536:
+   case 20538:
+   case 20540:
+   case 20542:
+   case 20544:
+   case 20546:
+   case 20548:
+   case 20550:
+   case 20552:
+   case 20554:
+   case 20556:
+   case 20558:
+   case 20560:
+   case 20562:
+   case 20564:
+   case 20566:
+   case 20568:
+   case 20570:
+   case 20572:
+   case 20574:
+   case 20576:
+   case 20578:
+   case 20580:
+   case 20582:
+   case 20584:
+   case 20586:
+   case 20588:
+   case 20590:
+   case 20592:
+   case 20594:
+   case 20596:
+   case 20598:
+   case 20600:
+   case 20602:
+   case 20604:
+   case 20606:
+   case 20608:
+   case 20610:
+   case 20612:
+   case 20614:
+   case 20616:
+   case 20618:
+   case 20620:
+   case 20622:
+   case 20624:
+   case 20626:
+   case 20628:
+   case 20630:
+   case 20632:
+   case 20634:
+   case 20636:
+   case 20638:
+   case 20640:
+   case 20642:
+   case 20644:
+   case 20646:
+   case 20648:
+   case 20650:
+   case 20652:
+   case 20654:
+   case 20656:
+   case 20658:
+   case 20660:
+   case 20662:
+   case 20664:
+   case 20666:
+   case 20668:
+   case 20670:
+   case 20672:
+   case 20674:
+   case 20676:
+   case 20678:
+   case 20680:
+   case 20682:
+   case 20684:
+   case 20686:
+   case 20688:
+   case 20690:
+   case 20692:
+   case 20694:
+   case 20696:
+   case 20698:
+   case 20700:
+   case 20702:
+   case 20704:
+   case 20706:
+   case 20708:
+   case 20710:
+   case 20712:
+   case 20714:
+   case 20716:
+   case 20718:
+   case 20720:
+   case 20722:
+   case 20724:
+   case 20726:
+   case 20728:
+   case 20730:
+   case 20732:
+   case 20734:
+   case 20736:
+   case 20738:
+   case 20740:
+   case 20742:
+   case 20744:
+   case 20746:
+   case 20748:
+   case 20750:
+   case 20752:
+   case 20754:
+   case 20756:
+   case 20758:
+   case 20760:
+   case 20762:
+   case 20764:
+   case 20766:
+   case 20768:
+   case 20770:
+   case 20772:
+   case 20774:
+   case 20776:
+   case 20778:
+   case 20780:
+   case 20782:
+   case 20784:
+   case 20786:
+   case 20788:
+   case 20790:
+   case 20792:
+   case 20794:
+   case 20796:
+   case 20798:
+   case 20800:
+   case 20802:
+   case 20804:
+   case 20806:
+   case 20808:
+   case 20810:
+   case 20812:
+   case 20814:
+   case 20816:
+   case 20818:
+   case 20820:
+   case 20822:
+   case 20824:
+   case 20826:
+   case 20828:
+   case 20830:
+   case 20832:
+   case 20834:
+   case 20836:
+   case 20838:
+   case 20840:
+   case 20842:
+   case 20844:
+   case 20846:
+   case 20848:
+   case 20850:
+   case 20852:
+   case 20854:
+   case 20856:
+   case 20858:
+   case 20860:
+   case 20862:
+   case 20864:
+   case 20866:
+   case 20868:
+   case 20870:
+   case 20872:
+   case 20874:
+   case 20876:
+   case 20878:
+   case 20880:
+   case 20882:
+   case 20884:
+   case 20886:
+   case 20888:
+   case 20890:
+   case 20892:
+   case 20894:
+   case 20896:
+   case 20898:
+   case 20900:
+   case 20902:
+   case 20904:
+   case 20906:
+   case 20908:
+   case 20910:
+   case 20912:
+   case 20914:
+   case 20916:
+   case 20918:
+   case 20920:
+   case 20922:
+   case 20924:
+   case 20926:
+   case 20928:
+   case 20930:
+   case 20932:
+   case 20934:
+   case 20936:
+   case 20938:
+   case 20940:
+   case 20942:
+   case 20944:
+   case 20946:
+   case 20948:
+   case 20950:
+   case 20952:
+   case 20954:
+   case 20956:
+   case 20958:
+   case 20960:
+   case 20962:
+   case 20964:
+   case 20966:
+   case 20968:
+   case 20970:
+   case 20972:
+   case 20974:
+   case 20976:
+   case 20978:
+   case 20980:
+   case 20982:
+   case 20984:
+   case 20986:
+   case 20988:
+   case 20990:
+   case 20992:
+   case 20994:
+   case 20996:
+   case 20998:
+   case 21e3:
+   case 21002:
+   case 21004:
+   case 21006:
+   case 21008:
+   case 21010:
+   case 21012:
+   case 21014:
+   case 21016:
+   case 21018:
+   case 21020:
+   case 21022:
+   case 21024:
+   case 21026:
+   case 21028:
+   case 21030:
+   case 21032:
+   case 21034:
+   case 21036:
+   case 21038:
+   case 21040:
+   case 21042:
+   case 21044:
+   case 21046:
+   case 21048:
+   case 21050:
+   case 21052:
+   case 21054:
+   case 21056:
+   case 21058:
+   case 21060:
+   case 21062:
+   case 21064:
+   case 21066:
+   case 21068:
+   case 21070:
+   case 21072:
+   case 21074:
+   case 21076:
+   case 21078:
+   case 21080:
+   case 21082:
+   case 21084:
+   case 21086:
+   case 21088:
+   case 21090:
+   case 21092:
+   case 21094:
+   case 21096:
+   case 21098:
+   case 21100:
+   case 21102:
+   case 21104:
+   case 21106:
+   case 21108:
+   case 21110:
+   case 21112:
+   case 21114:
+   case 21116:
+   case 21118:
+   case 21120:
+   case 21122:
+   case 21124:
+   case 21126:
+   case 21128:
+   case 21130:
+   case 21132:
+   case 21134:
+   case 21136:
+   case 21138:
+   case 21140:
+   case 21142:
+   case 21144:
+   case 21146:
+   case 21148:
+   case 21150:
+   case 21152:
+   case 21154:
+   case 21156:
+   case 21158:
+   case 21160:
+   case 21162:
+   case 21164:
+   case 21166:
+   case 21168:
+   case 21170:
+   case 21172:
+   case 21174:
+   case 21176:
+   case 21178:
+   case 21180:
+   case 21182:
+   case 21184:
+   case 21186:
+   case 21188:
+   case 21190:
+   case 21192:
+   case 21194:
+   case 21196:
+   case 21198:
+   case 21200:
+   case 21202:
+   case 21204:
+   case 21206:
+   case 21208:
+   case 21210:
+   case 21212:
+   case 21214:
+   case 21216:
+   case 21218:
+   case 21220:
+   case 21222:
+   case 21224:
+   case 21226:
+   case 21228:
+   case 21230:
+   case 21232:
+   case 21234:
+   case 21236:
+   case 21238:
+   case 21240:
+   case 21242:
+   case 21244:
+   case 21246:
+   case 21248:
+   case 21250:
+   case 21252:
+   case 21254:
+   case 21256:
+   case 21258:
+   case 21260:
+   case 21262:
+   case 21264:
+   case 21266:
+   case 21268:
+   case 21270:
+   case 21272:
+   case 21274:
+   case 21276:
+   case 21278:
+   case 21280:
+   case 21282:
+   case 21284:
+   case 21286:
+   case 21288:
+   case 21290:
+   case 21292:
+   case 21294:
+   case 21296:
+   case 21298:
+   case 21300:
+   case 21302:
+   case 21304:
+   case 21306:
+   case 21308:
+   case 21310:
+   case 21312:
+   case 21314:
+   case 21316:
+   case 21318:
+   case 21320:
+   case 21322:
+   case 21324:
+   case 21326:
+   case 21328:
+   case 21330:
+   case 21332:
+   case 21334:
+   case 21336:
+   case 21338:
+   case 21340:
+   case 21342:
+   case 21344:
+   case 21346:
+   case 21348:
+   case 21350:
+   case 21352:
+   case 21354:
+   case 21356:
+   case 21358:
+   case 21360:
+   case 21362:
+   case 21364:
+   case 21366:
+   case 21368:
+   case 21370:
+   case 21372:
+   case 21374:
+   case 21376:
+   case 21378:
+   case 21380:
+   case 21382:
+   case 21384:
+   case 21386:
+   case 21388:
+   case 21390:
+   case 21392:
+   case 21394:
+   case 21396:
+   case 21398:
+   case 21400:
+   case 21402:
+   case 21404:
+   case 21406:
+   case 21408:
+   case 21410:
+   case 21412:
+   case 21414:
+   case 21416:
+   case 21418:
+   case 21420:
+   case 21422:
+   case 21424:
+   case 21426:
+   case 21428:
+   case 21430:
+   case 21432:
+   case 21434:
+   case 21436:
+   case 21438:
+   case 21440:
+   case 21442:
+   case 21444:
+   case 21446:
+   case 21448:
+   case 21450:
+   case 21452:
+   case 21454:
+   case 21456:
+   case 21458:
+   case 21460:
+   case 21462:
+   case 21464:
+   case 21466:
+   case 21468:
+   case 21470:
+   case 21472:
+   case 21474:
+   case 21476:
+   case 21478:
+   case 21480:
+   case 21482:
+   case 21484:
+   case 21486:
+   case 21488:
+   case 21490:
+   case 21492:
+   case 21494:
+   case 21496:
+   case 21498:
+   case 21500:
+   case 21502:
+   case 21504:
+   case 21506:
+   case 21508:
+   case 21510:
+   case 21512:
+   case 21514:
+   case 21516:
+   case 21518:
+   case 21520:
+   case 21522:
+   case 21524:
+   case 21526:
+   case 21528:
+   case 21530:
+   case 21532:
+   case 21534:
+   case 21536:
+   case 21538:
+   case 21540:
+   case 21542:
+   case 21544:
+   case 21546:
+   case 21548:
+   case 21550:
+   case 21552:
+   case 21554:
+   case 21556:
+   case 21558:
+   case 21560:
+   case 21562:
+   case 21564:
+   case 21566:
+   case 21568:
+   case 21570:
+   case 21572:
+   case 21574:
+   case 21576:
+   case 21578:
+   case 21580:
+   case 21582:
+   case 21584:
+   case 21586:
+   case 21588:
+   case 21590:
+   case 21592:
+   case 21594:
+   case 21596:
+   case 21598:
+   case 21600:
+   case 21602:
+   case 21604:
+   case 21606:
+   case 21608:
+   case 21610:
+   case 21612:
+   case 21614:
+   case 21616:
+   case 21618:
+   case 21620:
+   case 21622:
+   case 21624:
+   case 21626:
+   case 21628:
+   case 21630:
+   case 21632:
+   case 21634:
+   case 21636:
+   case 21638:
+   case 21640:
+   case 21642:
+   case 21644:
+   case 21646:
+   case 21648:
+   case 21650:
+   case 21652:
+   case 21654:
+   case 21656:
+   case 21658:
+   case 21660:
+   case 21662:
+   case 21664:
+   case 21666:
+   case 21668:
+   case 21670:
+   case 21672:
+   case 21674:
+   case 21676:
+   case 21678:
+   case 21680:
+   case 21682:
+   case 21684:
+   case 21686:
+   case 21688:
+   case 21690:
+   case 21692:
+   case 21694:
+   case 21696:
+   case 21698:
+   case 21700:
+   case 21702:
+   case 21704:
+   case 21706:
+   case 21708:
+   case 21710:
+   case 21712:
+   case 21714:
+   case 21716:
+   case 21718:
+   case 21720:
+   case 21722:
+   case 21724:
+   case 21726:
+   case 21728:
+   case 21730:
+   case 21732:
+   case 21734:
+   case 21736:
+   case 21738:
+   case 21740:
+   case 21742:
+   case 21744:
+   case 21746:
+   case 21748:
+   case 21750:
+   case 21752:
+   case 21754:
+   case 21756:
+   case 21758:
+   case 21760:
+   case 21762:
+   case 21764:
+   case 21766:
+   case 21768:
+   case 21770:
+   case 21772:
+   case 21774:
+   case 21776:
+   case 21778:
+   case 21780:
+   case 21782:
+   case 21784:
+   case 21786:
+   case 21788:
+   case 21790:
+   case 21792:
+   case 21794:
+   case 21796:
+   case 21798:
+   case 21800:
+   case 21802:
+   case 21804:
+   case 21806:
+   case 21808:
+   case 21810:
+   case 21812:
+   case 21814:
+   case 21816:
+   case 21818:
+   case 21820:
+   case 21822:
+   case 21824:
+   case 21826:
+   case 21828:
+   case 21830:
+   case 21832:
+   case 21834:
+   case 21836:
+   case 21838:
+   case 21840:
+   case 21842:
+   case 21844:
+   case 21846:
+   case 21848:
+   case 21850:
+   case 21852:
+   case 21854:
+   case 21856:
+   case 21858:
+   case 21860:
+   case 21862:
+   case 21864:
+   case 21866:
+   case 21868:
+   case 21870:
+   case 21872:
+   case 21874:
+   case 21876:
+   case 21878:
+   case 21880:
+   case 21882:
+   case 21884:
+   case 21886:
+   case 21888:
+   case 21890:
+   case 21892:
+   case 21894:
+   case 21896:
+   case 21898:
+   case 21900:
+   case 21902:
+   case 21904:
+   case 21906:
+   case 21908:
+   case 21910:
+   case 21912:
+   case 21914:
+   case 21916:
+   case 21918:
+   case 21920:
+   case 21922:
+   case 21924:
+   case 21926:
+   case 21928:
+   case 21930:
+   case 21932:
+   case 21934:
+   case 21936:
+   case 21938:
+   case 21940:
+   case 21942:
+   case 21944:
+   case 21946:
+   case 21948:
+   case 21950:
+   case 21952:
+   case 21954:
+   case 21956:
+   case 21958:
+   case 21960:
+   case 21962:
+   case 21964:
+   case 21966:
+   case 21968:
+   case 21970:
+   case 21972:
+   case 21974:
+   case 21976:
+   case 21978:
+   case 21980:
+   case 21982:
+   case 21984:
+   case 21986:
+   case 21988:
+   case 21990:
+   case 21992:
+   case 21994:
+   case 21996:
+   case 21998:
+   case 22e3:
+   case 22002:
+   case 22004:
+   case 22006:
+   case 22008:
+   case 22010:
+   case 22012:
+   case 22014:
+   case 22016:
+   case 22018:
+   case 22020:
+   case 22022:
+   case 22024:
+   case 22026:
+   case 22028:
+   case 22030:
+   case 22032:
+   case 22034:
+   case 22036:
+   case 22038:
+   case 22040:
+   case 22042:
+   case 22044:
+   case 22046:
+   case 22048:
+   case 22050:
+   case 22052:
+   case 22054:
+   case 22056:
+   case 22058:
+   case 22060:
+   case 22062:
+   case 22064:
+   case 22066:
+   case 22068:
+   case 22070:
+   case 22072:
+   case 22074:
+   case 22076:
+   case 22078:
+   case 22080:
+   case 22082:
+   case 22084:
+   case 22086:
+   case 22088:
+   case 22090:
+   case 22092:
+   case 22094:
+   case 22096:
+   case 22098:
+   case 22100:
+   case 22102:
+   case 22104:
+   case 22106:
+   case 22108:
+   case 22110:
+   case 22112:
+   case 22114:
+   case 22116:
+   case 22118:
+   case 22120:
+   case 22122:
+   case 22124:
+   case 22126:
+   case 22128:
+   case 22130:
+   case 22132:
+   case 22134:
+   case 22136:
+   case 22138:
+   case 22140:
+   case 22142:
+   case 22144:
+   case 22146:
+   case 22148:
+   case 22150:
+   case 22152:
+   case 22154:
+   case 22156:
+   case 22158:
+   case 22160:
+   case 22162:
+   case 22164:
+   case 22166:
+   case 22168:
+   case 22170:
+   case 22172:
+   case 22174:
+   case 22176:
+   case 22178:
+   case 22180:
+   case 22182:
+   case 22184:
+   case 22186:
+   case 22188:
+   case 22190:
+   case 22192:
+   case 22194:
+   case 22196:
+   case 22198:
+   case 22200:
+   case 22202:
+   case 22204:
+   case 22206:
+   case 22208:
+   case 22210:
+   case 22212:
+   case 22214:
+   case 22216:
+   case 22218:
+   case 22220:
+   case 22222:
+   case 22224:
+   case 22226:
+   case 22228:
+   case 22230:
+   case 22232:
+   case 22234:
+   case 22236:
+   case 22238:
+   case 22240:
+   case 22242:
+   case 22244:
+   case 22246:
+   case 22248:
+   case 22250:
+   case 22252:
+   case 22254:
+   case 22256:
+   case 22258:
+   case 22260:
+   case 22262:
+   case 22264:
+   case 22266:
+   case 22268:
+   case 22270:
+   case 22272:
+   case 22274:
+   case 22276:
+   case 22278:
+   case 22280:
+   case 22282:
+   case 22284:
+   case 22286:
+   case 22288:
+   case 22290:
+   case 22292:
+   case 22294:
+   case 22296:
+   case 22298:
+   case 22300:
+   case 22302:
+   case 22304:
+   case 22306:
+   case 22308:
+   case 22310:
+   case 22312:
+   case 22314:
+   case 22316:
+   case 22318:
+   case 22320:
+   case 22322:
+   case 22324:
+   case 22326:
+   case 22328:
+   case 22330:
+   case 22332:
+   case 22334:
+   case 22336:
+   case 22338:
+   case 22340:
+   case 22342:
+   case 22344:
+   case 22346:
+   case 22348:
+   case 22350:
+   case 22352:
+   case 22354:
+   case 22356:
+   case 22358:
+   case 22360:
+   case 22362:
+   case 22364:
+   case 22366:
+   case 22368:
+   case 22370:
+   case 22372:
+   case 22374:
+   case 22376:
+   case 22378:
+   case 22380:
+   case 22382:
+   case 22384:
+   case 22386:
+   case 22388:
+   case 22390:
+   case 22392:
+   case 22394:
+   case 22396:
+   case 22398:
+   case 22400:
+   case 22402:
+   case 22404:
+   case 22406:
+   case 22408:
+   case 22410:
+   case 22412:
+   case 22414:
+   case 22416:
+   case 22418:
+   case 22420:
+   case 22422:
+   case 22424:
+   case 22426:
+   case 22428:
+   case 22430:
+   case 22432:
+   case 22434:
+   case 22436:
+   case 22438:
+   case 22440:
+   case 22442:
+   case 22444:
+   case 22446:
+   case 22448:
+   case 22450:
+   case 22452:
+   case 22454:
+   case 22456:
+   case 22458:
+   case 22460:
+   case 22462:
+   case 22464:
+   case 22466:
+   case 22468:
+   case 22470:
+   case 22472:
+   case 22474:
+   case 22476:
+   case 22478:
+   case 22480:
+   case 22482:
+   case 22484:
+   case 22486:
+   case 22488:
+   case 22490:
+   case 22492:
+   case 22494:
+   case 22496:
+   case 22498:
+   case 22500:
+   case 22502:
+   case 22504:
+   case 22506:
+   case 22508:
+   case 22510:
+   case 22512:
+   case 22514:
+   case 22516:
+   case 22518:
+   case 22520:
+   case 22522:
+   case 22524:
+   case 22526:
+   case 22528:
+   case 22530:
+   case 22532:
+   case 22534:
+   case 22536:
+   case 22538:
+   case 22540:
+   case 22542:
+   case 22544:
+   case 22546:
+   case 22548:
+   case 22550:
+   case 22552:
+   case 22554:
+   case 22556:
+   case 22558:
+   case 22560:
+   case 22562:
+   case 22564:
+   case 22566:
+   case 22568:
+   case 22570:
+   case 22572:
+   case 22574:
+   case 22576:
+   case 22578:
+   case 22580:
+   case 22582:
+   case 22584:
+   case 22586:
+   case 22588:
+   case 22590:
+   case 22592:
+   case 22594:
+   case 22596:
+   case 22598:
+   case 22600:
+   case 22602:
+   case 22604:
+   case 22606:
+   case 22608:
+   case 22610:
+   case 22612:
+   case 22614:
+   case 22616:
+   case 22618:
+   case 22620:
+   case 22622:
+   case 22624:
+   case 22626:
+   case 22628:
+   case 22630:
+   case 22632:
+   case 22634:
+   case 22636:
+   case 22638:
+   case 22640:
+   case 22642:
+   case 22644:
+   case 22646:
+   case 22648:
+   case 22650:
+   case 22652:
+   case 22654:
+   case 22656:
+   case 22658:
+   case 22660:
+   case 22662:
+   case 22664:
+   case 22666:
+   case 22668:
+   case 22670:
+   case 22672:
+   case 22674:
+   case 22676:
+   case 22678:
+   case 22680:
+   case 22682:
+   case 22684:
+   case 22686:
+   case 22688:
+   case 22690:
+   case 22692:
+   case 22694:
+   case 22696:
+   case 22698:
+   case 22700:
+   case 22702:
+   case 22704:
+   case 22706:
+   case 22708:
+   case 22710:
+   case 22712:
+   case 22714:
+   case 22716:
+   case 22718:
+   case 22720:
+   case 22722:
+   case 22724:
+   case 22726:
+   case 22728:
+   case 22730:
+   case 22732:
+   case 22734:
+   case 22736:
+   case 22738:
+   case 22740:
+   case 22742:
+   case 22744:
+   case 22746:
+   case 22748:
+   case 22750:
+   case 22752:
+   case 22754:
+   case 22756:
+   case 22758:
+   case 22760:
+   case 22762:
+   case 22764:
+   case 22766:
+   case 22768:
+   case 22770:
+   case 22772:
+   case 22774:
+   case 22776:
+   case 22778:
+   case 22780:
+   case 22782:
+   case 22784:
+   case 22786:
+   case 22788:
+   case 22790:
+   case 22792:
+   case 22794:
+   case 22796:
+   case 22798:
+   case 22800:
+   case 22802:
+   case 22804:
+   case 22806:
+   case 22808:
+   case 22810:
+   case 22812:
+   case 22814:
+   case 22816:
+   case 22818:
+   case 22820:
+   case 22822:
+   case 22824:
+   case 22826:
+   case 22828:
+   case 22830:
+   case 22832:
+   case 22834:
+   case 22836:
+   case 22838:
+   case 22840:
+   case 22842:
+   case 22844:
+   case 22846:
+   case 22848:
+   case 22850:
+   case 22852:
+   case 22854:
+   case 22856:
+   case 22858:
+   case 22860:
+   case 22862:
+   case 22864:
+   case 22866:
+   case 22868:
+   case 22870:
+   case 22872:
+   case 22874:
+   case 22876:
+   case 22878:
+   case 22880:
+   case 22882:
+   case 22884:
+   case 22886:
+   case 22888:
+   case 22890:
+   case 22892:
+   case 22894:
+   case 22896:
+   case 22898:
+   case 22900:
+   case 22902:
+   case 22904:
+   case 22906:
+   case 22908:
+   case 22910:
+   case 22912:
+   case 22914:
+   case 22916:
+   case 22918:
+   case 22920:
+   case 22922:
+   case 22924:
+   case 22926:
+   case 22928:
+   case 22930:
+   case 22932:
+   case 22934:
+   case 22936:
+   case 22938:
+   case 22940:
+   case 22942:
+   case 22944:
+   case 22946:
+   case 22948:
+   case 22950:
+   case 22952:
+   case 22954:
+   case 22956:
+   case 22958:
+   case 22960:
+   case 22962:
+   case 22964:
+   case 22966:
+   case 22968:
+   case 22970:
+   case 22972:
+   case 22974:
+   case 22976:
+   case 22978:
+   case 22980:
+   case 22982:
+   case 22984:
+   case 22986:
+   case 22988:
+   case 22990:
+   case 22992:
+   case 22994:
+   case 22996:
+   case 22998:
+   case 23e3:
+   case 23002:
+   case 23004:
+   case 23006:
+   case 23008:
+   case 23010:
+   case 23012:
+   case 23014:
+   case 23016:
+   case 23018:
+   case 23020:
+   case 23022:
+   case 23024:
+   case 23026:
+   case 23028:
+   case 23030:
+   case 23032:
+   case 23034:
+   case 23036:
+   case 23038:
+   case 23040:
+   case 23042:
+   case 23044:
+   case 23046:
+   case 23048:
+   case 23050:
+   case 23052:
+   case 23054:
+   case 23056:
+   case 23058:
+   case 23060:
+   case 23062:
+   case 23064:
+   case 23066:
+   case 23068:
+   case 23070:
+   case 23072:
+   case 23074:
+   case 23076:
+   case 23078:
+   case 23080:
+   case 23082:
+   case 23084:
+   case 23086:
+   case 23088:
+   case 23090:
+   case 23092:
+   case 23094:
+   case 23096:
+   case 23098:
+   case 23100:
+   case 23102:
+   case 23104:
+   case 23106:
+   case 23108:
+   case 23110:
+   case 23112:
+   case 23114:
+   case 23116:
+   case 23118:
+   case 23120:
+   case 23122:
+   case 23124:
+   case 23126:
+   case 23128:
+   case 23130:
+   case 23132:
+   case 23134:
+   case 23136:
+   case 23138:
+   case 23140:
+   case 23142:
+   case 23144:
+   case 23146:
+   case 23148:
+   case 23150:
+   case 23152:
+   case 23154:
+   case 23156:
+   case 23158:
+   case 23160:
+   case 23162:
+   case 23164:
+   case 23166:
+   case 23168:
+   case 23170:
+   case 23172:
+   case 23174:
+   case 23176:
+   case 23178:
+   case 23180:
+   case 23182:
+   case 23184:
+   case 23186:
+   case 23188:
+   case 23190:
+   case 23192:
+   case 23194:
+   case 23196:
+   case 23198:
+   case 23200:
+   case 23202:
+   case 23204:
+   case 23206:
+   case 23208:
+   case 23210:
+   case 23212:
+   case 23214:
+   case 23216:
+   case 23218:
+   case 23220:
+   case 23222:
+   case 23224:
+   case 23226:
+   case 23228:
+   case 23230:
+   case 23232:
+   case 23234:
+   case 23236:
+   case 23238:
+   case 23240:
+   case 23242:
+   case 23244:
+   case 23246:
+   case 23248:
+   case 23250:
+   case 23252:
+   case 23254:
+   case 23256:
+   case 23258:
+   case 23260:
+   case 23262:
+   case 23264:
+   case 23266:
+   case 23268:
+   case 23270:
+   case 23272:
+   case 23274:
+   case 23276:
+   case 23278:
+   case 23280:
+   case 23282:
+   case 23284:
+   case 23286:
+   case 23288:
+   case 23290:
+   case 23292:
+   case 23294:
+   case 23296:
+   case 23298:
+   case 23300:
+   case 23302:
+   case 23304:
+   case 23306:
+   case 23308:
+   case 23310:
+   case 23312:
+   case 23314:
+   case 23316:
+   case 23318:
+   case 23320:
+   case 23322:
+   case 23324:
+   case 23326:
+   case 23328:
+   case 23330:
+   case 23332:
+   case 23334:
+   case 23336:
+   case 23338:
+   case 23340:
+   case 23342:
+   case 23344:
+   case 23346:
+   case 23348:
+   case 23350:
+   case 23352:
+   case 23354:
+   case 23356:
+   case 23358:
+   case 23360:
+   case 23362:
+   case 23364:
+   case 23366:
+   case 23368:
+   case 23370:
+   case 23372:
+   case 23374:
+   case 23376:
+   case 23378:
+   case 23380:
+   case 23382:
+   case 23384:
+   case 23386:
+   case 23388:
+   case 23390:
+   case 23392:
+   case 23394:
+   case 23396:
+   case 23398:
+   case 23400:
+   case 23402:
+   case 23404:
+   case 23406:
+   case 23408:
+   case 23410:
+   case 23412:
+   case 23414:
+   case 23416:
+   case 23418:
+   case 23420:
+   case 23422:
+   case 23424:
+   case 23426:
+   case 23428:
+   case 23430:
+   case 23432:
+   case 23434:
+   case 23436:
+   case 23438:
+   case 23440:
+   case 23442:
+   case 23444:
+   case 23446:
+   case 23448:
+   case 23450:
+   case 23452:
+   case 23454:
+   case 23456:
+   case 23458:
+   case 23460:
+   case 23462:
+   case 23464:
+   case 23466:
+   case 23468:
+   case 23470:
+   case 23472:
+   case 23474:
+   case 23476:
+   case 23478:
+   case 23480:
+   case 23482:
+   case 23484:
+   case 23486:
+   case 23488:
+   case 23490:
+   case 23492:
+   case 23494:
+   case 23496:
+   case 23498:
+   case 23500:
+   case 23502:
+   case 23504:
+   case 23506:
+   case 23508:
+   case 23510:
+   case 23512:
+   case 23514:
+   case 23516:
+   case 23518:
+   case 23520:
+   case 23522:
+   case 23524:
+   case 23526:
+   case 23528:
+   case 23530:
+   case 23532:
+   case 23534:
+   case 23536:
+   case 23538:
+   case 23540:
+   case 23542:
+   case 23544:
+   case 23546:
+   case 23548:
+   case 23550:
+   case 23552:
+   case 23554:
+   case 23556:
+   case 23558:
+   case 23560:
+   case 23562:
+   case 23564:
+   case 23566:
+   case 23568:
+   case 23570:
+   case 23572:
+   case 23574:
+   case 23576:
+   case 23578:
+   case 23580:
+   case 23582:
+   case 23584:
+   case 23586:
+   case 23588:
+   case 23590:
+   case 23592:
+   case 23594:
+   case 23596:
+   case 23598:
+   case 23600:
+   case 23602:
+   case 23604:
+   case 23606:
+   case 23608:
+   case 23610:
+   case 23612:
+   case 23614:
+   case 23616:
+   case 23618:
+   case 23620:
+   case 23622:
+   case 23624:
+   case 23626:
+   case 23628:
+   case 23630:
+   case 23632:
+   case 23634:
+   case 23636:
+   case 23638:
+   case 23640:
+   case 23642:
+   case 23644:
+   case 23646:
+   case 23648:
+   case 23650:
+   case 23652:
+   case 23654:
+   case 23656:
+   case 23658:
+   case 23660:
+   case 23662:
+   case 23664:
+   case 23666:
+   case 23668:
+   case 23670:
+   case 23672:
+   case 23674:
+   case 23676:
+   case 23678:
+   case 23680:
+   case 23682:
+   case 23684:
+   case 23686:
+   case 23688:
+   case 23690:
+   case 23692:
+   case 23694:
+   case 23696:
+   case 23698:
+   case 23700:
+   case 23702:
+   case 23704:
+   case 23706:
+   case 23708:
+   case 23710:
+   case 23712:
+   case 23714:
+   case 23716:
+   case 23718:
+   case 23720:
+   case 23722:
+   case 23724:
+   case 23726:
+   case 23728:
+   case 23730:
+   case 23732:
+   case 23734:
+   case 23736:
+   case 23738:
+   case 23740:
+   case 23742:
+   case 23744:
+   case 23746:
+   case 23748:
+   case 23750:
+   case 23752:
+   case 23754:
+   case 23756:
+   case 23758:
+   case 23760:
+   case 23762:
+   case 23764:
+   case 23766:
+   case 23768:
+   case 23770:
+   case 23772:
+   case 23774:
+   case 23776:
+   case 23778:
+   case 23780:
+   case 23782:
+   case 23784:
+   case 23786:
+   case 23788:
+   case 23790:
+   case 23792:
+   case 23794:
+   case 23796:
+   case 23798:
+   case 23800:
+   case 23802:
+   case 23804:
+   case 23806:
+   case 23808:
+   case 23810:
+   case 23812:
+   case 23814:
+   case 23816:
+   case 23818:
+   case 23820:
+   case 23822:
+   case 23824:
+   case 23826:
+   case 23828:
+   case 23830:
+   case 23832:
+   case 23834:
+   case 23836:
+   case 23838:
+   case 23840:
+   case 23842:
+   case 23844:
+   case 23846:
+   case 23848:
+   case 23850:
+   case 23852:
+   case 23854:
+   case 23856:
+   case 23858:
+   case 23860:
+   case 23862:
+   case 23864:
+   case 23866:
+   case 23868:
+   case 23870:
+   case 23872:
+   case 23874:
+   case 23876:
+   case 23878:
+   case 23880:
+   case 23882:
+   case 23884:
+   case 23886:
+   case 23888:
+   case 23890:
+   case 23892:
+   case 23894:
+   case 23896:
+   case 23898:
+   case 23900:
+   case 23902:
+   case 23904:
+   case 23906:
+   case 23908:
+   case 23910:
+   case 23912:
+   case 23914:
+   case 23916:
+   case 23918:
+   case 23920:
+   case 23922:
+   case 23924:
+   case 23926:
+   case 23928:
+   case 23930:
+   case 23932:
+   case 23934:
+   case 23936:
+   case 23938:
+   case 23940:
+   case 23942:
+   case 23944:
+   case 23946:
+   case 23948:
+   case 23950:
+   case 23952:
+   case 23954:
+   case 23956:
+   case 23958:
+   case 23960:
+   case 23962:
+   case 23964:
+   case 23966:
+   case 23968:
+   case 23970:
+   case 23972:
+   case 23974:
+   case 23976:
+   case 23978:
+   case 23980:
+   case 23982:
+   case 23984:
+   case 23986:
+   case 23988:
+   case 23990:
+   case 23992:
+   case 23994:
+   case 23996:
+   case 23998:
+   case 24e3:
+   case 24002:
+   case 24004:
+   case 24006:
+   case 24008:
+   case 24010:
+   case 24012:
+   case 24014:
+   case 24016:
+   case 24018:
+   case 24020:
+   case 24022:
+   case 24024:
+   case 24026:
+   case 24028:
+   case 24030:
+   case 24032:
+   case 24034:
+   case 24036:
+   case 24038:
+   case 24040:
+   case 24042:
+   case 24044:
+   case 24046:
+   case 24048:
+   case 24050:
+   case 24052:
+   case 24054:
+   case 24056:
+   case 24058:
+   case 24060:
+   case 24062:
+   case 24064:
+   case 24066:
+   case 24068:
+   case 24070:
+   case 24072:
+   case 24074:
+   case 24076:
+   case 24078:
+   case 24080:
+   case 24082:
+   case 24084:
+   case 24086:
+   case 24088:
+   case 24090:
+   case 24092:
+   case 24094:
+   case 24096:
+   case 24098:
+   case 24100:
+   case 24102:
+   case 24104:
+   case 24106:
+   case 24108:
+   case 24110:
+   case 24112:
+   case 24114:
+   case 24116:
+   case 24118:
+   case 24120:
+   case 24122:
+   case 24124:
+   case 24126:
+   case 24128:
+   case 24130:
+   case 24132:
+   case 24134:
+   case 24136:
+   case 24138:
+   case 24140:
+   case 24142:
+   case 24144:
+   case 24146:
+   case 24148:
+   case 24150:
+   case 24152:
+   case 24154:
+   case 24156:
+   case 24158:
+   case 24160:
+   case 24162:
+   case 24164:
+   case 24166:
+   case 24168:
+   case 24170:
+   case 24172:
+   case 24174:
+   case 24176:
+   case 24178:
+   case 24180:
+   case 24182:
+   case 24184:
+   case 24186:
+   case 24188:
+   case 24190:
+   case 24192:
+   case 24194:
+   case 24196:
+   case 24198:
+   case 24200:
+   case 24202:
+   case 24204:
+   case 24206:
+   case 24208:
+   case 24210:
+   case 24212:
+   case 24214:
+   case 24216:
+   case 24218:
+   case 24220:
+   case 24222:
+   case 24224:
+   case 24226:
+   case 24228:
+   case 24230:
+   case 24232:
+   case 24234:
+   case 24236:
+   case 24238:
+   case 24240:
+   case 24242:
+   case 24244:
+   case 24246:
+   case 24248:
+   case 24250:
+   case 24252:
+   case 24254:
+   case 24256:
+   case 24258:
+   case 24260:
+   case 24262:
+   case 24264:
+   case 24266:
+   case 24268:
+   case 24270:
+   case 24272:
+   case 24274:
+   case 24276:
+   case 24278:
+   case 24280:
+   case 24282:
+   case 24284:
+   case 24286:
+   case 24288:
+   case 24290:
+   case 24292:
+   case 24294:
+   case 24296:
+   case 24298:
+   case 24300:
+   case 24302:
+   case 24304:
+   case 24306:
+   case 24308:
+   case 24310:
+   case 24312:
+   case 24314:
+   case 24316:
+   case 24318:
+   case 24320:
+   case 24322:
+   case 24324:
+   case 24326:
+   case 24328:
+   case 24330:
+   case 24332:
+   case 24334:
+   case 24336:
+   case 24338:
+   case 24340:
+   case 24342:
+   case 24344:
+   case 24346:
+   case 24348:
+   case 24350:
+   case 24352:
+   case 24354:
+   case 24356:
+   case 24358:
+   case 24360:
+   case 24362:
+   case 24364:
+   case 24366:
+   case 24368:
+   case 24370:
+   case 24372:
+   case 24374:
+   case 24376:
+   case 24378:
+   case 24380:
+   case 24382:
+   case 24384:
+   case 24386:
+   case 24388:
+   case 24390:
+   case 24392:
+   case 24394:
+   case 24396:
+   case 24398:
+   case 24400:
+   case 24402:
+   case 24404:
+   case 24406:
+   case 24408:
+   case 24410:
+   case 24412:
+   case 24414:
+   case 24416:
+   case 24418:
+   case 24420:
+   case 24422:
+   case 24424:
+   case 24426:
+   case 24428:
+   case 24430:
+   case 24432:
+   case 24434:
+   case 24436:
+   case 24438:
+   case 24440:
+   case 24442:
+   case 24444:
+   case 24446:
+   case 24448:
+   case 24450:
+   case 24452:
+   case 24454:
+   case 24456:
+   case 24458:
+   case 24460:
+   case 24462:
+   case 24464:
+   case 24466:
+   case 24468:
+   case 24470:
+   case 24472:
+   case 24474:
+   case 24476:
+   case 24478:
+   case 24480:
+   case 24482:
+   case 24484:
+   case 24486:
+   case 24488:
+   case 24490:
+   case 24492:
+   case 24494:
+   case 24496:
+   case 24498:
+   case 24500:
+   case 24502:
+   case 24504:
+   case 24506:
+   case 24508:
+   case 24510:
+   case 24512:
+   case 24514:
+   case 24516:
+   case 24518:
+   case 24520:
+   case 24522:
+   case 24524:
+   case 24526:
+   case 24528:
+   case 24530:
+   case 24532:
+   case 24534:
+   case 24536:
+   case 24538:
+   case 24540:
+   case 24542:
+   case 24544:
+   case 24546:
+   case 24548:
+   case 24550:
+   case 24552:
+   case 24554:
+   case 24556:
+   case 24558:
+   case 24560:
+   case 24562:
+   case 24564:
+   case 24566:
+   case 24568:
+   case 24570:
+   case 24572:
+   case 24574:
+   case 24576:
+   case 24578:
+   case 24580:
+   case 24582:
+   case 24584:
+   case 24586:
+   case 24588:
+   case 24590:
+   case 24592:
+   case 24594:
+   case 24596:
+   case 24598:
+   case 24600:
+   case 24602:
+   case 24604:
+   case 24606:
+   case 24608:
+   case 24610:
+   case 24612:
+   case 24614:
+    return 0 | 0;
+   default:
+    break block;
+   };
+  }
+  return 1 | 0;
+ }
+ 
+ function $16() {
+  
+ }
+ 
+ function $17() {
+  block : {
+   dummy();
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+ }
+ 
+ function $18() {
+  block : {
+   dummy();
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+ }
+ 
+ function $19() {
+  var $1_1 = 0;
+  block : {
+   dummy();
+   $1_1 = 2;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ 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;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ 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;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $22() {
+  var $1_1 = 0;
+  fake_return_waka123 : {
+   dummy();
+   $1_1 = 5;
+   switch (1 | 0) {
+   default:
+    break fake_return_waka123;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $23() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 9;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $24() {
+  
+ }
+ 
+ function $25() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 8;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $26() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 9;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $27() {
+  
+ }
+ 
+ function $28() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 10;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $29() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 11;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $30() {
+  var i64toi32_i32$0 = 0, $1_1 = 0, $1$hi = 0;
+  block : {
+   i64toi32_i32$0 = 0;
+   $1_1 = 7;
+   $1$hi = i64toi32_i32$0;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return $1_1 | 0;
+ }
+ 
+ function $31() {
+  var $1_1 = 0, $6_1 = 0;
+  if_ : {
+   $1_1 = 2;
+   switch (0 | 0) {
+   default:
+    break if_;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $32($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var $4_1 = 0, $8_1 = 0;
+  block : {
+   if ($0) {
+    $4_1 = 3;
+    switch (0 | 0) {
+    default:
+     break block;
+    };
+   } else {
+    $8_1 = $1_1
+   }
+   $4_1 = $8_1;
+  }
+  return $4_1 | 0;
+ }
+ 
+ function $33($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var $6_1 = 0, $7_1 = 0, $8_1 = 0, $9_1 = 0;
+  block : {
+   if_ : {
+    if ($0) {
+     $9_1 = $1_1
+    } else {
+     $6_1 = 4;
+     $7_1 = $6_1;
+     $8_1 = $6_1;
+     switch (0 | 0) {
+     case 0:
+      break block;
+     default:
+      break if_;
+     };
+    }
+    $8_1 = $9_1;
+   }
+   $7_1 = $8_1;
+  }
+  return $7_1 | 0;
+ }
+ 
+ function $34($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var $3_1 = 0, $4_1 = 0, $5_1 = 0;
+  block : {
+   $3_1 = 5;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $35($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var $2_1 = 0, $4_1 = 0, $5_1 = 0;
+  block : {
+   $2_1 = $0;
+   $4_1 = 6;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $4_1 | 0;
+ }
+ 
+ function $36() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 7;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function f($0, $1_1, $2_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  return -1 | 0;
+ }
+ 
+ function $38() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 12;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $39() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 13;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $40() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 14;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $41() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 20;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $42() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 21;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $43() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 22;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $44() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 23;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $45() {
+  var $2_1 = 0;
+  block : {
+   $2_1 = 17;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $2_1 | 0;
+ }
+ 
+ function $46() {
+  var $2_1 = 0;
+  block : {
+   $2_1 = 1;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $2_1 | 0;
+ }
+ 
+ function $47() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 1;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $48() {
+  var $1_1 = Math_fround(0);
+  block : {
+   $1_1 = Math_fround(1.7000000476837158);
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return Math_fround($1_1);
+ }
+ 
+ function $49() {
+  var i64toi32_i32$0 = 0, $1_1 = 0, $1$hi = 0;
+  block : {
+   i64toi32_i32$0 = 0;
+   $1_1 = 30;
+   $1$hi = i64toi32_i32$0;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return $1_1 | 0;
+ }
+ 
+ function $50() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 30;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $51() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 31;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $52() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 32;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $53() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 33;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $54() {
+  var $1_1 = Math_fround(0);
+  block : {
+   $1_1 = Math_fround(3.4000000953674316);
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return Math_fround($1_1);
+ }
+ 
+ function $55() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 3;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $56() {
+  var i64toi32_i32$0 = 0, $1_1 = 0, $1$hi = 0, i64toi32_i32$1 = 0;
+  block : {
+   i64toi32_i32$0 = 0;
+   $1_1 = 45;
+   $1$hi = i64toi32_i32$0;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return $1_1 | 0;
+ }
+ 
+ function $57() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 44;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $58() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 43;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $59() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 42;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $60() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 41;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $61() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 40;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $62($0) {
+  $0 = $0 | 0;
+  var $2_1 = 0, $3_1 = 0, $4_1 = 0, $5_1 = 0;
+  block : {
+   block11 : {
+    block12 : {
+     $2_1 = 16;
+     $3_1 = $2_1;
+     $4_1 = $2_1;
+     $5_1 = $2_1;
+     switch ($0 | 0) {
+     case 1:
+      break block11;
+     case 0:
+      break block12;
+     default:
+      break block;
+     };
+    }
+    $4_1 = 2 + $5_1 | 0;
+   }
+   $3_1 = 1 + $4_1 | 0;
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $63($0) {
+  $0 = $0 | 0;
+  var $2_1 = 0, $3_1 = 0, $4_1 = 0, $5_1 = 0;
+  block : {
+   block13 : {
+    block14 : {
+     $2_1 = 8;
+     $3_1 = $2_1;
+     $4_1 = $2_1;
+     $5_1 = $2_1;
+     switch ($0 | 0) {
+     case 0:
+      break block;
+     case 1:
+      break block13;
+     default:
+      break block14;
+     };
+    }
+    $4_1 = 16;
+   }
+   $3_1 = 1 + $4_1 | 0;
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $64($0) {
+  $0 = $0 | 0;
+  var $2_1 = 0, $3_1 = 0, $4_1 = 0, $5_1 = 0;
+  block : {
+   block15 : {
+    block16 : {
+     $2_1 = 8;
+     $3_1 = $2_1;
+     $4_1 = $2_1;
+     $5_1 = $2_1;
+     switch ($0 | 0) {
+     case 1:
+      break block15;
+     case 0:
+      break block16;
+     default:
+      break block;
+     };
+    }
+    $4_1 = 16;
+   }
+   $3_1 = 1 + $4_1 | 0;
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $65($0) {
+  $0 = $0 | 0;
+  var $4_1 = 0, $2_1 = 0, $3_1 = 0;
+  block : {
+   block17 : {
+    $2_1 = 8;
+    $3_1 = $2_1;
+    $4_1 = $2_1;
+    switch ($0 | 0) {
+    case 1:
+     break block;
+    default:
+     break block17;
+    };
+   }
+   $3_1 = 1 + $4_1 | 0;
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $66($0) {
+  $0 = $0 | 0;
+  var $2_1 = 0, $3_1 = 0, $4_1 = 0, $5_1 = 0;
+  block : {
+   block18 : {
+    block19 : {
+     $2_1 = 8;
+     $3_1 = $2_1;
+     $4_1 = $2_1;
+     $5_1 = $2_1;
+     switch ($0 | 0) {
+     case 1:
+      break block18;
+     case 0:
+      break block19;
+     default:
+      break block;
+     };
+    }
+    $4_1 = 16;
+   }
+   $3_1 = 1 + $4_1 | 0;
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $67($0) {
+  $0 = $0 | 0;
+  var $4_1 = 0, $2_1 = 0, $3_1 = 0;
+  block : {
+   block20 : {
+    $2_1 = 8;
+    $3_1 = $2_1;
+    $4_1 = $2_1;
+    switch ($0 | 0) {
+    case 1:
+     break block;
+    default:
+     break block20;
+    };
+   }
+   $3_1 = 1 + $4_1 | 0;
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $68($0) {
+  $0 = $0 | 0;
+  var $4_1 = 0, $9_1 = 0;
+  loop_in : while (1) {
+   block : {
+    switch ($0 | 0) {
+    case 0:
+     continue loop_in;
+    default:
+     break block;
+    };
+   }
+   $4_1 = 0;
+   break loop_in;
+  };
+  $0 = $4_1;
+  loop_in21 : while (1) {
+   block22 : {
+    switch ($0 | 0) {
+    case 0:
+     break block22;
+    default:
+     continue loop_in21;
+    };
+   }
+   $9_1 = 3;
+   break loop_in21;
+  };
+  return $9_1 | 0;
+ }
+ 
+ function legalstub$6() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $6() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0 | 0;
+ }
+ 
+ function legalstub$30() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $30() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0 | 0;
+ }
+ 
+ function legalstub$49() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $49() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0 | 0;
+ }
+ 
+ function legalstub$56() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $56() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0 | 0;
+ }
+ 
+ return {
+  "type_i32": $1, 
+  "type_i64": $2, 
+  "type_f32": $3, 
+  "type_f64": $4, 
+  "type_i32_value": $5, 
+  "type_i64_value": legalstub$6, 
+  "type_f32_value": $7, 
+  "type_f64_value": $8, 
+  "empty": $9, 
+  "empty_value": $10, 
+  "singleton": $11, 
+  "singleton_value": $12, 
+  "multiple": $13, 
+  "multiple_value": $14, 
+  "large": $15, 
+  "as_block_first": $16, 
+  "as_block_mid": $17, 
+  "as_block_last": $18, 
+  "as_block_value": $19, 
+  "as_loop_first": $20, 
+  "as_loop_mid": $21, 
+  "as_loop_last": $22, 
+  "as_br_value": $23, 
+  "as_br_if_cond": $24, 
+  "as_br_if_value": $25, 
+  "as_br_if_value_cond": $26, 
+  "as_br_table_index": $27, 
+  "as_br_table_value": $28, 
+  "as_br_table_value_index": $29, 
+  "as_return_value": legalstub$30, 
+  "as_if_cond": $31, 
+  "as_if_then": $32, 
+  "as_if_else": $33, 
+  "as_select_first": $34, 
+  "as_select_second": $35, 
+  "as_select_cond": $36, 
+  "as_call_first": $38, 
+  "as_call_mid": $39, 
+  "as_call_last": $40, 
+  "as_call_indirect_first": $41, 
+  "as_call_indirect_mid": $42, 
+  "as_call_indirect_last": $43, 
+  "as_call_indirect_func": $44, 
+  "as_local_set_value": $45, 
+  "as_local_tee_value": $46, 
+  "as_global_set_value": $47, 
+  "as_load_address": $48, 
+  "as_loadN_address": legalstub$49, 
+  "as_store_address": $50, 
+  "as_store_value": $51, 
+  "as_storeN_address": $52, 
+  "as_storeN_value": $53, 
+  "as_unary_operand": $54, 
+  "as_binary_left": $55, 
+  "as_binary_right": legalstub$56, 
+  "as_test_operand": $57, 
+  "as_compare_left": $58, 
+  "as_compare_right": $59, 
+  "as_convert_operand": $60, 
+  "as_memory_grow_size": $61, 
+  "nested_block_value": $62, 
+  "nested_br_value": $63, 
+  "nested_br_if_value": $64, 
+  "nested_br_if_value_cond": $65, 
+  "nested_br_table_value": $66, 
+  "nested_br_table_value_index": $67, 
+  "nested_br_table_loop_block": $68
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var type_i32 = retasmFunc.type_i32;
+export var type_i64 = retasmFunc.type_i64;
+export var type_f32 = retasmFunc.type_f32;
+export var type_f64 = retasmFunc.type_f64;
+export var type_i32_value = retasmFunc.type_i32_value;
+export var type_i64_value = retasmFunc.type_i64_value;
+export var type_f32_value = retasmFunc.type_f32_value;
+export var type_f64_value = retasmFunc.type_f64_value;
+export var empty = retasmFunc.empty;
+export var empty_value = retasmFunc.empty_value;
+export var singleton = retasmFunc.singleton;
+export var singleton_value = retasmFunc.singleton_value;
+export var multiple = retasmFunc.multiple;
+export var multiple_value = retasmFunc.multiple_value;
+export var large = retasmFunc.large;
+export var as_block_first = retasmFunc.as_block_first;
+export var as_block_mid = retasmFunc.as_block_mid;
+export var as_block_last = retasmFunc.as_block_last;
+export var as_block_value = retasmFunc.as_block_value;
+export var as_loop_first = retasmFunc.as_loop_first;
+export var as_loop_mid = retasmFunc.as_loop_mid;
+export var as_loop_last = retasmFunc.as_loop_last;
+export var as_br_value = retasmFunc.as_br_value;
+export var as_br_if_cond = retasmFunc.as_br_if_cond;
+export var as_br_if_value = retasmFunc.as_br_if_value;
+export var as_br_if_value_cond = retasmFunc.as_br_if_value_cond;
+export var as_br_table_index = retasmFunc.as_br_table_index;
+export var as_br_table_value = retasmFunc.as_br_table_value;
+export var as_br_table_value_index = retasmFunc.as_br_table_value_index;
+export var as_return_value = retasmFunc.as_return_value;
+export var as_if_cond = retasmFunc.as_if_cond;
+export var as_if_then = retasmFunc.as_if_then;
+export var as_if_else = retasmFunc.as_if_else;
+export var as_select_first = retasmFunc.as_select_first;
+export var as_select_second = retasmFunc.as_select_second;
+export var as_select_cond = retasmFunc.as_select_cond;
+export var as_call_first = retasmFunc.as_call_first;
+export var as_call_mid = retasmFunc.as_call_mid;
+export var as_call_last = retasmFunc.as_call_last;
+export var as_call_indirect_first = retasmFunc.as_call_indirect_first;
+export var as_call_indirect_mid = retasmFunc.as_call_indirect_mid;
+export var as_call_indirect_last = retasmFunc.as_call_indirect_last;
+export var as_call_indirect_func = retasmFunc.as_call_indirect_func;
+export var as_local_set_value = retasmFunc.as_local_set_value;
+export var as_local_tee_value = retasmFunc.as_local_tee_value;
+export var as_global_set_value = retasmFunc.as_global_set_value;
+export var as_load_address = retasmFunc.as_load_address;
+export var as_loadN_address = retasmFunc.as_loadN_address;
+export var as_store_address = retasmFunc.as_store_address;
+export var as_store_value = retasmFunc.as_store_value;
+export var as_storeN_address = retasmFunc.as_storeN_address;
+export var as_storeN_value = retasmFunc.as_storeN_value;
+export var as_unary_operand = retasmFunc.as_unary_operand;
+export var as_binary_left = retasmFunc.as_binary_left;
+export var as_binary_right = retasmFunc.as_binary_right;
+export var as_test_operand = retasmFunc.as_test_operand;
+export var as_compare_left = retasmFunc.as_compare_left;
+export var as_compare_right = retasmFunc.as_compare_right;
+export var as_convert_operand = retasmFunc.as_convert_operand;
+export var as_memory_grow_size = retasmFunc.as_memory_grow_size;
+export var nested_block_value = retasmFunc.nested_block_value;
+export var nested_br_value = retasmFunc.nested_br_value;
+export var nested_br_if_value = retasmFunc.nested_br_if_value;
+export var nested_br_if_value_cond = retasmFunc.nested_br_if_value_cond;
+export var nested_br_table_value = retasmFunc.nested_br_table_value;
+export var nested_br_table_value_index = retasmFunc.nested_br_table_value_index;
+export var nested_br_table_loop_block = retasmFunc.nested_br_table_loop_block;
diff --git a/binaryen/test/wasm2js/br_table_hoisting.2asm.js b/binaryen/test/wasm2js/br_table_hoisting.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/br_table_hoisting.2asm.js
@@ -0,0 +1,197 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function zed($0) {
+  $0 = $0 | 0;
+  zed($0 | 0);
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  a : {
+   b : {
+    switch (x | 0) {
+    default:
+     zed(-1 | 0);
+     zed(-2 | 0);
+    case 3:
+     zed(-3 | 0);
+     zed(-4 | 0);
+    case 2:
+     zed(-5 | 0);
+     zed(-6 | 0);
+     break a;
+    case 0:
+     break a;
+    case 1:
+     break b;
+    };
+   }
+   zed(-7 | 0);
+   zed(-8 | 0);
+   break a;
+  }
+  zed(-9 | 0);
+  zed(-10 | 0);
+ }
+ 
+ function $2(x) {
+  x = x | 0;
+  a : {
+   b : {
+    c : {
+     d : {
+      switch (x | 0) {
+      default:
+       zed(-1 | 0);
+       zed(-2 | 0);
+       break c;
+      case 0:
+       break a;
+      case 1:
+       break b;
+      case 2:
+       break c;
+      case 3:
+       break d;
+      };
+     }
+     zed(-3 | 0);
+     zed(-4 | 0);
+     break c;
+    }
+    zed(-5 | 0);
+    zed(-6 | 0);
+    break a;
+   }
+   zed(-7 | 0);
+   zed(-8 | 0);
+   break a;
+  }
+  zed(-9 | 0);
+  zed(-10 | 0);
+ }
+ 
+ function $3(x) {
+  x = x | 0;
+  a : {
+   b : {
+    c : {
+     d : {
+      switch (x | 0) {
+      default:
+       if (x) {
+        break c
+       }
+       zed(-1 | 0);
+       zed(-2 | 0);
+       break;
+      case 0:
+       break a;
+      case 1:
+       break b;
+      case 2:
+       break c;
+      case 3:
+       break d;
+      };
+     }
+     zed(-3 | 0);
+     zed(-4 | 0);
+     break c;
+    }
+    zed(-5 | 0);
+    zed(-6 | 0);
+    break a;
+   }
+   zed(-7 | 0);
+   zed(-8 | 0);
+   break a;
+  }
+  zed(-9 | 0);
+  zed(-10 | 0);
+ }
+ 
+ function $4(x) {
+  x = x | 0;
+  a : {
+   b : {
+    c : {
+     d : {
+      if (x) {
+       break c
+      }
+      e : {
+       switch (x | 0) {
+       case 0:
+        break a;
+       case 1:
+        break b;
+       case 2:
+        break c;
+       case 3:
+        break d;
+       default:
+        break e;
+       };
+      }
+      if (x) {
+       break c
+      }
+      zed(-1 | 0);
+      zed(-2 | 0);
+     }
+     zed(-3 | 0);
+     zed(-4 | 0);
+     break c;
+    }
+    zed(-5 | 0);
+    zed(-6 | 0);
+    break a;
+   }
+   zed(-7 | 0);
+   zed(-8 | 0);
+   break a;
+  }
+  zed(-9 | 0);
+  zed(-10 | 0);
+ }
+ 
+ return {
+  "foo1": $1, 
+  "foo2": $2, 
+  "foo3": $3, 
+  "foo4": $4
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var foo1 = retasmFunc.foo1;
+export var foo2 = retasmFunc.foo2;
+export var foo3 = retasmFunc.foo3;
+export var foo4 = retasmFunc.foo4;
diff --git a/binaryen/test/wasm2js/br_table_hoisting.2asm.js.opt b/binaryen/test/wasm2js/br_table_hoisting.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/br_table_hoisting.2asm.js.opt
@@ -0,0 +1,187 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function zed($0) {
+  zed($0);
+ }
+ 
+ function $1($0) {
+  $0 = $0 | 0;
+  a : {
+   b : {
+    switch ($0 | 0) {
+    default:
+     zed(-1);
+     zed(-2);
+    case 3:
+     zed(-3);
+     zed(-4);
+    case 2:
+     zed(-5);
+     zed(-6);
+     break a;
+    case 0:
+     break a;
+    case 1:
+     break b;
+    };
+   }
+   zed(-7);
+   zed(-8);
+  }
+  zed(-9);
+  zed(-10);
+ }
+ 
+ function $2($0) {
+  $0 = $0 | 0;
+  a : {
+   b : {
+    c : {
+     d : {
+      switch ($0 | 0) {
+      default:
+       zed(-1);
+       zed(-2);
+       break c;
+      case 0:
+       break a;
+      case 1:
+       break b;
+      case 2:
+       break c;
+      case 3:
+       break d;
+      };
+     }
+     zed(-3);
+     zed(-4);
+    }
+    zed(-5);
+    zed(-6);
+    break a;
+   }
+   zed(-7);
+   zed(-8);
+  }
+  zed(-9);
+  zed(-10);
+ }
+ 
+ function $3($0) {
+  $0 = $0 | 0;
+  a : {
+   b : {
+    c : {
+     d : {
+      switch ($0 | 0) {
+      default:
+       if ($0) {
+        break c
+       }
+       zed(-1);
+       zed(-2);
+       break;
+      case 0:
+       break a;
+      case 1:
+       break b;
+      case 2:
+       break c;
+      case 3:
+       break d;
+      };
+     }
+     zed(-3);
+     zed(-4);
+    }
+    zed(-5);
+    zed(-6);
+    break a;
+   }
+   zed(-7);
+   zed(-8);
+  }
+  zed(-9);
+  zed(-10);
+ }
+ 
+ function $4($0) {
+  $0 = $0 | 0;
+  a : {
+   b : {
+    c : {
+     if ($0) {
+      break c
+     }
+     d : {
+      switch ($0 | 0) {
+      default:
+       if ($0) {
+        break c
+       }
+       zed(-1);
+       zed(-2);
+       break;
+      case 0:
+       break a;
+      case 1:
+       break b;
+      case 2:
+       break c;
+      case 3:
+       break d;
+      };
+     }
+     zed(-3);
+     zed(-4);
+    }
+    zed(-5);
+    zed(-6);
+    break a;
+   }
+   zed(-7);
+   zed(-8);
+  }
+  zed(-9);
+  zed(-10);
+ }
+ 
+ return {
+  "foo1": $1, 
+  "foo2": $2, 
+  "foo3": $3, 
+  "foo4": $4
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var foo1 = retasmFunc.foo1;
+export var foo2 = retasmFunc.foo2;
+export var foo3 = retasmFunc.foo3;
+export var foo4 = retasmFunc.foo4;
diff --git a/binaryen/test/wasm2js/br_table_hoisting.wast b/binaryen/test/wasm2js/br_table_hoisting.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/br_table_hoisting.wast
@@ -0,0 +1,115 @@
+(module
+ (func $zed (param i32)
+  (call $zed (local.get 0))
+ )
+ (func "foo1" (param $x i32)
+  (block $a
+   (block $b
+    (block $c
+     (block $d
+      (block $e
+       (br_table $a $b $c $d $e (local.get $x))
+      )
+      (call $zed (i32.const -1))
+      (call $zed (i32.const -2))
+      ;; implicit fallthrough - can be done in the switch too
+     )
+     (call $zed (i32.const -3))
+     (call $zed (i32.const -4))
+     (br $c) ;; branch which is identical to a fallthrough
+    )
+    (call $zed (i32.const -5))
+    (call $zed (i32.const -6))
+    (br $a) ;; skip some blocks - can't do this in a switch!
+   )
+   (call $zed (i32.const -7))
+   (call $zed (i32.const -8))
+   (br $a)
+  )
+  (call $zed (i32.const -9))
+  (call $zed (i32.const -10))
+ )
+ (func "foo2" (param $x i32)
+  (block $a
+   (block $b
+    (block $c
+     (block $d
+      (block $e
+       (br_table $a $b $c $d $e (local.get $x))
+      )
+      (call $zed (i32.const -1))
+      (call $zed (i32.const -2))
+      (br $c) ;; skip some blocks - can't do this in a switch!
+     )
+     (call $zed (i32.const -3))
+     (call $zed (i32.const -4))
+     (br $c) ;; branch which is identical to a fallthrough
+    )
+    (call $zed (i32.const -5))
+    (call $zed (i32.const -6))
+    (br $a) ;; skip some blocks - can't do this in a switch!
+   )
+   (call $zed (i32.const -7))
+   (call $zed (i32.const -8))
+   (br $a)
+  )
+  (call $zed (i32.const -9))
+  (call $zed (i32.const -10))
+ )
+ (func "foo3" (param $x i32)
+  (block $a
+   (block $b
+    (block $c
+     (block $d
+      (block $e
+       (br_table $a $b $c $d $e (local.get $x))
+      )
+      (br_if $c (local.get $x))
+      (call $zed (i32.const -1))
+      (call $zed (i32.const -2))
+     )
+     (call $zed (i32.const -3))
+     (call $zed (i32.const -4))
+     (br $c) ;; branch which is identical to a fallthrough
+    )
+    (call $zed (i32.const -5))
+    (call $zed (i32.const -6))
+    (br $a) ;; skip some blocks - can't do this in a switch!
+   )
+   (call $zed (i32.const -7))
+   (call $zed (i32.const -8))
+   (br $a)
+  )
+  (call $zed (i32.const -9))
+  (call $zed (i32.const -10))
+ )
+ (func "foo4" (param $x i32)
+  (block $a
+   (block $b
+    (block $c
+     (block $d
+      (br_if $c (local.get $x))
+      (block $e
+       (br_table $a $b $c $d $e (local.get $x))
+      )
+      (br_if $c (local.get $x))
+      (call $zed (i32.const -1))
+      (call $zed (i32.const -2))
+     )
+     (call $zed (i32.const -3))
+     (call $zed (i32.const -4))
+     (br $c) ;; branch which is identical to a fallthrough
+    )
+    (call $zed (i32.const -5))
+    (call $zed (i32.const -6))
+    (br $a) ;; skip some blocks - can't do this in a switch!
+   )
+   (call $zed (i32.const -7))
+   (call $zed (i32.const -8))
+   (br $a)
+  )
+  (call $zed (i32.const -9))
+  (call $zed (i32.const -10))
+ )
+)
+
diff --git a/binaryen/test/wasm2js/br_table_temp.2asm.js b/binaryen/test/wasm2js/br_table_temp.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/br_table_temp.2asm.js
@@ -0,0 +1,13338 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function dummy() {
+  
+ }
+ 
+ function $1() {
+  
+ }
+ 
+ function $2() {
+  
+ }
+ 
+ function $3() {
+  
+ }
+ 
+ function $4() {
+  
+ }
+ 
+ function $5() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 1;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $6() {
+  var i64toi32_i32$0 = 0, $1_1 = 0, $1$hi = 0;
+  block : {
+   i64toi32_i32$0 = 0;
+   $1_1 = 2;
+   $1$hi = i64toi32_i32$0;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  i64toi32_i32$0 = $1$hi;
+  return $1_1 | 0;
+ }
+ 
+ function $7() {
+  var $1_1 = Math_fround(0);
+  block : {
+   $1_1 = Math_fround(3.0);
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return Math_fround($1_1);
+ }
+ 
+ function $8() {
+  var $1_1 = 0.0;
+  block : {
+   $1_1 = 4.0;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return +$1_1;
+ }
+ 
+ function $9($0) {
+  $0 = $0 | 0;
+  return 22 | 0;
+ }
+ 
+ function $10($0) {
+  $0 = $0 | 0;
+  var $3_1 = 0;
+  block : {
+   $3_1 = 33;
+   switch ($0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $11($0) {
+  $0 = $0 | 0;
+  block : {
+   switch ($0 | 0) {
+   default:
+    return 20 | 0;
+   case 0:
+    break block;
+   };
+  }
+  return 22 | 0;
+ }
+ 
+ function $12($0) {
+  $0 = $0 | 0;
+  var $2_1 = 0, $3_1 = 0, $4_1 = 0;
+  block : {
+   block1 : {
+    $2_1 = 33;
+    $3_1 = $2_1;
+    $4_1 = $2_1;
+    switch ($0 | 0) {
+    case 0:
+     break block1;
+    default:
+     break block;
+    };
+   }
+   $3_1 = 32;
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $13($0) {
+  $0 = $0 | 0;
+  block : {
+   switch ($0 | 0) {
+   case 3:
+    return 100 | 0;
+   case 2:
+    return 101 | 0;
+   case 1:
+    return 102 | 0;
+   case 0:
+    return 103 | 0;
+   default:
+    break block;
+   };
+  }
+  return 104 | 0;
+ }
+ 
+ function $14($0) {
+  $0 = $0 | 0;
+  var $1_1 = 0, $3_1 = 0, $4_1 = 0, $5_1 = 0, $6_1 = 0, $7_1 = 0, $8_1 = 0;
+  block : {
+   block6 : {
+    block7 : {
+     block8 : {
+      block9 : {
+       $3_1 = 200;
+       $4_1 = $3_1;
+       $5_1 = $3_1;
+       $6_1 = $3_1;
+       $7_1 = $3_1;
+       $8_1 = $3_1;
+       switch ($0 | 0) {
+       case 0:
+        break block6;
+       case 1:
+        break block7;
+       case 2:
+        break block8;
+       case 3:
+        break block9;
+       default:
+        break block;
+       };
+      }
+      $1_1 = $8_1;
+      return $1_1 + 10 | 0 | 0;
+     }
+     $1_1 = $7_1;
+     return $1_1 + 11 | 0 | 0;
+    }
+    $1_1 = $6_1;
+    return $1_1 + 12 | 0 | 0;
+   }
+   $1_1 = $5_1;
+   return $1_1 + 13 | 0 | 0;
+  }
+  $1_1 = $4_1;
+  return $1_1 + 14 | 0 | 0;
+ }
+ 
+ function $15($0) {
+  $0 = $0 | 0;
+  block : {
+   switch ($0 | 0) {
+   case 0:
+   case 2:
+   case 4:
+   case 6:
+   case 8:
+   case 10:
+   case 12:
+   case 14:
+   case 16:
+   case 18:
+   case 20:
+   case 22:
+   case 24:
+   case 26:
+   case 28:
+   case 30:
+   case 32:
+   case 34:
+   case 36:
+   case 38:
+   case 40:
+   case 42:
+   case 44:
+   case 46:
+   case 48:
+   case 50:
+   case 52:
+   case 54:
+   case 56:
+   case 58:
+   case 60:
+   case 62:
+   case 64:
+   case 66:
+   case 68:
+   case 70:
+   case 72:
+   case 74:
+   case 76:
+   case 78:
+   case 80:
+   case 82:
+   case 84:
+   case 86:
+   case 88:
+   case 90:
+   case 92:
+   case 94:
+   case 96:
+   case 98:
+   case 100:
+   case 102:
+   case 104:
+   case 106:
+   case 108:
+   case 110:
+   case 112:
+   case 114:
+   case 116:
+   case 118:
+   case 120:
+   case 122:
+   case 124:
+   case 126:
+   case 128:
+   case 130:
+   case 132:
+   case 134:
+   case 136:
+   case 138:
+   case 140:
+   case 142:
+   case 144:
+   case 146:
+   case 148:
+   case 150:
+   case 152:
+   case 154:
+   case 156:
+   case 158:
+   case 160:
+   case 162:
+   case 164:
+   case 166:
+   case 168:
+   case 170:
+   case 172:
+   case 174:
+   case 176:
+   case 178:
+   case 180:
+   case 182:
+   case 184:
+   case 186:
+   case 188:
+   case 190:
+   case 192:
+   case 194:
+   case 196:
+   case 198:
+   case 200:
+   case 202:
+   case 204:
+   case 206:
+   case 208:
+   case 210:
+   case 212:
+   case 214:
+   case 216:
+   case 218:
+   case 220:
+   case 222:
+   case 224:
+   case 226:
+   case 228:
+   case 230:
+   case 232:
+   case 234:
+   case 236:
+   case 238:
+   case 240:
+   case 242:
+   case 244:
+   case 246:
+   case 248:
+   case 250:
+   case 252:
+   case 254:
+   case 256:
+   case 258:
+   case 260:
+   case 262:
+   case 264:
+   case 266:
+   case 268:
+   case 270:
+   case 272:
+   case 274:
+   case 276:
+   case 278:
+   case 280:
+   case 282:
+   case 284:
+   case 286:
+   case 288:
+   case 290:
+   case 292:
+   case 294:
+   case 296:
+   case 298:
+   case 300:
+   case 302:
+   case 304:
+   case 306:
+   case 308:
+   case 310:
+   case 312:
+   case 314:
+   case 316:
+   case 318:
+   case 320:
+   case 322:
+   case 324:
+   case 326:
+   case 328:
+   case 330:
+   case 332:
+   case 334:
+   case 336:
+   case 338:
+   case 340:
+   case 342:
+   case 344:
+   case 346:
+   case 348:
+   case 350:
+   case 352:
+   case 354:
+   case 356:
+   case 358:
+   case 360:
+   case 362:
+   case 364:
+   case 366:
+   case 368:
+   case 370:
+   case 372:
+   case 374:
+   case 376:
+   case 378:
+   case 380:
+   case 382:
+   case 384:
+   case 386:
+   case 388:
+   case 390:
+   case 392:
+   case 394:
+   case 396:
+   case 398:
+   case 400:
+   case 402:
+   case 404:
+   case 406:
+   case 408:
+   case 410:
+   case 412:
+   case 414:
+   case 416:
+   case 418:
+   case 420:
+   case 422:
+   case 424:
+   case 426:
+   case 428:
+   case 430:
+   case 432:
+   case 434:
+   case 436:
+   case 438:
+   case 440:
+   case 442:
+   case 444:
+   case 446:
+   case 448:
+   case 450:
+   case 452:
+   case 454:
+   case 456:
+   case 458:
+   case 460:
+   case 462:
+   case 464:
+   case 466:
+   case 468:
+   case 470:
+   case 472:
+   case 474:
+   case 476:
+   case 478:
+   case 480:
+   case 482:
+   case 484:
+   case 486:
+   case 488:
+   case 490:
+   case 492:
+   case 494:
+   case 496:
+   case 498:
+   case 500:
+   case 502:
+   case 504:
+   case 506:
+   case 508:
+   case 510:
+   case 512:
+   case 514:
+   case 516:
+   case 518:
+   case 520:
+   case 522:
+   case 524:
+   case 526:
+   case 528:
+   case 530:
+   case 532:
+   case 534:
+   case 536:
+   case 538:
+   case 540:
+   case 542:
+   case 544:
+   case 546:
+   case 548:
+   case 550:
+   case 552:
+   case 554:
+   case 556:
+   case 558:
+   case 560:
+   case 562:
+   case 564:
+   case 566:
+   case 568:
+   case 570:
+   case 572:
+   case 574:
+   case 576:
+   case 578:
+   case 580:
+   case 582:
+   case 584:
+   case 586:
+   case 588:
+   case 590:
+   case 592:
+   case 594:
+   case 596:
+   case 598:
+   case 600:
+   case 602:
+   case 604:
+   case 606:
+   case 608:
+   case 610:
+   case 612:
+   case 614:
+   case 616:
+   case 618:
+   case 620:
+   case 622:
+   case 624:
+   case 626:
+   case 628:
+   case 630:
+   case 632:
+   case 634:
+   case 636:
+   case 638:
+   case 640:
+   case 642:
+   case 644:
+   case 646:
+   case 648:
+   case 650:
+   case 652:
+   case 654:
+   case 656:
+   case 658:
+   case 660:
+   case 662:
+   case 664:
+   case 666:
+   case 668:
+   case 670:
+   case 672:
+   case 674:
+   case 676:
+   case 678:
+   case 680:
+   case 682:
+   case 684:
+   case 686:
+   case 688:
+   case 690:
+   case 692:
+   case 694:
+   case 696:
+   case 698:
+   case 700:
+   case 702:
+   case 704:
+   case 706:
+   case 708:
+   case 710:
+   case 712:
+   case 714:
+   case 716:
+   case 718:
+   case 720:
+   case 722:
+   case 724:
+   case 726:
+   case 728:
+   case 730:
+   case 732:
+   case 734:
+   case 736:
+   case 738:
+   case 740:
+   case 742:
+   case 744:
+   case 746:
+   case 748:
+   case 750:
+   case 752:
+   case 754:
+   case 756:
+   case 758:
+   case 760:
+   case 762:
+   case 764:
+   case 766:
+   case 768:
+   case 770:
+   case 772:
+   case 774:
+   case 776:
+   case 778:
+   case 780:
+   case 782:
+   case 784:
+   case 786:
+   case 788:
+   case 790:
+   case 792:
+   case 794:
+   case 796:
+   case 798:
+   case 800:
+   case 802:
+   case 804:
+   case 806:
+   case 808:
+   case 810:
+   case 812:
+   case 814:
+   case 816:
+   case 818:
+   case 820:
+   case 822:
+   case 824:
+   case 826:
+   case 828:
+   case 830:
+   case 832:
+   case 834:
+   case 836:
+   case 838:
+   case 840:
+   case 842:
+   case 844:
+   case 846:
+   case 848:
+   case 850:
+   case 852:
+   case 854:
+   case 856:
+   case 858:
+   case 860:
+   case 862:
+   case 864:
+   case 866:
+   case 868:
+   case 870:
+   case 872:
+   case 874:
+   case 876:
+   case 878:
+   case 880:
+   case 882:
+   case 884:
+   case 886:
+   case 888:
+   case 890:
+   case 892:
+   case 894:
+   case 896:
+   case 898:
+   case 900:
+   case 902:
+   case 904:
+   case 906:
+   case 908:
+   case 910:
+   case 912:
+   case 914:
+   case 916:
+   case 918:
+   case 920:
+   case 922:
+   case 924:
+   case 926:
+   case 928:
+   case 930:
+   case 932:
+   case 934:
+   case 936:
+   case 938:
+   case 940:
+   case 942:
+   case 944:
+   case 946:
+   case 948:
+   case 950:
+   case 952:
+   case 954:
+   case 956:
+   case 958:
+   case 960:
+   case 962:
+   case 964:
+   case 966:
+   case 968:
+   case 970:
+   case 972:
+   case 974:
+   case 976:
+   case 978:
+   case 980:
+   case 982:
+   case 984:
+   case 986:
+   case 988:
+   case 990:
+   case 992:
+   case 994:
+   case 996:
+   case 998:
+   case 1e3:
+   case 1002:
+   case 1004:
+   case 1006:
+   case 1008:
+   case 1010:
+   case 1012:
+   case 1014:
+   case 1016:
+   case 1018:
+   case 1020:
+   case 1022:
+   case 1024:
+   case 1026:
+   case 1028:
+   case 1030:
+   case 1032:
+   case 1034:
+   case 1036:
+   case 1038:
+   case 1040:
+   case 1042:
+   case 1044:
+   case 1046:
+   case 1048:
+   case 1050:
+   case 1052:
+   case 1054:
+   case 1056:
+   case 1058:
+   case 1060:
+   case 1062:
+   case 1064:
+   case 1066:
+   case 1068:
+   case 1070:
+   case 1072:
+   case 1074:
+   case 1076:
+   case 1078:
+   case 1080:
+   case 1082:
+   case 1084:
+   case 1086:
+   case 1088:
+   case 1090:
+   case 1092:
+   case 1094:
+   case 1096:
+   case 1098:
+   case 1100:
+   case 1102:
+   case 1104:
+   case 1106:
+   case 1108:
+   case 1110:
+   case 1112:
+   case 1114:
+   case 1116:
+   case 1118:
+   case 1120:
+   case 1122:
+   case 1124:
+   case 1126:
+   case 1128:
+   case 1130:
+   case 1132:
+   case 1134:
+   case 1136:
+   case 1138:
+   case 1140:
+   case 1142:
+   case 1144:
+   case 1146:
+   case 1148:
+   case 1150:
+   case 1152:
+   case 1154:
+   case 1156:
+   case 1158:
+   case 1160:
+   case 1162:
+   case 1164:
+   case 1166:
+   case 1168:
+   case 1170:
+   case 1172:
+   case 1174:
+   case 1176:
+   case 1178:
+   case 1180:
+   case 1182:
+   case 1184:
+   case 1186:
+   case 1188:
+   case 1190:
+   case 1192:
+   case 1194:
+   case 1196:
+   case 1198:
+   case 1200:
+   case 1202:
+   case 1204:
+   case 1206:
+   case 1208:
+   case 1210:
+   case 1212:
+   case 1214:
+   case 1216:
+   case 1218:
+   case 1220:
+   case 1222:
+   case 1224:
+   case 1226:
+   case 1228:
+   case 1230:
+   case 1232:
+   case 1234:
+   case 1236:
+   case 1238:
+   case 1240:
+   case 1242:
+   case 1244:
+   case 1246:
+   case 1248:
+   case 1250:
+   case 1252:
+   case 1254:
+   case 1256:
+   case 1258:
+   case 1260:
+   case 1262:
+   case 1264:
+   case 1266:
+   case 1268:
+   case 1270:
+   case 1272:
+   case 1274:
+   case 1276:
+   case 1278:
+   case 1280:
+   case 1282:
+   case 1284:
+   case 1286:
+   case 1288:
+   case 1290:
+   case 1292:
+   case 1294:
+   case 1296:
+   case 1298:
+   case 1300:
+   case 1302:
+   case 1304:
+   case 1306:
+   case 1308:
+   case 1310:
+   case 1312:
+   case 1314:
+   case 1316:
+   case 1318:
+   case 1320:
+   case 1322:
+   case 1324:
+   case 1326:
+   case 1328:
+   case 1330:
+   case 1332:
+   case 1334:
+   case 1336:
+   case 1338:
+   case 1340:
+   case 1342:
+   case 1344:
+   case 1346:
+   case 1348:
+   case 1350:
+   case 1352:
+   case 1354:
+   case 1356:
+   case 1358:
+   case 1360:
+   case 1362:
+   case 1364:
+   case 1366:
+   case 1368:
+   case 1370:
+   case 1372:
+   case 1374:
+   case 1376:
+   case 1378:
+   case 1380:
+   case 1382:
+   case 1384:
+   case 1386:
+   case 1388:
+   case 1390:
+   case 1392:
+   case 1394:
+   case 1396:
+   case 1398:
+   case 1400:
+   case 1402:
+   case 1404:
+   case 1406:
+   case 1408:
+   case 1410:
+   case 1412:
+   case 1414:
+   case 1416:
+   case 1418:
+   case 1420:
+   case 1422:
+   case 1424:
+   case 1426:
+   case 1428:
+   case 1430:
+   case 1432:
+   case 1434:
+   case 1436:
+   case 1438:
+   case 1440:
+   case 1442:
+   case 1444:
+   case 1446:
+   case 1448:
+   case 1450:
+   case 1452:
+   case 1454:
+   case 1456:
+   case 1458:
+   case 1460:
+   case 1462:
+   case 1464:
+   case 1466:
+   case 1468:
+   case 1470:
+   case 1472:
+   case 1474:
+   case 1476:
+   case 1478:
+   case 1480:
+   case 1482:
+   case 1484:
+   case 1486:
+   case 1488:
+   case 1490:
+   case 1492:
+   case 1494:
+   case 1496:
+   case 1498:
+   case 1500:
+   case 1502:
+   case 1504:
+   case 1506:
+   case 1508:
+   case 1510:
+   case 1512:
+   case 1514:
+   case 1516:
+   case 1518:
+   case 1520:
+   case 1522:
+   case 1524:
+   case 1526:
+   case 1528:
+   case 1530:
+   case 1532:
+   case 1534:
+   case 1536:
+   case 1538:
+   case 1540:
+   case 1542:
+   case 1544:
+   case 1546:
+   case 1548:
+   case 1550:
+   case 1552:
+   case 1554:
+   case 1556:
+   case 1558:
+   case 1560:
+   case 1562:
+   case 1564:
+   case 1566:
+   case 1568:
+   case 1570:
+   case 1572:
+   case 1574:
+   case 1576:
+   case 1578:
+   case 1580:
+   case 1582:
+   case 1584:
+   case 1586:
+   case 1588:
+   case 1590:
+   case 1592:
+   case 1594:
+   case 1596:
+   case 1598:
+   case 1600:
+   case 1602:
+   case 1604:
+   case 1606:
+   case 1608:
+   case 1610:
+   case 1612:
+   case 1614:
+   case 1616:
+   case 1618:
+   case 1620:
+   case 1622:
+   case 1624:
+   case 1626:
+   case 1628:
+   case 1630:
+   case 1632:
+   case 1634:
+   case 1636:
+   case 1638:
+   case 1640:
+   case 1642:
+   case 1644:
+   case 1646:
+   case 1648:
+   case 1650:
+   case 1652:
+   case 1654:
+   case 1656:
+   case 1658:
+   case 1660:
+   case 1662:
+   case 1664:
+   case 1666:
+   case 1668:
+   case 1670:
+   case 1672:
+   case 1674:
+   case 1676:
+   case 1678:
+   case 1680:
+   case 1682:
+   case 1684:
+   case 1686:
+   case 1688:
+   case 1690:
+   case 1692:
+   case 1694:
+   case 1696:
+   case 1698:
+   case 1700:
+   case 1702:
+   case 1704:
+   case 1706:
+   case 1708:
+   case 1710:
+   case 1712:
+   case 1714:
+   case 1716:
+   case 1718:
+   case 1720:
+   case 1722:
+   case 1724:
+   case 1726:
+   case 1728:
+   case 1730:
+   case 1732:
+   case 1734:
+   case 1736:
+   case 1738:
+   case 1740:
+   case 1742:
+   case 1744:
+   case 1746:
+   case 1748:
+   case 1750:
+   case 1752:
+   case 1754:
+   case 1756:
+   case 1758:
+   case 1760:
+   case 1762:
+   case 1764:
+   case 1766:
+   case 1768:
+   case 1770:
+   case 1772:
+   case 1774:
+   case 1776:
+   case 1778:
+   case 1780:
+   case 1782:
+   case 1784:
+   case 1786:
+   case 1788:
+   case 1790:
+   case 1792:
+   case 1794:
+   case 1796:
+   case 1798:
+   case 1800:
+   case 1802:
+   case 1804:
+   case 1806:
+   case 1808:
+   case 1810:
+   case 1812:
+   case 1814:
+   case 1816:
+   case 1818:
+   case 1820:
+   case 1822:
+   case 1824:
+   case 1826:
+   case 1828:
+   case 1830:
+   case 1832:
+   case 1834:
+   case 1836:
+   case 1838:
+   case 1840:
+   case 1842:
+   case 1844:
+   case 1846:
+   case 1848:
+   case 1850:
+   case 1852:
+   case 1854:
+   case 1856:
+   case 1858:
+   case 1860:
+   case 1862:
+   case 1864:
+   case 1866:
+   case 1868:
+   case 1870:
+   case 1872:
+   case 1874:
+   case 1876:
+   case 1878:
+   case 1880:
+   case 1882:
+   case 1884:
+   case 1886:
+   case 1888:
+   case 1890:
+   case 1892:
+   case 1894:
+   case 1896:
+   case 1898:
+   case 1900:
+   case 1902:
+   case 1904:
+   case 1906:
+   case 1908:
+   case 1910:
+   case 1912:
+   case 1914:
+   case 1916:
+   case 1918:
+   case 1920:
+   case 1922:
+   case 1924:
+   case 1926:
+   case 1928:
+   case 1930:
+   case 1932:
+   case 1934:
+   case 1936:
+   case 1938:
+   case 1940:
+   case 1942:
+   case 1944:
+   case 1946:
+   case 1948:
+   case 1950:
+   case 1952:
+   case 1954:
+   case 1956:
+   case 1958:
+   case 1960:
+   case 1962:
+   case 1964:
+   case 1966:
+   case 1968:
+   case 1970:
+   case 1972:
+   case 1974:
+   case 1976:
+   case 1978:
+   case 1980:
+   case 1982:
+   case 1984:
+   case 1986:
+   case 1988:
+   case 1990:
+   case 1992:
+   case 1994:
+   case 1996:
+   case 1998:
+   case 2e3:
+   case 2002:
+   case 2004:
+   case 2006:
+   case 2008:
+   case 2010:
+   case 2012:
+   case 2014:
+   case 2016:
+   case 2018:
+   case 2020:
+   case 2022:
+   case 2024:
+   case 2026:
+   case 2028:
+   case 2030:
+   case 2032:
+   case 2034:
+   case 2036:
+   case 2038:
+   case 2040:
+   case 2042:
+   case 2044:
+   case 2046:
+   case 2048:
+   case 2050:
+   case 2052:
+   case 2054:
+   case 2056:
+   case 2058:
+   case 2060:
+   case 2062:
+   case 2064:
+   case 2066:
+   case 2068:
+   case 2070:
+   case 2072:
+   case 2074:
+   case 2076:
+   case 2078:
+   case 2080:
+   case 2082:
+   case 2084:
+   case 2086:
+   case 2088:
+   case 2090:
+   case 2092:
+   case 2094:
+   case 2096:
+   case 2098:
+   case 2100:
+   case 2102:
+   case 2104:
+   case 2106:
+   case 2108:
+   case 2110:
+   case 2112:
+   case 2114:
+   case 2116:
+   case 2118:
+   case 2120:
+   case 2122:
+   case 2124:
+   case 2126:
+   case 2128:
+   case 2130:
+   case 2132:
+   case 2134:
+   case 2136:
+   case 2138:
+   case 2140:
+   case 2142:
+   case 2144:
+   case 2146:
+   case 2148:
+   case 2150:
+   case 2152:
+   case 2154:
+   case 2156:
+   case 2158:
+   case 2160:
+   case 2162:
+   case 2164:
+   case 2166:
+   case 2168:
+   case 2170:
+   case 2172:
+   case 2174:
+   case 2176:
+   case 2178:
+   case 2180:
+   case 2182:
+   case 2184:
+   case 2186:
+   case 2188:
+   case 2190:
+   case 2192:
+   case 2194:
+   case 2196:
+   case 2198:
+   case 2200:
+   case 2202:
+   case 2204:
+   case 2206:
+   case 2208:
+   case 2210:
+   case 2212:
+   case 2214:
+   case 2216:
+   case 2218:
+   case 2220:
+   case 2222:
+   case 2224:
+   case 2226:
+   case 2228:
+   case 2230:
+   case 2232:
+   case 2234:
+   case 2236:
+   case 2238:
+   case 2240:
+   case 2242:
+   case 2244:
+   case 2246:
+   case 2248:
+   case 2250:
+   case 2252:
+   case 2254:
+   case 2256:
+   case 2258:
+   case 2260:
+   case 2262:
+   case 2264:
+   case 2266:
+   case 2268:
+   case 2270:
+   case 2272:
+   case 2274:
+   case 2276:
+   case 2278:
+   case 2280:
+   case 2282:
+   case 2284:
+   case 2286:
+   case 2288:
+   case 2290:
+   case 2292:
+   case 2294:
+   case 2296:
+   case 2298:
+   case 2300:
+   case 2302:
+   case 2304:
+   case 2306:
+   case 2308:
+   case 2310:
+   case 2312:
+   case 2314:
+   case 2316:
+   case 2318:
+   case 2320:
+   case 2322:
+   case 2324:
+   case 2326:
+   case 2328:
+   case 2330:
+   case 2332:
+   case 2334:
+   case 2336:
+   case 2338:
+   case 2340:
+   case 2342:
+   case 2344:
+   case 2346:
+   case 2348:
+   case 2350:
+   case 2352:
+   case 2354:
+   case 2356:
+   case 2358:
+   case 2360:
+   case 2362:
+   case 2364:
+   case 2366:
+   case 2368:
+   case 2370:
+   case 2372:
+   case 2374:
+   case 2376:
+   case 2378:
+   case 2380:
+   case 2382:
+   case 2384:
+   case 2386:
+   case 2388:
+   case 2390:
+   case 2392:
+   case 2394:
+   case 2396:
+   case 2398:
+   case 2400:
+   case 2402:
+   case 2404:
+   case 2406:
+   case 2408:
+   case 2410:
+   case 2412:
+   case 2414:
+   case 2416:
+   case 2418:
+   case 2420:
+   case 2422:
+   case 2424:
+   case 2426:
+   case 2428:
+   case 2430:
+   case 2432:
+   case 2434:
+   case 2436:
+   case 2438:
+   case 2440:
+   case 2442:
+   case 2444:
+   case 2446:
+   case 2448:
+   case 2450:
+   case 2452:
+   case 2454:
+   case 2456:
+   case 2458:
+   case 2460:
+   case 2462:
+   case 2464:
+   case 2466:
+   case 2468:
+   case 2470:
+   case 2472:
+   case 2474:
+   case 2476:
+   case 2478:
+   case 2480:
+   case 2482:
+   case 2484:
+   case 2486:
+   case 2488:
+   case 2490:
+   case 2492:
+   case 2494:
+   case 2496:
+   case 2498:
+   case 2500:
+   case 2502:
+   case 2504:
+   case 2506:
+   case 2508:
+   case 2510:
+   case 2512:
+   case 2514:
+   case 2516:
+   case 2518:
+   case 2520:
+   case 2522:
+   case 2524:
+   case 2526:
+   case 2528:
+   case 2530:
+   case 2532:
+   case 2534:
+   case 2536:
+   case 2538:
+   case 2540:
+   case 2542:
+   case 2544:
+   case 2546:
+   case 2548:
+   case 2550:
+   case 2552:
+   case 2554:
+   case 2556:
+   case 2558:
+   case 2560:
+   case 2562:
+   case 2564:
+   case 2566:
+   case 2568:
+   case 2570:
+   case 2572:
+   case 2574:
+   case 2576:
+   case 2578:
+   case 2580:
+   case 2582:
+   case 2584:
+   case 2586:
+   case 2588:
+   case 2590:
+   case 2592:
+   case 2594:
+   case 2596:
+   case 2598:
+   case 2600:
+   case 2602:
+   case 2604:
+   case 2606:
+   case 2608:
+   case 2610:
+   case 2612:
+   case 2614:
+   case 2616:
+   case 2618:
+   case 2620:
+   case 2622:
+   case 2624:
+   case 2626:
+   case 2628:
+   case 2630:
+   case 2632:
+   case 2634:
+   case 2636:
+   case 2638:
+   case 2640:
+   case 2642:
+   case 2644:
+   case 2646:
+   case 2648:
+   case 2650:
+   case 2652:
+   case 2654:
+   case 2656:
+   case 2658:
+   case 2660:
+   case 2662:
+   case 2664:
+   case 2666:
+   case 2668:
+   case 2670:
+   case 2672:
+   case 2674:
+   case 2676:
+   case 2678:
+   case 2680:
+   case 2682:
+   case 2684:
+   case 2686:
+   case 2688:
+   case 2690:
+   case 2692:
+   case 2694:
+   case 2696:
+   case 2698:
+   case 2700:
+   case 2702:
+   case 2704:
+   case 2706:
+   case 2708:
+   case 2710:
+   case 2712:
+   case 2714:
+   case 2716:
+   case 2718:
+   case 2720:
+   case 2722:
+   case 2724:
+   case 2726:
+   case 2728:
+   case 2730:
+   case 2732:
+   case 2734:
+   case 2736:
+   case 2738:
+   case 2740:
+   case 2742:
+   case 2744:
+   case 2746:
+   case 2748:
+   case 2750:
+   case 2752:
+   case 2754:
+   case 2756:
+   case 2758:
+   case 2760:
+   case 2762:
+   case 2764:
+   case 2766:
+   case 2768:
+   case 2770:
+   case 2772:
+   case 2774:
+   case 2776:
+   case 2778:
+   case 2780:
+   case 2782:
+   case 2784:
+   case 2786:
+   case 2788:
+   case 2790:
+   case 2792:
+   case 2794:
+   case 2796:
+   case 2798:
+   case 2800:
+   case 2802:
+   case 2804:
+   case 2806:
+   case 2808:
+   case 2810:
+   case 2812:
+   case 2814:
+   case 2816:
+   case 2818:
+   case 2820:
+   case 2822:
+   case 2824:
+   case 2826:
+   case 2828:
+   case 2830:
+   case 2832:
+   case 2834:
+   case 2836:
+   case 2838:
+   case 2840:
+   case 2842:
+   case 2844:
+   case 2846:
+   case 2848:
+   case 2850:
+   case 2852:
+   case 2854:
+   case 2856:
+   case 2858:
+   case 2860:
+   case 2862:
+   case 2864:
+   case 2866:
+   case 2868:
+   case 2870:
+   case 2872:
+   case 2874:
+   case 2876:
+   case 2878:
+   case 2880:
+   case 2882:
+   case 2884:
+   case 2886:
+   case 2888:
+   case 2890:
+   case 2892:
+   case 2894:
+   case 2896:
+   case 2898:
+   case 2900:
+   case 2902:
+   case 2904:
+   case 2906:
+   case 2908:
+   case 2910:
+   case 2912:
+   case 2914:
+   case 2916:
+   case 2918:
+   case 2920:
+   case 2922:
+   case 2924:
+   case 2926:
+   case 2928:
+   case 2930:
+   case 2932:
+   case 2934:
+   case 2936:
+   case 2938:
+   case 2940:
+   case 2942:
+   case 2944:
+   case 2946:
+   case 2948:
+   case 2950:
+   case 2952:
+   case 2954:
+   case 2956:
+   case 2958:
+   case 2960:
+   case 2962:
+   case 2964:
+   case 2966:
+   case 2968:
+   case 2970:
+   case 2972:
+   case 2974:
+   case 2976:
+   case 2978:
+   case 2980:
+   case 2982:
+   case 2984:
+   case 2986:
+   case 2988:
+   case 2990:
+   case 2992:
+   case 2994:
+   case 2996:
+   case 2998:
+   case 3e3:
+   case 3002:
+   case 3004:
+   case 3006:
+   case 3008:
+   case 3010:
+   case 3012:
+   case 3014:
+   case 3016:
+   case 3018:
+   case 3020:
+   case 3022:
+   case 3024:
+   case 3026:
+   case 3028:
+   case 3030:
+   case 3032:
+   case 3034:
+   case 3036:
+   case 3038:
+   case 3040:
+   case 3042:
+   case 3044:
+   case 3046:
+   case 3048:
+   case 3050:
+   case 3052:
+   case 3054:
+   case 3056:
+   case 3058:
+   case 3060:
+   case 3062:
+   case 3064:
+   case 3066:
+   case 3068:
+   case 3070:
+   case 3072:
+   case 3074:
+   case 3076:
+   case 3078:
+   case 3080:
+   case 3082:
+   case 3084:
+   case 3086:
+   case 3088:
+   case 3090:
+   case 3092:
+   case 3094:
+   case 3096:
+   case 3098:
+   case 3100:
+   case 3102:
+   case 3104:
+   case 3106:
+   case 3108:
+   case 3110:
+   case 3112:
+   case 3114:
+   case 3116:
+   case 3118:
+   case 3120:
+   case 3122:
+   case 3124:
+   case 3126:
+   case 3128:
+   case 3130:
+   case 3132:
+   case 3134:
+   case 3136:
+   case 3138:
+   case 3140:
+   case 3142:
+   case 3144:
+   case 3146:
+   case 3148:
+   case 3150:
+   case 3152:
+   case 3154:
+   case 3156:
+   case 3158:
+   case 3160:
+   case 3162:
+   case 3164:
+   case 3166:
+   case 3168:
+   case 3170:
+   case 3172:
+   case 3174:
+   case 3176:
+   case 3178:
+   case 3180:
+   case 3182:
+   case 3184:
+   case 3186:
+   case 3188:
+   case 3190:
+   case 3192:
+   case 3194:
+   case 3196:
+   case 3198:
+   case 3200:
+   case 3202:
+   case 3204:
+   case 3206:
+   case 3208:
+   case 3210:
+   case 3212:
+   case 3214:
+   case 3216:
+   case 3218:
+   case 3220:
+   case 3222:
+   case 3224:
+   case 3226:
+   case 3228:
+   case 3230:
+   case 3232:
+   case 3234:
+   case 3236:
+   case 3238:
+   case 3240:
+   case 3242:
+   case 3244:
+   case 3246:
+   case 3248:
+   case 3250:
+   case 3252:
+   case 3254:
+   case 3256:
+   case 3258:
+   case 3260:
+   case 3262:
+   case 3264:
+   case 3266:
+   case 3268:
+   case 3270:
+   case 3272:
+   case 3274:
+   case 3276:
+   case 3278:
+   case 3280:
+   case 3282:
+   case 3284:
+   case 3286:
+   case 3288:
+   case 3290:
+   case 3292:
+   case 3294:
+   case 3296:
+   case 3298:
+   case 3300:
+   case 3302:
+   case 3304:
+   case 3306:
+   case 3308:
+   case 3310:
+   case 3312:
+   case 3314:
+   case 3316:
+   case 3318:
+   case 3320:
+   case 3322:
+   case 3324:
+   case 3326:
+   case 3328:
+   case 3330:
+   case 3332:
+   case 3334:
+   case 3336:
+   case 3338:
+   case 3340:
+   case 3342:
+   case 3344:
+   case 3346:
+   case 3348:
+   case 3350:
+   case 3352:
+   case 3354:
+   case 3356:
+   case 3358:
+   case 3360:
+   case 3362:
+   case 3364:
+   case 3366:
+   case 3368:
+   case 3370:
+   case 3372:
+   case 3374:
+   case 3376:
+   case 3378:
+   case 3380:
+   case 3382:
+   case 3384:
+   case 3386:
+   case 3388:
+   case 3390:
+   case 3392:
+   case 3394:
+   case 3396:
+   case 3398:
+   case 3400:
+   case 3402:
+   case 3404:
+   case 3406:
+   case 3408:
+   case 3410:
+   case 3412:
+   case 3414:
+   case 3416:
+   case 3418:
+   case 3420:
+   case 3422:
+   case 3424:
+   case 3426:
+   case 3428:
+   case 3430:
+   case 3432:
+   case 3434:
+   case 3436:
+   case 3438:
+   case 3440:
+   case 3442:
+   case 3444:
+   case 3446:
+   case 3448:
+   case 3450:
+   case 3452:
+   case 3454:
+   case 3456:
+   case 3458:
+   case 3460:
+   case 3462:
+   case 3464:
+   case 3466:
+   case 3468:
+   case 3470:
+   case 3472:
+   case 3474:
+   case 3476:
+   case 3478:
+   case 3480:
+   case 3482:
+   case 3484:
+   case 3486:
+   case 3488:
+   case 3490:
+   case 3492:
+   case 3494:
+   case 3496:
+   case 3498:
+   case 3500:
+   case 3502:
+   case 3504:
+   case 3506:
+   case 3508:
+   case 3510:
+   case 3512:
+   case 3514:
+   case 3516:
+   case 3518:
+   case 3520:
+   case 3522:
+   case 3524:
+   case 3526:
+   case 3528:
+   case 3530:
+   case 3532:
+   case 3534:
+   case 3536:
+   case 3538:
+   case 3540:
+   case 3542:
+   case 3544:
+   case 3546:
+   case 3548:
+   case 3550:
+   case 3552:
+   case 3554:
+   case 3556:
+   case 3558:
+   case 3560:
+   case 3562:
+   case 3564:
+   case 3566:
+   case 3568:
+   case 3570:
+   case 3572:
+   case 3574:
+   case 3576:
+   case 3578:
+   case 3580:
+   case 3582:
+   case 3584:
+   case 3586:
+   case 3588:
+   case 3590:
+   case 3592:
+   case 3594:
+   case 3596:
+   case 3598:
+   case 3600:
+   case 3602:
+   case 3604:
+   case 3606:
+   case 3608:
+   case 3610:
+   case 3612:
+   case 3614:
+   case 3616:
+   case 3618:
+   case 3620:
+   case 3622:
+   case 3624:
+   case 3626:
+   case 3628:
+   case 3630:
+   case 3632:
+   case 3634:
+   case 3636:
+   case 3638:
+   case 3640:
+   case 3642:
+   case 3644:
+   case 3646:
+   case 3648:
+   case 3650:
+   case 3652:
+   case 3654:
+   case 3656:
+   case 3658:
+   case 3660:
+   case 3662:
+   case 3664:
+   case 3666:
+   case 3668:
+   case 3670:
+   case 3672:
+   case 3674:
+   case 3676:
+   case 3678:
+   case 3680:
+   case 3682:
+   case 3684:
+   case 3686:
+   case 3688:
+   case 3690:
+   case 3692:
+   case 3694:
+   case 3696:
+   case 3698:
+   case 3700:
+   case 3702:
+   case 3704:
+   case 3706:
+   case 3708:
+   case 3710:
+   case 3712:
+   case 3714:
+   case 3716:
+   case 3718:
+   case 3720:
+   case 3722:
+   case 3724:
+   case 3726:
+   case 3728:
+   case 3730:
+   case 3732:
+   case 3734:
+   case 3736:
+   case 3738:
+   case 3740:
+   case 3742:
+   case 3744:
+   case 3746:
+   case 3748:
+   case 3750:
+   case 3752:
+   case 3754:
+   case 3756:
+   case 3758:
+   case 3760:
+   case 3762:
+   case 3764:
+   case 3766:
+   case 3768:
+   case 3770:
+   case 3772:
+   case 3774:
+   case 3776:
+   case 3778:
+   case 3780:
+   case 3782:
+   case 3784:
+   case 3786:
+   case 3788:
+   case 3790:
+   case 3792:
+   case 3794:
+   case 3796:
+   case 3798:
+   case 3800:
+   case 3802:
+   case 3804:
+   case 3806:
+   case 3808:
+   case 3810:
+   case 3812:
+   case 3814:
+   case 3816:
+   case 3818:
+   case 3820:
+   case 3822:
+   case 3824:
+   case 3826:
+   case 3828:
+   case 3830:
+   case 3832:
+   case 3834:
+   case 3836:
+   case 3838:
+   case 3840:
+   case 3842:
+   case 3844:
+   case 3846:
+   case 3848:
+   case 3850:
+   case 3852:
+   case 3854:
+   case 3856:
+   case 3858:
+   case 3860:
+   case 3862:
+   case 3864:
+   case 3866:
+   case 3868:
+   case 3870:
+   case 3872:
+   case 3874:
+   case 3876:
+   case 3878:
+   case 3880:
+   case 3882:
+   case 3884:
+   case 3886:
+   case 3888:
+   case 3890:
+   case 3892:
+   case 3894:
+   case 3896:
+   case 3898:
+   case 3900:
+   case 3902:
+   case 3904:
+   case 3906:
+   case 3908:
+   case 3910:
+   case 3912:
+   case 3914:
+   case 3916:
+   case 3918:
+   case 3920:
+   case 3922:
+   case 3924:
+   case 3926:
+   case 3928:
+   case 3930:
+   case 3932:
+   case 3934:
+   case 3936:
+   case 3938:
+   case 3940:
+   case 3942:
+   case 3944:
+   case 3946:
+   case 3948:
+   case 3950:
+   case 3952:
+   case 3954:
+   case 3956:
+   case 3958:
+   case 3960:
+   case 3962:
+   case 3964:
+   case 3966:
+   case 3968:
+   case 3970:
+   case 3972:
+   case 3974:
+   case 3976:
+   case 3978:
+   case 3980:
+   case 3982:
+   case 3984:
+   case 3986:
+   case 3988:
+   case 3990:
+   case 3992:
+   case 3994:
+   case 3996:
+   case 3998:
+   case 4e3:
+   case 4002:
+   case 4004:
+   case 4006:
+   case 4008:
+   case 4010:
+   case 4012:
+   case 4014:
+   case 4016:
+   case 4018:
+   case 4020:
+   case 4022:
+   case 4024:
+   case 4026:
+   case 4028:
+   case 4030:
+   case 4032:
+   case 4034:
+   case 4036:
+   case 4038:
+   case 4040:
+   case 4042:
+   case 4044:
+   case 4046:
+   case 4048:
+   case 4050:
+   case 4052:
+   case 4054:
+   case 4056:
+   case 4058:
+   case 4060:
+   case 4062:
+   case 4064:
+   case 4066:
+   case 4068:
+   case 4070:
+   case 4072:
+   case 4074:
+   case 4076:
+   case 4078:
+   case 4080:
+   case 4082:
+   case 4084:
+   case 4086:
+   case 4088:
+   case 4090:
+   case 4092:
+   case 4094:
+   case 4096:
+   case 4098:
+   case 4100:
+   case 4102:
+   case 4104:
+   case 4106:
+   case 4108:
+   case 4110:
+   case 4112:
+   case 4114:
+   case 4116:
+   case 4118:
+   case 4120:
+   case 4122:
+   case 4124:
+   case 4126:
+   case 4128:
+   case 4130:
+   case 4132:
+   case 4134:
+   case 4136:
+   case 4138:
+   case 4140:
+   case 4142:
+   case 4144:
+   case 4146:
+   case 4148:
+   case 4150:
+   case 4152:
+   case 4154:
+   case 4156:
+   case 4158:
+   case 4160:
+   case 4162:
+   case 4164:
+   case 4166:
+   case 4168:
+   case 4170:
+   case 4172:
+   case 4174:
+   case 4176:
+   case 4178:
+   case 4180:
+   case 4182:
+   case 4184:
+   case 4186:
+   case 4188:
+   case 4190:
+   case 4192:
+   case 4194:
+   case 4196:
+   case 4198:
+   case 4200:
+   case 4202:
+   case 4204:
+   case 4206:
+   case 4208:
+   case 4210:
+   case 4212:
+   case 4214:
+   case 4216:
+   case 4218:
+   case 4220:
+   case 4222:
+   case 4224:
+   case 4226:
+   case 4228:
+   case 4230:
+   case 4232:
+   case 4234:
+   case 4236:
+   case 4238:
+   case 4240:
+   case 4242:
+   case 4244:
+   case 4246:
+   case 4248:
+   case 4250:
+   case 4252:
+   case 4254:
+   case 4256:
+   case 4258:
+   case 4260:
+   case 4262:
+   case 4264:
+   case 4266:
+   case 4268:
+   case 4270:
+   case 4272:
+   case 4274:
+   case 4276:
+   case 4278:
+   case 4280:
+   case 4282:
+   case 4284:
+   case 4286:
+   case 4288:
+   case 4290:
+   case 4292:
+   case 4294:
+   case 4296:
+   case 4298:
+   case 4300:
+   case 4302:
+   case 4304:
+   case 4306:
+   case 4308:
+   case 4310:
+   case 4312:
+   case 4314:
+   case 4316:
+   case 4318:
+   case 4320:
+   case 4322:
+   case 4324:
+   case 4326:
+   case 4328:
+   case 4330:
+   case 4332:
+   case 4334:
+   case 4336:
+   case 4338:
+   case 4340:
+   case 4342:
+   case 4344:
+   case 4346:
+   case 4348:
+   case 4350:
+   case 4352:
+   case 4354:
+   case 4356:
+   case 4358:
+   case 4360:
+   case 4362:
+   case 4364:
+   case 4366:
+   case 4368:
+   case 4370:
+   case 4372:
+   case 4374:
+   case 4376:
+   case 4378:
+   case 4380:
+   case 4382:
+   case 4384:
+   case 4386:
+   case 4388:
+   case 4390:
+   case 4392:
+   case 4394:
+   case 4396:
+   case 4398:
+   case 4400:
+   case 4402:
+   case 4404:
+   case 4406:
+   case 4408:
+   case 4410:
+   case 4412:
+   case 4414:
+   case 4416:
+   case 4418:
+   case 4420:
+   case 4422:
+   case 4424:
+   case 4426:
+   case 4428:
+   case 4430:
+   case 4432:
+   case 4434:
+   case 4436:
+   case 4438:
+   case 4440:
+   case 4442:
+   case 4444:
+   case 4446:
+   case 4448:
+   case 4450:
+   case 4452:
+   case 4454:
+   case 4456:
+   case 4458:
+   case 4460:
+   case 4462:
+   case 4464:
+   case 4466:
+   case 4468:
+   case 4470:
+   case 4472:
+   case 4474:
+   case 4476:
+   case 4478:
+   case 4480:
+   case 4482:
+   case 4484:
+   case 4486:
+   case 4488:
+   case 4490:
+   case 4492:
+   case 4494:
+   case 4496:
+   case 4498:
+   case 4500:
+   case 4502:
+   case 4504:
+   case 4506:
+   case 4508:
+   case 4510:
+   case 4512:
+   case 4514:
+   case 4516:
+   case 4518:
+   case 4520:
+   case 4522:
+   case 4524:
+   case 4526:
+   case 4528:
+   case 4530:
+   case 4532:
+   case 4534:
+   case 4536:
+   case 4538:
+   case 4540:
+   case 4542:
+   case 4544:
+   case 4546:
+   case 4548:
+   case 4550:
+   case 4552:
+   case 4554:
+   case 4556:
+   case 4558:
+   case 4560:
+   case 4562:
+   case 4564:
+   case 4566:
+   case 4568:
+   case 4570:
+   case 4572:
+   case 4574:
+   case 4576:
+   case 4578:
+   case 4580:
+   case 4582:
+   case 4584:
+   case 4586:
+   case 4588:
+   case 4590:
+   case 4592:
+   case 4594:
+   case 4596:
+   case 4598:
+   case 4600:
+   case 4602:
+   case 4604:
+   case 4606:
+   case 4608:
+   case 4610:
+   case 4612:
+   case 4614:
+   case 4616:
+   case 4618:
+   case 4620:
+   case 4622:
+   case 4624:
+   case 4626:
+   case 4628:
+   case 4630:
+   case 4632:
+   case 4634:
+   case 4636:
+   case 4638:
+   case 4640:
+   case 4642:
+   case 4644:
+   case 4646:
+   case 4648:
+   case 4650:
+   case 4652:
+   case 4654:
+   case 4656:
+   case 4658:
+   case 4660:
+   case 4662:
+   case 4664:
+   case 4666:
+   case 4668:
+   case 4670:
+   case 4672:
+   case 4674:
+   case 4676:
+   case 4678:
+   case 4680:
+   case 4682:
+   case 4684:
+   case 4686:
+   case 4688:
+   case 4690:
+   case 4692:
+   case 4694:
+   case 4696:
+   case 4698:
+   case 4700:
+   case 4702:
+   case 4704:
+   case 4706:
+   case 4708:
+   case 4710:
+   case 4712:
+   case 4714:
+   case 4716:
+   case 4718:
+   case 4720:
+   case 4722:
+   case 4724:
+   case 4726:
+   case 4728:
+   case 4730:
+   case 4732:
+   case 4734:
+   case 4736:
+   case 4738:
+   case 4740:
+   case 4742:
+   case 4744:
+   case 4746:
+   case 4748:
+   case 4750:
+   case 4752:
+   case 4754:
+   case 4756:
+   case 4758:
+   case 4760:
+   case 4762:
+   case 4764:
+   case 4766:
+   case 4768:
+   case 4770:
+   case 4772:
+   case 4774:
+   case 4776:
+   case 4778:
+   case 4780:
+   case 4782:
+   case 4784:
+   case 4786:
+   case 4788:
+   case 4790:
+   case 4792:
+   case 4794:
+   case 4796:
+   case 4798:
+   case 4800:
+   case 4802:
+   case 4804:
+   case 4806:
+   case 4808:
+   case 4810:
+   case 4812:
+   case 4814:
+   case 4816:
+   case 4818:
+   case 4820:
+   case 4822:
+   case 4824:
+   case 4826:
+   case 4828:
+   case 4830:
+   case 4832:
+   case 4834:
+   case 4836:
+   case 4838:
+   case 4840:
+   case 4842:
+   case 4844:
+   case 4846:
+   case 4848:
+   case 4850:
+   case 4852:
+   case 4854:
+   case 4856:
+   case 4858:
+   case 4860:
+   case 4862:
+   case 4864:
+   case 4866:
+   case 4868:
+   case 4870:
+   case 4872:
+   case 4874:
+   case 4876:
+   case 4878:
+   case 4880:
+   case 4882:
+   case 4884:
+   case 4886:
+   case 4888:
+   case 4890:
+   case 4892:
+   case 4894:
+   case 4896:
+   case 4898:
+   case 4900:
+   case 4902:
+   case 4904:
+   case 4906:
+   case 4908:
+   case 4910:
+   case 4912:
+   case 4914:
+   case 4916:
+   case 4918:
+   case 4920:
+   case 4922:
+   case 4924:
+   case 4926:
+   case 4928:
+   case 4930:
+   case 4932:
+   case 4934:
+   case 4936:
+   case 4938:
+   case 4940:
+   case 4942:
+   case 4944:
+   case 4946:
+   case 4948:
+   case 4950:
+   case 4952:
+   case 4954:
+   case 4956:
+   case 4958:
+   case 4960:
+   case 4962:
+   case 4964:
+   case 4966:
+   case 4968:
+   case 4970:
+   case 4972:
+   case 4974:
+   case 4976:
+   case 4978:
+   case 4980:
+   case 4982:
+   case 4984:
+   case 4986:
+   case 4988:
+   case 4990:
+   case 4992:
+   case 4994:
+   case 4996:
+   case 4998:
+   case 5e3:
+   case 5002:
+   case 5004:
+   case 5006:
+   case 5008:
+   case 5010:
+   case 5012:
+   case 5014:
+   case 5016:
+   case 5018:
+   case 5020:
+   case 5022:
+   case 5024:
+   case 5026:
+   case 5028:
+   case 5030:
+   case 5032:
+   case 5034:
+   case 5036:
+   case 5038:
+   case 5040:
+   case 5042:
+   case 5044:
+   case 5046:
+   case 5048:
+   case 5050:
+   case 5052:
+   case 5054:
+   case 5056:
+   case 5058:
+   case 5060:
+   case 5062:
+   case 5064:
+   case 5066:
+   case 5068:
+   case 5070:
+   case 5072:
+   case 5074:
+   case 5076:
+   case 5078:
+   case 5080:
+   case 5082:
+   case 5084:
+   case 5086:
+   case 5088:
+   case 5090:
+   case 5092:
+   case 5094:
+   case 5096:
+   case 5098:
+   case 5100:
+   case 5102:
+   case 5104:
+   case 5106:
+   case 5108:
+   case 5110:
+   case 5112:
+   case 5114:
+   case 5116:
+   case 5118:
+   case 5120:
+   case 5122:
+   case 5124:
+   case 5126:
+   case 5128:
+   case 5130:
+   case 5132:
+   case 5134:
+   case 5136:
+   case 5138:
+   case 5140:
+   case 5142:
+   case 5144:
+   case 5146:
+   case 5148:
+   case 5150:
+   case 5152:
+   case 5154:
+   case 5156:
+   case 5158:
+   case 5160:
+   case 5162:
+   case 5164:
+   case 5166:
+   case 5168:
+   case 5170:
+   case 5172:
+   case 5174:
+   case 5176:
+   case 5178:
+   case 5180:
+   case 5182:
+   case 5184:
+   case 5186:
+   case 5188:
+   case 5190:
+   case 5192:
+   case 5194:
+   case 5196:
+   case 5198:
+   case 5200:
+   case 5202:
+   case 5204:
+   case 5206:
+   case 5208:
+   case 5210:
+   case 5212:
+   case 5214:
+   case 5216:
+   case 5218:
+   case 5220:
+   case 5222:
+   case 5224:
+   case 5226:
+   case 5228:
+   case 5230:
+   case 5232:
+   case 5234:
+   case 5236:
+   case 5238:
+   case 5240:
+   case 5242:
+   case 5244:
+   case 5246:
+   case 5248:
+   case 5250:
+   case 5252:
+   case 5254:
+   case 5256:
+   case 5258:
+   case 5260:
+   case 5262:
+   case 5264:
+   case 5266:
+   case 5268:
+   case 5270:
+   case 5272:
+   case 5274:
+   case 5276:
+   case 5278:
+   case 5280:
+   case 5282:
+   case 5284:
+   case 5286:
+   case 5288:
+   case 5290:
+   case 5292:
+   case 5294:
+   case 5296:
+   case 5298:
+   case 5300:
+   case 5302:
+   case 5304:
+   case 5306:
+   case 5308:
+   case 5310:
+   case 5312:
+   case 5314:
+   case 5316:
+   case 5318:
+   case 5320:
+   case 5322:
+   case 5324:
+   case 5326:
+   case 5328:
+   case 5330:
+   case 5332:
+   case 5334:
+   case 5336:
+   case 5338:
+   case 5340:
+   case 5342:
+   case 5344:
+   case 5346:
+   case 5348:
+   case 5350:
+   case 5352:
+   case 5354:
+   case 5356:
+   case 5358:
+   case 5360:
+   case 5362:
+   case 5364:
+   case 5366:
+   case 5368:
+   case 5370:
+   case 5372:
+   case 5374:
+   case 5376:
+   case 5378:
+   case 5380:
+   case 5382:
+   case 5384:
+   case 5386:
+   case 5388:
+   case 5390:
+   case 5392:
+   case 5394:
+   case 5396:
+   case 5398:
+   case 5400:
+   case 5402:
+   case 5404:
+   case 5406:
+   case 5408:
+   case 5410:
+   case 5412:
+   case 5414:
+   case 5416:
+   case 5418:
+   case 5420:
+   case 5422:
+   case 5424:
+   case 5426:
+   case 5428:
+   case 5430:
+   case 5432:
+   case 5434:
+   case 5436:
+   case 5438:
+   case 5440:
+   case 5442:
+   case 5444:
+   case 5446:
+   case 5448:
+   case 5450:
+   case 5452:
+   case 5454:
+   case 5456:
+   case 5458:
+   case 5460:
+   case 5462:
+   case 5464:
+   case 5466:
+   case 5468:
+   case 5470:
+   case 5472:
+   case 5474:
+   case 5476:
+   case 5478:
+   case 5480:
+   case 5482:
+   case 5484:
+   case 5486:
+   case 5488:
+   case 5490:
+   case 5492:
+   case 5494:
+   case 5496:
+   case 5498:
+   case 5500:
+   case 5502:
+   case 5504:
+   case 5506:
+   case 5508:
+   case 5510:
+   case 5512:
+   case 5514:
+   case 5516:
+   case 5518:
+   case 5520:
+   case 5522:
+   case 5524:
+   case 5526:
+   case 5528:
+   case 5530:
+   case 5532:
+   case 5534:
+   case 5536:
+   case 5538:
+   case 5540:
+   case 5542:
+   case 5544:
+   case 5546:
+   case 5548:
+   case 5550:
+   case 5552:
+   case 5554:
+   case 5556:
+   case 5558:
+   case 5560:
+   case 5562:
+   case 5564:
+   case 5566:
+   case 5568:
+   case 5570:
+   case 5572:
+   case 5574:
+   case 5576:
+   case 5578:
+   case 5580:
+   case 5582:
+   case 5584:
+   case 5586:
+   case 5588:
+   case 5590:
+   case 5592:
+   case 5594:
+   case 5596:
+   case 5598:
+   case 5600:
+   case 5602:
+   case 5604:
+   case 5606:
+   case 5608:
+   case 5610:
+   case 5612:
+   case 5614:
+   case 5616:
+   case 5618:
+   case 5620:
+   case 5622:
+   case 5624:
+   case 5626:
+   case 5628:
+   case 5630:
+   case 5632:
+   case 5634:
+   case 5636:
+   case 5638:
+   case 5640:
+   case 5642:
+   case 5644:
+   case 5646:
+   case 5648:
+   case 5650:
+   case 5652:
+   case 5654:
+   case 5656:
+   case 5658:
+   case 5660:
+   case 5662:
+   case 5664:
+   case 5666:
+   case 5668:
+   case 5670:
+   case 5672:
+   case 5674:
+   case 5676:
+   case 5678:
+   case 5680:
+   case 5682:
+   case 5684:
+   case 5686:
+   case 5688:
+   case 5690:
+   case 5692:
+   case 5694:
+   case 5696:
+   case 5698:
+   case 5700:
+   case 5702:
+   case 5704:
+   case 5706:
+   case 5708:
+   case 5710:
+   case 5712:
+   case 5714:
+   case 5716:
+   case 5718:
+   case 5720:
+   case 5722:
+   case 5724:
+   case 5726:
+   case 5728:
+   case 5730:
+   case 5732:
+   case 5734:
+   case 5736:
+   case 5738:
+   case 5740:
+   case 5742:
+   case 5744:
+   case 5746:
+   case 5748:
+   case 5750:
+   case 5752:
+   case 5754:
+   case 5756:
+   case 5758:
+   case 5760:
+   case 5762:
+   case 5764:
+   case 5766:
+   case 5768:
+   case 5770:
+   case 5772:
+   case 5774:
+   case 5776:
+   case 5778:
+   case 5780:
+   case 5782:
+   case 5784:
+   case 5786:
+   case 5788:
+   case 5790:
+   case 5792:
+   case 5794:
+   case 5796:
+   case 5798:
+   case 5800:
+   case 5802:
+   case 5804:
+   case 5806:
+   case 5808:
+   case 5810:
+   case 5812:
+   case 5814:
+   case 5816:
+   case 5818:
+   case 5820:
+   case 5822:
+   case 5824:
+   case 5826:
+   case 5828:
+   case 5830:
+   case 5832:
+   case 5834:
+   case 5836:
+   case 5838:
+   case 5840:
+   case 5842:
+   case 5844:
+   case 5846:
+   case 5848:
+   case 5850:
+   case 5852:
+   case 5854:
+   case 5856:
+   case 5858:
+   case 5860:
+   case 5862:
+   case 5864:
+   case 5866:
+   case 5868:
+   case 5870:
+   case 5872:
+   case 5874:
+   case 5876:
+   case 5878:
+   case 5880:
+   case 5882:
+   case 5884:
+   case 5886:
+   case 5888:
+   case 5890:
+   case 5892:
+   case 5894:
+   case 5896:
+   case 5898:
+   case 5900:
+   case 5902:
+   case 5904:
+   case 5906:
+   case 5908:
+   case 5910:
+   case 5912:
+   case 5914:
+   case 5916:
+   case 5918:
+   case 5920:
+   case 5922:
+   case 5924:
+   case 5926:
+   case 5928:
+   case 5930:
+   case 5932:
+   case 5934:
+   case 5936:
+   case 5938:
+   case 5940:
+   case 5942:
+   case 5944:
+   case 5946:
+   case 5948:
+   case 5950:
+   case 5952:
+   case 5954:
+   case 5956:
+   case 5958:
+   case 5960:
+   case 5962:
+   case 5964:
+   case 5966:
+   case 5968:
+   case 5970:
+   case 5972:
+   case 5974:
+   case 5976:
+   case 5978:
+   case 5980:
+   case 5982:
+   case 5984:
+   case 5986:
+   case 5988:
+   case 5990:
+   case 5992:
+   case 5994:
+   case 5996:
+   case 5998:
+   case 6e3:
+   case 6002:
+   case 6004:
+   case 6006:
+   case 6008:
+   case 6010:
+   case 6012:
+   case 6014:
+   case 6016:
+   case 6018:
+   case 6020:
+   case 6022:
+   case 6024:
+   case 6026:
+   case 6028:
+   case 6030:
+   case 6032:
+   case 6034:
+   case 6036:
+   case 6038:
+   case 6040:
+   case 6042:
+   case 6044:
+   case 6046:
+   case 6048:
+   case 6050:
+   case 6052:
+   case 6054:
+   case 6056:
+   case 6058:
+   case 6060:
+   case 6062:
+   case 6064:
+   case 6066:
+   case 6068:
+   case 6070:
+   case 6072:
+   case 6074:
+   case 6076:
+   case 6078:
+   case 6080:
+   case 6082:
+   case 6084:
+   case 6086:
+   case 6088:
+   case 6090:
+   case 6092:
+   case 6094:
+   case 6096:
+   case 6098:
+   case 6100:
+   case 6102:
+   case 6104:
+   case 6106:
+   case 6108:
+   case 6110:
+   case 6112:
+   case 6114:
+   case 6116:
+   case 6118:
+   case 6120:
+   case 6122:
+   case 6124:
+   case 6126:
+   case 6128:
+   case 6130:
+   case 6132:
+   case 6134:
+   case 6136:
+   case 6138:
+   case 6140:
+   case 6142:
+   case 6144:
+   case 6146:
+   case 6148:
+   case 6150:
+   case 6152:
+   case 6154:
+   case 6156:
+   case 6158:
+   case 6160:
+   case 6162:
+   case 6164:
+   case 6166:
+   case 6168:
+   case 6170:
+   case 6172:
+   case 6174:
+   case 6176:
+   case 6178:
+   case 6180:
+   case 6182:
+   case 6184:
+   case 6186:
+   case 6188:
+   case 6190:
+   case 6192:
+   case 6194:
+   case 6196:
+   case 6198:
+   case 6200:
+   case 6202:
+   case 6204:
+   case 6206:
+   case 6208:
+   case 6210:
+   case 6212:
+   case 6214:
+   case 6216:
+   case 6218:
+   case 6220:
+   case 6222:
+   case 6224:
+   case 6226:
+   case 6228:
+   case 6230:
+   case 6232:
+   case 6234:
+   case 6236:
+   case 6238:
+   case 6240:
+   case 6242:
+   case 6244:
+   case 6246:
+   case 6248:
+   case 6250:
+   case 6252:
+   case 6254:
+   case 6256:
+   case 6258:
+   case 6260:
+   case 6262:
+   case 6264:
+   case 6266:
+   case 6268:
+   case 6270:
+   case 6272:
+   case 6274:
+   case 6276:
+   case 6278:
+   case 6280:
+   case 6282:
+   case 6284:
+   case 6286:
+   case 6288:
+   case 6290:
+   case 6292:
+   case 6294:
+   case 6296:
+   case 6298:
+   case 6300:
+   case 6302:
+   case 6304:
+   case 6306:
+   case 6308:
+   case 6310:
+   case 6312:
+   case 6314:
+   case 6316:
+   case 6318:
+   case 6320:
+   case 6322:
+   case 6324:
+   case 6326:
+   case 6328:
+   case 6330:
+   case 6332:
+   case 6334:
+   case 6336:
+   case 6338:
+   case 6340:
+   case 6342:
+   case 6344:
+   case 6346:
+   case 6348:
+   case 6350:
+   case 6352:
+   case 6354:
+   case 6356:
+   case 6358:
+   case 6360:
+   case 6362:
+   case 6364:
+   case 6366:
+   case 6368:
+   case 6370:
+   case 6372:
+   case 6374:
+   case 6376:
+   case 6378:
+   case 6380:
+   case 6382:
+   case 6384:
+   case 6386:
+   case 6388:
+   case 6390:
+   case 6392:
+   case 6394:
+   case 6396:
+   case 6398:
+   case 6400:
+   case 6402:
+   case 6404:
+   case 6406:
+   case 6408:
+   case 6410:
+   case 6412:
+   case 6414:
+   case 6416:
+   case 6418:
+   case 6420:
+   case 6422:
+   case 6424:
+   case 6426:
+   case 6428:
+   case 6430:
+   case 6432:
+   case 6434:
+   case 6436:
+   case 6438:
+   case 6440:
+   case 6442:
+   case 6444:
+   case 6446:
+   case 6448:
+   case 6450:
+   case 6452:
+   case 6454:
+   case 6456:
+   case 6458:
+   case 6460:
+   case 6462:
+   case 6464:
+   case 6466:
+   case 6468:
+   case 6470:
+   case 6472:
+   case 6474:
+   case 6476:
+   case 6478:
+   case 6480:
+   case 6482:
+   case 6484:
+   case 6486:
+   case 6488:
+   case 6490:
+   case 6492:
+   case 6494:
+   case 6496:
+   case 6498:
+   case 6500:
+   case 6502:
+   case 6504:
+   case 6506:
+   case 6508:
+   case 6510:
+   case 6512:
+   case 6514:
+   case 6516:
+   case 6518:
+   case 6520:
+   case 6522:
+   case 6524:
+   case 6526:
+   case 6528:
+   case 6530:
+   case 6532:
+   case 6534:
+   case 6536:
+   case 6538:
+   case 6540:
+   case 6542:
+   case 6544:
+   case 6546:
+   case 6548:
+   case 6550:
+   case 6552:
+   case 6554:
+   case 6556:
+   case 6558:
+   case 6560:
+   case 6562:
+   case 6564:
+   case 6566:
+   case 6568:
+   case 6570:
+   case 6572:
+   case 6574:
+   case 6576:
+   case 6578:
+   case 6580:
+   case 6582:
+   case 6584:
+   case 6586:
+   case 6588:
+   case 6590:
+   case 6592:
+   case 6594:
+   case 6596:
+   case 6598:
+   case 6600:
+   case 6602:
+   case 6604:
+   case 6606:
+   case 6608:
+   case 6610:
+   case 6612:
+   case 6614:
+   case 6616:
+   case 6618:
+   case 6620:
+   case 6622:
+   case 6624:
+   case 6626:
+   case 6628:
+   case 6630:
+   case 6632:
+   case 6634:
+   case 6636:
+   case 6638:
+   case 6640:
+   case 6642:
+   case 6644:
+   case 6646:
+   case 6648:
+   case 6650:
+   case 6652:
+   case 6654:
+   case 6656:
+   case 6658:
+   case 6660:
+   case 6662:
+   case 6664:
+   case 6666:
+   case 6668:
+   case 6670:
+   case 6672:
+   case 6674:
+   case 6676:
+   case 6678:
+   case 6680:
+   case 6682:
+   case 6684:
+   case 6686:
+   case 6688:
+   case 6690:
+   case 6692:
+   case 6694:
+   case 6696:
+   case 6698:
+   case 6700:
+   case 6702:
+   case 6704:
+   case 6706:
+   case 6708:
+   case 6710:
+   case 6712:
+   case 6714:
+   case 6716:
+   case 6718:
+   case 6720:
+   case 6722:
+   case 6724:
+   case 6726:
+   case 6728:
+   case 6730:
+   case 6732:
+   case 6734:
+   case 6736:
+   case 6738:
+   case 6740:
+   case 6742:
+   case 6744:
+   case 6746:
+   case 6748:
+   case 6750:
+   case 6752:
+   case 6754:
+   case 6756:
+   case 6758:
+   case 6760:
+   case 6762:
+   case 6764:
+   case 6766:
+   case 6768:
+   case 6770:
+   case 6772:
+   case 6774:
+   case 6776:
+   case 6778:
+   case 6780:
+   case 6782:
+   case 6784:
+   case 6786:
+   case 6788:
+   case 6790:
+   case 6792:
+   case 6794:
+   case 6796:
+   case 6798:
+   case 6800:
+   case 6802:
+   case 6804:
+   case 6806:
+   case 6808:
+   case 6810:
+   case 6812:
+   case 6814:
+   case 6816:
+   case 6818:
+   case 6820:
+   case 6822:
+   case 6824:
+   case 6826:
+   case 6828:
+   case 6830:
+   case 6832:
+   case 6834:
+   case 6836:
+   case 6838:
+   case 6840:
+   case 6842:
+   case 6844:
+   case 6846:
+   case 6848:
+   case 6850:
+   case 6852:
+   case 6854:
+   case 6856:
+   case 6858:
+   case 6860:
+   case 6862:
+   case 6864:
+   case 6866:
+   case 6868:
+   case 6870:
+   case 6872:
+   case 6874:
+   case 6876:
+   case 6878:
+   case 6880:
+   case 6882:
+   case 6884:
+   case 6886:
+   case 6888:
+   case 6890:
+   case 6892:
+   case 6894:
+   case 6896:
+   case 6898:
+   case 6900:
+   case 6902:
+   case 6904:
+   case 6906:
+   case 6908:
+   case 6910:
+   case 6912:
+   case 6914:
+   case 6916:
+   case 6918:
+   case 6920:
+   case 6922:
+   case 6924:
+   case 6926:
+   case 6928:
+   case 6930:
+   case 6932:
+   case 6934:
+   case 6936:
+   case 6938:
+   case 6940:
+   case 6942:
+   case 6944:
+   case 6946:
+   case 6948:
+   case 6950:
+   case 6952:
+   case 6954:
+   case 6956:
+   case 6958:
+   case 6960:
+   case 6962:
+   case 6964:
+   case 6966:
+   case 6968:
+   case 6970:
+   case 6972:
+   case 6974:
+   case 6976:
+   case 6978:
+   case 6980:
+   case 6982:
+   case 6984:
+   case 6986:
+   case 6988:
+   case 6990:
+   case 6992:
+   case 6994:
+   case 6996:
+   case 6998:
+   case 7e3:
+   case 7002:
+   case 7004:
+   case 7006:
+   case 7008:
+   case 7010:
+   case 7012:
+   case 7014:
+   case 7016:
+   case 7018:
+   case 7020:
+   case 7022:
+   case 7024:
+   case 7026:
+   case 7028:
+   case 7030:
+   case 7032:
+   case 7034:
+   case 7036:
+   case 7038:
+   case 7040:
+   case 7042:
+   case 7044:
+   case 7046:
+   case 7048:
+   case 7050:
+   case 7052:
+   case 7054:
+   case 7056:
+   case 7058:
+   case 7060:
+   case 7062:
+   case 7064:
+   case 7066:
+   case 7068:
+   case 7070:
+   case 7072:
+   case 7074:
+   case 7076:
+   case 7078:
+   case 7080:
+   case 7082:
+   case 7084:
+   case 7086:
+   case 7088:
+   case 7090:
+   case 7092:
+   case 7094:
+   case 7096:
+   case 7098:
+   case 7100:
+   case 7102:
+   case 7104:
+   case 7106:
+   case 7108:
+   case 7110:
+   case 7112:
+   case 7114:
+   case 7116:
+   case 7118:
+   case 7120:
+   case 7122:
+   case 7124:
+   case 7126:
+   case 7128:
+   case 7130:
+   case 7132:
+   case 7134:
+   case 7136:
+   case 7138:
+   case 7140:
+   case 7142:
+   case 7144:
+   case 7146:
+   case 7148:
+   case 7150:
+   case 7152:
+   case 7154:
+   case 7156:
+   case 7158:
+   case 7160:
+   case 7162:
+   case 7164:
+   case 7166:
+   case 7168:
+   case 7170:
+   case 7172:
+   case 7174:
+   case 7176:
+   case 7178:
+   case 7180:
+   case 7182:
+   case 7184:
+   case 7186:
+   case 7188:
+   case 7190:
+   case 7192:
+   case 7194:
+   case 7196:
+   case 7198:
+   case 7200:
+   case 7202:
+   case 7204:
+   case 7206:
+   case 7208:
+   case 7210:
+   case 7212:
+   case 7214:
+   case 7216:
+   case 7218:
+   case 7220:
+   case 7222:
+   case 7224:
+   case 7226:
+   case 7228:
+   case 7230:
+   case 7232:
+   case 7234:
+   case 7236:
+   case 7238:
+   case 7240:
+   case 7242:
+   case 7244:
+   case 7246:
+   case 7248:
+   case 7250:
+   case 7252:
+   case 7254:
+   case 7256:
+   case 7258:
+   case 7260:
+   case 7262:
+   case 7264:
+   case 7266:
+   case 7268:
+   case 7270:
+   case 7272:
+   case 7274:
+   case 7276:
+   case 7278:
+   case 7280:
+   case 7282:
+   case 7284:
+   case 7286:
+   case 7288:
+   case 7290:
+   case 7292:
+   case 7294:
+   case 7296:
+   case 7298:
+   case 7300:
+   case 7302:
+   case 7304:
+   case 7306:
+   case 7308:
+   case 7310:
+   case 7312:
+   case 7314:
+   case 7316:
+   case 7318:
+   case 7320:
+   case 7322:
+   case 7324:
+   case 7326:
+   case 7328:
+   case 7330:
+   case 7332:
+   case 7334:
+   case 7336:
+   case 7338:
+   case 7340:
+   case 7342:
+   case 7344:
+   case 7346:
+   case 7348:
+   case 7350:
+   case 7352:
+   case 7354:
+   case 7356:
+   case 7358:
+   case 7360:
+   case 7362:
+   case 7364:
+   case 7366:
+   case 7368:
+   case 7370:
+   case 7372:
+   case 7374:
+   case 7376:
+   case 7378:
+   case 7380:
+   case 7382:
+   case 7384:
+   case 7386:
+   case 7388:
+   case 7390:
+   case 7392:
+   case 7394:
+   case 7396:
+   case 7398:
+   case 7400:
+   case 7402:
+   case 7404:
+   case 7406:
+   case 7408:
+   case 7410:
+   case 7412:
+   case 7414:
+   case 7416:
+   case 7418:
+   case 7420:
+   case 7422:
+   case 7424:
+   case 7426:
+   case 7428:
+   case 7430:
+   case 7432:
+   case 7434:
+   case 7436:
+   case 7438:
+   case 7440:
+   case 7442:
+   case 7444:
+   case 7446:
+   case 7448:
+   case 7450:
+   case 7452:
+   case 7454:
+   case 7456:
+   case 7458:
+   case 7460:
+   case 7462:
+   case 7464:
+   case 7466:
+   case 7468:
+   case 7470:
+   case 7472:
+   case 7474:
+   case 7476:
+   case 7478:
+   case 7480:
+   case 7482:
+   case 7484:
+   case 7486:
+   case 7488:
+   case 7490:
+   case 7492:
+   case 7494:
+   case 7496:
+   case 7498:
+   case 7500:
+   case 7502:
+   case 7504:
+   case 7506:
+   case 7508:
+   case 7510:
+   case 7512:
+   case 7514:
+   case 7516:
+   case 7518:
+   case 7520:
+   case 7522:
+   case 7524:
+   case 7526:
+   case 7528:
+   case 7530:
+   case 7532:
+   case 7534:
+   case 7536:
+   case 7538:
+   case 7540:
+   case 7542:
+   case 7544:
+   case 7546:
+   case 7548:
+   case 7550:
+   case 7552:
+   case 7554:
+   case 7556:
+   case 7558:
+   case 7560:
+   case 7562:
+   case 7564:
+   case 7566:
+   case 7568:
+   case 7570:
+   case 7572:
+   case 7574:
+   case 7576:
+   case 7578:
+   case 7580:
+   case 7582:
+   case 7584:
+   case 7586:
+   case 7588:
+   case 7590:
+   case 7592:
+   case 7594:
+   case 7596:
+   case 7598:
+   case 7600:
+   case 7602:
+   case 7604:
+   case 7606:
+   case 7608:
+   case 7610:
+   case 7612:
+   case 7614:
+   case 7616:
+   case 7618:
+   case 7620:
+   case 7622:
+   case 7624:
+   case 7626:
+   case 7628:
+   case 7630:
+   case 7632:
+   case 7634:
+   case 7636:
+   case 7638:
+   case 7640:
+   case 7642:
+   case 7644:
+   case 7646:
+   case 7648:
+   case 7650:
+   case 7652:
+   case 7654:
+   case 7656:
+   case 7658:
+   case 7660:
+   case 7662:
+   case 7664:
+   case 7666:
+   case 7668:
+   case 7670:
+   case 7672:
+   case 7674:
+   case 7676:
+   case 7678:
+   case 7680:
+   case 7682:
+   case 7684:
+   case 7686:
+   case 7688:
+   case 7690:
+   case 7692:
+   case 7694:
+   case 7696:
+   case 7698:
+   case 7700:
+   case 7702:
+   case 7704:
+   case 7706:
+   case 7708:
+   case 7710:
+   case 7712:
+   case 7714:
+   case 7716:
+   case 7718:
+   case 7720:
+   case 7722:
+   case 7724:
+   case 7726:
+   case 7728:
+   case 7730:
+   case 7732:
+   case 7734:
+   case 7736:
+   case 7738:
+   case 7740:
+   case 7742:
+   case 7744:
+   case 7746:
+   case 7748:
+   case 7750:
+   case 7752:
+   case 7754:
+   case 7756:
+   case 7758:
+   case 7760:
+   case 7762:
+   case 7764:
+   case 7766:
+   case 7768:
+   case 7770:
+   case 7772:
+   case 7774:
+   case 7776:
+   case 7778:
+   case 7780:
+   case 7782:
+   case 7784:
+   case 7786:
+   case 7788:
+   case 7790:
+   case 7792:
+   case 7794:
+   case 7796:
+   case 7798:
+   case 7800:
+   case 7802:
+   case 7804:
+   case 7806:
+   case 7808:
+   case 7810:
+   case 7812:
+   case 7814:
+   case 7816:
+   case 7818:
+   case 7820:
+   case 7822:
+   case 7824:
+   case 7826:
+   case 7828:
+   case 7830:
+   case 7832:
+   case 7834:
+   case 7836:
+   case 7838:
+   case 7840:
+   case 7842:
+   case 7844:
+   case 7846:
+   case 7848:
+   case 7850:
+   case 7852:
+   case 7854:
+   case 7856:
+   case 7858:
+   case 7860:
+   case 7862:
+   case 7864:
+   case 7866:
+   case 7868:
+   case 7870:
+   case 7872:
+   case 7874:
+   case 7876:
+   case 7878:
+   case 7880:
+   case 7882:
+   case 7884:
+   case 7886:
+   case 7888:
+   case 7890:
+   case 7892:
+   case 7894:
+   case 7896:
+   case 7898:
+   case 7900:
+   case 7902:
+   case 7904:
+   case 7906:
+   case 7908:
+   case 7910:
+   case 7912:
+   case 7914:
+   case 7916:
+   case 7918:
+   case 7920:
+   case 7922:
+   case 7924:
+   case 7926:
+   case 7928:
+   case 7930:
+   case 7932:
+   case 7934:
+   case 7936:
+   case 7938:
+   case 7940:
+   case 7942:
+   case 7944:
+   case 7946:
+   case 7948:
+   case 7950:
+   case 7952:
+   case 7954:
+   case 7956:
+   case 7958:
+   case 7960:
+   case 7962:
+   case 7964:
+   case 7966:
+   case 7968:
+   case 7970:
+   case 7972:
+   case 7974:
+   case 7976:
+   case 7978:
+   case 7980:
+   case 7982:
+   case 7984:
+   case 7986:
+   case 7988:
+   case 7990:
+   case 7992:
+   case 7994:
+   case 7996:
+   case 7998:
+   case 8e3:
+   case 8002:
+   case 8004:
+   case 8006:
+   case 8008:
+   case 8010:
+   case 8012:
+   case 8014:
+   case 8016:
+   case 8018:
+   case 8020:
+   case 8022:
+   case 8024:
+   case 8026:
+   case 8028:
+   case 8030:
+   case 8032:
+   case 8034:
+   case 8036:
+   case 8038:
+   case 8040:
+   case 8042:
+   case 8044:
+   case 8046:
+   case 8048:
+   case 8050:
+   case 8052:
+   case 8054:
+   case 8056:
+   case 8058:
+   case 8060:
+   case 8062:
+   case 8064:
+   case 8066:
+   case 8068:
+   case 8070:
+   case 8072:
+   case 8074:
+   case 8076:
+   case 8078:
+   case 8080:
+   case 8082:
+   case 8084:
+   case 8086:
+   case 8088:
+   case 8090:
+   case 8092:
+   case 8094:
+   case 8096:
+   case 8098:
+   case 8100:
+   case 8102:
+   case 8104:
+   case 8106:
+   case 8108:
+   case 8110:
+   case 8112:
+   case 8114:
+   case 8116:
+   case 8118:
+   case 8120:
+   case 8122:
+   case 8124:
+   case 8126:
+   case 8128:
+   case 8130:
+   case 8132:
+   case 8134:
+   case 8136:
+   case 8138:
+   case 8140:
+   case 8142:
+   case 8144:
+   case 8146:
+   case 8148:
+   case 8150:
+   case 8152:
+   case 8154:
+   case 8156:
+   case 8158:
+   case 8160:
+   case 8162:
+   case 8164:
+   case 8166:
+   case 8168:
+   case 8170:
+   case 8172:
+   case 8174:
+   case 8176:
+   case 8178:
+   case 8180:
+   case 8182:
+   case 8184:
+   case 8186:
+   case 8188:
+   case 8190:
+   case 8192:
+   case 8194:
+   case 8196:
+   case 8198:
+   case 8200:
+   case 8202:
+   case 8204:
+   case 8206:
+   case 8208:
+   case 8210:
+   case 8212:
+   case 8214:
+   case 8216:
+   case 8218:
+   case 8220:
+   case 8222:
+   case 8224:
+   case 8226:
+   case 8228:
+   case 8230:
+   case 8232:
+   case 8234:
+   case 8236:
+   case 8238:
+   case 8240:
+   case 8242:
+   case 8244:
+   case 8246:
+   case 8248:
+   case 8250:
+   case 8252:
+   case 8254:
+   case 8256:
+   case 8258:
+   case 8260:
+   case 8262:
+   case 8264:
+   case 8266:
+   case 8268:
+   case 8270:
+   case 8272:
+   case 8274:
+   case 8276:
+   case 8278:
+   case 8280:
+   case 8282:
+   case 8284:
+   case 8286:
+   case 8288:
+   case 8290:
+   case 8292:
+   case 8294:
+   case 8296:
+   case 8298:
+   case 8300:
+   case 8302:
+   case 8304:
+   case 8306:
+   case 8308:
+   case 8310:
+   case 8312:
+   case 8314:
+   case 8316:
+   case 8318:
+   case 8320:
+   case 8322:
+   case 8324:
+   case 8326:
+   case 8328:
+   case 8330:
+   case 8332:
+   case 8334:
+   case 8336:
+   case 8338:
+   case 8340:
+   case 8342:
+   case 8344:
+   case 8346:
+   case 8348:
+   case 8350:
+   case 8352:
+   case 8354:
+   case 8356:
+   case 8358:
+   case 8360:
+   case 8362:
+   case 8364:
+   case 8366:
+   case 8368:
+   case 8370:
+   case 8372:
+   case 8374:
+   case 8376:
+   case 8378:
+   case 8380:
+   case 8382:
+   case 8384:
+   case 8386:
+   case 8388:
+   case 8390:
+   case 8392:
+   case 8394:
+   case 8396:
+   case 8398:
+   case 8400:
+   case 8402:
+   case 8404:
+   case 8406:
+   case 8408:
+   case 8410:
+   case 8412:
+   case 8414:
+   case 8416:
+   case 8418:
+   case 8420:
+   case 8422:
+   case 8424:
+   case 8426:
+   case 8428:
+   case 8430:
+   case 8432:
+   case 8434:
+   case 8436:
+   case 8438:
+   case 8440:
+   case 8442:
+   case 8444:
+   case 8446:
+   case 8448:
+   case 8450:
+   case 8452:
+   case 8454:
+   case 8456:
+   case 8458:
+   case 8460:
+   case 8462:
+   case 8464:
+   case 8466:
+   case 8468:
+   case 8470:
+   case 8472:
+   case 8474:
+   case 8476:
+   case 8478:
+   case 8480:
+   case 8482:
+   case 8484:
+   case 8486:
+   case 8488:
+   case 8490:
+   case 8492:
+   case 8494:
+   case 8496:
+   case 8498:
+   case 8500:
+   case 8502:
+   case 8504:
+   case 8506:
+   case 8508:
+   case 8510:
+   case 8512:
+   case 8514:
+   case 8516:
+   case 8518:
+   case 8520:
+   case 8522:
+   case 8524:
+   case 8526:
+   case 8528:
+   case 8530:
+   case 8532:
+   case 8534:
+   case 8536:
+   case 8538:
+   case 8540:
+   case 8542:
+   case 8544:
+   case 8546:
+   case 8548:
+   case 8550:
+   case 8552:
+   case 8554:
+   case 8556:
+   case 8558:
+   case 8560:
+   case 8562:
+   case 8564:
+   case 8566:
+   case 8568:
+   case 8570:
+   case 8572:
+   case 8574:
+   case 8576:
+   case 8578:
+   case 8580:
+   case 8582:
+   case 8584:
+   case 8586:
+   case 8588:
+   case 8590:
+   case 8592:
+   case 8594:
+   case 8596:
+   case 8598:
+   case 8600:
+   case 8602:
+   case 8604:
+   case 8606:
+   case 8608:
+   case 8610:
+   case 8612:
+   case 8614:
+   case 8616:
+   case 8618:
+   case 8620:
+   case 8622:
+   case 8624:
+   case 8626:
+   case 8628:
+   case 8630:
+   case 8632:
+   case 8634:
+   case 8636:
+   case 8638:
+   case 8640:
+   case 8642:
+   case 8644:
+   case 8646:
+   case 8648:
+   case 8650:
+   case 8652:
+   case 8654:
+   case 8656:
+   case 8658:
+   case 8660:
+   case 8662:
+   case 8664:
+   case 8666:
+   case 8668:
+   case 8670:
+   case 8672:
+   case 8674:
+   case 8676:
+   case 8678:
+   case 8680:
+   case 8682:
+   case 8684:
+   case 8686:
+   case 8688:
+   case 8690:
+   case 8692:
+   case 8694:
+   case 8696:
+   case 8698:
+   case 8700:
+   case 8702:
+   case 8704:
+   case 8706:
+   case 8708:
+   case 8710:
+   case 8712:
+   case 8714:
+   case 8716:
+   case 8718:
+   case 8720:
+   case 8722:
+   case 8724:
+   case 8726:
+   case 8728:
+   case 8730:
+   case 8732:
+   case 8734:
+   case 8736:
+   case 8738:
+   case 8740:
+   case 8742:
+   case 8744:
+   case 8746:
+   case 8748:
+   case 8750:
+   case 8752:
+   case 8754:
+   case 8756:
+   case 8758:
+   case 8760:
+   case 8762:
+   case 8764:
+   case 8766:
+   case 8768:
+   case 8770:
+   case 8772:
+   case 8774:
+   case 8776:
+   case 8778:
+   case 8780:
+   case 8782:
+   case 8784:
+   case 8786:
+   case 8788:
+   case 8790:
+   case 8792:
+   case 8794:
+   case 8796:
+   case 8798:
+   case 8800:
+   case 8802:
+   case 8804:
+   case 8806:
+   case 8808:
+   case 8810:
+   case 8812:
+   case 8814:
+   case 8816:
+   case 8818:
+   case 8820:
+   case 8822:
+   case 8824:
+   case 8826:
+   case 8828:
+   case 8830:
+   case 8832:
+   case 8834:
+   case 8836:
+   case 8838:
+   case 8840:
+   case 8842:
+   case 8844:
+   case 8846:
+   case 8848:
+   case 8850:
+   case 8852:
+   case 8854:
+   case 8856:
+   case 8858:
+   case 8860:
+   case 8862:
+   case 8864:
+   case 8866:
+   case 8868:
+   case 8870:
+   case 8872:
+   case 8874:
+   case 8876:
+   case 8878:
+   case 8880:
+   case 8882:
+   case 8884:
+   case 8886:
+   case 8888:
+   case 8890:
+   case 8892:
+   case 8894:
+   case 8896:
+   case 8898:
+   case 8900:
+   case 8902:
+   case 8904:
+   case 8906:
+   case 8908:
+   case 8910:
+   case 8912:
+   case 8914:
+   case 8916:
+   case 8918:
+   case 8920:
+   case 8922:
+   case 8924:
+   case 8926:
+   case 8928:
+   case 8930:
+   case 8932:
+   case 8934:
+   case 8936:
+   case 8938:
+   case 8940:
+   case 8942:
+   case 8944:
+   case 8946:
+   case 8948:
+   case 8950:
+   case 8952:
+   case 8954:
+   case 8956:
+   case 8958:
+   case 8960:
+   case 8962:
+   case 8964:
+   case 8966:
+   case 8968:
+   case 8970:
+   case 8972:
+   case 8974:
+   case 8976:
+   case 8978:
+   case 8980:
+   case 8982:
+   case 8984:
+   case 8986:
+   case 8988:
+   case 8990:
+   case 8992:
+   case 8994:
+   case 8996:
+   case 8998:
+   case 9e3:
+   case 9002:
+   case 9004:
+   case 9006:
+   case 9008:
+   case 9010:
+   case 9012:
+   case 9014:
+   case 9016:
+   case 9018:
+   case 9020:
+   case 9022:
+   case 9024:
+   case 9026:
+   case 9028:
+   case 9030:
+   case 9032:
+   case 9034:
+   case 9036:
+   case 9038:
+   case 9040:
+   case 9042:
+   case 9044:
+   case 9046:
+   case 9048:
+   case 9050:
+   case 9052:
+   case 9054:
+   case 9056:
+   case 9058:
+   case 9060:
+   case 9062:
+   case 9064:
+   case 9066:
+   case 9068:
+   case 9070:
+   case 9072:
+   case 9074:
+   case 9076:
+   case 9078:
+   case 9080:
+   case 9082:
+   case 9084:
+   case 9086:
+   case 9088:
+   case 9090:
+   case 9092:
+   case 9094:
+   case 9096:
+   case 9098:
+   case 9100:
+   case 9102:
+   case 9104:
+   case 9106:
+   case 9108:
+   case 9110:
+   case 9112:
+   case 9114:
+   case 9116:
+   case 9118:
+   case 9120:
+   case 9122:
+   case 9124:
+   case 9126:
+   case 9128:
+   case 9130:
+   case 9132:
+   case 9134:
+   case 9136:
+   case 9138:
+   case 9140:
+   case 9142:
+   case 9144:
+   case 9146:
+   case 9148:
+   case 9150:
+   case 9152:
+   case 9154:
+   case 9156:
+   case 9158:
+   case 9160:
+   case 9162:
+   case 9164:
+   case 9166:
+   case 9168:
+   case 9170:
+   case 9172:
+   case 9174:
+   case 9176:
+   case 9178:
+   case 9180:
+   case 9182:
+   case 9184:
+   case 9186:
+   case 9188:
+   case 9190:
+   case 9192:
+   case 9194:
+   case 9196:
+   case 9198:
+   case 9200:
+   case 9202:
+   case 9204:
+   case 9206:
+   case 9208:
+   case 9210:
+   case 9212:
+   case 9214:
+   case 9216:
+   case 9218:
+   case 9220:
+   case 9222:
+   case 9224:
+   case 9226:
+   case 9228:
+   case 9230:
+   case 9232:
+   case 9234:
+   case 9236:
+   case 9238:
+   case 9240:
+   case 9242:
+   case 9244:
+   case 9246:
+   case 9248:
+   case 9250:
+   case 9252:
+   case 9254:
+   case 9256:
+   case 9258:
+   case 9260:
+   case 9262:
+   case 9264:
+   case 9266:
+   case 9268:
+   case 9270:
+   case 9272:
+   case 9274:
+   case 9276:
+   case 9278:
+   case 9280:
+   case 9282:
+   case 9284:
+   case 9286:
+   case 9288:
+   case 9290:
+   case 9292:
+   case 9294:
+   case 9296:
+   case 9298:
+   case 9300:
+   case 9302:
+   case 9304:
+   case 9306:
+   case 9308:
+   case 9310:
+   case 9312:
+   case 9314:
+   case 9316:
+   case 9318:
+   case 9320:
+   case 9322:
+   case 9324:
+   case 9326:
+   case 9328:
+   case 9330:
+   case 9332:
+   case 9334:
+   case 9336:
+   case 9338:
+   case 9340:
+   case 9342:
+   case 9344:
+   case 9346:
+   case 9348:
+   case 9350:
+   case 9352:
+   case 9354:
+   case 9356:
+   case 9358:
+   case 9360:
+   case 9362:
+   case 9364:
+   case 9366:
+   case 9368:
+   case 9370:
+   case 9372:
+   case 9374:
+   case 9376:
+   case 9378:
+   case 9380:
+   case 9382:
+   case 9384:
+   case 9386:
+   case 9388:
+   case 9390:
+   case 9392:
+   case 9394:
+   case 9396:
+   case 9398:
+   case 9400:
+   case 9402:
+   case 9404:
+   case 9406:
+   case 9408:
+   case 9410:
+   case 9412:
+   case 9414:
+   case 9416:
+   case 9418:
+   case 9420:
+   case 9422:
+   case 9424:
+   case 9426:
+   case 9428:
+   case 9430:
+   case 9432:
+   case 9434:
+   case 9436:
+   case 9438:
+   case 9440:
+   case 9442:
+   case 9444:
+   case 9446:
+   case 9448:
+   case 9450:
+   case 9452:
+   case 9454:
+   case 9456:
+   case 9458:
+   case 9460:
+   case 9462:
+   case 9464:
+   case 9466:
+   case 9468:
+   case 9470:
+   case 9472:
+   case 9474:
+   case 9476:
+   case 9478:
+   case 9480:
+   case 9482:
+   case 9484:
+   case 9486:
+   case 9488:
+   case 9490:
+   case 9492:
+   case 9494:
+   case 9496:
+   case 9498:
+   case 9500:
+   case 9502:
+   case 9504:
+   case 9506:
+   case 9508:
+   case 9510:
+   case 9512:
+   case 9514:
+   case 9516:
+   case 9518:
+   case 9520:
+   case 9522:
+   case 9524:
+   case 9526:
+   case 9528:
+   case 9530:
+   case 9532:
+   case 9534:
+   case 9536:
+   case 9538:
+   case 9540:
+   case 9542:
+   case 9544:
+   case 9546:
+   case 9548:
+   case 9550:
+   case 9552:
+   case 9554:
+   case 9556:
+   case 9558:
+   case 9560:
+   case 9562:
+   case 9564:
+   case 9566:
+   case 9568:
+   case 9570:
+   case 9572:
+   case 9574:
+   case 9576:
+   case 9578:
+   case 9580:
+   case 9582:
+   case 9584:
+   case 9586:
+   case 9588:
+   case 9590:
+   case 9592:
+   case 9594:
+   case 9596:
+   case 9598:
+   case 9600:
+   case 9602:
+   case 9604:
+   case 9606:
+   case 9608:
+   case 9610:
+   case 9612:
+   case 9614:
+   case 9616:
+   case 9618:
+   case 9620:
+   case 9622:
+   case 9624:
+   case 9626:
+   case 9628:
+   case 9630:
+   case 9632:
+   case 9634:
+   case 9636:
+   case 9638:
+   case 9640:
+   case 9642:
+   case 9644:
+   case 9646:
+   case 9648:
+   case 9650:
+   case 9652:
+   case 9654:
+   case 9656:
+   case 9658:
+   case 9660:
+   case 9662:
+   case 9664:
+   case 9666:
+   case 9668:
+   case 9670:
+   case 9672:
+   case 9674:
+   case 9676:
+   case 9678:
+   case 9680:
+   case 9682:
+   case 9684:
+   case 9686:
+   case 9688:
+   case 9690:
+   case 9692:
+   case 9694:
+   case 9696:
+   case 9698:
+   case 9700:
+   case 9702:
+   case 9704:
+   case 9706:
+   case 9708:
+   case 9710:
+   case 9712:
+   case 9714:
+   case 9716:
+   case 9718:
+   case 9720:
+   case 9722:
+   case 9724:
+   case 9726:
+   case 9728:
+   case 9730:
+   case 9732:
+   case 9734:
+   case 9736:
+   case 9738:
+   case 9740:
+   case 9742:
+   case 9744:
+   case 9746:
+   case 9748:
+   case 9750:
+   case 9752:
+   case 9754:
+   case 9756:
+   case 9758:
+   case 9760:
+   case 9762:
+   case 9764:
+   case 9766:
+   case 9768:
+   case 9770:
+   case 9772:
+   case 9774:
+   case 9776:
+   case 9778:
+   case 9780:
+   case 9782:
+   case 9784:
+   case 9786:
+   case 9788:
+   case 9790:
+   case 9792:
+   case 9794:
+   case 9796:
+   case 9798:
+   case 9800:
+   case 9802:
+   case 9804:
+   case 9806:
+   case 9808:
+   case 9810:
+   case 9812:
+   case 9814:
+   case 9816:
+   case 9818:
+   case 9820:
+   case 9822:
+   case 9824:
+   case 9826:
+   case 9828:
+   case 9830:
+   case 9832:
+   case 9834:
+   case 9836:
+   case 9838:
+   case 9840:
+   case 9842:
+   case 9844:
+   case 9846:
+   case 9848:
+   case 9850:
+   case 9852:
+   case 9854:
+   case 9856:
+   case 9858:
+   case 9860:
+   case 9862:
+   case 9864:
+   case 9866:
+   case 9868:
+   case 9870:
+   case 9872:
+   case 9874:
+   case 9876:
+   case 9878:
+   case 9880:
+   case 9882:
+   case 9884:
+   case 9886:
+   case 9888:
+   case 9890:
+   case 9892:
+   case 9894:
+   case 9896:
+   case 9898:
+   case 9900:
+   case 9902:
+   case 9904:
+   case 9906:
+   case 9908:
+   case 9910:
+   case 9912:
+   case 9914:
+   case 9916:
+   case 9918:
+   case 9920:
+   case 9922:
+   case 9924:
+   case 9926:
+   case 9928:
+   case 9930:
+   case 9932:
+   case 9934:
+   case 9936:
+   case 9938:
+   case 9940:
+   case 9942:
+   case 9944:
+   case 9946:
+   case 9948:
+   case 9950:
+   case 9952:
+   case 9954:
+   case 9956:
+   case 9958:
+   case 9960:
+   case 9962:
+   case 9964:
+   case 9966:
+   case 9968:
+   case 9970:
+   case 9972:
+   case 9974:
+   case 9976:
+   case 9978:
+   case 9980:
+   case 9982:
+   case 9984:
+   case 9986:
+   case 9988:
+   case 9990:
+   case 9992:
+   case 9994:
+   case 9996:
+   case 9998:
+   case 1e4:
+   case 10002:
+   case 10004:
+   case 10006:
+   case 10008:
+   case 10010:
+   case 10012:
+   case 10014:
+   case 10016:
+   case 10018:
+   case 10020:
+   case 10022:
+   case 10024:
+   case 10026:
+   case 10028:
+   case 10030:
+   case 10032:
+   case 10034:
+   case 10036:
+   case 10038:
+   case 10040:
+   case 10042:
+   case 10044:
+   case 10046:
+   case 10048:
+   case 10050:
+   case 10052:
+   case 10054:
+   case 10056:
+   case 10058:
+   case 10060:
+   case 10062:
+   case 10064:
+   case 10066:
+   case 10068:
+   case 10070:
+   case 10072:
+   case 10074:
+   case 10076:
+   case 10078:
+   case 10080:
+   case 10082:
+   case 10084:
+   case 10086:
+   case 10088:
+   case 10090:
+   case 10092:
+   case 10094:
+   case 10096:
+   case 10098:
+   case 10100:
+   case 10102:
+   case 10104:
+   case 10106:
+   case 10108:
+   case 10110:
+   case 10112:
+   case 10114:
+   case 10116:
+   case 10118:
+   case 10120:
+   case 10122:
+   case 10124:
+   case 10126:
+   case 10128:
+   case 10130:
+   case 10132:
+   case 10134:
+   case 10136:
+   case 10138:
+   case 10140:
+   case 10142:
+   case 10144:
+   case 10146:
+   case 10148:
+   case 10150:
+   case 10152:
+   case 10154:
+   case 10156:
+   case 10158:
+   case 10160:
+   case 10162:
+   case 10164:
+   case 10166:
+   case 10168:
+   case 10170:
+   case 10172:
+   case 10174:
+   case 10176:
+   case 10178:
+   case 10180:
+   case 10182:
+   case 10184:
+   case 10186:
+   case 10188:
+   case 10190:
+   case 10192:
+   case 10194:
+   case 10196:
+   case 10198:
+   case 10200:
+   case 10202:
+   case 10204:
+   case 10206:
+   case 10208:
+   case 10210:
+   case 10212:
+   case 10214:
+   case 10216:
+   case 10218:
+   case 10220:
+   case 10222:
+   case 10224:
+   case 10226:
+   case 10228:
+   case 10230:
+   case 10232:
+   case 10234:
+   case 10236:
+   case 10238:
+   case 10240:
+   case 10242:
+   case 10244:
+   case 10246:
+   case 10248:
+   case 10250:
+   case 10252:
+   case 10254:
+   case 10256:
+   case 10258:
+   case 10260:
+   case 10262:
+   case 10264:
+   case 10266:
+   case 10268:
+   case 10270:
+   case 10272:
+   case 10274:
+   case 10276:
+   case 10278:
+   case 10280:
+   case 10282:
+   case 10284:
+   case 10286:
+   case 10288:
+   case 10290:
+   case 10292:
+   case 10294:
+   case 10296:
+   case 10298:
+   case 10300:
+   case 10302:
+   case 10304:
+   case 10306:
+   case 10308:
+   case 10310:
+   case 10312:
+   case 10314:
+   case 10316:
+   case 10318:
+   case 10320:
+   case 10322:
+   case 10324:
+   case 10326:
+   case 10328:
+   case 10330:
+   case 10332:
+   case 10334:
+   case 10336:
+   case 10338:
+   case 10340:
+   case 10342:
+   case 10344:
+   case 10346:
+   case 10348:
+   case 10350:
+   case 10352:
+   case 10354:
+   case 10356:
+   case 10358:
+   case 10360:
+   case 10362:
+   case 10364:
+   case 10366:
+   case 10368:
+   case 10370:
+   case 10372:
+   case 10374:
+   case 10376:
+   case 10378:
+   case 10380:
+   case 10382:
+   case 10384:
+   case 10386:
+   case 10388:
+   case 10390:
+   case 10392:
+   case 10394:
+   case 10396:
+   case 10398:
+   case 10400:
+   case 10402:
+   case 10404:
+   case 10406:
+   case 10408:
+   case 10410:
+   case 10412:
+   case 10414:
+   case 10416:
+   case 10418:
+   case 10420:
+   case 10422:
+   case 10424:
+   case 10426:
+   case 10428:
+   case 10430:
+   case 10432:
+   case 10434:
+   case 10436:
+   case 10438:
+   case 10440:
+   case 10442:
+   case 10444:
+   case 10446:
+   case 10448:
+   case 10450:
+   case 10452:
+   case 10454:
+   case 10456:
+   case 10458:
+   case 10460:
+   case 10462:
+   case 10464:
+   case 10466:
+   case 10468:
+   case 10470:
+   case 10472:
+   case 10474:
+   case 10476:
+   case 10478:
+   case 10480:
+   case 10482:
+   case 10484:
+   case 10486:
+   case 10488:
+   case 10490:
+   case 10492:
+   case 10494:
+   case 10496:
+   case 10498:
+   case 10500:
+   case 10502:
+   case 10504:
+   case 10506:
+   case 10508:
+   case 10510:
+   case 10512:
+   case 10514:
+   case 10516:
+   case 10518:
+   case 10520:
+   case 10522:
+   case 10524:
+   case 10526:
+   case 10528:
+   case 10530:
+   case 10532:
+   case 10534:
+   case 10536:
+   case 10538:
+   case 10540:
+   case 10542:
+   case 10544:
+   case 10546:
+   case 10548:
+   case 10550:
+   case 10552:
+   case 10554:
+   case 10556:
+   case 10558:
+   case 10560:
+   case 10562:
+   case 10564:
+   case 10566:
+   case 10568:
+   case 10570:
+   case 10572:
+   case 10574:
+   case 10576:
+   case 10578:
+   case 10580:
+   case 10582:
+   case 10584:
+   case 10586:
+   case 10588:
+   case 10590:
+   case 10592:
+   case 10594:
+   case 10596:
+   case 10598:
+   case 10600:
+   case 10602:
+   case 10604:
+   case 10606:
+   case 10608:
+   case 10610:
+   case 10612:
+   case 10614:
+   case 10616:
+   case 10618:
+   case 10620:
+   case 10622:
+   case 10624:
+   case 10626:
+   case 10628:
+   case 10630:
+   case 10632:
+   case 10634:
+   case 10636:
+   case 10638:
+   case 10640:
+   case 10642:
+   case 10644:
+   case 10646:
+   case 10648:
+   case 10650:
+   case 10652:
+   case 10654:
+   case 10656:
+   case 10658:
+   case 10660:
+   case 10662:
+   case 10664:
+   case 10666:
+   case 10668:
+   case 10670:
+   case 10672:
+   case 10674:
+   case 10676:
+   case 10678:
+   case 10680:
+   case 10682:
+   case 10684:
+   case 10686:
+   case 10688:
+   case 10690:
+   case 10692:
+   case 10694:
+   case 10696:
+   case 10698:
+   case 10700:
+   case 10702:
+   case 10704:
+   case 10706:
+   case 10708:
+   case 10710:
+   case 10712:
+   case 10714:
+   case 10716:
+   case 10718:
+   case 10720:
+   case 10722:
+   case 10724:
+   case 10726:
+   case 10728:
+   case 10730:
+   case 10732:
+   case 10734:
+   case 10736:
+   case 10738:
+   case 10740:
+   case 10742:
+   case 10744:
+   case 10746:
+   case 10748:
+   case 10750:
+   case 10752:
+   case 10754:
+   case 10756:
+   case 10758:
+   case 10760:
+   case 10762:
+   case 10764:
+   case 10766:
+   case 10768:
+   case 10770:
+   case 10772:
+   case 10774:
+   case 10776:
+   case 10778:
+   case 10780:
+   case 10782:
+   case 10784:
+   case 10786:
+   case 10788:
+   case 10790:
+   case 10792:
+   case 10794:
+   case 10796:
+   case 10798:
+   case 10800:
+   case 10802:
+   case 10804:
+   case 10806:
+   case 10808:
+   case 10810:
+   case 10812:
+   case 10814:
+   case 10816:
+   case 10818:
+   case 10820:
+   case 10822:
+   case 10824:
+   case 10826:
+   case 10828:
+   case 10830:
+   case 10832:
+   case 10834:
+   case 10836:
+   case 10838:
+   case 10840:
+   case 10842:
+   case 10844:
+   case 10846:
+   case 10848:
+   case 10850:
+   case 10852:
+   case 10854:
+   case 10856:
+   case 10858:
+   case 10860:
+   case 10862:
+   case 10864:
+   case 10866:
+   case 10868:
+   case 10870:
+   case 10872:
+   case 10874:
+   case 10876:
+   case 10878:
+   case 10880:
+   case 10882:
+   case 10884:
+   case 10886:
+   case 10888:
+   case 10890:
+   case 10892:
+   case 10894:
+   case 10896:
+   case 10898:
+   case 10900:
+   case 10902:
+   case 10904:
+   case 10906:
+   case 10908:
+   case 10910:
+   case 10912:
+   case 10914:
+   case 10916:
+   case 10918:
+   case 10920:
+   case 10922:
+   case 10924:
+   case 10926:
+   case 10928:
+   case 10930:
+   case 10932:
+   case 10934:
+   case 10936:
+   case 10938:
+   case 10940:
+   case 10942:
+   case 10944:
+   case 10946:
+   case 10948:
+   case 10950:
+   case 10952:
+   case 10954:
+   case 10956:
+   case 10958:
+   case 10960:
+   case 10962:
+   case 10964:
+   case 10966:
+   case 10968:
+   case 10970:
+   case 10972:
+   case 10974:
+   case 10976:
+   case 10978:
+   case 10980:
+   case 10982:
+   case 10984:
+   case 10986:
+   case 10988:
+   case 10990:
+   case 10992:
+   case 10994:
+   case 10996:
+   case 10998:
+   case 11e3:
+   case 11002:
+   case 11004:
+   case 11006:
+   case 11008:
+   case 11010:
+   case 11012:
+   case 11014:
+   case 11016:
+   case 11018:
+   case 11020:
+   case 11022:
+   case 11024:
+   case 11026:
+   case 11028:
+   case 11030:
+   case 11032:
+   case 11034:
+   case 11036:
+   case 11038:
+   case 11040:
+   case 11042:
+   case 11044:
+   case 11046:
+   case 11048:
+   case 11050:
+   case 11052:
+   case 11054:
+   case 11056:
+   case 11058:
+   case 11060:
+   case 11062:
+   case 11064:
+   case 11066:
+   case 11068:
+   case 11070:
+   case 11072:
+   case 11074:
+   case 11076:
+   case 11078:
+   case 11080:
+   case 11082:
+   case 11084:
+   case 11086:
+   case 11088:
+   case 11090:
+   case 11092:
+   case 11094:
+   case 11096:
+   case 11098:
+   case 11100:
+   case 11102:
+   case 11104:
+   case 11106:
+   case 11108:
+   case 11110:
+   case 11112:
+   case 11114:
+   case 11116:
+   case 11118:
+   case 11120:
+   case 11122:
+   case 11124:
+   case 11126:
+   case 11128:
+   case 11130:
+   case 11132:
+   case 11134:
+   case 11136:
+   case 11138:
+   case 11140:
+   case 11142:
+   case 11144:
+   case 11146:
+   case 11148:
+   case 11150:
+   case 11152:
+   case 11154:
+   case 11156:
+   case 11158:
+   case 11160:
+   case 11162:
+   case 11164:
+   case 11166:
+   case 11168:
+   case 11170:
+   case 11172:
+   case 11174:
+   case 11176:
+   case 11178:
+   case 11180:
+   case 11182:
+   case 11184:
+   case 11186:
+   case 11188:
+   case 11190:
+   case 11192:
+   case 11194:
+   case 11196:
+   case 11198:
+   case 11200:
+   case 11202:
+   case 11204:
+   case 11206:
+   case 11208:
+   case 11210:
+   case 11212:
+   case 11214:
+   case 11216:
+   case 11218:
+   case 11220:
+   case 11222:
+   case 11224:
+   case 11226:
+   case 11228:
+   case 11230:
+   case 11232:
+   case 11234:
+   case 11236:
+   case 11238:
+   case 11240:
+   case 11242:
+   case 11244:
+   case 11246:
+   case 11248:
+   case 11250:
+   case 11252:
+   case 11254:
+   case 11256:
+   case 11258:
+   case 11260:
+   case 11262:
+   case 11264:
+   case 11266:
+   case 11268:
+   case 11270:
+   case 11272:
+   case 11274:
+   case 11276:
+   case 11278:
+   case 11280:
+   case 11282:
+   case 11284:
+   case 11286:
+   case 11288:
+   case 11290:
+   case 11292:
+   case 11294:
+   case 11296:
+   case 11298:
+   case 11300:
+   case 11302:
+   case 11304:
+   case 11306:
+   case 11308:
+   case 11310:
+   case 11312:
+   case 11314:
+   case 11316:
+   case 11318:
+   case 11320:
+   case 11322:
+   case 11324:
+   case 11326:
+   case 11328:
+   case 11330:
+   case 11332:
+   case 11334:
+   case 11336:
+   case 11338:
+   case 11340:
+   case 11342:
+   case 11344:
+   case 11346:
+   case 11348:
+   case 11350:
+   case 11352:
+   case 11354:
+   case 11356:
+   case 11358:
+   case 11360:
+   case 11362:
+   case 11364:
+   case 11366:
+   case 11368:
+   case 11370:
+   case 11372:
+   case 11374:
+   case 11376:
+   case 11378:
+   case 11380:
+   case 11382:
+   case 11384:
+   case 11386:
+   case 11388:
+   case 11390:
+   case 11392:
+   case 11394:
+   case 11396:
+   case 11398:
+   case 11400:
+   case 11402:
+   case 11404:
+   case 11406:
+   case 11408:
+   case 11410:
+   case 11412:
+   case 11414:
+   case 11416:
+   case 11418:
+   case 11420:
+   case 11422:
+   case 11424:
+   case 11426:
+   case 11428:
+   case 11430:
+   case 11432:
+   case 11434:
+   case 11436:
+   case 11438:
+   case 11440:
+   case 11442:
+   case 11444:
+   case 11446:
+   case 11448:
+   case 11450:
+   case 11452:
+   case 11454:
+   case 11456:
+   case 11458:
+   case 11460:
+   case 11462:
+   case 11464:
+   case 11466:
+   case 11468:
+   case 11470:
+   case 11472:
+   case 11474:
+   case 11476:
+   case 11478:
+   case 11480:
+   case 11482:
+   case 11484:
+   case 11486:
+   case 11488:
+   case 11490:
+   case 11492:
+   case 11494:
+   case 11496:
+   case 11498:
+   case 11500:
+   case 11502:
+   case 11504:
+   case 11506:
+   case 11508:
+   case 11510:
+   case 11512:
+   case 11514:
+   case 11516:
+   case 11518:
+   case 11520:
+   case 11522:
+   case 11524:
+   case 11526:
+   case 11528:
+   case 11530:
+   case 11532:
+   case 11534:
+   case 11536:
+   case 11538:
+   case 11540:
+   case 11542:
+   case 11544:
+   case 11546:
+   case 11548:
+   case 11550:
+   case 11552:
+   case 11554:
+   case 11556:
+   case 11558:
+   case 11560:
+   case 11562:
+   case 11564:
+   case 11566:
+   case 11568:
+   case 11570:
+   case 11572:
+   case 11574:
+   case 11576:
+   case 11578:
+   case 11580:
+   case 11582:
+   case 11584:
+   case 11586:
+   case 11588:
+   case 11590:
+   case 11592:
+   case 11594:
+   case 11596:
+   case 11598:
+   case 11600:
+   case 11602:
+   case 11604:
+   case 11606:
+   case 11608:
+   case 11610:
+   case 11612:
+   case 11614:
+   case 11616:
+   case 11618:
+   case 11620:
+   case 11622:
+   case 11624:
+   case 11626:
+   case 11628:
+   case 11630:
+   case 11632:
+   case 11634:
+   case 11636:
+   case 11638:
+   case 11640:
+   case 11642:
+   case 11644:
+   case 11646:
+   case 11648:
+   case 11650:
+   case 11652:
+   case 11654:
+   case 11656:
+   case 11658:
+   case 11660:
+   case 11662:
+   case 11664:
+   case 11666:
+   case 11668:
+   case 11670:
+   case 11672:
+   case 11674:
+   case 11676:
+   case 11678:
+   case 11680:
+   case 11682:
+   case 11684:
+   case 11686:
+   case 11688:
+   case 11690:
+   case 11692:
+   case 11694:
+   case 11696:
+   case 11698:
+   case 11700:
+   case 11702:
+   case 11704:
+   case 11706:
+   case 11708:
+   case 11710:
+   case 11712:
+   case 11714:
+   case 11716:
+   case 11718:
+   case 11720:
+   case 11722:
+   case 11724:
+   case 11726:
+   case 11728:
+   case 11730:
+   case 11732:
+   case 11734:
+   case 11736:
+   case 11738:
+   case 11740:
+   case 11742:
+   case 11744:
+   case 11746:
+   case 11748:
+   case 11750:
+   case 11752:
+   case 11754:
+   case 11756:
+   case 11758:
+   case 11760:
+   case 11762:
+   case 11764:
+   case 11766:
+   case 11768:
+   case 11770:
+   case 11772:
+   case 11774:
+   case 11776:
+   case 11778:
+   case 11780:
+   case 11782:
+   case 11784:
+   case 11786:
+   case 11788:
+   case 11790:
+   case 11792:
+   case 11794:
+   case 11796:
+   case 11798:
+   case 11800:
+   case 11802:
+   case 11804:
+   case 11806:
+   case 11808:
+   case 11810:
+   case 11812:
+   case 11814:
+   case 11816:
+   case 11818:
+   case 11820:
+   case 11822:
+   case 11824:
+   case 11826:
+   case 11828:
+   case 11830:
+   case 11832:
+   case 11834:
+   case 11836:
+   case 11838:
+   case 11840:
+   case 11842:
+   case 11844:
+   case 11846:
+   case 11848:
+   case 11850:
+   case 11852:
+   case 11854:
+   case 11856:
+   case 11858:
+   case 11860:
+   case 11862:
+   case 11864:
+   case 11866:
+   case 11868:
+   case 11870:
+   case 11872:
+   case 11874:
+   case 11876:
+   case 11878:
+   case 11880:
+   case 11882:
+   case 11884:
+   case 11886:
+   case 11888:
+   case 11890:
+   case 11892:
+   case 11894:
+   case 11896:
+   case 11898:
+   case 11900:
+   case 11902:
+   case 11904:
+   case 11906:
+   case 11908:
+   case 11910:
+   case 11912:
+   case 11914:
+   case 11916:
+   case 11918:
+   case 11920:
+   case 11922:
+   case 11924:
+   case 11926:
+   case 11928:
+   case 11930:
+   case 11932:
+   case 11934:
+   case 11936:
+   case 11938:
+   case 11940:
+   case 11942:
+   case 11944:
+   case 11946:
+   case 11948:
+   case 11950:
+   case 11952:
+   case 11954:
+   case 11956:
+   case 11958:
+   case 11960:
+   case 11962:
+   case 11964:
+   case 11966:
+   case 11968:
+   case 11970:
+   case 11972:
+   case 11974:
+   case 11976:
+   case 11978:
+   case 11980:
+   case 11982:
+   case 11984:
+   case 11986:
+   case 11988:
+   case 11990:
+   case 11992:
+   case 11994:
+   case 11996:
+   case 11998:
+   case 12e3:
+   case 12002:
+   case 12004:
+   case 12006:
+   case 12008:
+   case 12010:
+   case 12012:
+   case 12014:
+   case 12016:
+   case 12018:
+   case 12020:
+   case 12022:
+   case 12024:
+   case 12026:
+   case 12028:
+   case 12030:
+   case 12032:
+   case 12034:
+   case 12036:
+   case 12038:
+   case 12040:
+   case 12042:
+   case 12044:
+   case 12046:
+   case 12048:
+   case 12050:
+   case 12052:
+   case 12054:
+   case 12056:
+   case 12058:
+   case 12060:
+   case 12062:
+   case 12064:
+   case 12066:
+   case 12068:
+   case 12070:
+   case 12072:
+   case 12074:
+   case 12076:
+   case 12078:
+   case 12080:
+   case 12082:
+   case 12084:
+   case 12086:
+   case 12088:
+   case 12090:
+   case 12092:
+   case 12094:
+   case 12096:
+   case 12098:
+   case 12100:
+   case 12102:
+   case 12104:
+   case 12106:
+   case 12108:
+   case 12110:
+   case 12112:
+   case 12114:
+   case 12116:
+   case 12118:
+   case 12120:
+   case 12122:
+   case 12124:
+   case 12126:
+   case 12128:
+   case 12130:
+   case 12132:
+   case 12134:
+   case 12136:
+   case 12138:
+   case 12140:
+   case 12142:
+   case 12144:
+   case 12146:
+   case 12148:
+   case 12150:
+   case 12152:
+   case 12154:
+   case 12156:
+   case 12158:
+   case 12160:
+   case 12162:
+   case 12164:
+   case 12166:
+   case 12168:
+   case 12170:
+   case 12172:
+   case 12174:
+   case 12176:
+   case 12178:
+   case 12180:
+   case 12182:
+   case 12184:
+   case 12186:
+   case 12188:
+   case 12190:
+   case 12192:
+   case 12194:
+   case 12196:
+   case 12198:
+   case 12200:
+   case 12202:
+   case 12204:
+   case 12206:
+   case 12208:
+   case 12210:
+   case 12212:
+   case 12214:
+   case 12216:
+   case 12218:
+   case 12220:
+   case 12222:
+   case 12224:
+   case 12226:
+   case 12228:
+   case 12230:
+   case 12232:
+   case 12234:
+   case 12236:
+   case 12238:
+   case 12240:
+   case 12242:
+   case 12244:
+   case 12246:
+   case 12248:
+   case 12250:
+   case 12252:
+   case 12254:
+   case 12256:
+   case 12258:
+   case 12260:
+   case 12262:
+   case 12264:
+   case 12266:
+   case 12268:
+   case 12270:
+   case 12272:
+   case 12274:
+   case 12276:
+   case 12278:
+   case 12280:
+   case 12282:
+   case 12284:
+   case 12286:
+   case 12288:
+   case 12290:
+   case 12292:
+   case 12294:
+   case 12296:
+   case 12298:
+   case 12300:
+   case 12302:
+   case 12304:
+   case 12306:
+   case 12308:
+   case 12310:
+   case 12312:
+   case 12314:
+   case 12316:
+   case 12318:
+   case 12320:
+   case 12322:
+   case 12324:
+   case 12326:
+   case 12328:
+   case 12330:
+   case 12332:
+   case 12334:
+   case 12336:
+   case 12338:
+   case 12340:
+   case 12342:
+   case 12344:
+   case 12346:
+   case 12348:
+   case 12350:
+   case 12352:
+   case 12354:
+   case 12356:
+   case 12358:
+   case 12360:
+   case 12362:
+   case 12364:
+   case 12366:
+   case 12368:
+   case 12370:
+   case 12372:
+   case 12374:
+   case 12376:
+   case 12378:
+   case 12380:
+   case 12382:
+   case 12384:
+   case 12386:
+   case 12388:
+   case 12390:
+   case 12392:
+   case 12394:
+   case 12396:
+   case 12398:
+   case 12400:
+   case 12402:
+   case 12404:
+   case 12406:
+   case 12408:
+   case 12410:
+   case 12412:
+   case 12414:
+   case 12416:
+   case 12418:
+   case 12420:
+   case 12422:
+   case 12424:
+   case 12426:
+   case 12428:
+   case 12430:
+   case 12432:
+   case 12434:
+   case 12436:
+   case 12438:
+   case 12440:
+   case 12442:
+   case 12444:
+   case 12446:
+   case 12448:
+   case 12450:
+   case 12452:
+   case 12454:
+   case 12456:
+   case 12458:
+   case 12460:
+   case 12462:
+   case 12464:
+   case 12466:
+   case 12468:
+   case 12470:
+   case 12472:
+   case 12474:
+   case 12476:
+   case 12478:
+   case 12480:
+   case 12482:
+   case 12484:
+   case 12486:
+   case 12488:
+   case 12490:
+   case 12492:
+   case 12494:
+   case 12496:
+   case 12498:
+   case 12500:
+   case 12502:
+   case 12504:
+   case 12506:
+   case 12508:
+   case 12510:
+   case 12512:
+   case 12514:
+   case 12516:
+   case 12518:
+   case 12520:
+   case 12522:
+   case 12524:
+   case 12526:
+   case 12528:
+   case 12530:
+   case 12532:
+   case 12534:
+   case 12536:
+   case 12538:
+   case 12540:
+   case 12542:
+   case 12544:
+   case 12546:
+   case 12548:
+   case 12550:
+   case 12552:
+   case 12554:
+   case 12556:
+   case 12558:
+   case 12560:
+   case 12562:
+   case 12564:
+   case 12566:
+   case 12568:
+   case 12570:
+   case 12572:
+   case 12574:
+   case 12576:
+   case 12578:
+   case 12580:
+   case 12582:
+   case 12584:
+   case 12586:
+   case 12588:
+   case 12590:
+   case 12592:
+   case 12594:
+   case 12596:
+   case 12598:
+   case 12600:
+   case 12602:
+   case 12604:
+   case 12606:
+   case 12608:
+   case 12610:
+   case 12612:
+   case 12614:
+   case 12616:
+   case 12618:
+   case 12620:
+   case 12622:
+   case 12624:
+   case 12626:
+   case 12628:
+   case 12630:
+   case 12632:
+   case 12634:
+   case 12636:
+   case 12638:
+   case 12640:
+   case 12642:
+   case 12644:
+   case 12646:
+   case 12648:
+   case 12650:
+   case 12652:
+   case 12654:
+   case 12656:
+   case 12658:
+   case 12660:
+   case 12662:
+   case 12664:
+   case 12666:
+   case 12668:
+   case 12670:
+   case 12672:
+   case 12674:
+   case 12676:
+   case 12678:
+   case 12680:
+   case 12682:
+   case 12684:
+   case 12686:
+   case 12688:
+   case 12690:
+   case 12692:
+   case 12694:
+   case 12696:
+   case 12698:
+   case 12700:
+   case 12702:
+   case 12704:
+   case 12706:
+   case 12708:
+   case 12710:
+   case 12712:
+   case 12714:
+   case 12716:
+   case 12718:
+   case 12720:
+   case 12722:
+   case 12724:
+   case 12726:
+   case 12728:
+   case 12730:
+   case 12732:
+   case 12734:
+   case 12736:
+   case 12738:
+   case 12740:
+   case 12742:
+   case 12744:
+   case 12746:
+   case 12748:
+   case 12750:
+   case 12752:
+   case 12754:
+   case 12756:
+   case 12758:
+   case 12760:
+   case 12762:
+   case 12764:
+   case 12766:
+   case 12768:
+   case 12770:
+   case 12772:
+   case 12774:
+   case 12776:
+   case 12778:
+   case 12780:
+   case 12782:
+   case 12784:
+   case 12786:
+   case 12788:
+   case 12790:
+   case 12792:
+   case 12794:
+   case 12796:
+   case 12798:
+   case 12800:
+   case 12802:
+   case 12804:
+   case 12806:
+   case 12808:
+   case 12810:
+   case 12812:
+   case 12814:
+   case 12816:
+   case 12818:
+   case 12820:
+   case 12822:
+   case 12824:
+   case 12826:
+   case 12828:
+   case 12830:
+   case 12832:
+   case 12834:
+   case 12836:
+   case 12838:
+   case 12840:
+   case 12842:
+   case 12844:
+   case 12846:
+   case 12848:
+   case 12850:
+   case 12852:
+   case 12854:
+   case 12856:
+   case 12858:
+   case 12860:
+   case 12862:
+   case 12864:
+   case 12866:
+   case 12868:
+   case 12870:
+   case 12872:
+   case 12874:
+   case 12876:
+   case 12878:
+   case 12880:
+   case 12882:
+   case 12884:
+   case 12886:
+   case 12888:
+   case 12890:
+   case 12892:
+   case 12894:
+   case 12896:
+   case 12898:
+   case 12900:
+   case 12902:
+   case 12904:
+   case 12906:
+   case 12908:
+   case 12910:
+   case 12912:
+   case 12914:
+   case 12916:
+   case 12918:
+   case 12920:
+   case 12922:
+   case 12924:
+   case 12926:
+   case 12928:
+   case 12930:
+   case 12932:
+   case 12934:
+   case 12936:
+   case 12938:
+   case 12940:
+   case 12942:
+   case 12944:
+   case 12946:
+   case 12948:
+   case 12950:
+   case 12952:
+   case 12954:
+   case 12956:
+   case 12958:
+   case 12960:
+   case 12962:
+   case 12964:
+   case 12966:
+   case 12968:
+   case 12970:
+   case 12972:
+   case 12974:
+   case 12976:
+   case 12978:
+   case 12980:
+   case 12982:
+   case 12984:
+   case 12986:
+   case 12988:
+   case 12990:
+   case 12992:
+   case 12994:
+   case 12996:
+   case 12998:
+   case 13e3:
+   case 13002:
+   case 13004:
+   case 13006:
+   case 13008:
+   case 13010:
+   case 13012:
+   case 13014:
+   case 13016:
+   case 13018:
+   case 13020:
+   case 13022:
+   case 13024:
+   case 13026:
+   case 13028:
+   case 13030:
+   case 13032:
+   case 13034:
+   case 13036:
+   case 13038:
+   case 13040:
+   case 13042:
+   case 13044:
+   case 13046:
+   case 13048:
+   case 13050:
+   case 13052:
+   case 13054:
+   case 13056:
+   case 13058:
+   case 13060:
+   case 13062:
+   case 13064:
+   case 13066:
+   case 13068:
+   case 13070:
+   case 13072:
+   case 13074:
+   case 13076:
+   case 13078:
+   case 13080:
+   case 13082:
+   case 13084:
+   case 13086:
+   case 13088:
+   case 13090:
+   case 13092:
+   case 13094:
+   case 13096:
+   case 13098:
+   case 13100:
+   case 13102:
+   case 13104:
+   case 13106:
+   case 13108:
+   case 13110:
+   case 13112:
+   case 13114:
+   case 13116:
+   case 13118:
+   case 13120:
+   case 13122:
+   case 13124:
+   case 13126:
+   case 13128:
+   case 13130:
+   case 13132:
+   case 13134:
+   case 13136:
+   case 13138:
+   case 13140:
+   case 13142:
+   case 13144:
+   case 13146:
+   case 13148:
+   case 13150:
+   case 13152:
+   case 13154:
+   case 13156:
+   case 13158:
+   case 13160:
+   case 13162:
+   case 13164:
+   case 13166:
+   case 13168:
+   case 13170:
+   case 13172:
+   case 13174:
+   case 13176:
+   case 13178:
+   case 13180:
+   case 13182:
+   case 13184:
+   case 13186:
+   case 13188:
+   case 13190:
+   case 13192:
+   case 13194:
+   case 13196:
+   case 13198:
+   case 13200:
+   case 13202:
+   case 13204:
+   case 13206:
+   case 13208:
+   case 13210:
+   case 13212:
+   case 13214:
+   case 13216:
+   case 13218:
+   case 13220:
+   case 13222:
+   case 13224:
+   case 13226:
+   case 13228:
+   case 13230:
+   case 13232:
+   case 13234:
+   case 13236:
+   case 13238:
+   case 13240:
+   case 13242:
+   case 13244:
+   case 13246:
+   case 13248:
+   case 13250:
+   case 13252:
+   case 13254:
+   case 13256:
+   case 13258:
+   case 13260:
+   case 13262:
+   case 13264:
+   case 13266:
+   case 13268:
+   case 13270:
+   case 13272:
+   case 13274:
+   case 13276:
+   case 13278:
+   case 13280:
+   case 13282:
+   case 13284:
+   case 13286:
+   case 13288:
+   case 13290:
+   case 13292:
+   case 13294:
+   case 13296:
+   case 13298:
+   case 13300:
+   case 13302:
+   case 13304:
+   case 13306:
+   case 13308:
+   case 13310:
+   case 13312:
+   case 13314:
+   case 13316:
+   case 13318:
+   case 13320:
+   case 13322:
+   case 13324:
+   case 13326:
+   case 13328:
+   case 13330:
+   case 13332:
+   case 13334:
+   case 13336:
+   case 13338:
+   case 13340:
+   case 13342:
+   case 13344:
+   case 13346:
+   case 13348:
+   case 13350:
+   case 13352:
+   case 13354:
+   case 13356:
+   case 13358:
+   case 13360:
+   case 13362:
+   case 13364:
+   case 13366:
+   case 13368:
+   case 13370:
+   case 13372:
+   case 13374:
+   case 13376:
+   case 13378:
+   case 13380:
+   case 13382:
+   case 13384:
+   case 13386:
+   case 13388:
+   case 13390:
+   case 13392:
+   case 13394:
+   case 13396:
+   case 13398:
+   case 13400:
+   case 13402:
+   case 13404:
+   case 13406:
+   case 13408:
+   case 13410:
+   case 13412:
+   case 13414:
+   case 13416:
+   case 13418:
+   case 13420:
+   case 13422:
+   case 13424:
+   case 13426:
+   case 13428:
+   case 13430:
+   case 13432:
+   case 13434:
+   case 13436:
+   case 13438:
+   case 13440:
+   case 13442:
+   case 13444:
+   case 13446:
+   case 13448:
+   case 13450:
+   case 13452:
+   case 13454:
+   case 13456:
+   case 13458:
+   case 13460:
+   case 13462:
+   case 13464:
+   case 13466:
+   case 13468:
+   case 13470:
+   case 13472:
+   case 13474:
+   case 13476:
+   case 13478:
+   case 13480:
+   case 13482:
+   case 13484:
+   case 13486:
+   case 13488:
+   case 13490:
+   case 13492:
+   case 13494:
+   case 13496:
+   case 13498:
+   case 13500:
+   case 13502:
+   case 13504:
+   case 13506:
+   case 13508:
+   case 13510:
+   case 13512:
+   case 13514:
+   case 13516:
+   case 13518:
+   case 13520:
+   case 13522:
+   case 13524:
+   case 13526:
+   case 13528:
+   case 13530:
+   case 13532:
+   case 13534:
+   case 13536:
+   case 13538:
+   case 13540:
+   case 13542:
+   case 13544:
+   case 13546:
+   case 13548:
+   case 13550:
+   case 13552:
+   case 13554:
+   case 13556:
+   case 13558:
+   case 13560:
+   case 13562:
+   case 13564:
+   case 13566:
+   case 13568:
+   case 13570:
+   case 13572:
+   case 13574:
+   case 13576:
+   case 13578:
+   case 13580:
+   case 13582:
+   case 13584:
+   case 13586:
+   case 13588:
+   case 13590:
+   case 13592:
+   case 13594:
+   case 13596:
+   case 13598:
+   case 13600:
+   case 13602:
+   case 13604:
+   case 13606:
+   case 13608:
+   case 13610:
+   case 13612:
+   case 13614:
+   case 13616:
+   case 13618:
+   case 13620:
+   case 13622:
+   case 13624:
+   case 13626:
+   case 13628:
+   case 13630:
+   case 13632:
+   case 13634:
+   case 13636:
+   case 13638:
+   case 13640:
+   case 13642:
+   case 13644:
+   case 13646:
+   case 13648:
+   case 13650:
+   case 13652:
+   case 13654:
+   case 13656:
+   case 13658:
+   case 13660:
+   case 13662:
+   case 13664:
+   case 13666:
+   case 13668:
+   case 13670:
+   case 13672:
+   case 13674:
+   case 13676:
+   case 13678:
+   case 13680:
+   case 13682:
+   case 13684:
+   case 13686:
+   case 13688:
+   case 13690:
+   case 13692:
+   case 13694:
+   case 13696:
+   case 13698:
+   case 13700:
+   case 13702:
+   case 13704:
+   case 13706:
+   case 13708:
+   case 13710:
+   case 13712:
+   case 13714:
+   case 13716:
+   case 13718:
+   case 13720:
+   case 13722:
+   case 13724:
+   case 13726:
+   case 13728:
+   case 13730:
+   case 13732:
+   case 13734:
+   case 13736:
+   case 13738:
+   case 13740:
+   case 13742:
+   case 13744:
+   case 13746:
+   case 13748:
+   case 13750:
+   case 13752:
+   case 13754:
+   case 13756:
+   case 13758:
+   case 13760:
+   case 13762:
+   case 13764:
+   case 13766:
+   case 13768:
+   case 13770:
+   case 13772:
+   case 13774:
+   case 13776:
+   case 13778:
+   case 13780:
+   case 13782:
+   case 13784:
+   case 13786:
+   case 13788:
+   case 13790:
+   case 13792:
+   case 13794:
+   case 13796:
+   case 13798:
+   case 13800:
+   case 13802:
+   case 13804:
+   case 13806:
+   case 13808:
+   case 13810:
+   case 13812:
+   case 13814:
+   case 13816:
+   case 13818:
+   case 13820:
+   case 13822:
+   case 13824:
+   case 13826:
+   case 13828:
+   case 13830:
+   case 13832:
+   case 13834:
+   case 13836:
+   case 13838:
+   case 13840:
+   case 13842:
+   case 13844:
+   case 13846:
+   case 13848:
+   case 13850:
+   case 13852:
+   case 13854:
+   case 13856:
+   case 13858:
+   case 13860:
+   case 13862:
+   case 13864:
+   case 13866:
+   case 13868:
+   case 13870:
+   case 13872:
+   case 13874:
+   case 13876:
+   case 13878:
+   case 13880:
+   case 13882:
+   case 13884:
+   case 13886:
+   case 13888:
+   case 13890:
+   case 13892:
+   case 13894:
+   case 13896:
+   case 13898:
+   case 13900:
+   case 13902:
+   case 13904:
+   case 13906:
+   case 13908:
+   case 13910:
+   case 13912:
+   case 13914:
+   case 13916:
+   case 13918:
+   case 13920:
+   case 13922:
+   case 13924:
+   case 13926:
+   case 13928:
+   case 13930:
+   case 13932:
+   case 13934:
+   case 13936:
+   case 13938:
+   case 13940:
+   case 13942:
+   case 13944:
+   case 13946:
+   case 13948:
+   case 13950:
+   case 13952:
+   case 13954:
+   case 13956:
+   case 13958:
+   case 13960:
+   case 13962:
+   case 13964:
+   case 13966:
+   case 13968:
+   case 13970:
+   case 13972:
+   case 13974:
+   case 13976:
+   case 13978:
+   case 13980:
+   case 13982:
+   case 13984:
+   case 13986:
+   case 13988:
+   case 13990:
+   case 13992:
+   case 13994:
+   case 13996:
+   case 13998:
+   case 14e3:
+   case 14002:
+   case 14004:
+   case 14006:
+   case 14008:
+   case 14010:
+   case 14012:
+   case 14014:
+   case 14016:
+   case 14018:
+   case 14020:
+   case 14022:
+   case 14024:
+   case 14026:
+   case 14028:
+   case 14030:
+   case 14032:
+   case 14034:
+   case 14036:
+   case 14038:
+   case 14040:
+   case 14042:
+   case 14044:
+   case 14046:
+   case 14048:
+   case 14050:
+   case 14052:
+   case 14054:
+   case 14056:
+   case 14058:
+   case 14060:
+   case 14062:
+   case 14064:
+   case 14066:
+   case 14068:
+   case 14070:
+   case 14072:
+   case 14074:
+   case 14076:
+   case 14078:
+   case 14080:
+   case 14082:
+   case 14084:
+   case 14086:
+   case 14088:
+   case 14090:
+   case 14092:
+   case 14094:
+   case 14096:
+   case 14098:
+   case 14100:
+   case 14102:
+   case 14104:
+   case 14106:
+   case 14108:
+   case 14110:
+   case 14112:
+   case 14114:
+   case 14116:
+   case 14118:
+   case 14120:
+   case 14122:
+   case 14124:
+   case 14126:
+   case 14128:
+   case 14130:
+   case 14132:
+   case 14134:
+   case 14136:
+   case 14138:
+   case 14140:
+   case 14142:
+   case 14144:
+   case 14146:
+   case 14148:
+   case 14150:
+   case 14152:
+   case 14154:
+   case 14156:
+   case 14158:
+   case 14160:
+   case 14162:
+   case 14164:
+   case 14166:
+   case 14168:
+   case 14170:
+   case 14172:
+   case 14174:
+   case 14176:
+   case 14178:
+   case 14180:
+   case 14182:
+   case 14184:
+   case 14186:
+   case 14188:
+   case 14190:
+   case 14192:
+   case 14194:
+   case 14196:
+   case 14198:
+   case 14200:
+   case 14202:
+   case 14204:
+   case 14206:
+   case 14208:
+   case 14210:
+   case 14212:
+   case 14214:
+   case 14216:
+   case 14218:
+   case 14220:
+   case 14222:
+   case 14224:
+   case 14226:
+   case 14228:
+   case 14230:
+   case 14232:
+   case 14234:
+   case 14236:
+   case 14238:
+   case 14240:
+   case 14242:
+   case 14244:
+   case 14246:
+   case 14248:
+   case 14250:
+   case 14252:
+   case 14254:
+   case 14256:
+   case 14258:
+   case 14260:
+   case 14262:
+   case 14264:
+   case 14266:
+   case 14268:
+   case 14270:
+   case 14272:
+   case 14274:
+   case 14276:
+   case 14278:
+   case 14280:
+   case 14282:
+   case 14284:
+   case 14286:
+   case 14288:
+   case 14290:
+   case 14292:
+   case 14294:
+   case 14296:
+   case 14298:
+   case 14300:
+   case 14302:
+   case 14304:
+   case 14306:
+   case 14308:
+   case 14310:
+   case 14312:
+   case 14314:
+   case 14316:
+   case 14318:
+   case 14320:
+   case 14322:
+   case 14324:
+   case 14326:
+   case 14328:
+   case 14330:
+   case 14332:
+   case 14334:
+   case 14336:
+   case 14338:
+   case 14340:
+   case 14342:
+   case 14344:
+   case 14346:
+   case 14348:
+   case 14350:
+   case 14352:
+   case 14354:
+   case 14356:
+   case 14358:
+   case 14360:
+   case 14362:
+   case 14364:
+   case 14366:
+   case 14368:
+   case 14370:
+   case 14372:
+   case 14374:
+   case 14376:
+   case 14378:
+   case 14380:
+   case 14382:
+   case 14384:
+   case 14386:
+   case 14388:
+   case 14390:
+   case 14392:
+   case 14394:
+   case 14396:
+   case 14398:
+   case 14400:
+   case 14402:
+   case 14404:
+   case 14406:
+   case 14408:
+   case 14410:
+   case 14412:
+   case 14414:
+   case 14416:
+   case 14418:
+   case 14420:
+   case 14422:
+   case 14424:
+   case 14426:
+   case 14428:
+   case 14430:
+   case 14432:
+   case 14434:
+   case 14436:
+   case 14438:
+   case 14440:
+   case 14442:
+   case 14444:
+   case 14446:
+   case 14448:
+   case 14450:
+   case 14452:
+   case 14454:
+   case 14456:
+   case 14458:
+   case 14460:
+   case 14462:
+   case 14464:
+   case 14466:
+   case 14468:
+   case 14470:
+   case 14472:
+   case 14474:
+   case 14476:
+   case 14478:
+   case 14480:
+   case 14482:
+   case 14484:
+   case 14486:
+   case 14488:
+   case 14490:
+   case 14492:
+   case 14494:
+   case 14496:
+   case 14498:
+   case 14500:
+   case 14502:
+   case 14504:
+   case 14506:
+   case 14508:
+   case 14510:
+   case 14512:
+   case 14514:
+   case 14516:
+   case 14518:
+   case 14520:
+   case 14522:
+   case 14524:
+   case 14526:
+   case 14528:
+   case 14530:
+   case 14532:
+   case 14534:
+   case 14536:
+   case 14538:
+   case 14540:
+   case 14542:
+   case 14544:
+   case 14546:
+   case 14548:
+   case 14550:
+   case 14552:
+   case 14554:
+   case 14556:
+   case 14558:
+   case 14560:
+   case 14562:
+   case 14564:
+   case 14566:
+   case 14568:
+   case 14570:
+   case 14572:
+   case 14574:
+   case 14576:
+   case 14578:
+   case 14580:
+   case 14582:
+   case 14584:
+   case 14586:
+   case 14588:
+   case 14590:
+   case 14592:
+   case 14594:
+   case 14596:
+   case 14598:
+   case 14600:
+   case 14602:
+   case 14604:
+   case 14606:
+   case 14608:
+   case 14610:
+   case 14612:
+   case 14614:
+   case 14616:
+   case 14618:
+   case 14620:
+   case 14622:
+   case 14624:
+   case 14626:
+   case 14628:
+   case 14630:
+   case 14632:
+   case 14634:
+   case 14636:
+   case 14638:
+   case 14640:
+   case 14642:
+   case 14644:
+   case 14646:
+   case 14648:
+   case 14650:
+   case 14652:
+   case 14654:
+   case 14656:
+   case 14658:
+   case 14660:
+   case 14662:
+   case 14664:
+   case 14666:
+   case 14668:
+   case 14670:
+   case 14672:
+   case 14674:
+   case 14676:
+   case 14678:
+   case 14680:
+   case 14682:
+   case 14684:
+   case 14686:
+   case 14688:
+   case 14690:
+   case 14692:
+   case 14694:
+   case 14696:
+   case 14698:
+   case 14700:
+   case 14702:
+   case 14704:
+   case 14706:
+   case 14708:
+   case 14710:
+   case 14712:
+   case 14714:
+   case 14716:
+   case 14718:
+   case 14720:
+   case 14722:
+   case 14724:
+   case 14726:
+   case 14728:
+   case 14730:
+   case 14732:
+   case 14734:
+   case 14736:
+   case 14738:
+   case 14740:
+   case 14742:
+   case 14744:
+   case 14746:
+   case 14748:
+   case 14750:
+   case 14752:
+   case 14754:
+   case 14756:
+   case 14758:
+   case 14760:
+   case 14762:
+   case 14764:
+   case 14766:
+   case 14768:
+   case 14770:
+   case 14772:
+   case 14774:
+   case 14776:
+   case 14778:
+   case 14780:
+   case 14782:
+   case 14784:
+   case 14786:
+   case 14788:
+   case 14790:
+   case 14792:
+   case 14794:
+   case 14796:
+   case 14798:
+   case 14800:
+   case 14802:
+   case 14804:
+   case 14806:
+   case 14808:
+   case 14810:
+   case 14812:
+   case 14814:
+   case 14816:
+   case 14818:
+   case 14820:
+   case 14822:
+   case 14824:
+   case 14826:
+   case 14828:
+   case 14830:
+   case 14832:
+   case 14834:
+   case 14836:
+   case 14838:
+   case 14840:
+   case 14842:
+   case 14844:
+   case 14846:
+   case 14848:
+   case 14850:
+   case 14852:
+   case 14854:
+   case 14856:
+   case 14858:
+   case 14860:
+   case 14862:
+   case 14864:
+   case 14866:
+   case 14868:
+   case 14870:
+   case 14872:
+   case 14874:
+   case 14876:
+   case 14878:
+   case 14880:
+   case 14882:
+   case 14884:
+   case 14886:
+   case 14888:
+   case 14890:
+   case 14892:
+   case 14894:
+   case 14896:
+   case 14898:
+   case 14900:
+   case 14902:
+   case 14904:
+   case 14906:
+   case 14908:
+   case 14910:
+   case 14912:
+   case 14914:
+   case 14916:
+   case 14918:
+   case 14920:
+   case 14922:
+   case 14924:
+   case 14926:
+   case 14928:
+   case 14930:
+   case 14932:
+   case 14934:
+   case 14936:
+   case 14938:
+   case 14940:
+   case 14942:
+   case 14944:
+   case 14946:
+   case 14948:
+   case 14950:
+   case 14952:
+   case 14954:
+   case 14956:
+   case 14958:
+   case 14960:
+   case 14962:
+   case 14964:
+   case 14966:
+   case 14968:
+   case 14970:
+   case 14972:
+   case 14974:
+   case 14976:
+   case 14978:
+   case 14980:
+   case 14982:
+   case 14984:
+   case 14986:
+   case 14988:
+   case 14990:
+   case 14992:
+   case 14994:
+   case 14996:
+   case 14998:
+   case 15e3:
+   case 15002:
+   case 15004:
+   case 15006:
+   case 15008:
+   case 15010:
+   case 15012:
+   case 15014:
+   case 15016:
+   case 15018:
+   case 15020:
+   case 15022:
+   case 15024:
+   case 15026:
+   case 15028:
+   case 15030:
+   case 15032:
+   case 15034:
+   case 15036:
+   case 15038:
+   case 15040:
+   case 15042:
+   case 15044:
+   case 15046:
+   case 15048:
+   case 15050:
+   case 15052:
+   case 15054:
+   case 15056:
+   case 15058:
+   case 15060:
+   case 15062:
+   case 15064:
+   case 15066:
+   case 15068:
+   case 15070:
+   case 15072:
+   case 15074:
+   case 15076:
+   case 15078:
+   case 15080:
+   case 15082:
+   case 15084:
+   case 15086:
+   case 15088:
+   case 15090:
+   case 15092:
+   case 15094:
+   case 15096:
+   case 15098:
+   case 15100:
+   case 15102:
+   case 15104:
+   case 15106:
+   case 15108:
+   case 15110:
+   case 15112:
+   case 15114:
+   case 15116:
+   case 15118:
+   case 15120:
+   case 15122:
+   case 15124:
+   case 15126:
+   case 15128:
+   case 15130:
+   case 15132:
+   case 15134:
+   case 15136:
+   case 15138:
+   case 15140:
+   case 15142:
+   case 15144:
+   case 15146:
+   case 15148:
+   case 15150:
+   case 15152:
+   case 15154:
+   case 15156:
+   case 15158:
+   case 15160:
+   case 15162:
+   case 15164:
+   case 15166:
+   case 15168:
+   case 15170:
+   case 15172:
+   case 15174:
+   case 15176:
+   case 15178:
+   case 15180:
+   case 15182:
+   case 15184:
+   case 15186:
+   case 15188:
+   case 15190:
+   case 15192:
+   case 15194:
+   case 15196:
+   case 15198:
+   case 15200:
+   case 15202:
+   case 15204:
+   case 15206:
+   case 15208:
+   case 15210:
+   case 15212:
+   case 15214:
+   case 15216:
+   case 15218:
+   case 15220:
+   case 15222:
+   case 15224:
+   case 15226:
+   case 15228:
+   case 15230:
+   case 15232:
+   case 15234:
+   case 15236:
+   case 15238:
+   case 15240:
+   case 15242:
+   case 15244:
+   case 15246:
+   case 15248:
+   case 15250:
+   case 15252:
+   case 15254:
+   case 15256:
+   case 15258:
+   case 15260:
+   case 15262:
+   case 15264:
+   case 15266:
+   case 15268:
+   case 15270:
+   case 15272:
+   case 15274:
+   case 15276:
+   case 15278:
+   case 15280:
+   case 15282:
+   case 15284:
+   case 15286:
+   case 15288:
+   case 15290:
+   case 15292:
+   case 15294:
+   case 15296:
+   case 15298:
+   case 15300:
+   case 15302:
+   case 15304:
+   case 15306:
+   case 15308:
+   case 15310:
+   case 15312:
+   case 15314:
+   case 15316:
+   case 15318:
+   case 15320:
+   case 15322:
+   case 15324:
+   case 15326:
+   case 15328:
+   case 15330:
+   case 15332:
+   case 15334:
+   case 15336:
+   case 15338:
+   case 15340:
+   case 15342:
+   case 15344:
+   case 15346:
+   case 15348:
+   case 15350:
+   case 15352:
+   case 15354:
+   case 15356:
+   case 15358:
+   case 15360:
+   case 15362:
+   case 15364:
+   case 15366:
+   case 15368:
+   case 15370:
+   case 15372:
+   case 15374:
+   case 15376:
+   case 15378:
+   case 15380:
+   case 15382:
+   case 15384:
+   case 15386:
+   case 15388:
+   case 15390:
+   case 15392:
+   case 15394:
+   case 15396:
+   case 15398:
+   case 15400:
+   case 15402:
+   case 15404:
+   case 15406:
+   case 15408:
+   case 15410:
+   case 15412:
+   case 15414:
+   case 15416:
+   case 15418:
+   case 15420:
+   case 15422:
+   case 15424:
+   case 15426:
+   case 15428:
+   case 15430:
+   case 15432:
+   case 15434:
+   case 15436:
+   case 15438:
+   case 15440:
+   case 15442:
+   case 15444:
+   case 15446:
+   case 15448:
+   case 15450:
+   case 15452:
+   case 15454:
+   case 15456:
+   case 15458:
+   case 15460:
+   case 15462:
+   case 15464:
+   case 15466:
+   case 15468:
+   case 15470:
+   case 15472:
+   case 15474:
+   case 15476:
+   case 15478:
+   case 15480:
+   case 15482:
+   case 15484:
+   case 15486:
+   case 15488:
+   case 15490:
+   case 15492:
+   case 15494:
+   case 15496:
+   case 15498:
+   case 15500:
+   case 15502:
+   case 15504:
+   case 15506:
+   case 15508:
+   case 15510:
+   case 15512:
+   case 15514:
+   case 15516:
+   case 15518:
+   case 15520:
+   case 15522:
+   case 15524:
+   case 15526:
+   case 15528:
+   case 15530:
+   case 15532:
+   case 15534:
+   case 15536:
+   case 15538:
+   case 15540:
+   case 15542:
+   case 15544:
+   case 15546:
+   case 15548:
+   case 15550:
+   case 15552:
+   case 15554:
+   case 15556:
+   case 15558:
+   case 15560:
+   case 15562:
+   case 15564:
+   case 15566:
+   case 15568:
+   case 15570:
+   case 15572:
+   case 15574:
+   case 15576:
+   case 15578:
+   case 15580:
+   case 15582:
+   case 15584:
+   case 15586:
+   case 15588:
+   case 15590:
+   case 15592:
+   case 15594:
+   case 15596:
+   case 15598:
+   case 15600:
+   case 15602:
+   case 15604:
+   case 15606:
+   case 15608:
+   case 15610:
+   case 15612:
+   case 15614:
+   case 15616:
+   case 15618:
+   case 15620:
+   case 15622:
+   case 15624:
+   case 15626:
+   case 15628:
+   case 15630:
+   case 15632:
+   case 15634:
+   case 15636:
+   case 15638:
+   case 15640:
+   case 15642:
+   case 15644:
+   case 15646:
+   case 15648:
+   case 15650:
+   case 15652:
+   case 15654:
+   case 15656:
+   case 15658:
+   case 15660:
+   case 15662:
+   case 15664:
+   case 15666:
+   case 15668:
+   case 15670:
+   case 15672:
+   case 15674:
+   case 15676:
+   case 15678:
+   case 15680:
+   case 15682:
+   case 15684:
+   case 15686:
+   case 15688:
+   case 15690:
+   case 15692:
+   case 15694:
+   case 15696:
+   case 15698:
+   case 15700:
+   case 15702:
+   case 15704:
+   case 15706:
+   case 15708:
+   case 15710:
+   case 15712:
+   case 15714:
+   case 15716:
+   case 15718:
+   case 15720:
+   case 15722:
+   case 15724:
+   case 15726:
+   case 15728:
+   case 15730:
+   case 15732:
+   case 15734:
+   case 15736:
+   case 15738:
+   case 15740:
+   case 15742:
+   case 15744:
+   case 15746:
+   case 15748:
+   case 15750:
+   case 15752:
+   case 15754:
+   case 15756:
+   case 15758:
+   case 15760:
+   case 15762:
+   case 15764:
+   case 15766:
+   case 15768:
+   case 15770:
+   case 15772:
+   case 15774:
+   case 15776:
+   case 15778:
+   case 15780:
+   case 15782:
+   case 15784:
+   case 15786:
+   case 15788:
+   case 15790:
+   case 15792:
+   case 15794:
+   case 15796:
+   case 15798:
+   case 15800:
+   case 15802:
+   case 15804:
+   case 15806:
+   case 15808:
+   case 15810:
+   case 15812:
+   case 15814:
+   case 15816:
+   case 15818:
+   case 15820:
+   case 15822:
+   case 15824:
+   case 15826:
+   case 15828:
+   case 15830:
+   case 15832:
+   case 15834:
+   case 15836:
+   case 15838:
+   case 15840:
+   case 15842:
+   case 15844:
+   case 15846:
+   case 15848:
+   case 15850:
+   case 15852:
+   case 15854:
+   case 15856:
+   case 15858:
+   case 15860:
+   case 15862:
+   case 15864:
+   case 15866:
+   case 15868:
+   case 15870:
+   case 15872:
+   case 15874:
+   case 15876:
+   case 15878:
+   case 15880:
+   case 15882:
+   case 15884:
+   case 15886:
+   case 15888:
+   case 15890:
+   case 15892:
+   case 15894:
+   case 15896:
+   case 15898:
+   case 15900:
+   case 15902:
+   case 15904:
+   case 15906:
+   case 15908:
+   case 15910:
+   case 15912:
+   case 15914:
+   case 15916:
+   case 15918:
+   case 15920:
+   case 15922:
+   case 15924:
+   case 15926:
+   case 15928:
+   case 15930:
+   case 15932:
+   case 15934:
+   case 15936:
+   case 15938:
+   case 15940:
+   case 15942:
+   case 15944:
+   case 15946:
+   case 15948:
+   case 15950:
+   case 15952:
+   case 15954:
+   case 15956:
+   case 15958:
+   case 15960:
+   case 15962:
+   case 15964:
+   case 15966:
+   case 15968:
+   case 15970:
+   case 15972:
+   case 15974:
+   case 15976:
+   case 15978:
+   case 15980:
+   case 15982:
+   case 15984:
+   case 15986:
+   case 15988:
+   case 15990:
+   case 15992:
+   case 15994:
+   case 15996:
+   case 15998:
+   case 16e3:
+   case 16002:
+   case 16004:
+   case 16006:
+   case 16008:
+   case 16010:
+   case 16012:
+   case 16014:
+   case 16016:
+   case 16018:
+   case 16020:
+   case 16022:
+   case 16024:
+   case 16026:
+   case 16028:
+   case 16030:
+   case 16032:
+   case 16034:
+   case 16036:
+   case 16038:
+   case 16040:
+   case 16042:
+   case 16044:
+   case 16046:
+   case 16048:
+   case 16050:
+   case 16052:
+   case 16054:
+   case 16056:
+   case 16058:
+   case 16060:
+   case 16062:
+   case 16064:
+   case 16066:
+   case 16068:
+   case 16070:
+   case 16072:
+   case 16074:
+   case 16076:
+   case 16078:
+   case 16080:
+   case 16082:
+   case 16084:
+   case 16086:
+   case 16088:
+   case 16090:
+   case 16092:
+   case 16094:
+   case 16096:
+   case 16098:
+   case 16100:
+   case 16102:
+   case 16104:
+   case 16106:
+   case 16108:
+   case 16110:
+   case 16112:
+   case 16114:
+   case 16116:
+   case 16118:
+   case 16120:
+   case 16122:
+   case 16124:
+   case 16126:
+   case 16128:
+   case 16130:
+   case 16132:
+   case 16134:
+   case 16136:
+   case 16138:
+   case 16140:
+   case 16142:
+   case 16144:
+   case 16146:
+   case 16148:
+   case 16150:
+   case 16152:
+   case 16154:
+   case 16156:
+   case 16158:
+   case 16160:
+   case 16162:
+   case 16164:
+   case 16166:
+   case 16168:
+   case 16170:
+   case 16172:
+   case 16174:
+   case 16176:
+   case 16178:
+   case 16180:
+   case 16182:
+   case 16184:
+   case 16186:
+   case 16188:
+   case 16190:
+   case 16192:
+   case 16194:
+   case 16196:
+   case 16198:
+   case 16200:
+   case 16202:
+   case 16204:
+   case 16206:
+   case 16208:
+   case 16210:
+   case 16212:
+   case 16214:
+   case 16216:
+   case 16218:
+   case 16220:
+   case 16222:
+   case 16224:
+   case 16226:
+   case 16228:
+   case 16230:
+   case 16232:
+   case 16234:
+   case 16236:
+   case 16238:
+   case 16240:
+   case 16242:
+   case 16244:
+   case 16246:
+   case 16248:
+   case 16250:
+   case 16252:
+   case 16254:
+   case 16256:
+   case 16258:
+   case 16260:
+   case 16262:
+   case 16264:
+   case 16266:
+   case 16268:
+   case 16270:
+   case 16272:
+   case 16274:
+   case 16276:
+   case 16278:
+   case 16280:
+   case 16282:
+   case 16284:
+   case 16286:
+   case 16288:
+   case 16290:
+   case 16292:
+   case 16294:
+   case 16296:
+   case 16298:
+   case 16300:
+   case 16302:
+   case 16304:
+   case 16306:
+   case 16308:
+   case 16310:
+   case 16312:
+   case 16314:
+   case 16316:
+   case 16318:
+   case 16320:
+   case 16322:
+   case 16324:
+   case 16326:
+   case 16328:
+   case 16330:
+   case 16332:
+   case 16334:
+   case 16336:
+   case 16338:
+   case 16340:
+   case 16342:
+   case 16344:
+   case 16346:
+   case 16348:
+   case 16350:
+   case 16352:
+   case 16354:
+   case 16356:
+   case 16358:
+   case 16360:
+   case 16362:
+   case 16364:
+   case 16366:
+   case 16368:
+   case 16370:
+   case 16372:
+   case 16374:
+   case 16376:
+   case 16378:
+   case 16380:
+   case 16382:
+   case 16384:
+   case 16386:
+   case 16388:
+   case 16390:
+   case 16392:
+   case 16394:
+   case 16396:
+   case 16398:
+   case 16400:
+   case 16402:
+   case 16404:
+   case 16406:
+   case 16408:
+   case 16410:
+   case 16412:
+   case 16414:
+   case 16416:
+   case 16418:
+   case 16420:
+   case 16422:
+   case 16424:
+   case 16426:
+   case 16428:
+   case 16430:
+   case 16432:
+   case 16434:
+   case 16436:
+   case 16438:
+   case 16440:
+   case 16442:
+   case 16444:
+   case 16446:
+   case 16448:
+   case 16450:
+   case 16452:
+   case 16454:
+   case 16456:
+   case 16458:
+   case 16460:
+   case 16462:
+   case 16464:
+   case 16466:
+   case 16468:
+   case 16470:
+   case 16472:
+   case 16474:
+   case 16476:
+   case 16478:
+   case 16480:
+   case 16482:
+   case 16484:
+   case 16486:
+   case 16488:
+   case 16490:
+   case 16492:
+   case 16494:
+   case 16496:
+   case 16498:
+   case 16500:
+   case 16502:
+   case 16504:
+   case 16506:
+   case 16508:
+   case 16510:
+   case 16512:
+   case 16514:
+   case 16516:
+   case 16518:
+   case 16520:
+   case 16522:
+   case 16524:
+   case 16526:
+   case 16528:
+   case 16530:
+   case 16532:
+   case 16534:
+   case 16536:
+   case 16538:
+   case 16540:
+   case 16542:
+   case 16544:
+   case 16546:
+   case 16548:
+   case 16550:
+   case 16552:
+   case 16554:
+   case 16556:
+   case 16558:
+   case 16560:
+   case 16562:
+   case 16564:
+   case 16566:
+   case 16568:
+   case 16570:
+   case 16572:
+   case 16574:
+   case 16576:
+   case 16578:
+   case 16580:
+   case 16582:
+   case 16584:
+   case 16586:
+   case 16588:
+   case 16590:
+   case 16592:
+   case 16594:
+   case 16596:
+   case 16598:
+   case 16600:
+   case 16602:
+   case 16604:
+   case 16606:
+   case 16608:
+   case 16610:
+   case 16612:
+   case 16614:
+   case 16616:
+   case 16618:
+   case 16620:
+   case 16622:
+   case 16624:
+   case 16626:
+   case 16628:
+   case 16630:
+   case 16632:
+   case 16634:
+   case 16636:
+   case 16638:
+   case 16640:
+   case 16642:
+   case 16644:
+   case 16646:
+   case 16648:
+   case 16650:
+   case 16652:
+   case 16654:
+   case 16656:
+   case 16658:
+   case 16660:
+   case 16662:
+   case 16664:
+   case 16666:
+   case 16668:
+   case 16670:
+   case 16672:
+   case 16674:
+   case 16676:
+   case 16678:
+   case 16680:
+   case 16682:
+   case 16684:
+   case 16686:
+   case 16688:
+   case 16690:
+   case 16692:
+   case 16694:
+   case 16696:
+   case 16698:
+   case 16700:
+   case 16702:
+   case 16704:
+   case 16706:
+   case 16708:
+   case 16710:
+   case 16712:
+   case 16714:
+   case 16716:
+   case 16718:
+   case 16720:
+   case 16722:
+   case 16724:
+   case 16726:
+   case 16728:
+   case 16730:
+   case 16732:
+   case 16734:
+   case 16736:
+   case 16738:
+   case 16740:
+   case 16742:
+   case 16744:
+   case 16746:
+   case 16748:
+   case 16750:
+   case 16752:
+   case 16754:
+   case 16756:
+   case 16758:
+   case 16760:
+   case 16762:
+   case 16764:
+   case 16766:
+   case 16768:
+   case 16770:
+   case 16772:
+   case 16774:
+   case 16776:
+   case 16778:
+   case 16780:
+   case 16782:
+   case 16784:
+   case 16786:
+   case 16788:
+   case 16790:
+   case 16792:
+   case 16794:
+   case 16796:
+   case 16798:
+   case 16800:
+   case 16802:
+   case 16804:
+   case 16806:
+   case 16808:
+   case 16810:
+   case 16812:
+   case 16814:
+   case 16816:
+   case 16818:
+   case 16820:
+   case 16822:
+   case 16824:
+   case 16826:
+   case 16828:
+   case 16830:
+   case 16832:
+   case 16834:
+   case 16836:
+   case 16838:
+   case 16840:
+   case 16842:
+   case 16844:
+   case 16846:
+   case 16848:
+   case 16850:
+   case 16852:
+   case 16854:
+   case 16856:
+   case 16858:
+   case 16860:
+   case 16862:
+   case 16864:
+   case 16866:
+   case 16868:
+   case 16870:
+   case 16872:
+   case 16874:
+   case 16876:
+   case 16878:
+   case 16880:
+   case 16882:
+   case 16884:
+   case 16886:
+   case 16888:
+   case 16890:
+   case 16892:
+   case 16894:
+   case 16896:
+   case 16898:
+   case 16900:
+   case 16902:
+   case 16904:
+   case 16906:
+   case 16908:
+   case 16910:
+   case 16912:
+   case 16914:
+   case 16916:
+   case 16918:
+   case 16920:
+   case 16922:
+   case 16924:
+   case 16926:
+   case 16928:
+   case 16930:
+   case 16932:
+   case 16934:
+   case 16936:
+   case 16938:
+   case 16940:
+   case 16942:
+   case 16944:
+   case 16946:
+   case 16948:
+   case 16950:
+   case 16952:
+   case 16954:
+   case 16956:
+   case 16958:
+   case 16960:
+   case 16962:
+   case 16964:
+   case 16966:
+   case 16968:
+   case 16970:
+   case 16972:
+   case 16974:
+   case 16976:
+   case 16978:
+   case 16980:
+   case 16982:
+   case 16984:
+   case 16986:
+   case 16988:
+   case 16990:
+   case 16992:
+   case 16994:
+   case 16996:
+   case 16998:
+   case 17e3:
+   case 17002:
+   case 17004:
+   case 17006:
+   case 17008:
+   case 17010:
+   case 17012:
+   case 17014:
+   case 17016:
+   case 17018:
+   case 17020:
+   case 17022:
+   case 17024:
+   case 17026:
+   case 17028:
+   case 17030:
+   case 17032:
+   case 17034:
+   case 17036:
+   case 17038:
+   case 17040:
+   case 17042:
+   case 17044:
+   case 17046:
+   case 17048:
+   case 17050:
+   case 17052:
+   case 17054:
+   case 17056:
+   case 17058:
+   case 17060:
+   case 17062:
+   case 17064:
+   case 17066:
+   case 17068:
+   case 17070:
+   case 17072:
+   case 17074:
+   case 17076:
+   case 17078:
+   case 17080:
+   case 17082:
+   case 17084:
+   case 17086:
+   case 17088:
+   case 17090:
+   case 17092:
+   case 17094:
+   case 17096:
+   case 17098:
+   case 17100:
+   case 17102:
+   case 17104:
+   case 17106:
+   case 17108:
+   case 17110:
+   case 17112:
+   case 17114:
+   case 17116:
+   case 17118:
+   case 17120:
+   case 17122:
+   case 17124:
+   case 17126:
+   case 17128:
+   case 17130:
+   case 17132:
+   case 17134:
+   case 17136:
+   case 17138:
+   case 17140:
+   case 17142:
+   case 17144:
+   case 17146:
+   case 17148:
+   case 17150:
+   case 17152:
+   case 17154:
+   case 17156:
+   case 17158:
+   case 17160:
+   case 17162:
+   case 17164:
+   case 17166:
+   case 17168:
+   case 17170:
+   case 17172:
+   case 17174:
+   case 17176:
+   case 17178:
+   case 17180:
+   case 17182:
+   case 17184:
+   case 17186:
+   case 17188:
+   case 17190:
+   case 17192:
+   case 17194:
+   case 17196:
+   case 17198:
+   case 17200:
+   case 17202:
+   case 17204:
+   case 17206:
+   case 17208:
+   case 17210:
+   case 17212:
+   case 17214:
+   case 17216:
+   case 17218:
+   case 17220:
+   case 17222:
+   case 17224:
+   case 17226:
+   case 17228:
+   case 17230:
+   case 17232:
+   case 17234:
+   case 17236:
+   case 17238:
+   case 17240:
+   case 17242:
+   case 17244:
+   case 17246:
+   case 17248:
+   case 17250:
+   case 17252:
+   case 17254:
+   case 17256:
+   case 17258:
+   case 17260:
+   case 17262:
+   case 17264:
+   case 17266:
+   case 17268:
+   case 17270:
+   case 17272:
+   case 17274:
+   case 17276:
+   case 17278:
+   case 17280:
+   case 17282:
+   case 17284:
+   case 17286:
+   case 17288:
+   case 17290:
+   case 17292:
+   case 17294:
+   case 17296:
+   case 17298:
+   case 17300:
+   case 17302:
+   case 17304:
+   case 17306:
+   case 17308:
+   case 17310:
+   case 17312:
+   case 17314:
+   case 17316:
+   case 17318:
+   case 17320:
+   case 17322:
+   case 17324:
+   case 17326:
+   case 17328:
+   case 17330:
+   case 17332:
+   case 17334:
+   case 17336:
+   case 17338:
+   case 17340:
+   case 17342:
+   case 17344:
+   case 17346:
+   case 17348:
+   case 17350:
+   case 17352:
+   case 17354:
+   case 17356:
+   case 17358:
+   case 17360:
+   case 17362:
+   case 17364:
+   case 17366:
+   case 17368:
+   case 17370:
+   case 17372:
+   case 17374:
+   case 17376:
+   case 17378:
+   case 17380:
+   case 17382:
+   case 17384:
+   case 17386:
+   case 17388:
+   case 17390:
+   case 17392:
+   case 17394:
+   case 17396:
+   case 17398:
+   case 17400:
+   case 17402:
+   case 17404:
+   case 17406:
+   case 17408:
+   case 17410:
+   case 17412:
+   case 17414:
+   case 17416:
+   case 17418:
+   case 17420:
+   case 17422:
+   case 17424:
+   case 17426:
+   case 17428:
+   case 17430:
+   case 17432:
+   case 17434:
+   case 17436:
+   case 17438:
+   case 17440:
+   case 17442:
+   case 17444:
+   case 17446:
+   case 17448:
+   case 17450:
+   case 17452:
+   case 17454:
+   case 17456:
+   case 17458:
+   case 17460:
+   case 17462:
+   case 17464:
+   case 17466:
+   case 17468:
+   case 17470:
+   case 17472:
+   case 17474:
+   case 17476:
+   case 17478:
+   case 17480:
+   case 17482:
+   case 17484:
+   case 17486:
+   case 17488:
+   case 17490:
+   case 17492:
+   case 17494:
+   case 17496:
+   case 17498:
+   case 17500:
+   case 17502:
+   case 17504:
+   case 17506:
+   case 17508:
+   case 17510:
+   case 17512:
+   case 17514:
+   case 17516:
+   case 17518:
+   case 17520:
+   case 17522:
+   case 17524:
+   case 17526:
+   case 17528:
+   case 17530:
+   case 17532:
+   case 17534:
+   case 17536:
+   case 17538:
+   case 17540:
+   case 17542:
+   case 17544:
+   case 17546:
+   case 17548:
+   case 17550:
+   case 17552:
+   case 17554:
+   case 17556:
+   case 17558:
+   case 17560:
+   case 17562:
+   case 17564:
+   case 17566:
+   case 17568:
+   case 17570:
+   case 17572:
+   case 17574:
+   case 17576:
+   case 17578:
+   case 17580:
+   case 17582:
+   case 17584:
+   case 17586:
+   case 17588:
+   case 17590:
+   case 17592:
+   case 17594:
+   case 17596:
+   case 17598:
+   case 17600:
+   case 17602:
+   case 17604:
+   case 17606:
+   case 17608:
+   case 17610:
+   case 17612:
+   case 17614:
+   case 17616:
+   case 17618:
+   case 17620:
+   case 17622:
+   case 17624:
+   case 17626:
+   case 17628:
+   case 17630:
+   case 17632:
+   case 17634:
+   case 17636:
+   case 17638:
+   case 17640:
+   case 17642:
+   case 17644:
+   case 17646:
+   case 17648:
+   case 17650:
+   case 17652:
+   case 17654:
+   case 17656:
+   case 17658:
+   case 17660:
+   case 17662:
+   case 17664:
+   case 17666:
+   case 17668:
+   case 17670:
+   case 17672:
+   case 17674:
+   case 17676:
+   case 17678:
+   case 17680:
+   case 17682:
+   case 17684:
+   case 17686:
+   case 17688:
+   case 17690:
+   case 17692:
+   case 17694:
+   case 17696:
+   case 17698:
+   case 17700:
+   case 17702:
+   case 17704:
+   case 17706:
+   case 17708:
+   case 17710:
+   case 17712:
+   case 17714:
+   case 17716:
+   case 17718:
+   case 17720:
+   case 17722:
+   case 17724:
+   case 17726:
+   case 17728:
+   case 17730:
+   case 17732:
+   case 17734:
+   case 17736:
+   case 17738:
+   case 17740:
+   case 17742:
+   case 17744:
+   case 17746:
+   case 17748:
+   case 17750:
+   case 17752:
+   case 17754:
+   case 17756:
+   case 17758:
+   case 17760:
+   case 17762:
+   case 17764:
+   case 17766:
+   case 17768:
+   case 17770:
+   case 17772:
+   case 17774:
+   case 17776:
+   case 17778:
+   case 17780:
+   case 17782:
+   case 17784:
+   case 17786:
+   case 17788:
+   case 17790:
+   case 17792:
+   case 17794:
+   case 17796:
+   case 17798:
+   case 17800:
+   case 17802:
+   case 17804:
+   case 17806:
+   case 17808:
+   case 17810:
+   case 17812:
+   case 17814:
+   case 17816:
+   case 17818:
+   case 17820:
+   case 17822:
+   case 17824:
+   case 17826:
+   case 17828:
+   case 17830:
+   case 17832:
+   case 17834:
+   case 17836:
+   case 17838:
+   case 17840:
+   case 17842:
+   case 17844:
+   case 17846:
+   case 17848:
+   case 17850:
+   case 17852:
+   case 17854:
+   case 17856:
+   case 17858:
+   case 17860:
+   case 17862:
+   case 17864:
+   case 17866:
+   case 17868:
+   case 17870:
+   case 17872:
+   case 17874:
+   case 17876:
+   case 17878:
+   case 17880:
+   case 17882:
+   case 17884:
+   case 17886:
+   case 17888:
+   case 17890:
+   case 17892:
+   case 17894:
+   case 17896:
+   case 17898:
+   case 17900:
+   case 17902:
+   case 17904:
+   case 17906:
+   case 17908:
+   case 17910:
+   case 17912:
+   case 17914:
+   case 17916:
+   case 17918:
+   case 17920:
+   case 17922:
+   case 17924:
+   case 17926:
+   case 17928:
+   case 17930:
+   case 17932:
+   case 17934:
+   case 17936:
+   case 17938:
+   case 17940:
+   case 17942:
+   case 17944:
+   case 17946:
+   case 17948:
+   case 17950:
+   case 17952:
+   case 17954:
+   case 17956:
+   case 17958:
+   case 17960:
+   case 17962:
+   case 17964:
+   case 17966:
+   case 17968:
+   case 17970:
+   case 17972:
+   case 17974:
+   case 17976:
+   case 17978:
+   case 17980:
+   case 17982:
+   case 17984:
+   case 17986:
+   case 17988:
+   case 17990:
+   case 17992:
+   case 17994:
+   case 17996:
+   case 17998:
+   case 18e3:
+   case 18002:
+   case 18004:
+   case 18006:
+   case 18008:
+   case 18010:
+   case 18012:
+   case 18014:
+   case 18016:
+   case 18018:
+   case 18020:
+   case 18022:
+   case 18024:
+   case 18026:
+   case 18028:
+   case 18030:
+   case 18032:
+   case 18034:
+   case 18036:
+   case 18038:
+   case 18040:
+   case 18042:
+   case 18044:
+   case 18046:
+   case 18048:
+   case 18050:
+   case 18052:
+   case 18054:
+   case 18056:
+   case 18058:
+   case 18060:
+   case 18062:
+   case 18064:
+   case 18066:
+   case 18068:
+   case 18070:
+   case 18072:
+   case 18074:
+   case 18076:
+   case 18078:
+   case 18080:
+   case 18082:
+   case 18084:
+   case 18086:
+   case 18088:
+   case 18090:
+   case 18092:
+   case 18094:
+   case 18096:
+   case 18098:
+   case 18100:
+   case 18102:
+   case 18104:
+   case 18106:
+   case 18108:
+   case 18110:
+   case 18112:
+   case 18114:
+   case 18116:
+   case 18118:
+   case 18120:
+   case 18122:
+   case 18124:
+   case 18126:
+   case 18128:
+   case 18130:
+   case 18132:
+   case 18134:
+   case 18136:
+   case 18138:
+   case 18140:
+   case 18142:
+   case 18144:
+   case 18146:
+   case 18148:
+   case 18150:
+   case 18152:
+   case 18154:
+   case 18156:
+   case 18158:
+   case 18160:
+   case 18162:
+   case 18164:
+   case 18166:
+   case 18168:
+   case 18170:
+   case 18172:
+   case 18174:
+   case 18176:
+   case 18178:
+   case 18180:
+   case 18182:
+   case 18184:
+   case 18186:
+   case 18188:
+   case 18190:
+   case 18192:
+   case 18194:
+   case 18196:
+   case 18198:
+   case 18200:
+   case 18202:
+   case 18204:
+   case 18206:
+   case 18208:
+   case 18210:
+   case 18212:
+   case 18214:
+   case 18216:
+   case 18218:
+   case 18220:
+   case 18222:
+   case 18224:
+   case 18226:
+   case 18228:
+   case 18230:
+   case 18232:
+   case 18234:
+   case 18236:
+   case 18238:
+   case 18240:
+   case 18242:
+   case 18244:
+   case 18246:
+   case 18248:
+   case 18250:
+   case 18252:
+   case 18254:
+   case 18256:
+   case 18258:
+   case 18260:
+   case 18262:
+   case 18264:
+   case 18266:
+   case 18268:
+   case 18270:
+   case 18272:
+   case 18274:
+   case 18276:
+   case 18278:
+   case 18280:
+   case 18282:
+   case 18284:
+   case 18286:
+   case 18288:
+   case 18290:
+   case 18292:
+   case 18294:
+   case 18296:
+   case 18298:
+   case 18300:
+   case 18302:
+   case 18304:
+   case 18306:
+   case 18308:
+   case 18310:
+   case 18312:
+   case 18314:
+   case 18316:
+   case 18318:
+   case 18320:
+   case 18322:
+   case 18324:
+   case 18326:
+   case 18328:
+   case 18330:
+   case 18332:
+   case 18334:
+   case 18336:
+   case 18338:
+   case 18340:
+   case 18342:
+   case 18344:
+   case 18346:
+   case 18348:
+   case 18350:
+   case 18352:
+   case 18354:
+   case 18356:
+   case 18358:
+   case 18360:
+   case 18362:
+   case 18364:
+   case 18366:
+   case 18368:
+   case 18370:
+   case 18372:
+   case 18374:
+   case 18376:
+   case 18378:
+   case 18380:
+   case 18382:
+   case 18384:
+   case 18386:
+   case 18388:
+   case 18390:
+   case 18392:
+   case 18394:
+   case 18396:
+   case 18398:
+   case 18400:
+   case 18402:
+   case 18404:
+   case 18406:
+   case 18408:
+   case 18410:
+   case 18412:
+   case 18414:
+   case 18416:
+   case 18418:
+   case 18420:
+   case 18422:
+   case 18424:
+   case 18426:
+   case 18428:
+   case 18430:
+   case 18432:
+   case 18434:
+   case 18436:
+   case 18438:
+   case 18440:
+   case 18442:
+   case 18444:
+   case 18446:
+   case 18448:
+   case 18450:
+   case 18452:
+   case 18454:
+   case 18456:
+   case 18458:
+   case 18460:
+   case 18462:
+   case 18464:
+   case 18466:
+   case 18468:
+   case 18470:
+   case 18472:
+   case 18474:
+   case 18476:
+   case 18478:
+   case 18480:
+   case 18482:
+   case 18484:
+   case 18486:
+   case 18488:
+   case 18490:
+   case 18492:
+   case 18494:
+   case 18496:
+   case 18498:
+   case 18500:
+   case 18502:
+   case 18504:
+   case 18506:
+   case 18508:
+   case 18510:
+   case 18512:
+   case 18514:
+   case 18516:
+   case 18518:
+   case 18520:
+   case 18522:
+   case 18524:
+   case 18526:
+   case 18528:
+   case 18530:
+   case 18532:
+   case 18534:
+   case 18536:
+   case 18538:
+   case 18540:
+   case 18542:
+   case 18544:
+   case 18546:
+   case 18548:
+   case 18550:
+   case 18552:
+   case 18554:
+   case 18556:
+   case 18558:
+   case 18560:
+   case 18562:
+   case 18564:
+   case 18566:
+   case 18568:
+   case 18570:
+   case 18572:
+   case 18574:
+   case 18576:
+   case 18578:
+   case 18580:
+   case 18582:
+   case 18584:
+   case 18586:
+   case 18588:
+   case 18590:
+   case 18592:
+   case 18594:
+   case 18596:
+   case 18598:
+   case 18600:
+   case 18602:
+   case 18604:
+   case 18606:
+   case 18608:
+   case 18610:
+   case 18612:
+   case 18614:
+   case 18616:
+   case 18618:
+   case 18620:
+   case 18622:
+   case 18624:
+   case 18626:
+   case 18628:
+   case 18630:
+   case 18632:
+   case 18634:
+   case 18636:
+   case 18638:
+   case 18640:
+   case 18642:
+   case 18644:
+   case 18646:
+   case 18648:
+   case 18650:
+   case 18652:
+   case 18654:
+   case 18656:
+   case 18658:
+   case 18660:
+   case 18662:
+   case 18664:
+   case 18666:
+   case 18668:
+   case 18670:
+   case 18672:
+   case 18674:
+   case 18676:
+   case 18678:
+   case 18680:
+   case 18682:
+   case 18684:
+   case 18686:
+   case 18688:
+   case 18690:
+   case 18692:
+   case 18694:
+   case 18696:
+   case 18698:
+   case 18700:
+   case 18702:
+   case 18704:
+   case 18706:
+   case 18708:
+   case 18710:
+   case 18712:
+   case 18714:
+   case 18716:
+   case 18718:
+   case 18720:
+   case 18722:
+   case 18724:
+   case 18726:
+   case 18728:
+   case 18730:
+   case 18732:
+   case 18734:
+   case 18736:
+   case 18738:
+   case 18740:
+   case 18742:
+   case 18744:
+   case 18746:
+   case 18748:
+   case 18750:
+   case 18752:
+   case 18754:
+   case 18756:
+   case 18758:
+   case 18760:
+   case 18762:
+   case 18764:
+   case 18766:
+   case 18768:
+   case 18770:
+   case 18772:
+   case 18774:
+   case 18776:
+   case 18778:
+   case 18780:
+   case 18782:
+   case 18784:
+   case 18786:
+   case 18788:
+   case 18790:
+   case 18792:
+   case 18794:
+   case 18796:
+   case 18798:
+   case 18800:
+   case 18802:
+   case 18804:
+   case 18806:
+   case 18808:
+   case 18810:
+   case 18812:
+   case 18814:
+   case 18816:
+   case 18818:
+   case 18820:
+   case 18822:
+   case 18824:
+   case 18826:
+   case 18828:
+   case 18830:
+   case 18832:
+   case 18834:
+   case 18836:
+   case 18838:
+   case 18840:
+   case 18842:
+   case 18844:
+   case 18846:
+   case 18848:
+   case 18850:
+   case 18852:
+   case 18854:
+   case 18856:
+   case 18858:
+   case 18860:
+   case 18862:
+   case 18864:
+   case 18866:
+   case 18868:
+   case 18870:
+   case 18872:
+   case 18874:
+   case 18876:
+   case 18878:
+   case 18880:
+   case 18882:
+   case 18884:
+   case 18886:
+   case 18888:
+   case 18890:
+   case 18892:
+   case 18894:
+   case 18896:
+   case 18898:
+   case 18900:
+   case 18902:
+   case 18904:
+   case 18906:
+   case 18908:
+   case 18910:
+   case 18912:
+   case 18914:
+   case 18916:
+   case 18918:
+   case 18920:
+   case 18922:
+   case 18924:
+   case 18926:
+   case 18928:
+   case 18930:
+   case 18932:
+   case 18934:
+   case 18936:
+   case 18938:
+   case 18940:
+   case 18942:
+   case 18944:
+   case 18946:
+   case 18948:
+   case 18950:
+   case 18952:
+   case 18954:
+   case 18956:
+   case 18958:
+   case 18960:
+   case 18962:
+   case 18964:
+   case 18966:
+   case 18968:
+   case 18970:
+   case 18972:
+   case 18974:
+   case 18976:
+   case 18978:
+   case 18980:
+   case 18982:
+   case 18984:
+   case 18986:
+   case 18988:
+   case 18990:
+   case 18992:
+   case 18994:
+   case 18996:
+   case 18998:
+   case 19e3:
+   case 19002:
+   case 19004:
+   case 19006:
+   case 19008:
+   case 19010:
+   case 19012:
+   case 19014:
+   case 19016:
+   case 19018:
+   case 19020:
+   case 19022:
+   case 19024:
+   case 19026:
+   case 19028:
+   case 19030:
+   case 19032:
+   case 19034:
+   case 19036:
+   case 19038:
+   case 19040:
+   case 19042:
+   case 19044:
+   case 19046:
+   case 19048:
+   case 19050:
+   case 19052:
+   case 19054:
+   case 19056:
+   case 19058:
+   case 19060:
+   case 19062:
+   case 19064:
+   case 19066:
+   case 19068:
+   case 19070:
+   case 19072:
+   case 19074:
+   case 19076:
+   case 19078:
+   case 19080:
+   case 19082:
+   case 19084:
+   case 19086:
+   case 19088:
+   case 19090:
+   case 19092:
+   case 19094:
+   case 19096:
+   case 19098:
+   case 19100:
+   case 19102:
+   case 19104:
+   case 19106:
+   case 19108:
+   case 19110:
+   case 19112:
+   case 19114:
+   case 19116:
+   case 19118:
+   case 19120:
+   case 19122:
+   case 19124:
+   case 19126:
+   case 19128:
+   case 19130:
+   case 19132:
+   case 19134:
+   case 19136:
+   case 19138:
+   case 19140:
+   case 19142:
+   case 19144:
+   case 19146:
+   case 19148:
+   case 19150:
+   case 19152:
+   case 19154:
+   case 19156:
+   case 19158:
+   case 19160:
+   case 19162:
+   case 19164:
+   case 19166:
+   case 19168:
+   case 19170:
+   case 19172:
+   case 19174:
+   case 19176:
+   case 19178:
+   case 19180:
+   case 19182:
+   case 19184:
+   case 19186:
+   case 19188:
+   case 19190:
+   case 19192:
+   case 19194:
+   case 19196:
+   case 19198:
+   case 19200:
+   case 19202:
+   case 19204:
+   case 19206:
+   case 19208:
+   case 19210:
+   case 19212:
+   case 19214:
+   case 19216:
+   case 19218:
+   case 19220:
+   case 19222:
+   case 19224:
+   case 19226:
+   case 19228:
+   case 19230:
+   case 19232:
+   case 19234:
+   case 19236:
+   case 19238:
+   case 19240:
+   case 19242:
+   case 19244:
+   case 19246:
+   case 19248:
+   case 19250:
+   case 19252:
+   case 19254:
+   case 19256:
+   case 19258:
+   case 19260:
+   case 19262:
+   case 19264:
+   case 19266:
+   case 19268:
+   case 19270:
+   case 19272:
+   case 19274:
+   case 19276:
+   case 19278:
+   case 19280:
+   case 19282:
+   case 19284:
+   case 19286:
+   case 19288:
+   case 19290:
+   case 19292:
+   case 19294:
+   case 19296:
+   case 19298:
+   case 19300:
+   case 19302:
+   case 19304:
+   case 19306:
+   case 19308:
+   case 19310:
+   case 19312:
+   case 19314:
+   case 19316:
+   case 19318:
+   case 19320:
+   case 19322:
+   case 19324:
+   case 19326:
+   case 19328:
+   case 19330:
+   case 19332:
+   case 19334:
+   case 19336:
+   case 19338:
+   case 19340:
+   case 19342:
+   case 19344:
+   case 19346:
+   case 19348:
+   case 19350:
+   case 19352:
+   case 19354:
+   case 19356:
+   case 19358:
+   case 19360:
+   case 19362:
+   case 19364:
+   case 19366:
+   case 19368:
+   case 19370:
+   case 19372:
+   case 19374:
+   case 19376:
+   case 19378:
+   case 19380:
+   case 19382:
+   case 19384:
+   case 19386:
+   case 19388:
+   case 19390:
+   case 19392:
+   case 19394:
+   case 19396:
+   case 19398:
+   case 19400:
+   case 19402:
+   case 19404:
+   case 19406:
+   case 19408:
+   case 19410:
+   case 19412:
+   case 19414:
+   case 19416:
+   case 19418:
+   case 19420:
+   case 19422:
+   case 19424:
+   case 19426:
+   case 19428:
+   case 19430:
+   case 19432:
+   case 19434:
+   case 19436:
+   case 19438:
+   case 19440:
+   case 19442:
+   case 19444:
+   case 19446:
+   case 19448:
+   case 19450:
+   case 19452:
+   case 19454:
+   case 19456:
+   case 19458:
+   case 19460:
+   case 19462:
+   case 19464:
+   case 19466:
+   case 19468:
+   case 19470:
+   case 19472:
+   case 19474:
+   case 19476:
+   case 19478:
+   case 19480:
+   case 19482:
+   case 19484:
+   case 19486:
+   case 19488:
+   case 19490:
+   case 19492:
+   case 19494:
+   case 19496:
+   case 19498:
+   case 19500:
+   case 19502:
+   case 19504:
+   case 19506:
+   case 19508:
+   case 19510:
+   case 19512:
+   case 19514:
+   case 19516:
+   case 19518:
+   case 19520:
+   case 19522:
+   case 19524:
+   case 19526:
+   case 19528:
+   case 19530:
+   case 19532:
+   case 19534:
+   case 19536:
+   case 19538:
+   case 19540:
+   case 19542:
+   case 19544:
+   case 19546:
+   case 19548:
+   case 19550:
+   case 19552:
+   case 19554:
+   case 19556:
+   case 19558:
+   case 19560:
+   case 19562:
+   case 19564:
+   case 19566:
+   case 19568:
+   case 19570:
+   case 19572:
+   case 19574:
+   case 19576:
+   case 19578:
+   case 19580:
+   case 19582:
+   case 19584:
+   case 19586:
+   case 19588:
+   case 19590:
+   case 19592:
+   case 19594:
+   case 19596:
+   case 19598:
+   case 19600:
+   case 19602:
+   case 19604:
+   case 19606:
+   case 19608:
+   case 19610:
+   case 19612:
+   case 19614:
+   case 19616:
+   case 19618:
+   case 19620:
+   case 19622:
+   case 19624:
+   case 19626:
+   case 19628:
+   case 19630:
+   case 19632:
+   case 19634:
+   case 19636:
+   case 19638:
+   case 19640:
+   case 19642:
+   case 19644:
+   case 19646:
+   case 19648:
+   case 19650:
+   case 19652:
+   case 19654:
+   case 19656:
+   case 19658:
+   case 19660:
+   case 19662:
+   case 19664:
+   case 19666:
+   case 19668:
+   case 19670:
+   case 19672:
+   case 19674:
+   case 19676:
+   case 19678:
+   case 19680:
+   case 19682:
+   case 19684:
+   case 19686:
+   case 19688:
+   case 19690:
+   case 19692:
+   case 19694:
+   case 19696:
+   case 19698:
+   case 19700:
+   case 19702:
+   case 19704:
+   case 19706:
+   case 19708:
+   case 19710:
+   case 19712:
+   case 19714:
+   case 19716:
+   case 19718:
+   case 19720:
+   case 19722:
+   case 19724:
+   case 19726:
+   case 19728:
+   case 19730:
+   case 19732:
+   case 19734:
+   case 19736:
+   case 19738:
+   case 19740:
+   case 19742:
+   case 19744:
+   case 19746:
+   case 19748:
+   case 19750:
+   case 19752:
+   case 19754:
+   case 19756:
+   case 19758:
+   case 19760:
+   case 19762:
+   case 19764:
+   case 19766:
+   case 19768:
+   case 19770:
+   case 19772:
+   case 19774:
+   case 19776:
+   case 19778:
+   case 19780:
+   case 19782:
+   case 19784:
+   case 19786:
+   case 19788:
+   case 19790:
+   case 19792:
+   case 19794:
+   case 19796:
+   case 19798:
+   case 19800:
+   case 19802:
+   case 19804:
+   case 19806:
+   case 19808:
+   case 19810:
+   case 19812:
+   case 19814:
+   case 19816:
+   case 19818:
+   case 19820:
+   case 19822:
+   case 19824:
+   case 19826:
+   case 19828:
+   case 19830:
+   case 19832:
+   case 19834:
+   case 19836:
+   case 19838:
+   case 19840:
+   case 19842:
+   case 19844:
+   case 19846:
+   case 19848:
+   case 19850:
+   case 19852:
+   case 19854:
+   case 19856:
+   case 19858:
+   case 19860:
+   case 19862:
+   case 19864:
+   case 19866:
+   case 19868:
+   case 19870:
+   case 19872:
+   case 19874:
+   case 19876:
+   case 19878:
+   case 19880:
+   case 19882:
+   case 19884:
+   case 19886:
+   case 19888:
+   case 19890:
+   case 19892:
+   case 19894:
+   case 19896:
+   case 19898:
+   case 19900:
+   case 19902:
+   case 19904:
+   case 19906:
+   case 19908:
+   case 19910:
+   case 19912:
+   case 19914:
+   case 19916:
+   case 19918:
+   case 19920:
+   case 19922:
+   case 19924:
+   case 19926:
+   case 19928:
+   case 19930:
+   case 19932:
+   case 19934:
+   case 19936:
+   case 19938:
+   case 19940:
+   case 19942:
+   case 19944:
+   case 19946:
+   case 19948:
+   case 19950:
+   case 19952:
+   case 19954:
+   case 19956:
+   case 19958:
+   case 19960:
+   case 19962:
+   case 19964:
+   case 19966:
+   case 19968:
+   case 19970:
+   case 19972:
+   case 19974:
+   case 19976:
+   case 19978:
+   case 19980:
+   case 19982:
+   case 19984:
+   case 19986:
+   case 19988:
+   case 19990:
+   case 19992:
+   case 19994:
+   case 19996:
+   case 19998:
+   case 2e4:
+   case 20002:
+   case 20004:
+   case 20006:
+   case 20008:
+   case 20010:
+   case 20012:
+   case 20014:
+   case 20016:
+   case 20018:
+   case 20020:
+   case 20022:
+   case 20024:
+   case 20026:
+   case 20028:
+   case 20030:
+   case 20032:
+   case 20034:
+   case 20036:
+   case 20038:
+   case 20040:
+   case 20042:
+   case 20044:
+   case 20046:
+   case 20048:
+   case 20050:
+   case 20052:
+   case 20054:
+   case 20056:
+   case 20058:
+   case 20060:
+   case 20062:
+   case 20064:
+   case 20066:
+   case 20068:
+   case 20070:
+   case 20072:
+   case 20074:
+   case 20076:
+   case 20078:
+   case 20080:
+   case 20082:
+   case 20084:
+   case 20086:
+   case 20088:
+   case 20090:
+   case 20092:
+   case 20094:
+   case 20096:
+   case 20098:
+   case 20100:
+   case 20102:
+   case 20104:
+   case 20106:
+   case 20108:
+   case 20110:
+   case 20112:
+   case 20114:
+   case 20116:
+   case 20118:
+   case 20120:
+   case 20122:
+   case 20124:
+   case 20126:
+   case 20128:
+   case 20130:
+   case 20132:
+   case 20134:
+   case 20136:
+   case 20138:
+   case 20140:
+   case 20142:
+   case 20144:
+   case 20146:
+   case 20148:
+   case 20150:
+   case 20152:
+   case 20154:
+   case 20156:
+   case 20158:
+   case 20160:
+   case 20162:
+   case 20164:
+   case 20166:
+   case 20168:
+   case 20170:
+   case 20172:
+   case 20174:
+   case 20176:
+   case 20178:
+   case 20180:
+   case 20182:
+   case 20184:
+   case 20186:
+   case 20188:
+   case 20190:
+   case 20192:
+   case 20194:
+   case 20196:
+   case 20198:
+   case 20200:
+   case 20202:
+   case 20204:
+   case 20206:
+   case 20208:
+   case 20210:
+   case 20212:
+   case 20214:
+   case 20216:
+   case 20218:
+   case 20220:
+   case 20222:
+   case 20224:
+   case 20226:
+   case 20228:
+   case 20230:
+   case 20232:
+   case 20234:
+   case 20236:
+   case 20238:
+   case 20240:
+   case 20242:
+   case 20244:
+   case 20246:
+   case 20248:
+   case 20250:
+   case 20252:
+   case 20254:
+   case 20256:
+   case 20258:
+   case 20260:
+   case 20262:
+   case 20264:
+   case 20266:
+   case 20268:
+   case 20270:
+   case 20272:
+   case 20274:
+   case 20276:
+   case 20278:
+   case 20280:
+   case 20282:
+   case 20284:
+   case 20286:
+   case 20288:
+   case 20290:
+   case 20292:
+   case 20294:
+   case 20296:
+   case 20298:
+   case 20300:
+   case 20302:
+   case 20304:
+   case 20306:
+   case 20308:
+   case 20310:
+   case 20312:
+   case 20314:
+   case 20316:
+   case 20318:
+   case 20320:
+   case 20322:
+   case 20324:
+   case 20326:
+   case 20328:
+   case 20330:
+   case 20332:
+   case 20334:
+   case 20336:
+   case 20338:
+   case 20340:
+   case 20342:
+   case 20344:
+   case 20346:
+   case 20348:
+   case 20350:
+   case 20352:
+   case 20354:
+   case 20356:
+   case 20358:
+   case 20360:
+   case 20362:
+   case 20364:
+   case 20366:
+   case 20368:
+   case 20370:
+   case 20372:
+   case 20374:
+   case 20376:
+   case 20378:
+   case 20380:
+   case 20382:
+   case 20384:
+   case 20386:
+   case 20388:
+   case 20390:
+   case 20392:
+   case 20394:
+   case 20396:
+   case 20398:
+   case 20400:
+   case 20402:
+   case 20404:
+   case 20406:
+   case 20408:
+   case 20410:
+   case 20412:
+   case 20414:
+   case 20416:
+   case 20418:
+   case 20420:
+   case 20422:
+   case 20424:
+   case 20426:
+   case 20428:
+   case 20430:
+   case 20432:
+   case 20434:
+   case 20436:
+   case 20438:
+   case 20440:
+   case 20442:
+   case 20444:
+   case 20446:
+   case 20448:
+   case 20450:
+   case 20452:
+   case 20454:
+   case 20456:
+   case 20458:
+   case 20460:
+   case 20462:
+   case 20464:
+   case 20466:
+   case 20468:
+   case 20470:
+   case 20472:
+   case 20474:
+   case 20476:
+   case 20478:
+   case 20480:
+   case 20482:
+   case 20484:
+   case 20486:
+   case 20488:
+   case 20490:
+   case 20492:
+   case 20494:
+   case 20496:
+   case 20498:
+   case 20500:
+   case 20502:
+   case 20504:
+   case 20506:
+   case 20508:
+   case 20510:
+   case 20512:
+   case 20514:
+   case 20516:
+   case 20518:
+   case 20520:
+   case 20522:
+   case 20524:
+   case 20526:
+   case 20528:
+   case 20530:
+   case 20532:
+   case 20534:
+   case 20536:
+   case 20538:
+   case 20540:
+   case 20542:
+   case 20544:
+   case 20546:
+   case 20548:
+   case 20550:
+   case 20552:
+   case 20554:
+   case 20556:
+   case 20558:
+   case 20560:
+   case 20562:
+   case 20564:
+   case 20566:
+   case 20568:
+   case 20570:
+   case 20572:
+   case 20574:
+   case 20576:
+   case 20578:
+   case 20580:
+   case 20582:
+   case 20584:
+   case 20586:
+   case 20588:
+   case 20590:
+   case 20592:
+   case 20594:
+   case 20596:
+   case 20598:
+   case 20600:
+   case 20602:
+   case 20604:
+   case 20606:
+   case 20608:
+   case 20610:
+   case 20612:
+   case 20614:
+   case 20616:
+   case 20618:
+   case 20620:
+   case 20622:
+   case 20624:
+   case 20626:
+   case 20628:
+   case 20630:
+   case 20632:
+   case 20634:
+   case 20636:
+   case 20638:
+   case 20640:
+   case 20642:
+   case 20644:
+   case 20646:
+   case 20648:
+   case 20650:
+   case 20652:
+   case 20654:
+   case 20656:
+   case 20658:
+   case 20660:
+   case 20662:
+   case 20664:
+   case 20666:
+   case 20668:
+   case 20670:
+   case 20672:
+   case 20674:
+   case 20676:
+   case 20678:
+   case 20680:
+   case 20682:
+   case 20684:
+   case 20686:
+   case 20688:
+   case 20690:
+   case 20692:
+   case 20694:
+   case 20696:
+   case 20698:
+   case 20700:
+   case 20702:
+   case 20704:
+   case 20706:
+   case 20708:
+   case 20710:
+   case 20712:
+   case 20714:
+   case 20716:
+   case 20718:
+   case 20720:
+   case 20722:
+   case 20724:
+   case 20726:
+   case 20728:
+   case 20730:
+   case 20732:
+   case 20734:
+   case 20736:
+   case 20738:
+   case 20740:
+   case 20742:
+   case 20744:
+   case 20746:
+   case 20748:
+   case 20750:
+   case 20752:
+   case 20754:
+   case 20756:
+   case 20758:
+   case 20760:
+   case 20762:
+   case 20764:
+   case 20766:
+   case 20768:
+   case 20770:
+   case 20772:
+   case 20774:
+   case 20776:
+   case 20778:
+   case 20780:
+   case 20782:
+   case 20784:
+   case 20786:
+   case 20788:
+   case 20790:
+   case 20792:
+   case 20794:
+   case 20796:
+   case 20798:
+   case 20800:
+   case 20802:
+   case 20804:
+   case 20806:
+   case 20808:
+   case 20810:
+   case 20812:
+   case 20814:
+   case 20816:
+   case 20818:
+   case 20820:
+   case 20822:
+   case 20824:
+   case 20826:
+   case 20828:
+   case 20830:
+   case 20832:
+   case 20834:
+   case 20836:
+   case 20838:
+   case 20840:
+   case 20842:
+   case 20844:
+   case 20846:
+   case 20848:
+   case 20850:
+   case 20852:
+   case 20854:
+   case 20856:
+   case 20858:
+   case 20860:
+   case 20862:
+   case 20864:
+   case 20866:
+   case 20868:
+   case 20870:
+   case 20872:
+   case 20874:
+   case 20876:
+   case 20878:
+   case 20880:
+   case 20882:
+   case 20884:
+   case 20886:
+   case 20888:
+   case 20890:
+   case 20892:
+   case 20894:
+   case 20896:
+   case 20898:
+   case 20900:
+   case 20902:
+   case 20904:
+   case 20906:
+   case 20908:
+   case 20910:
+   case 20912:
+   case 20914:
+   case 20916:
+   case 20918:
+   case 20920:
+   case 20922:
+   case 20924:
+   case 20926:
+   case 20928:
+   case 20930:
+   case 20932:
+   case 20934:
+   case 20936:
+   case 20938:
+   case 20940:
+   case 20942:
+   case 20944:
+   case 20946:
+   case 20948:
+   case 20950:
+   case 20952:
+   case 20954:
+   case 20956:
+   case 20958:
+   case 20960:
+   case 20962:
+   case 20964:
+   case 20966:
+   case 20968:
+   case 20970:
+   case 20972:
+   case 20974:
+   case 20976:
+   case 20978:
+   case 20980:
+   case 20982:
+   case 20984:
+   case 20986:
+   case 20988:
+   case 20990:
+   case 20992:
+   case 20994:
+   case 20996:
+   case 20998:
+   case 21e3:
+   case 21002:
+   case 21004:
+   case 21006:
+   case 21008:
+   case 21010:
+   case 21012:
+   case 21014:
+   case 21016:
+   case 21018:
+   case 21020:
+   case 21022:
+   case 21024:
+   case 21026:
+   case 21028:
+   case 21030:
+   case 21032:
+   case 21034:
+   case 21036:
+   case 21038:
+   case 21040:
+   case 21042:
+   case 21044:
+   case 21046:
+   case 21048:
+   case 21050:
+   case 21052:
+   case 21054:
+   case 21056:
+   case 21058:
+   case 21060:
+   case 21062:
+   case 21064:
+   case 21066:
+   case 21068:
+   case 21070:
+   case 21072:
+   case 21074:
+   case 21076:
+   case 21078:
+   case 21080:
+   case 21082:
+   case 21084:
+   case 21086:
+   case 21088:
+   case 21090:
+   case 21092:
+   case 21094:
+   case 21096:
+   case 21098:
+   case 21100:
+   case 21102:
+   case 21104:
+   case 21106:
+   case 21108:
+   case 21110:
+   case 21112:
+   case 21114:
+   case 21116:
+   case 21118:
+   case 21120:
+   case 21122:
+   case 21124:
+   case 21126:
+   case 21128:
+   case 21130:
+   case 21132:
+   case 21134:
+   case 21136:
+   case 21138:
+   case 21140:
+   case 21142:
+   case 21144:
+   case 21146:
+   case 21148:
+   case 21150:
+   case 21152:
+   case 21154:
+   case 21156:
+   case 21158:
+   case 21160:
+   case 21162:
+   case 21164:
+   case 21166:
+   case 21168:
+   case 21170:
+   case 21172:
+   case 21174:
+   case 21176:
+   case 21178:
+   case 21180:
+   case 21182:
+   case 21184:
+   case 21186:
+   case 21188:
+   case 21190:
+   case 21192:
+   case 21194:
+   case 21196:
+   case 21198:
+   case 21200:
+   case 21202:
+   case 21204:
+   case 21206:
+   case 21208:
+   case 21210:
+   case 21212:
+   case 21214:
+   case 21216:
+   case 21218:
+   case 21220:
+   case 21222:
+   case 21224:
+   case 21226:
+   case 21228:
+   case 21230:
+   case 21232:
+   case 21234:
+   case 21236:
+   case 21238:
+   case 21240:
+   case 21242:
+   case 21244:
+   case 21246:
+   case 21248:
+   case 21250:
+   case 21252:
+   case 21254:
+   case 21256:
+   case 21258:
+   case 21260:
+   case 21262:
+   case 21264:
+   case 21266:
+   case 21268:
+   case 21270:
+   case 21272:
+   case 21274:
+   case 21276:
+   case 21278:
+   case 21280:
+   case 21282:
+   case 21284:
+   case 21286:
+   case 21288:
+   case 21290:
+   case 21292:
+   case 21294:
+   case 21296:
+   case 21298:
+   case 21300:
+   case 21302:
+   case 21304:
+   case 21306:
+   case 21308:
+   case 21310:
+   case 21312:
+   case 21314:
+   case 21316:
+   case 21318:
+   case 21320:
+   case 21322:
+   case 21324:
+   case 21326:
+   case 21328:
+   case 21330:
+   case 21332:
+   case 21334:
+   case 21336:
+   case 21338:
+   case 21340:
+   case 21342:
+   case 21344:
+   case 21346:
+   case 21348:
+   case 21350:
+   case 21352:
+   case 21354:
+   case 21356:
+   case 21358:
+   case 21360:
+   case 21362:
+   case 21364:
+   case 21366:
+   case 21368:
+   case 21370:
+   case 21372:
+   case 21374:
+   case 21376:
+   case 21378:
+   case 21380:
+   case 21382:
+   case 21384:
+   case 21386:
+   case 21388:
+   case 21390:
+   case 21392:
+   case 21394:
+   case 21396:
+   case 21398:
+   case 21400:
+   case 21402:
+   case 21404:
+   case 21406:
+   case 21408:
+   case 21410:
+   case 21412:
+   case 21414:
+   case 21416:
+   case 21418:
+   case 21420:
+   case 21422:
+   case 21424:
+   case 21426:
+   case 21428:
+   case 21430:
+   case 21432:
+   case 21434:
+   case 21436:
+   case 21438:
+   case 21440:
+   case 21442:
+   case 21444:
+   case 21446:
+   case 21448:
+   case 21450:
+   case 21452:
+   case 21454:
+   case 21456:
+   case 21458:
+   case 21460:
+   case 21462:
+   case 21464:
+   case 21466:
+   case 21468:
+   case 21470:
+   case 21472:
+   case 21474:
+   case 21476:
+   case 21478:
+   case 21480:
+   case 21482:
+   case 21484:
+   case 21486:
+   case 21488:
+   case 21490:
+   case 21492:
+   case 21494:
+   case 21496:
+   case 21498:
+   case 21500:
+   case 21502:
+   case 21504:
+   case 21506:
+   case 21508:
+   case 21510:
+   case 21512:
+   case 21514:
+   case 21516:
+   case 21518:
+   case 21520:
+   case 21522:
+   case 21524:
+   case 21526:
+   case 21528:
+   case 21530:
+   case 21532:
+   case 21534:
+   case 21536:
+   case 21538:
+   case 21540:
+   case 21542:
+   case 21544:
+   case 21546:
+   case 21548:
+   case 21550:
+   case 21552:
+   case 21554:
+   case 21556:
+   case 21558:
+   case 21560:
+   case 21562:
+   case 21564:
+   case 21566:
+   case 21568:
+   case 21570:
+   case 21572:
+   case 21574:
+   case 21576:
+   case 21578:
+   case 21580:
+   case 21582:
+   case 21584:
+   case 21586:
+   case 21588:
+   case 21590:
+   case 21592:
+   case 21594:
+   case 21596:
+   case 21598:
+   case 21600:
+   case 21602:
+   case 21604:
+   case 21606:
+   case 21608:
+   case 21610:
+   case 21612:
+   case 21614:
+   case 21616:
+   case 21618:
+   case 21620:
+   case 21622:
+   case 21624:
+   case 21626:
+   case 21628:
+   case 21630:
+   case 21632:
+   case 21634:
+   case 21636:
+   case 21638:
+   case 21640:
+   case 21642:
+   case 21644:
+   case 21646:
+   case 21648:
+   case 21650:
+   case 21652:
+   case 21654:
+   case 21656:
+   case 21658:
+   case 21660:
+   case 21662:
+   case 21664:
+   case 21666:
+   case 21668:
+   case 21670:
+   case 21672:
+   case 21674:
+   case 21676:
+   case 21678:
+   case 21680:
+   case 21682:
+   case 21684:
+   case 21686:
+   case 21688:
+   case 21690:
+   case 21692:
+   case 21694:
+   case 21696:
+   case 21698:
+   case 21700:
+   case 21702:
+   case 21704:
+   case 21706:
+   case 21708:
+   case 21710:
+   case 21712:
+   case 21714:
+   case 21716:
+   case 21718:
+   case 21720:
+   case 21722:
+   case 21724:
+   case 21726:
+   case 21728:
+   case 21730:
+   case 21732:
+   case 21734:
+   case 21736:
+   case 21738:
+   case 21740:
+   case 21742:
+   case 21744:
+   case 21746:
+   case 21748:
+   case 21750:
+   case 21752:
+   case 21754:
+   case 21756:
+   case 21758:
+   case 21760:
+   case 21762:
+   case 21764:
+   case 21766:
+   case 21768:
+   case 21770:
+   case 21772:
+   case 21774:
+   case 21776:
+   case 21778:
+   case 21780:
+   case 21782:
+   case 21784:
+   case 21786:
+   case 21788:
+   case 21790:
+   case 21792:
+   case 21794:
+   case 21796:
+   case 21798:
+   case 21800:
+   case 21802:
+   case 21804:
+   case 21806:
+   case 21808:
+   case 21810:
+   case 21812:
+   case 21814:
+   case 21816:
+   case 21818:
+   case 21820:
+   case 21822:
+   case 21824:
+   case 21826:
+   case 21828:
+   case 21830:
+   case 21832:
+   case 21834:
+   case 21836:
+   case 21838:
+   case 21840:
+   case 21842:
+   case 21844:
+   case 21846:
+   case 21848:
+   case 21850:
+   case 21852:
+   case 21854:
+   case 21856:
+   case 21858:
+   case 21860:
+   case 21862:
+   case 21864:
+   case 21866:
+   case 21868:
+   case 21870:
+   case 21872:
+   case 21874:
+   case 21876:
+   case 21878:
+   case 21880:
+   case 21882:
+   case 21884:
+   case 21886:
+   case 21888:
+   case 21890:
+   case 21892:
+   case 21894:
+   case 21896:
+   case 21898:
+   case 21900:
+   case 21902:
+   case 21904:
+   case 21906:
+   case 21908:
+   case 21910:
+   case 21912:
+   case 21914:
+   case 21916:
+   case 21918:
+   case 21920:
+   case 21922:
+   case 21924:
+   case 21926:
+   case 21928:
+   case 21930:
+   case 21932:
+   case 21934:
+   case 21936:
+   case 21938:
+   case 21940:
+   case 21942:
+   case 21944:
+   case 21946:
+   case 21948:
+   case 21950:
+   case 21952:
+   case 21954:
+   case 21956:
+   case 21958:
+   case 21960:
+   case 21962:
+   case 21964:
+   case 21966:
+   case 21968:
+   case 21970:
+   case 21972:
+   case 21974:
+   case 21976:
+   case 21978:
+   case 21980:
+   case 21982:
+   case 21984:
+   case 21986:
+   case 21988:
+   case 21990:
+   case 21992:
+   case 21994:
+   case 21996:
+   case 21998:
+   case 22e3:
+   case 22002:
+   case 22004:
+   case 22006:
+   case 22008:
+   case 22010:
+   case 22012:
+   case 22014:
+   case 22016:
+   case 22018:
+   case 22020:
+   case 22022:
+   case 22024:
+   case 22026:
+   case 22028:
+   case 22030:
+   case 22032:
+   case 22034:
+   case 22036:
+   case 22038:
+   case 22040:
+   case 22042:
+   case 22044:
+   case 22046:
+   case 22048:
+   case 22050:
+   case 22052:
+   case 22054:
+   case 22056:
+   case 22058:
+   case 22060:
+   case 22062:
+   case 22064:
+   case 22066:
+   case 22068:
+   case 22070:
+   case 22072:
+   case 22074:
+   case 22076:
+   case 22078:
+   case 22080:
+   case 22082:
+   case 22084:
+   case 22086:
+   case 22088:
+   case 22090:
+   case 22092:
+   case 22094:
+   case 22096:
+   case 22098:
+   case 22100:
+   case 22102:
+   case 22104:
+   case 22106:
+   case 22108:
+   case 22110:
+   case 22112:
+   case 22114:
+   case 22116:
+   case 22118:
+   case 22120:
+   case 22122:
+   case 22124:
+   case 22126:
+   case 22128:
+   case 22130:
+   case 22132:
+   case 22134:
+   case 22136:
+   case 22138:
+   case 22140:
+   case 22142:
+   case 22144:
+   case 22146:
+   case 22148:
+   case 22150:
+   case 22152:
+   case 22154:
+   case 22156:
+   case 22158:
+   case 22160:
+   case 22162:
+   case 22164:
+   case 22166:
+   case 22168:
+   case 22170:
+   case 22172:
+   case 22174:
+   case 22176:
+   case 22178:
+   case 22180:
+   case 22182:
+   case 22184:
+   case 22186:
+   case 22188:
+   case 22190:
+   case 22192:
+   case 22194:
+   case 22196:
+   case 22198:
+   case 22200:
+   case 22202:
+   case 22204:
+   case 22206:
+   case 22208:
+   case 22210:
+   case 22212:
+   case 22214:
+   case 22216:
+   case 22218:
+   case 22220:
+   case 22222:
+   case 22224:
+   case 22226:
+   case 22228:
+   case 22230:
+   case 22232:
+   case 22234:
+   case 22236:
+   case 22238:
+   case 22240:
+   case 22242:
+   case 22244:
+   case 22246:
+   case 22248:
+   case 22250:
+   case 22252:
+   case 22254:
+   case 22256:
+   case 22258:
+   case 22260:
+   case 22262:
+   case 22264:
+   case 22266:
+   case 22268:
+   case 22270:
+   case 22272:
+   case 22274:
+   case 22276:
+   case 22278:
+   case 22280:
+   case 22282:
+   case 22284:
+   case 22286:
+   case 22288:
+   case 22290:
+   case 22292:
+   case 22294:
+   case 22296:
+   case 22298:
+   case 22300:
+   case 22302:
+   case 22304:
+   case 22306:
+   case 22308:
+   case 22310:
+   case 22312:
+   case 22314:
+   case 22316:
+   case 22318:
+   case 22320:
+   case 22322:
+   case 22324:
+   case 22326:
+   case 22328:
+   case 22330:
+   case 22332:
+   case 22334:
+   case 22336:
+   case 22338:
+   case 22340:
+   case 22342:
+   case 22344:
+   case 22346:
+   case 22348:
+   case 22350:
+   case 22352:
+   case 22354:
+   case 22356:
+   case 22358:
+   case 22360:
+   case 22362:
+   case 22364:
+   case 22366:
+   case 22368:
+   case 22370:
+   case 22372:
+   case 22374:
+   case 22376:
+   case 22378:
+   case 22380:
+   case 22382:
+   case 22384:
+   case 22386:
+   case 22388:
+   case 22390:
+   case 22392:
+   case 22394:
+   case 22396:
+   case 22398:
+   case 22400:
+   case 22402:
+   case 22404:
+   case 22406:
+   case 22408:
+   case 22410:
+   case 22412:
+   case 22414:
+   case 22416:
+   case 22418:
+   case 22420:
+   case 22422:
+   case 22424:
+   case 22426:
+   case 22428:
+   case 22430:
+   case 22432:
+   case 22434:
+   case 22436:
+   case 22438:
+   case 22440:
+   case 22442:
+   case 22444:
+   case 22446:
+   case 22448:
+   case 22450:
+   case 22452:
+   case 22454:
+   case 22456:
+   case 22458:
+   case 22460:
+   case 22462:
+   case 22464:
+   case 22466:
+   case 22468:
+   case 22470:
+   case 22472:
+   case 22474:
+   case 22476:
+   case 22478:
+   case 22480:
+   case 22482:
+   case 22484:
+   case 22486:
+   case 22488:
+   case 22490:
+   case 22492:
+   case 22494:
+   case 22496:
+   case 22498:
+   case 22500:
+   case 22502:
+   case 22504:
+   case 22506:
+   case 22508:
+   case 22510:
+   case 22512:
+   case 22514:
+   case 22516:
+   case 22518:
+   case 22520:
+   case 22522:
+   case 22524:
+   case 22526:
+   case 22528:
+   case 22530:
+   case 22532:
+   case 22534:
+   case 22536:
+   case 22538:
+   case 22540:
+   case 22542:
+   case 22544:
+   case 22546:
+   case 22548:
+   case 22550:
+   case 22552:
+   case 22554:
+   case 22556:
+   case 22558:
+   case 22560:
+   case 22562:
+   case 22564:
+   case 22566:
+   case 22568:
+   case 22570:
+   case 22572:
+   case 22574:
+   case 22576:
+   case 22578:
+   case 22580:
+   case 22582:
+   case 22584:
+   case 22586:
+   case 22588:
+   case 22590:
+   case 22592:
+   case 22594:
+   case 22596:
+   case 22598:
+   case 22600:
+   case 22602:
+   case 22604:
+   case 22606:
+   case 22608:
+   case 22610:
+   case 22612:
+   case 22614:
+   case 22616:
+   case 22618:
+   case 22620:
+   case 22622:
+   case 22624:
+   case 22626:
+   case 22628:
+   case 22630:
+   case 22632:
+   case 22634:
+   case 22636:
+   case 22638:
+   case 22640:
+   case 22642:
+   case 22644:
+   case 22646:
+   case 22648:
+   case 22650:
+   case 22652:
+   case 22654:
+   case 22656:
+   case 22658:
+   case 22660:
+   case 22662:
+   case 22664:
+   case 22666:
+   case 22668:
+   case 22670:
+   case 22672:
+   case 22674:
+   case 22676:
+   case 22678:
+   case 22680:
+   case 22682:
+   case 22684:
+   case 22686:
+   case 22688:
+   case 22690:
+   case 22692:
+   case 22694:
+   case 22696:
+   case 22698:
+   case 22700:
+   case 22702:
+   case 22704:
+   case 22706:
+   case 22708:
+   case 22710:
+   case 22712:
+   case 22714:
+   case 22716:
+   case 22718:
+   case 22720:
+   case 22722:
+   case 22724:
+   case 22726:
+   case 22728:
+   case 22730:
+   case 22732:
+   case 22734:
+   case 22736:
+   case 22738:
+   case 22740:
+   case 22742:
+   case 22744:
+   case 22746:
+   case 22748:
+   case 22750:
+   case 22752:
+   case 22754:
+   case 22756:
+   case 22758:
+   case 22760:
+   case 22762:
+   case 22764:
+   case 22766:
+   case 22768:
+   case 22770:
+   case 22772:
+   case 22774:
+   case 22776:
+   case 22778:
+   case 22780:
+   case 22782:
+   case 22784:
+   case 22786:
+   case 22788:
+   case 22790:
+   case 22792:
+   case 22794:
+   case 22796:
+   case 22798:
+   case 22800:
+   case 22802:
+   case 22804:
+   case 22806:
+   case 22808:
+   case 22810:
+   case 22812:
+   case 22814:
+   case 22816:
+   case 22818:
+   case 22820:
+   case 22822:
+   case 22824:
+   case 22826:
+   case 22828:
+   case 22830:
+   case 22832:
+   case 22834:
+   case 22836:
+   case 22838:
+   case 22840:
+   case 22842:
+   case 22844:
+   case 22846:
+   case 22848:
+   case 22850:
+   case 22852:
+   case 22854:
+   case 22856:
+   case 22858:
+   case 22860:
+   case 22862:
+   case 22864:
+   case 22866:
+   case 22868:
+   case 22870:
+   case 22872:
+   case 22874:
+   case 22876:
+   case 22878:
+   case 22880:
+   case 22882:
+   case 22884:
+   case 22886:
+   case 22888:
+   case 22890:
+   case 22892:
+   case 22894:
+   case 22896:
+   case 22898:
+   case 22900:
+   case 22902:
+   case 22904:
+   case 22906:
+   case 22908:
+   case 22910:
+   case 22912:
+   case 22914:
+   case 22916:
+   case 22918:
+   case 22920:
+   case 22922:
+   case 22924:
+   case 22926:
+   case 22928:
+   case 22930:
+   case 22932:
+   case 22934:
+   case 22936:
+   case 22938:
+   case 22940:
+   case 22942:
+   case 22944:
+   case 22946:
+   case 22948:
+   case 22950:
+   case 22952:
+   case 22954:
+   case 22956:
+   case 22958:
+   case 22960:
+   case 22962:
+   case 22964:
+   case 22966:
+   case 22968:
+   case 22970:
+   case 22972:
+   case 22974:
+   case 22976:
+   case 22978:
+   case 22980:
+   case 22982:
+   case 22984:
+   case 22986:
+   case 22988:
+   case 22990:
+   case 22992:
+   case 22994:
+   case 22996:
+   case 22998:
+   case 23e3:
+   case 23002:
+   case 23004:
+   case 23006:
+   case 23008:
+   case 23010:
+   case 23012:
+   case 23014:
+   case 23016:
+   case 23018:
+   case 23020:
+   case 23022:
+   case 23024:
+   case 23026:
+   case 23028:
+   case 23030:
+   case 23032:
+   case 23034:
+   case 23036:
+   case 23038:
+   case 23040:
+   case 23042:
+   case 23044:
+   case 23046:
+   case 23048:
+   case 23050:
+   case 23052:
+   case 23054:
+   case 23056:
+   case 23058:
+   case 23060:
+   case 23062:
+   case 23064:
+   case 23066:
+   case 23068:
+   case 23070:
+   case 23072:
+   case 23074:
+   case 23076:
+   case 23078:
+   case 23080:
+   case 23082:
+   case 23084:
+   case 23086:
+   case 23088:
+   case 23090:
+   case 23092:
+   case 23094:
+   case 23096:
+   case 23098:
+   case 23100:
+   case 23102:
+   case 23104:
+   case 23106:
+   case 23108:
+   case 23110:
+   case 23112:
+   case 23114:
+   case 23116:
+   case 23118:
+   case 23120:
+   case 23122:
+   case 23124:
+   case 23126:
+   case 23128:
+   case 23130:
+   case 23132:
+   case 23134:
+   case 23136:
+   case 23138:
+   case 23140:
+   case 23142:
+   case 23144:
+   case 23146:
+   case 23148:
+   case 23150:
+   case 23152:
+   case 23154:
+   case 23156:
+   case 23158:
+   case 23160:
+   case 23162:
+   case 23164:
+   case 23166:
+   case 23168:
+   case 23170:
+   case 23172:
+   case 23174:
+   case 23176:
+   case 23178:
+   case 23180:
+   case 23182:
+   case 23184:
+   case 23186:
+   case 23188:
+   case 23190:
+   case 23192:
+   case 23194:
+   case 23196:
+   case 23198:
+   case 23200:
+   case 23202:
+   case 23204:
+   case 23206:
+   case 23208:
+   case 23210:
+   case 23212:
+   case 23214:
+   case 23216:
+   case 23218:
+   case 23220:
+   case 23222:
+   case 23224:
+   case 23226:
+   case 23228:
+   case 23230:
+   case 23232:
+   case 23234:
+   case 23236:
+   case 23238:
+   case 23240:
+   case 23242:
+   case 23244:
+   case 23246:
+   case 23248:
+   case 23250:
+   case 23252:
+   case 23254:
+   case 23256:
+   case 23258:
+   case 23260:
+   case 23262:
+   case 23264:
+   case 23266:
+   case 23268:
+   case 23270:
+   case 23272:
+   case 23274:
+   case 23276:
+   case 23278:
+   case 23280:
+   case 23282:
+   case 23284:
+   case 23286:
+   case 23288:
+   case 23290:
+   case 23292:
+   case 23294:
+   case 23296:
+   case 23298:
+   case 23300:
+   case 23302:
+   case 23304:
+   case 23306:
+   case 23308:
+   case 23310:
+   case 23312:
+   case 23314:
+   case 23316:
+   case 23318:
+   case 23320:
+   case 23322:
+   case 23324:
+   case 23326:
+   case 23328:
+   case 23330:
+   case 23332:
+   case 23334:
+   case 23336:
+   case 23338:
+   case 23340:
+   case 23342:
+   case 23344:
+   case 23346:
+   case 23348:
+   case 23350:
+   case 23352:
+   case 23354:
+   case 23356:
+   case 23358:
+   case 23360:
+   case 23362:
+   case 23364:
+   case 23366:
+   case 23368:
+   case 23370:
+   case 23372:
+   case 23374:
+   case 23376:
+   case 23378:
+   case 23380:
+   case 23382:
+   case 23384:
+   case 23386:
+   case 23388:
+   case 23390:
+   case 23392:
+   case 23394:
+   case 23396:
+   case 23398:
+   case 23400:
+   case 23402:
+   case 23404:
+   case 23406:
+   case 23408:
+   case 23410:
+   case 23412:
+   case 23414:
+   case 23416:
+   case 23418:
+   case 23420:
+   case 23422:
+   case 23424:
+   case 23426:
+   case 23428:
+   case 23430:
+   case 23432:
+   case 23434:
+   case 23436:
+   case 23438:
+   case 23440:
+   case 23442:
+   case 23444:
+   case 23446:
+   case 23448:
+   case 23450:
+   case 23452:
+   case 23454:
+   case 23456:
+   case 23458:
+   case 23460:
+   case 23462:
+   case 23464:
+   case 23466:
+   case 23468:
+   case 23470:
+   case 23472:
+   case 23474:
+   case 23476:
+   case 23478:
+   case 23480:
+   case 23482:
+   case 23484:
+   case 23486:
+   case 23488:
+   case 23490:
+   case 23492:
+   case 23494:
+   case 23496:
+   case 23498:
+   case 23500:
+   case 23502:
+   case 23504:
+   case 23506:
+   case 23508:
+   case 23510:
+   case 23512:
+   case 23514:
+   case 23516:
+   case 23518:
+   case 23520:
+   case 23522:
+   case 23524:
+   case 23526:
+   case 23528:
+   case 23530:
+   case 23532:
+   case 23534:
+   case 23536:
+   case 23538:
+   case 23540:
+   case 23542:
+   case 23544:
+   case 23546:
+   case 23548:
+   case 23550:
+   case 23552:
+   case 23554:
+   case 23556:
+   case 23558:
+   case 23560:
+   case 23562:
+   case 23564:
+   case 23566:
+   case 23568:
+   case 23570:
+   case 23572:
+   case 23574:
+   case 23576:
+   case 23578:
+   case 23580:
+   case 23582:
+   case 23584:
+   case 23586:
+   case 23588:
+   case 23590:
+   case 23592:
+   case 23594:
+   case 23596:
+   case 23598:
+   case 23600:
+   case 23602:
+   case 23604:
+   case 23606:
+   case 23608:
+   case 23610:
+   case 23612:
+   case 23614:
+   case 23616:
+   case 23618:
+   case 23620:
+   case 23622:
+   case 23624:
+   case 23626:
+   case 23628:
+   case 23630:
+   case 23632:
+   case 23634:
+   case 23636:
+   case 23638:
+   case 23640:
+   case 23642:
+   case 23644:
+   case 23646:
+   case 23648:
+   case 23650:
+   case 23652:
+   case 23654:
+   case 23656:
+   case 23658:
+   case 23660:
+   case 23662:
+   case 23664:
+   case 23666:
+   case 23668:
+   case 23670:
+   case 23672:
+   case 23674:
+   case 23676:
+   case 23678:
+   case 23680:
+   case 23682:
+   case 23684:
+   case 23686:
+   case 23688:
+   case 23690:
+   case 23692:
+   case 23694:
+   case 23696:
+   case 23698:
+   case 23700:
+   case 23702:
+   case 23704:
+   case 23706:
+   case 23708:
+   case 23710:
+   case 23712:
+   case 23714:
+   case 23716:
+   case 23718:
+   case 23720:
+   case 23722:
+   case 23724:
+   case 23726:
+   case 23728:
+   case 23730:
+   case 23732:
+   case 23734:
+   case 23736:
+   case 23738:
+   case 23740:
+   case 23742:
+   case 23744:
+   case 23746:
+   case 23748:
+   case 23750:
+   case 23752:
+   case 23754:
+   case 23756:
+   case 23758:
+   case 23760:
+   case 23762:
+   case 23764:
+   case 23766:
+   case 23768:
+   case 23770:
+   case 23772:
+   case 23774:
+   case 23776:
+   case 23778:
+   case 23780:
+   case 23782:
+   case 23784:
+   case 23786:
+   case 23788:
+   case 23790:
+   case 23792:
+   case 23794:
+   case 23796:
+   case 23798:
+   case 23800:
+   case 23802:
+   case 23804:
+   case 23806:
+   case 23808:
+   case 23810:
+   case 23812:
+   case 23814:
+   case 23816:
+   case 23818:
+   case 23820:
+   case 23822:
+   case 23824:
+   case 23826:
+   case 23828:
+   case 23830:
+   case 23832:
+   case 23834:
+   case 23836:
+   case 23838:
+   case 23840:
+   case 23842:
+   case 23844:
+   case 23846:
+   case 23848:
+   case 23850:
+   case 23852:
+   case 23854:
+   case 23856:
+   case 23858:
+   case 23860:
+   case 23862:
+   case 23864:
+   case 23866:
+   case 23868:
+   case 23870:
+   case 23872:
+   case 23874:
+   case 23876:
+   case 23878:
+   case 23880:
+   case 23882:
+   case 23884:
+   case 23886:
+   case 23888:
+   case 23890:
+   case 23892:
+   case 23894:
+   case 23896:
+   case 23898:
+   case 23900:
+   case 23902:
+   case 23904:
+   case 23906:
+   case 23908:
+   case 23910:
+   case 23912:
+   case 23914:
+   case 23916:
+   case 23918:
+   case 23920:
+   case 23922:
+   case 23924:
+   case 23926:
+   case 23928:
+   case 23930:
+   case 23932:
+   case 23934:
+   case 23936:
+   case 23938:
+   case 23940:
+   case 23942:
+   case 23944:
+   case 23946:
+   case 23948:
+   case 23950:
+   case 23952:
+   case 23954:
+   case 23956:
+   case 23958:
+   case 23960:
+   case 23962:
+   case 23964:
+   case 23966:
+   case 23968:
+   case 23970:
+   case 23972:
+   case 23974:
+   case 23976:
+   case 23978:
+   case 23980:
+   case 23982:
+   case 23984:
+   case 23986:
+   case 23988:
+   case 23990:
+   case 23992:
+   case 23994:
+   case 23996:
+   case 23998:
+   case 24e3:
+   case 24002:
+   case 24004:
+   case 24006:
+   case 24008:
+   case 24010:
+   case 24012:
+   case 24014:
+   case 24016:
+   case 24018:
+   case 24020:
+   case 24022:
+   case 24024:
+   case 24026:
+   case 24028:
+   case 24030:
+   case 24032:
+   case 24034:
+   case 24036:
+   case 24038:
+   case 24040:
+   case 24042:
+   case 24044:
+   case 24046:
+   case 24048:
+   case 24050:
+   case 24052:
+   case 24054:
+   case 24056:
+   case 24058:
+   case 24060:
+   case 24062:
+   case 24064:
+   case 24066:
+   case 24068:
+   case 24070:
+   case 24072:
+   case 24074:
+   case 24076:
+   case 24078:
+   case 24080:
+   case 24082:
+   case 24084:
+   case 24086:
+   case 24088:
+   case 24090:
+   case 24092:
+   case 24094:
+   case 24096:
+   case 24098:
+   case 24100:
+   case 24102:
+   case 24104:
+   case 24106:
+   case 24108:
+   case 24110:
+   case 24112:
+   case 24114:
+   case 24116:
+   case 24118:
+   case 24120:
+   case 24122:
+   case 24124:
+   case 24126:
+   case 24128:
+   case 24130:
+   case 24132:
+   case 24134:
+   case 24136:
+   case 24138:
+   case 24140:
+   case 24142:
+   case 24144:
+   case 24146:
+   case 24148:
+   case 24150:
+   case 24152:
+   case 24154:
+   case 24156:
+   case 24158:
+   case 24160:
+   case 24162:
+   case 24164:
+   case 24166:
+   case 24168:
+   case 24170:
+   case 24172:
+   case 24174:
+   case 24176:
+   case 24178:
+   case 24180:
+   case 24182:
+   case 24184:
+   case 24186:
+   case 24188:
+   case 24190:
+   case 24192:
+   case 24194:
+   case 24196:
+   case 24198:
+   case 24200:
+   case 24202:
+   case 24204:
+   case 24206:
+   case 24208:
+   case 24210:
+   case 24212:
+   case 24214:
+   case 24216:
+   case 24218:
+   case 24220:
+   case 24222:
+   case 24224:
+   case 24226:
+   case 24228:
+   case 24230:
+   case 24232:
+   case 24234:
+   case 24236:
+   case 24238:
+   case 24240:
+   case 24242:
+   case 24244:
+   case 24246:
+   case 24248:
+   case 24250:
+   case 24252:
+   case 24254:
+   case 24256:
+   case 24258:
+   case 24260:
+   case 24262:
+   case 24264:
+   case 24266:
+   case 24268:
+   case 24270:
+   case 24272:
+   case 24274:
+   case 24276:
+   case 24278:
+   case 24280:
+   case 24282:
+   case 24284:
+   case 24286:
+   case 24288:
+   case 24290:
+   case 24292:
+   case 24294:
+   case 24296:
+   case 24298:
+   case 24300:
+   case 24302:
+   case 24304:
+   case 24306:
+   case 24308:
+   case 24310:
+   case 24312:
+   case 24314:
+   case 24316:
+   case 24318:
+   case 24320:
+   case 24322:
+   case 24324:
+   case 24326:
+   case 24328:
+   case 24330:
+   case 24332:
+   case 24334:
+   case 24336:
+   case 24338:
+   case 24340:
+   case 24342:
+   case 24344:
+   case 24346:
+   case 24348:
+   case 24350:
+   case 24352:
+   case 24354:
+   case 24356:
+   case 24358:
+   case 24360:
+   case 24362:
+   case 24364:
+   case 24366:
+   case 24368:
+   case 24370:
+   case 24372:
+   case 24374:
+   case 24376:
+   case 24378:
+   case 24380:
+   case 24382:
+   case 24384:
+   case 24386:
+   case 24388:
+   case 24390:
+   case 24392:
+   case 24394:
+   case 24396:
+   case 24398:
+   case 24400:
+   case 24402:
+   case 24404:
+   case 24406:
+   case 24408:
+   case 24410:
+   case 24412:
+   case 24414:
+   case 24416:
+   case 24418:
+   case 24420:
+   case 24422:
+   case 24424:
+   case 24426:
+   case 24428:
+   case 24430:
+   case 24432:
+   case 24434:
+   case 24436:
+   case 24438:
+   case 24440:
+   case 24442:
+   case 24444:
+   case 24446:
+   case 24448:
+   case 24450:
+   case 24452:
+   case 24454:
+   case 24456:
+   case 24458:
+   case 24460:
+   case 24462:
+   case 24464:
+   case 24466:
+   case 24468:
+   case 24470:
+   case 24472:
+   case 24474:
+   case 24476:
+   case 24478:
+   case 24480:
+   case 24482:
+   case 24484:
+   case 24486:
+   case 24488:
+   case 24490:
+   case 24492:
+   case 24494:
+   case 24496:
+   case 24498:
+   case 24500:
+   case 24502:
+   case 24504:
+   case 24506:
+   case 24508:
+   case 24510:
+   case 24512:
+   case 24514:
+   case 24516:
+   case 24518:
+   case 24520:
+   case 24522:
+   case 24524:
+   case 24526:
+   case 24528:
+   case 24530:
+   case 24532:
+   case 24534:
+   case 24536:
+   case 24538:
+   case 24540:
+   case 24542:
+   case 24544:
+   case 24546:
+   case 24548:
+   case 24550:
+   case 24552:
+   case 24554:
+   case 24556:
+   case 24558:
+   case 24560:
+   case 24562:
+   case 24564:
+   case 24566:
+   case 24568:
+   case 24570:
+   case 24572:
+   case 24574:
+   case 24576:
+   case 24578:
+   case 24580:
+   case 24582:
+   case 24584:
+   case 24586:
+   case 24588:
+   case 24590:
+   case 24592:
+   case 24594:
+   case 24596:
+   case 24598:
+   case 24600:
+   case 24602:
+   case 24604:
+   case 24606:
+   case 24608:
+   case 24610:
+   case 24612:
+   case 24614:
+    return 0 | 0;
+   default:
+    break block;
+   };
+  }
+  return 1 | 0;
+ }
+ 
+ function $16() {
+  
+ }
+ 
+ function $17() {
+  block : {
+   dummy();
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+ }
+ 
+ function $18() {
+  block : {
+   dummy();
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+ }
+ 
+ function $19() {
+  var $1_1 = 0;
+  block : {
+   dummy();
+   $1_1 = 2;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ 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;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ 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;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $22() {
+  var $1_1 = 0;
+  fake_return_waka123 : {
+   dummy();
+   $1_1 = 5;
+   switch (1 | 0) {
+   default:
+    break fake_return_waka123;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $23() {
+  var $0 = 0;
+  block : {
+   $0 = 9;
+   break block;
+  }
+  return $0 | 0;
+ }
+ 
+ function $24() {
+  
+ }
+ 
+ function $25() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 8;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $26() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 9;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $27() {
+  
+ }
+ 
+ function $28() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 10;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $29() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 11;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $30() {
+  var i64toi32_i32$0 = 0, $1_1 = 0, $1$hi = 0;
+  block : {
+   i64toi32_i32$0 = 0;
+   $1_1 = 7;
+   $1$hi = i64toi32_i32$0;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  i64toi32_i32$0 = $1$hi;
+  return $1_1 | 0;
+ }
+ 
+ function $31() {
+  var $1_1 = 0, $2_1 = 0;
+  if_ : {
+   $1_1 = 2;
+   switch (0 | 0) {
+   default:
+    break if_;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $32($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var $4_1 = 0, $6_1 = 0;
+  block : {
+   if ($0) {
+    $4_1 = 3;
+    switch (0 | 0) {
+    default:
+     break block;
+    };
+   } else {
+    $6_1 = $1_1
+   }
+   $4_1 = $6_1;
+  }
+  return $4_1 | 0;
+ }
+ 
+ function $33($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var $4_1 = 0, $5_1 = 0, $6_1 = 0, $7_1 = 0;
+  block : {
+   if_ : {
+    if ($0) {
+     $7_1 = $1_1
+    } else {
+     $4_1 = 4;
+     $5_1 = $4_1;
+     $6_1 = $4_1;
+     switch (0 | 0) {
+     case 0:
+      break block;
+     default:
+      break if_;
+     };
+    }
+    $6_1 = $7_1;
+   }
+   $5_1 = $6_1;
+  }
+  return $5_1 | 0;
+ }
+ 
+ function $34($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var $3_1 = 0, $4_1 = 0, $5_1 = 0;
+  block : {
+   $3_1 = 5;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $35($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var $2_1 = 0, $4_1 = 0, $5_1 = 0;
+  block : {
+   $2_1 = $0;
+   $4_1 = 6;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $4_1 | 0;
+ }
+ 
+ function $36() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 7;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function f($0, $1_1, $2_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  return -1 | 0;
+ }
+ 
+ function $38() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 12;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $39() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 13;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $40() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 14;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $41() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 20;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $42() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 21;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $43() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 22;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $44() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 23;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $45() {
+  var $2_1 = 0;
+  block : {
+   $2_1 = 17;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $2_1 | 0;
+ }
+ 
+ function $46() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 2;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $47() {
+  var i64toi32_i32$0 = 0, $1_1 = 0, $1$hi = 0;
+  block : {
+   i64toi32_i32$0 = 0;
+   $1_1 = 30;
+   $1$hi = i64toi32_i32$0;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  i64toi32_i32$0 = $1$hi;
+  return $1_1 | 0;
+ }
+ 
+ function $48() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 30;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $49() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 31;
+   switch (1 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $50() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 32;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $51() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 33;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $52() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 3;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $53() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 3;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $54() {
+  var i64toi32_i32$0 = 0, $1_1 = 0, $1$hi = 0;
+  block : {
+   i64toi32_i32$0 = 0;
+   $1_1 = 45;
+   $1$hi = i64toi32_i32$0;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $55() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 44;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $56() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 43;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $57() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 42;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $58() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 41;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $59() {
+  var $1_1 = 0;
+  block : {
+   $1_1 = 40;
+   switch (0 | 0) {
+   default:
+    break block;
+   };
+  }
+  return $1_1 | 0;
+ }
+ 
+ function $60($0) {
+  $0 = $0 | 0;
+  var $2_1 = 0, $3_1 = 0, $4_1 = 0, $5_1 = 0;
+  block : {
+   block11 : {
+    block12 : {
+     $2_1 = 16;
+     $3_1 = $2_1;
+     $4_1 = $2_1;
+     $5_1 = $2_1;
+     switch ($0 | 0) {
+     case 1:
+      break block11;
+     case 0:
+      break block12;
+     default:
+      break block;
+     };
+    }
+    $4_1 = 2 + $5_1 | 0;
+   }
+   $3_1 = 1 + $4_1 | 0;
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $61($0) {
+  $0 = $0 | 0;
+  var $2_1 = 0, $3_1 = 0, $4_1 = 0, $5_1 = 0;
+  block : {
+   block13 : {
+    block14 : {
+     $2_1 = 8;
+     $3_1 = $2_1;
+     $4_1 = $2_1;
+     $5_1 = $2_1;
+     switch ($0 | 0) {
+     case 0:
+      break block;
+     case 1:
+      break block13;
+     default:
+      break block14;
+     };
+    }
+    $4_1 = 16;
+   }
+   $3_1 = 1 + $4_1 | 0;
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $62($0) {
+  $0 = $0 | 0;
+  var $2_1 = 0, $3_1 = 0, $4_1 = 0, $5_1 = 0;
+  block : {
+   block15 : {
+    block16 : {
+     $2_1 = 8;
+     $3_1 = $2_1;
+     $4_1 = $2_1;
+     $5_1 = $2_1;
+     switch ($0 | 0) {
+     case 1:
+      break block15;
+     case 0:
+      break block16;
+     default:
+      break block;
+     };
+    }
+    $4_1 = 16;
+   }
+   $3_1 = 1 + $4_1 | 0;
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $63($0) {
+  $0 = $0 | 0;
+  var $4_1 = 0, $2_1 = 0, $3_1 = 0;
+  block : {
+   block17 : {
+    $2_1 = 8;
+    $3_1 = $2_1;
+    $4_1 = $2_1;
+    switch ($0 | 0) {
+    case 1:
+     break block;
+    default:
+     break block17;
+    };
+   }
+   $3_1 = 1 + $4_1 | 0;
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $64($0) {
+  $0 = $0 | 0;
+  var $2_1 = 0, $3_1 = 0, $4_1 = 0, $5_1 = 0;
+  block : {
+   block18 : {
+    block19 : {
+     $2_1 = 8;
+     $3_1 = $2_1;
+     $4_1 = $2_1;
+     $5_1 = $2_1;
+     switch ($0 | 0) {
+     case 1:
+      break block18;
+     case 0:
+      break block19;
+     default:
+      break block;
+     };
+    }
+    $4_1 = 16;
+   }
+   $3_1 = 1 + $4_1 | 0;
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $65($0) {
+  $0 = $0 | 0;
+  var $4_1 = 0, $2_1 = 0, $3_1 = 0;
+  block : {
+   block20 : {
+    $2_1 = 8;
+    $3_1 = $2_1;
+    $4_1 = $2_1;
+    switch ($0 | 0) {
+    case 1:
+     break block;
+    default:
+     break block20;
+    };
+   }
+   $3_1 = 1 + $4_1 | 0;
+  }
+  return $3_1 | 0;
+ }
+ 
+ return {
+  "type_i32": $1, 
+  "type_i64": $2, 
+  "type_f32": $3, 
+  "type_f64": $4, 
+  "type_i32_value": $5, 
+  "type_i64_value": $6, 
+  "type_f32_value": $7, 
+  "type_f64_value": $8, 
+  "empty": $9, 
+  "empty_value": $10, 
+  "singleton": $11, 
+  "singleton_value": $12, 
+  "multiple": $13, 
+  "multiple_value": $14, 
+  "large": $15, 
+  "as_block_first": $16, 
+  "as_block_mid": $17, 
+  "as_block_last": $18, 
+  "as_block_value": $19, 
+  "as_loop_first": $20, 
+  "as_loop_mid": $21, 
+  "as_loop_last": $22, 
+  "as_br_value": $23, 
+  "as_br_if_cond": $24, 
+  "as_br_if_value": $25, 
+  "as_br_if_value_cond": $26, 
+  "as_br_table_index": $27, 
+  "as_br_table_value": $28, 
+  "as_br_table_value_index": $29, 
+  "as_return_value": $30, 
+  "as_if_cond": $31, 
+  "as_if_then": $32, 
+  "as_if_else": $33, 
+  "as_select_first": $34, 
+  "as_select_second": $35, 
+  "as_select_cond": $36, 
+  "as_call_first": $38, 
+  "as_call_mid": $39, 
+  "as_call_last": $40, 
+  "as_call_indirect_first": $41, 
+  "as_call_indirect_mid": $42, 
+  "as_call_indirect_last": $43, 
+  "as_call_indirect_func": $44, 
+  "as_local_set_value": $45, 
+  "as_load_address": $46, 
+  "as_loadN_address": $47, 
+  "as_store_address": $48, 
+  "as_store_value": $49, 
+  "as_storeN_address": $50, 
+  "as_storeN_value": $51, 
+  "as_unary_operand": $52, 
+  "as_binary_left": $53, 
+  "as_binary_right": $54, 
+  "as_test_operand": $55, 
+  "as_compare_left": $56, 
+  "as_compare_right": $57, 
+  "as_convert_operand": $58, 
+  "as_memory_grow_size": $59, 
+  "nested_block_value": $60, 
+  "nested_br_value": $61, 
+  "nested_br_if_value": $62, 
+  "nested_br_if_value_cond": $63, 
+  "nested_br_table_value": $64, 
+  "nested_br_table_value_index": $65
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var type_i32 = retasmFunc.type_i32;
+export var type_i64 = retasmFunc.type_i64;
+export var type_f32 = retasmFunc.type_f32;
+export var type_f64 = retasmFunc.type_f64;
+export var type_i32_value = retasmFunc.type_i32_value;
+export var type_i64_value = retasmFunc.type_i64_value;
+export var type_f32_value = retasmFunc.type_f32_value;
+export var type_f64_value = retasmFunc.type_f64_value;
+export var empty = retasmFunc.empty;
+export var empty_value = retasmFunc.empty_value;
+export var singleton = retasmFunc.singleton;
+export var singleton_value = retasmFunc.singleton_value;
+export var multiple = retasmFunc.multiple;
+export var multiple_value = retasmFunc.multiple_value;
+export var large = retasmFunc.large;
+export var as_block_first = retasmFunc.as_block_first;
+export var as_block_mid = retasmFunc.as_block_mid;
+export var as_block_last = retasmFunc.as_block_last;
+export var as_block_value = retasmFunc.as_block_value;
+export var as_loop_first = retasmFunc.as_loop_first;
+export var as_loop_mid = retasmFunc.as_loop_mid;
+export var as_loop_last = retasmFunc.as_loop_last;
+export var as_br_value = retasmFunc.as_br_value;
+export var as_br_if_cond = retasmFunc.as_br_if_cond;
+export var as_br_if_value = retasmFunc.as_br_if_value;
+export var as_br_if_value_cond = retasmFunc.as_br_if_value_cond;
+export var as_br_table_index = retasmFunc.as_br_table_index;
+export var as_br_table_value = retasmFunc.as_br_table_value;
+export var as_br_table_value_index = retasmFunc.as_br_table_value_index;
+export var as_return_value = retasmFunc.as_return_value;
+export var as_if_cond = retasmFunc.as_if_cond;
+export var as_if_then = retasmFunc.as_if_then;
+export var as_if_else = retasmFunc.as_if_else;
+export var as_select_first = retasmFunc.as_select_first;
+export var as_select_second = retasmFunc.as_select_second;
+export var as_select_cond = retasmFunc.as_select_cond;
+export var as_call_first = retasmFunc.as_call_first;
+export var as_call_mid = retasmFunc.as_call_mid;
+export var as_call_last = retasmFunc.as_call_last;
+export var as_call_indirect_first = retasmFunc.as_call_indirect_first;
+export var as_call_indirect_mid = retasmFunc.as_call_indirect_mid;
+export var as_call_indirect_last = retasmFunc.as_call_indirect_last;
+export var as_call_indirect_func = retasmFunc.as_call_indirect_func;
+export var as_local_set_value = retasmFunc.as_local_set_value;
+export var as_load_address = retasmFunc.as_load_address;
+export var as_loadN_address = retasmFunc.as_loadN_address;
+export var as_store_address = retasmFunc.as_store_address;
+export var as_store_value = retasmFunc.as_store_value;
+export var as_storeN_address = retasmFunc.as_storeN_address;
+export var as_storeN_value = retasmFunc.as_storeN_value;
+export var as_unary_operand = retasmFunc.as_unary_operand;
+export var as_binary_left = retasmFunc.as_binary_left;
+export var as_binary_right = retasmFunc.as_binary_right;
+export var as_test_operand = retasmFunc.as_test_operand;
+export var as_compare_left = retasmFunc.as_compare_left;
+export var as_compare_right = retasmFunc.as_compare_right;
+export var as_convert_operand = retasmFunc.as_convert_operand;
+export var as_memory_grow_size = retasmFunc.as_memory_grow_size;
+export var nested_block_value = retasmFunc.nested_block_value;
+export var nested_br_value = retasmFunc.nested_br_value;
+export var nested_br_if_value = retasmFunc.nested_br_if_value;
+export var nested_br_if_value_cond = retasmFunc.nested_br_if_value_cond;
+export var nested_br_table_value = retasmFunc.nested_br_table_value;
+export var nested_br_table_value_index = retasmFunc.nested_br_table_value_index;
diff --git a/binaryen/test/wasm2js/br_table_temp.2asm.js.opt b/binaryen/test/wasm2js/br_table_temp.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/br_table_temp.2asm.js.opt
@@ -0,0 +1,12768 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function dummy() {
+  
+ }
+ 
+ function $5() {
+  return 1;
+ }
+ 
+ function $6() {
+  return 2;
+ }
+ 
+ function $7() {
+  return Math_fround(Math_fround(3.0));
+ }
+ 
+ function $8() {
+  return 4.0;
+ }
+ 
+ function $9($0) {
+  $0 = $0 | 0;
+  return 22;
+ }
+ 
+ function $10($0) {
+  $0 = $0 | 0;
+  return 33;
+ }
+ 
+ function $11($0) {
+  $0 = $0 | 0;
+  if ($0) {
+   return 20
+  }
+  return 22;
+ }
+ 
+ function $12($0) {
+  $0 = $0 | 0;
+  if ($0) {
+   $0 = 33
+  } else {
+   $0 = 32
+  }
+  return $0 | 0;
+ }
+ 
+ function $13($0) {
+  $0 = $0 | 0;
+  block : {
+   switch ($0 | 0) {
+   case 3:
+    return 100;
+   case 2:
+    return 101;
+   case 1:
+    return 102;
+   case 0:
+    return 103;
+   default:
+    break block;
+   };
+  }
+  return 104;
+ }
+ 
+ function $14($0) {
+  $0 = $0 | 0;
+  block : {
+   switch ($0 | 0) {
+   case 3:
+    return 210;
+   case 2:
+    return 211;
+   case 1:
+    return 212;
+   case 0:
+    return 213;
+   default:
+    break block;
+   };
+  }
+  return 214;
+ }
+ 
+ function $15($0) {
+  $0 = $0 | 0;
+  block : {
+   switch ($0 | 0) {
+   case 0:
+   case 2:
+   case 4:
+   case 6:
+   case 8:
+   case 10:
+   case 12:
+   case 14:
+   case 16:
+   case 18:
+   case 20:
+   case 22:
+   case 24:
+   case 26:
+   case 28:
+   case 30:
+   case 32:
+   case 34:
+   case 36:
+   case 38:
+   case 40:
+   case 42:
+   case 44:
+   case 46:
+   case 48:
+   case 50:
+   case 52:
+   case 54:
+   case 56:
+   case 58:
+   case 60:
+   case 62:
+   case 64:
+   case 66:
+   case 68:
+   case 70:
+   case 72:
+   case 74:
+   case 76:
+   case 78:
+   case 80:
+   case 82:
+   case 84:
+   case 86:
+   case 88:
+   case 90:
+   case 92:
+   case 94:
+   case 96:
+   case 98:
+   case 100:
+   case 102:
+   case 104:
+   case 106:
+   case 108:
+   case 110:
+   case 112:
+   case 114:
+   case 116:
+   case 118:
+   case 120:
+   case 122:
+   case 124:
+   case 126:
+   case 128:
+   case 130:
+   case 132:
+   case 134:
+   case 136:
+   case 138:
+   case 140:
+   case 142:
+   case 144:
+   case 146:
+   case 148:
+   case 150:
+   case 152:
+   case 154:
+   case 156:
+   case 158:
+   case 160:
+   case 162:
+   case 164:
+   case 166:
+   case 168:
+   case 170:
+   case 172:
+   case 174:
+   case 176:
+   case 178:
+   case 180:
+   case 182:
+   case 184:
+   case 186:
+   case 188:
+   case 190:
+   case 192:
+   case 194:
+   case 196:
+   case 198:
+   case 200:
+   case 202:
+   case 204:
+   case 206:
+   case 208:
+   case 210:
+   case 212:
+   case 214:
+   case 216:
+   case 218:
+   case 220:
+   case 222:
+   case 224:
+   case 226:
+   case 228:
+   case 230:
+   case 232:
+   case 234:
+   case 236:
+   case 238:
+   case 240:
+   case 242:
+   case 244:
+   case 246:
+   case 248:
+   case 250:
+   case 252:
+   case 254:
+   case 256:
+   case 258:
+   case 260:
+   case 262:
+   case 264:
+   case 266:
+   case 268:
+   case 270:
+   case 272:
+   case 274:
+   case 276:
+   case 278:
+   case 280:
+   case 282:
+   case 284:
+   case 286:
+   case 288:
+   case 290:
+   case 292:
+   case 294:
+   case 296:
+   case 298:
+   case 300:
+   case 302:
+   case 304:
+   case 306:
+   case 308:
+   case 310:
+   case 312:
+   case 314:
+   case 316:
+   case 318:
+   case 320:
+   case 322:
+   case 324:
+   case 326:
+   case 328:
+   case 330:
+   case 332:
+   case 334:
+   case 336:
+   case 338:
+   case 340:
+   case 342:
+   case 344:
+   case 346:
+   case 348:
+   case 350:
+   case 352:
+   case 354:
+   case 356:
+   case 358:
+   case 360:
+   case 362:
+   case 364:
+   case 366:
+   case 368:
+   case 370:
+   case 372:
+   case 374:
+   case 376:
+   case 378:
+   case 380:
+   case 382:
+   case 384:
+   case 386:
+   case 388:
+   case 390:
+   case 392:
+   case 394:
+   case 396:
+   case 398:
+   case 400:
+   case 402:
+   case 404:
+   case 406:
+   case 408:
+   case 410:
+   case 412:
+   case 414:
+   case 416:
+   case 418:
+   case 420:
+   case 422:
+   case 424:
+   case 426:
+   case 428:
+   case 430:
+   case 432:
+   case 434:
+   case 436:
+   case 438:
+   case 440:
+   case 442:
+   case 444:
+   case 446:
+   case 448:
+   case 450:
+   case 452:
+   case 454:
+   case 456:
+   case 458:
+   case 460:
+   case 462:
+   case 464:
+   case 466:
+   case 468:
+   case 470:
+   case 472:
+   case 474:
+   case 476:
+   case 478:
+   case 480:
+   case 482:
+   case 484:
+   case 486:
+   case 488:
+   case 490:
+   case 492:
+   case 494:
+   case 496:
+   case 498:
+   case 500:
+   case 502:
+   case 504:
+   case 506:
+   case 508:
+   case 510:
+   case 512:
+   case 514:
+   case 516:
+   case 518:
+   case 520:
+   case 522:
+   case 524:
+   case 526:
+   case 528:
+   case 530:
+   case 532:
+   case 534:
+   case 536:
+   case 538:
+   case 540:
+   case 542:
+   case 544:
+   case 546:
+   case 548:
+   case 550:
+   case 552:
+   case 554:
+   case 556:
+   case 558:
+   case 560:
+   case 562:
+   case 564:
+   case 566:
+   case 568:
+   case 570:
+   case 572:
+   case 574:
+   case 576:
+   case 578:
+   case 580:
+   case 582:
+   case 584:
+   case 586:
+   case 588:
+   case 590:
+   case 592:
+   case 594:
+   case 596:
+   case 598:
+   case 600:
+   case 602:
+   case 604:
+   case 606:
+   case 608:
+   case 610:
+   case 612:
+   case 614:
+   case 616:
+   case 618:
+   case 620:
+   case 622:
+   case 624:
+   case 626:
+   case 628:
+   case 630:
+   case 632:
+   case 634:
+   case 636:
+   case 638:
+   case 640:
+   case 642:
+   case 644:
+   case 646:
+   case 648:
+   case 650:
+   case 652:
+   case 654:
+   case 656:
+   case 658:
+   case 660:
+   case 662:
+   case 664:
+   case 666:
+   case 668:
+   case 670:
+   case 672:
+   case 674:
+   case 676:
+   case 678:
+   case 680:
+   case 682:
+   case 684:
+   case 686:
+   case 688:
+   case 690:
+   case 692:
+   case 694:
+   case 696:
+   case 698:
+   case 700:
+   case 702:
+   case 704:
+   case 706:
+   case 708:
+   case 710:
+   case 712:
+   case 714:
+   case 716:
+   case 718:
+   case 720:
+   case 722:
+   case 724:
+   case 726:
+   case 728:
+   case 730:
+   case 732:
+   case 734:
+   case 736:
+   case 738:
+   case 740:
+   case 742:
+   case 744:
+   case 746:
+   case 748:
+   case 750:
+   case 752:
+   case 754:
+   case 756:
+   case 758:
+   case 760:
+   case 762:
+   case 764:
+   case 766:
+   case 768:
+   case 770:
+   case 772:
+   case 774:
+   case 776:
+   case 778:
+   case 780:
+   case 782:
+   case 784:
+   case 786:
+   case 788:
+   case 790:
+   case 792:
+   case 794:
+   case 796:
+   case 798:
+   case 800:
+   case 802:
+   case 804:
+   case 806:
+   case 808:
+   case 810:
+   case 812:
+   case 814:
+   case 816:
+   case 818:
+   case 820:
+   case 822:
+   case 824:
+   case 826:
+   case 828:
+   case 830:
+   case 832:
+   case 834:
+   case 836:
+   case 838:
+   case 840:
+   case 842:
+   case 844:
+   case 846:
+   case 848:
+   case 850:
+   case 852:
+   case 854:
+   case 856:
+   case 858:
+   case 860:
+   case 862:
+   case 864:
+   case 866:
+   case 868:
+   case 870:
+   case 872:
+   case 874:
+   case 876:
+   case 878:
+   case 880:
+   case 882:
+   case 884:
+   case 886:
+   case 888:
+   case 890:
+   case 892:
+   case 894:
+   case 896:
+   case 898:
+   case 900:
+   case 902:
+   case 904:
+   case 906:
+   case 908:
+   case 910:
+   case 912:
+   case 914:
+   case 916:
+   case 918:
+   case 920:
+   case 922:
+   case 924:
+   case 926:
+   case 928:
+   case 930:
+   case 932:
+   case 934:
+   case 936:
+   case 938:
+   case 940:
+   case 942:
+   case 944:
+   case 946:
+   case 948:
+   case 950:
+   case 952:
+   case 954:
+   case 956:
+   case 958:
+   case 960:
+   case 962:
+   case 964:
+   case 966:
+   case 968:
+   case 970:
+   case 972:
+   case 974:
+   case 976:
+   case 978:
+   case 980:
+   case 982:
+   case 984:
+   case 986:
+   case 988:
+   case 990:
+   case 992:
+   case 994:
+   case 996:
+   case 998:
+   case 1e3:
+   case 1002:
+   case 1004:
+   case 1006:
+   case 1008:
+   case 1010:
+   case 1012:
+   case 1014:
+   case 1016:
+   case 1018:
+   case 1020:
+   case 1022:
+   case 1024:
+   case 1026:
+   case 1028:
+   case 1030:
+   case 1032:
+   case 1034:
+   case 1036:
+   case 1038:
+   case 1040:
+   case 1042:
+   case 1044:
+   case 1046:
+   case 1048:
+   case 1050:
+   case 1052:
+   case 1054:
+   case 1056:
+   case 1058:
+   case 1060:
+   case 1062:
+   case 1064:
+   case 1066:
+   case 1068:
+   case 1070:
+   case 1072:
+   case 1074:
+   case 1076:
+   case 1078:
+   case 1080:
+   case 1082:
+   case 1084:
+   case 1086:
+   case 1088:
+   case 1090:
+   case 1092:
+   case 1094:
+   case 1096:
+   case 1098:
+   case 1100:
+   case 1102:
+   case 1104:
+   case 1106:
+   case 1108:
+   case 1110:
+   case 1112:
+   case 1114:
+   case 1116:
+   case 1118:
+   case 1120:
+   case 1122:
+   case 1124:
+   case 1126:
+   case 1128:
+   case 1130:
+   case 1132:
+   case 1134:
+   case 1136:
+   case 1138:
+   case 1140:
+   case 1142:
+   case 1144:
+   case 1146:
+   case 1148:
+   case 1150:
+   case 1152:
+   case 1154:
+   case 1156:
+   case 1158:
+   case 1160:
+   case 1162:
+   case 1164:
+   case 1166:
+   case 1168:
+   case 1170:
+   case 1172:
+   case 1174:
+   case 1176:
+   case 1178:
+   case 1180:
+   case 1182:
+   case 1184:
+   case 1186:
+   case 1188:
+   case 1190:
+   case 1192:
+   case 1194:
+   case 1196:
+   case 1198:
+   case 1200:
+   case 1202:
+   case 1204:
+   case 1206:
+   case 1208:
+   case 1210:
+   case 1212:
+   case 1214:
+   case 1216:
+   case 1218:
+   case 1220:
+   case 1222:
+   case 1224:
+   case 1226:
+   case 1228:
+   case 1230:
+   case 1232:
+   case 1234:
+   case 1236:
+   case 1238:
+   case 1240:
+   case 1242:
+   case 1244:
+   case 1246:
+   case 1248:
+   case 1250:
+   case 1252:
+   case 1254:
+   case 1256:
+   case 1258:
+   case 1260:
+   case 1262:
+   case 1264:
+   case 1266:
+   case 1268:
+   case 1270:
+   case 1272:
+   case 1274:
+   case 1276:
+   case 1278:
+   case 1280:
+   case 1282:
+   case 1284:
+   case 1286:
+   case 1288:
+   case 1290:
+   case 1292:
+   case 1294:
+   case 1296:
+   case 1298:
+   case 1300:
+   case 1302:
+   case 1304:
+   case 1306:
+   case 1308:
+   case 1310:
+   case 1312:
+   case 1314:
+   case 1316:
+   case 1318:
+   case 1320:
+   case 1322:
+   case 1324:
+   case 1326:
+   case 1328:
+   case 1330:
+   case 1332:
+   case 1334:
+   case 1336:
+   case 1338:
+   case 1340:
+   case 1342:
+   case 1344:
+   case 1346:
+   case 1348:
+   case 1350:
+   case 1352:
+   case 1354:
+   case 1356:
+   case 1358:
+   case 1360:
+   case 1362:
+   case 1364:
+   case 1366:
+   case 1368:
+   case 1370:
+   case 1372:
+   case 1374:
+   case 1376:
+   case 1378:
+   case 1380:
+   case 1382:
+   case 1384:
+   case 1386:
+   case 1388:
+   case 1390:
+   case 1392:
+   case 1394:
+   case 1396:
+   case 1398:
+   case 1400:
+   case 1402:
+   case 1404:
+   case 1406:
+   case 1408:
+   case 1410:
+   case 1412:
+   case 1414:
+   case 1416:
+   case 1418:
+   case 1420:
+   case 1422:
+   case 1424:
+   case 1426:
+   case 1428:
+   case 1430:
+   case 1432:
+   case 1434:
+   case 1436:
+   case 1438:
+   case 1440:
+   case 1442:
+   case 1444:
+   case 1446:
+   case 1448:
+   case 1450:
+   case 1452:
+   case 1454:
+   case 1456:
+   case 1458:
+   case 1460:
+   case 1462:
+   case 1464:
+   case 1466:
+   case 1468:
+   case 1470:
+   case 1472:
+   case 1474:
+   case 1476:
+   case 1478:
+   case 1480:
+   case 1482:
+   case 1484:
+   case 1486:
+   case 1488:
+   case 1490:
+   case 1492:
+   case 1494:
+   case 1496:
+   case 1498:
+   case 1500:
+   case 1502:
+   case 1504:
+   case 1506:
+   case 1508:
+   case 1510:
+   case 1512:
+   case 1514:
+   case 1516:
+   case 1518:
+   case 1520:
+   case 1522:
+   case 1524:
+   case 1526:
+   case 1528:
+   case 1530:
+   case 1532:
+   case 1534:
+   case 1536:
+   case 1538:
+   case 1540:
+   case 1542:
+   case 1544:
+   case 1546:
+   case 1548:
+   case 1550:
+   case 1552:
+   case 1554:
+   case 1556:
+   case 1558:
+   case 1560:
+   case 1562:
+   case 1564:
+   case 1566:
+   case 1568:
+   case 1570:
+   case 1572:
+   case 1574:
+   case 1576:
+   case 1578:
+   case 1580:
+   case 1582:
+   case 1584:
+   case 1586:
+   case 1588:
+   case 1590:
+   case 1592:
+   case 1594:
+   case 1596:
+   case 1598:
+   case 1600:
+   case 1602:
+   case 1604:
+   case 1606:
+   case 1608:
+   case 1610:
+   case 1612:
+   case 1614:
+   case 1616:
+   case 1618:
+   case 1620:
+   case 1622:
+   case 1624:
+   case 1626:
+   case 1628:
+   case 1630:
+   case 1632:
+   case 1634:
+   case 1636:
+   case 1638:
+   case 1640:
+   case 1642:
+   case 1644:
+   case 1646:
+   case 1648:
+   case 1650:
+   case 1652:
+   case 1654:
+   case 1656:
+   case 1658:
+   case 1660:
+   case 1662:
+   case 1664:
+   case 1666:
+   case 1668:
+   case 1670:
+   case 1672:
+   case 1674:
+   case 1676:
+   case 1678:
+   case 1680:
+   case 1682:
+   case 1684:
+   case 1686:
+   case 1688:
+   case 1690:
+   case 1692:
+   case 1694:
+   case 1696:
+   case 1698:
+   case 1700:
+   case 1702:
+   case 1704:
+   case 1706:
+   case 1708:
+   case 1710:
+   case 1712:
+   case 1714:
+   case 1716:
+   case 1718:
+   case 1720:
+   case 1722:
+   case 1724:
+   case 1726:
+   case 1728:
+   case 1730:
+   case 1732:
+   case 1734:
+   case 1736:
+   case 1738:
+   case 1740:
+   case 1742:
+   case 1744:
+   case 1746:
+   case 1748:
+   case 1750:
+   case 1752:
+   case 1754:
+   case 1756:
+   case 1758:
+   case 1760:
+   case 1762:
+   case 1764:
+   case 1766:
+   case 1768:
+   case 1770:
+   case 1772:
+   case 1774:
+   case 1776:
+   case 1778:
+   case 1780:
+   case 1782:
+   case 1784:
+   case 1786:
+   case 1788:
+   case 1790:
+   case 1792:
+   case 1794:
+   case 1796:
+   case 1798:
+   case 1800:
+   case 1802:
+   case 1804:
+   case 1806:
+   case 1808:
+   case 1810:
+   case 1812:
+   case 1814:
+   case 1816:
+   case 1818:
+   case 1820:
+   case 1822:
+   case 1824:
+   case 1826:
+   case 1828:
+   case 1830:
+   case 1832:
+   case 1834:
+   case 1836:
+   case 1838:
+   case 1840:
+   case 1842:
+   case 1844:
+   case 1846:
+   case 1848:
+   case 1850:
+   case 1852:
+   case 1854:
+   case 1856:
+   case 1858:
+   case 1860:
+   case 1862:
+   case 1864:
+   case 1866:
+   case 1868:
+   case 1870:
+   case 1872:
+   case 1874:
+   case 1876:
+   case 1878:
+   case 1880:
+   case 1882:
+   case 1884:
+   case 1886:
+   case 1888:
+   case 1890:
+   case 1892:
+   case 1894:
+   case 1896:
+   case 1898:
+   case 1900:
+   case 1902:
+   case 1904:
+   case 1906:
+   case 1908:
+   case 1910:
+   case 1912:
+   case 1914:
+   case 1916:
+   case 1918:
+   case 1920:
+   case 1922:
+   case 1924:
+   case 1926:
+   case 1928:
+   case 1930:
+   case 1932:
+   case 1934:
+   case 1936:
+   case 1938:
+   case 1940:
+   case 1942:
+   case 1944:
+   case 1946:
+   case 1948:
+   case 1950:
+   case 1952:
+   case 1954:
+   case 1956:
+   case 1958:
+   case 1960:
+   case 1962:
+   case 1964:
+   case 1966:
+   case 1968:
+   case 1970:
+   case 1972:
+   case 1974:
+   case 1976:
+   case 1978:
+   case 1980:
+   case 1982:
+   case 1984:
+   case 1986:
+   case 1988:
+   case 1990:
+   case 1992:
+   case 1994:
+   case 1996:
+   case 1998:
+   case 2e3:
+   case 2002:
+   case 2004:
+   case 2006:
+   case 2008:
+   case 2010:
+   case 2012:
+   case 2014:
+   case 2016:
+   case 2018:
+   case 2020:
+   case 2022:
+   case 2024:
+   case 2026:
+   case 2028:
+   case 2030:
+   case 2032:
+   case 2034:
+   case 2036:
+   case 2038:
+   case 2040:
+   case 2042:
+   case 2044:
+   case 2046:
+   case 2048:
+   case 2050:
+   case 2052:
+   case 2054:
+   case 2056:
+   case 2058:
+   case 2060:
+   case 2062:
+   case 2064:
+   case 2066:
+   case 2068:
+   case 2070:
+   case 2072:
+   case 2074:
+   case 2076:
+   case 2078:
+   case 2080:
+   case 2082:
+   case 2084:
+   case 2086:
+   case 2088:
+   case 2090:
+   case 2092:
+   case 2094:
+   case 2096:
+   case 2098:
+   case 2100:
+   case 2102:
+   case 2104:
+   case 2106:
+   case 2108:
+   case 2110:
+   case 2112:
+   case 2114:
+   case 2116:
+   case 2118:
+   case 2120:
+   case 2122:
+   case 2124:
+   case 2126:
+   case 2128:
+   case 2130:
+   case 2132:
+   case 2134:
+   case 2136:
+   case 2138:
+   case 2140:
+   case 2142:
+   case 2144:
+   case 2146:
+   case 2148:
+   case 2150:
+   case 2152:
+   case 2154:
+   case 2156:
+   case 2158:
+   case 2160:
+   case 2162:
+   case 2164:
+   case 2166:
+   case 2168:
+   case 2170:
+   case 2172:
+   case 2174:
+   case 2176:
+   case 2178:
+   case 2180:
+   case 2182:
+   case 2184:
+   case 2186:
+   case 2188:
+   case 2190:
+   case 2192:
+   case 2194:
+   case 2196:
+   case 2198:
+   case 2200:
+   case 2202:
+   case 2204:
+   case 2206:
+   case 2208:
+   case 2210:
+   case 2212:
+   case 2214:
+   case 2216:
+   case 2218:
+   case 2220:
+   case 2222:
+   case 2224:
+   case 2226:
+   case 2228:
+   case 2230:
+   case 2232:
+   case 2234:
+   case 2236:
+   case 2238:
+   case 2240:
+   case 2242:
+   case 2244:
+   case 2246:
+   case 2248:
+   case 2250:
+   case 2252:
+   case 2254:
+   case 2256:
+   case 2258:
+   case 2260:
+   case 2262:
+   case 2264:
+   case 2266:
+   case 2268:
+   case 2270:
+   case 2272:
+   case 2274:
+   case 2276:
+   case 2278:
+   case 2280:
+   case 2282:
+   case 2284:
+   case 2286:
+   case 2288:
+   case 2290:
+   case 2292:
+   case 2294:
+   case 2296:
+   case 2298:
+   case 2300:
+   case 2302:
+   case 2304:
+   case 2306:
+   case 2308:
+   case 2310:
+   case 2312:
+   case 2314:
+   case 2316:
+   case 2318:
+   case 2320:
+   case 2322:
+   case 2324:
+   case 2326:
+   case 2328:
+   case 2330:
+   case 2332:
+   case 2334:
+   case 2336:
+   case 2338:
+   case 2340:
+   case 2342:
+   case 2344:
+   case 2346:
+   case 2348:
+   case 2350:
+   case 2352:
+   case 2354:
+   case 2356:
+   case 2358:
+   case 2360:
+   case 2362:
+   case 2364:
+   case 2366:
+   case 2368:
+   case 2370:
+   case 2372:
+   case 2374:
+   case 2376:
+   case 2378:
+   case 2380:
+   case 2382:
+   case 2384:
+   case 2386:
+   case 2388:
+   case 2390:
+   case 2392:
+   case 2394:
+   case 2396:
+   case 2398:
+   case 2400:
+   case 2402:
+   case 2404:
+   case 2406:
+   case 2408:
+   case 2410:
+   case 2412:
+   case 2414:
+   case 2416:
+   case 2418:
+   case 2420:
+   case 2422:
+   case 2424:
+   case 2426:
+   case 2428:
+   case 2430:
+   case 2432:
+   case 2434:
+   case 2436:
+   case 2438:
+   case 2440:
+   case 2442:
+   case 2444:
+   case 2446:
+   case 2448:
+   case 2450:
+   case 2452:
+   case 2454:
+   case 2456:
+   case 2458:
+   case 2460:
+   case 2462:
+   case 2464:
+   case 2466:
+   case 2468:
+   case 2470:
+   case 2472:
+   case 2474:
+   case 2476:
+   case 2478:
+   case 2480:
+   case 2482:
+   case 2484:
+   case 2486:
+   case 2488:
+   case 2490:
+   case 2492:
+   case 2494:
+   case 2496:
+   case 2498:
+   case 2500:
+   case 2502:
+   case 2504:
+   case 2506:
+   case 2508:
+   case 2510:
+   case 2512:
+   case 2514:
+   case 2516:
+   case 2518:
+   case 2520:
+   case 2522:
+   case 2524:
+   case 2526:
+   case 2528:
+   case 2530:
+   case 2532:
+   case 2534:
+   case 2536:
+   case 2538:
+   case 2540:
+   case 2542:
+   case 2544:
+   case 2546:
+   case 2548:
+   case 2550:
+   case 2552:
+   case 2554:
+   case 2556:
+   case 2558:
+   case 2560:
+   case 2562:
+   case 2564:
+   case 2566:
+   case 2568:
+   case 2570:
+   case 2572:
+   case 2574:
+   case 2576:
+   case 2578:
+   case 2580:
+   case 2582:
+   case 2584:
+   case 2586:
+   case 2588:
+   case 2590:
+   case 2592:
+   case 2594:
+   case 2596:
+   case 2598:
+   case 2600:
+   case 2602:
+   case 2604:
+   case 2606:
+   case 2608:
+   case 2610:
+   case 2612:
+   case 2614:
+   case 2616:
+   case 2618:
+   case 2620:
+   case 2622:
+   case 2624:
+   case 2626:
+   case 2628:
+   case 2630:
+   case 2632:
+   case 2634:
+   case 2636:
+   case 2638:
+   case 2640:
+   case 2642:
+   case 2644:
+   case 2646:
+   case 2648:
+   case 2650:
+   case 2652:
+   case 2654:
+   case 2656:
+   case 2658:
+   case 2660:
+   case 2662:
+   case 2664:
+   case 2666:
+   case 2668:
+   case 2670:
+   case 2672:
+   case 2674:
+   case 2676:
+   case 2678:
+   case 2680:
+   case 2682:
+   case 2684:
+   case 2686:
+   case 2688:
+   case 2690:
+   case 2692:
+   case 2694:
+   case 2696:
+   case 2698:
+   case 2700:
+   case 2702:
+   case 2704:
+   case 2706:
+   case 2708:
+   case 2710:
+   case 2712:
+   case 2714:
+   case 2716:
+   case 2718:
+   case 2720:
+   case 2722:
+   case 2724:
+   case 2726:
+   case 2728:
+   case 2730:
+   case 2732:
+   case 2734:
+   case 2736:
+   case 2738:
+   case 2740:
+   case 2742:
+   case 2744:
+   case 2746:
+   case 2748:
+   case 2750:
+   case 2752:
+   case 2754:
+   case 2756:
+   case 2758:
+   case 2760:
+   case 2762:
+   case 2764:
+   case 2766:
+   case 2768:
+   case 2770:
+   case 2772:
+   case 2774:
+   case 2776:
+   case 2778:
+   case 2780:
+   case 2782:
+   case 2784:
+   case 2786:
+   case 2788:
+   case 2790:
+   case 2792:
+   case 2794:
+   case 2796:
+   case 2798:
+   case 2800:
+   case 2802:
+   case 2804:
+   case 2806:
+   case 2808:
+   case 2810:
+   case 2812:
+   case 2814:
+   case 2816:
+   case 2818:
+   case 2820:
+   case 2822:
+   case 2824:
+   case 2826:
+   case 2828:
+   case 2830:
+   case 2832:
+   case 2834:
+   case 2836:
+   case 2838:
+   case 2840:
+   case 2842:
+   case 2844:
+   case 2846:
+   case 2848:
+   case 2850:
+   case 2852:
+   case 2854:
+   case 2856:
+   case 2858:
+   case 2860:
+   case 2862:
+   case 2864:
+   case 2866:
+   case 2868:
+   case 2870:
+   case 2872:
+   case 2874:
+   case 2876:
+   case 2878:
+   case 2880:
+   case 2882:
+   case 2884:
+   case 2886:
+   case 2888:
+   case 2890:
+   case 2892:
+   case 2894:
+   case 2896:
+   case 2898:
+   case 2900:
+   case 2902:
+   case 2904:
+   case 2906:
+   case 2908:
+   case 2910:
+   case 2912:
+   case 2914:
+   case 2916:
+   case 2918:
+   case 2920:
+   case 2922:
+   case 2924:
+   case 2926:
+   case 2928:
+   case 2930:
+   case 2932:
+   case 2934:
+   case 2936:
+   case 2938:
+   case 2940:
+   case 2942:
+   case 2944:
+   case 2946:
+   case 2948:
+   case 2950:
+   case 2952:
+   case 2954:
+   case 2956:
+   case 2958:
+   case 2960:
+   case 2962:
+   case 2964:
+   case 2966:
+   case 2968:
+   case 2970:
+   case 2972:
+   case 2974:
+   case 2976:
+   case 2978:
+   case 2980:
+   case 2982:
+   case 2984:
+   case 2986:
+   case 2988:
+   case 2990:
+   case 2992:
+   case 2994:
+   case 2996:
+   case 2998:
+   case 3e3:
+   case 3002:
+   case 3004:
+   case 3006:
+   case 3008:
+   case 3010:
+   case 3012:
+   case 3014:
+   case 3016:
+   case 3018:
+   case 3020:
+   case 3022:
+   case 3024:
+   case 3026:
+   case 3028:
+   case 3030:
+   case 3032:
+   case 3034:
+   case 3036:
+   case 3038:
+   case 3040:
+   case 3042:
+   case 3044:
+   case 3046:
+   case 3048:
+   case 3050:
+   case 3052:
+   case 3054:
+   case 3056:
+   case 3058:
+   case 3060:
+   case 3062:
+   case 3064:
+   case 3066:
+   case 3068:
+   case 3070:
+   case 3072:
+   case 3074:
+   case 3076:
+   case 3078:
+   case 3080:
+   case 3082:
+   case 3084:
+   case 3086:
+   case 3088:
+   case 3090:
+   case 3092:
+   case 3094:
+   case 3096:
+   case 3098:
+   case 3100:
+   case 3102:
+   case 3104:
+   case 3106:
+   case 3108:
+   case 3110:
+   case 3112:
+   case 3114:
+   case 3116:
+   case 3118:
+   case 3120:
+   case 3122:
+   case 3124:
+   case 3126:
+   case 3128:
+   case 3130:
+   case 3132:
+   case 3134:
+   case 3136:
+   case 3138:
+   case 3140:
+   case 3142:
+   case 3144:
+   case 3146:
+   case 3148:
+   case 3150:
+   case 3152:
+   case 3154:
+   case 3156:
+   case 3158:
+   case 3160:
+   case 3162:
+   case 3164:
+   case 3166:
+   case 3168:
+   case 3170:
+   case 3172:
+   case 3174:
+   case 3176:
+   case 3178:
+   case 3180:
+   case 3182:
+   case 3184:
+   case 3186:
+   case 3188:
+   case 3190:
+   case 3192:
+   case 3194:
+   case 3196:
+   case 3198:
+   case 3200:
+   case 3202:
+   case 3204:
+   case 3206:
+   case 3208:
+   case 3210:
+   case 3212:
+   case 3214:
+   case 3216:
+   case 3218:
+   case 3220:
+   case 3222:
+   case 3224:
+   case 3226:
+   case 3228:
+   case 3230:
+   case 3232:
+   case 3234:
+   case 3236:
+   case 3238:
+   case 3240:
+   case 3242:
+   case 3244:
+   case 3246:
+   case 3248:
+   case 3250:
+   case 3252:
+   case 3254:
+   case 3256:
+   case 3258:
+   case 3260:
+   case 3262:
+   case 3264:
+   case 3266:
+   case 3268:
+   case 3270:
+   case 3272:
+   case 3274:
+   case 3276:
+   case 3278:
+   case 3280:
+   case 3282:
+   case 3284:
+   case 3286:
+   case 3288:
+   case 3290:
+   case 3292:
+   case 3294:
+   case 3296:
+   case 3298:
+   case 3300:
+   case 3302:
+   case 3304:
+   case 3306:
+   case 3308:
+   case 3310:
+   case 3312:
+   case 3314:
+   case 3316:
+   case 3318:
+   case 3320:
+   case 3322:
+   case 3324:
+   case 3326:
+   case 3328:
+   case 3330:
+   case 3332:
+   case 3334:
+   case 3336:
+   case 3338:
+   case 3340:
+   case 3342:
+   case 3344:
+   case 3346:
+   case 3348:
+   case 3350:
+   case 3352:
+   case 3354:
+   case 3356:
+   case 3358:
+   case 3360:
+   case 3362:
+   case 3364:
+   case 3366:
+   case 3368:
+   case 3370:
+   case 3372:
+   case 3374:
+   case 3376:
+   case 3378:
+   case 3380:
+   case 3382:
+   case 3384:
+   case 3386:
+   case 3388:
+   case 3390:
+   case 3392:
+   case 3394:
+   case 3396:
+   case 3398:
+   case 3400:
+   case 3402:
+   case 3404:
+   case 3406:
+   case 3408:
+   case 3410:
+   case 3412:
+   case 3414:
+   case 3416:
+   case 3418:
+   case 3420:
+   case 3422:
+   case 3424:
+   case 3426:
+   case 3428:
+   case 3430:
+   case 3432:
+   case 3434:
+   case 3436:
+   case 3438:
+   case 3440:
+   case 3442:
+   case 3444:
+   case 3446:
+   case 3448:
+   case 3450:
+   case 3452:
+   case 3454:
+   case 3456:
+   case 3458:
+   case 3460:
+   case 3462:
+   case 3464:
+   case 3466:
+   case 3468:
+   case 3470:
+   case 3472:
+   case 3474:
+   case 3476:
+   case 3478:
+   case 3480:
+   case 3482:
+   case 3484:
+   case 3486:
+   case 3488:
+   case 3490:
+   case 3492:
+   case 3494:
+   case 3496:
+   case 3498:
+   case 3500:
+   case 3502:
+   case 3504:
+   case 3506:
+   case 3508:
+   case 3510:
+   case 3512:
+   case 3514:
+   case 3516:
+   case 3518:
+   case 3520:
+   case 3522:
+   case 3524:
+   case 3526:
+   case 3528:
+   case 3530:
+   case 3532:
+   case 3534:
+   case 3536:
+   case 3538:
+   case 3540:
+   case 3542:
+   case 3544:
+   case 3546:
+   case 3548:
+   case 3550:
+   case 3552:
+   case 3554:
+   case 3556:
+   case 3558:
+   case 3560:
+   case 3562:
+   case 3564:
+   case 3566:
+   case 3568:
+   case 3570:
+   case 3572:
+   case 3574:
+   case 3576:
+   case 3578:
+   case 3580:
+   case 3582:
+   case 3584:
+   case 3586:
+   case 3588:
+   case 3590:
+   case 3592:
+   case 3594:
+   case 3596:
+   case 3598:
+   case 3600:
+   case 3602:
+   case 3604:
+   case 3606:
+   case 3608:
+   case 3610:
+   case 3612:
+   case 3614:
+   case 3616:
+   case 3618:
+   case 3620:
+   case 3622:
+   case 3624:
+   case 3626:
+   case 3628:
+   case 3630:
+   case 3632:
+   case 3634:
+   case 3636:
+   case 3638:
+   case 3640:
+   case 3642:
+   case 3644:
+   case 3646:
+   case 3648:
+   case 3650:
+   case 3652:
+   case 3654:
+   case 3656:
+   case 3658:
+   case 3660:
+   case 3662:
+   case 3664:
+   case 3666:
+   case 3668:
+   case 3670:
+   case 3672:
+   case 3674:
+   case 3676:
+   case 3678:
+   case 3680:
+   case 3682:
+   case 3684:
+   case 3686:
+   case 3688:
+   case 3690:
+   case 3692:
+   case 3694:
+   case 3696:
+   case 3698:
+   case 3700:
+   case 3702:
+   case 3704:
+   case 3706:
+   case 3708:
+   case 3710:
+   case 3712:
+   case 3714:
+   case 3716:
+   case 3718:
+   case 3720:
+   case 3722:
+   case 3724:
+   case 3726:
+   case 3728:
+   case 3730:
+   case 3732:
+   case 3734:
+   case 3736:
+   case 3738:
+   case 3740:
+   case 3742:
+   case 3744:
+   case 3746:
+   case 3748:
+   case 3750:
+   case 3752:
+   case 3754:
+   case 3756:
+   case 3758:
+   case 3760:
+   case 3762:
+   case 3764:
+   case 3766:
+   case 3768:
+   case 3770:
+   case 3772:
+   case 3774:
+   case 3776:
+   case 3778:
+   case 3780:
+   case 3782:
+   case 3784:
+   case 3786:
+   case 3788:
+   case 3790:
+   case 3792:
+   case 3794:
+   case 3796:
+   case 3798:
+   case 3800:
+   case 3802:
+   case 3804:
+   case 3806:
+   case 3808:
+   case 3810:
+   case 3812:
+   case 3814:
+   case 3816:
+   case 3818:
+   case 3820:
+   case 3822:
+   case 3824:
+   case 3826:
+   case 3828:
+   case 3830:
+   case 3832:
+   case 3834:
+   case 3836:
+   case 3838:
+   case 3840:
+   case 3842:
+   case 3844:
+   case 3846:
+   case 3848:
+   case 3850:
+   case 3852:
+   case 3854:
+   case 3856:
+   case 3858:
+   case 3860:
+   case 3862:
+   case 3864:
+   case 3866:
+   case 3868:
+   case 3870:
+   case 3872:
+   case 3874:
+   case 3876:
+   case 3878:
+   case 3880:
+   case 3882:
+   case 3884:
+   case 3886:
+   case 3888:
+   case 3890:
+   case 3892:
+   case 3894:
+   case 3896:
+   case 3898:
+   case 3900:
+   case 3902:
+   case 3904:
+   case 3906:
+   case 3908:
+   case 3910:
+   case 3912:
+   case 3914:
+   case 3916:
+   case 3918:
+   case 3920:
+   case 3922:
+   case 3924:
+   case 3926:
+   case 3928:
+   case 3930:
+   case 3932:
+   case 3934:
+   case 3936:
+   case 3938:
+   case 3940:
+   case 3942:
+   case 3944:
+   case 3946:
+   case 3948:
+   case 3950:
+   case 3952:
+   case 3954:
+   case 3956:
+   case 3958:
+   case 3960:
+   case 3962:
+   case 3964:
+   case 3966:
+   case 3968:
+   case 3970:
+   case 3972:
+   case 3974:
+   case 3976:
+   case 3978:
+   case 3980:
+   case 3982:
+   case 3984:
+   case 3986:
+   case 3988:
+   case 3990:
+   case 3992:
+   case 3994:
+   case 3996:
+   case 3998:
+   case 4e3:
+   case 4002:
+   case 4004:
+   case 4006:
+   case 4008:
+   case 4010:
+   case 4012:
+   case 4014:
+   case 4016:
+   case 4018:
+   case 4020:
+   case 4022:
+   case 4024:
+   case 4026:
+   case 4028:
+   case 4030:
+   case 4032:
+   case 4034:
+   case 4036:
+   case 4038:
+   case 4040:
+   case 4042:
+   case 4044:
+   case 4046:
+   case 4048:
+   case 4050:
+   case 4052:
+   case 4054:
+   case 4056:
+   case 4058:
+   case 4060:
+   case 4062:
+   case 4064:
+   case 4066:
+   case 4068:
+   case 4070:
+   case 4072:
+   case 4074:
+   case 4076:
+   case 4078:
+   case 4080:
+   case 4082:
+   case 4084:
+   case 4086:
+   case 4088:
+   case 4090:
+   case 4092:
+   case 4094:
+   case 4096:
+   case 4098:
+   case 4100:
+   case 4102:
+   case 4104:
+   case 4106:
+   case 4108:
+   case 4110:
+   case 4112:
+   case 4114:
+   case 4116:
+   case 4118:
+   case 4120:
+   case 4122:
+   case 4124:
+   case 4126:
+   case 4128:
+   case 4130:
+   case 4132:
+   case 4134:
+   case 4136:
+   case 4138:
+   case 4140:
+   case 4142:
+   case 4144:
+   case 4146:
+   case 4148:
+   case 4150:
+   case 4152:
+   case 4154:
+   case 4156:
+   case 4158:
+   case 4160:
+   case 4162:
+   case 4164:
+   case 4166:
+   case 4168:
+   case 4170:
+   case 4172:
+   case 4174:
+   case 4176:
+   case 4178:
+   case 4180:
+   case 4182:
+   case 4184:
+   case 4186:
+   case 4188:
+   case 4190:
+   case 4192:
+   case 4194:
+   case 4196:
+   case 4198:
+   case 4200:
+   case 4202:
+   case 4204:
+   case 4206:
+   case 4208:
+   case 4210:
+   case 4212:
+   case 4214:
+   case 4216:
+   case 4218:
+   case 4220:
+   case 4222:
+   case 4224:
+   case 4226:
+   case 4228:
+   case 4230:
+   case 4232:
+   case 4234:
+   case 4236:
+   case 4238:
+   case 4240:
+   case 4242:
+   case 4244:
+   case 4246:
+   case 4248:
+   case 4250:
+   case 4252:
+   case 4254:
+   case 4256:
+   case 4258:
+   case 4260:
+   case 4262:
+   case 4264:
+   case 4266:
+   case 4268:
+   case 4270:
+   case 4272:
+   case 4274:
+   case 4276:
+   case 4278:
+   case 4280:
+   case 4282:
+   case 4284:
+   case 4286:
+   case 4288:
+   case 4290:
+   case 4292:
+   case 4294:
+   case 4296:
+   case 4298:
+   case 4300:
+   case 4302:
+   case 4304:
+   case 4306:
+   case 4308:
+   case 4310:
+   case 4312:
+   case 4314:
+   case 4316:
+   case 4318:
+   case 4320:
+   case 4322:
+   case 4324:
+   case 4326:
+   case 4328:
+   case 4330:
+   case 4332:
+   case 4334:
+   case 4336:
+   case 4338:
+   case 4340:
+   case 4342:
+   case 4344:
+   case 4346:
+   case 4348:
+   case 4350:
+   case 4352:
+   case 4354:
+   case 4356:
+   case 4358:
+   case 4360:
+   case 4362:
+   case 4364:
+   case 4366:
+   case 4368:
+   case 4370:
+   case 4372:
+   case 4374:
+   case 4376:
+   case 4378:
+   case 4380:
+   case 4382:
+   case 4384:
+   case 4386:
+   case 4388:
+   case 4390:
+   case 4392:
+   case 4394:
+   case 4396:
+   case 4398:
+   case 4400:
+   case 4402:
+   case 4404:
+   case 4406:
+   case 4408:
+   case 4410:
+   case 4412:
+   case 4414:
+   case 4416:
+   case 4418:
+   case 4420:
+   case 4422:
+   case 4424:
+   case 4426:
+   case 4428:
+   case 4430:
+   case 4432:
+   case 4434:
+   case 4436:
+   case 4438:
+   case 4440:
+   case 4442:
+   case 4444:
+   case 4446:
+   case 4448:
+   case 4450:
+   case 4452:
+   case 4454:
+   case 4456:
+   case 4458:
+   case 4460:
+   case 4462:
+   case 4464:
+   case 4466:
+   case 4468:
+   case 4470:
+   case 4472:
+   case 4474:
+   case 4476:
+   case 4478:
+   case 4480:
+   case 4482:
+   case 4484:
+   case 4486:
+   case 4488:
+   case 4490:
+   case 4492:
+   case 4494:
+   case 4496:
+   case 4498:
+   case 4500:
+   case 4502:
+   case 4504:
+   case 4506:
+   case 4508:
+   case 4510:
+   case 4512:
+   case 4514:
+   case 4516:
+   case 4518:
+   case 4520:
+   case 4522:
+   case 4524:
+   case 4526:
+   case 4528:
+   case 4530:
+   case 4532:
+   case 4534:
+   case 4536:
+   case 4538:
+   case 4540:
+   case 4542:
+   case 4544:
+   case 4546:
+   case 4548:
+   case 4550:
+   case 4552:
+   case 4554:
+   case 4556:
+   case 4558:
+   case 4560:
+   case 4562:
+   case 4564:
+   case 4566:
+   case 4568:
+   case 4570:
+   case 4572:
+   case 4574:
+   case 4576:
+   case 4578:
+   case 4580:
+   case 4582:
+   case 4584:
+   case 4586:
+   case 4588:
+   case 4590:
+   case 4592:
+   case 4594:
+   case 4596:
+   case 4598:
+   case 4600:
+   case 4602:
+   case 4604:
+   case 4606:
+   case 4608:
+   case 4610:
+   case 4612:
+   case 4614:
+   case 4616:
+   case 4618:
+   case 4620:
+   case 4622:
+   case 4624:
+   case 4626:
+   case 4628:
+   case 4630:
+   case 4632:
+   case 4634:
+   case 4636:
+   case 4638:
+   case 4640:
+   case 4642:
+   case 4644:
+   case 4646:
+   case 4648:
+   case 4650:
+   case 4652:
+   case 4654:
+   case 4656:
+   case 4658:
+   case 4660:
+   case 4662:
+   case 4664:
+   case 4666:
+   case 4668:
+   case 4670:
+   case 4672:
+   case 4674:
+   case 4676:
+   case 4678:
+   case 4680:
+   case 4682:
+   case 4684:
+   case 4686:
+   case 4688:
+   case 4690:
+   case 4692:
+   case 4694:
+   case 4696:
+   case 4698:
+   case 4700:
+   case 4702:
+   case 4704:
+   case 4706:
+   case 4708:
+   case 4710:
+   case 4712:
+   case 4714:
+   case 4716:
+   case 4718:
+   case 4720:
+   case 4722:
+   case 4724:
+   case 4726:
+   case 4728:
+   case 4730:
+   case 4732:
+   case 4734:
+   case 4736:
+   case 4738:
+   case 4740:
+   case 4742:
+   case 4744:
+   case 4746:
+   case 4748:
+   case 4750:
+   case 4752:
+   case 4754:
+   case 4756:
+   case 4758:
+   case 4760:
+   case 4762:
+   case 4764:
+   case 4766:
+   case 4768:
+   case 4770:
+   case 4772:
+   case 4774:
+   case 4776:
+   case 4778:
+   case 4780:
+   case 4782:
+   case 4784:
+   case 4786:
+   case 4788:
+   case 4790:
+   case 4792:
+   case 4794:
+   case 4796:
+   case 4798:
+   case 4800:
+   case 4802:
+   case 4804:
+   case 4806:
+   case 4808:
+   case 4810:
+   case 4812:
+   case 4814:
+   case 4816:
+   case 4818:
+   case 4820:
+   case 4822:
+   case 4824:
+   case 4826:
+   case 4828:
+   case 4830:
+   case 4832:
+   case 4834:
+   case 4836:
+   case 4838:
+   case 4840:
+   case 4842:
+   case 4844:
+   case 4846:
+   case 4848:
+   case 4850:
+   case 4852:
+   case 4854:
+   case 4856:
+   case 4858:
+   case 4860:
+   case 4862:
+   case 4864:
+   case 4866:
+   case 4868:
+   case 4870:
+   case 4872:
+   case 4874:
+   case 4876:
+   case 4878:
+   case 4880:
+   case 4882:
+   case 4884:
+   case 4886:
+   case 4888:
+   case 4890:
+   case 4892:
+   case 4894:
+   case 4896:
+   case 4898:
+   case 4900:
+   case 4902:
+   case 4904:
+   case 4906:
+   case 4908:
+   case 4910:
+   case 4912:
+   case 4914:
+   case 4916:
+   case 4918:
+   case 4920:
+   case 4922:
+   case 4924:
+   case 4926:
+   case 4928:
+   case 4930:
+   case 4932:
+   case 4934:
+   case 4936:
+   case 4938:
+   case 4940:
+   case 4942:
+   case 4944:
+   case 4946:
+   case 4948:
+   case 4950:
+   case 4952:
+   case 4954:
+   case 4956:
+   case 4958:
+   case 4960:
+   case 4962:
+   case 4964:
+   case 4966:
+   case 4968:
+   case 4970:
+   case 4972:
+   case 4974:
+   case 4976:
+   case 4978:
+   case 4980:
+   case 4982:
+   case 4984:
+   case 4986:
+   case 4988:
+   case 4990:
+   case 4992:
+   case 4994:
+   case 4996:
+   case 4998:
+   case 5e3:
+   case 5002:
+   case 5004:
+   case 5006:
+   case 5008:
+   case 5010:
+   case 5012:
+   case 5014:
+   case 5016:
+   case 5018:
+   case 5020:
+   case 5022:
+   case 5024:
+   case 5026:
+   case 5028:
+   case 5030:
+   case 5032:
+   case 5034:
+   case 5036:
+   case 5038:
+   case 5040:
+   case 5042:
+   case 5044:
+   case 5046:
+   case 5048:
+   case 5050:
+   case 5052:
+   case 5054:
+   case 5056:
+   case 5058:
+   case 5060:
+   case 5062:
+   case 5064:
+   case 5066:
+   case 5068:
+   case 5070:
+   case 5072:
+   case 5074:
+   case 5076:
+   case 5078:
+   case 5080:
+   case 5082:
+   case 5084:
+   case 5086:
+   case 5088:
+   case 5090:
+   case 5092:
+   case 5094:
+   case 5096:
+   case 5098:
+   case 5100:
+   case 5102:
+   case 5104:
+   case 5106:
+   case 5108:
+   case 5110:
+   case 5112:
+   case 5114:
+   case 5116:
+   case 5118:
+   case 5120:
+   case 5122:
+   case 5124:
+   case 5126:
+   case 5128:
+   case 5130:
+   case 5132:
+   case 5134:
+   case 5136:
+   case 5138:
+   case 5140:
+   case 5142:
+   case 5144:
+   case 5146:
+   case 5148:
+   case 5150:
+   case 5152:
+   case 5154:
+   case 5156:
+   case 5158:
+   case 5160:
+   case 5162:
+   case 5164:
+   case 5166:
+   case 5168:
+   case 5170:
+   case 5172:
+   case 5174:
+   case 5176:
+   case 5178:
+   case 5180:
+   case 5182:
+   case 5184:
+   case 5186:
+   case 5188:
+   case 5190:
+   case 5192:
+   case 5194:
+   case 5196:
+   case 5198:
+   case 5200:
+   case 5202:
+   case 5204:
+   case 5206:
+   case 5208:
+   case 5210:
+   case 5212:
+   case 5214:
+   case 5216:
+   case 5218:
+   case 5220:
+   case 5222:
+   case 5224:
+   case 5226:
+   case 5228:
+   case 5230:
+   case 5232:
+   case 5234:
+   case 5236:
+   case 5238:
+   case 5240:
+   case 5242:
+   case 5244:
+   case 5246:
+   case 5248:
+   case 5250:
+   case 5252:
+   case 5254:
+   case 5256:
+   case 5258:
+   case 5260:
+   case 5262:
+   case 5264:
+   case 5266:
+   case 5268:
+   case 5270:
+   case 5272:
+   case 5274:
+   case 5276:
+   case 5278:
+   case 5280:
+   case 5282:
+   case 5284:
+   case 5286:
+   case 5288:
+   case 5290:
+   case 5292:
+   case 5294:
+   case 5296:
+   case 5298:
+   case 5300:
+   case 5302:
+   case 5304:
+   case 5306:
+   case 5308:
+   case 5310:
+   case 5312:
+   case 5314:
+   case 5316:
+   case 5318:
+   case 5320:
+   case 5322:
+   case 5324:
+   case 5326:
+   case 5328:
+   case 5330:
+   case 5332:
+   case 5334:
+   case 5336:
+   case 5338:
+   case 5340:
+   case 5342:
+   case 5344:
+   case 5346:
+   case 5348:
+   case 5350:
+   case 5352:
+   case 5354:
+   case 5356:
+   case 5358:
+   case 5360:
+   case 5362:
+   case 5364:
+   case 5366:
+   case 5368:
+   case 5370:
+   case 5372:
+   case 5374:
+   case 5376:
+   case 5378:
+   case 5380:
+   case 5382:
+   case 5384:
+   case 5386:
+   case 5388:
+   case 5390:
+   case 5392:
+   case 5394:
+   case 5396:
+   case 5398:
+   case 5400:
+   case 5402:
+   case 5404:
+   case 5406:
+   case 5408:
+   case 5410:
+   case 5412:
+   case 5414:
+   case 5416:
+   case 5418:
+   case 5420:
+   case 5422:
+   case 5424:
+   case 5426:
+   case 5428:
+   case 5430:
+   case 5432:
+   case 5434:
+   case 5436:
+   case 5438:
+   case 5440:
+   case 5442:
+   case 5444:
+   case 5446:
+   case 5448:
+   case 5450:
+   case 5452:
+   case 5454:
+   case 5456:
+   case 5458:
+   case 5460:
+   case 5462:
+   case 5464:
+   case 5466:
+   case 5468:
+   case 5470:
+   case 5472:
+   case 5474:
+   case 5476:
+   case 5478:
+   case 5480:
+   case 5482:
+   case 5484:
+   case 5486:
+   case 5488:
+   case 5490:
+   case 5492:
+   case 5494:
+   case 5496:
+   case 5498:
+   case 5500:
+   case 5502:
+   case 5504:
+   case 5506:
+   case 5508:
+   case 5510:
+   case 5512:
+   case 5514:
+   case 5516:
+   case 5518:
+   case 5520:
+   case 5522:
+   case 5524:
+   case 5526:
+   case 5528:
+   case 5530:
+   case 5532:
+   case 5534:
+   case 5536:
+   case 5538:
+   case 5540:
+   case 5542:
+   case 5544:
+   case 5546:
+   case 5548:
+   case 5550:
+   case 5552:
+   case 5554:
+   case 5556:
+   case 5558:
+   case 5560:
+   case 5562:
+   case 5564:
+   case 5566:
+   case 5568:
+   case 5570:
+   case 5572:
+   case 5574:
+   case 5576:
+   case 5578:
+   case 5580:
+   case 5582:
+   case 5584:
+   case 5586:
+   case 5588:
+   case 5590:
+   case 5592:
+   case 5594:
+   case 5596:
+   case 5598:
+   case 5600:
+   case 5602:
+   case 5604:
+   case 5606:
+   case 5608:
+   case 5610:
+   case 5612:
+   case 5614:
+   case 5616:
+   case 5618:
+   case 5620:
+   case 5622:
+   case 5624:
+   case 5626:
+   case 5628:
+   case 5630:
+   case 5632:
+   case 5634:
+   case 5636:
+   case 5638:
+   case 5640:
+   case 5642:
+   case 5644:
+   case 5646:
+   case 5648:
+   case 5650:
+   case 5652:
+   case 5654:
+   case 5656:
+   case 5658:
+   case 5660:
+   case 5662:
+   case 5664:
+   case 5666:
+   case 5668:
+   case 5670:
+   case 5672:
+   case 5674:
+   case 5676:
+   case 5678:
+   case 5680:
+   case 5682:
+   case 5684:
+   case 5686:
+   case 5688:
+   case 5690:
+   case 5692:
+   case 5694:
+   case 5696:
+   case 5698:
+   case 5700:
+   case 5702:
+   case 5704:
+   case 5706:
+   case 5708:
+   case 5710:
+   case 5712:
+   case 5714:
+   case 5716:
+   case 5718:
+   case 5720:
+   case 5722:
+   case 5724:
+   case 5726:
+   case 5728:
+   case 5730:
+   case 5732:
+   case 5734:
+   case 5736:
+   case 5738:
+   case 5740:
+   case 5742:
+   case 5744:
+   case 5746:
+   case 5748:
+   case 5750:
+   case 5752:
+   case 5754:
+   case 5756:
+   case 5758:
+   case 5760:
+   case 5762:
+   case 5764:
+   case 5766:
+   case 5768:
+   case 5770:
+   case 5772:
+   case 5774:
+   case 5776:
+   case 5778:
+   case 5780:
+   case 5782:
+   case 5784:
+   case 5786:
+   case 5788:
+   case 5790:
+   case 5792:
+   case 5794:
+   case 5796:
+   case 5798:
+   case 5800:
+   case 5802:
+   case 5804:
+   case 5806:
+   case 5808:
+   case 5810:
+   case 5812:
+   case 5814:
+   case 5816:
+   case 5818:
+   case 5820:
+   case 5822:
+   case 5824:
+   case 5826:
+   case 5828:
+   case 5830:
+   case 5832:
+   case 5834:
+   case 5836:
+   case 5838:
+   case 5840:
+   case 5842:
+   case 5844:
+   case 5846:
+   case 5848:
+   case 5850:
+   case 5852:
+   case 5854:
+   case 5856:
+   case 5858:
+   case 5860:
+   case 5862:
+   case 5864:
+   case 5866:
+   case 5868:
+   case 5870:
+   case 5872:
+   case 5874:
+   case 5876:
+   case 5878:
+   case 5880:
+   case 5882:
+   case 5884:
+   case 5886:
+   case 5888:
+   case 5890:
+   case 5892:
+   case 5894:
+   case 5896:
+   case 5898:
+   case 5900:
+   case 5902:
+   case 5904:
+   case 5906:
+   case 5908:
+   case 5910:
+   case 5912:
+   case 5914:
+   case 5916:
+   case 5918:
+   case 5920:
+   case 5922:
+   case 5924:
+   case 5926:
+   case 5928:
+   case 5930:
+   case 5932:
+   case 5934:
+   case 5936:
+   case 5938:
+   case 5940:
+   case 5942:
+   case 5944:
+   case 5946:
+   case 5948:
+   case 5950:
+   case 5952:
+   case 5954:
+   case 5956:
+   case 5958:
+   case 5960:
+   case 5962:
+   case 5964:
+   case 5966:
+   case 5968:
+   case 5970:
+   case 5972:
+   case 5974:
+   case 5976:
+   case 5978:
+   case 5980:
+   case 5982:
+   case 5984:
+   case 5986:
+   case 5988:
+   case 5990:
+   case 5992:
+   case 5994:
+   case 5996:
+   case 5998:
+   case 6e3:
+   case 6002:
+   case 6004:
+   case 6006:
+   case 6008:
+   case 6010:
+   case 6012:
+   case 6014:
+   case 6016:
+   case 6018:
+   case 6020:
+   case 6022:
+   case 6024:
+   case 6026:
+   case 6028:
+   case 6030:
+   case 6032:
+   case 6034:
+   case 6036:
+   case 6038:
+   case 6040:
+   case 6042:
+   case 6044:
+   case 6046:
+   case 6048:
+   case 6050:
+   case 6052:
+   case 6054:
+   case 6056:
+   case 6058:
+   case 6060:
+   case 6062:
+   case 6064:
+   case 6066:
+   case 6068:
+   case 6070:
+   case 6072:
+   case 6074:
+   case 6076:
+   case 6078:
+   case 6080:
+   case 6082:
+   case 6084:
+   case 6086:
+   case 6088:
+   case 6090:
+   case 6092:
+   case 6094:
+   case 6096:
+   case 6098:
+   case 6100:
+   case 6102:
+   case 6104:
+   case 6106:
+   case 6108:
+   case 6110:
+   case 6112:
+   case 6114:
+   case 6116:
+   case 6118:
+   case 6120:
+   case 6122:
+   case 6124:
+   case 6126:
+   case 6128:
+   case 6130:
+   case 6132:
+   case 6134:
+   case 6136:
+   case 6138:
+   case 6140:
+   case 6142:
+   case 6144:
+   case 6146:
+   case 6148:
+   case 6150:
+   case 6152:
+   case 6154:
+   case 6156:
+   case 6158:
+   case 6160:
+   case 6162:
+   case 6164:
+   case 6166:
+   case 6168:
+   case 6170:
+   case 6172:
+   case 6174:
+   case 6176:
+   case 6178:
+   case 6180:
+   case 6182:
+   case 6184:
+   case 6186:
+   case 6188:
+   case 6190:
+   case 6192:
+   case 6194:
+   case 6196:
+   case 6198:
+   case 6200:
+   case 6202:
+   case 6204:
+   case 6206:
+   case 6208:
+   case 6210:
+   case 6212:
+   case 6214:
+   case 6216:
+   case 6218:
+   case 6220:
+   case 6222:
+   case 6224:
+   case 6226:
+   case 6228:
+   case 6230:
+   case 6232:
+   case 6234:
+   case 6236:
+   case 6238:
+   case 6240:
+   case 6242:
+   case 6244:
+   case 6246:
+   case 6248:
+   case 6250:
+   case 6252:
+   case 6254:
+   case 6256:
+   case 6258:
+   case 6260:
+   case 6262:
+   case 6264:
+   case 6266:
+   case 6268:
+   case 6270:
+   case 6272:
+   case 6274:
+   case 6276:
+   case 6278:
+   case 6280:
+   case 6282:
+   case 6284:
+   case 6286:
+   case 6288:
+   case 6290:
+   case 6292:
+   case 6294:
+   case 6296:
+   case 6298:
+   case 6300:
+   case 6302:
+   case 6304:
+   case 6306:
+   case 6308:
+   case 6310:
+   case 6312:
+   case 6314:
+   case 6316:
+   case 6318:
+   case 6320:
+   case 6322:
+   case 6324:
+   case 6326:
+   case 6328:
+   case 6330:
+   case 6332:
+   case 6334:
+   case 6336:
+   case 6338:
+   case 6340:
+   case 6342:
+   case 6344:
+   case 6346:
+   case 6348:
+   case 6350:
+   case 6352:
+   case 6354:
+   case 6356:
+   case 6358:
+   case 6360:
+   case 6362:
+   case 6364:
+   case 6366:
+   case 6368:
+   case 6370:
+   case 6372:
+   case 6374:
+   case 6376:
+   case 6378:
+   case 6380:
+   case 6382:
+   case 6384:
+   case 6386:
+   case 6388:
+   case 6390:
+   case 6392:
+   case 6394:
+   case 6396:
+   case 6398:
+   case 6400:
+   case 6402:
+   case 6404:
+   case 6406:
+   case 6408:
+   case 6410:
+   case 6412:
+   case 6414:
+   case 6416:
+   case 6418:
+   case 6420:
+   case 6422:
+   case 6424:
+   case 6426:
+   case 6428:
+   case 6430:
+   case 6432:
+   case 6434:
+   case 6436:
+   case 6438:
+   case 6440:
+   case 6442:
+   case 6444:
+   case 6446:
+   case 6448:
+   case 6450:
+   case 6452:
+   case 6454:
+   case 6456:
+   case 6458:
+   case 6460:
+   case 6462:
+   case 6464:
+   case 6466:
+   case 6468:
+   case 6470:
+   case 6472:
+   case 6474:
+   case 6476:
+   case 6478:
+   case 6480:
+   case 6482:
+   case 6484:
+   case 6486:
+   case 6488:
+   case 6490:
+   case 6492:
+   case 6494:
+   case 6496:
+   case 6498:
+   case 6500:
+   case 6502:
+   case 6504:
+   case 6506:
+   case 6508:
+   case 6510:
+   case 6512:
+   case 6514:
+   case 6516:
+   case 6518:
+   case 6520:
+   case 6522:
+   case 6524:
+   case 6526:
+   case 6528:
+   case 6530:
+   case 6532:
+   case 6534:
+   case 6536:
+   case 6538:
+   case 6540:
+   case 6542:
+   case 6544:
+   case 6546:
+   case 6548:
+   case 6550:
+   case 6552:
+   case 6554:
+   case 6556:
+   case 6558:
+   case 6560:
+   case 6562:
+   case 6564:
+   case 6566:
+   case 6568:
+   case 6570:
+   case 6572:
+   case 6574:
+   case 6576:
+   case 6578:
+   case 6580:
+   case 6582:
+   case 6584:
+   case 6586:
+   case 6588:
+   case 6590:
+   case 6592:
+   case 6594:
+   case 6596:
+   case 6598:
+   case 6600:
+   case 6602:
+   case 6604:
+   case 6606:
+   case 6608:
+   case 6610:
+   case 6612:
+   case 6614:
+   case 6616:
+   case 6618:
+   case 6620:
+   case 6622:
+   case 6624:
+   case 6626:
+   case 6628:
+   case 6630:
+   case 6632:
+   case 6634:
+   case 6636:
+   case 6638:
+   case 6640:
+   case 6642:
+   case 6644:
+   case 6646:
+   case 6648:
+   case 6650:
+   case 6652:
+   case 6654:
+   case 6656:
+   case 6658:
+   case 6660:
+   case 6662:
+   case 6664:
+   case 6666:
+   case 6668:
+   case 6670:
+   case 6672:
+   case 6674:
+   case 6676:
+   case 6678:
+   case 6680:
+   case 6682:
+   case 6684:
+   case 6686:
+   case 6688:
+   case 6690:
+   case 6692:
+   case 6694:
+   case 6696:
+   case 6698:
+   case 6700:
+   case 6702:
+   case 6704:
+   case 6706:
+   case 6708:
+   case 6710:
+   case 6712:
+   case 6714:
+   case 6716:
+   case 6718:
+   case 6720:
+   case 6722:
+   case 6724:
+   case 6726:
+   case 6728:
+   case 6730:
+   case 6732:
+   case 6734:
+   case 6736:
+   case 6738:
+   case 6740:
+   case 6742:
+   case 6744:
+   case 6746:
+   case 6748:
+   case 6750:
+   case 6752:
+   case 6754:
+   case 6756:
+   case 6758:
+   case 6760:
+   case 6762:
+   case 6764:
+   case 6766:
+   case 6768:
+   case 6770:
+   case 6772:
+   case 6774:
+   case 6776:
+   case 6778:
+   case 6780:
+   case 6782:
+   case 6784:
+   case 6786:
+   case 6788:
+   case 6790:
+   case 6792:
+   case 6794:
+   case 6796:
+   case 6798:
+   case 6800:
+   case 6802:
+   case 6804:
+   case 6806:
+   case 6808:
+   case 6810:
+   case 6812:
+   case 6814:
+   case 6816:
+   case 6818:
+   case 6820:
+   case 6822:
+   case 6824:
+   case 6826:
+   case 6828:
+   case 6830:
+   case 6832:
+   case 6834:
+   case 6836:
+   case 6838:
+   case 6840:
+   case 6842:
+   case 6844:
+   case 6846:
+   case 6848:
+   case 6850:
+   case 6852:
+   case 6854:
+   case 6856:
+   case 6858:
+   case 6860:
+   case 6862:
+   case 6864:
+   case 6866:
+   case 6868:
+   case 6870:
+   case 6872:
+   case 6874:
+   case 6876:
+   case 6878:
+   case 6880:
+   case 6882:
+   case 6884:
+   case 6886:
+   case 6888:
+   case 6890:
+   case 6892:
+   case 6894:
+   case 6896:
+   case 6898:
+   case 6900:
+   case 6902:
+   case 6904:
+   case 6906:
+   case 6908:
+   case 6910:
+   case 6912:
+   case 6914:
+   case 6916:
+   case 6918:
+   case 6920:
+   case 6922:
+   case 6924:
+   case 6926:
+   case 6928:
+   case 6930:
+   case 6932:
+   case 6934:
+   case 6936:
+   case 6938:
+   case 6940:
+   case 6942:
+   case 6944:
+   case 6946:
+   case 6948:
+   case 6950:
+   case 6952:
+   case 6954:
+   case 6956:
+   case 6958:
+   case 6960:
+   case 6962:
+   case 6964:
+   case 6966:
+   case 6968:
+   case 6970:
+   case 6972:
+   case 6974:
+   case 6976:
+   case 6978:
+   case 6980:
+   case 6982:
+   case 6984:
+   case 6986:
+   case 6988:
+   case 6990:
+   case 6992:
+   case 6994:
+   case 6996:
+   case 6998:
+   case 7e3:
+   case 7002:
+   case 7004:
+   case 7006:
+   case 7008:
+   case 7010:
+   case 7012:
+   case 7014:
+   case 7016:
+   case 7018:
+   case 7020:
+   case 7022:
+   case 7024:
+   case 7026:
+   case 7028:
+   case 7030:
+   case 7032:
+   case 7034:
+   case 7036:
+   case 7038:
+   case 7040:
+   case 7042:
+   case 7044:
+   case 7046:
+   case 7048:
+   case 7050:
+   case 7052:
+   case 7054:
+   case 7056:
+   case 7058:
+   case 7060:
+   case 7062:
+   case 7064:
+   case 7066:
+   case 7068:
+   case 7070:
+   case 7072:
+   case 7074:
+   case 7076:
+   case 7078:
+   case 7080:
+   case 7082:
+   case 7084:
+   case 7086:
+   case 7088:
+   case 7090:
+   case 7092:
+   case 7094:
+   case 7096:
+   case 7098:
+   case 7100:
+   case 7102:
+   case 7104:
+   case 7106:
+   case 7108:
+   case 7110:
+   case 7112:
+   case 7114:
+   case 7116:
+   case 7118:
+   case 7120:
+   case 7122:
+   case 7124:
+   case 7126:
+   case 7128:
+   case 7130:
+   case 7132:
+   case 7134:
+   case 7136:
+   case 7138:
+   case 7140:
+   case 7142:
+   case 7144:
+   case 7146:
+   case 7148:
+   case 7150:
+   case 7152:
+   case 7154:
+   case 7156:
+   case 7158:
+   case 7160:
+   case 7162:
+   case 7164:
+   case 7166:
+   case 7168:
+   case 7170:
+   case 7172:
+   case 7174:
+   case 7176:
+   case 7178:
+   case 7180:
+   case 7182:
+   case 7184:
+   case 7186:
+   case 7188:
+   case 7190:
+   case 7192:
+   case 7194:
+   case 7196:
+   case 7198:
+   case 7200:
+   case 7202:
+   case 7204:
+   case 7206:
+   case 7208:
+   case 7210:
+   case 7212:
+   case 7214:
+   case 7216:
+   case 7218:
+   case 7220:
+   case 7222:
+   case 7224:
+   case 7226:
+   case 7228:
+   case 7230:
+   case 7232:
+   case 7234:
+   case 7236:
+   case 7238:
+   case 7240:
+   case 7242:
+   case 7244:
+   case 7246:
+   case 7248:
+   case 7250:
+   case 7252:
+   case 7254:
+   case 7256:
+   case 7258:
+   case 7260:
+   case 7262:
+   case 7264:
+   case 7266:
+   case 7268:
+   case 7270:
+   case 7272:
+   case 7274:
+   case 7276:
+   case 7278:
+   case 7280:
+   case 7282:
+   case 7284:
+   case 7286:
+   case 7288:
+   case 7290:
+   case 7292:
+   case 7294:
+   case 7296:
+   case 7298:
+   case 7300:
+   case 7302:
+   case 7304:
+   case 7306:
+   case 7308:
+   case 7310:
+   case 7312:
+   case 7314:
+   case 7316:
+   case 7318:
+   case 7320:
+   case 7322:
+   case 7324:
+   case 7326:
+   case 7328:
+   case 7330:
+   case 7332:
+   case 7334:
+   case 7336:
+   case 7338:
+   case 7340:
+   case 7342:
+   case 7344:
+   case 7346:
+   case 7348:
+   case 7350:
+   case 7352:
+   case 7354:
+   case 7356:
+   case 7358:
+   case 7360:
+   case 7362:
+   case 7364:
+   case 7366:
+   case 7368:
+   case 7370:
+   case 7372:
+   case 7374:
+   case 7376:
+   case 7378:
+   case 7380:
+   case 7382:
+   case 7384:
+   case 7386:
+   case 7388:
+   case 7390:
+   case 7392:
+   case 7394:
+   case 7396:
+   case 7398:
+   case 7400:
+   case 7402:
+   case 7404:
+   case 7406:
+   case 7408:
+   case 7410:
+   case 7412:
+   case 7414:
+   case 7416:
+   case 7418:
+   case 7420:
+   case 7422:
+   case 7424:
+   case 7426:
+   case 7428:
+   case 7430:
+   case 7432:
+   case 7434:
+   case 7436:
+   case 7438:
+   case 7440:
+   case 7442:
+   case 7444:
+   case 7446:
+   case 7448:
+   case 7450:
+   case 7452:
+   case 7454:
+   case 7456:
+   case 7458:
+   case 7460:
+   case 7462:
+   case 7464:
+   case 7466:
+   case 7468:
+   case 7470:
+   case 7472:
+   case 7474:
+   case 7476:
+   case 7478:
+   case 7480:
+   case 7482:
+   case 7484:
+   case 7486:
+   case 7488:
+   case 7490:
+   case 7492:
+   case 7494:
+   case 7496:
+   case 7498:
+   case 7500:
+   case 7502:
+   case 7504:
+   case 7506:
+   case 7508:
+   case 7510:
+   case 7512:
+   case 7514:
+   case 7516:
+   case 7518:
+   case 7520:
+   case 7522:
+   case 7524:
+   case 7526:
+   case 7528:
+   case 7530:
+   case 7532:
+   case 7534:
+   case 7536:
+   case 7538:
+   case 7540:
+   case 7542:
+   case 7544:
+   case 7546:
+   case 7548:
+   case 7550:
+   case 7552:
+   case 7554:
+   case 7556:
+   case 7558:
+   case 7560:
+   case 7562:
+   case 7564:
+   case 7566:
+   case 7568:
+   case 7570:
+   case 7572:
+   case 7574:
+   case 7576:
+   case 7578:
+   case 7580:
+   case 7582:
+   case 7584:
+   case 7586:
+   case 7588:
+   case 7590:
+   case 7592:
+   case 7594:
+   case 7596:
+   case 7598:
+   case 7600:
+   case 7602:
+   case 7604:
+   case 7606:
+   case 7608:
+   case 7610:
+   case 7612:
+   case 7614:
+   case 7616:
+   case 7618:
+   case 7620:
+   case 7622:
+   case 7624:
+   case 7626:
+   case 7628:
+   case 7630:
+   case 7632:
+   case 7634:
+   case 7636:
+   case 7638:
+   case 7640:
+   case 7642:
+   case 7644:
+   case 7646:
+   case 7648:
+   case 7650:
+   case 7652:
+   case 7654:
+   case 7656:
+   case 7658:
+   case 7660:
+   case 7662:
+   case 7664:
+   case 7666:
+   case 7668:
+   case 7670:
+   case 7672:
+   case 7674:
+   case 7676:
+   case 7678:
+   case 7680:
+   case 7682:
+   case 7684:
+   case 7686:
+   case 7688:
+   case 7690:
+   case 7692:
+   case 7694:
+   case 7696:
+   case 7698:
+   case 7700:
+   case 7702:
+   case 7704:
+   case 7706:
+   case 7708:
+   case 7710:
+   case 7712:
+   case 7714:
+   case 7716:
+   case 7718:
+   case 7720:
+   case 7722:
+   case 7724:
+   case 7726:
+   case 7728:
+   case 7730:
+   case 7732:
+   case 7734:
+   case 7736:
+   case 7738:
+   case 7740:
+   case 7742:
+   case 7744:
+   case 7746:
+   case 7748:
+   case 7750:
+   case 7752:
+   case 7754:
+   case 7756:
+   case 7758:
+   case 7760:
+   case 7762:
+   case 7764:
+   case 7766:
+   case 7768:
+   case 7770:
+   case 7772:
+   case 7774:
+   case 7776:
+   case 7778:
+   case 7780:
+   case 7782:
+   case 7784:
+   case 7786:
+   case 7788:
+   case 7790:
+   case 7792:
+   case 7794:
+   case 7796:
+   case 7798:
+   case 7800:
+   case 7802:
+   case 7804:
+   case 7806:
+   case 7808:
+   case 7810:
+   case 7812:
+   case 7814:
+   case 7816:
+   case 7818:
+   case 7820:
+   case 7822:
+   case 7824:
+   case 7826:
+   case 7828:
+   case 7830:
+   case 7832:
+   case 7834:
+   case 7836:
+   case 7838:
+   case 7840:
+   case 7842:
+   case 7844:
+   case 7846:
+   case 7848:
+   case 7850:
+   case 7852:
+   case 7854:
+   case 7856:
+   case 7858:
+   case 7860:
+   case 7862:
+   case 7864:
+   case 7866:
+   case 7868:
+   case 7870:
+   case 7872:
+   case 7874:
+   case 7876:
+   case 7878:
+   case 7880:
+   case 7882:
+   case 7884:
+   case 7886:
+   case 7888:
+   case 7890:
+   case 7892:
+   case 7894:
+   case 7896:
+   case 7898:
+   case 7900:
+   case 7902:
+   case 7904:
+   case 7906:
+   case 7908:
+   case 7910:
+   case 7912:
+   case 7914:
+   case 7916:
+   case 7918:
+   case 7920:
+   case 7922:
+   case 7924:
+   case 7926:
+   case 7928:
+   case 7930:
+   case 7932:
+   case 7934:
+   case 7936:
+   case 7938:
+   case 7940:
+   case 7942:
+   case 7944:
+   case 7946:
+   case 7948:
+   case 7950:
+   case 7952:
+   case 7954:
+   case 7956:
+   case 7958:
+   case 7960:
+   case 7962:
+   case 7964:
+   case 7966:
+   case 7968:
+   case 7970:
+   case 7972:
+   case 7974:
+   case 7976:
+   case 7978:
+   case 7980:
+   case 7982:
+   case 7984:
+   case 7986:
+   case 7988:
+   case 7990:
+   case 7992:
+   case 7994:
+   case 7996:
+   case 7998:
+   case 8e3:
+   case 8002:
+   case 8004:
+   case 8006:
+   case 8008:
+   case 8010:
+   case 8012:
+   case 8014:
+   case 8016:
+   case 8018:
+   case 8020:
+   case 8022:
+   case 8024:
+   case 8026:
+   case 8028:
+   case 8030:
+   case 8032:
+   case 8034:
+   case 8036:
+   case 8038:
+   case 8040:
+   case 8042:
+   case 8044:
+   case 8046:
+   case 8048:
+   case 8050:
+   case 8052:
+   case 8054:
+   case 8056:
+   case 8058:
+   case 8060:
+   case 8062:
+   case 8064:
+   case 8066:
+   case 8068:
+   case 8070:
+   case 8072:
+   case 8074:
+   case 8076:
+   case 8078:
+   case 8080:
+   case 8082:
+   case 8084:
+   case 8086:
+   case 8088:
+   case 8090:
+   case 8092:
+   case 8094:
+   case 8096:
+   case 8098:
+   case 8100:
+   case 8102:
+   case 8104:
+   case 8106:
+   case 8108:
+   case 8110:
+   case 8112:
+   case 8114:
+   case 8116:
+   case 8118:
+   case 8120:
+   case 8122:
+   case 8124:
+   case 8126:
+   case 8128:
+   case 8130:
+   case 8132:
+   case 8134:
+   case 8136:
+   case 8138:
+   case 8140:
+   case 8142:
+   case 8144:
+   case 8146:
+   case 8148:
+   case 8150:
+   case 8152:
+   case 8154:
+   case 8156:
+   case 8158:
+   case 8160:
+   case 8162:
+   case 8164:
+   case 8166:
+   case 8168:
+   case 8170:
+   case 8172:
+   case 8174:
+   case 8176:
+   case 8178:
+   case 8180:
+   case 8182:
+   case 8184:
+   case 8186:
+   case 8188:
+   case 8190:
+   case 8192:
+   case 8194:
+   case 8196:
+   case 8198:
+   case 8200:
+   case 8202:
+   case 8204:
+   case 8206:
+   case 8208:
+   case 8210:
+   case 8212:
+   case 8214:
+   case 8216:
+   case 8218:
+   case 8220:
+   case 8222:
+   case 8224:
+   case 8226:
+   case 8228:
+   case 8230:
+   case 8232:
+   case 8234:
+   case 8236:
+   case 8238:
+   case 8240:
+   case 8242:
+   case 8244:
+   case 8246:
+   case 8248:
+   case 8250:
+   case 8252:
+   case 8254:
+   case 8256:
+   case 8258:
+   case 8260:
+   case 8262:
+   case 8264:
+   case 8266:
+   case 8268:
+   case 8270:
+   case 8272:
+   case 8274:
+   case 8276:
+   case 8278:
+   case 8280:
+   case 8282:
+   case 8284:
+   case 8286:
+   case 8288:
+   case 8290:
+   case 8292:
+   case 8294:
+   case 8296:
+   case 8298:
+   case 8300:
+   case 8302:
+   case 8304:
+   case 8306:
+   case 8308:
+   case 8310:
+   case 8312:
+   case 8314:
+   case 8316:
+   case 8318:
+   case 8320:
+   case 8322:
+   case 8324:
+   case 8326:
+   case 8328:
+   case 8330:
+   case 8332:
+   case 8334:
+   case 8336:
+   case 8338:
+   case 8340:
+   case 8342:
+   case 8344:
+   case 8346:
+   case 8348:
+   case 8350:
+   case 8352:
+   case 8354:
+   case 8356:
+   case 8358:
+   case 8360:
+   case 8362:
+   case 8364:
+   case 8366:
+   case 8368:
+   case 8370:
+   case 8372:
+   case 8374:
+   case 8376:
+   case 8378:
+   case 8380:
+   case 8382:
+   case 8384:
+   case 8386:
+   case 8388:
+   case 8390:
+   case 8392:
+   case 8394:
+   case 8396:
+   case 8398:
+   case 8400:
+   case 8402:
+   case 8404:
+   case 8406:
+   case 8408:
+   case 8410:
+   case 8412:
+   case 8414:
+   case 8416:
+   case 8418:
+   case 8420:
+   case 8422:
+   case 8424:
+   case 8426:
+   case 8428:
+   case 8430:
+   case 8432:
+   case 8434:
+   case 8436:
+   case 8438:
+   case 8440:
+   case 8442:
+   case 8444:
+   case 8446:
+   case 8448:
+   case 8450:
+   case 8452:
+   case 8454:
+   case 8456:
+   case 8458:
+   case 8460:
+   case 8462:
+   case 8464:
+   case 8466:
+   case 8468:
+   case 8470:
+   case 8472:
+   case 8474:
+   case 8476:
+   case 8478:
+   case 8480:
+   case 8482:
+   case 8484:
+   case 8486:
+   case 8488:
+   case 8490:
+   case 8492:
+   case 8494:
+   case 8496:
+   case 8498:
+   case 8500:
+   case 8502:
+   case 8504:
+   case 8506:
+   case 8508:
+   case 8510:
+   case 8512:
+   case 8514:
+   case 8516:
+   case 8518:
+   case 8520:
+   case 8522:
+   case 8524:
+   case 8526:
+   case 8528:
+   case 8530:
+   case 8532:
+   case 8534:
+   case 8536:
+   case 8538:
+   case 8540:
+   case 8542:
+   case 8544:
+   case 8546:
+   case 8548:
+   case 8550:
+   case 8552:
+   case 8554:
+   case 8556:
+   case 8558:
+   case 8560:
+   case 8562:
+   case 8564:
+   case 8566:
+   case 8568:
+   case 8570:
+   case 8572:
+   case 8574:
+   case 8576:
+   case 8578:
+   case 8580:
+   case 8582:
+   case 8584:
+   case 8586:
+   case 8588:
+   case 8590:
+   case 8592:
+   case 8594:
+   case 8596:
+   case 8598:
+   case 8600:
+   case 8602:
+   case 8604:
+   case 8606:
+   case 8608:
+   case 8610:
+   case 8612:
+   case 8614:
+   case 8616:
+   case 8618:
+   case 8620:
+   case 8622:
+   case 8624:
+   case 8626:
+   case 8628:
+   case 8630:
+   case 8632:
+   case 8634:
+   case 8636:
+   case 8638:
+   case 8640:
+   case 8642:
+   case 8644:
+   case 8646:
+   case 8648:
+   case 8650:
+   case 8652:
+   case 8654:
+   case 8656:
+   case 8658:
+   case 8660:
+   case 8662:
+   case 8664:
+   case 8666:
+   case 8668:
+   case 8670:
+   case 8672:
+   case 8674:
+   case 8676:
+   case 8678:
+   case 8680:
+   case 8682:
+   case 8684:
+   case 8686:
+   case 8688:
+   case 8690:
+   case 8692:
+   case 8694:
+   case 8696:
+   case 8698:
+   case 8700:
+   case 8702:
+   case 8704:
+   case 8706:
+   case 8708:
+   case 8710:
+   case 8712:
+   case 8714:
+   case 8716:
+   case 8718:
+   case 8720:
+   case 8722:
+   case 8724:
+   case 8726:
+   case 8728:
+   case 8730:
+   case 8732:
+   case 8734:
+   case 8736:
+   case 8738:
+   case 8740:
+   case 8742:
+   case 8744:
+   case 8746:
+   case 8748:
+   case 8750:
+   case 8752:
+   case 8754:
+   case 8756:
+   case 8758:
+   case 8760:
+   case 8762:
+   case 8764:
+   case 8766:
+   case 8768:
+   case 8770:
+   case 8772:
+   case 8774:
+   case 8776:
+   case 8778:
+   case 8780:
+   case 8782:
+   case 8784:
+   case 8786:
+   case 8788:
+   case 8790:
+   case 8792:
+   case 8794:
+   case 8796:
+   case 8798:
+   case 8800:
+   case 8802:
+   case 8804:
+   case 8806:
+   case 8808:
+   case 8810:
+   case 8812:
+   case 8814:
+   case 8816:
+   case 8818:
+   case 8820:
+   case 8822:
+   case 8824:
+   case 8826:
+   case 8828:
+   case 8830:
+   case 8832:
+   case 8834:
+   case 8836:
+   case 8838:
+   case 8840:
+   case 8842:
+   case 8844:
+   case 8846:
+   case 8848:
+   case 8850:
+   case 8852:
+   case 8854:
+   case 8856:
+   case 8858:
+   case 8860:
+   case 8862:
+   case 8864:
+   case 8866:
+   case 8868:
+   case 8870:
+   case 8872:
+   case 8874:
+   case 8876:
+   case 8878:
+   case 8880:
+   case 8882:
+   case 8884:
+   case 8886:
+   case 8888:
+   case 8890:
+   case 8892:
+   case 8894:
+   case 8896:
+   case 8898:
+   case 8900:
+   case 8902:
+   case 8904:
+   case 8906:
+   case 8908:
+   case 8910:
+   case 8912:
+   case 8914:
+   case 8916:
+   case 8918:
+   case 8920:
+   case 8922:
+   case 8924:
+   case 8926:
+   case 8928:
+   case 8930:
+   case 8932:
+   case 8934:
+   case 8936:
+   case 8938:
+   case 8940:
+   case 8942:
+   case 8944:
+   case 8946:
+   case 8948:
+   case 8950:
+   case 8952:
+   case 8954:
+   case 8956:
+   case 8958:
+   case 8960:
+   case 8962:
+   case 8964:
+   case 8966:
+   case 8968:
+   case 8970:
+   case 8972:
+   case 8974:
+   case 8976:
+   case 8978:
+   case 8980:
+   case 8982:
+   case 8984:
+   case 8986:
+   case 8988:
+   case 8990:
+   case 8992:
+   case 8994:
+   case 8996:
+   case 8998:
+   case 9e3:
+   case 9002:
+   case 9004:
+   case 9006:
+   case 9008:
+   case 9010:
+   case 9012:
+   case 9014:
+   case 9016:
+   case 9018:
+   case 9020:
+   case 9022:
+   case 9024:
+   case 9026:
+   case 9028:
+   case 9030:
+   case 9032:
+   case 9034:
+   case 9036:
+   case 9038:
+   case 9040:
+   case 9042:
+   case 9044:
+   case 9046:
+   case 9048:
+   case 9050:
+   case 9052:
+   case 9054:
+   case 9056:
+   case 9058:
+   case 9060:
+   case 9062:
+   case 9064:
+   case 9066:
+   case 9068:
+   case 9070:
+   case 9072:
+   case 9074:
+   case 9076:
+   case 9078:
+   case 9080:
+   case 9082:
+   case 9084:
+   case 9086:
+   case 9088:
+   case 9090:
+   case 9092:
+   case 9094:
+   case 9096:
+   case 9098:
+   case 9100:
+   case 9102:
+   case 9104:
+   case 9106:
+   case 9108:
+   case 9110:
+   case 9112:
+   case 9114:
+   case 9116:
+   case 9118:
+   case 9120:
+   case 9122:
+   case 9124:
+   case 9126:
+   case 9128:
+   case 9130:
+   case 9132:
+   case 9134:
+   case 9136:
+   case 9138:
+   case 9140:
+   case 9142:
+   case 9144:
+   case 9146:
+   case 9148:
+   case 9150:
+   case 9152:
+   case 9154:
+   case 9156:
+   case 9158:
+   case 9160:
+   case 9162:
+   case 9164:
+   case 9166:
+   case 9168:
+   case 9170:
+   case 9172:
+   case 9174:
+   case 9176:
+   case 9178:
+   case 9180:
+   case 9182:
+   case 9184:
+   case 9186:
+   case 9188:
+   case 9190:
+   case 9192:
+   case 9194:
+   case 9196:
+   case 9198:
+   case 9200:
+   case 9202:
+   case 9204:
+   case 9206:
+   case 9208:
+   case 9210:
+   case 9212:
+   case 9214:
+   case 9216:
+   case 9218:
+   case 9220:
+   case 9222:
+   case 9224:
+   case 9226:
+   case 9228:
+   case 9230:
+   case 9232:
+   case 9234:
+   case 9236:
+   case 9238:
+   case 9240:
+   case 9242:
+   case 9244:
+   case 9246:
+   case 9248:
+   case 9250:
+   case 9252:
+   case 9254:
+   case 9256:
+   case 9258:
+   case 9260:
+   case 9262:
+   case 9264:
+   case 9266:
+   case 9268:
+   case 9270:
+   case 9272:
+   case 9274:
+   case 9276:
+   case 9278:
+   case 9280:
+   case 9282:
+   case 9284:
+   case 9286:
+   case 9288:
+   case 9290:
+   case 9292:
+   case 9294:
+   case 9296:
+   case 9298:
+   case 9300:
+   case 9302:
+   case 9304:
+   case 9306:
+   case 9308:
+   case 9310:
+   case 9312:
+   case 9314:
+   case 9316:
+   case 9318:
+   case 9320:
+   case 9322:
+   case 9324:
+   case 9326:
+   case 9328:
+   case 9330:
+   case 9332:
+   case 9334:
+   case 9336:
+   case 9338:
+   case 9340:
+   case 9342:
+   case 9344:
+   case 9346:
+   case 9348:
+   case 9350:
+   case 9352:
+   case 9354:
+   case 9356:
+   case 9358:
+   case 9360:
+   case 9362:
+   case 9364:
+   case 9366:
+   case 9368:
+   case 9370:
+   case 9372:
+   case 9374:
+   case 9376:
+   case 9378:
+   case 9380:
+   case 9382:
+   case 9384:
+   case 9386:
+   case 9388:
+   case 9390:
+   case 9392:
+   case 9394:
+   case 9396:
+   case 9398:
+   case 9400:
+   case 9402:
+   case 9404:
+   case 9406:
+   case 9408:
+   case 9410:
+   case 9412:
+   case 9414:
+   case 9416:
+   case 9418:
+   case 9420:
+   case 9422:
+   case 9424:
+   case 9426:
+   case 9428:
+   case 9430:
+   case 9432:
+   case 9434:
+   case 9436:
+   case 9438:
+   case 9440:
+   case 9442:
+   case 9444:
+   case 9446:
+   case 9448:
+   case 9450:
+   case 9452:
+   case 9454:
+   case 9456:
+   case 9458:
+   case 9460:
+   case 9462:
+   case 9464:
+   case 9466:
+   case 9468:
+   case 9470:
+   case 9472:
+   case 9474:
+   case 9476:
+   case 9478:
+   case 9480:
+   case 9482:
+   case 9484:
+   case 9486:
+   case 9488:
+   case 9490:
+   case 9492:
+   case 9494:
+   case 9496:
+   case 9498:
+   case 9500:
+   case 9502:
+   case 9504:
+   case 9506:
+   case 9508:
+   case 9510:
+   case 9512:
+   case 9514:
+   case 9516:
+   case 9518:
+   case 9520:
+   case 9522:
+   case 9524:
+   case 9526:
+   case 9528:
+   case 9530:
+   case 9532:
+   case 9534:
+   case 9536:
+   case 9538:
+   case 9540:
+   case 9542:
+   case 9544:
+   case 9546:
+   case 9548:
+   case 9550:
+   case 9552:
+   case 9554:
+   case 9556:
+   case 9558:
+   case 9560:
+   case 9562:
+   case 9564:
+   case 9566:
+   case 9568:
+   case 9570:
+   case 9572:
+   case 9574:
+   case 9576:
+   case 9578:
+   case 9580:
+   case 9582:
+   case 9584:
+   case 9586:
+   case 9588:
+   case 9590:
+   case 9592:
+   case 9594:
+   case 9596:
+   case 9598:
+   case 9600:
+   case 9602:
+   case 9604:
+   case 9606:
+   case 9608:
+   case 9610:
+   case 9612:
+   case 9614:
+   case 9616:
+   case 9618:
+   case 9620:
+   case 9622:
+   case 9624:
+   case 9626:
+   case 9628:
+   case 9630:
+   case 9632:
+   case 9634:
+   case 9636:
+   case 9638:
+   case 9640:
+   case 9642:
+   case 9644:
+   case 9646:
+   case 9648:
+   case 9650:
+   case 9652:
+   case 9654:
+   case 9656:
+   case 9658:
+   case 9660:
+   case 9662:
+   case 9664:
+   case 9666:
+   case 9668:
+   case 9670:
+   case 9672:
+   case 9674:
+   case 9676:
+   case 9678:
+   case 9680:
+   case 9682:
+   case 9684:
+   case 9686:
+   case 9688:
+   case 9690:
+   case 9692:
+   case 9694:
+   case 9696:
+   case 9698:
+   case 9700:
+   case 9702:
+   case 9704:
+   case 9706:
+   case 9708:
+   case 9710:
+   case 9712:
+   case 9714:
+   case 9716:
+   case 9718:
+   case 9720:
+   case 9722:
+   case 9724:
+   case 9726:
+   case 9728:
+   case 9730:
+   case 9732:
+   case 9734:
+   case 9736:
+   case 9738:
+   case 9740:
+   case 9742:
+   case 9744:
+   case 9746:
+   case 9748:
+   case 9750:
+   case 9752:
+   case 9754:
+   case 9756:
+   case 9758:
+   case 9760:
+   case 9762:
+   case 9764:
+   case 9766:
+   case 9768:
+   case 9770:
+   case 9772:
+   case 9774:
+   case 9776:
+   case 9778:
+   case 9780:
+   case 9782:
+   case 9784:
+   case 9786:
+   case 9788:
+   case 9790:
+   case 9792:
+   case 9794:
+   case 9796:
+   case 9798:
+   case 9800:
+   case 9802:
+   case 9804:
+   case 9806:
+   case 9808:
+   case 9810:
+   case 9812:
+   case 9814:
+   case 9816:
+   case 9818:
+   case 9820:
+   case 9822:
+   case 9824:
+   case 9826:
+   case 9828:
+   case 9830:
+   case 9832:
+   case 9834:
+   case 9836:
+   case 9838:
+   case 9840:
+   case 9842:
+   case 9844:
+   case 9846:
+   case 9848:
+   case 9850:
+   case 9852:
+   case 9854:
+   case 9856:
+   case 9858:
+   case 9860:
+   case 9862:
+   case 9864:
+   case 9866:
+   case 9868:
+   case 9870:
+   case 9872:
+   case 9874:
+   case 9876:
+   case 9878:
+   case 9880:
+   case 9882:
+   case 9884:
+   case 9886:
+   case 9888:
+   case 9890:
+   case 9892:
+   case 9894:
+   case 9896:
+   case 9898:
+   case 9900:
+   case 9902:
+   case 9904:
+   case 9906:
+   case 9908:
+   case 9910:
+   case 9912:
+   case 9914:
+   case 9916:
+   case 9918:
+   case 9920:
+   case 9922:
+   case 9924:
+   case 9926:
+   case 9928:
+   case 9930:
+   case 9932:
+   case 9934:
+   case 9936:
+   case 9938:
+   case 9940:
+   case 9942:
+   case 9944:
+   case 9946:
+   case 9948:
+   case 9950:
+   case 9952:
+   case 9954:
+   case 9956:
+   case 9958:
+   case 9960:
+   case 9962:
+   case 9964:
+   case 9966:
+   case 9968:
+   case 9970:
+   case 9972:
+   case 9974:
+   case 9976:
+   case 9978:
+   case 9980:
+   case 9982:
+   case 9984:
+   case 9986:
+   case 9988:
+   case 9990:
+   case 9992:
+   case 9994:
+   case 9996:
+   case 9998:
+   case 1e4:
+   case 10002:
+   case 10004:
+   case 10006:
+   case 10008:
+   case 10010:
+   case 10012:
+   case 10014:
+   case 10016:
+   case 10018:
+   case 10020:
+   case 10022:
+   case 10024:
+   case 10026:
+   case 10028:
+   case 10030:
+   case 10032:
+   case 10034:
+   case 10036:
+   case 10038:
+   case 10040:
+   case 10042:
+   case 10044:
+   case 10046:
+   case 10048:
+   case 10050:
+   case 10052:
+   case 10054:
+   case 10056:
+   case 10058:
+   case 10060:
+   case 10062:
+   case 10064:
+   case 10066:
+   case 10068:
+   case 10070:
+   case 10072:
+   case 10074:
+   case 10076:
+   case 10078:
+   case 10080:
+   case 10082:
+   case 10084:
+   case 10086:
+   case 10088:
+   case 10090:
+   case 10092:
+   case 10094:
+   case 10096:
+   case 10098:
+   case 10100:
+   case 10102:
+   case 10104:
+   case 10106:
+   case 10108:
+   case 10110:
+   case 10112:
+   case 10114:
+   case 10116:
+   case 10118:
+   case 10120:
+   case 10122:
+   case 10124:
+   case 10126:
+   case 10128:
+   case 10130:
+   case 10132:
+   case 10134:
+   case 10136:
+   case 10138:
+   case 10140:
+   case 10142:
+   case 10144:
+   case 10146:
+   case 10148:
+   case 10150:
+   case 10152:
+   case 10154:
+   case 10156:
+   case 10158:
+   case 10160:
+   case 10162:
+   case 10164:
+   case 10166:
+   case 10168:
+   case 10170:
+   case 10172:
+   case 10174:
+   case 10176:
+   case 10178:
+   case 10180:
+   case 10182:
+   case 10184:
+   case 10186:
+   case 10188:
+   case 10190:
+   case 10192:
+   case 10194:
+   case 10196:
+   case 10198:
+   case 10200:
+   case 10202:
+   case 10204:
+   case 10206:
+   case 10208:
+   case 10210:
+   case 10212:
+   case 10214:
+   case 10216:
+   case 10218:
+   case 10220:
+   case 10222:
+   case 10224:
+   case 10226:
+   case 10228:
+   case 10230:
+   case 10232:
+   case 10234:
+   case 10236:
+   case 10238:
+   case 10240:
+   case 10242:
+   case 10244:
+   case 10246:
+   case 10248:
+   case 10250:
+   case 10252:
+   case 10254:
+   case 10256:
+   case 10258:
+   case 10260:
+   case 10262:
+   case 10264:
+   case 10266:
+   case 10268:
+   case 10270:
+   case 10272:
+   case 10274:
+   case 10276:
+   case 10278:
+   case 10280:
+   case 10282:
+   case 10284:
+   case 10286:
+   case 10288:
+   case 10290:
+   case 10292:
+   case 10294:
+   case 10296:
+   case 10298:
+   case 10300:
+   case 10302:
+   case 10304:
+   case 10306:
+   case 10308:
+   case 10310:
+   case 10312:
+   case 10314:
+   case 10316:
+   case 10318:
+   case 10320:
+   case 10322:
+   case 10324:
+   case 10326:
+   case 10328:
+   case 10330:
+   case 10332:
+   case 10334:
+   case 10336:
+   case 10338:
+   case 10340:
+   case 10342:
+   case 10344:
+   case 10346:
+   case 10348:
+   case 10350:
+   case 10352:
+   case 10354:
+   case 10356:
+   case 10358:
+   case 10360:
+   case 10362:
+   case 10364:
+   case 10366:
+   case 10368:
+   case 10370:
+   case 10372:
+   case 10374:
+   case 10376:
+   case 10378:
+   case 10380:
+   case 10382:
+   case 10384:
+   case 10386:
+   case 10388:
+   case 10390:
+   case 10392:
+   case 10394:
+   case 10396:
+   case 10398:
+   case 10400:
+   case 10402:
+   case 10404:
+   case 10406:
+   case 10408:
+   case 10410:
+   case 10412:
+   case 10414:
+   case 10416:
+   case 10418:
+   case 10420:
+   case 10422:
+   case 10424:
+   case 10426:
+   case 10428:
+   case 10430:
+   case 10432:
+   case 10434:
+   case 10436:
+   case 10438:
+   case 10440:
+   case 10442:
+   case 10444:
+   case 10446:
+   case 10448:
+   case 10450:
+   case 10452:
+   case 10454:
+   case 10456:
+   case 10458:
+   case 10460:
+   case 10462:
+   case 10464:
+   case 10466:
+   case 10468:
+   case 10470:
+   case 10472:
+   case 10474:
+   case 10476:
+   case 10478:
+   case 10480:
+   case 10482:
+   case 10484:
+   case 10486:
+   case 10488:
+   case 10490:
+   case 10492:
+   case 10494:
+   case 10496:
+   case 10498:
+   case 10500:
+   case 10502:
+   case 10504:
+   case 10506:
+   case 10508:
+   case 10510:
+   case 10512:
+   case 10514:
+   case 10516:
+   case 10518:
+   case 10520:
+   case 10522:
+   case 10524:
+   case 10526:
+   case 10528:
+   case 10530:
+   case 10532:
+   case 10534:
+   case 10536:
+   case 10538:
+   case 10540:
+   case 10542:
+   case 10544:
+   case 10546:
+   case 10548:
+   case 10550:
+   case 10552:
+   case 10554:
+   case 10556:
+   case 10558:
+   case 10560:
+   case 10562:
+   case 10564:
+   case 10566:
+   case 10568:
+   case 10570:
+   case 10572:
+   case 10574:
+   case 10576:
+   case 10578:
+   case 10580:
+   case 10582:
+   case 10584:
+   case 10586:
+   case 10588:
+   case 10590:
+   case 10592:
+   case 10594:
+   case 10596:
+   case 10598:
+   case 10600:
+   case 10602:
+   case 10604:
+   case 10606:
+   case 10608:
+   case 10610:
+   case 10612:
+   case 10614:
+   case 10616:
+   case 10618:
+   case 10620:
+   case 10622:
+   case 10624:
+   case 10626:
+   case 10628:
+   case 10630:
+   case 10632:
+   case 10634:
+   case 10636:
+   case 10638:
+   case 10640:
+   case 10642:
+   case 10644:
+   case 10646:
+   case 10648:
+   case 10650:
+   case 10652:
+   case 10654:
+   case 10656:
+   case 10658:
+   case 10660:
+   case 10662:
+   case 10664:
+   case 10666:
+   case 10668:
+   case 10670:
+   case 10672:
+   case 10674:
+   case 10676:
+   case 10678:
+   case 10680:
+   case 10682:
+   case 10684:
+   case 10686:
+   case 10688:
+   case 10690:
+   case 10692:
+   case 10694:
+   case 10696:
+   case 10698:
+   case 10700:
+   case 10702:
+   case 10704:
+   case 10706:
+   case 10708:
+   case 10710:
+   case 10712:
+   case 10714:
+   case 10716:
+   case 10718:
+   case 10720:
+   case 10722:
+   case 10724:
+   case 10726:
+   case 10728:
+   case 10730:
+   case 10732:
+   case 10734:
+   case 10736:
+   case 10738:
+   case 10740:
+   case 10742:
+   case 10744:
+   case 10746:
+   case 10748:
+   case 10750:
+   case 10752:
+   case 10754:
+   case 10756:
+   case 10758:
+   case 10760:
+   case 10762:
+   case 10764:
+   case 10766:
+   case 10768:
+   case 10770:
+   case 10772:
+   case 10774:
+   case 10776:
+   case 10778:
+   case 10780:
+   case 10782:
+   case 10784:
+   case 10786:
+   case 10788:
+   case 10790:
+   case 10792:
+   case 10794:
+   case 10796:
+   case 10798:
+   case 10800:
+   case 10802:
+   case 10804:
+   case 10806:
+   case 10808:
+   case 10810:
+   case 10812:
+   case 10814:
+   case 10816:
+   case 10818:
+   case 10820:
+   case 10822:
+   case 10824:
+   case 10826:
+   case 10828:
+   case 10830:
+   case 10832:
+   case 10834:
+   case 10836:
+   case 10838:
+   case 10840:
+   case 10842:
+   case 10844:
+   case 10846:
+   case 10848:
+   case 10850:
+   case 10852:
+   case 10854:
+   case 10856:
+   case 10858:
+   case 10860:
+   case 10862:
+   case 10864:
+   case 10866:
+   case 10868:
+   case 10870:
+   case 10872:
+   case 10874:
+   case 10876:
+   case 10878:
+   case 10880:
+   case 10882:
+   case 10884:
+   case 10886:
+   case 10888:
+   case 10890:
+   case 10892:
+   case 10894:
+   case 10896:
+   case 10898:
+   case 10900:
+   case 10902:
+   case 10904:
+   case 10906:
+   case 10908:
+   case 10910:
+   case 10912:
+   case 10914:
+   case 10916:
+   case 10918:
+   case 10920:
+   case 10922:
+   case 10924:
+   case 10926:
+   case 10928:
+   case 10930:
+   case 10932:
+   case 10934:
+   case 10936:
+   case 10938:
+   case 10940:
+   case 10942:
+   case 10944:
+   case 10946:
+   case 10948:
+   case 10950:
+   case 10952:
+   case 10954:
+   case 10956:
+   case 10958:
+   case 10960:
+   case 10962:
+   case 10964:
+   case 10966:
+   case 10968:
+   case 10970:
+   case 10972:
+   case 10974:
+   case 10976:
+   case 10978:
+   case 10980:
+   case 10982:
+   case 10984:
+   case 10986:
+   case 10988:
+   case 10990:
+   case 10992:
+   case 10994:
+   case 10996:
+   case 10998:
+   case 11e3:
+   case 11002:
+   case 11004:
+   case 11006:
+   case 11008:
+   case 11010:
+   case 11012:
+   case 11014:
+   case 11016:
+   case 11018:
+   case 11020:
+   case 11022:
+   case 11024:
+   case 11026:
+   case 11028:
+   case 11030:
+   case 11032:
+   case 11034:
+   case 11036:
+   case 11038:
+   case 11040:
+   case 11042:
+   case 11044:
+   case 11046:
+   case 11048:
+   case 11050:
+   case 11052:
+   case 11054:
+   case 11056:
+   case 11058:
+   case 11060:
+   case 11062:
+   case 11064:
+   case 11066:
+   case 11068:
+   case 11070:
+   case 11072:
+   case 11074:
+   case 11076:
+   case 11078:
+   case 11080:
+   case 11082:
+   case 11084:
+   case 11086:
+   case 11088:
+   case 11090:
+   case 11092:
+   case 11094:
+   case 11096:
+   case 11098:
+   case 11100:
+   case 11102:
+   case 11104:
+   case 11106:
+   case 11108:
+   case 11110:
+   case 11112:
+   case 11114:
+   case 11116:
+   case 11118:
+   case 11120:
+   case 11122:
+   case 11124:
+   case 11126:
+   case 11128:
+   case 11130:
+   case 11132:
+   case 11134:
+   case 11136:
+   case 11138:
+   case 11140:
+   case 11142:
+   case 11144:
+   case 11146:
+   case 11148:
+   case 11150:
+   case 11152:
+   case 11154:
+   case 11156:
+   case 11158:
+   case 11160:
+   case 11162:
+   case 11164:
+   case 11166:
+   case 11168:
+   case 11170:
+   case 11172:
+   case 11174:
+   case 11176:
+   case 11178:
+   case 11180:
+   case 11182:
+   case 11184:
+   case 11186:
+   case 11188:
+   case 11190:
+   case 11192:
+   case 11194:
+   case 11196:
+   case 11198:
+   case 11200:
+   case 11202:
+   case 11204:
+   case 11206:
+   case 11208:
+   case 11210:
+   case 11212:
+   case 11214:
+   case 11216:
+   case 11218:
+   case 11220:
+   case 11222:
+   case 11224:
+   case 11226:
+   case 11228:
+   case 11230:
+   case 11232:
+   case 11234:
+   case 11236:
+   case 11238:
+   case 11240:
+   case 11242:
+   case 11244:
+   case 11246:
+   case 11248:
+   case 11250:
+   case 11252:
+   case 11254:
+   case 11256:
+   case 11258:
+   case 11260:
+   case 11262:
+   case 11264:
+   case 11266:
+   case 11268:
+   case 11270:
+   case 11272:
+   case 11274:
+   case 11276:
+   case 11278:
+   case 11280:
+   case 11282:
+   case 11284:
+   case 11286:
+   case 11288:
+   case 11290:
+   case 11292:
+   case 11294:
+   case 11296:
+   case 11298:
+   case 11300:
+   case 11302:
+   case 11304:
+   case 11306:
+   case 11308:
+   case 11310:
+   case 11312:
+   case 11314:
+   case 11316:
+   case 11318:
+   case 11320:
+   case 11322:
+   case 11324:
+   case 11326:
+   case 11328:
+   case 11330:
+   case 11332:
+   case 11334:
+   case 11336:
+   case 11338:
+   case 11340:
+   case 11342:
+   case 11344:
+   case 11346:
+   case 11348:
+   case 11350:
+   case 11352:
+   case 11354:
+   case 11356:
+   case 11358:
+   case 11360:
+   case 11362:
+   case 11364:
+   case 11366:
+   case 11368:
+   case 11370:
+   case 11372:
+   case 11374:
+   case 11376:
+   case 11378:
+   case 11380:
+   case 11382:
+   case 11384:
+   case 11386:
+   case 11388:
+   case 11390:
+   case 11392:
+   case 11394:
+   case 11396:
+   case 11398:
+   case 11400:
+   case 11402:
+   case 11404:
+   case 11406:
+   case 11408:
+   case 11410:
+   case 11412:
+   case 11414:
+   case 11416:
+   case 11418:
+   case 11420:
+   case 11422:
+   case 11424:
+   case 11426:
+   case 11428:
+   case 11430:
+   case 11432:
+   case 11434:
+   case 11436:
+   case 11438:
+   case 11440:
+   case 11442:
+   case 11444:
+   case 11446:
+   case 11448:
+   case 11450:
+   case 11452:
+   case 11454:
+   case 11456:
+   case 11458:
+   case 11460:
+   case 11462:
+   case 11464:
+   case 11466:
+   case 11468:
+   case 11470:
+   case 11472:
+   case 11474:
+   case 11476:
+   case 11478:
+   case 11480:
+   case 11482:
+   case 11484:
+   case 11486:
+   case 11488:
+   case 11490:
+   case 11492:
+   case 11494:
+   case 11496:
+   case 11498:
+   case 11500:
+   case 11502:
+   case 11504:
+   case 11506:
+   case 11508:
+   case 11510:
+   case 11512:
+   case 11514:
+   case 11516:
+   case 11518:
+   case 11520:
+   case 11522:
+   case 11524:
+   case 11526:
+   case 11528:
+   case 11530:
+   case 11532:
+   case 11534:
+   case 11536:
+   case 11538:
+   case 11540:
+   case 11542:
+   case 11544:
+   case 11546:
+   case 11548:
+   case 11550:
+   case 11552:
+   case 11554:
+   case 11556:
+   case 11558:
+   case 11560:
+   case 11562:
+   case 11564:
+   case 11566:
+   case 11568:
+   case 11570:
+   case 11572:
+   case 11574:
+   case 11576:
+   case 11578:
+   case 11580:
+   case 11582:
+   case 11584:
+   case 11586:
+   case 11588:
+   case 11590:
+   case 11592:
+   case 11594:
+   case 11596:
+   case 11598:
+   case 11600:
+   case 11602:
+   case 11604:
+   case 11606:
+   case 11608:
+   case 11610:
+   case 11612:
+   case 11614:
+   case 11616:
+   case 11618:
+   case 11620:
+   case 11622:
+   case 11624:
+   case 11626:
+   case 11628:
+   case 11630:
+   case 11632:
+   case 11634:
+   case 11636:
+   case 11638:
+   case 11640:
+   case 11642:
+   case 11644:
+   case 11646:
+   case 11648:
+   case 11650:
+   case 11652:
+   case 11654:
+   case 11656:
+   case 11658:
+   case 11660:
+   case 11662:
+   case 11664:
+   case 11666:
+   case 11668:
+   case 11670:
+   case 11672:
+   case 11674:
+   case 11676:
+   case 11678:
+   case 11680:
+   case 11682:
+   case 11684:
+   case 11686:
+   case 11688:
+   case 11690:
+   case 11692:
+   case 11694:
+   case 11696:
+   case 11698:
+   case 11700:
+   case 11702:
+   case 11704:
+   case 11706:
+   case 11708:
+   case 11710:
+   case 11712:
+   case 11714:
+   case 11716:
+   case 11718:
+   case 11720:
+   case 11722:
+   case 11724:
+   case 11726:
+   case 11728:
+   case 11730:
+   case 11732:
+   case 11734:
+   case 11736:
+   case 11738:
+   case 11740:
+   case 11742:
+   case 11744:
+   case 11746:
+   case 11748:
+   case 11750:
+   case 11752:
+   case 11754:
+   case 11756:
+   case 11758:
+   case 11760:
+   case 11762:
+   case 11764:
+   case 11766:
+   case 11768:
+   case 11770:
+   case 11772:
+   case 11774:
+   case 11776:
+   case 11778:
+   case 11780:
+   case 11782:
+   case 11784:
+   case 11786:
+   case 11788:
+   case 11790:
+   case 11792:
+   case 11794:
+   case 11796:
+   case 11798:
+   case 11800:
+   case 11802:
+   case 11804:
+   case 11806:
+   case 11808:
+   case 11810:
+   case 11812:
+   case 11814:
+   case 11816:
+   case 11818:
+   case 11820:
+   case 11822:
+   case 11824:
+   case 11826:
+   case 11828:
+   case 11830:
+   case 11832:
+   case 11834:
+   case 11836:
+   case 11838:
+   case 11840:
+   case 11842:
+   case 11844:
+   case 11846:
+   case 11848:
+   case 11850:
+   case 11852:
+   case 11854:
+   case 11856:
+   case 11858:
+   case 11860:
+   case 11862:
+   case 11864:
+   case 11866:
+   case 11868:
+   case 11870:
+   case 11872:
+   case 11874:
+   case 11876:
+   case 11878:
+   case 11880:
+   case 11882:
+   case 11884:
+   case 11886:
+   case 11888:
+   case 11890:
+   case 11892:
+   case 11894:
+   case 11896:
+   case 11898:
+   case 11900:
+   case 11902:
+   case 11904:
+   case 11906:
+   case 11908:
+   case 11910:
+   case 11912:
+   case 11914:
+   case 11916:
+   case 11918:
+   case 11920:
+   case 11922:
+   case 11924:
+   case 11926:
+   case 11928:
+   case 11930:
+   case 11932:
+   case 11934:
+   case 11936:
+   case 11938:
+   case 11940:
+   case 11942:
+   case 11944:
+   case 11946:
+   case 11948:
+   case 11950:
+   case 11952:
+   case 11954:
+   case 11956:
+   case 11958:
+   case 11960:
+   case 11962:
+   case 11964:
+   case 11966:
+   case 11968:
+   case 11970:
+   case 11972:
+   case 11974:
+   case 11976:
+   case 11978:
+   case 11980:
+   case 11982:
+   case 11984:
+   case 11986:
+   case 11988:
+   case 11990:
+   case 11992:
+   case 11994:
+   case 11996:
+   case 11998:
+   case 12e3:
+   case 12002:
+   case 12004:
+   case 12006:
+   case 12008:
+   case 12010:
+   case 12012:
+   case 12014:
+   case 12016:
+   case 12018:
+   case 12020:
+   case 12022:
+   case 12024:
+   case 12026:
+   case 12028:
+   case 12030:
+   case 12032:
+   case 12034:
+   case 12036:
+   case 12038:
+   case 12040:
+   case 12042:
+   case 12044:
+   case 12046:
+   case 12048:
+   case 12050:
+   case 12052:
+   case 12054:
+   case 12056:
+   case 12058:
+   case 12060:
+   case 12062:
+   case 12064:
+   case 12066:
+   case 12068:
+   case 12070:
+   case 12072:
+   case 12074:
+   case 12076:
+   case 12078:
+   case 12080:
+   case 12082:
+   case 12084:
+   case 12086:
+   case 12088:
+   case 12090:
+   case 12092:
+   case 12094:
+   case 12096:
+   case 12098:
+   case 12100:
+   case 12102:
+   case 12104:
+   case 12106:
+   case 12108:
+   case 12110:
+   case 12112:
+   case 12114:
+   case 12116:
+   case 12118:
+   case 12120:
+   case 12122:
+   case 12124:
+   case 12126:
+   case 12128:
+   case 12130:
+   case 12132:
+   case 12134:
+   case 12136:
+   case 12138:
+   case 12140:
+   case 12142:
+   case 12144:
+   case 12146:
+   case 12148:
+   case 12150:
+   case 12152:
+   case 12154:
+   case 12156:
+   case 12158:
+   case 12160:
+   case 12162:
+   case 12164:
+   case 12166:
+   case 12168:
+   case 12170:
+   case 12172:
+   case 12174:
+   case 12176:
+   case 12178:
+   case 12180:
+   case 12182:
+   case 12184:
+   case 12186:
+   case 12188:
+   case 12190:
+   case 12192:
+   case 12194:
+   case 12196:
+   case 12198:
+   case 12200:
+   case 12202:
+   case 12204:
+   case 12206:
+   case 12208:
+   case 12210:
+   case 12212:
+   case 12214:
+   case 12216:
+   case 12218:
+   case 12220:
+   case 12222:
+   case 12224:
+   case 12226:
+   case 12228:
+   case 12230:
+   case 12232:
+   case 12234:
+   case 12236:
+   case 12238:
+   case 12240:
+   case 12242:
+   case 12244:
+   case 12246:
+   case 12248:
+   case 12250:
+   case 12252:
+   case 12254:
+   case 12256:
+   case 12258:
+   case 12260:
+   case 12262:
+   case 12264:
+   case 12266:
+   case 12268:
+   case 12270:
+   case 12272:
+   case 12274:
+   case 12276:
+   case 12278:
+   case 12280:
+   case 12282:
+   case 12284:
+   case 12286:
+   case 12288:
+   case 12290:
+   case 12292:
+   case 12294:
+   case 12296:
+   case 12298:
+   case 12300:
+   case 12302:
+   case 12304:
+   case 12306:
+   case 12308:
+   case 12310:
+   case 12312:
+   case 12314:
+   case 12316:
+   case 12318:
+   case 12320:
+   case 12322:
+   case 12324:
+   case 12326:
+   case 12328:
+   case 12330:
+   case 12332:
+   case 12334:
+   case 12336:
+   case 12338:
+   case 12340:
+   case 12342:
+   case 12344:
+   case 12346:
+   case 12348:
+   case 12350:
+   case 12352:
+   case 12354:
+   case 12356:
+   case 12358:
+   case 12360:
+   case 12362:
+   case 12364:
+   case 12366:
+   case 12368:
+   case 12370:
+   case 12372:
+   case 12374:
+   case 12376:
+   case 12378:
+   case 12380:
+   case 12382:
+   case 12384:
+   case 12386:
+   case 12388:
+   case 12390:
+   case 12392:
+   case 12394:
+   case 12396:
+   case 12398:
+   case 12400:
+   case 12402:
+   case 12404:
+   case 12406:
+   case 12408:
+   case 12410:
+   case 12412:
+   case 12414:
+   case 12416:
+   case 12418:
+   case 12420:
+   case 12422:
+   case 12424:
+   case 12426:
+   case 12428:
+   case 12430:
+   case 12432:
+   case 12434:
+   case 12436:
+   case 12438:
+   case 12440:
+   case 12442:
+   case 12444:
+   case 12446:
+   case 12448:
+   case 12450:
+   case 12452:
+   case 12454:
+   case 12456:
+   case 12458:
+   case 12460:
+   case 12462:
+   case 12464:
+   case 12466:
+   case 12468:
+   case 12470:
+   case 12472:
+   case 12474:
+   case 12476:
+   case 12478:
+   case 12480:
+   case 12482:
+   case 12484:
+   case 12486:
+   case 12488:
+   case 12490:
+   case 12492:
+   case 12494:
+   case 12496:
+   case 12498:
+   case 12500:
+   case 12502:
+   case 12504:
+   case 12506:
+   case 12508:
+   case 12510:
+   case 12512:
+   case 12514:
+   case 12516:
+   case 12518:
+   case 12520:
+   case 12522:
+   case 12524:
+   case 12526:
+   case 12528:
+   case 12530:
+   case 12532:
+   case 12534:
+   case 12536:
+   case 12538:
+   case 12540:
+   case 12542:
+   case 12544:
+   case 12546:
+   case 12548:
+   case 12550:
+   case 12552:
+   case 12554:
+   case 12556:
+   case 12558:
+   case 12560:
+   case 12562:
+   case 12564:
+   case 12566:
+   case 12568:
+   case 12570:
+   case 12572:
+   case 12574:
+   case 12576:
+   case 12578:
+   case 12580:
+   case 12582:
+   case 12584:
+   case 12586:
+   case 12588:
+   case 12590:
+   case 12592:
+   case 12594:
+   case 12596:
+   case 12598:
+   case 12600:
+   case 12602:
+   case 12604:
+   case 12606:
+   case 12608:
+   case 12610:
+   case 12612:
+   case 12614:
+   case 12616:
+   case 12618:
+   case 12620:
+   case 12622:
+   case 12624:
+   case 12626:
+   case 12628:
+   case 12630:
+   case 12632:
+   case 12634:
+   case 12636:
+   case 12638:
+   case 12640:
+   case 12642:
+   case 12644:
+   case 12646:
+   case 12648:
+   case 12650:
+   case 12652:
+   case 12654:
+   case 12656:
+   case 12658:
+   case 12660:
+   case 12662:
+   case 12664:
+   case 12666:
+   case 12668:
+   case 12670:
+   case 12672:
+   case 12674:
+   case 12676:
+   case 12678:
+   case 12680:
+   case 12682:
+   case 12684:
+   case 12686:
+   case 12688:
+   case 12690:
+   case 12692:
+   case 12694:
+   case 12696:
+   case 12698:
+   case 12700:
+   case 12702:
+   case 12704:
+   case 12706:
+   case 12708:
+   case 12710:
+   case 12712:
+   case 12714:
+   case 12716:
+   case 12718:
+   case 12720:
+   case 12722:
+   case 12724:
+   case 12726:
+   case 12728:
+   case 12730:
+   case 12732:
+   case 12734:
+   case 12736:
+   case 12738:
+   case 12740:
+   case 12742:
+   case 12744:
+   case 12746:
+   case 12748:
+   case 12750:
+   case 12752:
+   case 12754:
+   case 12756:
+   case 12758:
+   case 12760:
+   case 12762:
+   case 12764:
+   case 12766:
+   case 12768:
+   case 12770:
+   case 12772:
+   case 12774:
+   case 12776:
+   case 12778:
+   case 12780:
+   case 12782:
+   case 12784:
+   case 12786:
+   case 12788:
+   case 12790:
+   case 12792:
+   case 12794:
+   case 12796:
+   case 12798:
+   case 12800:
+   case 12802:
+   case 12804:
+   case 12806:
+   case 12808:
+   case 12810:
+   case 12812:
+   case 12814:
+   case 12816:
+   case 12818:
+   case 12820:
+   case 12822:
+   case 12824:
+   case 12826:
+   case 12828:
+   case 12830:
+   case 12832:
+   case 12834:
+   case 12836:
+   case 12838:
+   case 12840:
+   case 12842:
+   case 12844:
+   case 12846:
+   case 12848:
+   case 12850:
+   case 12852:
+   case 12854:
+   case 12856:
+   case 12858:
+   case 12860:
+   case 12862:
+   case 12864:
+   case 12866:
+   case 12868:
+   case 12870:
+   case 12872:
+   case 12874:
+   case 12876:
+   case 12878:
+   case 12880:
+   case 12882:
+   case 12884:
+   case 12886:
+   case 12888:
+   case 12890:
+   case 12892:
+   case 12894:
+   case 12896:
+   case 12898:
+   case 12900:
+   case 12902:
+   case 12904:
+   case 12906:
+   case 12908:
+   case 12910:
+   case 12912:
+   case 12914:
+   case 12916:
+   case 12918:
+   case 12920:
+   case 12922:
+   case 12924:
+   case 12926:
+   case 12928:
+   case 12930:
+   case 12932:
+   case 12934:
+   case 12936:
+   case 12938:
+   case 12940:
+   case 12942:
+   case 12944:
+   case 12946:
+   case 12948:
+   case 12950:
+   case 12952:
+   case 12954:
+   case 12956:
+   case 12958:
+   case 12960:
+   case 12962:
+   case 12964:
+   case 12966:
+   case 12968:
+   case 12970:
+   case 12972:
+   case 12974:
+   case 12976:
+   case 12978:
+   case 12980:
+   case 12982:
+   case 12984:
+   case 12986:
+   case 12988:
+   case 12990:
+   case 12992:
+   case 12994:
+   case 12996:
+   case 12998:
+   case 13e3:
+   case 13002:
+   case 13004:
+   case 13006:
+   case 13008:
+   case 13010:
+   case 13012:
+   case 13014:
+   case 13016:
+   case 13018:
+   case 13020:
+   case 13022:
+   case 13024:
+   case 13026:
+   case 13028:
+   case 13030:
+   case 13032:
+   case 13034:
+   case 13036:
+   case 13038:
+   case 13040:
+   case 13042:
+   case 13044:
+   case 13046:
+   case 13048:
+   case 13050:
+   case 13052:
+   case 13054:
+   case 13056:
+   case 13058:
+   case 13060:
+   case 13062:
+   case 13064:
+   case 13066:
+   case 13068:
+   case 13070:
+   case 13072:
+   case 13074:
+   case 13076:
+   case 13078:
+   case 13080:
+   case 13082:
+   case 13084:
+   case 13086:
+   case 13088:
+   case 13090:
+   case 13092:
+   case 13094:
+   case 13096:
+   case 13098:
+   case 13100:
+   case 13102:
+   case 13104:
+   case 13106:
+   case 13108:
+   case 13110:
+   case 13112:
+   case 13114:
+   case 13116:
+   case 13118:
+   case 13120:
+   case 13122:
+   case 13124:
+   case 13126:
+   case 13128:
+   case 13130:
+   case 13132:
+   case 13134:
+   case 13136:
+   case 13138:
+   case 13140:
+   case 13142:
+   case 13144:
+   case 13146:
+   case 13148:
+   case 13150:
+   case 13152:
+   case 13154:
+   case 13156:
+   case 13158:
+   case 13160:
+   case 13162:
+   case 13164:
+   case 13166:
+   case 13168:
+   case 13170:
+   case 13172:
+   case 13174:
+   case 13176:
+   case 13178:
+   case 13180:
+   case 13182:
+   case 13184:
+   case 13186:
+   case 13188:
+   case 13190:
+   case 13192:
+   case 13194:
+   case 13196:
+   case 13198:
+   case 13200:
+   case 13202:
+   case 13204:
+   case 13206:
+   case 13208:
+   case 13210:
+   case 13212:
+   case 13214:
+   case 13216:
+   case 13218:
+   case 13220:
+   case 13222:
+   case 13224:
+   case 13226:
+   case 13228:
+   case 13230:
+   case 13232:
+   case 13234:
+   case 13236:
+   case 13238:
+   case 13240:
+   case 13242:
+   case 13244:
+   case 13246:
+   case 13248:
+   case 13250:
+   case 13252:
+   case 13254:
+   case 13256:
+   case 13258:
+   case 13260:
+   case 13262:
+   case 13264:
+   case 13266:
+   case 13268:
+   case 13270:
+   case 13272:
+   case 13274:
+   case 13276:
+   case 13278:
+   case 13280:
+   case 13282:
+   case 13284:
+   case 13286:
+   case 13288:
+   case 13290:
+   case 13292:
+   case 13294:
+   case 13296:
+   case 13298:
+   case 13300:
+   case 13302:
+   case 13304:
+   case 13306:
+   case 13308:
+   case 13310:
+   case 13312:
+   case 13314:
+   case 13316:
+   case 13318:
+   case 13320:
+   case 13322:
+   case 13324:
+   case 13326:
+   case 13328:
+   case 13330:
+   case 13332:
+   case 13334:
+   case 13336:
+   case 13338:
+   case 13340:
+   case 13342:
+   case 13344:
+   case 13346:
+   case 13348:
+   case 13350:
+   case 13352:
+   case 13354:
+   case 13356:
+   case 13358:
+   case 13360:
+   case 13362:
+   case 13364:
+   case 13366:
+   case 13368:
+   case 13370:
+   case 13372:
+   case 13374:
+   case 13376:
+   case 13378:
+   case 13380:
+   case 13382:
+   case 13384:
+   case 13386:
+   case 13388:
+   case 13390:
+   case 13392:
+   case 13394:
+   case 13396:
+   case 13398:
+   case 13400:
+   case 13402:
+   case 13404:
+   case 13406:
+   case 13408:
+   case 13410:
+   case 13412:
+   case 13414:
+   case 13416:
+   case 13418:
+   case 13420:
+   case 13422:
+   case 13424:
+   case 13426:
+   case 13428:
+   case 13430:
+   case 13432:
+   case 13434:
+   case 13436:
+   case 13438:
+   case 13440:
+   case 13442:
+   case 13444:
+   case 13446:
+   case 13448:
+   case 13450:
+   case 13452:
+   case 13454:
+   case 13456:
+   case 13458:
+   case 13460:
+   case 13462:
+   case 13464:
+   case 13466:
+   case 13468:
+   case 13470:
+   case 13472:
+   case 13474:
+   case 13476:
+   case 13478:
+   case 13480:
+   case 13482:
+   case 13484:
+   case 13486:
+   case 13488:
+   case 13490:
+   case 13492:
+   case 13494:
+   case 13496:
+   case 13498:
+   case 13500:
+   case 13502:
+   case 13504:
+   case 13506:
+   case 13508:
+   case 13510:
+   case 13512:
+   case 13514:
+   case 13516:
+   case 13518:
+   case 13520:
+   case 13522:
+   case 13524:
+   case 13526:
+   case 13528:
+   case 13530:
+   case 13532:
+   case 13534:
+   case 13536:
+   case 13538:
+   case 13540:
+   case 13542:
+   case 13544:
+   case 13546:
+   case 13548:
+   case 13550:
+   case 13552:
+   case 13554:
+   case 13556:
+   case 13558:
+   case 13560:
+   case 13562:
+   case 13564:
+   case 13566:
+   case 13568:
+   case 13570:
+   case 13572:
+   case 13574:
+   case 13576:
+   case 13578:
+   case 13580:
+   case 13582:
+   case 13584:
+   case 13586:
+   case 13588:
+   case 13590:
+   case 13592:
+   case 13594:
+   case 13596:
+   case 13598:
+   case 13600:
+   case 13602:
+   case 13604:
+   case 13606:
+   case 13608:
+   case 13610:
+   case 13612:
+   case 13614:
+   case 13616:
+   case 13618:
+   case 13620:
+   case 13622:
+   case 13624:
+   case 13626:
+   case 13628:
+   case 13630:
+   case 13632:
+   case 13634:
+   case 13636:
+   case 13638:
+   case 13640:
+   case 13642:
+   case 13644:
+   case 13646:
+   case 13648:
+   case 13650:
+   case 13652:
+   case 13654:
+   case 13656:
+   case 13658:
+   case 13660:
+   case 13662:
+   case 13664:
+   case 13666:
+   case 13668:
+   case 13670:
+   case 13672:
+   case 13674:
+   case 13676:
+   case 13678:
+   case 13680:
+   case 13682:
+   case 13684:
+   case 13686:
+   case 13688:
+   case 13690:
+   case 13692:
+   case 13694:
+   case 13696:
+   case 13698:
+   case 13700:
+   case 13702:
+   case 13704:
+   case 13706:
+   case 13708:
+   case 13710:
+   case 13712:
+   case 13714:
+   case 13716:
+   case 13718:
+   case 13720:
+   case 13722:
+   case 13724:
+   case 13726:
+   case 13728:
+   case 13730:
+   case 13732:
+   case 13734:
+   case 13736:
+   case 13738:
+   case 13740:
+   case 13742:
+   case 13744:
+   case 13746:
+   case 13748:
+   case 13750:
+   case 13752:
+   case 13754:
+   case 13756:
+   case 13758:
+   case 13760:
+   case 13762:
+   case 13764:
+   case 13766:
+   case 13768:
+   case 13770:
+   case 13772:
+   case 13774:
+   case 13776:
+   case 13778:
+   case 13780:
+   case 13782:
+   case 13784:
+   case 13786:
+   case 13788:
+   case 13790:
+   case 13792:
+   case 13794:
+   case 13796:
+   case 13798:
+   case 13800:
+   case 13802:
+   case 13804:
+   case 13806:
+   case 13808:
+   case 13810:
+   case 13812:
+   case 13814:
+   case 13816:
+   case 13818:
+   case 13820:
+   case 13822:
+   case 13824:
+   case 13826:
+   case 13828:
+   case 13830:
+   case 13832:
+   case 13834:
+   case 13836:
+   case 13838:
+   case 13840:
+   case 13842:
+   case 13844:
+   case 13846:
+   case 13848:
+   case 13850:
+   case 13852:
+   case 13854:
+   case 13856:
+   case 13858:
+   case 13860:
+   case 13862:
+   case 13864:
+   case 13866:
+   case 13868:
+   case 13870:
+   case 13872:
+   case 13874:
+   case 13876:
+   case 13878:
+   case 13880:
+   case 13882:
+   case 13884:
+   case 13886:
+   case 13888:
+   case 13890:
+   case 13892:
+   case 13894:
+   case 13896:
+   case 13898:
+   case 13900:
+   case 13902:
+   case 13904:
+   case 13906:
+   case 13908:
+   case 13910:
+   case 13912:
+   case 13914:
+   case 13916:
+   case 13918:
+   case 13920:
+   case 13922:
+   case 13924:
+   case 13926:
+   case 13928:
+   case 13930:
+   case 13932:
+   case 13934:
+   case 13936:
+   case 13938:
+   case 13940:
+   case 13942:
+   case 13944:
+   case 13946:
+   case 13948:
+   case 13950:
+   case 13952:
+   case 13954:
+   case 13956:
+   case 13958:
+   case 13960:
+   case 13962:
+   case 13964:
+   case 13966:
+   case 13968:
+   case 13970:
+   case 13972:
+   case 13974:
+   case 13976:
+   case 13978:
+   case 13980:
+   case 13982:
+   case 13984:
+   case 13986:
+   case 13988:
+   case 13990:
+   case 13992:
+   case 13994:
+   case 13996:
+   case 13998:
+   case 14e3:
+   case 14002:
+   case 14004:
+   case 14006:
+   case 14008:
+   case 14010:
+   case 14012:
+   case 14014:
+   case 14016:
+   case 14018:
+   case 14020:
+   case 14022:
+   case 14024:
+   case 14026:
+   case 14028:
+   case 14030:
+   case 14032:
+   case 14034:
+   case 14036:
+   case 14038:
+   case 14040:
+   case 14042:
+   case 14044:
+   case 14046:
+   case 14048:
+   case 14050:
+   case 14052:
+   case 14054:
+   case 14056:
+   case 14058:
+   case 14060:
+   case 14062:
+   case 14064:
+   case 14066:
+   case 14068:
+   case 14070:
+   case 14072:
+   case 14074:
+   case 14076:
+   case 14078:
+   case 14080:
+   case 14082:
+   case 14084:
+   case 14086:
+   case 14088:
+   case 14090:
+   case 14092:
+   case 14094:
+   case 14096:
+   case 14098:
+   case 14100:
+   case 14102:
+   case 14104:
+   case 14106:
+   case 14108:
+   case 14110:
+   case 14112:
+   case 14114:
+   case 14116:
+   case 14118:
+   case 14120:
+   case 14122:
+   case 14124:
+   case 14126:
+   case 14128:
+   case 14130:
+   case 14132:
+   case 14134:
+   case 14136:
+   case 14138:
+   case 14140:
+   case 14142:
+   case 14144:
+   case 14146:
+   case 14148:
+   case 14150:
+   case 14152:
+   case 14154:
+   case 14156:
+   case 14158:
+   case 14160:
+   case 14162:
+   case 14164:
+   case 14166:
+   case 14168:
+   case 14170:
+   case 14172:
+   case 14174:
+   case 14176:
+   case 14178:
+   case 14180:
+   case 14182:
+   case 14184:
+   case 14186:
+   case 14188:
+   case 14190:
+   case 14192:
+   case 14194:
+   case 14196:
+   case 14198:
+   case 14200:
+   case 14202:
+   case 14204:
+   case 14206:
+   case 14208:
+   case 14210:
+   case 14212:
+   case 14214:
+   case 14216:
+   case 14218:
+   case 14220:
+   case 14222:
+   case 14224:
+   case 14226:
+   case 14228:
+   case 14230:
+   case 14232:
+   case 14234:
+   case 14236:
+   case 14238:
+   case 14240:
+   case 14242:
+   case 14244:
+   case 14246:
+   case 14248:
+   case 14250:
+   case 14252:
+   case 14254:
+   case 14256:
+   case 14258:
+   case 14260:
+   case 14262:
+   case 14264:
+   case 14266:
+   case 14268:
+   case 14270:
+   case 14272:
+   case 14274:
+   case 14276:
+   case 14278:
+   case 14280:
+   case 14282:
+   case 14284:
+   case 14286:
+   case 14288:
+   case 14290:
+   case 14292:
+   case 14294:
+   case 14296:
+   case 14298:
+   case 14300:
+   case 14302:
+   case 14304:
+   case 14306:
+   case 14308:
+   case 14310:
+   case 14312:
+   case 14314:
+   case 14316:
+   case 14318:
+   case 14320:
+   case 14322:
+   case 14324:
+   case 14326:
+   case 14328:
+   case 14330:
+   case 14332:
+   case 14334:
+   case 14336:
+   case 14338:
+   case 14340:
+   case 14342:
+   case 14344:
+   case 14346:
+   case 14348:
+   case 14350:
+   case 14352:
+   case 14354:
+   case 14356:
+   case 14358:
+   case 14360:
+   case 14362:
+   case 14364:
+   case 14366:
+   case 14368:
+   case 14370:
+   case 14372:
+   case 14374:
+   case 14376:
+   case 14378:
+   case 14380:
+   case 14382:
+   case 14384:
+   case 14386:
+   case 14388:
+   case 14390:
+   case 14392:
+   case 14394:
+   case 14396:
+   case 14398:
+   case 14400:
+   case 14402:
+   case 14404:
+   case 14406:
+   case 14408:
+   case 14410:
+   case 14412:
+   case 14414:
+   case 14416:
+   case 14418:
+   case 14420:
+   case 14422:
+   case 14424:
+   case 14426:
+   case 14428:
+   case 14430:
+   case 14432:
+   case 14434:
+   case 14436:
+   case 14438:
+   case 14440:
+   case 14442:
+   case 14444:
+   case 14446:
+   case 14448:
+   case 14450:
+   case 14452:
+   case 14454:
+   case 14456:
+   case 14458:
+   case 14460:
+   case 14462:
+   case 14464:
+   case 14466:
+   case 14468:
+   case 14470:
+   case 14472:
+   case 14474:
+   case 14476:
+   case 14478:
+   case 14480:
+   case 14482:
+   case 14484:
+   case 14486:
+   case 14488:
+   case 14490:
+   case 14492:
+   case 14494:
+   case 14496:
+   case 14498:
+   case 14500:
+   case 14502:
+   case 14504:
+   case 14506:
+   case 14508:
+   case 14510:
+   case 14512:
+   case 14514:
+   case 14516:
+   case 14518:
+   case 14520:
+   case 14522:
+   case 14524:
+   case 14526:
+   case 14528:
+   case 14530:
+   case 14532:
+   case 14534:
+   case 14536:
+   case 14538:
+   case 14540:
+   case 14542:
+   case 14544:
+   case 14546:
+   case 14548:
+   case 14550:
+   case 14552:
+   case 14554:
+   case 14556:
+   case 14558:
+   case 14560:
+   case 14562:
+   case 14564:
+   case 14566:
+   case 14568:
+   case 14570:
+   case 14572:
+   case 14574:
+   case 14576:
+   case 14578:
+   case 14580:
+   case 14582:
+   case 14584:
+   case 14586:
+   case 14588:
+   case 14590:
+   case 14592:
+   case 14594:
+   case 14596:
+   case 14598:
+   case 14600:
+   case 14602:
+   case 14604:
+   case 14606:
+   case 14608:
+   case 14610:
+   case 14612:
+   case 14614:
+   case 14616:
+   case 14618:
+   case 14620:
+   case 14622:
+   case 14624:
+   case 14626:
+   case 14628:
+   case 14630:
+   case 14632:
+   case 14634:
+   case 14636:
+   case 14638:
+   case 14640:
+   case 14642:
+   case 14644:
+   case 14646:
+   case 14648:
+   case 14650:
+   case 14652:
+   case 14654:
+   case 14656:
+   case 14658:
+   case 14660:
+   case 14662:
+   case 14664:
+   case 14666:
+   case 14668:
+   case 14670:
+   case 14672:
+   case 14674:
+   case 14676:
+   case 14678:
+   case 14680:
+   case 14682:
+   case 14684:
+   case 14686:
+   case 14688:
+   case 14690:
+   case 14692:
+   case 14694:
+   case 14696:
+   case 14698:
+   case 14700:
+   case 14702:
+   case 14704:
+   case 14706:
+   case 14708:
+   case 14710:
+   case 14712:
+   case 14714:
+   case 14716:
+   case 14718:
+   case 14720:
+   case 14722:
+   case 14724:
+   case 14726:
+   case 14728:
+   case 14730:
+   case 14732:
+   case 14734:
+   case 14736:
+   case 14738:
+   case 14740:
+   case 14742:
+   case 14744:
+   case 14746:
+   case 14748:
+   case 14750:
+   case 14752:
+   case 14754:
+   case 14756:
+   case 14758:
+   case 14760:
+   case 14762:
+   case 14764:
+   case 14766:
+   case 14768:
+   case 14770:
+   case 14772:
+   case 14774:
+   case 14776:
+   case 14778:
+   case 14780:
+   case 14782:
+   case 14784:
+   case 14786:
+   case 14788:
+   case 14790:
+   case 14792:
+   case 14794:
+   case 14796:
+   case 14798:
+   case 14800:
+   case 14802:
+   case 14804:
+   case 14806:
+   case 14808:
+   case 14810:
+   case 14812:
+   case 14814:
+   case 14816:
+   case 14818:
+   case 14820:
+   case 14822:
+   case 14824:
+   case 14826:
+   case 14828:
+   case 14830:
+   case 14832:
+   case 14834:
+   case 14836:
+   case 14838:
+   case 14840:
+   case 14842:
+   case 14844:
+   case 14846:
+   case 14848:
+   case 14850:
+   case 14852:
+   case 14854:
+   case 14856:
+   case 14858:
+   case 14860:
+   case 14862:
+   case 14864:
+   case 14866:
+   case 14868:
+   case 14870:
+   case 14872:
+   case 14874:
+   case 14876:
+   case 14878:
+   case 14880:
+   case 14882:
+   case 14884:
+   case 14886:
+   case 14888:
+   case 14890:
+   case 14892:
+   case 14894:
+   case 14896:
+   case 14898:
+   case 14900:
+   case 14902:
+   case 14904:
+   case 14906:
+   case 14908:
+   case 14910:
+   case 14912:
+   case 14914:
+   case 14916:
+   case 14918:
+   case 14920:
+   case 14922:
+   case 14924:
+   case 14926:
+   case 14928:
+   case 14930:
+   case 14932:
+   case 14934:
+   case 14936:
+   case 14938:
+   case 14940:
+   case 14942:
+   case 14944:
+   case 14946:
+   case 14948:
+   case 14950:
+   case 14952:
+   case 14954:
+   case 14956:
+   case 14958:
+   case 14960:
+   case 14962:
+   case 14964:
+   case 14966:
+   case 14968:
+   case 14970:
+   case 14972:
+   case 14974:
+   case 14976:
+   case 14978:
+   case 14980:
+   case 14982:
+   case 14984:
+   case 14986:
+   case 14988:
+   case 14990:
+   case 14992:
+   case 14994:
+   case 14996:
+   case 14998:
+   case 15e3:
+   case 15002:
+   case 15004:
+   case 15006:
+   case 15008:
+   case 15010:
+   case 15012:
+   case 15014:
+   case 15016:
+   case 15018:
+   case 15020:
+   case 15022:
+   case 15024:
+   case 15026:
+   case 15028:
+   case 15030:
+   case 15032:
+   case 15034:
+   case 15036:
+   case 15038:
+   case 15040:
+   case 15042:
+   case 15044:
+   case 15046:
+   case 15048:
+   case 15050:
+   case 15052:
+   case 15054:
+   case 15056:
+   case 15058:
+   case 15060:
+   case 15062:
+   case 15064:
+   case 15066:
+   case 15068:
+   case 15070:
+   case 15072:
+   case 15074:
+   case 15076:
+   case 15078:
+   case 15080:
+   case 15082:
+   case 15084:
+   case 15086:
+   case 15088:
+   case 15090:
+   case 15092:
+   case 15094:
+   case 15096:
+   case 15098:
+   case 15100:
+   case 15102:
+   case 15104:
+   case 15106:
+   case 15108:
+   case 15110:
+   case 15112:
+   case 15114:
+   case 15116:
+   case 15118:
+   case 15120:
+   case 15122:
+   case 15124:
+   case 15126:
+   case 15128:
+   case 15130:
+   case 15132:
+   case 15134:
+   case 15136:
+   case 15138:
+   case 15140:
+   case 15142:
+   case 15144:
+   case 15146:
+   case 15148:
+   case 15150:
+   case 15152:
+   case 15154:
+   case 15156:
+   case 15158:
+   case 15160:
+   case 15162:
+   case 15164:
+   case 15166:
+   case 15168:
+   case 15170:
+   case 15172:
+   case 15174:
+   case 15176:
+   case 15178:
+   case 15180:
+   case 15182:
+   case 15184:
+   case 15186:
+   case 15188:
+   case 15190:
+   case 15192:
+   case 15194:
+   case 15196:
+   case 15198:
+   case 15200:
+   case 15202:
+   case 15204:
+   case 15206:
+   case 15208:
+   case 15210:
+   case 15212:
+   case 15214:
+   case 15216:
+   case 15218:
+   case 15220:
+   case 15222:
+   case 15224:
+   case 15226:
+   case 15228:
+   case 15230:
+   case 15232:
+   case 15234:
+   case 15236:
+   case 15238:
+   case 15240:
+   case 15242:
+   case 15244:
+   case 15246:
+   case 15248:
+   case 15250:
+   case 15252:
+   case 15254:
+   case 15256:
+   case 15258:
+   case 15260:
+   case 15262:
+   case 15264:
+   case 15266:
+   case 15268:
+   case 15270:
+   case 15272:
+   case 15274:
+   case 15276:
+   case 15278:
+   case 15280:
+   case 15282:
+   case 15284:
+   case 15286:
+   case 15288:
+   case 15290:
+   case 15292:
+   case 15294:
+   case 15296:
+   case 15298:
+   case 15300:
+   case 15302:
+   case 15304:
+   case 15306:
+   case 15308:
+   case 15310:
+   case 15312:
+   case 15314:
+   case 15316:
+   case 15318:
+   case 15320:
+   case 15322:
+   case 15324:
+   case 15326:
+   case 15328:
+   case 15330:
+   case 15332:
+   case 15334:
+   case 15336:
+   case 15338:
+   case 15340:
+   case 15342:
+   case 15344:
+   case 15346:
+   case 15348:
+   case 15350:
+   case 15352:
+   case 15354:
+   case 15356:
+   case 15358:
+   case 15360:
+   case 15362:
+   case 15364:
+   case 15366:
+   case 15368:
+   case 15370:
+   case 15372:
+   case 15374:
+   case 15376:
+   case 15378:
+   case 15380:
+   case 15382:
+   case 15384:
+   case 15386:
+   case 15388:
+   case 15390:
+   case 15392:
+   case 15394:
+   case 15396:
+   case 15398:
+   case 15400:
+   case 15402:
+   case 15404:
+   case 15406:
+   case 15408:
+   case 15410:
+   case 15412:
+   case 15414:
+   case 15416:
+   case 15418:
+   case 15420:
+   case 15422:
+   case 15424:
+   case 15426:
+   case 15428:
+   case 15430:
+   case 15432:
+   case 15434:
+   case 15436:
+   case 15438:
+   case 15440:
+   case 15442:
+   case 15444:
+   case 15446:
+   case 15448:
+   case 15450:
+   case 15452:
+   case 15454:
+   case 15456:
+   case 15458:
+   case 15460:
+   case 15462:
+   case 15464:
+   case 15466:
+   case 15468:
+   case 15470:
+   case 15472:
+   case 15474:
+   case 15476:
+   case 15478:
+   case 15480:
+   case 15482:
+   case 15484:
+   case 15486:
+   case 15488:
+   case 15490:
+   case 15492:
+   case 15494:
+   case 15496:
+   case 15498:
+   case 15500:
+   case 15502:
+   case 15504:
+   case 15506:
+   case 15508:
+   case 15510:
+   case 15512:
+   case 15514:
+   case 15516:
+   case 15518:
+   case 15520:
+   case 15522:
+   case 15524:
+   case 15526:
+   case 15528:
+   case 15530:
+   case 15532:
+   case 15534:
+   case 15536:
+   case 15538:
+   case 15540:
+   case 15542:
+   case 15544:
+   case 15546:
+   case 15548:
+   case 15550:
+   case 15552:
+   case 15554:
+   case 15556:
+   case 15558:
+   case 15560:
+   case 15562:
+   case 15564:
+   case 15566:
+   case 15568:
+   case 15570:
+   case 15572:
+   case 15574:
+   case 15576:
+   case 15578:
+   case 15580:
+   case 15582:
+   case 15584:
+   case 15586:
+   case 15588:
+   case 15590:
+   case 15592:
+   case 15594:
+   case 15596:
+   case 15598:
+   case 15600:
+   case 15602:
+   case 15604:
+   case 15606:
+   case 15608:
+   case 15610:
+   case 15612:
+   case 15614:
+   case 15616:
+   case 15618:
+   case 15620:
+   case 15622:
+   case 15624:
+   case 15626:
+   case 15628:
+   case 15630:
+   case 15632:
+   case 15634:
+   case 15636:
+   case 15638:
+   case 15640:
+   case 15642:
+   case 15644:
+   case 15646:
+   case 15648:
+   case 15650:
+   case 15652:
+   case 15654:
+   case 15656:
+   case 15658:
+   case 15660:
+   case 15662:
+   case 15664:
+   case 15666:
+   case 15668:
+   case 15670:
+   case 15672:
+   case 15674:
+   case 15676:
+   case 15678:
+   case 15680:
+   case 15682:
+   case 15684:
+   case 15686:
+   case 15688:
+   case 15690:
+   case 15692:
+   case 15694:
+   case 15696:
+   case 15698:
+   case 15700:
+   case 15702:
+   case 15704:
+   case 15706:
+   case 15708:
+   case 15710:
+   case 15712:
+   case 15714:
+   case 15716:
+   case 15718:
+   case 15720:
+   case 15722:
+   case 15724:
+   case 15726:
+   case 15728:
+   case 15730:
+   case 15732:
+   case 15734:
+   case 15736:
+   case 15738:
+   case 15740:
+   case 15742:
+   case 15744:
+   case 15746:
+   case 15748:
+   case 15750:
+   case 15752:
+   case 15754:
+   case 15756:
+   case 15758:
+   case 15760:
+   case 15762:
+   case 15764:
+   case 15766:
+   case 15768:
+   case 15770:
+   case 15772:
+   case 15774:
+   case 15776:
+   case 15778:
+   case 15780:
+   case 15782:
+   case 15784:
+   case 15786:
+   case 15788:
+   case 15790:
+   case 15792:
+   case 15794:
+   case 15796:
+   case 15798:
+   case 15800:
+   case 15802:
+   case 15804:
+   case 15806:
+   case 15808:
+   case 15810:
+   case 15812:
+   case 15814:
+   case 15816:
+   case 15818:
+   case 15820:
+   case 15822:
+   case 15824:
+   case 15826:
+   case 15828:
+   case 15830:
+   case 15832:
+   case 15834:
+   case 15836:
+   case 15838:
+   case 15840:
+   case 15842:
+   case 15844:
+   case 15846:
+   case 15848:
+   case 15850:
+   case 15852:
+   case 15854:
+   case 15856:
+   case 15858:
+   case 15860:
+   case 15862:
+   case 15864:
+   case 15866:
+   case 15868:
+   case 15870:
+   case 15872:
+   case 15874:
+   case 15876:
+   case 15878:
+   case 15880:
+   case 15882:
+   case 15884:
+   case 15886:
+   case 15888:
+   case 15890:
+   case 15892:
+   case 15894:
+   case 15896:
+   case 15898:
+   case 15900:
+   case 15902:
+   case 15904:
+   case 15906:
+   case 15908:
+   case 15910:
+   case 15912:
+   case 15914:
+   case 15916:
+   case 15918:
+   case 15920:
+   case 15922:
+   case 15924:
+   case 15926:
+   case 15928:
+   case 15930:
+   case 15932:
+   case 15934:
+   case 15936:
+   case 15938:
+   case 15940:
+   case 15942:
+   case 15944:
+   case 15946:
+   case 15948:
+   case 15950:
+   case 15952:
+   case 15954:
+   case 15956:
+   case 15958:
+   case 15960:
+   case 15962:
+   case 15964:
+   case 15966:
+   case 15968:
+   case 15970:
+   case 15972:
+   case 15974:
+   case 15976:
+   case 15978:
+   case 15980:
+   case 15982:
+   case 15984:
+   case 15986:
+   case 15988:
+   case 15990:
+   case 15992:
+   case 15994:
+   case 15996:
+   case 15998:
+   case 16e3:
+   case 16002:
+   case 16004:
+   case 16006:
+   case 16008:
+   case 16010:
+   case 16012:
+   case 16014:
+   case 16016:
+   case 16018:
+   case 16020:
+   case 16022:
+   case 16024:
+   case 16026:
+   case 16028:
+   case 16030:
+   case 16032:
+   case 16034:
+   case 16036:
+   case 16038:
+   case 16040:
+   case 16042:
+   case 16044:
+   case 16046:
+   case 16048:
+   case 16050:
+   case 16052:
+   case 16054:
+   case 16056:
+   case 16058:
+   case 16060:
+   case 16062:
+   case 16064:
+   case 16066:
+   case 16068:
+   case 16070:
+   case 16072:
+   case 16074:
+   case 16076:
+   case 16078:
+   case 16080:
+   case 16082:
+   case 16084:
+   case 16086:
+   case 16088:
+   case 16090:
+   case 16092:
+   case 16094:
+   case 16096:
+   case 16098:
+   case 16100:
+   case 16102:
+   case 16104:
+   case 16106:
+   case 16108:
+   case 16110:
+   case 16112:
+   case 16114:
+   case 16116:
+   case 16118:
+   case 16120:
+   case 16122:
+   case 16124:
+   case 16126:
+   case 16128:
+   case 16130:
+   case 16132:
+   case 16134:
+   case 16136:
+   case 16138:
+   case 16140:
+   case 16142:
+   case 16144:
+   case 16146:
+   case 16148:
+   case 16150:
+   case 16152:
+   case 16154:
+   case 16156:
+   case 16158:
+   case 16160:
+   case 16162:
+   case 16164:
+   case 16166:
+   case 16168:
+   case 16170:
+   case 16172:
+   case 16174:
+   case 16176:
+   case 16178:
+   case 16180:
+   case 16182:
+   case 16184:
+   case 16186:
+   case 16188:
+   case 16190:
+   case 16192:
+   case 16194:
+   case 16196:
+   case 16198:
+   case 16200:
+   case 16202:
+   case 16204:
+   case 16206:
+   case 16208:
+   case 16210:
+   case 16212:
+   case 16214:
+   case 16216:
+   case 16218:
+   case 16220:
+   case 16222:
+   case 16224:
+   case 16226:
+   case 16228:
+   case 16230:
+   case 16232:
+   case 16234:
+   case 16236:
+   case 16238:
+   case 16240:
+   case 16242:
+   case 16244:
+   case 16246:
+   case 16248:
+   case 16250:
+   case 16252:
+   case 16254:
+   case 16256:
+   case 16258:
+   case 16260:
+   case 16262:
+   case 16264:
+   case 16266:
+   case 16268:
+   case 16270:
+   case 16272:
+   case 16274:
+   case 16276:
+   case 16278:
+   case 16280:
+   case 16282:
+   case 16284:
+   case 16286:
+   case 16288:
+   case 16290:
+   case 16292:
+   case 16294:
+   case 16296:
+   case 16298:
+   case 16300:
+   case 16302:
+   case 16304:
+   case 16306:
+   case 16308:
+   case 16310:
+   case 16312:
+   case 16314:
+   case 16316:
+   case 16318:
+   case 16320:
+   case 16322:
+   case 16324:
+   case 16326:
+   case 16328:
+   case 16330:
+   case 16332:
+   case 16334:
+   case 16336:
+   case 16338:
+   case 16340:
+   case 16342:
+   case 16344:
+   case 16346:
+   case 16348:
+   case 16350:
+   case 16352:
+   case 16354:
+   case 16356:
+   case 16358:
+   case 16360:
+   case 16362:
+   case 16364:
+   case 16366:
+   case 16368:
+   case 16370:
+   case 16372:
+   case 16374:
+   case 16376:
+   case 16378:
+   case 16380:
+   case 16382:
+   case 16384:
+   case 16386:
+   case 16388:
+   case 16390:
+   case 16392:
+   case 16394:
+   case 16396:
+   case 16398:
+   case 16400:
+   case 16402:
+   case 16404:
+   case 16406:
+   case 16408:
+   case 16410:
+   case 16412:
+   case 16414:
+   case 16416:
+   case 16418:
+   case 16420:
+   case 16422:
+   case 16424:
+   case 16426:
+   case 16428:
+   case 16430:
+   case 16432:
+   case 16434:
+   case 16436:
+   case 16438:
+   case 16440:
+   case 16442:
+   case 16444:
+   case 16446:
+   case 16448:
+   case 16450:
+   case 16452:
+   case 16454:
+   case 16456:
+   case 16458:
+   case 16460:
+   case 16462:
+   case 16464:
+   case 16466:
+   case 16468:
+   case 16470:
+   case 16472:
+   case 16474:
+   case 16476:
+   case 16478:
+   case 16480:
+   case 16482:
+   case 16484:
+   case 16486:
+   case 16488:
+   case 16490:
+   case 16492:
+   case 16494:
+   case 16496:
+   case 16498:
+   case 16500:
+   case 16502:
+   case 16504:
+   case 16506:
+   case 16508:
+   case 16510:
+   case 16512:
+   case 16514:
+   case 16516:
+   case 16518:
+   case 16520:
+   case 16522:
+   case 16524:
+   case 16526:
+   case 16528:
+   case 16530:
+   case 16532:
+   case 16534:
+   case 16536:
+   case 16538:
+   case 16540:
+   case 16542:
+   case 16544:
+   case 16546:
+   case 16548:
+   case 16550:
+   case 16552:
+   case 16554:
+   case 16556:
+   case 16558:
+   case 16560:
+   case 16562:
+   case 16564:
+   case 16566:
+   case 16568:
+   case 16570:
+   case 16572:
+   case 16574:
+   case 16576:
+   case 16578:
+   case 16580:
+   case 16582:
+   case 16584:
+   case 16586:
+   case 16588:
+   case 16590:
+   case 16592:
+   case 16594:
+   case 16596:
+   case 16598:
+   case 16600:
+   case 16602:
+   case 16604:
+   case 16606:
+   case 16608:
+   case 16610:
+   case 16612:
+   case 16614:
+   case 16616:
+   case 16618:
+   case 16620:
+   case 16622:
+   case 16624:
+   case 16626:
+   case 16628:
+   case 16630:
+   case 16632:
+   case 16634:
+   case 16636:
+   case 16638:
+   case 16640:
+   case 16642:
+   case 16644:
+   case 16646:
+   case 16648:
+   case 16650:
+   case 16652:
+   case 16654:
+   case 16656:
+   case 16658:
+   case 16660:
+   case 16662:
+   case 16664:
+   case 16666:
+   case 16668:
+   case 16670:
+   case 16672:
+   case 16674:
+   case 16676:
+   case 16678:
+   case 16680:
+   case 16682:
+   case 16684:
+   case 16686:
+   case 16688:
+   case 16690:
+   case 16692:
+   case 16694:
+   case 16696:
+   case 16698:
+   case 16700:
+   case 16702:
+   case 16704:
+   case 16706:
+   case 16708:
+   case 16710:
+   case 16712:
+   case 16714:
+   case 16716:
+   case 16718:
+   case 16720:
+   case 16722:
+   case 16724:
+   case 16726:
+   case 16728:
+   case 16730:
+   case 16732:
+   case 16734:
+   case 16736:
+   case 16738:
+   case 16740:
+   case 16742:
+   case 16744:
+   case 16746:
+   case 16748:
+   case 16750:
+   case 16752:
+   case 16754:
+   case 16756:
+   case 16758:
+   case 16760:
+   case 16762:
+   case 16764:
+   case 16766:
+   case 16768:
+   case 16770:
+   case 16772:
+   case 16774:
+   case 16776:
+   case 16778:
+   case 16780:
+   case 16782:
+   case 16784:
+   case 16786:
+   case 16788:
+   case 16790:
+   case 16792:
+   case 16794:
+   case 16796:
+   case 16798:
+   case 16800:
+   case 16802:
+   case 16804:
+   case 16806:
+   case 16808:
+   case 16810:
+   case 16812:
+   case 16814:
+   case 16816:
+   case 16818:
+   case 16820:
+   case 16822:
+   case 16824:
+   case 16826:
+   case 16828:
+   case 16830:
+   case 16832:
+   case 16834:
+   case 16836:
+   case 16838:
+   case 16840:
+   case 16842:
+   case 16844:
+   case 16846:
+   case 16848:
+   case 16850:
+   case 16852:
+   case 16854:
+   case 16856:
+   case 16858:
+   case 16860:
+   case 16862:
+   case 16864:
+   case 16866:
+   case 16868:
+   case 16870:
+   case 16872:
+   case 16874:
+   case 16876:
+   case 16878:
+   case 16880:
+   case 16882:
+   case 16884:
+   case 16886:
+   case 16888:
+   case 16890:
+   case 16892:
+   case 16894:
+   case 16896:
+   case 16898:
+   case 16900:
+   case 16902:
+   case 16904:
+   case 16906:
+   case 16908:
+   case 16910:
+   case 16912:
+   case 16914:
+   case 16916:
+   case 16918:
+   case 16920:
+   case 16922:
+   case 16924:
+   case 16926:
+   case 16928:
+   case 16930:
+   case 16932:
+   case 16934:
+   case 16936:
+   case 16938:
+   case 16940:
+   case 16942:
+   case 16944:
+   case 16946:
+   case 16948:
+   case 16950:
+   case 16952:
+   case 16954:
+   case 16956:
+   case 16958:
+   case 16960:
+   case 16962:
+   case 16964:
+   case 16966:
+   case 16968:
+   case 16970:
+   case 16972:
+   case 16974:
+   case 16976:
+   case 16978:
+   case 16980:
+   case 16982:
+   case 16984:
+   case 16986:
+   case 16988:
+   case 16990:
+   case 16992:
+   case 16994:
+   case 16996:
+   case 16998:
+   case 17e3:
+   case 17002:
+   case 17004:
+   case 17006:
+   case 17008:
+   case 17010:
+   case 17012:
+   case 17014:
+   case 17016:
+   case 17018:
+   case 17020:
+   case 17022:
+   case 17024:
+   case 17026:
+   case 17028:
+   case 17030:
+   case 17032:
+   case 17034:
+   case 17036:
+   case 17038:
+   case 17040:
+   case 17042:
+   case 17044:
+   case 17046:
+   case 17048:
+   case 17050:
+   case 17052:
+   case 17054:
+   case 17056:
+   case 17058:
+   case 17060:
+   case 17062:
+   case 17064:
+   case 17066:
+   case 17068:
+   case 17070:
+   case 17072:
+   case 17074:
+   case 17076:
+   case 17078:
+   case 17080:
+   case 17082:
+   case 17084:
+   case 17086:
+   case 17088:
+   case 17090:
+   case 17092:
+   case 17094:
+   case 17096:
+   case 17098:
+   case 17100:
+   case 17102:
+   case 17104:
+   case 17106:
+   case 17108:
+   case 17110:
+   case 17112:
+   case 17114:
+   case 17116:
+   case 17118:
+   case 17120:
+   case 17122:
+   case 17124:
+   case 17126:
+   case 17128:
+   case 17130:
+   case 17132:
+   case 17134:
+   case 17136:
+   case 17138:
+   case 17140:
+   case 17142:
+   case 17144:
+   case 17146:
+   case 17148:
+   case 17150:
+   case 17152:
+   case 17154:
+   case 17156:
+   case 17158:
+   case 17160:
+   case 17162:
+   case 17164:
+   case 17166:
+   case 17168:
+   case 17170:
+   case 17172:
+   case 17174:
+   case 17176:
+   case 17178:
+   case 17180:
+   case 17182:
+   case 17184:
+   case 17186:
+   case 17188:
+   case 17190:
+   case 17192:
+   case 17194:
+   case 17196:
+   case 17198:
+   case 17200:
+   case 17202:
+   case 17204:
+   case 17206:
+   case 17208:
+   case 17210:
+   case 17212:
+   case 17214:
+   case 17216:
+   case 17218:
+   case 17220:
+   case 17222:
+   case 17224:
+   case 17226:
+   case 17228:
+   case 17230:
+   case 17232:
+   case 17234:
+   case 17236:
+   case 17238:
+   case 17240:
+   case 17242:
+   case 17244:
+   case 17246:
+   case 17248:
+   case 17250:
+   case 17252:
+   case 17254:
+   case 17256:
+   case 17258:
+   case 17260:
+   case 17262:
+   case 17264:
+   case 17266:
+   case 17268:
+   case 17270:
+   case 17272:
+   case 17274:
+   case 17276:
+   case 17278:
+   case 17280:
+   case 17282:
+   case 17284:
+   case 17286:
+   case 17288:
+   case 17290:
+   case 17292:
+   case 17294:
+   case 17296:
+   case 17298:
+   case 17300:
+   case 17302:
+   case 17304:
+   case 17306:
+   case 17308:
+   case 17310:
+   case 17312:
+   case 17314:
+   case 17316:
+   case 17318:
+   case 17320:
+   case 17322:
+   case 17324:
+   case 17326:
+   case 17328:
+   case 17330:
+   case 17332:
+   case 17334:
+   case 17336:
+   case 17338:
+   case 17340:
+   case 17342:
+   case 17344:
+   case 17346:
+   case 17348:
+   case 17350:
+   case 17352:
+   case 17354:
+   case 17356:
+   case 17358:
+   case 17360:
+   case 17362:
+   case 17364:
+   case 17366:
+   case 17368:
+   case 17370:
+   case 17372:
+   case 17374:
+   case 17376:
+   case 17378:
+   case 17380:
+   case 17382:
+   case 17384:
+   case 17386:
+   case 17388:
+   case 17390:
+   case 17392:
+   case 17394:
+   case 17396:
+   case 17398:
+   case 17400:
+   case 17402:
+   case 17404:
+   case 17406:
+   case 17408:
+   case 17410:
+   case 17412:
+   case 17414:
+   case 17416:
+   case 17418:
+   case 17420:
+   case 17422:
+   case 17424:
+   case 17426:
+   case 17428:
+   case 17430:
+   case 17432:
+   case 17434:
+   case 17436:
+   case 17438:
+   case 17440:
+   case 17442:
+   case 17444:
+   case 17446:
+   case 17448:
+   case 17450:
+   case 17452:
+   case 17454:
+   case 17456:
+   case 17458:
+   case 17460:
+   case 17462:
+   case 17464:
+   case 17466:
+   case 17468:
+   case 17470:
+   case 17472:
+   case 17474:
+   case 17476:
+   case 17478:
+   case 17480:
+   case 17482:
+   case 17484:
+   case 17486:
+   case 17488:
+   case 17490:
+   case 17492:
+   case 17494:
+   case 17496:
+   case 17498:
+   case 17500:
+   case 17502:
+   case 17504:
+   case 17506:
+   case 17508:
+   case 17510:
+   case 17512:
+   case 17514:
+   case 17516:
+   case 17518:
+   case 17520:
+   case 17522:
+   case 17524:
+   case 17526:
+   case 17528:
+   case 17530:
+   case 17532:
+   case 17534:
+   case 17536:
+   case 17538:
+   case 17540:
+   case 17542:
+   case 17544:
+   case 17546:
+   case 17548:
+   case 17550:
+   case 17552:
+   case 17554:
+   case 17556:
+   case 17558:
+   case 17560:
+   case 17562:
+   case 17564:
+   case 17566:
+   case 17568:
+   case 17570:
+   case 17572:
+   case 17574:
+   case 17576:
+   case 17578:
+   case 17580:
+   case 17582:
+   case 17584:
+   case 17586:
+   case 17588:
+   case 17590:
+   case 17592:
+   case 17594:
+   case 17596:
+   case 17598:
+   case 17600:
+   case 17602:
+   case 17604:
+   case 17606:
+   case 17608:
+   case 17610:
+   case 17612:
+   case 17614:
+   case 17616:
+   case 17618:
+   case 17620:
+   case 17622:
+   case 17624:
+   case 17626:
+   case 17628:
+   case 17630:
+   case 17632:
+   case 17634:
+   case 17636:
+   case 17638:
+   case 17640:
+   case 17642:
+   case 17644:
+   case 17646:
+   case 17648:
+   case 17650:
+   case 17652:
+   case 17654:
+   case 17656:
+   case 17658:
+   case 17660:
+   case 17662:
+   case 17664:
+   case 17666:
+   case 17668:
+   case 17670:
+   case 17672:
+   case 17674:
+   case 17676:
+   case 17678:
+   case 17680:
+   case 17682:
+   case 17684:
+   case 17686:
+   case 17688:
+   case 17690:
+   case 17692:
+   case 17694:
+   case 17696:
+   case 17698:
+   case 17700:
+   case 17702:
+   case 17704:
+   case 17706:
+   case 17708:
+   case 17710:
+   case 17712:
+   case 17714:
+   case 17716:
+   case 17718:
+   case 17720:
+   case 17722:
+   case 17724:
+   case 17726:
+   case 17728:
+   case 17730:
+   case 17732:
+   case 17734:
+   case 17736:
+   case 17738:
+   case 17740:
+   case 17742:
+   case 17744:
+   case 17746:
+   case 17748:
+   case 17750:
+   case 17752:
+   case 17754:
+   case 17756:
+   case 17758:
+   case 17760:
+   case 17762:
+   case 17764:
+   case 17766:
+   case 17768:
+   case 17770:
+   case 17772:
+   case 17774:
+   case 17776:
+   case 17778:
+   case 17780:
+   case 17782:
+   case 17784:
+   case 17786:
+   case 17788:
+   case 17790:
+   case 17792:
+   case 17794:
+   case 17796:
+   case 17798:
+   case 17800:
+   case 17802:
+   case 17804:
+   case 17806:
+   case 17808:
+   case 17810:
+   case 17812:
+   case 17814:
+   case 17816:
+   case 17818:
+   case 17820:
+   case 17822:
+   case 17824:
+   case 17826:
+   case 17828:
+   case 17830:
+   case 17832:
+   case 17834:
+   case 17836:
+   case 17838:
+   case 17840:
+   case 17842:
+   case 17844:
+   case 17846:
+   case 17848:
+   case 17850:
+   case 17852:
+   case 17854:
+   case 17856:
+   case 17858:
+   case 17860:
+   case 17862:
+   case 17864:
+   case 17866:
+   case 17868:
+   case 17870:
+   case 17872:
+   case 17874:
+   case 17876:
+   case 17878:
+   case 17880:
+   case 17882:
+   case 17884:
+   case 17886:
+   case 17888:
+   case 17890:
+   case 17892:
+   case 17894:
+   case 17896:
+   case 17898:
+   case 17900:
+   case 17902:
+   case 17904:
+   case 17906:
+   case 17908:
+   case 17910:
+   case 17912:
+   case 17914:
+   case 17916:
+   case 17918:
+   case 17920:
+   case 17922:
+   case 17924:
+   case 17926:
+   case 17928:
+   case 17930:
+   case 17932:
+   case 17934:
+   case 17936:
+   case 17938:
+   case 17940:
+   case 17942:
+   case 17944:
+   case 17946:
+   case 17948:
+   case 17950:
+   case 17952:
+   case 17954:
+   case 17956:
+   case 17958:
+   case 17960:
+   case 17962:
+   case 17964:
+   case 17966:
+   case 17968:
+   case 17970:
+   case 17972:
+   case 17974:
+   case 17976:
+   case 17978:
+   case 17980:
+   case 17982:
+   case 17984:
+   case 17986:
+   case 17988:
+   case 17990:
+   case 17992:
+   case 17994:
+   case 17996:
+   case 17998:
+   case 18e3:
+   case 18002:
+   case 18004:
+   case 18006:
+   case 18008:
+   case 18010:
+   case 18012:
+   case 18014:
+   case 18016:
+   case 18018:
+   case 18020:
+   case 18022:
+   case 18024:
+   case 18026:
+   case 18028:
+   case 18030:
+   case 18032:
+   case 18034:
+   case 18036:
+   case 18038:
+   case 18040:
+   case 18042:
+   case 18044:
+   case 18046:
+   case 18048:
+   case 18050:
+   case 18052:
+   case 18054:
+   case 18056:
+   case 18058:
+   case 18060:
+   case 18062:
+   case 18064:
+   case 18066:
+   case 18068:
+   case 18070:
+   case 18072:
+   case 18074:
+   case 18076:
+   case 18078:
+   case 18080:
+   case 18082:
+   case 18084:
+   case 18086:
+   case 18088:
+   case 18090:
+   case 18092:
+   case 18094:
+   case 18096:
+   case 18098:
+   case 18100:
+   case 18102:
+   case 18104:
+   case 18106:
+   case 18108:
+   case 18110:
+   case 18112:
+   case 18114:
+   case 18116:
+   case 18118:
+   case 18120:
+   case 18122:
+   case 18124:
+   case 18126:
+   case 18128:
+   case 18130:
+   case 18132:
+   case 18134:
+   case 18136:
+   case 18138:
+   case 18140:
+   case 18142:
+   case 18144:
+   case 18146:
+   case 18148:
+   case 18150:
+   case 18152:
+   case 18154:
+   case 18156:
+   case 18158:
+   case 18160:
+   case 18162:
+   case 18164:
+   case 18166:
+   case 18168:
+   case 18170:
+   case 18172:
+   case 18174:
+   case 18176:
+   case 18178:
+   case 18180:
+   case 18182:
+   case 18184:
+   case 18186:
+   case 18188:
+   case 18190:
+   case 18192:
+   case 18194:
+   case 18196:
+   case 18198:
+   case 18200:
+   case 18202:
+   case 18204:
+   case 18206:
+   case 18208:
+   case 18210:
+   case 18212:
+   case 18214:
+   case 18216:
+   case 18218:
+   case 18220:
+   case 18222:
+   case 18224:
+   case 18226:
+   case 18228:
+   case 18230:
+   case 18232:
+   case 18234:
+   case 18236:
+   case 18238:
+   case 18240:
+   case 18242:
+   case 18244:
+   case 18246:
+   case 18248:
+   case 18250:
+   case 18252:
+   case 18254:
+   case 18256:
+   case 18258:
+   case 18260:
+   case 18262:
+   case 18264:
+   case 18266:
+   case 18268:
+   case 18270:
+   case 18272:
+   case 18274:
+   case 18276:
+   case 18278:
+   case 18280:
+   case 18282:
+   case 18284:
+   case 18286:
+   case 18288:
+   case 18290:
+   case 18292:
+   case 18294:
+   case 18296:
+   case 18298:
+   case 18300:
+   case 18302:
+   case 18304:
+   case 18306:
+   case 18308:
+   case 18310:
+   case 18312:
+   case 18314:
+   case 18316:
+   case 18318:
+   case 18320:
+   case 18322:
+   case 18324:
+   case 18326:
+   case 18328:
+   case 18330:
+   case 18332:
+   case 18334:
+   case 18336:
+   case 18338:
+   case 18340:
+   case 18342:
+   case 18344:
+   case 18346:
+   case 18348:
+   case 18350:
+   case 18352:
+   case 18354:
+   case 18356:
+   case 18358:
+   case 18360:
+   case 18362:
+   case 18364:
+   case 18366:
+   case 18368:
+   case 18370:
+   case 18372:
+   case 18374:
+   case 18376:
+   case 18378:
+   case 18380:
+   case 18382:
+   case 18384:
+   case 18386:
+   case 18388:
+   case 18390:
+   case 18392:
+   case 18394:
+   case 18396:
+   case 18398:
+   case 18400:
+   case 18402:
+   case 18404:
+   case 18406:
+   case 18408:
+   case 18410:
+   case 18412:
+   case 18414:
+   case 18416:
+   case 18418:
+   case 18420:
+   case 18422:
+   case 18424:
+   case 18426:
+   case 18428:
+   case 18430:
+   case 18432:
+   case 18434:
+   case 18436:
+   case 18438:
+   case 18440:
+   case 18442:
+   case 18444:
+   case 18446:
+   case 18448:
+   case 18450:
+   case 18452:
+   case 18454:
+   case 18456:
+   case 18458:
+   case 18460:
+   case 18462:
+   case 18464:
+   case 18466:
+   case 18468:
+   case 18470:
+   case 18472:
+   case 18474:
+   case 18476:
+   case 18478:
+   case 18480:
+   case 18482:
+   case 18484:
+   case 18486:
+   case 18488:
+   case 18490:
+   case 18492:
+   case 18494:
+   case 18496:
+   case 18498:
+   case 18500:
+   case 18502:
+   case 18504:
+   case 18506:
+   case 18508:
+   case 18510:
+   case 18512:
+   case 18514:
+   case 18516:
+   case 18518:
+   case 18520:
+   case 18522:
+   case 18524:
+   case 18526:
+   case 18528:
+   case 18530:
+   case 18532:
+   case 18534:
+   case 18536:
+   case 18538:
+   case 18540:
+   case 18542:
+   case 18544:
+   case 18546:
+   case 18548:
+   case 18550:
+   case 18552:
+   case 18554:
+   case 18556:
+   case 18558:
+   case 18560:
+   case 18562:
+   case 18564:
+   case 18566:
+   case 18568:
+   case 18570:
+   case 18572:
+   case 18574:
+   case 18576:
+   case 18578:
+   case 18580:
+   case 18582:
+   case 18584:
+   case 18586:
+   case 18588:
+   case 18590:
+   case 18592:
+   case 18594:
+   case 18596:
+   case 18598:
+   case 18600:
+   case 18602:
+   case 18604:
+   case 18606:
+   case 18608:
+   case 18610:
+   case 18612:
+   case 18614:
+   case 18616:
+   case 18618:
+   case 18620:
+   case 18622:
+   case 18624:
+   case 18626:
+   case 18628:
+   case 18630:
+   case 18632:
+   case 18634:
+   case 18636:
+   case 18638:
+   case 18640:
+   case 18642:
+   case 18644:
+   case 18646:
+   case 18648:
+   case 18650:
+   case 18652:
+   case 18654:
+   case 18656:
+   case 18658:
+   case 18660:
+   case 18662:
+   case 18664:
+   case 18666:
+   case 18668:
+   case 18670:
+   case 18672:
+   case 18674:
+   case 18676:
+   case 18678:
+   case 18680:
+   case 18682:
+   case 18684:
+   case 18686:
+   case 18688:
+   case 18690:
+   case 18692:
+   case 18694:
+   case 18696:
+   case 18698:
+   case 18700:
+   case 18702:
+   case 18704:
+   case 18706:
+   case 18708:
+   case 18710:
+   case 18712:
+   case 18714:
+   case 18716:
+   case 18718:
+   case 18720:
+   case 18722:
+   case 18724:
+   case 18726:
+   case 18728:
+   case 18730:
+   case 18732:
+   case 18734:
+   case 18736:
+   case 18738:
+   case 18740:
+   case 18742:
+   case 18744:
+   case 18746:
+   case 18748:
+   case 18750:
+   case 18752:
+   case 18754:
+   case 18756:
+   case 18758:
+   case 18760:
+   case 18762:
+   case 18764:
+   case 18766:
+   case 18768:
+   case 18770:
+   case 18772:
+   case 18774:
+   case 18776:
+   case 18778:
+   case 18780:
+   case 18782:
+   case 18784:
+   case 18786:
+   case 18788:
+   case 18790:
+   case 18792:
+   case 18794:
+   case 18796:
+   case 18798:
+   case 18800:
+   case 18802:
+   case 18804:
+   case 18806:
+   case 18808:
+   case 18810:
+   case 18812:
+   case 18814:
+   case 18816:
+   case 18818:
+   case 18820:
+   case 18822:
+   case 18824:
+   case 18826:
+   case 18828:
+   case 18830:
+   case 18832:
+   case 18834:
+   case 18836:
+   case 18838:
+   case 18840:
+   case 18842:
+   case 18844:
+   case 18846:
+   case 18848:
+   case 18850:
+   case 18852:
+   case 18854:
+   case 18856:
+   case 18858:
+   case 18860:
+   case 18862:
+   case 18864:
+   case 18866:
+   case 18868:
+   case 18870:
+   case 18872:
+   case 18874:
+   case 18876:
+   case 18878:
+   case 18880:
+   case 18882:
+   case 18884:
+   case 18886:
+   case 18888:
+   case 18890:
+   case 18892:
+   case 18894:
+   case 18896:
+   case 18898:
+   case 18900:
+   case 18902:
+   case 18904:
+   case 18906:
+   case 18908:
+   case 18910:
+   case 18912:
+   case 18914:
+   case 18916:
+   case 18918:
+   case 18920:
+   case 18922:
+   case 18924:
+   case 18926:
+   case 18928:
+   case 18930:
+   case 18932:
+   case 18934:
+   case 18936:
+   case 18938:
+   case 18940:
+   case 18942:
+   case 18944:
+   case 18946:
+   case 18948:
+   case 18950:
+   case 18952:
+   case 18954:
+   case 18956:
+   case 18958:
+   case 18960:
+   case 18962:
+   case 18964:
+   case 18966:
+   case 18968:
+   case 18970:
+   case 18972:
+   case 18974:
+   case 18976:
+   case 18978:
+   case 18980:
+   case 18982:
+   case 18984:
+   case 18986:
+   case 18988:
+   case 18990:
+   case 18992:
+   case 18994:
+   case 18996:
+   case 18998:
+   case 19e3:
+   case 19002:
+   case 19004:
+   case 19006:
+   case 19008:
+   case 19010:
+   case 19012:
+   case 19014:
+   case 19016:
+   case 19018:
+   case 19020:
+   case 19022:
+   case 19024:
+   case 19026:
+   case 19028:
+   case 19030:
+   case 19032:
+   case 19034:
+   case 19036:
+   case 19038:
+   case 19040:
+   case 19042:
+   case 19044:
+   case 19046:
+   case 19048:
+   case 19050:
+   case 19052:
+   case 19054:
+   case 19056:
+   case 19058:
+   case 19060:
+   case 19062:
+   case 19064:
+   case 19066:
+   case 19068:
+   case 19070:
+   case 19072:
+   case 19074:
+   case 19076:
+   case 19078:
+   case 19080:
+   case 19082:
+   case 19084:
+   case 19086:
+   case 19088:
+   case 19090:
+   case 19092:
+   case 19094:
+   case 19096:
+   case 19098:
+   case 19100:
+   case 19102:
+   case 19104:
+   case 19106:
+   case 19108:
+   case 19110:
+   case 19112:
+   case 19114:
+   case 19116:
+   case 19118:
+   case 19120:
+   case 19122:
+   case 19124:
+   case 19126:
+   case 19128:
+   case 19130:
+   case 19132:
+   case 19134:
+   case 19136:
+   case 19138:
+   case 19140:
+   case 19142:
+   case 19144:
+   case 19146:
+   case 19148:
+   case 19150:
+   case 19152:
+   case 19154:
+   case 19156:
+   case 19158:
+   case 19160:
+   case 19162:
+   case 19164:
+   case 19166:
+   case 19168:
+   case 19170:
+   case 19172:
+   case 19174:
+   case 19176:
+   case 19178:
+   case 19180:
+   case 19182:
+   case 19184:
+   case 19186:
+   case 19188:
+   case 19190:
+   case 19192:
+   case 19194:
+   case 19196:
+   case 19198:
+   case 19200:
+   case 19202:
+   case 19204:
+   case 19206:
+   case 19208:
+   case 19210:
+   case 19212:
+   case 19214:
+   case 19216:
+   case 19218:
+   case 19220:
+   case 19222:
+   case 19224:
+   case 19226:
+   case 19228:
+   case 19230:
+   case 19232:
+   case 19234:
+   case 19236:
+   case 19238:
+   case 19240:
+   case 19242:
+   case 19244:
+   case 19246:
+   case 19248:
+   case 19250:
+   case 19252:
+   case 19254:
+   case 19256:
+   case 19258:
+   case 19260:
+   case 19262:
+   case 19264:
+   case 19266:
+   case 19268:
+   case 19270:
+   case 19272:
+   case 19274:
+   case 19276:
+   case 19278:
+   case 19280:
+   case 19282:
+   case 19284:
+   case 19286:
+   case 19288:
+   case 19290:
+   case 19292:
+   case 19294:
+   case 19296:
+   case 19298:
+   case 19300:
+   case 19302:
+   case 19304:
+   case 19306:
+   case 19308:
+   case 19310:
+   case 19312:
+   case 19314:
+   case 19316:
+   case 19318:
+   case 19320:
+   case 19322:
+   case 19324:
+   case 19326:
+   case 19328:
+   case 19330:
+   case 19332:
+   case 19334:
+   case 19336:
+   case 19338:
+   case 19340:
+   case 19342:
+   case 19344:
+   case 19346:
+   case 19348:
+   case 19350:
+   case 19352:
+   case 19354:
+   case 19356:
+   case 19358:
+   case 19360:
+   case 19362:
+   case 19364:
+   case 19366:
+   case 19368:
+   case 19370:
+   case 19372:
+   case 19374:
+   case 19376:
+   case 19378:
+   case 19380:
+   case 19382:
+   case 19384:
+   case 19386:
+   case 19388:
+   case 19390:
+   case 19392:
+   case 19394:
+   case 19396:
+   case 19398:
+   case 19400:
+   case 19402:
+   case 19404:
+   case 19406:
+   case 19408:
+   case 19410:
+   case 19412:
+   case 19414:
+   case 19416:
+   case 19418:
+   case 19420:
+   case 19422:
+   case 19424:
+   case 19426:
+   case 19428:
+   case 19430:
+   case 19432:
+   case 19434:
+   case 19436:
+   case 19438:
+   case 19440:
+   case 19442:
+   case 19444:
+   case 19446:
+   case 19448:
+   case 19450:
+   case 19452:
+   case 19454:
+   case 19456:
+   case 19458:
+   case 19460:
+   case 19462:
+   case 19464:
+   case 19466:
+   case 19468:
+   case 19470:
+   case 19472:
+   case 19474:
+   case 19476:
+   case 19478:
+   case 19480:
+   case 19482:
+   case 19484:
+   case 19486:
+   case 19488:
+   case 19490:
+   case 19492:
+   case 19494:
+   case 19496:
+   case 19498:
+   case 19500:
+   case 19502:
+   case 19504:
+   case 19506:
+   case 19508:
+   case 19510:
+   case 19512:
+   case 19514:
+   case 19516:
+   case 19518:
+   case 19520:
+   case 19522:
+   case 19524:
+   case 19526:
+   case 19528:
+   case 19530:
+   case 19532:
+   case 19534:
+   case 19536:
+   case 19538:
+   case 19540:
+   case 19542:
+   case 19544:
+   case 19546:
+   case 19548:
+   case 19550:
+   case 19552:
+   case 19554:
+   case 19556:
+   case 19558:
+   case 19560:
+   case 19562:
+   case 19564:
+   case 19566:
+   case 19568:
+   case 19570:
+   case 19572:
+   case 19574:
+   case 19576:
+   case 19578:
+   case 19580:
+   case 19582:
+   case 19584:
+   case 19586:
+   case 19588:
+   case 19590:
+   case 19592:
+   case 19594:
+   case 19596:
+   case 19598:
+   case 19600:
+   case 19602:
+   case 19604:
+   case 19606:
+   case 19608:
+   case 19610:
+   case 19612:
+   case 19614:
+   case 19616:
+   case 19618:
+   case 19620:
+   case 19622:
+   case 19624:
+   case 19626:
+   case 19628:
+   case 19630:
+   case 19632:
+   case 19634:
+   case 19636:
+   case 19638:
+   case 19640:
+   case 19642:
+   case 19644:
+   case 19646:
+   case 19648:
+   case 19650:
+   case 19652:
+   case 19654:
+   case 19656:
+   case 19658:
+   case 19660:
+   case 19662:
+   case 19664:
+   case 19666:
+   case 19668:
+   case 19670:
+   case 19672:
+   case 19674:
+   case 19676:
+   case 19678:
+   case 19680:
+   case 19682:
+   case 19684:
+   case 19686:
+   case 19688:
+   case 19690:
+   case 19692:
+   case 19694:
+   case 19696:
+   case 19698:
+   case 19700:
+   case 19702:
+   case 19704:
+   case 19706:
+   case 19708:
+   case 19710:
+   case 19712:
+   case 19714:
+   case 19716:
+   case 19718:
+   case 19720:
+   case 19722:
+   case 19724:
+   case 19726:
+   case 19728:
+   case 19730:
+   case 19732:
+   case 19734:
+   case 19736:
+   case 19738:
+   case 19740:
+   case 19742:
+   case 19744:
+   case 19746:
+   case 19748:
+   case 19750:
+   case 19752:
+   case 19754:
+   case 19756:
+   case 19758:
+   case 19760:
+   case 19762:
+   case 19764:
+   case 19766:
+   case 19768:
+   case 19770:
+   case 19772:
+   case 19774:
+   case 19776:
+   case 19778:
+   case 19780:
+   case 19782:
+   case 19784:
+   case 19786:
+   case 19788:
+   case 19790:
+   case 19792:
+   case 19794:
+   case 19796:
+   case 19798:
+   case 19800:
+   case 19802:
+   case 19804:
+   case 19806:
+   case 19808:
+   case 19810:
+   case 19812:
+   case 19814:
+   case 19816:
+   case 19818:
+   case 19820:
+   case 19822:
+   case 19824:
+   case 19826:
+   case 19828:
+   case 19830:
+   case 19832:
+   case 19834:
+   case 19836:
+   case 19838:
+   case 19840:
+   case 19842:
+   case 19844:
+   case 19846:
+   case 19848:
+   case 19850:
+   case 19852:
+   case 19854:
+   case 19856:
+   case 19858:
+   case 19860:
+   case 19862:
+   case 19864:
+   case 19866:
+   case 19868:
+   case 19870:
+   case 19872:
+   case 19874:
+   case 19876:
+   case 19878:
+   case 19880:
+   case 19882:
+   case 19884:
+   case 19886:
+   case 19888:
+   case 19890:
+   case 19892:
+   case 19894:
+   case 19896:
+   case 19898:
+   case 19900:
+   case 19902:
+   case 19904:
+   case 19906:
+   case 19908:
+   case 19910:
+   case 19912:
+   case 19914:
+   case 19916:
+   case 19918:
+   case 19920:
+   case 19922:
+   case 19924:
+   case 19926:
+   case 19928:
+   case 19930:
+   case 19932:
+   case 19934:
+   case 19936:
+   case 19938:
+   case 19940:
+   case 19942:
+   case 19944:
+   case 19946:
+   case 19948:
+   case 19950:
+   case 19952:
+   case 19954:
+   case 19956:
+   case 19958:
+   case 19960:
+   case 19962:
+   case 19964:
+   case 19966:
+   case 19968:
+   case 19970:
+   case 19972:
+   case 19974:
+   case 19976:
+   case 19978:
+   case 19980:
+   case 19982:
+   case 19984:
+   case 19986:
+   case 19988:
+   case 19990:
+   case 19992:
+   case 19994:
+   case 19996:
+   case 19998:
+   case 2e4:
+   case 20002:
+   case 20004:
+   case 20006:
+   case 20008:
+   case 20010:
+   case 20012:
+   case 20014:
+   case 20016:
+   case 20018:
+   case 20020:
+   case 20022:
+   case 20024:
+   case 20026:
+   case 20028:
+   case 20030:
+   case 20032:
+   case 20034:
+   case 20036:
+   case 20038:
+   case 20040:
+   case 20042:
+   case 20044:
+   case 20046:
+   case 20048:
+   case 20050:
+   case 20052:
+   case 20054:
+   case 20056:
+   case 20058:
+   case 20060:
+   case 20062:
+   case 20064:
+   case 20066:
+   case 20068:
+   case 20070:
+   case 20072:
+   case 20074:
+   case 20076:
+   case 20078:
+   case 20080:
+   case 20082:
+   case 20084:
+   case 20086:
+   case 20088:
+   case 20090:
+   case 20092:
+   case 20094:
+   case 20096:
+   case 20098:
+   case 20100:
+   case 20102:
+   case 20104:
+   case 20106:
+   case 20108:
+   case 20110:
+   case 20112:
+   case 20114:
+   case 20116:
+   case 20118:
+   case 20120:
+   case 20122:
+   case 20124:
+   case 20126:
+   case 20128:
+   case 20130:
+   case 20132:
+   case 20134:
+   case 20136:
+   case 20138:
+   case 20140:
+   case 20142:
+   case 20144:
+   case 20146:
+   case 20148:
+   case 20150:
+   case 20152:
+   case 20154:
+   case 20156:
+   case 20158:
+   case 20160:
+   case 20162:
+   case 20164:
+   case 20166:
+   case 20168:
+   case 20170:
+   case 20172:
+   case 20174:
+   case 20176:
+   case 20178:
+   case 20180:
+   case 20182:
+   case 20184:
+   case 20186:
+   case 20188:
+   case 20190:
+   case 20192:
+   case 20194:
+   case 20196:
+   case 20198:
+   case 20200:
+   case 20202:
+   case 20204:
+   case 20206:
+   case 20208:
+   case 20210:
+   case 20212:
+   case 20214:
+   case 20216:
+   case 20218:
+   case 20220:
+   case 20222:
+   case 20224:
+   case 20226:
+   case 20228:
+   case 20230:
+   case 20232:
+   case 20234:
+   case 20236:
+   case 20238:
+   case 20240:
+   case 20242:
+   case 20244:
+   case 20246:
+   case 20248:
+   case 20250:
+   case 20252:
+   case 20254:
+   case 20256:
+   case 20258:
+   case 20260:
+   case 20262:
+   case 20264:
+   case 20266:
+   case 20268:
+   case 20270:
+   case 20272:
+   case 20274:
+   case 20276:
+   case 20278:
+   case 20280:
+   case 20282:
+   case 20284:
+   case 20286:
+   case 20288:
+   case 20290:
+   case 20292:
+   case 20294:
+   case 20296:
+   case 20298:
+   case 20300:
+   case 20302:
+   case 20304:
+   case 20306:
+   case 20308:
+   case 20310:
+   case 20312:
+   case 20314:
+   case 20316:
+   case 20318:
+   case 20320:
+   case 20322:
+   case 20324:
+   case 20326:
+   case 20328:
+   case 20330:
+   case 20332:
+   case 20334:
+   case 20336:
+   case 20338:
+   case 20340:
+   case 20342:
+   case 20344:
+   case 20346:
+   case 20348:
+   case 20350:
+   case 20352:
+   case 20354:
+   case 20356:
+   case 20358:
+   case 20360:
+   case 20362:
+   case 20364:
+   case 20366:
+   case 20368:
+   case 20370:
+   case 20372:
+   case 20374:
+   case 20376:
+   case 20378:
+   case 20380:
+   case 20382:
+   case 20384:
+   case 20386:
+   case 20388:
+   case 20390:
+   case 20392:
+   case 20394:
+   case 20396:
+   case 20398:
+   case 20400:
+   case 20402:
+   case 20404:
+   case 20406:
+   case 20408:
+   case 20410:
+   case 20412:
+   case 20414:
+   case 20416:
+   case 20418:
+   case 20420:
+   case 20422:
+   case 20424:
+   case 20426:
+   case 20428:
+   case 20430:
+   case 20432:
+   case 20434:
+   case 20436:
+   case 20438:
+   case 20440:
+   case 20442:
+   case 20444:
+   case 20446:
+   case 20448:
+   case 20450:
+   case 20452:
+   case 20454:
+   case 20456:
+   case 20458:
+   case 20460:
+   case 20462:
+   case 20464:
+   case 20466:
+   case 20468:
+   case 20470:
+   case 20472:
+   case 20474:
+   case 20476:
+   case 20478:
+   case 20480:
+   case 20482:
+   case 20484:
+   case 20486:
+   case 20488:
+   case 20490:
+   case 20492:
+   case 20494:
+   case 20496:
+   case 20498:
+   case 20500:
+   case 20502:
+   case 20504:
+   case 20506:
+   case 20508:
+   case 20510:
+   case 20512:
+   case 20514:
+   case 20516:
+   case 20518:
+   case 20520:
+   case 20522:
+   case 20524:
+   case 20526:
+   case 20528:
+   case 20530:
+   case 20532:
+   case 20534:
+   case 20536:
+   case 20538:
+   case 20540:
+   case 20542:
+   case 20544:
+   case 20546:
+   case 20548:
+   case 20550:
+   case 20552:
+   case 20554:
+   case 20556:
+   case 20558:
+   case 20560:
+   case 20562:
+   case 20564:
+   case 20566:
+   case 20568:
+   case 20570:
+   case 20572:
+   case 20574:
+   case 20576:
+   case 20578:
+   case 20580:
+   case 20582:
+   case 20584:
+   case 20586:
+   case 20588:
+   case 20590:
+   case 20592:
+   case 20594:
+   case 20596:
+   case 20598:
+   case 20600:
+   case 20602:
+   case 20604:
+   case 20606:
+   case 20608:
+   case 20610:
+   case 20612:
+   case 20614:
+   case 20616:
+   case 20618:
+   case 20620:
+   case 20622:
+   case 20624:
+   case 20626:
+   case 20628:
+   case 20630:
+   case 20632:
+   case 20634:
+   case 20636:
+   case 20638:
+   case 20640:
+   case 20642:
+   case 20644:
+   case 20646:
+   case 20648:
+   case 20650:
+   case 20652:
+   case 20654:
+   case 20656:
+   case 20658:
+   case 20660:
+   case 20662:
+   case 20664:
+   case 20666:
+   case 20668:
+   case 20670:
+   case 20672:
+   case 20674:
+   case 20676:
+   case 20678:
+   case 20680:
+   case 20682:
+   case 20684:
+   case 20686:
+   case 20688:
+   case 20690:
+   case 20692:
+   case 20694:
+   case 20696:
+   case 20698:
+   case 20700:
+   case 20702:
+   case 20704:
+   case 20706:
+   case 20708:
+   case 20710:
+   case 20712:
+   case 20714:
+   case 20716:
+   case 20718:
+   case 20720:
+   case 20722:
+   case 20724:
+   case 20726:
+   case 20728:
+   case 20730:
+   case 20732:
+   case 20734:
+   case 20736:
+   case 20738:
+   case 20740:
+   case 20742:
+   case 20744:
+   case 20746:
+   case 20748:
+   case 20750:
+   case 20752:
+   case 20754:
+   case 20756:
+   case 20758:
+   case 20760:
+   case 20762:
+   case 20764:
+   case 20766:
+   case 20768:
+   case 20770:
+   case 20772:
+   case 20774:
+   case 20776:
+   case 20778:
+   case 20780:
+   case 20782:
+   case 20784:
+   case 20786:
+   case 20788:
+   case 20790:
+   case 20792:
+   case 20794:
+   case 20796:
+   case 20798:
+   case 20800:
+   case 20802:
+   case 20804:
+   case 20806:
+   case 20808:
+   case 20810:
+   case 20812:
+   case 20814:
+   case 20816:
+   case 20818:
+   case 20820:
+   case 20822:
+   case 20824:
+   case 20826:
+   case 20828:
+   case 20830:
+   case 20832:
+   case 20834:
+   case 20836:
+   case 20838:
+   case 20840:
+   case 20842:
+   case 20844:
+   case 20846:
+   case 20848:
+   case 20850:
+   case 20852:
+   case 20854:
+   case 20856:
+   case 20858:
+   case 20860:
+   case 20862:
+   case 20864:
+   case 20866:
+   case 20868:
+   case 20870:
+   case 20872:
+   case 20874:
+   case 20876:
+   case 20878:
+   case 20880:
+   case 20882:
+   case 20884:
+   case 20886:
+   case 20888:
+   case 20890:
+   case 20892:
+   case 20894:
+   case 20896:
+   case 20898:
+   case 20900:
+   case 20902:
+   case 20904:
+   case 20906:
+   case 20908:
+   case 20910:
+   case 20912:
+   case 20914:
+   case 20916:
+   case 20918:
+   case 20920:
+   case 20922:
+   case 20924:
+   case 20926:
+   case 20928:
+   case 20930:
+   case 20932:
+   case 20934:
+   case 20936:
+   case 20938:
+   case 20940:
+   case 20942:
+   case 20944:
+   case 20946:
+   case 20948:
+   case 20950:
+   case 20952:
+   case 20954:
+   case 20956:
+   case 20958:
+   case 20960:
+   case 20962:
+   case 20964:
+   case 20966:
+   case 20968:
+   case 20970:
+   case 20972:
+   case 20974:
+   case 20976:
+   case 20978:
+   case 20980:
+   case 20982:
+   case 20984:
+   case 20986:
+   case 20988:
+   case 20990:
+   case 20992:
+   case 20994:
+   case 20996:
+   case 20998:
+   case 21e3:
+   case 21002:
+   case 21004:
+   case 21006:
+   case 21008:
+   case 21010:
+   case 21012:
+   case 21014:
+   case 21016:
+   case 21018:
+   case 21020:
+   case 21022:
+   case 21024:
+   case 21026:
+   case 21028:
+   case 21030:
+   case 21032:
+   case 21034:
+   case 21036:
+   case 21038:
+   case 21040:
+   case 21042:
+   case 21044:
+   case 21046:
+   case 21048:
+   case 21050:
+   case 21052:
+   case 21054:
+   case 21056:
+   case 21058:
+   case 21060:
+   case 21062:
+   case 21064:
+   case 21066:
+   case 21068:
+   case 21070:
+   case 21072:
+   case 21074:
+   case 21076:
+   case 21078:
+   case 21080:
+   case 21082:
+   case 21084:
+   case 21086:
+   case 21088:
+   case 21090:
+   case 21092:
+   case 21094:
+   case 21096:
+   case 21098:
+   case 21100:
+   case 21102:
+   case 21104:
+   case 21106:
+   case 21108:
+   case 21110:
+   case 21112:
+   case 21114:
+   case 21116:
+   case 21118:
+   case 21120:
+   case 21122:
+   case 21124:
+   case 21126:
+   case 21128:
+   case 21130:
+   case 21132:
+   case 21134:
+   case 21136:
+   case 21138:
+   case 21140:
+   case 21142:
+   case 21144:
+   case 21146:
+   case 21148:
+   case 21150:
+   case 21152:
+   case 21154:
+   case 21156:
+   case 21158:
+   case 21160:
+   case 21162:
+   case 21164:
+   case 21166:
+   case 21168:
+   case 21170:
+   case 21172:
+   case 21174:
+   case 21176:
+   case 21178:
+   case 21180:
+   case 21182:
+   case 21184:
+   case 21186:
+   case 21188:
+   case 21190:
+   case 21192:
+   case 21194:
+   case 21196:
+   case 21198:
+   case 21200:
+   case 21202:
+   case 21204:
+   case 21206:
+   case 21208:
+   case 21210:
+   case 21212:
+   case 21214:
+   case 21216:
+   case 21218:
+   case 21220:
+   case 21222:
+   case 21224:
+   case 21226:
+   case 21228:
+   case 21230:
+   case 21232:
+   case 21234:
+   case 21236:
+   case 21238:
+   case 21240:
+   case 21242:
+   case 21244:
+   case 21246:
+   case 21248:
+   case 21250:
+   case 21252:
+   case 21254:
+   case 21256:
+   case 21258:
+   case 21260:
+   case 21262:
+   case 21264:
+   case 21266:
+   case 21268:
+   case 21270:
+   case 21272:
+   case 21274:
+   case 21276:
+   case 21278:
+   case 21280:
+   case 21282:
+   case 21284:
+   case 21286:
+   case 21288:
+   case 21290:
+   case 21292:
+   case 21294:
+   case 21296:
+   case 21298:
+   case 21300:
+   case 21302:
+   case 21304:
+   case 21306:
+   case 21308:
+   case 21310:
+   case 21312:
+   case 21314:
+   case 21316:
+   case 21318:
+   case 21320:
+   case 21322:
+   case 21324:
+   case 21326:
+   case 21328:
+   case 21330:
+   case 21332:
+   case 21334:
+   case 21336:
+   case 21338:
+   case 21340:
+   case 21342:
+   case 21344:
+   case 21346:
+   case 21348:
+   case 21350:
+   case 21352:
+   case 21354:
+   case 21356:
+   case 21358:
+   case 21360:
+   case 21362:
+   case 21364:
+   case 21366:
+   case 21368:
+   case 21370:
+   case 21372:
+   case 21374:
+   case 21376:
+   case 21378:
+   case 21380:
+   case 21382:
+   case 21384:
+   case 21386:
+   case 21388:
+   case 21390:
+   case 21392:
+   case 21394:
+   case 21396:
+   case 21398:
+   case 21400:
+   case 21402:
+   case 21404:
+   case 21406:
+   case 21408:
+   case 21410:
+   case 21412:
+   case 21414:
+   case 21416:
+   case 21418:
+   case 21420:
+   case 21422:
+   case 21424:
+   case 21426:
+   case 21428:
+   case 21430:
+   case 21432:
+   case 21434:
+   case 21436:
+   case 21438:
+   case 21440:
+   case 21442:
+   case 21444:
+   case 21446:
+   case 21448:
+   case 21450:
+   case 21452:
+   case 21454:
+   case 21456:
+   case 21458:
+   case 21460:
+   case 21462:
+   case 21464:
+   case 21466:
+   case 21468:
+   case 21470:
+   case 21472:
+   case 21474:
+   case 21476:
+   case 21478:
+   case 21480:
+   case 21482:
+   case 21484:
+   case 21486:
+   case 21488:
+   case 21490:
+   case 21492:
+   case 21494:
+   case 21496:
+   case 21498:
+   case 21500:
+   case 21502:
+   case 21504:
+   case 21506:
+   case 21508:
+   case 21510:
+   case 21512:
+   case 21514:
+   case 21516:
+   case 21518:
+   case 21520:
+   case 21522:
+   case 21524:
+   case 21526:
+   case 21528:
+   case 21530:
+   case 21532:
+   case 21534:
+   case 21536:
+   case 21538:
+   case 21540:
+   case 21542:
+   case 21544:
+   case 21546:
+   case 21548:
+   case 21550:
+   case 21552:
+   case 21554:
+   case 21556:
+   case 21558:
+   case 21560:
+   case 21562:
+   case 21564:
+   case 21566:
+   case 21568:
+   case 21570:
+   case 21572:
+   case 21574:
+   case 21576:
+   case 21578:
+   case 21580:
+   case 21582:
+   case 21584:
+   case 21586:
+   case 21588:
+   case 21590:
+   case 21592:
+   case 21594:
+   case 21596:
+   case 21598:
+   case 21600:
+   case 21602:
+   case 21604:
+   case 21606:
+   case 21608:
+   case 21610:
+   case 21612:
+   case 21614:
+   case 21616:
+   case 21618:
+   case 21620:
+   case 21622:
+   case 21624:
+   case 21626:
+   case 21628:
+   case 21630:
+   case 21632:
+   case 21634:
+   case 21636:
+   case 21638:
+   case 21640:
+   case 21642:
+   case 21644:
+   case 21646:
+   case 21648:
+   case 21650:
+   case 21652:
+   case 21654:
+   case 21656:
+   case 21658:
+   case 21660:
+   case 21662:
+   case 21664:
+   case 21666:
+   case 21668:
+   case 21670:
+   case 21672:
+   case 21674:
+   case 21676:
+   case 21678:
+   case 21680:
+   case 21682:
+   case 21684:
+   case 21686:
+   case 21688:
+   case 21690:
+   case 21692:
+   case 21694:
+   case 21696:
+   case 21698:
+   case 21700:
+   case 21702:
+   case 21704:
+   case 21706:
+   case 21708:
+   case 21710:
+   case 21712:
+   case 21714:
+   case 21716:
+   case 21718:
+   case 21720:
+   case 21722:
+   case 21724:
+   case 21726:
+   case 21728:
+   case 21730:
+   case 21732:
+   case 21734:
+   case 21736:
+   case 21738:
+   case 21740:
+   case 21742:
+   case 21744:
+   case 21746:
+   case 21748:
+   case 21750:
+   case 21752:
+   case 21754:
+   case 21756:
+   case 21758:
+   case 21760:
+   case 21762:
+   case 21764:
+   case 21766:
+   case 21768:
+   case 21770:
+   case 21772:
+   case 21774:
+   case 21776:
+   case 21778:
+   case 21780:
+   case 21782:
+   case 21784:
+   case 21786:
+   case 21788:
+   case 21790:
+   case 21792:
+   case 21794:
+   case 21796:
+   case 21798:
+   case 21800:
+   case 21802:
+   case 21804:
+   case 21806:
+   case 21808:
+   case 21810:
+   case 21812:
+   case 21814:
+   case 21816:
+   case 21818:
+   case 21820:
+   case 21822:
+   case 21824:
+   case 21826:
+   case 21828:
+   case 21830:
+   case 21832:
+   case 21834:
+   case 21836:
+   case 21838:
+   case 21840:
+   case 21842:
+   case 21844:
+   case 21846:
+   case 21848:
+   case 21850:
+   case 21852:
+   case 21854:
+   case 21856:
+   case 21858:
+   case 21860:
+   case 21862:
+   case 21864:
+   case 21866:
+   case 21868:
+   case 21870:
+   case 21872:
+   case 21874:
+   case 21876:
+   case 21878:
+   case 21880:
+   case 21882:
+   case 21884:
+   case 21886:
+   case 21888:
+   case 21890:
+   case 21892:
+   case 21894:
+   case 21896:
+   case 21898:
+   case 21900:
+   case 21902:
+   case 21904:
+   case 21906:
+   case 21908:
+   case 21910:
+   case 21912:
+   case 21914:
+   case 21916:
+   case 21918:
+   case 21920:
+   case 21922:
+   case 21924:
+   case 21926:
+   case 21928:
+   case 21930:
+   case 21932:
+   case 21934:
+   case 21936:
+   case 21938:
+   case 21940:
+   case 21942:
+   case 21944:
+   case 21946:
+   case 21948:
+   case 21950:
+   case 21952:
+   case 21954:
+   case 21956:
+   case 21958:
+   case 21960:
+   case 21962:
+   case 21964:
+   case 21966:
+   case 21968:
+   case 21970:
+   case 21972:
+   case 21974:
+   case 21976:
+   case 21978:
+   case 21980:
+   case 21982:
+   case 21984:
+   case 21986:
+   case 21988:
+   case 21990:
+   case 21992:
+   case 21994:
+   case 21996:
+   case 21998:
+   case 22e3:
+   case 22002:
+   case 22004:
+   case 22006:
+   case 22008:
+   case 22010:
+   case 22012:
+   case 22014:
+   case 22016:
+   case 22018:
+   case 22020:
+   case 22022:
+   case 22024:
+   case 22026:
+   case 22028:
+   case 22030:
+   case 22032:
+   case 22034:
+   case 22036:
+   case 22038:
+   case 22040:
+   case 22042:
+   case 22044:
+   case 22046:
+   case 22048:
+   case 22050:
+   case 22052:
+   case 22054:
+   case 22056:
+   case 22058:
+   case 22060:
+   case 22062:
+   case 22064:
+   case 22066:
+   case 22068:
+   case 22070:
+   case 22072:
+   case 22074:
+   case 22076:
+   case 22078:
+   case 22080:
+   case 22082:
+   case 22084:
+   case 22086:
+   case 22088:
+   case 22090:
+   case 22092:
+   case 22094:
+   case 22096:
+   case 22098:
+   case 22100:
+   case 22102:
+   case 22104:
+   case 22106:
+   case 22108:
+   case 22110:
+   case 22112:
+   case 22114:
+   case 22116:
+   case 22118:
+   case 22120:
+   case 22122:
+   case 22124:
+   case 22126:
+   case 22128:
+   case 22130:
+   case 22132:
+   case 22134:
+   case 22136:
+   case 22138:
+   case 22140:
+   case 22142:
+   case 22144:
+   case 22146:
+   case 22148:
+   case 22150:
+   case 22152:
+   case 22154:
+   case 22156:
+   case 22158:
+   case 22160:
+   case 22162:
+   case 22164:
+   case 22166:
+   case 22168:
+   case 22170:
+   case 22172:
+   case 22174:
+   case 22176:
+   case 22178:
+   case 22180:
+   case 22182:
+   case 22184:
+   case 22186:
+   case 22188:
+   case 22190:
+   case 22192:
+   case 22194:
+   case 22196:
+   case 22198:
+   case 22200:
+   case 22202:
+   case 22204:
+   case 22206:
+   case 22208:
+   case 22210:
+   case 22212:
+   case 22214:
+   case 22216:
+   case 22218:
+   case 22220:
+   case 22222:
+   case 22224:
+   case 22226:
+   case 22228:
+   case 22230:
+   case 22232:
+   case 22234:
+   case 22236:
+   case 22238:
+   case 22240:
+   case 22242:
+   case 22244:
+   case 22246:
+   case 22248:
+   case 22250:
+   case 22252:
+   case 22254:
+   case 22256:
+   case 22258:
+   case 22260:
+   case 22262:
+   case 22264:
+   case 22266:
+   case 22268:
+   case 22270:
+   case 22272:
+   case 22274:
+   case 22276:
+   case 22278:
+   case 22280:
+   case 22282:
+   case 22284:
+   case 22286:
+   case 22288:
+   case 22290:
+   case 22292:
+   case 22294:
+   case 22296:
+   case 22298:
+   case 22300:
+   case 22302:
+   case 22304:
+   case 22306:
+   case 22308:
+   case 22310:
+   case 22312:
+   case 22314:
+   case 22316:
+   case 22318:
+   case 22320:
+   case 22322:
+   case 22324:
+   case 22326:
+   case 22328:
+   case 22330:
+   case 22332:
+   case 22334:
+   case 22336:
+   case 22338:
+   case 22340:
+   case 22342:
+   case 22344:
+   case 22346:
+   case 22348:
+   case 22350:
+   case 22352:
+   case 22354:
+   case 22356:
+   case 22358:
+   case 22360:
+   case 22362:
+   case 22364:
+   case 22366:
+   case 22368:
+   case 22370:
+   case 22372:
+   case 22374:
+   case 22376:
+   case 22378:
+   case 22380:
+   case 22382:
+   case 22384:
+   case 22386:
+   case 22388:
+   case 22390:
+   case 22392:
+   case 22394:
+   case 22396:
+   case 22398:
+   case 22400:
+   case 22402:
+   case 22404:
+   case 22406:
+   case 22408:
+   case 22410:
+   case 22412:
+   case 22414:
+   case 22416:
+   case 22418:
+   case 22420:
+   case 22422:
+   case 22424:
+   case 22426:
+   case 22428:
+   case 22430:
+   case 22432:
+   case 22434:
+   case 22436:
+   case 22438:
+   case 22440:
+   case 22442:
+   case 22444:
+   case 22446:
+   case 22448:
+   case 22450:
+   case 22452:
+   case 22454:
+   case 22456:
+   case 22458:
+   case 22460:
+   case 22462:
+   case 22464:
+   case 22466:
+   case 22468:
+   case 22470:
+   case 22472:
+   case 22474:
+   case 22476:
+   case 22478:
+   case 22480:
+   case 22482:
+   case 22484:
+   case 22486:
+   case 22488:
+   case 22490:
+   case 22492:
+   case 22494:
+   case 22496:
+   case 22498:
+   case 22500:
+   case 22502:
+   case 22504:
+   case 22506:
+   case 22508:
+   case 22510:
+   case 22512:
+   case 22514:
+   case 22516:
+   case 22518:
+   case 22520:
+   case 22522:
+   case 22524:
+   case 22526:
+   case 22528:
+   case 22530:
+   case 22532:
+   case 22534:
+   case 22536:
+   case 22538:
+   case 22540:
+   case 22542:
+   case 22544:
+   case 22546:
+   case 22548:
+   case 22550:
+   case 22552:
+   case 22554:
+   case 22556:
+   case 22558:
+   case 22560:
+   case 22562:
+   case 22564:
+   case 22566:
+   case 22568:
+   case 22570:
+   case 22572:
+   case 22574:
+   case 22576:
+   case 22578:
+   case 22580:
+   case 22582:
+   case 22584:
+   case 22586:
+   case 22588:
+   case 22590:
+   case 22592:
+   case 22594:
+   case 22596:
+   case 22598:
+   case 22600:
+   case 22602:
+   case 22604:
+   case 22606:
+   case 22608:
+   case 22610:
+   case 22612:
+   case 22614:
+   case 22616:
+   case 22618:
+   case 22620:
+   case 22622:
+   case 22624:
+   case 22626:
+   case 22628:
+   case 22630:
+   case 22632:
+   case 22634:
+   case 22636:
+   case 22638:
+   case 22640:
+   case 22642:
+   case 22644:
+   case 22646:
+   case 22648:
+   case 22650:
+   case 22652:
+   case 22654:
+   case 22656:
+   case 22658:
+   case 22660:
+   case 22662:
+   case 22664:
+   case 22666:
+   case 22668:
+   case 22670:
+   case 22672:
+   case 22674:
+   case 22676:
+   case 22678:
+   case 22680:
+   case 22682:
+   case 22684:
+   case 22686:
+   case 22688:
+   case 22690:
+   case 22692:
+   case 22694:
+   case 22696:
+   case 22698:
+   case 22700:
+   case 22702:
+   case 22704:
+   case 22706:
+   case 22708:
+   case 22710:
+   case 22712:
+   case 22714:
+   case 22716:
+   case 22718:
+   case 22720:
+   case 22722:
+   case 22724:
+   case 22726:
+   case 22728:
+   case 22730:
+   case 22732:
+   case 22734:
+   case 22736:
+   case 22738:
+   case 22740:
+   case 22742:
+   case 22744:
+   case 22746:
+   case 22748:
+   case 22750:
+   case 22752:
+   case 22754:
+   case 22756:
+   case 22758:
+   case 22760:
+   case 22762:
+   case 22764:
+   case 22766:
+   case 22768:
+   case 22770:
+   case 22772:
+   case 22774:
+   case 22776:
+   case 22778:
+   case 22780:
+   case 22782:
+   case 22784:
+   case 22786:
+   case 22788:
+   case 22790:
+   case 22792:
+   case 22794:
+   case 22796:
+   case 22798:
+   case 22800:
+   case 22802:
+   case 22804:
+   case 22806:
+   case 22808:
+   case 22810:
+   case 22812:
+   case 22814:
+   case 22816:
+   case 22818:
+   case 22820:
+   case 22822:
+   case 22824:
+   case 22826:
+   case 22828:
+   case 22830:
+   case 22832:
+   case 22834:
+   case 22836:
+   case 22838:
+   case 22840:
+   case 22842:
+   case 22844:
+   case 22846:
+   case 22848:
+   case 22850:
+   case 22852:
+   case 22854:
+   case 22856:
+   case 22858:
+   case 22860:
+   case 22862:
+   case 22864:
+   case 22866:
+   case 22868:
+   case 22870:
+   case 22872:
+   case 22874:
+   case 22876:
+   case 22878:
+   case 22880:
+   case 22882:
+   case 22884:
+   case 22886:
+   case 22888:
+   case 22890:
+   case 22892:
+   case 22894:
+   case 22896:
+   case 22898:
+   case 22900:
+   case 22902:
+   case 22904:
+   case 22906:
+   case 22908:
+   case 22910:
+   case 22912:
+   case 22914:
+   case 22916:
+   case 22918:
+   case 22920:
+   case 22922:
+   case 22924:
+   case 22926:
+   case 22928:
+   case 22930:
+   case 22932:
+   case 22934:
+   case 22936:
+   case 22938:
+   case 22940:
+   case 22942:
+   case 22944:
+   case 22946:
+   case 22948:
+   case 22950:
+   case 22952:
+   case 22954:
+   case 22956:
+   case 22958:
+   case 22960:
+   case 22962:
+   case 22964:
+   case 22966:
+   case 22968:
+   case 22970:
+   case 22972:
+   case 22974:
+   case 22976:
+   case 22978:
+   case 22980:
+   case 22982:
+   case 22984:
+   case 22986:
+   case 22988:
+   case 22990:
+   case 22992:
+   case 22994:
+   case 22996:
+   case 22998:
+   case 23e3:
+   case 23002:
+   case 23004:
+   case 23006:
+   case 23008:
+   case 23010:
+   case 23012:
+   case 23014:
+   case 23016:
+   case 23018:
+   case 23020:
+   case 23022:
+   case 23024:
+   case 23026:
+   case 23028:
+   case 23030:
+   case 23032:
+   case 23034:
+   case 23036:
+   case 23038:
+   case 23040:
+   case 23042:
+   case 23044:
+   case 23046:
+   case 23048:
+   case 23050:
+   case 23052:
+   case 23054:
+   case 23056:
+   case 23058:
+   case 23060:
+   case 23062:
+   case 23064:
+   case 23066:
+   case 23068:
+   case 23070:
+   case 23072:
+   case 23074:
+   case 23076:
+   case 23078:
+   case 23080:
+   case 23082:
+   case 23084:
+   case 23086:
+   case 23088:
+   case 23090:
+   case 23092:
+   case 23094:
+   case 23096:
+   case 23098:
+   case 23100:
+   case 23102:
+   case 23104:
+   case 23106:
+   case 23108:
+   case 23110:
+   case 23112:
+   case 23114:
+   case 23116:
+   case 23118:
+   case 23120:
+   case 23122:
+   case 23124:
+   case 23126:
+   case 23128:
+   case 23130:
+   case 23132:
+   case 23134:
+   case 23136:
+   case 23138:
+   case 23140:
+   case 23142:
+   case 23144:
+   case 23146:
+   case 23148:
+   case 23150:
+   case 23152:
+   case 23154:
+   case 23156:
+   case 23158:
+   case 23160:
+   case 23162:
+   case 23164:
+   case 23166:
+   case 23168:
+   case 23170:
+   case 23172:
+   case 23174:
+   case 23176:
+   case 23178:
+   case 23180:
+   case 23182:
+   case 23184:
+   case 23186:
+   case 23188:
+   case 23190:
+   case 23192:
+   case 23194:
+   case 23196:
+   case 23198:
+   case 23200:
+   case 23202:
+   case 23204:
+   case 23206:
+   case 23208:
+   case 23210:
+   case 23212:
+   case 23214:
+   case 23216:
+   case 23218:
+   case 23220:
+   case 23222:
+   case 23224:
+   case 23226:
+   case 23228:
+   case 23230:
+   case 23232:
+   case 23234:
+   case 23236:
+   case 23238:
+   case 23240:
+   case 23242:
+   case 23244:
+   case 23246:
+   case 23248:
+   case 23250:
+   case 23252:
+   case 23254:
+   case 23256:
+   case 23258:
+   case 23260:
+   case 23262:
+   case 23264:
+   case 23266:
+   case 23268:
+   case 23270:
+   case 23272:
+   case 23274:
+   case 23276:
+   case 23278:
+   case 23280:
+   case 23282:
+   case 23284:
+   case 23286:
+   case 23288:
+   case 23290:
+   case 23292:
+   case 23294:
+   case 23296:
+   case 23298:
+   case 23300:
+   case 23302:
+   case 23304:
+   case 23306:
+   case 23308:
+   case 23310:
+   case 23312:
+   case 23314:
+   case 23316:
+   case 23318:
+   case 23320:
+   case 23322:
+   case 23324:
+   case 23326:
+   case 23328:
+   case 23330:
+   case 23332:
+   case 23334:
+   case 23336:
+   case 23338:
+   case 23340:
+   case 23342:
+   case 23344:
+   case 23346:
+   case 23348:
+   case 23350:
+   case 23352:
+   case 23354:
+   case 23356:
+   case 23358:
+   case 23360:
+   case 23362:
+   case 23364:
+   case 23366:
+   case 23368:
+   case 23370:
+   case 23372:
+   case 23374:
+   case 23376:
+   case 23378:
+   case 23380:
+   case 23382:
+   case 23384:
+   case 23386:
+   case 23388:
+   case 23390:
+   case 23392:
+   case 23394:
+   case 23396:
+   case 23398:
+   case 23400:
+   case 23402:
+   case 23404:
+   case 23406:
+   case 23408:
+   case 23410:
+   case 23412:
+   case 23414:
+   case 23416:
+   case 23418:
+   case 23420:
+   case 23422:
+   case 23424:
+   case 23426:
+   case 23428:
+   case 23430:
+   case 23432:
+   case 23434:
+   case 23436:
+   case 23438:
+   case 23440:
+   case 23442:
+   case 23444:
+   case 23446:
+   case 23448:
+   case 23450:
+   case 23452:
+   case 23454:
+   case 23456:
+   case 23458:
+   case 23460:
+   case 23462:
+   case 23464:
+   case 23466:
+   case 23468:
+   case 23470:
+   case 23472:
+   case 23474:
+   case 23476:
+   case 23478:
+   case 23480:
+   case 23482:
+   case 23484:
+   case 23486:
+   case 23488:
+   case 23490:
+   case 23492:
+   case 23494:
+   case 23496:
+   case 23498:
+   case 23500:
+   case 23502:
+   case 23504:
+   case 23506:
+   case 23508:
+   case 23510:
+   case 23512:
+   case 23514:
+   case 23516:
+   case 23518:
+   case 23520:
+   case 23522:
+   case 23524:
+   case 23526:
+   case 23528:
+   case 23530:
+   case 23532:
+   case 23534:
+   case 23536:
+   case 23538:
+   case 23540:
+   case 23542:
+   case 23544:
+   case 23546:
+   case 23548:
+   case 23550:
+   case 23552:
+   case 23554:
+   case 23556:
+   case 23558:
+   case 23560:
+   case 23562:
+   case 23564:
+   case 23566:
+   case 23568:
+   case 23570:
+   case 23572:
+   case 23574:
+   case 23576:
+   case 23578:
+   case 23580:
+   case 23582:
+   case 23584:
+   case 23586:
+   case 23588:
+   case 23590:
+   case 23592:
+   case 23594:
+   case 23596:
+   case 23598:
+   case 23600:
+   case 23602:
+   case 23604:
+   case 23606:
+   case 23608:
+   case 23610:
+   case 23612:
+   case 23614:
+   case 23616:
+   case 23618:
+   case 23620:
+   case 23622:
+   case 23624:
+   case 23626:
+   case 23628:
+   case 23630:
+   case 23632:
+   case 23634:
+   case 23636:
+   case 23638:
+   case 23640:
+   case 23642:
+   case 23644:
+   case 23646:
+   case 23648:
+   case 23650:
+   case 23652:
+   case 23654:
+   case 23656:
+   case 23658:
+   case 23660:
+   case 23662:
+   case 23664:
+   case 23666:
+   case 23668:
+   case 23670:
+   case 23672:
+   case 23674:
+   case 23676:
+   case 23678:
+   case 23680:
+   case 23682:
+   case 23684:
+   case 23686:
+   case 23688:
+   case 23690:
+   case 23692:
+   case 23694:
+   case 23696:
+   case 23698:
+   case 23700:
+   case 23702:
+   case 23704:
+   case 23706:
+   case 23708:
+   case 23710:
+   case 23712:
+   case 23714:
+   case 23716:
+   case 23718:
+   case 23720:
+   case 23722:
+   case 23724:
+   case 23726:
+   case 23728:
+   case 23730:
+   case 23732:
+   case 23734:
+   case 23736:
+   case 23738:
+   case 23740:
+   case 23742:
+   case 23744:
+   case 23746:
+   case 23748:
+   case 23750:
+   case 23752:
+   case 23754:
+   case 23756:
+   case 23758:
+   case 23760:
+   case 23762:
+   case 23764:
+   case 23766:
+   case 23768:
+   case 23770:
+   case 23772:
+   case 23774:
+   case 23776:
+   case 23778:
+   case 23780:
+   case 23782:
+   case 23784:
+   case 23786:
+   case 23788:
+   case 23790:
+   case 23792:
+   case 23794:
+   case 23796:
+   case 23798:
+   case 23800:
+   case 23802:
+   case 23804:
+   case 23806:
+   case 23808:
+   case 23810:
+   case 23812:
+   case 23814:
+   case 23816:
+   case 23818:
+   case 23820:
+   case 23822:
+   case 23824:
+   case 23826:
+   case 23828:
+   case 23830:
+   case 23832:
+   case 23834:
+   case 23836:
+   case 23838:
+   case 23840:
+   case 23842:
+   case 23844:
+   case 23846:
+   case 23848:
+   case 23850:
+   case 23852:
+   case 23854:
+   case 23856:
+   case 23858:
+   case 23860:
+   case 23862:
+   case 23864:
+   case 23866:
+   case 23868:
+   case 23870:
+   case 23872:
+   case 23874:
+   case 23876:
+   case 23878:
+   case 23880:
+   case 23882:
+   case 23884:
+   case 23886:
+   case 23888:
+   case 23890:
+   case 23892:
+   case 23894:
+   case 23896:
+   case 23898:
+   case 23900:
+   case 23902:
+   case 23904:
+   case 23906:
+   case 23908:
+   case 23910:
+   case 23912:
+   case 23914:
+   case 23916:
+   case 23918:
+   case 23920:
+   case 23922:
+   case 23924:
+   case 23926:
+   case 23928:
+   case 23930:
+   case 23932:
+   case 23934:
+   case 23936:
+   case 23938:
+   case 23940:
+   case 23942:
+   case 23944:
+   case 23946:
+   case 23948:
+   case 23950:
+   case 23952:
+   case 23954:
+   case 23956:
+   case 23958:
+   case 23960:
+   case 23962:
+   case 23964:
+   case 23966:
+   case 23968:
+   case 23970:
+   case 23972:
+   case 23974:
+   case 23976:
+   case 23978:
+   case 23980:
+   case 23982:
+   case 23984:
+   case 23986:
+   case 23988:
+   case 23990:
+   case 23992:
+   case 23994:
+   case 23996:
+   case 23998:
+   case 24e3:
+   case 24002:
+   case 24004:
+   case 24006:
+   case 24008:
+   case 24010:
+   case 24012:
+   case 24014:
+   case 24016:
+   case 24018:
+   case 24020:
+   case 24022:
+   case 24024:
+   case 24026:
+   case 24028:
+   case 24030:
+   case 24032:
+   case 24034:
+   case 24036:
+   case 24038:
+   case 24040:
+   case 24042:
+   case 24044:
+   case 24046:
+   case 24048:
+   case 24050:
+   case 24052:
+   case 24054:
+   case 24056:
+   case 24058:
+   case 24060:
+   case 24062:
+   case 24064:
+   case 24066:
+   case 24068:
+   case 24070:
+   case 24072:
+   case 24074:
+   case 24076:
+   case 24078:
+   case 24080:
+   case 24082:
+   case 24084:
+   case 24086:
+   case 24088:
+   case 24090:
+   case 24092:
+   case 24094:
+   case 24096:
+   case 24098:
+   case 24100:
+   case 24102:
+   case 24104:
+   case 24106:
+   case 24108:
+   case 24110:
+   case 24112:
+   case 24114:
+   case 24116:
+   case 24118:
+   case 24120:
+   case 24122:
+   case 24124:
+   case 24126:
+   case 24128:
+   case 24130:
+   case 24132:
+   case 24134:
+   case 24136:
+   case 24138:
+   case 24140:
+   case 24142:
+   case 24144:
+   case 24146:
+   case 24148:
+   case 24150:
+   case 24152:
+   case 24154:
+   case 24156:
+   case 24158:
+   case 24160:
+   case 24162:
+   case 24164:
+   case 24166:
+   case 24168:
+   case 24170:
+   case 24172:
+   case 24174:
+   case 24176:
+   case 24178:
+   case 24180:
+   case 24182:
+   case 24184:
+   case 24186:
+   case 24188:
+   case 24190:
+   case 24192:
+   case 24194:
+   case 24196:
+   case 24198:
+   case 24200:
+   case 24202:
+   case 24204:
+   case 24206:
+   case 24208:
+   case 24210:
+   case 24212:
+   case 24214:
+   case 24216:
+   case 24218:
+   case 24220:
+   case 24222:
+   case 24224:
+   case 24226:
+   case 24228:
+   case 24230:
+   case 24232:
+   case 24234:
+   case 24236:
+   case 24238:
+   case 24240:
+   case 24242:
+   case 24244:
+   case 24246:
+   case 24248:
+   case 24250:
+   case 24252:
+   case 24254:
+   case 24256:
+   case 24258:
+   case 24260:
+   case 24262:
+   case 24264:
+   case 24266:
+   case 24268:
+   case 24270:
+   case 24272:
+   case 24274:
+   case 24276:
+   case 24278:
+   case 24280:
+   case 24282:
+   case 24284:
+   case 24286:
+   case 24288:
+   case 24290:
+   case 24292:
+   case 24294:
+   case 24296:
+   case 24298:
+   case 24300:
+   case 24302:
+   case 24304:
+   case 24306:
+   case 24308:
+   case 24310:
+   case 24312:
+   case 24314:
+   case 24316:
+   case 24318:
+   case 24320:
+   case 24322:
+   case 24324:
+   case 24326:
+   case 24328:
+   case 24330:
+   case 24332:
+   case 24334:
+   case 24336:
+   case 24338:
+   case 24340:
+   case 24342:
+   case 24344:
+   case 24346:
+   case 24348:
+   case 24350:
+   case 24352:
+   case 24354:
+   case 24356:
+   case 24358:
+   case 24360:
+   case 24362:
+   case 24364:
+   case 24366:
+   case 24368:
+   case 24370:
+   case 24372:
+   case 24374:
+   case 24376:
+   case 24378:
+   case 24380:
+   case 24382:
+   case 24384:
+   case 24386:
+   case 24388:
+   case 24390:
+   case 24392:
+   case 24394:
+   case 24396:
+   case 24398:
+   case 24400:
+   case 24402:
+   case 24404:
+   case 24406:
+   case 24408:
+   case 24410:
+   case 24412:
+   case 24414:
+   case 24416:
+   case 24418:
+   case 24420:
+   case 24422:
+   case 24424:
+   case 24426:
+   case 24428:
+   case 24430:
+   case 24432:
+   case 24434:
+   case 24436:
+   case 24438:
+   case 24440:
+   case 24442:
+   case 24444:
+   case 24446:
+   case 24448:
+   case 24450:
+   case 24452:
+   case 24454:
+   case 24456:
+   case 24458:
+   case 24460:
+   case 24462:
+   case 24464:
+   case 24466:
+   case 24468:
+   case 24470:
+   case 24472:
+   case 24474:
+   case 24476:
+   case 24478:
+   case 24480:
+   case 24482:
+   case 24484:
+   case 24486:
+   case 24488:
+   case 24490:
+   case 24492:
+   case 24494:
+   case 24496:
+   case 24498:
+   case 24500:
+   case 24502:
+   case 24504:
+   case 24506:
+   case 24508:
+   case 24510:
+   case 24512:
+   case 24514:
+   case 24516:
+   case 24518:
+   case 24520:
+   case 24522:
+   case 24524:
+   case 24526:
+   case 24528:
+   case 24530:
+   case 24532:
+   case 24534:
+   case 24536:
+   case 24538:
+   case 24540:
+   case 24542:
+   case 24544:
+   case 24546:
+   case 24548:
+   case 24550:
+   case 24552:
+   case 24554:
+   case 24556:
+   case 24558:
+   case 24560:
+   case 24562:
+   case 24564:
+   case 24566:
+   case 24568:
+   case 24570:
+   case 24572:
+   case 24574:
+   case 24576:
+   case 24578:
+   case 24580:
+   case 24582:
+   case 24584:
+   case 24586:
+   case 24588:
+   case 24590:
+   case 24592:
+   case 24594:
+   case 24596:
+   case 24598:
+   case 24600:
+   case 24602:
+   case 24604:
+   case 24606:
+   case 24608:
+   case 24610:
+   case 24612:
+   case 24614:
+    return 0;
+   default:
+    break block;
+   };
+  }
+  return 1;
+ }
+ 
+ function $20() {
+  return 3;
+ }
+ 
+ function $21() {
+  return 4;
+ }
+ 
+ function $22() {
+  return 5;
+ }
+ 
+ function $23() {
+  return 9;
+ }
+ 
+ function $25() {
+  return 8;
+ }
+ 
+ function $28() {
+  return 10;
+ }
+ 
+ function $29() {
+  return 11;
+ }
+ 
+ function $30() {
+  return 7;
+ }
+ 
+ function $32($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  if ($0) {
+   $1 = 3
+  }
+  return $1 | 0;
+ }
+ 
+ function $33($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  if (!$0) {
+   $1 = 4
+  }
+  return $1 | 0;
+ }
+ 
+ function $34($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  return 5;
+ }
+ 
+ function $35($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  return 6;
+ }
+ 
+ function $38() {
+  return 12;
+ }
+ 
+ function $39() {
+  return 13;
+ }
+ 
+ function $40() {
+  return 14;
+ }
+ 
+ function $41() {
+  return 20;
+ }
+ 
+ function $42() {
+  return 21;
+ }
+ 
+ function $43() {
+  return 22;
+ }
+ 
+ function $44() {
+  return 23;
+ }
+ 
+ function $45() {
+  return 17;
+ }
+ 
+ function $47() {
+  return 30;
+ }
+ 
+ function $49() {
+  return 31;
+ }
+ 
+ function $50() {
+  return 32;
+ }
+ 
+ function $51() {
+  return 33;
+ }
+ 
+ function $54() {
+  return 45;
+ }
+ 
+ function $55() {
+  return 44;
+ }
+ 
+ function $56() {
+  return 43;
+ }
+ 
+ function $57() {
+  return 42;
+ }
+ 
+ function $58() {
+  return 41;
+ }
+ 
+ function $59() {
+  return 40;
+ }
+ 
+ function $60($0) {
+  $0 = $0 | 0;
+  var $1 = 0, $2 = 0;
+  $1 = 16;
+  $2 = 16;
+  block : {
+   switch ($0 | 0) {
+   case 0:
+    $2 = 18;
+   case 1:
+    $1 = $2 + 1 | 0;
+    break;
+   default:
+    break block;
+   };
+  }
+  return $1 | 0;
+ }
+ 
+ function $61($0) {
+  $0 = $0 | 0;
+  var $1 = 0, $2 = 0;
+  $1 = 8;
+  $2 = 8;
+  block : {
+   switch ($0 | 0) {
+   default:
+    $2 = 16;
+   case 1:
+    $1 = $2 + 1 | 0;
+    break;
+   case 0:
+    break block;
+   };
+  }
+  return $1 | 0;
+ }
+ 
+ function $62($0) {
+  $0 = $0 | 0;
+  var $1 = 0, $2 = 0;
+  $1 = 8;
+  $2 = 8;
+  block : {
+   switch ($0 | 0) {
+   case 0:
+    $2 = 16;
+   case 1:
+    $1 = $2 + 1 | 0;
+    break;
+   default:
+    break block;
+   };
+  }
+  return $1 | 0;
+ }
+ 
+ function $63($0) {
+  $0 = $0 | 0;
+  if ($0 - 1 | 0) {
+   $0 = 9
+  } else {
+   $0 = 8
+  }
+  return $0 | 0;
+ }
+ 
+ return {
+  "type_i32": dummy, 
+  "type_i64": dummy, 
+  "type_f32": dummy, 
+  "type_f64": dummy, 
+  "type_i32_value": $5, 
+  "type_i64_value": $6, 
+  "type_f32_value": $7, 
+  "type_f64_value": $8, 
+  "empty": $9, 
+  "empty_value": $10, 
+  "singleton": $11, 
+  "singleton_value": $12, 
+  "multiple": $13, 
+  "multiple_value": $14, 
+  "large": $15, 
+  "as_block_first": dummy, 
+  "as_block_mid": dummy, 
+  "as_block_last": dummy, 
+  "as_block_value": $6, 
+  "as_loop_first": $20, 
+  "as_loop_mid": $21, 
+  "as_loop_last": $22, 
+  "as_br_value": $23, 
+  "as_br_if_cond": dummy, 
+  "as_br_if_value": $25, 
+  "as_br_if_value_cond": $23, 
+  "as_br_table_index": dummy, 
+  "as_br_table_value": $28, 
+  "as_br_table_value_index": $29, 
+  "as_return_value": $30, 
+  "as_if_cond": $6, 
+  "as_if_then": $32, 
+  "as_if_else": $33, 
+  "as_select_first": $34, 
+  "as_select_second": $35, 
+  "as_select_cond": $30, 
+  "as_call_first": $38, 
+  "as_call_mid": $39, 
+  "as_call_last": $40, 
+  "as_call_indirect_first": $41, 
+  "as_call_indirect_mid": $42, 
+  "as_call_indirect_last": $43, 
+  "as_call_indirect_func": $44, 
+  "as_local_set_value": $45, 
+  "as_load_address": $6, 
+  "as_loadN_address": $47, 
+  "as_store_address": $47, 
+  "as_store_value": $49, 
+  "as_storeN_address": $50, 
+  "as_storeN_value": $51, 
+  "as_unary_operand": $20, 
+  "as_binary_left": $20, 
+  "as_binary_right": $54, 
+  "as_test_operand": $55, 
+  "as_compare_left": $56, 
+  "as_compare_right": $57, 
+  "as_convert_operand": $58, 
+  "as_memory_grow_size": $59, 
+  "nested_block_value": $60, 
+  "nested_br_value": $61, 
+  "nested_br_if_value": $62, 
+  "nested_br_if_value_cond": $63, 
+  "nested_br_table_value": $62, 
+  "nested_br_table_value_index": $63
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var type_i32 = retasmFunc.type_i32;
+export var type_i64 = retasmFunc.type_i64;
+export var type_f32 = retasmFunc.type_f32;
+export var type_f64 = retasmFunc.type_f64;
+export var type_i32_value = retasmFunc.type_i32_value;
+export var type_i64_value = retasmFunc.type_i64_value;
+export var type_f32_value = retasmFunc.type_f32_value;
+export var type_f64_value = retasmFunc.type_f64_value;
+export var empty = retasmFunc.empty;
+export var empty_value = retasmFunc.empty_value;
+export var singleton = retasmFunc.singleton;
+export var singleton_value = retasmFunc.singleton_value;
+export var multiple = retasmFunc.multiple;
+export var multiple_value = retasmFunc.multiple_value;
+export var large = retasmFunc.large;
+export var as_block_first = retasmFunc.as_block_first;
+export var as_block_mid = retasmFunc.as_block_mid;
+export var as_block_last = retasmFunc.as_block_last;
+export var as_block_value = retasmFunc.as_block_value;
+export var as_loop_first = retasmFunc.as_loop_first;
+export var as_loop_mid = retasmFunc.as_loop_mid;
+export var as_loop_last = retasmFunc.as_loop_last;
+export var as_br_value = retasmFunc.as_br_value;
+export var as_br_if_cond = retasmFunc.as_br_if_cond;
+export var as_br_if_value = retasmFunc.as_br_if_value;
+export var as_br_if_value_cond = retasmFunc.as_br_if_value_cond;
+export var as_br_table_index = retasmFunc.as_br_table_index;
+export var as_br_table_value = retasmFunc.as_br_table_value;
+export var as_br_table_value_index = retasmFunc.as_br_table_value_index;
+export var as_return_value = retasmFunc.as_return_value;
+export var as_if_cond = retasmFunc.as_if_cond;
+export var as_if_then = retasmFunc.as_if_then;
+export var as_if_else = retasmFunc.as_if_else;
+export var as_select_first = retasmFunc.as_select_first;
+export var as_select_second = retasmFunc.as_select_second;
+export var as_select_cond = retasmFunc.as_select_cond;
+export var as_call_first = retasmFunc.as_call_first;
+export var as_call_mid = retasmFunc.as_call_mid;
+export var as_call_last = retasmFunc.as_call_last;
+export var as_call_indirect_first = retasmFunc.as_call_indirect_first;
+export var as_call_indirect_mid = retasmFunc.as_call_indirect_mid;
+export var as_call_indirect_last = retasmFunc.as_call_indirect_last;
+export var as_call_indirect_func = retasmFunc.as_call_indirect_func;
+export var as_local_set_value = retasmFunc.as_local_set_value;
+export var as_load_address = retasmFunc.as_load_address;
+export var as_loadN_address = retasmFunc.as_loadN_address;
+export var as_store_address = retasmFunc.as_store_address;
+export var as_store_value = retasmFunc.as_store_value;
+export var as_storeN_address = retasmFunc.as_storeN_address;
+export var as_storeN_value = retasmFunc.as_storeN_value;
+export var as_unary_operand = retasmFunc.as_unary_operand;
+export var as_binary_left = retasmFunc.as_binary_left;
+export var as_binary_right = retasmFunc.as_binary_right;
+export var as_test_operand = retasmFunc.as_test_operand;
+export var as_compare_left = retasmFunc.as_compare_left;
+export var as_compare_right = retasmFunc.as_compare_right;
+export var as_convert_operand = retasmFunc.as_convert_operand;
+export var as_memory_grow_size = retasmFunc.as_memory_grow_size;
+export var nested_block_value = retasmFunc.nested_block_value;
+export var nested_br_value = retasmFunc.nested_br_value;
+export var nested_br_if_value = retasmFunc.nested_br_if_value;
+export var nested_br_if_value_cond = retasmFunc.nested_br_if_value_cond;
+export var nested_br_table_value = retasmFunc.nested_br_table_value;
+export var nested_br_table_value_index = retasmFunc.nested_br_table_value_index;
diff --git a/binaryen/test/wasm2js/br_table_temp.wast b/binaryen/test/wasm2js/br_table_temp.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/br_table_temp.wast
@@ -0,0 +1,1468 @@
+;; Test `br_table` operator TODO: implement more ops and replace with spec/br_table.wast
+
+(module
+  ;; Auxiliary definition
+  (func $dummy)
+
+  (func (export "type-i32")
+    (block (drop (i32.ctz (br_table 0 0 (i32.const 0)))))
+  )
+  (func (export "type-i64")
+    (block (drop (i64.ctz (br_table 0 0 (i32.const 0)))))
+  )
+  (func (export "type-f32")
+    (block (drop (f32.neg (br_table 0 0 (i32.const 0)))))
+  )
+  (func (export "type-f64")
+    (block (drop (f64.neg (br_table 0 0 (i32.const 0)))))
+  )
+
+  (func (export "type-i32-value") (result i32)
+    (block i32 (i32.ctz (br_table 0 0 (i32.const 1) (i32.const 0))))
+  )
+  (func (export "type-i64-value") (result i32)
+    (i32.wrap_i64 (block i64 (i64.ctz (br_table 0 0 (i64.const 2) (i32.const 0)))))
+  )
+  (func (export "type-f32-value") (result f32)
+    (block f32 (f32.neg (br_table 0 0 (f32.const 3) (i32.const 0))))
+  )
+  (func (export "type-f64-value") (result f64)
+    (block f64 (f64.neg (br_table 0 0 (f64.const 4) (i32.const 0))))
+  )
+
+  (func (export "empty") (param i32) (result i32)
+    (block (br_table 0 (local.get 0)) (return (i32.const 21)))
+    (i32.const 22)
+  )
+  (func (export "empty-value") (param i32) (result i32)
+    (block i32 (br_table 0 (i32.const 33) (local.get 0)) (i32.const 31))
+  )
+
+  (func (export "singleton") (param i32) (result i32)
+    (block
+      (block
+        (br_table 1 0 (local.get 0))
+        (return (i32.const 21))
+      )
+      (return (i32.const 20))
+    )
+    (i32.const 22)
+  )
+
+  (func (export "singleton-value") (param i32) (result i32)
+    (block i32
+      (drop
+        (block i32
+          (br_table 0 1 (i32.const 33) (local.get 0))
+          (return (i32.const 31))
+        )
+      )
+      (i32.const 32)
+    )
+  )
+
+  (func (export "multiple") (param i32) (result i32)
+    (block
+      (block
+        (block
+          (block
+            (block
+              (br_table 3 2 1 0 4 (local.get 0))
+              (return (i32.const 99))
+            )
+            (return (i32.const 100))
+          )
+          (return (i32.const 101))
+        )
+        (return (i32.const 102))
+      )
+      (return (i32.const 103))
+    )
+    (i32.const 104)
+  )
+
+  (func (export "multiple-value") (param i32) (result i32)
+    (local i32)
+    (local.set 1 (block i32
+      (local.set 1 (block i32
+        (local.set 1 (block i32
+          (local.set 1 (block i32
+            (local.set 1 (block i32
+              (br_table 3 2 1 0 4 (i32.const 200) (local.get 0))
+              (return (i32.add (local.get 1) (i32.const 99)))
+            ))
+            (return (i32.add (local.get 1) (i32.const 10)))
+          ))
+          (return (i32.add (local.get 1) (i32.const 11)))
+        ))
+        (return (i32.add (local.get 1) (i32.const 12)))
+      ))
+      (return (i32.add (local.get 1) (i32.const 13)))
+    ))
+    (i32.add (local.get 1) (i32.const 14))
+  )
+
+  (func (export "large") (param i32) (result i32)
+    (block
+      (block
+        (br_table
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+          (local.get 0)
+        )
+        (return (i32.const -1))
+      )
+      (return (i32.const 0))
+    )
+    (return (i32.const 1))
+  )
+
+  (func (export "as-block-first")
+    (block (br_table 0 0 0 (i32.const 0)) (call $dummy))
+  )
+  (func (export "as-block-mid")
+    (block (call $dummy) (br_table 0 0 0 (i32.const 0)) (call $dummy))
+  )
+  (func (export "as-block-last")
+    (block (nop) (call $dummy) (br_table 0 0 0 (i32.const 0)))
+  )
+  (func (export "as-block-value") (result i32)
+    (block i32 (nop) (call $dummy) (br_table 0 0 0 (i32.const 2) (i32.const 0)))
+  )
+
+  (func (export "as-loop-first") (result i32)
+    (loop i32 (br_table 1 1 (i32.const 3) (i32.const 0)) (i32.const 1))
+  )
+  (func (export "as-loop-mid") (result i32)
+    (loop i32
+      (call $dummy)
+      (br_table 1 1 1 (i32.const 4) (i32.const -1))
+      (i32.const 2)
+    )
+  )
+  (func (export "as-loop-last") (result i32)
+    (loop i32 (nop) (call $dummy) (br_table 1 1 1 (i32.const 5) (i32.const 1)))
+  )
+
+  (func (export "as-br-value") (result i32)
+    (block i32 (br 0 (br 0 (i32.const 9))))
+  )
+
+  (func (export "as-br_if-cond")
+    (block (br_if 0 (br_table 0 0 0 (i32.const 1))))
+  )
+  (func (export "as-br_if-value") (result i32)
+    (block i32
+      (br_if 0 (br_table 0 (i32.const 8) (i32.const 0)) (i32.const 1))
+      (i32.const 7)
+    )
+  )
+  (func (export "as-br_if-value-cond") (result i32)
+    (block i32
+      (drop (br_if 0 (i32.const 6) (br_table 0 0 (i32.const 9) (i32.const 0))))
+      (i32.const 7)
+    )
+  )
+
+  (func (export "as-br_table-index")
+    (block (br_table 0 0 0 (br_table 0 (i32.const 1))))
+  )
+  (func (export "as-br_table-value") (result i32)
+    (block i32
+      (br_table 0 0 0 (br_table 0 (i32.const 10) (i32.const 0)) (i32.const 1))
+      (i32.const 7)
+    )
+  )
+  (func (export "as-br_table-value-index") (result i32)
+    (block i32
+      (br_table 0 0 (i32.const 6) (br_table 0 (i32.const 11) (i32.const 1)))
+      (i32.const 7)
+    )
+  )
+
+  (func (export "as-return-value") (result i32)
+    (i32.wrap_i64 (block i64 (return (br_table 0 (i64.const 7) (i32.const 0)))))
+  )
+
+  (func (export "as-if-cond") (result i32)
+    (block i32
+      (if i32
+        (br_table 0 (i32.const 2) (i32.const 0))
+        (i32.const 0)
+        (i32.const 1)
+      )
+    )
+  )
+  (func (export "as-if-then") (param i32 i32) (result i32)
+    (block i32
+      (if i32
+        (local.get 0)
+        (br_table 1 (i32.const 3) (i32.const 0))
+        (local.get 1)
+      )
+    )
+  )
+  (func (export "as-if-else") (param i32 i32) (result i32)
+    (block i32
+      (if i32
+        (local.get 0)
+        (local.get 1)
+        (br_table 1 0 (i32.const 4) (i32.const 0))
+      )
+    )
+  )
+
+  (func (export "as-select-first") (param i32 i32) (result i32)
+    (block i32
+      (select
+        (br_table 0 (i32.const 5) (i32.const 0)) (local.get 0) (local.get 1)
+      )
+    )
+  )
+  (func (export "as-select-second") (param i32 i32) (result i32)
+    (block i32
+      (select
+        (local.get 0) (br_table 0 (i32.const 6) (i32.const 1)) (local.get 1)
+      )
+    )
+  )
+  (func (export "as-select-cond") (result i32)
+    (block i32
+      (select
+        (i32.const 0) (i32.const 1) (br_table 0 (i32.const 7) (i32.const 1))
+      )
+    )
+  )
+
+  (func $f (param i32 i32 i32) (result i32) (i32.const -1))
+  (func (export "as-call-first") (result i32)
+    (block i32
+      (call $f
+        (br_table 0 (i32.const 12) (i32.const 1)) (i32.const 2) (i32.const 3)
+      )
+    )
+  )
+  (func (export "as-call-mid") (result i32)
+    (block i32
+      (call $f
+        (i32.const 1) (br_table 0 (i32.const 13) (i32.const 1)) (i32.const 3)
+      )
+    )
+  )
+  (func (export "as-call-last") (result i32)
+    (block i32
+      (call $f
+        (i32.const 1) (i32.const 2) (br_table 0 (i32.const 14) (i32.const 1))
+      )
+    )
+  )
+
+  (type $sig (func (param i32 i32 i32) (result i32)))
+  (table funcref (elem $f))
+  (func (export "as-call_indirect-first") (result i32)
+    (block i32
+      (call_indirect (type $sig)
+        (br_table 0 (i32.const 20) (i32.const 1)) (i32.const 1) (i32.const 2)
+        (i32.const 3)
+      )
+    )
+  )
+  (func (export "as-call_indirect-mid") (result i32)
+    (block i32
+      (call_indirect (type $sig)
+        (i32.const 0) (br_table 0 (i32.const 21) (i32.const 1)) (i32.const 2)
+        (i32.const 3)
+      )
+    )
+  )
+  (func (export "as-call_indirect-last") (result i32)
+    (block i32
+      (call_indirect (type $sig)
+        (i32.const 0) (i32.const 1) (br_table 0 (i32.const 22) (i32.const 1))
+        (i32.const 3)
+      )
+    )
+  )
+  (func (export "as-call_indirect-func") (result i32)
+    (block i32
+      (call_indirect (type $sig)
+        (i32.const 0) (i32.const 1) (i32.const 2)
+        (br_table 0 (i32.const 23) (i32.const 1))
+      )
+    )
+  )
+
+  (func (export "as-local.set-value") (result i32)
+    (local f32)
+    (block i32
+      (local.set 0 (br_table 0 (i32.const 17) (i32.const 1)))
+      (i32.const -1)
+    )
+  )
+
+  (memory 1)
+  (func (export "as-load-address") (result i32)
+    (block i32 (i32.load (br_table 0 (i32.const 2) (i32.const 1))))
+  )
+  (func (export "as-loadN-address") (result i32)
+    (i32.wrap_i64 (block i64 (i64.load8_s (br_table 0 (i64.const 30) (i32.const 1)))))
+  )
+
+  (func (export "as-store-address") (result i32)
+    (block i32
+      (f64.store (br_table 0 (i32.const 30) (i32.const 1)) (f64.const 7))
+      (i32.const -1)
+    )
+  )
+  (func (export "as-store-value") (result i32)
+    (block i32
+      (i64.store (i32.const 2) (br_table 0 (i32.const 31) (i32.const 1)))
+      (i32.const -1)
+     )
+  )
+
+  (func (export "as-storeN-address") (result i32)
+    (block i32
+      (i32.store8 (br_table 0 (i32.const 32) (i32.const 0)) (i32.const 7))
+      (i32.const -1)
+    )
+  )
+  (func (export "as-storeN-value") (result i32)
+    (block i32
+      (i64.store16 (i32.const 2) (br_table 0 (i32.const 33) (i32.const 0)))
+      (i32.const -1)
+    )
+  )
+
+  (func (export "as-unary-operand") (result i32)
+    (block i32 (i32.ctz (br_table 0 (i32.const 3) (i32.const 0))))
+  )
+
+  (func (export "as-binary-left") (result i32)
+    (block i32
+      (i32.add (br_table 0 0 (i32.const 3) (i32.const 0)) (i32.const 10))
+    )
+  )
+  (func (export "as-binary-right") (result i32)
+    (i32.wrap_i64 (block i64
+      (i64.add (i64.const 10) (br_table 0 (i64.const 45) (i32.const 0))))
+    )
+  )
+
+  (func (export "as-test-operand") (result i32)
+    (block i32 (i32.eqz (br_table 0 (i32.const 44) (i32.const 0))))
+  )
+
+  (func (export "as-compare-left") (result i32)
+    (block i32
+      (f64.le (br_table 0 0 (i32.const 43) (i32.const 0)) (f64.const 10))
+    )
+  )
+  (func (export "as-compare-right") (result i32)
+    (block i32
+      (f32.ne (f32.const 10) (br_table 0 (i32.const 42) (i32.const 0)))
+    )
+  )
+
+  (func (export "as-convert-operand") (result i32)
+    (block i32 (i32.wrap_i64 (br_table 0 (i32.const 41) (i32.const 0))))
+  )
+
+  (func (export "as-memory.grow-size") (result i32)
+    (block i32 (memory.grow (br_table 0 (i32.const 40) (i32.const 0))))
+  )
+
+  (func (export "nested-block-value") (param i32) (result i32)
+    (block i32
+      (drop (i32.const -1))
+      (i32.add
+        (i32.const 1)
+        (block i32
+          (i32.add
+            (i32.const 2)
+            (block i32
+              (drop (i32.const 4))
+              (i32.add
+                (i32.const 8)
+                (br_table 0 1 2 (i32.const 16) (local.get 0))
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+
+  (func (export "nested-br-value") (param i32) (result i32)
+    (block i32
+      (i32.add
+        (i32.const 1)
+        (block i32
+          (drop (i32.const 2))
+          (drop
+            (block i32
+              (drop (i32.const 4))
+              (br 0 (br_table 2 1 0 (i32.const 8) (local.get 0)))
+            )
+          )
+          (i32.const 16)
+        )
+      )
+    )
+  )
+
+  (func (export "nested-br_if-value") (param i32) (result i32)
+    (block i32
+      (i32.add
+        (i32.const 1)
+        (block i32
+          (drop (i32.const 2))
+          (drop
+            (block i32
+              (drop (i32.const 4))
+              (br_if 0 (br_table 0 1 2 (i32.const 8) (local.get 0)) (i32.const 1))
+              (i32.const 32)
+            )
+          )
+          (i32.const 16)
+        )
+      )
+    )
+  )
+
+  (func (export "nested-br_if-value-cond") (param i32) (result i32)
+    (block i32
+      (i32.add
+        (i32.const 1)
+        (block i32
+          (drop (i32.const 2))
+          (drop (br_if 0 (i32.const 4) (br_table 0 1 0 (i32.const 8) (local.get 0))))
+          (i32.const 16)
+        )
+      )
+    )
+  )
+
+  (func (export "nested-br_table-value") (param i32) (result i32)
+    (block i32
+      (i32.add
+        (i32.const 1)
+        (block i32
+          (drop (i32.const 2))
+          (drop
+            (block i32
+              (drop (i32.const 4))
+              (br_table 0 (br_table 0 1 2 (i32.const 8) (local.get 0)) (i32.const 1))
+              (i32.const 32)
+            )
+          )
+          (i32.const 16)
+        )
+      )
+    )
+  )
+
+  (func (export "nested-br_table-value-index") (param i32) (result i32)
+    (block i32
+      (i32.add
+        (i32.const 1)
+        (block i32
+          (drop (i32.const 2))
+          (br_table 0 (i32.const 4) (br_table 0 1 0 (i32.const 8) (local.get 0)))
+          (i32.const 16)
+        )
+      )
+    )
+  )
+)
+
+(assert_return (invoke "type-i32"))
+(assert_return (invoke "type-i64"))
+(assert_return (invoke "type-f32"))
+(assert_return (invoke "type-f64"))
+
+(assert_return (invoke "type-i32-value") (i32.const 1))
+(assert_return (invoke "type-i64-value") (i32.const 2))
+;; (assert_return (invoke "type-f32-value") (f32.const 3))
+;; (assert_return (invoke "type-f64-value") (f64.const 4))
+
+(assert_return (invoke "empty" (i32.const 0)) (i32.const 22))
+(assert_return (invoke "empty" (i32.const 1)) (i32.const 22))
+(assert_return (invoke "empty" (i32.const 11)) (i32.const 22))
+(assert_return (invoke "empty" (i32.const -1)) (i32.const 22))
+(assert_return (invoke "empty" (i32.const -100)) (i32.const 22))
+(assert_return (invoke "empty" (i32.const 0xffffffff)) (i32.const 22))
+
+(assert_return (invoke "empty-value" (i32.const 0)) (i32.const 33))
+(assert_return (invoke "empty-value" (i32.const 1)) (i32.const 33))
+(assert_return (invoke "empty-value" (i32.const 11)) (i32.const 33))
+(assert_return (invoke "empty-value" (i32.const -1)) (i32.const 33))
+(assert_return (invoke "empty-value" (i32.const -100)) (i32.const 33))
+(assert_return (invoke "empty-value" (i32.const 0xffffffff)) (i32.const 33))
+
+(assert_return (invoke "singleton" (i32.const 0)) (i32.const 22))
+(assert_return (invoke "singleton" (i32.const 1)) (i32.const 20))
+(assert_return (invoke "singleton" (i32.const 11)) (i32.const 20))
+(assert_return (invoke "singleton" (i32.const -1)) (i32.const 20))
+(assert_return (invoke "singleton" (i32.const -100)) (i32.const 20))
+(assert_return (invoke "singleton" (i32.const 0xffffffff)) (i32.const 20))
+
+(assert_return (invoke "singleton-value" (i32.const 0)) (i32.const 32))
+(assert_return (invoke "singleton-value" (i32.const 1)) (i32.const 33))
+(assert_return (invoke "singleton-value" (i32.const 11)) (i32.const 33))
+(assert_return (invoke "singleton-value" (i32.const -1)) (i32.const 33))
+(assert_return (invoke "singleton-value" (i32.const -100)) (i32.const 33))
+(assert_return (invoke "singleton-value" (i32.const 0xffffffff)) (i32.const 33))
+
+(assert_return (invoke "multiple" (i32.const 0)) (i32.const 103))
+(assert_return (invoke "multiple" (i32.const 1)) (i32.const 102))
+(assert_return (invoke "multiple" (i32.const 2)) (i32.const 101))
+(assert_return (invoke "multiple" (i32.const 3)) (i32.const 100))
+(assert_return (invoke "multiple" (i32.const 4)) (i32.const 104))
+(assert_return (invoke "multiple" (i32.const 5)) (i32.const 104))
+(assert_return (invoke "multiple" (i32.const 6)) (i32.const 104))
+(assert_return (invoke "multiple" (i32.const 10)) (i32.const 104))
+(assert_return (invoke "multiple" (i32.const -1)) (i32.const 104))
+(assert_return (invoke "multiple" (i32.const 0xffffffff)) (i32.const 104))
+
+(assert_return (invoke "multiple-value" (i32.const 0)) (i32.const 213))
+(assert_return (invoke "multiple-value" (i32.const 1)) (i32.const 212))
+(assert_return (invoke "multiple-value" (i32.const 2)) (i32.const 211))
+(assert_return (invoke "multiple-value" (i32.const 3)) (i32.const 210))
+(assert_return (invoke "multiple-value" (i32.const 4)) (i32.const 214))
+(assert_return (invoke "multiple-value" (i32.const 5)) (i32.const 214))
+(assert_return (invoke "multiple-value" (i32.const 6)) (i32.const 214))
+(assert_return (invoke "multiple-value" (i32.const 10)) (i32.const 214))
+(assert_return (invoke "multiple-value" (i32.const -1)) (i32.const 214))
+(assert_return (invoke "multiple-value" (i32.const 0xffffffff)) (i32.const 214))
+
+(assert_return (invoke "large" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "large" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "large" (i32.const 100)) (i32.const 0))
+(assert_return (invoke "large" (i32.const 101)) (i32.const 1))
+(assert_return (invoke "large" (i32.const 10000)) (i32.const 0))
+(assert_return (invoke "large" (i32.const 10001)) (i32.const 1))
+(assert_return (invoke "large" (i32.const 1000000)) (i32.const 1))
+(assert_return (invoke "large" (i32.const 1000001)) (i32.const 1))
+
+(assert_return (invoke "as-block-first"))
+(assert_return (invoke "as-block-mid"))
+(assert_return (invoke "as-block-last"))
+(assert_return (invoke "as-block-value") (i32.const 2))
+
+(assert_return (invoke "as-loop-first") (i32.const 3))
+(assert_return (invoke "as-loop-mid") (i32.const 4))
+(assert_return (invoke "as-loop-last") (i32.const 5))
+
+(assert_return (invoke "as-br-value") (i32.const 9))
+
+(assert_return (invoke "as-br_if-cond"))
+(assert_return (invoke "as-br_if-value") (i32.const 8))
+(assert_return (invoke "as-br_if-value-cond") (i32.const 9))
+
+(assert_return (invoke "as-br_table-index"))
+(assert_return (invoke "as-br_table-value") (i32.const 10))
+(assert_return (invoke "as-br_table-value-index") (i32.const 11))
+
+(assert_return (invoke "as-return-value") (i32.const 7))
+
+(assert_return (invoke "as-if-cond") (i32.const 2))
+(assert_return (invoke "as-if-then" (i32.const 1) (i32.const 6)) (i32.const 3))
+(assert_return (invoke "as-if-then" (i32.const 0) (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-if-else" (i32.const 0) (i32.const 6)) (i32.const 4))
+(assert_return (invoke "as-if-else" (i32.const 1) (i32.const 6)) (i32.const 6))
+
+(assert_return (invoke "as-select-first" (i32.const 0) (i32.const 6)) (i32.const 5))
+(assert_return (invoke "as-select-first" (i32.const 1) (i32.const 6)) (i32.const 5))
+(assert_return (invoke "as-select-second" (i32.const 0) (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-select-second" (i32.const 1) (i32.const 6)) (i32.const 6))
+(assert_return (invoke "as-select-cond") (i32.const 7))
+
+(assert_return (invoke "as-call-first") (i32.const 12))
+(assert_return (invoke "as-call-mid") (i32.const 13))
+(assert_return (invoke "as-call-last") (i32.const 14))
+
+(assert_return (invoke "as-call_indirect-first") (i32.const 20))
+(assert_return (invoke "as-call_indirect-mid") (i32.const 21))
+(assert_return (invoke "as-call_indirect-last") (i32.const 22))
+(assert_return (invoke "as-call_indirect-func") (i32.const 23))
+
+(assert_return (invoke "as-local.set-value") (i32.const 17))
+
+(assert_return (invoke "as-load-address") (i32.const 2))
+(assert_return (invoke "as-loadN-address") (i32.const 30))
+
+(assert_return (invoke "as-store-address") (i32.const 30))
+(assert_return (invoke "as-store-value") (i32.const 31))
+(assert_return (invoke "as-storeN-address") (i32.const 32))
+(assert_return (invoke "as-storeN-value") (i32.const 33))
+
+(assert_return (invoke "as-unary-operand") (i32.const 3))
+
+(assert_return (invoke "as-binary-left") (i32.const 3))
+(assert_return (invoke "as-binary-right") (i32.const 45))
+
+(assert_return (invoke "as-test-operand") (i32.const 44))
+
+(assert_return (invoke "as-compare-left") (i32.const 43))
+(assert_return (invoke "as-compare-right") (i32.const 42))
+
+(assert_return (invoke "as-convert-operand") (i32.const 41))
+
+(assert_return (invoke "as-memory.grow-size") (i32.const 40))
+
+(assert_return (invoke "nested-block-value" (i32.const 0)) (i32.const 19))
+(assert_return (invoke "nested-block-value" (i32.const 1)) (i32.const 17))
+(assert_return (invoke "nested-block-value" (i32.const 2)) (i32.const 16))
+(assert_return (invoke "nested-block-value" (i32.const 10)) (i32.const 16))
+(assert_return (invoke "nested-block-value" (i32.const -1)) (i32.const 16))
+(assert_return (invoke "nested-block-value" (i32.const 100000)) (i32.const 16))
+
+(assert_return (invoke "nested-br-value" (i32.const 0)) (i32.const 8))
+(assert_return (invoke "nested-br-value" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br-value" (i32.const 2)) (i32.const 17))
+(assert_return (invoke "nested-br-value" (i32.const 11)) (i32.const 17))
+(assert_return (invoke "nested-br-value" (i32.const -4)) (i32.const 17))
+(assert_return (invoke "nested-br-value" (i32.const 10213210)) (i32.const 17))
+
+(assert_return (invoke "nested-br_if-value" (i32.const 0)) (i32.const 17))
+(assert_return (invoke "nested-br_if-value" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br_if-value" (i32.const 2)) (i32.const 8))
+(assert_return (invoke "nested-br_if-value" (i32.const 9)) (i32.const 8))
+(assert_return (invoke "nested-br_if-value" (i32.const -9)) (i32.const 8))
+(assert_return (invoke "nested-br_if-value" (i32.const 999999)) (i32.const 8))
+
+(assert_return (invoke "nested-br_if-value-cond" (i32.const 0)) (i32.const 9))
+(assert_return (invoke "nested-br_if-value-cond" (i32.const 1)) (i32.const 8))
+(assert_return (invoke "nested-br_if-value-cond" (i32.const 2)) (i32.const 9))
+(assert_return (invoke "nested-br_if-value-cond" (i32.const 3)) (i32.const 9))
+(assert_return (invoke "nested-br_if-value-cond" (i32.const -1000000)) (i32.const 9))
+(assert_return (invoke "nested-br_if-value-cond" (i32.const 9423975)) (i32.const 9))
+
+(assert_return (invoke "nested-br_table-value" (i32.const 0)) (i32.const 17))
+(assert_return (invoke "nested-br_table-value" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "nested-br_table-value" (i32.const 2)) (i32.const 8))
+(assert_return (invoke "nested-br_table-value" (i32.const 9)) (i32.const 8))
+(assert_return (invoke "nested-br_table-value" (i32.const -9)) (i32.const 8))
+(assert_return (invoke "nested-br_table-value" (i32.const 999999)) (i32.const 8))
+
+(assert_return (invoke "nested-br_table-value-index" (i32.const 0)) (i32.const 9))
+(assert_return (invoke "nested-br_table-value-index" (i32.const 1)) (i32.const 8))
+(assert_return (invoke "nested-br_table-value-index" (i32.const 2)) (i32.const 9))
+(assert_return (invoke "nested-br_table-value-index" (i32.const 3)) (i32.const 9))
+(assert_return (invoke "nested-br_table-value-index" (i32.const -1000000)) (i32.const 9))
+(assert_return (invoke "nested-br_table-value-index" (i32.const 9423975)) (i32.const 9))
+
+(assert_invalid
+  (module (func $type-arg-void-vs-num (result i32)
+    (block (br_table 0 (i32.const 1)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+(; TODO(stack): soft failure
+(assert_invalid
+  (module (func $type-arg-poly-vs-empty
+    (block (br_table 0 (unreachable) (i32.const 1)))
+  ))
+  "type mismatch"
+)
+;)
+
+(assert_invalid
+  (module (func $type-arg-void-vs-num (result i32)
+    (block i32 (br_table 0 (nop) (i32.const 1)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-arg-num-vs-num (result i32)
+    (block i32 (br_table 0 0 0 (i64.const 1) (i32.const 1)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $type-index-void-vs-i32
+    (block (br_table 0 0 0 (nop)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-index-num-vs-i32
+    (block (br_table 0 (i64.const 0)))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-arg-index-void-vs-i32 (result i32)
+    (block i32 (br_table 0 0 (i32.const 0) (nop)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+(assert_invalid
+  (module (func $type-arg-index-num-vs-i32 (result i32)
+    (block i32 (br_table 0 0 (i32.const 0) (i64.const 0)) (i32.const 1))
+  ))
+  "type mismatch"
+)
+
+(assert_invalid
+  (module (func $unbound-label
+    (block (br_table 2 1 (i32.const 1)))
+  ))
+  "unknown label"
+)
+(assert_invalid
+  (module (func $unbound-nested-label
+    (block (block (br_table 0 5 (i32.const 1))))
+  ))
+  "unknown label"
+)
+(assert_invalid
+  (module (func $large-label
+    (block (br_table 0 0x10000001 0 (i32.const 1)))
+  ))
+  "unknown label"
+)
+
+(assert_invalid
+  (module (func $unbound-label-default
+    (block (br_table 1 2 (i32.const 1)))
+  ))
+  "unknown label"
+)
+(assert_invalid
+  (module (func $unbound-nested-label-default
+    (block (block (br_table 0 5 (i32.const 1))))
+  ))
+  "unknown label"
+)
+(assert_invalid
+  (module (func $large-label-default
+    (block (br_table 0 0 0x10000001 (i32.const 1)))
+  ))
+  "unknown label"
+)
diff --git a/binaryen/test/wasm2js/br_table_to_loop.2asm.js b/binaryen/test/wasm2js/br_table_to_loop.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/br_table_to_loop.2asm.js
@@ -0,0 +1,59 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  block : {
+   loop : while (1) switch (1 | 0) {
+   case 1:
+    continue loop;
+   default:
+    break block;
+   };
+  }
+ }
+ 
+ function $1() {
+  block : {
+   loop : while (1) switch (1 | 0) {
+   case 1:
+    break block;
+   default:
+    continue loop;
+   };
+  }
+ }
+ 
+ return {
+  "exp1": $0, 
+  "exp2": $1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/br_table_to_loop.2asm.js.opt
@@ -0,0 +1,45 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  while (1) continue;
+ }
+ 
+ function $1() {
+  
+ }
+ 
+ return {
+  "exp1": $0, 
+  "exp2": $1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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.wast b/binaryen/test/wasm2js/br_table_to_loop.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/br_table_to_loop.wast
@@ -0,0 +1,16 @@
+(module
+ (func "exp1"
+  (block $block
+   (loop $loop
+    (br_table $block $loop $block (i32.const 1))
+   )
+  )
+ )
+ (func "exp2"
+  (block $block
+   (loop $loop
+    (br_table $loop $block $loop (i32.const 1))
+   )
+  )
+ )
+)
diff --git a/binaryen/test/wasm2js/break-drop.2asm.js b/binaryen/test/wasm2js/break-drop.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/break-drop.2asm.js
@@ -0,0 +1,51 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  
+ }
+ 
+ function $1() {
+  
+ }
+ 
+ function $2() {
+  
+ }
+ 
+ return {
+  "br": $0, 
+  "br_if": $1, 
+  "br_table": $2
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var br = retasmFunc.br;
+export var br_if = retasmFunc.br_if;
+export var br_table = retasmFunc.br_table;
diff --git a/binaryen/test/wasm2js/bulk-memory.2asm.js b/binaryen/test/wasm2js/bulk-memory.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/bulk-memory.2asm.js
@@ -0,0 +1,484 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ return {
+  
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_memory_fill(dest, value, size) {
+    dest = dest >>> 0;
+    size = size >>> 0;
+    if (dest + size > bufferView.length) throw "trap: invalid memory.fill";
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0($0_1, $1_1, $2) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2 = $2 | 0;
+  wasm2js_memory_fill($0_1, $1_1, $2);
+ }
+ 
+ function $1($0_1) {
+  $0_1 = $0_1 | 0;
+  return HEAPU8[$0_1 >> 0] | 0 | 0;
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "fill": $0, 
+  "load8_u": $1
+ };
+}
+
+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
+);
+export var fill = retasmFunc.fill;
+export var load8_u = retasmFunc.load8_u;
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_memory_copy(dest, source, size) {
+    // TODO: traps on invalid things
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0($0_1, $1_1, $2) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2 = $2 | 0;
+  wasm2js_memory_copy($0_1, $1_1, $2);
+ }
+ 
+ function $1($0_1) {
+  $0_1 = $0_1 | 0;
+  return HEAPU8[$0_1 >> 0] | 0 | 0;
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "copy": $0, 
+  "load8_u": $1
+ };
+}
+
+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; 
+  }
+  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;
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_memory_init(segment, dest, offset, size) {
+    // TODO: traps on invalid things
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0($0_1, $1_1, $2) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2 = $2 | 0;
+  wasm2js_memory_init(0, $0_1, $1_1, $2);
+ }
+ 
+ function $1($0_1) {
+  $0_1 = $0_1 | 0;
+  return HEAPU8[$0_1 >> 0] | 0 | 0;
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "init": $0, 
+  "load8_u": $1
+ };
+}
+
+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
+);
+export var init = retasmFunc.init;
+export var load8_u = retasmFunc.load8_u;
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_data_drop(segment) {
+    // TODO: traps on invalid things
+    memorySegments[segment] = new Uint8Array(0);
+  }
+      
+  function wasm2js_memory_init(segment, dest, offset, size) {
+    // TODO: traps on invalid things
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  wasm2js_data_drop(0);
+ }
+ 
+ function $1() {
+  wasm2js_memory_init(0, 0, 0, 0);
+ }
+ 
+ function $2() {
+  wasm2js_data_drop(1);
+ }
+ 
+ function $3() {
+  wasm2js_memory_init(1, 0, 0, 0);
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "drop_passive": $0, 
+  "init_passive": $1, 
+  "drop_active": $2, 
+  "init_active": $3
+ };
+}
+
+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
+);
+export var drop_passive = retasmFunc.drop_passive;
+export var init_passive = retasmFunc.init_passive;
+export var drop_active = retasmFunc.drop_active;
+export var init_active = retasmFunc.init_active;
diff --git a/binaryen/test/wasm2js/bulk-memory.2asm.js.opt b/binaryen/test/wasm2js/bulk-memory.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/bulk-memory.2asm.js.opt
@@ -0,0 +1,439 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ return {
+  
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_memory_fill(dest, value, size) {
+    dest = dest >>> 0;
+    size = size >>> 0;
+    if (dest + size > bufferView.length) throw "trap: invalid memory.fill";
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0($0_1, $1_1, $2) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2 = $2 | 0;
+  wasm2js_memory_fill($0_1, $1_1, $2);
+ }
+ 
+ function $1($0_1) {
+  $0_1 = $0_1 | 0;
+  return HEAPU8[$0_1 | 0];
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "fill": $0, 
+  "load8_u": $1
+ };
+}
+
+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
+);
+export var fill = retasmFunc.fill;
+export var load8_u = retasmFunc.load8_u;
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_memory_copy(dest, source, size) {
+    // TODO: traps on invalid things
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0($0_1, $1_1, $2) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2 = $2 | 0;
+  wasm2js_memory_copy($0_1, $1_1, $2);
+ }
+ 
+ function $1($0_1) {
+  $0_1 = $0_1 | 0;
+  return HEAPU8[$0_1 | 0];
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "copy": $0, 
+  "load8_u": $1
+ };
+}
+
+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; 
+  }
+  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;
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_memory_init(segment, dest, offset, size) {
+    // TODO: traps on invalid things
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0($0_1, $1_1, $2) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2 = $2 | 0;
+  wasm2js_memory_init(0, $0_1, $1_1, $2);
+ }
+ 
+ function $1($0_1) {
+  $0_1 = $0_1 | 0;
+  return HEAPU8[$0_1 | 0];
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "init": $0, 
+  "load8_u": $1
+ };
+}
+
+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
+);
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  
+ }
+ 
+ function $1() {
+  if (0 > __wasm_memory_size() << 16 >>> 0) {
+   abort()
+  }
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "drop_passive": $0, 
+  "init_passive": $1, 
+  "drop_active": $0, 
+  "init_active": $1
+ };
+}
+
+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
+);
+export var drop_passive = retasmFunc.drop_passive;
+export var init_passive = retasmFunc.init_passive;
+export var drop_active = retasmFunc.drop_active;
+export var init_active = retasmFunc.init_active;
diff --git a/binaryen/test/wasm2js/comments.2asm.js b/binaryen/test/wasm2js/comments.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/comments.2asm.js
@@ -0,0 +1,68 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ return {
+  
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ return {
+  
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
diff --git a/binaryen/test/wasm2js/conversions-modified.2asm.js b/binaryen/test/wasm2js/conversions-modified.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/conversions-modified.2asm.js
@@ -0,0 +1,661 @@
+import { setTempRet0 } from 'env';
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_scratch_load_i32(index) {
+    return i32ScratchView[index];
+  }
+      
+  function wasm2js_scratch_store_i32(index, value) {
+    i32ScratchView[index] = value;
+  }
+      
+  function wasm2js_scratch_load_f64() {
+    return f64ScratchView[0];
+  }
+      
+  function wasm2js_scratch_store_f64(value) {
+    f64ScratchView[0] = value;
+  }
+      
+  function wasm2js_scratch_load_f32() {
+    return f32ScratchView[2];
+  }
+      
+  function wasm2js_scratch_store_f32(value) {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0;
+  i64toi32_i32$1 = x;
+  i64toi32_i32$0 = i64toi32_i32$1 >> 31 | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return x | 0;
+ }
+ 
+ function $2(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  return x | 0;
+ }
+ 
+ function $3(x) {
+  x = Math_fround(x);
+  return ~~x | 0;
+ }
+ 
+ function $4(x) {
+  x = Math_fround(x);
+  return ~~x >>> 0 | 0;
+ }
+ 
+ function $5(x) {
+  x = +x;
+  return ~~x | 0;
+ }
+ 
+ function $6(x) {
+  x = +x;
+  return ~~x >>> 0 | 0;
+ }
+ 
+ function $7(x) {
+  x = Math_fround(x);
+  var i64toi32_i32$0 = Math_fround(0), $4_1 = 0, $5_1 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = x;
+  if (Math_fround(Math_abs(i64toi32_i32$0)) >= Math_fround(1.0)) {
+   if (i64toi32_i32$0 > Math_fround(0.0)) {
+    $4_1 = ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround(i64toi32_i32$0 / Math_fround(4294967296.0)))), Math_fround(Math_fround(4294967296.0) - Math_fround(1.0)))) >>> 0
+   } else {
+    $4_1 = ~~Math_fround(Math_ceil(Math_fround(Math_fround(i64toi32_i32$0 - Math_fround(~~i64toi32_i32$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0
+   }
+   $5_1 = $4_1;
+  } else {
+   $5_1 = 0
+  }
+  i64toi32_i32$1 = $5_1;
+  i64toi32_i32$2 = ~~i64toi32_i32$0 >>> 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function $8(x) {
+  x = Math_fround(x);
+  var i64toi32_i32$0 = Math_fround(0), $4_1 = 0, $5_1 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = x;
+  if (Math_fround(Math_abs(i64toi32_i32$0)) >= Math_fround(1.0)) {
+   if (i64toi32_i32$0 > Math_fround(0.0)) {
+    $4_1 = ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround(i64toi32_i32$0 / Math_fround(4294967296.0)))), Math_fround(Math_fround(4294967296.0) - Math_fround(1.0)))) >>> 0
+   } else {
+    $4_1 = ~~Math_fround(Math_ceil(Math_fround(Math_fround(i64toi32_i32$0 - Math_fround(~~i64toi32_i32$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0
+   }
+   $5_1 = $4_1;
+  } else {
+   $5_1 = 0
+  }
+  i64toi32_i32$1 = $5_1;
+  i64toi32_i32$2 = ~~i64toi32_i32$0 >>> 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function $9(x) {
+  x = +x;
+  var i64toi32_i32$0 = 0.0, $4_1 = 0, $5_1 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = x;
+  if (Math_abs(i64toi32_i32$0) >= 1.0) {
+   if (i64toi32_i32$0 > 0.0) {
+    $4_1 = ~~Math_min(Math_floor(i64toi32_i32$0 / 4294967296.0), 4294967296.0 - 1.0) >>> 0
+   } else {
+    $4_1 = ~~Math_ceil((i64toi32_i32$0 - +(~~i64toi32_i32$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0
+   }
+   $5_1 = $4_1;
+  } else {
+   $5_1 = 0
+  }
+  i64toi32_i32$1 = $5_1;
+  i64toi32_i32$2 = ~~i64toi32_i32$0 >>> 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function $10(x) {
+  x = +x;
+  var i64toi32_i32$0 = 0.0, $4_1 = 0, $5_1 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = x;
+  if (Math_abs(i64toi32_i32$0) >= 1.0) {
+   if (i64toi32_i32$0 > 0.0) {
+    $4_1 = ~~Math_min(Math_floor(i64toi32_i32$0 / 4294967296.0), 4294967296.0 - 1.0) >>> 0
+   } else {
+    $4_1 = ~~Math_ceil((i64toi32_i32$0 - +(~~i64toi32_i32$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0
+   }
+   $5_1 = $4_1;
+  } else {
+   $5_1 = 0
+  }
+  i64toi32_i32$1 = $5_1;
+  i64toi32_i32$2 = ~~i64toi32_i32$0 >>> 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function $11(x) {
+  x = x | 0;
+  return Math_fround(Math_fround(x | 0));
+ }
+ 
+ function $12(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = x$hi;
+  return Math_fround(Math_fround(+(x >>> 0) + 4294967296.0 * +(i64toi32_i32$0 | 0)));
+ }
+ 
+ function $13(x) {
+  x = x | 0;
+  return +(+(x | 0));
+ }
+ 
+ function $14(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = x$hi;
+  return +(+(x >>> 0) + 4294967296.0 * +(i64toi32_i32$0 | 0));
+ }
+ 
+ function $15(x) {
+  x = x | 0;
+  return Math_fround(Math_fround(x >>> 0));
+ }
+ 
+ function $16(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = x$hi;
+  return Math_fround(Math_fround(+(x >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0)));
+ }
+ 
+ function $17(x) {
+  x = x | 0;
+  return +(+(x >>> 0));
+ }
+ 
+ function $18(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = x$hi;
+  return +(+(x >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0));
+ }
+ 
+ function $19(x) {
+  x = Math_fround(x);
+  return +(+x);
+ }
+ 
+ function $20(x) {
+  x = +x;
+  return Math_fround(Math_fround(x));
+ }
+ 
+ function $21(x) {
+  x = x | 0;
+  return Math_fround((wasm2js_scratch_store_i32(2, x), wasm2js_scratch_load_f32()));
+ }
+ 
+ function $22(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = x$hi;
+  wasm2js_scratch_store_i32(0 | 0, x | 0);
+  wasm2js_scratch_store_i32(1 | 0, i64toi32_i32$0 | 0);
+  return +(+wasm2js_scratch_load_f64());
+ }
+ 
+ function $23(x) {
+  x = Math_fround(x);
+  return (wasm2js_scratch_store_f32(x), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $24(x) {
+  x = +x;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+x);
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$0($0_1) {
+  $0_1 = $0_1 | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $8_1 = 0, $1_1 = 0, $1$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $0($0_1 | 0) | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $1_1 = i64toi32_i32$0;
+  $1$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $8_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $8_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($8_1 | 0);
+  i64toi32_i32$0 = $1$hi;
+  return $1_1 | 0;
+ }
+ 
+ function legalstub$1($0_1) {
+  $0_1 = $0_1 | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $8_1 = 0, $1_1 = 0, $1$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $1($0_1 | 0) | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $1_1 = i64toi32_i32$0;
+  $1$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $8_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $8_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($8_1 | 0);
+  i64toi32_i32$0 = $1$hi;
+  return $1_1 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $10_1 = 0, $3_1 = 0, $3$hi = 0, $6$hi = 0;
+  i64toi32_i32$0 = 0;
+  $3_1 = $0_1;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $10_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $10_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $6$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$0 = $3_1;
+  i64toi32_i32$2 = $6$hi;
+  i64toi32_i32$3 = $10_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$7($0_1) {
+  $0_1 = Math_fround($0_1);
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $8_1 = 0, $1_1 = 0, $1$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $7(Math_fround($0_1)) | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $1_1 = i64toi32_i32$0;
+  $1$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $8_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $8_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($8_1 | 0);
+  i64toi32_i32$0 = $1$hi;
+  return $1_1 | 0;
+ }
+ 
+ function legalstub$8($0_1) {
+  $0_1 = Math_fround($0_1);
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $8_1 = 0, $1_1 = 0, $1$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $8(Math_fround($0_1)) | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $1_1 = i64toi32_i32$0;
+  $1$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $8_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $8_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($8_1 | 0);
+  i64toi32_i32$0 = $1$hi;
+  return $1_1 | 0;
+ }
+ 
+ function legalstub$9($0_1) {
+  $0_1 = +$0_1;
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $8_1 = 0, $1_1 = 0, $1$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $9(+$0_1) | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $1_1 = i64toi32_i32$0;
+  $1$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $8_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $8_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($8_1 | 0);
+  i64toi32_i32$0 = $1$hi;
+  return $1_1 | 0;
+ }
+ 
+ function legalstub$10($0_1) {
+  $0_1 = +$0_1;
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $8_1 = 0, $1_1 = 0, $1$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $10(+$0_1) | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $1_1 = i64toi32_i32$0;
+  $1$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $8_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $8_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($8_1 | 0);
+  i64toi32_i32$0 = $1$hi;
+  return $1_1 | 0;
+ }
+ 
+ function legalstub$12($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $10_1 = 0, $3_1 = 0, $3$hi = 0, $6$hi = 0;
+  i64toi32_i32$0 = 0;
+  $3_1 = $0_1;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $10_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $10_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $6$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$0 = $3_1;
+  i64toi32_i32$2 = $6$hi;
+  i64toi32_i32$3 = $10_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return Math_fround(Math_fround($12(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0)));
+ }
+ 
+ function legalstub$14($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $10_1 = 0, $3_1 = 0, $3$hi = 0, $6$hi = 0;
+  i64toi32_i32$0 = 0;
+  $3_1 = $0_1;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $10_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $10_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $6$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$0 = $3_1;
+  i64toi32_i32$2 = $6$hi;
+  i64toi32_i32$3 = $10_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return +(+$14(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0));
+ }
+ 
+ function legalstub$16($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $10_1 = 0, $3_1 = 0, $3$hi = 0, $6$hi = 0;
+  i64toi32_i32$0 = 0;
+  $3_1 = $0_1;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $10_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $10_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $6$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$0 = $3_1;
+  i64toi32_i32$2 = $6$hi;
+  i64toi32_i32$3 = $10_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return Math_fround(Math_fround($16(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0)));
+ }
+ 
+ function legalstub$18($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $10_1 = 0, $3_1 = 0, $3$hi = 0, $6$hi = 0;
+  i64toi32_i32$0 = 0;
+  $3_1 = $0_1;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $10_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $10_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $6$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$0 = $3_1;
+  i64toi32_i32$2 = $6$hi;
+  i64toi32_i32$3 = $10_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return +(+$18(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0));
+ }
+ 
+ function legalstub$22($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $10_1 = 0, $3_1 = 0, $3$hi = 0, $6$hi = 0;
+  i64toi32_i32$0 = 0;
+  $3_1 = $0_1;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $10_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $10_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $6$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$0 = $3_1;
+  i64toi32_i32$2 = $6$hi;
+  i64toi32_i32$3 = $10_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return +(+$22(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0));
+ }
+ 
+ function legalstub$24($0_1) {
+  $0_1 = +$0_1;
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $8_1 = 0, $1_1 = 0, $1$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $24(+$0_1) | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $1_1 = i64toi32_i32$0;
+  $1$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $8_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $8_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($8_1 | 0);
+  i64toi32_i32$0 = $1$hi;
+  return $1_1 | 0;
+ }
+ 
+ return {
+  "i64_extend_s_i32": legalstub$0, 
+  "i64_extend_u_i32": legalstub$1, 
+  "i32_wrap_i64": legalstub$2, 
+  "i32_trunc_s_f32": $3, 
+  "i32_trunc_u_f32": $4, 
+  "i32_trunc_s_f64": $5, 
+  "i32_trunc_u_f64": $6, 
+  "i64_trunc_s_f32": legalstub$7, 
+  "i64_trunc_u_f32": legalstub$8, 
+  "i64_trunc_s_f64": legalstub$9, 
+  "i64_trunc_u_f64": legalstub$10, 
+  "f32_convert_s_i32": $11, 
+  "f32_convert_s_i64": legalstub$12, 
+  "f64_convert_s_i32": $13, 
+  "f64_convert_s_i64": legalstub$14, 
+  "f32_convert_u_i32": $15, 
+  "f32_convert_u_i64": legalstub$16, 
+  "f64_convert_u_i32": $17, 
+  "f64_convert_u_i64": legalstub$18, 
+  "f64_promote_f32": $19, 
+  "f32_demote_f64": $20, 
+  "f32_reinterpret_i32": $21, 
+  "f64_reinterpret_i64": legalstub$22, 
+  "i32_reinterpret_f32": $23, 
+  "i64_reinterpret_f64": legalstub$24
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i64_extend_s_i32 = retasmFunc.i64_extend_s_i32;
+export var i64_extend_u_i32 = retasmFunc.i64_extend_u_i32;
+export var i32_wrap_i64 = retasmFunc.i32_wrap_i64;
+export var i32_trunc_s_f32 = retasmFunc.i32_trunc_s_f32;
+export var i32_trunc_u_f32 = retasmFunc.i32_trunc_u_f32;
+export var i32_trunc_s_f64 = retasmFunc.i32_trunc_s_f64;
+export var i32_trunc_u_f64 = retasmFunc.i32_trunc_u_f64;
+export var i64_trunc_s_f32 = retasmFunc.i64_trunc_s_f32;
+export var i64_trunc_u_f32 = retasmFunc.i64_trunc_u_f32;
+export var i64_trunc_s_f64 = retasmFunc.i64_trunc_s_f64;
+export var i64_trunc_u_f64 = retasmFunc.i64_trunc_u_f64;
+export var f32_convert_s_i32 = retasmFunc.f32_convert_s_i32;
+export var f32_convert_s_i64 = retasmFunc.f32_convert_s_i64;
+export var f64_convert_s_i32 = retasmFunc.f64_convert_s_i32;
+export var f64_convert_s_i64 = retasmFunc.f64_convert_s_i64;
+export var f32_convert_u_i32 = retasmFunc.f32_convert_u_i32;
+export var f32_convert_u_i64 = retasmFunc.f32_convert_u_i64;
+export var f64_convert_u_i32 = retasmFunc.f64_convert_u_i32;
+export var f64_convert_u_i64 = retasmFunc.f64_convert_u_i64;
+export var f64_promote_f32 = retasmFunc.f64_promote_f32;
+export var f32_demote_f64 = retasmFunc.f32_demote_f64;
+export var f32_reinterpret_i32 = retasmFunc.f32_reinterpret_i32;
+export var f64_reinterpret_i64 = retasmFunc.f64_reinterpret_i64;
+export var i32_reinterpret_f32 = retasmFunc.i32_reinterpret_f32;
+export var i64_reinterpret_f64 = retasmFunc.i64_reinterpret_f64;
diff --git a/binaryen/test/wasm2js/conversions-modified.2asm.js.opt b/binaryen/test/wasm2js/conversions-modified.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/conversions-modified.2asm.js.opt
@@ -0,0 +1,252 @@
+import { setTempRet0 } from 'env';
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_scratch_load_i32(index) {
+    return i32ScratchView[index];
+  }
+      
+  function wasm2js_scratch_store_i32(index, value) {
+    i32ScratchView[index] = value;
+  }
+      
+  function wasm2js_scratch_load_f64() {
+    return f64ScratchView[0];
+  }
+      
+  function wasm2js_scratch_store_f64(value) {
+    f64ScratchView[0] = value;
+  }
+      
+  function wasm2js_scratch_load_f32() {
+    return f32ScratchView[2];
+  }
+      
+  function wasm2js_scratch_store_f32(value) {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $3($0) {
+  $0 = Math_fround($0);
+  return ~~$0 | 0;
+ }
+ 
+ function $4($0) {
+  $0 = Math_fround($0);
+  return ~~$0 >>> 0 | 0;
+ }
+ 
+ function $5($0) {
+  $0 = +$0;
+  return ~~$0 | 0;
+ }
+ 
+ function $6($0) {
+  $0 = +$0;
+  return ~~$0 >>> 0 | 0;
+ }
+ 
+ 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;
+  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;
+  return ~~$0 >>> 0 | 0;
+ }
+ 
+ function $11($0) {
+  $0 = $0 | 0;
+  return Math_fround(Math_fround($0 | 0));
+ }
+ 
+ function $13($0) {
+  $0 = $0 | 0;
+  return +($0 | 0);
+ }
+ 
+ function $15($0) {
+  $0 = $0 | 0;
+  return Math_fround(Math_fround($0 >>> 0));
+ }
+ 
+ function $17($0) {
+  $0 = $0 | 0;
+  return +($0 >>> 0);
+ }
+ 
+ function $19($0) {
+  $0 = Math_fround($0);
+  return +$0;
+ }
+ 
+ function $20($0) {
+  $0 = +$0;
+  return Math_fround(Math_fround($0));
+ }
+ 
+ function $21($0) {
+  $0 = $0 | 0;
+  return Math_fround((wasm2js_scratch_store_i32(2, $0), wasm2js_scratch_load_f32()));
+ }
+ 
+ function $23($0) {
+  $0 = Math_fround($0);
+  return (wasm2js_scratch_store_f32($0), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function legalstub$0($0) {
+  i64toi32_i32$HIGH_BITS = $0 >> 31;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0;
+ }
+ 
+ function legalstub$1($0) {
+  i64toi32_i32$HIGH_BITS = 0;
+  setTempRet0(0);
+  return $0;
+ }
+ 
+ function legalstub$2($0, $1) {
+  return $0;
+ }
+ 
+ function legalstub$7($0) {
+  var $1 = 0;
+  $1 = $7($0);
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $1;
+ }
+ 
+ function legalstub$9($0) {
+  var $1 = 0;
+  $1 = $9($0);
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $1;
+ }
+ 
+ function legalstub$12($0, $1) {
+  return Math_fround(+($0 >>> 0) + +($1 | 0) * 4294967296.0);
+ }
+ 
+ function legalstub$14($0, $1) {
+  return +($0 >>> 0) + +($1 | 0) * 4294967296.0;
+ }
+ 
+ function legalstub$16($0, $1) {
+  return Math_fround(+($0 >>> 0) + +($1 >>> 0) * 4294967296.0);
+ }
+ 
+ function legalstub$18($0, $1) {
+  return +($0 >>> 0) + +($1 >>> 0) * 4294967296.0;
+ }
+ 
+ function legalstub$22($0, $1) {
+  wasm2js_scratch_store_i32(0, $0 | 0);
+  wasm2js_scratch_store_i32(1, $1 | 0);
+  return +wasm2js_scratch_load_f64();
+ }
+ 
+ function legalstub$24($0) {
+  var $1 = 0, $2 = 0;
+  wasm2js_scratch_store_f64(+$0);
+  $1 = wasm2js_scratch_load_i32(1) | 0;
+  $2 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $1;
+  $1 = $2;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $1;
+ }
+ 
+ return {
+  "i64_extend_s_i32": legalstub$0, 
+  "i64_extend_u_i32": legalstub$1, 
+  "i32_wrap_i64": legalstub$2, 
+  "i32_trunc_s_f32": $3, 
+  "i32_trunc_u_f32": $4, 
+  "i32_trunc_s_f64": $5, 
+  "i32_trunc_u_f64": $6, 
+  "i64_trunc_s_f32": legalstub$7, 
+  "i64_trunc_u_f32": legalstub$7, 
+  "i64_trunc_s_f64": legalstub$9, 
+  "i64_trunc_u_f64": legalstub$9, 
+  "f32_convert_s_i32": $11, 
+  "f32_convert_s_i64": legalstub$12, 
+  "f64_convert_s_i32": $13, 
+  "f64_convert_s_i64": legalstub$14, 
+  "f32_convert_u_i32": $15, 
+  "f32_convert_u_i64": legalstub$16, 
+  "f64_convert_u_i32": $17, 
+  "f64_convert_u_i64": legalstub$18, 
+  "f64_promote_f32": $19, 
+  "f32_demote_f64": $20, 
+  "f32_reinterpret_i32": $21, 
+  "f64_reinterpret_i64": legalstub$22, 
+  "i32_reinterpret_f32": $23, 
+  "i64_reinterpret_f64": legalstub$24
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i64_extend_s_i32 = retasmFunc.i64_extend_s_i32;
+export var i64_extend_u_i32 = retasmFunc.i64_extend_u_i32;
+export var i32_wrap_i64 = retasmFunc.i32_wrap_i64;
+export var i32_trunc_s_f32 = retasmFunc.i32_trunc_s_f32;
+export var i32_trunc_u_f32 = retasmFunc.i32_trunc_u_f32;
+export var i32_trunc_s_f64 = retasmFunc.i32_trunc_s_f64;
+export var i32_trunc_u_f64 = retasmFunc.i32_trunc_u_f64;
+export var i64_trunc_s_f32 = retasmFunc.i64_trunc_s_f32;
+export var i64_trunc_u_f32 = retasmFunc.i64_trunc_u_f32;
+export var i64_trunc_s_f64 = retasmFunc.i64_trunc_s_f64;
+export var i64_trunc_u_f64 = retasmFunc.i64_trunc_u_f64;
+export var f32_convert_s_i32 = retasmFunc.f32_convert_s_i32;
+export var f32_convert_s_i64 = retasmFunc.f32_convert_s_i64;
+export var f64_convert_s_i32 = retasmFunc.f64_convert_s_i32;
+export var f64_convert_s_i64 = retasmFunc.f64_convert_s_i64;
+export var f32_convert_u_i32 = retasmFunc.f32_convert_u_i32;
+export var f32_convert_u_i64 = retasmFunc.f32_convert_u_i64;
+export var f64_convert_u_i32 = retasmFunc.f64_convert_u_i32;
+export var f64_convert_u_i64 = retasmFunc.f64_convert_u_i64;
+export var f64_promote_f32 = retasmFunc.f64_promote_f32;
+export var f32_demote_f64 = retasmFunc.f32_demote_f64;
+export var f32_reinterpret_i32 = retasmFunc.f32_reinterpret_i32;
+export var f64_reinterpret_i64 = retasmFunc.f64_reinterpret_i64;
+export var i32_reinterpret_f32 = retasmFunc.i32_reinterpret_f32;
+export var i64_reinterpret_f64 = retasmFunc.i64_reinterpret_f64;
diff --git a/binaryen/test/wasm2js/conversions-modified.wast b/binaryen/test/wasm2js/conversions-modified.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/conversions-modified.wast
@@ -0,0 +1,419 @@
+(module
+  (func (export "i64.extend_s_i32") (param $x i32) (result i64) (i64.extend_i32_s (local.get $x)))
+  (func (export "i64.extend_u_i32") (param $x i32) (result i64) (i64.extend_i32_u (local.get $x)))
+  (func (export "i32.wrap_i64") (param $x i64) (result i32) (i32.wrap_i64 (local.get $x)))
+  (func (export "i32.trunc_s_f32") (param $x f32) (result i32) (i32.trunc_f32_s (local.get $x)))
+  (func (export "i32.trunc_u_f32") (param $x f32) (result i32) (i32.trunc_f32_u (local.get $x)))
+  (func (export "i32.trunc_s_f64") (param $x f64) (result i32) (i32.trunc_f64_s (local.get $x)))
+  (func (export "i32.trunc_u_f64") (param $x f64) (result i32) (i32.trunc_f64_u (local.get $x)))
+  (func (export "i64.trunc_s_f32") (param $x f32) (result i64) (i64.trunc_f32_s (local.get $x)))
+  (func (export "i64.trunc_u_f32") (param $x f32) (result i64) (i64.trunc_f32_u (local.get $x)))
+  (func (export "i64.trunc_s_f64") (param $x f64) (result i64) (i64.trunc_f64_s (local.get $x)))
+  (func (export "i64.trunc_u_f64") (param $x f64) (result i64) (i64.trunc_f64_u (local.get $x)))
+  (func (export "f32.convert_s_i32") (param $x i32) (result f32) (f32.convert_i32_s (local.get $x)))
+  (func (export "f32.convert_s_i64") (param $x i64) (result f32) (f32.convert_i64_s (local.get $x)))
+  (func (export "f64.convert_s_i32") (param $x i32) (result f64) (f64.convert_i32_s (local.get $x)))
+  (func (export "f64.convert_s_i64") (param $x i64) (result f64) (f64.convert_i64_s (local.get $x)))
+  (func (export "f32.convert_u_i32") (param $x i32) (result f32) (f32.convert_i32_u (local.get $x)))
+  (func (export "f32.convert_u_i64") (param $x i64) (result f32) (f32.convert_i64_u (local.get $x)))
+  (func (export "f64.convert_u_i32") (param $x i32) (result f64) (f64.convert_i32_u (local.get $x)))
+  (func (export "f64.convert_u_i64") (param $x i64) (result f64) (f64.convert_i64_u (local.get $x)))
+  (func (export "f64.promote_f32") (param $x f32) (result f64) (f64.promote_f32 (local.get $x)))
+  (func (export "f32.demote_f64") (param $x f64) (result f32) (f32.demote_f64 (local.get $x)))
+  (func (export "f32.reinterpret_i32") (param $x i32) (result f32) (f32.reinterpret_i32 (local.get $x)))
+  (func (export "f64.reinterpret_i64") (param $x i64) (result f64) (f64.reinterpret_i64 (local.get $x)))
+  (func (export "i32.reinterpret_f32") (param $x f32) (result i32) (i32.reinterpret_f32 (local.get $x)))
+  (func (export "i64.reinterpret_f64") (param $x f64) (result i64) (i64.reinterpret_f64 (local.get $x)))
+)
+
+(assert_return (invoke "i64.extend_s_i32" (i32.const 0)) (i64.const 0))
+(assert_return (invoke "i64.extend_s_i32" (i32.const 10000)) (i64.const 10000))
+(assert_return (invoke "i64.extend_s_i32" (i32.const -10000)) (i64.const -10000))
+(assert_return (invoke "i64.extend_s_i32" (i32.const -1)) (i64.const -1))
+(assert_return (invoke "i64.extend_s_i32" (i32.const 0x7fffffff)) (i64.const 0x000000007fffffff))
+(assert_return (invoke "i64.extend_s_i32" (i32.const 0x80000000)) (i64.const 0xffffffff80000000))
+
+(assert_return (invoke "i64.extend_u_i32" (i32.const 0)) (i64.const 0))
+(assert_return (invoke "i64.extend_u_i32" (i32.const 10000)) (i64.const 10000))
+(assert_return (invoke "i64.extend_u_i32" (i32.const -10000)) (i64.const 0x00000000ffffd8f0))
+(assert_return (invoke "i64.extend_u_i32" (i32.const -1)) (i64.const 0xffffffff))
+(assert_return (invoke "i64.extend_u_i32" (i32.const 0x7fffffff)) (i64.const 0x000000007fffffff))
+(assert_return (invoke "i64.extend_u_i32" (i32.const 0x80000000)) (i64.const 0x0000000080000000))
+
+(assert_return (invoke "i32.wrap_i64" (i64.const -1)) (i32.const -1))
+(assert_return (invoke "i32.wrap_i64" (i64.const -100000)) (i32.const -100000))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0x80000000)) (i32.const 0x80000000))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0xffffffff7fffffff)) (i32.const 0x7fffffff))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0xffffffff00000000)) (i32.const 0x00000000))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0xfffffffeffffffff)) (i32.const 0xffffffff))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0xffffffff00000001)) (i32.const 0x00000001))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0)) (i32.const 0))
+(assert_return (invoke "i32.wrap_i64" (i64.const 1311768467463790320)) (i32.const 0x9abcdef0))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0x00000000ffffffff)) (i32.const 0xffffffff))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0x0000000100000000)) (i32.const 0x00000000))
+(assert_return (invoke "i32.wrap_i64" (i64.const 0x0000000100000001)) (i32.const 0x00000001))
+
+(assert_return (invoke "i32.trunc_s_f32" (f32.const 0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const 1.0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const 0x1.19999ap+0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const 1.5)) (i32.const 1))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -1.0)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -0x1.19999ap+0)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -1.5)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -1.9)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -2.0)) (i32.const -2))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const 2147483520.0)) (i32.const 2147483520))
+(assert_return (invoke "i32.trunc_s_f32" (f32.const -2147483648.0)) (i32.const -2147483648))
+(assert_trap (invoke "i32.trunc_s_f32" (f32.const 2147483648.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f32" (f32.const -2147483904.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f32" (f32.const infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f32" (f32.const -infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f32" (f32.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const -0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 0x1p-149)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const -0x1p-149)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 1.0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 0x1.19999ap+0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 1.5)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 1.9)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 2.0)) (i32.const 2))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 2147483648)) (i32.const -2147483648)) ;; 0x1.00000p+31 -> 8000 0000
+(assert_return (invoke "i32.trunc_u_f32" (f32.const 4294967040.0)) (i32.const -256))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const -0x1.ccccccp-1)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f32" (f32.const -0x1.fffffep-1)) (i32.const 0))
+(assert_trap (invoke "i32.trunc_u_f32" (f32.const 4294967296.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f32" (f32.const -1.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f32" (f32.const infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f32" (f32.const -infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f32" (f32.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "i32.trunc_s_f64" (f64.const 0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const 1.0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const 0x1.199999999999ap+0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const 1.5)) (i32.const 1))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -1.0)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -0x1.199999999999ap+0)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -1.5)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -1.9)) (i32.const -1))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -2.0)) (i32.const -2))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const 2147483647.0)) (i32.const 2147483647))
+(assert_return (invoke "i32.trunc_s_f64" (f64.const -2147483648.0)) (i32.const -2147483648))
+(assert_trap (invoke "i32.trunc_s_f64" (f64.const 2147483648.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f64" (f64.const -2147483649.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f64" (f64.const infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f64" (f64.const -infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_s_f64" (f64.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const -0.0)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const -0x0.0000000000001p-1022)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 1.0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 0x1.199999999999ap+0)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 1.5)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 1.9)) (i32.const 1))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 2.0)) (i32.const 2))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 2147483648)) (i32.const -2147483648)) ;; 0x1.00000p+31 -> 8000 0000
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 4294967295.0)) (i32.const -1))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const -0x1.ccccccccccccdp-1)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const -0x1.fffffffffffffp-1)) (i32.const 0))
+(assert_return (invoke "i32.trunc_u_f64" (f64.const 1e8)) (i32.const 100000000))
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const 4294967296.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const -1.0)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const 1e16)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const 1e30)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const 9223372036854775808)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const -infinity)) "integer overflow")
+(assert_trap (invoke "i32.trunc_u_f64" (f64.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "i64.trunc_s_f32" (f32.const 0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const 0x1p-149)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -0x1p-149)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const 1.0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const 0x1.19999ap+0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const 1.5)) (i64.const 1))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -1.0)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -0x1.19999ap+0)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -1.5)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -1.9)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -2.0)) (i64.const -2))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const 4294967296)) (i64.const 4294967296)) ;; 0x1.00000p+32 -> 1 0000 0000
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -4294967296)) (i64.const -4294967296)) ;; -0x1.00000p+32 -> ffff ffff 0000 0000
+(assert_return (invoke "i64.trunc_s_f32" (f32.const 9223371487098961920.0)) (i64.const 9223371487098961920))
+(assert_return (invoke "i64.trunc_s_f32" (f32.const -9223372036854775808.0)) (i64.const -9223372036854775808))
+(assert_trap (invoke "i64.trunc_s_f32" (f32.const 9223372036854775808.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f32" (f32.const -9223373136366403584.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f32" (f32.const infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f32" (f32.const -infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f32" (f32.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "i64.trunc_u_f32" (f32.const 0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const -0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const 0x1p-149)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const -0x1p-149)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const 1.0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const 0x1.19999ap+0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const 1.5)) (i64.const 1))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const 4294967296)) (i64.const 4294967296))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const 18446742974197923840.0)) (i64.const -1099511627776))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const -0x1.ccccccp-1)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f32" (f32.const -0x1.fffffep-1)) (i64.const 0))
+(assert_trap (invoke "i64.trunc_u_f32" (f32.const 18446744073709551616.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f32" (f32.const -1.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f32" (f32.const infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f32" (f32.const -infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f32" (f32.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "i64.trunc_s_f64" (f64.const 0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const 0x0.0000000000001p-1022)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -0x0.0000000000001p-1022)) (i64.const 0))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const 1.0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const 0x1.199999999999ap+0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const 1.5)) (i64.const 1))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -1.0)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -0x1.199999999999ap+0)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -1.5)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -1.9)) (i64.const -1))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -2.0)) (i64.const -2))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const 4294967296)) (i64.const 4294967296)) ;; 0x1.00000p+32 -> 1 0000 0000
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -4294967296)) (i64.const -4294967296)) ;; -0x1.00000p+32 -> ffff ffff 0000 0000
+(assert_return (invoke "i64.trunc_s_f64" (f64.const 9223372036854774784.0)) (i64.const 9223372036854774784))
+(assert_return (invoke "i64.trunc_s_f64" (f64.const -9223372036854775808.0)) (i64.const -9223372036854775808))
+(assert_trap (invoke "i64.trunc_s_f64" (f64.const 9223372036854775808.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f64" (f64.const -9223372036854777856.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f64" (f64.const infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f64" (f64.const -infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_s_f64" (f64.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const -0.0)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 0x0.0000000000001p-1022)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const -0x0.0000000000001p-1022)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 1.0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 0x1.199999999999ap+0)) (i64.const 1))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 1.5)) (i64.const 1))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 4294967295)) (i64.const 0xffffffff))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 4294967296)) (i64.const 0x100000000))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 18446744073709549568.0)) (i64.const -2048))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const -0x1.ccccccccccccdp-1)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const -0x1.fffffffffffffp-1)) (i64.const 0))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 1e8)) (i64.const 100000000))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 1e16)) (i64.const 10000000000000000))
+(assert_return (invoke "i64.trunc_u_f64" (f64.const 9223372036854775808)) (i64.const -9223372036854775808))
+(assert_trap (invoke "i64.trunc_u_f64" (f64.const 18446744073709551616.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f64" (f64.const -1.0)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f64" (f64.const infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f64" (f64.const -infinity)) "integer overflow")
+(assert_trap (invoke "i64.trunc_u_f64" (f64.const nan)) "invalid conversion to integer")
+
+(assert_return (invoke "f32.convert_s_i32" (i32.const 1)) (f32.const 1.0))
+(assert_return (invoke "f32.convert_s_i32" (i32.const -1)) (f32.const -1.0))
+(assert_return (invoke "f32.convert_s_i32" (i32.const 0)) (f32.const 0.0))
+(assert_return (invoke "f32.convert_s_i32" (i32.const 2147483647)) (f32.const 2147483648))
+(assert_return (invoke "f32.convert_s_i32" (i32.const -2147483648)) (f32.const -2147483648))
+(assert_return (invoke "f32.convert_s_i32" (i32.const 1234567890)) (f32.const 0x1.26580cp+30))
+;; Test rounding directions.
+(assert_return (invoke "f32.convert_s_i32" (i32.const 16777217)) (f32.const 16777216.0))
+(assert_return (invoke "f32.convert_s_i32" (i32.const -16777217)) (f32.const -16777216.0))
+(assert_return (invoke "f32.convert_s_i32" (i32.const 16777219)) (f32.const 16777220.0))
+(assert_return (invoke "f32.convert_s_i32" (i32.const -16777219)) (f32.const -16777220.0))
+
+(assert_return (invoke "f32.convert_s_i64" (i64.const 1)) (f32.const 1.0))
+(assert_return (invoke "f32.convert_s_i64" (i64.const -1)) (f32.const -1.0))
+(assert_return (invoke "f32.convert_s_i64" (i64.const 0)) (f32.const 0.0))
+(assert_return (invoke "f32.convert_s_i64" (i64.const 9223372036854775807)) (f32.const 9223372036854775807))
+(assert_return (invoke "f32.convert_s_i64" (i64.const -9223372036854775808)) (f32.const -9223372036854775808))
+(assert_return (invoke "f32.convert_s_i64" (i64.const 314159265358979)) (f32.const 0x1.1db9e8p+48)) ;; PI
+;; Test rounding directions.
+(assert_return (invoke "f32.convert_s_i64" (i64.const 16777217)) (f32.const 16777216.0))
+(assert_return (invoke "f32.convert_s_i64" (i64.const -16777217)) (f32.const -16777216.0))
+(assert_return (invoke "f32.convert_s_i64" (i64.const 16777219)) (f32.const 16777220.0))
+(assert_return (invoke "f32.convert_s_i64" (i64.const -16777219)) (f32.const -16777220.0))
+
+(assert_return (invoke "f64.convert_s_i32" (i32.const 1)) (f64.const 1.0))
+(assert_return (invoke "f64.convert_s_i32" (i32.const -1)) (f64.const -1.0))
+(assert_return (invoke "f64.convert_s_i32" (i32.const 0)) (f64.const 0.0))
+(assert_return (invoke "f64.convert_s_i32" (i32.const 2147483647)) (f64.const 2147483647))
+(assert_return (invoke "f64.convert_s_i32" (i32.const -2147483648)) (f64.const -2147483648))
+(assert_return (invoke "f64.convert_s_i32" (i32.const 987654321)) (f64.const 987654321))
+
+(assert_return (invoke "f64.convert_s_i64" (i64.const 1)) (f64.const 1.0))
+(assert_return (invoke "f64.convert_s_i64" (i64.const -1)) (f64.const -1.0))
+(assert_return (invoke "f64.convert_s_i64" (i64.const 0)) (f64.const 0.0))
+(assert_return (invoke "f64.convert_s_i64" (i64.const 9223372036854775807)) (f64.const 9223372036854775807))
+(assert_return (invoke "f64.convert_s_i64" (i64.const -9223372036854775808)) (f64.const -9223372036854775808))
+(assert_return (invoke "f64.convert_s_i64" (i64.const 4669201609102990)) (f64.const 4669201609102990)) ;; Feigenbaum
+;; Test rounding directions.
+(assert_return (invoke "f64.convert_s_i64" (i64.const 9007199254740993)) (f64.const 9007199254740992))
+(assert_return (invoke "f64.convert_s_i64" (i64.const -9007199254740993)) (f64.const -9007199254740992))
+(assert_return (invoke "f64.convert_s_i64" (i64.const 9007199254740995)) (f64.const 9007199254740996))
+(assert_return (invoke "f64.convert_s_i64" (i64.const -9007199254740995)) (f64.const -9007199254740996))
+
+(assert_return (invoke "f32.convert_u_i32" (i32.const 1)) (f32.const 1.0))
+(assert_return (invoke "f32.convert_u_i32" (i32.const 0)) (f32.const 0.0))
+(assert_return (invoke "f32.convert_u_i32" (i32.const 2147483647)) (f32.const 2147483648))
+(assert_return (invoke "f32.convert_u_i32" (i32.const -2147483648)) (f32.const 2147483648))
+(assert_return (invoke "f32.convert_u_i32" (i32.const 0x12345678)) (f32.const 0x1.234568p+28))
+(assert_return (invoke "f32.convert_u_i32" (i32.const 0xffffffff)) (f32.const 4294967296.0))
+;; Test rounding directions.
+(assert_return (invoke "f32.convert_u_i32" (i32.const 16777217)) (f32.const 16777216.0))
+(assert_return (invoke "f32.convert_u_i32" (i32.const 16777219)) (f32.const 16777220.0))
+
+(assert_return (invoke "f32.convert_u_i64" (i64.const 1)) (f32.const 1.0))
+(assert_return (invoke "f32.convert_u_i64" (i64.const 0)) (f32.const 0.0))
+(assert_return (invoke "f32.convert_u_i64" (i64.const 9223372036854775807)) (f32.const 9223372036854775807))
+(assert_return (invoke "f32.convert_u_i64" (i64.const -9223372036854775808)) (f32.const 9223372036854775808))
+(assert_return (invoke "f32.convert_u_i64" (i64.const 0xffffffffffffffff)) (f32.const 18446744073709551616.0))
+;; Test rounding directions.
+(assert_return (invoke "f32.convert_u_i64" (i64.const 16777217)) (f32.const 16777216.0))
+(assert_return (invoke "f32.convert_u_i64" (i64.const 16777219)) (f32.const 16777220.0))
+
+(assert_return (invoke "f64.convert_u_i32" (i32.const 1)) (f64.const 1.0))
+(assert_return (invoke "f64.convert_u_i32" (i32.const 0)) (f64.const 0.0))
+(assert_return (invoke "f64.convert_u_i32" (i32.const 2147483647)) (f64.const 2147483647))
+(assert_return (invoke "f64.convert_u_i32" (i32.const -2147483648)) (f64.const 2147483648))
+(assert_return (invoke "f64.convert_u_i32" (i32.const 0xffffffff)) (f64.const 4294967295.0))
+
+(assert_return (invoke "f64.convert_u_i64" (i64.const 1)) (f64.const 1.0))
+(assert_return (invoke "f64.convert_u_i64" (i64.const 0)) (f64.const 0.0))
+(assert_return (invoke "f64.convert_u_i64" (i64.const 9223372036854775807)) (f64.const 9223372036854775807))
+(assert_return (invoke "f64.convert_u_i64" (i64.const -9223372036854775808)) (f64.const 9223372036854775808))
+(assert_return (invoke "f64.convert_u_i64" (i64.const 0xffffffffffffffff)) (f64.const 18446744073709551616.0))
+;; Test rounding directions.
+(assert_return (invoke "f64.convert_u_i64" (i64.const 9007199254740993)) (f64.const 9007199254740992))
+(assert_return (invoke "f64.convert_u_i64" (i64.const 9007199254740995)) (f64.const 9007199254740996))
+
+(assert_return (invoke "f64.promote_f32" (f32.const 0.0)) (f64.const 0.0))
+(assert_return (invoke "f64.promote_f32" (f32.const -0.0)) (f64.const -0.0))
+(assert_return (invoke "f64.promote_f32" (f32.const 0x1p-149)) (f64.const 0x1p-149))
+(assert_return (invoke "f64.promote_f32" (f32.const -0x1p-149)) (f64.const -0x1p-149))
+(assert_return (invoke "f64.promote_f32" (f32.const 1.0)) (f64.const 1.0))
+(assert_return (invoke "f64.promote_f32" (f32.const -1.0)) (f64.const -1.0))
+(assert_return (invoke "f64.promote_f32" (f32.const -0x1.fffffep+127)) (f64.const -0x1.fffffep+127))
+(assert_return (invoke "f64.promote_f32" (f32.const 0x1.fffffep+127)) (f64.const 0x1.fffffep+127))
+;; Generated randomly by picking a random int and reinterpret it to float.
+(assert_return (invoke "f64.promote_f32" (f32.const 0x1p-119)) (f64.const 0x1p-119))
+;; Generated randomly by picking a random float.
+(assert_return (invoke "f64.promote_f32" (f32.const 0x1.8f867ep+125)) (f64.const 6.6382536710104395e+37))
+(assert_return (invoke "f64.promote_f32" (f32.const infinity)) (f64.const infinity))
+(assert_return (invoke "f64.promote_f32" (f32.const -infinity)) (f64.const -infinity))
+(assert_return (invoke "f64.promote_f32" (f32.const nan)) (f64.const nan))
+
+(assert_return (invoke "f32.demote_f64" (f64.const 0.0)) (f32.const 0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -0.0)) (f32.const -0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x0.0000000000001p-1022)) (f32.const 0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x0.0000000000001p-1022)) (f32.const -0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 1.0)) (f32.const 1.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -1.0)) (f32.const -1.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffe0000000p-127)) (f32.const 0x1p-126))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffe0000000p-127)) (f32.const -0x1p-126))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffdfffffffp-127)) (f32.const 0x1.fffffcp-127))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffdfffffffp-127)) (f32.const -0x1.fffffcp-127))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1p-149)) (f32.const 0x1p-149))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1p-149)) (f32.const -0x1p-149))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffd0000000p+127)) (f32.const 0x1.fffffcp+127))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffd0000000p+127)) (f32.const -0x1.fffffcp+127))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffd0000001p+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffd0000001p+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffep+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffep+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffefffffffp+127)) (f32.const 0x1.fffffep+127))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.fffffefffffffp+127)) (f32.const -0x1.fffffep+127))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.ffffffp+127)) (f32.const infinity))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.ffffffp+127)) (f32.const -infinity))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1p-119)) (f32.const 0x1p-119))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.8f867ep+125)) (f32.const 0x1.8f867ep+125))
+(assert_return (invoke "f32.demote_f64" (f64.const infinity)) (f32.const infinity))
+(assert_return (invoke "f32.demote_f64" (f64.const -infinity)) (f32.const -infinity))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000000000001p+0)) (f32.const 1.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.fffffffffffffp-1)) (f32.const 1.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000010000000p+0)) (f32.const 0x1.000000p+0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000010000001p+0)) (f32.const 0x1.000002p+0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.000002fffffffp+0)) (f32.const 0x1.000002p+0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000030000000p+0)) (f32.const 0x1.000004p+0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000050000000p+0)) (f32.const 0x1.000004p+0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000010000000p+24)) (f32.const 0x1.0p+24))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000010000001p+24)) (f32.const 0x1.000002p+24))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.000002fffffffp+24)) (f32.const 0x1.000002p+24))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000030000000p+24)) (f32.const 0x1.000004p+24))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.4eae4f7024c7p+108)) (f32.const 0x1.4eae5p+108))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.a12e71e358685p-113)) (f32.const 0x1.a12e72p-113))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.cb98354d521ffp-127)) (f32.const 0x1.cb9834p-127))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.6972b30cfb562p+1)) (f32.const -0x1.6972b4p+1))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.bedbe4819d4c4p+112)) (f32.const -0x1.bedbe4p+112))
+(assert_return (invoke "f32.demote_f64" (f64.const nan)) (f32.const nan))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1p-1022)) (f32.const 0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1p-1022)) (f32.const -0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0p-150)) (f32.const 0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.0p-150)) (f32.const -0.0))
+(assert_return (invoke "f32.demote_f64" (f64.const 0x1.0000000000001p-150)) (f32.const 0x1p-149))
+(assert_return (invoke "f32.demote_f64" (f64.const -0x1.0000000000001p-150)) (f32.const -0x1p-149))
+
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0)) (f32.const 0.0))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x80000000)) (f32.const -0.0))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 1)) (f32.const 0x1p-149))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const -1)) (f32.const -nan:0x7fffff))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 123456789)) (f32.const 0x1.b79a2ap-113))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const -2147483647)) (f32.const -0x1p-149))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x7f800000)) (f32.const infinity))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0xff800000)) (f32.const -infinity))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x7fc00000)) (f32.const nan))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0xffc00000)) (f32.const -nan))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0x7fa00000)) (f32.const nan:0x200000))
+(assert_return (invoke "f32.reinterpret_i32" (i32.const 0xffa00000)) (f32.const -nan:0x200000))
+
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0)) (f64.const 0.0))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 1)) (f64.const 0x0.0000000000001p-1022))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const -1)) (f64.const -nan:0xfffffffffffff))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x8000000000000000)) (f64.const -0.0))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 1234567890)) (f64.const 0x0.00000499602d2p-1022))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const -9223372036854775807)) (f64.const -0x0.0000000000001p-1022))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x7ff0000000000000)) (f64.const infinity))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0xfff0000000000000)) (f64.const -infinity))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x7ff8000000000000)) (f64.const nan))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0xfff8000000000000)) (f64.const -nan))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0x7ff4000000000000)) (f64.const nan:0x4000000000000))
+(assert_return (invoke "f64.reinterpret_i64" (i64.const 0xfff4000000000000)) (f64.const -nan:0x4000000000000))
+
+(assert_return (invoke "i32.reinterpret_f32" (f32.const 0.0)) (i32.const 0))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -0.0)) (i32.const 0x80000000))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const 0x1p-149)) (i32.const 1))
+;;(assert_return (invoke "i32.reinterpret_f32" (f32.const -nan:0x7fffff)) (i32.const -1))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -0x1p-149)) (i32.const 0x80000001))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const 1.0)) (i32.const 1065353216))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const 3.1415926)) (i32.const 1078530010))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const 0x1.fffffep+127)) (i32.const 2139095039))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -0x1.fffffep+127)) (i32.const -8388609))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const infinity)) (i32.const 0x7f800000))
+(assert_return (invoke "i32.reinterpret_f32" (f32.const -infinity)) (i32.const 0xff800000))
+;;(assert_return (invoke "i32.reinterpret_f32" (f32.const nan)) (i32.const 0x7fc00000))
+;;(assert_return (invoke "i32.reinterpret_f32" (f32.const -nan)) (i32.const 0xffc00000))
+;;(assert_return (invoke "i32.reinterpret_f32" (f32.const nan:0x200000)) (i32.const 0x7fa00000))
+;;(assert_return (invoke "i32.reinterpret_f32" (f32.const -nan:0x200000)) (i32.const 0xffa00000))
+
+(assert_return (invoke "i64.reinterpret_f64" (f64.const 0.0)) (i64.const 0))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -0.0)) (i64.const 0x8000000000000000))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const 0x0.0000000000001p-1022)) (i64.const 1))
+;;(assert_return (invoke "i64.reinterpret_f64" (f64.const -nan:0xfffffffffffff)) (i64.const -1))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -0x0.0000000000001p-1022)) (i64.const 0x8000000000000001))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const 1.0)) (i64.const 4607182418800017408))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const 3.14159265358979)) (i64.const 4614256656552045841))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const 0x1.fffffffffffffp+1023)) (i64.const 9218868437227405311))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -0x1.fffffffffffffp+1023)) (i64.const -4503599627370497))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const infinity)) (i64.const 0x7ff0000000000000))
+(assert_return (invoke "i64.reinterpret_f64" (f64.const -infinity)) (i64.const 0xfff0000000000000))
+;;(assert_return (invoke "i64.reinterpret_f64" (f64.const nan)) (i64.const 0x7ff8000000000000))
+;;(assert_return (invoke "i64.reinterpret_f64" (f64.const -nan)) (i64.const 0xfff8000000000000))
+;;(assert_return (invoke "i64.reinterpret_f64" (f64.const nan:0x4000000000000)) (i64.const 0x7ff4000000000000))
+;;(assert_return (invoke "i64.reinterpret_f64" (f64.const -nan:0x4000000000000)) (i64.const 0xfff4000000000000))
diff --git a/binaryen/test/wasm2js/deterministic.2asm.js b/binaryen/test/wasm2js/deterministic.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/deterministic.2asm.js
@@ -0,0 +1,60 @@
+
+function asmFunc(global, 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var global$0 = -44;
+ function $0() {
+  if ((global$0 >>> 0) / ((HEAP32[0 >> 2] | 0) >>> 0) | 0) {
+   abort()
+  }
+  return 1 | 0;
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "foo": $0
+ };
+}
+
+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'); },
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/deterministic.2asm.js.opt
@@ -0,0 +1,59 @@
+
+function asmFunc(global, 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  if (4294967252 / HEAPU32[0] | 0) {
+   abort()
+  }
+  return 1;
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "foo": $0
+ };
+}
+
+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'); },
+    memory: { buffer : memasmFunc }
+  });
+export var foo = retasmFunc.foo;
diff --git a/binaryen/test/wasm2js/deterministic.wast b/binaryen/test/wasm2js/deterministic.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/deterministic.wast
@@ -0,0 +1,14 @@
+(module
+ (global $global$0 (mut i32) (i32.const -44))
+ (import "env" "memory" (memory $0 1 1))
+ (func "foo" (result i32)
+  (if
+   (i32.div_u
+    (global.get $global$0)
+    (i32.load (i32.const 0))
+   )
+   (unreachable)
+  )
+  (i32.const 1)
+ )
+)
diff --git a/binaryen/test/wasm2js/dot_import.2asm.js b/binaryen/test/wasm2js/dot_import.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/dot_import.2asm.js
@@ -0,0 +1,42 @@
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var base = env.ba_se;
+ function $0() {
+  base();
+ }
+ 
+ return {
+  "exported": $0
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/dot_import.2asm.js.opt
@@ -0,0 +1,42 @@
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var base = env.ba_se;
+ function $0() {
+  base();
+ }
+ 
+ return {
+  "exported": $0
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    ba_se
+  });
+export var exported = retasmFunc.exported;
diff --git a/binaryen/test/wasm2js/dot_import.wast b/binaryen/test/wasm2js/dot_import.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/dot_import.wast
@@ -0,0 +1,6 @@
+(module
+ (import "mod.ule" "ba.se" (func $base))
+ (func "exported"
+  (call $base)
+ )
+)
diff --git a/binaryen/test/wasm2js/dynamicLibrary.2asm.js b/binaryen/test/wasm2js/dynamicLibrary.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/dynamicLibrary.2asm.js
@@ -0,0 +1,103 @@
+import { memoryBase } from 'env';
+import { tableBase } from 'env';
+
+function Table(ret) {
+  // grow method not included; table is not growable
+  ret.set = function(i, func) {
+    this[i] = func;
+  };
+  ret.get = function(i) {
+    return this[i];
+  };
+  return ret;
+}
+
+function asmFunc(global, 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var import$memoryBase = env.memoryBase | 0;
+ var import$tableBase = env.tableBase | 0;
+ function foo() {
+  
+ }
+ 
+ function bar() {
+  
+ }
+ 
+ function baz() {
+  
+ }
+ 
+ var FUNCTION_TABLE = Table(new Array(10));
+ FUNCTION_TABLE[import$tableBase + 0] = foo;
+ FUNCTION_TABLE[import$tableBase + 1] = bar;
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "baz": baz, 
+  "tab": FUNCTION_TABLE
+ };
+}
+
+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'); },
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/dynamicLibrary.2asm.js.opt
@@ -0,0 +1,95 @@
+import { memoryBase } from 'env';
+import { tableBase } from 'env';
+
+function Table(ret) {
+  // grow method not included; table is not growable
+  ret.set = function(i, func) {
+    this[i] = func;
+  };
+  ret.get = function(i) {
+    return this[i];
+  };
+  return ret;
+}
+
+function asmFunc(global, 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var import$memoryBase = env.memoryBase | 0;
+ var import$tableBase = env.tableBase | 0;
+ function foo() {
+  
+ }
+ 
+ var FUNCTION_TABLE = Table(new Array(10));
+ FUNCTION_TABLE[import$tableBase + 0] = foo;
+ FUNCTION_TABLE[import$tableBase + 1] = foo;
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "baz": foo, 
+  "tab": FUNCTION_TABLE
+ };
+}
+
+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'); },
+    memory: { buffer : memasmFunc }
+  });
+export var baz = retasmFunc.baz;
diff --git a/binaryen/test/wasm2js/dynamicLibrary.wast b/binaryen/test/wasm2js/dynamicLibrary.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/dynamicLibrary.wast
@@ -0,0 +1,19 @@
+(module
+ (type $FUNCSIG$vi (func (param i32)))
+ (type $FUNCSIG$ii (func (param i32) (result i32)))
+
+ (import "env" "memory" (memory $import$memory 256 256))
+ (import "env" "memoryBase" (global $import$memoryBase i32))
+ (data (global.get $import$memoryBase) "dynamic data")
+
+ (table 10 10 funcref)
+ (import "env" "tableBase" (global $import$tableBase i32))
+ (elem (global.get $import$tableBase) $foo $bar)
+
+ (export "baz" (func $baz))
+ (export "tab" (table 0))
+
+ (func $foo)
+ (func $bar)
+ (func $baz)
+)
diff --git a/binaryen/test/wasm2js/empty_export.2asm.js b/binaryen/test/wasm2js/empty_export.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/empty_export.2asm.js
@@ -0,0 +1,39 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function foo() {
+  
+ }
+ 
+ return {
+  "$": foo
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/empty_export.2asm.js.opt
@@ -0,0 +1,39 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function foo() {
+  
+ }
+ 
+ return {
+  "$": foo
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var $ = retasmFunc.$;
diff --git a/binaryen/test/wasm2js/empty_export.wast b/binaryen/test/wasm2js/empty_export.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/empty_export.wast
@@ -0,0 +1,5 @@
+(module
+  (export "" (func $foo))
+  (func $foo)
+)
+
diff --git a/binaryen/test/wasm2js/empty_imported_table.2asm.js b/binaryen/test/wasm2js/empty_imported_table.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/empty_imported_table.2asm.js
@@ -0,0 +1,29 @@
+function asmFunc(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 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var import$table$0 = env.table;
+ var i64toi32_i32$HIGH_BITS = 0;
+ return {
+  
+ };
+}
+
diff --git a/binaryen/test/wasm2js/empty_table.2asm.js b/binaryen/test/wasm2js/empty_table.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/empty_table.2asm.js
@@ -0,0 +1,34 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ return {
+  
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/emscripten-grow-no.2asm.js
@@ -0,0 +1,86 @@
+function instantiate(asmLibraryArg, wasmMemory) {
+function asmFunc(global, 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ // EMSCRIPTEN_START_FUNCS
+;
+ // EMSCRIPTEN_END_FUNCS
+;
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "memory": Object.create(Object.prototype, {
+   "grow": {
+    
+   }, 
+   "buffer": {
+    "get": function () {
+     return buffer;
+    }
+    
+   }
+  })
+ };
+}
+
+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
+)
+
+}
diff --git a/binaryen/test/wasm2js/emscripten-grow-no.2asm.js.opt b/binaryen/test/wasm2js/emscripten-grow-no.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/emscripten-grow-no.2asm.js.opt
@@ -0,0 +1,86 @@
+function instantiate(asmLibraryArg, wasmMemory) {
+function asmFunc(global, 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ // EMSCRIPTEN_START_FUNCS
+;
+ // EMSCRIPTEN_END_FUNCS
+;
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "memory": Object.create(Object.prototype, {
+   "grow": {
+    
+   }, 
+   "buffer": {
+    "get": function () {
+     return buffer;
+    }
+    
+   }
+  })
+ };
+}
+
+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
+)
+
+}
diff --git a/binaryen/test/wasm2js/emscripten-grow-no.wast b/binaryen/test/wasm2js/emscripten-grow-no.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/emscripten-grow-no.wast
@@ -0,0 +1,7 @@
+(module
+ (type $0 (func))
+ (import "env" "memory" (memory $0 256 256))
+ (data (i32.const 1600) "abc")
+ (export "memory" (memory $0))
+)
+
diff --git a/binaryen/test/wasm2js/emscripten-grow-yes.2asm.js b/binaryen/test/wasm2js/emscripten-grow-yes.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/emscripten-grow-yes.2asm.js
@@ -0,0 +1,110 @@
+function instantiate(asmLibraryArg, wasmMemory) {
+function asmFunc(global, 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ // EMSCRIPTEN_START_FUNCS
+;
+ // EMSCRIPTEN_END_FUNCS
+;
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+   memory.buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "memory": Object.create(Object.prototype, {
+   "grow": {
+    "value": __wasm_memory_grow
+   }, 
+   "buffer": {
+    "get": function () {
+     return buffer;
+    }
+    
+   }
+  })
+ };
+}
+
+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
+)
+
+}
diff --git a/binaryen/test/wasm2js/emscripten-grow-yes.2asm.js.opt b/binaryen/test/wasm2js/emscripten-grow-yes.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/emscripten-grow-yes.2asm.js.opt
@@ -0,0 +1,110 @@
+function instantiate(asmLibraryArg, wasmMemory) {
+function asmFunc(global, 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ // EMSCRIPTEN_START_FUNCS
+;
+ // EMSCRIPTEN_END_FUNCS
+;
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+   memory.buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "memory": Object.create(Object.prototype, {
+   "grow": {
+    "value": __wasm_memory_grow
+   }, 
+   "buffer": {
+    "get": function () {
+     return buffer;
+    }
+    
+   }
+  })
+ };
+}
+
+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
+)
+
+}
diff --git a/binaryen/test/wasm2js/emscripten-grow-yes.wast b/binaryen/test/wasm2js/emscripten-grow-yes.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/emscripten-grow-yes.wast
@@ -0,0 +1,7 @@
+(module
+ (type $0 (func))
+ (import "env" "memory" (memory $0 256 1024))
+ (data (i32.const 1600) "abc")
+ (export "memory" (memory $0))
+)
+
diff --git a/binaryen/test/wasm2js/emscripten.2asm.js b/binaryen/test/wasm2js/emscripten.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/emscripten.2asm.js
@@ -0,0 +1,246 @@
+function instantiate(asmLibraryArg, wasmMemory) {
+function asmFunc(global, env) {
+ var memory = env.memory;
+ var buffer = memory.buffer;
+ 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var syscall$6 = env.__syscall6;
+ var syscall$54 = env.__syscall54;
+ // EMSCRIPTEN_START_FUNCS
+;
+ function main() {
+  syscall$6(1 | 0, 2 | 0) | 0;
+  syscall$54(3 | 0, 4 | 0) | 0;
+  FUNCTION_TABLE[HEAP32[(0 + 1030 | 0) >> 2] | 0 | 0]();
+  internal(1 | 0) | 0;
+  tabled(1 | 0) | 0;
+  exported(1 | 0) | 0;
+ }
+ 
+ function other() {
+  main();
+ }
+ 
+ function foo() {
+  abort();
+ }
+ 
+ function bar() {
+  HEAPU8[128 >> 0] | 0;
+  HEAP8[128 >> 0] | 0;
+  HEAPU16[128 >> 1] | 0;
+  HEAP16[128 >> 1] | 0;
+  HEAP32[16 >> 2] = 1 + 2 | 0;
+  HEAPF32[16 >> 2] = Math_fround(Math_fround(3.0) + Math_fround(4.0));
+  HEAPF64[16 >> 3] = 5.0 + 6.0;
+  HEAP8[16 >> 0] = 7 + 8 | 0;
+  HEAP16[16 >> 1] = 9 + 10 | 0;
+  if ((HEAP32[100 >> 2] | 0 | 0) == (1 | 0)) {
+   bar()
+  }
+  if ((HEAP32[104 >> 2] | 0 | 0) < (2 | 0)) {
+   bar()
+  }
+  if ((HEAP32[108 >> 2] | 0) >>> 0 < 3 >>> 0) {
+   bar()
+  }
+  if ((HEAP16[112 >> 1] | 0 | 0) == (1 | 0)) {
+   bar()
+  }
+  if ((HEAP16[116 >> 1] | 0 | 0) < (2 | 0)) {
+   bar()
+  }
+  if ((HEAPU16[120 >> 1] | 0 | 0) < (2 | 0)) {
+   bar()
+  }
+  if ((HEAP16[124 >> 1] | 0) >>> 0 < 3 >>> 0) {
+   bar()
+  }
+  if ((HEAPU16[128 >> 1] | 0) >>> 0 < 3 >>> 0) {
+   bar()
+  }
+  if ((HEAP8[132 >> 0] | 0 | 0) < (2 | 0)) {
+   bar()
+  }
+  if ((HEAPU8[136 >> 0] | 0 | 0) < (2 | 0)) {
+   bar()
+  }
+  if ((HEAP8[140 >> 0] | 0) >>> 0 < 3 >>> 0) {
+   bar()
+  }
+  if ((HEAPU8[144 >> 0] | 0) >>> 0 < 3 >>> 0) {
+   bar()
+  }
+  if ((bools(314159 | 0) | 0) >>> 7 | 0) {
+   bar()
+  }
+  if ((bools(314159 | 0) | 0) >> 8 | 0) {
+   bar()
+  }
+  if (~~Math_fround(getf32()) >>> 0) {
+   bar()
+  }
+  if (~~Math_fround(getf32())) {
+   bar()
+  }
+  if (~~+getf64() >>> 0) {
+   bar()
+  }
+  if (~~+getf64()) {
+   bar()
+  }
+  if (((geti32() | 0) + (geti32() | 0) | 0) + (geti32() | 0) | 0) {
+   bar()
+  }
+  if ((geti32() | 0) + ((geti32() | 0) + (geti32() | 0) | 0) | 0) {
+   bar()
+  }
+  if (((geti32() | 0) + (geti32() | 0) | 0) + ((geti32() | 0) + (geti32() | 0) | 0) | 0) {
+   bar()
+  }
+  if ((((geti32() | 0) + (geti32() | 0) | 0) + ((geti32() | 0) + (geti32() | 0) | 0) | 0) + (((geti32() | 0) + (geti32() | 0) | 0) + ((geti32() | 0) + (geti32() | 0) | 0) | 0) | 0) {
+   bar()
+  }
+ }
+ 
+ function geti32() {
+  return geti32() | 0 | 0;
+ }
+ 
+ function getf32() {
+  return Math_fround(Math_fround(getf32()));
+ }
+ 
+ function getf64() {
+  return +(+getf64());
+ }
+ 
+ function __growWasmMemory($0) {
+  $0 = $0 | 0;
+  return abort() | 0;
+ }
+ 
+ function internal(x) {
+  x = x | 0;
+  return x | 0;
+ }
+ 
+ function tabled(x) {
+  x = x | 0;
+  return x | 0;
+ }
+ 
+ function exported(x) {
+  x = x | 0;
+  return x | 0;
+ }
+ 
+ function sub_zero(x) {
+  x = x | 0;
+  return x - -5 | 0 | 0;
+ }
+ 
+ function select(x) {
+  x = x | 0;
+  var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0, wasm2js_i32$2 = 0;
+  return (wasm2js_i32$0 = x, wasm2js_i32$1 = HEAP32[16 >> 2] | 0, wasm2js_i32$2 = x, wasm2js_i32$2 ? wasm2js_i32$0 : wasm2js_i32$1) | 0;
+ }
+ 
+ function bools(x) {
+  x = x | 0;
+  bools((HEAPU8[0 >> 0] | 0) & 1 | 0 | 0) | 0;
+  bools((HEAP8[0 >> 0] | 0) & 1 | 0 | 0) | 0;
+  bools((HEAPU16[0 >> 1] | 0) & 1 | 0 | 0) | 0;
+  bools((HEAP16[0 >> 1] | 0) & 1 | 0 | 0) | 0;
+  bools((HEAP32[0 >> 2] | 0) & 1 | 0 | 0) | 0;
+  bools((HEAPU8[0 >> 0] | 0) & 2 | 0 | 0) | 0;
+  bools(x ^ 1 | 0 | 0) | 0;
+  if (x ^ 1 | 0) {
+   bools(2 | 0) | 0
+  }
+  if (x ^ 2 | 0) {
+   bools(2 | 0) | 0
+  }
+  bools(!(x ^ 1 | 0) | 0) | 0;
+  abort();
+ }
+ 
+ // EMSCRIPTEN_END_FUNCS
+;
+ FUNCTION_TABLE[1] = foo;
+ FUNCTION_TABLE[2] = bar;
+ FUNCTION_TABLE[3] = tabled;
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "main": main, 
+  "other": other, 
+  "__growWasmMemory": __growWasmMemory, 
+  "exported": exported, 
+  "sub_zero": sub_zero, 
+  "select": select, 
+  "bools": bools
+ };
+}
+
+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
+)
+
+}
diff --git a/binaryen/test/wasm2js/emscripten.2asm.js.opt b/binaryen/test/wasm2js/emscripten.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/emscripten.2asm.js.opt
@@ -0,0 +1,239 @@
+function instantiate(asmLibraryArg, wasmMemory) {
+function asmFunc(global, env) {
+ var memory = env.memory;
+ var buffer = memory.buffer;
+ 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var syscall$6 = env.__syscall6;
+ var syscall$54 = env.__syscall54;
+ // EMSCRIPTEN_START_FUNCS
+;
+ function main() {
+  syscall$6(1, 2) | 0;
+  syscall$54(3, 4) | 0;
+  FUNCTION_TABLE[HEAP32[257]]();
+ }
+ 
+ function other() {
+  main();
+ }
+ 
+ function foo() {
+  abort();
+ }
+ 
+ function bar() {
+  HEAP32[4] = 3;
+  HEAPF32[4] = 7;
+  HEAPF64[2] = 11;
+  HEAP8[16] = 15;
+  HEAP16[8] = 19;
+  if (HEAP32[25] == 1) {
+   bar()
+  }
+  if (HEAP32[26] < 2) {
+   bar()
+  }
+  if (HEAPU32[27] < 3) {
+   bar()
+  }
+  if (HEAP16[56] == 1) {
+   bar()
+  }
+  if (HEAP16[58] < 2) {
+   bar()
+  }
+  if (HEAPU16[60] < 2) {
+   bar()
+  }
+  if (HEAP16[62] >>> 0 < 3) {
+   bar()
+  }
+  if (HEAPU16[64] < 3) {
+   bar()
+  }
+  if (HEAP8[132] < 2) {
+   bar()
+  }
+  if (HEAPU8[136] < 2) {
+   bar()
+  }
+  if (HEAP8[140] >>> 0 < 3) {
+   bar()
+  }
+  if (HEAPU8[144] < 3) {
+   bar()
+  }
+  if (bools(314159) >>> 7 | 0) {
+   bar()
+  }
+  if (bools(314159) >> 8) {
+   bar()
+  }
+  if (~~getf32() >>> 0) {
+   bar()
+  }
+  if (~~getf32()) {
+   bar()
+  }
+  if (~~getf64() >>> 0) {
+   bar()
+  }
+  if (~~getf64()) {
+   bar()
+  }
+  if ((geti32() + geti32() | 0) + geti32() | 0) {
+   bar()
+  }
+  if (geti32() + (geti32() + geti32() | 0) | 0) {
+   bar()
+  }
+  if (geti32() + geti32() + (geti32() + geti32()) | 0) {
+   bar()
+  }
+  if (geti32() + geti32() + (geti32() + geti32()) + (geti32() + geti32() + (geti32() + geti32())) | 0) {
+   bar()
+  }
+ }
+ 
+ function geti32() {
+  return geti32();
+ }
+ 
+ function getf32() {
+  return getf32();
+ }
+ 
+ function getf64() {
+  return getf64();
+ }
+ 
+ function __growWasmMemory($0) {
+  $0 = $0 | 0;
+  return abort() | 0;
+ }
+ 
+ function internal($0) {
+  return $0;
+ }
+ 
+ function sub_zero($0) {
+  $0 = $0 | 0;
+  return $0 + 5 | 0;
+ }
+ 
+ function select($0) {
+  $0 = $0 | 0;
+  return ($0 ? $0 : HEAP32[4]) | 0;
+ }
+ 
+ function bools($0) {
+  $0 = $0 | 0;
+  bools(HEAP8[0] & 1);
+  bools(HEAP8[0] & 1);
+  bools(HEAP16[0] & 1);
+  bools(HEAP16[0] & 1);
+  bools(HEAP32[0] & 1);
+  bools(HEAPU8[0] & 2);
+  bools($0 ^ 1);
+  if ($0 ^ 1) {
+   bools(2)
+  }
+  if ($0 ^ 2) {
+   bools(2)
+  }
+  bools(!($0 ^ 1));
+  abort();
+ }
+ 
+ // EMSCRIPTEN_END_FUNCS
+;
+ FUNCTION_TABLE[1] = foo;
+ FUNCTION_TABLE[2] = bar;
+ FUNCTION_TABLE[3] = internal;
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "main": main, 
+  "other": other, 
+  "__growWasmMemory": __growWasmMemory, 
+  "exported": internal, 
+  "sub_zero": sub_zero, 
+  "select": select, 
+  "bools": bools
+ };
+}
+
+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
+)
+
+}
diff --git a/binaryen/test/wasm2js/emscripten.wast b/binaryen/test/wasm2js/emscripten.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/emscripten.wast
@@ -0,0 +1,243 @@
+(module
+ (type $0 (func))
+ (import "env" "memory" (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))
+ (elem (i32.const 1) $foo $bar $tabled)
+ (import "env" "__syscall6" (func $syscall$6 (param i32 i32) (result i32)))
+ (import "env" "__syscall54" (func $syscall$54 (param i32 i32) (result i32)))
+ (global $global$0 (mut i32) (i32.const 5243904))
+ (export "main" (func $main))
+ (export "other" (func $other))
+ (export "__growWasmMemory" (func $__growWasmMemory))
+ (export "exported" (func $exported))
+ (export "sub-zero" (func $sub-zero))
+ (export "select" (func $select))
+ (export "bools" (func $bools))
+ (func $main
+  (drop (call $syscall$6 (i32.const 1) (i32.const 2)))
+  (drop (call $syscall$54 (i32.const 3) (i32.const 4)))
+  (call_indirect (type $0)
+   (i32.load offset=1030
+    (i32.const 0)
+   )
+  )
+  (drop (call $internal (i32.const 1)))
+  (drop (call $tabled (i32.const 1)))
+  (drop (call $exported (i32.const 1)))
+ )
+ (func $other
+  (call $main)
+ )
+ (func $foo
+  (unreachable)
+ )
+ (func $bar
+  (drop
+   (i32.load8_u
+    (i32.const 128)
+   )
+  )
+  (drop
+   (i32.load8_s
+    (i32.const 128)
+   )
+  )
+  (drop
+   (i32.load16_u
+    (i32.const 128)
+   )
+  )
+  (drop
+   (i32.load16_s
+    (i32.const 128)
+   )
+  )
+  (i32.store
+   (i32.const 16)
+   (i32.add (i32.const 1) (i32.const 2))
+  )
+  (f32.store
+   (i32.const 16)
+   (f32.add (f32.const 3) (f32.const 4))
+  )
+  (f64.store
+   (i32.const 16)
+   (f64.add (f64.const 5) (f64.const 6))
+  )
+  (i32.store8
+   (i32.const 16)
+   (i32.add (i32.const 7) (i32.const 8))
+  )
+  (i32.store16
+   (i32.const 16)
+   (i32.add (i32.const 9) (i32.const 10))
+  )
+  (if (i32.eq (i32.load (i32.const 100)) (i32.const 1))
+   (call  $bar)
+  )
+  (if (i32.lt_s (i32.load (i32.const 104)) (i32.const 2))
+   (call  $bar)
+  )
+  (if (i32.lt_u (i32.load (i32.const 108)) (i32.const 3))
+   (call  $bar)
+  )
+  (if (i32.eq (i32.load16_s (i32.const 112)) (i32.const 1))
+   (call  $bar)
+  )
+  (if (i32.lt_s (i32.load16_s (i32.const 116)) (i32.const 2))
+   (call  $bar)
+  )
+  (if (i32.lt_s (i32.load16_u (i32.const 120)) (i32.const 2))
+   (call  $bar)
+  )
+  (if (i32.lt_u (i32.load16_s (i32.const 124)) (i32.const 3))
+   (call  $bar)
+  )
+  (if (i32.lt_u (i32.load16_u (i32.const 128)) (i32.const 3))
+   (call  $bar)
+  )
+  (if (i32.lt_s (i32.load8_s (i32.const 132)) (i32.const 2))
+   (call  $bar)
+  )
+  (if (i32.lt_s (i32.load8_u (i32.const 136)) (i32.const 2))
+   (call  $bar)
+  )
+  (if (i32.lt_u (i32.load8_s (i32.const 140)) (i32.const 3))
+   (call  $bar)
+  )
+  (if (i32.lt_u (i32.load8_u (i32.const 144)) (i32.const 3))
+   (call  $bar)
+  )
+  (if (i32.shr_u (call $bools (i32.const 314159)) (i32.const 7))
+   (call  $bar)
+  )
+  (if (i32.shr_s (call $bools (i32.const 314159)) (i32.const 8))
+   (call  $bar)
+  )
+  (if (i32.trunc_f32_u (call $getf32))
+   (call  $bar)
+  )
+  (if (i32.trunc_f32_s (call $getf32))
+   (call  $bar)
+  )
+  (if (i32.trunc_f64_u (call $getf64))
+   (call  $bar)
+  )
+  (if (i32.trunc_f64_s (call $getf64))
+   (call  $bar)
+  )
+  (if
+    (i32.add
+      (i32.add
+        (call $geti32)
+        (call $geti32)
+      )
+      (call $geti32)
+    )
+    (call $bar)
+  )
+  (if
+    (i32.add
+      (call $geti32)
+      (i32.add
+        (call $geti32)
+        (call $geti32)
+      )
+    )
+    (call $bar)
+  )
+  (if
+    (i32.add
+      (i32.add
+        (call $geti32)
+        (call $geti32)
+      )
+      (i32.add
+        (call $geti32)
+        (call $geti32)
+      )
+    )
+    (call $bar)
+  )
+  (if
+    (i32.add
+      (i32.add
+        (i32.add
+          (call $geti32)
+          (call $geti32)
+        )
+        (i32.add
+          (call $geti32)
+          (call $geti32)
+        )
+      )
+      (i32.add
+        (i32.add
+          (call $geti32)
+          (call $geti32)
+        )
+        (i32.add
+          (call $geti32)
+          (call $geti32)
+        )
+      )
+    )
+    (call $bar)
+  )
+ )
+ (func $geti32 (result i32)
+  (call $geti32)
+ )
+ (func $getf32 (result f32)
+  (call $getf32)
+ )
+ (func $getf64 (result f64)
+  (call $getf64)
+ )
+ (func $__growWasmMemory (param $0 i32) (result i32)
+  (memory.grow
+   (local.get $0)
+  )
+ )
+ (func $internal (param $x i32) (result i32)
+  (local.get $x)
+ )
+ (func $tabled (param $x i32) (result i32)
+  (local.get $x)
+ )
+ (func $exported (param $x i32) (result i32)
+  (local.get $x)
+ )
+ (func $sub-zero (param $x i32) (result i32)
+  (i32.sub (local.get $x) (i32.const -5))
+ )
+ (func $select (param $x i32) (result i32)
+  (select
+   (local.get $x)
+   (i32.load (i32.const 16)) ;; we can ignore this implicit trap, no side effects
+   (local.get $x)
+  )
+ )
+ (func $bools (param $x i32) (result i32)
+  (drop (call $bools (i32.and (i32.load8_u (i32.const 0)) (i32.const 1))))
+  (drop (call $bools (i32.and (i32.load8_s (i32.const 0)) (i32.const 1))))
+  (drop (call $bools (i32.and (i32.load16_u (i32.const 0)) (i32.const 1))))
+  (drop (call $bools (i32.and (i32.load16_s (i32.const 0)) (i32.const 1))))
+  (drop (call $bools (i32.and (i32.load (i32.const 0)) (i32.const 1))))
+  (drop (call $bools (i32.and (i32.load8_u (i32.const 0)) (i32.const 2))))
+  (drop (call $bools (i32.xor (local.get $x) (i32.const 1))))
+  (if
+    (i32.xor (local.get $x) (i32.const 1))
+    (drop (call $bools (i32.const 2)))
+  )
+  (if
+    (i32.xor (local.get $x) (i32.const 2))
+    (drop (call $bools (i32.const 2)))
+  )
+  (drop (call $bools (i32.eqz (i32.xor (local.get $x) (i32.const 1)))))
+  (unreachable)
+ )
+)
+
diff --git a/binaryen/test/wasm2js/endianness.2asm.js b/binaryen/test/wasm2js/endianness.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/endianness.2asm.js
@@ -0,0 +1,735 @@
+import { setTempRet0 } from 'env';
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_scratch_load_i32(index) {
+    return i32ScratchView[index];
+  }
+      
+  function wasm2js_scratch_store_i32(index, value) {
+    i32ScratchView[index] = value;
+  }
+      
+  function wasm2js_scratch_load_f64() {
+    return f64ScratchView[0];
+  }
+      
+  function wasm2js_scratch_store_f64(value) {
+    f64ScratchView[0] = value;
+  }
+      
+  function wasm2js_scratch_store_f32(value) {
+    f32ScratchView[2] = value;
+  }
+      
+  function wasm2js_scratch_load_f32() {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function i16_store_little(address, value) {
+  address = address | 0;
+  value = value | 0;
+  HEAP8[address >> 0] = value;
+  HEAP8[(address + 1 | 0) >> 0] = value >>> 8 | 0;
+ }
+ 
+ function i32_store_little(address, value) {
+  address = address | 0;
+  value = value | 0;
+  i16_store_little(address | 0, value | 0);
+  i16_store_little(address + 2 | 0 | 0, value >>> 16 | 0 | 0);
+ }
+ 
+ function i64_store_little(address, value, value$hi) {
+  address = address | 0;
+  value = value | 0;
+  value$hi = value$hi | 0;
+  var i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $9_1 = 0, $6_1 = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = value$hi;
+  i32_store_little(address | 0, value | 0);
+  $6_1 = address + 4 | 0;
+  i64toi32_i32$2 = value;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = 0;
+   $9_1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $9_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  i32_store_little($6_1 | 0, $9_1 | 0);
+ }
+ 
+ function i16_load_little(address) {
+  address = address | 0;
+  return HEAPU8[address >> 0] | 0 | ((HEAPU8[(address + 1 | 0) >> 0] | 0) << 8 | 0) | 0 | 0;
+ }
+ 
+ function i32_load_little(address) {
+  address = address | 0;
+  return i16_load_little(address | 0) | 0 | ((i16_load_little(address + 2 | 0 | 0) | 0) << 16 | 0) | 0 | 0;
+ }
+ 
+ function i64_load_little(address) {
+  address = address | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $9_1 = 0, $3 = 0, $3$hi = 0, $8$hi = 0;
+  i64toi32_i32$0 = 0;
+  $3 = i32_load_little(address | 0) | 0;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = i32_load_little(address + 4 | 0 | 0) | 0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $9_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $9_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$0 = $3;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $9_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$0 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$2;
+  return i64toi32_i32$0 | 0;
+ }
+ 
+ function $6(value) {
+  value = value | 0;
+  i16_store_little(0 | 0, value | 0);
+  return HEAP16[0 >> 1] | 0 | 0;
+ }
+ 
+ function $7(value) {
+  value = value | 0;
+  i16_store_little(0 | 0, value | 0);
+  return HEAPU16[0 >> 1] | 0 | 0;
+ }
+ 
+ function $8(value) {
+  value = value | 0;
+  i32_store_little(0 | 0, value | 0);
+  return HEAP32[0 >> 2] | 0 | 0;
+ }
+ 
+ function $9(value, value$hi) {
+  value = value | 0;
+  value$hi = value$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = value$hi;
+  i16_store_little(0 | 0, value | 0);
+  i64toi32_i32$0 = HEAP16[0 >> 1] | 0;
+  i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$0 | 0;
+ }
+ 
+ function $10(value, value$hi) {
+  value = value | 0;
+  value$hi = value$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = value$hi;
+  i16_store_little(0 | 0, value | 0);
+  i64toi32_i32$0 = HEAPU16[0 >> 1] | 0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$0 | 0;
+ }
+ 
+ function $11(value, value$hi) {
+  value = value | 0;
+  value$hi = value$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = value$hi;
+  i32_store_little(0 | 0, value | 0);
+  i64toi32_i32$0 = HEAP32[0 >> 2] | 0;
+  i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$0 | 0;
+ }
+ 
+ function $12(value, value$hi) {
+  value = value | 0;
+  value$hi = value$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = value$hi;
+  i32_store_little(0 | 0, value | 0);
+  i64toi32_i32$0 = HEAP32[0 >> 2] | 0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$0 | 0;
+ }
+ 
+ function $13(value, value$hi) {
+  value = value | 0;
+  value$hi = value$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = value$hi;
+  i64_store_little(0 | 0, value | 0, i64toi32_i32$0 | 0);
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = HEAP32[i64toi32_i32$2 >> 2] | 0;
+  i64toi32_i32$1 = HEAP32[(i64toi32_i32$2 + 4 | 0) >> 2] | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$0 | 0;
+ }
+ 
+ function $14(value) {
+  value = Math_fround(value);
+  i32_store_little(0 | 0, (wasm2js_scratch_store_f32(value), wasm2js_scratch_load_i32(2)) | 0);
+  return Math_fround(Math_fround(HEAPF32[0 >> 2]));
+ }
+ 
+ function $15(value) {
+  value = +value;
+  var i64toi32_i32$0 = 0;
+  wasm2js_scratch_store_f64(+value);
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64_store_little(0 | 0, wasm2js_scratch_load_i32(0 | 0) | 0 | 0, i64toi32_i32$0 | 0);
+  return +(+HEAPF64[0 >> 3]);
+ }
+ 
+ function $16(value) {
+  value = value | 0;
+  HEAP16[0 >> 1] = value;
+  return i16_load_little(0 | 0) | 0 | 0;
+ }
+ 
+ function $17(value) {
+  value = value | 0;
+  HEAP32[0 >> 2] = value;
+  return i32_load_little(0 | 0) | 0 | 0;
+ }
+ 
+ function $18(value, value$hi) {
+  value = value | 0;
+  value$hi = value$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = value$hi;
+  HEAP16[0 >> 1] = value;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$1 = i16_load_little(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $19(value, value$hi) {
+  value = value | 0;
+  value$hi = value$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = value$hi;
+  HEAP32[0 >> 2] = value;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$1 = i32_load_little(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $20(value, value$hi) {
+  value = value | 0;
+  value$hi = value$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = value$hi;
+  i64toi32_i32$1 = 0;
+  HEAP32[i64toi32_i32$1 >> 2] = value;
+  HEAP32[(i64toi32_i32$1 + 4 | 0) >> 2] = i64toi32_i32$0;
+  i64toi32_i32$0 = i64_load_little(0 | 0) | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$0 | 0;
+ }
+ 
+ function $21(value) {
+  value = Math_fround(value);
+  HEAPF32[0 >> 2] = value;
+  return Math_fround((wasm2js_scratch_store_i32(2, i32_load_little(0 | 0) | 0), wasm2js_scratch_load_f32()));
+ }
+ 
+ function $22(value) {
+  value = +value;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  HEAPF64[0 >> 3] = value;
+  i64toi32_i32$0 = i64_load_little(0 | 0) | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  wasm2js_scratch_store_i32(0 | 0, i64toi32_i32$0 | 0);
+  wasm2js_scratch_store_i32(1 | 0, i64toi32_i32$1 | 0);
+  return +(+wasm2js_scratch_load_f64());
+ }
+ 
+ function legalstub$9($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12_1 = 0, $13_1 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $9(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13_1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13_1 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2 | 0;
+ }
+ 
+ function legalstub$10($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12_1 = 0, $13_1 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $10(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13_1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13_1 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2 | 0;
+ }
+ 
+ function legalstub$11($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12_1 = 0, $13_1 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $11(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13_1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13_1 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2 | 0;
+ }
+ 
+ function legalstub$12($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12_1 = 0, $13_1 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $12(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13_1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13_1 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2 | 0;
+ }
+ 
+ function legalstub$13($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12_1 = 0, $13_1 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $13(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13_1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13_1 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2 | 0;
+ }
+ 
+ function legalstub$18($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12_1 = 0, $13_1 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $18(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13_1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13_1 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2 | 0;
+ }
+ 
+ function legalstub$19($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12_1 = 0, $13_1 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $19(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13_1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13_1 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2 | 0;
+ }
+ 
+ function legalstub$20($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12_1 = 0, $13_1 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $20(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13_1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13_1 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2 | 0;
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "i32_load16_s": $6, 
+  "i32_load16_u": $7, 
+  "i32_load": $8, 
+  "i64_load16_s": legalstub$9, 
+  "i64_load16_u": legalstub$10, 
+  "i64_load32_s": legalstub$11, 
+  "i64_load32_u": legalstub$12, 
+  "i64_load": legalstub$13, 
+  "f32_load": $14, 
+  "f64_load": $15, 
+  "i32_store16": $16, 
+  "i32_store": $17, 
+  "i64_store16": legalstub$18, 
+  "i64_store32": legalstub$19, 
+  "i64_store": legalstub$20, 
+  "f32_store": $21, 
+  "f64_store": $22
+ };
+}
+
+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'); },
+    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;
+export var i64_load16_s = retasmFunc.i64_load16_s;
+export var i64_load16_u = retasmFunc.i64_load16_u;
+export var i64_load32_s = retasmFunc.i64_load32_s;
+export var i64_load32_u = retasmFunc.i64_load32_u;
+export var i64_load = retasmFunc.i64_load;
+export var f32_load = retasmFunc.f32_load;
+export var f64_load = retasmFunc.f64_load;
+export var i32_store16 = retasmFunc.i32_store16;
+export var i32_store = retasmFunc.i32_store;
+export var i64_store16 = retasmFunc.i64_store16;
+export var i64_store32 = retasmFunc.i64_store32;
+export var i64_store = retasmFunc.i64_store;
+export var f32_store = retasmFunc.f32_store;
+export var f64_store = retasmFunc.f64_store;
diff --git a/binaryen/test/wasm2js/excess_fallthrough.2asm.js b/binaryen/test/wasm2js/excess_fallthrough.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/excess_fallthrough.2asm.js
@@ -0,0 +1,57 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function bar() {
+  
+ }
+ 
+ function foo($0) {
+  $0 = $0 | 0;
+  label$5 : {
+   bar();
+   block : {
+    switch (123 | 0) {
+    case 0:
+     bar();
+     break;
+    default:
+     break label$5;
+    };
+   }
+   return;
+  }
+  abort();
+ }
+ 
+ return {
+  "foo": foo
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/excess_fallthrough.2asm.js.opt
@@ -0,0 +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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function foo($0) {
+  $0 = $0 | 0;
+  abort();
+ }
+ 
+ return {
+  "foo": foo
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var foo = retasmFunc.foo;
diff --git a/binaryen/test/wasm2js/excess_fallthrough.wast b/binaryen/test/wasm2js/excess_fallthrough.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/excess_fallthrough.wast
@@ -0,0 +1,21 @@
+(module
+ (export "foo" (func $foo))
+ (func $bar)
+ (func $foo (param $0 i32)
+  (loop $label$4
+   (block $label$5
+    (call $bar)
+    (block
+     (block $label$7
+      (br_table $label$7 $label$5
+       (i32.const 123)
+      )
+     )
+     (call $bar)
+    )
+    (return)
+   )
+   (unreachable)
+  )
+ )
+)
diff --git a/binaryen/test/wasm2js/f32.2asm.js b/binaryen/test/wasm2js/f32.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/f32.2asm.js
@@ -0,0 +1,139 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return Math_fround(Math_fround(x + y));
+ }
+ 
+ function $1(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return Math_fround(Math_fround(x - y));
+ }
+ 
+ function $2(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return Math_fround(Math_fround(x * y));
+ }
+ 
+ function $3(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return Math_fround(Math_fround(x / y));
+ }
+ 
+ function $4(x) {
+  x = Math_fround(x);
+  return Math_fround(Math_fround(Math_sqrt(x)));
+ }
+ 
+ function $5(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return Math_fround(Math_fround(Math_min(x, y)));
+ }
+ 
+ function $6(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return Math_fround(Math_fround(Math_max(x, y)));
+ }
+ 
+ function $7(x) {
+  x = Math_fround(x);
+  return Math_fround(Math_fround(Math_ceil(x)));
+ }
+ 
+ function $8(x) {
+  x = Math_fround(x);
+  return Math_fround(Math_fround(Math_floor(x)));
+ }
+ 
+ function $9(x) {
+  x = Math_fround(x);
+  return Math_fround(Math_fround(__wasm_trunc_f32(Math_fround(x))));
+ }
+ 
+ function $10(x) {
+  x = Math_fround(x);
+  return Math_fround(Math_fround(__wasm_nearest_f32(Math_fround(x))));
+ }
+ 
+ function __wasm_nearest_f32(var$0) {
+  var$0 = Math_fround(var$0);
+  var var$1 = Math_fround(0), var$2 = Math_fround(0);
+  var$1 = Math_fround(Math_floor(var$0));
+  var$2 = Math_fround(var$0 - var$1);
+  if (!(var$2 < Math_fround(.5))) {
+   block : {
+    var$0 = Math_fround(Math_ceil(var$0));
+    if (var$2 > Math_fround(.5)) {
+     return Math_fround(var$0)
+    }
+    var$2 = Math_fround(var$1 * Math_fround(.5));
+    var$1 = Math_fround(var$2 - Math_fround(Math_floor(var$2))) == Math_fround(0.0) ? var$1 : var$0;
+   }
+  }
+  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, 
+  "mul": $2, 
+  "div": $3, 
+  "sqrt": $4, 
+  "min": $5, 
+  "max": $6, 
+  "ceil": $7, 
+  "floor": $8, 
+  "trunc": $9, 
+  "nearest": $10
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var add = retasmFunc.add;
+export var sub = retasmFunc.sub;
+export var mul = retasmFunc.mul;
+export var div = retasmFunc.div;
+export var sqrt = retasmFunc.sqrt;
+export var min = retasmFunc.min;
+export var max = retasmFunc.max;
+export var ceil = retasmFunc.ceil;
+export var floor = retasmFunc.floor;
+export var trunc = retasmFunc.trunc;
+export var nearest = retasmFunc.nearest;
diff --git a/binaryen/test/wasm2js/f32_cmp.2asm.js b/binaryen/test/wasm2js/f32_cmp.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/f32_cmp.2asm.js
@@ -0,0 +1,81 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return x == y | 0;
+ }
+ 
+ function $1(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return x != y | 0;
+ }
+ 
+ function $2(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return x < y | 0;
+ }
+ 
+ function $3(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return x <= y | 0;
+ }
+ 
+ function $4(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return x > y | 0;
+ }
+ 
+ function $5(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return x >= y | 0;
+ }
+ 
+ return {
+  "eq": $0, 
+  "ne": $1, 
+  "lt": $2, 
+  "le": $3, 
+  "gt": $4, 
+  "ge": $5
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var eq = retasmFunc.eq;
+export var ne = retasmFunc.ne;
+export var lt = retasmFunc.lt;
+export var le = retasmFunc.le;
+export var gt = retasmFunc.gt;
+export var ge = retasmFunc.ge;
diff --git a/binaryen/test/wasm2js/f64_cmp.2asm.js b/binaryen/test/wasm2js/f64_cmp.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/f64_cmp.2asm.js
@@ -0,0 +1,81 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0(x, y) {
+  x = +x;
+  y = +y;
+  return x == y | 0;
+ }
+ 
+ function $1(x, y) {
+  x = +x;
+  y = +y;
+  return x != y | 0;
+ }
+ 
+ function $2(x, y) {
+  x = +x;
+  y = +y;
+  return x < y | 0;
+ }
+ 
+ function $3(x, y) {
+  x = +x;
+  y = +y;
+  return x <= y | 0;
+ }
+ 
+ function $4(x, y) {
+  x = +x;
+  y = +y;
+  return x > y | 0;
+ }
+ 
+ function $5(x, y) {
+  x = +x;
+  y = +y;
+  return x >= y | 0;
+ }
+ 
+ return {
+  "eq": $0, 
+  "ne": $1, 
+  "lt": $2, 
+  "le": $3, 
+  "gt": $4, 
+  "ge": $5
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var eq = retasmFunc.eq;
+export var ne = retasmFunc.ne;
+export var lt = retasmFunc.lt;
+export var le = retasmFunc.le;
+export var gt = retasmFunc.gt;
+export var ge = retasmFunc.ge;
diff --git a/binaryen/test/wasm2js/fac.2asm.js b/binaryen/test/wasm2js/fac.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/fac.2asm.js
@@ -0,0 +1,596 @@
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0($0_1, $0$hi) {
+  $0_1 = $0_1 | 0;
+  $0$hi = $0$hi | 0;
+  var i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, $12 = 0, $12$hi = 0, $8 = 0, $8$hi = 0;
+  i64toi32_i32$2 = $0_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 0;
+  if ((i64toi32_i32$2 | 0) == (i64toi32_i32$3 | 0) & ($0$hi | 0) == (i64toi32_i32$1 | 0) | 0) {
+   i64toi32_i32$2 = 0;
+   $12 = 1;
+   $12$hi = i64toi32_i32$2;
+  } else {
+   i64toi32_i32$2 = $0$hi;
+   i64toi32_i32$3 = $0_1;
+   i64toi32_i32$1 = 1;
+   i64toi32_i32$5 = (i64toi32_i32$3 >>> 0 < i64toi32_i32$1 >>> 0) + 0 | 0;
+   i64toi32_i32$5 = $0$hi - i64toi32_i32$5 | 0;
+   i64toi32_i32$5 = $0(i64toi32_i32$3 - i64toi32_i32$1 | 0 | 0, i64toi32_i32$5 | 0) | 0;
+   i64toi32_i32$3 = i64toi32_i32$HIGH_BITS;
+   $8 = i64toi32_i32$5;
+   $8$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = $0$hi;
+   i64toi32_i32$5 = $8$hi;
+   i64toi32_i32$5 = __wasm_i64_mul($0_1 | 0, i64toi32_i32$3 | 0, $8 | 0, i64toi32_i32$5 | 0) | 0;
+   i64toi32_i32$3 = i64toi32_i32$HIGH_BITS;
+   $12 = i64toi32_i32$5;
+   $12$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = $12$hi;
+  i64toi32_i32$5 = $12;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function fac_rec_named(n, n$hi) {
+  n = n | 0;
+  n$hi = n$hi | 0;
+  var i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, $12 = 0, $12$hi = 0, $8 = 0, $8$hi = 0;
+  i64toi32_i32$2 = n;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 0;
+  if ((i64toi32_i32$2 | 0) == (i64toi32_i32$3 | 0) & (n$hi | 0) == (i64toi32_i32$1 | 0) | 0) {
+   i64toi32_i32$2 = 0;
+   $12 = 1;
+   $12$hi = i64toi32_i32$2;
+  } else {
+   i64toi32_i32$2 = n$hi;
+   i64toi32_i32$3 = n;
+   i64toi32_i32$1 = 1;
+   i64toi32_i32$5 = (i64toi32_i32$3 >>> 0 < i64toi32_i32$1 >>> 0) + 0 | 0;
+   i64toi32_i32$5 = n$hi - i64toi32_i32$5 | 0;
+   i64toi32_i32$5 = fac_rec_named(i64toi32_i32$3 - i64toi32_i32$1 | 0 | 0, i64toi32_i32$5 | 0) | 0;
+   i64toi32_i32$3 = i64toi32_i32$HIGH_BITS;
+   $8 = i64toi32_i32$5;
+   $8$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = n$hi;
+   i64toi32_i32$5 = $8$hi;
+   i64toi32_i32$5 = __wasm_i64_mul(n | 0, i64toi32_i32$3 | 0, $8 | 0, i64toi32_i32$5 | 0) | 0;
+   i64toi32_i32$3 = i64toi32_i32$HIGH_BITS;
+   $12 = i64toi32_i32$5;
+   $12$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = $12$hi;
+  i64toi32_i32$5 = $12;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function $2($0_1, $0$hi) {
+  $0_1 = $0_1 | 0;
+  $0$hi = $0$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, $1$hi = 0, i64toi32_i32$5 = 0, $1 = 0, $2$hi = 0, i64toi32_i32$1 = 0, $2_1 = 0;
+  i64toi32_i32$0 = $0$hi;
+  $1 = $0_1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  $2_1 = 1;
+  $2$hi = i64toi32_i32$0;
+  block : {
+   loop_in : while (1) {
+    i64toi32_i32$0 = $1$hi;
+    i64toi32_i32$2 = $1;
+    i64toi32_i32$1 = 0;
+    i64toi32_i32$3 = 0;
+    if ((i64toi32_i32$2 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$0 | 0) == (i64toi32_i32$1 | 0) | 0) {
+     break block
+    } else {
+     i64toi32_i32$2 = $1$hi;
+     i64toi32_i32$2 = $2$hi;
+     i64toi32_i32$2 = $1$hi;
+     i64toi32_i32$0 = $2$hi;
+     i64toi32_i32$0 = __wasm_i64_mul($1 | 0, i64toi32_i32$2 | 0, $2_1 | 0, i64toi32_i32$0 | 0) | 0;
+     i64toi32_i32$2 = i64toi32_i32$HIGH_BITS;
+     $2_1 = i64toi32_i32$0;
+     $2$hi = i64toi32_i32$2;
+     i64toi32_i32$2 = $1$hi;
+     i64toi32_i32$3 = $1;
+     i64toi32_i32$0 = 0;
+     i64toi32_i32$1 = 1;
+     i64toi32_i32$5 = (i64toi32_i32$3 >>> 0 < i64toi32_i32$1 >>> 0) + i64toi32_i32$0 | 0;
+     i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+     $1 = i64toi32_i32$3 - i64toi32_i32$1 | 0;
+     $1$hi = i64toi32_i32$5;
+    }
+    continue loop_in;
+   };
+  }
+  i64toi32_i32$5 = $2$hi;
+  i64toi32_i32$3 = $2_1;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+  return i64toi32_i32$3 | 0;
+ }
+ 
+ function $3(n, n$hi) {
+  n = n | 0;
+  n$hi = n$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i$hi = 0, i64toi32_i32$5 = 0, i = 0, res$hi = 0, i64toi32_i32$1 = 0, res = 0;
+  i64toi32_i32$0 = n$hi;
+  i = n;
+  i$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  res = 1;
+  res$hi = i64toi32_i32$0;
+  done : {
+   loop : while (1) {
+    i64toi32_i32$0 = i$hi;
+    i64toi32_i32$2 = i;
+    i64toi32_i32$1 = 0;
+    i64toi32_i32$3 = 0;
+    if ((i64toi32_i32$2 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$0 | 0) == (i64toi32_i32$1 | 0) | 0) {
+     break done
+    } else {
+     i64toi32_i32$2 = i$hi;
+     i64toi32_i32$2 = res$hi;
+     i64toi32_i32$2 = i$hi;
+     i64toi32_i32$0 = res$hi;
+     i64toi32_i32$0 = __wasm_i64_mul(i | 0, i64toi32_i32$2 | 0, res | 0, i64toi32_i32$0 | 0) | 0;
+     i64toi32_i32$2 = i64toi32_i32$HIGH_BITS;
+     res = i64toi32_i32$0;
+     res$hi = i64toi32_i32$2;
+     i64toi32_i32$2 = i$hi;
+     i64toi32_i32$3 = i;
+     i64toi32_i32$0 = 0;
+     i64toi32_i32$1 = 1;
+     i64toi32_i32$5 = (i64toi32_i32$3 >>> 0 < i64toi32_i32$1 >>> 0) + i64toi32_i32$0 | 0;
+     i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+     i = i64toi32_i32$3 - i64toi32_i32$1 | 0;
+     i$hi = i64toi32_i32$5;
+    }
+    continue loop;
+   };
+  }
+  i64toi32_i32$5 = res$hi;
+  i64toi32_i32$3 = res;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+  return i64toi32_i32$3 | 0;
+ }
+ 
+ function $4($0_1, $0$hi) {
+  $0_1 = $0_1 | 0;
+  $0$hi = $0$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$5 = 0, i64toi32_i32$3 = 0, $1$hi = 0, $1 = 0, $10 = 0, $11 = 0, $12 = 0, i64toi32_i32$4 = 0, $13 = 0, $14 = 0, $15 = 0;
+  i64toi32_i32$0 = 0;
+  $1 = 1;
+  $1$hi = i64toi32_i32$0;
+  block : {
+   i64toi32_i32$0 = $0$hi;
+   i64toi32_i32$2 = $0_1;
+   i64toi32_i32$1 = 0;
+   i64toi32_i32$3 = 2;
+   if ((i64toi32_i32$0 | 0) < (i64toi32_i32$1 | 0)) {
+    $10 = 1
+   } else {
+    if ((i64toi32_i32$0 | 0) <= (i64toi32_i32$1 | 0)) {
+     if (i64toi32_i32$2 >>> 0 >= i64toi32_i32$3 >>> 0) {
+      $11 = 0
+     } else {
+      $11 = 1
+     }
+     $12 = $11;
+    } else {
+     $12 = 0
+    }
+    $10 = $12;
+   }
+   if ($10) {
+    break block
+   }
+   loop_in : while (1) {
+    i64toi32_i32$2 = $1$hi;
+    i64toi32_i32$2 = $0$hi;
+    i64toi32_i32$2 = $1$hi;
+    i64toi32_i32$0 = $0$hi;
+    i64toi32_i32$0 = __wasm_i64_mul($1 | 0, i64toi32_i32$2 | 0, $0_1 | 0, i64toi32_i32$0 | 0) | 0;
+    i64toi32_i32$2 = i64toi32_i32$HIGH_BITS;
+    $1 = i64toi32_i32$0;
+    $1$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = $0$hi;
+    i64toi32_i32$3 = $0_1;
+    i64toi32_i32$0 = -1;
+    i64toi32_i32$1 = -1;
+    i64toi32_i32$4 = $0_1 + i64toi32_i32$1 | 0;
+    i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$0 | 0;
+    if (i64toi32_i32$4 >>> 0 < i64toi32_i32$1 >>> 0) {
+     i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+    }
+    $0_1 = i64toi32_i32$4;
+    $0$hi = i64toi32_i32$5;
+    i64toi32_i32$2 = $0_1;
+    i64toi32_i32$3 = 0;
+    i64toi32_i32$1 = 1;
+    if ((i64toi32_i32$5 | 0) > (i64toi32_i32$3 | 0)) {
+     $13 = 1
+    } else {
+     if ((i64toi32_i32$5 | 0) >= (i64toi32_i32$3 | 0)) {
+      if (i64toi32_i32$2 >>> 0 <= i64toi32_i32$1 >>> 0) {
+       $14 = 0
+      } else {
+       $14 = 1
+      }
+      $15 = $14;
+     } else {
+      $15 = 0
+     }
+     $13 = $15;
+    }
+    if ($13) {
+     continue loop_in
+    }
+    break loop_in;
+   };
+  }
+  i64toi32_i32$2 = $1$hi;
+  i64toi32_i32$5 = $1;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$2;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function legalstub$0($0_1, $1) {
+  $0_1 = $0_1 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4_1 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4_1 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4_1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $0(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$fac_rec_named($0_1, $1) {
+  $0_1 = $0_1 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4_1 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4_1 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4_1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = fac_rec_named(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1) {
+  $0_1 = $0_1 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4_1 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4_1 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4_1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1) {
+  $0_1 = $0_1 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4_1 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4_1 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4_1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $3(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$4($0_1, $1) {
+  $0_1 = $0_1 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4_1 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4_1 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4_1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $4(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, var$2 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, var$3 = 0, var$4 = 0, var$5 = 0, $21 = 0, $22 = 0, var$6 = 0, $24 = 0, $17 = 0, $18 = 0, $23 = 0, $29 = 0, $45 = 0, $56$hi = 0, $62$hi = 0;
+  i64toi32_i32$0 = var$1$hi;
+  var$2 = var$1;
+  var$4 = var$2 >>> 16 | 0;
+  i64toi32_i32$0 = var$0$hi;
+  var$3 = var$0;
+  var$5 = var$3 >>> 16 | 0;
+  $17 = Math_imul(var$4, var$5);
+  $18 = var$2;
+  i64toi32_i32$2 = var$3;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = 0;
+   $21 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  $23 = $17 + Math_imul($18, $21) | 0;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$0 = var$1;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $22 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $22 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  $29 = $23 + Math_imul($22, var$3) | 0;
+  var$2 = var$2 & 65535 | 0;
+  var$3 = var$3 & 65535 | 0;
+  var$6 = Math_imul(var$2, var$3);
+  var$2 = (var$6 >>> 16 | 0) + Math_imul(var$2, var$5) | 0;
+  $45 = $29 + (var$2 >>> 16 | 0) | 0;
+  var$2 = (var$2 & 65535 | 0) + Math_imul(var$4, var$3) | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $45 + (var$2 >>> 16 | 0) | 0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $24 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $24 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $56$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  $62$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $56$hi;
+  i64toi32_i32$2 = $24;
+  i64toi32_i32$1 = $62$hi;
+  i64toi32_i32$3 = var$2 << 16 | 0 | (var$6 & 65535 | 0) | 0;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  i64toi32_i32$2 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function __wasm_i64_mul(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ return {
+  "fac_rec": legalstub$0, 
+  "fac_rec_named": legalstub$fac_rec_named, 
+  "fac_iter": legalstub$2, 
+  "fac_iter_named": legalstub$3, 
+  "fac_opt": legalstub$4
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var fac_rec = retasmFunc.fac_rec;
+export var fac_rec_named = retasmFunc.fac_rec_named;
+export var fac_iter = retasmFunc.fac_iter;
+export var fac_iter_named = retasmFunc.fac_iter_named;
+export var fac_opt = retasmFunc.fac_opt;
diff --git a/binaryen/test/wasm2js/float-ops.2asm.js b/binaryen/test/wasm2js/float-ops.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/float-ops.2asm.js
@@ -0,0 +1,569 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $1($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return Math_fround(Math_fround($0 + $1_1));
+ }
+ 
+ function $2($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return Math_fround(Math_fround($0 - $1_1));
+ }
+ 
+ function $3($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return Math_fround(Math_fround($0 * $1_1));
+ }
+ 
+ function $4($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return Math_fround(Math_fround($0 / $1_1));
+ }
+ 
+ function $5($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return +($0 + $1_1);
+ }
+ 
+ function $6($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return +($0 - $1_1);
+ }
+ 
+ function $7($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return +($0 * $1_1);
+ }
+ 
+ function $8($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return +($0 / $1_1);
+ }
+ 
+ function $9($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return $0 == $1_1 | 0;
+ }
+ 
+ function $10($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return $0 != $1_1 | 0;
+ }
+ 
+ function $11($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return $0 >= $1_1 | 0;
+ }
+ 
+ function $12($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return $0 > $1_1 | 0;
+ }
+ 
+ function $13($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return $0 <= $1_1 | 0;
+ }
+ 
+ function $14($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return $0 < $1_1 | 0;
+ }
+ 
+ function $15($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return $0 == $1_1 | 0;
+ }
+ 
+ function $16($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return $0 != $1_1 | 0;
+ }
+ 
+ function $17($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return $0 >= $1_1 | 0;
+ }
+ 
+ function $18($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return $0 > $1_1 | 0;
+ }
+ 
+ function $19($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return $0 <= $1_1 | 0;
+ }
+ 
+ function $20($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return $0 < $1_1 | 0;
+ }
+ 
+ function $21($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return Math_fround(Math_fround(Math_min($0, $1_1)));
+ }
+ 
+ function $22($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return Math_fround(Math_fround(Math_max($0, $1_1)));
+ }
+ 
+ function $23($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return +Math_min($0, $1_1);
+ }
+ 
+ function $24($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return +Math_max($0, $1_1);
+ }
+ 
+ function $25($0) {
+  $0 = Math_fround($0);
+  return +(+$0);
+ }
+ 
+ function $26($0) {
+  $0 = +$0;
+  return Math_fround(Math_fround($0));
+ }
+ 
+ function $27($0) {
+  $0 = Math_fround($0);
+  return Math_fround(Math_fround(Math_floor($0)));
+ }
+ 
+ function $28($0) {
+  $0 = Math_fround($0);
+  return Math_fround(Math_fround(Math_ceil($0)));
+ }
+ 
+ function $29($0) {
+  $0 = +$0;
+  return +Math_floor($0);
+ }
+ 
+ function $30($0) {
+  $0 = +$0;
+  return +Math_ceil($0);
+ }
+ 
+ function $31($0) {
+  $0 = Math_fround($0);
+  return Math_fround(Math_fround(Math_sqrt($0)));
+ }
+ 
+ function $32($0) {
+  $0 = +$0;
+  return +Math_sqrt($0);
+ }
+ 
+ function $35($0) {
+  $0 = $0 | 0;
+  return Math_fround(Math_fround($0 | 0));
+ }
+ 
+ function $36($0) {
+  $0 = $0 | 0;
+  return +(+($0 | 0));
+ }
+ 
+ function $37($0) {
+  $0 = $0 | 0;
+  return Math_fround(Math_fround($0 >>> 0));
+ }
+ 
+ function $38($0) {
+  $0 = $0 | 0;
+  return +(+($0 >>> 0));
+ }
+ 
+ function $39($0) {
+  $0 = Math_fround($0);
+  return ~~$0 | 0;
+ }
+ 
+ function $40($0) {
+  $0 = +$0;
+  return ~~$0 | 0;
+ }
+ 
+ function $41($0) {
+  $0 = Math_fround($0);
+  return ~~$0 >>> 0 | 0;
+ }
+ 
+ function $42($0) {
+  $0 = +$0;
+  return ~~$0 >>> 0 | 0;
+ }
+ 
+ function $43($0, $0$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = $0$hi;
+  return Math_fround(Math_fround(+($0 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 | 0)));
+ }
+ 
+ function $44($0, $0$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = $0$hi;
+  return +(+($0 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 | 0));
+ }
+ 
+ function $45($0, $0$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = $0$hi;
+  return Math_fround(Math_fround(+($0 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0)));
+ }
+ 
+ function $46($0, $0$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = $0$hi;
+  return +(+($0 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0));
+ }
+ 
+ function $47($0) {
+  $0 = Math_fround($0);
+  var i64toi32_i32$0 = Math_fround(0), $3_1 = 0, $4_1 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = $0;
+  if (Math_fround(Math_abs(i64toi32_i32$0)) >= Math_fround(1.0)) {
+   if (i64toi32_i32$0 > Math_fround(0.0)) {
+    $3_1 = ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround(i64toi32_i32$0 / Math_fround(4294967296.0)))), Math_fround(Math_fround(4294967296.0) - Math_fround(1.0)))) >>> 0
+   } else {
+    $3_1 = ~~Math_fround(Math_ceil(Math_fround(Math_fround(i64toi32_i32$0 - Math_fround(~~i64toi32_i32$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0
+   }
+   $4_1 = $3_1;
+  } else {
+   $4_1 = 0
+  }
+  i64toi32_i32$1 = $4_1;
+  return (~~i64toi32_i32$0 >>> 0 | 0) == (0 | 0) & (i64toi32_i32$1 | 0) == (0 | 0) | 0 | 0;
+ }
+ 
+ function $48($0) {
+  $0 = +$0;
+  var i64toi32_i32$0 = 0.0, $3_1 = 0, $4_1 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = $0;
+  if (Math_abs(i64toi32_i32$0) >= 1.0) {
+   if (i64toi32_i32$0 > 0.0) {
+    $3_1 = ~~Math_min(Math_floor(i64toi32_i32$0 / 4294967296.0), 4294967296.0 - 1.0) >>> 0
+   } else {
+    $3_1 = ~~Math_ceil((i64toi32_i32$0 - +(~~i64toi32_i32$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0
+   }
+   $4_1 = $3_1;
+  } else {
+   $4_1 = 0
+  }
+  i64toi32_i32$1 = $4_1;
+  return (~~i64toi32_i32$0 >>> 0 | 0) == (0 | 0) & (i64toi32_i32$1 | 0) == (0 | 0) | 0 | 0;
+ }
+ 
+ function $49($0) {
+  $0 = Math_fround($0);
+  var i64toi32_i32$0 = Math_fround(0), $3_1 = 0, $4_1 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = $0;
+  if (Math_fround(Math_abs(i64toi32_i32$0)) >= Math_fround(1.0)) {
+   if (i64toi32_i32$0 > Math_fround(0.0)) {
+    $3_1 = ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround(i64toi32_i32$0 / Math_fround(4294967296.0)))), Math_fround(Math_fround(4294967296.0) - Math_fround(1.0)))) >>> 0
+   } else {
+    $3_1 = ~~Math_fround(Math_ceil(Math_fround(Math_fround(i64toi32_i32$0 - Math_fround(~~i64toi32_i32$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0
+   }
+   $4_1 = $3_1;
+  } else {
+   $4_1 = 0
+  }
+  i64toi32_i32$1 = $4_1;
+  return (~~i64toi32_i32$0 >>> 0 | 0) == (0 | 0) & (i64toi32_i32$1 | 0) == (0 | 0) | 0 | 0;
+ }
+ 
+ function $50($0) {
+  $0 = +$0;
+  var i64toi32_i32$0 = 0.0, $3_1 = 0, $4_1 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = $0;
+  if (Math_abs(i64toi32_i32$0) >= 1.0) {
+   if (i64toi32_i32$0 > 0.0) {
+    $3_1 = ~~Math_min(Math_floor(i64toi32_i32$0 / 4294967296.0), 4294967296.0 - 1.0) >>> 0
+   } else {
+    $3_1 = ~~Math_ceil((i64toi32_i32$0 - +(~~i64toi32_i32$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0
+   }
+   $4_1 = $3_1;
+  } else {
+   $4_1 = 0
+  }
+  i64toi32_i32$1 = $4_1;
+  return (~~i64toi32_i32$0 >>> 0 | 0) == (0 | 0) & (i64toi32_i32$1 | 0) == (0 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$43($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $10_1 = 0, $3_1 = 0, $3$hi = 0, $6$hi = 0;
+  i64toi32_i32$0 = 0;
+  $3_1 = $0;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $10_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $10_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $6$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$0 = $3_1;
+  i64toi32_i32$2 = $6$hi;
+  i64toi32_i32$3 = $10_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return Math_fround(Math_fround($43(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0)));
+ }
+ 
+ function legalstub$44($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $10_1 = 0, $3_1 = 0, $3$hi = 0, $6$hi = 0;
+  i64toi32_i32$0 = 0;
+  $3_1 = $0;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $10_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $10_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $6$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$0 = $3_1;
+  i64toi32_i32$2 = $6$hi;
+  i64toi32_i32$3 = $10_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return +(+$44(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0));
+ }
+ 
+ function legalstub$45($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $10_1 = 0, $3_1 = 0, $3$hi = 0, $6$hi = 0;
+  i64toi32_i32$0 = 0;
+  $3_1 = $0;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $10_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $10_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $6$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$0 = $3_1;
+  i64toi32_i32$2 = $6$hi;
+  i64toi32_i32$3 = $10_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return Math_fround(Math_fround($45(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0)));
+ }
+ 
+ function legalstub$46($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $10_1 = 0, $3_1 = 0, $3$hi = 0, $6$hi = 0;
+  i64toi32_i32$0 = 0;
+  $3_1 = $0;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $10_1 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $10_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $6$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$0 = $3_1;
+  i64toi32_i32$2 = $6$hi;
+  i64toi32_i32$3 = $10_1;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return +(+$46(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0));
+ }
+ 
+ return {
+  "f32_add": $1, 
+  "f32_sub": $2, 
+  "f32_mul": $3, 
+  "f32_div": $4, 
+  "f64_add": $5, 
+  "f64_sub": $6, 
+  "f64_mul": $7, 
+  "f64_div": $8, 
+  "f32_eq": $9, 
+  "f32_ne": $10, 
+  "f32_ge": $11, 
+  "f32_gt": $12, 
+  "f32_le": $13, 
+  "f32_lt": $14, 
+  "f64_eq": $15, 
+  "f64_ne": $16, 
+  "f64_ge": $17, 
+  "f64_gt": $18, 
+  "f64_le": $19, 
+  "f64_lt": $20, 
+  "f32_min": $21, 
+  "f32_max": $22, 
+  "f64_min": $23, 
+  "f64_max": $24, 
+  "f64_promote": $25, 
+  "f32_demote": $26, 
+  "f32_floor": $27, 
+  "f32_ceil": $28, 
+  "f64_floor": $29, 
+  "f64_ceil": $30, 
+  "f32_sqrt": $31, 
+  "f64_sqrt": $32, 
+  "i32_to_f32": $35, 
+  "i32_to_f64": $36, 
+  "u32_to_f32": $37, 
+  "u32_to_f64": $38, 
+  "f32_to_i32": $39, 
+  "f64_to_i32": $40, 
+  "f32_to_u32": $41, 
+  "f64_to_u32": $42, 
+  "i64_to_f32": legalstub$43, 
+  "i64_to_f64": legalstub$44, 
+  "u64_to_f32": legalstub$45, 
+  "u64_to_f64": legalstub$46, 
+  "f32_to_i64": $47, 
+  "f64_to_i64": $48, 
+  "f32_to_u64": $49, 
+  "f64_to_u64": $50
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var f32_add = retasmFunc.f32_add;
+export var f32_sub = retasmFunc.f32_sub;
+export var f32_mul = retasmFunc.f32_mul;
+export var f32_div = retasmFunc.f32_div;
+export var f64_add = retasmFunc.f64_add;
+export var f64_sub = retasmFunc.f64_sub;
+export var f64_mul = retasmFunc.f64_mul;
+export var f64_div = retasmFunc.f64_div;
+export var f32_eq = retasmFunc.f32_eq;
+export var f32_ne = retasmFunc.f32_ne;
+export var f32_ge = retasmFunc.f32_ge;
+export var f32_gt = retasmFunc.f32_gt;
+export var f32_le = retasmFunc.f32_le;
+export var f32_lt = retasmFunc.f32_lt;
+export var f64_eq = retasmFunc.f64_eq;
+export var f64_ne = retasmFunc.f64_ne;
+export var f64_ge = retasmFunc.f64_ge;
+export var f64_gt = retasmFunc.f64_gt;
+export var f64_le = retasmFunc.f64_le;
+export var f64_lt = retasmFunc.f64_lt;
+export var f32_min = retasmFunc.f32_min;
+export var f32_max = retasmFunc.f32_max;
+export var f64_min = retasmFunc.f64_min;
+export var f64_max = retasmFunc.f64_max;
+export var f64_promote = retasmFunc.f64_promote;
+export var f32_demote = retasmFunc.f32_demote;
+export var f32_floor = retasmFunc.f32_floor;
+export var f32_ceil = retasmFunc.f32_ceil;
+export var f64_floor = retasmFunc.f64_floor;
+export var f64_ceil = retasmFunc.f64_ceil;
+export var f32_sqrt = retasmFunc.f32_sqrt;
+export var f64_sqrt = retasmFunc.f64_sqrt;
+export var i32_to_f32 = retasmFunc.i32_to_f32;
+export var i32_to_f64 = retasmFunc.i32_to_f64;
+export var u32_to_f32 = retasmFunc.u32_to_f32;
+export var u32_to_f64 = retasmFunc.u32_to_f64;
+export var f32_to_i32 = retasmFunc.f32_to_i32;
+export var f64_to_i32 = retasmFunc.f64_to_i32;
+export var f32_to_u32 = retasmFunc.f32_to_u32;
+export var f64_to_u32 = retasmFunc.f64_to_u32;
+export var i64_to_f32 = retasmFunc.i64_to_f32;
+export var i64_to_f64 = retasmFunc.i64_to_f64;
+export var u64_to_f32 = retasmFunc.u64_to_f32;
+export var u64_to_f64 = retasmFunc.u64_to_f64;
+export var f32_to_i64 = retasmFunc.f32_to_i64;
+export var f64_to_i64 = retasmFunc.f64_to_i64;
+export var f32_to_u64 = retasmFunc.f32_to_u64;
+export var f64_to_u64 = retasmFunc.f64_to_u64;
diff --git a/binaryen/test/wasm2js/float-ops.2asm.js.opt b/binaryen/test/wasm2js/float-ops.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/float-ops.2asm.js.opt
@@ -0,0 +1,379 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $1($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return Math_fround(Math_fround($0 + $1_1));
+ }
+ 
+ function $2($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return Math_fround(Math_fround($0 - $1_1));
+ }
+ 
+ function $3($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return Math_fround(Math_fround($0 * $1_1));
+ }
+ 
+ function $4($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return Math_fround(Math_fround($0 / $1_1));
+ }
+ 
+ function $5($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return +($0 + $1_1);
+ }
+ 
+ function $6($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return +($0 - $1_1);
+ }
+ 
+ function $7($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return +($0 * $1_1);
+ }
+ 
+ function $8($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return +($0 / $1_1);
+ }
+ 
+ function $9($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return $0 == $1_1 | 0;
+ }
+ 
+ function $10($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return $0 != $1_1 | 0;
+ }
+ 
+ function $11($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return $0 >= $1_1 | 0;
+ }
+ 
+ function $12($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return $0 > $1_1 | 0;
+ }
+ 
+ function $13($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return $0 <= $1_1 | 0;
+ }
+ 
+ function $14($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return $0 < $1_1 | 0;
+ }
+ 
+ function $15($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return $0 == $1_1 | 0;
+ }
+ 
+ function $16($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return $0 != $1_1 | 0;
+ }
+ 
+ function $17($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return $0 >= $1_1 | 0;
+ }
+ 
+ function $18($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return $0 > $1_1 | 0;
+ }
+ 
+ function $19($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return $0 <= $1_1 | 0;
+ }
+ 
+ function $20($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return $0 < $1_1 | 0;
+ }
+ 
+ function $21($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return Math_fround(Math_fround(Math_min($0, $1_1)));
+ }
+ 
+ function $22($0, $1_1) {
+  $0 = Math_fround($0);
+  $1_1 = Math_fround($1_1);
+  return Math_fround(Math_fround(Math_max($0, $1_1)));
+ }
+ 
+ function $23($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return +Math_min($0, $1_1);
+ }
+ 
+ function $24($0, $1_1) {
+  $0 = +$0;
+  $1_1 = +$1_1;
+  return +Math_max($0, $1_1);
+ }
+ 
+ function $25($0) {
+  $0 = Math_fround($0);
+  return +$0;
+ }
+ 
+ function $26($0) {
+  $0 = +$0;
+  return Math_fround(Math_fround($0));
+ }
+ 
+ function $27($0) {
+  $0 = Math_fround($0);
+  return Math_fround(Math_fround(Math_floor($0)));
+ }
+ 
+ function $28($0) {
+  $0 = Math_fround($0);
+  return Math_fround(Math_fround(Math_ceil($0)));
+ }
+ 
+ function $29($0) {
+  $0 = +$0;
+  return +Math_floor($0);
+ }
+ 
+ function $30($0) {
+  $0 = +$0;
+  return +Math_ceil($0);
+ }
+ 
+ function $31($0) {
+  $0 = Math_fround($0);
+  return Math_fround(Math_fround(Math_sqrt($0)));
+ }
+ 
+ function $32($0) {
+  $0 = +$0;
+  return +Math_sqrt($0);
+ }
+ 
+ function $35($0) {
+  $0 = $0 | 0;
+  return Math_fround(Math_fround($0 | 0));
+ }
+ 
+ function $36($0) {
+  $0 = $0 | 0;
+  return +($0 | 0);
+ }
+ 
+ function $37($0) {
+  $0 = $0 | 0;
+  return Math_fround(Math_fround($0 >>> 0));
+ }
+ 
+ function $38($0) {
+  $0 = $0 | 0;
+  return +($0 >>> 0);
+ }
+ 
+ function $39($0) {
+  $0 = Math_fround($0);
+  return ~~$0 | 0;
+ }
+ 
+ function $40($0) {
+  $0 = +$0;
+  return ~~$0 | 0;
+ }
+ 
+ function $41($0) {
+  $0 = Math_fround($0);
+  return ~~$0 >>> 0 | 0;
+ }
+ 
+ function $42($0) {
+  $0 = +$0;
+  return ~~$0 >>> 0 | 0;
+ }
+ 
+ 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;
+ }
+ 
+ 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;
+ }
+ 
+ function legalstub$43($0, $1_1) {
+  return Math_fround(+($0 >>> 0) + +($1_1 | 0) * 4294967296.0);
+ }
+ 
+ function legalstub$44($0, $1_1) {
+  return +($0 >>> 0) + +($1_1 | 0) * 4294967296.0;
+ }
+ 
+ function legalstub$45($0, $1_1) {
+  return Math_fround(+($0 >>> 0) + +($1_1 >>> 0) * 4294967296.0);
+ }
+ 
+ function legalstub$46($0, $1_1) {
+  return +($0 >>> 0) + +($1_1 >>> 0) * 4294967296.0;
+ }
+ 
+ return {
+  "f32_add": $1, 
+  "f32_sub": $2, 
+  "f32_mul": $3, 
+  "f32_div": $4, 
+  "f64_add": $5, 
+  "f64_sub": $6, 
+  "f64_mul": $7, 
+  "f64_div": $8, 
+  "f32_eq": $9, 
+  "f32_ne": $10, 
+  "f32_ge": $11, 
+  "f32_gt": $12, 
+  "f32_le": $13, 
+  "f32_lt": $14, 
+  "f64_eq": $15, 
+  "f64_ne": $16, 
+  "f64_ge": $17, 
+  "f64_gt": $18, 
+  "f64_le": $19, 
+  "f64_lt": $20, 
+  "f32_min": $21, 
+  "f32_max": $22, 
+  "f64_min": $23, 
+  "f64_max": $24, 
+  "f64_promote": $25, 
+  "f32_demote": $26, 
+  "f32_floor": $27, 
+  "f32_ceil": $28, 
+  "f64_floor": $29, 
+  "f64_ceil": $30, 
+  "f32_sqrt": $31, 
+  "f64_sqrt": $32, 
+  "i32_to_f32": $35, 
+  "i32_to_f64": $36, 
+  "u32_to_f32": $37, 
+  "u32_to_f64": $38, 
+  "f32_to_i32": $39, 
+  "f64_to_i32": $40, 
+  "f32_to_u32": $41, 
+  "f64_to_u32": $42, 
+  "i64_to_f32": legalstub$43, 
+  "i64_to_f64": legalstub$44, 
+  "u64_to_f32": legalstub$45, 
+  "u64_to_f64": legalstub$46, 
+  "f32_to_i64": $47, 
+  "f64_to_i64": $48, 
+  "f32_to_u64": $47, 
+  "f64_to_u64": $48
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var f32_add = retasmFunc.f32_add;
+export var f32_sub = retasmFunc.f32_sub;
+export var f32_mul = retasmFunc.f32_mul;
+export var f32_div = retasmFunc.f32_div;
+export var f64_add = retasmFunc.f64_add;
+export var f64_sub = retasmFunc.f64_sub;
+export var f64_mul = retasmFunc.f64_mul;
+export var f64_div = retasmFunc.f64_div;
+export var f32_eq = retasmFunc.f32_eq;
+export var f32_ne = retasmFunc.f32_ne;
+export var f32_ge = retasmFunc.f32_ge;
+export var f32_gt = retasmFunc.f32_gt;
+export var f32_le = retasmFunc.f32_le;
+export var f32_lt = retasmFunc.f32_lt;
+export var f64_eq = retasmFunc.f64_eq;
+export var f64_ne = retasmFunc.f64_ne;
+export var f64_ge = retasmFunc.f64_ge;
+export var f64_gt = retasmFunc.f64_gt;
+export var f64_le = retasmFunc.f64_le;
+export var f64_lt = retasmFunc.f64_lt;
+export var f32_min = retasmFunc.f32_min;
+export var f32_max = retasmFunc.f32_max;
+export var f64_min = retasmFunc.f64_min;
+export var f64_max = retasmFunc.f64_max;
+export var f64_promote = retasmFunc.f64_promote;
+export var f32_demote = retasmFunc.f32_demote;
+export var f32_floor = retasmFunc.f32_floor;
+export var f32_ceil = retasmFunc.f32_ceil;
+export var f64_floor = retasmFunc.f64_floor;
+export var f64_ceil = retasmFunc.f64_ceil;
+export var f32_sqrt = retasmFunc.f32_sqrt;
+export var f64_sqrt = retasmFunc.f64_sqrt;
+export var i32_to_f32 = retasmFunc.i32_to_f32;
+export var i32_to_f64 = retasmFunc.i32_to_f64;
+export var u32_to_f32 = retasmFunc.u32_to_f32;
+export var u32_to_f64 = retasmFunc.u32_to_f64;
+export var f32_to_i32 = retasmFunc.f32_to_i32;
+export var f64_to_i32 = retasmFunc.f64_to_i32;
+export var f32_to_u32 = retasmFunc.f32_to_u32;
+export var f64_to_u32 = retasmFunc.f64_to_u32;
+export var i64_to_f32 = retasmFunc.i64_to_f32;
+export var i64_to_f64 = retasmFunc.i64_to_f64;
+export var u64_to_f32 = retasmFunc.u64_to_f32;
+export var u64_to_f64 = retasmFunc.u64_to_f64;
+export var f32_to_i64 = retasmFunc.f32_to_i64;
+export var f64_to_i64 = retasmFunc.f64_to_i64;
+export var f32_to_u64 = retasmFunc.f32_to_u64;
+export var f64_to_u64 = retasmFunc.f64_to_u64;
diff --git a/binaryen/test/wasm2js/float-ops.wast b/binaryen/test/wasm2js/float-ops.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/float-ops.wast
@@ -0,0 +1,147 @@
+(module
+  (func $dummy)
+
+  (func (export "f32.add") (param $0 f32) (param $1 f32) (result f32)
+    (f32.add (local.get $0) (local.get $1)))
+
+  (func (export "f32.sub") (param $0 f32) (param $1 f32) (result f32)
+    (f32.sub (local.get $0) (local.get $1)))
+
+  (func (export "f32.mul") (param $0 f32) (param $1 f32) (result f32)
+    (f32.mul (local.get $0) (local.get $1)))
+
+  (func (export "f32.div") (param $0 f32) (param $1 f32) (result f32)
+    (f32.div (local.get $0) (local.get $1)))
+
+  (func (export "f64.add") (param $0 f64) (param $1 f64) (result f64)
+    (f64.add (local.get $0) (local.get $1)))
+
+  (func (export "f64.sub") (param $0 f64) (param $1 f64) (result f64)
+    (f64.sub (local.get $0) (local.get $1)))
+
+  (func (export "f64.mul") (param $0 f64) (param $1 f64) (result f64)
+    (f64.mul (local.get $0) (local.get $1)))
+
+  (func (export "f64.div") (param $0 f64) (param $1 f64) (result f64)
+    (f64.div (local.get $0) (local.get $1)))
+
+  ;; comparisons
+  (func (export "f32.eq") (param $0 f32) (param $1 f32) (result i32)
+    (f32.eq (local.get $0) (local.get $1)))
+
+  (func (export "f32.ne") (param $0 f32) (param $1 f32) (result i32)
+    (f32.ne (local.get $0) (local.get $1)))
+
+  (func (export "f32.ge") (param $0 f32) (param $1 f32) (result i32)
+    (f32.ge (local.get $0) (local.get $1)))
+
+  (func (export "f32.gt") (param $0 f32) (param $1 f32) (result i32)
+    (f32.gt (local.get $0) (local.get $1)))
+
+  (func (export "f32.le") (param $0 f32) (param $1 f32) (result i32)
+    (f32.le (local.get $0) (local.get $1)))
+
+  (func (export "f32.lt") (param $0 f32) (param $1 f32) (result i32)
+    (f32.lt (local.get $0) (local.get $1)))
+
+  (func (export "f64.eq") (param $0 f64) (param $1 f64) (result i32)
+    (f64.eq (local.get $0) (local.get $1)))
+
+  (func (export "f64.ne") (param $0 f64) (param $1 f64) (result i32)
+    (f64.ne (local.get $0) (local.get $1)))
+
+  (func (export "f64.ge") (param $0 f64) (param $1 f64) (result i32)
+    (f64.ge (local.get $0) (local.get $1)))
+
+  (func (export "f64.gt") (param $0 f64) (param $1 f64) (result i32)
+    (f64.gt (local.get $0) (local.get $1)))
+
+  (func (export "f64.le") (param $0 f64) (param $1 f64) (result i32)
+    (f64.le (local.get $0) (local.get $1)))
+
+  (func (export "f64.lt") (param $0 f64) (param $1 f64) (result i32)
+    (f64.lt (local.get $0) (local.get $1)))
+
+  ;; min/max
+  (func (export "f32.min") (param $0 f32) (param $1 f32) (result f32)
+    (f32.min (local.get $0) (local.get $1)))
+
+  (func (export "f32.max") (param $0 f32) (param $1 f32) (result f32)
+    (f32.max (local.get $0) (local.get $1)))
+
+  (func (export "f64.min") (param $0 f64) (param $1 f64) (result f64)
+    (f64.min (local.get $0) (local.get $1)))
+
+  (func (export "f64.max") (param $0 f64) (param $1 f64) (result f64)
+    (f64.max (local.get $0) (local.get $1)))
+
+  ;; promotion/demotion
+  (func (export "f64.promote") (param $0 f32) (result f64)
+    (f64.promote_f32 (local.get $0)))
+
+  (func (export "f32.demote") (param $0 f64) (result f32)
+    (f32.demote_f64 (local.get $0)))
+
+  ;; floor/ceil
+  (func (export "f32.floor") (param $0 f32) (result f32)
+    (f32.floor (local.get $0)))
+
+  (func (export "f32.ceil") (param $0 f32) (result f32)
+    (f32.ceil (local.get $0)))
+
+  (func (export "f64.floor") (param $0 f64) (result f64)
+    (f64.floor (local.get $0)))
+
+  (func (export "f64.ceil") (param $0 f64) (result f64)
+    (f64.ceil (local.get $0)))
+
+  ;; sqrt
+  (func (export "f32.sqrt") (param $0 f32) (result f32)
+    (f32.sqrt (local.get $0)))
+
+  (func (export "f64.sqrt") (param $0 f64) (result f64)
+    (f64.sqrt (local.get $0)))
+
+  ;; copysign
+ (func $copysign64 (param $0 f64) (param $1 f64) (result f64)
+   (f64.copysign (local.get $0) (local.get $1)))
+ (func $copysign32 (param $0 f32) (param $1 f32) (result f32)
+   (f32.copysign (local.get $0) (local.get $1)))
+
+  ;; float<->int
+  (func (export "i32_to_f32") (param $0 i32) (result f32)
+    (f32.convert_i32_s (local.get $0)))
+  (func (export "i32_to_f64") (param $0 i32) (result f64)
+    (f64.convert_i32_s (local.get $0)))
+  (func (export "u32_to_f32") (param $0 i32) (result f32)
+    (f32.convert_i32_u (local.get $0)))
+  (func (export "u32_to_f64") (param $0 i32) (result f64)
+    (f64.convert_i32_u (local.get $0)))
+
+  (func (export "f32_to_i32") (param $0 f32) (result i32)
+    (i32.trunc_f32_s (local.get $0)))
+  (func (export "f64_to_i32") (param $0 f64) (result i32)
+    (i32.trunc_f64_s (local.get $0)))
+  (func (export "f32_to_u32") (param $0 f32) (result i32)
+    (i32.trunc_f32_u (local.get $0)))
+  (func (export "f64_to_u32") (param $0 f64) (result i32)
+    (i32.trunc_f64_u (local.get $0)))
+
+  (func (export "i64_to_f32") (param $0 i64) (result f32)
+    (f32.convert_i64_s (local.get $0)))
+  (func (export "i64_to_f64") (param $0 i64) (result f64)
+    (f64.convert_i64_s (local.get $0)))
+  (func (export "u64_to_f32") (param $0 i64) (result f32)
+    (f32.convert_i64_u (local.get $0)))
+  (func (export "u64_to_f64") (param $0 i64) (result f64)
+    (f64.convert_i64_u (local.get $0)))
+
+  (func (export "f32_to_i64") (param $0 f32) (result i32)
+    (i64.eq (i64.trunc_f32_s (local.get $0)) (i64.const 0)))
+  (func (export "f64_to_i64") (param $0 f64) (result i32)
+    (i64.eq (i64.trunc_f64_s (local.get $0)) (i64.const 0)))
+  (func (export "f32_to_u64") (param $0 f32) (result i32)
+    (i64.eq (i64.trunc_f32_u (local.get $0)) (i64.const 0)))
+  (func (export "f64_to_u64") (param $0 f64) (result i32)
+    (i64.eq (i64.trunc_f64_u (local.get $0)) (i64.const 0)))
+)
diff --git a/binaryen/test/wasm2js/float_literals-modified.2asm.js b/binaryen/test/wasm2js/float_literals-modified.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/float_literals-modified.2asm.js
@@ -0,0 +1,1225 @@
+import { setTempRet0 } from 'env';
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_scratch_load_i32(index) {
+    return i32ScratchView[index];
+  }
+      
+  function wasm2js_scratch_store_f64(value) {
+    f64ScratchView[0] = value;
+  }
+      
+  function wasm2js_scratch_store_f32(value) {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0() {
+  return (wasm2js_scratch_store_f32(Math_fround(nan)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $1() {
+  return (wasm2js_scratch_store_f32(Math_fround(nan)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $2() {
+  return (wasm2js_scratch_store_f32(Math_fround(-nan)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $3() {
+  return (wasm2js_scratch_store_f32(Math_fround(nan)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $4() {
+  return (wasm2js_scratch_store_f32(Math_fround(nan)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $5() {
+  return (wasm2js_scratch_store_f32(Math_fround(-nan)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $6() {
+  return (wasm2js_scratch_store_f32(Math_fround(nan)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $7() {
+  return (wasm2js_scratch_store_f32(Math_fround(nan)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $8() {
+  return (wasm2js_scratch_store_f32(Math_fround(-nan)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $9() {
+  return (wasm2js_scratch_store_f32(Math_fround(infinity)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $10() {
+  return (wasm2js_scratch_store_f32(Math_fround(infinity)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $11() {
+  return (wasm2js_scratch_store_f32(Math_fround(-infinity)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $12() {
+  return (wasm2js_scratch_store_f32(Math_fround(0.0)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $13() {
+  return (wasm2js_scratch_store_f32(Math_fround(0.0)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $14() {
+  return (wasm2js_scratch_store_f32(Math_fround(-0.0)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $15() {
+  return (wasm2js_scratch_store_f32(Math_fround(6.2831854820251465)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $16() {
+  return (wasm2js_scratch_store_f32(Math_fround(1.401298464324817e-45)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $17() {
+  return (wasm2js_scratch_store_f32(Math_fround(1.1754943508222875e-38)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $18() {
+  return (wasm2js_scratch_store_f32(Math_fround(3402823466385288598117041.0e14)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $19() {
+  return (wasm2js_scratch_store_f32(Math_fround(1.1754942106924411e-38)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $20() {
+  return (wasm2js_scratch_store_f32(Math_fround(1024.0)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $21() {
+  return (wasm2js_scratch_store_f32(Math_fround(0.0)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $22() {
+  return (wasm2js_scratch_store_f32(Math_fround(0.0)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $23() {
+  return (wasm2js_scratch_store_f32(Math_fround(-0.0)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $24() {
+  return (wasm2js_scratch_store_f32(Math_fround(6.2831854820251465)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $25() {
+  return (wasm2js_scratch_store_f32(Math_fround(1.401298464324817e-45)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $26() {
+  return (wasm2js_scratch_store_f32(Math_fround(1.1754943508222875e-38)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $27() {
+  return (wasm2js_scratch_store_f32(Math_fround(1.1754942106924411e-38)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $28() {
+  return (wasm2js_scratch_store_f32(Math_fround(3402823466385288598117041.0e14)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $29() {
+  return (wasm2js_scratch_store_f32(Math_fround(1.0e10)), wasm2js_scratch_load_i32(2)) | 0;
+ }
+ 
+ function $30() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(nan));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $31() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(nan));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $32() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(-nan));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $33() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(nan));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $34() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(nan));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $35() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(-nan));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $36() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(nan));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $37() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(nan));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $38() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(-nan));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $39() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(infinity));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $40() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(infinity));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $41() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(-infinity));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $42() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(0.0));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $43() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(0.0));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $44() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(-0.0));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $45() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(6.283185307179586));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $46() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(5.0e-324));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $47() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(2.2250738585072014e-308));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $48() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(2.225073858507201e-308));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $49() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(1797693134862315708145274.0e284));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $50() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(1267650600228229401496703.0e6));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $51() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(0.0));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $52() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(0.0));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $53() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(-0.0));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $54() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(6.283185307179586));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $55() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(5.0e-324));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $56() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(2.2250738585072014e-308));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $57() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(2.225073858507201e-308));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $58() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(1797693134862315708145274.0e284));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $59() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  wasm2js_scratch_store_f64(+(1.e+100));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$30() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $30() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$31() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $31() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$32() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $32() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$33() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $33() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$34() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $34() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$35() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $35() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$36() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $36() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$37() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $37() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$38() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $38() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$39() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $39() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$40() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $40() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$41() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $41() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$42() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $42() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$43() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $43() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$44() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $44() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$45() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $45() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$46() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $46() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$47() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $47() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$48() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $48() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$49() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $49() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$50() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $50() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$51() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $51() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$52() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $52() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$53() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $53() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$54() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $54() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$55() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $55() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$56() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $56() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$57() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $57() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$58() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $58() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$59() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $59() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ return {
+  "f32_nan": $0, 
+  "f32_positive_nan": $1, 
+  "f32_negative_nan": $2, 
+  "f32_plain_nan": $3, 
+  "f32_informally_known_as_plain_snan": $4, 
+  "f32_all_ones_nan": $5, 
+  "f32_misc_nan": $6, 
+  "f32_misc_positive_nan": $7, 
+  "f32_misc_negative_nan": $8, 
+  "f32_infinity": $9, 
+  "f32_positive_infinity": $10, 
+  "f32_negative_infinity": $11, 
+  "f32_zero": $12, 
+  "f32_positive_zero": $13, 
+  "f32_negative_zero": $14, 
+  "f32_misc": $15, 
+  "f32_min_positive": $16, 
+  "f32_min_normal": $17, 
+  "f32_max_finite": $18, 
+  "f32_max_subnormal": $19, 
+  "f32_trailing_dot": $20, 
+  "f32_dec_zero": $21, 
+  "f32_dec_positive_zero": $22, 
+  "f32_dec_negative_zero": $23, 
+  "f32_dec_misc": $24, 
+  "f32_dec_min_positive": $25, 
+  "f32_dec_min_normal": $26, 
+  "f32_dec_max_subnormal": $27, 
+  "f32_dec_max_finite": $28, 
+  "f32_dec_trailing_dot": $29, 
+  "f64_nan": legalstub$30, 
+  "f64_positive_nan": legalstub$31, 
+  "f64_negative_nan": legalstub$32, 
+  "f64_plain_nan": legalstub$33, 
+  "f64_informally_known_as_plain_snan": legalstub$34, 
+  "f64_all_ones_nan": legalstub$35, 
+  "f64_misc_nan": legalstub$36, 
+  "f64_misc_positive_nan": legalstub$37, 
+  "f64_misc_negative_nan": legalstub$38, 
+  "f64_infinity": legalstub$39, 
+  "f64_positive_infinity": legalstub$40, 
+  "f64_negative_infinity": legalstub$41, 
+  "f64_zero": legalstub$42, 
+  "f64_positive_zero": legalstub$43, 
+  "f64_negative_zero": legalstub$44, 
+  "f64_misc": legalstub$45, 
+  "f64_min_positive": legalstub$46, 
+  "f64_min_normal": legalstub$47, 
+  "f64_max_subnormal": legalstub$48, 
+  "f64_max_finite": legalstub$49, 
+  "f64_trailing_dot": legalstub$50, 
+  "f64_dec_zero": legalstub$51, 
+  "f64_dec_positive_zero": legalstub$52, 
+  "f64_dec_negative_zero": legalstub$53, 
+  "f64_dec_misc": legalstub$54, 
+  "f64_dec_min_positive": legalstub$55, 
+  "f64_dec_min_normal": legalstub$56, 
+  "f64_dec_max_subnormal": legalstub$57, 
+  "f64_dec_max_finite": legalstub$58, 
+  "f64_dec_trailing_dot": legalstub$59
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var f32_nan = retasmFunc.f32_nan;
+export var f32_positive_nan = retasmFunc.f32_positive_nan;
+export var f32_negative_nan = retasmFunc.f32_negative_nan;
+export var f32_plain_nan = retasmFunc.f32_plain_nan;
+export var f32_informally_known_as_plain_snan = retasmFunc.f32_informally_known_as_plain_snan;
+export var f32_all_ones_nan = retasmFunc.f32_all_ones_nan;
+export var f32_misc_nan = retasmFunc.f32_misc_nan;
+export var f32_misc_positive_nan = retasmFunc.f32_misc_positive_nan;
+export var f32_misc_negative_nan = retasmFunc.f32_misc_negative_nan;
+export var f32_infinity = retasmFunc.f32_infinity;
+export var f32_positive_infinity = retasmFunc.f32_positive_infinity;
+export var f32_negative_infinity = retasmFunc.f32_negative_infinity;
+export var f32_zero = retasmFunc.f32_zero;
+export var f32_positive_zero = retasmFunc.f32_positive_zero;
+export var f32_negative_zero = retasmFunc.f32_negative_zero;
+export var f32_misc = retasmFunc.f32_misc;
+export var f32_min_positive = retasmFunc.f32_min_positive;
+export var f32_min_normal = retasmFunc.f32_min_normal;
+export var f32_max_finite = retasmFunc.f32_max_finite;
+export var f32_max_subnormal = retasmFunc.f32_max_subnormal;
+export var f32_trailing_dot = retasmFunc.f32_trailing_dot;
+export var f32_dec_zero = retasmFunc.f32_dec_zero;
+export var f32_dec_positive_zero = retasmFunc.f32_dec_positive_zero;
+export var f32_dec_negative_zero = retasmFunc.f32_dec_negative_zero;
+export var f32_dec_misc = retasmFunc.f32_dec_misc;
+export var f32_dec_min_positive = retasmFunc.f32_dec_min_positive;
+export var f32_dec_min_normal = retasmFunc.f32_dec_min_normal;
+export var f32_dec_max_subnormal = retasmFunc.f32_dec_max_subnormal;
+export var f32_dec_max_finite = retasmFunc.f32_dec_max_finite;
+export var f32_dec_trailing_dot = retasmFunc.f32_dec_trailing_dot;
+export var f64_nan = retasmFunc.f64_nan;
+export var f64_positive_nan = retasmFunc.f64_positive_nan;
+export var f64_negative_nan = retasmFunc.f64_negative_nan;
+export var f64_plain_nan = retasmFunc.f64_plain_nan;
+export var f64_informally_known_as_plain_snan = retasmFunc.f64_informally_known_as_plain_snan;
+export var f64_all_ones_nan = retasmFunc.f64_all_ones_nan;
+export var f64_misc_nan = retasmFunc.f64_misc_nan;
+export var f64_misc_positive_nan = retasmFunc.f64_misc_positive_nan;
+export var f64_misc_negative_nan = retasmFunc.f64_misc_negative_nan;
+export var f64_infinity = retasmFunc.f64_infinity;
+export var f64_positive_infinity = retasmFunc.f64_positive_infinity;
+export var f64_negative_infinity = retasmFunc.f64_negative_infinity;
+export var f64_zero = retasmFunc.f64_zero;
+export var f64_positive_zero = retasmFunc.f64_positive_zero;
+export var f64_negative_zero = retasmFunc.f64_negative_zero;
+export var f64_misc = retasmFunc.f64_misc;
+export var f64_min_positive = retasmFunc.f64_min_positive;
+export var f64_min_normal = retasmFunc.f64_min_normal;
+export var f64_max_subnormal = retasmFunc.f64_max_subnormal;
+export var f64_max_finite = retasmFunc.f64_max_finite;
+export var f64_trailing_dot = retasmFunc.f64_trailing_dot;
+export var f64_dec_zero = retasmFunc.f64_dec_zero;
+export var f64_dec_positive_zero = retasmFunc.f64_dec_positive_zero;
+export var f64_dec_negative_zero = retasmFunc.f64_dec_negative_zero;
+export var f64_dec_misc = retasmFunc.f64_dec_misc;
+export var f64_dec_min_positive = retasmFunc.f64_dec_min_positive;
+export var f64_dec_min_normal = retasmFunc.f64_dec_min_normal;
+export var f64_dec_max_subnormal = retasmFunc.f64_dec_max_subnormal;
+export var f64_dec_max_finite = retasmFunc.f64_dec_max_finite;
+export var f64_dec_trailing_dot = retasmFunc.f64_dec_trailing_dot;
diff --git a/binaryen/test/wasm2js/float_literals-modified.2asm.js.opt b/binaryen/test/wasm2js/float_literals-modified.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/float_literals-modified.2asm.js.opt
@@ -0,0 +1,441 @@
+import { setTempRet0 } from 'env';
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_scratch_load_i32(index) {
+    return i32ScratchView[index];
+  }
+      
+  function wasm2js_scratch_store_f64(value) {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0() {
+  return 2143289344;
+ }
+ 
+ function $2() {
+  return -4194304;
+ }
+ 
+ function $4() {
+  return 2141192192;
+ }
+ 
+ function $5() {
+  return -1;
+ }
+ 
+ function $6() {
+  return 2139169605;
+ }
+ 
+ function $7() {
+  return 2142257232;
+ }
+ 
+ function $8() {
+  return -5587746;
+ }
+ 
+ function $9() {
+  return 2139095040;
+ }
+ 
+ function $11() {
+  return -8388608;
+ }
+ 
+ function $12() {
+  return 0;
+ }
+ 
+ function $14() {
+  return -2147483648;
+ }
+ 
+ function $15() {
+  return 1086918619;
+ }
+ 
+ function $16() {
+  return 1;
+ }
+ 
+ function $17() {
+  return 8388608;
+ }
+ 
+ function $18() {
+  return 2139095039;
+ }
+ 
+ function $19() {
+  return 8388607;
+ }
+ 
+ function $20() {
+  return 1149239296;
+ }
+ 
+ function $29() {
+  return 1343554297;
+ }
+ 
+ function legalstub$30() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(nan);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$32() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(-nan);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$34() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(nan);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$35() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(-nan);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$36() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(nan);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$37() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(nan);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$38() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(-nan);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$39() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(infinity);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$41() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(-infinity);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$42() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(0.0);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$44() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(-0.0);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$45() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(6.283185307179586);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$46() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(5.0e-324);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$47() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(2.2250738585072014e-308);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$48() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(2.225073858507201e-308);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$49() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(1797693134862315708145274.0e284);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$50() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(1267650600228229401496703.0e6);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function legalstub$59() {
+  var $0_1 = 0, $1 = 0;
+  wasm2js_scratch_store_f64(1.e+100);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1 = wasm2js_scratch_load_i32(0) | 0;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  $0_1 = $1;
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ return {
+  "f32_nan": $0, 
+  "f32_positive_nan": $0, 
+  "f32_negative_nan": $2, 
+  "f32_plain_nan": $0, 
+  "f32_informally_known_as_plain_snan": $4, 
+  "f32_all_ones_nan": $5, 
+  "f32_misc_nan": $6, 
+  "f32_misc_positive_nan": $7, 
+  "f32_misc_negative_nan": $8, 
+  "f32_infinity": $9, 
+  "f32_positive_infinity": $9, 
+  "f32_negative_infinity": $11, 
+  "f32_zero": $12, 
+  "f32_positive_zero": $12, 
+  "f32_negative_zero": $14, 
+  "f32_misc": $15, 
+  "f32_min_positive": $16, 
+  "f32_min_normal": $17, 
+  "f32_max_finite": $18, 
+  "f32_max_subnormal": $19, 
+  "f32_trailing_dot": $20, 
+  "f32_dec_zero": $12, 
+  "f32_dec_positive_zero": $12, 
+  "f32_dec_negative_zero": $14, 
+  "f32_dec_misc": $15, 
+  "f32_dec_min_positive": $16, 
+  "f32_dec_min_normal": $17, 
+  "f32_dec_max_subnormal": $19, 
+  "f32_dec_max_finite": $18, 
+  "f32_dec_trailing_dot": $29, 
+  "f64_nan": legalstub$30, 
+  "f64_positive_nan": legalstub$30, 
+  "f64_negative_nan": legalstub$32, 
+  "f64_plain_nan": legalstub$30, 
+  "f64_informally_known_as_plain_snan": legalstub$34, 
+  "f64_all_ones_nan": legalstub$35, 
+  "f64_misc_nan": legalstub$36, 
+  "f64_misc_positive_nan": legalstub$37, 
+  "f64_misc_negative_nan": legalstub$38, 
+  "f64_infinity": legalstub$39, 
+  "f64_positive_infinity": legalstub$39, 
+  "f64_negative_infinity": legalstub$41, 
+  "f64_zero": legalstub$42, 
+  "f64_positive_zero": legalstub$42, 
+  "f64_negative_zero": legalstub$44, 
+  "f64_misc": legalstub$45, 
+  "f64_min_positive": legalstub$46, 
+  "f64_min_normal": legalstub$47, 
+  "f64_max_subnormal": legalstub$48, 
+  "f64_max_finite": legalstub$49, 
+  "f64_trailing_dot": legalstub$50, 
+  "f64_dec_zero": legalstub$42, 
+  "f64_dec_positive_zero": legalstub$42, 
+  "f64_dec_negative_zero": legalstub$44, 
+  "f64_dec_misc": legalstub$45, 
+  "f64_dec_min_positive": legalstub$46, 
+  "f64_dec_min_normal": legalstub$47, 
+  "f64_dec_max_subnormal": legalstub$48, 
+  "f64_dec_max_finite": legalstub$49, 
+  "f64_dec_trailing_dot": legalstub$59
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var f32_nan = retasmFunc.f32_nan;
+export var f32_positive_nan = retasmFunc.f32_positive_nan;
+export var f32_negative_nan = retasmFunc.f32_negative_nan;
+export var f32_plain_nan = retasmFunc.f32_plain_nan;
+export var f32_informally_known_as_plain_snan = retasmFunc.f32_informally_known_as_plain_snan;
+export var f32_all_ones_nan = retasmFunc.f32_all_ones_nan;
+export var f32_misc_nan = retasmFunc.f32_misc_nan;
+export var f32_misc_positive_nan = retasmFunc.f32_misc_positive_nan;
+export var f32_misc_negative_nan = retasmFunc.f32_misc_negative_nan;
+export var f32_infinity = retasmFunc.f32_infinity;
+export var f32_positive_infinity = retasmFunc.f32_positive_infinity;
+export var f32_negative_infinity = retasmFunc.f32_negative_infinity;
+export var f32_zero = retasmFunc.f32_zero;
+export var f32_positive_zero = retasmFunc.f32_positive_zero;
+export var f32_negative_zero = retasmFunc.f32_negative_zero;
+export var f32_misc = retasmFunc.f32_misc;
+export var f32_min_positive = retasmFunc.f32_min_positive;
+export var f32_min_normal = retasmFunc.f32_min_normal;
+export var f32_max_finite = retasmFunc.f32_max_finite;
+export var f32_max_subnormal = retasmFunc.f32_max_subnormal;
+export var f32_trailing_dot = retasmFunc.f32_trailing_dot;
+export var f32_dec_zero = retasmFunc.f32_dec_zero;
+export var f32_dec_positive_zero = retasmFunc.f32_dec_positive_zero;
+export var f32_dec_negative_zero = retasmFunc.f32_dec_negative_zero;
+export var f32_dec_misc = retasmFunc.f32_dec_misc;
+export var f32_dec_min_positive = retasmFunc.f32_dec_min_positive;
+export var f32_dec_min_normal = retasmFunc.f32_dec_min_normal;
+export var f32_dec_max_subnormal = retasmFunc.f32_dec_max_subnormal;
+export var f32_dec_max_finite = retasmFunc.f32_dec_max_finite;
+export var f32_dec_trailing_dot = retasmFunc.f32_dec_trailing_dot;
+export var f64_nan = retasmFunc.f64_nan;
+export var f64_positive_nan = retasmFunc.f64_positive_nan;
+export var f64_negative_nan = retasmFunc.f64_negative_nan;
+export var f64_plain_nan = retasmFunc.f64_plain_nan;
+export var f64_informally_known_as_plain_snan = retasmFunc.f64_informally_known_as_plain_snan;
+export var f64_all_ones_nan = retasmFunc.f64_all_ones_nan;
+export var f64_misc_nan = retasmFunc.f64_misc_nan;
+export var f64_misc_positive_nan = retasmFunc.f64_misc_positive_nan;
+export var f64_misc_negative_nan = retasmFunc.f64_misc_negative_nan;
+export var f64_infinity = retasmFunc.f64_infinity;
+export var f64_positive_infinity = retasmFunc.f64_positive_infinity;
+export var f64_negative_infinity = retasmFunc.f64_negative_infinity;
+export var f64_zero = retasmFunc.f64_zero;
+export var f64_positive_zero = retasmFunc.f64_positive_zero;
+export var f64_negative_zero = retasmFunc.f64_negative_zero;
+export var f64_misc = retasmFunc.f64_misc;
+export var f64_min_positive = retasmFunc.f64_min_positive;
+export var f64_min_normal = retasmFunc.f64_min_normal;
+export var f64_max_subnormal = retasmFunc.f64_max_subnormal;
+export var f64_max_finite = retasmFunc.f64_max_finite;
+export var f64_trailing_dot = retasmFunc.f64_trailing_dot;
+export var f64_dec_zero = retasmFunc.f64_dec_zero;
+export var f64_dec_positive_zero = retasmFunc.f64_dec_positive_zero;
+export var f64_dec_negative_zero = retasmFunc.f64_dec_negative_zero;
+export var f64_dec_misc = retasmFunc.f64_dec_misc;
+export var f64_dec_min_positive = retasmFunc.f64_dec_min_positive;
+export var f64_dec_min_normal = retasmFunc.f64_dec_min_normal;
+export var f64_dec_max_subnormal = retasmFunc.f64_dec_max_subnormal;
+export var f64_dec_max_finite = retasmFunc.f64_dec_max_finite;
+export var f64_dec_trailing_dot = retasmFunc.f64_dec_trailing_dot;
diff --git a/binaryen/test/wasm2js/float_literals-modified.wast b/binaryen/test/wasm2js/float_literals-modified.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/float_literals-modified.wast
@@ -0,0 +1,137 @@
+;; Test floating-point literal parsing.
+
+(module
+  ;; f32 special values
+  (func (export "f32.nan") (result i32) (i32.reinterpret_f32 (f32.const nan)))
+  (func (export "f32.positive_nan") (result i32) (i32.reinterpret_f32 (f32.const +nan)))
+  (func (export "f32.negative_nan") (result i32) (i32.reinterpret_f32 (f32.const -nan)))
+  (func (export "f32.plain_nan") (result i32) (i32.reinterpret_f32 (f32.const nan:0x400000)))
+  (func (export "f32.informally_known_as_plain_snan") (result i32) (i32.reinterpret_f32 (f32.const nan:0x200000)))
+  (func (export "f32.all_ones_nan") (result i32) (i32.reinterpret_f32 (f32.const -nan:0x7fffff)))
+  (func (export "f32.misc_nan") (result i32) (i32.reinterpret_f32 (f32.const nan:0x012345)))
+  (func (export "f32.misc_positive_nan") (result i32) (i32.reinterpret_f32 (f32.const +nan:0x304050)))
+  (func (export "f32.misc_negative_nan") (result i32) (i32.reinterpret_f32 (f32.const -nan:0x2abcde)))
+  (func (export "f32.infinity") (result i32) (i32.reinterpret_f32 (f32.const infinity)))
+  (func (export "f32.positive_infinity") (result i32) (i32.reinterpret_f32 (f32.const +infinity)))
+  (func (export "f32.negative_infinity") (result i32) (i32.reinterpret_f32 (f32.const -infinity)))
+
+  ;; f32 numbers
+  (func (export "f32.zero") (result i32) (i32.reinterpret_f32 (f32.const 0x0.0p0)))
+  (func (export "f32.positive_zero") (result i32) (i32.reinterpret_f32 (f32.const +0x0.0p0)))
+  (func (export "f32.negative_zero") (result i32) (i32.reinterpret_f32 (f32.const -0x0.0p0)))
+  (func (export "f32.misc") (result i32) (i32.reinterpret_f32 (f32.const 0x1.921fb6p+2)))
+  (func (export "f32.min_positive") (result i32) (i32.reinterpret_f32 (f32.const 0x1p-149)))
+  (func (export "f32.min_normal") (result i32) (i32.reinterpret_f32 (f32.const 0x1p-126)))
+  (func (export "f32.max_finite") (result i32) (i32.reinterpret_f32 (f32.const 0x1.fffffep+127)))
+  (func (export "f32.max_subnormal") (result i32) (i32.reinterpret_f32 (f32.const 0x1.fffffcp-127)))
+  (func (export "f32.trailing_dot") (result i32) (i32.reinterpret_f32 (f32.const 0x1.p10)))
+
+  ;; f32 in decimal format
+  (func (export "f32_dec.zero") (result i32) (i32.reinterpret_f32 (f32.const 0.0e0)))
+  (func (export "f32_dec.positive_zero") (result i32) (i32.reinterpret_f32 (f32.const +0.0e0)))
+  (func (export "f32_dec.negative_zero") (result i32) (i32.reinterpret_f32 (f32.const -0.0e0)))
+  (func (export "f32_dec.misc") (result i32) (i32.reinterpret_f32 (f32.const 6.28318548202514648)))
+  (func (export "f32_dec.min_positive") (result i32) (i32.reinterpret_f32 (f32.const 1.4013e-45)))
+  (func (export "f32_dec.min_normal") (result i32) (i32.reinterpret_f32 (f32.const 1.1754944e-38)))
+  (func (export "f32_dec.max_subnormal") (result i32) (i32.reinterpret_f32 (f32.const 1.1754942e-38)))
+  (func (export "f32_dec.max_finite") (result i32) (i32.reinterpret_f32 (f32.const 3.4028234e+38)))
+  (func (export "f32_dec.trailing_dot") (result i32) (i32.reinterpret_f32 (f32.const 1.e10)))
+
+  ;; f64 special values
+  (func (export "f64.nan") (result i64) (i64.reinterpret_f64 (f64.const nan)))
+  (func (export "f64.positive_nan") (result i64) (i64.reinterpret_f64 (f64.const +nan)))
+  (func (export "f64.negative_nan") (result i64) (i64.reinterpret_f64 (f64.const -nan)))
+  (func (export "f64.plain_nan") (result i64) (i64.reinterpret_f64 (f64.const nan:0x8000000000000)))
+  (func (export "f64.informally_known_as_plain_snan") (result i64) (i64.reinterpret_f64 (f64.const nan:0x4000000000000)))
+  (func (export "f64.all_ones_nan") (result i64) (i64.reinterpret_f64 (f64.const -nan:0xfffffffffffff)))
+  (func (export "f64.misc_nan") (result i64) (i64.reinterpret_f64 (f64.const nan:0x0123456789abc)))
+  (func (export "f64.misc_positive_nan") (result i64) (i64.reinterpret_f64 (f64.const +nan:0x3040506070809)))
+  (func (export "f64.misc_negative_nan") (result i64) (i64.reinterpret_f64 (f64.const -nan:0x2abcdef012345)))
+  (func (export "f64.infinity") (result i64) (i64.reinterpret_f64 (f64.const infinity)))
+  (func (export "f64.positive_infinity") (result i64) (i64.reinterpret_f64 (f64.const +infinity)))
+  (func (export "f64.negative_infinity") (result i64) (i64.reinterpret_f64 (f64.const -infinity)))
+
+  ;; f64 numbers
+  (func (export "f64.zero") (result i64) (i64.reinterpret_f64 (f64.const 0x0.0p0)))
+  (func (export "f64.positive_zero") (result i64) (i64.reinterpret_f64 (f64.const +0x0.0p0)))
+  (func (export "f64.negative_zero") (result i64) (i64.reinterpret_f64 (f64.const -0x0.0p0)))
+  (func (export "f64.misc") (result i64) (i64.reinterpret_f64 (f64.const 0x1.921fb54442d18p+2)))
+  (func (export "f64.min_positive") (result i64) (i64.reinterpret_f64 (f64.const 0x0.0000000000001p-1022)))
+  (func (export "f64.min_normal") (result i64) (i64.reinterpret_f64 (f64.const 0x1p-1022)))
+  (func (export "f64.max_subnormal") (result i64) (i64.reinterpret_f64 (f64.const 0x0.fffffffffffffp-1022)))
+  (func (export "f64.max_finite") (result i64) (i64.reinterpret_f64 (f64.const 0x1.fffffffffffffp+1023)))
+  (func (export "f64.trailing_dot") (result i64) (i64.reinterpret_f64 (f64.const 0x1.p100)))
+
+  ;; f64 numbers in decimal format
+  (func (export "f64_dec.zero") (result i64) (i64.reinterpret_f64 (f64.const 0.0e0)))
+  (func (export "f64_dec.positive_zero") (result i64) (i64.reinterpret_f64 (f64.const +0.0e0)))
+  (func (export "f64_dec.negative_zero") (result i64) (i64.reinterpret_f64 (f64.const -0.0e0)))
+  (func (export "f64_dec.misc") (result i64) (i64.reinterpret_f64 (f64.const 6.28318530717958623)))
+  (func (export "f64_dec.min_positive") (result i64) (i64.reinterpret_f64 (f64.const 4.94066e-324)))
+  (func (export "f64_dec.min_normal") (result i64) (i64.reinterpret_f64 (f64.const 2.2250738585072012e-308)))
+  (func (export "f64_dec.max_subnormal") (result i64) (i64.reinterpret_f64 (f64.const 2.2250738585072011e-308)))
+  (func (export "f64_dec.max_finite") (result i64) (i64.reinterpret_f64 (f64.const 1.7976931348623157e+308)))
+  (func (export "f64_dec.trailing_dot") (result i64) (i64.reinterpret_f64 (f64.const 1.e100)))
+)
+
+;;(assert_return (invoke "f32.nan") (i32.const 0x7fc00000))
+;;(assert_return (invoke "f32.positive_nan") (i32.const 0x7fc00000))
+;;(assert_return (invoke "f32.negative_nan") (i32.const 0xffc00000))
+;;(assert_return (invoke "f32.plain_nan") (i32.const 0x7fc00000))
+;;(assert_return (invoke "f32.informally_known_as_plain_snan") (i32.const 0x7fa00000))
+;;(assert_return (invoke "f32.all_ones_nan") (i32.const 0xffffffff))
+;;(assert_return (invoke "f32.misc_nan") (i32.const 0x7f812345))
+;;(assert_return (invoke "f32.misc_positive_nan") (i32.const 0x7fb04050))
+;;(assert_return (invoke "f32.misc_negative_nan") (i32.const 0xffaabcde))
+(assert_return (invoke "f32.infinity") (i32.const 0x7f800000))
+(assert_return (invoke "f32.positive_infinity") (i32.const 0x7f800000))
+(assert_return (invoke "f32.negative_infinity") (i32.const 0xff800000))
+(assert_return (invoke "f32.zero") (i32.const 0))
+(assert_return (invoke "f32.positive_zero") (i32.const 0))
+(assert_return (invoke "f32.negative_zero") (i32.const 0x80000000))
+(assert_return (invoke "f32.misc") (i32.const 0x40c90fdb))
+(assert_return (invoke "f32.min_positive") (i32.const 1))
+(assert_return (invoke "f32.min_normal") (i32.const 0x800000))
+(assert_return (invoke "f32.max_subnormal") (i32.const 0x7fffff))
+(assert_return (invoke "f32.max_finite") (i32.const 0x7f7fffff))
+(assert_return (invoke "f32.trailing_dot") (i32.const 0x44800000))
+(assert_return (invoke "f32_dec.zero") (i32.const 0))
+(assert_return (invoke "f32_dec.positive_zero") (i32.const 0))
+(assert_return (invoke "f32_dec.negative_zero") (i32.const 0x80000000))
+(assert_return (invoke "f32_dec.misc") (i32.const 0x40c90fdb))
+(assert_return (invoke "f32_dec.min_positive") (i32.const 1))
+(assert_return (invoke "f32_dec.min_normal") (i32.const 0x800000))
+(assert_return (invoke "f32_dec.max_subnormal") (i32.const 0x7fffff))
+(assert_return (invoke "f32_dec.max_finite") (i32.const 0x7f7fffff))
+(assert_return (invoke "f32_dec.trailing_dot") (i32.const 0x501502f9))
+
+;;(assert_return (invoke "f64.nan") (i64.const 0x7ff8000000000000))
+;;(assert_return (invoke "f64.positive_nan") (i64.const 0x7ff8000000000000))
+;;(assert_return (invoke "f64.negative_nan") (i64.const 0xfff8000000000000))
+;;(assert_return (invoke "f64.plain_nan") (i64.const 0x7ff8000000000000))
+;;(assert_return (invoke "f64.informally_known_as_plain_snan") (i64.const 0x7ff4000000000000))
+;;(assert_return (invoke "f64.all_ones_nan") (i64.const 0xffffffffffffffff))
+;;(assert_return (invoke "f64.misc_nan") (i64.const 0x7ff0123456789abc))
+;;(assert_return (invoke "f64.misc_positive_nan") (i64.const 0x7ff3040506070809))
+;;(assert_return (invoke "f64.misc_negative_nan") (i64.const 0xfff2abcdef012345))
+(assert_return (invoke "f64.infinity") (i64.const 0x7ff0000000000000))
+(assert_return (invoke "f64.positive_infinity") (i64.const 0x7ff0000000000000))
+(assert_return (invoke "f64.negative_infinity") (i64.const 0xfff0000000000000))
+(assert_return (invoke "f64.zero") (i64.const 0))
+(assert_return (invoke "f64.positive_zero") (i64.const 0))
+(assert_return (invoke "f64.negative_zero") (i64.const 0x8000000000000000))
+(assert_return (invoke "f64.misc") (i64.const 0x401921fb54442d18))
+(assert_return (invoke "f64.min_positive") (i64.const 1))
+(assert_return (invoke "f64.min_normal") (i64.const 0x10000000000000))
+(assert_return (invoke "f64.max_subnormal") (i64.const 0xfffffffffffff))
+(assert_return (invoke "f64.max_finite") (i64.const 0x7fefffffffffffff))
+(assert_return (invoke "f64.trailing_dot") (i64.const 0x4630000000000000))
+(assert_return (invoke "f64_dec.zero") (i64.const 0))
+(assert_return (invoke "f64_dec.positive_zero") (i64.const 0))
+(assert_return (invoke "f64_dec.negative_zero") (i64.const 0x8000000000000000))
+(assert_return (invoke "f64_dec.misc") (i64.const 0x401921fb54442d18))
+(assert_return (invoke "f64_dec.min_positive") (i64.const 1))
+(assert_return (invoke "f64_dec.min_normal") (i64.const 0x10000000000000))
+(assert_return (invoke "f64_dec.max_subnormal") (i64.const 0xfffffffffffff))
+(assert_return (invoke "f64_dec.max_finite") (i64.const 0x7fefffffffffffff))
+(assert_return (invoke "f64_dec.trailing_dot") (i64.const 0x54b249ad2594c37d))
diff --git a/binaryen/test/wasm2js/float_misc.2asm.js b/binaryen/test/wasm2js/float_misc.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/float_misc.2asm.js
@@ -0,0 +1,343 @@
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_scratch_load_i32(index) {
+    return i32ScratchView[index];
+  }
+      
+  function wasm2js_scratch_store_i32(index, value) {
+    i32ScratchView[index] = value;
+  }
+      
+  function wasm2js_scratch_load_f64() {
+    return f64ScratchView[0];
+  }
+      
+  function wasm2js_scratch_store_f64(value) {
+    f64ScratchView[0] = value;
+  }
+      
+  function wasm2js_scratch_load_f32() {
+    return f32ScratchView[2];
+  }
+      
+  function wasm2js_scratch_store_f32(value) {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return Math_fround(Math_fround(x + y));
+ }
+ 
+ function $1(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return Math_fround(Math_fround(x - y));
+ }
+ 
+ function $2(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return Math_fround(Math_fround(x * y));
+ }
+ 
+ function $3(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return Math_fround(Math_fround(x / y));
+ }
+ 
+ function $4(x) {
+  x = Math_fround(x);
+  return Math_fround(Math_fround(Math_sqrt(x)));
+ }
+ 
+ function $5(x) {
+  x = Math_fround(x);
+  return Math_fround(Math_fround(Math_abs(x)));
+ }
+ 
+ function $6(x) {
+  x = Math_fround(x);
+  return Math_fround(Math_fround(-x));
+ }
+ 
+ function $7(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return Math_fround((wasm2js_scratch_store_i32(2, (wasm2js_scratch_store_f32(x), wasm2js_scratch_load_i32(2)) & 2147483647 | 0 | ((wasm2js_scratch_store_f32(y), wasm2js_scratch_load_i32(2)) & -2147483648 | 0) | 0), wasm2js_scratch_load_f32()));
+ }
+ 
+ function $8(x) {
+  x = Math_fround(x);
+  return Math_fround(Math_fround(Math_ceil(x)));
+ }
+ 
+ function $9(x) {
+  x = Math_fround(x);
+  return Math_fround(Math_fround(Math_floor(x)));
+ }
+ 
+ function $10(x) {
+  x = Math_fround(x);
+  return Math_fround(Math_fround(__wasm_trunc_f32(Math_fround(x))));
+ }
+ 
+ function $11(x) {
+  x = Math_fround(x);
+  return Math_fround(Math_fround(__wasm_nearest_f32(Math_fround(x))));
+ }
+ 
+ function $12(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return Math_fround(Math_fround(Math_min(x, y)));
+ }
+ 
+ function $13(x, y) {
+  x = Math_fround(x);
+  y = Math_fround(y);
+  return Math_fround(Math_fround(Math_max(x, y)));
+ }
+ 
+ function $14(x, y) {
+  x = +x;
+  y = +y;
+  return +(x + y);
+ }
+ 
+ function $15(x, y) {
+  x = +x;
+  y = +y;
+  return +(x - y);
+ }
+ 
+ function $16(x, y) {
+  x = +x;
+  y = +y;
+  return +(x * y);
+ }
+ 
+ function $17(x, y) {
+  x = +x;
+  y = +y;
+  return +(x / y);
+ }
+ 
+ function $18(x) {
+  x = +x;
+  return +Math_sqrt(x);
+ }
+ 
+ function $19(x) {
+  x = +x;
+  return +Math_abs(x);
+ }
+ 
+ function $20(x) {
+  x = +x;
+  return +-x;
+ }
+ 
+ function $21(x, y) {
+  x = +x;
+  y = +y;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $4_1 = 0, $4$hi = 0, $7_1 = 0, $7$hi = 0;
+  wasm2js_scratch_store_f64(+x);
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$2 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$1 = 2147483647;
+  i64toi32_i32$3 = -1;
+  i64toi32_i32$1 = i64toi32_i32$0 & i64toi32_i32$1 | 0;
+  $4_1 = i64toi32_i32$2 & i64toi32_i32$3 | 0;
+  $4$hi = i64toi32_i32$1;
+  wasm2js_scratch_store_f64(+y);
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$2 = -2147483648;
+  i64toi32_i32$3 = 0;
+  i64toi32_i32$2 = i64toi32_i32$1 & i64toi32_i32$2 | 0;
+  $7_1 = i64toi32_i32$0 & i64toi32_i32$3 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $4$hi;
+  i64toi32_i32$1 = $4_1;
+  i64toi32_i32$0 = $7$hi;
+  i64toi32_i32$3 = $7_1;
+  i64toi32_i32$0 = i64toi32_i32$2 | i64toi32_i32$0 | 0;
+  wasm2js_scratch_store_i32(0 | 0, i64toi32_i32$1 | i64toi32_i32$3 | 0 | 0);
+  wasm2js_scratch_store_i32(1 | 0, i64toi32_i32$0 | 0);
+  return +(+wasm2js_scratch_load_f64());
+ }
+ 
+ function $22(x) {
+  x = +x;
+  return +Math_ceil(x);
+ }
+ 
+ function $23(x) {
+  x = +x;
+  return +Math_floor(x);
+ }
+ 
+ function $24(x) {
+  x = +x;
+  return +(+__wasm_trunc_f64(+x));
+ }
+ 
+ function $25(x) {
+  x = +x;
+  return +(+__wasm_nearest_f64(+x));
+ }
+ 
+ function $26(x, y) {
+  x = +x;
+  y = +y;
+  return +Math_min(x, y);
+ }
+ 
+ function $27(x, y) {
+  x = +x;
+  y = +y;
+  return +Math_max(x, y);
+ }
+ 
+ function __wasm_nearest_f32(var$0) {
+  var$0 = Math_fround(var$0);
+  var var$1 = Math_fround(0), var$2 = Math_fround(0);
+  var$1 = Math_fround(Math_floor(var$0));
+  var$2 = Math_fround(var$0 - var$1);
+  if (!(var$2 < Math_fround(.5))) {
+   block : {
+    var$0 = Math_fround(Math_ceil(var$0));
+    if (var$2 > Math_fround(.5)) {
+     return Math_fround(var$0)
+    }
+    var$2 = Math_fround(var$1 * Math_fround(.5));
+    var$1 = Math_fround(var$2 - Math_fround(Math_floor(var$2))) == Math_fround(0.0) ? var$1 : var$0;
+   }
+  }
+  return Math_fround(var$1);
+ }
+ 
+ function __wasm_nearest_f64(var$0) {
+  var$0 = +var$0;
+  var var$1 = 0.0, var$2 = 0.0;
+  var$1 = Math_floor(var$0);
+  var$2 = var$0 - var$1;
+  if (!(var$2 < .5)) {
+   block : {
+    var$0 = Math_ceil(var$0);
+    if (var$2 > .5) {
+     return +var$0
+    }
+    var$2 = var$1 * .5;
+    var$1 = var$2 - Math_floor(var$2) == 0.0 ? var$1 : var$0;
+   }
+  }
+  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, 
+  "f32_mul": $2, 
+  "f32_div": $3, 
+  "f32_sqrt": $4, 
+  "f32_abs": $5, 
+  "f32_neg": $6, 
+  "f32_copysign": $7, 
+  "f32_ceil": $8, 
+  "f32_floor": $9, 
+  "f32_trunc": $10, 
+  "f32_nearest": $11, 
+  "f32_min": $12, 
+  "f32_max": $13, 
+  "f64_add": $14, 
+  "f64_sub": $15, 
+  "f64_mul": $16, 
+  "f64_div": $17, 
+  "f64_sqrt": $18, 
+  "f64_abs": $19, 
+  "f64_neg": $20, 
+  "f64_copysign": $21, 
+  "f64_ceil": $22, 
+  "f64_floor": $23, 
+  "f64_trunc": $24, 
+  "f64_nearest": $25, 
+  "f64_min": $26, 
+  "f64_max": $27
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var f32_add = retasmFunc.f32_add;
+export var f32_sub = retasmFunc.f32_sub;
+export var f32_mul = retasmFunc.f32_mul;
+export var f32_div = retasmFunc.f32_div;
+export var f32_sqrt = retasmFunc.f32_sqrt;
+export var f32_abs = retasmFunc.f32_abs;
+export var f32_neg = retasmFunc.f32_neg;
+export var f32_copysign = retasmFunc.f32_copysign;
+export var f32_ceil = retasmFunc.f32_ceil;
+export var f32_floor = retasmFunc.f32_floor;
+export var f32_trunc = retasmFunc.f32_trunc;
+export var f32_nearest = retasmFunc.f32_nearest;
+export var f32_min = retasmFunc.f32_min;
+export var f32_max = retasmFunc.f32_max;
+export var f64_add = retasmFunc.f64_add;
+export var f64_sub = retasmFunc.f64_sub;
+export var f64_mul = retasmFunc.f64_mul;
+export var f64_div = retasmFunc.f64_div;
+export var f64_sqrt = retasmFunc.f64_sqrt;
+export var f64_abs = retasmFunc.f64_abs;
+export var f64_neg = retasmFunc.f64_neg;
+export var f64_copysign = retasmFunc.f64_copysign;
+export var f64_ceil = retasmFunc.f64_ceil;
+export var f64_floor = retasmFunc.f64_floor;
+export var f64_trunc = retasmFunc.f64_trunc;
+export var f64_nearest = retasmFunc.f64_nearest;
+export var f64_min = retasmFunc.f64_min;
+export var f64_max = retasmFunc.f64_max;
diff --git a/binaryen/test/wasm2js/forward.2asm.js b/binaryen/test/wasm2js/forward.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/forward.2asm.js
@@ -0,0 +1,59 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function even(n) {
+  n = n | 0;
+  var $10 = 0;
+  if ((n | 0) == (0 | 0)) {
+   $10 = 1
+  } else {
+   $10 = odd(n - 1 | 0 | 0) | 0
+  }
+  return $10 | 0;
+ }
+ 
+ function odd(n) {
+  n = n | 0;
+  var $10 = 0;
+  if ((n | 0) == (0 | 0)) {
+   $10 = 0
+  } else {
+   $10 = even(n - 1 | 0 | 0) | 0
+  }
+  return $10 | 0;
+ }
+ 
+ return {
+  "even": even, 
+  "odd": odd
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/func-ptr-offset.2asm.js
@@ -0,0 +1,53 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function t1() {
+  return 1 | 0;
+ }
+ 
+ function t2() {
+  return 2 | 0;
+ }
+ 
+ function t3() {
+  return 3 | 0;
+ }
+ 
+ function $3($0) {
+  $0 = $0 | 0;
+  return FUNCTION_TABLE[$0 | 0]() | 0 | 0;
+ }
+ 
+ var FUNCTION_TABLE = [null, t1, t2, t3];
+ return {
+  "call": $3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/func-ptr-offset.2asm.js.opt
@@ -0,0 +1,53 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function t1() {
+  return 1;
+ }
+ 
+ function t2() {
+  return 2;
+ }
+ 
+ function t3() {
+  return 3;
+ }
+ 
+ function $3($0) {
+  $0 = $0 | 0;
+  return FUNCTION_TABLE[$0 | 0]() | 0;
+ }
+ 
+ var FUNCTION_TABLE = [null, t1, t2, t3];
+ return {
+  "call": $3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var call = retasmFunc.call;
diff --git a/binaryen/test/wasm2js/func-ptr-offset.wast b/binaryen/test/wasm2js/func-ptr-offset.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/func-ptr-offset.wast
@@ -0,0 +1,17 @@
+(module
+  (type $T (func (result i32)))
+  (table 4 funcref)
+  (elem (i32.const 1) $t1 $t2 $t3)
+
+  (func $t1 (type $T) (i32.const 1))
+  (func $t2 (type $T) (i32.const 2))
+  (func $t3 (type $T) (i32.const 3))
+
+  (func (export "call") (param i32) (result i32)
+    (call_indirect (type $T) (local.get $0))
+  )
+)
+
+(assert_return (invoke "call" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "call" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "call" (i32.const 3)) (i32.const 3))
diff --git a/binaryen/test/wasm2js/func_ptrs.2asm.js b/binaryen/test/wasm2js/func_ptrs.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/func_ptrs.2asm.js
@@ -0,0 +1,180 @@
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var print = env.print_i32;
+ function $3() {
+  return 13 | 0;
+ }
+ 
+ function $4($0) {
+  $0 = $0 | 0;
+  return $0 + 1 | 0 | 0;
+ }
+ 
+ function $5(a) {
+  a = a | 0;
+  return a - 2 | 0 | 0;
+ }
+ 
+ function $6($0) {
+  $0 = $0 | 0;
+  print($0 | 0);
+ }
+ 
+ return {
+  "one": $3, 
+  "two": $4, 
+  "three": $5, 
+  "four": $6
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    print_i32
+  });
+export var one = retasmFunc.one;
+export var two = retasmFunc.two;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function t1() {
+  return 1 | 0;
+ }
+ 
+ function t2() {
+  return 2 | 0;
+ }
+ 
+ function t3() {
+  return 3 | 0;
+ }
+ 
+ function u1() {
+  return 4 | 0;
+ }
+ 
+ function u2() {
+  return 5 | 0;
+ }
+ 
+ function $5(i) {
+  i = i | 0;
+  return FUNCTION_TABLE[i | 0]() | 0 | 0;
+ }
+ 
+ function $6(i) {
+  i = i | 0;
+  return FUNCTION_TABLE[i | 0]() | 0 | 0;
+ }
+ 
+ var FUNCTION_TABLE = [t1, t2, t3, u1, u2, t1, t3];
+ return {
+  "callt": $5, 
+  "callu": $6
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function t1() {
+  return 1 | 0;
+ }
+ 
+ function t2() {
+  return 2 | 0;
+ }
+ 
+ function $2(i) {
+  i = i | 0;
+  return FUNCTION_TABLE[i | 0]() | 0 | 0;
+ }
+ 
+ var FUNCTION_TABLE = [t1, t2];
+ return {
+  "callt": $2
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/get-set-local.2asm.js
@@ -0,0 +1,78 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $1($0, r, r$hi) {
+  $0 = $0 | 0;
+  r = r | 0;
+  r$hi = r$hi | 0;
+  var i64toi32_i32$0 = 0, $9$hi = 0;
+  i64toi32_i32$0 = r$hi;
+  i64toi32_i32$0 = 0;
+  $9$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = r$hi;
+  i64toi32_i32$0 = $9$hi;
+  return ($0 | 0) == (r | 0) & (i64toi32_i32$0 | 0) == (r$hi | 0) | 0 | 0;
+ }
+ 
+ function legalstub$1($0, $1_1, $2) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2 = $2 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $12 = 0, $3 = 0, $5 = 0, $5$hi = 0, $8$hi = 0;
+  $3 = $0;
+  i64toi32_i32$0 = 0;
+  $5 = $1_1;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $2;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return $1($3 | 0, i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ return {
+  "check_extend_ui32": legalstub$1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/get-set-local.2asm.js.opt
@@ -0,0 +1,39 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function legalstub$1($0, $1, $2) {
+  return !$2 & ($0 | 0) == ($1 | 0);
+ }
+ 
+ return {
+  "check_extend_ui32": legalstub$1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var check_extend_ui32 = retasmFunc.check_extend_ui32;
diff --git a/binaryen/test/wasm2js/get-set-local.wast b/binaryen/test/wasm2js/get-set-local.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/get-set-local.wast
@@ -0,0 +1,27 @@
+;; Tests for lowering local.get and local.set.
+
+(module
+  (func $dummy)
+
+  (func (export "check_extend_ui32") (param $0 i32) (param $r i64) (result i32)
+    (local $x i32)
+    (local $result i64)
+    (local $extend i64)
+    (local.set $x (local.get $0))
+    (local.set $result (local.get $r))
+    (local.set $extend (i64.extend_i32_u (local.get $x)))
+    (i64.eq (local.get $extend) (local.get $result)))
+)
+
+(assert_return (invoke "check_extend_ui32" (i32.const 0)
+                                           (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_extend_ui32" (i32.const 1)
+                                           (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_extend_ui32" (i32.const 0x7fffffff)
+                                           (i32.const 0x7fffffff) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_extend_ui32" (i32.const 0xffffffff)
+                                           (i32.const 0xffffffff) (i32.const 0))
+               (i32.const 1))
diff --git a/binaryen/test/wasm2js/get_local.2asm.js b/binaryen/test/wasm2js/get_local.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/get_local.2asm.js
@@ -0,0 +1,268 @@
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0() {
+  var $0_1 = 0;
+  return $0_1 | 0;
+ }
+ 
+ function $1() {
+  var i64toi32_i32$0 = 0, $0$hi = 0, $0_1 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return $0_1 | 0;
+ }
+ 
+ function $2() {
+  var $0_1 = Math_fround(0);
+  return Math_fround($0_1);
+ }
+ 
+ function $3() {
+  var $0_1 = 0.0;
+  return +$0_1;
+ }
+ 
+ function $4($0_1) {
+  $0_1 = $0_1 | 0;
+  return $0_1 | 0;
+ }
+ 
+ function $5($0_1, $0$hi) {
+  $0_1 = $0_1 | 0;
+  $0$hi = $0$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return $0_1 | 0;
+ }
+ 
+ function $6($0_1) {
+  $0_1 = Math_fround($0_1);
+  return Math_fround($0_1);
+ }
+ 
+ function $7($0_1) {
+  $0_1 = +$0_1;
+  return +$0_1;
+ }
+ 
+ function $8($0_1, $0$hi, $1_1, $2_1, $3_1, $4_1) {
+  $0_1 = $0_1 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = Math_fround($1_1);
+  $2_1 = +$2_1;
+  $3_1 = $3_1 | 0;
+  $4_1 = $4_1 | 0;
+  var i64toi32_i32$0 = 0, $5_1 = Math_fround(0), $6$hi = 0, $6_1 = 0, $7$hi = 0, $7_1 = 0, $8_1 = 0.0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $6$hi;
+  i64toi32_i32$0 = $7$hi;
+ }
+ 
+ function $9($0_1, $0$hi, $1_1, $2_1, $3_1, $4_1) {
+  $0_1 = $0_1 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = Math_fround($1_1);
+  $2_1 = +$2_1;
+  $3_1 = $3_1 | 0;
+  $4_1 = $4_1 | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $6$hi = 0, $10 = 0.0, $21 = 0.0, $7$hi = 0, $7_1 = 0;
+  i64toi32_i32$0 = 0;
+  $6$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $0_1;
+  $10 = +(i64toi32_i32$1 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0);
+  i64toi32_i32$0 = $6$hi;
+  i64toi32_i32$1 = 6;
+  $21 = +(i64toi32_i32$1 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0);
+  i64toi32_i32$0 = $7$hi;
+  i64toi32_i32$1 = $7_1;
+  return +($10 + (+$1_1 + ($2_1 + (+($3_1 >>> 0) + (+($4_1 | 0) + (+Math_fround(5.5) + ($21 + (+(i64toi32_i32$1 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0) + 8.0))))))));
+ }
+ 
+ function legalstub$1() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $1() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$5($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4_1 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4_1 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4_1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $5(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$8($0_1, $1_1, $2_1, $3_1, $4_1, $5_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = Math_fround($2_1);
+  $3_1 = +$3_1;
+  $4_1 = $4_1 | 0;
+  $5_1 = $5_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $14 = 0, $7_1 = 0, $7$hi = 0, $10$hi = 0;
+  i64toi32_i32$0 = 0;
+  $7_1 = $0_1;
+  $7$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $14 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $14 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $10$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $7$hi;
+  i64toi32_i32$0 = $7_1;
+  i64toi32_i32$2 = $10$hi;
+  i64toi32_i32$3 = $14;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $8(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0, Math_fround($2_1), +$3_1, $4_1 | 0, $5_1 | 0);
+ }
+ 
+ function legalstub$9($0_1, $1_1, $2_1, $3_1, $4_1, $5_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = Math_fround($2_1);
+  $3_1 = +$3_1;
+  $4_1 = $4_1 | 0;
+  $5_1 = $5_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $14 = 0, $7_1 = 0, $7$hi = 0, $10$hi = 0;
+  i64toi32_i32$0 = 0;
+  $7_1 = $0_1;
+  $7$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $14 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $14 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $10$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $7$hi;
+  i64toi32_i32$0 = $7_1;
+  i64toi32_i32$2 = $10$hi;
+  i64toi32_i32$3 = $14;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return +(+$9(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0, Math_fround($2_1), +$3_1, $4_1 | 0, $5_1 | 0));
+ }
+ 
+ return {
+  "type_local_i32": $0, 
+  "type_local_i64": legalstub$1, 
+  "type_local_f32": $2, 
+  "type_local_f64": $3, 
+  "type_param_i32": $4, 
+  "type_param_i64": legalstub$5, 
+  "type_param_f32": $6, 
+  "type_param_f64": $7, 
+  "type_mixed": legalstub$8, 
+  "read": legalstub$9
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var type_local_i32 = retasmFunc.type_local_i32;
+export var type_local_i64 = retasmFunc.type_local_i64;
+export var type_local_f32 = retasmFunc.type_local_f32;
+export var type_local_f64 = retasmFunc.type_local_f64;
+export var type_param_i32 = retasmFunc.type_param_i32;
+export var type_param_i64 = retasmFunc.type_param_i64;
+export var type_param_f32 = retasmFunc.type_param_f32;
+export var type_param_f64 = retasmFunc.type_param_f64;
+export var type_mixed = retasmFunc.type_mixed;
+export var read = retasmFunc.read;
diff --git a/binaryen/test/wasm2js/global_i64.2asm.js b/binaryen/test/wasm2js/global_i64.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/global_i64.2asm.js
@@ -0,0 +1,51 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var f = -1412567121;
+ var f$hi = 305419896;
+ function call($0, $0$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+ }
+ 
+ function $1() {
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = f$hi;
+  call(f | 0, i64toi32_i32$0 | 0);
+  i64toi32_i32$0 = 287454020;
+  f = 1432778632;
+  f$hi = i64toi32_i32$0;
+ }
+ 
+ return {
+  "exp": $1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/global_i64.2asm.js.opt
@@ -0,0 +1,39 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $1() {
+  
+ }
+ 
+ return {
+  "exp": $1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var exp = retasmFunc.exp;
diff --git a/binaryen/test/wasm2js/global_i64.wast b/binaryen/test/wasm2js/global_i64.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/global_i64.wast
@@ -0,0 +1,9 @@
+(module
+ (global $f (mut i64) (i64.const 0x12345678ABCDEFAF))
+ (global $g (mut i64) (global.get $f))
+ (func $call (param i64))
+ (func "exp"
+  (call $call (global.get $f))
+  (global.set $f (i64.const 0x1122334455667788))
+ )
+)
diff --git a/binaryen/test/wasm2js/grow-memory-tricky.2asm.js b/binaryen/test/wasm2js/grow-memory-tricky.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/grow-memory-tricky.2asm.js
@@ -0,0 +1,103 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.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;
+  return HEAP32[0 >> 2] | 0 | 0;
+ }
+ 
+ function $1() {
+  var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0;
+  (wasm2js_i32$0 = 0, wasm2js_i32$1 = grow() | 0), HEAP32[wasm2js_i32$0 >> 2] = wasm2js_i32$1;
+  return HEAP32[0 >> 2] | 0 | 0;
+ }
+ 
+ function grow() {
+  return __wasm_memory_grow(1 | 0) | 0;
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "memory": Object.create(Object.prototype, {
+   "grow": {
+    "value": __wasm_memory_grow
+   }, 
+   "buffer": {
+    "get": function () {
+     return buffer;
+    }
+    
+   }
+  }), 
+  "f1": $0, 
+  "f2": $1
+ };
+}
+
+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
+);
+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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/grow-memory-tricky.2asm.js.opt
@@ -0,0 +1,93 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.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;
+  return HEAP32[0];
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "memory": Object.create(Object.prototype, {
+   "grow": {
+    "value": __wasm_memory_grow
+   }, 
+   "buffer": {
+    "get": function () {
+     return buffer;
+    }
+    
+   }
+  }), 
+  "f1": $0, 
+  "f2": $0
+ };
+}
+
+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
+);
+export var memory = retasmFunc.memory;
+export var f1 = retasmFunc.f1;
+export var f2 = retasmFunc.f2;
diff --git a/binaryen/test/wasm2js/grow-memory-tricky.wast b/binaryen/test/wasm2js/grow-memory-tricky.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/grow-memory-tricky.wast
@@ -0,0 +1,30 @@
+(module
+ (type $0 (func (param i32) (result i32)))
+ (type $1 (func (result i32)))
+ (memory $0 1)
+ (export "memory" (memory $0))
+ (export "f1" (func $0))
+ (export "f2" (func $1))
+
+ (func $0 (result i32)
+  (block (result i32)
+    (i32.store (i32.const 0) (memory.grow (i32.const 1)))
+    (i32.load (i32.const 0))
+  )
+ )
+
+ (func $1 (result i32)
+  (block (result i32)
+    (i32.store (i32.const 0) (call $grow))
+    (i32.load (i32.const 0))
+  )
+ )
+
+ (func $grow (result i32)
+  (memory.grow (i32.const 1))
+ )
+)
+
+
+(assert_return (invoke "f1") (i32.const 1))
+(assert_return (invoke "f2") (i32.const 2))
diff --git a/binaryen/test/wasm2js/grow_memory.2asm.js b/binaryen/test/wasm2js/grow_memory.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/grow_memory.2asm.js
@@ -0,0 +1,96 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0(var$0) {
+  var$0 = var$0 | 0;
+  return __wasm_memory_grow(var$0 | 0) | 0;
+ }
+ 
+ function $1() {
+  return __wasm_memory_size() | 0;
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "memory": Object.create(Object.prototype, {
+   "grow": {
+    "value": __wasm_memory_grow
+   }, 
+   "buffer": {
+    "get": function () {
+     return buffer;
+    }
+    
+   }
+  }), 
+  "grow": $0, 
+  "current": $1
+ };
+}
+
+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
+);
+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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i32.2asm.js
@@ -0,0 +1,304 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x + y | 0 | 0;
+ }
+ 
+ function $1(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x - y | 0 | 0;
+ }
+ 
+ function $2(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return Math_imul(x, y) | 0;
+ }
+ 
+ function $3(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x | 0) / (y | 0) | 0 | 0;
+ }
+ 
+ function $4(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x >>> 0) / (y >>> 0) | 0 | 0;
+ }
+ 
+ function $5(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x | 0) % (y | 0) | 0 | 0;
+ }
+ 
+ function $6(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x >>> 0) % (y >>> 0) | 0 | 0;
+ }
+ 
+ function $7(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x & y | 0 | 0;
+ }
+ 
+ function $8(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x | y | 0 | 0;
+ }
+ 
+ function $9(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x ^ y | 0 | 0;
+ }
+ 
+ function $10(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x << y | 0 | 0;
+ }
+ 
+ function $11(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x >> y | 0 | 0;
+ }
+ 
+ function $12(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x >>> y | 0 | 0;
+ }
+ 
+ function $13(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return __wasm_rotl_i32(x | 0, y | 0) | 0 | 0;
+ }
+ 
+ function $14(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return __wasm_rotr_i32(x | 0, y | 0) | 0 | 0;
+ }
+ 
+ function $15(x) {
+  x = x | 0;
+  return Math_clz32(x) | 0;
+ }
+ 
+ function $16(x) {
+  x = x | 0;
+  return __wasm_ctz_i32(x | 0) | 0 | 0;
+ }
+ 
+ function $17(x) {
+  x = x | 0;
+  return __wasm_popcnt_i32(x | 0) | 0 | 0;
+ }
+ 
+ function $18(x) {
+  x = x | 0;
+  return !x | 0;
+ }
+ 
+ function $19(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x | 0) == (y | 0) | 0;
+ }
+ 
+ function $20(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x | 0) != (y | 0) | 0;
+ }
+ 
+ function $21(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x | 0) < (y | 0) | 0;
+ }
+ 
+ function $22(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x >>> 0 < y >>> 0 | 0;
+ }
+ 
+ function $23(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x | 0) <= (y | 0) | 0;
+ }
+ 
+ function $24(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x >>> 0 <= y >>> 0 | 0;
+ }
+ 
+ function $25(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x | 0) > (y | 0) | 0;
+ }
+ 
+ function $26(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x >>> 0 > y >>> 0 | 0;
+ }
+ 
+ function $27(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x | 0) >= (y | 0) | 0;
+ }
+ 
+ function $28(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return x >>> 0 >= y >>> 0 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ function __wasm_popcnt_i32(var$0) {
+  var$0 = var$0 | 0;
+  var var$1 = 0, $5_1 = 0;
+  label$1 : {
+   label$2 : while (1) {
+    $5_1 = var$1;
+    if (!var$0) {
+     break label$1
+    }
+    var$0 = var$0 & (var$0 - 1 | 0) | 0;
+    var$1 = var$1 + 1 | 0;
+    continue label$2;
+   };
+  }
+  return $5_1 | 0;
+ }
+ 
+ function __wasm_rotl_i32(var$0, var$1) {
+  var$0 = var$0 | 0;
+  var$1 = var$1 | 0;
+  var var$2 = 0;
+  var$2 = var$1 & 31 | 0;
+  var$1 = (0 - var$1 | 0) & 31 | 0;
+  return ((-1 >>> var$2 | 0) & var$0 | 0) << var$2 | 0 | (((-1 << var$1 | 0) & var$0 | 0) >>> var$1 | 0) | 0 | 0;
+ }
+ 
+ function __wasm_rotr_i32(var$0, var$1) {
+  var$0 = var$0 | 0;
+  var$1 = var$1 | 0;
+  var var$2 = 0;
+  var$2 = var$1 & 31 | 0;
+  var$1 = (0 - var$1 | 0) & 31 | 0;
+  return ((-1 << var$2 | 0) & var$0 | 0) >>> var$2 | 0 | (((-1 >>> var$1 | 0) & var$0 | 0) << var$1 | 0) | 0 | 0;
+ }
+ 
+ return {
+  "add": $0, 
+  "sub": $1, 
+  "mul": $2, 
+  "div_s": $3, 
+  "div_u": $4, 
+  "rem_s": $5, 
+  "rem_u": $6, 
+  "and": $7, 
+  "or": $8, 
+  "xor": $9, 
+  "shl": $10, 
+  "shr_s": $11, 
+  "shr_u": $12, 
+  "rotl": $13, 
+  "rotr": $14, 
+  "clz": $15, 
+  "ctz": $16, 
+  "popcnt": $17, 
+  "eqz": $18, 
+  "eq": $19, 
+  "ne": $20, 
+  "lt_s": $21, 
+  "lt_u": $22, 
+  "le_s": $23, 
+  "le_u": $24, 
+  "gt_s": $25, 
+  "gt_u": $26, 
+  "ge_s": $27, 
+  "ge_u": $28
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var add = retasmFunc.add;
+export var sub = retasmFunc.sub;
+export var mul = retasmFunc.mul;
+export var div_s = retasmFunc.div_s;
+export var div_u = retasmFunc.div_u;
+export var rem_s = retasmFunc.rem_s;
+export var rem_u = retasmFunc.rem_u;
+export var and = retasmFunc.and;
+export var or = retasmFunc.or;
+export var xor = retasmFunc.xor;
+export var shl = retasmFunc.shl;
+export var shr_s = retasmFunc.shr_s;
+export var shr_u = retasmFunc.shr_u;
+export var rotl = retasmFunc.rotl;
+export var rotr = retasmFunc.rotr;
+export var clz = retasmFunc.clz;
+export var ctz = retasmFunc.ctz;
+export var popcnt = retasmFunc.popcnt;
+export var eqz = retasmFunc.eqz;
+export var eq = retasmFunc.eq;
+export var ne = retasmFunc.ne;
+export var lt_s = retasmFunc.lt_s;
+export var lt_u = retasmFunc.lt_u;
+export var le_s = retasmFunc.le_s;
+export var le_u = retasmFunc.le_u;
+export var gt_s = retasmFunc.gt_s;
+export var gt_u = retasmFunc.gt_u;
+export var ge_s = retasmFunc.ge_s;
+export var ge_u = retasmFunc.ge_u;
diff --git a/binaryen/test/wasm2js/i64-add-sub.2asm.js b/binaryen/test/wasm2js/i64-add-sub.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-add-sub.2asm.js
@@ -0,0 +1,248 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $1($0, $0$hi, $1_1, $1$hi, r, r$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  r = r | 0;
+  r$hi = r$hi | 0;
+  var i64toi32_i32$5 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, $5$hi = 0;
+  i64toi32_i32$3 = $1_1;
+  i64toi32_i32$4 = $0 + i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = $0$hi + $1$hi | 0;
+  if (i64toi32_i32$4 >>> 0 < i64toi32_i32$3 >>> 0) {
+   i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+  }
+  $5$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = r$hi;
+  i64toi32_i32$5 = $5$hi;
+  i64toi32_i32$3 = r;
+  return (i64toi32_i32$4 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$5 | 0) == (r$hi | 0) | 0 | 0;
+ }
+ 
+ function $2($0, $0$hi, $1_1, $1$hi, r, r$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  r = r | 0;
+  r$hi = r$hi | 0;
+  var i64toi32_i32$5 = 0, i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, $5$hi = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$2 = $0;
+  i64toi32_i32$3 = $1_1;
+  i64toi32_i32$5 = (i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0) + $1$hi | 0;
+  i64toi32_i32$5 = i64toi32_i32$0 - i64toi32_i32$5 | 0;
+  $5$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = r$hi;
+  i64toi32_i32$5 = $5$hi;
+  i64toi32_i32$0 = i64toi32_i32$2 - i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = r$hi;
+  i64toi32_i32$3 = r;
+  return (i64toi32_i32$0 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$5 | 0) == (i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$1($0, $1_1, $2_1, $3, $4, $5) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3 = $3 | 0;
+  $4 = $4 | 0;
+  $5 = $5 | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $26 = 0, $27 = 0, $28 = 0, $7 = 0, $7$hi = 0, $10$hi = 0, $11 = 0, $11$hi = 0, $13 = 0, $13$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $19 = 0, $19$hi = 0, $22$hi = 0, $23 = 0, $23$hi = 0;
+  i64toi32_i32$0 = 0;
+  $7 = $0;
+  $7$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $26 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $26 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $10$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $7$hi;
+  i64toi32_i32$0 = $7;
+  i64toi32_i32$2 = $10$hi;
+  i64toi32_i32$3 = $26;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $11 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $13 = $2_1;
+  $13$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $27 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $27 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $16$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $13$hi;
+  i64toi32_i32$2 = $13;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$3 = $27;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $17 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $17$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  $19 = $4;
+  $19$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = $5;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+   $28 = 0;
+  } else {
+   i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$0 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+   $28 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+  }
+  $22$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $19$hi;
+  i64toi32_i32$1 = $19;
+  i64toi32_i32$0 = $22$hi;
+  i64toi32_i32$3 = $28;
+  i64toi32_i32$0 = i64toi32_i32$2 | i64toi32_i32$0 | 0;
+  $23 = i64toi32_i32$1 | i64toi32_i32$3 | 0;
+  $23$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$1 = $17$hi;
+  i64toi32_i32$2 = $23$hi;
+  return $1($11 | 0, i64toi32_i32$0 | 0, $17 | 0, i64toi32_i32$1 | 0, $23 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$2($0, $1_1, $2_1, $3, $4, $5) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3 = $3 | 0;
+  $4 = $4 | 0;
+  $5 = $5 | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $26 = 0, $27 = 0, $28 = 0, $7 = 0, $7$hi = 0, $10$hi = 0, $11 = 0, $11$hi = 0, $13 = 0, $13$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $19 = 0, $19$hi = 0, $22$hi = 0, $23 = 0, $23$hi = 0;
+  i64toi32_i32$0 = 0;
+  $7 = $0;
+  $7$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $26 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $26 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $10$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $7$hi;
+  i64toi32_i32$0 = $7;
+  i64toi32_i32$2 = $10$hi;
+  i64toi32_i32$3 = $26;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $11 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $13 = $2_1;
+  $13$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $27 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $27 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $16$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $13$hi;
+  i64toi32_i32$2 = $13;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$3 = $27;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $17 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $17$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  $19 = $4;
+  $19$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = $5;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+   $28 = 0;
+  } else {
+   i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$0 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+   $28 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+  }
+  $22$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $19$hi;
+  i64toi32_i32$1 = $19;
+  i64toi32_i32$0 = $22$hi;
+  i64toi32_i32$3 = $28;
+  i64toi32_i32$0 = i64toi32_i32$2 | i64toi32_i32$0 | 0;
+  $23 = i64toi32_i32$1 | i64toi32_i32$3 | 0;
+  $23$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$1 = $17$hi;
+  i64toi32_i32$2 = $23$hi;
+  return $2($11 | 0, i64toi32_i32$0 | 0, $17 | 0, i64toi32_i32$1 | 0, $23 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ return {
+  "check_add_i64": legalstub$1, 
+  "check_sub_i64": legalstub$2
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-add-sub.2asm.js.opt
@@ -0,0 +1,60 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $1($0, $1_1, $2, $3, $4, $5) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2 = $2 | 0;
+  $3 = $3 | 0;
+  $4 = $4 | 0;
+  $5 = $5 | 0;
+  $1_1 = $1_1 + $3 | 0;
+  $0 = $0 + $2 | 0;
+  if ($0 >>> 0 < $2 >>> 0) {
+   $1_1 = $1_1 + 1 | 0
+  }
+  return ($0 | 0) == ($4 | 0) & ($1_1 | 0) == ($5 | 0);
+ }
+ 
+ function legalstub$1($0, $1_1, $2, $3, $4, $5) {
+  return $1($0, $1_1, $2, $3, $4, $5);
+ }
+ 
+ function legalstub$2($0, $1_1, $2, $3, $4, $5) {
+  return ($4 | 0) == ($0 - $2 | 0) & ($5 | 0) == ($1_1 - (($0 >>> 0 < $2 >>> 0) + $3 | 0) | 0);
+ }
+ 
+ return {
+  "check_add_i64": legalstub$1, 
+  "check_sub_i64": legalstub$2
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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.wast b/binaryen/test/wasm2js/i64-add-sub.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-add-sub.wast
@@ -0,0 +1,66 @@
+;; Testing i64 lowering for addition and subtraction.
+
+(module
+  (func $dummy)
+
+  (func (export "check_add_i64") (param $0 i64) (param $1 i64) (param $r i64) (result i32)
+    (i64.eq (i64.add (local.get $0) (local.get $1)) (local.get $r)))
+
+  (func (export "check_sub_i64") (param $0 i64) (param $1 i64) (param $r i64) (result i32)
+    (i64.eq (i64.sub (local.get $0) (local.get $1)) (local.get $r)))
+)
+
+(assert_return (invoke "check_add_i64" (i32.const 0) (i32.const 0)
+                                       (i32.const 0) (i32.const 0)
+                                       (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_add_i64" (i32.const 1) (i32.const 0)
+                                       (i32.const 0) (i32.const 0)
+                                       (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_add_i64" (i32.const 0) (i32.const 0)
+                                       (i32.const 1) (i32.const 0)
+                                       (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_add_i64" (i32.const 0) (i32.const 1)
+                                       (i32.const 0) (i32.const 0)
+                                       (i32.const 0) (i32.const 1))
+               (i32.const 1))
+(assert_return (invoke "check_add_i64" (i32.const 0) (i32.const 0)
+                                       (i32.const 0) (i32.const 1)
+                                       (i32.const 0) (i32.const 1))
+               (i32.const 1))
+(assert_return (invoke "check_add_i64" (i32.const 0xffffffff) (i32.const 0)
+                                       (i32.const 1) (i32.const 0)
+                                       (i32.const 0) (i32.const 1))
+               (i32.const 1))
+
+;; subtraction
+(assert_return (invoke "check_sub_i64" (i32.const 0) (i32.const 0)
+                                       (i32.const 0) (i32.const 0)
+                                       (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_sub_i64" (i32.const 1) (i32.const 0)
+                                       (i32.const 0) (i32.const 0)
+                                       (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_sub_i64" (i32.const 0) (i32.const 0)
+                                       (i32.const 1) (i32.const 0)
+                                       (i32.const 0xffffffff) (i32.const 0xffffffff))
+               (i32.const 1))
+(assert_return (invoke "check_sub_i64" (i32.const 0) (i32.const 1)
+                                       (i32.const 0) (i32.const 0)
+                                       (i32.const 0) (i32.const 1))
+               (i32.const 1))
+(assert_return (invoke "check_sub_i64" (i32.const 0) (i32.const 0)
+                                       (i32.const 0) (i32.const 1)
+                                       (i32.const 0) (i32.const 0xffffffff))
+               (i32.const 1))
+(assert_return (invoke "check_sub_i64" (i32.const 0xffffffff) (i32.const 0)
+                                       (i32.const 1) (i32.const 0)
+                                       (i32.const 0xfffffffe) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_sub_i64" (i32.const 0) (i32.const 1)
+                                       (i32.const 1) (i32.const 1)
+                                       (i32.const 0xffffffff) (i32.const 0xffffffff))
+               (i32.const 1))
diff --git a/binaryen/test/wasm2js/i64-ctz.2asm.js b/binaryen/test/wasm2js/i64-ctz.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-ctz.2asm.js
@@ -0,0 +1,252 @@
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function popcnt64($0, $0$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = __wasm_popcnt_i64($0 | 0, i64toi32_i32$0 | 0) | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$0 | 0;
+ }
+ 
+ function ctz64($0, $0$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = __wasm_ctz_i64($0 | 0, i64toi32_i32$0 | 0) | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$0 | 0;
+ }
+ 
+ function legalstub$popcnt64($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = popcnt64(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2 | 0;
+ }
+ 
+ function legalstub$ctz64($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = ctz64(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2 | 0;
+ }
+ 
+ function __wasm_ctz_i64(var$0, var$0$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, i64toi32_i32$4 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, $10 = 0, $5$hi = 0, $8$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  if (!!(var$0 | i64toi32_i32$0 | 0)) {
+   i64toi32_i32$0 = var$0$hi;
+   i64toi32_i32$2 = var$0;
+   i64toi32_i32$1 = -1;
+   i64toi32_i32$3 = -1;
+   i64toi32_i32$4 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+   i64toi32_i32$5 = i64toi32_i32$0 + i64toi32_i32$1 | 0;
+   if (i64toi32_i32$4 >>> 0 < i64toi32_i32$3 >>> 0) {
+    i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+   }
+   $5$hi = i64toi32_i32$5;
+   i64toi32_i32$5 = var$0$hi;
+   i64toi32_i32$5 = $5$hi;
+   i64toi32_i32$0 = i64toi32_i32$4;
+   i64toi32_i32$2 = var$0$hi;
+   i64toi32_i32$3 = var$0;
+   i64toi32_i32$2 = i64toi32_i32$5 ^ i64toi32_i32$2 | 0;
+   i64toi32_i32$0 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+   i64toi32_i32$3 = Math_clz32(i64toi32_i32$2);
+   i64toi32_i32$5 = 0;
+   if ((i64toi32_i32$3 | 0) == (32 | 0)) {
+    $10 = Math_clz32(i64toi32_i32$0) + 32 | 0
+   } else {
+    $10 = i64toi32_i32$3
+   }
+   $8$hi = i64toi32_i32$5;
+   i64toi32_i32$5 = 0;
+   i64toi32_i32$0 = 63;
+   i64toi32_i32$2 = $8$hi;
+   i64toi32_i32$3 = $10;
+   i64toi32_i32$1 = i64toi32_i32$0 - i64toi32_i32$3 | 0;
+   i64toi32_i32$4 = (i64toi32_i32$0 >>> 0 < i64toi32_i32$3 >>> 0) + i64toi32_i32$2 | 0;
+   i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+   i64toi32_i32$0 = i64toi32_i32$1;
+   i64toi32_i32$HIGH_BITS = i64toi32_i32$4;
+   return i64toi32_i32$0 | 0;
+  }
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$4 = 64;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$4 | 0;
+ }
+ 
+ function __wasm_popcnt_i64(var$0, var$0$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$5 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$1 = 0, var$1$hi = 0, var$1 = 0, $5 = 0, $5$hi = 0, $4 = 0, $9$hi = 0;
+  label$1 : {
+   label$2 : while (1) {
+    i64toi32_i32$0 = var$1$hi;
+    i64toi32_i32$0 = var$0$hi;
+    $4 = !(var$0 | i64toi32_i32$0 | 0);
+    i64toi32_i32$0 = var$1$hi;
+    $5 = var$1;
+    $5$hi = i64toi32_i32$0;
+    if ($4) {
+     break label$1
+    }
+    i64toi32_i32$0 = $5$hi;
+    i64toi32_i32$0 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = 0;
+    i64toi32_i32$3 = 1;
+    i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$3 | 0;
+    i64toi32_i32$5 = (i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0) + i64toi32_i32$1 | 0;
+    i64toi32_i32$5 = i64toi32_i32$0 - i64toi32_i32$5 | 0;
+    $9$hi = i64toi32_i32$5;
+    i64toi32_i32$5 = i64toi32_i32$0;
+    i64toi32_i32$0 = i64toi32_i32$2;
+    i64toi32_i32$2 = $9$hi;
+    i64toi32_i32$3 = i64toi32_i32$4;
+    i64toi32_i32$2 = i64toi32_i32$5 & i64toi32_i32$2 | 0;
+    var$0 = i64toi32_i32$0 & i64toi32_i32$4 | 0;
+    var$0$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$1$hi;
+    i64toi32_i32$5 = var$1;
+    i64toi32_i32$0 = 0;
+    i64toi32_i32$3 = 1;
+    i64toi32_i32$1 = i64toi32_i32$5 + i64toi32_i32$3 | 0;
+    i64toi32_i32$4 = i64toi32_i32$2 + i64toi32_i32$0 | 0;
+    if (i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0) {
+     i64toi32_i32$4 = i64toi32_i32$4 + 1 | 0
+    }
+    var$1 = i64toi32_i32$1;
+    var$1$hi = i64toi32_i32$4;
+    continue label$2;
+   };
+  }
+  i64toi32_i32$4 = $5$hi;
+  i64toi32_i32$5 = $5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$4;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ return {
+  "a": legalstub$popcnt64, 
+  "b": legalstub$ctz64
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var a = retasmFunc.a;
+export var b = retasmFunc.b;
diff --git a/binaryen/test/wasm2js/i64-ctz.2asm.js.opt b/binaryen/test/wasm2js/i64-ctz.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-ctz.2asm.js.opt
@@ -0,0 +1,94 @@
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function legalstub$popcnt64($0, $1) {
+  $0 = __wasm_popcnt_i64($0, $1);
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0;
+ }
+ 
+ function legalstub$ctz64($0, $1) {
+  $0 = __wasm_ctz_i64($0, $1);
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0;
+ }
+ 
+ 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;
+   $1 = 63 - $0 | 0;
+   i64toi32_i32$HIGH_BITS = 0 - (63 < $0 >>> 0) | 0;
+   return $1;
+  }
+  i64toi32_i32$HIGH_BITS = 0;
+  return 64;
+ }
+ 
+ function __wasm_popcnt_i64($0, $1) {
+  var $2 = 0, $3 = 0, $4 = 0, $5 = 0;
+  while (1) {
+   $5 = $3;
+   $2 = $4;
+   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;
+    continue;
+   }
+   break;
+  };
+  i64toi32_i32$HIGH_BITS = $2;
+  return $5;
+ }
+ 
+ return {
+  "a": legalstub$popcnt64, 
+  "b": legalstub$ctz64
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var a = retasmFunc.a;
+export var b = retasmFunc.b;
diff --git a/binaryen/test/wasm2js/i64-ctz.wast b/binaryen/test/wasm2js/i64-ctz.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-ctz.wast
@@ -0,0 +1,8 @@
+(module
+ (export "a" (func $popcnt64))
+ (export "b" (func $ctz64))
+ (func $popcnt64 (param $0 i64) (result i64)
+   (i64.popcnt (local.get $0)))
+ (func $ctz64 (param $0 i64) (result i64)
+   (i64.ctz (local.get $0)))
+ )
diff --git a/binaryen/test/wasm2js/i64-lowering.2asm.js b/binaryen/test/wasm2js/i64-lowering.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-lowering.2asm.js
@@ -0,0 +1,815 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $1($0, $0$hi, $1_1, $1$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$0 = $0$hi;
+  return ($0 | 0) == ($1_1 | 0) & (i64toi32_i32$0 | 0) == ($1$hi | 0) | 0 | 0;
+ }
+ 
+ function $2($0, $0$hi, $1_1, $1$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$0 = $0$hi;
+  return ($0 | 0) != ($1_1 | 0) | (i64toi32_i32$0 | 0) != ($1$hi | 0) | 0 | 0;
+ }
+ 
+ function $3($0, $0$hi, $1_1, $1$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  var i64toi32_i32$0 = 0, $8_1 = 0, $9_1 = 0, $10_1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$2 = $0;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$3 = $1_1;
+  if ((i64toi32_i32$0 | 0) > ($1$hi | 0)) {
+   $8_1 = 1
+  } else {
+   if ((i64toi32_i32$0 | 0) >= (i64toi32_i32$1 | 0)) {
+    if (i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0) {
+     $9_1 = 0
+    } else {
+     $9_1 = 1
+    }
+    $10_1 = $9_1;
+   } else {
+    $10_1 = 0
+   }
+   $8_1 = $10_1;
+  }
+  return $8_1 | 0;
+ }
+ 
+ function $4($0, $0$hi, $1_1, $1$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  var i64toi32_i32$0 = 0, $8_1 = 0, $9_1 = 0, $10_1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$2 = $0;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$3 = $1_1;
+  if ((i64toi32_i32$0 | 0) > ($1$hi | 0)) {
+   $8_1 = 1
+  } else {
+   if ((i64toi32_i32$0 | 0) >= (i64toi32_i32$1 | 0)) {
+    if (i64toi32_i32$2 >>> 0 <= i64toi32_i32$3 >>> 0) {
+     $9_1 = 0
+    } else {
+     $9_1 = 1
+    }
+    $10_1 = $9_1;
+   } else {
+    $10_1 = 0
+   }
+   $8_1 = $10_1;
+  }
+  return $8_1 | 0;
+ }
+ 
+ function $5($0, $0$hi, $1_1, $1$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  var i64toi32_i32$0 = 0, $8_1 = 0, $9_1 = 0, $10_1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$2 = $0;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$3 = $1_1;
+  if ((i64toi32_i32$0 | 0) < ($1$hi | 0)) {
+   $8_1 = 1
+  } else {
+   if ((i64toi32_i32$0 | 0) <= (i64toi32_i32$1 | 0)) {
+    if (i64toi32_i32$2 >>> 0 > i64toi32_i32$3 >>> 0) {
+     $9_1 = 0
+    } else {
+     $9_1 = 1
+    }
+    $10_1 = $9_1;
+   } else {
+    $10_1 = 0
+   }
+   $8_1 = $10_1;
+  }
+  return $8_1 | 0;
+ }
+ 
+ function $6($0, $0$hi, $1_1, $1$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  var i64toi32_i32$0 = 0, $8_1 = 0, $9_1 = 0, $10_1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$2 = $0;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$3 = $1_1;
+  if ((i64toi32_i32$0 | 0) < ($1$hi | 0)) {
+   $8_1 = 1
+  } else {
+   if ((i64toi32_i32$0 | 0) <= (i64toi32_i32$1 | 0)) {
+    if (i64toi32_i32$2 >>> 0 >= i64toi32_i32$3 >>> 0) {
+     $9_1 = 0
+    } else {
+     $9_1 = 1
+    }
+    $10_1 = $9_1;
+   } else {
+    $10_1 = 0
+   }
+   $8_1 = $10_1;
+  }
+  return $8_1 | 0;
+ }
+ 
+ function $7($0, $0$hi, $1_1, $1$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$0 = $0$hi;
+  return i64toi32_i32$0 >>> 0 > $1$hi >>> 0 | ((i64toi32_i32$0 | 0) == ($1$hi | 0) & $0 >>> 0 >= $1_1 >>> 0 | 0) | 0 | 0;
+ }
+ 
+ function $8($0, $0$hi, $1_1, $1$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$0 = $0$hi;
+  return i64toi32_i32$0 >>> 0 > $1$hi >>> 0 | ((i64toi32_i32$0 | 0) == ($1$hi | 0) & $0 >>> 0 > $1_1 >>> 0 | 0) | 0 | 0;
+ }
+ 
+ function $9($0, $0$hi, $1_1, $1$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$0 = $0$hi;
+  return i64toi32_i32$0 >>> 0 < $1$hi >>> 0 | ((i64toi32_i32$0 | 0) == ($1$hi | 0) & $0 >>> 0 <= $1_1 >>> 0 | 0) | 0 | 0;
+ }
+ 
+ function $10($0, $0$hi, $1_1, $1$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$0 = $0$hi;
+  return i64toi32_i32$0 >>> 0 < $1$hi >>> 0 | ((i64toi32_i32$0 | 0) == ($1$hi | 0) & $0 >>> 0 < $1_1 >>> 0 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$1($0, $1_1, $2_1, $3_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5_1 = 0, $5$hi = 0, $8$hi = 0, $9_1 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5_1 = $0;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5_1;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9_1 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  return $1($9_1 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$2($0, $1_1, $2_1, $3_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5_1 = 0, $5$hi = 0, $8$hi = 0, $9_1 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5_1 = $0;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5_1;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9_1 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  return $2($9_1 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$3($0, $1_1, $2_1, $3_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5_1 = 0, $5$hi = 0, $8$hi = 0, $9_1 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5_1 = $0;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5_1;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9_1 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  return $3($9_1 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$4($0, $1_1, $2_1, $3_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5_1 = 0, $5$hi = 0, $8$hi = 0, $9_1 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5_1 = $0;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5_1;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9_1 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  return $4($9_1 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$5($0, $1_1, $2_1, $3_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5_1 = 0, $5$hi = 0, $8$hi = 0, $9_1 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5_1 = $0;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5_1;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9_1 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  return $5($9_1 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$6($0, $1_1, $2_1, $3_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5_1 = 0, $5$hi = 0, $8$hi = 0, $9_1 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5_1 = $0;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5_1;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9_1 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  return $6($9_1 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$7($0, $1_1, $2_1, $3_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5_1 = 0, $5$hi = 0, $8$hi = 0, $9_1 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5_1 = $0;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5_1;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9_1 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  return $7($9_1 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$8($0, $1_1, $2_1, $3_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5_1 = 0, $5$hi = 0, $8$hi = 0, $9_1 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5_1 = $0;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5_1;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9_1 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  return $8($9_1 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$9($0, $1_1, $2_1, $3_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5_1 = 0, $5$hi = 0, $8$hi = 0, $9_1 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5_1 = $0;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5_1;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9_1 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  return $9($9_1 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$10($0, $1_1, $2_1, $3_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5_1 = 0, $5$hi = 0, $8$hi = 0, $9_1 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5_1 = $0;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5_1;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9_1 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  return $10($9_1 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ return {
+  "eq_i64": legalstub$1, 
+  "ne_i64": legalstub$2, 
+  "ge_s_i64": legalstub$3, 
+  "gt_s_i64": legalstub$4, 
+  "le_s_i64": legalstub$5, 
+  "lt_s_i64": legalstub$6, 
+  "ge_u_i64": legalstub$7, 
+  "gt_u_i64": legalstub$8, 
+  "le_u_i64": legalstub$9, 
+  "lt_u_i64": legalstub$10
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var eq_i64 = retasmFunc.eq_i64;
+export var ne_i64 = retasmFunc.ne_i64;
+export var ge_s_i64 = retasmFunc.ge_s_i64;
+export var gt_s_i64 = retasmFunc.gt_s_i64;
+export var le_s_i64 = retasmFunc.le_s_i64;
+export var lt_s_i64 = retasmFunc.lt_s_i64;
+export var ge_u_i64 = retasmFunc.ge_u_i64;
+export var gt_u_i64 = retasmFunc.gt_u_i64;
+export var le_u_i64 = retasmFunc.le_u_i64;
+export var lt_u_i64 = retasmFunc.lt_u_i64;
diff --git a/binaryen/test/wasm2js/i64-lowering.2asm.js.opt b/binaryen/test/wasm2js/i64-lowering.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-lowering.2asm.js.opt
@@ -0,0 +1,93 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function legalstub$1($0, $1, $2, $3) {
+  return ($0 | 0) == ($2 | 0) & ($1 | 0) == ($3 | 0);
+ }
+ 
+ function legalstub$2($0, $1, $2, $3) {
+  return ($0 | 0) != ($2 | 0) | ($1 | 0) != ($3 | 0);
+ }
+ 
+ function legalstub$3($0, $1, $2, $3) {
+  return ($1 | 0) > ($3 | 0) ? 1 : ($1 | 0) >= ($3 | 0) ? $0 >>> 0 >= $2 >>> 0 : 0;
+ }
+ 
+ function legalstub$4($0, $1, $2, $3) {
+  return ($1 | 0) > ($3 | 0) ? 1 : ($1 | 0) >= ($3 | 0) ? $0 >>> 0 > $2 >>> 0 : 0;
+ }
+ 
+ function legalstub$5($0, $1, $2, $3) {
+  return ($1 | 0) < ($3 | 0) ? 1 : ($1 | 0) <= ($3 | 0) ? $0 >>> 0 <= $2 >>> 0 : 0;
+ }
+ 
+ function legalstub$6($0, $1, $2, $3) {
+  return ($1 | 0) < ($3 | 0) ? 1 : ($1 | 0) <= ($3 | 0) ? $0 >>> 0 < $2 >>> 0 : 0;
+ }
+ 
+ function legalstub$7($0, $1, $2, $3) {
+  return ($1 | 0) == ($3 | 0) & $0 >>> 0 >= $2 >>> 0 | $1 >>> 0 > $3 >>> 0;
+ }
+ 
+ function legalstub$8($0, $1, $2, $3) {
+  return ($1 | 0) == ($3 | 0) & $0 >>> 0 > $2 >>> 0 | $1 >>> 0 > $3 >>> 0;
+ }
+ 
+ function legalstub$9($0, $1, $2, $3) {
+  return ($1 | 0) == ($3 | 0) & $0 >>> 0 <= $2 >>> 0 | $1 >>> 0 < $3 >>> 0;
+ }
+ 
+ function legalstub$10($0, $1, $2, $3) {
+  return ($1 | 0) == ($3 | 0) & $0 >>> 0 < $2 >>> 0 | $1 >>> 0 < $3 >>> 0;
+ }
+ 
+ return {
+  "eq_i64": legalstub$1, 
+  "ne_i64": legalstub$2, 
+  "ge_s_i64": legalstub$3, 
+  "gt_s_i64": legalstub$4, 
+  "le_s_i64": legalstub$5, 
+  "lt_s_i64": legalstub$6, 
+  "ge_u_i64": legalstub$7, 
+  "gt_u_i64": legalstub$8, 
+  "le_u_i64": legalstub$9, 
+  "lt_u_i64": legalstub$10
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var eq_i64 = retasmFunc.eq_i64;
+export var ne_i64 = retasmFunc.ne_i64;
+export var ge_s_i64 = retasmFunc.ge_s_i64;
+export var gt_s_i64 = retasmFunc.gt_s_i64;
+export var le_s_i64 = retasmFunc.le_s_i64;
+export var lt_s_i64 = retasmFunc.lt_s_i64;
+export var ge_u_i64 = retasmFunc.ge_u_i64;
+export var gt_u_i64 = retasmFunc.gt_u_i64;
+export var le_u_i64 = retasmFunc.le_u_i64;
+export var lt_u_i64 = retasmFunc.lt_u_i64;
diff --git a/binaryen/test/wasm2js/i64-lowering.wast b/binaryen/test/wasm2js/i64-lowering.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-lowering.wast
@@ -0,0 +1,269 @@
+;; Testing i64 lowering.
+
+(module
+  (func $dummy)
+
+  (func (export "eq_i64") (param $0 i64) (param $1 i64) (result i32)
+    (i64.eq (local.get $0) (local.get $1)))
+
+  (func (export "ne_i64") (param $0 i64) (param $1 i64) (result i32)
+    (i64.ne (local.get $0) (local.get $1)))
+
+  (func (export "ge_s_i64") (param $0 i64) (param $1 i64) (result i32)
+    (i64.ge_s (local.get $0) (local.get $1)))
+
+  (func (export "gt_s_i64") (param $0 i64) (param $1 i64) (result i32)
+    (i64.gt_s (local.get $0) (local.get $1)))
+
+  (func (export "le_s_i64") (param $0 i64) (param $1 i64) (result i32)
+    (i64.le_s (local.get $0) (local.get $1)))
+
+  (func (export "lt_s_i64") (param $0 i64) (param $1 i64) (result i32)
+    (i64.lt_s (local.get $0) (local.get $1)))
+
+  (func (export "ge_u_i64") (param $0 i64) (param $1 i64) (result i32)
+    (i64.ge_u (local.get $0) (local.get $1)))
+
+  (func (export "gt_u_i64") (param $0 i64) (param $1 i64) (result i32)
+    (i64.gt_u (local.get $0) (local.get $1)))
+
+  (func (export "le_u_i64") (param $0 i64) (param $1 i64) (result i32)
+    (i64.le_u (local.get $0) (local.get $1)))
+
+  (func (export "lt_u_i64") (param $0 i64) (param $1 i64) (result i32)
+    (i64.lt_u (local.get $0) (local.get $1)))
+)
+
+;; TODO: change things so we can invoke with i64 args and automatically lower
+;; the arguments, rather than doing it manually.
+(assert_return (invoke "eq_i64" (i32.const 0) (i32.const 0)
+                                (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "eq_i64" (i32.const 0) (i32.const 0)
+                                (i32.const 0) (i32.const 1))
+               (i32.const 0))
+(assert_return (invoke "eq_i64" (i32.const 1) (i32.const 0)
+                                (i32.const 0) (i32.const 1))
+               (i32.const 0))
+
+(assert_return (invoke "ne_i64" (i32.const 0) (i32.const 0)
+                                (i32.const 0) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "ne_i64" (i32.const 0) (i32.const 0)
+                                (i32.const 0) (i32.const 1))
+               (i32.const 1))
+(assert_return (invoke "ne_i64" (i32.const 1) (i32.const 0)
+                                (i32.const 0) (i32.const 1))
+               (i32.const 1))
+
+(assert_return (invoke "lt_u_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "lt_u_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "lt_u_i64" (i32.const 1) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "lt_u_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 1))
+               (i32.const 1))
+(assert_return (invoke "lt_u_i64" (i32.const 0) (i32.const 1)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "lt_u_i64" (i32.const 0) (i32.const 0xffffffff)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 0))
+
+(assert_return (invoke "gt_u_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "gt_u_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "gt_u_i64" (i32.const 1) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "gt_u_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 1))
+               (i32.const 0))
+(assert_return (invoke "gt_u_i64" (i32.const 0) (i32.const 1)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "gt_u_i64" (i32.const 0) (i32.const 0xffffffff)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 1))
+
+(assert_return (invoke "le_u_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "le_u_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "le_u_i64" (i32.const 1) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "le_u_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 1))
+               (i32.const 1))
+(assert_return (invoke "le_u_i64" (i32.const 0) (i32.const 1)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "le_u_i64" (i32.const 0) (i32.const 0xffffffff)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 0))
+
+(assert_return (invoke "ge_u_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "ge_u_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "ge_u_i64" (i32.const 1) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "ge_u_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 1))
+               (i32.const 0))
+(assert_return (invoke "ge_u_i64" (i32.const 0) (i32.const 1)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "ge_u_i64" (i32.const 0) (i32.const 0xffffffff)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 1))
+
+(assert_return (invoke "lt_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "lt_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "lt_s_i64" (i32.const 1) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "lt_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 1))
+               (i32.const 1))
+(assert_return (invoke "lt_s_i64" (i32.const 0) (i32.const 1)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "lt_s_i64" (i32.const 0) (i32.const 0xffffffff)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "lt_s_i64" (i32.const 1) (i32.const 0)
+                                  (i32.const 0) (i32.const 0xffffffff))
+               (i32.const 0))
+(assert_return (invoke "lt_s_i64" (i32.const 0) (i32.const 0xffffffff)
+                                  (i32.const 1) (i32.const 0xffffffff))
+               (i32.const 1))
+(assert_return (invoke "lt_s_i64" (i32.const 1) (i32.const 0xffffffff)
+                                  (i32.const 0) (i32.const 0xffffffff))
+               (i32.const 0))
+(assert_return (invoke "lt_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 0x80000000))
+               (i32.const 0))
+(assert_return (invoke "lt_s_i64" (i32.const 0) (i32.const 0x80000000)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 1))
+
+(assert_return (invoke "gt_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "gt_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "gt_s_i64" (i32.const 1) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "gt_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 1))
+               (i32.const 0))
+(assert_return (invoke "gt_s_i64" (i32.const 0) (i32.const 1)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "gt_s_i64" (i32.const 0) (i32.const 0xffffffff)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "gt_s_i64" (i32.const 1) (i32.const 0)
+                                  (i32.const 0) (i32.const 0xffffffff))
+               (i32.const 1))
+(assert_return (invoke "gt_s_i64" (i32.const 0) (i32.const 0xffffffff)
+                                  (i32.const 1) (i32.const 0xffffffff))
+               (i32.const 0))
+(assert_return (invoke "gt_s_i64" (i32.const 1) (i32.const 0xffffffff)
+                                  (i32.const 0) (i32.const 0xffffffff))
+               (i32.const 1))
+(assert_return (invoke "gt_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 0x80000000))
+               (i32.const 1))
+(assert_return (invoke "gt_s_i64" (i32.const 0) (i32.const 0x80000000)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 0))
+
+(assert_return (invoke "le_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "le_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "le_s_i64" (i32.const 1) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "le_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 1))
+               (i32.const 1))
+(assert_return (invoke "le_s_i64" (i32.const 0) (i32.const 1)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "le_s_i64" (i32.const 0) (i32.const 0xffffffff)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "le_s_i64" (i32.const 1) (i32.const 0)
+                                  (i32.const 0) (i32.const 0xffffffff))
+               (i32.const 0))
+(assert_return (invoke "le_s_i64" (i32.const 0) (i32.const 0xffffffff)
+                                  (i32.const 1) (i32.const 0xffffffff))
+               (i32.const 1))
+(assert_return (invoke "le_s_i64" (i32.const 1) (i32.const 0xffffffff)
+                                  (i32.const 0) (i32.const 0xffffffff))
+               (i32.const 0))
+(assert_return (invoke "le_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 0x80000000))
+               (i32.const 0))
+(assert_return (invoke "le_s_i64" (i32.const 0) (i32.const 0x80000000)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 1))
+
+(assert_return (invoke "ge_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "ge_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "ge_s_i64" (i32.const 1) (i32.const 0)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "ge_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 1))
+               (i32.const 0))
+(assert_return (invoke "ge_s_i64" (i32.const 0) (i32.const 1)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "ge_s_i64" (i32.const 0) (i32.const 0xffffffff)
+                                  (i32.const 1) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "ge_s_i64" (i32.const 1) (i32.const 0)
+                                  (i32.const 0) (i32.const 0xffffffff))
+               (i32.const 1))
+(assert_return (invoke "ge_s_i64" (i32.const 0) (i32.const 0xffffffff)
+                                  (i32.const 1) (i32.const 0xffffffff))
+               (i32.const 0))
+(assert_return (invoke "ge_s_i64" (i32.const 1) (i32.const 0xffffffff)
+                                  (i32.const 0) (i32.const 0xffffffff))
+               (i32.const 1))
+(assert_return (invoke "ge_s_i64" (i32.const 0) (i32.const 0)
+                                  (i32.const 0) (i32.const 0x80000000))
+               (i32.const 1))
+(assert_return (invoke "ge_s_i64" (i32.const 0) (i32.const 0x80000000)
+                                  (i32.const 0) (i32.const 0))
+               (i32.const 0))
diff --git a/binaryen/test/wasm2js/i64-rotate.2asm.js b/binaryen/test/wasm2js/i64-rotate.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-rotate.2asm.js
@@ -0,0 +1,460 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $1($0, $0$hi, $1_1, $1$hi, $2_1, $2$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  $2_1 = $2_1 | 0;
+  $2$hi = $2$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $5$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$1 = __wasm_rotl_i64($0 | 0, i64toi32_i32$0 | 0, $1_1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $2$hi;
+  i64toi32_i32$0 = $5$hi;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$1 = $2$hi;
+  return (i64toi32_i32$2 | 0) == ($2_1 | 0) & (i64toi32_i32$0 | 0) == (i64toi32_i32$1 | 0) | 0 | 0;
+ }
+ 
+ function $2($0, $0$hi, $1_1, $1$hi, $2_1, $2$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  $2_1 = $2_1 | 0;
+  $2$hi = $2$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $5$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$1 = __wasm_rotr_i64($0 | 0, i64toi32_i32$0 | 0, $1_1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $2$hi;
+  i64toi32_i32$0 = $5$hi;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$1 = $2$hi;
+  return (i64toi32_i32$2 | 0) == ($2_1 | 0) & (i64toi32_i32$0 | 0) == (i64toi32_i32$1 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$1($0, $1_1, $2_1, $3, $4, $5) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3 = $3 | 0;
+  $4 = $4 | 0;
+  $5 = $5 | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $26 = 0, $27 = 0, $28 = 0, $7 = 0, $7$hi = 0, $10$hi = 0, $11 = 0, $11$hi = 0, $13 = 0, $13$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $19 = 0, $19$hi = 0, $22$hi = 0, $23 = 0, $23$hi = 0;
+  i64toi32_i32$0 = 0;
+  $7 = $0;
+  $7$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $26 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $26 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $10$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $7$hi;
+  i64toi32_i32$0 = $7;
+  i64toi32_i32$2 = $10$hi;
+  i64toi32_i32$3 = $26;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $11 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $13 = $2_1;
+  $13$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $27 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $27 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $16$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $13$hi;
+  i64toi32_i32$2 = $13;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$3 = $27;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $17 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $17$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  $19 = $4;
+  $19$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = $5;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+   $28 = 0;
+  } else {
+   i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$0 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+   $28 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+  }
+  $22$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $19$hi;
+  i64toi32_i32$1 = $19;
+  i64toi32_i32$0 = $22$hi;
+  i64toi32_i32$3 = $28;
+  i64toi32_i32$0 = i64toi32_i32$2 | i64toi32_i32$0 | 0;
+  $23 = i64toi32_i32$1 | i64toi32_i32$3 | 0;
+  $23$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$1 = $17$hi;
+  i64toi32_i32$2 = $23$hi;
+  return $1($11 | 0, i64toi32_i32$0 | 0, $17 | 0, i64toi32_i32$1 | 0, $23 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$2($0, $1_1, $2_1, $3, $4, $5) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3 = $3 | 0;
+  $4 = $4 | 0;
+  $5 = $5 | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $26 = 0, $27 = 0, $28 = 0, $7 = 0, $7$hi = 0, $10$hi = 0, $11 = 0, $11$hi = 0, $13 = 0, $13$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $19 = 0, $19$hi = 0, $22$hi = 0, $23 = 0, $23$hi = 0;
+  i64toi32_i32$0 = 0;
+  $7 = $0;
+  $7$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $26 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $26 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $10$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $7$hi;
+  i64toi32_i32$0 = $7;
+  i64toi32_i32$2 = $10$hi;
+  i64toi32_i32$3 = $26;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $11 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $13 = $2_1;
+  $13$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $27 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $27 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $16$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $13$hi;
+  i64toi32_i32$2 = $13;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$3 = $27;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $17 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $17$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  $19 = $4;
+  $19$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = $5;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+   $28 = 0;
+  } else {
+   i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$0 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+   $28 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+  }
+  $22$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $19$hi;
+  i64toi32_i32$1 = $19;
+  i64toi32_i32$0 = $22$hi;
+  i64toi32_i32$3 = $28;
+  i64toi32_i32$0 = i64toi32_i32$2 | i64toi32_i32$0 | 0;
+  $23 = i64toi32_i32$1 | i64toi32_i32$3 | 0;
+  $23$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$1 = $17$hi;
+  i64toi32_i32$2 = $23$hi;
+  return $2($11 | 0, i64toi32_i32$0 | 0, $17 | 0, i64toi32_i32$1 | 0, $23 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function __wasm_rotl_i64(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, i64toi32_i32$4 = 0, var$2$hi = 0, var$2 = 0, $19 = 0, $20 = 0, $21 = 0, $22 = 0, $6$hi = 0, $8$hi = 0, $10 = 0, $10$hi = 0, $15$hi = 0, $17$hi = 0, $19$hi = 0;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$1 = i64toi32_i32$0 & i64toi32_i32$1 | 0;
+  var$2 = i64toi32_i32$2 & i64toi32_i32$3 | 0;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = -1;
+  i64toi32_i32$0 = -1;
+  i64toi32_i32$2 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $19 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $19 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  $6$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$2 = $6$hi;
+  i64toi32_i32$1 = $19;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$0 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+  $8$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$0 = $8$hi;
+  i64toi32_i32$2 = i64toi32_i32$1 & i64toi32_i32$3 | 0;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $10 = $20;
+  $10$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$4 = i64toi32_i32$0 - i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = (i64toi32_i32$0 >>> 0 < i64toi32_i32$3 >>> 0) + i64toi32_i32$2 | 0;
+  i64toi32_i32$5 = i64toi32_i32$1 - i64toi32_i32$5 | 0;
+  i64toi32_i32$1 = i64toi32_i32$4;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$5 & i64toi32_i32$0 | 0;
+  var$1 = i64toi32_i32$1 & i64toi32_i32$3 | 0;
+  var$1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = -1;
+  i64toi32_i32$5 = -1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 << i64toi32_i32$2 | 0;
+   $21 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$2 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$2 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$2 | 0) | 0;
+   $21 = i64toi32_i32$5 << i64toi32_i32$2 | 0;
+  }
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = $15$hi;
+  i64toi32_i32$0 = $21;
+  i64toi32_i32$5 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$5 = i64toi32_i32$1 & i64toi32_i32$5 | 0;
+  $17$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$5 = $17$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 & i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $22 = i64toi32_i32$5 >>> i64toi32_i32$2 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$5 >>> i64toi32_i32$2 | 0;
+   $22 = (((1 << i64toi32_i32$2 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$2 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$2 | 0) | 0;
+  }
+  $19$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $10$hi;
+  i64toi32_i32$5 = $10;
+  i64toi32_i32$1 = $19$hi;
+  i64toi32_i32$3 = $22;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  i64toi32_i32$5 = i64toi32_i32$5 | i64toi32_i32$3 | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_rotr_i64(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, i64toi32_i32$4 = 0, var$2$hi = 0, var$2 = 0, $19 = 0, $20 = 0, $21 = 0, $22 = 0, $6$hi = 0, $8$hi = 0, $10 = 0, $10$hi = 0, $15$hi = 0, $17$hi = 0, $19$hi = 0;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$1 = i64toi32_i32$0 & i64toi32_i32$1 | 0;
+  var$2 = i64toi32_i32$2 & i64toi32_i32$3 | 0;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = -1;
+  i64toi32_i32$0 = -1;
+  i64toi32_i32$2 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$0 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+  }
+  $6$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$2 = $6$hi;
+  i64toi32_i32$1 = $19;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$0 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+  $8$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$0 = $8$hi;
+  i64toi32_i32$2 = i64toi32_i32$1 & i64toi32_i32$3 | 0;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = 0;
+   $20 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $20 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  $10 = $20;
+  $10$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$4 = i64toi32_i32$0 - i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = (i64toi32_i32$0 >>> 0 < i64toi32_i32$3 >>> 0) + i64toi32_i32$2 | 0;
+  i64toi32_i32$5 = i64toi32_i32$1 - i64toi32_i32$5 | 0;
+  i64toi32_i32$1 = i64toi32_i32$4;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$5 & i64toi32_i32$0 | 0;
+  var$1 = i64toi32_i32$1 & i64toi32_i32$3 | 0;
+  var$1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = -1;
+  i64toi32_i32$5 = -1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = 0;
+   $21 = i64toi32_i32$0 >>> i64toi32_i32$2 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$2 | 0;
+   $21 = (((1 << i64toi32_i32$2 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$2 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$2 | 0) | 0;
+  }
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = $15$hi;
+  i64toi32_i32$0 = $21;
+  i64toi32_i32$5 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$5 = i64toi32_i32$1 & i64toi32_i32$5 | 0;
+  $17$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$5 = $17$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 & i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$2 | 0;
+   $22 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$2 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$2 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$2 | 0) | 0;
+   $22 = i64toi32_i32$1 << i64toi32_i32$2 | 0;
+  }
+  $19$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $10$hi;
+  i64toi32_i32$5 = $10;
+  i64toi32_i32$1 = $19$hi;
+  i64toi32_i32$3 = $22;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  i64toi32_i32$5 = i64toi32_i32$5 | i64toi32_i32$3 | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ return {
+  "rotl": legalstub$1, 
+  "rotr": legalstub$2
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-rotate.2asm.js.opt
@@ -0,0 +1,139 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.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);
+ }
+ 
+ function legalstub$2($0, $1, $2, $3, $4, $5) {
+  return (__wasm_rotr_i64($0, $1, $2) | 0) == ($4 | 0) & ($5 | 0) == (i64toi32_i32$HIGH_BITS | 0);
+ }
+ 
+ function __wasm_rotl_i64($0, $1, $2) {
+  var $3 = 0, $4 = 0, $5 = 0, $6 = 0;
+  $6 = $2 & 63;
+  $5 = $6;
+  $3 = $5 & 31;
+  if (32 <= $5 >>> 0) {
+   $3 = -1 >>> $3 | 0
+  } else {
+   $4 = -1 >>> $3 | 0;
+   $3 = (1 << $3) - 1 << 32 - $3 | -1 >>> $3;
+  }
+  $5 = $3 & $0;
+  $3 = $1 & $4;
+  $4 = $6 & 31;
+  if (32 <= $6 >>> 0) {
+   $3 = $5 << $4;
+   $6 = 0;
+  } else {
+   $3 = (1 << $4) - 1 & $5 >>> 32 - $4 | $3 << $4;
+   $6 = $5 << $4;
+  }
+  $5 = $3;
+  $4 = 0 - $2 & 63;
+  $3 = $4;
+  $2 = $3 & 31;
+  if (32 <= $3 >>> 0) {
+   $3 = -1 << $2;
+   $2 = 0;
+  } else {
+   $3 = (1 << $2) - 1 & -1 >>> 32 - $2 | -1 << $2;
+   $2 = -1 << $2;
+  }
+  $0 = $2 & $0;
+  $3 = $1 & $3;
+  $1 = $4 & 31;
+  if (32 <= $4 >>> 0) {
+   $2 = 0;
+   $0 = $3 >>> $1 | 0;
+  } else {
+   $2 = $3 >>> $1 | 0;
+   $0 = ((1 << $1) - 1 & $3) << 32 - $1 | $0 >>> $1;
+  }
+  $0 = $0 | $6;
+  i64toi32_i32$HIGH_BITS = $2 | $5;
+  return $0;
+ }
+ 
+ function __wasm_rotr_i64($0, $1, $2) {
+  var $3 = 0, $4 = 0, $5 = 0, $6 = 0, $7 = 0;
+  $6 = $2 & 63;
+  $3 = $6 & 31;
+  if (32 <= $6 >>> 0) {
+   $4 = -1 << $3;
+   $7 = 0;
+  } else {
+   $4 = (1 << $3) - 1 & -1 >>> 32 - $3 | -1 << $3;
+   $7 = -1 << $3;
+  }
+  $7 = $7 & $0;
+  $3 = $1 & $4;
+  $5 = $6 & 31;
+  if (32 <= $6 >>> 0) {
+   $4 = 0;
+   $6 = $3 >>> $5 | 0;
+  } else {
+   $4 = $3 >>> $5 | 0;
+   $6 = ((1 << $5) - 1 & $3) << 32 - $5 | $7 >>> $5;
+  }
+  $7 = $4;
+  $3 = 0 - $2 & 63;
+  $5 = $3 & 31;
+  if (32 <= $3 >>> 0) {
+   $4 = 0;
+   $2 = -1 >>> $5 | 0;
+  } else {
+   $4 = -1 >>> $5 | 0;
+   $2 = (1 << $5) - 1 << 32 - $5 | -1 >>> $5;
+  }
+  $0 = $2 & $0;
+  $1 = $1 & $4;
+  $4 = $3 & 31;
+  if (32 <= $3 >>> 0) {
+   $2 = $0 << $4;
+   $0 = 0;
+  } else {
+   $2 = (1 << $4) - 1 & $0 >>> 32 - $4 | $1 << $4;
+   $0 = $0 << $4;
+  }
+  $0 = $0 | $6;
+  i64toi32_i32$HIGH_BITS = $2 | $7;
+  return $0;
+ }
+ 
+ return {
+  "rotl": legalstub$1, 
+  "rotr": legalstub$2
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var rotl = retasmFunc.rotl;
+export var rotr = retasmFunc.rotr;
diff --git a/binaryen/test/wasm2js/i64-rotate.wast b/binaryen/test/wasm2js/i64-rotate.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-rotate.wast
@@ -0,0 +1,70 @@
+;; Testing i64 rotates
+
+(module
+  (func $dummy)
+
+  (func (export "rotl") (param $0 i64) (param $1 i64) (param $2 i64) (result i32)
+    (i64.eq (i64.rotl (local.get $0) (local.get $1)) (local.get $2)))
+  (func (export "rotr") (param $0 i64) (param $1 i64) (param $2 i64) (result i32)
+    (i64.eq (i64.rotr (local.get $0) (local.get $1)) (local.get $2)))
+)
+
+(assert_return (invoke "rotl" (i32.const 0) (i32.const 0)
+                              (i32.const 0) (i32.const 0)
+                              (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "rotl" (i32.const 1) (i32.const 0)
+                              (i32.const 1) (i32.const 0)
+                              (i32.const 2) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "rotl" (i32.const 1) (i32.const 0)
+                              (i32.const 31) (i32.const 0)
+                              (i32.const 2147483648) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "rotl" (i32.const 1) (i32.const 0)
+                              (i32.const 32) (i32.const 0)
+                              (i32.const 0) (i32.const 1))
+               (i32.const 1))
+(assert_return (invoke "rotl" (i32.const 1) (i32.const 0)
+                              (i32.const 33) (i32.const 0)
+                              (i32.const 0) (i32.const 2))
+               (i32.const 1))
+
+(assert_return (invoke "rotl" (i32.const 1) (i32.const 1)
+                              (i32.const 1) (i32.const 0)
+                              (i32.const 2) (i32.const 2))
+               (i32.const 1))
+(assert_return (invoke "rotl" (i32.const 1) (i32.const 1)
+                              (i32.const 31) (i32.const 0)
+                              (i32.const 2147483648) (i32.const 2147483648))
+               (i32.const 1))
+(assert_return (invoke "rotl" (i32.const 1) (i32.const 1)
+                              (i32.const 32) (i32.const 0)
+                              (i32.const 1) (i32.const 1))
+               (i32.const 1))
+(assert_return (invoke "rotl" (i32.const 1) (i32.const 1)
+                              (i32.const 33) (i32.const 0)
+                              (i32.const 2) (i32.const 2))
+               (i32.const 1))
+
+
+(assert_return (invoke "rotr" (i32.const 0) (i32.const 0)
+                              (i32.const 0) (i32.const 0)
+                              (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "rotr" (i32.const 1) (i32.const 0)
+                              (i32.const 1) (i32.const 0)
+                              (i32.const 0) (i32.const 2147483648))
+               (i32.const 1))
+(assert_return (invoke "rotr" (i32.const 1) (i32.const 0)
+                              (i32.const 31) (i32.const 0)
+                              (i32.const 0) (i32.const 2))
+               (i32.const 1))
+(assert_return (invoke "rotr" (i32.const 1) (i32.const 0)
+                              (i32.const 32) (i32.const 0)
+                              (i32.const 0) (i32.const 1))
+               (i32.const 1))
+(assert_return (invoke "rotr" (i32.const 1) (i32.const 0)
+                              (i32.const 33) (i32.const 0)
+                              (i32.const 2147483648) (i32.const 0))
+               (i32.const 1))
diff --git a/binaryen/test/wasm2js/i64-select.2asm.js b/binaryen/test/wasm2js/i64-select.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-select.2asm.js
@@ -0,0 +1,34 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ return {
+  
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-select.2asm.js.opt
@@ -0,0 +1,34 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ return {
+  
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
diff --git a/binaryen/test/wasm2js/i64-select.wast b/binaryen/test/wasm2js/i64-select.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-select.wast
@@ -0,0 +1,44 @@
+;; Testing i64 select
+
+(module
+ (func $p (param $i i32) (result i32) (local.get $i))
+ (func (param i32) (result i32)
+  (return
+   (select
+    (call $p (i32.const -1))
+    (call $p (i32.const 0))
+    (i32.const 1)
+   )
+  )
+ )
+ (func (result i64)
+  (return
+   (select
+    (i64.const -1)
+    (i64.const 0)
+    (i32.const 1)
+   )   
+  )    
+ )
+ (func $unreachable-select-i64 (result i64)
+  (select
+   (i64.const 1)
+   (unreachable)
+   (i32.const 268435456)
+  )
+ )
+ (func $unreachable-select-i64-b (result i64)
+  (select
+   (unreachable)
+   (i64.const 1)
+   (i32.const 268435456)
+  )
+ )
+ (func $unreachable-select-i64-c (result i64)
+  (select
+   (i64.const 1)
+   (i64.const 1)
+   (unreachable)
+  )
+ )
+)
diff --git a/binaryen/test/wasm2js/i64-shifts.2asm.js b/binaryen/test/wasm2js/i64-shifts.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-shifts.2asm.js
@@ -0,0 +1,265 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $1($0, $0$hi, $1_1, $1$hi, $2_1, $2$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  $2_1 = $2_1 | 0;
+  $2$hi = $2$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $12 = 0, $5$hi = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$2 = $0;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$3 = $1_1;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $5$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $2$hi;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $12;
+  i64toi32_i32$2 = $2$hi;
+  i64toi32_i32$3 = $2_1;
+  return (i64toi32_i32$0 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$1 | 0) == (i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function $2($0, $0$hi, $1_1, $1$hi, $2_1, $2$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = $1_1 | 0;
+  $1$hi = $1$hi | 0;
+  $2_1 = $2_1 | 0;
+  $2$hi = $2$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$2 = 0, $12 = 0, $5$hi = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $1$hi;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$2 = $0;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$3 = $1_1;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $12 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $12 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  $5$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $2$hi;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $12;
+  i64toi32_i32$2 = $2$hi;
+  i64toi32_i32$3 = $2_1;
+  return (i64toi32_i32$0 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$1 | 0) == ($2$hi | 0) | 0 | 0;
+ }
+ 
+ function legalstub$1($0, $1_1, $2_1, $3, $4, $5) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3 = $3 | 0;
+  $4 = $4 | 0;
+  $5 = $5 | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $26 = 0, $27 = 0, $28 = 0, $7 = 0, $7$hi = 0, $10$hi = 0, $11 = 0, $11$hi = 0, $13 = 0, $13$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $19 = 0, $19$hi = 0, $22$hi = 0, $23 = 0, $23$hi = 0;
+  i64toi32_i32$0 = 0;
+  $7 = $0;
+  $7$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $26 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $26 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $10$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $7$hi;
+  i64toi32_i32$0 = $7;
+  i64toi32_i32$2 = $10$hi;
+  i64toi32_i32$3 = $26;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $11 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $13 = $2_1;
+  $13$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $27 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $27 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $16$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $13$hi;
+  i64toi32_i32$2 = $13;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$3 = $27;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $17 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $17$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  $19 = $4;
+  $19$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = $5;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+   $28 = 0;
+  } else {
+   i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$0 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+   $28 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+  }
+  $22$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $19$hi;
+  i64toi32_i32$1 = $19;
+  i64toi32_i32$0 = $22$hi;
+  i64toi32_i32$3 = $28;
+  i64toi32_i32$0 = i64toi32_i32$2 | i64toi32_i32$0 | 0;
+  $23 = i64toi32_i32$1 | i64toi32_i32$3 | 0;
+  $23$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$1 = $17$hi;
+  i64toi32_i32$2 = $23$hi;
+  return $1($11 | 0, i64toi32_i32$0 | 0, $17 | 0, i64toi32_i32$1 | 0, $23 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$2($0, $1_1, $2_1, $3, $4, $5) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3 = $3 | 0;
+  $4 = $4 | 0;
+  $5 = $5 | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $26 = 0, $27 = 0, $28 = 0, $7 = 0, $7$hi = 0, $10$hi = 0, $11 = 0, $11$hi = 0, $13 = 0, $13$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $19 = 0, $19$hi = 0, $22$hi = 0, $23 = 0, $23$hi = 0;
+  i64toi32_i32$0 = 0;
+  $7 = $0;
+  $7$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $26 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $26 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $10$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $7$hi;
+  i64toi32_i32$0 = $7;
+  i64toi32_i32$2 = $10$hi;
+  i64toi32_i32$3 = $26;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $11 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $13 = $2_1;
+  $13$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $27 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $27 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $16$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $13$hi;
+  i64toi32_i32$2 = $13;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$3 = $27;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $17 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $17$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  $19 = $4;
+  $19$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = $5;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+   $28 = 0;
+  } else {
+   i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$0 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+   $28 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+  }
+  $22$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $19$hi;
+  i64toi32_i32$1 = $19;
+  i64toi32_i32$0 = $22$hi;
+  i64toi32_i32$3 = $28;
+  i64toi32_i32$0 = i64toi32_i32$2 | i64toi32_i32$0 | 0;
+  $23 = i64toi32_i32$1 | i64toi32_i32$3 | 0;
+  $23$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$1 = $17$hi;
+  i64toi32_i32$2 = $23$hi;
+  return $2($11 | 0, i64toi32_i32$0 | 0, $17 | 0, i64toi32_i32$1 | 0, $23 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ return {
+  "shl_i64": legalstub$1, 
+  "shr_i64": legalstub$2
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-shifts.2asm.js.opt
@@ -0,0 +1,81 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $1($0, $1_1, $2_1, $3, $4) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3 = $3 | 0;
+  $4 = $4 | 0;
+  var $5 = 0;
+  $5 = $2_1 & 31;
+  if (32 <= ($2_1 & 63) >>> 0) {
+   $1_1 = $0 << $5;
+   $0 = 0;
+  } else {
+   $1_1 = (1 << $5) - 1 & $0 >>> 32 - $5 | $1_1 << $5;
+   $0 = $0 << $5;
+  }
+  return ($0 | 0) == ($3 | 0) & ($1_1 | 0) == ($4 | 0);
+ }
+ 
+ function $2($0, $1_1, $2_1, $3, $4) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3 = $3 | 0;
+  $4 = $4 | 0;
+  var $5 = 0;
+  $5 = $2_1 & 31;
+  if (32 <= ($2_1 & 63) >>> 0) {
+   $2_1 = $1_1 >> 31;
+   $0 = $1_1 >> $5;
+  } else {
+   $2_1 = $1_1 >> $5;
+   $0 = ((1 << $5) - 1 & $1_1) << 32 - $5 | $0 >>> $5;
+  }
+  return ($0 | 0) == ($3 | 0) & ($2_1 | 0) == ($4 | 0);
+ }
+ 
+ function legalstub$1($0, $1_1, $2_1, $3, $4, $5) {
+  return $1($0, $1_1, $2_1, $4, $5);
+ }
+ 
+ function legalstub$2($0, $1_1, $2_1, $3, $4, $5) {
+  return $2($0, $1_1, $2_1, $4, $5);
+ }
+ 
+ return {
+  "shl_i64": legalstub$1, 
+  "shr_i64": legalstub$2
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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.wast b/binaryen/test/wasm2js/i64-shifts.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/i64-shifts.wast
@@ -0,0 +1,81 @@
+;; Testing i64 shifts
+
+(module
+  (func $dummy)
+
+  (func (export "shl_i64") (param $0 i64) (param $1 i64) (param $2 i64) (result i32)
+    (i64.eq (i64.shl (local.get $0) (local.get $1)) (local.get $2)))
+  (func (export "shr_i64") (param $0 i64) (param $1 i64) (param $2 i64) (result i32)
+    (i64.eq (i64.shr_s (local.get $0) (local.get $1)) (local.get $2)))
+)
+
+(assert_return (invoke "shl_i64" (i32.const 0) (i32.const 0)
+                                 (i32.const 0) (i32.const 0)
+                                 (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "shl_i64" (i32.const 1) (i32.const 0)
+                                 (i32.const 1) (i32.const 0)
+                                 (i32.const 2) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "shl_i64" (i32.const 1) (i32.const 0)
+                                 (i32.const 0) (i32.const 0)
+                                 (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "shl_i64" (i32.const 1) (i32.const 0)
+                                 (i32.const 32) (i32.const 0)
+                                 (i32.const 0) (i32.const 1))
+               (i32.const 1))
+(assert_return (invoke "shl_i64" (i32.const 1) (i32.const 0)
+                                 (i32.const 63) (i32.const 0)
+                                 (i32.const 0) (i32.const 2147483648))
+               (i32.const 1))
+(assert_return (invoke "shl_i64" (i32.const 1) (i32.const 0)
+                                 (i32.const 64) (i32.const 0)
+                                 (i32.const 1) (i32.const 0))
+               (i32.const 1))
+
+(assert_return (invoke "shr_i64" (i32.const 1) (i32.const 0)
+                                 (i32.const 0) (i32.const 0)
+                                 (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "shr_i64" (i32.const 1) (i32.const 0)
+                                 (i32.const 32) (i32.const 0)
+                                 (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "shr_i64" (i32.const 0) (i32.const 1)
+                                 (i32.const 32) (i32.const 0)
+                                 (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "shr_i64" (i32.const 0) (i32.const 2)
+                                 (i32.const 33) (i32.const 0)
+                                 (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "shr_i64" (i32.const 0) (i32.const 2147483648)
+                                 (i32.const 32) (i32.const 0)
+                                 (i32.const 2147483648) (i32.const -1))
+               (i32.const 1))
+(assert_return (invoke "shr_i64" (i32.const 0) (i32.const 2147483648)
+                                 (i32.const 33) (i32.const 0)
+                                 (i32.const 3221225472) (i32.const -1))
+               (i32.const 1))
+(assert_return (invoke "shr_i64" (i32.const 0) (i32.const 2147483648)
+                                 (i32.const 63) (i32.const 0)
+                                 (i32.const -1) (i32.const -1))
+               (i32.const 1))
+(assert_return (invoke "shr_i64" (i32.const 1) (i32.const 0)
+                                 (i32.const 1) (i32.const 0)
+                                 (i32.const 0) (i32.const 0))
+               (i32.const 1))
+
+(assert_return (invoke "shr_i64" (i32.const 1) (i32.const 0)
+                                 (i32.const 2) (i32.const 0)
+                                 (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "shr_i64" (i32.const 2) (i32.const 1)
+                                 (i32.const 1) (i32.const 0)
+                                 (i32.const -2147483647) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "shr_i64" (i32.const 2) (i32.const 1)
+                                 (i32.const 2) (i32.const 0)
+                                 (i32.const 1073741824) (i32.const 0))
+               (i32.const 1))
diff --git a/binaryen/test/wasm2js/if_unreachable.2asm.js b/binaryen/test/wasm2js/if_unreachable.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/if_unreachable.2asm.js
@@ -0,0 +1,34 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ return {
+  
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/if_unreachable.2asm.js.opt
@@ -0,0 +1,34 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ return {
+  
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
diff --git a/binaryen/test/wasm2js/if_unreachable.wast b/binaryen/test/wasm2js/if_unreachable.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/if_unreachable.wast
@@ -0,0 +1,21 @@
+(module
+ (type $0 (func (param i32 i32 i32 i32 i32 i32)))
+ (import "env" "table" (table $timport$0 6 funcref))
+ (func $0 (; 0 ;) (type $0) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (param $5 i32)
+  (if
+   (i32.ne
+    (i32.const 0)
+    (i32.const 48)
+   )
+   (block $label$2
+    (br_if $label$2
+     (i32.const 0)
+    )
+    (unreachable)
+   )
+   (unreachable)
+  )
+  (unreachable)
+ )
+)
+
diff --git a/binaryen/test/wasm2js/indirect-select.2asm.js b/binaryen/test/wasm2js/indirect-select.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/indirect-select.2asm.js
@@ -0,0 +1,50 @@
+import { table } from 'env';
+
+function asmFunc(global, 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0(x) {
+  x = x | 0;
+  return FUNCTION_TABLE[(x ? 1 : 0) | 0]() | 0 | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  return FUNCTION_TABLE[(x ? 0 : 1) | 0]() | 0 | 0;
+ }
+ 
+ return {
+  "foo_true": $0, 
+  "foo_false": $1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    table
+  });
+export var foo_true = retasmFunc.foo_true;
+export var foo_false = retasmFunc.foo_false;
diff --git a/binaryen/test/wasm2js/indirect-select.2asm.js.opt b/binaryen/test/wasm2js/indirect-select.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/indirect-select.2asm.js.opt
@@ -0,0 +1,50 @@
+import { table } from 'env';
+
+function asmFunc(global, 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0($0_1) {
+  $0_1 = $0_1 | 0;
+  return FUNCTION_TABLE[!!$0_1 | 0]() | 0;
+ }
+ 
+ function $1($0_1) {
+  $0_1 = $0_1 | 0;
+  return FUNCTION_TABLE[!$0_1 | 0]() | 0;
+ }
+ 
+ return {
+  "foo_true": $0, 
+  "foo_false": $1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    table
+  });
+export var foo_true = retasmFunc.foo_true;
+export var foo_false = retasmFunc.foo_false;
diff --git a/binaryen/test/wasm2js/indirect-select.wast b/binaryen/test/wasm2js/indirect-select.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/indirect-select.wast
@@ -0,0 +1,22 @@
+(module
+  (type $none_=>_i32 (func (result i32)))
+  (import "env" "table" (table $timport 6 funcref))
+  (func "foo-true" (param $x i32) (result i32)
+    (call_indirect (type $none_=>_i32)
+      (select
+        (i32.const 1)
+        (i32.const 0)
+        (local.get $x)
+      )
+    )
+  )
+  (func "foo-false" (param $x i32) (result i32)
+    (call_indirect (type $none_=>_i32)
+      (select
+        (i32.const 0)
+        (i32.const 1)
+        (local.get $x)
+      )
+    )
+  )
+)
diff --git a/binaryen/test/wasm2js/int_exprs.2asm.js b/binaryen/test/wasm2js/int_exprs.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/int_exprs.2asm.js
@@ -0,0 +1,11033 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x + 1 | 0 | 0) < (y + 1 | 0 | 0) | 0;
+ }
+ 
+ function $1(x, y) {
+  x = x | 0;
+  y = y | 0;
+  return (x + 1 | 0) >>> 0 < (y + 1 | 0) >>> 0 | 0;
+ }
+ 
+ function $2(x, x$hi, y, y$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  y = y | 0;
+  y$hi = y$hi | 0;
+  var i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, $13 = 0, $14 = 0, $15 = 0, $3_1 = 0, $3$hi = 0, $5$hi = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$2 = x;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 1;
+  i64toi32_i32$4 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = i64toi32_i32$0 + i64toi32_i32$1 | 0;
+  if (i64toi32_i32$4 >>> 0 < i64toi32_i32$3 >>> 0) {
+   i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+  }
+  $3_1 = i64toi32_i32$4;
+  $3$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = y$hi;
+  i64toi32_i32$0 = y;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 1;
+  i64toi32_i32$1 = i64toi32_i32$0 + i64toi32_i32$3 | 0;
+  i64toi32_i32$4 = i64toi32_i32$5 + i64toi32_i32$2 | 0;
+  if (i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0) {
+   i64toi32_i32$4 = i64toi32_i32$4 + 1 | 0
+  }
+  $5$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $3$hi;
+  i64toi32_i32$5 = $3_1;
+  i64toi32_i32$0 = $5$hi;
+  i64toi32_i32$3 = i64toi32_i32$1;
+  if ((i64toi32_i32$4 | 0) < (i64toi32_i32$0 | 0)) {
+   $13 = 1
+  } else {
+   if ((i64toi32_i32$4 | 0) <= (i64toi32_i32$0 | 0)) {
+    if (i64toi32_i32$5 >>> 0 >= i64toi32_i32$3 >>> 0) {
+     $14 = 0
+    } else {
+     $14 = 1
+    }
+    $15 = $14;
+   } else {
+    $15 = 0
+   }
+   $13 = $15;
+  }
+  return $13 | 0;
+ }
+ 
+ function $3(x, x$hi, y, y$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  y = y | 0;
+  y$hi = y$hi | 0;
+  var i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, $3_1 = 0, $3$hi = 0, $5$hi = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$2 = x;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 1;
+  i64toi32_i32$4 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = i64toi32_i32$0 + i64toi32_i32$1 | 0;
+  if (i64toi32_i32$4 >>> 0 < i64toi32_i32$3 >>> 0) {
+   i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+  }
+  $3_1 = i64toi32_i32$4;
+  $3$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = y$hi;
+  i64toi32_i32$0 = y;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 1;
+  i64toi32_i32$1 = i64toi32_i32$0 + i64toi32_i32$3 | 0;
+  i64toi32_i32$4 = i64toi32_i32$5 + i64toi32_i32$2 | 0;
+  if (i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0) {
+   i64toi32_i32$4 = i64toi32_i32$4 + 1 | 0
+  }
+  $5$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $3$hi;
+  i64toi32_i32$5 = $3_1;
+  i64toi32_i32$0 = $5$hi;
+  i64toi32_i32$3 = i64toi32_i32$1;
+  return i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0 | ((i64toi32_i32$4 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$5 >>> 0 < i64toi32_i32$3 >>> 0 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1, $2_1, $3_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5 = 0, $5$hi = 0, $8$hi = 0, $9 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5 = $0_1;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  return $2($9 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1_1, $2_1, $3_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5 = 0, $5$hi = 0, $8$hi = 0, $9 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5 = $0_1;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  return $3($9 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ return {
+  "i32_no_fold_cmp_s_offset": $0, 
+  "i32_no_fold_cmp_u_offset": $1, 
+  "i64_no_fold_cmp_s_offset": legalstub$2, 
+  "i64_no_fold_cmp_u_offset": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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;
+export var i64_no_fold_cmp_s_offset = retasmFunc.i64_no_fold_cmp_s_offset;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = x;
+  i64toi32_i32$0 = i64toi32_i32$1 >> 31 | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$0($0_1, $1) {
+  $0_1 = $0_1 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $0(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2 | 0;
+ }
+ 
+ return {
+  "i64_no_fold_wrap_extend_s": legalstub$0
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return x | 0;
+ }
+ 
+ function legalstub$0($0_1, $1) {
+  $0_1 = $0_1 | 0;
+  $1 = $1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $0(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2 | 0;
+ }
+ 
+ return {
+  "i64_no_fold_wrap_extend_u": legalstub$0
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return (x << 1 | 0) >> 1 | 0 | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  return (x << 1 | 0) >>> 1 | 0 | 0;
+ }
+ 
+ function $2(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$4 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$3 = 0, $7 = 0, $8 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$2 = x;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 1;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $7 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $7 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  i64toi32_i32$0 = $7;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 1;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$1 >> 31 | 0;
+   $8 = i64toi32_i32$1 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >> i64toi32_i32$4 | 0;
+   $8 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  i64toi32_i32$0 = $8;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$2;
+  return i64toi32_i32$0 | 0;
+ }
+ 
+ function $3(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$4 = 0, i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7 = 0, $8 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$2 = x;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 1;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $7 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $7 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  i64toi32_i32$0 = $7;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 1;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $8 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $8 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  i64toi32_i32$0 = $8;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$2;
+  return i64toi32_i32$0 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $3(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ return {
+  "i32_no_fold_shl_shr_s": $0, 
+  "i32_no_fold_shl_shr_u": $1, 
+  "i64_no_fold_shl_shr_s": legalstub$2, 
+  "i64_no_fold_shl_shr_u": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i32_no_fold_shl_shr_s = retasmFunc.i32_no_fold_shl_shr_s;
+export var i32_no_fold_shl_shr_u = retasmFunc.i32_no_fold_shl_shr_u;
+export var i64_no_fold_shl_shr_s = retasmFunc.i64_no_fold_shl_shr_s;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return (x >> 1 | 0) << 1 | 0 | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  return (x >>> 1 | 0) << 1 | 0 | 0;
+ }
+ 
+ function $2(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$1 = 0, $7 = 0, $8 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$2 = x;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 1;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $7 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $7 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  i64toi32_i32$0 = $7;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 1;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+   $8 = 0;
+  } else {
+   i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$0 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+   $8 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+  }
+  i64toi32_i32$0 = $8;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$2;
+  return i64toi32_i32$0 | 0;
+ }
+ 
+ function $3(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$1 = 0, $7 = 0, $8 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$2 = x;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 1;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = 0;
+   $7 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $7 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  i64toi32_i32$0 = $7;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 1;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+   $8 = 0;
+  } else {
+   i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$0 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+   $8 = i64toi32_i32$0 << i64toi32_i32$4 | 0;
+  }
+  i64toi32_i32$0 = $8;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$2;
+  return i64toi32_i32$0 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $3(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ return {
+  "i32_no_fold_shr_s_shl": $0, 
+  "i32_no_fold_shr_u_shl": $1, 
+  "i64_no_fold_shr_s_shl": legalstub$2, 
+  "i64_no_fold_shr_u_shl": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i32_no_fold_shr_s_shl = retasmFunc.i32_no_fold_shr_s_shl;
+export var i32_no_fold_shr_u_shl = retasmFunc.i32_no_fold_shr_u_shl;
+export var i64_no_fold_shr_s_shl = retasmFunc.i64_no_fold_shr_s_shl;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return Math_imul((x | 0) / (6 | 0) | 0, 6) | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  return Math_imul((x >>> 0) / (6 >>> 0) | 0, 6) | 0;
+ }
+ 
+ function $2(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, $4 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_sdiv(x | 0, i64toi32_i32$0 | 0, 6 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $4 = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_mul($4 | 0, i64toi32_i32$0 | 0, 6 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $3(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, $4 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_udiv(x | 0, i64toi32_i32$0 | 0, 6 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $4 = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_mul($4 | 0, i64toi32_i32$0 | 0, 6 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $3(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, var$2 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, var$3 = 0, var$4 = 0, var$5 = 0, $21 = 0, $22 = 0, var$6 = 0, $24 = 0, $17 = 0, $18 = 0, $23 = 0, $29 = 0, $45 = 0, $56$hi = 0, $62$hi = 0;
+  i64toi32_i32$0 = var$1$hi;
+  var$2 = var$1;
+  var$4 = var$2 >>> 16 | 0;
+  i64toi32_i32$0 = var$0$hi;
+  var$3 = var$0;
+  var$5 = var$3 >>> 16 | 0;
+  $17 = Math_imul(var$4, var$5);
+  $18 = var$2;
+  i64toi32_i32$2 = var$3;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = 0;
+   $21 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  $23 = $17 + Math_imul($18, $21) | 0;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$0 = var$1;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $22 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $22 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  $29 = $23 + Math_imul($22, var$3) | 0;
+  var$2 = var$2 & 65535 | 0;
+  var$3 = var$3 & 65535 | 0;
+  var$6 = Math_imul(var$2, var$3);
+  var$2 = (var$6 >>> 16 | 0) + Math_imul(var$2, var$5) | 0;
+  $45 = $29 + (var$2 >>> 16 | 0) | 0;
+  var$2 = (var$2 & 65535 | 0) + Math_imul(var$4, var$3) | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $45 + (var$2 >>> 16 | 0) | 0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $24 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $24 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $56$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  $62$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $56$hi;
+  i64toi32_i32$2 = $24;
+  i64toi32_i32$1 = $62$hi;
+  i64toi32_i32$3 = var$2 << 16 | 0 | (var$6 & 65535 | 0) | 0;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  i64toi32_i32$2 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, $21 = 0, $22 = 0, $23 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $23$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $21 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $21;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $22 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $22 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$2 = $22;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$5 = var$2;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_udiv($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17 = i64toi32_i32$1;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$5 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$1 >> 31 | 0;
+   $23 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+   $23 = (((1 << i64toi32_i32$5 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$5 | 0) | 0 | (i64toi32_i32$4 >>> i64toi32_i32$5 | 0) | 0;
+  }
+  var$0 = $23;
+  var$0$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $17$hi;
+  i64toi32_i32$1 = $17;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$4 | 0;
+  $23$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = $23$hi;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+  i64toi32_i32$0 = i64toi32_i32$4 - i64toi32_i32$0 | 0;
+  i64toi32_i32$2 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_mul(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_sdiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_udiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "i32_no_fold_div_s_mul": $0, 
+  "i32_no_fold_div_u_mul": $1, 
+  "i64_no_fold_div_s_mul": legalstub$2, 
+  "i64_no_fold_div_u_mul": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i32_no_fold_div_s_mul = retasmFunc.i32_no_fold_div_s_mul;
+export var i32_no_fold_div_u_mul = retasmFunc.i32_no_fold_div_u_mul;
+export var i64_no_fold_div_s_mul = retasmFunc.i64_no_fold_div_s_mul;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return (x | 0) / (x | 0) | 0 | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  return (x >>> 0) / (x >>> 0) | 0 | 0;
+ }
+ 
+ function $2(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = i64toi32_i32$0;
+  i64toi32_i32$1 = __wasm_i64_sdiv(x | 0, i64toi32_i32$0 | 0, x | 0, i64toi32_i32$0 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $3(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = i64toi32_i32$0;
+  i64toi32_i32$1 = __wasm_i64_udiv(x | 0, i64toi32_i32$0 | 0, x | 0, i64toi32_i32$0 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $3(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, $21 = 0, $22 = 0, $23 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $23$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $21 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $21;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $22 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $22 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$2 = $22;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$5 = var$2;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_udiv($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17 = i64toi32_i32$1;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$5 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$1 >> 31 | 0;
+   $23 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+   $23 = (((1 << i64toi32_i32$5 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$5 | 0) | 0 | (i64toi32_i32$4 >>> i64toi32_i32$5 | 0) | 0;
+  }
+  var$0 = $23;
+  var$0$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $17$hi;
+  i64toi32_i32$1 = $17;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$4 | 0;
+  $23$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = $23$hi;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+  i64toi32_i32$0 = i64toi32_i32$4 - i64toi32_i32$0 | 0;
+  i64toi32_i32$2 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_sdiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_udiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "i32_no_fold_div_s_self": $0, 
+  "i32_no_fold_div_u_self": $1, 
+  "i64_no_fold_div_s_self": legalstub$2, 
+  "i64_no_fold_div_u_self": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i32_no_fold_div_s_self = retasmFunc.i32_no_fold_div_s_self;
+export var i32_no_fold_div_u_self = retasmFunc.i32_no_fold_div_u_self;
+export var i64_no_fold_div_s_self = retasmFunc.i64_no_fold_div_s_self;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return (x | 0) % (x | 0) | 0 | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  return (x >>> 0) % (x >>> 0) | 0 | 0;
+ }
+ 
+ function $2(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = i64toi32_i32$0;
+  i64toi32_i32$1 = __wasm_i64_srem(x | 0, i64toi32_i32$0 | 0, x | 0, i64toi32_i32$0 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $3(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = i64toi32_i32$0;
+  i64toi32_i32$1 = __wasm_i64_urem(x | 0, i64toi32_i32$0 | 0, x | 0, i64toi32_i32$0 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $3(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, var$2 = 0, $20 = 0, $21 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17$hi = 0, $19$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $20 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $20 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $20;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $21 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $21 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$0 = $21;
+  var$0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_urem($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$2$hi;
+  i64toi32_i32$4 = $17$hi;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  $19$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$1 = $19$hi;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = var$2$hi;
+  i64toi32_i32$5 = i64toi32_i32$4 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$4 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$2 | 0;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$0 | 0;
+  i64toi32_i32$4 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$4 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_srem(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_urem(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$0 = __wasm_intrinsics_temp_i64$hi;
+  i64toi32_i32$1 = __wasm_intrinsics_temp_i64;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "i32_no_fold_rem_s_self": $0, 
+  "i32_no_fold_rem_u_self": $1, 
+  "i64_no_fold_rem_s_self": legalstub$2, 
+  "i64_no_fold_rem_u_self": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i32_no_fold_rem_s_self = retasmFunc.i32_no_fold_rem_s_self;
+export var i32_no_fold_rem_u_self = retasmFunc.i32_no_fold_rem_u_self;
+export var i64_no_fold_rem_s_self = retasmFunc.i64_no_fold_rem_s_self;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return (Math_imul(x, 6) | 0) / (6 | 0) | 0 | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  return (Math_imul(x, 6) >>> 0) / (6 >>> 0) | 0 | 0;
+ }
+ 
+ function $2(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, $4 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_mul(x | 0, i64toi32_i32$0 | 0, 6 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $4 = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_sdiv($4 | 0, i64toi32_i32$0 | 0, 6 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $3(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, $4 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_mul(x | 0, i64toi32_i32$0 | 0, 6 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $4 = i64toi32_i32$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_udiv($4 | 0, i64toi32_i32$0 | 0, 6 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $3(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, var$2 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, var$3 = 0, var$4 = 0, var$5 = 0, $21 = 0, $22 = 0, var$6 = 0, $24 = 0, $17 = 0, $18 = 0, $23 = 0, $29 = 0, $45 = 0, $56$hi = 0, $62$hi = 0;
+  i64toi32_i32$0 = var$1$hi;
+  var$2 = var$1;
+  var$4 = var$2 >>> 16 | 0;
+  i64toi32_i32$0 = var$0$hi;
+  var$3 = var$0;
+  var$5 = var$3 >>> 16 | 0;
+  $17 = Math_imul(var$4, var$5);
+  $18 = var$2;
+  i64toi32_i32$2 = var$3;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = 0;
+   $21 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  $23 = $17 + Math_imul($18, $21) | 0;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$0 = var$1;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $22 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $22 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  $29 = $23 + Math_imul($22, var$3) | 0;
+  var$2 = var$2 & 65535 | 0;
+  var$3 = var$3 & 65535 | 0;
+  var$6 = Math_imul(var$2, var$3);
+  var$2 = (var$6 >>> 16 | 0) + Math_imul(var$2, var$5) | 0;
+  $45 = $29 + (var$2 >>> 16 | 0) | 0;
+  var$2 = (var$2 & 65535 | 0) + Math_imul(var$4, var$3) | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $45 + (var$2 >>> 16 | 0) | 0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $24 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $24 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $56$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  $62$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $56$hi;
+  i64toi32_i32$2 = $24;
+  i64toi32_i32$1 = $62$hi;
+  i64toi32_i32$3 = var$2 << 16 | 0 | (var$6 & 65535 | 0) | 0;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  i64toi32_i32$2 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, $21 = 0, $22 = 0, $23 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $23$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $21 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $21;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $22 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $22 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$2 = $22;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$5 = var$2;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_udiv($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17 = i64toi32_i32$1;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$5 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$1 >> 31 | 0;
+   $23 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+   $23 = (((1 << i64toi32_i32$5 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$5 | 0) | 0 | (i64toi32_i32$4 >>> i64toi32_i32$5 | 0) | 0;
+  }
+  var$0 = $23;
+  var$0$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $17$hi;
+  i64toi32_i32$1 = $17;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$4 | 0;
+  $23$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = $23$hi;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+  i64toi32_i32$0 = i64toi32_i32$4 - i64toi32_i32$0 | 0;
+  i64toi32_i32$2 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_mul(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_sdiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_udiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "i32_no_fold_mul_div_s": $0, 
+  "i32_no_fold_mul_div_u": $1, 
+  "i64_no_fold_mul_div_s": legalstub$2, 
+  "i64_no_fold_mul_div_u": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i32_no_fold_mul_div_s = retasmFunc.i32_no_fold_mul_div_s;
+export var i32_no_fold_mul_div_u = retasmFunc.i32_no_fold_mul_div_u;
+export var i64_no_fold_mul_div_s = retasmFunc.i64_no_fold_mul_div_s;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return (x | 0) / (2 | 0) | 0 | 0;
+ }
+ 
+ function $1(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_sdiv(x | 0, i64toi32_i32$0 | 0, 2 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$1($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $1(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, $21 = 0, $22 = 0, $23 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $23$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $21 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $21;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $22 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $22 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$2 = $22;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$5 = var$2;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_udiv($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17 = i64toi32_i32$1;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$5 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$1 >> 31 | 0;
+   $23 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+   $23 = (((1 << i64toi32_i32$5 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$5 | 0) | 0 | (i64toi32_i32$4 >>> i64toi32_i32$5 | 0) | 0;
+  }
+  var$0 = $23;
+  var$0$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $17$hi;
+  i64toi32_i32$1 = $17;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$4 | 0;
+  $23$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = $23$hi;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+  i64toi32_i32$0 = i64toi32_i32$4 - i64toi32_i32$0 | 0;
+  i64toi32_i32$2 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function __wasm_i64_sdiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_udiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "i32_no_fold_div_s_2": $0, 
+  "i64_no_fold_div_s_2": legalstub$1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return (x | 0) % (2 | 0) | 0 | 0;
+ }
+ 
+ function $1(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_srem(x | 0, i64toi32_i32$0 | 0, 2 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$1($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $1(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, var$2 = 0, $20 = 0, $21 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17$hi = 0, $19$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $20 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $20 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $20;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $21 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $21 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$0 = $21;
+  var$0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_urem($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$2$hi;
+  i64toi32_i32$4 = $17$hi;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  $19$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$1 = $19$hi;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = var$2$hi;
+  i64toi32_i32$5 = i64toi32_i32$4 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$4 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$2 | 0;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$0 | 0;
+  i64toi32_i32$4 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$4 | 0;
+ }
+ 
+ function __wasm_i64_srem(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_urem(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$0 = __wasm_intrinsics_temp_i64$hi;
+  i64toi32_i32$1 = __wasm_intrinsics_temp_i64;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "i32_no_fold_rem_s_2": $0, 
+  "i64_no_fold_rem_s_2": legalstub$1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return (x | 0) / (0 | 0) | 0 | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  return (x >>> 0) / (0 >>> 0) | 0 | 0;
+ }
+ 
+ function $2(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_sdiv(x | 0, i64toi32_i32$0 | 0, 0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $3(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_udiv(x | 0, i64toi32_i32$0 | 0, 0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $3(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, $21 = 0, $22 = 0, $23 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $23$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $21 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $21;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $22 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $22 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$2 = $22;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$5 = var$2;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_udiv($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17 = i64toi32_i32$1;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$5 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$1 >> 31 | 0;
+   $23 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+   $23 = (((1 << i64toi32_i32$5 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$5 | 0) | 0 | (i64toi32_i32$4 >>> i64toi32_i32$5 | 0) | 0;
+  }
+  var$0 = $23;
+  var$0$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $17$hi;
+  i64toi32_i32$1 = $17;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$4 | 0;
+  $23$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = $23$hi;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+  i64toi32_i32$0 = i64toi32_i32$4 - i64toi32_i32$0 | 0;
+  i64toi32_i32$2 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_sdiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_udiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "i32_div_s_0": $0, 
+  "i32_div_u_0": $1, 
+  "i64_div_s_0": legalstub$2, 
+  "i64_div_u_0": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i32_div_s_0 = retasmFunc.i32_div_s_0;
+export var i32_div_u_0 = retasmFunc.i32_div_u_0;
+export var i64_div_s_0 = retasmFunc.i64_div_s_0;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return (x | 0) / (3 | 0) | 0 | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  return (x >>> 0) / (3 >>> 0) | 0 | 0;
+ }
+ 
+ function $2(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_sdiv(x | 0, i64toi32_i32$0 | 0, 3 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $3(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_udiv(x | 0, i64toi32_i32$0 | 0, 3 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $3(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, $21 = 0, $22 = 0, $23 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $23$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $21 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $21;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $22 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $22 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$2 = $22;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$5 = var$2;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_udiv($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17 = i64toi32_i32$1;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$5 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$1 >> 31 | 0;
+   $23 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+   $23 = (((1 << i64toi32_i32$5 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$5 | 0) | 0 | (i64toi32_i32$4 >>> i64toi32_i32$5 | 0) | 0;
+  }
+  var$0 = $23;
+  var$0$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $17$hi;
+  i64toi32_i32$1 = $17;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$4 | 0;
+  $23$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = $23$hi;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+  i64toi32_i32$0 = i64toi32_i32$4 - i64toi32_i32$0 | 0;
+  i64toi32_i32$2 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_sdiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_udiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "i32_div_s_3": $0, 
+  "i32_div_u_3": $1, 
+  "i64_div_s_3": legalstub$2, 
+  "i64_div_u_3": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i32_div_s_3 = retasmFunc.i32_div_s_3;
+export var i32_div_u_3 = retasmFunc.i32_div_u_3;
+export var i64_div_s_3 = retasmFunc.i64_div_s_3;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return (x | 0) / (5 | 0) | 0 | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  return (x >>> 0) / (5 >>> 0) | 0 | 0;
+ }
+ 
+ function $2(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_sdiv(x | 0, i64toi32_i32$0 | 0, 5 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $3(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_udiv(x | 0, i64toi32_i32$0 | 0, 5 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $3(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, $21 = 0, $22 = 0, $23 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $23$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $21 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $21;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $22 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $22 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$2 = $22;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$5 = var$2;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_udiv($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17 = i64toi32_i32$1;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$5 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$1 >> 31 | 0;
+   $23 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+   $23 = (((1 << i64toi32_i32$5 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$5 | 0) | 0 | (i64toi32_i32$4 >>> i64toi32_i32$5 | 0) | 0;
+  }
+  var$0 = $23;
+  var$0$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $17$hi;
+  i64toi32_i32$1 = $17;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$4 | 0;
+  $23$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = $23$hi;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+  i64toi32_i32$0 = i64toi32_i32$4 - i64toi32_i32$0 | 0;
+  i64toi32_i32$2 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_sdiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_udiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "i32_div_s_5": $0, 
+  "i32_div_u_5": $1, 
+  "i64_div_s_5": legalstub$2, 
+  "i64_div_u_5": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i32_div_s_5 = retasmFunc.i32_div_s_5;
+export var i32_div_u_5 = retasmFunc.i32_div_u_5;
+export var i64_div_s_5 = retasmFunc.i64_div_s_5;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return (x | 0) / (7 | 0) | 0 | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  return (x >>> 0) / (7 >>> 0) | 0 | 0;
+ }
+ 
+ function $2(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_sdiv(x | 0, i64toi32_i32$0 | 0, 7 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $3(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_udiv(x | 0, i64toi32_i32$0 | 0, 7 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $3(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, $21 = 0, $22 = 0, $23 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $23$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $21 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $21;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $22 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $22 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$2 = $22;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$5 = var$2;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_udiv($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17 = i64toi32_i32$1;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$5 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$1 >> 31 | 0;
+   $23 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+   $23 = (((1 << i64toi32_i32$5 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$5 | 0) | 0 | (i64toi32_i32$4 >>> i64toi32_i32$5 | 0) | 0;
+  }
+  var$0 = $23;
+  var$0$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $17$hi;
+  i64toi32_i32$1 = $17;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$4 | 0;
+  $23$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = $23$hi;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+  i64toi32_i32$0 = i64toi32_i32$4 - i64toi32_i32$0 | 0;
+  i64toi32_i32$2 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_sdiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_udiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "i32_div_s_7": $0, 
+  "i32_div_u_7": $1, 
+  "i64_div_s_7": legalstub$2, 
+  "i64_div_u_7": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i32_div_s_7 = retasmFunc.i32_div_s_7;
+export var i32_div_u_7 = retasmFunc.i32_div_u_7;
+export var i64_div_s_7 = retasmFunc.i64_div_s_7;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return (x | 0) % (3 | 0) | 0 | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  return (x >>> 0) % (3 >>> 0) | 0 | 0;
+ }
+ 
+ function $2(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_srem(x | 0, i64toi32_i32$0 | 0, 3 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $3(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_urem(x | 0, i64toi32_i32$0 | 0, 3 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $3(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, var$2 = 0, $20 = 0, $21 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17$hi = 0, $19$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $20 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $20 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $20;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $21 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $21 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$0 = $21;
+  var$0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_urem($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$2$hi;
+  i64toi32_i32$4 = $17$hi;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  $19$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$1 = $19$hi;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = var$2$hi;
+  i64toi32_i32$5 = i64toi32_i32$4 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$4 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$2 | 0;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$0 | 0;
+  i64toi32_i32$4 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$4 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_srem(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_urem(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$0 = __wasm_intrinsics_temp_i64$hi;
+  i64toi32_i32$1 = __wasm_intrinsics_temp_i64;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "i32_rem_s_3": $0, 
+  "i32_rem_u_3": $1, 
+  "i64_rem_s_3": legalstub$2, 
+  "i64_rem_u_3": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i32_rem_s_3 = retasmFunc.i32_rem_s_3;
+export var i32_rem_u_3 = retasmFunc.i32_rem_u_3;
+export var i64_rem_s_3 = retasmFunc.i64_rem_s_3;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return (x | 0) % (5 | 0) | 0 | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  return (x >>> 0) % (5 >>> 0) | 0 | 0;
+ }
+ 
+ function $2(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_srem(x | 0, i64toi32_i32$0 | 0, 5 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $3(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_urem(x | 0, i64toi32_i32$0 | 0, 5 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $3(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, var$2 = 0, $20 = 0, $21 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17$hi = 0, $19$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $20 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $20 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $20;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $21 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $21 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$0 = $21;
+  var$0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_urem($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$2$hi;
+  i64toi32_i32$4 = $17$hi;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  $19$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$1 = $19$hi;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = var$2$hi;
+  i64toi32_i32$5 = i64toi32_i32$4 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$4 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$2 | 0;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$0 | 0;
+  i64toi32_i32$4 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$4 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_srem(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_urem(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$0 = __wasm_intrinsics_temp_i64$hi;
+  i64toi32_i32$1 = __wasm_intrinsics_temp_i64;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "i32_rem_s_5": $0, 
+  "i32_rem_u_5": $1, 
+  "i64_rem_s_5": legalstub$2, 
+  "i64_rem_u_5": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i32_rem_s_5 = retasmFunc.i32_rem_s_5;
+export var i32_rem_u_5 = retasmFunc.i32_rem_u_5;
+export var i64_rem_s_5 = retasmFunc.i64_rem_s_5;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return (x | 0) % (7 | 0) | 0 | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  return (x >>> 0) % (7 >>> 0) | 0 | 0;
+ }
+ 
+ function $2(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_srem(x | 0, i64toi32_i32$0 | 0, 7 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $3(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$1 = __wasm_i64_urem(x | 0, i64toi32_i32$0 | 0, 7 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $3(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, var$2 = 0, $20 = 0, $21 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17$hi = 0, $19$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $20 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $20 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $20;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $21 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $21 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$0 = $21;
+  var$0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_urem($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$2$hi;
+  i64toi32_i32$4 = $17$hi;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  $19$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$1 = $19$hi;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = var$2$hi;
+  i64toi32_i32$5 = i64toi32_i32$4 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$4 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$2 | 0;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$0 | 0;
+  i64toi32_i32$4 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$4 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_srem(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_urem(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$0 = __wasm_intrinsics_temp_i64$hi;
+  i64toi32_i32$1 = __wasm_intrinsics_temp_i64;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "i32_rem_s_7": $0, 
+  "i32_rem_u_7": $1, 
+  "i64_rem_s_7": legalstub$2, 
+  "i64_rem_u_7": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i32_rem_s_7 = retasmFunc.i32_rem_s_7;
+export var i32_rem_u_7 = retasmFunc.i32_rem_u_7;
+export var i64_rem_s_7 = retasmFunc.i64_rem_s_7;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x) {
+  x = x | 0;
+  return (x | 0) / (-1 | 0) | 0 | 0;
+ }
+ 
+ function $1(x, x$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = x$hi;
+  i64toi32_i32$1 = -1;
+  i64toi32_i32$1 = __wasm_i64_sdiv(x | 0, i64toi32_i32$0 | 0, -1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$1($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $1(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, $21 = 0, $22 = 0, $23 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $23$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $21 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $21;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $22 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $22 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$2 = $22;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$5 = var$2;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_udiv($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17 = i64toi32_i32$1;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$5 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$1 >> 31 | 0;
+   $23 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+   $23 = (((1 << i64toi32_i32$5 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$5 | 0) | 0 | (i64toi32_i32$4 >>> i64toi32_i32$5 | 0) | 0;
+  }
+  var$0 = $23;
+  var$0$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $17$hi;
+  i64toi32_i32$1 = $17;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$4 | 0;
+  $23$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = $23$hi;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+  i64toi32_i32$0 = i64toi32_i32$4 - i64toi32_i32$0 | 0;
+  i64toi32_i32$2 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function __wasm_i64_sdiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_udiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "i32_no_fold_div_neg1": $0, 
+  "i64_no_fold_div_neg1": legalstub$1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var i32_no_fold_div_neg1 = retasmFunc.i32_no_fold_div_neg1;
+export var i64_no_fold_div_neg1 = retasmFunc.i64_no_fold_div_neg1;
diff --git a/binaryen/test/wasm2js/labels.2asm.js b/binaryen/test/wasm2js/labels.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/labels.2asm.js
@@ -0,0 +1,376 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  var $0_1 = 0;
+  exit : {
+   $0_1 = 1;
+   break exit;
+  }
+  return $0_1 | 0;
+ }
+ 
+ function $1() {
+  var i = 0, $6_1 = 0;
+  i = 0;
+  exit : {
+   cont : while (1) {
+    i = i + 1 | 0;
+    if ((i | 0) == (5 | 0)) {
+     $6_1 = i;
+     break exit;
+    }
+    continue cont;
+   };
+  }
+  return $6_1 | 0;
+ }
+ 
+ function $2() {
+  var i = 0, $8_1 = 0;
+  i = 0;
+  exit : {
+   cont : while (1) {
+    i = i + 1 | 0;
+    if ((i | 0) == (5 | 0)) {
+     continue cont
+    }
+    if ((i | 0) == (8 | 0)) {
+     $8_1 = i;
+     break exit;
+    }
+    i = i + 1 | 0;
+    continue cont;
+   };
+  }
+  return $8_1 | 0;
+ }
+ 
+ function $3() {
+  var i = 0, $6_1 = 0;
+  i = 0;
+  exit : {
+   cont : while (1) {
+    i = i + 1 | 0;
+    if ((i | 0) == (5 | 0)) {
+     $6_1 = i;
+     break exit;
+    }
+    break cont;
+   };
+   $6_1 = i;
+  }
+  return $6_1 | 0;
+ }
+ 
+ function $4(max) {
+  max = max | 0;
+  var i = 0, $9_1 = 0;
+  i = 1;
+  exit : {
+   cont : while (1) {
+    i = i + i | 0;
+    if (i >>> 0 > max >>> 0) {
+     $9_1 = i;
+     break exit;
+    }
+    continue cont;
+   };
+  }
+  return $9_1 | 0;
+ }
+ 
+ function $5() {
+  var $0_1 = 0;
+  l : while (1) {
+   $0_1 = 1;
+   break l;
+  };
+  return $0_1 + 1 | 0 | 0;
+ }
+ 
+ function $6() {
+  var $2_1 = 0;
+  loop_in : while (1) {
+   if (0) {
+    continue loop_in
+   }
+   $2_1 = 3;
+   break loop_in;
+  };
+  return $2_1 | 0;
+ }
+ 
+ function $7() {
+  var i = 0;
+  i = 0;
+  block : {
+   l : {
+    break l;
+   }
+   i = i + 1 | 0;
+   l1 : {
+    break l1;
+   }
+   i = i + 1 | 0;
+   l2 : {
+    break l2;
+   }
+   i = i + 1 | 0;
+   l3 : {
+    break l3;
+   }
+   i = i + 1 | 0;
+   l4 : {
+    break l4;
+   }
+   i = i + 1 | 0;
+  }
+  return i | 0;
+ }
+ 
+ function $8() {
+  var i = 0;
+  i = 0;
+  block : {
+   if_ : {
+    break if_;
+   }
+   i = i + 1 | 0;
+   if5 : {
+    break if5;
+   }
+   i = i + 1 | 0;
+   if6 : {
+    break if6;
+   }
+   i = i + 1 | 0;
+   if7 : {
+    break if7;
+   }
+   i = i + 1 | 0;
+   if8 : {
+    break if8;
+   }
+   i = i + 1 | 0;
+  }
+  return i | 0;
+ }
+ 
+ function $9($0_1) {
+  $0_1 = $0_1 | 0;
+  var $2_1 = 0, $3_1 = 0;
+  ret : {
+   exit : {
+    $0 : {
+     switch ($0_1 | 0) {
+     case 1:
+     case 2:
+      $2_1 = 2;
+      break exit;
+     case 3:
+      $3_1 = 3;
+      break ret;
+     default:
+     case 0:
+      break $0;
+     };
+    }
+    $2_1 = 5;
+   }
+   $3_1 = Math_imul(10, $2_1);
+  }
+  return $3_1 | 0;
+ }
+ 
+ function $10($0_1) {
+  $0_1 = $0_1 | 0;
+  $1 : {
+   switch ($0_1 | 0) {
+   case 0:
+    return 0 | 0;
+   default:
+    break $1;
+   };
+  }
+  return 2 | 0;
+ }
+ 
+ function $11() {
+  var i = 0, $10_1 = 0;
+  i = 0;
+  outer : {
+   inner : {
+    if (0) {
+     break inner
+    }
+    i = i | 1 | 0;
+    if (1) {
+     break inner
+    }
+    i = i | 2 | 0;
+   }
+   i = i | 4 | 0;
+   $10_1 = i;
+   if (0) {
+    break outer
+   }
+   i = i | 8 | 0;
+   i = i | 16 | 0;
+   $10_1 = i;
+   if (1) {
+    break outer
+   }
+   i = i | 32 | 0;
+   $10_1 = i;
+  }
+  return $10_1 | 0;
+ }
+ 
+ function $12() {
+  var $2_1 = 0, $0_1 = 0;
+  l0 : {
+   l1 : {
+    $0_1 = 1;
+    break l1;
+   }
+   $2_1 = $0_1;
+   if (1) {
+    break l0
+   }
+   $2_1 = 0;
+  }
+  return $2_1 | 0;
+ }
+ 
+ function $13() {
+  var $2_1 = 0, $0_1 = 0;
+  l0 : {
+   l1 : {
+    $0_1 = 1;
+    break l1;
+   }
+   $2_1 = $0_1;
+   if (1) {
+    break l0
+   }
+   $2_1 = 0;
+  }
+  return $2_1 | 0;
+ }
+ 
+ function $14() {
+  var i1 = 0, $7_1 = 0, $3_1 = 0;
+  l0 : {
+   i1 = 1;
+   $3_1 = i1;
+   i1 = 2;
+   $7_1 = $3_1;
+   if (i1) {
+    break l0
+   }
+   $7_1 = 0;
+  }
+  return i1 | 0;
+ }
+ 
+ function $15() {
+  var $2_1 = 0, $0_1 = 0, $3_1 = 0;
+  l0 : {
+   l1 : {
+    $0_1 = 1;
+    break l1;
+   }
+   $2_1 = $0_1;
+   break l0;
+  }
+  return $2_1 | 0;
+ }
+ 
+ function $16() {
+  var $0_1 = 0;
+  l1 : {
+   $0_1 = 1;
+   break l1;
+  }
+  return $0_1 | 0;
+ }
+ 
+ function $17() {
+  var $1_1 = 0, $2_1 = 0;
+  l1 : {
+   $1_1 = 2;
+   l113 : {
+    $2_1 = 3;
+    break l113;
+   }
+  }
+  return $1_1 + $2_1 | 0 | 0;
+ }
+ 
+ return {
+  "block": $0, 
+  "loop1": $1, 
+  "loop2": $2, 
+  "loop3": $3, 
+  "loop4": $4, 
+  "loop5": $5, 
+  "loop6": $6, 
+  "if_": $7, 
+  "if2": $8, 
+  "switch_": $9, 
+  "return_": $10, 
+  "br_if0": $11, 
+  "br_if1": $12, 
+  "br_if2": $13, 
+  "br_if3": $14, 
+  "br": $15, 
+  "shadowing": $16, 
+  "redefinition": $17
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var block = retasmFunc.block;
+export var loop1 = retasmFunc.loop1;
+export var loop2 = retasmFunc.loop2;
+export var loop3 = retasmFunc.loop3;
+export var loop4 = retasmFunc.loop4;
+export var loop5 = retasmFunc.loop5;
+export var loop6 = retasmFunc.loop6;
+export var if_ = retasmFunc.if_;
+export var if2 = retasmFunc.if2;
+export var switch_ = retasmFunc.switch_;
+export var return_ = retasmFunc.return_;
+export var br_if0 = retasmFunc.br_if0;
+export var br_if1 = retasmFunc.br_if1;
+export var br_if2 = retasmFunc.br_if2;
+export var br_if3 = retasmFunc.br_if3;
+export var br = retasmFunc.br;
+export var shadowing = retasmFunc.shadowing;
+export var redefinition = retasmFunc.redefinition;
diff --git a/binaryen/test/wasm2js/left-to-right.2asm.js b/binaryen/test/wasm2js/left-to-right.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/left-to-right.2asm.js
@@ -0,0 +1,2279 @@
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_scratch_load_i32(index) {
+    return i32ScratchView[index];
+  }
+      
+  function wasm2js_scratch_store_i32(index, value) {
+    i32ScratchView[index] = value;
+  }
+      
+  function wasm2js_scratch_load_f64() {
+    return f64ScratchView[0];
+  }
+      
+  function wasm2js_scratch_store_f64(value) {
+    f64ScratchView[0] = value;
+  }
+      
+  function wasm2js_scratch_store_f32(value) {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function i32_t0($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  return -1 | 0;
+ }
+ 
+ function i32_t1($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+  return -2 | 0;
+ }
+ 
+ function i64_t0($0, $0$hi, $1, $1$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1 = $1 | 0;
+  $1$hi = $1$hi | 0;
+  return -1 | 0;
+ }
+ 
+ function i64_t1($0, $0$hi, $1, $1$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1 = $1 | 0;
+  $1$hi = $1$hi | 0;
+  return -2 | 0;
+ }
+ 
+ function f32_t0($0, $1) {
+  $0 = Math_fround($0);
+  $1 = Math_fround($1);
+  return -1 | 0;
+ }
+ 
+ function f32_t1($0, $1) {
+  $0 = Math_fround($0);
+  $1 = Math_fround($1);
+  return -2 | 0;
+ }
+ 
+ function f64_t0($0, $1) {
+  $0 = +$0;
+  $1 = +$1;
+  return -1 | 0;
+ }
+ 
+ function f64_t1($0, $1) {
+  $0 = +$0;
+  $1 = +$1;
+  return -2 | 0;
+ }
+ 
+ function reset() {
+  HEAP32[8 >> 2] = 0;
+ }
+ 
+ function bump() {
+  HEAP8[11 >> 0] = HEAPU8[10 >> 0] | 0;
+  HEAP8[10 >> 0] = HEAPU8[9 >> 0] | 0;
+  HEAP8[9 >> 0] = HEAPU8[8 >> 0] | 0;
+  HEAP8[8 >> 0] = -3;
+ }
+ 
+ function get() {
+  return HEAP32[8 >> 2] | 0 | 0;
+ }
+ 
+ function i32_left() {
+  bump();
+  HEAP8[8 >> 0] = 1;
+  return 0 | 0;
+ }
+ 
+ function i32_right() {
+  bump();
+  HEAP8[8 >> 0] = 2;
+  return 1 | 0;
+ }
+ 
+ function i32_callee() {
+  bump();
+  HEAP8[8 >> 0] = 4;
+  return 0 | 0;
+ }
+ 
+ function i32_bool() {
+  bump();
+  HEAP8[8 >> 0] = 5;
+  return 0 | 0;
+ }
+ 
+ function i64_left() {
+  var i64toi32_i32$0 = 0;
+  bump();
+  HEAP8[8 >> 0] = 1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return 0 | 0;
+ }
+ 
+ function i64_right() {
+  var i64toi32_i32$0 = 0;
+  bump();
+  HEAP8[8 >> 0] = 2;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return 1 | 0;
+ }
+ 
+ function i64_callee() {
+  bump();
+  HEAP8[8 >> 0] = 4;
+  return 2 | 0;
+ }
+ 
+ function i64_bool() {
+  bump();
+  HEAP8[8 >> 0] = 5;
+  return 0 | 0;
+ }
+ 
+ function f32_left() {
+  bump();
+  HEAP8[8 >> 0] = 1;
+  return Math_fround(Math_fround(0.0));
+ }
+ 
+ function f32_right() {
+  bump();
+  HEAP8[8 >> 0] = 2;
+  return Math_fround(Math_fround(1.0));
+ }
+ 
+ function f32_callee() {
+  bump();
+  HEAP8[8 >> 0] = 4;
+  return 4 | 0;
+ }
+ 
+ function f32_bool() {
+  bump();
+  HEAP8[8 >> 0] = 5;
+  return 0 | 0;
+ }
+ 
+ function f64_left() {
+  bump();
+  HEAP8[8 >> 0] = 1;
+  return +(0.0);
+ }
+ 
+ function f64_right() {
+  bump();
+  HEAP8[8 >> 0] = 2;
+  return +(1.0);
+ }
+ 
+ function f64_callee() {
+  bump();
+  HEAP8[8 >> 0] = 4;
+  return 6 | 0;
+ }
+ 
+ function f64_bool() {
+  bump();
+  HEAP8[8 >> 0] = 5;
+  return 0 | 0;
+ }
+ 
+ function i32_dummy($0, $1) {
+  $0 = $0 | 0;
+  $1 = $1 | 0;
+ }
+ 
+ function i64_dummy($0, $0$hi, $1, $1$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  $1 = $1 | 0;
+  $1$hi = $1$hi | 0;
+ }
+ 
+ function f32_dummy($0, $1) {
+  $0 = Math_fround($0);
+  $1 = Math_fround($1);
+ }
+ 
+ function f64_dummy($0, $1) {
+  $0 = +$0;
+  $1 = +$1;
+ }
+ 
+ function $35() {
+  reset();
+  (i32_left() | 0) + (i32_right() | 0) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $36() {
+  reset();
+  (i32_left() | 0) - (i32_right() | 0) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $37() {
+  reset();
+  Math_imul(i32_left() | 0, i32_right() | 0);
+  return get() | 0 | 0;
+ }
+ 
+ function $38() {
+  reset();
+  (i32_left() | 0 | 0) / (i32_right() | 0 | 0) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $39() {
+  reset();
+  ((i32_left() | 0) >>> 0) / ((i32_right() | 0) >>> 0) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $40() {
+  reset();
+  (i32_left() | 0 | 0) % (i32_right() | 0 | 0) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $41() {
+  reset();
+  ((i32_left() | 0) >>> 0) % ((i32_right() | 0) >>> 0) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $42() {
+  reset();
+  (i32_left() | 0) & (i32_right() | 0) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $43() {
+  reset();
+  i32_left() | 0 | (i32_right() | 0) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $44() {
+  reset();
+  (i32_left() | 0) ^ (i32_right() | 0) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $45() {
+  reset();
+  (i32_left() | 0) << (i32_right() | 0) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $46() {
+  reset();
+  (i32_left() | 0) >>> (i32_right() | 0) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $47() {
+  reset();
+  (i32_left() | 0) >> (i32_right() | 0) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $48() {
+  reset();
+  (i32_left() | 0 | 0) == (i32_right() | 0 | 0);
+  return get() | 0 | 0;
+ }
+ 
+ function $49() {
+  reset();
+  (i32_left() | 0 | 0) != (i32_right() | 0 | 0);
+  return get() | 0 | 0;
+ }
+ 
+ function $50() {
+  reset();
+  (i32_left() | 0 | 0) < (i32_right() | 0 | 0);
+  return get() | 0 | 0;
+ }
+ 
+ function $51() {
+  reset();
+  (i32_left() | 0 | 0) <= (i32_right() | 0 | 0);
+  return get() | 0 | 0;
+ }
+ 
+ function $52() {
+  reset();
+  (i32_left() | 0) >>> 0 < (i32_right() | 0) >>> 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $53() {
+  reset();
+  (i32_left() | 0) >>> 0 <= (i32_right() | 0) >>> 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $54() {
+  reset();
+  (i32_left() | 0 | 0) > (i32_right() | 0 | 0);
+  return get() | 0 | 0;
+ }
+ 
+ function $55() {
+  reset();
+  (i32_left() | 0 | 0) >= (i32_right() | 0 | 0);
+  return get() | 0 | 0;
+ }
+ 
+ function $56() {
+  reset();
+  (i32_left() | 0) >>> 0 > (i32_right() | 0) >>> 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $57() {
+  reset();
+  (i32_left() | 0) >>> 0 >= (i32_right() | 0) >>> 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $58() {
+  var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0;
+  reset();
+  (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$1 = i32_right() | 0), HEAP32[wasm2js_i32$0 >> 2] = wasm2js_i32$1;
+  return get() | 0 | 0;
+ }
+ 
+ function $59() {
+  var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0;
+  reset();
+  (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$1 = i32_right() | 0), HEAP8[wasm2js_i32$0 >> 0] = wasm2js_i32$1;
+  return get() | 0 | 0;
+ }
+ 
+ function $60() {
+  var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0;
+  reset();
+  (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$1 = i32_right() | 0), HEAP16[wasm2js_i32$0 >> 1] = wasm2js_i32$1;
+  return get() | 0 | 0;
+ }
+ 
+ function $61() {
+  reset();
+  i32_dummy(i32_left() | 0 | 0, i32_right() | 0 | 0);
+  return get() | 0 | 0;
+ }
+ 
+ function $62() {
+  var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0, wasm2js_i32$2 = 0;
+  reset();
+  ((wasm2js_i32$1 = i32_left() | 0, wasm2js_i32$2 = i32_right() | 0), wasm2js_i32$0 = i32_callee() | 0 | 0), FUNCTION_TABLE[wasm2js_i32$0](wasm2js_i32$1 | 0, wasm2js_i32$2 | 0) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $63() {
+  var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0, wasm2js_i32$2 = 0;
+  reset();
+  wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$1 = i32_right() | 0, wasm2js_i32$2 = i32_bool() | 0, wasm2js_i32$2 ? wasm2js_i32$0 : wasm2js_i32$1;
+  return get() | 0 | 0;
+ }
+ 
+ function $64() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$5 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$3 = $1;
+  i64toi32_i32$4 = $0 + i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = i64toi32_i32$0 + i64toi32_i32$1 | 0;
+  if (i64toi32_i32$4 >>> 0 < i64toi32_i32$3 >>> 0) {
+   i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+  }
+  return get() | 0 | 0;
+ }
+ 
+ function $65() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$2 = $0;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$3 = $1;
+  i64toi32_i32$5 = (i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0) + i64toi32_i32$1 | 0;
+  i64toi32_i32$5 = i64toi32_i32$0 - i64toi32_i32$5 | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $66() {
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$1 = __wasm_i64_mul($0 | 0, i64toi32_i32$0 | 0, $1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  return get() | 0 | 0;
+ }
+ 
+ function $67() {
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$1 = __wasm_i64_sdiv($0 | 0, i64toi32_i32$0 | 0, $1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  return get() | 0 | 0;
+ }
+ 
+ function $68() {
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$1 = __wasm_i64_udiv($0 | 0, i64toi32_i32$0 | 0, $1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  return get() | 0 | 0;
+ }
+ 
+ function $69() {
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$1 = __wasm_i64_srem($0 | 0, i64toi32_i32$0 | 0, $1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  return get() | 0 | 0;
+ }
+ 
+ function $70() {
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$1 = __wasm_i64_urem($0 | 0, i64toi32_i32$0 | 0, $1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  return get() | 0 | 0;
+ }
+ 
+ function $71() {
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 & i64toi32_i32$1 | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $72() {
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $73() {
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$1 | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $74() {
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, $9 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$2 = $0;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$3 = $1;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $9 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $9 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  return get() | 0 | 0;
+ }
+ 
+ function $75() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $9 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0, i64toi32_i32$2 = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$2 = $0;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$3 = $1;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = 0;
+   $9 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $9 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  return get() | 0 | 0;
+ }
+ 
+ function $76() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $9 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0, i64toi32_i32$2 = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$2 = $0;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$3 = $1;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $9 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $9 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  return get() | 0 | 0;
+ }
+ 
+ function $77() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  return get() | 0 | 0;
+ }
+ 
+ function $78() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  return get() | 0 | 0;
+ }
+ 
+ function $79() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $8 = 0, $9 = 0, $10 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$2 = $0;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$3 = $1;
+  if ((i64toi32_i32$0 | 0) < (i64toi32_i32$1 | 0)) {
+   $8 = 1
+  } else {
+   if ((i64toi32_i32$0 | 0) <= (i64toi32_i32$1 | 0)) {
+    if (i64toi32_i32$2 >>> 0 >= i64toi32_i32$3 >>> 0) {
+     $9 = 0
+    } else {
+     $9 = 1
+    }
+    $10 = $9;
+   } else {
+    $10 = 0
+   }
+   $8 = $10;
+  }
+  return get() | 0 | 0;
+ }
+ 
+ function $80() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $8 = 0, $9 = 0, $10 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$2 = $0;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$3 = $1;
+  if ((i64toi32_i32$0 | 0) < (i64toi32_i32$1 | 0)) {
+   $8 = 1
+  } else {
+   if ((i64toi32_i32$0 | 0) <= (i64toi32_i32$1 | 0)) {
+    if (i64toi32_i32$2 >>> 0 > i64toi32_i32$3 >>> 0) {
+     $9 = 0
+    } else {
+     $9 = 1
+    }
+    $10 = $9;
+   } else {
+    $10 = 0
+   }
+   $8 = $10;
+  }
+  return get() | 0 | 0;
+ }
+ 
+ function $81() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  return get() | 0 | 0;
+ }
+ 
+ function $82() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  return get() | 0 | 0;
+ }
+ 
+ function $83() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $8 = 0, $9 = 0, $10 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$2 = $0;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$3 = $1;
+  if ((i64toi32_i32$0 | 0) > (i64toi32_i32$1 | 0)) {
+   $8 = 1
+  } else {
+   if ((i64toi32_i32$0 | 0) >= (i64toi32_i32$1 | 0)) {
+    if (i64toi32_i32$2 >>> 0 <= i64toi32_i32$3 >>> 0) {
+     $9 = 0
+    } else {
+     $9 = 1
+    }
+    $10 = $9;
+   } else {
+    $10 = 0
+   }
+   $8 = $10;
+  }
+  return get() | 0 | 0;
+ }
+ 
+ function $84() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $8 = 0, $9 = 0, $10 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$2 = $0;
+  i64toi32_i32$1 = $1$hi;
+  i64toi32_i32$3 = $1;
+  if ((i64toi32_i32$0 | 0) > (i64toi32_i32$1 | 0)) {
+   $8 = 1
+  } else {
+   if ((i64toi32_i32$0 | 0) >= (i64toi32_i32$1 | 0)) {
+    if (i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0) {
+     $9 = 0
+    } else {
+     $9 = 1
+    }
+    $10 = $9;
+   } else {
+    $10 = 0
+   }
+   $8 = $10;
+  }
+  return get() | 0 | 0;
+ }
+ 
+ function $85() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  return get() | 0 | 0;
+ }
+ 
+ function $86() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  return get() | 0 | 0;
+ }
+ 
+ function $87() {
+  var i64toi32_i32$0 = 0, $0 = 0, i64toi32_i32$1 = 0, $1 = 0;
+  reset();
+  $0 = i32_left() | 0;
+  i64toi32_i32$0 = i64_right() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$0;
+  i64toi32_i32$0 = $0;
+  HEAP32[i64toi32_i32$0 >> 2] = $1;
+  HEAP32[(i64toi32_i32$0 + 4 | 0) >> 2] = i64toi32_i32$1;
+  return get() | 0 | 0;
+ }
+ 
+ function $88() {
+  var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0;
+  reset();
+  (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$1 = i64_right() | 0), HEAP8[wasm2js_i32$0 >> 0] = wasm2js_i32$1;
+  return get() | 0 | 0;
+ }
+ 
+ function $89() {
+  var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0;
+  reset();
+  (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$1 = i64_right() | 0), HEAP16[wasm2js_i32$0 >> 1] = wasm2js_i32$1;
+  return get() | 0 | 0;
+ }
+ 
+ function $90() {
+  var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0;
+  reset();
+  (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$1 = i64_right() | 0), HEAP32[wasm2js_i32$0 >> 2] = wasm2js_i32$1;
+  return get() | 0 | 0;
+ }
+ 
+ function $91() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  i64_dummy($0 | 0, i64toi32_i32$0 | 0, $1 | 0, i64toi32_i32$1 | 0);
+  return get() | 0 | 0;
+ }
+ 
+ function $92() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  FUNCTION_TABLE[i64_callee() | 0 | 0]($0, i64toi32_i32$0, $1, i64toi32_i32$1) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $93() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $0 = 0, $0$hi = 0, $1 = 0, $1$hi = 0, i64toi32_i32$4 = 0;
+  reset();
+  i64toi32_i32$0 = i64_left() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = i64_right() | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $1 = i64toi32_i32$1;
+  $1$hi = i64toi32_i32$0;
+  i64toi32_i32$4 = i64_bool() | 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $1$hi;
+  return get() | 0 | 0;
+ }
+ 
+ function $94() {
+  reset();
+  Math_fround(Math_fround(f32_left()) + Math_fround(f32_right()));
+  return get() | 0 | 0;
+ }
+ 
+ function $95() {
+  reset();
+  Math_fround(Math_fround(f32_left()) - Math_fround(f32_right()));
+  return get() | 0 | 0;
+ }
+ 
+ function $96() {
+  reset();
+  Math_fround(Math_fround(f32_left()) * Math_fround(f32_right()));
+  return get() | 0 | 0;
+ }
+ 
+ function $97() {
+  reset();
+  Math_fround(Math_fround(f32_left()) / Math_fround(f32_right()));
+  return get() | 0 | 0;
+ }
+ 
+ function $98() {
+  reset();
+  (wasm2js_scratch_store_f32(Math_fround(f32_left())), wasm2js_scratch_load_i32(2)) & 2147483647 | 0 | ((wasm2js_scratch_store_f32(Math_fround(f32_right())), wasm2js_scratch_load_i32(2)) & -2147483648 | 0) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $99() {
+  reset();
+  Math_fround(f32_left()) == Math_fround(f32_right());
+  return get() | 0 | 0;
+ }
+ 
+ function $100() {
+  reset();
+  Math_fround(f32_left()) != Math_fround(f32_right());
+  return get() | 0 | 0;
+ }
+ 
+ function $101() {
+  reset();
+  Math_fround(f32_left()) < Math_fround(f32_right());
+  return get() | 0 | 0;
+ }
+ 
+ function $102() {
+  reset();
+  Math_fround(f32_left()) <= Math_fround(f32_right());
+  return get() | 0 | 0;
+ }
+ 
+ function $103() {
+  reset();
+  Math_fround(f32_left()) > Math_fround(f32_right());
+  return get() | 0 | 0;
+ }
+ 
+ function $104() {
+  reset();
+  Math_fround(f32_left()) >= Math_fround(f32_right());
+  return get() | 0 | 0;
+ }
+ 
+ function $105() {
+  reset();
+  Math_fround(Math_min(Math_fround(f32_left()), Math_fround(f32_right())));
+  return get() | 0 | 0;
+ }
+ 
+ function $106() {
+  reset();
+  Math_fround(Math_max(Math_fround(f32_left()), Math_fround(f32_right())));
+  return get() | 0 | 0;
+ }
+ 
+ function $107() {
+  var wasm2js_i32$0 = 0, wasm2js_f32$0 = Math_fround(0);
+  reset();
+  (wasm2js_i32$0 = i32_left() | 0, wasm2js_f32$0 = Math_fround(f32_right())), HEAPF32[wasm2js_i32$0 >> 2] = wasm2js_f32$0;
+  return get() | 0 | 0;
+ }
+ 
+ function $108() {
+  reset();
+  f32_dummy(Math_fround(Math_fround(f32_left())), Math_fround(Math_fround(f32_right())));
+  return get() | 0 | 0;
+ }
+ 
+ function $109() {
+  var wasm2js_i32$0 = 0, wasm2js_f32$0 = Math_fround(0), wasm2js_f32$1 = Math_fround(0);
+  reset();
+  ((wasm2js_f32$0 = Math_fround(f32_left()), wasm2js_f32$1 = Math_fround(f32_right())), wasm2js_i32$0 = f32_callee() | 0 | 0), FUNCTION_TABLE[wasm2js_i32$0](Math_fround(wasm2js_f32$0), Math_fround(wasm2js_f32$1)) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $110() {
+  var wasm2js_f32$0 = Math_fround(0), wasm2js_f32$1 = Math_fround(0), wasm2js_i32$0 = 0;
+  reset();
+  wasm2js_f32$0 = Math_fround(f32_left()), wasm2js_f32$1 = Math_fround(f32_right()), wasm2js_i32$0 = f32_bool() | 0, wasm2js_i32$0 ? wasm2js_f32$0 : wasm2js_f32$1;
+  return get() | 0 | 0;
+ }
+ 
+ function $111() {
+  reset();
+  +f64_left() + +f64_right();
+  return get() | 0 | 0;
+ }
+ 
+ function $112() {
+  reset();
+  +f64_left() - +f64_right();
+  return get() | 0 | 0;
+ }
+ 
+ function $113() {
+  reset();
+  +f64_left() * +f64_right();
+  return get() | 0 | 0;
+ }
+ 
+ function $114() {
+  reset();
+  +f64_left() / +f64_right();
+  return get() | 0 | 0;
+ }
+ 
+ function $115() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $2 = 0, $2$hi = 0, $5 = 0, $5$hi = 0;
+  reset();
+  wasm2js_scratch_store_f64(+(+f64_left()));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$2 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$1 = 2147483647;
+  i64toi32_i32$3 = -1;
+  i64toi32_i32$1 = i64toi32_i32$0 & i64toi32_i32$1 | 0;
+  $2 = i64toi32_i32$2 & i64toi32_i32$3 | 0;
+  $2$hi = i64toi32_i32$1;
+  wasm2js_scratch_store_f64(+(+f64_right()));
+  i64toi32_i32$1 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  i64toi32_i32$2 = -2147483648;
+  i64toi32_i32$3 = 0;
+  i64toi32_i32$2 = i64toi32_i32$1 & i64toi32_i32$2 | 0;
+  $5 = i64toi32_i32$0 & i64toi32_i32$3 | 0;
+  $5$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $2$hi;
+  i64toi32_i32$1 = $2;
+  i64toi32_i32$0 = $5$hi;
+  i64toi32_i32$3 = $5;
+  i64toi32_i32$0 = i64toi32_i32$2 | i64toi32_i32$0 | 0;
+  wasm2js_scratch_store_i32(0 | 0, i64toi32_i32$1 | i64toi32_i32$3 | 0 | 0);
+  wasm2js_scratch_store_i32(1 | 0, i64toi32_i32$0 | 0);
+  +wasm2js_scratch_load_f64();
+  return get() | 0 | 0;
+ }
+ 
+ function $116() {
+  reset();
+  +f64_left() == +f64_right();
+  return get() | 0 | 0;
+ }
+ 
+ function $117() {
+  reset();
+  +f64_left() != +f64_right();
+  return get() | 0 | 0;
+ }
+ 
+ function $118() {
+  reset();
+  +f64_left() < +f64_right();
+  return get() | 0 | 0;
+ }
+ 
+ function $119() {
+  reset();
+  +f64_left() <= +f64_right();
+  return get() | 0 | 0;
+ }
+ 
+ function $120() {
+  reset();
+  +f64_left() > +f64_right();
+  return get() | 0 | 0;
+ }
+ 
+ function $121() {
+  reset();
+  +f64_left() >= +f64_right();
+  return get() | 0 | 0;
+ }
+ 
+ function $122() {
+  reset();
+  Math_min(+f64_left(), +f64_right());
+  return get() | 0 | 0;
+ }
+ 
+ function $123() {
+  reset();
+  Math_max(+f64_left(), +f64_right());
+  return get() | 0 | 0;
+ }
+ 
+ function $124() {
+  var wasm2js_i32$0 = 0, wasm2js_f64$0 = 0.0;
+  reset();
+  (wasm2js_i32$0 = i32_left() | 0, wasm2js_f64$0 = +f64_right()), HEAPF64[wasm2js_i32$0 >> 3] = wasm2js_f64$0;
+  return get() | 0 | 0;
+ }
+ 
+ function $125() {
+  reset();
+  f64_dummy(+(+f64_left()), +(+f64_right()));
+  return get() | 0 | 0;
+ }
+ 
+ function $126() {
+  var wasm2js_i32$0 = 0, wasm2js_f64$0 = 0.0, wasm2js_f64$1 = 0.0;
+  reset();
+  ((wasm2js_f64$0 = +f64_left(), wasm2js_f64$1 = +f64_right()), wasm2js_i32$0 = f64_callee() | 0 | 0), FUNCTION_TABLE[wasm2js_i32$0](+wasm2js_f64$0, +wasm2js_f64$1) | 0;
+  return get() | 0 | 0;
+ }
+ 
+ function $127() {
+  var wasm2js_f64$0 = 0.0, wasm2js_f64$1 = 0.0, wasm2js_i32$0 = 0;
+  reset();
+  wasm2js_f64$0 = +f64_left(), wasm2js_f64$1 = +f64_right(), wasm2js_i32$0 = f64_bool() | 0, wasm2js_i32$0 ? wasm2js_f64$0 : wasm2js_f64$1;
+  return get() | 0 | 0;
+ }
+ 
+ function $128() {
+  var $3 = 0;
+  block : {
+   reset();
+   $3 = i32_left() | 0;
+   if ((i32_right() | 0) & 0 | 0) {
+    break block
+   }
+   $3 = get() | 0;
+  }
+  return $3 | 0;
+ }
+ 
+ function $129() {
+  var $2 = 0, $3 = 0, $4 = 0;
+  a : {
+   reset();
+   b : {
+    $2 = i32_left() | 0;
+    $3 = $2;
+    $4 = $2;
+    switch (i32_right() | 0 | 0) {
+    case 0:
+     break a;
+    default:
+     break b;
+    };
+   }
+   $3 = get() | 0;
+  }
+  return $3 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, var$2 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, var$3 = 0, var$4 = 0, var$5 = 0, $21 = 0, $22 = 0, var$6 = 0, $24 = 0, $17 = 0, $18 = 0, $23 = 0, $29 = 0, $45_1 = 0, $56$hi = 0, $62$hi = 0;
+  i64toi32_i32$0 = var$1$hi;
+  var$2 = var$1;
+  var$4 = var$2 >>> 16 | 0;
+  i64toi32_i32$0 = var$0$hi;
+  var$3 = var$0;
+  var$5 = var$3 >>> 16 | 0;
+  $17 = Math_imul(var$4, var$5);
+  $18 = var$2;
+  i64toi32_i32$2 = var$3;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = 0;
+   $21 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  $23 = $17 + Math_imul($18, $21) | 0;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$0 = var$1;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $22 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $22 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  $29 = $23 + Math_imul($22, var$3) | 0;
+  var$2 = var$2 & 65535 | 0;
+  var$3 = var$3 & 65535 | 0;
+  var$6 = Math_imul(var$2, var$3);
+  var$2 = (var$6 >>> 16 | 0) + Math_imul(var$2, var$5) | 0;
+  $45_1 = $29 + (var$2 >>> 16 | 0) | 0;
+  var$2 = (var$2 & 65535 | 0) + Math_imul(var$4, var$3) | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $45_1 + (var$2 >>> 16 | 0) | 0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $24 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $24 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $56$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  $62$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $56$hi;
+  i64toi32_i32$2 = $24;
+  i64toi32_i32$1 = $62$hi;
+  i64toi32_i32$3 = var$2 << 16 | 0 | (var$6 & 65535 | 0) | 0;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  i64toi32_i32$2 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, $21 = 0, $22 = 0, $23 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $23$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $21 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $21;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $22 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $22 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$2 = $22;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$5 = var$2;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_udiv($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17 = i64toi32_i32$1;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$5 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$1 >> 31 | 0;
+   $23 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+   $23 = (((1 << i64toi32_i32$5 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$5 | 0) | 0 | (i64toi32_i32$4 >>> i64toi32_i32$5 | 0) | 0;
+  }
+  var$0 = $23;
+  var$0$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $17$hi;
+  i64toi32_i32$1 = $17;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$4 | 0;
+  $23$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = $23$hi;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+  i64toi32_i32$0 = i64toi32_i32$4 - i64toi32_i32$0 | 0;
+  i64toi32_i32$2 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, var$2 = 0, $20 = 0, $21 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17$hi = 0, $19$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $20 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $20 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $20;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $21 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $21 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$0 = $21;
+  var$0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_urem($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$2$hi;
+  i64toi32_i32$4 = $17$hi;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  $19$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$1 = $19$hi;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = var$2$hi;
+  i64toi32_i32$5 = i64toi32_i32$4 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$4 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$2 | 0;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$0 | 0;
+  i64toi32_i32$4 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$4 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37_1 = 0, $38_1 = 0, $39_1 = 0, $40_1 = 0, $41_1 = 0, $42_1 = 0, $43_1 = 0, $44_1 = 0, var$8$hi = 0, $45_1 = 0, $46_1 = 0, $47_1 = 0, $48_1 = 0, var$7$hi = 0, $49_1 = 0, $63$hi = 0, $65_1 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37_1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37_1;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38_1;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39_1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39_1;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40_1 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65_1 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40_1;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65_1;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41_1 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41_1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41_1;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42_1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42_1;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43_1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43_1;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44_1 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44_1 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44_1;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45_1 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45_1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45_1;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46_1 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46_1 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46_1;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47_1 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47_1 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47_1;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48_1 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48_1 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48_1;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49_1 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49_1 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49_1;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_mul(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_sdiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_srem(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_udiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_urem(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$0 = __wasm_intrinsics_temp_i64$hi;
+  i64toi32_i32$1 = __wasm_intrinsics_temp_i64;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ 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;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "i32_add": $35, 
+  "i32_sub": $36, 
+  "i32_mul": $37, 
+  "i32_div_s": $38, 
+  "i32_div_u": $39, 
+  "i32_rem_s": $40, 
+  "i32_rem_u": $41, 
+  "i32_and": $42, 
+  "i32_or": $43, 
+  "i32_xor": $44, 
+  "i32_shl": $45, 
+  "i32_shr_u": $46, 
+  "i32_shr_s": $47, 
+  "i32_eq": $48, 
+  "i32_ne": $49, 
+  "i32_lt_s": $50, 
+  "i32_le_s": $51, 
+  "i32_lt_u": $52, 
+  "i32_le_u": $53, 
+  "i32_gt_s": $54, 
+  "i32_ge_s": $55, 
+  "i32_gt_u": $56, 
+  "i32_ge_u": $57, 
+  "i32_store": $58, 
+  "i32_store8": $59, 
+  "i32_store16": $60, 
+  "i32_call": $61, 
+  "i32_call_indirect": $62, 
+  "i32_select": $63, 
+  "i64_add": $64, 
+  "i64_sub": $65, 
+  "i64_mul": $66, 
+  "i64_div_s": $67, 
+  "i64_div_u": $68, 
+  "i64_rem_s": $69, 
+  "i64_rem_u": $70, 
+  "i64_and": $71, 
+  "i64_or": $72, 
+  "i64_xor": $73, 
+  "i64_shl": $74, 
+  "i64_shr_u": $75, 
+  "i64_shr_s": $76, 
+  "i64_eq": $77, 
+  "i64_ne": $78, 
+  "i64_lt_s": $79, 
+  "i64_le_s": $80, 
+  "i64_lt_u": $81, 
+  "i64_le_u": $82, 
+  "i64_gt_s": $83, 
+  "i64_ge_s": $84, 
+  "i64_gt_u": $85, 
+  "i64_ge_u": $86, 
+  "i64_store": $87, 
+  "i64_store8": $88, 
+  "i64_store16": $89, 
+  "i64_store32": $90, 
+  "i64_call": $91, 
+  "i64_call_indirect": $92, 
+  "i64_select": $93, 
+  "f32_add": $94, 
+  "f32_sub": $95, 
+  "f32_mul": $96, 
+  "f32_div": $97, 
+  "f32_copysign": $98, 
+  "f32_eq": $99, 
+  "f32_ne": $100, 
+  "f32_lt": $101, 
+  "f32_le": $102, 
+  "f32_gt": $103, 
+  "f32_ge": $104, 
+  "f32_min": $105, 
+  "f32_max": $106, 
+  "f32_store": $107, 
+  "f32_call": $108, 
+  "f32_call_indirect": $109, 
+  "f32_select": $110, 
+  "f64_add": $111, 
+  "f64_sub": $112, 
+  "f64_mul": $113, 
+  "f64_div": $114, 
+  "f64_copysign": $115, 
+  "f64_eq": $116, 
+  "f64_ne": $117, 
+  "f64_lt": $118, 
+  "f64_le": $119, 
+  "f64_gt": $120, 
+  "f64_ge": $121, 
+  "f64_min": $122, 
+  "f64_max": $123, 
+  "f64_store": $124, 
+  "f64_call": $125, 
+  "f64_call_indirect": $126, 
+  "f64_select": $127, 
+  "br_if": $128, 
+  "br_table": $129
+ };
+}
+
+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
+);
+export var i32_add = retasmFunc.i32_add;
+export var i32_sub = retasmFunc.i32_sub;
+export var i32_mul = retasmFunc.i32_mul;
+export var i32_div_s = retasmFunc.i32_div_s;
+export var i32_div_u = retasmFunc.i32_div_u;
+export var i32_rem_s = retasmFunc.i32_rem_s;
+export var i32_rem_u = retasmFunc.i32_rem_u;
+export var i32_and = retasmFunc.i32_and;
+export var i32_or = retasmFunc.i32_or;
+export var i32_xor = retasmFunc.i32_xor;
+export var i32_shl = retasmFunc.i32_shl;
+export var i32_shr_u = retasmFunc.i32_shr_u;
+export var i32_shr_s = retasmFunc.i32_shr_s;
+export var i32_eq = retasmFunc.i32_eq;
+export var i32_ne = retasmFunc.i32_ne;
+export var i32_lt_s = retasmFunc.i32_lt_s;
+export var i32_le_s = retasmFunc.i32_le_s;
+export var i32_lt_u = retasmFunc.i32_lt_u;
+export var i32_le_u = retasmFunc.i32_le_u;
+export var i32_gt_s = retasmFunc.i32_gt_s;
+export var i32_ge_s = retasmFunc.i32_ge_s;
+export var i32_gt_u = retasmFunc.i32_gt_u;
+export var i32_ge_u = retasmFunc.i32_ge_u;
+export var i32_store = retasmFunc.i32_store;
+export var i32_store8 = retasmFunc.i32_store8;
+export var i32_store16 = retasmFunc.i32_store16;
+export var i32_call = retasmFunc.i32_call;
+export var i32_call_indirect = retasmFunc.i32_call_indirect;
+export var i32_select = retasmFunc.i32_select;
+export var i64_add = retasmFunc.i64_add;
+export var i64_sub = retasmFunc.i64_sub;
+export var i64_mul = retasmFunc.i64_mul;
+export var i64_div_s = retasmFunc.i64_div_s;
+export var i64_div_u = retasmFunc.i64_div_u;
+export var i64_rem_s = retasmFunc.i64_rem_s;
+export var i64_rem_u = retasmFunc.i64_rem_u;
+export var i64_and = retasmFunc.i64_and;
+export var i64_or = retasmFunc.i64_or;
+export var i64_xor = retasmFunc.i64_xor;
+export var i64_shl = retasmFunc.i64_shl;
+export var i64_shr_u = retasmFunc.i64_shr_u;
+export var i64_shr_s = retasmFunc.i64_shr_s;
+export var i64_eq = retasmFunc.i64_eq;
+export var i64_ne = retasmFunc.i64_ne;
+export var i64_lt_s = retasmFunc.i64_lt_s;
+export var i64_le_s = retasmFunc.i64_le_s;
+export var i64_lt_u = retasmFunc.i64_lt_u;
+export var i64_le_u = retasmFunc.i64_le_u;
+export var i64_gt_s = retasmFunc.i64_gt_s;
+export var i64_ge_s = retasmFunc.i64_ge_s;
+export var i64_gt_u = retasmFunc.i64_gt_u;
+export var i64_ge_u = retasmFunc.i64_ge_u;
+export var i64_store = retasmFunc.i64_store;
+export var i64_store8 = retasmFunc.i64_store8;
+export var i64_store16 = retasmFunc.i64_store16;
+export var i64_store32 = retasmFunc.i64_store32;
+export var i64_call = retasmFunc.i64_call;
+export var i64_call_indirect = retasmFunc.i64_call_indirect;
+export var i64_select = retasmFunc.i64_select;
+export var f32_add = retasmFunc.f32_add;
+export var f32_sub = retasmFunc.f32_sub;
+export var f32_mul = retasmFunc.f32_mul;
+export var f32_div = retasmFunc.f32_div;
+export var f32_copysign = retasmFunc.f32_copysign;
+export var f32_eq = retasmFunc.f32_eq;
+export var f32_ne = retasmFunc.f32_ne;
+export var f32_lt = retasmFunc.f32_lt;
+export var f32_le = retasmFunc.f32_le;
+export var f32_gt = retasmFunc.f32_gt;
+export var f32_ge = retasmFunc.f32_ge;
+export var f32_min = retasmFunc.f32_min;
+export var f32_max = retasmFunc.f32_max;
+export var f32_store = retasmFunc.f32_store;
+export var f32_call = retasmFunc.f32_call;
+export var f32_call_indirect = retasmFunc.f32_call_indirect;
+export var f32_select = retasmFunc.f32_select;
+export var f64_add = retasmFunc.f64_add;
+export var f64_sub = retasmFunc.f64_sub;
+export var f64_mul = retasmFunc.f64_mul;
+export var f64_div = retasmFunc.f64_div;
+export var f64_copysign = retasmFunc.f64_copysign;
+export var f64_eq = retasmFunc.f64_eq;
+export var f64_ne = retasmFunc.f64_ne;
+export var f64_lt = retasmFunc.f64_lt;
+export var f64_le = retasmFunc.f64_le;
+export var f64_gt = retasmFunc.f64_gt;
+export var f64_ge = retasmFunc.f64_ge;
+export var f64_min = retasmFunc.f64_min;
+export var f64_max = retasmFunc.f64_max;
+export var f64_store = retasmFunc.f64_store;
+export var f64_call = retasmFunc.f64_call;
+export var f64_call_indirect = retasmFunc.f64_call_indirect;
+export var f64_select = retasmFunc.f64_select;
+export var br_if = retasmFunc.br_if;
+export var br_table = retasmFunc.br_table;
diff --git a/binaryen/test/wasm2js/minified-memory.2asm.js b/binaryen/test/wasm2js/minified-memory.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/minified-memory.2asm.js
@@ -0,0 +1,80 @@
+
+function asmFunc(global, 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  return HEAP32[0 >> 2] | 0 | 0;
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+   memory.buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "foo": $0
+ };
+}
+
+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'); },
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/minified-memory.2asm.js.opt
@@ -0,0 +1,80 @@
+
+function asmFunc(global, 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  return HEAP32[0];
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+   memory.buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "foo": $0
+ };
+}
+
+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'); },
+    a: { buffer : memasmFunc }
+  });
+export var foo = retasmFunc.foo;
diff --git a/binaryen/test/wasm2js/minified-memory.wast b/binaryen/test/wasm2js/minified-memory.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/minified-memory.wast
@@ -0,0 +1,6 @@
+(module
+ (import "env" "a" (memory $0 1))
+ (func "foo" (result i32)
+  (i32.load (i32.const 0))
+ )
+)
diff --git a/binaryen/test/wasm2js/minus_minus.2asm.js b/binaryen/test/wasm2js/minus_minus.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/minus_minus.2asm.js
@@ -0,0 +1,43 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  return ~~- -7094.0 | 0;
+ }
+ 
+ function $1() {
+  $0() | 0;
+ }
+ 
+ return {
+  "func_44_invoker": $1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/minus_minus.2asm.js.opt
@@ -0,0 +1,39 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $1() {
+  
+ }
+ 
+ return {
+  "func_44_invoker": $1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var func_44_invoker = retasmFunc.func_44_invoker;
diff --git a/binaryen/test/wasm2js/minus_minus.wast b/binaryen/test/wasm2js/minus_minus.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/minus_minus.wast
@@ -0,0 +1,18 @@
+(module
+ (type $0 (func (result i32)))
+ (type $1 (func))
+ (export "func_44_invoker" (func $1))
+ (func $0 (; 0 ;) (type $0) (result i32)
+  (i32.trunc_f64_s
+   (f64.neg
+    (f64.const -7094) ;; negation of a negative must not be emitted as "--" in js, that will not parse
+   )
+  )
+ )
+ (func $1 (; 1 ;) (type $1)
+  (drop
+   (call $0)
+  )
+ )
+)
+
diff --git a/binaryen/test/wasm2js/nested-selects.2asm.js b/binaryen/test/wasm2js/nested-selects.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/nested-selects.2asm.js
@@ -0,0 +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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $1($0) {
+  $0 = $0 | 0;
+  return (($0 | 0) < (0 | 0) ? -1 : ($0 | 0) > (0 | 0) ? 1 : 0) | 0;
+ }
+ 
+ return {
+  "sign": $1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/nested-selects.2asm.js.opt
@@ -0,0 +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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $1($0) {
+  $0 = $0 | 0;
+  return (($0 | 0) < 0 ? -1 : ($0 | 0) > 0) | 0;
+ }
+ 
+ return {
+  "sign": $1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var sign = retasmFunc.sign;
diff --git a/binaryen/test/wasm2js/nested-selects.wast b/binaryen/test/wasm2js/nested-selects.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/nested-selects.wast
@@ -0,0 +1,21 @@
+(module
+  (func $dummy)
+
+  (func (export "sign") (param $0 i32) (result i32)
+    (select
+      (i32.const -1)
+      (select
+        (i32.const 1)
+        (i32.const 0)
+        (i32.gt_s
+          (local.get $0)
+          (i32.const 0)
+        )
+      )
+      (i32.lt_s
+        (local.get $0)
+        (i32.const 0)
+      )
+    )
+  )
+)
diff --git a/binaryen/test/wasm2js/ordering.2asm.js b/binaryen/test/wasm2js/ordering.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/ordering.2asm.js
@@ -0,0 +1,72 @@
+import { table } from 'env';
+
+function asmFunc(global, 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.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;
+  FUNCTION_TABLE[4 | 0](foo(3 | 0) | 0) | 0;
+  (wasm2js_i32$1 = foo(5 | 0) | 0, wasm2js_i32$0 = bar(6 | 0) | 0 | 0), FUNCTION_TABLE[wasm2js_i32$0](wasm2js_i32$1 | 0) | 0;
+  FUNCTION_TABLE[8 | 0](7) | 0;
+  baz((11 ? 9 : 10) | 0) | 0;
+  baz((wasm2js_i32$0 = foo(12 | 0) | 0, wasm2js_i32$1 = 13, wasm2js_i32$2 = 14, wasm2js_i32$2 ? wasm2js_i32$0 : wasm2js_i32$1) | 0) | 0;
+  baz((wasm2js_i32$0 = 15, wasm2js_i32$1 = foo(16 | 0) | 0, wasm2js_i32$2 = 17, wasm2js_i32$2 ? wasm2js_i32$0 : wasm2js_i32$1) | 0) | 0;
+  baz((foo(20 | 0) | 0 ? 18 : 19) | 0) | 0;
+  baz((wasm2js_i32$0 = foo(21 | 0) | 0, wasm2js_i32$1 = 22, wasm2js_i32$2 = foo(23 | 0) | 0, wasm2js_i32$2 ? wasm2js_i32$0 : wasm2js_i32$1) | 0) | 0;
+  baz((wasm2js_i32$0 = 24, wasm2js_i32$1 = foo(25 | 0) | 0, wasm2js_i32$2 = foo(26 | 0) | 0, wasm2js_i32$2 ? wasm2js_i32$0 : wasm2js_i32$1) | 0) | 0;
+  baz((wasm2js_i32$0 = foo(27 | 0) | 0, wasm2js_i32$1 = foo(28 | 0) | 0, wasm2js_i32$2 = 29, wasm2js_i32$2 ? wasm2js_i32$0 : wasm2js_i32$1) | 0) | 0;
+  baz((wasm2js_i32$0 = foo(30 | 0) | 0, wasm2js_i32$1 = foo(31 | 0) | 0, wasm2js_i32$2 = foo(32 | 0) | 0, wasm2js_i32$2 ? wasm2js_i32$0 : wasm2js_i32$1) | 0) | 0;
+ }
+ 
+ function foo($0) {
+  $0 = $0 | 0;
+  return 1 | 0;
+ }
+ 
+ function bar($0) {
+  $0 = $0 | 0;
+  return 2 | 0;
+ }
+ 
+ function baz($0) {
+  $0 = $0 | 0;
+  return 3 | 0;
+ }
+ 
+ FUNCTION_TABLE[1] = foo;
+ FUNCTION_TABLE[2] = bar;
+ FUNCTION_TABLE[3] = baz;
+ return {
+  "main": main
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/ordering.2asm.js.opt
@@ -0,0 +1,63 @@
+import { table } from 'env';
+
+function asmFunc(global, 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 abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function main() {
+  FUNCTION_TABLE[1](1) | 0;
+  FUNCTION_TABLE[4](1) | 0;
+  FUNCTION_TABLE[2](1) | 0;
+  FUNCTION_TABLE[8](7) | 0;
+ }
+ 
+ function foo($0) {
+  $0 = $0 | 0;
+  return 1;
+ }
+ 
+ function bar($0) {
+  $0 = $0 | 0;
+  return 2;
+ }
+ 
+ function baz($0) {
+  $0 = $0 | 0;
+  return 3;
+ }
+ 
+ FUNCTION_TABLE[1] = foo;
+ FUNCTION_TABLE[2] = bar;
+ FUNCTION_TABLE[3] = baz;
+ return {
+  "main": main
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    table
+  });
+export var main = retasmFunc.main;
diff --git a/binaryen/test/wasm2js/ordering.wast b/binaryen/test/wasm2js/ordering.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/ordering.wast
@@ -0,0 +1,98 @@
+(module
+ (type $0 (func (param i32) (result i32)))
+ (import "env" "table" (table $timport$9 7 funcref))
+ (elem (i32.const 1) $foo $bar $baz)
+ (export "main" (func $main))
+ (func $main
+  (drop
+   (call_indirect (type $0)
+    (i32.const 1)
+    (call $foo (i32.const 2))
+   )
+  )
+  (drop
+   (call_indirect (type $0)
+    (call $foo (i32.const 3))
+    (i32.const 4)
+   )
+  )
+  (drop
+   (call_indirect (type $0)
+    (call $foo (i32.const 5))
+    (call $bar (i32.const 6))
+   )
+  )
+  (drop
+   (call_indirect (type $0)
+    (i32.const 7)
+    (i32.const 8)
+   )
+  )
+  (drop (call $baz
+   (select
+    (i32.const 9)
+    (i32.const 10)
+    (i32.const 11)
+   )
+  ))
+  (drop (call $baz
+   (select
+    (call $foo (i32.const 12))
+    (i32.const 13)
+    (i32.const 14)
+   )
+  ))
+  (drop (call $baz
+   (select
+    (i32.const 15)
+    (call $foo (i32.const 16))
+    (i32.const 17)
+   )
+  ))
+  (drop (call $baz
+   (select
+    (i32.const 18)
+    (i32.const 19)
+    (call $foo (i32.const 20))
+   )
+  ))
+  (drop (call $baz
+   (select
+    (call $foo (i32.const 21))
+    (i32.const 22)
+    (call $foo (i32.const 23))
+   )
+  ))
+  (drop (call $baz
+   (select
+    (i32.const 24)
+    (call $foo (i32.const 25))
+    (call $foo (i32.const 26))
+   )
+  ))
+  (drop (call $baz
+   (select
+    (call $foo (i32.const 27))
+    (call $foo (i32.const 28))
+    (i32.const 29)
+   )
+  ))
+  (drop (call $baz
+   (select
+    (call $foo (i32.const 30))
+    (call $foo (i32.const 31))
+    (call $foo (i32.const 32))
+   )
+  ))
+ )
+ (func $foo (param i32) (result i32)
+  (i32.const 1)
+ )
+ (func $bar (param i32) (result i32)
+  (i32.const 2)
+ )
+ (func $baz (param i32) (result i32)
+  (i32.const 3)
+ )
+)
+
diff --git a/binaryen/test/wasm2js/reinterpret.2asm.js b/binaryen/test/wasm2js/reinterpret.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/reinterpret.2asm.js
@@ -0,0 +1,115 @@
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_scratch_load_i32(index) {
+    return i32ScratchView[index];
+  }
+      
+  function wasm2js_scratch_store_i32(index, value) {
+    i32ScratchView[index] = value;
+  }
+      
+  function wasm2js_scratch_load_f64() {
+    return f64ScratchView[0];
+  }
+      
+  function wasm2js_scratch_store_f64(value) {
+    f64ScratchView[0] = value;
+  }
+      
+  function wasm2js_scratch_store_f32(value) {
+    f32ScratchView[2] = value;
+  }
+      
+  function wasm2js_scratch_load_f32() {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.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;
+ }
+ 
+ function $2($0, $0$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  var i64toi32_i32$0 = 0, $3$hi = 0;
+  i64toi32_i32$0 = $0$hi;
+  wasm2js_scratch_store_i32(0 | 0, $0 | 0);
+  wasm2js_scratch_store_i32(1 | 0, i64toi32_i32$0 | 0);
+  wasm2js_scratch_store_f64(+(+wasm2js_scratch_load_f64()));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = $3$hi;
+  return (wasm2js_scratch_load_i32(0 | 0) | 0 | 0) == ($0 | 0) & (i64toi32_i32$0 | 0) == ($0$hi | 0) | 0 | 0;
+ }
+ 
+ function legalstub$2($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $10 = 0, $3 = 0, $3$hi = 0, $6$hi = 0;
+  i64toi32_i32$0 = 0;
+  $3 = $0;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $10 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $10 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $6$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$0 = $3;
+  i64toi32_i32$2 = $6$hi;
+  i64toi32_i32$3 = $10;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ return {
+  "i32_roundtrip": $1, 
+  "i64_roundtrip": legalstub$2
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/reinterpret.2asm.js.opt
@@ -0,0 +1,87 @@
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_scratch_load_i32(index) {
+    return i32ScratchView[index];
+  }
+      
+  function wasm2js_scratch_store_i32(index, value) {
+    i32ScratchView[index] = value;
+  }
+      
+  function wasm2js_scratch_load_f64() {
+    return f64ScratchView[0];
+  }
+      
+  function wasm2js_scratch_store_f64(value) {
+    f64ScratchView[0] = value;
+  }
+      
+  function wasm2js_scratch_store_f32(value) {
+    f32ScratchView[2] = value;
+  }
+      
+  function wasm2js_scratch_load_f32() {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.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;
+ }
+ 
+ function $2($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var $2_1 = 0;
+  wasm2js_scratch_store_i32(0, $0 | 0);
+  wasm2js_scratch_store_i32(1, $1_1 | 0);
+  wasm2js_scratch_store_f64(+wasm2js_scratch_load_f64());
+  $2_1 = wasm2js_scratch_load_i32(1) | 0;
+  return (wasm2js_scratch_load_i32(0) | 0) == ($0 | 0) & ($1_1 | 0) == ($2_1 | 0);
+ }
+ 
+ function legalstub$2($0, $1_1) {
+  return $2($0, $1_1);
+ }
+ 
+ return {
+  "i32_roundtrip": $1, 
+  "i64_roundtrip": legalstub$2
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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.wast b/binaryen/test/wasm2js/reinterpret.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/reinterpret.wast
@@ -0,0 +1,24 @@
+(module
+  (func $dummy)
+
+  (func (export "i32_roundtrip") (param $0 i32) (result i32)
+    (i32.eq (i32.reinterpret_f32 (f32.reinterpret_i32 (local.get $0))) (local.get $0)))
+  (func (export "i64_roundtrip") (param $0 i64) (result i32)
+    (i64.eq (i64.reinterpret_f64 (f64.reinterpret_i64 (local.get $0))) (local.get $0)))
+)
+
+(assert_return (invoke "i32_roundtrip" (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "i32_roundtrip" (i32.const 1))
+               (i32.const 1))
+(assert_return (invoke "i32_roundtrip" (i32.const 100))
+               (i32.const 1))
+(assert_return (invoke "i32_roundtrip" (i32.const 10000))
+               (i32.const 1))
+
+(assert_return (invoke "i64_roundtrip" (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "i64_roundtrip" (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "i64_roundtrip" (i32.const 0) (i32.const 1))
+               (i32.const 1))
diff --git a/binaryen/test/wasm2js/reinterpret_scratch.2asm.js b/binaryen/test/wasm2js/reinterpret_scratch.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/reinterpret_scratch.2asm.js
@@ -0,0 +1,79 @@
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_scratch_load_i32(index) {
+    return i32ScratchView[index];
+  }
+      
+  function wasm2js_scratch_store_f64(value) {
+    f64ScratchView[0] = value;
+  }
+      
+  function wasm2js_scratch_store_f32(value) {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, $0_1 = Math_fround(0);
+  wasm2js_scratch_store_f64(+(305419896.0));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  i64toi32_i32$1 = (wasm2js_scratch_store_f32($0_1), wasm2js_scratch_load_i32(2));
+  HEAP32[i64toi32_i32$1 >> 2] = wasm2js_scratch_load_i32(0 | 0) | 0;
+  HEAP32[(i64toi32_i32$1 + 4 | 0) >> 2] = i64toi32_i32$0;
+  return HEAP32[0 >> 2] | 0 | 0;
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "foo": $0
+ };
+}
+
+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
+);
+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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/reinterpret_scratch.2asm.js.opt
@@ -0,0 +1,74 @@
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_scratch_load_i32(index) {
+    return i32ScratchView[index];
+  }
+      
+  function wasm2js_scratch_store_f64(value) {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0() {
+  var $0_1 = 0;
+  wasm2js_scratch_store_f64(305419896.0);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  HEAP32[0] = wasm2js_scratch_load_i32(0);
+  HEAP32[1] = $0_1;
+  return HEAP32[0];
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "foo": $0
+ };
+}
+
+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
+);
+export var foo = retasmFunc.foo;
diff --git a/binaryen/test/wasm2js/reinterpret_scratch.wast b/binaryen/test/wasm2js/reinterpret_scratch.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/reinterpret_scratch.wast
@@ -0,0 +1,17 @@
+(module
+ (memory $0 1 1)
+ (func "foo" (result i32)
+  (local $0 f32)
+  (i64.store align=4
+   (i32.reinterpret_f32 ;; i32 0
+    (local.get $0)      ;; f32 0
+   )
+   (i64.reinterpret_f64    ;; these two reinterprets must not interfere with
+    (f64.const 0x12345678) ;; each other, even though both use scratch memory
+   )
+  )
+  (i32.load
+   (i32.const 0)
+  )
+ )
+)
diff --git a/binaryen/test/wasm2js/set_local.2asm.js b/binaryen/test/wasm2js/set_local.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/set_local.2asm.js
@@ -0,0 +1,247 @@
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0() {
+  
+ }
+ 
+ function $1() {
+  
+ }
+ 
+ function $2() {
+  
+ }
+ 
+ function $3() {
+  
+ }
+ 
+ function $4($0_1) {
+  $0_1 = $0_1 | 0;
+ }
+ 
+ function $5($0_1, $0$hi) {
+  $0_1 = $0_1 | 0;
+  $0$hi = $0$hi | 0;
+ }
+ 
+ function $6($0_1) {
+  $0_1 = Math_fround($0_1);
+ }
+ 
+ function $7($0_1) {
+  $0_1 = +$0_1;
+ }
+ 
+ function $8($0_1, $0$hi, $1_1, $2_1, $3_1, $4_1) {
+  $0_1 = $0_1 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = Math_fround($1_1);
+  $2_1 = +$2_1;
+  $3_1 = $3_1 | 0;
+  $4_1 = $4_1 | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = 0;
+ }
+ 
+ function $9($0_1, $0$hi, $1_1, $2_1, $3_1, $4_1) {
+  $0_1 = $0_1 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = Math_fround($1_1);
+  $2_1 = +$2_1;
+  $3_1 = $3_1 | 0;
+  $4_1 = $4_1 | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0.0, $14 = 0, $15 = 0, $6$hi = 0, $10 = 0.0, $21 = 0.0, $7$hi = 0, $7_1 = 0;
+  i64toi32_i32$0 = 0;
+  $6$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $0_1;
+  $10 = +(i64toi32_i32$1 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0);
+  i64toi32_i32$0 = $6$hi;
+  i64toi32_i32$1 = 6;
+  $21 = +(i64toi32_i32$1 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0);
+  i64toi32_i32$0 = $7$hi;
+  i64toi32_i32$1 = $7_1;
+  i64toi32_i32$3 = $10 + (+Math_fround(-.30000001192092896) + ($2_1 + (+(40 >>> 0) + (+(-7 | 0) + (+Math_fround(5.5) + ($21 + (+(i64toi32_i32$1 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0) + 8.0)))))));
+  if (Math_abs(i64toi32_i32$3) >= 1.0) {
+   if (i64toi32_i32$3 > 0.0) {
+    $14 = ~~Math_min(Math_floor(i64toi32_i32$3 / 4294967296.0), 4294967296.0 - 1.0) >>> 0
+   } else {
+    $14 = ~~Math_ceil((i64toi32_i32$3 - +(~~i64toi32_i32$3 >>> 0 >>> 0)) / 4294967296.0) >>> 0
+   }
+   $15 = $14;
+  } else {
+   $15 = 0
+  }
+  i64toi32_i32$0 = $15;
+  i64toi32_i32$1 = ~~i64toi32_i32$3 >>> 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function legalstub$5($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $10 = 0, $3_1 = 0, $3$hi = 0, $6$hi = 0;
+  i64toi32_i32$0 = 0;
+  $3_1 = $0_1;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $10 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $10 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $6$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$0 = $3_1;
+  i64toi32_i32$2 = $6$hi;
+  i64toi32_i32$3 = $10;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $5(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0);
+ }
+ 
+ function legalstub$8($0_1, $1_1, $2_1, $3_1, $4_1, $5_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = Math_fround($2_1);
+  $3_1 = +$3_1;
+  $4_1 = $4_1 | 0;
+  $5_1 = $5_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $14 = 0, $7_1 = 0, $7$hi = 0, $10$hi = 0;
+  i64toi32_i32$0 = 0;
+  $7_1 = $0_1;
+  $7$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $14 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $14 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $10$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $7$hi;
+  i64toi32_i32$0 = $7_1;
+  i64toi32_i32$2 = $10$hi;
+  i64toi32_i32$3 = $14;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $8(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0, Math_fround($2_1), +$3_1, $4_1 | 0, $5_1 | 0);
+ }
+ 
+ function legalstub$9($0_1, $1_1, $2_1, $3_1, $4_1, $5_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = Math_fround($2_1);
+  $3_1 = +$3_1;
+  $4_1 = $4_1 | 0;
+  $5_1 = $5_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $16 = 0, $17 = 0, $8_1 = 0, $8$hi = 0, $11$hi = 0, $6_1 = 0, $6$hi = 0;
+  i64toi32_i32$0 = 0;
+  $8_1 = $0_1;
+  $8$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $16 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $16 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $11$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $8$hi;
+  i64toi32_i32$0 = $8_1;
+  i64toi32_i32$2 = $11$hi;
+  i64toi32_i32$3 = $16;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $9(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0, Math_fround($2_1), +$3_1, $4_1 | 0, $5_1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $6_1 = i64toi32_i32$2;
+  $6$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $17 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $17 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($17 | 0);
+  i64toi32_i32$2 = $6$hi;
+  return $6_1 | 0;
+ }
+ 
+ return {
+  "type_local_i32": $0, 
+  "type_local_i64": $1, 
+  "type_local_f32": $2, 
+  "type_local_f64": $3, 
+  "type_param_i32": $4, 
+  "type_param_i64": legalstub$5, 
+  "type_param_f32": $6, 
+  "type_param_f64": $7, 
+  "type_mixed": legalstub$8, 
+  "write": legalstub$9
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var type_local_i32 = retasmFunc.type_local_i32;
+export var type_local_i64 = retasmFunc.type_local_i64;
+export var type_local_f32 = retasmFunc.type_local_f32;
+export var type_local_f64 = retasmFunc.type_local_f64;
+export var type_param_i32 = retasmFunc.type_param_i32;
+export var type_param_i64 = retasmFunc.type_param_i64;
+export var type_param_f32 = retasmFunc.type_param_f32;
+export var type_param_f64 = retasmFunc.type_param_f64;
+export var type_mixed = retasmFunc.type_mixed;
+export var write = retasmFunc.write;
diff --git a/binaryen/test/wasm2js/sign_ext.2asm.js b/binaryen/test/wasm2js/sign_ext.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/sign_ext.2asm.js
@@ -0,0 +1,47 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0(x) {
+  x = x | 0;
+  return x << 24 >> 24 | 0;
+ }
+ 
+ function $1(x) {
+  x = x | 0;
+  return x << 16 >> 16 | 0;
+ }
+ 
+ return {
+  "test8": $0, 
+  "test16": $1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/sign_ext.2asm.js.opt
@@ -0,0 +1,47 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0($0_1) {
+  $0_1 = $0_1 | 0;
+  return $0_1 << 24 >> 24;
+ }
+ 
+ function $1($0_1) {
+  $0_1 = $0_1 | 0;
+  return $0_1 << 16 >> 16;
+ }
+ 
+ return {
+  "test8": $0, 
+  "test16": $1
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var test8 = retasmFunc.test8;
+export var test16 = retasmFunc.test16;
diff --git a/binaryen/test/wasm2js/sign_ext.wast b/binaryen/test/wasm2js/sign_ext.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/sign_ext.wast
@@ -0,0 +1,8 @@
+(module
+  (func "test8" (param $x i32) (result i32)
+    (i32.extend8_s (local.get $x))
+  )
+  (func "test16" (param $x i32) (result i32)
+    (i32.extend16_s (local.get $x))
+  )
+)
diff --git a/binaryen/test/wasm2js/stack-modified.2asm.js b/binaryen/test/wasm2js/stack-modified.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/stack-modified.2asm.js
@@ -0,0 +1,593 @@
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(var$0, var$0$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, var$1$hi = 0, i64toi32_i32$5 = 0, var$1 = 0, var$2$hi = 0, i64toi32_i32$1 = 0, var$2 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  var$1 = var$0;
+  var$1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  var$2 = 1;
+  var$2$hi = i64toi32_i32$0;
+  label$1 : {
+   label$2 : while (1) {
+    i64toi32_i32$0 = var$1$hi;
+    i64toi32_i32$2 = var$1;
+    i64toi32_i32$1 = 0;
+    i64toi32_i32$3 = 0;
+    if ((i64toi32_i32$2 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$0 | 0) == (i64toi32_i32$1 | 0) | 0) {
+     break label$1
+    } else {
+     label$5 : {
+      i64toi32_i32$2 = var$1$hi;
+      i64toi32_i32$2 = var$2$hi;
+      i64toi32_i32$2 = var$1$hi;
+      i64toi32_i32$0 = var$2$hi;
+      i64toi32_i32$0 = __wasm_i64_mul(var$1 | 0, i64toi32_i32$2 | 0, var$2 | 0, i64toi32_i32$0 | 0) | 0;
+      i64toi32_i32$2 = i64toi32_i32$HIGH_BITS;
+      var$2 = i64toi32_i32$0;
+      var$2$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$1$hi;
+      i64toi32_i32$3 = var$1;
+      i64toi32_i32$0 = 0;
+      i64toi32_i32$1 = 1;
+      i64toi32_i32$5 = (i64toi32_i32$3 >>> 0 < i64toi32_i32$1 >>> 0) + i64toi32_i32$0 | 0;
+      i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+      var$1 = i64toi32_i32$3 - i64toi32_i32$1 | 0;
+      var$1$hi = i64toi32_i32$5;
+     }
+    }
+    continue label$2;
+   };
+  }
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+  return i64toi32_i32$3 | 0;
+ }
+ 
+ function $1(var$0, var$0$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, var$1$hi = 0, i64toi32_i32$5 = 0, var$1 = 0, var$2$hi = 0, i64toi32_i32$1 = 0, var$2 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  var$1 = var$0;
+  var$1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  var$2 = 1;
+  var$2$hi = i64toi32_i32$0;
+  label$1 : {
+   label$2 : while (1) {
+    i64toi32_i32$0 = var$1$hi;
+    i64toi32_i32$2 = var$1;
+    i64toi32_i32$1 = 0;
+    i64toi32_i32$3 = 0;
+    if ((i64toi32_i32$2 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$0 | 0) == (i64toi32_i32$1 | 0) | 0) {
+     break label$1
+    } else {
+     block : {
+      i64toi32_i32$2 = var$1$hi;
+      i64toi32_i32$2 = var$2$hi;
+      i64toi32_i32$2 = var$1$hi;
+      i64toi32_i32$0 = var$2$hi;
+      i64toi32_i32$0 = __wasm_i64_mul(var$1 | 0, i64toi32_i32$2 | 0, var$2 | 0, i64toi32_i32$0 | 0) | 0;
+      i64toi32_i32$2 = i64toi32_i32$HIGH_BITS;
+      var$2 = i64toi32_i32$0;
+      var$2$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$1$hi;
+      i64toi32_i32$3 = var$1;
+      i64toi32_i32$0 = 0;
+      i64toi32_i32$1 = 1;
+      i64toi32_i32$5 = (i64toi32_i32$3 >>> 0 < i64toi32_i32$1 >>> 0) + i64toi32_i32$0 | 0;
+      i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+      var$1 = i64toi32_i32$3 - i64toi32_i32$1 | 0;
+      var$1$hi = i64toi32_i32$5;
+     }
+    }
+    continue label$2;
+   };
+  }
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+  return i64toi32_i32$3 | 0;
+ }
+ 
+ function $2(var$0, var$0$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, var$1$hi = 0, i64toi32_i32$5 = 0, var$1 = 0, var$2$hi = 0, i64toi32_i32$1 = 0, var$2 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  var$1 = var$0;
+  var$1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  var$2 = 1;
+  var$2$hi = i64toi32_i32$0;
+  label$1 : {
+   label$2 : while (1) {
+    i64toi32_i32$0 = var$1$hi;
+    i64toi32_i32$2 = var$1;
+    i64toi32_i32$1 = 0;
+    i64toi32_i32$3 = 0;
+    if ((i64toi32_i32$2 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$0 | 0) == (i64toi32_i32$1 | 0) | 0) {
+     break label$1
+    } else {
+     block : {
+      i64toi32_i32$2 = var$1$hi;
+      i64toi32_i32$2 = var$2$hi;
+      i64toi32_i32$2 = var$1$hi;
+      i64toi32_i32$0 = var$2$hi;
+      i64toi32_i32$0 = __wasm_i64_mul(var$1 | 0, i64toi32_i32$2 | 0, var$2 | 0, i64toi32_i32$0 | 0) | 0;
+      i64toi32_i32$2 = i64toi32_i32$HIGH_BITS;
+      var$2 = i64toi32_i32$0;
+      var$2$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$1$hi;
+      i64toi32_i32$3 = var$1;
+      i64toi32_i32$0 = 0;
+      i64toi32_i32$1 = 1;
+      i64toi32_i32$5 = (i64toi32_i32$3 >>> 0 < i64toi32_i32$1 >>> 0) + i64toi32_i32$0 | 0;
+      i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+      var$1 = i64toi32_i32$3 - i64toi32_i32$1 | 0;
+      var$1$hi = i64toi32_i32$5;
+     }
+    }
+    continue label$2;
+   };
+  }
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+  return i64toi32_i32$3 | 0;
+ }
+ 
+ function $3(var$0, var$0$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, var$1$hi = 0, i64toi32_i32$5 = 0, var$1 = 0, var$2$hi = 0, i64toi32_i32$1 = 0, var$2 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  var$1 = var$0;
+  var$1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  var$2 = 1;
+  var$2$hi = i64toi32_i32$0;
+  label$1 : {
+   label$2 : while (1) {
+    i64toi32_i32$0 = var$1$hi;
+    i64toi32_i32$2 = var$1;
+    i64toi32_i32$1 = 0;
+    i64toi32_i32$3 = 0;
+    if ((i64toi32_i32$2 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$0 | 0) == (i64toi32_i32$1 | 0) | 0) {
+     break label$1
+    } else {
+     block : {
+      i64toi32_i32$2 = var$1$hi;
+      i64toi32_i32$2 = var$2$hi;
+      i64toi32_i32$2 = var$1$hi;
+      i64toi32_i32$0 = var$2$hi;
+      i64toi32_i32$0 = __wasm_i64_mul(var$1 | 0, i64toi32_i32$2 | 0, var$2 | 0, i64toi32_i32$0 | 0) | 0;
+      i64toi32_i32$2 = i64toi32_i32$HIGH_BITS;
+      var$2 = i64toi32_i32$0;
+      var$2$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$1$hi;
+      i64toi32_i32$3 = var$1;
+      i64toi32_i32$0 = 0;
+      i64toi32_i32$1 = 1;
+      i64toi32_i32$5 = (i64toi32_i32$3 >>> 0 < i64toi32_i32$1 >>> 0) + i64toi32_i32$0 | 0;
+      i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+      var$1 = i64toi32_i32$3 - i64toi32_i32$1 | 0;
+      var$1$hi = i64toi32_i32$5;
+     }
+    }
+    continue label$2;
+   };
+  }
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+  return i64toi32_i32$3 | 0;
+ }
+ 
+ function $4(var$0, var$0$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, var$1$hi = 0, i64toi32_i32$5 = 0, var$1 = 0, var$2$hi = 0, i64toi32_i32$1 = 0, var$2 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  var$1 = var$0;
+  var$1$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  var$2 = 1;
+  var$2$hi = i64toi32_i32$0;
+  label$1 : {
+   label$2 : while (1) {
+    i64toi32_i32$0 = var$1$hi;
+    i64toi32_i32$2 = var$1;
+    i64toi32_i32$1 = 0;
+    i64toi32_i32$3 = 0;
+    if ((i64toi32_i32$2 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$0 | 0) == (i64toi32_i32$1 | 0) | 0) {
+     break label$1
+    } else {
+     block : {
+      i64toi32_i32$2 = var$1$hi;
+      i64toi32_i32$2 = var$2$hi;
+      i64toi32_i32$2 = var$1$hi;
+      i64toi32_i32$0 = var$2$hi;
+      i64toi32_i32$0 = __wasm_i64_mul(var$1 | 0, i64toi32_i32$2 | 0, var$2 | 0, i64toi32_i32$0 | 0) | 0;
+      i64toi32_i32$2 = i64toi32_i32$HIGH_BITS;
+      var$2 = i64toi32_i32$0;
+      var$2$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$1$hi;
+      i64toi32_i32$3 = var$1;
+      i64toi32_i32$0 = 0;
+      i64toi32_i32$1 = 1;
+      i64toi32_i32$5 = (i64toi32_i32$3 >>> 0 < i64toi32_i32$1 >>> 0) + i64toi32_i32$0 | 0;
+      i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+      var$1 = i64toi32_i32$3 - i64toi32_i32$1 | 0;
+      var$1$hi = i64toi32_i32$5;
+     }
+    }
+    continue label$2;
+   };
+  }
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+  return i64toi32_i32$3 | 0;
+ }
+ 
+ function legalstub$0($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4_1 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4_1 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4_1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $0(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$1($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4_1 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4_1 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4_1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $1(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4_1 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4_1 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4_1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $2(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$3($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4_1 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4_1 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4_1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $3(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$4($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4_1 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4_1 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4_1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $4(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, var$2 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, var$3 = 0, var$4 = 0, var$5 = 0, $21 = 0, $22 = 0, var$6 = 0, $24 = 0, $17 = 0, $18 = 0, $23 = 0, $29 = 0, $45 = 0, $56$hi = 0, $62$hi = 0;
+  i64toi32_i32$0 = var$1$hi;
+  var$2 = var$1;
+  var$4 = var$2 >>> 16 | 0;
+  i64toi32_i32$0 = var$0$hi;
+  var$3 = var$0;
+  var$5 = var$3 >>> 16 | 0;
+  $17 = Math_imul(var$4, var$5);
+  $18 = var$2;
+  i64toi32_i32$2 = var$3;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = 0;
+   $21 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  $23 = $17 + Math_imul($18, $21) | 0;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$0 = var$1;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $22 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $22 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  $29 = $23 + Math_imul($22, var$3) | 0;
+  var$2 = var$2 & 65535 | 0;
+  var$3 = var$3 & 65535 | 0;
+  var$6 = Math_imul(var$2, var$3);
+  var$2 = (var$6 >>> 16 | 0) + Math_imul(var$2, var$5) | 0;
+  $45 = $29 + (var$2 >>> 16 | 0) | 0;
+  var$2 = (var$2 & 65535 | 0) + Math_imul(var$4, var$3) | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $45 + (var$2 >>> 16 | 0) | 0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $24 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $24 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $56$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  $62$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $56$hi;
+  i64toi32_i32$2 = $24;
+  i64toi32_i32$1 = $62$hi;
+  i64toi32_i32$3 = var$2 << 16 | 0 | (var$6 & 65535 | 0) | 0;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  i64toi32_i32$2 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function __wasm_i64_mul(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ return {
+  "fac_expr": legalstub$0, 
+  "fac_stack": legalstub$1, 
+  "fac_stack_raw": legalstub$2, 
+  "fac_mixed": legalstub$3, 
+  "fac_mixed_raw": legalstub$4
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var fac_expr = retasmFunc.fac_expr;
+export var fac_stack = retasmFunc.fac_stack;
+export var fac_stack_raw = retasmFunc.fac_stack_raw;
+export var fac_mixed = retasmFunc.fac_mixed;
+export var fac_mixed_raw = retasmFunc.fac_mixed_raw;
diff --git a/binaryen/test/wasm2js/stack-modified.2asm.js.opt b/binaryen/test/wasm2js/stack-modified.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/stack-modified.2asm.js.opt
@@ -0,0 +1,90 @@
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0($0_1, $1) {
+  $0_1 = $0_1 | 0;
+  $1 = $1 | 0;
+  var $2 = 0, $3 = 0, $4 = 0;
+  $2 = $1;
+  $3 = 1;
+  while (1) {
+   if ($0_1 | $2) {
+    $3 = _ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE($0_1, $2, $3, $4);
+    $4 = i64toi32_i32$HIGH_BITS;
+    $1 = $0_1;
+    $0_1 = $0_1 - 1 | 0;
+    $2 = $2 - ($1 >>> 0 < 1) | 0;
+    continue;
+   }
+   break;
+  };
+  i64toi32_i32$HIGH_BITS = $4;
+  return $3 | 0;
+ }
+ 
+ function legalstub$0($0_1, $1) {
+  $0_1 = $0($0_1, $1);
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function _ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE($0_1, $1, $2, $3) {
+  var $4 = 0, $5 = 0, $6 = 0, $7 = 0, $8 = 0, $9 = 0;
+  $4 = $2 >>> 16 | 0;
+  $5 = $0_1 >>> 16 | 0;
+  $9 = Math_imul($4, $5);
+  $6 = $2 & 65535;
+  $7 = $0_1 & 65535;
+  $8 = Math_imul($6, $7);
+  $5 = ($8 >>> 16 | 0) + Math_imul($5, $6) | 0;
+  $4 = ($5 & 65535) + Math_imul($4, $7) | 0;
+  $0_1 = (Math_imul($1, $2) + $9 | 0) + Math_imul($0_1, $3) + ($5 >>> 16) + ($4 >>> 16) | 0;
+  $1 = $8 & 65535 | $4 << 16;
+  i64toi32_i32$HIGH_BITS = $0_1;
+  return $1;
+ }
+ 
+ return {
+  "fac_expr": legalstub$0, 
+  "fac_stack": legalstub$0, 
+  "fac_stack_raw": legalstub$0, 
+  "fac_mixed": legalstub$0, 
+  "fac_mixed_raw": legalstub$0
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var fac_expr = retasmFunc.fac_expr;
+export var fac_stack = retasmFunc.fac_stack;
+export var fac_stack_raw = retasmFunc.fac_stack_raw;
+export var fac_mixed = retasmFunc.fac_mixed;
+export var fac_mixed_raw = retasmFunc.fac_mixed_raw;
diff --git a/binaryen/test/wasm2js/stack-modified.wast b/binaryen/test/wasm2js/stack-modified.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/stack-modified.wast
@@ -0,0 +1,198 @@
+(module
+ (type $0 (func (param i64) (result i64)))
+ (export "fac-expr" (func $0))
+ (export "fac-stack" (func $1))
+ (export "fac-stack-raw" (func $2))
+ (export "fac-mixed" (func $3))
+ (export "fac-mixed-raw" (func $4))
+ (func $0 (; 0 ;) (type $0) (param $var$0 i64) (result i64)
+  (local $var$1 i64)
+  (local $var$2 i64)
+  (local.set $var$1
+   (local.get $var$0)
+  )
+  (local.set $var$2
+   (i64.const 1)
+  )
+  (block $label$1
+   (loop $label$2
+    (if
+     (i64.eq
+      (local.get $var$1)
+      (i64.const 0)
+     )
+     (br $label$1)
+     (block $label$5
+      (local.set $var$2
+       (i64.mul
+        (local.get $var$1)
+        (local.get $var$2)
+       )
+      )
+      (local.set $var$1
+       (i64.sub
+        (local.get $var$1)
+        (i64.const 1)
+       )
+      )
+     )
+    )
+    (br $label$2)
+   )
+  )
+  (local.get $var$2)
+ )
+ (func $1 (; 1 ;) (type $0) (param $var$0 i64) (result i64)
+  (local $var$1 i64)
+  (local $var$2 i64)
+  (local.set $var$1
+   (local.get $var$0)
+  )
+  (local.set $var$2
+   (i64.const 1)
+  )
+  (block $label$1
+   (loop $label$2
+    (if
+     (i64.eq
+      (local.get $var$1)
+      (i64.const 0)
+     )
+     (br $label$1)
+     (block
+      (local.set $var$2
+       (i64.mul
+        (local.get $var$1)
+        (local.get $var$2)
+       )
+      )
+      (local.set $var$1
+       (i64.sub
+        (local.get $var$1)
+        (i64.const 1)
+       )
+      )
+     )
+    )
+    (br $label$2)
+   )
+  )
+  (local.get $var$2)
+ )
+ (func $2 (; 2 ;) (type $0) (param $var$0 i64) (result i64)
+  (local $var$1 i64)
+  (local $var$2 i64)
+  (local.set $var$1
+   (local.get $var$0)
+  )
+  (local.set $var$2
+   (i64.const 1)
+  )
+  (block $label$1
+   (loop $label$2
+    (if
+     (i64.eq
+      (local.get $var$1)
+      (i64.const 0)
+     )
+     (br $label$1)
+     (block
+      (local.set $var$2
+       (i64.mul
+        (local.get $var$1)
+        (local.get $var$2)
+       )
+      )
+      (local.set $var$1
+       (i64.sub
+        (local.get $var$1)
+        (i64.const 1)
+       )
+      )
+     )
+    )
+    (br $label$2)
+   )
+  )
+  (local.get $var$2)
+ )
+ (func $3 (; 3 ;) (type $0) (param $var$0 i64) (result i64)
+  (local $var$1 i64)
+  (local $var$2 i64)
+  (local.set $var$1
+   (local.get $var$0)
+  )
+  (local.set $var$2
+   (i64.const 1)
+  )
+  (block $label$1
+   (loop $label$2
+    (if
+     (i64.eq
+      (local.get $var$1)
+      (i64.const 0)
+     )
+     (br $label$1)
+     (block
+      (local.set $var$2
+       (i64.mul
+        (local.get $var$1)
+        (local.get $var$2)
+       )
+      )
+      (local.set $var$1
+       (i64.sub
+        (local.get $var$1)
+        (i64.const 1)
+       )
+      )
+     )
+    )
+    (br $label$2)
+   )
+  )
+  (local.get $var$2)
+ )
+ (func $4 (; 4 ;) (type $0) (param $var$0 i64) (result i64)
+  (local $var$1 i64)
+  (local $var$2 i64)
+  (local.set $var$1
+   (local.get $var$0)
+  )
+  (local.set $var$2
+   (i64.const 1)
+  )
+  (block $label$1
+   (loop $label$2
+    (if
+     (i64.eq
+      (local.get $var$1)
+      (i64.const 0)
+     )
+     (br $label$1)
+     (block
+      (local.set $var$2
+       (i64.mul
+        (local.get $var$1)
+        (local.get $var$2)
+       )
+      )
+      (local.set $var$1
+       (i64.sub
+        (local.get $var$1)
+        (i64.const 1)
+       )
+      )
+     )
+    )
+    (br $label$2)
+   )
+  )
+  (local.get $var$2)
+ )
+)
+
+
+(assert_return (invoke "fac-expr" (i64.const 25)) (i64.const 7034535277573963776))
+(assert_return (invoke "fac-stack" (i64.const 25)) (i64.const 7034535277573963776))
+(assert_return (invoke "fac-mixed" (i64.const 25)) (i64.const 7034535277573963776))
diff --git a/binaryen/test/wasm2js/start_func.2asm.js b/binaryen/test/wasm2js/start_func.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/start_func.2asm.js
@@ -0,0 +1,77 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function foo() {
+  HEAP32[1 >> 2] = 2;
+ }
+ 
+ foo();
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  
+ };
+}
+
+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
+);
diff --git a/binaryen/test/wasm2js/start_func.2asm.js.opt b/binaryen/test/wasm2js/start_func.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/start_func.2asm.js.opt
@@ -0,0 +1,77 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function foo() {
+  HEAP32[0] = 2;
+ }
+ 
+ foo();
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  
+ };
+}
+
+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
+);
diff --git a/binaryen/test/wasm2js/start_func.wast b/binaryen/test/wasm2js/start_func.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/start_func.wast
@@ -0,0 +1,7 @@
+(module
+  (memory 1)
+  (start $foo)
+  (func $foo
+    (i32.store (i32.const 1) (i32.const 2))
+  )
+)
diff --git a/binaryen/test/wasm2js/switch.2asm.js b/binaryen/test/wasm2js/switch.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/switch.2asm.js
@@ -0,0 +1,204 @@
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(i) {
+  i = i | 0;
+  var j = 0;
+  j = 100;
+  switch_ : {
+   $7 : {
+    switch (i | 0) {
+    case 0:
+     return i | 0;
+    case 1:
+    case 2:
+    case 3:
+     j = 0 - i | 0;
+     break switch_;
+    case 4:
+     break switch_;
+    case 5:
+     j = 101;
+     break switch_;
+    case 6:
+     j = 101;
+    default:
+     j = 102;
+     break;
+    case 7:
+     break $7;
+    };
+   }
+  }
+  return j | 0;
+ }
+ 
+ function $1(i, i$hi) {
+  i = i | 0;
+  i$hi = i$hi | 0;
+  var i64toi32_i32$5 = 0, i64toi32_i32$2 = 0, $7 = 0, $7$hi = 0, j = 0, j$hi = 0;
+  j = 100;
+  j$hi = 0;
+  switch_ : {
+   $7 : {
+    switch (i | 0) {
+    case 0:
+     i64toi32_i32$HIGH_BITS = i$hi;
+     return i | 0;
+    case 1:
+    case 2:
+    case 3:
+     i64toi32_i32$2 = 0;
+     i64toi32_i32$5 = (i64toi32_i32$2 >>> 0 < i >>> 0) + i$hi | 0;
+     i64toi32_i32$5 = 0 - i64toi32_i32$5 | 0;
+     $7 = i64toi32_i32$2 - i | 0;
+     $7$hi = i64toi32_i32$5;
+     break switch_;
+    case 6:
+     i64toi32_i32$5 = 0;
+     j = 101;
+     j$hi = i64toi32_i32$5;
+    case 5:
+    case 4:
+    default:
+     i64toi32_i32$5 = j$hi;
+     $7 = j;
+     $7$hi = i64toi32_i32$5;
+     break switch_;
+    case 7:
+     break $7;
+    };
+   }
+   i64toi32_i32$5 = -1;
+   $7 = -5;
+   $7$hi = i64toi32_i32$5;
+  }
+  i64toi32_i32$5 = $7$hi;
+  i64toi32_i32$2 = $7;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function $2(i) {
+  i = i | 0;
+  var $5 = 0, $6 = 0, $7 = 0, $8 = 0, $9 = 0;
+  $2 : {
+   $1 : {
+    $0 : {
+     default_ : {
+      $5 = Math_imul(2, i);
+      $6 = $5;
+      $7 = $5;
+      $8 = $5;
+      $9 = $5;
+      switch (3 & i | 0 | 0) {
+      case 0:
+       break $0;
+      case 1:
+       break $1;
+      case 2:
+       break $2;
+      default:
+       break default_;
+      };
+     }
+     $6 = 1e3 + $9 | 0;
+    }
+    $7 = 100 + $6 | 0;
+   }
+   $8 = 10 + $7 | 0;
+  }
+  return $8 | 0;
+ }
+ 
+ function $3() {
+  return 1 | 0;
+ }
+ 
+ function legalstub$1($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $1(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ return {
+  "stmt": $0, 
+  "expr": legalstub$1, 
+  "arg": $2, 
+  "corner": $3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var stmt = retasmFunc.stmt;
+export var expr = retasmFunc.expr;
+export var arg = retasmFunc.arg;
+export var corner = retasmFunc.corner;
diff --git a/binaryen/test/wasm2js/tee_local.2asm.js b/binaryen/test/wasm2js/tee_local.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/tee_local.2asm.js
@@ -0,0 +1,355 @@
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0() {
+  return 0 | 0;
+ }
+ 
+ function $1() {
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return 0 | 0;
+ }
+ 
+ function $2() {
+  return Math_fround(Math_fround(0.0));
+ }
+ 
+ function $3() {
+  return +(0.0);
+ }
+ 
+ function $4($0_1) {
+  $0_1 = $0_1 | 0;
+  return 10 | 0;
+ }
+ 
+ function $5($0_1, $0$hi) {
+  $0_1 = $0_1 | 0;
+  $0$hi = $0$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return 11 | 0;
+ }
+ 
+ function $6($0_1) {
+  $0_1 = Math_fround($0_1);
+  return Math_fround(Math_fround(11.100000381469727));
+ }
+ 
+ function $7($0_1) {
+  $0_1 = +$0_1;
+  return +(12.2);
+ }
+ 
+ function $8($0_1, $0$hi, $1_1, $2_1, $3_1, $4_1) {
+  $0_1 = $0_1 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = Math_fround($1_1);
+  $2_1 = +$2_1;
+  $3_1 = $3_1 | 0;
+  $4_1 = $4_1 | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = 0;
+ }
+ 
+ function $9($0_1, $0$hi, $1_1, $2_1, $3_1, $4_1) {
+  $0_1 = $0_1 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = Math_fround($1_1);
+  $2_1 = +$2_1;
+  $3_1 = $3_1 | 0;
+  $4_1 = $4_1 | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0.0, $5_1 = Math_fround(0), $6_1 = 0, $8_1 = 0.0, $17 = 0, $18 = 0, $6$hi = 0, $16 = 0.0, $27 = 0.0, $7$hi = 0, $7_1 = 0;
+  $1_1 = Math_fround(-.30000001192092896);
+  $3_1 = 40;
+  $4_1 = -7;
+  $5_1 = Math_fround(5.5);
+  i64toi32_i32$0 = 0;
+  $6_1 = 6;
+  $6$hi = i64toi32_i32$0;
+  $8_1 = 8.0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $0_1;
+  $16 = +(i64toi32_i32$1 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0);
+  i64toi32_i32$0 = $6$hi;
+  i64toi32_i32$1 = $6_1;
+  $27 = +(i64toi32_i32$1 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0);
+  i64toi32_i32$0 = $7$hi;
+  i64toi32_i32$1 = $7_1;
+  i64toi32_i32$3 = $16 + (+$1_1 + ($2_1 + (+($3_1 >>> 0) + (+($4_1 | 0) + (+$5_1 + ($27 + (+(i64toi32_i32$1 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0) + $8_1)))))));
+  if (Math_abs(i64toi32_i32$3) >= 1.0) {
+   if (i64toi32_i32$3 > 0.0) {
+    $17 = ~~Math_min(Math_floor(i64toi32_i32$3 / 4294967296.0), 4294967296.0 - 1.0) >>> 0
+   } else {
+    $17 = ~~Math_ceil((i64toi32_i32$3 - +(~~i64toi32_i32$3 >>> 0 >>> 0)) / 4294967296.0) >>> 0
+   }
+   $18 = $17;
+  } else {
+   $18 = 0
+  }
+  i64toi32_i32$0 = $18;
+  i64toi32_i32$1 = ~~i64toi32_i32$3 >>> 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function $10($0_1, $0$hi, $1_1, $2_1, $3_1, $4_1) {
+  $0_1 = $0_1 | 0;
+  $0$hi = $0$hi | 0;
+  $1_1 = Math_fround($1_1);
+  $2_1 = +$2_1;
+  $3_1 = $3_1 | 0;
+  $4_1 = $4_1 | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $10_1 = 0.0, $21 = 0.0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$1 = 1;
+  $10_1 = +(i64toi32_i32$1 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0);
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$1 = 6;
+  $21 = +(i64toi32_i32$1 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0);
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$1 = 0;
+  return +($10_1 + (+Math_fround(2.0) + (3.3 + (+(4 >>> 0) + (+(5 | 0) + (+Math_fround(5.5) + ($21 + (+(i64toi32_i32$1 >>> 0) + 4294967296.0 * +(i64toi32_i32$0 >>> 0) + 8.0))))))));
+ }
+ 
+ function legalstub$1() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $1() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function legalstub$5($0_1, $1_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4_1 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
+  i64toi32_i32$0 = 0;
+  $4_1 = $0_1;
+  $4$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $7$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $4$hi;
+  i64toi32_i32$0 = $4_1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $5(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $2_1 = i64toi32_i32$2;
+  $2$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $13 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $13 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($13 | 0);
+  i64toi32_i32$2 = $2$hi;
+  return $2_1 | 0;
+ }
+ 
+ function legalstub$8($0_1, $1_1, $2_1, $3_1, $4_1, $5_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = Math_fround($2_1);
+  $3_1 = +$3_1;
+  $4_1 = $4_1 | 0;
+  $5_1 = $5_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $14 = 0, $7_1 = 0, $7$hi = 0, $10$hi = 0;
+  i64toi32_i32$0 = 0;
+  $7_1 = $0_1;
+  $7$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $14 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $14 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $10$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $7$hi;
+  i64toi32_i32$0 = $7_1;
+  i64toi32_i32$2 = $10$hi;
+  i64toi32_i32$3 = $14;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $8(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0, Math_fround($2_1), +$3_1, $4_1 | 0, $5_1 | 0);
+ }
+ 
+ function legalstub$9($0_1, $1_1, $2_1, $3_1, $4_1, $5_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = Math_fround($2_1);
+  $3_1 = +$3_1;
+  $4_1 = $4_1 | 0;
+  $5_1 = $5_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $16 = 0, $17 = 0, $8_1 = 0, $8$hi = 0, $11$hi = 0, $6_1 = 0, $6$hi = 0;
+  i64toi32_i32$0 = 0;
+  $8_1 = $0_1;
+  $8$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $16 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $16 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $11$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $8$hi;
+  i64toi32_i32$0 = $8_1;
+  i64toi32_i32$2 = $11$hi;
+  i64toi32_i32$3 = $16;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  i64toi32_i32$2 = $9(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0, Math_fround($2_1), +$3_1, $4_1 | 0, $5_1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  $6_1 = i64toi32_i32$2;
+  $6$hi = i64toi32_i32$0;
+  i64toi32_i32$1 = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = 0;
+   $17 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+   $17 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$1 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($17 | 0);
+  i64toi32_i32$2 = $6$hi;
+  return $6_1 | 0;
+ }
+ 
+ function legalstub$10($0_1, $1_1, $2_1, $3_1, $4_1, $5_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = Math_fround($2_1);
+  $3_1 = +$3_1;
+  $4_1 = $4_1 | 0;
+  $5_1 = $5_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $14 = 0, $7_1 = 0, $7$hi = 0, $10$hi = 0;
+  i64toi32_i32$0 = 0;
+  $7_1 = $0_1;
+  $7$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $14 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $14 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $10$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $7$hi;
+  i64toi32_i32$0 = $7_1;
+  i64toi32_i32$2 = $10$hi;
+  i64toi32_i32$3 = $14;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return +(+$10(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0, Math_fround($2_1), +$3_1, $4_1 | 0, $5_1 | 0));
+ }
+ 
+ return {
+  "type_local_i32": $0, 
+  "type_local_i64": legalstub$1, 
+  "type_local_f32": $2, 
+  "type_local_f64": $3, 
+  "type_param_i32": $4, 
+  "type_param_i64": legalstub$5, 
+  "type_param_f32": $6, 
+  "type_param_f64": $7, 
+  "type_mixed": legalstub$8, 
+  "write": legalstub$9, 
+  "result": legalstub$10
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); },
+    setTempRet0
+  });
+export var type_local_i32 = retasmFunc.type_local_i32;
+export var type_local_i64 = retasmFunc.type_local_i64;
+export var type_local_f32 = retasmFunc.type_local_f32;
+export var type_local_f64 = retasmFunc.type_local_f64;
+export var type_param_i32 = retasmFunc.type_param_i32;
+export var type_param_i64 = retasmFunc.type_param_i64;
+export var type_param_f32 = retasmFunc.type_param_f32;
+export var type_param_f64 = retasmFunc.type_param_f64;
+export var type_mixed = retasmFunc.type_mixed;
+export var write = retasmFunc.write;
+export var result = retasmFunc.result;
diff --git a/binaryen/test/wasm2js/traps.2asm.js b/binaryen/test/wasm2js/traps.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/traps.2asm.js
@@ -0,0 +1,1792 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x, y) {
+  x = x | 0;
+  y = y | 0;
+  (x | 0) / (y | 0) | 0;
+ }
+ 
+ function $1(x, y) {
+  x = x | 0;
+  y = y | 0;
+  (x >>> 0) / (y >>> 0) | 0;
+ }
+ 
+ function $2(x, x$hi, y, y$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  y = y | 0;
+  y$hi = y$hi | 0;
+  __wasm_i64_sdiv(x | 0, x$hi | 0, y | 0, y$hi | 0) | 0;
+ }
+ 
+ function $3(x, x$hi, y, y$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  y = y | 0;
+  y$hi = y$hi | 0;
+  __wasm_i64_udiv(x | 0, x$hi | 0, y | 0, y$hi | 0) | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1, $2_1, $3_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5 = 0, $5$hi = 0, $8$hi = 0, $9 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5 = $0_1;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  $2($9 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0);
+ }
+ 
+ function legalstub$3($0_1, $1_1, $2_1, $3_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5 = 0, $5$hi = 0, $8$hi = 0, $9 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5 = $0_1;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  $3($9 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0);
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, $21 = 0, $22 = 0, $23 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17 = 0, $17$hi = 0, $23$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $21 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $21 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $21;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $22 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $22 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$2 = $22;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$5 = var$2;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_udiv($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17 = i64toi32_i32$1;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$5 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$2 = i64toi32_i32$1 >> 31 | 0;
+   $23 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+  } else {
+   i64toi32_i32$2 = i64toi32_i32$1 >> i64toi32_i32$5 | 0;
+   $23 = (((1 << i64toi32_i32$5 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$5 | 0) | 0 | (i64toi32_i32$4 >>> i64toi32_i32$5 | 0) | 0;
+  }
+  var$0 = $23;
+  var$0$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = $17$hi;
+  i64toi32_i32$1 = $17;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$4 | 0;
+  $23$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$0$hi;
+  i64toi32_i32$4 = $23$hi;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+  i64toi32_i32$0 = i64toi32_i32$4 - i64toi32_i32$0 | 0;
+  i64toi32_i32$2 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$2 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_sdiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Div3div17he78fc483e41d7ec7E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_udiv(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "no_dce_i32_div_s": $0, 
+  "no_dce_i32_div_u": $1, 
+  "no_dce_i64_div_s": legalstub$2, 
+  "no_dce_i64_div_u": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var __wasm_intrinsics_temp_i64 = 0;
+ var __wasm_intrinsics_temp_i64$hi = 0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0(x, y) {
+  x = x | 0;
+  y = y | 0;
+  (x | 0) % (y | 0) | 0;
+ }
+ 
+ function $1(x, y) {
+  x = x | 0;
+  y = y | 0;
+  (x >>> 0) % (y >>> 0) | 0;
+ }
+ 
+ function $2(x, x$hi, y, y$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  y = y | 0;
+  y$hi = y$hi | 0;
+  __wasm_i64_srem(x | 0, x$hi | 0, y | 0, y$hi | 0) | 0;
+ }
+ 
+ function $3(x, x$hi, y, y$hi) {
+  x = x | 0;
+  x$hi = x$hi | 0;
+  y = y | 0;
+  y$hi = y$hi | 0;
+  __wasm_i64_urem(x | 0, x$hi | 0, y | 0, y$hi | 0) | 0;
+ }
+ 
+ function legalstub$2($0_1, $1_1, $2_1, $3_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5 = 0, $5$hi = 0, $8$hi = 0, $9 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5 = $0_1;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  $2($9 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0);
+ }
+ 
+ function legalstub$3($0_1, $1_1, $2_1, $3_1) {
+  $0_1 = $0_1 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5 = 0, $5$hi = 0, $8$hi = 0, $9 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5 = $0_1;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  $3($9 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0);
+ }
+ 
+ function _ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, var$2$hi = 0, i64toi32_i32$6 = 0, var$2 = 0, $20 = 0, $21 = 0, $7$hi = 0, $9 = 0, $9$hi = 0, $14$hi = 0, $16$hi = 0, $17$hi = 0, $19$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$2 = var$0;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$0 >> 31 | 0;
+   $20 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$0 >> i64toi32_i32$4 | 0;
+   $20 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  var$2 = $20;
+  var$2$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$0 = var$2;
+  i64toi32_i32$2 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $7$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $7$hi;
+  i64toi32_i32$1 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$0 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$4 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$5 = i64toi32_i32$6 + i64toi32_i32$0 | 0;
+  i64toi32_i32$5 = i64toi32_i32$2 - i64toi32_i32$5 | 0;
+  $9 = i64toi32_i32$4;
+  $9$hi = i64toi32_i32$5;
+  i64toi32_i32$5 = var$1$hi;
+  i64toi32_i32$2 = var$1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 63;
+  i64toi32_i32$0 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$5 >> 31 | 0;
+   $21 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+  } else {
+   i64toi32_i32$1 = i64toi32_i32$5 >> i64toi32_i32$0 | 0;
+   $21 = (((1 << i64toi32_i32$0 | 0) - 1 | 0) & i64toi32_i32$5 | 0) << (32 - i64toi32_i32$0 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$0 | 0) | 0;
+  }
+  var$0 = $21;
+  var$0$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$2 = var$1$hi;
+  i64toi32_i32$3 = var$1;
+  i64toi32_i32$2 = i64toi32_i32$1 ^ i64toi32_i32$2 | 0;
+  $14$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$2 = $14$hi;
+  i64toi32_i32$1 = i64toi32_i32$5 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$5 = var$0$hi;
+  i64toi32_i32$3 = var$0;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$5 | 0;
+  i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$4 | 0;
+  $16$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = $9$hi;
+  i64toi32_i32$1 = $16$hi;
+  i64toi32_i32$1 = __wasm_i64_urem($9 | 0, i64toi32_i32$4 | 0, i64toi32_i32$0 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$4 = i64toi32_i32$HIGH_BITS;
+  $17$hi = i64toi32_i32$4;
+  i64toi32_i32$4 = var$2$hi;
+  i64toi32_i32$4 = $17$hi;
+  i64toi32_i32$2 = i64toi32_i32$1;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$3 = var$2;
+  i64toi32_i32$1 = i64toi32_i32$4 ^ i64toi32_i32$1 | 0;
+  $19$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = var$2$hi;
+  i64toi32_i32$1 = $19$hi;
+  i64toi32_i32$4 = i64toi32_i32$2 ^ i64toi32_i32$3 | 0;
+  i64toi32_i32$2 = var$2$hi;
+  i64toi32_i32$5 = i64toi32_i32$4 - i64toi32_i32$3 | 0;
+  i64toi32_i32$6 = i64toi32_i32$4 >>> 0 < i64toi32_i32$3 >>> 0;
+  i64toi32_i32$0 = i64toi32_i32$6 + i64toi32_i32$2 | 0;
+  i64toi32_i32$0 = i64toi32_i32$1 - i64toi32_i32$0 | 0;
+  i64toi32_i32$4 = i64toi32_i32$5;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$4 | 0;
+ }
+ 
+ function _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$5 = 0, var$2 = 0, var$3 = 0, var$4 = 0, var$5 = 0, var$5$hi = 0, var$6 = 0, var$6$hi = 0, i64toi32_i32$6 = 0, $37 = 0, $38 = 0, $39 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, var$8$hi = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, var$7$hi = 0, $49 = 0, $63$hi = 0, $65 = 0, $65$hi = 0, $120$hi = 0, $129$hi = 0, $134$hi = 0, var$8 = 0, $140 = 0, $140$hi = 0, $142$hi = 0, $144 = 0, $144$hi = 0, $151 = 0, $151$hi = 0, $154$hi = 0, var$7 = 0, $165$hi = 0;
+  label$1 : {
+   label$2 : {
+    label$3 : {
+     label$4 : {
+      label$5 : {
+       label$6 : {
+        label$7 : {
+         label$8 : {
+          label$9 : {
+           label$10 : {
+            label$11 : {
+             i64toi32_i32$0 = var$0$hi;
+             i64toi32_i32$2 = var$0;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$3 = 32;
+             i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+             if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+              i64toi32_i32$1 = 0;
+              $37 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+             } else {
+              i64toi32_i32$1 = i64toi32_i32$0 >>> i64toi32_i32$4 | 0;
+              $37 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$0 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+             }
+             var$2 = $37;
+             if (var$2) {
+              block : {
+               i64toi32_i32$1 = var$1$hi;
+               var$3 = var$1;
+               if (!var$3) {
+                break label$11
+               }
+               i64toi32_i32$1 = var$1$hi;
+               i64toi32_i32$0 = var$1;
+               i64toi32_i32$2 = 0;
+               i64toi32_i32$3 = 32;
+               i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+               if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+                i64toi32_i32$2 = 0;
+                $38 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+               } else {
+                i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+                $38 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$0 >>> i64toi32_i32$4 | 0) | 0;
+               }
+               var$4 = $38;
+               if (!var$4) {
+                break label$9
+               }
+               var$2 = Math_clz32(var$4) - Math_clz32(var$2) | 0;
+               if (var$2 >>> 0 <= 31 >>> 0) {
+                break label$8
+               }
+               break label$2;
+              }
+             }
+             i64toi32_i32$2 = var$1$hi;
+             i64toi32_i32$1 = var$1;
+             i64toi32_i32$0 = 1;
+             i64toi32_i32$3 = 0;
+             if (i64toi32_i32$2 >>> 0 > i64toi32_i32$0 >>> 0 | ((i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) & i64toi32_i32$1 >>> 0 >= i64toi32_i32$3 >>> 0 | 0) | 0) {
+              break label$2
+             }
+             i64toi32_i32$1 = var$0$hi;
+             var$2 = var$0;
+             i64toi32_i32$1 = var$1$hi;
+             var$3 = var$1;
+             var$2 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+             i64toi32_i32$1 = 0;
+             __wasm_intrinsics_temp_i64 = var$0 - Math_imul(var$2, var$3) | 0;
+             __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+             i64toi32_i32$1 = 0;
+             i64toi32_i32$2 = var$2;
+             i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+             return i64toi32_i32$2 | 0;
+            }
+            i64toi32_i32$2 = var$1$hi;
+            i64toi32_i32$3 = var$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$1 = 0;
+             $39 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+            } else {
+             i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+             $39 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+            }
+            var$3 = $39;
+            i64toi32_i32$1 = var$0$hi;
+            if (!var$0) {
+             break label$7
+            }
+            if (!var$3) {
+             break label$6
+            }
+            var$4 = var$3 + -1 | 0;
+            if (var$4 & var$3 | 0) {
+             break label$6
+            }
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$2 = var$4 & var$2 | 0;
+            i64toi32_i32$3 = 0;
+            i64toi32_i32$0 = 32;
+            i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+            if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+             i64toi32_i32$3 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+             $40 = 0;
+            } else {
+             i64toi32_i32$3 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+             $40 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+            }
+            $63$hi = i64toi32_i32$3;
+            i64toi32_i32$3 = var$0$hi;
+            i64toi32_i32$1 = var$0;
+            i64toi32_i32$2 = 0;
+            i64toi32_i32$0 = -1;
+            i64toi32_i32$2 = i64toi32_i32$3 & i64toi32_i32$2 | 0;
+            $65 = i64toi32_i32$1 & i64toi32_i32$0 | 0;
+            $65$hi = i64toi32_i32$2;
+            i64toi32_i32$2 = $63$hi;
+            i64toi32_i32$3 = $40;
+            i64toi32_i32$1 = $65$hi;
+            i64toi32_i32$0 = $65;
+            i64toi32_i32$1 = i64toi32_i32$2 | i64toi32_i32$1 | 0;
+            __wasm_intrinsics_temp_i64 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+            __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+            i64toi32_i32$1 = 0;
+            i64toi32_i32$3 = var$2 >>> ((__wasm_ctz_i32(var$3 | 0) | 0) & 31 | 0) | 0;
+            i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+            return i64toi32_i32$3 | 0;
+           }
+          }
+          var$4 = var$3 + -1 | 0;
+          if (!(var$4 & var$3 | 0)) {
+           break label$5
+          }
+          var$2 = (Math_clz32(var$3) + 33 | 0) - Math_clz32(var$2) | 0;
+          var$3 = 0 - var$2 | 0;
+          break label$3;
+         }
+         var$3 = 63 - var$2 | 0;
+         var$2 = var$2 + 1 | 0;
+         break label$3;
+        }
+        var$4 = (var$2 >>> 0) / (var$3 >>> 0) | 0;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$2 = var$2 - Math_imul(var$4, var$3) | 0;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 32;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+         $41 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $41 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+        }
+        __wasm_intrinsics_temp_i64 = $41;
+        __wasm_intrinsics_temp_i64$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$2 = var$4;
+        i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+        return i64toi32_i32$2 | 0;
+       }
+       var$2 = Math_clz32(var$3) - Math_clz32(var$2) | 0;
+       if (var$2 >>> 0 < 31 >>> 0) {
+        break label$4
+       }
+       break label$2;
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      __wasm_intrinsics_temp_i64 = var$4 & var$0 | 0;
+      __wasm_intrinsics_temp_i64$hi = i64toi32_i32$2;
+      if ((var$3 | 0) == (1 | 0)) {
+       break label$1
+      }
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$2 = 0;
+      $120$hi = i64toi32_i32$2;
+      i64toi32_i32$2 = var$0$hi;
+      i64toi32_i32$3 = var$0;
+      i64toi32_i32$1 = $120$hi;
+      i64toi32_i32$0 = __wasm_ctz_i32(var$3 | 0) | 0;
+      i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+      if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+       i64toi32_i32$1 = 0;
+       $42 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+      } else {
+       i64toi32_i32$1 = i64toi32_i32$2 >>> i64toi32_i32$4 | 0;
+       $42 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$2 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$3 >>> i64toi32_i32$4 | 0) | 0;
+      }
+      i64toi32_i32$3 = $42;
+      i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+      return i64toi32_i32$3 | 0;
+     }
+     var$3 = 63 - var$2 | 0;
+     var$2 = var$2 + 1 | 0;
+    }
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$3 = 0;
+    $129$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = $129$hi;
+    i64toi32_i32$0 = var$2 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$1 = 0;
+     $43 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+    } else {
+     i64toi32_i32$1 = i64toi32_i32$3 >>> i64toi32_i32$4 | 0;
+     $43 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$3 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+    }
+    var$5 = $43;
+    var$5$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$1 = 0;
+    $134$hi = i64toi32_i32$1;
+    i64toi32_i32$1 = var$0$hi;
+    i64toi32_i32$3 = var$0;
+    i64toi32_i32$2 = $134$hi;
+    i64toi32_i32$0 = var$3 & 63 | 0;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+     $44 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$3 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$1 << i64toi32_i32$4 | 0) | 0;
+     $44 = i64toi32_i32$3 << i64toi32_i32$4 | 0;
+    }
+    var$0 = $44;
+    var$0$hi = i64toi32_i32$2;
+    label$13 : {
+     if (var$2) {
+      block3 : {
+       i64toi32_i32$2 = var$1$hi;
+       i64toi32_i32$1 = var$1;
+       i64toi32_i32$3 = -1;
+       i64toi32_i32$0 = -1;
+       i64toi32_i32$4 = i64toi32_i32$1 + i64toi32_i32$0 | 0;
+       i64toi32_i32$5 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+       if (i64toi32_i32$4 >>> 0 < i64toi32_i32$0 >>> 0) {
+        i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+       }
+       var$8 = i64toi32_i32$4;
+       var$8$hi = i64toi32_i32$5;
+       label$15 : while (1) {
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$2 = var$5;
+        i64toi32_i32$1 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+         $45 = 0;
+        } else {
+         i64toi32_i32$1 = ((1 << i64toi32_i32$3 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$3 | 0) | 0) | 0 | (i64toi32_i32$5 << i64toi32_i32$3 | 0) | 0;
+         $45 = i64toi32_i32$2 << i64toi32_i32$3 | 0;
+        }
+        $140 = $45;
+        $140$hi = i64toi32_i32$1;
+        i64toi32_i32$1 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$3 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = 0;
+         $46 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$1 >>> i64toi32_i32$3 | 0;
+         $46 = (((1 << i64toi32_i32$3 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$3 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$3 | 0) | 0;
+        }
+        $142$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = $140$hi;
+        i64toi32_i32$1 = $140;
+        i64toi32_i32$5 = $142$hi;
+        i64toi32_i32$0 = $46;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$5 = i64toi32_i32$1 | i64toi32_i32$0 | 0;
+        var$5$hi = i64toi32_i32$5;
+        $144 = var$5;
+        $144$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$5 = var$5$hi;
+        i64toi32_i32$5 = var$8$hi;
+        i64toi32_i32$2 = var$8;
+        i64toi32_i32$1 = var$5$hi;
+        i64toi32_i32$0 = var$5;
+        i64toi32_i32$3 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$4 = i64toi32_i32$6 + i64toi32_i32$1 | 0;
+        i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+        i64toi32_i32$5 = i64toi32_i32$3;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 63;
+        i64toi32_i32$1 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$4 >> 31 | 0;
+         $47 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+        } else {
+         i64toi32_i32$2 = i64toi32_i32$4 >> i64toi32_i32$1 | 0;
+         $47 = (((1 << i64toi32_i32$1 | 0) - 1 | 0) & i64toi32_i32$4 | 0) << (32 - i64toi32_i32$1 | 0) | 0 | (i64toi32_i32$5 >>> i64toi32_i32$1 | 0) | 0;
+        }
+        var$6 = $47;
+        var$6$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$1$hi;
+        i64toi32_i32$2 = var$6$hi;
+        i64toi32_i32$4 = var$6;
+        i64toi32_i32$5 = var$1$hi;
+        i64toi32_i32$0 = var$1;
+        i64toi32_i32$5 = i64toi32_i32$2 & i64toi32_i32$5 | 0;
+        $151 = i64toi32_i32$4 & i64toi32_i32$0 | 0;
+        $151$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = $144$hi;
+        i64toi32_i32$2 = $144;
+        i64toi32_i32$4 = $151$hi;
+        i64toi32_i32$0 = $151;
+        i64toi32_i32$1 = i64toi32_i32$2 - i64toi32_i32$0 | 0;
+        i64toi32_i32$6 = i64toi32_i32$2 >>> 0 < i64toi32_i32$0 >>> 0;
+        i64toi32_i32$3 = i64toi32_i32$6 + i64toi32_i32$4 | 0;
+        i64toi32_i32$3 = i64toi32_i32$5 - i64toi32_i32$3 | 0;
+        var$5 = i64toi32_i32$1;
+        var$5$hi = i64toi32_i32$3;
+        i64toi32_i32$3 = var$0$hi;
+        i64toi32_i32$5 = var$0;
+        i64toi32_i32$2 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+        if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+         i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+         $48 = 0;
+        } else {
+         i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+         $48 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+        }
+        $154$hi = i64toi32_i32$2;
+        i64toi32_i32$2 = var$7$hi;
+        i64toi32_i32$2 = $154$hi;
+        i64toi32_i32$3 = $48;
+        i64toi32_i32$5 = var$7$hi;
+        i64toi32_i32$0 = var$7;
+        i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+        var$0 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+        var$0$hi = i64toi32_i32$5;
+        i64toi32_i32$5 = var$6$hi;
+        i64toi32_i32$2 = var$6;
+        i64toi32_i32$3 = 0;
+        i64toi32_i32$0 = 1;
+        i64toi32_i32$3 = i64toi32_i32$5 & i64toi32_i32$3 | 0;
+        var$6 = i64toi32_i32$2 & i64toi32_i32$0 | 0;
+        var$6$hi = i64toi32_i32$3;
+        var$7 = var$6;
+        var$7$hi = i64toi32_i32$3;
+        var$2 = var$2 + -1 | 0;
+        if (var$2) {
+         continue label$15
+        }
+        break label$15;
+       };
+       break label$13;
+      }
+     }
+    }
+    i64toi32_i32$3 = var$5$hi;
+    __wasm_intrinsics_temp_i64 = var$5;
+    __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+    i64toi32_i32$3 = var$0$hi;
+    i64toi32_i32$5 = var$0;
+    i64toi32_i32$2 = 0;
+    i64toi32_i32$0 = 1;
+    i64toi32_i32$4 = i64toi32_i32$0 & 31 | 0;
+    if (32 >>> 0 <= (i64toi32_i32$0 & 63 | 0) >>> 0) {
+     i64toi32_i32$2 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+     $49 = 0;
+    } else {
+     i64toi32_i32$2 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$5 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$3 << i64toi32_i32$4 | 0) | 0;
+     $49 = i64toi32_i32$5 << i64toi32_i32$4 | 0;
+    }
+    $165$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$6$hi;
+    i64toi32_i32$2 = $165$hi;
+    i64toi32_i32$3 = $49;
+    i64toi32_i32$5 = var$6$hi;
+    i64toi32_i32$0 = var$6;
+    i64toi32_i32$5 = i64toi32_i32$2 | i64toi32_i32$5 | 0;
+    i64toi32_i32$3 = i64toi32_i32$3 | i64toi32_i32$0 | 0;
+    i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
+    return i64toi32_i32$3 | 0;
+   }
+   i64toi32_i32$3 = var$0$hi;
+   __wasm_intrinsics_temp_i64 = var$0;
+   __wasm_intrinsics_temp_i64$hi = i64toi32_i32$3;
+   i64toi32_i32$3 = 0;
+   var$0 = 0;
+   var$0$hi = i64toi32_i32$3;
+  }
+  i64toi32_i32$3 = var$0$hi;
+  i64toi32_i32$5 = var$0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$3;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ function __wasm_i64_srem(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4sdiv3Mod4mod_17h2cbb7bbf36e41d68E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_i64_urem(var$0, var$0$hi, var$1, var$1$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var$1 = var$1 | 0;
+  var$1$hi = var$1$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$0 = var$1$hi;
+  i64toi32_i32$0 = var$0$hi;
+  i64toi32_i32$1 = var$1$hi;
+  i64toi32_i32$1 = _ZN17compiler_builtins3int4udiv10divmod_u6417h6026910b5ed08e40E(var$0 | 0, i64toi32_i32$0 | 0, var$1 | 0, i64toi32_i32$1 | 0) | 0;
+  i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
+  i64toi32_i32$0 = __wasm_intrinsics_temp_i64$hi;
+  i64toi32_i32$1 = __wasm_intrinsics_temp_i64;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$1 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ return {
+  "no_dce_i32_rem_s": $0, 
+  "no_dce_i32_rem_u": $1, 
+  "no_dce_i64_rem_s": legalstub$2, 
+  "no_dce_i64_rem_u": legalstub$3
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0(x) {
+  x = Math_fround(x);
+  ~~x;
+ }
+ 
+ function $1(x) {
+  x = Math_fround(x);
+  ~~x >>> 0;
+ }
+ 
+ function $2(x) {
+  x = +x;
+  ~~x;
+ }
+ 
+ function $3(x) {
+  x = +x;
+  ~~x >>> 0;
+ }
+ 
+ function $4(x) {
+  x = Math_fround(x);
+  var i64toi32_i32$0 = Math_fround(0), $2_1 = 0, $3_1 = 0;
+  i64toi32_i32$0 = x;
+  if (Math_fround(Math_abs(i64toi32_i32$0)) >= Math_fround(1.0)) {
+   if (i64toi32_i32$0 > Math_fround(0.0)) {
+    $2_1 = ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround(i64toi32_i32$0 / Math_fround(4294967296.0)))), Math_fround(Math_fround(4294967296.0) - Math_fround(1.0)))) >>> 0
+   } else {
+    $2_1 = ~~Math_fround(Math_ceil(Math_fround(Math_fround(i64toi32_i32$0 - Math_fround(~~i64toi32_i32$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0
+   }
+   $3_1 = $2_1;
+  } else {
+   $3_1 = 0
+  }
+  ~~i64toi32_i32$0 >>> 0;
+ }
+ 
+ function $5(x) {
+  x = Math_fround(x);
+  var i64toi32_i32$0 = Math_fround(0), $2_1 = 0, $3_1 = 0;
+  i64toi32_i32$0 = x;
+  if (Math_fround(Math_abs(i64toi32_i32$0)) >= Math_fround(1.0)) {
+   if (i64toi32_i32$0 > Math_fround(0.0)) {
+    $2_1 = ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround(i64toi32_i32$0 / Math_fround(4294967296.0)))), Math_fround(Math_fround(4294967296.0) - Math_fround(1.0)))) >>> 0
+   } else {
+    $2_1 = ~~Math_fround(Math_ceil(Math_fround(Math_fround(i64toi32_i32$0 - Math_fround(~~i64toi32_i32$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0
+   }
+   $3_1 = $2_1;
+  } else {
+   $3_1 = 0
+  }
+  ~~i64toi32_i32$0 >>> 0;
+ }
+ 
+ function $6(x) {
+  x = +x;
+  var i64toi32_i32$0 = 0.0, $2_1 = 0, $3_1 = 0;
+  i64toi32_i32$0 = x;
+  if (Math_abs(i64toi32_i32$0) >= 1.0) {
+   if (i64toi32_i32$0 > 0.0) {
+    $2_1 = ~~Math_min(Math_floor(i64toi32_i32$0 / 4294967296.0), 4294967296.0 - 1.0) >>> 0
+   } else {
+    $2_1 = ~~Math_ceil((i64toi32_i32$0 - +(~~i64toi32_i32$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0
+   }
+   $3_1 = $2_1;
+  } else {
+   $3_1 = 0
+  }
+  ~~i64toi32_i32$0 >>> 0;
+ }
+ 
+ function $7(x) {
+  x = +x;
+  var i64toi32_i32$0 = 0.0, $2_1 = 0, $3_1 = 0;
+  i64toi32_i32$0 = x;
+  if (Math_abs(i64toi32_i32$0) >= 1.0) {
+   if (i64toi32_i32$0 > 0.0) {
+    $2_1 = ~~Math_min(Math_floor(i64toi32_i32$0 / 4294967296.0), 4294967296.0 - 1.0) >>> 0
+   } else {
+    $2_1 = ~~Math_ceil((i64toi32_i32$0 - +(~~i64toi32_i32$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0
+   }
+   $3_1 = $2_1;
+  } else {
+   $3_1 = 0
+  }
+  ~~i64toi32_i32$0 >>> 0;
+ }
+ 
+ return {
+  "no_dce_i32_trunc_f32_s": $0, 
+  "no_dce_i32_trunc_f32_u": $1, 
+  "no_dce_i32_trunc_f64_s": $2, 
+  "no_dce_i32_trunc_f64_u": $3, 
+  "no_dce_i64_trunc_f32_s": $4, 
+  "no_dce_i64_trunc_f32_u": $5, 
+  "no_dce_i64_trunc_f64_s": $6, 
+  "no_dce_i64_trunc_f64_u": $7
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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;
+export var no_dce_i32_trunc_f64_s = retasmFunc.no_dce_i32_trunc_f64_s;
+export var no_dce_i32_trunc_f64_u = retasmFunc.no_dce_i32_trunc_f64_u;
+export var no_dce_i64_trunc_f32_s = retasmFunc.no_dce_i64_trunc_f32_s;
+export var no_dce_i64_trunc_f32_u = retasmFunc.no_dce_i64_trunc_f32_u;
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ function $0(i) {
+  i = i | 0;
+  HEAP32[i >> 2] | 0;
+ }
+ 
+ function $1(i) {
+  i = i | 0;
+  HEAP16[i >> 1] | 0;
+ }
+ 
+ function $2(i) {
+  i = i | 0;
+  HEAPU16[i >> 1] | 0;
+ }
+ 
+ function $3(i) {
+  i = i | 0;
+  HEAP8[i >> 0] | 0;
+ }
+ 
+ function $4(i) {
+  i = i | 0;
+  HEAPU8[i >> 0] | 0;
+ }
+ 
+ function $5(i) {
+  i = i | 0;
+  var i64toi32_i32$2 = 0;
+  i64toi32_i32$2 = i;
+  HEAP32[(i64toi32_i32$2 + 4 | 0) >> 2] | 0;
+  HEAP32[i64toi32_i32$2 >> 2] | 0;
+ }
+ 
+ function $6(i) {
+  i = i | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = HEAP32[i >> 2] | 0;
+ }
+ 
+ function $7(i) {
+  i = i | 0;
+  HEAP32[i >> 2] | 0;
+ }
+ 
+ function $8(i) {
+  i = i | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = HEAP16[i >> 1] | 0;
+ }
+ 
+ function $9(i) {
+  i = i | 0;
+  HEAPU16[i >> 1] | 0;
+ }
+ 
+ function $10(i) {
+  i = i | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = HEAP8[i >> 0] | 0;
+ }
+ 
+ function $11(i) {
+  i = i | 0;
+  HEAPU8[i >> 0] | 0;
+ }
+ 
+ function $12(i) {
+  i = i | 0;
+  Math_fround(HEAPF32[i >> 2]);
+ }
+ 
+ function $13(i) {
+  i = i | 0;
+  +HEAPF64[i >> 3];
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ function __wasm_memory_grow(pagesToAdd) {
+  pagesToAdd = pagesToAdd | 0;
+  var oldPages = __wasm_memory_size() | 0;
+  var newPages = oldPages + pagesToAdd | 0;
+  if ((oldPages < newPages) && (newPages < 65536)) {
+   var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
+   var newHEAP8 = new global.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);
+   buffer = newBuffer;
+  }
+  return oldPages;
+ }
+ 
+ return {
+  "no_dce_i32_load": $0, 
+  "no_dce_i32_load16_s": $1, 
+  "no_dce_i32_load16_u": $2, 
+  "no_dce_i32_load8_s": $3, 
+  "no_dce_i32_load8_u": $4, 
+  "no_dce_i64_load": $5, 
+  "no_dce_i64_load32_s": $6, 
+  "no_dce_i64_load32_u": $7, 
+  "no_dce_i64_load16_s": $8, 
+  "no_dce_i64_load16_u": $9, 
+  "no_dce_i64_load8_s": $10, 
+  "no_dce_i64_load8_u": $11, 
+  "no_dce_f32_load": $12, 
+  "no_dce_f64_load": $13
+ };
+}
+
+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
+);
+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;
+export var no_dce_i32_load8_s = retasmFunc.no_dce_i32_load8_s;
+export var no_dce_i32_load8_u = retasmFunc.no_dce_i32_load8_u;
+export var no_dce_i64_load = retasmFunc.no_dce_i64_load;
+export var no_dce_i64_load32_s = retasmFunc.no_dce_i64_load32_s;
+export var no_dce_i64_load32_u = retasmFunc.no_dce_i64_load32_u;
+export var no_dce_i64_load16_s = retasmFunc.no_dce_i64_load16_s;
+export var no_dce_i64_load16_u = retasmFunc.no_dce_i64_load16_u;
+export var no_dce_i64_load8_s = retasmFunc.no_dce_i64_load8_s;
+export var no_dce_i64_load8_u = retasmFunc.no_dce_i64_load8_u;
+export var no_dce_f32_load = retasmFunc.no_dce_f32_load;
+export var no_dce_f64_load = retasmFunc.no_dce_f64_load;
diff --git a/binaryen/test/wasm2js/unaligned.2asm.js b/binaryen/test/wasm2js/unaligned.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/unaligned.2asm.js
@@ -0,0 +1,203 @@
+import { setTempRet0 } from 'env';
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_scratch_load_i32(index) {
+    return i32ScratchView[index];
+  }
+      
+  function wasm2js_scratch_store_i32(index, value) {
+    i32ScratchView[index] = value;
+  }
+      
+  function wasm2js_scratch_load_f64() {
+    return f64ScratchView[0];
+  }
+      
+  function wasm2js_scratch_store_f64(value) {
+    f64ScratchView[0] = value;
+  }
+      
+  function wasm2js_scratch_load_f32() {
+    return f32ScratchView[2];
+  }
+      
+  function wasm2js_scratch_store_f32(value) {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0() {
+  var $0_1 = 0;
+  $0_1 = 0;
+  return HEAPU8[$0_1 >> 0] | 0 | ((HEAPU8[($0_1 + 1 | 0) >> 0] | 0) << 8 | 0) | 0 | ((HEAPU8[($0_1 + 2 | 0) >> 0] | 0) << 16 | 0 | ((HEAPU8[($0_1 + 3 | 0) >> 0] | 0) << 24 | 0) | 0) | 0 | 0;
+ }
+ 
+ function $1() {
+  var $2_1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0;
+  $2_1 = 0;
+  i64toi32_i32$0 = HEAPU8[$2_1 >> 0] | 0 | ((HEAPU8[($2_1 + 1 | 0) >> 0] | 0) << 8 | 0) | 0 | ((HEAPU8[($2_1 + 2 | 0) >> 0] | 0) << 16 | 0 | ((HEAPU8[($2_1 + 3 | 0) >> 0] | 0) << 24 | 0) | 0) | 0;
+  i64toi32_i32$1 = HEAPU8[($2_1 + 4 | 0) >> 0] | 0 | ((HEAPU8[($2_1 + 5 | 0) >> 0] | 0) << 8 | 0) | 0 | ((HEAPU8[($2_1 + 6 | 0) >> 0] | 0) << 16 | 0 | ((HEAPU8[($2_1 + 7 | 0) >> 0] | 0) << 24 | 0) | 0) | 0;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
+  return i64toi32_i32$0 | 0;
+ }
+ 
+ function $2() {
+  var $0_1 = 0;
+  $0_1 = 0;
+  return Math_fround((wasm2js_scratch_store_i32(2, HEAPU8[$0_1 >> 0] | 0 | ((HEAPU8[($0_1 + 1 | 0) >> 0] | 0) << 8 | 0) | 0 | ((HEAPU8[($0_1 + 2 | 0) >> 0] | 0) << 16 | 0 | ((HEAPU8[($0_1 + 3 | 0) >> 0] | 0) << 24 | 0) | 0) | 0), wasm2js_scratch_load_f32()));
+ }
+ 
+ function $3() {
+  var $1_1 = 0, i64toi32_i32$1 = 0;
+  $1_1 = 0;
+  i64toi32_i32$1 = HEAPU8[($1_1 + 4 | 0) >> 0] | 0 | ((HEAPU8[($1_1 + 5 | 0) >> 0] | 0) << 8 | 0) | 0 | ((HEAPU8[($1_1 + 6 | 0) >> 0] | 0) << 16 | 0 | ((HEAPU8[($1_1 + 7 | 0) >> 0] | 0) << 24 | 0) | 0) | 0;
+  wasm2js_scratch_store_i32(0 | 0, HEAPU8[$1_1 >> 0] | 0 | ((HEAPU8[($1_1 + 1 | 0) >> 0] | 0) << 8 | 0) | 0 | ((HEAPU8[($1_1 + 2 | 0) >> 0] | 0) << 16 | 0 | ((HEAPU8[($1_1 + 3 | 0) >> 0] | 0) << 24 | 0) | 0) | 0 | 0);
+  wasm2js_scratch_store_i32(1 | 0, i64toi32_i32$1 | 0);
+  return +(+wasm2js_scratch_load_f64());
+ }
+ 
+ function $4() {
+  var $0_1 = 0, $1_1 = 0;
+  $0_1 = 0;
+  $1_1 = 0;
+  HEAP8[$0_1 >> 0] = $1_1;
+  HEAP8[($0_1 + 1 | 0) >> 0] = $1_1 >>> 8 | 0;
+  HEAP8[($0_1 + 2 | 0) >> 0] = $1_1 >>> 16 | 0;
+  HEAP8[($0_1 + 3 | 0) >> 0] = $1_1 >>> 24 | 0;
+ }
+ 
+ function $5() {
+  var $0_1 = 0, $1_1 = 0, $2_1 = 0;
+  $0_1 = 0;
+  $1_1 = 0;
+  HEAP8[$0_1 >> 0] = $1_1;
+  HEAP8[($0_1 + 1 | 0) >> 0] = $1_1 >>> 8 | 0;
+  HEAP8[($0_1 + 2 | 0) >> 0] = $1_1 >>> 16 | 0;
+  HEAP8[($0_1 + 3 | 0) >> 0] = $1_1 >>> 24 | 0;
+  $2_1 = 0;
+  HEAP8[($0_1 + 4 | 0) >> 0] = $2_1;
+  HEAP8[($0_1 + 5 | 0) >> 0] = $2_1 >>> 8 | 0;
+  HEAP8[($0_1 + 6 | 0) >> 0] = $2_1 >>> 16 | 0;
+  HEAP8[($0_1 + 7 | 0) >> 0] = $2_1 >>> 24 | 0;
+ }
+ 
+ function $6() {
+  var $0_1 = 0, $1_1 = 0;
+  $0_1 = 0;
+  $1_1 = (wasm2js_scratch_store_f32(Math_fround(0.0)), wasm2js_scratch_load_i32(2));
+  HEAP8[$0_1 >> 0] = $1_1;
+  HEAP8[($0_1 + 1 | 0) >> 0] = $1_1 >>> 8 | 0;
+  HEAP8[($0_1 + 2 | 0) >> 0] = $1_1 >>> 16 | 0;
+  HEAP8[($0_1 + 3 | 0) >> 0] = $1_1 >>> 24 | 0;
+ }
+ 
+ function $7() {
+  var $1_1 = 0, $2_1 = 0, $3_1 = 0, i64toi32_i32$0 = 0;
+  wasm2js_scratch_store_f64(+(0.0));
+  i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0;
+  $1_1 = 0;
+  $2_1 = wasm2js_scratch_load_i32(0 | 0) | 0;
+  HEAP8[$1_1 >> 0] = $2_1;
+  HEAP8[($1_1 + 1 | 0) >> 0] = $2_1 >>> 8 | 0;
+  HEAP8[($1_1 + 2 | 0) >> 0] = $2_1 >>> 16 | 0;
+  HEAP8[($1_1 + 3 | 0) >> 0] = $2_1 >>> 24 | 0;
+  $3_1 = i64toi32_i32$0;
+  HEAP8[($1_1 + 4 | 0) >> 0] = $3_1;
+  HEAP8[($1_1 + 5 | 0) >> 0] = $3_1 >>> 8 | 0;
+  HEAP8[($1_1 + 6 | 0) >> 0] = $3_1 >>> 16 | 0;
+  HEAP8[($1_1 + 7 | 0) >> 0] = $3_1 >>> 24 | 0;
+ }
+ 
+ function legalstub$1() {
+  var i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $7_1 = 0, $0_1 = 0, $0$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $1() | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $0_1 = i64toi32_i32$0;
+  $0$hi = i64toi32_i32$1;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = 0;
+   $7_1 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+  } else {
+   i64toi32_i32$0 = i64toi32_i32$1 >>> i64toi32_i32$4 | 0;
+   $7_1 = (((1 << i64toi32_i32$4 | 0) - 1 | 0) & i64toi32_i32$1 | 0) << (32 - i64toi32_i32$4 | 0) | 0 | (i64toi32_i32$2 >>> i64toi32_i32$4 | 0) | 0;
+  }
+  setTempRet0($7_1 | 0);
+  i64toi32_i32$0 = $0$hi;
+  return $0_1 | 0;
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "i32_load": $0, 
+  "i64_load": legalstub$1, 
+  "f32_load": $2, 
+  "f64_load": $3, 
+  "i32_store": $4, 
+  "i64_store": $5, 
+  "f32_store": $6, 
+  "f64_store": $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'); },
+    setTempRet0
+  },
+  memasmFunc
+);
+export var i32_load = retasmFunc.i32_load;
+export var i64_load = retasmFunc.i64_load;
+export var f32_load = retasmFunc.f32_load;
+export var f64_load = retasmFunc.f64_load;
+export var i32_store = retasmFunc.i32_store;
+export var i64_store = retasmFunc.i64_store;
+export var f32_store = retasmFunc.f32_store;
+export var f64_store = retasmFunc.f64_store;
diff --git a/binaryen/test/wasm2js/unaligned.2asm.js.opt b/binaryen/test/wasm2js/unaligned.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/unaligned.2asm.js.opt
@@ -0,0 +1,156 @@
+import { setTempRet0 } from 'env';
+
+
+  var scratchBuffer = new ArrayBuffer(16);
+  var i32ScratchView = new Int32Array(scratchBuffer);
+  var f32ScratchView = new Float32Array(scratchBuffer);
+  var f64ScratchView = new Float64Array(scratchBuffer);
+  
+  function wasm2js_scratch_load_i32(index) {
+    return i32ScratchView[index];
+  }
+      
+  function wasm2js_scratch_store_i32(index, value) {
+    i32ScratchView[index] = value;
+  }
+      
+  function wasm2js_scratch_load_f64() {
+    return f64ScratchView[0];
+  }
+      
+  function wasm2js_scratch_store_f64(value) {
+    f64ScratchView[0] = value;
+  }
+      
+  function wasm2js_scratch_load_f32() {
+    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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var setTempRet0 = env.setTempRet0;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $0() {
+  return HEAPU8[0] | HEAPU8[1] << 8 | (HEAPU8[2] << 16 | HEAPU8[3] << 24);
+ }
+ 
+ function $1() {
+  i64toi32_i32$HIGH_BITS = HEAPU8[4] | HEAPU8[5] << 8 | (HEAPU8[6] << 16 | HEAPU8[7] << 24);
+  return HEAPU8[0] | HEAPU8[1] << 8 | (HEAPU8[2] << 16 | HEAPU8[3] << 24);
+ }
+ 
+ function $2() {
+  return Math_fround((wasm2js_scratch_store_i32(2, HEAPU8[0] | HEAPU8[1] << 8 | (HEAPU8[2] << 16 | HEAPU8[3] << 24)), wasm2js_scratch_load_f32()));
+ }
+ 
+ function $3() {
+  var $0_1 = 0;
+  $0_1 = HEAPU8[4] | HEAPU8[5] << 8 | (HEAPU8[6] << 16 | HEAPU8[7] << 24);
+  wasm2js_scratch_store_i32(0, HEAPU8[0] | HEAPU8[1] << 8 | (HEAPU8[2] << 16 | HEAPU8[3] << 24));
+  wasm2js_scratch_store_i32(1, $0_1 | 0);
+  return +wasm2js_scratch_load_f64();
+ }
+ 
+ function $4() {
+  HEAP8[0] = 0;
+  HEAP8[1] = 0;
+  HEAP8[2] = 0;
+  HEAP8[3] = 0;
+ }
+ 
+ function $5() {
+  HEAP8[0] = 0;
+  HEAP8[1] = 0;
+  HEAP8[2] = 0;
+  HEAP8[3] = 0;
+  HEAP8[4] = 0;
+  HEAP8[5] = 0;
+  HEAP8[6] = 0;
+  HEAP8[7] = 0;
+ }
+ 
+ function $7() {
+  var $0_1 = 0, $1_1 = 0;
+  wasm2js_scratch_store_f64(0.0);
+  $0_1 = wasm2js_scratch_load_i32(1) | 0;
+  $1_1 = wasm2js_scratch_load_i32(0) | 0;
+  HEAP8[0] = $1_1;
+  HEAP8[1] = $1_1 >>> 8;
+  HEAP8[2] = $1_1 >>> 16;
+  HEAP8[3] = $1_1 >>> 24;
+  HEAP8[4] = $0_1;
+  HEAP8[5] = $0_1 >>> 8;
+  HEAP8[6] = $0_1 >>> 16;
+  HEAP8[7] = $0_1 >>> 24;
+ }
+ 
+ function legalstub$1() {
+  var $0_1 = 0;
+  $0_1 = $1();
+  setTempRet0(i64toi32_i32$HIGH_BITS | 0);
+  return $0_1;
+ }
+ 
+ function __wasm_memory_size() {
+  return buffer.byteLength / 65536 | 0;
+ }
+ 
+ return {
+  "i32_load": $0, 
+  "i64_load": legalstub$1, 
+  "f32_load": $2, 
+  "f64_load": $3, 
+  "i32_store": $4, 
+  "i64_store": $5, 
+  "f32_store": $4, 
+  "f64_store": $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'); },
+    setTempRet0
+  },
+  memasmFunc
+);
+export var i32_load = retasmFunc.i32_load;
+export var i64_load = retasmFunc.i64_load;
+export var f32_load = retasmFunc.f32_load;
+export var f64_load = retasmFunc.f64_load;
+export var i32_store = retasmFunc.i32_store;
+export var i64_store = retasmFunc.i64_store;
+export var f32_store = retasmFunc.f32_store;
+export var f64_store = retasmFunc.f64_store;
diff --git a/binaryen/test/wasm2js/unaligned.wast b/binaryen/test/wasm2js/unaligned.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/unaligned.wast
@@ -0,0 +1,21 @@
+(module
+  (memory 1 1)
+
+  (func (export "i32.load") (result i32)
+    (i32.load align=1 (i32.const 0)))
+  (func (export "i64.load") (result i64)
+    (i64.load align=1 (i32.const 0)))
+  (func (export "f32.load") (result f32)
+    (f32.load align=1 (i32.const 0)))
+  (func (export "f64.load") (result f64)
+    (f64.load align=1 (i32.const 0)))
+
+  (func (export "i32.store")
+    (i32.store align=1 (i32.const 0) (i32.const 0)))
+  (func (export "i64.store")
+    (i64.store align=1 (i32.const 0) (i64.const 0)))
+  (func (export "f32.store")
+    (f32.store align=1 (i32.const 0) (f32.const 0)))
+  (func (export "f64.store")
+    (f64.store align=1 (i32.const 0) (f64.const 0)))
+)
diff --git a/binaryen/test/wasm2js/unary-ops.2asm.js b/binaryen/test/wasm2js/unary-ops.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/unary-ops.2asm.js
@@ -0,0 +1,542 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $1($0) {
+  $0 = $0 | 0;
+  return __wasm_popcnt_i32($0 | 0) | 0 | 0;
+ }
+ 
+ function $2($0, $0$hi, r, r$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  r = r | 0;
+  r$hi = r$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $3$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = __wasm_popcnt_i64($0 | 0, i64toi32_i32$0 | 0) | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $3$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = r$hi;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = r$hi;
+  return (i64toi32_i32$2 | 0) == (r | 0) & (i64toi32_i32$1 | 0) == (i64toi32_i32$0 | 0) | 0 | 0;
+ }
+ 
+ function $3($0, r, r$hi) {
+  $0 = $0 | 0;
+  r = r | 0;
+  r$hi = r$hi | 0;
+  var i64toi32_i32$0 = 0, $3$hi = 0;
+  i64toi32_i32$0 = 0;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = r$hi;
+  i64toi32_i32$0 = $3$hi;
+  return ($0 | 0) == (r | 0) & (i64toi32_i32$0 | 0) == (r$hi | 0) | 0 | 0;
+ }
+ 
+ function $4($0, r, r$hi) {
+  $0 = $0 | 0;
+  r = r | 0;
+  r$hi = r$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $3$hi = 0;
+  i64toi32_i32$1 = $0;
+  i64toi32_i32$0 = i64toi32_i32$1 >> 31 | 0;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = r$hi;
+  i64toi32_i32$0 = $3$hi;
+  i64toi32_i32$1 = r$hi;
+  return ($0 | 0) == (r | 0) & (i64toi32_i32$0 | 0) == (i64toi32_i32$1 | 0) | 0 | 0;
+ }
+ 
+ function $5($0, $0$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  var i64toi32_i32$0 = 0;
+  i64toi32_i32$0 = $0$hi;
+  return !($0 | i64toi32_i32$0 | 0) | 0;
+ }
+ 
+ function $6($0) {
+  $0 = $0 | 0;
+  return Math_clz32($0) | 0;
+ }
+ 
+ function $7($0) {
+  $0 = $0 | 0;
+  return __wasm_ctz_i32($0 | 0) | 0 | 0;
+ }
+ 
+ function $8($0, $0$hi, r, r$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  r = r | 0;
+  r$hi = r$hi | 0;
+  var i64toi32_i32$3 = 0, i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $9_1 = 0, $3$hi = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$1 = $0;
+  i64toi32_i32$3 = Math_clz32(i64toi32_i32$0);
+  i64toi32_i32$2 = 0;
+  if ((i64toi32_i32$3 | 0) == (32 | 0)) {
+   $9_1 = Math_clz32(i64toi32_i32$1) + 32 | 0
+  } else {
+   $9_1 = i64toi32_i32$3
+  }
+  $3$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = r$hi;
+  i64toi32_i32$2 = $3$hi;
+  i64toi32_i32$1 = $9_1;
+  i64toi32_i32$0 = r$hi;
+  i64toi32_i32$3 = r;
+  return (i64toi32_i32$1 | 0) == (i64toi32_i32$3 | 0) & (i64toi32_i32$2 | 0) == (i64toi32_i32$0 | 0) | 0 | 0;
+ }
+ 
+ function $9($0, $0$hi, r, r$hi) {
+  $0 = $0 | 0;
+  $0$hi = $0$hi | 0;
+  r = r | 0;
+  r$hi = r$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, $3$hi = 0, i64toi32_i32$2 = 0;
+  i64toi32_i32$0 = $0$hi;
+  i64toi32_i32$0 = __wasm_ctz_i64($0 | 0, i64toi32_i32$0 | 0) | 0;
+  i64toi32_i32$1 = i64toi32_i32$HIGH_BITS;
+  $3$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = r$hi;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$2 = i64toi32_i32$0;
+  i64toi32_i32$0 = r$hi;
+  return (i64toi32_i32$2 | 0) == (r | 0) & (i64toi32_i32$1 | 0) == (i64toi32_i32$0 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$2($0, $1_1, $2_1, $3_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5_1 = 0, $5$hi = 0, $8$hi = 0, $9_1 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5_1 = $0;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5_1;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9_1 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  return $2($9_1 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$3($0, $1_1, $2_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $12 = 0, $3_1 = 0, $5_1 = 0, $5$hi = 0, $8$hi = 0;
+  $3_1 = $0;
+  i64toi32_i32$0 = 0;
+  $5_1 = $1_1;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $2_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5_1;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return $3($3_1 | 0, i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$4($0, $1_1, $2_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $12 = 0, $3_1 = 0, $5_1 = 0, $5$hi = 0, $8$hi = 0;
+  $3_1 = $0;
+  i64toi32_i32$0 = 0;
+  $5_1 = $1_1;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $2_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $12 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $12 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5_1;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $12;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return $4($3_1 | 0, i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$5($0, $1_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $10 = 0, $3_1 = 0, $3$hi = 0, $6$hi = 0;
+  i64toi32_i32$0 = 0;
+  $3_1 = $0;
+  $3$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $10 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $10 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $6$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $3$hi;
+  i64toi32_i32$0 = $3_1;
+  i64toi32_i32$2 = $6$hi;
+  i64toi32_i32$3 = $10;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  return $5(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$8($0, $1_1, $2_1, $3_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5_1 = 0, $5$hi = 0, $8$hi = 0, $9_1 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5_1 = $0;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5_1;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9_1 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  return $8($9_1 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function legalstub$9($0, $1_1, $2_1, $3_1) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2_1 = $2_1 | 0;
+  $3_1 = $3_1 | 0;
+  var i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, $19 = 0, $20 = 0, $5_1 = 0, $5$hi = 0, $8$hi = 0, $9_1 = 0, $9$hi = 0, $11 = 0, $11$hi = 0, $14$hi = 0, $15 = 0, $15$hi = 0;
+  i64toi32_i32$0 = 0;
+  $5_1 = $0;
+  $5$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$2 = $1_1;
+  i64toi32_i32$1 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$1 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+   $19 = 0;
+  } else {
+   i64toi32_i32$1 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$2 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$0 << i64toi32_i32$4 | 0) | 0;
+   $19 = i64toi32_i32$2 << i64toi32_i32$4 | 0;
+  }
+  $8$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $5$hi;
+  i64toi32_i32$0 = $5_1;
+  i64toi32_i32$2 = $8$hi;
+  i64toi32_i32$3 = $19;
+  i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
+  $9_1 = i64toi32_i32$0 | i64toi32_i32$3 | 0;
+  $9$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  $11 = $2_1;
+  $11$hi = i64toi32_i32$2;
+  i64toi32_i32$2 = 0;
+  i64toi32_i32$1 = $3_1;
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$3 = 32;
+  i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
+  if (32 >>> 0 <= (i64toi32_i32$3 & 63 | 0) >>> 0) {
+   i64toi32_i32$0 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+   $20 = 0;
+  } else {
+   i64toi32_i32$0 = ((1 << i64toi32_i32$4 | 0) - 1 | 0) & (i64toi32_i32$1 >>> (32 - i64toi32_i32$4 | 0) | 0) | 0 | (i64toi32_i32$2 << i64toi32_i32$4 | 0) | 0;
+   $20 = i64toi32_i32$1 << i64toi32_i32$4 | 0;
+  }
+  $14$hi = i64toi32_i32$0;
+  i64toi32_i32$0 = $11$hi;
+  i64toi32_i32$2 = $11;
+  i64toi32_i32$1 = $14$hi;
+  i64toi32_i32$3 = $20;
+  i64toi32_i32$1 = i64toi32_i32$0 | i64toi32_i32$1 | 0;
+  $15 = i64toi32_i32$2 | i64toi32_i32$3 | 0;
+  $15$hi = i64toi32_i32$1;
+  i64toi32_i32$1 = $9$hi;
+  i64toi32_i32$2 = $15$hi;
+  return $9($9_1 | 0, i64toi32_i32$1 | 0, $15 | 0, i64toi32_i32$2 | 0) | 0 | 0;
+ }
+ 
+ function __wasm_ctz_i32(var$0) {
+  var$0 = var$0 | 0;
+  if (var$0) {
+   return 31 - Math_clz32((var$0 + -1 | 0) ^ var$0 | 0) | 0 | 0
+  }
+  return 32 | 0;
+ }
+ 
+ function __wasm_ctz_i64(var$0, var$0$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$3 = 0, i64toi32_i32$5 = 0, i64toi32_i32$4 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0, $10 = 0, $5$hi = 0, $8$hi = 0;
+  i64toi32_i32$0 = var$0$hi;
+  if (!!(var$0 | i64toi32_i32$0 | 0)) {
+   i64toi32_i32$0 = var$0$hi;
+   i64toi32_i32$2 = var$0;
+   i64toi32_i32$1 = -1;
+   i64toi32_i32$3 = -1;
+   i64toi32_i32$4 = i64toi32_i32$2 + i64toi32_i32$3 | 0;
+   i64toi32_i32$5 = i64toi32_i32$0 + i64toi32_i32$1 | 0;
+   if (i64toi32_i32$4 >>> 0 < i64toi32_i32$3 >>> 0) {
+    i64toi32_i32$5 = i64toi32_i32$5 + 1 | 0
+   }
+   $5$hi = i64toi32_i32$5;
+   i64toi32_i32$5 = var$0$hi;
+   i64toi32_i32$5 = $5$hi;
+   i64toi32_i32$0 = i64toi32_i32$4;
+   i64toi32_i32$2 = var$0$hi;
+   i64toi32_i32$3 = var$0;
+   i64toi32_i32$2 = i64toi32_i32$5 ^ i64toi32_i32$2 | 0;
+   i64toi32_i32$0 = i64toi32_i32$0 ^ i64toi32_i32$3 | 0;
+   i64toi32_i32$3 = Math_clz32(i64toi32_i32$2);
+   i64toi32_i32$5 = 0;
+   if ((i64toi32_i32$3 | 0) == (32 | 0)) {
+    $10 = Math_clz32(i64toi32_i32$0) + 32 | 0
+   } else {
+    $10 = i64toi32_i32$3
+   }
+   $8$hi = i64toi32_i32$5;
+   i64toi32_i32$5 = 0;
+   i64toi32_i32$0 = 63;
+   i64toi32_i32$2 = $8$hi;
+   i64toi32_i32$3 = $10;
+   i64toi32_i32$1 = i64toi32_i32$0 - i64toi32_i32$3 | 0;
+   i64toi32_i32$4 = (i64toi32_i32$0 >>> 0 < i64toi32_i32$3 >>> 0) + i64toi32_i32$2 | 0;
+   i64toi32_i32$4 = i64toi32_i32$5 - i64toi32_i32$4 | 0;
+   i64toi32_i32$0 = i64toi32_i32$1;
+   i64toi32_i32$HIGH_BITS = i64toi32_i32$4;
+   return i64toi32_i32$0 | 0;
+  }
+  i64toi32_i32$0 = 0;
+  i64toi32_i32$4 = 64;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
+  return i64toi32_i32$4 | 0;
+ }
+ 
+ function __wasm_popcnt_i32(var$0) {
+  var$0 = var$0 | 0;
+  var var$1 = 0, $5_1 = 0;
+  label$1 : {
+   label$2 : while (1) {
+    $5_1 = var$1;
+    if (!var$0) {
+     break label$1
+    }
+    var$0 = var$0 & (var$0 - 1 | 0) | 0;
+    var$1 = var$1 + 1 | 0;
+    continue label$2;
+   };
+  }
+  return $5_1 | 0;
+ }
+ 
+ function __wasm_popcnt_i64(var$0, var$0$hi) {
+  var$0 = var$0 | 0;
+  var$0$hi = var$0$hi | 0;
+  var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$5 = 0, i64toi32_i32$4 = 0, i64toi32_i32$3 = 0, i64toi32_i32$1 = 0, var$1$hi = 0, var$1 = 0, $5_1 = 0, $5$hi = 0, $4_1 = 0, $9$hi = 0;
+  label$1 : {
+   label$2 : while (1) {
+    i64toi32_i32$0 = var$1$hi;
+    i64toi32_i32$0 = var$0$hi;
+    $4_1 = !(var$0 | i64toi32_i32$0 | 0);
+    i64toi32_i32$0 = var$1$hi;
+    $5_1 = var$1;
+    $5$hi = i64toi32_i32$0;
+    if ($4_1) {
+     break label$1
+    }
+    i64toi32_i32$0 = $5$hi;
+    i64toi32_i32$0 = var$0$hi;
+    i64toi32_i32$2 = var$0;
+    i64toi32_i32$1 = 0;
+    i64toi32_i32$3 = 1;
+    i64toi32_i32$4 = i64toi32_i32$2 - i64toi32_i32$3 | 0;
+    i64toi32_i32$5 = (i64toi32_i32$2 >>> 0 < i64toi32_i32$3 >>> 0) + i64toi32_i32$1 | 0;
+    i64toi32_i32$5 = i64toi32_i32$0 - i64toi32_i32$5 | 0;
+    $9$hi = i64toi32_i32$5;
+    i64toi32_i32$5 = i64toi32_i32$0;
+    i64toi32_i32$0 = i64toi32_i32$2;
+    i64toi32_i32$2 = $9$hi;
+    i64toi32_i32$3 = i64toi32_i32$4;
+    i64toi32_i32$2 = i64toi32_i32$5 & i64toi32_i32$2 | 0;
+    var$0 = i64toi32_i32$0 & i64toi32_i32$4 | 0;
+    var$0$hi = i64toi32_i32$2;
+    i64toi32_i32$2 = var$1$hi;
+    i64toi32_i32$5 = var$1;
+    i64toi32_i32$0 = 0;
+    i64toi32_i32$3 = 1;
+    i64toi32_i32$1 = i64toi32_i32$5 + i64toi32_i32$3 | 0;
+    i64toi32_i32$4 = i64toi32_i32$2 + i64toi32_i32$0 | 0;
+    if (i64toi32_i32$1 >>> 0 < i64toi32_i32$3 >>> 0) {
+     i64toi32_i32$4 = i64toi32_i32$4 + 1 | 0
+    }
+    var$1 = i64toi32_i32$1;
+    var$1$hi = i64toi32_i32$4;
+    continue label$2;
+   };
+  }
+  i64toi32_i32$4 = $5$hi;
+  i64toi32_i32$5 = $5_1;
+  i64toi32_i32$HIGH_BITS = i64toi32_i32$4;
+  return i64toi32_i32$5 | 0;
+ }
+ 
+ return {
+  "i32_popcnt": $1, 
+  "check_popcnt_i64": legalstub$2, 
+  "check_extend_ui32": legalstub$3, 
+  "check_extend_si32": legalstub$4, 
+  "check_eqz_i64": legalstub$5, 
+  "i32_clz": $6, 
+  "i32_ctz": $7, 
+  "check_clz_i64": legalstub$8, 
+  "check_ctz_i64": legalstub$9
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var i32_popcnt = retasmFunc.i32_popcnt;
+export var check_popcnt_i64 = retasmFunc.check_popcnt_i64;
+export var check_extend_ui32 = retasmFunc.check_extend_ui32;
+export var check_extend_si32 = retasmFunc.check_extend_si32;
+export var check_eqz_i64 = retasmFunc.check_eqz_i64;
+export var i32_clz = retasmFunc.i32_clz;
+export var i32_ctz = retasmFunc.i32_ctz;
+export var check_clz_i64 = retasmFunc.check_clz_i64;
+export var check_ctz_i64 = retasmFunc.check_ctz_i64;
diff --git a/binaryen/test/wasm2js/unary-ops.2asm.js.opt b/binaryen/test/wasm2js/unary-ops.2asm.js.opt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/unary-ops.2asm.js.opt
@@ -0,0 +1,162 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var i64toi32_i32$HIGH_BITS = 0;
+ function $1($0) {
+  $0 = $0 | 0;
+  return __wasm_popcnt_i32($0) | 0;
+ }
+ 
+ function $6($0) {
+  $0 = $0 | 0;
+  return Math_clz32($0) | 0;
+ }
+ 
+ function $7($0) {
+  $0 = $0 | 0;
+  if ($0) {
+   $0 = 31 - Math_clz32($0 + -1 ^ $0) | 0
+  } else {
+   $0 = 32
+  }
+  return $0 | 0;
+ }
+ 
+ function $8($0, $1_1, $2, $3) {
+  $0 = $0 | 0;
+  $1_1 = $1_1 | 0;
+  $2 = $2 | 0;
+  $3 = $3 | 0;
+  var $4 = 0;
+  $4 = Math_clz32($0) + 32 | 0;
+  $0 = Math_clz32($1_1);
+  return !$3 & ($2 | 0) == ((($0 | 0) == 32 ? $4 : $0) | 0);
+ }
+ 
+ function legalstub$2($0, $1_1, $2, $3) {
+  return (__wasm_popcnt_i64($0, $1_1) | 0) == ($2 | 0) & ($3 | 0) == (i64toi32_i32$HIGH_BITS | 0);
+ }
+ 
+ function legalstub$3($0, $1_1, $2) {
+  return !$2 & ($0 | 0) == ($1_1 | 0);
+ }
+ 
+ function legalstub$4($0, $1_1, $2) {
+  return ($0 | 0) == ($1_1 | 0) & ($2 | 0) == $0 >> 31;
+ }
+ 
+ function legalstub$5($0, $1_1) {
+  return !($0 | $1_1);
+ }
+ 
+ function legalstub$8($0, $1_1, $2, $3) {
+  return $8($0, $1_1, $2, $3);
+ }
+ 
+ function legalstub$9($0, $1_1, $2, $3) {
+  return (__wasm_ctz_i64($0, $1_1) | 0) == ($2 | 0) & ($3 | 0) == (i64toi32_i32$HIGH_BITS | 0);
+ }
+ 
+ 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;
+   $1_1 = 63 - $0 | 0;
+   i64toi32_i32$HIGH_BITS = 0 - (63 < $0 >>> 0) | 0;
+   return $1_1;
+  }
+  i64toi32_i32$HIGH_BITS = 0;
+  return 64;
+ }
+ 
+ function __wasm_popcnt_i32($0) {
+  var $1_1 = 0, $2 = 0;
+  while (1) {
+   $2 = $1_1;
+   if ($0) {
+    $0 = $0 - 1 & $0;
+    $1_1 = $1_1 + 1 | 0;
+    continue;
+   }
+   break;
+  };
+  return $2;
+ }
+ 
+ function __wasm_popcnt_i64($0, $1_1) {
+  var $2 = 0, $3 = 0, $4 = 0, $5 = 0;
+  while (1) {
+   $5 = $3;
+   $2 = $4;
+   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;
+    continue;
+   }
+   break;
+  };
+  i64toi32_i32$HIGH_BITS = $2;
+  return $5;
+ }
+ 
+ return {
+  "i32_popcnt": $1, 
+  "check_popcnt_i64": legalstub$2, 
+  "check_extend_ui32": legalstub$3, 
+  "check_extend_si32": legalstub$4, 
+  "check_eqz_i64": legalstub$5, 
+  "i32_clz": $6, 
+  "i32_ctz": $7, 
+  "check_clz_i64": legalstub$8, 
+  "check_ctz_i64": legalstub$9
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var i32_popcnt = retasmFunc.i32_popcnt;
+export var check_popcnt_i64 = retasmFunc.check_popcnt_i64;
+export var check_extend_ui32 = retasmFunc.check_extend_ui32;
+export var check_extend_si32 = retasmFunc.check_extend_si32;
+export var check_eqz_i64 = retasmFunc.check_eqz_i64;
+export var i32_clz = retasmFunc.i32_clz;
+export var i32_ctz = retasmFunc.i32_ctz;
+export var check_clz_i64 = retasmFunc.check_clz_i64;
+export var check_ctz_i64 = retasmFunc.check_ctz_i64;
diff --git a/binaryen/test/wasm2js/unary-ops.wast b/binaryen/test/wasm2js/unary-ops.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/unary-ops.wast
@@ -0,0 +1,145 @@
+(module
+  (func $dummy)
+
+  (func (export "i32.popcnt") (param $0 i32) (result i32)
+    (i32.popcnt (local.get $0)))
+
+  (func (export "check_popcnt_i64") (param $0 i64) (param $r i64) (result i32)
+    (i64.eq (i64.popcnt (local.get $0)) (local.get $r)))
+
+  (func (export "check_extend_ui32") (param $0 i32) (param $r i64) (result i32)
+    (i64.eq (i64.extend_i32_u (local.get $0)) (local.get $r)))
+
+  (func (export "check_extend_si32") (param $0 i32) (param $r i64) (result i32)
+    (i64.eq (i64.extend_i32_s (local.get $0)) (local.get $r)))
+
+  (func (export "check_eqz_i64") (param $0 i64) (result i32)
+    (i64.eqz (local.get $0)))
+
+  (func (export "i32.clz") (param $0 i32) (result i32)
+    (i32.clz (local.get $0)))
+
+  (func (export "i32.ctz") (param $0 i32) (result i32)
+    (i32.ctz (local.get $0)))
+
+  (func (export "check_clz_i64") (param $0 i64) (param $r i64) (result i32)
+    (i64.eq (i64.clz (local.get $0)) (local.get $r)))
+
+  (func (export "check_ctz_i64") (param $0 i64) (param $r i64) (result i32)
+    (i64.eq (i64.ctz (local.get $0)) (local.get $r)))
+)
+
+(assert_return (invoke "i32.popcnt" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "i32.popcnt" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "i32.popcnt" (i32.const 0x7fffffff)) (i32.const 31))
+(assert_return (invoke "i32.popcnt" (i32.const 0xffffffff)) (i32.const 32))
+
+(assert_return (invoke "check_popcnt_i64" (i32.const 0) (i32.const 0)
+                                          (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_popcnt_i64" (i32.const 1) (i32.const 0)
+                                          (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_popcnt_i64" (i32.const 0) (i32.const 1)
+                                          (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_popcnt_i64" (i32.const 0x7fffffff) (i32.const 0)
+                                          (i32.const 31) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_popcnt_i64" (i32.const 0x7fffffff) (i32.const 1)
+                                          (i32.const 32) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_popcnt_i64" (i32.const 0x7fffffff) (i32.const 0x7fffffff)
+                                          (i32.const 62) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_popcnt_i64" (i32.const 0xffffffff) (i32.const 0xffffffff)
+                                          (i32.const 64) (i32.const 0))
+               (i32.const 1))
+
+(assert_return (invoke "check_extend_ui32" (i32.const 0)
+                                           (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_extend_ui32" (i32.const 1)
+                                           (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_extend_ui32" (i32.const 0x7fffffff)
+                                           (i32.const 0x7fffffff) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_extend_ui32" (i32.const 0xffffffff)
+                                           (i32.const 0xffffffff) (i32.const 0))
+               (i32.const 1))
+
+(assert_return (invoke "check_extend_si32" (i32.const 0)
+                                           (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_extend_si32" (i32.const 1)
+                                           (i32.const 1) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_extend_si32" (i32.const 0x7fffffff)
+                                           (i32.const 0x7fffffff) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_extend_si32" (i32.const 0x80000000)
+                                           (i32.const 0x80000000) (i32.const 0xffffffff))
+               (i32.const 1))
+(assert_return (invoke "check_extend_si32" (i32.const 0xffffffff)
+                                           (i32.const 0xffffffff) (i32.const 0xffffffff))
+               (i32.const 1))
+
+(assert_return (invoke "check_eqz_i64" (i32.const 0) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_eqz_i64" (i32.const 1) (i32.const 0))
+               (i32.const 0))
+(assert_return (invoke "check_eqz_i64" (i32.const 0) (i32.const 1))
+               (i32.const 0))
+
+(assert_return (invoke "i32.clz" (i32.const 0)) (i32.const 32))
+(assert_return (invoke "i32.clz" (i32.const 1)) (i32.const 31))
+(assert_return (invoke "i32.clz" (i32.const 0x7fffffff)) (i32.const 1))
+(assert_return (invoke "i32.clz" (i32.const 0xffffffff)) (i32.const 0))
+
+(assert_return (invoke "i32.ctz" (i32.const 0)) (i32.const 32))
+(assert_return (invoke "i32.ctz" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "i32.ctz" (i32.const 0xfffffffe)) (i32.const 1))
+(assert_return (invoke "i32.ctz" (i32.const 0x80000000)) (i32.const 31))
+
+(assert_return (invoke "check_clz_i64"
+                       (i32.const 0) (i32.const 0)
+                       (i32.const 64) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_clz_i64"
+                       (i32.const 1) (i32.const 0)
+                       (i32.const 63) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_clz_i64"
+                       (i32.const 0x80000000) (i32.const 0)
+                       (i32.const 32) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_clz_i64"
+                       (i32.const 0) (i32.const 1)
+                       (i32.const 31) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_clz_i64"
+                       (i32.const 0) (i32.const 0x80000000)
+                       (i32.const 0) (i32.const 0))
+               (i32.const 1))
+
+(assert_return (invoke "check_ctz_i64"
+                       (i32.const 0) (i32.const 0)
+                       (i32.const 64) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_ctz_i64"
+                       (i32.const 0) (i32.const 0x80000000)
+                       (i32.const 63) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_ctz_i64"
+                       (i32.const 0) (i32.const 1)
+                       (i32.const 32) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_ctz_i64"
+                       (i32.const 0x80000000) (i32.const 0)
+                       (i32.const 31) (i32.const 0))
+               (i32.const 1))
+(assert_return (invoke "check_ctz_i64"
+                       (i32.const 1) (i32.const 0)
+                       (i32.const 0) (i32.const 0))
+               (i32.const 1))
diff --git a/binaryen/test/wasm2js/unreachable-get-cycle.2asm.js b/binaryen/test/wasm2js/unreachable-get-cycle.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/unreachable-get-cycle.2asm.js
@@ -0,0 +1,34 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ return {
+  
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/unreachable-get-cycle.2asm.js.opt
@@ -0,0 +1,34 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ return {
+  
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
diff --git a/binaryen/test/wasm2js/unreachable-get-cycle.wast b/binaryen/test/wasm2js/unreachable-get-cycle.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/unreachable-get-cycle.wast
@@ -0,0 +1,35 @@
+(module
+ (type $0 (func (param i64 f64) (result i64)))
+ (memory $0 1 1)
+ (func $0 (; 0 ;) (type $0) (param $0 i64) (param $1 f64) (result i64)
+  (local $2 f32)
+  (if (result i64)
+   (loop $label$1 (result i32)
+    (br_if $label$1
+     (i32.const 1)
+    )
+    (i32.const 0)
+   )
+   (loop $label$3
+    (block $label$4
+     (f32.store offset=22 align=2
+      (i32.const 0)
+      (local.get $2)
+     )
+     (drop
+      (local.tee $2
+       (if (result f32)
+        (i32.const -19666)
+        (local.get $2)
+        (unreachable)
+       )
+      )
+     )
+    )
+    (br $label$3)
+   )
+   (i64.const 1)
+  )
+ )
+)
+
diff --git a/binaryen/test/wasm2js/unreachable-insts.2asm.js b/binaryen/test/wasm2js/unreachable-insts.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/unreachable-insts.2asm.js
@@ -0,0 +1,34 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ return {
+  
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/unreachable-insts.2asm.js.opt
@@ -0,0 +1,34 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ return {
+  
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
diff --git a/binaryen/test/wasm2js/unreachable-insts.wast b/binaryen/test/wasm2js/unreachable-insts.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/unreachable-insts.wast
@@ -0,0 +1,13 @@
+(module
+ (type $0 (func (param f64 f64 f32)))
+ (memory $0 1 1)
+ (func $0 (; 0 ;) (type $0) (param $0 f64) (param $1 f64) (param $2 f32)
+  (f64.store offset=22 align=1
+   (block $label$1 (result i32)
+    (unreachable)
+   )
+   (f64.const 1)
+  )
+ )
+)
+
diff --git a/binaryen/test/wasm2js/unreachable-later.2asm.js b/binaryen/test/wasm2js/unreachable-later.2asm.js
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/unreachable-later.2asm.js
@@ -0,0 +1,81 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var global$0 = 10;
+ function $0($0_1) {
+  $0_1 = $0_1 | 0;
+  var $15 = Math_fround(0), $21 = 0, $29 = 0, $26 = 0;
+  if (global$0) {
+   return $0_1 | 0
+  }
+  if (global$0) {
+   return $0_1 | 0
+  }
+  global$0 = 0;
+  label$3 : while (1) {
+   label$4 : {
+    if (global$0) {
+     return $0_1 | 0
+    }
+    if (global$0) {
+     return $0_1 | 0
+    }
+    if (global$0) {
+     return $0_1 | 0
+    }
+    $15 = Math_fround(0.0);
+    if (global$0) {
+     return $0_1 | 0
+    }
+   }
+   $21 = 32;
+   if (!$21) {
+    continue label$3
+   }
+   $26 = 1;
+   break label$3;
+  };
+  if (!$26) {
+   $29 = 0
+  } else {
+   $29 = 1
+  }
+  if (!$29) {
+   return -255 | 0
+  } else {
+   abort()
+  }
+ }
+ 
+ return {
+  "func_50": $0
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    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
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/unreachable-later.2asm.js.opt
@@ -0,0 +1,54 @@
+
+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;
+ var abort = env.abort;
+ var nan = global.NaN;
+ var infinity = global.Infinity;
+ var global$0 = 10;
+ function $0($0_1) {
+  $0_1 = $0_1 | 0;
+  folding_inner0 : {
+   if (global$0) {
+    break folding_inner0
+   }
+   global$0 = 0;
+   if (global$0) {
+    break folding_inner0
+   }
+   if (global$0) {
+    break folding_inner0
+   }
+   abort();
+  }
+  return $0_1 | 0;
+ }
+ 
+ return {
+  "func_50": $0
+ };
+}
+
+var retasmFunc = asmFunc({
+    Math,
+    Int8Array,
+    Uint8Array,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array,
+    NaN,
+    Infinity
+  }, {
+    abort: function() { throw new Error('abort'); }
+  });
+export var func_50 = retasmFunc.func_50;
diff --git a/binaryen/test/wasm2js/unreachable-later.wast b/binaryen/test/wasm2js/unreachable-later.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/unreachable-later.wast
@@ -0,0 +1,86 @@
+(module
+ (type $0 (func (param i32) (result i32)))
+ (global $global$0 (mut i32) (i32.const 10))
+ (export "func_50" (func $0))
+ (func $0 (; 0 ;) (type $0) (param $0 i32) (result i32)
+  (if
+   (global.get $global$0)
+   (return
+    (local.get $0)
+   )
+  )
+  (if
+   (global.get $global$0)
+   (return
+    (local.get $0)
+   )
+  )
+  (global.set $global$0
+   (i32.const 0)
+  )
+  (if
+   (i32.eqz
+    (if (result i32)
+     (i32.eqz
+      (loop $label$3 (result i32)
+       (br_if $label$3
+        (i32.eqz
+         (if (result i32)
+          (block $label$4 (result i32)
+           (if
+            (global.get $global$0)
+            (return
+             (local.get $0)
+            )
+           )
+           (drop
+            (if (result f32)
+             (block $label$6 (result i32)
+              (if
+               (global.get $global$0)
+               (return
+                (local.get $0)
+               )
+              )
+              (i32.const 65445)
+             )
+             (block (result f32)
+              (if
+               (global.get $global$0)
+               (return
+                (local.get $0)
+               )
+              )
+              (f32.const 0)
+             )
+             (f32.const 1)
+            )
+           )
+           (if
+            (global.get $global$0)
+            (return
+             (local.get $0)
+            )
+           )
+           (i32.const 1)
+          )
+          (i32.const 32)
+          (i32.const 0)
+         )
+        )
+       )
+       (i32.const 1)
+      )
+     )
+     (i32.const 0)
+     (i32.const 1)
+    )
+   )
+   (return
+    (i32.const -255)
+   )
+   (unreachable)
+  )
+ )
+)
+
diff --git a/binaryen/test/wasm2js/wasm2js.wast.asserts b/binaryen/test/wasm2js/wasm2js.wast.asserts
new file mode 100644
--- /dev/null
+++ b/binaryen/test/wasm2js/wasm2js.wast.asserts
@@ -0,0 +1,12 @@
+;; i32 operations
+
+(module
+  (func (export "empty"))
+  (func (export "add") (param $x i32) (param $y i32) (result i32) (i32.add (local.get $x) (local.get $y)))
+  (func (export "div_s") (param $x i32) (param $y i32) (result i32) (i32.div_s (local.get $x) (local.get $y)))
+)
+
+(assert_return (invoke "empty"))
+(assert_return (invoke "add" (i32.const 1) (i32.const 1)) (i32.const 2))
+(assert_trap (invoke "div_s" (i32.const 0) (i32.const 0)) "integer divide by zero")
+(assert_trap (invoke "div_s" (i32.const 0x80000000) (i32.const -1)) "integer overflow")
diff --git a/binaryen/third_party/CMakeLists.txt b/binaryen/third_party/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/CMakeLists.txt
@@ -0,0 +1,3 @@
+if(BUILD_LLVM_DWARF)
+  add_subdirectory(llvm-project)
+endif()
diff --git a/binaryen/third_party/llvm-project/Binary.cpp b/binaryen/third_party/llvm-project/Binary.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/Binary.cpp
@@ -0,0 +1,72 @@
+//===- Binary.cpp - A generic binary file ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Binary class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/Binary.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/Error.h"
+#if 0 // XXX BINARYEN
+#include "llvm/Object/MachOUniversal.h"
+#include "llvm/Object/Minidump.h"
+#endif
+#include "llvm/Object/ObjectFile.h"
+#if 0 // XXX BINARYEN
+#include "llvm/Object/TapiUniversal.h"
+#include "llvm/Object/WindowsResource.h"
+#endif
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <algorithm>
+#include <memory>
+#include <system_error>
+
+using namespace llvm;
+using namespace object;
+
+Binary::~Binary() = default;
+
+Binary::Binary(unsigned int Type, MemoryBufferRef Source)
+    : TypeID(Type), Data(Source) {}
+
+StringRef Binary::getData() const { return Data.getBuffer(); }
+
+StringRef Binary::getFileName() const { return Data.getBufferIdentifier(); }
+
+MemoryBufferRef Binary::getMemoryBufferRef() const { return Data; }
+
+Expected<std::unique_ptr<Binary>> object::createBinary(MemoryBufferRef Buffer,
+                                                      LLVMContext *Context) {
+  llvm_unreachable("createBinary");
+}
+
+#if 0 // XXX BINARYEN
+Expected<OwningBinary<Binary>> object::createBinary(StringRef Path) {
+  ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
+      MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1,
+                                   /*RequiresNullTerminator=*/false);
+  if (std::error_code EC = FileOrErr.getError())
+    return errorCodeToError(EC);
+  std::unique_ptr<MemoryBuffer> &Buffer = FileOrErr.get();
+
+  Expected<std::unique_ptr<Binary>> BinOrErr =
+      createBinary(Buffer->getMemBufferRef());
+  if (!BinOrErr)
+    return BinOrErr.takeError();
+  std::unique_ptr<Binary> &Bin = BinOrErr.get();
+
+  return OwningBinary<Binary>(std::move(Bin), std::move(Buffer));
+}
+#endif
diff --git a/binaryen/third_party/llvm-project/CMakeLists.txt b/binaryen/third_party/llvm-project/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/CMakeLists.txt
@@ -0,0 +1,76 @@
+# LLVM sources have warnings, ignore them. Otherwise, use options as close
+# as possible to LLVM's defaults.
+foreach(variable CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+  if(NOT MSVC)
+    set(${variable} "${${variable}} -w -std=c++14 -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS")
+  else()
+    set(${variable} "${${variable}} /w -std:c++14 -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -DUNICODE -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS")
+  endif()
+endforeach(variable)
+
+SET(llvm_dwarf_SOURCES
+  Binary.cpp
+  ConvertUTF.cpp
+  DataExtractor.cpp
+  Debug.cpp
+  DJB.cpp
+  Dwarf.cpp
+  dwarf2yaml.cpp
+  DWARFAbbreviationDeclaration.cpp
+  DWARFAcceleratorTable.cpp
+  DWARFAddressRange.cpp
+  DWARFCompileUnit.cpp
+  DWARFContext.cpp
+  DWARFDataExtractor.cpp
+  DWARFDebugAbbrev.cpp
+  DWARFDebugAddr.cpp
+  DWARFDebugAranges.cpp
+  DWARFDebugArangeSet.cpp
+  DWARFDebugFrame.cpp
+  DWARFDebugInfoEntry.cpp
+  DWARFDebugLine.cpp
+  DWARFDebugLoc.cpp
+  DWARFDebugMacro.cpp
+  DWARFDebugPubTable.cpp
+  DWARFDebugRangeList.cpp
+  DWARFDebugRnglists.cpp
+  DWARFDie.cpp
+  DWARFEmitter.cpp
+  DWARFExpression.cpp
+  DWARFFormValue.cpp
+  DWARFGdbIndex.cpp
+  DWARFListTable.cpp
+  DWARFTypeUnit.cpp
+  DWARFUnit.cpp
+  DWARFUnitIndex.cpp
+  DWARFVerifier.cpp
+  DWARFVisitor.cpp
+  DWARFYAML.cpp
+  Error.cpp
+  ErrorHandling.cpp
+  FormatVariadic.cpp
+  Hashing.cpp
+  LEB128.cpp
+  LineIterator.cpp
+  MCRegisterInfo.cpp
+  MD5.cpp
+  MemoryBuffer.cpp
+  NativeFormatting.cpp
+  ObjectFile.cpp
+  obj2yaml_Error.cpp
+  Optional.cpp
+  Path.cpp
+  raw_ostream.cpp
+  ScopedPrinter.cpp
+  SmallVector.cpp
+  SourceMgr.cpp 
+  StringMap.cpp
+  StringRef.cpp
+  SymbolicFile.cpp
+  Twine.cpp
+  UnicodeCaseFold.cpp
+  WithColor.cpp
+  YAMLParser.cpp # XXX needed?
+  YAMLTraits.cpp
+)
+ADD_LIBRARY(llvm_dwarf OBJECT ${llvm_dwarf_SOURCES})
diff --git a/binaryen/third_party/llvm-project/ConvertUTF.cpp b/binaryen/third_party/llvm-project/ConvertUTF.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/ConvertUTF.cpp
@@ -0,0 +1,738 @@
+/*===--- ConvertUTF.c - Universal Character Names conversions ---------------===
+ *
+ * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+ * See https://llvm.org/LICENSE.txt for license information.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ *
+ *===------------------------------------------------------------------------=*/
+/*
+ * Copyright 2001-2004 Unicode, Inc.
+ *
+ * Disclaimer
+ *
+ * This source code is provided as is by Unicode, Inc. No claims are
+ * made as to fitness for any particular purpose. No warranties of any
+ * kind are expressed or implied. The recipient agrees to determine
+ * applicability of information provided. If this file has been
+ * purchased on magnetic or optical media from Unicode, Inc., the
+ * sole remedy for any claim will be exchange of defective media
+ * within 90 days of receipt.
+ *
+ * Limitations on Rights to Redistribute This Code
+ *
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+
+/* ---------------------------------------------------------------------
+
+    Conversions between UTF32, UTF-16, and UTF-8. Source code file.
+    Author: Mark E. Davis, 1994.
+    Rev History: Rick McGowan, fixes & updates May 2001.
+    Sept 2001: fixed const & error conditions per
+        mods suggested by S. Parent & A. Lillich.
+    June 2002: Tim Dodd added detection and handling of incomplete
+        source sequences, enhanced error detection, added casts
+        to eliminate compiler warnings.
+    July 2003: slight mods to back out aggressive FFFE detection.
+    Jan 2004: updated switches in from-UTF8 conversions.
+    Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
+
+    See the header file "ConvertUTF.h" for complete documentation.
+
+------------------------------------------------------------------------ */
+
+#include "llvm/Support/ConvertUTF.h"
+#ifdef CVTUTF_DEBUG
+#include <stdio.h>
+#endif
+#include <assert.h>
+
+/*
+ * This code extensively uses fall-through switches.
+ * Keep the compiler from warning about that.
+ */
+#if defined(__clang__) && defined(__has_warning)
+# if __has_warning("-Wimplicit-fallthrough")
+#  define ConvertUTF_DISABLE_WARNINGS \
+    _Pragma("clang diagnostic push")  \
+    _Pragma("clang diagnostic ignored \"-Wimplicit-fallthrough\"")
+#  define ConvertUTF_RESTORE_WARNINGS \
+    _Pragma("clang diagnostic pop")
+# endif
+#elif defined(__GNUC__) && __GNUC__ > 6
+# define ConvertUTF_DISABLE_WARNINGS \
+   _Pragma("GCC diagnostic push")    \
+   _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
+# define ConvertUTF_RESTORE_WARNINGS \
+   _Pragma("GCC diagnostic pop")
+#endif
+#ifndef ConvertUTF_DISABLE_WARNINGS
+# define ConvertUTF_DISABLE_WARNINGS
+#endif
+#ifndef ConvertUTF_RESTORE_WARNINGS
+# define ConvertUTF_RESTORE_WARNINGS
+#endif
+
+ConvertUTF_DISABLE_WARNINGS
+
+namespace llvm {
+
+static const int halfShift  = 10; /* used for shifting by 10 bits */
+
+static const UTF32 halfBase = 0x0010000UL;
+static const UTF32 halfMask = 0x3FFUL;
+
+#define UNI_SUR_HIGH_START  (UTF32)0xD800
+#define UNI_SUR_HIGH_END    (UTF32)0xDBFF
+#define UNI_SUR_LOW_START   (UTF32)0xDC00
+#define UNI_SUR_LOW_END     (UTF32)0xDFFF
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Index into the table below with the first byte of a UTF-8 sequence to
+ * get the number of trailing bytes that are supposed to follow it.
+ * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
+ * left as-is for anyone who may want to do such conversion, which was
+ * allowed in earlier algorithms.
+ */
+static const char trailingBytesForUTF8[256] = {
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
+};
+
+/*
+ * Magic values subtracted from a buffer value during UTF8 conversion.
+ * This table contains as many values as there might be trailing bytes
+ * in a UTF-8 sequence.
+ */
+static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
+                     0x03C82080UL, 0xFA082080UL, 0x82082080UL };
+
+/*
+ * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
+ * into the first byte, depending on how many bytes follow.  There are
+ * as many entries in this table as there are UTF-8 sequence types.
+ * (I.e., one byte sequence, two byte... etc.). Remember that sequencs
+ * for *legal* UTF-8 will be 4 or fewer bytes total.
+ */
+static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+/* --------------------------------------------------------------------- */
+
+/* The interface converts a whole buffer to avoid function-call overhead.
+ * Constants have been gathered. Loops & conditionals have been removed as
+ * much as possible for efficiency, in favor of drop-through switches.
+ * (See "Note A" at the bottom of the file for equivalent code.)
+ * If your compiler supports it, the "isLegalUTF8" call can be turned
+ * into an inline function.
+ */
+
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF32toUTF16 (
+        const UTF32** sourceStart, const UTF32* sourceEnd,
+        UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
+    ConversionResult result = conversionOK;
+    const UTF32* source = *sourceStart;
+    UTF16* target = *targetStart;
+    while (source < sourceEnd) {
+        UTF32 ch;
+        if (target >= targetEnd) {
+            result = targetExhausted; break;
+        }
+        ch = *source++;
+        if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+            /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
+            if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+                if (flags == strictConversion) {
+                    --source; /* return to the illegal value itself */
+                    result = sourceIllegal;
+                    break;
+                } else {
+                    *target++ = UNI_REPLACEMENT_CHAR;
+                }
+            } else {
+                *target++ = (UTF16)ch; /* normal case */
+            }
+        } else if (ch > UNI_MAX_LEGAL_UTF32) {
+            if (flags == strictConversion) {
+                result = sourceIllegal;
+            } else {
+                *target++ = UNI_REPLACEMENT_CHAR;
+            }
+        } else {
+            /* target is a character in range 0xFFFF - 0x10FFFF. */
+            if (target + 1 >= targetEnd) {
+                --source; /* Back up source pointer! */
+                result = targetExhausted; break;
+            }
+            ch -= halfBase;
+            *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+            *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+        }
+    }
+    *sourceStart = source;
+    *targetStart = target;
+    return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF16toUTF32 (
+        const UTF16** sourceStart, const UTF16* sourceEnd,
+        UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
+    ConversionResult result = conversionOK;
+    const UTF16* source = *sourceStart;
+    UTF32* target = *targetStart;
+    UTF32 ch, ch2;
+    while (source < sourceEnd) {
+        const UTF16* oldSource = source; /*  In case we have to back up because of target overflow. */
+        ch = *source++;
+        /* If we have a surrogate pair, convert to UTF32 first. */
+        if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+            /* If the 16 bits following the high surrogate are in the source buffer... */
+            if (source < sourceEnd) {
+                ch2 = *source;
+                /* If it's a low surrogate, convert to UTF32. */
+                if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+                    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+                        + (ch2 - UNI_SUR_LOW_START) + halfBase;
+                    ++source;
+                } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+                    --source; /* return to the illegal value itself */
+                    result = sourceIllegal;
+                    break;
+                }
+            } else { /* We don't have the 16 bits following the high surrogate. */
+                --source; /* return to the high surrogate */
+                result = sourceExhausted;
+                break;
+            }
+        } else if (flags == strictConversion) {
+            /* UTF-16 surrogate values are illegal in UTF-32 */
+            if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+                --source; /* return to the illegal value itself */
+                result = sourceIllegal;
+                break;
+            }
+        }
+        if (target >= targetEnd) {
+            source = oldSource; /* Back up source pointer! */
+            result = targetExhausted; break;
+        }
+        *target++ = ch;
+    }
+    *sourceStart = source;
+    *targetStart = target;
+#ifdef CVTUTF_DEBUG
+if (result == sourceIllegal) {
+    fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
+    fflush(stderr);
+}
+#endif
+    return result;
+}
+ConversionResult ConvertUTF16toUTF8 (
+        const UTF16** sourceStart, const UTF16* sourceEnd,
+        UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
+    ConversionResult result = conversionOK;
+    const UTF16* source = *sourceStart;
+    UTF8* target = *targetStart;
+    while (source < sourceEnd) {
+        UTF32 ch;
+        unsigned short bytesToWrite = 0;
+        const UTF32 byteMask = 0xBF;
+        const UTF32 byteMark = 0x80;
+        const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
+        ch = *source++;
+        /* If we have a surrogate pair, convert to UTF32 first. */
+        if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+            /* If the 16 bits following the high surrogate are in the source buffer... */
+            if (source < sourceEnd) {
+                UTF32 ch2 = *source;
+                /* If it's a low surrogate, convert to UTF32. */
+                if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+                    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+                        + (ch2 - UNI_SUR_LOW_START) + halfBase;
+                    ++source;
+                } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+                    --source; /* return to the illegal value itself */
+                    result = sourceIllegal;
+                    break;
+                }
+            } else { /* We don't have the 16 bits following the high surrogate. */
+                --source; /* return to the high surrogate */
+                result = sourceExhausted;
+                break;
+            }
+        } else if (flags == strictConversion) {
+            /* UTF-16 surrogate values are illegal in UTF-32 */
+            if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+                --source; /* return to the illegal value itself */
+                result = sourceIllegal;
+                break;
+            }
+        }
+        /* Figure out how many bytes the result will require */
+        if (ch < (UTF32)0x80) {      bytesToWrite = 1;
+        } else if (ch < (UTF32)0x800) {     bytesToWrite = 2;
+        } else if (ch < (UTF32)0x10000) {   bytesToWrite = 3;
+        } else if (ch < (UTF32)0x110000) {  bytesToWrite = 4;
+        } else {                            bytesToWrite = 3;
+                                            ch = UNI_REPLACEMENT_CHAR;
+        }
+
+        target += bytesToWrite;
+        if (target > targetEnd) {
+            source = oldSource; /* Back up source pointer! */
+            target -= bytesToWrite; result = targetExhausted; break;
+        }
+        switch (bytesToWrite) { /* note: everything falls through. */
+            case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+            case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+            case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+            case 1: *--target =  (UTF8)(ch | firstByteMark[bytesToWrite]);
+        }
+        target += bytesToWrite;
+    }
+    *sourceStart = source;
+    *targetStart = target;
+    return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF32toUTF8 (
+        const UTF32** sourceStart, const UTF32* sourceEnd,
+        UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
+    ConversionResult result = conversionOK;
+    const UTF32* source = *sourceStart;
+    UTF8* target = *targetStart;
+    while (source < sourceEnd) {
+        UTF32 ch;
+        unsigned short bytesToWrite = 0;
+        const UTF32 byteMask = 0xBF;
+        const UTF32 byteMark = 0x80;
+        ch = *source++;
+        if (flags == strictConversion ) {
+            /* UTF-16 surrogate values are illegal in UTF-32 */
+            if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+                --source; /* return to the illegal value itself */
+                result = sourceIllegal;
+                break;
+            }
+        }
+        /*
+         * Figure out how many bytes the result will require. Turn any
+         * illegally large UTF32 things (> Plane 17) into replacement chars.
+         */
+        if (ch < (UTF32)0x80) {      bytesToWrite = 1;
+        } else if (ch < (UTF32)0x800) {     bytesToWrite = 2;
+        } else if (ch < (UTF32)0x10000) {   bytesToWrite = 3;
+        } else if (ch <= UNI_MAX_LEGAL_UTF32) {  bytesToWrite = 4;
+        } else {                            bytesToWrite = 3;
+                                            ch = UNI_REPLACEMENT_CHAR;
+                                            result = sourceIllegal;
+        }
+
+        target += bytesToWrite;
+        if (target > targetEnd) {
+            --source; /* Back up source pointer! */
+            target -= bytesToWrite; result = targetExhausted; break;
+        }
+        switch (bytesToWrite) { /* note: everything falls through. */
+            case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+            case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+            case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+            case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
+        }
+        target += bytesToWrite;
+    }
+    *sourceStart = source;
+    *targetStart = target;
+    return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Utility routine to tell whether a sequence of bytes is legal UTF-8.
+ * This must be called with the length pre-determined by the first byte.
+ * If not calling this from ConvertUTF8to*, then the length can be set by:
+ *  length = trailingBytesForUTF8[*source]+1;
+ * and the sequence is illegal right away if there aren't that many bytes
+ * available.
+ * If presented with a length > 4, this returns false.  The Unicode
+ * definition of UTF-8 goes up to 4-byte sequences.
+ */
+
+static Boolean isLegalUTF8(const UTF8 *source, int length) {
+    UTF8 a;
+    const UTF8 *srcptr = source+length;
+    switch (length) {
+    default: return false;
+        /* Everything else falls through when "true"... */
+    case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+    case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+    case 2: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+
+        switch (*source) {
+            /* no fall-through in this inner switch */
+            case 0xE0: if (a < 0xA0) return false; break;
+            case 0xED: if (a > 0x9F) return false; break;
+            case 0xF0: if (a < 0x90) return false; break;
+            case 0xF4: if (a > 0x8F) return false; break;
+            default:   if (a < 0x80) return false;
+        }
+
+    case 1: if (*source >= 0x80 && *source < 0xC2) return false;
+    }
+    if (*source > 0xF4) return false;
+    return true;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Exported function to return whether a UTF-8 sequence is legal or not.
+ * This is not used here; it's just exported.
+ */
+Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
+    int length = trailingBytesForUTF8[*source]+1;
+    if (length > sourceEnd - source) {
+        return false;
+    }
+    return isLegalUTF8(source, length);
+}
+
+/* --------------------------------------------------------------------- */
+
+static unsigned
+findMaximalSubpartOfIllFormedUTF8Sequence(const UTF8 *source,
+                                          const UTF8 *sourceEnd) {
+  UTF8 b1, b2, b3;
+
+  assert(!isLegalUTF8Sequence(source, sourceEnd));
+
+  /*
+   * Unicode 6.3.0, D93b:
+   *
+   *   Maximal subpart of an ill-formed subsequence: The longest code unit
+   *   subsequence starting at an unconvertible offset that is either:
+   *   a. the initial subsequence of a well-formed code unit sequence, or
+   *   b. a subsequence of length one.
+   */
+
+  if (source == sourceEnd)
+    return 0;
+
+  /*
+   * Perform case analysis.  See Unicode 6.3.0, Table 3-7. Well-Formed UTF-8
+   * Byte Sequences.
+   */
+
+  b1 = *source;
+  ++source;
+  if (b1 >= 0xC2 && b1 <= 0xDF) {
+    /*
+     * First byte is valid, but we know that this code unit sequence is
+     * invalid, so the maximal subpart has to end after the first byte.
+     */
+    return 1;
+  }
+
+  if (source == sourceEnd)
+    return 1;
+
+  b2 = *source;
+  ++source;
+
+  if (b1 == 0xE0) {
+    return (b2 >= 0xA0 && b2 <= 0xBF) ? 2 : 1;
+  }
+  if (b1 >= 0xE1 && b1 <= 0xEC) {
+    return (b2 >= 0x80 && b2 <= 0xBF) ? 2 : 1;
+  }
+  if (b1 == 0xED) {
+    return (b2 >= 0x80 && b2 <= 0x9F) ? 2 : 1;
+  }
+  if (b1 >= 0xEE && b1 <= 0xEF) {
+    return (b2 >= 0x80 && b2 <= 0xBF) ? 2 : 1;
+  }
+  if (b1 == 0xF0) {
+    if (b2 >= 0x90 && b2 <= 0xBF) {
+      if (source == sourceEnd)
+        return 2;
+
+      b3 = *source;
+      return (b3 >= 0x80 && b3 <= 0xBF) ? 3 : 2;
+    }
+    return 1;
+  }
+  if (b1 >= 0xF1 && b1 <= 0xF3) {
+    if (b2 >= 0x80 && b2 <= 0xBF) {
+      if (source == sourceEnd)
+        return 2;
+
+      b3 = *source;
+      return (b3 >= 0x80 && b3 <= 0xBF) ? 3 : 2;
+    }
+    return 1;
+  }
+  if (b1 == 0xF4) {
+    if (b2 >= 0x80 && b2 <= 0x8F) {
+      if (source == sourceEnd)
+        return 2;
+
+      b3 = *source;
+      return (b3 >= 0x80 && b3 <= 0xBF) ? 3 : 2;
+    }
+    return 1;
+  }
+
+  assert((b1 >= 0x80 && b1 <= 0xC1) || b1 >= 0xF5);
+  /*
+   * There are no valid sequences that start with these bytes.  Maximal subpart
+   * is defined to have length 1 in these cases.
+   */
+  return 1;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Exported function to return the total number of bytes in a codepoint
+ * represented in UTF-8, given the value of the first byte.
+ */
+unsigned getNumBytesForUTF8(UTF8 first) {
+  return trailingBytesForUTF8[first] + 1;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Exported function to return whether a UTF-8 string is legal or not.
+ * This is not used here; it's just exported.
+ */
+Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd) {
+    while (*source != sourceEnd) {
+        int length = trailingBytesForUTF8[**source] + 1;
+        if (length > sourceEnd - *source || !isLegalUTF8(*source, length))
+            return false;
+        *source += length;
+    }
+    return true;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF8toUTF16 (
+        const UTF8** sourceStart, const UTF8* sourceEnd,
+        UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
+    ConversionResult result = conversionOK;
+    const UTF8* source = *sourceStart;
+    UTF16* target = *targetStart;
+    while (source < sourceEnd) {
+        UTF32 ch = 0;
+        unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+        if (extraBytesToRead >= sourceEnd - source) {
+            result = sourceExhausted; break;
+        }
+        /* Do this check whether lenient or strict */
+        if (!isLegalUTF8(source, extraBytesToRead+1)) {
+            result = sourceIllegal;
+            break;
+        }
+        /*
+         * The cases all fall through. See "Note A" below.
+         */
+        switch (extraBytesToRead) {
+            case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+            case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+            case 3: ch += *source++; ch <<= 6;
+            case 2: ch += *source++; ch <<= 6;
+            case 1: ch += *source++; ch <<= 6;
+            case 0: ch += *source++;
+        }
+        ch -= offsetsFromUTF8[extraBytesToRead];
+
+        if (target >= targetEnd) {
+            source -= (extraBytesToRead+1); /* Back up source pointer! */
+            result = targetExhausted; break;
+        }
+        if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+            /* UTF-16 surrogate values are illegal in UTF-32 */
+            if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+                if (flags == strictConversion) {
+                    source -= (extraBytesToRead+1); /* return to the illegal value itself */
+                    result = sourceIllegal;
+                    break;
+                } else {
+                    *target++ = UNI_REPLACEMENT_CHAR;
+                }
+            } else {
+                *target++ = (UTF16)ch; /* normal case */
+            }
+        } else if (ch > UNI_MAX_UTF16) {
+            if (flags == strictConversion) {
+                result = sourceIllegal;
+                source -= (extraBytesToRead+1); /* return to the start */
+                break; /* Bail out; shouldn't continue */
+            } else {
+                *target++ = UNI_REPLACEMENT_CHAR;
+            }
+        } else {
+            /* target is a character in range 0xFFFF - 0x10FFFF. */
+            if (target + 1 >= targetEnd) {
+                source -= (extraBytesToRead+1); /* Back up source pointer! */
+                result = targetExhausted; break;
+            }
+            ch -= halfBase;
+            *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+            *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+        }
+    }
+    *sourceStart = source;
+    *targetStart = target;
+    return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+static ConversionResult ConvertUTF8toUTF32Impl(
+        const UTF8** sourceStart, const UTF8* sourceEnd,
+        UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags,
+        Boolean InputIsPartial) {
+    ConversionResult result = conversionOK;
+    const UTF8* source = *sourceStart;
+    UTF32* target = *targetStart;
+    while (source < sourceEnd) {
+        UTF32 ch = 0;
+        unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+        if (extraBytesToRead >= sourceEnd - source) {
+            if (flags == strictConversion || InputIsPartial) {
+                result = sourceExhausted;
+                break;
+            } else {
+                result = sourceIllegal;
+
+                /*
+                 * Replace the maximal subpart of ill-formed sequence with
+                 * replacement character.
+                 */
+                source += findMaximalSubpartOfIllFormedUTF8Sequence(source,
+                                                                    sourceEnd);
+                *target++ = UNI_REPLACEMENT_CHAR;
+                continue;
+            }
+        }
+        if (target >= targetEnd) {
+            result = targetExhausted; break;
+        }
+
+        /* Do this check whether lenient or strict */
+        if (!isLegalUTF8(source, extraBytesToRead+1)) {
+            result = sourceIllegal;
+            if (flags == strictConversion) {
+                /* Abort conversion. */
+                break;
+            } else {
+                /*
+                 * Replace the maximal subpart of ill-formed sequence with
+                 * replacement character.
+                 */
+                source += findMaximalSubpartOfIllFormedUTF8Sequence(source,
+                                                                    sourceEnd);
+                *target++ = UNI_REPLACEMENT_CHAR;
+                continue;
+            }
+        }
+        /*
+         * The cases all fall through. See "Note A" below.
+         */
+        switch (extraBytesToRead) {
+            case 5: ch += *source++; ch <<= 6;
+            case 4: ch += *source++; ch <<= 6;
+            case 3: ch += *source++; ch <<= 6;
+            case 2: ch += *source++; ch <<= 6;
+            case 1: ch += *source++; ch <<= 6;
+            case 0: ch += *source++;
+        }
+        ch -= offsetsFromUTF8[extraBytesToRead];
+
+        if (ch <= UNI_MAX_LEGAL_UTF32) {
+            /*
+             * UTF-16 surrogate values are illegal in UTF-32, and anything
+             * over Plane 17 (> 0x10FFFF) is illegal.
+             */
+            if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+                if (flags == strictConversion) {
+                    source -= (extraBytesToRead+1); /* return to the illegal value itself */
+                    result = sourceIllegal;
+                    break;
+                } else {
+                    *target++ = UNI_REPLACEMENT_CHAR;
+                }
+            } else {
+                *target++ = ch;
+            }
+        } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
+            result = sourceIllegal;
+            *target++ = UNI_REPLACEMENT_CHAR;
+        }
+    }
+    *sourceStart = source;
+    *targetStart = target;
+    return result;
+}
+
+ConversionResult ConvertUTF8toUTF32Partial(const UTF8 **sourceStart,
+                                           const UTF8 *sourceEnd,
+                                           UTF32 **targetStart,
+                                           UTF32 *targetEnd,
+                                           ConversionFlags flags) {
+  return ConvertUTF8toUTF32Impl(sourceStart, sourceEnd, targetStart, targetEnd,
+                                flags, /*InputIsPartial=*/true);
+}
+
+ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart,
+                                    const UTF8 *sourceEnd, UTF32 **targetStart,
+                                    UTF32 *targetEnd, ConversionFlags flags) {
+  return ConvertUTF8toUTF32Impl(sourceStart, sourceEnd, targetStart, targetEnd,
+                                flags, /*InputIsPartial=*/false);
+}
+
+/* ---------------------------------------------------------------------
+
+    Note A.
+    The fall-through switches in UTF-8 reading code save a
+    temp variable, some decrements & conditionals.  The switches
+    are equivalent to the following loop:
+        {
+            int tmpBytesToRead = extraBytesToRead+1;
+            do {
+                ch += *source++;
+                --tmpBytesToRead;
+                if (tmpBytesToRead) ch <<= 6;
+            } while (tmpBytesToRead > 0);
+        }
+    In UTF-8 writing code, the switches on "bytesToWrite" are
+    similarly unrolled loops.
+
+   --------------------------------------------------------------------- */
+
+} // namespace llvm
+
+ConvertUTF_RESTORE_WARNINGS
diff --git a/binaryen/third_party/llvm-project/DJB.cpp b/binaryen/third_party/llvm-project/DJB.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DJB.cpp
@@ -0,0 +1,82 @@
+//===-- Support/DJB.cpp ---DJB Hash -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains support for the DJ Bernstein hash function.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/DJB.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Unicode.h"
+
+using namespace llvm;
+
+static UTF32 chopOneUTF32(StringRef &Buffer) {
+  UTF32 C;
+  const UTF8 *const Begin8Const =
+      reinterpret_cast<const UTF8 *>(Buffer.begin());
+  const UTF8 *Begin8 = Begin8Const;
+  UTF32 *Begin32 = &C;
+
+  // In lenient mode we will always end up with a "reasonable" value in C for
+  // non-empty input.
+  assert(!Buffer.empty());
+  ConvertUTF8toUTF32(&Begin8, reinterpret_cast<const UTF8 *>(Buffer.end()),
+                     &Begin32, &C + 1, lenientConversion);
+  Buffer = Buffer.drop_front(Begin8 - Begin8Const);
+  return C;
+}
+
+static StringRef toUTF8(UTF32 C, MutableArrayRef<UTF8> Storage) {
+  const UTF32 *Begin32 = &C;
+  UTF8 *Begin8 = Storage.begin();
+
+  // The case-folded output should always be a valid unicode character, so use
+  // strict mode here.
+  ConversionResult CR = ConvertUTF32toUTF8(&Begin32, &C + 1, &Begin8,
+                                           Storage.end(), strictConversion);
+  assert(CR == conversionOK && "Case folding produced invalid char?");
+  (void)CR;
+  return StringRef(reinterpret_cast<char *>(Storage.begin()),
+                   Begin8 - Storage.begin());
+}
+
+static UTF32 foldCharDwarf(UTF32 C) {
+  // DWARF v5 addition to the unicode folding rules.
+  // Fold "Latin Small Letter Dotless I" and "Latin Capital Letter I With Dot
+  // Above" into "i".
+  if (C == 0x130 || C == 0x131)
+    return 'i';
+  return sys::unicode::foldCharSimple(C);
+}
+
+static Optional<uint32_t> fastCaseFoldingDjbHash(StringRef Buffer, uint32_t H) {
+  bool AllASCII = true;
+  for (unsigned char C : Buffer) {
+    H = H * 33 + ('A' <= C && C <= 'Z' ? C - 'A' + 'a' : C);
+    AllASCII &= C <= 0x7f;
+  }
+  if (AllASCII)
+    return H;
+  return None;
+}
+
+uint32_t llvm::caseFoldingDjbHash(StringRef Buffer, uint32_t H) {
+  if (Optional<uint32_t> Result = fastCaseFoldingDjbHash(Buffer, H))
+    return *Result;
+
+  std::array<UTF8, UNI_MAX_UTF8_BYTES_PER_CODE_POINT> Storage;
+  while (!Buffer.empty()) {
+    UTF32 C = foldCharDwarf(chopOneUTF32(Buffer));
+    StringRef Folded = toUTF8(C, Storage);
+    H = djbHash(Folded, H);
+  }
+  return H;
+}
diff --git a/binaryen/third_party/llvm-project/DWARFAbbreviationDeclaration.cpp b/binaryen/third_party/llvm-project/DWARFAbbreviationDeclaration.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFAbbreviationDeclaration.cpp
@@ -0,0 +1,215 @@
+//===- DWARFAbbreviationDeclaration.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
+
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstddef>
+#include <cstdint>
+
+using namespace llvm;
+using namespace dwarf;
+
+void DWARFAbbreviationDeclaration::clear() {
+  Code = 0;
+  Tag = DW_TAG_null;
+  CodeByteSize = 0;
+  HasChildren = false;
+  AttributeSpecs.clear();
+  FixedAttributeSize.reset();
+}
+
+DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() {
+  clear();
+}
+
+bool
+DWARFAbbreviationDeclaration::extract(DataExtractor Data,
+                                      uint64_t* OffsetPtr) {
+  clear();
+  const uint64_t Offset = *OffsetPtr;
+  Code = Data.getULEB128(OffsetPtr);
+  if (Code == 0) {
+    return false;
+  }
+  CodeByteSize = *OffsetPtr - Offset;
+  Tag = static_cast<llvm::dwarf::Tag>(Data.getULEB128(OffsetPtr));
+  if (Tag == DW_TAG_null) {
+    clear();
+    return false;
+  }
+  uint8_t ChildrenByte = Data.getU8(OffsetPtr);
+  HasChildren = (ChildrenByte == DW_CHILDREN_yes);
+  // Assign a value to our optional FixedAttributeSize member variable. If
+  // this member variable still has a value after the while loop below, then
+  // all attribute data in this abbreviation declaration has a fixed byte size.
+  FixedAttributeSize = FixedSizeInfo();
+
+  // Read all of the abbreviation attributes and forms.
+  while (true) {
+    auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr));
+    auto F = static_cast<Form>(Data.getULEB128(OffsetPtr));
+    if (A && F) {
+      bool IsImplicitConst = (F == DW_FORM_implicit_const);
+      if (IsImplicitConst) {
+        int64_t V = Data.getSLEB128(OffsetPtr);
+        AttributeSpecs.push_back(AttributeSpec(A, F, V));
+        continue;
+      }
+      Optional<uint8_t> ByteSize;
+      // If this abbrevation still has a fixed byte size, then update the
+      // FixedAttributeSize as needed.
+      switch (F) {
+      case DW_FORM_addr:
+        if (FixedAttributeSize)
+          ++FixedAttributeSize->NumAddrs;
+        break;
+
+      case DW_FORM_ref_addr:
+        if (FixedAttributeSize)
+          ++FixedAttributeSize->NumRefAddrs;
+        break;
+
+      case DW_FORM_strp:
+      case DW_FORM_GNU_ref_alt:
+      case DW_FORM_GNU_strp_alt:
+      case DW_FORM_line_strp:
+      case DW_FORM_sec_offset:
+      case DW_FORM_strp_sup:
+        if (FixedAttributeSize)
+          ++FixedAttributeSize->NumDwarfOffsets;
+        break;
+
+      default:
+        // The form has a byte size that doesn't depend on Params.
+        // If it's a fixed size, keep track of it.
+        if ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) {
+          if (FixedAttributeSize)
+            FixedAttributeSize->NumBytes += *ByteSize;
+          break;
+        }
+        // Indicate we no longer have a fixed byte size for this
+        // abbreviation by clearing the FixedAttributeSize optional value
+        // so it doesn't have a value.
+        FixedAttributeSize.reset();
+        break;
+      }
+      // Record this attribute and its fixed size if it has one.
+      AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize));
+    } else if (A == 0 && F == 0) {
+      // We successfully reached the end of this abbreviation declaration
+      // since both attribute and form are zero.
+      break;
+    } else {
+      // Attribute and form pairs must either both be non-zero, in which case
+      // they are added to the abbreviation declaration, or both be zero to
+      // terminate the abbrevation declaration. In this case only one was
+      // zero which is an error.
+      clear();
+      return false;
+    }
+  }
+  return true;
+}
+
+void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const {
+  OS << '[' << getCode() << "] ";
+  OS << formatv("{0}", getTag());
+  OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n';
+  for (const AttributeSpec &Spec : AttributeSpecs) {
+    OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form);
+    if (Spec.isImplicitConst())
+      OS << '\t' << Spec.getImplicitConstValue();
+    OS << '\n';
+  }
+  OS << '\n';
+}
+
+Optional<uint32_t>
+DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const {
+  for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) {
+    if (AttributeSpecs[i].Attr == Attr)
+      return i;
+  }
+  return None;
+}
+
+Optional<DWARFFormValue> DWARFAbbreviationDeclaration::getAttributeValue(
+    const uint64_t DIEOffset, const dwarf::Attribute Attr,
+    const DWARFUnit &U) const {
+  Optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr);
+  if (!MatchAttrIndex)
+    return None;
+
+  auto DebugInfoData = U.getDebugInfoExtractor();
+
+  // Add the byte size of ULEB that for the abbrev Code so we can start
+  // skipping the attribute data.
+  uint64_t Offset = DIEOffset + CodeByteSize;
+  uint32_t AttrIndex = 0;
+  for (const auto &Spec : AttributeSpecs) {
+    if (*MatchAttrIndex == AttrIndex) {
+      // We have arrived at the attribute to extract, extract if from Offset.
+      if (Spec.isImplicitConst())
+        return DWARFFormValue::createFromSValue(Spec.Form,
+                                                Spec.getImplicitConstValue());
+
+      DWARFFormValue FormValue(Spec.Form);
+      if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U))
+        return FormValue;
+    }
+    // March Offset along until we get to the attribute we want.
+    if (auto FixedSize = Spec.getByteSize(U))
+      Offset += *FixedSize;
+    else
+      DWARFFormValue::skipValue(Spec.Form, DebugInfoData, &Offset,
+                                U.getFormParams());
+    ++AttrIndex;
+  }
+  return None;
+}
+
+size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize(
+    const DWARFUnit &U) const {
+  size_t ByteSize = NumBytes;
+  if (NumAddrs)
+    ByteSize += NumAddrs * U.getAddressByteSize();
+  if (NumRefAddrs)
+    ByteSize += NumRefAddrs * U.getRefAddrByteSize();
+  if (NumDwarfOffsets)
+    ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize();
+  return ByteSize;
+}
+
+Optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize(
+    const DWARFUnit &U) const {
+  if (isImplicitConst())
+    return 0;
+  if (ByteSize.HasByteSize)
+    return ByteSize.ByteSize;
+  Optional<int64_t> S;
+  auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams());
+  if (FixedByteSize)
+    S = *FixedByteSize;
+  return S;
+}
+
+Optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize(
+    const DWARFUnit &U) const {
+  if (FixedAttributeSize)
+    return FixedAttributeSize->getByteSize(U);
+  return None;
+}
diff --git a/binaryen/third_party/llvm-project/DWARFAcceleratorTable.cpp b/binaryen/third_party/llvm-project/DWARFAcceleratorTable.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFAcceleratorTable.cpp
@@ -0,0 +1,889 @@
+//===- DWARFAcceleratorTable.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DJB.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstddef>
+#include <cstdint>
+#include <utility>
+
+using namespace llvm;
+
+namespace {
+struct Atom {
+  unsigned Value;
+};
+
+static raw_ostream &operator<<(raw_ostream &OS, const Atom &A) {
+  StringRef Str = dwarf::AtomTypeString(A.Value);
+  if (!Str.empty())
+    return OS << Str;
+  return OS << "DW_ATOM_unknown_" << format("%x", A.Value);
+}
+} // namespace
+
+static Atom formatAtom(unsigned Atom) { return {Atom}; }
+
+DWARFAcceleratorTable::~DWARFAcceleratorTable() = default;
+
+Error AppleAcceleratorTable::extract() {
+  uint64_t Offset = 0;
+
+  // Check that we can at least read the header.
+  if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength) + 4))
+    return createStringError(errc::illegal_byte_sequence,
+                             "Section too small: cannot read header.");
+
+  Hdr.Magic = AccelSection.getU32(&Offset);
+  Hdr.Version = AccelSection.getU16(&Offset);
+  Hdr.HashFunction = AccelSection.getU16(&Offset);
+  Hdr.BucketCount = AccelSection.getU32(&Offset);
+  Hdr.HashCount = AccelSection.getU32(&Offset);
+  Hdr.HeaderDataLength = AccelSection.getU32(&Offset);
+
+  // Check that we can read all the hashes and offsets from the
+  // section (see SourceLevelDebugging.rst for the structure of the index).
+  // We need to substract one because we're checking for an *offset* which is
+  // equal to the size for an empty table and hence pointer after the section.
+  if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength +
+                                  Hdr.BucketCount * 4 + Hdr.HashCount * 8 - 1))
+    return createStringError(
+        errc::illegal_byte_sequence,
+        "Section too small: cannot read buckets and hashes.");
+
+  HdrData.DIEOffsetBase = AccelSection.getU32(&Offset);
+  uint32_t NumAtoms = AccelSection.getU32(&Offset);
+
+  for (unsigned i = 0; i < NumAtoms; ++i) {
+    uint16_t AtomType = AccelSection.getU16(&Offset);
+    auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset));
+    HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm));
+  }
+
+  IsValid = true;
+  return Error::success();
+}
+
+uint32_t AppleAcceleratorTable::getNumBuckets() { return Hdr.BucketCount; }
+uint32_t AppleAcceleratorTable::getNumHashes() { return Hdr.HashCount; }
+uint32_t AppleAcceleratorTable::getSizeHdr() { return sizeof(Hdr); }
+uint32_t AppleAcceleratorTable::getHeaderDataLength() {
+  return Hdr.HeaderDataLength;
+}
+
+ArrayRef<std::pair<AppleAcceleratorTable::HeaderData::AtomType,
+                   AppleAcceleratorTable::HeaderData::Form>>
+AppleAcceleratorTable::getAtomsDesc() {
+  return HdrData.Atoms;
+}
+
+bool AppleAcceleratorTable::validateForms() {
+  for (auto Atom : getAtomsDesc()) {
+    DWARFFormValue FormValue(Atom.second);
+    switch (Atom.first) {
+    case dwarf::DW_ATOM_die_offset:
+    case dwarf::DW_ATOM_die_tag:
+    case dwarf::DW_ATOM_type_flags:
+      if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) &&
+           !FormValue.isFormClass(DWARFFormValue::FC_Flag)) ||
+          FormValue.getForm() == dwarf::DW_FORM_sdata)
+        return false;
+      break;
+    default:
+      break;
+    }
+  }
+  return true;
+}
+
+std::pair<uint64_t, dwarf::Tag>
+AppleAcceleratorTable::readAtoms(uint64_t *HashDataOffset) {
+  uint64_t DieOffset = dwarf::DW_INVALID_OFFSET;
+  dwarf::Tag DieTag = dwarf::DW_TAG_null;
+  dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
+
+  for (auto Atom : getAtomsDesc()) {
+    DWARFFormValue FormValue(Atom.second);
+    FormValue.extractValue(AccelSection, HashDataOffset, FormParams);
+    switch (Atom.first) {
+    case dwarf::DW_ATOM_die_offset:
+      DieOffset = *FormValue.getAsUnsignedConstant();
+      break;
+    case dwarf::DW_ATOM_die_tag:
+      DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant();
+      break;
+    default:
+      break;
+    }
+  }
+  return {DieOffset, DieTag};
+}
+
+void AppleAcceleratorTable::Header::dump(ScopedPrinter &W) const {
+  DictScope HeaderScope(W, "Header");
+  W.printHex("Magic", Magic);
+  W.printHex("Version", Version);
+  W.printHex("Hash function", HashFunction);
+  W.printNumber("Bucket count", BucketCount);
+  W.printNumber("Hashes count", HashCount);
+  W.printNumber("HeaderData length", HeaderDataLength);
+}
+
+Optional<uint64_t> AppleAcceleratorTable::HeaderData::extractOffset(
+    Optional<DWARFFormValue> Value) const {
+  if (!Value)
+    return None;
+
+  switch (Value->getForm()) {
+  case dwarf::DW_FORM_ref1:
+  case dwarf::DW_FORM_ref2:
+  case dwarf::DW_FORM_ref4:
+  case dwarf::DW_FORM_ref8:
+  case dwarf::DW_FORM_ref_udata:
+    return Value->getRawUValue() + DIEOffsetBase;
+  default:
+    return Value->getAsSectionOffset();
+  }
+}
+
+bool AppleAcceleratorTable::dumpName(ScopedPrinter &W,
+                                     SmallVectorImpl<DWARFFormValue> &AtomForms,
+                                     uint64_t *DataOffset) const {
+  dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
+  uint64_t NameOffset = *DataOffset;
+  if (!AccelSection.isValidOffsetForDataOfSize(*DataOffset, 4)) {
+    W.printString("Incorrectly terminated list.");
+    return false;
+  }
+  uint64_t StringOffset = AccelSection.getRelocatedValue(4, DataOffset);
+  if (!StringOffset)
+    return false; // End of list
+
+  DictScope NameScope(W, ("Name@0x" + Twine::utohexstr(NameOffset)).str());
+  W.startLine() << format("String: 0x%08" PRIx64, StringOffset);
+  W.getOStream() << " \"" << StringSection.getCStr(&StringOffset) << "\"\n";
+
+  unsigned NumData = AccelSection.getU32(DataOffset);
+  for (unsigned Data = 0; Data < NumData; ++Data) {
+    ListScope DataScope(W, ("Data " + Twine(Data)).str());
+    unsigned i = 0;
+    for (auto &Atom : AtomForms) {
+      W.startLine() << format("Atom[%d]: ", i);
+      if (Atom.extractValue(AccelSection, DataOffset, FormParams)) {
+        Atom.dump(W.getOStream());
+        if (Optional<uint64_t> Val = Atom.getAsUnsignedConstant()) {
+          StringRef Str = dwarf::AtomValueString(HdrData.Atoms[i].first, *Val);
+          if (!Str.empty())
+            W.getOStream() << " (" << Str << ")";
+        }
+      } else
+        W.getOStream() << "Error extracting the value";
+      W.getOStream() << "\n";
+      i++;
+    }
+  }
+  return true; // more entries follow
+}
+
+LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const {
+  if (!IsValid)
+    return;
+
+  ScopedPrinter W(OS);
+
+  Hdr.dump(W);
+
+  W.printNumber("DIE offset base", HdrData.DIEOffsetBase);
+  W.printNumber("Number of atoms", uint64_t(HdrData.Atoms.size()));
+  SmallVector<DWARFFormValue, 3> AtomForms;
+  {
+    ListScope AtomsScope(W, "Atoms");
+    unsigned i = 0;
+    for (const auto &Atom : HdrData.Atoms) {
+      DictScope AtomScope(W, ("Atom " + Twine(i++)).str());
+      W.startLine() << "Type: " << formatAtom(Atom.first) << '\n';
+      W.startLine() << "Form: " << formatv("{0}", Atom.second) << '\n';
+      AtomForms.push_back(DWARFFormValue(Atom.second));
+    }
+  }
+
+  // Now go through the actual tables and dump them.
+  uint64_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength;
+  uint64_t HashesBase = Offset + Hdr.BucketCount * 4;
+  uint64_t OffsetsBase = HashesBase + Hdr.HashCount * 4;
+
+  for (unsigned Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket) {
+    unsigned Index = AccelSection.getU32(&Offset);
+
+    ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str());
+    if (Index == UINT32_MAX) {
+      W.printString("EMPTY");
+      continue;
+    }
+
+    for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) {
+      uint64_t HashOffset = HashesBase + HashIdx*4;
+      uint64_t OffsetsOffset = OffsetsBase + HashIdx*4;
+      uint32_t Hash = AccelSection.getU32(&HashOffset);
+
+      if (Hash % Hdr.BucketCount != Bucket)
+        break;
+
+      uint64_t DataOffset = AccelSection.getU32(&OffsetsOffset);
+      ListScope HashScope(W, ("Hash 0x" + Twine::utohexstr(Hash)).str());
+      if (!AccelSection.isValidOffset(DataOffset)) {
+        W.printString("Invalid section offset");
+        continue;
+      }
+      while (dumpName(W, AtomForms, &DataOffset))
+        /*empty*/;
+    }
+  }
+}
+
+AppleAcceleratorTable::Entry::Entry(
+    const AppleAcceleratorTable::HeaderData &HdrData)
+    : HdrData(&HdrData) {
+  Values.reserve(HdrData.Atoms.size());
+  for (const auto &Atom : HdrData.Atoms)
+    Values.push_back(DWARFFormValue(Atom.second));
+}
+
+void AppleAcceleratorTable::Entry::extract(
+    const AppleAcceleratorTable &AccelTable, uint64_t *Offset) {
+
+  dwarf::FormParams FormParams = {AccelTable.Hdr.Version, 0,
+                                  dwarf::DwarfFormat::DWARF32};
+  for (auto &Atom : Values)
+    Atom.extractValue(AccelTable.AccelSection, Offset, FormParams);
+}
+
+Optional<DWARFFormValue>
+AppleAcceleratorTable::Entry::lookup(HeaderData::AtomType Atom) const {
+  assert(HdrData && "Dereferencing end iterator?");
+  assert(HdrData->Atoms.size() == Values.size());
+  for (const auto &Tuple : zip_first(HdrData->Atoms, Values)) {
+    if (std::get<0>(Tuple).first == Atom)
+      return std::get<1>(Tuple);
+  }
+  return None;
+}
+
+Optional<uint64_t> AppleAcceleratorTable::Entry::getDIESectionOffset() const {
+  return HdrData->extractOffset(lookup(dwarf::DW_ATOM_die_offset));
+}
+
+Optional<uint64_t> AppleAcceleratorTable::Entry::getCUOffset() const {
+  return HdrData->extractOffset(lookup(dwarf::DW_ATOM_cu_offset));
+}
+
+Optional<dwarf::Tag> AppleAcceleratorTable::Entry::getTag() const {
+  Optional<DWARFFormValue> Tag = lookup(dwarf::DW_ATOM_die_tag);
+  if (!Tag)
+    return None;
+  if (Optional<uint64_t> Value = Tag->getAsUnsignedConstant())
+    return dwarf::Tag(*Value);
+  return None;
+}
+
+AppleAcceleratorTable::ValueIterator::ValueIterator(
+    const AppleAcceleratorTable &AccelTable, uint64_t Offset)
+    : AccelTable(&AccelTable), Current(AccelTable.HdrData), DataOffset(Offset) {
+  if (!AccelTable.AccelSection.isValidOffsetForDataOfSize(DataOffset, 4))
+    return;
+
+  // Read the first entry.
+  NumData = AccelTable.AccelSection.getU32(&DataOffset);
+  Next();
+}
+
+void AppleAcceleratorTable::ValueIterator::Next() {
+  assert(NumData > 0 && "attempted to increment iterator past the end");
+  auto &AccelSection = AccelTable->AccelSection;
+  if (Data >= NumData ||
+      !AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
+    NumData = 0;
+    DataOffset = 0;
+    return;
+  }
+  Current.extract(*AccelTable, &DataOffset);
+  ++Data;
+}
+
+iterator_range<AppleAcceleratorTable::ValueIterator>
+AppleAcceleratorTable::equal_range(StringRef Key) const {
+  if (!IsValid)
+    return make_range(ValueIterator(), ValueIterator());
+
+  // Find the bucket.
+  unsigned HashValue = djbHash(Key);
+  unsigned Bucket = HashValue % Hdr.BucketCount;
+  uint64_t BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength;
+  uint64_t HashesBase = BucketBase + Hdr.BucketCount * 4;
+  uint64_t OffsetsBase = HashesBase + Hdr.HashCount * 4;
+
+  uint64_t BucketOffset = BucketBase + Bucket * 4;
+  unsigned Index = AccelSection.getU32(&BucketOffset);
+
+  // Search through all hashes in the bucket.
+  for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) {
+    uint64_t HashOffset = HashesBase + HashIdx * 4;
+    uint64_t OffsetsOffset = OffsetsBase + HashIdx * 4;
+    uint32_t Hash = AccelSection.getU32(&HashOffset);
+
+    if (Hash % Hdr.BucketCount != Bucket)
+      // We are already in the next bucket.
+      break;
+
+    uint64_t DataOffset = AccelSection.getU32(&OffsetsOffset);
+    uint64_t StringOffset = AccelSection.getRelocatedValue(4, &DataOffset);
+    if (!StringOffset)
+      break;
+
+    // Finally, compare the key.
+    if (Key == StringSection.getCStr(&StringOffset))
+      return make_range({*this, DataOffset}, ValueIterator());
+  }
+  return make_range(ValueIterator(), ValueIterator());
+}
+
+void DWARFDebugNames::Header::dump(ScopedPrinter &W) const {
+  DictScope HeaderScope(W, "Header");
+  W.printHex("Length", UnitLength);
+  W.printNumber("Version", Version);
+  W.printHex("Padding", Padding);
+  W.printNumber("CU count", CompUnitCount);
+  W.printNumber("Local TU count", LocalTypeUnitCount);
+  W.printNumber("Foreign TU count", ForeignTypeUnitCount);
+  W.printNumber("Bucket count", BucketCount);
+  W.printNumber("Name count", NameCount);
+  W.printHex("Abbreviations table size", AbbrevTableSize);
+  W.startLine() << "Augmentation: '" << AugmentationString << "'\n";
+}
+
+Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS,
+                                             uint64_t *Offset) {
+  // Check that we can read the fixed-size part.
+  if (!AS.isValidOffset(*Offset + sizeof(HeaderPOD) - 1))
+    return createStringError(errc::illegal_byte_sequence,
+                             "Section too small: cannot read header.");
+
+  UnitLength = AS.getU32(Offset);
+  Version = AS.getU16(Offset);
+  Padding = AS.getU16(Offset);
+  CompUnitCount = AS.getU32(Offset);
+  LocalTypeUnitCount = AS.getU32(Offset);
+  ForeignTypeUnitCount = AS.getU32(Offset);
+  BucketCount = AS.getU32(Offset);
+  NameCount = AS.getU32(Offset);
+  AbbrevTableSize = AS.getU32(Offset);
+  AugmentationStringSize = alignTo(AS.getU32(Offset), 4);
+
+  if (!AS.isValidOffsetForDataOfSize(*Offset, AugmentationStringSize))
+    return createStringError(
+        errc::illegal_byte_sequence,
+        "Section too small: cannot read header augmentation.");
+  AugmentationString.resize(AugmentationStringSize);
+  AS.getU8(Offset, reinterpret_cast<uint8_t *>(AugmentationString.data()),
+           AugmentationStringSize);
+  return Error::success();
+}
+
+void DWARFDebugNames::Abbrev::dump(ScopedPrinter &W) const {
+  DictScope AbbrevScope(W, ("Abbreviation 0x" + Twine::utohexstr(Code)).str());
+  W.startLine() << formatv("Tag: {0}\n", Tag);
+
+  for (const auto &Attr : Attributes)
+    W.startLine() << formatv("{0}: {1}\n", Attr.Index, Attr.Form);
+}
+
+static constexpr DWARFDebugNames::AttributeEncoding sentinelAttrEnc() {
+  return {dwarf::Index(0), dwarf::Form(0)};
+}
+
+static bool isSentinel(const DWARFDebugNames::AttributeEncoding &AE) {
+  return AE == sentinelAttrEnc();
+}
+
+static DWARFDebugNames::Abbrev sentinelAbbrev() {
+  return DWARFDebugNames::Abbrev(0, dwarf::Tag(0), {});
+}
+
+static bool isSentinel(const DWARFDebugNames::Abbrev &Abbr) {
+  return Abbr.Code == 0;
+}
+
+DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getEmptyKey() {
+  return sentinelAbbrev();
+}
+
+DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getTombstoneKey() {
+  return DWARFDebugNames::Abbrev(~0, dwarf::Tag(0), {});
+}
+
+Expected<DWARFDebugNames::AttributeEncoding>
+DWARFDebugNames::NameIndex::extractAttributeEncoding(uint64_t *Offset) {
+  if (*Offset >= EntriesBase) {
+    return createStringError(errc::illegal_byte_sequence,
+                             "Incorrectly terminated abbreviation table.");
+  }
+
+  uint32_t Index = Section.AccelSection.getULEB128(Offset);
+  uint32_t Form = Section.AccelSection.getULEB128(Offset);
+  return AttributeEncoding(dwarf::Index(Index), dwarf::Form(Form));
+}
+
+Expected<std::vector<DWARFDebugNames::AttributeEncoding>>
+DWARFDebugNames::NameIndex::extractAttributeEncodings(uint64_t *Offset) {
+  std::vector<AttributeEncoding> Result;
+  for (;;) {
+    auto AttrEncOr = extractAttributeEncoding(Offset);
+    if (!AttrEncOr)
+      return AttrEncOr.takeError();
+    if (isSentinel(*AttrEncOr))
+      return std::move(Result);
+
+    Result.emplace_back(*AttrEncOr);
+  }
+}
+
+Expected<DWARFDebugNames::Abbrev>
+DWARFDebugNames::NameIndex::extractAbbrev(uint64_t *Offset) {
+  if (*Offset >= EntriesBase) {
+    return createStringError(errc::illegal_byte_sequence,
+                             "Incorrectly terminated abbreviation table.");
+  }
+
+  uint32_t Code = Section.AccelSection.getULEB128(Offset);
+  if (Code == 0)
+    return sentinelAbbrev();
+
+  uint32_t Tag = Section.AccelSection.getULEB128(Offset);
+  auto AttrEncOr = extractAttributeEncodings(Offset);
+  if (!AttrEncOr)
+    return AttrEncOr.takeError();
+  return Abbrev(Code, dwarf::Tag(Tag), std::move(*AttrEncOr));
+}
+
+Error DWARFDebugNames::NameIndex::extract() {
+  const DWARFDataExtractor &AS = Section.AccelSection;
+  uint64_t Offset = Base;
+  if (Error E = Hdr.extract(AS, &Offset))
+    return E;
+
+  CUsBase = Offset;
+  Offset += Hdr.CompUnitCount * 4;
+  Offset += Hdr.LocalTypeUnitCount * 4;
+  Offset += Hdr.ForeignTypeUnitCount * 8;
+  BucketsBase = Offset;
+  Offset += Hdr.BucketCount * 4;
+  HashesBase = Offset;
+  if (Hdr.BucketCount > 0)
+    Offset += Hdr.NameCount * 4;
+  StringOffsetsBase = Offset;
+  Offset += Hdr.NameCount * 4;
+  EntryOffsetsBase = Offset;
+  Offset += Hdr.NameCount * 4;
+
+  if (!AS.isValidOffsetForDataOfSize(Offset, Hdr.AbbrevTableSize))
+    return createStringError(errc::illegal_byte_sequence,
+                             "Section too small: cannot read abbreviations.");
+
+  EntriesBase = Offset + Hdr.AbbrevTableSize;
+
+  for (;;) {
+    auto AbbrevOr = extractAbbrev(&Offset);
+    if (!AbbrevOr)
+      return AbbrevOr.takeError();
+    if (isSentinel(*AbbrevOr))
+      return Error::success();
+
+    if (!Abbrevs.insert(std::move(*AbbrevOr)).second)
+      return createStringError(errc::invalid_argument,
+                               "Duplicate abbreviation code.");
+  }
+}
+
+DWARFDebugNames::Entry::Entry(const NameIndex &NameIdx, const Abbrev &Abbr)
+    : NameIdx(&NameIdx), Abbr(&Abbr) {
+  // This merely creates form values. It is up to the caller
+  // (NameIndex::getEntry) to populate them.
+  Values.reserve(Abbr.Attributes.size());
+  for (const auto &Attr : Abbr.Attributes)
+    Values.emplace_back(Attr.Form);
+}
+
+Optional<DWARFFormValue>
+DWARFDebugNames::Entry::lookup(dwarf::Index Index) const {
+  assert(Abbr->Attributes.size() == Values.size());
+  for (const auto &Tuple : zip_first(Abbr->Attributes, Values)) {
+    if (std::get<0>(Tuple).Index == Index)
+      return std::get<1>(Tuple);
+  }
+  return None;
+}
+
+Optional<uint64_t> DWARFDebugNames::Entry::getDIEUnitOffset() const {
+  if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_die_offset))
+    return Off->getAsReferenceUVal();
+  return None;
+}
+
+Optional<uint64_t> DWARFDebugNames::Entry::getCUIndex() const {
+  if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit))
+    return Off->getAsUnsignedConstant();
+  // In a per-CU index, the entries without a DW_IDX_compile_unit attribute
+  // implicitly refer to the single CU.
+  if (NameIdx->getCUCount() == 1)
+    return 0;
+  return None;
+}
+
+Optional<uint64_t> DWARFDebugNames::Entry::getCUOffset() const {
+  Optional<uint64_t> Index = getCUIndex();
+  if (!Index || *Index >= NameIdx->getCUCount())
+    return None;
+  return NameIdx->getCUOffset(*Index);
+}
+
+void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const {
+  W.printHex("Abbrev", Abbr->Code);
+  W.startLine() << formatv("Tag: {0}\n", Abbr->Tag);
+  assert(Abbr->Attributes.size() == Values.size());
+  for (const auto &Tuple : zip_first(Abbr->Attributes, Values)) {
+    W.startLine() << formatv("{0}: ", std::get<0>(Tuple).Index);
+    std::get<1>(Tuple).dump(W.getOStream());
+    W.getOStream() << '\n';
+  }
+}
+
+char DWARFDebugNames::SentinelError::ID;
+std::error_code DWARFDebugNames::SentinelError::convertToErrorCode() const {
+  return inconvertibleErrorCode();
+}
+
+uint64_t DWARFDebugNames::NameIndex::getCUOffset(uint32_t CU) const {
+  assert(CU < Hdr.CompUnitCount);
+  uint64_t Offset = CUsBase + 4 * CU;
+  return Section.AccelSection.getRelocatedValue(4, &Offset);
+}
+
+uint64_t DWARFDebugNames::NameIndex::getLocalTUOffset(uint32_t TU) const {
+  assert(TU < Hdr.LocalTypeUnitCount);
+  uint64_t Offset = CUsBase + 4 * (Hdr.CompUnitCount + TU);
+  return Section.AccelSection.getRelocatedValue(4, &Offset);
+}
+
+uint64_t DWARFDebugNames::NameIndex::getForeignTUSignature(uint32_t TU) const {
+  assert(TU < Hdr.ForeignTypeUnitCount);
+  uint64_t Offset =
+      CUsBase + 4 * (Hdr.CompUnitCount + Hdr.LocalTypeUnitCount) + 8 * TU;
+  return Section.AccelSection.getU64(&Offset);
+}
+
+Expected<DWARFDebugNames::Entry>
+DWARFDebugNames::NameIndex::getEntry(uint64_t *Offset) const {
+  const DWARFDataExtractor &AS = Section.AccelSection;
+  if (!AS.isValidOffset(*Offset))
+    return createStringError(errc::illegal_byte_sequence,
+                             "Incorrectly terminated entry list.");
+
+  uint32_t AbbrevCode = AS.getULEB128(Offset);
+  if (AbbrevCode == 0)
+    return make_error<SentinelError>();
+
+  const auto AbbrevIt = Abbrevs.find_as(AbbrevCode);
+  if (AbbrevIt == Abbrevs.end())
+    return createStringError(errc::invalid_argument, "Invalid abbreviation.");
+
+  Entry E(*this, *AbbrevIt);
+
+  dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
+  for (auto &Value : E.Values) {
+    if (!Value.extractValue(AS, Offset, FormParams))
+      return createStringError(errc::io_error,
+                               "Error extracting index attribute values.");
+  }
+  return std::move(E);
+}
+
+DWARFDebugNames::NameTableEntry
+DWARFDebugNames::NameIndex::getNameTableEntry(uint32_t Index) const {
+  assert(0 < Index && Index <= Hdr.NameCount);
+  uint64_t StringOffsetOffset = StringOffsetsBase + 4 * (Index - 1);
+  uint64_t EntryOffsetOffset = EntryOffsetsBase + 4 * (Index - 1);
+  const DWARFDataExtractor &AS = Section.AccelSection;
+
+  uint64_t StringOffset = AS.getRelocatedValue(4, &StringOffsetOffset);
+  uint64_t EntryOffset = AS.getU32(&EntryOffsetOffset);
+  EntryOffset += EntriesBase;
+  return {Section.StringSection, Index, StringOffset, EntryOffset};
+}
+
+uint32_t
+DWARFDebugNames::NameIndex::getBucketArrayEntry(uint32_t Bucket) const {
+  assert(Bucket < Hdr.BucketCount);
+  uint64_t BucketOffset = BucketsBase + 4 * Bucket;
+  return Section.AccelSection.getU32(&BucketOffset);
+}
+
+uint32_t DWARFDebugNames::NameIndex::getHashArrayEntry(uint32_t Index) const {
+  assert(0 < Index && Index <= Hdr.NameCount);
+  uint64_t HashOffset = HashesBase + 4 * (Index - 1);
+  return Section.AccelSection.getU32(&HashOffset);
+}
+
+// Returns true if we should continue scanning for entries, false if this is the
+// last (sentinel) entry). In case of a parsing error we also return false, as
+// it's not possible to recover this entry list (but the other lists may still
+// parse OK).
+bool DWARFDebugNames::NameIndex::dumpEntry(ScopedPrinter &W,
+                                           uint64_t *Offset) const {
+  uint64_t EntryId = *Offset;
+  auto EntryOr = getEntry(Offset);
+  if (!EntryOr) {
+    handleAllErrors(EntryOr.takeError(), [](const SentinelError &) {},
+                    [&W](const ErrorInfoBase &EI) { EI.log(W.startLine()); });
+    return false;
+  }
+
+  DictScope EntryScope(W, ("Entry @ 0x" + Twine::utohexstr(EntryId)).str());
+  EntryOr->dump(W);
+  return true;
+}
+
+void DWARFDebugNames::NameIndex::dumpName(ScopedPrinter &W,
+                                          const NameTableEntry &NTE,
+                                          Optional<uint32_t> Hash) const {
+  DictScope NameScope(W, ("Name " + Twine(NTE.getIndex())).str());
+  if (Hash)
+    W.printHex("Hash", *Hash);
+
+  W.startLine() << format("String: 0x%08" PRIx64, NTE.getStringOffset());
+  W.getOStream() << " \"" << NTE.getString() << "\"\n";
+
+  uint64_t EntryOffset = NTE.getEntryOffset();
+  while (dumpEntry(W, &EntryOffset))
+    /*empty*/;
+}
+
+void DWARFDebugNames::NameIndex::dumpCUs(ScopedPrinter &W) const {
+  ListScope CUScope(W, "Compilation Unit offsets");
+  for (uint32_t CU = 0; CU < Hdr.CompUnitCount; ++CU)
+    W.startLine() << format("CU[%u]: 0x%08" PRIx64 "\n", CU, getCUOffset(CU));
+}
+
+void DWARFDebugNames::NameIndex::dumpLocalTUs(ScopedPrinter &W) const {
+  if (Hdr.LocalTypeUnitCount == 0)
+    return;
+
+  ListScope TUScope(W, "Local Type Unit offsets");
+  for (uint32_t TU = 0; TU < Hdr.LocalTypeUnitCount; ++TU)
+    W.startLine() << format("LocalTU[%u]: 0x%08" PRIx64 "\n", TU,
+                            getLocalTUOffset(TU));
+}
+
+void DWARFDebugNames::NameIndex::dumpForeignTUs(ScopedPrinter &W) const {
+  if (Hdr.ForeignTypeUnitCount == 0)
+    return;
+
+  ListScope TUScope(W, "Foreign Type Unit signatures");
+  for (uint32_t TU = 0; TU < Hdr.ForeignTypeUnitCount; ++TU) {
+    W.startLine() << format("ForeignTU[%u]: 0x%016" PRIx64 "\n", TU,
+                            getForeignTUSignature(TU));
+  }
+}
+
+void DWARFDebugNames::NameIndex::dumpAbbreviations(ScopedPrinter &W) const {
+  ListScope AbbrevsScope(W, "Abbreviations");
+  for (const auto &Abbr : Abbrevs)
+    Abbr.dump(W);
+}
+
+void DWARFDebugNames::NameIndex::dumpBucket(ScopedPrinter &W,
+                                            uint32_t Bucket) const {
+  ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str());
+  uint32_t Index = getBucketArrayEntry(Bucket);
+  if (Index == 0) {
+    W.printString("EMPTY");
+    return;
+  }
+  if (Index > Hdr.NameCount) {
+    W.printString("Name index is invalid");
+    return;
+  }
+
+  for (; Index <= Hdr.NameCount; ++Index) {
+    uint32_t Hash = getHashArrayEntry(Index);
+    if (Hash % Hdr.BucketCount != Bucket)
+      break;
+
+    dumpName(W, getNameTableEntry(Index), Hash);
+  }
+}
+
+LLVM_DUMP_METHOD void DWARFDebugNames::NameIndex::dump(ScopedPrinter &W) const {
+  DictScope UnitScope(W, ("Name Index @ 0x" + Twine::utohexstr(Base)).str());
+  Hdr.dump(W);
+  dumpCUs(W);
+  dumpLocalTUs(W);
+  dumpForeignTUs(W);
+  dumpAbbreviations(W);
+
+  if (Hdr.BucketCount > 0) {
+    for (uint32_t Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket)
+      dumpBucket(W, Bucket);
+    return;
+  }
+
+  W.startLine() << "Hash table not present\n";
+  for (NameTableEntry NTE : *this)
+    dumpName(W, NTE, None);
+}
+
+Error DWARFDebugNames::extract() {
+  uint64_t Offset = 0;
+  while (AccelSection.isValidOffset(Offset)) {
+    NameIndex Next(*this, Offset);
+    if (Error E = Next.extract())
+      return E;
+    Offset = Next.getNextUnitOffset();
+    NameIndices.push_back(std::move(Next));
+  }
+  return Error::success();
+}
+
+iterator_range<DWARFDebugNames::ValueIterator>
+DWARFDebugNames::NameIndex::equal_range(StringRef Key) const {
+  return make_range(ValueIterator(*this, Key), ValueIterator());
+}
+
+LLVM_DUMP_METHOD void DWARFDebugNames::dump(raw_ostream &OS) const {
+  ScopedPrinter W(OS);
+  for (const NameIndex &NI : NameIndices)
+    NI.dump(W);
+}
+
+Optional<uint64_t>
+DWARFDebugNames::ValueIterator::findEntryOffsetInCurrentIndex() {
+  const Header &Hdr = CurrentIndex->Hdr;
+  if (Hdr.BucketCount == 0) {
+    // No Hash Table, We need to search through all names in the Name Index.
+    for (NameTableEntry NTE : *CurrentIndex) {
+      if (NTE.getString() == Key)
+        return NTE.getEntryOffset();
+    }
+    return None;
+  }
+
+  // The Name Index has a Hash Table, so use that to speed up the search.
+  // Compute the Key Hash, if it has not been done already.
+  if (!Hash)
+    Hash = caseFoldingDjbHash(Key);
+  uint32_t Bucket = *Hash % Hdr.BucketCount;
+  uint32_t Index = CurrentIndex->getBucketArrayEntry(Bucket);
+  if (Index == 0)
+    return None; // Empty bucket
+
+  for (; Index <= Hdr.NameCount; ++Index) {
+    uint32_t Hash = CurrentIndex->getHashArrayEntry(Index);
+    if (Hash % Hdr.BucketCount != Bucket)
+      return None; // End of bucket
+
+    NameTableEntry NTE = CurrentIndex->getNameTableEntry(Index);
+    if (NTE.getString() == Key)
+      return NTE.getEntryOffset();
+  }
+  return None;
+}
+
+bool DWARFDebugNames::ValueIterator::getEntryAtCurrentOffset() {
+  auto EntryOr = CurrentIndex->getEntry(&DataOffset);
+  if (!EntryOr) {
+    consumeError(EntryOr.takeError());
+    return false;
+  }
+  CurrentEntry = std::move(*EntryOr);
+  return true;
+}
+
+bool DWARFDebugNames::ValueIterator::findInCurrentIndex() {
+  Optional<uint64_t> Offset = findEntryOffsetInCurrentIndex();
+  if (!Offset)
+    return false;
+  DataOffset = *Offset;
+  return getEntryAtCurrentOffset();
+}
+
+void DWARFDebugNames::ValueIterator::searchFromStartOfCurrentIndex() {
+  for (const NameIndex *End = CurrentIndex->Section.NameIndices.end();
+       CurrentIndex != End; ++CurrentIndex) {
+    if (findInCurrentIndex())
+      return;
+  }
+  setEnd();
+}
+
+void DWARFDebugNames::ValueIterator::next() {
+  assert(CurrentIndex && "Incrementing an end() iterator?");
+
+  // First try the next entry in the current Index.
+  if (getEntryAtCurrentOffset())
+    return;
+
+  // If we're a local iterator or we have reached the last Index, we're done.
+  if (IsLocal || CurrentIndex == &CurrentIndex->Section.NameIndices.back()) {
+    setEnd();
+    return;
+  }
+
+  // Otherwise, try the next index.
+  ++CurrentIndex;
+  searchFromStartOfCurrentIndex();
+}
+
+DWARFDebugNames::ValueIterator::ValueIterator(const DWARFDebugNames &AccelTable,
+                                              StringRef Key)
+    : CurrentIndex(AccelTable.NameIndices.begin()), IsLocal(false), Key(Key) {
+  searchFromStartOfCurrentIndex();
+}
+
+DWARFDebugNames::ValueIterator::ValueIterator(
+    const DWARFDebugNames::NameIndex &NI, StringRef Key)
+    : CurrentIndex(&NI), IsLocal(true), Key(Key) {
+  if (!findInCurrentIndex())
+    setEnd();
+}
+
+iterator_range<DWARFDebugNames::ValueIterator>
+DWARFDebugNames::equal_range(StringRef Key) const {
+  if (NameIndices.empty())
+    return make_range(ValueIterator(), ValueIterator());
+  return make_range(ValueIterator(*this, Key), ValueIterator());
+}
+
+const DWARFDebugNames::NameIndex *
+DWARFDebugNames::getCUNameIndex(uint64_t CUOffset) {
+  if (CUToNameIndex.size() == 0 && NameIndices.size() > 0) {
+    for (const auto &NI : *this) {
+      for (uint32_t CU = 0; CU < NI.getCUCount(); ++CU)
+        CUToNameIndex.try_emplace(NI.getCUOffset(CU), &NI);
+    }
+  }
+  return CUToNameIndex.lookup(CUOffset);
+}
diff --git a/binaryen/third_party/llvm-project/DWARFAddressRange.cpp b/binaryen/third_party/llvm-project/DWARFAddressRange.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFAddressRange.cpp
@@ -0,0 +1,28 @@
+//===- DWARFDebugAranges.cpp ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
+
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+void DWARFAddressRange::dump(raw_ostream &OS, uint32_t AddressSize,
+                             DIDumpOptions DumpOpts) const {
+
+  OS << (DumpOpts.DisplayRawContents ? " " : "[");
+  OS << format("0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2, LowPC)
+     << format("0x%*.*" PRIx64, AddressSize * 2, AddressSize * 2, HighPC);
+  OS << (DumpOpts.DisplayRawContents ? "" : ")");
+}
+
+raw_ostream &llvm::operator<<(raw_ostream &OS, const DWARFAddressRange &R) {
+  R.dump(OS, /* AddressSize */ 8);
+  return OS;
+}
diff --git a/binaryen/third_party/llvm-project/DWARFCompileUnit.cpp b/binaryen/third_party/llvm-project/DWARFCompileUnit.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFCompileUnit.cpp
@@ -0,0 +1,40 @@
+//===-- DWARFCompileUnit.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+void DWARFCompileUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
+  OS << format("0x%08" PRIx64, getOffset()) << ": Compile Unit:"
+     << " length = " << format("0x%08" PRIx64, getLength())
+     << " version = " << format("0x%04x", getVersion());
+  if (getVersion() >= 5)
+    OS << " unit_type = " << dwarf::UnitTypeString(getUnitType());
+  if (auto* Abbreviations = getAbbreviations()) { // XXX BINARYEN
+    OS << " abbr_offset = "
+       << format("0x%04" PRIx64, Abbreviations->getOffset());
+  }
+  OS << " addr_size = " << format("0x%02x", getAddressByteSize());
+  if (getVersion() >= 5 && getUnitType() != dwarf::DW_UT_compile)
+    OS << " DWO_id = " << format("0x%016" PRIx64, *getDWOId());
+  OS << " (next unit at " << format("0x%08" PRIx64, getNextUnitOffset())
+     << ")\n";
+
+  if (DWARFDie CUDie = getUnitDIE(false))
+    CUDie.dump(OS, 0, DumpOpts);
+  else
+    OS << "<compile unit can't be parsed!>\n\n";
+}
+
+// VTable anchor.
+DWARFCompileUnit::~DWARFCompileUnit() = default;
diff --git a/binaryen/third_party/llvm-project/DWARFContext.cpp b/binaryen/third_party/llvm-project/DWARFContext.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFContext.cpp
@@ -0,0 +1,1883 @@
+//===- DWARFContext.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h"
+#include "llvm/DebugInfo/DWARF/DWARFSection.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
+#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Object/Decompressor.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/RelocationResolver.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstdint>
+#include <deque>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+using namespace object;
+
+#define DEBUG_TYPE "dwarf"
+
+using DWARFLineTable = DWARFDebugLine::LineTable;
+using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind;
+using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind;
+
+DWARFContext::DWARFContext(std::unique_ptr<const DWARFObject> DObj,
+                           std::string DWPName)
+    : DIContext(CK_DWARF), DWPName(std::move(DWPName)), DObj(std::move(DObj)) {}
+
+DWARFContext::~DWARFContext() = default;
+
+/// Dump the UUID load command.
+static void dumpUUID(raw_ostream &OS, const ObjectFile &Obj) {
+#if 0 // XXX BINARYEN
+  auto *MachO = dyn_cast<MachOObjectFile>(&Obj);
+  if (!MachO)
+    return;
+  for (auto LC : MachO->load_commands()) {
+    raw_ostream::uuid_t UUID;
+    if (LC.C.cmd == MachO::LC_UUID) {
+      if (LC.C.cmdsize < sizeof(UUID) + sizeof(LC.C)) {
+        OS << "error: UUID load command is too short.\n";
+        return;
+      }
+      OS << "UUID: ";
+      memcpy(&UUID, LC.Ptr+sizeof(LC.C), sizeof(UUID));
+      OS.write_uuid(UUID);
+      Triple T = MachO->getArchTriple();
+      OS << " (" << T.getArchName() << ')';
+      OS << ' ' << MachO->getFileName() << '\n';
+    }
+  }
+#endif
+}
+
+using ContributionCollection =
+    std::vector<Optional<StrOffsetsContributionDescriptor>>;
+
+// Collect all the contributions to the string offsets table from all units,
+// sort them by their starting offsets and remove duplicates.
+static ContributionCollection
+collectContributionData(DWARFContext::unit_iterator_range Units) {
+  ContributionCollection Contributions;
+  for (const auto &U : Units)
+    if (const auto &C = U->getStringOffsetsTableContribution())
+      Contributions.push_back(C);
+  // Sort the contributions so that any invalid ones are placed at
+  // the start of the contributions vector. This way they are reported
+  // first.
+  llvm::sort(Contributions,
+             [](const Optional<StrOffsetsContributionDescriptor> &L,
+                const Optional<StrOffsetsContributionDescriptor> &R) {
+               if (L && R)
+                 return L->Base < R->Base;
+               return R.hasValue();
+             });
+
+  // Uniquify contributions, as it is possible that units (specifically
+  // type units in dwo or dwp files) share contributions. We don't want
+  // to report them more than once.
+  Contributions.erase(
+      std::unique(Contributions.begin(), Contributions.end(),
+                  [](const Optional<StrOffsetsContributionDescriptor> &L,
+                     const Optional<StrOffsetsContributionDescriptor> &R) {
+                    if (L && R)
+                      return L->Base == R->Base && L->Size == R->Size;
+                    return false;
+                  }),
+      Contributions.end());
+  return Contributions;
+}
+
+static void dumpDWARFv5StringOffsetsSection(
+    raw_ostream &OS, StringRef SectionName, const DWARFObject &Obj,
+    const DWARFSection &StringOffsetsSection, StringRef StringSection,
+    DWARFContext::unit_iterator_range Units, bool LittleEndian) {
+  auto Contributions = collectContributionData(Units);
+  DWARFDataExtractor StrOffsetExt(Obj, StringOffsetsSection, LittleEndian, 0);
+  DataExtractor StrData(StringSection, LittleEndian, 0);
+  uint64_t SectionSize = StringOffsetsSection.Data.size();
+  uint64_t Offset = 0;
+  for (auto &Contribution : Contributions) {
+    // Report an ill-formed contribution.
+    if (!Contribution) {
+      OS << "error: invalid contribution to string offsets table in section ."
+         << SectionName << ".\n";
+      return;
+    }
+
+    dwarf::DwarfFormat Format = Contribution->getFormat();
+    uint16_t Version = Contribution->getVersion();
+    uint64_t ContributionHeader = Contribution->Base;
+    // In DWARF v5 there is a contribution header that immediately precedes
+    // the string offsets base (the location we have previously retrieved from
+    // the CU DIE's DW_AT_str_offsets attribute). The header is located either
+    // 8 or 16 bytes before the base, depending on the contribution's format.
+    if (Version >= 5)
+      ContributionHeader -= Format == DWARF32 ? 8 : 16;
+
+    // Detect overlapping contributions.
+    if (Offset > ContributionHeader) {
+      WithColor::error()
+          << "overlapping contributions to string offsets table in section ."
+          << SectionName << ".\n";
+      return;
+    }
+    // Report a gap in the table.
+    if (Offset < ContributionHeader) {
+      OS << format("0x%8.8" PRIx64 ": Gap, length = ", Offset);
+      OS << (ContributionHeader - Offset) << "\n";
+    }
+    OS << format("0x%8.8" PRIx64 ": ", ContributionHeader);
+    // In DWARF v5 the contribution size in the descriptor does not equal
+    // the originally encoded length (it does not contain the length of the
+    // version field and the padding, a total of 4 bytes). Add them back in
+    // for reporting.
+    OS << "Contribution size = " << (Contribution->Size + (Version < 5 ? 0 : 4))
+       << ", Format = " << (Format == DWARF32 ? "DWARF32" : "DWARF64")
+       << ", Version = " << Version << "\n";
+
+    Offset = Contribution->Base;
+    unsigned EntrySize = Contribution->getDwarfOffsetByteSize();
+    while (Offset - Contribution->Base < Contribution->Size) {
+      OS << format("0x%8.8" PRIx64 ": ", Offset);
+      uint64_t StringOffset =
+          StrOffsetExt.getRelocatedValue(EntrySize, &Offset);
+      OS << format("%8.8" PRIx64 " ", StringOffset);
+      const char *S = StrData.getCStr(&StringOffset);
+      if (S)
+        OS << format("\"%s\"", S);
+      OS << "\n";
+    }
+  }
+  // Report a gap at the end of the table.
+  if (Offset < SectionSize) {
+    OS << format("0x%8.8" PRIx64 ": Gap, length = ", Offset);
+    OS << (SectionSize - Offset) << "\n";
+  }
+}
+
+// Dump a DWARF string offsets section. This may be a DWARF v5 formatted
+// string offsets section, where each compile or type unit contributes a
+// number of entries (string offsets), with each contribution preceded by
+// a header containing size and version number. Alternatively, it may be a
+// monolithic series of string offsets, as generated by the pre-DWARF v5
+// implementation of split DWARF.
+static void dumpStringOffsetsSection(raw_ostream &OS, StringRef SectionName,
+                                     const DWARFObject &Obj,
+                                     const DWARFSection &StringOffsetsSection,
+                                     StringRef StringSection,
+                                     DWARFContext::unit_iterator_range Units,
+                                     bool LittleEndian, unsigned MaxVersion) {
+  // If we have at least one (compile or type) unit with DWARF v5 or greater,
+  // we assume that the section is formatted like a DWARF v5 string offsets
+  // section.
+  if (MaxVersion >= 5)
+    dumpDWARFv5StringOffsetsSection(OS, SectionName, Obj, StringOffsetsSection,
+                                    StringSection, Units, LittleEndian);
+  else {
+    DataExtractor strOffsetExt(StringOffsetsSection.Data, LittleEndian, 0);
+    uint64_t offset = 0;
+    uint64_t size = StringOffsetsSection.Data.size();
+    // Ensure that size is a multiple of the size of an entry.
+    if (size & ((uint64_t)(sizeof(uint32_t) - 1))) {
+      OS << "error: size of ." << SectionName << " is not a multiple of "
+         << sizeof(uint32_t) << ".\n";
+      size &= -(uint64_t)sizeof(uint32_t);
+    }
+    DataExtractor StrData(StringSection, LittleEndian, 0);
+    while (offset < size) {
+      OS << format("0x%8.8" PRIx64 ": ", offset);
+      uint64_t StringOffset = strOffsetExt.getU32(&offset);
+      OS << format("%8.8" PRIx64 "  ", StringOffset);
+      const char *S = StrData.getCStr(&StringOffset);
+      if (S)
+        OS << format("\"%s\"", S);
+      OS << "\n";
+    }
+  }
+}
+
+// Dump the .debug_addr section.
+static void dumpAddrSection(raw_ostream &OS, DWARFDataExtractor &AddrData,
+                            DIDumpOptions DumpOpts, uint16_t Version,
+                            uint8_t AddrSize) {
+  uint64_t Offset = 0;
+  while (AddrData.isValidOffset(Offset)) {
+    DWARFDebugAddrTable AddrTable;
+    uint64_t TableOffset = Offset;
+    if (Error Err = AddrTable.extract(AddrData, &Offset, Version, AddrSize,
+                                      DWARFContext::dumpWarning)) {
+      WithColor::error() << toString(std::move(Err)) << '\n';
+      // Keep going after an error, if we can, assuming that the length field
+      // could be read. If it couldn't, stop reading the section.
+      if (!AddrTable.hasValidLength())
+        break;
+      Offset = TableOffset + AddrTable.getLength();
+    } else {
+      AddrTable.dump(OS, DumpOpts);
+    }
+  }
+}
+
+// Dump the .debug_rnglists or .debug_rnglists.dwo section (DWARF v5).
+static void dumpRnglistsSection(
+    raw_ostream &OS, DWARFDataExtractor &rnglistData,
+    llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)>
+        LookupPooledAddress,
+    DIDumpOptions DumpOpts) {
+  uint64_t Offset = 0;
+  while (rnglistData.isValidOffset(Offset)) {
+    llvm::DWARFDebugRnglistTable Rnglists;
+    uint64_t TableOffset = Offset;
+    if (Error Err = Rnglists.extract(rnglistData, &Offset)) {
+      WithColor::error() << toString(std::move(Err)) << '\n';
+      uint64_t Length = Rnglists.length();
+      // Keep going after an error, if we can, assuming that the length field
+      // could be read. If it couldn't, stop reading the section.
+      if (Length == 0)
+        break;
+      Offset = TableOffset + Length;
+    } else {
+      Rnglists.dump(OS, LookupPooledAddress, DumpOpts);
+    }
+  }
+}
+
+static void dumpLoclistsSection(raw_ostream &OS, DIDumpOptions DumpOpts,
+                                DWARFDataExtractor Data,
+                                const MCRegisterInfo *MRI,
+                                Optional<uint64_t> DumpOffset) {
+  uint64_t Offset = 0;
+
+  while (Data.isValidOffset(Offset)) {
+    DWARFListTableHeader Header(".debug_loclists", "locations");
+    if (Error E = Header.extract(Data, &Offset)) {
+      WithColor::error() << toString(std::move(E)) << '\n';
+      return;
+    }
+
+    Header.dump(OS, DumpOpts);
+
+    uint64_t EndOffset = Header.length() + Header.getHeaderOffset();
+    Data.setAddressSize(Header.getAddrSize());
+    if (DumpOffset) {
+      if (DumpOffset >= Offset && DumpOffset < EndOffset) {
+        Offset = *DumpOffset;
+        DWARFDebugLoclists::dumpLocationList(Data, &Offset, Header.getVersion(),
+                                             OS, /*BaseAddr=*/0, MRI, nullptr,
+                                             DumpOpts, /*Indent=*/0);
+        OS << "\n";
+        return;
+      }
+    } else {
+      DWARFDebugLoclists::dumpRange(Data, Offset, EndOffset - Offset,
+                                    Header.getVersion(), OS, 0, MRI, DumpOpts);
+    }
+    Offset = EndOffset;
+  }
+}
+
+void DWARFContext::dump(
+    raw_ostream &OS, DIDumpOptions DumpOpts,
+    std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets) {
+  uint64_t DumpType = DumpOpts.DumpType;
+
+  StringRef Extension = sys::path::extension(DObj->getFileName());
+  bool IsDWO = (Extension == ".dwo") || (Extension == ".dwp");
+
+#if 0 // XXX BINARYEN
+  // Print UUID header.
+  const auto *ObjFile = DObj->getFile();
+  if (DumpType & DIDT_UUID)
+    dumpUUID(OS, *ObjFile);
+#endif
+
+  // Print a header for each explicitly-requested section.
+  // Otherwise just print one for non-empty sections.
+  // Only print empty .dwo section headers when dumping a .dwo file.
+  bool Explicit = DumpType != DIDT_All && !IsDWO;
+  bool ExplicitDWO = Explicit && IsDWO;
+  auto shouldDump = [&](bool Explicit, const char *Name, unsigned ID,
+                        StringRef Section) -> Optional<uint64_t> * {
+
+    unsigned Mask = 1U << ID;
+    bool Should = (DumpType & Mask) && (Explicit || !Section.empty());
+    if (!Should)
+      return nullptr;
+    OS << "\n" << Name << " contents:\n";
+    return &DumpOffsets[ID];
+  };
+
+  // Dump individual sections.
+  if (shouldDump(Explicit, ".debug_abbrev", DIDT_ID_DebugAbbrev,
+                 DObj->getAbbrevSection()))
+    getDebugAbbrev()->dump(OS);
+  if (shouldDump(ExplicitDWO, ".debug_abbrev.dwo", DIDT_ID_DebugAbbrev,
+                 DObj->getAbbrevDWOSection()))
+    getDebugAbbrevDWO()->dump(OS);
+
+  auto dumpDebugInfo = [&](const char *Name, unit_iterator_range Units) {
+    OS << '\n' << Name << " contents:\n";
+    if (auto DumpOffset = DumpOffsets[DIDT_ID_DebugInfo])
+      for (const auto &U : Units)
+        U->getDIEForOffset(DumpOffset.getValue())
+            .dump(OS, 0, DumpOpts.noImplicitRecursion());
+    else
+      for (const auto &U : Units)
+        U->dump(OS, DumpOpts);
+  };
+  if ((DumpType & DIDT_DebugInfo)) {
+    if (Explicit || getNumCompileUnits())
+      dumpDebugInfo(".debug_info", info_section_units());
+    if (ExplicitDWO || getNumDWOCompileUnits())
+      dumpDebugInfo(".debug_info.dwo", dwo_info_section_units());
+  }
+
+  auto dumpDebugType = [&](const char *Name, unit_iterator_range Units) {
+    OS << '\n' << Name << " contents:\n";
+    for (const auto &U : Units)
+      if (auto DumpOffset = DumpOffsets[DIDT_ID_DebugTypes])
+        U->getDIEForOffset(*DumpOffset)
+            .dump(OS, 0, DumpOpts.noImplicitRecursion());
+      else
+        U->dump(OS, DumpOpts);
+  };
+  if ((DumpType & DIDT_DebugTypes)) {
+    if (Explicit || getNumTypeUnits())
+      dumpDebugType(".debug_types", types_section_units());
+    if (ExplicitDWO || getNumDWOTypeUnits())
+      dumpDebugType(".debug_types.dwo", dwo_types_section_units());
+  }
+
+  if (const auto *Off = shouldDump(Explicit, ".debug_loc", DIDT_ID_DebugLoc,
+                                   DObj->getLocSection().Data)) {
+    getDebugLoc()->dump(OS, getRegisterInfo(), DumpOpts, *Off);
+  }
+  if (const auto *Off =
+          shouldDump(Explicit, ".debug_loclists", DIDT_ID_DebugLoclists,
+                     DObj->getLoclistsSection().Data)) {
+    DWARFDataExtractor Data(*DObj, DObj->getLoclistsSection(), isLittleEndian(),
+                            0);
+    dumpLoclistsSection(OS, DumpOpts, Data, getRegisterInfo(), *Off);
+  }
+  if (const auto *Off =
+          shouldDump(ExplicitDWO, ".debug_loc.dwo", DIDT_ID_DebugLoc,
+                     DObj->getLocDWOSection().Data)) {
+    DWARFDataExtractor Data(*DObj, DObj->getLocDWOSection(), isLittleEndian(),
+                            4);
+    if (*Off) {
+      uint64_t Offset = **Off;
+      DWARFDebugLoclists::dumpLocationList(Data, &Offset, /*Version=*/4, OS,
+                                           /*BaseAddr=*/0, getRegisterInfo(),
+                                           nullptr, DumpOpts, /*Indent=*/0);
+      OS << "\n";
+    } else {
+      DWARFDebugLoclists::dumpRange(Data, 0, Data.getData().size(),
+                                    /*Version=*/4, OS, /*BaseAddr=*/0,
+                                    getRegisterInfo(), DumpOpts);
+    }
+  }
+
+  if (const auto *Off = shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame,
+                                   DObj->getFrameSection().Data))
+    getDebugFrame()->dump(OS, getRegisterInfo(), *Off);
+
+  if (const auto *Off = shouldDump(Explicit, ".eh_frame", DIDT_ID_DebugFrame,
+                                   DObj->getEHFrameSection().Data))
+    getEHFrame()->dump(OS, getRegisterInfo(), *Off);
+
+  if (DumpType & DIDT_DebugMacro) {
+    if (Explicit || !getDebugMacro()->empty()) {
+      OS << "\n.debug_macinfo contents:\n";
+      getDebugMacro()->dump(OS);
+    }
+  }
+
+  if (shouldDump(Explicit, ".debug_aranges", DIDT_ID_DebugAranges,
+                 DObj->getArangesSection())) {
+    uint64_t offset = 0;
+    DataExtractor arangesData(DObj->getArangesSection(), isLittleEndian(), 0);
+    DWARFDebugArangeSet set;
+    while (set.extract(arangesData, &offset))
+      set.dump(OS);
+  }
+
+  auto DumpLineSection = [&](DWARFDebugLine::SectionParser Parser,
+                             DIDumpOptions DumpOpts,
+                             Optional<uint64_t> DumpOffset) {
+    while (!Parser.done()) {
+      if (DumpOffset && Parser.getOffset() != *DumpOffset) {
+        Parser.skip(dumpWarning);
+        continue;
+      }
+      OS << "debug_line[" << format("0x%8.8" PRIx64, Parser.getOffset())
+         << "]\n";
+      if (DumpOpts.Verbose) {
+        Parser.parseNext(dumpWarning, dumpWarning, &OS);
+      } else {
+        DWARFDebugLine::LineTable LineTable =
+            Parser.parseNext(dumpWarning, dumpWarning);
+        LineTable.dump(OS, DumpOpts);
+      }
+    }
+  };
+
+  if (const auto *Off = shouldDump(Explicit, ".debug_line", DIDT_ID_DebugLine,
+                                   DObj->getLineSection().Data)) {
+    DWARFDataExtractor LineData(*DObj, DObj->getLineSection(), isLittleEndian(),
+                                0);
+    DWARFDebugLine::SectionParser Parser(LineData, *this, compile_units(),
+                                         type_units());
+    DumpLineSection(Parser, DumpOpts, *Off);
+  }
+
+  if (const auto *Off =
+          shouldDump(ExplicitDWO, ".debug_line.dwo", DIDT_ID_DebugLine,
+                     DObj->getLineDWOSection().Data)) {
+    DWARFDataExtractor LineData(*DObj, DObj->getLineDWOSection(),
+                                isLittleEndian(), 0);
+    DWARFDebugLine::SectionParser Parser(LineData, *this, dwo_compile_units(),
+                                         dwo_type_units());
+    DumpLineSection(Parser, DumpOpts, *Off);
+  }
+
+  if (shouldDump(Explicit, ".debug_cu_index", DIDT_ID_DebugCUIndex,
+                 DObj->getCUIndexSection())) {
+    getCUIndex().dump(OS);
+  }
+
+  if (shouldDump(Explicit, ".debug_tu_index", DIDT_ID_DebugTUIndex,
+                 DObj->getTUIndexSection())) {
+    getTUIndex().dump(OS);
+  }
+
+  if (shouldDump(Explicit, ".debug_str", DIDT_ID_DebugStr,
+                 DObj->getStrSection())) {
+    DataExtractor strData(DObj->getStrSection(), isLittleEndian(), 0);
+    uint64_t offset = 0;
+    uint64_t strOffset = 0;
+    while (const char *s = strData.getCStr(&offset)) {
+      OS << format("0x%8.8" PRIx64 ": \"%s\"\n", strOffset, s);
+      strOffset = offset;
+    }
+  }
+  if (shouldDump(ExplicitDWO, ".debug_str.dwo", DIDT_ID_DebugStr,
+                 DObj->getStrDWOSection())) {
+    DataExtractor strDWOData(DObj->getStrDWOSection(), isLittleEndian(), 0);
+    uint64_t offset = 0;
+    uint64_t strDWOOffset = 0;
+    while (const char *s = strDWOData.getCStr(&offset)) {
+      OS << format("0x%8.8" PRIx64 ": \"%s\"\n", strDWOOffset, s);
+      strDWOOffset = offset;
+    }
+  }
+  if (shouldDump(Explicit, ".debug_line_str", DIDT_ID_DebugLineStr,
+                 DObj->getLineStrSection())) {
+    DataExtractor strData(DObj->getLineStrSection(), isLittleEndian(), 0);
+    uint64_t offset = 0;
+    uint64_t strOffset = 0;
+    while (const char *s = strData.getCStr(&offset)) {
+      OS << format("0x%8.8" PRIx64 ": \"", strOffset);
+      OS.write_escaped(s);
+      OS << "\"\n";
+      strOffset = offset;
+    }
+  }
+
+  if (shouldDump(Explicit, ".debug_addr", DIDT_ID_DebugAddr,
+                 DObj->getAddrSection().Data)) {
+    DWARFDataExtractor AddrData(*DObj, DObj->getAddrSection(),
+                                   isLittleEndian(), 0);
+    dumpAddrSection(OS, AddrData, DumpOpts, getMaxVersion(), getCUAddrSize());
+  }
+
+  if (shouldDump(Explicit, ".debug_ranges", DIDT_ID_DebugRanges,
+                 DObj->getRangesSection().Data)) {
+    uint8_t savedAddressByteSize = getCUAddrSize();
+    DWARFDataExtractor rangesData(*DObj, DObj->getRangesSection(),
+                                  isLittleEndian(), savedAddressByteSize);
+    uint64_t offset = 0;
+    DWARFDebugRangeList rangeList;
+    while (rangesData.isValidOffset(offset)) {
+      if (Error E = rangeList.extract(rangesData, &offset)) {
+        WithColor::error() << toString(std::move(E)) << '\n';
+        break;
+      }
+      rangeList.dump(OS);
+    }
+  }
+
+  auto LookupPooledAddress = [&](uint32_t Index) -> Optional<SectionedAddress> {
+    const auto &CUs = compile_units();
+    auto I = CUs.begin();
+    if (I == CUs.end())
+      return None;
+    return (*I)->getAddrOffsetSectionItem(Index);
+  };
+
+  if (shouldDump(Explicit, ".debug_rnglists", DIDT_ID_DebugRnglists,
+                 DObj->getRnglistsSection().Data)) {
+    DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsSection(),
+                                   isLittleEndian(), 0);
+    dumpRnglistsSection(OS, RnglistData, LookupPooledAddress, DumpOpts);
+  }
+
+  if (shouldDump(ExplicitDWO, ".debug_rnglists.dwo", DIDT_ID_DebugRnglists,
+                 DObj->getRnglistsDWOSection().Data)) {
+    DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsDWOSection(),
+                                   isLittleEndian(), 0);
+    dumpRnglistsSection(OS, RnglistData, LookupPooledAddress, DumpOpts);
+  }
+
+  if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames,
+                 DObj->getPubnamesSection().Data))
+    DWARFDebugPubTable(*DObj, DObj->getPubnamesSection(), isLittleEndian(), false)
+        .dump(OS);
+
+  if (shouldDump(Explicit, ".debug_pubtypes", DIDT_ID_DebugPubtypes,
+                 DObj->getPubtypesSection().Data))
+    DWARFDebugPubTable(*DObj, DObj->getPubtypesSection(), isLittleEndian(), false)
+        .dump(OS);
+
+  if (shouldDump(Explicit, ".debug_gnu_pubnames", DIDT_ID_DebugGnuPubnames,
+                 DObj->getGnuPubnamesSection().Data))
+    DWARFDebugPubTable(*DObj, DObj->getGnuPubnamesSection(), isLittleEndian(),
+                       true /* GnuStyle */)
+        .dump(OS);
+
+  if (shouldDump(Explicit, ".debug_gnu_pubtypes", DIDT_ID_DebugGnuPubtypes,
+                 DObj->getGnuPubtypesSection().Data))
+    DWARFDebugPubTable(*DObj, DObj->getGnuPubtypesSection(), isLittleEndian(),
+                       true /* GnuStyle */)
+        .dump(OS);
+
+  if (shouldDump(Explicit, ".debug_str_offsets", DIDT_ID_DebugStrOffsets,
+                 DObj->getStrOffsetsSection().Data))
+    dumpStringOffsetsSection(OS, "debug_str_offsets", *DObj,
+                             DObj->getStrOffsetsSection(),
+                             DObj->getStrSection(), normal_units(),
+                             isLittleEndian(), getMaxVersion());
+  if (shouldDump(ExplicitDWO, ".debug_str_offsets.dwo", DIDT_ID_DebugStrOffsets,
+                 DObj->getStrOffsetsDWOSection().Data))
+    dumpStringOffsetsSection(OS, "debug_str_offsets.dwo", *DObj,
+                             DObj->getStrOffsetsDWOSection(),
+                             DObj->getStrDWOSection(), dwo_units(),
+                             isLittleEndian(), getMaxDWOVersion());
+
+  if (shouldDump(Explicit, ".gdb_index", DIDT_ID_GdbIndex,
+                 DObj->getGdbIndexSection())) {
+    getGdbIndex().dump(OS);
+  }
+
+  if (shouldDump(Explicit, ".apple_names", DIDT_ID_AppleNames,
+                 DObj->getAppleNamesSection().Data))
+    getAppleNames().dump(OS);
+
+  if (shouldDump(Explicit, ".apple_types", DIDT_ID_AppleTypes,
+                 DObj->getAppleTypesSection().Data))
+    getAppleTypes().dump(OS);
+
+  if (shouldDump(Explicit, ".apple_namespaces", DIDT_ID_AppleNamespaces,
+                 DObj->getAppleNamespacesSection().Data))
+    getAppleNamespaces().dump(OS);
+
+  if (shouldDump(Explicit, ".apple_objc", DIDT_ID_AppleObjC,
+                 DObj->getAppleObjCSection().Data))
+    getAppleObjC().dump(OS);
+  if (shouldDump(Explicit, ".debug_names", DIDT_ID_DebugNames,
+                 DObj->getNamesSection().Data))
+    getDebugNames().dump(OS);
+}
+
+DWARFCompileUnit *DWARFContext::getDWOCompileUnitForHash(uint64_t Hash) {
+  parseDWOUnits(LazyParse);
+
+  if (const auto &CUI = getCUIndex()) {
+    if (const auto *R = CUI.getFromHash(Hash))
+      return dyn_cast_or_null<DWARFCompileUnit>(
+          DWOUnits.getUnitForIndexEntry(*R));
+    return nullptr;
+  }
+
+  // If there's no index, just search through the CUs in the DWO - there's
+  // probably only one unless this is something like LTO - though an in-process
+  // built/cached lookup table could be used in that case to improve repeated
+  // lookups of different CUs in the DWO.
+  for (const auto &DWOCU : dwo_compile_units()) {
+    // Might not have parsed DWO ID yet.
+    if (!DWOCU->getDWOId()) {
+      if (Optional<uint64_t> DWOId =
+          toUnsigned(DWOCU->getUnitDIE().find(DW_AT_GNU_dwo_id)))
+        DWOCU->setDWOId(*DWOId);
+      else
+        // No DWO ID?
+        continue;
+    }
+    if (DWOCU->getDWOId() == Hash)
+      return dyn_cast<DWARFCompileUnit>(DWOCU.get());
+  }
+  return nullptr;
+}
+
+DWARFDie DWARFContext::getDIEForOffset(uint64_t Offset) {
+  parseNormalUnits();
+  if (auto *CU = NormalUnits.getUnitForOffset(Offset))
+    return CU->getDIEForOffset(Offset);
+  return DWARFDie();
+}
+
+bool DWARFContext::verify(raw_ostream &OS, DIDumpOptions DumpOpts) {
+  bool Success = true;
+  DWARFVerifier verifier(OS, *this, DumpOpts);
+
+  Success &= verifier.handleDebugAbbrev();
+  if (DumpOpts.DumpType & DIDT_DebugInfo)
+    Success &= verifier.handleDebugInfo();
+  if (DumpOpts.DumpType & DIDT_DebugLine)
+    Success &= verifier.handleDebugLine();
+  Success &= verifier.handleAccelTables();
+  return Success;
+}
+
+const DWARFUnitIndex &DWARFContext::getCUIndex() {
+  if (CUIndex)
+    return *CUIndex;
+
+  DataExtractor CUIndexData(DObj->getCUIndexSection(), isLittleEndian(), 0);
+
+  CUIndex = std::make_unique<DWARFUnitIndex>(DW_SECT_INFO);
+  CUIndex->parse(CUIndexData);
+  return *CUIndex;
+}
+
+const DWARFUnitIndex &DWARFContext::getTUIndex() {
+  if (TUIndex)
+    return *TUIndex;
+
+  DataExtractor TUIndexData(DObj->getTUIndexSection(), isLittleEndian(), 0);
+
+  TUIndex = std::make_unique<DWARFUnitIndex>(DW_SECT_TYPES);
+  TUIndex->parse(TUIndexData);
+  return *TUIndex;
+}
+
+DWARFGdbIndex &DWARFContext::getGdbIndex() {
+  if (GdbIndex)
+    return *GdbIndex;
+
+  DataExtractor GdbIndexData(DObj->getGdbIndexSection(), true /*LE*/, 0);
+  GdbIndex = std::make_unique<DWARFGdbIndex>();
+  GdbIndex->parse(GdbIndexData);
+  return *GdbIndex;
+}
+
+const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() {
+  if (Abbrev)
+    return Abbrev.get();
+
+  DataExtractor abbrData(DObj->getAbbrevSection(), isLittleEndian(), 0);
+
+  Abbrev.reset(new DWARFDebugAbbrev());
+  Abbrev->extract(abbrData);
+  return Abbrev.get();
+}
+
+const DWARFDebugAbbrev *DWARFContext::getDebugAbbrevDWO() {
+  if (AbbrevDWO)
+    return AbbrevDWO.get();
+
+  DataExtractor abbrData(DObj->getAbbrevDWOSection(), isLittleEndian(), 0);
+  AbbrevDWO.reset(new DWARFDebugAbbrev());
+  AbbrevDWO->extract(abbrData);
+  return AbbrevDWO.get();
+}
+
+const DWARFDebugLoc *DWARFContext::getDebugLoc() {
+  if (Loc)
+    return Loc.get();
+
+  Loc.reset(new DWARFDebugLoc);
+  // Assume all units have the same address byte size.
+  if (getNumCompileUnits()) {
+    DWARFDataExtractor LocData(*DObj, DObj->getLocSection(), isLittleEndian(),
+                               getUnitAtIndex(0)->getAddressByteSize());
+    Loc->parse(LocData);
+  }
+  return Loc.get();
+}
+
+const DWARFDebugAranges *DWARFContext::getDebugAranges() {
+  if (Aranges)
+    return Aranges.get();
+
+  Aranges.reset(new DWARFDebugAranges());
+  Aranges->generate(this);
+  return Aranges.get();
+}
+
+const DWARFDebugFrame *DWARFContext::getDebugFrame() {
+  if (DebugFrame)
+    return DebugFrame.get();
+
+  // There's a "bug" in the DWARFv3 standard with respect to the target address
+  // size within debug frame sections. While DWARF is supposed to be independent
+  // of its container, FDEs have fields with size being "target address size",
+  // which isn't specified in DWARF in general. It's only specified for CUs, but
+  // .eh_frame can appear without a .debug_info section. Follow the example of
+  // other tools (libdwarf) and extract this from the container (ObjectFile
+  // provides this information). This problem is fixed in DWARFv4
+  // See this dwarf-discuss discussion for more details:
+  // http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html
+  DWARFDataExtractor debugFrameData(*DObj, DObj->getFrameSection(),
+                                    isLittleEndian(), DObj->getAddressSize());
+  DebugFrame.reset(new DWARFDebugFrame(getArch(), false /* IsEH */));
+  DebugFrame->parse(debugFrameData);
+  return DebugFrame.get();
+}
+
+const DWARFDebugFrame *DWARFContext::getEHFrame() {
+  if (EHFrame)
+    return EHFrame.get();
+
+  DWARFDataExtractor debugFrameData(*DObj, DObj->getEHFrameSection(),
+                                    isLittleEndian(), DObj->getAddressSize());
+  DebugFrame.reset(new DWARFDebugFrame(getArch(), true /* IsEH */));
+  DebugFrame->parse(debugFrameData);
+  return DebugFrame.get();
+}
+
+const DWARFDebugMacro *DWARFContext::getDebugMacro() {
+  if (Macro)
+    return Macro.get();
+
+  DataExtractor MacinfoData(DObj->getMacinfoSection(), isLittleEndian(), 0);
+  Macro.reset(new DWARFDebugMacro());
+  Macro->parse(MacinfoData);
+  return Macro.get();
+}
+
+template <typename T>
+static T &getAccelTable(std::unique_ptr<T> &Cache, const DWARFObject &Obj,
+                        const DWARFSection &Section, StringRef StringSection,
+                        bool IsLittleEndian) {
+  if (Cache)
+    return *Cache;
+  DWARFDataExtractor AccelSection(Obj, Section, IsLittleEndian, 0);
+  DataExtractor StrData(StringSection, IsLittleEndian, 0);
+  Cache.reset(new T(AccelSection, StrData));
+  if (Error E = Cache->extract())
+    llvm::consumeError(std::move(E));
+  return *Cache;
+}
+
+const DWARFDebugNames &DWARFContext::getDebugNames() {
+  return getAccelTable(Names, *DObj, DObj->getNamesSection(),
+                       DObj->getStrSection(), isLittleEndian());
+}
+
+const AppleAcceleratorTable &DWARFContext::getAppleNames() {
+  return getAccelTable(AppleNames, *DObj, DObj->getAppleNamesSection(),
+                       DObj->getStrSection(), isLittleEndian());
+}
+
+const AppleAcceleratorTable &DWARFContext::getAppleTypes() {
+  return getAccelTable(AppleTypes, *DObj, DObj->getAppleTypesSection(),
+                       DObj->getStrSection(), isLittleEndian());
+}
+
+const AppleAcceleratorTable &DWARFContext::getAppleNamespaces() {
+  return getAccelTable(AppleNamespaces, *DObj,
+                       DObj->getAppleNamespacesSection(),
+                       DObj->getStrSection(), isLittleEndian());
+}
+
+const AppleAcceleratorTable &DWARFContext::getAppleObjC() {
+  return getAccelTable(AppleObjC, *DObj, DObj->getAppleObjCSection(),
+                       DObj->getStrSection(), isLittleEndian());
+}
+
+const DWARFDebugLine::LineTable *
+DWARFContext::getLineTableForUnit(DWARFUnit *U) {
+  Expected<const DWARFDebugLine::LineTable *> ExpectedLineTable =
+      getLineTableForUnit(U, dumpWarning);
+  if (!ExpectedLineTable) {
+    dumpWarning(ExpectedLineTable.takeError());
+    return nullptr;
+  }
+  return *ExpectedLineTable;
+}
+
+Expected<const DWARFDebugLine::LineTable *> DWARFContext::getLineTableForUnit(
+    DWARFUnit *U, std::function<void(Error)> RecoverableErrorCallback) {
+  if (!Line)
+    Line.reset(new DWARFDebugLine);
+
+  auto UnitDIE = U->getUnitDIE();
+  if (!UnitDIE)
+    return nullptr;
+
+  auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list));
+  if (!Offset)
+    return nullptr; // No line table for this compile unit.
+
+  uint64_t stmtOffset = *Offset + U->getLineTableOffset();
+  // See if the line table is cached.
+  if (const DWARFLineTable *lt = Line->getLineTable(stmtOffset))
+    return lt;
+
+  // Make sure the offset is good before we try to parse.
+  if (stmtOffset >= U->getLineSection().Data.size())
+    return nullptr;
+
+  // We have to parse it first.
+  DWARFDataExtractor lineData(*DObj, U->getLineSection(), isLittleEndian(),
+                              U->getAddressByteSize());
+  return Line->getOrParseLineTable(lineData, stmtOffset, *this, U,
+                                   RecoverableErrorCallback);
+}
+
+void DWARFContext::parseNormalUnits() {
+  if (!NormalUnits.empty())
+    return;
+  DObj->forEachInfoSections([&](const DWARFSection &S) {
+    NormalUnits.addUnitsForSection(*this, S, DW_SECT_INFO);
+  });
+  NormalUnits.finishedInfoUnits();
+  DObj->forEachTypesSections([&](const DWARFSection &S) {
+    NormalUnits.addUnitsForSection(*this, S, DW_SECT_TYPES);
+  });
+}
+
+void DWARFContext::parseDWOUnits(bool Lazy) {
+  if (!DWOUnits.empty())
+    return;
+  DObj->forEachInfoDWOSections([&](const DWARFSection &S) {
+    DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_INFO, Lazy);
+  });
+  DWOUnits.finishedInfoUnits();
+  DObj->forEachTypesDWOSections([&](const DWARFSection &S) {
+    DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_TYPES, Lazy);
+  });
+}
+
+DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint64_t Offset) {
+  parseNormalUnits();
+  return dyn_cast_or_null<DWARFCompileUnit>(
+      NormalUnits.getUnitForOffset(Offset));
+}
+
+DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) {
+  // First, get the offset of the compile unit.
+  uint64_t CUOffset = getDebugAranges()->findAddress(Address);
+  // Retrieve the compile unit.
+  return getCompileUnitForOffset(CUOffset);
+}
+
+DWARFContext::DIEsForAddress DWARFContext::getDIEsForAddress(uint64_t Address) {
+  DIEsForAddress Result;
+
+  DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
+  if (!CU)
+    return Result;
+
+  Result.CompileUnit = CU;
+  Result.FunctionDIE = CU->getSubroutineForAddress(Address);
+
+  std::vector<DWARFDie> Worklist;
+  Worklist.push_back(Result.FunctionDIE);
+  while (!Worklist.empty()) {
+    DWARFDie DIE = Worklist.back();
+    Worklist.pop_back();
+
+    if (!DIE.isValid())
+      continue;
+
+    if (DIE.getTag() == DW_TAG_lexical_block &&
+        DIE.addressRangeContainsAddress(Address)) {
+      Result.BlockDIE = DIE;
+      break;
+    }
+
+    for (auto Child : DIE)
+      Worklist.push_back(Child);
+  }
+
+  return Result;
+}
+
+/// TODO: change input parameter from "uint64_t Address"
+///       into "SectionedAddress Address"
+static bool getFunctionNameAndStartLineForAddress(DWARFCompileUnit *CU,
+                                                  uint64_t Address,
+                                                  FunctionNameKind Kind,
+                                                  std::string &FunctionName,
+                                                  uint32_t &StartLine) {
+  // The address may correspond to instruction in some inlined function,
+  // so we have to build the chain of inlined functions and take the
+  // name of the topmost function in it.
+  SmallVector<DWARFDie, 4> InlinedChain;
+  CU->getInlinedChainForAddress(Address, InlinedChain);
+  if (InlinedChain.empty())
+    return false;
+
+  const DWARFDie &DIE = InlinedChain[0];
+  bool FoundResult = false;
+  const char *Name = nullptr;
+  if (Kind != FunctionNameKind::None && (Name = DIE.getSubroutineName(Kind))) {
+    FunctionName = Name;
+    FoundResult = true;
+  }
+  if (auto DeclLineResult = DIE.getDeclLine()) {
+    StartLine = DeclLineResult;
+    FoundResult = true;
+  }
+
+  return FoundResult;
+}
+
+static Optional<uint64_t> getTypeSize(DWARFDie Type, uint64_t PointerSize) {
+  if (auto SizeAttr = Type.find(DW_AT_byte_size))
+    if (Optional<uint64_t> Size = SizeAttr->getAsUnsignedConstant())
+      return Size;
+
+  switch (Type.getTag()) {
+  case DW_TAG_pointer_type:
+  case DW_TAG_reference_type:
+  case DW_TAG_rvalue_reference_type:
+    return PointerSize;
+  case DW_TAG_ptr_to_member_type: {
+    if (DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type))
+      if (BaseType.getTag() == DW_TAG_subroutine_type)
+        return 2 * PointerSize;
+    return PointerSize;
+  }
+  case DW_TAG_const_type:
+  case DW_TAG_volatile_type:
+  case DW_TAG_restrict_type:
+  case DW_TAG_typedef: {
+    if (DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type))
+      return getTypeSize(BaseType, PointerSize);
+    break;
+  }
+  case DW_TAG_array_type: {
+    DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type);
+    if (!BaseType)
+      return Optional<uint64_t>();
+    Optional<uint64_t> BaseSize = getTypeSize(BaseType, PointerSize);
+    if (!BaseSize)
+      return Optional<uint64_t>();
+    uint64_t Size = *BaseSize;
+    for (DWARFDie Child : Type) {
+      if (Child.getTag() != DW_TAG_subrange_type)
+        continue;
+
+      if (auto ElemCountAttr = Child.find(DW_AT_count))
+        if (Optional<uint64_t> ElemCount =
+                ElemCountAttr->getAsUnsignedConstant())
+          Size *= *ElemCount;
+      if (auto UpperBoundAttr = Child.find(DW_AT_upper_bound))
+        if (Optional<int64_t> UpperBound =
+                UpperBoundAttr->getAsSignedConstant()) {
+          int64_t LowerBound = 0;
+          if (auto LowerBoundAttr = Child.find(DW_AT_lower_bound))
+            LowerBound = LowerBoundAttr->getAsSignedConstant().getValueOr(0);
+          Size *= *UpperBound - LowerBound + 1;
+        }
+    }
+    return Size;
+  }
+  default:
+    break;
+  }
+  return Optional<uint64_t>();
+}
+
+void DWARFContext::addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram,
+                                   DWARFDie Die, std::vector<DILocal> &Result) {
+  if (Die.getTag() == DW_TAG_variable ||
+      Die.getTag() == DW_TAG_formal_parameter) {
+    DILocal Local;
+    if (auto NameAttr = Subprogram.find(DW_AT_name))
+      if (Optional<const char *> Name = NameAttr->getAsCString())
+        Local.FunctionName = *Name;
+    if (auto LocationAttr = Die.find(DW_AT_location))
+      if (Optional<ArrayRef<uint8_t>> Location = LocationAttr->getAsBlock())
+        if (!Location->empty() && (*Location)[0] == DW_OP_fbreg)
+          Local.FrameOffset =
+              decodeSLEB128(Location->data() + 1, nullptr, Location->end());
+    if (auto TagOffsetAttr = Die.find(DW_AT_LLVM_tag_offset))
+      Local.TagOffset = TagOffsetAttr->getAsUnsignedConstant();
+
+    if (auto Origin =
+            Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin))
+      Die = Origin;
+    if (auto NameAttr = Die.find(DW_AT_name))
+      if (Optional<const char *> Name = NameAttr->getAsCString())
+        Local.Name = *Name;
+    if (auto Type = Die.getAttributeValueAsReferencedDie(DW_AT_type))
+      Local.Size = getTypeSize(Type, getCUAddrSize());
+    if (auto DeclFileAttr = Die.find(DW_AT_decl_file)) {
+      if (const auto *LT = CU->getContext().getLineTableForUnit(CU))
+        LT->getFileNameByIndex(
+            DeclFileAttr->getAsUnsignedConstant().getValue(),
+            CU->getCompilationDir(),
+            DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
+            Local.DeclFile);
+    }
+    if (auto DeclLineAttr = Die.find(DW_AT_decl_line))
+      Local.DeclLine = DeclLineAttr->getAsUnsignedConstant().getValue();
+
+    Result.push_back(Local);
+    return;
+  }
+
+  if (Die.getTag() == DW_TAG_inlined_subroutine)
+    if (auto Origin =
+            Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin))
+      Subprogram = Origin;
+
+  for (auto Child : Die)
+    addLocalsForDie(CU, Subprogram, Child, Result);
+}
+
+std::vector<DILocal>
+DWARFContext::getLocalsForAddress(object::SectionedAddress Address) {
+  std::vector<DILocal> Result;
+  DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address);
+  if (!CU)
+    return Result;
+
+  DWARFDie Subprogram = CU->getSubroutineForAddress(Address.Address);
+  if (Subprogram.isValid())
+    addLocalsForDie(CU, Subprogram, Subprogram, Result);
+  return Result;
+}
+
+DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address,
+                                               DILineInfoSpecifier Spec) {
+  DILineInfo Result;
+
+  DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address);
+  if (!CU)
+    return Result;
+
+  getFunctionNameAndStartLineForAddress(CU, Address.Address, Spec.FNKind,
+                                        Result.FunctionName, Result.StartLine);
+  if (Spec.FLIKind != FileLineInfoKind::None) {
+    if (const DWARFLineTable *LineTable = getLineTableForUnit(CU)) {
+      LineTable->getFileLineInfoForAddress(
+          {Address.Address, Address.SectionIndex}, CU->getCompilationDir(),
+          Spec.FLIKind, Result);
+    }
+  }
+  return Result;
+}
+
+DILineInfoTable DWARFContext::getLineInfoForAddressRange(
+    object::SectionedAddress Address, uint64_t Size, DILineInfoSpecifier Spec) {
+  DILineInfoTable  Lines;
+  DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address);
+  if (!CU)
+    return Lines;
+
+  uint32_t StartLine = 0;
+  std::string FunctionName(DILineInfo::BadString);
+  getFunctionNameAndStartLineForAddress(CU, Address.Address, Spec.FNKind,
+                                        FunctionName, StartLine);
+
+  // If the Specifier says we don't need FileLineInfo, just
+  // return the top-most function at the starting address.
+  if (Spec.FLIKind == FileLineInfoKind::None) {
+    DILineInfo Result;
+    Result.FunctionName = FunctionName;
+    Result.StartLine = StartLine;
+    Lines.push_back(std::make_pair(Address.Address, Result));
+    return Lines;
+  }
+
+  const DWARFLineTable *LineTable = getLineTableForUnit(CU);
+
+  // Get the index of row we're looking for in the line table.
+  std::vector<uint32_t> RowVector;
+  if (!LineTable->lookupAddressRange({Address.Address, Address.SectionIndex},
+                                     Size, RowVector)) {
+    return Lines;
+  }
+
+  for (uint32_t RowIndex : RowVector) {
+    // Take file number and line/column from the row.
+    const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex];
+    DILineInfo Result;
+    LineTable->getFileNameByIndex(Row.File, CU->getCompilationDir(),
+                                  Spec.FLIKind, Result.FileName);
+    Result.FunctionName = FunctionName;
+    Result.Line = Row.Line;
+    Result.Column = Row.Column;
+    Result.StartLine = StartLine;
+    Lines.push_back(std::make_pair(Row.Address.Address, Result));
+  }
+
+  return Lines;
+}
+
+DIInliningInfo
+DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address,
+                                        DILineInfoSpecifier Spec) {
+  DIInliningInfo InliningInfo;
+
+  DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address);
+  if (!CU)
+    return InliningInfo;
+
+  const DWARFLineTable *LineTable = nullptr;
+  SmallVector<DWARFDie, 4> InlinedChain;
+  CU->getInlinedChainForAddress(Address.Address, InlinedChain);
+  if (InlinedChain.size() == 0) {
+    // If there is no DIE for address (e.g. it is in unavailable .dwo file),
+    // try to at least get file/line info from symbol table.
+    if (Spec.FLIKind != FileLineInfoKind::None) {
+      DILineInfo Frame;
+      LineTable = getLineTableForUnit(CU);
+      if (LineTable && LineTable->getFileLineInfoForAddress(
+                           {Address.Address, Address.SectionIndex},
+                           CU->getCompilationDir(), Spec.FLIKind, Frame))
+        InliningInfo.addFrame(Frame);
+    }
+    return InliningInfo;
+  }
+
+  uint32_t CallFile = 0, CallLine = 0, CallColumn = 0, CallDiscriminator = 0;
+  for (uint32_t i = 0, n = InlinedChain.size(); i != n; i++) {
+    DWARFDie &FunctionDIE = InlinedChain[i];
+    DILineInfo Frame;
+    // Get function name if necessary.
+    if (const char *Name = FunctionDIE.getSubroutineName(Spec.FNKind))
+      Frame.FunctionName = Name;
+    if (auto DeclLineResult = FunctionDIE.getDeclLine())
+      Frame.StartLine = DeclLineResult;
+    if (Spec.FLIKind != FileLineInfoKind::None) {
+      if (i == 0) {
+        // For the topmost frame, initialize the line table of this
+        // compile unit and fetch file/line info from it.
+        LineTable = getLineTableForUnit(CU);
+        // For the topmost routine, get file/line info from line table.
+        if (LineTable)
+          LineTable->getFileLineInfoForAddress(
+              {Address.Address, Address.SectionIndex}, CU->getCompilationDir(),
+              Spec.FLIKind, Frame);
+      } else {
+        // Otherwise, use call file, call line and call column from
+        // previous DIE in inlined chain.
+        if (LineTable)
+          LineTable->getFileNameByIndex(CallFile, CU->getCompilationDir(),
+                                        Spec.FLIKind, Frame.FileName);
+        Frame.Line = CallLine;
+        Frame.Column = CallColumn;
+        Frame.Discriminator = CallDiscriminator;
+      }
+      // Get call file/line/column of a current DIE.
+      if (i + 1 < n) {
+        FunctionDIE.getCallerFrame(CallFile, CallLine, CallColumn,
+                                   CallDiscriminator);
+      }
+    }
+    InliningInfo.addFrame(Frame);
+  }
+  return InliningInfo;
+}
+
+std::shared_ptr<DWARFContext>
+DWARFContext::getDWOContext(StringRef AbsolutePath) {
+#if 0
+  if (auto S = DWP.lock()) {
+    DWARFContext *Ctxt = S->Context.get();
+    return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
+  }
+
+  std::weak_ptr<DWOFile> *Entry = &DWOFiles[AbsolutePath];
+
+  if (auto S = Entry->lock()) {
+    DWARFContext *Ctxt = S->Context.get();
+    return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
+  }
+
+  Expected<OwningBinary<ObjectFile>> Obj = [&] {
+    if (!CheckedForDWP) {
+      SmallString<128> DWPName;
+      auto Obj = object::ObjectFile::createObjectFile(
+          this->DWPName.empty()
+              ? (DObj->getFileName() + ".dwp").toStringRef(DWPName)
+              : StringRef(this->DWPName));
+      if (Obj) {
+        Entry = &DWP;
+        return Obj;
+      } else {
+        CheckedForDWP = true;
+        // TODO: Should this error be handled (maybe in a high verbosity mode)
+        // before falling back to .dwo files?
+        consumeError(Obj.takeError());
+      }
+    }
+
+    return object::ObjectFile::createObjectFile(AbsolutePath);
+  }();
+
+  if (!Obj) {
+    // TODO: Actually report errors helpfully.
+    consumeError(Obj.takeError());
+    return nullptr;
+  }
+
+  auto S = std::make_shared<DWOFile>();
+  S->File = std::move(Obj.get());
+  S->Context = DWARFContext::create(*S->File.getBinary());
+  *Entry = S;
+  auto *Ctxt = S->Context.get();
+  return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
+#else
+  llvm_unreachable("XXX BINARYEN DWO");
+#endif
+}
+
+static Error createError(const Twine &Reason, llvm::Error E) {
+  return make_error<StringError>(Reason + toString(std::move(E)),
+                                 inconvertibleErrorCode());
+}
+
+/// SymInfo contains information about symbol: it's address
+/// and section index which is -1LL for absolute symbols.
+struct SymInfo {
+  uint64_t Address;
+  uint64_t SectionIndex;
+};
+
+/// Returns the address of symbol relocation used against and a section index.
+/// Used for futher relocations computation. Symbol's section load address is
+static Expected<SymInfo> getSymbolInfo(const object::ObjectFile &Obj,
+                                       const RelocationRef &Reloc,
+                                       const LoadedObjectInfo *L,
+                                       std::map<SymbolRef, SymInfo> &Cache) {
+  SymInfo Ret = {0, (uint64_t)-1LL};
+  object::section_iterator RSec = Obj.section_end();
+  object::symbol_iterator Sym = Reloc.getSymbol();
+
+  std::map<SymbolRef, SymInfo>::iterator CacheIt = Cache.end();
+  // First calculate the address of the symbol or section as it appears
+  // in the object file
+  if (Sym != Obj.symbol_end()) {
+    bool New;
+    std::tie(CacheIt, New) = Cache.insert({*Sym, {0, 0}});
+    if (!New)
+      return CacheIt->second;
+
+    Expected<uint64_t> SymAddrOrErr = Sym->getAddress();
+    if (!SymAddrOrErr)
+      return createError("failed to compute symbol address: ",
+                         SymAddrOrErr.takeError());
+
+    // Also remember what section this symbol is in for later
+    auto SectOrErr = Sym->getSection();
+    if (!SectOrErr)
+      return createError("failed to get symbol section: ",
+                         SectOrErr.takeError());
+
+    RSec = *SectOrErr;
+    Ret.Address = *SymAddrOrErr;
+#if 0 // XXX BINARYEN
+  } else if (auto *MObj = dyn_cast<MachOObjectFile>(&Obj)) {
+    RSec = MObj->getRelocationSection(Reloc.getRawDataRefImpl());
+    Ret.Address = RSec->getAddress();
+#endif
+  }
+
+  if (RSec != Obj.section_end())
+    Ret.SectionIndex = RSec->getIndex();
+
+  // If we are given load addresses for the sections, we need to adjust:
+  // SymAddr = (Address of Symbol Or Section in File) -
+  //           (Address of Section in File) +
+  //           (Load Address of Section)
+  // RSec is now either the section being targeted or the section
+  // containing the symbol being targeted. In either case,
+  // we need to perform the same computation.
+  if (L && RSec != Obj.section_end())
+    if (uint64_t SectionLoadAddress = L->getSectionLoadAddress(*RSec))
+      Ret.Address += SectionLoadAddress - RSec->getAddress();
+
+  if (CacheIt != Cache.end())
+    CacheIt->second = Ret;
+
+  return Ret;
+}
+
+#if 0 // XXX BINARYEN
+static bool isRelocScattered(const object::ObjectFile &Obj,
+                             const RelocationRef &Reloc) {
+  const MachOObjectFile *MachObj = dyn_cast<MachOObjectFile>(&Obj);
+  if (!MachObj)
+    return false;
+  // MachO also has relocations that point to sections and
+  // scattered relocations.
+  auto RelocInfo = MachObj->getRelocation(Reloc.getRawDataRefImpl());
+  return MachObj->isRelocationScattered(RelocInfo);
+}
+#endif
+
+ErrorPolicy DWARFContext::defaultErrorHandler(Error E) {
+  WithColor::error() << toString(std::move(E)) << '\n';
+  return ErrorPolicy::Continue;
+}
+
+namespace {
+struct DWARFSectionMap final : public DWARFSection {
+  RelocAddrMap Relocs;
+};
+
+class DWARFObjInMemory final : public DWARFObject {
+  bool IsLittleEndian;
+  uint8_t AddressSize;
+  StringRef FileName;
+  const object::ObjectFile *Obj = nullptr;
+  std::vector<SectionName> SectionNames;
+
+  using InfoSectionMap = MapVector<object::SectionRef, DWARFSectionMap,
+                                   std::map<object::SectionRef, unsigned>>;
+
+  InfoSectionMap InfoSections;
+  InfoSectionMap TypesSections;
+  InfoSectionMap InfoDWOSections;
+  InfoSectionMap TypesDWOSections;
+
+  DWARFSectionMap LocSection;
+  DWARFSectionMap LoclistsSection;
+  DWARFSectionMap LineSection;
+  DWARFSectionMap RangesSection;
+  DWARFSectionMap RnglistsSection;
+  DWARFSectionMap StrOffsetsSection;
+  DWARFSectionMap LineDWOSection;
+  DWARFSectionMap FrameSection;
+  DWARFSectionMap EHFrameSection;
+  DWARFSectionMap LocDWOSection;
+  DWARFSectionMap StrOffsetsDWOSection;
+  DWARFSectionMap RangesDWOSection;
+  DWARFSectionMap RnglistsDWOSection;
+  DWARFSectionMap AddrSection;
+  DWARFSectionMap AppleNamesSection;
+  DWARFSectionMap AppleTypesSection;
+  DWARFSectionMap AppleNamespacesSection;
+  DWARFSectionMap AppleObjCSection;
+  DWARFSectionMap NamesSection;
+  DWARFSectionMap PubnamesSection;
+  DWARFSectionMap PubtypesSection;
+  DWARFSectionMap GnuPubnamesSection;
+  DWARFSectionMap GnuPubtypesSection;
+
+  DWARFSectionMap *mapNameToDWARFSection(StringRef Name) {
+    return StringSwitch<DWARFSectionMap *>(Name)
+        .Case("debug_loc", &LocSection)
+        .Case("debug_loclists", &LoclistsSection)
+        .Case("debug_line", &LineSection)
+        .Case("debug_frame", &FrameSection)
+        .Case("eh_frame", &EHFrameSection)
+        .Case("debug_str_offsets", &StrOffsetsSection)
+        .Case("debug_ranges", &RangesSection)
+        .Case("debug_rnglists", &RnglistsSection)
+        .Case("debug_loc.dwo", &LocDWOSection)
+        .Case("debug_line.dwo", &LineDWOSection)
+        .Case("debug_names", &NamesSection)
+        .Case("debug_rnglists.dwo", &RnglistsDWOSection)
+        .Case("debug_str_offsets.dwo", &StrOffsetsDWOSection)
+        .Case("debug_addr", &AddrSection)
+        .Case("apple_names", &AppleNamesSection)
+        .Case("debug_pubnames", &PubnamesSection)
+        .Case("debug_pubtypes", &PubtypesSection)
+        .Case("debug_gnu_pubnames", &GnuPubnamesSection)
+        .Case("debug_gnu_pubtypes", &GnuPubtypesSection)
+        .Case("apple_types", &AppleTypesSection)
+        .Case("apple_namespaces", &AppleNamespacesSection)
+        .Case("apple_namespac", &AppleNamespacesSection)
+        .Case("apple_objc", &AppleObjCSection)
+        .Default(nullptr);
+  }
+
+  StringRef AbbrevSection;
+  StringRef ArangesSection;
+  StringRef StrSection;
+  StringRef MacinfoSection;
+  StringRef AbbrevDWOSection;
+  StringRef StrDWOSection;
+  StringRef CUIndexSection;
+  StringRef GdbIndexSection;
+  StringRef TUIndexSection;
+  StringRef LineStrSection;
+
+  // A deque holding section data whose iterators are not invalidated when
+  // new decompressed sections are inserted at the end.
+  std::deque<SmallString<0>> UncompressedSections;
+
+  StringRef *mapSectionToMember(StringRef Name) {
+    if (DWARFSection *Sec = mapNameToDWARFSection(Name))
+      return &Sec->Data;
+    return StringSwitch<StringRef *>(Name)
+        .Case("debug_abbrev", &AbbrevSection)
+        .Case("debug_aranges", &ArangesSection)
+        .Case("debug_str", &StrSection)
+        .Case("debug_macinfo", &MacinfoSection)
+        .Case("debug_abbrev.dwo", &AbbrevDWOSection)
+        .Case("debug_str.dwo", &StrDWOSection)
+        .Case("debug_cu_index", &CUIndexSection)
+        .Case("debug_tu_index", &TUIndexSection)
+        .Case("gdb_index", &GdbIndexSection)
+        .Case("debug_line_str", &LineStrSection)
+        // Any more debug info sections go here.
+        .Default(nullptr);
+  }
+
+  /// If Sec is compressed section, decompresses and updates its contents
+  /// provided by Data. Otherwise leaves it unchanged.
+  Error maybeDecompress(const object::SectionRef &Sec, StringRef Name,
+                        StringRef &Data) {
+#if 1 // XXX BINARYEN
+    errs() << "maybeDecompress?\n";
+    return Error::success();
+#else
+    if (!Decompressor::isCompressed(Sec))
+      return Error::success();
+
+    Expected<Decompressor> Decompressor =
+        Decompressor::create(Name, Data, IsLittleEndian, AddressSize == 8);
+    if (!Decompressor)
+      return Decompressor.takeError();
+
+    SmallString<0> Out;
+    if (auto Err = Decompressor->resizeAndDecompress(Out))
+      return Err;
+
+    UncompressedSections.push_back(std::move(Out));
+    Data = UncompressedSections.back();
+
+    return Error::success();
+#endif
+  }
+
+public:
+  DWARFObjInMemory(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
+                   uint8_t AddrSize, bool IsLittleEndian)
+      : IsLittleEndian(IsLittleEndian),
+        AddressSize(4) // XXX BINARYEN
+  {
+    for (const auto &SecIt : Sections) {
+      if (StringRef *SectionData = mapSectionToMember(SecIt.first()))
+        *SectionData = SecIt.second->getBuffer();
+      else if (SecIt.first() == "debug_info")
+        // Find debug_info and debug_types data by section rather than name as
+        // there are multiple, comdat grouped, of these sections.
+        InfoSections[SectionRef()].Data = SecIt.second->getBuffer();
+      else if (SecIt.first() == "debug_info.dwo")
+        InfoDWOSections[SectionRef()].Data = SecIt.second->getBuffer();
+      else if (SecIt.first() == "debug_types")
+        TypesSections[SectionRef()].Data = SecIt.second->getBuffer();
+      else if (SecIt.first() == "debug_types.dwo")
+        TypesDWOSections[SectionRef()].Data = SecIt.second->getBuffer();
+    }
+  }
+  DWARFObjInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L,
+                   function_ref<ErrorPolicy(Error)> HandleError)
+      : IsLittleEndian(Obj.isLittleEndian()),
+        AddressSize(Obj.getBytesInAddress()), FileName(Obj.getFileName()),
+        Obj(&Obj) {
+
+    StringMap<unsigned> SectionAmountMap;
+    for (const SectionRef &Section : Obj.sections()) {
+      StringRef Name;
+      if (auto NameOrErr = Section.getName())
+        Name = *NameOrErr;
+      else
+        consumeError(NameOrErr.takeError());
+
+      ++SectionAmountMap[Name];
+      SectionNames.push_back({ Name, true });
+
+      // Skip BSS and Virtual sections, they aren't interesting.
+      if (Section.isBSS() || Section.isVirtual())
+        continue;
+
+      // Skip sections stripped by dsymutil.
+      if (Section.isStripped())
+        continue;
+
+      StringRef Data;
+      Expected<section_iterator> SecOrErr = Section.getRelocatedSection();
+      if (!SecOrErr) {
+        ErrorPolicy EP = HandleError(createError(
+            "failed to get relocated section: ", SecOrErr.takeError()));
+        if (EP == ErrorPolicy::Halt)
+          return;
+        continue;
+      }
+
+      // Try to obtain an already relocated version of this section.
+      // Else use the unrelocated section from the object file. We'll have to
+      // apply relocations ourselves later.
+      section_iterator RelocatedSection = *SecOrErr;
+      if (!L || !L->getLoadedSectionContents(*RelocatedSection, Data)) {
+        Expected<StringRef> E = Section.getContents();
+        if (E)
+          Data = *E;
+        else
+          // maybeDecompress below will error.
+          consumeError(E.takeError());
+      }
+
+      if (auto Err = maybeDecompress(Section, Name, Data)) {
+        ErrorPolicy EP = HandleError(createError(
+            "failed to decompress '" + Name + "', ", std::move(Err)));
+        if (EP == ErrorPolicy::Halt)
+          return;
+        continue;
+      }
+
+      // Compressed sections names in GNU style starts from ".z",
+      // at this point section is decompressed and we drop compression prefix.
+      Name = Name.substr(
+          Name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes.
+
+      // Map platform specific debug section names to DWARF standard section
+      // names.
+      Name = Obj.mapDebugSectionName(Name);
+
+      if (StringRef *SectionData = mapSectionToMember(Name)) {
+        *SectionData = Data;
+        if (Name == "debug_ranges") {
+          // FIXME: Use the other dwo range section when we emit it.
+          RangesDWOSection.Data = Data;
+        }
+      } else if (Name == "debug_info") {
+        // Find debug_info and debug_types data by section rather than name as
+        // there are multiple, comdat grouped, of these sections.
+        InfoSections[Section].Data = Data;
+      } else if (Name == "debug_info.dwo") {
+        InfoDWOSections[Section].Data = Data;
+      } else if (Name == "debug_types") {
+        TypesSections[Section].Data = Data;
+      } else if (Name == "debug_types.dwo") {
+        TypesDWOSections[Section].Data = Data;
+      }
+
+      if (RelocatedSection == Obj.section_end())
+        continue;
+
+      StringRef RelSecName;
+      if (auto NameOrErr = RelocatedSection->getName())
+        RelSecName = *NameOrErr;
+      else
+        consumeError(NameOrErr.takeError());
+
+      // If the section we're relocating was relocated already by the JIT,
+      // then we used the relocated version above, so we do not need to process
+      // relocations for it now.
+      StringRef RelSecData;
+      if (L && L->getLoadedSectionContents(*RelocatedSection, RelSecData))
+        continue;
+
+      // In Mach-o files, the relocations do not need to be applied if
+      // there is no load offset to apply. The value read at the
+      // relocation point already factors in the section address
+      // (actually applying the relocations will produce wrong results
+      // as the section address will be added twice).
+      if (!L && isa<MachOObjectFile>(&Obj))
+        continue;
+
+      RelSecName = RelSecName.substr(
+          RelSecName.find_first_not_of("._z")); // Skip . and _ prefixes.
+
+      // TODO: Add support for relocations in other sections as needed.
+      // Record relocations for the debug_info and debug_line sections.
+      DWARFSectionMap *Sec = mapNameToDWARFSection(RelSecName);
+      RelocAddrMap *Map = Sec ? &Sec->Relocs : nullptr;
+      if (!Map) {
+        // Find debug_info and debug_types relocs by section rather than name
+        // as there are multiple, comdat grouped, of these sections.
+        if (RelSecName == "debug_info")
+          Map = &static_cast<DWARFSectionMap &>(InfoSections[*RelocatedSection])
+                     .Relocs;
+        else if (RelSecName == "debug_info.dwo")
+          Map = &static_cast<DWARFSectionMap &>(
+                     InfoDWOSections[*RelocatedSection])
+                     .Relocs;
+        else if (RelSecName == "debug_types")
+          Map =
+              &static_cast<DWARFSectionMap &>(TypesSections[*RelocatedSection])
+                   .Relocs;
+        else if (RelSecName == "debug_types.dwo")
+          Map = &static_cast<DWARFSectionMap &>(
+                     TypesDWOSections[*RelocatedSection])
+                     .Relocs;
+        else
+          continue;
+      }
+
+      if (Section.relocation_begin() == Section.relocation_end())
+        continue;
+
+#if 1 // XXX BINARYEN
+      errs() << "relocation?\n";
+#else
+      // Symbol to [address, section index] cache mapping.
+      std::map<SymbolRef, SymInfo> AddrCache;
+      bool (*Supports)(uint64_t);
+      RelocationResolver Resolver;
+      std::tie(Supports, Resolver) = getRelocationResolver(Obj);
+      for (const RelocationRef &Reloc : Section.relocations()) {
+        // FIXME: it's not clear how to correctly handle scattered
+        // relocations.
+        if (isRelocScattered(Obj, Reloc))
+          continue;
+
+        Expected<SymInfo> SymInfoOrErr =
+            getSymbolInfo(Obj, Reloc, L, AddrCache);
+        if (!SymInfoOrErr) {
+          if (HandleError(SymInfoOrErr.takeError()) == ErrorPolicy::Halt)
+            return;
+          continue;
+        }
+
+        // Check if Resolver can handle this relocation type early so as not to
+        // handle invalid cases in DWARFDataExtractor.
+        //
+        // TODO Don't store Resolver in every RelocAddrEntry.
+        if (Supports && Supports(Reloc.getType())) {
+          auto I = Map->try_emplace(
+              Reloc.getOffset(),
+              RelocAddrEntry{SymInfoOrErr->SectionIndex, Reloc,
+                             SymInfoOrErr->Address,
+                             Optional<object::RelocationRef>(), 0, Resolver});
+          // If we didn't successfully insert that's because we already had a
+          // relocation for that offset. Store it as a second relocation in the
+          // same RelocAddrEntry instead.
+          if (!I.second) {
+            RelocAddrEntry &entry = I.first->getSecond();
+            if (entry.Reloc2) {
+              ErrorPolicy EP = HandleError(createError(
+                  "At most two relocations per offset are supported"));
+              if (EP == ErrorPolicy::Halt)
+                return;
+            }
+            entry.Reloc2 = Reloc;
+            entry.SymbolValue2 = SymInfoOrErr->Address;
+          }
+        } else {
+          SmallString<32> Type;
+          Reloc.getTypeName(Type);
+          ErrorPolicy EP = HandleError(
+              createError("failed to compute relocation: " + Type + ", ",
+                          errorCodeToError(object_error::parse_failed)));
+          if (EP == ErrorPolicy::Halt)
+            return;
+        }
+      }
+#endif
+    }
+
+    for (SectionName &S : SectionNames)
+      if (SectionAmountMap[S.Name] > 1)
+        S.IsNameUnique = false;
+  }
+
+  Optional<RelocAddrEntry> find(const DWARFSection &S,
+                                uint64_t Pos) const override {
+    auto &Sec = static_cast<const DWARFSectionMap &>(S);
+    RelocAddrMap::const_iterator AI = Sec.Relocs.find(Pos);
+    if (AI == Sec.Relocs.end())
+      return None;
+    return AI->second;
+  }
+
+  const object::ObjectFile *getFile() const override { return Obj; }
+
+  ArrayRef<SectionName> getSectionNames() const override {
+    return SectionNames;
+  }
+
+  bool isLittleEndian() const override { return IsLittleEndian; }
+  StringRef getAbbrevDWOSection() const override { return AbbrevDWOSection; }
+  const DWARFSection &getLineDWOSection() const override {
+    return LineDWOSection;
+  }
+  const DWARFSection &getLocDWOSection() const override {
+    return LocDWOSection;
+  }
+  StringRef getStrDWOSection() const override { return StrDWOSection; }
+  const DWARFSection &getStrOffsetsDWOSection() const override {
+    return StrOffsetsDWOSection;
+  }
+  const DWARFSection &getRangesDWOSection() const override {
+    return RangesDWOSection;
+  }
+  const DWARFSection &getRnglistsDWOSection() const override {
+    return RnglistsDWOSection;
+  }
+  const DWARFSection &getAddrSection() const override { return AddrSection; }
+  StringRef getCUIndexSection() const override { return CUIndexSection; }
+  StringRef getGdbIndexSection() const override { return GdbIndexSection; }
+  StringRef getTUIndexSection() const override { return TUIndexSection; }
+
+  // DWARF v5
+  const DWARFSection &getStrOffsetsSection() const override {
+    return StrOffsetsSection;
+  }
+  StringRef getLineStrSection() const override { return LineStrSection; }
+
+  // Sections for DWARF5 split dwarf proposal.
+  void forEachInfoDWOSections(
+      function_ref<void(const DWARFSection &)> F) const override {
+    for (auto &P : InfoDWOSections)
+      F(P.second);
+  }
+  void forEachTypesDWOSections(
+      function_ref<void(const DWARFSection &)> F) const override {
+    for (auto &P : TypesDWOSections)
+      F(P.second);
+  }
+
+  StringRef getAbbrevSection() const override { return AbbrevSection; }
+  const DWARFSection &getLocSection() const override { return LocSection; }
+  const DWARFSection &getLoclistsSection() const override { return LoclistsSection; }
+  StringRef getArangesSection() const override { return ArangesSection; }
+  const DWARFSection &getFrameSection() const override {
+    return FrameSection;
+  }
+  const DWARFSection &getEHFrameSection() const override {
+    return EHFrameSection;
+  }
+  const DWARFSection &getLineSection() const override { return LineSection; }
+  StringRef getStrSection() const override { return StrSection; }
+  const DWARFSection &getRangesSection() const override { return RangesSection; }
+  const DWARFSection &getRnglistsSection() const override {
+    return RnglistsSection;
+  }
+  StringRef getMacinfoSection() const override { return MacinfoSection; }
+  const DWARFSection &getPubnamesSection() const override { return PubnamesSection; }
+  const DWARFSection &getPubtypesSection() const override { return PubtypesSection; }
+  const DWARFSection &getGnuPubnamesSection() const override {
+    return GnuPubnamesSection;
+  }
+  const DWARFSection &getGnuPubtypesSection() const override {
+    return GnuPubtypesSection;
+  }
+  const DWARFSection &getAppleNamesSection() const override {
+    return AppleNamesSection;
+  }
+  const DWARFSection &getAppleTypesSection() const override {
+    return AppleTypesSection;
+  }
+  const DWARFSection &getAppleNamespacesSection() const override {
+    return AppleNamespacesSection;
+  }
+  const DWARFSection &getAppleObjCSection() const override {
+    return AppleObjCSection;
+  }
+  const DWARFSection &getNamesSection() const override {
+    return NamesSection;
+  }
+
+  StringRef getFileName() const override { return FileName; }
+  uint8_t getAddressSize() const override { return AddressSize; }
+  void forEachInfoSections(
+      function_ref<void(const DWARFSection &)> F) const override {
+    for (auto &P : InfoSections)
+      F(P.second);
+  }
+  void forEachTypesSections(
+      function_ref<void(const DWARFSection &)> F) const override {
+    for (auto &P : TypesSections)
+      F(P.second);
+  }
+};
+} // namespace
+
+#if 0 // XXX BINARYEN
+std::unique_ptr<DWARFContext>
+DWARFContext::create(const object::ObjectFile &Obj, const LoadedObjectInfo *L,
+                     function_ref<ErrorPolicy(Error)> HandleError,
+                     std::string DWPName) {
+  auto DObj = std::make_unique<DWARFObjInMemory>(Obj, L, HandleError);
+  return std::make_unique<DWARFContext>(std::move(DObj), std::move(DWPName));
+}
+#endif
+
+std::unique_ptr<DWARFContext>
+DWARFContext::create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
+                     uint8_t AddrSize, bool isLittleEndian) {
+  auto DObj =
+      std::make_unique<DWARFObjInMemory>(Sections, AddrSize, isLittleEndian);
+  return std::make_unique<DWARFContext>(std::move(DObj), "");
+}
+
+Error DWARFContext::loadRegisterInfo(const object::ObjectFile &Obj) {
+  llvm_unreachable("loadRegisterInfo"); // XXX BINARYEN
+}
+
+uint8_t DWARFContext::getCUAddrSize() {
+  // In theory, different compile units may have different address byte
+  // sizes, but for simplicity we just use the address byte size of the
+  // last compile unit. In practice the address size field is repeated across
+  // various DWARF headers (at least in version 5) to make it easier to dump
+  // them independently, not to enable varying the address size.
+  uint8_t Addr = 0;
+  for (const auto &CU : compile_units()) {
+    Addr = CU->getAddressByteSize();
+    break;
+  }
+  return Addr;
+}
+
+void DWARFContext::dumpWarning(Error Warning) {
+  handleAllErrors(std::move(Warning), [](ErrorInfoBase &Info) {
+      WithColor::warning() << Info.message() << '\n';
+  });
+}
diff --git a/binaryen/third_party/llvm-project/DWARFDataExtractor.cpp b/binaryen/third_party/llvm-project/DWARFDataExtractor.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFDataExtractor.cpp
@@ -0,0 +1,100 @@
+//===- DWARFDataExtractor.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+
+using namespace llvm;
+
+uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint64_t *Off,
+                                               uint64_t *SecNdx,
+                                               Error *Err) const {
+  if (SecNdx)
+    *SecNdx = object::SectionedAddress::UndefSection;
+  if (!Section)
+    return getUnsigned(Off, Size, Err);
+  Optional<RelocAddrEntry> E = Obj->find(*Section, *Off);
+  uint64_t A = getUnsigned(Off, Size, Err);
+  if (!E)
+    return A;
+  if (SecNdx)
+    *SecNdx = E->SectionIndex;
+  uint64_t R = E->Resolver(E->Reloc, E->SymbolValue, A);
+  if (E->Reloc2)
+    R = E->Resolver(*E->Reloc2, E->SymbolValue2, R);
+  return R;
+}
+
+Optional<uint64_t>
+DWARFDataExtractor::getEncodedPointer(uint64_t *Offset, uint8_t Encoding,
+                                      uint64_t PCRelOffset) const {
+  if (Encoding == dwarf::DW_EH_PE_omit)
+    return None;
+
+  uint64_t Result = 0;
+  uint64_t OldOffset = *Offset;
+  // First get value
+  switch (Encoding & 0x0F) {
+  case dwarf::DW_EH_PE_absptr:
+    switch (getAddressSize()) {
+    case 2:
+    case 4:
+    case 8:
+      Result = getUnsigned(Offset, getAddressSize());
+      break;
+    default:
+      return None;
+    }
+    break;
+  case dwarf::DW_EH_PE_uleb128:
+    Result = getULEB128(Offset);
+    break;
+  case dwarf::DW_EH_PE_sleb128:
+    Result = getSLEB128(Offset);
+    break;
+  case dwarf::DW_EH_PE_udata2:
+    Result = getUnsigned(Offset, 2);
+    break;
+  case dwarf::DW_EH_PE_udata4:
+    Result = getUnsigned(Offset, 4);
+    break;
+  case dwarf::DW_EH_PE_udata8:
+    Result = getUnsigned(Offset, 8);
+    break;
+  case dwarf::DW_EH_PE_sdata2:
+    Result = getSigned(Offset, 2);
+    break;
+  case dwarf::DW_EH_PE_sdata4:
+    Result = getSigned(Offset, 4);
+    break;
+  case dwarf::DW_EH_PE_sdata8:
+    Result = getSigned(Offset, 8);
+    break;
+  default:
+    return None;
+  }
+  // Then add relative offset, if required
+  switch (Encoding & 0x70) {
+  case dwarf::DW_EH_PE_absptr:
+    // do nothing
+    break;
+  case dwarf::DW_EH_PE_pcrel:
+    Result += PCRelOffset;
+    break;
+  case dwarf::DW_EH_PE_datarel:
+  case dwarf::DW_EH_PE_textrel:
+  case dwarf::DW_EH_PE_funcrel:
+  case dwarf::DW_EH_PE_aligned:
+  default:
+    *Offset = OldOffset;
+    return None;
+  }
+
+  return Result;
+}
diff --git a/binaryen/third_party/llvm-project/DWARFDebugAbbrev.cpp b/binaryen/third_party/llvm-project/DWARFDebugAbbrev.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFDebugAbbrev.cpp
@@ -0,0 +1,138 @@
+//===- DWARFDebugAbbrev.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cinttypes>
+#include <cstdint>
+
+using namespace llvm;
+
+DWARFAbbreviationDeclarationSet::DWARFAbbreviationDeclarationSet() {
+  clear();
+}
+
+void DWARFAbbreviationDeclarationSet::clear() {
+  Offset = 0;
+  FirstAbbrCode = 0;
+  Decls.clear();
+}
+
+bool DWARFAbbreviationDeclarationSet::extract(DataExtractor Data,
+                                              uint64_t *OffsetPtr) {
+  clear();
+  const uint64_t BeginOffset = *OffsetPtr;
+  Offset = BeginOffset;
+  DWARFAbbreviationDeclaration AbbrDecl;
+  uint32_t PrevAbbrCode = 0;
+  while (AbbrDecl.extract(Data, OffsetPtr)) {
+    if (FirstAbbrCode == 0) {
+      FirstAbbrCode = AbbrDecl.getCode();
+    } else {
+      if (PrevAbbrCode + 1 != AbbrDecl.getCode()) {
+        // Codes are not consecutive, can't do O(1) lookups.
+        FirstAbbrCode = UINT32_MAX;
+      }
+    }
+    PrevAbbrCode = AbbrDecl.getCode();
+    Decls.push_back(std::move(AbbrDecl));
+  }
+  return BeginOffset != *OffsetPtr;
+}
+
+void DWARFAbbreviationDeclarationSet::dump(raw_ostream &OS) const {
+  for (const auto &Decl : Decls)
+    Decl.dump(OS);
+}
+
+const DWARFAbbreviationDeclaration *
+DWARFAbbreviationDeclarationSet::getAbbreviationDeclaration(
+    uint32_t AbbrCode) const {
+  if (FirstAbbrCode == UINT32_MAX) {
+    for (const auto &Decl : Decls) {
+      if (Decl.getCode() == AbbrCode)
+        return &Decl;
+    }
+    return nullptr;
+  }
+  if (AbbrCode < FirstAbbrCode || AbbrCode >= FirstAbbrCode + Decls.size())
+    return nullptr;
+  return &Decls[AbbrCode - FirstAbbrCode];
+}
+
+DWARFDebugAbbrev::DWARFDebugAbbrev() { clear(); }
+
+void DWARFDebugAbbrev::clear() {
+  AbbrDeclSets.clear();
+  PrevAbbrOffsetPos = AbbrDeclSets.end();
+}
+
+void DWARFDebugAbbrev::extract(DataExtractor Data) {
+  clear();
+  this->Data = Data;
+}
+
+void DWARFDebugAbbrev::parse() const {
+  if (!Data)
+    return;
+  uint64_t Offset = 0;
+  auto I = AbbrDeclSets.begin();
+  while (Data->isValidOffset(Offset)) {
+    while (I != AbbrDeclSets.end() && I->first < Offset)
+      ++I;
+    uint64_t CUAbbrOffset = Offset;
+    DWARFAbbreviationDeclarationSet AbbrDecls;
+    if (!AbbrDecls.extract(*Data, &Offset))
+      break;
+    AbbrDeclSets.insert(I, std::make_pair(CUAbbrOffset, std::move(AbbrDecls)));
+  }
+  Data = None;
+}
+
+void DWARFDebugAbbrev::dump(raw_ostream &OS) const {
+  parse();
+
+  if (AbbrDeclSets.empty()) {
+    OS << "< EMPTY >\n";
+    return;
+  }
+
+  for (const auto &I : AbbrDeclSets) {
+    OS << format("Abbrev table for offset: 0x%8.8" PRIx64 "\n", I.first);
+    I.second.dump(OS);
+  }
+}
+
+const DWARFAbbreviationDeclarationSet*
+DWARFDebugAbbrev::getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const {
+  const auto End = AbbrDeclSets.end();
+  if (PrevAbbrOffsetPos != End && PrevAbbrOffsetPos->first == CUAbbrOffset) {
+    return &(PrevAbbrOffsetPos->second);
+  }
+
+  const auto Pos = AbbrDeclSets.find(CUAbbrOffset);
+  if (Pos != End) {
+    PrevAbbrOffsetPos = Pos;
+    return &(Pos->second);
+  }
+
+  if (Data && CUAbbrOffset < Data->getData().size()) {
+    uint64_t Offset = CUAbbrOffset;
+    DWARFAbbreviationDeclarationSet AbbrDecls;
+    if (!AbbrDecls.extract(*Data, &Offset))
+      return nullptr;
+    PrevAbbrOffsetPos =
+        AbbrDeclSets.insert(std::make_pair(CUAbbrOffset, std::move(AbbrDecls)))
+            .first;
+    return &PrevAbbrOffsetPos->second;
+  }
+
+  return nullptr;
+}
diff --git a/binaryen/third_party/llvm-project/DWARFDebugAddr.cpp b/binaryen/third_party/llvm-project/DWARFDebugAddr.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFDebugAddr.cpp
@@ -0,0 +1,182 @@
+//===- DWARFDebugAddr.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+
+using namespace llvm;
+
+void DWARFDebugAddrTable::clear() {
+  HeaderData = {};
+  Addrs.clear();
+  invalidateLength();
+}
+
+Error DWARFDebugAddrTable::extract(DWARFDataExtractor Data,
+                                   uint64_t *OffsetPtr,
+                                   uint16_t Version,
+                                   uint8_t AddrSize,
+                                   std::function<void(Error)> WarnCallback) {
+  clear();
+  HeaderOffset = *OffsetPtr;
+  // Read and verify the length field.
+  if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t)))
+    return createStringError(errc::invalid_argument,
+                       "section is not large enough to contain a "
+                       ".debug_addr table length at offset 0x%"
+                       PRIx64, *OffsetPtr);
+  uint16_t UnitVersion;
+  if (Version == 0) {
+    WarnCallback(createStringError(errc::invalid_argument,
+                       "DWARF version is not defined in CU,"
+                       " assuming version 5"));
+    UnitVersion = 5;
+  } else {
+    UnitVersion = Version;
+  }
+  // TODO: Add support for DWARF64.
+  Format = dwarf::DwarfFormat::DWARF32;
+  if (UnitVersion >= 5) {
+    HeaderData.Length = Data.getU32(OffsetPtr);
+    if (HeaderData.Length == dwarf::DW_LENGTH_DWARF64) {
+      invalidateLength();
+      return createStringError(errc::not_supported,
+          "DWARF64 is not supported in .debug_addr at offset 0x%" PRIx64,
+          HeaderOffset);
+    }
+    if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) {
+      uint32_t TmpLength = getLength();
+      invalidateLength();
+      return createStringError(errc::invalid_argument,
+                         ".debug_addr table at offset 0x%" PRIx64
+                         " has too small length (0x%" PRIx32
+                         ") to contain a complete header",
+                         HeaderOffset, TmpLength);
+    }
+    uint64_t End = HeaderOffset + getLength();
+    if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) {
+      uint32_t TmpLength = getLength();
+      invalidateLength();
+      return createStringError(errc::invalid_argument,
+          "section is not large enough to contain a .debug_addr table "
+          "of length 0x%" PRIx32 " at offset 0x%" PRIx64,
+          TmpLength, HeaderOffset);
+    }
+
+    HeaderData.Version = Data.getU16(OffsetPtr);
+    HeaderData.AddrSize = Data.getU8(OffsetPtr);
+    HeaderData.SegSize = Data.getU8(OffsetPtr);
+    DataSize = getDataSize();
+  } else {
+    HeaderData.Version = UnitVersion;
+    HeaderData.AddrSize = AddrSize;
+    // TODO: Support for non-zero SegSize.
+    HeaderData.SegSize = 0;
+    DataSize = Data.size();
+  }
+
+  // Perform basic validation of the remaining header fields.
+
+  // We support DWARF version 5 for now as well as pre-DWARF5
+  // implementations of .debug_addr table, which doesn't contain a header
+  // and consists only of a series of addresses.
+  if (HeaderData.Version > 5) {
+    return createStringError(errc::not_supported, "version %" PRIu16
+        " of .debug_addr section at offset 0x%" PRIx64 " is not supported",
+        HeaderData.Version, HeaderOffset);
+  }
+  // FIXME: For now we just treat version mismatch as an error,
+  // however the correct way to associate a .debug_addr table
+  // with a .debug_info table is to look at the DW_AT_addr_base
+  // attribute in the info table.
+  if (HeaderData.Version != UnitVersion)
+    return createStringError(errc::invalid_argument,
+                       ".debug_addr table at offset 0x%" PRIx64
+                       " has version %" PRIu16
+                       " which is different from the version suggested"
+                       " by the DWARF unit header: %" PRIu16,
+                       HeaderOffset, HeaderData.Version, UnitVersion);
+  if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
+    return createStringError(errc::not_supported,
+                       ".debug_addr table at offset 0x%" PRIx64
+                       " has unsupported address size %" PRIu8,
+                       HeaderOffset, HeaderData.AddrSize);
+  if (HeaderData.AddrSize != AddrSize && AddrSize != 0)
+    return createStringError(errc::invalid_argument,
+                       ".debug_addr table at offset 0x%" PRIx64
+                       " has address size %" PRIu8
+                       " which is different from CU address size %" PRIu8,
+                       HeaderOffset, HeaderData.AddrSize, AddrSize);
+
+  // TODO: add support for non-zero segment selector size.
+  if (HeaderData.SegSize != 0)
+    return createStringError(errc::not_supported,
+                       ".debug_addr table at offset 0x%" PRIx64
+                       " has unsupported segment selector size %" PRIu8,
+                       HeaderOffset, HeaderData.SegSize);
+  if (DataSize % HeaderData.AddrSize != 0) {
+    invalidateLength();
+    return createStringError(errc::invalid_argument,
+                       ".debug_addr table at offset 0x%" PRIx64
+                       " contains data of size %" PRIu32
+                       " which is not a multiple of addr size %" PRIu8,
+                       HeaderOffset, DataSize, HeaderData.AddrSize);
+  }
+  Data.setAddressSize(HeaderData.AddrSize);
+  uint32_t AddrCount = DataSize / HeaderData.AddrSize;
+  for (uint32_t I = 0; I < AddrCount; ++I)
+    if (HeaderData.AddrSize == 4)
+      Addrs.push_back(Data.getU32(OffsetPtr));
+    else
+      Addrs.push_back(Data.getU64(OffsetPtr));
+  return Error::success();
+}
+
+void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
+  if (DumpOpts.Verbose)
+    OS << format("0x%8.8" PRIx32 ": ", HeaderOffset);
+  OS << format("Addr Section: length = 0x%8.8" PRIx32
+               ", version = 0x%4.4" PRIx16 ", "
+               "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 "\n",
+               HeaderData.Length, HeaderData.Version, HeaderData.AddrSize,
+               HeaderData.SegSize);
+
+  if (Addrs.size() > 0) {
+    const char *AddrFmt = (HeaderData.AddrSize == 4) ? "0x%8.8" PRIx64 "\n"
+                                                     : "0x%16.16" PRIx64 "\n";
+    OS << "Addrs: [\n";
+    for (uint64_t Addr : Addrs)
+      OS << format(AddrFmt, Addr);
+    OS << "]\n";
+  }
+}
+
+Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {
+  if (Index < Addrs.size())
+    return Addrs[Index];
+  return createStringError(errc::invalid_argument,
+                           "Index %" PRIu32 " is out of range of the "
+                           ".debug_addr table at offset 0x%" PRIx64,
+                           Index, HeaderOffset);
+}
+
+uint32_t DWARFDebugAddrTable::getLength() const {
+  if (HeaderData.Length == 0)
+    return 0;
+  // TODO: DWARF64 support.
+  return HeaderData.Length + sizeof(uint32_t);
+}
+
+uint32_t DWARFDebugAddrTable::getDataSize() const {
+  if (DataSize != 0)
+    return DataSize;
+  if (getLength() == 0)
+    return 0;
+  return getLength() - getHeaderSize();
+}
diff --git a/binaryen/third_party/llvm-project/DWARFDebugArangeSet.cpp b/binaryen/third_party/llvm-project/DWARFDebugArangeSet.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFDebugArangeSet.cpp
@@ -0,0 +1,111 @@
+//===- DWARFDebugArangeSet.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <cstring>
+
+using namespace llvm;
+
+void DWARFDebugArangeSet::Descriptor::dump(raw_ostream &OS,
+                                           uint32_t AddressSize) const {
+  OS << format("[0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2, Address)
+     << format(" 0x%*.*" PRIx64 ")", AddressSize * 2, AddressSize * 2,
+               getEndAddress());
+}
+
+void DWARFDebugArangeSet::clear() {
+  Offset = -1ULL;
+  std::memset(&HeaderData, 0, sizeof(Header));
+  ArangeDescriptors.clear();
+}
+
+bool
+DWARFDebugArangeSet::extract(DataExtractor data, uint64_t *offset_ptr) {
+  if (data.isValidOffset(*offset_ptr)) {
+    ArangeDescriptors.clear();
+    Offset = *offset_ptr;
+
+    // 7.20 Address Range Table
+    //
+    // Each set of entries in the table of address ranges contained in
+    // the .debug_aranges section begins with a header consisting of: a
+    // 4-byte length containing the length of the set of entries for this
+    // compilation unit, not including the length field itself; a 2-byte
+    // version identifier containing the value 2 for DWARF Version 2; a
+    // 4-byte offset into the.debug_infosection; a 1-byte unsigned integer
+    // containing the size in bytes of an address (or the offset portion of
+    // an address for segmented addressing) on the target system; and a
+    // 1-byte unsigned integer containing the size in bytes of a segment
+    // descriptor on the target system. This header is followed by a series
+    // of tuples. Each tuple consists of an address and a length, each in
+    // the size appropriate for an address on the target architecture.
+    HeaderData.Length = data.getU32(offset_ptr);
+    HeaderData.Version = data.getU16(offset_ptr);
+    HeaderData.CuOffset = data.getU32(offset_ptr);
+    HeaderData.AddrSize = data.getU8(offset_ptr);
+    HeaderData.SegSize = data.getU8(offset_ptr);
+
+    // Perform basic validation of the header fields.
+    if (!data.isValidOffsetForDataOfSize(Offset, HeaderData.Length) ||
+        (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)) {
+      clear();
+      return false;
+    }
+
+    // The first tuple following the header in each set begins at an offset
+    // that is a multiple of the size of a single tuple (that is, twice the
+    // size of an address). The header is padded, if necessary, to the
+    // appropriate boundary.
+    const uint32_t header_size = *offset_ptr - Offset;
+    const uint32_t tuple_size = HeaderData.AddrSize * 2;
+    uint32_t first_tuple_offset = 0;
+    while (first_tuple_offset < header_size)
+      first_tuple_offset += tuple_size;
+
+    *offset_ptr = Offset + first_tuple_offset;
+
+    Descriptor arangeDescriptor;
+
+    static_assert(sizeof(arangeDescriptor.Address) ==
+                      sizeof(arangeDescriptor.Length),
+                  "Different datatypes for addresses and sizes!");
+    assert(sizeof(arangeDescriptor.Address) >= HeaderData.AddrSize);
+
+    while (data.isValidOffset(*offset_ptr)) {
+      arangeDescriptor.Address = data.getUnsigned(offset_ptr, HeaderData.AddrSize);
+      arangeDescriptor.Length = data.getUnsigned(offset_ptr, HeaderData.AddrSize);
+
+      // Each set of tuples is terminated by a 0 for the address and 0
+      // for the length.
+      if (arangeDescriptor.Address || arangeDescriptor.Length)
+        ArangeDescriptors.push_back(arangeDescriptor);
+      else
+        break; // We are done if we get a zero address and length
+    }
+
+    return !ArangeDescriptors.empty();
+  }
+  return false;
+}
+
+void DWARFDebugArangeSet::dump(raw_ostream &OS) const {
+  OS << format("Address Range Header: length = 0x%8.8x, version = 0x%4.4x, ",
+               HeaderData.Length, HeaderData.Version)
+     << format("cu_offset = 0x%8.8x, addr_size = 0x%2.2x, seg_size = 0x%2.2x\n",
+               HeaderData.CuOffset, HeaderData.AddrSize, HeaderData.SegSize);
+
+  for (const auto &Desc : ArangeDescriptors) {
+    Desc.dump(OS, HeaderData.AddrSize);
+    OS << '\n';
+  }
+}
diff --git a/binaryen/third_party/llvm-project/DWARFDebugAranges.cpp b/binaryen/third_party/llvm-project/DWARFDebugAranges.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFDebugAranges.cpp
@@ -0,0 +1,122 @@
+//===- DWARFDebugAranges.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/WithColor.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <set>
+#include <vector>
+
+using namespace llvm;
+
+void DWARFDebugAranges::extract(DataExtractor DebugArangesData) {
+  if (!DebugArangesData.isValidOffset(0))
+    return;
+  uint64_t Offset = 0;
+  DWARFDebugArangeSet Set;
+
+  while (Set.extract(DebugArangesData, &Offset)) {
+    uint64_t CUOffset = Set.getCompileUnitDIEOffset();
+    for (const auto &Desc : Set.descriptors()) {
+      uint64_t LowPC = Desc.Address;
+      uint64_t HighPC = Desc.getEndAddress();
+      appendRange(CUOffset, LowPC, HighPC);
+    }
+    ParsedCUOffsets.insert(CUOffset);
+  }
+}
+
+void DWARFDebugAranges::generate(DWARFContext *CTX) {
+  clear();
+  if (!CTX)
+    return;
+
+  // Extract aranges from .debug_aranges section.
+  DataExtractor ArangesData(CTX->getDWARFObj().getArangesSection(),
+                            CTX->isLittleEndian(), 0);
+  extract(ArangesData);
+
+  // Generate aranges from DIEs: even if .debug_aranges section is present,
+  // it may describe only a small subset of compilation units, so we need to
+  // manually build aranges for the rest of them.
+  for (const auto &CU : CTX->compile_units()) {
+    uint64_t CUOffset = CU->getOffset();
+    if (ParsedCUOffsets.insert(CUOffset).second) {
+      Expected<DWARFAddressRangesVector> CURanges = CU->collectAddressRanges();
+      if (!CURanges)
+        WithColor::error() << toString(CURanges.takeError()) << '\n';
+      else
+        for (const auto &R : *CURanges)
+          appendRange(CUOffset, R.LowPC, R.HighPC);
+    }
+  }
+
+  construct();
+}
+
+void DWARFDebugAranges::clear() {
+  Endpoints.clear();
+  Aranges.clear();
+  ParsedCUOffsets.clear();
+}
+
+void DWARFDebugAranges::appendRange(uint64_t CUOffset, uint64_t LowPC,
+                                    uint64_t HighPC) {
+  if (LowPC >= HighPC)
+    return;
+  Endpoints.emplace_back(LowPC, CUOffset, true);
+  Endpoints.emplace_back(HighPC, CUOffset, false);
+}
+
+void DWARFDebugAranges::construct() {
+  std::multiset<uint64_t> ValidCUs;  // Maintain the set of CUs describing
+                                     // a current address range.
+  llvm::sort(Endpoints);
+  uint64_t PrevAddress = -1ULL;
+  for (const auto &E : Endpoints) {
+    if (PrevAddress < E.Address && !ValidCUs.empty()) {
+      // If the address range between two endpoints is described by some
+      // CU, first try to extend the last range in Aranges. If we can't
+      // do it, start a new range.
+      if (!Aranges.empty() && Aranges.back().HighPC() == PrevAddress &&
+          ValidCUs.find(Aranges.back().CUOffset) != ValidCUs.end()) {
+        Aranges.back().setHighPC(E.Address);
+      } else {
+        Aranges.emplace_back(PrevAddress, E.Address, *ValidCUs.begin());
+      }
+    }
+    // Update the set of valid CUs.
+    if (E.IsRangeStart) {
+      ValidCUs.insert(E.CUOffset);
+    } else {
+      auto CUPos = ValidCUs.find(E.CUOffset);
+      assert(CUPos != ValidCUs.end());
+      ValidCUs.erase(CUPos);
+    }
+    PrevAddress = E.Address;
+  }
+  assert(ValidCUs.empty());
+
+  // Endpoints are not needed now.
+  Endpoints.clear();
+  Endpoints.shrink_to_fit();
+}
+
+uint32_t DWARFDebugAranges::findAddress(uint64_t Address) const {
+  RangeCollIterator It =
+      partition_point(Aranges, [=](Range R) { return R.HighPC() <= Address; });
+  if (It != Aranges.end() && It->LowPC <= Address)
+    return It->CUOffset;
+  return -1U;
+}
diff --git a/binaryen/third_party/llvm-project/DWARFDebugFrame.cpp b/binaryen/third_party/llvm-project/DWARFDebugFrame.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFDebugFrame.cpp
@@ -0,0 +1,554 @@
+//===- DWARFDebugFrame.h - Parsing of .debug_frame ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+
+
+// See DWARF standard v3, section 7.23
+const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
+const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f;
+
+Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset,
+                        uint64_t EndOffset) {
+  while (*Offset < EndOffset) {
+    uint8_t Opcode = Data.getRelocatedValue(1, Offset);
+    // Some instructions have a primary opcode encoded in the top bits.
+    uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK;
+
+    if (Primary) {
+      // If it's a primary opcode, the first operand is encoded in the bottom
+      // bits of the opcode itself.
+      uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK;
+      switch (Primary) {
+      default:
+        return createStringError(errc::illegal_byte_sequence,
+                                 "Invalid primary CFI opcode 0x%" PRIx8,
+                                 Primary);
+      case DW_CFA_advance_loc:
+      case DW_CFA_restore:
+        addInstruction(Primary, Op1);
+        break;
+      case DW_CFA_offset:
+        addInstruction(Primary, Op1, Data.getULEB128(Offset));
+        break;
+      }
+    } else {
+      // Extended opcode - its value is Opcode itself.
+      switch (Opcode) {
+      default:
+        return createStringError(errc::illegal_byte_sequence,
+                                 "Invalid extended CFI opcode 0x%" PRIx8,
+                                 Opcode);
+      case DW_CFA_nop:
+      case DW_CFA_remember_state:
+      case DW_CFA_restore_state:
+      case DW_CFA_GNU_window_save:
+        // No operands
+        addInstruction(Opcode);
+        break;
+      case DW_CFA_set_loc:
+        // Operands: Address
+        addInstruction(Opcode, Data.getRelocatedAddress(Offset));
+        break;
+      case DW_CFA_advance_loc1:
+        // Operands: 1-byte delta
+        addInstruction(Opcode, Data.getRelocatedValue(1, Offset));
+        break;
+      case DW_CFA_advance_loc2:
+        // Operands: 2-byte delta
+        addInstruction(Opcode, Data.getRelocatedValue(2, Offset));
+        break;
+      case DW_CFA_advance_loc4:
+        // Operands: 4-byte delta
+        addInstruction(Opcode, Data.getRelocatedValue(4, Offset));
+        break;
+      case DW_CFA_restore_extended:
+      case DW_CFA_undefined:
+      case DW_CFA_same_value:
+      case DW_CFA_def_cfa_register:
+      case DW_CFA_def_cfa_offset:
+      case DW_CFA_GNU_args_size:
+        // Operands: ULEB128
+        addInstruction(Opcode, Data.getULEB128(Offset));
+        break;
+      case DW_CFA_def_cfa_offset_sf:
+        // Operands: SLEB128
+        addInstruction(Opcode, Data.getSLEB128(Offset));
+        break;
+      case DW_CFA_offset_extended:
+      case DW_CFA_register:
+      case DW_CFA_def_cfa:
+      case DW_CFA_val_offset: {
+        // Operands: ULEB128, ULEB128
+        // Note: We can not embed getULEB128 directly into function
+        // argument list. getULEB128 changes Offset and order of evaluation
+        // for arguments is unspecified.
+        auto op1 = Data.getULEB128(Offset);
+        auto op2 = Data.getULEB128(Offset);
+        addInstruction(Opcode, op1, op2);
+        break;
+        }
+        case DW_CFA_offset_extended_sf:
+        case DW_CFA_def_cfa_sf:
+        case DW_CFA_val_offset_sf: {
+          // Operands: ULEB128, SLEB128
+          // Note: see comment for the previous case
+          auto op1 = Data.getULEB128(Offset);
+          auto op2 = (uint64_t)Data.getSLEB128(Offset);
+          addInstruction(Opcode, op1, op2);
+          break;
+        }
+        case DW_CFA_def_cfa_expression: {
+          uint32_t ExprLength = Data.getULEB128(Offset);
+          addInstruction(Opcode, 0);
+          DataExtractor Extractor(
+              Data.getData().slice(*Offset, *Offset + ExprLength),
+              Data.isLittleEndian(), Data.getAddressSize());
+          Instructions.back().Expression = DWARFExpression(
+              Extractor, Data.getAddressSize(), dwarf::DWARF_VERSION);
+          *Offset += ExprLength;
+          break;
+        }
+        case DW_CFA_expression:
+        case DW_CFA_val_expression: {
+          auto RegNum = Data.getULEB128(Offset);
+          auto BlockLength = Data.getULEB128(Offset);
+          addInstruction(Opcode, RegNum, 0);
+          DataExtractor Extractor(
+              Data.getData().slice(*Offset, *Offset + BlockLength),
+              Data.isLittleEndian(), Data.getAddressSize());
+          Instructions.back().Expression = DWARFExpression(
+              Extractor, Data.getAddressSize(), dwarf::DWARF_VERSION);
+          *Offset += BlockLength;
+          break;
+        }
+      }
+    }
+  }
+
+  return Error::success();
+}
+
+namespace {
+
+
+} // end anonymous namespace
+
+ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() {
+  static OperandType OpTypes[DW_CFA_restore+1][2];
+  static bool Initialized = false;
+  if (Initialized) {
+    return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
+  }
+  Initialized = true;
+
+#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1)       \
+  do {                                          \
+    OpTypes[OP][0] = OPTYPE0;                   \
+    OpTypes[OP][1] = OPTYPE1;                   \
+  } while (false)
+#define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None)
+#define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None)
+
+  DECLARE_OP1(DW_CFA_set_loc, OT_Address);
+  DECLARE_OP1(DW_CFA_advance_loc, OT_FactoredCodeOffset);
+  DECLARE_OP1(DW_CFA_advance_loc1, OT_FactoredCodeOffset);
+  DECLARE_OP1(DW_CFA_advance_loc2, OT_FactoredCodeOffset);
+  DECLARE_OP1(DW_CFA_advance_loc4, OT_FactoredCodeOffset);
+  DECLARE_OP1(DW_CFA_MIPS_advance_loc8, OT_FactoredCodeOffset);
+  DECLARE_OP2(DW_CFA_def_cfa, OT_Register, OT_Offset);
+  DECLARE_OP2(DW_CFA_def_cfa_sf, OT_Register, OT_SignedFactDataOffset);
+  DECLARE_OP1(DW_CFA_def_cfa_register, OT_Register);
+  DECLARE_OP1(DW_CFA_def_cfa_offset, OT_Offset);
+  DECLARE_OP1(DW_CFA_def_cfa_offset_sf, OT_SignedFactDataOffset);
+  DECLARE_OP1(DW_CFA_def_cfa_expression, OT_Expression);
+  DECLARE_OP1(DW_CFA_undefined, OT_Register);
+  DECLARE_OP1(DW_CFA_same_value, OT_Register);
+  DECLARE_OP2(DW_CFA_offset, OT_Register, OT_UnsignedFactDataOffset);
+  DECLARE_OP2(DW_CFA_offset_extended, OT_Register, OT_UnsignedFactDataOffset);
+  DECLARE_OP2(DW_CFA_offset_extended_sf, OT_Register, OT_SignedFactDataOffset);
+  DECLARE_OP2(DW_CFA_val_offset, OT_Register, OT_UnsignedFactDataOffset);
+  DECLARE_OP2(DW_CFA_val_offset_sf, OT_Register, OT_SignedFactDataOffset);
+  DECLARE_OP2(DW_CFA_register, OT_Register, OT_Register);
+  DECLARE_OP2(DW_CFA_expression, OT_Register, OT_Expression);
+  DECLARE_OP2(DW_CFA_val_expression, OT_Register, OT_Expression);
+  DECLARE_OP1(DW_CFA_restore, OT_Register);
+  DECLARE_OP1(DW_CFA_restore_extended, OT_Register);
+  DECLARE_OP0(DW_CFA_remember_state);
+  DECLARE_OP0(DW_CFA_restore_state);
+  DECLARE_OP0(DW_CFA_GNU_window_save);
+  DECLARE_OP1(DW_CFA_GNU_args_size, OT_Offset);
+  DECLARE_OP0(DW_CFA_nop);
+
+#undef DECLARE_OP0
+#undef DECLARE_OP1
+#undef DECLARE_OP2
+
+  return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
+}
+
+/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
+void CFIProgram::printOperand(raw_ostream &OS, const MCRegisterInfo *MRI,
+                              bool IsEH, const Instruction &Instr,
+                              unsigned OperandIdx, uint64_t Operand) const {
+  assert(OperandIdx < 2);
+  uint8_t Opcode = Instr.Opcode;
+  OperandType Type = getOperandTypes()[Opcode][OperandIdx];
+
+  switch (Type) {
+  case OT_Unset: {
+    OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to";
+    auto OpcodeName = CallFrameString(Opcode, Arch);
+    if (!OpcodeName.empty())
+      OS << " " << OpcodeName;
+    else
+      OS << format(" Opcode %x",  Opcode);
+    break;
+  }
+  case OT_None:
+    break;
+  case OT_Address:
+    OS << format(" %" PRIx64, Operand);
+    break;
+  case OT_Offset:
+    // The offsets are all encoded in a unsigned form, but in practice
+    // consumers use them signed. It's most certainly legacy due to
+    // the lack of signed variants in the first Dwarf standards.
+    OS << format(" %+" PRId64, int64_t(Operand));
+    break;
+  case OT_FactoredCodeOffset: // Always Unsigned
+    if (CodeAlignmentFactor)
+      OS << format(" %" PRId64, Operand * CodeAlignmentFactor);
+    else
+      OS << format(" %" PRId64 "*code_alignment_factor" , Operand);
+    break;
+  case OT_SignedFactDataOffset:
+    if (DataAlignmentFactor)
+      OS << format(" %" PRId64, int64_t(Operand) * DataAlignmentFactor);
+    else
+      OS << format(" %" PRId64 "*data_alignment_factor" , int64_t(Operand));
+    break;
+  case OT_UnsignedFactDataOffset:
+    if (DataAlignmentFactor)
+      OS << format(" %" PRId64, Operand * DataAlignmentFactor);
+    else
+      OS << format(" %" PRId64 "*data_alignment_factor" , Operand);
+    break;
+  case OT_Register:
+    OS << format(" reg%" PRId64, Operand);
+    break;
+  case OT_Expression:
+    assert(Instr.Expression && "missing DWARFExpression object");
+    OS << " ";
+    Instr.Expression->print(OS, MRI, nullptr, IsEH);
+    break;
+  }
+}
+
+void CFIProgram::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
+                      unsigned IndentLevel) const {
+  for (const auto &Instr : Instructions) {
+    uint8_t Opcode = Instr.Opcode;
+    if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK)
+      Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK;
+    OS.indent(2 * IndentLevel);
+    OS << CallFrameString(Opcode, Arch) << ":";
+    for (unsigned i = 0; i < Instr.Ops.size(); ++i)
+      printOperand(OS, MRI, IsEH, Instr, i, Instr.Ops[i]);
+    OS << '\n';
+  }
+}
+
+void CIE::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH) const {
+  OS << format("%08x %08x %08x CIE", (uint32_t)Offset, (uint32_t)Length,
+               DW_CIE_ID)
+     << "\n";
+  OS << format("  Version:               %d\n", Version);
+  OS << "  Augmentation:          \"" << Augmentation << "\"\n";
+  if (Version >= 4) {
+    OS << format("  Address size:          %u\n", (uint32_t)AddressSize);
+    OS << format("  Segment desc size:     %u\n",
+                 (uint32_t)SegmentDescriptorSize);
+  }
+  OS << format("  Code alignment factor: %u\n", (uint32_t)CodeAlignmentFactor);
+  OS << format("  Data alignment factor: %d\n", (int32_t)DataAlignmentFactor);
+  OS << format("  Return address column: %d\n", (int32_t)ReturnAddressRegister);
+  if (Personality)
+    OS << format("  Personality Address: %016" PRIx64 "\n", *Personality);
+  if (!AugmentationData.empty()) {
+    OS << "  Augmentation data:    ";
+    for (uint8_t Byte : AugmentationData)
+      OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf);
+    OS << "\n";
+  }
+  OS << "\n";
+  CFIs.dump(OS, MRI, IsEH);
+  OS << "\n";
+}
+
+void FDE::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH) const {
+  OS << format("%08x %08x %08x FDE ", (uint32_t)Offset, (uint32_t)Length,
+               (int32_t)LinkedCIEOffset);
+  OS << format("cie=%08x pc=%08x...%08x\n", (int32_t)LinkedCIEOffset,
+               (uint32_t)InitialLocation,
+               (uint32_t)InitialLocation + (uint32_t)AddressRange);
+  if (LSDAAddress)
+    OS << format("  LSDA Address: %016" PRIx64 "\n", *LSDAAddress);
+  CFIs.dump(OS, MRI, IsEH);
+  OS << "\n";
+}
+
+DWARFDebugFrame::DWARFDebugFrame(Triple::ArchType Arch,
+    bool IsEH, uint64_t EHFrameAddress)
+    : Arch(Arch), IsEH(IsEH), EHFrameAddress(EHFrameAddress) {}
+
+DWARFDebugFrame::~DWARFDebugFrame() = default;
+
+static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
+                                              uint64_t Offset, int Length) {
+  errs() << "DUMP: ";
+  for (int i = 0; i < Length; ++i) {
+    uint8_t c = Data.getU8(&Offset);
+    errs().write_hex(c); errs() << " ";
+  }
+  errs() << "\n";
+}
+
+// This is a workaround for old compilers which do not allow
+// noreturn attribute usage in lambdas. Once the support for those
+// compilers are phased out, we can remove this and return back to
+// a ReportError lambda: [StartOffset](const char *ErrorMsg).
+static void LLVM_ATTRIBUTE_NORETURN ReportError(uint64_t StartOffset,
+                                                const char *ErrorMsg) {
+  std::string Str;
+  raw_string_ostream OS(Str);
+  OS << format(ErrorMsg, StartOffset);
+  OS.flush();
+  report_fatal_error(Str);
+}
+
+void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
+  uint64_t Offset = 0;
+  DenseMap<uint64_t, CIE *> CIEs;
+
+  while (Data.isValidOffset(Offset)) {
+    uint64_t StartOffset = Offset;
+
+    bool IsDWARF64 = false;
+    uint64_t Length = Data.getRelocatedValue(4, &Offset);
+    uint64_t Id;
+
+    if (Length == dwarf::DW_LENGTH_DWARF64) {
+      // DWARF-64 is distinguished by the first 32 bits of the initial length
+      // field being 0xffffffff. Then, the next 64 bits are the actual entry
+      // length.
+      IsDWARF64 = true;
+      Length = Data.getRelocatedValue(8, &Offset);
+    }
+
+    // At this point, Offset points to the next field after Length.
+    // Length is the structure size excluding itself. Compute an offset one
+    // past the end of the structure (needed to know how many instructions to
+    // read).
+    uint64_t StartStructureOffset = Offset;
+    uint64_t EndStructureOffset = Offset + Length;
+
+    // The Id field's size depends on the DWARF format
+    Id = Data.getUnsigned(&Offset, (IsDWARF64 && !IsEH) ? 8 : 4);
+    bool IsCIE =
+        ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID || (IsEH && !Id));
+
+    if (IsCIE) {
+      uint8_t Version = Data.getU8(&Offset);
+      const char *Augmentation = Data.getCStr(&Offset);
+      StringRef AugmentationString(Augmentation ? Augmentation : "");
+      uint8_t AddressSize = Version < 4 ? Data.getAddressSize() :
+                                          Data.getU8(&Offset);
+      Data.setAddressSize(AddressSize);
+      uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset);
+      uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
+      int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
+      uint64_t ReturnAddressRegister =
+          Version == 1 ? Data.getU8(&Offset) : Data.getULEB128(&Offset);
+
+      // Parse the augmentation data for EH CIEs
+      StringRef AugmentationData("");
+      uint32_t FDEPointerEncoding = DW_EH_PE_absptr;
+      uint32_t LSDAPointerEncoding = DW_EH_PE_omit;
+      Optional<uint64_t> Personality;
+      Optional<uint32_t> PersonalityEncoding;
+      if (IsEH) {
+        Optional<uint64_t> AugmentationLength;
+        uint64_t StartAugmentationOffset;
+        uint64_t EndAugmentationOffset;
+
+        // Walk the augmentation string to get all the augmentation data.
+        for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {
+          switch (AugmentationString[i]) {
+            default:
+              ReportError(
+                  StartOffset,
+                  "Unknown augmentation character in entry at %" PRIx64);
+            case 'L':
+              LSDAPointerEncoding = Data.getU8(&Offset);
+              break;
+            case 'P': {
+              if (Personality)
+                ReportError(StartOffset,
+                            "Duplicate personality in entry at %" PRIx64);
+              PersonalityEncoding = Data.getU8(&Offset);
+              Personality = Data.getEncodedPointer(
+                  &Offset, *PersonalityEncoding,
+                  EHFrameAddress ? EHFrameAddress + Offset : 0);
+              break;
+            }
+            case 'R':
+              FDEPointerEncoding = Data.getU8(&Offset);
+              break;
+            case 'S':
+              // Current frame is a signal trampoline.
+              break;
+            case 'z':
+              if (i)
+                ReportError(StartOffset,
+                            "'z' must be the first character at %" PRIx64);
+              // Parse the augmentation length first.  We only parse it if
+              // the string contains a 'z'.
+              AugmentationLength = Data.getULEB128(&Offset);
+              StartAugmentationOffset = Offset;
+              EndAugmentationOffset = Offset + *AugmentationLength;
+              break;
+            case 'B':
+              // B-Key is used for signing functions associated with this
+              // augmentation string
+              break;
+          }
+        }
+
+        if (AugmentationLength.hasValue()) {
+          if (Offset != EndAugmentationOffset)
+            ReportError(StartOffset,
+                        "Parsing augmentation data at %" PRIx64 " failed");
+
+          AugmentationData = Data.getData().slice(StartAugmentationOffset,
+                                                  EndAugmentationOffset);
+        }
+      }
+
+      auto Cie = std::make_unique<CIE>(
+          StartOffset, Length, Version, AugmentationString, AddressSize,
+          SegmentDescriptorSize, CodeAlignmentFactor, DataAlignmentFactor,
+          ReturnAddressRegister, AugmentationData, FDEPointerEncoding,
+          LSDAPointerEncoding, Personality, PersonalityEncoding, Arch);
+      CIEs[StartOffset] = Cie.get();
+      Entries.emplace_back(std::move(Cie));
+    } else {
+      // FDE
+      uint64_t CIEPointer = Id;
+      uint64_t InitialLocation = 0;
+      uint64_t AddressRange = 0;
+      Optional<uint64_t> LSDAAddress;
+      CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer];
+
+      if (IsEH) {
+        // The address size is encoded in the CIE we reference.
+        if (!Cie)
+          ReportError(StartOffset, "Parsing FDE data at %" PRIx64
+                                   " failed due to missing CIE");
+
+        if (auto Val = Data.getEncodedPointer(
+                &Offset, Cie->getFDEPointerEncoding(),
+                EHFrameAddress ? EHFrameAddress + Offset : 0)) {
+          InitialLocation = *Val;
+        }
+        if (auto Val = Data.getEncodedPointer(
+                &Offset, Cie->getFDEPointerEncoding(), 0)) {
+          AddressRange = *Val;
+        }
+
+        StringRef AugmentationString = Cie->getAugmentationString();
+        if (!AugmentationString.empty()) {
+          // Parse the augmentation length and data for this FDE.
+          uint64_t AugmentationLength = Data.getULEB128(&Offset);
+
+          uint64_t EndAugmentationOffset = Offset + AugmentationLength;
+
+          // Decode the LSDA if the CIE augmentation string said we should.
+          if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit) {
+            LSDAAddress = Data.getEncodedPointer(
+                &Offset, Cie->getLSDAPointerEncoding(),
+                EHFrameAddress ? Offset + EHFrameAddress : 0);
+          }
+
+          if (Offset != EndAugmentationOffset)
+            ReportError(StartOffset,
+                        "Parsing augmentation data at %" PRIx64 " failed");
+        }
+      } else {
+        InitialLocation = Data.getRelocatedAddress(&Offset);
+        AddressRange = Data.getRelocatedAddress(&Offset);
+      }
+
+      Entries.emplace_back(new FDE(StartOffset, Length, CIEPointer,
+                                   InitialLocation, AddressRange,
+                                   Cie, LSDAAddress, Arch));
+    }
+
+    if (Error E =
+            Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset)) {
+      report_fatal_error(toString(std::move(E)));
+    }
+
+    if (Offset != EndStructureOffset)
+      ReportError(StartOffset,
+                  "Parsing entry instructions at %" PRIx64 " failed");
+  }
+}
+
+FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const {
+  auto It = partition_point(Entries, [=](const std::unique_ptr<FrameEntry> &E) {
+    return E->getOffset() < Offset;
+  });
+  if (It != Entries.end() && (*It)->getOffset() == Offset)
+    return It->get();
+  return nullptr;
+}
+
+void DWARFDebugFrame::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+                           Optional<uint64_t> Offset) const {
+  if (Offset) {
+    if (auto *Entry = getEntryAtOffset(*Offset))
+      Entry->dump(OS, MRI, IsEH);
+    return;
+  }
+
+  OS << "\n";
+  for (const auto &Entry : Entries)
+    Entry->dump(OS, MRI, IsEH);
+}
diff --git a/binaryen/third_party/llvm-project/DWARFDebugInfoEntry.cpp b/binaryen/third_party/llvm-project/DWARFDebugInfoEntry.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFDebugInfoEntry.cpp
@@ -0,0 +1,73 @@
+//===- DWARFDebugInfoEntry.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/DataExtractor.h"
+#include <cstddef>
+#include <cstdint>
+
+using namespace llvm;
+using namespace dwarf;
+
+bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U,
+                                             uint64_t *OffsetPtr) {
+  DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
+  const uint64_t UEndOffset = U.getNextUnitOffset();
+  return extractFast(U, OffsetPtr, DebugInfoData, UEndOffset, 0);
+}
+
+bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint64_t *OffsetPtr,
+                                      const DWARFDataExtractor &DebugInfoData,
+                                      uint64_t UEndOffset, uint32_t D) {
+  Offset = *OffsetPtr;
+  Depth = D;
+  if (Offset >= UEndOffset || !DebugInfoData.isValidOffset(Offset))
+    return false;
+  uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr);
+  if (0 == AbbrCode) {
+    // NULL debug tag entry.
+    AbbrevDecl = nullptr;
+    return true;
+  }
+  if (auto* Abbreviations = U.getAbbreviations()) { // XXX BINARYEN
+    AbbrevDecl = Abbreviations->getAbbreviationDeclaration(AbbrCode);
+  } else {
+    AbbrevDecl = nullptr; // XXX BINARYEN
+  }
+  if (nullptr == AbbrevDecl) {
+    // Restore the original offset.
+    *OffsetPtr = Offset;
+    return false;
+  }
+  // See if all attributes in this DIE have fixed byte sizes. If so, we can
+  // just add this size to the offset to skip to the next DIE.
+  if (Optional<size_t> FixedSize = AbbrevDecl->getFixedAttributesByteSize(U)) {
+    *OffsetPtr += *FixedSize;
+    return true;
+  }
+
+  // Skip all data in the .debug_info for the attributes
+  for (const auto &AttrSpec : AbbrevDecl->attributes()) {
+    // Check if this attribute has a fixed byte size.
+    if (auto FixedSize = AttrSpec.getByteSize(U)) {
+      // Attribute byte size if fixed, just add the size to the offset.
+      *OffsetPtr += *FixedSize;
+    } else if (!DWARFFormValue::skipValue(AttrSpec.Form, DebugInfoData,
+                                          OffsetPtr, U.getFormParams())) {
+      // We failed to skip this attribute's value, restore the original offset
+      // and return the failure status.
+      *OffsetPtr = Offset;
+      return false;
+    }
+  }
+  return true;
+}
diff --git a/binaryen/third_party/llvm-project/DWARFDebugLine.cpp b/binaryen/third_party/llvm-project/DWARFDebugLine.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFDebugLine.cpp
@@ -0,0 +1,1181 @@
+//===- DWARFDebugLine.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <cstdio>
+#include <utility>
+
+using namespace llvm;
+using namespace dwarf;
+
+using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind;
+
+namespace {
+
+struct ContentDescriptor {
+  dwarf::LineNumberEntryFormat Type;
+  dwarf::Form Form;
+};
+
+using ContentDescriptors = SmallVector<ContentDescriptor, 4>;
+
+} // end anonmyous namespace
+
+void DWARFDebugLine::ContentTypeTracker::trackContentType(
+    dwarf::LineNumberEntryFormat ContentType) {
+  switch (ContentType) {
+  case dwarf::DW_LNCT_timestamp:
+    HasModTime = true;
+    break;
+  case dwarf::DW_LNCT_size:
+    HasLength = true;
+    break;
+  case dwarf::DW_LNCT_MD5:
+    HasMD5 = true;
+    break;
+  case dwarf::DW_LNCT_LLVM_source:
+    HasSource = true;
+    break;
+  default:
+    // We only care about values we consider optional, and new values may be
+    // added in the vendor extension range, so we do not match exhaustively.
+    break;
+  }
+}
+
+DWARFDebugLine::Prologue::Prologue() { clear(); }
+
+bool DWARFDebugLine::Prologue::hasFileAtIndex(uint64_t FileIndex) const {
+  uint16_t DwarfVersion = getVersion();
+  assert(DwarfVersion != 0 &&
+         "line table prologue has no dwarf version information");
+  if (DwarfVersion >= 5)
+    return FileIndex < FileNames.size();
+  return FileIndex != 0 && FileIndex <= FileNames.size();
+}
+
+const llvm::DWARFDebugLine::FileNameEntry &
+DWARFDebugLine::Prologue::getFileNameEntry(uint64_t Index) const {
+  uint16_t DwarfVersion = getVersion();
+  assert(DwarfVersion != 0 &&
+         "line table prologue has no dwarf version information");
+  // In DWARF v5 the file names are 0-indexed.
+  if (DwarfVersion >= 5)
+    return FileNames[Index];
+  return FileNames[Index - 1];
+}
+
+void DWARFDebugLine::Prologue::clear() {
+  TotalLength = PrologueLength = 0;
+  SegSelectorSize = 0;
+  MinInstLength = MaxOpsPerInst = DefaultIsStmt = LineBase = LineRange = 0;
+  OpcodeBase = 0;
+  FormParams = dwarf::FormParams({0, 0, DWARF32});
+  ContentTypes = ContentTypeTracker();
+  StandardOpcodeLengths.clear();
+  IncludeDirectories.clear();
+  FileNames.clear();
+}
+
+void DWARFDebugLine::Prologue::dump(raw_ostream &OS,
+                                    DIDumpOptions DumpOptions) const {
+  OS << "Line table prologue:\n"
+     << format("    total_length: 0x%8.8" PRIx64 "\n", TotalLength)
+     << format("         version: %u\n", getVersion());
+  if (getVersion() >= 5)
+    OS << format("    address_size: %u\n", getAddressSize())
+       << format(" seg_select_size: %u\n", SegSelectorSize);
+  OS << format(" prologue_length: 0x%8.8" PRIx64 "\n", PrologueLength)
+     << format(" min_inst_length: %u\n", MinInstLength)
+     << format(getVersion() >= 4 ? "max_ops_per_inst: %u\n" : "", MaxOpsPerInst)
+     << format(" default_is_stmt: %u\n", DefaultIsStmt)
+     << format("       line_base: %i\n", LineBase)
+     << format("      line_range: %u\n", LineRange)
+     << format("     opcode_base: %u\n", OpcodeBase);
+
+  for (uint32_t I = 0; I != StandardOpcodeLengths.size(); ++I)
+    OS << format("standard_opcode_lengths[%s] = %u\n",
+                 LNStandardString(I + 1).data(), StandardOpcodeLengths[I]);
+
+  if (!IncludeDirectories.empty()) {
+    // DWARF v5 starts directory indexes at 0.
+    uint32_t DirBase = getVersion() >= 5 ? 0 : 1;
+    for (uint32_t I = 0; I != IncludeDirectories.size(); ++I) {
+      OS << format("include_directories[%3u] = ", I + DirBase);
+      IncludeDirectories[I].dump(OS, DumpOptions);
+      OS << '\n';
+    }
+  }
+
+  if (!FileNames.empty()) {
+    // DWARF v5 starts file indexes at 0.
+    uint32_t FileBase = getVersion() >= 5 ? 0 : 1;
+    for (uint32_t I = 0; I != FileNames.size(); ++I) {
+      const FileNameEntry &FileEntry = FileNames[I];
+      OS <<   format("file_names[%3u]:\n", I + FileBase);
+      OS <<          "           name: ";
+      FileEntry.Name.dump(OS, DumpOptions);
+      OS << '\n'
+         <<   format("      dir_index: %" PRIu64 "\n", FileEntry.DirIdx);
+      if (ContentTypes.HasMD5)
+        OS <<        "   md5_checksum: " << FileEntry.Checksum.digest() << '\n';
+      if (ContentTypes.HasModTime)
+        OS << format("       mod_time: 0x%8.8" PRIx64 "\n", FileEntry.ModTime);
+      if (ContentTypes.HasLength)
+        OS << format("         length: 0x%8.8" PRIx64 "\n", FileEntry.Length);
+      if (ContentTypes.HasSource) {
+        OS <<        "         source: ";
+        FileEntry.Source.dump(OS, DumpOptions);
+        OS << '\n';
+      }
+    }
+  }
+}
+
+// Parse v2-v4 directory and file tables.
+static void
+parseV2DirFileTables(const DWARFDataExtractor &DebugLineData,
+                     uint64_t *OffsetPtr, uint64_t EndPrologueOffset,
+                     DWARFDebugLine::ContentTypeTracker &ContentTypes,
+                     std::vector<DWARFFormValue> &IncludeDirectories,
+                     std::vector<DWARFDebugLine::FileNameEntry> &FileNames) {
+  while (*OffsetPtr < EndPrologueOffset) {
+    StringRef S = DebugLineData.getCStrRef(OffsetPtr);
+    if (S.empty())
+      break;
+    DWARFFormValue Dir =
+        DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, S.data());
+    IncludeDirectories.push_back(Dir);
+  }
+
+  while (*OffsetPtr < EndPrologueOffset) {
+    StringRef Name = DebugLineData.getCStrRef(OffsetPtr);
+    if (Name.empty())
+      break;
+    DWARFDebugLine::FileNameEntry FileEntry;
+    FileEntry.Name =
+        DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, Name.data());
+    FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr);
+    FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr);
+    FileEntry.Length = DebugLineData.getULEB128(OffsetPtr);
+    FileNames.push_back(FileEntry);
+  }
+
+  ContentTypes.HasModTime = true;
+  ContentTypes.HasLength = true;
+}
+
+// Parse v5 directory/file entry content descriptions.
+// Returns the descriptors, or an error if we did not find a path or ran off
+// the end of the prologue.
+static llvm::Expected<ContentDescriptors>
+parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr,
+                   uint64_t EndPrologueOffset,
+                   DWARFDebugLine::ContentTypeTracker *ContentTypes) {
+  ContentDescriptors Descriptors;
+  int FormatCount = DebugLineData.getU8(OffsetPtr);
+  bool HasPath = false;
+  for (int I = 0; I != FormatCount; ++I) {
+    if (*OffsetPtr >= EndPrologueOffset)
+      return createStringError(
+          errc::invalid_argument,
+          "failed to parse entry content descriptions at offset "
+          "0x%8.8" PRIx64
+          " because offset extends beyond the prologue end at offset "
+          "0x%8.8" PRIx64,
+          *OffsetPtr, EndPrologueOffset);
+    ContentDescriptor Descriptor;
+    Descriptor.Type =
+      dwarf::LineNumberEntryFormat(DebugLineData.getULEB128(OffsetPtr));
+    Descriptor.Form = dwarf::Form(DebugLineData.getULEB128(OffsetPtr));
+    if (Descriptor.Type == dwarf::DW_LNCT_path)
+      HasPath = true;
+    if (ContentTypes)
+      ContentTypes->trackContentType(Descriptor.Type);
+    Descriptors.push_back(Descriptor);
+  }
+
+  if (!HasPath)
+    return createStringError(errc::invalid_argument,
+                             "failed to parse entry content descriptions"
+                             " because no path was found");
+  return Descriptors;
+}
+
+static Error
+parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
+                     uint64_t *OffsetPtr, uint64_t EndPrologueOffset,
+                     const dwarf::FormParams &FormParams,
+                     const DWARFContext &Ctx, const DWARFUnit *U,
+                     DWARFDebugLine::ContentTypeTracker &ContentTypes,
+                     std::vector<DWARFFormValue> &IncludeDirectories,
+                     std::vector<DWARFDebugLine::FileNameEntry> &FileNames) {
+  // Get the directory entry description.
+  llvm::Expected<ContentDescriptors> DirDescriptors =
+      parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset, nullptr);
+  if (!DirDescriptors)
+    return DirDescriptors.takeError();
+
+  // Get the directory entries, according to the format described above.
+  int DirEntryCount = DebugLineData.getU8(OffsetPtr);
+  for (int I = 0; I != DirEntryCount; ++I) {
+    if (*OffsetPtr >= EndPrologueOffset)
+      return createStringError(
+          errc::invalid_argument,
+          "failed to parse directory entry at offset "
+          "0x%8.8" PRIx64
+          " because offset extends beyond the prologue end at offset "
+          "0x%8.8" PRIx64,
+          *OffsetPtr, EndPrologueOffset);
+    for (auto Descriptor : *DirDescriptors) {
+      DWARFFormValue Value(Descriptor.Form);
+      switch (Descriptor.Type) {
+      case DW_LNCT_path:
+        if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U))
+          return createStringError(errc::invalid_argument,
+                                   "failed to parse directory entry because "
+                                   "extracting the form value failed.");
+        IncludeDirectories.push_back(Value);
+        break;
+      default:
+        if (!Value.skipValue(DebugLineData, OffsetPtr, FormParams))
+          return createStringError(errc::invalid_argument,
+                                   "failed to parse directory entry because "
+                                   "skipping the form value failed.");
+      }
+    }
+  }
+
+  // Get the file entry description.
+  llvm::Expected<ContentDescriptors> FileDescriptors = parseV5EntryFormat(
+      DebugLineData, OffsetPtr, EndPrologueOffset, &ContentTypes);
+  if (!FileDescriptors)
+    return FileDescriptors.takeError();
+
+  // Get the file entries, according to the format described above.
+  int FileEntryCount = DebugLineData.getU8(OffsetPtr);
+  for (int I = 0; I != FileEntryCount; ++I) {
+    if (*OffsetPtr >= EndPrologueOffset)
+      return createStringError(
+          errc::invalid_argument,
+          "failed to parse file entry at offset "
+          "0x%8.8" PRIx64
+          " because offset extends beyond the prologue end at offset "
+          "0x%8.8" PRIx64,
+          *OffsetPtr, EndPrologueOffset);
+    DWARFDebugLine::FileNameEntry FileEntry;
+    for (auto Descriptor : *FileDescriptors) {
+      DWARFFormValue Value(Descriptor.Form);
+      if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U))
+        return createStringError(errc::invalid_argument,
+                                 "failed to parse file entry because "
+                                 "extracting the form value failed.");
+      switch (Descriptor.Type) {
+      case DW_LNCT_path:
+        FileEntry.Name = Value;
+        break;
+      case DW_LNCT_LLVM_source:
+        FileEntry.Source = Value;
+        break;
+      case DW_LNCT_directory_index:
+        FileEntry.DirIdx = Value.getAsUnsignedConstant().getValue();
+        break;
+      case DW_LNCT_timestamp:
+        FileEntry.ModTime = Value.getAsUnsignedConstant().getValue();
+        break;
+      case DW_LNCT_size:
+        FileEntry.Length = Value.getAsUnsignedConstant().getValue();
+        break;
+      case DW_LNCT_MD5:
+        if (!Value.getAsBlock() || Value.getAsBlock().getValue().size() != 16)
+          return createStringError(
+              errc::invalid_argument,
+              "failed to parse file entry because the MD5 hash is invalid");
+        std::uninitialized_copy_n(Value.getAsBlock().getValue().begin(), 16,
+                                  FileEntry.Checksum.Bytes.begin());
+        break;
+      default:
+        break;
+      }
+    }
+    FileNames.push_back(FileEntry);
+  }
+  return Error::success();
+}
+
+Error DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData,
+                                      uint64_t *OffsetPtr,
+                                      const DWARFContext &Ctx,
+                                      const DWARFUnit *U) {
+  const uint64_t PrologueOffset = *OffsetPtr;
+
+  clear();
+  TotalLength = DebugLineData.getRelocatedValue(4, OffsetPtr);
+  if (TotalLength == dwarf::DW_LENGTH_DWARF64) {
+    FormParams.Format = dwarf::DWARF64;
+    TotalLength = DebugLineData.getU64(OffsetPtr);
+  } else if (TotalLength >= dwarf::DW_LENGTH_lo_reserved) {
+    return createStringError(errc::invalid_argument,
+        "parsing line table prologue at offset 0x%8.8" PRIx64
+        " unsupported reserved unit length found of value 0x%8.8" PRIx64,
+        PrologueOffset, TotalLength);
+  }
+  FormParams.Version = DebugLineData.getU16(OffsetPtr);
+  if (getVersion() < 2)
+    return createStringError(errc::not_supported,
+                       "parsing line table prologue at offset 0x%8.8" PRIx64
+                       " found unsupported version 0x%2.2" PRIx16,
+                       PrologueOffset, getVersion());
+
+  if (getVersion() >= 5) {
+    FormParams.AddrSize = DebugLineData.getU8(OffsetPtr);
+    assert((DebugLineData.getAddressSize() == 0 ||
+            DebugLineData.getAddressSize() == getAddressSize()) &&
+           "Line table header and data extractor disagree");
+    SegSelectorSize = DebugLineData.getU8(OffsetPtr);
+  }
+
+  PrologueLength =
+      DebugLineData.getRelocatedValue(sizeofPrologueLength(), OffsetPtr);
+  const uint64_t EndPrologueOffset = PrologueLength + *OffsetPtr;
+  MinInstLength = DebugLineData.getU8(OffsetPtr);
+  if (getVersion() >= 4)
+    MaxOpsPerInst = DebugLineData.getU8(OffsetPtr);
+  DefaultIsStmt = DebugLineData.getU8(OffsetPtr);
+  LineBase = DebugLineData.getU8(OffsetPtr);
+  LineRange = DebugLineData.getU8(OffsetPtr);
+  OpcodeBase = DebugLineData.getU8(OffsetPtr);
+
+  StandardOpcodeLengths.reserve(OpcodeBase - 1);
+  for (uint32_t I = 1; I < OpcodeBase; ++I) {
+    uint8_t OpLen = DebugLineData.getU8(OffsetPtr);
+    StandardOpcodeLengths.push_back(OpLen);
+  }
+
+  if (getVersion() >= 5) {
+    if (Error e = parseV5DirFileTables(
+            DebugLineData, OffsetPtr, EndPrologueOffset, FormParams, Ctx, U,
+            ContentTypes, IncludeDirectories, FileNames)) {
+      return joinErrors(
+          createStringError(
+              errc::invalid_argument,
+              "parsing line table prologue at 0x%8.8" PRIx64
+              " found an invalid directory or file table description at"
+              " 0x%8.8" PRIx64,
+              PrologueOffset, *OffsetPtr),
+          std::move(e));
+    }
+  } else
+    parseV2DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset,
+                         ContentTypes, IncludeDirectories, FileNames);
+
+  if (*OffsetPtr != EndPrologueOffset)
+    return createStringError(errc::invalid_argument,
+                       "parsing line table prologue at 0x%8.8" PRIx64
+                       " should have ended at 0x%8.8" PRIx64
+                       " but it ended at 0x%8.8" PRIx64,
+                       PrologueOffset, EndPrologueOffset, *OffsetPtr);
+  return Error::success();
+}
+
+DWARFDebugLine::Row::Row(bool DefaultIsStmt) { reset(DefaultIsStmt); }
+
+void DWARFDebugLine::Row::postAppend() {
+  Discriminator = 0;
+  BasicBlock = false;
+  PrologueEnd = false;
+  EpilogueBegin = false;
+}
+
+void DWARFDebugLine::Row::reset(bool DefaultIsStmt) {
+  Address.Address = 0;
+  Address.SectionIndex = object::SectionedAddress::UndefSection;
+  Line = 1;
+  Column = 0;
+  File = 1;
+  Isa = 0;
+  Discriminator = 0;
+  IsStmt = DefaultIsStmt;
+  BasicBlock = false;
+  EndSequence = false;
+  PrologueEnd = false;
+  EpilogueBegin = false;
+}
+
+void DWARFDebugLine::Row::dumpTableHeader(raw_ostream &OS) {
+  OS << "Address            Line   Column File   ISA Discriminator Flags\n"
+     << "------------------ ------ ------ ------ --- ------------- "
+        "-------------\n";
+}
+
+void DWARFDebugLine::Row::dump(raw_ostream &OS) const {
+  OS << format("0x%16.16" PRIx64 " %6u %6u", Address.Address, Line, Column)
+     << format(" %6u %3u %13u ", File, Isa, Discriminator)
+     << (IsStmt ? " is_stmt" : "") << (BasicBlock ? " basic_block" : "")
+     << (PrologueEnd ? " prologue_end" : "")
+     << (EpilogueBegin ? " epilogue_begin" : "")
+     << (EndSequence ? " end_sequence" : "") << '\n';
+}
+
+DWARFDebugLine::Sequence::Sequence() { reset(); }
+
+void DWARFDebugLine::Sequence::reset() {
+  LowPC = 0;
+  HighPC = 0;
+  SectionIndex = object::SectionedAddress::UndefSection;
+  FirstRowIndex = 0;
+  LastRowIndex = 0;
+  Empty = true;
+}
+
+DWARFDebugLine::LineTable::LineTable() { clear(); }
+
+void DWARFDebugLine::LineTable::dump(raw_ostream &OS,
+                                     DIDumpOptions DumpOptions) const {
+  Prologue.dump(OS, DumpOptions);
+  OS << '\n';
+
+  if (!Rows.empty()) {
+    Row::dumpTableHeader(OS);
+    for (const Row &R : Rows) {
+      R.dump(OS);
+    }
+  }
+}
+
+void DWARFDebugLine::LineTable::clear() {
+  Prologue.clear();
+  Rows.clear();
+  Sequences.clear();
+}
+
+DWARFDebugLine::ParsingState::ParsingState(struct LineTable *LT)
+    : LineTable(LT) {
+  resetRowAndSequence();
+}
+
+void DWARFDebugLine::ParsingState::resetRowAndSequence() {
+  Row.reset(LineTable->Prologue.DefaultIsStmt);
+  Sequence.reset();
+}
+
+void DWARFDebugLine::ParsingState::appendRowToMatrix() {
+  unsigned RowNumber = LineTable->Rows.size();
+  if (Sequence.Empty) {
+    // Record the beginning of instruction sequence.
+    Sequence.Empty = false;
+    Sequence.LowPC = Row.Address.Address;
+    Sequence.FirstRowIndex = RowNumber;
+  }
+  LineTable->appendRow(Row);
+  if (Row.EndSequence) {
+    // Record the end of instruction sequence.
+    Sequence.HighPC = Row.Address.Address;
+    Sequence.LastRowIndex = RowNumber + 1;
+    Sequence.SectionIndex = Row.Address.SectionIndex;
+    if (Sequence.isValid())
+      LineTable->appendSequence(Sequence);
+    Sequence.reset();
+  }
+  Row.postAppend();
+}
+
+const DWARFDebugLine::LineTable *
+DWARFDebugLine::getLineTable(uint64_t Offset) const {
+  LineTableConstIter Pos = LineTableMap.find(Offset);
+  if (Pos != LineTableMap.end())
+    return &Pos->second;
+  return nullptr;
+}
+
+Expected<const DWARFDebugLine::LineTable *> DWARFDebugLine::getOrParseLineTable(
+    DWARFDataExtractor &DebugLineData, uint64_t Offset, const DWARFContext &Ctx,
+    const DWARFUnit *U, std::function<void(Error)> RecoverableErrorCallback) {
+  if (!DebugLineData.isValidOffset(Offset))
+    return createStringError(errc::invalid_argument, "offset 0x%8.8" PRIx64
+                       " is not a valid debug line section offset",
+                       Offset);
+
+  std::pair<LineTableIter, bool> Pos =
+      LineTableMap.insert(LineTableMapTy::value_type(Offset, LineTable()));
+  LineTable *LT = &Pos.first->second;
+  if (Pos.second) {
+    if (Error Err =
+            LT->parse(DebugLineData, &Offset, Ctx, U, RecoverableErrorCallback))
+      return std::move(Err);
+    return LT;
+  }
+  return LT;
+}
+
+Error DWARFDebugLine::LineTable::parse(
+    DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr,
+    const DWARFContext &Ctx, const DWARFUnit *U,
+    std::function<void(Error)> RecoverableErrorCallback, raw_ostream *OS) {
+  const uint64_t DebugLineOffset = *OffsetPtr;
+
+  clear();
+
+  Error PrologueErr = Prologue.parse(DebugLineData, OffsetPtr, Ctx, U);
+
+  if (OS) {
+    // The presence of OS signals verbose dumping.
+    DIDumpOptions DumpOptions;
+    DumpOptions.Verbose = true;
+    Prologue.dump(*OS, DumpOptions);
+  }
+
+  if (PrologueErr)
+    return PrologueErr;
+
+  const uint64_t EndOffset =
+      DebugLineOffset + Prologue.TotalLength + Prologue.sizeofTotalLength();
+
+  // See if we should tell the data extractor the address size.
+  if (DebugLineData.getAddressSize() == 0)
+    DebugLineData.setAddressSize(Prologue.getAddressSize());
+  else
+    assert(Prologue.getAddressSize() == 0 ||
+           Prologue.getAddressSize() == DebugLineData.getAddressSize());
+
+  ParsingState State(this);
+
+  while (*OffsetPtr < EndOffset) {
+    if (OS)
+      *OS << format("0x%08.08" PRIx64 ": ", *OffsetPtr);
+
+    uint8_t Opcode = DebugLineData.getU8(OffsetPtr);
+
+    if (OS)
+      *OS << format("%02.02" PRIx8 " ", Opcode);
+
+    if (Opcode == 0) {
+      // Extended Opcodes always start with a zero opcode followed by
+      // a uleb128 length so you can skip ones you don't know about
+      uint64_t Len = DebugLineData.getULEB128(OffsetPtr);
+      uint64_t ExtOffset = *OffsetPtr;
+
+      // Tolerate zero-length; assume length is correct and soldier on.
+      if (Len == 0) {
+        if (OS)
+          *OS << "Badly formed extended line op (length 0)\n";
+        continue;
+      }
+
+      uint8_t SubOpcode = DebugLineData.getU8(OffsetPtr);
+      if (OS)
+        *OS << LNExtendedString(SubOpcode);
+      switch (SubOpcode) {
+      case DW_LNE_end_sequence:
+        // Set the end_sequence register of the state machine to true and
+        // append a row to the matrix using the current values of the
+        // state-machine registers. Then reset the registers to the initial
+        // values specified above. Every statement program sequence must end
+        // with a DW_LNE_end_sequence instruction which creates a row whose
+        // address is that of the byte after the last target machine instruction
+        // of the sequence.
+        State.Row.EndSequence = true;
+        State.appendRowToMatrix();
+        if (OS) {
+          *OS << "\n";
+          OS->indent(12);
+          State.Row.dump(*OS);
+        }
+        State.resetRowAndSequence();
+        break;
+
+      case DW_LNE_set_address:
+        // Takes a single relocatable address as an operand. The size of the
+        // operand is the size appropriate to hold an address on the target
+        // machine. Set the address register to the value given by the
+        // relocatable address. All of the other statement program opcodes
+        // that affect the address register add a delta to it. This instruction
+        // stores a relocatable value into it instead.
+        //
+        // Make sure the extractor knows the address size.  If not, infer it
+        // from the size of the operand.
+        if (DebugLineData.getAddressSize() == 0)
+          DebugLineData.setAddressSize(Len - 1);
+        else if (DebugLineData.getAddressSize() != Len - 1) {
+          return createStringError(errc::invalid_argument,
+                             "mismatching address size at offset 0x%8.8" PRIx64
+                             " expected 0x%2.2" PRIx8 " found 0x%2.2" PRIx64,
+                             ExtOffset, DebugLineData.getAddressSize(),
+                             Len - 1);
+        }
+        State.Row.Address.Address = DebugLineData.getRelocatedAddress(
+            OffsetPtr, &State.Row.Address.SectionIndex);
+        if (OS)
+          *OS << format(" (0x%16.16" PRIx64 ")", State.Row.Address.Address);
+        break;
+
+      case DW_LNE_define_file:
+        // Takes 4 arguments. The first is a null terminated string containing
+        // a source file name. The second is an unsigned LEB128 number
+        // representing the directory index of the directory in which the file
+        // was found. The third is an unsigned LEB128 number representing the
+        // time of last modification of the file. The fourth is an unsigned
+        // LEB128 number representing the length in bytes of the file. The time
+        // and length fields may contain LEB128(0) if the information is not
+        // available.
+        //
+        // The directory index represents an entry in the include_directories
+        // section of the statement program prologue. The index is LEB128(0)
+        // if the file was found in the current directory of the compilation,
+        // LEB128(1) if it was found in the first directory in the
+        // include_directories section, and so on. The directory index is
+        // ignored for file names that represent full path names.
+        //
+        // The files are numbered, starting at 1, in the order in which they
+        // appear; the names in the prologue come before names defined by
+        // the DW_LNE_define_file instruction. These numbers are used in the
+        // the file register of the state machine.
+        {
+          FileNameEntry FileEntry;
+          const char *Name = DebugLineData.getCStr(OffsetPtr);
+          FileEntry.Name =
+              DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, Name);
+          FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr);
+          FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr);
+          FileEntry.Length = DebugLineData.getULEB128(OffsetPtr);
+          Prologue.FileNames.push_back(FileEntry);
+          if (OS)
+            *OS << " (" << Name << ", dir=" << FileEntry.DirIdx << ", mod_time="
+                << format("(0x%16.16" PRIx64 ")", FileEntry.ModTime)
+                << ", length=" << FileEntry.Length << ")";
+        }
+        break;
+
+      case DW_LNE_set_discriminator:
+        State.Row.Discriminator = DebugLineData.getULEB128(OffsetPtr);
+        if (OS)
+          *OS << " (" << State.Row.Discriminator << ")";
+        break;
+
+      default:
+        if (OS)
+          *OS << format("Unrecognized extended op 0x%02.02" PRIx8, SubOpcode)
+              << format(" length %" PRIx64, Len);
+        // Len doesn't include the zero opcode byte or the length itself, but
+        // it does include the sub_opcode, so we have to adjust for that.
+        (*OffsetPtr) += Len - 1;
+        break;
+      }
+      // Make sure the stated and parsed lengths are the same.
+      // Otherwise we have an unparseable line-number program.
+      if (*OffsetPtr - ExtOffset != Len)
+        return createStringError(errc::illegal_byte_sequence,
+                           "unexpected line op length at offset 0x%8.8" PRIx64
+                           " expected 0x%2.2" PRIx64 " found 0x%2.2" PRIx64,
+                           ExtOffset, Len, *OffsetPtr - ExtOffset);
+    } else if (Opcode < Prologue.OpcodeBase) {
+      if (OS)
+        *OS << LNStandardString(Opcode);
+      switch (Opcode) {
+      // Standard Opcodes
+      case DW_LNS_copy:
+        // Takes no arguments. Append a row to the matrix using the
+        // current values of the state-machine registers.
+        if (OS) {
+          *OS << "\n";
+          OS->indent(12);
+          State.Row.dump(*OS);
+          *OS << "\n";
+        }
+        State.appendRowToMatrix();
+        break;
+
+      case DW_LNS_advance_pc:
+        // Takes a single unsigned LEB128 operand, multiplies it by the
+        // min_inst_length field of the prologue, and adds the
+        // result to the address register of the state machine.
+        {
+          uint64_t AddrOffset =
+              DebugLineData.getULEB128(OffsetPtr) * Prologue.MinInstLength;
+          State.Row.Address.Address += AddrOffset;
+          if (OS)
+            *OS << " (" << AddrOffset << ")";
+        }
+        break;
+
+      case DW_LNS_advance_line:
+        // Takes a single signed LEB128 operand and adds that value to
+        // the line register of the state machine.
+        State.Row.Line += DebugLineData.getSLEB128(OffsetPtr);
+        if (OS)
+          *OS << " (" << State.Row.Line << ")";
+        break;
+
+      case DW_LNS_set_file:
+        // Takes a single unsigned LEB128 operand and stores it in the file
+        // register of the state machine.
+        State.Row.File = DebugLineData.getULEB128(OffsetPtr);
+        if (OS)
+          *OS << " (" << State.Row.File << ")";
+        break;
+
+      case DW_LNS_set_column:
+        // Takes a single unsigned LEB128 operand and stores it in the
+        // column register of the state machine.
+        State.Row.Column = DebugLineData.getULEB128(OffsetPtr);
+        if (OS)
+          *OS << " (" << State.Row.Column << ")";
+        break;
+
+      case DW_LNS_negate_stmt:
+        // Takes no arguments. Set the is_stmt register of the state
+        // machine to the logical negation of its current value.
+        State.Row.IsStmt = !State.Row.IsStmt;
+        break;
+
+      case DW_LNS_set_basic_block:
+        // Takes no arguments. Set the basic_block register of the
+        // state machine to true
+        State.Row.BasicBlock = true;
+        break;
+
+      case DW_LNS_const_add_pc:
+        // Takes no arguments. Add to the address register of the state
+        // machine the address increment value corresponding to special
+        // opcode 255. The motivation for DW_LNS_const_add_pc is this:
+        // when the statement program needs to advance the address by a
+        // small amount, it can use a single special opcode, which occupies
+        // a single byte. When it needs to advance the address by up to
+        // twice the range of the last special opcode, it can use
+        // DW_LNS_const_add_pc followed by a special opcode, for a total
+        // of two bytes. Only if it needs to advance the address by more
+        // than twice that range will it need to use both DW_LNS_advance_pc
+        // and a special opcode, requiring three or more bytes.
+        {
+          uint8_t AdjustOpcode = 255 - Prologue.OpcodeBase;
+          uint64_t AddrOffset =
+              (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength;
+          State.Row.Address.Address += AddrOffset;
+          if (OS)
+            *OS
+                << format(" (0x%16.16" PRIx64 ")", AddrOffset);
+        }
+        break;
+
+      case DW_LNS_fixed_advance_pc:
+        // Takes a single uhalf operand. Add to the address register of
+        // the state machine the value of the (unencoded) operand. This
+        // is the only extended opcode that takes an argument that is not
+        // a variable length number. The motivation for DW_LNS_fixed_advance_pc
+        // is this: existing assemblers cannot emit DW_LNS_advance_pc or
+        // special opcodes because they cannot encode LEB128 numbers or
+        // judge when the computation of a special opcode overflows and
+        // requires the use of DW_LNS_advance_pc. Such assemblers, however,
+        // can use DW_LNS_fixed_advance_pc instead, sacrificing compression.
+        {
+          uint16_t PCOffset = DebugLineData.getRelocatedValue(2, OffsetPtr);
+          State.Row.Address.Address += PCOffset;
+          if (OS)
+            *OS
+                << format(" (0x%4.4" PRIx16 ")", PCOffset);
+        }
+        break;
+
+      case DW_LNS_set_prologue_end:
+        // Takes no arguments. Set the prologue_end register of the
+        // state machine to true
+        State.Row.PrologueEnd = true;
+        break;
+
+      case DW_LNS_set_epilogue_begin:
+        // Takes no arguments. Set the basic_block register of the
+        // state machine to true
+        State.Row.EpilogueBegin = true;
+        break;
+
+      case DW_LNS_set_isa:
+        // Takes a single unsigned LEB128 operand and stores it in the
+        // column register of the state machine.
+        State.Row.Isa = DebugLineData.getULEB128(OffsetPtr);
+        if (OS)
+          *OS << " (" << State.Row.Isa << ")";
+        break;
+
+      default:
+        // Handle any unknown standard opcodes here. We know the lengths
+        // of such opcodes because they are specified in the prologue
+        // as a multiple of LEB128 operands for each opcode.
+        {
+          assert(Opcode - 1U < Prologue.StandardOpcodeLengths.size());
+          uint8_t OpcodeLength = Prologue.StandardOpcodeLengths[Opcode - 1];
+          for (uint8_t I = 0; I < OpcodeLength; ++I) {
+            uint64_t Value = DebugLineData.getULEB128(OffsetPtr);
+            if (OS)
+              *OS << format("Skipping ULEB128 value: 0x%16.16" PRIx64 ")\n",
+                            Value);
+          }
+        }
+        break;
+      }
+    } else {
+      // Special Opcodes
+
+      // A special opcode value is chosen based on the amount that needs
+      // to be added to the line and address registers. The maximum line
+      // increment for a special opcode is the value of the line_base
+      // field in the header, plus the value of the line_range field,
+      // minus 1 (line base + line range - 1). If the desired line
+      // increment is greater than the maximum line increment, a standard
+      // opcode must be used instead of a special opcode. The "address
+      // advance" is calculated by dividing the desired address increment
+      // by the minimum_instruction_length field from the header. The
+      // special opcode is then calculated using the following formula:
+      //
+      //  opcode = (desired line increment - line_base) +
+      //           (line_range * address advance) + opcode_base
+      //
+      // If the resulting opcode is greater than 255, a standard opcode
+      // must be used instead.
+      //
+      // To decode a special opcode, subtract the opcode_base from the
+      // opcode itself to give the adjusted opcode. The amount to
+      // increment the address register is the result of the adjusted
+      // opcode divided by the line_range multiplied by the
+      // minimum_instruction_length field from the header. That is:
+      //
+      //  address increment = (adjusted opcode / line_range) *
+      //                      minimum_instruction_length
+      //
+      // The amount to increment the line register is the line_base plus
+      // the result of the adjusted opcode modulo the line_range. That is:
+      //
+      // line increment = line_base + (adjusted opcode % line_range)
+
+      uint8_t AdjustOpcode = Opcode - Prologue.OpcodeBase;
+      uint64_t AddrOffset =
+          (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength;
+      int32_t LineOffset =
+          Prologue.LineBase + (AdjustOpcode % Prologue.LineRange);
+      State.Row.Line += LineOffset;
+      State.Row.Address.Address += AddrOffset;
+
+      if (OS) {
+        *OS << "address += " << AddrOffset << ",  line += " << LineOffset
+            << "\n";
+        OS->indent(12);
+        State.Row.dump(*OS);
+      }
+
+      State.appendRowToMatrix();
+    }
+    if(OS)
+      *OS << "\n";
+  }
+
+  if (!State.Sequence.Empty)
+    RecoverableErrorCallback(
+        createStringError(errc::illegal_byte_sequence,
+                    "last sequence in debug line table is not terminated!"));
+
+  // Sort all sequences so that address lookup will work faster.
+  if (!Sequences.empty()) {
+    llvm::sort(Sequences, Sequence::orderByHighPC);
+    // Note: actually, instruction address ranges of sequences should not
+    // overlap (in shared objects and executables). If they do, the address
+    // lookup would still work, though, but result would be ambiguous.
+    // We don't report warning in this case. For example,
+    // sometimes .so compiled from multiple object files contains a few
+    // rudimentary sequences for address ranges [0x0, 0xsomething).
+  }
+
+  return Error::success();
+}
+
+uint32_t DWARFDebugLine::LineTable::findRowInSeq(
+    const DWARFDebugLine::Sequence &Seq,
+    object::SectionedAddress Address) const {
+  if (!Seq.containsPC(Address))
+    return UnknownRowIndex;
+  assert(Seq.SectionIndex == Address.SectionIndex);
+  // In some cases, e.g. first instruction in a function, the compiler generates
+  // two entries, both with the same address. We want the last one.
+  //
+  // In general we want a non-empty range: the last row whose address is less
+  // than or equal to Address. This can be computed as upper_bound - 1.
+  DWARFDebugLine::Row Row;
+  Row.Address = Address;
+  RowIter FirstRow = Rows.begin() + Seq.FirstRowIndex;
+  RowIter LastRow = Rows.begin() + Seq.LastRowIndex;
+  assert(FirstRow->Address.Address <= Row.Address.Address &&
+         Row.Address.Address < LastRow[-1].Address.Address);
+  RowIter RowPos = std::upper_bound(FirstRow + 1, LastRow - 1, Row,
+                                    DWARFDebugLine::Row::orderByAddress) -
+                   1;
+  assert(Seq.SectionIndex == RowPos->Address.SectionIndex);
+  return RowPos - Rows.begin();
+}
+
+uint32_t DWARFDebugLine::LineTable::lookupAddress(
+    object::SectionedAddress Address) const {
+
+  // Search for relocatable addresses
+  uint32_t Result = lookupAddressImpl(Address);
+
+  if (Result != UnknownRowIndex ||
+      Address.SectionIndex == object::SectionedAddress::UndefSection)
+    return Result;
+
+  // Search for absolute addresses
+  Address.SectionIndex = object::SectionedAddress::UndefSection;
+  return lookupAddressImpl(Address);
+}
+
+uint32_t DWARFDebugLine::LineTable::lookupAddressImpl(
+    object::SectionedAddress Address) const {
+  // First, find an instruction sequence containing the given address.
+  DWARFDebugLine::Sequence Sequence;
+  Sequence.SectionIndex = Address.SectionIndex;
+  Sequence.HighPC = Address.Address;
+  SequenceIter It = llvm::upper_bound(Sequences, Sequence,
+                                      DWARFDebugLine::Sequence::orderByHighPC);
+  if (It == Sequences.end() || It->SectionIndex != Address.SectionIndex)
+    return UnknownRowIndex;
+  return findRowInSeq(*It, Address);
+}
+
+bool DWARFDebugLine::LineTable::lookupAddressRange(
+    object::SectionedAddress Address, uint64_t Size,
+    std::vector<uint32_t> &Result) const {
+
+  // Search for relocatable addresses
+  if (lookupAddressRangeImpl(Address, Size, Result))
+    return true;
+
+  if (Address.SectionIndex == object::SectionedAddress::UndefSection)
+    return false;
+
+  // Search for absolute addresses
+  Address.SectionIndex = object::SectionedAddress::UndefSection;
+  return lookupAddressRangeImpl(Address, Size, Result);
+}
+
+bool DWARFDebugLine::LineTable::lookupAddressRangeImpl(
+    object::SectionedAddress Address, uint64_t Size,
+    std::vector<uint32_t> &Result) const {
+  if (Sequences.empty())
+    return false;
+  uint64_t EndAddr = Address.Address + Size;
+  // First, find an instruction sequence containing the given address.
+  DWARFDebugLine::Sequence Sequence;
+  Sequence.SectionIndex = Address.SectionIndex;
+  Sequence.HighPC = Address.Address;
+  SequenceIter LastSeq = Sequences.end();
+  SequenceIter SeqPos = llvm::upper_bound(
+      Sequences, Sequence, DWARFDebugLine::Sequence::orderByHighPC);
+  if (SeqPos == LastSeq || !SeqPos->containsPC(Address))
+    return false;
+
+  SequenceIter StartPos = SeqPos;
+
+  // Add the rows from the first sequence to the vector, starting with the
+  // index we just calculated
+
+  while (SeqPos != LastSeq && SeqPos->LowPC < EndAddr) {
+    const DWARFDebugLine::Sequence &CurSeq = *SeqPos;
+    // For the first sequence, we need to find which row in the sequence is the
+    // first in our range.
+    uint32_t FirstRowIndex = CurSeq.FirstRowIndex;
+    if (SeqPos == StartPos)
+      FirstRowIndex = findRowInSeq(CurSeq, Address);
+
+    // Figure out the last row in the range.
+    uint32_t LastRowIndex =
+        findRowInSeq(CurSeq, {EndAddr - 1, Address.SectionIndex});
+    if (LastRowIndex == UnknownRowIndex)
+      LastRowIndex = CurSeq.LastRowIndex - 1;
+
+    assert(FirstRowIndex != UnknownRowIndex);
+    assert(LastRowIndex != UnknownRowIndex);
+
+    for (uint32_t I = FirstRowIndex; I <= LastRowIndex; ++I) {
+      Result.push_back(I);
+    }
+
+    ++SeqPos;
+  }
+
+  return true;
+}
+
+Optional<StringRef> DWARFDebugLine::LineTable::getSourceByIndex(uint64_t FileIndex,
+                                                                FileLineInfoKind Kind) const {
+  if (Kind == FileLineInfoKind::None || !Prologue.hasFileAtIndex(FileIndex))
+    return None;
+  const FileNameEntry &Entry = Prologue.getFileNameEntry(FileIndex);
+  if (Optional<const char *> source = Entry.Source.getAsCString())
+    return StringRef(*source);
+  return None;
+}
+
+static bool isPathAbsoluteOnWindowsOrPosix(const Twine &Path) {
+  // Debug info can contain paths from any OS, not necessarily
+  // an OS we're currently running on. Moreover different compilation units can
+  // be compiled on different operating systems and linked together later.
+  return sys::path::is_absolute(Path, sys::path::Style::posix) ||
+         sys::path::is_absolute(Path, sys::path::Style::windows);
+}
+
+bool DWARFDebugLine::Prologue::getFileNameByIndex(
+    uint64_t FileIndex, StringRef CompDir, FileLineInfoKind Kind,
+    std::string &Result, sys::path::Style Style) const {
+  if (Kind == FileLineInfoKind::None || !hasFileAtIndex(FileIndex))
+    return false;
+  const FileNameEntry &Entry = getFileNameEntry(FileIndex);
+  StringRef FileName = Entry.Name.getAsCString().getValue();
+  if (Kind != FileLineInfoKind::AbsoluteFilePath ||
+      isPathAbsoluteOnWindowsOrPosix(FileName)) {
+    Result = FileName;
+    return true;
+  }
+
+  SmallString<16> FilePath;
+  StringRef IncludeDir;
+  // Be defensive about the contents of Entry.
+  if (getVersion() >= 5) {
+    if (Entry.DirIdx < IncludeDirectories.size())
+      IncludeDir = IncludeDirectories[Entry.DirIdx].getAsCString().getValue();
+  } else {
+    if (0 < Entry.DirIdx && Entry.DirIdx <= IncludeDirectories.size())
+      IncludeDir =
+          IncludeDirectories[Entry.DirIdx - 1].getAsCString().getValue();
+
+    // We may still need to append compilation directory of compile unit.
+    // We know that FileName is not absolute, the only way to have an
+    // absolute path at this point would be if IncludeDir is absolute.
+    if (!CompDir.empty() && !isPathAbsoluteOnWindowsOrPosix(IncludeDir))
+      sys::path::append(FilePath, Style, CompDir);
+  }
+
+  // sys::path::append skips empty strings.
+  sys::path::append(FilePath, Style, IncludeDir, FileName);
+  Result = FilePath.str();
+  return true;
+}
+
+bool DWARFDebugLine::LineTable::getFileLineInfoForAddress(
+    object::SectionedAddress Address, const char *CompDir,
+    FileLineInfoKind Kind, DILineInfo &Result) const {
+  // Get the index of row we're looking for in the line table.
+  uint32_t RowIndex = lookupAddress(Address);
+  if (RowIndex == -1U)
+    return false;
+  // Take file number and line/column from the row.
+  const auto &Row = Rows[RowIndex];
+  if (!getFileNameByIndex(Row.File, CompDir, Kind, Result.FileName))
+    return false;
+  Result.Line = Row.Line;
+  Result.Column = Row.Column;
+  Result.Discriminator = Row.Discriminator;
+  Result.Source = getSourceByIndex(Row.File, Kind);
+  return true;
+}
+
+// We want to supply the Unit associated with a .debug_line[.dwo] table when
+// we dump it, if possible, but still dump the table even if there isn't a Unit.
+// Therefore, collect up handles on all the Units that point into the
+// line-table section.
+static DWARFDebugLine::SectionParser::LineToUnitMap
+buildLineToUnitMap(DWARFDebugLine::SectionParser::cu_range CUs,
+                   DWARFDebugLine::SectionParser::tu_range TUs) {
+  DWARFDebugLine::SectionParser::LineToUnitMap LineToUnit;
+  for (const auto &CU : CUs)
+    if (auto CUDIE = CU->getUnitDIE())
+      if (auto StmtOffset = toSectionOffset(CUDIE.find(DW_AT_stmt_list)))
+        LineToUnit.insert(std::make_pair(*StmtOffset, &*CU));
+  for (const auto &TU : TUs)
+    if (auto TUDIE = TU->getUnitDIE())
+      if (auto StmtOffset = toSectionOffset(TUDIE.find(DW_AT_stmt_list)))
+        LineToUnit.insert(std::make_pair(*StmtOffset, &*TU));
+  return LineToUnit;
+}
+
+DWARFDebugLine::SectionParser::SectionParser(DWARFDataExtractor &Data,
+                                             const DWARFContext &C,
+                                             cu_range CUs, tu_range TUs)
+    : DebugLineData(Data), Context(C) {
+  LineToUnit = buildLineToUnitMap(CUs, TUs);
+  if (!DebugLineData.isValidOffset(Offset))
+    Done = true;
+}
+
+bool DWARFDebugLine::Prologue::totalLengthIsValid() const {
+  return TotalLength == dwarf::DW_LENGTH_DWARF64 ||
+         TotalLength < dwarf::DW_LENGTH_lo_reserved;
+}
+
+DWARFDebugLine::LineTable DWARFDebugLine::SectionParser::parseNext(
+    function_ref<void(Error)> RecoverableErrorCallback,
+    function_ref<void(Error)> UnrecoverableErrorCallback, raw_ostream *OS) {
+  assert(DebugLineData.isValidOffset(Offset) &&
+         "parsing should have terminated");
+  DWARFUnit *U = prepareToParse(Offset);
+  uint64_t OldOffset = Offset;
+  LineTable LT;
+  if (Error Err = LT.parse(DebugLineData, &Offset, Context, U,
+                           RecoverableErrorCallback, OS))
+    UnrecoverableErrorCallback(std::move(Err));
+  moveToNextTable(OldOffset, LT.Prologue);
+  return LT;
+}
+
+void DWARFDebugLine::SectionParser::skip(
+    function_ref<void(Error)> ErrorCallback) {
+  assert(DebugLineData.isValidOffset(Offset) &&
+         "parsing should have terminated");
+  DWARFUnit *U = prepareToParse(Offset);
+  uint64_t OldOffset = Offset;
+  LineTable LT;
+  if (Error Err = LT.Prologue.parse(DebugLineData, &Offset, Context, U))
+    ErrorCallback(std::move(Err));
+  moveToNextTable(OldOffset, LT.Prologue);
+}
+
+DWARFUnit *DWARFDebugLine::SectionParser::prepareToParse(uint64_t Offset) {
+  DWARFUnit *U = nullptr;
+  auto It = LineToUnit.find(Offset);
+  if (It != LineToUnit.end())
+    U = It->second;
+  DebugLineData.setAddressSize(U ? U->getAddressByteSize() : 0);
+  return U;
+}
+
+void DWARFDebugLine::SectionParser::moveToNextTable(uint64_t OldOffset,
+                                                    const Prologue &P) {
+  // If the length field is not valid, we don't know where the next table is, so
+  // cannot continue to parse. Mark the parser as done, and leave the Offset
+  // value as it currently is. This will be the end of the bad length field.
+  if (!P.totalLengthIsValid()) {
+    Done = true;
+    return;
+  }
+
+  Offset = OldOffset + P.TotalLength + P.sizeofTotalLength();
+  if (!DebugLineData.isValidOffset(Offset)) {
+    Done = true;
+  }
+}
diff --git a/binaryen/third_party/llvm-project/DWARFDebugLoc.cpp b/binaryen/third_party/llvm-project/DWARFDebugLoc.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFDebugLoc.cpp
@@ -0,0 +1,326 @@
+//===- DWARFDebugLoc.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
+#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cinttypes>
+#include <cstdint>
+
+using namespace llvm;
+
+// When directly dumping the .debug_loc without a compile unit, we have to guess
+// at the DWARF version. This only affects DW_OP_call_ref, which is a rare
+// expression that LLVM doesn't produce. Guessing the wrong version means we
+// won't be able to pretty print expressions in DWARF2 binaries produced by
+// non-LLVM tools.
+static void dumpExpression(raw_ostream &OS, ArrayRef<uint8_t> Data,
+                           bool IsLittleEndian, unsigned AddressSize,
+                           const MCRegisterInfo *MRI, DWARFUnit *U) {
+  DWARFDataExtractor Extractor(toStringRef(Data), IsLittleEndian, AddressSize);
+  DWARFExpression(Extractor, dwarf::DWARF_VERSION, AddressSize).print(OS, MRI, U);
+}
+
+void DWARFDebugLoc::LocationList::dump(raw_ostream &OS, uint64_t BaseAddress,
+                                       bool IsLittleEndian,
+                                       unsigned AddressSize,
+                                       const MCRegisterInfo *MRI, DWARFUnit *U,
+                                       DIDumpOptions DumpOpts,
+                                       unsigned Indent) const {
+  for (const Entry &E : Entries) {
+    OS << '\n';
+    OS.indent(Indent);
+    OS << format("[0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2,
+                 BaseAddress + E.Begin);
+    OS << format(" 0x%*.*" PRIx64 ")", AddressSize * 2, AddressSize * 2,
+                 BaseAddress + E.End);
+    OS << ": ";
+
+    dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI, U);
+  }
+}
+
+DWARFDebugLoc::LocationList const *
+DWARFDebugLoc::getLocationListAtOffset(uint64_t Offset) const {
+  auto It = partition_point(
+      Locations, [=](const LocationList &L) { return L.Offset < Offset; });
+  if (It != Locations.end() && It->Offset == Offset)
+    return &(*It);
+  return nullptr;
+}
+
+void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI, DIDumpOptions DumpOpts,
+                         Optional<uint64_t> Offset) const {
+  auto DumpLocationList = [&](const LocationList &L) {
+    OS << format("0x%8.8" PRIx64 ": ", L.Offset);
+    L.dump(OS, 0, IsLittleEndian, AddressSize, MRI, nullptr, DumpOpts, 12);
+    OS << "\n";
+  };
+
+  if (Offset) {
+    if (auto *L = getLocationListAtOffset(*Offset))
+      DumpLocationList(*L);
+    return;
+  }
+
+  for (const LocationList &L : Locations) {
+    DumpLocationList(L);
+    if (&L != &Locations.back())
+      OS << '\n';
+  }
+}
+
+Expected<DWARFDebugLoc::LocationList>
+DWARFDebugLoc::parseOneLocationList(const DWARFDataExtractor &Data,
+                                    uint64_t *Offset) {
+  LocationList LL;
+  LL.Offset = *Offset;
+  AddressSize = Data.getAddressSize();
+  DataExtractor::Cursor C(*Offset);
+
+  // 2.6.2 Location Lists
+  // A location list entry consists of:
+  while (true) {
+    Entry E;
+
+    // 1. A beginning address offset. ...
+    E.Begin = Data.getRelocatedAddress(C);
+
+    // 2. An ending address offset. ...
+    E.End = Data.getRelocatedAddress(C);
+
+    if (Error Err = C.takeError())
+      return std::move(Err);
+
+    // The end of any given location list is marked by an end of list entry,
+    // which consists of a 0 for the beginning address offset and a 0 for the
+    // ending address offset.
+    if (E.Begin == 0 && E.End == 0) {
+      *Offset = C.tell();
+      return LL;
+    }
+
+    if (E.Begin != (AddressSize == 4 ? -1U : -1ULL)) {
+      unsigned Bytes = Data.getU16(C);
+      // A single location description describing the location of the object...
+      Data.getU8(C, E.Loc, Bytes);
+    }
+
+    LL.Entries.push_back(std::move(E));
+  }
+}
+
+void DWARFDebugLoc::parse(const DWARFDataExtractor &data) {
+  IsLittleEndian = data.isLittleEndian();
+  AddressSize = data.getAddressSize();
+
+  uint64_t Offset = 0;
+  while (Offset < data.getData().size()) {
+    if (auto LL = parseOneLocationList(data, &Offset))
+      Locations.push_back(std::move(*LL));
+    else {
+      logAllUnhandledErrors(LL.takeError(), WithColor::error());
+      break;
+    }
+  }
+}
+
+Error DWARFDebugLoclists::visitLocationList(
+    const DWARFDataExtractor &Data, uint64_t *Offset, uint16_t Version,
+    llvm::function_ref<bool(const Entry &)> F) {
+
+  DataExtractor::Cursor C(*Offset);
+  bool Continue = true;
+  while (Continue) {
+    Entry E;
+    E.Offset = C.tell();
+    E.Kind = Data.getU8(C);
+    switch (E.Kind) {
+    case dwarf::DW_LLE_end_of_list:
+      break;
+    case dwarf::DW_LLE_base_addressx:
+      E.Value0 = Data.getULEB128(C);
+      break;
+    case dwarf::DW_LLE_startx_length:
+      E.Value0 = Data.getULEB128(C);
+      // Pre-DWARF 5 has different interpretation of the length field. We have
+      // to support both pre- and standartized styles for the compatibility.
+      if (Version < 5)
+        E.Value1 = Data.getU32(C);
+      else
+        E.Value1 = Data.getULEB128(C);
+      break;
+    case dwarf::DW_LLE_offset_pair:
+      E.Value0 = Data.getULEB128(C);
+      E.Value1 = Data.getULEB128(C);
+      break;
+    case dwarf::DW_LLE_base_address:
+      E.Value0 = Data.getRelocatedAddress(C);
+      break;
+    case dwarf::DW_LLE_start_length:
+      E.Value0 = Data.getRelocatedAddress(C);
+      E.Value1 = Data.getULEB128(C);
+      break;
+    case dwarf::DW_LLE_startx_endx:
+    case dwarf::DW_LLE_default_location:
+    case dwarf::DW_LLE_start_end:
+    default:
+      cantFail(C.takeError());
+      return createStringError(errc::illegal_byte_sequence,
+                               "LLE of kind %x not supported", (int)E.Kind);
+    }
+
+    if (E.Kind != dwarf::DW_LLE_base_address &&
+        E.Kind != dwarf::DW_LLE_base_addressx &&
+        E.Kind != dwarf::DW_LLE_end_of_list) {
+      unsigned Bytes = Version >= 5 ? Data.getULEB128(C) : Data.getU16(C);
+      // A single location description describing the location of the object...
+      Data.getU8(C, E.Loc, Bytes);
+    }
+
+    if (!C)
+      return C.takeError();
+    Continue = F(E) && E.Kind != dwarf::DW_LLE_end_of_list;
+  }
+  *Offset = C.tell();
+  return Error::success();
+}
+
+bool DWARFDebugLoclists::dumpLocationList(const DWARFDataExtractor &Data,
+                                          uint64_t *Offset, uint16_t Version,
+                                          raw_ostream &OS, uint64_t BaseAddr,
+                                          const MCRegisterInfo *MRI,
+                                          DWARFUnit *U, DIDumpOptions DumpOpts,
+                                          unsigned Indent) {
+  size_t MaxEncodingStringLength = 0;
+  if (DumpOpts.Verbose) {
+#define HANDLE_DW_LLE(ID, NAME)                                                \
+  MaxEncodingStringLength = std::max(MaxEncodingStringLength,                  \
+                                     dwarf::LocListEncodingString(ID).size());
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+
+  OS << format("0x%8.8" PRIx64 ": ", *Offset);
+  Error E = visitLocationList(Data, Offset, Version, [&](const Entry &E) {
+    E.dump(OS, BaseAddr, Data.isLittleEndian(), Data.getAddressSize(), MRI, U,
+           DumpOpts, Indent, MaxEncodingStringLength);
+    return true;
+  });
+  if (E) {
+    OS << "\n";
+    OS.indent(Indent);
+    OS << "error: " << toString(std::move(E));
+    return false;
+  }
+  return true;
+}
+
+void DWARFDebugLoclists::Entry::dump(raw_ostream &OS, uint64_t &BaseAddr,
+                                     bool IsLittleEndian, unsigned AddressSize,
+                                     const MCRegisterInfo *MRI, DWARFUnit *U,
+                                     DIDumpOptions DumpOpts, unsigned Indent,
+                                     size_t MaxEncodingStringLength) const {
+  if (DumpOpts.Verbose) {
+    OS << "\n";
+    OS.indent(Indent);
+    auto EncodingString = dwarf::LocListEncodingString(Kind);
+    // Unsupported encodings should have been reported during parsing.
+    assert(!EncodingString.empty() && "Unknown loclist entry encoding");
+    OS << format("%s%*c", EncodingString.data(),
+                 MaxEncodingStringLength - EncodingString.size() + 1, '(');
+    switch (Kind) {
+    case dwarf::DW_LLE_startx_length:
+    case dwarf::DW_LLE_start_length:
+    case dwarf::DW_LLE_offset_pair:
+      OS << format("0x%*.*" PRIx64 ", 0x%*.*" PRIx64, AddressSize * 2,
+                 AddressSize * 2, Value0, AddressSize * 2, AddressSize * 2,
+                 Value1);
+      break;
+    case dwarf::DW_LLE_base_addressx:
+    case dwarf::DW_LLE_base_address:
+      OS << format("0x%*.*" PRIx64, AddressSize * 2, AddressSize * 2,
+                   Value0);
+      break;
+    case dwarf::DW_LLE_end_of_list:
+      break;
+    }
+    OS << ')';
+  }
+  auto PrintPrefix = [&] {
+    OS << "\n";
+    OS.indent(Indent);
+    if (DumpOpts.Verbose)
+      OS << format("%*s", MaxEncodingStringLength, (const char *)"=> ");
+  };
+  switch (Kind) {
+  case dwarf::DW_LLE_startx_length:
+    PrintPrefix();
+    OS << "Addr idx " << Value0 << " (w/ length " << Value1 << "): ";
+    break;
+  case dwarf::DW_LLE_start_length:
+    PrintPrefix();
+    DWARFAddressRange(Value0, Value0 + Value1)
+        .dump(OS, AddressSize, DumpOpts);
+    OS << ": ";
+    break;
+  case dwarf::DW_LLE_offset_pair:
+    PrintPrefix();
+    DWARFAddressRange(BaseAddr + Value0, BaseAddr + Value1)
+        .dump(OS, AddressSize, DumpOpts);
+    OS << ": ";
+    break;
+  case dwarf::DW_LLE_base_addressx:
+    if (!DumpOpts.Verbose)
+      return;
+    break;
+  case dwarf::DW_LLE_end_of_list:
+    if (!DumpOpts.Verbose)
+      return;
+    break;
+  case dwarf::DW_LLE_base_address:
+    BaseAddr = Value0;
+    if (!DumpOpts.Verbose)
+      return;
+    break;
+  default:
+    llvm_unreachable("unreachable locations list kind");
+  }
+
+  dumpExpression(OS, Loc, IsLittleEndian, AddressSize, MRI, U);
+}
+
+void DWARFDebugLoclists::dumpRange(const DWARFDataExtractor &Data,
+                                   uint64_t StartOffset, uint64_t Size,
+                                   uint16_t Version, raw_ostream &OS,
+                                   uint64_t BaseAddr, const MCRegisterInfo *MRI,
+                                   DIDumpOptions DumpOpts) {
+  if (!Data.isValidOffsetForDataOfSize(StartOffset, Size))  {
+    OS << "Invalid dump range\n";
+    return;
+  }
+  uint64_t Offset = StartOffset;
+  StringRef Separator;
+  bool CanContinue = true;
+  while (CanContinue && Offset < StartOffset + Size) {
+    OS << Separator;
+    Separator = "\n";
+
+    CanContinue = dumpLocationList(Data, &Offset, Version, OS, BaseAddr, MRI,
+                                   nullptr, DumpOpts, /*Indent=*/12);
+    OS << '\n';
+  }
+}
diff --git a/binaryen/third_party/llvm-project/DWARFDebugMacro.cpp b/binaryen/third_party/llvm-project/DWARFDebugMacro.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFDebugMacro.cpp
@@ -0,0 +1,106 @@
+//===- DWARFDebugMacro.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace dwarf;
+
+void DWARFDebugMacro::dump(raw_ostream &OS) const {
+  unsigned IndLevel = 0;
+  for (const auto &Macros : MacroLists) {
+    for (const Entry &E : Macros) {
+      // There should not be DW_MACINFO_end_file when IndLevel is Zero. However,
+      // this check handles the case of corrupted ".debug_macinfo" section.
+      if (IndLevel > 0)
+        IndLevel -= (E.Type == DW_MACINFO_end_file);
+      // Print indentation.
+      for (unsigned I = 0; I < IndLevel; I++)
+        OS << "  ";
+      IndLevel += (E.Type == DW_MACINFO_start_file);
+
+      WithColor(OS, HighlightColor::Macro).get() << MacinfoString(E.Type);
+      switch (E.Type) {
+      default:
+        // Got a corrupted ".debug_macinfo" section (invalid macinfo type).
+        break;
+      case DW_MACINFO_define:
+      case DW_MACINFO_undef:
+        OS << " - lineno: " << E.Line;
+        OS << " macro: " << E.MacroStr;
+        break;
+      case DW_MACINFO_start_file:
+        OS << " - lineno: " << E.Line;
+        OS << " filenum: " << E.File;
+        break;
+      case DW_MACINFO_end_file:
+        break;
+      case DW_MACINFO_vendor_ext:
+        OS << " - constant: " << E.ExtConstant;
+        OS << " string: " << E.ExtStr;
+        break;
+      }
+      OS << "\n";
+    }
+    OS << "\n";
+  }
+}
+
+void DWARFDebugMacro::parse(DataExtractor data) {
+  uint64_t Offset = 0;
+  MacroList *M = nullptr;
+  while (data.isValidOffset(Offset)) {
+    if (!M) {
+      MacroLists.emplace_back();
+      M = &MacroLists.back();
+    }
+    // A macro list entry consists of:
+    M->emplace_back();
+    Entry &E = M->back();
+    // 1. Macinfo type
+    E.Type = data.getULEB128(&Offset);
+
+    if (E.Type == 0) {
+      // Reached end of a ".debug_macinfo" section contribution.
+      continue;
+    }
+
+    switch (E.Type) {
+    default:
+      // Got a corrupted ".debug_macinfo" section (invalid macinfo type).
+      // Push the corrupted entry to the list and halt parsing.
+      E.Type = DW_MACINFO_invalid;
+      return;
+    case DW_MACINFO_define:
+    case DW_MACINFO_undef:
+      // 2. Source line
+      E.Line = data.getULEB128(&Offset);
+      // 3. Macro string
+      E.MacroStr = data.getCStr(&Offset);
+      break;
+    case DW_MACINFO_start_file:
+      // 2. Source line
+      E.Line = data.getULEB128(&Offset);
+      // 3. Source file id
+      E.File = data.getULEB128(&Offset);
+      break;
+    case DW_MACINFO_end_file:
+      break;
+    case DW_MACINFO_vendor_ext:
+      // 2. Vendor extension constant
+      E.ExtConstant = data.getULEB128(&Offset);
+      // 3. Vendor extension string
+      E.ExtStr = data.getCStr(&Offset);
+      break;
+    }
+  }
+}
diff --git a/binaryen/third_party/llvm-project/DWARFDebugPubTable.cpp b/binaryen/third_party/llvm-project/DWARFDebugPubTable.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFDebugPubTable.cpp
@@ -0,0 +1,69 @@
+//===- DWARFDebugPubTable.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace dwarf;
+
+DWARFDebugPubTable::DWARFDebugPubTable(const DWARFObject &Obj,
+                                       const DWARFSection &Sec,
+                                       bool LittleEndian, bool GnuStyle)
+    : GnuStyle(GnuStyle) {
+  DWARFDataExtractor PubNames(Obj, Sec, LittleEndian, 0);
+  uint64_t Offset = 0;
+  while (PubNames.isValidOffset(Offset)) {
+    Sets.push_back({});
+    Set &SetData = Sets.back();
+
+    SetData.Length = PubNames.getU32(&Offset);
+    SetData.Version = PubNames.getU16(&Offset);
+    SetData.Offset = PubNames.getRelocatedValue(4, &Offset);
+    SetData.Size = PubNames.getU32(&Offset);
+
+    while (Offset < Sec.Data.size()) {
+      uint32_t DieRef = PubNames.getU32(&Offset);
+      if (DieRef == 0)
+        break;
+      uint8_t IndexEntryValue = GnuStyle ? PubNames.getU8(&Offset) : 0;
+      StringRef Name = PubNames.getCStrRef(&Offset);
+      SetData.Entries.push_back(
+          {DieRef, PubIndexEntryDescriptor(IndexEntryValue), Name});
+    }
+  }
+}
+
+void DWARFDebugPubTable::dump(raw_ostream &OS) const {
+  for (const Set &S : Sets) {
+    OS << "length = " << format("0x%08x", S.Length);
+    OS << " version = " << format("0x%04x", S.Version);
+    OS << " unit_offset = " << format("0x%08" PRIx64, S.Offset);
+    OS << " unit_size = " << format("0x%08x", S.Size) << '\n';
+    OS << (GnuStyle ? "Offset     Linkage  Kind     Name\n"
+                    : "Offset     Name\n");
+
+    for (const Entry &E : S.Entries) {
+      OS << format("0x%8.8" PRIx64 " ", E.SecOffset);
+      if (GnuStyle) {
+        StringRef EntryLinkage =
+            GDBIndexEntryLinkageString(E.Descriptor.Linkage);
+        StringRef EntryKind = dwarf::GDBIndexEntryKindString(E.Descriptor.Kind);
+        OS << format("%-8s", EntryLinkage.data()) << ' '
+           << format("%-8s", EntryKind.data()) << ' ';
+      }
+      OS << '\"' << E.Name << "\"\n";
+    }
+  }
+}
diff --git a/binaryen/third_party/llvm-project/DWARFDebugRangeList.cpp b/binaryen/third_party/llvm-project/DWARFDebugRangeList.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFDebugRangeList.cpp
@@ -0,0 +1,95 @@
+//===- DWARFDebugRangesList.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cinttypes>
+#include <cstdint>
+
+using namespace llvm;
+
+void DWARFDebugRangeList::clear() {
+  Offset = -1ULL;
+  AddressSize = 0;
+  Entries.clear();
+}
+
+Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
+                                   uint64_t *offset_ptr) {
+  clear();
+  if (!data.isValidOffset(*offset_ptr))
+    return createStringError(errc::invalid_argument,
+                       "invalid range list offset 0x%" PRIx64, *offset_ptr);
+
+  AddressSize = data.getAddressSize();
+  if (AddressSize != 4 && AddressSize != 8)
+    return createStringError(errc::invalid_argument,
+                       "invalid address size: %" PRIu8, AddressSize);
+  Offset = *offset_ptr;
+  while (true) {
+    RangeListEntry Entry;
+    Entry.SectionIndex = -1ULL;
+
+    uint64_t prev_offset = *offset_ptr;
+    Entry.StartAddress = data.getRelocatedAddress(offset_ptr);
+    Entry.EndAddress =
+        data.getRelocatedAddress(offset_ptr, &Entry.SectionIndex);
+
+    // Check that both values were extracted correctly.
+    if (*offset_ptr != prev_offset + 2 * AddressSize) {
+      clear();
+      return createStringError(errc::invalid_argument,
+                         "invalid range list entry at offset 0x%" PRIx64,
+                         prev_offset);
+    }
+    if (Entry.isEndOfListEntry())
+      break;
+    Entries.push_back(Entry);
+  }
+  return Error::success();
+}
+
+void DWARFDebugRangeList::dump(raw_ostream &OS) const {
+  for (const RangeListEntry &RLE : Entries) {
+    const char *format_str =
+        (AddressSize == 4 ? "%08" PRIx64 " %08" PRIx64 " %08" PRIx64 "\n"
+                          : "%08" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n");
+    OS << format(format_str, Offset, RLE.StartAddress, RLE.EndAddress);
+  }
+  OS << format("%08" PRIx64 " <End of list>\n", Offset);
+}
+
+DWARFAddressRangesVector DWARFDebugRangeList::getAbsoluteRanges(
+    llvm::Optional<object::SectionedAddress> BaseAddr) const {
+  DWARFAddressRangesVector Res;
+  for (const RangeListEntry &RLE : Entries) {
+    if (RLE.isBaseAddressSelectionEntry(AddressSize)) {
+      BaseAddr = {RLE.EndAddress, RLE.SectionIndex};
+      continue;
+    }
+
+    DWARFAddressRange E;
+    E.LowPC = RLE.StartAddress;
+    E.HighPC = RLE.EndAddress;
+    E.SectionIndex = RLE.SectionIndex;
+    // Base address of a range list entry is determined by the closest preceding
+    // base address selection entry in the same range list. It defaults to the
+    // base address of the compilation unit if there is no such entry.
+    if (BaseAddr) {
+      E.LowPC += BaseAddr->Address;
+      E.HighPC += BaseAddr->Address;
+      if (E.SectionIndex == -1ULL)
+        E.SectionIndex = BaseAddr->SectionIndex;
+    }
+    Res.push_back(E);
+  }
+  return Res;
+}
diff --git a/binaryen/third_party/llvm-project/DWARFDebugRnglists.cpp b/binaryen/third_party/llvm-project/DWARFDebugRnglists.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFDebugRnglists.cpp
@@ -0,0 +1,245 @@
+//===- DWARFDebugRnglists.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+Error RangeListEntry::extract(DWARFDataExtractor Data, uint64_t End,
+                              uint64_t *OffsetPtr) {
+  Offset = *OffsetPtr;
+  SectionIndex = -1ULL;
+  // The caller should guarantee that we have at least 1 byte available, so
+  // we just assert instead of revalidate.
+  assert(*OffsetPtr < End &&
+         "not enough space to extract a rangelist encoding");
+  uint8_t Encoding = Data.getU8(OffsetPtr);
+
+  switch (Encoding) {
+  case dwarf::DW_RLE_end_of_list:
+    Value0 = Value1 = 0;
+    break;
+  // TODO: Support other encodings.
+  case dwarf::DW_RLE_base_addressx: {
+    uint64_t PreviousOffset = *OffsetPtr - 1;
+    Value0 = Data.getULEB128(OffsetPtr);
+    if (End < *OffsetPtr)
+      return createStringError(
+          errc::invalid_argument,
+          "read past end of table when reading "
+          "DW_RLE_base_addressx encoding at offset 0x%" PRIx64,
+          PreviousOffset);
+    break;
+  }
+  case dwarf::DW_RLE_startx_endx:
+    return createStringError(errc::not_supported,
+                       "unsupported rnglists encoding DW_RLE_startx_endx at "
+                       "offset 0x%" PRIx64,
+                       *OffsetPtr - 1);
+  case dwarf::DW_RLE_startx_length: {
+    uint64_t PreviousOffset = *OffsetPtr - 1;
+    Value0 = Data.getULEB128(OffsetPtr);
+    Value1 = Data.getULEB128(OffsetPtr);
+    if (End < *OffsetPtr)
+      return createStringError(
+          errc::invalid_argument,
+          "read past end of table when reading "
+          "DW_RLE_startx_length encoding at offset 0x%" PRIx64,
+          PreviousOffset);
+    break;
+  }
+  case dwarf::DW_RLE_offset_pair: {
+    uint64_t PreviousOffset = *OffsetPtr - 1;
+    Value0 = Data.getULEB128(OffsetPtr);
+    Value1 = Data.getULEB128(OffsetPtr);
+    if (End < *OffsetPtr)
+      return createStringError(errc::invalid_argument,
+                         "read past end of table when reading "
+                         "DW_RLE_offset_pair encoding at offset 0x%" PRIx64,
+                         PreviousOffset);
+    break;
+  }
+  case dwarf::DW_RLE_base_address: {
+    if ((End - *OffsetPtr) < Data.getAddressSize())
+      return createStringError(errc::invalid_argument,
+                         "insufficient space remaining in table for "
+                         "DW_RLE_base_address encoding at offset 0x%" PRIx64,
+                         *OffsetPtr - 1);
+    Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
+    break;
+  }
+  case dwarf::DW_RLE_start_end: {
+    if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2))
+      return createStringError(errc::invalid_argument,
+                         "insufficient space remaining in table for "
+                         "DW_RLE_start_end encoding "
+                         "at offset 0x%" PRIx64,
+                         *OffsetPtr - 1);
+    Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
+    Value1 = Data.getRelocatedAddress(OffsetPtr);
+    break;
+  }
+  case dwarf::DW_RLE_start_length: {
+    uint64_t PreviousOffset = *OffsetPtr - 1;
+    Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
+    Value1 = Data.getULEB128(OffsetPtr);
+    if (End < *OffsetPtr)
+      return createStringError(errc::invalid_argument,
+                         "read past end of table when reading "
+                         "DW_RLE_start_length encoding at offset 0x%" PRIx64,
+                         PreviousOffset);
+    break;
+  }
+  default:
+    return createStringError(errc::not_supported,
+                       "unknown rnglists encoding 0x%" PRIx32
+                       " at offset 0x%" PRIx64,
+                       uint32_t(Encoding), *OffsetPtr - 1);
+  }
+
+  EntryKind = Encoding;
+  return Error::success();
+}
+
+DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
+    llvm::Optional<object::SectionedAddress> BaseAddr, DWARFUnit &U) const {
+  DWARFAddressRangesVector Res;
+  for (const RangeListEntry &RLE : Entries) {
+    if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
+      break;
+    if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) {
+      BaseAddr = U.getAddrOffsetSectionItem(RLE.Value0);
+      if (!BaseAddr)
+        BaseAddr = {RLE.Value0, -1ULL};
+      continue;
+    }
+    if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
+      BaseAddr = {RLE.Value0, RLE.SectionIndex};
+      continue;
+    }
+
+    DWARFAddressRange E;
+    E.SectionIndex = RLE.SectionIndex;
+    if (BaseAddr && E.SectionIndex == -1ULL)
+      E.SectionIndex = BaseAddr->SectionIndex;
+
+    switch (RLE.EntryKind) {
+    case dwarf::DW_RLE_offset_pair:
+      E.LowPC = RLE.Value0;
+      E.HighPC = RLE.Value1;
+      if (BaseAddr) {
+        E.LowPC += BaseAddr->Address;
+        E.HighPC += BaseAddr->Address;
+      }
+      break;
+    case dwarf::DW_RLE_start_end:
+      E.LowPC = RLE.Value0;
+      E.HighPC = RLE.Value1;
+      break;
+    case dwarf::DW_RLE_start_length:
+      E.LowPC = RLE.Value0;
+      E.HighPC = E.LowPC + RLE.Value1;
+      break;
+    case dwarf::DW_RLE_startx_length: {
+      auto Start = U.getAddrOffsetSectionItem(RLE.Value0);
+      if (!Start)
+        Start = {0, -1ULL};
+      E.SectionIndex = Start->SectionIndex;
+      E.LowPC = Start->Address;
+      E.HighPC = E.LowPC + RLE.Value1;
+      break;
+    }
+    default:
+      // Unsupported encodings should have been reported during extraction,
+      // so we should not run into any here.
+      llvm_unreachable("Unsupported range list encoding");
+    }
+    Res.push_back(E);
+  }
+  return Res;
+}
+
+void RangeListEntry::dump(
+    raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength,
+    uint64_t &CurrentBase, DIDumpOptions DumpOpts,
+    llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)>
+        LookupPooledAddress) const {
+  auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry,
+                          uint8_t AddrSize, DIDumpOptions DumpOpts) {
+    if (DumpOpts.Verbose) {
+      DumpOpts.DisplayRawContents = true;
+      DWARFAddressRange(Entry.Value0, Entry.Value1)
+          .dump(OS, AddrSize, DumpOpts);
+      OS << " => ";
+    }
+  };
+
+  if (DumpOpts.Verbose) {
+    // Print the section offset in verbose mode.
+    OS << format("0x%8.8" PRIx64 ":", Offset);
+    auto EncodingString = dwarf::RangeListEncodingString(EntryKind);
+    // Unsupported encodings should have been reported during parsing.
+    assert(!EncodingString.empty() && "Unknown range entry encoding");
+    OS << format(" [%s%*c", EncodingString.data(),
+                 MaxEncodingStringLength - EncodingString.size() + 1, ']');
+    if (EntryKind != dwarf::DW_RLE_end_of_list)
+      OS << ": ";
+  }
+
+  switch (EntryKind) {
+  case dwarf::DW_RLE_end_of_list:
+    OS << (DumpOpts.Verbose ? "" : "<End of list>");
+    break;
+  case dwarf::DW_RLE_base_addressx: {
+    if (auto SA = LookupPooledAddress(Value0))
+      CurrentBase = SA->Address;
+    else
+      CurrentBase = Value0;
+    if (!DumpOpts.Verbose)
+      return;
+    OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
+    break;
+  }
+  case dwarf::DW_RLE_base_address:
+    // In non-verbose mode we do not print anything for this entry.
+    CurrentBase = Value0;
+    if (!DumpOpts.Verbose)
+      return;
+    OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
+    break;
+  case dwarf::DW_RLE_start_length:
+    PrintRawEntry(OS, *this, AddrSize, DumpOpts);
+    DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts);
+    break;
+  case dwarf::DW_RLE_offset_pair:
+    PrintRawEntry(OS, *this, AddrSize, DumpOpts);
+    DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase)
+        .dump(OS, AddrSize, DumpOpts);
+    break;
+  case dwarf::DW_RLE_start_end:
+    DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts);
+    break;
+  case dwarf::DW_RLE_startx_length: {
+    PrintRawEntry(OS, *this, AddrSize, DumpOpts);
+    uint64_t Start = 0;
+    if (auto SA = LookupPooledAddress(Value0))
+      Start = SA->Address;
+    DWARFAddressRange(Start, Start + Value1).dump(OS, AddrSize, DumpOpts);
+    break;
+  }
+  default:
+    llvm_unreachable("Unsupported range list encoding");
+  }
+  OS << "\n";
+}
diff --git a/binaryen/third_party/llvm-project/DWARFDie.cpp b/binaryen/third_party/llvm-project/DWARFDie.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFDie.cpp
@@ -0,0 +1,747 @@
+//===- DWARFDie.cpp -------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <string>
+#include <utility>
+
+using namespace llvm;
+using namespace dwarf;
+using namespace object;
+
+static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) {
+  OS << " (";
+  do {
+    uint64_t Shift = countTrailingZeros(Val);
+    assert(Shift < 64 && "undefined behavior");
+    uint64_t Bit = 1ULL << Shift;
+    auto PropName = ApplePropertyString(Bit);
+    if (!PropName.empty())
+      OS << PropName;
+    else
+      OS << format("DW_APPLE_PROPERTY_0x%" PRIx64, Bit);
+    if (!(Val ^= Bit))
+      break;
+    OS << ", ";
+  } while (true);
+  OS << ")";
+}
+
+static void dumpRanges(const DWARFObject &Obj, raw_ostream &OS,
+                       const DWARFAddressRangesVector &Ranges,
+                       unsigned AddressSize, unsigned Indent,
+                       const DIDumpOptions &DumpOpts) {
+  if (!DumpOpts.ShowAddresses)
+    return;
+
+  ArrayRef<SectionName> SectionNames;
+  if (DumpOpts.Verbose)
+    SectionNames = Obj.getSectionNames();
+
+  for (const DWARFAddressRange &R : Ranges) {
+    OS << '\n';
+    OS.indent(Indent);
+    R.dump(OS, AddressSize);
+
+    DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, R.SectionIndex);
+  }
+}
+
+static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue,
+                         DWARFUnit *U, unsigned Indent,
+                         DIDumpOptions DumpOpts) {
+  DWARFContext &Ctx = U->getContext();
+  const DWARFObject &Obj = Ctx.getDWARFObj();
+  const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
+  if (FormValue.isFormClass(DWARFFormValue::FC_Block) ||
+      FormValue.isFormClass(DWARFFormValue::FC_Exprloc)) {
+    ArrayRef<uint8_t> Expr = *FormValue.getAsBlock();
+    DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()),
+                       Ctx.isLittleEndian(), 0);
+    DWARFExpression(Data, U->getVersion(), U->getAddressByteSize())
+        .print(OS, MRI, U);
+    return;
+  }
+
+  if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) {
+    uint64_t Offset = *FormValue.getAsSectionOffset();
+    uint64_t BaseAddr = 0;
+    if (Optional<object::SectionedAddress> BA = U->getBaseAddress())
+      BaseAddr = BA->Address;
+    auto LLDumpOpts = DumpOpts;
+    LLDumpOpts.Verbose = false;
+
+    if (!U->isDWOUnit() && !U->getLocSection()->Data.empty()) {
+      DWARFDebugLoc DebugLoc;
+      DWARFDataExtractor Data(Obj, *U->getLocSection(), Ctx.isLittleEndian(),
+                              Obj.getAddressSize());
+
+      FormValue.dump(OS, DumpOpts);
+      OS << ": ";
+
+      if (Expected<DWARFDebugLoc::LocationList> LL =
+              DebugLoc.parseOneLocationList(Data, &Offset)) {
+        LL->dump(OS, BaseAddr, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI,
+                 U, LLDumpOpts, Indent);
+      } else {
+        OS << '\n';
+        OS.indent(Indent);
+        OS << formatv("error extracting location list: {0}",
+                      fmt_consume(LL.takeError()));
+      }
+      return;
+    }
+
+    bool UseLocLists = !U->isDWOUnit();
+    auto Data =
+        UseLocLists
+            ? DWARFDataExtractor(Obj, Obj.getLoclistsSection(),
+                                 Ctx.isLittleEndian(), Obj.getAddressSize())
+            : DWARFDataExtractor(U->getLocSectionData(), Ctx.isLittleEndian(),
+                                 Obj.getAddressSize());
+
+    if (!Data.getData().empty()) {
+      // Old-style location list were used in DWARF v4 (.debug_loc.dwo section).
+      // Modern locations list (.debug_loclists) are used starting from v5.
+      // Ideally we should take the version from the .debug_loclists section
+      // header, but using CU's version for simplicity.
+      DWARFDebugLoclists::dumpLocationList(
+          Data, &Offset, UseLocLists ? U->getVersion() : 4, OS, BaseAddr, MRI,
+          U, LLDumpOpts, Indent);
+    }
+    return;
+  }
+
+  FormValue.dump(OS, DumpOpts);
+}
+
+/// Dump the name encoded in the type tag.
+static void dumpTypeTagName(raw_ostream &OS, dwarf::Tag T) {
+  StringRef TagStr = TagString(T);
+  if (!TagStr.startswith("DW_TAG_") || !TagStr.endswith("_type"))
+    return;
+  OS << TagStr.substr(7, TagStr.size() - 12) << " ";
+}
+
+static void dumpArrayType(raw_ostream &OS, const DWARFDie &D) {
+  Optional<uint64_t> Bound;
+  for (const DWARFDie &C : D.children())
+    if (C.getTag() == DW_TAG_subrange_type) {
+      Optional<uint64_t> LB;
+      Optional<uint64_t> Count;
+      Optional<uint64_t> UB;
+      Optional<unsigned> DefaultLB;
+      if (Optional<DWARFFormValue> L = C.find(DW_AT_lower_bound))
+        LB = L->getAsUnsignedConstant();
+      if (Optional<DWARFFormValue> CountV = C.find(DW_AT_count))
+        Count = CountV->getAsUnsignedConstant();
+      if (Optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound))
+        UB = UpperV->getAsUnsignedConstant();
+      if (Optional<DWARFFormValue> LV =
+              D.getDwarfUnit()->getUnitDIE().find(DW_AT_language))
+        if (Optional<uint64_t> LC = LV->getAsUnsignedConstant())
+          if ((DefaultLB =
+                   LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
+            if (LB && *LB == *DefaultLB)
+              LB = None;
+      if (!LB && !Count && !UB)
+        OS << "[]";
+      else if (!LB && (Count || UB) && DefaultLB)
+        OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']';
+      else {
+        OS << "[[";
+        if (LB)
+          OS << *LB;
+        else
+          OS << '?';
+        OS << ", ";
+        if (Count)
+          if (LB)
+            OS << *LB + *Count;
+          else
+            OS << "? + " << *Count;
+        else if (UB)
+          OS << *UB + 1;
+        else
+          OS << '?';
+        OS << ")]";
+      }
+    }
+}
+
+/// Recursively dump the DIE type name when applicable.
+static void dumpTypeName(raw_ostream &OS, const DWARFDie &D) {
+  if (!D.isValid())
+    return;
+
+  if (const char *Name = D.getName(DINameKind::LinkageName)) {
+    OS << Name;
+    return;
+  }
+
+  // FIXME: We should have pretty printers per language. Currently we print
+  // everything as if it was C++ and fall back to the TAG type name.
+  const dwarf::Tag T = D.getTag();
+  switch (T) {
+  case DW_TAG_array_type:
+  case DW_TAG_pointer_type:
+  case DW_TAG_ptr_to_member_type:
+  case DW_TAG_reference_type:
+  case DW_TAG_rvalue_reference_type:
+  case DW_TAG_subroutine_type:
+    break;
+  default:
+    dumpTypeTagName(OS, T);
+  }
+
+  // Follow the DW_AT_type if possible.
+  DWARFDie TypeDie = D.getAttributeValueAsReferencedDie(DW_AT_type);
+  dumpTypeName(OS, TypeDie);
+
+  switch (T) {
+  case DW_TAG_subroutine_type: {
+    if (!TypeDie)
+      OS << "void";
+    OS << '(';
+    bool First = true;
+    for (const DWARFDie &C : D.children()) {
+      if (C.getTag() == DW_TAG_formal_parameter) {
+        if (!First)
+          OS << ", ";
+        First = false;
+        dumpTypeName(OS, C.getAttributeValueAsReferencedDie(DW_AT_type));
+      }
+    }
+    OS << ')';
+    break;
+  }
+  case DW_TAG_array_type: {
+    dumpArrayType(OS, D);
+    break;
+  }
+  case DW_TAG_pointer_type:
+    OS << '*';
+    break;
+  case DW_TAG_ptr_to_member_type:
+    if (DWARFDie Cont =
+            D.getAttributeValueAsReferencedDie(DW_AT_containing_type)) {
+      dumpTypeName(OS << ' ', Cont);
+      OS << "::";
+    }
+    OS << '*';
+    break;
+  case DW_TAG_reference_type:
+    OS << '&';
+    break;
+  case DW_TAG_rvalue_reference_type:
+    OS << "&&";
+    break;
+  default:
+    break;
+  }
+}
+
+static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
+                          uint64_t *OffsetPtr, dwarf::Attribute Attr,
+                          dwarf::Form Form, unsigned Indent,
+                          DIDumpOptions DumpOpts) {
+  if (!Die.isValid())
+    return;
+  const char BaseIndent[] = "            ";
+  OS << BaseIndent;
+  OS.indent(Indent + 2);
+  WithColor(OS, HighlightColor::Attribute) << formatv("{0}", Attr);
+
+  if (DumpOpts.Verbose || DumpOpts.ShowForm)
+    OS << formatv(" [{0}]", Form);
+
+  DWARFUnit *U = Die.getDwarfUnit();
+  DWARFFormValue FormValue = DWARFFormValue::createFromUnit(Form, U, OffsetPtr);
+
+  OS << "\t(";
+
+  StringRef Name;
+  std::string File;
+  auto Color = HighlightColor::Enumerator;
+  if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) {
+    Color = HighlightColor::String;
+    if (const auto *LT = U->getContext().getLineTableForUnit(U))
+      if (LT->getFileNameByIndex(
+              FormValue.getAsUnsignedConstant().getValue(),
+              U->getCompilationDir(),
+              DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) {
+        File = '"' + File + '"';
+        Name = File;
+      }
+  } else if (Optional<uint64_t> Val = FormValue.getAsUnsignedConstant())
+    Name = AttributeValueString(Attr, *Val);
+
+  if (!Name.empty())
+    WithColor(OS, Color) << Name;
+  else if (Attr == DW_AT_decl_line || Attr == DW_AT_call_line)
+    OS << *FormValue.getAsUnsignedConstant();
+  else if (Attr == DW_AT_high_pc && !DumpOpts.ShowForm && !DumpOpts.Verbose &&
+           FormValue.getAsUnsignedConstant()) {
+    if (DumpOpts.ShowAddresses) {
+      // Print the actual address rather than the offset.
+      uint64_t LowPC, HighPC, Index;
+      if (Die.getLowAndHighPC(LowPC, HighPC, Index))
+        OS << format("0x%016" PRIx64, HighPC);
+      else
+        FormValue.dump(OS, DumpOpts);
+    }
+  } else if (DWARFAttribute::mayHaveLocationDescription(Attr))
+    dumpLocation(OS, FormValue, U, sizeof(BaseIndent) + Indent + 4, DumpOpts);
+  else
+    FormValue.dump(OS, DumpOpts);
+
+  std::string Space = DumpOpts.ShowAddresses ? " " : "";
+
+  // We have dumped the attribute raw value. For some attributes
+  // having both the raw value and the pretty-printed value is
+  // interesting. These attributes are handled below.
+  if (Attr == DW_AT_specification || Attr == DW_AT_abstract_origin) {
+    if (const char *Name =
+            Die.getAttributeValueAsReferencedDie(FormValue).getName(
+                DINameKind::LinkageName))
+      OS << Space << "\"" << Name << '\"';
+  } else if (Attr == DW_AT_type) {
+    OS << Space << "\"";
+    dumpTypeName(OS, Die.getAttributeValueAsReferencedDie(FormValue));
+    OS << '"';
+  } else if (Attr == DW_AT_APPLE_property_attribute) {
+    if (Optional<uint64_t> OptVal = FormValue.getAsUnsignedConstant())
+      dumpApplePropertyAttribute(OS, *OptVal);
+  } else if (Attr == DW_AT_ranges) {
+    const DWARFObject &Obj = Die.getDwarfUnit()->getContext().getDWARFObj();
+    // For DW_FORM_rnglistx we need to dump the offset separately, since
+    // we have only dumped the index so far.
+    if (FormValue.getForm() == DW_FORM_rnglistx)
+      if (auto RangeListOffset =
+              U->getRnglistOffset(*FormValue.getAsSectionOffset())) {
+        DWARFFormValue FV = DWARFFormValue::createFromUValue(
+            dwarf::DW_FORM_sec_offset, *RangeListOffset);
+        FV.dump(OS, DumpOpts);
+      }
+    if (auto RangesOrError = Die.getAddressRanges())
+      dumpRanges(Obj, OS, RangesOrError.get(), U->getAddressByteSize(),
+                 sizeof(BaseIndent) + Indent + 4, DumpOpts);
+    else
+      WithColor::error() << "decoding address ranges: "
+                         << toString(RangesOrError.takeError()) << '\n';
+  }
+
+  OS << ")\n";
+}
+
+bool DWARFDie::isSubprogramDIE() const { return getTag() == DW_TAG_subprogram; }
+
+bool DWARFDie::isSubroutineDIE() const {
+  auto Tag = getTag();
+  return Tag == DW_TAG_subprogram || Tag == DW_TAG_inlined_subroutine;
+}
+
+Optional<DWARFFormValue> DWARFDie::find(dwarf::Attribute Attr) const {
+  if (!isValid())
+    return None;
+  auto AbbrevDecl = getAbbreviationDeclarationPtr();
+  if (AbbrevDecl)
+    return AbbrevDecl->getAttributeValue(getOffset(), Attr, *U);
+  return None;
+}
+
+Optional<DWARFFormValue>
+DWARFDie::find(ArrayRef<dwarf::Attribute> Attrs) const {
+  if (!isValid())
+    return None;
+  auto AbbrevDecl = getAbbreviationDeclarationPtr();
+  if (AbbrevDecl) {
+    for (auto Attr : Attrs) {
+      if (auto Value = AbbrevDecl->getAttributeValue(getOffset(), Attr, *U))
+        return Value;
+    }
+  }
+  return None;
+}
+
+Optional<DWARFFormValue>
+DWARFDie::findRecursively(ArrayRef<dwarf::Attribute> Attrs) const {
+  std::vector<DWARFDie> Worklist;
+  Worklist.push_back(*this);
+
+  // Keep track if DIEs already seen to prevent infinite recursion.
+  // Empirically we rarely see a depth of more than 3 when dealing with valid
+  // DWARF. This corresponds to following the DW_AT_abstract_origin and
+  // DW_AT_specification just once.
+  SmallSet<DWARFDie, 3> Seen;
+  Seen.insert(*this);
+
+  while (!Worklist.empty()) {
+    DWARFDie Die = Worklist.back();
+    Worklist.pop_back();
+
+    if (!Die.isValid())
+      continue;
+
+    if (auto Value = Die.find(Attrs))
+      return Value;
+
+    if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin))
+      if (Seen.insert(D).second)
+        Worklist.push_back(D);
+
+    if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_specification))
+      if (Seen.insert(D).second)
+        Worklist.push_back(D);
+  }
+
+  return None;
+}
+
+DWARFDie
+DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const {
+  if (Optional<DWARFFormValue> F = find(Attr))
+    return getAttributeValueAsReferencedDie(*F);
+  return DWARFDie();
+}
+
+DWARFDie
+DWARFDie::getAttributeValueAsReferencedDie(const DWARFFormValue &V) const {
+  if (auto SpecRef = V.getAsRelativeReference()) {
+    if (SpecRef->Unit)
+      return SpecRef->Unit->getDIEForOffset(SpecRef->Unit->getOffset() + SpecRef->Offset);
+    if (auto SpecUnit = U->getUnitVector().getUnitForOffset(SpecRef->Offset))
+      return SpecUnit->getDIEForOffset(SpecRef->Offset);
+  }
+  return DWARFDie();
+}
+
+Optional<uint64_t> DWARFDie::getRangesBaseAttribute() const {
+  return toSectionOffset(find({DW_AT_rnglists_base, DW_AT_GNU_ranges_base}));
+}
+
+Optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const {
+  if (auto FormValue = find(DW_AT_high_pc)) {
+    if (auto Address = FormValue->getAsAddress()) {
+      // High PC is an address.
+      return Address;
+    }
+    if (auto Offset = FormValue->getAsUnsignedConstant()) {
+      // High PC is an offset from LowPC.
+      return LowPC + *Offset;
+    }
+  }
+  return None;
+}
+
+bool DWARFDie::getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC,
+                               uint64_t &SectionIndex) const {
+  auto F = find(DW_AT_low_pc);
+  auto LowPcAddr = toSectionedAddress(F);
+  if (!LowPcAddr)
+    return false;
+  if (auto HighPcAddr = getHighPC(LowPcAddr->Address)) {
+    LowPC = LowPcAddr->Address;
+    HighPC = *HighPcAddr;
+    SectionIndex = LowPcAddr->SectionIndex;
+    return true;
+  }
+  return false;
+}
+
+Expected<DWARFAddressRangesVector> DWARFDie::getAddressRanges() const {
+  if (isNULL())
+    return DWARFAddressRangesVector();
+  // Single range specified by low/high PC.
+  uint64_t LowPC, HighPC, Index;
+  if (getLowAndHighPC(LowPC, HighPC, Index))
+    return DWARFAddressRangesVector{{LowPC, HighPC, Index}};
+
+  Optional<DWARFFormValue> Value = find(DW_AT_ranges);
+  if (Value) {
+    if (Value->getForm() == DW_FORM_rnglistx)
+      return U->findRnglistFromIndex(*Value->getAsSectionOffset());
+    return U->findRnglistFromOffset(*Value->getAsSectionOffset());
+  }
+  return DWARFAddressRangesVector();
+}
+
+void DWARFDie::collectChildrenAddressRanges(
+    DWARFAddressRangesVector &Ranges) const {
+  if (isNULL())
+    return;
+  if (isSubprogramDIE()) {
+    if (auto DIERangesOrError = getAddressRanges())
+      Ranges.insert(Ranges.end(), DIERangesOrError.get().begin(),
+                    DIERangesOrError.get().end());
+    else
+      llvm::consumeError(DIERangesOrError.takeError());
+  }
+
+  for (auto Child : children())
+    Child.collectChildrenAddressRanges(Ranges);
+}
+
+bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const {
+  auto RangesOrError = getAddressRanges();
+  if (!RangesOrError) {
+    llvm::consumeError(RangesOrError.takeError());
+    return false;
+  }
+
+  for (const auto &R : RangesOrError.get())
+    if (R.LowPC <= Address && Address < R.HighPC)
+      return true;
+  return false;
+}
+
+const char *DWARFDie::getSubroutineName(DINameKind Kind) const {
+  if (!isSubroutineDIE())
+    return nullptr;
+  return getName(Kind);
+}
+
+const char *DWARFDie::getName(DINameKind Kind) const {
+  if (!isValid() || Kind == DINameKind::None)
+    return nullptr;
+  // Try to get mangled name only if it was asked for.
+  if (Kind == DINameKind::LinkageName) {
+    if (auto Name = dwarf::toString(
+            findRecursively({DW_AT_MIPS_linkage_name, DW_AT_linkage_name}),
+            nullptr))
+      return Name;
+  }
+  if (auto Name = dwarf::toString(findRecursively(DW_AT_name), nullptr))
+    return Name;
+  return nullptr;
+}
+
+uint64_t DWARFDie::getDeclLine() const {
+  return toUnsigned(findRecursively(DW_AT_decl_line), 0);
+}
+
+void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
+                              uint32_t &CallColumn,
+                              uint32_t &CallDiscriminator) const {
+  CallFile = toUnsigned(find(DW_AT_call_file), 0);
+  CallLine = toUnsigned(find(DW_AT_call_line), 0);
+  CallColumn = toUnsigned(find(DW_AT_call_column), 0);
+  CallDiscriminator = toUnsigned(find(DW_AT_GNU_discriminator), 0);
+}
+
+/// Helper to dump a DIE with all of its parents, but no siblings.
+static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent,
+                                DIDumpOptions DumpOpts, unsigned Depth = 0) {
+  if (!Die)
+    return Indent;
+  if (DumpOpts.ParentRecurseDepth > 0 && Depth >= DumpOpts.ParentRecurseDepth)
+    return Indent;
+  Indent = dumpParentChain(Die.getParent(), OS, Indent, DumpOpts, Depth + 1);
+  Die.dump(OS, Indent, DumpOpts);
+  return Indent + 2;
+}
+
+void DWARFDie::dump(raw_ostream &OS, unsigned Indent,
+                    DIDumpOptions DumpOpts) const {
+  if (!isValid())
+    return;
+  DWARFDataExtractor debug_info_data = U->getDebugInfoExtractor();
+  const uint64_t Offset = getOffset();
+  uint64_t offset = Offset;
+  if (DumpOpts.ShowParents) {
+    DIDumpOptions ParentDumpOpts = DumpOpts;
+    ParentDumpOpts.ShowParents = false;
+    ParentDumpOpts.ShowChildren = false;
+    Indent = dumpParentChain(getParent(), OS, Indent, ParentDumpOpts);
+  }
+
+  if (debug_info_data.isValidOffset(offset)) {
+    uint32_t abbrCode = debug_info_data.getULEB128(&offset);
+    if (DumpOpts.ShowAddresses)
+      WithColor(OS, HighlightColor::Address).get()
+          << format("\n0x%8.8" PRIx64 ": ", Offset);
+
+    if (abbrCode) {
+      auto AbbrevDecl = getAbbreviationDeclarationPtr();
+      if (AbbrevDecl) {
+        WithColor(OS, HighlightColor::Tag).get().indent(Indent)
+            << formatv("{0}", getTag());
+        if (DumpOpts.Verbose)
+          OS << format(" [%u] %c", abbrCode,
+                       AbbrevDecl->hasChildren() ? '*' : ' ');
+        OS << '\n';
+
+        // Dump all data in the DIE for the attributes.
+        for (const auto &AttrSpec : AbbrevDecl->attributes()) {
+          if (AttrSpec.Form == DW_FORM_implicit_const) {
+            // We are dumping .debug_info section ,
+            // implicit_const attribute values are not really stored here,
+            // but in .debug_abbrev section. So we just skip such attrs.
+            continue;
+          }
+          dumpAttribute(OS, *this, &offset, AttrSpec.Attr, AttrSpec.Form,
+                        Indent, DumpOpts);
+        }
+
+        DWARFDie child = getFirstChild();
+        if (DumpOpts.ShowChildren && DumpOpts.ChildRecurseDepth > 0 && child) {
+          DumpOpts.ChildRecurseDepth--;
+          DIDumpOptions ChildDumpOpts = DumpOpts;
+          ChildDumpOpts.ShowParents = false;
+          while (child) {
+            child.dump(OS, Indent + 2, ChildDumpOpts);
+            child = child.getSibling();
+          }
+        }
+      } else {
+        OS << "Abbreviation code not found in 'debug_abbrev' class for code: "
+           << abbrCode << '\n';
+      }
+    } else {
+      OS.indent(Indent) << "NULL\n";
+    }
+  }
+}
+
+LLVM_DUMP_METHOD void DWARFDie::dump() const { dump(llvm::errs(), 0); }
+
+DWARFDie DWARFDie::getParent() const {
+  if (isValid())
+    return U->getParent(Die);
+  return DWARFDie();
+}
+
+DWARFDie DWARFDie::getSibling() const {
+  if (isValid())
+    return U->getSibling(Die);
+  return DWARFDie();
+}
+
+DWARFDie DWARFDie::getPreviousSibling() const {
+  if (isValid())
+    return U->getPreviousSibling(Die);
+  return DWARFDie();
+}
+
+DWARFDie DWARFDie::getFirstChild() const {
+  if (isValid())
+    return U->getFirstChild(Die);
+  return DWARFDie();
+}
+
+DWARFDie DWARFDie::getLastChild() const {
+  if (isValid())
+    return U->getLastChild(Die);
+  return DWARFDie();
+}
+
+iterator_range<DWARFDie::attribute_iterator> DWARFDie::attributes() const {
+  return make_range(attribute_iterator(*this, false),
+                    attribute_iterator(*this, true));
+}
+
+DWARFDie::attribute_iterator::attribute_iterator(DWARFDie D, bool End)
+    : Die(D), Index(0) {
+  auto AbbrDecl = Die.getAbbreviationDeclarationPtr();
+  assert(AbbrDecl && "Must have abbreviation declaration");
+  if (End) {
+    // This is the end iterator so we set the index to the attribute count.
+    Index = AbbrDecl->getNumAttributes();
+  } else {
+    // This is the begin iterator so we extract the value for this->Index.
+    AttrValue.Offset = D.getOffset() + AbbrDecl->getCodeByteSize();
+    updateForIndex(*AbbrDecl, 0);
+  }
+}
+
+void DWARFDie::attribute_iterator::updateForIndex(
+    const DWARFAbbreviationDeclaration &AbbrDecl, uint32_t I) {
+  Index = I;
+  // AbbrDecl must be valid before calling this function.
+  auto NumAttrs = AbbrDecl.getNumAttributes();
+  if (Index < NumAttrs) {
+    AttrValue.Attr = AbbrDecl.getAttrByIndex(Index);
+    // Add the previous byte size of any previous attribute value.
+    AttrValue.Offset += AttrValue.ByteSize;
+    uint64_t ParseOffset = AttrValue.Offset;
+    auto U = Die.getDwarfUnit();
+    assert(U && "Die must have valid DWARF unit");
+    AttrValue.Value = DWARFFormValue::createFromUnit(
+        AbbrDecl.getFormByIndex(Index), U, &ParseOffset);
+    AttrValue.ByteSize = ParseOffset - AttrValue.Offset;
+  } else {
+    assert(Index == NumAttrs && "Indexes should be [0, NumAttrs) only");
+    AttrValue = {};
+  }
+}
+
+DWARFDie::attribute_iterator &DWARFDie::attribute_iterator::operator++() {
+  if (auto AbbrDecl = Die.getAbbreviationDeclarationPtr())
+    updateForIndex(*AbbrDecl, Index + 1);
+  return *this;
+}
+
+bool DWARFAttribute::mayHaveLocationDescription(dwarf::Attribute Attr) {
+  switch (Attr) {
+  // From the DWARF v5 specification.
+  case DW_AT_location:
+  case DW_AT_byte_size:
+  case DW_AT_bit_size:
+  case DW_AT_string_length:
+  case DW_AT_lower_bound:
+  case DW_AT_return_addr:
+  case DW_AT_bit_stride:
+  case DW_AT_upper_bound:
+  case DW_AT_count:
+  case DW_AT_data_member_location:
+  case DW_AT_frame_base:
+  case DW_AT_segment:
+  case DW_AT_static_link:
+  case DW_AT_use_location:
+  case DW_AT_vtable_elem_location:
+  case DW_AT_allocated:
+  case DW_AT_associated:
+  case DW_AT_byte_stride:
+  case DW_AT_rank:
+  case DW_AT_call_value:
+  case DW_AT_call_origin:
+  case DW_AT_call_target:
+  case DW_AT_call_target_clobbered:
+  case DW_AT_call_data_location:
+  case DW_AT_call_data_value:
+  // Extensions.
+  case DW_AT_GNU_call_site_value:
+  case DW_AT_GNU_call_site_target:
+    return true;
+  default:
+    return false;
+  }
+}
diff --git a/binaryen/third_party/llvm-project/DWARFEmitter.cpp b/binaryen/third_party/llvm-project/DWARFEmitter.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFEmitter.cpp
@@ -0,0 +1,490 @@
+//===- DWARFEmitter - Convert YAML to DWARF binary data -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// The DWARF component of yaml2obj. Provided as library code for tests.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ObjectYAML/DWARFEmitter.h"
+#include "DWARFVisitor.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ObjectYAML/DWARFYAML.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SwapByteOrder.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+template <typename T>
+static void writeInteger(T Integer, raw_ostream &OS, bool IsLittleEndian) {
+  if (IsLittleEndian != sys::IsLittleEndianHost)
+    sys::swapByteOrder(Integer);
+  OS.write(reinterpret_cast<char *>(&Integer), sizeof(T));
+}
+
+static void writeVariableSizedInteger(uint64_t Integer, size_t Size,
+                                      raw_ostream &OS, bool IsLittleEndian) {
+  if (8 == Size)
+    writeInteger((uint64_t)Integer, OS, IsLittleEndian);
+  else if (4 == Size)
+    writeInteger((uint32_t)Integer, OS, IsLittleEndian);
+  else if (2 == Size)
+    writeInteger((uint16_t)Integer, OS, IsLittleEndian);
+  else if (1 == Size)
+    writeInteger((uint8_t)Integer, OS, IsLittleEndian);
+  else
+    assert(false && "Invalid integer write size.");
+}
+
+static void ZeroFillBytes(raw_ostream &OS, size_t Size) {
+  std::vector<uint8_t> FillData;
+  FillData.insert(FillData.begin(), Size, 0);
+  OS.write(reinterpret_cast<char *>(FillData.data()), Size);
+}
+
+static void writeInitialLength(const DWARFYAML::InitialLength &Length,
+                               raw_ostream &OS, bool IsLittleEndian) {
+  writeInteger((uint32_t)Length.TotalLength, OS, IsLittleEndian);
+  if (Length.isDWARF64())
+    writeInteger((uint64_t)Length.TotalLength64, OS, IsLittleEndian);
+}
+
+void DWARFYAML::EmitDebugStr(raw_ostream &OS, const DWARFYAML::Data &DI) {
+  for (auto Str : DI.DebugStrings) {
+    OS.write(Str.data(), Str.size());
+    OS.write('\0');
+  }
+}
+
+void DWARFYAML::EmitDebugAbbrev(raw_ostream &OS, const DWARFYAML::Data &DI) {
+  for (auto AbbrevDecl : DI.AbbrevDecls) {
+    encodeULEB128(AbbrevDecl.Code, OS);
+    // XXX BINARYEN This is a terminator.
+    if (!AbbrevDecl.Code) {
+      continue;
+    }
+    encodeULEB128(AbbrevDecl.Tag, OS);
+    OS.write(AbbrevDecl.Children);
+    for (auto Attr : AbbrevDecl.Attributes) {
+      encodeULEB128(Attr.Attribute, OS);
+      encodeULEB128(Attr.Form, OS);
+      if (Attr.Form == dwarf::DW_FORM_implicit_const)
+        encodeSLEB128(Attr.Value, OS);
+    }
+    encodeULEB128(0, OS);
+    encodeULEB128(0, OS);
+  }
+}
+
+void DWARFYAML::EmitDebugAranges(raw_ostream &OS, const DWARFYAML::Data &DI) {
+  for (auto Range : DI.ARanges) {
+    auto HeaderStart = OS.tell();
+    writeInitialLength(Range.Length, OS, DI.IsLittleEndian);
+    writeInteger((uint16_t)Range.Version, OS, DI.IsLittleEndian);
+    writeInteger((uint32_t)Range.CuOffset, OS, DI.IsLittleEndian);
+    writeInteger((uint8_t)Range.AddrSize, OS, DI.IsLittleEndian);
+    writeInteger((uint8_t)Range.SegSize, OS, DI.IsLittleEndian);
+
+    auto HeaderSize = OS.tell() - HeaderStart;
+    auto FirstDescriptor = alignTo(HeaderSize, Range.AddrSize * 2);
+    ZeroFillBytes(OS, FirstDescriptor - HeaderSize);
+
+    for (auto Descriptor : Range.Descriptors) {
+      writeVariableSizedInteger(Descriptor.Address, Range.AddrSize, OS,
+                                DI.IsLittleEndian);
+      writeVariableSizedInteger(Descriptor.Length, Range.AddrSize, OS,
+                                DI.IsLittleEndian);
+    }
+    ZeroFillBytes(OS, Range.AddrSize * 2);
+  }
+}
+
+// XXX BINARYEN
+void DWARFYAML::EmitDebugRanges(raw_ostream &OS, const DWARFYAML::Data &DI) {
+  // As DwarfStreamer.cpp says, "The debug_range section
+  // format is totally trivial, consisting just of pairs of address
+  // sized addresses describing the ranges." and apparently it ends
+  // with a null termination of a pair of zeros
+  for (auto Range : DI.Ranges) {
+    writeInteger((uint32_t)Range.Start, OS, DI.IsLittleEndian);
+    writeInteger((uint32_t)Range.End, OS, DI.IsLittleEndian);
+  }
+}
+
+// XXX BINARYEN
+void DWARFYAML::EmitDebugLoc(raw_ostream &OS, const DWARFYAML::Data &DI) {
+  for (auto Loc : DI.Locs) {
+    writeInteger((uint32_t)Loc.Start, OS, DI.IsLittleEndian);
+    writeInteger((uint32_t)Loc.End, OS, DI.IsLittleEndian);
+    if (Loc.Start == 0 && Loc.End == 0) {
+      // End of a list.
+      continue;
+    }
+    if (Loc.Start != -1) {
+      writeInteger((uint16_t)Loc.Location.size(), OS, DI.IsLittleEndian);
+      for (auto x : Loc.Location) {
+        writeInteger((uint8_t)x, OS, DI.IsLittleEndian);
+      }
+    }
+  }
+}
+
+void DWARFYAML::EmitPubSection(raw_ostream &OS,
+                               const DWARFYAML::PubSection &Sect,
+                               bool IsLittleEndian) {
+  writeInitialLength(Sect.Length, OS, IsLittleEndian);
+  writeInteger((uint16_t)Sect.Version, OS, IsLittleEndian);
+  writeInteger((uint32_t)Sect.UnitOffset, OS, IsLittleEndian);
+  writeInteger((uint32_t)Sect.UnitSize, OS, IsLittleEndian);
+  for (auto Entry : Sect.Entries) {
+    writeInteger((uint32_t)Entry.DieOffset, OS, IsLittleEndian);
+    if (Sect.IsGNUStyle)
+      writeInteger((uint32_t)Entry.Descriptor, OS, IsLittleEndian);
+    OS.write(Entry.Name.data(), Entry.Name.size());
+    OS.write('\0');
+  }
+}
+
+namespace {
+/// An extension of the DWARFYAML::ConstVisitor which writes compile
+/// units and DIEs to a stream.
+class DumpVisitor : public DWARFYAML::ConstVisitor {
+  raw_ostream &OS;
+
+  size_t StartPos; // XXX BINARYEN
+
+protected:
+  void onStartCompileUnit(const DWARFYAML::Unit &CU) override {
+    writeInitialLength(CU.Length, OS, DebugInfo.IsLittleEndian);
+    StartPos = OS.tell(); // XXX BINARYEN
+    writeInteger((uint16_t)CU.Version, OS, DebugInfo.IsLittleEndian);
+    if(CU.Version >= 5) {
+      writeInteger((uint8_t)CU.Type, OS, DebugInfo.IsLittleEndian);
+      writeInteger((uint8_t)CU.AddrSize, OS, DebugInfo.IsLittleEndian);
+      writeInteger((uint32_t)CU.AbbrOffset, OS, DebugInfo.IsLittleEndian);
+    }else {
+      writeInteger((uint32_t)CU.AbbrOffset, OS, DebugInfo.IsLittleEndian);
+      writeInteger((uint8_t)CU.AddrSize, OS, DebugInfo.IsLittleEndian);
+    }
+  }
+
+  // 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.
+  void onEndCompileUnit(const DWARFYAML::Unit &CU) {
+    size_t EndPos = OS.tell();
+    if (EndPos - StartPos != CU.Length.getLength()) {
+      llvm_unreachable("compile unit size was incorrect");
+    }
+  }
+
+  void onStartDIE(const DWARFYAML::Unit &CU,
+                  const DWARFYAML::Entry &DIE) override {
+    encodeULEB128(DIE.AbbrCode, OS);
+  }
+
+  void onValue(const uint8_t U) override {
+    writeInteger(U, OS, DebugInfo.IsLittleEndian);
+  }
+
+  void onValue(const uint16_t U) override {
+    writeInteger(U, OS, DebugInfo.IsLittleEndian);
+  }
+
+  void onValue(const uint32_t U) override {
+    writeInteger(U, OS, DebugInfo.IsLittleEndian);
+  }
+
+  void onValue(const uint64_t U, const bool LEB = false) override {
+    if (LEB)
+      encodeULEB128(U, OS);
+    else
+      writeInteger(U, OS, DebugInfo.IsLittleEndian);
+  }
+
+  void onValue(const int64_t S, const bool LEB = false) override {
+    if (LEB)
+      encodeSLEB128(S, OS);
+    else
+      writeInteger(S, OS, DebugInfo.IsLittleEndian);
+  }
+
+  void onValue(const StringRef String) override {
+    OS.write(String.data(), String.size());
+    OS.write('\0');
+  }
+
+  void onValue(const MemoryBufferRef MBR) override {
+    OS.write(MBR.getBufferStart(), MBR.getBufferSize());
+  }
+
+public:
+  DumpVisitor(const DWARFYAML::Data &DI, raw_ostream &Out)
+      : DWARFYAML::ConstVisitor(DI), OS(Out) {}
+};
+} // namespace
+
+void DWARFYAML::EmitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) {
+  DumpVisitor Visitor(DI, OS);
+  Visitor.traverseDebugInfo();
+}
+
+static void EmitFileEntry(raw_ostream &OS, const DWARFYAML::File &File) {
+  OS.write(File.Name.data(), File.Name.size());
+  OS.write('\0');
+  encodeULEB128(File.DirIdx, OS);
+  encodeULEB128(File.ModTime, OS);
+  encodeULEB128(File.Length, OS);
+}
+
+// XXX BINARYEN: Refactor to an *Internal method that allows us to optionally
+//               compute the new lengths.
+static void EmitDebugLineInternal(raw_ostream &RealOS,
+                                  const DWARFYAML::Data &DI,
+                                  std::vector<size_t>* computedLengths) {
+  for (auto &LineTable : DI.DebugLines) {
+    // XXX BINARYEN We need to update each line table's length. Write to a
+    // temp stream first, then get the size from that.
+    std::string Buffer;
+    raw_string_ostream OS(Buffer);
+
+    // XXX BINARYEN writeInitialLength(LineTable.Length, OS, DI.IsLittleEndian);
+
+    uint64_t SizeOfPrologueLength = LineTable.Length.isDWARF64() ? 8 : 4;
+    writeInteger((uint16_t)LineTable.Version, OS, DI.IsLittleEndian);
+    writeVariableSizedInteger(LineTable.PrologueLength, SizeOfPrologueLength,
+                              OS, DI.IsLittleEndian);
+    writeInteger((uint8_t)LineTable.MinInstLength, OS, DI.IsLittleEndian);
+    if (LineTable.Version >= 4)
+      writeInteger((uint8_t)LineTable.MaxOpsPerInst, OS, DI.IsLittleEndian);
+    writeInteger((uint8_t)LineTable.DefaultIsStmt, OS, DI.IsLittleEndian);
+    writeInteger((uint8_t)LineTable.LineBase, OS, DI.IsLittleEndian);
+    writeInteger((uint8_t)LineTable.LineRange, OS, DI.IsLittleEndian);
+    writeInteger((uint8_t)LineTable.OpcodeBase, OS, DI.IsLittleEndian);
+
+    for (auto OpcodeLength : LineTable.StandardOpcodeLengths)
+      writeInteger((uint8_t)OpcodeLength, OS, DI.IsLittleEndian);
+
+    for (auto IncludeDir : LineTable.IncludeDirs) {
+      OS.write(IncludeDir.data(), IncludeDir.size());
+      OS.write('\0');
+    }
+    OS.write('\0');
+
+    for (auto File : LineTable.Files)
+      EmitFileEntry(OS, File);
+    OS.write('\0');
+
+    for (auto Op : LineTable.Opcodes) {
+      writeInteger((uint8_t)Op.Opcode, OS, DI.IsLittleEndian);
+      if (Op.Opcode == 0) {
+        encodeULEB128(Op.ExtLen, OS);
+        writeInteger((uint8_t)Op.SubOpcode, OS, DI.IsLittleEndian);
+        switch (Op.SubOpcode) {
+        case dwarf::DW_LNE_set_address:
+        case dwarf::DW_LNE_set_discriminator:
+          writeVariableSizedInteger(Op.Data, DI.CompileUnits[0].AddrSize, OS,
+                                    DI.IsLittleEndian);
+          break;
+        case dwarf::DW_LNE_define_file:
+          EmitFileEntry(OS, Op.FileEntry);
+          break;
+        case dwarf::DW_LNE_end_sequence:
+          break;
+        default:
+          for (auto OpByte : Op.UnknownOpcodeData)
+            writeInteger((uint8_t)OpByte, OS, DI.IsLittleEndian);
+        }
+      } else if (Op.Opcode < LineTable.OpcodeBase) {
+        switch (Op.Opcode) {
+        case dwarf::DW_LNS_copy:
+        case dwarf::DW_LNS_negate_stmt:
+        case dwarf::DW_LNS_set_basic_block:
+        case dwarf::DW_LNS_const_add_pc:
+        case dwarf::DW_LNS_set_prologue_end:
+        case dwarf::DW_LNS_set_epilogue_begin:
+          break;
+
+        case dwarf::DW_LNS_advance_pc:
+        case dwarf::DW_LNS_set_file:
+        case dwarf::DW_LNS_set_column:
+        case dwarf::DW_LNS_set_isa:
+          encodeULEB128(Op.Data, OS);
+          break;
+
+        case dwarf::DW_LNS_advance_line:
+          encodeSLEB128(Op.SData, OS);
+          break;
+
+        case dwarf::DW_LNS_fixed_advance_pc:
+          writeInteger((uint16_t)Op.Data, OS, DI.IsLittleEndian);
+          break;
+
+        default:
+          for (auto OpData : Op.StandardOpcodeData) {
+            encodeULEB128(OpData, OS);
+          }
+        }
+      }
+    }
+    // XXX BINARYEN Write to the actual stream, with the proper size.
+    // We assume for now that the length fits in 32 bits.
+    size_t Size = OS.str().size();
+    if (Size >= UINT32_MAX) {
+      llvm_unreachable("Table is too big");
+    }
+    if (computedLengths) {
+      computedLengths->push_back(Size);
+    }
+    writeInteger((uint32_t)Size, RealOS, DI.IsLittleEndian);
+    RealOS << OS.str();
+  }
+}
+
+void DWARFYAML::EmitDebugLine(raw_ostream &RealOS, const DWARFYAML::Data &DI) {
+  EmitDebugLineInternal(RealOS, DI, nullptr);
+}
+
+void DWARFYAML::ComputeDebugLine(Data &DI,
+                                 std::vector<size_t>& computedLengths) {
+  // TODO: Avoid writing out the data, or at least cache it so we don't need to
+  //       do it again later.
+  std::string buffer;
+  llvm::raw_string_ostream tempStream(buffer);
+  EmitDebugLineInternal(tempStream, DI, &computedLengths);
+}
+
+using EmitFuncType = void (*)(raw_ostream &, const DWARFYAML::Data &);
+
+static void
+EmitDebugSectionImpl(const DWARFYAML::Data &DI, EmitFuncType EmitFunc,
+                     StringRef Sec,
+                     StringMap<std::unique_ptr<MemoryBuffer>> &OutputBuffers) {
+  std::string Data;
+  raw_string_ostream DebugInfoStream(Data);
+  EmitFunc(DebugInfoStream, DI);
+  DebugInfoStream.flush();
+  if (!Data.empty())
+    OutputBuffers[Sec] = MemoryBuffer::getMemBufferCopy(Data);
+}
+
+namespace {
+class DIEFixupVisitor : public DWARFYAML::Visitor {
+  uint64_t Length;
+
+public:
+  DIEFixupVisitor(DWARFYAML::Data &DI) : DWARFYAML::Visitor(DI){};
+
+private:
+  virtual void onStartCompileUnit(DWARFYAML::Unit &CU) { Length = 7; }
+
+  virtual void onEndCompileUnit(DWARFYAML::Unit &CU) {
+    CU.Length.setLength(Length);
+  }
+
+  virtual void onStartDIE(DWARFYAML::Unit &CU, DWARFYAML::Entry &DIE) {
+    Length += getULEB128Size(DIE.AbbrCode);
+  }
+
+  virtual void onValue(const uint8_t U) { Length += 1; }
+  virtual void onValue(const uint16_t U) { Length += 2; }
+  virtual void onValue(const uint32_t U) { Length += 4; }
+  virtual void onValue(const uint64_t U, const bool LEB = false) {
+    if (LEB)
+      Length += getULEB128Size(U);
+    else
+      Length += 8;
+  }
+  virtual void onValue(const int64_t S, const bool LEB = false) {
+    if (LEB)
+      Length += getSLEB128Size(S);
+    else
+      Length += 8;
+  }
+  virtual void onValue(const StringRef String) { Length += String.size() + 1; }
+
+  virtual void onValue(const MemoryBufferRef MBR) {
+    Length += MBR.getBufferSize();
+  }
+};
+} // namespace
+
+Expected<StringMap<std::unique_ptr<MemoryBuffer>>>
+DWARFYAML::EmitDebugSections(StringRef YAMLString, bool ApplyFixups,
+                             bool IsLittleEndian) {
+  yaml::Input YIn(YAMLString);
+
+  DWARFYAML::Data DI;
+  DI.IsLittleEndian = IsLittleEndian;
+  YIn >> DI;
+  if (YIn.error())
+    return errorCodeToError(YIn.error());
+
+  if (ApplyFixups) {
+    DIEFixupVisitor DIFixer(DI);
+    DIFixer.traverseDebugInfo();
+  }
+
+  StringMap<std::unique_ptr<MemoryBuffer>> DebugSections;
+  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugInfo, "debug_info",
+                       DebugSections);
+  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugLine, "debug_line",
+                       DebugSections);
+  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugStr, "debug_str",
+                       DebugSections);
+  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAbbrev, "debug_abbrev",
+                       DebugSections);
+  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAranges, "debug_aranges",
+                       DebugSections);
+  return std::move(DebugSections);
+}
+
+// XXX BINARYEN <--
+namespace llvm {
+namespace DWARFYAML {
+StringMap<std::unique_ptr<MemoryBuffer>>
+EmitDebugSections(llvm::DWARFYAML::Data &DI, bool ApplyFixups) {
+  if (ApplyFixups) {
+    DIEFixupVisitor DIFixer(DI);
+    DIFixer.traverseDebugInfo();
+  }
+
+  StringMap<std::unique_ptr<MemoryBuffer>> DebugSections;
+  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugInfo, "debug_info",
+                       DebugSections);
+  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugLine, "debug_line",
+                       DebugSections);
+  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugStr, "debug_str",
+                       DebugSections);
+  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAbbrev, "debug_abbrev",
+                       DebugSections);
+  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAranges, "debug_aranges",
+                       DebugSections);
+  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugRanges, "debug_ranges",
+                       DebugSections); // XXX BINARYEN
+  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugLoc, "debug_loc",
+                       DebugSections); // XXX BINARYEN
+  return std::move(DebugSections);
+}
+} // namespace DWARFYAML
+} // namespace llvm
+// XXX BINARYEN -->
diff --git a/binaryen/third_party/llvm-project/DWARFExpression.cpp b/binaryen/third_party/llvm-project/DWARFExpression.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFExpression.cpp
@@ -0,0 +1,346 @@
+//===-- DWARFExpression.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Support/Format.h"
+#include <cassert>
+#include <cstdint>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+
+namespace llvm {
+
+typedef std::vector<DWARFExpression::Operation::Description> DescVector;
+
+static DescVector getDescriptions() {
+  DescVector Descriptions;
+  typedef DWARFExpression::Operation Op;
+  typedef Op::Description Desc;
+
+  Descriptions.resize(0xff);
+  Descriptions[DW_OP_addr] = Desc(Op::Dwarf2, Op::SizeAddr);
+  Descriptions[DW_OP_deref] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_const1u] = Desc(Op::Dwarf2, Op::Size1);
+  Descriptions[DW_OP_const1s] = Desc(Op::Dwarf2, Op::SignedSize1);
+  Descriptions[DW_OP_const2u] = Desc(Op::Dwarf2, Op::Size2);
+  Descriptions[DW_OP_const2s] = Desc(Op::Dwarf2, Op::SignedSize2);
+  Descriptions[DW_OP_const4u] = Desc(Op::Dwarf2, Op::Size4);
+  Descriptions[DW_OP_const4s] = Desc(Op::Dwarf2, Op::SignedSize4);
+  Descriptions[DW_OP_const8u] = Desc(Op::Dwarf2, Op::Size8);
+  Descriptions[DW_OP_const8s] = Desc(Op::Dwarf2, Op::SignedSize8);
+  Descriptions[DW_OP_constu] = Desc(Op::Dwarf2, Op::SizeLEB);
+  Descriptions[DW_OP_consts] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
+  Descriptions[DW_OP_dup] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_drop] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_over] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_pick] = Desc(Op::Dwarf2, Op::Size1);
+  Descriptions[DW_OP_swap] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_rot] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_xderef] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_abs] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_and] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_div] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_minus] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_mod] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_mul] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_neg] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_not] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_or] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_plus] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_plus_uconst] = Desc(Op::Dwarf2, Op::SizeLEB);
+  Descriptions[DW_OP_shl] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_shr] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_shra] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_xor] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_skip] = Desc(Op::Dwarf2, Op::SignedSize2);
+  Descriptions[DW_OP_bra] = Desc(Op::Dwarf2, Op::SignedSize2);
+  Descriptions[DW_OP_eq] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_ge] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_gt] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_le] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_lt] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_ne] = Desc(Op::Dwarf2);
+  for (uint16_t LA = DW_OP_lit0; LA <= DW_OP_lit31; ++LA)
+    Descriptions[LA] = Desc(Op::Dwarf2);
+  for (uint16_t LA = DW_OP_reg0; LA <= DW_OP_reg31; ++LA)
+    Descriptions[LA] = Desc(Op::Dwarf2);
+  for (uint16_t LA = DW_OP_breg0; LA <= DW_OP_breg31; ++LA)
+    Descriptions[LA] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
+  Descriptions[DW_OP_regx] = Desc(Op::Dwarf2, Op::SizeLEB);
+  Descriptions[DW_OP_fbreg] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
+  Descriptions[DW_OP_bregx] = Desc(Op::Dwarf2, Op::SizeLEB, Op::SignedSizeLEB);
+  Descriptions[DW_OP_piece] = Desc(Op::Dwarf2, Op::SizeLEB);
+  Descriptions[DW_OP_deref_size] = Desc(Op::Dwarf2, Op::Size1);
+  Descriptions[DW_OP_xderef_size] = Desc(Op::Dwarf2, Op::Size1);
+  Descriptions[DW_OP_nop] = Desc(Op::Dwarf2);
+  Descriptions[DW_OP_push_object_address] = Desc(Op::Dwarf3);
+  Descriptions[DW_OP_call2] = Desc(Op::Dwarf3, Op::Size2);
+  Descriptions[DW_OP_call4] = Desc(Op::Dwarf3, Op::Size4);
+  Descriptions[DW_OP_call_ref] = Desc(Op::Dwarf3, Op::SizeRefAddr);
+  Descriptions[DW_OP_form_tls_address] = Desc(Op::Dwarf3);
+  Descriptions[DW_OP_call_frame_cfa] = Desc(Op::Dwarf3);
+  Descriptions[DW_OP_bit_piece] = Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeLEB);
+  Descriptions[DW_OP_implicit_value] =
+      Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeBlock);
+  Descriptions[DW_OP_stack_value] = Desc(Op::Dwarf3);
+  Descriptions[DW_OP_WASM_location] =
+      Desc(Op::Dwarf4, Op::SizeLEB, Op::SignedSizeLEB);
+  Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3);
+  Descriptions[DW_OP_addrx] = Desc(Op::Dwarf4, Op::SizeLEB);
+  Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB);
+  Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB);
+  Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB);
+
+  Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef);
+  Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB);
+
+  return Descriptions;
+}
+
+static DWARFExpression::Operation::Description getOpDesc(unsigned OpCode) {
+  // FIXME: Make this constexpr once all compilers are smart enough to do it.
+  static DescVector Descriptions = getDescriptions();
+  // Handle possible corrupted or unsupported operation.
+  if (OpCode >= Descriptions.size())
+    return {};
+  return Descriptions[OpCode];
+}
+
+static uint8_t getRefAddrSize(uint8_t AddrSize, uint16_t Version) {
+  return (Version == 2) ? AddrSize : 4;
+}
+
+bool DWARFExpression::Operation::extract(DataExtractor Data, uint16_t Version,
+                                         uint8_t AddressSize, uint64_t Offset) {
+  Opcode = Data.getU8(&Offset);
+
+  Desc = getOpDesc(Opcode);
+  if (Desc.Version == Operation::DwarfNA) {
+    EndOffset = Offset;
+    return false;
+  }
+
+  for (unsigned Operand = 0; Operand < 2; ++Operand) {
+    unsigned Size = Desc.Op[Operand];
+    unsigned Signed = Size & Operation::SignBit;
+
+    if (Size == Operation::SizeNA)
+      break;
+
+    switch (Size & ~Operation::SignBit) {
+    case Operation::Size1:
+      Operands[Operand] = Data.getU8(&Offset);
+      if (Signed)
+        Operands[Operand] = (int8_t)Operands[Operand];
+      break;
+    case Operation::Size2:
+      Operands[Operand] = Data.getU16(&Offset);
+      if (Signed)
+        Operands[Operand] = (int16_t)Operands[Operand];
+      break;
+    case Operation::Size4:
+      Operands[Operand] = Data.getU32(&Offset);
+      if (Signed)
+        Operands[Operand] = (int32_t)Operands[Operand];
+      break;
+    case Operation::Size8:
+      Operands[Operand] = Data.getU64(&Offset);
+      break;
+    case Operation::SizeAddr:
+      if (AddressSize == 8) {
+        Operands[Operand] = Data.getU64(&Offset);
+      } else if (AddressSize == 4) {
+        Operands[Operand] = Data.getU32(&Offset);
+      } else {
+        assert(AddressSize == 2);
+        Operands[Operand] = Data.getU16(&Offset);
+      }
+      break;
+    case Operation::SizeRefAddr:
+      if (getRefAddrSize(AddressSize, Version) == 8) {
+        Operands[Operand] = Data.getU64(&Offset);
+      } else if (getRefAddrSize(AddressSize, Version) == 4) {
+        Operands[Operand] = Data.getU32(&Offset);
+      } else {
+        assert(getRefAddrSize(AddressSize, Version) == 2);
+        Operands[Operand] = Data.getU16(&Offset);
+      }
+      break;
+    case Operation::SizeLEB:
+      if (Signed)
+        Operands[Operand] = Data.getSLEB128(&Offset);
+      else
+        Operands[Operand] = Data.getULEB128(&Offset);
+      break;
+    case Operation::BaseTypeRef:
+      Operands[Operand] = Data.getULEB128(&Offset);
+      break;
+    case Operation::SizeBlock:
+      // We need a size, so this cannot be the first operand
+      if (Operand == 0)
+        return false;
+      // Store the offset of the block as the value.
+      Operands[Operand] = Offset;
+      Offset += Operands[Operand - 1];
+      break;
+    default:
+      llvm_unreachable("Unknown DWARFExpression Op size");
+    }
+
+    OperandEndOffsets[Operand] = Offset;
+  }
+
+  EndOffset = Offset;
+  return true;
+}
+
+static bool prettyPrintRegisterOp(raw_ostream &OS, uint8_t Opcode,
+                                  uint64_t Operands[2],
+                                  const MCRegisterInfo *MRI, bool isEH) {
+  if (!MRI)
+    return false;
+
+  uint64_t DwarfRegNum;
+  unsigned OpNum = 0;
+
+  if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx)
+    DwarfRegNum = Operands[OpNum++];
+  else if (Opcode >= DW_OP_breg0 && Opcode < DW_OP_bregx)
+    DwarfRegNum = Opcode - DW_OP_breg0;
+  else
+    DwarfRegNum = Opcode - DW_OP_reg0;
+
+  if (Optional<unsigned> LLVMRegNum = MRI->getLLVMRegNum(DwarfRegNum, isEH)) {
+    if (const char *RegName = MRI->getName(*LLVMRegNum)) {
+      if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
+          Opcode == DW_OP_bregx)
+        OS << format(" %s%+" PRId64, RegName, Operands[OpNum]);
+      else
+        OS << ' ' << RegName;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool DWARFExpression::Operation::print(raw_ostream &OS,
+                                       const DWARFExpression *Expr,
+                                       const MCRegisterInfo *RegInfo,
+                                       DWARFUnit *U,
+                                       bool isEH) {
+  if (Error) {
+    OS << "<decoding error>";
+    return false;
+  }
+
+  StringRef Name = OperationEncodingString(Opcode);
+  assert(!Name.empty() && "DW_OP has no name!");
+  OS << Name;
+
+  if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
+      (Opcode >= DW_OP_reg0 && Opcode <= DW_OP_reg31) ||
+      Opcode == DW_OP_bregx || Opcode == DW_OP_regx)
+    if (prettyPrintRegisterOp(OS, Opcode, Operands, RegInfo, isEH))
+      return true;
+
+  for (unsigned Operand = 0; Operand < 2; ++Operand) {
+    unsigned Size = Desc.Op[Operand];
+    unsigned Signed = Size & Operation::SignBit;
+
+    if (Size == Operation::SizeNA)
+      break;
+
+    if (Size == Operation::BaseTypeRef && U) {
+      auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]);
+      if (Die && Die.getTag() == dwarf::DW_TAG_base_type) {
+        OS << format(" (0x%08" PRIx64 ")", U->getOffset() + Operands[Operand]);
+        if (auto Name = Die.find(dwarf::DW_AT_name))
+          OS << " \"" << Name->getAsCString() << "\"";
+      } else {
+        OS << format(" <invalid base_type ref: 0x%" PRIx64 ">",
+                     Operands[Operand]);
+      }
+    } else if (Size == Operation::SizeBlock) {
+      uint64_t Offset = Operands[Operand];
+      for (unsigned i = 0; i < Operands[Operand - 1]; ++i)
+        OS << format(" 0x%02x", Expr->Data.getU8(&Offset));
+    } else {
+      if (Signed)
+        OS << format(" %+" PRId64, (int64_t)Operands[Operand]);
+      else if (Opcode != DW_OP_entry_value &&
+               Opcode != DW_OP_GNU_entry_value)
+        OS << format(" 0x%" PRIx64, Operands[Operand]);
+    }
+  }
+  return true;
+}
+
+void DWARFExpression::print(raw_ostream &OS, const MCRegisterInfo *RegInfo,
+                            DWARFUnit *U, bool IsEH) const {
+  uint32_t EntryValExprSize = 0;
+  for (auto &Op : *this) {
+    if (!Op.print(OS, this, RegInfo, U, IsEH)) {
+      uint64_t FailOffset = Op.getEndOffset();
+      while (FailOffset < Data.getData().size())
+        OS << format(" %02x", Data.getU8(&FailOffset));
+      return;
+    }
+
+    if (Op.getCode() == DW_OP_entry_value ||
+        Op.getCode() == DW_OP_GNU_entry_value) {
+      OS << "(";
+      EntryValExprSize = Op.getRawOperand(0);
+      continue;
+    }
+
+    if (EntryValExprSize) {
+      EntryValExprSize--;
+      if (EntryValExprSize == 0)
+        OS << ")";
+    }
+
+    if (Op.getEndOffset() < Data.getData().size())
+      OS << ", ";
+  }
+}
+
+bool DWARFExpression::Operation::verify(DWARFUnit *U) {
+
+  for (unsigned Operand = 0; Operand < 2; ++Operand) {
+    unsigned Size = Desc.Op[Operand];
+
+    if (Size == Operation::SizeNA)
+      break;
+
+    if (Size == Operation::BaseTypeRef) {
+      auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]);
+      if (!Die || Die.getTag() != dwarf::DW_TAG_base_type) {
+        Error = true;
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+bool DWARFExpression::verify(DWARFUnit *U) {
+  for (auto &Op : *this)
+    if (!Op.verify(U))
+      return false;
+
+  return true;
+}
+
+} // namespace llvm
diff --git a/binaryen/third_party/llvm-project/DWARFFormValue.cpp b/binaryen/third_party/llvm-project/DWARFFormValue.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFFormValue.cpp
@@ -0,0 +1,720 @@
+//===- DWARFFormValue.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cinttypes>
+#include <cstdint>
+#include <limits>
+
+using namespace llvm;
+using namespace dwarf;
+
+static const DWARFFormValue::FormClass DWARF5FormClasses[] = {
+    DWARFFormValue::FC_Unknown,  // 0x0
+    DWARFFormValue::FC_Address,  // 0x01 DW_FORM_addr
+    DWARFFormValue::FC_Unknown,  // 0x02 unused
+    DWARFFormValue::FC_Block,    // 0x03 DW_FORM_block2
+    DWARFFormValue::FC_Block,    // 0x04 DW_FORM_block4
+    DWARFFormValue::FC_Constant, // 0x05 DW_FORM_data2
+    // --- These can be FC_SectionOffset in DWARF3 and below:
+    DWARFFormValue::FC_Constant, // 0x06 DW_FORM_data4
+    DWARFFormValue::FC_Constant, // 0x07 DW_FORM_data8
+    // ---
+    DWARFFormValue::FC_String,        // 0x08 DW_FORM_string
+    DWARFFormValue::FC_Block,         // 0x09 DW_FORM_block
+    DWARFFormValue::FC_Block,         // 0x0a DW_FORM_block1
+    DWARFFormValue::FC_Constant,      // 0x0b DW_FORM_data1
+    DWARFFormValue::FC_Flag,          // 0x0c DW_FORM_flag
+    DWARFFormValue::FC_Constant,      // 0x0d DW_FORM_sdata
+    DWARFFormValue::FC_String,        // 0x0e DW_FORM_strp
+    DWARFFormValue::FC_Constant,      // 0x0f DW_FORM_udata
+    DWARFFormValue::FC_Reference,     // 0x10 DW_FORM_ref_addr
+    DWARFFormValue::FC_Reference,     // 0x11 DW_FORM_ref1
+    DWARFFormValue::FC_Reference,     // 0x12 DW_FORM_ref2
+    DWARFFormValue::FC_Reference,     // 0x13 DW_FORM_ref4
+    DWARFFormValue::FC_Reference,     // 0x14 DW_FORM_ref8
+    DWARFFormValue::FC_Reference,     // 0x15 DW_FORM_ref_udata
+    DWARFFormValue::FC_Indirect,      // 0x16 DW_FORM_indirect
+    DWARFFormValue::FC_SectionOffset, // 0x17 DW_FORM_sec_offset
+    DWARFFormValue::FC_Exprloc,       // 0x18 DW_FORM_exprloc
+    DWARFFormValue::FC_Flag,          // 0x19 DW_FORM_flag_present
+    DWARFFormValue::FC_String,        // 0x1a DW_FORM_strx
+    DWARFFormValue::FC_Address,       // 0x1b DW_FORM_addrx
+    DWARFFormValue::FC_Reference,     // 0x1c DW_FORM_ref_sup4
+    DWARFFormValue::FC_String,        // 0x1d DW_FORM_strp_sup
+    DWARFFormValue::FC_Constant,      // 0x1e DW_FORM_data16
+    DWARFFormValue::FC_String,        // 0x1f DW_FORM_line_strp
+    DWARFFormValue::FC_Reference,     // 0x20 DW_FORM_ref_sig8
+    DWARFFormValue::FC_Constant,      // 0x21 DW_FORM_implicit_const
+    DWARFFormValue::FC_SectionOffset, // 0x22 DW_FORM_loclistx
+    DWARFFormValue::FC_SectionOffset, // 0x23 DW_FORM_rnglistx
+    DWARFFormValue::FC_Reference,     // 0x24 DW_FORM_ref_sup8
+    DWARFFormValue::FC_String,        // 0x25 DW_FORM_strx1
+    DWARFFormValue::FC_String,        // 0x26 DW_FORM_strx2
+    DWARFFormValue::FC_String,        // 0x27 DW_FORM_strx3
+    DWARFFormValue::FC_String,        // 0x28 DW_FORM_strx4
+    DWARFFormValue::FC_Address,       // 0x29 DW_FORM_addrx1
+    DWARFFormValue::FC_Address,       // 0x2a DW_FORM_addrx2
+    DWARFFormValue::FC_Address,       // 0x2b DW_FORM_addrx3
+    DWARFFormValue::FC_Address,       // 0x2c DW_FORM_addrx4
+
+};
+
+DWARFFormValue DWARFFormValue::createFromSValue(dwarf::Form F, int64_t V) {
+  return DWARFFormValue(F, ValueType(V));
+}
+
+DWARFFormValue DWARFFormValue::createFromUValue(dwarf::Form F, uint64_t V) {
+  return DWARFFormValue(F, ValueType(V));
+}
+
+DWARFFormValue DWARFFormValue::createFromPValue(dwarf::Form F, const char *V) {
+  return DWARFFormValue(F, ValueType(V));
+}
+
+DWARFFormValue DWARFFormValue::createFromBlockValue(dwarf::Form F,
+                                                    ArrayRef<uint8_t> D) {
+  ValueType V;
+  V.uval = D.size();
+  V.data = D.data();
+  return DWARFFormValue(F, V);
+}
+
+DWARFFormValue DWARFFormValue::createFromUnit(dwarf::Form F, const DWARFUnit *U,
+                                              uint64_t *OffsetPtr) {
+  DWARFFormValue FormValue(F);
+  FormValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr,
+                         U->getFormParams(), U);
+  return FormValue;
+}
+
+bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData,
+                               uint64_t *OffsetPtr,
+                               const dwarf::FormParams Params) {
+  bool Indirect = false;
+  do {
+    switch (Form) {
+    // Blocks of inlined data that have a length field and the data bytes
+    // inlined in the .debug_info.
+    case DW_FORM_exprloc:
+    case DW_FORM_block: {
+      uint64_t size = DebugInfoData.getULEB128(OffsetPtr);
+      *OffsetPtr += size;
+      return true;
+    }
+    case DW_FORM_block1: {
+      uint8_t size = DebugInfoData.getU8(OffsetPtr);
+      *OffsetPtr += size;
+      return true;
+    }
+    case DW_FORM_block2: {
+      uint16_t size = DebugInfoData.getU16(OffsetPtr);
+      *OffsetPtr += size;
+      return true;
+    }
+    case DW_FORM_block4: {
+      uint32_t size = DebugInfoData.getU32(OffsetPtr);
+      *OffsetPtr += size;
+      return true;
+    }
+
+    // Inlined NULL terminated C-strings.
+    case DW_FORM_string:
+      DebugInfoData.getCStr(OffsetPtr);
+      return true;
+
+    case DW_FORM_addr:
+    case DW_FORM_ref_addr:
+    case DW_FORM_flag_present:
+    case DW_FORM_data1:
+    case DW_FORM_data2:
+    case DW_FORM_data4:
+    case DW_FORM_data8:
+    case DW_FORM_data16:
+    case DW_FORM_flag:
+    case DW_FORM_ref1:
+    case DW_FORM_ref2:
+    case DW_FORM_ref4:
+    case DW_FORM_ref8:
+    case DW_FORM_ref_sig8:
+    case DW_FORM_ref_sup4:
+    case DW_FORM_ref_sup8:
+    case DW_FORM_strx1:
+    case DW_FORM_strx2:
+    case DW_FORM_strx4:
+    case DW_FORM_addrx1:
+    case DW_FORM_addrx2:
+    case DW_FORM_addrx4:
+    case DW_FORM_sec_offset:
+    case DW_FORM_strp:
+    case DW_FORM_strp_sup:
+    case DW_FORM_line_strp:
+    case DW_FORM_GNU_ref_alt:
+    case DW_FORM_GNU_strp_alt:
+      if (Optional<uint8_t> FixedSize =
+              dwarf::getFixedFormByteSize(Form, Params)) {
+        *OffsetPtr += *FixedSize;
+        return true;
+      }
+      return false;
+
+    // signed or unsigned LEB 128 values.
+    case DW_FORM_sdata:
+      DebugInfoData.getSLEB128(OffsetPtr);
+      return true;
+
+    case DW_FORM_udata:
+    case DW_FORM_ref_udata:
+    case DW_FORM_strx:
+    case DW_FORM_addrx:
+    case DW_FORM_loclistx:
+    case DW_FORM_rnglistx:
+    case DW_FORM_GNU_addr_index:
+    case DW_FORM_GNU_str_index:
+      DebugInfoData.getULEB128(OffsetPtr);
+      return true;
+
+    case DW_FORM_indirect:
+      Indirect = true;
+      Form = static_cast<dwarf::Form>(DebugInfoData.getULEB128(OffsetPtr));
+      break;
+
+    default:
+      return false;
+    }
+  } while (Indirect);
+  return true;
+}
+
+bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const {
+  // First, check DWARF5 form classes.
+  if (Form < makeArrayRef(DWARF5FormClasses).size() &&
+      DWARF5FormClasses[Form] == FC)
+    return true;
+  // Check more forms from extensions and proposals.
+  switch (Form) {
+  case DW_FORM_GNU_ref_alt:
+    return (FC == FC_Reference);
+  case DW_FORM_GNU_addr_index:
+    return (FC == FC_Address);
+  case DW_FORM_GNU_str_index:
+  case DW_FORM_GNU_strp_alt:
+    return (FC == FC_String);
+  default:
+    break;
+  }
+
+  if (FC == FC_SectionOffset) {
+    if (Form == DW_FORM_strp || Form == DW_FORM_line_strp)
+      return true;
+    // In DWARF3 DW_FORM_data4 and DW_FORM_data8 served also as a section
+    // offset. If we don't have a DWARFUnit, default to the old behavior.
+    if (Form == DW_FORM_data4 || Form == DW_FORM_data8)
+      return !U || U->getVersion() <= 3;
+  }
+
+  return false;
+}
+
+bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
+                                  uint64_t *OffsetPtr, dwarf::FormParams FP,
+                                  const DWARFContext *Ctx,
+                                  const DWARFUnit *CU) {
+  if (!Ctx && CU)
+    Ctx = &CU->getContext();
+  C = Ctx;
+  U = CU;
+  bool Indirect = false;
+  bool IsBlock = false;
+  Value.data = nullptr;
+  // Read the value for the form into value and follow and DW_FORM_indirect
+  // instances we run into
+  do {
+    Indirect = false;
+    switch (Form) {
+    case DW_FORM_addr:
+    case DW_FORM_ref_addr: {
+      uint16_t Size =
+          (Form == DW_FORM_addr) ? FP.AddrSize : FP.getRefAddrByteSize();
+      Value.uval = Data.getRelocatedValue(Size, OffsetPtr, &Value.SectionIndex);
+      break;
+    }
+    case DW_FORM_exprloc:
+    case DW_FORM_block:
+      Value.uval = Data.getULEB128(OffsetPtr);
+      IsBlock = true;
+      break;
+    case DW_FORM_block1:
+      Value.uval = Data.getU8(OffsetPtr);
+      IsBlock = true;
+      break;
+    case DW_FORM_block2:
+      Value.uval = Data.getU16(OffsetPtr);
+      IsBlock = true;
+      break;
+    case DW_FORM_block4:
+      Value.uval = Data.getU32(OffsetPtr);
+      IsBlock = true;
+      break;
+    case DW_FORM_data1:
+    case DW_FORM_ref1:
+    case DW_FORM_flag:
+    case DW_FORM_strx1:
+    case DW_FORM_addrx1:
+      Value.uval = Data.getU8(OffsetPtr);
+      break;
+    case DW_FORM_data2:
+    case DW_FORM_ref2:
+    case DW_FORM_strx2:
+    case DW_FORM_addrx2:
+      Value.uval = Data.getU16(OffsetPtr);
+      break;
+    case DW_FORM_strx3:
+      Value.uval = Data.getU24(OffsetPtr);
+      break;
+    case DW_FORM_data4:
+    case DW_FORM_ref4:
+    case DW_FORM_ref_sup4:
+    case DW_FORM_strx4:
+    case DW_FORM_addrx4:
+      Value.uval = Data.getRelocatedValue(4, OffsetPtr);
+      break;
+    case DW_FORM_data8:
+    case DW_FORM_ref8:
+    case DW_FORM_ref_sup8:
+      Value.uval = Data.getRelocatedValue(8, OffsetPtr);
+      break;
+    case DW_FORM_data16:
+      // Treat this like a 16-byte block.
+      Value.uval = 16;
+      IsBlock = true;
+      break;
+    case DW_FORM_sdata:
+      Value.sval = Data.getSLEB128(OffsetPtr);
+      break;
+    case DW_FORM_udata:
+    case DW_FORM_ref_udata:
+    case DW_FORM_rnglistx:
+      Value.uval = Data.getULEB128(OffsetPtr);
+      break;
+    case DW_FORM_string:
+      Value.cstr = Data.getCStr(OffsetPtr);
+      break;
+    case DW_FORM_indirect:
+      Form = static_cast<dwarf::Form>(Data.getULEB128(OffsetPtr));
+      Indirect = true;
+      break;
+    case DW_FORM_strp:
+    case DW_FORM_sec_offset:
+    case DW_FORM_GNU_ref_alt:
+    case DW_FORM_GNU_strp_alt:
+    case DW_FORM_line_strp:
+    case DW_FORM_strp_sup: {
+      Value.uval =
+          Data.getRelocatedValue(FP.getDwarfOffsetByteSize(), OffsetPtr);
+      break;
+    }
+    case DW_FORM_flag_present:
+      Value.uval = 1;
+      break;
+    case DW_FORM_ref_sig8:
+      Value.uval = Data.getU64(OffsetPtr);
+      break;
+    case DW_FORM_GNU_addr_index:
+    case DW_FORM_GNU_str_index:
+    case DW_FORM_addrx:
+    case DW_FORM_strx:
+      Value.uval = Data.getULEB128(OffsetPtr);
+      break;
+    default:
+      // DWARFFormValue::skipValue() will have caught this and caused all
+      // DWARF DIEs to fail to be parsed, so this code is not be reachable.
+      llvm_unreachable("unsupported form");
+    }
+  } while (Indirect);
+
+  if (IsBlock) {
+    StringRef Str = Data.getData().substr(*OffsetPtr, Value.uval);
+    Value.data = nullptr;
+    if (!Str.empty()) {
+      Value.data = Str.bytes_begin();
+      *OffsetPtr += Value.uval;
+    }
+  }
+
+  return true;
+}
+
+void DWARFFormValue::dumpSectionedAddress(raw_ostream &OS,
+                                          DIDumpOptions DumpOpts,
+                                          object::SectionedAddress SA) const {
+  OS << format("0x%016" PRIx64, SA.Address);
+  dumpAddressSection(U->getContext().getDWARFObj(), OS, DumpOpts,
+                     SA.SectionIndex);
+}
+
+void DWARFFormValue::dumpAddressSection(const DWARFObject &Obj, raw_ostream &OS,
+                                        DIDumpOptions DumpOpts,
+                                        uint64_t SectionIndex) {
+  if (!DumpOpts.Verbose || SectionIndex == -1ULL)
+    return;
+  ArrayRef<SectionName> SectionNames = Obj.getSectionNames();
+  const auto &SecRef = SectionNames[SectionIndex];
+
+  OS << " \"" << SecRef.Name << '\"';
+
+  // Print section index if name is not unique.
+  if (!SecRef.IsNameUnique)
+    OS << format(" [%" PRIu64 "]", SectionIndex);
+}
+
+void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
+  uint64_t UValue = Value.uval;
+  bool CURelativeOffset = false;
+  raw_ostream &AddrOS = DumpOpts.ShowAddresses
+                            ? WithColor(OS, HighlightColor::Address).get()
+                            : nulls();
+  switch (Form) {
+  case DW_FORM_addr:
+    dumpSectionedAddress(AddrOS, DumpOpts, {Value.uval, Value.SectionIndex});
+    break;
+  case DW_FORM_addrx:
+  case DW_FORM_addrx1:
+  case DW_FORM_addrx2:
+  case DW_FORM_addrx3:
+  case DW_FORM_addrx4:
+  case DW_FORM_GNU_addr_index: {
+    if (U == nullptr) {
+      OS << "<invalid dwarf unit>";
+      break;
+    }
+    Optional<object::SectionedAddress> A = U->getAddrOffsetSectionItem(UValue);
+    if (!A || DumpOpts.Verbose)
+      AddrOS << format("indexed (%8.8x) address = ", (uint32_t)UValue);
+    if (A)
+      dumpSectionedAddress(AddrOS, DumpOpts, *A);
+    else
+      OS << "<no .debug_addr section>";
+    break;
+  }
+  case DW_FORM_flag_present:
+    OS << "true";
+    break;
+  case DW_FORM_flag:
+  case DW_FORM_data1:
+    OS << format("0x%02x", (uint8_t)UValue);
+    break;
+  case DW_FORM_data2:
+    OS << format("0x%04x", (uint16_t)UValue);
+    break;
+  case DW_FORM_data4:
+    OS << format("0x%08x", (uint32_t)UValue);
+    break;
+  case DW_FORM_ref_sig8:
+    AddrOS << format("0x%016" PRIx64, UValue);
+    break;
+  case DW_FORM_data8:
+    OS << format("0x%016" PRIx64, UValue);
+    break;
+  case DW_FORM_data16:
+    OS << format_bytes(ArrayRef<uint8_t>(Value.data, 16), None, 16, 16);
+    break;
+  case DW_FORM_string:
+    OS << '"';
+    OS.write_escaped(Value.cstr);
+    OS << '"';
+    break;
+  case DW_FORM_exprloc:
+  case DW_FORM_block:
+  case DW_FORM_block1:
+  case DW_FORM_block2:
+  case DW_FORM_block4:
+    if (UValue > 0) {
+      switch (Form) {
+      case DW_FORM_exprloc:
+      case DW_FORM_block:
+        AddrOS << format("<0x%" PRIx64 "> ", UValue);
+        break;
+      case DW_FORM_block1:
+        AddrOS << format("<0x%2.2x> ", (uint8_t)UValue);
+        break;
+      case DW_FORM_block2:
+        AddrOS << format("<0x%4.4x> ", (uint16_t)UValue);
+        break;
+      case DW_FORM_block4:
+        AddrOS << format("<0x%8.8x> ", (uint32_t)UValue);
+        break;
+      default:
+        break;
+      }
+
+      const uint8_t *DataPtr = Value.data;
+      if (DataPtr) {
+        // UValue contains size of block
+        const uint8_t *EndDataPtr = DataPtr + UValue;
+        while (DataPtr < EndDataPtr) {
+          AddrOS << format("%2.2x ", *DataPtr);
+          ++DataPtr;
+        }
+      } else
+        OS << "NULL";
+    }
+    break;
+
+  case DW_FORM_sdata:
+    OS << Value.sval;
+    break;
+  case DW_FORM_udata:
+    OS << Value.uval;
+    break;
+  case DW_FORM_strp:
+    if (DumpOpts.Verbose)
+      OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)UValue);
+    dumpString(OS);
+    break;
+  case DW_FORM_line_strp:
+    if (DumpOpts.Verbose)
+      OS << format(" .debug_line_str[0x%8.8x] = ", (uint32_t)UValue);
+    dumpString(OS);
+    break;
+  case DW_FORM_strx:
+  case DW_FORM_strx1:
+  case DW_FORM_strx2:
+  case DW_FORM_strx3:
+  case DW_FORM_strx4:
+  case DW_FORM_GNU_str_index:
+    if (DumpOpts.Verbose)
+      OS << format("indexed (%8.8x) string = ", (uint32_t)UValue);
+    dumpString(OS);
+    break;
+  case DW_FORM_GNU_strp_alt:
+    if (DumpOpts.Verbose)
+      OS << format("alt indirect string, offset: 0x%" PRIx64 "", UValue);
+    dumpString(OS);
+    break;
+  case DW_FORM_ref_addr:
+    AddrOS << format("0x%016" PRIx64, UValue);
+    break;
+  case DW_FORM_ref1:
+    CURelativeOffset = true;
+    if (DumpOpts.Verbose)
+      AddrOS << format("cu + 0x%2.2x", (uint8_t)UValue);
+    break;
+  case DW_FORM_ref2:
+    CURelativeOffset = true;
+    if (DumpOpts.Verbose)
+      AddrOS << format("cu + 0x%4.4x", (uint16_t)UValue);
+    break;
+  case DW_FORM_ref4:
+    CURelativeOffset = true;
+    if (DumpOpts.Verbose)
+      AddrOS << format("cu + 0x%4.4x", (uint32_t)UValue);
+    break;
+  case DW_FORM_ref8:
+    CURelativeOffset = true;
+    if (DumpOpts.Verbose)
+      AddrOS << format("cu + 0x%8.8" PRIx64, UValue);
+    break;
+  case DW_FORM_ref_udata:
+    CURelativeOffset = true;
+    if (DumpOpts.Verbose)
+      AddrOS << format("cu + 0x%" PRIx64, UValue);
+    break;
+  case DW_FORM_GNU_ref_alt:
+    AddrOS << format("<alt 0x%" PRIx64 ">", UValue);
+    break;
+
+  // All DW_FORM_indirect attributes should be resolved prior to calling
+  // this function
+  case DW_FORM_indirect:
+    OS << "DW_FORM_indirect";
+    break;
+
+  case DW_FORM_rnglistx:
+    OS << format("indexed (0x%x) rangelist = ", (uint32_t)UValue);
+    break;
+
+  // Should be formatted to 64-bit for DWARF64.
+  case DW_FORM_sec_offset:
+    AddrOS << format("0x%08x", (uint32_t)UValue);
+    break;
+
+  default:
+    OS << format("DW_FORM(0x%4.4x)", Form);
+    break;
+  }
+
+  if (CURelativeOffset) {
+    if (DumpOpts.Verbose)
+      OS << " => {";
+    if (DumpOpts.ShowAddresses)
+      WithColor(OS, HighlightColor::Address).get()
+          << format("0x%8.8" PRIx64, UValue + (U ? U->getOffset() : 0));
+    if (DumpOpts.Verbose)
+      OS << "}";
+  }
+}
+
+void DWARFFormValue::dumpString(raw_ostream &OS) const {
+  Optional<const char *> DbgStr = getAsCString();
+  if (DbgStr.hasValue()) {
+    auto COS = WithColor(OS, HighlightColor::String);
+    COS.get() << '"';
+    COS.get().write_escaped(DbgStr.getValue());
+    COS.get() << '"';
+  }
+}
+
+Optional<const char *> DWARFFormValue::getAsCString() const {
+  if (!isFormClass(FC_String))
+    return None;
+  if (Form == DW_FORM_string)
+    return Value.cstr;
+  // FIXME: Add support for DW_FORM_GNU_strp_alt
+  if (Form == DW_FORM_GNU_strp_alt || C == nullptr)
+    return None;
+  uint64_t Offset = Value.uval;
+  if (Form == DW_FORM_line_strp) {
+    // .debug_line_str is tracked in the Context.
+    if (const char *Str = C->getLineStringExtractor().getCStr(&Offset))
+      return Str;
+    return None;
+  }
+  if (Form == DW_FORM_GNU_str_index || Form == DW_FORM_strx ||
+      Form == DW_FORM_strx1 || Form == DW_FORM_strx2 || Form == DW_FORM_strx3 ||
+      Form == DW_FORM_strx4) {
+    if (!U)
+      return None;
+    Optional<uint64_t> StrOffset = U->getStringOffsetSectionItem(Offset);
+    if (!StrOffset)
+      return None;
+    Offset = *StrOffset;
+  }
+  // Prefer the Unit's string extractor, because for .dwo it will point to
+  // .debug_str.dwo, while the Context's extractor always uses .debug_str.
+  if (U) {
+    if (const char *Str = U->getStringExtractor().getCStr(&Offset))
+      return Str;
+    return None;
+  }
+  if (const char *Str = C->getStringExtractor().getCStr(&Offset))
+    return Str;
+  return None;
+}
+
+Optional<uint64_t> DWARFFormValue::getAsAddress() const {
+  if (auto SA = getAsSectionedAddress())
+    return SA->Address;
+  return None;
+}
+
+Optional<object::SectionedAddress>
+DWARFFormValue::getAsSectionedAddress() const {
+  if (!isFormClass(FC_Address))
+    return None;
+  if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx) {
+    uint32_t Index = Value.uval;
+    if (!U)
+      return None;
+    Optional<object::SectionedAddress> SA = U->getAddrOffsetSectionItem(Index);
+    if (!SA)
+      return None;
+    return SA;
+  }
+  return {{Value.uval, Value.SectionIndex}};
+}
+
+Optional<uint64_t> DWARFFormValue::getAsReference() const {
+  if (auto R = getAsRelativeReference())
+    return R->Unit ? R->Unit->getOffset() + R->Offset : R->Offset;
+  return None;
+}
+  
+Optional<DWARFFormValue::UnitOffset> DWARFFormValue::getAsRelativeReference() const {
+  if (!isFormClass(FC_Reference))
+    return None;
+  switch (Form) {
+  case DW_FORM_ref1:
+  case DW_FORM_ref2:
+  case DW_FORM_ref4:
+  case DW_FORM_ref8:
+  case DW_FORM_ref_udata:
+    if (!U)
+      return None;
+    return UnitOffset{const_cast<DWARFUnit*>(U), Value.uval};
+  case DW_FORM_ref_addr:
+  case DW_FORM_ref_sig8:
+  case DW_FORM_GNU_ref_alt:
+    return UnitOffset{nullptr, Value.uval};
+  default:
+    return None;
+  }
+}
+
+Optional<uint64_t> DWARFFormValue::getAsSectionOffset() const {
+  if (!isFormClass(FC_SectionOffset))
+    return None;
+  return Value.uval;
+}
+
+Optional<uint64_t> DWARFFormValue::getAsUnsignedConstant() const {
+  if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) ||
+      Form == DW_FORM_sdata)
+    return None;
+  return Value.uval;
+}
+
+Optional<int64_t> DWARFFormValue::getAsSignedConstant() const {
+  if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) ||
+      (Form == DW_FORM_udata &&
+       uint64_t(std::numeric_limits<int64_t>::max()) < Value.uval))
+    return None;
+  switch (Form) {
+  case DW_FORM_data4:
+    return int32_t(Value.uval);
+  case DW_FORM_data2:
+    return int16_t(Value.uval);
+  case DW_FORM_data1:
+    return int8_t(Value.uval);
+  case DW_FORM_sdata:
+  case DW_FORM_data8:
+  default:
+    return Value.sval;
+  }
+}
+
+Optional<ArrayRef<uint8_t>> DWARFFormValue::getAsBlock() const {
+  if (!isFormClass(FC_Block) && !isFormClass(FC_Exprloc) &&
+      Form != DW_FORM_data16)
+    return None;
+  return makeArrayRef(Value.data, Value.uval);
+}
+
+Optional<uint64_t> DWARFFormValue::getAsCStringOffset() const {
+  if (!isFormClass(FC_String) && Form == DW_FORM_string)
+    return None;
+  return Value.uval;
+}
+
+Optional<uint64_t> DWARFFormValue::getAsReferenceUVal() const {
+  if (!isFormClass(FC_Reference))
+    return None;
+  return Value.uval;
+}
diff --git a/binaryen/third_party/llvm-project/DWARFGdbIndex.cpp b/binaryen/third_party/llvm-project/DWARFGdbIndex.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFGdbIndex.cpp
@@ -0,0 +1,199 @@
+//===- DWARFGdbIndex.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <utility>
+
+using namespace llvm;
+
+// .gdb_index section format reference:
+// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html
+
+void DWARFGdbIndex::dumpCUList(raw_ostream &OS) const {
+  OS << format("\n  CU list offset = 0x%x, has %" PRId64 " entries:",
+               CuListOffset, (uint64_t)CuList.size())
+     << '\n';
+  uint32_t I = 0;
+  for (const CompUnitEntry &CU : CuList)
+    OS << format("    %d: Offset = 0x%llx, Length = 0x%llx\n", I++, CU.Offset,
+                 CU.Length);
+}
+
+void DWARFGdbIndex::dumpTUList(raw_ostream &OS) const {
+  OS << formatv("\n  Types CU list offset = {0:x}, has {1} entries:\n",
+                TuListOffset, TuList.size());
+  uint32_t I = 0;
+  for (const TypeUnitEntry &TU : TuList)
+    OS << formatv("    {0}: offset = {1:x8}, type_offset = {2:x8}, "
+                  "type_signature = {3:x16}\n",
+                  I++, TU.Offset, TU.TypeOffset, TU.TypeSignature);
+}
+
+void DWARFGdbIndex::dumpAddressArea(raw_ostream &OS) const {
+  OS << format("\n  Address area offset = 0x%x, has %" PRId64 " entries:",
+               AddressAreaOffset, (uint64_t)AddressArea.size())
+     << '\n';
+  for (const AddressEntry &Addr : AddressArea)
+    OS << format(
+        "    Low/High address = [0x%llx, 0x%llx) (Size: 0x%llx), CU id = %d\n",
+        Addr.LowAddress, Addr.HighAddress, Addr.HighAddress - Addr.LowAddress,
+        Addr.CuIndex);
+}
+
+void DWARFGdbIndex::dumpSymbolTable(raw_ostream &OS) const {
+  OS << format("\n  Symbol table offset = 0x%x, size = %" PRId64
+               ", filled slots:",
+               SymbolTableOffset, (uint64_t)SymbolTable.size())
+     << '\n';
+  uint32_t I = -1;
+  for (const SymTableEntry &E : SymbolTable) {
+    ++I;
+    if (!E.NameOffset && !E.VecOffset)
+      continue;
+
+    OS << format("    %d: Name offset = 0x%x, CU vector offset = 0x%x\n", I,
+                 E.NameOffset, E.VecOffset);
+
+    StringRef Name = ConstantPoolStrings.substr(
+        ConstantPoolOffset - StringPoolOffset + E.NameOffset);
+
+    auto CuVector = std::find_if(
+        ConstantPoolVectors.begin(), ConstantPoolVectors.end(),
+        [&](const std::pair<uint32_t, SmallVector<uint32_t, 0>> &V) {
+          return V.first == E.VecOffset;
+        });
+    assert(CuVector != ConstantPoolVectors.end() && "Invalid symbol table");
+    uint32_t CuVectorId = CuVector - ConstantPoolVectors.begin();
+    OS << format("      String name: %s, CU vector index: %d\n", Name.data(),
+                 CuVectorId);
+  }
+}
+
+void DWARFGdbIndex::dumpConstantPool(raw_ostream &OS) const {
+  OS << format("\n  Constant pool offset = 0x%x, has %" PRId64 " CU vectors:",
+               ConstantPoolOffset, (uint64_t)ConstantPoolVectors.size());
+  uint32_t I = 0;
+  for (const auto &V : ConstantPoolVectors) {
+    OS << format("\n    %d(0x%x): ", I++, V.first);
+    for (uint32_t Val : V.second)
+      OS << format("0x%x ", Val);
+  }
+  OS << '\n';
+}
+
+void DWARFGdbIndex::dump(raw_ostream &OS) {
+  if (HasError) {
+    OS << "\n<error parsing>\n";
+    return;
+  }
+
+  if (HasContent) {
+    OS << "  Version = " << Version << '\n';
+    dumpCUList(OS);
+    dumpTUList(OS);
+    dumpAddressArea(OS);
+    dumpSymbolTable(OS);
+    dumpConstantPool(OS);
+  }
+}
+
+bool DWARFGdbIndex::parseImpl(DataExtractor Data) {
+  uint64_t Offset = 0;
+
+  // Only version 7 is supported at this moment.
+  Version = Data.getU32(&Offset);
+  if (Version != 7)
+    return false;
+
+  CuListOffset = Data.getU32(&Offset);
+  TuListOffset = Data.getU32(&Offset);
+  AddressAreaOffset = Data.getU32(&Offset);
+  SymbolTableOffset = Data.getU32(&Offset);
+  ConstantPoolOffset = Data.getU32(&Offset);
+
+  if (Offset != CuListOffset)
+    return false;
+
+  uint32_t CuListSize = (TuListOffset - CuListOffset) / 16;
+  CuList.reserve(CuListSize);
+  for (uint32_t i = 0; i < CuListSize; ++i) {
+    uint64_t CuOffset = Data.getU64(&Offset);
+    uint64_t CuLength = Data.getU64(&Offset);
+    CuList.push_back({CuOffset, CuLength});
+  }
+
+  // CU Types are no longer needed as DWARF skeleton type units never made it
+  // into the standard.
+  uint32_t TuListSize = (AddressAreaOffset - TuListOffset) / 24;
+  TuList.resize(TuListSize);
+  for (uint32_t I = 0; I < TuListSize; ++I) {
+    uint64_t CuOffset = Data.getU64(&Offset);
+    uint64_t TypeOffset = Data.getU64(&Offset);
+    uint64_t Signature = Data.getU64(&Offset);
+    TuList[I] = {CuOffset, TypeOffset, Signature};
+  }
+
+  uint32_t AddressAreaSize = (SymbolTableOffset - AddressAreaOffset) / 20;
+  AddressArea.reserve(AddressAreaSize);
+  for (uint32_t i = 0; i < AddressAreaSize; ++i) {
+    uint64_t LowAddress = Data.getU64(&Offset);
+    uint64_t HighAddress = Data.getU64(&Offset);
+    uint32_t CuIndex = Data.getU32(&Offset);
+    AddressArea.push_back({LowAddress, HighAddress, CuIndex});
+  }
+
+  // The symbol table. This is an open addressed hash table. The size of the
+  // hash table is always a power of 2.
+  // Each slot in the hash table consists of a pair of offset_type values. The
+  // first value is the offset of the symbol's name in the constant pool. The
+  // second value is the offset of the CU vector in the constant pool.
+  // If both values are 0, then this slot in the hash table is empty. This is ok
+  // because while 0 is a valid constant pool index, it cannot be a valid index
+  // for both a string and a CU vector.
+  uint32_t SymTableSize = (ConstantPoolOffset - SymbolTableOffset) / 8;
+  SymbolTable.reserve(SymTableSize);
+  uint32_t CuVectorsTotal = 0;
+  for (uint32_t i = 0; i < SymTableSize; ++i) {
+    uint32_t NameOffset = Data.getU32(&Offset);
+    uint32_t CuVecOffset = Data.getU32(&Offset);
+    SymbolTable.push_back({NameOffset, CuVecOffset});
+    if (NameOffset || CuVecOffset)
+      ++CuVectorsTotal;
+  }
+
+  // The constant pool. CU vectors are stored first, followed by strings.
+  // The first value is the number of CU indices in the vector. Each subsequent
+  // value is the index and symbol attributes of a CU in the CU list.
+  for (uint32_t i = 0; i < CuVectorsTotal; ++i) {
+    ConstantPoolVectors.emplace_back(0, SmallVector<uint32_t, 0>());
+    auto &Vec = ConstantPoolVectors.back();
+    Vec.first = Offset - ConstantPoolOffset;
+
+    uint32_t Num = Data.getU32(&Offset);
+    for (uint32_t j = 0; j < Num; ++j)
+      Vec.second.push_back(Data.getU32(&Offset));
+  }
+
+  ConstantPoolStrings = Data.getData().drop_front(Offset);
+  StringPoolOffset = Offset;
+  return true;
+}
+
+void DWARFGdbIndex::parse(DataExtractor Data) {
+  HasContent = !Data.getData().empty();
+  HasError = HasContent && !parseImpl(Data);
+}
diff --git a/binaryen/third_party/llvm-project/DWARFListTable.cpp b/binaryen/third_party/llvm-project/DWARFListTable.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFListTable.cpp
@@ -0,0 +1,116 @@
+//===- DWARFListTable.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFListTable.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+Error DWARFListTableHeader::extract(DWARFDataExtractor Data,
+                                    uint64_t *OffsetPtr) {
+  HeaderOffset = *OffsetPtr;
+  // Read and verify the length field.
+  if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t)))
+    return createStringError(errc::invalid_argument,
+                       "section is not large enough to contain a "
+                       "%s table length at offset 0x%" PRIx64,
+                       SectionName.data(), *OffsetPtr);
+  Format = dwarf::DwarfFormat::DWARF32;
+  uint8_t OffsetByteSize = 4;
+  HeaderData.Length = Data.getRelocatedValue(4, OffsetPtr);
+  if (HeaderData.Length == dwarf::DW_LENGTH_DWARF64) {
+    Format = dwarf::DwarfFormat::DWARF64;
+    OffsetByteSize = 8;
+    HeaderData.Length = Data.getU64(OffsetPtr);
+  } else if (HeaderData.Length >= dwarf::DW_LENGTH_lo_reserved) {
+    return createStringError(errc::invalid_argument,
+        "%s table at offset 0x%" PRIx64
+        " has unsupported reserved unit length of value 0x%8.8" PRIx64,
+        SectionName.data(), HeaderOffset, HeaderData.Length);
+  }
+  uint64_t FullLength =
+      HeaderData.Length + dwarf::getUnitLengthFieldByteSize(Format);
+  assert(FullLength == length());
+  if (FullLength < getHeaderSize(Format))
+    return createStringError(errc::invalid_argument,
+                       "%s table at offset 0x%" PRIx64
+                       " has too small length (0x%" PRIx64
+                       ") to contain a complete header",
+                       SectionName.data(), HeaderOffset, FullLength);
+  uint64_t End = HeaderOffset + FullLength;
+  if (!Data.isValidOffsetForDataOfSize(HeaderOffset, FullLength))
+    return createStringError(errc::invalid_argument,
+                       "section is not large enough to contain a %s table "
+                       "of length 0x%" PRIx64 " at offset 0x%" PRIx64,
+                       SectionName.data(), FullLength, HeaderOffset);
+
+  HeaderData.Version = Data.getU16(OffsetPtr);
+  HeaderData.AddrSize = Data.getU8(OffsetPtr);
+  HeaderData.SegSize = Data.getU8(OffsetPtr);
+  HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr);
+
+  // Perform basic validation of the remaining header fields.
+  if (HeaderData.Version != 5)
+    return createStringError(errc::invalid_argument,
+                       "unrecognised %s table version %" PRIu16
+                       " in table at offset 0x%" PRIx64,
+                       SectionName.data(), HeaderData.Version, HeaderOffset);
+  if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
+    return createStringError(errc::not_supported,
+                       "%s table at offset 0x%" PRIx64
+                       " has unsupported address size %" PRIu8,
+                       SectionName.data(), HeaderOffset, HeaderData.AddrSize);
+  if (HeaderData.SegSize != 0)
+    return createStringError(errc::not_supported,
+                       "%s table at offset 0x%" PRIx64
+                       " has unsupported segment selector size %" PRIu8,
+                       SectionName.data(), HeaderOffset, HeaderData.SegSize);
+  if (End < HeaderOffset + getHeaderSize(Format) +
+                HeaderData.OffsetEntryCount * OffsetByteSize)
+    return createStringError(errc::invalid_argument,
+        "%s table at offset 0x%" PRIx64 " has more offset entries (%" PRIu32
+        ") than there is space for",
+        SectionName.data(), HeaderOffset, HeaderData.OffsetEntryCount);
+  Data.setAddressSize(HeaderData.AddrSize);
+  for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I)
+    Offsets.push_back(Data.getRelocatedValue(OffsetByteSize, OffsetPtr));
+  return Error::success();
+}
+
+void DWARFListTableHeader::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
+  if (DumpOpts.Verbose)
+    OS << format("0x%8.8" PRIx64 ": ", HeaderOffset);
+  OS << format(
+      "%s list header: length = 0x%8.8" PRIx64 ", version = 0x%4.4" PRIx16 ", "
+      "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8
+      ", offset_entry_count = "
+      "0x%8.8" PRIx32 "\n",
+      ListTypeString.data(), HeaderData.Length, HeaderData.Version,
+      HeaderData.AddrSize, HeaderData.SegSize, HeaderData.OffsetEntryCount);
+
+  if (HeaderData.OffsetEntryCount > 0) {
+    OS << "offsets: [";
+    for (const auto &Off : Offsets) {
+      OS << format("\n0x%8.8" PRIx64, Off);
+      if (DumpOpts.Verbose)
+        OS << format(" => 0x%8.8" PRIx64,
+                     Off + HeaderOffset + getHeaderSize(Format));
+    }
+    OS << "\n]\n";
+  }
+}
+
+uint64_t DWARFListTableHeader::length() const {
+  if (HeaderData.Length == 0)
+    return 0;
+  return HeaderData.Length + dwarf::getUnitLengthFieldByteSize(Format);
+}
diff --git a/binaryen/third_party/llvm-project/DWARFTypeUnit.cpp b/binaryen/third_party/llvm-project/DWARFTypeUnit.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFTypeUnit.cpp
@@ -0,0 +1,49 @@
+//===- DWARFTypeUnit.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cinttypes>
+
+using namespace llvm;
+
+void DWARFTypeUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
+  DWARFDie TD = getDIEForOffset(getTypeOffset() + getOffset());
+  const char *Name = TD.getName(DINameKind::ShortName);
+
+  if (DumpOpts.SummarizeTypes) {
+    OS << "name = '" << Name << "'"
+       << " type_signature = " << format("0x%016" PRIx64, getTypeHash())
+       << " length = " << format("0x%08" PRIx64, getLength()) << '\n';
+    return;
+  }
+
+  OS << format("0x%08" PRIx64, getOffset()) << ": Type Unit:"
+     << " length = " << format("0x%08" PRIx64, getLength())
+     << " version = " << format("0x%04x", getVersion());
+  if (getVersion() >= 5)
+    OS << " unit_type = " << dwarf::UnitTypeString(getUnitType());
+  OS << " abbr_offset = "
+     << format("0x%04" PRIx64, getAbbreviations()->getOffset())
+     << " addr_size = " << format("0x%02x", getAddressByteSize())
+     << " name = '" << Name << "'"
+     << " type_signature = " << format("0x%016" PRIx64, getTypeHash())
+     << " type_offset = " << format("0x%04" PRIx64, getTypeOffset())
+     << " (next unit at " << format("0x%08" PRIx64, getNextUnitOffset())
+     << ")\n";
+
+  if (DWARFDie TU = getUnitDIE(false))
+    TU.dump(OS, 0, DumpOpts);
+  else
+    OS << "<type unit can't be parsed!>\n\n";
+}
diff --git a/binaryen/third_party/llvm-project/DWARFUnit.cpp b/binaryen/third_party/llvm-project/DWARFUnit.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFUnit.cpp
@@ -0,0 +1,904 @@
+//===- DWARFUnit.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/WithColor.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+
+void DWARFUnitVector::addUnitsForSection(DWARFContext &C,
+                                         const DWARFSection &Section,
+                                         DWARFSectionKind SectionKind) {
+  const DWARFObject &D = C.getDWARFObj();
+  addUnitsImpl(C, D, Section, C.getDebugAbbrev(), &D.getRangesSection(),
+               &D.getLocSection(), D.getStrSection(),
+               D.getStrOffsetsSection(), &D.getAddrSection(),
+               D.getLineSection(), D.isLittleEndian(), false, false,
+               SectionKind);
+}
+
+void DWARFUnitVector::addUnitsForDWOSection(DWARFContext &C,
+                                            const DWARFSection &DWOSection,
+                                            DWARFSectionKind SectionKind,
+                                            bool Lazy) {
+  const DWARFObject &D = C.getDWARFObj();
+  addUnitsImpl(C, D, DWOSection, C.getDebugAbbrevDWO(), &D.getRangesDWOSection(),
+               &D.getLocDWOSection(), D.getStrDWOSection(),
+               D.getStrOffsetsDWOSection(), &D.getAddrSection(),
+               D.getLineDWOSection(), C.isLittleEndian(), true, Lazy,
+               SectionKind);
+}
+
+void DWARFUnitVector::addUnitsImpl(
+    DWARFContext &Context, const DWARFObject &Obj, const DWARFSection &Section,
+    const DWARFDebugAbbrev *DA, const DWARFSection *RS,
+    const DWARFSection *LocSection, StringRef SS, const DWARFSection &SOS,
+    const DWARFSection *AOS, const DWARFSection &LS, bool LE, bool IsDWO,
+    bool Lazy, DWARFSectionKind SectionKind) {
+  DWARFDataExtractor Data(Obj, Section, LE, 0);
+  // Lazy initialization of Parser, now that we have all section info.
+  if (!Parser) {
+    Parser = [=, &Context, &Obj, &Section, &SOS,
+              &LS](uint64_t Offset, DWARFSectionKind SectionKind,
+                   const DWARFSection *CurSection,
+                   const DWARFUnitIndex::Entry *IndexEntry)
+        -> std::unique_ptr<DWARFUnit> {
+      const DWARFSection &InfoSection = CurSection ? *CurSection : Section;
+      DWARFDataExtractor Data(Obj, InfoSection, LE, 0);
+      if (!Data.isValidOffset(Offset))
+        return nullptr;
+      const DWARFUnitIndex *Index = nullptr;
+      if (IsDWO)
+        Index = &getDWARFUnitIndex(Context, SectionKind);
+      DWARFUnitHeader Header;
+      if (!Header.extract(Context, Data, &Offset, SectionKind, Index,
+                          IndexEntry))
+        return nullptr;
+      std::unique_ptr<DWARFUnit> U;
+      if (Header.isTypeUnit())
+        U = std::make_unique<DWARFTypeUnit>(Context, InfoSection, Header, DA,
+                                             RS, LocSection, SS, SOS, AOS, LS,
+                                             LE, IsDWO, *this);
+      else
+        U = std::make_unique<DWARFCompileUnit>(Context, InfoSection, Header,
+                                                DA, RS, LocSection, SS, SOS,
+                                                AOS, LS, LE, IsDWO, *this);
+      return U;
+    };
+  }
+  if (Lazy)
+    return;
+  // Find a reasonable insertion point within the vector.  We skip over
+  // (a) units from a different section, (b) units from the same section
+  // but with lower offset-within-section.  This keeps units in order
+  // within a section, although not necessarily within the object file,
+  // even if we do lazy parsing.
+  auto I = this->begin();
+  uint64_t Offset = 0;
+  while (Data.isValidOffset(Offset)) {
+    if (I != this->end() &&
+        (&(*I)->getInfoSection() != &Section || (*I)->getOffset() == Offset)) {
+      ++I;
+      continue;
+    }
+    auto U = Parser(Offset, SectionKind, &Section, nullptr);
+    // If parsing failed, we're done with this section.
+    if (!U)
+      break;
+    Offset = U->getNextUnitOffset();
+    I = std::next(this->insert(I, std::move(U)));
+  }
+}
+
+DWARFUnit *DWARFUnitVector::addUnit(std::unique_ptr<DWARFUnit> Unit) {
+  auto I = std::upper_bound(begin(), end(), Unit,
+                            [](const std::unique_ptr<DWARFUnit> &LHS,
+                               const std::unique_ptr<DWARFUnit> &RHS) {
+                              return LHS->getOffset() < RHS->getOffset();
+                            });
+  return this->insert(I, std::move(Unit))->get();
+}
+
+DWARFUnit *DWARFUnitVector::getUnitForOffset(uint64_t Offset) const {
+  auto end = begin() + getNumInfoUnits();
+  auto *CU =
+      std::upper_bound(begin(), end, Offset,
+                       [](uint64_t LHS, const std::unique_ptr<DWARFUnit> &RHS) {
+                         return LHS < RHS->getNextUnitOffset();
+                       });
+  if (CU != end && (*CU)->getOffset() <= Offset)
+    return CU->get();
+  return nullptr;
+}
+
+DWARFUnit *
+DWARFUnitVector::getUnitForIndexEntry(const DWARFUnitIndex::Entry &E) {
+  const auto *CUOff = E.getOffset(DW_SECT_INFO);
+  if (!CUOff)
+    return nullptr;
+
+  auto Offset = CUOff->Offset;
+  auto end = begin() + getNumInfoUnits();
+
+  auto *CU =
+      std::upper_bound(begin(), end, CUOff->Offset,
+                       [](uint64_t LHS, const std::unique_ptr<DWARFUnit> &RHS) {
+                         return LHS < RHS->getNextUnitOffset();
+                       });
+  if (CU != end && (*CU)->getOffset() <= Offset)
+    return CU->get();
+
+  if (!Parser)
+    return nullptr;
+
+  auto U = Parser(Offset, DW_SECT_INFO, nullptr, &E);
+  if (!U)
+    U = nullptr;
+
+  auto *NewCU = U.get();
+  this->insert(CU, std::move(U));
+  ++NumInfoUnits;
+  return NewCU;
+}
+
+DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section,
+                     const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA,
+                     const DWARFSection *RS, const DWARFSection *LocSection,
+                     StringRef SS, const DWARFSection &SOS,
+                     const DWARFSection *AOS, const DWARFSection &LS, bool LE,
+                     bool IsDWO, const DWARFUnitVector &UnitVector)
+    : Context(DC), InfoSection(Section), Header(Header), Abbrev(DA),
+      RangeSection(RS), LocSection(LocSection), LineSection(LS),
+      StringSection(SS), StringOffsetSection(SOS), AddrOffsetSection(AOS),
+      isLittleEndian(LE), IsDWO(IsDWO), UnitVector(UnitVector) {
+  clear();
+  // For split DWARF we only need to keep track of the location list section's
+  // data (no relocations), and if we are reading a package file, we need to
+  // adjust the location list data based on the index entries.
+  if (IsDWO) {
+    LocSectionData = LocSection->Data;
+    if (auto *IndexEntry = Header.getIndexEntry())
+      if (const auto *C = IndexEntry->getOffset(DW_SECT_LOC))
+        LocSectionData = LocSectionData.substr(C->Offset, C->Length);
+  }
+}
+
+DWARFUnit::~DWARFUnit() = default;
+
+DWARFDataExtractor DWARFUnit::getDebugInfoExtractor() const {
+  return DWARFDataExtractor(Context.getDWARFObj(), InfoSection, isLittleEndian,
+                            getAddressByteSize());
+}
+
+Optional<object::SectionedAddress>
+DWARFUnit::getAddrOffsetSectionItem(uint32_t Index) const {
+  if (IsDWO) {
+    auto R = Context.info_section_units();
+    auto I = R.begin();
+    // Surprising if a DWO file has more than one skeleton unit in it - this
+    // probably shouldn't be valid, but if a use case is found, here's where to
+    // support it (probably have to linearly search for the matching skeleton CU
+    // here)
+    if (I != R.end() && std::next(I) == R.end())
+      return (*I)->getAddrOffsetSectionItem(Index);
+  }
+  uint64_t Offset = AddrOffsetSectionBase + Index * getAddressByteSize();
+  if (AddrOffsetSection->Data.size() < Offset + getAddressByteSize())
+    return None;
+  DWARFDataExtractor DA(Context.getDWARFObj(), *AddrOffsetSection,
+                        isLittleEndian, getAddressByteSize());
+  uint64_t Section;
+  uint64_t Address = DA.getRelocatedAddress(&Offset, &Section);
+  return {{Address, Section}};
+}
+
+Optional<uint64_t> DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const {
+  if (!StringOffsetsTableContribution)
+    return None;
+  unsigned ItemSize = getDwarfStringOffsetsByteSize();
+  uint64_t Offset = getStringOffsetsBase() + Index * ItemSize;
+  if (StringOffsetSection.Data.size() < Offset + ItemSize)
+    return None;
+  DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection,
+                        isLittleEndian, 0);
+  return DA.getRelocatedValue(ItemSize, &Offset);
+}
+
+bool DWARFUnitHeader::extract(DWARFContext &Context,
+                              const DWARFDataExtractor &debug_info,
+                              uint64_t *offset_ptr,
+                              DWARFSectionKind SectionKind,
+                              const DWARFUnitIndex *Index,
+                              const DWARFUnitIndex::Entry *Entry) {
+  Offset = *offset_ptr;
+  IndexEntry = Entry;
+  if (!IndexEntry && Index)
+    IndexEntry = Index->getFromOffset(*offset_ptr);
+  Length = debug_info.getRelocatedValue(4, offset_ptr);
+  FormParams.Format = DWARF32;
+  if (Length == dwarf::DW_LENGTH_DWARF64) {
+    Length = debug_info.getU64(offset_ptr);
+    FormParams.Format = DWARF64;
+  }
+  FormParams.Version = debug_info.getU16(offset_ptr);
+  if (FormParams.Version >= 5) {
+    UnitType = debug_info.getU8(offset_ptr);
+    FormParams.AddrSize = debug_info.getU8(offset_ptr);
+    AbbrOffset = debug_info.getRelocatedValue(FormParams.getDwarfOffsetByteSize(), offset_ptr);
+  } else {
+    AbbrOffset = debug_info.getRelocatedValue(FormParams.getDwarfOffsetByteSize(), offset_ptr);
+    FormParams.AddrSize = debug_info.getU8(offset_ptr);
+    // Fake a unit type based on the section type.  This isn't perfect,
+    // but distinguishing compile and type units is generally enough.
+    if (SectionKind == DW_SECT_TYPES)
+      UnitType = DW_UT_type;
+    else
+      UnitType = DW_UT_compile;
+  }
+  if (IndexEntry) {
+    if (AbbrOffset)
+      return false;
+    auto *UnitContrib = IndexEntry->getOffset();
+    if (!UnitContrib || UnitContrib->Length != (Length + 4))
+      return false;
+    auto *AbbrEntry = IndexEntry->getOffset(DW_SECT_ABBREV);
+    if (!AbbrEntry)
+      return false;
+    AbbrOffset = AbbrEntry->Offset;
+  }
+  if (isTypeUnit()) {
+    TypeHash = debug_info.getU64(offset_ptr);
+    TypeOffset =
+        debug_info.getUnsigned(offset_ptr, FormParams.getDwarfOffsetByteSize());
+  } else if (UnitType == DW_UT_split_compile || UnitType == DW_UT_skeleton)
+    DWOId = debug_info.getU64(offset_ptr);
+
+  // Header fields all parsed, capture the size of this unit header.
+  assert(*offset_ptr - Offset <= 255 && "unexpected header size");
+  Size = uint8_t(*offset_ptr - Offset);
+
+  // Type offset is unit-relative; should be after the header and before
+  // the end of the current unit.
+  bool TypeOffsetOK =
+      !isTypeUnit()
+          ? true
+          : TypeOffset >= Size &&
+                TypeOffset < getLength() + getUnitLengthFieldByteSize();
+  bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1);
+  bool VersionOK = DWARFContext::isSupportedVersion(getVersion());
+  bool AddrSizeOK = getAddressByteSize() == 4 || getAddressByteSize() == 8;
+
+  if (!LengthOK || !VersionOK || !AddrSizeOK || !TypeOffsetOK)
+    return false;
+
+  // Keep track of the highest DWARF version we encounter across all units.
+  Context.setMaxVersionIfGreater(getVersion());
+  return true;
+}
+
+// Parse the rangelist table header, including the optional array of offsets
+// following it (DWARF v5 and later).
+static Expected<DWARFDebugRnglistTable>
+parseRngListTableHeader(DWARFDataExtractor &DA, uint64_t Offset,
+                        DwarfFormat Format) {
+  // We are expected to be called with Offset 0 or pointing just past the table
+  // header. Correct Offset in the latter case so that it points to the start
+  // of the header.
+  if (Offset > 0) {
+    uint64_t HeaderSize = DWARFListTableHeader::getHeaderSize(Format);
+    if (Offset < HeaderSize)
+      return createStringError(errc::invalid_argument, "Did not detect a valid"
+                               " range list table with base = 0x%" PRIx64 "\n",
+                               Offset);
+    Offset -= HeaderSize;
+  }
+  llvm::DWARFDebugRnglistTable Table;
+  if (Error E = Table.extractHeaderAndOffsets(DA, &Offset))
+    return std::move(E);
+  return Table;
+}
+
+Error DWARFUnit::extractRangeList(uint64_t RangeListOffset,
+                                  DWARFDebugRangeList &RangeList) const {
+  // Require that compile unit is extracted.
+  assert(!DieArray.empty());
+  DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
+                                isLittleEndian, getAddressByteSize());
+  uint64_t ActualRangeListOffset = RangeSectionBase + RangeListOffset;
+  return RangeList.extract(RangesData, &ActualRangeListOffset);
+}
+
+void DWARFUnit::clear() {
+  Abbrevs = nullptr;
+  BaseAddr.reset();
+  RangeSectionBase = 0;
+  AddrOffsetSectionBase = 0;
+  clearDIEs(false);
+  DWO.reset();
+}
+
+const char *DWARFUnit::getCompilationDir() {
+  return dwarf::toString(getUnitDIE().find(DW_AT_comp_dir), nullptr);
+}
+
+void DWARFUnit::extractDIEsToVector(
+    bool AppendCUDie, bool AppendNonCUDies,
+    std::vector<DWARFDebugInfoEntry> &Dies) const {
+  if (!AppendCUDie && !AppendNonCUDies)
+    return;
+
+  // Set the offset to that of the first DIE and calculate the start of the
+  // next compilation unit header.
+  uint64_t DIEOffset = getOffset() + getHeaderSize();
+  uint64_t NextCUOffset = getNextUnitOffset();
+  DWARFDebugInfoEntry DIE;
+  DWARFDataExtractor DebugInfoData = getDebugInfoExtractor();
+  uint32_t Depth = 0;
+  bool IsCUDie = true;
+
+  while (DIE.extractFast(*this, &DIEOffset, DebugInfoData, NextCUOffset,
+                         Depth)) {
+    if (IsCUDie) {
+      if (AppendCUDie)
+        Dies.push_back(DIE);
+      if (!AppendNonCUDies)
+        break;
+      // The average bytes per DIE entry has been seen to be
+      // around 14-20 so let's pre-reserve the needed memory for
+      // our DIE entries accordingly.
+      Dies.reserve(Dies.size() + getDebugInfoSize() / 14);
+      IsCUDie = false;
+    } else {
+      Dies.push_back(DIE);
+    }
+
+    if (const DWARFAbbreviationDeclaration *AbbrDecl =
+            DIE.getAbbreviationDeclarationPtr()) {
+      // Normal DIE
+      if (AbbrDecl->hasChildren())
+        ++Depth;
+    } else {
+      // NULL DIE.
+      if (Depth > 0)
+        --Depth;
+      if (Depth == 0)
+        break;  // We are done with this compile unit!
+    }
+  }
+
+  // Give a little bit of info if we encounter corrupt DWARF (our offset
+  // should always terminate at or before the start of the next compilation
+  // unit header).
+  if (DIEOffset > NextCUOffset)
+    WithColor::warning() << format("DWARF compile unit extends beyond its "
+                                   "bounds cu 0x%8.8" PRIx64 " "
+                                   "at 0x%8.8" PRIx64 "\n",
+                                   getOffset(), DIEOffset);
+}
+
+void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
+  if (Error e = tryExtractDIEsIfNeeded(CUDieOnly))
+    WithColor::error() << toString(std::move(e));
+}
+
+Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
+  if ((CUDieOnly && !DieArray.empty()) ||
+      DieArray.size() > 1)
+    return Error::success(); // Already parsed.
+
+  bool HasCUDie = !DieArray.empty();
+  extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
+
+  if (DieArray.empty())
+    return Error::success();
+
+  // If CU DIE was just parsed, copy several attribute values from it.
+  if (HasCUDie)
+    return Error::success();
+
+  DWARFDie UnitDie(this, &DieArray[0]);
+  if (Optional<uint64_t> DWOId = toUnsigned(UnitDie.find(DW_AT_GNU_dwo_id)))
+    Header.setDWOId(*DWOId);
+  if (!IsDWO) {
+    assert(AddrOffsetSectionBase == 0);
+    assert(RangeSectionBase == 0);
+    AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_addr_base), 0);
+    if (!AddrOffsetSectionBase)
+      AddrOffsetSectionBase =
+          toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base), 0);
+    RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0);
+  }
+
+  // In general, in DWARF v5 and beyond we derive the start of the unit's
+  // contribution to the string offsets table from the unit DIE's
+  // DW_AT_str_offsets_base attribute. Split DWARF units do not use this
+  // attribute, so we assume that there is a contribution to the string
+  // offsets table starting at offset 0 of the debug_str_offsets.dwo section.
+  // In both cases we need to determine the format of the contribution,
+  // which may differ from the unit's format.
+  DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection,
+                        isLittleEndian, 0);
+  if (IsDWO || getVersion() >= 5) {
+    auto StringOffsetOrError =
+        IsDWO ? determineStringOffsetsTableContributionDWO(DA)
+              : determineStringOffsetsTableContribution(DA);
+    if (!StringOffsetOrError)
+      return createStringError(errc::invalid_argument,
+                               "invalid reference to or invalid content in "
+                               ".debug_str_offsets[.dwo]: " +
+                                   toString(StringOffsetOrError.takeError()));
+
+    StringOffsetsTableContribution = *StringOffsetOrError;
+  }
+
+  // DWARF v5 uses the .debug_rnglists and .debug_rnglists.dwo sections to
+  // describe address ranges.
+  if (getVersion() >= 5) {
+    if (IsDWO)
+      setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0);
+    else
+      setRangesSection(&Context.getDWARFObj().getRnglistsSection(),
+                       toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0));
+    if (RangeSection->Data.size()) {
+      // Parse the range list table header. Individual range lists are
+      // extracted lazily.
+      DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection,
+                                  isLittleEndian, 0);
+      auto TableOrError = parseRngListTableHeader(RangesDA, RangeSectionBase,
+                                                  Header.getFormat());
+      if (!TableOrError)
+        return createStringError(errc::invalid_argument,
+                                 "parsing a range list table: " +
+                                     toString(TableOrError.takeError()));
+
+      RngListTable = TableOrError.get();
+
+      // In a split dwarf unit, there is no DW_AT_rnglists_base attribute.
+      // Adjust RangeSectionBase to point past the table header.
+      if (IsDWO && RngListTable)
+        RangeSectionBase = RngListTable->getHeaderSize();
+    }
+  }
+
+  // Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for
+  // skeleton CU DIE, so that DWARF users not aware of it are not broken.
+  return Error::success();
+}
+
+bool DWARFUnit::parseDWO() {
+  if (IsDWO)
+    return false;
+  if (DWO.get())
+    return false;
+  DWARFDie UnitDie = getUnitDIE();
+  if (!UnitDie)
+    return false;
+  auto DWOFileName = dwarf::toString(UnitDie.find(DW_AT_GNU_dwo_name));
+  if (!DWOFileName)
+    return false;
+  auto CompilationDir = dwarf::toString(UnitDie.find(DW_AT_comp_dir));
+  SmallString<16> AbsolutePath;
+  if (sys::path::is_relative(*DWOFileName) && CompilationDir &&
+      *CompilationDir) {
+    sys::path::append(AbsolutePath, *CompilationDir);
+  }
+  sys::path::append(AbsolutePath, *DWOFileName);
+  auto DWOId = getDWOId();
+  if (!DWOId)
+    return false;
+  auto DWOContext = Context.getDWOContext(AbsolutePath);
+  if (!DWOContext)
+    return false;
+
+  DWARFCompileUnit *DWOCU = DWOContext->getDWOCompileUnitForHash(*DWOId);
+  if (!DWOCU)
+    return false;
+  DWO = std::shared_ptr<DWARFCompileUnit>(std::move(DWOContext), DWOCU);
+  // Share .debug_addr and .debug_ranges section with compile unit in .dwo
+  DWO->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase);
+  if (getVersion() >= 5) {
+    DWO->setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0);
+    DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection,
+                                isLittleEndian, 0);
+    if (auto TableOrError = parseRngListTableHeader(RangesDA, RangeSectionBase,
+                                                    Header.getFormat()))
+      DWO->RngListTable = TableOrError.get();
+    else
+      WithColor::error() << "parsing a range list table: "
+                         << toString(TableOrError.takeError())
+                         << '\n';
+    if (DWO->RngListTable)
+      DWO->RangeSectionBase = DWO->RngListTable->getHeaderSize();
+  } else {
+    auto DWORangesBase = UnitDie.getRangesBaseAttribute();
+    DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0);
+  }
+
+  return true;
+}
+
+void DWARFUnit::clearDIEs(bool KeepCUDie) {
+  if (DieArray.size() > (unsigned)KeepCUDie) {
+    DieArray.resize((unsigned)KeepCUDie);
+    DieArray.shrink_to_fit();
+  }
+}
+
+Expected<DWARFAddressRangesVector>
+DWARFUnit::findRnglistFromOffset(uint64_t Offset) {
+  if (getVersion() <= 4) {
+    DWARFDebugRangeList RangeList;
+    if (Error E = extractRangeList(Offset, RangeList))
+      return std::move(E);
+    return RangeList.getAbsoluteRanges(getBaseAddress());
+  }
+  if (RngListTable) {
+    DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
+                                  isLittleEndian, RngListTable->getAddrSize());
+    auto RangeListOrError = RngListTable->findList(RangesData, Offset);
+    if (RangeListOrError)
+      return RangeListOrError.get().getAbsoluteRanges(getBaseAddress(), *this);
+    return RangeListOrError.takeError();
+  }
+
+  return createStringError(errc::invalid_argument,
+                           "missing or invalid range list table");
+}
+
+Expected<DWARFAddressRangesVector>
+DWARFUnit::findRnglistFromIndex(uint32_t Index) {
+  if (auto Offset = getRnglistOffset(Index))
+    return findRnglistFromOffset(*Offset + RangeSectionBase);
+
+  if (RngListTable)
+    return createStringError(errc::invalid_argument,
+                             "invalid range list table index %d", Index);
+
+  return createStringError(errc::invalid_argument,
+                           "missing or invalid range list table");
+}
+
+Expected<DWARFAddressRangesVector> DWARFUnit::collectAddressRanges() {
+  DWARFDie UnitDie = getUnitDIE();
+  if (!UnitDie)
+    return createStringError(errc::invalid_argument, "No unit DIE");
+
+  // First, check if unit DIE describes address ranges for the whole unit.
+  auto CUDIERangesOrError = UnitDie.getAddressRanges();
+  if (!CUDIERangesOrError)
+    return createStringError(errc::invalid_argument,
+                             "decoding address ranges: %s",
+                             toString(CUDIERangesOrError.takeError()).c_str());
+  return *CUDIERangesOrError;
+}
+
+void DWARFUnit::updateAddressDieMap(DWARFDie Die) {
+  if (Die.isSubroutineDIE()) {
+    auto DIERangesOrError = Die.getAddressRanges();
+    if (DIERangesOrError) {
+      for (const auto &R : DIERangesOrError.get()) {
+        // Ignore 0-sized ranges.
+        if (R.LowPC == R.HighPC)
+          continue;
+        auto B = AddrDieMap.upper_bound(R.LowPC);
+        if (B != AddrDieMap.begin() && R.LowPC < (--B)->second.first) {
+          // The range is a sub-range of existing ranges, we need to split the
+          // existing range.
+          if (R.HighPC < B->second.first)
+            AddrDieMap[R.HighPC] = B->second;
+          if (R.LowPC > B->first)
+            AddrDieMap[B->first].first = R.LowPC;
+        }
+        AddrDieMap[R.LowPC] = std::make_pair(R.HighPC, Die);
+      }
+    } else
+      llvm::consumeError(DIERangesOrError.takeError());
+  }
+  // Parent DIEs are added to the AddrDieMap prior to the Children DIEs to
+  // simplify the logic to update AddrDieMap. The child's range will always
+  // be equal or smaller than the parent's range. With this assumption, when
+  // adding one range into the map, it will at most split a range into 3
+  // sub-ranges.
+  for (DWARFDie Child = Die.getFirstChild(); Child; Child = Child.getSibling())
+    updateAddressDieMap(Child);
+}
+
+DWARFDie DWARFUnit::getSubroutineForAddress(uint64_t Address) {
+  extractDIEsIfNeeded(false);
+  if (AddrDieMap.empty())
+    updateAddressDieMap(getUnitDIE());
+  auto R = AddrDieMap.upper_bound(Address);
+  if (R == AddrDieMap.begin())
+    return DWARFDie();
+  // upper_bound's previous item contains Address.
+  --R;
+  if (Address >= R->second.first)
+    return DWARFDie();
+  return R->second.second;
+}
+
+void
+DWARFUnit::getInlinedChainForAddress(uint64_t Address,
+                                     SmallVectorImpl<DWARFDie> &InlinedChain) {
+  assert(InlinedChain.empty());
+  // Try to look for subprogram DIEs in the DWO file.
+  parseDWO();
+  // First, find the subroutine that contains the given address (the leaf
+  // of inlined chain).
+  DWARFDie SubroutineDIE =
+      (DWO ? *DWO : *this).getSubroutineForAddress(Address);
+
+  if (!SubroutineDIE)
+    return;
+
+  while (!SubroutineDIE.isSubprogramDIE()) {
+    if (SubroutineDIE.getTag() == DW_TAG_inlined_subroutine)
+      InlinedChain.push_back(SubroutineDIE);
+    SubroutineDIE  = SubroutineDIE.getParent();
+  }
+  InlinedChain.push_back(SubroutineDIE);
+}
+
+const DWARFUnitIndex &llvm::getDWARFUnitIndex(DWARFContext &Context,
+                                              DWARFSectionKind Kind) {
+  if (Kind == DW_SECT_INFO)
+    return Context.getCUIndex();
+  assert(Kind == DW_SECT_TYPES);
+  return Context.getTUIndex();
+}
+
+DWARFDie DWARFUnit::getParent(const DWARFDebugInfoEntry *Die) {
+  if (!Die)
+    return DWARFDie();
+  const uint32_t Depth = Die->getDepth();
+  // Unit DIEs always have a depth of zero and never have parents.
+  if (Depth == 0)
+    return DWARFDie();
+  // Depth of 1 always means parent is the compile/type unit.
+  if (Depth == 1)
+    return getUnitDIE();
+  // Look for previous DIE with a depth that is one less than the Die's depth.
+  const uint32_t ParentDepth = Depth - 1;
+  for (uint32_t I = getDIEIndex(Die) - 1; I > 0; --I) {
+    if (DieArray[I].getDepth() == ParentDepth)
+      return DWARFDie(this, &DieArray[I]);
+  }
+  return DWARFDie();
+}
+
+DWARFDie DWARFUnit::getSibling(const DWARFDebugInfoEntry *Die) {
+  if (!Die)
+    return DWARFDie();
+  uint32_t Depth = Die->getDepth();
+  // Unit DIEs always have a depth of zero and never have siblings.
+  if (Depth == 0)
+    return DWARFDie();
+  // NULL DIEs don't have siblings.
+  if (Die->getAbbreviationDeclarationPtr() == nullptr)
+    return DWARFDie();
+
+  // Find the next DIE whose depth is the same as the Die's depth.
+  for (size_t I = getDIEIndex(Die) + 1, EndIdx = DieArray.size(); I < EndIdx;
+       ++I) {
+    if (DieArray[I].getDepth() == Depth)
+      return DWARFDie(this, &DieArray[I]);
+  }
+  return DWARFDie();
+}
+
+DWARFDie DWARFUnit::getPreviousSibling(const DWARFDebugInfoEntry *Die) {
+  if (!Die)
+    return DWARFDie();
+  uint32_t Depth = Die->getDepth();
+  // Unit DIEs always have a depth of zero and never have siblings.
+  if (Depth == 0)
+    return DWARFDie();
+
+  // Find the previous DIE whose depth is the same as the Die's depth.
+  for (size_t I = getDIEIndex(Die); I > 0;) {
+    --I;
+    if (DieArray[I].getDepth() == Depth - 1)
+      return DWARFDie();
+    if (DieArray[I].getDepth() == Depth)
+      return DWARFDie(this, &DieArray[I]);
+  }
+  return DWARFDie();
+}
+
+DWARFDie DWARFUnit::getFirstChild(const DWARFDebugInfoEntry *Die) {
+  if (!Die->hasChildren())
+    return DWARFDie();
+
+  // We do not want access out of bounds when parsing corrupted debug data.
+  size_t I = getDIEIndex(Die) + 1;
+  if (I >= DieArray.size())
+    return DWARFDie();
+  return DWARFDie(this, &DieArray[I]);
+}
+
+DWARFDie DWARFUnit::getLastChild(const DWARFDebugInfoEntry *Die) {
+  if (!Die->hasChildren())
+    return DWARFDie();
+
+  uint32_t Depth = Die->getDepth();
+  for (size_t I = getDIEIndex(Die) + 1, EndIdx = DieArray.size(); I < EndIdx;
+       ++I) {
+    if (DieArray[I].getDepth() == Depth + 1 &&
+        DieArray[I].getTag() == dwarf::DW_TAG_null)
+      return DWARFDie(this, &DieArray[I]);
+    assert(DieArray[I].getDepth() > Depth && "Not processing children?");
+  }
+  return DWARFDie();
+}
+
+const DWARFAbbreviationDeclarationSet *DWARFUnit::getAbbreviations() const {
+  if (!Abbrevs)
+    Abbrevs = Abbrev->getAbbreviationDeclarationSet(Header.getAbbrOffset());
+  return Abbrevs;
+}
+
+llvm::Optional<object::SectionedAddress> DWARFUnit::getBaseAddress() {
+  if (BaseAddr)
+    return BaseAddr;
+
+  DWARFDie UnitDie = getUnitDIE();
+  Optional<DWARFFormValue> PC = UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc});
+  BaseAddr = toSectionedAddress(PC);
+  return BaseAddr;
+}
+
+Expected<StrOffsetsContributionDescriptor>
+StrOffsetsContributionDescriptor::validateContributionSize(
+    DWARFDataExtractor &DA) {
+  uint8_t EntrySize = getDwarfOffsetByteSize();
+  // In order to ensure that we don't read a partial record at the end of
+  // the section we validate for a multiple of the entry size.
+  uint64_t ValidationSize = alignTo(Size, EntrySize);
+  // Guard against overflow.
+  if (ValidationSize >= Size)
+    if (DA.isValidOffsetForDataOfSize((uint32_t)Base, ValidationSize))
+      return *this;
+  return createStringError(errc::invalid_argument, "length exceeds section size");
+}
+
+// Look for a DWARF64-formatted contribution to the string offsets table
+// starting at a given offset and record it in a descriptor.
+static Expected<StrOffsetsContributionDescriptor>
+parseDWARF64StringOffsetsTableHeader(DWARFDataExtractor &DA, uint64_t Offset) {
+  if (!DA.isValidOffsetForDataOfSize(Offset, 16))
+    return createStringError(errc::invalid_argument, "section offset exceeds section size");
+
+  if (DA.getU32(&Offset) != dwarf::DW_LENGTH_DWARF64)
+    return createStringError(errc::invalid_argument, "32 bit contribution referenced from a 64 bit unit");
+
+  uint64_t Size = DA.getU64(&Offset);
+  uint8_t Version = DA.getU16(&Offset);
+  (void)DA.getU16(&Offset); // padding
+  // The encoded length includes the 2-byte version field and the 2-byte
+  // padding, so we need to subtract them out when we populate the descriptor.
+  return StrOffsetsContributionDescriptor(Offset, Size - 4, Version, DWARF64);
+}
+
+// Look for a DWARF32-formatted contribution to the string offsets table
+// starting at a given offset and record it in a descriptor.
+static Expected<StrOffsetsContributionDescriptor>
+parseDWARF32StringOffsetsTableHeader(DWARFDataExtractor &DA, uint64_t Offset) {
+  if (!DA.isValidOffsetForDataOfSize(Offset, 8))
+    return createStringError(errc::invalid_argument, "section offset exceeds section size");
+
+  uint32_t ContributionSize = DA.getU32(&Offset);
+  if (ContributionSize >= dwarf::DW_LENGTH_lo_reserved)
+    return createStringError(errc::invalid_argument, "invalid length");
+
+  uint8_t Version = DA.getU16(&Offset);
+  (void)DA.getU16(&Offset); // padding
+  // The encoded length includes the 2-byte version field and the 2-byte
+  // padding, so we need to subtract them out when we populate the descriptor.
+  return StrOffsetsContributionDescriptor(Offset, ContributionSize - 4, Version,
+                                          DWARF32);
+}
+
+static Expected<StrOffsetsContributionDescriptor>
+parseDWARFStringOffsetsTableHeader(DWARFDataExtractor &DA,
+                                   llvm::dwarf::DwarfFormat Format,
+                                   uint64_t Offset) {
+  StrOffsetsContributionDescriptor Desc;
+  switch (Format) {
+  case dwarf::DwarfFormat::DWARF64: {
+    if (Offset < 16)
+      return createStringError(errc::invalid_argument, "insufficient space for 64 bit header prefix");
+    auto DescOrError = parseDWARF64StringOffsetsTableHeader(DA, Offset - 16);
+    if (!DescOrError)
+      return DescOrError.takeError();
+    Desc = *DescOrError;
+    break;
+  }
+  case dwarf::DwarfFormat::DWARF32: {
+    if (Offset < 8)
+      return createStringError(errc::invalid_argument, "insufficient space for 32 bit header prefix");
+    auto DescOrError = parseDWARF32StringOffsetsTableHeader(DA, Offset - 8);
+    if (!DescOrError)
+      return DescOrError.takeError();
+    Desc = *DescOrError;
+    break;
+  }
+  }
+  return Desc.validateContributionSize(DA);
+}
+
+Expected<Optional<StrOffsetsContributionDescriptor>>
+DWARFUnit::determineStringOffsetsTableContribution(DWARFDataExtractor &DA) {
+  uint64_t Offset;
+  if (IsDWO) {
+    Offset = 0;
+    if (DA.getData().data() == nullptr)
+      return None;
+  } else {
+    auto OptOffset = toSectionOffset(getUnitDIE().find(DW_AT_str_offsets_base));
+    if (!OptOffset)
+      return None;
+    Offset = *OptOffset;
+  }
+  auto DescOrError = parseDWARFStringOffsetsTableHeader(DA, Header.getFormat(), Offset);
+  if (!DescOrError)
+    return DescOrError.takeError();
+  return *DescOrError;
+}
+
+Expected<Optional<StrOffsetsContributionDescriptor>>
+DWARFUnit::determineStringOffsetsTableContributionDWO(DWARFDataExtractor & DA) {
+  uint64_t Offset = 0;
+  auto IndexEntry = Header.getIndexEntry();
+  const auto *C =
+      IndexEntry ? IndexEntry->getOffset(DW_SECT_STR_OFFSETS) : nullptr;
+  if (C)
+    Offset = C->Offset;
+  if (getVersion() >= 5) {
+    if (DA.getData().data() == nullptr)
+      return None;
+    Offset += Header.getFormat() == dwarf::DwarfFormat::DWARF32 ? 8 : 16;
+    // Look for a valid contribution at the given offset.
+    auto DescOrError = parseDWARFStringOffsetsTableHeader(DA, Header.getFormat(), Offset);
+    if (!DescOrError)
+      return DescOrError.takeError();
+    return *DescOrError;
+  }
+  // Prior to DWARF v5, we derive the contribution size from the
+  // index table (in a package file). In a .dwo file it is simply
+  // the length of the string offsets section.
+  if (!IndexEntry)
+    return {
+        Optional<StrOffsetsContributionDescriptor>(
+            {0, StringOffsetSection.Data.size(), 4, DWARF32})};
+  if (C)
+    return {Optional<StrOffsetsContributionDescriptor>(
+        {C->Offset, C->Length, 4, DWARF32})};
+  return None;
+}
diff --git a/binaryen/third_party/llvm-project/DWARFUnitIndex.cpp b/binaryen/third_party/llvm-project/DWARFUnitIndex.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFUnitIndex.cpp
@@ -0,0 +1,200 @@
+//===- DWARFUnitIndex.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cinttypes>
+#include <cstdint>
+
+using namespace llvm;
+
+bool DWARFUnitIndex::Header::parse(DataExtractor IndexData,
+                                   uint64_t *OffsetPtr) {
+  if (!IndexData.isValidOffsetForDataOfSize(*OffsetPtr, 16))
+    return false;
+  Version = IndexData.getU32(OffsetPtr);
+  NumColumns = IndexData.getU32(OffsetPtr);
+  NumUnits = IndexData.getU32(OffsetPtr);
+  NumBuckets = IndexData.getU32(OffsetPtr);
+  return Version <= 2;
+}
+
+void DWARFUnitIndex::Header::dump(raw_ostream &OS) const {
+  OS << format("version = %u slots = %u\n\n", Version, NumBuckets);
+}
+
+bool DWARFUnitIndex::parse(DataExtractor IndexData) {
+  bool b = parseImpl(IndexData);
+  if (!b) {
+    // Make sure we don't try to dump anything
+    Header.NumBuckets = 0;
+    // Release any partially initialized data.
+    ColumnKinds.reset();
+    Rows.reset();
+  }
+  return b;
+}
+
+bool DWARFUnitIndex::parseImpl(DataExtractor IndexData) {
+  uint64_t Offset = 0;
+  if (!Header.parse(IndexData, &Offset))
+    return false;
+
+  if (!IndexData.isValidOffsetForDataOfSize(
+          Offset, Header.NumBuckets * (8 + 4) +
+                      (2 * Header.NumUnits + 1) * 4 * Header.NumColumns))
+    return false;
+
+  Rows = std::make_unique<Entry[]>(Header.NumBuckets);
+  auto Contribs =
+      std::make_unique<Entry::SectionContribution *[]>(Header.NumUnits);
+  ColumnKinds = std::make_unique<DWARFSectionKind[]>(Header.NumColumns);
+
+  // Read Hash Table of Signatures
+  for (unsigned i = 0; i != Header.NumBuckets; ++i)
+    Rows[i].Signature = IndexData.getU64(&Offset);
+
+  // Read Parallel Table of Indexes
+  for (unsigned i = 0; i != Header.NumBuckets; ++i) {
+    auto Index = IndexData.getU32(&Offset);
+    if (!Index)
+      continue;
+    Rows[i].Index = this;
+    Rows[i].Contributions =
+        std::make_unique<Entry::SectionContribution[]>(Header.NumColumns);
+    Contribs[Index - 1] = Rows[i].Contributions.get();
+  }
+
+  // Read the Column Headers
+  for (unsigned i = 0; i != Header.NumColumns; ++i) {
+    ColumnKinds[i] = static_cast<DWARFSectionKind>(IndexData.getU32(&Offset));
+    if (ColumnKinds[i] == InfoColumnKind) {
+      if (InfoColumn != -1)
+        return false;
+      InfoColumn = i;
+    }
+  }
+
+  if (InfoColumn == -1)
+    return false;
+
+  // Read Table of Section Offsets
+  for (unsigned i = 0; i != Header.NumUnits; ++i) {
+    auto *Contrib = Contribs[i];
+    for (unsigned i = 0; i != Header.NumColumns; ++i)
+      Contrib[i].Offset = IndexData.getU32(&Offset);
+  }
+
+  // Read Table of Section Sizes
+  for (unsigned i = 0; i != Header.NumUnits; ++i) {
+    auto *Contrib = Contribs[i];
+    for (unsigned i = 0; i != Header.NumColumns; ++i)
+      Contrib[i].Length = IndexData.getU32(&Offset);
+  }
+
+  return true;
+}
+
+StringRef DWARFUnitIndex::getColumnHeader(DWARFSectionKind DS) {
+#define CASE(DS)                                                               \
+  case DW_SECT_##DS:                                                           \
+    return #DS;
+  switch (DS) {
+    CASE(INFO);
+    CASE(TYPES);
+    CASE(ABBREV);
+    CASE(LINE);
+    CASE(LOC);
+    CASE(STR_OFFSETS);
+    CASE(MACINFO);
+    CASE(MACRO);
+  }
+  llvm_unreachable("unknown DWARFSectionKind");
+}
+
+void DWARFUnitIndex::dump(raw_ostream &OS) const {
+  if (!*this)
+    return;
+
+  Header.dump(OS);
+  OS << "Index Signature         ";
+  for (unsigned i = 0; i != Header.NumColumns; ++i)
+    OS << ' ' << left_justify(getColumnHeader(ColumnKinds[i]), 24);
+  OS << "\n----- ------------------";
+  for (unsigned i = 0; i != Header.NumColumns; ++i)
+    OS << " ------------------------";
+  OS << '\n';
+  for (unsigned i = 0; i != Header.NumBuckets; ++i) {
+    auto &Row = Rows[i];
+    if (auto *Contribs = Row.Contributions.get()) {
+      OS << format("%5u 0x%016" PRIx64 " ", i + 1, Row.Signature);
+      for (unsigned i = 0; i != Header.NumColumns; ++i) {
+        auto &Contrib = Contribs[i];
+        OS << format("[0x%08x, 0x%08x) ", Contrib.Offset,
+                     Contrib.Offset + Contrib.Length);
+      }
+      OS << '\n';
+    }
+  }
+}
+
+const DWARFUnitIndex::Entry::SectionContribution *
+DWARFUnitIndex::Entry::getOffset(DWARFSectionKind Sec) const {
+  uint32_t i = 0;
+  for (; i != Index->Header.NumColumns; ++i)
+    if (Index->ColumnKinds[i] == Sec)
+      return &Contributions[i];
+  return nullptr;
+}
+
+const DWARFUnitIndex::Entry::SectionContribution *
+DWARFUnitIndex::Entry::getOffset() const {
+  return &Contributions[Index->InfoColumn];
+}
+
+const DWARFUnitIndex::Entry *
+DWARFUnitIndex::getFromOffset(uint32_t Offset) const {
+  if (OffsetLookup.empty()) {
+    for (uint32_t i = 0; i != Header.NumBuckets; ++i)
+      if (Rows[i].Contributions)
+        OffsetLookup.push_back(&Rows[i]);
+    llvm::sort(OffsetLookup, [&](Entry *E1, Entry *E2) {
+      return E1->Contributions[InfoColumn].Offset <
+             E2->Contributions[InfoColumn].Offset;
+    });
+  }
+  auto I = partition_point(OffsetLookup, [&](Entry *E2) {
+    return E2->Contributions[InfoColumn].Offset <= Offset;
+  });
+  if (I == OffsetLookup.begin())
+    return nullptr;
+  --I;
+  const auto *E = *I;
+  const auto &InfoContrib = E->Contributions[InfoColumn];
+  if ((InfoContrib.Offset + InfoContrib.Length) <= Offset)
+    return nullptr;
+  return E;
+}
+
+const DWARFUnitIndex::Entry *DWARFUnitIndex::getFromHash(uint64_t S) const {
+  uint64_t Mask = Header.NumBuckets - 1;
+
+  auto H = S & Mask;
+  auto HP = ((S >> 32) & Mask) | 1;
+  while (Rows[H].getSignature() != S && Rows[H].getSignature() != 0)
+    H = (H + HP) & Mask;
+
+  if (Rows[H].getSignature() != S)
+    return nullptr;
+
+  return &Rows[H];
+}
diff --git a/binaryen/third_party/llvm-project/DWARFVerifier.cpp b/binaryen/third_party/llvm-project/DWARFVerifier.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFVerifier.cpp
@@ -0,0 +1,1493 @@
+//===- DWARFVerifier.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFSection.h"
+#include "llvm/Support/DJB.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <map>
+#include <set>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+using namespace object;
+
+DWARFVerifier::DieRangeInfo::address_range_iterator
+DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) {
+  auto Begin = Ranges.begin();
+  auto End = Ranges.end();
+  auto Pos = std::lower_bound(Begin, End, R);
+
+  if (Pos != End) {
+    if (Pos->intersects(R))
+      return std::move(Pos);
+    if (Pos != Begin) {
+      auto Iter = Pos - 1;
+      if (Iter->intersects(R))
+        return std::move(Iter);
+    }
+  }
+
+  Ranges.insert(Pos, R);
+  return Ranges.end();
+}
+
+DWARFVerifier::DieRangeInfo::die_range_info_iterator
+DWARFVerifier::DieRangeInfo::insert(const DieRangeInfo &RI) {
+  auto End = Children.end();
+  auto Iter = Children.begin();
+  while (Iter != End) {
+    if (Iter->intersects(RI))
+      return Iter;
+    ++Iter;
+  }
+  Children.insert(RI);
+  return Children.end();
+}
+
+bool DWARFVerifier::DieRangeInfo::contains(const DieRangeInfo &RHS) const {
+  auto I1 = Ranges.begin(), E1 = Ranges.end();
+  auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end();
+  if (I2 == E2)
+    return true;
+
+  DWARFAddressRange R = *I2;
+  while (I1 != E1) {
+    bool Covered = I1->LowPC <= R.LowPC;
+    if (R.LowPC == R.HighPC || (Covered && R.HighPC <= I1->HighPC)) {
+      if (++I2 == E2)
+        return true;
+      R = *I2;
+      continue;
+    }
+    if (!Covered)
+      return false;
+    if (R.LowPC < I1->HighPC)
+      R.LowPC = I1->HighPC;
+    ++I1;
+  }
+  return false;
+}
+
+bool DWARFVerifier::DieRangeInfo::intersects(const DieRangeInfo &RHS) const {
+  auto I1 = Ranges.begin(), E1 = Ranges.end();
+  auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end();
+  while (I1 != E1 && I2 != E2) {
+    if (I1->intersects(*I2))
+      return true;
+    if (I1->LowPC < I2->LowPC)
+      ++I1;
+    else
+      ++I2;
+  }
+  return false;
+}
+
+bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
+                                     uint64_t *Offset, unsigned UnitIndex,
+                                     uint8_t &UnitType, bool &isUnitDWARF64) {
+  uint64_t AbbrOffset, Length;
+  uint8_t AddrSize = 0;
+  uint16_t Version;
+  bool Success = true;
+
+  bool ValidLength = false;
+  bool ValidVersion = false;
+  bool ValidAddrSize = false;
+  bool ValidType = true;
+  bool ValidAbbrevOffset = true;
+
+  uint64_t OffsetStart = *Offset;
+  Length = DebugInfoData.getU32(Offset);
+  if (Length == dwarf::DW_LENGTH_DWARF64) {
+    Length = DebugInfoData.getU64(Offset);
+    isUnitDWARF64 = true;
+  }
+  Version = DebugInfoData.getU16(Offset);
+
+  if (Version >= 5) {
+    UnitType = DebugInfoData.getU8(Offset);
+    AddrSize = DebugInfoData.getU8(Offset);
+    AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) : DebugInfoData.getU32(Offset);
+    ValidType = dwarf::isUnitType(UnitType);
+  } else {
+    UnitType = 0;
+    AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) : DebugInfoData.getU32(Offset);
+    AddrSize = DebugInfoData.getU8(Offset);
+  }
+
+  if (!DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset))
+    ValidAbbrevOffset = false;
+
+  ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3);
+  ValidVersion = DWARFContext::isSupportedVersion(Version);
+  ValidAddrSize = AddrSize == 4 || AddrSize == 8;
+  if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset ||
+      !ValidType) {
+    Success = false;
+    error() << format("Units[%d] - start offset: 0x%08" PRIx64 " \n", UnitIndex,
+                      OffsetStart);
+    if (!ValidLength)
+      note() << "The length for this unit is too "
+                "large for the .debug_info provided.\n";
+    if (!ValidVersion)
+      note() << "The 16 bit unit header version is not valid.\n";
+    if (!ValidType)
+      note() << "The unit type encoding is not valid.\n";
+    if (!ValidAbbrevOffset)
+      note() << "The offset into the .debug_abbrev section is "
+                "not valid.\n";
+    if (!ValidAddrSize)
+      note() << "The address size is unsupported.\n";
+  }
+  *Offset = OffsetStart + Length + (isUnitDWARF64 ? 12 : 4);
+  return Success;
+}
+
+unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit) {
+  unsigned NumUnitErrors = 0;
+  unsigned NumDies = Unit.getNumDIEs();
+  for (unsigned I = 0; I < NumDies; ++I) {
+    auto Die = Unit.getDIEAtIndex(I);
+
+    if (Die.getTag() == DW_TAG_null)
+      continue;
+
+    for (auto AttrValue : Die.attributes()) {
+      NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue);
+      NumUnitErrors += verifyDebugInfoForm(Die, AttrValue);
+    }
+
+    NumUnitErrors += verifyDebugInfoCallSite(Die);
+  }
+
+  DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false);
+  if (!Die) {
+    error() << "Compilation unit without DIE.\n";
+    NumUnitErrors++;
+    return NumUnitErrors;
+  }
+
+  if (!dwarf::isUnitType(Die.getTag())) {
+    error() << "Compilation unit root DIE is not a unit DIE: "
+            << dwarf::TagString(Die.getTag()) << ".\n";
+    NumUnitErrors++;
+  }
+
+  uint8_t UnitType = Unit.getUnitType();
+  if (!DWARFUnit::isMatchingUnitTypeAndTag(UnitType, Die.getTag())) {
+    error() << "Compilation unit type (" << dwarf::UnitTypeString(UnitType)
+            << ") and root DIE (" << dwarf::TagString(Die.getTag())
+            << ") do not match.\n";
+    NumUnitErrors++;
+  }
+
+  DieRangeInfo RI;
+  NumUnitErrors += verifyDieRanges(Die, RI);
+
+  return NumUnitErrors;
+}
+
+unsigned DWARFVerifier::verifyDebugInfoCallSite(const DWARFDie &Die) {
+  if (Die.getTag() != DW_TAG_call_site && Die.getTag() != DW_TAG_GNU_call_site)
+    return 0;
+
+  DWARFDie Curr = Die.getParent();
+  for (; Curr.isValid() && !Curr.isSubprogramDIE(); Curr = Die.getParent()) {
+    if (Curr.getTag() == DW_TAG_inlined_subroutine) {
+      error() << "Call site entry nested within inlined subroutine:";
+      Curr.dump(OS);
+      return 1;
+    }
+  }
+
+  if (!Curr.isValid()) {
+    error() << "Call site entry not nested within a valid subprogram:";
+    Die.dump(OS);
+    return 1;
+  }
+
+  Optional<DWARFFormValue> CallAttr =
+      Curr.find({DW_AT_call_all_calls, DW_AT_call_all_source_calls,
+                 DW_AT_call_all_tail_calls, DW_AT_GNU_all_call_sites,
+                 DW_AT_GNU_all_source_call_sites,
+                 DW_AT_GNU_all_tail_call_sites});
+  if (!CallAttr) {
+    error() << "Subprogram with call site entry has no DW_AT_call attribute:";
+    Curr.dump(OS);
+    Die.dump(OS, /*indent*/ 1);
+    return 1;
+  }
+
+  return 0;
+}
+
+unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) {
+  unsigned NumErrors = 0;
+  if (Abbrev) {
+    const DWARFAbbreviationDeclarationSet *AbbrDecls =
+        Abbrev->getAbbreviationDeclarationSet(0);
+    for (auto AbbrDecl : *AbbrDecls) {
+      SmallDenseSet<uint16_t> AttributeSet;
+      for (auto Attribute : AbbrDecl.attributes()) {
+        auto Result = AttributeSet.insert(Attribute.Attr);
+        if (!Result.second) {
+          error() << "Abbreviation declaration contains multiple "
+                  << AttributeString(Attribute.Attr) << " attributes.\n";
+          AbbrDecl.dump(OS);
+          ++NumErrors;
+        }
+      }
+    }
+  }
+  return NumErrors;
+}
+
+bool DWARFVerifier::handleDebugAbbrev() {
+  OS << "Verifying .debug_abbrev...\n";
+
+  const DWARFObject &DObj = DCtx.getDWARFObj();
+  unsigned NumErrors = 0;
+  if (!DObj.getAbbrevSection().empty())
+    NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev());
+  if (!DObj.getAbbrevDWOSection().empty())
+    NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO());
+
+  return NumErrors == 0;
+}
+
+unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S,
+                                          DWARFSectionKind SectionKind) {
+  const DWARFObject &DObj = DCtx.getDWARFObj();
+  DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0);
+  unsigned NumDebugInfoErrors = 0;
+  uint64_t OffsetStart = 0, Offset = 0, UnitIdx = 0;
+  uint8_t UnitType = 0;
+  bool isUnitDWARF64 = false;
+  bool isHeaderChainValid = true;
+  bool hasDIE = DebugInfoData.isValidOffset(Offset);
+  DWARFUnitVector TypeUnitVector;
+  DWARFUnitVector CompileUnitVector;
+  while (hasDIE) {
+    OffsetStart = Offset;
+    if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType,
+                          isUnitDWARF64)) {
+      isHeaderChainValid = false;
+      if (isUnitDWARF64)
+        break;
+    } else {
+      DWARFUnitHeader Header;
+      Header.extract(DCtx, DebugInfoData, &OffsetStart, SectionKind);
+      DWARFUnit *Unit;
+      switch (UnitType) {
+      case dwarf::DW_UT_type:
+      case dwarf::DW_UT_split_type: {
+        Unit = TypeUnitVector.addUnit(std::make_unique<DWARFTypeUnit>(
+            DCtx, S, Header, DCtx.getDebugAbbrev(), &DObj.getRangesSection(),
+            &DObj.getLocSection(), DObj.getStrSection(),
+            DObj.getStrOffsetsSection(), &DObj.getAppleObjCSection(),
+            DObj.getLineSection(), DCtx.isLittleEndian(), false,
+            TypeUnitVector));
+        break;
+      }
+      case dwarf::DW_UT_skeleton:
+      case dwarf::DW_UT_split_compile:
+      case dwarf::DW_UT_compile:
+      case dwarf::DW_UT_partial:
+      // UnitType = 0 means that we are verifying a compile unit in DWARF v4.
+      case 0: {
+        Unit = CompileUnitVector.addUnit(std::make_unique<DWARFCompileUnit>(
+            DCtx, S, Header, DCtx.getDebugAbbrev(), &DObj.getRangesSection(),
+            &DObj.getLocSection(), DObj.getStrSection(),
+            DObj.getStrOffsetsSection(), &DObj.getAppleObjCSection(),
+            DObj.getLineSection(), DCtx.isLittleEndian(), false,
+            CompileUnitVector));
+        break;
+      }
+      default: { llvm_unreachable("Invalid UnitType."); }
+      }
+      NumDebugInfoErrors += verifyUnitContents(*Unit);
+    }
+    hasDIE = DebugInfoData.isValidOffset(Offset);
+    ++UnitIdx;
+  }
+  if (UnitIdx == 0 && !hasDIE) {
+    warn() << "Section is empty.\n";
+    isHeaderChainValid = true;
+  }
+  if (!isHeaderChainValid)
+    ++NumDebugInfoErrors;
+  NumDebugInfoErrors += verifyDebugInfoReferences();
+  return NumDebugInfoErrors;
+}
+
+bool DWARFVerifier::handleDebugInfo() {
+  const DWARFObject &DObj = DCtx.getDWARFObj();
+  unsigned NumErrors = 0;
+
+  OS << "Verifying .debug_info Unit Header Chain...\n";
+  DObj.forEachInfoSections([&](const DWARFSection &S) {
+    NumErrors += verifyUnitSection(S, DW_SECT_INFO);
+  });
+
+  OS << "Verifying .debug_types Unit Header Chain...\n";
+  DObj.forEachTypesSections([&](const DWARFSection &S) {
+    NumErrors += verifyUnitSection(S, DW_SECT_TYPES);
+  });
+  return NumErrors == 0;
+}
+
+unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,
+                                        DieRangeInfo &ParentRI) {
+  unsigned NumErrors = 0;
+
+  if (!Die.isValid())
+    return NumErrors;
+
+  auto RangesOrError = Die.getAddressRanges();
+  if (!RangesOrError) {
+    // FIXME: Report the error.
+    ++NumErrors;
+    llvm::consumeError(RangesOrError.takeError());
+    return NumErrors;
+  }
+
+  DWARFAddressRangesVector Ranges = RangesOrError.get();
+  // Build RI for this DIE and check that ranges within this DIE do not
+  // overlap.
+  DieRangeInfo RI(Die);
+
+  // TODO support object files better
+  //
+  // Some object file formats (i.e. non-MachO) support COMDAT.  ELF in
+  // particular does so by placing each function into a section.  The DWARF data
+  // for the function at that point uses a section relative DW_FORM_addrp for
+  // the DW_AT_low_pc and a DW_FORM_data4 for the offset as the DW_AT_high_pc.
+  // In such a case, when the Die is the CU, the ranges will overlap, and we
+  // will flag valid conflicting ranges as invalid.
+  //
+  // For such targets, we should read the ranges from the CU and partition them
+  // by the section id.  The ranges within a particular section should be
+  // disjoint, although the ranges across sections may overlap.  We would map
+  // the child die to the entity that it references and the section with which
+  // it is associated.  The child would then be checked against the range
+  // information for the associated section.
+  //
+  // For now, simply elide the range verification for the CU DIEs if we are
+  // processing an object file.
+
+  if (!IsObjectFile || IsMachOObject || Die.getTag() != DW_TAG_compile_unit) {
+    for (auto Range : Ranges) {
+      if (!Range.valid()) {
+        ++NumErrors;
+        error() << "Invalid address range " << Range << "\n";
+        continue;
+      }
+
+      // Verify that ranges don't intersect.
+      const auto IntersectingRange = RI.insert(Range);
+      if (IntersectingRange != RI.Ranges.end()) {
+        ++NumErrors;
+        error() << "DIE has overlapping address ranges: " << Range << " and "
+                << *IntersectingRange << "\n";
+        break;
+      }
+    }
+  }
+
+  // Verify that children don't intersect.
+  const auto IntersectingChild = ParentRI.insert(RI);
+  if (IntersectingChild != ParentRI.Children.end()) {
+    ++NumErrors;
+    error() << "DIEs have overlapping address ranges:";
+    dump(Die);
+    dump(IntersectingChild->Die) << '\n';
+  }
+
+  // Verify that ranges are contained within their parent.
+  bool ShouldBeContained = !Ranges.empty() && !ParentRI.Ranges.empty() &&
+                           !(Die.getTag() == DW_TAG_subprogram &&
+                             ParentRI.Die.getTag() == DW_TAG_subprogram);
+  if (ShouldBeContained && !ParentRI.contains(RI)) {
+    ++NumErrors;
+    error() << "DIE address ranges are not contained in its parent's ranges:";
+    dump(ParentRI.Die);
+    dump(Die, 2) << '\n';
+  }
+
+  // Recursively check children.
+  for (DWARFDie Child : Die)
+    NumErrors += verifyDieRanges(Child, RI);
+
+  return NumErrors;
+}
+
+unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
+                                                 DWARFAttribute &AttrValue) {
+  unsigned NumErrors = 0;
+  auto ReportError = [&](const Twine &TitleMsg) {
+    ++NumErrors;
+    error() << TitleMsg << '\n';
+    dump(Die) << '\n';
+  };
+
+  const DWARFObject &DObj = DCtx.getDWARFObj();
+  const auto Attr = AttrValue.Attr;
+  switch (Attr) {
+  case DW_AT_ranges:
+    // Make sure the offset in the DW_AT_ranges attribute is valid.
+    if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
+      if (*SectionOffset >= DObj.getRangesSection().Data.size())
+        ReportError("DW_AT_ranges offset is beyond .debug_ranges bounds:");
+      break;
+    }
+    ReportError("DIE has invalid DW_AT_ranges encoding:");
+    break;
+  case DW_AT_stmt_list:
+    // Make sure the offset in the DW_AT_stmt_list attribute is valid.
+    if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
+      if (*SectionOffset >= DObj.getLineSection().Data.size())
+        ReportError("DW_AT_stmt_list offset is beyond .debug_line bounds: " +
+                    llvm::formatv("{0:x8}", *SectionOffset));
+      break;
+    }
+    ReportError("DIE has invalid DW_AT_stmt_list encoding:");
+    break;
+  case DW_AT_location: {
+    auto VerifyLocationExpr = [&](ArrayRef<uint8_t> D) {
+      DWARFUnit *U = Die.getDwarfUnit();
+      DataExtractor Data(toStringRef(D), DCtx.isLittleEndian(), 0);
+      DWARFExpression Expression(Data, U->getVersion(),
+                                 U->getAddressByteSize());
+      bool Error = llvm::any_of(Expression, [](DWARFExpression::Operation &Op) {
+        return Op.isError();
+      });
+      if (Error || !Expression.verify(U))
+        ReportError("DIE contains invalid DWARF expression:");
+    };
+    if (Optional<ArrayRef<uint8_t>> Expr = AttrValue.Value.getAsBlock()) {
+      // Verify inlined location.
+      VerifyLocationExpr(*Expr);
+    } else if (auto LocOffset = AttrValue.Value.getAsSectionOffset()) {
+      // Verify location list.
+      if (auto DebugLoc = DCtx.getDebugLoc())
+        if (auto LocList = DebugLoc->getLocationListAtOffset(*LocOffset))
+          for (const auto &Entry : LocList->Entries)
+            VerifyLocationExpr(Entry.Loc);
+    }
+    break;
+  }
+  case DW_AT_specification:
+  case DW_AT_abstract_origin: {
+    if (auto ReferencedDie = Die.getAttributeValueAsReferencedDie(Attr)) {
+      auto DieTag = Die.getTag();
+      auto RefTag = ReferencedDie.getTag();
+      if (DieTag == RefTag)
+        break;
+      if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram)
+        break;
+      if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member)
+        break;
+      // This might be reference to a function declaration.
+      if (DieTag == DW_TAG_GNU_call_site && RefTag == DW_TAG_subprogram)
+        break;
+      ReportError("DIE with tag " + TagString(DieTag) + " has " +
+                  AttributeString(Attr) +
+                  " that points to DIE with "
+                  "incompatible tag " +
+                  TagString(RefTag));
+    }
+    break;
+  }
+  case DW_AT_type: {
+    DWARFDie TypeDie = Die.getAttributeValueAsReferencedDie(DW_AT_type);
+    if (TypeDie && !isType(TypeDie.getTag())) {
+      ReportError("DIE has " + AttributeString(Attr) +
+                  " with incompatible tag " + TagString(TypeDie.getTag()));
+    }
+    break;
+  }
+  default:
+    break;
+  }
+  return NumErrors;
+}
+
+unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
+                                            DWARFAttribute &AttrValue) {
+  const DWARFObject &DObj = DCtx.getDWARFObj();
+  auto DieCU = Die.getDwarfUnit();
+  unsigned NumErrors = 0;
+  const auto Form = AttrValue.Value.getForm();
+  switch (Form) {
+  case DW_FORM_ref1:
+  case DW_FORM_ref2:
+  case DW_FORM_ref4:
+  case DW_FORM_ref8:
+  case DW_FORM_ref_udata: {
+    // Verify all CU relative references are valid CU offsets.
+    Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
+    assert(RefVal);
+    if (RefVal) {
+      auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
+      auto CUOffset = AttrValue.Value.getRawUValue();
+      if (CUOffset >= CUSize) {
+        ++NumErrors;
+        error() << FormEncodingString(Form) << " CU offset "
+                << format("0x%08" PRIx64, CUOffset)
+                << " is invalid (must be less than CU size of "
+                << format("0x%08" PRIx64, CUSize) << "):\n";
+        Die.dump(OS, 0, DumpOpts);
+        dump(Die) << '\n';
+      } else {
+        // Valid reference, but we will verify it points to an actual
+        // DIE later.
+        ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
+      }
+    }
+    break;
+  }
+  case DW_FORM_ref_addr: {
+    // Verify all absolute DIE references have valid offsets in the
+    // .debug_info section.
+    Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
+    assert(RefVal);
+    if (RefVal) {
+      if (*RefVal >= DieCU->getInfoSection().Data.size()) {
+        ++NumErrors;
+        error() << "DW_FORM_ref_addr offset beyond .debug_info "
+                   "bounds:\n";
+        dump(Die) << '\n';
+      } else {
+        // Valid reference, but we will verify it points to an actual
+        // DIE later.
+        ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
+      }
+    }
+    break;
+  }
+  case DW_FORM_strp: {
+    auto SecOffset = AttrValue.Value.getAsSectionOffset();
+    assert(SecOffset); // DW_FORM_strp is a section offset.
+    if (SecOffset && *SecOffset >= DObj.getStrSection().size()) {
+      ++NumErrors;
+      error() << "DW_FORM_strp offset beyond .debug_str bounds:\n";
+      dump(Die) << '\n';
+    }
+    break;
+  }
+  case DW_FORM_strx:
+  case DW_FORM_strx1:
+  case DW_FORM_strx2:
+  case DW_FORM_strx3:
+  case DW_FORM_strx4: {
+    auto Index = AttrValue.Value.getRawUValue();
+    auto DieCU = Die.getDwarfUnit();
+    // Check that we have a valid DWARF v5 string offsets table.
+    if (!DieCU->getStringOffsetsTableContribution()) {
+      ++NumErrors;
+      error() << FormEncodingString(Form)
+              << " used without a valid string offsets table:\n";
+      dump(Die) << '\n';
+      break;
+    }
+    // Check that the index is within the bounds of the section.
+    unsigned ItemSize = DieCU->getDwarfStringOffsetsByteSize();
+    // Use a 64-bit type to calculate the offset to guard against overflow.
+    uint64_t Offset =
+        (uint64_t)DieCU->getStringOffsetsBase() + Index * ItemSize;
+    if (DObj.getStrOffsetsSection().Data.size() < Offset + ItemSize) {
+      ++NumErrors;
+      error() << FormEncodingString(Form) << " uses index "
+              << format("%" PRIu64, Index) << ", which is too large:\n";
+      dump(Die) << '\n';
+      break;
+    }
+    // Check that the string offset is valid.
+    uint64_t StringOffset = *DieCU->getStringOffsetSectionItem(Index);
+    if (StringOffset >= DObj.getStrSection().size()) {
+      ++NumErrors;
+      error() << FormEncodingString(Form) << " uses index "
+              << format("%" PRIu64, Index)
+              << ", but the referenced string"
+                 " offset is beyond .debug_str bounds:\n";
+      dump(Die) << '\n';
+    }
+    break;
+  }
+  default:
+    break;
+  }
+  return NumErrors;
+}
+
+unsigned DWARFVerifier::verifyDebugInfoReferences() {
+  // Take all references and make sure they point to an actual DIE by
+  // getting the DIE by offset and emitting an error
+  OS << "Verifying .debug_info references...\n";
+  unsigned NumErrors = 0;
+  for (const std::pair<uint64_t, std::set<uint64_t>> &Pair :
+       ReferenceToDIEOffsets) {
+    if (DCtx.getDIEForOffset(Pair.first))
+      continue;
+    ++NumErrors;
+    error() << "invalid DIE reference " << format("0x%08" PRIx64, Pair.first)
+            << ". Offset is in between DIEs:\n";
+    for (auto Offset : Pair.second)
+      dump(DCtx.getDIEForOffset(Offset)) << '\n';
+    OS << "\n";
+  }
+  return NumErrors;
+}
+
+void DWARFVerifier::verifyDebugLineStmtOffsets() {
+  std::map<uint64_t, DWARFDie> StmtListToDie;
+  for (const auto &CU : DCtx.compile_units()) {
+    auto Die = CU->getUnitDIE();
+    // Get the attribute value as a section offset. No need to produce an
+    // error here if the encoding isn't correct because we validate this in
+    // the .debug_info verifier.
+    auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list));
+    if (!StmtSectionOffset)
+      continue;
+    const uint64_t LineTableOffset = *StmtSectionOffset;
+    auto LineTable = DCtx.getLineTableForUnit(CU.get());
+    if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) {
+      if (!LineTable) {
+        ++NumDebugLineErrors;
+        error() << ".debug_line[" << format("0x%08" PRIx64, LineTableOffset)
+                << "] was not able to be parsed for CU:\n";
+        dump(Die) << '\n';
+        continue;
+      }
+    } else {
+      // Make sure we don't get a valid line table back if the offset is wrong.
+      assert(LineTable == nullptr);
+      // Skip this line table as it isn't valid. No need to create an error
+      // here because we validate this in the .debug_info verifier.
+      continue;
+    }
+    auto Iter = StmtListToDie.find(LineTableOffset);
+    if (Iter != StmtListToDie.end()) {
+      ++NumDebugLineErrors;
+      error() << "two compile unit DIEs, "
+              << format("0x%08" PRIx64, Iter->second.getOffset()) << " and "
+              << format("0x%08" PRIx64, Die.getOffset())
+              << ", have the same DW_AT_stmt_list section offset:\n";
+      dump(Iter->second);
+      dump(Die) << '\n';
+      // Already verified this line table before, no need to do it again.
+      continue;
+    }
+    StmtListToDie[LineTableOffset] = Die;
+  }
+}
+
+void DWARFVerifier::verifyDebugLineRows() {
+  for (const auto &CU : DCtx.compile_units()) {
+    auto Die = CU->getUnitDIE();
+    auto LineTable = DCtx.getLineTableForUnit(CU.get());
+    // If there is no line table we will have created an error in the
+    // .debug_info verifier or in verifyDebugLineStmtOffsets().
+    if (!LineTable)
+      continue;
+
+    // Verify prologue.
+    uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size();
+    uint32_t FileIndex = 1;
+    StringMap<uint16_t> FullPathMap;
+    for (const auto &FileName : LineTable->Prologue.FileNames) {
+      // Verify directory index.
+      if (FileName.DirIdx > MaxDirIndex) {
+        ++NumDebugLineErrors;
+        error() << ".debug_line["
+                << format("0x%08" PRIx64,
+                          *toSectionOffset(Die.find(DW_AT_stmt_list)))
+                << "].prologue.file_names[" << FileIndex
+                << "].dir_idx contains an invalid index: " << FileName.DirIdx
+                << "\n";
+      }
+
+      // Check file paths for duplicates.
+      std::string FullPath;
+      const bool HasFullPath = LineTable->getFileNameByIndex(
+          FileIndex, CU->getCompilationDir(),
+          DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath);
+      assert(HasFullPath && "Invalid index?");
+      (void)HasFullPath;
+      auto It = FullPathMap.find(FullPath);
+      if (It == FullPathMap.end())
+        FullPathMap[FullPath] = FileIndex;
+      else if (It->second != FileIndex) {
+        warn() << ".debug_line["
+               << format("0x%08" PRIx64,
+                         *toSectionOffset(Die.find(DW_AT_stmt_list)))
+               << "].prologue.file_names[" << FileIndex
+               << "] is a duplicate of file_names[" << It->second << "]\n";
+      }
+
+      FileIndex++;
+    }
+
+    // Verify rows.
+    uint64_t PrevAddress = 0;
+    uint32_t RowIndex = 0;
+    for (const auto &Row : LineTable->Rows) {
+      // Verify row address.
+      if (Row.Address.Address < PrevAddress) {
+        ++NumDebugLineErrors;
+        error() << ".debug_line["
+                << format("0x%08" PRIx64,
+                          *toSectionOffset(Die.find(DW_AT_stmt_list)))
+                << "] row[" << RowIndex
+                << "] decreases in address from previous row:\n";
+
+        DWARFDebugLine::Row::dumpTableHeader(OS);
+        if (RowIndex > 0)
+          LineTable->Rows[RowIndex - 1].dump(OS);
+        Row.dump(OS);
+        OS << '\n';
+      }
+
+      // Verify file index.
+      if (!LineTable->hasFileAtIndex(Row.File)) {
+        ++NumDebugLineErrors;
+        bool isDWARF5 = LineTable->Prologue.getVersion() >= 5;
+        error() << ".debug_line["
+                << format("0x%08" PRIx64,
+                          *toSectionOffset(Die.find(DW_AT_stmt_list)))
+                << "][" << RowIndex << "] has invalid file index " << Row.File
+                << " (valid values are [" << (isDWARF5 ? "0," : "1,")
+                << LineTable->Prologue.FileNames.size()
+                << (isDWARF5 ? ")" : "]") << "):\n";
+        DWARFDebugLine::Row::dumpTableHeader(OS);
+        Row.dump(OS);
+        OS << '\n';
+      }
+      if (Row.EndSequence)
+        PrevAddress = 0;
+      else
+        PrevAddress = Row.Address.Address;
+      ++RowIndex;
+    }
+  }
+}
+
+DWARFVerifier::DWARFVerifier(raw_ostream &S, DWARFContext &D,
+                             DIDumpOptions DumpOpts)
+    : OS(S), DCtx(D), DumpOpts(std::move(DumpOpts)), IsObjectFile(false),
+      IsMachOObject(false) {
+  if (const auto *F = DCtx.getDWARFObj().getFile()) {
+    IsObjectFile = F->isRelocatableObject();
+    IsMachOObject = F->isMachO();
+  }
+}
+
+bool DWARFVerifier::handleDebugLine() {
+  NumDebugLineErrors = 0;
+  OS << "Verifying .debug_line...\n";
+  verifyDebugLineStmtOffsets();
+  verifyDebugLineRows();
+  return NumDebugLineErrors == 0;
+}
+
+unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
+                                              DataExtractor *StrData,
+                                              const char *SectionName) {
+  unsigned NumErrors = 0;
+  DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection,
+                                      DCtx.isLittleEndian(), 0);
+  AppleAcceleratorTable AccelTable(AccelSectionData, *StrData);
+
+  OS << "Verifying " << SectionName << "...\n";
+
+  // Verify that the fixed part of the header is not too short.
+  if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) {
+    error() << "Section is too small to fit a section header.\n";
+    return 1;
+  }
+
+  // Verify that the section is not too short.
+  if (Error E = AccelTable.extract()) {
+    error() << toString(std::move(E)) << '\n';
+    return 1;
+  }
+
+  // Verify that all buckets have a valid hash index or are empty.
+  uint32_t NumBuckets = AccelTable.getNumBuckets();
+  uint32_t NumHashes = AccelTable.getNumHashes();
+
+  uint64_t BucketsOffset =
+      AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength();
+  uint64_t HashesBase = BucketsOffset + NumBuckets * 4;
+  uint64_t OffsetsBase = HashesBase + NumHashes * 4;
+  for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
+    uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
+    if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
+      error() << format("Bucket[%d] has invalid hash index: %u.\n", BucketIdx,
+                        HashIdx);
+      ++NumErrors;
+    }
+  }
+  uint32_t NumAtoms = AccelTable.getAtomsDesc().size();
+  if (NumAtoms == 0) {
+    error() << "No atoms: failed to read HashData.\n";
+    return 1;
+  }
+  if (!AccelTable.validateForms()) {
+    error() << "Unsupported form: failed to read HashData.\n";
+    return 1;
+  }
+
+  for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
+    uint64_t HashOffset = HashesBase + 4 * HashIdx;
+    uint64_t DataOffset = OffsetsBase + 4 * HashIdx;
+    uint32_t Hash = AccelSectionData.getU32(&HashOffset);
+    uint64_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
+    if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
+                                                     sizeof(uint64_t))) {
+      error() << format("Hash[%d] has invalid HashData offset: "
+                        "0x%08" PRIx64 ".\n",
+                        HashIdx, HashDataOffset);
+      ++NumErrors;
+    }
+
+    uint64_t StrpOffset;
+    uint64_t StringOffset;
+    uint32_t StringCount = 0;
+    uint64_t Offset;
+    unsigned Tag;
+    while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {
+      const uint32_t NumHashDataObjects =
+          AccelSectionData.getU32(&HashDataOffset);
+      for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
+           ++HashDataIdx) {
+        std::tie(Offset, Tag) = AccelTable.readAtoms(&HashDataOffset);
+        auto Die = DCtx.getDIEForOffset(Offset);
+        if (!Die) {
+          const uint32_t BucketIdx =
+              NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
+          StringOffset = StrpOffset;
+          const char *Name = StrData->getCStr(&StringOffset);
+          if (!Name)
+            Name = "<NULL>";
+
+          error() << format(
+              "%s Bucket[%d] Hash[%d] = 0x%08x "
+              "Str[%u] = 0x%08" PRIx64 " DIE[%d] = 0x%08" PRIx64 " "
+              "is not a valid DIE offset for \"%s\".\n",
+              SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset,
+              HashDataIdx, Offset, Name);
+
+          ++NumErrors;
+          continue;
+        }
+        if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)) {
+          error() << "Tag " << dwarf::TagString(Tag)
+                  << " in accelerator table does not match Tag "
+                  << dwarf::TagString(Die.getTag()) << " of DIE[" << HashDataIdx
+                  << "].\n";
+          ++NumErrors;
+        }
+      }
+      ++StringCount;
+    }
+  }
+  return NumErrors;
+}
+
+unsigned
+DWARFVerifier::verifyDebugNamesCULists(const DWARFDebugNames &AccelTable) {
+  // A map from CU offset to the (first) Name Index offset which claims to index
+  // this CU.
+  DenseMap<uint64_t, uint64_t> CUMap;
+  const uint64_t NotIndexed = std::numeric_limits<uint64_t>::max();
+
+  CUMap.reserve(DCtx.getNumCompileUnits());
+  for (const auto &CU : DCtx.compile_units())
+    CUMap[CU->getOffset()] = NotIndexed;
+
+  unsigned NumErrors = 0;
+  for (const DWARFDebugNames::NameIndex &NI : AccelTable) {
+    if (NI.getCUCount() == 0) {
+      error() << formatv("Name Index @ {0:x} does not index any CU\n",
+                         NI.getUnitOffset());
+      ++NumErrors;
+      continue;
+    }
+    for (uint32_t CU = 0, End = NI.getCUCount(); CU < End; ++CU) {
+      uint64_t Offset = NI.getCUOffset(CU);
+      auto Iter = CUMap.find(Offset);
+
+      if (Iter == CUMap.end()) {
+        error() << formatv(
+            "Name Index @ {0:x} references a non-existing CU @ {1:x}\n",
+            NI.getUnitOffset(), Offset);
+        ++NumErrors;
+        continue;
+      }
+
+      if (Iter->second != NotIndexed) {
+        error() << formatv("Name Index @ {0:x} references a CU @ {1:x}, but "
+                           "this CU is already indexed by Name Index @ {2:x}\n",
+                           NI.getUnitOffset(), Offset, Iter->second);
+        continue;
+      }
+      Iter->second = NI.getUnitOffset();
+    }
+  }
+
+  for (const auto &KV : CUMap) {
+    if (KV.second == NotIndexed)
+      warn() << formatv("CU @ {0:x} not covered by any Name Index\n", KV.first);
+  }
+
+  return NumErrors;
+}
+
+unsigned
+DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
+                                      const DataExtractor &StrData) {
+  struct BucketInfo {
+    uint32_t Bucket;
+    uint32_t Index;
+
+    constexpr BucketInfo(uint32_t Bucket, uint32_t Index)
+        : Bucket(Bucket), Index(Index) {}
+    bool operator<(const BucketInfo &RHS) const { return Index < RHS.Index; };
+  };
+
+  uint32_t NumErrors = 0;
+  if (NI.getBucketCount() == 0) {
+    warn() << formatv("Name Index @ {0:x} does not contain a hash table.\n",
+                      NI.getUnitOffset());
+    return NumErrors;
+  }
+
+  // Build up a list of (Bucket, Index) pairs. We use this later to verify that
+  // each Name is reachable from the appropriate bucket.
+  std::vector<BucketInfo> BucketStarts;
+  BucketStarts.reserve(NI.getBucketCount() + 1);
+  for (uint32_t Bucket = 0, End = NI.getBucketCount(); Bucket < End; ++Bucket) {
+    uint32_t Index = NI.getBucketArrayEntry(Bucket);
+    if (Index > NI.getNameCount()) {
+      error() << formatv("Bucket {0} of Name Index @ {1:x} contains invalid "
+                         "value {2}. Valid range is [0, {3}].\n",
+                         Bucket, NI.getUnitOffset(), Index, NI.getNameCount());
+      ++NumErrors;
+      continue;
+    }
+    if (Index > 0)
+      BucketStarts.emplace_back(Bucket, Index);
+  }
+
+  // If there were any buckets with invalid values, skip further checks as they
+  // will likely produce many errors which will only confuse the actual root
+  // problem.
+  if (NumErrors > 0)
+    return NumErrors;
+
+  // Sort the list in the order of increasing "Index" entries.
+  array_pod_sort(BucketStarts.begin(), BucketStarts.end());
+
+  // Insert a sentinel entry at the end, so we can check that the end of the
+  // table is covered in the loop below.
+  BucketStarts.emplace_back(NI.getBucketCount(), NI.getNameCount() + 1);
+
+  // Loop invariant: NextUncovered is the (1-based) index of the first Name
+  // which is not reachable by any of the buckets we processed so far (and
+  // hasn't been reported as uncovered).
+  uint32_t NextUncovered = 1;
+  for (const BucketInfo &B : BucketStarts) {
+    // Under normal circumstances B.Index be equal to NextUncovered, but it can
+    // be less if a bucket points to names which are already known to be in some
+    // bucket we processed earlier. In that case, we won't trigger this error,
+    // but report the mismatched hash value error instead. (We know the hash
+    // will not match because we have already verified that the name's hash
+    // puts it into the previous bucket.)
+    if (B.Index > NextUncovered) {
+      error() << formatv("Name Index @ {0:x}: Name table entries [{1}, {2}] "
+                         "are not covered by the hash table.\n",
+                         NI.getUnitOffset(), NextUncovered, B.Index - 1);
+      ++NumErrors;
+    }
+    uint32_t Idx = B.Index;
+
+    // The rest of the checks apply only to non-sentinel entries.
+    if (B.Bucket == NI.getBucketCount())
+      break;
+
+    // This triggers if a non-empty bucket points to a name with a mismatched
+    // hash. Clients are likely to interpret this as an empty bucket, because a
+    // mismatched hash signals the end of a bucket, but if this is indeed an
+    // empty bucket, the producer should have signalled this by marking the
+    // bucket as empty.
+    uint32_t FirstHash = NI.getHashArrayEntry(Idx);
+    if (FirstHash % NI.getBucketCount() != B.Bucket) {
+      error() << formatv(
+          "Name Index @ {0:x}: Bucket {1} is not empty but points to a "
+          "mismatched hash value {2:x} (belonging to bucket {3}).\n",
+          NI.getUnitOffset(), B.Bucket, FirstHash,
+          FirstHash % NI.getBucketCount());
+      ++NumErrors;
+    }
+
+    // This find the end of this bucket and also verifies that all the hashes in
+    // this bucket are correct by comparing the stored hashes to the ones we
+    // compute ourselves.
+    while (Idx <= NI.getNameCount()) {
+      uint32_t Hash = NI.getHashArrayEntry(Idx);
+      if (Hash % NI.getBucketCount() != B.Bucket)
+        break;
+
+      const char *Str = NI.getNameTableEntry(Idx).getString();
+      if (caseFoldingDjbHash(Str) != Hash) {
+        error() << formatv("Name Index @ {0:x}: String ({1}) at index {2} "
+                           "hashes to {3:x}, but "
+                           "the Name Index hash is {4:x}\n",
+                           NI.getUnitOffset(), Str, Idx,
+                           caseFoldingDjbHash(Str), Hash);
+        ++NumErrors;
+      }
+
+      ++Idx;
+    }
+    NextUncovered = std::max(NextUncovered, Idx);
+  }
+  return NumErrors;
+}
+
+unsigned DWARFVerifier::verifyNameIndexAttribute(
+    const DWARFDebugNames::NameIndex &NI, const DWARFDebugNames::Abbrev &Abbr,
+    DWARFDebugNames::AttributeEncoding AttrEnc) {
+  StringRef FormName = dwarf::FormEncodingString(AttrEnc.Form);
+  if (FormName.empty()) {
+    error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
+                       "unknown form: {3}.\n",
+                       NI.getUnitOffset(), Abbr.Code, AttrEnc.Index,
+                       AttrEnc.Form);
+    return 1;
+  }
+
+  if (AttrEnc.Index == DW_IDX_type_hash) {
+    if (AttrEnc.Form != dwarf::DW_FORM_data8) {
+      error() << formatv(
+          "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash "
+          "uses an unexpected form {2} (should be {3}).\n",
+          NI.getUnitOffset(), Abbr.Code, AttrEnc.Form, dwarf::DW_FORM_data8);
+      return 1;
+    }
+  }
+
+  // A list of known index attributes and their expected form classes.
+  // DW_IDX_type_hash is handled specially in the check above, as it has a
+  // specific form (not just a form class) we should expect.
+  struct FormClassTable {
+    dwarf::Index Index;
+    DWARFFormValue::FormClass Class;
+    StringLiteral ClassName;
+  };
+  static constexpr FormClassTable Table[] = {
+      {dwarf::DW_IDX_compile_unit, DWARFFormValue::FC_Constant, {"constant"}},
+      {dwarf::DW_IDX_type_unit, DWARFFormValue::FC_Constant, {"constant"}},
+      {dwarf::DW_IDX_die_offset, DWARFFormValue::FC_Reference, {"reference"}},
+      {dwarf::DW_IDX_parent, DWARFFormValue::FC_Constant, {"constant"}},
+  };
+
+  ArrayRef<FormClassTable> TableRef(Table);
+  auto Iter = find_if(TableRef, [AttrEnc](const FormClassTable &T) {
+    return T.Index == AttrEnc.Index;
+  });
+  if (Iter == TableRef.end()) {
+    warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains an "
+                      "unknown index attribute: {2}.\n",
+                      NI.getUnitOffset(), Abbr.Code, AttrEnc.Index);
+    return 0;
+  }
+
+  if (!DWARFFormValue(AttrEnc.Form).isFormClass(Iter->Class)) {
+    error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
+                       "unexpected form {3} (expected form class {4}).\n",
+                       NI.getUnitOffset(), Abbr.Code, AttrEnc.Index,
+                       AttrEnc.Form, Iter->ClassName);
+    return 1;
+  }
+  return 0;
+}
+
+unsigned
+DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) {
+  if (NI.getLocalTUCount() + NI.getForeignTUCount() > 0) {
+    warn() << formatv("Name Index @ {0:x}: Verifying indexes of type units is "
+                      "not currently supported.\n",
+                      NI.getUnitOffset());
+    return 0;
+  }
+
+  unsigned NumErrors = 0;
+  for (const auto &Abbrev : NI.getAbbrevs()) {
+    StringRef TagName = dwarf::TagString(Abbrev.Tag);
+    if (TagName.empty()) {
+      warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} references an "
+                        "unknown tag: {2}.\n",
+                        NI.getUnitOffset(), Abbrev.Code, Abbrev.Tag);
+    }
+    SmallSet<unsigned, 5> Attributes;
+    for (const auto &AttrEnc : Abbrev.Attributes) {
+      if (!Attributes.insert(AttrEnc.Index).second) {
+        error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains "
+                           "multiple {2} attributes.\n",
+                           NI.getUnitOffset(), Abbrev.Code, AttrEnc.Index);
+        ++NumErrors;
+        continue;
+      }
+      NumErrors += verifyNameIndexAttribute(NI, Abbrev, AttrEnc);
+    }
+
+    if (NI.getCUCount() > 1 && !Attributes.count(dwarf::DW_IDX_compile_unit)) {
+      error() << formatv("NameIndex @ {0:x}: Indexing multiple compile units "
+                         "and abbreviation {1:x} has no {2} attribute.\n",
+                         NI.getUnitOffset(), Abbrev.Code,
+                         dwarf::DW_IDX_compile_unit);
+      ++NumErrors;
+    }
+    if (!Attributes.count(dwarf::DW_IDX_die_offset)) {
+      error() << formatv(
+          "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n",
+          NI.getUnitOffset(), Abbrev.Code, dwarf::DW_IDX_die_offset);
+      ++NumErrors;
+    }
+  }
+  return NumErrors;
+}
+
+static SmallVector<StringRef, 2> getNames(const DWARFDie &DIE,
+                                          bool IncludeLinkageName = true) {
+  SmallVector<StringRef, 2> Result;
+  if (const char *Str = DIE.getName(DINameKind::ShortName))
+    Result.emplace_back(Str);
+  else if (DIE.getTag() == dwarf::DW_TAG_namespace)
+    Result.emplace_back("(anonymous namespace)");
+
+  if (IncludeLinkageName) {
+    if (const char *Str = DIE.getName(DINameKind::LinkageName)) {
+      if (Result.empty() || Result[0] != Str)
+        Result.emplace_back(Str);
+    }
+  }
+
+  return Result;
+}
+
+unsigned DWARFVerifier::verifyNameIndexEntries(
+    const DWARFDebugNames::NameIndex &NI,
+    const DWARFDebugNames::NameTableEntry &NTE) {
+  // Verifying type unit indexes not supported.
+  if (NI.getLocalTUCount() + NI.getForeignTUCount() > 0)
+    return 0;
+
+  const char *CStr = NTE.getString();
+  if (!CStr) {
+    error() << formatv(
+        "Name Index @ {0:x}: Unable to get string associated with name {1}.\n",
+        NI.getUnitOffset(), NTE.getIndex());
+    return 1;
+  }
+  StringRef Str(CStr);
+
+  unsigned NumErrors = 0;
+  unsigned NumEntries = 0;
+  uint64_t EntryID = NTE.getEntryOffset();
+  uint64_t NextEntryID = EntryID;
+  Expected<DWARFDebugNames::Entry> EntryOr = NI.getEntry(&NextEntryID);
+  for (; EntryOr; ++NumEntries, EntryID = NextEntryID,
+                                EntryOr = NI.getEntry(&NextEntryID)) {
+    uint32_t CUIndex = *EntryOr->getCUIndex();
+    if (CUIndex > NI.getCUCount()) {
+      error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an "
+                         "invalid CU index ({2}).\n",
+                         NI.getUnitOffset(), EntryID, CUIndex);
+      ++NumErrors;
+      continue;
+    }
+    uint64_t CUOffset = NI.getCUOffset(CUIndex);
+    uint64_t DIEOffset = CUOffset + *EntryOr->getDIEUnitOffset();
+    DWARFDie DIE = DCtx.getDIEForOffset(DIEOffset);
+    if (!DIE) {
+      error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a "
+                         "non-existing DIE @ {2:x}.\n",
+                         NI.getUnitOffset(), EntryID, DIEOffset);
+      ++NumErrors;
+      continue;
+    }
+    if (DIE.getDwarfUnit()->getOffset() != CUOffset) {
+      error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of "
+                         "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n",
+                         NI.getUnitOffset(), EntryID, DIEOffset, CUOffset,
+                         DIE.getDwarfUnit()->getOffset());
+      ++NumErrors;
+    }
+    if (DIE.getTag() != EntryOr->tag()) {
+      error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of "
+                         "DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
+                         NI.getUnitOffset(), EntryID, DIEOffset, EntryOr->tag(),
+                         DIE.getTag());
+      ++NumErrors;
+    }
+
+    auto EntryNames = getNames(DIE);
+    if (!is_contained(EntryNames, Str)) {
+      error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Name "
+                         "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
+                         NI.getUnitOffset(), EntryID, DIEOffset, Str,
+                         make_range(EntryNames.begin(), EntryNames.end()));
+      ++NumErrors;
+    }
+  }
+  handleAllErrors(EntryOr.takeError(),
+                  [&](const DWARFDebugNames::SentinelError &) {
+                    if (NumEntries > 0)
+                      return;
+                    error() << formatv("Name Index @ {0:x}: Name {1} ({2}) is "
+                                       "not associated with any entries.\n",
+                                       NI.getUnitOffset(), NTE.getIndex(), Str);
+                    ++NumErrors;
+                  },
+                  [&](const ErrorInfoBase &Info) {
+                    error()
+                        << formatv("Name Index @ {0:x}: Name {1} ({2}): {3}\n",
+                                   NI.getUnitOffset(), NTE.getIndex(), Str,
+                                   Info.message());
+                    ++NumErrors;
+                  });
+  return NumErrors;
+}
+
+static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx) {
+  Optional<DWARFFormValue> Location = Die.findRecursively(DW_AT_location);
+  if (!Location)
+    return false;
+
+  auto ContainsInterestingOperators = [&](ArrayRef<uint8_t> D) {
+    DWARFUnit *U = Die.getDwarfUnit();
+    DataExtractor Data(toStringRef(D), DCtx.isLittleEndian(), U->getAddressByteSize());
+    DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize());
+    return any_of(Expression, [](DWARFExpression::Operation &Op) {
+      return !Op.isError() && (Op.getCode() == DW_OP_addr ||
+                               Op.getCode() == DW_OP_form_tls_address ||
+                               Op.getCode() == DW_OP_GNU_push_tls_address);
+    });
+  };
+
+  if (Optional<ArrayRef<uint8_t>> Expr = Location->getAsBlock()) {
+    // Inlined location.
+    if (ContainsInterestingOperators(*Expr))
+      return true;
+  } else if (Optional<uint64_t> Offset = Location->getAsSectionOffset()) {
+    // Location list.
+    if (const DWARFDebugLoc *DebugLoc = DCtx.getDebugLoc()) {
+      if (const DWARFDebugLoc::LocationList *LocList =
+              DebugLoc->getLocationListAtOffset(*Offset)) {
+        if (any_of(LocList->Entries, [&](const DWARFDebugLoc::Entry &E) {
+              return ContainsInterestingOperators(E.Loc);
+            }))
+          return true;
+      }
+    }
+  }
+  return false;
+}
+
+unsigned DWARFVerifier::verifyNameIndexCompleteness(
+    const DWARFDie &Die, const DWARFDebugNames::NameIndex &NI) {
+
+  // First check, if the Die should be indexed. The code follows the DWARF v5
+  // wording as closely as possible.
+
+  // "All non-defining declarations (that is, debugging information entries
+  // with a DW_AT_declaration attribute) are excluded."
+  if (Die.find(DW_AT_declaration))
+    return 0;
+
+  // "DW_TAG_namespace debugging information entries without a DW_AT_name
+  // attribute are included with the name “(anonymous namespace)”.
+  // All other debugging information entries without a DW_AT_name attribute
+  // are excluded."
+  // "If a subprogram or inlined subroutine is included, and has a
+  // DW_AT_linkage_name attribute, there will be an additional index entry for
+  // the linkage name."
+  auto IncludeLinkageName = Die.getTag() == DW_TAG_subprogram ||
+                            Die.getTag() == DW_TAG_inlined_subroutine;
+  auto EntryNames = getNames(Die, IncludeLinkageName);
+  if (EntryNames.empty())
+    return 0;
+
+  // We deviate from the specification here, which says:
+  // "The name index must contain an entry for each debugging information entry
+  // that defines a named subprogram, label, variable, type, or namespace,
+  // subject to ..."
+  // Instead whitelisting all TAGs representing a "type" or a "subprogram", to
+  // make sure we catch any missing items, we instead blacklist all TAGs that we
+  // know shouldn't be indexed.
+  switch (Die.getTag()) {
+  // Compile units and modules have names but shouldn't be indexed.
+  case DW_TAG_compile_unit:
+  case DW_TAG_module:
+    return 0;
+
+  // Function and template parameters are not globally visible, so we shouldn't
+  // index them.
+  case DW_TAG_formal_parameter:
+  case DW_TAG_template_value_parameter:
+  case DW_TAG_template_type_parameter:
+  case DW_TAG_GNU_template_parameter_pack:
+  case DW_TAG_GNU_template_template_param:
+    return 0;
+
+  // Object members aren't globally visible.
+  case DW_TAG_member:
+    return 0;
+
+  // According to a strict reading of the specification, enumerators should not
+  // be indexed (and LLVM currently does not do that). However, this causes
+  // problems for the debuggers, so we may need to reconsider this.
+  case DW_TAG_enumerator:
+    return 0;
+
+  // Imported declarations should not be indexed according to the specification
+  // and LLVM currently does not do that.
+  case DW_TAG_imported_declaration:
+    return 0;
+
+  // "DW_TAG_subprogram, DW_TAG_inlined_subroutine, and DW_TAG_label debugging
+  // information entries without an address attribute (DW_AT_low_pc,
+  // DW_AT_high_pc, DW_AT_ranges, or DW_AT_entry_pc) are excluded."
+  case DW_TAG_subprogram:
+  case DW_TAG_inlined_subroutine:
+  case DW_TAG_label:
+    if (Die.findRecursively(
+            {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc}))
+      break;
+    return 0;
+
+  // "DW_TAG_variable debugging information entries with a DW_AT_location
+  // attribute that includes a DW_OP_addr or DW_OP_form_tls_address operator are
+  // included; otherwise, they are excluded."
+  //
+  // LLVM extension: We also add DW_OP_GNU_push_tls_address to this list.
+  case DW_TAG_variable:
+    if (isVariableIndexable(Die, DCtx))
+      break;
+    return 0;
+
+  default:
+    break;
+  }
+
+  // Now we know that our Die should be present in the Index. Let's check if
+  // that's the case.
+  unsigned NumErrors = 0;
+  uint64_t DieUnitOffset = Die.getOffset() - Die.getDwarfUnit()->getOffset();
+  for (StringRef Name : EntryNames) {
+    if (none_of(NI.equal_range(Name), [&](const DWARFDebugNames::Entry &E) {
+          return E.getDIEUnitOffset() == DieUnitOffset;
+        })) {
+      error() << formatv("Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with "
+                         "name {3} missing.\n",
+                         NI.getUnitOffset(), Die.getOffset(), Die.getTag(),
+                         Name);
+      ++NumErrors;
+    }
+  }
+  return NumErrors;
+}
+
+unsigned DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection,
+                                         const DataExtractor &StrData) {
+  unsigned NumErrors = 0;
+  DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), AccelSection,
+                                      DCtx.isLittleEndian(), 0);
+  DWARFDebugNames AccelTable(AccelSectionData, StrData);
+
+  OS << "Verifying .debug_names...\n";
+
+  // This verifies that we can read individual name indices and their
+  // abbreviation tables.
+  if (Error E = AccelTable.extract()) {
+    error() << toString(std::move(E)) << '\n';
+    return 1;
+  }
+
+  NumErrors += verifyDebugNamesCULists(AccelTable);
+  for (const auto &NI : AccelTable)
+    NumErrors += verifyNameIndexBuckets(NI, StrData);
+  for (const auto &NI : AccelTable)
+    NumErrors += verifyNameIndexAbbrevs(NI);
+
+  // Don't attempt Entry validation if any of the previous checks found errors
+  if (NumErrors > 0)
+    return NumErrors;
+  for (const auto &NI : AccelTable)
+    for (DWARFDebugNames::NameTableEntry NTE : NI)
+      NumErrors += verifyNameIndexEntries(NI, NTE);
+
+  if (NumErrors > 0)
+    return NumErrors;
+
+  for (const std::unique_ptr<DWARFUnit> &U : DCtx.compile_units()) {
+    if (const DWARFDebugNames::NameIndex *NI =
+            AccelTable.getCUNameIndex(U->getOffset())) {
+      auto *CU = cast<DWARFCompileUnit>(U.get());
+      for (const DWARFDebugInfoEntry &Die : CU->dies())
+        NumErrors += verifyNameIndexCompleteness(DWARFDie(CU, &Die), *NI);
+    }
+  }
+  return NumErrors;
+}
+
+bool DWARFVerifier::handleAccelTables() {
+  const DWARFObject &D = DCtx.getDWARFObj();
+  DataExtractor StrData(D.getStrSection(), DCtx.isLittleEndian(), 0);
+  unsigned NumErrors = 0;
+  if (!D.getAppleNamesSection().Data.empty())
+    NumErrors += verifyAppleAccelTable(&D.getAppleNamesSection(), &StrData,
+                                       ".apple_names");
+  if (!D.getAppleTypesSection().Data.empty())
+    NumErrors += verifyAppleAccelTable(&D.getAppleTypesSection(), &StrData,
+                                       ".apple_types");
+  if (!D.getAppleNamespacesSection().Data.empty())
+    NumErrors += verifyAppleAccelTable(&D.getAppleNamespacesSection(), &StrData,
+                                       ".apple_namespaces");
+  if (!D.getAppleObjCSection().Data.empty())
+    NumErrors += verifyAppleAccelTable(&D.getAppleObjCSection(), &StrData,
+                                       ".apple_objc");
+
+  if (!D.getNamesSection().Data.empty())
+    NumErrors += verifyDebugNames(D.getNamesSection(), StrData);
+  return NumErrors == 0;
+}
+
+raw_ostream &DWARFVerifier::error() const { return WithColor::error(OS); }
+
+raw_ostream &DWARFVerifier::warn() const { return WithColor::warning(OS); }
+
+raw_ostream &DWARFVerifier::note() const { return WithColor::note(OS); }
+
+raw_ostream &DWARFVerifier::dump(const DWARFDie &Die, unsigned indent) const {
+  Die.dump(OS, indent, DumpOpts);
+  return OS;
+}
diff --git a/binaryen/third_party/llvm-project/DWARFVisitor.cpp b/binaryen/third_party/llvm-project/DWARFVisitor.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFVisitor.cpp
@@ -0,0 +1,238 @@
+//===--- DWARFVisitor.cpp ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include <unordered_map>
+
+#include "DWARFVisitor.h"
+#include "llvm/ObjectYAML/DWARFYAML.h"
+
+using namespace llvm;
+
+template <typename T>
+void DWARFYAML::VisitorImpl<T>::onVariableSizeValue(uint64_t U, unsigned Size) {
+  switch (Size) {
+  case 8:
+    onValue((uint64_t)U);
+    break;
+  case 4:
+    onValue((uint32_t)U);
+    break;
+  case 2:
+    onValue((uint16_t)U);
+    break;
+  case 1:
+    onValue((uint8_t)U);
+    break;
+  default:
+    llvm_unreachable("Invalid integer write size.");
+  }
+}
+
+static unsigned getOffsetSize(const DWARFYAML::Unit &Unit) {
+  return Unit.Length.isDWARF64() ? 8 : 4;
+}
+
+static unsigned getRefSize(const DWARFYAML::Unit &Unit) {
+  if (Unit.Version == 2)
+    return Unit.AddrSize;
+  return getOffsetSize(Unit);
+}
+
+template <typename T> void DWARFYAML::VisitorImpl<T>::traverseDebugInfo() {
+  // XXX BINARYEN: Handle multiple linked compile units, each of which can
+  // refer to a different abbreviation list.
+  // TODO: This code appears to assume that abbreviation codes increment by 1
+  // so that lookups are linear. In LLVM output that is true, but it might not
+  // be in general.
+  // Create a map of [byte offset into the abbreviation section] => [index in
+  // DebugInfo.AbbrevDecls]. This avoids linear search for each CU.
+  std::unordered_map<size_t, size_t> abbrByteOffsetToDeclsIndex;
+  for (size_t i = 0; i < DebugInfo.AbbrevDecls.size(); i++) {
+    auto offset = DebugInfo.AbbrevDecls[i].ListOffset;
+    // The offset is the same for all entries for the same CU, so only note the
+    // first as that is where the list for the CU (that LLVM DeclSet) begins.
+    // That is, DebugInfo.AbbrevDecls looks like this:
+    //
+    //  i  CU   Abbrev  ListOffset
+    // ============================
+    //  0   X     X1      150
+    //  1   X     X2      150
+    //  2   X     X3      150
+    //           ..
+    //  6   Y     Y1      260
+    //  7   Y     Y2      260
+    //
+    // Note how multiple rows i have the same CU. All those abbrevs have the
+    // same ListOffset, which is the byte offset into the abbreviation section
+    // for that set of abbreviations.
+    if (abbrByteOffsetToDeclsIndex.count(offset)) {
+      continue;
+    }
+    abbrByteOffsetToDeclsIndex[offset] = i;
+  }
+  for (auto &Unit : DebugInfo.CompileUnits) {
+    // AbbrOffset is the byte offset into the abbreviation section, which we
+    // need to find among the Abbrev's ListOffsets (which are the byte offsets
+    // of where that abbreviation list begins).
+    // TODO: Optimize this to not be O(#CUs * #abbrevs).
+    auto offset = Unit.AbbrOffset;
+    assert(abbrByteOffsetToDeclsIndex.count(offset));
+    size_t AbbrevStart = abbrByteOffsetToDeclsIndex[offset];
+    assert(DebugInfo.AbbrevDecls[AbbrevStart].ListOffset == offset);
+    // Find the last entry in this abbreviation list.
+    size_t AbbrevEnd = AbbrevStart;
+    while (AbbrevEnd < DebugInfo.AbbrevDecls.size() &&
+           DebugInfo.AbbrevDecls[AbbrevEnd].Code) {
+      AbbrevEnd++;
+    }
+    // XXX BINARYEN If there are no abbreviations, there is nothing to
+    //              do in this unit.
+    if (AbbrevStart == AbbrevEnd) {
+      continue;
+    }
+    onStartCompileUnit(Unit);
+    if (Unit.Entries.empty()) { // XXX BINARYEN
+      continue;
+    }
+    for (auto &Entry : Unit.Entries) {
+      onStartDIE(Unit, Entry);
+      if (Entry.AbbrCode == 0u)
+        continue;
+      // XXX BINARYEN valid abbreviation codes start from 1, so subtract that,
+      //              and are relative to the start of the abbrev table
+      auto RelativeAbbrIndex = Entry.AbbrCode - 1 + AbbrevStart;
+      if (RelativeAbbrIndex >= AbbrevEnd) {
+        errs() << "warning: invalid abbreviation code " << Entry.AbbrCode
+               << " (range: " << AbbrevStart << ".." << AbbrevEnd << ")\n";
+        continue;
+      }
+      auto &Abbrev = DebugInfo.AbbrevDecls[RelativeAbbrIndex];
+      auto FormVal = Entry.Values.begin();
+      auto AbbrForm = Abbrev.Attributes.begin();
+      for (;
+           FormVal != Entry.Values.end() && AbbrForm != Abbrev.Attributes.end();
+           ++FormVal, ++AbbrForm) {
+        onForm(*AbbrForm, *FormVal);
+        dwarf::Form Form = AbbrForm->Form;
+        bool Indirect;
+        do {
+          Indirect = false;
+          switch (Form) {
+          case dwarf::DW_FORM_addr:
+            onVariableSizeValue(FormVal->Value, Unit.AddrSize);
+            break;
+          case dwarf::DW_FORM_ref_addr:
+            onVariableSizeValue(FormVal->Value, getRefSize(Unit));
+            break;
+          case dwarf::DW_FORM_exprloc:
+          case dwarf::DW_FORM_block:
+            onValue((uint64_t)FormVal->BlockData.size(), true);
+            onValue(
+                MemoryBufferRef(StringRef((const char *)&FormVal->BlockData[0],
+                                          FormVal->BlockData.size()),
+                                ""));
+            break;
+          case dwarf::DW_FORM_block1: {
+            auto writeSize = FormVal->BlockData.size();
+            onValue((uint8_t)writeSize);
+            onValue(
+                MemoryBufferRef(StringRef((const char *)&FormVal->BlockData[0],
+                                          FormVal->BlockData.size()),
+                                ""));
+            break;
+          }
+          case dwarf::DW_FORM_block2: {
+            auto writeSize = FormVal->BlockData.size();
+            onValue((uint16_t)writeSize);
+            onValue(
+                MemoryBufferRef(StringRef((const char *)&FormVal->BlockData[0],
+                                          FormVal->BlockData.size()),
+                                ""));
+            break;
+          }
+          case dwarf::DW_FORM_block4: {
+            auto writeSize = FormVal->BlockData.size();
+            onValue((uint32_t)writeSize);
+            onValue(
+                MemoryBufferRef(StringRef((const char *)&FormVal->BlockData[0],
+                                          FormVal->BlockData.size()),
+                                ""));
+            break;
+          }
+          case dwarf::DW_FORM_data1:
+          case dwarf::DW_FORM_ref1:
+          case dwarf::DW_FORM_flag:
+          case dwarf::DW_FORM_strx1:
+          case dwarf::DW_FORM_addrx1:
+            onValue((uint8_t)FormVal->Value);
+            break;
+          case dwarf::DW_FORM_data2:
+          case dwarf::DW_FORM_ref2:
+          case dwarf::DW_FORM_strx2:
+          case dwarf::DW_FORM_addrx2:
+            onValue((uint16_t)FormVal->Value);
+            break;
+          case dwarf::DW_FORM_data4:
+          case dwarf::DW_FORM_ref4:
+          case dwarf::DW_FORM_ref_sup4:
+          case dwarf::DW_FORM_strx4:
+          case dwarf::DW_FORM_addrx4:
+            onValue((uint32_t)FormVal->Value);
+            break;
+          case dwarf::DW_FORM_data8:
+          case dwarf::DW_FORM_ref8:
+          case dwarf::DW_FORM_ref_sup8:
+            onValue((uint64_t)FormVal->Value);
+            break;
+          case dwarf::DW_FORM_sdata:
+            onValue((int64_t)FormVal->Value, true);
+            break;
+          case dwarf::DW_FORM_udata:
+          case dwarf::DW_FORM_ref_udata:
+            onValue((uint64_t)FormVal->Value, true);
+            break;
+          case dwarf::DW_FORM_string:
+            onValue(FormVal->CStr);
+            break;
+          case dwarf::DW_FORM_indirect:
+            onValue((uint64_t)FormVal->Value, true);
+            Indirect = true;
+            Form = static_cast<dwarf::Form>((uint64_t)FormVal->Value);
+            ++FormVal;
+            break;
+          case dwarf::DW_FORM_strp:
+          case dwarf::DW_FORM_sec_offset:
+          case dwarf::DW_FORM_GNU_ref_alt:
+          case dwarf::DW_FORM_GNU_strp_alt:
+          case dwarf::DW_FORM_line_strp:
+          case dwarf::DW_FORM_strp_sup:
+            onVariableSizeValue(FormVal->Value, getOffsetSize(Unit));
+            break;
+          case dwarf::DW_FORM_ref_sig8:
+            onValue((uint64_t)FormVal->Value);
+            break;
+          case dwarf::DW_FORM_GNU_addr_index:
+          case dwarf::DW_FORM_GNU_str_index:
+            onValue((uint64_t)FormVal->Value, true);
+            break;
+          default:
+            break;
+          }
+        } while (Indirect);
+      }
+      onEndDIE(Unit, Entry);
+    }
+    onEndCompileUnit(Unit);
+  }
+}
+
+// Explicitly instantiate the two template expansions.
+template class DWARFYAML::VisitorImpl<DWARFYAML::Data>;
+template class DWARFYAML::VisitorImpl<const DWARFYAML::Data>;
diff --git a/binaryen/third_party/llvm-project/DWARFVisitor.h b/binaryen/third_party/llvm-project/DWARFVisitor.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFVisitor.h
@@ -0,0 +1,96 @@
+//===--- DWARFVisitor.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECTYAML_DWARFVISITOR_H
+#define LLVM_OBJECTYAML_DWARFVISITOR_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+namespace llvm {
+
+namespace DWARFYAML {
+
+struct Data;
+struct Unit;
+struct Entry;
+struct FormValue;
+struct AttributeAbbrev;
+
+/// A class to visits DWARFYAML Compile Units and DIEs in preorder.
+///
+/// Extensions of this class can either maintain const or non-const references
+/// to the DWARFYAML::Data object.
+template <typename T> class VisitorImpl {
+protected:
+  T &DebugInfo;
+
+  /// Visitor Functions
+  /// @{
+  virtual void onStartCompileUnit(Unit &CU) {}
+  virtual void onEndCompileUnit(Unit &CU) {}
+  virtual void onStartDIE(Unit &CU, Entry &DIE) {}
+  virtual void onEndDIE(Unit &CU, Entry &DIE) {}
+  virtual void onForm(AttributeAbbrev &AttAbbrev, FormValue &Value) {}
+  /// @}
+
+  /// Const Visitor Functions
+  /// @{
+  virtual void onStartCompileUnit(const Unit &CU) {}
+  virtual void onEndCompileUnit(const Unit &CU) {}
+  virtual void onStartDIE(const Unit &CU, const Entry &DIE) {}
+  virtual void onEndDIE(const Unit &CU, const Entry &DIE) {}
+  virtual void onForm(const AttributeAbbrev &AttAbbrev,
+                      const FormValue &Value) {}
+  /// @}
+
+  /// Value visitors
+  /// @{
+  virtual void onValue(const uint8_t U) {}
+  virtual void onValue(const uint16_t U) {}
+  virtual void onValue(const uint32_t U) {}
+  virtual void onValue(const uint64_t U, const bool LEB = false) {}
+  virtual void onValue(const int64_t S, const bool LEB = false) {}
+  virtual void onValue(const StringRef String) {}
+  virtual void onValue(const MemoryBufferRef MBR) {}
+  /// @}
+
+public:
+  VisitorImpl(T &DI) : DebugInfo(DI) {}
+
+  virtual ~VisitorImpl() {}
+
+  void traverseDebugInfo();
+
+private:
+  void onVariableSizeValue(uint64_t U, unsigned Size);
+};
+
+// Making the visior instantiations extern and explicit in the cpp file. This
+// prevents them from being instantiated in every compile unit that uses the
+// visitors.
+extern template class VisitorImpl<DWARFYAML::Data>;
+extern template class VisitorImpl<const DWARFYAML::Data>;
+
+class Visitor : public VisitorImpl<Data> {
+public:
+  Visitor(Data &DI) : VisitorImpl<Data>(DI) {}
+};
+
+class ConstVisitor : public VisitorImpl<const Data> {
+public:
+  ConstVisitor(const Data &DI) : VisitorImpl<const Data>(DI) {}
+};
+
+} // namespace DWARFYAML
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/DWARFYAML.cpp b/binaryen/third_party/llvm-project/DWARFYAML.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DWARFYAML.cpp
@@ -0,0 +1,175 @@
+//===- DWARFYAML.cpp - DWARF YAMLIO implementation ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines classes for handling the YAML representation of DWARF Debug
+// Info.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ObjectYAML/DWARFYAML.h"
+
+namespace llvm {
+
+bool DWARFYAML::Data::isEmpty() const {
+  return 0 == DebugStrings.size() + AbbrevDecls.size();
+}
+
+namespace yaml {
+
+void MappingTraits<DWARFYAML::Data>::mapping(IO &IO, DWARFYAML::Data &DWARF) {
+  auto oldContext = IO.getContext();
+  IO.setContext(&DWARF);
+  IO.mapOptional("debug_str", DWARF.DebugStrings);
+  IO.mapOptional("debug_abbrev", DWARF.AbbrevDecls);
+  if (!DWARF.ARanges.empty() || !IO.outputting())
+    IO.mapOptional("debug_aranges", DWARF.ARanges);
+  if (!DWARF.PubNames.Entries.empty() || !IO.outputting())
+    IO.mapOptional("debug_pubnames", DWARF.PubNames);
+  if (!DWARF.PubTypes.Entries.empty() || !IO.outputting())
+    IO.mapOptional("debug_pubtypes", DWARF.PubTypes);
+  if (!DWARF.GNUPubNames.Entries.empty() || !IO.outputting())
+    IO.mapOptional("debug_gnu_pubnames", DWARF.GNUPubNames);
+  if (!DWARF.GNUPubTypes.Entries.empty() || !IO.outputting())
+    IO.mapOptional("debug_gnu_pubtypes", DWARF.GNUPubTypes);
+  IO.mapOptional("debug_info", DWARF.CompileUnits);
+  IO.mapOptional("debug_line", DWARF.DebugLines);
+  IO.setContext(&oldContext);
+}
+
+void MappingTraits<DWARFYAML::Abbrev>::mapping(IO &IO,
+                                               DWARFYAML::Abbrev &Abbrev) {
+  IO.mapRequired("Code", Abbrev.Code);
+  IO.mapRequired("Tag", Abbrev.Tag);
+  IO.mapRequired("Children", Abbrev.Children);
+  IO.mapRequired("Attributes", Abbrev.Attributes);
+}
+
+void MappingTraits<DWARFYAML::AttributeAbbrev>::mapping(
+    IO &IO, DWARFYAML::AttributeAbbrev &AttAbbrev) {
+  IO.mapRequired("Attribute", AttAbbrev.Attribute);
+  IO.mapRequired("Form", AttAbbrev.Form);
+  if(AttAbbrev.Form == dwarf::DW_FORM_implicit_const)
+    IO.mapRequired("Value", AttAbbrev.Value);
+}
+
+void MappingTraits<DWARFYAML::ARangeDescriptor>::mapping(
+    IO &IO, DWARFYAML::ARangeDescriptor &Descriptor) {
+  IO.mapRequired("Address", Descriptor.Address);
+  IO.mapRequired("Length", Descriptor.Length);
+}
+
+void MappingTraits<DWARFYAML::ARange>::mapping(IO &IO,
+                                               DWARFYAML::ARange &Range) {
+  IO.mapRequired("Length", Range.Length);
+  IO.mapRequired("Version", Range.Version);
+  IO.mapRequired("CuOffset", Range.CuOffset);
+  IO.mapRequired("AddrSize", Range.AddrSize);
+  IO.mapRequired("SegSize", Range.SegSize);
+  IO.mapRequired("Descriptors", Range.Descriptors);
+}
+
+void MappingTraits<DWARFYAML::PubEntry>::mapping(IO &IO,
+                                                 DWARFYAML::PubEntry &Entry) {
+  IO.mapRequired("DieOffset", Entry.DieOffset);
+  if (reinterpret_cast<DWARFYAML::PubSection *>(IO.getContext())->IsGNUStyle)
+    IO.mapRequired("Descriptor", Entry.Descriptor);
+  IO.mapRequired("Name", Entry.Name);
+}
+
+void MappingTraits<DWARFYAML::PubSection>::mapping(
+    IO &IO, DWARFYAML::PubSection &Section) {
+  auto OldContext = IO.getContext();
+  IO.setContext(&Section);
+
+  IO.mapRequired("Length", Section.Length);
+  IO.mapRequired("Version", Section.Version);
+  IO.mapRequired("UnitOffset", Section.UnitOffset);
+  IO.mapRequired("UnitSize", Section.UnitSize);
+  IO.mapRequired("Entries", Section.Entries);
+
+  IO.setContext(OldContext);
+}
+
+void MappingTraits<DWARFYAML::Unit>::mapping(IO &IO, DWARFYAML::Unit &Unit) {
+  IO.mapRequired("Length", Unit.Length);
+  IO.mapRequired("Version", Unit.Version);
+  if (Unit.Version >= 5)
+    IO.mapRequired("UnitType", Unit.Type);
+  IO.mapRequired("AbbrOffset", Unit.AbbrOffset);
+  IO.mapRequired("AddrSize", Unit.AddrSize);
+  IO.mapOptional("Entries", Unit.Entries);
+}
+
+void MappingTraits<DWARFYAML::Entry>::mapping(IO &IO, DWARFYAML::Entry &Entry) {
+  IO.mapRequired("AbbrCode", Entry.AbbrCode);
+  IO.mapRequired("Values", Entry.Values);
+}
+
+void MappingTraits<DWARFYAML::FormValue>::mapping(
+    IO &IO, DWARFYAML::FormValue &FormValue) {
+  IO.mapOptional("Value", FormValue.Value);
+  if (!FormValue.CStr.empty() || !IO.outputting())
+    IO.mapOptional("CStr", FormValue.CStr);
+  if (!FormValue.BlockData.empty() || !IO.outputting())
+    IO.mapOptional("BlockData", FormValue.BlockData);
+}
+
+void MappingTraits<DWARFYAML::File>::mapping(IO &IO, DWARFYAML::File &File) {
+  IO.mapRequired("Name", File.Name);
+  IO.mapRequired("DirIdx", File.DirIdx);
+  IO.mapRequired("ModTime", File.ModTime);
+  IO.mapRequired("Length", File.Length);
+}
+
+void MappingTraits<DWARFYAML::LineTableOpcode>::mapping(
+    IO &IO, DWARFYAML::LineTableOpcode &LineTableOpcode) {
+  IO.mapRequired("Opcode", LineTableOpcode.Opcode);
+  if (LineTableOpcode.Opcode == dwarf::DW_LNS_extended_op) {
+    IO.mapRequired("ExtLen", LineTableOpcode.ExtLen);
+    IO.mapRequired("SubOpcode", LineTableOpcode.SubOpcode);
+  }
+
+  if (!LineTableOpcode.UnknownOpcodeData.empty() || !IO.outputting())
+    IO.mapOptional("UnknownOpcodeData", LineTableOpcode.UnknownOpcodeData);
+  if (!LineTableOpcode.UnknownOpcodeData.empty() || !IO.outputting())
+    IO.mapOptional("StandardOpcodeData", LineTableOpcode.StandardOpcodeData);
+  if (!LineTableOpcode.FileEntry.Name.empty() || !IO.outputting())
+    IO.mapOptional("FileEntry", LineTableOpcode.FileEntry);
+  if (LineTableOpcode.Opcode == dwarf::DW_LNS_advance_line || !IO.outputting())
+    IO.mapOptional("SData", LineTableOpcode.SData);
+  IO.mapOptional("Data", LineTableOpcode.Data);
+}
+
+void MappingTraits<DWARFYAML::LineTable>::mapping(
+    IO &IO, DWARFYAML::LineTable &LineTable) {
+  IO.mapRequired("Length", LineTable.Length);
+  IO.mapRequired("Version", LineTable.Version);
+  IO.mapRequired("PrologueLength", LineTable.PrologueLength);
+  IO.mapRequired("MinInstLength", LineTable.MinInstLength);
+  if(LineTable.Version >= 4)
+    IO.mapRequired("MaxOpsPerInst", LineTable.MaxOpsPerInst);
+  IO.mapRequired("DefaultIsStmt", LineTable.DefaultIsStmt);
+  IO.mapRequired("LineBase", LineTable.LineBase);
+  IO.mapRequired("LineRange", LineTable.LineRange);
+  IO.mapRequired("OpcodeBase", LineTable.OpcodeBase);
+  IO.mapRequired("StandardOpcodeLengths", LineTable.StandardOpcodeLengths);
+  IO.mapRequired("IncludeDirs", LineTable.IncludeDirs);
+  IO.mapRequired("Files", LineTable.Files);
+  IO.mapRequired("Opcodes", LineTable.Opcodes);
+}
+
+void MappingTraits<DWARFYAML::InitialLength>::mapping(
+    IO &IO, DWARFYAML::InitialLength &InitialLength) {
+  IO.mapRequired("TotalLength", InitialLength.TotalLength);
+  if (InitialLength.isDWARF64())
+    IO.mapRequired("TotalLength64", InitialLength.TotalLength64);
+}
+
+} // end namespace yaml
+
+} // end namespace llvm
diff --git a/binaryen/third_party/llvm-project/DataExtractor.cpp b/binaryen/third_party/llvm-project/DataExtractor.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/DataExtractor.cpp
@@ -0,0 +1,218 @@
+//===-- DataExtractor.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/SwapByteOrder.h"
+
+using namespace llvm;
+
+static void unexpectedEndReached(Error *E) {
+  if (E)
+    *E = createStringError(errc::illegal_byte_sequence,
+                           "unexpected end of data");
+}
+
+static bool isError(Error *E) { return E && *E; }
+
+template <typename T>
+static T getU(uint64_t *offset_ptr, const DataExtractor *de,
+              bool isLittleEndian, const char *Data, llvm::Error *Err) {
+  ErrorAsOutParameter ErrAsOut(Err);
+  T val = 0;
+  if (isError(Err))
+    return val;
+
+  uint64_t offset = *offset_ptr;
+  if (!de->isValidOffsetForDataOfSize(offset, sizeof(T))) {
+    unexpectedEndReached(Err);
+    return val;
+  }
+  std::memcpy(&val, &Data[offset], sizeof(val));
+  if (sys::IsLittleEndianHost != isLittleEndian)
+    sys::swapByteOrder(val);
+
+  // Advance the offset
+  *offset_ptr += sizeof(val);
+  return val;
+}
+
+template <typename T>
+static T *getUs(uint64_t *offset_ptr, T *dst, uint32_t count,
+                const DataExtractor *de, bool isLittleEndian, const char *Data,
+                llvm::Error *Err) {
+  ErrorAsOutParameter ErrAsOut(Err);
+  if (isError(Err))
+    return nullptr;
+
+  uint64_t offset = *offset_ptr;
+
+  if (!de->isValidOffsetForDataOfSize(offset, sizeof(*dst) * count)) {
+    unexpectedEndReached(Err);
+    return nullptr;
+  }
+  for (T *value_ptr = dst, *end = dst + count; value_ptr != end;
+       ++value_ptr, offset += sizeof(*dst))
+    *value_ptr = getU<T>(offset_ptr, de, isLittleEndian, Data, Err);
+  // Advance the offset
+  *offset_ptr = offset;
+  // Return a non-NULL pointer to the converted data as an indicator of
+  // success
+  return dst;
+}
+
+uint8_t DataExtractor::getU8(uint64_t *offset_ptr, llvm::Error *Err) const {
+  return getU<uint8_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
+}
+
+uint8_t *
+DataExtractor::getU8(uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const {
+  return getUs<uint8_t>(offset_ptr, dst, count, this, IsLittleEndian,
+                        Data.data(), nullptr);
+}
+
+uint8_t *DataExtractor::getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const {
+  return getUs<uint8_t>(&C.Offset, Dst, Count, this, IsLittleEndian,
+                        Data.data(), &C.Err);
+}
+
+uint16_t DataExtractor::getU16(uint64_t *offset_ptr, llvm::Error *Err) const {
+  return getU<uint16_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
+}
+
+uint16_t *DataExtractor::getU16(uint64_t *offset_ptr, uint16_t *dst,
+                                uint32_t count) const {
+  return getUs<uint16_t>(offset_ptr, dst, count, this, IsLittleEndian,
+                         Data.data(), nullptr);
+}
+
+uint32_t DataExtractor::getU24(uint64_t *offset_ptr) const {
+  uint24_t ExtractedVal =
+      getU<uint24_t>(offset_ptr, this, IsLittleEndian, Data.data(), nullptr);
+  // The 3 bytes are in the correct byte order for the host.
+  return ExtractedVal.getAsUint32(sys::IsLittleEndianHost);
+}
+
+uint32_t DataExtractor::getU32(uint64_t *offset_ptr, llvm::Error *Err) const {
+  return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
+}
+
+uint32_t *DataExtractor::getU32(uint64_t *offset_ptr, uint32_t *dst,
+                                uint32_t count) const {
+  return getUs<uint32_t>(offset_ptr, dst, count, this, IsLittleEndian,
+                         Data.data(), nullptr);
+}
+
+uint64_t DataExtractor::getU64(uint64_t *offset_ptr, llvm::Error *Err) const {
+  return getU<uint64_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
+}
+
+uint64_t *DataExtractor::getU64(uint64_t *offset_ptr, uint64_t *dst,
+                                uint32_t count) const {
+  return getUs<uint64_t>(offset_ptr, dst, count, this, IsLittleEndian,
+                         Data.data(), nullptr);
+}
+
+uint64_t DataExtractor::getUnsigned(uint64_t *offset_ptr, uint32_t byte_size,
+                                    llvm::Error *Err) const {
+  switch (byte_size) {
+  case 1:
+    return getU8(offset_ptr, Err);
+  case 2:
+    return getU16(offset_ptr, Err);
+  case 4:
+    return getU32(offset_ptr, Err);
+  case 8:
+    return getU64(offset_ptr, Err);
+  }
+  llvm_unreachable("getUnsigned unhandled case!");
+}
+
+int64_t
+DataExtractor::getSigned(uint64_t *offset_ptr, uint32_t byte_size) const {
+  switch (byte_size) {
+  case 1:
+    return (int8_t)getU8(offset_ptr);
+  case 2:
+    return (int16_t)getU16(offset_ptr);
+  case 4:
+    return (int32_t)getU32(offset_ptr);
+  case 8:
+    return (int64_t)getU64(offset_ptr);
+  }
+  llvm_unreachable("getSigned unhandled case!");
+}
+
+const char *DataExtractor::getCStr(uint64_t *offset_ptr) const {
+  uint64_t offset = *offset_ptr;
+  StringRef::size_type pos = Data.find('\0', offset);
+  if (pos != StringRef::npos) {
+    *offset_ptr = pos + 1;
+    return Data.data() + offset;
+  }
+  return nullptr;
+}
+
+StringRef DataExtractor::getCStrRef(uint64_t *offset_ptr) const {
+  uint64_t Start = *offset_ptr;
+  StringRef::size_type Pos = Data.find('\0', Start);
+  if (Pos != StringRef::npos) {
+    *offset_ptr = Pos + 1;
+    return StringRef(Data.data() + Start, Pos - Start);
+  }
+  return StringRef();
+}
+
+uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr,
+                                   llvm::Error *Err) const {
+  assert(*offset_ptr <= Data.size());
+  ErrorAsOutParameter ErrAsOut(Err);
+  if (isError(Err))
+    return 0;
+
+  const char *error;
+  unsigned bytes_read;
+  uint64_t result = decodeULEB128(
+      reinterpret_cast<const uint8_t *>(Data.data() + *offset_ptr), &bytes_read,
+      reinterpret_cast<const uint8_t *>(Data.data() + Data.size()), &error);
+  if (error) {
+    if (Err)
+      *Err = createStringError(errc::illegal_byte_sequence, error);
+    return 0;
+  }
+  *offset_ptr += bytes_read;
+  return result;
+}
+
+int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr) const {
+  assert(*offset_ptr <= Data.size());
+
+  const char *error;
+  unsigned bytes_read;
+  int64_t result = decodeSLEB128(
+      reinterpret_cast<const uint8_t *>(Data.data() + *offset_ptr), &bytes_read,
+      reinterpret_cast<const uint8_t *>(Data.data() + Data.size()), &error);
+  if (error)
+    return 0;
+  *offset_ptr += bytes_read;
+  return result;
+}
+
+void DataExtractor::skip(Cursor &C, uint64_t Length) const {
+  ErrorAsOutParameter ErrAsOut(&C.Err);
+  if (isError(&C.Err))
+    return;
+
+  if (isValidOffsetForDataOfSize(C.Offset, Length))
+    C.Offset += Length;
+  else
+    unexpectedEndReached(&C.Err);
+}
diff --git a/binaryen/third_party/llvm-project/Debug.cpp b/binaryen/third_party/llvm-project/Debug.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/Debug.cpp
@@ -0,0 +1,157 @@
+//===-- Debug.cpp - An easy way to add debug output to your code ----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a handy way of adding debugging information to your
+// code, without it being enabled all of the time, and without having to add
+// command line options to enable it.
+//
+// In particular, just wrap your code with the LLVM_DEBUG() macro, and it will
+// be enabled automatically if you specify '-debug' on the command-line.
+// Alternatively, you can also use the SET_DEBUG_TYPE("foo") macro to specify
+// that your debug code belongs to class "foo".  Then, on the command line, you
+// can specify '-debug-only=foo' to enable JUST the debug information for the
+// foo class.
+//
+// When compiling without assertions, the -debug-* options and all code in
+// LLVM_DEBUG() statements disappears, so it does not affect the runtime of the
+// code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/circular_raw_ostream.h"
+#include "llvm/Support/raw_ostream.h"
+
+#undef isCurrentDebugType
+#undef setCurrentDebugType
+#undef setCurrentDebugTypes
+
+using namespace llvm;
+
+// Even though LLVM might be built with NDEBUG, define symbols that the code
+// built without NDEBUG can depend on via the llvm/Support/Debug.h header.
+namespace llvm {
+/// Exported boolean set by the -debug option.
+bool DebugFlag = false;
+
+#if 0 // XXX BINARYEN
+static ManagedStatic<std::vector<std::string>> CurrentDebugType;
+#endif
+
+/// Return true if the specified string is the debug type
+/// specified on the command line, or if none was specified on the command line
+/// with the -debug-only=X option.
+bool isCurrentDebugType(const char *DebugType) {
+  llvm_unreachable("debug type");
+}
+
+/// Set the current debug type, as if the -debug-only=X
+/// option were specified.  Note that DebugFlag also needs to be set to true for
+/// debug output to be produced.
+///
+void setCurrentDebugTypes(const char **Types, unsigned Count);
+
+void setCurrentDebugType(const char *Type) {
+  setCurrentDebugTypes(&Type, 1);
+}
+
+void setCurrentDebugTypes(const char **Types, unsigned Count) {
+  llvm_unreachable("set debug type");
+}
+} // namespace llvm
+
+// All Debug.h functionality is a no-op in NDEBUG mode.
+#if 0 // XXX BINARYEN ndef NDEBUG
+
+// -debug - Command line option to enable the DEBUG statements in the passes.
+// This flag may only be enabled in debug builds.
+static cl::opt<bool, true>
+Debug("debug", cl::desc("Enable debug output"), cl::Hidden,
+      cl::location(DebugFlag));
+
+// -debug-buffer-size - Buffer the last N characters of debug output
+//until program termination.
+static cl::opt<unsigned>
+DebugBufferSize("debug-buffer-size",
+                cl::desc("Buffer the last N characters of debug output "
+                         "until program termination. "
+                         "[default 0 -- immediate print-out]"),
+                cl::Hidden,
+                cl::init(0));
+
+namespace {
+
+struct DebugOnlyOpt {
+  void operator=(const std::string &Val) const {
+    if (Val.empty())
+      return;
+    DebugFlag = true;
+    SmallVector<StringRef,8> dbgTypes;
+    StringRef(Val).split(dbgTypes, ',', -1, false);
+    for (auto dbgType : dbgTypes)
+      CurrentDebugType->push_back(dbgType);
+  }
+};
+
+}
+
+static DebugOnlyOpt DebugOnlyOptLoc;
+
+static cl::opt<DebugOnlyOpt, true, cl::parser<std::string> >
+DebugOnly("debug-only", cl::desc("Enable a specific type of debug output (comma separated list of types)"),
+          cl::Hidden, cl::ZeroOrMore, cl::value_desc("debug string"),
+          cl::location(DebugOnlyOptLoc), cl::ValueRequired);
+// Signal handlers - dump debug output on termination.
+static void debug_user_sig_handler(void *Cookie) {
+  // This is a bit sneaky.  Since this is under #ifndef NDEBUG, we
+  // know that debug mode is enabled and dbgs() really is a
+  // circular_raw_ostream.  If NDEBUG is defined, then dbgs() ==
+  // errs() but this will never be invoked.
+  llvm::circular_raw_ostream &dbgout =
+      static_cast<circular_raw_ostream &>(llvm::dbgs());
+  dbgout.flushBufferWithBanner();
+}
+
+/// dbgs - Return a circular-buffered debug stream.
+raw_ostream &llvm::dbgs() {
+  // Do one-time initialization in a thread-safe way.
+  static struct dbgstream {
+    circular_raw_ostream strm;
+
+    dbgstream() :
+        strm(errs(), "*** Debug Log Output ***\n",
+             (!EnableDebugBuffering || !DebugFlag) ? 0 : DebugBufferSize) {
+      if (EnableDebugBuffering && DebugFlag && DebugBufferSize != 0)
+        // TODO: Add a handler for SIGUSER1-type signals so the user can
+        // force a debug dump.
+        sys::AddSignalHandler(&debug_user_sig_handler, nullptr);
+      // Otherwise we've already set the debug stream buffer size to
+      // zero, disabling buffering so it will output directly to errs().
+    }
+  } thestrm;
+
+  return thestrm.strm;
+}
+
+#else
+// Avoid "has no symbols" warning.
+namespace llvm {
+  /// dbgs - Return errs().
+  raw_ostream &dbgs() {
+    return errs();
+  }
+}
+
+#endif
+
+/// EnableDebugBuffering - Turn on signal handler installation.
+///
+bool llvm::EnableDebugBuffering = false;
diff --git a/binaryen/third_party/llvm-project/Dwarf.cpp b/binaryen/third_party/llvm-project/Dwarf.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/Dwarf.cpp
@@ -0,0 +1,759 @@
+//===-- llvm/BinaryFormat/Dwarf.cpp - Dwarf Framework ------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains support for generic dwarf information.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+using namespace dwarf;
+
+StringRef llvm::dwarf::TagString(unsigned Tag) {
+  switch (Tag) {
+  default:
+    return StringRef();
+#define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR, KIND)                         \
+  case DW_TAG_##NAME:                                                          \
+    return "DW_TAG_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+unsigned llvm::dwarf::getTag(StringRef TagString) {
+  return StringSwitch<unsigned>(TagString)
+#define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR, KIND)                         \
+  .Case("DW_TAG_" #NAME, DW_TAG_##NAME)
+#include "llvm/BinaryFormat/Dwarf.def"
+      .Default(DW_TAG_invalid);
+}
+
+unsigned llvm::dwarf::TagVersion(dwarf::Tag Tag) {
+  switch (Tag) {
+  default:
+    return 0;
+#define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR, KIND)                         \
+  case DW_TAG_##NAME:                                                          \
+    return VERSION;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+unsigned llvm::dwarf::TagVendor(dwarf::Tag Tag) {
+  switch (Tag) {
+  default:
+    return 0;
+#define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR, KIND)                         \
+  case DW_TAG_##NAME:                                                          \
+    return DWARF_VENDOR_##VENDOR;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+StringRef llvm::dwarf::ChildrenString(unsigned Children) {
+  switch (Children) {
+  case DW_CHILDREN_no:
+    return "DW_CHILDREN_no";
+  case DW_CHILDREN_yes:
+    return "DW_CHILDREN_yes";
+  }
+  return StringRef();
+}
+
+StringRef llvm::dwarf::AttributeString(unsigned Attribute) {
+  switch (Attribute) {
+  default:
+    return StringRef();
+#define HANDLE_DW_AT(ID, NAME, VERSION, VENDOR)                                \
+  case DW_AT_##NAME:                                                           \
+    return "DW_AT_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+unsigned llvm::dwarf::AttributeVersion(dwarf::Attribute Attribute) {
+  switch (Attribute) {
+  default:
+    return 0;
+#define HANDLE_DW_AT(ID, NAME, VERSION, VENDOR)                                \
+  case DW_AT_##NAME:                                                           \
+    return VERSION;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+unsigned llvm::dwarf::AttributeVendor(dwarf::Attribute Attribute) {
+  switch (Attribute) {
+  default:
+    return 0;
+#define HANDLE_DW_AT(ID, NAME, VERSION, VENDOR)                                \
+  case DW_AT_##NAME:                                                           \
+    return DWARF_VENDOR_##VENDOR;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+StringRef llvm::dwarf::FormEncodingString(unsigned Encoding) {
+  switch (Encoding) {
+  default:
+    return StringRef();
+#define HANDLE_DW_FORM(ID, NAME, VERSION, VENDOR)                              \
+  case DW_FORM_##NAME:                                                         \
+    return "DW_FORM_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+unsigned llvm::dwarf::FormVersion(dwarf::Form Form) {
+  switch (Form) {
+  default:
+    return 0;
+#define HANDLE_DW_FORM(ID, NAME, VERSION, VENDOR)                              \
+  case DW_FORM_##NAME:                                                         \
+    return VERSION;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+unsigned llvm::dwarf::FormVendor(dwarf::Form Form) {
+  switch (Form) {
+  default:
+    return 0;
+#define HANDLE_DW_FORM(ID, NAME, VERSION, VENDOR)                              \
+  case DW_FORM_##NAME:                                                         \
+    return DWARF_VENDOR_##VENDOR;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+StringRef llvm::dwarf::OperationEncodingString(unsigned Encoding) {
+  switch (Encoding) {
+  default:
+    return StringRef();
+#define HANDLE_DW_OP(ID, NAME, VERSION, VENDOR)                                \
+  case DW_OP_##NAME:                                                           \
+    return "DW_OP_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+  case DW_OP_LLVM_convert:
+    return "DW_OP_LLVM_convert";
+  case DW_OP_LLVM_fragment:
+    return "DW_OP_LLVM_fragment";
+  case DW_OP_LLVM_tag_offset:
+    return "DW_OP_LLVM_tag_offset";
+  case DW_OP_LLVM_entry_value:
+    return "DW_OP_LLVM_entry_value";
+  }
+}
+
+unsigned llvm::dwarf::getOperationEncoding(StringRef OperationEncodingString) {
+  return StringSwitch<unsigned>(OperationEncodingString)
+#define HANDLE_DW_OP(ID, NAME, VERSION, VENDOR)                                \
+  .Case("DW_OP_" #NAME, DW_OP_##NAME)
+#include "llvm/BinaryFormat/Dwarf.def"
+      .Case("DW_OP_LLVM_convert", DW_OP_LLVM_convert)
+      .Case("DW_OP_LLVM_fragment", DW_OP_LLVM_fragment)
+      .Case("DW_OP_LLVM_tag_offset", DW_OP_LLVM_tag_offset)
+      .Case("DW_OP_LLVM_entry_value", DW_OP_LLVM_entry_value)
+      .Default(0);
+}
+
+unsigned llvm::dwarf::OperationVersion(dwarf::LocationAtom Op) {
+  switch (Op) {
+  default:
+    return 0;
+#define HANDLE_DW_OP(ID, NAME, VERSION, VENDOR)                                \
+  case DW_OP_##NAME:                                                           \
+    return VERSION;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+unsigned llvm::dwarf::OperationVendor(dwarf::LocationAtom Op) {
+  switch (Op) {
+  default:
+    return 0;
+#define HANDLE_DW_OP(ID, NAME, VERSION, VENDOR)                                \
+  case DW_OP_##NAME:                                                           \
+    return DWARF_VENDOR_##VENDOR;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+StringRef llvm::dwarf::AttributeEncodingString(unsigned Encoding) {
+  switch (Encoding) {
+  default:
+    return StringRef();
+#define HANDLE_DW_ATE(ID, NAME, VERSION, VENDOR)                               \
+  case DW_ATE_##NAME:                                                          \
+    return "DW_ATE_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+unsigned llvm::dwarf::getAttributeEncoding(StringRef EncodingString) {
+  return StringSwitch<unsigned>(EncodingString)
+#define HANDLE_DW_ATE(ID, NAME, VERSION, VENDOR)                               \
+  .Case("DW_ATE_" #NAME, DW_ATE_##NAME)
+#include "llvm/BinaryFormat/Dwarf.def"
+      .Default(0);
+}
+
+unsigned llvm::dwarf::AttributeEncodingVersion(dwarf::TypeKind ATE) {
+  switch (ATE) {
+  default:
+    return 0;
+#define HANDLE_DW_ATE(ID, NAME, VERSION, VENDOR)                               \
+  case DW_ATE_##NAME:                                                          \
+    return VERSION;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+unsigned llvm::dwarf::AttributeEncodingVendor(dwarf::TypeKind ATE) {
+  switch (ATE) {
+  default:
+    return 0;
+#define HANDLE_DW_ATE(ID, NAME, VERSION, VENDOR)                               \
+  case DW_ATE_##NAME:                                                          \
+    return DWARF_VENDOR_##VENDOR;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+StringRef llvm::dwarf::DecimalSignString(unsigned Sign) {
+  switch (Sign) {
+  case DW_DS_unsigned:
+    return "DW_DS_unsigned";
+  case DW_DS_leading_overpunch:
+    return "DW_DS_leading_overpunch";
+  case DW_DS_trailing_overpunch:
+    return "DW_DS_trailing_overpunch";
+  case DW_DS_leading_separate:
+    return "DW_DS_leading_separate";
+  case DW_DS_trailing_separate:
+    return "DW_DS_trailing_separate";
+  }
+  return StringRef();
+}
+
+StringRef llvm::dwarf::EndianityString(unsigned Endian) {
+  switch (Endian) {
+  case DW_END_default:
+    return "DW_END_default";
+  case DW_END_big:
+    return "DW_END_big";
+  case DW_END_little:
+    return "DW_END_little";
+  case DW_END_lo_user:
+    return "DW_END_lo_user";
+  case DW_END_hi_user:
+    return "DW_END_hi_user";
+  }
+  return StringRef();
+}
+
+StringRef llvm::dwarf::AccessibilityString(unsigned Access) {
+  switch (Access) {
+  // Accessibility codes
+  case DW_ACCESS_public:
+    return "DW_ACCESS_public";
+  case DW_ACCESS_protected:
+    return "DW_ACCESS_protected";
+  case DW_ACCESS_private:
+    return "DW_ACCESS_private";
+  }
+  return StringRef();
+}
+
+StringRef llvm::dwarf::DefaultedMemberString(unsigned DefaultedEncodings) {
+  switch (DefaultedEncodings) {
+  // Defaulted Member Encodings codes
+  case DW_DEFAULTED_no:
+    return "DW_DEFAULTED_no";
+  case DW_DEFAULTED_in_class:
+    return "DW_DEFAULTED_in_class";
+  case DW_DEFAULTED_out_of_class:
+    return "DW_DEFAULTED_out_of_class";
+  }
+  return StringRef();
+}
+
+StringRef llvm::dwarf::VisibilityString(unsigned Visibility) {
+  switch (Visibility) {
+  case DW_VIS_local:
+    return "DW_VIS_local";
+  case DW_VIS_exported:
+    return "DW_VIS_exported";
+  case DW_VIS_qualified:
+    return "DW_VIS_qualified";
+  }
+  return StringRef();
+}
+
+StringRef llvm::dwarf::VirtualityString(unsigned Virtuality) {
+  switch (Virtuality) {
+  default:
+    return StringRef();
+#define HANDLE_DW_VIRTUALITY(ID, NAME)                                         \
+  case DW_VIRTUALITY_##NAME:                                                   \
+    return "DW_VIRTUALITY_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+unsigned llvm::dwarf::getVirtuality(StringRef VirtualityString) {
+  return StringSwitch<unsigned>(VirtualityString)
+#define HANDLE_DW_VIRTUALITY(ID, NAME)                                         \
+  .Case("DW_VIRTUALITY_" #NAME, DW_VIRTUALITY_##NAME)
+#include "llvm/BinaryFormat/Dwarf.def"
+      .Default(DW_VIRTUALITY_invalid);
+}
+
+StringRef llvm::dwarf::LanguageString(unsigned Language) {
+  switch (Language) {
+  default:
+    return StringRef();
+#define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR)                 \
+  case DW_LANG_##NAME:                                                         \
+    return "DW_LANG_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+unsigned llvm::dwarf::getLanguage(StringRef LanguageString) {
+  return StringSwitch<unsigned>(LanguageString)
+#define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR)                 \
+  .Case("DW_LANG_" #NAME, DW_LANG_##NAME)
+#include "llvm/BinaryFormat/Dwarf.def"
+      .Default(0);
+}
+
+unsigned llvm::dwarf::LanguageVersion(dwarf::SourceLanguage Lang) {
+  switch (Lang) {
+  default:
+    return 0;
+#define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR)                 \
+  case DW_LANG_##NAME:                                                         \
+    return VERSION;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+unsigned llvm::dwarf::LanguageVendor(dwarf::SourceLanguage Lang) {
+  switch (Lang) {
+  default:
+    return 0;
+#define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR)                 \
+  case DW_LANG_##NAME:                                                         \
+    return DWARF_VENDOR_##VENDOR;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+Optional<unsigned> llvm::dwarf::LanguageLowerBound(dwarf::SourceLanguage Lang) {
+  switch (Lang) {
+  default:
+    return None;
+#define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR)                 \
+  case DW_LANG_##NAME:                                                         \
+    return LOWER_BOUND;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+StringRef llvm::dwarf::CaseString(unsigned Case) {
+  switch (Case) {
+  case DW_ID_case_sensitive:
+    return "DW_ID_case_sensitive";
+  case DW_ID_up_case:
+    return "DW_ID_up_case";
+  case DW_ID_down_case:
+    return "DW_ID_down_case";
+  case DW_ID_case_insensitive:
+    return "DW_ID_case_insensitive";
+  }
+  return StringRef();
+}
+
+StringRef llvm::dwarf::ConventionString(unsigned CC) {
+  switch (CC) {
+  default:
+    return StringRef();
+#define HANDLE_DW_CC(ID, NAME)                                                 \
+  case DW_CC_##NAME:                                                           \
+    return "DW_CC_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+unsigned llvm::dwarf::getCallingConvention(StringRef CCString) {
+  return StringSwitch<unsigned>(CCString)
+#define HANDLE_DW_CC(ID, NAME) .Case("DW_CC_" #NAME, DW_CC_##NAME)
+#include "llvm/BinaryFormat/Dwarf.def"
+      .Default(0);
+}
+
+StringRef llvm::dwarf::InlineCodeString(unsigned Code) {
+  switch (Code) {
+  case DW_INL_not_inlined:
+    return "DW_INL_not_inlined";
+  case DW_INL_inlined:
+    return "DW_INL_inlined";
+  case DW_INL_declared_not_inlined:
+    return "DW_INL_declared_not_inlined";
+  case DW_INL_declared_inlined:
+    return "DW_INL_declared_inlined";
+  }
+  return StringRef();
+}
+
+StringRef llvm::dwarf::ArrayOrderString(unsigned Order) {
+  switch (Order) {
+  case DW_ORD_row_major:
+    return "DW_ORD_row_major";
+  case DW_ORD_col_major:
+    return "DW_ORD_col_major";
+  }
+  return StringRef();
+}
+
+StringRef llvm::dwarf::LNStandardString(unsigned Standard) {
+  switch (Standard) {
+  default:
+    return StringRef();
+#define HANDLE_DW_LNS(ID, NAME)                                                \
+  case DW_LNS_##NAME:                                                          \
+    return "DW_LNS_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+StringRef llvm::dwarf::LNExtendedString(unsigned Encoding) {
+  switch (Encoding) {
+  default:
+    return StringRef();
+#define HANDLE_DW_LNE(ID, NAME)                                                \
+  case DW_LNE_##NAME:                                                          \
+    return "DW_LNE_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+StringRef llvm::dwarf::MacinfoString(unsigned Encoding) {
+  switch (Encoding) {
+  // Macinfo Type Encodings
+  case DW_MACINFO_define:
+    return "DW_MACINFO_define";
+  case DW_MACINFO_undef:
+    return "DW_MACINFO_undef";
+  case DW_MACINFO_start_file:
+    return "DW_MACINFO_start_file";
+  case DW_MACINFO_end_file:
+    return "DW_MACINFO_end_file";
+  case DW_MACINFO_vendor_ext:
+    return "DW_MACINFO_vendor_ext";
+  case DW_MACINFO_invalid:
+    return "DW_MACINFO_invalid";
+  }
+  return StringRef();
+}
+
+unsigned llvm::dwarf::getMacinfo(StringRef MacinfoString) {
+  return StringSwitch<unsigned>(MacinfoString)
+      .Case("DW_MACINFO_define", DW_MACINFO_define)
+      .Case("DW_MACINFO_undef", DW_MACINFO_undef)
+      .Case("DW_MACINFO_start_file", DW_MACINFO_start_file)
+      .Case("DW_MACINFO_end_file", DW_MACINFO_end_file)
+      .Case("DW_MACINFO_vendor_ext", DW_MACINFO_vendor_ext)
+      .Default(DW_MACINFO_invalid);
+}
+
+StringRef llvm::dwarf::RangeListEncodingString(unsigned Encoding) {
+  switch (Encoding) {
+  default:
+    return StringRef();
+#define HANDLE_DW_RLE(ID, NAME)                                                \
+  case DW_RLE_##NAME:                                                          \
+    return "DW_RLE_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+StringRef llvm::dwarf::LocListEncodingString(unsigned Encoding) {
+  switch (Encoding) {
+  default:
+    return StringRef();
+#define HANDLE_DW_LLE(ID, NAME)                                                \
+  case DW_LLE_##NAME:                                                          \
+    return "DW_LLE_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+StringRef llvm::dwarf::CallFrameString(unsigned Encoding,
+    Triple::ArchType Arch) {
+  assert(Arch != llvm::Triple::ArchType::UnknownArch);
+#define SELECT_AARCH64 (Arch == llvm::Triple::aarch64_be || Arch == llvm::Triple::aarch64)
+#define SELECT_MIPS64 Arch == llvm::Triple::mips64
+#define SELECT_SPARC (Arch == llvm::Triple::sparc || Arch == llvm::Triple::sparcv9)
+#define SELECT_X86 (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64)
+#define HANDLE_DW_CFA(ID, NAME)
+#define HANDLE_DW_CFA_PRED(ID, NAME, PRED) \
+  if (ID == Encoding && PRED) \
+    return "DW_CFA_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+
+  switch (Encoding) {
+  default:
+    return StringRef();
+#define HANDLE_DW_CFA_PRED(ID, NAME, PRED)
+#define HANDLE_DW_CFA(ID, NAME)                                                \
+  case DW_CFA_##NAME:                                                          \
+    return "DW_CFA_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+
+#undef SELECT_X86
+#undef SELECT_SPARC
+#undef SELECT_MIPS64
+#undef SELECT_AARCH64
+  }
+}
+
+StringRef llvm::dwarf::ApplePropertyString(unsigned Prop) {
+  switch (Prop) {
+  default:
+    return StringRef();
+#define HANDLE_DW_APPLE_PROPERTY(ID, NAME)                                     \
+  case DW_APPLE_PROPERTY_##NAME:                                               \
+    return "DW_APPLE_PROPERTY_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+StringRef llvm::dwarf::UnitTypeString(unsigned UT) {
+  switch (UT) {
+  default:
+    return StringRef();
+#define HANDLE_DW_UT(ID, NAME)                                                 \
+  case DW_UT_##NAME:                                                           \
+    return "DW_UT_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+StringRef llvm::dwarf::AtomTypeString(unsigned AT) {
+  switch (AT) {
+  case dwarf::DW_ATOM_null:
+    return "DW_ATOM_null";
+  case dwarf::DW_ATOM_die_offset:
+    return "DW_ATOM_die_offset";
+  case DW_ATOM_cu_offset:
+    return "DW_ATOM_cu_offset";
+  case DW_ATOM_die_tag:
+    return "DW_ATOM_die_tag";
+  case DW_ATOM_type_flags:
+  case DW_ATOM_type_type_flags:
+    return "DW_ATOM_type_flags";
+  case DW_ATOM_qual_name_hash:
+    return "DW_ATOM_qual_name_hash";
+  }
+  return StringRef();
+}
+
+StringRef llvm::dwarf::GDBIndexEntryKindString(GDBIndexEntryKind Kind) {
+  switch (Kind) {
+  case GIEK_NONE:
+    return "NONE";
+  case GIEK_TYPE:
+    return "TYPE";
+  case GIEK_VARIABLE:
+    return "VARIABLE";
+  case GIEK_FUNCTION:
+    return "FUNCTION";
+  case GIEK_OTHER:
+    return "OTHER";
+  case GIEK_UNUSED5:
+    return "UNUSED5";
+  case GIEK_UNUSED6:
+    return "UNUSED6";
+  case GIEK_UNUSED7:
+    return "UNUSED7";
+  }
+  llvm_unreachable("Unknown GDBIndexEntryKind value");
+}
+
+StringRef
+llvm::dwarf::GDBIndexEntryLinkageString(GDBIndexEntryLinkage Linkage) {
+  switch (Linkage) {
+  case GIEL_EXTERNAL:
+    return "EXTERNAL";
+  case GIEL_STATIC:
+    return "STATIC";
+  }
+  llvm_unreachable("Unknown GDBIndexEntryLinkage value");
+}
+
+StringRef llvm::dwarf::AttributeValueString(uint16_t Attr, unsigned Val) {
+  switch (Attr) {
+  case DW_AT_accessibility:
+    return AccessibilityString(Val);
+  case DW_AT_virtuality:
+    return VirtualityString(Val);
+  case DW_AT_language:
+    return LanguageString(Val);
+  case DW_AT_encoding:
+    return AttributeEncodingString(Val);
+  case DW_AT_decimal_sign:
+    return DecimalSignString(Val);
+  case DW_AT_endianity:
+    return EndianityString(Val);
+  case DW_AT_visibility:
+    return VisibilityString(Val);
+  case DW_AT_identifier_case:
+    return CaseString(Val);
+  case DW_AT_calling_convention:
+    return ConventionString(Val);
+  case DW_AT_inline:
+    return InlineCodeString(Val);
+  case DW_AT_ordering:
+    return ArrayOrderString(Val);
+  case DW_AT_APPLE_runtime_class:
+    return LanguageString(Val);
+  case DW_AT_defaulted:
+    return DefaultedMemberString(Val);
+  }
+
+  return StringRef();
+}
+
+StringRef llvm::dwarf::AtomValueString(uint16_t Atom, unsigned Val) {
+  switch (Atom) {
+  case DW_ATOM_null:
+    return "NULL";
+  case DW_ATOM_die_tag:
+    return TagString(Val);
+  }
+
+  return StringRef();
+}
+
+StringRef llvm::dwarf::IndexString(unsigned Idx) {
+  switch (Idx) {
+  default:
+    return StringRef();
+#define HANDLE_DW_IDX(ID, NAME)                                                \
+  case DW_IDX_##NAME:                                                          \
+    return "DW_IDX_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+Optional<uint8_t> llvm::dwarf::getFixedFormByteSize(dwarf::Form Form,
+                                                    FormParams Params) {
+  switch (Form) {
+  case DW_FORM_addr:
+    if (Params)
+      return Params.AddrSize;
+    return None;
+
+  case DW_FORM_block:          // ULEB128 length L followed by L bytes.
+  case DW_FORM_block1:         // 1 byte length L followed by L bytes.
+  case DW_FORM_block2:         // 2 byte length L followed by L bytes.
+  case DW_FORM_block4:         // 4 byte length L followed by L bytes.
+  case DW_FORM_string:         // C-string with null terminator.
+  case DW_FORM_sdata:          // SLEB128.
+  case DW_FORM_udata:          // ULEB128.
+  case DW_FORM_ref_udata:      // ULEB128.
+  case DW_FORM_indirect:       // ULEB128.
+  case DW_FORM_exprloc:        // ULEB128 length L followed by L bytes.
+  case DW_FORM_strx:           // ULEB128.
+  case DW_FORM_addrx:          // ULEB128.
+  case DW_FORM_loclistx:       // ULEB128.
+  case DW_FORM_rnglistx:       // ULEB128.
+  case DW_FORM_GNU_addr_index: // ULEB128.
+  case DW_FORM_GNU_str_index:  // ULEB128.
+    return None;
+
+  case DW_FORM_ref_addr:
+    if (Params)
+      return Params.getRefAddrByteSize();
+    return None;
+
+  case DW_FORM_flag:
+  case DW_FORM_data1:
+  case DW_FORM_ref1:
+  case DW_FORM_strx1:
+  case DW_FORM_addrx1:
+    return 1;
+
+  case DW_FORM_data2:
+  case DW_FORM_ref2:
+  case DW_FORM_strx2:
+  case DW_FORM_addrx2:
+    return 2;
+
+  case DW_FORM_strx3:
+    return 3;
+
+  case DW_FORM_data4:
+  case DW_FORM_ref4:
+  case DW_FORM_ref_sup4:
+  case DW_FORM_strx4:
+  case DW_FORM_addrx4:
+    return 4;
+
+  case DW_FORM_strp:
+  case DW_FORM_GNU_ref_alt:
+  case DW_FORM_GNU_strp_alt:
+  case DW_FORM_line_strp:
+  case DW_FORM_sec_offset:
+  case DW_FORM_strp_sup:
+    if (Params)
+      return Params.getDwarfOffsetByteSize();
+    return None;
+
+  case DW_FORM_data8:
+  case DW_FORM_ref8:
+  case DW_FORM_ref_sig8:
+  case DW_FORM_ref_sup8:
+    return 8;
+
+  case DW_FORM_flag_present:
+    return 0;
+
+  case DW_FORM_data16:
+    return 16;
+
+  case DW_FORM_implicit_const:
+    // The implicit value is stored in the abbreviation as a SLEB128, and
+    // there no data in debug info.
+    return 0;
+
+  default:
+    break;
+  }
+  return None;
+}
+
+bool llvm::dwarf::isValidFormForVersion(Form F, unsigned Version,
+                                        bool ExtensionsOk) {
+  if (FormVendor(F) == DWARF_VENDOR_DWARF) {
+    unsigned FV = FormVersion(F);
+    return FV > 0 && FV <= Version;
+  }
+  return ExtensionsOk;
+}
+
+constexpr char llvm::dwarf::EnumTraits<Attribute>::Type[];
+constexpr char llvm::dwarf::EnumTraits<Form>::Type[];
+constexpr char llvm::dwarf::EnumTraits<Index>::Type[];
+constexpr char llvm::dwarf::EnumTraits<Tag>::Type[];
diff --git a/binaryen/third_party/llvm-project/Error.cpp b/binaryen/third_party/llvm-project/Error.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/Error.cpp
@@ -0,0 +1,168 @@
+//===----- lib/Support/Error.cpp - Error and associated utilities ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Error.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+#include <system_error>
+
+using namespace llvm;
+
+namespace {
+
+  enum class ErrorErrorCode : int {
+    MultipleErrors = 1,
+    FileError,
+    InconvertibleError
+  };
+
+  // FIXME: This class is only here to support the transition to llvm::Error. It
+  // will be removed once this transition is complete. Clients should prefer to
+  // deal with the Error value directly, rather than converting to error_code.
+  class ErrorErrorCategory : public std::error_category {
+  public:
+    const char *name() const noexcept override { return "Error"; }
+
+    std::string message(int condition) const override {
+      switch (static_cast<ErrorErrorCode>(condition)) {
+      case ErrorErrorCode::MultipleErrors:
+        return "Multiple errors";
+      case ErrorErrorCode::InconvertibleError:
+        return "Inconvertible error value. An error has occurred that could "
+               "not be converted to a known std::error_code. Please file a "
+               "bug.";
+      case ErrorErrorCode::FileError:
+          return "A file error occurred.";
+      }
+      llvm_unreachable("Unhandled error code");
+    }
+  };
+
+}
+
+#if 0 // XXX BINARYEN
+static ManagedStatic<ErrorErrorCategory> ErrorErrorCat;
+#endif
+
+namespace llvm {
+
+void ErrorInfoBase::anchor() {}
+char ErrorInfoBase::ID = 0;
+char ErrorList::ID = 0;
+void ECError::anchor() {}
+char ECError::ID = 0;
+char StringError::ID = 0;
+char FileError::ID = 0;
+
+void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner) {
+  if (!E)
+    return;
+  OS << ErrorBanner;
+  handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
+    EI.log(OS);
+    OS << "\n";
+  });
+}
+
+
+std::error_code ErrorList::convertToErrorCode() const {
+  llvm_unreachable("convert error code");
+}
+
+std::error_code inconvertibleErrorCode() {
+  llvm_unreachable("inconvertible error code");
+}
+
+std::error_code FileError::convertToErrorCode() const {
+  llvm_unreachable("(file) convert error code");
+}
+
+Error errorCodeToError(std::error_code EC) {
+  if (!EC)
+    return Error::success();
+  return Error(std::make_unique<ECError>(ECError(EC)));
+}
+
+std::error_code errorToErrorCode(Error Err) {
+  std::error_code EC;
+  handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
+    EC = EI.convertToErrorCode();
+  });
+  if (EC == inconvertibleErrorCode())
+    report_fatal_error(EC.message());
+  return EC;
+}
+
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+void Error::fatalUncheckedError() const {
+  dbgs() << "Program aborted due to an unhandled Error:\n";
+  if (getPtr())
+    getPtr()->log(dbgs());
+  else
+    dbgs() << "Error value was Success. (Note: Success values must still be "
+              "checked prior to being destroyed).\n";
+  abort();
+}
+#endif
+
+StringError::StringError(std::error_code EC, const Twine &S)
+    : Msg(S.str()), EC(EC) {}
+
+StringError::StringError(const Twine &S, std::error_code EC)
+    : Msg(S.str()), EC(EC), PrintMsgOnly(true) {}
+
+void StringError::log(raw_ostream &OS) const {
+  if (PrintMsgOnly) {
+    OS << Msg;
+  } else {
+    OS << EC.message();
+    if (!Msg.empty())
+      OS << (" " + Msg);
+  }
+}
+
+std::error_code StringError::convertToErrorCode() const {
+  return EC;
+}
+
+Error createStringError(std::error_code EC, char const *Msg) {
+  return make_error<StringError>(Msg, EC);
+}
+
+void report_fatal_error(Error Err, bool GenCrashDiag) {
+  assert(Err && "report_fatal_error called with success value");
+  std::string ErrMsg;
+  {
+    raw_string_ostream ErrStream(ErrMsg);
+    logAllUnhandledErrors(std::move(Err), ErrStream);
+  }
+  report_fatal_error(ErrMsg);
+}
+
+} // end namespace llvm
+
+LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err) {
+  return reinterpret_cast<ErrorInfoBase *>(Err)->dynamicClassID();
+}
+
+void LLVMConsumeError(LLVMErrorRef Err) { consumeError(unwrap(Err)); }
+
+char *LLVMGetErrorMessage(LLVMErrorRef Err) {
+  std::string Tmp = toString(unwrap(Err));
+  char *ErrMsg = new char[Tmp.size() + 1];
+  memcpy(ErrMsg, Tmp.data(), Tmp.size());
+  ErrMsg[Tmp.size()] = '\0';
+  return ErrMsg;
+}
+
+void LLVMDisposeErrorMessage(char *ErrMsg) { delete[] ErrMsg; }
+
+LLVMErrorTypeId LLVMGetStringErrorTypeId() {
+  return reinterpret_cast<void *>(&StringError::ID);
+}
diff --git a/binaryen/third_party/llvm-project/Error.h b/binaryen/third_party/llvm-project/Error.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/Error.h
@@ -0,0 +1,53 @@
+//===- Error.h - system_error extensions for obj2yaml -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_OBJ2YAML_ERROR_H
+#define LLVM_TOOLS_OBJ2YAML_ERROR_H
+
+#include "llvm/Support/Error.h"
+
+#include <system_error>
+
+namespace llvm {
+const std::error_category &obj2yaml_category();
+
+enum class obj2yaml_error {
+  success = 0,
+  file_not_found,
+  unrecognized_file_format,
+  unsupported_obj_file_format,
+  not_implemented
+};
+
+inline std::error_code make_error_code(obj2yaml_error e) {
+  return std::error_code(static_cast<int>(e), obj2yaml_category());
+}
+
+class Obj2YamlError : public ErrorInfo<Obj2YamlError> {
+public:
+  static char ID;
+  Obj2YamlError(obj2yaml_error C) : Code(C) {}
+  Obj2YamlError(std::string ErrMsg) : ErrMsg(std::move(ErrMsg)) {}
+  Obj2YamlError(obj2yaml_error C, std::string ErrMsg)
+      : ErrMsg(std::move(ErrMsg)), Code(C) {}
+  void log(raw_ostream &OS) const override;
+  const std::string &getErrorMessage() const { return ErrMsg; }
+  std::error_code convertToErrorCode() const override;
+
+private:
+  std::string ErrMsg;
+  obj2yaml_error Code = obj2yaml_error::success;
+};
+
+} // namespace llvm
+
+namespace std {
+template <> struct is_error_code_enum<llvm::obj2yaml_error> : std::true_type {};
+}
+
+#endif
diff --git a/binaryen/third_party/llvm-project/ErrorHandling.cpp b/binaryen/third_party/llvm-project/ErrorHandling.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/ErrorHandling.cpp
@@ -0,0 +1,305 @@
+//===- lib/Support/ErrorHandling.cpp - Callbacks for errors ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines an API used to indicate fatal error conditions.  Non-fatal
+// errors (most of them) should be handled through LLVMContext.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm-c/ErrorHandling.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/WindowsError.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdlib>
+#include <mutex>
+#include <new>
+#include <iostream> // XXX BINARYEN
+
+#if defined(HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+#if defined(_MSC_VER)
+# include <io.h>
+# include <fcntl.h>
+#endif
+
+using namespace llvm;
+
+static fatal_error_handler_t ErrorHandler = nullptr;
+static void *ErrorHandlerUserData = nullptr;
+
+static fatal_error_handler_t BadAllocErrorHandler = nullptr;
+static void *BadAllocErrorHandlerUserData = nullptr;
+
+#if LLVM_ENABLE_THREADS == 1
+// Mutexes to synchronize installing error handlers and calling error handlers.
+// Do not use ManagedStatic, or that may allocate memory while attempting to
+// report an OOM.
+//
+// This usage of std::mutex has to be conditionalized behind ifdefs because
+// of this script:
+//   compiler-rt/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh
+// That script attempts to statically link the LLVM symbolizer library with the
+// STL and hide all of its symbols with 'opt -internalize'. To reduce size, it
+// cuts out the threading portions of the hermetic copy of libc++ that it
+// builds. We can remove these ifdefs if that script goes away.
+static std::mutex ErrorHandlerMutex;
+static std::mutex BadAllocErrorHandlerMutex;
+#endif
+
+void llvm::install_fatal_error_handler(fatal_error_handler_t handler,
+                                       void *user_data) {
+#if LLVM_ENABLE_THREADS == 1
+  std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
+#endif
+  assert(!ErrorHandler && "Error handler already registered!\n");
+  ErrorHandler = handler;
+  ErrorHandlerUserData = user_data;
+}
+
+void llvm::remove_fatal_error_handler() {
+#if LLVM_ENABLE_THREADS == 1
+  std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
+#endif
+  ErrorHandler = nullptr;
+  ErrorHandlerUserData = nullptr;
+}
+
+void llvm::report_fatal_error(const char *Reason, bool GenCrashDiag) {
+  report_fatal_error(Twine(Reason), GenCrashDiag);
+}
+
+void llvm::report_fatal_error(const std::string &Reason, bool GenCrashDiag) {
+  report_fatal_error(Twine(Reason), GenCrashDiag);
+}
+
+void llvm::report_fatal_error(StringRef Reason, bool GenCrashDiag) {
+  report_fatal_error(Twine(Reason), GenCrashDiag);
+}
+
+void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
+  Reason.dump();
+#if 0 // XXX BINARYEN
+  llvm::fatal_error_handler_t handler = nullptr;
+  void* handlerData = nullptr;
+  {
+    // Only acquire the mutex while reading the handler, so as not to invoke a
+    // user-supplied callback under a lock.
+#if LLVM_ENABLE_THREADS == 1
+    std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
+#endif
+    handler = ErrorHandler;
+    handlerData = ErrorHandlerUserData;
+  }
+
+  if (handler) {
+    handler(handlerData, Reason.str(), GenCrashDiag);
+  } else {
+    // Blast the result out to stderr.  We don't try hard to make sure this
+    // succeeds (e.g. handling EINTR) and we can't use errs() here because
+    // raw ostreams can call report_fatal_error.
+    SmallVector<char, 64> Buffer;
+    raw_svector_ostream OS(Buffer);
+    OS << "LLVM ERROR: " << Reason << "\n";
+    ssize_t written = ::write(2, MessageStr.data(), MessageStr.size());
+    StringRef MessageStr = OS.str();
+    (void)written; // If something went wrong, we deliberately just give up.
+  }
+
+  // If we reached here, we are failing ungracefully. Run the interrupt handlers
+  // to make sure any special cleanups get done, in particular that we remove
+  // files registered with RemoveFileOnSignal.
+  sys::RunInterruptHandlers();
+#else
+  Reason.dump();
+#endif
+
+  exit(1);
+}
+
+void llvm::install_bad_alloc_error_handler(fatal_error_handler_t handler,
+                                           void *user_data) {
+#if LLVM_ENABLE_THREADS == 1
+  std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
+#endif
+  assert(!ErrorHandler && "Bad alloc error handler already registered!\n");
+  BadAllocErrorHandler = handler;
+  BadAllocErrorHandlerUserData = user_data;
+}
+
+void llvm::remove_bad_alloc_error_handler() {
+#if LLVM_ENABLE_THREADS == 1
+  std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
+#endif
+  BadAllocErrorHandler = nullptr;
+  BadAllocErrorHandlerUserData = nullptr;
+}
+
+void llvm::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
+  fatal_error_handler_t Handler = nullptr;
+  void *HandlerData = nullptr;
+  {
+    // Only acquire the mutex while reading the handler, so as not to invoke a
+    // user-supplied callback under a lock.
+#if LLVM_ENABLE_THREADS == 1
+    std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
+#endif
+    Handler = BadAllocErrorHandler;
+    HandlerData = BadAllocErrorHandlerUserData;
+  }
+
+  if (Handler) {
+    Handler(HandlerData, Reason, GenCrashDiag);
+    llvm_unreachable("bad alloc handler should not return");
+  }
+
+#ifdef LLVM_ENABLE_EXCEPTIONS
+  // If exceptions are enabled, make OOM in malloc look like OOM in new.
+  throw std::bad_alloc();
+#else
+  // Don't call the normal error handler. It may allocate memory. Directly write
+  // an OOM to stderr and abort.
+  char OOMMessage[] = "LLVM ERROR: out of memory\n";
+  ssize_t written = ::write(2, OOMMessage, strlen(OOMMessage));
+  (void)written;
+  abort();
+#endif
+}
+
+#ifdef LLVM_ENABLE_EXCEPTIONS
+// Do not set custom new handler if exceptions are enabled. In this case OOM
+// errors are handled by throwing 'std::bad_alloc'.
+void llvm::install_out_of_memory_new_handler() {
+}
+#else
+// Causes crash on allocation failure. It is called prior to the handler set by
+// 'install_bad_alloc_error_handler'.
+static void out_of_memory_new_handler() {
+  llvm::report_bad_alloc_error("Allocation failed");
+}
+
+// Installs new handler that causes crash on allocation failure. It is called by
+// InitLLVM.
+void llvm::install_out_of_memory_new_handler() {
+  std::new_handler old = std::set_new_handler(out_of_memory_new_handler);
+  (void)old;
+  assert(old == nullptr && "new-handler already installed");
+}
+#endif
+
+void llvm::llvm_unreachable_internal(const char *msg, const char *file,
+                                     unsigned line) {
+  // This code intentionally doesn't call the ErrorHandler callback, because
+  // llvm_unreachable is intended to be used to indicate "impossible"
+  // situations, and not legitimate runtime errors.
+  // XXX BINARYEN: use cout
+  if (msg)
+    std::cout << msg << "\n";
+  std::cout << "UNREACHABLE executed";
+  if (file)
+    std::cout << " at " << file << ":" << line;
+  std::cout << "!\n";
+  abort();
+#ifdef LLVM_BUILTIN_UNREACHABLE
+  // Windows systems and possibly others don't declare abort() to be noreturn,
+  // so use the unreachable builtin to avoid a Clang self-host warning.
+  LLVM_BUILTIN_UNREACHABLE;
+#endif
+}
+
+static void bindingsErrorHandler(void *user_data, const std::string& reason,
+                                 bool gen_crash_diag) {
+  LLVMFatalErrorHandler handler =
+      LLVM_EXTENSION reinterpret_cast<LLVMFatalErrorHandler>(user_data);
+  handler(reason.c_str());
+}
+
+void LLVMInstallFatalErrorHandler(LLVMFatalErrorHandler Handler) {
+  install_fatal_error_handler(bindingsErrorHandler,
+                              LLVM_EXTENSION reinterpret_cast<void *>(Handler));
+}
+
+void LLVMResetFatalErrorHandler() {
+  remove_fatal_error_handler();
+}
+
+#ifdef _WIN32
+
+#include <winerror.h>
+
+// I'd rather not double the line count of the following.
+#define MAP_ERR_TO_COND(x, y)                                                  \
+  case x:                                                                      \
+    return make_error_code(errc::y)
+
+std::error_code llvm::mapWindowsError(unsigned EV) {
+  switch (EV) {
+    MAP_ERR_TO_COND(ERROR_ACCESS_DENIED, permission_denied);
+    MAP_ERR_TO_COND(ERROR_ALREADY_EXISTS, file_exists);
+    MAP_ERR_TO_COND(ERROR_BAD_UNIT, no_such_device);
+    MAP_ERR_TO_COND(ERROR_BUFFER_OVERFLOW, filename_too_long);
+    MAP_ERR_TO_COND(ERROR_BUSY, device_or_resource_busy);
+    MAP_ERR_TO_COND(ERROR_BUSY_DRIVE, device_or_resource_busy);
+    MAP_ERR_TO_COND(ERROR_CANNOT_MAKE, permission_denied);
+    MAP_ERR_TO_COND(ERROR_CANTOPEN, io_error);
+    MAP_ERR_TO_COND(ERROR_CANTREAD, io_error);
+    MAP_ERR_TO_COND(ERROR_CANTWRITE, io_error);
+    MAP_ERR_TO_COND(ERROR_CURRENT_DIRECTORY, permission_denied);
+    MAP_ERR_TO_COND(ERROR_DEV_NOT_EXIST, no_such_device);
+    MAP_ERR_TO_COND(ERROR_DEVICE_IN_USE, device_or_resource_busy);
+    MAP_ERR_TO_COND(ERROR_DIR_NOT_EMPTY, directory_not_empty);
+    MAP_ERR_TO_COND(ERROR_DIRECTORY, invalid_argument);
+    MAP_ERR_TO_COND(ERROR_DISK_FULL, no_space_on_device);
+    MAP_ERR_TO_COND(ERROR_FILE_EXISTS, file_exists);
+    MAP_ERR_TO_COND(ERROR_FILE_NOT_FOUND, no_such_file_or_directory);
+    MAP_ERR_TO_COND(ERROR_HANDLE_DISK_FULL, no_space_on_device);
+    MAP_ERR_TO_COND(ERROR_INVALID_ACCESS, permission_denied);
+    MAP_ERR_TO_COND(ERROR_INVALID_DRIVE, no_such_device);
+    MAP_ERR_TO_COND(ERROR_INVALID_FUNCTION, function_not_supported);
+    MAP_ERR_TO_COND(ERROR_INVALID_HANDLE, invalid_argument);
+    MAP_ERR_TO_COND(ERROR_INVALID_NAME, invalid_argument);
+    MAP_ERR_TO_COND(ERROR_LOCK_VIOLATION, no_lock_available);
+    MAP_ERR_TO_COND(ERROR_LOCKED, no_lock_available);
+    MAP_ERR_TO_COND(ERROR_NEGATIVE_SEEK, invalid_argument);
+    MAP_ERR_TO_COND(ERROR_NOACCESS, permission_denied);
+    MAP_ERR_TO_COND(ERROR_NOT_ENOUGH_MEMORY, not_enough_memory);
+    MAP_ERR_TO_COND(ERROR_NOT_READY, resource_unavailable_try_again);
+    MAP_ERR_TO_COND(ERROR_OPEN_FAILED, io_error);
+    MAP_ERR_TO_COND(ERROR_OPEN_FILES, device_or_resource_busy);
+    MAP_ERR_TO_COND(ERROR_OUTOFMEMORY, not_enough_memory);
+    MAP_ERR_TO_COND(ERROR_PATH_NOT_FOUND, no_such_file_or_directory);
+    MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory);
+    MAP_ERR_TO_COND(ERROR_READ_FAULT, io_error);
+    MAP_ERR_TO_COND(ERROR_RETRY, resource_unavailable_try_again);
+    MAP_ERR_TO_COND(ERROR_SEEK, io_error);
+    MAP_ERR_TO_COND(ERROR_SHARING_VIOLATION, permission_denied);
+    MAP_ERR_TO_COND(ERROR_TOO_MANY_OPEN_FILES, too_many_files_open);
+    MAP_ERR_TO_COND(ERROR_WRITE_FAULT, io_error);
+    MAP_ERR_TO_COND(ERROR_WRITE_PROTECT, permission_denied);
+    MAP_ERR_TO_COND(WSAEACCES, permission_denied);
+    MAP_ERR_TO_COND(WSAEBADF, bad_file_descriptor);
+    MAP_ERR_TO_COND(WSAEFAULT, bad_address);
+    MAP_ERR_TO_COND(WSAEINTR, interrupted);
+    MAP_ERR_TO_COND(WSAEINVAL, invalid_argument);
+    MAP_ERR_TO_COND(WSAEMFILE, too_many_files_open);
+    MAP_ERR_TO_COND(WSAENAMETOOLONG, filename_too_long);
+  default:
+    return std::error_code(EV, std::system_category());
+  }
+}
+
+#endif
diff --git a/binaryen/third_party/llvm-project/FormatVariadic.cpp b/binaryen/third_party/llvm-project/FormatVariadic.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/FormatVariadic.cpp
@@ -0,0 +1,155 @@
+//===- FormatVariadic.cpp - Format string parsing and analysis ----*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+
+static Optional<AlignStyle> translateLocChar(char C) {
+  switch (C) {
+  case '-':
+    return AlignStyle::Left;
+  case '=':
+    return AlignStyle::Center;
+  case '+':
+    return AlignStyle::Right;
+  default:
+    return None;
+  }
+  LLVM_BUILTIN_UNREACHABLE;
+}
+
+bool formatv_object_base::consumeFieldLayout(StringRef &Spec, AlignStyle &Where,
+                                             size_t &Align, char &Pad) {
+  Where = AlignStyle::Right;
+  Align = 0;
+  Pad = ' ';
+  if (Spec.empty())
+    return true;
+
+  if (Spec.size() > 1) {
+    // A maximum of 2 characters at the beginning can be used for something
+    // other
+    // than the width.
+    // If Spec[1] is a loc char, then Spec[0] is a pad char and Spec[2:...]
+    // contains the width.
+    // Otherwise, if Spec[0] is a loc char, then Spec[1:...] contains the width.
+    // Otherwise, Spec[0:...] contains the width.
+    if (auto Loc = translateLocChar(Spec[1])) {
+      Pad = Spec[0];
+      Where = *Loc;
+      Spec = Spec.drop_front(2);
+    } else if (auto Loc = translateLocChar(Spec[0])) {
+      Where = *Loc;
+      Spec = Spec.drop_front(1);
+    }
+  }
+
+  bool Failed = Spec.consumeInteger(0, Align);
+  return !Failed;
+}
+
+Optional<ReplacementItem>
+formatv_object_base::parseReplacementItem(StringRef Spec) {
+  StringRef RepString = Spec.trim("{}");
+
+  // If the replacement sequence does not start with a non-negative integer,
+  // this is an error.
+  char Pad = ' ';
+  std::size_t Align = 0;
+  AlignStyle Where = AlignStyle::Right;
+  StringRef Options;
+  size_t Index = 0;
+  RepString = RepString.trim();
+  if (RepString.consumeInteger(0, Index)) {
+    assert(false && "Invalid replacement sequence index!");
+    return ReplacementItem{};
+  }
+  RepString = RepString.trim();
+  if (!RepString.empty() && RepString.front() == ',') {
+    RepString = RepString.drop_front();
+    if (!consumeFieldLayout(RepString, Where, Align, Pad))
+      assert(false && "Invalid replacement field layout specification!");
+  }
+  RepString = RepString.trim();
+  if (!RepString.empty() && RepString.front() == ':') {
+    Options = RepString.drop_front().trim();
+    RepString = StringRef();
+  }
+  RepString = RepString.trim();
+  if (!RepString.empty()) {
+    assert(false && "Unexpected characters found in replacement string!");
+  }
+
+  return ReplacementItem{Spec, Index, Align, Where, Pad, Options};
+}
+
+std::pair<ReplacementItem, StringRef>
+formatv_object_base::splitLiteralAndReplacement(StringRef Fmt) {
+  std::size_t From = 0;
+  while (From < Fmt.size() && From != StringRef::npos) {
+    std::size_t BO = Fmt.find_first_of('{', From);
+    // Everything up until the first brace is a literal.
+    if (BO != 0)
+      return std::make_pair(ReplacementItem{Fmt.substr(0, BO)}, Fmt.substr(BO));
+
+    StringRef Braces =
+        Fmt.drop_front(BO).take_while([](char C) { return C == '{'; });
+    // If there is more than one brace, then some of them are escaped.  Treat
+    // these as replacements.
+    if (Braces.size() > 1) {
+      size_t NumEscapedBraces = Braces.size() / 2;
+      StringRef Middle = Fmt.substr(BO, NumEscapedBraces);
+      StringRef Right = Fmt.drop_front(BO + NumEscapedBraces * 2);
+      return std::make_pair(ReplacementItem{Middle}, Right);
+    }
+    // An unterminated open brace is undefined.  We treat the rest of the string
+    // as a literal replacement, but we assert to indicate that this is
+    // undefined and that we consider it an error.
+    std::size_t BC = Fmt.find_first_of('}', BO);
+    if (BC == StringRef::npos) {
+      assert(
+          false &&
+          "Unterminated brace sequence.  Escape with {{ for a literal brace.");
+      return std::make_pair(ReplacementItem{Fmt}, StringRef());
+    }
+
+    // Even if there is a closing brace, if there is another open brace before
+    // this closing brace, treat this portion as literal, and try again with the
+    // next one.
+    std::size_t BO2 = Fmt.find_first_of('{', BO + 1);
+    if (BO2 < BC)
+      return std::make_pair(ReplacementItem{Fmt.substr(0, BO2)},
+                            Fmt.substr(BO2));
+
+    StringRef Spec = Fmt.slice(BO + 1, BC);
+    StringRef Right = Fmt.substr(BC + 1);
+
+    auto RI = parseReplacementItem(Spec);
+    if (RI.hasValue())
+      return std::make_pair(*RI, Right);
+
+    // If there was an error parsing the replacement item, treat it as an
+    // invalid replacement spec, and just continue.
+    From = BC + 1;
+  }
+  return std::make_pair(ReplacementItem{Fmt}, StringRef());
+}
+
+std::vector<ReplacementItem>
+formatv_object_base::parseFormatString(StringRef Fmt) {
+  std::vector<ReplacementItem> Replacements;
+  ReplacementItem I;
+  while (!Fmt.empty()) {
+    std::tie(I, Fmt) = splitLiteralAndReplacement(Fmt);
+    if (I.Type != ReplacementType::Empty)
+      Replacements.push_back(I);
+  }
+  return Replacements;
+}
+
+void detail::format_adapter::anchor() { }
diff --git a/binaryen/third_party/llvm-project/Hashing.cpp b/binaryen/third_party/llvm-project/Hashing.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/Hashing.cpp
@@ -0,0 +1,28 @@
+//===-------------- lib/Support/Hashing.cpp -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides implementation bits for the LLVM common hashing
+// infrastructure. Documentation and most of the other information is in the
+// header file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/Hashing.h"
+
+using namespace llvm;
+
+// Provide a definition and static initializer for the fixed seed. This
+// initializer should always be zero to ensure its value can never appear to be
+// non-zero, even during dynamic initialization.
+uint64_t llvm::hashing::detail::fixed_seed_override = 0;
+
+// Implement the function for forced setting of the fixed seed.
+// FIXME: Use atomic operations here so that there is no data race.
+void llvm::set_fixed_execution_hash_seed(uint64_t fixed_value) {
+  hashing::detail::fixed_seed_override = fixed_value;
+}
diff --git a/binaryen/third_party/llvm-project/LEB128.cpp b/binaryen/third_party/llvm-project/LEB128.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/LEB128.cpp
@@ -0,0 +1,43 @@
+//===- LEB128.cpp - LEB128 utility functions implementation -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements some utility functions for encoding SLEB128 and
+// ULEB128 values.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/LEB128.h"
+
+namespace llvm {
+
+/// Utility function to get the size of the ULEB128-encoded value.
+unsigned getULEB128Size(uint64_t Value) {
+  unsigned Size = 0;
+  do {
+    Value >>= 7;
+    Size += sizeof(int8_t);
+  } while (Value);
+  return Size;
+}
+
+/// Utility function to get the size of the SLEB128-encoded value.
+unsigned getSLEB128Size(int64_t Value) {
+  unsigned Size = 0;
+  int Sign = Value >> (8 * sizeof(Value) - 1);
+  bool IsMore;
+
+  do {
+    unsigned Byte = Value & 0x7f;
+    Value >>= 7;
+    IsMore = Value != Sign || ((Byte ^ Sign) & 0x40) != 0;
+    Size += sizeof(int8_t);
+  } while (IsMore);
+  return Size;
+}
+
+}  // namespace llvm
diff --git a/binaryen/third_party/llvm-project/LineIterator.cpp b/binaryen/third_party/llvm-project/LineIterator.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/LineIterator.cpp
@@ -0,0 +1,93 @@
+//===- LineIterator.cpp - Implementation of line iteration ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+
+static bool isAtLineEnd(const char *P) {
+  if (*P == '\n')
+    return true;
+  if (*P == '\r' && *(P + 1) == '\n')
+    return true;
+  return false;
+}
+
+static bool skipIfAtLineEnd(const char *&P) {
+  if (*P == '\n') {
+    ++P;
+    return true;
+  }
+  if (*P == '\r' && *(P + 1) == '\n') {
+    P += 2;
+    return true;
+  }
+  return false;
+}
+
+line_iterator::line_iterator(const MemoryBuffer &Buffer, bool SkipBlanks,
+                             char CommentMarker)
+    : Buffer(Buffer.getBufferSize() ? &Buffer : nullptr),
+      CommentMarker(CommentMarker), SkipBlanks(SkipBlanks), LineNumber(1),
+      CurrentLine(Buffer.getBufferSize() ? Buffer.getBufferStart() : nullptr,
+                  0) {
+  // Ensure that if we are constructed on a non-empty memory buffer that it is
+  // a null terminated buffer.
+  if (Buffer.getBufferSize()) {
+    assert(Buffer.getBufferEnd()[0] == '\0');
+    // Make sure we don't skip a leading newline if we're keeping blanks
+    if (SkipBlanks || !isAtLineEnd(Buffer.getBufferStart()))
+      advance();
+  }
+}
+
+void line_iterator::advance() {
+  assert(Buffer && "Cannot advance past the end!");
+
+  const char *Pos = CurrentLine.end();
+  assert(Pos == Buffer->getBufferStart() || isAtLineEnd(Pos) || *Pos == '\0');
+
+  if (skipIfAtLineEnd(Pos))
+    ++LineNumber;
+  if (!SkipBlanks && isAtLineEnd(Pos)) {
+    // Nothing to do for a blank line.
+  } else if (CommentMarker == '\0') {
+    // If we're not stripping comments, this is simpler.
+    while (skipIfAtLineEnd(Pos))
+      ++LineNumber;
+  } else {
+    // Skip comments and count line numbers, which is a bit more complex.
+    for (;;) {
+      if (isAtLineEnd(Pos) && !SkipBlanks)
+        break;
+      if (*Pos == CommentMarker)
+        do {
+          ++Pos;
+        } while (*Pos != '\0' && !isAtLineEnd(Pos));
+      if (!skipIfAtLineEnd(Pos))
+        break;
+      ++LineNumber;
+    }
+  }
+
+  if (*Pos == '\0') {
+    // We've hit the end of the buffer, reset ourselves to the end state.
+    Buffer = nullptr;
+    CurrentLine = StringRef();
+    return;
+  }
+
+  // Measure the line.
+  size_t Length = 0;
+  while (Pos[Length] != '\0' && !isAtLineEnd(&Pos[Length])) {
+    ++Length;
+  }
+
+  CurrentLine = StringRef(Pos, Length);
+}
diff --git a/binaryen/third_party/llvm-project/MCRegisterInfo.cpp b/binaryen/third_party/llvm-project/MCRegisterInfo.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/MCRegisterInfo.cpp
@@ -0,0 +1,124 @@
+//===- MC/MCRegisterInfo.cpp - Target Register Description ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements MCRegisterInfo functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+
+MCRegister
+MCRegisterInfo::getMatchingSuperReg(MCRegister Reg, unsigned SubIdx,
+                                    const MCRegisterClass *RC) const {
+  for (MCSuperRegIterator Supers(Reg, this); Supers.isValid(); ++Supers)
+    if (RC->contains(*Supers) && Reg == getSubReg(*Supers, SubIdx))
+      return *Supers;
+  return 0;
+}
+
+MCRegister MCRegisterInfo::getSubReg(MCRegister Reg, unsigned Idx) const {
+  assert(Idx && Idx < getNumSubRegIndices() &&
+         "This is not a subregister index");
+  // Get a pointer to the corresponding SubRegIndices list. This list has the
+  // name of each sub-register in the same order as MCSubRegIterator.
+  const uint16_t *SRI = SubRegIndices + get(Reg).SubRegIndices;
+  for (MCSubRegIterator Subs(Reg, this); Subs.isValid(); ++Subs, ++SRI)
+    if (*SRI == Idx)
+      return *Subs;
+  return 0;
+}
+
+unsigned MCRegisterInfo::getSubRegIndex(MCRegister Reg,
+                                        MCRegister SubReg) const {
+  assert(SubReg && SubReg < getNumRegs() && "This is not a register");
+  // Get a pointer to the corresponding SubRegIndices list. This list has the
+  // name of each sub-register in the same order as MCSubRegIterator.
+  const uint16_t *SRI = SubRegIndices + get(Reg).SubRegIndices;
+  for (MCSubRegIterator Subs(Reg, this); Subs.isValid(); ++Subs, ++SRI)
+    if (*Subs == SubReg)
+      return *SRI;
+  return 0;
+}
+
+unsigned MCRegisterInfo::getSubRegIdxSize(unsigned Idx) const {
+  assert(Idx && Idx < getNumSubRegIndices() &&
+         "This is not a subregister index");
+  return SubRegIdxRanges[Idx].Size;
+}
+
+unsigned MCRegisterInfo::getSubRegIdxOffset(unsigned Idx) const {
+  assert(Idx && Idx < getNumSubRegIndices() &&
+         "This is not a subregister index");
+  return SubRegIdxRanges[Idx].Offset;
+}
+
+int MCRegisterInfo::getDwarfRegNum(MCRegister RegNum, bool isEH) const {
+  const DwarfLLVMRegPair *M = isEH ? EHL2DwarfRegs : L2DwarfRegs;
+  unsigned Size = isEH ? EHL2DwarfRegsSize : L2DwarfRegsSize;
+
+  if (!M)
+    return -1;
+  DwarfLLVMRegPair Key = { RegNum, 0 };
+  const DwarfLLVMRegPair *I = std::lower_bound(M, M+Size, Key);
+  if (I == M+Size || I->FromReg != RegNum)
+    return -1;
+  return I->ToReg;
+}
+
+Optional<unsigned> MCRegisterInfo::getLLVMRegNum(unsigned RegNum,
+                                                 bool isEH) const {
+  const DwarfLLVMRegPair *M = isEH ? EHDwarf2LRegs : Dwarf2LRegs;
+  unsigned Size = isEH ? EHDwarf2LRegsSize : Dwarf2LRegsSize;
+
+  if (!M)
+    return None;
+  DwarfLLVMRegPair Key = { RegNum, 0 };
+  const DwarfLLVMRegPair *I = std::lower_bound(M, M+Size, Key);
+  if (I != M + Size && I->FromReg == RegNum)
+    return I->ToReg;
+  return None;
+}
+
+int MCRegisterInfo::getDwarfRegNumFromDwarfEHRegNum(unsigned RegNum) const {
+  // On ELF platforms, DWARF EH register numbers are the same as DWARF
+  // other register numbers.  On Darwin x86, they differ and so need to be
+  // mapped.  The .cfi_* directives accept integer literals as well as
+  // register names and should generate exactly what the assembly code
+  // asked for, so there might be DWARF/EH register numbers that don't have
+  // a corresponding LLVM register number at all.  So if we can't map the
+  // EH register number to an LLVM register number, assume it's just a
+  // valid DWARF register number as is.
+  if (Optional<unsigned> LRegNum = getLLVMRegNum(RegNum, true))
+    return getDwarfRegNum(*LRegNum, false);
+  return RegNum;
+}
+
+int MCRegisterInfo::getSEHRegNum(MCRegister RegNum) const {
+  const DenseMap<MCRegister, int>::const_iterator I = L2SEHRegs.find(RegNum);
+  if (I == L2SEHRegs.end()) return (int)RegNum;
+  return I->second;
+}
+
+int MCRegisterInfo::getCodeViewRegNum(MCRegister RegNum) const {
+  if (L2CVRegs.empty())
+    report_fatal_error("target does not implement codeview register mapping");
+  const DenseMap<MCRegister, int>::const_iterator I = L2CVRegs.find(RegNum);
+  if (I == L2CVRegs.end())
+    report_fatal_error("unknown codeview register " + (RegNum < getNumRegs()
+                                                           ? getName(RegNum)
+                                                           : Twine(RegNum)));
+  return I->second;
+}
diff --git a/binaryen/third_party/llvm-project/MD5.cpp b/binaryen/third_party/llvm-project/MD5.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/MD5.cpp
@@ -0,0 +1,283 @@
+/*
+ * This code is derived from (original license follows):
+ *
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001.  No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * (This is a heavily cut-down "BSD license".)
+ *
+ * This differs from Colin Plumb's older public domain implementation in that
+ * no exactly 32-bit integer data type is required (any 32-bit or wider
+ * unsigned integer data type will do), there's no compile-time endianness
+ * configuration, and the function prototypes match OpenSSL's.  No code from
+ * Colin Plumb's implementation has been reused; this comment merely compares
+ * the properties of the two independent implementations.
+ *
+ * The primary goals of this implementation are portability and ease of use.
+ * It is meant to be fast, but not as fast as possible.  Some known
+ * optimizations are not included to reduce source code size and avoid
+ * compile-time configuration.
+ */
+
+#include "llvm/Support/MD5.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <array>
+#include <cstdint>
+#include <cstring>
+
+// The basic MD5 functions.
+
+// F and G are optimized compared to their RFC 1321 definitions for
+// architectures that lack an AND-NOT instruction, just like in Colin Plumb's
+// implementation.
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+
+// The MD5 transformation for all four rounds.
+#define STEP(f, a, b, c, d, x, t, s)                                           \
+  (a) += f((b), (c), (d)) + (x) + (t);                                         \
+  (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s))));                   \
+  (a) += (b);
+
+// SET reads 4 input bytes in little-endian byte order and stores them
+// in a properly aligned word in host byte order.
+#define SET(n)                                                                 \
+  (block[(n)] =                                                                \
+       (MD5_u32plus) ptr[(n) * 4] | ((MD5_u32plus) ptr[(n) * 4 + 1] << 8) |    \
+       ((MD5_u32plus) ptr[(n) * 4 + 2] << 16) |                                \
+       ((MD5_u32plus) ptr[(n) * 4 + 3] << 24))
+#define GET(n) (block[(n)])
+
+using namespace llvm;
+
+/// This processes one or more 64-byte data blocks, but does NOT update
+///the bit counters.  There are no alignment requirements.
+const uint8_t *MD5::body(ArrayRef<uint8_t> Data) {
+  const uint8_t *ptr;
+  MD5_u32plus a, b, c, d;
+  MD5_u32plus saved_a, saved_b, saved_c, saved_d;
+  unsigned long Size = Data.size();
+
+  ptr = Data.data();
+
+  a = this->a;
+  b = this->b;
+  c = this->c;
+  d = this->d;
+
+  do {
+    saved_a = a;
+    saved_b = b;
+    saved_c = c;
+    saved_d = d;
+
+    // Round 1
+    STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
+    STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
+    STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
+    STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
+    STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
+    STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
+    STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
+    STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
+    STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
+    STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
+    STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
+    STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
+    STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
+    STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
+    STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
+    STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
+
+    // Round 2
+    STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
+    STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
+    STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
+    STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
+    STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
+    STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
+    STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
+    STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
+    STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
+    STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
+    STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
+    STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
+    STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
+    STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
+    STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
+    STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
+
+    // Round 3
+    STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
+    STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
+    STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
+    STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
+    STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
+    STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
+    STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
+    STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
+    STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
+    STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
+    STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
+    STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
+    STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
+    STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
+    STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
+    STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
+
+    // Round 4
+    STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
+    STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
+    STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
+    STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
+    STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
+    STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
+    STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
+    STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
+    STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
+    STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
+    STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
+    STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
+    STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
+    STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
+    STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
+    STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
+
+    a += saved_a;
+    b += saved_b;
+    c += saved_c;
+    d += saved_d;
+
+    ptr += 64;
+  } while (Size -= 64);
+
+  this->a = a;
+  this->b = b;
+  this->c = c;
+  this->d = d;
+
+  return ptr;
+}
+
+MD5::MD5() = default;
+
+/// Incrementally add the bytes in \p Data to the hash.
+void MD5::update(ArrayRef<uint8_t> Data) {
+  MD5_u32plus saved_lo;
+  unsigned long used, free;
+  const uint8_t *Ptr = Data.data();
+  unsigned long Size = Data.size();
+
+  saved_lo = lo;
+  if ((lo = (saved_lo + Size) & 0x1fffffff) < saved_lo)
+    hi++;
+  hi += Size >> 29;
+
+  used = saved_lo & 0x3f;
+
+  if (used) {
+    free = 64 - used;
+
+    if (Size < free) {
+      memcpy(&buffer[used], Ptr, Size);
+      return;
+    }
+
+    memcpy(&buffer[used], Ptr, free);
+    Ptr = Ptr + free;
+    Size -= free;
+    body(makeArrayRef(buffer, 64));
+  }
+
+  if (Size >= 64) {
+    Ptr = body(makeArrayRef(Ptr, Size & ~(unsigned long) 0x3f));
+    Size &= 0x3f;
+  }
+
+  memcpy(buffer, Ptr, Size);
+}
+
+/// Add the bytes in the StringRef \p Str to the hash.
+// Note that this isn't a string and so this won't include any trailing NULL
+// bytes.
+void MD5::update(StringRef Str) {
+  ArrayRef<uint8_t> SVal((const uint8_t *)Str.data(), Str.size());
+  update(SVal);
+}
+
+/// Finish the hash and place the resulting hash into \p result.
+/// \param Result is assumed to be a minimum of 16-bytes in size.
+void MD5::final(MD5Result &Result) {
+  unsigned long used, free;
+
+  used = lo & 0x3f;
+
+  buffer[used++] = 0x80;
+
+  free = 64 - used;
+
+  if (free < 8) {
+    memset(&buffer[used], 0, free);
+    body(makeArrayRef(buffer, 64));
+    used = 0;
+    free = 64;
+  }
+
+  memset(&buffer[used], 0, free - 8);
+
+  lo <<= 3;
+  support::endian::write32le(&buffer[56], lo);
+  support::endian::write32le(&buffer[60], hi);
+
+  body(makeArrayRef(buffer, 64));
+
+  support::endian::write32le(&Result[0], a);
+  support::endian::write32le(&Result[4], b);
+  support::endian::write32le(&Result[8], c);
+  support::endian::write32le(&Result[12], d);
+}
+
+SmallString<32> MD5::MD5Result::digest() const {
+  SmallString<32> Str;
+  raw_svector_ostream Res(Str);
+  for (int i = 0; i < 16; ++i)
+    Res << format("%.2x", Bytes[i]);
+  return Str;
+}
+
+void MD5::stringifyResult(MD5Result &Result, SmallString<32> &Str) {
+  Str = Result.digest();
+}
+
+std::array<uint8_t, 16> MD5::hash(ArrayRef<uint8_t> Data) {
+  MD5 Hash;
+  Hash.update(Data);
+  MD5::MD5Result Res;
+  Hash.final(Res);
+
+  return Res;
+}
diff --git a/binaryen/third_party/llvm-project/MemoryBuffer.cpp b/binaryen/third_party/llvm-project/MemoryBuffer.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/MemoryBuffer.cpp
@@ -0,0 +1,355 @@
+//===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements the MemoryBuffer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Errno.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/SmallVectorMemoryBuffer.h"
+#include <cassert>
+#include <cerrno>
+#include <cstring>
+#include <new>
+#include <sys/types.h>
+#include <system_error>
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// MemoryBuffer implementation itself.
+//===----------------------------------------------------------------------===//
+
+MemoryBuffer::~MemoryBuffer() { }
+
+/// init - Initialize this MemoryBuffer as a reference to externally allocated
+/// memory, memory that we know is already null terminated.
+void MemoryBuffer::init(const char *BufStart, const char *BufEnd,
+                        bool RequiresNullTerminator) {
+  assert((!RequiresNullTerminator || BufEnd[0] == 0) &&
+         "Buffer is not null terminated!");
+  BufferStart = BufStart;
+  BufferEnd = BufEnd;
+}
+
+//===----------------------------------------------------------------------===//
+// MemoryBufferMem implementation.
+//===----------------------------------------------------------------------===//
+
+/// CopyStringRef - Copies contents of a StringRef into a block of memory and
+/// null-terminates it.
+static void CopyStringRef(char *Memory, StringRef Data) {
+  if (!Data.empty())
+    memcpy(Memory, Data.data(), Data.size());
+  Memory[Data.size()] = 0; // Null terminate string.
+}
+
+namespace {
+struct NamedBufferAlloc {
+  const Twine &Name;
+  NamedBufferAlloc(const Twine &Name) : Name(Name) {}
+};
+}
+
+void *operator new(size_t N, const NamedBufferAlloc &Alloc) {
+  SmallString<256> NameBuf;
+  StringRef NameRef = Alloc.Name.toStringRef(NameBuf);
+
+  char *Mem = static_cast<char *>(operator new(N + NameRef.size() + 1));
+  CopyStringRef(Mem + N, NameRef);
+  return Mem;
+}
+
+namespace {
+/// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory.
+template<typename MB>
+class MemoryBufferMem : public MB {
+public:
+  MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) {
+    MemoryBuffer::init(InputData.begin(), InputData.end(),
+                       RequiresNullTerminator);
+  }
+
+  /// Disable sized deallocation for MemoryBufferMem, because it has
+  /// tail-allocated data.
+  void operator delete(void *p) { ::operator delete(p); }
+
+  StringRef getBufferIdentifier() const override {
+    // The name is stored after the class itself.
+    return StringRef(reinterpret_cast<const char *>(this + 1));
+  }
+
+  MemoryBuffer::BufferKind getBufferKind() const override {
+    return MemoryBuffer::MemoryBuffer_Malloc;
+  }
+};
+}
+
+template <typename MB>
+static ErrorOr<std::unique_ptr<MB>>
+getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize,
+           uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile);
+
+std::unique_ptr<MemoryBuffer>
+MemoryBuffer::getMemBuffer(StringRef InputData, StringRef BufferName,
+                           bool RequiresNullTerminator) {
+  auto *Ret = new (NamedBufferAlloc(BufferName))
+      MemoryBufferMem<MemoryBuffer>(InputData, RequiresNullTerminator);
+  return std::unique_ptr<MemoryBuffer>(Ret);
+}
+
+std::unique_ptr<MemoryBuffer>
+MemoryBuffer::getMemBuffer(MemoryBufferRef Ref, bool RequiresNullTerminator) {
+  return std::unique_ptr<MemoryBuffer>(getMemBuffer(
+      Ref.getBuffer(), Ref.getBufferIdentifier(), RequiresNullTerminator));
+}
+
+static ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
+getMemBufferCopyImpl(StringRef InputData, const Twine &BufferName) {
+  auto Buf = WritableMemoryBuffer::getNewUninitMemBuffer(InputData.size(), BufferName);
+  if (!Buf)
+    return make_error_code(errc::not_enough_memory);
+  memcpy(Buf->getBufferStart(), InputData.data(), InputData.size());
+  return std::move(Buf);
+}
+
+std::unique_ptr<MemoryBuffer>
+MemoryBuffer::getMemBufferCopy(StringRef InputData, const Twine &BufferName) {
+  auto Buf = getMemBufferCopyImpl(InputData, BufferName);
+  if (Buf)
+    return std::move(*Buf);
+  return nullptr;
+}
+
+ErrorOr<std::unique_ptr<MemoryBuffer>>
+MemoryBuffer::getFileOrSTDIN(const Twine &Filename, int64_t FileSize,
+                             bool RequiresNullTerminator) {
+  SmallString<256> NameBuf;
+  StringRef NameRef = Filename.toStringRef(NameBuf);
+
+  if (NameRef == "-")
+    return getSTDIN();
+  return getFile(Filename, FileSize, RequiresNullTerminator);
+}
+
+ErrorOr<std::unique_ptr<MemoryBuffer>>
+MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize,
+                           uint64_t Offset, bool IsVolatile) {
+  return getFileAux<MemoryBuffer>(FilePath, -1, MapSize, Offset, false,
+                                  IsVolatile);
+}
+
+//===----------------------------------------------------------------------===//
+// MemoryBuffer::getFile implementation.
+//===----------------------------------------------------------------------===//
+
+#if 0 // XXX BINARYEN
+namespace {
+/// Memory maps a file descriptor using sys::fs::mapped_file_region.
+///
+/// This handles converting the offset into a legal offset on the platform.
+template<typename MB>
+class MemoryBufferMMapFile : public MB {
+  sys::fs::mapped_file_region MFR;
+
+  static uint64_t getLegalMapOffset(uint64_t Offset) {
+    return Offset & ~(sys::fs::mapped_file_region::alignment() - 1);
+  }
+
+  static uint64_t getLegalMapSize(uint64_t Len, uint64_t Offset) {
+    return Len + (Offset - getLegalMapOffset(Offset));
+  }
+
+  const char *getStart(uint64_t Len, uint64_t Offset) {
+    return MFR.const_data() + (Offset - getLegalMapOffset(Offset));
+  }
+
+public:
+  MemoryBufferMMapFile(bool RequiresNullTerminator, sys::fs::file_t FD, uint64_t Len,
+                       uint64_t Offset, std::error_code &EC)
+      : MFR(FD, MB::Mapmode, getLegalMapSize(Len, Offset),
+            getLegalMapOffset(Offset), EC) {
+    if (!EC) {
+      const char *Start = getStart(Len, Offset);
+      MemoryBuffer::init(Start, Start + Len, RequiresNullTerminator);
+    }
+  }
+
+  /// Disable sized deallocation for MemoryBufferMMapFile, because it has
+  /// tail-allocated data.
+  void operator delete(void *p) { ::operator delete(p); }
+
+  StringRef getBufferIdentifier() const override {
+    // The name is stored after the class itself.
+    return StringRef(reinterpret_cast<const char *>(this + 1));
+  }
+
+  MemoryBuffer::BufferKind getBufferKind() const override {
+    return MemoryBuffer::MemoryBuffer_MMap;
+  }
+};
+}
+#endif
+
+static ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
+getMemoryBufferForStream(sys::fs::file_t FD, const Twine &BufferName) {
+  llvm_unreachable("getMemoryBufferForStream");
+}
+
+
+ErrorOr<std::unique_ptr<MemoryBuffer>>
+MemoryBuffer::getFile(const Twine &Filename, int64_t FileSize,
+                      bool RequiresNullTerminator, bool IsVolatile) {
+  return getFileAux<MemoryBuffer>(Filename, FileSize, FileSize, 0,
+                                  RequiresNullTerminator, IsVolatile);
+}
+
+template <typename MB>
+static ErrorOr<std::unique_ptr<MB>>
+getOpenFileImpl(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize,
+                uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator,
+                bool IsVolatile);
+
+template <typename MB>
+static ErrorOr<std::unique_ptr<MB>>
+getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize,
+           uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile) {
+  llvm_unreachable("getFileAux");
+}
+
+ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
+WritableMemoryBuffer::getFile(const Twine &Filename, int64_t FileSize,
+                              bool IsVolatile) {
+  return getFileAux<WritableMemoryBuffer>(Filename, FileSize, FileSize, 0,
+                                          /*RequiresNullTerminator*/ false,
+                                          IsVolatile);
+}
+
+ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
+WritableMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize,
+                                   uint64_t Offset, bool IsVolatile) {
+  return getFileAux<WritableMemoryBuffer>(Filename, -1, MapSize, Offset, false,
+                                          IsVolatile);
+}
+
+std::unique_ptr<WritableMemoryBuffer>
+WritableMemoryBuffer::getNewUninitMemBuffer(size_t Size, const Twine &BufferName) {
+  using MemBuffer = MemoryBufferMem<WritableMemoryBuffer>;
+  // Allocate space for the MemoryBuffer, the data and the name. It is important
+  // that MemoryBuffer and data are aligned so PointerIntPair works with them.
+  // TODO: Is 16-byte alignment enough?  We copy small object files with large
+  // alignment expectations into this buffer.
+  SmallString<256> NameBuf;
+  StringRef NameRef = BufferName.toStringRef(NameBuf);
+  size_t AlignedStringLen = alignTo(sizeof(MemBuffer) + NameRef.size() + 1, 16);
+  size_t RealLen = AlignedStringLen + Size + 1;
+  char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow));
+  if (!Mem)
+    return nullptr;
+
+  // The name is stored after the class itself.
+  CopyStringRef(Mem + sizeof(MemBuffer), NameRef);
+
+  // The buffer begins after the name and must be aligned.
+  char *Buf = Mem + AlignedStringLen;
+  Buf[Size] = 0; // Null terminate buffer.
+
+  auto *Ret = new (Mem) MemBuffer(StringRef(Buf, Size), true);
+  return std::unique_ptr<WritableMemoryBuffer>(Ret);
+}
+
+std::unique_ptr<WritableMemoryBuffer>
+WritableMemoryBuffer::getNewMemBuffer(size_t Size, const Twine &BufferName) {
+  auto SB = WritableMemoryBuffer::getNewUninitMemBuffer(Size, BufferName);
+  if (!SB)
+    return nullptr;
+  memset(SB->getBufferStart(), 0, Size);
+  return SB;
+}
+
+static bool shouldUseMmap(sys::fs::file_t FD,
+                          size_t FileSize,
+                          size_t MapSize,
+                          off_t Offset,
+                          bool RequiresNullTerminator,
+                          int PageSize,
+                          bool IsVolatile) {
+  // XXX BINARYEn
+  return false;
+}
+
+static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>>
+getReadWriteFile(const Twine &Filename, uint64_t FileSize, uint64_t MapSize,
+                 uint64_t Offset) {
+  llvm_unreachable("getReadWriteFile");
+}
+
+ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>>
+WriteThroughMemoryBuffer::getFile(const Twine &Filename, int64_t FileSize) {
+  return getReadWriteFile(Filename, FileSize, FileSize, 0);
+}
+
+/// Map a subrange of the specified file as a WritableMemoryBuffer.
+ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>>
+WriteThroughMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize,
+                                       uint64_t Offset) {
+  return getReadWriteFile(Filename, -1, MapSize, Offset);
+}
+
+template <typename MB>
+static ErrorOr<std::unique_ptr<MB>>
+getOpenFileImpl(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize,
+                uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator,
+                bool IsVolatile) {
+  llvm_unreachable("getOpenFileImpl");
+}
+
+ErrorOr<std::unique_ptr<MemoryBuffer>>
+MemoryBuffer::getOpenFile(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize,
+                          bool RequiresNullTerminator, bool IsVolatile) {
+  return getOpenFileImpl<MemoryBuffer>(FD, Filename, FileSize, FileSize, 0,
+                         RequiresNullTerminator, IsVolatile);
+}
+
+ErrorOr<std::unique_ptr<MemoryBuffer>>
+MemoryBuffer::getOpenFileSlice(sys::fs::file_t FD, const Twine &Filename, uint64_t MapSize,
+                               int64_t Offset, bool IsVolatile) {
+  assert(MapSize != uint64_t(-1));
+  return getOpenFileImpl<MemoryBuffer>(FD, Filename, -1, MapSize, Offset, false,
+                                       IsVolatile);
+}
+
+ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getSTDIN() {
+  llvm_unreachable("getSTDIN");
+}
+
+ErrorOr<std::unique_ptr<MemoryBuffer>>
+MemoryBuffer::getFileAsStream(const Twine &Filename) {
+  llvm_unreachable("getFileAsStream");
+}
+
+MemoryBufferRef MemoryBuffer::getMemBufferRef() const {
+  StringRef Data = getBuffer();
+  StringRef Identifier = getBufferIdentifier();
+  return MemoryBufferRef(Data, Identifier);
+}
+
+SmallVectorMemoryBuffer::~SmallVectorMemoryBuffer() {}
diff --git a/binaryen/third_party/llvm-project/NativeFormatting.cpp b/binaryen/third_party/llvm-project/NativeFormatting.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/NativeFormatting.cpp
@@ -0,0 +1,263 @@
+//===- NativeFormatting.cpp - Low level formatting helpers -------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/NativeFormatting.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Format.h"
+
+#include <float.h>
+
+using namespace llvm;
+
+template<typename T, std::size_t N>
+static int format_to_buffer(T Value, char (&Buffer)[N]) {
+  char *EndPtr = std::end(Buffer);
+  char *CurPtr = EndPtr;
+
+  do {
+    *--CurPtr = '0' + char(Value % 10);
+    Value /= 10;
+  } while (Value);
+  return EndPtr - CurPtr;
+}
+
+static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) {
+  assert(!Buffer.empty());
+
+  ArrayRef<char> ThisGroup;
+  int InitialDigits = ((Buffer.size() - 1) % 3) + 1;
+  ThisGroup = Buffer.take_front(InitialDigits);
+  S.write(ThisGroup.data(), ThisGroup.size());
+
+  Buffer = Buffer.drop_front(InitialDigits);
+  assert(Buffer.size() % 3 == 0);
+  while (!Buffer.empty()) {
+    S << ',';
+    ThisGroup = Buffer.take_front(3);
+    S.write(ThisGroup.data(), 3);
+    Buffer = Buffer.drop_front(3);
+  }
+}
+
+template <typename T>
+static void write_unsigned_impl(raw_ostream &S, T N, size_t MinDigits,
+                                IntegerStyle Style, bool IsNegative) {
+  static_assert(std::is_unsigned<T>::value, "Value is not unsigned!");
+
+  char NumberBuffer[128];
+  std::memset(NumberBuffer, '0', sizeof(NumberBuffer));
+
+  size_t Len = 0;
+  Len = format_to_buffer(N, NumberBuffer);
+
+  if (IsNegative)
+    S << '-';
+
+  if (Len < MinDigits && Style != IntegerStyle::Number) {
+    for (size_t I = Len; I < MinDigits; ++I)
+      S << '0';
+  }
+
+  if (Style == IntegerStyle::Number) {
+    writeWithCommas(S, ArrayRef<char>(std::end(NumberBuffer) - Len, Len));
+  } else {
+    S.write(std::end(NumberBuffer) - Len, Len);
+  }
+}
+
+template <typename T>
+static void write_unsigned(raw_ostream &S, T N, size_t MinDigits,
+                           IntegerStyle Style, bool IsNegative = false) {
+  // Output using 32-bit div/mod if possible.
+  if (N == static_cast<uint32_t>(N))
+    write_unsigned_impl(S, static_cast<uint32_t>(N), MinDigits, Style,
+                        IsNegative);
+  else
+    write_unsigned_impl(S, N, MinDigits, Style, IsNegative);
+}
+
+template <typename T>
+static void write_signed(raw_ostream &S, T N, size_t MinDigits,
+                         IntegerStyle Style) {
+  static_assert(std::is_signed<T>::value, "Value is not signed!");
+
+  using UnsignedT = typename std::make_unsigned<T>::type;
+
+  if (N >= 0) {
+    write_unsigned(S, static_cast<UnsignedT>(N), MinDigits, Style);
+    return;
+  }
+
+  UnsignedT UN = -(UnsignedT)N;
+  write_unsigned(S, UN, MinDigits, Style, true);
+}
+
+void llvm::write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
+                         IntegerStyle Style) {
+  write_unsigned(S, N, MinDigits, Style);
+}
+
+void llvm::write_integer(raw_ostream &S, int N, size_t MinDigits,
+                         IntegerStyle Style) {
+  write_signed(S, N, MinDigits, Style);
+}
+
+void llvm::write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
+                         IntegerStyle Style) {
+  write_unsigned(S, N, MinDigits, Style);
+}
+
+void llvm::write_integer(raw_ostream &S, long N, size_t MinDigits,
+                         IntegerStyle Style) {
+  write_signed(S, N, MinDigits, Style);
+}
+
+void llvm::write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
+                         IntegerStyle Style) {
+  write_unsigned(S, N, MinDigits, Style);
+}
+
+void llvm::write_integer(raw_ostream &S, long long N, size_t MinDigits,
+                         IntegerStyle Style) {
+  write_signed(S, N, MinDigits, Style);
+}
+
+void llvm::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
+                     Optional<size_t> Width) {
+  const size_t kMaxWidth = 128u;
+
+  size_t W = std::min(kMaxWidth, Width.getValueOr(0u));
+
+  unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
+  bool Prefix = (Style == HexPrintStyle::PrefixLower ||
+                 Style == HexPrintStyle::PrefixUpper);
+  bool Upper =
+      (Style == HexPrintStyle::Upper || Style == HexPrintStyle::PrefixUpper);
+  unsigned PrefixChars = Prefix ? 2 : 0;
+  unsigned NumChars =
+      std::max(static_cast<unsigned>(W), std::max(1u, Nibbles) + PrefixChars);
+
+  char NumberBuffer[kMaxWidth];
+  ::memset(NumberBuffer, '0', llvm::array_lengthof(NumberBuffer));
+  if (Prefix)
+    NumberBuffer[1] = 'x';
+  char *EndPtr = NumberBuffer + NumChars;
+  char *CurPtr = EndPtr;
+  while (N) {
+    unsigned char x = static_cast<unsigned char>(N) % 16;
+    *--CurPtr = hexdigit(x, !Upper);
+    N /= 16;
+  }
+
+  S.write(NumberBuffer, NumChars);
+}
+
+void llvm::write_double(raw_ostream &S, double N, FloatStyle Style,
+                        Optional<size_t> Precision) {
+  size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));
+
+  if (std::isnan(N)) {
+    S << "nan";
+    return;
+  } else if (std::isinf(N)) {
+    S << "INF";
+    return;
+  }
+
+  char Letter;
+  if (Style == FloatStyle::Exponent)
+    Letter = 'e';
+  else if (Style == FloatStyle::ExponentUpper)
+    Letter = 'E';
+  else
+    Letter = 'f';
+
+  SmallString<8> Spec;
+  llvm::raw_svector_ostream Out(Spec);
+  Out << "%." << Prec << Letter;
+
+  if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
+#ifdef _WIN32
+// On MSVCRT and compatible, output of %e is incompatible to Posix
+// by default. Number of exponent digits should be at least 2. "%+03d"
+// FIXME: Implement our formatter to here or Support/Format.h!
+#if defined(__MINGW32__)
+    // FIXME: It should be generic to C++11.
+    if (N == 0.0 && std::signbit(N)) {
+      char NegativeZero[] = "-0.000000e+00";
+      if (Style == FloatStyle::ExponentUpper)
+        NegativeZero[strlen(NegativeZero) - 4] = 'E';
+      S << NegativeZero;
+      return;
+    }
+#else
+    int fpcl = _fpclass(N);
+
+    // negative zero
+    if (fpcl == _FPCLASS_NZ) {
+      char NegativeZero[] = "-0.000000e+00";
+      if (Style == FloatStyle::ExponentUpper)
+        NegativeZero[strlen(NegativeZero) - 4] = 'E';
+      S << NegativeZero;
+      return;
+    }
+#endif
+
+    char buf[32];
+    unsigned len;
+    len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
+    if (len <= sizeof(buf) - 2) {
+      if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
+          buf[len - 3] == '0') {
+        int cs = buf[len - 4];
+        if (cs == '+' || cs == '-') {
+          int c1 = buf[len - 2];
+          int c0 = buf[len - 1];
+          if (isdigit(static_cast<unsigned char>(c1)) &&
+              isdigit(static_cast<unsigned char>(c0))) {
+            // Trim leading '0': "...e+012" -> "...e+12\0"
+            buf[len - 3] = c1;
+            buf[len - 2] = c0;
+            buf[--len] = 0;
+          }
+        }
+      }
+      S << buf;
+      return;
+    }
+#endif
+  }
+
+  if (Style == FloatStyle::Percent)
+    N *= 100.0;
+
+  char Buf[32];
+  format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));
+  S << Buf;
+  if (Style == FloatStyle::Percent)
+    S << '%';
+}
+
+bool llvm::isPrefixedHexStyle(HexPrintStyle S) {
+  return (S == HexPrintStyle::PrefixLower || S == HexPrintStyle::PrefixUpper);
+}
+
+size_t llvm::getDefaultPrecision(FloatStyle Style) {
+  switch (Style) {
+  case FloatStyle::Exponent:
+  case FloatStyle::ExponentUpper:
+    return 6; // Number of decimal places.
+  case FloatStyle::Fixed:
+  case FloatStyle::Percent:
+    return 2; // Number of decimal places.
+  }
+  LLVM_BUILTIN_UNREACHABLE;
+}
diff --git a/binaryen/third_party/llvm-project/ObjectFile.cpp b/binaryen/third_party/llvm-project/ObjectFile.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/ObjectFile.cpp
@@ -0,0 +1,112 @@
+//===- ObjectFile.cpp - File format independent object file ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a file format independent ObjectFile class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstdint>
+#include <memory>
+#include <system_error>
+
+using namespace llvm;
+using namespace object;
+
+void ObjectFile::anchor() {}
+
+ObjectFile::ObjectFile(unsigned int Type, MemoryBufferRef Source)
+    : SymbolicFile(Type, Source) {}
+
+bool SectionRef::containsSymbol(SymbolRef S) const {
+  llvm_unreachable("containsSymbol"); // XXX BINARYEN
+}
+
+uint64_t ObjectFile::getSymbolValue(DataRefImpl Ref) const {
+  uint32_t Flags = getSymbolFlags(Ref);
+  if (Flags & SymbolRef::SF_Undefined)
+    return 0;
+  if (Flags & SymbolRef::SF_Common)
+    return getCommonSymbolSize(Ref);
+  return getSymbolValueImpl(Ref);
+}
+
+Error ObjectFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const {
+  Expected<StringRef> Name = getSymbolName(Symb);
+  if (!Name)
+    return Name.takeError();
+  OS << *Name;
+  return Error::success();
+}
+
+uint32_t ObjectFile::getSymbolAlignment(DataRefImpl DRI) const { return 0; }
+
+bool ObjectFile::isSectionBitcode(DataRefImpl Sec) const {
+  Expected<StringRef> NameOrErr = getSectionName(Sec);
+  if (NameOrErr)
+    return *NameOrErr == ".llvmbc";
+  consumeError(NameOrErr.takeError());
+  return false;
+}
+
+bool ObjectFile::isSectionStripped(DataRefImpl Sec) const { return false; }
+
+bool ObjectFile::isBerkeleyText(DataRefImpl Sec) const {
+  return isSectionText(Sec);
+}
+
+bool ObjectFile::isBerkeleyData(DataRefImpl Sec) const {
+  return isSectionData(Sec);
+}
+
+Expected<section_iterator>
+ObjectFile::getRelocatedSection(DataRefImpl Sec) const {
+  return section_iterator(SectionRef(Sec, this));
+}
+
+Triple ObjectFile::makeTriple() const {
+  llvm_unreachable("makeTriple"); // XXX BINARYEN
+}
+
+Expected<std::unique_ptr<ObjectFile>>
+ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type) {
+  llvm_unreachable("createObjectFile"); // XXX BINARYEN
+}
+
+#if 0 // XXX BINARYEN
+Expected<OwningBinary<ObjectFile>>
+ObjectFile::createObjectFile(StringRef ObjectPath) {
+  ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
+      MemoryBuffer::getFile(ObjectPath);
+  if (std::error_code EC = FileOrErr.getError())
+    return errorCodeToError(EC);
+  std::unique_ptr<MemoryBuffer> Buffer = std::move(FileOrErr.get());
+
+  Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
+      createObjectFile(Buffer->getMemBufferRef());
+  if (Error Err = ObjOrErr.takeError())
+    return std::move(Err);
+  std::unique_ptr<ObjectFile> Obj = std::move(ObjOrErr.get());
+
+  return OwningBinary<ObjectFile>(std::move(Obj), std::move(Buffer));
+}
+#endif
diff --git a/binaryen/third_party/llvm-project/Optional.cpp b/binaryen/third_party/llvm-project/Optional.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/Optional.cpp
@@ -0,0 +1,14 @@
+//===- Optional.cpp - Optional values ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/raw_ostream.h"
+
+llvm::raw_ostream &llvm::operator<<(raw_ostream &OS, NoneType) {
+  return OS << "None";
+}
diff --git a/binaryen/third_party/llvm-project/Path.cpp b/binaryen/third_party/llvm-project/Path.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/Path.cpp
@@ -0,0 +1,1217 @@
+//===-- Path.cpp - Implement OS Path Concept ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements the operating system Path API.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Path.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include <cctype>
+#include <cstring>
+
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+using namespace llvm;
+using namespace llvm::support::endian;
+
+namespace {
+  using llvm::StringRef;
+  using llvm::sys::path::is_separator;
+  using llvm::sys::path::Style;
+
+  inline Style real_style(Style style) {
+#ifdef _WIN32
+    return (style == Style::posix) ? Style::posix : Style::windows;
+#else
+    return (style == Style::windows) ? Style::windows : Style::posix;
+#endif
+  }
+
+  inline const char *separators(Style style) {
+    if (real_style(style) == Style::windows)
+      return "\\/";
+    return "/";
+  }
+
+  inline char preferred_separator(Style style) {
+    if (real_style(style) == Style::windows)
+      return '\\';
+    return '/';
+  }
+
+  StringRef find_first_component(StringRef path, Style style) {
+    // Look for this first component in the following order.
+    // * empty (in this case we return an empty string)
+    // * either C: or {//,\\}net.
+    // * {/,\}
+    // * {file,directory}name
+
+    if (path.empty())
+      return path;
+
+    if (real_style(style) == Style::windows) {
+      // C:
+      if (path.size() >= 2 &&
+          std::isalpha(static_cast<unsigned char>(path[0])) && path[1] == ':')
+        return path.substr(0, 2);
+    }
+
+    // //net
+    if ((path.size() > 2) && is_separator(path[0], style) &&
+        path[0] == path[1] && !is_separator(path[2], style)) {
+      // Find the next directory separator.
+      size_t end = path.find_first_of(separators(style), 2);
+      return path.substr(0, end);
+    }
+
+    // {/,\}
+    if (is_separator(path[0], style))
+      return path.substr(0, 1);
+
+    // * {file,directory}name
+    size_t end = path.find_first_of(separators(style));
+    return path.substr(0, end);
+  }
+
+  // Returns the first character of the filename in str. For paths ending in
+  // '/', it returns the position of the '/'.
+  size_t filename_pos(StringRef str, Style style) {
+    if (str.size() > 0 && is_separator(str[str.size() - 1], style))
+      return str.size() - 1;
+
+    size_t pos = str.find_last_of(separators(style), str.size() - 1);
+
+    if (real_style(style) == Style::windows) {
+      if (pos == StringRef::npos)
+        pos = str.find_last_of(':', str.size() - 2);
+    }
+
+    if (pos == StringRef::npos || (pos == 1 && is_separator(str[0], style)))
+      return 0;
+
+    return pos + 1;
+  }
+
+  // Returns the position of the root directory in str. If there is no root
+  // directory in str, it returns StringRef::npos.
+  size_t root_dir_start(StringRef str, Style style) {
+    // case "c:/"
+    if (real_style(style) == Style::windows) {
+      if (str.size() > 2 && str[1] == ':' && is_separator(str[2], style))
+        return 2;
+    }
+
+    // case "//net"
+    if (str.size() > 3 && is_separator(str[0], style) && str[0] == str[1] &&
+        !is_separator(str[2], style)) {
+      return str.find_first_of(separators(style), 2);
+    }
+
+    // case "/"
+    if (str.size() > 0 && is_separator(str[0], style))
+      return 0;
+
+    return StringRef::npos;
+  }
+
+  // Returns the position past the end of the "parent path" of path. The parent
+  // path will not end in '/', unless the parent is the root directory. If the
+  // path has no parent, 0 is returned.
+  size_t parent_path_end(StringRef path, Style style) {
+    size_t end_pos = filename_pos(path, style);
+
+    bool filename_was_sep =
+        path.size() > 0 && is_separator(path[end_pos], style);
+
+    // Skip separators until we reach root dir (or the start of the string).
+    size_t root_dir_pos = root_dir_start(path, style);
+    while (end_pos > 0 &&
+           (root_dir_pos == StringRef::npos || end_pos > root_dir_pos) &&
+           is_separator(path[end_pos - 1], style))
+      --end_pos;
+
+    if (end_pos == root_dir_pos && !filename_was_sep) {
+      // We've reached the root dir and the input path was *not* ending in a
+      // sequence of slashes. Include the root dir in the parent path.
+      return root_dir_pos + 1;
+    }
+
+    // Otherwise, just include before the last slash.
+    return end_pos;
+  }
+} // end unnamed namespace
+
+enum FSEntity {
+  FS_Dir,
+  FS_File,
+  FS_Name
+};
+
+static std::error_code
+createUniqueEntity(const Twine &Model, int &ResultFD,
+                   SmallVectorImpl<char> &ResultPath, bool MakeAbsolute,
+                   unsigned Mode, FSEntity Type,
+                   sys::fs::OpenFlags Flags = sys::fs::OF_None) {
+  llvm_unreachable("createUniqueEntity"); // XXX BINARYEN
+}
+
+namespace llvm {
+namespace sys  {
+namespace path {
+
+const_iterator begin(StringRef path, Style style) {
+  const_iterator i;
+  i.Path      = path;
+  i.Component = find_first_component(path, style);
+  i.Position  = 0;
+  i.S = style;
+  return i;
+}
+
+const_iterator end(StringRef path) {
+  const_iterator i;
+  i.Path      = path;
+  i.Position  = path.size();
+  return i;
+}
+
+const_iterator &const_iterator::operator++() {
+  assert(Position < Path.size() && "Tried to increment past end!");
+
+  // Increment Position to past the current component
+  Position += Component.size();
+
+  // Check for end.
+  if (Position == Path.size()) {
+    Component = StringRef();
+    return *this;
+  }
+
+  // Both POSIX and Windows treat paths that begin with exactly two separators
+  // specially.
+  bool was_net = Component.size() > 2 && is_separator(Component[0], S) &&
+                 Component[1] == Component[0] && !is_separator(Component[2], S);
+
+  // Handle separators.
+  if (is_separator(Path[Position], S)) {
+    // Root dir.
+    if (was_net ||
+        // c:/
+        (real_style(S) == Style::windows && Component.endswith(":"))) {
+      Component = Path.substr(Position, 1);
+      return *this;
+    }
+
+    // Skip extra separators.
+    while (Position != Path.size() && is_separator(Path[Position], S)) {
+      ++Position;
+    }
+
+    // Treat trailing '/' as a '.', unless it is the root dir.
+    if (Position == Path.size() && Component != "/") {
+      --Position;
+      Component = ".";
+      return *this;
+    }
+  }
+
+  // Find next component.
+  size_t end_pos = Path.find_first_of(separators(S), Position);
+  Component = Path.slice(Position, end_pos);
+
+  return *this;
+}
+
+bool const_iterator::operator==(const const_iterator &RHS) const {
+  return Path.begin() == RHS.Path.begin() && Position == RHS.Position;
+}
+
+ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const {
+  return Position - RHS.Position;
+}
+
+reverse_iterator rbegin(StringRef Path, Style style) {
+  reverse_iterator I;
+  I.Path = Path;
+  I.Position = Path.size();
+  I.S = style;
+  ++I;
+  return I;
+}
+
+reverse_iterator rend(StringRef Path) {
+  reverse_iterator I;
+  I.Path = Path;
+  I.Component = Path.substr(0, 0);
+  I.Position = 0;
+  return I;
+}
+
+reverse_iterator &reverse_iterator::operator++() {
+  size_t root_dir_pos = root_dir_start(Path, S);
+
+  // Skip separators unless it's the root directory.
+  size_t end_pos = Position;
+  while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
+         is_separator(Path[end_pos - 1], S))
+    --end_pos;
+
+  // Treat trailing '/' as a '.', unless it is the root dir.
+  if (Position == Path.size() && !Path.empty() &&
+      is_separator(Path.back(), S) &&
+      (root_dir_pos == StringRef::npos || end_pos - 1 > root_dir_pos)) {
+    --Position;
+    Component = ".";
+    return *this;
+  }
+
+  // Find next separator.
+  size_t start_pos = filename_pos(Path.substr(0, end_pos), S);
+  Component = Path.slice(start_pos, end_pos);
+  Position = start_pos;
+  return *this;
+}
+
+bool reverse_iterator::operator==(const reverse_iterator &RHS) const {
+  return Path.begin() == RHS.Path.begin() && Component == RHS.Component &&
+         Position == RHS.Position;
+}
+
+ptrdiff_t reverse_iterator::operator-(const reverse_iterator &RHS) const {
+  return Position - RHS.Position;
+}
+
+StringRef root_path(StringRef path, Style style) {
+  const_iterator b = begin(path, style), pos = b, e = end(path);
+  if (b != e) {
+    bool has_net =
+        b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
+    bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
+
+    if (has_net || has_drive) {
+      if ((++pos != e) && is_separator((*pos)[0], style)) {
+        // {C:/,//net/}, so get the first two components.
+        return path.substr(0, b->size() + pos->size());
+      } else {
+        // just {C:,//net}, return the first component.
+        return *b;
+      }
+    }
+
+    // POSIX style root directory.
+    if (is_separator((*b)[0], style)) {
+      return *b;
+    }
+  }
+
+  return StringRef();
+}
+
+StringRef root_name(StringRef path, Style style) {
+  const_iterator b = begin(path, style), e = end(path);
+  if (b != e) {
+    bool has_net =
+        b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
+    bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
+
+    if (has_net || has_drive) {
+      // just {C:,//net}, return the first component.
+      return *b;
+    }
+  }
+
+  // No path or no name.
+  return StringRef();
+}
+
+StringRef root_directory(StringRef path, Style style) {
+  const_iterator b = begin(path, style), pos = b, e = end(path);
+  if (b != e) {
+    bool has_net =
+        b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
+    bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
+
+    if ((has_net || has_drive) &&
+        // {C:,//net}, skip to the next component.
+        (++pos != e) && is_separator((*pos)[0], style)) {
+      return *pos;
+    }
+
+    // POSIX style root directory.
+    if (!has_net && is_separator((*b)[0], style)) {
+      return *b;
+    }
+  }
+
+  // No path or no root.
+  return StringRef();
+}
+
+StringRef relative_path(StringRef path, Style style) {
+  StringRef root = root_path(path, style);
+  return path.substr(root.size());
+}
+
+void append(SmallVectorImpl<char> &path, Style style, const Twine &a,
+            const Twine &b, const Twine &c, const Twine &d) {
+  SmallString<32> a_storage;
+  SmallString<32> b_storage;
+  SmallString<32> c_storage;
+  SmallString<32> d_storage;
+
+  SmallVector<StringRef, 4> components;
+  if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage));
+  if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage));
+  if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage));
+  if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage));
+
+  for (auto &component : components) {
+    bool path_has_sep =
+        !path.empty() && is_separator(path[path.size() - 1], style);
+    if (path_has_sep) {
+      // Strip separators from beginning of component.
+      size_t loc = component.find_first_not_of(separators(style));
+      StringRef c = component.substr(loc);
+
+      // Append it.
+      path.append(c.begin(), c.end());
+      continue;
+    }
+
+    bool component_has_sep =
+        !component.empty() && is_separator(component[0], style);
+    if (!component_has_sep &&
+        !(path.empty() || has_root_name(component, style))) {
+      // Add a separator.
+      path.push_back(preferred_separator(style));
+    }
+
+    path.append(component.begin(), component.end());
+  }
+}
+
+void append(SmallVectorImpl<char> &path, const Twine &a, const Twine &b,
+            const Twine &c, const Twine &d) {
+  append(path, Style::native, a, b, c, d);
+}
+
+void append(SmallVectorImpl<char> &path, const_iterator begin,
+            const_iterator end, Style style) {
+  for (; begin != end; ++begin)
+    path::append(path, style, *begin);
+}
+
+StringRef parent_path(StringRef path, Style style) {
+  size_t end_pos = parent_path_end(path, style);
+  if (end_pos == StringRef::npos)
+    return StringRef();
+  else
+    return path.substr(0, end_pos);
+}
+
+void remove_filename(SmallVectorImpl<char> &path, Style style) {
+  size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()), style);
+  if (end_pos != StringRef::npos)
+    path.set_size(end_pos);
+}
+
+void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
+                       Style style) {
+  StringRef p(path.begin(), path.size());
+  SmallString<32> ext_storage;
+  StringRef ext = extension.toStringRef(ext_storage);
+
+  // Erase existing extension.
+  size_t pos = p.find_last_of('.');
+  if (pos != StringRef::npos && pos >= filename_pos(p, style))
+    path.set_size(pos);
+
+  // Append '.' if needed.
+  if (ext.size() > 0 && ext[0] != '.')
+    path.push_back('.');
+
+  // Append extension.
+  path.append(ext.begin(), ext.end());
+}
+
+void replace_path_prefix(SmallVectorImpl<char> &Path,
+                         const StringRef &OldPrefix, const StringRef &NewPrefix,
+                         Style style) {
+  if (OldPrefix.empty() && NewPrefix.empty())
+    return;
+
+  StringRef OrigPath(Path.begin(), Path.size());
+  if (!OrigPath.startswith(OldPrefix))
+    return;
+
+  // If prefixes have the same size we can simply copy the new one over.
+  if (OldPrefix.size() == NewPrefix.size()) {
+    llvm::copy(NewPrefix, Path.begin());
+    return;
+  }
+
+  StringRef RelPath = OrigPath.substr(OldPrefix.size());
+  SmallString<256> NewPath;
+  path::append(NewPath, style, NewPrefix);
+  path::append(NewPath, style, RelPath);
+  Path.swap(NewPath);
+}
+
+void native(const Twine &path, SmallVectorImpl<char> &result, Style style) {
+  assert((!path.isSingleStringRef() ||
+          path.getSingleStringRef().data() != result.data()) &&
+         "path and result are not allowed to overlap!");
+  // Clear result.
+  result.clear();
+  path.toVector(result);
+  native(result, style);
+}
+
+void native(SmallVectorImpl<char> &Path, Style style) {
+  if (Path.empty())
+    return;
+  if (real_style(style) == Style::windows) {
+    std::replace(Path.begin(), Path.end(), '/', '\\');
+    if (Path[0] == '~' && (Path.size() == 1 || is_separator(Path[1], style))) {
+      llvm_unreachable("BINARYEN native");
+#if 0
+      SmallString<128> PathHome;
+      home_directory(PathHome);
+      PathHome.append(Path.begin() + 1, Path.end());
+      Path = PathHome;
+#endif
+    }
+  } else {
+    for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) {
+      if (*PI == '\\') {
+        auto PN = PI + 1;
+        if (PN < PE && *PN == '\\')
+          ++PI; // increment once, the for loop will move over the escaped slash
+        else
+          *PI = '/';
+      }
+    }
+  }
+}
+
+std::string convert_to_slash(StringRef path, Style style) {
+  if (real_style(style) != Style::windows)
+    return path;
+
+  std::string s = path.str();
+  std::replace(s.begin(), s.end(), '\\', '/');
+  return s;
+}
+
+StringRef filename(StringRef path, Style style) { return *rbegin(path, style); }
+
+StringRef stem(StringRef path, Style style) {
+  StringRef fname = filename(path, style);
+  size_t pos = fname.find_last_of('.');
+  if (pos == StringRef::npos)
+    return fname;
+  else
+    if ((fname.size() == 1 && fname == ".") ||
+        (fname.size() == 2 && fname == ".."))
+      return fname;
+    else
+      return fname.substr(0, pos);
+}
+
+StringRef extension(StringRef path, Style style) {
+  StringRef fname = filename(path, style);
+  size_t pos = fname.find_last_of('.');
+  if (pos == StringRef::npos)
+    return StringRef();
+  else
+    if ((fname.size() == 1 && fname == ".") ||
+        (fname.size() == 2 && fname == ".."))
+      return StringRef();
+    else
+      return fname.substr(pos);
+}
+
+bool is_separator(char value, Style style) {
+  if (value == '/')
+    return true;
+  if (real_style(style) == Style::windows)
+    return value == '\\';
+  return false;
+}
+
+StringRef get_separator(Style style) {
+  if (real_style(style) == Style::windows)
+    return "\\";
+  return "/";
+}
+
+bool has_root_name(const Twine &path, Style style) {
+  SmallString<128> path_storage;
+  StringRef p = path.toStringRef(path_storage);
+
+  return !root_name(p, style).empty();
+}
+
+bool has_root_directory(const Twine &path, Style style) {
+  SmallString<128> path_storage;
+  StringRef p = path.toStringRef(path_storage);
+
+  return !root_directory(p, style).empty();
+}
+
+bool has_root_path(const Twine &path, Style style) {
+  SmallString<128> path_storage;
+  StringRef p = path.toStringRef(path_storage);
+
+  return !root_path(p, style).empty();
+}
+
+bool has_relative_path(const Twine &path, Style style) {
+  SmallString<128> path_storage;
+  StringRef p = path.toStringRef(path_storage);
+
+  return !relative_path(p, style).empty();
+}
+
+bool has_filename(const Twine &path, Style style) {
+  SmallString<128> path_storage;
+  StringRef p = path.toStringRef(path_storage);
+
+  return !filename(p, style).empty();
+}
+
+bool has_parent_path(const Twine &path, Style style) {
+  SmallString<128> path_storage;
+  StringRef p = path.toStringRef(path_storage);
+
+  return !parent_path(p, style).empty();
+}
+
+bool has_stem(const Twine &path, Style style) {
+  SmallString<128> path_storage;
+  StringRef p = path.toStringRef(path_storage);
+
+  return !stem(p, style).empty();
+}
+
+bool has_extension(const Twine &path, Style style) {
+  SmallString<128> path_storage;
+  StringRef p = path.toStringRef(path_storage);
+
+  return !extension(p, style).empty();
+}
+
+bool is_absolute(const Twine &path, Style style) {
+  SmallString<128> path_storage;
+  StringRef p = path.toStringRef(path_storage);
+
+  bool rootDir = has_root_directory(p, style);
+  bool rootName =
+      (real_style(style) != Style::windows) || has_root_name(p, style);
+
+  return rootDir && rootName;
+}
+
+bool is_relative(const Twine &path, Style style) {
+  return !is_absolute(path, style);
+}
+
+StringRef remove_leading_dotslash(StringRef Path, Style style) {
+  // Remove leading "./" (or ".//" or "././" etc.)
+  while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1], style)) {
+    Path = Path.substr(2);
+    while (Path.size() > 0 && is_separator(Path[0], style))
+      Path = Path.substr(1);
+  }
+  return Path;
+}
+
+static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot,
+                                    Style style) {
+  SmallVector<StringRef, 16> components;
+
+  // Skip the root path, then look for traversal in the components.
+  StringRef rel = path::relative_path(path, style);
+  for (StringRef C :
+       llvm::make_range(path::begin(rel, style), path::end(rel))) {
+    if (C == ".")
+      continue;
+    // Leading ".." will remain in the path unless it's at the root.
+    if (remove_dot_dot && C == "..") {
+      if (!components.empty() && components.back() != "..") {
+        components.pop_back();
+        continue;
+      }
+      if (path::is_absolute(path, style))
+        continue;
+    }
+    components.push_back(C);
+  }
+
+  SmallString<256> buffer = path::root_path(path, style);
+  for (StringRef C : components)
+    path::append(buffer, style, C);
+  return buffer;
+}
+
+bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot,
+                 Style style) {
+  StringRef p(path.data(), path.size());
+
+  SmallString<256> result = remove_dots(p, remove_dot_dot, style);
+  if (result == path)
+    return false;
+
+  path.swap(result);
+  return true;
+}
+
+} // end namespace path
+
+#if 0 // XXX BINARYEN
+
+namespace fs {
+
+std::error_code getUniqueID(const Twine Path, UniqueID &Result) {
+  file_status Status;
+  std::error_code EC = status(Path, Status);
+  if (EC)
+    return EC;
+  Result = Status.getUniqueID();
+  return std::error_code();
+}
+
+void createUniquePath(const Twine &Model, SmallVectorImpl<char> &ResultPath,
+                      bool MakeAbsolute) {
+  SmallString<128> ModelStorage;
+  Model.toVector(ModelStorage);
+
+  if (MakeAbsolute) {
+    // Make model absolute by prepending a temp directory if it's not already.
+    if (!sys::path::is_absolute(Twine(ModelStorage))) {
+      SmallString<128> TDir;
+      sys::path::system_temp_directory(true, TDir);
+      sys::path::append(TDir, Twine(ModelStorage));
+      ModelStorage.swap(TDir);
+    }
+  }
+
+  ResultPath = ModelStorage;
+  ResultPath.push_back(0);
+  ResultPath.pop_back();
+
+  // Replace '%' with random chars.
+  for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) {
+    if (ModelStorage[i] == '%')
+      ResultPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15];
+  }
+}
+
+std::error_code createUniqueFile(const Twine &Model, int &ResultFd,
+                                 SmallVectorImpl<char> &ResultPath,
+                                 unsigned Mode) {
+  return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File);
+}
+
+static std::error_code createUniqueFile(const Twine &Model, int &ResultFd,
+                                        SmallVectorImpl<char> &ResultPath,
+                                        unsigned Mode, OpenFlags Flags) {
+  return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File,
+                            Flags);
+}
+
+std::error_code createUniqueFile(const Twine &Model,
+                                 SmallVectorImpl<char> &ResultPath,
+                                 unsigned Mode) {
+  int FD;
+  auto EC = createUniqueFile(Model, FD, ResultPath, Mode);
+  if (EC)
+    return EC;
+  // FD is only needed to avoid race conditions. Close it right away.
+  close(FD);
+  return EC;
+}
+
+static std::error_code
+createTemporaryFile(const Twine &Model, int &ResultFD,
+                    llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) {
+  SmallString<128> Storage;
+  StringRef P = Model.toNullTerminatedStringRef(Storage);
+  assert(P.find_first_of(separators(Style::native)) == StringRef::npos &&
+         "Model must be a simple filename.");
+  // Use P.begin() so that createUniqueEntity doesn't need to recreate Storage.
+  return createUniqueEntity(P.begin(), ResultFD, ResultPath, true,
+                            owner_read | owner_write, Type);
+}
+
+static std::error_code
+createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD,
+                    llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) {
+  const char *Middle = Suffix.empty() ? "-%%%%%%" : "-%%%%%%.";
+  return createTemporaryFile(Prefix + Middle + Suffix, ResultFD, ResultPath,
+                             Type);
+}
+
+std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
+                                    int &ResultFD,
+                                    SmallVectorImpl<char> &ResultPath) {
+  return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File);
+}
+
+std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
+                                    SmallVectorImpl<char> &ResultPath) {
+  int FD;
+  auto EC = createTemporaryFile(Prefix, Suffix, FD, ResultPath);
+  if (EC)
+    return EC;
+  // FD is only needed to avoid race conditions. Close it right away.
+  close(FD);
+  return EC;
+}
+
+
+// This is a mkdtemp with a different pattern. We use createUniqueEntity mostly
+// for consistency. We should try using mkdtemp.
+std::error_code createUniqueDirectory(const Twine &Prefix,
+                                      SmallVectorImpl<char> &ResultPath) {
+  int Dummy;
+  return createUniqueEntity(Prefix + "-%%%%%%", Dummy, ResultPath, true, 0,
+                            FS_Dir);
+}
+
+std::error_code
+getPotentiallyUniqueFileName(const Twine &Model,
+                             SmallVectorImpl<char> &ResultPath) {
+  int Dummy;
+  return createUniqueEntity(Model, Dummy, ResultPath, false, 0, FS_Name);
+}
+
+std::error_code
+getPotentiallyUniqueTempFileName(const Twine &Prefix, StringRef Suffix,
+                                 SmallVectorImpl<char> &ResultPath) {
+  int Dummy;
+  return createTemporaryFile(Prefix, Suffix, Dummy, ResultPath, FS_Name);
+}
+
+void make_absolute(const Twine &current_directory,
+                   SmallVectorImpl<char> &path) {
+  StringRef p(path.data(), path.size());
+
+  bool rootDirectory = path::has_root_directory(p);
+  bool rootName = path::has_root_name(p);
+
+  // Already absolute.
+  if ((rootName || real_style(Style::native) != Style::windows) &&
+      rootDirectory)
+    return;
+
+  // All of the following conditions will need the current directory.
+  SmallString<128> current_dir;
+  current_directory.toVector(current_dir);
+
+  // Relative path. Prepend the current directory.
+  if (!rootName && !rootDirectory) {
+    // Append path to the current directory.
+    path::append(current_dir, p);
+    // Set path to the result.
+    path.swap(current_dir);
+    return;
+  }
+
+  if (!rootName && rootDirectory) {
+    StringRef cdrn = path::root_name(current_dir);
+    SmallString<128> curDirRootName(cdrn.begin(), cdrn.end());
+    path::append(curDirRootName, p);
+    // Set path to the result.
+    path.swap(curDirRootName);
+    return;
+  }
+
+  if (rootName && !rootDirectory) {
+    StringRef pRootName      = path::root_name(p);
+    StringRef bRootDirectory = path::root_directory(current_dir);
+    StringRef bRelativePath  = path::relative_path(current_dir);
+    StringRef pRelativePath  = path::relative_path(p);
+
+    SmallString<128> res;
+    path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath);
+    path.swap(res);
+    return;
+  }
+
+  llvm_unreachable("All rootName and rootDirectory combinations should have "
+                   "occurred above!");
+}
+
+std::error_code make_absolute(SmallVectorImpl<char> &path) {
+  if (path::is_absolute(path))
+    return {};
+
+  SmallString<128> current_dir;
+  if (std::error_code ec = current_path(current_dir))
+    return ec;
+
+  make_absolute(current_dir, path);
+  return {};
+}
+
+std::error_code create_directories(const Twine &Path, bool IgnoreExisting,
+                                   perms Perms) {
+  SmallString<128> PathStorage;
+  StringRef P = Path.toStringRef(PathStorage);
+
+  // Be optimistic and try to create the directory
+  std::error_code EC = create_directory(P, IgnoreExisting, Perms);
+  // If we succeeded, or had any error other than the parent not existing, just
+  // return it.
+  if (EC != errc::no_such_file_or_directory)
+    return EC;
+
+  // We failed because of a no_such_file_or_directory, try to create the
+  // parent.
+  StringRef Parent = path::parent_path(P);
+  if (Parent.empty())
+    return EC;
+
+  if ((EC = create_directories(Parent, IgnoreExisting, Perms)))
+      return EC;
+
+  return create_directory(P, IgnoreExisting, Perms);
+}
+
+static std::error_code copy_file_internal(int ReadFD, int WriteFD) {
+  const size_t BufSize = 4096;
+  char *Buf = new char[BufSize];
+  int BytesRead = 0, BytesWritten = 0;
+  for (;;) {
+    BytesRead = read(ReadFD, Buf, BufSize);
+    if (BytesRead <= 0)
+      break;
+    while (BytesRead) {
+      BytesWritten = write(WriteFD, Buf, BytesRead);
+      if (BytesWritten < 0)
+        break;
+      BytesRead -= BytesWritten;
+    }
+    if (BytesWritten < 0)
+      break;
+  }
+  delete[] Buf;
+
+  if (BytesRead < 0 || BytesWritten < 0)
+    return std::error_code(errno, std::generic_category());
+  return std::error_code();
+}
+
+#ifndef __APPLE__
+std::error_code copy_file(const Twine &From, const Twine &To) {
+  int ReadFD, WriteFD;
+  if (std::error_code EC = openFileForRead(From, ReadFD, OF_None))
+    return EC;
+  if (std::error_code EC =
+          openFileForWrite(To, WriteFD, CD_CreateAlways, OF_None)) {
+    close(ReadFD);
+    return EC;
+  }
+
+  std::error_code EC = copy_file_internal(ReadFD, WriteFD);
+
+  close(ReadFD);
+  close(WriteFD);
+
+  return EC;
+}
+#endif
+
+std::error_code copy_file(const Twine &From, int ToFD) {
+  int ReadFD;
+  if (std::error_code EC = openFileForRead(From, ReadFD, OF_None))
+    return EC;
+
+  std::error_code EC = copy_file_internal(ReadFD, ToFD);
+
+  close(ReadFD);
+
+  return EC;
+}
+
+ErrorOr<MD5::MD5Result> md5_contents(int FD) {
+  MD5 Hash;
+
+  constexpr size_t BufSize = 4096;
+  std::vector<uint8_t> Buf(BufSize);
+  int BytesRead = 0;
+  for (;;) {
+    BytesRead = read(FD, Buf.data(), BufSize);
+    if (BytesRead <= 0)
+      break;
+    Hash.update(makeArrayRef(Buf.data(), BytesRead));
+  }
+
+  if (BytesRead < 0)
+    return std::error_code(errno, std::generic_category());
+  MD5::MD5Result Result;
+  Hash.final(Result);
+  return Result;
+}
+
+ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path) {
+  int FD;
+  if (auto EC = openFileForRead(Path, FD, OF_None))
+    return EC;
+
+  auto Result = md5_contents(FD);
+  close(FD);
+  return Result;
+}
+
+bool exists(const basic_file_status &status) {
+  return status_known(status) && status.type() != file_type::file_not_found;
+}
+
+bool status_known(const basic_file_status &s) {
+  return s.type() != file_type::status_error;
+}
+
+file_type get_file_type(const Twine &Path, bool Follow) {
+  file_status st;
+  if (status(Path, st, Follow))
+    return file_type::status_error;
+  return st.type();
+}
+
+bool is_directory(const basic_file_status &status) {
+  return status.type() == file_type::directory_file;
+}
+
+std::error_code is_directory(const Twine &path, bool &result) {
+  file_status st;
+  if (std::error_code ec = status(path, st))
+    return ec;
+  result = is_directory(st);
+  return std::error_code();
+}
+
+bool is_regular_file(const basic_file_status &status) {
+  return status.type() == file_type::regular_file;
+}
+
+std::error_code is_regular_file(const Twine &path, bool &result) {
+  file_status st;
+  if (std::error_code ec = status(path, st))
+    return ec;
+  result = is_regular_file(st);
+  return std::error_code();
+}
+
+bool is_symlink_file(const basic_file_status &status) {
+  return status.type() == file_type::symlink_file;
+}
+
+std::error_code is_symlink_file(const Twine &path, bool &result) {
+  file_status st;
+  if (std::error_code ec = status(path, st, false))
+    return ec;
+  result = is_symlink_file(st);
+  return std::error_code();
+}
+
+bool is_other(const basic_file_status &status) {
+  return exists(status) &&
+         !is_regular_file(status) &&
+         !is_directory(status);
+}
+
+std::error_code is_other(const Twine &Path, bool &Result) {
+  file_status FileStatus;
+  if (std::error_code EC = status(Path, FileStatus))
+    return EC;
+  Result = is_other(FileStatus);
+  return std::error_code();
+}
+
+void directory_entry::replace_filename(const Twine &Filename, file_type Type,
+                                       basic_file_status Status) {
+  SmallString<128> PathStr = path::parent_path(Path);
+  path::append(PathStr, Filename);
+  this->Path = PathStr.str();
+  this->Type = Type;
+  this->Status = Status;
+}
+
+ErrorOr<perms> getPermissions(const Twine &Path) {
+  file_status Status;
+  if (std::error_code EC = status(Path, Status))
+    return EC;
+
+  return Status.permissions();
+}
+
+} // end namespace fs
+
+#endif // XXX BINARYEN
+
+} // end namespace sys
+} // end namespace llvm
+
+// Include the truly platform-specific parts.
+#if 0 // XXX BINARYEN - we don't need platform-specific parts.
+#if defined(LLVM_ON_UNIX)
+#include "Unix/Path.inc"
+#endif
+#if defined(_WIN32)
+#include "Windows/Path.inc"
+#endif
+#endif
+
+#if 0 // XXX BINARYEN
+
+namespace llvm {
+namespace sys {
+namespace fs {
+TempFile::TempFile(StringRef Name, int FD) : TmpName(Name), FD(FD) {}
+TempFile::TempFile(TempFile &&Other) { *this = std::move(Other); }
+TempFile &TempFile::operator=(TempFile &&Other) {
+  TmpName = std::move(Other.TmpName);
+  FD = Other.FD;
+  Other.Done = true;
+  Other.FD = -1;
+  return *this;
+}
+
+TempFile::~TempFile() { assert(Done); }
+
+Error TempFile::discard() {
+  Done = true;
+  if (FD != -1 && close(FD) == -1) {
+    std::error_code EC = std::error_code(errno, std::generic_category());
+    return errorCodeToError(EC);
+  }
+  FD = -1;
+
+#ifdef _WIN32
+  // On windows closing will remove the file.
+  TmpName = "";
+  return Error::success();
+#else
+  // Always try to close and remove.
+  std::error_code RemoveEC;
+  if (!TmpName.empty()) {
+    RemoveEC = fs::remove(TmpName);
+    sys::DontRemoveFileOnSignal(TmpName);
+    if (!RemoveEC)
+      TmpName = "";
+  }
+  return errorCodeToError(RemoveEC);
+#endif
+}
+
+Error TempFile::keep(const Twine &Name) {
+  assert(!Done);
+  Done = true;
+  // Always try to close and rename.
+#ifdef _WIN32
+  // If we can't cancel the delete don't rename.
+  auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+  std::error_code RenameEC = setDeleteDisposition(H, false);
+  if (!RenameEC) {
+    RenameEC = rename_fd(FD, Name);
+    // If rename failed because it's cross-device, copy instead
+    if (RenameEC ==
+      std::error_code(ERROR_NOT_SAME_DEVICE, std::system_category())) {
+      RenameEC = copy_file(TmpName, Name);
+      setDeleteDisposition(H, true);
+    }
+  }
+
+  // If we can't rename, discard the temporary file.
+  if (RenameEC)
+    setDeleteDisposition(H, true);
+#else
+  std::error_code RenameEC = fs::rename(TmpName, Name);
+  if (RenameEC) {
+    // If we can't rename, try to copy to work around cross-device link issues.
+    RenameEC = sys::fs::copy_file(TmpName, Name);
+    // If we can't rename or copy, discard the temporary file.
+    if (RenameEC)
+      remove(TmpName);
+  }
+  sys::DontRemoveFileOnSignal(TmpName);
+#endif
+
+  if (!RenameEC)
+    TmpName = "";
+
+  if (close(FD) == -1) {
+    std::error_code EC(errno, std::generic_category());
+    return errorCodeToError(EC);
+  }
+  FD = -1;
+
+  return errorCodeToError(RenameEC);
+}
+
+Error TempFile::keep() {
+  assert(!Done);
+  Done = true;
+
+#ifdef _WIN32
+  auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+  if (std::error_code EC = setDeleteDisposition(H, false))
+    return errorCodeToError(EC);
+#else
+  sys::DontRemoveFileOnSignal(TmpName);
+#endif
+
+  TmpName = "";
+
+  if (close(FD) == -1) {
+    std::error_code EC(errno, std::generic_category());
+    return errorCodeToError(EC);
+  }
+  FD = -1;
+
+  return Error::success();
+}
+
+Expected<TempFile> TempFile::create(const Twine &Model, unsigned Mode) {
+  int FD;
+  SmallString<128> ResultPath;
+  if (std::error_code EC =
+          createUniqueFile(Model, FD, ResultPath, Mode, OF_Delete))
+    return errorCodeToError(EC);
+
+  TempFile Ret(ResultPath, FD);
+#ifndef _WIN32
+  if (sys::RemoveFileOnSignal(ResultPath)) {
+    // Make sure we delete the file when RemoveFileOnSignal fails.
+    consumeError(Ret.discard());
+    std::error_code EC(errc::operation_not_permitted);
+    return errorCodeToError(EC);
+  }
+#endif
+  return std::move(Ret);
+}
+}
+
+} // end namsspace sys
+} // end namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/ScopedPrinter.cpp b/binaryen/third_party/llvm-project/ScopedPrinter.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/ScopedPrinter.cpp
@@ -0,0 +1,46 @@
+#include "llvm/Support/ScopedPrinter.h"
+
+#include "llvm/Support/Format.h"
+#include <cctype>
+
+using namespace llvm::support;
+
+namespace llvm {
+
+raw_ostream &operator<<(raw_ostream &OS, const HexNumber &Value) {
+  OS << "0x" << to_hexString(Value.Value);
+  return OS;
+}
+
+const std::string to_hexString(uint64_t Value, bool UpperCase) {
+  std::string number;
+  llvm::raw_string_ostream stream(number);
+  stream << format_hex_no_prefix(Value, 1, UpperCase);
+  return stream.str();
+}
+
+void ScopedPrinter::printBinaryImpl(StringRef Label, StringRef Str,
+                                    ArrayRef<uint8_t> Data, bool Block,
+                                    uint32_t StartOffset) {
+  if (Data.size() > 16)
+    Block = true;
+
+  if (Block) {
+    startLine() << Label;
+    if (!Str.empty())
+      OS << ": " << Str;
+    OS << " (\n";
+    if (!Data.empty())
+      OS << format_bytes_with_ascii(Data, StartOffset, 16, 4,
+                                    (IndentLevel + 1) * 2, true)
+         << "\n";
+    startLine() << ")\n";
+  } else {
+    startLine() << Label << ":";
+    if (!Str.empty())
+      OS << " " << Str;
+    OS << " (" << format_bytes(Data, None, Data.size(), 1, 0, true) << ")\n";
+  }
+}
+
+} // namespace llvm
diff --git a/binaryen/third_party/llvm-project/SmallVector.cpp b/binaryen/third_party/llvm-project/SmallVector.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/SmallVector.cpp
@@ -0,0 +1,65 @@
+//===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the SmallVector class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallVector.h"
+using namespace llvm;
+
+// Check that no bytes are wasted and everything is well-aligned.
+namespace {
+struct Struct16B {
+  alignas(16) void *X;
+};
+struct Struct32B {
+  alignas(32) void *X;
+};
+}
+static_assert(sizeof(SmallVector<void *, 0>) ==
+                  sizeof(unsigned) * 2 + sizeof(void *),
+              "wasted space in SmallVector size 0");
+static_assert(alignof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
+              "wrong alignment for 16-byte aligned T");
+static_assert(alignof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
+              "wrong alignment for 32-byte aligned T");
+static_assert(sizeof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
+              "missing padding for 16-byte aligned T");
+static_assert(sizeof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
+              "missing padding for 32-byte aligned T");
+static_assert(sizeof(SmallVector<void *, 1>) ==
+                  sizeof(unsigned) * 2 + sizeof(void *) * 2,
+              "wasted space in SmallVector size 1");
+
+/// grow_pod - This is an implementation of the grow() method which only works
+/// on POD-like datatypes and is out of line to reduce code duplication.
+void SmallVectorBase::grow_pod(void *FirstEl, size_t MinCapacity,
+                               size_t TSize) {
+  // Ensure we can fit the new capacity in 32 bits.
+  if (MinCapacity > UINT32_MAX)
+    report_bad_alloc_error("SmallVector capacity overflow during allocation");
+
+  size_t NewCapacity = 2 * capacity() + 1; // Always grow.
+  NewCapacity =
+      std::min(std::max(NewCapacity, MinCapacity), size_t(UINT32_MAX));
+
+  void *NewElts;
+  if (BeginX == FirstEl) {
+    NewElts = safe_malloc(NewCapacity * TSize);
+
+    // Copy the elements over.  No need to run dtors on PODs.
+    memcpy(NewElts, this->BeginX, size() * TSize);
+  } else {
+    // If this wasn't grown from the inline copy, grow the allocated space.
+    NewElts = safe_realloc(this->BeginX, NewCapacity * TSize);
+  }
+
+  this->BeginX = NewElts;
+  this->Capacity = NewCapacity;
+}
diff --git a/binaryen/third_party/llvm-project/SourceMgr.cpp b/binaryen/third_party/llvm-project/SourceMgr.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/SourceMgr.cpp
@@ -0,0 +1,503 @@
+//===- SourceMgr.cpp - Manager for Simple Source Buffers & Diagnostics ----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the SourceMgr class.  This class is used as a simple
+// substrate for diagnostics, #include handling, and other low level things for
+// simple parsers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Locale.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <limits>
+#include <memory>
+#include <string>
+#include <utility>
+
+using namespace llvm;
+
+static const size_t TabStop = 8;
+
+unsigned SourceMgr::AddIncludeFile(const std::string &Filename,
+                                   SMLoc IncludeLoc,
+                                   std::string &IncludedFile) {
+  IncludedFile = Filename;
+  ErrorOr<std::unique_ptr<MemoryBuffer>> NewBufOrErr =
+    MemoryBuffer::getFile(IncludedFile);
+
+  // If the file didn't exist directly, see if it's in an include path.
+  for (unsigned i = 0, e = IncludeDirectories.size(); i != e && !NewBufOrErr;
+       ++i) {
+    IncludedFile =
+        IncludeDirectories[i] + sys::path::get_separator().data() + Filename;
+    NewBufOrErr = MemoryBuffer::getFile(IncludedFile);
+  }
+
+  if (!NewBufOrErr)
+    return 0;
+
+  return AddNewSourceBuffer(std::move(*NewBufOrErr), IncludeLoc);
+}
+
+unsigned SourceMgr::FindBufferContainingLoc(SMLoc Loc) const {
+  for (unsigned i = 0, e = Buffers.size(); i != e; ++i)
+    if (Loc.getPointer() >= Buffers[i].Buffer->getBufferStart() &&
+        // Use <= here so that a pointer to the null at the end of the buffer
+        // is included as part of the buffer.
+        Loc.getPointer() <= Buffers[i].Buffer->getBufferEnd())
+      return i + 1;
+  return 0;
+}
+
+template <typename T>
+unsigned SourceMgr::SrcBuffer::getLineNumber(const char *Ptr) const {
+
+  // Ensure OffsetCache is allocated and populated with offsets of all the
+  // '\n' bytes.
+  std::vector<T> *Offsets = nullptr;
+  if (OffsetCache.isNull()) {
+    Offsets = new std::vector<T>();
+    OffsetCache = Offsets;
+    size_t Sz = Buffer->getBufferSize();
+    assert(Sz <= std::numeric_limits<T>::max());
+    StringRef S = Buffer->getBuffer();
+    for (size_t N = 0; N < Sz; ++N) {
+      if (S[N] == '\n') {
+        Offsets->push_back(static_cast<T>(N));
+      }
+    }
+  } else {
+    Offsets = OffsetCache.get<std::vector<T> *>();
+  }
+
+  const char *BufStart = Buffer->getBufferStart();
+  assert(Ptr >= BufStart && Ptr <= Buffer->getBufferEnd());
+  ptrdiff_t PtrDiff = Ptr - BufStart;
+  assert(PtrDiff >= 0 && static_cast<size_t>(PtrDiff) <= std::numeric_limits<T>::max());
+  T PtrOffset = static_cast<T>(PtrDiff);
+
+  // llvm::lower_bound gives the number of EOL before PtrOffset. Add 1 to get
+  // the line number.
+  return llvm::lower_bound(*Offsets, PtrOffset) - Offsets->begin() + 1;
+}
+
+SourceMgr::SrcBuffer::SrcBuffer(SourceMgr::SrcBuffer &&Other)
+  : Buffer(std::move(Other.Buffer)),
+    OffsetCache(Other.OffsetCache),
+    IncludeLoc(Other.IncludeLoc) {
+  Other.OffsetCache = nullptr;
+}
+
+SourceMgr::SrcBuffer::~SrcBuffer() {
+  if (!OffsetCache.isNull()) {
+    if (OffsetCache.is<std::vector<uint8_t>*>())
+      delete OffsetCache.get<std::vector<uint8_t>*>();
+    else if (OffsetCache.is<std::vector<uint16_t>*>())
+      delete OffsetCache.get<std::vector<uint16_t>*>();
+    else if (OffsetCache.is<std::vector<uint32_t>*>())
+      delete OffsetCache.get<std::vector<uint32_t>*>();
+    else
+      delete OffsetCache.get<std::vector<uint64_t>*>();
+    OffsetCache = nullptr;
+  }
+}
+
+std::pair<unsigned, unsigned>
+SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const {
+  if (!BufferID)
+    BufferID = FindBufferContainingLoc(Loc);
+  assert(BufferID && "Invalid Location!");
+
+  auto &SB = getBufferInfo(BufferID);
+  const char *Ptr = Loc.getPointer();
+
+  size_t Sz = SB.Buffer->getBufferSize();
+  unsigned LineNo;
+  if (Sz <= std::numeric_limits<uint8_t>::max())
+    LineNo = SB.getLineNumber<uint8_t>(Ptr);
+  else if (Sz <= std::numeric_limits<uint16_t>::max())
+    LineNo = SB.getLineNumber<uint16_t>(Ptr);
+  else if (Sz <= std::numeric_limits<uint32_t>::max())
+    LineNo = SB.getLineNumber<uint32_t>(Ptr);
+  else
+    LineNo = SB.getLineNumber<uint64_t>(Ptr);
+
+  const char *BufStart = SB.Buffer->getBufferStart();
+  size_t NewlineOffs = StringRef(BufStart, Ptr-BufStart).find_last_of("\n\r");
+  if (NewlineOffs == StringRef::npos) NewlineOffs = ~(size_t)0;
+  return std::make_pair(LineNo, Ptr-BufStart-NewlineOffs);
+}
+
+void SourceMgr::PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const {
+  if (IncludeLoc == SMLoc()) return;  // Top of stack.
+
+  unsigned CurBuf = FindBufferContainingLoc(IncludeLoc);
+  assert(CurBuf && "Invalid or unspecified location!");
+
+  PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS);
+
+  OS << "Included from "
+     << getBufferInfo(CurBuf).Buffer->getBufferIdentifier()
+     << ":" << FindLineNumber(IncludeLoc, CurBuf) << ":\n";
+}
+
+SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
+                                   const Twine &Msg,
+                                   ArrayRef<SMRange> Ranges,
+                                   ArrayRef<SMFixIt> FixIts) const {
+  // First thing to do: find the current buffer containing the specified
+  // location to pull out the source line.
+  SmallVector<std::pair<unsigned, unsigned>, 4> ColRanges;
+  std::pair<unsigned, unsigned> LineAndCol;
+  StringRef BufferID = "<unknown>";
+  std::string LineStr;
+
+  if (Loc.isValid()) {
+    unsigned CurBuf = FindBufferContainingLoc(Loc);
+    assert(CurBuf && "Invalid or unspecified location!");
+
+    const MemoryBuffer *CurMB = getMemoryBuffer(CurBuf);
+    BufferID = CurMB->getBufferIdentifier();
+
+    // Scan backward to find the start of the line.
+    const char *LineStart = Loc.getPointer();
+    const char *BufStart = CurMB->getBufferStart();
+    while (LineStart != BufStart && LineStart[-1] != '\n' &&
+           LineStart[-1] != '\r')
+      --LineStart;
+
+    // Get the end of the line.
+    const char *LineEnd = Loc.getPointer();
+    const char *BufEnd = CurMB->getBufferEnd();
+    while (LineEnd != BufEnd && LineEnd[0] != '\n' && LineEnd[0] != '\r')
+      ++LineEnd;
+    LineStr = std::string(LineStart, LineEnd);
+
+    // Convert any ranges to column ranges that only intersect the line of the
+    // location.
+    for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
+      SMRange R = Ranges[i];
+      if (!R.isValid()) continue;
+
+      // If the line doesn't contain any part of the range, then ignore it.
+      if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart)
+        continue;
+
+      // Ignore pieces of the range that go onto other lines.
+      if (R.Start.getPointer() < LineStart)
+        R.Start = SMLoc::getFromPointer(LineStart);
+      if (R.End.getPointer() > LineEnd)
+        R.End = SMLoc::getFromPointer(LineEnd);
+
+      // Translate from SMLoc ranges to column ranges.
+      // FIXME: Handle multibyte characters.
+      ColRanges.push_back(std::make_pair(R.Start.getPointer()-LineStart,
+                                         R.End.getPointer()-LineStart));
+    }
+
+    LineAndCol = getLineAndColumn(Loc, CurBuf);
+  }
+
+  return SMDiagnostic(*this, Loc, BufferID, LineAndCol.first,
+                      LineAndCol.second-1, Kind, Msg.str(),
+                      LineStr, ColRanges, FixIts);
+}
+
+void SourceMgr::PrintMessage(raw_ostream &OS, const SMDiagnostic &Diagnostic,
+                             bool ShowColors) const {
+  // Report the message with the diagnostic handler if present.
+  if (DiagHandler) {
+    DiagHandler(Diagnostic, DiagContext);
+    return;
+  }
+
+  if (Diagnostic.getLoc().isValid()) {
+    unsigned CurBuf = FindBufferContainingLoc(Diagnostic.getLoc());
+    assert(CurBuf && "Invalid or unspecified location!");
+    PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS);
+  }
+
+  Diagnostic.print(nullptr, OS, ShowColors);
+}
+
+void SourceMgr::PrintMessage(raw_ostream &OS, SMLoc Loc,
+                             SourceMgr::DiagKind Kind,
+                             const Twine &Msg, ArrayRef<SMRange> Ranges,
+                             ArrayRef<SMFixIt> FixIts, bool ShowColors) const {
+  PrintMessage(OS, GetMessage(Loc, Kind, Msg, Ranges, FixIts), ShowColors);
+}
+
+void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
+                             const Twine &Msg, ArrayRef<SMRange> Ranges,
+                             ArrayRef<SMFixIt> FixIts, bool ShowColors) const {
+  PrintMessage(errs(), Loc, Kind, Msg, Ranges, FixIts, ShowColors);
+}
+
+//===----------------------------------------------------------------------===//
+// SMDiagnostic Implementation
+//===----------------------------------------------------------------------===//
+
+SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN,
+                           int Line, int Col, SourceMgr::DiagKind Kind,
+                           StringRef Msg, StringRef LineStr,
+                           ArrayRef<std::pair<unsigned,unsigned>> Ranges,
+                           ArrayRef<SMFixIt> Hints)
+  : SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Kind(Kind),
+    Message(Msg), LineContents(LineStr), Ranges(Ranges.vec()),
+    FixIts(Hints.begin(), Hints.end()) {
+  llvm::sort(FixIts);
+}
+
+static void buildFixItLine(std::string &CaretLine, std::string &FixItLine,
+                           ArrayRef<SMFixIt> FixIts, ArrayRef<char> SourceLine){
+  if (FixIts.empty())
+    return;
+
+  const char *LineStart = SourceLine.begin();
+  const char *LineEnd = SourceLine.end();
+
+  size_t PrevHintEndCol = 0;
+
+  for (ArrayRef<SMFixIt>::iterator I = FixIts.begin(), E = FixIts.end();
+       I != E; ++I) {
+    // If the fixit contains a newline or tab, ignore it.
+    if (I->getText().find_first_of("\n\r\t") != StringRef::npos)
+      continue;
+
+    SMRange R = I->getRange();
+
+    // If the line doesn't contain any part of the range, then ignore it.
+    if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart)
+      continue;
+
+    // Translate from SMLoc to column.
+    // Ignore pieces of the range that go onto other lines.
+    // FIXME: Handle multibyte characters in the source line.
+    unsigned FirstCol;
+    if (R.Start.getPointer() < LineStart)
+      FirstCol = 0;
+    else
+      FirstCol = R.Start.getPointer() - LineStart;
+
+    // If we inserted a long previous hint, push this one forwards, and add
+    // an extra space to show that this is not part of the previous
+    // completion. This is sort of the best we can do when two hints appear
+    // to overlap.
+    //
+    // Note that if this hint is located immediately after the previous
+    // hint, no space will be added, since the location is more important.
+    unsigned HintCol = FirstCol;
+    if (HintCol < PrevHintEndCol)
+      HintCol = PrevHintEndCol + 1;
+
+#if 0 // XXX BINARYEN
+    // FIXME: This assertion is intended to catch unintended use of multibyte
+    // characters in fixits. If we decide to do this, we'll have to track
+    // separate byte widths for the source and fixit lines.
+    assert((size_t)sys::locale::columnWidth(I->getText()) ==
+           I->getText().size());
+#endif
+
+    // This relies on one byte per column in our fixit hints.
+    unsigned LastColumnModified = HintCol + I->getText().size();
+    if (LastColumnModified > FixItLine.size())
+      FixItLine.resize(LastColumnModified, ' ');
+
+    std::copy(I->getText().begin(), I->getText().end(),
+              FixItLine.begin() + HintCol);
+
+    PrevHintEndCol = LastColumnModified;
+
+    // For replacements, mark the removal range with '~'.
+    // FIXME: Handle multibyte characters in the source line.
+    unsigned LastCol;
+    if (R.End.getPointer() >= LineEnd)
+      LastCol = LineEnd - LineStart;
+    else
+      LastCol = R.End.getPointer() - LineStart;
+
+    std::fill(&CaretLine[FirstCol], &CaretLine[LastCol], '~');
+  }
+}
+
+static void printSourceLine(raw_ostream &S, StringRef LineContents) {
+  // Print out the source line one character at a time, so we can expand tabs.
+  for (unsigned i = 0, e = LineContents.size(), OutCol = 0; i != e; ++i) {
+    size_t NextTab = LineContents.find('\t', i);
+    // If there were no tabs left, print the rest, we are done.
+    if (NextTab == StringRef::npos) {
+      S << LineContents.drop_front(i);
+      break;
+    }
+
+    // Otherwise, print from i to NextTab.
+    S << LineContents.slice(i, NextTab);
+    OutCol += NextTab - i;
+    i = NextTab;
+
+    // If we have a tab, emit at least one space, then round up to 8 columns.
+    do {
+      S << ' ';
+      ++OutCol;
+    } while ((OutCol % TabStop) != 0);
+  }
+  S << '\n';
+}
+
+static bool isNonASCII(char c) {
+  return c & 0x80;
+}
+
+void SMDiagnostic::print(const char *ProgName, raw_ostream &OS,
+                         bool ShowColors, bool ShowKindLabel) const {
+  {
+    WithColor S(OS, raw_ostream::SAVEDCOLOR, true, false, !ShowColors);
+
+    if (ProgName && ProgName[0])
+      S << ProgName << ": ";
+
+    if (!Filename.empty()) {
+      if (Filename == "-")
+        S << "<stdin>";
+      else
+        S << Filename;
+
+      if (LineNo != -1) {
+        S << ':' << LineNo;
+        if (ColumnNo != -1)
+          S << ':' << (ColumnNo + 1);
+      }
+      S << ": ";
+    }
+  }
+
+  if (ShowKindLabel) {
+    switch (Kind) {
+    case SourceMgr::DK_Error:
+      WithColor::error(OS, "", !ShowColors);
+      break;
+    case SourceMgr::DK_Warning:
+      WithColor::warning(OS, "", !ShowColors);
+      break;
+    case SourceMgr::DK_Note:
+      WithColor::note(OS, "", !ShowColors);
+      break;
+    case SourceMgr::DK_Remark:
+      WithColor::remark(OS, "", !ShowColors);
+      break;
+    }
+  }
+
+  WithColor(OS, raw_ostream::SAVEDCOLOR, true, false, !ShowColors)
+      << Message << '\n';
+
+  if (LineNo == -1 || ColumnNo == -1)
+    return;
+
+  // FIXME: If there are multibyte or multi-column characters in the source, all
+  // our ranges will be wrong. To do this properly, we'll need a byte-to-column
+  // map like Clang's TextDiagnostic. For now, we'll just handle tabs by
+  // expanding them later, and bail out rather than show incorrect ranges and
+  // misaligned fixits for any other odd characters.
+  if (find_if(LineContents, isNonASCII) != LineContents.end()) {
+    printSourceLine(OS, LineContents);
+    return;
+  }
+  size_t NumColumns = LineContents.size();
+
+  // Build the line with the caret and ranges.
+  std::string CaretLine(NumColumns+1, ' ');
+
+  // Expand any ranges.
+  for (unsigned r = 0, e = Ranges.size(); r != e; ++r) {
+    std::pair<unsigned, unsigned> R = Ranges[r];
+    std::fill(&CaretLine[R.first],
+              &CaretLine[std::min((size_t)R.second, CaretLine.size())],
+              '~');
+  }
+
+  // Add any fix-its.
+  // FIXME: Find the beginning of the line properly for multibyte characters.
+  std::string FixItInsertionLine;
+  buildFixItLine(CaretLine, FixItInsertionLine, FixIts,
+                 makeArrayRef(Loc.getPointer() - ColumnNo,
+                              LineContents.size()));
+
+  // Finally, plop on the caret.
+  if (unsigned(ColumnNo) <= NumColumns)
+    CaretLine[ColumnNo] = '^';
+  else
+    CaretLine[NumColumns] = '^';
+
+  // ... and remove trailing whitespace so the output doesn't wrap for it.  We
+  // know that the line isn't completely empty because it has the caret in it at
+  // least.
+  CaretLine.erase(CaretLine.find_last_not_of(' ')+1);
+
+  printSourceLine(OS, LineContents);
+
+  {
+    WithColor S(OS, raw_ostream::GREEN, true, false, !ShowColors);
+
+    // Print out the caret line, matching tabs in the source line.
+    for (unsigned i = 0, e = CaretLine.size(), OutCol = 0; i != e; ++i) {
+      if (i >= LineContents.size() || LineContents[i] != '\t') {
+        S << CaretLine[i];
+        ++OutCol;
+        continue;
+      }
+
+      // Okay, we have a tab.  Insert the appropriate number of characters.
+      do {
+        S << CaretLine[i];
+        ++OutCol;
+      } while ((OutCol % TabStop) != 0);
+    }
+    S << '\n';
+  }
+
+  // Print out the replacement line, matching tabs in the source line.
+  if (FixItInsertionLine.empty())
+    return;
+
+  for (size_t i = 0, e = FixItInsertionLine.size(), OutCol = 0; i < e; ++i) {
+    if (i >= LineContents.size() || LineContents[i] != '\t') {
+      OS << FixItInsertionLine[i];
+      ++OutCol;
+      continue;
+    }
+
+    // Okay, we have a tab.  Insert the appropriate number of characters.
+    do {
+      OS << FixItInsertionLine[i];
+      // FIXME: This is trying not to break up replacements, but then to re-sync
+      // with the tabs between replacements. This will fail, though, if two
+      // fix-it replacements are exactly adjacent, or if a fix-it contains a
+      // space. Really we should be precomputing column widths, which we'll
+      // need anyway for multibyte chars.
+      if (FixItInsertionLine[i] != ' ')
+        ++i;
+      ++OutCol;
+    } while (((OutCol % TabStop) != 0) && i != e);
+  }
+  OS << '\n';
+}
diff --git a/binaryen/third_party/llvm-project/StringMap.cpp b/binaryen/third_party/llvm-project/StringMap.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/StringMap.cpp
@@ -0,0 +1,261 @@
+//===--- StringMap.cpp - String Hash table map implementation -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the StringMap class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DJB.h"
+#include "llvm/Support/MathExtras.h"
+#include <cassert>
+
+using namespace llvm;
+
+/// Returns the number of buckets to allocate to ensure that the DenseMap can
+/// accommodate \p NumEntries without need to grow().
+static unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
+  // Ensure that "NumEntries * 4 < NumBuckets * 3"
+  if (NumEntries == 0)
+    return 0;
+  // +1 is required because of the strict equality.
+  // For example if NumEntries is 48, we need to return 401.
+  return NextPowerOf2(NumEntries * 4 / 3 + 1);
+}
+
+StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) {
+  ItemSize = itemSize;
+
+  // If a size is specified, initialize the table with that many buckets.
+  if (InitSize) {
+    // The table will grow when the number of entries reach 3/4 of the number of
+    // buckets. To guarantee that "InitSize" number of entries can be inserted
+    // in the table without growing, we allocate just what is needed here.
+    init(getMinBucketToReserveForEntries(InitSize));
+    return;
+  }
+
+  // Otherwise, initialize it with zero buckets to avoid the allocation.
+  TheTable = nullptr;
+  NumBuckets = 0;
+  NumItems = 0;
+  NumTombstones = 0;
+}
+
+void StringMapImpl::init(unsigned InitSize) {
+  assert((InitSize & (InitSize-1)) == 0 &&
+         "Init Size must be a power of 2 or zero!");
+
+  unsigned NewNumBuckets = InitSize ? InitSize : 16;
+  NumItems = 0;
+  NumTombstones = 0;
+
+  TheTable = static_cast<StringMapEntryBase **>(
+      safe_calloc(NewNumBuckets+1,
+                  sizeof(StringMapEntryBase **) + sizeof(unsigned)));
+
+  // Set the member only if TheTable was successfully allocated
+  NumBuckets = NewNumBuckets;
+
+  // Allocate one extra bucket, set it to look filled so the iterators stop at
+  // end.
+  TheTable[NumBuckets] = (StringMapEntryBase*)2;
+}
+
+/// LookupBucketFor - Look up the bucket that the specified string should end
+/// up in.  If it already exists as a key in the map, the Item pointer for the
+/// specified bucket will be non-null.  Otherwise, it will be null.  In either
+/// case, the FullHashValue field of the bucket will be set to the hash value
+/// of the string.
+unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
+  unsigned HTSize = NumBuckets;
+  if (HTSize == 0) {  // Hash table unallocated so far?
+    init(16);
+    HTSize = NumBuckets;
+  }
+  unsigned FullHashValue = djbHash(Name, 0);
+  unsigned BucketNo = FullHashValue & (HTSize-1);
+  unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
+
+  unsigned ProbeAmt = 1;
+  int FirstTombstone = -1;
+  while (true) {
+    StringMapEntryBase *BucketItem = TheTable[BucketNo];
+    // If we found an empty bucket, this key isn't in the table yet, return it.
+    if (LLVM_LIKELY(!BucketItem)) {
+      // If we found a tombstone, we want to reuse the tombstone instead of an
+      // empty bucket.  This reduces probing.
+      if (FirstTombstone != -1) {
+        HashTable[FirstTombstone] = FullHashValue;
+        return FirstTombstone;
+      }
+
+      HashTable[BucketNo] = FullHashValue;
+      return BucketNo;
+    }
+
+    if (BucketItem == getTombstoneVal()) {
+      // Skip over tombstones.  However, remember the first one we see.
+      if (FirstTombstone == -1) FirstTombstone = BucketNo;
+    } else if (LLVM_LIKELY(HashTable[BucketNo] == FullHashValue)) {
+      // If the full hash value matches, check deeply for a match.  The common
+      // case here is that we are only looking at the buckets (for item info
+      // being non-null and for the full hash value) not at the items.  This
+      // is important for cache locality.
+
+      // Do the comparison like this because Name isn't necessarily
+      // null-terminated!
+      char *ItemStr = (char*)BucketItem+ItemSize;
+      if (Name == StringRef(ItemStr, BucketItem->getKeyLength())) {
+        // We found a match!
+        return BucketNo;
+      }
+    }
+
+    // Okay, we didn't find the item.  Probe to the next bucket.
+    BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
+
+    // Use quadratic probing, it has fewer clumping artifacts than linear
+    // probing and has good cache behavior in the common case.
+    ++ProbeAmt;
+  }
+}
+
+/// FindKey - Look up the bucket that contains the specified key. If it exists
+/// in the map, return the bucket number of the key.  Otherwise return -1.
+/// This does not modify the map.
+int StringMapImpl::FindKey(StringRef Key) const {
+  unsigned HTSize = NumBuckets;
+  if (HTSize == 0) return -1;  // Really empty table?
+  unsigned FullHashValue = djbHash(Key, 0);
+  unsigned BucketNo = FullHashValue & (HTSize-1);
+  unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
+
+  unsigned ProbeAmt = 1;
+  while (true) {
+    StringMapEntryBase *BucketItem = TheTable[BucketNo];
+    // If we found an empty bucket, this key isn't in the table yet, return.
+    if (LLVM_LIKELY(!BucketItem))
+      return -1;
+
+    if (BucketItem == getTombstoneVal()) {
+      // Ignore tombstones.
+    } else if (LLVM_LIKELY(HashTable[BucketNo] == FullHashValue)) {
+      // If the full hash value matches, check deeply for a match.  The common
+      // case here is that we are only looking at the buckets (for item info
+      // being non-null and for the full hash value) not at the items.  This
+      // is important for cache locality.
+
+      // Do the comparison like this because NameStart isn't necessarily
+      // null-terminated!
+      char *ItemStr = (char*)BucketItem+ItemSize;
+      if (Key == StringRef(ItemStr, BucketItem->getKeyLength())) {
+        // We found a match!
+        return BucketNo;
+      }
+    }
+
+    // Okay, we didn't find the item.  Probe to the next bucket.
+    BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
+
+    // Use quadratic probing, it has fewer clumping artifacts than linear
+    // probing and has good cache behavior in the common case.
+    ++ProbeAmt;
+  }
+}
+
+/// RemoveKey - Remove the specified StringMapEntry from the table, but do not
+/// delete it.  This aborts if the value isn't in the table.
+void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
+  const char *VStr = (char*)V + ItemSize;
+  StringMapEntryBase *V2 = RemoveKey(StringRef(VStr, V->getKeyLength()));
+  (void)V2;
+  assert(V == V2 && "Didn't find key?");
+}
+
+/// RemoveKey - Remove the StringMapEntry for the specified key from the
+/// table, returning it.  If the key is not in the table, this returns null.
+StringMapEntryBase *StringMapImpl::RemoveKey(StringRef Key) {
+  int Bucket = FindKey(Key);
+  if (Bucket == -1) return nullptr;
+
+  StringMapEntryBase *Result = TheTable[Bucket];
+  TheTable[Bucket] = getTombstoneVal();
+  --NumItems;
+  ++NumTombstones;
+  assert(NumItems + NumTombstones <= NumBuckets);
+
+  return Result;
+}
+
+/// RehashTable - Grow the table, redistributing values into the buckets with
+/// the appropriate mod-of-hashtable-size.
+unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
+  unsigned NewSize;
+  unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
+
+  // If the hash table is now more than 3/4 full, or if fewer than 1/8 of
+  // the buckets are empty (meaning that many are filled with tombstones),
+  // grow/rehash the table.
+  if (LLVM_UNLIKELY(NumItems * 4 > NumBuckets * 3)) {
+    NewSize = NumBuckets*2;
+  } else if (LLVM_UNLIKELY(NumBuckets - (NumItems + NumTombstones) <=
+                           NumBuckets / 8)) {
+    NewSize = NumBuckets;
+  } else {
+    return BucketNo;
+  }
+
+  unsigned NewBucketNo = BucketNo;
+  // Allocate one extra bucket which will always be non-empty.  This allows the
+  // iterators to stop at end.
+  auto NewTableArray = static_cast<StringMapEntryBase **>(
+      safe_calloc(NewSize+1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
+
+  unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1);
+  NewTableArray[NewSize] = (StringMapEntryBase*)2;
+
+  // Rehash all the items into their new buckets.  Luckily :) we already have
+  // the hash values available, so we don't have to rehash any strings.
+  for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
+    StringMapEntryBase *Bucket = TheTable[I];
+    if (Bucket && Bucket != getTombstoneVal()) {
+      // Fast case, bucket available.
+      unsigned FullHash = HashTable[I];
+      unsigned NewBucket = FullHash & (NewSize-1);
+      if (!NewTableArray[NewBucket]) {
+        NewTableArray[FullHash & (NewSize-1)] = Bucket;
+        NewHashArray[FullHash & (NewSize-1)] = FullHash;
+        if (I == BucketNo)
+          NewBucketNo = NewBucket;
+        continue;
+      }
+
+      // Otherwise probe for a spot.
+      unsigned ProbeSize = 1;
+      do {
+        NewBucket = (NewBucket + ProbeSize++) & (NewSize-1);
+      } while (NewTableArray[NewBucket]);
+
+      // Finally found a slot.  Fill it in.
+      NewTableArray[NewBucket] = Bucket;
+      NewHashArray[NewBucket] = FullHash;
+      if (I == BucketNo)
+        NewBucketNo = NewBucket;
+    }
+  }
+
+  free(TheTable);
+
+  TheTable = NewTableArray;
+  NumBuckets = NewSize;
+  NumTombstones = 0;
+  return NewBucketNo;
+}
diff --git a/binaryen/third_party/llvm-project/StringRef.cpp b/binaryen/third_party/llvm-project/StringRef.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/StringRef.cpp
@@ -0,0 +1,519 @@
+//===-- StringRef.cpp - Lightweight String References ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/edit_distance.h"
+#include <bitset>
+
+using namespace llvm;
+
+// MSVC emits references to this into the translation units which reference it.
+#ifndef _MSC_VER
+const size_t StringRef::npos;
+#endif
+
+// strncasecmp() is not available on non-POSIX systems, so define an
+// alternative function here.
+static int ascii_strncasecmp(const char *LHS, const char *RHS, size_t Length) {
+  for (size_t I = 0; I < Length; ++I) {
+    unsigned char LHC = toLower(LHS[I]);
+    unsigned char RHC = toLower(RHS[I]);
+    if (LHC != RHC)
+      return LHC < RHC ? -1 : 1;
+  }
+  return 0;
+}
+
+/// compare_lower - Compare strings, ignoring case.
+int StringRef::compare_lower(StringRef RHS) const {
+  if (int Res = ascii_strncasecmp(Data, RHS.Data, std::min(Length, RHS.Length)))
+    return Res;
+  if (Length == RHS.Length)
+    return 0;
+  return Length < RHS.Length ? -1 : 1;
+}
+
+/// Check if this string starts with the given \p Prefix, ignoring case.
+bool StringRef::startswith_lower(StringRef Prefix) const {
+  return Length >= Prefix.Length &&
+      ascii_strncasecmp(Data, Prefix.Data, Prefix.Length) == 0;
+}
+
+/// Check if this string ends with the given \p Suffix, ignoring case.
+bool StringRef::endswith_lower(StringRef Suffix) const {
+  return Length >= Suffix.Length &&
+      ascii_strncasecmp(end() - Suffix.Length, Suffix.Data, Suffix.Length) == 0;
+}
+
+size_t StringRef::find_lower(char C, size_t From) const {
+  char L = toLower(C);
+  return find_if([L](char D) { return toLower(D) == L; }, From);
+}
+
+/// compare_numeric - Compare strings, handle embedded numbers.
+int StringRef::compare_numeric(StringRef RHS) const {
+  for (size_t I = 0, E = std::min(Length, RHS.Length); I != E; ++I) {
+    // Check for sequences of digits.
+    if (isDigit(Data[I]) && isDigit(RHS.Data[I])) {
+      // The longer sequence of numbers is considered larger.
+      // This doesn't really handle prefixed zeros well.
+      size_t J;
+      for (J = I + 1; J != E + 1; ++J) {
+        bool ld = J < Length && isDigit(Data[J]);
+        bool rd = J < RHS.Length && isDigit(RHS.Data[J]);
+        if (ld != rd)
+          return rd ? -1 : 1;
+        if (!rd)
+          break;
+      }
+      // The two number sequences have the same length (J-I), just memcmp them.
+      if (int Res = compareMemory(Data + I, RHS.Data + I, J - I))
+        return Res < 0 ? -1 : 1;
+      // Identical number sequences, continue search after the numbers.
+      I = J - 1;
+      continue;
+    }
+    if (Data[I] != RHS.Data[I])
+      return (unsigned char)Data[I] < (unsigned char)RHS.Data[I] ? -1 : 1;
+  }
+  if (Length == RHS.Length)
+    return 0;
+  return Length < RHS.Length ? -1 : 1;
+}
+
+// Compute the edit distance between the two given strings.
+unsigned StringRef::edit_distance(llvm::StringRef Other,
+                                  bool AllowReplacements,
+                                  unsigned MaxEditDistance) const {
+  return llvm::ComputeEditDistance(
+      makeArrayRef(data(), size()),
+      makeArrayRef(Other.data(), Other.size()),
+      AllowReplacements, MaxEditDistance);
+}
+
+//===----------------------------------------------------------------------===//
+// String Operations
+//===----------------------------------------------------------------------===//
+
+std::string StringRef::lower() const {
+  std::string Result(size(), char());
+  for (size_type i = 0, e = size(); i != e; ++i) {
+    Result[i] = toLower(Data[i]);
+  }
+  return Result;
+}
+
+std::string StringRef::upper() const {
+  std::string Result(size(), char());
+  for (size_type i = 0, e = size(); i != e; ++i) {
+    Result[i] = toUpper(Data[i]);
+  }
+  return Result;
+}
+
+//===----------------------------------------------------------------------===//
+// String Searching
+//===----------------------------------------------------------------------===//
+
+
+/// find - Search for the first string \arg Str in the string.
+///
+/// \return - The index of the first occurrence of \arg Str, or npos if not
+/// found.
+size_t StringRef::find(StringRef Str, size_t From) const {
+  if (From > Length)
+    return npos;
+
+  const char *Start = Data + From;
+  size_t Size = Length - From;
+
+  const char *Needle = Str.data();
+  size_t N = Str.size();
+  if (N == 0)
+    return From;
+  if (Size < N)
+    return npos;
+  if (N == 1) {
+    const char *Ptr = (const char *)::memchr(Start, Needle[0], Size);
+    return Ptr == nullptr ? npos : Ptr - Data;
+  }
+
+  const char *Stop = Start + (Size - N + 1);
+
+  // For short haystacks or unsupported needles fall back to the naive algorithm
+  if (Size < 16 || N > 255) {
+    do {
+      if (std::memcmp(Start, Needle, N) == 0)
+        return Start - Data;
+      ++Start;
+    } while (Start < Stop);
+    return npos;
+  }
+
+  // Build the bad char heuristic table, with uint8_t to reduce cache thrashing.
+  uint8_t BadCharSkip[256];
+  std::memset(BadCharSkip, N, 256);
+  for (unsigned i = 0; i != N-1; ++i)
+    BadCharSkip[(uint8_t)Str[i]] = N-1-i;
+
+  do {
+    uint8_t Last = Start[N - 1];
+    if (LLVM_UNLIKELY(Last == (uint8_t)Needle[N - 1]))
+      if (std::memcmp(Start, Needle, N - 1) == 0)
+        return Start - Data;
+
+    // Otherwise skip the appropriate number of bytes.
+    Start += BadCharSkip[Last];
+  } while (Start < Stop);
+
+  return npos;
+}
+
+size_t StringRef::find_lower(StringRef Str, size_t From) const {
+  StringRef This = substr(From);
+  while (This.size() >= Str.size()) {
+    if (This.startswith_lower(Str))
+      return From;
+    This = This.drop_front();
+    ++From;
+  }
+  return npos;
+}
+
+size_t StringRef::rfind_lower(char C, size_t From) const {
+  From = std::min(From, Length);
+  size_t i = From;
+  while (i != 0) {
+    --i;
+    if (toLower(Data[i]) == toLower(C))
+      return i;
+  }
+  return npos;
+}
+
+/// rfind - Search for the last string \arg Str in the string.
+///
+/// \return - The index of the last occurrence of \arg Str, or npos if not
+/// found.
+size_t StringRef::rfind(StringRef Str) const {
+  size_t N = Str.size();
+  if (N > Length)
+    return npos;
+  for (size_t i = Length - N + 1, e = 0; i != e;) {
+    --i;
+    if (substr(i, N).equals(Str))
+      return i;
+  }
+  return npos;
+}
+
+size_t StringRef::rfind_lower(StringRef Str) const {
+  size_t N = Str.size();
+  if (N > Length)
+    return npos;
+  for (size_t i = Length - N + 1, e = 0; i != e;) {
+    --i;
+    if (substr(i, N).equals_lower(Str))
+      return i;
+  }
+  return npos;
+}
+
+/// find_first_of - Find the first character in the string that is in \arg
+/// Chars, or npos if not found.
+///
+/// Note: O(size() + Chars.size())
+StringRef::size_type StringRef::find_first_of(StringRef Chars,
+                                              size_t From) const {
+  std::bitset<1 << CHAR_BIT> CharBits;
+  for (size_type i = 0; i != Chars.size(); ++i)
+    CharBits.set((unsigned char)Chars[i]);
+
+  for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
+    if (CharBits.test((unsigned char)Data[i]))
+      return i;
+  return npos;
+}
+
+/// find_first_not_of - Find the first character in the string that is not
+/// \arg C or npos if not found.
+StringRef::size_type StringRef::find_first_not_of(char C, size_t From) const {
+  for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
+    if (Data[i] != C)
+      return i;
+  return npos;
+}
+
+/// find_first_not_of - Find the first character in the string that is not
+/// in the string \arg Chars, or npos if not found.
+///
+/// Note: O(size() + Chars.size())
+StringRef::size_type StringRef::find_first_not_of(StringRef Chars,
+                                                  size_t From) const {
+  std::bitset<1 << CHAR_BIT> CharBits;
+  for (size_type i = 0; i != Chars.size(); ++i)
+    CharBits.set((unsigned char)Chars[i]);
+
+  for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
+    if (!CharBits.test((unsigned char)Data[i]))
+      return i;
+  return npos;
+}
+
+/// find_last_of - Find the last character in the string that is in \arg C,
+/// or npos if not found.
+///
+/// Note: O(size() + Chars.size())
+StringRef::size_type StringRef::find_last_of(StringRef Chars,
+                                             size_t From) const {
+  std::bitset<1 << CHAR_BIT> CharBits;
+  for (size_type i = 0; i != Chars.size(); ++i)
+    CharBits.set((unsigned char)Chars[i]);
+
+  for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
+    if (CharBits.test((unsigned char)Data[i]))
+      return i;
+  return npos;
+}
+
+/// find_last_not_of - Find the last character in the string that is not
+/// \arg C, or npos if not found.
+StringRef::size_type StringRef::find_last_not_of(char C, size_t From) const {
+  for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
+    if (Data[i] != C)
+      return i;
+  return npos;
+}
+
+/// find_last_not_of - Find the last character in the string that is not in
+/// \arg Chars, or npos if not found.
+///
+/// Note: O(size() + Chars.size())
+StringRef::size_type StringRef::find_last_not_of(StringRef Chars,
+                                                 size_t From) const {
+  std::bitset<1 << CHAR_BIT> CharBits;
+  for (size_type i = 0, e = Chars.size(); i != e; ++i)
+    CharBits.set((unsigned char)Chars[i]);
+
+  for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
+    if (!CharBits.test((unsigned char)Data[i]))
+      return i;
+  return npos;
+}
+
+void StringRef::split(SmallVectorImpl<StringRef> &A,
+                      StringRef Separator, int MaxSplit,
+                      bool KeepEmpty) const {
+  StringRef S = *this;
+
+  // Count down from MaxSplit. When MaxSplit is -1, this will just split
+  // "forever". This doesn't support splitting more than 2^31 times
+  // intentionally; if we ever want that we can make MaxSplit a 64-bit integer
+  // but that seems unlikely to be useful.
+  while (MaxSplit-- != 0) {
+    size_t Idx = S.find(Separator);
+    if (Idx == npos)
+      break;
+
+    // Push this split.
+    if (KeepEmpty || Idx > 0)
+      A.push_back(S.slice(0, Idx));
+
+    // Jump forward.
+    S = S.slice(Idx + Separator.size(), npos);
+  }
+
+  // Push the tail.
+  if (KeepEmpty || !S.empty())
+    A.push_back(S);
+}
+
+void StringRef::split(SmallVectorImpl<StringRef> &A, char Separator,
+                      int MaxSplit, bool KeepEmpty) const {
+  StringRef S = *this;
+
+  // Count down from MaxSplit. When MaxSplit is -1, this will just split
+  // "forever". This doesn't support splitting more than 2^31 times
+  // intentionally; if we ever want that we can make MaxSplit a 64-bit integer
+  // but that seems unlikely to be useful.
+  while (MaxSplit-- != 0) {
+    size_t Idx = S.find(Separator);
+    if (Idx == npos)
+      break;
+
+    // Push this split.
+    if (KeepEmpty || Idx > 0)
+      A.push_back(S.slice(0, Idx));
+
+    // Jump forward.
+    S = S.slice(Idx + 1, npos);
+  }
+
+  // Push the tail.
+  if (KeepEmpty || !S.empty())
+    A.push_back(S);
+}
+
+//===----------------------------------------------------------------------===//
+// Helpful Algorithms
+//===----------------------------------------------------------------------===//
+
+/// count - Return the number of non-overlapped occurrences of \arg Str in
+/// the string.
+size_t StringRef::count(StringRef Str) const {
+  size_t Count = 0;
+  size_t N = Str.size();
+  if (N > Length)
+    return 0;
+  for (size_t i = 0, e = Length - N + 1; i != e; ++i)
+    if (substr(i, N).equals(Str))
+      ++Count;
+  return Count;
+}
+
+static unsigned GetAutoSenseRadix(StringRef &Str) {
+  if (Str.empty())
+    return 10;
+
+  if (Str.startswith("0x") || Str.startswith("0X")) {
+    Str = Str.substr(2);
+    return 16;
+  }
+
+  if (Str.startswith("0b") || Str.startswith("0B")) {
+    Str = Str.substr(2);
+    return 2;
+  }
+
+  if (Str.startswith("0o")) {
+    Str = Str.substr(2);
+    return 8;
+  }
+
+  if (Str[0] == '0' && Str.size() > 1 && isDigit(Str[1])) {
+    Str = Str.substr(1);
+    return 8;
+  }
+
+  return 10;
+}
+
+bool llvm::consumeUnsignedInteger(StringRef &Str, unsigned Radix,
+                                  unsigned long long &Result) {
+  // Autosense radix if not specified.
+  if (Radix == 0)
+    Radix = GetAutoSenseRadix(Str);
+
+  // Empty strings (after the radix autosense) are invalid.
+  if (Str.empty()) return true;
+
+  // Parse all the bytes of the string given this radix.  Watch for overflow.
+  StringRef Str2 = Str;
+  Result = 0;
+  while (!Str2.empty()) {
+    unsigned CharVal;
+    if (Str2[0] >= '0' && Str2[0] <= '9')
+      CharVal = Str2[0] - '0';
+    else if (Str2[0] >= 'a' && Str2[0] <= 'z')
+      CharVal = Str2[0] - 'a' + 10;
+    else if (Str2[0] >= 'A' && Str2[0] <= 'Z')
+      CharVal = Str2[0] - 'A' + 10;
+    else
+      break;
+
+    // If the parsed value is larger than the integer radix, we cannot
+    // consume any more characters.
+    if (CharVal >= Radix)
+      break;
+
+    // Add in this character.
+    unsigned long long PrevResult = Result;
+    Result = Result * Radix + CharVal;
+
+    // Check for overflow by shifting back and seeing if bits were lost.
+    if (Result / Radix < PrevResult)
+      return true;
+
+    Str2 = Str2.substr(1);
+  }
+
+  // We consider the operation a failure if no characters were consumed
+  // successfully.
+  if (Str.size() == Str2.size())
+    return true;
+
+  Str = Str2;
+  return false;
+}
+
+bool llvm::consumeSignedInteger(StringRef &Str, unsigned Radix,
+                                long long &Result) {
+  unsigned long long ULLVal;
+
+  // Handle positive strings first.
+  if (Str.empty() || Str.front() != '-') {
+    if (consumeUnsignedInteger(Str, Radix, ULLVal) ||
+        // Check for value so large it overflows a signed value.
+        (long long)ULLVal < 0)
+      return true;
+    Result = ULLVal;
+    return false;
+  }
+
+  // Get the positive part of the value.
+  StringRef Str2 = Str.drop_front(1);
+  if (consumeUnsignedInteger(Str2, Radix, ULLVal) ||
+      // Reject values so large they'd overflow as negative signed, but allow
+      // "-0".  This negates the unsigned so that the negative isn't undefined
+      // on signed overflow.
+      (long long)-ULLVal > 0)
+    return true;
+
+  Str = Str2;
+  Result = -ULLVal;
+  return false;
+}
+
+/// GetAsUnsignedInteger - Workhorse method that converts a integer character
+/// sequence of radix up to 36 to an unsigned long long value.
+bool llvm::getAsUnsignedInteger(StringRef Str, unsigned Radix,
+                                unsigned long long &Result) {
+  if (consumeUnsignedInteger(Str, Radix, Result))
+    return true;
+
+  // For getAsUnsignedInteger, we require the whole string to be consumed or
+  // else we consider it a failure.
+  return !Str.empty();
+}
+
+bool llvm::getAsSignedInteger(StringRef Str, unsigned Radix,
+                              long long &Result) {
+  if (consumeSignedInteger(Str, Radix, Result))
+    return true;
+
+  // For getAsSignedInteger, we require the whole string to be consumed or else
+  // we consider it a failure.
+  return !Str.empty();
+}
+
+bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const {
+  llvm_unreachable("getAsinteger");
+}
+
+bool StringRef::getAsDouble(double &Result, bool AllowInexact) const {
+  llvm_unreachable("getAsDouble");
+}
+
+// Implementation of StringRef hashing.
+hash_code llvm::hash_value(StringRef S) {
+  return hash_combine_range(S.begin(), S.end());
+}
diff --git a/binaryen/third_party/llvm-project/SymbolicFile.cpp b/binaryen/third_party/llvm-project/SymbolicFile.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/SymbolicFile.cpp
@@ -0,0 +1,45 @@
+//===- SymbolicFile.cpp - Interface that only provides symbols ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a file format independent SymbolicFile class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#if 0 // XXX BINARYEN
+#include "llvm/Object/COFFImportFile.h"
+#endif
+#include "llvm/Object/Error.h"
+#if 0 // XXX BINARYEN
+#include "llvm/Object/IRObjectFile.h"
+#endif
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <algorithm>
+#include <memory>
+
+using namespace llvm;
+using namespace object;
+
+SymbolicFile::SymbolicFile(unsigned int Type, MemoryBufferRef Source)
+    : Binary(Type, Source) {}
+
+SymbolicFile::~SymbolicFile() = default;
+
+Expected<std::unique_ptr<SymbolicFile>>
+SymbolicFile::createSymbolicFile(MemoryBufferRef Object, file_magic Type,
+                                 LLVMContext *Context) {
+  llvm_unreachable("createSymbolicFile");
+}
diff --git a/binaryen/third_party/llvm-project/Twine.cpp b/binaryen/third_party/llvm-project/Twine.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/Twine.cpp
@@ -0,0 +1,184 @@
+//===-- Twine.cpp - Fast Temporary String Concatenation -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+std::string Twine::str() const {
+  // If we're storing only a std::string, just return it.
+  if (LHSKind == StdStringKind && RHSKind == EmptyKind)
+    return *LHS.stdString;
+
+  // If we're storing a formatv_object, we can avoid an extra copy by formatting
+  // it immediately and returning the result.
+  if (LHSKind == FormatvObjectKind && RHSKind == EmptyKind)
+    return LHS.formatvObject->str();
+
+  // Otherwise, flatten and copy the contents first.
+  SmallString<256> Vec;
+  return toStringRef(Vec).str();
+}
+
+void Twine::toVector(SmallVectorImpl<char> &Out) const {
+  raw_svector_ostream OS(Out);
+  print(OS);
+}
+
+StringRef Twine::toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const {
+  if (isUnary()) {
+    switch (getLHSKind()) {
+    case CStringKind:
+      // Already null terminated, yay!
+      return StringRef(LHS.cString);
+    case StdStringKind: {
+      const std::string *str = LHS.stdString;
+      return StringRef(str->c_str(), str->size());
+    }
+    default:
+      break;
+    }
+  }
+  toVector(Out);
+  Out.push_back(0);
+  Out.pop_back();
+  return StringRef(Out.data(), Out.size());
+}
+
+void Twine::printOneChild(raw_ostream &OS, Child Ptr,
+                          NodeKind Kind) const {
+  switch (Kind) {
+  case Twine::NullKind: break;
+  case Twine::EmptyKind: break;
+  case Twine::TwineKind:
+    Ptr.twine->print(OS);
+    break;
+  case Twine::CStringKind:
+    OS << Ptr.cString;
+    break;
+  case Twine::StdStringKind:
+    OS << *Ptr.stdString;
+    break;
+  case Twine::StringRefKind:
+    OS << *Ptr.stringRef;
+    break;
+  case Twine::SmallStringKind:
+    OS << *Ptr.smallString;
+    break;
+  case Twine::FormatvObjectKind:
+    OS << *Ptr.formatvObject;
+    break;
+  case Twine::CharKind:
+    OS << Ptr.character;
+    break;
+  case Twine::DecUIKind:
+    OS << Ptr.decUI;
+    break;
+  case Twine::DecIKind:
+    OS << Ptr.decI;
+    break;
+  case Twine::DecULKind:
+    OS << *Ptr.decUL;
+    break;
+  case Twine::DecLKind:
+    OS << *Ptr.decL;
+    break;
+  case Twine::DecULLKind:
+    OS << *Ptr.decULL;
+    break;
+  case Twine::DecLLKind:
+    OS << *Ptr.decLL;
+    break;
+  case Twine::UHexKind:
+    OS.write_hex(*Ptr.uHex);
+    break;
+  }
+}
+
+void Twine::printOneChildRepr(raw_ostream &OS, Child Ptr,
+                              NodeKind Kind) const {
+  switch (Kind) {
+  case Twine::NullKind:
+    OS << "null"; break;
+  case Twine::EmptyKind:
+    OS << "empty"; break;
+  case Twine::TwineKind:
+    OS << "rope:";
+    Ptr.twine->printRepr(OS);
+    break;
+  case Twine::CStringKind:
+    OS << "cstring:\""
+       << Ptr.cString << "\"";
+    break;
+  case Twine::StdStringKind:
+    OS << "std::string:\""
+       << Ptr.stdString << "\"";
+    break;
+  case Twine::StringRefKind:
+    OS << "stringref:\""
+       << Ptr.stringRef << "\"";
+    break;
+  case Twine::SmallStringKind:
+    OS << "smallstring:\"" << *Ptr.smallString << "\"";
+    break;
+  case Twine::FormatvObjectKind:
+    OS << "formatv:\"" << *Ptr.formatvObject << "\"";
+    break;
+  case Twine::CharKind:
+    OS << "char:\"" << Ptr.character << "\"";
+    break;
+  case Twine::DecUIKind:
+    OS << "decUI:\"" << Ptr.decUI << "\"";
+    break;
+  case Twine::DecIKind:
+    OS << "decI:\"" << Ptr.decI << "\"";
+    break;
+  case Twine::DecULKind:
+    OS << "decUL:\"" << *Ptr.decUL << "\"";
+    break;
+  case Twine::DecLKind:
+    OS << "decL:\"" << *Ptr.decL << "\"";
+    break;
+  case Twine::DecULLKind:
+    OS << "decULL:\"" << *Ptr.decULL << "\"";
+    break;
+  case Twine::DecLLKind:
+    OS << "decLL:\"" << *Ptr.decLL << "\"";
+    break;
+  case Twine::UHexKind:
+    OS << "uhex:\"" << Ptr.uHex << "\"";
+    break;
+  }
+}
+
+void Twine::print(raw_ostream &OS) const {
+  printOneChild(OS, LHS, getLHSKind());
+  printOneChild(OS, RHS, getRHSKind());
+}
+
+void Twine::printRepr(raw_ostream &OS) const {
+  OS << "(Twine ";
+  printOneChildRepr(OS, LHS, getLHSKind());
+  OS << " ";
+  printOneChildRepr(OS, RHS, getRHSKind());
+  OS << ")";
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void Twine::dump() const {
+  print(dbgs());
+}
+
+LLVM_DUMP_METHOD void Twine::dumpRepr() const {
+  printRepr(dbgs());
+}
+#endif
diff --git a/binaryen/third_party/llvm-project/UnicodeCaseFold.cpp b/binaryen/third_party/llvm-project/UnicodeCaseFold.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/UnicodeCaseFold.cpp
@@ -0,0 +1,742 @@
+//===---------- Support/UnicodeCaseFold.cpp -------------------------------===//
+//
+// This file was generated by utils/unicode-case-fold.py from the Unicode
+// case folding database at
+//    http://www.unicode.org/Public/9.0.0/ucd/CaseFolding.txt
+//
+// To regenerate this file, run:
+//   utils/unicode-case-fold.py
+//     "http://www.unicode.org/Public/9.0.0/ucd/CaseFolding.txt"
+//     > lib/Support/UnicodeCaseFold.cpp
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Unicode.h"
+
+int llvm::sys::unicode::foldCharSimple(int C) {
+  if (C < 0x0041)
+    return C;
+  // 26 characters
+  if (C <= 0x005a)
+    return C + 32;
+  // MICRO SIGN
+  if (C == 0x00b5)
+    return 0x03bc;
+  if (C < 0x00c0)
+    return C;
+  // 23 characters
+  if (C <= 0x00d6)
+    return C + 32;
+  if (C < 0x00d8)
+    return C;
+  // 7 characters
+  if (C <= 0x00de)
+    return C + 32;
+  if (C < 0x0100)
+    return C;
+  // 24 characters
+  if (C <= 0x012e)
+    return C | 1;
+  if (C < 0x0132)
+    return C;
+  // 3 characters
+  if (C <= 0x0136)
+    return C | 1;
+  if (C < 0x0139)
+    return C;
+  // 8 characters
+  if (C <= 0x0147 && C % 2 == 1)
+    return C + 1;
+  if (C < 0x014a)
+    return C;
+  // 23 characters
+  if (C <= 0x0176)
+    return C | 1;
+  // LATIN CAPITAL LETTER Y WITH DIAERESIS
+  if (C == 0x0178)
+    return 0x00ff;
+  if (C < 0x0179)
+    return C;
+  // 3 characters
+  if (C <= 0x017d && C % 2 == 1)
+    return C + 1;
+  // LATIN SMALL LETTER LONG S
+  if (C == 0x017f)
+    return 0x0073;
+  // LATIN CAPITAL LETTER B WITH HOOK
+  if (C == 0x0181)
+    return 0x0253;
+  if (C < 0x0182)
+    return C;
+  // 2 characters
+  if (C <= 0x0184)
+    return C | 1;
+  // LATIN CAPITAL LETTER OPEN O
+  if (C == 0x0186)
+    return 0x0254;
+  // LATIN CAPITAL LETTER C WITH HOOK
+  if (C == 0x0187)
+    return 0x0188;
+  if (C < 0x0189)
+    return C;
+  // 2 characters
+  if (C <= 0x018a)
+    return C + 205;
+  // LATIN CAPITAL LETTER D WITH TOPBAR
+  if (C == 0x018b)
+    return 0x018c;
+  // LATIN CAPITAL LETTER REVERSED E
+  if (C == 0x018e)
+    return 0x01dd;
+  // LATIN CAPITAL LETTER SCHWA
+  if (C == 0x018f)
+    return 0x0259;
+  // LATIN CAPITAL LETTER OPEN E
+  if (C == 0x0190)
+    return 0x025b;
+  // LATIN CAPITAL LETTER F WITH HOOK
+  if (C == 0x0191)
+    return 0x0192;
+  // LATIN CAPITAL LETTER G WITH HOOK
+  if (C == 0x0193)
+    return 0x0260;
+  // LATIN CAPITAL LETTER GAMMA
+  if (C == 0x0194)
+    return 0x0263;
+  // LATIN CAPITAL LETTER IOTA
+  if (C == 0x0196)
+    return 0x0269;
+  // LATIN CAPITAL LETTER I WITH STROKE
+  if (C == 0x0197)
+    return 0x0268;
+  // LATIN CAPITAL LETTER K WITH HOOK
+  if (C == 0x0198)
+    return 0x0199;
+  // LATIN CAPITAL LETTER TURNED M
+  if (C == 0x019c)
+    return 0x026f;
+  // LATIN CAPITAL LETTER N WITH LEFT HOOK
+  if (C == 0x019d)
+    return 0x0272;
+  // LATIN CAPITAL LETTER O WITH MIDDLE TILDE
+  if (C == 0x019f)
+    return 0x0275;
+  if (C < 0x01a0)
+    return C;
+  // 3 characters
+  if (C <= 0x01a4)
+    return C | 1;
+  // LATIN LETTER YR
+  if (C == 0x01a6)
+    return 0x0280;
+  // LATIN CAPITAL LETTER TONE TWO
+  if (C == 0x01a7)
+    return 0x01a8;
+  // LATIN CAPITAL LETTER ESH
+  if (C == 0x01a9)
+    return 0x0283;
+  // LATIN CAPITAL LETTER T WITH HOOK
+  if (C == 0x01ac)
+    return 0x01ad;
+  // LATIN CAPITAL LETTER T WITH RETROFLEX HOOK
+  if (C == 0x01ae)
+    return 0x0288;
+  // LATIN CAPITAL LETTER U WITH HORN
+  if (C == 0x01af)
+    return 0x01b0;
+  if (C < 0x01b1)
+    return C;
+  // 2 characters
+  if (C <= 0x01b2)
+    return C + 217;
+  if (C < 0x01b3)
+    return C;
+  // 2 characters
+  if (C <= 0x01b5 && C % 2 == 1)
+    return C + 1;
+  // LATIN CAPITAL LETTER EZH
+  if (C == 0x01b7)
+    return 0x0292;
+  if (C < 0x01b8)
+    return C;
+  // 2 characters
+  if (C <= 0x01bc && C % 4 == 0)
+    return C + 1;
+  // LATIN CAPITAL LETTER DZ WITH CARON
+  if (C == 0x01c4)
+    return 0x01c6;
+  // LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
+  if (C == 0x01c5)
+    return 0x01c6;
+  // LATIN CAPITAL LETTER LJ
+  if (C == 0x01c7)
+    return 0x01c9;
+  // LATIN CAPITAL LETTER L WITH SMALL LETTER J
+  if (C == 0x01c8)
+    return 0x01c9;
+  // LATIN CAPITAL LETTER NJ
+  if (C == 0x01ca)
+    return 0x01cc;
+  if (C < 0x01cb)
+    return C;
+  // 9 characters
+  if (C <= 0x01db && C % 2 == 1)
+    return C + 1;
+  if (C < 0x01de)
+    return C;
+  // 9 characters
+  if (C <= 0x01ee)
+    return C | 1;
+  // LATIN CAPITAL LETTER DZ
+  if (C == 0x01f1)
+    return 0x01f3;
+  if (C < 0x01f2)
+    return C;
+  // 2 characters
+  if (C <= 0x01f4)
+    return C | 1;
+  // LATIN CAPITAL LETTER HWAIR
+  if (C == 0x01f6)
+    return 0x0195;
+  // LATIN CAPITAL LETTER WYNN
+  if (C == 0x01f7)
+    return 0x01bf;
+  if (C < 0x01f8)
+    return C;
+  // 20 characters
+  if (C <= 0x021e)
+    return C | 1;
+  // LATIN CAPITAL LETTER N WITH LONG RIGHT LEG
+  if (C == 0x0220)
+    return 0x019e;
+  if (C < 0x0222)
+    return C;
+  // 9 characters
+  if (C <= 0x0232)
+    return C | 1;
+  // LATIN CAPITAL LETTER A WITH STROKE
+  if (C == 0x023a)
+    return 0x2c65;
+  // LATIN CAPITAL LETTER C WITH STROKE
+  if (C == 0x023b)
+    return 0x023c;
+  // LATIN CAPITAL LETTER L WITH BAR
+  if (C == 0x023d)
+    return 0x019a;
+  // LATIN CAPITAL LETTER T WITH DIAGONAL STROKE
+  if (C == 0x023e)
+    return 0x2c66;
+  // LATIN CAPITAL LETTER GLOTTAL STOP
+  if (C == 0x0241)
+    return 0x0242;
+  // LATIN CAPITAL LETTER B WITH STROKE
+  if (C == 0x0243)
+    return 0x0180;
+  // LATIN CAPITAL LETTER U BAR
+  if (C == 0x0244)
+    return 0x0289;
+  // LATIN CAPITAL LETTER TURNED V
+  if (C == 0x0245)
+    return 0x028c;
+  if (C < 0x0246)
+    return C;
+  // 5 characters
+  if (C <= 0x024e)
+    return C | 1;
+  // COMBINING GREEK YPOGEGRAMMENI
+  if (C == 0x0345)
+    return 0x03b9;
+  if (C < 0x0370)
+    return C;
+  // 2 characters
+  if (C <= 0x0372)
+    return C | 1;
+  // GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA
+  if (C == 0x0376)
+    return 0x0377;
+  // GREEK CAPITAL LETTER YOT
+  if (C == 0x037f)
+    return 0x03f3;
+  // GREEK CAPITAL LETTER ALPHA WITH TONOS
+  if (C == 0x0386)
+    return 0x03ac;
+  if (C < 0x0388)
+    return C;
+  // 3 characters
+  if (C <= 0x038a)
+    return C + 37;
+  // GREEK CAPITAL LETTER OMICRON WITH TONOS
+  if (C == 0x038c)
+    return 0x03cc;
+  if (C < 0x038e)
+    return C;
+  // 2 characters
+  if (C <= 0x038f)
+    return C + 63;
+  if (C < 0x0391)
+    return C;
+  // 17 characters
+  if (C <= 0x03a1)
+    return C + 32;
+  if (C < 0x03a3)
+    return C;
+  // 9 characters
+  if (C <= 0x03ab)
+    return C + 32;
+  // GREEK SMALL LETTER FINAL SIGMA
+  if (C == 0x03c2)
+    return 0x03c3;
+  // GREEK CAPITAL KAI SYMBOL
+  if (C == 0x03cf)
+    return 0x03d7;
+  // GREEK BETA SYMBOL
+  if (C == 0x03d0)
+    return 0x03b2;
+  // GREEK THETA SYMBOL
+  if (C == 0x03d1)
+    return 0x03b8;
+  // GREEK PHI SYMBOL
+  if (C == 0x03d5)
+    return 0x03c6;
+  // GREEK PI SYMBOL
+  if (C == 0x03d6)
+    return 0x03c0;
+  if (C < 0x03d8)
+    return C;
+  // 12 characters
+  if (C <= 0x03ee)
+    return C | 1;
+  // GREEK KAPPA SYMBOL
+  if (C == 0x03f0)
+    return 0x03ba;
+  // GREEK RHO SYMBOL
+  if (C == 0x03f1)
+    return 0x03c1;
+  // GREEK CAPITAL THETA SYMBOL
+  if (C == 0x03f4)
+    return 0x03b8;
+  // GREEK LUNATE EPSILON SYMBOL
+  if (C == 0x03f5)
+    return 0x03b5;
+  // GREEK CAPITAL LETTER SHO
+  if (C == 0x03f7)
+    return 0x03f8;
+  // GREEK CAPITAL LUNATE SIGMA SYMBOL
+  if (C == 0x03f9)
+    return 0x03f2;
+  // GREEK CAPITAL LETTER SAN
+  if (C == 0x03fa)
+    return 0x03fb;
+  if (C < 0x03fd)
+    return C;
+  // 3 characters
+  if (C <= 0x03ff)
+    return C + -130;
+  if (C < 0x0400)
+    return C;
+  // 16 characters
+  if (C <= 0x040f)
+    return C + 80;
+  if (C < 0x0410)
+    return C;
+  // 32 characters
+  if (C <= 0x042f)
+    return C + 32;
+  if (C < 0x0460)
+    return C;
+  // 17 characters
+  if (C <= 0x0480)
+    return C | 1;
+  if (C < 0x048a)
+    return C;
+  // 27 characters
+  if (C <= 0x04be)
+    return C | 1;
+  // CYRILLIC LETTER PALOCHKA
+  if (C == 0x04c0)
+    return 0x04cf;
+  if (C < 0x04c1)
+    return C;
+  // 7 characters
+  if (C <= 0x04cd && C % 2 == 1)
+    return C + 1;
+  if (C < 0x04d0)
+    return C;
+  // 48 characters
+  if (C <= 0x052e)
+    return C | 1;
+  if (C < 0x0531)
+    return C;
+  // 38 characters
+  if (C <= 0x0556)
+    return C + 48;
+  if (C < 0x10a0)
+    return C;
+  // 38 characters
+  if (C <= 0x10c5)
+    return C + 7264;
+  if (C < 0x10c7)
+    return C;
+  // 2 characters
+  if (C <= 0x10cd && C % 6 == 5)
+    return C + 7264;
+  if (C < 0x13f8)
+    return C;
+  // 6 characters
+  if (C <= 0x13fd)
+    return C + -8;
+  // CYRILLIC SMALL LETTER ROUNDED VE
+  if (C == 0x1c80)
+    return 0x0432;
+  // CYRILLIC SMALL LETTER LONG-LEGGED DE
+  if (C == 0x1c81)
+    return 0x0434;
+  // CYRILLIC SMALL LETTER NARROW O
+  if (C == 0x1c82)
+    return 0x043e;
+  if (C < 0x1c83)
+    return C;
+  // 2 characters
+  if (C <= 0x1c84)
+    return C + -6210;
+  // CYRILLIC SMALL LETTER THREE-LEGGED TE
+  if (C == 0x1c85)
+    return 0x0442;
+  // CYRILLIC SMALL LETTER TALL HARD SIGN
+  if (C == 0x1c86)
+    return 0x044a;
+  // CYRILLIC SMALL LETTER TALL YAT
+  if (C == 0x1c87)
+    return 0x0463;
+  // CYRILLIC SMALL LETTER UNBLENDED UK
+  if (C == 0x1c88)
+    return 0xa64b;
+  if (C < 0x1e00)
+    return C;
+  // 75 characters
+  if (C <= 0x1e94)
+    return C | 1;
+  // LATIN SMALL LETTER LONG S WITH DOT ABOVE
+  if (C == 0x1e9b)
+    return 0x1e61;
+  // LATIN CAPITAL LETTER SHARP S
+  if (C == 0x1e9e)
+    return 0x00df;
+  if (C < 0x1ea0)
+    return C;
+  // 48 characters
+  if (C <= 0x1efe)
+    return C | 1;
+  if (C < 0x1f08)
+    return C;
+  // 8 characters
+  if (C <= 0x1f0f)
+    return C + -8;
+  if (C < 0x1f18)
+    return C;
+  // 6 characters
+  if (C <= 0x1f1d)
+    return C + -8;
+  if (C < 0x1f28)
+    return C;
+  // 8 characters
+  if (C <= 0x1f2f)
+    return C + -8;
+  if (C < 0x1f38)
+    return C;
+  // 8 characters
+  if (C <= 0x1f3f)
+    return C + -8;
+  if (C < 0x1f48)
+    return C;
+  // 6 characters
+  if (C <= 0x1f4d)
+    return C + -8;
+  if (C < 0x1f59)
+    return C;
+  // 4 characters
+  if (C <= 0x1f5f && C % 2 == 1)
+    return C + -8;
+  if (C < 0x1f68)
+    return C;
+  // 8 characters
+  if (C <= 0x1f6f)
+    return C + -8;
+  if (C < 0x1f88)
+    return C;
+  // 8 characters
+  if (C <= 0x1f8f)
+    return C + -8;
+  if (C < 0x1f98)
+    return C;
+  // 8 characters
+  if (C <= 0x1f9f)
+    return C + -8;
+  if (C < 0x1fa8)
+    return C;
+  // 8 characters
+  if (C <= 0x1faf)
+    return C + -8;
+  if (C < 0x1fb8)
+    return C;
+  // 2 characters
+  if (C <= 0x1fb9)
+    return C + -8;
+  if (C < 0x1fba)
+    return C;
+  // 2 characters
+  if (C <= 0x1fbb)
+    return C + -74;
+  // GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+  if (C == 0x1fbc)
+    return 0x1fb3;
+  // GREEK PROSGEGRAMMENI
+  if (C == 0x1fbe)
+    return 0x03b9;
+  if (C < 0x1fc8)
+    return C;
+  // 4 characters
+  if (C <= 0x1fcb)
+    return C + -86;
+  // GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+  if (C == 0x1fcc)
+    return 0x1fc3;
+  if (C < 0x1fd8)
+    return C;
+  // 2 characters
+  if (C <= 0x1fd9)
+    return C + -8;
+  if (C < 0x1fda)
+    return C;
+  // 2 characters
+  if (C <= 0x1fdb)
+    return C + -100;
+  if (C < 0x1fe8)
+    return C;
+  // 2 characters
+  if (C <= 0x1fe9)
+    return C + -8;
+  if (C < 0x1fea)
+    return C;
+  // 2 characters
+  if (C <= 0x1feb)
+    return C + -112;
+  // GREEK CAPITAL LETTER RHO WITH DASIA
+  if (C == 0x1fec)
+    return 0x1fe5;
+  if (C < 0x1ff8)
+    return C;
+  // 2 characters
+  if (C <= 0x1ff9)
+    return C + -128;
+  if (C < 0x1ffa)
+    return C;
+  // 2 characters
+  if (C <= 0x1ffb)
+    return C + -126;
+  // GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+  if (C == 0x1ffc)
+    return 0x1ff3;
+  // OHM SIGN
+  if (C == 0x2126)
+    return 0x03c9;
+  // KELVIN SIGN
+  if (C == 0x212a)
+    return 0x006b;
+  // ANGSTROM SIGN
+  if (C == 0x212b)
+    return 0x00e5;
+  // TURNED CAPITAL F
+  if (C == 0x2132)
+    return 0x214e;
+  if (C < 0x2160)
+    return C;
+  // 16 characters
+  if (C <= 0x216f)
+    return C + 16;
+  // ROMAN NUMERAL REVERSED ONE HUNDRED
+  if (C == 0x2183)
+    return 0x2184;
+  if (C < 0x24b6)
+    return C;
+  // 26 characters
+  if (C <= 0x24cf)
+    return C + 26;
+  if (C < 0x2c00)
+    return C;
+  // 47 characters
+  if (C <= 0x2c2e)
+    return C + 48;
+  // LATIN CAPITAL LETTER L WITH DOUBLE BAR
+  if (C == 0x2c60)
+    return 0x2c61;
+  // LATIN CAPITAL LETTER L WITH MIDDLE TILDE
+  if (C == 0x2c62)
+    return 0x026b;
+  // LATIN CAPITAL LETTER P WITH STROKE
+  if (C == 0x2c63)
+    return 0x1d7d;
+  // LATIN CAPITAL LETTER R WITH TAIL
+  if (C == 0x2c64)
+    return 0x027d;
+  if (C < 0x2c67)
+    return C;
+  // 3 characters
+  if (C <= 0x2c6b && C % 2 == 1)
+    return C + 1;
+  // LATIN CAPITAL LETTER ALPHA
+  if (C == 0x2c6d)
+    return 0x0251;
+  // LATIN CAPITAL LETTER M WITH HOOK
+  if (C == 0x2c6e)
+    return 0x0271;
+  // LATIN CAPITAL LETTER TURNED A
+  if (C == 0x2c6f)
+    return 0x0250;
+  // LATIN CAPITAL LETTER TURNED ALPHA
+  if (C == 0x2c70)
+    return 0x0252;
+  if (C < 0x2c72)
+    return C;
+  // 2 characters
+  if (C <= 0x2c75 && C % 3 == 2)
+    return C + 1;
+  if (C < 0x2c7e)
+    return C;
+  // 2 characters
+  if (C <= 0x2c7f)
+    return C + -10815;
+  if (C < 0x2c80)
+    return C;
+  // 50 characters
+  if (C <= 0x2ce2)
+    return C | 1;
+  if (C < 0x2ceb)
+    return C;
+  // 2 characters
+  if (C <= 0x2ced && C % 2 == 1)
+    return C + 1;
+  if (C < 0x2cf2)
+    return C;
+  // 2 characters
+  if (C <= 0xa640 && C % 31054 == 11506)
+    return C + 1;
+  if (C < 0xa642)
+    return C;
+  // 22 characters
+  if (C <= 0xa66c)
+    return C | 1;
+  if (C < 0xa680)
+    return C;
+  // 14 characters
+  if (C <= 0xa69a)
+    return C | 1;
+  if (C < 0xa722)
+    return C;
+  // 7 characters
+  if (C <= 0xa72e)
+    return C | 1;
+  if (C < 0xa732)
+    return C;
+  // 31 characters
+  if (C <= 0xa76e)
+    return C | 1;
+  if (C < 0xa779)
+    return C;
+  // 2 characters
+  if (C <= 0xa77b && C % 2 == 1)
+    return C + 1;
+  // LATIN CAPITAL LETTER INSULAR G
+  if (C == 0xa77d)
+    return 0x1d79;
+  if (C < 0xa77e)
+    return C;
+  // 5 characters
+  if (C <= 0xa786)
+    return C | 1;
+  // LATIN CAPITAL LETTER SALTILLO
+  if (C == 0xa78b)
+    return 0xa78c;
+  // LATIN CAPITAL LETTER TURNED H
+  if (C == 0xa78d)
+    return 0x0265;
+  if (C < 0xa790)
+    return C;
+  // 2 characters
+  if (C <= 0xa792)
+    return C | 1;
+  if (C < 0xa796)
+    return C;
+  // 10 characters
+  if (C <= 0xa7a8)
+    return C | 1;
+  // LATIN CAPITAL LETTER H WITH HOOK
+  if (C == 0xa7aa)
+    return 0x0266;
+  // LATIN CAPITAL LETTER REVERSED OPEN E
+  if (C == 0xa7ab)
+    return 0x025c;
+  // LATIN CAPITAL LETTER SCRIPT G
+  if (C == 0xa7ac)
+    return 0x0261;
+  // LATIN CAPITAL LETTER L WITH BELT
+  if (C == 0xa7ad)
+    return 0x026c;
+  // LATIN CAPITAL LETTER SMALL CAPITAL I
+  if (C == 0xa7ae)
+    return 0x026a;
+  // LATIN CAPITAL LETTER TURNED K
+  if (C == 0xa7b0)
+    return 0x029e;
+  // LATIN CAPITAL LETTER TURNED T
+  if (C == 0xa7b1)
+    return 0x0287;
+  // LATIN CAPITAL LETTER J WITH CROSSED-TAIL
+  if (C == 0xa7b2)
+    return 0x029d;
+  // LATIN CAPITAL LETTER CHI
+  if (C == 0xa7b3)
+    return 0xab53;
+  if (C < 0xa7b4)
+    return C;
+  // 2 characters
+  if (C <= 0xa7b6)
+    return C | 1;
+  if (C < 0xab70)
+    return C;
+  // 80 characters
+  if (C <= 0xabbf)
+    return C + -38864;
+  if (C < 0xff21)
+    return C;
+  // 26 characters
+  if (C <= 0xff3a)
+    return C + 32;
+  if (C < 0x10400)
+    return C;
+  // 40 characters
+  if (C <= 0x10427)
+    return C + 40;
+  if (C < 0x104b0)
+    return C;
+  // 36 characters
+  if (C <= 0x104d3)
+    return C + 40;
+  if (C < 0x10c80)
+    return C;
+  // 51 characters
+  if (C <= 0x10cb2)
+    return C + 64;
+  if (C < 0x118a0)
+    return C;
+  // 32 characters
+  if (C <= 0x118bf)
+    return C + 32;
+  if (C < 0x1e900)
+    return C;
+  // 34 characters
+  if (C <= 0x1e921)
+    return C + 34;
+
+  return C;
+}
diff --git a/binaryen/third_party/llvm-project/Unix/Path.inc b/binaryen/third_party/llvm-project/Unix/Path.inc
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/Unix/Path.inc
@@ -0,0 +1,1213 @@
+//===- llvm/Support/Unix/Path.inc - Unix Path Implementation ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Unix specific implementation of the Path API.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+//=== WARNING: Implementation here must contain only generic UNIX code that
+//===          is guaranteed to work on *all* UNIX variants.
+//===----------------------------------------------------------------------===//
+
+#include "Unix.h"
+#include <limits.h>
+#include <stdio.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#include <dirent.h>
+#include <pwd.h>
+
+#ifdef __APPLE__
+#include <mach-o/dyld.h>
+#include <sys/attr.h>
+#include <copyfile.h>
+#elif defined(__DragonFly__)
+#include <sys/mount.h>
+#endif
+
+// Both stdio.h and cstdio are included via different paths and
+// stdcxx's cstdio doesn't include stdio.h, so it doesn't #undef the macros
+// either.
+#undef ferror
+#undef feof
+
+// For GNU Hurd
+#if defined(__GNU__) && !defined(PATH_MAX)
+# define PATH_MAX 4096
+# define MAXPATHLEN 4096
+#endif
+
+#include <sys/types.h>
+#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__) &&   \
+    !defined(__linux__) && !defined(__FreeBSD_kernel__) && !defined(_AIX)
+#include <sys/statvfs.h>
+#define STATVFS statvfs
+#define FSTATVFS fstatvfs
+#define STATVFS_F_FRSIZE(vfs) vfs.f_frsize
+#else
+#if defined(__OpenBSD__) || defined(__FreeBSD__)
+#include <sys/mount.h>
+#include <sys/param.h>
+#elif defined(__linux__)
+#if defined(HAVE_LINUX_MAGIC_H)
+#include <linux/magic.h>
+#else
+#if defined(HAVE_LINUX_NFS_FS_H)
+#include <linux/nfs_fs.h>
+#endif
+#if defined(HAVE_LINUX_SMB_H)
+#include <linux/smb.h>
+#endif
+#endif
+#include <sys/vfs.h>
+#elif defined(_AIX)
+#include <sys/statfs.h>
+
+// <sys/vmount.h> depends on `uint` to be a typedef from <sys/types.h> to
+// `uint_t`; however, <sys/types.h> does not always declare `uint`. We provide
+// the typedef prior to including <sys/vmount.h> to work around this issue.
+typedef uint_t uint;
+#include <sys/vmount.h>
+#else
+#include <sys/mount.h>
+#endif
+#define STATVFS statfs
+#define FSTATVFS fstatfs
+#define STATVFS_F_FRSIZE(vfs) static_cast<uint64_t>(vfs.f_bsize)
+#endif
+
+#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__GNU__)
+#define STATVFS_F_FLAG(vfs) (vfs).f_flag
+#else
+#define STATVFS_F_FLAG(vfs) (vfs).f_flags
+#endif
+
+using namespace llvm;
+
+namespace llvm {
+namespace sys  {
+namespace fs {
+
+const file_t kInvalidFile = -1;
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||     \
+    defined(__minix) || defined(__FreeBSD_kernel__) || defined(__linux__) ||   \
+    defined(__CYGWIN__) || defined(__DragonFly__) || defined(_AIX) || defined(__GNU__)
+static int
+test_dir(char ret[PATH_MAX], const char *dir, const char *bin)
+{
+  struct stat sb;
+  char fullpath[PATH_MAX];
+
+  int chars = snprintf(fullpath, PATH_MAX, "%s/%s", dir, bin);
+  // We cannot write PATH_MAX characters because the string will be terminated
+  // with a null character. Fail if truncation happened.
+  if (chars >= PATH_MAX)
+    return 1;
+  if (!realpath(fullpath, ret))
+    return 1;
+  if (stat(fullpath, &sb) != 0)
+    return 1;
+
+  return 0;
+}
+
+static char *
+getprogpath(char ret[PATH_MAX], const char *bin)
+{
+  /* First approach: absolute path. */
+  if (bin[0] == '/') {
+    if (test_dir(ret, "/", bin) == 0)
+      return ret;
+    return nullptr;
+  }
+
+  /* Second approach: relative path. */
+  if (strchr(bin, '/')) {
+    char cwd[PATH_MAX];
+    if (!getcwd(cwd, PATH_MAX))
+      return nullptr;
+    if (test_dir(ret, cwd, bin) == 0)
+      return ret;
+    return nullptr;
+  }
+
+  /* Third approach: $PATH */
+  char *pv;
+  if ((pv = getenv("PATH")) == nullptr)
+    return nullptr;
+  char *s = strdup(pv);
+  if (!s)
+    return nullptr;
+  char *state;
+  for (char *t = strtok_r(s, ":", &state); t != nullptr;
+       t = strtok_r(nullptr, ":", &state)) {
+    if (test_dir(ret, t, bin) == 0) {
+      free(s);
+      return ret;
+    }
+  }
+  free(s);
+  return nullptr;
+}
+#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__
+
+/// GetMainExecutable - Return the path to the main executable, given the
+/// value of argv[0] from program startup.
+std::string getMainExecutable(const char *argv0, void *MainAddr) {
+#if defined(__APPLE__)
+  // On OS X the executable path is saved to the stack by dyld. Reading it
+  // from there is much faster than calling dladdr, especially for large
+  // binaries with symbols.
+  char exe_path[MAXPATHLEN];
+  uint32_t size = sizeof(exe_path);
+  if (_NSGetExecutablePath(exe_path, &size) == 0) {
+    char link_path[MAXPATHLEN];
+    if (realpath(exe_path, link_path))
+      return link_path;
+  }
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||   \
+    defined(__minix) || defined(__DragonFly__) ||                              \
+    defined(__FreeBSD_kernel__) || defined(_AIX)
+  const char *curproc = "/proc/curproc/file";
+  char exe_path[PATH_MAX];
+  // /proc is not mounted by default under FreeBSD, but gives more accurate
+  // information than argv[0] when it is.
+  if (sys::fs::exists(curproc)) {
+    ssize_t len = readlink(curproc, exe_path, sizeof(exe_path));
+    if (len > 0) {
+      // Null terminate the string for realpath. readlink never null
+      // terminates its output.
+      len = std::min(len, ssize_t(sizeof(exe_path) - 1));
+      exe_path[len] = '\0';
+      return exe_path;
+    }
+  }
+  // If we don't have procfs mounted, fall back to argv[0]
+  if (getprogpath(exe_path, argv0) != NULL)
+    return exe_path;
+#elif defined(__linux__) || defined(__CYGWIN__) || defined(__gnu_hurd__)
+  char exe_path[MAXPATHLEN];
+  const char *aPath = "/proc/self/exe";
+  if (sys::fs::exists(aPath)) {
+    // /proc is not always mounted under Linux (chroot for example).
+    ssize_t len = readlink(aPath, exe_path, sizeof(exe_path));
+    if (len < 0)
+      return "";
+
+    // Null terminate the string for realpath. readlink never null
+    // terminates its output.
+    len = std::min(len, ssize_t(sizeof(exe_path) - 1));
+    exe_path[len] = '\0';
+
+    // On Linux, /proc/self/exe always looks through symlinks. However, on
+    // GNU/Hurd, /proc/self/exe is a symlink to the path that was used to start
+    // the program, and not the eventual binary file. Therefore, call realpath
+    // so this behaves the same on all platforms.
+#if _POSIX_VERSION >= 200112 || defined(__GLIBC__)
+    if (char *real_path = realpath(exe_path, NULL)) {
+      std::string ret = std::string(real_path);
+      free(real_path);
+      return ret;
+    }
+#else
+    char real_path[MAXPATHLEN];
+    if (realpath(exe_path, real_path))
+      return std::string(real_path);
+#endif
+  }
+  // Fall back to the classical detection.
+  if (getprogpath(exe_path, argv0))
+    return exe_path;
+#elif defined(HAVE_DLFCN_H) && defined(HAVE_DLADDR)
+  // Use dladdr to get executable path if available.
+  Dl_info DLInfo;
+  int err = dladdr(MainAddr, &DLInfo);
+  if (err == 0)
+    return "";
+
+  // If the filename is a symlink, we need to resolve and return the location of
+  // the actual executable.
+  char link_path[MAXPATHLEN];
+  if (realpath(DLInfo.dli_fname, link_path))
+    return link_path;
+#else
+#error GetMainExecutable is not implemented on this host yet.
+#endif
+  return "";
+}
+
+TimePoint<> basic_file_status::getLastAccessedTime() const {
+  return toTimePoint(fs_st_atime, fs_st_atime_nsec);
+}
+
+TimePoint<> basic_file_status::getLastModificationTime() const {
+  return toTimePoint(fs_st_mtime, fs_st_mtime_nsec);
+}
+
+UniqueID file_status::getUniqueID() const {
+  return UniqueID(fs_st_dev, fs_st_ino);
+}
+
+uint32_t file_status::getLinkCount() const {
+  return fs_st_nlinks;
+}
+
+ErrorOr<space_info> disk_space(const Twine &Path) {
+  struct STATVFS Vfs;
+  if (::STATVFS(const_cast<char *>(Path.str().c_str()), &Vfs))
+    return std::error_code(errno, std::generic_category());
+  auto FrSize = STATVFS_F_FRSIZE(Vfs);
+  space_info SpaceInfo;
+  SpaceInfo.capacity = static_cast<uint64_t>(Vfs.f_blocks) * FrSize;
+  SpaceInfo.free = static_cast<uint64_t>(Vfs.f_bfree) * FrSize;
+  SpaceInfo.available = static_cast<uint64_t>(Vfs.f_bavail) * FrSize;
+  return SpaceInfo;
+}
+
+std::error_code current_path(SmallVectorImpl<char> &result) {
+  result.clear();
+
+  const char *pwd = ::getenv("PWD");
+  llvm::sys::fs::file_status PWDStatus, DotStatus;
+  if (pwd && llvm::sys::path::is_absolute(pwd) &&
+      !llvm::sys::fs::status(pwd, PWDStatus) &&
+      !llvm::sys::fs::status(".", DotStatus) &&
+      PWDStatus.getUniqueID() == DotStatus.getUniqueID()) {
+    result.append(pwd, pwd + strlen(pwd));
+    return std::error_code();
+  }
+
+#ifdef MAXPATHLEN
+  result.reserve(MAXPATHLEN);
+#else
+// For GNU Hurd
+  result.reserve(1024);
+#endif
+
+  while (true) {
+    if (::getcwd(result.data(), result.capacity()) == nullptr) {
+      // See if there was a real error.
+      if (errno != ENOMEM)
+        return std::error_code(errno, std::generic_category());
+      // Otherwise there just wasn't enough space.
+      result.reserve(result.capacity() * 2);
+    } else
+      break;
+  }
+
+  result.set_size(strlen(result.data()));
+  return std::error_code();
+}
+
+std::error_code set_current_path(const Twine &path) {
+  SmallString<128> path_storage;
+  StringRef p = path.toNullTerminatedStringRef(path_storage);
+
+  if (::chdir(p.begin()) == -1)
+    return std::error_code(errno, std::generic_category());
+
+  return std::error_code();
+}
+
+std::error_code create_directory(const Twine &path, bool IgnoreExisting,
+                                 perms Perms) {
+  SmallString<128> path_storage;
+  StringRef p = path.toNullTerminatedStringRef(path_storage);
+
+  if (::mkdir(p.begin(), Perms) == -1) {
+    if (errno != EEXIST || !IgnoreExisting)
+      return std::error_code(errno, std::generic_category());
+  }
+
+  return std::error_code();
+}
+
+// Note that we are using symbolic link because hard links are not supported by
+// all filesystems (SMB doesn't).
+std::error_code create_link(const Twine &to, const Twine &from) {
+  // Get arguments.
+  SmallString<128> from_storage;
+  SmallString<128> to_storage;
+  StringRef f = from.toNullTerminatedStringRef(from_storage);
+  StringRef t = to.toNullTerminatedStringRef(to_storage);
+
+  if (::symlink(t.begin(), f.begin()) == -1)
+    return std::error_code(errno, std::generic_category());
+
+  return std::error_code();
+}
+
+std::error_code create_hard_link(const Twine &to, const Twine &from) {
+  // Get arguments.
+  SmallString<128> from_storage;
+  SmallString<128> to_storage;
+  StringRef f = from.toNullTerminatedStringRef(from_storage);
+  StringRef t = to.toNullTerminatedStringRef(to_storage);
+
+  if (::link(t.begin(), f.begin()) == -1)
+    return std::error_code(errno, std::generic_category());
+
+  return std::error_code();
+}
+
+std::error_code remove(const Twine &path, bool IgnoreNonExisting) {
+  SmallString<128> path_storage;
+  StringRef p = path.toNullTerminatedStringRef(path_storage);
+
+  struct stat buf;
+  if (lstat(p.begin(), &buf) != 0) {
+    if (errno != ENOENT || !IgnoreNonExisting)
+      return std::error_code(errno, std::generic_category());
+    return std::error_code();
+  }
+
+  // Note: this check catches strange situations. In all cases, LLVM should
+  // only be involved in the creation and deletion of regular files.  This
+  // check ensures that what we're trying to erase is a regular file. It
+  // effectively prevents LLVM from erasing things like /dev/null, any block
+  // special file, or other things that aren't "regular" files.
+  if (!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode) && !S_ISLNK(buf.st_mode))
+    return make_error_code(errc::operation_not_permitted);
+
+  if (::remove(p.begin()) == -1) {
+    if (errno != ENOENT || !IgnoreNonExisting)
+      return std::error_code(errno, std::generic_category());
+  }
+
+  return std::error_code();
+}
+
+static bool is_local_impl(struct STATVFS &Vfs) {
+#if defined(__linux__) || defined(__GNU__)
+#ifndef NFS_SUPER_MAGIC
+#define NFS_SUPER_MAGIC 0x6969
+#endif
+#ifndef SMB_SUPER_MAGIC
+#define SMB_SUPER_MAGIC 0x517B
+#endif
+#ifndef CIFS_MAGIC_NUMBER
+#define CIFS_MAGIC_NUMBER 0xFF534D42
+#endif
+#ifdef __GNU__
+  switch ((uint32_t)Vfs.__f_type) {
+#else
+  switch ((uint32_t)Vfs.f_type) {
+#endif
+  case NFS_SUPER_MAGIC:
+  case SMB_SUPER_MAGIC:
+  case CIFS_MAGIC_NUMBER:
+    return false;
+  default:
+    return true;
+  }
+#elif defined(__CYGWIN__)
+  // Cygwin doesn't expose this information; would need to use Win32 API.
+  return false;
+#elif defined(__Fuchsia__)
+  // Fuchsia doesn't yet support remote filesystem mounts.
+  return true;
+#elif defined(__EMSCRIPTEN__)
+  // Emscripten doesn't currently support remote filesystem mounts.
+  return true;
+#elif defined(__HAIKU__)
+  // Haiku doesn't expose this information.
+  return false;
+#elif defined(__sun)
+  // statvfs::f_basetype contains a null-terminated FSType name of the mounted target
+  StringRef fstype(Vfs.f_basetype);
+  // NFS is the only non-local fstype??
+  return !fstype.equals("nfs");
+#elif defined(_AIX)
+  // Call mntctl; try more than twice in case of timing issues with a concurrent
+  // mount.
+  int Ret;
+  size_t BufSize = 2048u;
+  std::unique_ptr<char[]> Buf;
+  int Tries = 3;
+  while (Tries--) {
+    Buf = std::make_unique<char[]>(BufSize);
+    Ret = mntctl(MCTL_QUERY, BufSize, Buf.get());
+    if (Ret != 0)
+      break;
+    BufSize = *reinterpret_cast<unsigned int *>(Buf.get());
+    Buf.reset();
+  }
+
+  if (Ret == -1)
+    // There was an error; "remote" is the conservative answer.
+    return false;
+
+  // Look for the correct vmount entry.
+  char *CurObjPtr = Buf.get();
+  while (Ret--) {
+    struct vmount *Vp = reinterpret_cast<struct vmount *>(CurObjPtr);
+    static_assert(sizeof(Vfs.f_fsid) == sizeof(Vp->vmt_fsid),
+                  "fsid length mismatch");
+    if (memcmp(&Vfs.f_fsid, &Vp->vmt_fsid, sizeof Vfs.f_fsid) == 0)
+      return (Vp->vmt_flags & MNT_REMOTE) == 0;
+
+    CurObjPtr += Vp->vmt_length;
+  }
+
+  // vmount entry not found; "remote" is the conservative answer.
+  return false;
+#else
+  return !!(STATVFS_F_FLAG(Vfs) & MNT_LOCAL);
+#endif
+}
+
+std::error_code is_local(const Twine &Path, bool &Result) {
+  struct STATVFS Vfs;
+  if (::STATVFS(const_cast<char *>(Path.str().c_str()), &Vfs))
+    return std::error_code(errno, std::generic_category());
+
+  Result = is_local_impl(Vfs);
+  return std::error_code();
+}
+
+std::error_code is_local(int FD, bool &Result) {
+  struct STATVFS Vfs;
+  if (::FSTATVFS(FD, &Vfs))
+    return std::error_code(errno, std::generic_category());
+
+  Result = is_local_impl(Vfs);
+  return std::error_code();
+}
+
+std::error_code rename(const Twine &from, const Twine &to) {
+  // Get arguments.
+  SmallString<128> from_storage;
+  SmallString<128> to_storage;
+  StringRef f = from.toNullTerminatedStringRef(from_storage);
+  StringRef t = to.toNullTerminatedStringRef(to_storage);
+
+  if (::rename(f.begin(), t.begin()) == -1)
+    return std::error_code(errno, std::generic_category());
+
+  return std::error_code();
+}
+
+std::error_code resize_file(int FD, uint64_t Size) {
+#if defined(HAVE_POSIX_FALLOCATE)
+  // If we have posix_fallocate use it. Unlike ftruncate it always allocates
+  // space, so we get an error if the disk is full.
+  if (int Err = ::posix_fallocate(FD, 0, Size)) {
+#ifdef _AIX
+    constexpr int NotSupportedError = ENOTSUP;
+#else
+    constexpr int NotSupportedError = EOPNOTSUPP;
+#endif
+    if (Err != EINVAL && Err != NotSupportedError)
+      return std::error_code(Err, std::generic_category());
+  }
+#endif
+  // Use ftruncate as a fallback. It may or may not allocate space. At least on
+  // OS X with HFS+ it does.
+  if (::ftruncate(FD, Size) == -1)
+    return std::error_code(errno, std::generic_category());
+
+  return std::error_code();
+}
+
+static int convertAccessMode(AccessMode Mode) {
+  switch (Mode) {
+  case AccessMode::Exist:
+    return F_OK;
+  case AccessMode::Write:
+    return W_OK;
+  case AccessMode::Execute:
+    return R_OK | X_OK; // scripts also need R_OK.
+  }
+  llvm_unreachable("invalid enum");
+}
+
+std::error_code access(const Twine &Path, AccessMode Mode) {
+  SmallString<128> PathStorage;
+  StringRef P = Path.toNullTerminatedStringRef(PathStorage);
+
+  if (::access(P.begin(), convertAccessMode(Mode)) == -1)
+    return std::error_code(errno, std::generic_category());
+
+  if (Mode == AccessMode::Execute) {
+    // Don't say that directories are executable.
+    struct stat buf;
+    if (0 != stat(P.begin(), &buf))
+      return errc::permission_denied;
+    if (!S_ISREG(buf.st_mode))
+      return errc::permission_denied;
+  }
+
+  return std::error_code();
+}
+
+bool can_execute(const Twine &Path) {
+  return !access(Path, AccessMode::Execute);
+}
+
+bool equivalent(file_status A, file_status B) {
+  assert(status_known(A) && status_known(B));
+  return A.fs_st_dev == B.fs_st_dev &&
+         A.fs_st_ino == B.fs_st_ino;
+}
+
+std::error_code equivalent(const Twine &A, const Twine &B, bool &result) {
+  file_status fsA, fsB;
+  if (std::error_code ec = status(A, fsA))
+    return ec;
+  if (std::error_code ec = status(B, fsB))
+    return ec;
+  result = equivalent(fsA, fsB);
+  return std::error_code();
+}
+
+static void expandTildeExpr(SmallVectorImpl<char> &Path) {
+  StringRef PathStr(Path.begin(), Path.size());
+  if (PathStr.empty() || !PathStr.startswith("~"))
+    return;
+
+  PathStr = PathStr.drop_front();
+  StringRef Expr =
+      PathStr.take_until([](char c) { return path::is_separator(c); });
+  StringRef Remainder = PathStr.substr(Expr.size() + 1);
+  SmallString<128> Storage;
+  if (Expr.empty()) {
+    // This is just ~/..., resolve it to the current user's home dir.
+    if (!path::home_directory(Storage)) {
+      // For some reason we couldn't get the home directory.  Just exit.
+      return;
+    }
+
+    // Overwrite the first character and insert the rest.
+    Path[0] = Storage[0];
+    Path.insert(Path.begin() + 1, Storage.begin() + 1, Storage.end());
+    return;
+  }
+
+  // This is a string of the form ~username/, look up this user's entry in the
+  // password database.
+  struct passwd *Entry = nullptr;
+  std::string User = Expr.str();
+  Entry = ::getpwnam(User.c_str());
+
+  if (!Entry) {
+    // Unable to look up the entry, just return back the original path.
+    return;
+  }
+
+  Storage = Remainder;
+  Path.clear();
+  Path.append(Entry->pw_dir, Entry->pw_dir + strlen(Entry->pw_dir));
+  llvm::sys::path::append(Path, Storage);
+}
+
+
+void expand_tilde(const Twine &path, SmallVectorImpl<char> &dest) {
+  dest.clear();
+  if (path.isTriviallyEmpty())
+    return;
+
+  path.toVector(dest);
+  expandTildeExpr(dest);
+
+  return;
+}
+
+static file_type typeForMode(mode_t Mode) {
+  if (S_ISDIR(Mode))
+    return file_type::directory_file;
+  else if (S_ISREG(Mode))
+    return file_type::regular_file;
+  else if (S_ISBLK(Mode))
+    return file_type::block_file;
+  else if (S_ISCHR(Mode))
+    return file_type::character_file;
+  else if (S_ISFIFO(Mode))
+    return file_type::fifo_file;
+  else if (S_ISSOCK(Mode))
+    return file_type::socket_file;
+  else if (S_ISLNK(Mode))
+    return file_type::symlink_file;
+  return file_type::type_unknown;
+}
+
+static std::error_code fillStatus(int StatRet, const struct stat &Status,
+                                  file_status &Result) {
+  if (StatRet != 0) {
+    std::error_code EC(errno, std::generic_category());
+    if (EC == errc::no_such_file_or_directory)
+      Result = file_status(file_type::file_not_found);
+    else
+      Result = file_status(file_type::status_error);
+    return EC;
+  }
+
+  uint32_t atime_nsec, mtime_nsec;
+#if defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
+  atime_nsec = Status.st_atimespec.tv_nsec;
+  mtime_nsec = Status.st_mtimespec.tv_nsec;
+#elif defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
+  atime_nsec = Status.st_atim.tv_nsec;
+  mtime_nsec = Status.st_mtim.tv_nsec;
+#else
+  atime_nsec = mtime_nsec = 0;
+#endif
+
+  perms Perms = static_cast<perms>(Status.st_mode) & all_perms;
+  Result = file_status(typeForMode(Status.st_mode), Perms, Status.st_dev,
+                       Status.st_nlink, Status.st_ino,
+                       Status.st_atime, atime_nsec, Status.st_mtime, mtime_nsec,
+                       Status.st_uid, Status.st_gid, Status.st_size);
+
+  return std::error_code();
+}
+
+std::error_code status(const Twine &Path, file_status &Result, bool Follow) {
+  SmallString<128> PathStorage;
+  StringRef P = Path.toNullTerminatedStringRef(PathStorage);
+
+  struct stat Status;
+  int StatRet = (Follow ? ::stat : ::lstat)(P.begin(), &Status);
+  return fillStatus(StatRet, Status, Result);
+}
+
+std::error_code status(int FD, file_status &Result) {
+  struct stat Status;
+  int StatRet = ::fstat(FD, &Status);
+  return fillStatus(StatRet, Status, Result);
+}
+
+unsigned getUmask() {
+  // Chose arbitary new mask and reset the umask to the old mask.
+  // umask(2) never fails so ignore the return of the second call.
+  unsigned Mask = ::umask(0);
+  (void) ::umask(Mask);
+  return Mask;
+}
+
+std::error_code setPermissions(const Twine &Path, perms Permissions) {
+  SmallString<128> PathStorage;
+  StringRef P = Path.toNullTerminatedStringRef(PathStorage);
+
+  if (::chmod(P.begin(), Permissions))
+    return std::error_code(errno, std::generic_category());
+  return std::error_code();
+}
+
+std::error_code setPermissions(int FD, perms Permissions) {
+  if (::fchmod(FD, Permissions))
+    return std::error_code(errno, std::generic_category());
+  return std::error_code();
+}
+
+std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime,
+                                                 TimePoint<> ModificationTime) {
+#if defined(HAVE_FUTIMENS)
+  timespec Times[2];
+  Times[0] = sys::toTimeSpec(AccessTime);
+  Times[1] = sys::toTimeSpec(ModificationTime);
+  if (::futimens(FD, Times))
+    return std::error_code(errno, std::generic_category());
+  return std::error_code();
+#elif defined(HAVE_FUTIMES)
+  timeval Times[2];
+  Times[0] = sys::toTimeVal(
+      std::chrono::time_point_cast<std::chrono::microseconds>(AccessTime));
+  Times[1] =
+      sys::toTimeVal(std::chrono::time_point_cast<std::chrono::microseconds>(
+          ModificationTime));
+  if (::futimes(FD, Times))
+    return std::error_code(errno, std::generic_category());
+  return std::error_code();
+#else
+#warning Missing futimes() and futimens()
+  return make_error_code(errc::function_not_supported);
+#endif
+}
+
+std::error_code mapped_file_region::init(int FD, uint64_t Offset,
+                                         mapmode Mode) {
+  assert(Size != 0);
+
+  int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE;
+  int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE);
+#if defined(__APPLE__)
+  //----------------------------------------------------------------------
+  // Newer versions of MacOSX have a flag that will allow us to read from
+  // binaries whose code signature is invalid without crashing by using
+  // the MAP_RESILIENT_CODESIGN flag. Also if a file from removable media
+  // is mapped we can avoid crashing and return zeroes to any pages we try
+  // to read if the media becomes unavailable by using the
+  // MAP_RESILIENT_MEDIA flag.  These flags are only usable when mapping
+  // with PROT_READ, so take care not to specify them otherwise.
+  //----------------------------------------------------------------------
+  if (Mode == readonly) {
+#if defined(MAP_RESILIENT_CODESIGN)
+    flags |= MAP_RESILIENT_CODESIGN;
+#endif
+#if defined(MAP_RESILIENT_MEDIA)
+    flags |= MAP_RESILIENT_MEDIA;
+#endif
+  }
+#endif // #if defined (__APPLE__)
+
+  Mapping = ::mmap(nullptr, Size, prot, flags, FD, Offset);
+  if (Mapping == MAP_FAILED)
+    return std::error_code(errno, std::generic_category());
+  return std::error_code();
+}
+
+mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length,
+                                       uint64_t offset, std::error_code &ec)
+    : Size(length), Mapping(), Mode(mode) {
+  (void)Mode;
+  ec = init(fd, offset, mode);
+  if (ec)
+    Mapping = nullptr;
+}
+
+mapped_file_region::~mapped_file_region() {
+  if (Mapping)
+    ::munmap(Mapping, Size);
+}
+
+size_t mapped_file_region::size() const {
+  assert(Mapping && "Mapping failed but used anyway!");
+  return Size;
+}
+
+char *mapped_file_region::data() const {
+  assert(Mapping && "Mapping failed but used anyway!");
+  return reinterpret_cast<char*>(Mapping);
+}
+
+const char *mapped_file_region::const_data() const {
+  assert(Mapping && "Mapping failed but used anyway!");
+  return reinterpret_cast<const char*>(Mapping);
+}
+
+int mapped_file_region::alignment() {
+  return Process::getPageSizeEstimate();
+}
+
+std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
+                                                     StringRef path,
+                                                     bool follow_symlinks) {
+  SmallString<128> path_null(path);
+  DIR *directory = ::opendir(path_null.c_str());
+  if (!directory)
+    return std::error_code(errno, std::generic_category());
+
+  it.IterationHandle = reinterpret_cast<intptr_t>(directory);
+  // Add something for replace_filename to replace.
+  path::append(path_null, ".");
+  it.CurrentEntry = directory_entry(path_null.str(), follow_symlinks);
+  return directory_iterator_increment(it);
+}
+
+std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
+  if (it.IterationHandle)
+    ::closedir(reinterpret_cast<DIR *>(it.IterationHandle));
+  it.IterationHandle = 0;
+  it.CurrentEntry = directory_entry();
+  return std::error_code();
+}
+
+static file_type direntType(dirent* Entry) {
+  // Most platforms provide the file type in the dirent: Linux/BSD/Mac.
+  // The DTTOIF macro lets us reuse our status -> type conversion.
+  // Note that while glibc provides a macro to see if this is supported,
+  // _DIRENT_HAVE_D_TYPE, it's not defined on BSD/Mac, so we test for the
+  // d_type-to-mode_t conversion macro instead.
+#if defined(DTTOIF)
+  return typeForMode(DTTOIF(Entry->d_type));
+#else
+  // Other platforms such as Solaris require a stat() to get the type.
+  return file_type::type_unknown;
+#endif
+}
+
+std::error_code detail::directory_iterator_increment(detail::DirIterState &It) {
+  errno = 0;
+  dirent *CurDir = ::readdir(reinterpret_cast<DIR *>(It.IterationHandle));
+  if (CurDir == nullptr && errno != 0) {
+    return std::error_code(errno, std::generic_category());
+  } else if (CurDir != nullptr) {
+    StringRef Name(CurDir->d_name);
+    if ((Name.size() == 1 && Name[0] == '.') ||
+        (Name.size() == 2 && Name[0] == '.' && Name[1] == '.'))
+      return directory_iterator_increment(It);
+    It.CurrentEntry.replace_filename(Name, direntType(CurDir));
+  } else
+    return directory_iterator_destruct(It);
+
+  return std::error_code();
+}
+
+ErrorOr<basic_file_status> directory_entry::status() const {
+  file_status s;
+  if (auto EC = fs::status(Path, s, FollowSymlinks))
+    return EC;
+  return s;
+}
+
+#if !defined(F_GETPATH)
+static bool hasProcSelfFD() {
+  // If we have a /proc filesystem mounted, we can quickly establish the
+  // real name of the file with readlink
+  static const bool Result = (::access("/proc/self/fd", R_OK) == 0);
+  return Result;
+}
+#endif
+
+static int nativeOpenFlags(CreationDisposition Disp, OpenFlags Flags,
+                           FileAccess Access) {
+  int Result = 0;
+  if (Access == FA_Read)
+    Result |= O_RDONLY;
+  else if (Access == FA_Write)
+    Result |= O_WRONLY;
+  else if (Access == (FA_Read | FA_Write))
+    Result |= O_RDWR;
+
+  // This is for compatibility with old code that assumed OF_Append implied
+  // would open an existing file.  See Windows/Path.inc for a longer comment.
+  if (Flags & OF_Append)
+    Disp = CD_OpenAlways;
+
+  if (Disp == CD_CreateNew) {
+    Result |= O_CREAT; // Create if it doesn't exist.
+    Result |= O_EXCL;  // Fail if it does.
+  } else if (Disp == CD_CreateAlways) {
+    Result |= O_CREAT; // Create if it doesn't exist.
+    Result |= O_TRUNC; // Truncate if it does.
+  } else if (Disp == CD_OpenAlways) {
+    Result |= O_CREAT; // Create if it doesn't exist.
+  } else if (Disp == CD_OpenExisting) {
+    // Nothing special, just don't add O_CREAT and we get these semantics.
+  }
+
+  if (Flags & OF_Append)
+    Result |= O_APPEND;
+
+#ifdef O_CLOEXEC
+  if (!(Flags & OF_ChildInherit))
+    Result |= O_CLOEXEC;
+#endif
+
+  return Result;
+}
+
+std::error_code openFile(const Twine &Name, int &ResultFD,
+                         CreationDisposition Disp, FileAccess Access,
+                         OpenFlags Flags, unsigned Mode) {
+  int OpenFlags = nativeOpenFlags(Disp, Flags, Access);
+
+  SmallString<128> Storage;
+  StringRef P = Name.toNullTerminatedStringRef(Storage);
+  // Call ::open in a lambda to avoid overload resolution in RetryAfterSignal
+  // when open is overloaded, such as in Bionic.
+  auto Open = [&]() { return ::open(P.begin(), OpenFlags, Mode); };
+  if ((ResultFD = sys::RetryAfterSignal(-1, Open)) < 0)
+    return std::error_code(errno, std::generic_category());
+#ifndef O_CLOEXEC
+  if (!(Flags & OF_ChildInherit)) {
+    int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC);
+    (void)r;
+    assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed");
+  }
+#endif
+  return std::error_code();
+}
+
+Expected<int> openNativeFile(const Twine &Name, CreationDisposition Disp,
+                             FileAccess Access, OpenFlags Flags,
+                             unsigned Mode) {
+
+  int FD;
+  std::error_code EC = openFile(Name, FD, Disp, Access, Flags, Mode);
+  if (EC)
+    return errorCodeToError(EC);
+  return FD;
+}
+
+std::error_code openFileForRead(const Twine &Name, int &ResultFD,
+                                OpenFlags Flags,
+                                SmallVectorImpl<char> *RealPath) {
+  std::error_code EC =
+      openFile(Name, ResultFD, CD_OpenExisting, FA_Read, Flags, 0666);
+  if (EC)
+    return EC;
+
+  // Attempt to get the real name of the file, if the user asked
+  if(!RealPath)
+    return std::error_code();
+  RealPath->clear();
+#if defined(F_GETPATH)
+  // When F_GETPATH is availble, it is the quickest way to get
+  // the real path name.
+  char Buffer[MAXPATHLEN];
+  if (::fcntl(ResultFD, F_GETPATH, Buffer) != -1)
+    RealPath->append(Buffer, Buffer + strlen(Buffer));
+#else
+  char Buffer[PATH_MAX];
+  if (hasProcSelfFD()) {
+    char ProcPath[64];
+    snprintf(ProcPath, sizeof(ProcPath), "/proc/self/fd/%d", ResultFD);
+    ssize_t CharCount = ::readlink(ProcPath, Buffer, sizeof(Buffer));
+    if (CharCount > 0)
+      RealPath->append(Buffer, Buffer + CharCount);
+  } else {
+    SmallString<128> Storage;
+    StringRef P = Name.toNullTerminatedStringRef(Storage);
+
+    // Use ::realpath to get the real path name
+    if (::realpath(P.begin(), Buffer) != nullptr)
+      RealPath->append(Buffer, Buffer + strlen(Buffer));
+  }
+#endif
+  return std::error_code();
+}
+
+Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags,
+                                       SmallVectorImpl<char> *RealPath) {
+  file_t ResultFD;
+  std::error_code EC = openFileForRead(Name, ResultFD, Flags, RealPath);
+  if (EC)
+    return errorCodeToError(EC);
+  return ResultFD;
+}
+
+file_t getStdinHandle() { return 0; }
+file_t getStdoutHandle() { return 1; }
+file_t getStderrHandle() { return 2; }
+
+Expected<size_t> readNativeFile(file_t FD, MutableArrayRef<char> Buf) {
+  ssize_t NumRead =
+      sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Buf.size());
+  if (ssize_t(NumRead) == -1)
+    return errorCodeToError(std::error_code(errno, std::generic_category()));
+  return NumRead;
+}
+
+Expected<size_t> readNativeFileSlice(file_t FD, MutableArrayRef<char> Buf,
+                                     uint64_t Offset) {
+#ifdef HAVE_PREAD
+  ssize_t NumRead =
+      sys::RetryAfterSignal(-1, ::pread, FD, Buf.data(), Buf.size(), Offset);
+#else
+  if (lseek(FD, Offset, SEEK_SET) == -1)
+    return errorCodeToError(std::error_code(errno, std::generic_category()));
+  ssize_t NumRead =
+      sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Buf.size());
+#endif
+  if (NumRead == -1)
+    return errorCodeToError(std::error_code(errno, std::generic_category()));
+  return NumRead;
+}
+
+std::error_code closeFile(file_t &F) {
+  file_t TmpF = F;
+  F = kInvalidFile;
+  return Process::SafelyCloseFileDescriptor(TmpF);
+}
+
+template <typename T>
+static std::error_code remove_directories_impl(const T &Entry,
+                                               bool IgnoreErrors) {
+  std::error_code EC;
+  directory_iterator Begin(Entry, EC, false);
+  directory_iterator End;
+  while (Begin != End) {
+    auto &Item = *Begin;
+    ErrorOr<basic_file_status> st = Item.status();
+    if (!st && !IgnoreErrors)
+      return st.getError();
+
+    if (is_directory(*st)) {
+      EC = remove_directories_impl(Item, IgnoreErrors);
+      if (EC && !IgnoreErrors)
+        return EC;
+    }
+
+    EC = fs::remove(Item.path(), true);
+    if (EC && !IgnoreErrors)
+      return EC;
+
+    Begin.increment(EC);
+    if (EC && !IgnoreErrors)
+      return EC;
+  }
+  return std::error_code();
+}
+
+std::error_code remove_directories(const Twine &path, bool IgnoreErrors) {
+  auto EC = remove_directories_impl(path, IgnoreErrors);
+  if (EC && !IgnoreErrors)
+    return EC;
+  EC = fs::remove(path, true);
+  if (EC && !IgnoreErrors)
+    return EC;
+  return std::error_code();
+}
+
+std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest,
+                          bool expand_tilde) {
+  dest.clear();
+  if (path.isTriviallyEmpty())
+    return std::error_code();
+
+  if (expand_tilde) {
+    SmallString<128> Storage;
+    path.toVector(Storage);
+    expandTildeExpr(Storage);
+    return real_path(Storage, dest, false);
+  }
+
+  SmallString<128> Storage;
+  StringRef P = path.toNullTerminatedStringRef(Storage);
+  char Buffer[PATH_MAX];
+  if (::realpath(P.begin(), Buffer) == nullptr)
+    return std::error_code(errno, std::generic_category());
+  dest.append(Buffer, Buffer + strlen(Buffer));
+  return std::error_code();
+}
+
+} // end namespace fs
+
+namespace path {
+
+bool home_directory(SmallVectorImpl<char> &result) {
+  char *RequestedDir = getenv("HOME");
+  if (!RequestedDir) {
+    struct passwd *pw = getpwuid(getuid());
+    if (pw && pw->pw_dir)
+      RequestedDir = pw->pw_dir;
+  }
+  if (!RequestedDir)
+    return false;
+
+  result.clear();
+  result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
+  return true;
+}
+
+static bool getDarwinConfDir(bool TempDir, SmallVectorImpl<char> &Result) {
+  #if defined(_CS_DARWIN_USER_TEMP_DIR) && defined(_CS_DARWIN_USER_CACHE_DIR)
+  // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR.
+  // macros defined in <unistd.h> on darwin >= 9
+  int ConfName = TempDir ? _CS_DARWIN_USER_TEMP_DIR
+                         : _CS_DARWIN_USER_CACHE_DIR;
+  size_t ConfLen = confstr(ConfName, nullptr, 0);
+  if (ConfLen > 0) {
+    do {
+      Result.resize(ConfLen);
+      ConfLen = confstr(ConfName, Result.data(), Result.size());
+    } while (ConfLen > 0 && ConfLen != Result.size());
+
+    if (ConfLen > 0) {
+      assert(Result.back() == 0);
+      Result.pop_back();
+      return true;
+    }
+
+    Result.clear();
+  }
+  #endif
+  return false;
+}
+
+static const char *getEnvTempDir() {
+  // Check whether the temporary directory is specified by an environment
+  // variable.
+  const char *EnvironmentVariables[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
+  for (const char *Env : EnvironmentVariables) {
+    if (const char *Dir = std::getenv(Env))
+      return Dir;
+  }
+
+  return nullptr;
+}
+
+static const char *getDefaultTempDir(bool ErasedOnReboot) {
+#ifdef P_tmpdir
+  if ((bool)P_tmpdir)
+    return P_tmpdir;
+#endif
+
+  if (ErasedOnReboot)
+    return "/tmp";
+  return "/var/tmp";
+}
+
+void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) {
+  Result.clear();
+
+  if (ErasedOnReboot) {
+    // There is no env variable for the cache directory.
+    if (const char *RequestedDir = getEnvTempDir()) {
+      Result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
+      return;
+    }
+  }
+
+  if (getDarwinConfDir(ErasedOnReboot, Result))
+    return;
+
+  const char *RequestedDir = getDefaultTempDir(ErasedOnReboot);
+  Result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
+}
+
+} // end namespace path
+
+namespace fs {
+
+#ifdef __APPLE__
+/// This implementation tries to perform an APFS CoW clone of the file,
+/// which can be much faster and uses less space.
+/// Unfortunately fcopyfile(3) does not support COPYFILE_CLONE, so the
+/// file descriptor variant of this function still uses the default
+/// implementation.
+std::error_code copy_file(const Twine &From, const Twine &To) {
+  uint32_t Flag = COPYFILE_DATA;
+#if __has_builtin(__builtin_available) && defined(COPYFILE_CLONE)
+  if (__builtin_available(macos 10.12, *)) {
+    bool IsSymlink;
+    if (std::error_code Error = is_symlink_file(From, IsSymlink))
+      return Error;
+    // COPYFILE_CLONE clones the symlink instead of following it
+    // and returns EEXISTS if the target file already exists.
+    if (!IsSymlink && !exists(To))
+      Flag = COPYFILE_CLONE;
+  }
+#endif
+  int Status =
+      copyfile(From.str().c_str(), To.str().c_str(), /* State */ NULL, Flag);
+
+  if (Status == 0)
+    return std::error_code();
+  return std::error_code(errno, std::generic_category());
+}
+#endif // __APPLE__
+
+} // end namespace fs
+
+} // end namespace sys
+} // end namespace llvm
diff --git a/binaryen/third_party/llvm-project/Unix/Unix.h b/binaryen/third_party/llvm-project/Unix/Unix.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/Unix/Unix.h
@@ -0,0 +1,114 @@
+//===- llvm/Support/Unix/Unix.h - Common Unix Include File -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines things specific to Unix implementations.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_SUPPORT_UNIX_UNIX_H
+#define LLVM_LIB_SUPPORT_UNIX_UNIX_H
+
+//===----------------------------------------------------------------------===//
+//=== WARNING: Implementation here must contain only generic UNIX code that
+//===          is guaranteed to work on all UNIX variants.
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Config/config.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/Errno.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <algorithm>
+#include <assert.h>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#include <time.h>
+
+#ifdef HAVE_DLFCN_H
+# include <dlfcn.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+/// This function builds an error message into \p ErrMsg using the \p prefix
+/// string and the Unix error number given by \p errnum. If errnum is -1, the
+/// default then the value of errno is used.
+/// Make an error message
+///
+/// If the error number can be converted to a string, it will be
+/// separated from prefix by ": ".
+static inline bool MakeErrMsg(
+  std::string* ErrMsg, const std::string& prefix, int errnum = -1) {
+  if (!ErrMsg)
+    return true;
+  if (errnum == -1)
+    errnum = errno;
+  *ErrMsg = prefix + ": " + llvm::sys::StrError(errnum);
+  return true;
+}
+
+// Include StrError(errnum) in a fatal error message.
+LLVM_ATTRIBUTE_NORETURN static inline void ReportErrnumFatal(const char *Msg,
+                                                             int errnum) {
+  std::string ErrMsg;
+  MakeErrMsg(&ErrMsg, Msg, errnum);
+  llvm::report_fatal_error(ErrMsg);
+}
+
+namespace llvm {
+namespace sys {
+
+/// Convert a struct timeval to a duration. Note that timeval can be used both
+/// as a time point and a duration. Be sure to check what the input represents.
+inline std::chrono::microseconds toDuration(const struct timeval &TV) {
+  return std::chrono::seconds(TV.tv_sec) +
+         std::chrono::microseconds(TV.tv_usec);
+}
+
+/// Convert a time point to struct timespec.
+inline struct timespec toTimeSpec(TimePoint<> TP) {
+  using namespace std::chrono;
+
+  struct timespec RetVal;
+  RetVal.tv_sec = toTimeT(TP);
+  RetVal.tv_nsec = (TP.time_since_epoch() % seconds(1)).count();
+  return RetVal;
+}
+
+/// Convert a time point to struct timeval.
+inline struct timeval toTimeVal(TimePoint<std::chrono::microseconds> TP) {
+  using namespace std::chrono;
+
+  struct timeval RetVal;
+  RetVal.tv_sec = toTimeT(TP);
+  RetVal.tv_usec = (TP.time_since_epoch() % seconds(1)).count();
+  return RetVal;
+}
+
+} // namespace sys
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/WithColor.cpp b/binaryen/third_party/llvm-project/WithColor.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/WithColor.cpp
@@ -0,0 +1,83 @@
+//===- WithColor.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+#if 0 // XXX BINARYEN
+cl::OptionCategory llvm::ColorCategory("Color Options");
+
+static cl::opt<cl::boolOrDefault>
+    UseColor("color", cl::cat(ColorCategory),
+             cl::desc("Use colors in output (default=autodetect)"),
+             cl::init(cl::BOU_UNSET));
+#endif
+
+WithColor::WithColor(raw_ostream &OS, HighlightColor Color, bool DisableColors)
+    : OS(OS), DisableColors(DisableColors) {
+  // Detect color from terminal type unless the user passed the --color option.
+  // XXX BINARYEN - no color support
+}
+
+raw_ostream &WithColor::error() { return error(errs()); }
+
+raw_ostream &WithColor::warning() { return warning(errs()); }
+
+raw_ostream &WithColor::note() { return note(errs()); }
+
+raw_ostream &WithColor::remark() { return remark(errs()); }
+
+raw_ostream &WithColor::error(raw_ostream &OS, StringRef Prefix,
+                              bool DisableColors) {
+  if (!Prefix.empty())
+    OS << Prefix << ": ";
+  return WithColor(OS, HighlightColor::Error, DisableColors).get()
+         << "error: ";
+}
+
+raw_ostream &WithColor::warning(raw_ostream &OS, StringRef Prefix,
+                                bool DisableColors) {
+  if (!Prefix.empty())
+    OS << Prefix << ": ";
+  return WithColor(OS, HighlightColor::Warning, DisableColors).get()
+         << "warning: ";
+}
+
+raw_ostream &WithColor::note(raw_ostream &OS, StringRef Prefix,
+                             bool DisableColors) {
+  if (!Prefix.empty())
+    OS << Prefix << ": ";
+  return WithColor(OS, HighlightColor::Note, DisableColors).get() << "note: ";
+}
+
+raw_ostream &WithColor::remark(raw_ostream &OS, StringRef Prefix,
+                               bool DisableColors) {
+  if (!Prefix.empty())
+    OS << Prefix << ": ";
+  return WithColor(OS, HighlightColor::Remark, DisableColors).get()
+         << "remark: ";
+}
+
+bool WithColor::colorsEnabled() {
+  return false; // XXX BINARYEN
+}
+
+WithColor &WithColor::changeColor(raw_ostream::Colors Color, bool Bold,
+                                  bool BG) {
+  // XXX BINARYEN
+  return *this;
+}
+
+WithColor &WithColor::resetColor() {
+  // XXX BINARYEN
+  return *this;
+}
+
+WithColor::~WithColor() { resetColor(); }
diff --git a/binaryen/third_party/llvm-project/YAMLParser.cpp b/binaryen/third_party/llvm-project/YAMLParser.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/YAMLParser.cpp
@@ -0,0 +1,2408 @@
+//===- YAMLParser.cpp - Simple YAML parser --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements a YAML parser.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/ADT/AllocatorList.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/Unicode.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <utility>
+
+using namespace llvm;
+using namespace yaml;
+
+enum UnicodeEncodingForm {
+  UEF_UTF32_LE, ///< UTF-32 Little Endian
+  UEF_UTF32_BE, ///< UTF-32 Big Endian
+  UEF_UTF16_LE, ///< UTF-16 Little Endian
+  UEF_UTF16_BE, ///< UTF-16 Big Endian
+  UEF_UTF8,     ///< UTF-8 or ascii.
+  UEF_Unknown   ///< Not a valid Unicode encoding.
+};
+
+/// EncodingInfo - Holds the encoding type and length of the byte order mark if
+///                it exists. Length is in {0, 2, 3, 4}.
+using EncodingInfo = std::pair<UnicodeEncodingForm, unsigned>;
+
+/// getUnicodeEncoding - Reads up to the first 4 bytes to determine the Unicode
+///                      encoding form of \a Input.
+///
+/// @param Input A string of length 0 or more.
+/// @returns An EncodingInfo indicating the Unicode encoding form of the input
+///          and how long the byte order mark is if one exists.
+static EncodingInfo getUnicodeEncoding(StringRef Input) {
+  if (Input.empty())
+    return std::make_pair(UEF_Unknown, 0);
+
+  switch (uint8_t(Input[0])) {
+  case 0x00:
+    if (Input.size() >= 4) {
+      if (  Input[1] == 0
+         && uint8_t(Input[2]) == 0xFE
+         && uint8_t(Input[3]) == 0xFF)
+        return std::make_pair(UEF_UTF32_BE, 4);
+      if (Input[1] == 0 && Input[2] == 0 && Input[3] != 0)
+        return std::make_pair(UEF_UTF32_BE, 0);
+    }
+
+    if (Input.size() >= 2 && Input[1] != 0)
+      return std::make_pair(UEF_UTF16_BE, 0);
+    return std::make_pair(UEF_Unknown, 0);
+  case 0xFF:
+    if (  Input.size() >= 4
+       && uint8_t(Input[1]) == 0xFE
+       && Input[2] == 0
+       && Input[3] == 0)
+      return std::make_pair(UEF_UTF32_LE, 4);
+
+    if (Input.size() >= 2 && uint8_t(Input[1]) == 0xFE)
+      return std::make_pair(UEF_UTF16_LE, 2);
+    return std::make_pair(UEF_Unknown, 0);
+  case 0xFE:
+    if (Input.size() >= 2 && uint8_t(Input[1]) == 0xFF)
+      return std::make_pair(UEF_UTF16_BE, 2);
+    return std::make_pair(UEF_Unknown, 0);
+  case 0xEF:
+    if (  Input.size() >= 3
+       && uint8_t(Input[1]) == 0xBB
+       && uint8_t(Input[2]) == 0xBF)
+      return std::make_pair(UEF_UTF8, 3);
+    return std::make_pair(UEF_Unknown, 0);
+  }
+
+  // It could still be utf-32 or utf-16.
+  if (Input.size() >= 4 && Input[1] == 0 && Input[2] == 0 && Input[3] == 0)
+    return std::make_pair(UEF_UTF32_LE, 0);
+
+  if (Input.size() >= 2 && Input[1] == 0)
+    return std::make_pair(UEF_UTF16_LE, 0);
+
+  return std::make_pair(UEF_UTF8, 0);
+}
+
+/// Pin the vtables to this file.
+void Node::anchor() {}
+void NullNode::anchor() {}
+void ScalarNode::anchor() {}
+void BlockScalarNode::anchor() {}
+void KeyValueNode::anchor() {}
+void MappingNode::anchor() {}
+void SequenceNode::anchor() {}
+void AliasNode::anchor() {}
+
+namespace llvm {
+namespace yaml {
+
+/// Token - A single YAML token.
+struct Token {
+  enum TokenKind {
+    TK_Error, // Uninitialized token.
+    TK_StreamStart,
+    TK_StreamEnd,
+    TK_VersionDirective,
+    TK_TagDirective,
+    TK_DocumentStart,
+    TK_DocumentEnd,
+    TK_BlockEntry,
+    TK_BlockEnd,
+    TK_BlockSequenceStart,
+    TK_BlockMappingStart,
+    TK_FlowEntry,
+    TK_FlowSequenceStart,
+    TK_FlowSequenceEnd,
+    TK_FlowMappingStart,
+    TK_FlowMappingEnd,
+    TK_Key,
+    TK_Value,
+    TK_Scalar,
+    TK_BlockScalar,
+    TK_Alias,
+    TK_Anchor,
+    TK_Tag
+  } Kind = TK_Error;
+
+  /// A string of length 0 or more whose begin() points to the logical location
+  /// of the token in the input.
+  StringRef Range;
+
+  /// The value of a block scalar node.
+  std::string Value;
+
+  Token() = default;
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+using TokenQueueT = BumpPtrList<Token>;
+
+namespace {
+
+/// This struct is used to track simple keys.
+///
+/// Simple keys are handled by creating an entry in SimpleKeys for each Token
+/// which could legally be the start of a simple key. When peekNext is called,
+/// if the Token To be returned is referenced by a SimpleKey, we continue
+/// tokenizing until that potential simple key has either been found to not be
+/// a simple key (we moved on to the next line or went further than 1024 chars).
+/// Or when we run into a Value, and then insert a Key token (and possibly
+/// others) before the SimpleKey's Tok.
+struct SimpleKey {
+  TokenQueueT::iterator Tok;
+  unsigned Column = 0;
+  unsigned Line = 0;
+  unsigned FlowLevel = 0;
+  bool IsRequired = false;
+
+  bool operator ==(const SimpleKey &Other) {
+    return Tok == Other.Tok;
+  }
+};
+
+} // end anonymous namespace
+
+/// The Unicode scalar value of a UTF-8 minimal well-formed code unit
+///        subsequence and the subsequence's length in code units (uint8_t).
+///        A length of 0 represents an error.
+using UTF8Decoded = std::pair<uint32_t, unsigned>;
+
+static UTF8Decoded decodeUTF8(StringRef Range) {
+  StringRef::iterator Position= Range.begin();
+  StringRef::iterator End = Range.end();
+  // 1 byte: [0x00, 0x7f]
+  // Bit pattern: 0xxxxxxx
+  if ((*Position & 0x80) == 0) {
+     return std::make_pair(*Position, 1);
+  }
+  // 2 bytes: [0x80, 0x7ff]
+  // Bit pattern: 110xxxxx 10xxxxxx
+  if (Position + 1 != End &&
+      ((*Position & 0xE0) == 0xC0) &&
+      ((*(Position + 1) & 0xC0) == 0x80)) {
+    uint32_t codepoint = ((*Position & 0x1F) << 6) |
+                          (*(Position + 1) & 0x3F);
+    if (codepoint >= 0x80)
+      return std::make_pair(codepoint, 2);
+  }
+  // 3 bytes: [0x8000, 0xffff]
+  // Bit pattern: 1110xxxx 10xxxxxx 10xxxxxx
+  if (Position + 2 != End &&
+      ((*Position & 0xF0) == 0xE0) &&
+      ((*(Position + 1) & 0xC0) == 0x80) &&
+      ((*(Position + 2) & 0xC0) == 0x80)) {
+    uint32_t codepoint = ((*Position & 0x0F) << 12) |
+                         ((*(Position + 1) & 0x3F) << 6) |
+                          (*(Position + 2) & 0x3F);
+    // Codepoints between 0xD800 and 0xDFFF are invalid, as
+    // they are high / low surrogate halves used by UTF-16.
+    if (codepoint >= 0x800 &&
+        (codepoint < 0xD800 || codepoint > 0xDFFF))
+      return std::make_pair(codepoint, 3);
+  }
+  // 4 bytes: [0x10000, 0x10FFFF]
+  // Bit pattern: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+  if (Position + 3 != End &&
+      ((*Position & 0xF8) == 0xF0) &&
+      ((*(Position + 1) & 0xC0) == 0x80) &&
+      ((*(Position + 2) & 0xC0) == 0x80) &&
+      ((*(Position + 3) & 0xC0) == 0x80)) {
+    uint32_t codepoint = ((*Position & 0x07) << 18) |
+                         ((*(Position + 1) & 0x3F) << 12) |
+                         ((*(Position + 2) & 0x3F) << 6) |
+                          (*(Position + 3) & 0x3F);
+    if (codepoint >= 0x10000 && codepoint <= 0x10FFFF)
+      return std::make_pair(codepoint, 4);
+  }
+  return std::make_pair(0, 0);
+}
+
+namespace llvm {
+namespace yaml {
+
+/// Scans YAML tokens from a MemoryBuffer.
+class Scanner {
+public:
+  Scanner(StringRef Input, SourceMgr &SM, bool ShowColors = true,
+          std::error_code *EC = nullptr);
+  Scanner(MemoryBufferRef Buffer, SourceMgr &SM_, bool ShowColors = true,
+          std::error_code *EC = nullptr);
+
+  /// Parse the next token and return it without popping it.
+  Token &peekNext();
+
+  /// Parse the next token and pop it from the queue.
+  Token getNext();
+
+  void printError(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Message,
+                  ArrayRef<SMRange> Ranges = None) {
+    SM.PrintMessage(Loc, Kind, Message, Ranges, /* FixIts= */ None, ShowColors);
+  }
+
+  void setError(const Twine &Message, StringRef::iterator Position) {
+    if (Current >= End)
+      Current = End - 1;
+
+    // propagate the error if possible
+    if (EC)
+      *EC = make_error_code(std::errc::invalid_argument);
+
+    // Don't print out more errors after the first one we encounter. The rest
+    // are just the result of the first, and have no meaning.
+    if (!Failed)
+      printError(SMLoc::getFromPointer(Current), SourceMgr::DK_Error, Message);
+    Failed = true;
+  }
+
+  void setError(const Twine &Message) {
+    setError(Message, Current);
+  }
+
+  /// Returns true if an error occurred while parsing.
+  bool failed() {
+    return Failed;
+  }
+
+private:
+  void init(MemoryBufferRef Buffer);
+
+  StringRef currentInput() {
+    return StringRef(Current, End - Current);
+  }
+
+  /// Decode a UTF-8 minimal well-formed code unit subsequence starting
+  ///        at \a Position.
+  ///
+  /// If the UTF-8 code units starting at Position do not form a well-formed
+  /// code unit subsequence, then the Unicode scalar value is 0, and the length
+  /// is 0.
+  UTF8Decoded decodeUTF8(StringRef::iterator Position) {
+    return ::decodeUTF8(StringRef(Position, End - Position));
+  }
+
+  // The following functions are based on the gramar rules in the YAML spec. The
+  // style of the function names it meant to closely match how they are written
+  // in the spec. The number within the [] is the number of the grammar rule in
+  // the spec.
+  //
+  // See 4.2 [Production Naming Conventions] for the meaning of the prefixes.
+  //
+  // c-
+  //   A production starting and ending with a special character.
+  // b-
+  //   A production matching a single line break.
+  // nb-
+  //   A production starting and ending with a non-break character.
+  // s-
+  //   A production starting and ending with a white space character.
+  // ns-
+  //   A production starting and ending with a non-space character.
+  // l-
+  //   A production matching complete line(s).
+
+  /// Skip a single nb-char[27] starting at Position.
+  ///
+  /// A nb-char is 0x9 | [0x20-0x7E] | 0x85 | [0xA0-0xD7FF] | [0xE000-0xFEFE]
+  ///                  | [0xFF00-0xFFFD] | [0x10000-0x10FFFF]
+  ///
+  /// @returns The code unit after the nb-char, or Position if it's not an
+  ///          nb-char.
+  StringRef::iterator skip_nb_char(StringRef::iterator Position);
+
+  /// Skip a single b-break[28] starting at Position.
+  ///
+  /// A b-break is 0xD 0xA | 0xD | 0xA
+  ///
+  /// @returns The code unit after the b-break, or Position if it's not a
+  ///          b-break.
+  StringRef::iterator skip_b_break(StringRef::iterator Position);
+
+  /// Skip a single s-space[31] starting at Position.
+  ///
+  /// An s-space is 0x20
+  ///
+  /// @returns The code unit after the s-space, or Position if it's not a
+  ///          s-space.
+  StringRef::iterator skip_s_space(StringRef::iterator Position);
+
+  /// Skip a single s-white[33] starting at Position.
+  ///
+  /// A s-white is 0x20 | 0x9
+  ///
+  /// @returns The code unit after the s-white, or Position if it's not a
+  ///          s-white.
+  StringRef::iterator skip_s_white(StringRef::iterator Position);
+
+  /// Skip a single ns-char[34] starting at Position.
+  ///
+  /// A ns-char is nb-char - s-white
+  ///
+  /// @returns The code unit after the ns-char, or Position if it's not a
+  ///          ns-char.
+  StringRef::iterator skip_ns_char(StringRef::iterator Position);
+
+  using SkipWhileFunc = StringRef::iterator (Scanner::*)(StringRef::iterator);
+
+  /// Skip minimal well-formed code unit subsequences until Func
+  ///        returns its input.
+  ///
+  /// @returns The code unit after the last minimal well-formed code unit
+  ///          subsequence that Func accepted.
+  StringRef::iterator skip_while( SkipWhileFunc Func
+                                , StringRef::iterator Position);
+
+  /// Skip minimal well-formed code unit subsequences until Func returns its
+  /// input.
+  void advanceWhile(SkipWhileFunc Func);
+
+  /// Scan ns-uri-char[39]s starting at Cur.
+  ///
+  /// This updates Cur and Column while scanning.
+  void scan_ns_uri_char();
+
+  /// Consume a minimal well-formed code unit subsequence starting at
+  ///        \a Cur. Return false if it is not the same Unicode scalar value as
+  ///        \a Expected. This updates \a Column.
+  bool consume(uint32_t Expected);
+
+  /// Skip \a Distance UTF-8 code units. Updates \a Cur and \a Column.
+  void skip(uint32_t Distance);
+
+  /// Return true if the minimal well-formed code unit subsequence at
+  ///        Pos is whitespace or a new line
+  bool isBlankOrBreak(StringRef::iterator Position);
+
+  /// Consume a single b-break[28] if it's present at the current position.
+  ///
+  /// Return false if the code unit at the current position isn't a line break.
+  bool consumeLineBreakIfPresent();
+
+  /// If IsSimpleKeyAllowed, create and push_back a new SimpleKey.
+  void saveSimpleKeyCandidate( TokenQueueT::iterator Tok
+                             , unsigned AtColumn
+                             , bool IsRequired);
+
+  /// Remove simple keys that can no longer be valid simple keys.
+  ///
+  /// Invalid simple keys are not on the current line or are further than 1024
+  /// columns back.
+  void removeStaleSimpleKeyCandidates();
+
+  /// Remove all simple keys on FlowLevel \a Level.
+  void removeSimpleKeyCandidatesOnFlowLevel(unsigned Level);
+
+  /// Unroll indentation in \a Indents back to \a Col. Creates BlockEnd
+  ///        tokens if needed.
+  bool unrollIndent(int ToColumn);
+
+  /// Increase indent to \a Col. Creates \a Kind token at \a InsertPoint
+  ///        if needed.
+  bool rollIndent( int ToColumn
+                 , Token::TokenKind Kind
+                 , TokenQueueT::iterator InsertPoint);
+
+  /// Skip a single-line comment when the comment starts at the current
+  /// position of the scanner.
+  void skipComment();
+
+  /// Skip whitespace and comments until the start of the next token.
+  void scanToNextToken();
+
+  /// Must be the first token generated.
+  bool scanStreamStart();
+
+  /// Generate tokens needed to close out the stream.
+  bool scanStreamEnd();
+
+  /// Scan a %BLAH directive.
+  bool scanDirective();
+
+  /// Scan a ... or ---.
+  bool scanDocumentIndicator(bool IsStart);
+
+  /// Scan a [ or { and generate the proper flow collection start token.
+  bool scanFlowCollectionStart(bool IsSequence);
+
+  /// Scan a ] or } and generate the proper flow collection end token.
+  bool scanFlowCollectionEnd(bool IsSequence);
+
+  /// Scan the , that separates entries in a flow collection.
+  bool scanFlowEntry();
+
+  /// Scan the - that starts block sequence entries.
+  bool scanBlockEntry();
+
+  /// Scan an explicit ? indicating a key.
+  bool scanKey();
+
+  /// Scan an explicit : indicating a value.
+  bool scanValue();
+
+  /// Scan a quoted scalar.
+  bool scanFlowScalar(bool IsDoubleQuoted);
+
+  /// Scan an unquoted scalar.
+  bool scanPlainScalar();
+
+  /// Scan an Alias or Anchor starting with * or &.
+  bool scanAliasOrAnchor(bool IsAlias);
+
+  /// Scan a block scalar starting with | or >.
+  bool scanBlockScalar(bool IsLiteral);
+
+  /// Scan a chomping indicator in a block scalar header.
+  char scanBlockChompingIndicator();
+
+  /// Scan an indentation indicator in a block scalar header.
+  unsigned scanBlockIndentationIndicator();
+
+  /// Scan a block scalar header.
+  ///
+  /// Return false if an error occurred.
+  bool scanBlockScalarHeader(char &ChompingIndicator, unsigned &IndentIndicator,
+                             bool &IsDone);
+
+  /// Look for the indentation level of a block scalar.
+  ///
+  /// Return false if an error occurred.
+  bool findBlockScalarIndent(unsigned &BlockIndent, unsigned BlockExitIndent,
+                             unsigned &LineBreaks, bool &IsDone);
+
+  /// Scan the indentation of a text line in a block scalar.
+  ///
+  /// Return false if an error occurred.
+  bool scanBlockScalarIndent(unsigned BlockIndent, unsigned BlockExitIndent,
+                             bool &IsDone);
+
+  /// Scan a tag of the form !stuff.
+  bool scanTag();
+
+  /// Dispatch to the next scanning function based on \a *Cur.
+  bool fetchMoreTokens();
+
+  /// The SourceMgr used for diagnostics and buffer management.
+  SourceMgr &SM;
+
+  /// The original input.
+  MemoryBufferRef InputBuffer;
+
+  /// The current position of the scanner.
+  StringRef::iterator Current;
+
+  /// The end of the input (one past the last character).
+  StringRef::iterator End;
+
+  /// Current YAML indentation level in spaces.
+  int Indent;
+
+  /// Current column number in Unicode code points.
+  unsigned Column;
+
+  /// Current line number.
+  unsigned Line;
+
+  /// How deep we are in flow style containers. 0 Means at block level.
+  unsigned FlowLevel;
+
+  /// Are we at the start of the stream?
+  bool IsStartOfStream;
+
+  /// Can the next token be the start of a simple key?
+  bool IsSimpleKeyAllowed;
+
+  /// True if an error has occurred.
+  bool Failed;
+
+  /// Should colors be used when printing out the diagnostic messages?
+  bool ShowColors;
+
+  /// Queue of tokens. This is required to queue up tokens while looking
+  ///        for the end of a simple key. And for cases where a single character
+  ///        can produce multiple tokens (e.g. BlockEnd).
+  TokenQueueT TokenQueue;
+
+  /// Indentation levels.
+  SmallVector<int, 4> Indents;
+
+  /// Potential simple keys.
+  SmallVector<SimpleKey, 4> SimpleKeys;
+
+  std::error_code *EC;
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+/// encodeUTF8 - Encode \a UnicodeScalarValue in UTF-8 and append it to result.
+static void encodeUTF8( uint32_t UnicodeScalarValue
+                      , SmallVectorImpl<char> &Result) {
+  if (UnicodeScalarValue <= 0x7F) {
+    Result.push_back(UnicodeScalarValue & 0x7F);
+  } else if (UnicodeScalarValue <= 0x7FF) {
+    uint8_t FirstByte = 0xC0 | ((UnicodeScalarValue & 0x7C0) >> 6);
+    uint8_t SecondByte = 0x80 | (UnicodeScalarValue & 0x3F);
+    Result.push_back(FirstByte);
+    Result.push_back(SecondByte);
+  } else if (UnicodeScalarValue <= 0xFFFF) {
+    uint8_t FirstByte = 0xE0 | ((UnicodeScalarValue & 0xF000) >> 12);
+    uint8_t SecondByte = 0x80 | ((UnicodeScalarValue & 0xFC0) >> 6);
+    uint8_t ThirdByte = 0x80 | (UnicodeScalarValue & 0x3F);
+    Result.push_back(FirstByte);
+    Result.push_back(SecondByte);
+    Result.push_back(ThirdByte);
+  } else if (UnicodeScalarValue <= 0x10FFFF) {
+    uint8_t FirstByte = 0xF0 | ((UnicodeScalarValue & 0x1F0000) >> 18);
+    uint8_t SecondByte = 0x80 | ((UnicodeScalarValue & 0x3F000) >> 12);
+    uint8_t ThirdByte = 0x80 | ((UnicodeScalarValue & 0xFC0) >> 6);
+    uint8_t FourthByte = 0x80 | (UnicodeScalarValue & 0x3F);
+    Result.push_back(FirstByte);
+    Result.push_back(SecondByte);
+    Result.push_back(ThirdByte);
+    Result.push_back(FourthByte);
+  }
+}
+
+bool yaml::dumpTokens(StringRef Input, raw_ostream &OS) {
+  SourceMgr SM;
+  Scanner scanner(Input, SM);
+  while (true) {
+    Token T = scanner.getNext();
+    switch (T.Kind) {
+    case Token::TK_StreamStart:
+      OS << "Stream-Start: ";
+      break;
+    case Token::TK_StreamEnd:
+      OS << "Stream-End: ";
+      break;
+    case Token::TK_VersionDirective:
+      OS << "Version-Directive: ";
+      break;
+    case Token::TK_TagDirective:
+      OS << "Tag-Directive: ";
+      break;
+    case Token::TK_DocumentStart:
+      OS << "Document-Start: ";
+      break;
+    case Token::TK_DocumentEnd:
+      OS << "Document-End: ";
+      break;
+    case Token::TK_BlockEntry:
+      OS << "Block-Entry: ";
+      break;
+    case Token::TK_BlockEnd:
+      OS << "Block-End: ";
+      break;
+    case Token::TK_BlockSequenceStart:
+      OS << "Block-Sequence-Start: ";
+      break;
+    case Token::TK_BlockMappingStart:
+      OS << "Block-Mapping-Start: ";
+      break;
+    case Token::TK_FlowEntry:
+      OS << "Flow-Entry: ";
+      break;
+    case Token::TK_FlowSequenceStart:
+      OS << "Flow-Sequence-Start: ";
+      break;
+    case Token::TK_FlowSequenceEnd:
+      OS << "Flow-Sequence-End: ";
+      break;
+    case Token::TK_FlowMappingStart:
+      OS << "Flow-Mapping-Start: ";
+      break;
+    case Token::TK_FlowMappingEnd:
+      OS << "Flow-Mapping-End: ";
+      break;
+    case Token::TK_Key:
+      OS << "Key: ";
+      break;
+    case Token::TK_Value:
+      OS << "Value: ";
+      break;
+    case Token::TK_Scalar:
+      OS << "Scalar: ";
+      break;
+    case Token::TK_BlockScalar:
+      OS << "Block Scalar: ";
+      break;
+    case Token::TK_Alias:
+      OS << "Alias: ";
+      break;
+    case Token::TK_Anchor:
+      OS << "Anchor: ";
+      break;
+    case Token::TK_Tag:
+      OS << "Tag: ";
+      break;
+    case Token::TK_Error:
+      break;
+    }
+    OS << T.Range << "\n";
+    if (T.Kind == Token::TK_StreamEnd)
+      break;
+    else if (T.Kind == Token::TK_Error)
+      return false;
+  }
+  return true;
+}
+
+bool yaml::scanTokens(StringRef Input) {
+  SourceMgr SM;
+  Scanner scanner(Input, SM);
+  while (true) {
+    Token T = scanner.getNext();
+    if (T.Kind == Token::TK_StreamEnd)
+      break;
+    else if (T.Kind == Token::TK_Error)
+      return false;
+  }
+  return true;
+}
+
+std::string yaml::escape(StringRef Input, bool EscapePrintable) {
+  llvm_unreachable("BYN yaml::escape");
+}
+
+Scanner::Scanner(StringRef Input, SourceMgr &sm, bool ShowColors,
+                 std::error_code *EC)
+    : SM(sm), ShowColors(ShowColors), EC(EC) {
+  init(MemoryBufferRef(Input, "YAML"));
+}
+
+Scanner::Scanner(MemoryBufferRef Buffer, SourceMgr &SM_, bool ShowColors,
+                 std::error_code *EC)
+    : SM(SM_), ShowColors(ShowColors), EC(EC) {
+  init(Buffer);
+}
+
+void Scanner::init(MemoryBufferRef Buffer) {
+  InputBuffer = Buffer;
+  Current = InputBuffer.getBufferStart();
+  End = InputBuffer.getBufferEnd();
+  Indent = -1;
+  Column = 0;
+  Line = 0;
+  FlowLevel = 0;
+  IsStartOfStream = true;
+  IsSimpleKeyAllowed = true;
+  Failed = false;
+  std::unique_ptr<MemoryBuffer> InputBufferOwner =
+      MemoryBuffer::getMemBuffer(Buffer);
+  SM.AddNewSourceBuffer(std::move(InputBufferOwner), SMLoc());
+}
+
+Token &Scanner::peekNext() {
+  // If the current token is a possible simple key, keep parsing until we
+  // can confirm.
+  bool NeedMore = false;
+  while (true) {
+    if (TokenQueue.empty() || NeedMore) {
+      if (!fetchMoreTokens()) {
+        TokenQueue.clear();
+        SimpleKeys.clear();
+        TokenQueue.push_back(Token());
+        return TokenQueue.front();
+      }
+    }
+    assert(!TokenQueue.empty() &&
+            "fetchMoreTokens lied about getting tokens!");
+
+    removeStaleSimpleKeyCandidates();
+    SimpleKey SK;
+    SK.Tok = TokenQueue.begin();
+    if (!is_contained(SimpleKeys, SK))
+      break;
+    else
+      NeedMore = true;
+  }
+  return TokenQueue.front();
+}
+
+Token Scanner::getNext() {
+  Token Ret = peekNext();
+  // TokenQueue can be empty if there was an error getting the next token.
+  if (!TokenQueue.empty())
+    TokenQueue.pop_front();
+
+  // There cannot be any referenced Token's if the TokenQueue is empty. So do a
+  // quick deallocation of them all.
+  if (TokenQueue.empty())
+    TokenQueue.resetAlloc();
+
+  return Ret;
+}
+
+StringRef::iterator Scanner::skip_nb_char(StringRef::iterator Position) {
+  if (Position == End)
+    return Position;
+  // Check 7 bit c-printable - b-char.
+  if (   *Position == 0x09
+      || (*Position >= 0x20 && *Position <= 0x7E))
+    return Position + 1;
+
+  // Check for valid UTF-8.
+  if (uint8_t(*Position) & 0x80) {
+    UTF8Decoded u8d = decodeUTF8(Position);
+    if (   u8d.second != 0
+        && u8d.first != 0xFEFF
+        && ( u8d.first == 0x85
+          || ( u8d.first >= 0xA0
+            && u8d.first <= 0xD7FF)
+          || ( u8d.first >= 0xE000
+            && u8d.first <= 0xFFFD)
+          || ( u8d.first >= 0x10000
+            && u8d.first <= 0x10FFFF)))
+      return Position + u8d.second;
+  }
+  return Position;
+}
+
+StringRef::iterator Scanner::skip_b_break(StringRef::iterator Position) {
+  if (Position == End)
+    return Position;
+  if (*Position == 0x0D) {
+    if (Position + 1 != End && *(Position + 1) == 0x0A)
+      return Position + 2;
+    return Position + 1;
+  }
+
+  if (*Position == 0x0A)
+    return Position + 1;
+  return Position;
+}
+
+StringRef::iterator Scanner::skip_s_space(StringRef::iterator Position) {
+  if (Position == End)
+    return Position;
+  if (*Position == ' ')
+    return Position + 1;
+  return Position;
+}
+
+StringRef::iterator Scanner::skip_s_white(StringRef::iterator Position) {
+  if (Position == End)
+    return Position;
+  if (*Position == ' ' || *Position == '\t')
+    return Position + 1;
+  return Position;
+}
+
+StringRef::iterator Scanner::skip_ns_char(StringRef::iterator Position) {
+  if (Position == End)
+    return Position;
+  if (*Position == ' ' || *Position == '\t')
+    return Position;
+  return skip_nb_char(Position);
+}
+
+StringRef::iterator Scanner::skip_while( SkipWhileFunc Func
+                                       , StringRef::iterator Position) {
+  while (true) {
+    StringRef::iterator i = (this->*Func)(Position);
+    if (i == Position)
+      break;
+    Position = i;
+  }
+  return Position;
+}
+
+void Scanner::advanceWhile(SkipWhileFunc Func) {
+  auto Final = skip_while(Func, Current);
+  Column += Final - Current;
+  Current = Final;
+}
+
+static bool is_ns_hex_digit(const char C) {
+  return    (C >= '0' && C <= '9')
+         || (C >= 'a' && C <= 'z')
+         || (C >= 'A' && C <= 'Z');
+}
+
+static bool is_ns_word_char(const char C) {
+  return    C == '-'
+         || (C >= 'a' && C <= 'z')
+         || (C >= 'A' && C <= 'Z');
+}
+
+void Scanner::scan_ns_uri_char() {
+  while (true) {
+    if (Current == End)
+      break;
+    if ((   *Current == '%'
+          && Current + 2 < End
+          && is_ns_hex_digit(*(Current + 1))
+          && is_ns_hex_digit(*(Current + 2)))
+        || is_ns_word_char(*Current)
+        || StringRef(Current, 1).find_first_of("#;/?:@&=+$,_.!~*'()[]")
+          != StringRef::npos) {
+      ++Current;
+      ++Column;
+    } else
+      break;
+  }
+}
+
+bool Scanner::consume(uint32_t Expected) {
+  if (Expected >= 0x80) {
+    setError("Cannot consume non-ascii characters");
+    return false;
+  }
+  if (Current == End)
+    return false;
+  if (uint8_t(*Current) >= 0x80) {
+    setError("Cannot consume non-ascii characters");
+    return false;
+  }
+  if (uint8_t(*Current) == Expected) {
+    ++Current;
+    ++Column;
+    return true;
+  }
+  return false;
+}
+
+void Scanner::skip(uint32_t Distance) {
+  Current += Distance;
+  Column += Distance;
+  assert(Current <= End && "Skipped past the end");
+}
+
+bool Scanner::isBlankOrBreak(StringRef::iterator Position) {
+  if (Position == End)
+    return false;
+  return *Position == ' ' || *Position == '\t' || *Position == '\r' ||
+         *Position == '\n';
+}
+
+bool Scanner::consumeLineBreakIfPresent() {
+  auto Next = skip_b_break(Current);
+  if (Next == Current)
+    return false;
+  Column = 0;
+  ++Line;
+  Current = Next;
+  return true;
+}
+
+void Scanner::saveSimpleKeyCandidate( TokenQueueT::iterator Tok
+                                    , unsigned AtColumn
+                                    , bool IsRequired) {
+  if (IsSimpleKeyAllowed) {
+    SimpleKey SK;
+    SK.Tok = Tok;
+    SK.Line = Line;
+    SK.Column = AtColumn;
+    SK.IsRequired = IsRequired;
+    SK.FlowLevel = FlowLevel;
+    SimpleKeys.push_back(SK);
+  }
+}
+
+void Scanner::removeStaleSimpleKeyCandidates() {
+  for (SmallVectorImpl<SimpleKey>::iterator i = SimpleKeys.begin();
+                                            i != SimpleKeys.end();) {
+    if (i->Line != Line || i->Column + 1024 < Column) {
+      if (i->IsRequired)
+        setError( "Could not find expected : for simple key"
+                , i->Tok->Range.begin());
+      i = SimpleKeys.erase(i);
+    } else
+      ++i;
+  }
+}
+
+void Scanner::removeSimpleKeyCandidatesOnFlowLevel(unsigned Level) {
+  if (!SimpleKeys.empty() && (SimpleKeys.end() - 1)->FlowLevel == Level)
+    SimpleKeys.pop_back();
+}
+
+bool Scanner::unrollIndent(int ToColumn) {
+  Token T;
+  // Indentation is ignored in flow.
+  if (FlowLevel != 0)
+    return true;
+
+  while (Indent > ToColumn) {
+    T.Kind = Token::TK_BlockEnd;
+    T.Range = StringRef(Current, 1);
+    TokenQueue.push_back(T);
+    Indent = Indents.pop_back_val();
+  }
+
+  return true;
+}
+
+bool Scanner::rollIndent( int ToColumn
+                        , Token::TokenKind Kind
+                        , TokenQueueT::iterator InsertPoint) {
+  if (FlowLevel)
+    return true;
+  if (Indent < ToColumn) {
+    Indents.push_back(Indent);
+    Indent = ToColumn;
+
+    Token T;
+    T.Kind = Kind;
+    T.Range = StringRef(Current, 0);
+    TokenQueue.insert(InsertPoint, T);
+  }
+  return true;
+}
+
+void Scanner::skipComment() {
+  if (*Current != '#')
+    return;
+  while (true) {
+    // This may skip more than one byte, thus Column is only incremented
+    // for code points.
+    StringRef::iterator I = skip_nb_char(Current);
+    if (I == Current)
+      break;
+    Current = I;
+    ++Column;
+  }
+}
+
+void Scanner::scanToNextToken() {
+  while (true) {
+    while (*Current == ' ' || *Current == '\t') {
+      skip(1);
+    }
+
+    skipComment();
+
+    // Skip EOL.
+    StringRef::iterator i = skip_b_break(Current);
+    if (i == Current)
+      break;
+    Current = i;
+    ++Line;
+    Column = 0;
+    // New lines may start a simple key.
+    if (!FlowLevel)
+      IsSimpleKeyAllowed = true;
+  }
+}
+
+bool Scanner::scanStreamStart() {
+  IsStartOfStream = false;
+
+  EncodingInfo EI = getUnicodeEncoding(currentInput());
+
+  Token T;
+  T.Kind = Token::TK_StreamStart;
+  T.Range = StringRef(Current, EI.second);
+  TokenQueue.push_back(T);
+  Current += EI.second;
+  return true;
+}
+
+bool Scanner::scanStreamEnd() {
+  // Force an ending new line if one isn't present.
+  if (Column != 0) {
+    Column = 0;
+    ++Line;
+  }
+
+  unrollIndent(-1);
+  SimpleKeys.clear();
+  IsSimpleKeyAllowed = false;
+
+  Token T;
+  T.Kind = Token::TK_StreamEnd;
+  T.Range = StringRef(Current, 0);
+  TokenQueue.push_back(T);
+  return true;
+}
+
+bool Scanner::scanDirective() {
+  // Reset the indentation level.
+  unrollIndent(-1);
+  SimpleKeys.clear();
+  IsSimpleKeyAllowed = false;
+
+  StringRef::iterator Start = Current;
+  consume('%');
+  StringRef::iterator NameStart = Current;
+  Current = skip_while(&Scanner::skip_ns_char, Current);
+  StringRef Name(NameStart, Current - NameStart);
+  Current = skip_while(&Scanner::skip_s_white, Current);
+
+  Token T;
+  if (Name == "YAML") {
+    Current = skip_while(&Scanner::skip_ns_char, Current);
+    T.Kind = Token::TK_VersionDirective;
+    T.Range = StringRef(Start, Current - Start);
+    TokenQueue.push_back(T);
+    return true;
+  } else if(Name == "TAG") {
+    Current = skip_while(&Scanner::skip_ns_char, Current);
+    Current = skip_while(&Scanner::skip_s_white, Current);
+    Current = skip_while(&Scanner::skip_ns_char, Current);
+    T.Kind = Token::TK_TagDirective;
+    T.Range = StringRef(Start, Current - Start);
+    TokenQueue.push_back(T);
+    return true;
+  }
+  return false;
+}
+
+bool Scanner::scanDocumentIndicator(bool IsStart) {
+  unrollIndent(-1);
+  SimpleKeys.clear();
+  IsSimpleKeyAllowed = false;
+
+  Token T;
+  T.Kind = IsStart ? Token::TK_DocumentStart : Token::TK_DocumentEnd;
+  T.Range = StringRef(Current, 3);
+  skip(3);
+  TokenQueue.push_back(T);
+  return true;
+}
+
+bool Scanner::scanFlowCollectionStart(bool IsSequence) {
+  Token T;
+  T.Kind = IsSequence ? Token::TK_FlowSequenceStart
+                      : Token::TK_FlowMappingStart;
+  T.Range = StringRef(Current, 1);
+  skip(1);
+  TokenQueue.push_back(T);
+
+  // [ and { may begin a simple key.
+  saveSimpleKeyCandidate(--TokenQueue.end(), Column - 1, false);
+
+  // And may also be followed by a simple key.
+  IsSimpleKeyAllowed = true;
+  ++FlowLevel;
+  return true;
+}
+
+bool Scanner::scanFlowCollectionEnd(bool IsSequence) {
+  removeSimpleKeyCandidatesOnFlowLevel(FlowLevel);
+  IsSimpleKeyAllowed = false;
+  Token T;
+  T.Kind = IsSequence ? Token::TK_FlowSequenceEnd
+                      : Token::TK_FlowMappingEnd;
+  T.Range = StringRef(Current, 1);
+  skip(1);
+  TokenQueue.push_back(T);
+  if (FlowLevel)
+    --FlowLevel;
+  return true;
+}
+
+bool Scanner::scanFlowEntry() {
+  removeSimpleKeyCandidatesOnFlowLevel(FlowLevel);
+  IsSimpleKeyAllowed = true;
+  Token T;
+  T.Kind = Token::TK_FlowEntry;
+  T.Range = StringRef(Current, 1);
+  skip(1);
+  TokenQueue.push_back(T);
+  return true;
+}
+
+bool Scanner::scanBlockEntry() {
+  rollIndent(Column, Token::TK_BlockSequenceStart, TokenQueue.end());
+  removeSimpleKeyCandidatesOnFlowLevel(FlowLevel);
+  IsSimpleKeyAllowed = true;
+  Token T;
+  T.Kind = Token::TK_BlockEntry;
+  T.Range = StringRef(Current, 1);
+  skip(1);
+  TokenQueue.push_back(T);
+  return true;
+}
+
+bool Scanner::scanKey() {
+  if (!FlowLevel)
+    rollIndent(Column, Token::TK_BlockMappingStart, TokenQueue.end());
+
+  removeSimpleKeyCandidatesOnFlowLevel(FlowLevel);
+  IsSimpleKeyAllowed = !FlowLevel;
+
+  Token T;
+  T.Kind = Token::TK_Key;
+  T.Range = StringRef(Current, 1);
+  skip(1);
+  TokenQueue.push_back(T);
+  return true;
+}
+
+bool Scanner::scanValue() {
+  // If the previous token could have been a simple key, insert the key token
+  // into the token queue.
+  if (!SimpleKeys.empty()) {
+    SimpleKey SK = SimpleKeys.pop_back_val();
+    Token T;
+    T.Kind = Token::TK_Key;
+    T.Range = SK.Tok->Range;
+    TokenQueueT::iterator i, e;
+    for (i = TokenQueue.begin(), e = TokenQueue.end(); i != e; ++i) {
+      if (i == SK.Tok)
+        break;
+    }
+    if (i == e) {
+      Failed = true;
+      return false;
+    }
+    i = TokenQueue.insert(i, T);
+
+    // We may also need to add a Block-Mapping-Start token.
+    rollIndent(SK.Column, Token::TK_BlockMappingStart, i);
+
+    IsSimpleKeyAllowed = false;
+  } else {
+    if (!FlowLevel)
+      rollIndent(Column, Token::TK_BlockMappingStart, TokenQueue.end());
+    IsSimpleKeyAllowed = !FlowLevel;
+  }
+
+  Token T;
+  T.Kind = Token::TK_Value;
+  T.Range = StringRef(Current, 1);
+  skip(1);
+  TokenQueue.push_back(T);
+  return true;
+}
+
+// Forbidding inlining improves performance by roughly 20%.
+// FIXME: Remove once llvm optimizes this to the faster version without hints.
+LLVM_ATTRIBUTE_NOINLINE static bool
+wasEscaped(StringRef::iterator First, StringRef::iterator Position);
+
+// Returns whether a character at 'Position' was escaped with a leading '\'.
+// 'First' specifies the position of the first character in the string.
+static bool wasEscaped(StringRef::iterator First,
+                       StringRef::iterator Position) {
+  assert(Position - 1 >= First);
+  StringRef::iterator I = Position - 1;
+  // We calculate the number of consecutive '\'s before the current position
+  // by iterating backwards through our string.
+  while (I >= First && *I == '\\') --I;
+  // (Position - 1 - I) now contains the number of '\'s before the current
+  // position. If it is odd, the character at 'Position' was escaped.
+  return (Position - 1 - I) % 2 == 1;
+}
+
+bool Scanner::scanFlowScalar(bool IsDoubleQuoted) {
+  StringRef::iterator Start = Current;
+  unsigned ColStart = Column;
+  if (IsDoubleQuoted) {
+    do {
+      ++Current;
+      while (Current != End && *Current != '"')
+        ++Current;
+      // Repeat until the previous character was not a '\' or was an escaped
+      // backslash.
+    } while (   Current != End
+             && *(Current - 1) == '\\'
+             && wasEscaped(Start + 1, Current));
+  } else {
+    skip(1);
+    while (true) {
+      // Skip a ' followed by another '.
+      if (Current + 1 < End && *Current == '\'' && *(Current + 1) == '\'') {
+        skip(2);
+        continue;
+      } else if (*Current == '\'')
+        break;
+      StringRef::iterator i = skip_nb_char(Current);
+      if (i == Current) {
+        i = skip_b_break(Current);
+        if (i == Current)
+          break;
+        Current = i;
+        Column = 0;
+        ++Line;
+      } else {
+        if (i == End)
+          break;
+        Current = i;
+        ++Column;
+      }
+    }
+  }
+
+  if (Current == End) {
+    setError("Expected quote at end of scalar", Current);
+    return false;
+  }
+
+  skip(1); // Skip ending quote.
+  Token T;
+  T.Kind = Token::TK_Scalar;
+  T.Range = StringRef(Start, Current - Start);
+  TokenQueue.push_back(T);
+
+  saveSimpleKeyCandidate(--TokenQueue.end(), ColStart, false);
+
+  IsSimpleKeyAllowed = false;
+
+  return true;
+}
+
+bool Scanner::scanPlainScalar() {
+  StringRef::iterator Start = Current;
+  unsigned ColStart = Column;
+  unsigned LeadingBlanks = 0;
+  assert(Indent >= -1 && "Indent must be >= -1 !");
+  unsigned indent = static_cast<unsigned>(Indent + 1);
+  while (true) {
+    if (*Current == '#')
+      break;
+
+    while (!isBlankOrBreak(Current)) {
+      if (  FlowLevel && *Current == ':'
+          && !(isBlankOrBreak(Current + 1) || *(Current + 1) == ',')) {
+        setError("Found unexpected ':' while scanning a plain scalar", Current);
+        return false;
+      }
+
+      // Check for the end of the plain scalar.
+      if (  (*Current == ':' && isBlankOrBreak(Current + 1))
+          || (  FlowLevel
+          && (StringRef(Current, 1).find_first_of(",:?[]{}")
+              != StringRef::npos)))
+        break;
+
+      StringRef::iterator i = skip_nb_char(Current);
+      if (i == Current)
+        break;
+      Current = i;
+      ++Column;
+    }
+
+    // Are we at the end?
+    if (!isBlankOrBreak(Current))
+      break;
+
+    // Eat blanks.
+    StringRef::iterator Tmp = Current;
+    while (isBlankOrBreak(Tmp)) {
+      StringRef::iterator i = skip_s_white(Tmp);
+      if (i != Tmp) {
+        if (LeadingBlanks && (Column < indent) && *Tmp == '\t') {
+          setError("Found invalid tab character in indentation", Tmp);
+          return false;
+        }
+        Tmp = i;
+        ++Column;
+      } else {
+        i = skip_b_break(Tmp);
+        if (!LeadingBlanks)
+          LeadingBlanks = 1;
+        Tmp = i;
+        Column = 0;
+        ++Line;
+      }
+    }
+
+    if (!FlowLevel && Column < indent)
+      break;
+
+    Current = Tmp;
+  }
+  if (Start == Current) {
+    setError("Got empty plain scalar", Start);
+    return false;
+  }
+  Token T;
+  T.Kind = Token::TK_Scalar;
+  T.Range = StringRef(Start, Current - Start);
+  TokenQueue.push_back(T);
+
+  // Plain scalars can be simple keys.
+  saveSimpleKeyCandidate(--TokenQueue.end(), ColStart, false);
+
+  IsSimpleKeyAllowed = false;
+
+  return true;
+}
+
+bool Scanner::scanAliasOrAnchor(bool IsAlias) {
+  StringRef::iterator Start = Current;
+  unsigned ColStart = Column;
+  skip(1);
+  while(true) {
+    if (   *Current == '[' || *Current == ']'
+        || *Current == '{' || *Current == '}'
+        || *Current == ','
+        || *Current == ':')
+      break;
+    StringRef::iterator i = skip_ns_char(Current);
+    if (i == Current)
+      break;
+    Current = i;
+    ++Column;
+  }
+
+  if (Start == Current) {
+    setError("Got empty alias or anchor", Start);
+    return false;
+  }
+
+  Token T;
+  T.Kind = IsAlias ? Token::TK_Alias : Token::TK_Anchor;
+  T.Range = StringRef(Start, Current - Start);
+  TokenQueue.push_back(T);
+
+  // Alias and anchors can be simple keys.
+  saveSimpleKeyCandidate(--TokenQueue.end(), ColStart, false);
+
+  IsSimpleKeyAllowed = false;
+
+  return true;
+}
+
+char Scanner::scanBlockChompingIndicator() {
+  char Indicator = ' ';
+  if (Current != End && (*Current == '+' || *Current == '-')) {
+    Indicator = *Current;
+    skip(1);
+  }
+  return Indicator;
+}
+
+/// Get the number of line breaks after chomping.
+///
+/// Return the number of trailing line breaks to emit, depending on
+/// \p ChompingIndicator.
+static unsigned getChompedLineBreaks(char ChompingIndicator,
+                                     unsigned LineBreaks, StringRef Str) {
+  if (ChompingIndicator == '-') // Strip all line breaks.
+    return 0;
+  if (ChompingIndicator == '+') // Keep all line breaks.
+    return LineBreaks;
+  // Clip trailing lines.
+  return Str.empty() ? 0 : 1;
+}
+
+unsigned Scanner::scanBlockIndentationIndicator() {
+  unsigned Indent = 0;
+  if (Current != End && (*Current >= '1' && *Current <= '9')) {
+    Indent = unsigned(*Current - '0');
+    skip(1);
+  }
+  return Indent;
+}
+
+bool Scanner::scanBlockScalarHeader(char &ChompingIndicator,
+                                    unsigned &IndentIndicator, bool &IsDone) {
+  auto Start = Current;
+
+  ChompingIndicator = scanBlockChompingIndicator();
+  IndentIndicator = scanBlockIndentationIndicator();
+  // Check for the chomping indicator once again.
+  if (ChompingIndicator == ' ')
+    ChompingIndicator = scanBlockChompingIndicator();
+  Current = skip_while(&Scanner::skip_s_white, Current);
+  skipComment();
+
+  if (Current == End) { // EOF, we have an empty scalar.
+    Token T;
+    T.Kind = Token::TK_BlockScalar;
+    T.Range = StringRef(Start, Current - Start);
+    TokenQueue.push_back(T);
+    IsDone = true;
+    return true;
+  }
+
+  if (!consumeLineBreakIfPresent()) {
+    setError("Expected a line break after block scalar header", Current);
+    return false;
+  }
+  return true;
+}
+
+bool Scanner::findBlockScalarIndent(unsigned &BlockIndent,
+                                    unsigned BlockExitIndent,
+                                    unsigned &LineBreaks, bool &IsDone) {
+  unsigned MaxAllSpaceLineCharacters = 0;
+  StringRef::iterator LongestAllSpaceLine;
+
+  while (true) {
+    advanceWhile(&Scanner::skip_s_space);
+    if (skip_nb_char(Current) != Current) {
+      // This line isn't empty, so try and find the indentation.
+      if (Column <= BlockExitIndent) { // End of the block literal.
+        IsDone = true;
+        return true;
+      }
+      // We found the block's indentation.
+      BlockIndent = Column;
+      if (MaxAllSpaceLineCharacters > BlockIndent) {
+        setError(
+            "Leading all-spaces line must be smaller than the block indent",
+            LongestAllSpaceLine);
+        return false;
+      }
+      return true;
+    }
+    if (skip_b_break(Current) != Current &&
+        Column > MaxAllSpaceLineCharacters) {
+      // Record the longest all-space line in case it's longer than the
+      // discovered block indent.
+      MaxAllSpaceLineCharacters = Column;
+      LongestAllSpaceLine = Current;
+    }
+
+    // Check for EOF.
+    if (Current == End) {
+      IsDone = true;
+      return true;
+    }
+
+    if (!consumeLineBreakIfPresent()) {
+      IsDone = true;
+      return true;
+    }
+    ++LineBreaks;
+  }
+  return true;
+}
+
+bool Scanner::scanBlockScalarIndent(unsigned BlockIndent,
+                                    unsigned BlockExitIndent, bool &IsDone) {
+  // Skip the indentation.
+  while (Column < BlockIndent) {
+    auto I = skip_s_space(Current);
+    if (I == Current)
+      break;
+    Current = I;
+    ++Column;
+  }
+
+  if (skip_nb_char(Current) == Current)
+    return true;
+
+  if (Column <= BlockExitIndent) { // End of the block literal.
+    IsDone = true;
+    return true;
+  }
+
+  if (Column < BlockIndent) {
+    if (Current != End && *Current == '#') { // Trailing comment.
+      IsDone = true;
+      return true;
+    }
+    setError("A text line is less indented than the block scalar", Current);
+    return false;
+  }
+  return true; // A normal text line.
+}
+
+bool Scanner::scanBlockScalar(bool IsLiteral) {
+  // Eat '|' or '>'
+  assert(*Current == '|' || *Current == '>');
+  skip(1);
+
+  char ChompingIndicator;
+  unsigned BlockIndent;
+  bool IsDone = false;
+  if (!scanBlockScalarHeader(ChompingIndicator, BlockIndent, IsDone))
+    return false;
+  if (IsDone)
+    return true;
+
+  auto Start = Current;
+  unsigned BlockExitIndent = Indent < 0 ? 0 : (unsigned)Indent;
+  unsigned LineBreaks = 0;
+  if (BlockIndent == 0) {
+    if (!findBlockScalarIndent(BlockIndent, BlockExitIndent, LineBreaks,
+                               IsDone))
+      return false;
+  }
+
+  // Scan the block's scalars body.
+  SmallString<256> Str;
+  while (!IsDone) {
+    if (!scanBlockScalarIndent(BlockIndent, BlockExitIndent, IsDone))
+      return false;
+    if (IsDone)
+      break;
+
+    // Parse the current line.
+    auto LineStart = Current;
+    advanceWhile(&Scanner::skip_nb_char);
+    if (LineStart != Current) {
+      Str.append(LineBreaks, '\n');
+      Str.append(StringRef(LineStart, Current - LineStart));
+      LineBreaks = 0;
+    }
+
+    // Check for EOF.
+    if (Current == End)
+      break;
+
+    if (!consumeLineBreakIfPresent())
+      break;
+    ++LineBreaks;
+  }
+
+  if (Current == End && !LineBreaks)
+    // Ensure that there is at least one line break before the end of file.
+    LineBreaks = 1;
+  Str.append(getChompedLineBreaks(ChompingIndicator, LineBreaks, Str), '\n');
+
+  // New lines may start a simple key.
+  if (!FlowLevel)
+    IsSimpleKeyAllowed = true;
+
+  Token T;
+  T.Kind = Token::TK_BlockScalar;
+  T.Range = StringRef(Start, Current - Start);
+  T.Value = Str.str().str();
+  TokenQueue.push_back(T);
+  return true;
+}
+
+bool Scanner::scanTag() {
+  StringRef::iterator Start = Current;
+  unsigned ColStart = Column;
+  skip(1); // Eat !.
+  if (Current == End || isBlankOrBreak(Current)); // An empty tag.
+  else if (*Current == '<') {
+    skip(1);
+    scan_ns_uri_char();
+    if (!consume('>'))
+      return false;
+  } else {
+    // FIXME: Actually parse the c-ns-shorthand-tag rule.
+    Current = skip_while(&Scanner::skip_ns_char, Current);
+  }
+
+  Token T;
+  T.Kind = Token::TK_Tag;
+  T.Range = StringRef(Start, Current - Start);
+  TokenQueue.push_back(T);
+
+  // Tags can be simple keys.
+  saveSimpleKeyCandidate(--TokenQueue.end(), ColStart, false);
+
+  IsSimpleKeyAllowed = false;
+
+  return true;
+}
+
+bool Scanner::fetchMoreTokens() {
+  if (IsStartOfStream)
+    return scanStreamStart();
+
+  scanToNextToken();
+
+  if (Current == End)
+    return scanStreamEnd();
+
+  removeStaleSimpleKeyCandidates();
+
+  unrollIndent(Column);
+
+  if (Column == 0 && *Current == '%')
+    return scanDirective();
+
+  if (Column == 0 && Current + 4 <= End
+      && *Current == '-'
+      && *(Current + 1) == '-'
+      && *(Current + 2) == '-'
+      && (Current + 3 == End || isBlankOrBreak(Current + 3)))
+    return scanDocumentIndicator(true);
+
+  if (Column == 0 && Current + 4 <= End
+      && *Current == '.'
+      && *(Current + 1) == '.'
+      && *(Current + 2) == '.'
+      && (Current + 3 == End || isBlankOrBreak(Current + 3)))
+    return scanDocumentIndicator(false);
+
+  if (*Current == '[')
+    return scanFlowCollectionStart(true);
+
+  if (*Current == '{')
+    return scanFlowCollectionStart(false);
+
+  if (*Current == ']')
+    return scanFlowCollectionEnd(true);
+
+  if (*Current == '}')
+    return scanFlowCollectionEnd(false);
+
+  if (*Current == ',')
+    return scanFlowEntry();
+
+  if (*Current == '-' && isBlankOrBreak(Current + 1))
+    return scanBlockEntry();
+
+  if (*Current == '?' && (FlowLevel || isBlankOrBreak(Current + 1)))
+    return scanKey();
+
+  if (*Current == ':' && (FlowLevel || isBlankOrBreak(Current + 1)))
+    return scanValue();
+
+  if (*Current == '*')
+    return scanAliasOrAnchor(true);
+
+  if (*Current == '&')
+    return scanAliasOrAnchor(false);
+
+  if (*Current == '!')
+    return scanTag();
+
+  if (*Current == '|' && !FlowLevel)
+    return scanBlockScalar(true);
+
+  if (*Current == '>' && !FlowLevel)
+    return scanBlockScalar(false);
+
+  if (*Current == '\'')
+    return scanFlowScalar(false);
+
+  if (*Current == '"')
+    return scanFlowScalar(true);
+
+  // Get a plain scalar.
+  StringRef FirstChar(Current, 1);
+  if (!(isBlankOrBreak(Current)
+        || FirstChar.find_first_of("-?:,[]{}#&*!|>'\"%@`") != StringRef::npos)
+      || (*Current == '-' && !isBlankOrBreak(Current + 1))
+      || (!FlowLevel && (*Current == '?' || *Current == ':')
+          && isBlankOrBreak(Current + 1))
+      || (!FlowLevel && *Current == ':'
+                      && Current + 2 < End
+                      && *(Current + 1) == ':'
+                      && !isBlankOrBreak(Current + 2)))
+    return scanPlainScalar();
+
+  setError("Unrecognized character while tokenizing.");
+  return false;
+}
+
+Stream::Stream(StringRef Input, SourceMgr &SM, bool ShowColors,
+               std::error_code *EC)
+    : scanner(new Scanner(Input, SM, ShowColors, EC)), CurrentDoc() {}
+
+Stream::Stream(MemoryBufferRef InputBuffer, SourceMgr &SM, bool ShowColors,
+               std::error_code *EC)
+    : scanner(new Scanner(InputBuffer, SM, ShowColors, EC)), CurrentDoc() {}
+
+Stream::~Stream() = default;
+
+bool Stream::failed() { return scanner->failed(); }
+
+void Stream::printError(Node *N, const Twine &Msg) {
+  SMRange Range = N ? N->getSourceRange() : SMRange();
+  scanner->printError( Range.Start
+                     , SourceMgr::DK_Error
+                     , Msg
+                     , Range);
+}
+
+document_iterator Stream::begin() {
+  if (CurrentDoc)
+    report_fatal_error("Can only iterate over the stream once");
+
+  // Skip Stream-Start.
+  scanner->getNext();
+
+  CurrentDoc.reset(new Document(*this));
+  return document_iterator(CurrentDoc);
+}
+
+document_iterator Stream::end() {
+  return document_iterator();
+}
+
+void Stream::skip() {
+  for (document_iterator i = begin(), e = end(); i != e; ++i)
+    i->skip();
+}
+
+Node::Node(unsigned int Type, std::unique_ptr<Document> &D, StringRef A,
+           StringRef T)
+    : Doc(D), TypeID(Type), Anchor(A), Tag(T) {
+  SMLoc Start = SMLoc::getFromPointer(peekNext().Range.begin());
+  SourceRange = SMRange(Start, Start);
+}
+
+std::string Node::getVerbatimTag() const {
+  StringRef Raw = getRawTag();
+  if (!Raw.empty() && Raw != "!") {
+    std::string Ret;
+    if (Raw.find_last_of('!') == 0) {
+      Ret = Doc->getTagMap().find("!")->second;
+      Ret += Raw.substr(1);
+      return Ret;
+    } else if (Raw.startswith("!!")) {
+      Ret = Doc->getTagMap().find("!!")->second;
+      Ret += Raw.substr(2);
+      return Ret;
+    } else {
+      StringRef TagHandle = Raw.substr(0, Raw.find_last_of('!') + 1);
+      std::map<StringRef, StringRef>::const_iterator It =
+          Doc->getTagMap().find(TagHandle);
+      if (It != Doc->getTagMap().end())
+        Ret = It->second;
+      else {
+        Token T;
+        T.Kind = Token::TK_Tag;
+        T.Range = TagHandle;
+        setError(Twine("Unknown tag handle ") + TagHandle, T);
+      }
+      Ret += Raw.substr(Raw.find_last_of('!') + 1);
+      return Ret;
+    }
+  }
+
+  switch (getType()) {
+  case NK_Null:
+    return "tag:yaml.org,2002:null";
+  case NK_Scalar:
+  case NK_BlockScalar:
+    // TODO: Tag resolution.
+    return "tag:yaml.org,2002:str";
+  case NK_Mapping:
+    return "tag:yaml.org,2002:map";
+  case NK_Sequence:
+    return "tag:yaml.org,2002:seq";
+  }
+
+  return "";
+}
+
+Token &Node::peekNext() {
+  return Doc->peekNext();
+}
+
+Token Node::getNext() {
+  return Doc->getNext();
+}
+
+Node *Node::parseBlockNode() {
+  return Doc->parseBlockNode();
+}
+
+BumpPtrAllocator &Node::getAllocator() {
+  return Doc->NodeAllocator;
+}
+
+void Node::setError(const Twine &Msg, Token &Tok) const {
+  Doc->setError(Msg, Tok);
+}
+
+bool Node::failed() const {
+  return Doc->failed();
+}
+
+StringRef ScalarNode::getValue(SmallVectorImpl<char> &Storage) const {
+  // TODO: Handle newlines properly. We need to remove leading whitespace.
+  if (Value[0] == '"') { // Double quoted.
+    // Pull off the leading and trailing "s.
+    StringRef UnquotedValue = Value.substr(1, Value.size() - 2);
+    // Search for characters that would require unescaping the value.
+    StringRef::size_type i = UnquotedValue.find_first_of("\\\r\n");
+    if (i != StringRef::npos)
+      return unescapeDoubleQuoted(UnquotedValue, i, Storage);
+    return UnquotedValue;
+  } else if (Value[0] == '\'') { // Single quoted.
+    // Pull off the leading and trailing 's.
+    StringRef UnquotedValue = Value.substr(1, Value.size() - 2);
+    StringRef::size_type i = UnquotedValue.find('\'');
+    if (i != StringRef::npos) {
+      // We're going to need Storage.
+      Storage.clear();
+      Storage.reserve(UnquotedValue.size());
+      for (; i != StringRef::npos; i = UnquotedValue.find('\'')) {
+        StringRef Valid(UnquotedValue.begin(), i);
+        Storage.insert(Storage.end(), Valid.begin(), Valid.end());
+        Storage.push_back('\'');
+        UnquotedValue = UnquotedValue.substr(i + 2);
+      }
+      Storage.insert(Storage.end(), UnquotedValue.begin(), UnquotedValue.end());
+      return StringRef(Storage.begin(), Storage.size());
+    }
+    return UnquotedValue;
+  }
+  // Plain or block.
+  return Value.rtrim(' ');
+}
+
+StringRef ScalarNode::unescapeDoubleQuoted( StringRef UnquotedValue
+                                          , StringRef::size_type i
+                                          , SmallVectorImpl<char> &Storage)
+                                          const {
+  // Use Storage to build proper value.
+  Storage.clear();
+  Storage.reserve(UnquotedValue.size());
+  for (; i != StringRef::npos; i = UnquotedValue.find_first_of("\\\r\n")) {
+    // Insert all previous chars into Storage.
+    StringRef Valid(UnquotedValue.begin(), i);
+    Storage.insert(Storage.end(), Valid.begin(), Valid.end());
+    // Chop off inserted chars.
+    UnquotedValue = UnquotedValue.substr(i);
+
+    assert(!UnquotedValue.empty() && "Can't be empty!");
+
+    // Parse escape or line break.
+    switch (UnquotedValue[0]) {
+    case '\r':
+    case '\n':
+      Storage.push_back('\n');
+      if (   UnquotedValue.size() > 1
+          && (UnquotedValue[1] == '\r' || UnquotedValue[1] == '\n'))
+        UnquotedValue = UnquotedValue.substr(1);
+      UnquotedValue = UnquotedValue.substr(1);
+      break;
+    default:
+      if (UnquotedValue.size() == 1) {
+        Token T;
+        T.Range = StringRef(UnquotedValue.begin(), 1);
+        setError("Unrecognized escape code", T);
+        return "";
+      }
+      UnquotedValue = UnquotedValue.substr(1);
+      switch (UnquotedValue[0]) {
+      default: {
+          Token T;
+          T.Range = StringRef(UnquotedValue.begin(), 1);
+          setError("Unrecognized escape code", T);
+          return "";
+        }
+      case '\r':
+      case '\n':
+        // Remove the new line.
+        if (   UnquotedValue.size() > 1
+            && (UnquotedValue[1] == '\r' || UnquotedValue[1] == '\n'))
+          UnquotedValue = UnquotedValue.substr(1);
+        // If this was just a single byte newline, it will get skipped
+        // below.
+        break;
+      case '0':
+        Storage.push_back(0x00);
+        break;
+      case 'a':
+        Storage.push_back(0x07);
+        break;
+      case 'b':
+        Storage.push_back(0x08);
+        break;
+      case 't':
+      case 0x09:
+        Storage.push_back(0x09);
+        break;
+      case 'n':
+        Storage.push_back(0x0A);
+        break;
+      case 'v':
+        Storage.push_back(0x0B);
+        break;
+      case 'f':
+        Storage.push_back(0x0C);
+        break;
+      case 'r':
+        Storage.push_back(0x0D);
+        break;
+      case 'e':
+        Storage.push_back(0x1B);
+        break;
+      case ' ':
+        Storage.push_back(0x20);
+        break;
+      case '"':
+        Storage.push_back(0x22);
+        break;
+      case '/':
+        Storage.push_back(0x2F);
+        break;
+      case '\\':
+        Storage.push_back(0x5C);
+        break;
+      case 'N':
+        encodeUTF8(0x85, Storage);
+        break;
+      case '_':
+        encodeUTF8(0xA0, Storage);
+        break;
+      case 'L':
+        encodeUTF8(0x2028, Storage);
+        break;
+      case 'P':
+        encodeUTF8(0x2029, Storage);
+        break;
+      case 'x': {
+          if (UnquotedValue.size() < 3)
+            // TODO: Report error.
+            break;
+          unsigned int UnicodeScalarValue;
+          if (UnquotedValue.substr(1, 2).getAsInteger(16, UnicodeScalarValue))
+            // TODO: Report error.
+            UnicodeScalarValue = 0xFFFD;
+          encodeUTF8(UnicodeScalarValue, Storage);
+          UnquotedValue = UnquotedValue.substr(2);
+          break;
+        }
+      case 'u': {
+          if (UnquotedValue.size() < 5)
+            // TODO: Report error.
+            break;
+          unsigned int UnicodeScalarValue;
+          if (UnquotedValue.substr(1, 4).getAsInteger(16, UnicodeScalarValue))
+            // TODO: Report error.
+            UnicodeScalarValue = 0xFFFD;
+          encodeUTF8(UnicodeScalarValue, Storage);
+          UnquotedValue = UnquotedValue.substr(4);
+          break;
+        }
+      case 'U': {
+          if (UnquotedValue.size() < 9)
+            // TODO: Report error.
+            break;
+          unsigned int UnicodeScalarValue;
+          if (UnquotedValue.substr(1, 8).getAsInteger(16, UnicodeScalarValue))
+            // TODO: Report error.
+            UnicodeScalarValue = 0xFFFD;
+          encodeUTF8(UnicodeScalarValue, Storage);
+          UnquotedValue = UnquotedValue.substr(8);
+          break;
+        }
+      }
+      UnquotedValue = UnquotedValue.substr(1);
+    }
+  }
+  Storage.insert(Storage.end(), UnquotedValue.begin(), UnquotedValue.end());
+  return StringRef(Storage.begin(), Storage.size());
+}
+
+Node *KeyValueNode::getKey() {
+  if (Key)
+    return Key;
+  // Handle implicit null keys.
+  {
+    Token &t = peekNext();
+    if (   t.Kind == Token::TK_BlockEnd
+        || t.Kind == Token::TK_Value
+        || t.Kind == Token::TK_Error) {
+      return Key = new (getAllocator()) NullNode(Doc);
+    }
+    if (t.Kind == Token::TK_Key)
+      getNext(); // skip TK_Key.
+  }
+
+  // Handle explicit null keys.
+  Token &t = peekNext();
+  if (t.Kind == Token::TK_BlockEnd || t.Kind == Token::TK_Value) {
+    return Key = new (getAllocator()) NullNode(Doc);
+  }
+
+  // We've got a normal key.
+  return Key = parseBlockNode();
+}
+
+Node *KeyValueNode::getValue() {
+  if (Value)
+    return Value;
+
+  if (Node* Key = getKey())
+    Key->skip();
+  else {
+    setError("Null key in Key Value.", peekNext());
+    return Value = new (getAllocator()) NullNode(Doc);
+  }
+
+  if (failed())
+    return Value = new (getAllocator()) NullNode(Doc);
+
+  // Handle implicit null values.
+  {
+    Token &t = peekNext();
+    if (   t.Kind == Token::TK_BlockEnd
+        || t.Kind == Token::TK_FlowMappingEnd
+        || t.Kind == Token::TK_Key
+        || t.Kind == Token::TK_FlowEntry
+        || t.Kind == Token::TK_Error) {
+      return Value = new (getAllocator()) NullNode(Doc);
+    }
+
+    if (t.Kind != Token::TK_Value) {
+      setError("Unexpected token in Key Value.", t);
+      return Value = new (getAllocator()) NullNode(Doc);
+    }
+    getNext(); // skip TK_Value.
+  }
+
+  // Handle explicit null values.
+  Token &t = peekNext();
+  if (t.Kind == Token::TK_BlockEnd || t.Kind == Token::TK_Key) {
+    return Value = new (getAllocator()) NullNode(Doc);
+  }
+
+  // We got a normal value.
+  return Value = parseBlockNode();
+}
+
+void MappingNode::increment() {
+  if (failed()) {
+    IsAtEnd = true;
+    CurrentEntry = nullptr;
+    return;
+  }
+  if (CurrentEntry) {
+    CurrentEntry->skip();
+    if (Type == MT_Inline) {
+      IsAtEnd = true;
+      CurrentEntry = nullptr;
+      return;
+    }
+  }
+  Token T = peekNext();
+  if (T.Kind == Token::TK_Key || T.Kind == Token::TK_Scalar) {
+    // KeyValueNode eats the TK_Key. That way it can detect null keys.
+    CurrentEntry = new (getAllocator()) KeyValueNode(Doc);
+  } else if (Type == MT_Block) {
+    switch (T.Kind) {
+    case Token::TK_BlockEnd:
+      getNext();
+      IsAtEnd = true;
+      CurrentEntry = nullptr;
+      break;
+    default:
+      setError("Unexpected token. Expected Key or Block End", T);
+      LLVM_FALLTHROUGH;
+    case Token::TK_Error:
+      IsAtEnd = true;
+      CurrentEntry = nullptr;
+    }
+  } else {
+    switch (T.Kind) {
+    case Token::TK_FlowEntry:
+      // Eat the flow entry and recurse.
+      getNext();
+      return increment();
+    case Token::TK_FlowMappingEnd:
+      getNext();
+      LLVM_FALLTHROUGH;
+    case Token::TK_Error:
+      // Set this to end iterator.
+      IsAtEnd = true;
+      CurrentEntry = nullptr;
+      break;
+    default:
+      setError( "Unexpected token. Expected Key, Flow Entry, or Flow "
+                "Mapping End."
+              , T);
+      IsAtEnd = true;
+      CurrentEntry = nullptr;
+    }
+  }
+}
+
+void SequenceNode::increment() {
+  if (failed()) {
+    IsAtEnd = true;
+    CurrentEntry = nullptr;
+    return;
+  }
+  if (CurrentEntry)
+    CurrentEntry->skip();
+  Token T = peekNext();
+  if (SeqType == ST_Block) {
+    switch (T.Kind) {
+    case Token::TK_BlockEntry:
+      getNext();
+      CurrentEntry = parseBlockNode();
+      if (!CurrentEntry) { // An error occurred.
+        IsAtEnd = true;
+        CurrentEntry = nullptr;
+      }
+      break;
+    case Token::TK_BlockEnd:
+      getNext();
+      IsAtEnd = true;
+      CurrentEntry = nullptr;
+      break;
+    default:
+      setError( "Unexpected token. Expected Block Entry or Block End."
+              , T);
+      LLVM_FALLTHROUGH;
+    case Token::TK_Error:
+      IsAtEnd = true;
+      CurrentEntry = nullptr;
+    }
+  } else if (SeqType == ST_Indentless) {
+    switch (T.Kind) {
+    case Token::TK_BlockEntry:
+      getNext();
+      CurrentEntry = parseBlockNode();
+      if (!CurrentEntry) { // An error occurred.
+        IsAtEnd = true;
+        CurrentEntry = nullptr;
+      }
+      break;
+    default:
+    case Token::TK_Error:
+      IsAtEnd = true;
+      CurrentEntry = nullptr;
+    }
+  } else if (SeqType == ST_Flow) {
+    switch (T.Kind) {
+    case Token::TK_FlowEntry:
+      // Eat the flow entry and recurse.
+      getNext();
+      WasPreviousTokenFlowEntry = true;
+      return increment();
+    case Token::TK_FlowSequenceEnd:
+      getNext();
+      LLVM_FALLTHROUGH;
+    case Token::TK_Error:
+      // Set this to end iterator.
+      IsAtEnd = true;
+      CurrentEntry = nullptr;
+      break;
+    case Token::TK_StreamEnd:
+    case Token::TK_DocumentEnd:
+    case Token::TK_DocumentStart:
+      setError("Could not find closing ]!", T);
+      // Set this to end iterator.
+      IsAtEnd = true;
+      CurrentEntry = nullptr;
+      break;
+    default:
+      if (!WasPreviousTokenFlowEntry) {
+        setError("Expected , between entries!", T);
+        IsAtEnd = true;
+        CurrentEntry = nullptr;
+        break;
+      }
+      // Otherwise it must be a flow entry.
+      CurrentEntry = parseBlockNode();
+      if (!CurrentEntry) {
+        IsAtEnd = true;
+      }
+      WasPreviousTokenFlowEntry = false;
+      break;
+    }
+  }
+}
+
+Document::Document(Stream &S) : stream(S), Root(nullptr) {
+  // Tag maps starts with two default mappings.
+  TagMap["!"] = "!";
+  TagMap["!!"] = "tag:yaml.org,2002:";
+
+  if (parseDirectives())
+    expectToken(Token::TK_DocumentStart);
+  Token &T = peekNext();
+  if (T.Kind == Token::TK_DocumentStart)
+    getNext();
+}
+
+bool Document::skip()  {
+  if (stream.scanner->failed())
+    return false;
+  if (!Root)
+    getRoot();
+  Root->skip();
+  Token &T = peekNext();
+  if (T.Kind == Token::TK_StreamEnd)
+    return false;
+  if (T.Kind == Token::TK_DocumentEnd) {
+    getNext();
+    return skip();
+  }
+  return true;
+}
+
+Token &Document::peekNext() {
+  return stream.scanner->peekNext();
+}
+
+Token Document::getNext() {
+  return stream.scanner->getNext();
+}
+
+void Document::setError(const Twine &Message, Token &Location) const {
+  stream.scanner->setError(Message, Location.Range.begin());
+}
+
+bool Document::failed() const {
+  return stream.scanner->failed();
+}
+
+Node *Document::parseBlockNode() {
+  Token T = peekNext();
+  // Handle properties.
+  Token AnchorInfo;
+  Token TagInfo;
+parse_property:
+  switch (T.Kind) {
+  case Token::TK_Alias:
+    getNext();
+    return new (NodeAllocator) AliasNode(stream.CurrentDoc, T.Range.substr(1));
+  case Token::TK_Anchor:
+    if (AnchorInfo.Kind == Token::TK_Anchor) {
+      setError("Already encountered an anchor for this node!", T);
+      return nullptr;
+    }
+    AnchorInfo = getNext(); // Consume TK_Anchor.
+    T = peekNext();
+    goto parse_property;
+  case Token::TK_Tag:
+    if (TagInfo.Kind == Token::TK_Tag) {
+      setError("Already encountered a tag for this node!", T);
+      return nullptr;
+    }
+    TagInfo = getNext(); // Consume TK_Tag.
+    T = peekNext();
+    goto parse_property;
+  default:
+    break;
+  }
+
+  switch (T.Kind) {
+  case Token::TK_BlockEntry:
+    // We got an unindented BlockEntry sequence. This is not terminated with
+    // a BlockEnd.
+    // Don't eat the TK_BlockEntry, SequenceNode needs it.
+    return new (NodeAllocator) SequenceNode( stream.CurrentDoc
+                                           , AnchorInfo.Range.substr(1)
+                                           , TagInfo.Range
+                                           , SequenceNode::ST_Indentless);
+  case Token::TK_BlockSequenceStart:
+    getNext();
+    return new (NodeAllocator)
+      SequenceNode( stream.CurrentDoc
+                  , AnchorInfo.Range.substr(1)
+                  , TagInfo.Range
+                  , SequenceNode::ST_Block);
+  case Token::TK_BlockMappingStart:
+    getNext();
+    return new (NodeAllocator)
+      MappingNode( stream.CurrentDoc
+                 , AnchorInfo.Range.substr(1)
+                 , TagInfo.Range
+                 , MappingNode::MT_Block);
+  case Token::TK_FlowSequenceStart:
+    getNext();
+    return new (NodeAllocator)
+      SequenceNode( stream.CurrentDoc
+                  , AnchorInfo.Range.substr(1)
+                  , TagInfo.Range
+                  , SequenceNode::ST_Flow);
+  case Token::TK_FlowMappingStart:
+    getNext();
+    return new (NodeAllocator)
+      MappingNode( stream.CurrentDoc
+                 , AnchorInfo.Range.substr(1)
+                 , TagInfo.Range
+                 , MappingNode::MT_Flow);
+  case Token::TK_Scalar:
+    getNext();
+    return new (NodeAllocator)
+      ScalarNode( stream.CurrentDoc
+                , AnchorInfo.Range.substr(1)
+                , TagInfo.Range
+                , T.Range);
+  case Token::TK_BlockScalar: {
+    getNext();
+    StringRef NullTerminatedStr(T.Value.c_str(), T.Value.length() + 1);
+    StringRef StrCopy = NullTerminatedStr.copy(NodeAllocator).drop_back();
+    return new (NodeAllocator)
+        BlockScalarNode(stream.CurrentDoc, AnchorInfo.Range.substr(1),
+                        TagInfo.Range, StrCopy, T.Range);
+  }
+  case Token::TK_Key:
+    // Don't eat the TK_Key, KeyValueNode expects it.
+    return new (NodeAllocator)
+      MappingNode( stream.CurrentDoc
+                 , AnchorInfo.Range.substr(1)
+                 , TagInfo.Range
+                 , MappingNode::MT_Inline);
+  case Token::TK_DocumentStart:
+  case Token::TK_DocumentEnd:
+  case Token::TK_StreamEnd:
+  default:
+    // TODO: Properly handle tags. "[!!str ]" should resolve to !!str "", not
+    //       !!null null.
+    return new (NodeAllocator) NullNode(stream.CurrentDoc);
+  case Token::TK_FlowMappingEnd:
+  case Token::TK_FlowSequenceEnd:
+  case Token::TK_FlowEntry: {
+    if (Root && (isa<MappingNode>(Root) || isa<SequenceNode>(Root)))
+      return new (NodeAllocator) NullNode(stream.CurrentDoc);
+
+    setError("Unexpected token", T);
+    return nullptr;
+  }
+  case Token::TK_Error:
+    return nullptr;
+  }
+  llvm_unreachable("Control flow shouldn't reach here.");
+  return nullptr;
+}
+
+bool Document::parseDirectives() {
+  bool isDirective = false;
+  while (true) {
+    Token T = peekNext();
+    if (T.Kind == Token::TK_TagDirective) {
+      parseTAGDirective();
+      isDirective = true;
+    } else if (T.Kind == Token::TK_VersionDirective) {
+      parseYAMLDirective();
+      isDirective = true;
+    } else
+      break;
+  }
+  return isDirective;
+}
+
+void Document::parseYAMLDirective() {
+  getNext(); // Eat %YAML <version>
+}
+
+void Document::parseTAGDirective() {
+  Token Tag = getNext(); // %TAG <handle> <prefix>
+  StringRef T = Tag.Range;
+  // Strip %TAG
+  T = T.substr(T.find_first_of(" \t")).ltrim(" \t");
+  std::size_t HandleEnd = T.find_first_of(" \t");
+  StringRef TagHandle = T.substr(0, HandleEnd);
+  StringRef TagPrefix = T.substr(HandleEnd).ltrim(" \t");
+  TagMap[TagHandle] = TagPrefix;
+}
+
+bool Document::expectToken(int TK) {
+  Token T = getNext();
+  if (T.Kind != TK) {
+    setError("Unexpected token", T);
+    return false;
+  }
+  return true;
+}
diff --git a/binaryen/third_party/llvm-project/YAMLTraits.cpp b/binaryen/third_party/llvm-project/YAMLTraits.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/YAMLTraits.cpp
@@ -0,0 +1,1087 @@
+//===- lib/Support/YAMLTraits.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Unicode.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+using namespace yaml;
+
+//===----------------------------------------------------------------------===//
+//  IO
+//===----------------------------------------------------------------------===//
+
+IO::IO(void *Context) : Ctxt(Context) {}
+
+IO::~IO() = default;
+
+void *IO::getContext() const {
+  return Ctxt;
+}
+
+void IO::setContext(void *Context) {
+  Ctxt = Context;
+}
+
+//===----------------------------------------------------------------------===//
+//  Input
+//===----------------------------------------------------------------------===//
+
+Input::Input(StringRef InputContent, void *Ctxt,
+             SourceMgr::DiagHandlerTy DiagHandler, void *DiagHandlerCtxt)
+    : IO(Ctxt), Strm(new Stream(InputContent, SrcMgr, false, &EC)) {
+  if (DiagHandler)
+    SrcMgr.setDiagHandler(DiagHandler, DiagHandlerCtxt);
+  DocIterator = Strm->begin();
+}
+
+Input::Input(MemoryBufferRef Input, void *Ctxt,
+             SourceMgr::DiagHandlerTy DiagHandler, void *DiagHandlerCtxt)
+    : IO(Ctxt), Strm(new Stream(Input, SrcMgr, false, &EC)) {
+  if (DiagHandler)
+    SrcMgr.setDiagHandler(DiagHandler, DiagHandlerCtxt);
+  DocIterator = Strm->begin();
+}
+
+Input::~Input() = default;
+
+std::error_code Input::error() { return EC; }
+
+// Pin the vtables to this file.
+void Input::HNode::anchor() {}
+void Input::EmptyHNode::anchor() {}
+void Input::ScalarHNode::anchor() {}
+void Input::MapHNode::anchor() {}
+void Input::SequenceHNode::anchor() {}
+
+bool Input::outputting() const {
+  return false;
+}
+
+bool Input::setCurrentDocument() {
+  if (DocIterator != Strm->end()) {
+    Node *N = DocIterator->getRoot();
+    if (!N) {
+      EC = make_error_code(errc::invalid_argument);
+      return false;
+    }
+
+    if (isa<NullNode>(N)) {
+      // Empty files are allowed and ignored
+      ++DocIterator;
+      return setCurrentDocument();
+    }
+    TopNode = createHNodes(N);
+    CurrentNode = TopNode.get();
+    return true;
+  }
+  return false;
+}
+
+bool Input::nextDocument() {
+  return ++DocIterator != Strm->end();
+}
+
+const Node *Input::getCurrentNode() const {
+  return CurrentNode ? CurrentNode->_node : nullptr;
+}
+
+bool Input::mapTag(StringRef Tag, bool Default) {
+  // CurrentNode can be null if setCurrentDocument() was unable to
+  // parse the document because it was invalid or empty.
+  if (!CurrentNode)
+    return false;
+
+  std::string foundTag = CurrentNode->_node->getVerbatimTag();
+  if (foundTag.empty()) {
+    // If no tag found and 'Tag' is the default, say it was found.
+    return Default;
+  }
+  // Return true iff found tag matches supplied tag.
+  return Tag.equals(foundTag);
+}
+
+void Input::beginMapping() {
+  if (EC)
+    return;
+  // CurrentNode can be null if the document is empty.
+  MapHNode *MN = dyn_cast_or_null<MapHNode>(CurrentNode);
+  if (MN) {
+    MN->ValidKeys.clear();
+  }
+}
+
+std::vector<StringRef> Input::keys() {
+  MapHNode *MN = dyn_cast<MapHNode>(CurrentNode);
+  std::vector<StringRef> Ret;
+  if (!MN) {
+    setError(CurrentNode, "not a mapping");
+    return Ret;
+  }
+  for (auto &P : MN->Mapping)
+    Ret.push_back(P.first());
+  return Ret;
+}
+
+bool Input::preflightKey(const char *Key, bool Required, bool, bool &UseDefault,
+                         void *&SaveInfo) {
+  UseDefault = false;
+  if (EC)
+    return false;
+
+  // CurrentNode is null for empty documents, which is an error in case required
+  // nodes are present.
+  if (!CurrentNode) {
+    if (Required)
+      EC = make_error_code(errc::invalid_argument);
+    return false;
+  }
+
+  MapHNode *MN = dyn_cast<MapHNode>(CurrentNode);
+  if (!MN) {
+    if (Required || !isa<EmptyHNode>(CurrentNode))
+      setError(CurrentNode, "not a mapping");
+    return false;
+  }
+  MN->ValidKeys.push_back(Key);
+  HNode *Value = MN->Mapping[Key].get();
+  if (!Value) {
+    if (Required)
+      setError(CurrentNode, Twine("missing required key '") + Key + "'");
+    else
+      UseDefault = true;
+    return false;
+  }
+  SaveInfo = CurrentNode;
+  CurrentNode = Value;
+  return true;
+}
+
+void Input::postflightKey(void *saveInfo) {
+  CurrentNode = reinterpret_cast<HNode *>(saveInfo);
+}
+
+void Input::endMapping() {
+  if (EC)
+    return;
+  // CurrentNode can be null if the document is empty.
+  MapHNode *MN = dyn_cast_or_null<MapHNode>(CurrentNode);
+  if (!MN)
+    return;
+  for (const auto &NN : MN->Mapping) {
+    if (!is_contained(MN->ValidKeys, NN.first())) {
+      setError(NN.second.get(), Twine("unknown key '") + NN.first() + "'");
+      break;
+    }
+  }
+}
+
+void Input::beginFlowMapping() { beginMapping(); }
+
+void Input::endFlowMapping() { endMapping(); }
+
+unsigned Input::beginSequence() {
+  if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode))
+    return SQ->Entries.size();
+  if (isa<EmptyHNode>(CurrentNode))
+    return 0;
+  // Treat case where there's a scalar "null" value as an empty sequence.
+  if (ScalarHNode *SN = dyn_cast<ScalarHNode>(CurrentNode)) {
+    if (isNull(SN->value()))
+      return 0;
+  }
+  // Any other type of HNode is an error.
+  setError(CurrentNode, "not a sequence");
+  return 0;
+}
+
+void Input::endSequence() {
+}
+
+bool Input::preflightElement(unsigned Index, void *&SaveInfo) {
+  if (EC)
+    return false;
+  if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {
+    SaveInfo = CurrentNode;
+    CurrentNode = SQ->Entries[Index].get();
+    return true;
+  }
+  return false;
+}
+
+void Input::postflightElement(void *SaveInfo) {
+  CurrentNode = reinterpret_cast<HNode *>(SaveInfo);
+}
+
+unsigned Input::beginFlowSequence() { return beginSequence(); }
+
+bool Input::preflightFlowElement(unsigned index, void *&SaveInfo) {
+  if (EC)
+    return false;
+  if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {
+    SaveInfo = CurrentNode;
+    CurrentNode = SQ->Entries[index].get();
+    return true;
+  }
+  return false;
+}
+
+void Input::postflightFlowElement(void *SaveInfo) {
+  CurrentNode = reinterpret_cast<HNode *>(SaveInfo);
+}
+
+void Input::endFlowSequence() {
+}
+
+void Input::beginEnumScalar() {
+  ScalarMatchFound = false;
+}
+
+bool Input::matchEnumScalar(const char *Str, bool) {
+  if (ScalarMatchFound)
+    return false;
+  if (ScalarHNode *SN = dyn_cast<ScalarHNode>(CurrentNode)) {
+    if (SN->value().equals(Str)) {
+      ScalarMatchFound = true;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool Input::matchEnumFallback() {
+  if (ScalarMatchFound)
+    return false;
+  ScalarMatchFound = true;
+  return true;
+}
+
+void Input::endEnumScalar() {
+  if (!ScalarMatchFound) {
+    setError(CurrentNode, "unknown enumerated scalar");
+  }
+}
+
+bool Input::beginBitSetScalar(bool &DoClear) {
+  BitValuesUsed.clear();
+  if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {
+    BitValuesUsed.insert(BitValuesUsed.begin(), SQ->Entries.size(), false);
+  } else {
+    setError(CurrentNode, "expected sequence of bit values");
+  }
+  DoClear = true;
+  return true;
+}
+
+bool Input::bitSetMatch(const char *Str, bool) {
+  if (EC)
+    return false;
+  if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {
+    unsigned Index = 0;
+    for (auto &N : SQ->Entries) {
+      if (ScalarHNode *SN = dyn_cast<ScalarHNode>(N.get())) {
+        if (SN->value().equals(Str)) {
+          BitValuesUsed[Index] = true;
+          return true;
+        }
+      } else {
+        setError(CurrentNode, "unexpected scalar in sequence of bit values");
+      }
+      ++Index;
+    }
+  } else {
+    setError(CurrentNode, "expected sequence of bit values");
+  }
+  return false;
+}
+
+void Input::endBitSetScalar() {
+  if (EC)
+    return;
+  if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {
+    assert(BitValuesUsed.size() == SQ->Entries.size());
+    for (unsigned i = 0; i < SQ->Entries.size(); ++i) {
+      if (!BitValuesUsed[i]) {
+        setError(SQ->Entries[i].get(), "unknown bit value");
+        return;
+      }
+    }
+  }
+}
+
+void Input::scalarString(StringRef &S, QuotingType) {
+  if (ScalarHNode *SN = dyn_cast<ScalarHNode>(CurrentNode)) {
+    S = SN->value();
+  } else {
+    setError(CurrentNode, "unexpected scalar");
+  }
+}
+
+void Input::blockScalarString(StringRef &S) { scalarString(S, QuotingType::None); }
+
+void Input::scalarTag(std::string &Tag) {
+  Tag = CurrentNode->_node->getVerbatimTag();
+}
+
+void Input::setError(HNode *hnode, const Twine &message) {
+  assert(hnode && "HNode must not be NULL");
+  setError(hnode->_node, message);
+}
+
+NodeKind Input::getNodeKind() {
+  if (isa<ScalarHNode>(CurrentNode))
+    return NodeKind::Scalar;
+  else if (isa<MapHNode>(CurrentNode))
+    return NodeKind::Map;
+  else if (isa<SequenceHNode>(CurrentNode))
+    return NodeKind::Sequence;
+  llvm_unreachable("Unsupported node kind");
+}
+
+void Input::setError(Node *node, const Twine &message) {
+  Strm->printError(node, message);
+  EC = make_error_code(errc::invalid_argument);
+}
+
+std::unique_ptr<Input::HNode> Input::createHNodes(Node *N) {
+  SmallString<128> StringStorage;
+  if (ScalarNode *SN = dyn_cast<ScalarNode>(N)) {
+    StringRef KeyStr = SN->getValue(StringStorage);
+    if (!StringStorage.empty()) {
+      // Copy string to permanent storage
+      KeyStr = StringStorage.str().copy(StringAllocator);
+    }
+    return std::make_unique<ScalarHNode>(N, KeyStr);
+  } else if (BlockScalarNode *BSN = dyn_cast<BlockScalarNode>(N)) {
+    StringRef ValueCopy = BSN->getValue().copy(StringAllocator);
+    return std::make_unique<ScalarHNode>(N, ValueCopy);
+  } else if (SequenceNode *SQ = dyn_cast<SequenceNode>(N)) {
+    auto SQHNode = std::make_unique<SequenceHNode>(N);
+    for (Node &SN : *SQ) {
+      auto Entry = createHNodes(&SN);
+      if (EC)
+        break;
+      SQHNode->Entries.push_back(std::move(Entry));
+    }
+    return std::move(SQHNode);
+  } else if (MappingNode *Map = dyn_cast<MappingNode>(N)) {
+    auto mapHNode = std::make_unique<MapHNode>(N);
+    for (KeyValueNode &KVN : *Map) {
+      Node *KeyNode = KVN.getKey();
+      ScalarNode *Key = dyn_cast_or_null<ScalarNode>(KeyNode);
+      Node *Value = KVN.getValue();
+      if (!Key || !Value) {
+        if (!Key)
+          setError(KeyNode, "Map key must be a scalar");
+        if (!Value)
+          setError(KeyNode, "Map value must not be empty");
+        break;
+      }
+      StringStorage.clear();
+      StringRef KeyStr = Key->getValue(StringStorage);
+      if (!StringStorage.empty()) {
+        // Copy string to permanent storage
+        KeyStr = StringStorage.str().copy(StringAllocator);
+      }
+      auto ValueHNode = createHNodes(Value);
+      if (EC)
+        break;
+      mapHNode->Mapping[KeyStr] = std::move(ValueHNode);
+    }
+    return std::move(mapHNode);
+  } else if (isa<NullNode>(N)) {
+    return std::make_unique<EmptyHNode>(N);
+  } else {
+    setError(N, "unknown node kind");
+    return nullptr;
+  }
+}
+
+void Input::setError(const Twine &Message) {
+  setError(CurrentNode, Message);
+}
+
+bool Input::canElideEmptySequence() {
+  return false;
+}
+
+//===----------------------------------------------------------------------===//
+//  Output
+//===----------------------------------------------------------------------===//
+
+Output::Output(raw_ostream &yout, void *context, int WrapColumn)
+    : IO(context), Out(yout), WrapColumn(WrapColumn) {}
+
+Output::~Output() = default;
+
+bool Output::outputting() const {
+  return true;
+}
+
+void Output::beginMapping() {
+  StateStack.push_back(inMapFirstKey);
+  PaddingBeforeContainer = Padding;
+  Padding = "\n";
+}
+
+bool Output::mapTag(StringRef Tag, bool Use) {
+  if (Use) {
+    // If this tag is being written inside a sequence we should write the start
+    // of the sequence before writing the tag, otherwise the tag won't be
+    // attached to the element in the sequence, but rather the sequence itself.
+    bool SequenceElement = false;
+    if (StateStack.size() > 1) {
+      auto &E = StateStack[StateStack.size() - 2];
+      SequenceElement = inSeqAnyElement(E) || inFlowSeqAnyElement(E);
+    }
+    if (SequenceElement && StateStack.back() == inMapFirstKey) {
+      newLineCheck();
+    } else {
+      output(" ");
+    }
+    output(Tag);
+    if (SequenceElement) {
+      // If we're writing the tag during the first element of a map, the tag
+      // takes the place of the first element in the sequence.
+      if (StateStack.back() == inMapFirstKey) {
+        StateStack.pop_back();
+        StateStack.push_back(inMapOtherKey);
+      }
+      // Tags inside maps in sequences should act as keys in the map from a
+      // formatting perspective, so we always want a newline in a sequence.
+      Padding = "\n";
+    }
+  }
+  return Use;
+}
+
+void Output::endMapping() {
+  // If we did not map anything, we should explicitly emit an empty map
+  if (StateStack.back() == inMapFirstKey) {
+    Padding = PaddingBeforeContainer;
+    newLineCheck();
+    output("{}");
+    Padding = "\n";
+  }
+  StateStack.pop_back();
+}
+
+std::vector<StringRef> Output::keys() {
+  report_fatal_error("invalid call");
+}
+
+bool Output::preflightKey(const char *Key, bool Required, bool SameAsDefault,
+                          bool &UseDefault, void *&) {
+  UseDefault = false;
+  if (Required || !SameAsDefault || WriteDefaultValues) {
+    auto State = StateStack.back();
+    if (State == inFlowMapFirstKey || State == inFlowMapOtherKey) {
+      flowKey(Key);
+    } else {
+      newLineCheck();
+      paddedKey(Key);
+    }
+    return true;
+  }
+  return false;
+}
+
+void Output::postflightKey(void *) {
+  if (StateStack.back() == inMapFirstKey) {
+    StateStack.pop_back();
+    StateStack.push_back(inMapOtherKey);
+  } else if (StateStack.back() == inFlowMapFirstKey) {
+    StateStack.pop_back();
+    StateStack.push_back(inFlowMapOtherKey);
+  }
+}
+
+void Output::beginFlowMapping() {
+  StateStack.push_back(inFlowMapFirstKey);
+  newLineCheck();
+  ColumnAtMapFlowStart = Column;
+  output("{ ");
+}
+
+void Output::endFlowMapping() {
+  StateStack.pop_back();
+  outputUpToEndOfLine(" }");
+}
+
+void Output::beginDocuments() {
+  outputUpToEndOfLine("---");
+}
+
+bool Output::preflightDocument(unsigned index) {
+  if (index > 0)
+    outputUpToEndOfLine("\n---");
+  return true;
+}
+
+void Output::postflightDocument() {
+}
+
+void Output::endDocuments() {
+  output("\n...\n");
+}
+
+unsigned Output::beginSequence() {
+  StateStack.push_back(inSeqFirstElement);
+  PaddingBeforeContainer = Padding;
+  Padding = "\n";
+  return 0;
+}
+
+void Output::endSequence() {
+  // If we did not emit anything, we should explicitly emit an empty sequence
+  if (StateStack.back() == inSeqFirstElement) {
+    Padding = PaddingBeforeContainer;
+    newLineCheck();
+    output("[]");
+    Padding = "\n";
+  }
+  StateStack.pop_back();
+}
+
+bool Output::preflightElement(unsigned, void *&) {
+  return true;
+}
+
+void Output::postflightElement(void *) {
+  if (StateStack.back() == inSeqFirstElement) {
+    StateStack.pop_back();
+    StateStack.push_back(inSeqOtherElement);
+  } else if (StateStack.back() == inFlowSeqFirstElement) {
+    StateStack.pop_back();
+    StateStack.push_back(inFlowSeqOtherElement);
+  }
+}
+
+unsigned Output::beginFlowSequence() {
+  StateStack.push_back(inFlowSeqFirstElement);
+  newLineCheck();
+  ColumnAtFlowStart = Column;
+  output("[ ");
+  NeedFlowSequenceComma = false;
+  return 0;
+}
+
+void Output::endFlowSequence() {
+  StateStack.pop_back();
+  outputUpToEndOfLine(" ]");
+}
+
+bool Output::preflightFlowElement(unsigned, void *&) {
+  if (NeedFlowSequenceComma)
+    output(", ");
+  if (WrapColumn && Column > WrapColumn) {
+    output("\n");
+    for (int i = 0; i < ColumnAtFlowStart; ++i)
+      output(" ");
+    Column = ColumnAtFlowStart;
+    output("  ");
+  }
+  return true;
+}
+
+void Output::postflightFlowElement(void *) {
+  NeedFlowSequenceComma = true;
+}
+
+void Output::beginEnumScalar() {
+  EnumerationMatchFound = false;
+}
+
+bool Output::matchEnumScalar(const char *Str, bool Match) {
+  if (Match && !EnumerationMatchFound) {
+    newLineCheck();
+    outputUpToEndOfLine(Str);
+    EnumerationMatchFound = true;
+  }
+  return false;
+}
+
+bool Output::matchEnumFallback() {
+  if (EnumerationMatchFound)
+    return false;
+  EnumerationMatchFound = true;
+  return true;
+}
+
+void Output::endEnumScalar() {
+  if (!EnumerationMatchFound)
+    llvm_unreachable("bad runtime enum value");
+}
+
+bool Output::beginBitSetScalar(bool &DoClear) {
+  newLineCheck();
+  output("[ ");
+  NeedBitValueComma = false;
+  DoClear = false;
+  return true;
+}
+
+bool Output::bitSetMatch(const char *Str, bool Matches) {
+  if (Matches) {
+    if (NeedBitValueComma)
+      output(", ");
+    output(Str);
+    NeedBitValueComma = true;
+  }
+  return false;
+}
+
+void Output::endBitSetScalar() {
+  outputUpToEndOfLine(" ]");
+}
+
+void Output::scalarString(StringRef &S, QuotingType MustQuote) {
+  newLineCheck();
+  if (S.empty()) {
+    // Print '' for the empty string because leaving the field empty is not
+    // allowed.
+    outputUpToEndOfLine("''");
+    return;
+  }
+  if (MustQuote == QuotingType::None) {
+    // Only quote if we must.
+    outputUpToEndOfLine(S);
+    return;
+  }
+
+  const char *const Quote = MustQuote == QuotingType::Single ? "'" : "\"";
+  output(Quote); // Starting quote.
+
+  // When using double-quoted strings (and only in that case), non-printable characters may be
+  // present, and will be escaped using a variety of unicode-scalar and special short-form
+  // escapes. This is handled in yaml::escape.
+  if (MustQuote == QuotingType::Double) {
+    output(yaml::escape(S, /* EscapePrintable= */ false));
+    outputUpToEndOfLine(Quote);
+    return;
+  }
+
+  unsigned i = 0;
+  unsigned j = 0;
+  unsigned End = S.size();
+  const char *Base = S.data();
+
+  // When using single-quoted strings, any single quote ' must be doubled to be escaped.
+  while (j < End) {
+    if (S[j] == '\'') {                    // Escape quotes.
+      output(StringRef(&Base[i], j - i));  // "flush".
+      output(StringLiteral("''"));         // Print it as ''
+      i = j + 1;
+    }
+    ++j;
+  }
+  output(StringRef(&Base[i], j - i));
+  outputUpToEndOfLine(Quote); // Ending quote.
+}
+
+void Output::blockScalarString(StringRef &S) {
+  if (!StateStack.empty())
+    newLineCheck();
+  output(" |");
+  outputNewLine();
+
+  unsigned Indent = StateStack.empty() ? 1 : StateStack.size();
+
+  auto Buffer = MemoryBuffer::getMemBuffer(S, "", false);
+  for (line_iterator Lines(*Buffer, false); !Lines.is_at_end(); ++Lines) {
+    for (unsigned I = 0; I < Indent; ++I) {
+      output("  ");
+    }
+    output(*Lines);
+    outputNewLine();
+  }
+}
+
+void Output::scalarTag(std::string &Tag) {
+  if (Tag.empty())
+    return;
+  newLineCheck();
+  output(Tag);
+  output(" ");
+}
+
+void Output::setError(const Twine &message) {
+}
+
+bool Output::canElideEmptySequence() {
+  // Normally, with an optional key/value where the value is an empty sequence,
+  // the whole key/value can be not written.  But, that produces wrong yaml
+  // if the key/value is the only thing in the map and the map is used in
+  // a sequence.  This detects if the this sequence is the first key/value
+  // in map that itself is embedded in a sequnce.
+  if (StateStack.size() < 2)
+    return true;
+  if (StateStack.back() != inMapFirstKey)
+    return true;
+  return !inSeqAnyElement(StateStack[StateStack.size() - 2]);
+}
+
+void Output::output(StringRef s) {
+  Column += s.size();
+  Out << s;
+}
+
+void Output::outputUpToEndOfLine(StringRef s) {
+  output(s);
+  if (StateStack.empty() || (!inFlowSeqAnyElement(StateStack.back()) &&
+                             !inFlowMapAnyKey(StateStack.back())))
+    Padding = "\n";
+}
+
+void Output::outputNewLine() {
+  Out << "\n";
+  Column = 0;
+}
+
+// if seq at top, indent as if map, then add "- "
+// if seq in middle, use "- " if firstKey, else use "  "
+//
+
+void Output::newLineCheck() {
+  if (Padding != "\n") {
+    output(Padding);
+    Padding = {};
+    return;
+  }
+  outputNewLine();
+  Padding = {};
+
+  if (StateStack.size() == 0)
+    return;
+
+  unsigned Indent = StateStack.size() - 1;
+  bool OutputDash = false;
+
+  if (StateStack.back() == inSeqFirstElement ||
+      StateStack.back() == inSeqOtherElement) {
+    OutputDash = true;
+  } else if ((StateStack.size() > 1) &&
+             ((StateStack.back() == inMapFirstKey) ||
+              inFlowSeqAnyElement(StateStack.back()) ||
+              (StateStack.back() == inFlowMapFirstKey)) &&
+             inSeqAnyElement(StateStack[StateStack.size() - 2])) {
+    --Indent;
+    OutputDash = true;
+  }
+
+  for (unsigned i = 0; i < Indent; ++i) {
+    output("  ");
+  }
+  if (OutputDash) {
+    output("- ");
+  }
+
+}
+
+void Output::paddedKey(StringRef key) {
+  output(key);
+  output(":");
+  const char *spaces = "                ";
+  if (key.size() < strlen(spaces))
+    Padding = &spaces[key.size()];
+  else
+    Padding = " ";
+}
+
+void Output::flowKey(StringRef Key) {
+  if (StateStack.back() == inFlowMapOtherKey)
+    output(", ");
+  if (WrapColumn && Column > WrapColumn) {
+    output("\n");
+    for (int I = 0; I < ColumnAtMapFlowStart; ++I)
+      output(" ");
+    Column = ColumnAtMapFlowStart;
+    output("  ");
+  }
+  output(Key);
+  output(": ");
+}
+
+NodeKind Output::getNodeKind() { report_fatal_error("invalid call"); }
+
+bool Output::inSeqAnyElement(InState State) {
+  return State == inSeqFirstElement || State == inSeqOtherElement;
+}
+
+bool Output::inFlowSeqAnyElement(InState State) {
+  return State == inFlowSeqFirstElement || State == inFlowSeqOtherElement;
+}
+
+bool Output::inMapAnyKey(InState State) {
+  return State == inMapFirstKey || State == inMapOtherKey;
+}
+
+bool Output::inFlowMapAnyKey(InState State) {
+  return State == inFlowMapFirstKey || State == inFlowMapOtherKey;
+}
+
+//===----------------------------------------------------------------------===//
+//  traits for built-in types
+//===----------------------------------------------------------------------===//
+
+void ScalarTraits<bool>::output(const bool &Val, void *, raw_ostream &Out) {
+  Out << (Val ? "true" : "false");
+}
+
+StringRef ScalarTraits<bool>::input(StringRef Scalar, void *, bool &Val) {
+  if (Scalar.equals("true")) {
+    Val = true;
+    return StringRef();
+  } else if (Scalar.equals("false")) {
+    Val = false;
+    return StringRef();
+  }
+  return "invalid boolean";
+}
+
+void ScalarTraits<StringRef>::output(const StringRef &Val, void *,
+                                     raw_ostream &Out) {
+  Out << Val;
+}
+
+StringRef ScalarTraits<StringRef>::input(StringRef Scalar, void *,
+                                         StringRef &Val) {
+  Val = Scalar;
+  return StringRef();
+}
+
+void ScalarTraits<std::string>::output(const std::string &Val, void *,
+                                     raw_ostream &Out) {
+  Out << Val;
+}
+
+StringRef ScalarTraits<std::string>::input(StringRef Scalar, void *,
+                                         std::string &Val) {
+  Val = Scalar.str();
+  return StringRef();
+}
+
+void ScalarTraits<uint8_t>::output(const uint8_t &Val, void *,
+                                   raw_ostream &Out) {
+  // use temp uin32_t because ostream thinks uint8_t is a character
+  uint32_t Num = Val;
+  Out << Num;
+}
+
+StringRef ScalarTraits<uint8_t>::input(StringRef Scalar, void *, uint8_t &Val) {
+  unsigned long long n;
+  if (getAsUnsignedInteger(Scalar, 0, n))
+    return "invalid number";
+  if (n > 0xFF)
+    return "out of range number";
+  Val = n;
+  return StringRef();
+}
+
+void ScalarTraits<uint16_t>::output(const uint16_t &Val, void *,
+                                    raw_ostream &Out) {
+  Out << Val;
+}
+
+StringRef ScalarTraits<uint16_t>::input(StringRef Scalar, void *,
+                                        uint16_t &Val) {
+  unsigned long long n;
+  if (getAsUnsignedInteger(Scalar, 0, n))
+    return "invalid number";
+  if (n > 0xFFFF)
+    return "out of range number";
+  Val = n;
+  return StringRef();
+}
+
+void ScalarTraits<uint32_t>::output(const uint32_t &Val, void *,
+                                    raw_ostream &Out) {
+  Out << Val;
+}
+
+StringRef ScalarTraits<uint32_t>::input(StringRef Scalar, void *,
+                                        uint32_t &Val) {
+  unsigned long long n;
+  if (getAsUnsignedInteger(Scalar, 0, n))
+    return "invalid number";
+  if (n > 0xFFFFFFFFUL)
+    return "out of range number";
+  Val = n;
+  return StringRef();
+}
+
+void ScalarTraits<uint64_t>::output(const uint64_t &Val, void *,
+                                    raw_ostream &Out) {
+  Out << Val;
+}
+
+StringRef ScalarTraits<uint64_t>::input(StringRef Scalar, void *,
+                                        uint64_t &Val) {
+  unsigned long long N;
+  if (getAsUnsignedInteger(Scalar, 0, N))
+    return "invalid number";
+  Val = N;
+  return StringRef();
+}
+
+void ScalarTraits<int8_t>::output(const int8_t &Val, void *, raw_ostream &Out) {
+  // use temp in32_t because ostream thinks int8_t is a character
+  int32_t Num = Val;
+  Out << Num;
+}
+
+StringRef ScalarTraits<int8_t>::input(StringRef Scalar, void *, int8_t &Val) {
+  long long N;
+  if (getAsSignedInteger(Scalar, 0, N))
+    return "invalid number";
+  if ((N > 127) || (N < -128))
+    return "out of range number";
+  Val = N;
+  return StringRef();
+}
+
+void ScalarTraits<int16_t>::output(const int16_t &Val, void *,
+                                   raw_ostream &Out) {
+  Out << Val;
+}
+
+StringRef ScalarTraits<int16_t>::input(StringRef Scalar, void *, int16_t &Val) {
+  long long N;
+  if (getAsSignedInteger(Scalar, 0, N))
+    return "invalid number";
+  if ((N > INT16_MAX) || (N < INT16_MIN))
+    return "out of range number";
+  Val = N;
+  return StringRef();
+}
+
+void ScalarTraits<int32_t>::output(const int32_t &Val, void *,
+                                   raw_ostream &Out) {
+  Out << Val;
+}
+
+StringRef ScalarTraits<int32_t>::input(StringRef Scalar, void *, int32_t &Val) {
+  long long N;
+  if (getAsSignedInteger(Scalar, 0, N))
+    return "invalid number";
+  if ((N > INT32_MAX) || (N < INT32_MIN))
+    return "out of range number";
+  Val = N;
+  return StringRef();
+}
+
+void ScalarTraits<int64_t>::output(const int64_t &Val, void *,
+                                   raw_ostream &Out) {
+  Out << Val;
+}
+
+StringRef ScalarTraits<int64_t>::input(StringRef Scalar, void *, int64_t &Val) {
+  long long N;
+  if (getAsSignedInteger(Scalar, 0, N))
+    return "invalid number";
+  Val = N;
+  return StringRef();
+}
+
+void ScalarTraits<double>::output(const double &Val, void *, raw_ostream &Out) {
+  Out << format("%g", Val);
+}
+
+StringRef ScalarTraits<double>::input(StringRef Scalar, void *, double &Val) {
+  if (to_float(Scalar, Val))
+    return StringRef();
+  return "invalid floating point number";
+}
+
+void ScalarTraits<float>::output(const float &Val, void *, raw_ostream &Out) {
+  Out << format("%g", Val);
+}
+
+StringRef ScalarTraits<float>::input(StringRef Scalar, void *, float &Val) {
+  if (to_float(Scalar, Val))
+    return StringRef();
+  return "invalid floating point number";
+}
+
+void ScalarTraits<Hex8>::output(const Hex8 &Val, void *, raw_ostream &Out) {
+  uint8_t Num = Val;
+  Out << format("0x%02X", Num);
+}
+
+StringRef ScalarTraits<Hex8>::input(StringRef Scalar, void *, Hex8 &Val) {
+  unsigned long long n;
+  if (getAsUnsignedInteger(Scalar, 0, n))
+    return "invalid hex8 number";
+  if (n > 0xFF)
+    return "out of range hex8 number";
+  Val = n;
+  return StringRef();
+}
+
+void ScalarTraits<Hex16>::output(const Hex16 &Val, void *, raw_ostream &Out) {
+  uint16_t Num = Val;
+  Out << format("0x%04X", Num);
+}
+
+StringRef ScalarTraits<Hex16>::input(StringRef Scalar, void *, Hex16 &Val) {
+  unsigned long long n;
+  if (getAsUnsignedInteger(Scalar, 0, n))
+    return "invalid hex16 number";
+  if (n > 0xFFFF)
+    return "out of range hex16 number";
+  Val = n;
+  return StringRef();
+}
+
+void ScalarTraits<Hex32>::output(const Hex32 &Val, void *, raw_ostream &Out) {
+  uint32_t Num = Val;
+  Out << format("0x%08X", Num);
+}
+
+StringRef ScalarTraits<Hex32>::input(StringRef Scalar, void *, Hex32 &Val) {
+  unsigned long long n;
+  if (getAsUnsignedInteger(Scalar, 0, n))
+    return "invalid hex32 number";
+  if (n > 0xFFFFFFFFUL)
+    return "out of range hex32 number";
+  Val = n;
+  return StringRef();
+}
+
+void ScalarTraits<Hex64>::output(const Hex64 &Val, void *, raw_ostream &Out) {
+  uint64_t Num = Val;
+  Out << format("0x%016llX", Num);
+}
+
+StringRef ScalarTraits<Hex64>::input(StringRef Scalar, void *, Hex64 &Val) {
+  unsigned long long Num;
+  if (getAsUnsignedInteger(Scalar, 0, Num))
+    return "invalid hex64 number";
+  Val = Num;
+  return StringRef();
+}
diff --git a/binaryen/third_party/llvm-project/dwarf2yaml.cpp b/binaryen/third_party/llvm-project/dwarf2yaml.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/dwarf2yaml.cpp
@@ -0,0 +1,434 @@
+//===------ dwarf2yaml.cpp - obj2yaml conversion tool -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/ObjectYAML/DWARFYAML.h"
+
+#include <algorithm>
+
+using namespace llvm;
+
+void dumpInitialLength(DataExtractor &Data, uint64_t &Offset,
+                       DWARFYAML::InitialLength &InitialLength) {
+  InitialLength.TotalLength = Data.getU32(&Offset);
+  if (InitialLength.isDWARF64())
+    InitialLength.TotalLength64 = Data.getU64(&Offset);
+}
+
+void dumpDebugAbbrev(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+  auto AbbrevSetPtr = DCtx.getDebugAbbrev();
+  if (AbbrevSetPtr) {
+    for (auto AbbrvDeclSet : *AbbrevSetPtr) {
+      auto ListOffset = AbbrvDeclSet.second.getOffset();
+      for (auto AbbrvDecl : AbbrvDeclSet.second) {
+        DWARFYAML::Abbrev Abbrv;
+        Abbrv.Code = AbbrvDecl.getCode();
+        Abbrv.Tag = AbbrvDecl.getTag();
+        Abbrv.Children = AbbrvDecl.hasChildren() ? dwarf::DW_CHILDREN_yes
+                                                 : dwarf::DW_CHILDREN_no;
+        for (auto Attribute : AbbrvDecl.attributes()) {
+          DWARFYAML::AttributeAbbrev AttAbrv;
+          AttAbrv.Attribute = Attribute.Attr;
+          AttAbrv.Form = Attribute.Form;
+          if (AttAbrv.Form == dwarf::DW_FORM_implicit_const)
+            AttAbrv.Value = Attribute.getImplicitConstValue();
+          Abbrv.Attributes.push_back(AttAbrv);
+        }
+        Abbrv.ListOffset = ListOffset;
+        Y.AbbrevDecls.push_back(Abbrv);
+      }
+      // XXX BINARYEN: null-terminate the DeclSet. This is needed to separate
+      // DeclSets from each other, and to null-terminate the entire list
+      // (LLVM works with or without this, but other decoders may error, see
+      //  https://bugs.llvm.org/show_bug.cgi?id=44511).
+      DWARFYAML::Abbrev Abbrv;
+      Abbrv.Code = 0;
+      Abbrv.Tag = dwarf::Tag(0);
+      Y.AbbrevDecls.push_back(Abbrv);
+    }
+  }
+}
+
+void dumpDebugStrings(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+  StringRef RemainingTable = DCtx.getDWARFObj().getStrSection();
+  while (RemainingTable.size() > 0) {
+    auto SymbolPair = RemainingTable.split('\0');
+    RemainingTable = SymbolPair.second;
+    Y.DebugStrings.push_back(SymbolPair.first);
+  }
+}
+
+void dumpDebugARanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+  DataExtractor ArangesData(DCtx.getDWARFObj().getArangesSection(),
+                            DCtx.isLittleEndian(), 0);
+  uint64_t Offset = 0;
+  DWARFDebugArangeSet Set;
+
+  while (Set.extract(ArangesData, &Offset)) {
+    DWARFYAML::ARange Range;
+    Range.Length.setLength(Set.getHeader().Length);
+    Range.Version = Set.getHeader().Version;
+    Range.CuOffset = Set.getHeader().CuOffset;
+    Range.AddrSize = Set.getHeader().AddrSize;
+    Range.SegSize = Set.getHeader().SegSize;
+    for (auto Descriptor : Set.descriptors()) {
+      DWARFYAML::ARangeDescriptor Desc;
+      Desc.Address = Descriptor.Address;
+      Desc.Length = Descriptor.Length;
+      Range.Descriptors.push_back(Desc);
+    }
+    Y.ARanges.push_back(Range);
+  }
+}
+
+void dumpDebugRanges(DWARFContext &DCtx, DWARFYAML::Data &Y) { // XXX BINARYEN
+  uint8_t savedAddressByteSize = 4;
+  DWARFDataExtractor rangesData(DCtx.getDWARFObj(), DCtx.getDWARFObj().getRangesSection(),
+                                DCtx.isLittleEndian(), savedAddressByteSize);
+  uint64_t offset = 0;
+  DWARFDebugRangeList rangeList;
+  while (rangesData.isValidOffset(offset)) {
+    if (Error E = rangeList.extract(rangesData, &offset)) {
+      errs() << toString(std::move(E)) << '\n';
+      break;
+    }
+    for (auto& entry : rangeList.getEntries()) {
+      DWARFYAML::Range range;
+      range.Start = entry.StartAddress;
+      range.End = entry.EndAddress;
+      range.SectionIndex = entry.SectionIndex;
+      Y.Ranges.push_back(range);
+    }
+    DWARFYAML::Range range;
+    range.Start = 0;
+    range.End = 0;
+    range.SectionIndex = -1;
+    Y.Ranges.push_back(range);
+  }
+}
+
+void dumpDebugLoc(DWARFContext &DCtx, DWARFYAML::Data &Y) { // XXX BINARYEN
+  uint8_t savedAddressByteSize = 4;
+  DWARFDataExtractor locsData(DCtx.getDWARFObj(), DCtx.getDWARFObj().getLocSection(),
+                              DCtx.isLittleEndian(), savedAddressByteSize);
+  uint64_t offset = 0;
+  DWARFDebugLoc locList;
+  while (locsData.isValidOffset(offset)) {
+    uint64_t locListOffset = offset; // XXX BINARYEN
+    auto list = locList.parseOneLocationList(locsData, &offset);
+    if (!list) {
+      errs() << "debug_loc error\n";
+      break;
+    }
+    for (auto& entry : list.get().Entries) {
+      DWARFYAML::Loc loc;
+      loc.Start = entry.Begin;
+      loc.End = entry.End;
+      for (auto x : entry.Loc) {
+        loc.Location.push_back(x);
+      }
+      loc.CompileUnitOffset = locListOffset; // XXX BINARYEN
+      Y.Locs.push_back(loc);
+    }
+    DWARFYAML::Loc loc;
+    loc.Start = 0;
+    loc.End = 0;
+    loc.CompileUnitOffset = locListOffset; // XXX BINARYEN
+    Y.Locs.push_back(loc);
+  }
+}
+
+void dumpPubSection(DWARFContext &DCtx, DWARFYAML::PubSection &Y,
+                    DWARFSection Section) {
+  DWARFDataExtractor PubSectionData(DCtx.getDWARFObj(), Section,
+                                    DCtx.isLittleEndian(), 0);
+  uint64_t Offset = 0;
+  dumpInitialLength(PubSectionData, Offset, Y.Length);
+  Y.Version = PubSectionData.getU16(&Offset);
+  Y.UnitOffset = PubSectionData.getU32(&Offset);
+  Y.UnitSize = PubSectionData.getU32(&Offset);
+  while (Offset < Y.Length.getLength()) {
+    DWARFYAML::PubEntry NewEntry;
+    NewEntry.DieOffset = PubSectionData.getU32(&Offset);
+    if (Y.IsGNUStyle)
+      NewEntry.Descriptor = PubSectionData.getU8(&Offset);
+    NewEntry.Name = PubSectionData.getCStr(&Offset);
+    Y.Entries.push_back(NewEntry);
+  }
+}
+
+void dumpDebugPubSections(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+  const DWARFObject &D = DCtx.getDWARFObj();
+  Y.PubNames.IsGNUStyle = false;
+  dumpPubSection(DCtx, Y.PubNames, D.getPubnamesSection());
+
+  Y.PubTypes.IsGNUStyle = false;
+  dumpPubSection(DCtx, Y.PubTypes, D.getPubtypesSection());
+
+  Y.GNUPubNames.IsGNUStyle = true;
+  dumpPubSection(DCtx, Y.GNUPubNames, D.getGnuPubnamesSection());
+
+  Y.GNUPubTypes.IsGNUStyle = true;
+  dumpPubSection(DCtx, Y.GNUPubTypes, D.getGnuPubtypesSection());
+}
+
+void dumpDebugInfo(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+  for (const auto &CU : DCtx.compile_units()) {
+    DWARFYAML::Unit NewUnit;
+    NewUnit.Length.setLength(CU->getLength());
+    NewUnit.Version = CU->getVersion();
+    if(NewUnit.Version >= 5)
+      NewUnit.Type = (dwarf::UnitType)CU->getUnitType();
+    if (auto* Abbreviations = CU->getAbbreviations()) { // XXX BINARYEN
+      NewUnit.AbbrOffset = Abbreviations->getOffset();
+    }
+    NewUnit.AddrSize = CU->getAddressByteSize();
+    for (auto DIE : CU->dies()) {
+      DWARFYAML::Entry NewEntry;
+      DataExtractor EntryData = CU->getDebugInfoExtractor();
+      uint64_t offset = DIE.getOffset();
+
+      assert(EntryData.isValidOffset(offset) && "Invalid DIE Offset");
+      if (!EntryData.isValidOffset(offset))
+        continue;
+
+      NewEntry.AbbrCode = EntryData.getULEB128(&offset);
+
+      auto AbbrevDecl = DIE.getAbbreviationDeclarationPtr();
+      if (AbbrevDecl) {
+        for (const auto &AttrSpec : AbbrevDecl->attributes()) {
+          DWARFYAML::FormValue NewValue;
+          NewValue.Value = 0xDEADBEEFDEADBEEF;
+          DWARFDie DIEWrapper(CU.get(), &DIE);
+          auto FormValue = DIEWrapper.find(AttrSpec.Attr);
+          if (!FormValue)
+            return;
+          auto Form = FormValue.getValue().getForm();
+          bool indirect = false;
+          do {
+            indirect = false;
+            switch (Form) {
+            case dwarf::DW_FORM_addr:
+            case dwarf::DW_FORM_GNU_addr_index:
+              if (auto Val = FormValue.getValue().getAsAddress())
+                NewValue.Value = Val.getValue();
+              break;
+            case dwarf::DW_FORM_ref_addr:
+            case dwarf::DW_FORM_ref1:
+            case dwarf::DW_FORM_ref2:
+            case dwarf::DW_FORM_ref4:
+            case dwarf::DW_FORM_ref8:
+            case dwarf::DW_FORM_ref_udata:
+            case dwarf::DW_FORM_ref_sig8:
+              if (auto Val = FormValue.getValue().getAsReferenceUVal())
+                NewValue.Value = Val.getValue();
+              break;
+            case dwarf::DW_FORM_exprloc:
+            case dwarf::DW_FORM_block:
+            case dwarf::DW_FORM_block1:
+            case dwarf::DW_FORM_block2:
+            case dwarf::DW_FORM_block4:
+              if (auto Val = FormValue.getValue().getAsBlock()) {
+                auto BlockData = Val.getValue();
+                std::copy(BlockData.begin(), BlockData.end(),
+                          std::back_inserter(NewValue.BlockData));
+              }
+              NewValue.Value = NewValue.BlockData.size();
+              break;
+            case dwarf::DW_FORM_data1:
+            case dwarf::DW_FORM_flag:
+            case dwarf::DW_FORM_data2:
+            case dwarf::DW_FORM_data4:
+            case dwarf::DW_FORM_data8:
+            case dwarf::DW_FORM_udata:
+            case dwarf::DW_FORM_ref_sup4:
+            case dwarf::DW_FORM_ref_sup8:
+              if (auto Val = FormValue.getValue().getAsUnsignedConstant())
+                NewValue.Value = Val.getValue();
+              break;
+            // XXX BINARYEN: sdata is signed, and FormValue won't return it as
+            //               unsigned (it returns an empty value).
+            case dwarf::DW_FORM_sdata:
+              if (auto Val = FormValue.getValue().getAsSignedConstant())
+                NewValue.Value = Val.getValue();
+              break;
+            case dwarf::DW_FORM_string:
+              if (auto Val = FormValue.getValue().getAsCString())
+                NewValue.CStr = Val.getValue();
+              break;
+            case dwarf::DW_FORM_indirect:
+              indirect = true;
+              if (auto Val = FormValue.getValue().getAsUnsignedConstant()) {
+                NewValue.Value = Val.getValue();
+                NewEntry.Values.push_back(NewValue);
+                Form = static_cast<dwarf::Form>(Val.getValue());
+              }
+              break;
+            case dwarf::DW_FORM_strp:
+            case dwarf::DW_FORM_sec_offset:
+            case dwarf::DW_FORM_GNU_ref_alt:
+            case dwarf::DW_FORM_GNU_strp_alt:
+            case dwarf::DW_FORM_line_strp:
+            case dwarf::DW_FORM_strp_sup:
+            case dwarf::DW_FORM_GNU_str_index:
+            case dwarf::DW_FORM_strx:
+              if (auto Val = FormValue.getValue().getAsCStringOffset())
+                NewValue.Value = Val.getValue();
+              break;
+            case dwarf::DW_FORM_flag_present:
+              NewValue.Value = 1;
+              break;
+            default:
+              break;
+            }
+          } while (indirect);
+          NewEntry.Values.push_back(NewValue);
+        }
+      }
+
+      NewUnit.Entries.push_back(NewEntry);
+    }
+    Y.CompileUnits.push_back(NewUnit);
+  }
+}
+
+bool dumpFileEntry(DataExtractor &Data, uint64_t &Offset,
+                   DWARFYAML::File &File) {
+  File.Name = Data.getCStr(&Offset);
+  if (File.Name.empty())
+    return false;
+  File.DirIdx = Data.getULEB128(&Offset);
+  File.ModTime = Data.getULEB128(&Offset);
+  File.Length = Data.getULEB128(&Offset);
+  return true;
+}
+
+void dumpDebugLines(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+  for (const auto &CU : DCtx.compile_units()) {
+    auto CUDIE = CU->getUnitDIE();
+    if (!CUDIE)
+      continue;
+    if (auto StmtOffset =
+            dwarf::toSectionOffset(CUDIE.find(dwarf::DW_AT_stmt_list))) {
+      DWARFYAML::LineTable DebugLines;
+      DataExtractor LineData(DCtx.getDWARFObj().getLineSection().Data,
+                             DCtx.isLittleEndian(), CU->getAddressByteSize());
+      uint64_t Offset = *StmtOffset;
+      dumpInitialLength(LineData, Offset, DebugLines.Length);
+      uint64_t LineTableLength = DebugLines.Length.getLength();
+      uint64_t SizeOfPrologueLength = DebugLines.Length.isDWARF64() ? 8 : 4;
+      DebugLines.Version = LineData.getU16(&Offset);
+      DebugLines.PrologueLength =
+          LineData.getUnsigned(&Offset, SizeOfPrologueLength);
+      const uint64_t EndPrologue = DebugLines.PrologueLength + Offset;
+
+      DebugLines.MinInstLength = LineData.getU8(&Offset);
+      if (DebugLines.Version >= 4)
+        DebugLines.MaxOpsPerInst = LineData.getU8(&Offset);
+      DebugLines.DefaultIsStmt = LineData.getU8(&Offset);
+      DebugLines.LineBase = LineData.getU8(&Offset);
+      DebugLines.LineRange = LineData.getU8(&Offset);
+      DebugLines.OpcodeBase = LineData.getU8(&Offset);
+
+      DebugLines.StandardOpcodeLengths.reserve(DebugLines.OpcodeBase - 1);
+      for (uint8_t i = 1; i < DebugLines.OpcodeBase; ++i)
+        DebugLines.StandardOpcodeLengths.push_back(LineData.getU8(&Offset));
+
+      while (Offset < EndPrologue) {
+        StringRef Dir = LineData.getCStr(&Offset);
+        if (!Dir.empty())
+          DebugLines.IncludeDirs.push_back(Dir);
+        else
+          break;
+      }
+
+      while (Offset < EndPrologue) {
+        DWARFYAML::File TmpFile;
+        if (dumpFileEntry(LineData, Offset, TmpFile))
+          DebugLines.Files.push_back(TmpFile);
+        else
+          break;
+      }
+
+      const uint64_t LineEnd =
+          LineTableLength + *StmtOffset + SizeOfPrologueLength;
+      while (Offset < LineEnd) {
+        DWARFYAML::LineTableOpcode NewOp = {};
+        NewOp.Opcode = (dwarf::LineNumberOps)LineData.getU8(&Offset);
+        if (NewOp.Opcode == 0) {
+          auto StartExt = Offset;
+          NewOp.ExtLen = LineData.getULEB128(&Offset);
+          NewOp.SubOpcode =
+              (dwarf::LineNumberExtendedOps)LineData.getU8(&Offset);
+          switch (NewOp.SubOpcode) {
+          case dwarf::DW_LNE_set_address:
+          case dwarf::DW_LNE_set_discriminator:
+            NewOp.Data = LineData.getAddress(&Offset);
+            break;
+          case dwarf::DW_LNE_define_file:
+            dumpFileEntry(LineData, Offset, NewOp.FileEntry);
+            break;
+          case dwarf::DW_LNE_end_sequence:
+            break;
+          default:
+            while (Offset < StartExt + NewOp.ExtLen)
+              NewOp.UnknownOpcodeData.push_back(LineData.getU8(&Offset));
+          }
+        } else if (NewOp.Opcode < DebugLines.OpcodeBase) {
+          switch (NewOp.Opcode) {
+          case dwarf::DW_LNS_copy:
+          case dwarf::DW_LNS_negate_stmt:
+          case dwarf::DW_LNS_set_basic_block:
+          case dwarf::DW_LNS_const_add_pc:
+          case dwarf::DW_LNS_set_prologue_end:
+          case dwarf::DW_LNS_set_epilogue_begin:
+            break;
+
+          case dwarf::DW_LNS_advance_pc:
+          case dwarf::DW_LNS_set_file:
+          case dwarf::DW_LNS_set_column:
+          case dwarf::DW_LNS_set_isa:
+            NewOp.Data = LineData.getULEB128(&Offset);
+            break;
+
+          case dwarf::DW_LNS_advance_line:
+            NewOp.SData = LineData.getSLEB128(&Offset);
+            break;
+
+          case dwarf::DW_LNS_fixed_advance_pc:
+            NewOp.Data = LineData.getU16(&Offset);
+            break;
+
+          default:
+            for (uint8_t i = 0;
+                 i < DebugLines.StandardOpcodeLengths[NewOp.Opcode - 1]; ++i)
+              NewOp.StandardOpcodeData.push_back(LineData.getULEB128(&Offset));
+          }
+        }
+        DebugLines.Opcodes.push_back(NewOp);
+      }
+      Y.DebugLines.push_back(DebugLines);
+    }
+  }
+}
+
+std::error_code dwarf2yaml(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+  Y.IsLittleEndian = true; // XXX BINARYEN
+  dumpDebugAbbrev(DCtx, Y);
+  dumpDebugStrings(DCtx, Y);
+  dumpDebugARanges(DCtx, Y);
+  dumpDebugRanges(DCtx, Y); // XXX BINARYEN
+  dumpDebugLoc(DCtx, Y); // XXX BINARYEN
+  dumpDebugPubSections(DCtx, Y);
+  dumpDebugInfo(DCtx, Y);
+  dumpDebugLines(DCtx, Y);
+  return obj2yaml_error::success;
+}
diff --git a/binaryen/third_party/llvm-project/include/llvm-c/DataTypes.h b/binaryen/third_party/llvm-project/include/llvm-c/DataTypes.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm-c/DataTypes.h
@@ -0,0 +1,90 @@
+/*===-- include/llvm-c/DataTypes.h - Define fixed size types ------*- C -*-===*\
+|*                                                                            *|
+|* Part of the LLVM Project, under the Apache License v2.0 with LLVM          *|
+|* Exceptions.                                                                *|
+|* See https://llvm.org/LICENSE.txt for license information.                  *|
+|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception                    *|
+|*                                                                            *|
+|*===----------------------------------------------------------------------===*|
+|*                                                                            *|
+|* This file contains definitions to figure out the size of _HOST_ data types.*|
+|* This file is important because different host OS's define different macros,*|
+|* which makes portability tough.  This file exports the following            *|
+|* definitions:                                                               *|
+|*                                                                            *|
+|*   [u]int(32|64)_t : typedefs for signed and unsigned 32/64 bit system types*|
+|*   [U]INT(8|16|32|64)_(MIN|MAX) : Constants for the min and max values.     *|
+|*                                                                            *|
+|* No library is required when using these functions.                         *|
+|*                                                                            *|
+|*===----------------------------------------------------------------------===*/
+
+/* Please leave this file C-compatible. */
+
+#ifndef LLVM_C_DATATYPES_H
+#define LLVM_C_DATATYPES_H
+
+#ifdef __cplusplus
+#include <cmath>
+#else
+#include <math.h>
+#endif
+
+#include <inttypes.h>
+#include <stdint.h>
+
+#ifndef _MSC_VER
+
+#if !defined(UINT32_MAX)
+# error "The standard header <cstdint> is not C++11 compliant. Must #define "\
+        "__STDC_LIMIT_MACROS before #including llvm-c/DataTypes.h"
+#endif
+
+#if !defined(UINT32_C)
+# error "The standard header <cstdint> is not C++11 compliant. Must #define "\
+        "__STDC_CONSTANT_MACROS before #including llvm-c/DataTypes.h"
+#endif
+
+/* Note that <inttypes.h> includes <stdint.h>, if this is a C99 system. */
+#include <sys/types.h>
+
+#ifdef _AIX
+// GCC is strict about defining large constants: they must have LL modifier.
+#undef INT64_MAX
+#undef INT64_MIN
+#endif
+
+#else /* _MSC_VER */
+#ifdef __cplusplus
+#include <cstddef>
+#include <cstdlib>
+#else
+#include <stddef.h>
+#include <stdlib.h>
+#endif
+#include <sys/types.h>
+
+#if defined(_WIN64)
+typedef signed __int64 ssize_t;
+#else
+typedef signed int ssize_t;
+#endif /* _WIN64 */
+
+#endif /* _MSC_VER */
+
+/* Set defaults for constants which we cannot find. */
+#if !defined(INT64_MAX)
+# define INT64_MAX 9223372036854775807LL
+#endif
+#if !defined(INT64_MIN)
+# define INT64_MIN ((-INT64_MAX)-1)
+#endif
+#if !defined(UINT64_MAX)
+# define UINT64_MAX 0xffffffffffffffffULL
+#endif
+
+#ifndef HUGE_VALF
+#define HUGE_VALF (float)HUGE_VAL
+#endif
+
+#endif /* LLVM_C_DATATYPES_H */
diff --git a/binaryen/third_party/llvm-project/include/llvm-c/DisassemblerTypes.h b/binaryen/third_party/llvm-project/include/llvm-c/DisassemblerTypes.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm-c/DisassemblerTypes.h
@@ -0,0 +1,160 @@
+/*===-- llvm-c/DisassemblerTypedefs.h -----------------------------*- C -*-===*\
+|*                                                                            *|
+|* Part of the LLVM Project, under the Apache License v2.0 with LLVM          *|
+|* Exceptions.                                                                *|
+|* See https://llvm.org/LICENSE.txt for license information.                  *|
+|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception                    *|
+|*                                                                            *|
+|*===----------------------------------------------------------------------===*/
+
+#ifndef LLVM_DISASSEMBLER_TYPES_H
+#define LLVM_DISASSEMBLER_TYPES_H
+
+#include "llvm-c/DataTypes.h"
+#ifdef __cplusplus
+#include <cstddef>
+#else
+#include <stddef.h>
+#endif
+
+/**
+ * An opaque reference to a disassembler context.
+ */
+typedef void *LLVMDisasmContextRef;
+
+/**
+ * The type for the operand information call back function.  This is called to
+ * get the symbolic information for an operand of an instruction.  Typically
+ * this is from the relocation information, symbol table, etc.  That block of
+ * information is saved when the disassembler context is created and passed to
+ * the call back in the DisInfo parameter.  The instruction containing operand
+ * is at the PC parameter.  For some instruction sets, there can be more than
+ * one operand with symbolic information.  To determine the symbolic operand
+ * information for each operand, the bytes for the specific operand in the
+ * instruction are specified by the Offset parameter and its byte widith is the
+ * size parameter.  For instructions sets with fixed widths and one symbolic
+ * operand per instruction, the Offset parameter will be zero and Size parameter
+ * will be the instruction width.  The information is returned in TagBuf and is
+ * Triple specific with its specific information defined by the value of
+ * TagType for that Triple.  If symbolic information is returned the function
+ * returns 1, otherwise it returns 0.
+ */
+typedef int (*LLVMOpInfoCallback)(void *DisInfo, uint64_t PC,
+                                  uint64_t Offset, uint64_t Size,
+                                  int TagType, void *TagBuf);
+
+/**
+ * The initial support in LLVM MC for the most general form of a relocatable
+ * expression is "AddSymbol - SubtractSymbol + Offset".  For some Darwin targets
+ * this full form is encoded in the relocation information so that AddSymbol and
+ * SubtractSymbol can be link edited independent of each other.  Many other
+ * platforms only allow a relocatable expression of the form AddSymbol + Offset
+ * to be encoded.
+ *
+ * The LLVMOpInfoCallback() for the TagType value of 1 uses the struct
+ * LLVMOpInfo1.  The value of the relocatable expression for the operand,
+ * including any PC adjustment, is passed in to the call back in the Value
+ * field.  The symbolic information about the operand is returned using all
+ * the fields of the structure with the Offset of the relocatable expression
+ * returned in the Value field.  It is possible that some symbols in the
+ * relocatable expression were assembly temporary symbols, for example
+ * "Ldata - LpicBase + constant", and only the Values of the symbols without
+ * symbol names are present in the relocation information.  The VariantKind
+ * type is one of the Target specific #defines below and is used to print
+ * operands like "_foo@GOT", ":lower16:_foo", etc.
+ */
+struct LLVMOpInfoSymbol1 {
+  uint64_t Present;  /* 1 if this symbol is present */
+  const char *Name;  /* symbol name if not NULL */
+  uint64_t Value;    /* symbol value if name is NULL */
+};
+
+struct LLVMOpInfo1 {
+  struct LLVMOpInfoSymbol1 AddSymbol;
+  struct LLVMOpInfoSymbol1 SubtractSymbol;
+  uint64_t Value;
+  uint64_t VariantKind;
+};
+
+/**
+ * The operand VariantKinds for symbolic disassembly.
+ */
+#define LLVMDisassembler_VariantKind_None 0 /* all targets */
+
+/**
+ * The ARM target VariantKinds.
+ */
+#define LLVMDisassembler_VariantKind_ARM_HI16 1 /* :upper16: */
+#define LLVMDisassembler_VariantKind_ARM_LO16 2 /* :lower16: */
+
+/**
+ * The ARM64 target VariantKinds.
+ */
+#define LLVMDisassembler_VariantKind_ARM64_PAGE       1 /* @page */
+#define LLVMDisassembler_VariantKind_ARM64_PAGEOFF    2 /* @pageoff */
+#define LLVMDisassembler_VariantKind_ARM64_GOTPAGE    3 /* @gotpage */
+#define LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF 4 /* @gotpageoff */
+#define LLVMDisassembler_VariantKind_ARM64_TLVP       5 /* @tvlppage */
+#define LLVMDisassembler_VariantKind_ARM64_TLVOFF     6 /* @tvlppageoff */
+
+/**
+ * The type for the symbol lookup function.  This may be called by the
+ * disassembler for things like adding a comment for a PC plus a constant
+ * offset load instruction to use a symbol name instead of a load address value.
+ * It is passed the block information is saved when the disassembler context is
+ * created and the ReferenceValue to look up as a symbol.  If no symbol is found
+ * for the ReferenceValue NULL is returned.  The ReferenceType of the
+ * instruction is passed indirectly as is the PC of the instruction in
+ * ReferencePC.  If the output reference can be determined its type is returned
+ * indirectly in ReferenceType along with ReferenceName if any, or that is set
+ * to NULL.
+ */
+typedef const char *(*LLVMSymbolLookupCallback)(void *DisInfo,
+                                                uint64_t ReferenceValue,
+                                                uint64_t *ReferenceType,
+                                                uint64_t ReferencePC,
+                                                const char **ReferenceName);
+/**
+ * The reference types on input and output.
+ */
+/* No input reference type or no output reference type. */
+#define LLVMDisassembler_ReferenceType_InOut_None 0
+
+/* The input reference is from a branch instruction. */
+#define LLVMDisassembler_ReferenceType_In_Branch 1
+/* The input reference is from a PC relative load instruction. */
+#define LLVMDisassembler_ReferenceType_In_PCrel_Load 2
+
+/* The input reference is from an ARM64::ADRP instruction. */
+#define LLVMDisassembler_ReferenceType_In_ARM64_ADRP 0x100000001
+/* The input reference is from an ARM64::ADDXri instruction. */
+#define LLVMDisassembler_ReferenceType_In_ARM64_ADDXri 0x100000002
+/* The input reference is from an ARM64::LDRXui instruction. */
+#define LLVMDisassembler_ReferenceType_In_ARM64_LDRXui 0x100000003
+/* The input reference is from an ARM64::LDRXl instruction. */
+#define LLVMDisassembler_ReferenceType_In_ARM64_LDRXl 0x100000004
+/* The input reference is from an ARM64::ADR instruction. */
+#define LLVMDisassembler_ReferenceType_In_ARM64_ADR 0x100000005
+
+/* The output reference is to as symbol stub. */
+#define LLVMDisassembler_ReferenceType_Out_SymbolStub 1
+/* The output reference is to a symbol address in a literal pool. */
+#define LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr 2
+/* The output reference is to a cstring address in a literal pool. */
+#define LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr 3
+
+/* The output reference is to a Objective-C CoreFoundation string. */
+#define LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref 4
+/* The output reference is to a Objective-C message. */
+#define LLVMDisassembler_ReferenceType_Out_Objc_Message 5
+/* The output reference is to a Objective-C message ref. */
+#define LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref 6
+/* The output reference is to a Objective-C selector ref. */
+#define LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref 7
+/* The output reference is to a Objective-C class ref. */
+#define LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref 8
+
+/* The output reference is to a C++ symbol name. */
+#define LLVMDisassembler_ReferenceType_DeMangled_Name 9
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm-c/Error.h b/binaryen/third_party/llvm-project/include/llvm-c/Error.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm-c/Error.h
@@ -0,0 +1,69 @@
+/*===------- llvm-c/Error.h - llvm::Error class C Interface -------*- C -*-===*\
+|*                                                                            *|
+|* Part of the LLVM Project, under the Apache License v2.0 with LLVM          *|
+|* Exceptions.                                                                *|
+|* See https://llvm.org/LICENSE.txt for license information.                  *|
+|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception                    *|
+|*                                                                            *|
+|*===----------------------------------------------------------------------===*|
+|*                                                                            *|
+|* This file defines the C interface to LLVM's Error class.                   *|
+|*                                                                            *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef LLVM_C_ERROR_H
+#define LLVM_C_ERROR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LLVMErrorSuccess 0
+
+/**
+ * Opaque reference to an error instance. Null serves as the 'success' value.
+ */
+typedef struct LLVMOpaqueError *LLVMErrorRef;
+
+/**
+ * Error type identifier.
+ */
+typedef const void *LLVMErrorTypeId;
+
+/**
+ * Returns the type id for the given error instance, which must be a failure
+ * value (i.e. non-null).
+ */
+LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err);
+
+/**
+ * Dispose of the given error without handling it. This operation consumes the
+ * error, and the given LLVMErrorRef value is not usable once this call returns.
+ * Note: This method *only* needs to be called if the error is not being passed
+ * to some other consuming operation, e.g. LLVMGetErrorMessage.
+ */
+void LLVMConsumeError(LLVMErrorRef Err);
+
+/**
+ * Returns the given string's error message. This operation consumes the error,
+ * and the given LLVMErrorRef value is not usable once this call returns.
+ * The caller is responsible for disposing of the string by calling
+ * LLVMDisposeErrorMessage.
+ */
+char *LLVMGetErrorMessage(LLVMErrorRef Err);
+
+/**
+ * Dispose of the given error message.
+ */
+void LLVMDisposeErrorMessage(char *ErrMsg);
+
+/**
+ * Returns the type id for llvm StringError.
+ */
+LLVMErrorTypeId LLVMGetStringErrorTypeId(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm-c/ErrorHandling.h b/binaryen/third_party/llvm-project/include/llvm-c/ErrorHandling.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm-c/ErrorHandling.h
@@ -0,0 +1,49 @@
+/*===-- llvm-c/ErrorHandling.h - Error Handling C Interface -------*- C -*-===*\
+|*                                                                            *|
+|* Part of the LLVM Project, under the Apache License v2.0 with LLVM          *|
+|* Exceptions.                                                                *|
+|* See https://llvm.org/LICENSE.txt for license information.                  *|
+|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception                    *|
+|*                                                                            *|
+|*===----------------------------------------------------------------------===*|
+|*                                                                            *|
+|* This file defines the C interface to LLVM's error handling mechanism.      *|
+|*                                                                            *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef LLVM_C_ERROR_HANDLING_H
+#define LLVM_C_ERROR_HANDLING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*LLVMFatalErrorHandler)(const char *Reason);
+
+/**
+ * Install a fatal error handler. By default, if LLVM detects a fatal error, it
+ * will call exit(1). This may not be appropriate in many contexts. For example,
+ * doing exit(1) will bypass many crash reporting/tracing system tools. This
+ * function allows you to install a callback that will be invoked prior to the
+ * call to exit(1).
+ */
+void LLVMInstallFatalErrorHandler(LLVMFatalErrorHandler Handler);
+
+/**
+ * Reset the fatal error handler. This resets LLVM's fatal error handling
+ * behavior to the default.
+ */
+void LLVMResetFatalErrorHandler(void);
+
+/**
+ * Enable LLVM's built-in stack trace code. This intercepts the OS's crash
+ * signals and prints which component of LLVM you were in at the time if the
+ * crash.
+ */
+void LLVMEnablePrettyStackTrace(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm-c/Types.h b/binaryen/third_party/llvm-project/include/llvm-c/Types.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm-c/Types.h
@@ -0,0 +1,179 @@
+/*===-- llvm-c/Support.h - C Interface Types declarations ---------*- C -*-===*\
+|*                                                                            *|
+|* Part of the LLVM Project, under the Apache License v2.0 with LLVM          *|
+|* Exceptions.                                                                *|
+|* See https://llvm.org/LICENSE.txt for license information.                  *|
+|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception                    *|
+|*                                                                            *|
+|*===----------------------------------------------------------------------===*|
+|*                                                                            *|
+|* This file defines types used by the C interface to LLVM.                   *|
+|*                                                                            *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef LLVM_C_TYPES_H
+#define LLVM_C_TYPES_H
+
+#include "llvm-c/DataTypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup LLVMCSupportTypes Types and Enumerations
+ *
+ * @{
+ */
+
+typedef int LLVMBool;
+
+/* Opaque types. */
+
+/**
+ * LLVM uses a polymorphic type hierarchy which C cannot represent, therefore
+ * parameters must be passed as base types. Despite the declared types, most
+ * of the functions provided operate only on branches of the type hierarchy.
+ * The declared parameter names are descriptive and specify which type is
+ * required. Additionally, each type hierarchy is documented along with the
+ * functions that operate upon it. For more detail, refer to LLVM's C++ code.
+ * If in doubt, refer to Core.cpp, which performs parameter downcasts in the
+ * form unwrap<RequiredType>(Param).
+ */
+
+/**
+ * Used to pass regions of memory through LLVM interfaces.
+ *
+ * @see llvm::MemoryBuffer
+ */
+typedef struct LLVMOpaqueMemoryBuffer *LLVMMemoryBufferRef;
+
+/**
+ * The top-level container for all LLVM global data. See the LLVMContext class.
+ */
+typedef struct LLVMOpaqueContext *LLVMContextRef;
+
+/**
+ * The top-level container for all other LLVM Intermediate Representation (IR)
+ * objects.
+ *
+ * @see llvm::Module
+ */
+typedef struct LLVMOpaqueModule *LLVMModuleRef;
+
+/**
+ * Each value in the LLVM IR has a type, an LLVMTypeRef.
+ *
+ * @see llvm::Type
+ */
+typedef struct LLVMOpaqueType *LLVMTypeRef;
+
+/**
+ * Represents an individual value in LLVM IR.
+ *
+ * This models llvm::Value.
+ */
+typedef struct LLVMOpaqueValue *LLVMValueRef;
+
+/**
+ * Represents a basic block of instructions in LLVM IR.
+ *
+ * This models llvm::BasicBlock.
+ */
+typedef struct LLVMOpaqueBasicBlock *LLVMBasicBlockRef;
+
+/**
+ * Represents an LLVM Metadata.
+ *
+ * This models llvm::Metadata.
+ */
+typedef struct LLVMOpaqueMetadata *LLVMMetadataRef;
+
+/**
+ * Represents an LLVM Named Metadata Node.
+ *
+ * This models llvm::NamedMDNode.
+ */
+typedef struct LLVMOpaqueNamedMDNode *LLVMNamedMDNodeRef;
+
+/**
+ * Represents an entry in a Global Object's metadata attachments.
+ *
+ * This models std::pair<unsigned, MDNode *>
+ */
+typedef struct LLVMOpaqueValueMetadataEntry LLVMValueMetadataEntry;
+
+/**
+ * Represents an LLVM basic block builder.
+ *
+ * This models llvm::IRBuilder.
+ */
+typedef struct LLVMOpaqueBuilder *LLVMBuilderRef;
+
+/**
+ * Represents an LLVM debug info builder.
+ *
+ * This models llvm::DIBuilder.
+ */
+typedef struct LLVMOpaqueDIBuilder *LLVMDIBuilderRef;
+
+/**
+ * Interface used to provide a module to JIT or interpreter.
+ * This is now just a synonym for llvm::Module, but we have to keep using the
+ * different type to keep binary compatibility.
+ */
+typedef struct LLVMOpaqueModuleProvider *LLVMModuleProviderRef;
+
+/** @see llvm::PassManagerBase */
+typedef struct LLVMOpaquePassManager *LLVMPassManagerRef;
+
+/** @see llvm::PassRegistry */
+typedef struct LLVMOpaquePassRegistry *LLVMPassRegistryRef;
+
+/**
+ * Used to get the users and usees of a Value.
+ *
+ * @see llvm::Use */
+typedef struct LLVMOpaqueUse *LLVMUseRef;
+
+/**
+ * Used to represent an attributes.
+ *
+ * @see llvm::Attribute
+ */
+typedef struct LLVMOpaqueAttributeRef *LLVMAttributeRef;
+
+/**
+ * @see llvm::DiagnosticInfo
+ */
+typedef struct LLVMOpaqueDiagnosticInfo *LLVMDiagnosticInfoRef;
+
+/**
+ * @see llvm::Comdat
+ */
+typedef struct LLVMComdat *LLVMComdatRef;
+
+/**
+ * @see llvm::Module::ModuleFlagEntry
+ */
+typedef struct LLVMOpaqueModuleFlagEntry LLVMModuleFlagEntry;
+
+/**
+ * @see llvm::JITEventListener
+ */
+typedef struct LLVMOpaqueJITEventListener *LLVMJITEventListenerRef;
+
+/**
+ * @see llvm::object::Binary
+ */
+typedef struct LLVMOpaqueBinary *LLVMBinaryRef;
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/APFloat.h b/binaryen/third_party/llvm-project/include/llvm/ADT/APFloat.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/APFloat.h
@@ -0,0 +1,1290 @@
+//===- llvm/ADT/APFloat.h - Arbitrary Precision Floating Point ---*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief
+/// This file declares a class to represent arbitrary precision floating point
+/// values and provide a variety of arithmetic operations on them.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_APFLOAT_H
+#define LLVM_ADT_APFLOAT_H
+
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <memory>
+
+#define APFLOAT_DISPATCH_ON_SEMANTICS(METHOD_CALL)                             \
+  do {                                                                         \
+    if (usesLayout<IEEEFloat>(getSemantics()))                                 \
+      return U.IEEE.METHOD_CALL;                                               \
+    if (usesLayout<DoubleAPFloat>(getSemantics()))                             \
+      return U.Double.METHOD_CALL;                                             \
+    llvm_unreachable("Unexpected semantics");                                  \
+  } while (false)
+
+namespace llvm {
+
+struct fltSemantics;
+class APSInt;
+class StringRef;
+class APFloat;
+class raw_ostream;
+
+template <typename T> class SmallVectorImpl;
+
+/// Enum that represents what fraction of the LSB truncated bits of an fp number
+/// represent.
+///
+/// This essentially combines the roles of guard and sticky bits.
+enum lostFraction { // Example of truncated bits:
+  lfExactlyZero,    // 000000
+  lfLessThanHalf,   // 0xxxxx  x's not all zero
+  lfExactlyHalf,    // 100000
+  lfMoreThanHalf    // 1xxxxx  x's not all zero
+};
+
+/// A self-contained host- and target-independent arbitrary-precision
+/// floating-point software implementation.
+///
+/// APFloat uses bignum integer arithmetic as provided by static functions in
+/// the APInt class.  The library will work with bignum integers whose parts are
+/// any unsigned type at least 16 bits wide, but 64 bits is recommended.
+///
+/// Written for clarity rather than speed, in particular with a view to use in
+/// the front-end of a cross compiler so that target arithmetic can be correctly
+/// performed on the host.  Performance should nonetheless be reasonable,
+/// particularly for its intended use.  It may be useful as a base
+/// implementation for a run-time library during development of a faster
+/// target-specific one.
+///
+/// All 5 rounding modes in the IEEE-754R draft are handled correctly for all
+/// implemented operations.  Currently implemented operations are add, subtract,
+/// multiply, divide, fused-multiply-add, conversion-to-float,
+/// conversion-to-integer and conversion-from-integer.  New rounding modes
+/// (e.g. away from zero) can be added with three or four lines of code.
+///
+/// Four formats are built-in: IEEE single precision, double precision,
+/// quadruple precision, and x87 80-bit extended double (when operating with
+/// full extended precision).  Adding a new format that obeys IEEE semantics
+/// only requires adding two lines of code: a declaration and definition of the
+/// format.
+///
+/// All operations return the status of that operation as an exception bit-mask,
+/// so multiple operations can be done consecutively with their results or-ed
+/// together.  The returned status can be useful for compiler diagnostics; e.g.,
+/// inexact, underflow and overflow can be easily diagnosed on constant folding,
+/// and compiler optimizers can determine what exceptions would be raised by
+/// folding operations and optimize, or perhaps not optimize, accordingly.
+///
+/// At present, underflow tininess is detected after rounding; it should be
+/// straight forward to add support for the before-rounding case too.
+///
+/// The library reads hexadecimal floating point numbers as per C99, and
+/// correctly rounds if necessary according to the specified rounding mode.
+/// Syntax is required to have been validated by the caller.  It also converts
+/// floating point numbers to hexadecimal text as per the C99 %a and %A
+/// conversions.  The output precision (or alternatively the natural minimal
+/// precision) can be specified; if the requested precision is less than the
+/// natural precision the output is correctly rounded for the specified rounding
+/// mode.
+///
+/// It also reads decimal floating point numbers and correctly rounds according
+/// to the specified rounding mode.
+///
+/// Conversion to decimal text is not currently implemented.
+///
+/// Non-zero finite numbers are represented internally as a sign bit, a 16-bit
+/// signed exponent, and the significand as an array of integer parts.  After
+/// normalization of a number of precision P the exponent is within the range of
+/// the format, and if the number is not denormal the P-th bit of the
+/// significand is set as an explicit integer bit.  For denormals the most
+/// significant bit is shifted right so that the exponent is maintained at the
+/// format's minimum, so that the smallest denormal has just the least
+/// significant bit of the significand set.  The sign of zeroes and infinities
+/// is significant; the exponent and significand of such numbers is not stored,
+/// but has a known implicit (deterministic) value: 0 for the significands, 0
+/// for zero exponent, all 1 bits for infinity exponent.  For NaNs the sign and
+/// significand are deterministic, although not really meaningful, and preserved
+/// in non-conversion operations.  The exponent is implicitly all 1 bits.
+///
+/// APFloat does not provide any exception handling beyond default exception
+/// handling. We represent Signaling NaNs via IEEE-754R 2008 6.2.1 should clause
+/// by encoding Signaling NaNs with the first bit of its trailing significand as
+/// 0.
+///
+/// TODO
+/// ====
+///
+/// Some features that may or may not be worth adding:
+///
+/// Binary to decimal conversion (hard).
+///
+/// Optional ability to detect underflow tininess before rounding.
+///
+/// New formats: x87 in single and double precision mode (IEEE apart from
+/// extended exponent range) (hard).
+///
+/// New operations: sqrt, IEEE remainder, C90 fmod, nexttoward.
+///
+
+// This is the common type definitions shared by APFloat and its internal
+// implementation classes. This struct should not define any non-static data
+// members.
+struct APFloatBase {
+  typedef APInt::WordType integerPart;
+  static const unsigned integerPartWidth = APInt::APINT_BITS_PER_WORD;
+
+  /// A signed type to represent a floating point numbers unbiased exponent.
+  typedef signed short ExponentType;
+
+  /// \name Floating Point Semantics.
+  /// @{
+  enum Semantics {
+    S_IEEEhalf,
+    S_IEEEsingle,
+    S_IEEEdouble,
+    S_x87DoubleExtended,
+    S_IEEEquad,
+    S_PPCDoubleDouble
+  };
+
+  static const llvm::fltSemantics &EnumToSemantics(Semantics S);
+  static Semantics SemanticsToEnum(const llvm::fltSemantics &Sem);
+
+  static const fltSemantics &IEEEhalf() LLVM_READNONE;
+  static const fltSemantics &IEEEsingle() LLVM_READNONE;
+  static const fltSemantics &IEEEdouble() LLVM_READNONE;
+  static const fltSemantics &IEEEquad() LLVM_READNONE;
+  static const fltSemantics &PPCDoubleDouble() LLVM_READNONE;
+  static const fltSemantics &x87DoubleExtended() LLVM_READNONE;
+
+  /// A Pseudo fltsemantic used to construct APFloats that cannot conflict with
+  /// anything real.
+  static const fltSemantics &Bogus() LLVM_READNONE;
+
+  /// @}
+
+  /// IEEE-754R 5.11: Floating Point Comparison Relations.
+  enum cmpResult {
+    cmpLessThan,
+    cmpEqual,
+    cmpGreaterThan,
+    cmpUnordered
+  };
+
+  /// IEEE-754R 4.3: Rounding-direction attributes.
+  enum roundingMode {
+    rmNearestTiesToEven,
+    rmTowardPositive,
+    rmTowardNegative,
+    rmTowardZero,
+    rmNearestTiesToAway
+  };
+
+  /// IEEE-754R 7: Default exception handling.
+  ///
+  /// opUnderflow or opOverflow are always returned or-ed with opInexact.
+  ///
+  /// APFloat models this behavior specified by IEEE-754:
+  ///   "For operations producing results in floating-point format, the default
+  ///    result of an operation that signals the invalid operation exception
+  ///    shall be a quiet NaN."
+  enum opStatus {
+    opOK = 0x00,
+    opInvalidOp = 0x01,
+    opDivByZero = 0x02,
+    opOverflow = 0x04,
+    opUnderflow = 0x08,
+    opInexact = 0x10
+  };
+
+  /// Category of internally-represented number.
+  enum fltCategory {
+    fcInfinity,
+    fcNaN,
+    fcNormal,
+    fcZero
+  };
+
+  /// Convenience enum used to construct an uninitialized APFloat.
+  enum uninitializedTag {
+    uninitialized
+  };
+
+  /// Enumeration of \c ilogb error results.
+  enum IlogbErrorKinds {
+    IEK_Zero = INT_MIN + 1,
+    IEK_NaN = INT_MIN,
+    IEK_Inf = INT_MAX
+  };
+
+  static unsigned int semanticsPrecision(const fltSemantics &);
+  static ExponentType semanticsMinExponent(const fltSemantics &);
+  static ExponentType semanticsMaxExponent(const fltSemantics &);
+  static unsigned int semanticsSizeInBits(const fltSemantics &);
+
+  /// Returns the size of the floating point number (in bits) in the given
+  /// semantics.
+  static unsigned getSizeInBits(const fltSemantics &Sem);
+};
+
+namespace detail {
+
+class IEEEFloat final : public APFloatBase {
+public:
+  /// \name Constructors
+  /// @{
+
+  IEEEFloat(const fltSemantics &); // Default construct to 0.0
+  IEEEFloat(const fltSemantics &, integerPart);
+  IEEEFloat(const fltSemantics &, uninitializedTag);
+  IEEEFloat(const fltSemantics &, const APInt &);
+  explicit IEEEFloat(double d);
+  explicit IEEEFloat(float f);
+  IEEEFloat(const IEEEFloat &);
+  IEEEFloat(IEEEFloat &&);
+  ~IEEEFloat();
+
+  /// @}
+
+  /// Returns whether this instance allocated memory.
+  bool needsCleanup() const { return partCount() > 1; }
+
+  /// \name Convenience "constructors"
+  /// @{
+
+  /// @}
+
+  /// \name Arithmetic
+  /// @{
+
+  opStatus add(const IEEEFloat &, roundingMode);
+  opStatus subtract(const IEEEFloat &, roundingMode);
+  opStatus multiply(const IEEEFloat &, roundingMode);
+  opStatus divide(const IEEEFloat &, roundingMode);
+  /// IEEE remainder.
+  opStatus remainder(const IEEEFloat &);
+  /// C fmod, or llvm frem.
+  opStatus mod(const IEEEFloat &);
+  opStatus fusedMultiplyAdd(const IEEEFloat &, const IEEEFloat &, roundingMode);
+  opStatus roundToIntegral(roundingMode);
+  /// IEEE-754R 5.3.1: nextUp/nextDown.
+  opStatus next(bool nextDown);
+
+  /// @}
+
+  /// \name Sign operations.
+  /// @{
+
+  void changeSign();
+
+  /// @}
+
+  /// \name Conversions
+  /// @{
+
+  opStatus convert(const fltSemantics &, roundingMode, bool *);
+  opStatus convertToInteger(MutableArrayRef<integerPart>, unsigned int, bool,
+                            roundingMode, bool *) const;
+  opStatus convertFromAPInt(const APInt &, bool, roundingMode);
+  opStatus convertFromSignExtendedInteger(const integerPart *, unsigned int,
+                                          bool, roundingMode);
+  opStatus convertFromZeroExtendedInteger(const integerPart *, unsigned int,
+                                          bool, roundingMode);
+  opStatus convertFromString(StringRef, roundingMode);
+  APInt bitcastToAPInt() const;
+  double convertToDouble() const;
+  float convertToFloat() const;
+
+  /// @}
+
+  /// The definition of equality is not straightforward for floating point, so
+  /// we won't use operator==.  Use one of the following, or write whatever it
+  /// is you really mean.
+  bool operator==(const IEEEFloat &) const = delete;
+
+  /// IEEE comparison with another floating point number (NaNs compare
+  /// unordered, 0==-0).
+  cmpResult compare(const IEEEFloat &) const;
+
+  /// Bitwise comparison for equality (QNaNs compare equal, 0!=-0).
+  bool bitwiseIsEqual(const IEEEFloat &) const;
+
+  /// Write out a hexadecimal representation of the floating point value to DST,
+  /// which must be of sufficient size, in the C99 form [-]0xh.hhhhp[+-]d.
+  /// Return the number of characters written, excluding the terminating NUL.
+  unsigned int convertToHexString(char *dst, unsigned int hexDigits,
+                                  bool upperCase, roundingMode) const;
+
+  /// \name IEEE-754R 5.7.2 General operations.
+  /// @{
+
+  /// IEEE-754R isSignMinus: Returns true if and only if the current value is
+  /// negative.
+  ///
+  /// This applies to zeros and NaNs as well.
+  bool isNegative() const { return sign; }
+
+  /// IEEE-754R isNormal: Returns true if and only if the current value is normal.
+  ///
+  /// This implies that the current value of the float is not zero, subnormal,
+  /// infinite, or NaN following the definition of normality from IEEE-754R.
+  bool isNormal() const { return !isDenormal() && isFiniteNonZero(); }
+
+  /// Returns true if and only if the current value is zero, subnormal, or
+  /// normal.
+  ///
+  /// This means that the value is not infinite or NaN.
+  bool isFinite() const { return !isNaN() && !isInfinity(); }
+
+  /// Returns true if and only if the float is plus or minus zero.
+  bool isZero() const { return category == fcZero; }
+
+  /// IEEE-754R isSubnormal(): Returns true if and only if the float is a
+  /// denormal.
+  bool isDenormal() const;
+
+  /// IEEE-754R isInfinite(): Returns true if and only if the float is infinity.
+  bool isInfinity() const { return category == fcInfinity; }
+
+  /// Returns true if and only if the float is a quiet or signaling NaN.
+  bool isNaN() const { return category == fcNaN; }
+
+  /// Returns true if and only if the float is a signaling NaN.
+  bool isSignaling() const;
+
+  /// @}
+
+  /// \name Simple Queries
+  /// @{
+
+  fltCategory getCategory() const { return category; }
+  const fltSemantics &getSemantics() const { return *semantics; }
+  bool isNonZero() const { return category != fcZero; }
+  bool isFiniteNonZero() const { return isFinite() && !isZero(); }
+  bool isPosZero() const { return isZero() && !isNegative(); }
+  bool isNegZero() const { return isZero() && isNegative(); }
+
+  /// Returns true if and only if the number has the smallest possible non-zero
+  /// magnitude in the current semantics.
+  bool isSmallest() const;
+
+  /// Returns true if and only if the number has the largest possible finite
+  /// magnitude in the current semantics.
+  bool isLargest() const;
+
+  /// Returns true if and only if the number is an exact integer.
+  bool isInteger() const;
+
+  /// @}
+
+  IEEEFloat &operator=(const IEEEFloat &);
+  IEEEFloat &operator=(IEEEFloat &&);
+
+  /// Overload to compute a hash code for an APFloat value.
+  ///
+  /// Note that the use of hash codes for floating point values is in general
+  /// frought with peril. Equality is hard to define for these values. For
+  /// example, should negative and positive zero hash to different codes? Are
+  /// they equal or not? This hash value implementation specifically
+  /// emphasizes producing different codes for different inputs in order to
+  /// be used in canonicalization and memoization. As such, equality is
+  /// bitwiseIsEqual, and 0 != -0.
+  friend hash_code hash_value(const IEEEFloat &Arg);
+
+  /// Converts this value into a decimal string.
+  ///
+  /// \param FormatPrecision The maximum number of digits of
+  ///   precision to output.  If there are fewer digits available,
+  ///   zero padding will not be used unless the value is
+  ///   integral and small enough to be expressed in
+  ///   FormatPrecision digits.  0 means to use the natural
+  ///   precision of the number.
+  /// \param FormatMaxPadding The maximum number of zeros to
+  ///   consider inserting before falling back to scientific
+  ///   notation.  0 means to always use scientific notation.
+  ///
+  /// \param TruncateZero Indicate whether to remove the trailing zero in
+  ///   fraction part or not. Also setting this parameter to false forcing
+  ///   producing of output more similar to default printf behavior.
+  ///   Specifically the lower e is used as exponent delimiter and exponent
+  ///   always contains no less than two digits.
+  ///
+  /// Number       Precision    MaxPadding      Result
+  /// ------       ---------    ----------      ------
+  /// 1.01E+4              5             2       10100
+  /// 1.01E+4              4             2       1.01E+4
+  /// 1.01E+4              5             1       1.01E+4
+  /// 1.01E-2              5             2       0.0101
+  /// 1.01E-2              4             2       0.0101
+  /// 1.01E-2              4             1       1.01E-2
+  void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision = 0,
+                unsigned FormatMaxPadding = 3, bool TruncateZero = true) const;
+
+  /// If this value has an exact multiplicative inverse, store it in inv and
+  /// return true.
+  bool getExactInverse(APFloat *inv) const;
+
+  /// Returns the exponent of the internal representation of the APFloat.
+  ///
+  /// Because the radix of APFloat is 2, this is equivalent to floor(log2(x)).
+  /// For special APFloat values, this returns special error codes:
+  ///
+  ///   NaN -> \c IEK_NaN
+  ///   0   -> \c IEK_Zero
+  ///   Inf -> \c IEK_Inf
+  ///
+  friend int ilogb(const IEEEFloat &Arg);
+
+  /// Returns: X * 2^Exp for integral exponents.
+  friend IEEEFloat scalbn(IEEEFloat X, int Exp, roundingMode);
+
+  friend IEEEFloat frexp(const IEEEFloat &X, int &Exp, roundingMode);
+
+  /// \name Special value setters.
+  /// @{
+
+  void makeLargest(bool Neg = false);
+  void makeSmallest(bool Neg = false);
+  void makeNaN(bool SNaN = false, bool Neg = false,
+               const APInt *fill = nullptr);
+  void makeInf(bool Neg = false);
+  void makeZero(bool Neg = false);
+  void makeQuiet();
+
+  /// Returns the smallest (by magnitude) normalized finite number in the given
+  /// semantics.
+  ///
+  /// \param Negative - True iff the number should be negative
+  void makeSmallestNormalized(bool Negative = false);
+
+  /// @}
+
+  cmpResult compareAbsoluteValue(const IEEEFloat &) const;
+
+private:
+  /// \name Simple Queries
+  /// @{
+
+  integerPart *significandParts();
+  const integerPart *significandParts() const;
+  unsigned int partCount() const;
+
+  /// @}
+
+  /// \name Significand operations.
+  /// @{
+
+  integerPart addSignificand(const IEEEFloat &);
+  integerPart subtractSignificand(const IEEEFloat &, integerPart);
+  lostFraction addOrSubtractSignificand(const IEEEFloat &, bool subtract);
+  lostFraction multiplySignificand(const IEEEFloat &, const IEEEFloat *);
+  lostFraction divideSignificand(const IEEEFloat &);
+  void incrementSignificand();
+  void initialize(const fltSemantics *);
+  void shiftSignificandLeft(unsigned int);
+  lostFraction shiftSignificandRight(unsigned int);
+  unsigned int significandLSB() const;
+  unsigned int significandMSB() const;
+  void zeroSignificand();
+  /// Return true if the significand excluding the integral bit is all ones.
+  bool isSignificandAllOnes() const;
+  /// Return true if the significand excluding the integral bit is all zeros.
+  bool isSignificandAllZeros() const;
+
+  /// @}
+
+  /// \name Arithmetic on special values.
+  /// @{
+
+  opStatus addOrSubtractSpecials(const IEEEFloat &, bool subtract);
+  opStatus divideSpecials(const IEEEFloat &);
+  opStatus multiplySpecials(const IEEEFloat &);
+  opStatus modSpecials(const IEEEFloat &);
+
+  /// @}
+
+  /// \name Miscellany
+  /// @{
+
+  bool convertFromStringSpecials(StringRef str);
+  opStatus normalize(roundingMode, lostFraction);
+  opStatus addOrSubtract(const IEEEFloat &, roundingMode, bool subtract);
+  opStatus handleOverflow(roundingMode);
+  bool roundAwayFromZero(roundingMode, lostFraction, unsigned int) const;
+  opStatus convertToSignExtendedInteger(MutableArrayRef<integerPart>,
+                                        unsigned int, bool, roundingMode,
+                                        bool *) const;
+  opStatus convertFromUnsignedParts(const integerPart *, unsigned int,
+                                    roundingMode);
+  opStatus convertFromHexadecimalString(StringRef, roundingMode);
+  opStatus convertFromDecimalString(StringRef, roundingMode);
+  char *convertNormalToHexString(char *, unsigned int, bool,
+                                 roundingMode) const;
+  opStatus roundSignificandWithExponent(const integerPart *, unsigned int, int,
+                                        roundingMode);
+
+  /// @}
+
+  APInt convertHalfAPFloatToAPInt() const;
+  APInt convertFloatAPFloatToAPInt() const;
+  APInt convertDoubleAPFloatToAPInt() const;
+  APInt convertQuadrupleAPFloatToAPInt() const;
+  APInt convertF80LongDoubleAPFloatToAPInt() const;
+  APInt convertPPCDoubleDoubleAPFloatToAPInt() const;
+  void initFromAPInt(const fltSemantics *Sem, const APInt &api);
+  void initFromHalfAPInt(const APInt &api);
+  void initFromFloatAPInt(const APInt &api);
+  void initFromDoubleAPInt(const APInt &api);
+  void initFromQuadrupleAPInt(const APInt &api);
+  void initFromF80LongDoubleAPInt(const APInt &api);
+  void initFromPPCDoubleDoubleAPInt(const APInt &api);
+
+  void assign(const IEEEFloat &);
+  void copySignificand(const IEEEFloat &);
+  void freeSignificand();
+
+  /// Note: this must be the first data member.
+  /// The semantics that this value obeys.
+  const fltSemantics *semantics;
+
+  /// A binary fraction with an explicit integer bit.
+  ///
+  /// The significand must be at least one bit wider than the target precision.
+  union Significand {
+    integerPart part;
+    integerPart *parts;
+  } significand;
+
+  /// The signed unbiased exponent of the value.
+  ExponentType exponent;
+
+  /// What kind of floating point number this is.
+  ///
+  /// Only 2 bits are required, but VisualStudio incorrectly sign extends it.
+  /// Using the extra bit keeps it from failing under VisualStudio.
+  fltCategory category : 3;
+
+  /// Sign bit of the number.
+  unsigned int sign : 1;
+};
+
+hash_code hash_value(const IEEEFloat &Arg);
+int ilogb(const IEEEFloat &Arg);
+IEEEFloat scalbn(IEEEFloat X, int Exp, IEEEFloat::roundingMode);
+IEEEFloat frexp(const IEEEFloat &Val, int &Exp, IEEEFloat::roundingMode RM);
+
+// This mode implements more precise float in terms of two APFloats.
+// The interface and layout is designed for arbitray underlying semantics,
+// though currently only PPCDoubleDouble semantics are supported, whose
+// corresponding underlying semantics are IEEEdouble.
+class DoubleAPFloat final : public APFloatBase {
+  // Note: this must be the first data member.
+  const fltSemantics *Semantics;
+  std::unique_ptr<APFloat[]> Floats;
+
+  opStatus addImpl(const APFloat &a, const APFloat &aa, const APFloat &c,
+                   const APFloat &cc, roundingMode RM);
+
+  opStatus addWithSpecial(const DoubleAPFloat &LHS, const DoubleAPFloat &RHS,
+                          DoubleAPFloat &Out, roundingMode RM);
+
+public:
+  DoubleAPFloat(const fltSemantics &S);
+  DoubleAPFloat(const fltSemantics &S, uninitializedTag);
+  DoubleAPFloat(const fltSemantics &S, integerPart);
+  DoubleAPFloat(const fltSemantics &S, const APInt &I);
+  DoubleAPFloat(const fltSemantics &S, APFloat &&First, APFloat &&Second);
+  DoubleAPFloat(const DoubleAPFloat &RHS);
+  DoubleAPFloat(DoubleAPFloat &&RHS);
+
+  DoubleAPFloat &operator=(const DoubleAPFloat &RHS);
+
+  DoubleAPFloat &operator=(DoubleAPFloat &&RHS) {
+    if (this != &RHS) {
+      this->~DoubleAPFloat();
+      new (this) DoubleAPFloat(std::move(RHS));
+    }
+    return *this;
+  }
+
+  bool needsCleanup() const { return Floats != nullptr; }
+
+  APFloat &getFirst() { return Floats[0]; }
+  const APFloat &getFirst() const { return Floats[0]; }
+  APFloat &getSecond() { return Floats[1]; }
+  const APFloat &getSecond() const { return Floats[1]; }
+
+  opStatus add(const DoubleAPFloat &RHS, roundingMode RM);
+  opStatus subtract(const DoubleAPFloat &RHS, roundingMode RM);
+  opStatus multiply(const DoubleAPFloat &RHS, roundingMode RM);
+  opStatus divide(const DoubleAPFloat &RHS, roundingMode RM);
+  opStatus remainder(const DoubleAPFloat &RHS);
+  opStatus mod(const DoubleAPFloat &RHS);
+  opStatus fusedMultiplyAdd(const DoubleAPFloat &Multiplicand,
+                            const DoubleAPFloat &Addend, roundingMode RM);
+  opStatus roundToIntegral(roundingMode RM);
+  void changeSign();
+  cmpResult compareAbsoluteValue(const DoubleAPFloat &RHS) const;
+
+  fltCategory getCategory() const;
+  bool isNegative() const;
+
+  void makeInf(bool Neg);
+  void makeZero(bool Neg);
+  void makeLargest(bool Neg);
+  void makeSmallest(bool Neg);
+  void makeSmallestNormalized(bool Neg);
+  void makeNaN(bool SNaN, bool Neg, const APInt *fill);
+
+  cmpResult compare(const DoubleAPFloat &RHS) const;
+  bool bitwiseIsEqual(const DoubleAPFloat &RHS) const;
+  APInt bitcastToAPInt() const;
+  opStatus convertFromString(StringRef, roundingMode);
+  opStatus next(bool nextDown);
+
+  opStatus convertToInteger(MutableArrayRef<integerPart> Input,
+                            unsigned int Width, bool IsSigned, roundingMode RM,
+                            bool *IsExact) const;
+  opStatus convertFromAPInt(const APInt &Input, bool IsSigned, roundingMode RM);
+  opStatus convertFromSignExtendedInteger(const integerPart *Input,
+                                          unsigned int InputSize, bool IsSigned,
+                                          roundingMode RM);
+  opStatus convertFromZeroExtendedInteger(const integerPart *Input,
+                                          unsigned int InputSize, bool IsSigned,
+                                          roundingMode RM);
+  unsigned int convertToHexString(char *DST, unsigned int HexDigits,
+                                  bool UpperCase, roundingMode RM) const;
+
+  bool isDenormal() const;
+  bool isSmallest() const;
+  bool isLargest() const;
+  bool isInteger() const;
+
+  void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision,
+                unsigned FormatMaxPadding, bool TruncateZero = true) const;
+
+  bool getExactInverse(APFloat *inv) const;
+
+  friend int ilogb(const DoubleAPFloat &Arg);
+  friend DoubleAPFloat scalbn(DoubleAPFloat X, int Exp, roundingMode);
+  friend DoubleAPFloat frexp(const DoubleAPFloat &X, int &Exp, roundingMode);
+  friend hash_code hash_value(const DoubleAPFloat &Arg);
+};
+
+hash_code hash_value(const DoubleAPFloat &Arg);
+
+} // End detail namespace
+
+// This is a interface class that is currently forwarding functionalities from
+// detail::IEEEFloat.
+class APFloat : public APFloatBase {
+  typedef detail::IEEEFloat IEEEFloat;
+  typedef detail::DoubleAPFloat DoubleAPFloat;
+
+  static_assert(std::is_standard_layout<IEEEFloat>::value, "");
+
+  union Storage {
+    const fltSemantics *semantics;
+    IEEEFloat IEEE;
+    DoubleAPFloat Double;
+
+    explicit Storage(IEEEFloat F, const fltSemantics &S);
+    explicit Storage(DoubleAPFloat F, const fltSemantics &S)
+        : Double(std::move(F)) {
+      assert(&S == &PPCDoubleDouble());
+    }
+
+    template <typename... ArgTypes>
+    Storage(const fltSemantics &Semantics, ArgTypes &&... Args) {
+      if (usesLayout<IEEEFloat>(Semantics)) {
+        new (&IEEE) IEEEFloat(Semantics, std::forward<ArgTypes>(Args)...);
+        return;
+      }
+      if (usesLayout<DoubleAPFloat>(Semantics)) {
+        new (&Double) DoubleAPFloat(Semantics, std::forward<ArgTypes>(Args)...);
+        return;
+      }
+      llvm_unreachable("Unexpected semantics");
+    }
+
+    ~Storage() {
+      if (usesLayout<IEEEFloat>(*semantics)) {
+        IEEE.~IEEEFloat();
+        return;
+      }
+      if (usesLayout<DoubleAPFloat>(*semantics)) {
+        Double.~DoubleAPFloat();
+        return;
+      }
+      llvm_unreachable("Unexpected semantics");
+    }
+
+    Storage(const Storage &RHS) {
+      if (usesLayout<IEEEFloat>(*RHS.semantics)) {
+        new (this) IEEEFloat(RHS.IEEE);
+        return;
+      }
+      if (usesLayout<DoubleAPFloat>(*RHS.semantics)) {
+        new (this) DoubleAPFloat(RHS.Double);
+        return;
+      }
+      llvm_unreachable("Unexpected semantics");
+    }
+
+    Storage(Storage &&RHS) {
+      if (usesLayout<IEEEFloat>(*RHS.semantics)) {
+        new (this) IEEEFloat(std::move(RHS.IEEE));
+        return;
+      }
+      if (usesLayout<DoubleAPFloat>(*RHS.semantics)) {
+        new (this) DoubleAPFloat(std::move(RHS.Double));
+        return;
+      }
+      llvm_unreachable("Unexpected semantics");
+    }
+
+    Storage &operator=(const Storage &RHS) {
+      if (usesLayout<IEEEFloat>(*semantics) &&
+          usesLayout<IEEEFloat>(*RHS.semantics)) {
+        IEEE = RHS.IEEE;
+      } else if (usesLayout<DoubleAPFloat>(*semantics) &&
+                 usesLayout<DoubleAPFloat>(*RHS.semantics)) {
+        Double = RHS.Double;
+      } else if (this != &RHS) {
+        this->~Storage();
+        new (this) Storage(RHS);
+      }
+      return *this;
+    }
+
+    Storage &operator=(Storage &&RHS) {
+      if (usesLayout<IEEEFloat>(*semantics) &&
+          usesLayout<IEEEFloat>(*RHS.semantics)) {
+        IEEE = std::move(RHS.IEEE);
+      } else if (usesLayout<DoubleAPFloat>(*semantics) &&
+                 usesLayout<DoubleAPFloat>(*RHS.semantics)) {
+        Double = std::move(RHS.Double);
+      } else if (this != &RHS) {
+        this->~Storage();
+        new (this) Storage(std::move(RHS));
+      }
+      return *this;
+    }
+  } U;
+
+  template <typename T> static bool usesLayout(const fltSemantics &Semantics) {
+    static_assert(std::is_same<T, IEEEFloat>::value ||
+                  std::is_same<T, DoubleAPFloat>::value, "");
+    if (std::is_same<T, DoubleAPFloat>::value) {
+      return &Semantics == &PPCDoubleDouble();
+    }
+    return &Semantics != &PPCDoubleDouble();
+  }
+
+  IEEEFloat &getIEEE() {
+    if (usesLayout<IEEEFloat>(*U.semantics))
+      return U.IEEE;
+    if (usesLayout<DoubleAPFloat>(*U.semantics))
+      return U.Double.getFirst().U.IEEE;
+    llvm_unreachable("Unexpected semantics");
+  }
+
+  const IEEEFloat &getIEEE() const {
+    if (usesLayout<IEEEFloat>(*U.semantics))
+      return U.IEEE;
+    if (usesLayout<DoubleAPFloat>(*U.semantics))
+      return U.Double.getFirst().U.IEEE;
+    llvm_unreachable("Unexpected semantics");
+  }
+
+  void makeZero(bool Neg) { APFLOAT_DISPATCH_ON_SEMANTICS(makeZero(Neg)); }
+
+  void makeInf(bool Neg) { APFLOAT_DISPATCH_ON_SEMANTICS(makeInf(Neg)); }
+
+  void makeNaN(bool SNaN, bool Neg, const APInt *fill) {
+    APFLOAT_DISPATCH_ON_SEMANTICS(makeNaN(SNaN, Neg, fill));
+  }
+
+  void makeLargest(bool Neg) {
+    APFLOAT_DISPATCH_ON_SEMANTICS(makeLargest(Neg));
+  }
+
+  void makeSmallest(bool Neg) {
+    APFLOAT_DISPATCH_ON_SEMANTICS(makeSmallest(Neg));
+  }
+
+  void makeSmallestNormalized(bool Neg) {
+    APFLOAT_DISPATCH_ON_SEMANTICS(makeSmallestNormalized(Neg));
+  }
+
+  // FIXME: This is due to clang 3.3 (or older version) always checks for the
+  // default constructor in an array aggregate initialization, even if no
+  // elements in the array is default initialized.
+  APFloat() : U(IEEEdouble()) {
+    llvm_unreachable("This is a workaround for old clang.");
+  }
+
+  explicit APFloat(IEEEFloat F, const fltSemantics &S) : U(std::move(F), S) {}
+  explicit APFloat(DoubleAPFloat F, const fltSemantics &S)
+      : U(std::move(F), S) {}
+
+  cmpResult compareAbsoluteValue(const APFloat &RHS) const {
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only compare APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.compareAbsoluteValue(RHS.U.IEEE);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.compareAbsoluteValue(RHS.U.Double);
+    llvm_unreachable("Unexpected semantics");
+  }
+
+public:
+  APFloat(const fltSemantics &Semantics) : U(Semantics) {}
+  APFloat(const fltSemantics &Semantics, StringRef S);
+  APFloat(const fltSemantics &Semantics, integerPart I) : U(Semantics, I) {}
+  // TODO: Remove this constructor. This isn't faster than the first one.
+  APFloat(const fltSemantics &Semantics, uninitializedTag)
+      : U(Semantics, uninitialized) {}
+  APFloat(const fltSemantics &Semantics, const APInt &I) : U(Semantics, I) {}
+  explicit APFloat(double d) : U(IEEEFloat(d), IEEEdouble()) {}
+  explicit APFloat(float f) : U(IEEEFloat(f), IEEEsingle()) {}
+  APFloat(const APFloat &RHS) = default;
+  APFloat(APFloat &&RHS) = default;
+
+  ~APFloat() = default;
+
+  bool needsCleanup() const { APFLOAT_DISPATCH_ON_SEMANTICS(needsCleanup()); }
+
+  /// Factory for Positive and Negative Zero.
+  ///
+  /// \param Negative True iff the number should be negative.
+  static APFloat getZero(const fltSemantics &Sem, bool Negative = false) {
+    APFloat Val(Sem, uninitialized);
+    Val.makeZero(Negative);
+    return Val;
+  }
+
+  /// Factory for Positive and Negative Infinity.
+  ///
+  /// \param Negative True iff the number should be negative.
+  static APFloat getInf(const fltSemantics &Sem, bool Negative = false) {
+    APFloat Val(Sem, uninitialized);
+    Val.makeInf(Negative);
+    return Val;
+  }
+
+  /// Factory for NaN values.
+  ///
+  /// \param Negative - True iff the NaN generated should be negative.
+  /// \param payload - The unspecified fill bits for creating the NaN, 0 by
+  /// default.  The value is truncated as necessary.
+  static APFloat getNaN(const fltSemantics &Sem, bool Negative = false,
+                        uint64_t payload = 0) {
+    if (payload) {
+      APInt intPayload(64, payload);
+      return getQNaN(Sem, Negative, &intPayload);
+    } else {
+      return getQNaN(Sem, Negative, nullptr);
+    }
+  }
+
+  /// Factory for QNaN values.
+  static APFloat getQNaN(const fltSemantics &Sem, bool Negative = false,
+                         const APInt *payload = nullptr) {
+    APFloat Val(Sem, uninitialized);
+    Val.makeNaN(false, Negative, payload);
+    return Val;
+  }
+
+  /// Factory for SNaN values.
+  static APFloat getSNaN(const fltSemantics &Sem, bool Negative = false,
+                         const APInt *payload = nullptr) {
+    APFloat Val(Sem, uninitialized);
+    Val.makeNaN(true, Negative, payload);
+    return Val;
+  }
+
+  /// Returns the largest finite number in the given semantics.
+  ///
+  /// \param Negative - True iff the number should be negative
+  static APFloat getLargest(const fltSemantics &Sem, bool Negative = false) {
+    APFloat Val(Sem, uninitialized);
+    Val.makeLargest(Negative);
+    return Val;
+  }
+
+  /// Returns the smallest (by magnitude) finite number in the given semantics.
+  /// Might be denormalized, which implies a relative loss of precision.
+  ///
+  /// \param Negative - True iff the number should be negative
+  static APFloat getSmallest(const fltSemantics &Sem, bool Negative = false) {
+    APFloat Val(Sem, uninitialized);
+    Val.makeSmallest(Negative);
+    return Val;
+  }
+
+  /// Returns the smallest (by magnitude) normalized finite number in the given
+  /// semantics.
+  ///
+  /// \param Negative - True iff the number should be negative
+  static APFloat getSmallestNormalized(const fltSemantics &Sem,
+                                       bool Negative = false) {
+    APFloat Val(Sem, uninitialized);
+    Val.makeSmallestNormalized(Negative);
+    return Val;
+  }
+
+  /// Returns a float which is bitcasted from an all one value int.
+  ///
+  /// \param BitWidth - Select float type
+  /// \param isIEEE   - If 128 bit number, select between PPC and IEEE
+  static APFloat getAllOnesValue(unsigned BitWidth, bool isIEEE = false);
+
+  /// Used to insert APFloat objects, or objects that contain APFloat objects,
+  /// into FoldingSets.
+  void Profile(FoldingSetNodeID &NID) const;
+
+  opStatus add(const APFloat &RHS, roundingMode RM) {
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.add(RHS.U.IEEE, RM);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.add(RHS.U.Double, RM);
+    llvm_unreachable("Unexpected semantics");
+  }
+  opStatus subtract(const APFloat &RHS, roundingMode RM) {
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.subtract(RHS.U.IEEE, RM);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.subtract(RHS.U.Double, RM);
+    llvm_unreachable("Unexpected semantics");
+  }
+  opStatus multiply(const APFloat &RHS, roundingMode RM) {
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.multiply(RHS.U.IEEE, RM);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.multiply(RHS.U.Double, RM);
+    llvm_unreachable("Unexpected semantics");
+  }
+  opStatus divide(const APFloat &RHS, roundingMode RM) {
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.divide(RHS.U.IEEE, RM);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.divide(RHS.U.Double, RM);
+    llvm_unreachable("Unexpected semantics");
+  }
+  opStatus remainder(const APFloat &RHS) {
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.remainder(RHS.U.IEEE);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.remainder(RHS.U.Double);
+    llvm_unreachable("Unexpected semantics");
+  }
+  opStatus mod(const APFloat &RHS) {
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.mod(RHS.U.IEEE);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.mod(RHS.U.Double);
+    llvm_unreachable("Unexpected semantics");
+  }
+  opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend,
+                            roundingMode RM) {
+    assert(&getSemantics() == &Multiplicand.getSemantics() &&
+           "Should only call on APFloats with the same semantics");
+    assert(&getSemantics() == &Addend.getSemantics() &&
+           "Should only call on APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.fusedMultiplyAdd(Multiplicand.U.IEEE, Addend.U.IEEE, RM);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.fusedMultiplyAdd(Multiplicand.U.Double, Addend.U.Double,
+                                       RM);
+    llvm_unreachable("Unexpected semantics");
+  }
+  opStatus roundToIntegral(roundingMode RM) {
+    APFLOAT_DISPATCH_ON_SEMANTICS(roundToIntegral(RM));
+  }
+
+  // TODO: bool parameters are not readable and a source of bugs.
+  // Do something.
+  opStatus next(bool nextDown) {
+    APFLOAT_DISPATCH_ON_SEMANTICS(next(nextDown));
+  }
+
+  /// Add two APFloats, rounding ties to the nearest even.
+  /// No error checking.
+  APFloat operator+(const APFloat &RHS) const {
+    APFloat Result(*this);
+    (void)Result.add(RHS, rmNearestTiesToEven);
+    return Result;
+  }
+
+  /// Subtract two APFloats, rounding ties to the nearest even.
+  /// No error checking.
+  APFloat operator-(const APFloat &RHS) const {
+    APFloat Result(*this);
+    (void)Result.subtract(RHS, rmNearestTiesToEven);
+    return Result;
+  }
+
+  /// Multiply two APFloats, rounding ties to the nearest even.
+  /// No error checking.
+  APFloat operator*(const APFloat &RHS) const {
+    APFloat Result(*this);
+    (void)Result.multiply(RHS, rmNearestTiesToEven);
+    return Result;
+  }
+
+  /// Divide the first APFloat by the second, rounding ties to the nearest even.
+  /// No error checking.
+  APFloat operator/(const APFloat &RHS) const {
+    APFloat Result(*this);
+    (void)Result.divide(RHS, rmNearestTiesToEven);
+    return Result;
+  }
+
+  void changeSign() { APFLOAT_DISPATCH_ON_SEMANTICS(changeSign()); }
+  void clearSign() {
+    if (isNegative())
+      changeSign();
+  }
+  void copySign(const APFloat &RHS) {
+    if (isNegative() != RHS.isNegative())
+      changeSign();
+  }
+
+  /// A static helper to produce a copy of an APFloat value with its sign
+  /// copied from some other APFloat.
+  static APFloat copySign(APFloat Value, const APFloat &Sign) {
+    Value.copySign(Sign);
+    return Value;
+  }
+
+  opStatus convert(const fltSemantics &ToSemantics, roundingMode RM,
+                   bool *losesInfo);
+  opStatus convertToInteger(MutableArrayRef<integerPart> Input,
+                            unsigned int Width, bool IsSigned, roundingMode RM,
+                            bool *IsExact) const {
+    APFLOAT_DISPATCH_ON_SEMANTICS(
+        convertToInteger(Input, Width, IsSigned, RM, IsExact));
+  }
+  opStatus convertToInteger(APSInt &Result, roundingMode RM,
+                            bool *IsExact) const;
+  opStatus convertFromAPInt(const APInt &Input, bool IsSigned,
+                            roundingMode RM) {
+    APFLOAT_DISPATCH_ON_SEMANTICS(convertFromAPInt(Input, IsSigned, RM));
+  }
+  opStatus convertFromSignExtendedInteger(const integerPart *Input,
+                                          unsigned int InputSize, bool IsSigned,
+                                          roundingMode RM) {
+    APFLOAT_DISPATCH_ON_SEMANTICS(
+        convertFromSignExtendedInteger(Input, InputSize, IsSigned, RM));
+  }
+  opStatus convertFromZeroExtendedInteger(const integerPart *Input,
+                                          unsigned int InputSize, bool IsSigned,
+                                          roundingMode RM) {
+    APFLOAT_DISPATCH_ON_SEMANTICS(
+        convertFromZeroExtendedInteger(Input, InputSize, IsSigned, RM));
+  }
+  opStatus convertFromString(StringRef, roundingMode);
+  APInt bitcastToAPInt() const {
+    APFLOAT_DISPATCH_ON_SEMANTICS(bitcastToAPInt());
+  }
+  double convertToDouble() const { return getIEEE().convertToDouble(); }
+  float convertToFloat() const { return getIEEE().convertToFloat(); }
+
+  bool operator==(const APFloat &) const = delete;
+
+  cmpResult compare(const APFloat &RHS) const {
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only compare APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.compare(RHS.U.IEEE);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.compare(RHS.U.Double);
+    llvm_unreachable("Unexpected semantics");
+  }
+
+  bool bitwiseIsEqual(const APFloat &RHS) const {
+    if (&getSemantics() != &RHS.getSemantics())
+      return false;
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.bitwiseIsEqual(RHS.U.IEEE);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.bitwiseIsEqual(RHS.U.Double);
+    llvm_unreachable("Unexpected semantics");
+  }
+
+  /// We don't rely on operator== working on double values, as
+  /// it returns true for things that are clearly not equal, like -0.0 and 0.0.
+  /// As such, this method can be used to do an exact bit-for-bit comparison of
+  /// two floating point values.
+  ///
+  /// We leave the version with the double argument here because it's just so
+  /// convenient to write "2.0" and the like.  Without this function we'd
+  /// have to duplicate its logic everywhere it's called.
+  bool isExactlyValue(double V) const {
+    bool ignored;
+    APFloat Tmp(V);
+    Tmp.convert(getSemantics(), APFloat::rmNearestTiesToEven, &ignored);
+    return bitwiseIsEqual(Tmp);
+  }
+
+  unsigned int convertToHexString(char *DST, unsigned int HexDigits,
+                                  bool UpperCase, roundingMode RM) const {
+    APFLOAT_DISPATCH_ON_SEMANTICS(
+        convertToHexString(DST, HexDigits, UpperCase, RM));
+  }
+
+  bool isZero() const { return getCategory() == fcZero; }
+  bool isInfinity() const { return getCategory() == fcInfinity; }
+  bool isNaN() const { return getCategory() == fcNaN; }
+
+  bool isNegative() const { return getIEEE().isNegative(); }
+  bool isDenormal() const { APFLOAT_DISPATCH_ON_SEMANTICS(isDenormal()); }
+  bool isSignaling() const { return getIEEE().isSignaling(); }
+
+  bool isNormal() const { return !isDenormal() && isFiniteNonZero(); }
+  bool isFinite() const { return !isNaN() && !isInfinity(); }
+
+  fltCategory getCategory() const { return getIEEE().getCategory(); }
+  const fltSemantics &getSemantics() const { return *U.semantics; }
+  bool isNonZero() const { return !isZero(); }
+  bool isFiniteNonZero() const { return isFinite() && !isZero(); }
+  bool isPosZero() const { return isZero() && !isNegative(); }
+  bool isNegZero() const { return isZero() && isNegative(); }
+  bool isSmallest() const { APFLOAT_DISPATCH_ON_SEMANTICS(isSmallest()); }
+  bool isLargest() const { APFLOAT_DISPATCH_ON_SEMANTICS(isLargest()); }
+  bool isInteger() const { APFLOAT_DISPATCH_ON_SEMANTICS(isInteger()); }
+
+  APFloat &operator=(const APFloat &RHS) = default;
+  APFloat &operator=(APFloat &&RHS) = default;
+
+  void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision = 0,
+                unsigned FormatMaxPadding = 3, bool TruncateZero = true) const {
+    APFLOAT_DISPATCH_ON_SEMANTICS(
+        toString(Str, FormatPrecision, FormatMaxPadding, TruncateZero));
+  }
+
+  void print(raw_ostream &) const;
+  void dump() const;
+
+  bool getExactInverse(APFloat *inv) const {
+    APFLOAT_DISPATCH_ON_SEMANTICS(getExactInverse(inv));
+  }
+
+  friend hash_code hash_value(const APFloat &Arg);
+  friend int ilogb(const APFloat &Arg) { return ilogb(Arg.getIEEE()); }
+  friend APFloat scalbn(APFloat X, int Exp, roundingMode RM);
+  friend APFloat frexp(const APFloat &X, int &Exp, roundingMode RM);
+  friend IEEEFloat;
+  friend DoubleAPFloat;
+};
+
+/// See friend declarations above.
+///
+/// These additional declarations are required in order to compile LLVM with IBM
+/// xlC compiler.
+hash_code hash_value(const APFloat &Arg);
+inline APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode RM) {
+  if (APFloat::usesLayout<detail::IEEEFloat>(X.getSemantics()))
+    return APFloat(scalbn(X.U.IEEE, Exp, RM), X.getSemantics());
+  if (APFloat::usesLayout<detail::DoubleAPFloat>(X.getSemantics()))
+    return APFloat(scalbn(X.U.Double, Exp, RM), X.getSemantics());
+  llvm_unreachable("Unexpected semantics");
+}
+
+/// Equivalent of C standard library function.
+///
+/// While the C standard says Exp is an unspecified value for infinity and nan,
+/// this returns INT_MAX for infinities, and INT_MIN for NaNs.
+inline APFloat frexp(const APFloat &X, int &Exp, APFloat::roundingMode RM) {
+  if (APFloat::usesLayout<detail::IEEEFloat>(X.getSemantics()))
+    return APFloat(frexp(X.U.IEEE, Exp, RM), X.getSemantics());
+  if (APFloat::usesLayout<detail::DoubleAPFloat>(X.getSemantics()))
+    return APFloat(frexp(X.U.Double, Exp, RM), X.getSemantics());
+  llvm_unreachable("Unexpected semantics");
+}
+/// Returns the absolute value of the argument.
+inline APFloat abs(APFloat X) {
+  X.clearSign();
+  return X;
+}
+
+/// Returns the negated value of the argument.
+inline APFloat neg(APFloat X) {
+  X.changeSign();
+  return X;
+}
+
+/// Implements IEEE minNum semantics. Returns the smaller of the 2 arguments if
+/// both are not NaN. If either argument is a NaN, returns the other argument.
+LLVM_READONLY
+inline APFloat minnum(const APFloat &A, const APFloat &B) {
+  if (A.isNaN())
+    return B;
+  if (B.isNaN())
+    return A;
+  return (B.compare(A) == APFloat::cmpLessThan) ? B : A;
+}
+
+/// Implements IEEE maxNum semantics. Returns the larger of the 2 arguments if
+/// both are not NaN. If either argument is a NaN, returns the other argument.
+LLVM_READONLY
+inline APFloat maxnum(const APFloat &A, const APFloat &B) {
+  if (A.isNaN())
+    return B;
+  if (B.isNaN())
+    return A;
+  return (A.compare(B) == APFloat::cmpLessThan) ? B : A;
+}
+
+/// Implements IEEE 754-2018 minimum semantics. Returns the smaller of 2
+/// arguments, propagating NaNs and treating -0 as less than +0.
+LLVM_READONLY
+inline APFloat minimum(const APFloat &A, const APFloat &B) {
+  if (A.isNaN())
+    return A;
+  if (B.isNaN())
+    return B;
+  if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
+    return A.isNegative() ? A : B;
+  return (B.compare(A) == APFloat::cmpLessThan) ? B : A;
+}
+
+/// Implements IEEE 754-2018 maximum semantics. Returns the larger of 2
+/// arguments, propagating NaNs and treating -0 as less than +0.
+LLVM_READONLY
+inline APFloat maximum(const APFloat &A, const APFloat &B) {
+  if (A.isNaN())
+    return A;
+  if (B.isNaN())
+    return B;
+  if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
+    return A.isNegative() ? B : A;
+  return (A.compare(B) == APFloat::cmpLessThan) ? B : A;
+}
+
+} // namespace llvm
+
+#undef APFLOAT_DISPATCH_ON_SEMANTICS
+#endif // LLVM_ADT_APFLOAT_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/APInt.h b/binaryen/third_party/llvm-project/include/llvm/ADT/APInt.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/APInt.h
@@ -0,0 +1,2258 @@
+//===-- llvm/ADT/APInt.h - For Arbitrary Precision Integer -----*- C++ -*--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements a class to represent arbitrary precision
+/// integral constant values and operations on them.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_APINT_H
+#define LLVM_ADT_APINT_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MathExtras.h"
+#include <cassert>
+#include <climits>
+#include <cstring>
+#include <string>
+
+namespace llvm {
+class FoldingSetNodeID;
+class StringRef;
+class hash_code;
+class raw_ostream;
+
+template <typename T> class SmallVectorImpl;
+template <typename T> class ArrayRef;
+template <typename T> class Optional;
+
+class APInt;
+
+inline APInt operator-(APInt);
+
+//===----------------------------------------------------------------------===//
+//                              APInt Class
+//===----------------------------------------------------------------------===//
+
+/// Class for arbitrary precision integers.
+///
+/// APInt is a functional replacement for common case unsigned integer type like
+/// "unsigned", "unsigned long" or "uint64_t", but also allows non-byte-width
+/// integer sizes and large integer value types such as 3-bits, 15-bits, or more
+/// than 64-bits of precision. APInt provides a variety of arithmetic operators
+/// and methods to manipulate integer values of any bit-width. It supports both
+/// the typical integer arithmetic and comparison operations as well as bitwise
+/// manipulation.
+///
+/// The class has several invariants worth noting:
+///   * All bit, byte, and word positions are zero-based.
+///   * Once the bit width is set, it doesn't change except by the Truncate,
+///     SignExtend, or ZeroExtend operations.
+///   * All binary operators must be on APInt instances of the same bit width.
+///     Attempting to use these operators on instances with different bit
+///     widths will yield an assertion.
+///   * The value is stored canonically as an unsigned value. For operations
+///     where it makes a difference, there are both signed and unsigned variants
+///     of the operation. For example, sdiv and udiv. However, because the bit
+///     widths must be the same, operations such as Mul and Add produce the same
+///     results regardless of whether the values are interpreted as signed or
+///     not.
+///   * In general, the class tries to follow the style of computation that LLVM
+///     uses in its IR. This simplifies its use for LLVM.
+///
+class LLVM_NODISCARD APInt {
+public:
+  typedef uint64_t WordType;
+
+  /// This enum is used to hold the constants we needed for APInt.
+  enum : unsigned {
+    /// Byte size of a word.
+    APINT_WORD_SIZE = sizeof(WordType),
+    /// Bits in a word.
+    APINT_BITS_PER_WORD = APINT_WORD_SIZE * CHAR_BIT
+  };
+
+  enum class Rounding {
+    DOWN,
+    TOWARD_ZERO,
+    UP,
+  };
+
+  static const WordType WORDTYPE_MAX = ~WordType(0);
+
+private:
+  /// This union is used to store the integer value. When the
+  /// integer bit-width <= 64, it uses VAL, otherwise it uses pVal.
+  union {
+    uint64_t VAL;   ///< Used to store the <= 64 bits integer value.
+    uint64_t *pVal; ///< Used to store the >64 bits integer value.
+  } U;
+
+  unsigned BitWidth; ///< The number of bits in this APInt.
+
+  friend struct DenseMapAPIntKeyInfo;
+
+  friend class APSInt;
+
+  /// Fast internal constructor
+  ///
+  /// This constructor is used only internally for speed of construction of
+  /// temporaries. It is unsafe for general use so it is not public.
+  APInt(uint64_t *val, unsigned bits) : BitWidth(bits) {
+    U.pVal = val;
+  }
+
+  /// Determine if this APInt just has one word to store value.
+  ///
+  /// \returns true if the number of bits <= 64, false otherwise.
+  bool isSingleWord() const { return BitWidth <= APINT_BITS_PER_WORD; }
+
+  /// Determine which word a bit is in.
+  ///
+  /// \returns the word position for the specified bit position.
+  static unsigned whichWord(unsigned bitPosition) {
+    return bitPosition / APINT_BITS_PER_WORD;
+  }
+
+  /// Determine which bit in a word a bit is in.
+  ///
+  /// \returns the bit position in a word for the specified bit position
+  /// in the APInt.
+  static unsigned whichBit(unsigned bitPosition) {
+    return bitPosition % APINT_BITS_PER_WORD;
+  }
+
+  /// Get a single bit mask.
+  ///
+  /// \returns a uint64_t with only bit at "whichBit(bitPosition)" set
+  /// This method generates and returns a uint64_t (word) mask for a single
+  /// bit at a specific bit position. This is used to mask the bit in the
+  /// corresponding word.
+  static uint64_t maskBit(unsigned bitPosition) {
+    return 1ULL << whichBit(bitPosition);
+  }
+
+  /// Clear unused high order bits
+  ///
+  /// This method is used internally to clear the top "N" bits in the high order
+  /// word that are not used by the APInt. This is needed after the most
+  /// significant word is assigned a value to ensure that those bits are
+  /// zero'd out.
+  APInt &clearUnusedBits() {
+    // Compute how many bits are used in the final word
+    unsigned WordBits = ((BitWidth-1) % APINT_BITS_PER_WORD) + 1;
+
+    // Mask out the high bits.
+    uint64_t mask = WORDTYPE_MAX >> (APINT_BITS_PER_WORD - WordBits);
+    if (isSingleWord())
+      U.VAL &= mask;
+    else
+      U.pVal[getNumWords() - 1] &= mask;
+    return *this;
+  }
+
+  /// Get the word corresponding to a bit position
+  /// \returns the corresponding word for the specified bit position.
+  uint64_t getWord(unsigned bitPosition) const {
+    return isSingleWord() ? U.VAL : U.pVal[whichWord(bitPosition)];
+  }
+
+  /// Utility method to change the bit width of this APInt to new bit width,
+  /// allocating and/or deallocating as necessary. There is no guarantee on the
+  /// value of any bits upon return. Caller should populate the bits after.
+  void reallocate(unsigned NewBitWidth);
+
+  /// Convert a char array into an APInt
+  ///
+  /// \param radix 2, 8, 10, 16, or 36
+  /// Converts a string into a number.  The string must be non-empty
+  /// and well-formed as a number of the given base. The bit-width
+  /// must be sufficient to hold the result.
+  ///
+  /// This is used by the constructors that take string arguments.
+  ///
+  /// StringRef::getAsInteger is superficially similar but (1) does
+  /// not assume that the string is well-formed and (2) grows the
+  /// result to hold the input.
+  void fromString(unsigned numBits, StringRef str, uint8_t radix);
+
+  /// An internal division function for dividing APInts.
+  ///
+  /// This is used by the toString method to divide by the radix. It simply
+  /// provides a more convenient form of divide for internal use since KnuthDiv
+  /// has specific constraints on its inputs. If those constraints are not met
+  /// then it provides a simpler form of divide.
+  static void divide(const WordType *LHS, unsigned lhsWords,
+                     const WordType *RHS, unsigned rhsWords, WordType *Quotient,
+                     WordType *Remainder);
+
+  /// out-of-line slow case for inline constructor
+  void initSlowCase(uint64_t val, bool isSigned);
+
+  /// shared code between two array constructors
+  void initFromArray(ArrayRef<uint64_t> array);
+
+  /// out-of-line slow case for inline copy constructor
+  void initSlowCase(const APInt &that);
+
+  /// out-of-line slow case for shl
+  void shlSlowCase(unsigned ShiftAmt);
+
+  /// out-of-line slow case for lshr.
+  void lshrSlowCase(unsigned ShiftAmt);
+
+  /// out-of-line slow case for ashr.
+  void ashrSlowCase(unsigned ShiftAmt);
+
+  /// out-of-line slow case for operator=
+  void AssignSlowCase(const APInt &RHS);
+
+  /// out-of-line slow case for operator==
+  bool EqualSlowCase(const APInt &RHS) const LLVM_READONLY;
+
+  /// out-of-line slow case for countLeadingZeros
+  unsigned countLeadingZerosSlowCase() const LLVM_READONLY;
+
+  /// out-of-line slow case for countLeadingOnes.
+  unsigned countLeadingOnesSlowCase() const LLVM_READONLY;
+
+  /// out-of-line slow case for countTrailingZeros.
+  unsigned countTrailingZerosSlowCase() const LLVM_READONLY;
+
+  /// out-of-line slow case for countTrailingOnes
+  unsigned countTrailingOnesSlowCase() const LLVM_READONLY;
+
+  /// out-of-line slow case for countPopulation
+  unsigned countPopulationSlowCase() const LLVM_READONLY;
+
+  /// out-of-line slow case for intersects.
+  bool intersectsSlowCase(const APInt &RHS) const LLVM_READONLY;
+
+  /// out-of-line slow case for isSubsetOf.
+  bool isSubsetOfSlowCase(const APInt &RHS) const LLVM_READONLY;
+
+  /// out-of-line slow case for setBits.
+  void setBitsSlowCase(unsigned loBit, unsigned hiBit);
+
+  /// out-of-line slow case for flipAllBits.
+  void flipAllBitsSlowCase();
+
+  /// out-of-line slow case for operator&=.
+  void AndAssignSlowCase(const APInt& RHS);
+
+  /// out-of-line slow case for operator|=.
+  void OrAssignSlowCase(const APInt& RHS);
+
+  /// out-of-line slow case for operator^=.
+  void XorAssignSlowCase(const APInt& RHS);
+
+  /// Unsigned comparison. Returns -1, 0, or 1 if this APInt is less than, equal
+  /// to, or greater than RHS.
+  int compare(const APInt &RHS) const LLVM_READONLY;
+
+  /// Signed comparison. Returns -1, 0, or 1 if this APInt is less than, equal
+  /// to, or greater than RHS.
+  int compareSigned(const APInt &RHS) const LLVM_READONLY;
+
+public:
+  /// \name Constructors
+  /// @{
+
+  /// Create a new APInt of numBits width, initialized as val.
+  ///
+  /// If isSigned is true then val is treated as if it were a signed value
+  /// (i.e. as an int64_t) and the appropriate sign extension to the bit width
+  /// will be done. Otherwise, no sign extension occurs (high order bits beyond
+  /// the range of val are zero filled).
+  ///
+  /// \param numBits the bit width of the constructed APInt
+  /// \param val the initial value of the APInt
+  /// \param isSigned how to treat signedness of val
+  APInt(unsigned numBits, uint64_t val, bool isSigned = false)
+      : BitWidth(numBits) {
+    assert(BitWidth && "bitwidth too small");
+    if (isSingleWord()) {
+      U.VAL = val;
+      clearUnusedBits();
+    } else {
+      initSlowCase(val, isSigned);
+    }
+  }
+
+  /// Construct an APInt of numBits width, initialized as bigVal[].
+  ///
+  /// Note that bigVal.size() can be smaller or larger than the corresponding
+  /// bit width but any extraneous bits will be dropped.
+  ///
+  /// \param numBits the bit width of the constructed APInt
+  /// \param bigVal a sequence of words to form the initial value of the APInt
+  APInt(unsigned numBits, ArrayRef<uint64_t> bigVal);
+
+  /// Equivalent to APInt(numBits, ArrayRef<uint64_t>(bigVal, numWords)), but
+  /// deprecated because this constructor is prone to ambiguity with the
+  /// APInt(unsigned, uint64_t, bool) constructor.
+  ///
+  /// If this overload is ever deleted, care should be taken to prevent calls
+  /// from being incorrectly captured by the APInt(unsigned, uint64_t, bool)
+  /// constructor.
+  APInt(unsigned numBits, unsigned numWords, const uint64_t bigVal[]);
+
+  /// Construct an APInt from a string representation.
+  ///
+  /// This constructor interprets the string \p str in the given radix. The
+  /// interpretation stops when the first character that is not suitable for the
+  /// radix is encountered, or the end of the string. Acceptable radix values
+  /// are 2, 8, 10, 16, and 36. It is an error for the value implied by the
+  /// string to require more bits than numBits.
+  ///
+  /// \param numBits the bit width of the constructed APInt
+  /// \param str the string to be interpreted
+  /// \param radix the radix to use for the conversion
+  APInt(unsigned numBits, StringRef str, uint8_t radix);
+
+  /// Simply makes *this a copy of that.
+  /// Copy Constructor.
+  APInt(const APInt &that) : BitWidth(that.BitWidth) {
+    if (isSingleWord())
+      U.VAL = that.U.VAL;
+    else
+      initSlowCase(that);
+  }
+
+  /// Move Constructor.
+  APInt(APInt &&that) : BitWidth(that.BitWidth) {
+    memcpy(&U, &that.U, sizeof(U));
+    that.BitWidth = 0;
+  }
+
+  /// Destructor.
+  ~APInt() {
+    if (needsCleanup())
+      delete[] U.pVal;
+  }
+
+  /// Default constructor that creates an uninteresting APInt
+  /// representing a 1-bit zero value.
+  ///
+  /// This is useful for object deserialization (pair this with the static
+  ///  method Read).
+  explicit APInt() : BitWidth(1) { U.VAL = 0; }
+
+  /// Returns whether this instance allocated memory.
+  bool needsCleanup() const { return !isSingleWord(); }
+
+  /// Used to insert APInt objects, or objects that contain APInt objects, into
+  ///  FoldingSets.
+  void Profile(FoldingSetNodeID &id) const;
+
+  /// @}
+  /// \name Value Tests
+  /// @{
+
+  /// Determine sign of this APInt.
+  ///
+  /// This tests the high bit of this APInt to determine if it is set.
+  ///
+  /// \returns true if this APInt is negative, false otherwise
+  bool isNegative() const { return (*this)[BitWidth - 1]; }
+
+  /// Determine if this APInt Value is non-negative (>= 0)
+  ///
+  /// This tests the high bit of the APInt to determine if it is unset.
+  bool isNonNegative() const { return !isNegative(); }
+
+  /// Determine if sign bit of this APInt is set.
+  ///
+  /// This tests the high bit of this APInt to determine if it is set.
+  ///
+  /// \returns true if this APInt has its sign bit set, false otherwise.
+  bool isSignBitSet() const { return (*this)[BitWidth-1]; }
+
+  /// Determine if sign bit of this APInt is clear.
+  ///
+  /// This tests the high bit of this APInt to determine if it is clear.
+  ///
+  /// \returns true if this APInt has its sign bit clear, false otherwise.
+  bool isSignBitClear() const { return !isSignBitSet(); }
+
+  /// Determine if this APInt Value is positive.
+  ///
+  /// This tests if the value of this APInt is positive (> 0). Note
+  /// that 0 is not a positive value.
+  ///
+  /// \returns true if this APInt is positive.
+  bool isStrictlyPositive() const { return isNonNegative() && !isNullValue(); }
+
+  /// Determine if all bits are set
+  ///
+  /// This checks to see if the value has all bits of the APInt are set or not.
+  bool isAllOnesValue() const {
+    if (isSingleWord())
+      return U.VAL == WORDTYPE_MAX >> (APINT_BITS_PER_WORD - BitWidth);
+    return countTrailingOnesSlowCase() == BitWidth;
+  }
+
+  /// Determine if all bits are clear
+  ///
+  /// This checks to see if the value has all bits of the APInt are clear or
+  /// not.
+  bool isNullValue() const { return !*this; }
+
+  /// Determine if this is a value of 1.
+  ///
+  /// This checks to see if the value of this APInt is one.
+  bool isOneValue() const {
+    if (isSingleWord())
+      return U.VAL == 1;
+    return countLeadingZerosSlowCase() == BitWidth - 1;
+  }
+
+  /// Determine if this is the largest unsigned value.
+  ///
+  /// This checks to see if the value of this APInt is the maximum unsigned
+  /// value for the APInt's bit width.
+  bool isMaxValue() const { return isAllOnesValue(); }
+
+  /// Determine if this is the largest signed value.
+  ///
+  /// This checks to see if the value of this APInt is the maximum signed
+  /// value for the APInt's bit width.
+  bool isMaxSignedValue() const {
+    if (isSingleWord())
+      return U.VAL == ((WordType(1) << (BitWidth - 1)) - 1);
+    return !isNegative() && countTrailingOnesSlowCase() == BitWidth - 1;
+  }
+
+  /// Determine if this is the smallest unsigned value.
+  ///
+  /// This checks to see if the value of this APInt is the minimum unsigned
+  /// value for the APInt's bit width.
+  bool isMinValue() const { return isNullValue(); }
+
+  /// Determine if this is the smallest signed value.
+  ///
+  /// This checks to see if the value of this APInt is the minimum signed
+  /// value for the APInt's bit width.
+  bool isMinSignedValue() const {
+    if (isSingleWord())
+      return U.VAL == (WordType(1) << (BitWidth - 1));
+    return isNegative() && countTrailingZerosSlowCase() == BitWidth - 1;
+  }
+
+  /// Check if this APInt has an N-bits unsigned integer value.
+  bool isIntN(unsigned N) const {
+    assert(N && "N == 0 ???");
+    return getActiveBits() <= N;
+  }
+
+  /// Check if this APInt has an N-bits signed integer value.
+  bool isSignedIntN(unsigned N) const {
+    assert(N && "N == 0 ???");
+    return getMinSignedBits() <= N;
+  }
+
+  /// Check if this APInt's value is a power of two greater than zero.
+  ///
+  /// \returns true if the argument APInt value is a power of two > 0.
+  bool isPowerOf2() const {
+    if (isSingleWord())
+      return isPowerOf2_64(U.VAL);
+    return countPopulationSlowCase() == 1;
+  }
+
+  /// Check if the APInt's value is returned by getSignMask.
+  ///
+  /// \returns true if this is the value returned by getSignMask.
+  bool isSignMask() const { return isMinSignedValue(); }
+
+  /// Convert APInt to a boolean value.
+  ///
+  /// This converts the APInt to a boolean value as a test against zero.
+  bool getBoolValue() const { return !!*this; }
+
+  /// If this value is smaller than the specified limit, return it, otherwise
+  /// return the limit value.  This causes the value to saturate to the limit.
+  uint64_t getLimitedValue(uint64_t Limit = UINT64_MAX) const {
+    return ugt(Limit) ? Limit : getZExtValue();
+  }
+
+  /// Check if the APInt consists of a repeated bit pattern.
+  ///
+  /// e.g. 0x01010101 satisfies isSplat(8).
+  /// \param SplatSizeInBits The size of the pattern in bits. Must divide bit
+  /// width without remainder.
+  bool isSplat(unsigned SplatSizeInBits) const;
+
+  /// \returns true if this APInt value is a sequence of \param numBits ones
+  /// starting at the least significant bit with the remainder zero.
+  bool isMask(unsigned numBits) const {
+    assert(numBits != 0 && "numBits must be non-zero");
+    assert(numBits <= BitWidth && "numBits out of range");
+    if (isSingleWord())
+      return U.VAL == (WORDTYPE_MAX >> (APINT_BITS_PER_WORD - numBits));
+    unsigned Ones = countTrailingOnesSlowCase();
+    return (numBits == Ones) &&
+           ((Ones + countLeadingZerosSlowCase()) == BitWidth);
+  }
+
+  /// \returns true if this APInt is a non-empty sequence of ones starting at
+  /// the least significant bit with the remainder zero.
+  /// Ex. isMask(0x0000FFFFU) == true.
+  bool isMask() const {
+    if (isSingleWord())
+      return isMask_64(U.VAL);
+    unsigned Ones = countTrailingOnesSlowCase();
+    return (Ones > 0) && ((Ones + countLeadingZerosSlowCase()) == BitWidth);
+  }
+
+  /// Return true if this APInt value contains a sequence of ones with
+  /// the remainder zero.
+  bool isShiftedMask() const {
+    if (isSingleWord())
+      return isShiftedMask_64(U.VAL);
+    unsigned Ones = countPopulationSlowCase();
+    unsigned LeadZ = countLeadingZerosSlowCase();
+    return (Ones + LeadZ + countTrailingZeros()) == BitWidth;
+  }
+
+  /// @}
+  /// \name Value Generators
+  /// @{
+
+  /// Gets maximum unsigned value of APInt for specific bit width.
+  static APInt getMaxValue(unsigned numBits) {
+    return getAllOnesValue(numBits);
+  }
+
+  /// Gets maximum signed value of APInt for a specific bit width.
+  static APInt getSignedMaxValue(unsigned numBits) {
+    APInt API = getAllOnesValue(numBits);
+    API.clearBit(numBits - 1);
+    return API;
+  }
+
+  /// Gets minimum unsigned value of APInt for a specific bit width.
+  static APInt getMinValue(unsigned numBits) { return APInt(numBits, 0); }
+
+  /// Gets minimum signed value of APInt for a specific bit width.
+  static APInt getSignedMinValue(unsigned numBits) {
+    APInt API(numBits, 0);
+    API.setBit(numBits - 1);
+    return API;
+  }
+
+  /// Get the SignMask for a specific bit width.
+  ///
+  /// This is just a wrapper function of getSignedMinValue(), and it helps code
+  /// readability when we want to get a SignMask.
+  static APInt getSignMask(unsigned BitWidth) {
+    return getSignedMinValue(BitWidth);
+  }
+
+  /// Get the all-ones value.
+  ///
+  /// \returns the all-ones value for an APInt of the specified bit-width.
+  static APInt getAllOnesValue(unsigned numBits) {
+    return APInt(numBits, WORDTYPE_MAX, true);
+  }
+
+  /// Get the '0' value.
+  ///
+  /// \returns the '0' value for an APInt of the specified bit-width.
+  static APInt getNullValue(unsigned numBits) { return APInt(numBits, 0); }
+
+  /// Compute an APInt containing numBits highbits from this APInt.
+  ///
+  /// Get an APInt with the same BitWidth as this APInt, just zero mask
+  /// the low bits and right shift to the least significant bit.
+  ///
+  /// \returns the high "numBits" bits of this APInt.
+  APInt getHiBits(unsigned numBits) const;
+
+  /// Compute an APInt containing numBits lowbits from this APInt.
+  ///
+  /// Get an APInt with the same BitWidth as this APInt, just zero mask
+  /// the high bits.
+  ///
+  /// \returns the low "numBits" bits of this APInt.
+  APInt getLoBits(unsigned numBits) const;
+
+  /// Return an APInt with exactly one bit set in the result.
+  static APInt getOneBitSet(unsigned numBits, unsigned BitNo) {
+    APInt Res(numBits, 0);
+    Res.setBit(BitNo);
+    return Res;
+  }
+
+  /// Get a value with a block of bits set.
+  ///
+  /// Constructs an APInt value that has a contiguous range of bits set. The
+  /// bits from loBit (inclusive) to hiBit (exclusive) will be set. All other
+  /// bits will be zero. For example, with parameters(32, 0, 16) you would get
+  /// 0x0000FFFF. If hiBit is less than loBit then the set bits "wrap". For
+  /// example, with parameters (32, 28, 4), you would get 0xF000000F.
+  ///
+  /// \param numBits the intended bit width of the result
+  /// \param loBit the index of the lowest bit set.
+  /// \param hiBit the index of the highest bit set.
+  ///
+  /// \returns An APInt value with the requested bits set.
+  static APInt getBitsSet(unsigned numBits, unsigned loBit, unsigned hiBit) {
+    APInt Res(numBits, 0);
+    Res.setBits(loBit, hiBit);
+    return Res;
+  }
+
+  /// Get a value with upper bits starting at loBit set.
+  ///
+  /// Constructs an APInt value that has a contiguous range of bits set. The
+  /// bits from loBit (inclusive) to numBits (exclusive) will be set. All other
+  /// bits will be zero. For example, with parameters(32, 12) you would get
+  /// 0xFFFFF000.
+  ///
+  /// \param numBits the intended bit width of the result
+  /// \param loBit the index of the lowest bit to set.
+  ///
+  /// \returns An APInt value with the requested bits set.
+  static APInt getBitsSetFrom(unsigned numBits, unsigned loBit) {
+    APInt Res(numBits, 0);
+    Res.setBitsFrom(loBit);
+    return Res;
+  }
+
+  /// Get a value with high bits set
+  ///
+  /// Constructs an APInt value that has the top hiBitsSet bits set.
+  ///
+  /// \param numBits the bitwidth of the result
+  /// \param hiBitsSet the number of high-order bits set in the result.
+  static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet) {
+    APInt Res(numBits, 0);
+    Res.setHighBits(hiBitsSet);
+    return Res;
+  }
+
+  /// Get a value with low bits set
+  ///
+  /// Constructs an APInt value that has the bottom loBitsSet bits set.
+  ///
+  /// \param numBits the bitwidth of the result
+  /// \param loBitsSet the number of low-order bits set in the result.
+  static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet) {
+    APInt Res(numBits, 0);
+    Res.setLowBits(loBitsSet);
+    return Res;
+  }
+
+  /// Return a value containing V broadcasted over NewLen bits.
+  static APInt getSplat(unsigned NewLen, const APInt &V);
+
+  /// Determine if two APInts have the same value, after zero-extending
+  /// one of them (if needed!) to ensure that the bit-widths match.
+  static bool isSameValue(const APInt &I1, const APInt &I2) {
+    if (I1.getBitWidth() == I2.getBitWidth())
+      return I1 == I2;
+
+    if (I1.getBitWidth() > I2.getBitWidth())
+      return I1 == I2.zext(I1.getBitWidth());
+
+    return I1.zext(I2.getBitWidth()) == I2;
+  }
+
+  /// Overload to compute a hash_code for an APInt value.
+  friend hash_code hash_value(const APInt &Arg);
+
+  /// This function returns a pointer to the internal storage of the APInt.
+  /// This is useful for writing out the APInt in binary form without any
+  /// conversions.
+  const uint64_t *getRawData() const {
+    if (isSingleWord())
+      return &U.VAL;
+    return &U.pVal[0];
+  }
+
+  /// @}
+  /// \name Unary Operators
+  /// @{
+
+  /// Postfix increment operator.
+  ///
+  /// Increments *this by 1.
+  ///
+  /// \returns a new APInt value representing the original value of *this.
+  const APInt operator++(int) {
+    APInt API(*this);
+    ++(*this);
+    return API;
+  }
+
+  /// Prefix increment operator.
+  ///
+  /// \returns *this incremented by one
+  APInt &operator++();
+
+  /// Postfix decrement operator.
+  ///
+  /// Decrements *this by 1.
+  ///
+  /// \returns a new APInt value representing the original value of *this.
+  const APInt operator--(int) {
+    APInt API(*this);
+    --(*this);
+    return API;
+  }
+
+  /// Prefix decrement operator.
+  ///
+  /// \returns *this decremented by one.
+  APInt &operator--();
+
+  /// Logical negation operator.
+  ///
+  /// Performs logical negation operation on this APInt.
+  ///
+  /// \returns true if *this is zero, false otherwise.
+  bool operator!() const {
+    if (isSingleWord())
+      return U.VAL == 0;
+    return countLeadingZerosSlowCase() == BitWidth;
+  }
+
+  /// @}
+  /// \name Assignment Operators
+  /// @{
+
+  /// Copy assignment operator.
+  ///
+  /// \returns *this after assignment of RHS.
+  APInt &operator=(const APInt &RHS) {
+    // If the bitwidths are the same, we can avoid mucking with memory
+    if (isSingleWord() && RHS.isSingleWord()) {
+      U.VAL = RHS.U.VAL;
+      BitWidth = RHS.BitWidth;
+      return clearUnusedBits();
+    }
+
+    AssignSlowCase(RHS);
+    return *this;
+  }
+
+  /// Move assignment operator.
+  APInt &operator=(APInt &&that) {
+#ifdef _MSC_VER
+    // The MSVC std::shuffle implementation still does self-assignment.
+    if (this == &that)
+      return *this;
+#endif
+    assert(this != &that && "Self-move not supported");
+    if (!isSingleWord())
+      delete[] U.pVal;
+
+    // Use memcpy so that type based alias analysis sees both VAL and pVal
+    // as modified.
+    memcpy(&U, &that.U, sizeof(U));
+
+    BitWidth = that.BitWidth;
+    that.BitWidth = 0;
+
+    return *this;
+  }
+
+  /// Assignment operator.
+  ///
+  /// The RHS value is assigned to *this. If the significant bits in RHS exceed
+  /// the bit width, the excess bits are truncated. If the bit width is larger
+  /// than 64, the value is zero filled in the unspecified high order bits.
+  ///
+  /// \returns *this after assignment of RHS value.
+  APInt &operator=(uint64_t RHS) {
+    if (isSingleWord()) {
+      U.VAL = RHS;
+      clearUnusedBits();
+    } else {
+      U.pVal[0] = RHS;
+      memset(U.pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE);
+    }
+    return *this;
+  }
+
+  /// Bitwise AND assignment operator.
+  ///
+  /// Performs a bitwise AND operation on this APInt and RHS. The result is
+  /// assigned to *this.
+  ///
+  /// \returns *this after ANDing with RHS.
+  APInt &operator&=(const APInt &RHS) {
+    assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
+    if (isSingleWord())
+      U.VAL &= RHS.U.VAL;
+    else
+      AndAssignSlowCase(RHS);
+    return *this;
+  }
+
+  /// Bitwise AND assignment operator.
+  ///
+  /// Performs a bitwise AND operation on this APInt and RHS. RHS is
+  /// logically zero-extended or truncated to match the bit-width of
+  /// the LHS.
+  APInt &operator&=(uint64_t RHS) {
+    if (isSingleWord()) {
+      U.VAL &= RHS;
+      return *this;
+    }
+    U.pVal[0] &= RHS;
+    memset(U.pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE);
+    return *this;
+  }
+
+  /// Bitwise OR assignment operator.
+  ///
+  /// Performs a bitwise OR operation on this APInt and RHS. The result is
+  /// assigned *this;
+  ///
+  /// \returns *this after ORing with RHS.
+  APInt &operator|=(const APInt &RHS) {
+    assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
+    if (isSingleWord())
+      U.VAL |= RHS.U.VAL;
+    else
+      OrAssignSlowCase(RHS);
+    return *this;
+  }
+
+  /// Bitwise OR assignment operator.
+  ///
+  /// Performs a bitwise OR operation on this APInt and RHS. RHS is
+  /// logically zero-extended or truncated to match the bit-width of
+  /// the LHS.
+  APInt &operator|=(uint64_t RHS) {
+    if (isSingleWord()) {
+      U.VAL |= RHS;
+      clearUnusedBits();
+    } else {
+      U.pVal[0] |= RHS;
+    }
+    return *this;
+  }
+
+  /// Bitwise XOR assignment operator.
+  ///
+  /// Performs a bitwise XOR operation on this APInt and RHS. The result is
+  /// assigned to *this.
+  ///
+  /// \returns *this after XORing with RHS.
+  APInt &operator^=(const APInt &RHS) {
+    assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
+    if (isSingleWord())
+      U.VAL ^= RHS.U.VAL;
+    else
+      XorAssignSlowCase(RHS);
+    return *this;
+  }
+
+  /// Bitwise XOR assignment operator.
+  ///
+  /// Performs a bitwise XOR operation on this APInt and RHS. RHS is
+  /// logically zero-extended or truncated to match the bit-width of
+  /// the LHS.
+  APInt &operator^=(uint64_t RHS) {
+    if (isSingleWord()) {
+      U.VAL ^= RHS;
+      clearUnusedBits();
+    } else {
+      U.pVal[0] ^= RHS;
+    }
+    return *this;
+  }
+
+  /// Multiplication assignment operator.
+  ///
+  /// Multiplies this APInt by RHS and assigns the result to *this.
+  ///
+  /// \returns *this
+  APInt &operator*=(const APInt &RHS);
+  APInt &operator*=(uint64_t RHS);
+
+  /// Addition assignment operator.
+  ///
+  /// Adds RHS to *this and assigns the result to *this.
+  ///
+  /// \returns *this
+  APInt &operator+=(const APInt &RHS);
+  APInt &operator+=(uint64_t RHS);
+
+  /// Subtraction assignment operator.
+  ///
+  /// Subtracts RHS from *this and assigns the result to *this.
+  ///
+  /// \returns *this
+  APInt &operator-=(const APInt &RHS);
+  APInt &operator-=(uint64_t RHS);
+
+  /// Left-shift assignment function.
+  ///
+  /// Shifts *this left by shiftAmt and assigns the result to *this.
+  ///
+  /// \returns *this after shifting left by ShiftAmt
+  APInt &operator<<=(unsigned ShiftAmt) {
+    assert(ShiftAmt <= BitWidth && "Invalid shift amount");
+    if (isSingleWord()) {
+      if (ShiftAmt == BitWidth)
+        U.VAL = 0;
+      else
+        U.VAL <<= ShiftAmt;
+      return clearUnusedBits();
+    }
+    shlSlowCase(ShiftAmt);
+    return *this;
+  }
+
+  /// Left-shift assignment function.
+  ///
+  /// Shifts *this left by shiftAmt and assigns the result to *this.
+  ///
+  /// \returns *this after shifting left by ShiftAmt
+  APInt &operator<<=(const APInt &ShiftAmt);
+
+  /// @}
+  /// \name Binary Operators
+  /// @{
+
+  /// Multiplication operator.
+  ///
+  /// Multiplies this APInt by RHS and returns the result.
+  APInt operator*(const APInt &RHS) const;
+
+  /// Left logical shift operator.
+  ///
+  /// Shifts this APInt left by \p Bits and returns the result.
+  APInt operator<<(unsigned Bits) const { return shl(Bits); }
+
+  /// Left logical shift operator.
+  ///
+  /// Shifts this APInt left by \p Bits and returns the result.
+  APInt operator<<(const APInt &Bits) const { return shl(Bits); }
+
+  /// Arithmetic right-shift function.
+  ///
+  /// Arithmetic right-shift this APInt by shiftAmt.
+  APInt ashr(unsigned ShiftAmt) const {
+    APInt R(*this);
+    R.ashrInPlace(ShiftAmt);
+    return R;
+  }
+
+  /// Arithmetic right-shift this APInt by ShiftAmt in place.
+  void ashrInPlace(unsigned ShiftAmt) {
+    assert(ShiftAmt <= BitWidth && "Invalid shift amount");
+    if (isSingleWord()) {
+      int64_t SExtVAL = SignExtend64(U.VAL, BitWidth);
+      if (ShiftAmt == BitWidth)
+        U.VAL = SExtVAL >> (APINT_BITS_PER_WORD - 1); // Fill with sign bit.
+      else
+        U.VAL = SExtVAL >> ShiftAmt;
+      clearUnusedBits();
+      return;
+    }
+    ashrSlowCase(ShiftAmt);
+  }
+
+  /// Logical right-shift function.
+  ///
+  /// Logical right-shift this APInt by shiftAmt.
+  APInt lshr(unsigned shiftAmt) const {
+    APInt R(*this);
+    R.lshrInPlace(shiftAmt);
+    return R;
+  }
+
+  /// Logical right-shift this APInt by ShiftAmt in place.
+  void lshrInPlace(unsigned ShiftAmt) {
+    assert(ShiftAmt <= BitWidth && "Invalid shift amount");
+    if (isSingleWord()) {
+      if (ShiftAmt == BitWidth)
+        U.VAL = 0;
+      else
+        U.VAL >>= ShiftAmt;
+      return;
+    }
+    lshrSlowCase(ShiftAmt);
+  }
+
+  /// Left-shift function.
+  ///
+  /// Left-shift this APInt by shiftAmt.
+  APInt shl(unsigned shiftAmt) const {
+    APInt R(*this);
+    R <<= shiftAmt;
+    return R;
+  }
+
+  /// Rotate left by rotateAmt.
+  APInt rotl(unsigned rotateAmt) const;
+
+  /// Rotate right by rotateAmt.
+  APInt rotr(unsigned rotateAmt) const;
+
+  /// Arithmetic right-shift function.
+  ///
+  /// Arithmetic right-shift this APInt by shiftAmt.
+  APInt ashr(const APInt &ShiftAmt) const {
+    APInt R(*this);
+    R.ashrInPlace(ShiftAmt);
+    return R;
+  }
+
+  /// Arithmetic right-shift this APInt by shiftAmt in place.
+  void ashrInPlace(const APInt &shiftAmt);
+
+  /// Logical right-shift function.
+  ///
+  /// Logical right-shift this APInt by shiftAmt.
+  APInt lshr(const APInt &ShiftAmt) const {
+    APInt R(*this);
+    R.lshrInPlace(ShiftAmt);
+    return R;
+  }
+
+  /// Logical right-shift this APInt by ShiftAmt in place.
+  void lshrInPlace(const APInt &ShiftAmt);
+
+  /// Left-shift function.
+  ///
+  /// Left-shift this APInt by shiftAmt.
+  APInt shl(const APInt &ShiftAmt) const {
+    APInt R(*this);
+    R <<= ShiftAmt;
+    return R;
+  }
+
+  /// Rotate left by rotateAmt.
+  APInt rotl(const APInt &rotateAmt) const;
+
+  /// Rotate right by rotateAmt.
+  APInt rotr(const APInt &rotateAmt) const;
+
+  /// Unsigned division operation.
+  ///
+  /// Perform an unsigned divide operation on this APInt by RHS. Both this and
+  /// RHS are treated as unsigned quantities for purposes of this division.
+  ///
+  /// \returns a new APInt value containing the division result, rounded towards
+  /// zero.
+  APInt udiv(const APInt &RHS) const;
+  APInt udiv(uint64_t RHS) const;
+
+  /// Signed division function for APInt.
+  ///
+  /// Signed divide this APInt by APInt RHS.
+  ///
+  /// The result is rounded towards zero.
+  APInt sdiv(const APInt &RHS) const;
+  APInt sdiv(int64_t RHS) const;
+
+  /// Unsigned remainder operation.
+  ///
+  /// Perform an unsigned remainder operation on this APInt with RHS being the
+  /// divisor. Both this and RHS are treated as unsigned quantities for purposes
+  /// of this operation. Note that this is a true remainder operation and not a
+  /// modulo operation because the sign follows the sign of the dividend which
+  /// is *this.
+  ///
+  /// \returns a new APInt value containing the remainder result
+  APInt urem(const APInt &RHS) const;
+  uint64_t urem(uint64_t RHS) const;
+
+  /// Function for signed remainder operation.
+  ///
+  /// Signed remainder operation on APInt.
+  APInt srem(const APInt &RHS) const;
+  int64_t srem(int64_t RHS) const;
+
+  /// Dual division/remainder interface.
+  ///
+  /// Sometimes it is convenient to divide two APInt values and obtain both the
+  /// quotient and remainder. This function does both operations in the same
+  /// computation making it a little more efficient. The pair of input arguments
+  /// may overlap with the pair of output arguments. It is safe to call
+  /// udivrem(X, Y, X, Y), for example.
+  static void udivrem(const APInt &LHS, const APInt &RHS, APInt &Quotient,
+                      APInt &Remainder);
+  static void udivrem(const APInt &LHS, uint64_t RHS, APInt &Quotient,
+                      uint64_t &Remainder);
+
+  static void sdivrem(const APInt &LHS, const APInt &RHS, APInt &Quotient,
+                      APInt &Remainder);
+  static void sdivrem(const APInt &LHS, int64_t RHS, APInt &Quotient,
+                      int64_t &Remainder);
+
+  // Operations that return overflow indicators.
+  APInt sadd_ov(const APInt &RHS, bool &Overflow) const;
+  APInt uadd_ov(const APInt &RHS, bool &Overflow) const;
+  APInt ssub_ov(const APInt &RHS, bool &Overflow) const;
+  APInt usub_ov(const APInt &RHS, bool &Overflow) const;
+  APInt sdiv_ov(const APInt &RHS, bool &Overflow) const;
+  APInt smul_ov(const APInt &RHS, bool &Overflow) const;
+  APInt umul_ov(const APInt &RHS, bool &Overflow) const;
+  APInt sshl_ov(const APInt &Amt, bool &Overflow) const;
+  APInt ushl_ov(const APInt &Amt, bool &Overflow) const;
+
+  // Operations that saturate
+  APInt sadd_sat(const APInt &RHS) const;
+  APInt uadd_sat(const APInt &RHS) const;
+  APInt ssub_sat(const APInt &RHS) const;
+  APInt usub_sat(const APInt &RHS) const;
+  APInt smul_sat(const APInt &RHS) const;
+  APInt umul_sat(const APInt &RHS) const;
+  APInt sshl_sat(const APInt &RHS) const;
+  APInt ushl_sat(const APInt &RHS) const;
+
+  /// Array-indexing support.
+  ///
+  /// \returns the bit value at bitPosition
+  bool operator[](unsigned bitPosition) const {
+    assert(bitPosition < getBitWidth() && "Bit position out of bounds!");
+    return (maskBit(bitPosition) & getWord(bitPosition)) != 0;
+  }
+
+  /// @}
+  /// \name Comparison Operators
+  /// @{
+
+  /// Equality operator.
+  ///
+  /// Compares this APInt with RHS for the validity of the equality
+  /// relationship.
+  bool operator==(const APInt &RHS) const {
+    assert(BitWidth == RHS.BitWidth && "Comparison requires equal bit widths");
+    if (isSingleWord())
+      return U.VAL == RHS.U.VAL;
+    return EqualSlowCase(RHS);
+  }
+
+  /// Equality operator.
+  ///
+  /// Compares this APInt with a uint64_t for the validity of the equality
+  /// relationship.
+  ///
+  /// \returns true if *this == Val
+  bool operator==(uint64_t Val) const {
+    return (isSingleWord() || getActiveBits() <= 64) && getZExtValue() == Val;
+  }
+
+  /// Equality comparison.
+  ///
+  /// Compares this APInt with RHS for the validity of the equality
+  /// relationship.
+  ///
+  /// \returns true if *this == Val
+  bool eq(const APInt &RHS) const { return (*this) == RHS; }
+
+  /// Inequality operator.
+  ///
+  /// Compares this APInt with RHS for the validity of the inequality
+  /// relationship.
+  ///
+  /// \returns true if *this != Val
+  bool operator!=(const APInt &RHS) const { return !((*this) == RHS); }
+
+  /// Inequality operator.
+  ///
+  /// Compares this APInt with a uint64_t for the validity of the inequality
+  /// relationship.
+  ///
+  /// \returns true if *this != Val
+  bool operator!=(uint64_t Val) const { return !((*this) == Val); }
+
+  /// Inequality comparison
+  ///
+  /// Compares this APInt with RHS for the validity of the inequality
+  /// relationship.
+  ///
+  /// \returns true if *this != Val
+  bool ne(const APInt &RHS) const { return !((*this) == RHS); }
+
+  /// Unsigned less than comparison
+  ///
+  /// Regards both *this and RHS as unsigned quantities and compares them for
+  /// the validity of the less-than relationship.
+  ///
+  /// \returns true if *this < RHS when both are considered unsigned.
+  bool ult(const APInt &RHS) const { return compare(RHS) < 0; }
+
+  /// Unsigned less than comparison
+  ///
+  /// Regards both *this as an unsigned quantity and compares it with RHS for
+  /// the validity of the less-than relationship.
+  ///
+  /// \returns true if *this < RHS when considered unsigned.
+  bool ult(uint64_t RHS) const {
+    // Only need to check active bits if not a single word.
+    return (isSingleWord() || getActiveBits() <= 64) && getZExtValue() < RHS;
+  }
+
+  /// Signed less than comparison
+  ///
+  /// Regards both *this and RHS as signed quantities and compares them for
+  /// validity of the less-than relationship.
+  ///
+  /// \returns true if *this < RHS when both are considered signed.
+  bool slt(const APInt &RHS) const { return compareSigned(RHS) < 0; }
+
+  /// Signed less than comparison
+  ///
+  /// Regards both *this as a signed quantity and compares it with RHS for
+  /// the validity of the less-than relationship.
+  ///
+  /// \returns true if *this < RHS when considered signed.
+  bool slt(int64_t RHS) const {
+    return (!isSingleWord() && getMinSignedBits() > 64) ? isNegative()
+                                                        : getSExtValue() < RHS;
+  }
+
+  /// Unsigned less or equal comparison
+  ///
+  /// Regards both *this and RHS as unsigned quantities and compares them for
+  /// validity of the less-or-equal relationship.
+  ///
+  /// \returns true if *this <= RHS when both are considered unsigned.
+  bool ule(const APInt &RHS) const { return compare(RHS) <= 0; }
+
+  /// Unsigned less or equal comparison
+  ///
+  /// Regards both *this as an unsigned quantity and compares it with RHS for
+  /// the validity of the less-or-equal relationship.
+  ///
+  /// \returns true if *this <= RHS when considered unsigned.
+  bool ule(uint64_t RHS) const { return !ugt(RHS); }
+
+  /// Signed less or equal comparison
+  ///
+  /// Regards both *this and RHS as signed quantities and compares them for
+  /// validity of the less-or-equal relationship.
+  ///
+  /// \returns true if *this <= RHS when both are considered signed.
+  bool sle(const APInt &RHS) const { return compareSigned(RHS) <= 0; }
+
+  /// Signed less or equal comparison
+  ///
+  /// Regards both *this as a signed quantity and compares it with RHS for the
+  /// validity of the less-or-equal relationship.
+  ///
+  /// \returns true if *this <= RHS when considered signed.
+  bool sle(uint64_t RHS) const { return !sgt(RHS); }
+
+  /// Unsigned greater than comparison
+  ///
+  /// Regards both *this and RHS as unsigned quantities and compares them for
+  /// the validity of the greater-than relationship.
+  ///
+  /// \returns true if *this > RHS when both are considered unsigned.
+  bool ugt(const APInt &RHS) const { return !ule(RHS); }
+
+  /// Unsigned greater than comparison
+  ///
+  /// Regards both *this as an unsigned quantity and compares it with RHS for
+  /// the validity of the greater-than relationship.
+  ///
+  /// \returns true if *this > RHS when considered unsigned.
+  bool ugt(uint64_t RHS) const {
+    // Only need to check active bits if not a single word.
+    return (!isSingleWord() && getActiveBits() > 64) || getZExtValue() > RHS;
+  }
+
+  /// Signed greater than comparison
+  ///
+  /// Regards both *this and RHS as signed quantities and compares them for the
+  /// validity of the greater-than relationship.
+  ///
+  /// \returns true if *this > RHS when both are considered signed.
+  bool sgt(const APInt &RHS) const { return !sle(RHS); }
+
+  /// Signed greater than comparison
+  ///
+  /// Regards both *this as a signed quantity and compares it with RHS for
+  /// the validity of the greater-than relationship.
+  ///
+  /// \returns true if *this > RHS when considered signed.
+  bool sgt(int64_t RHS) const {
+    return (!isSingleWord() && getMinSignedBits() > 64) ? !isNegative()
+                                                        : getSExtValue() > RHS;
+  }
+
+  /// Unsigned greater or equal comparison
+  ///
+  /// Regards both *this and RHS as unsigned quantities and compares them for
+  /// validity of the greater-or-equal relationship.
+  ///
+  /// \returns true if *this >= RHS when both are considered unsigned.
+  bool uge(const APInt &RHS) const { return !ult(RHS); }
+
+  /// Unsigned greater or equal comparison
+  ///
+  /// Regards both *this as an unsigned quantity and compares it with RHS for
+  /// the validity of the greater-or-equal relationship.
+  ///
+  /// \returns true if *this >= RHS when considered unsigned.
+  bool uge(uint64_t RHS) const { return !ult(RHS); }
+
+  /// Signed greater or equal comparison
+  ///
+  /// Regards both *this and RHS as signed quantities and compares them for
+  /// validity of the greater-or-equal relationship.
+  ///
+  /// \returns true if *this >= RHS when both are considered signed.
+  bool sge(const APInt &RHS) const { return !slt(RHS); }
+
+  /// Signed greater or equal comparison
+  ///
+  /// Regards both *this as a signed quantity and compares it with RHS for
+  /// the validity of the greater-or-equal relationship.
+  ///
+  /// \returns true if *this >= RHS when considered signed.
+  bool sge(int64_t RHS) const { return !slt(RHS); }
+
+  /// This operation tests if there are any pairs of corresponding bits
+  /// between this APInt and RHS that are both set.
+  bool intersects(const APInt &RHS) const {
+    assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
+    if (isSingleWord())
+      return (U.VAL & RHS.U.VAL) != 0;
+    return intersectsSlowCase(RHS);
+  }
+
+  /// This operation checks that all bits set in this APInt are also set in RHS.
+  bool isSubsetOf(const APInt &RHS) const {
+    assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
+    if (isSingleWord())
+      return (U.VAL & ~RHS.U.VAL) == 0;
+    return isSubsetOfSlowCase(RHS);
+  }
+
+  /// @}
+  /// \name Resizing Operators
+  /// @{
+
+  /// Truncate to new width.
+  ///
+  /// Truncate the APInt to a specified width. It is an error to specify a width
+  /// that is greater than or equal to the current width.
+  APInt trunc(unsigned width) const;
+
+  /// Truncate to new width with unsigned saturation.
+  ///
+  /// If the APInt, treated as unsigned integer, can be losslessly truncated to
+  /// the new bitwidth, then return truncated APInt. Else, return max value.
+  APInt truncUSat(unsigned width) const;
+
+  /// Truncate to new width with signed saturation.
+  ///
+  /// If this APInt, treated as signed integer, can be losslessly truncated to
+  /// the new bitwidth, then return truncated APInt. Else, return either
+  /// signed min value if the APInt was negative, or signed max value.
+  APInt truncSSat(unsigned width) const;
+
+  /// Sign extend to a new width.
+  ///
+  /// This operation sign extends the APInt to a new width. If the high order
+  /// bit is set, the fill on the left will be done with 1 bits, otherwise zero.
+  /// It is an error to specify a width that is less than or equal to the
+  /// current width.
+  APInt sext(unsigned width) const;
+
+  /// Zero extend to a new width.
+  ///
+  /// This operation zero extends the APInt to a new width. The high order bits
+  /// are filled with 0 bits.  It is an error to specify a width that is less
+  /// than or equal to the current width.
+  APInt zext(unsigned width) const;
+
+  /// Sign extend or truncate to width
+  ///
+  /// Make this APInt have the bit width given by \p width. The value is sign
+  /// extended, truncated, or left alone to make it that width.
+  APInt sextOrTrunc(unsigned width) const;
+
+  /// Zero extend or truncate to width
+  ///
+  /// Make this APInt have the bit width given by \p width. The value is zero
+  /// extended, truncated, or left alone to make it that width.
+  APInt zextOrTrunc(unsigned width) const;
+
+  /// Sign extend or truncate to width
+  ///
+  /// Make this APInt have the bit width given by \p width. The value is sign
+  /// extended, or left alone to make it that width.
+  APInt sextOrSelf(unsigned width) const;
+
+  /// Zero extend or truncate to width
+  ///
+  /// Make this APInt have the bit width given by \p width. The value is zero
+  /// extended, or left alone to make it that width.
+  APInt zextOrSelf(unsigned width) const;
+
+  /// @}
+  /// \name Bit Manipulation Operators
+  /// @{
+
+  /// Set every bit to 1.
+  void setAllBits() {
+    if (isSingleWord())
+      U.VAL = WORDTYPE_MAX;
+    else
+      // Set all the bits in all the words.
+      memset(U.pVal, -1, getNumWords() * APINT_WORD_SIZE);
+    // Clear the unused ones
+    clearUnusedBits();
+  }
+
+  /// Set a given bit to 1.
+  ///
+  /// Set the given bit to 1 whose position is given as "bitPosition".
+  void setBit(unsigned BitPosition) {
+    assert(BitPosition < BitWidth && "BitPosition out of range");
+    WordType Mask = maskBit(BitPosition);
+    if (isSingleWord())
+      U.VAL |= Mask;
+    else
+      U.pVal[whichWord(BitPosition)] |= Mask;
+  }
+
+  /// Set the sign bit to 1.
+  void setSignBit() {
+    setBit(BitWidth - 1);
+  }
+
+  /// Set the bits from loBit (inclusive) to hiBit (exclusive) to 1.
+  void setBits(unsigned loBit, unsigned hiBit) {
+    assert(hiBit <= BitWidth && "hiBit out of range");
+    assert(loBit <= BitWidth && "loBit out of range");
+    assert(loBit <= hiBit && "loBit greater than hiBit");
+    if (loBit == hiBit)
+      return;
+    if (loBit < APINT_BITS_PER_WORD && hiBit <= APINT_BITS_PER_WORD) {
+      uint64_t mask = WORDTYPE_MAX >> (APINT_BITS_PER_WORD - (hiBit - loBit));
+      mask <<= loBit;
+      if (isSingleWord())
+        U.VAL |= mask;
+      else
+        U.pVal[0] |= mask;
+    } else {
+      setBitsSlowCase(loBit, hiBit);
+    }
+  }
+
+  /// Set the top bits starting from loBit.
+  void setBitsFrom(unsigned loBit) {
+    return setBits(loBit, BitWidth);
+  }
+
+  /// Set the bottom loBits bits.
+  void setLowBits(unsigned loBits) {
+    return setBits(0, loBits);
+  }
+
+  /// Set the top hiBits bits.
+  void setHighBits(unsigned hiBits) {
+    return setBits(BitWidth - hiBits, BitWidth);
+  }
+
+  /// Set every bit to 0.
+  void clearAllBits() {
+    if (isSingleWord())
+      U.VAL = 0;
+    else
+      memset(U.pVal, 0, getNumWords() * APINT_WORD_SIZE);
+  }
+
+  /// Set a given bit to 0.
+  ///
+  /// Set the given bit to 0 whose position is given as "bitPosition".
+  void clearBit(unsigned BitPosition) {
+    assert(BitPosition < BitWidth && "BitPosition out of range");
+    WordType Mask = ~maskBit(BitPosition);
+    if (isSingleWord())
+      U.VAL &= Mask;
+    else
+      U.pVal[whichWord(BitPosition)] &= Mask;
+  }
+
+  /// Set bottom loBits bits to 0.
+  void clearLowBits(unsigned loBits) {
+    assert(loBits <= BitWidth && "More bits than bitwidth");
+    APInt Keep = getHighBitsSet(BitWidth, BitWidth - loBits);
+    *this &= Keep;
+  }
+
+  /// Set the sign bit to 0.
+  void clearSignBit() {
+    clearBit(BitWidth - 1);
+  }
+
+  /// Toggle every bit to its opposite value.
+  void flipAllBits() {
+    if (isSingleWord()) {
+      U.VAL ^= WORDTYPE_MAX;
+      clearUnusedBits();
+    } else {
+      flipAllBitsSlowCase();
+    }
+  }
+
+  /// Toggles a given bit to its opposite value.
+  ///
+  /// Toggle a given bit to its opposite value whose position is given
+  /// as "bitPosition".
+  void flipBit(unsigned bitPosition);
+
+  /// Negate this APInt in place.
+  void negate() {
+    flipAllBits();
+    ++(*this);
+  }
+
+  /// Insert the bits from a smaller APInt starting at bitPosition.
+  void insertBits(const APInt &SubBits, unsigned bitPosition);
+  void insertBits(uint64_t SubBits, unsigned bitPosition, unsigned numBits);
+
+  /// Return an APInt with the extracted bits [bitPosition,bitPosition+numBits).
+  APInt extractBits(unsigned numBits, unsigned bitPosition) const;
+  uint64_t extractBitsAsZExtValue(unsigned numBits, unsigned bitPosition) const;
+
+  /// @}
+  /// \name Value Characterization Functions
+  /// @{
+
+  /// Return the number of bits in the APInt.
+  unsigned getBitWidth() const { return BitWidth; }
+
+  /// Get the number of words.
+  ///
+  /// Here one word's bitwidth equals to that of uint64_t.
+  ///
+  /// \returns the number of words to hold the integer value of this APInt.
+  unsigned getNumWords() const { return getNumWords(BitWidth); }
+
+  /// Get the number of words.
+  ///
+  /// *NOTE* Here one word's bitwidth equals to that of uint64_t.
+  ///
+  /// \returns the number of words to hold the integer value with a given bit
+  /// width.
+  static unsigned getNumWords(unsigned BitWidth) {
+    return ((uint64_t)BitWidth + APINT_BITS_PER_WORD - 1) / APINT_BITS_PER_WORD;
+  }
+
+  /// Compute the number of active bits in the value
+  ///
+  /// This function returns the number of active bits which is defined as the
+  /// bit width minus the number of leading zeros. This is used in several
+  /// computations to see how "wide" the value is.
+  unsigned getActiveBits() const { return BitWidth - countLeadingZeros(); }
+
+  /// Compute the number of active words in the value of this APInt.
+  ///
+  /// This is used in conjunction with getActiveData to extract the raw value of
+  /// the APInt.
+  unsigned getActiveWords() const {
+    unsigned numActiveBits = getActiveBits();
+    return numActiveBits ? whichWord(numActiveBits - 1) + 1 : 1;
+  }
+
+  /// Get the minimum bit size for this signed APInt
+  ///
+  /// Computes the minimum bit width for this APInt while considering it to be a
+  /// signed (and probably negative) value. If the value is not negative, this
+  /// function returns the same value as getActiveBits()+1. Otherwise, it
+  /// returns the smallest bit width that will retain the negative value. For
+  /// example, -1 can be written as 0b1 or 0xFFFFFFFFFF. 0b1 is shorter and so
+  /// for -1, this function will always return 1.
+  unsigned getMinSignedBits() const {
+    if (isNegative())
+      return BitWidth - countLeadingOnes() + 1;
+    return getActiveBits() + 1;
+  }
+
+  /// Get zero extended value
+  ///
+  /// This method attempts to return the value of this APInt as a zero extended
+  /// uint64_t. The bitwidth must be <= 64 or the value must fit within a
+  /// uint64_t. Otherwise an assertion will result.
+  uint64_t getZExtValue() const {
+    if (isSingleWord())
+      return U.VAL;
+    assert(getActiveBits() <= 64 && "Too many bits for uint64_t");
+    return U.pVal[0];
+  }
+
+  /// Get sign extended value
+  ///
+  /// This method attempts to return the value of this APInt as a sign extended
+  /// int64_t. The bit width must be <= 64 or the value must fit within an
+  /// int64_t. Otherwise an assertion will result.
+  int64_t getSExtValue() const {
+    if (isSingleWord())
+      return SignExtend64(U.VAL, BitWidth);
+    assert(getMinSignedBits() <= 64 && "Too many bits for int64_t");
+    return int64_t(U.pVal[0]);
+  }
+
+  /// Get bits required for string value.
+  ///
+  /// This method determines how many bits are required to hold the APInt
+  /// equivalent of the string given by \p str.
+  static unsigned getBitsNeeded(StringRef str, uint8_t radix);
+
+  /// The APInt version of the countLeadingZeros functions in
+  ///   MathExtras.h.
+  ///
+  /// It counts the number of zeros from the most significant bit to the first
+  /// one bit.
+  ///
+  /// \returns BitWidth if the value is zero, otherwise returns the number of
+  ///   zeros from the most significant bit to the first one bits.
+  unsigned countLeadingZeros() const {
+    if (isSingleWord()) {
+      unsigned unusedBits = APINT_BITS_PER_WORD - BitWidth;
+      return llvm::countLeadingZeros(U.VAL) - unusedBits;
+    }
+    return countLeadingZerosSlowCase();
+  }
+
+  /// Count the number of leading one bits.
+  ///
+  /// This function is an APInt version of the countLeadingOnes
+  /// functions in MathExtras.h. It counts the number of ones from the most
+  /// significant bit to the first zero bit.
+  ///
+  /// \returns 0 if the high order bit is not set, otherwise returns the number
+  /// of 1 bits from the most significant to the least
+  unsigned countLeadingOnes() const {
+    if (isSingleWord())
+      return llvm::countLeadingOnes(U.VAL << (APINT_BITS_PER_WORD - BitWidth));
+    return countLeadingOnesSlowCase();
+  }
+
+  /// Computes the number of leading bits of this APInt that are equal to its
+  /// sign bit.
+  unsigned getNumSignBits() const {
+    return isNegative() ? countLeadingOnes() : countLeadingZeros();
+  }
+
+  /// Count the number of trailing zero bits.
+  ///
+  /// This function is an APInt version of the countTrailingZeros
+  /// functions in MathExtras.h. It counts the number of zeros from the least
+  /// significant bit to the first set bit.
+  ///
+  /// \returns BitWidth if the value is zero, otherwise returns the number of
+  /// zeros from the least significant bit to the first one bit.
+  unsigned countTrailingZeros() const {
+    if (isSingleWord())
+      return std::min(unsigned(llvm::countTrailingZeros(U.VAL)), BitWidth);
+    return countTrailingZerosSlowCase();
+  }
+
+  /// Count the number of trailing one bits.
+  ///
+  /// This function is an APInt version of the countTrailingOnes
+  /// functions in MathExtras.h. It counts the number of ones from the least
+  /// significant bit to the first zero bit.
+  ///
+  /// \returns BitWidth if the value is all ones, otherwise returns the number
+  /// of ones from the least significant bit to the first zero bit.
+  unsigned countTrailingOnes() const {
+    if (isSingleWord())
+      return llvm::countTrailingOnes(U.VAL);
+    return countTrailingOnesSlowCase();
+  }
+
+  /// Count the number of bits set.
+  ///
+  /// This function is an APInt version of the countPopulation functions
+  /// in MathExtras.h. It counts the number of 1 bits in the APInt value.
+  ///
+  /// \returns 0 if the value is zero, otherwise returns the number of set bits.
+  unsigned countPopulation() const {
+    if (isSingleWord())
+      return llvm::countPopulation(U.VAL);
+    return countPopulationSlowCase();
+  }
+
+  /// @}
+  /// \name Conversion Functions
+  /// @{
+  void print(raw_ostream &OS, bool isSigned) const;
+
+  /// Converts an APInt to a string and append it to Str.  Str is commonly a
+  /// SmallString.
+  void toString(SmallVectorImpl<char> &Str, unsigned Radix, bool Signed,
+                bool formatAsCLiteral = false) const;
+
+  /// Considers the APInt to be unsigned and converts it into a string in the
+  /// radix given. The radix can be 2, 8, 10 16, or 36.
+  void toStringUnsigned(SmallVectorImpl<char> &Str, unsigned Radix = 10) const {
+    toString(Str, Radix, false, false);
+  }
+
+  /// Considers the APInt to be signed and converts it into a string in the
+  /// radix given. The radix can be 2, 8, 10, 16, or 36.
+  void toStringSigned(SmallVectorImpl<char> &Str, unsigned Radix = 10) const {
+    toString(Str, Radix, true, false);
+  }
+
+  /// Return the APInt as a std::string.
+  ///
+  /// Note that this is an inefficient method.  It is better to pass in a
+  /// SmallVector/SmallString to the methods above to avoid thrashing the heap
+  /// for the string.
+  std::string toString(unsigned Radix, bool Signed) const;
+
+  /// \returns a byte-swapped representation of this APInt Value.
+  APInt byteSwap() const;
+
+  /// \returns the value with the bit representation reversed of this APInt
+  /// Value.
+  APInt reverseBits() const;
+
+  /// Converts this APInt to a double value.
+  double roundToDouble(bool isSigned) const;
+
+  /// Converts this unsigned APInt to a double value.
+  double roundToDouble() const { return roundToDouble(false); }
+
+  /// Converts this signed APInt to a double value.
+  double signedRoundToDouble() const { return roundToDouble(true); }
+
+  /// Converts APInt bits to a double
+  ///
+  /// The conversion does not do a translation from integer to double, it just
+  /// re-interprets the bits as a double. Note that it is valid to do this on
+  /// any bit width. Exactly 64 bits will be translated.
+  double bitsToDouble() const {
+    return BitsToDouble(getWord(0));
+  }
+
+  /// Converts APInt bits to a float
+  ///
+  /// The conversion does not do a translation from integer to float, it just
+  /// re-interprets the bits as a float. Note that it is valid to do this on
+  /// any bit width. Exactly 32 bits will be translated.
+  float bitsToFloat() const {
+    return BitsToFloat(static_cast<uint32_t>(getWord(0)));
+  }
+
+  /// Converts a double to APInt bits.
+  ///
+  /// The conversion does not do a translation from double to integer, it just
+  /// re-interprets the bits of the double.
+  static APInt doubleToBits(double V) {
+    return APInt(sizeof(double) * CHAR_BIT, DoubleToBits(V));
+  }
+
+  /// Converts a float to APInt bits.
+  ///
+  /// The conversion does not do a translation from float to integer, it just
+  /// re-interprets the bits of the float.
+  static APInt floatToBits(float V) {
+    return APInt(sizeof(float) * CHAR_BIT, FloatToBits(V));
+  }
+
+  /// @}
+  /// \name Mathematics Operations
+  /// @{
+
+  /// \returns the floor log base 2 of this APInt.
+  unsigned logBase2() const { return getActiveBits() -  1; }
+
+  /// \returns the ceil log base 2 of this APInt.
+  unsigned ceilLogBase2() const {
+    APInt temp(*this);
+    --temp;
+    return temp.getActiveBits();
+  }
+
+  /// \returns the nearest log base 2 of this APInt. Ties round up.
+  ///
+  /// NOTE: When we have a BitWidth of 1, we define:
+  ///
+  ///   log2(0) = UINT32_MAX
+  ///   log2(1) = 0
+  ///
+  /// to get around any mathematical concerns resulting from
+  /// referencing 2 in a space where 2 does no exist.
+  unsigned nearestLogBase2() const {
+    // Special case when we have a bitwidth of 1. If VAL is 1, then we
+    // get 0. If VAL is 0, we get WORDTYPE_MAX which gets truncated to
+    // UINT32_MAX.
+    if (BitWidth == 1)
+      return U.VAL - 1;
+
+    // Handle the zero case.
+    if (isNullValue())
+      return UINT32_MAX;
+
+    // The non-zero case is handled by computing:
+    //
+    //   nearestLogBase2(x) = logBase2(x) + x[logBase2(x)-1].
+    //
+    // where x[i] is referring to the value of the ith bit of x.
+    unsigned lg = logBase2();
+    return lg + unsigned((*this)[lg - 1]);
+  }
+
+  /// \returns the log base 2 of this APInt if its an exact power of two, -1
+  /// otherwise
+  int32_t exactLogBase2() const {
+    if (!isPowerOf2())
+      return -1;
+    return logBase2();
+  }
+
+  /// Compute the square root
+  APInt sqrt() const;
+
+  /// Get the absolute value;
+  ///
+  /// If *this is < 0 then return -(*this), otherwise *this;
+  APInt abs() const {
+    if (isNegative())
+      return -(*this);
+    return *this;
+  }
+
+  /// \returns the multiplicative inverse for a given modulo.
+  APInt multiplicativeInverse(const APInt &modulo) const;
+
+  /// @}
+  /// \name Support for division by constant
+  /// @{
+
+  /// Calculate the magic number for signed division by a constant.
+  struct ms;
+  ms magic() const;
+
+  /// Calculate the magic number for unsigned division by a constant.
+  struct mu;
+  mu magicu(unsigned LeadingZeros = 0) const;
+
+  /// @}
+  /// \name Building-block Operations for APInt and APFloat
+  /// @{
+
+  // These building block operations operate on a representation of arbitrary
+  // precision, two's-complement, bignum integer values. They should be
+  // sufficient to implement APInt and APFloat bignum requirements. Inputs are
+  // generally a pointer to the base of an array of integer parts, representing
+  // an unsigned bignum, and a count of how many parts there are.
+
+  /// Sets the least significant part of a bignum to the input value, and zeroes
+  /// out higher parts.
+  static void tcSet(WordType *, WordType, unsigned);
+
+  /// Assign one bignum to another.
+  static void tcAssign(WordType *, const WordType *, unsigned);
+
+  /// Returns true if a bignum is zero, false otherwise.
+  static bool tcIsZero(const WordType *, unsigned);
+
+  /// Extract the given bit of a bignum; returns 0 or 1.  Zero-based.
+  static int tcExtractBit(const WordType *, unsigned bit);
+
+  /// Copy the bit vector of width srcBITS from SRC, starting at bit srcLSB, to
+  /// DST, of dstCOUNT parts, such that the bit srcLSB becomes the least
+  /// significant bit of DST.  All high bits above srcBITS in DST are
+  /// zero-filled.
+  static void tcExtract(WordType *, unsigned dstCount,
+                        const WordType *, unsigned srcBits,
+                        unsigned srcLSB);
+
+  /// Set the given bit of a bignum.  Zero-based.
+  static void tcSetBit(WordType *, unsigned bit);
+
+  /// Clear the given bit of a bignum.  Zero-based.
+  static void tcClearBit(WordType *, unsigned bit);
+
+  /// Returns the bit number of the least or most significant set bit of a
+  /// number.  If the input number has no bits set -1U is returned.
+  static unsigned tcLSB(const WordType *, unsigned n);
+  static unsigned tcMSB(const WordType *parts, unsigned n);
+
+  /// Negate a bignum in-place.
+  static void tcNegate(WordType *, unsigned);
+
+  /// DST += RHS + CARRY where CARRY is zero or one.  Returns the carry flag.
+  static WordType tcAdd(WordType *, const WordType *,
+                        WordType carry, unsigned);
+  /// DST += RHS.  Returns the carry flag.
+  static WordType tcAddPart(WordType *, WordType, unsigned);
+
+  /// DST -= RHS + CARRY where CARRY is zero or one. Returns the carry flag.
+  static WordType tcSubtract(WordType *, const WordType *,
+                             WordType carry, unsigned);
+  /// DST -= RHS.  Returns the carry flag.
+  static WordType tcSubtractPart(WordType *, WordType, unsigned);
+
+  /// DST += SRC * MULTIPLIER + PART   if add is true
+  /// DST  = SRC * MULTIPLIER + PART   if add is false
+  ///
+  /// Requires 0 <= DSTPARTS <= SRCPARTS + 1.  If DST overlaps SRC they must
+  /// start at the same point, i.e. DST == SRC.
+  ///
+  /// If DSTPARTS == SRC_PARTS + 1 no overflow occurs and zero is returned.
+  /// Otherwise DST is filled with the least significant DSTPARTS parts of the
+  /// result, and if all of the omitted higher parts were zero return zero,
+  /// otherwise overflow occurred and return one.
+  static int tcMultiplyPart(WordType *dst, const WordType *src,
+                            WordType multiplier, WordType carry,
+                            unsigned srcParts, unsigned dstParts,
+                            bool add);
+
+  /// DST = LHS * RHS, where DST has the same width as the operands and is
+  /// filled with the least significant parts of the result.  Returns one if
+  /// overflow occurred, otherwise zero.  DST must be disjoint from both
+  /// operands.
+  static int tcMultiply(WordType *, const WordType *, const WordType *,
+                        unsigned);
+
+  /// DST = LHS * RHS, where DST has width the sum of the widths of the
+  /// operands. No overflow occurs. DST must be disjoint from both operands.
+  static void tcFullMultiply(WordType *, const WordType *,
+                             const WordType *, unsigned, unsigned);
+
+  /// If RHS is zero LHS and REMAINDER are left unchanged, return one.
+  /// Otherwise set LHS to LHS / RHS with the fractional part discarded, set
+  /// REMAINDER to the remainder, return zero.  i.e.
+  ///
+  ///  OLD_LHS = RHS * LHS + REMAINDER
+  ///
+  /// SCRATCH is a bignum of the same size as the operands and result for use by
+  /// the routine; its contents need not be initialized and are destroyed.  LHS,
+  /// REMAINDER and SCRATCH must be distinct.
+  static int tcDivide(WordType *lhs, const WordType *rhs,
+                      WordType *remainder, WordType *scratch,
+                      unsigned parts);
+
+  /// Shift a bignum left Count bits. Shifted in bits are zero. There are no
+  /// restrictions on Count.
+  static void tcShiftLeft(WordType *, unsigned Words, unsigned Count);
+
+  /// Shift a bignum right Count bits.  Shifted in bits are zero.  There are no
+  /// restrictions on Count.
+  static void tcShiftRight(WordType *, unsigned Words, unsigned Count);
+
+  /// The obvious AND, OR and XOR and complement operations.
+  static void tcAnd(WordType *, const WordType *, unsigned);
+  static void tcOr(WordType *, const WordType *, unsigned);
+  static void tcXor(WordType *, const WordType *, unsigned);
+  static void tcComplement(WordType *, unsigned);
+
+  /// Comparison (unsigned) of two bignums.
+  static int tcCompare(const WordType *, const WordType *, unsigned);
+
+  /// Increment a bignum in-place.  Return the carry flag.
+  static WordType tcIncrement(WordType *dst, unsigned parts) {
+    return tcAddPart(dst, 1, parts);
+  }
+
+  /// Decrement a bignum in-place.  Return the borrow flag.
+  static WordType tcDecrement(WordType *dst, unsigned parts) {
+    return tcSubtractPart(dst, 1, parts);
+  }
+
+  /// Set the least significant BITS and clear the rest.
+  static void tcSetLeastSignificantBits(WordType *, unsigned, unsigned bits);
+
+  /// debug method
+  void dump() const;
+
+  /// @}
+};
+
+/// Magic data for optimising signed division by a constant.
+struct APInt::ms {
+  APInt m;    ///< magic number
+  unsigned s; ///< shift amount
+};
+
+/// Magic data for optimising unsigned division by a constant.
+struct APInt::mu {
+  APInt m;    ///< magic number
+  bool a;     ///< add indicator
+  unsigned s; ///< shift amount
+};
+
+inline bool operator==(uint64_t V1, const APInt &V2) { return V2 == V1; }
+
+inline bool operator!=(uint64_t V1, const APInt &V2) { return V2 != V1; }
+
+/// Unary bitwise complement operator.
+///
+/// \returns an APInt that is the bitwise complement of \p v.
+inline APInt operator~(APInt v) {
+  v.flipAllBits();
+  return v;
+}
+
+inline APInt operator&(APInt a, const APInt &b) {
+  a &= b;
+  return a;
+}
+
+inline APInt operator&(const APInt &a, APInt &&b) {
+  b &= a;
+  return std::move(b);
+}
+
+inline APInt operator&(APInt a, uint64_t RHS) {
+  a &= RHS;
+  return a;
+}
+
+inline APInt operator&(uint64_t LHS, APInt b) {
+  b &= LHS;
+  return b;
+}
+
+inline APInt operator|(APInt a, const APInt &b) {
+  a |= b;
+  return a;
+}
+
+inline APInt operator|(const APInt &a, APInt &&b) {
+  b |= a;
+  return std::move(b);
+}
+
+inline APInt operator|(APInt a, uint64_t RHS) {
+  a |= RHS;
+  return a;
+}
+
+inline APInt operator|(uint64_t LHS, APInt b) {
+  b |= LHS;
+  return b;
+}
+
+inline APInt operator^(APInt a, const APInt &b) {
+  a ^= b;
+  return a;
+}
+
+inline APInt operator^(const APInt &a, APInt &&b) {
+  b ^= a;
+  return std::move(b);
+}
+
+inline APInt operator^(APInt a, uint64_t RHS) {
+  a ^= RHS;
+  return a;
+}
+
+inline APInt operator^(uint64_t LHS, APInt b) {
+  b ^= LHS;
+  return b;
+}
+
+inline raw_ostream &operator<<(raw_ostream &OS, const APInt &I) {
+  I.print(OS, true);
+  return OS;
+}
+
+inline APInt operator-(APInt v) {
+  v.negate();
+  return v;
+}
+
+inline APInt operator+(APInt a, const APInt &b) {
+  a += b;
+  return a;
+}
+
+inline APInt operator+(const APInt &a, APInt &&b) {
+  b += a;
+  return std::move(b);
+}
+
+inline APInt operator+(APInt a, uint64_t RHS) {
+  a += RHS;
+  return a;
+}
+
+inline APInt operator+(uint64_t LHS, APInt b) {
+  b += LHS;
+  return b;
+}
+
+inline APInt operator-(APInt a, const APInt &b) {
+  a -= b;
+  return a;
+}
+
+inline APInt operator-(const APInt &a, APInt &&b) {
+  b.negate();
+  b += a;
+  return std::move(b);
+}
+
+inline APInt operator-(APInt a, uint64_t RHS) {
+  a -= RHS;
+  return a;
+}
+
+inline APInt operator-(uint64_t LHS, APInt b) {
+  b.negate();
+  b += LHS;
+  return b;
+}
+
+inline APInt operator*(APInt a, uint64_t RHS) {
+  a *= RHS;
+  return a;
+}
+
+inline APInt operator*(uint64_t LHS, APInt b) {
+  b *= LHS;
+  return b;
+}
+
+
+namespace APIntOps {
+
+/// Determine the smaller of two APInts considered to be signed.
+inline const APInt &smin(const APInt &A, const APInt &B) {
+  return A.slt(B) ? A : B;
+}
+
+/// Determine the larger of two APInts considered to be signed.
+inline const APInt &smax(const APInt &A, const APInt &B) {
+  return A.sgt(B) ? A : B;
+}
+
+/// Determine the smaller of two APInts considered to be signed.
+inline const APInt &umin(const APInt &A, const APInt &B) {
+  return A.ult(B) ? A : B;
+}
+
+/// Determine the larger of two APInts considered to be unsigned.
+inline const APInt &umax(const APInt &A, const APInt &B) {
+  return A.ugt(B) ? A : B;
+}
+
+/// Compute GCD of two unsigned APInt values.
+///
+/// This function returns the greatest common divisor of the two APInt values
+/// using Stein's algorithm.
+///
+/// \returns the greatest common divisor of A and B.
+APInt GreatestCommonDivisor(APInt A, APInt B);
+
+/// Converts the given APInt to a double value.
+///
+/// Treats the APInt as an unsigned value for conversion purposes.
+inline double RoundAPIntToDouble(const APInt &APIVal) {
+  return APIVal.roundToDouble();
+}
+
+/// Converts the given APInt to a double value.
+///
+/// Treats the APInt as a signed value for conversion purposes.
+inline double RoundSignedAPIntToDouble(const APInt &APIVal) {
+  return APIVal.signedRoundToDouble();
+}
+
+/// Converts the given APInt to a float vlalue.
+inline float RoundAPIntToFloat(const APInt &APIVal) {
+  return float(RoundAPIntToDouble(APIVal));
+}
+
+/// Converts the given APInt to a float value.
+///
+/// Treats the APInt as a signed value for conversion purposes.
+inline float RoundSignedAPIntToFloat(const APInt &APIVal) {
+  return float(APIVal.signedRoundToDouble());
+}
+
+/// Converts the given double value into a APInt.
+///
+/// This function convert a double value to an APInt value.
+APInt RoundDoubleToAPInt(double Double, unsigned width);
+
+/// Converts a float value into a APInt.
+///
+/// Converts a float value into an APInt value.
+inline APInt RoundFloatToAPInt(float Float, unsigned width) {
+  return RoundDoubleToAPInt(double(Float), width);
+}
+
+/// Return A unsign-divided by B, rounded by the given rounding mode.
+APInt RoundingUDiv(const APInt &A, const APInt &B, APInt::Rounding RM);
+
+/// Return A sign-divided by B, rounded by the given rounding mode.
+APInt RoundingSDiv(const APInt &A, const APInt &B, APInt::Rounding RM);
+
+/// Let q(n) = An^2 + Bn + C, and BW = bit width of the value range
+/// (e.g. 32 for i32).
+/// This function finds the smallest number n, such that
+/// (a) n >= 0 and q(n) = 0, or
+/// (b) n >= 1 and q(n-1) and q(n), when evaluated in the set of all
+///     integers, belong to two different intervals [Rk, Rk+R),
+///     where R = 2^BW, and k is an integer.
+/// The idea here is to find when q(n) "overflows" 2^BW, while at the
+/// same time "allowing" subtraction. In unsigned modulo arithmetic a
+/// subtraction (treated as addition of negated numbers) would always
+/// count as an overflow, but here we want to allow values to decrease
+/// and increase as long as they are within the same interval.
+/// Specifically, adding of two negative numbers should not cause an
+/// overflow (as long as the magnitude does not exceed the bit width).
+/// On the other hand, given a positive number, adding a negative
+/// number to it can give a negative result, which would cause the
+/// value to go from [-2^BW, 0) to [0, 2^BW). In that sense, zero is
+/// treated as a special case of an overflow.
+///
+/// This function returns None if after finding k that minimizes the
+/// positive solution to q(n) = kR, both solutions are contained between
+/// two consecutive integers.
+///
+/// There are cases where q(n) > T, and q(n+1) < T (assuming evaluation
+/// in arithmetic modulo 2^BW, and treating the values as signed) by the
+/// virtue of *signed* overflow. This function will *not* find such an n,
+/// however it may find a value of n satisfying the inequalities due to
+/// an *unsigned* overflow (if the values are treated as unsigned).
+/// To find a solution for a signed overflow, treat it as a problem of
+/// finding an unsigned overflow with a range with of BW-1.
+///
+/// The returned value may have a different bit width from the input
+/// coefficients.
+Optional<APInt> SolveQuadraticEquationWrap(APInt A, APInt B, APInt C,
+                                           unsigned RangeWidth);
+
+/// Compare two values, and if they are different, return the position of the
+/// most significant bit that is different in the values.
+Optional<unsigned> GetMostSignificantDifferentBit(const APInt &A,
+                                                  const APInt &B);
+
+} // End of APIntOps namespace
+
+// See friend declaration above. This additional declaration is required in
+// order to compile LLVM with IBM xlC compiler.
+hash_code hash_value(const APInt &Arg);
+
+/// StoreIntToMemory - Fills the StoreBytes bytes of memory starting from Dst
+/// with the integer held in IntVal.
+void StoreIntToMemory(const APInt &IntVal, uint8_t *Dst, unsigned StoreBytes);
+
+/// LoadIntFromMemory - Loads the integer stored in the LoadBytes bytes starting
+/// from Src into IntVal, which is assumed to be wide enough and to hold zero.
+void LoadIntFromMemory(APInt &IntVal, uint8_t *Src, unsigned LoadBytes);
+
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/APSInt.h b/binaryen/third_party/llvm-project/include/llvm/ADT/APSInt.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/APSInt.h
@@ -0,0 +1,353 @@
+//===-- llvm/ADT/APSInt.h - Arbitrary Precision Signed Int -----*- C++ -*--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the APSInt class, which is a simple class that
+// represents an arbitrary sized integer that knows its signedness.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_APSINT_H
+#define LLVM_ADT_APSINT_H
+
+#include "llvm/ADT/APInt.h"
+
+namespace llvm {
+
+class LLVM_NODISCARD APSInt : public APInt {
+  bool IsUnsigned;
+
+public:
+  /// Default constructor that creates an uninitialized APInt.
+  explicit APSInt() : IsUnsigned(false) {}
+
+  /// APSInt ctor - Create an APSInt with the specified width, default to
+  /// unsigned.
+  explicit APSInt(uint32_t BitWidth, bool isUnsigned = true)
+   : APInt(BitWidth, 0), IsUnsigned(isUnsigned) {}
+
+  explicit APSInt(APInt I, bool isUnsigned = true)
+   : APInt(std::move(I)), IsUnsigned(isUnsigned) {}
+
+  /// Construct an APSInt from a string representation.
+  ///
+  /// This constructor interprets the string \p Str using the radix of 10.
+  /// The interpretation stops at the end of the string. The bit width of the
+  /// constructed APSInt is determined automatically.
+  ///
+  /// \param Str the string to be interpreted.
+  explicit APSInt(StringRef Str);
+
+  /// Determine sign of this APSInt.
+  ///
+  /// \returns true if this APSInt is negative, false otherwise
+  bool isNegative() const { return isSigned() && APInt::isNegative(); }
+
+  /// Determine if this APSInt Value is non-negative (>= 0)
+  ///
+  /// \returns true if this APSInt is non-negative, false otherwise
+  bool isNonNegative() const { return !isNegative(); }
+
+  /// Determine if this APSInt Value is positive.
+  ///
+  /// This tests if the value of this APSInt is positive (> 0). Note
+  /// that 0 is not a positive value.
+  ///
+  /// \returns true if this APSInt is positive.
+  bool isStrictlyPositive() const { return isNonNegative() && !isNullValue(); }
+
+  APSInt &operator=(APInt RHS) {
+    // Retain our current sign.
+    APInt::operator=(std::move(RHS));
+    return *this;
+  }
+
+  APSInt &operator=(uint64_t RHS) {
+    // Retain our current sign.
+    APInt::operator=(RHS);
+    return *this;
+  }
+
+  // Query sign information.
+  bool isSigned() const { return !IsUnsigned; }
+  bool isUnsigned() const { return IsUnsigned; }
+  void setIsUnsigned(bool Val) { IsUnsigned = Val; }
+  void setIsSigned(bool Val) { IsUnsigned = !Val; }
+
+  /// toString - Append this APSInt to the specified SmallString.
+  void toString(SmallVectorImpl<char> &Str, unsigned Radix = 10) const {
+    APInt::toString(Str, Radix, isSigned());
+  }
+  /// toString - Converts an APInt to a std::string.  This is an inefficient
+  /// method; you should prefer passing in a SmallString instead.
+  std::string toString(unsigned Radix) const {
+    return APInt::toString(Radix, isSigned());
+  }
+  using APInt::toString;
+
+  /// Get the correctly-extended \c int64_t value.
+  int64_t getExtValue() const {
+    assert(getMinSignedBits() <= 64 && "Too many bits for int64_t");
+    return isSigned() ? getSExtValue() : getZExtValue();
+  }
+
+  APSInt trunc(uint32_t width) const {
+    return APSInt(APInt::trunc(width), IsUnsigned);
+  }
+
+  APSInt extend(uint32_t width) const {
+    if (IsUnsigned)
+      return APSInt(zext(width), IsUnsigned);
+    else
+      return APSInt(sext(width), IsUnsigned);
+  }
+
+  APSInt extOrTrunc(uint32_t width) const {
+    if (IsUnsigned)
+      return APSInt(zextOrTrunc(width), IsUnsigned);
+    else
+      return APSInt(sextOrTrunc(width), IsUnsigned);
+  }
+
+  const APSInt &operator%=(const APSInt &RHS) {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    if (IsUnsigned)
+      *this = urem(RHS);
+    else
+      *this = srem(RHS);
+    return *this;
+  }
+  const APSInt &operator/=(const APSInt &RHS) {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    if (IsUnsigned)
+      *this = udiv(RHS);
+    else
+      *this = sdiv(RHS);
+    return *this;
+  }
+  APSInt operator%(const APSInt &RHS) const {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    return IsUnsigned ? APSInt(urem(RHS), true) : APSInt(srem(RHS), false);
+  }
+  APSInt operator/(const APSInt &RHS) const {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    return IsUnsigned ? APSInt(udiv(RHS), true) : APSInt(sdiv(RHS), false);
+  }
+
+  APSInt operator>>(unsigned Amt) const {
+    return IsUnsigned ? APSInt(lshr(Amt), true) : APSInt(ashr(Amt), false);
+  }
+  APSInt& operator>>=(unsigned Amt) {
+    if (IsUnsigned)
+      lshrInPlace(Amt);
+    else
+      ashrInPlace(Amt);
+    return *this;
+  }
+
+  inline bool operator<(const APSInt& RHS) const {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    return IsUnsigned ? ult(RHS) : slt(RHS);
+  }
+  inline bool operator>(const APSInt& RHS) const {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    return IsUnsigned ? ugt(RHS) : sgt(RHS);
+  }
+  inline bool operator<=(const APSInt& RHS) const {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    return IsUnsigned ? ule(RHS) : sle(RHS);
+  }
+  inline bool operator>=(const APSInt& RHS) const {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    return IsUnsigned ? uge(RHS) : sge(RHS);
+  }
+  inline bool operator==(const APSInt& RHS) const {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    return eq(RHS);
+  }
+  inline bool operator!=(const APSInt& RHS) const {
+    return !((*this) == RHS);
+  }
+
+  bool operator==(int64_t RHS) const {
+    return compareValues(*this, get(RHS)) == 0;
+  }
+  bool operator!=(int64_t RHS) const {
+    return compareValues(*this, get(RHS)) != 0;
+  }
+  bool operator<=(int64_t RHS) const {
+    return compareValues(*this, get(RHS)) <= 0;
+  }
+  bool operator>=(int64_t RHS) const {
+    return compareValues(*this, get(RHS)) >= 0;
+  }
+  bool operator<(int64_t RHS) const {
+    return compareValues(*this, get(RHS)) < 0;
+  }
+  bool operator>(int64_t RHS) const {
+    return compareValues(*this, get(RHS)) > 0;
+  }
+
+  // The remaining operators just wrap the logic of APInt, but retain the
+  // signedness information.
+
+  APSInt operator<<(unsigned Bits) const {
+    return APSInt(static_cast<const APInt&>(*this) << Bits, IsUnsigned);
+  }
+  APSInt& operator<<=(unsigned Amt) {
+    static_cast<APInt&>(*this) <<= Amt;
+    return *this;
+  }
+
+  APSInt& operator++() {
+    ++(static_cast<APInt&>(*this));
+    return *this;
+  }
+  APSInt& operator--() {
+    --(static_cast<APInt&>(*this));
+    return *this;
+  }
+  APSInt operator++(int) {
+    return APSInt(++static_cast<APInt&>(*this), IsUnsigned);
+  }
+  APSInt operator--(int) {
+    return APSInt(--static_cast<APInt&>(*this), IsUnsigned);
+  }
+  APSInt operator-() const {
+    return APSInt(-static_cast<const APInt&>(*this), IsUnsigned);
+  }
+  APSInt& operator+=(const APSInt& RHS) {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    static_cast<APInt&>(*this) += RHS;
+    return *this;
+  }
+  APSInt& operator-=(const APSInt& RHS) {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    static_cast<APInt&>(*this) -= RHS;
+    return *this;
+  }
+  APSInt& operator*=(const APSInt& RHS) {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    static_cast<APInt&>(*this) *= RHS;
+    return *this;
+  }
+  APSInt& operator&=(const APSInt& RHS) {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    static_cast<APInt&>(*this) &= RHS;
+    return *this;
+  }
+  APSInt& operator|=(const APSInt& RHS) {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    static_cast<APInt&>(*this) |= RHS;
+    return *this;
+  }
+  APSInt& operator^=(const APSInt& RHS) {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    static_cast<APInt&>(*this) ^= RHS;
+    return *this;
+  }
+
+  APSInt operator&(const APSInt& RHS) const {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    return APSInt(static_cast<const APInt&>(*this) & RHS, IsUnsigned);
+  }
+
+  APSInt operator|(const APSInt& RHS) const {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    return APSInt(static_cast<const APInt&>(*this) | RHS, IsUnsigned);
+  }
+
+  APSInt operator^(const APSInt &RHS) const {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    return APSInt(static_cast<const APInt&>(*this) ^ RHS, IsUnsigned);
+  }
+
+  APSInt operator*(const APSInt& RHS) const {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    return APSInt(static_cast<const APInt&>(*this) * RHS, IsUnsigned);
+  }
+  APSInt operator+(const APSInt& RHS) const {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    return APSInt(static_cast<const APInt&>(*this) + RHS, IsUnsigned);
+  }
+  APSInt operator-(const APSInt& RHS) const {
+    assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
+    return APSInt(static_cast<const APInt&>(*this) - RHS, IsUnsigned);
+  }
+  APSInt operator~() const {
+    return APSInt(~static_cast<const APInt&>(*this), IsUnsigned);
+  }
+
+  /// getMaxValue - Return the APSInt representing the maximum integer value
+  ///  with the given bit width and signedness.
+  static APSInt getMaxValue(uint32_t numBits, bool Unsigned) {
+    return APSInt(Unsigned ? APInt::getMaxValue(numBits)
+                           : APInt::getSignedMaxValue(numBits), Unsigned);
+  }
+
+  /// getMinValue - Return the APSInt representing the minimum integer value
+  ///  with the given bit width and signedness.
+  static APSInt getMinValue(uint32_t numBits, bool Unsigned) {
+    return APSInt(Unsigned ? APInt::getMinValue(numBits)
+                           : APInt::getSignedMinValue(numBits), Unsigned);
+  }
+
+  /// Determine if two APSInts have the same value, zero- or
+  /// sign-extending as needed.
+  static bool isSameValue(const APSInt &I1, const APSInt &I2) {
+    return !compareValues(I1, I2);
+  }
+
+  /// Compare underlying values of two numbers.
+  static int compareValues(const APSInt &I1, const APSInt &I2) {
+    if (I1.getBitWidth() == I2.getBitWidth() && I1.isSigned() == I2.isSigned())
+      return I1.IsUnsigned ? I1.compare(I2) : I1.compareSigned(I2);
+
+    // Check for a bit-width mismatch.
+    if (I1.getBitWidth() > I2.getBitWidth())
+      return compareValues(I1, I2.extend(I1.getBitWidth()));
+    if (I2.getBitWidth() > I1.getBitWidth())
+      return compareValues(I1.extend(I2.getBitWidth()), I2);
+
+    // We have a signedness mismatch. Check for negative values and do an
+    // unsigned compare if both are positive.
+    if (I1.isSigned()) {
+      assert(!I2.isSigned() && "Expected signed mismatch");
+      if (I1.isNegative())
+        return -1;
+    } else {
+      assert(I2.isSigned() && "Expected signed mismatch");
+      if (I2.isNegative())
+        return 1;
+    }
+
+    return I1.compare(I2);
+  }
+
+  static APSInt get(int64_t X) { return APSInt(APInt(64, X), false); }
+  static APSInt getUnsigned(uint64_t X) { return APSInt(APInt(64, X), true); }
+
+  /// Profile - Used to insert APSInt objects, or objects that contain APSInt
+  ///  objects, into FoldingSets.
+  void Profile(FoldingSetNodeID& ID) const;
+};
+
+inline bool operator==(int64_t V1, const APSInt &V2) { return V2 == V1; }
+inline bool operator!=(int64_t V1, const APSInt &V2) { return V2 != V1; }
+inline bool operator<=(int64_t V1, const APSInt &V2) { return V2 >= V1; }
+inline bool operator>=(int64_t V1, const APSInt &V2) { return V2 <= V1; }
+inline bool operator<(int64_t V1, const APSInt &V2) { return V2 > V1; }
+inline bool operator>(int64_t V1, const APSInt &V2) { return V2 < V1; }
+
+inline raw_ostream &operator<<(raw_ostream &OS, const APSInt &I) {
+  I.print(OS, I.isSigned());
+  return OS;
+}
+
+} // end namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/AllocatorList.h b/binaryen/third_party/llvm-project/include/llvm/ADT/AllocatorList.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/AllocatorList.h
@@ -0,0 +1,240 @@
+//===- llvm/ADT/AllocatorList.h - Custom allocator list ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_ALLOCATORLIST_H
+#define LLVM_ADT_ALLOCATORLIST_H
+
+#include "llvm/ADT/ilist_node.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/simple_ilist.h"
+#include "llvm/Support/Allocator.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+
+namespace llvm {
+
+/// A linked-list with a custom, local allocator.
+///
+/// Expose a std::list-like interface that owns and uses a custom LLVM-style
+/// allocator (e.g., BumpPtrAllocator), leveraging \a simple_ilist for the
+/// implementation details.
+///
+/// Because this list owns the allocator, calling \a splice() with a different
+/// list isn't generally safe.  As such, \a splice has been left out of the
+/// interface entirely.
+template <class T, class AllocatorT> class AllocatorList : AllocatorT {
+  struct Node : ilist_node<Node> {
+    Node(Node &&) = delete;
+    Node(const Node &) = delete;
+    Node &operator=(Node &&) = delete;
+    Node &operator=(const Node &) = delete;
+
+    Node(T &&V) : V(std::move(V)) {}
+    Node(const T &V) : V(V) {}
+    template <class... Ts> Node(Ts &&... Vs) : V(std::forward<Ts>(Vs)...) {}
+    T V;
+  };
+
+  using list_type = simple_ilist<Node>;
+
+  list_type List;
+
+  AllocatorT &getAlloc() { return *this; }
+  const AllocatorT &getAlloc() const { return *this; }
+
+  template <class... ArgTs> Node *create(ArgTs &&... Args) {
+    return new (getAlloc()) Node(std::forward<ArgTs>(Args)...);
+  }
+
+  struct Cloner {
+    AllocatorList &AL;
+
+    Cloner(AllocatorList &AL) : AL(AL) {}
+
+    Node *operator()(const Node &N) const { return AL.create(N.V); }
+  };
+
+  struct Disposer {
+    AllocatorList &AL;
+
+    Disposer(AllocatorList &AL) : AL(AL) {}
+
+    void operator()(Node *N) const {
+      N->~Node();
+      AL.getAlloc().Deallocate(N);
+    }
+  };
+
+public:
+  using value_type = T;
+  using pointer = T *;
+  using reference = T &;
+  using const_pointer = const T *;
+  using const_reference = const T &;
+  using size_type = typename list_type::size_type;
+  using difference_type = typename list_type::difference_type;
+
+private:
+  template <class ValueT, class IteratorBase>
+  class IteratorImpl
+      : public iterator_adaptor_base<IteratorImpl<ValueT, IteratorBase>,
+                                     IteratorBase,
+                                     std::bidirectional_iterator_tag, ValueT> {
+    template <class OtherValueT, class OtherIteratorBase>
+    friend class IteratorImpl;
+    friend AllocatorList;
+
+    using base_type =
+        iterator_adaptor_base<IteratorImpl<ValueT, IteratorBase>, IteratorBase,
+                              std::bidirectional_iterator_tag, ValueT>;
+
+  public:
+    using value_type = ValueT;
+    using pointer = ValueT *;
+    using reference = ValueT &;
+
+    IteratorImpl() = default;
+    IteratorImpl(const IteratorImpl &) = default;
+    IteratorImpl &operator=(const IteratorImpl &) = default;
+
+    explicit IteratorImpl(const IteratorBase &I) : base_type(I) {}
+
+    template <class OtherValueT, class OtherIteratorBase>
+    IteratorImpl(const IteratorImpl<OtherValueT, OtherIteratorBase> &X,
+                 typename std::enable_if<std::is_convertible<
+                     OtherIteratorBase, IteratorBase>::value>::type * = nullptr)
+        : base_type(X.wrapped()) {}
+
+    ~IteratorImpl() = default;
+
+    reference operator*() const { return base_type::wrapped()->V; }
+    pointer operator->() const { return &operator*(); }
+
+    friend bool operator==(const IteratorImpl &L, const IteratorImpl &R) {
+      return L.wrapped() == R.wrapped();
+    }
+    friend bool operator!=(const IteratorImpl &L, const IteratorImpl &R) {
+      return !(L == R);
+    }
+  };
+
+public:
+  using iterator = IteratorImpl<T, typename list_type::iterator>;
+  using reverse_iterator =
+      IteratorImpl<T, typename list_type::reverse_iterator>;
+  using const_iterator =
+      IteratorImpl<const T, typename list_type::const_iterator>;
+  using const_reverse_iterator =
+      IteratorImpl<const T, typename list_type::const_reverse_iterator>;
+
+  AllocatorList() = default;
+  AllocatorList(AllocatorList &&X)
+      : AllocatorT(std::move(X.getAlloc())), List(std::move(X.List)) {}
+
+  AllocatorList(const AllocatorList &X) {
+    List.cloneFrom(X.List, Cloner(*this), Disposer(*this));
+  }
+
+  AllocatorList &operator=(AllocatorList &&X) {
+    clear(); // Dispose of current nodes explicitly.
+    List = std::move(X.List);
+    getAlloc() = std::move(X.getAlloc());
+    return *this;
+  }
+
+  AllocatorList &operator=(const AllocatorList &X) {
+    List.cloneFrom(X.List, Cloner(*this), Disposer(*this));
+    return *this;
+  }
+
+  ~AllocatorList() { clear(); }
+
+  void swap(AllocatorList &RHS) {
+    List.swap(RHS.List);
+    std::swap(getAlloc(), RHS.getAlloc());
+  }
+
+  bool empty() { return List.empty(); }
+  size_t size() { return List.size(); }
+
+  iterator begin() { return iterator(List.begin()); }
+  iterator end() { return iterator(List.end()); }
+  const_iterator begin() const { return const_iterator(List.begin()); }
+  const_iterator end() const { return const_iterator(List.end()); }
+  reverse_iterator rbegin() { return reverse_iterator(List.rbegin()); }
+  reverse_iterator rend() { return reverse_iterator(List.rend()); }
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(List.rbegin());
+  }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(List.rend());
+  }
+
+  T &back() { return List.back().V; }
+  T &front() { return List.front().V; }
+  const T &back() const { return List.back().V; }
+  const T &front() const { return List.front().V; }
+
+  template <class... Ts> iterator emplace(iterator I, Ts &&... Vs) {
+    return iterator(List.insert(I.wrapped(), *create(std::forward<Ts>(Vs)...)));
+  }
+
+  iterator insert(iterator I, T &&V) {
+    return iterator(List.insert(I.wrapped(), *create(std::move(V))));
+  }
+  iterator insert(iterator I, const T &V) {
+    return iterator(List.insert(I.wrapped(), *create(V)));
+  }
+
+  template <class Iterator>
+  void insert(iterator I, Iterator First, Iterator Last) {
+    for (; First != Last; ++First)
+      List.insert(I.wrapped(), *create(*First));
+  }
+
+  iterator erase(iterator I) {
+    return iterator(List.eraseAndDispose(I.wrapped(), Disposer(*this)));
+  }
+
+  iterator erase(iterator First, iterator Last) {
+    return iterator(
+        List.eraseAndDispose(First.wrapped(), Last.wrapped(), Disposer(*this)));
+  }
+
+  void clear() { List.clearAndDispose(Disposer(*this)); }
+  void pop_back() { List.eraseAndDispose(--List.end(), Disposer(*this)); }
+  void pop_front() { List.eraseAndDispose(List.begin(), Disposer(*this)); }
+  void push_back(T &&V) { insert(end(), std::move(V)); }
+  void push_front(T &&V) { insert(begin(), std::move(V)); }
+  void push_back(const T &V) { insert(end(), V); }
+  void push_front(const T &V) { insert(begin(), V); }
+  template <class... Ts> void emplace_back(Ts &&... Vs) {
+    emplace(end(), std::forward<Ts>(Vs)...);
+  }
+  template <class... Ts> void emplace_front(Ts &&... Vs) {
+    emplace(begin(), std::forward<Ts>(Vs)...);
+  }
+
+  /// Reset the underlying allocator.
+  ///
+  /// \pre \c empty()
+  void resetAlloc() {
+    assert(empty() && "Cannot reset allocator if not empty");
+    getAlloc().Reset();
+  }
+};
+
+template <class T> using BumpPtrList = AllocatorList<T, BumpPtrAllocator>;
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_ALLOCATORLIST_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/ArrayRef.h b/binaryen/third_party/llvm-project/include/llvm/ADT/ArrayRef.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/ArrayRef.h
@@ -0,0 +1,540 @@
+//===- ArrayRef.h - Array Reference Wrapper ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_ARRAYREF_H
+#define LLVM_ADT_ARRAYREF_H
+
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <initializer_list>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <vector>
+
+namespace llvm {
+
+  /// ArrayRef - Represent a constant reference to an array (0 or more elements
+  /// consecutively in memory), i.e. a start pointer and a length.  It allows
+  /// various APIs to take consecutive elements easily and conveniently.
+  ///
+  /// This class does not own the underlying data, it is expected to be used in
+  /// situations where the data resides in some other buffer, whose lifetime
+  /// extends past that of the ArrayRef. For this reason, it is not in general
+  /// safe to store an ArrayRef.
+  ///
+  /// This is intended to be trivially copyable, so it should be passed by
+  /// value.
+  template<typename T>
+  class LLVM_NODISCARD ArrayRef {
+  public:
+    using iterator = const T *;
+    using const_iterator = const T *;
+    using size_type = size_t;
+    using reverse_iterator = std::reverse_iterator<iterator>;
+
+  private:
+    /// The start of the array, in an external buffer.
+    const T *Data = nullptr;
+
+    /// The number of elements.
+    size_type Length = 0;
+
+  public:
+    /// @name Constructors
+    /// @{
+
+    /// Construct an empty ArrayRef.
+    /*implicit*/ ArrayRef() = default;
+
+    /// Construct an empty ArrayRef from None.
+    /*implicit*/ ArrayRef(NoneType) {}
+
+    /// Construct an ArrayRef from a single element.
+    /*implicit*/ ArrayRef(const T &OneElt)
+      : Data(&OneElt), Length(1) {}
+
+    /// Construct an ArrayRef from a pointer and length.
+    /*implicit*/ ArrayRef(const T *data, size_t length)
+      : Data(data), Length(length) {}
+
+    /// Construct an ArrayRef from a range.
+    ArrayRef(const T *begin, const T *end)
+      : Data(begin), Length(end - begin) {}
+
+    /// Construct an ArrayRef from a SmallVector. This is templated in order to
+    /// avoid instantiating SmallVectorTemplateCommon<T> whenever we
+    /// copy-construct an ArrayRef.
+    template<typename U>
+    /*implicit*/ ArrayRef(const SmallVectorTemplateCommon<T, U> &Vec)
+      : Data(Vec.data()), Length(Vec.size()) {
+    }
+
+    /// Construct an ArrayRef from a std::vector.
+    template<typename A>
+    /*implicit*/ ArrayRef(const std::vector<T, A> &Vec)
+      : Data(Vec.data()), Length(Vec.size()) {}
+
+    /// Construct an ArrayRef from a std::array
+    template <size_t N>
+    /*implicit*/ constexpr ArrayRef(const std::array<T, N> &Arr)
+        : Data(Arr.data()), Length(N) {}
+
+    /// Construct an ArrayRef from a C array.
+    template <size_t N>
+    /*implicit*/ constexpr ArrayRef(const T (&Arr)[N]) : Data(Arr), Length(N) {}
+
+    /// Construct an ArrayRef from a std::initializer_list.
+    /*implicit*/ ArrayRef(const std::initializer_list<T> &Vec)
+    : Data(Vec.begin() == Vec.end() ? (T*)nullptr : Vec.begin()),
+      Length(Vec.size()) {}
+
+    /// Construct an ArrayRef<const T*> from ArrayRef<T*>. This uses SFINAE to
+    /// ensure that only ArrayRefs of pointers can be converted.
+    template <typename U>
+    ArrayRef(
+        const ArrayRef<U *> &A,
+        typename std::enable_if<
+           std::is_convertible<U *const *, T const *>::value>::type * = nullptr)
+      : Data(A.data()), Length(A.size()) {}
+
+    /// Construct an ArrayRef<const T*> from a SmallVector<T*>. This is
+    /// templated in order to avoid instantiating SmallVectorTemplateCommon<T>
+    /// whenever we copy-construct an ArrayRef.
+    template<typename U, typename DummyT>
+    /*implicit*/ ArrayRef(
+      const SmallVectorTemplateCommon<U *, DummyT> &Vec,
+      typename std::enable_if<
+          std::is_convertible<U *const *, T const *>::value>::type * = nullptr)
+      : Data(Vec.data()), Length(Vec.size()) {
+    }
+
+    /// Construct an ArrayRef<const T*> from std::vector<T*>. This uses SFINAE
+    /// to ensure that only vectors of pointers can be converted.
+    template<typename U, typename A>
+    ArrayRef(const std::vector<U *, A> &Vec,
+             typename std::enable_if<
+                 std::is_convertible<U *const *, T const *>::value>::type* = 0)
+      : Data(Vec.data()), Length(Vec.size()) {}
+
+    /// @}
+    /// @name Simple Operations
+    /// @{
+
+    iterator begin() const { return Data; }
+    iterator end() const { return Data + Length; }
+
+    reverse_iterator rbegin() const { return reverse_iterator(end()); }
+    reverse_iterator rend() const { return reverse_iterator(begin()); }
+
+    /// empty - Check if the array is empty.
+    bool empty() const { return Length == 0; }
+
+    const T *data() const { return Data; }
+
+    /// size - Get the array size.
+    size_t size() const { return Length; }
+
+    /// front - Get the first element.
+    const T &front() const {
+      assert(!empty());
+      return Data[0];
+    }
+
+    /// back - Get the last element.
+    const T &back() const {
+      assert(!empty());
+      return Data[Length-1];
+    }
+
+    // copy - Allocate copy in Allocator and return ArrayRef<T> to it.
+    template <typename Allocator> ArrayRef<T> copy(Allocator &A) {
+      T *Buff = A.template Allocate<T>(Length);
+      std::uninitialized_copy(begin(), end(), Buff);
+      return ArrayRef<T>(Buff, Length);
+    }
+
+    /// equals - Check for element-wise equality.
+    bool equals(ArrayRef RHS) const {
+      if (Length != RHS.Length)
+        return false;
+      return std::equal(begin(), end(), RHS.begin());
+    }
+
+    /// slice(n, m) - Chop off the first N elements of the array, and keep M
+    /// elements in the array.
+    ArrayRef<T> slice(size_t N, size_t M) const {
+      assert(N+M <= size() && "Invalid specifier");
+      return ArrayRef<T>(data()+N, M);
+    }
+
+    /// slice(n) - Chop off the first N elements of the array.
+    ArrayRef<T> slice(size_t N) const { return slice(N, size() - N); }
+
+    /// Drop the first \p N elements of the array.
+    ArrayRef<T> drop_front(size_t N = 1) const {
+      assert(size() >= N && "Dropping more elements than exist");
+      return slice(N, size() - N);
+    }
+
+    /// Drop the last \p N elements of the array.
+    ArrayRef<T> drop_back(size_t N = 1) const {
+      assert(size() >= N && "Dropping more elements than exist");
+      return slice(0, size() - N);
+    }
+
+    /// Return a copy of *this with the first N elements satisfying the
+    /// given predicate removed.
+    template <class PredicateT> ArrayRef<T> drop_while(PredicateT Pred) const {
+      return ArrayRef<T>(find_if_not(*this, Pred), end());
+    }
+
+    /// Return a copy of *this with the first N elements not satisfying
+    /// the given predicate removed.
+    template <class PredicateT> ArrayRef<T> drop_until(PredicateT Pred) const {
+      return ArrayRef<T>(find_if(*this, Pred), end());
+    }
+
+    /// Return a copy of *this with only the first \p N elements.
+    ArrayRef<T> take_front(size_t N = 1) const {
+      if (N >= size())
+        return *this;
+      return drop_back(size() - N);
+    }
+
+    /// Return a copy of *this with only the last \p N elements.
+    ArrayRef<T> take_back(size_t N = 1) const {
+      if (N >= size())
+        return *this;
+      return drop_front(size() - N);
+    }
+
+    /// Return the first N elements of this Array that satisfy the given
+    /// predicate.
+    template <class PredicateT> ArrayRef<T> take_while(PredicateT Pred) const {
+      return ArrayRef<T>(begin(), find_if_not(*this, Pred));
+    }
+
+    /// Return the first N elements of this Array that don't satisfy the
+    /// given predicate.
+    template <class PredicateT> ArrayRef<T> take_until(PredicateT Pred) const {
+      return ArrayRef<T>(begin(), find_if(*this, Pred));
+    }
+
+    /// @}
+    /// @name Operator Overloads
+    /// @{
+    const T &operator[](size_t Index) const {
+      assert(Index < Length && "Invalid index!");
+      return Data[Index];
+    }
+
+    /// Disallow accidental assignment from a temporary.
+    ///
+    /// The declaration here is extra complicated so that "arrayRef = {}"
+    /// continues to select the move assignment operator.
+    template <typename U>
+    typename std::enable_if<std::is_same<U, T>::value, ArrayRef<T>>::type &
+    operator=(U &&Temporary) = delete;
+
+    /// Disallow accidental assignment from a temporary.
+    ///
+    /// The declaration here is extra complicated so that "arrayRef = {}"
+    /// continues to select the move assignment operator.
+    template <typename U>
+    typename std::enable_if<std::is_same<U, T>::value, ArrayRef<T>>::type &
+    operator=(std::initializer_list<U>) = delete;
+
+    /// @}
+    /// @name Expensive Operations
+    /// @{
+    std::vector<T> vec() const {
+      return std::vector<T>(Data, Data+Length);
+    }
+
+    /// @}
+    /// @name Conversion operators
+    /// @{
+    operator std::vector<T>() const {
+      return std::vector<T>(Data, Data+Length);
+    }
+
+    /// @}
+  };
+
+  /// MutableArrayRef - Represent a mutable reference to an array (0 or more
+  /// elements consecutively in memory), i.e. a start pointer and a length.  It
+  /// allows various APIs to take and modify consecutive elements easily and
+  /// conveniently.
+  ///
+  /// This class does not own the underlying data, it is expected to be used in
+  /// situations where the data resides in some other buffer, whose lifetime
+  /// extends past that of the MutableArrayRef. For this reason, it is not in
+  /// general safe to store a MutableArrayRef.
+  ///
+  /// This is intended to be trivially copyable, so it should be passed by
+  /// value.
+  template<typename T>
+  class LLVM_NODISCARD MutableArrayRef : public ArrayRef<T> {
+  public:
+    using iterator = T *;
+    using reverse_iterator = std::reverse_iterator<iterator>;
+
+    /// Construct an empty MutableArrayRef.
+    /*implicit*/ MutableArrayRef() = default;
+
+    /// Construct an empty MutableArrayRef from None.
+    /*implicit*/ MutableArrayRef(NoneType) : ArrayRef<T>() {}
+
+    /// Construct an MutableArrayRef from a single element.
+    /*implicit*/ MutableArrayRef(T &OneElt) : ArrayRef<T>(OneElt) {}
+
+    /// Construct an MutableArrayRef from a pointer and length.
+    /*implicit*/ MutableArrayRef(T *data, size_t length)
+      : ArrayRef<T>(data, length) {}
+
+    /// Construct an MutableArrayRef from a range.
+    MutableArrayRef(T *begin, T *end) : ArrayRef<T>(begin, end) {}
+
+    /// Construct an MutableArrayRef from a SmallVector.
+    /*implicit*/ MutableArrayRef(SmallVectorImpl<T> &Vec)
+    : ArrayRef<T>(Vec) {}
+
+    /// Construct a MutableArrayRef from a std::vector.
+    /*implicit*/ MutableArrayRef(std::vector<T> &Vec)
+    : ArrayRef<T>(Vec) {}
+
+    /// Construct an ArrayRef from a std::array
+    template <size_t N>
+    /*implicit*/ constexpr MutableArrayRef(std::array<T, N> &Arr)
+        : ArrayRef<T>(Arr) {}
+
+    /// Construct an MutableArrayRef from a C array.
+    template <size_t N>
+    /*implicit*/ constexpr MutableArrayRef(T (&Arr)[N]) : ArrayRef<T>(Arr) {}
+
+    T *data() const { return const_cast<T*>(ArrayRef<T>::data()); }
+
+    iterator begin() const { return data(); }
+    iterator end() const { return data() + this->size(); }
+
+    reverse_iterator rbegin() const { return reverse_iterator(end()); }
+    reverse_iterator rend() const { return reverse_iterator(begin()); }
+
+    /// front - Get the first element.
+    T &front() const {
+      assert(!this->empty());
+      return data()[0];
+    }
+
+    /// back - Get the last element.
+    T &back() const {
+      assert(!this->empty());
+      return data()[this->size()-1];
+    }
+
+    /// slice(n, m) - Chop off the first N elements of the array, and keep M
+    /// elements in the array.
+    MutableArrayRef<T> slice(size_t N, size_t M) const {
+      assert(N + M <= this->size() && "Invalid specifier");
+      return MutableArrayRef<T>(this->data() + N, M);
+    }
+
+    /// slice(n) - Chop off the first N elements of the array.
+    MutableArrayRef<T> slice(size_t N) const {
+      return slice(N, this->size() - N);
+    }
+
+    /// Drop the first \p N elements of the array.
+    MutableArrayRef<T> drop_front(size_t N = 1) const {
+      assert(this->size() >= N && "Dropping more elements than exist");
+      return slice(N, this->size() - N);
+    }
+
+    MutableArrayRef<T> drop_back(size_t N = 1) const {
+      assert(this->size() >= N && "Dropping more elements than exist");
+      return slice(0, this->size() - N);
+    }
+
+    /// Return a copy of *this with the first N elements satisfying the
+    /// given predicate removed.
+    template <class PredicateT>
+    MutableArrayRef<T> drop_while(PredicateT Pred) const {
+      return MutableArrayRef<T>(find_if_not(*this, Pred), end());
+    }
+
+    /// Return a copy of *this with the first N elements not satisfying
+    /// the given predicate removed.
+    template <class PredicateT>
+    MutableArrayRef<T> drop_until(PredicateT Pred) const {
+      return MutableArrayRef<T>(find_if(*this, Pred), end());
+    }
+
+    /// Return a copy of *this with only the first \p N elements.
+    MutableArrayRef<T> take_front(size_t N = 1) const {
+      if (N >= this->size())
+        return *this;
+      return drop_back(this->size() - N);
+    }
+
+    /// Return a copy of *this with only the last \p N elements.
+    MutableArrayRef<T> take_back(size_t N = 1) const {
+      if (N >= this->size())
+        return *this;
+      return drop_front(this->size() - N);
+    }
+
+    /// Return the first N elements of this Array that satisfy the given
+    /// predicate.
+    template <class PredicateT>
+    MutableArrayRef<T> take_while(PredicateT Pred) const {
+      return MutableArrayRef<T>(begin(), find_if_not(*this, Pred));
+    }
+
+    /// Return the first N elements of this Array that don't satisfy the
+    /// given predicate.
+    template <class PredicateT>
+    MutableArrayRef<T> take_until(PredicateT Pred) const {
+      return MutableArrayRef<T>(begin(), find_if(*this, Pred));
+    }
+
+    /// @}
+    /// @name Operator Overloads
+    /// @{
+    T &operator[](size_t Index) const {
+      assert(Index < this->size() && "Invalid index!");
+      return data()[Index];
+    }
+  };
+
+  /// This is a MutableArrayRef that owns its array.
+  template <typename T> class OwningArrayRef : public MutableArrayRef<T> {
+  public:
+    OwningArrayRef() = default;
+    OwningArrayRef(size_t Size) : MutableArrayRef<T>(new T[Size], Size) {}
+
+    OwningArrayRef(ArrayRef<T> Data)
+        : MutableArrayRef<T>(new T[Data.size()], Data.size()) {
+      std::copy(Data.begin(), Data.end(), this->begin());
+    }
+
+    OwningArrayRef(OwningArrayRef &&Other) { *this = std::move(Other); }
+
+    OwningArrayRef &operator=(OwningArrayRef &&Other) {
+      delete[] this->data();
+      this->MutableArrayRef<T>::operator=(Other);
+      Other.MutableArrayRef<T>::operator=(MutableArrayRef<T>());
+      return *this;
+    }
+
+    ~OwningArrayRef() { delete[] this->data(); }
+  };
+
+  /// @name ArrayRef Convenience constructors
+  /// @{
+
+  /// Construct an ArrayRef from a single element.
+  template<typename T>
+  ArrayRef<T> makeArrayRef(const T &OneElt) {
+    return OneElt;
+  }
+
+  /// Construct an ArrayRef from a pointer and length.
+  template<typename T>
+  ArrayRef<T> makeArrayRef(const T *data, size_t length) {
+    return ArrayRef<T>(data, length);
+  }
+
+  /// Construct an ArrayRef from a range.
+  template<typename T>
+  ArrayRef<T> makeArrayRef(const T *begin, const T *end) {
+    return ArrayRef<T>(begin, end);
+  }
+
+  /// Construct an ArrayRef from a SmallVector.
+  template <typename T>
+  ArrayRef<T> makeArrayRef(const SmallVectorImpl<T> &Vec) {
+    return Vec;
+  }
+
+  /// Construct an ArrayRef from a SmallVector.
+  template <typename T, unsigned N>
+  ArrayRef<T> makeArrayRef(const SmallVector<T, N> &Vec) {
+    return Vec;
+  }
+
+  /// Construct an ArrayRef from a std::vector.
+  template<typename T>
+  ArrayRef<T> makeArrayRef(const std::vector<T> &Vec) {
+    return Vec;
+  }
+
+  /// Construct an ArrayRef from a std::array.
+  template <typename T, std::size_t N>
+  ArrayRef<T> makeArrayRef(const std::array<T, N> &Arr) {
+    return Arr;
+  }
+
+  /// Construct an ArrayRef from an ArrayRef (no-op) (const)
+  template <typename T> ArrayRef<T> makeArrayRef(const ArrayRef<T> &Vec) {
+    return Vec;
+  }
+
+  /// Construct an ArrayRef from an ArrayRef (no-op)
+  template <typename T> ArrayRef<T> &makeArrayRef(ArrayRef<T> &Vec) {
+    return Vec;
+  }
+
+  /// Construct an ArrayRef from a C array.
+  template<typename T, size_t N>
+  ArrayRef<T> makeArrayRef(const T (&Arr)[N]) {
+    return ArrayRef<T>(Arr);
+  }
+
+  /// Construct a MutableArrayRef from a single element.
+  template<typename T>
+  MutableArrayRef<T> makeMutableArrayRef(T &OneElt) {
+    return OneElt;
+  }
+
+  /// Construct a MutableArrayRef from a pointer and length.
+  template<typename T>
+  MutableArrayRef<T> makeMutableArrayRef(T *data, size_t length) {
+    return MutableArrayRef<T>(data, length);
+  }
+
+  /// @}
+  /// @name ArrayRef Comparison Operators
+  /// @{
+
+  template<typename T>
+  inline bool operator==(ArrayRef<T> LHS, ArrayRef<T> RHS) {
+    return LHS.equals(RHS);
+  }
+
+  template<typename T>
+  inline bool operator!=(ArrayRef<T> LHS, ArrayRef<T> RHS) {
+    return !(LHS == RHS);
+  }
+
+  /// @}
+
+  template <typename T> hash_code hash_value(ArrayRef<T> S) {
+    return hash_combine_range(S.begin(), S.end());
+  }
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_ARRAYREF_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/BitmaskEnum.h b/binaryen/third_party/llvm-project/include/llvm/ADT/BitmaskEnum.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/BitmaskEnum.h
@@ -0,0 +1,152 @@
+//===-- llvm/ADT/BitmaskEnum.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_BITMASKENUM_H
+#define LLVM_ADT_BITMASKENUM_H
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+
+#include "llvm/Support/MathExtras.h"
+
+/// LLVM_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you can
+/// perform bitwise operations on it without putting static_cast everywhere.
+///
+/// \code
+///   enum MyEnum {
+///     E1 = 1, E2 = 2, E3 = 4, E4 = 8,
+///     LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ E4)
+///   };
+///
+///   void Foo() {
+///     MyEnum A = (E1 | E2) & E3 ^ ~E4; // Look, ma: No static_cast!
+///   }
+/// \endcode
+///
+/// Normally when you do a bitwise operation on an enum value, you get back an
+/// instance of the underlying type (e.g. int).  But using this macro, bitwise
+/// ops on your enum will return you back instances of the enum.  This is
+/// particularly useful for enums which represent a combination of flags.
+///
+/// The parameter to LLVM_MARK_AS_BITMASK_ENUM should be the largest individual
+/// value in your enum.
+///
+/// All of the enum's values must be non-negative.
+#define LLVM_MARK_AS_BITMASK_ENUM(LargestValue)                                \
+  LLVM_BITMASK_LARGEST_ENUMERATOR = LargestValue
+
+/// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() pulls the operator overloads used
+/// by LLVM_MARK_AS_BITMASK_ENUM into the current namespace.
+///
+/// Suppose you have an enum foo::bar::MyEnum.  Before using
+/// LLVM_MARK_AS_BITMASK_ENUM on MyEnum, you must put
+/// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() somewhere inside namespace foo or
+/// namespace foo::bar.  This allows the relevant operator overloads to be found
+/// by ADL.
+///
+/// You don't need to use this macro in namespace llvm; it's done at the bottom
+/// of this file.
+#define LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE()                               \
+  using ::llvm::BitmaskEnumDetail::operator~;                                  \
+  using ::llvm::BitmaskEnumDetail::operator|;                                  \
+  using ::llvm::BitmaskEnumDetail::operator&;                                  \
+  using ::llvm::BitmaskEnumDetail::operator^;                                  \
+  using ::llvm::BitmaskEnumDetail::operator|=;                                 \
+  using ::llvm::BitmaskEnumDetail::operator&=;                                 \
+  /* Force a semicolon at the end of this macro. */                            \
+  using ::llvm::BitmaskEnumDetail::operator^=
+
+namespace llvm {
+
+/// Traits class to determine whether an enum has a
+/// LLVM_BITMASK_LARGEST_ENUMERATOR enumerator.
+template <typename E, typename Enable = void>
+struct is_bitmask_enum : std::false_type {};
+
+template <typename E>
+struct is_bitmask_enum<
+    E, typename std::enable_if<sizeof(E::LLVM_BITMASK_LARGEST_ENUMERATOR) >=
+                               0>::type> : std::true_type {};
+namespace BitmaskEnumDetail {
+
+/// Get a bitmask with 1s in all places up to the high-order bit of E's largest
+/// value.
+template <typename E> typename std::underlying_type<E>::type Mask() {
+  // On overflow, NextPowerOf2 returns zero with the type uint64_t, so
+  // subtracting 1 gives us the mask with all bits set, like we want.
+  return NextPowerOf2(static_cast<typename std::underlying_type<E>::type>(
+             E::LLVM_BITMASK_LARGEST_ENUMERATOR)) -
+         1;
+}
+
+/// Check that Val is in range for E, and return Val cast to E's underlying
+/// type.
+template <typename E> typename std::underlying_type<E>::type Underlying(E Val) {
+  auto U = static_cast<typename std::underlying_type<E>::type>(Val);
+  assert(U >= 0 && "Negative enum values are not allowed.");
+  assert(U <= Mask<E>() && "Enum value too large (or largest val too small?)");
+  return U;
+}
+
+template <typename E,
+          typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
+E operator~(E Val) {
+  return static_cast<E>(~Underlying(Val) & Mask<E>());
+}
+
+template <typename E,
+          typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
+E operator|(E LHS, E RHS) {
+  return static_cast<E>(Underlying(LHS) | Underlying(RHS));
+}
+
+template <typename E,
+          typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
+E operator&(E LHS, E RHS) {
+  return static_cast<E>(Underlying(LHS) & Underlying(RHS));
+}
+
+template <typename E,
+          typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
+E operator^(E LHS, E RHS) {
+  return static_cast<E>(Underlying(LHS) ^ Underlying(RHS));
+}
+
+// |=, &=, and ^= return a reference to LHS, to match the behavior of the
+// operators on builtin types.
+
+template <typename E,
+          typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
+E &operator|=(E &LHS, E RHS) {
+  LHS = LHS | RHS;
+  return LHS;
+}
+
+template <typename E,
+          typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
+E &operator&=(E &LHS, E RHS) {
+  LHS = LHS & RHS;
+  return LHS;
+}
+
+template <typename E,
+          typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
+E &operator^=(E &LHS, E RHS) {
+  LHS = LHS ^ RHS;
+  return LHS;
+}
+
+} // namespace BitmaskEnumDetail
+
+// Enable bitmask enums in namespace ::llvm and all nested namespaces.
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/DenseMap.h b/binaryen/third_party/llvm-project/include/llvm/ADT/DenseMap.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/DenseMap.h
@@ -0,0 +1,1275 @@
+//===- llvm/ADT/DenseMap.h - Dense probed hash table ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the DenseMap class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_DENSEMAP_H
+#define LLVM_ADT_DENSEMAP_H
+
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/EpochTracker.h"
+#include "llvm/Support/AlignOf.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/ReverseIteration.h"
+#include "llvm/Support/type_traits.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <initializer_list>
+#include <iterator>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+namespace llvm {
+
+namespace detail {
+
+// We extend a pair to allow users to override the bucket type with their own
+// implementation without requiring two members.
+template <typename KeyT, typename ValueT>
+struct DenseMapPair : public std::pair<KeyT, ValueT> {
+  using std::pair<KeyT, ValueT>::pair;
+
+  KeyT &getFirst() { return std::pair<KeyT, ValueT>::first; }
+  const KeyT &getFirst() const { return std::pair<KeyT, ValueT>::first; }
+  ValueT &getSecond() { return std::pair<KeyT, ValueT>::second; }
+  const ValueT &getSecond() const { return std::pair<KeyT, ValueT>::second; }
+};
+
+} // end namespace detail
+
+template <typename KeyT, typename ValueT,
+          typename KeyInfoT = DenseMapInfo<KeyT>,
+          typename Bucket = llvm::detail::DenseMapPair<KeyT, ValueT>,
+          bool IsConst = false>
+class DenseMapIterator;
+
+template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
+          typename BucketT>
+class DenseMapBase : public DebugEpochBase {
+  template <typename T>
+  using const_arg_type_t = typename const_pointer_or_const_ref<T>::type;
+
+public:
+  using size_type = unsigned;
+  using key_type = KeyT;
+  using mapped_type = ValueT;
+  using value_type = BucketT;
+
+  using iterator = DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT>;
+  using const_iterator =
+      DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT, true>;
+
+  inline iterator begin() {
+    // When the map is empty, avoid the overhead of advancing/retreating past
+    // empty buckets.
+    if (empty())
+      return end();
+    if (shouldReverseIterate<KeyT>())
+      return makeIterator(getBucketsEnd() - 1, getBuckets(), *this);
+    return makeIterator(getBuckets(), getBucketsEnd(), *this);
+  }
+  inline iterator end() {
+    return makeIterator(getBucketsEnd(), getBucketsEnd(), *this, true);
+  }
+  inline const_iterator begin() const {
+    if (empty())
+      return end();
+    if (shouldReverseIterate<KeyT>())
+      return makeConstIterator(getBucketsEnd() - 1, getBuckets(), *this);
+    return makeConstIterator(getBuckets(), getBucketsEnd(), *this);
+  }
+  inline const_iterator end() const {
+    return makeConstIterator(getBucketsEnd(), getBucketsEnd(), *this, true);
+  }
+
+  LLVM_NODISCARD bool empty() const {
+    return getNumEntries() == 0;
+  }
+  unsigned size() const { return getNumEntries(); }
+
+  /// Grow the densemap so that it can contain at least \p NumEntries items
+  /// before resizing again.
+  void reserve(size_type NumEntries) {
+    auto NumBuckets = getMinBucketToReserveForEntries(NumEntries);
+    incrementEpoch();
+    if (NumBuckets > getNumBuckets())
+      grow(NumBuckets);
+  }
+
+  void clear() {
+    incrementEpoch();
+    if (getNumEntries() == 0 && getNumTombstones() == 0) return;
+
+    // If the capacity of the array is huge, and the # elements used is small,
+    // shrink the array.
+    if (getNumEntries() * 4 < getNumBuckets() && getNumBuckets() > 64) {
+      shrink_and_clear();
+      return;
+    }
+
+    const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
+    if (is_trivially_copyable<KeyT>::value &&
+        is_trivially_copyable<ValueT>::value) {
+      // Use a simpler loop when these are trivial types.
+      for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P)
+        P->getFirst() = EmptyKey;
+    } else {
+      unsigned NumEntries = getNumEntries();
+      for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
+        if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) {
+          if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
+            P->getSecond().~ValueT();
+            --NumEntries;
+          }
+          P->getFirst() = EmptyKey;
+        }
+      }
+      assert(NumEntries == 0 && "Node count imbalance!");
+    }
+    setNumEntries(0);
+    setNumTombstones(0);
+  }
+
+  /// Return 1 if the specified key is in the map, 0 otherwise.
+  size_type count(const_arg_type_t<KeyT> Val) const {
+    const BucketT *TheBucket;
+    return LookupBucketFor(Val, TheBucket) ? 1 : 0;
+  }
+
+  iterator find(const_arg_type_t<KeyT> Val) {
+    BucketT *TheBucket;
+    if (LookupBucketFor(Val, TheBucket))
+      return makeIterator(TheBucket, getBucketsEnd(), *this, true);
+    return end();
+  }
+  const_iterator find(const_arg_type_t<KeyT> Val) const {
+    const BucketT *TheBucket;
+    if (LookupBucketFor(Val, TheBucket))
+      return makeConstIterator(TheBucket, getBucketsEnd(), *this, true);
+    return end();
+  }
+
+  /// Alternate version of find() which allows a different, and possibly
+  /// less expensive, key type.
+  /// The DenseMapInfo is responsible for supplying methods
+  /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key
+  /// type used.
+  template<class LookupKeyT>
+  iterator find_as(const LookupKeyT &Val) {
+    BucketT *TheBucket;
+    if (LookupBucketFor(Val, TheBucket))
+      return makeIterator(TheBucket, getBucketsEnd(), *this, true);
+    return end();
+  }
+  template<class LookupKeyT>
+  const_iterator find_as(const LookupKeyT &Val) const {
+    const BucketT *TheBucket;
+    if (LookupBucketFor(Val, TheBucket))
+      return makeConstIterator(TheBucket, getBucketsEnd(), *this, true);
+    return end();
+  }
+
+  /// lookup - Return the entry for the specified key, or a default
+  /// constructed value if no such entry exists.
+  ValueT lookup(const_arg_type_t<KeyT> Val) const {
+    const BucketT *TheBucket;
+    if (LookupBucketFor(Val, TheBucket))
+      return TheBucket->getSecond();
+    return ValueT();
+  }
+
+  // Inserts key,value pair into the map if the key isn't already in the map.
+  // If the key is already in the map, it returns false and doesn't update the
+  // value.
+  std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
+    return try_emplace(KV.first, KV.second);
+  }
+
+  // Inserts key,value pair into the map if the key isn't already in the map.
+  // If the key is already in the map, it returns false and doesn't update the
+  // value.
+  std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
+    return try_emplace(std::move(KV.first), std::move(KV.second));
+  }
+
+  // Inserts key,value pair into the map if the key isn't already in the map.
+  // The value is constructed in-place if the key is not in the map, otherwise
+  // it is not moved.
+  template <typename... Ts>
+  std::pair<iterator, bool> try_emplace(KeyT &&Key, Ts &&... Args) {
+    BucketT *TheBucket;
+    if (LookupBucketFor(Key, TheBucket))
+      return std::make_pair(
+               makeIterator(TheBucket, getBucketsEnd(), *this, true),
+               false); // Already in map.
+
+    // Otherwise, insert the new element.
+    TheBucket =
+        InsertIntoBucket(TheBucket, std::move(Key), std::forward<Ts>(Args)...);
+    return std::make_pair(
+             makeIterator(TheBucket, getBucketsEnd(), *this, true),
+             true);
+  }
+
+  // Inserts key,value pair into the map if the key isn't already in the map.
+  // The value is constructed in-place if the key is not in the map, otherwise
+  // it is not moved.
+  template <typename... Ts>
+  std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&... Args) {
+    BucketT *TheBucket;
+    if (LookupBucketFor(Key, TheBucket))
+      return std::make_pair(
+               makeIterator(TheBucket, getBucketsEnd(), *this, true),
+               false); // Already in map.
+
+    // Otherwise, insert the new element.
+    TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...);
+    return std::make_pair(
+             makeIterator(TheBucket, getBucketsEnd(), *this, true),
+             true);
+  }
+
+  /// Alternate version of insert() which allows a different, and possibly
+  /// less expensive, key type.
+  /// The DenseMapInfo is responsible for supplying methods
+  /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key
+  /// type used.
+  template <typename LookupKeyT>
+  std::pair<iterator, bool> insert_as(std::pair<KeyT, ValueT> &&KV,
+                                      const LookupKeyT &Val) {
+    BucketT *TheBucket;
+    if (LookupBucketFor(Val, TheBucket))
+      return std::make_pair(
+               makeIterator(TheBucket, getBucketsEnd(), *this, true),
+               false); // Already in map.
+
+    // Otherwise, insert the new element.
+    TheBucket = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first),
+                                           std::move(KV.second), Val);
+    return std::make_pair(
+             makeIterator(TheBucket, getBucketsEnd(), *this, true),
+             true);
+  }
+
+  /// insert - Range insertion of pairs.
+  template<typename InputIt>
+  void insert(InputIt I, InputIt E) {
+    for (; I != E; ++I)
+      insert(*I);
+  }
+
+  bool erase(const KeyT &Val) {
+    BucketT *TheBucket;
+    if (!LookupBucketFor(Val, TheBucket))
+      return false; // not in map.
+
+    TheBucket->getSecond().~ValueT();
+    TheBucket->getFirst() = getTombstoneKey();
+    decrementNumEntries();
+    incrementNumTombstones();
+    return true;
+  }
+  void erase(iterator I) {
+    BucketT *TheBucket = &*I;
+    TheBucket->getSecond().~ValueT();
+    TheBucket->getFirst() = getTombstoneKey();
+    decrementNumEntries();
+    incrementNumTombstones();
+  }
+
+  value_type& FindAndConstruct(const KeyT &Key) {
+    BucketT *TheBucket;
+    if (LookupBucketFor(Key, TheBucket))
+      return *TheBucket;
+
+    return *InsertIntoBucket(TheBucket, Key);
+  }
+
+  ValueT &operator[](const KeyT &Key) {
+    return FindAndConstruct(Key).second;
+  }
+
+  value_type& FindAndConstruct(KeyT &&Key) {
+    BucketT *TheBucket;
+    if (LookupBucketFor(Key, TheBucket))
+      return *TheBucket;
+
+    return *InsertIntoBucket(TheBucket, std::move(Key));
+  }
+
+  ValueT &operator[](KeyT &&Key) {
+    return FindAndConstruct(std::move(Key)).second;
+  }
+
+  /// isPointerIntoBucketsArray - Return true if the specified pointer points
+  /// somewhere into the DenseMap's array of buckets (i.e. either to a key or
+  /// value in the DenseMap).
+  bool isPointerIntoBucketsArray(const void *Ptr) const {
+    return Ptr >= getBuckets() && Ptr < getBucketsEnd();
+  }
+
+  /// getPointerIntoBucketsArray() - Return an opaque pointer into the buckets
+  /// array.  In conjunction with the previous method, this can be used to
+  /// determine whether an insertion caused the DenseMap to reallocate.
+  const void *getPointerIntoBucketsArray() const { return getBuckets(); }
+
+protected:
+  DenseMapBase() = default;
+
+  void destroyAll() {
+    if (getNumBuckets() == 0) // Nothing to do.
+      return;
+
+    const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
+    for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
+      if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey) &&
+          !KeyInfoT::isEqual(P->getFirst(), TombstoneKey))
+        P->getSecond().~ValueT();
+      P->getFirst().~KeyT();
+    }
+  }
+
+  void initEmpty() {
+    setNumEntries(0);
+    setNumTombstones(0);
+
+    assert((getNumBuckets() & (getNumBuckets()-1)) == 0 &&
+           "# initial buckets must be a power of two!");
+    const KeyT EmptyKey = getEmptyKey();
+    for (BucketT *B = getBuckets(), *E = getBucketsEnd(); B != E; ++B)
+      ::new (&B->getFirst()) KeyT(EmptyKey);
+  }
+
+  /// Returns the number of buckets to allocate to ensure that the DenseMap can
+  /// accommodate \p NumEntries without need to grow().
+  unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
+    // Ensure that "NumEntries * 4 < NumBuckets * 3"
+    if (NumEntries == 0)
+      return 0;
+    // +1 is required because of the strict equality.
+    // For example if NumEntries is 48, we need to return 401.
+    return NextPowerOf2(NumEntries * 4 / 3 + 1);
+  }
+
+  void moveFromOldBuckets(BucketT *OldBucketsBegin, BucketT *OldBucketsEnd) {
+    initEmpty();
+
+    // Insert all the old elements.
+    const KeyT EmptyKey = getEmptyKey();
+    const KeyT TombstoneKey = getTombstoneKey();
+    for (BucketT *B = OldBucketsBegin, *E = OldBucketsEnd; B != E; ++B) {
+      if (!KeyInfoT::isEqual(B->getFirst(), EmptyKey) &&
+          !KeyInfoT::isEqual(B->getFirst(), TombstoneKey)) {
+        // Insert the key/value into the new table.
+        BucketT *DestBucket;
+        bool FoundVal = LookupBucketFor(B->getFirst(), DestBucket);
+        (void)FoundVal; // silence warning.
+        assert(!FoundVal && "Key already in new map?");
+        DestBucket->getFirst() = std::move(B->getFirst());
+        ::new (&DestBucket->getSecond()) ValueT(std::move(B->getSecond()));
+        incrementNumEntries();
+
+        // Free the value.
+        B->getSecond().~ValueT();
+      }
+      B->getFirst().~KeyT();
+    }
+  }
+
+  template <typename OtherBaseT>
+  void copyFrom(
+      const DenseMapBase<OtherBaseT, KeyT, ValueT, KeyInfoT, BucketT> &other) {
+    assert(&other != this);
+    assert(getNumBuckets() == other.getNumBuckets());
+
+    setNumEntries(other.getNumEntries());
+    setNumTombstones(other.getNumTombstones());
+
+    if (is_trivially_copyable<KeyT>::value &&
+        is_trivially_copyable<ValueT>::value)
+      memcpy(reinterpret_cast<void *>(getBuckets()), other.getBuckets(),
+             getNumBuckets() * sizeof(BucketT));
+    else
+      for (size_t i = 0; i < getNumBuckets(); ++i) {
+        ::new (&getBuckets()[i].getFirst())
+            KeyT(other.getBuckets()[i].getFirst());
+        if (!KeyInfoT::isEqual(getBuckets()[i].getFirst(), getEmptyKey()) &&
+            !KeyInfoT::isEqual(getBuckets()[i].getFirst(), getTombstoneKey()))
+          ::new (&getBuckets()[i].getSecond())
+              ValueT(other.getBuckets()[i].getSecond());
+      }
+  }
+
+  static unsigned getHashValue(const KeyT &Val) {
+    return KeyInfoT::getHashValue(Val);
+  }
+
+  template<typename LookupKeyT>
+  static unsigned getHashValue(const LookupKeyT &Val) {
+    return KeyInfoT::getHashValue(Val);
+  }
+
+  static const KeyT getEmptyKey() {
+    static_assert(std::is_base_of<DenseMapBase, DerivedT>::value,
+                  "Must pass the derived type to this template!");
+    return KeyInfoT::getEmptyKey();
+  }
+
+  static const KeyT getTombstoneKey() {
+    return KeyInfoT::getTombstoneKey();
+  }
+
+private:
+  iterator makeIterator(BucketT *P, BucketT *E,
+                        DebugEpochBase &Epoch,
+                        bool NoAdvance=false) {
+    if (shouldReverseIterate<KeyT>()) {
+      BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1;
+      return iterator(B, E, Epoch, NoAdvance);
+    }
+    return iterator(P, E, Epoch, NoAdvance);
+  }
+
+  const_iterator makeConstIterator(const BucketT *P, const BucketT *E,
+                                   const DebugEpochBase &Epoch,
+                                   const bool NoAdvance=false) const {
+    if (shouldReverseIterate<KeyT>()) {
+      const BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1;
+      return const_iterator(B, E, Epoch, NoAdvance);
+    }
+    return const_iterator(P, E, Epoch, NoAdvance);
+  }
+
+  unsigned getNumEntries() const {
+    return static_cast<const DerivedT *>(this)->getNumEntries();
+  }
+
+  void setNumEntries(unsigned Num) {
+    static_cast<DerivedT *>(this)->setNumEntries(Num);
+  }
+
+  void incrementNumEntries() {
+    setNumEntries(getNumEntries() + 1);
+  }
+
+  void decrementNumEntries() {
+    setNumEntries(getNumEntries() - 1);
+  }
+
+  unsigned getNumTombstones() const {
+    return static_cast<const DerivedT *>(this)->getNumTombstones();
+  }
+
+  void setNumTombstones(unsigned Num) {
+    static_cast<DerivedT *>(this)->setNumTombstones(Num);
+  }
+
+  void incrementNumTombstones() {
+    setNumTombstones(getNumTombstones() + 1);
+  }
+
+  void decrementNumTombstones() {
+    setNumTombstones(getNumTombstones() - 1);
+  }
+
+  const BucketT *getBuckets() const {
+    return static_cast<const DerivedT *>(this)->getBuckets();
+  }
+
+  BucketT *getBuckets() {
+    return static_cast<DerivedT *>(this)->getBuckets();
+  }
+
+  unsigned getNumBuckets() const {
+    return static_cast<const DerivedT *>(this)->getNumBuckets();
+  }
+
+  BucketT *getBucketsEnd() {
+    return getBuckets() + getNumBuckets();
+  }
+
+  const BucketT *getBucketsEnd() const {
+    return getBuckets() + getNumBuckets();
+  }
+
+  void grow(unsigned AtLeast) {
+    static_cast<DerivedT *>(this)->grow(AtLeast);
+  }
+
+  void shrink_and_clear() {
+    static_cast<DerivedT *>(this)->shrink_and_clear();
+  }
+
+  template <typename KeyArg, typename... ValueArgs>
+  BucketT *InsertIntoBucket(BucketT *TheBucket, KeyArg &&Key,
+                            ValueArgs &&... Values) {
+    TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
+
+    TheBucket->getFirst() = std::forward<KeyArg>(Key);
+    ::new (&TheBucket->getSecond()) ValueT(std::forward<ValueArgs>(Values)...);
+    return TheBucket;
+  }
+
+  template <typename LookupKeyT>
+  BucketT *InsertIntoBucketWithLookup(BucketT *TheBucket, KeyT &&Key,
+                                      ValueT &&Value, LookupKeyT &Lookup) {
+    TheBucket = InsertIntoBucketImpl(Key, Lookup, TheBucket);
+
+    TheBucket->getFirst() = std::move(Key);
+    ::new (&TheBucket->getSecond()) ValueT(std::move(Value));
+    return TheBucket;
+  }
+
+  template <typename LookupKeyT>
+  BucketT *InsertIntoBucketImpl(const KeyT &Key, const LookupKeyT &Lookup,
+                                BucketT *TheBucket) {
+    incrementEpoch();
+
+    // If the load of the hash table is more than 3/4, or if fewer than 1/8 of
+    // the buckets are empty (meaning that many are filled with tombstones),
+    // grow the table.
+    //
+    // The later case is tricky.  For example, if we had one empty bucket with
+    // tons of tombstones, failing lookups (e.g. for insertion) would have to
+    // probe almost the entire table until it found the empty bucket.  If the
+    // table completely filled with tombstones, no lookup would ever succeed,
+    // causing infinite loops in lookup.
+    unsigned NewNumEntries = getNumEntries() + 1;
+    unsigned NumBuckets = getNumBuckets();
+    if (LLVM_UNLIKELY(NewNumEntries * 4 >= NumBuckets * 3)) {
+      this->grow(NumBuckets * 2);
+      LookupBucketFor(Lookup, TheBucket);
+      NumBuckets = getNumBuckets();
+    } else if (LLVM_UNLIKELY(NumBuckets-(NewNumEntries+getNumTombstones()) <=
+                             NumBuckets/8)) {
+      this->grow(NumBuckets);
+      LookupBucketFor(Lookup, TheBucket);
+    }
+    assert(TheBucket);
+
+    // Only update the state after we've grown our bucket space appropriately
+    // so that when growing buckets we have self-consistent entry count.
+    incrementNumEntries();
+
+    // If we are writing over a tombstone, remember this.
+    const KeyT EmptyKey = getEmptyKey();
+    if (!KeyInfoT::isEqual(TheBucket->getFirst(), EmptyKey))
+      decrementNumTombstones();
+
+    return TheBucket;
+  }
+
+  /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in
+  /// FoundBucket.  If the bucket contains the key and a value, this returns
+  /// true, otherwise it returns a bucket with an empty marker or tombstone and
+  /// returns false.
+  template<typename LookupKeyT>
+  bool LookupBucketFor(const LookupKeyT &Val,
+                       const BucketT *&FoundBucket) const {
+    const BucketT *BucketsPtr = getBuckets();
+    const unsigned NumBuckets = getNumBuckets();
+
+    if (NumBuckets == 0) {
+      FoundBucket = nullptr;
+      return false;
+    }
+
+    // FoundTombstone - Keep track of whether we find a tombstone while probing.
+    const BucketT *FoundTombstone = nullptr;
+    const KeyT EmptyKey = getEmptyKey();
+    const KeyT TombstoneKey = getTombstoneKey();
+    assert(!KeyInfoT::isEqual(Val, EmptyKey) &&
+           !KeyInfoT::isEqual(Val, TombstoneKey) &&
+           "Empty/Tombstone value shouldn't be inserted into map!");
+
+    unsigned BucketNo = getHashValue(Val) & (NumBuckets-1);
+    unsigned ProbeAmt = 1;
+    while (true) {
+      const BucketT *ThisBucket = BucketsPtr + BucketNo;
+      // Found Val's bucket?  If so, return it.
+      if (LLVM_LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) {
+        FoundBucket = ThisBucket;
+        return true;
+      }
+
+      // If we found an empty bucket, the key doesn't exist in the set.
+      // Insert it and return the default value.
+      if (LLVM_LIKELY(KeyInfoT::isEqual(ThisBucket->getFirst(), EmptyKey))) {
+        // If we've already seen a tombstone while probing, fill it in instead
+        // of the empty bucket we eventually probed to.
+        FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket;
+        return false;
+      }
+
+      // If this is a tombstone, remember it.  If Val ends up not in the map, we
+      // prefer to return it than something that would require more probing.
+      if (KeyInfoT::isEqual(ThisBucket->getFirst(), TombstoneKey) &&
+          !FoundTombstone)
+        FoundTombstone = ThisBucket;  // Remember the first tombstone found.
+
+      // Otherwise, it's a hash collision or a tombstone, continue quadratic
+      // probing.
+      BucketNo += ProbeAmt++;
+      BucketNo &= (NumBuckets-1);
+    }
+  }
+
+  template <typename LookupKeyT>
+  bool LookupBucketFor(const LookupKeyT &Val, BucketT *&FoundBucket) {
+    const BucketT *ConstFoundBucket;
+    bool Result = const_cast<const DenseMapBase *>(this)
+      ->LookupBucketFor(Val, ConstFoundBucket);
+    FoundBucket = const_cast<BucketT *>(ConstFoundBucket);
+    return Result;
+  }
+
+public:
+  /// Return the approximate size (in bytes) of the actual map.
+  /// This is just the raw memory used by DenseMap.
+  /// If entries are pointers to objects, the size of the referenced objects
+  /// are not included.
+  size_t getMemorySize() const {
+    return getNumBuckets() * sizeof(BucketT);
+  }
+};
+
+/// Equality comparison for DenseMap.
+///
+/// Iterates over elements of LHS confirming that each (key, value) pair in LHS
+/// is also in RHS, and that no additional pairs are in RHS.
+/// Equivalent to N calls to RHS.find and N value comparisons. Amortized
+/// complexity is linear, worst case is O(N^2) (if every hash collides).
+template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
+          typename BucketT>
+bool operator==(
+    const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS,
+    const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) {
+  if (LHS.size() != RHS.size())
+    return false;
+
+  for (auto &KV : LHS) {
+    auto I = RHS.find(KV.first);
+    if (I == RHS.end() || I->second != KV.second)
+      return false;
+  }
+
+  return true;
+}
+
+/// Inequality comparison for DenseMap.
+///
+/// Equivalent to !(LHS == RHS). See operator== for performance notes.
+template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
+          typename BucketT>
+bool operator!=(
+    const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS,
+    const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) {
+  return !(LHS == RHS);
+}
+
+template <typename KeyT, typename ValueT,
+          typename KeyInfoT = DenseMapInfo<KeyT>,
+          typename BucketT = llvm::detail::DenseMapPair<KeyT, ValueT>>
+class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
+                                     KeyT, ValueT, KeyInfoT, BucketT> {
+  friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
+
+  // Lift some types from the dependent base class into this class for
+  // simplicity of referring to them.
+  using BaseT = DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
+
+  BucketT *Buckets;
+  unsigned NumEntries;
+  unsigned NumTombstones;
+  unsigned NumBuckets;
+
+public:
+  /// Create a DenseMap wth an optional \p InitialReserve that guarantee that
+  /// this number of elements can be inserted in the map without grow()
+  explicit DenseMap(unsigned InitialReserve = 0) { init(InitialReserve); }
+
+  DenseMap(const DenseMap &other) : BaseT() {
+    init(0);
+    copyFrom(other);
+  }
+
+  DenseMap(DenseMap &&other) : BaseT() {
+    init(0);
+    swap(other);
+  }
+
+  template<typename InputIt>
+  DenseMap(const InputIt &I, const InputIt &E) {
+    init(std::distance(I, E));
+    this->insert(I, E);
+  }
+
+  DenseMap(std::initializer_list<typename BaseT::value_type> Vals) {
+    init(Vals.size());
+    this->insert(Vals.begin(), Vals.end());
+  }
+
+  ~DenseMap() {
+    this->destroyAll();
+    deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
+  }
+
+  void swap(DenseMap& RHS) {
+    this->incrementEpoch();
+    RHS.incrementEpoch();
+    std::swap(Buckets, RHS.Buckets);
+    std::swap(NumEntries, RHS.NumEntries);
+    std::swap(NumTombstones, RHS.NumTombstones);
+    std::swap(NumBuckets, RHS.NumBuckets);
+  }
+
+  DenseMap& operator=(const DenseMap& other) {
+    if (&other != this)
+      copyFrom(other);
+    return *this;
+  }
+
+  DenseMap& operator=(DenseMap &&other) {
+    this->destroyAll();
+    deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
+    init(0);
+    swap(other);
+    return *this;
+  }
+
+  void copyFrom(const DenseMap& other) {
+    this->destroyAll();
+    deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
+    if (allocateBuckets(other.NumBuckets)) {
+      this->BaseT::copyFrom(other);
+    } else {
+      NumEntries = 0;
+      NumTombstones = 0;
+    }
+  }
+
+  void init(unsigned InitNumEntries) {
+    auto InitBuckets = BaseT::getMinBucketToReserveForEntries(InitNumEntries);
+    if (allocateBuckets(InitBuckets)) {
+      this->BaseT::initEmpty();
+    } else {
+      NumEntries = 0;
+      NumTombstones = 0;
+    }
+  }
+
+  void grow(unsigned AtLeast) {
+    unsigned OldNumBuckets = NumBuckets;
+    BucketT *OldBuckets = Buckets;
+
+    allocateBuckets(std::max<unsigned>(64, static_cast<unsigned>(NextPowerOf2(AtLeast-1))));
+    assert(Buckets);
+    if (!OldBuckets) {
+      this->BaseT::initEmpty();
+      return;
+    }
+
+    this->moveFromOldBuckets(OldBuckets, OldBuckets+OldNumBuckets);
+
+    // Free the old table.
+    deallocate_buffer(OldBuckets, sizeof(BucketT) * OldNumBuckets,
+                      alignof(BucketT));
+  }
+
+  void shrink_and_clear() {
+    unsigned OldNumBuckets = NumBuckets;
+    unsigned OldNumEntries = NumEntries;
+    this->destroyAll();
+
+    // Reduce the number of buckets.
+    unsigned NewNumBuckets = 0;
+    if (OldNumEntries)
+      NewNumBuckets = std::max(64, 1 << (Log2_32_Ceil(OldNumEntries) + 1));
+    if (NewNumBuckets == NumBuckets) {
+      this->BaseT::initEmpty();
+      return;
+    }
+
+    deallocate_buffer(Buckets, sizeof(BucketT) * OldNumBuckets,
+                      alignof(BucketT));
+    init(NewNumBuckets);
+  }
+
+private:
+  unsigned getNumEntries() const {
+    return NumEntries;
+  }
+
+  void setNumEntries(unsigned Num) {
+    NumEntries = Num;
+  }
+
+  unsigned getNumTombstones() const {
+    return NumTombstones;
+  }
+
+  void setNumTombstones(unsigned Num) {
+    NumTombstones = Num;
+  }
+
+  BucketT *getBuckets() const {
+    return Buckets;
+  }
+
+  unsigned getNumBuckets() const {
+    return NumBuckets;
+  }
+
+  bool allocateBuckets(unsigned Num) {
+    NumBuckets = Num;
+    if (NumBuckets == 0) {
+      Buckets = nullptr;
+      return false;
+    }
+
+    Buckets = static_cast<BucketT *>(
+        allocate_buffer(sizeof(BucketT) * NumBuckets, alignof(BucketT)));
+    return true;
+  }
+};
+
+template <typename KeyT, typename ValueT, unsigned InlineBuckets = 4,
+          typename KeyInfoT = DenseMapInfo<KeyT>,
+          typename BucketT = llvm::detail::DenseMapPair<KeyT, ValueT>>
+class SmallDenseMap
+    : public DenseMapBase<
+          SmallDenseMap<KeyT, ValueT, InlineBuckets, KeyInfoT, BucketT>, KeyT,
+          ValueT, KeyInfoT, BucketT> {
+  friend class DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
+
+  // Lift some types from the dependent base class into this class for
+  // simplicity of referring to them.
+  using BaseT = DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
+
+  static_assert(isPowerOf2_64(InlineBuckets),
+                "InlineBuckets must be a power of 2.");
+
+  unsigned Small : 1;
+  unsigned NumEntries : 31;
+  unsigned NumTombstones;
+
+  struct LargeRep {
+    BucketT *Buckets;
+    unsigned NumBuckets;
+  };
+
+  /// A "union" of an inline bucket array and the struct representing
+  /// a large bucket. This union will be discriminated by the 'Small' bit.
+  AlignedCharArrayUnion<BucketT[InlineBuckets], LargeRep> storage;
+
+public:
+  explicit SmallDenseMap(unsigned NumInitBuckets = 0) {
+    init(NumInitBuckets);
+  }
+
+  SmallDenseMap(const SmallDenseMap &other) : BaseT() {
+    init(0);
+    copyFrom(other);
+  }
+
+  SmallDenseMap(SmallDenseMap &&other) : BaseT() {
+    init(0);
+    swap(other);
+  }
+
+  template<typename InputIt>
+  SmallDenseMap(const InputIt &I, const InputIt &E) {
+    init(NextPowerOf2(std::distance(I, E)));
+    this->insert(I, E);
+  }
+
+  ~SmallDenseMap() {
+    this->destroyAll();
+    deallocateBuckets();
+  }
+
+  void swap(SmallDenseMap& RHS) {
+    unsigned TmpNumEntries = RHS.NumEntries;
+    RHS.NumEntries = NumEntries;
+    NumEntries = TmpNumEntries;
+    std::swap(NumTombstones, RHS.NumTombstones);
+
+    const KeyT EmptyKey = this->getEmptyKey();
+    const KeyT TombstoneKey = this->getTombstoneKey();
+    if (Small && RHS.Small) {
+      // If we're swapping inline bucket arrays, we have to cope with some of
+      // the tricky bits of DenseMap's storage system: the buckets are not
+      // fully initialized. Thus we swap every key, but we may have
+      // a one-directional move of the value.
+      for (unsigned i = 0, e = InlineBuckets; i != e; ++i) {
+        BucketT *LHSB = &getInlineBuckets()[i],
+                *RHSB = &RHS.getInlineBuckets()[i];
+        bool hasLHSValue = (!KeyInfoT::isEqual(LHSB->getFirst(), EmptyKey) &&
+                            !KeyInfoT::isEqual(LHSB->getFirst(), TombstoneKey));
+        bool hasRHSValue = (!KeyInfoT::isEqual(RHSB->getFirst(), EmptyKey) &&
+                            !KeyInfoT::isEqual(RHSB->getFirst(), TombstoneKey));
+        if (hasLHSValue && hasRHSValue) {
+          // Swap together if we can...
+          std::swap(*LHSB, *RHSB);
+          continue;
+        }
+        // Swap separately and handle any assymetry.
+        std::swap(LHSB->getFirst(), RHSB->getFirst());
+        if (hasLHSValue) {
+          ::new (&RHSB->getSecond()) ValueT(std::move(LHSB->getSecond()));
+          LHSB->getSecond().~ValueT();
+        } else if (hasRHSValue) {
+          ::new (&LHSB->getSecond()) ValueT(std::move(RHSB->getSecond()));
+          RHSB->getSecond().~ValueT();
+        }
+      }
+      return;
+    }
+    if (!Small && !RHS.Small) {
+      std::swap(getLargeRep()->Buckets, RHS.getLargeRep()->Buckets);
+      std::swap(getLargeRep()->NumBuckets, RHS.getLargeRep()->NumBuckets);
+      return;
+    }
+
+    SmallDenseMap &SmallSide = Small ? *this : RHS;
+    SmallDenseMap &LargeSide = Small ? RHS : *this;
+
+    // First stash the large side's rep and move the small side across.
+    LargeRep TmpRep = std::move(*LargeSide.getLargeRep());
+    LargeSide.getLargeRep()->~LargeRep();
+    LargeSide.Small = true;
+    // This is similar to the standard move-from-old-buckets, but the bucket
+    // count hasn't actually rotated in this case. So we have to carefully
+    // move construct the keys and values into their new locations, but there
+    // is no need to re-hash things.
+    for (unsigned i = 0, e = InlineBuckets; i != e; ++i) {
+      BucketT *NewB = &LargeSide.getInlineBuckets()[i],
+              *OldB = &SmallSide.getInlineBuckets()[i];
+      ::new (&NewB->getFirst()) KeyT(std::move(OldB->getFirst()));
+      OldB->getFirst().~KeyT();
+      if (!KeyInfoT::isEqual(NewB->getFirst(), EmptyKey) &&
+          !KeyInfoT::isEqual(NewB->getFirst(), TombstoneKey)) {
+        ::new (&NewB->getSecond()) ValueT(std::move(OldB->getSecond()));
+        OldB->getSecond().~ValueT();
+      }
+    }
+
+    // The hard part of moving the small buckets across is done, just move
+    // the TmpRep into its new home.
+    SmallSide.Small = false;
+    new (SmallSide.getLargeRep()) LargeRep(std::move(TmpRep));
+  }
+
+  SmallDenseMap& operator=(const SmallDenseMap& other) {
+    if (&other != this)
+      copyFrom(other);
+    return *this;
+  }
+
+  SmallDenseMap& operator=(SmallDenseMap &&other) {
+    this->destroyAll();
+    deallocateBuckets();
+    init(0);
+    swap(other);
+    return *this;
+  }
+
+  void copyFrom(const SmallDenseMap& other) {
+    this->destroyAll();
+    deallocateBuckets();
+    Small = true;
+    if (other.getNumBuckets() > InlineBuckets) {
+      Small = false;
+      new (getLargeRep()) LargeRep(allocateBuckets(other.getNumBuckets()));
+    }
+    this->BaseT::copyFrom(other);
+  }
+
+  void init(unsigned InitBuckets) {
+    Small = true;
+    if (InitBuckets > InlineBuckets) {
+      Small = false;
+      new (getLargeRep()) LargeRep(allocateBuckets(InitBuckets));
+    }
+    this->BaseT::initEmpty();
+  }
+
+  void grow(unsigned AtLeast) {
+    if (AtLeast >= InlineBuckets)
+      AtLeast = std::max<unsigned>(64, NextPowerOf2(AtLeast-1));
+
+    if (Small) {
+      if (AtLeast < InlineBuckets)
+        return; // Nothing to do.
+
+      // First move the inline buckets into a temporary storage.
+      AlignedCharArrayUnion<BucketT[InlineBuckets]> TmpStorage;
+      BucketT *TmpBegin = reinterpret_cast<BucketT *>(TmpStorage.buffer);
+      BucketT *TmpEnd = TmpBegin;
+
+      // Loop over the buckets, moving non-empty, non-tombstones into the
+      // temporary storage. Have the loop move the TmpEnd forward as it goes.
+      const KeyT EmptyKey = this->getEmptyKey();
+      const KeyT TombstoneKey = this->getTombstoneKey();
+      for (BucketT *P = getBuckets(), *E = P + InlineBuckets; P != E; ++P) {
+        if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey) &&
+            !KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
+          assert(size_t(TmpEnd - TmpBegin) < InlineBuckets &&
+                 "Too many inline buckets!");
+          ::new (&TmpEnd->getFirst()) KeyT(std::move(P->getFirst()));
+          ::new (&TmpEnd->getSecond()) ValueT(std::move(P->getSecond()));
+          ++TmpEnd;
+          P->getSecond().~ValueT();
+        }
+        P->getFirst().~KeyT();
+      }
+
+      // Now make this map use the large rep, and move all the entries back
+      // into it.
+      Small = false;
+      new (getLargeRep()) LargeRep(allocateBuckets(AtLeast));
+      this->moveFromOldBuckets(TmpBegin, TmpEnd);
+      return;
+    }
+
+    LargeRep OldRep = std::move(*getLargeRep());
+    getLargeRep()->~LargeRep();
+    if (AtLeast <= InlineBuckets) {
+      Small = true;
+    } else {
+      new (getLargeRep()) LargeRep(allocateBuckets(AtLeast));
+    }
+
+    this->moveFromOldBuckets(OldRep.Buckets, OldRep.Buckets+OldRep.NumBuckets);
+
+    // Free the old table.
+    deallocate_buffer(OldRep.Buckets, sizeof(BucketT) * OldRep.NumBuckets,
+                      alignof(BucketT));
+  }
+
+  void shrink_and_clear() {
+    unsigned OldSize = this->size();
+    this->destroyAll();
+
+    // Reduce the number of buckets.
+    unsigned NewNumBuckets = 0;
+    if (OldSize) {
+      NewNumBuckets = 1 << (Log2_32_Ceil(OldSize) + 1);
+      if (NewNumBuckets > InlineBuckets && NewNumBuckets < 64u)
+        NewNumBuckets = 64;
+    }
+    if ((Small && NewNumBuckets <= InlineBuckets) ||
+        (!Small && NewNumBuckets == getLargeRep()->NumBuckets)) {
+      this->BaseT::initEmpty();
+      return;
+    }
+
+    deallocateBuckets();
+    init(NewNumBuckets);
+  }
+
+private:
+  unsigned getNumEntries() const {
+    return NumEntries;
+  }
+
+  void setNumEntries(unsigned Num) {
+    // NumEntries is hardcoded to be 31 bits wide.
+    assert(Num < (1U << 31) && "Cannot support more than 1<<31 entries");
+    NumEntries = Num;
+  }
+
+  unsigned getNumTombstones() const {
+    return NumTombstones;
+  }
+
+  void setNumTombstones(unsigned Num) {
+    NumTombstones = Num;
+  }
+
+  const BucketT *getInlineBuckets() const {
+    assert(Small);
+    // Note that this cast does not violate aliasing rules as we assert that
+    // the memory's dynamic type is the small, inline bucket buffer, and the
+    // 'storage.buffer' static type is 'char *'.
+    return reinterpret_cast<const BucketT *>(storage.buffer);
+  }
+
+  BucketT *getInlineBuckets() {
+    return const_cast<BucketT *>(
+      const_cast<const SmallDenseMap *>(this)->getInlineBuckets());
+  }
+
+  const LargeRep *getLargeRep() const {
+    assert(!Small);
+    // Note, same rule about aliasing as with getInlineBuckets.
+    return reinterpret_cast<const LargeRep *>(storage.buffer);
+  }
+
+  LargeRep *getLargeRep() {
+    return const_cast<LargeRep *>(
+      const_cast<const SmallDenseMap *>(this)->getLargeRep());
+  }
+
+  const BucketT *getBuckets() const {
+    return Small ? getInlineBuckets() : getLargeRep()->Buckets;
+  }
+
+  BucketT *getBuckets() {
+    return const_cast<BucketT *>(
+      const_cast<const SmallDenseMap *>(this)->getBuckets());
+  }
+
+  unsigned getNumBuckets() const {
+    return Small ? InlineBuckets : getLargeRep()->NumBuckets;
+  }
+
+  void deallocateBuckets() {
+    if (Small)
+      return;
+
+    deallocate_buffer(getLargeRep()->Buckets,
+                      sizeof(BucketT) * getLargeRep()->NumBuckets,
+                      alignof(BucketT));
+    getLargeRep()->~LargeRep();
+  }
+
+  LargeRep allocateBuckets(unsigned Num) {
+    assert(Num > InlineBuckets && "Must allocate more buckets than are inline");
+    LargeRep Rep = {static_cast<BucketT *>(allocate_buffer(
+                        sizeof(BucketT) * Num, alignof(BucketT))),
+                    Num};
+    return Rep;
+  }
+};
+
+template <typename KeyT, typename ValueT, typename KeyInfoT, typename Bucket,
+          bool IsConst>
+class DenseMapIterator : DebugEpochBase::HandleBase {
+  friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
+  friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, false>;
+
+  using ConstIterator = DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
+
+public:
+  using difference_type = ptrdiff_t;
+  using value_type =
+      typename std::conditional<IsConst, const Bucket, Bucket>::type;
+  using pointer = value_type *;
+  using reference = value_type &;
+  using iterator_category = std::forward_iterator_tag;
+
+private:
+  pointer Ptr = nullptr;
+  pointer End = nullptr;
+
+public:
+  DenseMapIterator() = default;
+
+  DenseMapIterator(pointer Pos, pointer E, const DebugEpochBase &Epoch,
+                   bool NoAdvance = false)
+      : DebugEpochBase::HandleBase(&Epoch), Ptr(Pos), End(E) {
+    assert(isHandleInSync() && "invalid construction!");
+
+    if (NoAdvance) return;
+    if (shouldReverseIterate<KeyT>()) {
+      RetreatPastEmptyBuckets();
+      return;
+    }
+    AdvancePastEmptyBuckets();
+  }
+
+  // Converting ctor from non-const iterators to const iterators. SFINAE'd out
+  // for const iterator destinations so it doesn't end up as a user defined copy
+  // constructor.
+  template <bool IsConstSrc,
+            typename = typename std::enable_if<!IsConstSrc && IsConst>::type>
+  DenseMapIterator(
+      const DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, IsConstSrc> &I)
+      : DebugEpochBase::HandleBase(I), Ptr(I.Ptr), End(I.End) {}
+
+  reference operator*() const {
+    assert(isHandleInSync() && "invalid iterator access!");
+    if (shouldReverseIterate<KeyT>())
+      return Ptr[-1];
+    return *Ptr;
+  }
+  pointer operator->() const {
+    assert(isHandleInSync() && "invalid iterator access!");
+    if (shouldReverseIterate<KeyT>())
+      return &(Ptr[-1]);
+    return Ptr;
+  }
+
+  bool operator==(const ConstIterator &RHS) const {
+    assert((!Ptr || isHandleInSync()) && "handle not in sync!");
+    assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
+    assert(getEpochAddress() == RHS.getEpochAddress() &&
+           "comparing incomparable iterators!");
+    return Ptr == RHS.Ptr;
+  }
+  bool operator!=(const ConstIterator &RHS) const {
+    assert((!Ptr || isHandleInSync()) && "handle not in sync!");
+    assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
+    assert(getEpochAddress() == RHS.getEpochAddress() &&
+           "comparing incomparable iterators!");
+    return Ptr != RHS.Ptr;
+  }
+
+  inline DenseMapIterator& operator++() {  // Preincrement
+    assert(isHandleInSync() && "invalid iterator access!");
+    if (shouldReverseIterate<KeyT>()) {
+      --Ptr;
+      RetreatPastEmptyBuckets();
+      return *this;
+    }
+    ++Ptr;
+    AdvancePastEmptyBuckets();
+    return *this;
+  }
+  DenseMapIterator operator++(int) {  // Postincrement
+    assert(isHandleInSync() && "invalid iterator access!");
+    DenseMapIterator tmp = *this; ++*this; return tmp;
+  }
+
+private:
+  void AdvancePastEmptyBuckets() {
+    assert(Ptr <= End);
+    const KeyT Empty = KeyInfoT::getEmptyKey();
+    const KeyT Tombstone = KeyInfoT::getTombstoneKey();
+
+    while (Ptr != End && (KeyInfoT::isEqual(Ptr->getFirst(), Empty) ||
+                          KeyInfoT::isEqual(Ptr->getFirst(), Tombstone)))
+      ++Ptr;
+  }
+
+  void RetreatPastEmptyBuckets() {
+    assert(Ptr >= End);
+    const KeyT Empty = KeyInfoT::getEmptyKey();
+    const KeyT Tombstone = KeyInfoT::getTombstoneKey();
+
+    while (Ptr != End && (KeyInfoT::isEqual(Ptr[-1].getFirst(), Empty) ||
+                          KeyInfoT::isEqual(Ptr[-1].getFirst(), Tombstone)))
+      --Ptr;
+  }
+};
+
+template <typename KeyT, typename ValueT, typename KeyInfoT>
+inline size_t capacity_in_bytes(const DenseMap<KeyT, ValueT, KeyInfoT> &X) {
+  return X.getMemorySize();
+}
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_DENSEMAP_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/DenseMapInfo.h b/binaryen/third_party/llvm-project/include/llvm/ADT/DenseMapInfo.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/DenseMapInfo.h
@@ -0,0 +1,300 @@
+//===- llvm/ADT/DenseMapInfo.h - Type traits for DenseMap -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines DenseMapInfo traits for DenseMap.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_DENSEMAPINFO_H
+#define LLVM_ADT_DENSEMAPINFO_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
+#include "llvm/Support/TypeSize.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <utility>
+
+namespace llvm {
+
+template<typename T>
+struct DenseMapInfo {
+  //static inline T getEmptyKey();
+  //static inline T getTombstoneKey();
+  //static unsigned getHashValue(const T &Val);
+  //static bool isEqual(const T &LHS, const T &RHS);
+};
+
+// Provide DenseMapInfo for all pointers.
+template<typename T>
+struct DenseMapInfo<T*> {
+  static inline T* getEmptyKey() {
+    uintptr_t Val = static_cast<uintptr_t>(-1);
+    Val <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable;
+    return reinterpret_cast<T*>(Val);
+  }
+
+  static inline T* getTombstoneKey() {
+    uintptr_t Val = static_cast<uintptr_t>(-2);
+    Val <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable;
+    return reinterpret_cast<T*>(Val);
+  }
+
+  static unsigned getHashValue(const T *PtrVal) {
+    return (unsigned((uintptr_t)PtrVal) >> 4) ^
+           (unsigned((uintptr_t)PtrVal) >> 9);
+  }
+
+  static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; }
+};
+
+// Provide DenseMapInfo for chars.
+template<> struct DenseMapInfo<char> {
+  static inline char getEmptyKey() { return ~0; }
+  static inline char getTombstoneKey() { return ~0 - 1; }
+  static unsigned getHashValue(const char& Val) { return Val * 37U; }
+
+  static bool isEqual(const char &LHS, const char &RHS) {
+    return LHS == RHS;
+  }
+};
+
+// Provide DenseMapInfo for unsigned chars.
+template <> struct DenseMapInfo<unsigned char> {
+  static inline unsigned char getEmptyKey() { return ~0; }
+  static inline unsigned char getTombstoneKey() { return ~0 - 1; }
+  static unsigned getHashValue(const unsigned char &Val) { return Val * 37U; }
+
+  static bool isEqual(const unsigned char &LHS, const unsigned char &RHS) {
+    return LHS == RHS;
+  }
+};
+
+// Provide DenseMapInfo for unsigned shorts.
+template <> struct DenseMapInfo<unsigned short> {
+  static inline unsigned short getEmptyKey() { return 0xFFFF; }
+  static inline unsigned short getTombstoneKey() { return 0xFFFF - 1; }
+  static unsigned getHashValue(const unsigned short &Val) { return Val * 37U; }
+
+  static bool isEqual(const unsigned short &LHS, const unsigned short &RHS) {
+    return LHS == RHS;
+  }
+};
+
+// Provide DenseMapInfo for unsigned ints.
+template<> struct DenseMapInfo<unsigned> {
+  static inline unsigned getEmptyKey() { return ~0U; }
+  static inline unsigned getTombstoneKey() { return ~0U - 1; }
+  static unsigned getHashValue(const unsigned& Val) { return Val * 37U; }
+
+  static bool isEqual(const unsigned& LHS, const unsigned& RHS) {
+    return LHS == RHS;
+  }
+};
+
+// Provide DenseMapInfo for unsigned longs.
+template<> struct DenseMapInfo<unsigned long> {
+  static inline unsigned long getEmptyKey() { return ~0UL; }
+  static inline unsigned long getTombstoneKey() { return ~0UL - 1L; }
+
+  static unsigned getHashValue(const unsigned long& Val) {
+    return (unsigned)(Val * 37UL);
+  }
+
+  static bool isEqual(const unsigned long& LHS, const unsigned long& RHS) {
+    return LHS == RHS;
+  }
+};
+
+// Provide DenseMapInfo for unsigned long longs.
+template<> struct DenseMapInfo<unsigned long long> {
+  static inline unsigned long long getEmptyKey() { return ~0ULL; }
+  static inline unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; }
+
+  static unsigned getHashValue(const unsigned long long& Val) {
+    return (unsigned)(Val * 37ULL);
+  }
+
+  static bool isEqual(const unsigned long long& LHS,
+                      const unsigned long long& RHS) {
+    return LHS == RHS;
+  }
+};
+
+// Provide DenseMapInfo for shorts.
+template <> struct DenseMapInfo<short> {
+  static inline short getEmptyKey() { return 0x7FFF; }
+  static inline short getTombstoneKey() { return -0x7FFF - 1; }
+  static unsigned getHashValue(const short &Val) { return Val * 37U; }
+  static bool isEqual(const short &LHS, const short &RHS) { return LHS == RHS; }
+};
+
+// Provide DenseMapInfo for ints.
+template<> struct DenseMapInfo<int> {
+  static inline int getEmptyKey() { return 0x7fffffff; }
+  static inline int getTombstoneKey() { return -0x7fffffff - 1; }
+  static unsigned getHashValue(const int& Val) { return (unsigned)(Val * 37U); }
+
+  static bool isEqual(const int& LHS, const int& RHS) {
+    return LHS == RHS;
+  }
+};
+
+// Provide DenseMapInfo for longs.
+template<> struct DenseMapInfo<long> {
+  static inline long getEmptyKey() {
+    return (1UL << (sizeof(long) * 8 - 1)) - 1UL;
+  }
+
+  static inline long getTombstoneKey() { return getEmptyKey() - 1L; }
+
+  static unsigned getHashValue(const long& Val) {
+    return (unsigned)(Val * 37UL);
+  }
+
+  static bool isEqual(const long& LHS, const long& RHS) {
+    return LHS == RHS;
+  }
+};
+
+// Provide DenseMapInfo for long longs.
+template<> struct DenseMapInfo<long long> {
+  static inline long long getEmptyKey() { return 0x7fffffffffffffffLL; }
+  static inline long long getTombstoneKey() { return -0x7fffffffffffffffLL-1; }
+
+  static unsigned getHashValue(const long long& Val) {
+    return (unsigned)(Val * 37ULL);
+  }
+
+  static bool isEqual(const long long& LHS,
+                      const long long& RHS) {
+    return LHS == RHS;
+  }
+};
+
+// Provide DenseMapInfo for all pairs whose members have info.
+template<typename T, typename U>
+struct DenseMapInfo<std::pair<T, U>> {
+  using Pair = std::pair<T, U>;
+  using FirstInfo = DenseMapInfo<T>;
+  using SecondInfo = DenseMapInfo<U>;
+
+  static inline Pair getEmptyKey() {
+    return std::make_pair(FirstInfo::getEmptyKey(),
+                          SecondInfo::getEmptyKey());
+  }
+
+  static inline Pair getTombstoneKey() {
+    return std::make_pair(FirstInfo::getTombstoneKey(),
+                          SecondInfo::getTombstoneKey());
+  }
+
+  static unsigned getHashValue(const Pair& PairVal) {
+    uint64_t key = (uint64_t)FirstInfo::getHashValue(PairVal.first) << 32
+          | (uint64_t)SecondInfo::getHashValue(PairVal.second);
+    key += ~(key << 32);
+    key ^= (key >> 22);
+    key += ~(key << 13);
+    key ^= (key >> 8);
+    key += (key << 3);
+    key ^= (key >> 15);
+    key += ~(key << 27);
+    key ^= (key >> 31);
+    return (unsigned)key;
+  }
+
+  static bool isEqual(const Pair &LHS, const Pair &RHS) {
+    return FirstInfo::isEqual(LHS.first, RHS.first) &&
+           SecondInfo::isEqual(LHS.second, RHS.second);
+  }
+};
+
+// Provide DenseMapInfo for StringRefs.
+template <> struct DenseMapInfo<StringRef> {
+  static inline StringRef getEmptyKey() {
+    return StringRef(reinterpret_cast<const char *>(~static_cast<uintptr_t>(0)),
+                     0);
+  }
+
+  static inline StringRef getTombstoneKey() {
+    return StringRef(reinterpret_cast<const char *>(~static_cast<uintptr_t>(1)),
+                     0);
+  }
+
+  static unsigned getHashValue(StringRef Val) {
+    assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!");
+    assert(Val.data() != getTombstoneKey().data() &&
+           "Cannot hash the tombstone key!");
+    return (unsigned)(hash_value(Val));
+  }
+
+  static bool isEqual(StringRef LHS, StringRef RHS) {
+    if (RHS.data() == getEmptyKey().data())
+      return LHS.data() == getEmptyKey().data();
+    if (RHS.data() == getTombstoneKey().data())
+      return LHS.data() == getTombstoneKey().data();
+    return LHS == RHS;
+  }
+};
+
+// Provide DenseMapInfo for ArrayRefs.
+template <typename T> struct DenseMapInfo<ArrayRef<T>> {
+  static inline ArrayRef<T> getEmptyKey() {
+    return ArrayRef<T>(reinterpret_cast<const T *>(~static_cast<uintptr_t>(0)),
+                       size_t(0));
+  }
+
+  static inline ArrayRef<T> getTombstoneKey() {
+    return ArrayRef<T>(reinterpret_cast<const T *>(~static_cast<uintptr_t>(1)),
+                       size_t(0));
+  }
+
+  static unsigned getHashValue(ArrayRef<T> Val) {
+    assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!");
+    assert(Val.data() != getTombstoneKey().data() &&
+           "Cannot hash the tombstone key!");
+    return (unsigned)(hash_value(Val));
+  }
+
+  static bool isEqual(ArrayRef<T> LHS, ArrayRef<T> RHS) {
+    if (RHS.data() == getEmptyKey().data())
+      return LHS.data() == getEmptyKey().data();
+    if (RHS.data() == getTombstoneKey().data())
+      return LHS.data() == getTombstoneKey().data();
+    return LHS == RHS;
+  }
+};
+
+template <> struct DenseMapInfo<hash_code> {
+  static inline hash_code getEmptyKey() { return hash_code(-1); }
+  static inline hash_code getTombstoneKey() { return hash_code(-2); }
+  static unsigned getHashValue(hash_code val) { return val; }
+  static bool isEqual(hash_code LHS, hash_code RHS) { return LHS == RHS; }
+};
+
+template <> struct DenseMapInfo<ElementCount> {
+  static inline ElementCount getEmptyKey() { return {~0U, true}; }
+  static inline ElementCount getTombstoneKey() { return {~0U - 1, false}; }
+  static unsigned getHashValue(const ElementCount& EltCnt) {
+    if (EltCnt.Scalable)
+      return (EltCnt.Min * 37U) - 1U;
+
+    return EltCnt.Min * 37U;
+  }
+
+  static bool isEqual(const ElementCount& LHS, const ElementCount& RHS) {
+    return LHS == RHS;
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_DENSEMAPINFO_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/DenseSet.h b/binaryen/third_party/llvm-project/include/llvm/ADT/DenseSet.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/DenseSet.h
@@ -0,0 +1,283 @@
+//===- llvm/ADT/DenseSet.h - Dense probed hash table ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the DenseSet and SmallDenseSet classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_DENSESET_H
+#define LLVM_ADT_DENSESET_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/type_traits.h"
+#include <algorithm>
+#include <cstddef>
+#include <initializer_list>
+#include <iterator>
+#include <utility>
+
+namespace llvm {
+
+namespace detail {
+
+struct DenseSetEmpty {};
+
+// Use the empty base class trick so we can create a DenseMap where the buckets
+// contain only a single item.
+template <typename KeyT> class DenseSetPair : public DenseSetEmpty {
+  KeyT key;
+
+public:
+  KeyT &getFirst() { return key; }
+  const KeyT &getFirst() const { return key; }
+  DenseSetEmpty &getSecond() { return *this; }
+  const DenseSetEmpty &getSecond() const { return *this; }
+};
+
+/// Base class for DenseSet and DenseSmallSet.
+///
+/// MapTy should be either
+///
+///   DenseMap<ValueT, detail::DenseSetEmpty, ValueInfoT,
+///            detail::DenseSetPair<ValueT>>
+///
+/// or the equivalent SmallDenseMap type.  ValueInfoT must implement the
+/// DenseMapInfo "concept".
+template <typename ValueT, typename MapTy, typename ValueInfoT>
+class DenseSetImpl {
+  static_assert(sizeof(typename MapTy::value_type) == sizeof(ValueT),
+                "DenseMap buckets unexpectedly large!");
+  MapTy TheMap;
+
+  template <typename T>
+  using const_arg_type_t = typename const_pointer_or_const_ref<T>::type;
+
+public:
+  using key_type = ValueT;
+  using value_type = ValueT;
+  using size_type = unsigned;
+
+  explicit DenseSetImpl(unsigned InitialReserve = 0) : TheMap(InitialReserve) {}
+
+  DenseSetImpl(std::initializer_list<ValueT> Elems)
+      : DenseSetImpl(PowerOf2Ceil(Elems.size())) {
+    insert(Elems.begin(), Elems.end());
+  }
+
+  bool empty() const { return TheMap.empty(); }
+  size_type size() const { return TheMap.size(); }
+  size_t getMemorySize() const { return TheMap.getMemorySize(); }
+
+  /// Grow the DenseSet so that it has at least Size buckets. Will not shrink
+  /// the Size of the set.
+  void resize(size_t Size) { TheMap.resize(Size); }
+
+  /// Grow the DenseSet so that it can contain at least \p NumEntries items
+  /// before resizing again.
+  void reserve(size_t Size) { TheMap.reserve(Size); }
+
+  void clear() {
+    TheMap.clear();
+  }
+
+  /// Return 1 if the specified key is in the set, 0 otherwise.
+  size_type count(const_arg_type_t<ValueT> V) const {
+    return TheMap.count(V);
+  }
+
+  bool erase(const ValueT &V) {
+    return TheMap.erase(V);
+  }
+
+  void swap(DenseSetImpl &RHS) { TheMap.swap(RHS.TheMap); }
+
+  // Iterators.
+
+  class ConstIterator;
+
+  class Iterator {
+    typename MapTy::iterator I;
+    friend class DenseSetImpl;
+    friend class ConstIterator;
+
+  public:
+    using difference_type = typename MapTy::iterator::difference_type;
+    using value_type = ValueT;
+    using pointer = value_type *;
+    using reference = value_type &;
+    using iterator_category = std::forward_iterator_tag;
+
+    Iterator() = default;
+    Iterator(const typename MapTy::iterator &i) : I(i) {}
+
+    ValueT &operator*() { return I->getFirst(); }
+    const ValueT &operator*() const { return I->getFirst(); }
+    ValueT *operator->() { return &I->getFirst(); }
+    const ValueT *operator->() const { return &I->getFirst(); }
+
+    Iterator& operator++() { ++I; return *this; }
+    Iterator operator++(int) { auto T = *this; ++I; return T; }
+    bool operator==(const ConstIterator& X) const { return I == X.I; }
+    bool operator!=(const ConstIterator& X) const { return I != X.I; }
+  };
+
+  class ConstIterator {
+    typename MapTy::const_iterator I;
+    friend class DenseSetImpl;
+    friend class Iterator;
+
+  public:
+    using difference_type = typename MapTy::const_iterator::difference_type;
+    using value_type = ValueT;
+    using pointer = const value_type *;
+    using reference = const value_type &;
+    using iterator_category = std::forward_iterator_tag;
+
+    ConstIterator() = default;
+    ConstIterator(const Iterator &B) : I(B.I) {}
+    ConstIterator(const typename MapTy::const_iterator &i) : I(i) {}
+
+    const ValueT &operator*() const { return I->getFirst(); }
+    const ValueT *operator->() const { return &I->getFirst(); }
+
+    ConstIterator& operator++() { ++I; return *this; }
+    ConstIterator operator++(int) { auto T = *this; ++I; return T; }
+    bool operator==(const ConstIterator& X) const { return I == X.I; }
+    bool operator!=(const ConstIterator& X) const { return I != X.I; }
+  };
+
+  using iterator = Iterator;
+  using const_iterator = ConstIterator;
+
+  iterator begin() { return Iterator(TheMap.begin()); }
+  iterator end() { return Iterator(TheMap.end()); }
+
+  const_iterator begin() const { return ConstIterator(TheMap.begin()); }
+  const_iterator end() const { return ConstIterator(TheMap.end()); }
+
+  iterator find(const_arg_type_t<ValueT> V) { return Iterator(TheMap.find(V)); }
+  const_iterator find(const_arg_type_t<ValueT> V) const {
+    return ConstIterator(TheMap.find(V));
+  }
+
+  /// Alternative version of find() which allows a different, and possibly less
+  /// expensive, key type.
+  /// The DenseMapInfo is responsible for supplying methods
+  /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key type
+  /// used.
+  template <class LookupKeyT>
+  iterator find_as(const LookupKeyT &Val) {
+    return Iterator(TheMap.find_as(Val));
+  }
+  template <class LookupKeyT>
+  const_iterator find_as(const LookupKeyT &Val) const {
+    return ConstIterator(TheMap.find_as(Val));
+  }
+
+  void erase(Iterator I) { return TheMap.erase(I.I); }
+  void erase(ConstIterator CI) { return TheMap.erase(CI.I); }
+
+  std::pair<iterator, bool> insert(const ValueT &V) {
+    detail::DenseSetEmpty Empty;
+    return TheMap.try_emplace(V, Empty);
+  }
+
+  std::pair<iterator, bool> insert(ValueT &&V) {
+    detail::DenseSetEmpty Empty;
+    return TheMap.try_emplace(std::move(V), Empty);
+  }
+
+  /// Alternative version of insert that uses a different (and possibly less
+  /// expensive) key type.
+  template <typename LookupKeyT>
+  std::pair<iterator, bool> insert_as(const ValueT &V,
+                                      const LookupKeyT &LookupKey) {
+    return TheMap.insert_as({V, detail::DenseSetEmpty()}, LookupKey);
+  }
+  template <typename LookupKeyT>
+  std::pair<iterator, bool> insert_as(ValueT &&V, const LookupKeyT &LookupKey) {
+    return TheMap.insert_as({std::move(V), detail::DenseSetEmpty()}, LookupKey);
+  }
+
+  // Range insertion of values.
+  template<typename InputIt>
+  void insert(InputIt I, InputIt E) {
+    for (; I != E; ++I)
+      insert(*I);
+  }
+};
+
+/// Equality comparison for DenseSet.
+///
+/// Iterates over elements of LHS confirming that each element is also a member
+/// of RHS, and that RHS contains no additional values.
+/// Equivalent to N calls to RHS.count. Amortized complexity is linear, worst
+/// case is O(N^2) (if every hash collides).
+template <typename ValueT, typename MapTy, typename ValueInfoT>
+bool operator==(const DenseSetImpl<ValueT, MapTy, ValueInfoT> &LHS,
+                const DenseSetImpl<ValueT, MapTy, ValueInfoT> &RHS) {
+  if (LHS.size() != RHS.size())
+    return false;
+
+  for (auto &E : LHS)
+    if (!RHS.count(E))
+      return false;
+
+  return true;
+}
+
+/// Inequality comparison for DenseSet.
+///
+/// Equivalent to !(LHS == RHS). See operator== for performance notes.
+template <typename ValueT, typename MapTy, typename ValueInfoT>
+bool operator!=(const DenseSetImpl<ValueT, MapTy, ValueInfoT> &LHS,
+                const DenseSetImpl<ValueT, MapTy, ValueInfoT> &RHS) {
+  return !(LHS == RHS);
+}
+
+} // end namespace detail
+
+/// Implements a dense probed hash-table based set.
+template <typename ValueT, typename ValueInfoT = DenseMapInfo<ValueT>>
+class DenseSet : public detail::DenseSetImpl<
+                     ValueT, DenseMap<ValueT, detail::DenseSetEmpty, ValueInfoT,
+                                      detail::DenseSetPair<ValueT>>,
+                     ValueInfoT> {
+  using BaseT =
+      detail::DenseSetImpl<ValueT,
+                           DenseMap<ValueT, detail::DenseSetEmpty, ValueInfoT,
+                                    detail::DenseSetPair<ValueT>>,
+                           ValueInfoT>;
+
+public:
+  using BaseT::BaseT;
+};
+
+/// Implements a dense probed hash-table based set with some number of buckets
+/// stored inline.
+template <typename ValueT, unsigned InlineBuckets = 4,
+          typename ValueInfoT = DenseMapInfo<ValueT>>
+class SmallDenseSet
+    : public detail::DenseSetImpl<
+          ValueT, SmallDenseMap<ValueT, detail::DenseSetEmpty, InlineBuckets,
+                                ValueInfoT, detail::DenseSetPair<ValueT>>,
+          ValueInfoT> {
+  using BaseT = detail::DenseSetImpl<
+      ValueT, SmallDenseMap<ValueT, detail::DenseSetEmpty, InlineBuckets,
+                            ValueInfoT, detail::DenseSetPair<ValueT>>,
+      ValueInfoT>;
+
+public:
+  using BaseT::BaseT;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_DENSESET_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/EpochTracker.h b/binaryen/third_party/llvm-project/include/llvm/ADT/EpochTracker.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/EpochTracker.h
@@ -0,0 +1,98 @@
+//===- llvm/ADT/EpochTracker.h - ADT epoch tracking --------------*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the DebugEpochBase and DebugEpochBase::HandleBase classes.
+// These can be used to write iterators that are fail-fast when LLVM is built
+// with asserts enabled.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_EPOCH_TRACKER_H
+#define LLVM_ADT_EPOCH_TRACKER_H
+
+#include "llvm/Config/abi-breaking.h"
+
+#include <cstdint>
+
+namespace llvm {
+
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+
+/// A base class for data structure classes wishing to make iterators
+/// ("handles") pointing into themselves fail-fast.  When building without
+/// asserts, this class is empty and does nothing.
+///
+/// DebugEpochBase does not by itself track handles pointing into itself.  The
+/// expectation is that routines touching the handles will poll on
+/// isHandleInSync at appropriate points to assert that the handle they're using
+/// is still valid.
+///
+class DebugEpochBase {
+  uint64_t Epoch;
+
+public:
+  DebugEpochBase() : Epoch(0) {}
+
+  /// Calling incrementEpoch invalidates all handles pointing into the
+  /// calling instance.
+  void incrementEpoch() { ++Epoch; }
+
+  /// The destructor calls incrementEpoch to make use-after-free bugs
+  /// more likely to crash deterministically.
+  ~DebugEpochBase() { incrementEpoch(); }
+
+  /// A base class for iterator classes ("handles") that wish to poll for
+  /// iterator invalidating modifications in the underlying data structure.
+  /// When LLVM is built without asserts, this class is empty and does nothing.
+  ///
+  /// HandleBase does not track the parent data structure by itself.  It expects
+  /// the routines modifying the data structure to call incrementEpoch when they
+  /// make an iterator-invalidating modification.
+  ///
+  class HandleBase {
+    const uint64_t *EpochAddress;
+    uint64_t EpochAtCreation;
+
+  public:
+    HandleBase() : EpochAddress(nullptr), EpochAtCreation(UINT64_MAX) {}
+
+    explicit HandleBase(const DebugEpochBase *Parent)
+        : EpochAddress(&Parent->Epoch), EpochAtCreation(Parent->Epoch) {}
+
+    /// Returns true if the DebugEpochBase this Handle is linked to has
+    /// not called incrementEpoch on itself since the creation of this
+    /// HandleBase instance.
+    bool isHandleInSync() const { return *EpochAddress == EpochAtCreation; }
+
+    /// Returns a pointer to the epoch word stored in the data structure
+    /// this handle points into.  Can be used to check if two iterators point
+    /// into the same data structure.
+    const void *getEpochAddress() const { return EpochAddress; }
+  };
+};
+
+#else
+
+class DebugEpochBase {
+public:
+  void incrementEpoch() {}
+
+  class HandleBase {
+  public:
+    HandleBase() = default;
+    explicit HandleBase(const DebugEpochBase *) {}
+    bool isHandleInSync() const { return true; }
+    const void *getEpochAddress() const { return nullptr; }
+  };
+};
+
+#endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
+
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/FoldingSet.h b/binaryen/third_party/llvm-project/include/llvm/ADT/FoldingSet.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/FoldingSet.h
@@ -0,0 +1,761 @@
+//===- llvm/ADT/FoldingSet.h - Uniquing Hash Set ----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a hash set that can be used to remove duplication of nodes
+// in a graph.  This code was originally created by Chris Lattner for use with
+// SelectionDAGCSEMap, but was isolated to provide use across the llvm code set.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_FOLDINGSET_H
+#define LLVM_ADT_FOLDINGSET_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/Support/Allocator.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <utility>
+
+namespace llvm {
+
+/// This folding set used for two purposes:
+///   1. Given information about a node we want to create, look up the unique
+///      instance of the node in the set.  If the node already exists, return
+///      it, otherwise return the bucket it should be inserted into.
+///   2. Given a node that has already been created, remove it from the set.
+///
+/// This class is implemented as a single-link chained hash table, where the
+/// "buckets" are actually the nodes themselves (the next pointer is in the
+/// node).  The last node points back to the bucket to simplify node removal.
+///
+/// Any node that is to be included in the folding set must be a subclass of
+/// FoldingSetNode.  The node class must also define a Profile method used to
+/// establish the unique bits of data for the node.  The Profile method is
+/// passed a FoldingSetNodeID object which is used to gather the bits.  Just
+/// call one of the Add* functions defined in the FoldingSetBase::NodeID class.
+/// NOTE: That the folding set does not own the nodes and it is the
+/// responsibility of the user to dispose of the nodes.
+///
+/// Eg.
+///    class MyNode : public FoldingSetNode {
+///    private:
+///      std::string Name;
+///      unsigned Value;
+///    public:
+///      MyNode(const char *N, unsigned V) : Name(N), Value(V) {}
+///       ...
+///      void Profile(FoldingSetNodeID &ID) const {
+///        ID.AddString(Name);
+///        ID.AddInteger(Value);
+///      }
+///      ...
+///    };
+///
+/// To define the folding set itself use the FoldingSet template;
+///
+/// Eg.
+///    FoldingSet<MyNode> MyFoldingSet;
+///
+/// Four public methods are available to manipulate the folding set;
+///
+/// 1) If you have an existing node that you want add to the set but unsure
+/// that the node might already exist then call;
+///
+///    MyNode *M = MyFoldingSet.GetOrInsertNode(N);
+///
+/// If The result is equal to the input then the node has been inserted.
+/// Otherwise, the result is the node existing in the folding set, and the
+/// input can be discarded (use the result instead.)
+///
+/// 2) If you are ready to construct a node but want to check if it already
+/// exists, then call FindNodeOrInsertPos with a FoldingSetNodeID of the bits to
+/// check;
+///
+///   FoldingSetNodeID ID;
+///   ID.AddString(Name);
+///   ID.AddInteger(Value);
+///   void *InsertPoint;
+///
+///    MyNode *M = MyFoldingSet.FindNodeOrInsertPos(ID, InsertPoint);
+///
+/// If found then M with be non-NULL, else InsertPoint will point to where it
+/// should be inserted using InsertNode.
+///
+/// 3) If you get a NULL result from FindNodeOrInsertPos then you can as a new
+/// node with FindNodeOrInsertPos;
+///
+///    InsertNode(N, InsertPoint);
+///
+/// 4) Finally, if you want to remove a node from the folding set call;
+///
+///    bool WasRemoved = RemoveNode(N);
+///
+/// The result indicates whether the node existed in the folding set.
+
+class FoldingSetNodeID;
+class StringRef;
+
+//===----------------------------------------------------------------------===//
+/// FoldingSetBase - Implements the folding set functionality.  The main
+/// structure is an array of buckets.  Each bucket is indexed by the hash of
+/// the nodes it contains.  The bucket itself points to the nodes contained
+/// in the bucket via a singly linked list.  The last node in the list points
+/// back to the bucket to facilitate node removal.
+///
+class FoldingSetBase {
+  virtual void anchor(); // Out of line virtual method.
+
+protected:
+  /// Buckets - Array of bucket chains.
+  void **Buckets;
+
+  /// NumBuckets - Length of the Buckets array.  Always a power of 2.
+  unsigned NumBuckets;
+
+  /// NumNodes - Number of nodes in the folding set. Growth occurs when NumNodes
+  /// is greater than twice the number of buckets.
+  unsigned NumNodes;
+
+  explicit FoldingSetBase(unsigned Log2InitSize = 6);
+  FoldingSetBase(FoldingSetBase &&Arg);
+  FoldingSetBase &operator=(FoldingSetBase &&RHS);
+  ~FoldingSetBase();
+
+public:
+  //===--------------------------------------------------------------------===//
+  /// Node - This class is used to maintain the singly linked bucket list in
+  /// a folding set.
+  class Node {
+  private:
+    // NextInFoldingSetBucket - next link in the bucket list.
+    void *NextInFoldingSetBucket = nullptr;
+
+  public:
+    Node() = default;
+
+    // Accessors
+    void *getNextInBucket() const { return NextInFoldingSetBucket; }
+    void SetNextInBucket(void *N) { NextInFoldingSetBucket = N; }
+  };
+
+  /// clear - Remove all nodes from the folding set.
+  void clear();
+
+  /// size - Returns the number of nodes in the folding set.
+  unsigned size() const { return NumNodes; }
+
+  /// empty - Returns true if there are no nodes in the folding set.
+  bool empty() const { return NumNodes == 0; }
+
+  /// reserve - Increase the number of buckets such that adding the
+  /// EltCount-th node won't cause a rebucket operation. reserve is permitted
+  /// to allocate more space than requested by EltCount.
+  void reserve(unsigned EltCount);
+
+  /// capacity - Returns the number of nodes permitted in the folding set
+  /// before a rebucket operation is performed.
+  unsigned capacity() {
+    // We allow a load factor of up to 2.0,
+    // so that means our capacity is NumBuckets * 2
+    return NumBuckets * 2;
+  }
+
+private:
+  /// GrowHashTable - Double the size of the hash table and rehash everything.
+  void GrowHashTable();
+
+  /// GrowBucketCount - resize the hash table and rehash everything.
+  /// NewBucketCount must be a power of two, and must be greater than the old
+  /// bucket count.
+  void GrowBucketCount(unsigned NewBucketCount);
+
+protected:
+  /// GetNodeProfile - Instantiations of the FoldingSet template implement
+  /// this function to gather data bits for the given node.
+  virtual void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const = 0;
+
+  /// NodeEquals - Instantiations of the FoldingSet template implement
+  /// this function to compare the given node with the given ID.
+  virtual bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash,
+                          FoldingSetNodeID &TempID) const=0;
+
+  /// ComputeNodeHash - Instantiations of the FoldingSet template implement
+  /// this function to compute a hash value for the given node.
+  virtual unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const = 0;
+
+  // The below methods are protected to encourage subclasses to provide a more
+  // type-safe API.
+
+  /// RemoveNode - Remove a node from the folding set, returning true if one
+  /// was removed or false if the node was not in the folding set.
+  bool RemoveNode(Node *N);
+
+  /// GetOrInsertNode - If there is an existing simple Node exactly
+  /// equal to the specified node, return it.  Otherwise, insert 'N' and return
+  /// it instead.
+  Node *GetOrInsertNode(Node *N);
+
+  /// FindNodeOrInsertPos - Look up the node specified by ID.  If it exists,
+  /// return it.  If not, return the insertion token that will make insertion
+  /// faster.
+  Node *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos);
+
+  /// InsertNode - Insert the specified node into the folding set, knowing that
+  /// it is not already in the folding set.  InsertPos must be obtained from
+  /// FindNodeOrInsertPos.
+  void InsertNode(Node *N, void *InsertPos);
+};
+
+//===----------------------------------------------------------------------===//
+
+/// DefaultFoldingSetTrait - This class provides default implementations
+/// for FoldingSetTrait implementations.
+template<typename T> struct DefaultFoldingSetTrait {
+  static void Profile(const T &X, FoldingSetNodeID &ID) {
+    X.Profile(ID);
+  }
+  static void Profile(T &X, FoldingSetNodeID &ID) {
+    X.Profile(ID);
+  }
+
+  // Equals - Test if the profile for X would match ID, using TempID
+  // to compute a temporary ID if necessary. The default implementation
+  // just calls Profile and does a regular comparison. Implementations
+  // can override this to provide more efficient implementations.
+  static inline bool Equals(T &X, const FoldingSetNodeID &ID, unsigned IDHash,
+                            FoldingSetNodeID &TempID);
+
+  // ComputeHash - Compute a hash value for X, using TempID to
+  // compute a temporary ID if necessary. The default implementation
+  // just calls Profile and does a regular hash computation.
+  // Implementations can override this to provide more efficient
+  // implementations.
+  static inline unsigned ComputeHash(T &X, FoldingSetNodeID &TempID);
+};
+
+/// FoldingSetTrait - This trait class is used to define behavior of how
+/// to "profile" (in the FoldingSet parlance) an object of a given type.
+/// The default behavior is to invoke a 'Profile' method on an object, but
+/// through template specialization the behavior can be tailored for specific
+/// types.  Combined with the FoldingSetNodeWrapper class, one can add objects
+/// to FoldingSets that were not originally designed to have that behavior.
+template<typename T> struct FoldingSetTrait
+  : public DefaultFoldingSetTrait<T> {};
+
+/// DefaultContextualFoldingSetTrait - Like DefaultFoldingSetTrait, but
+/// for ContextualFoldingSets.
+template<typename T, typename Ctx>
+struct DefaultContextualFoldingSetTrait {
+  static void Profile(T &X, FoldingSetNodeID &ID, Ctx Context) {
+    X.Profile(ID, Context);
+  }
+
+  static inline bool Equals(T &X, const FoldingSetNodeID &ID, unsigned IDHash,
+                            FoldingSetNodeID &TempID, Ctx Context);
+  static inline unsigned ComputeHash(T &X, FoldingSetNodeID &TempID,
+                                     Ctx Context);
+};
+
+/// ContextualFoldingSetTrait - Like FoldingSetTrait, but for
+/// ContextualFoldingSets.
+template<typename T, typename Ctx> struct ContextualFoldingSetTrait
+  : public DefaultContextualFoldingSetTrait<T, Ctx> {};
+
+//===--------------------------------------------------------------------===//
+/// FoldingSetNodeIDRef - This class describes a reference to an interned
+/// FoldingSetNodeID, which can be a useful to store node id data rather
+/// than using plain FoldingSetNodeIDs, since the 32-element SmallVector
+/// is often much larger than necessary, and the possibility of heap
+/// allocation means it requires a non-trivial destructor call.
+class FoldingSetNodeIDRef {
+  const unsigned *Data = nullptr;
+  size_t Size = 0;
+
+public:
+  FoldingSetNodeIDRef() = default;
+  FoldingSetNodeIDRef(const unsigned *D, size_t S) : Data(D), Size(S) {}
+
+  /// ComputeHash - Compute a strong hash value for this FoldingSetNodeIDRef,
+  /// used to lookup the node in the FoldingSetBase.
+  unsigned ComputeHash() const;
+
+  bool operator==(FoldingSetNodeIDRef) const;
+
+  bool operator!=(FoldingSetNodeIDRef RHS) const { return !(*this == RHS); }
+
+  /// Used to compare the "ordering" of two nodes as defined by the
+  /// profiled bits and their ordering defined by memcmp().
+  bool operator<(FoldingSetNodeIDRef) const;
+
+  const unsigned *getData() const { return Data; }
+  size_t getSize() const { return Size; }
+};
+
+//===--------------------------------------------------------------------===//
+/// FoldingSetNodeID - This class is used to gather all the unique data bits of
+/// a node.  When all the bits are gathered this class is used to produce a
+/// hash value for the node.
+class FoldingSetNodeID {
+  /// Bits - Vector of all the data bits that make the node unique.
+  /// Use a SmallVector to avoid a heap allocation in the common case.
+  SmallVector<unsigned, 32> Bits;
+
+public:
+  FoldingSetNodeID() = default;
+
+  FoldingSetNodeID(FoldingSetNodeIDRef Ref)
+    : Bits(Ref.getData(), Ref.getData() + Ref.getSize()) {}
+
+  /// Add* - Add various data types to Bit data.
+  void AddPointer(const void *Ptr);
+  void AddInteger(signed I);
+  void AddInteger(unsigned I);
+  void AddInteger(long I);
+  void AddInteger(unsigned long I);
+  void AddInteger(long long I);
+  void AddInteger(unsigned long long I);
+  void AddBoolean(bool B) { AddInteger(B ? 1U : 0U); }
+  void AddString(StringRef String);
+  void AddNodeID(const FoldingSetNodeID &ID);
+
+  template <typename T>
+  inline void Add(const T &x) { FoldingSetTrait<T>::Profile(x, *this); }
+
+  /// clear - Clear the accumulated profile, allowing this FoldingSetNodeID
+  /// object to be used to compute a new profile.
+  inline void clear() { Bits.clear(); }
+
+  /// ComputeHash - Compute a strong hash value for this FoldingSetNodeID, used
+  /// to lookup the node in the FoldingSetBase.
+  unsigned ComputeHash() const;
+
+  /// operator== - Used to compare two nodes to each other.
+  bool operator==(const FoldingSetNodeID &RHS) const;
+  bool operator==(const FoldingSetNodeIDRef RHS) const;
+
+  bool operator!=(const FoldingSetNodeID &RHS) const { return !(*this == RHS); }
+  bool operator!=(const FoldingSetNodeIDRef RHS) const { return !(*this ==RHS);}
+
+  /// Used to compare the "ordering" of two nodes as defined by the
+  /// profiled bits and their ordering defined by memcmp().
+  bool operator<(const FoldingSetNodeID &RHS) const;
+  bool operator<(const FoldingSetNodeIDRef RHS) const;
+
+  /// Intern - Copy this node's data to a memory region allocated from the
+  /// given allocator and return a FoldingSetNodeIDRef describing the
+  /// interned data.
+  FoldingSetNodeIDRef Intern(BumpPtrAllocator &Allocator) const;
+};
+
+// Convenience type to hide the implementation of the folding set.
+using FoldingSetNode = FoldingSetBase::Node;
+template<class T> class FoldingSetIterator;
+template<class T> class FoldingSetBucketIterator;
+
+// Definitions of FoldingSetTrait and ContextualFoldingSetTrait functions, which
+// require the definition of FoldingSetNodeID.
+template<typename T>
+inline bool
+DefaultFoldingSetTrait<T>::Equals(T &X, const FoldingSetNodeID &ID,
+                                  unsigned /*IDHash*/,
+                                  FoldingSetNodeID &TempID) {
+  FoldingSetTrait<T>::Profile(X, TempID);
+  return TempID == ID;
+}
+template<typename T>
+inline unsigned
+DefaultFoldingSetTrait<T>::ComputeHash(T &X, FoldingSetNodeID &TempID) {
+  FoldingSetTrait<T>::Profile(X, TempID);
+  return TempID.ComputeHash();
+}
+template<typename T, typename Ctx>
+inline bool
+DefaultContextualFoldingSetTrait<T, Ctx>::Equals(T &X,
+                                                 const FoldingSetNodeID &ID,
+                                                 unsigned /*IDHash*/,
+                                                 FoldingSetNodeID &TempID,
+                                                 Ctx Context) {
+  ContextualFoldingSetTrait<T, Ctx>::Profile(X, TempID, Context);
+  return TempID == ID;
+}
+template<typename T, typename Ctx>
+inline unsigned
+DefaultContextualFoldingSetTrait<T, Ctx>::ComputeHash(T &X,
+                                                      FoldingSetNodeID &TempID,
+                                                      Ctx Context) {
+  ContextualFoldingSetTrait<T, Ctx>::Profile(X, TempID, Context);
+  return TempID.ComputeHash();
+}
+
+//===----------------------------------------------------------------------===//
+/// FoldingSetImpl - An implementation detail that lets us share code between
+/// FoldingSet and ContextualFoldingSet.
+template <class T> class FoldingSetImpl : public FoldingSetBase {
+protected:
+  explicit FoldingSetImpl(unsigned Log2InitSize)
+      : FoldingSetBase(Log2InitSize) {}
+
+  FoldingSetImpl(FoldingSetImpl &&Arg) = default;
+  FoldingSetImpl &operator=(FoldingSetImpl &&RHS) = default;
+  ~FoldingSetImpl() = default;
+
+public:
+  using iterator = FoldingSetIterator<T>;
+
+  iterator begin() { return iterator(Buckets); }
+  iterator end() { return iterator(Buckets+NumBuckets); }
+
+  using const_iterator = FoldingSetIterator<const T>;
+
+  const_iterator begin() const { return const_iterator(Buckets); }
+  const_iterator end() const { return const_iterator(Buckets+NumBuckets); }
+
+  using bucket_iterator = FoldingSetBucketIterator<T>;
+
+  bucket_iterator bucket_begin(unsigned hash) {
+    return bucket_iterator(Buckets + (hash & (NumBuckets-1)));
+  }
+
+  bucket_iterator bucket_end(unsigned hash) {
+    return bucket_iterator(Buckets + (hash & (NumBuckets-1)), true);
+  }
+
+  /// RemoveNode - Remove a node from the folding set, returning true if one
+  /// was removed or false if the node was not in the folding set.
+  bool RemoveNode(T *N) { return FoldingSetBase::RemoveNode(N); }
+
+  /// GetOrInsertNode - If there is an existing simple Node exactly
+  /// equal to the specified node, return it.  Otherwise, insert 'N' and
+  /// return it instead.
+  T *GetOrInsertNode(T *N) {
+    return static_cast<T *>(FoldingSetBase::GetOrInsertNode(N));
+  }
+
+  /// FindNodeOrInsertPos - Look up the node specified by ID.  If it exists,
+  /// return it.  If not, return the insertion token that will make insertion
+  /// faster.
+  T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) {
+    return static_cast<T *>(FoldingSetBase::FindNodeOrInsertPos(ID, InsertPos));
+  }
+
+  /// InsertNode - Insert the specified node into the folding set, knowing that
+  /// it is not already in the folding set.  InsertPos must be obtained from
+  /// FindNodeOrInsertPos.
+  void InsertNode(T *N, void *InsertPos) {
+    FoldingSetBase::InsertNode(N, InsertPos);
+  }
+
+  /// InsertNode - Insert the specified node into the folding set, knowing that
+  /// it is not already in the folding set.
+  void InsertNode(T *N) {
+    T *Inserted = GetOrInsertNode(N);
+    (void)Inserted;
+    assert(Inserted == N && "Node already inserted!");
+  }
+};
+
+//===----------------------------------------------------------------------===//
+/// FoldingSet - This template class is used to instantiate a specialized
+/// implementation of the folding set to the node class T.  T must be a
+/// subclass of FoldingSetNode and implement a Profile function.
+///
+/// Note that this set type is movable and move-assignable. However, its
+/// moved-from state is not a valid state for anything other than
+/// move-assigning and destroying. This is primarily to enable movable APIs
+/// that incorporate these objects.
+template <class T> class FoldingSet final : public FoldingSetImpl<T> {
+  using Super = FoldingSetImpl<T>;
+  using Node = typename Super::Node;
+
+  /// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a
+  /// way to convert nodes into a unique specifier.
+  void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const override {
+    T *TN = static_cast<T *>(N);
+    FoldingSetTrait<T>::Profile(*TN, ID);
+  }
+
+  /// NodeEquals - Instantiations may optionally provide a way to compare a
+  /// node with a specified ID.
+  bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash,
+                  FoldingSetNodeID &TempID) const override {
+    T *TN = static_cast<T *>(N);
+    return FoldingSetTrait<T>::Equals(*TN, ID, IDHash, TempID);
+  }
+
+  /// ComputeNodeHash - Instantiations may optionally provide a way to compute a
+  /// hash value directly from a node.
+  unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const override {
+    T *TN = static_cast<T *>(N);
+    return FoldingSetTrait<T>::ComputeHash(*TN, TempID);
+  }
+
+public:
+  explicit FoldingSet(unsigned Log2InitSize = 6) : Super(Log2InitSize) {}
+  FoldingSet(FoldingSet &&Arg) = default;
+  FoldingSet &operator=(FoldingSet &&RHS) = default;
+};
+
+//===----------------------------------------------------------------------===//
+/// ContextualFoldingSet - This template class is a further refinement
+/// of FoldingSet which provides a context argument when calling
+/// Profile on its nodes.  Currently, that argument is fixed at
+/// initialization time.
+///
+/// T must be a subclass of FoldingSetNode and implement a Profile
+/// function with signature
+///   void Profile(FoldingSetNodeID &, Ctx);
+template <class T, class Ctx>
+class ContextualFoldingSet final : public FoldingSetImpl<T> {
+  // Unfortunately, this can't derive from FoldingSet<T> because the
+  // construction of the vtable for FoldingSet<T> requires
+  // FoldingSet<T>::GetNodeProfile to be instantiated, which in turn
+  // requires a single-argument T::Profile().
+
+  using Super = FoldingSetImpl<T>;
+  using Node = typename Super::Node;
+
+  Ctx Context;
+
+  /// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a
+  /// way to convert nodes into a unique specifier.
+  void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const override {
+    T *TN = static_cast<T *>(N);
+    ContextualFoldingSetTrait<T, Ctx>::Profile(*TN, ID, Context);
+  }
+
+  bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash,
+                  FoldingSetNodeID &TempID) const override {
+    T *TN = static_cast<T *>(N);
+    return ContextualFoldingSetTrait<T, Ctx>::Equals(*TN, ID, IDHash, TempID,
+                                                     Context);
+  }
+
+  unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const override {
+    T *TN = static_cast<T *>(N);
+    return ContextualFoldingSetTrait<T, Ctx>::ComputeHash(*TN, TempID, Context);
+  }
+
+public:
+  explicit ContextualFoldingSet(Ctx Context, unsigned Log2InitSize = 6)
+      : Super(Log2InitSize), Context(Context) {}
+
+  Ctx getContext() const { return Context; }
+};
+
+//===----------------------------------------------------------------------===//
+/// FoldingSetVector - This template class combines a FoldingSet and a vector
+/// to provide the interface of FoldingSet but with deterministic iteration
+/// order based on the insertion order. T must be a subclass of FoldingSetNode
+/// and implement a Profile function.
+template <class T, class VectorT = SmallVector<T*, 8>>
+class FoldingSetVector {
+  FoldingSet<T> Set;
+  VectorT Vector;
+
+public:
+  explicit FoldingSetVector(unsigned Log2InitSize = 6) : Set(Log2InitSize) {}
+
+  using iterator = pointee_iterator<typename VectorT::iterator>;
+
+  iterator begin() { return Vector.begin(); }
+  iterator end()   { return Vector.end(); }
+
+  using const_iterator = pointee_iterator<typename VectorT::const_iterator>;
+
+  const_iterator begin() const { return Vector.begin(); }
+  const_iterator end()   const { return Vector.end(); }
+
+  /// clear - Remove all nodes from the folding set.
+  void clear() { Set.clear(); Vector.clear(); }
+
+  /// FindNodeOrInsertPos - Look up the node specified by ID.  If it exists,
+  /// return it.  If not, return the insertion token that will make insertion
+  /// faster.
+  T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) {
+    return Set.FindNodeOrInsertPos(ID, InsertPos);
+  }
+
+  /// GetOrInsertNode - If there is an existing simple Node exactly
+  /// equal to the specified node, return it.  Otherwise, insert 'N' and
+  /// return it instead.
+  T *GetOrInsertNode(T *N) {
+    T *Result = Set.GetOrInsertNode(N);
+    if (Result == N) Vector.push_back(N);
+    return Result;
+  }
+
+  /// InsertNode - Insert the specified node into the folding set, knowing that
+  /// it is not already in the folding set.  InsertPos must be obtained from
+  /// FindNodeOrInsertPos.
+  void InsertNode(T *N, void *InsertPos) {
+    Set.InsertNode(N, InsertPos);
+    Vector.push_back(N);
+  }
+
+  /// InsertNode - Insert the specified node into the folding set, knowing that
+  /// it is not already in the folding set.
+  void InsertNode(T *N) {
+    Set.InsertNode(N);
+    Vector.push_back(N);
+  }
+
+  /// size - Returns the number of nodes in the folding set.
+  unsigned size() const { return Set.size(); }
+
+  /// empty - Returns true if there are no nodes in the folding set.
+  bool empty() const { return Set.empty(); }
+};
+
+//===----------------------------------------------------------------------===//
+/// FoldingSetIteratorImpl - This is the common iterator support shared by all
+/// folding sets, which knows how to walk the folding set hash table.
+class FoldingSetIteratorImpl {
+protected:
+  FoldingSetNode *NodePtr;
+
+  FoldingSetIteratorImpl(void **Bucket);
+
+  void advance();
+
+public:
+  bool operator==(const FoldingSetIteratorImpl &RHS) const {
+    return NodePtr == RHS.NodePtr;
+  }
+  bool operator!=(const FoldingSetIteratorImpl &RHS) const {
+    return NodePtr != RHS.NodePtr;
+  }
+};
+
+template <class T> class FoldingSetIterator : public FoldingSetIteratorImpl {
+public:
+  explicit FoldingSetIterator(void **Bucket) : FoldingSetIteratorImpl(Bucket) {}
+
+  T &operator*() const {
+    return *static_cast<T*>(NodePtr);
+  }
+
+  T *operator->() const {
+    return static_cast<T*>(NodePtr);
+  }
+
+  inline FoldingSetIterator &operator++() {          // Preincrement
+    advance();
+    return *this;
+  }
+  FoldingSetIterator operator++(int) {        // Postincrement
+    FoldingSetIterator tmp = *this; ++*this; return tmp;
+  }
+};
+
+//===----------------------------------------------------------------------===//
+/// FoldingSetBucketIteratorImpl - This is the common bucket iterator support
+/// shared by all folding sets, which knows how to walk a particular bucket
+/// of a folding set hash table.
+class FoldingSetBucketIteratorImpl {
+protected:
+  void *Ptr;
+
+  explicit FoldingSetBucketIteratorImpl(void **Bucket);
+
+  FoldingSetBucketIteratorImpl(void **Bucket, bool) : Ptr(Bucket) {}
+
+  void advance() {
+    void *Probe = static_cast<FoldingSetNode*>(Ptr)->getNextInBucket();
+    uintptr_t x = reinterpret_cast<uintptr_t>(Probe) & ~0x1;
+    Ptr = reinterpret_cast<void*>(x);
+  }
+
+public:
+  bool operator==(const FoldingSetBucketIteratorImpl &RHS) const {
+    return Ptr == RHS.Ptr;
+  }
+  bool operator!=(const FoldingSetBucketIteratorImpl &RHS) const {
+    return Ptr != RHS.Ptr;
+  }
+};
+
+template <class T>
+class FoldingSetBucketIterator : public FoldingSetBucketIteratorImpl {
+public:
+  explicit FoldingSetBucketIterator(void **Bucket) :
+    FoldingSetBucketIteratorImpl(Bucket) {}
+
+  FoldingSetBucketIterator(void **Bucket, bool) :
+    FoldingSetBucketIteratorImpl(Bucket, true) {}
+
+  T &operator*() const { return *static_cast<T*>(Ptr); }
+  T *operator->() const { return static_cast<T*>(Ptr); }
+
+  inline FoldingSetBucketIterator &operator++() { // Preincrement
+    advance();
+    return *this;
+  }
+  FoldingSetBucketIterator operator++(int) {      // Postincrement
+    FoldingSetBucketIterator tmp = *this; ++*this; return tmp;
+  }
+};
+
+//===----------------------------------------------------------------------===//
+/// FoldingSetNodeWrapper - This template class is used to "wrap" arbitrary
+/// types in an enclosing object so that they can be inserted into FoldingSets.
+template <typename T>
+class FoldingSetNodeWrapper : public FoldingSetNode {
+  T data;
+
+public:
+  template <typename... Ts>
+  explicit FoldingSetNodeWrapper(Ts &&... Args)
+      : data(std::forward<Ts>(Args)...) {}
+
+  void Profile(FoldingSetNodeID &ID) { FoldingSetTrait<T>::Profile(data, ID); }
+
+  T &getValue() { return data; }
+  const T &getValue() const { return data; }
+
+  operator T&() { return data; }
+  operator const T&() const { return data; }
+};
+
+//===----------------------------------------------------------------------===//
+/// FastFoldingSetNode - This is a subclass of FoldingSetNode which stores
+/// a FoldingSetNodeID value rather than requiring the node to recompute it
+/// each time it is needed. This trades space for speed (which can be
+/// significant if the ID is long), and it also permits nodes to drop
+/// information that would otherwise only be required for recomputing an ID.
+class FastFoldingSetNode : public FoldingSetNode {
+  FoldingSetNodeID FastID;
+
+protected:
+  explicit FastFoldingSetNode(const FoldingSetNodeID &ID) : FastID(ID) {}
+
+public:
+  void Profile(FoldingSetNodeID &ID) const { ID.AddNodeID(FastID); }
+};
+
+//===----------------------------------------------------------------------===//
+// Partial specializations of FoldingSetTrait.
+
+template<typename T> struct FoldingSetTrait<T*> {
+  static inline void Profile(T *X, FoldingSetNodeID &ID) {
+    ID.AddPointer(X);
+  }
+};
+template <typename T1, typename T2>
+struct FoldingSetTrait<std::pair<T1, T2>> {
+  static inline void Profile(const std::pair<T1, T2> &P,
+                             FoldingSetNodeID &ID) {
+    ID.Add(P.first);
+    ID.Add(P.second);
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_FOLDINGSET_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/FunctionExtras.h b/binaryen/third_party/llvm-project/include/llvm/ADT/FunctionExtras.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/FunctionExtras.h
@@ -0,0 +1,292 @@
+//===- FunctionExtras.h - Function type erasure utilities -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file provides a collection of function (or more generally, callable)
+/// type erasure utilities supplementing those provided by the standard library
+/// in `<function>`.
+///
+/// It provides `unique_function`, which works like `std::function` but supports
+/// move-only callable objects.
+///
+/// Future plans:
+/// - Add a `function` that provides const, volatile, and ref-qualified support,
+///   which doesn't work with `std::function`.
+/// - Provide support for specifying multiple signatures to type erase callable
+///   objects with an overload set, such as those produced by generic lambdas.
+/// - Expand to include a copyable utility that directly replaces std::function
+///   but brings the above improvements.
+///
+/// Note that LLVM's utilities are greatly simplified by not supporting
+/// allocators.
+///
+/// If the standard library ever begins to provide comparable facilities we can
+/// consider switching to those.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_FUNCTION_EXTRAS_H
+#define LLVM_ADT_FUNCTION_EXTRAS_H
+
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/Support/type_traits.h"
+#include <memory>
+
+namespace llvm {
+
+template <typename FunctionT> class unique_function;
+
+template <typename ReturnT, typename... ParamTs>
+class unique_function<ReturnT(ParamTs...)> {
+  static constexpr size_t InlineStorageSize = sizeof(void *) * 3;
+
+  // MSVC has a bug and ICEs if we give it a particular dependent value
+  // expression as part of the `std::conditional` below. To work around this,
+  // we build that into a template struct's constexpr bool.
+  template <typename T> struct IsSizeLessThanThresholdT {
+    static constexpr bool value = sizeof(T) <= (2 * sizeof(void *));
+  };
+
+  // Provide a type function to map parameters that won't observe extra copies
+  // or moves and which are small enough to likely pass in register to values
+  // and all other types to l-value reference types. We use this to compute the
+  // types used in our erased call utility to minimize copies and moves unless
+  // doing so would force things unnecessarily into memory.
+  //
+  // The heuristic used is related to common ABI register passing conventions.
+  // It doesn't have to be exact though, and in one way it is more strict
+  // because we want to still be able to observe either moves *or* copies.
+  template <typename T>
+  using AdjustedParamT = typename std::conditional<
+      !std::is_reference<T>::value &&
+          llvm::is_trivially_copy_constructible<T>::value &&
+          llvm::is_trivially_move_constructible<T>::value &&
+          IsSizeLessThanThresholdT<T>::value,
+      T, T &>::type;
+
+  // The type of the erased function pointer we use as a callback to dispatch to
+  // the stored callable when it is trivial to move and destroy.
+  using CallPtrT = ReturnT (*)(void *CallableAddr,
+                               AdjustedParamT<ParamTs>... Params);
+  using MovePtrT = void (*)(void *LHSCallableAddr, void *RHSCallableAddr);
+  using DestroyPtrT = void (*)(void *CallableAddr);
+
+  /// A struct to hold a single trivial callback with sufficient alignment for
+  /// our bitpacking.
+  struct alignas(8) TrivialCallback {
+    CallPtrT CallPtr;
+  };
+
+  /// A struct we use to aggregate three callbacks when we need full set of
+  /// operations.
+  struct alignas(8) NonTrivialCallbacks {
+    CallPtrT CallPtr;
+    MovePtrT MovePtr;
+    DestroyPtrT DestroyPtr;
+  };
+
+  // Create a pointer union between either a pointer to a static trivial call
+  // pointer in a struct or a pointer to a static struct of the call, move, and
+  // destroy pointers.
+  using CallbackPointerUnionT =
+      PointerUnion<TrivialCallback *, NonTrivialCallbacks *>;
+
+  // The main storage buffer. This will either have a pointer to out-of-line
+  // storage or an inline buffer storing the callable.
+  union StorageUnionT {
+    // For out-of-line storage we keep a pointer to the underlying storage and
+    // the size. This is enough to deallocate the memory.
+    struct OutOfLineStorageT {
+      void *StoragePtr;
+      size_t Size;
+      size_t Alignment;
+    } OutOfLineStorage;
+    static_assert(
+        sizeof(OutOfLineStorageT) <= InlineStorageSize,
+        "Should always use all of the out-of-line storage for inline storage!");
+
+    // For in-line storage, we just provide an aligned character buffer. We
+    // provide three pointers worth of storage here.
+    typename std::aligned_storage<InlineStorageSize, alignof(void *)>::type
+        InlineStorage;
+  } StorageUnion;
+
+  // A compressed pointer to either our dispatching callback or our table of
+  // dispatching callbacks and the flag for whether the callable itself is
+  // stored inline or not.
+  PointerIntPair<CallbackPointerUnionT, 1, bool> CallbackAndInlineFlag;
+
+  bool isInlineStorage() const { return CallbackAndInlineFlag.getInt(); }
+
+  bool isTrivialCallback() const {
+    return CallbackAndInlineFlag.getPointer().template is<TrivialCallback *>();
+  }
+
+  CallPtrT getTrivialCallback() const {
+    return CallbackAndInlineFlag.getPointer().template get<TrivialCallback *>()->CallPtr;
+  }
+
+  NonTrivialCallbacks *getNonTrivialCallbacks() const {
+    return CallbackAndInlineFlag.getPointer()
+        .template get<NonTrivialCallbacks *>();
+  }
+
+  void *getInlineStorage() { return &StorageUnion.InlineStorage; }
+
+  void *getOutOfLineStorage() {
+    return StorageUnion.OutOfLineStorage.StoragePtr;
+  }
+  size_t getOutOfLineStorageSize() const {
+    return StorageUnion.OutOfLineStorage.Size;
+  }
+  size_t getOutOfLineStorageAlignment() const {
+    return StorageUnion.OutOfLineStorage.Alignment;
+  }
+
+  void setOutOfLineStorage(void *Ptr, size_t Size, size_t Alignment) {
+    StorageUnion.OutOfLineStorage = {Ptr, Size, Alignment};
+  }
+
+  template <typename CallableT>
+  static ReturnT CallImpl(void *CallableAddr, AdjustedParamT<ParamTs>... Params) {
+    return (*reinterpret_cast<CallableT *>(CallableAddr))(
+        std::forward<ParamTs>(Params)...);
+  }
+
+  template <typename CallableT>
+  static void MoveImpl(void *LHSCallableAddr, void *RHSCallableAddr) noexcept {
+    new (LHSCallableAddr)
+        CallableT(std::move(*reinterpret_cast<CallableT *>(RHSCallableAddr)));
+  }
+
+  template <typename CallableT>
+  static void DestroyImpl(void *CallableAddr) noexcept {
+    reinterpret_cast<CallableT *>(CallableAddr)->~CallableT();
+  }
+
+public:
+  unique_function() = default;
+  unique_function(std::nullptr_t /*null_callable*/) {}
+
+  ~unique_function() {
+    if (!CallbackAndInlineFlag.getPointer())
+      return;
+
+    // Cache this value so we don't re-check it after type-erased operations.
+    bool IsInlineStorage = isInlineStorage();
+
+    if (!isTrivialCallback())
+      getNonTrivialCallbacks()->DestroyPtr(
+          IsInlineStorage ? getInlineStorage() : getOutOfLineStorage());
+
+    if (!IsInlineStorage)
+      deallocate_buffer(getOutOfLineStorage(), getOutOfLineStorageSize(),
+                        getOutOfLineStorageAlignment());
+  }
+
+  unique_function(unique_function &&RHS) noexcept {
+    // Copy the callback and inline flag.
+    CallbackAndInlineFlag = RHS.CallbackAndInlineFlag;
+
+    // If the RHS is empty, just copying the above is sufficient.
+    if (!RHS)
+      return;
+
+    if (!isInlineStorage()) {
+      // The out-of-line case is easiest to move.
+      StorageUnion.OutOfLineStorage = RHS.StorageUnion.OutOfLineStorage;
+    } else if (isTrivialCallback()) {
+      // Move is trivial, just memcpy the bytes across.
+      memcpy(getInlineStorage(), RHS.getInlineStorage(), InlineStorageSize);
+    } else {
+      // Non-trivial move, so dispatch to a type-erased implementation.
+      getNonTrivialCallbacks()->MovePtr(getInlineStorage(),
+                                        RHS.getInlineStorage());
+    }
+
+    // Clear the old callback and inline flag to get back to as-if-null.
+    RHS.CallbackAndInlineFlag = {};
+
+#ifndef NDEBUG
+    // In debug builds, we also scribble across the rest of the storage.
+    memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize);
+#endif
+  }
+
+  unique_function &operator=(unique_function &&RHS) noexcept {
+    if (this == &RHS)
+      return *this;
+
+    // Because we don't try to provide any exception safety guarantees we can
+    // implement move assignment very simply by first destroying the current
+    // object and then move-constructing over top of it.
+    this->~unique_function();
+    new (this) unique_function(std::move(RHS));
+    return *this;
+  }
+
+  template <typename CallableT> unique_function(CallableT Callable) {
+    bool IsInlineStorage = true;
+    void *CallableAddr = getInlineStorage();
+    if (sizeof(CallableT) > InlineStorageSize ||
+        alignof(CallableT) > alignof(decltype(StorageUnion.InlineStorage))) {
+      IsInlineStorage = false;
+      // Allocate out-of-line storage. FIXME: Use an explicit alignment
+      // parameter in C++17 mode.
+      auto Size = sizeof(CallableT);
+      auto Alignment = alignof(CallableT);
+      CallableAddr = allocate_buffer(Size, Alignment);
+      setOutOfLineStorage(CallableAddr, Size, Alignment);
+    }
+
+    // Now move into the storage.
+    new (CallableAddr) CallableT(std::move(Callable));
+
+    // See if we can create a trivial callback. We need the callable to be
+    // trivially moved and trivially destroyed so that we don't have to store
+    // type erased callbacks for those operations.
+    //
+    // FIXME: We should use constexpr if here and below to avoid instantiating
+    // the non-trivial static objects when unnecessary. While the linker should
+    // remove them, it is still wasteful.
+    if (llvm::is_trivially_move_constructible<CallableT>::value &&
+        std::is_trivially_destructible<CallableT>::value) {
+      // We need to create a nicely aligned object. We use a static variable
+      // for this because it is a trivial struct.
+      static TrivialCallback Callback = { &CallImpl<CallableT> };
+
+      CallbackAndInlineFlag = {&Callback, IsInlineStorage};
+      return;
+    }
+
+    // Otherwise, we need to point at an object that contains all the different
+    // type erased behaviors needed. Create a static instance of the struct type
+    // here and then use a pointer to that.
+    static NonTrivialCallbacks Callbacks = {
+        &CallImpl<CallableT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>};
+
+    CallbackAndInlineFlag = {&Callbacks, IsInlineStorage};
+  }
+
+  ReturnT operator()(ParamTs... Params) {
+    void *CallableAddr =
+        isInlineStorage() ? getInlineStorage() : getOutOfLineStorage();
+
+    return (isTrivialCallback()
+                ? getTrivialCallback()
+                : getNonTrivialCallbacks()->CallPtr)(CallableAddr, Params...);
+  }
+
+  explicit operator bool() const {
+    return (bool)CallbackAndInlineFlag.getPointer();
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_FUNCTION_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/Hashing.h b/binaryen/third_party/llvm-project/include/llvm/ADT/Hashing.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/Hashing.h
@@ -0,0 +1,659 @@
+//===-- llvm/ADT/Hashing.h - Utilities for hashing --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the newly proposed standard C++ interfaces for hashing
+// arbitrary data and building hash functions for user-defined types. This
+// interface was originally proposed in N3333[1] and is currently under review
+// for inclusion in a future TR and/or standard.
+//
+// The primary interfaces provide are comprised of one type and three functions:
+//
+//  -- 'hash_code' class is an opaque type representing the hash code for some
+//     data. It is the intended product of hashing, and can be used to implement
+//     hash tables, checksumming, and other common uses of hashes. It is not an
+//     integer type (although it can be converted to one) because it is risky
+//     to assume much about the internals of a hash_code. In particular, each
+//     execution of the program has a high probability of producing a different
+//     hash_code for a given input. Thus their values are not stable to save or
+//     persist, and should only be used during the execution for the
+//     construction of hashing datastructures.
+//
+//  -- 'hash_value' is a function designed to be overloaded for each
+//     user-defined type which wishes to be used within a hashing context. It
+//     should be overloaded within the user-defined type's namespace and found
+//     via ADL. Overloads for primitive types are provided by this library.
+//
+//  -- 'hash_combine' and 'hash_combine_range' are functions designed to aid
+//      programmers in easily and intuitively combining a set of data into
+//      a single hash_code for their object. They should only logically be used
+//      within the implementation of a 'hash_value' routine or similar context.
+//
+// Note that 'hash_combine_range' contains very special logic for hashing
+// a contiguous array of integers or pointers. This logic is *extremely* fast,
+// on a modern Intel "Gainestown" Xeon (Nehalem uarch) @2.2 GHz, these were
+// benchmarked at over 6.5 GiB/s for large keys, and <20 cycles/hash for keys
+// under 32-bytes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_HASHING_H
+#define LLVM_ADT_HASHING_H
+
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/SwapByteOrder.h"
+#include "llvm/Support/type_traits.h"
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+#include <string>
+#include <utility>
+
+namespace llvm {
+
+/// An opaque object representing a hash code.
+///
+/// This object represents the result of hashing some entity. It is intended to
+/// be used to implement hashtables or other hashing-based data structures.
+/// While it wraps and exposes a numeric value, this value should not be
+/// trusted to be stable or predictable across processes or executions.
+///
+/// In order to obtain the hash_code for an object 'x':
+/// \code
+///   using llvm::hash_value;
+///   llvm::hash_code code = hash_value(x);
+/// \endcode
+class hash_code {
+  size_t value;
+
+public:
+  /// Default construct a hash_code.
+  /// Note that this leaves the value uninitialized.
+  hash_code() = default;
+
+  /// Form a hash code directly from a numerical value.
+  hash_code(size_t value) : value(value) {}
+
+  /// Convert the hash code to its numerical value for use.
+  /*explicit*/ operator size_t() const { return value; }
+
+  friend bool operator==(const hash_code &lhs, const hash_code &rhs) {
+    return lhs.value == rhs.value;
+  }
+  friend bool operator!=(const hash_code &lhs, const hash_code &rhs) {
+    return lhs.value != rhs.value;
+  }
+
+  /// Allow a hash_code to be directly run through hash_value.
+  friend size_t hash_value(const hash_code &code) { return code.value; }
+};
+
+/// Compute a hash_code for any integer value.
+///
+/// Note that this function is intended to compute the same hash_code for
+/// a particular value without regard to the pre-promotion type. This is in
+/// contrast to hash_combine which may produce different hash_codes for
+/// differing argument types even if they would implicit promote to a common
+/// type without changing the value.
+template <typename T>
+typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type
+hash_value(T value);
+
+/// Compute a hash_code for a pointer's address.
+///
+/// N.B.: This hashes the *address*. Not the value and not the type.
+template <typename T> hash_code hash_value(const T *ptr);
+
+/// Compute a hash_code for a pair of objects.
+template <typename T, typename U>
+hash_code hash_value(const std::pair<T, U> &arg);
+
+/// Compute a hash_code for a standard string.
+template <typename T>
+hash_code hash_value(const std::basic_string<T> &arg);
+
+
+/// Override the execution seed with a fixed value.
+///
+/// This hashing library uses a per-execution seed designed to change on each
+/// run with high probability in order to ensure that the hash codes are not
+/// attackable and to ensure that output which is intended to be stable does
+/// not rely on the particulars of the hash codes produced.
+///
+/// That said, there are use cases where it is important to be able to
+/// reproduce *exactly* a specific behavior. To that end, we provide a function
+/// which will forcibly set the seed to a fixed value. This must be done at the
+/// start of the program, before any hashes are computed. Also, it cannot be
+/// undone. This makes it thread-hostile and very hard to use outside of
+/// immediately on start of a simple program designed for reproducible
+/// behavior.
+void set_fixed_execution_hash_seed(uint64_t fixed_value);
+
+
+// All of the implementation details of actually computing the various hash
+// code values are held within this namespace. These routines are included in
+// the header file mainly to allow inlining and constant propagation.
+namespace hashing {
+namespace detail {
+
+inline uint64_t fetch64(const char *p) {
+  uint64_t result;
+  memcpy(&result, p, sizeof(result));
+  if (sys::IsBigEndianHost)
+    sys::swapByteOrder(result);
+  return result;
+}
+
+inline uint32_t fetch32(const char *p) {
+  uint32_t result;
+  memcpy(&result, p, sizeof(result));
+  if (sys::IsBigEndianHost)
+    sys::swapByteOrder(result);
+  return result;
+}
+
+/// Some primes between 2^63 and 2^64 for various uses.
+static const uint64_t k0 = 0xc3a5c85c97cb3127ULL;
+static const uint64_t k1 = 0xb492b66fbe98f273ULL;
+static const uint64_t k2 = 0x9ae16a3b2f90404fULL;
+static const uint64_t k3 = 0xc949d7c7509e6557ULL;
+
+/// Bitwise right rotate.
+/// Normally this will compile to a single instruction, especially if the
+/// shift is a manifest constant.
+inline uint64_t rotate(uint64_t val, size_t shift) {
+  // Avoid shifting by 64: doing so yields an undefined result.
+  return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
+}
+
+inline uint64_t shift_mix(uint64_t val) {
+  return val ^ (val >> 47);
+}
+
+inline uint64_t hash_16_bytes(uint64_t low, uint64_t high) {
+  // Murmur-inspired hashing.
+  const uint64_t kMul = 0x9ddfea08eb382d69ULL;
+  uint64_t a = (low ^ high) * kMul;
+  a ^= (a >> 47);
+  uint64_t b = (high ^ a) * kMul;
+  b ^= (b >> 47);
+  b *= kMul;
+  return b;
+}
+
+inline uint64_t hash_1to3_bytes(const char *s, size_t len, uint64_t seed) {
+  uint8_t a = s[0];
+  uint8_t b = s[len >> 1];
+  uint8_t c = s[len - 1];
+  uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8);
+  uint32_t z = static_cast<uint32_t>(len) + (static_cast<uint32_t>(c) << 2);
+  return shift_mix(y * k2 ^ z * k3 ^ seed) * k2;
+}
+
+inline uint64_t hash_4to8_bytes(const char *s, size_t len, uint64_t seed) {
+  uint64_t a = fetch32(s);
+  return hash_16_bytes(len + (a << 3), seed ^ fetch32(s + len - 4));
+}
+
+inline uint64_t hash_9to16_bytes(const char *s, size_t len, uint64_t seed) {
+  uint64_t a = fetch64(s);
+  uint64_t b = fetch64(s + len - 8);
+  return hash_16_bytes(seed ^ a, rotate(b + len, len)) ^ b;
+}
+
+inline uint64_t hash_17to32_bytes(const char *s, size_t len, uint64_t seed) {
+  uint64_t a = fetch64(s) * k1;
+  uint64_t b = fetch64(s + 8);
+  uint64_t c = fetch64(s + len - 8) * k2;
+  uint64_t d = fetch64(s + len - 16) * k0;
+  return hash_16_bytes(rotate(a - b, 43) + rotate(c ^ seed, 30) + d,
+                       a + rotate(b ^ k3, 20) - c + len + seed);
+}
+
+inline uint64_t hash_33to64_bytes(const char *s, size_t len, uint64_t seed) {
+  uint64_t z = fetch64(s + 24);
+  uint64_t a = fetch64(s) + (len + fetch64(s + len - 16)) * k0;
+  uint64_t b = rotate(a + z, 52);
+  uint64_t c = rotate(a, 37);
+  a += fetch64(s + 8);
+  c += rotate(a, 7);
+  a += fetch64(s + 16);
+  uint64_t vf = a + z;
+  uint64_t vs = b + rotate(a, 31) + c;
+  a = fetch64(s + 16) + fetch64(s + len - 32);
+  z = fetch64(s + len - 8);
+  b = rotate(a + z, 52);
+  c = rotate(a, 37);
+  a += fetch64(s + len - 24);
+  c += rotate(a, 7);
+  a += fetch64(s + len - 16);
+  uint64_t wf = a + z;
+  uint64_t ws = b + rotate(a, 31) + c;
+  uint64_t r = shift_mix((vf + ws) * k2 + (wf + vs) * k0);
+  return shift_mix((seed ^ (r * k0)) + vs) * k2;
+}
+
+inline uint64_t hash_short(const char *s, size_t length, uint64_t seed) {
+  if (length >= 4 && length <= 8)
+    return hash_4to8_bytes(s, length, seed);
+  if (length > 8 && length <= 16)
+    return hash_9to16_bytes(s, length, seed);
+  if (length > 16 && length <= 32)
+    return hash_17to32_bytes(s, length, seed);
+  if (length > 32)
+    return hash_33to64_bytes(s, length, seed);
+  if (length != 0)
+    return hash_1to3_bytes(s, length, seed);
+
+  return k2 ^ seed;
+}
+
+/// The intermediate state used during hashing.
+/// Currently, the algorithm for computing hash codes is based on CityHash and
+/// keeps 56 bytes of arbitrary state.
+struct hash_state {
+  uint64_t h0 = 0, h1 = 0, h2 = 0, h3 = 0, h4 = 0, h5 = 0, h6 = 0;
+
+  /// Create a new hash_state structure and initialize it based on the
+  /// seed and the first 64-byte chunk.
+  /// This effectively performs the initial mix.
+  static hash_state create(const char *s, uint64_t seed) {
+    hash_state state = {
+      0, seed, hash_16_bytes(seed, k1), rotate(seed ^ k1, 49),
+      seed * k1, shift_mix(seed), 0 };
+    state.h6 = hash_16_bytes(state.h4, state.h5);
+    state.mix(s);
+    return state;
+  }
+
+  /// Mix 32-bytes from the input sequence into the 16-bytes of 'a'
+  /// and 'b', including whatever is already in 'a' and 'b'.
+  static void mix_32_bytes(const char *s, uint64_t &a, uint64_t &b) {
+    a += fetch64(s);
+    uint64_t c = fetch64(s + 24);
+    b = rotate(b + a + c, 21);
+    uint64_t d = a;
+    a += fetch64(s + 8) + fetch64(s + 16);
+    b += rotate(a, 44) + d;
+    a += c;
+  }
+
+  /// Mix in a 64-byte buffer of data.
+  /// We mix all 64 bytes even when the chunk length is smaller, but we
+  /// record the actual length.
+  void mix(const char *s) {
+    h0 = rotate(h0 + h1 + h3 + fetch64(s + 8), 37) * k1;
+    h1 = rotate(h1 + h4 + fetch64(s + 48), 42) * k1;
+    h0 ^= h6;
+    h1 += h3 + fetch64(s + 40);
+    h2 = rotate(h2 + h5, 33) * k1;
+    h3 = h4 * k1;
+    h4 = h0 + h5;
+    mix_32_bytes(s, h3, h4);
+    h5 = h2 + h6;
+    h6 = h1 + fetch64(s + 16);
+    mix_32_bytes(s + 32, h5, h6);
+    std::swap(h2, h0);
+  }
+
+  /// Compute the final 64-bit hash code value based on the current
+  /// state and the length of bytes hashed.
+  uint64_t finalize(size_t length) {
+    return hash_16_bytes(hash_16_bytes(h3, h5) + shift_mix(h1) * k1 + h2,
+                         hash_16_bytes(h4, h6) + shift_mix(length) * k1 + h0);
+  }
+};
+
+
+/// A global, fixed seed-override variable.
+///
+/// This variable can be set using the \see llvm::set_fixed_execution_seed
+/// function. See that function for details. Do not, under any circumstances,
+/// set or read this variable.
+extern uint64_t fixed_seed_override;
+
+inline uint64_t get_execution_seed() {
+  // FIXME: This needs to be a per-execution seed. This is just a placeholder
+  // implementation. Switching to a per-execution seed is likely to flush out
+  // instability bugs and so will happen as its own commit.
+  //
+  // However, if there is a fixed seed override set the first time this is
+  // called, return that instead of the per-execution seed.
+  const uint64_t seed_prime = 0xff51afd7ed558ccdULL;
+  static uint64_t seed = fixed_seed_override ? fixed_seed_override : seed_prime;
+  return seed;
+}
+
+
+/// Trait to indicate whether a type's bits can be hashed directly.
+///
+/// A type trait which is true if we want to combine values for hashing by
+/// reading the underlying data. It is false if values of this type must
+/// first be passed to hash_value, and the resulting hash_codes combined.
+//
+// FIXME: We want to replace is_integral_or_enum and is_pointer here with
+// a predicate which asserts that comparing the underlying storage of two
+// values of the type for equality is equivalent to comparing the two values
+// for equality. For all the platforms we care about, this holds for integers
+// and pointers, but there are platforms where it doesn't and we would like to
+// support user-defined types which happen to satisfy this property.
+template <typename T> struct is_hashable_data
+  : std::integral_constant<bool, ((is_integral_or_enum<T>::value ||
+                                   std::is_pointer<T>::value) &&
+                                  64 % sizeof(T) == 0)> {};
+
+// Special case std::pair to detect when both types are viable and when there
+// is no alignment-derived padding in the pair. This is a bit of a lie because
+// std::pair isn't truly POD, but it's close enough in all reasonable
+// implementations for our use case of hashing the underlying data.
+template <typename T, typename U> struct is_hashable_data<std::pair<T, U> >
+  : std::integral_constant<bool, (is_hashable_data<T>::value &&
+                                  is_hashable_data<U>::value &&
+                                  (sizeof(T) + sizeof(U)) ==
+                                   sizeof(std::pair<T, U>))> {};
+
+/// Helper to get the hashable data representation for a type.
+/// This variant is enabled when the type itself can be used.
+template <typename T>
+typename std::enable_if<is_hashable_data<T>::value, T>::type
+get_hashable_data(const T &value) {
+  return value;
+}
+/// Helper to get the hashable data representation for a type.
+/// This variant is enabled when we must first call hash_value and use the
+/// result as our data.
+template <typename T>
+typename std::enable_if<!is_hashable_data<T>::value, size_t>::type
+get_hashable_data(const T &value) {
+  using ::llvm::hash_value;
+  return hash_value(value);
+}
+
+/// Helper to store data from a value into a buffer and advance the
+/// pointer into that buffer.
+///
+/// This routine first checks whether there is enough space in the provided
+/// buffer, and if not immediately returns false. If there is space, it
+/// copies the underlying bytes of value into the buffer, advances the
+/// buffer_ptr past the copied bytes, and returns true.
+template <typename T>
+bool store_and_advance(char *&buffer_ptr, char *buffer_end, const T& value,
+                       size_t offset = 0) {
+  size_t store_size = sizeof(value) - offset;
+  if (buffer_ptr + store_size > buffer_end)
+    return false;
+  const char *value_data = reinterpret_cast<const char *>(&value);
+  memcpy(buffer_ptr, value_data + offset, store_size);
+  buffer_ptr += store_size;
+  return true;
+}
+
+/// Implement the combining of integral values into a hash_code.
+///
+/// This overload is selected when the value type of the iterator is
+/// integral. Rather than computing a hash_code for each object and then
+/// combining them, this (as an optimization) directly combines the integers.
+template <typename InputIteratorT>
+hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) {
+  const uint64_t seed = get_execution_seed();
+  char buffer[64], *buffer_ptr = buffer;
+  char *const buffer_end = std::end(buffer);
+  while (first != last && store_and_advance(buffer_ptr, buffer_end,
+                                            get_hashable_data(*first)))
+    ++first;
+  if (first == last)
+    return hash_short(buffer, buffer_ptr - buffer, seed);
+  assert(buffer_ptr == buffer_end);
+
+  hash_state state = state.create(buffer, seed);
+  size_t length = 64;
+  while (first != last) {
+    // Fill up the buffer. We don't clear it, which re-mixes the last round
+    // when only a partial 64-byte chunk is left.
+    buffer_ptr = buffer;
+    while (first != last && store_and_advance(buffer_ptr, buffer_end,
+                                              get_hashable_data(*first)))
+      ++first;
+
+    // Rotate the buffer if we did a partial fill in order to simulate doing
+    // a mix of the last 64-bytes. That is how the algorithm works when we
+    // have a contiguous byte sequence, and we want to emulate that here.
+    std::rotate(buffer, buffer_ptr, buffer_end);
+
+    // Mix this chunk into the current state.
+    state.mix(buffer);
+    length += buffer_ptr - buffer;
+  };
+
+  return state.finalize(length);
+}
+
+/// Implement the combining of integral values into a hash_code.
+///
+/// This overload is selected when the value type of the iterator is integral
+/// and when the input iterator is actually a pointer. Rather than computing
+/// a hash_code for each object and then combining them, this (as an
+/// optimization) directly combines the integers. Also, because the integers
+/// are stored in contiguous memory, this routine avoids copying each value
+/// and directly reads from the underlying memory.
+template <typename ValueT>
+typename std::enable_if<is_hashable_data<ValueT>::value, hash_code>::type
+hash_combine_range_impl(ValueT *first, ValueT *last) {
+  const uint64_t seed = get_execution_seed();
+  const char *s_begin = reinterpret_cast<const char *>(first);
+  const char *s_end = reinterpret_cast<const char *>(last);
+  const size_t length = std::distance(s_begin, s_end);
+  if (length <= 64)
+    return hash_short(s_begin, length, seed);
+
+  const char *s_aligned_end = s_begin + (length & ~63);
+  hash_state state = state.create(s_begin, seed);
+  s_begin += 64;
+  while (s_begin != s_aligned_end) {
+    state.mix(s_begin);
+    s_begin += 64;
+  }
+  if (length & 63)
+    state.mix(s_end - 64);
+
+  return state.finalize(length);
+}
+
+} // namespace detail
+} // namespace hashing
+
+
+/// Compute a hash_code for a sequence of values.
+///
+/// This hashes a sequence of values. It produces the same hash_code as
+/// 'hash_combine(a, b, c, ...)', but can run over arbitrary sized sequences
+/// and is significantly faster given pointers and types which can be hashed as
+/// a sequence of bytes.
+template <typename InputIteratorT>
+hash_code hash_combine_range(InputIteratorT first, InputIteratorT last) {
+  return ::llvm::hashing::detail::hash_combine_range_impl(first, last);
+}
+
+
+// Implementation details for hash_combine.
+namespace hashing {
+namespace detail {
+
+/// Helper class to manage the recursive combining of hash_combine
+/// arguments.
+///
+/// This class exists to manage the state and various calls involved in the
+/// recursive combining of arguments used in hash_combine. It is particularly
+/// useful at minimizing the code in the recursive calls to ease the pain
+/// caused by a lack of variadic functions.
+struct hash_combine_recursive_helper {
+  char buffer[64] = {};
+  hash_state state;
+  const uint64_t seed;
+
+public:
+  /// Construct a recursive hash combining helper.
+  ///
+  /// This sets up the state for a recursive hash combine, including getting
+  /// the seed and buffer setup.
+  hash_combine_recursive_helper()
+    : seed(get_execution_seed()) {}
+
+  /// Combine one chunk of data into the current in-flight hash.
+  ///
+  /// This merges one chunk of data into the hash. First it tries to buffer
+  /// the data. If the buffer is full, it hashes the buffer into its
+  /// hash_state, empties it, and then merges the new chunk in. This also
+  /// handles cases where the data straddles the end of the buffer.
+  template <typename T>
+  char *combine_data(size_t &length, char *buffer_ptr, char *buffer_end, T data) {
+    if (!store_and_advance(buffer_ptr, buffer_end, data)) {
+      // Check for skew which prevents the buffer from being packed, and do
+      // a partial store into the buffer to fill it. This is only a concern
+      // with the variadic combine because that formation can have varying
+      // argument types.
+      size_t partial_store_size = buffer_end - buffer_ptr;
+      memcpy(buffer_ptr, &data, partial_store_size);
+
+      // If the store fails, our buffer is full and ready to hash. We have to
+      // either initialize the hash state (on the first full buffer) or mix
+      // this buffer into the existing hash state. Length tracks the *hashed*
+      // length, not the buffered length.
+      if (length == 0) {
+        state = state.create(buffer, seed);
+        length = 64;
+      } else {
+        // Mix this chunk into the current state and bump length up by 64.
+        state.mix(buffer);
+        length += 64;
+      }
+      // Reset the buffer_ptr to the head of the buffer for the next chunk of
+      // data.
+      buffer_ptr = buffer;
+
+      // Try again to store into the buffer -- this cannot fail as we only
+      // store types smaller than the buffer.
+      if (!store_and_advance(buffer_ptr, buffer_end, data,
+                             partial_store_size))
+        llvm_unreachable("buffer smaller than stored type");
+    }
+    return buffer_ptr;
+  }
+
+  /// Recursive, variadic combining method.
+  ///
+  /// This function recurses through each argument, combining that argument
+  /// into a single hash.
+  template <typename T, typename ...Ts>
+  hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
+                    const T &arg, const Ts &...args) {
+    buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg));
+
+    // Recurse to the next argument.
+    return combine(length, buffer_ptr, buffer_end, args...);
+  }
+
+  /// Base case for recursive, variadic combining.
+  ///
+  /// The base case when combining arguments recursively is reached when all
+  /// arguments have been handled. It flushes the remaining buffer and
+  /// constructs a hash_code.
+  hash_code combine(size_t length, char *buffer_ptr, char *buffer_end) {
+    // Check whether the entire set of values fit in the buffer. If so, we'll
+    // use the optimized short hashing routine and skip state entirely.
+    if (length == 0)
+      return hash_short(buffer, buffer_ptr - buffer, seed);
+
+    // Mix the final buffer, rotating it if we did a partial fill in order to
+    // simulate doing a mix of the last 64-bytes. That is how the algorithm
+    // works when we have a contiguous byte sequence, and we want to emulate
+    // that here.
+    std::rotate(buffer, buffer_ptr, buffer_end);
+
+    // Mix this chunk into the current state.
+    state.mix(buffer);
+    length += buffer_ptr - buffer;
+
+    return state.finalize(length);
+  }
+};
+
+} // namespace detail
+} // namespace hashing
+
+/// Combine values into a single hash_code.
+///
+/// This routine accepts a varying number of arguments of any type. It will
+/// attempt to combine them into a single hash_code. For user-defined types it
+/// attempts to call a \see hash_value overload (via ADL) for the type. For
+/// integer and pointer types it directly combines their data into the
+/// resulting hash_code.
+///
+/// The result is suitable for returning from a user's hash_value
+/// *implementation* for their user-defined type. Consumers of a type should
+/// *not* call this routine, they should instead call 'hash_value'.
+template <typename ...Ts> hash_code hash_combine(const Ts &...args) {
+  // Recursively hash each argument using a helper class.
+  ::llvm::hashing::detail::hash_combine_recursive_helper helper;
+  return helper.combine(0, helper.buffer, helper.buffer + 64, args...);
+}
+
+// Implementation details for implementations of hash_value overloads provided
+// here.
+namespace hashing {
+namespace detail {
+
+/// Helper to hash the value of a single integer.
+///
+/// Overloads for smaller integer types are not provided to ensure consistent
+/// behavior in the presence of integral promotions. Essentially,
+/// "hash_value('4')" and "hash_value('0' + 4)" should be the same.
+inline hash_code hash_integer_value(uint64_t value) {
+  // Similar to hash_4to8_bytes but using a seed instead of length.
+  const uint64_t seed = get_execution_seed();
+  const char *s = reinterpret_cast<const char *>(&value);
+  const uint64_t a = fetch32(s);
+  return hash_16_bytes(seed + (a << 3), fetch32(s + 4));
+}
+
+} // namespace detail
+} // namespace hashing
+
+// Declared and documented above, but defined here so that any of the hashing
+// infrastructure is available.
+template <typename T>
+typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type
+hash_value(T value) {
+  return ::llvm::hashing::detail::hash_integer_value(
+      static_cast<uint64_t>(value));
+}
+
+// Declared and documented above, but defined here so that any of the hashing
+// infrastructure is available.
+template <typename T> hash_code hash_value(const T *ptr) {
+  return ::llvm::hashing::detail::hash_integer_value(
+    reinterpret_cast<uintptr_t>(ptr));
+}
+
+// Declared and documented above, but defined here so that any of the hashing
+// infrastructure is available.
+template <typename T, typename U>
+hash_code hash_value(const std::pair<T, U> &arg) {
+  return hash_combine(arg.first, arg.second);
+}
+
+// Declared and documented above, but defined here so that any of the hashing
+// infrastructure is available.
+template <typename T>
+hash_code hash_value(const std::basic_string<T> &arg) {
+  return hash_combine_range(arg.begin(), arg.end());
+}
+
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/MapVector.h b/binaryen/third_party/llvm-project/include/llvm/ADT/MapVector.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/MapVector.h
@@ -0,0 +1,239 @@
+//===- llvm/ADT/MapVector.h - Map w/ deterministic value order --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a map that provides insertion order iteration. The
+// interface is purposefully minimal. The key is assumed to be cheap to copy
+// and 2 copies are kept, one for indexing in a DenseMap, one for iteration in
+// a std::vector.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_MAPVECTOR_H
+#define LLVM_ADT_MAPVECTOR_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+
+/// This class implements a map that also provides access to all stored values
+/// in a deterministic order. The values are kept in a std::vector and the
+/// mapping is done with DenseMap from Keys to indexes in that vector.
+template<typename KeyT, typename ValueT,
+         typename MapType = DenseMap<KeyT, unsigned>,
+         typename VectorType = std::vector<std::pair<KeyT, ValueT>>>
+class MapVector {
+  MapType Map;
+  VectorType Vector;
+
+  static_assert(
+      std::is_integral<typename MapType::mapped_type>::value,
+      "The mapped_type of the specified Map must be an integral type");
+
+public:
+  using value_type = typename VectorType::value_type;
+  using size_type = typename VectorType::size_type;
+
+  using iterator = typename VectorType::iterator;
+  using const_iterator = typename VectorType::const_iterator;
+  using reverse_iterator = typename VectorType::reverse_iterator;
+  using const_reverse_iterator = typename VectorType::const_reverse_iterator;
+
+  /// Clear the MapVector and return the underlying vector.
+  VectorType takeVector() {
+    Map.clear();
+    return std::move(Vector);
+  }
+
+  size_type size() const { return Vector.size(); }
+
+  /// Grow the MapVector so that it can contain at least \p NumEntries items
+  /// before resizing again.
+  void reserve(size_type NumEntries) {
+    Map.reserve(NumEntries);
+    Vector.reserve(NumEntries);
+  }
+
+  iterator begin() { return Vector.begin(); }
+  const_iterator begin() const { return Vector.begin(); }
+  iterator end() { return Vector.end(); }
+  const_iterator end() const { return Vector.end(); }
+
+  reverse_iterator rbegin() { return Vector.rbegin(); }
+  const_reverse_iterator rbegin() const { return Vector.rbegin(); }
+  reverse_iterator rend() { return Vector.rend(); }
+  const_reverse_iterator rend() const { return Vector.rend(); }
+
+  bool empty() const {
+    return Vector.empty();
+  }
+
+  std::pair<KeyT, ValueT>       &front()       { return Vector.front(); }
+  const std::pair<KeyT, ValueT> &front() const { return Vector.front(); }
+  std::pair<KeyT, ValueT>       &back()        { return Vector.back(); }
+  const std::pair<KeyT, ValueT> &back()  const { return Vector.back(); }
+
+  void clear() {
+    Map.clear();
+    Vector.clear();
+  }
+
+  void swap(MapVector &RHS) {
+    std::swap(Map, RHS.Map);
+    std::swap(Vector, RHS.Vector);
+  }
+
+  ValueT &operator[](const KeyT &Key) {
+    std::pair<KeyT, typename MapType::mapped_type> Pair = std::make_pair(Key, 0);
+    std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair);
+    auto &I = Result.first->second;
+    if (Result.second) {
+      Vector.push_back(std::make_pair(Key, ValueT()));
+      I = Vector.size() - 1;
+    }
+    return Vector[I].second;
+  }
+
+  // Returns a copy of the value.  Only allowed if ValueT is copyable.
+  ValueT lookup(const KeyT &Key) const {
+    static_assert(std::is_copy_constructible<ValueT>::value,
+                  "Cannot call lookup() if ValueT is not copyable.");
+    typename MapType::const_iterator Pos = Map.find(Key);
+    return Pos == Map.end()? ValueT() : Vector[Pos->second].second;
+  }
+
+  std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
+    std::pair<KeyT, typename MapType::mapped_type> Pair = std::make_pair(KV.first, 0);
+    std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair);
+    auto &I = Result.first->second;
+    if (Result.second) {
+      Vector.push_back(std::make_pair(KV.first, KV.second));
+      I = Vector.size() - 1;
+      return std::make_pair(std::prev(end()), true);
+    }
+    return std::make_pair(begin() + I, false);
+  }
+
+  std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
+    // Copy KV.first into the map, then move it into the vector.
+    std::pair<KeyT, typename MapType::mapped_type> Pair = std::make_pair(KV.first, 0);
+    std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair);
+    auto &I = Result.first->second;
+    if (Result.second) {
+      Vector.push_back(std::move(KV));
+      I = Vector.size() - 1;
+      return std::make_pair(std::prev(end()), true);
+    }
+    return std::make_pair(begin() + I, false);
+  }
+
+  size_type count(const KeyT &Key) const {
+    typename MapType::const_iterator Pos = Map.find(Key);
+    return Pos == Map.end()? 0 : 1;
+  }
+
+  iterator find(const KeyT &Key) {
+    typename MapType::const_iterator Pos = Map.find(Key);
+    return Pos == Map.end()? Vector.end() :
+                            (Vector.begin() + Pos->second);
+  }
+
+  const_iterator find(const KeyT &Key) const {
+    typename MapType::const_iterator Pos = Map.find(Key);
+    return Pos == Map.end()? Vector.end() :
+                            (Vector.begin() + Pos->second);
+  }
+
+  /// Remove the last element from the vector.
+  void pop_back() {
+    typename MapType::iterator Pos = Map.find(Vector.back().first);
+    Map.erase(Pos);
+    Vector.pop_back();
+  }
+
+  /// Remove the element given by Iterator.
+  ///
+  /// Returns an iterator to the element following the one which was removed,
+  /// which may be end().
+  ///
+  /// \note This is a deceivingly expensive operation (linear time).  It's
+  /// usually better to use \a remove_if() if possible.
+  typename VectorType::iterator erase(typename VectorType::iterator Iterator) {
+    Map.erase(Iterator->first);
+    auto Next = Vector.erase(Iterator);
+    if (Next == Vector.end())
+      return Next;
+
+    // Update indices in the map.
+    size_t Index = Next - Vector.begin();
+    for (auto &I : Map) {
+      assert(I.second != Index && "Index was already erased!");
+      if (I.second > Index)
+        --I.second;
+    }
+    return Next;
+  }
+
+  /// Remove all elements with the key value Key.
+  ///
+  /// Returns the number of elements removed.
+  size_type erase(const KeyT &Key) {
+    auto Iterator = find(Key);
+    if (Iterator == end())
+      return 0;
+    erase(Iterator);
+    return 1;
+  }
+
+  /// Remove the elements that match the predicate.
+  ///
+  /// Erase all elements that match \c Pred in a single pass.  Takes linear
+  /// time.
+  template <class Predicate> void remove_if(Predicate Pred);
+};
+
+template <typename KeyT, typename ValueT, typename MapType, typename VectorType>
+template <class Function>
+void MapVector<KeyT, ValueT, MapType, VectorType>::remove_if(Function Pred) {
+  auto O = Vector.begin();
+  for (auto I = O, E = Vector.end(); I != E; ++I) {
+    if (Pred(*I)) {
+      // Erase from the map.
+      Map.erase(I->first);
+      continue;
+    }
+
+    if (I != O) {
+      // Move the value and update the index in the map.
+      *O = std::move(*I);
+      Map[O->first] = O - Vector.begin();
+    }
+    ++O;
+  }
+  // Erase trailing entries in the vector.
+  Vector.erase(O, Vector.end());
+}
+
+/// A MapVector that performs no allocations if smaller than a certain
+/// size.
+template <typename KeyT, typename ValueT, unsigned N>
+struct SmallMapVector
+    : MapVector<KeyT, ValueT, SmallDenseMap<KeyT, unsigned, N>,
+                SmallVector<std::pair<KeyT, ValueT>, N>> {
+};
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_MAPVECTOR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/None.h b/binaryen/third_party/llvm-project/include/llvm/ADT/None.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/None.h
@@ -0,0 +1,26 @@
+//===-- None.h - Simple null value for implicit construction ------*- C++ -*-=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file provides None, an enumerator for use in implicit constructors
+//  of various (usually templated) types to make such construction more
+//  terse.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_NONE_H
+#define LLVM_ADT_NONE_H
+
+namespace llvm {
+/// A simple null object to allow implicit construction of Optional<T>
+/// and similar types without having to spell out the specialization's name.
+// (constant value 1 in an attempt to workaround MSVC build issue... )
+enum class NoneType { None = 1 };
+const NoneType None = NoneType::None;
+}
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/Optional.h b/binaryen/third_party/llvm-project/include/llvm/ADT/Optional.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/Optional.h
@@ -0,0 +1,429 @@
+//===- Optional.h - Simple variant for passing optional values --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file provides Optional, a template class modeled in the spirit of
+//  OCaml's 'opt' variant.  The idea is to strongly type whether or not
+//  a value can be optional.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_OPTIONAL_H
+#define LLVM_ADT_OPTIONAL_H
+
+#include "llvm/ADT/None.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/type_traits.h"
+#include <cassert>
+#include <memory>
+#include <new>
+#include <utility>
+
+namespace llvm {
+
+class raw_ostream;
+
+namespace optional_detail {
+
+struct in_place_t {};
+
+/// Storage for any type.
+template <typename T, bool = is_trivially_copyable<T>::value>
+class OptionalStorage {
+  union {
+    char empty;
+    T value;
+  };
+  bool hasVal;
+
+public:
+  ~OptionalStorage() { reset(); }
+
+  OptionalStorage() noexcept : empty(), hasVal(false) {}
+
+  OptionalStorage(OptionalStorage const &other) : OptionalStorage() {
+    if (other.hasValue()) {
+      emplace(other.value);
+    }
+  }
+  OptionalStorage(OptionalStorage &&other) : OptionalStorage() {
+    if (other.hasValue()) {
+      emplace(std::move(other.value));
+    }
+  }
+
+  template <class... Args>
+  explicit OptionalStorage(in_place_t, Args &&... args)
+      : value(std::forward<Args>(args)...), hasVal(true) {}
+
+  void reset() noexcept {
+    if (hasVal) {
+      value.~T();
+      hasVal = false;
+    }
+  }
+
+  bool hasValue() const noexcept { return hasVal; }
+
+  T &getValue() LLVM_LVALUE_FUNCTION noexcept {
+    assert(hasVal);
+    return value;
+  }
+  T const &getValue() const LLVM_LVALUE_FUNCTION noexcept {
+    assert(hasVal);
+    return value;
+  }
+#if LLVM_HAS_RVALUE_REFERENCE_THIS
+  T &&getValue() && noexcept {
+    assert(hasVal);
+    return std::move(value);
+  }
+#endif
+
+  template <class... Args> void emplace(Args &&... args) {
+    reset();
+    ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
+    hasVal = true;
+  }
+
+  OptionalStorage &operator=(T const &y) {
+    if (hasValue()) {
+      value = y;
+    } else {
+      ::new ((void *)std::addressof(value)) T(y);
+      hasVal = true;
+    }
+    return *this;
+  }
+  OptionalStorage &operator=(T &&y) {
+    if (hasValue()) {
+      value = std::move(y);
+    } else {
+      ::new ((void *)std::addressof(value)) T(std::move(y));
+      hasVal = true;
+    }
+    return *this;
+  }
+
+  OptionalStorage &operator=(OptionalStorage const &other) {
+    if (other.hasValue()) {
+      if (hasValue()) {
+        value = other.value;
+      } else {
+        ::new ((void *)std::addressof(value)) T(other.value);
+        hasVal = true;
+      }
+    } else {
+      reset();
+    }
+    return *this;
+  }
+
+  OptionalStorage &operator=(OptionalStorage &&other) {
+    if (other.hasValue()) {
+      if (hasValue()) {
+        value = std::move(other.value);
+      } else {
+        ::new ((void *)std::addressof(value)) T(std::move(other.value));
+        hasVal = true;
+      }
+    } else {
+      reset();
+    }
+    return *this;
+  }
+};
+
+template <typename T> class OptionalStorage<T, true> {
+  union {
+    char empty;
+    T value;
+  };
+  bool hasVal = false;
+
+public:
+  ~OptionalStorage() = default;
+
+  OptionalStorage() noexcept : empty{} {}
+
+  OptionalStorage(OptionalStorage const &other) = default;
+  OptionalStorage(OptionalStorage &&other) = default;
+
+  OptionalStorage &operator=(OptionalStorage const &other) = default;
+  OptionalStorage &operator=(OptionalStorage &&other) = default;
+
+  template <class... Args>
+  explicit OptionalStorage(in_place_t, Args &&... args)
+      : value(std::forward<Args>(args)...), hasVal(true) {}
+
+  void reset() noexcept {
+    if (hasVal) {
+      value.~T();
+      hasVal = false;
+    }
+  }
+
+  bool hasValue() const noexcept { return hasVal; }
+
+  T &getValue() LLVM_LVALUE_FUNCTION noexcept {
+    assert(hasVal);
+    return value;
+  }
+  T const &getValue() const LLVM_LVALUE_FUNCTION noexcept {
+    assert(hasVal);
+    return value;
+  }
+#if LLVM_HAS_RVALUE_REFERENCE_THIS
+  T &&getValue() && noexcept {
+    assert(hasVal);
+    return std::move(value);
+  }
+#endif
+
+  template <class... Args> void emplace(Args &&... args) {
+    reset();
+    ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
+    hasVal = true;
+  }
+
+  OptionalStorage &operator=(T const &y) {
+    if (hasValue()) {
+      value = y;
+    } else {
+      ::new ((void *)std::addressof(value)) T(y);
+      hasVal = true;
+    }
+    return *this;
+  }
+  OptionalStorage &operator=(T &&y) {
+    if (hasValue()) {
+      value = std::move(y);
+    } else {
+      ::new ((void *)std::addressof(value)) T(std::move(y));
+      hasVal = true;
+    }
+    return *this;
+  }
+};
+
+} // namespace optional_detail
+
+template <typename T> class Optional {
+  optional_detail::OptionalStorage<T> Storage;
+
+public:
+  using value_type = T;
+
+  constexpr Optional() {}
+  constexpr Optional(NoneType) {}
+
+  Optional(const T &y) : Storage(optional_detail::in_place_t{}, y) {}
+  Optional(const Optional &O) = default;
+
+  Optional(T &&y) : Storage(optional_detail::in_place_t{}, std::move(y)) {}
+  Optional(Optional &&O) = default;
+
+  Optional &operator=(T &&y) {
+    Storage = std::move(y);
+    return *this;
+  }
+  Optional &operator=(Optional &&O) = default;
+
+  /// Create a new object by constructing it in place with the given arguments.
+  template <typename... ArgTypes> void emplace(ArgTypes &&... Args) {
+    Storage.emplace(std::forward<ArgTypes>(Args)...);
+  }
+
+  static inline Optional create(const T *y) {
+    return y ? Optional(*y) : Optional();
+  }
+
+  Optional &operator=(const T &y) {
+    Storage = y;
+    return *this;
+  }
+  Optional &operator=(const Optional &O) = default;
+
+  void reset() { Storage.reset(); }
+
+  const T *getPointer() const { return &Storage.getValue(); }
+  T *getPointer() { return &Storage.getValue(); }
+  const T &getValue() const LLVM_LVALUE_FUNCTION { return Storage.getValue(); }
+  T &getValue() LLVM_LVALUE_FUNCTION { return Storage.getValue(); }
+
+  explicit operator bool() const { return hasValue(); }
+  bool hasValue() const { return Storage.hasValue(); }
+  const T *operator->() const { return getPointer(); }
+  T *operator->() { return getPointer(); }
+  const T &operator*() const LLVM_LVALUE_FUNCTION { return getValue(); }
+  T &operator*() LLVM_LVALUE_FUNCTION { return getValue(); }
+
+  template <typename U>
+  constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
+    return hasValue() ? getValue() : std::forward<U>(value);
+  }
+
+#if LLVM_HAS_RVALUE_REFERENCE_THIS
+  T &&getValue() && { return std::move(Storage.getValue()); }
+  T &&operator*() && { return std::move(Storage.getValue()); }
+
+  template <typename U>
+  T getValueOr(U &&value) && {
+    return hasValue() ? std::move(getValue()) : std::forward<U>(value);
+  }
+#endif
+};
+
+template <typename T, typename U>
+bool operator==(const Optional<T> &X, const Optional<U> &Y) {
+  if (X && Y)
+    return *X == *Y;
+  return X.hasValue() == Y.hasValue();
+}
+
+template <typename T, typename U>
+bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
+  return !(X == Y);
+}
+
+template <typename T, typename U>
+bool operator<(const Optional<T> &X, const Optional<U> &Y) {
+  if (X && Y)
+    return *X < *Y;
+  return X.hasValue() < Y.hasValue();
+}
+
+template <typename T, typename U>
+bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
+  return !(Y < X);
+}
+
+template <typename T, typename U>
+bool operator>(const Optional<T> &X, const Optional<U> &Y) {
+  return Y < X;
+}
+
+template <typename T, typename U>
+bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
+  return !(X < Y);
+}
+
+template<typename T>
+bool operator==(const Optional<T> &X, NoneType) {
+  return !X;
+}
+
+template<typename T>
+bool operator==(NoneType, const Optional<T> &X) {
+  return X == None;
+}
+
+template<typename T>
+bool operator!=(const Optional<T> &X, NoneType) {
+  return !(X == None);
+}
+
+template<typename T>
+bool operator!=(NoneType, const Optional<T> &X) {
+  return X != None;
+}
+
+template <typename T> bool operator<(const Optional<T> &X, NoneType) {
+  return false;
+}
+
+template <typename T> bool operator<(NoneType, const Optional<T> &X) {
+  return X.hasValue();
+}
+
+template <typename T> bool operator<=(const Optional<T> &X, NoneType) {
+  return !(None < X);
+}
+
+template <typename T> bool operator<=(NoneType, const Optional<T> &X) {
+  return !(X < None);
+}
+
+template <typename T> bool operator>(const Optional<T> &X, NoneType) {
+  return None < X;
+}
+
+template <typename T> bool operator>(NoneType, const Optional<T> &X) {
+  return X < None;
+}
+
+template <typename T> bool operator>=(const Optional<T> &X, NoneType) {
+  return None <= X;
+}
+
+template <typename T> bool operator>=(NoneType, const Optional<T> &X) {
+  return X <= None;
+}
+
+template <typename T> bool operator==(const Optional<T> &X, const T &Y) {
+  return X && *X == Y;
+}
+
+template <typename T> bool operator==(const T &X, const Optional<T> &Y) {
+  return Y && X == *Y;
+}
+
+template <typename T> bool operator!=(const Optional<T> &X, const T &Y) {
+  return !(X == Y);
+}
+
+template <typename T> bool operator!=(const T &X, const Optional<T> &Y) {
+  return !(X == Y);
+}
+
+template <typename T> bool operator<(const Optional<T> &X, const T &Y) {
+  return !X || *X < Y;
+}
+
+template <typename T> bool operator<(const T &X, const Optional<T> &Y) {
+  return Y && X < *Y;
+}
+
+template <typename T> bool operator<=(const Optional<T> &X, const T &Y) {
+  return !(Y < X);
+}
+
+template <typename T> bool operator<=(const T &X, const Optional<T> &Y) {
+  return !(Y < X);
+}
+
+template <typename T> bool operator>(const Optional<T> &X, const T &Y) {
+  return Y < X;
+}
+
+template <typename T> bool operator>(const T &X, const Optional<T> &Y) {
+  return Y < X;
+}
+
+template <typename T> bool operator>=(const Optional<T> &X, const T &Y) {
+  return !(X < Y);
+}
+
+template <typename T> bool operator>=(const T &X, const Optional<T> &Y) {
+  return !(X < Y);
+}
+
+raw_ostream &operator<<(raw_ostream &OS, NoneType);
+
+template <typename T, typename = decltype(std::declval<raw_ostream &>()
+                                          << std::declval<const T &>())>
+raw_ostream &operator<<(raw_ostream &OS, const Optional<T> &O) {
+  if (O)
+    OS << *O;
+  else
+    OS << None;
+  return OS;
+}
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_OPTIONAL_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/PointerIntPair.h b/binaryen/third_party/llvm-project/include/llvm/ADT/PointerIntPair.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/PointerIntPair.h
@@ -0,0 +1,243 @@
+//===- llvm/ADT/PointerIntPair.h - Pair for pointer and int -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the PointerIntPair class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_POINTERINTPAIR_H
+#define LLVM_ADT_POINTERINTPAIR_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
+#include "llvm/Support/type_traits.h"
+#include <cassert>
+#include <cstdint>
+#include <limits>
+
+namespace llvm {
+
+template <typename T> struct DenseMapInfo;
+template <typename PointerT, unsigned IntBits, typename PtrTraits>
+struct PointerIntPairInfo;
+
+/// PointerIntPair - This class implements a pair of a pointer and small
+/// integer.  It is designed to represent this in the space required by one
+/// pointer by bitmangling the integer into the low part of the pointer.  This
+/// can only be done for small integers: typically up to 3 bits, but it depends
+/// on the number of bits available according to PointerLikeTypeTraits for the
+/// type.
+///
+/// Note that PointerIntPair always puts the IntVal part in the highest bits
+/// possible.  For example, PointerIntPair<void*, 1, bool> will put the bit for
+/// the bool into bit #2, not bit #0, which allows the low two bits to be used
+/// for something else.  For example, this allows:
+///   PointerIntPair<PointerIntPair<void*, 1, bool>, 1, bool>
+/// ... and the two bools will land in different bits.
+template <typename PointerTy, unsigned IntBits, typename IntType = unsigned,
+          typename PtrTraits = PointerLikeTypeTraits<PointerTy>,
+          typename Info = PointerIntPairInfo<PointerTy, IntBits, PtrTraits>>
+class PointerIntPair {
+  // Used by MSVC visualizer and generally helpful for debugging/visualizing.
+  using InfoTy = Info;
+  intptr_t Value = 0;
+
+public:
+  constexpr PointerIntPair() = default;
+
+  PointerIntPair(PointerTy PtrVal, IntType IntVal) {
+    setPointerAndInt(PtrVal, IntVal);
+  }
+
+  explicit PointerIntPair(PointerTy PtrVal) { initWithPointer(PtrVal); }
+
+  PointerTy getPointer() const { return Info::getPointer(Value); }
+
+  IntType getInt() const { return (IntType)Info::getInt(Value); }
+
+  void setPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
+    Value = Info::updatePointer(Value, PtrVal);
+  }
+
+  void setInt(IntType IntVal) LLVM_LVALUE_FUNCTION {
+    Value = Info::updateInt(Value, static_cast<intptr_t>(IntVal));
+  }
+
+  void initWithPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
+    Value = Info::updatePointer(0, PtrVal);
+  }
+
+  void setPointerAndInt(PointerTy PtrVal, IntType IntVal) LLVM_LVALUE_FUNCTION {
+    Value = Info::updateInt(Info::updatePointer(0, PtrVal),
+                            static_cast<intptr_t>(IntVal));
+  }
+
+  PointerTy const *getAddrOfPointer() const {
+    return const_cast<PointerIntPair *>(this)->getAddrOfPointer();
+  }
+
+  PointerTy *getAddrOfPointer() {
+    assert(Value == reinterpret_cast<intptr_t>(getPointer()) &&
+           "Can only return the address if IntBits is cleared and "
+           "PtrTraits doesn't change the pointer");
+    return reinterpret_cast<PointerTy *>(&Value);
+  }
+
+  void *getOpaqueValue() const { return reinterpret_cast<void *>(Value); }
+
+  void setFromOpaqueValue(void *Val) LLVM_LVALUE_FUNCTION {
+    Value = reinterpret_cast<intptr_t>(Val);
+  }
+
+  static PointerIntPair getFromOpaqueValue(void *V) {
+    PointerIntPair P;
+    P.setFromOpaqueValue(V);
+    return P;
+  }
+
+  // Allow PointerIntPairs to be created from const void * if and only if the
+  // pointer type could be created from a const void *.
+  static PointerIntPair getFromOpaqueValue(const void *V) {
+    (void)PtrTraits::getFromVoidPointer(V);
+    return getFromOpaqueValue(const_cast<void *>(V));
+  }
+
+  bool operator==(const PointerIntPair &RHS) const {
+    return Value == RHS.Value;
+  }
+
+  bool operator!=(const PointerIntPair &RHS) const {
+    return Value != RHS.Value;
+  }
+
+  bool operator<(const PointerIntPair &RHS) const { return Value < RHS.Value; }
+  bool operator>(const PointerIntPair &RHS) const { return Value > RHS.Value; }
+
+  bool operator<=(const PointerIntPair &RHS) const {
+    return Value <= RHS.Value;
+  }
+
+  bool operator>=(const PointerIntPair &RHS) const {
+    return Value >= RHS.Value;
+  }
+};
+
+// Specialize is_trivially_copyable to avoid limitation of llvm::is_trivially_copyable
+// when compiled with gcc 4.9.
+template <typename PointerTy, unsigned IntBits, typename IntType,
+          typename PtrTraits,
+          typename Info>
+struct is_trivially_copyable<PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info>> : std::true_type {
+#ifdef HAVE_STD_IS_TRIVIALLY_COPYABLE
+  static_assert(std::is_trivially_copyable<PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info>>::value,
+                "inconsistent behavior between llvm:: and std:: implementation of is_trivially_copyable");
+#endif
+};
+
+
+template <typename PointerT, unsigned IntBits, typename PtrTraits>
+struct PointerIntPairInfo {
+  static_assert(PtrTraits::NumLowBitsAvailable <
+                    std::numeric_limits<uintptr_t>::digits,
+                "cannot use a pointer type that has all bits free");
+  static_assert(IntBits <= PtrTraits::NumLowBitsAvailable,
+                "PointerIntPair with integer size too large for pointer");
+  enum : uintptr_t {
+    /// PointerBitMask - The bits that come from the pointer.
+    PointerBitMask =
+        ~(uintptr_t)(((intptr_t)1 << PtrTraits::NumLowBitsAvailable) - 1),
+
+    /// IntShift - The number of low bits that we reserve for other uses, and
+    /// keep zero.
+    IntShift = (uintptr_t)PtrTraits::NumLowBitsAvailable - IntBits,
+
+    /// IntMask - This is the unshifted mask for valid bits of the int type.
+    IntMask = (uintptr_t)(((intptr_t)1 << IntBits) - 1),
+
+    // ShiftedIntMask - This is the bits for the integer shifted in place.
+    ShiftedIntMask = (uintptr_t)(IntMask << IntShift)
+  };
+
+  static PointerT getPointer(intptr_t Value) {
+    return PtrTraits::getFromVoidPointer(
+        reinterpret_cast<void *>(Value & PointerBitMask));
+  }
+
+  static intptr_t getInt(intptr_t Value) {
+    return (Value >> IntShift) & IntMask;
+  }
+
+  static intptr_t updatePointer(intptr_t OrigValue, PointerT Ptr) {
+    intptr_t PtrWord =
+        reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(Ptr));
+    assert((PtrWord & ~PointerBitMask) == 0 &&
+           "Pointer is not sufficiently aligned");
+    // Preserve all low bits, just update the pointer.
+    return PtrWord | (OrigValue & ~PointerBitMask);
+  }
+
+  static intptr_t updateInt(intptr_t OrigValue, intptr_t Int) {
+    intptr_t IntWord = static_cast<intptr_t>(Int);
+    assert((IntWord & ~IntMask) == 0 && "Integer too large for field");
+
+    // Preserve all bits other than the ones we are updating.
+    return (OrigValue & ~ShiftedIntMask) | IntWord << IntShift;
+  }
+};
+
+// Provide specialization of DenseMapInfo for PointerIntPair.
+template <typename PointerTy, unsigned IntBits, typename IntType>
+struct DenseMapInfo<PointerIntPair<PointerTy, IntBits, IntType>> {
+  using Ty = PointerIntPair<PointerTy, IntBits, IntType>;
+
+  static Ty getEmptyKey() {
+    uintptr_t Val = static_cast<uintptr_t>(-1);
+    Val <<= PointerLikeTypeTraits<Ty>::NumLowBitsAvailable;
+    return Ty::getFromOpaqueValue(reinterpret_cast<void *>(Val));
+  }
+
+  static Ty getTombstoneKey() {
+    uintptr_t Val = static_cast<uintptr_t>(-2);
+    Val <<= PointerLikeTypeTraits<PointerTy>::NumLowBitsAvailable;
+    return Ty::getFromOpaqueValue(reinterpret_cast<void *>(Val));
+  }
+
+  static unsigned getHashValue(Ty V) {
+    uintptr_t IV = reinterpret_cast<uintptr_t>(V.getOpaqueValue());
+    return unsigned(IV) ^ unsigned(IV >> 9);
+  }
+
+  static bool isEqual(const Ty &LHS, const Ty &RHS) { return LHS == RHS; }
+};
+
+// Teach SmallPtrSet that PointerIntPair is "basically a pointer".
+template <typename PointerTy, unsigned IntBits, typename IntType,
+          typename PtrTraits>
+struct PointerLikeTypeTraits<
+    PointerIntPair<PointerTy, IntBits, IntType, PtrTraits>> {
+  static inline void *
+  getAsVoidPointer(const PointerIntPair<PointerTy, IntBits, IntType> &P) {
+    return P.getOpaqueValue();
+  }
+
+  static inline PointerIntPair<PointerTy, IntBits, IntType>
+  getFromVoidPointer(void *P) {
+    return PointerIntPair<PointerTy, IntBits, IntType>::getFromOpaqueValue(P);
+  }
+
+  static inline PointerIntPair<PointerTy, IntBits, IntType>
+  getFromVoidPointer(const void *P) {
+    return PointerIntPair<PointerTy, IntBits, IntType>::getFromOpaqueValue(P);
+  }
+
+  enum { NumLowBitsAvailable = PtrTraits::NumLowBitsAvailable - IntBits };
+};
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_POINTERINTPAIR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/PointerUnion.h b/binaryen/third_party/llvm-project/include/llvm/ADT/PointerUnion.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/PointerUnion.h
@@ -0,0 +1,309 @@
+//===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the PointerUnion class, which is a discriminated union of
+// pointer types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_POINTERUNION_H
+#define LLVM_ADT_POINTERUNION_H
+
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+
+namespace llvm {
+
+template <typename T> struct PointerUnionTypeSelectorReturn {
+  using Return = T;
+};
+
+/// Get a type based on whether two types are the same or not.
+///
+/// For:
+///
+/// \code
+///   using Ret = typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return;
+/// \endcode
+///
+/// Ret will be EQ type if T1 is same as T2 or NE type otherwise.
+template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
+struct PointerUnionTypeSelector {
+  using Return = typename PointerUnionTypeSelectorReturn<RET_NE>::Return;
+};
+
+template <typename T, typename RET_EQ, typename RET_NE>
+struct PointerUnionTypeSelector<T, T, RET_EQ, RET_NE> {
+  using Return = typename PointerUnionTypeSelectorReturn<RET_EQ>::Return;
+};
+
+template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
+struct PointerUnionTypeSelectorReturn<
+    PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>> {
+  using Return =
+      typename PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>::Return;
+};
+
+namespace pointer_union_detail {
+  /// Determine the number of bits required to store integers with values < n.
+  /// This is ceil(log2(n)).
+  constexpr int bitsRequired(unsigned n) {
+    return n > 1 ? 1 + bitsRequired((n + 1) / 2) : 0;
+  }
+
+  template <typename... Ts> constexpr int lowBitsAvailable() {
+    return std::min<int>({PointerLikeTypeTraits<Ts>::NumLowBitsAvailable...});
+  }
+
+  /// Find the index of a type in a list of types. TypeIndex<T, Us...>::Index
+  /// is the index of T in Us, or sizeof...(Us) if T does not appear in the
+  /// list.
+  template <typename T, typename ...Us> struct TypeIndex;
+  template <typename T, typename ...Us> struct TypeIndex<T, T, Us...> {
+    static constexpr int Index = 0;
+  };
+  template <typename T, typename U, typename... Us>
+  struct TypeIndex<T, U, Us...> {
+    static constexpr int Index = 1 + TypeIndex<T, Us...>::Index;
+  };
+  template <typename T> struct TypeIndex<T> {
+    static constexpr int Index = 0;
+  };
+
+  /// Find the first type in a list of types.
+  template <typename T, typename...> struct GetFirstType {
+    using type = T;
+  };
+
+  /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
+  /// for the template arguments.
+  template <typename ...PTs> class PointerUnionUIntTraits {
+  public:
+    static inline void *getAsVoidPointer(void *P) { return P; }
+    static inline void *getFromVoidPointer(void *P) { return P; }
+    static constexpr int NumLowBitsAvailable = lowBitsAvailable<PTs...>();
+  };
+
+  /// Implement assigment in terms of construction.
+  template <typename Derived, typename T> struct AssignableFrom {
+    Derived &operator=(T t) {
+      return static_cast<Derived &>(*this) = Derived(t);
+    }
+  };
+
+  template <typename Derived, typename ValTy, int I, typename ...Types>
+  class PointerUnionMembers;
+
+  template <typename Derived, typename ValTy, int I>
+  class PointerUnionMembers<Derived, ValTy, I> {
+  protected:
+    ValTy Val;
+    PointerUnionMembers() = default;
+    PointerUnionMembers(ValTy Val) : Val(Val) {}
+
+    friend struct PointerLikeTypeTraits<Derived>;
+  };
+
+  template <typename Derived, typename ValTy, int I, typename Type,
+            typename ...Types>
+  class PointerUnionMembers<Derived, ValTy, I, Type, Types...>
+      : public PointerUnionMembers<Derived, ValTy, I + 1, Types...> {
+    using Base = PointerUnionMembers<Derived, ValTy, I + 1, Types...>;
+  public:
+    using Base::Base;
+    PointerUnionMembers() = default;
+    PointerUnionMembers(Type V)
+        : Base(ValTy(const_cast<void *>(
+                         PointerLikeTypeTraits<Type>::getAsVoidPointer(V)),
+                     I)) {}
+
+    using Base::operator=;
+    Derived &operator=(Type V) {
+      this->Val = ValTy(
+          const_cast<void *>(PointerLikeTypeTraits<Type>::getAsVoidPointer(V)),
+          I);
+      return static_cast<Derived &>(*this);
+    };
+  };
+}
+
+/// A discriminated union of two or more pointer types, with the discriminator
+/// in the low bit of the pointer.
+///
+/// This implementation is extremely efficient in space due to leveraging the
+/// low bits of the pointer, while exposing a natural and type-safe API.
+///
+/// Common use patterns would be something like this:
+///    PointerUnion<int*, float*> P;
+///    P = (int*)0;
+///    printf("%d %d", P.is<int*>(), P.is<float*>());  // prints "1 0"
+///    X = P.get<int*>();     // ok.
+///    Y = P.get<float*>();   // runtime assertion failure.
+///    Z = P.get<double*>();  // compile time failure.
+///    P = (float*)0;
+///    Y = P.get<float*>();   // ok.
+///    X = P.get<int*>();     // runtime assertion failure.
+template <typename... PTs>
+class PointerUnion
+    : public pointer_union_detail::PointerUnionMembers<
+          PointerUnion<PTs...>,
+          PointerIntPair<
+              void *, pointer_union_detail::bitsRequired(sizeof...(PTs)), int,
+              pointer_union_detail::PointerUnionUIntTraits<PTs...>>,
+          0, PTs...> {
+  // The first type is special because we want to directly cast a pointer to a
+  // default-initialized union to a pointer to the first type. But we don't
+  // want PointerUnion to be a 'template <typename First, typename ...Rest>'
+  // because it's much more convenient to have a name for the whole pack. So
+  // split off the first type here.
+  using First = typename pointer_union_detail::GetFirstType<PTs...>::type;
+  using Base = typename PointerUnion::PointerUnionMembers;
+
+public:
+  PointerUnion() = default;
+
+  PointerUnion(std::nullptr_t) : PointerUnion() {}
+  using Base::Base;
+
+  /// Test if the pointer held in the union is null, regardless of
+  /// which type it is.
+  bool isNull() const { return !this->Val.getPointer(); }
+
+  explicit operator bool() const { return !isNull(); }
+
+  /// Test if the Union currently holds the type matching T.
+  template <typename T> int is() const {
+    constexpr int Index = pointer_union_detail::TypeIndex<T, PTs...>::Index;
+    static_assert(Index < sizeof...(PTs),
+                  "PointerUnion::is<T> given type not in the union");
+    return this->Val.getInt() == Index;
+  }
+
+  /// Returns the value of the specified pointer type.
+  ///
+  /// If the specified pointer type is incorrect, assert.
+  template <typename T> T get() const {
+    assert(is<T>() && "Invalid accessor called");
+    return PointerLikeTypeTraits<T>::getFromVoidPointer(this->Val.getPointer());
+  }
+
+  /// Returns the current pointer if it is of the specified pointer type,
+  /// otherwises returns null.
+  template <typename T> T dyn_cast() const {
+    if (is<T>())
+      return get<T>();
+    return T();
+  }
+
+  /// If the union is set to the first pointer type get an address pointing to
+  /// it.
+  First const *getAddrOfPtr1() const {
+    return const_cast<PointerUnion *>(this)->getAddrOfPtr1();
+  }
+
+  /// If the union is set to the first pointer type get an address pointing to
+  /// it.
+  First *getAddrOfPtr1() {
+    assert(is<First>() && "Val is not the first pointer");
+    assert(
+        PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) ==
+            this->Val.getPointer() &&
+        "Can't get the address because PointerLikeTypeTraits changes the ptr");
+    return const_cast<First *>(
+        reinterpret_cast<const First *>(this->Val.getAddrOfPointer()));
+  }
+
+  /// Assignment from nullptr which just clears the union.
+  const PointerUnion &operator=(std::nullptr_t) {
+    this->Val.initWithPointer(nullptr);
+    return *this;
+  }
+
+  /// Assignment from elements of the union.
+  using Base::operator=;
+
+  void *getOpaqueValue() const { return this->Val.getOpaqueValue(); }
+  static inline PointerUnion getFromOpaqueValue(void *VP) {
+    PointerUnion V;
+    V.Val = decltype(V.Val)::getFromOpaqueValue(VP);
+    return V;
+  }
+};
+
+template <typename ...PTs>
+bool operator==(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
+  return lhs.getOpaqueValue() == rhs.getOpaqueValue();
+}
+
+template <typename ...PTs>
+bool operator!=(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
+  return lhs.getOpaqueValue() != rhs.getOpaqueValue();
+}
+
+template <typename ...PTs>
+bool operator<(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
+  return lhs.getOpaqueValue() < rhs.getOpaqueValue();
+}
+
+// Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
+// # low bits available = min(PT1bits,PT2bits)-1.
+template <typename ...PTs>
+struct PointerLikeTypeTraits<PointerUnion<PTs...>> {
+  static inline void *getAsVoidPointer(const PointerUnion<PTs...> &P) {
+    return P.getOpaqueValue();
+  }
+
+  static inline PointerUnion<PTs...> getFromVoidPointer(void *P) {
+    return PointerUnion<PTs...>::getFromOpaqueValue(P);
+  }
+
+  // The number of bits available are the min of the pointer types minus the
+  // bits needed for the discriminator.
+  static constexpr int NumLowBitsAvailable = PointerLikeTypeTraits<decltype(
+      PointerUnion<PTs...>::Val)>::NumLowBitsAvailable;
+};
+
+/// A pointer union of three pointer types. See documentation for PointerUnion
+/// for usage.
+template <typename PT1, typename PT2, typename PT3>
+using PointerUnion3 = PointerUnion<PT1, PT2, PT3>;
+
+/// A pointer union of four pointer types. See documentation for PointerUnion
+/// for usage.
+template <typename PT1, typename PT2, typename PT3, typename PT4>
+using PointerUnion4 = PointerUnion<PT1, PT2, PT3, PT4>;
+
+// Teach DenseMap how to use PointerUnions as keys.
+template <typename ...PTs> struct DenseMapInfo<PointerUnion<PTs...>> {
+  using Union = PointerUnion<PTs...>;
+  using FirstInfo =
+      DenseMapInfo<typename pointer_union_detail::GetFirstType<PTs...>::type>;
+
+  static inline Union getEmptyKey() { return Union(FirstInfo::getEmptyKey()); }
+
+  static inline Union getTombstoneKey() {
+    return Union(FirstInfo::getTombstoneKey());
+  }
+
+  static unsigned getHashValue(const Union &UnionVal) {
+    intptr_t key = (intptr_t)UnionVal.getOpaqueValue();
+    return DenseMapInfo<intptr_t>::getHashValue(key);
+  }
+
+  static bool isEqual(const Union &LHS, const Union &RHS) {
+    return LHS == RHS;
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_POINTERUNION_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/STLExtras.h b/binaryen/third_party/llvm-project/include/llvm/ADT/STLExtras.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/STLExtras.h
@@ -0,0 +1,1578 @@
+//===- llvm/ADT/STLExtras.h - Useful STL related functions ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains some templates that are useful if you are working with the
+// STL at all.
+//
+// No library is required when using these functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_STLEXTRAS_H
+#define LLVM_ADT_STLEXTRAS_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Config/abi-breaking.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <functional>
+#include <initializer_list>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#ifdef EXPENSIVE_CHECKS
+#include <random> // for std::mt19937
+#endif
+
+namespace llvm {
+
+// Only used by compiler if both template types are the same.  Useful when
+// using SFINAE to test for the existence of member functions.
+template <typename T, T> struct SameType;
+
+namespace detail {
+
+template <typename RangeT>
+using IterOfRange = decltype(std::begin(std::declval<RangeT &>()));
+
+template <typename RangeT>
+using ValueOfRange = typename std::remove_reference<decltype(
+    *std::begin(std::declval<RangeT &>()))>::type;
+
+} // end namespace detail
+
+//===----------------------------------------------------------------------===//
+//     Extra additions to <type_traits>
+//===----------------------------------------------------------------------===//
+
+template <typename T>
+struct negation : std::integral_constant<bool, !bool(T::value)> {};
+
+template <typename...> struct conjunction : std::true_type {};
+template <typename B1> struct conjunction<B1> : B1 {};
+template <typename B1, typename... Bn>
+struct conjunction<B1, Bn...>
+    : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
+
+template <typename T> struct make_const_ptr {
+  using type =
+      typename std::add_pointer<typename std::add_const<T>::type>::type;
+};
+
+template <typename T> struct make_const_ref {
+  using type = typename std::add_lvalue_reference<
+      typename std::add_const<T>::type>::type;
+};
+
+//===----------------------------------------------------------------------===//
+//     Extra additions to <functional>
+//===----------------------------------------------------------------------===//
+
+template <class Ty> struct identity {
+  using argument_type = Ty;
+
+  Ty &operator()(Ty &self) const {
+    return self;
+  }
+  const Ty &operator()(const Ty &self) const {
+    return self;
+  }
+};
+
+/// An efficient, type-erasing, non-owning reference to a callable. This is
+/// intended for use as the type of a function parameter that is not used
+/// after the function in question returns.
+///
+/// This class does not own the callable, so it is not in general safe to store
+/// a function_ref.
+template<typename Fn> class function_ref;
+
+template<typename Ret, typename ...Params>
+class function_ref<Ret(Params...)> {
+  Ret (*callback)(intptr_t callable, Params ...params) = nullptr;
+  intptr_t callable;
+
+  template<typename Callable>
+  static Ret callback_fn(intptr_t callable, Params ...params) {
+    return (*reinterpret_cast<Callable*>(callable))(
+        std::forward<Params>(params)...);
+  }
+
+public:
+  function_ref() = default;
+  function_ref(std::nullptr_t) {}
+
+  template <typename Callable>
+  function_ref(Callable &&callable,
+               typename std::enable_if<
+                   !std::is_same<typename std::remove_reference<Callable>::type,
+                                 function_ref>::value>::type * = nullptr)
+      : callback(callback_fn<typename std::remove_reference<Callable>::type>),
+        callable(reinterpret_cast<intptr_t>(&callable)) {}
+
+  Ret operator()(Params ...params) const {
+    return callback(callable, std::forward<Params>(params)...);
+  }
+
+  operator bool() const { return callback; }
+};
+
+// deleter - Very very very simple method that is used to invoke operator
+// delete on something.  It is used like this:
+//
+//   for_each(V.begin(), B.end(), deleter<Interval>);
+template <class T>
+inline void deleter(T *Ptr) {
+  delete Ptr;
+}
+
+//===----------------------------------------------------------------------===//
+//     Extra additions to <iterator>
+//===----------------------------------------------------------------------===//
+
+namespace adl_detail {
+
+using std::begin;
+
+template <typename ContainerTy>
+auto adl_begin(ContainerTy &&container)
+    -> decltype(begin(std::forward<ContainerTy>(container))) {
+  return begin(std::forward<ContainerTy>(container));
+}
+
+using std::end;
+
+template <typename ContainerTy>
+auto adl_end(ContainerTy &&container)
+    -> decltype(end(std::forward<ContainerTy>(container))) {
+  return end(std::forward<ContainerTy>(container));
+}
+
+using std::swap;
+
+template <typename T>
+void adl_swap(T &&lhs, T &&rhs) noexcept(noexcept(swap(std::declval<T>(),
+                                                       std::declval<T>()))) {
+  swap(std::forward<T>(lhs), std::forward<T>(rhs));
+}
+
+} // end namespace adl_detail
+
+template <typename ContainerTy>
+auto adl_begin(ContainerTy &&container)
+    -> decltype(adl_detail::adl_begin(std::forward<ContainerTy>(container))) {
+  return adl_detail::adl_begin(std::forward<ContainerTy>(container));
+}
+
+template <typename ContainerTy>
+auto adl_end(ContainerTy &&container)
+    -> decltype(adl_detail::adl_end(std::forward<ContainerTy>(container))) {
+  return adl_detail::adl_end(std::forward<ContainerTy>(container));
+}
+
+template <typename T>
+void adl_swap(T &&lhs, T &&rhs) noexcept(
+    noexcept(adl_detail::adl_swap(std::declval<T>(), std::declval<T>()))) {
+  adl_detail::adl_swap(std::forward<T>(lhs), std::forward<T>(rhs));
+}
+
+/// Test whether \p RangeOrContainer is empty. Similar to C++17 std::empty.
+template <typename T>
+constexpr bool empty(const T &RangeOrContainer) {
+  return adl_begin(RangeOrContainer) == adl_end(RangeOrContainer);
+}
+
+// mapped_iterator - This is a simple iterator adapter that causes a function to
+// be applied whenever operator* is invoked on the iterator.
+
+template <typename ItTy, typename FuncTy,
+          typename FuncReturnTy =
+            decltype(std::declval<FuncTy>()(*std::declval<ItTy>()))>
+class mapped_iterator
+    : public iterator_adaptor_base<
+             mapped_iterator<ItTy, FuncTy>, ItTy,
+             typename std::iterator_traits<ItTy>::iterator_category,
+             typename std::remove_reference<FuncReturnTy>::type> {
+public:
+  mapped_iterator(ItTy U, FuncTy F)
+    : mapped_iterator::iterator_adaptor_base(std::move(U)), F(std::move(F)) {}
+
+  ItTy getCurrent() { return this->I; }
+
+  FuncReturnTy operator*() { return F(*this->I); }
+
+private:
+  FuncTy F;
+};
+
+// map_iterator - Provide a convenient way to create mapped_iterators, just like
+// make_pair is useful for creating pairs...
+template <class ItTy, class FuncTy>
+inline mapped_iterator<ItTy, FuncTy> map_iterator(ItTy I, FuncTy F) {
+  return mapped_iterator<ItTy, FuncTy>(std::move(I), std::move(F));
+}
+
+template <class ContainerTy, class FuncTy>
+auto map_range(ContainerTy &&C, FuncTy F)
+    -> decltype(make_range(map_iterator(C.begin(), F),
+                           map_iterator(C.end(), F))) {
+  return make_range(map_iterator(C.begin(), F), map_iterator(C.end(), F));
+}
+
+/// Helper to determine if type T has a member called rbegin().
+template <typename Ty> class has_rbegin_impl {
+  using yes = char[1];
+  using no = char[2];
+
+  template <typename Inner>
+  static yes& test(Inner *I, decltype(I->rbegin()) * = nullptr);
+
+  template <typename>
+  static no& test(...);
+
+public:
+  static const bool value = sizeof(test<Ty>(nullptr)) == sizeof(yes);
+};
+
+/// Metafunction to determine if T& or T has a member called rbegin().
+template <typename Ty>
+struct has_rbegin : has_rbegin_impl<typename std::remove_reference<Ty>::type> {
+};
+
+// Returns an iterator_range over the given container which iterates in reverse.
+// Note that the container must have rbegin()/rend() methods for this to work.
+template <typename ContainerTy>
+auto reverse(ContainerTy &&C,
+             typename std::enable_if<has_rbegin<ContainerTy>::value>::type * =
+                 nullptr) -> decltype(make_range(C.rbegin(), C.rend())) {
+  return make_range(C.rbegin(), C.rend());
+}
+
+// Returns a std::reverse_iterator wrapped around the given iterator.
+template <typename IteratorTy>
+std::reverse_iterator<IteratorTy> make_reverse_iterator(IteratorTy It) {
+  return std::reverse_iterator<IteratorTy>(It);
+}
+
+// Returns an iterator_range over the given container which iterates in reverse.
+// Note that the container must have begin()/end() methods which return
+// bidirectional iterators for this to work.
+template <typename ContainerTy>
+auto reverse(
+    ContainerTy &&C,
+    typename std::enable_if<!has_rbegin<ContainerTy>::value>::type * = nullptr)
+    -> decltype(make_range(llvm::make_reverse_iterator(std::end(C)),
+                           llvm::make_reverse_iterator(std::begin(C)))) {
+  return make_range(llvm::make_reverse_iterator(std::end(C)),
+                    llvm::make_reverse_iterator(std::begin(C)));
+}
+
+/// An iterator adaptor that filters the elements of given inner iterators.
+///
+/// The predicate parameter should be a callable object that accepts the wrapped
+/// iterator's reference type and returns a bool. When incrementing or
+/// decrementing the iterator, it will call the predicate on each element and
+/// skip any where it returns false.
+///
+/// \code
+///   int A[] = { 1, 2, 3, 4 };
+///   auto R = make_filter_range(A, [](int N) { return N % 2 == 1; });
+///   // R contains { 1, 3 }.
+/// \endcode
+///
+/// Note: filter_iterator_base implements support for forward iteration.
+/// filter_iterator_impl exists to provide support for bidirectional iteration,
+/// conditional on whether the wrapped iterator supports it.
+template <typename WrappedIteratorT, typename PredicateT, typename IterTag>
+class filter_iterator_base
+    : public iterator_adaptor_base<
+          filter_iterator_base<WrappedIteratorT, PredicateT, IterTag>,
+          WrappedIteratorT,
+          typename std::common_type<
+              IterTag, typename std::iterator_traits<
+                           WrappedIteratorT>::iterator_category>::type> {
+  using BaseT = iterator_adaptor_base<
+      filter_iterator_base<WrappedIteratorT, PredicateT, IterTag>,
+      WrappedIteratorT,
+      typename std::common_type<
+          IterTag, typename std::iterator_traits<
+                       WrappedIteratorT>::iterator_category>::type>;
+
+protected:
+  WrappedIteratorT End;
+  PredicateT Pred;
+
+  void findNextValid() {
+    while (this->I != End && !Pred(*this->I))
+      BaseT::operator++();
+  }
+
+  // Construct the iterator. The begin iterator needs to know where the end
+  // is, so that it can properly stop when it gets there. The end iterator only
+  // needs the predicate to support bidirectional iteration.
+  filter_iterator_base(WrappedIteratorT Begin, WrappedIteratorT End,
+                       PredicateT Pred)
+      : BaseT(Begin), End(End), Pred(Pred) {
+    findNextValid();
+  }
+
+public:
+  using BaseT::operator++;
+
+  filter_iterator_base &operator++() {
+    BaseT::operator++();
+    findNextValid();
+    return *this;
+  }
+};
+
+/// Specialization of filter_iterator_base for forward iteration only.
+template <typename WrappedIteratorT, typename PredicateT,
+          typename IterTag = std::forward_iterator_tag>
+class filter_iterator_impl
+    : public filter_iterator_base<WrappedIteratorT, PredicateT, IterTag> {
+  using BaseT = filter_iterator_base<WrappedIteratorT, PredicateT, IterTag>;
+
+public:
+  filter_iterator_impl(WrappedIteratorT Begin, WrappedIteratorT End,
+                       PredicateT Pred)
+      : BaseT(Begin, End, Pred) {}
+};
+
+/// Specialization of filter_iterator_base for bidirectional iteration.
+template <typename WrappedIteratorT, typename PredicateT>
+class filter_iterator_impl<WrappedIteratorT, PredicateT,
+                           std::bidirectional_iterator_tag>
+    : public filter_iterator_base<WrappedIteratorT, PredicateT,
+                                  std::bidirectional_iterator_tag> {
+  using BaseT = filter_iterator_base<WrappedIteratorT, PredicateT,
+                                     std::bidirectional_iterator_tag>;
+  void findPrevValid() {
+    while (!this->Pred(*this->I))
+      BaseT::operator--();
+  }
+
+public:
+  using BaseT::operator--;
+
+  filter_iterator_impl(WrappedIteratorT Begin, WrappedIteratorT End,
+                       PredicateT Pred)
+      : BaseT(Begin, End, Pred) {}
+
+  filter_iterator_impl &operator--() {
+    BaseT::operator--();
+    findPrevValid();
+    return *this;
+  }
+};
+
+namespace detail {
+
+template <bool is_bidirectional> struct fwd_or_bidi_tag_impl {
+  using type = std::forward_iterator_tag;
+};
+
+template <> struct fwd_or_bidi_tag_impl<true> {
+  using type = std::bidirectional_iterator_tag;
+};
+
+/// Helper which sets its type member to forward_iterator_tag if the category
+/// of \p IterT does not derive from bidirectional_iterator_tag, and to
+/// bidirectional_iterator_tag otherwise.
+template <typename IterT> struct fwd_or_bidi_tag {
+  using type = typename fwd_or_bidi_tag_impl<std::is_base_of<
+      std::bidirectional_iterator_tag,
+      typename std::iterator_traits<IterT>::iterator_category>::value>::type;
+};
+
+} // namespace detail
+
+/// Defines filter_iterator to a suitable specialization of
+/// filter_iterator_impl, based on the underlying iterator's category.
+template <typename WrappedIteratorT, typename PredicateT>
+using filter_iterator = filter_iterator_impl<
+    WrappedIteratorT, PredicateT,
+    typename detail::fwd_or_bidi_tag<WrappedIteratorT>::type>;
+
+/// Convenience function that takes a range of elements and a predicate,
+/// and return a new filter_iterator range.
+///
+/// FIXME: Currently if RangeT && is a rvalue reference to a temporary, the
+/// lifetime of that temporary is not kept by the returned range object, and the
+/// temporary is going to be dropped on the floor after the make_iterator_range
+/// full expression that contains this function call.
+template <typename RangeT, typename PredicateT>
+iterator_range<filter_iterator<detail::IterOfRange<RangeT>, PredicateT>>
+make_filter_range(RangeT &&Range, PredicateT Pred) {
+  using FilterIteratorT =
+      filter_iterator<detail::IterOfRange<RangeT>, PredicateT>;
+  return make_range(
+      FilterIteratorT(std::begin(std::forward<RangeT>(Range)),
+                      std::end(std::forward<RangeT>(Range)), Pred),
+      FilterIteratorT(std::end(std::forward<RangeT>(Range)),
+                      std::end(std::forward<RangeT>(Range)), Pred));
+}
+
+/// A pseudo-iterator adaptor that is designed to implement "early increment"
+/// style loops.
+///
+/// This is *not a normal iterator* and should almost never be used directly. It
+/// is intended primarily to be used with range based for loops and some range
+/// algorithms.
+///
+/// The iterator isn't quite an `OutputIterator` or an `InputIterator` but
+/// somewhere between them. The constraints of these iterators are:
+///
+/// - On construction or after being incremented, it is comparable and
+///   dereferencable. It is *not* incrementable.
+/// - After being dereferenced, it is neither comparable nor dereferencable, it
+///   is only incrementable.
+///
+/// This means you can only dereference the iterator once, and you can only
+/// increment it once between dereferences.
+template <typename WrappedIteratorT>
+class early_inc_iterator_impl
+    : public iterator_adaptor_base<early_inc_iterator_impl<WrappedIteratorT>,
+                                   WrappedIteratorT, std::input_iterator_tag> {
+  using BaseT =
+      iterator_adaptor_base<early_inc_iterator_impl<WrappedIteratorT>,
+                            WrappedIteratorT, std::input_iterator_tag>;
+
+  using PointerT = typename std::iterator_traits<WrappedIteratorT>::pointer;
+
+protected:
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+  bool IsEarlyIncremented = false;
+#endif
+
+public:
+  early_inc_iterator_impl(WrappedIteratorT I) : BaseT(I) {}
+
+  using BaseT::operator*;
+  typename BaseT::reference operator*() {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+    assert(!IsEarlyIncremented && "Cannot dereference twice!");
+    IsEarlyIncremented = true;
+#endif
+    return *(this->I)++;
+  }
+
+  using BaseT::operator++;
+  early_inc_iterator_impl &operator++() {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+    assert(IsEarlyIncremented && "Cannot increment before dereferencing!");
+    IsEarlyIncremented = false;
+#endif
+    return *this;
+  }
+
+  using BaseT::operator==;
+  bool operator==(const early_inc_iterator_impl &RHS) const {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+    assert(!IsEarlyIncremented && "Cannot compare after dereferencing!");
+#endif
+    return BaseT::operator==(RHS);
+  }
+};
+
+/// Make a range that does early increment to allow mutation of the underlying
+/// range without disrupting iteration.
+///
+/// The underlying iterator will be incremented immediately after it is
+/// dereferenced, allowing deletion of the current node or insertion of nodes to
+/// not disrupt iteration provided they do not invalidate the *next* iterator --
+/// the current iterator can be invalidated.
+///
+/// This requires a very exact pattern of use that is only really suitable to
+/// range based for loops and other range algorithms that explicitly guarantee
+/// to dereference exactly once each element, and to increment exactly once each
+/// element.
+template <typename RangeT>
+iterator_range<early_inc_iterator_impl<detail::IterOfRange<RangeT>>>
+make_early_inc_range(RangeT &&Range) {
+  using EarlyIncIteratorT =
+      early_inc_iterator_impl<detail::IterOfRange<RangeT>>;
+  return make_range(EarlyIncIteratorT(std::begin(std::forward<RangeT>(Range))),
+                    EarlyIncIteratorT(std::end(std::forward<RangeT>(Range))));
+}
+
+// forward declarations required by zip_shortest/zip_first/zip_longest
+template <typename R, typename UnaryPredicate>
+bool all_of(R &&range, UnaryPredicate P);
+template <typename R, typename UnaryPredicate>
+bool any_of(R &&range, UnaryPredicate P);
+
+namespace detail {
+
+using std::declval;
+
+// We have to alias this since inlining the actual type at the usage site
+// in the parameter list of iterator_facade_base<> below ICEs MSVC 2017.
+template<typename... Iters> struct ZipTupleType {
+  using type = std::tuple<decltype(*declval<Iters>())...>;
+};
+
+template <typename ZipType, typename... Iters>
+using zip_traits = iterator_facade_base<
+    ZipType, typename std::common_type<std::bidirectional_iterator_tag,
+                                       typename std::iterator_traits<
+                                           Iters>::iterator_category...>::type,
+    // ^ TODO: Implement random access methods.
+    typename ZipTupleType<Iters...>::type,
+    typename std::iterator_traits<typename std::tuple_element<
+        0, std::tuple<Iters...>>::type>::difference_type,
+    // ^ FIXME: This follows boost::make_zip_iterator's assumption that all
+    // inner iterators have the same difference_type. It would fail if, for
+    // instance, the second field's difference_type were non-numeric while the
+    // first is.
+    typename ZipTupleType<Iters...>::type *,
+    typename ZipTupleType<Iters...>::type>;
+
+template <typename ZipType, typename... Iters>
+struct zip_common : public zip_traits<ZipType, Iters...> {
+  using Base = zip_traits<ZipType, Iters...>;
+  using value_type = typename Base::value_type;
+
+  std::tuple<Iters...> iterators;
+
+protected:
+  template <size_t... Ns> value_type deref(std::index_sequence<Ns...>) const {
+    return value_type(*std::get<Ns>(iterators)...);
+  }
+
+  template <size_t... Ns>
+  decltype(iterators) tup_inc(std::index_sequence<Ns...>) const {
+    return std::tuple<Iters...>(std::next(std::get<Ns>(iterators))...);
+  }
+
+  template <size_t... Ns>
+  decltype(iterators) tup_dec(std::index_sequence<Ns...>) const {
+    return std::tuple<Iters...>(std::prev(std::get<Ns>(iterators))...);
+  }
+
+public:
+  zip_common(Iters &&... ts) : iterators(std::forward<Iters>(ts)...) {}
+
+  value_type operator*() { return deref(std::index_sequence_for<Iters...>{}); }
+
+  const value_type operator*() const {
+    return deref(std::index_sequence_for<Iters...>{});
+  }
+
+  ZipType &operator++() {
+    iterators = tup_inc(std::index_sequence_for<Iters...>{});
+    return *reinterpret_cast<ZipType *>(this);
+  }
+
+  ZipType &operator--() {
+    static_assert(Base::IsBidirectional,
+                  "All inner iterators must be at least bidirectional.");
+    iterators = tup_dec(std::index_sequence_for<Iters...>{});
+    return *reinterpret_cast<ZipType *>(this);
+  }
+};
+
+template <typename... Iters>
+struct zip_first : public zip_common<zip_first<Iters...>, Iters...> {
+  using Base = zip_common<zip_first<Iters...>, Iters...>;
+
+  bool operator==(const zip_first<Iters...> &other) const {
+    return std::get<0>(this->iterators) == std::get<0>(other.iterators);
+  }
+
+  zip_first(Iters &&... ts) : Base(std::forward<Iters>(ts)...) {}
+};
+
+template <typename... Iters>
+class zip_shortest : public zip_common<zip_shortest<Iters...>, Iters...> {
+  template <size_t... Ns>
+  bool test(const zip_shortest<Iters...> &other,
+            std::index_sequence<Ns...>) const {
+    return all_of(std::initializer_list<bool>{std::get<Ns>(this->iterators) !=
+                                              std::get<Ns>(other.iterators)...},
+                  identity<bool>{});
+  }
+
+public:
+  using Base = zip_common<zip_shortest<Iters...>, Iters...>;
+
+  zip_shortest(Iters &&... ts) : Base(std::forward<Iters>(ts)...) {}
+
+  bool operator==(const zip_shortest<Iters...> &other) const {
+    return !test(other, std::index_sequence_for<Iters...>{});
+  }
+};
+
+template <template <typename...> class ItType, typename... Args> class zippy {
+public:
+  using iterator = ItType<decltype(std::begin(std::declval<Args>()))...>;
+  using iterator_category = typename iterator::iterator_category;
+  using value_type = typename iterator::value_type;
+  using difference_type = typename iterator::difference_type;
+  using pointer = typename iterator::pointer;
+  using reference = typename iterator::reference;
+
+private:
+  std::tuple<Args...> ts;
+
+  template <size_t... Ns>
+  iterator begin_impl(std::index_sequence<Ns...>) const {
+    return iterator(std::begin(std::get<Ns>(ts))...);
+  }
+  template <size_t... Ns> iterator end_impl(std::index_sequence<Ns...>) const {
+    return iterator(std::end(std::get<Ns>(ts))...);
+  }
+
+public:
+  zippy(Args &&... ts_) : ts(std::forward<Args>(ts_)...) {}
+
+  iterator begin() const {
+    return begin_impl(std::index_sequence_for<Args...>{});
+  }
+  iterator end() const { return end_impl(std::index_sequence_for<Args...>{}); }
+};
+
+} // end namespace detail
+
+/// zip iterator for two or more iteratable types.
+template <typename T, typename U, typename... Args>
+detail::zippy<detail::zip_shortest, T, U, Args...> zip(T &&t, U &&u,
+                                                       Args &&... args) {
+  return detail::zippy<detail::zip_shortest, T, U, Args...>(
+      std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...);
+}
+
+/// zip iterator that, for the sake of efficiency, assumes the first iteratee to
+/// be the shortest.
+template <typename T, typename U, typename... Args>
+detail::zippy<detail::zip_first, T, U, Args...> zip_first(T &&t, U &&u,
+                                                          Args &&... args) {
+  return detail::zippy<detail::zip_first, T, U, Args...>(
+      std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...);
+}
+
+namespace detail {
+template <typename Iter>
+static Iter next_or_end(const Iter &I, const Iter &End) {
+  if (I == End)
+    return End;
+  return std::next(I);
+}
+
+template <typename Iter>
+static auto deref_or_none(const Iter &I, const Iter &End)
+    -> llvm::Optional<typename std::remove_const<
+        typename std::remove_reference<decltype(*I)>::type>::type> {
+  if (I == End)
+    return None;
+  return *I;
+}
+
+template <typename Iter> struct ZipLongestItemType {
+  using type =
+      llvm::Optional<typename std::remove_const<typename std::remove_reference<
+          decltype(*std::declval<Iter>())>::type>::type>;
+};
+
+template <typename... Iters> struct ZipLongestTupleType {
+  using type = std::tuple<typename ZipLongestItemType<Iters>::type...>;
+};
+
+template <typename... Iters>
+class zip_longest_iterator
+    : public iterator_facade_base<
+          zip_longest_iterator<Iters...>,
+          typename std::common_type<
+              std::forward_iterator_tag,
+              typename std::iterator_traits<Iters>::iterator_category...>::type,
+          typename ZipLongestTupleType<Iters...>::type,
+          typename std::iterator_traits<typename std::tuple_element<
+              0, std::tuple<Iters...>>::type>::difference_type,
+          typename ZipLongestTupleType<Iters...>::type *,
+          typename ZipLongestTupleType<Iters...>::type> {
+public:
+  using value_type = typename ZipLongestTupleType<Iters...>::type;
+
+private:
+  std::tuple<Iters...> iterators;
+  std::tuple<Iters...> end_iterators;
+
+  template <size_t... Ns>
+  bool test(const zip_longest_iterator<Iters...> &other,
+            std::index_sequence<Ns...>) const {
+    return llvm::any_of(
+        std::initializer_list<bool>{std::get<Ns>(this->iterators) !=
+                                    std::get<Ns>(other.iterators)...},
+        identity<bool>{});
+  }
+
+  template <size_t... Ns> value_type deref(std::index_sequence<Ns...>) const {
+    return value_type(
+        deref_or_none(std::get<Ns>(iterators), std::get<Ns>(end_iterators))...);
+  }
+
+  template <size_t... Ns>
+  decltype(iterators) tup_inc(std::index_sequence<Ns...>) const {
+    return std::tuple<Iters...>(
+        next_or_end(std::get<Ns>(iterators), std::get<Ns>(end_iterators))...);
+  }
+
+public:
+  zip_longest_iterator(std::pair<Iters &&, Iters &&>... ts)
+      : iterators(std::forward<Iters>(ts.first)...),
+        end_iterators(std::forward<Iters>(ts.second)...) {}
+
+  value_type operator*() { return deref(std::index_sequence_for<Iters...>{}); }
+
+  value_type operator*() const {
+    return deref(std::index_sequence_for<Iters...>{});
+  }
+
+  zip_longest_iterator<Iters...> &operator++() {
+    iterators = tup_inc(std::index_sequence_for<Iters...>{});
+    return *this;
+  }
+
+  bool operator==(const zip_longest_iterator<Iters...> &other) const {
+    return !test(other, std::index_sequence_for<Iters...>{});
+  }
+};
+
+template <typename... Args> class zip_longest_range {
+public:
+  using iterator =
+      zip_longest_iterator<decltype(adl_begin(std::declval<Args>()))...>;
+  using iterator_category = typename iterator::iterator_category;
+  using value_type = typename iterator::value_type;
+  using difference_type = typename iterator::difference_type;
+  using pointer = typename iterator::pointer;
+  using reference = typename iterator::reference;
+
+private:
+  std::tuple<Args...> ts;
+
+  template <size_t... Ns>
+  iterator begin_impl(std::index_sequence<Ns...>) const {
+    return iterator(std::make_pair(adl_begin(std::get<Ns>(ts)),
+                                   adl_end(std::get<Ns>(ts)))...);
+  }
+
+  template <size_t... Ns> iterator end_impl(std::index_sequence<Ns...>) const {
+    return iterator(std::make_pair(adl_end(std::get<Ns>(ts)),
+                                   adl_end(std::get<Ns>(ts)))...);
+  }
+
+public:
+  zip_longest_range(Args &&... ts_) : ts(std::forward<Args>(ts_)...) {}
+
+  iterator begin() const {
+    return begin_impl(std::index_sequence_for<Args...>{});
+  }
+  iterator end() const { return end_impl(std::index_sequence_for<Args...>{}); }
+};
+} // namespace detail
+
+/// Iterate over two or more iterators at the same time. Iteration continues
+/// until all iterators reach the end. The llvm::Optional only contains a value
+/// if the iterator has not reached the end.
+template <typename T, typename U, typename... Args>
+detail::zip_longest_range<T, U, Args...> zip_longest(T &&t, U &&u,
+                                                     Args &&... args) {
+  return detail::zip_longest_range<T, U, Args...>(
+      std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...);
+}
+
+/// Iterator wrapper that concatenates sequences together.
+///
+/// This can concatenate different iterators, even with different types, into
+/// a single iterator provided the value types of all the concatenated
+/// iterators expose `reference` and `pointer` types that can be converted to
+/// `ValueT &` and `ValueT *` respectively. It doesn't support more
+/// interesting/customized pointer or reference types.
+///
+/// Currently this only supports forward or higher iterator categories as
+/// inputs and always exposes a forward iterator interface.
+template <typename ValueT, typename... IterTs>
+class concat_iterator
+    : public iterator_facade_base<concat_iterator<ValueT, IterTs...>,
+                                  std::forward_iterator_tag, ValueT> {
+  using BaseT = typename concat_iterator::iterator_facade_base;
+
+  /// We store both the current and end iterators for each concatenated
+  /// sequence in a tuple of pairs.
+  ///
+  /// Note that something like iterator_range seems nice at first here, but the
+  /// range properties are of little benefit and end up getting in the way
+  /// because we need to do mutation on the current iterators.
+  std::tuple<IterTs...> Begins;
+  std::tuple<IterTs...> Ends;
+
+  /// Attempts to increment a specific iterator.
+  ///
+  /// Returns true if it was able to increment the iterator. Returns false if
+  /// the iterator is already at the end iterator.
+  template <size_t Index> bool incrementHelper() {
+    auto &Begin = std::get<Index>(Begins);
+    auto &End = std::get<Index>(Ends);
+    if (Begin == End)
+      return false;
+
+    ++Begin;
+    return true;
+  }
+
+  /// Increments the first non-end iterator.
+  ///
+  /// It is an error to call this with all iterators at the end.
+  template <size_t... Ns> void increment(std::index_sequence<Ns...>) {
+    // Build a sequence of functions to increment each iterator if possible.
+    bool (concat_iterator::*IncrementHelperFns[])() = {
+        &concat_iterator::incrementHelper<Ns>...};
+
+    // Loop over them, and stop as soon as we succeed at incrementing one.
+    for (auto &IncrementHelperFn : IncrementHelperFns)
+      if ((this->*IncrementHelperFn)())
+        return;
+
+    llvm_unreachable("Attempted to increment an end concat iterator!");
+  }
+
+  /// Returns null if the specified iterator is at the end. Otherwise,
+  /// dereferences the iterator and returns the address of the resulting
+  /// reference.
+  template <size_t Index> ValueT *getHelper() const {
+    auto &Begin = std::get<Index>(Begins);
+    auto &End = std::get<Index>(Ends);
+    if (Begin == End)
+      return nullptr;
+
+    return &*Begin;
+  }
+
+  /// Finds the first non-end iterator, dereferences, and returns the resulting
+  /// reference.
+  ///
+  /// It is an error to call this with all iterators at the end.
+  template <size_t... Ns> ValueT &get(std::index_sequence<Ns...>) const {
+    // Build a sequence of functions to get from iterator if possible.
+    ValueT *(concat_iterator::*GetHelperFns[])() const = {
+        &concat_iterator::getHelper<Ns>...};
+
+    // Loop over them, and return the first result we find.
+    for (auto &GetHelperFn : GetHelperFns)
+      if (ValueT *P = (this->*GetHelperFn)())
+        return *P;
+
+    llvm_unreachable("Attempted to get a pointer from an end concat iterator!");
+  }
+
+public:
+  /// Constructs an iterator from a squence of ranges.
+  ///
+  /// We need the full range to know how to switch between each of the
+  /// iterators.
+  template <typename... RangeTs>
+  explicit concat_iterator(RangeTs &&... Ranges)
+      : Begins(std::begin(Ranges)...), Ends(std::end(Ranges)...) {}
+
+  using BaseT::operator++;
+
+  concat_iterator &operator++() {
+    increment(std::index_sequence_for<IterTs...>());
+    return *this;
+  }
+
+  ValueT &operator*() const {
+    return get(std::index_sequence_for<IterTs...>());
+  }
+
+  bool operator==(const concat_iterator &RHS) const {
+    return Begins == RHS.Begins && Ends == RHS.Ends;
+  }
+};
+
+namespace detail {
+
+/// Helper to store a sequence of ranges being concatenated and access them.
+///
+/// This is designed to facilitate providing actual storage when temporaries
+/// are passed into the constructor such that we can use it as part of range
+/// based for loops.
+template <typename ValueT, typename... RangeTs> class concat_range {
+public:
+  using iterator =
+      concat_iterator<ValueT,
+                      decltype(std::begin(std::declval<RangeTs &>()))...>;
+
+private:
+  std::tuple<RangeTs...> Ranges;
+
+  template <size_t... Ns> iterator begin_impl(std::index_sequence<Ns...>) {
+    return iterator(std::get<Ns>(Ranges)...);
+  }
+  template <size_t... Ns> iterator end_impl(std::index_sequence<Ns...>) {
+    return iterator(make_range(std::end(std::get<Ns>(Ranges)),
+                               std::end(std::get<Ns>(Ranges)))...);
+  }
+
+public:
+  concat_range(RangeTs &&... Ranges)
+      : Ranges(std::forward<RangeTs>(Ranges)...) {}
+
+  iterator begin() { return begin_impl(std::index_sequence_for<RangeTs...>{}); }
+  iterator end() { return end_impl(std::index_sequence_for<RangeTs...>{}); }
+};
+
+} // end namespace detail
+
+/// Concatenated range across two or more ranges.
+///
+/// The desired value type must be explicitly specified.
+template <typename ValueT, typename... RangeTs>
+detail::concat_range<ValueT, RangeTs...> concat(RangeTs &&... Ranges) {
+  static_assert(sizeof...(RangeTs) > 1,
+                "Need more than one range to concatenate!");
+  return detail::concat_range<ValueT, RangeTs...>(
+      std::forward<RangeTs>(Ranges)...);
+}
+
+//===----------------------------------------------------------------------===//
+//     Extra additions to <utility>
+//===----------------------------------------------------------------------===//
+
+/// Function object to check whether the first component of a std::pair
+/// compares less than the first component of another std::pair.
+struct less_first {
+  template <typename T> bool operator()(const T &lhs, const T &rhs) const {
+    return lhs.first < rhs.first;
+  }
+};
+
+/// Function object to check whether the second component of a std::pair
+/// compares less than the second component of another std::pair.
+struct less_second {
+  template <typename T> bool operator()(const T &lhs, const T &rhs) const {
+    return lhs.second < rhs.second;
+  }
+};
+
+/// \brief Function object to apply a binary function to the first component of
+/// a std::pair.
+template<typename FuncTy>
+struct on_first {
+  FuncTy func;
+
+  template <typename T>
+  auto operator()(const T &lhs, const T &rhs) const
+      -> decltype(func(lhs.first, rhs.first)) {
+    return func(lhs.first, rhs.first);
+  }
+};
+
+/// Utility type to build an inheritance chain that makes it easy to rank
+/// overload candidates.
+template <int N> struct rank : rank<N - 1> {};
+template <> struct rank<0> {};
+
+/// traits class for checking whether type T is one of any of the given
+/// types in the variadic list.
+template <typename T, typename... Ts> struct is_one_of {
+  static const bool value = false;
+};
+
+template <typename T, typename U, typename... Ts>
+struct is_one_of<T, U, Ts...> {
+  static const bool value =
+      std::is_same<T, U>::value || is_one_of<T, Ts...>::value;
+};
+
+/// traits class for checking whether type T is a base class for all
+///  the given types in the variadic list.
+template <typename T, typename... Ts> struct are_base_of {
+  static const bool value = true;
+};
+
+template <typename T, typename U, typename... Ts>
+struct are_base_of<T, U, Ts...> {
+  static const bool value =
+      std::is_base_of<T, U>::value && are_base_of<T, Ts...>::value;
+};
+
+//===----------------------------------------------------------------------===//
+//     Extra additions for arrays
+//===----------------------------------------------------------------------===//
+
+/// Find the length of an array.
+template <class T, std::size_t N>
+constexpr inline size_t array_lengthof(T (&)[N]) {
+  return N;
+}
+
+/// Adapt std::less<T> for array_pod_sort.
+template<typename T>
+inline int array_pod_sort_comparator(const void *P1, const void *P2) {
+  if (std::less<T>()(*reinterpret_cast<const T*>(P1),
+                     *reinterpret_cast<const T*>(P2)))
+    return -1;
+  if (std::less<T>()(*reinterpret_cast<const T*>(P2),
+                     *reinterpret_cast<const T*>(P1)))
+    return 1;
+  return 0;
+}
+
+/// get_array_pod_sort_comparator - This is an internal helper function used to
+/// get type deduction of T right.
+template<typename T>
+inline int (*get_array_pod_sort_comparator(const T &))
+             (const void*, const void*) {
+  return array_pod_sort_comparator<T>;
+}
+
+/// array_pod_sort - This sorts an array with the specified start and end
+/// extent.  This is just like std::sort, except that it calls qsort instead of
+/// using an inlined template.  qsort is slightly slower than std::sort, but
+/// most sorts are not performance critical in LLVM and std::sort has to be
+/// template instantiated for each type, leading to significant measured code
+/// bloat.  This function should generally be used instead of std::sort where
+/// possible.
+///
+/// This function assumes that you have simple POD-like types that can be
+/// compared with std::less and can be moved with memcpy.  If this isn't true,
+/// you should use std::sort.
+///
+/// NOTE: If qsort_r were portable, we could allow a custom comparator and
+/// default to std::less.
+template<class IteratorTy>
+inline void array_pod_sort(IteratorTy Start, IteratorTy End) {
+  // Don't inefficiently call qsort with one element or trigger undefined
+  // behavior with an empty sequence.
+  auto NElts = End - Start;
+  if (NElts <= 1) return;
+#ifdef EXPENSIVE_CHECKS
+  std::mt19937 Generator(std::random_device{}());
+  std::shuffle(Start, End, Generator);
+#endif
+  qsort(&*Start, NElts, sizeof(*Start), get_array_pod_sort_comparator(*Start));
+}
+
+template <class IteratorTy>
+inline void array_pod_sort(
+    IteratorTy Start, IteratorTy End,
+    int (*Compare)(
+        const typename std::iterator_traits<IteratorTy>::value_type *,
+        const typename std::iterator_traits<IteratorTy>::value_type *)) {
+  // Don't inefficiently call qsort with one element or trigger undefined
+  // behavior with an empty sequence.
+  auto NElts = End - Start;
+  if (NElts <= 1) return;
+#ifdef EXPENSIVE_CHECKS
+  std::mt19937 Generator(std::random_device{}());
+  std::shuffle(Start, End, Generator);
+#endif
+  qsort(&*Start, NElts, sizeof(*Start),
+        reinterpret_cast<int (*)(const void *, const void *)>(Compare));
+}
+
+// Provide wrappers to std::sort which shuffle the elements before sorting
+// to help uncover non-deterministic behavior (PR35135).
+template <typename IteratorTy>
+inline void sort(IteratorTy Start, IteratorTy End) {
+#ifdef EXPENSIVE_CHECKS
+  std::mt19937 Generator(std::random_device{}());
+  std::shuffle(Start, End, Generator);
+#endif
+  std::sort(Start, End);
+}
+
+template <typename Container> inline void sort(Container &&C) {
+  llvm::sort(adl_begin(C), adl_end(C));
+}
+
+template <typename IteratorTy, typename Compare>
+inline void sort(IteratorTy Start, IteratorTy End, Compare Comp) {
+#ifdef EXPENSIVE_CHECKS
+  std::mt19937 Generator(std::random_device{}());
+  std::shuffle(Start, End, Generator);
+#endif
+  std::sort(Start, End, Comp);
+}
+
+template <typename Container, typename Compare>
+inline void sort(Container &&C, Compare Comp) {
+  llvm::sort(adl_begin(C), adl_end(C), Comp);
+}
+
+//===----------------------------------------------------------------------===//
+//     Extra additions to <algorithm>
+//===----------------------------------------------------------------------===//
+
+/// For a container of pointers, deletes the pointers and then clears the
+/// container.
+template<typename Container>
+void DeleteContainerPointers(Container &C) {
+  for (auto V : C)
+    delete V;
+  C.clear();
+}
+
+/// In a container of pairs (usually a map) whose second element is a pointer,
+/// deletes the second elements and then clears the container.
+template<typename Container>
+void DeleteContainerSeconds(Container &C) {
+  for (auto &V : C)
+    delete V.second;
+  C.clear();
+}
+
+/// Get the size of a range. This is a wrapper function around std::distance
+/// which is only enabled when the operation is O(1).
+template <typename R>
+auto size(R &&Range, typename std::enable_if<
+                         std::is_same<typename std::iterator_traits<decltype(
+                                          Range.begin())>::iterator_category,
+                                      std::random_access_iterator_tag>::value,
+                         void>::type * = nullptr)
+    -> decltype(std::distance(Range.begin(), Range.end())) {
+  return std::distance(Range.begin(), Range.end());
+}
+
+/// Provide wrappers to std::for_each which take ranges instead of having to
+/// pass begin/end explicitly.
+template <typename R, typename UnaryPredicate>
+UnaryPredicate for_each(R &&Range, UnaryPredicate P) {
+  return std::for_each(adl_begin(Range), adl_end(Range), P);
+}
+
+/// Provide wrappers to std::all_of which take ranges instead of having to pass
+/// begin/end explicitly.
+template <typename R, typename UnaryPredicate>
+bool all_of(R &&Range, UnaryPredicate P) {
+  return std::all_of(adl_begin(Range), adl_end(Range), P);
+}
+
+/// Provide wrappers to std::any_of which take ranges instead of having to pass
+/// begin/end explicitly.
+template <typename R, typename UnaryPredicate>
+bool any_of(R &&Range, UnaryPredicate P) {
+  return std::any_of(adl_begin(Range), adl_end(Range), P);
+}
+
+/// Provide wrappers to std::none_of which take ranges instead of having to pass
+/// begin/end explicitly.
+template <typename R, typename UnaryPredicate>
+bool none_of(R &&Range, UnaryPredicate P) {
+  return std::none_of(adl_begin(Range), adl_end(Range), P);
+}
+
+/// Provide wrappers to std::find which take ranges instead of having to pass
+/// begin/end explicitly.
+template <typename R, typename T>
+auto find(R &&Range, const T &Val) -> decltype(adl_begin(Range)) {
+  return std::find(adl_begin(Range), adl_end(Range), Val);
+}
+
+/// Provide wrappers to std::find_if which take ranges instead of having to pass
+/// begin/end explicitly.
+template <typename R, typename UnaryPredicate>
+auto find_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
+  return std::find_if(adl_begin(Range), adl_end(Range), P);
+}
+
+template <typename R, typename UnaryPredicate>
+auto find_if_not(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
+  return std::find_if_not(adl_begin(Range), adl_end(Range), P);
+}
+
+/// Provide wrappers to std::remove_if which take ranges instead of having to
+/// pass begin/end explicitly.
+template <typename R, typename UnaryPredicate>
+auto remove_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
+  return std::remove_if(adl_begin(Range), adl_end(Range), P);
+}
+
+/// Provide wrappers to std::copy_if which take ranges instead of having to
+/// pass begin/end explicitly.
+template <typename R, typename OutputIt, typename UnaryPredicate>
+OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate P) {
+  return std::copy_if(adl_begin(Range), adl_end(Range), Out, P);
+}
+
+template <typename R, typename OutputIt>
+OutputIt copy(R &&Range, OutputIt Out) {
+  return std::copy(adl_begin(Range), adl_end(Range), Out);
+}
+
+/// Wrapper function around std::find to detect if an element exists
+/// in a container.
+template <typename R, typename E>
+bool is_contained(R &&Range, const E &Element) {
+  return std::find(adl_begin(Range), adl_end(Range), Element) != adl_end(Range);
+}
+
+/// Wrapper function around std::count to count the number of times an element
+/// \p Element occurs in the given range \p Range.
+template <typename R, typename E>
+auto count(R &&Range, const E &Element) ->
+    typename std::iterator_traits<decltype(adl_begin(Range))>::difference_type {
+  return std::count(adl_begin(Range), adl_end(Range), Element);
+}
+
+/// Wrapper function around std::count_if to count the number of times an
+/// element satisfying a given predicate occurs in a range.
+template <typename R, typename UnaryPredicate>
+auto count_if(R &&Range, UnaryPredicate P) ->
+    typename std::iterator_traits<decltype(adl_begin(Range))>::difference_type {
+  return std::count_if(adl_begin(Range), adl_end(Range), P);
+}
+
+/// Wrapper function around std::transform to apply a function to a range and
+/// store the result elsewhere.
+template <typename R, typename OutputIt, typename UnaryPredicate>
+OutputIt transform(R &&Range, OutputIt d_first, UnaryPredicate P) {
+  return std::transform(adl_begin(Range), adl_end(Range), d_first, P);
+}
+
+/// Provide wrappers to std::partition which take ranges instead of having to
+/// pass begin/end explicitly.
+template <typename R, typename UnaryPredicate>
+auto partition(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
+  return std::partition(adl_begin(Range), adl_end(Range), P);
+}
+
+/// Provide wrappers to std::lower_bound which take ranges instead of having to
+/// pass begin/end explicitly.
+template <typename R, typename T>
+auto lower_bound(R &&Range, T &&Value) -> decltype(adl_begin(Range)) {
+  return std::lower_bound(adl_begin(Range), adl_end(Range),
+                          std::forward<T>(Value));
+}
+
+template <typename R, typename T, typename Compare>
+auto lower_bound(R &&Range, T &&Value, Compare C)
+    -> decltype(adl_begin(Range)) {
+  return std::lower_bound(adl_begin(Range), adl_end(Range),
+                          std::forward<T>(Value), C);
+}
+
+/// Provide wrappers to std::upper_bound which take ranges instead of having to
+/// pass begin/end explicitly.
+template <typename R, typename T>
+auto upper_bound(R &&Range, T &&Value) -> decltype(adl_begin(Range)) {
+  return std::upper_bound(adl_begin(Range), adl_end(Range),
+                          std::forward<T>(Value));
+}
+
+template <typename R, typename T, typename Compare>
+auto upper_bound(R &&Range, T &&Value, Compare C)
+    -> decltype(adl_begin(Range)) {
+  return std::upper_bound(adl_begin(Range), adl_end(Range),
+                          std::forward<T>(Value), C);
+}
+
+template <typename R>
+void stable_sort(R &&Range) {
+  std::stable_sort(adl_begin(Range), adl_end(Range));
+}
+
+template <typename R, typename Compare>
+void stable_sort(R &&Range, Compare C) {
+  std::stable_sort(adl_begin(Range), adl_end(Range), C);
+}
+
+/// Binary search for the first iterator in a range where a predicate is false.
+/// Requires that C is always true below some limit, and always false above it.
+template <typename R, typename Predicate,
+          typename Val = decltype(*adl_begin(std::declval<R>()))>
+auto partition_point(R &&Range, Predicate P) -> decltype(adl_begin(Range)) {
+  return std::partition_point(adl_begin(Range), adl_end(Range), P);
+}
+
+/// Wrapper function around std::equal to detect if all elements
+/// in a container are same.
+template <typename R>
+bool is_splat(R &&Range) {
+  size_t range_size = size(Range);
+  return range_size != 0 && (range_size == 1 ||
+         std::equal(adl_begin(Range) + 1, adl_end(Range), adl_begin(Range)));
+}
+
+/// Given a range of type R, iterate the entire range and return a
+/// SmallVector with elements of the vector.  This is useful, for example,
+/// when you want to iterate a range and then sort the results.
+template <unsigned Size, typename R>
+SmallVector<typename std::remove_const<detail::ValueOfRange<R>>::type, Size>
+to_vector(R &&Range) {
+  return {adl_begin(Range), adl_end(Range)};
+}
+
+/// Provide a container algorithm similar to C++ Library Fundamentals v2's
+/// `erase_if` which is equivalent to:
+///
+///   C.erase(remove_if(C, pred), C.end());
+///
+/// This version works for any container with an erase method call accepting
+/// two iterators.
+template <typename Container, typename UnaryPredicate>
+void erase_if(Container &C, UnaryPredicate P) {
+  C.erase(remove_if(C, P), C.end());
+}
+
+/// Given a sequence container Cont, replace the range [ContIt, ContEnd) with
+/// the range [ValIt, ValEnd) (which is not from the same container).
+template<typename Container, typename RandomAccessIterator>
+void replace(Container &Cont, typename Container::iterator ContIt,
+             typename Container::iterator ContEnd, RandomAccessIterator ValIt,
+             RandomAccessIterator ValEnd) {
+  while (true) {
+    if (ValIt == ValEnd) {
+      Cont.erase(ContIt, ContEnd);
+      return;
+    } else if (ContIt == ContEnd) {
+      Cont.insert(ContIt, ValIt, ValEnd);
+      return;
+    }
+    *ContIt++ = *ValIt++;
+  }
+}
+
+/// Given a sequence container Cont, replace the range [ContIt, ContEnd) with
+/// the range R.
+template<typename Container, typename Range = std::initializer_list<
+                                 typename Container::value_type>>
+void replace(Container &Cont, typename Container::iterator ContIt,
+             typename Container::iterator ContEnd, Range R) {
+  replace(Cont, ContIt, ContEnd, R.begin(), R.end());
+}
+
+//===----------------------------------------------------------------------===//
+//     Extra additions to <memory>
+//===----------------------------------------------------------------------===//
+
+struct FreeDeleter {
+  void operator()(void* v) {
+    ::free(v);
+  }
+};
+
+template<typename First, typename Second>
+struct pair_hash {
+  size_t operator()(const std::pair<First, Second> &P) const {
+    return std::hash<First>()(P.first) * 31 + std::hash<Second>()(P.second);
+  }
+};
+
+/// Binary functor that adapts to any other binary functor after dereferencing
+/// operands.
+template <typename T> struct deref {
+  T func;
+
+  // Could be further improved to cope with non-derivable functors and
+  // non-binary functors (should be a variadic template member function
+  // operator()).
+  template <typename A, typename B>
+  auto operator()(A &lhs, B &rhs) const -> decltype(func(*lhs, *rhs)) {
+    assert(lhs);
+    assert(rhs);
+    return func(*lhs, *rhs);
+  }
+};
+
+namespace detail {
+
+template <typename R> class enumerator_iter;
+
+template <typename R> struct result_pair {
+  using value_reference =
+      typename std::iterator_traits<IterOfRange<R>>::reference;
+
+  friend class enumerator_iter<R>;
+
+  result_pair() = default;
+  result_pair(std::size_t Index, IterOfRange<R> Iter)
+      : Index(Index), Iter(Iter) {}
+
+  result_pair<R> &operator=(const result_pair<R> &Other) {
+    Index = Other.Index;
+    Iter = Other.Iter;
+    return *this;
+  }
+
+  std::size_t index() const { return Index; }
+  const value_reference value() const { return *Iter; }
+  value_reference value() { return *Iter; }
+
+private:
+  std::size_t Index = std::numeric_limits<std::size_t>::max();
+  IterOfRange<R> Iter;
+};
+
+template <typename R>
+class enumerator_iter
+    : public iterator_facade_base<
+          enumerator_iter<R>, std::forward_iterator_tag, result_pair<R>,
+          typename std::iterator_traits<IterOfRange<R>>::difference_type,
+          typename std::iterator_traits<IterOfRange<R>>::pointer,
+          typename std::iterator_traits<IterOfRange<R>>::reference> {
+  using result_type = result_pair<R>;
+
+public:
+  explicit enumerator_iter(IterOfRange<R> EndIter)
+      : Result(std::numeric_limits<size_t>::max(), EndIter) {}
+
+  enumerator_iter(std::size_t Index, IterOfRange<R> Iter)
+      : Result(Index, Iter) {}
+
+  result_type &operator*() { return Result; }
+  const result_type &operator*() const { return Result; }
+
+  enumerator_iter<R> &operator++() {
+    assert(Result.Index != std::numeric_limits<size_t>::max());
+    ++Result.Iter;
+    ++Result.Index;
+    return *this;
+  }
+
+  bool operator==(const enumerator_iter<R> &RHS) const {
+    // Don't compare indices here, only iterators.  It's possible for an end
+    // iterator to have different indices depending on whether it was created
+    // by calling std::end() versus incrementing a valid iterator.
+    return Result.Iter == RHS.Result.Iter;
+  }
+
+  enumerator_iter<R> &operator=(const enumerator_iter<R> &Other) {
+    Result = Other.Result;
+    return *this;
+  }
+
+private:
+  result_type Result;
+};
+
+template <typename R> class enumerator {
+public:
+  explicit enumerator(R &&Range) : TheRange(std::forward<R>(Range)) {}
+
+  enumerator_iter<R> begin() {
+    return enumerator_iter<R>(0, std::begin(TheRange));
+  }
+
+  enumerator_iter<R> end() {
+    return enumerator_iter<R>(std::end(TheRange));
+  }
+
+private:
+  R TheRange;
+};
+
+} // end namespace detail
+
+/// Given an input range, returns a new range whose values are are pair (A,B)
+/// such that A is the 0-based index of the item in the sequence, and B is
+/// the value from the original sequence.  Example:
+///
+/// std::vector<char> Items = {'A', 'B', 'C', 'D'};
+/// for (auto X : enumerate(Items)) {
+///   printf("Item %d - %c\n", X.index(), X.value());
+/// }
+///
+/// Output:
+///   Item 0 - A
+///   Item 1 - B
+///   Item 2 - C
+///   Item 3 - D
+///
+template <typename R> detail::enumerator<R> enumerate(R &&TheRange) {
+  return detail::enumerator<R>(std::forward<R>(TheRange));
+}
+
+namespace detail {
+
+template <typename F, typename Tuple, std::size_t... I>
+auto apply_tuple_impl(F &&f, Tuple &&t, std::index_sequence<I...>)
+    -> decltype(std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...)) {
+  return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
+}
+
+} // end namespace detail
+
+/// Given an input tuple (a1, a2, ..., an), pass the arguments of the
+/// tuple variadically to f as if by calling f(a1, a2, ..., an) and
+/// return the result.
+template <typename F, typename Tuple>
+auto apply_tuple(F &&f, Tuple &&t) -> decltype(detail::apply_tuple_impl(
+    std::forward<F>(f), std::forward<Tuple>(t),
+    std::make_index_sequence<
+        std::tuple_size<typename std::decay<Tuple>::type>::value>{})) {
+  using Indices = std::make_index_sequence<
+      std::tuple_size<typename std::decay<Tuple>::type>::value>;
+
+  return detail::apply_tuple_impl(std::forward<F>(f), std::forward<Tuple>(t),
+                                  Indices{});
+}
+
+/// Return true if the sequence [Begin, End) has exactly N items. Runs in O(N)
+/// time. Not meant for use with random-access iterators.
+template <typename IterTy>
+bool hasNItems(
+    IterTy &&Begin, IterTy &&End, unsigned N,
+    typename std::enable_if<
+        !std::is_same<
+            typename std::iterator_traits<typename std::remove_reference<
+                decltype(Begin)>::type>::iterator_category,
+            std::random_access_iterator_tag>::value,
+        void>::type * = nullptr) {
+  for (; N; --N, ++Begin)
+    if (Begin == End)
+      return false; // Too few.
+  return Begin == End;
+}
+
+/// Return true if the sequence [Begin, End) has N or more items. Runs in O(N)
+/// time. Not meant for use with random-access iterators.
+template <typename IterTy>
+bool hasNItemsOrMore(
+    IterTy &&Begin, IterTy &&End, unsigned N,
+    typename std::enable_if<
+        !std::is_same<
+            typename std::iterator_traits<typename std::remove_reference<
+                decltype(Begin)>::type>::iterator_category,
+            std::random_access_iterator_tag>::value,
+        void>::type * = nullptr) {
+  for (; N; --N, ++Begin)
+    if (Begin == End)
+      return false; // Too few.
+  return true;
+}
+
+/// Returns a raw pointer that represents the same address as the argument.
+///
+/// The late bound return should be removed once we move to C++14 to better
+/// align with the C++20 declaration. Also, this implementation can be removed
+/// once we move to C++20 where it's defined as std::to_addres()
+///
+/// The std::pointer_traits<>::to_address(p) variations of these overloads has
+/// not been implemented.
+template <class Ptr> auto to_address(const Ptr &P) -> decltype(P.operator->()) {
+  return P.operator->();
+}
+template <class T> constexpr T *to_address(T *P) { return P; }
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_STLEXTRAS_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/SmallPtrSet.h b/binaryen/third_party/llvm-project/include/llvm/ADT/SmallPtrSet.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/SmallPtrSet.h
@@ -0,0 +1,511 @@
+//===- llvm/ADT/SmallPtrSet.h - 'Normally small' pointer set ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the SmallPtrSet class.  See the doxygen comment for
+// SmallPtrSetImplBase for more details on the algorithm used.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_SMALLPTRSET_H
+#define LLVM_ADT_SMALLPTRSET_H
+
+#include "llvm/ADT/EpochTracker.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ReverseIteration.h"
+#include "llvm/Support/type_traits.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <initializer_list>
+#include <iterator>
+#include <utility>
+
+namespace llvm {
+
+/// SmallPtrSetImplBase - This is the common code shared among all the
+/// SmallPtrSet<>'s, which is almost everything.  SmallPtrSet has two modes, one
+/// for small and one for large sets.
+///
+/// Small sets use an array of pointers allocated in the SmallPtrSet object,
+/// which is treated as a simple array of pointers.  When a pointer is added to
+/// the set, the array is scanned to see if the element already exists, if not
+/// the element is 'pushed back' onto the array.  If we run out of space in the
+/// array, we grow into the 'large set' case.  SmallSet should be used when the
+/// sets are often small.  In this case, no memory allocation is used, and only
+/// light-weight and cache-efficient scanning is used.
+///
+/// Large sets use a classic exponentially-probed hash table.  Empty buckets are
+/// represented with an illegal pointer value (-1) to allow null pointers to be
+/// inserted.  Tombstones are represented with another illegal pointer value
+/// (-2), to allow deletion.  The hash table is resized when the table is 3/4 or
+/// more.  When this happens, the table is doubled in size.
+///
+class SmallPtrSetImplBase : public DebugEpochBase {
+  friend class SmallPtrSetIteratorImpl;
+
+protected:
+  /// SmallArray - Points to a fixed size set of buckets, used in 'small mode'.
+  const void **SmallArray;
+  /// CurArray - This is the current set of buckets.  If equal to SmallArray,
+  /// then the set is in 'small mode'.
+  const void **CurArray;
+  /// CurArraySize - The allocated size of CurArray, always a power of two.
+  unsigned CurArraySize;
+
+  /// Number of elements in CurArray that contain a value or are a tombstone.
+  /// If small, all these elements are at the beginning of CurArray and the rest
+  /// is uninitialized.
+  unsigned NumNonEmpty;
+  /// Number of tombstones in CurArray.
+  unsigned NumTombstones;
+
+  // Helpers to copy and move construct a SmallPtrSet.
+  SmallPtrSetImplBase(const void **SmallStorage,
+                      const SmallPtrSetImplBase &that);
+  SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize,
+                      SmallPtrSetImplBase &&that);
+
+  explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize)
+      : SmallArray(SmallStorage), CurArray(SmallStorage),
+        CurArraySize(SmallSize), NumNonEmpty(0), NumTombstones(0) {
+    assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
+           "Initial size must be a power of two!");
+  }
+
+  ~SmallPtrSetImplBase() {
+    if (!isSmall())
+      free(CurArray);
+  }
+
+public:
+  using size_type = unsigned;
+
+  SmallPtrSetImplBase &operator=(const SmallPtrSetImplBase &) = delete;
+
+  LLVM_NODISCARD bool empty() const { return size() == 0; }
+  size_type size() const { return NumNonEmpty - NumTombstones; }
+
+  void clear() {
+    incrementEpoch();
+    // If the capacity of the array is huge, and the # elements used is small,
+    // shrink the array.
+    if (!isSmall()) {
+      if (size() * 4 < CurArraySize && CurArraySize > 32)
+        return shrink_and_clear();
+      // Fill the array with empty markers.
+      memset(CurArray, -1, CurArraySize * sizeof(void *));
+    }
+
+    NumNonEmpty = 0;
+    NumTombstones = 0;
+  }
+
+protected:
+  static void *getTombstoneMarker() { return reinterpret_cast<void*>(-2); }
+
+  static void *getEmptyMarker() {
+    // Note that -1 is chosen to make clear() efficiently implementable with
+    // memset and because it's not a valid pointer value.
+    return reinterpret_cast<void*>(-1);
+  }
+
+  const void **EndPointer() const {
+    return isSmall() ? CurArray + NumNonEmpty : CurArray + CurArraySize;
+  }
+
+  /// insert_imp - This returns true if the pointer was new to the set, false if
+  /// it was already in the set.  This is hidden from the client so that the
+  /// derived class can check that the right type of pointer is passed in.
+  std::pair<const void *const *, bool> insert_imp(const void *Ptr) {
+    if (isSmall()) {
+      // Check to see if it is already in the set.
+      const void **LastTombstone = nullptr;
+      for (const void **APtr = SmallArray, **E = SmallArray + NumNonEmpty;
+           APtr != E; ++APtr) {
+        const void *Value = *APtr;
+        if (Value == Ptr)
+          return std::make_pair(APtr, false);
+        if (Value == getTombstoneMarker())
+          LastTombstone = APtr;
+      }
+
+      // Did we find any tombstone marker?
+      if (LastTombstone != nullptr) {
+        *LastTombstone = Ptr;
+        --NumTombstones;
+        incrementEpoch();
+        return std::make_pair(LastTombstone, true);
+      }
+
+      // Nope, there isn't.  If we stay small, just 'pushback' now.
+      if (NumNonEmpty < CurArraySize) {
+        SmallArray[NumNonEmpty++] = Ptr;
+        incrementEpoch();
+        return std::make_pair(SmallArray + (NumNonEmpty - 1), true);
+      }
+      // Otherwise, hit the big set case, which will call grow.
+    }
+    return insert_imp_big(Ptr);
+  }
+
+  /// erase_imp - If the set contains the specified pointer, remove it and
+  /// return true, otherwise return false.  This is hidden from the client so
+  /// that the derived class can check that the right type of pointer is passed
+  /// in.
+  bool erase_imp(const void * Ptr) {
+    const void *const *P = find_imp(Ptr);
+    if (P == EndPointer())
+      return false;
+
+    const void **Loc = const_cast<const void **>(P);
+    assert(*Loc == Ptr && "broken find!");
+    *Loc = getTombstoneMarker();
+    NumTombstones++;
+    return true;
+  }
+
+  /// Returns the raw pointer needed to construct an iterator.  If element not
+  /// found, this will be EndPointer.  Otherwise, it will be a pointer to the
+  /// slot which stores Ptr;
+  const void *const * find_imp(const void * Ptr) const {
+    if (isSmall()) {
+      // Linear search for the item.
+      for (const void *const *APtr = SmallArray,
+                      *const *E = SmallArray + NumNonEmpty; APtr != E; ++APtr)
+        if (*APtr == Ptr)
+          return APtr;
+      return EndPointer();
+    }
+
+    // Big set case.
+    auto *Bucket = FindBucketFor(Ptr);
+    if (*Bucket == Ptr)
+      return Bucket;
+    return EndPointer();
+  }
+
+private:
+  bool isSmall() const { return CurArray == SmallArray; }
+
+  std::pair<const void *const *, bool> insert_imp_big(const void *Ptr);
+
+  const void * const *FindBucketFor(const void *Ptr) const;
+  void shrink_and_clear();
+
+  /// Grow - Allocate a larger backing store for the buckets and move it over.
+  void Grow(unsigned NewSize);
+
+protected:
+  /// swap - Swaps the elements of two sets.
+  /// Note: This method assumes that both sets have the same small size.
+  void swap(SmallPtrSetImplBase &RHS);
+
+  void CopyFrom(const SmallPtrSetImplBase &RHS);
+  void MoveFrom(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
+
+private:
+  /// Code shared by MoveFrom() and move constructor.
+  void MoveHelper(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
+  /// Code shared by CopyFrom() and copy constructor.
+  void CopyHelper(const SmallPtrSetImplBase &RHS);
+};
+
+/// SmallPtrSetIteratorImpl - This is the common base class shared between all
+/// instances of SmallPtrSetIterator.
+class SmallPtrSetIteratorImpl {
+protected:
+  const void *const *Bucket;
+  const void *const *End;
+
+public:
+  explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E)
+    : Bucket(BP), End(E) {
+    if (shouldReverseIterate()) {
+      RetreatIfNotValid();
+      return;
+    }
+    AdvanceIfNotValid();
+  }
+
+  bool operator==(const SmallPtrSetIteratorImpl &RHS) const {
+    return Bucket == RHS.Bucket;
+  }
+  bool operator!=(const SmallPtrSetIteratorImpl &RHS) const {
+    return Bucket != RHS.Bucket;
+  }
+
+protected:
+  /// AdvanceIfNotValid - If the current bucket isn't valid, advance to a bucket
+  /// that is.   This is guaranteed to stop because the end() bucket is marked
+  /// valid.
+  void AdvanceIfNotValid() {
+    assert(Bucket <= End);
+    while (Bucket != End &&
+           (*Bucket == SmallPtrSetImplBase::getEmptyMarker() ||
+            *Bucket == SmallPtrSetImplBase::getTombstoneMarker()))
+      ++Bucket;
+  }
+  void RetreatIfNotValid() {
+    assert(Bucket >= End);
+    while (Bucket != End &&
+           (Bucket[-1] == SmallPtrSetImplBase::getEmptyMarker() ||
+            Bucket[-1] == SmallPtrSetImplBase::getTombstoneMarker())) {
+      --Bucket;
+    }
+  }
+};
+
+/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
+template <typename PtrTy>
+class SmallPtrSetIterator : public SmallPtrSetIteratorImpl,
+                            DebugEpochBase::HandleBase {
+  using PtrTraits = PointerLikeTypeTraits<PtrTy>;
+
+public:
+  using value_type = PtrTy;
+  using reference = PtrTy;
+  using pointer = PtrTy;
+  using difference_type = std::ptrdiff_t;
+  using iterator_category = std::forward_iterator_tag;
+
+  explicit SmallPtrSetIterator(const void *const *BP, const void *const *E,
+                               const DebugEpochBase &Epoch)
+      : SmallPtrSetIteratorImpl(BP, E), DebugEpochBase::HandleBase(&Epoch) {}
+
+  // Most methods provided by baseclass.
+
+  const PtrTy operator*() const {
+    assert(isHandleInSync() && "invalid iterator access!");
+    if (shouldReverseIterate()) {
+      assert(Bucket > End);
+      return PtrTraits::getFromVoidPointer(const_cast<void *>(Bucket[-1]));
+    }
+    assert(Bucket < End);
+    return PtrTraits::getFromVoidPointer(const_cast<void*>(*Bucket));
+  }
+
+  inline SmallPtrSetIterator& operator++() {          // Preincrement
+    assert(isHandleInSync() && "invalid iterator access!");
+    if (shouldReverseIterate()) {
+      --Bucket;
+      RetreatIfNotValid();
+      return *this;
+    }
+    ++Bucket;
+    AdvanceIfNotValid();
+    return *this;
+  }
+
+  SmallPtrSetIterator operator++(int) {        // Postincrement
+    SmallPtrSetIterator tmp = *this;
+    ++*this;
+    return tmp;
+  }
+};
+
+/// RoundUpToPowerOfTwo - This is a helper template that rounds N up to the next
+/// power of two (which means N itself if N is already a power of two).
+template<unsigned N>
+struct RoundUpToPowerOfTwo;
+
+/// RoundUpToPowerOfTwoH - If N is not a power of two, increase it.  This is a
+/// helper template used to implement RoundUpToPowerOfTwo.
+template<unsigned N, bool isPowerTwo>
+struct RoundUpToPowerOfTwoH {
+  enum { Val = N };
+};
+template<unsigned N>
+struct RoundUpToPowerOfTwoH<N, false> {
+  enum {
+    // We could just use NextVal = N+1, but this converges faster.  N|(N-1) sets
+    // the right-most zero bits to one all at once, e.g. 0b0011000 -> 0b0011111.
+    Val = RoundUpToPowerOfTwo<(N|(N-1)) + 1>::Val
+  };
+};
+
+template<unsigned N>
+struct RoundUpToPowerOfTwo {
+  enum { Val = RoundUpToPowerOfTwoH<N, (N&(N-1)) == 0>::Val };
+};
+
+/// A templated base class for \c SmallPtrSet which provides the
+/// typesafe interface that is common across all small sizes.
+///
+/// This is particularly useful for passing around between interface boundaries
+/// to avoid encoding a particular small size in the interface boundary.
+template <typename PtrType>
+class SmallPtrSetImpl : public SmallPtrSetImplBase {
+  using ConstPtrType = typename add_const_past_pointer<PtrType>::type;
+  using PtrTraits = PointerLikeTypeTraits<PtrType>;
+  using ConstPtrTraits = PointerLikeTypeTraits<ConstPtrType>;
+
+protected:
+  // Constructors that forward to the base.
+  SmallPtrSetImpl(const void **SmallStorage, const SmallPtrSetImpl &that)
+      : SmallPtrSetImplBase(SmallStorage, that) {}
+  SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize,
+                  SmallPtrSetImpl &&that)
+      : SmallPtrSetImplBase(SmallStorage, SmallSize, std::move(that)) {}
+  explicit SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize)
+      : SmallPtrSetImplBase(SmallStorage, SmallSize) {}
+
+public:
+  using iterator = SmallPtrSetIterator<PtrType>;
+  using const_iterator = SmallPtrSetIterator<PtrType>;
+  using key_type = ConstPtrType;
+  using value_type = PtrType;
+
+  SmallPtrSetImpl(const SmallPtrSetImpl &) = delete;
+
+  /// Inserts Ptr if and only if there is no element in the container equal to
+  /// Ptr. The bool component of the returned pair is true if and only if the
+  /// insertion takes place, and the iterator component of the pair points to
+  /// the element equal to Ptr.
+  std::pair<iterator, bool> insert(PtrType Ptr) {
+    auto p = insert_imp(PtrTraits::getAsVoidPointer(Ptr));
+    return std::make_pair(makeIterator(p.first), p.second);
+  }
+
+  /// erase - If the set contains the specified pointer, remove it and return
+  /// true, otherwise return false.
+  bool erase(PtrType Ptr) {
+    return erase_imp(PtrTraits::getAsVoidPointer(Ptr));
+  }
+  /// count - Return 1 if the specified pointer is in the set, 0 otherwise.
+  size_type count(ConstPtrType Ptr) const { return find(Ptr) != end() ? 1 : 0; }
+  iterator find(ConstPtrType Ptr) const {
+    return makeIterator(find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)));
+  }
+
+  template <typename IterT>
+  void insert(IterT I, IterT E) {
+    for (; I != E; ++I)
+      insert(*I);
+  }
+
+  void insert(std::initializer_list<PtrType> IL) {
+    insert(IL.begin(), IL.end());
+  }
+
+  iterator begin() const {
+    if (shouldReverseIterate())
+      return makeIterator(EndPointer() - 1);
+    return makeIterator(CurArray);
+  }
+  iterator end() const { return makeIterator(EndPointer()); }
+
+private:
+  /// Create an iterator that dereferences to same place as the given pointer.
+  iterator makeIterator(const void *const *P) const {
+    if (shouldReverseIterate())
+      return iterator(P == EndPointer() ? CurArray : P + 1, CurArray, *this);
+    return iterator(P, EndPointer(), *this);
+  }
+};
+
+/// Equality comparison for SmallPtrSet.
+///
+/// Iterates over elements of LHS confirming that each value from LHS is also in
+/// RHS, and that no additional values are in RHS.
+template <typename PtrType>
+bool operator==(const SmallPtrSetImpl<PtrType> &LHS,
+                const SmallPtrSetImpl<PtrType> &RHS) {
+  if (LHS.size() != RHS.size())
+    return false;
+
+  for (const auto *KV : LHS)
+    if (!RHS.count(KV))
+      return false;
+
+  return true;
+}
+
+/// Inequality comparison for SmallPtrSet.
+///
+/// Equivalent to !(LHS == RHS).
+template <typename PtrType>
+bool operator!=(const SmallPtrSetImpl<PtrType> &LHS,
+                const SmallPtrSetImpl<PtrType> &RHS) {
+  return !(LHS == RHS);
+}
+
+/// SmallPtrSet - This class implements a set which is optimized for holding
+/// SmallSize or less elements.  This internally rounds up SmallSize to the next
+/// power of two if it is not already a power of two.  See the comments above
+/// SmallPtrSetImplBase for details of the algorithm.
+template<class PtrType, unsigned SmallSize>
+class SmallPtrSet : public SmallPtrSetImpl<PtrType> {
+  // In small mode SmallPtrSet uses linear search for the elements, so it is
+  // not a good idea to choose this value too high. You may consider using a
+  // DenseSet<> instead if you expect many elements in the set.
+  static_assert(SmallSize <= 32, "SmallSize should be small");
+
+  using BaseT = SmallPtrSetImpl<PtrType>;
+
+  // Make sure that SmallSize is a power of two, round up if not.
+  enum { SmallSizePowTwo = RoundUpToPowerOfTwo<SmallSize>::Val };
+  /// SmallStorage - Fixed size storage used in 'small mode'.
+  const void *SmallStorage[SmallSizePowTwo];
+
+public:
+  SmallPtrSet() : BaseT(SmallStorage, SmallSizePowTwo) {}
+  SmallPtrSet(const SmallPtrSet &that) : BaseT(SmallStorage, that) {}
+  SmallPtrSet(SmallPtrSet &&that)
+      : BaseT(SmallStorage, SmallSizePowTwo, std::move(that)) {}
+
+  template<typename It>
+  SmallPtrSet(It I, It E) : BaseT(SmallStorage, SmallSizePowTwo) {
+    this->insert(I, E);
+  }
+
+  SmallPtrSet(std::initializer_list<PtrType> IL)
+      : BaseT(SmallStorage, SmallSizePowTwo) {
+    this->insert(IL.begin(), IL.end());
+  }
+
+  SmallPtrSet<PtrType, SmallSize> &
+  operator=(const SmallPtrSet<PtrType, SmallSize> &RHS) {
+    if (&RHS != this)
+      this->CopyFrom(RHS);
+    return *this;
+  }
+
+  SmallPtrSet<PtrType, SmallSize> &
+  operator=(SmallPtrSet<PtrType, SmallSize> &&RHS) {
+    if (&RHS != this)
+      this->MoveFrom(SmallSizePowTwo, std::move(RHS));
+    return *this;
+  }
+
+  SmallPtrSet<PtrType, SmallSize> &
+  operator=(std::initializer_list<PtrType> IL) {
+    this->clear();
+    this->insert(IL.begin(), IL.end());
+    return *this;
+  }
+
+  /// swap - Swaps the elements of two sets.
+  void swap(SmallPtrSet<PtrType, SmallSize> &RHS) {
+    SmallPtrSetImplBase::swap(RHS);
+  }
+};
+
+} // end namespace llvm
+
+namespace std {
+
+  /// Implement std::swap in terms of SmallPtrSet swap.
+  template<class T, unsigned N>
+  inline void swap(llvm::SmallPtrSet<T, N> &LHS, llvm::SmallPtrSet<T, N> &RHS) {
+    LHS.swap(RHS);
+  }
+
+} // end namespace std
+
+#endif // LLVM_ADT_SMALLPTRSET_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/SmallSet.h b/binaryen/third_party/llvm-project/include/llvm/ADT/SmallSet.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/SmallSet.h
@@ -0,0 +1,278 @@
+//===- llvm/ADT/SmallSet.h - 'Normally small' sets --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the SmallSet class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_SMALLSET_H
+#define LLVM_ADT_SMALLSET_H
+
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/type_traits.h"
+#include <cstddef>
+#include <functional>
+#include <set>
+#include <type_traits>
+#include <utility>
+
+namespace llvm {
+
+/// SmallSetIterator - This class implements a const_iterator for SmallSet by
+/// delegating to the underlying SmallVector or Set iterators.
+template <typename T, unsigned N, typename C>
+class SmallSetIterator
+    : public iterator_facade_base<SmallSetIterator<T, N, C>,
+                                  std::forward_iterator_tag, T> {
+private:
+  using SetIterTy = typename std::set<T, C>::const_iterator;
+  using VecIterTy = typename SmallVector<T, N>::const_iterator;
+  using SelfTy = SmallSetIterator<T, N, C>;
+
+  /// Iterators to the parts of the SmallSet containing the data. They are set
+  /// depending on isSmall.
+  union {
+    SetIterTy SetIter;
+    VecIterTy VecIter;
+  };
+
+  bool isSmall;
+
+public:
+  SmallSetIterator(SetIterTy SetIter) : SetIter(SetIter), isSmall(false) {}
+
+  SmallSetIterator(VecIterTy VecIter) : VecIter(VecIter), isSmall(true) {}
+
+  // Spell out destructor, copy/move constructor and assignment operators for
+  // MSVC STL, where set<T>::const_iterator is not trivially copy constructible.
+  ~SmallSetIterator() {
+    if (isSmall)
+      VecIter.~VecIterTy();
+    else
+      SetIter.~SetIterTy();
+  }
+
+  SmallSetIterator(const SmallSetIterator &Other) : isSmall(Other.isSmall) {
+    if (isSmall)
+      VecIter = Other.VecIter;
+    else
+      // Use placement new, to make sure SetIter is properly constructed, even
+      // if it is not trivially copy-able (e.g. in MSVC).
+      new (&SetIter) SetIterTy(Other.SetIter);
+  }
+
+  SmallSetIterator(SmallSetIterator &&Other) : isSmall(Other.isSmall) {
+    if (isSmall)
+      VecIter = std::move(Other.VecIter);
+    else
+      // Use placement new, to make sure SetIter is properly constructed, even
+      // if it is not trivially copy-able (e.g. in MSVC).
+      new (&SetIter) SetIterTy(std::move(Other.SetIter));
+  }
+
+  SmallSetIterator& operator=(const SmallSetIterator& Other) {
+    // Call destructor for SetIter, so it gets properly destroyed if it is
+    // not trivially destructible in case we are setting VecIter.
+    if (!isSmall)
+      SetIter.~SetIterTy();
+
+    isSmall = Other.isSmall;
+    if (isSmall)
+      VecIter = Other.VecIter;
+    else
+      new (&SetIter) SetIterTy(Other.SetIter);
+    return *this;
+  }
+
+  SmallSetIterator& operator=(SmallSetIterator&& Other) {
+    // Call destructor for SetIter, so it gets properly destroyed if it is
+    // not trivially destructible in case we are setting VecIter.
+    if (!isSmall)
+      SetIter.~SetIterTy();
+
+    isSmall = Other.isSmall;
+    if (isSmall)
+      VecIter = std::move(Other.VecIter);
+    else
+      new (&SetIter) SetIterTy(std::move(Other.SetIter));
+    return *this;
+  }
+
+  bool operator==(const SmallSetIterator &RHS) const {
+    if (isSmall != RHS.isSmall)
+      return false;
+    if (isSmall)
+      return VecIter == RHS.VecIter;
+    return SetIter == RHS.SetIter;
+  }
+
+  SmallSetIterator &operator++() { // Preincrement
+    if (isSmall)
+      VecIter++;
+    else
+      SetIter++;
+    return *this;
+  }
+
+  const T &operator*() const { return isSmall ? *VecIter : *SetIter; }
+};
+
+/// SmallSet - This maintains a set of unique values, optimizing for the case
+/// when the set is small (less than N).  In this case, the set can be
+/// maintained with no mallocs.  If the set gets large, we expand to using an
+/// std::set to maintain reasonable lookup times.
+template <typename T, unsigned N, typename C = std::less<T>>
+class SmallSet {
+  /// Use a SmallVector to hold the elements here (even though it will never
+  /// reach its 'large' stage) to avoid calling the default ctors of elements
+  /// we will never use.
+  SmallVector<T, N> Vector;
+  std::set<T, C> Set;
+
+  using VIterator = typename SmallVector<T, N>::const_iterator;
+  using mutable_iterator = typename SmallVector<T, N>::iterator;
+
+  // In small mode SmallPtrSet uses linear search for the elements, so it is
+  // not a good idea to choose this value too high. You may consider using a
+  // DenseSet<> instead if you expect many elements in the set.
+  static_assert(N <= 32, "N should be small");
+
+public:
+  using size_type = size_t;
+  using const_iterator = SmallSetIterator<T, N, C>;
+
+  SmallSet() = default;
+
+  LLVM_NODISCARD bool empty() const {
+    return Vector.empty() && Set.empty();
+  }
+
+  size_type size() const {
+    return isSmall() ? Vector.size() : Set.size();
+  }
+
+  /// count - Return 1 if the element is in the set, 0 otherwise.
+  size_type count(const T &V) const {
+    if (isSmall()) {
+      // Since the collection is small, just do a linear search.
+      return vfind(V) == Vector.end() ? 0 : 1;
+    } else {
+      return Set.count(V);
+    }
+  }
+
+  /// insert - Insert an element into the set if it isn't already there.
+  /// Returns true if the element is inserted (it was not in the set before).
+  /// The first value of the returned pair is unused and provided for
+  /// partial compatibility with the standard library self-associative container
+  /// concept.
+  // FIXME: Add iterators that abstract over the small and large form, and then
+  // return those here.
+  std::pair<NoneType, bool> insert(const T &V) {
+    if (!isSmall())
+      return std::make_pair(None, Set.insert(V).second);
+
+    VIterator I = vfind(V);
+    if (I != Vector.end())    // Don't reinsert if it already exists.
+      return std::make_pair(None, false);
+    if (Vector.size() < N) {
+      Vector.push_back(V);
+      return std::make_pair(None, true);
+    }
+
+    // Otherwise, grow from vector to set.
+    while (!Vector.empty()) {
+      Set.insert(Vector.back());
+      Vector.pop_back();
+    }
+    Set.insert(V);
+    return std::make_pair(None, true);
+  }
+
+  template <typename IterT>
+  void insert(IterT I, IterT E) {
+    for (; I != E; ++I)
+      insert(*I);
+  }
+
+  bool erase(const T &V) {
+    if (!isSmall())
+      return Set.erase(V);
+    for (mutable_iterator I = Vector.begin(), E = Vector.end(); I != E; ++I)
+      if (*I == V) {
+        Vector.erase(I);
+        return true;
+      }
+    return false;
+  }
+
+  void clear() {
+    Vector.clear();
+    Set.clear();
+  }
+
+  const_iterator begin() const {
+    if (isSmall())
+      return {Vector.begin()};
+    return {Set.begin()};
+  }
+
+  const_iterator end() const {
+    if (isSmall())
+      return {Vector.end()};
+    return {Set.end()};
+  }
+
+private:
+  bool isSmall() const { return Set.empty(); }
+
+  VIterator vfind(const T &V) const {
+    for (VIterator I = Vector.begin(), E = Vector.end(); I != E; ++I)
+      if (*I == V)
+        return I;
+    return Vector.end();
+  }
+};
+
+/// If this set is of pointer values, transparently switch over to using
+/// SmallPtrSet for performance.
+template <typename PointeeType, unsigned N>
+class SmallSet<PointeeType*, N> : public SmallPtrSet<PointeeType*, N> {};
+
+/// Equality comparison for SmallSet.
+///
+/// Iterates over elements of LHS confirming that each element is also a member
+/// of RHS, and that RHS contains no additional values.
+/// Equivalent to N calls to RHS.count.
+/// For small-set mode amortized complexity is O(N^2)
+/// For large-set mode amortized complexity is linear, worst case is O(N^2) (if
+/// every hash collides).
+template <typename T, unsigned LN, unsigned RN, typename C>
+bool operator==(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) {
+  if (LHS.size() != RHS.size())
+    return false;
+
+  // All elements in LHS must also be in RHS
+  return all_of(LHS, [&RHS](const T &E) { return RHS.count(E); });
+}
+
+/// Inequality comparison for SmallSet.
+///
+/// Equivalent to !(LHS == RHS). See operator== for performance notes.
+template <typename T, unsigned LN, unsigned RN, typename C>
+bool operator!=(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) {
+  return !(LHS == RHS);
+}
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_SMALLSET_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/SmallString.h b/binaryen/third_party/llvm-project/include/llvm/ADT/SmallString.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/SmallString.h
@@ -0,0 +1,296 @@
+//===- llvm/ADT/SmallString.h - 'Normally small' strings --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the SmallString class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_SMALLSTRING_H
+#define LLVM_ADT_SMALLSTRING_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include <cstddef>
+
+namespace llvm {
+
+/// SmallString - A SmallString is just a SmallVector with methods and accessors
+/// that make it work better as a string (e.g. operator+ etc).
+template<unsigned InternalLen>
+class SmallString : public SmallVector<char, InternalLen> {
+public:
+  /// Default ctor - Initialize to empty.
+  SmallString() = default;
+
+  /// Initialize from a StringRef.
+  SmallString(StringRef S) : SmallVector<char, InternalLen>(S.begin(), S.end()) {}
+
+  /// Initialize with a range.
+  template<typename ItTy>
+  SmallString(ItTy S, ItTy E) : SmallVector<char, InternalLen>(S, E) {}
+
+  // Note that in order to add new overloads for append & assign, we have to
+  // duplicate the inherited versions so as not to inadvertently hide them.
+
+  /// @}
+  /// @name String Assignment
+  /// @{
+
+  /// Assign from a repeated element.
+  void assign(size_t NumElts, char Elt) {
+    this->SmallVectorImpl<char>::assign(NumElts, Elt);
+  }
+
+  /// Assign from an iterator pair.
+  template<typename in_iter>
+  void assign(in_iter S, in_iter E) {
+    this->clear();
+    SmallVectorImpl<char>::append(S, E);
+  }
+
+  /// Assign from a StringRef.
+  void assign(StringRef RHS) {
+    this->clear();
+    SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
+  }
+
+  /// Assign from a SmallVector.
+  void assign(const SmallVectorImpl<char> &RHS) {
+    this->clear();
+    SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
+  }
+
+  /// @}
+  /// @name String Concatenation
+  /// @{
+
+  /// Append from an iterator pair.
+  template<typename in_iter>
+  void append(in_iter S, in_iter E) {
+    SmallVectorImpl<char>::append(S, E);
+  }
+
+  void append(size_t NumInputs, char Elt) {
+    SmallVectorImpl<char>::append(NumInputs, Elt);
+  }
+
+  /// Append from a StringRef.
+  void append(StringRef RHS) {
+    SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
+  }
+
+  /// Append from a SmallVector.
+  void append(const SmallVectorImpl<char> &RHS) {
+    SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
+  }
+
+  /// @}
+  /// @name String Comparison
+  /// @{
+
+  /// Check for string equality.  This is more efficient than compare() when
+  /// the relative ordering of inequal strings isn't needed.
+  bool equals(StringRef RHS) const {
+    return str().equals(RHS);
+  }
+
+  /// Check for string equality, ignoring case.
+  bool equals_lower(StringRef RHS) const {
+    return str().equals_lower(RHS);
+  }
+
+  /// Compare two strings; the result is -1, 0, or 1 if this string is
+  /// lexicographically less than, equal to, or greater than the \p RHS.
+  int compare(StringRef RHS) const {
+    return str().compare(RHS);
+  }
+
+  /// compare_lower - Compare two strings, ignoring case.
+  int compare_lower(StringRef RHS) const {
+    return str().compare_lower(RHS);
+  }
+
+  /// compare_numeric - Compare two strings, treating sequences of digits as
+  /// numbers.
+  int compare_numeric(StringRef RHS) const {
+    return str().compare_numeric(RHS);
+  }
+
+  /// @}
+  /// @name String Predicates
+  /// @{
+
+  /// startswith - Check if this string starts with the given \p Prefix.
+  bool startswith(StringRef Prefix) const {
+    return str().startswith(Prefix);
+  }
+
+  /// endswith - Check if this string ends with the given \p Suffix.
+  bool endswith(StringRef Suffix) const {
+    return str().endswith(Suffix);
+  }
+
+  /// @}
+  /// @name String Searching
+  /// @{
+
+  /// find - Search for the first character \p C in the string.
+  ///
+  /// \return - The index of the first occurrence of \p C, or npos if not
+  /// found.
+  size_t find(char C, size_t From = 0) const {
+    return str().find(C, From);
+  }
+
+  /// Search for the first string \p Str in the string.
+  ///
+  /// \returns The index of the first occurrence of \p Str, or npos if not
+  /// found.
+  size_t find(StringRef Str, size_t From = 0) const {
+    return str().find(Str, From);
+  }
+
+  /// Search for the last character \p C in the string.
+  ///
+  /// \returns The index of the last occurrence of \p C, or npos if not
+  /// found.
+  size_t rfind(char C, size_t From = StringRef::npos) const {
+    return str().rfind(C, From);
+  }
+
+  /// Search for the last string \p Str in the string.
+  ///
+  /// \returns The index of the last occurrence of \p Str, or npos if not
+  /// found.
+  size_t rfind(StringRef Str) const {
+    return str().rfind(Str);
+  }
+
+  /// Find the first character in the string that is \p C, or npos if not
+  /// found. Same as find.
+  size_t find_first_of(char C, size_t From = 0) const {
+    return str().find_first_of(C, From);
+  }
+
+  /// Find the first character in the string that is in \p Chars, or npos if
+  /// not found.
+  ///
+  /// Complexity: O(size() + Chars.size())
+  size_t find_first_of(StringRef Chars, size_t From = 0) const {
+    return str().find_first_of(Chars, From);
+  }
+
+  /// Find the first character in the string that is not \p C or npos if not
+  /// found.
+  size_t find_first_not_of(char C, size_t From = 0) const {
+    return str().find_first_not_of(C, From);
+  }
+
+  /// Find the first character in the string that is not in the string
+  /// \p Chars, or npos if not found.
+  ///
+  /// Complexity: O(size() + Chars.size())
+  size_t find_first_not_of(StringRef Chars, size_t From = 0) const {
+    return str().find_first_not_of(Chars, From);
+  }
+
+  /// Find the last character in the string that is \p C, or npos if not
+  /// found.
+  size_t find_last_of(char C, size_t From = StringRef::npos) const {
+    return str().find_last_of(C, From);
+  }
+
+  /// Find the last character in the string that is in \p C, or npos if not
+  /// found.
+  ///
+  /// Complexity: O(size() + Chars.size())
+  size_t find_last_of(
+      StringRef Chars, size_t From = StringRef::npos) const {
+    return str().find_last_of(Chars, From);
+  }
+
+  /// @}
+  /// @name Helpful Algorithms
+  /// @{
+
+  /// Return the number of occurrences of \p C in the string.
+  size_t count(char C) const {
+    return str().count(C);
+  }
+
+  /// Return the number of non-overlapped occurrences of \p Str in the
+  /// string.
+  size_t count(StringRef Str) const {
+    return str().count(Str);
+  }
+
+  /// @}
+  /// @name Substring Operations
+  /// @{
+
+  /// Return a reference to the substring from [Start, Start + N).
+  ///
+  /// \param Start The index of the starting character in the substring; if
+  /// the index is npos or greater than the length of the string then the
+  /// empty substring will be returned.
+  ///
+  /// \param N The number of characters to included in the substring. If \p N
+  /// exceeds the number of characters remaining in the string, the string
+  /// suffix (starting with \p Start) will be returned.
+  StringRef substr(size_t Start, size_t N = StringRef::npos) const {
+    return str().substr(Start, N);
+  }
+
+  /// Return a reference to the substring from [Start, End).
+  ///
+  /// \param Start The index of the starting character in the substring; if
+  /// the index is npos or greater than the length of the string then the
+  /// empty substring will be returned.
+  ///
+  /// \param End The index following the last character to include in the
+  /// substring. If this is npos, or less than \p Start, or exceeds the
+  /// number of characters remaining in the string, the string suffix
+  /// (starting with \p Start) will be returned.
+  StringRef slice(size_t Start, size_t End) const {
+    return str().slice(Start, End);
+  }
+
+  // Extra methods.
+
+  /// Explicit conversion to StringRef.
+  StringRef str() const { return StringRef(this->begin(), this->size()); }
+
+  // TODO: Make this const, if it's safe...
+  const char* c_str() {
+    this->push_back(0);
+    this->pop_back();
+    return this->data();
+  }
+
+  /// Implicit conversion to StringRef.
+  operator StringRef() const { return str(); }
+
+  // Extra operators.
+  const SmallString &operator=(StringRef RHS) {
+    this->clear();
+    return *this += RHS;
+  }
+
+  SmallString &operator+=(StringRef RHS) {
+    this->append(RHS.begin(), RHS.end());
+    return *this;
+  }
+  SmallString &operator+=(char C) {
+    this->push_back(C);
+    return *this;
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_SMALLSTRING_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/SmallVector.h b/binaryen/third_party/llvm-project/include/llvm/ADT/SmallVector.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/SmallVector.h
@@ -0,0 +1,930 @@
+//===- llvm/ADT/SmallVector.h - 'Normally small' vectors --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the SmallVector class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_SMALLVECTOR_H
+#define LLVM_ADT_SMALLVECTOR_H
+
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/AlignOf.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemAlloc.h"
+#include "llvm/Support/type_traits.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <initializer_list>
+#include <iterator>
+#include <memory>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+namespace llvm {
+
+/// This is all the non-templated stuff common to all SmallVectors.
+class SmallVectorBase {
+protected:
+  void *BeginX;
+  unsigned Size = 0, Capacity;
+
+  SmallVectorBase() = delete;
+  SmallVectorBase(void *FirstEl, size_t TotalCapacity)
+      : BeginX(FirstEl), Capacity(TotalCapacity) {}
+
+  /// This is an implementation of the grow() method which only works
+  /// on POD-like data types and is out of line to reduce code duplication.
+  void grow_pod(void *FirstEl, size_t MinCapacity, size_t TSize);
+
+public:
+  size_t size() const { return Size; }
+  size_t capacity() const { return Capacity; }
+
+  LLVM_NODISCARD bool empty() const { return !Size; }
+
+  /// Set the array size to \p N, which the current array must have enough
+  /// capacity for.
+  ///
+  /// This does not construct or destroy any elements in the vector.
+  ///
+  /// Clients can use this in conjunction with capacity() to write past the end
+  /// of the buffer when they know that more elements are available, and only
+  /// update the size later. This avoids the cost of value initializing elements
+  /// which will only be overwritten.
+  void set_size(size_t N) {
+    assert(N <= capacity());
+    Size = N;
+  }
+};
+
+/// Figure out the offset of the first element.
+template <class T, typename = void> struct SmallVectorAlignmentAndSize {
+  AlignedCharArrayUnion<SmallVectorBase> Base;
+  AlignedCharArrayUnion<T> FirstEl;
+};
+
+/// This is the part of SmallVectorTemplateBase which does not depend on whether
+/// the type T is a POD. The extra dummy template argument is used by ArrayRef
+/// to avoid unnecessarily requiring T to be complete.
+template <typename T, typename = void>
+class SmallVectorTemplateCommon : public SmallVectorBase {
+  /// Find the address of the first element.  For this pointer math to be valid
+  /// with small-size of 0 for T with lots of alignment, it's important that
+  /// SmallVectorStorage is properly-aligned even for small-size of 0.
+  void *getFirstEl() const {
+    return const_cast<void *>(reinterpret_cast<const void *>(
+        reinterpret_cast<const char *>(this) +
+        offsetof(SmallVectorAlignmentAndSize<T>, FirstEl)));
+  }
+  // Space after 'FirstEl' is clobbered, do not add any instance vars after it.
+
+protected:
+  SmallVectorTemplateCommon(size_t Size)
+      : SmallVectorBase(getFirstEl(), Size) {}
+
+  void grow_pod(size_t MinCapacity, size_t TSize) {
+    SmallVectorBase::grow_pod(getFirstEl(), MinCapacity, TSize);
+  }
+
+  /// Return true if this is a smallvector which has not had dynamic
+  /// memory allocated for it.
+  bool isSmall() const { return BeginX == getFirstEl(); }
+
+  /// Put this vector in a state of being small.
+  void resetToSmall() {
+    BeginX = getFirstEl();
+    Size = Capacity = 0; // FIXME: Setting Capacity to 0 is suspect.
+  }
+
+public:
+  using size_type = size_t;
+  using difference_type = ptrdiff_t;
+  using value_type = T;
+  using iterator = T *;
+  using const_iterator = const T *;
+
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+  using reverse_iterator = std::reverse_iterator<iterator>;
+
+  using reference = T &;
+  using const_reference = const T &;
+  using pointer = T *;
+  using const_pointer = const T *;
+
+  // forward iterator creation methods.
+  iterator begin() { return (iterator)this->BeginX; }
+  const_iterator begin() const { return (const_iterator)this->BeginX; }
+  iterator end() { return begin() + size(); }
+  const_iterator end() const { return begin() + size(); }
+
+  // reverse iterator creation methods.
+  reverse_iterator rbegin()            { return reverse_iterator(end()); }
+  const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
+  reverse_iterator rend()              { return reverse_iterator(begin()); }
+  const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
+
+  size_type size_in_bytes() const { return size() * sizeof(T); }
+  size_type max_size() const { return size_type(-1) / sizeof(T); }
+
+  size_t capacity_in_bytes() const { return capacity() * sizeof(T); }
+
+  /// Return a pointer to the vector's buffer, even if empty().
+  pointer data() { return pointer(begin()); }
+  /// Return a pointer to the vector's buffer, even if empty().
+  const_pointer data() const { return const_pointer(begin()); }
+
+  reference operator[](size_type idx) {
+    assert(idx < size());
+    return begin()[idx];
+  }
+  const_reference operator[](size_type idx) const {
+    assert(idx < size());
+    return begin()[idx];
+  }
+
+  reference front() {
+    assert(!empty());
+    return begin()[0];
+  }
+  const_reference front() const {
+    assert(!empty());
+    return begin()[0];
+  }
+
+  reference back() {
+    assert(!empty());
+    return end()[-1];
+  }
+  const_reference back() const {
+    assert(!empty());
+    return end()[-1];
+  }
+};
+
+/// SmallVectorTemplateBase<TriviallyCopyable = false> - This is where we put method
+/// implementations that are designed to work with non-POD-like T's.
+template <typename T, bool = is_trivially_copyable<T>::value>
+class SmallVectorTemplateBase : public SmallVectorTemplateCommon<T> {
+protected:
+  SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
+
+  static void destroy_range(T *S, T *E) {
+    while (S != E) {
+      --E;
+      E->~T();
+    }
+  }
+
+  /// Move the range [I, E) into the uninitialized memory starting with "Dest",
+  /// constructing elements as needed.
+  template<typename It1, typename It2>
+  static void uninitialized_move(It1 I, It1 E, It2 Dest) {
+    std::uninitialized_copy(std::make_move_iterator(I),
+                            std::make_move_iterator(E), Dest);
+  }
+
+  /// Copy the range [I, E) onto the uninitialized memory starting with "Dest",
+  /// constructing elements as needed.
+  template<typename It1, typename It2>
+  static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
+    std::uninitialized_copy(I, E, Dest);
+  }
+
+  /// Grow the allocated memory (without initializing new elements), doubling
+  /// the size of the allocated memory. Guarantees space for at least one more
+  /// element, or MinSize more elements if specified.
+  void grow(size_t MinSize = 0);
+
+public:
+  void push_back(const T &Elt) {
+    if (LLVM_UNLIKELY(this->size() >= this->capacity()))
+      this->grow();
+    ::new ((void*) this->end()) T(Elt);
+    this->set_size(this->size() + 1);
+  }
+
+  void push_back(T &&Elt) {
+    if (LLVM_UNLIKELY(this->size() >= this->capacity()))
+      this->grow();
+    ::new ((void*) this->end()) T(::std::move(Elt));
+    this->set_size(this->size() + 1);
+  }
+
+  void pop_back() {
+    this->set_size(this->size() - 1);
+    this->end()->~T();
+  }
+};
+
+// Define this out-of-line to dissuade the C++ compiler from inlining it.
+template <typename T, bool TriviallyCopyable>
+void SmallVectorTemplateBase<T, TriviallyCopyable>::grow(size_t MinSize) {
+  if (MinSize > UINT32_MAX)
+    report_bad_alloc_error("SmallVector capacity overflow during allocation");
+
+  // Always grow, even from zero.
+  size_t NewCapacity = size_t(NextPowerOf2(this->capacity() + 2));
+  NewCapacity = std::min(std::max(NewCapacity, MinSize), size_t(UINT32_MAX));
+  T *NewElts = static_cast<T*>(llvm::safe_malloc(NewCapacity*sizeof(T)));
+
+  // Move the elements over.
+  this->uninitialized_move(this->begin(), this->end(), NewElts);
+
+  // Destroy the original elements.
+  destroy_range(this->begin(), this->end());
+
+  // If this wasn't grown from the inline copy, deallocate the old space.
+  if (!this->isSmall())
+    free(this->begin());
+
+  this->BeginX = NewElts;
+  this->Capacity = NewCapacity;
+}
+
+/// SmallVectorTemplateBase<TriviallyCopyable = true> - This is where we put
+/// method implementations that are designed to work with POD-like T's.
+template <typename T>
+class SmallVectorTemplateBase<T, true> : public SmallVectorTemplateCommon<T> {
+protected:
+  SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
+
+  // No need to do a destroy loop for POD's.
+  static void destroy_range(T *, T *) {}
+
+  /// Move the range [I, E) onto the uninitialized memory
+  /// starting with "Dest", constructing elements into it as needed.
+  template<typename It1, typename It2>
+  static void uninitialized_move(It1 I, It1 E, It2 Dest) {
+    // Just do a copy.
+    uninitialized_copy(I, E, Dest);
+  }
+
+  /// Copy the range [I, E) onto the uninitialized memory
+  /// starting with "Dest", constructing elements into it as needed.
+  template<typename It1, typename It2>
+  static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
+    // Arbitrary iterator types; just use the basic implementation.
+    std::uninitialized_copy(I, E, Dest);
+  }
+
+  /// Copy the range [I, E) onto the uninitialized memory
+  /// starting with "Dest", constructing elements into it as needed.
+  template <typename T1, typename T2>
+  static void uninitialized_copy(
+      T1 *I, T1 *E, T2 *Dest,
+      typename std::enable_if<std::is_same<typename std::remove_const<T1>::type,
+                                           T2>::value>::type * = nullptr) {
+    // Use memcpy for PODs iterated by pointers (which includes SmallVector
+    // iterators): std::uninitialized_copy optimizes to memmove, but we can
+    // use memcpy here. Note that I and E are iterators and thus might be
+    // invalid for memcpy if they are equal.
+    if (I != E)
+      memcpy(reinterpret_cast<void *>(Dest), I, (E - I) * sizeof(T));
+  }
+
+  /// Double the size of the allocated memory, guaranteeing space for at
+  /// least one more element or MinSize if specified.
+  void grow(size_t MinSize = 0) { this->grow_pod(MinSize, sizeof(T)); }
+
+public:
+  void push_back(const T &Elt) {
+    if (LLVM_UNLIKELY(this->size() >= this->capacity()))
+      this->grow();
+    memcpy(reinterpret_cast<void *>(this->end()), &Elt, sizeof(T));
+    this->set_size(this->size() + 1);
+  }
+
+  void pop_back() { this->set_size(this->size() - 1); }
+};
+
+/// This class consists of common code factored out of the SmallVector class to
+/// reduce code duplication based on the SmallVector 'N' template parameter.
+template <typename T>
+class SmallVectorImpl : public SmallVectorTemplateBase<T> {
+  using SuperClass = SmallVectorTemplateBase<T>;
+
+public:
+  using iterator = typename SuperClass::iterator;
+  using const_iterator = typename SuperClass::const_iterator;
+  using reference = typename SuperClass::reference;
+  using size_type = typename SuperClass::size_type;
+
+protected:
+  // Default ctor - Initialize to empty.
+  explicit SmallVectorImpl(unsigned N)
+      : SmallVectorTemplateBase<T>(N) {}
+
+public:
+  SmallVectorImpl(const SmallVectorImpl &) = delete;
+
+  ~SmallVectorImpl() {
+    // Subclass has already destructed this vector's elements.
+    // If this wasn't grown from the inline copy, deallocate the old space.
+    if (!this->isSmall())
+      free(this->begin());
+  }
+
+  void clear() {
+    this->destroy_range(this->begin(), this->end());
+    this->Size = 0;
+  }
+
+  void resize(size_type N) {
+    if (N < this->size()) {
+      this->destroy_range(this->begin()+N, this->end());
+      this->set_size(N);
+    } else if (N > this->size()) {
+      if (this->capacity() < N)
+        this->grow(N);
+      for (auto I = this->end(), E = this->begin() + N; I != E; ++I)
+        new (&*I) T();
+      this->set_size(N);
+    }
+  }
+
+  void resize(size_type N, const T &NV) {
+    if (N < this->size()) {
+      this->destroy_range(this->begin()+N, this->end());
+      this->set_size(N);
+    } else if (N > this->size()) {
+      if (this->capacity() < N)
+        this->grow(N);
+      std::uninitialized_fill(this->end(), this->begin()+N, NV);
+      this->set_size(N);
+    }
+  }
+
+  void reserve(size_type N) {
+    if (this->capacity() < N)
+      this->grow(N);
+  }
+
+  LLVM_NODISCARD T pop_back_val() {
+    T Result = ::std::move(this->back());
+    this->pop_back();
+    return Result;
+  }
+
+  void swap(SmallVectorImpl &RHS);
+
+  /// Add the specified range to the end of the SmallVector.
+  template <typename in_iter,
+            typename = typename std::enable_if<std::is_convertible<
+                typename std::iterator_traits<in_iter>::iterator_category,
+                std::input_iterator_tag>::value>::type>
+  void append(in_iter in_start, in_iter in_end) {
+    size_type NumInputs = std::distance(in_start, in_end);
+    if (NumInputs > this->capacity() - this->size())
+      this->grow(this->size()+NumInputs);
+
+    this->uninitialized_copy(in_start, in_end, this->end());
+    this->set_size(this->size() + NumInputs);
+  }
+
+  /// Append \p NumInputs copies of \p Elt to the end.
+  void append(size_type NumInputs, const T &Elt) {
+    if (NumInputs > this->capacity() - this->size())
+      this->grow(this->size()+NumInputs);
+
+    std::uninitialized_fill_n(this->end(), NumInputs, Elt);
+    this->set_size(this->size() + NumInputs);
+  }
+
+  void append(std::initializer_list<T> IL) {
+    append(IL.begin(), IL.end());
+  }
+
+  // FIXME: Consider assigning over existing elements, rather than clearing &
+  // re-initializing them - for all assign(...) variants.
+
+  void assign(size_type NumElts, const T &Elt) {
+    clear();
+    if (this->capacity() < NumElts)
+      this->grow(NumElts);
+    this->set_size(NumElts);
+    std::uninitialized_fill(this->begin(), this->end(), Elt);
+  }
+
+  template <typename in_iter,
+            typename = typename std::enable_if<std::is_convertible<
+                typename std::iterator_traits<in_iter>::iterator_category,
+                std::input_iterator_tag>::value>::type>
+  void assign(in_iter in_start, in_iter in_end) {
+    clear();
+    append(in_start, in_end);
+  }
+
+  void assign(std::initializer_list<T> IL) {
+    clear();
+    append(IL);
+  }
+
+  iterator erase(const_iterator CI) {
+    // Just cast away constness because this is a non-const member function.
+    iterator I = const_cast<iterator>(CI);
+
+    assert(I >= this->begin() && "Iterator to erase is out of bounds.");
+    assert(I < this->end() && "Erasing at past-the-end iterator.");
+
+    iterator N = I;
+    // Shift all elts down one.
+    std::move(I+1, this->end(), I);
+    // Drop the last elt.
+    this->pop_back();
+    return(N);
+  }
+
+  iterator erase(const_iterator CS, const_iterator CE) {
+    // Just cast away constness because this is a non-const member function.
+    iterator S = const_cast<iterator>(CS);
+    iterator E = const_cast<iterator>(CE);
+
+    assert(S >= this->begin() && "Range to erase is out of bounds.");
+    assert(S <= E && "Trying to erase invalid range.");
+    assert(E <= this->end() && "Trying to erase past the end.");
+
+    iterator N = S;
+    // Shift all elts down.
+    iterator I = std::move(E, this->end(), S);
+    // Drop the last elts.
+    this->destroy_range(I, this->end());
+    this->set_size(I - this->begin());
+    return(N);
+  }
+
+  iterator insert(iterator I, T &&Elt) {
+    if (I == this->end()) {  // Important special case for empty vector.
+      this->push_back(::std::move(Elt));
+      return this->end()-1;
+    }
+
+    assert(I >= this->begin() && "Insertion iterator is out of bounds.");
+    assert(I <= this->end() && "Inserting past the end of the vector.");
+
+    if (this->size() >= this->capacity()) {
+      size_t EltNo = I-this->begin();
+      this->grow();
+      I = this->begin()+EltNo;
+    }
+
+    ::new ((void*) this->end()) T(::std::move(this->back()));
+    // Push everything else over.
+    std::move_backward(I, this->end()-1, this->end());
+    this->set_size(this->size() + 1);
+
+    // If we just moved the element we're inserting, be sure to update
+    // the reference.
+    T *EltPtr = &Elt;
+    if (I <= EltPtr && EltPtr < this->end())
+      ++EltPtr;
+
+    *I = ::std::move(*EltPtr);
+    return I;
+  }
+
+  iterator insert(iterator I, const T &Elt) {
+    if (I == this->end()) {  // Important special case for empty vector.
+      this->push_back(Elt);
+      return this->end()-1;
+    }
+
+    assert(I >= this->begin() && "Insertion iterator is out of bounds.");
+    assert(I <= this->end() && "Inserting past the end of the vector.");
+
+    if (this->size() >= this->capacity()) {
+      size_t EltNo = I-this->begin();
+      this->grow();
+      I = this->begin()+EltNo;
+    }
+    ::new ((void*) this->end()) T(std::move(this->back()));
+    // Push everything else over.
+    std::move_backward(I, this->end()-1, this->end());
+    this->set_size(this->size() + 1);
+
+    // If we just moved the element we're inserting, be sure to update
+    // the reference.
+    const T *EltPtr = &Elt;
+    if (I <= EltPtr && EltPtr < this->end())
+      ++EltPtr;
+
+    *I = *EltPtr;
+    return I;
+  }
+
+  iterator insert(iterator I, size_type NumToInsert, const T &Elt) {
+    // Convert iterator to elt# to avoid invalidating iterator when we reserve()
+    size_t InsertElt = I - this->begin();
+
+    if (I == this->end()) {  // Important special case for empty vector.
+      append(NumToInsert, Elt);
+      return this->begin()+InsertElt;
+    }
+
+    assert(I >= this->begin() && "Insertion iterator is out of bounds.");
+    assert(I <= this->end() && "Inserting past the end of the vector.");
+
+    // Ensure there is enough space.
+    reserve(this->size() + NumToInsert);
+
+    // Uninvalidate the iterator.
+    I = this->begin()+InsertElt;
+
+    // If there are more elements between the insertion point and the end of the
+    // range than there are being inserted, we can use a simple approach to
+    // insertion.  Since we already reserved space, we know that this won't
+    // reallocate the vector.
+    if (size_t(this->end()-I) >= NumToInsert) {
+      T *OldEnd = this->end();
+      append(std::move_iterator<iterator>(this->end() - NumToInsert),
+             std::move_iterator<iterator>(this->end()));
+
+      // Copy the existing elements that get replaced.
+      std::move_backward(I, OldEnd-NumToInsert, OldEnd);
+
+      std::fill_n(I, NumToInsert, Elt);
+      return I;
+    }
+
+    // Otherwise, we're inserting more elements than exist already, and we're
+    // not inserting at the end.
+
+    // Move over the elements that we're about to overwrite.
+    T *OldEnd = this->end();
+    this->set_size(this->size() + NumToInsert);
+    size_t NumOverwritten = OldEnd-I;
+    this->uninitialized_move(I, OldEnd, this->end()-NumOverwritten);
+
+    // Replace the overwritten part.
+    std::fill_n(I, NumOverwritten, Elt);
+
+    // Insert the non-overwritten middle part.
+    std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt);
+    return I;
+  }
+
+  template <typename ItTy,
+            typename = typename std::enable_if<std::is_convertible<
+                typename std::iterator_traits<ItTy>::iterator_category,
+                std::input_iterator_tag>::value>::type>
+  iterator insert(iterator I, ItTy From, ItTy To) {
+    // Convert iterator to elt# to avoid invalidating iterator when we reserve()
+    size_t InsertElt = I - this->begin();
+
+    if (I == this->end()) {  // Important special case for empty vector.
+      append(From, To);
+      return this->begin()+InsertElt;
+    }
+
+    assert(I >= this->begin() && "Insertion iterator is out of bounds.");
+    assert(I <= this->end() && "Inserting past the end of the vector.");
+
+    size_t NumToInsert = std::distance(From, To);
+
+    // Ensure there is enough space.
+    reserve(this->size() + NumToInsert);
+
+    // Uninvalidate the iterator.
+    I = this->begin()+InsertElt;
+
+    // If there are more elements between the insertion point and the end of the
+    // range than there are being inserted, we can use a simple approach to
+    // insertion.  Since we already reserved space, we know that this won't
+    // reallocate the vector.
+    if (size_t(this->end()-I) >= NumToInsert) {
+      T *OldEnd = this->end();
+      append(std::move_iterator<iterator>(this->end() - NumToInsert),
+             std::move_iterator<iterator>(this->end()));
+
+      // Copy the existing elements that get replaced.
+      std::move_backward(I, OldEnd-NumToInsert, OldEnd);
+
+      std::copy(From, To, I);
+      return I;
+    }
+
+    // Otherwise, we're inserting more elements than exist already, and we're
+    // not inserting at the end.
+
+    // Move over the elements that we're about to overwrite.
+    T *OldEnd = this->end();
+    this->set_size(this->size() + NumToInsert);
+    size_t NumOverwritten = OldEnd-I;
+    this->uninitialized_move(I, OldEnd, this->end()-NumOverwritten);
+
+    // Replace the overwritten part.
+    for (T *J = I; NumOverwritten > 0; --NumOverwritten) {
+      *J = *From;
+      ++J; ++From;
+    }
+
+    // Insert the non-overwritten middle part.
+    this->uninitialized_copy(From, To, OldEnd);
+    return I;
+  }
+
+  void insert(iterator I, std::initializer_list<T> IL) {
+    insert(I, IL.begin(), IL.end());
+  }
+
+  template <typename... ArgTypes> reference emplace_back(ArgTypes &&... Args) {
+    if (LLVM_UNLIKELY(this->size() >= this->capacity()))
+      this->grow();
+    ::new ((void *)this->end()) T(std::forward<ArgTypes>(Args)...);
+    this->set_size(this->size() + 1);
+    return this->back();
+  }
+
+  SmallVectorImpl &operator=(const SmallVectorImpl &RHS);
+
+  SmallVectorImpl &operator=(SmallVectorImpl &&RHS);
+
+  bool operator==(const SmallVectorImpl &RHS) const {
+    if (this->size() != RHS.size()) return false;
+    return std::equal(this->begin(), this->end(), RHS.begin());
+  }
+  bool operator!=(const SmallVectorImpl &RHS) const {
+    return !(*this == RHS);
+  }
+
+  bool operator<(const SmallVectorImpl &RHS) const {
+    return std::lexicographical_compare(this->begin(), this->end(),
+                                        RHS.begin(), RHS.end());
+  }
+};
+
+template <typename T>
+void SmallVectorImpl<T>::swap(SmallVectorImpl<T> &RHS) {
+  if (this == &RHS) return;
+
+  // We can only avoid copying elements if neither vector is small.
+  if (!this->isSmall() && !RHS.isSmall()) {
+    std::swap(this->BeginX, RHS.BeginX);
+    std::swap(this->Size, RHS.Size);
+    std::swap(this->Capacity, RHS.Capacity);
+    return;
+  }
+  if (RHS.size() > this->capacity())
+    this->grow(RHS.size());
+  if (this->size() > RHS.capacity())
+    RHS.grow(this->size());
+
+  // Swap the shared elements.
+  size_t NumShared = this->size();
+  if (NumShared > RHS.size()) NumShared = RHS.size();
+  for (size_type i = 0; i != NumShared; ++i)
+    std::swap((*this)[i], RHS[i]);
+
+  // Copy over the extra elts.
+  if (this->size() > RHS.size()) {
+    size_t EltDiff = this->size() - RHS.size();
+    this->uninitialized_copy(this->begin()+NumShared, this->end(), RHS.end());
+    RHS.set_size(RHS.size() + EltDiff);
+    this->destroy_range(this->begin()+NumShared, this->end());
+    this->set_size(NumShared);
+  } else if (RHS.size() > this->size()) {
+    size_t EltDiff = RHS.size() - this->size();
+    this->uninitialized_copy(RHS.begin()+NumShared, RHS.end(), this->end());
+    this->set_size(this->size() + EltDiff);
+    this->destroy_range(RHS.begin()+NumShared, RHS.end());
+    RHS.set_size(NumShared);
+  }
+}
+
+template <typename T>
+SmallVectorImpl<T> &SmallVectorImpl<T>::
+  operator=(const SmallVectorImpl<T> &RHS) {
+  // Avoid self-assignment.
+  if (this == &RHS) return *this;
+
+  // If we already have sufficient space, assign the common elements, then
+  // destroy any excess.
+  size_t RHSSize = RHS.size();
+  size_t CurSize = this->size();
+  if (CurSize >= RHSSize) {
+    // Assign common elements.
+    iterator NewEnd;
+    if (RHSSize)
+      NewEnd = std::copy(RHS.begin(), RHS.begin()+RHSSize, this->begin());
+    else
+      NewEnd = this->begin();
+
+    // Destroy excess elements.
+    this->destroy_range(NewEnd, this->end());
+
+    // Trim.
+    this->set_size(RHSSize);
+    return *this;
+  }
+
+  // If we have to grow to have enough elements, destroy the current elements.
+  // This allows us to avoid copying them during the grow.
+  // FIXME: don't do this if they're efficiently moveable.
+  if (this->capacity() < RHSSize) {
+    // Destroy current elements.
+    this->destroy_range(this->begin(), this->end());
+    this->set_size(0);
+    CurSize = 0;
+    this->grow(RHSSize);
+  } else if (CurSize) {
+    // Otherwise, use assignment for the already-constructed elements.
+    std::copy(RHS.begin(), RHS.begin()+CurSize, this->begin());
+  }
+
+  // Copy construct the new elements in place.
+  this->uninitialized_copy(RHS.begin()+CurSize, RHS.end(),
+                           this->begin()+CurSize);
+
+  // Set end.
+  this->set_size(RHSSize);
+  return *this;
+}
+
+template <typename T>
+SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
+  // Avoid self-assignment.
+  if (this == &RHS) return *this;
+
+  // If the RHS isn't small, clear this vector and then steal its buffer.
+  if (!RHS.isSmall()) {
+    this->destroy_range(this->begin(), this->end());
+    if (!this->isSmall()) free(this->begin());
+    this->BeginX = RHS.BeginX;
+    this->Size = RHS.Size;
+    this->Capacity = RHS.Capacity;
+    RHS.resetToSmall();
+    return *this;
+  }
+
+  // If we already have sufficient space, assign the common elements, then
+  // destroy any excess.
+  size_t RHSSize = RHS.size();
+  size_t CurSize = this->size();
+  if (CurSize >= RHSSize) {
+    // Assign common elements.
+    iterator NewEnd = this->begin();
+    if (RHSSize)
+      NewEnd = std::move(RHS.begin(), RHS.end(), NewEnd);
+
+    // Destroy excess elements and trim the bounds.
+    this->destroy_range(NewEnd, this->end());
+    this->set_size(RHSSize);
+
+    // Clear the RHS.
+    RHS.clear();
+
+    return *this;
+  }
+
+  // If we have to grow to have enough elements, destroy the current elements.
+  // This allows us to avoid copying them during the grow.
+  // FIXME: this may not actually make any sense if we can efficiently move
+  // elements.
+  if (this->capacity() < RHSSize) {
+    // Destroy current elements.
+    this->destroy_range(this->begin(), this->end());
+    this->set_size(0);
+    CurSize = 0;
+    this->grow(RHSSize);
+  } else if (CurSize) {
+    // Otherwise, use assignment for the already-constructed elements.
+    std::move(RHS.begin(), RHS.begin()+CurSize, this->begin());
+  }
+
+  // Move-construct the new elements in place.
+  this->uninitialized_move(RHS.begin()+CurSize, RHS.end(),
+                           this->begin()+CurSize);
+
+  // Set end.
+  this->set_size(RHSSize);
+
+  RHS.clear();
+  return *this;
+}
+
+/// Storage for the SmallVector elements.  This is specialized for the N=0 case
+/// to avoid allocating unnecessary storage.
+template <typename T, unsigned N>
+struct SmallVectorStorage {
+  AlignedCharArrayUnion<T> InlineElts[N];
+};
+
+/// We need the storage to be properly aligned even for small-size of 0 so that
+/// the pointer math in \a SmallVectorTemplateCommon::getFirstEl() is
+/// well-defined.
+template <typename T> struct alignas(alignof(T)) SmallVectorStorage<T, 0> {};
+
+/// This is a 'vector' (really, a variable-sized array), optimized
+/// for the case when the array is small.  It contains some number of elements
+/// in-place, which allows it to avoid heap allocation when the actual number of
+/// elements is below that threshold.  This allows normal "small" cases to be
+/// fast without losing generality for large inputs.
+///
+/// Note that this does not attempt to be exception safe.
+///
+template <typename T, unsigned N>
+class SmallVector : public SmallVectorImpl<T>, SmallVectorStorage<T, N> {
+public:
+  SmallVector() : SmallVectorImpl<T>(N) {}
+
+  ~SmallVector() {
+    // Destroy the constructed elements in the vector.
+    this->destroy_range(this->begin(), this->end());
+  }
+
+  explicit SmallVector(size_t Size, const T &Value = T())
+    : SmallVectorImpl<T>(N) {
+    this->assign(Size, Value);
+  }
+
+  template <typename ItTy,
+            typename = typename std::enable_if<std::is_convertible<
+                typename std::iterator_traits<ItTy>::iterator_category,
+                std::input_iterator_tag>::value>::type>
+  SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N) {
+    this->append(S, E);
+  }
+
+  template <typename RangeTy>
+  explicit SmallVector(const iterator_range<RangeTy> &R)
+      : SmallVectorImpl<T>(N) {
+    this->append(R.begin(), R.end());
+  }
+
+  SmallVector(std::initializer_list<T> IL) : SmallVectorImpl<T>(N) {
+    this->assign(IL);
+  }
+
+  SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(N) {
+    if (!RHS.empty())
+      SmallVectorImpl<T>::operator=(RHS);
+  }
+
+  const SmallVector &operator=(const SmallVector &RHS) {
+    SmallVectorImpl<T>::operator=(RHS);
+    return *this;
+  }
+
+  SmallVector(SmallVector &&RHS) : SmallVectorImpl<T>(N) {
+    if (!RHS.empty())
+      SmallVectorImpl<T>::operator=(::std::move(RHS));
+  }
+
+  SmallVector(SmallVectorImpl<T> &&RHS) : SmallVectorImpl<T>(N) {
+    if (!RHS.empty())
+      SmallVectorImpl<T>::operator=(::std::move(RHS));
+  }
+
+  const SmallVector &operator=(SmallVector &&RHS) {
+    SmallVectorImpl<T>::operator=(::std::move(RHS));
+    return *this;
+  }
+
+  const SmallVector &operator=(SmallVectorImpl<T> &&RHS) {
+    SmallVectorImpl<T>::operator=(::std::move(RHS));
+    return *this;
+  }
+
+  const SmallVector &operator=(std::initializer_list<T> IL) {
+    this->assign(IL);
+    return *this;
+  }
+};
+
+template <typename T, unsigned N>
+inline size_t capacity_in_bytes(const SmallVector<T, N> &X) {
+  return X.capacity_in_bytes();
+}
+
+} // end namespace llvm
+
+namespace std {
+
+  /// Implement std::swap in terms of SmallVector swap.
+  template<typename T>
+  inline void
+  swap(llvm::SmallVectorImpl<T> &LHS, llvm::SmallVectorImpl<T> &RHS) {
+    LHS.swap(RHS);
+  }
+
+  /// Implement std::swap in terms of SmallVector swap.
+  template<typename T, unsigned N>
+  inline void
+  swap(llvm::SmallVector<T, N> &LHS, llvm::SmallVector<T, N> &RHS) {
+    LHS.swap(RHS);
+  }
+
+} // end namespace std
+
+#endif // LLVM_ADT_SMALLVECTOR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/StringExtras.h b/binaryen/third_party/llvm-project/include/llvm/ADT/StringExtras.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/StringExtras.h
@@ -0,0 +1,401 @@
+//===- llvm/ADT/StringExtras.h - Useful string functions --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains some functions that are useful when dealing with strings.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_STRINGEXTRAS_H
+#define LLVM_ADT_STRINGEXTRAS_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <iterator>
+#include <string>
+#include <utility>
+
+namespace llvm {
+
+template<typename T> class SmallVectorImpl;
+class raw_ostream;
+
+/// hexdigit - Return the hexadecimal character for the
+/// given number \p X (which should be less than 16).
+inline char hexdigit(unsigned X, bool LowerCase = false) {
+  const char HexChar = LowerCase ? 'a' : 'A';
+  return X < 10 ? '0' + X : HexChar + X - 10;
+}
+
+/// Given an array of c-style strings terminated by a null pointer, construct
+/// a vector of StringRefs representing the same strings without the terminating
+/// null string.
+inline std::vector<StringRef> toStringRefArray(const char *const *Strings) {
+  std::vector<StringRef> Result;
+  while (*Strings)
+    Result.push_back(*Strings++);
+  return Result;
+}
+
+/// Construct a string ref from a boolean.
+inline StringRef toStringRef(bool B) { return StringRef(B ? "true" : "false"); }
+
+/// Construct a string ref from an array ref of unsigned chars.
+inline StringRef toStringRef(ArrayRef<uint8_t> Input) {
+  return StringRef(reinterpret_cast<const char *>(Input.begin()), Input.size());
+}
+
+/// Construct a string ref from an array ref of unsigned chars.
+inline ArrayRef<uint8_t> arrayRefFromStringRef(StringRef Input) {
+  return {Input.bytes_begin(), Input.bytes_end()};
+}
+
+/// Interpret the given character \p C as a hexadecimal digit and return its
+/// value.
+///
+/// If \p C is not a valid hex digit, -1U is returned.
+inline unsigned hexDigitValue(char C) {
+  if (C >= '0' && C <= '9') return C-'0';
+  if (C >= 'a' && C <= 'f') return C-'a'+10U;
+  if (C >= 'A' && C <= 'F') return C-'A'+10U;
+  return -1U;
+}
+
+/// Checks if character \p C is one of the 10 decimal digits.
+inline bool isDigit(char C) { return C >= '0' && C <= '9'; }
+
+/// Checks if character \p C is a hexadecimal numeric character.
+inline bool isHexDigit(char C) { return hexDigitValue(C) != -1U; }
+
+/// Checks if character \p C is a valid letter as classified by "C" locale.
+inline bool isAlpha(char C) {
+  return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z');
+}
+
+/// Checks whether character \p C is either a decimal digit or an uppercase or
+/// lowercase letter as classified by "C" locale.
+inline bool isAlnum(char C) { return isAlpha(C) || isDigit(C); }
+
+/// Checks whether character \p C is valid ASCII (high bit is zero).
+inline bool isASCII(char C) { return static_cast<unsigned char>(C) <= 127; }
+
+/// Checks whether all characters in S are ASCII.
+inline bool isASCII(llvm::StringRef S) {
+  for (char C : S)
+    if (LLVM_UNLIKELY(!isASCII(C)))
+      return false;
+  return true;
+}
+
+/// Checks whether character \p C is printable.
+///
+/// Locale-independent version of the C standard library isprint whose results
+/// may differ on different platforms.
+inline bool isPrint(char C) {
+  unsigned char UC = static_cast<unsigned char>(C);
+  return (0x20 <= UC) && (UC <= 0x7E);
+}
+
+/// Returns the corresponding lowercase character if \p x is uppercase.
+inline char toLower(char x) {
+  if (x >= 'A' && x <= 'Z')
+    return x - 'A' + 'a';
+  return x;
+}
+
+/// Returns the corresponding uppercase character if \p x is lowercase.
+inline char toUpper(char x) {
+  if (x >= 'a' && x <= 'z')
+    return x - 'a' + 'A';
+  return x;
+}
+
+inline std::string utohexstr(uint64_t X, bool LowerCase = false) {
+  char Buffer[17];
+  char *BufPtr = std::end(Buffer);
+
+  if (X == 0) *--BufPtr = '0';
+
+  while (X) {
+    unsigned char Mod = static_cast<unsigned char>(X) & 15;
+    *--BufPtr = hexdigit(Mod, LowerCase);
+    X >>= 4;
+  }
+
+  return std::string(BufPtr, std::end(Buffer));
+}
+
+/// Convert buffer \p Input to its hexadecimal representation.
+/// The returned string is double the size of \p Input.
+inline std::string toHex(StringRef Input, bool LowerCase = false) {
+  static const char *const LUT = "0123456789ABCDEF";
+  const uint8_t Offset = LowerCase ? 32 : 0;
+  size_t Length = Input.size();
+
+  std::string Output;
+  Output.reserve(2 * Length);
+  for (size_t i = 0; i < Length; ++i) {
+    const unsigned char c = Input[i];
+    Output.push_back(LUT[c >> 4] | Offset);
+    Output.push_back(LUT[c & 15] | Offset);
+  }
+  return Output;
+}
+
+inline std::string toHex(ArrayRef<uint8_t> Input, bool LowerCase = false) {
+  return toHex(toStringRef(Input), LowerCase);
+}
+
+inline uint8_t hexFromNibbles(char MSB, char LSB) {
+  unsigned U1 = hexDigitValue(MSB);
+  unsigned U2 = hexDigitValue(LSB);
+  assert(U1 != -1U && U2 != -1U);
+
+  return static_cast<uint8_t>((U1 << 4) | U2);
+}
+
+/// Convert hexadecimal string \p Input to its binary representation.
+/// The return string is half the size of \p Input.
+inline std::string fromHex(StringRef Input) {
+  if (Input.empty())
+    return std::string();
+
+  std::string Output;
+  Output.reserve((Input.size() + 1) / 2);
+  if (Input.size() % 2 == 1) {
+    Output.push_back(hexFromNibbles('0', Input.front()));
+    Input = Input.drop_front();
+  }
+
+  assert(Input.size() % 2 == 0);
+  while (!Input.empty()) {
+    uint8_t Hex = hexFromNibbles(Input[0], Input[1]);
+    Output.push_back(Hex);
+    Input = Input.drop_front(2);
+  }
+  return Output;
+}
+
+/// Convert the string \p S to an integer of the specified type using
+/// the radix \p Base.  If \p Base is 0, auto-detects the radix.
+/// Returns true if the number was successfully converted, false otherwise.
+template <typename N> bool to_integer(StringRef S, N &Num, unsigned Base = 0) {
+  return !S.getAsInteger(Base, Num);
+}
+
+namespace detail {
+template <typename N>
+inline bool to_float(const Twine &T, N &Num, N (*StrTo)(const char *, char **)) {
+  SmallString<32> Storage;
+  StringRef S = T.toNullTerminatedStringRef(Storage);
+  char *End;
+  N Temp = StrTo(S.data(), &End);
+  if (*End != '\0')
+    return false;
+  Num = Temp;
+  return true;
+}
+}
+
+inline bool to_float(const Twine &T, float &Num) {
+  return detail::to_float(T, Num, strtof);
+}
+
+inline bool to_float(const Twine &T, double &Num) {
+  return detail::to_float(T, Num, strtod);
+}
+
+inline bool to_float(const Twine &T, long double &Num) {
+  return detail::to_float(T, Num, strtold);
+}
+
+inline std::string utostr(uint64_t X, bool isNeg = false) {
+  char Buffer[21];
+  char *BufPtr = std::end(Buffer);
+
+  if (X == 0) *--BufPtr = '0';  // Handle special case...
+
+  while (X) {
+    *--BufPtr = '0' + char(X % 10);
+    X /= 10;
+  }
+
+  if (isNeg) *--BufPtr = '-';   // Add negative sign...
+  return std::string(BufPtr, std::end(Buffer));
+}
+
+inline std::string itostr(int64_t X) {
+  if (X < 0)
+    return utostr(static_cast<uint64_t>(-X), true);
+  else
+    return utostr(static_cast<uint64_t>(X));
+}
+
+/// StrInStrNoCase - Portable version of strcasestr.  Locates the first
+/// occurrence of string 's1' in string 's2', ignoring case.  Returns
+/// the offset of s2 in s1 or npos if s2 cannot be found.
+StringRef::size_type StrInStrNoCase(StringRef s1, StringRef s2);
+
+/// getToken - This function extracts one token from source, ignoring any
+/// leading characters that appear in the Delimiters string, and ending the
+/// token at any of the characters that appear in the Delimiters string.  If
+/// there are no tokens in the source string, an empty string is returned.
+/// The function returns a pair containing the extracted token and the
+/// remaining tail string.
+std::pair<StringRef, StringRef> getToken(StringRef Source,
+                                         StringRef Delimiters = " \t\n\v\f\r");
+
+/// SplitString - Split up the specified string according to the specified
+/// delimiters, appending the result fragments to the output list.
+void SplitString(StringRef Source,
+                 SmallVectorImpl<StringRef> &OutFragments,
+                 StringRef Delimiters = " \t\n\v\f\r");
+
+/// Returns the English suffix for an ordinal integer (-st, -nd, -rd, -th).
+inline StringRef getOrdinalSuffix(unsigned Val) {
+  // It is critically important that we do this perfectly for
+  // user-written sequences with over 100 elements.
+  switch (Val % 100) {
+  case 11:
+  case 12:
+  case 13:
+    return "th";
+  default:
+    switch (Val % 10) {
+      case 1: return "st";
+      case 2: return "nd";
+      case 3: return "rd";
+      default: return "th";
+    }
+  }
+}
+
+/// Print each character of the specified string, escaping it if it is not
+/// printable or if it is an escape char.
+void printEscapedString(StringRef Name, raw_ostream &Out);
+
+/// Print each character of the specified string, escaping HTML special
+/// characters.
+void printHTMLEscaped(StringRef String, raw_ostream &Out);
+
+/// printLowerCase - Print each character as lowercase if it is uppercase.
+void printLowerCase(StringRef String, raw_ostream &Out);
+
+namespace detail {
+
+template <typename IteratorT>
+inline std::string join_impl(IteratorT Begin, IteratorT End,
+                             StringRef Separator, std::input_iterator_tag) {
+  std::string S;
+  if (Begin == End)
+    return S;
+
+  S += (*Begin);
+  while (++Begin != End) {
+    S += Separator;
+    S += (*Begin);
+  }
+  return S;
+}
+
+template <typename IteratorT>
+inline std::string join_impl(IteratorT Begin, IteratorT End,
+                             StringRef Separator, std::forward_iterator_tag) {
+  std::string S;
+  if (Begin == End)
+    return S;
+
+  size_t Len = (std::distance(Begin, End) - 1) * Separator.size();
+  for (IteratorT I = Begin; I != End; ++I)
+    Len += (*Begin).size();
+  S.reserve(Len);
+  S += (*Begin);
+  while (++Begin != End) {
+    S += Separator;
+    S += (*Begin);
+  }
+  return S;
+}
+
+template <typename Sep>
+inline void join_items_impl(std::string &Result, Sep Separator) {}
+
+template <typename Sep, typename Arg>
+inline void join_items_impl(std::string &Result, Sep Separator,
+                            const Arg &Item) {
+  Result += Item;
+}
+
+template <typename Sep, typename Arg1, typename... Args>
+inline void join_items_impl(std::string &Result, Sep Separator, const Arg1 &A1,
+                            Args &&... Items) {
+  Result += A1;
+  Result += Separator;
+  join_items_impl(Result, Separator, std::forward<Args>(Items)...);
+}
+
+inline size_t join_one_item_size(char) { return 1; }
+inline size_t join_one_item_size(const char *S) { return S ? ::strlen(S) : 0; }
+
+template <typename T> inline size_t join_one_item_size(const T &Str) {
+  return Str.size();
+}
+
+inline size_t join_items_size() { return 0; }
+
+template <typename A1> inline size_t join_items_size(const A1 &A) {
+  return join_one_item_size(A);
+}
+template <typename A1, typename... Args>
+inline size_t join_items_size(const A1 &A, Args &&... Items) {
+  return join_one_item_size(A) + join_items_size(std::forward<Args>(Items)...);
+}
+
+} // end namespace detail
+
+/// Joins the strings in the range [Begin, End), adding Separator between
+/// the elements.
+template <typename IteratorT>
+inline std::string join(IteratorT Begin, IteratorT End, StringRef Separator) {
+  using tag = typename std::iterator_traits<IteratorT>::iterator_category;
+  return detail::join_impl(Begin, End, Separator, tag());
+}
+
+/// Joins the strings in the range [R.begin(), R.end()), adding Separator
+/// between the elements.
+template <typename Range>
+inline std::string join(Range &&R, StringRef Separator) {
+  return join(R.begin(), R.end(), Separator);
+}
+
+/// Joins the strings in the parameter pack \p Items, adding \p Separator
+/// between the elements.  All arguments must be implicitly convertible to
+/// std::string, or there should be an overload of std::string::operator+=()
+/// that accepts the argument explicitly.
+template <typename Sep, typename... Args>
+inline std::string join_items(Sep Separator, Args &&... Items) {
+  std::string Result;
+  if (sizeof...(Items) == 0)
+    return Result;
+
+  size_t NS = detail::join_one_item_size(Separator);
+  size_t NI = detail::join_items_size(std::forward<Args>(Items)...);
+  Result.reserve(NI + (sizeof...(Items) - 1) * NS + 1);
+  detail::join_items_impl(Result, Separator, std::forward<Args>(Items)...);
+  return Result;
+}
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_STRINGEXTRAS_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/StringMap.h b/binaryen/third_party/llvm-project/include/llvm/ADT/StringMap.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/StringMap.h
@@ -0,0 +1,593 @@
+//===- StringMap.h - String Hash table map interface ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the StringMap class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_STRINGMAP_H
+#define LLVM_ADT_STRINGMAP_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <initializer_list>
+#include <iterator>
+#include <utility>
+
+namespace llvm {
+
+template<typename ValueTy> class StringMapConstIterator;
+template<typename ValueTy> class StringMapIterator;
+template<typename ValueTy> class StringMapKeyIterator;
+
+/// StringMapEntryBase - Shared base class of StringMapEntry instances.
+class StringMapEntryBase {
+  size_t StrLen;
+
+public:
+  explicit StringMapEntryBase(size_t Len) : StrLen(Len) {}
+
+  size_t getKeyLength() const { return StrLen; }
+};
+
+/// StringMapImpl - This is the base class of StringMap that is shared among
+/// all of its instantiations.
+class StringMapImpl {
+protected:
+  // Array of NumBuckets pointers to entries, null pointers are holes.
+  // TheTable[NumBuckets] contains a sentinel value for easy iteration. Followed
+  // by an array of the actual hash values as unsigned integers.
+  StringMapEntryBase **TheTable = nullptr;
+  unsigned NumBuckets = 0;
+  unsigned NumItems = 0;
+  unsigned NumTombstones = 0;
+  unsigned ItemSize;
+
+protected:
+  explicit StringMapImpl(unsigned itemSize)
+      : ItemSize(itemSize) {}
+  StringMapImpl(StringMapImpl &&RHS)
+      : TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets),
+        NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones),
+        ItemSize(RHS.ItemSize) {
+    RHS.TheTable = nullptr;
+    RHS.NumBuckets = 0;
+    RHS.NumItems = 0;
+    RHS.NumTombstones = 0;
+  }
+
+  StringMapImpl(unsigned InitSize, unsigned ItemSize);
+  unsigned RehashTable(unsigned BucketNo = 0);
+
+  /// LookupBucketFor - Look up the bucket that the specified string should end
+  /// up in.  If it already exists as a key in the map, the Item pointer for the
+  /// specified bucket will be non-null.  Otherwise, it will be null.  In either
+  /// case, the FullHashValue field of the bucket will be set to the hash value
+  /// of the string.
+  unsigned LookupBucketFor(StringRef Key);
+
+  /// FindKey - Look up the bucket that contains the specified key. If it exists
+  /// in the map, return the bucket number of the key.  Otherwise return -1.
+  /// This does not modify the map.
+  int FindKey(StringRef Key) const;
+
+  /// RemoveKey - Remove the specified StringMapEntry from the table, but do not
+  /// delete it.  This aborts if the value isn't in the table.
+  void RemoveKey(StringMapEntryBase *V);
+
+  /// RemoveKey - Remove the StringMapEntry for the specified key from the
+  /// table, returning it.  If the key is not in the table, this returns null.
+  StringMapEntryBase *RemoveKey(StringRef Key);
+
+  /// Allocate the table with the specified number of buckets and otherwise
+  /// setup the map as empty.
+  void init(unsigned Size);
+
+public:
+  static StringMapEntryBase *getTombstoneVal() {
+    uintptr_t Val = static_cast<uintptr_t>(-1);
+    Val <<= PointerLikeTypeTraits<StringMapEntryBase *>::NumLowBitsAvailable;
+    return reinterpret_cast<StringMapEntryBase *>(Val);
+  }
+
+  unsigned getNumBuckets() const { return NumBuckets; }
+  unsigned getNumItems() const { return NumItems; }
+
+  bool empty() const { return NumItems == 0; }
+  unsigned size() const { return NumItems; }
+
+  void swap(StringMapImpl &Other) {
+    std::swap(TheTable, Other.TheTable);
+    std::swap(NumBuckets, Other.NumBuckets);
+    std::swap(NumItems, Other.NumItems);
+    std::swap(NumTombstones, Other.NumTombstones);
+  }
+};
+
+/// StringMapEntryStorage - Holds the value in a StringMapEntry.
+///
+/// Factored out into a separate base class to make it easier to specialize.
+/// This is primarily intended to support StringSet, which doesn't need a value
+/// stored at all.
+template<typename ValueTy>
+class StringMapEntryStorage : public StringMapEntryBase {
+public:
+  ValueTy second;
+
+  explicit StringMapEntryStorage(size_t strLen)
+    : StringMapEntryBase(strLen), second() {}
+  template <typename... InitTy>
+  StringMapEntryStorage(size_t strLen, InitTy &&... InitVals)
+      : StringMapEntryBase(strLen), second(std::forward<InitTy>(InitVals)...) {}
+  StringMapEntryStorage(StringMapEntryStorage &E) = delete;
+
+  const ValueTy &getValue() const { return second; }
+  ValueTy &getValue() { return second; }
+
+  void setValue(const ValueTy &V) { second = V; }
+};
+
+template<>
+class StringMapEntryStorage<NoneType> : public StringMapEntryBase {
+public:
+  explicit StringMapEntryStorage(size_t strLen, NoneType none = None)
+    : StringMapEntryBase(strLen) {}
+  StringMapEntryStorage(StringMapEntryStorage &E) = delete;
+
+  NoneType getValue() const { return None; }
+};
+
+/// StringMapEntry - This is used to represent one value that is inserted into
+/// a StringMap.  It contains the Value itself and the key: the string length
+/// and data.
+template<typename ValueTy>
+class StringMapEntry final : public StringMapEntryStorage<ValueTy> {
+public:
+  using StringMapEntryStorage<ValueTy>::StringMapEntryStorage;
+
+  StringRef getKey() const {
+    return StringRef(getKeyData(), this->getKeyLength());
+  }
+
+  /// getKeyData - Return the start of the string data that is the key for this
+  /// value.  The string data is always stored immediately after the
+  /// StringMapEntry object.
+  const char *getKeyData() const {return reinterpret_cast<const char*>(this+1);}
+
+  StringRef first() const {
+    return StringRef(getKeyData(), this->getKeyLength());
+  }
+
+  /// Create a StringMapEntry for the specified key construct the value using
+  /// \p InitiVals.
+  template <typename AllocatorTy, typename... InitTy>
+  static StringMapEntry *Create(StringRef Key, AllocatorTy &Allocator,
+                                InitTy &&... InitVals) {
+    size_t KeyLength = Key.size();
+
+    // Allocate a new item with space for the string at the end and a null
+    // terminator.
+    size_t AllocSize = sizeof(StringMapEntry) + KeyLength + 1;
+    size_t Alignment = alignof(StringMapEntry);
+
+    StringMapEntry *NewItem =
+      static_cast<StringMapEntry*>(Allocator.Allocate(AllocSize,Alignment));
+    assert(NewItem && "Unhandled out-of-memory");
+
+    // Construct the value.
+    new (NewItem) StringMapEntry(KeyLength, std::forward<InitTy>(InitVals)...);
+
+    // Copy the string information.
+    char *StrBuffer = const_cast<char*>(NewItem->getKeyData());
+    if (KeyLength > 0)
+      memcpy(StrBuffer, Key.data(), KeyLength);
+    StrBuffer[KeyLength] = 0;  // Null terminate for convenience of clients.
+    return NewItem;
+  }
+
+  /// Create - Create a StringMapEntry with normal malloc/free.
+  template <typename... InitType>
+  static StringMapEntry *Create(StringRef Key, InitType &&... InitVal) {
+    MallocAllocator A;
+    return Create(Key, A, std::forward<InitType>(InitVal)...);
+  }
+
+  static StringMapEntry *Create(StringRef Key) {
+    return Create(Key, ValueTy());
+  }
+
+  /// GetStringMapEntryFromKeyData - Given key data that is known to be embedded
+  /// into a StringMapEntry, return the StringMapEntry itself.
+  static StringMapEntry &GetStringMapEntryFromKeyData(const char *KeyData) {
+    char *Ptr = const_cast<char*>(KeyData) - sizeof(StringMapEntry<ValueTy>);
+    return *reinterpret_cast<StringMapEntry*>(Ptr);
+  }
+
+  /// Destroy - Destroy this StringMapEntry, releasing memory back to the
+  /// specified allocator.
+  template<typename AllocatorTy>
+  void Destroy(AllocatorTy &Allocator) {
+    // Free memory referenced by the item.
+    size_t AllocSize = sizeof(StringMapEntry) + this->getKeyLength() + 1;
+    this->~StringMapEntry();
+    Allocator.Deallocate(static_cast<void *>(this), AllocSize);
+  }
+
+  /// Destroy this object, releasing memory back to the malloc allocator.
+  void Destroy() {
+    MallocAllocator A;
+    Destroy(A);
+  }
+};
+
+/// StringMap - This is an unconventional map that is specialized for handling
+/// keys that are "strings", which are basically ranges of bytes. This does some
+/// funky memory allocation and hashing things to make it extremely efficient,
+/// storing the string data *after* the value in the map.
+template<typename ValueTy, typename AllocatorTy = MallocAllocator>
+class StringMap : public StringMapImpl {
+  AllocatorTy Allocator;
+
+public:
+  using MapEntryTy = StringMapEntry<ValueTy>;
+
+  StringMap() : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {}
+
+  explicit StringMap(unsigned InitialSize)
+    : StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
+
+  explicit StringMap(AllocatorTy A)
+    : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))), Allocator(A) {}
+
+  StringMap(unsigned InitialSize, AllocatorTy A)
+    : StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))),
+      Allocator(A) {}
+
+  StringMap(std::initializer_list<std::pair<StringRef, ValueTy>> List)
+      : StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) {
+    for (const auto &P : List) {
+      insert(P);
+    }
+  }
+
+  StringMap(StringMap &&RHS)
+      : StringMapImpl(std::move(RHS)), Allocator(std::move(RHS.Allocator)) {}
+
+  StringMap(const StringMap &RHS) :
+    StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))),
+    Allocator(RHS.Allocator) {
+    if (RHS.empty())
+      return;
+
+    // Allocate TheTable of the same size as RHS's TheTable, and set the
+    // sentinel appropriately (and NumBuckets).
+    init(RHS.NumBuckets);
+    unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1),
+             *RHSHashTable = (unsigned *)(RHS.TheTable + NumBuckets + 1);
+
+    NumItems = RHS.NumItems;
+    NumTombstones = RHS.NumTombstones;
+    for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
+      StringMapEntryBase *Bucket = RHS.TheTable[I];
+      if (!Bucket || Bucket == getTombstoneVal()) {
+        TheTable[I] = Bucket;
+        continue;
+      }
+
+      TheTable[I] = MapEntryTy::Create(
+          static_cast<MapEntryTy *>(Bucket)->getKey(), Allocator,
+          static_cast<MapEntryTy *>(Bucket)->getValue());
+      HashTable[I] = RHSHashTable[I];
+    }
+
+    // Note that here we've copied everything from the RHS into this object,
+    // tombstones included. We could, instead, have re-probed for each key to
+    // instantiate this new object without any tombstone buckets. The
+    // assumption here is that items are rarely deleted from most StringMaps,
+    // and so tombstones are rare, so the cost of re-probing for all inputs is
+    // not worthwhile.
+  }
+
+  StringMap &operator=(StringMap RHS) {
+    StringMapImpl::swap(RHS);
+    std::swap(Allocator, RHS.Allocator);
+    return *this;
+  }
+
+  ~StringMap() {
+    // Delete all the elements in the map, but don't reset the elements
+    // to default values.  This is a copy of clear(), but avoids unnecessary
+    // work not required in the destructor.
+    if (!empty()) {
+      for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
+        StringMapEntryBase *Bucket = TheTable[I];
+        if (Bucket && Bucket != getTombstoneVal()) {
+          static_cast<MapEntryTy*>(Bucket)->Destroy(Allocator);
+        }
+      }
+    }
+    free(TheTable);
+  }
+
+  AllocatorTy &getAllocator() { return Allocator; }
+  const AllocatorTy &getAllocator() const { return Allocator; }
+
+  using key_type = const char*;
+  using mapped_type = ValueTy;
+  using value_type = StringMapEntry<ValueTy>;
+  using size_type = size_t;
+
+  using const_iterator = StringMapConstIterator<ValueTy>;
+  using iterator = StringMapIterator<ValueTy>;
+
+  iterator begin() {
+    return iterator(TheTable, NumBuckets == 0);
+  }
+  iterator end() {
+    return iterator(TheTable+NumBuckets, true);
+  }
+  const_iterator begin() const {
+    return const_iterator(TheTable, NumBuckets == 0);
+  }
+  const_iterator end() const {
+    return const_iterator(TheTable+NumBuckets, true);
+  }
+
+  iterator_range<StringMapKeyIterator<ValueTy>> keys() const {
+    return make_range(StringMapKeyIterator<ValueTy>(begin()),
+                      StringMapKeyIterator<ValueTy>(end()));
+  }
+
+  iterator find(StringRef Key) {
+    int Bucket = FindKey(Key);
+    if (Bucket == -1) return end();
+    return iterator(TheTable+Bucket, true);
+  }
+
+  const_iterator find(StringRef Key) const {
+    int Bucket = FindKey(Key);
+    if (Bucket == -1) return end();
+    return const_iterator(TheTable+Bucket, true);
+  }
+
+  /// lookup - Return the entry for the specified key, or a default
+  /// constructed value if no such entry exists.
+  ValueTy lookup(StringRef Key) const {
+    const_iterator it = find(Key);
+    if (it != end())
+      return it->second;
+    return ValueTy();
+  }
+
+  /// Lookup the ValueTy for the \p Key, or create a default constructed value
+  /// if the key is not in the map.
+  ValueTy &operator[](StringRef Key) { return try_emplace(Key).first->second; }
+
+  /// count - Return 1 if the element is in the map, 0 otherwise.
+  size_type count(StringRef Key) const {
+    return find(Key) == end() ? 0 : 1;
+  }
+
+  template <typename InputTy>
+  size_type count(const StringMapEntry<InputTy> &MapEntry) const {
+    return count(MapEntry.getKey());
+  }
+
+  /// insert - Insert the specified key/value pair into the map.  If the key
+  /// already exists in the map, return false and ignore the request, otherwise
+  /// insert it and return true.
+  bool insert(MapEntryTy *KeyValue) {
+    unsigned BucketNo = LookupBucketFor(KeyValue->getKey());
+    StringMapEntryBase *&Bucket = TheTable[BucketNo];
+    if (Bucket && Bucket != getTombstoneVal())
+      return false;  // Already exists in map.
+
+    if (Bucket == getTombstoneVal())
+      --NumTombstones;
+    Bucket = KeyValue;
+    ++NumItems;
+    assert(NumItems + NumTombstones <= NumBuckets);
+
+    RehashTable();
+    return true;
+  }
+
+  /// insert - Inserts the specified key/value pair into the map if the key
+  /// isn't already in the map. The bool component of the returned pair is true
+  /// if and only if the insertion takes place, and the iterator component of
+  /// the pair points to the element with key equivalent to the key of the pair.
+  std::pair<iterator, bool> insert(std::pair<StringRef, ValueTy> KV) {
+    return try_emplace(KV.first, std::move(KV.second));
+  }
+
+  /// Inserts an element or assigns to the current element if the key already
+  /// exists. The return type is the same as try_emplace.
+  template <typename V>
+  std::pair<iterator, bool> insert_or_assign(StringRef Key, V &&Val) {
+    auto Ret = try_emplace(Key, std::forward<V>(Val));
+    if (!Ret.second)
+      Ret.first->second = std::forward<V>(Val);
+    return Ret;
+  }
+
+  /// Emplace a new element for the specified key into the map if the key isn't
+  /// already in the map. The bool component of the returned pair is true
+  /// if and only if the insertion takes place, and the iterator component of
+  /// the pair points to the element with key equivalent to the key of the pair.
+  template <typename... ArgsTy>
+  std::pair<iterator, bool> try_emplace(StringRef Key, ArgsTy &&... Args) {
+    unsigned BucketNo = LookupBucketFor(Key);
+    StringMapEntryBase *&Bucket = TheTable[BucketNo];
+    if (Bucket && Bucket != getTombstoneVal())
+      return std::make_pair(iterator(TheTable + BucketNo, false),
+                            false); // Already exists in map.
+
+    if (Bucket == getTombstoneVal())
+      --NumTombstones;
+    Bucket = MapEntryTy::Create(Key, Allocator, std::forward<ArgsTy>(Args)...);
+    ++NumItems;
+    assert(NumItems + NumTombstones <= NumBuckets);
+
+    BucketNo = RehashTable(BucketNo);
+    return std::make_pair(iterator(TheTable + BucketNo, false), true);
+  }
+
+  // clear - Empties out the StringMap
+  void clear() {
+    if (empty()) return;
+
+    // Zap all values, resetting the keys back to non-present (not tombstone),
+    // which is safe because we're removing all elements.
+    for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
+      StringMapEntryBase *&Bucket = TheTable[I];
+      if (Bucket && Bucket != getTombstoneVal()) {
+        static_cast<MapEntryTy*>(Bucket)->Destroy(Allocator);
+      }
+      Bucket = nullptr;
+    }
+
+    NumItems = 0;
+    NumTombstones = 0;
+  }
+
+  /// remove - Remove the specified key/value pair from the map, but do not
+  /// erase it.  This aborts if the key is not in the map.
+  void remove(MapEntryTy *KeyValue) {
+    RemoveKey(KeyValue);
+  }
+
+  void erase(iterator I) {
+    MapEntryTy &V = *I;
+    remove(&V);
+    V.Destroy(Allocator);
+  }
+
+  bool erase(StringRef Key) {
+    iterator I = find(Key);
+    if (I == end()) return false;
+    erase(I);
+    return true;
+  }
+};
+
+template <typename DerivedTy, typename ValueTy>
+class StringMapIterBase
+    : public iterator_facade_base<DerivedTy, std::forward_iterator_tag,
+                                  ValueTy> {
+protected:
+  StringMapEntryBase **Ptr = nullptr;
+
+public:
+  StringMapIterBase() = default;
+
+  explicit StringMapIterBase(StringMapEntryBase **Bucket,
+                             bool NoAdvance = false)
+      : Ptr(Bucket) {
+    if (!NoAdvance) AdvancePastEmptyBuckets();
+  }
+
+  DerivedTy &operator=(const DerivedTy &Other) {
+    Ptr = Other.Ptr;
+    return static_cast<DerivedTy &>(*this);
+  }
+
+  bool operator==(const DerivedTy &RHS) const { return Ptr == RHS.Ptr; }
+
+  DerivedTy &operator++() { // Preincrement
+    ++Ptr;
+    AdvancePastEmptyBuckets();
+    return static_cast<DerivedTy &>(*this);
+  }
+
+  DerivedTy operator++(int) { // Post-increment
+    DerivedTy Tmp(Ptr);
+    ++*this;
+    return Tmp;
+  }
+
+private:
+  void AdvancePastEmptyBuckets() {
+    while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
+      ++Ptr;
+  }
+};
+
+template <typename ValueTy>
+class StringMapConstIterator
+    : public StringMapIterBase<StringMapConstIterator<ValueTy>,
+                               const StringMapEntry<ValueTy>> {
+  using base = StringMapIterBase<StringMapConstIterator<ValueTy>,
+                                 const StringMapEntry<ValueTy>>;
+
+public:
+  StringMapConstIterator() = default;
+  explicit StringMapConstIterator(StringMapEntryBase **Bucket,
+                                  bool NoAdvance = false)
+      : base(Bucket, NoAdvance) {}
+
+  const StringMapEntry<ValueTy> &operator*() const {
+    return *static_cast<const StringMapEntry<ValueTy> *>(*this->Ptr);
+  }
+};
+
+template <typename ValueTy>
+class StringMapIterator : public StringMapIterBase<StringMapIterator<ValueTy>,
+                                                   StringMapEntry<ValueTy>> {
+  using base =
+      StringMapIterBase<StringMapIterator<ValueTy>, StringMapEntry<ValueTy>>;
+
+public:
+  StringMapIterator() = default;
+  explicit StringMapIterator(StringMapEntryBase **Bucket,
+                             bool NoAdvance = false)
+      : base(Bucket, NoAdvance) {}
+
+  StringMapEntry<ValueTy> &operator*() const {
+    return *static_cast<StringMapEntry<ValueTy> *>(*this->Ptr);
+  }
+
+  operator StringMapConstIterator<ValueTy>() const {
+    return StringMapConstIterator<ValueTy>(this->Ptr, true);
+  }
+};
+
+template <typename ValueTy>
+class StringMapKeyIterator
+    : public iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
+                                   StringMapConstIterator<ValueTy>,
+                                   std::forward_iterator_tag, StringRef> {
+  using base = iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
+                                     StringMapConstIterator<ValueTy>,
+                                     std::forward_iterator_tag, StringRef>;
+
+public:
+  StringMapKeyIterator() = default;
+  explicit StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter)
+      : base(std::move(Iter)) {}
+
+  StringRef &operator*() {
+    Key = this->wrapped()->getKey();
+    return Key;
+  }
+
+private:
+  StringRef Key;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_STRINGMAP_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/StringRef.h b/binaryen/third_party/llvm-project/include/llvm/ADT/StringRef.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/StringRef.h
@@ -0,0 +1,920 @@
+//===- StringRef.h - Constant String Reference Wrapper ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_STRINGREF_H
+#define LLVM_ADT_STRINGREF_H
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Compiler.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <limits>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+// Declare the __builtin_strlen intrinsic for MSVC so it can be used in
+// constexpr context.
+#if defined(_MSC_VER)
+extern "C" size_t __builtin_strlen(const char *);
+#endif
+
+namespace llvm {
+
+  class APInt;
+  class hash_code;
+  template <typename T> class SmallVectorImpl;
+  class StringRef;
+
+  /// Helper functions for StringRef::getAsInteger.
+  bool getAsUnsignedInteger(StringRef Str, unsigned Radix,
+                            unsigned long long &Result);
+
+  bool getAsSignedInteger(StringRef Str, unsigned Radix, long long &Result);
+
+  bool consumeUnsignedInteger(StringRef &Str, unsigned Radix,
+                              unsigned long long &Result);
+  bool consumeSignedInteger(StringRef &Str, unsigned Radix, long long &Result);
+
+  /// StringRef - Represent a constant reference to a string, i.e. a character
+  /// array and a length, which need not be null terminated.
+  ///
+  /// This class does not own the string data, it is expected to be used in
+  /// situations where the character data resides in some other buffer, whose
+  /// lifetime extends past that of the StringRef. For this reason, it is not in
+  /// general safe to store a StringRef.
+  class StringRef {
+  public:
+    static const size_t npos = ~size_t(0);
+
+    using iterator = const char *;
+    using const_iterator = const char *;
+    using size_type = size_t;
+
+  private:
+    /// The start of the string, in an external buffer.
+    const char *Data = nullptr;
+
+    /// The length of the string.
+    size_t Length = 0;
+
+    // Workaround memcmp issue with null pointers (undefined behavior)
+    // by providing a specialized version
+    static int compareMemory(const char *Lhs, const char *Rhs, size_t Length) {
+      if (Length == 0) { return 0; }
+      return ::memcmp(Lhs,Rhs,Length);
+    }
+
+    // Constexpr version of std::strlen.
+    static constexpr size_t strLen(const char *Str) {
+#if __cplusplus > 201402L
+      return std::char_traits<char>::length(Str);
+#elif __has_builtin(__builtin_strlen) || defined(__GNUC__) || defined(_MSC_VER)
+      return __builtin_strlen(Str);
+#else
+      const char *Begin = Str;
+      while (*Str != '\0')
+        ++Str;
+      return Str - Begin;
+#endif
+    }
+
+  public:
+    /// @name Constructors
+    /// @{
+
+    /// Construct an empty string ref.
+    /*implicit*/ StringRef() = default;
+
+    /// Disable conversion from nullptr.  This prevents things like
+    /// if (S == nullptr)
+    StringRef(std::nullptr_t) = delete;
+
+    /// Construct a string ref from a cstring.
+    /*implicit*/ constexpr StringRef(const char *Str)
+        : Data(Str), Length(Str ? strLen(Str) : 0) {}
+
+    /// Construct a string ref from a pointer and length.
+    /*implicit*/ constexpr StringRef(const char *data, size_t length)
+        : Data(data), Length(length) {}
+
+    /// Construct a string ref from an std::string.
+    /*implicit*/ StringRef(const std::string &Str)
+      : Data(Str.data()), Length(Str.length()) {}
+
+    static StringRef withNullAsEmpty(const char *data) {
+      return StringRef(data ? data : "");
+    }
+
+    /// @}
+    /// @name Iterators
+    /// @{
+
+    iterator begin() const { return Data; }
+
+    iterator end() const { return Data + Length; }
+
+    const unsigned char *bytes_begin() const {
+      return reinterpret_cast<const unsigned char *>(begin());
+    }
+    const unsigned char *bytes_end() const {
+      return reinterpret_cast<const unsigned char *>(end());
+    }
+    iterator_range<const unsigned char *> bytes() const {
+      return make_range(bytes_begin(), bytes_end());
+    }
+
+    /// @}
+    /// @name String Operations
+    /// @{
+
+    /// data - Get a pointer to the start of the string (which may not be null
+    /// terminated).
+    LLVM_NODISCARD
+    const char *data() const { return Data; }
+
+    /// empty - Check if the string is empty.
+    LLVM_NODISCARD
+    bool empty() const { return Length == 0; }
+
+    /// size - Get the string size.
+    LLVM_NODISCARD
+    size_t size() const { return Length; }
+
+    /// front - Get the first character in the string.
+    LLVM_NODISCARD
+    char front() const {
+      assert(!empty());
+      return Data[0];
+    }
+
+    /// back - Get the last character in the string.
+    LLVM_NODISCARD
+    char back() const {
+      assert(!empty());
+      return Data[Length-1];
+    }
+
+    // copy - Allocate copy in Allocator and return StringRef to it.
+    template <typename Allocator>
+    LLVM_NODISCARD StringRef copy(Allocator &A) const {
+      // Don't request a length 0 copy from the allocator.
+      if (empty())
+        return StringRef();
+      char *S = A.template Allocate<char>(Length);
+      std::copy(begin(), end(), S);
+      return StringRef(S, Length);
+    }
+
+    /// equals - Check for string equality, this is more efficient than
+    /// compare() when the relative ordering of inequal strings isn't needed.
+    LLVM_NODISCARD
+    bool equals(StringRef RHS) const {
+      return (Length == RHS.Length &&
+              compareMemory(Data, RHS.Data, RHS.Length) == 0);
+    }
+
+    /// equals_lower - Check for string equality, ignoring case.
+    LLVM_NODISCARD
+    bool equals_lower(StringRef RHS) const {
+      return Length == RHS.Length && compare_lower(RHS) == 0;
+    }
+
+    /// compare - Compare two strings; the result is -1, 0, or 1 if this string
+    /// is lexicographically less than, equal to, or greater than the \p RHS.
+    LLVM_NODISCARD
+    int compare(StringRef RHS) const {
+      // Check the prefix for a mismatch.
+      if (int Res = compareMemory(Data, RHS.Data, std::min(Length, RHS.Length)))
+        return Res < 0 ? -1 : 1;
+
+      // Otherwise the prefixes match, so we only need to check the lengths.
+      if (Length == RHS.Length)
+        return 0;
+      return Length < RHS.Length ? -1 : 1;
+    }
+
+    /// compare_lower - Compare two strings, ignoring case.
+    LLVM_NODISCARD
+    int compare_lower(StringRef RHS) const;
+
+    /// compare_numeric - Compare two strings, treating sequences of digits as
+    /// numbers.
+    LLVM_NODISCARD
+    int compare_numeric(StringRef RHS) const;
+
+    /// Determine the edit distance between this string and another
+    /// string.
+    ///
+    /// \param Other the string to compare this string against.
+    ///
+    /// \param AllowReplacements whether to allow character
+    /// replacements (change one character into another) as a single
+    /// operation, rather than as two operations (an insertion and a
+    /// removal).
+    ///
+    /// \param MaxEditDistance If non-zero, the maximum edit distance that
+    /// this routine is allowed to compute. If the edit distance will exceed
+    /// that maximum, returns \c MaxEditDistance+1.
+    ///
+    /// \returns the minimum number of character insertions, removals,
+    /// or (if \p AllowReplacements is \c true) replacements needed to
+    /// transform one of the given strings into the other. If zero,
+    /// the strings are identical.
+    LLVM_NODISCARD
+    unsigned edit_distance(StringRef Other, bool AllowReplacements = true,
+                           unsigned MaxEditDistance = 0) const;
+
+    /// str - Get the contents as an std::string.
+    LLVM_NODISCARD
+    std::string str() const {
+      if (!Data) return std::string();
+      return std::string(Data, Length);
+    }
+
+    /// @}
+    /// @name Operator Overloads
+    /// @{
+
+    LLVM_NODISCARD
+    char operator[](size_t Index) const {
+      assert(Index < Length && "Invalid index!");
+      return Data[Index];
+    }
+
+    /// Disallow accidental assignment from a temporary std::string.
+    ///
+    /// The declaration here is extra complicated so that `stringRef = {}`
+    /// and `stringRef = "abc"` continue to select the move assignment operator.
+    template <typename T>
+    typename std::enable_if<std::is_same<T, std::string>::value,
+                            StringRef>::type &
+    operator=(T &&Str) = delete;
+
+    /// @}
+    /// @name Type Conversions
+    /// @{
+
+    operator std::string() const {
+      return str();
+    }
+
+    /// @}
+    /// @name String Predicates
+    /// @{
+
+    /// Check if this string starts with the given \p Prefix.
+    LLVM_NODISCARD
+    bool startswith(StringRef Prefix) const {
+      return Length >= Prefix.Length &&
+             compareMemory(Data, Prefix.Data, Prefix.Length) == 0;
+    }
+
+    /// Check if this string starts with the given \p Prefix, ignoring case.
+    LLVM_NODISCARD
+    bool startswith_lower(StringRef Prefix) const;
+
+    /// Check if this string ends with the given \p Suffix.
+    LLVM_NODISCARD
+    bool endswith(StringRef Suffix) const {
+      return Length >= Suffix.Length &&
+        compareMemory(end() - Suffix.Length, Suffix.Data, Suffix.Length) == 0;
+    }
+
+    /// Check if this string ends with the given \p Suffix, ignoring case.
+    LLVM_NODISCARD
+    bool endswith_lower(StringRef Suffix) const;
+
+    /// @}
+    /// @name String Searching
+    /// @{
+
+    /// Search for the first character \p C in the string.
+    ///
+    /// \returns The index of the first occurrence of \p C, or npos if not
+    /// found.
+    LLVM_NODISCARD
+    size_t find(char C, size_t From = 0) const {
+      size_t FindBegin = std::min(From, Length);
+      if (FindBegin < Length) { // Avoid calling memchr with nullptr.
+        // Just forward to memchr, which is faster than a hand-rolled loop.
+        if (const void *P = ::memchr(Data + FindBegin, C, Length - FindBegin))
+          return static_cast<const char *>(P) - Data;
+      }
+      return npos;
+    }
+
+    /// Search for the first character \p C in the string, ignoring case.
+    ///
+    /// \returns The index of the first occurrence of \p C, or npos if not
+    /// found.
+    LLVM_NODISCARD
+    size_t find_lower(char C, size_t From = 0) const;
+
+    /// Search for the first character satisfying the predicate \p F
+    ///
+    /// \returns The index of the first character satisfying \p F starting from
+    /// \p From, or npos if not found.
+    LLVM_NODISCARD
+    size_t find_if(function_ref<bool(char)> F, size_t From = 0) const {
+      StringRef S = drop_front(From);
+      while (!S.empty()) {
+        if (F(S.front()))
+          return size() - S.size();
+        S = S.drop_front();
+      }
+      return npos;
+    }
+
+    /// Search for the first character not satisfying the predicate \p F
+    ///
+    /// \returns The index of the first character not satisfying \p F starting
+    /// from \p From, or npos if not found.
+    LLVM_NODISCARD
+    size_t find_if_not(function_ref<bool(char)> F, size_t From = 0) const {
+      return find_if([F](char c) { return !F(c); }, From);
+    }
+
+    /// Search for the first string \p Str in the string.
+    ///
+    /// \returns The index of the first occurrence of \p Str, or npos if not
+    /// found.
+    LLVM_NODISCARD
+    size_t find(StringRef Str, size_t From = 0) const;
+
+    /// Search for the first string \p Str in the string, ignoring case.
+    ///
+    /// \returns The index of the first occurrence of \p Str, or npos if not
+    /// found.
+    LLVM_NODISCARD
+    size_t find_lower(StringRef Str, size_t From = 0) const;
+
+    /// Search for the last character \p C in the string.
+    ///
+    /// \returns The index of the last occurrence of \p C, or npos if not
+    /// found.
+    LLVM_NODISCARD
+    size_t rfind(char C, size_t From = npos) const {
+      From = std::min(From, Length);
+      size_t i = From;
+      while (i != 0) {
+        --i;
+        if (Data[i] == C)
+          return i;
+      }
+      return npos;
+    }
+
+    /// Search for the last character \p C in the string, ignoring case.
+    ///
+    /// \returns The index of the last occurrence of \p C, or npos if not
+    /// found.
+    LLVM_NODISCARD
+    size_t rfind_lower(char C, size_t From = npos) const;
+
+    /// Search for the last string \p Str in the string.
+    ///
+    /// \returns The index of the last occurrence of \p Str, or npos if not
+    /// found.
+    LLVM_NODISCARD
+    size_t rfind(StringRef Str) const;
+
+    /// Search for the last string \p Str in the string, ignoring case.
+    ///
+    /// \returns The index of the last occurrence of \p Str, or npos if not
+    /// found.
+    LLVM_NODISCARD
+    size_t rfind_lower(StringRef Str) const;
+
+    /// Find the first character in the string that is \p C, or npos if not
+    /// found. Same as find.
+    LLVM_NODISCARD
+    size_t find_first_of(char C, size_t From = 0) const {
+      return find(C, From);
+    }
+
+    /// Find the first character in the string that is in \p Chars, or npos if
+    /// not found.
+    ///
+    /// Complexity: O(size() + Chars.size())
+    LLVM_NODISCARD
+    size_t find_first_of(StringRef Chars, size_t From = 0) const;
+
+    /// Find the first character in the string that is not \p C or npos if not
+    /// found.
+    LLVM_NODISCARD
+    size_t find_first_not_of(char C, size_t From = 0) const;
+
+    /// Find the first character in the string that is not in the string
+    /// \p Chars, or npos if not found.
+    ///
+    /// Complexity: O(size() + Chars.size())
+    LLVM_NODISCARD
+    size_t find_first_not_of(StringRef Chars, size_t From = 0) const;
+
+    /// Find the last character in the string that is \p C, or npos if not
+    /// found.
+    LLVM_NODISCARD
+    size_t find_last_of(char C, size_t From = npos) const {
+      return rfind(C, From);
+    }
+
+    /// Find the last character in the string that is in \p C, or npos if not
+    /// found.
+    ///
+    /// Complexity: O(size() + Chars.size())
+    LLVM_NODISCARD
+    size_t find_last_of(StringRef Chars, size_t From = npos) const;
+
+    /// Find the last character in the string that is not \p C, or npos if not
+    /// found.
+    LLVM_NODISCARD
+    size_t find_last_not_of(char C, size_t From = npos) const;
+
+    /// Find the last character in the string that is not in \p Chars, or
+    /// npos if not found.
+    ///
+    /// Complexity: O(size() + Chars.size())
+    LLVM_NODISCARD
+    size_t find_last_not_of(StringRef Chars, size_t From = npos) const;
+
+    /// Return true if the given string is a substring of *this, and false
+    /// otherwise.
+    LLVM_NODISCARD
+    bool contains(StringRef Other) const { return find(Other) != npos; }
+
+    /// Return true if the given character is contained in *this, and false
+    /// otherwise.
+    LLVM_NODISCARD
+    bool contains(char C) const { return find_first_of(C) != npos; }
+
+    /// Return true if the given string is a substring of *this, and false
+    /// otherwise.
+    LLVM_NODISCARD
+    bool contains_lower(StringRef Other) const {
+      return find_lower(Other) != npos;
+    }
+
+    /// Return true if the given character is contained in *this, and false
+    /// otherwise.
+    LLVM_NODISCARD
+    bool contains_lower(char C) const { return find_lower(C) != npos; }
+
+    /// @}
+    /// @name Helpful Algorithms
+    /// @{
+
+    /// Return the number of occurrences of \p C in the string.
+    LLVM_NODISCARD
+    size_t count(char C) const {
+      size_t Count = 0;
+      for (size_t i = 0, e = Length; i != e; ++i)
+        if (Data[i] == C)
+          ++Count;
+      return Count;
+    }
+
+    /// Return the number of non-overlapped occurrences of \p Str in
+    /// the string.
+    size_t count(StringRef Str) const;
+
+    /// Parse the current string as an integer of the specified radix.  If
+    /// \p Radix is specified as zero, this does radix autosensing using
+    /// extended C rules: 0 is octal, 0x is hex, 0b is binary.
+    ///
+    /// If the string is invalid or if only a subset of the string is valid,
+    /// this returns true to signify the error.  The string is considered
+    /// erroneous if empty or if it overflows T.
+    template <typename T>
+    typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
+    getAsInteger(unsigned Radix, T &Result) const {
+      long long LLVal;
+      if (getAsSignedInteger(*this, Radix, LLVal) ||
+            static_cast<T>(LLVal) != LLVal)
+        return true;
+      Result = LLVal;
+      return false;
+    }
+
+    template <typename T>
+    typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type
+    getAsInteger(unsigned Radix, T &Result) const {
+      unsigned long long ULLVal;
+      // The additional cast to unsigned long long is required to avoid the
+      // Visual C++ warning C4805: '!=' : unsafe mix of type 'bool' and type
+      // 'unsigned __int64' when instantiating getAsInteger with T = bool.
+      if (getAsUnsignedInteger(*this, Radix, ULLVal) ||
+          static_cast<unsigned long long>(static_cast<T>(ULLVal)) != ULLVal)
+        return true;
+      Result = ULLVal;
+      return false;
+    }
+
+    /// Parse the current string as an integer of the specified radix.  If
+    /// \p Radix is specified as zero, this does radix autosensing using
+    /// extended C rules: 0 is octal, 0x is hex, 0b is binary.
+    ///
+    /// If the string does not begin with a number of the specified radix,
+    /// this returns true to signify the error. The string is considered
+    /// erroneous if empty or if it overflows T.
+    /// The portion of the string representing the discovered numeric value
+    /// is removed from the beginning of the string.
+    template <typename T>
+    typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
+    consumeInteger(unsigned Radix, T &Result) {
+      long long LLVal;
+      if (consumeSignedInteger(*this, Radix, LLVal) ||
+          static_cast<long long>(static_cast<T>(LLVal)) != LLVal)
+        return true;
+      Result = LLVal;
+      return false;
+    }
+
+    template <typename T>
+    typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type
+    consumeInteger(unsigned Radix, T &Result) {
+      unsigned long long ULLVal;
+      if (consumeUnsignedInteger(*this, Radix, ULLVal) ||
+          static_cast<unsigned long long>(static_cast<T>(ULLVal)) != ULLVal)
+        return true;
+      Result = ULLVal;
+      return false;
+    }
+
+    /// Parse the current string as an integer of the specified \p Radix, or of
+    /// an autosensed radix if the \p Radix given is 0.  The current value in
+    /// \p Result is discarded, and the storage is changed to be wide enough to
+    /// store the parsed integer.
+    ///
+    /// \returns true if the string does not solely consist of a valid
+    /// non-empty number in the appropriate base.
+    ///
+    /// APInt::fromString is superficially similar but assumes the
+    /// string is well-formed in the given radix.
+    bool getAsInteger(unsigned Radix, APInt &Result) const;
+
+    /// Parse the current string as an IEEE double-precision floating
+    /// point value.  The string must be a well-formed double.
+    ///
+    /// If \p AllowInexact is false, the function will fail if the string
+    /// cannot be represented exactly.  Otherwise, the function only fails
+    /// in case of an overflow or underflow.
+    bool getAsDouble(double &Result, bool AllowInexact = true) const;
+
+    /// @}
+    /// @name String Operations
+    /// @{
+
+    // Convert the given ASCII string to lowercase.
+    LLVM_NODISCARD
+    std::string lower() const;
+
+    /// Convert the given ASCII string to uppercase.
+    LLVM_NODISCARD
+    std::string upper() const;
+
+    /// @}
+    /// @name Substring Operations
+    /// @{
+
+    /// Return a reference to the substring from [Start, Start + N).
+    ///
+    /// \param Start The index of the starting character in the substring; if
+    /// the index is npos or greater than the length of the string then the
+    /// empty substring will be returned.
+    ///
+    /// \param N The number of characters to included in the substring. If N
+    /// exceeds the number of characters remaining in the string, the string
+    /// suffix (starting with \p Start) will be returned.
+    LLVM_NODISCARD
+    StringRef substr(size_t Start, size_t N = npos) const {
+      Start = std::min(Start, Length);
+      return StringRef(Data + Start, std::min(N, Length - Start));
+    }
+
+    /// Return a StringRef equal to 'this' but with only the first \p N
+    /// elements remaining.  If \p N is greater than the length of the
+    /// string, the entire string is returned.
+    LLVM_NODISCARD
+    StringRef take_front(size_t N = 1) const {
+      if (N >= size())
+        return *this;
+      return drop_back(size() - N);
+    }
+
+    /// Return a StringRef equal to 'this' but with only the last \p N
+    /// elements remaining.  If \p N is greater than the length of the
+    /// string, the entire string is returned.
+    LLVM_NODISCARD
+    StringRef take_back(size_t N = 1) const {
+      if (N >= size())
+        return *this;
+      return drop_front(size() - N);
+    }
+
+    /// Return the longest prefix of 'this' such that every character
+    /// in the prefix satisfies the given predicate.
+    LLVM_NODISCARD
+    StringRef take_while(function_ref<bool(char)> F) const {
+      return substr(0, find_if_not(F));
+    }
+
+    /// Return the longest prefix of 'this' such that no character in
+    /// the prefix satisfies the given predicate.
+    LLVM_NODISCARD
+    StringRef take_until(function_ref<bool(char)> F) const {
+      return substr(0, find_if(F));
+    }
+
+    /// Return a StringRef equal to 'this' but with the first \p N elements
+    /// dropped.
+    LLVM_NODISCARD
+    StringRef drop_front(size_t N = 1) const {
+      assert(size() >= N && "Dropping more elements than exist");
+      return substr(N);
+    }
+
+    /// Return a StringRef equal to 'this' but with the last \p N elements
+    /// dropped.
+    LLVM_NODISCARD
+    StringRef drop_back(size_t N = 1) const {
+      assert(size() >= N && "Dropping more elements than exist");
+      return substr(0, size()-N);
+    }
+
+    /// Return a StringRef equal to 'this', but with all characters satisfying
+    /// the given predicate dropped from the beginning of the string.
+    LLVM_NODISCARD
+    StringRef drop_while(function_ref<bool(char)> F) const {
+      return substr(find_if_not(F));
+    }
+
+    /// Return a StringRef equal to 'this', but with all characters not
+    /// satisfying the given predicate dropped from the beginning of the string.
+    LLVM_NODISCARD
+    StringRef drop_until(function_ref<bool(char)> F) const {
+      return substr(find_if(F));
+    }
+
+    /// Returns true if this StringRef has the given prefix and removes that
+    /// prefix.
+    bool consume_front(StringRef Prefix) {
+      if (!startswith(Prefix))
+        return false;
+
+      *this = drop_front(Prefix.size());
+      return true;
+    }
+
+    /// Returns true if this StringRef has the given suffix and removes that
+    /// suffix.
+    bool consume_back(StringRef Suffix) {
+      if (!endswith(Suffix))
+        return false;
+
+      *this = drop_back(Suffix.size());
+      return true;
+    }
+
+    /// Return a reference to the substring from [Start, End).
+    ///
+    /// \param Start The index of the starting character in the substring; if
+    /// the index is npos or greater than the length of the string then the
+    /// empty substring will be returned.
+    ///
+    /// \param End The index following the last character to include in the
+    /// substring. If this is npos or exceeds the number of characters
+    /// remaining in the string, the string suffix (starting with \p Start)
+    /// will be returned. If this is less than \p Start, an empty string will
+    /// be returned.
+    LLVM_NODISCARD
+    StringRef slice(size_t Start, size_t End) const {
+      Start = std::min(Start, Length);
+      End = std::min(std::max(Start, End), Length);
+      return StringRef(Data + Start, End - Start);
+    }
+
+    /// Split into two substrings around the first occurrence of a separator
+    /// character.
+    ///
+    /// If \p Separator is in the string, then the result is a pair (LHS, RHS)
+    /// such that (*this == LHS + Separator + RHS) is true and RHS is
+    /// maximal. If \p Separator is not in the string, then the result is a
+    /// pair (LHS, RHS) where (*this == LHS) and (RHS == "").
+    ///
+    /// \param Separator The character to split on.
+    /// \returns The split substrings.
+    LLVM_NODISCARD
+    std::pair<StringRef, StringRef> split(char Separator) const {
+      return split(StringRef(&Separator, 1));
+    }
+
+    /// Split into two substrings around the first occurrence of a separator
+    /// string.
+    ///
+    /// If \p Separator is in the string, then the result is a pair (LHS, RHS)
+    /// such that (*this == LHS + Separator + RHS) is true and RHS is
+    /// maximal. If \p Separator is not in the string, then the result is a
+    /// pair (LHS, RHS) where (*this == LHS) and (RHS == "").
+    ///
+    /// \param Separator - The string to split on.
+    /// \return - The split substrings.
+    LLVM_NODISCARD
+    std::pair<StringRef, StringRef> split(StringRef Separator) const {
+      size_t Idx = find(Separator);
+      if (Idx == npos)
+        return std::make_pair(*this, StringRef());
+      return std::make_pair(slice(0, Idx), slice(Idx + Separator.size(), npos));
+    }
+
+    /// Split into two substrings around the last occurrence of a separator
+    /// string.
+    ///
+    /// If \p Separator is in the string, then the result is a pair (LHS, RHS)
+    /// such that (*this == LHS + Separator + RHS) is true and RHS is
+    /// minimal. If \p Separator is not in the string, then the result is a
+    /// pair (LHS, RHS) where (*this == LHS) and (RHS == "").
+    ///
+    /// \param Separator - The string to split on.
+    /// \return - The split substrings.
+    LLVM_NODISCARD
+    std::pair<StringRef, StringRef> rsplit(StringRef Separator) const {
+      size_t Idx = rfind(Separator);
+      if (Idx == npos)
+        return std::make_pair(*this, StringRef());
+      return std::make_pair(slice(0, Idx), slice(Idx + Separator.size(), npos));
+    }
+
+    /// Split into substrings around the occurrences of a separator string.
+    ///
+    /// Each substring is stored in \p A. If \p MaxSplit is >= 0, at most
+    /// \p MaxSplit splits are done and consequently <= \p MaxSplit + 1
+    /// elements are added to A.
+    /// If \p KeepEmpty is false, empty strings are not added to \p A. They
+    /// still count when considering \p MaxSplit
+    /// An useful invariant is that
+    /// Separator.join(A) == *this if MaxSplit == -1 and KeepEmpty == true
+    ///
+    /// \param A - Where to put the substrings.
+    /// \param Separator - The string to split on.
+    /// \param MaxSplit - The maximum number of times the string is split.
+    /// \param KeepEmpty - True if empty substring should be added.
+    void split(SmallVectorImpl<StringRef> &A,
+               StringRef Separator, int MaxSplit = -1,
+               bool KeepEmpty = true) const;
+
+    /// Split into substrings around the occurrences of a separator character.
+    ///
+    /// Each substring is stored in \p A. If \p MaxSplit is >= 0, at most
+    /// \p MaxSplit splits are done and consequently <= \p MaxSplit + 1
+    /// elements are added to A.
+    /// If \p KeepEmpty is false, empty strings are not added to \p A. They
+    /// still count when considering \p MaxSplit
+    /// An useful invariant is that
+    /// Separator.join(A) == *this if MaxSplit == -1 and KeepEmpty == true
+    ///
+    /// \param A - Where to put the substrings.
+    /// \param Separator - The string to split on.
+    /// \param MaxSplit - The maximum number of times the string is split.
+    /// \param KeepEmpty - True if empty substring should be added.
+    void split(SmallVectorImpl<StringRef> &A, char Separator, int MaxSplit = -1,
+               bool KeepEmpty = true) const;
+
+    /// Split into two substrings around the last occurrence of a separator
+    /// character.
+    ///
+    /// If \p Separator is in the string, then the result is a pair (LHS, RHS)
+    /// such that (*this == LHS + Separator + RHS) is true and RHS is
+    /// minimal. If \p Separator is not in the string, then the result is a
+    /// pair (LHS, RHS) where (*this == LHS) and (RHS == "").
+    ///
+    /// \param Separator - The character to split on.
+    /// \return - The split substrings.
+    LLVM_NODISCARD
+    std::pair<StringRef, StringRef> rsplit(char Separator) const {
+      return rsplit(StringRef(&Separator, 1));
+    }
+
+    /// Return string with consecutive \p Char characters starting from the
+    /// the left removed.
+    LLVM_NODISCARD
+    StringRef ltrim(char Char) const {
+      return drop_front(std::min(Length, find_first_not_of(Char)));
+    }
+
+    /// Return string with consecutive characters in \p Chars starting from
+    /// the left removed.
+    LLVM_NODISCARD
+    StringRef ltrim(StringRef Chars = " \t\n\v\f\r") const {
+      return drop_front(std::min(Length, find_first_not_of(Chars)));
+    }
+
+    /// Return string with consecutive \p Char characters starting from the
+    /// right removed.
+    LLVM_NODISCARD
+    StringRef rtrim(char Char) const {
+      return drop_back(Length - std::min(Length, find_last_not_of(Char) + 1));
+    }
+
+    /// Return string with consecutive characters in \p Chars starting from
+    /// the right removed.
+    LLVM_NODISCARD
+    StringRef rtrim(StringRef Chars = " \t\n\v\f\r") const {
+      return drop_back(Length - std::min(Length, find_last_not_of(Chars) + 1));
+    }
+
+    /// Return string with consecutive \p Char characters starting from the
+    /// left and right removed.
+    LLVM_NODISCARD
+    StringRef trim(char Char) const {
+      return ltrim(Char).rtrim(Char);
+    }
+
+    /// Return string with consecutive characters in \p Chars starting from
+    /// the left and right removed.
+    LLVM_NODISCARD
+    StringRef trim(StringRef Chars = " \t\n\v\f\r") const {
+      return ltrim(Chars).rtrim(Chars);
+    }
+
+    /// @}
+  };
+
+  /// A wrapper around a string literal that serves as a proxy for constructing
+  /// global tables of StringRefs with the length computed at compile time.
+  /// In order to avoid the invocation of a global constructor, StringLiteral
+  /// should *only* be used in a constexpr context, as such:
+  ///
+  /// constexpr StringLiteral S("test");
+  ///
+  class StringLiteral : public StringRef {
+  private:
+    constexpr StringLiteral(const char *Str, size_t N) : StringRef(Str, N) {
+    }
+
+  public:
+    template <size_t N>
+    constexpr StringLiteral(const char (&Str)[N])
+#if defined(__clang__) && __has_attribute(enable_if)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgcc-compat"
+        __attribute((enable_if(__builtin_strlen(Str) == N - 1,
+                               "invalid string literal")))
+#pragma clang diagnostic pop
+#endif
+        : StringRef(Str, N - 1) {
+    }
+
+    // Explicit construction for strings like "foo\0bar".
+    template <size_t N>
+    static constexpr StringLiteral withInnerNUL(const char (&Str)[N]) {
+      return StringLiteral(Str, N - 1);
+    }
+  };
+
+  /// @name StringRef Comparison Operators
+  /// @{
+
+  inline bool operator==(StringRef LHS, StringRef RHS) {
+    return LHS.equals(RHS);
+  }
+
+  inline bool operator!=(StringRef LHS, StringRef RHS) { return !(LHS == RHS); }
+
+  inline bool operator<(StringRef LHS, StringRef RHS) {
+    return LHS.compare(RHS) == -1;
+  }
+
+  inline bool operator<=(StringRef LHS, StringRef RHS) {
+    return LHS.compare(RHS) != 1;
+  }
+
+  inline bool operator>(StringRef LHS, StringRef RHS) {
+    return LHS.compare(RHS) == 1;
+  }
+
+  inline bool operator>=(StringRef LHS, StringRef RHS) {
+    return LHS.compare(RHS) != -1;
+  }
+
+  inline std::string &operator+=(std::string &buffer, StringRef string) {
+    return buffer.append(string.data(), string.size());
+  }
+
+  /// @}
+
+  /// Compute a hash_code for a StringRef.
+  LLVM_NODISCARD
+  hash_code hash_value(StringRef S);
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_STRINGREF_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/StringSet.h b/binaryen/third_party/llvm-project/include/llvm/ADT/StringSet.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/StringSet.h
@@ -0,0 +1,58 @@
+//===- StringSet.h - The LLVM Compiler Driver -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  StringSet - A set-like wrapper for the StringMap.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_STRINGSET_H
+#define LLVM_ADT_STRINGSET_H
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+#include <cassert>
+#include <initializer_list>
+#include <utility>
+
+namespace llvm {
+
+  /// StringSet - A wrapper for StringMap that provides set-like functionality.
+  template <class AllocatorTy = MallocAllocator>
+  class StringSet : public StringMap<NoneType, AllocatorTy> {
+    using base = StringMap<NoneType, AllocatorTy>;
+
+  public:
+    StringSet() = default;
+    StringSet(std::initializer_list<StringRef> S) {
+      for (StringRef X : S)
+        insert(X);
+    }
+    explicit StringSet(AllocatorTy A) : base(A) {}
+
+    std::pair<typename base::iterator, bool> insert(StringRef Key) {
+      assert(!Key.empty());
+      return base::insert(std::make_pair(Key, None));
+    }
+
+    template <typename InputIt>
+    void insert(const InputIt &Begin, const InputIt &End) {
+      for (auto It = Begin; It != End; ++It)
+        base::insert(std::make_pair(*It, None));
+    }
+
+    template <typename ValueTy>
+    std::pair<typename base::iterator, bool>
+    insert(const StringMapEntry<ValueTy> &MapEntry) {
+      return insert(MapEntry.getKey());
+    }
+  };
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_STRINGSET_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/StringSwitch.h b/binaryen/third_party/llvm-project/include/llvm/ADT/StringSwitch.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/StringSwitch.h
@@ -0,0 +1,196 @@
+//===--- StringSwitch.h - Switch-on-literal-string Construct --------------===/
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//===----------------------------------------------------------------------===/
+//
+//  This file implements the StringSwitch template, which mimics a switch()
+//  statement whose cases are string literals.
+//
+//===----------------------------------------------------------------------===/
+#ifndef LLVM_ADT_STRINGSWITCH_H
+#define LLVM_ADT_STRINGSWITCH_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Compiler.h"
+#include <cassert>
+#include <cstring>
+
+namespace llvm {
+
+/// A switch()-like statement whose cases are string literals.
+///
+/// The StringSwitch class is a simple form of a switch() statement that
+/// determines whether the given string matches one of the given string
+/// literals. The template type parameter \p T is the type of the value that
+/// will be returned from the string-switch expression. For example,
+/// the following code switches on the name of a color in \c argv[i]:
+///
+/// \code
+/// Color color = StringSwitch<Color>(argv[i])
+///   .Case("red", Red)
+///   .Case("orange", Orange)
+///   .Case("yellow", Yellow)
+///   .Case("green", Green)
+///   .Case("blue", Blue)
+///   .Case("indigo", Indigo)
+///   .Cases("violet", "purple", Violet)
+///   .Default(UnknownColor);
+/// \endcode
+template<typename T, typename R = T>
+class StringSwitch {
+  /// The string we are matching.
+  const StringRef Str;
+
+  /// The pointer to the result of this switch statement, once known,
+  /// null before that.
+  Optional<T> Result;
+
+public:
+  explicit StringSwitch(StringRef S)
+  : Str(S), Result() { }
+
+  // StringSwitch is not copyable.
+  StringSwitch(const StringSwitch &) = delete;
+
+  // StringSwitch is not assignable due to 'Str' being 'const'.
+  void operator=(const StringSwitch &) = delete;
+  void operator=(StringSwitch &&other) = delete;
+
+  StringSwitch(StringSwitch &&other)
+    : Str(other.Str), Result(std::move(other.Result)) { }
+
+  ~StringSwitch() = default;
+
+  // Case-sensitive case matchers
+  StringSwitch &Case(StringLiteral S, T Value) {
+    if (!Result && Str == S) {
+      Result = std::move(Value);
+    }
+    return *this;
+  }
+
+  StringSwitch& EndsWith(StringLiteral S, T Value) {
+    if (!Result && Str.endswith(S)) {
+      Result = std::move(Value);
+    }
+    return *this;
+  }
+
+  StringSwitch& StartsWith(StringLiteral S, T Value) {
+    if (!Result && Str.startswith(S)) {
+      Result = std::move(Value);
+    }
+    return *this;
+  }
+
+  StringSwitch &Cases(StringLiteral S0, StringLiteral S1, T Value) {
+    return Case(S0, Value).Case(S1, Value);
+  }
+
+  StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
+                      T Value) {
+    return Case(S0, Value).Cases(S1, S2, Value);
+  }
+
+  StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
+                      StringLiteral S3, T Value) {
+    return Case(S0, Value).Cases(S1, S2, S3, Value);
+  }
+
+  StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
+                      StringLiteral S3, StringLiteral S4, T Value) {
+    return Case(S0, Value).Cases(S1, S2, S3, S4, Value);
+  }
+
+  StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
+                      StringLiteral S3, StringLiteral S4, StringLiteral S5,
+                      T Value) {
+    return Case(S0, Value).Cases(S1, S2, S3, S4, S5, Value);
+  }
+
+  StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
+                      StringLiteral S3, StringLiteral S4, StringLiteral S5,
+                      StringLiteral S6, T Value) {
+    return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, Value);
+  }
+
+  StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
+                      StringLiteral S3, StringLiteral S4, StringLiteral S5,
+                      StringLiteral S6, StringLiteral S7, T Value) {
+    return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, Value);
+  }
+
+  StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
+                      StringLiteral S3, StringLiteral S4, StringLiteral S5,
+                      StringLiteral S6, StringLiteral S7, StringLiteral S8,
+                      T Value) {
+    return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, Value);
+  }
+
+  StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
+                      StringLiteral S3, StringLiteral S4, StringLiteral S5,
+                      StringLiteral S6, StringLiteral S7, StringLiteral S8,
+                      StringLiteral S9, T Value) {
+    return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, S9, Value);
+  }
+
+  // Case-insensitive case matchers.
+  StringSwitch &CaseLower(StringLiteral S, T Value) {
+    if (!Result && Str.equals_lower(S))
+      Result = std::move(Value);
+
+    return *this;
+  }
+
+  StringSwitch &EndsWithLower(StringLiteral S, T Value) {
+    if (!Result && Str.endswith_lower(S))
+      Result = Value;
+
+    return *this;
+  }
+
+  StringSwitch &StartsWithLower(StringLiteral S, T Value) {
+    if (!Result && Str.startswith_lower(S))
+      Result = std::move(Value);
+
+    return *this;
+  }
+
+  StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, T Value) {
+    return CaseLower(S0, Value).CaseLower(S1, Value);
+  }
+
+  StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
+                           T Value) {
+    return CaseLower(S0, Value).CasesLower(S1, S2, Value);
+  }
+
+  StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
+                           StringLiteral S3, T Value) {
+    return CaseLower(S0, Value).CasesLower(S1, S2, S3, Value);
+  }
+
+  StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
+                           StringLiteral S3, StringLiteral S4, T Value) {
+    return CaseLower(S0, Value).CasesLower(S1, S2, S3, S4, Value);
+  }
+
+  LLVM_NODISCARD
+  R Default(T Value) {
+    if (Result)
+      return std::move(*Result);
+    return Value;
+  }
+
+  LLVM_NODISCARD
+  operator R() {
+    assert(Result && "Fell off the end of a string-switch");
+    return std::move(*Result);
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_STRINGSWITCH_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/Triple.h b/binaryen/third_party/llvm-project/include/llvm/ADT/Triple.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/Triple.h
@@ -0,0 +1,881 @@
+//===-- llvm/ADT/Triple.h - Target triple helper class ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_TRIPLE_H
+#define LLVM_ADT_TRIPLE_H
+
+#include "llvm/ADT/Twine.h"
+
+// Some system headers or GCC predefined macros conflict with identifiers in
+// this file.  Undefine them here.
+#undef NetBSD
+#undef mips
+#undef sparc
+
+namespace llvm {
+
+/// Triple - Helper class for working with autoconf configuration names. For
+/// historical reasons, we also call these 'triples' (they used to contain
+/// exactly three fields).
+///
+/// Configuration names are strings in the canonical form:
+///   ARCHITECTURE-VENDOR-OPERATING_SYSTEM
+/// or
+///   ARCHITECTURE-VENDOR-OPERATING_SYSTEM-ENVIRONMENT
+///
+/// This class is used for clients which want to support arbitrary
+/// configuration names, but also want to implement certain special
+/// behavior for particular configurations. This class isolates the mapping
+/// from the components of the configuration name to well known IDs.
+///
+/// At its core the Triple class is designed to be a wrapper for a triple
+/// string; the constructor does not change or normalize the triple string.
+/// Clients that need to handle the non-canonical triples that users often
+/// specify should use the normalize method.
+///
+/// See autoconf/config.guess for a glimpse into what configuration names
+/// look like in practice.
+class Triple {
+public:
+  enum ArchType {
+    UnknownArch,
+
+    arm,            // ARM (little endian): arm, armv.*, xscale
+    armeb,          // ARM (big endian): armeb
+    aarch64,        // AArch64 (little endian): aarch64
+    aarch64_be,     // AArch64 (big endian): aarch64_be
+    aarch64_32,     // AArch64 (little endian) ILP32: aarch64_32
+    arc,            // ARC: Synopsys ARC
+    avr,            // AVR: Atmel AVR microcontroller
+    bpfel,          // eBPF or extended BPF or 64-bit BPF (little endian)
+    bpfeb,          // eBPF or extended BPF or 64-bit BPF (big endian)
+    hexagon,        // Hexagon: hexagon
+    mips,           // MIPS: mips, mipsallegrex, mipsr6
+    mipsel,         // MIPSEL: mipsel, mipsallegrexe, mipsr6el
+    mips64,         // MIPS64: mips64, mips64r6, mipsn32, mipsn32r6
+    mips64el,       // MIPS64EL: mips64el, mips64r6el, mipsn32el, mipsn32r6el
+    msp430,         // MSP430: msp430
+    ppc,            // PPC: powerpc
+    ppc64,          // PPC64: powerpc64, ppu
+    ppc64le,        // PPC64LE: powerpc64le
+    r600,           // R600: AMD GPUs HD2XXX - HD6XXX
+    amdgcn,         // AMDGCN: AMD GCN GPUs
+    riscv32,        // RISC-V (32-bit): riscv32
+    riscv64,        // RISC-V (64-bit): riscv64
+    sparc,          // Sparc: sparc
+    sparcv9,        // Sparcv9: Sparcv9
+    sparcel,        // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant
+    systemz,        // SystemZ: s390x
+    tce,            // TCE (http://tce.cs.tut.fi/): tce
+    tcele,          // TCE little endian (http://tce.cs.tut.fi/): tcele
+    thumb,          // Thumb (little endian): thumb, thumbv.*
+    thumbeb,        // Thumb (big endian): thumbeb
+    x86,            // X86: i[3-9]86
+    x86_64,         // X86-64: amd64, x86_64
+    xcore,          // XCore: xcore
+    nvptx,          // NVPTX: 32-bit
+    nvptx64,        // NVPTX: 64-bit
+    le32,           // le32: generic little-endian 32-bit CPU (PNaCl)
+    le64,           // le64: generic little-endian 64-bit CPU (PNaCl)
+    amdil,          // AMDIL
+    amdil64,        // AMDIL with 64-bit pointers
+    hsail,          // AMD HSAIL
+    hsail64,        // AMD HSAIL with 64-bit pointers
+    spir,           // SPIR: standard portable IR for OpenCL 32-bit version
+    spir64,         // SPIR: standard portable IR for OpenCL 64-bit version
+    kalimba,        // Kalimba: generic kalimba
+    shave,          // SHAVE: Movidius vector VLIW processors
+    lanai,          // Lanai: Lanai 32-bit
+    wasm32,         // WebAssembly with 32-bit pointers
+    wasm64,         // WebAssembly with 64-bit pointers
+    renderscript32, // 32-bit RenderScript
+    renderscript64, // 64-bit RenderScript
+    LastArchType = renderscript64
+  };
+  enum SubArchType {
+    NoSubArch,
+
+    ARMSubArch_v8_5a,
+    ARMSubArch_v8_4a,
+    ARMSubArch_v8_3a,
+    ARMSubArch_v8_2a,
+    ARMSubArch_v8_1a,
+    ARMSubArch_v8,
+    ARMSubArch_v8r,
+    ARMSubArch_v8m_baseline,
+    ARMSubArch_v8m_mainline,
+    ARMSubArch_v8_1m_mainline,
+    ARMSubArch_v7,
+    ARMSubArch_v7em,
+    ARMSubArch_v7m,
+    ARMSubArch_v7s,
+    ARMSubArch_v7k,
+    ARMSubArch_v7ve,
+    ARMSubArch_v6,
+    ARMSubArch_v6m,
+    ARMSubArch_v6k,
+    ARMSubArch_v6t2,
+    ARMSubArch_v5,
+    ARMSubArch_v5te,
+    ARMSubArch_v4t,
+
+    KalimbaSubArch_v3,
+    KalimbaSubArch_v4,
+    KalimbaSubArch_v5,
+
+    MipsSubArch_r6
+  };
+  enum VendorType {
+    UnknownVendor,
+
+    Apple,
+    PC,
+    SCEI,
+    BGP,
+    BGQ,
+    Freescale,
+    IBM,
+    ImaginationTechnologies,
+    MipsTechnologies,
+    NVIDIA,
+    CSR,
+    Myriad,
+    AMD,
+    Mesa,
+    SUSE,
+    OpenEmbedded,
+    LastVendorType = OpenEmbedded
+  };
+  enum OSType {
+    UnknownOS,
+
+    Ananas,
+    CloudABI,
+    Darwin,
+    DragonFly,
+    FreeBSD,
+    Fuchsia,
+    IOS,
+    KFreeBSD,
+    Linux,
+    Lv2,        // PS3
+    MacOSX,
+    NetBSD,
+    OpenBSD,
+    Solaris,
+    Win32,
+    Haiku,
+    Minix,
+    RTEMS,
+    NaCl,       // Native Client
+    CNK,        // BG/P Compute-Node Kernel
+    AIX,
+    CUDA,       // NVIDIA CUDA
+    NVCL,       // NVIDIA OpenCL
+    AMDHSA,     // AMD HSA Runtime
+    PS4,
+    ELFIAMCU,
+    TvOS,       // Apple tvOS
+    WatchOS,    // Apple watchOS
+    Mesa3D,
+    Contiki,
+    AMDPAL,     // AMD PAL Runtime
+    HermitCore, // HermitCore Unikernel/Multikernel
+    Hurd,       // GNU/Hurd
+    WASI,       // Experimental WebAssembly OS
+    Emscripten,
+    LastOSType = Emscripten
+  };
+  enum EnvironmentType {
+    UnknownEnvironment,
+
+    GNU,
+    GNUABIN32,
+    GNUABI64,
+    GNUEABI,
+    GNUEABIHF,
+    GNUX32,
+    CODE16,
+    EABI,
+    EABIHF,
+    ELFv1,
+    ELFv2,
+    Android,
+    Musl,
+    MuslEABI,
+    MuslEABIHF,
+
+    MSVC,
+    Itanium,
+    Cygnus,
+    CoreCLR,
+    Simulator, // Simulator variants of other systems, e.g., Apple's iOS
+    MacABI, // Mac Catalyst variant of Apple's iOS deployment target.
+    LastEnvironmentType = MacABI
+  };
+  enum ObjectFormatType {
+    UnknownObjectFormat,
+
+    COFF,
+    ELF,
+    MachO,
+    Wasm,
+    XCOFF,
+  };
+
+private:
+  std::string Data;
+
+  /// The parsed arch type.
+  ArchType Arch;
+
+  /// The parsed subarchitecture type.
+  SubArchType SubArch;
+
+  /// The parsed vendor type.
+  VendorType Vendor;
+
+  /// The parsed OS type.
+  OSType OS;
+
+  /// The parsed Environment type.
+  EnvironmentType Environment;
+
+  /// The object format type.
+  ObjectFormatType ObjectFormat;
+
+public:
+  /// @name Constructors
+  /// @{
+
+  /// Default constructor is the same as an empty string and leaves all
+  /// triple fields unknown.
+  Triple()
+      : Data(), Arch(), SubArch(), Vendor(), OS(), Environment(),
+        ObjectFormat() {}
+
+  explicit Triple(const Twine &Str);
+  Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr);
+  Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr,
+         const Twine &EnvironmentStr);
+
+  bool operator==(const Triple &Other) const {
+    return Arch == Other.Arch && SubArch == Other.SubArch &&
+           Vendor == Other.Vendor && OS == Other.OS &&
+           Environment == Other.Environment &&
+           ObjectFormat == Other.ObjectFormat;
+  }
+
+  bool operator!=(const Triple &Other) const {
+    return !(*this == Other);
+  }
+
+  /// @}
+  /// @name Normalization
+  /// @{
+
+  /// normalize - Turn an arbitrary machine specification into the canonical
+  /// triple form (or something sensible that the Triple class understands if
+  /// nothing better can reasonably be done).  In particular, it handles the
+  /// common case in which otherwise valid components are in the wrong order.
+  static std::string normalize(StringRef Str);
+
+  /// Return the normalized form of this triple's string.
+  std::string normalize() const { return normalize(Data); }
+
+  /// @}
+  /// @name Typed Component Access
+  /// @{
+
+  /// getArch - Get the parsed architecture type of this triple.
+  ArchType getArch() const { return Arch; }
+
+  /// getSubArch - get the parsed subarchitecture type for this triple.
+  SubArchType getSubArch() const { return SubArch; }
+
+  /// getVendor - Get the parsed vendor type of this triple.
+  VendorType getVendor() const { return Vendor; }
+
+  /// getOS - Get the parsed operating system type of this triple.
+  OSType getOS() const { return OS; }
+
+  /// hasEnvironment - Does this triple have the optional environment
+  /// (fourth) component?
+  bool hasEnvironment() const {
+    return getEnvironmentName() != "";
+  }
+
+  /// getEnvironment - Get the parsed environment type of this triple.
+  EnvironmentType getEnvironment() const { return Environment; }
+
+  /// Parse the version number from the OS name component of the
+  /// triple, if present.
+  ///
+  /// For example, "fooos1.2.3" would return (1, 2, 3).
+  ///
+  /// If an entry is not defined, it will be returned as 0.
+  void getEnvironmentVersion(unsigned &Major, unsigned &Minor,
+                             unsigned &Micro) const;
+
+  /// getFormat - Get the object format for this triple.
+  ObjectFormatType getObjectFormat() const { return ObjectFormat; }
+
+  /// getOSVersion - Parse the version number from the OS name component of the
+  /// triple, if present.
+  ///
+  /// For example, "fooos1.2.3" would return (1, 2, 3).
+  ///
+  /// If an entry is not defined, it will be returned as 0.
+  void getOSVersion(unsigned &Major, unsigned &Minor, unsigned &Micro) const;
+
+  /// getOSMajorVersion - Return just the major version number, this is
+  /// specialized because it is a common query.
+  unsigned getOSMajorVersion() const {
+    unsigned Maj, Min, Micro;
+    getOSVersion(Maj, Min, Micro);
+    return Maj;
+  }
+
+  /// getMacOSXVersion - Parse the version number as with getOSVersion and then
+  /// translate generic "darwin" versions to the corresponding OS X versions.
+  /// This may also be called with IOS triples but the OS X version number is
+  /// just set to a constant 10.4.0 in that case.  Returns true if successful.
+  bool getMacOSXVersion(unsigned &Major, unsigned &Minor,
+                        unsigned &Micro) const;
+
+  /// getiOSVersion - Parse the version number as with getOSVersion.  This should
+  /// only be called with IOS or generic triples.
+  void getiOSVersion(unsigned &Major, unsigned &Minor,
+                     unsigned &Micro) const;
+
+  /// getWatchOSVersion - Parse the version number as with getOSVersion.  This
+  /// should only be called with WatchOS or generic triples.
+  void getWatchOSVersion(unsigned &Major, unsigned &Minor,
+                         unsigned &Micro) const;
+
+  /// @}
+  /// @name Direct Component Access
+  /// @{
+
+  const std::string &str() const { return Data; }
+
+  const std::string &getTriple() const { return Data; }
+
+  /// getArchName - Get the architecture (first) component of the
+  /// triple.
+  StringRef getArchName() const;
+
+  /// getVendorName - Get the vendor (second) component of the triple.
+  StringRef getVendorName() const;
+
+  /// getOSName - Get the operating system (third) component of the
+  /// triple.
+  StringRef getOSName() const;
+
+  /// getEnvironmentName - Get the optional environment (fourth)
+  /// component of the triple, or "" if empty.
+  StringRef getEnvironmentName() const;
+
+  /// getOSAndEnvironmentName - Get the operating system and optional
+  /// environment components as a single string (separated by a '-'
+  /// if the environment component is present).
+  StringRef getOSAndEnvironmentName() const;
+
+  /// @}
+  /// @name Convenience Predicates
+  /// @{
+
+  /// Test whether the architecture is 64-bit
+  ///
+  /// Note that this tests for 64-bit pointer width, and nothing else. Note
+  /// that we intentionally expose only three predicates, 64-bit, 32-bit, and
+  /// 16-bit. The inner details of pointer width for particular architectures
+  /// is not summed up in the triple, and so only a coarse grained predicate
+  /// system is provided.
+  bool isArch64Bit() const;
+
+  /// Test whether the architecture is 32-bit
+  ///
+  /// Note that this tests for 32-bit pointer width, and nothing else.
+  bool isArch32Bit() const;
+
+  /// Test whether the architecture is 16-bit
+  ///
+  /// Note that this tests for 16-bit pointer width, and nothing else.
+  bool isArch16Bit() const;
+
+  /// isOSVersionLT - Helper function for doing comparisons against version
+  /// numbers included in the target triple.
+  bool isOSVersionLT(unsigned Major, unsigned Minor = 0,
+                     unsigned Micro = 0) const {
+    unsigned LHS[3];
+    getOSVersion(LHS[0], LHS[1], LHS[2]);
+
+    if (LHS[0] != Major)
+      return LHS[0] < Major;
+    if (LHS[1] != Minor)
+      return LHS[1] < Minor;
+    if (LHS[2] != Micro)
+      return LHS[2] < Micro;
+
+    return false;
+  }
+
+  bool isOSVersionLT(const Triple &Other) const {
+    unsigned RHS[3];
+    Other.getOSVersion(RHS[0], RHS[1], RHS[2]);
+    return isOSVersionLT(RHS[0], RHS[1], RHS[2]);
+  }
+
+  /// isMacOSXVersionLT - Comparison function for checking OS X version
+  /// compatibility, which handles supporting skewed version numbering schemes
+  /// used by the "darwin" triples.
+  bool isMacOSXVersionLT(unsigned Major, unsigned Minor = 0,
+                         unsigned Micro = 0) const {
+    assert(isMacOSX() && "Not an OS X triple!");
+
+    // If this is OS X, expect a sane version number.
+    if (getOS() == Triple::MacOSX)
+      return isOSVersionLT(Major, Minor, Micro);
+
+    // Otherwise, compare to the "Darwin" number.
+    assert(Major == 10 && "Unexpected major version");
+    return isOSVersionLT(Minor + 4, Micro, 0);
+  }
+
+  /// isMacOSX - Is this a Mac OS X triple. For legacy reasons, we support both
+  /// "darwin" and "osx" as OS X triples.
+  bool isMacOSX() const {
+    return getOS() == Triple::Darwin || getOS() == Triple::MacOSX;
+  }
+
+  /// Is this an iOS triple.
+  /// Note: This identifies tvOS as a variant of iOS. If that ever
+  /// changes, i.e., if the two operating systems diverge or their version
+  /// numbers get out of sync, that will need to be changed.
+  /// watchOS has completely different version numbers so it is not included.
+  bool isiOS() const {
+    return getOS() == Triple::IOS || isTvOS();
+  }
+
+  /// Is this an Apple tvOS triple.
+  bool isTvOS() const {
+    return getOS() == Triple::TvOS;
+  }
+
+  /// Is this an Apple watchOS triple.
+  bool isWatchOS() const {
+    return getOS() == Triple::WatchOS;
+  }
+
+  bool isWatchABI() const {
+    return getSubArch() == Triple::ARMSubArch_v7k;
+  }
+
+  /// isOSDarwin - Is this a "Darwin" OS (OS X, iOS, or watchOS).
+  bool isOSDarwin() const {
+    return isMacOSX() || isiOS() || isWatchOS();
+  }
+
+  bool isSimulatorEnvironment() const {
+    return getEnvironment() == Triple::Simulator;
+  }
+
+  bool isMacCatalystEnvironment() const {
+    return getEnvironment() == Triple::MacABI;
+  }
+
+  bool isOSNetBSD() const {
+    return getOS() == Triple::NetBSD;
+  }
+
+  bool isOSOpenBSD() const {
+    return getOS() == Triple::OpenBSD;
+  }
+
+  bool isOSFreeBSD() const {
+    return getOS() == Triple::FreeBSD;
+  }
+
+  bool isOSFuchsia() const {
+    return getOS() == Triple::Fuchsia;
+  }
+
+  bool isOSDragonFly() const { return getOS() == Triple::DragonFly; }
+
+  bool isOSSolaris() const {
+    return getOS() == Triple::Solaris;
+  }
+
+  bool isOSIAMCU() const {
+    return getOS() == Triple::ELFIAMCU;
+  }
+
+  bool isOSUnknown() const { return getOS() == Triple::UnknownOS; }
+
+  bool isGNUEnvironment() const {
+    EnvironmentType Env = getEnvironment();
+    return Env == Triple::GNU || Env == Triple::GNUABIN32 ||
+           Env == Triple::GNUABI64 || Env == Triple::GNUEABI ||
+           Env == Triple::GNUEABIHF || Env == Triple::GNUX32;
+  }
+
+  bool isOSContiki() const {
+    return getOS() == Triple::Contiki;
+  }
+
+  /// Tests whether the OS is Haiku.
+  bool isOSHaiku() const {
+    return getOS() == Triple::Haiku;
+  }
+
+  /// Tests whether the OS is Windows.
+  bool isOSWindows() const {
+    return getOS() == Triple::Win32;
+  }
+
+  /// Checks if the environment is MSVC.
+  bool isKnownWindowsMSVCEnvironment() const {
+    return isOSWindows() && getEnvironment() == Triple::MSVC;
+  }
+
+  /// Checks if the environment could be MSVC.
+  bool isWindowsMSVCEnvironment() const {
+    return isKnownWindowsMSVCEnvironment() ||
+           (isOSWindows() && getEnvironment() == Triple::UnknownEnvironment);
+  }
+
+  bool isWindowsCoreCLREnvironment() const {
+    return isOSWindows() && getEnvironment() == Triple::CoreCLR;
+  }
+
+  bool isWindowsItaniumEnvironment() const {
+    return isOSWindows() && getEnvironment() == Triple::Itanium;
+  }
+
+  bool isWindowsCygwinEnvironment() const {
+    return isOSWindows() && getEnvironment() == Triple::Cygnus;
+  }
+
+  bool isWindowsGNUEnvironment() const {
+    return isOSWindows() && getEnvironment() == Triple::GNU;
+  }
+
+  /// Tests for either Cygwin or MinGW OS
+  bool isOSCygMing() const {
+    return isWindowsCygwinEnvironment() || isWindowsGNUEnvironment();
+  }
+
+  /// Is this a "Windows" OS targeting a "MSVCRT.dll" environment.
+  bool isOSMSVCRT() const {
+    return isWindowsMSVCEnvironment() || isWindowsGNUEnvironment() ||
+           isWindowsItaniumEnvironment();
+  }
+
+  /// Tests whether the OS is NaCl (Native Client)
+  bool isOSNaCl() const {
+    return getOS() == Triple::NaCl;
+  }
+
+  /// Tests whether the OS is Linux.
+  bool isOSLinux() const {
+    return getOS() == Triple::Linux;
+  }
+
+  /// Tests whether the OS is kFreeBSD.
+  bool isOSKFreeBSD() const {
+    return getOS() == Triple::KFreeBSD;
+  }
+
+  /// Tests whether the OS is Hurd.
+  bool isOSHurd() const {
+    return getOS() == Triple::Hurd;
+  }
+
+  /// Tests whether the OS is WASI.
+  bool isOSWASI() const {
+    return getOS() == Triple::WASI;
+  }
+
+  /// Tests whether the OS is Emscripten.
+  bool isOSEmscripten() const {
+    return getOS() == Triple::Emscripten;
+  }
+
+  /// Tests whether the OS uses glibc.
+  bool isOSGlibc() const {
+    return (getOS() == Triple::Linux || getOS() == Triple::KFreeBSD ||
+            getOS() == Triple::Hurd) &&
+           !isAndroid();
+  }
+
+  /// Tests whether the OS is AIX.
+  bool isOSAIX() const {
+    return getOS() == Triple::AIX;
+  }
+
+  /// Tests whether the OS uses the ELF binary format.
+  bool isOSBinFormatELF() const {
+    return getObjectFormat() == Triple::ELF;
+  }
+
+  /// Tests whether the OS uses the COFF binary format.
+  bool isOSBinFormatCOFF() const {
+    return getObjectFormat() == Triple::COFF;
+  }
+
+  /// Tests whether the environment is MachO.
+  bool isOSBinFormatMachO() const {
+    return getObjectFormat() == Triple::MachO;
+  }
+
+  /// Tests whether the OS uses the Wasm binary format.
+  bool isOSBinFormatWasm() const {
+    return getObjectFormat() == Triple::Wasm;
+  }
+
+  /// Tests whether the OS uses the XCOFF binary format.
+  bool isOSBinFormatXCOFF() const {
+    return getObjectFormat() == Triple::XCOFF;
+  }
+
+  /// Tests whether the target is the PS4 CPU
+  bool isPS4CPU() const {
+    return getArch() == Triple::x86_64 &&
+           getVendor() == Triple::SCEI &&
+           getOS() == Triple::PS4;
+  }
+
+  /// Tests whether the target is the PS4 platform
+  bool isPS4() const {
+    return getVendor() == Triple::SCEI &&
+           getOS() == Triple::PS4;
+  }
+
+  /// Tests whether the target is Android
+  bool isAndroid() const { return getEnvironment() == Triple::Android; }
+
+  bool isAndroidVersionLT(unsigned Major) const {
+    assert(isAndroid() && "Not an Android triple!");
+
+    unsigned Env[3];
+    getEnvironmentVersion(Env[0], Env[1], Env[2]);
+
+    // 64-bit targets did not exist before API level 21 (Lollipop).
+    if (isArch64Bit() && Env[0] < 21)
+      Env[0] = 21;
+
+    return Env[0] < Major;
+  }
+
+  /// Tests whether the environment is musl-libc
+  bool isMusl() const {
+    return getEnvironment() == Triple::Musl ||
+           getEnvironment() == Triple::MuslEABI ||
+           getEnvironment() == Triple::MuslEABIHF;
+  }
+
+  /// Tests whether the target is SPIR (32- or 64-bit).
+  bool isSPIR() const {
+    return getArch() == Triple::spir || getArch() == Triple::spir64;
+  }
+
+  /// Tests whether the target is NVPTX (32- or 64-bit).
+  bool isNVPTX() const {
+    return getArch() == Triple::nvptx || getArch() == Triple::nvptx64;
+  }
+
+  /// Tests whether the target is Thumb (little and big endian).
+  bool isThumb() const {
+    return getArch() == Triple::thumb || getArch() == Triple::thumbeb;
+  }
+
+  /// Tests whether the target is ARM (little and big endian).
+  bool isARM() const {
+    return getArch() == Triple::arm || getArch() == Triple::armeb;
+  }
+
+  /// Tests whether the target is AArch64 (little and big endian).
+  bool isAArch64() const {
+    return getArch() == Triple::aarch64 || getArch() == Triple::aarch64_be;
+  }
+
+  /// Tests whether the target is MIPS 32-bit (little and big endian).
+  bool isMIPS32() const {
+    return getArch() == Triple::mips || getArch() == Triple::mipsel;
+  }
+
+  /// Tests whether the target is MIPS 64-bit (little and big endian).
+  bool isMIPS64() const {
+    return getArch() == Triple::mips64 || getArch() == Triple::mips64el;
+  }
+
+  /// Tests whether the target is MIPS (little and big endian, 32- or 64-bit).
+  bool isMIPS() const {
+    return isMIPS32() || isMIPS64();
+  }
+
+  /// Tests whether the target is 64-bit PowerPC (little and big endian).
+  bool isPPC64() const {
+    return getArch() == Triple::ppc64 || getArch() == Triple::ppc64le;
+  }
+
+  /// Tests whether the target is RISC-V (32- and 64-bit).
+  bool isRISCV() const {
+    return getArch() == Triple::riscv32 || getArch() == Triple::riscv64;
+  }
+
+  /// Tests whether the target supports comdat
+  bool supportsCOMDAT() const {
+    return !isOSBinFormatMachO();
+  }
+
+  /// Tests whether the target uses emulated TLS as default.
+  bool hasDefaultEmulatedTLS() const {
+    return isAndroid() || isOSOpenBSD() || isWindowsCygwinEnvironment();
+  }
+
+  /// @}
+  /// @name Mutators
+  /// @{
+
+  /// setArch - Set the architecture (first) component of the triple
+  /// to a known type.
+  void setArch(ArchType Kind);
+
+  /// setVendor - Set the vendor (second) component of the triple to a
+  /// known type.
+  void setVendor(VendorType Kind);
+
+  /// setOS - Set the operating system (third) component of the triple
+  /// to a known type.
+  void setOS(OSType Kind);
+
+  /// setEnvironment - Set the environment (fourth) component of the triple
+  /// to a known type.
+  void setEnvironment(EnvironmentType Kind);
+
+  /// setObjectFormat - Set the object file format
+  void setObjectFormat(ObjectFormatType Kind);
+
+  /// setTriple - Set all components to the new triple \p Str.
+  void setTriple(const Twine &Str);
+
+  /// setArchName - Set the architecture (first) component of the
+  /// triple by name.
+  void setArchName(StringRef Str);
+
+  /// setVendorName - Set the vendor (second) component of the triple
+  /// by name.
+  void setVendorName(StringRef Str);
+
+  /// setOSName - Set the operating system (third) component of the
+  /// triple by name.
+  void setOSName(StringRef Str);
+
+  /// setEnvironmentName - Set the optional environment (fourth)
+  /// component of the triple by name.
+  void setEnvironmentName(StringRef Str);
+
+  /// setOSAndEnvironmentName - Set the operating system and optional
+  /// environment components with a single string.
+  void setOSAndEnvironmentName(StringRef Str);
+
+  /// @}
+  /// @name Helpers to build variants of a particular triple.
+  /// @{
+
+  /// Form a triple with a 32-bit variant of the current architecture.
+  ///
+  /// This can be used to move across "families" of architectures where useful.
+  ///
+  /// \returns A new triple with a 32-bit architecture or an unknown
+  ///          architecture if no such variant can be found.
+  llvm::Triple get32BitArchVariant() const;
+
+  /// Form a triple with a 64-bit variant of the current architecture.
+  ///
+  /// This can be used to move across "families" of architectures where useful.
+  ///
+  /// \returns A new triple with a 64-bit architecture or an unknown
+  ///          architecture if no such variant can be found.
+  llvm::Triple get64BitArchVariant() const;
+
+  /// Form a triple with a big endian variant of the current architecture.
+  ///
+  /// This can be used to move across "families" of architectures where useful.
+  ///
+  /// \returns A new triple with a big endian architecture or an unknown
+  ///          architecture if no such variant can be found.
+  llvm::Triple getBigEndianArchVariant() const;
+
+  /// Form a triple with a little endian variant of the current architecture.
+  ///
+  /// This can be used to move across "families" of architectures where useful.
+  ///
+  /// \returns A new triple with a little endian architecture or an unknown
+  ///          architecture if no such variant can be found.
+  llvm::Triple getLittleEndianArchVariant() const;
+
+  /// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting.
+  ///
+  /// \param Arch the architecture name (e.g., "armv7s"). If it is an empty
+  /// string then the triple's arch name is used.
+  StringRef getARMCPUForArch(StringRef Arch = StringRef()) const;
+
+  /// Tests whether the target triple is little endian.
+  ///
+  /// \returns true if the triple is little endian, false otherwise.
+  bool isLittleEndian() const;
+
+  /// Test whether target triples are compatible.
+  bool isCompatibleWith(const Triple &Other) const;
+
+  /// Merge target triples.
+  std::string merge(const Triple &Other) const;
+
+  /// @}
+  /// @name Static helpers for IDs.
+  /// @{
+
+  /// getArchTypeName - Get the canonical name for the \p Kind architecture.
+  static StringRef getArchTypeName(ArchType Kind);
+
+  /// getArchTypePrefix - Get the "prefix" canonical name for the \p Kind
+  /// architecture. This is the prefix used by the architecture specific
+  /// builtins, and is suitable for passing to \see
+  /// Intrinsic::getIntrinsicForGCCBuiltin().
+  ///
+  /// \return - The architecture prefix, or 0 if none is defined.
+  static StringRef getArchTypePrefix(ArchType Kind);
+
+  /// getVendorTypeName - Get the canonical name for the \p Kind vendor.
+  static StringRef getVendorTypeName(VendorType Kind);
+
+  /// getOSTypeName - Get the canonical name for the \p Kind operating system.
+  static StringRef getOSTypeName(OSType Kind);
+
+  /// getEnvironmentTypeName - Get the canonical name for the \p Kind
+  /// environment.
+  static StringRef getEnvironmentTypeName(EnvironmentType Kind);
+
+  /// @}
+  /// @name Static helpers for converting alternate architecture names.
+  /// @{
+
+  /// getArchTypeForLLVMName - The canonical type for the given LLVM
+  /// architecture name (e.g., "x86").
+  static ArchType getArchTypeForLLVMName(StringRef Str);
+
+  /// @}
+};
+
+} // End llvm namespace
+
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/Twine.h b/binaryen/third_party/llvm-project/include/llvm/ADT/Twine.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/Twine.h
@@ -0,0 +1,544 @@
+//===- Twine.h - Fast Temporary String Concatenation ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_TWINE_H
+#define LLVM_ADT_TWINE_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cassert>
+#include <cstdint>
+#include <string>
+
+namespace llvm {
+
+  class formatv_object_base;
+  class raw_ostream;
+
+  /// Twine - A lightweight data structure for efficiently representing the
+  /// concatenation of temporary values as strings.
+  ///
+  /// A Twine is a kind of rope, it represents a concatenated string using a
+  /// binary-tree, where the string is the preorder of the nodes. Since the
+  /// Twine can be efficiently rendered into a buffer when its result is used,
+  /// it avoids the cost of generating temporary values for intermediate string
+  /// results -- particularly in cases when the Twine result is never
+  /// required. By explicitly tracking the type of leaf nodes, we can also avoid
+  /// the creation of temporary strings for conversions operations (such as
+  /// appending an integer to a string).
+  ///
+  /// A Twine is not intended for use directly and should not be stored, its
+  /// implementation relies on the ability to store pointers to temporary stack
+  /// objects which may be deallocated at the end of a statement. Twines should
+  /// only be used accepted as const references in arguments, when an API wishes
+  /// to accept possibly-concatenated strings.
+  ///
+  /// Twines support a special 'null' value, which always concatenates to form
+  /// itself, and renders as an empty string. This can be returned from APIs to
+  /// effectively nullify any concatenations performed on the result.
+  ///
+  /// \b Implementation
+  ///
+  /// Given the nature of a Twine, it is not possible for the Twine's
+  /// concatenation method to construct interior nodes; the result must be
+  /// represented inside the returned value. For this reason a Twine object
+  /// actually holds two values, the left- and right-hand sides of a
+  /// concatenation. We also have nullary Twine objects, which are effectively
+  /// sentinel values that represent empty strings.
+  ///
+  /// Thus, a Twine can effectively have zero, one, or two children. The \see
+  /// isNullary(), \see isUnary(), and \see isBinary() predicates exist for
+  /// testing the number of children.
+  ///
+  /// We maintain a number of invariants on Twine objects (FIXME: Why):
+  ///  - Nullary twines are always represented with their Kind on the left-hand
+  ///    side, and the Empty kind on the right-hand side.
+  ///  - Unary twines are always represented with the value on the left-hand
+  ///    side, and the Empty kind on the right-hand side.
+  ///  - If a Twine has another Twine as a child, that child should always be
+  ///    binary (otherwise it could have been folded into the parent).
+  ///
+  /// These invariants are check by \see isValid().
+  ///
+  /// \b Efficiency Considerations
+  ///
+  /// The Twine is designed to yield efficient and small code for common
+  /// situations. For this reason, the concat() method is inlined so that
+  /// concatenations of leaf nodes can be optimized into stores directly into a
+  /// single stack allocated object.
+  ///
+  /// In practice, not all compilers can be trusted to optimize concat() fully,
+  /// so we provide two additional methods (and accompanying operator+
+  /// overloads) to guarantee that particularly important cases (cstring plus
+  /// StringRef) codegen as desired.
+  class Twine {
+    /// NodeKind - Represent the type of an argument.
+    enum NodeKind : unsigned char {
+      /// An empty string; the result of concatenating anything with it is also
+      /// empty.
+      NullKind,
+
+      /// The empty string.
+      EmptyKind,
+
+      /// A pointer to a Twine instance.
+      TwineKind,
+
+      /// A pointer to a C string instance.
+      CStringKind,
+
+      /// A pointer to an std::string instance.
+      StdStringKind,
+
+      /// A pointer to a StringRef instance.
+      StringRefKind,
+
+      /// A pointer to a SmallString instance.
+      SmallStringKind,
+
+      /// A pointer to a formatv_object_base instance.
+      FormatvObjectKind,
+
+      /// A char value, to render as a character.
+      CharKind,
+
+      /// An unsigned int value, to render as an unsigned decimal integer.
+      DecUIKind,
+
+      /// An int value, to render as a signed decimal integer.
+      DecIKind,
+
+      /// A pointer to an unsigned long value, to render as an unsigned decimal
+      /// integer.
+      DecULKind,
+
+      /// A pointer to a long value, to render as a signed decimal integer.
+      DecLKind,
+
+      /// A pointer to an unsigned long long value, to render as an unsigned
+      /// decimal integer.
+      DecULLKind,
+
+      /// A pointer to a long long value, to render as a signed decimal integer.
+      DecLLKind,
+
+      /// A pointer to a uint64_t value, to render as an unsigned hexadecimal
+      /// integer.
+      UHexKind
+    };
+
+    union Child
+    {
+      const Twine *twine;
+      const char *cString;
+      const std::string *stdString;
+      const StringRef *stringRef;
+      const SmallVectorImpl<char> *smallString;
+      const formatv_object_base *formatvObject;
+      char character;
+      unsigned int decUI;
+      int decI;
+      const unsigned long *decUL;
+      const long *decL;
+      const unsigned long long *decULL;
+      const long long *decLL;
+      const uint64_t *uHex;
+    };
+
+    /// LHS - The prefix in the concatenation, which may be uninitialized for
+    /// Null or Empty kinds.
+    Child LHS = {0};
+
+    /// RHS - The suffix in the concatenation, which may be uninitialized for
+    /// Null or Empty kinds.
+    Child RHS = {0};
+
+    /// LHSKind - The NodeKind of the left hand side, \see getLHSKind().
+    NodeKind LHSKind = EmptyKind;
+
+    /// RHSKind - The NodeKind of the right hand side, \see getRHSKind().
+    NodeKind RHSKind = EmptyKind;
+
+    /// Construct a nullary twine; the kind must be NullKind or EmptyKind.
+    explicit Twine(NodeKind Kind) : LHSKind(Kind) {
+      assert(isNullary() && "Invalid kind!");
+    }
+
+    /// Construct a binary twine.
+    explicit Twine(const Twine &LHS, const Twine &RHS)
+        : LHSKind(TwineKind), RHSKind(TwineKind) {
+      this->LHS.twine = &LHS;
+      this->RHS.twine = &RHS;
+      assert(isValid() && "Invalid twine!");
+    }
+
+    /// Construct a twine from explicit values.
+    explicit Twine(Child LHS, NodeKind LHSKind, Child RHS, NodeKind RHSKind)
+        : LHS(LHS), RHS(RHS), LHSKind(LHSKind), RHSKind(RHSKind) {
+      assert(isValid() && "Invalid twine!");
+    }
+
+    /// Check for the null twine.
+    bool isNull() const {
+      return getLHSKind() == NullKind;
+    }
+
+    /// Check for the empty twine.
+    bool isEmpty() const {
+      return getLHSKind() == EmptyKind;
+    }
+
+    /// Check if this is a nullary twine (null or empty).
+    bool isNullary() const {
+      return isNull() || isEmpty();
+    }
+
+    /// Check if this is a unary twine.
+    bool isUnary() const {
+      return getRHSKind() == EmptyKind && !isNullary();
+    }
+
+    /// Check if this is a binary twine.
+    bool isBinary() const {
+      return getLHSKind() != NullKind && getRHSKind() != EmptyKind;
+    }
+
+    /// Check if this is a valid twine (satisfying the invariants on
+    /// order and number of arguments).
+    bool isValid() const {
+      // Nullary twines always have Empty on the RHS.
+      if (isNullary() && getRHSKind() != EmptyKind)
+        return false;
+
+      // Null should never appear on the RHS.
+      if (getRHSKind() == NullKind)
+        return false;
+
+      // The RHS cannot be non-empty if the LHS is empty.
+      if (getRHSKind() != EmptyKind && getLHSKind() == EmptyKind)
+        return false;
+
+      // A twine child should always be binary.
+      if (getLHSKind() == TwineKind &&
+          !LHS.twine->isBinary())
+        return false;
+      if (getRHSKind() == TwineKind &&
+          !RHS.twine->isBinary())
+        return false;
+
+      return true;
+    }
+
+    /// Get the NodeKind of the left-hand side.
+    NodeKind getLHSKind() const { return LHSKind; }
+
+    /// Get the NodeKind of the right-hand side.
+    NodeKind getRHSKind() const { return RHSKind; }
+
+    /// Print one child from a twine.
+    void printOneChild(raw_ostream &OS, Child Ptr, NodeKind Kind) const;
+
+    /// Print the representation of one child from a twine.
+    void printOneChildRepr(raw_ostream &OS, Child Ptr,
+                           NodeKind Kind) const;
+
+  public:
+    /// @name Constructors
+    /// @{
+
+    /// Construct from an empty string.
+    /*implicit*/ Twine() {
+      assert(isValid() && "Invalid twine!");
+    }
+
+    Twine(const Twine &) = default;
+
+    /// Construct from a C string.
+    ///
+    /// We take care here to optimize "" into the empty twine -- this will be
+    /// optimized out for string constants. This allows Twine arguments have
+    /// default "" values, without introducing unnecessary string constants.
+    /*implicit*/ Twine(const char *Str) {
+      if (Str[0] != '\0') {
+        LHS.cString = Str;
+        LHSKind = CStringKind;
+      } else
+        LHSKind = EmptyKind;
+
+      assert(isValid() && "Invalid twine!");
+    }
+    /// Delete the implicit conversion from nullptr as Twine(const char *)
+    /// cannot take nullptr.
+    /*implicit*/ Twine(std::nullptr_t) = delete;
+
+    /// Construct from an std::string.
+    /*implicit*/ Twine(const std::string &Str) : LHSKind(StdStringKind) {
+      LHS.stdString = &Str;
+      assert(isValid() && "Invalid twine!");
+    }
+
+    /// Construct from a StringRef.
+    /*implicit*/ Twine(const StringRef &Str) : LHSKind(StringRefKind) {
+      LHS.stringRef = &Str;
+      assert(isValid() && "Invalid twine!");
+    }
+
+    /// Construct from a SmallString.
+    /*implicit*/ Twine(const SmallVectorImpl<char> &Str)
+        : LHSKind(SmallStringKind) {
+      LHS.smallString = &Str;
+      assert(isValid() && "Invalid twine!");
+    }
+
+    /// Construct from a formatv_object_base.
+    /*implicit*/ Twine(const formatv_object_base &Fmt)
+        : LHSKind(FormatvObjectKind) {
+      LHS.formatvObject = &Fmt;
+      assert(isValid() && "Invalid twine!");
+    }
+
+    /// Construct from a char.
+    explicit Twine(char Val) : LHSKind(CharKind) {
+      LHS.character = Val;
+    }
+
+    /// Construct from a signed char.
+    explicit Twine(signed char Val) : LHSKind(CharKind) {
+      LHS.character = static_cast<char>(Val);
+    }
+
+    /// Construct from an unsigned char.
+    explicit Twine(unsigned char Val) : LHSKind(CharKind) {
+      LHS.character = static_cast<char>(Val);
+    }
+
+    /// Construct a twine to print \p Val as an unsigned decimal integer.
+    explicit Twine(unsigned Val) : LHSKind(DecUIKind) {
+      LHS.decUI = Val;
+    }
+
+    /// Construct a twine to print \p Val as a signed decimal integer.
+    explicit Twine(int Val) : LHSKind(DecIKind) {
+      LHS.decI = Val;
+    }
+
+    /// Construct a twine to print \p Val as an unsigned decimal integer.
+    explicit Twine(const unsigned long &Val) : LHSKind(DecULKind) {
+      LHS.decUL = &Val;
+    }
+
+    /// Construct a twine to print \p Val as a signed decimal integer.
+    explicit Twine(const long &Val) : LHSKind(DecLKind) {
+      LHS.decL = &Val;
+    }
+
+    /// Construct a twine to print \p Val as an unsigned decimal integer.
+    explicit Twine(const unsigned long long &Val) : LHSKind(DecULLKind) {
+      LHS.decULL = &Val;
+    }
+
+    /// Construct a twine to print \p Val as a signed decimal integer.
+    explicit Twine(const long long &Val) : LHSKind(DecLLKind) {
+      LHS.decLL = &Val;
+    }
+
+    // FIXME: Unfortunately, to make sure this is as efficient as possible we
+    // need extra binary constructors from particular types. We can't rely on
+    // the compiler to be smart enough to fold operator+()/concat() down to the
+    // right thing. Yet.
+
+    /// Construct as the concatenation of a C string and a StringRef.
+    /*implicit*/ Twine(const char *LHS, const StringRef &RHS)
+        : LHSKind(CStringKind), RHSKind(StringRefKind) {
+      this->LHS.cString = LHS;
+      this->RHS.stringRef = &RHS;
+      assert(isValid() && "Invalid twine!");
+    }
+
+    /// Construct as the concatenation of a StringRef and a C string.
+    /*implicit*/ Twine(const StringRef &LHS, const char *RHS)
+        : LHSKind(StringRefKind), RHSKind(CStringKind) {
+      this->LHS.stringRef = &LHS;
+      this->RHS.cString = RHS;
+      assert(isValid() && "Invalid twine!");
+    }
+
+    /// Since the intended use of twines is as temporary objects, assignments
+    /// when concatenating might cause undefined behavior or stack corruptions
+    Twine &operator=(const Twine &) = delete;
+
+    /// Create a 'null' string, which is an empty string that always
+    /// concatenates to form another empty string.
+    static Twine createNull() {
+      return Twine(NullKind);
+    }
+
+    /// @}
+    /// @name Numeric Conversions
+    /// @{
+
+    // Construct a twine to print \p Val as an unsigned hexadecimal integer.
+    static Twine utohexstr(const uint64_t &Val) {
+      Child LHS, RHS;
+      LHS.uHex = &Val;
+      RHS.twine = nullptr;
+      return Twine(LHS, UHexKind, RHS, EmptyKind);
+    }
+
+    /// @}
+    /// @name Predicate Operations
+    /// @{
+
+    /// Check if this twine is trivially empty; a false return value does not
+    /// necessarily mean the twine is empty.
+    bool isTriviallyEmpty() const {
+      return isNullary();
+    }
+
+    /// Return true if this twine can be dynamically accessed as a single
+    /// StringRef value with getSingleStringRef().
+    bool isSingleStringRef() const {
+      if (getRHSKind() != EmptyKind) return false;
+
+      switch (getLHSKind()) {
+      case EmptyKind:
+      case CStringKind:
+      case StdStringKind:
+      case StringRefKind:
+      case SmallStringKind:
+        return true;
+      default:
+        return false;
+      }
+    }
+
+    /// @}
+    /// @name String Operations
+    /// @{
+
+    Twine concat(const Twine &Suffix) const;
+
+    /// @}
+    /// @name Output & Conversion.
+    /// @{
+
+    /// Return the twine contents as a std::string.
+    std::string str() const;
+
+    /// Append the concatenated string into the given SmallString or SmallVector.
+    void toVector(SmallVectorImpl<char> &Out) const;
+
+    /// This returns the twine as a single StringRef.  This method is only valid
+    /// if isSingleStringRef() is true.
+    StringRef getSingleStringRef() const {
+      assert(isSingleStringRef() &&"This cannot be had as a single stringref!");
+      switch (getLHSKind()) {
+      default: llvm_unreachable("Out of sync with isSingleStringRef");
+      case EmptyKind:      return StringRef();
+      case CStringKind:    return StringRef(LHS.cString);
+      case StdStringKind:  return StringRef(*LHS.stdString);
+      case StringRefKind:  return *LHS.stringRef;
+      case SmallStringKind:
+        return StringRef(LHS.smallString->data(), LHS.smallString->size());
+      }
+    }
+
+    /// This returns the twine as a single StringRef if it can be
+    /// represented as such. Otherwise the twine is written into the given
+    /// SmallVector and a StringRef to the SmallVector's data is returned.
+    StringRef toStringRef(SmallVectorImpl<char> &Out) const {
+      if (isSingleStringRef())
+        return getSingleStringRef();
+      toVector(Out);
+      return StringRef(Out.data(), Out.size());
+    }
+
+    /// This returns the twine as a single null terminated StringRef if it
+    /// can be represented as such. Otherwise the twine is written into the
+    /// given SmallVector and a StringRef to the SmallVector's data is returned.
+    ///
+    /// The returned StringRef's size does not include the null terminator.
+    StringRef toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const;
+
+    /// Write the concatenated string represented by this twine to the
+    /// stream \p OS.
+    void print(raw_ostream &OS) const;
+
+    /// Dump the concatenated string represented by this twine to stderr.
+    void dump() const;
+
+    /// Write the representation of this twine to the stream \p OS.
+    void printRepr(raw_ostream &OS) const;
+
+    /// Dump the representation of this twine to stderr.
+    void dumpRepr() const;
+
+    /// @}
+  };
+
+  /// @name Twine Inline Implementations
+  /// @{
+
+  inline Twine Twine::concat(const Twine &Suffix) const {
+    // Concatenation with null is null.
+    if (isNull() || Suffix.isNull())
+      return Twine(NullKind);
+
+    // Concatenation with empty yields the other side.
+    if (isEmpty())
+      return Suffix;
+    if (Suffix.isEmpty())
+      return *this;
+
+    // Otherwise we need to create a new node, taking care to fold in unary
+    // twines.
+    Child NewLHS, NewRHS;
+    NewLHS.twine = this;
+    NewRHS.twine = &Suffix;
+    NodeKind NewLHSKind = TwineKind, NewRHSKind = TwineKind;
+    if (isUnary()) {
+      NewLHS = LHS;
+      NewLHSKind = getLHSKind();
+    }
+    if (Suffix.isUnary()) {
+      NewRHS = Suffix.LHS;
+      NewRHSKind = Suffix.getLHSKind();
+    }
+
+    return Twine(NewLHS, NewLHSKind, NewRHS, NewRHSKind);
+  }
+
+  inline Twine operator+(const Twine &LHS, const Twine &RHS) {
+    return LHS.concat(RHS);
+  }
+
+  /// Additional overload to guarantee simplified codegen; this is equivalent to
+  /// concat().
+
+  inline Twine operator+(const char *LHS, const StringRef &RHS) {
+    return Twine(LHS, RHS);
+  }
+
+  /// Additional overload to guarantee simplified codegen; this is equivalent to
+  /// concat().
+
+  inline Twine operator+(const StringRef &LHS, const char *RHS) {
+    return Twine(LHS, RHS);
+  }
+
+  inline raw_ostream &operator<<(raw_ostream &OS, const Twine &RHS) {
+    RHS.print(OS);
+    return OS;
+  }
+
+  /// @}
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_TWINE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/bit.h b/binaryen/third_party/llvm-project/include/llvm/ADT/bit.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/bit.h
@@ -0,0 +1,58 @@
+//===-- llvm/ADT/bit.h - C++20 <bit> ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the C++20 <bit> header.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_BIT_H
+#define LLVM_ADT_BIT_H
+
+#include "llvm/Support/Compiler.h"
+#include <cstring>
+#include <type_traits>
+
+namespace llvm {
+
+// This implementation of bit_cast is different from the C++17 one in two ways:
+//  - It isn't constexpr because that requires compiler support.
+//  - It requires trivially-constructible To, to avoid UB in the implementation.
+template <typename To, typename From
+          , typename = typename std::enable_if<sizeof(To) == sizeof(From)>::type
+#if (__has_feature(is_trivially_constructible) && defined(_LIBCPP_VERSION)) || \
+    (defined(__GNUC__) && __GNUC__ >= 5)
+          , typename = typename std::is_trivially_constructible<To>::type
+#elif __has_feature(is_trivially_constructible)
+          , typename = typename std::enable_if<__is_trivially_constructible(To)>::type
+#else
+  // See comment below.
+#endif
+#if (__has_feature(is_trivially_copyable) && defined(_LIBCPP_VERSION)) || \
+    (defined(__GNUC__) && __GNUC__ >= 5)
+          , typename = typename std::enable_if<std::is_trivially_copyable<To>::value>::type
+          , typename = typename std::enable_if<std::is_trivially_copyable<From>::value>::type
+#elif __has_feature(is_trivially_copyable)
+          , typename = typename std::enable_if<__is_trivially_copyable(To)>::type
+          , typename = typename std::enable_if<__is_trivially_copyable(From)>::type
+#else
+// This case is GCC 4.x. clang with libc++ or libstdc++ never get here. Unlike
+// llvm/Support/type_traits.h's is_trivially_copyable we don't want to
+// provide a good-enough answer here: developers in that configuration will hit
+// compilation failures on the bots instead of locally. That's acceptable
+// because it's very few developers, and only until we move past C++11.
+#endif
+>
+inline To bit_cast(const From &from) noexcept {
+  To to;
+  std::memcpy(&to, &from, sizeof(To));
+  return to;
+}
+
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/edit_distance.h b/binaryen/third_party/llvm-project/include/llvm/ADT/edit_distance.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/edit_distance.h
@@ -0,0 +1,102 @@
+//===-- llvm/ADT/edit_distance.h - Array edit distance function --- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a Levenshtein distance function that works for any two
+// sequences, with each element of each sequence being analogous to a character
+// in a string.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_EDIT_DISTANCE_H
+#define LLVM_ADT_EDIT_DISTANCE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include <algorithm>
+#include <memory>
+
+namespace llvm {
+
+/// Determine the edit distance between two sequences.
+///
+/// \param FromArray the first sequence to compare.
+///
+/// \param ToArray the second sequence to compare.
+///
+/// \param AllowReplacements whether to allow element replacements (change one
+/// element into another) as a single operation, rather than as two operations
+/// (an insertion and a removal).
+///
+/// \param MaxEditDistance If non-zero, the maximum edit distance that this
+/// routine is allowed to compute. If the edit distance will exceed that
+/// maximum, returns \c MaxEditDistance+1.
+///
+/// \returns the minimum number of element insertions, removals, or (if
+/// \p AllowReplacements is \c true) replacements needed to transform one of
+/// the given sequences into the other. If zero, the sequences are identical.
+template<typename T>
+unsigned ComputeEditDistance(ArrayRef<T> FromArray, ArrayRef<T> ToArray,
+                             bool AllowReplacements = true,
+                             unsigned MaxEditDistance = 0) {
+  // The algorithm implemented below is the "classic"
+  // dynamic-programming algorithm for computing the Levenshtein
+  // distance, which is described here:
+  //
+  //   http://en.wikipedia.org/wiki/Levenshtein_distance
+  //
+  // Although the algorithm is typically described using an m x n
+  // array, only one row plus one element are used at a time, so this
+  // implementation just keeps one vector for the row.  To update one entry,
+  // only the entries to the left, top, and top-left are needed.  The left
+  // entry is in Row[x-1], the top entry is what's in Row[x] from the last
+  // iteration, and the top-left entry is stored in Previous.
+  typename ArrayRef<T>::size_type m = FromArray.size();
+  typename ArrayRef<T>::size_type n = ToArray.size();
+
+  const unsigned SmallBufferSize = 64;
+  unsigned SmallBuffer[SmallBufferSize];
+  std::unique_ptr<unsigned[]> Allocated;
+  unsigned *Row = SmallBuffer;
+  if (n + 1 > SmallBufferSize) {
+    Row = new unsigned[n + 1];
+    Allocated.reset(Row);
+  }
+
+  for (unsigned i = 1; i <= n; ++i)
+    Row[i] = i;
+
+  for (typename ArrayRef<T>::size_type y = 1; y <= m; ++y) {
+    Row[0] = y;
+    unsigned BestThisRow = Row[0];
+
+    unsigned Previous = y - 1;
+    for (typename ArrayRef<T>::size_type x = 1; x <= n; ++x) {
+      int OldRow = Row[x];
+      if (AllowReplacements) {
+        Row[x] = std::min(
+            Previous + (FromArray[y-1] == ToArray[x-1] ? 0u : 1u),
+            std::min(Row[x-1], Row[x])+1);
+      }
+      else {
+        if (FromArray[y-1] == ToArray[x-1]) Row[x] = Previous;
+        else Row[x] = std::min(Row[x-1], Row[x]) + 1;
+      }
+      Previous = OldRow;
+      BestThisRow = std::min(BestThisRow, Row[x]);
+    }
+
+    if (MaxEditDistance && BestThisRow > MaxEditDistance)
+      return MaxEditDistance + 1;
+  }
+
+  unsigned Result = Row[n];
+  return Result;
+}
+
+} // End llvm namespace
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/fallible_iterator.h b/binaryen/third_party/llvm-project/include/llvm/ADT/fallible_iterator.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/fallible_iterator.h
@@ -0,0 +1,243 @@
+//===--- fallible_iterator.h - Wrapper for fallible iterators ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_FALLIBLE_ITERATOR_H
+#define LLVM_ADT_FALLIBLE_ITERATOR_H
+
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Error.h"
+
+#include <type_traits>
+
+namespace llvm {
+
+/// A wrapper class for fallible iterators.
+///
+///   The fallible_iterator template wraps an underlying iterator-like class
+/// whose increment and decrement operations are replaced with fallible versions
+/// like:
+///
+///   @code{.cpp}
+///   Error inc();
+///   Error dec();
+///   @endcode
+///
+///   It produces an interface that is (mostly) compatible with a traditional
+/// c++ iterator, including ++ and -- operators that do not fail.
+///
+///   Instances of the wrapper are constructed with an instance of the
+/// underlying iterator and (for non-end iterators) a reference to an Error
+/// instance. If the underlying increment/decrement operations fail, the Error
+/// is returned via this reference, and the resulting iterator value set to an
+/// end-of-range sentinel value. This enables the following loop idiom:
+///
+///   @code{.cpp}
+///   class Archive { // E.g. Potentially malformed on-disk archive
+///   public:
+///     fallible_iterator<ArchiveChildItr> children_begin(Error &Err);
+///     fallible_iterator<ArchiveChildItr> children_end();
+///     iterator_range<fallible_iterator<ArchiveChildItr>>
+///     children(Error &Err) {
+///       return make_range(children_begin(Err), children_end());
+///     //...
+///   };
+///
+///   void walk(Archive &A) {
+///     Error Err = Error::success();
+///     for (auto &C : A.children(Err)) {
+///       // Loop body only entered when increment succeeds.
+///     }
+///     if (Err) {
+///       // handle error.
+///     }
+///   }
+///   @endcode
+///
+///   The wrapper marks the referenced Error as unchecked after each increment
+/// and/or decrement operation, and clears the unchecked flag when a non-end
+/// value is compared against end (since, by the increment invariant, not being
+/// an end value proves that there was no error, and is equivalent to checking
+/// that the Error is success). This allows early exits from the loop body
+/// without requiring redundant error checks.
+template <typename Underlying> class fallible_iterator {
+private:
+  template <typename T>
+  using enable_if_struct_deref_supported = std::enable_if<
+      !std::is_void<decltype(std::declval<T>().operator->())>::value,
+      decltype(std::declval<T>().operator->())>;
+
+public:
+  /// Construct a fallible iterator that *cannot* be used as an end-of-range
+  /// value.
+  ///
+  /// A value created by this method can be dereferenced, incremented,
+  /// decremented and compared, providing the underlying type supports it.
+  ///
+  /// The error that is passed in will be initially marked as checked, so if the
+  /// iterator is not used at all the Error need not be checked.
+  static fallible_iterator itr(Underlying I, Error &Err) {
+    (void)!!Err;
+    return fallible_iterator(std::move(I), &Err);
+  }
+
+  /// Construct a fallible iteratro that can be used as an end-of-range value.
+  ///
+  /// A value created by this method can be dereferenced (if the underlying
+  /// value points at a valid value) and compared, but not incremented or
+  /// decremented.
+  static fallible_iterator end(Underlying I) {
+    return fallible_iterator(std::move(I), nullptr);
+  }
+
+  /// Forward dereference to the underlying iterator.
+  auto operator*() -> decltype(*std::declval<Underlying>()) { return *I; }
+
+  /// Forward const dereference to the underlying iterator.
+  auto operator*() const -> decltype(*std::declval<const Underlying>()) {
+    return *I;
+  }
+
+  /// Forward structure dereference to the underlying iterator (if the
+  /// underlying iterator supports it).
+  template <typename T = Underlying>
+  typename enable_if_struct_deref_supported<T>::type operator->() {
+    return I.operator->();
+  }
+
+  /// Forward const structure dereference to the underlying iterator (if the
+  /// underlying iterator supports it).
+  template <typename T = Underlying>
+  typename enable_if_struct_deref_supported<const T>::type operator->() const {
+    return I.operator->();
+  }
+
+  /// Increment the fallible iterator.
+  ///
+  /// If the underlying 'inc' operation fails, this will set the Error value
+  /// and update this iterator value to point to end-of-range.
+  ///
+  /// The Error value is marked as needing checking, regardless of whether the
+  /// 'inc' operation succeeds or fails.
+  fallible_iterator &operator++() {
+    assert(getErrPtr() && "Cannot increment end iterator");
+    if (auto Err = I.inc())
+      handleError(std::move(Err));
+    else
+      resetCheckedFlag();
+    return *this;
+  }
+
+  /// Decrement the fallible iterator.
+  ///
+  /// If the underlying 'dec' operation fails, this will set the Error value
+  /// and update this iterator value to point to end-of-range.
+  ///
+  /// The Error value is marked as needing checking, regardless of whether the
+  /// 'dec' operation succeeds or fails.
+  fallible_iterator &operator--() {
+    assert(getErrPtr() && "Cannot decrement end iterator");
+    if (auto Err = I.dec())
+      handleError(std::move(Err));
+    else
+      resetCheckedFlag();
+    return *this;
+  }
+
+  /// Compare fallible iterators for equality.
+  ///
+  /// Returns true if both LHS and RHS are end-of-range values, or if both are
+  /// non-end-of-range values whose underlying iterator values compare equal.
+  ///
+  /// If this is a comparison between an end-of-range iterator and a
+  /// non-end-of-range iterator, then the Error (referenced by the
+  /// non-end-of-range value) is marked as checked: Since all
+  /// increment/decrement operations result in an end-of-range value, comparing
+  /// false against end-of-range is equivalent to checking that the Error value
+  /// is success. This flag management enables early returns from loop bodies
+  /// without redundant Error checks.
+  friend bool operator==(const fallible_iterator &LHS,
+                         const fallible_iterator &RHS) {
+    // If both iterators are in the end state they compare
+    // equal, regardless of whether either is valid.
+    if (LHS.isEnd() && RHS.isEnd())
+      return true;
+
+    assert(LHS.isValid() && RHS.isValid() &&
+           "Invalid iterators can only be compared against end");
+
+    bool Equal = LHS.I == RHS.I;
+
+    // If the iterators differ and this is a comparison against end then mark
+    // the Error as checked.
+    if (!Equal) {
+      if (LHS.isEnd())
+        (void)!!*RHS.getErrPtr();
+      else
+        (void)!!*LHS.getErrPtr();
+    }
+
+    return Equal;
+  }
+
+  /// Compare fallible iterators for inequality.
+  ///
+  /// See notes for operator==.
+  friend bool operator!=(const fallible_iterator &LHS,
+                         const fallible_iterator &RHS) {
+    return !(LHS == RHS);
+  }
+
+private:
+  fallible_iterator(Underlying I, Error *Err)
+      : I(std::move(I)), ErrState(Err, false) {}
+
+  Error *getErrPtr() const { return ErrState.getPointer(); }
+
+  bool isEnd() const { return getErrPtr() == nullptr; }
+
+  bool isValid() const { return !ErrState.getInt(); }
+
+  void handleError(Error Err) {
+    *getErrPtr() = std::move(Err);
+    ErrState.setPointer(nullptr);
+    ErrState.setInt(true);
+  }
+
+  void resetCheckedFlag() {
+    *getErrPtr() = Error::success();
+  }
+
+  Underlying I;
+  mutable PointerIntPair<Error *, 1> ErrState;
+};
+
+/// Convenience wrapper to make a fallible_iterator value from an instance
+/// of an underlying iterator and an Error reference.
+template <typename Underlying>
+fallible_iterator<Underlying> make_fallible_itr(Underlying I, Error &Err) {
+  return fallible_iterator<Underlying>::itr(std::move(I), Err);
+}
+
+/// Convenience wrapper to make a fallible_iterator end value from an instance
+/// of an underlying iterator.
+template <typename Underlying>
+fallible_iterator<Underlying> make_fallible_end(Underlying E) {
+  return fallible_iterator<Underlying>::end(std::move(E));
+}
+
+template <typename Underlying>
+iterator_range<fallible_iterator<Underlying>>
+make_fallible_range(Underlying I, Underlying E, Error &Err) {
+  return make_range(make_fallible_itr(std::move(I), Err),
+                    make_fallible_end(std::move(E)));
+}
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_FALLIBLE_ITERATOR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/ilist_base.h b/binaryen/third_party/llvm-project/include/llvm/ADT/ilist_base.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/ilist_base.h
@@ -0,0 +1,92 @@
+//===- llvm/ADT/ilist_base.h - Intrusive List Base --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_ILIST_BASE_H
+#define LLVM_ADT_ILIST_BASE_H
+
+#include "llvm/ADT/ilist_node_base.h"
+#include <cassert>
+
+namespace llvm {
+
+/// Implementations of list algorithms using ilist_node_base.
+template <bool EnableSentinelTracking> class ilist_base {
+public:
+  using node_base_type = ilist_node_base<EnableSentinelTracking>;
+
+  static void insertBeforeImpl(node_base_type &Next, node_base_type &N) {
+    node_base_type &Prev = *Next.getPrev();
+    N.setNext(&Next);
+    N.setPrev(&Prev);
+    Prev.setNext(&N);
+    Next.setPrev(&N);
+  }
+
+  static void removeImpl(node_base_type &N) {
+    node_base_type *Prev = N.getPrev();
+    node_base_type *Next = N.getNext();
+    Next->setPrev(Prev);
+    Prev->setNext(Next);
+
+    // Not strictly necessary, but helps catch a class of bugs.
+    N.setPrev(nullptr);
+    N.setNext(nullptr);
+  }
+
+  static void removeRangeImpl(node_base_type &First, node_base_type &Last) {
+    node_base_type *Prev = First.getPrev();
+    node_base_type *Final = Last.getPrev();
+    Last.setPrev(Prev);
+    Prev->setNext(&Last);
+
+    // Not strictly necessary, but helps catch a class of bugs.
+    First.setPrev(nullptr);
+    Final->setNext(nullptr);
+  }
+
+  static void transferBeforeImpl(node_base_type &Next, node_base_type &First,
+                                 node_base_type &Last) {
+    if (&Next == &Last || &First == &Last)
+      return;
+
+    // Position cannot be contained in the range to be transferred.
+    assert(&Next != &First &&
+           // Check for the most common mistake.
+           "Insertion point can't be one of the transferred nodes");
+
+    node_base_type &Final = *Last.getPrev();
+
+    // Detach from old list/position.
+    First.getPrev()->setNext(&Last);
+    Last.setPrev(First.getPrev());
+
+    // Splice [First, Final] into its new list/position.
+    node_base_type &Prev = *Next.getPrev();
+    Final.setNext(&Next);
+    First.setPrev(&Prev);
+    Prev.setNext(&First);
+    Next.setPrev(&Final);
+  }
+
+  template <class T> static void insertBefore(T &Next, T &N) {
+    insertBeforeImpl(Next, N);
+  }
+
+  template <class T> static void remove(T &N) { removeImpl(N); }
+  template <class T> static void removeRange(T &First, T &Last) {
+    removeRangeImpl(First, Last);
+  }
+
+  template <class T> static void transferBefore(T &Next, T &First, T &Last) {
+    transferBeforeImpl(Next, First, Last);
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_ILIST_BASE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/ilist_iterator.h b/binaryen/third_party/llvm-project/include/llvm/ADT/ilist_iterator.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/ilist_iterator.h
@@ -0,0 +1,198 @@
+//===- llvm/ADT/ilist_iterator.h - Intrusive List Iterator ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_ILIST_ITERATOR_H
+#define LLVM_ADT_ILIST_ITERATOR_H
+
+#include "llvm/ADT/ilist_node.h"
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <type_traits>
+
+namespace llvm {
+
+namespace ilist_detail {
+
+/// Find const-correct node types.
+template <class OptionsT, bool IsConst> struct IteratorTraits;
+template <class OptionsT> struct IteratorTraits<OptionsT, false> {
+  using value_type = typename OptionsT::value_type;
+  using pointer = typename OptionsT::pointer;
+  using reference = typename OptionsT::reference;
+  using node_pointer = ilist_node_impl<OptionsT> *;
+  using node_reference = ilist_node_impl<OptionsT> &;
+};
+template <class OptionsT> struct IteratorTraits<OptionsT, true> {
+  using value_type = const typename OptionsT::value_type;
+  using pointer = typename OptionsT::const_pointer;
+  using reference = typename OptionsT::const_reference;
+  using node_pointer = const ilist_node_impl<OptionsT> *;
+  using node_reference = const ilist_node_impl<OptionsT> &;
+};
+
+template <bool IsReverse> struct IteratorHelper;
+template <> struct IteratorHelper<false> : ilist_detail::NodeAccess {
+  using Access = ilist_detail::NodeAccess;
+
+  template <class T> static void increment(T *&I) { I = Access::getNext(*I); }
+  template <class T> static void decrement(T *&I) { I = Access::getPrev(*I); }
+};
+template <> struct IteratorHelper<true> : ilist_detail::NodeAccess {
+  using Access = ilist_detail::NodeAccess;
+
+  template <class T> static void increment(T *&I) { I = Access::getPrev(*I); }
+  template <class T> static void decrement(T *&I) { I = Access::getNext(*I); }
+};
+
+} // end namespace ilist_detail
+
+/// Iterator for intrusive lists  based on ilist_node.
+template <class OptionsT, bool IsReverse, bool IsConst>
+class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> {
+  friend ilist_iterator<OptionsT, IsReverse, !IsConst>;
+  friend ilist_iterator<OptionsT, !IsReverse, IsConst>;
+  friend ilist_iterator<OptionsT, !IsReverse, !IsConst>;
+
+  using Traits = ilist_detail::IteratorTraits<OptionsT, IsConst>;
+  using Access = ilist_detail::SpecificNodeAccess<OptionsT>;
+
+public:
+  using value_type = typename Traits::value_type;
+  using pointer = typename Traits::pointer;
+  using reference = typename Traits::reference;
+  using difference_type = ptrdiff_t;
+  using iterator_category = std::bidirectional_iterator_tag;
+  using const_pointer = typename OptionsT::const_pointer;
+  using const_reference = typename OptionsT::const_reference;
+
+private:
+  using node_pointer = typename Traits::node_pointer;
+  using node_reference = typename Traits::node_reference;
+
+  node_pointer NodePtr = nullptr;
+
+public:
+  /// Create from an ilist_node.
+  explicit ilist_iterator(node_reference N) : NodePtr(&N) {}
+
+  explicit ilist_iterator(pointer NP) : NodePtr(Access::getNodePtr(NP)) {}
+  explicit ilist_iterator(reference NR) : NodePtr(Access::getNodePtr(&NR)) {}
+  ilist_iterator() = default;
+
+  // This is templated so that we can allow constructing a const iterator from
+  // a nonconst iterator...
+  template <bool RHSIsConst>
+  ilist_iterator(
+      const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS,
+      typename std::enable_if<IsConst || !RHSIsConst, void *>::type = nullptr)
+      : NodePtr(RHS.NodePtr) {}
+
+  // This is templated so that we can allow assigning to a const iterator from
+  // a nonconst iterator...
+  template <bool RHSIsConst>
+  typename std::enable_if<IsConst || !RHSIsConst, ilist_iterator &>::type
+  operator=(const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS) {
+    NodePtr = RHS.NodePtr;
+    return *this;
+  }
+
+  /// Explicit conversion between forward/reverse iterators.
+  ///
+  /// Translate between forward and reverse iterators without changing range
+  /// boundaries.  The resulting iterator will dereference (and have a handle)
+  /// to the previous node, which is somewhat unexpected; but converting the
+  /// two endpoints in a range will give the same range in reverse.
+  ///
+  /// This matches std::reverse_iterator conversions.
+  explicit ilist_iterator(
+      const ilist_iterator<OptionsT, !IsReverse, IsConst> &RHS)
+      : ilist_iterator(++RHS.getReverse()) {}
+
+  /// Get a reverse iterator to the same node.
+  ///
+  /// Gives a reverse iterator that will dereference (and have a handle) to the
+  /// same node.  Converting the endpoint iterators in a range will give a
+  /// different range; for range operations, use the explicit conversions.
+  ilist_iterator<OptionsT, !IsReverse, IsConst> getReverse() const {
+    if (NodePtr)
+      return ilist_iterator<OptionsT, !IsReverse, IsConst>(*NodePtr);
+    return ilist_iterator<OptionsT, !IsReverse, IsConst>();
+  }
+
+  /// Const-cast.
+  ilist_iterator<OptionsT, IsReverse, false> getNonConst() const {
+    if (NodePtr)
+      return ilist_iterator<OptionsT, IsReverse, false>(
+          const_cast<typename ilist_iterator<OptionsT, IsReverse,
+                                             false>::node_reference>(*NodePtr));
+    return ilist_iterator<OptionsT, IsReverse, false>();
+  }
+
+  // Accessors...
+  reference operator*() const {
+    assert(!NodePtr->isKnownSentinel());
+    return *Access::getValuePtr(NodePtr);
+  }
+  pointer operator->() const { return &operator*(); }
+
+  // Comparison operators
+  friend bool operator==(const ilist_iterator &LHS, const ilist_iterator &RHS) {
+    return LHS.NodePtr == RHS.NodePtr;
+  }
+  friend bool operator!=(const ilist_iterator &LHS, const ilist_iterator &RHS) {
+    return LHS.NodePtr != RHS.NodePtr;
+  }
+
+  // Increment and decrement operators...
+  ilist_iterator &operator--() {
+    NodePtr = IsReverse ? NodePtr->getNext() : NodePtr->getPrev();
+    return *this;
+  }
+  ilist_iterator &operator++() {
+    NodePtr = IsReverse ? NodePtr->getPrev() : NodePtr->getNext();
+    return *this;
+  }
+  ilist_iterator operator--(int) {
+    ilist_iterator tmp = *this;
+    --*this;
+    return tmp;
+  }
+  ilist_iterator operator++(int) {
+    ilist_iterator tmp = *this;
+    ++*this;
+    return tmp;
+  }
+
+  /// Get the underlying ilist_node.
+  node_pointer getNodePtr() const { return static_cast<node_pointer>(NodePtr); }
+
+  /// Check for end.  Only valid if ilist_sentinel_tracking<true>.
+  bool isEnd() const { return NodePtr ? NodePtr->isSentinel() : false; }
+};
+
+template <typename From> struct simplify_type;
+
+/// Allow ilist_iterators to convert into pointers to a node automatically when
+/// used by the dyn_cast, cast, isa mechanisms...
+///
+/// FIXME: remove this, since there is no implicit conversion to NodeTy.
+template <class OptionsT, bool IsConst>
+struct simplify_type<ilist_iterator<OptionsT, false, IsConst>> {
+  using iterator = ilist_iterator<OptionsT, false, IsConst>;
+  using SimpleType = typename iterator::pointer;
+
+  static SimpleType getSimplifiedValue(const iterator &Node) { return &*Node; }
+};
+template <class OptionsT, bool IsConst>
+struct simplify_type<const ilist_iterator<OptionsT, false, IsConst>>
+    : simplify_type<ilist_iterator<OptionsT, false, IsConst>> {};
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_ILIST_ITERATOR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/ilist_node.h b/binaryen/third_party/llvm-project/include/llvm/ADT/ilist_node.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/ilist_node.h
@@ -0,0 +1,305 @@
+//===- llvm/ADT/ilist_node.h - Intrusive Linked List Helper -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ilist_node class template, which is a convenient
+// base class for creating classes that can be used with ilists.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_ILIST_NODE_H
+#define LLVM_ADT_ILIST_NODE_H
+
+#include "llvm/ADT/ilist_node_base.h"
+#include "llvm/ADT/ilist_node_options.h"
+
+namespace llvm {
+
+namespace ilist_detail {
+
+struct NodeAccess;
+
+} // end namespace ilist_detail
+
+template <class OptionsT, bool IsReverse, bool IsConst> class ilist_iterator;
+template <class OptionsT> class ilist_sentinel;
+
+/// Implementation for an ilist node.
+///
+/// Templated on an appropriate \a ilist_detail::node_options, usually computed
+/// by \a ilist_detail::compute_node_options.
+///
+/// This is a wrapper around \a ilist_node_base whose main purpose is to
+/// provide type safety: you can't insert nodes of \a ilist_node_impl into the
+/// wrong \a simple_ilist or \a iplist.
+template <class OptionsT> class ilist_node_impl : OptionsT::node_base_type {
+  using value_type = typename OptionsT::value_type;
+  using node_base_type = typename OptionsT::node_base_type;
+  using list_base_type = typename OptionsT::list_base_type;
+
+  friend typename OptionsT::list_base_type;
+  friend struct ilist_detail::NodeAccess;
+  friend class ilist_sentinel<OptionsT>;
+  friend class ilist_iterator<OptionsT, false, false>;
+  friend class ilist_iterator<OptionsT, false, true>;
+  friend class ilist_iterator<OptionsT, true, false>;
+  friend class ilist_iterator<OptionsT, true, true>;
+
+protected:
+  using self_iterator = ilist_iterator<OptionsT, false, false>;
+  using const_self_iterator = ilist_iterator<OptionsT, false, true>;
+  using reverse_self_iterator = ilist_iterator<OptionsT, true, false>;
+  using const_reverse_self_iterator = ilist_iterator<OptionsT, true, true>;
+
+  ilist_node_impl() = default;
+
+private:
+  ilist_node_impl *getPrev() {
+    return static_cast<ilist_node_impl *>(node_base_type::getPrev());
+  }
+
+  ilist_node_impl *getNext() {
+    return static_cast<ilist_node_impl *>(node_base_type::getNext());
+  }
+
+  const ilist_node_impl *getPrev() const {
+    return static_cast<ilist_node_impl *>(node_base_type::getPrev());
+  }
+
+  const ilist_node_impl *getNext() const {
+    return static_cast<ilist_node_impl *>(node_base_type::getNext());
+  }
+
+  void setPrev(ilist_node_impl *N) { node_base_type::setPrev(N); }
+  void setNext(ilist_node_impl *N) { node_base_type::setNext(N); }
+
+public:
+  self_iterator getIterator() { return self_iterator(*this); }
+  const_self_iterator getIterator() const { return const_self_iterator(*this); }
+
+  reverse_self_iterator getReverseIterator() {
+    return reverse_self_iterator(*this);
+  }
+
+  const_reverse_self_iterator getReverseIterator() const {
+    return const_reverse_self_iterator(*this);
+  }
+
+  // Under-approximation, but always available for assertions.
+  using node_base_type::isKnownSentinel;
+
+  /// Check whether this is the sentinel node.
+  ///
+  /// This requires sentinel tracking to be explicitly enabled.  Use the
+  /// ilist_sentinel_tracking<true> option to get this API.
+  bool isSentinel() const {
+    static_assert(OptionsT::is_sentinel_tracking_explicit,
+                  "Use ilist_sentinel_tracking<true> to enable isSentinel()");
+    return node_base_type::isSentinel();
+  }
+};
+
+/// An intrusive list node.
+///
+/// A base class to enable membership in intrusive lists, including \a
+/// simple_ilist, \a iplist, and \a ilist.  The first template parameter is the
+/// \a value_type for the list.
+///
+/// An ilist node can be configured with compile-time options to change
+/// behaviour and/or add API.
+///
+/// By default, an \a ilist_node knows whether it is the list sentinel (an
+/// instance of \a ilist_sentinel) if and only if
+/// LLVM_ENABLE_ABI_BREAKING_CHECKS.  The function \a isKnownSentinel() always
+/// returns \c false tracking is off.  Sentinel tracking steals a bit from the
+/// "prev" link, which adds a mask operation when decrementing an iterator, but
+/// enables bug-finding assertions in \a ilist_iterator.
+///
+/// To turn sentinel tracking on all the time, pass in the
+/// ilist_sentinel_tracking<true> template parameter.  This also enables the \a
+/// isSentinel() function.  The same option must be passed to the intrusive
+/// list.  (ilist_sentinel_tracking<false> turns sentinel tracking off all the
+/// time.)
+///
+/// A type can inherit from ilist_node multiple times by passing in different
+/// \a ilist_tag options.  This allows a single instance to be inserted into
+/// multiple lists simultaneously, where each list is given the same tag.
+///
+/// \example
+/// struct A {};
+/// struct B {};
+/// struct N : ilist_node<N, ilist_tag<A>>, ilist_node<N, ilist_tag<B>> {};
+///
+/// void foo() {
+///   simple_ilist<N, ilist_tag<A>> ListA;
+///   simple_ilist<N, ilist_tag<B>> ListB;
+///   N N1;
+///   ListA.push_back(N1);
+///   ListB.push_back(N1);
+/// }
+/// \endexample
+///
+/// See \a is_valid_option for steps on adding a new option.
+template <class T, class... Options>
+class ilist_node
+    : public ilist_node_impl<
+          typename ilist_detail::compute_node_options<T, Options...>::type> {
+  static_assert(ilist_detail::check_options<Options...>::value,
+                "Unrecognized node option!");
+};
+
+namespace ilist_detail {
+
+/// An access class for ilist_node private API.
+///
+/// This gives access to the private parts of ilist nodes.  Nodes for an ilist
+/// should friend this class if they inherit privately from ilist_node.
+///
+/// Using this class outside of the ilist implementation is unsupported.
+struct NodeAccess {
+protected:
+  template <class OptionsT>
+  static ilist_node_impl<OptionsT> *getNodePtr(typename OptionsT::pointer N) {
+    return N;
+  }
+
+  template <class OptionsT>
+  static const ilist_node_impl<OptionsT> *
+  getNodePtr(typename OptionsT::const_pointer N) {
+    return N;
+  }
+
+  template <class OptionsT>
+  static typename OptionsT::pointer getValuePtr(ilist_node_impl<OptionsT> *N) {
+    return static_cast<typename OptionsT::pointer>(N);
+  }
+
+  template <class OptionsT>
+  static typename OptionsT::const_pointer
+  getValuePtr(const ilist_node_impl<OptionsT> *N) {
+    return static_cast<typename OptionsT::const_pointer>(N);
+  }
+
+  template <class OptionsT>
+  static ilist_node_impl<OptionsT> *getPrev(ilist_node_impl<OptionsT> &N) {
+    return N.getPrev();
+  }
+
+  template <class OptionsT>
+  static ilist_node_impl<OptionsT> *getNext(ilist_node_impl<OptionsT> &N) {
+    return N.getNext();
+  }
+
+  template <class OptionsT>
+  static const ilist_node_impl<OptionsT> *
+  getPrev(const ilist_node_impl<OptionsT> &N) {
+    return N.getPrev();
+  }
+
+  template <class OptionsT>
+  static const ilist_node_impl<OptionsT> *
+  getNext(const ilist_node_impl<OptionsT> &N) {
+    return N.getNext();
+  }
+};
+
+template <class OptionsT> struct SpecificNodeAccess : NodeAccess {
+protected:
+  using pointer = typename OptionsT::pointer;
+  using const_pointer = typename OptionsT::const_pointer;
+  using node_type = ilist_node_impl<OptionsT>;
+
+  static node_type *getNodePtr(pointer N) {
+    return NodeAccess::getNodePtr<OptionsT>(N);
+  }
+
+  static const node_type *getNodePtr(const_pointer N) {
+    return NodeAccess::getNodePtr<OptionsT>(N);
+  }
+
+  static pointer getValuePtr(node_type *N) {
+    return NodeAccess::getValuePtr<OptionsT>(N);
+  }
+
+  static const_pointer getValuePtr(const node_type *N) {
+    return NodeAccess::getValuePtr<OptionsT>(N);
+  }
+};
+
+} // end namespace ilist_detail
+
+template <class OptionsT>
+class ilist_sentinel : public ilist_node_impl<OptionsT> {
+public:
+  ilist_sentinel() {
+    this->initializeSentinel();
+    reset();
+  }
+
+  void reset() {
+    this->setPrev(this);
+    this->setNext(this);
+  }
+
+  bool empty() const { return this == this->getPrev(); }
+};
+
+/// An ilist node that can access its parent list.
+///
+/// Requires \c NodeTy to have \a getParent() to find the parent node, and the
+/// \c ParentTy to have \a getSublistAccess() to get a reference to the list.
+template <typename NodeTy, typename ParentTy, class... Options>
+class ilist_node_with_parent : public ilist_node<NodeTy, Options...> {
+protected:
+  ilist_node_with_parent() = default;
+
+private:
+  /// Forward to NodeTy::getParent().
+  ///
+  /// Note: do not use the name "getParent()".  We want a compile error
+  /// (instead of recursion) when the subclass fails to implement \a
+  /// getParent().
+  const ParentTy *getNodeParent() const {
+    return static_cast<const NodeTy *>(this)->getParent();
+  }
+
+public:
+  /// @name Adjacent Node Accessors
+  /// @{
+  /// Get the previous node, or \c nullptr for the list head.
+  NodeTy *getPrevNode() {
+    // Should be separated to a reused function, but then we couldn't use auto
+    // (and would need the type of the list).
+    const auto &List =
+        getNodeParent()->*(ParentTy::getSublistAccess((NodeTy *)nullptr));
+    return List.getPrevNode(*static_cast<NodeTy *>(this));
+  }
+
+  /// Get the previous node, or \c nullptr for the list head.
+  const NodeTy *getPrevNode() const {
+    return const_cast<ilist_node_with_parent *>(this)->getPrevNode();
+  }
+
+  /// Get the next node, or \c nullptr for the list tail.
+  NodeTy *getNextNode() {
+    // Should be separated to a reused function, but then we couldn't use auto
+    // (and would need the type of the list).
+    const auto &List =
+        getNodeParent()->*(ParentTy::getSublistAccess((NodeTy *)nullptr));
+    return List.getNextNode(*static_cast<NodeTy *>(this));
+  }
+
+  /// Get the next node, or \c nullptr for the list tail.
+  const NodeTy *getNextNode() const {
+    return const_cast<ilist_node_with_parent *>(this)->getNextNode();
+  }
+  /// @}
+};
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_ILIST_NODE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/ilist_node_base.h b/binaryen/third_party/llvm-project/include/llvm/ADT/ilist_node_base.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/ilist_node_base.h
@@ -0,0 +1,52 @@
+//===- llvm/ADT/ilist_node_base.h - Intrusive List Node Base -----*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_ILIST_NODE_BASE_H
+#define LLVM_ADT_ILIST_NODE_BASE_H
+
+#include "llvm/ADT/PointerIntPair.h"
+
+namespace llvm {
+
+/// Base class for ilist nodes.
+///
+/// Optionally tracks whether this node is the sentinel.
+template <bool EnableSentinelTracking> class ilist_node_base;
+
+template <> class ilist_node_base<false> {
+  ilist_node_base *Prev = nullptr;
+  ilist_node_base *Next = nullptr;
+
+public:
+  void setPrev(ilist_node_base *Prev) { this->Prev = Prev; }
+  void setNext(ilist_node_base *Next) { this->Next = Next; }
+  ilist_node_base *getPrev() const { return Prev; }
+  ilist_node_base *getNext() const { return Next; }
+
+  bool isKnownSentinel() const { return false; }
+  void initializeSentinel() {}
+};
+
+template <> class ilist_node_base<true> {
+  PointerIntPair<ilist_node_base *, 1> PrevAndSentinel;
+  ilist_node_base *Next = nullptr;
+
+public:
+  void setPrev(ilist_node_base *Prev) { PrevAndSentinel.setPointer(Prev); }
+  void setNext(ilist_node_base *Next) { this->Next = Next; }
+  ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); }
+  ilist_node_base *getNext() const { return Next; }
+
+  bool isSentinel() const { return PrevAndSentinel.getInt(); }
+  bool isKnownSentinel() const { return isSentinel(); }
+  void initializeSentinel() { PrevAndSentinel.setInt(true); }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_ILIST_NODE_BASE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/ilist_node_options.h b/binaryen/third_party/llvm-project/include/llvm/ADT/ilist_node_options.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/ilist_node_options.h
@@ -0,0 +1,131 @@
+//===- llvm/ADT/ilist_node_options.h - ilist_node Options -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_ILIST_NODE_OPTIONS_H
+#define LLVM_ADT_ILIST_NODE_OPTIONS_H
+
+#include "llvm/Config/abi-breaking.h"
+
+#include <type_traits>
+
+namespace llvm {
+
+template <bool EnableSentinelTracking> class ilist_node_base;
+template <bool EnableSentinelTracking> class ilist_base;
+
+/// Option to choose whether to track sentinels.
+///
+/// This option affects the ABI for the nodes.  When not specified explicitly,
+/// the ABI depends on LLVM_ENABLE_ABI_BREAKING_CHECKS.  Specify explicitly to
+/// enable \a ilist_node::isSentinel().
+template <bool EnableSentinelTracking> struct ilist_sentinel_tracking {};
+
+/// Option to specify a tag for the node type.
+///
+/// This option allows a single value type to be inserted in multiple lists
+/// simultaneously.  See \a ilist_node for usage examples.
+template <class Tag> struct ilist_tag {};
+
+namespace ilist_detail {
+
+/// Helper trait for recording whether an option is specified explicitly.
+template <bool IsExplicit> struct explicitness {
+  static const bool is_explicit = IsExplicit;
+};
+typedef explicitness<true> is_explicit;
+typedef explicitness<false> is_implicit;
+
+/// Check whether an option is valid.
+///
+/// The steps for adding and enabling a new ilist option include:
+/// \li define the option, ilist_foo<Bar>, above;
+/// \li add new parameters for Bar to \a ilist_detail::node_options;
+/// \li add an extraction meta-function, ilist_detail::extract_foo;
+/// \li call extract_foo from \a ilist_detail::compute_node_options and pass it
+/// into \a ilist_detail::node_options; and
+/// \li specialize \c is_valid_option<ilist_foo<Bar>> to inherit from \c
+/// std::true_type to get static assertions passing in \a simple_ilist and \a
+/// ilist_node.
+template <class Option> struct is_valid_option : std::false_type {};
+
+/// Extract sentinel tracking option.
+///
+/// Look through \p Options for the \a ilist_sentinel_tracking option, with the
+/// default depending on LLVM_ENABLE_ABI_BREAKING_CHECKS.
+template <class... Options> struct extract_sentinel_tracking;
+template <bool EnableSentinelTracking, class... Options>
+struct extract_sentinel_tracking<
+    ilist_sentinel_tracking<EnableSentinelTracking>, Options...>
+    : std::integral_constant<bool, EnableSentinelTracking>, is_explicit {};
+template <class Option1, class... Options>
+struct extract_sentinel_tracking<Option1, Options...>
+    : extract_sentinel_tracking<Options...> {};
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+template <> struct extract_sentinel_tracking<> : std::true_type, is_implicit {};
+#else
+template <>
+struct extract_sentinel_tracking<> : std::false_type, is_implicit {};
+#endif
+template <bool EnableSentinelTracking>
+struct is_valid_option<ilist_sentinel_tracking<EnableSentinelTracking>>
+    : std::true_type {};
+
+/// Extract custom tag option.
+///
+/// Look through \p Options for the \a ilist_tag option, pulling out the
+/// custom tag type, using void as a default.
+template <class... Options> struct extract_tag;
+template <class Tag, class... Options>
+struct extract_tag<ilist_tag<Tag>, Options...> {
+  typedef Tag type;
+};
+template <class Option1, class... Options>
+struct extract_tag<Option1, Options...> : extract_tag<Options...> {};
+template <> struct extract_tag<> { typedef void type; };
+template <class Tag> struct is_valid_option<ilist_tag<Tag>> : std::true_type {};
+
+/// Check whether options are valid.
+///
+/// The conjunction of \a is_valid_option on each individual option.
+template <class... Options> struct check_options;
+template <> struct check_options<> : std::true_type {};
+template <class Option1, class... Options>
+struct check_options<Option1, Options...>
+    : std::integral_constant<bool, is_valid_option<Option1>::value &&
+                                       check_options<Options...>::value> {};
+
+/// Traits for options for \a ilist_node.
+///
+/// This is usually computed via \a compute_node_options.
+template <class T, bool EnableSentinelTracking, bool IsSentinelTrackingExplicit,
+          class TagT>
+struct node_options {
+  typedef T value_type;
+  typedef T *pointer;
+  typedef T &reference;
+  typedef const T *const_pointer;
+  typedef const T &const_reference;
+
+  static const bool enable_sentinel_tracking = EnableSentinelTracking;
+  static const bool is_sentinel_tracking_explicit = IsSentinelTrackingExplicit;
+  typedef TagT tag;
+  typedef ilist_node_base<enable_sentinel_tracking> node_base_type;
+  typedef ilist_base<enable_sentinel_tracking> list_base_type;
+};
+
+template <class T, class... Options> struct compute_node_options {
+  typedef node_options<T, extract_sentinel_tracking<Options...>::value,
+                       extract_sentinel_tracking<Options...>::is_explicit,
+                       typename extract_tag<Options...>::type>
+      type;
+};
+
+} // end namespace ilist_detail
+} // end namespace llvm
+
+#endif // LLVM_ADT_ILIST_NODE_OPTIONS_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/iterator.h b/binaryen/third_party/llvm-project/include/llvm/ADT/iterator.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/iterator.h
@@ -0,0 +1,366 @@
+//===- iterator.h - Utilities for using and defining iterators --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_ITERATOR_H
+#define LLVM_ADT_ITERATOR_H
+
+#include "llvm/ADT/iterator_range.h"
+#include <algorithm>
+#include <cstddef>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+
+namespace llvm {
+
+/// CRTP base class which implements the entire standard iterator facade
+/// in terms of a minimal subset of the interface.
+///
+/// Use this when it is reasonable to implement most of the iterator
+/// functionality in terms of a core subset. If you need special behavior or
+/// there are performance implications for this, you may want to override the
+/// relevant members instead.
+///
+/// Note, one abstraction that this does *not* provide is implementing
+/// subtraction in terms of addition by negating the difference. Negation isn't
+/// always information preserving, and I can see very reasonable iterator
+/// designs where this doesn't work well. It doesn't really force much added
+/// boilerplate anyways.
+///
+/// Another abstraction that this doesn't provide is implementing increment in
+/// terms of addition of one. These aren't equivalent for all iterator
+/// categories, and respecting that adds a lot of complexity for little gain.
+///
+/// Classes wishing to use `iterator_facade_base` should implement the following
+/// methods:
+///
+/// Forward Iterators:
+///   (All of the following methods)
+///   - DerivedT &operator=(const DerivedT &R);
+///   - bool operator==(const DerivedT &R) const;
+///   - const T &operator*() const;
+///   - T &operator*();
+///   - DerivedT &operator++();
+///
+/// Bidirectional Iterators:
+///   (All methods of forward iterators, plus the following)
+///   - DerivedT &operator--();
+///
+/// Random-access Iterators:
+///   (All methods of bidirectional iterators excluding the following)
+///   - DerivedT &operator++();
+///   - DerivedT &operator--();
+///   (and plus the following)
+///   - bool operator<(const DerivedT &RHS) const;
+///   - DifferenceTypeT operator-(const DerivedT &R) const;
+///   - DerivedT &operator+=(DifferenceTypeT N);
+///   - DerivedT &operator-=(DifferenceTypeT N);
+///
+template <typename DerivedT, typename IteratorCategoryT, typename T,
+          typename DifferenceTypeT = std::ptrdiff_t, typename PointerT = T *,
+          typename ReferenceT = T &>
+class iterator_facade_base
+    : public std::iterator<IteratorCategoryT, T, DifferenceTypeT, PointerT,
+                           ReferenceT> {
+protected:
+  enum {
+    IsRandomAccess = std::is_base_of<std::random_access_iterator_tag,
+                                     IteratorCategoryT>::value,
+    IsBidirectional = std::is_base_of<std::bidirectional_iterator_tag,
+                                      IteratorCategoryT>::value,
+  };
+
+  /// A proxy object for computing a reference via indirecting a copy of an
+  /// iterator. This is used in APIs which need to produce a reference via
+  /// indirection but for which the iterator object might be a temporary. The
+  /// proxy preserves the iterator internally and exposes the indirected
+  /// reference via a conversion operator.
+  class ReferenceProxy {
+    friend iterator_facade_base;
+
+    DerivedT I;
+
+    ReferenceProxy(DerivedT I) : I(std::move(I)) {}
+
+  public:
+    operator ReferenceT() const { return *I; }
+  };
+
+public:
+  DerivedT operator+(DifferenceTypeT n) const {
+    static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
+                  "Must pass the derived type to this template!");
+    static_assert(
+        IsRandomAccess,
+        "The '+' operator is only defined for random access iterators.");
+    DerivedT tmp = *static_cast<const DerivedT *>(this);
+    tmp += n;
+    return tmp;
+  }
+  friend DerivedT operator+(DifferenceTypeT n, const DerivedT &i) {
+    static_assert(
+        IsRandomAccess,
+        "The '+' operator is only defined for random access iterators.");
+    return i + n;
+  }
+  DerivedT operator-(DifferenceTypeT n) const {
+    static_assert(
+        IsRandomAccess,
+        "The '-' operator is only defined for random access iterators.");
+    DerivedT tmp = *static_cast<const DerivedT *>(this);
+    tmp -= n;
+    return tmp;
+  }
+
+  DerivedT &operator++() {
+    static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
+                  "Must pass the derived type to this template!");
+    return static_cast<DerivedT *>(this)->operator+=(1);
+  }
+  DerivedT operator++(int) {
+    DerivedT tmp = *static_cast<DerivedT *>(this);
+    ++*static_cast<DerivedT *>(this);
+    return tmp;
+  }
+  DerivedT &operator--() {
+    static_assert(
+        IsBidirectional,
+        "The decrement operator is only defined for bidirectional iterators.");
+    return static_cast<DerivedT *>(this)->operator-=(1);
+  }
+  DerivedT operator--(int) {
+    static_assert(
+        IsBidirectional,
+        "The decrement operator is only defined for bidirectional iterators.");
+    DerivedT tmp = *static_cast<DerivedT *>(this);
+    --*static_cast<DerivedT *>(this);
+    return tmp;
+  }
+
+  bool operator!=(const DerivedT &RHS) const {
+    return !static_cast<const DerivedT *>(this)->operator==(RHS);
+  }
+
+  bool operator>(const DerivedT &RHS) const {
+    static_assert(
+        IsRandomAccess,
+        "Relational operators are only defined for random access iterators.");
+    return !static_cast<const DerivedT *>(this)->operator<(RHS) &&
+           !static_cast<const DerivedT *>(this)->operator==(RHS);
+  }
+  bool operator<=(const DerivedT &RHS) const {
+    static_assert(
+        IsRandomAccess,
+        "Relational operators are only defined for random access iterators.");
+    return !static_cast<const DerivedT *>(this)->operator>(RHS);
+  }
+  bool operator>=(const DerivedT &RHS) const {
+    static_assert(
+        IsRandomAccess,
+        "Relational operators are only defined for random access iterators.");
+    return !static_cast<const DerivedT *>(this)->operator<(RHS);
+  }
+
+  PointerT operator->() { return &static_cast<DerivedT *>(this)->operator*(); }
+  PointerT operator->() const {
+    return &static_cast<const DerivedT *>(this)->operator*();
+  }
+  ReferenceProxy operator[](DifferenceTypeT n) {
+    static_assert(IsRandomAccess,
+                  "Subscripting is only defined for random access iterators.");
+    return ReferenceProxy(static_cast<DerivedT *>(this)->operator+(n));
+  }
+  ReferenceProxy operator[](DifferenceTypeT n) const {
+    static_assert(IsRandomAccess,
+                  "Subscripting is only defined for random access iterators.");
+    return ReferenceProxy(static_cast<const DerivedT *>(this)->operator+(n));
+  }
+};
+
+/// CRTP base class for adapting an iterator to a different type.
+///
+/// This class can be used through CRTP to adapt one iterator into another.
+/// Typically this is done through providing in the derived class a custom \c
+/// operator* implementation. Other methods can be overridden as well.
+template <
+    typename DerivedT, typename WrappedIteratorT,
+    typename IteratorCategoryT =
+        typename std::iterator_traits<WrappedIteratorT>::iterator_category,
+    typename T = typename std::iterator_traits<WrappedIteratorT>::value_type,
+    typename DifferenceTypeT =
+        typename std::iterator_traits<WrappedIteratorT>::difference_type,
+    typename PointerT = typename std::conditional<
+        std::is_same<T, typename std::iterator_traits<
+                            WrappedIteratorT>::value_type>::value,
+        typename std::iterator_traits<WrappedIteratorT>::pointer, T *>::type,
+    typename ReferenceT = typename std::conditional<
+        std::is_same<T, typename std::iterator_traits<
+                            WrappedIteratorT>::value_type>::value,
+        typename std::iterator_traits<WrappedIteratorT>::reference, T &>::type>
+class iterator_adaptor_base
+    : public iterator_facade_base<DerivedT, IteratorCategoryT, T,
+                                  DifferenceTypeT, PointerT, ReferenceT> {
+  using BaseT = typename iterator_adaptor_base::iterator_facade_base;
+
+protected:
+  WrappedIteratorT I;
+
+  iterator_adaptor_base() = default;
+
+  explicit iterator_adaptor_base(WrappedIteratorT u) : I(std::move(u)) {
+    static_assert(std::is_base_of<iterator_adaptor_base, DerivedT>::value,
+                  "Must pass the derived type to this template!");
+  }
+
+  const WrappedIteratorT &wrapped() const { return I; }
+
+public:
+  using difference_type = DifferenceTypeT;
+
+  DerivedT &operator+=(difference_type n) {
+    static_assert(
+        BaseT::IsRandomAccess,
+        "The '+=' operator is only defined for random access iterators.");
+    I += n;
+    return *static_cast<DerivedT *>(this);
+  }
+  DerivedT &operator-=(difference_type n) {
+    static_assert(
+        BaseT::IsRandomAccess,
+        "The '-=' operator is only defined for random access iterators.");
+    I -= n;
+    return *static_cast<DerivedT *>(this);
+  }
+  using BaseT::operator-;
+  difference_type operator-(const DerivedT &RHS) const {
+    static_assert(
+        BaseT::IsRandomAccess,
+        "The '-' operator is only defined for random access iterators.");
+    return I - RHS.I;
+  }
+
+  // We have to explicitly provide ++ and -- rather than letting the facade
+  // forward to += because WrappedIteratorT might not support +=.
+  using BaseT::operator++;
+  DerivedT &operator++() {
+    ++I;
+    return *static_cast<DerivedT *>(this);
+  }
+  using BaseT::operator--;
+  DerivedT &operator--() {
+    static_assert(
+        BaseT::IsBidirectional,
+        "The decrement operator is only defined for bidirectional iterators.");
+    --I;
+    return *static_cast<DerivedT *>(this);
+  }
+
+  bool operator==(const DerivedT &RHS) const { return I == RHS.I; }
+  bool operator<(const DerivedT &RHS) const {
+    static_assert(
+        BaseT::IsRandomAccess,
+        "Relational operators are only defined for random access iterators.");
+    return I < RHS.I;
+  }
+
+  ReferenceT operator*() const { return *I; }
+};
+
+/// An iterator type that allows iterating over the pointees via some
+/// other iterator.
+///
+/// The typical usage of this is to expose a type that iterates over Ts, but
+/// which is implemented with some iterator over T*s:
+///
+/// \code
+///   using iterator = pointee_iterator<SmallVectorImpl<T *>::iterator>;
+/// \endcode
+template <typename WrappedIteratorT,
+          typename T = typename std::remove_reference<
+              decltype(**std::declval<WrappedIteratorT>())>::type>
+struct pointee_iterator
+    : iterator_adaptor_base<
+          pointee_iterator<WrappedIteratorT, T>, WrappedIteratorT,
+          typename std::iterator_traits<WrappedIteratorT>::iterator_category,
+          T> {
+  pointee_iterator() = default;
+  template <typename U>
+  pointee_iterator(U &&u)
+      : pointee_iterator::iterator_adaptor_base(std::forward<U &&>(u)) {}
+
+  T &operator*() const { return **this->I; }
+};
+
+template <typename RangeT, typename WrappedIteratorT =
+                               decltype(std::begin(std::declval<RangeT>()))>
+iterator_range<pointee_iterator<WrappedIteratorT>>
+make_pointee_range(RangeT &&Range) {
+  using PointeeIteratorT = pointee_iterator<WrappedIteratorT>;
+  return make_range(PointeeIteratorT(std::begin(std::forward<RangeT>(Range))),
+                    PointeeIteratorT(std::end(std::forward<RangeT>(Range))));
+}
+
+template <typename WrappedIteratorT,
+          typename T = decltype(&*std::declval<WrappedIteratorT>())>
+class pointer_iterator
+    : public iterator_adaptor_base<
+          pointer_iterator<WrappedIteratorT, T>, WrappedIteratorT,
+          typename std::iterator_traits<WrappedIteratorT>::iterator_category,
+          T> {
+  mutable T Ptr;
+
+public:
+  pointer_iterator() = default;
+
+  explicit pointer_iterator(WrappedIteratorT u)
+      : pointer_iterator::iterator_adaptor_base(std::move(u)) {}
+
+  T &operator*() { return Ptr = &*this->I; }
+  const T &operator*() const { return Ptr = &*this->I; }
+};
+
+template <typename RangeT, typename WrappedIteratorT =
+                               decltype(std::begin(std::declval<RangeT>()))>
+iterator_range<pointer_iterator<WrappedIteratorT>>
+make_pointer_range(RangeT &&Range) {
+  using PointerIteratorT = pointer_iterator<WrappedIteratorT>;
+  return make_range(PointerIteratorT(std::begin(std::forward<RangeT>(Range))),
+                    PointerIteratorT(std::end(std::forward<RangeT>(Range))));
+}
+
+// Wrapper iterator over iterator ItType, adding DataRef to the type of ItType,
+// to create NodeRef = std::pair<InnerTypeOfItType, DataRef>.
+template <typename ItType, typename NodeRef, typename DataRef>
+class WrappedPairNodeDataIterator
+    : public iterator_adaptor_base<
+          WrappedPairNodeDataIterator<ItType, NodeRef, DataRef>, ItType,
+          typename std::iterator_traits<ItType>::iterator_category, NodeRef,
+          std::ptrdiff_t, NodeRef *, NodeRef &> {
+  using BaseT = iterator_adaptor_base<
+      WrappedPairNodeDataIterator, ItType,
+      typename std::iterator_traits<ItType>::iterator_category, NodeRef,
+      std::ptrdiff_t, NodeRef *, NodeRef &>;
+
+  const DataRef DR;
+  mutable NodeRef NR;
+
+public:
+  WrappedPairNodeDataIterator(ItType Begin, const DataRef DR)
+      : BaseT(Begin), DR(DR) {
+    NR.first = DR;
+  }
+
+  NodeRef &operator*() const {
+    NR.second = *this->I;
+    return NR;
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_ITERATOR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/iterator_range.h b/binaryen/third_party/llvm-project/include/llvm/ADT/iterator_range.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/iterator_range.h
@@ -0,0 +1,69 @@
+//===- iterator_range.h - A range adaptor for iterators ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This provides a very simple, boring adaptor for a begin and end iterator
+/// into a range type. This should be used to build range views that work well
+/// with range based for loops and range based constructors.
+///
+/// Note that code here follows more standards-based coding conventions as it
+/// is mirroring proposed interfaces for standardization.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_ITERATOR_RANGE_H
+#define LLVM_ADT_ITERATOR_RANGE_H
+
+#include <iterator>
+#include <utility>
+
+namespace llvm {
+
+/// A range adaptor for a pair of iterators.
+///
+/// This just wraps two iterators into a range-compatible interface. Nothing
+/// fancy at all.
+template <typename IteratorT>
+class iterator_range {
+  IteratorT begin_iterator, end_iterator;
+
+public:
+  //TODO: Add SFINAE to test that the Container's iterators match the range's
+  //      iterators.
+  template <typename Container>
+  iterator_range(Container &&c)
+  //TODO: Consider ADL/non-member begin/end calls.
+      : begin_iterator(c.begin()), end_iterator(c.end()) {}
+  iterator_range(IteratorT begin_iterator, IteratorT end_iterator)
+      : begin_iterator(std::move(begin_iterator)),
+        end_iterator(std::move(end_iterator)) {}
+
+  IteratorT begin() const { return begin_iterator; }
+  IteratorT end() const { return end_iterator; }
+  bool empty() const { return begin_iterator == end_iterator; }
+};
+
+/// Convenience function for iterating over sub-ranges.
+///
+/// This provides a bit of syntactic sugar to make using sub-ranges
+/// in for loops a bit easier. Analogous to std::make_pair().
+template <class T> iterator_range<T> make_range(T x, T y) {
+  return iterator_range<T>(std::move(x), std::move(y));
+}
+
+template <typename T> iterator_range<T> make_range(std::pair<T, T> p) {
+  return iterator_range<T>(std::move(p.first), std::move(p.second));
+}
+
+template <typename T>
+iterator_range<decltype(adl_begin(std::declval<T>()))> drop_begin(T &&t,
+                                                                  int n) {
+  return make_range(std::next(adl_begin(t), n), adl_end(t));
+}
+}
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/ADT/simple_ilist.h b/binaryen/third_party/llvm-project/include/llvm/ADT/simple_ilist.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ADT/simple_ilist.h
@@ -0,0 +1,314 @@
+//===- llvm/ADT/simple_ilist.h - Simple Intrusive List ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_SIMPLE_ILIST_H
+#define LLVM_ADT_SIMPLE_ILIST_H
+
+#include "llvm/ADT/ilist_base.h"
+#include "llvm/ADT/ilist_iterator.h"
+#include "llvm/ADT/ilist_node.h"
+#include "llvm/ADT/ilist_node_options.h"
+#include "llvm/Support/Compiler.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <functional>
+#include <iterator>
+#include <utility>
+
+namespace llvm {
+
+/// A simple intrusive list implementation.
+///
+/// This is a simple intrusive list for a \c T that inherits from \c
+/// ilist_node<T>.  The list never takes ownership of anything inserted in it.
+///
+/// Unlike \a iplist<T> and \a ilist<T>, \a simple_ilist<T> never allocates or
+/// deletes values, and has no callback traits.
+///
+/// The API for adding nodes include \a push_front(), \a push_back(), and \a
+/// insert().  These all take values by reference (not by pointer), except for
+/// the range version of \a insert().
+///
+/// There are three sets of API for discarding nodes from the list: \a
+/// remove(), which takes a reference to the node to remove, \a erase(), which
+/// takes an iterator or iterator range and returns the next one, and \a
+/// clear(), which empties out the container.  All three are constant time
+/// operations.  None of these deletes any nodes; in particular, if there is a
+/// single node in the list, then these have identical semantics:
+/// \li \c L.remove(L.front());
+/// \li \c L.erase(L.begin());
+/// \li \c L.clear();
+///
+/// As a convenience for callers, there are parallel APIs that take a \c
+/// Disposer (such as \c std::default_delete<T>): \a removeAndDispose(), \a
+/// eraseAndDispose(), and \a clearAndDispose().  These have different names
+/// because the extra semantic is otherwise non-obvious.  They are equivalent
+/// to calling \a std::for_each() on the range to be discarded.
+///
+/// The currently available \p Options customize the nodes in the list.  The
+/// same options must be specified in the \a ilist_node instantation for
+/// compatibility (although the order is irrelevant).
+/// \li Use \a ilist_tag to designate which ilist_node for a given \p T this
+/// list should use.  This is useful if a type \p T is part of multiple,
+/// independent lists simultaneously.
+/// \li Use \a ilist_sentinel_tracking to always (or never) track whether a
+/// node is a sentinel.  Specifying \c true enables the \a
+/// ilist_node::isSentinel() API.  Unlike \a ilist_node::isKnownSentinel(),
+/// which is only appropriate for assertions, \a ilist_node::isSentinel() is
+/// appropriate for real logic.
+///
+/// Here are examples of \p Options usage:
+/// \li \c simple_ilist<T> gives the defaults.  \li \c
+/// simple_ilist<T,ilist_sentinel_tracking<true>> enables the \a
+/// ilist_node::isSentinel() API.
+/// \li \c simple_ilist<T,ilist_tag<A>,ilist_sentinel_tracking<false>>
+/// specifies a tag of A and that tracking should be off (even when
+/// LLVM_ENABLE_ABI_BREAKING_CHECKS are enabled).
+/// \li \c simple_ilist<T,ilist_sentinel_tracking<false>,ilist_tag<A>> is
+/// equivalent to the last.
+///
+/// See \a is_valid_option for steps on adding a new option.
+template <typename T, class... Options>
+class simple_ilist
+    : ilist_detail::compute_node_options<T, Options...>::type::list_base_type,
+      ilist_detail::SpecificNodeAccess<
+          typename ilist_detail::compute_node_options<T, Options...>::type> {
+  static_assert(ilist_detail::check_options<Options...>::value,
+                "Unrecognized node option!");
+  using OptionsT =
+      typename ilist_detail::compute_node_options<T, Options...>::type;
+  using list_base_type = typename OptionsT::list_base_type;
+  ilist_sentinel<OptionsT> Sentinel;
+
+public:
+  using value_type = typename OptionsT::value_type;
+  using pointer = typename OptionsT::pointer;
+  using reference = typename OptionsT::reference;
+  using const_pointer = typename OptionsT::const_pointer;
+  using const_reference = typename OptionsT::const_reference;
+  using iterator = ilist_iterator<OptionsT, false, false>;
+  using const_iterator = ilist_iterator<OptionsT, false, true>;
+  using reverse_iterator = ilist_iterator<OptionsT, true, false>;
+  using const_reverse_iterator = ilist_iterator<OptionsT, true, true>;
+  using size_type = size_t;
+  using difference_type = ptrdiff_t;
+
+  simple_ilist() = default;
+  ~simple_ilist() = default;
+
+  // No copy constructors.
+  simple_ilist(const simple_ilist &) = delete;
+  simple_ilist &operator=(const simple_ilist &) = delete;
+
+  // Move constructors.
+  simple_ilist(simple_ilist &&X) { splice(end(), X); }
+  simple_ilist &operator=(simple_ilist &&X) {
+    clear();
+    splice(end(), X);
+    return *this;
+  }
+
+  iterator begin() { return ++iterator(Sentinel); }
+  const_iterator begin() const { return ++const_iterator(Sentinel); }
+  iterator end() { return iterator(Sentinel); }
+  const_iterator end() const { return const_iterator(Sentinel); }
+  reverse_iterator rbegin() { return ++reverse_iterator(Sentinel); }
+  const_reverse_iterator rbegin() const {
+    return ++const_reverse_iterator(Sentinel);
+  }
+  reverse_iterator rend() { return reverse_iterator(Sentinel); }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(Sentinel);
+  }
+
+  /// Check if the list is empty in constant time.
+  LLVM_NODISCARD bool empty() const { return Sentinel.empty(); }
+
+  /// Calculate the size of the list in linear time.
+  LLVM_NODISCARD size_type size() const {
+    return std::distance(begin(), end());
+  }
+
+  reference front() { return *begin(); }
+  const_reference front() const { return *begin(); }
+  reference back() { return *rbegin(); }
+  const_reference back() const { return *rbegin(); }
+
+  /// Insert a node at the front; never copies.
+  void push_front(reference Node) { insert(begin(), Node); }
+
+  /// Insert a node at the back; never copies.
+  void push_back(reference Node) { insert(end(), Node); }
+
+  /// Remove the node at the front; never deletes.
+  void pop_front() { erase(begin()); }
+
+  /// Remove the node at the back; never deletes.
+  void pop_back() { erase(--end()); }
+
+  /// Swap with another list in place using std::swap.
+  void swap(simple_ilist &X) { std::swap(*this, X); }
+
+  /// Insert a node by reference; never copies.
+  iterator insert(iterator I, reference Node) {
+    list_base_type::insertBefore(*I.getNodePtr(), *this->getNodePtr(&Node));
+    return iterator(&Node);
+  }
+
+  /// Insert a range of nodes; never copies.
+  template <class Iterator>
+  void insert(iterator I, Iterator First, Iterator Last) {
+    for (; First != Last; ++First)
+      insert(I, *First);
+  }
+
+  /// Clone another list.
+  template <class Cloner, class Disposer>
+  void cloneFrom(const simple_ilist &L2, Cloner clone, Disposer dispose) {
+    clearAndDispose(dispose);
+    for (const_reference V : L2)
+      push_back(*clone(V));
+  }
+
+  /// Remove a node by reference; never deletes.
+  ///
+  /// \see \a erase() for removing by iterator.
+  /// \see \a removeAndDispose() if the node should be deleted.
+  void remove(reference N) { list_base_type::remove(*this->getNodePtr(&N)); }
+
+  /// Remove a node by reference and dispose of it.
+  template <class Disposer>
+  void removeAndDispose(reference N, Disposer dispose) {
+    remove(N);
+    dispose(&N);
+  }
+
+  /// Remove a node by iterator; never deletes.
+  ///
+  /// \see \a remove() for removing by reference.
+  /// \see \a eraseAndDispose() it the node should be deleted.
+  iterator erase(iterator I) {
+    assert(I != end() && "Cannot remove end of list!");
+    remove(*I++);
+    return I;
+  }
+
+  /// Remove a range of nodes; never deletes.
+  ///
+  /// \see \a eraseAndDispose() if the nodes should be deleted.
+  iterator erase(iterator First, iterator Last) {
+    list_base_type::removeRange(*First.getNodePtr(), *Last.getNodePtr());
+    return Last;
+  }
+
+  /// Remove a node by iterator and dispose of it.
+  template <class Disposer>
+  iterator eraseAndDispose(iterator I, Disposer dispose) {
+    auto Next = std::next(I);
+    erase(I);
+    dispose(&*I);
+    return Next;
+  }
+
+  /// Remove a range of nodes and dispose of them.
+  template <class Disposer>
+  iterator eraseAndDispose(iterator First, iterator Last, Disposer dispose) {
+    while (First != Last)
+      First = eraseAndDispose(First, dispose);
+    return Last;
+  }
+
+  /// Clear the list; never deletes.
+  ///
+  /// \see \a clearAndDispose() if the nodes should be deleted.
+  void clear() { Sentinel.reset(); }
+
+  /// Clear the list and dispose of the nodes.
+  template <class Disposer> void clearAndDispose(Disposer dispose) {
+    eraseAndDispose(begin(), end(), dispose);
+  }
+
+  /// Splice in another list.
+  void splice(iterator I, simple_ilist &L2) {
+    splice(I, L2, L2.begin(), L2.end());
+  }
+
+  /// Splice in a node from another list.
+  void splice(iterator I, simple_ilist &L2, iterator Node) {
+    splice(I, L2, Node, std::next(Node));
+  }
+
+  /// Splice in a range of nodes from another list.
+  void splice(iterator I, simple_ilist &, iterator First, iterator Last) {
+    list_base_type::transferBefore(*I.getNodePtr(), *First.getNodePtr(),
+                                   *Last.getNodePtr());
+  }
+
+  /// Merge in another list.
+  ///
+  /// \pre \c this and \p RHS are sorted.
+  ///@{
+  void merge(simple_ilist &RHS) { merge(RHS, std::less<T>()); }
+  template <class Compare> void merge(simple_ilist &RHS, Compare comp);
+  ///@}
+
+  /// Sort the list.
+  ///@{
+  void sort() { sort(std::less<T>()); }
+  template <class Compare> void sort(Compare comp);
+  ///@}
+};
+
+template <class T, class... Options>
+template <class Compare>
+void simple_ilist<T, Options...>::merge(simple_ilist &RHS, Compare comp) {
+  if (this == &RHS || RHS.empty())
+    return;
+  iterator LI = begin(), LE = end();
+  iterator RI = RHS.begin(), RE = RHS.end();
+  while (LI != LE) {
+    if (comp(*RI, *LI)) {
+      // Transfer a run of at least size 1 from RHS to LHS.
+      iterator RunStart = RI++;
+      RI = std::find_if(RI, RE, [&](reference RV) { return !comp(RV, *LI); });
+      splice(LI, RHS, RunStart, RI);
+      if (RI == RE)
+        return;
+    }
+    ++LI;
+  }
+  // Transfer the remaining RHS nodes once LHS is finished.
+  splice(LE, RHS, RI, RE);
+}
+
+template <class T, class... Options>
+template <class Compare>
+void simple_ilist<T, Options...>::sort(Compare comp) {
+  // Vacuously sorted.
+  if (empty() || std::next(begin()) == end())
+    return;
+
+  // Split the list in the middle.
+  iterator Center = begin(), End = begin();
+  while (End != end() && ++End != end()) {
+    ++Center;
+    ++End;
+  }
+  simple_ilist RHS;
+  RHS.splice(RHS.end(), *this, Center, end());
+
+  // Sort the sublists and merge back together.
+  sort(comp);
+  RHS.sort(comp);
+  merge(RHS, comp);
+}
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_SIMPLE_ILIST_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/COFF.h b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/COFF.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/COFF.h
@@ -0,0 +1,729 @@
+//===-- llvm/BinaryFormat/COFF.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains an definitions used in Windows COFF Files.
+//
+// Structures and enums defined within this file where created using
+// information from Microsoft's publicly available PE/COFF format document:
+//
+// Microsoft Portable Executable and Common Object File Format Specification
+// Revision 8.1 - February 15, 2008
+//
+// As of 5/2/2010, hosted by Microsoft at:
+// http://www.microsoft.com/whdc/system/platform/firmware/pecoff.mspx
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BINARYFORMAT_COFF_H
+#define LLVM_BINARYFORMAT_COFF_H
+
+#include "llvm/Support/DataTypes.h"
+#include <cassert>
+#include <cstring>
+
+namespace llvm {
+namespace COFF {
+
+// The maximum number of sections that a COFF object can have (inclusive).
+const int32_t MaxNumberOfSections16 = 65279;
+
+// The PE signature bytes that follows the DOS stub header.
+static const char PEMagic[] = {'P', 'E', '\0', '\0'};
+
+static const char BigObjMagic[] = {
+    '\xc7', '\xa1', '\xba', '\xd1', '\xee', '\xba', '\xa9', '\x4b',
+    '\xaf', '\x20', '\xfa', '\xf6', '\x6a', '\xa4', '\xdc', '\xb8',
+};
+
+static const char ClGlObjMagic[] = {
+    '\x38', '\xfe', '\xb3', '\x0c', '\xa5', '\xd9', '\xab', '\x4d',
+    '\xac', '\x9b', '\xd6', '\xb6', '\x22', '\x26', '\x53', '\xc2',
+};
+
+// The signature bytes that start a .res file.
+static const char WinResMagic[] = {
+    '\x00', '\x00', '\x00', '\x00', '\x20', '\x00', '\x00', '\x00',
+    '\xff', '\xff', '\x00', '\x00', '\xff', '\xff', '\x00', '\x00',
+};
+
+// Sizes in bytes of various things in the COFF format.
+enum {
+  Header16Size = 20,
+  Header32Size = 56,
+  NameSize = 8,
+  Symbol16Size = 18,
+  Symbol32Size = 20,
+  SectionSize = 40,
+  RelocationSize = 10
+};
+
+struct header {
+  uint16_t Machine;
+  int32_t NumberOfSections;
+  uint32_t TimeDateStamp;
+  uint32_t PointerToSymbolTable;
+  uint32_t NumberOfSymbols;
+  uint16_t SizeOfOptionalHeader;
+  uint16_t Characteristics;
+};
+
+struct BigObjHeader {
+  enum : uint16_t { MinBigObjectVersion = 2 };
+
+  uint16_t Sig1; ///< Must be IMAGE_FILE_MACHINE_UNKNOWN (0).
+  uint16_t Sig2; ///< Must be 0xFFFF.
+  uint16_t Version;
+  uint16_t Machine;
+  uint32_t TimeDateStamp;
+  uint8_t UUID[16];
+  uint32_t unused1;
+  uint32_t unused2;
+  uint32_t unused3;
+  uint32_t unused4;
+  uint32_t NumberOfSections;
+  uint32_t PointerToSymbolTable;
+  uint32_t NumberOfSymbols;
+};
+
+enum MachineTypes : unsigned {
+  MT_Invalid = 0xffff,
+
+  IMAGE_FILE_MACHINE_UNKNOWN = 0x0,
+  IMAGE_FILE_MACHINE_AM33 = 0x1D3,
+  IMAGE_FILE_MACHINE_AMD64 = 0x8664,
+  IMAGE_FILE_MACHINE_ARM = 0x1C0,
+  IMAGE_FILE_MACHINE_ARMNT = 0x1C4,
+  IMAGE_FILE_MACHINE_ARM64 = 0xAA64,
+  IMAGE_FILE_MACHINE_EBC = 0xEBC,
+  IMAGE_FILE_MACHINE_I386 = 0x14C,
+  IMAGE_FILE_MACHINE_IA64 = 0x200,
+  IMAGE_FILE_MACHINE_M32R = 0x9041,
+  IMAGE_FILE_MACHINE_MIPS16 = 0x266,
+  IMAGE_FILE_MACHINE_MIPSFPU = 0x366,
+  IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466,
+  IMAGE_FILE_MACHINE_POWERPC = 0x1F0,
+  IMAGE_FILE_MACHINE_POWERPCFP = 0x1F1,
+  IMAGE_FILE_MACHINE_R4000 = 0x166,
+  IMAGE_FILE_MACHINE_RISCV32 = 0x5032,
+  IMAGE_FILE_MACHINE_RISCV64 = 0x5064,
+  IMAGE_FILE_MACHINE_RISCV128 = 0x5128,
+  IMAGE_FILE_MACHINE_SH3 = 0x1A2,
+  IMAGE_FILE_MACHINE_SH3DSP = 0x1A3,
+  IMAGE_FILE_MACHINE_SH4 = 0x1A6,
+  IMAGE_FILE_MACHINE_SH5 = 0x1A8,
+  IMAGE_FILE_MACHINE_THUMB = 0x1C2,
+  IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169
+};
+
+enum Characteristics : unsigned {
+  C_Invalid = 0,
+
+  /// The file does not contain base relocations and must be loaded at its
+  /// preferred base. If this cannot be done, the loader will error.
+  IMAGE_FILE_RELOCS_STRIPPED = 0x0001,
+  /// The file is valid and can be run.
+  IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002,
+  /// COFF line numbers have been stripped. This is deprecated and should be
+  /// 0.
+  IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004,
+  /// COFF symbol table entries for local symbols have been removed. This is
+  /// deprecated and should be 0.
+  IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008,
+  /// Aggressively trim working set. This is deprecated and must be 0.
+  IMAGE_FILE_AGGRESSIVE_WS_TRIM = 0x0010,
+  /// Image can handle > 2GiB addresses.
+  IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020,
+  /// Little endian: the LSB precedes the MSB in memory. This is deprecated
+  /// and should be 0.
+  IMAGE_FILE_BYTES_REVERSED_LO = 0x0080,
+  /// Machine is based on a 32bit word architecture.
+  IMAGE_FILE_32BIT_MACHINE = 0x0100,
+  /// Debugging info has been removed.
+  IMAGE_FILE_DEBUG_STRIPPED = 0x0200,
+  /// If the image is on removable media, fully load it and copy it to swap.
+  IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400,
+  /// If the image is on network media, fully load it and copy it to swap.
+  IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800,
+  /// The image file is a system file, not a user program.
+  IMAGE_FILE_SYSTEM = 0x1000,
+  /// The image file is a DLL.
+  IMAGE_FILE_DLL = 0x2000,
+  /// This file should only be run on a uniprocessor machine.
+  IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000,
+  /// Big endian: the MSB precedes the LSB in memory. This is deprecated
+  /// and should be 0.
+  IMAGE_FILE_BYTES_REVERSED_HI = 0x8000
+};
+
+enum ResourceTypeID : unsigned {
+  RID_Cursor = 1,
+  RID_Bitmap = 2,
+  RID_Icon = 3,
+  RID_Menu = 4,
+  RID_Dialog = 5,
+  RID_String = 6,
+  RID_FontDir = 7,
+  RID_Font = 8,
+  RID_Accelerator = 9,
+  RID_RCData = 10,
+  RID_MessageTable = 11,
+  RID_Group_Cursor = 12,
+  RID_Group_Icon = 14,
+  RID_Version = 16,
+  RID_DLGInclude = 17,
+  RID_PlugPlay = 19,
+  RID_VXD = 20,
+  RID_AniCursor = 21,
+  RID_AniIcon = 22,
+  RID_HTML = 23,
+  RID_Manifest = 24,
+};
+
+struct symbol {
+  char Name[NameSize];
+  uint32_t Value;
+  int32_t SectionNumber;
+  uint16_t Type;
+  uint8_t StorageClass;
+  uint8_t NumberOfAuxSymbols;
+};
+
+enum SymbolSectionNumber : int32_t {
+  IMAGE_SYM_DEBUG = -2,
+  IMAGE_SYM_ABSOLUTE = -1,
+  IMAGE_SYM_UNDEFINED = 0
+};
+
+/// Storage class tells where and what the symbol represents
+enum SymbolStorageClass {
+  SSC_Invalid = 0xff,
+
+  IMAGE_SYM_CLASS_END_OF_FUNCTION = -1,  ///< Physical end of function
+  IMAGE_SYM_CLASS_NULL = 0,              ///< No symbol
+  IMAGE_SYM_CLASS_AUTOMATIC = 1,         ///< Stack variable
+  IMAGE_SYM_CLASS_EXTERNAL = 2,          ///< External symbol
+  IMAGE_SYM_CLASS_STATIC = 3,            ///< Static
+  IMAGE_SYM_CLASS_REGISTER = 4,          ///< Register variable
+  IMAGE_SYM_CLASS_EXTERNAL_DEF = 5,      ///< External definition
+  IMAGE_SYM_CLASS_LABEL = 6,             ///< Label
+  IMAGE_SYM_CLASS_UNDEFINED_LABEL = 7,   ///< Undefined label
+  IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 8,  ///< Member of structure
+  IMAGE_SYM_CLASS_ARGUMENT = 9,          ///< Function argument
+  IMAGE_SYM_CLASS_STRUCT_TAG = 10,       ///< Structure tag
+  IMAGE_SYM_CLASS_MEMBER_OF_UNION = 11,  ///< Member of union
+  IMAGE_SYM_CLASS_UNION_TAG = 12,        ///< Union tag
+  IMAGE_SYM_CLASS_TYPE_DEFINITION = 13,  ///< Type definition
+  IMAGE_SYM_CLASS_UNDEFINED_STATIC = 14, ///< Undefined static
+  IMAGE_SYM_CLASS_ENUM_TAG = 15,         ///< Enumeration tag
+  IMAGE_SYM_CLASS_MEMBER_OF_ENUM = 16,   ///< Member of enumeration
+  IMAGE_SYM_CLASS_REGISTER_PARAM = 17,   ///< Register parameter
+  IMAGE_SYM_CLASS_BIT_FIELD = 18,        ///< Bit field
+  /// ".bb" or ".eb" - beginning or end of block
+  IMAGE_SYM_CLASS_BLOCK = 100,
+  /// ".bf" or ".ef" - beginning or end of function
+  IMAGE_SYM_CLASS_FUNCTION = 101,
+  IMAGE_SYM_CLASS_END_OF_STRUCT = 102, ///< End of structure
+  IMAGE_SYM_CLASS_FILE = 103,          ///< File name
+  /// Line number, reformatted as symbol
+  IMAGE_SYM_CLASS_SECTION = 104,
+  IMAGE_SYM_CLASS_WEAK_EXTERNAL = 105, ///< Duplicate tag
+  /// External symbol in dmert public lib
+  IMAGE_SYM_CLASS_CLR_TOKEN = 107
+};
+
+enum SymbolBaseType : unsigned {
+  IMAGE_SYM_TYPE_NULL = 0,   ///< No type information or unknown base type.
+  IMAGE_SYM_TYPE_VOID = 1,   ///< Used with void pointers and functions.
+  IMAGE_SYM_TYPE_CHAR = 2,   ///< A character (signed byte).
+  IMAGE_SYM_TYPE_SHORT = 3,  ///< A 2-byte signed integer.
+  IMAGE_SYM_TYPE_INT = 4,    ///< A natural integer type on the target.
+  IMAGE_SYM_TYPE_LONG = 5,   ///< A 4-byte signed integer.
+  IMAGE_SYM_TYPE_FLOAT = 6,  ///< A 4-byte floating-point number.
+  IMAGE_SYM_TYPE_DOUBLE = 7, ///< An 8-byte floating-point number.
+  IMAGE_SYM_TYPE_STRUCT = 8, ///< A structure.
+  IMAGE_SYM_TYPE_UNION = 9,  ///< An union.
+  IMAGE_SYM_TYPE_ENUM = 10,  ///< An enumerated type.
+  IMAGE_SYM_TYPE_MOE = 11,   ///< A member of enumeration (a specific value).
+  IMAGE_SYM_TYPE_BYTE = 12,  ///< A byte; unsigned 1-byte integer.
+  IMAGE_SYM_TYPE_WORD = 13,  ///< A word; unsigned 2-byte integer.
+  IMAGE_SYM_TYPE_UINT = 14,  ///< An unsigned integer of natural size.
+  IMAGE_SYM_TYPE_DWORD = 15  ///< An unsigned 4-byte integer.
+};
+
+enum SymbolComplexType : unsigned {
+  IMAGE_SYM_DTYPE_NULL = 0,     ///< No complex type; simple scalar variable.
+  IMAGE_SYM_DTYPE_POINTER = 1,  ///< A pointer to base type.
+  IMAGE_SYM_DTYPE_FUNCTION = 2, ///< A function that returns a base type.
+  IMAGE_SYM_DTYPE_ARRAY = 3,    ///< An array of base type.
+
+  /// Type is formed as (base + (derived << SCT_COMPLEX_TYPE_SHIFT))
+  SCT_COMPLEX_TYPE_SHIFT = 4
+};
+
+enum AuxSymbolType { IMAGE_AUX_SYMBOL_TYPE_TOKEN_DEF = 1 };
+
+struct section {
+  char Name[NameSize];
+  uint32_t VirtualSize;
+  uint32_t VirtualAddress;
+  uint32_t SizeOfRawData;
+  uint32_t PointerToRawData;
+  uint32_t PointerToRelocations;
+  uint32_t PointerToLineNumbers;
+  uint16_t NumberOfRelocations;
+  uint16_t NumberOfLineNumbers;
+  uint32_t Characteristics;
+};
+
+enum SectionCharacteristics : uint32_t {
+  SC_Invalid = 0xffffffff,
+
+  IMAGE_SCN_TYPE_NOLOAD = 0x00000002,
+  IMAGE_SCN_TYPE_NO_PAD = 0x00000008,
+  IMAGE_SCN_CNT_CODE = 0x00000020,
+  IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040,
+  IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080,
+  IMAGE_SCN_LNK_OTHER = 0x00000100,
+  IMAGE_SCN_LNK_INFO = 0x00000200,
+  IMAGE_SCN_LNK_REMOVE = 0x00000800,
+  IMAGE_SCN_LNK_COMDAT = 0x00001000,
+  IMAGE_SCN_GPREL = 0x00008000,
+  IMAGE_SCN_MEM_PURGEABLE = 0x00020000,
+  IMAGE_SCN_MEM_16BIT = 0x00020000,
+  IMAGE_SCN_MEM_LOCKED = 0x00040000,
+  IMAGE_SCN_MEM_PRELOAD = 0x00080000,
+  IMAGE_SCN_ALIGN_1BYTES = 0x00100000,
+  IMAGE_SCN_ALIGN_2BYTES = 0x00200000,
+  IMAGE_SCN_ALIGN_4BYTES = 0x00300000,
+  IMAGE_SCN_ALIGN_8BYTES = 0x00400000,
+  IMAGE_SCN_ALIGN_16BYTES = 0x00500000,
+  IMAGE_SCN_ALIGN_32BYTES = 0x00600000,
+  IMAGE_SCN_ALIGN_64BYTES = 0x00700000,
+  IMAGE_SCN_ALIGN_128BYTES = 0x00800000,
+  IMAGE_SCN_ALIGN_256BYTES = 0x00900000,
+  IMAGE_SCN_ALIGN_512BYTES = 0x00A00000,
+  IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000,
+  IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000,
+  IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000,
+  IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000,
+  IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000,
+  IMAGE_SCN_MEM_DISCARDABLE = 0x02000000,
+  IMAGE_SCN_MEM_NOT_CACHED = 0x04000000,
+  IMAGE_SCN_MEM_NOT_PAGED = 0x08000000,
+  IMAGE_SCN_MEM_SHARED = 0x10000000,
+  IMAGE_SCN_MEM_EXECUTE = 0x20000000,
+  IMAGE_SCN_MEM_READ = 0x40000000,
+  IMAGE_SCN_MEM_WRITE = 0x80000000
+};
+
+struct relocation {
+  uint32_t VirtualAddress;
+  uint32_t SymbolTableIndex;
+  uint16_t Type;
+};
+
+enum RelocationTypeI386 : unsigned {
+  IMAGE_REL_I386_ABSOLUTE = 0x0000,
+  IMAGE_REL_I386_DIR16 = 0x0001,
+  IMAGE_REL_I386_REL16 = 0x0002,
+  IMAGE_REL_I386_DIR32 = 0x0006,
+  IMAGE_REL_I386_DIR32NB = 0x0007,
+  IMAGE_REL_I386_SEG12 = 0x0009,
+  IMAGE_REL_I386_SECTION = 0x000A,
+  IMAGE_REL_I386_SECREL = 0x000B,
+  IMAGE_REL_I386_TOKEN = 0x000C,
+  IMAGE_REL_I386_SECREL7 = 0x000D,
+  IMAGE_REL_I386_REL32 = 0x0014
+};
+
+enum RelocationTypeAMD64 : unsigned {
+  IMAGE_REL_AMD64_ABSOLUTE = 0x0000,
+  IMAGE_REL_AMD64_ADDR64 = 0x0001,
+  IMAGE_REL_AMD64_ADDR32 = 0x0002,
+  IMAGE_REL_AMD64_ADDR32NB = 0x0003,
+  IMAGE_REL_AMD64_REL32 = 0x0004,
+  IMAGE_REL_AMD64_REL32_1 = 0x0005,
+  IMAGE_REL_AMD64_REL32_2 = 0x0006,
+  IMAGE_REL_AMD64_REL32_3 = 0x0007,
+  IMAGE_REL_AMD64_REL32_4 = 0x0008,
+  IMAGE_REL_AMD64_REL32_5 = 0x0009,
+  IMAGE_REL_AMD64_SECTION = 0x000A,
+  IMAGE_REL_AMD64_SECREL = 0x000B,
+  IMAGE_REL_AMD64_SECREL7 = 0x000C,
+  IMAGE_REL_AMD64_TOKEN = 0x000D,
+  IMAGE_REL_AMD64_SREL32 = 0x000E,
+  IMAGE_REL_AMD64_PAIR = 0x000F,
+  IMAGE_REL_AMD64_SSPAN32 = 0x0010
+};
+
+enum RelocationTypesARM : unsigned {
+  IMAGE_REL_ARM_ABSOLUTE = 0x0000,
+  IMAGE_REL_ARM_ADDR32 = 0x0001,
+  IMAGE_REL_ARM_ADDR32NB = 0x0002,
+  IMAGE_REL_ARM_BRANCH24 = 0x0003,
+  IMAGE_REL_ARM_BRANCH11 = 0x0004,
+  IMAGE_REL_ARM_TOKEN = 0x0005,
+  IMAGE_REL_ARM_BLX24 = 0x0008,
+  IMAGE_REL_ARM_BLX11 = 0x0009,
+  IMAGE_REL_ARM_REL32 = 0x000A,
+  IMAGE_REL_ARM_SECTION = 0x000E,
+  IMAGE_REL_ARM_SECREL = 0x000F,
+  IMAGE_REL_ARM_MOV32A = 0x0010,
+  IMAGE_REL_ARM_MOV32T = 0x0011,
+  IMAGE_REL_ARM_BRANCH20T = 0x0012,
+  IMAGE_REL_ARM_BRANCH24T = 0x0014,
+  IMAGE_REL_ARM_BLX23T = 0x0015,
+  IMAGE_REL_ARM_PAIR = 0x0016,
+};
+
+enum RelocationTypesARM64 : unsigned {
+  IMAGE_REL_ARM64_ABSOLUTE = 0x0000,
+  IMAGE_REL_ARM64_ADDR32 = 0x0001,
+  IMAGE_REL_ARM64_ADDR32NB = 0x0002,
+  IMAGE_REL_ARM64_BRANCH26 = 0x0003,
+  IMAGE_REL_ARM64_PAGEBASE_REL21 = 0x0004,
+  IMAGE_REL_ARM64_REL21 = 0x0005,
+  IMAGE_REL_ARM64_PAGEOFFSET_12A = 0x0006,
+  IMAGE_REL_ARM64_PAGEOFFSET_12L = 0x0007,
+  IMAGE_REL_ARM64_SECREL = 0x0008,
+  IMAGE_REL_ARM64_SECREL_LOW12A = 0x0009,
+  IMAGE_REL_ARM64_SECREL_HIGH12A = 0x000A,
+  IMAGE_REL_ARM64_SECREL_LOW12L = 0x000B,
+  IMAGE_REL_ARM64_TOKEN = 0x000C,
+  IMAGE_REL_ARM64_SECTION = 0x000D,
+  IMAGE_REL_ARM64_ADDR64 = 0x000E,
+  IMAGE_REL_ARM64_BRANCH19 = 0x000F,
+  IMAGE_REL_ARM64_BRANCH14 = 0x0010,
+  IMAGE_REL_ARM64_REL32 = 0x0011,
+};
+
+enum COMDATType : uint8_t {
+  IMAGE_COMDAT_SELECT_NODUPLICATES = 1,
+  IMAGE_COMDAT_SELECT_ANY,
+  IMAGE_COMDAT_SELECT_SAME_SIZE,
+  IMAGE_COMDAT_SELECT_EXACT_MATCH,
+  IMAGE_COMDAT_SELECT_ASSOCIATIVE,
+  IMAGE_COMDAT_SELECT_LARGEST,
+  IMAGE_COMDAT_SELECT_NEWEST
+};
+
+// Auxiliary Symbol Formats
+struct AuxiliaryFunctionDefinition {
+  uint32_t TagIndex;
+  uint32_t TotalSize;
+  uint32_t PointerToLinenumber;
+  uint32_t PointerToNextFunction;
+  char unused[2];
+};
+
+struct AuxiliarybfAndefSymbol {
+  uint8_t unused1[4];
+  uint16_t Linenumber;
+  uint8_t unused2[6];
+  uint32_t PointerToNextFunction;
+  uint8_t unused3[2];
+};
+
+struct AuxiliaryWeakExternal {
+  uint32_t TagIndex;
+  uint32_t Characteristics;
+  uint8_t unused[10];
+};
+
+enum WeakExternalCharacteristics : unsigned {
+  IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY = 1,
+  IMAGE_WEAK_EXTERN_SEARCH_LIBRARY = 2,
+  IMAGE_WEAK_EXTERN_SEARCH_ALIAS = 3
+};
+
+struct AuxiliarySectionDefinition {
+  uint32_t Length;
+  uint16_t NumberOfRelocations;
+  uint16_t NumberOfLinenumbers;
+  uint32_t CheckSum;
+  uint32_t Number;
+  uint8_t Selection;
+  char unused;
+};
+
+struct AuxiliaryCLRToken {
+  uint8_t AuxType;
+  uint8_t unused1;
+  uint32_t SymbolTableIndex;
+  char unused2[12];
+};
+
+union Auxiliary {
+  AuxiliaryFunctionDefinition FunctionDefinition;
+  AuxiliarybfAndefSymbol bfAndefSymbol;
+  AuxiliaryWeakExternal WeakExternal;
+  AuxiliarySectionDefinition SectionDefinition;
+};
+
+/// The Import Directory Table.
+///
+/// There is a single array of these and one entry per imported DLL.
+struct ImportDirectoryTableEntry {
+  uint32_t ImportLookupTableRVA;
+  uint32_t TimeDateStamp;
+  uint32_t ForwarderChain;
+  uint32_t NameRVA;
+  uint32_t ImportAddressTableRVA;
+};
+
+/// The PE32 Import Lookup Table.
+///
+/// There is an array of these for each imported DLL. It represents either
+/// the ordinal to import from the target DLL, or a name to lookup and import
+/// from the target DLL.
+///
+/// This also happens to be the same format used by the Import Address Table
+/// when it is initially written out to the image.
+struct ImportLookupTableEntry32 {
+  uint32_t data;
+
+  /// Is this entry specified by ordinal, or name?
+  bool isOrdinal() const { return data & 0x80000000; }
+
+  /// Get the ordinal value of this entry. isOrdinal must be true.
+  uint16_t getOrdinal() const {
+    assert(isOrdinal() && "ILT entry is not an ordinal!");
+    return data & 0xFFFF;
+  }
+
+  /// Set the ordinal value and set isOrdinal to true.
+  void setOrdinal(uint16_t o) {
+    data = o;
+    data |= 0x80000000;
+  }
+
+  /// Get the Hint/Name entry RVA. isOrdinal must be false.
+  uint32_t getHintNameRVA() const {
+    assert(!isOrdinal() && "ILT entry is not a Hint/Name RVA!");
+    return data;
+  }
+
+  /// Set the Hint/Name entry RVA and set isOrdinal to false.
+  void setHintNameRVA(uint32_t rva) { data = rva; }
+};
+
+/// The DOS compatible header at the front of all PEs.
+struct DOSHeader {
+  uint16_t Magic;
+  uint16_t UsedBytesInTheLastPage;
+  uint16_t FileSizeInPages;
+  uint16_t NumberOfRelocationItems;
+  uint16_t HeaderSizeInParagraphs;
+  uint16_t MinimumExtraParagraphs;
+  uint16_t MaximumExtraParagraphs;
+  uint16_t InitialRelativeSS;
+  uint16_t InitialSP;
+  uint16_t Checksum;
+  uint16_t InitialIP;
+  uint16_t InitialRelativeCS;
+  uint16_t AddressOfRelocationTable;
+  uint16_t OverlayNumber;
+  uint16_t Reserved[4];
+  uint16_t OEMid;
+  uint16_t OEMinfo;
+  uint16_t Reserved2[10];
+  uint32_t AddressOfNewExeHeader;
+};
+
+struct PE32Header {
+  enum { PE32 = 0x10b, PE32_PLUS = 0x20b };
+
+  uint16_t Magic;
+  uint8_t MajorLinkerVersion;
+  uint8_t MinorLinkerVersion;
+  uint32_t SizeOfCode;
+  uint32_t SizeOfInitializedData;
+  uint32_t SizeOfUninitializedData;
+  uint32_t AddressOfEntryPoint; // RVA
+  uint32_t BaseOfCode;          // RVA
+  uint32_t BaseOfData;          // RVA
+  uint32_t ImageBase;
+  uint32_t SectionAlignment;
+  uint32_t FileAlignment;
+  uint16_t MajorOperatingSystemVersion;
+  uint16_t MinorOperatingSystemVersion;
+  uint16_t MajorImageVersion;
+  uint16_t MinorImageVersion;
+  uint16_t MajorSubsystemVersion;
+  uint16_t MinorSubsystemVersion;
+  uint32_t Win32VersionValue;
+  uint32_t SizeOfImage;
+  uint32_t SizeOfHeaders;
+  uint32_t CheckSum;
+  uint16_t Subsystem;
+  // FIXME: This should be DllCharacteristics to match the COFF spec.
+  uint16_t DLLCharacteristics;
+  uint32_t SizeOfStackReserve;
+  uint32_t SizeOfStackCommit;
+  uint32_t SizeOfHeapReserve;
+  uint32_t SizeOfHeapCommit;
+  uint32_t LoaderFlags;
+  // FIXME: This should be NumberOfRvaAndSizes to match the COFF spec.
+  uint32_t NumberOfRvaAndSize;
+};
+
+struct DataDirectory {
+  uint32_t RelativeVirtualAddress;
+  uint32_t Size;
+};
+
+enum DataDirectoryIndex : unsigned {
+  EXPORT_TABLE = 0,
+  IMPORT_TABLE,
+  RESOURCE_TABLE,
+  EXCEPTION_TABLE,
+  CERTIFICATE_TABLE,
+  BASE_RELOCATION_TABLE,
+  DEBUG_DIRECTORY,
+  ARCHITECTURE,
+  GLOBAL_PTR,
+  TLS_TABLE,
+  LOAD_CONFIG_TABLE,
+  BOUND_IMPORT,
+  IAT,
+  DELAY_IMPORT_DESCRIPTOR,
+  CLR_RUNTIME_HEADER,
+
+  NUM_DATA_DIRECTORIES
+};
+
+enum WindowsSubsystem : unsigned {
+  IMAGE_SUBSYSTEM_UNKNOWN = 0, ///< An unknown subsystem.
+  IMAGE_SUBSYSTEM_NATIVE = 1,  ///< Device drivers and native Windows processes
+  IMAGE_SUBSYSTEM_WINDOWS_GUI = 2,      ///< The Windows GUI subsystem.
+  IMAGE_SUBSYSTEM_WINDOWS_CUI = 3,      ///< The Windows character subsystem.
+  IMAGE_SUBSYSTEM_OS2_CUI = 5,          ///< The OS/2 character subsytem.
+  IMAGE_SUBSYSTEM_POSIX_CUI = 7,        ///< The POSIX character subsystem.
+  IMAGE_SUBSYSTEM_NATIVE_WINDOWS = 8,   ///< Native Windows 9x driver.
+  IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9,   ///< Windows CE.
+  IMAGE_SUBSYSTEM_EFI_APPLICATION = 10, ///< An EFI application.
+  IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11, ///< An EFI driver with boot
+                                                ///  services.
+  IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12,      ///< An EFI driver with run-time
+                                                ///  services.
+  IMAGE_SUBSYSTEM_EFI_ROM = 13,                 ///< An EFI ROM image.
+  IMAGE_SUBSYSTEM_XBOX = 14,                    ///< XBOX.
+  IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16 ///< A BCD application.
+};
+
+enum DLLCharacteristics : unsigned {
+  /// ASLR with 64 bit address space.
+  IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020,
+  /// DLL can be relocated at load time.
+  IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040,
+  /// Code integrity checks are enforced.
+  IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY = 0x0080,
+  ///< Image is NX compatible.
+  IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100,
+  /// Isolation aware, but do not isolate the image.
+  IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION = 0x0200,
+  /// Does not use structured exception handling (SEH). No SEH handler may be
+  /// called in this image.
+  IMAGE_DLL_CHARACTERISTICS_NO_SEH = 0x0400,
+  /// Do not bind the image.
+  IMAGE_DLL_CHARACTERISTICS_NO_BIND = 0x0800,
+  ///< Image should execute in an AppContainer.
+  IMAGE_DLL_CHARACTERISTICS_APPCONTAINER = 0x1000,
+  ///< A WDM driver.
+  IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER = 0x2000,
+  ///< Image supports Control Flow Guard.
+  IMAGE_DLL_CHARACTERISTICS_GUARD_CF = 0x4000,
+  /// Terminal Server aware.
+  IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000
+};
+
+enum DebugType : unsigned {
+  IMAGE_DEBUG_TYPE_UNKNOWN = 0,
+  IMAGE_DEBUG_TYPE_COFF = 1,
+  IMAGE_DEBUG_TYPE_CODEVIEW = 2,
+  IMAGE_DEBUG_TYPE_FPO = 3,
+  IMAGE_DEBUG_TYPE_MISC = 4,
+  IMAGE_DEBUG_TYPE_EXCEPTION = 5,
+  IMAGE_DEBUG_TYPE_FIXUP = 6,
+  IMAGE_DEBUG_TYPE_OMAP_TO_SRC = 7,
+  IMAGE_DEBUG_TYPE_OMAP_FROM_SRC = 8,
+  IMAGE_DEBUG_TYPE_BORLAND = 9,
+  IMAGE_DEBUG_TYPE_RESERVED10 = 10,
+  IMAGE_DEBUG_TYPE_CLSID = 11,
+  IMAGE_DEBUG_TYPE_VC_FEATURE = 12,
+  IMAGE_DEBUG_TYPE_POGO = 13,
+  IMAGE_DEBUG_TYPE_ILTCG = 14,
+  IMAGE_DEBUG_TYPE_MPX = 15,
+  IMAGE_DEBUG_TYPE_REPRO = 16,
+};
+
+enum BaseRelocationType : unsigned {
+  IMAGE_REL_BASED_ABSOLUTE = 0,
+  IMAGE_REL_BASED_HIGH = 1,
+  IMAGE_REL_BASED_LOW = 2,
+  IMAGE_REL_BASED_HIGHLOW = 3,
+  IMAGE_REL_BASED_HIGHADJ = 4,
+  IMAGE_REL_BASED_MIPS_JMPADDR = 5,
+  IMAGE_REL_BASED_ARM_MOV32A = 5,
+  IMAGE_REL_BASED_ARM_MOV32T = 7,
+  IMAGE_REL_BASED_MIPS_JMPADDR16 = 9,
+  IMAGE_REL_BASED_DIR64 = 10
+};
+
+enum ImportType : unsigned {
+  IMPORT_CODE = 0,
+  IMPORT_DATA = 1,
+  IMPORT_CONST = 2
+};
+
+enum ImportNameType : unsigned {
+  /// Import is by ordinal. This indicates that the value in the Ordinal/Hint
+  /// field of the import header is the import's ordinal. If this constant is
+  /// not specified, then the Ordinal/Hint field should always be interpreted
+  /// as the import's hint.
+  IMPORT_ORDINAL = 0,
+  /// The import name is identical to the public symbol name
+  IMPORT_NAME = 1,
+  /// The import name is the public symbol name, but skipping the leading ?,
+  /// @, or optionally _.
+  IMPORT_NAME_NOPREFIX = 2,
+  /// The import name is the public symbol name, but skipping the leading ?,
+  /// @, or optionally _, and truncating at the first @.
+  IMPORT_NAME_UNDECORATE = 3
+};
+
+struct ImportHeader {
+  uint16_t Sig1; ///< Must be IMAGE_FILE_MACHINE_UNKNOWN (0).
+  uint16_t Sig2; ///< Must be 0xFFFF.
+  uint16_t Version;
+  uint16_t Machine;
+  uint32_t TimeDateStamp;
+  uint32_t SizeOfData;
+  uint16_t OrdinalHint;
+  uint16_t TypeInfo;
+
+  ImportType getType() const { return static_cast<ImportType>(TypeInfo & 0x3); }
+
+  ImportNameType getNameType() const {
+    return static_cast<ImportNameType>((TypeInfo & 0x1C) >> 2);
+  }
+};
+
+enum CodeViewIdentifiers {
+  DEBUG_SECTION_MAGIC = 0x4,
+  DEBUG_HASHES_SECTION_MAGIC = 0x133C9C5
+};
+
+inline bool isReservedSectionNumber(int32_t SectionNumber) {
+  return SectionNumber <= 0;
+}
+
+} // End namespace COFF.
+} // End namespace llvm.
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Dwarf.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Dwarf.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Dwarf.def
@@ -0,0 +1,966 @@
+//===- llvm/Support/Dwarf.def - Dwarf definitions ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Macros for running through Dwarf enumerators.
+//
+//===----------------------------------------------------------------------===//
+
+// TODO: Add other DW-based macros.
+#if !(                                                                         \
+    defined HANDLE_DW_TAG || defined HANDLE_DW_AT || defined HANDLE_DW_FORM || \
+    defined HANDLE_DW_OP || defined HANDLE_DW_LANG || defined HANDLE_DW_ATE || \
+    defined HANDLE_DW_VIRTUALITY || defined HANDLE_DW_DEFAULTED ||             \
+    defined HANDLE_DW_CC || defined HANDLE_DW_LNS || defined HANDLE_DW_LNE ||  \
+    defined HANDLE_DW_LNCT || defined HANDLE_DW_MACRO ||                       \
+    defined HANDLE_DW_RLE || defined HANDLE_DW_LLE ||                          \
+    (defined HANDLE_DW_CFA && defined HANDLE_DW_CFA_PRED) ||                   \
+    defined HANDLE_DW_APPLE_PROPERTY || defined HANDLE_DW_UT ||                \
+    defined HANDLE_DWARF_SECTION || defined HANDLE_DW_IDX ||                   \
+    defined HANDLE_DW_END)
+#error "Missing macro definition of HANDLE_DW*"
+#endif
+
+#ifndef HANDLE_DW_TAG
+#define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR, KIND)
+#endif
+
+// Note that DW_KIND is not a DWARF concept, but rather a way for us to
+// generate a list of tags that belong together.
+#ifndef DW_KIND_NONE
+#define DW_KIND_NONE 0
+#endif
+
+#ifndef DW_KIND_TYPE
+#define DW_KIND_TYPE 1
+#endif
+
+#ifndef HANDLE_DW_AT
+#define HANDLE_DW_AT(ID, NAME, VERSION, VENDOR)
+#endif
+
+#ifndef HANDLE_DW_FORM
+#define HANDLE_DW_FORM(ID, NAME, VERSION, VENDOR)
+#endif
+
+#ifndef HANDLE_DW_OP
+#define HANDLE_DW_OP(ID, NAME, VERSION, VENDOR)
+#endif
+
+#ifndef HANDLE_DW_LANG
+#define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR)
+#endif
+
+#ifndef HANDLE_DW_ATE
+#define HANDLE_DW_ATE(ID, NAME, VERSION, VENDOR)
+#endif
+
+#ifndef HANDLE_DW_VIRTUALITY
+#define HANDLE_DW_VIRTUALITY(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_DEFAULTED
+#define HANDLE_DW_DEFAULTED(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_CC
+#define HANDLE_DW_CC(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_LNS
+#define HANDLE_DW_LNS(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_LNE
+#define HANDLE_DW_LNE(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_LNCT
+#define HANDLE_DW_LNCT(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_MACRO
+#define HANDLE_DW_MACRO(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_RLE
+#define HANDLE_DW_RLE(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_LLE
+#define HANDLE_DW_LLE(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_CFA
+#define HANDLE_DW_CFA(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_CFA_PRED
+#define HANDLE_DW_CFA_PRED(ID, NAME, PRED)
+#endif
+
+#ifndef HANDLE_DW_APPLE_PROPERTY
+#define HANDLE_DW_APPLE_PROPERTY(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_UT
+#define HANDLE_DW_UT(ID, NAME)
+#endif
+
+#ifndef HANDLE_DWARF_SECTION
+#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME)
+#endif
+
+#ifndef HANDLE_DW_IDX
+#define HANDLE_DW_IDX(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_END
+#define HANDLE_DW_END(ID, NAME)
+#endif
+
+HANDLE_DW_TAG(0x0000, null, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0001, array_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0002, class_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0003, entry_point, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0004, enumeration_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0005, formal_parameter, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0008, imported_declaration, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x000a, label, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x000b, lexical_block, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x000d, member, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x000f, pointer_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0010, reference_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0011, compile_unit, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0012, string_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0013, structure_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0015, subroutine_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0016, typedef, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0017, union_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0018, unspecified_parameters, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0019, variant, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x001a, common_block, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x001b, common_inclusion, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x001c, inheritance, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x001d, inlined_subroutine, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x001e, module, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x001f, ptr_to_member_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0020, set_type, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0021, subrange_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0022, with_stmt, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0023, access_declaration, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0024, base_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0025, catch_block, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0026, const_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0027, constant, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0028, enumerator, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0029, file_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x002a, friend, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x002b, namelist, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x002c, namelist_item, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x002d, packed_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x002e, subprogram, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x002f, template_type_parameter, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0030, template_value_parameter, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0031, thrown_type, 2, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0032, try_block, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0033, variant_part, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0034, variable, 2, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0035, volatile_type, 2, DWARF, DW_KIND_TYPE)
+// New in DWARF v3:
+HANDLE_DW_TAG(0x0036, dwarf_procedure, 3, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0037, restrict_type, 3, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0038, interface_type, 3, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0039, namespace, 3, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x003a, imported_module, 3, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x003b, unspecified_type, 3, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x003c, partial_unit, 3, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x003d, imported_unit, 3, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x003f, condition, 3, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0040, shared_type, 3, DWARF, DW_KIND_TYPE)
+// New in DWARF v4:
+HANDLE_DW_TAG(0x0041, type_unit, 4, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0042, rvalue_reference_type, 4, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0043, template_alias, 4, DWARF, DW_KIND_NONE)
+// New in DWARF v5:
+HANDLE_DW_TAG(0x0044, coarray_type, 5, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0045, generic_subrange, 5, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0046, dynamic_type, 5, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0047, atomic_type, 5, DWARF, DW_KIND_TYPE)
+HANDLE_DW_TAG(0x0048, call_site, 5, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x0049, call_site_parameter, 5, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x004a, skeleton_unit, 5, DWARF, DW_KIND_NONE)
+HANDLE_DW_TAG(0x004b, immutable_type, 5, DWARF, DW_KIND_TYPE)
+// Vendor extensions:
+HANDLE_DW_TAG(0x4081, MIPS_loop, 0, MIPS, DW_KIND_NONE)
+HANDLE_DW_TAG(0x4101, format_label, 0, GNU, DW_KIND_NONE)
+HANDLE_DW_TAG(0x4102, function_template, 0, GNU, DW_KIND_NONE)
+HANDLE_DW_TAG(0x4103, class_template, 0, GNU, DW_KIND_NONE)
+HANDLE_DW_TAG(0x4106, GNU_template_template_param, 0, GNU, DW_KIND_NONE)
+HANDLE_DW_TAG(0x4107, GNU_template_parameter_pack, 0, GNU, DW_KIND_NONE)
+HANDLE_DW_TAG(0x4108, GNU_formal_parameter_pack, 0, GNU, DW_KIND_NONE)
+HANDLE_DW_TAG(0x4109, GNU_call_site, 0, GNU, DW_KIND_NONE)
+HANDLE_DW_TAG(0x410a, GNU_call_site_parameter, 0, GNU, DW_KIND_NONE)
+HANDLE_DW_TAG(0x4200, APPLE_property, 0, APPLE, DW_KIND_NONE)
+HANDLE_DW_TAG(0xb000, BORLAND_property, 0, BORLAND, DW_KIND_NONE)
+HANDLE_DW_TAG(0xb001, BORLAND_Delphi_string, 0, BORLAND, DW_KIND_TYPE)
+HANDLE_DW_TAG(0xb002, BORLAND_Delphi_dynamic_array, 0, BORLAND, DW_KIND_TYPE)
+HANDLE_DW_TAG(0xb003, BORLAND_Delphi_set, 0, BORLAND, DW_KIND_TYPE)
+HANDLE_DW_TAG(0xb004, BORLAND_Delphi_variant, 0, BORLAND, DW_KIND_TYPE)
+
+// Attributes.
+HANDLE_DW_AT(0x01, sibling, 2, DWARF)
+HANDLE_DW_AT(0x02, location, 2, DWARF)
+HANDLE_DW_AT(0x03, name, 2, DWARF)
+HANDLE_DW_AT(0x09, ordering, 2, DWARF)
+HANDLE_DW_AT(0x0b, byte_size, 2, DWARF)
+HANDLE_DW_AT(0x0c, bit_offset, 2, DWARF)
+HANDLE_DW_AT(0x0d, bit_size, 2, DWARF)
+HANDLE_DW_AT(0x10, stmt_list, 2, DWARF)
+HANDLE_DW_AT(0x11, low_pc, 2, DWARF)
+HANDLE_DW_AT(0x12, high_pc, 2, DWARF)
+HANDLE_DW_AT(0x13, language, 2, DWARF)
+HANDLE_DW_AT(0x15, discr, 2, DWARF)
+HANDLE_DW_AT(0x16, discr_value, 2, DWARF)
+HANDLE_DW_AT(0x17, visibility, 2, DWARF)
+HANDLE_DW_AT(0x18, import, 2, DWARF)
+HANDLE_DW_AT(0x19, string_length, 2, DWARF)
+HANDLE_DW_AT(0x1a, common_reference, 2, DWARF)
+HANDLE_DW_AT(0x1b, comp_dir, 2, DWARF)
+HANDLE_DW_AT(0x1c, const_value, 2, DWARF)
+HANDLE_DW_AT(0x1d, containing_type, 2, DWARF)
+HANDLE_DW_AT(0x1e, default_value, 2, DWARF)
+HANDLE_DW_AT(0x20, inline, 2, DWARF)
+HANDLE_DW_AT(0x21, is_optional, 2, DWARF)
+HANDLE_DW_AT(0x22, lower_bound, 2, DWARF)
+HANDLE_DW_AT(0x25, producer, 2, DWARF)
+HANDLE_DW_AT(0x27, prototyped, 2, DWARF)
+HANDLE_DW_AT(0x2a, return_addr, 2, DWARF)
+HANDLE_DW_AT(0x2c, start_scope, 2, DWARF)
+HANDLE_DW_AT(0x2e, bit_stride, 2, DWARF)
+HANDLE_DW_AT(0x2f, upper_bound, 2, DWARF)
+HANDLE_DW_AT(0x31, abstract_origin, 2, DWARF)
+HANDLE_DW_AT(0x32, accessibility, 2, DWARF)
+HANDLE_DW_AT(0x33, address_class, 2, DWARF)
+HANDLE_DW_AT(0x34, artificial, 2, DWARF)
+HANDLE_DW_AT(0x35, base_types, 2, DWARF)
+HANDLE_DW_AT(0x36, calling_convention, 2, DWARF)
+HANDLE_DW_AT(0x37, count, 2, DWARF)
+HANDLE_DW_AT(0x38, data_member_location, 2, DWARF)
+HANDLE_DW_AT(0x39, decl_column, 2, DWARF)
+HANDLE_DW_AT(0x3a, decl_file, 2, DWARF)
+HANDLE_DW_AT(0x3b, decl_line, 2, DWARF)
+HANDLE_DW_AT(0x3c, declaration, 2, DWARF)
+HANDLE_DW_AT(0x3d, discr_list, 2, DWARF)
+HANDLE_DW_AT(0x3e, encoding, 2, DWARF)
+HANDLE_DW_AT(0x3f, external, 2, DWARF)
+HANDLE_DW_AT(0x40, frame_base, 2, DWARF)
+HANDLE_DW_AT(0x41, friend, 2, DWARF)
+HANDLE_DW_AT(0x42, identifier_case, 2, DWARF)
+HANDLE_DW_AT(0x43, macro_info, 2, DWARF)
+HANDLE_DW_AT(0x44, namelist_item, 2, DWARF)
+HANDLE_DW_AT(0x45, priority, 2, DWARF)
+HANDLE_DW_AT(0x46, segment, 2, DWARF)
+HANDLE_DW_AT(0x47, specification, 2, DWARF)
+HANDLE_DW_AT(0x48, static_link, 2, DWARF)
+HANDLE_DW_AT(0x49, type, 2, DWARF)
+HANDLE_DW_AT(0x4a, use_location, 2, DWARF)
+HANDLE_DW_AT(0x4b, variable_parameter, 2, DWARF)
+HANDLE_DW_AT(0x4c, virtuality, 2, DWARF)
+HANDLE_DW_AT(0x4d, vtable_elem_location, 2, DWARF)
+// New in DWARF v3:
+HANDLE_DW_AT(0x4e, allocated, 3, DWARF)
+HANDLE_DW_AT(0x4f, associated, 3, DWARF)
+HANDLE_DW_AT(0x50, data_location, 3, DWARF)
+HANDLE_DW_AT(0x51, byte_stride, 3, DWARF)
+HANDLE_DW_AT(0x52, entry_pc, 3, DWARF)
+HANDLE_DW_AT(0x53, use_UTF8, 3, DWARF)
+HANDLE_DW_AT(0x54, extension, 3, DWARF)
+HANDLE_DW_AT(0x55, ranges, 3, DWARF)
+HANDLE_DW_AT(0x56, trampoline, 3, DWARF)
+HANDLE_DW_AT(0x57, call_column, 3, DWARF)
+HANDLE_DW_AT(0x58, call_file, 3, DWARF)
+HANDLE_DW_AT(0x59, call_line, 3, DWARF)
+HANDLE_DW_AT(0x5a, description, 3, DWARF)
+HANDLE_DW_AT(0x5b, binary_scale, 3, DWARF)
+HANDLE_DW_AT(0x5c, decimal_scale, 3, DWARF)
+HANDLE_DW_AT(0x5d, small, 3, DWARF)
+HANDLE_DW_AT(0x5e, decimal_sign, 3, DWARF)
+HANDLE_DW_AT(0x5f, digit_count, 3, DWARF)
+HANDLE_DW_AT(0x60, picture_string, 3, DWARF)
+HANDLE_DW_AT(0x61, mutable, 3, DWARF)
+HANDLE_DW_AT(0x62, threads_scaled, 3, DWARF)
+HANDLE_DW_AT(0x63, explicit, 3, DWARF)
+HANDLE_DW_AT(0x64, object_pointer, 3, DWARF)
+HANDLE_DW_AT(0x65, endianity, 3, DWARF)
+HANDLE_DW_AT(0x66, elemental, 3, DWARF)
+HANDLE_DW_AT(0x67, pure, 3, DWARF)
+HANDLE_DW_AT(0x68, recursive, 3, DWARF)
+// New in DWARF v4:
+HANDLE_DW_AT(0x69, signature, 4, DWARF)
+HANDLE_DW_AT(0x6a, main_subprogram, 4, DWARF)
+HANDLE_DW_AT(0x6b, data_bit_offset, 4, DWARF)
+HANDLE_DW_AT(0x6c, const_expr, 4, DWARF)
+HANDLE_DW_AT(0x6d, enum_class, 4, DWARF)
+HANDLE_DW_AT(0x6e, linkage_name, 4, DWARF)
+// New in DWARF v5:
+HANDLE_DW_AT(0x6f, string_length_bit_size, 5, DWARF)
+HANDLE_DW_AT(0x70, string_length_byte_size, 5, DWARF)
+HANDLE_DW_AT(0x71, rank, 5, DWARF)
+HANDLE_DW_AT(0x72, str_offsets_base, 5, DWARF)
+HANDLE_DW_AT(0x73, addr_base, 5, DWARF)
+HANDLE_DW_AT(0x74, rnglists_base, 5, DWARF)
+HANDLE_DW_AT(0x75, dwo_id, 0, DWARF) ///< Retracted from DWARF v5.
+HANDLE_DW_AT(0x76, dwo_name, 5, DWARF)
+HANDLE_DW_AT(0x77, reference, 5, DWARF)
+HANDLE_DW_AT(0x78, rvalue_reference, 5, DWARF)
+HANDLE_DW_AT(0x79, macros, 5, DWARF)
+HANDLE_DW_AT(0x7a, call_all_calls, 5, DWARF)
+HANDLE_DW_AT(0x7b, call_all_source_calls, 5, DWARF)
+HANDLE_DW_AT(0x7c, call_all_tail_calls, 5, DWARF)
+HANDLE_DW_AT(0x7d, call_return_pc, 5, DWARF)
+HANDLE_DW_AT(0x7e, call_value, 5, DWARF)
+HANDLE_DW_AT(0x7f, call_origin, 5, DWARF)
+HANDLE_DW_AT(0x80, call_parameter, 5, DWARF)
+HANDLE_DW_AT(0x81, call_pc, 5, DWARF)
+HANDLE_DW_AT(0x82, call_tail_call, 5, DWARF)
+HANDLE_DW_AT(0x83, call_target, 5, DWARF)
+HANDLE_DW_AT(0x84, call_target_clobbered, 5, DWARF)
+HANDLE_DW_AT(0x85, call_data_location, 5, DWARF)
+HANDLE_DW_AT(0x86, call_data_value, 5, DWARF)
+HANDLE_DW_AT(0x87, noreturn, 5, DWARF)
+HANDLE_DW_AT(0x88, alignment, 5, DWARF)
+HANDLE_DW_AT(0x89, export_symbols, 5, DWARF)
+HANDLE_DW_AT(0x8a, deleted, 5, DWARF)
+HANDLE_DW_AT(0x8b, defaulted, 5, DWARF)
+HANDLE_DW_AT(0x8c, loclists_base, 5, DWARF)
+// Vendor extensions:
+HANDLE_DW_AT(0x2002, MIPS_loop_begin, 0, MIPS)
+HANDLE_DW_AT(0x2003, MIPS_tail_loop_begin, 0, MIPS)
+HANDLE_DW_AT(0x2004, MIPS_epilog_begin, 0, MIPS)
+HANDLE_DW_AT(0x2005, MIPS_loop_unroll_factor, 0, MIPS)
+HANDLE_DW_AT(0x2006, MIPS_software_pipeline_depth, 0, MIPS)
+HANDLE_DW_AT(0x2007, MIPS_linkage_name, 0, MIPS)
+HANDLE_DW_AT(0x2008, MIPS_stride, 0, MIPS)
+HANDLE_DW_AT(0x2009, MIPS_abstract_name, 0, MIPS)
+HANDLE_DW_AT(0x200a, MIPS_clone_origin, 0, MIPS)
+HANDLE_DW_AT(0x200b, MIPS_has_inlines, 0, MIPS)
+HANDLE_DW_AT(0x200c, MIPS_stride_byte, 0, MIPS)
+HANDLE_DW_AT(0x200d, MIPS_stride_elem, 0, MIPS)
+HANDLE_DW_AT(0x200e, MIPS_ptr_dopetype, 0, MIPS)
+HANDLE_DW_AT(0x200f, MIPS_allocatable_dopetype, 0, MIPS)
+HANDLE_DW_AT(0x2010, MIPS_assumed_shape_dopetype, 0, MIPS)
+// This one appears to have only been implemented by Open64 for
+// fortran and may conflict with other extensions.
+HANDLE_DW_AT(0x2011, MIPS_assumed_size, 0, MIPS)
+// GNU extensions
+HANDLE_DW_AT(0x2101, sf_names, 0, GNU)
+HANDLE_DW_AT(0x2102, src_info, 0, GNU)
+HANDLE_DW_AT(0x2103, mac_info, 0, GNU)
+HANDLE_DW_AT(0x2104, src_coords, 0, GNU)
+HANDLE_DW_AT(0x2105, body_begin, 0, GNU)
+HANDLE_DW_AT(0x2106, body_end, 0, GNU)
+HANDLE_DW_AT(0x2107, GNU_vector, 0, GNU)
+HANDLE_DW_AT(0x2110, GNU_template_name, 0, GNU)
+HANDLE_DW_AT(0x210f, GNU_odr_signature, 0, GNU)
+HANDLE_DW_AT(0x2111, GNU_call_site_value, 0, GNU)
+HANDLE_DW_AT (0x2112, GNU_call_site_data_value, 0, GNU)
+HANDLE_DW_AT (0x2113, GNU_call_site_target, 0, GNU)
+HANDLE_DW_AT (0x2114, GNU_call_site_target_clobbered, 0, GNU)
+HANDLE_DW_AT (0x2115, GNU_tail_call, 0, GNU)
+HANDLE_DW_AT (0x2116, GNU_all_tail_call_sites, 0, GNU)
+HANDLE_DW_AT(0x2117, GNU_all_call_sites, 0, GNU)
+HANDLE_DW_AT (0x2118, GNU_all_source_call_sites, 0, GNU)
+HANDLE_DW_AT(0x2119, GNU_macros, 0, GNU)
+// Extensions for Fission proposal.
+HANDLE_DW_AT(0x2130, GNU_dwo_name, 0, GNU)
+HANDLE_DW_AT(0x2131, GNU_dwo_id, 0, GNU)
+HANDLE_DW_AT(0x2132, GNU_ranges_base, 0, GNU)
+HANDLE_DW_AT(0x2133, GNU_addr_base, 0, GNU)
+HANDLE_DW_AT(0x2134, GNU_pubnames, 0, GNU)
+HANDLE_DW_AT(0x2135, GNU_pubtypes, 0, GNU)
+HANDLE_DW_AT(0x2136, GNU_discriminator, 0, GNU)
+// Borland extensions.
+HANDLE_DW_AT(0x3b11, BORLAND_property_read, 0, BORLAND)
+HANDLE_DW_AT(0x3b12, BORLAND_property_write, 0, BORLAND)
+HANDLE_DW_AT(0x3b13, BORLAND_property_implements, 0, BORLAND)
+HANDLE_DW_AT(0x3b14, BORLAND_property_index, 0, BORLAND)
+HANDLE_DW_AT(0x3b15, BORLAND_property_default, 0, BORLAND)
+HANDLE_DW_AT(0x3b20, BORLAND_Delphi_unit, 0, BORLAND)
+HANDLE_DW_AT(0x3b21, BORLAND_Delphi_class, 0, BORLAND)
+HANDLE_DW_AT(0x3b22, BORLAND_Delphi_record, 0, BORLAND)
+HANDLE_DW_AT(0x3b23, BORLAND_Delphi_metaclass, 0, BORLAND)
+HANDLE_DW_AT(0x3b24, BORLAND_Delphi_constructor, 0, BORLAND)
+HANDLE_DW_AT(0x3b25, BORLAND_Delphi_destructor, 0, BORLAND)
+HANDLE_DW_AT(0x3b26, BORLAND_Delphi_anonymous_method, 0, BORLAND)
+HANDLE_DW_AT(0x3b27, BORLAND_Delphi_interface, 0, BORLAND)
+HANDLE_DW_AT(0x3b28, BORLAND_Delphi_ABI, 0, BORLAND)
+HANDLE_DW_AT(0x3b29, BORLAND_Delphi_return, 0, BORLAND)
+HANDLE_DW_AT(0x3b30, BORLAND_Delphi_frameptr, 0, BORLAND)
+HANDLE_DW_AT(0x3b31, BORLAND_closure, 0, BORLAND)
+// LLVM project extensions.
+HANDLE_DW_AT(0x3e00, LLVM_include_path, 0, LLVM)
+HANDLE_DW_AT(0x3e01, LLVM_config_macros, 0, LLVM)
+HANDLE_DW_AT(0x3e02, LLVM_isysroot, 0, LLVM)
+HANDLE_DW_AT(0x3e03, LLVM_tag_offset, 0, LLVM)
+// Apple extensions.
+HANDLE_DW_AT(0x3fe1, APPLE_optimized, 0, APPLE)
+HANDLE_DW_AT(0x3fe2, APPLE_flags, 0, APPLE)
+HANDLE_DW_AT(0x3fe3, APPLE_isa, 0, APPLE)
+HANDLE_DW_AT(0x3fe4, APPLE_block, 0, APPLE)
+HANDLE_DW_AT(0x3fe5, APPLE_major_runtime_vers, 0, APPLE)
+HANDLE_DW_AT(0x3fe6, APPLE_runtime_class, 0, APPLE)
+HANDLE_DW_AT(0x3fe7, APPLE_omit_frame_ptr, 0, APPLE)
+HANDLE_DW_AT(0x3fe8, APPLE_property_name, 0, APPLE)
+HANDLE_DW_AT(0x3fe9, APPLE_property_getter, 0, APPLE)
+HANDLE_DW_AT(0x3fea, APPLE_property_setter, 0, APPLE)
+HANDLE_DW_AT(0x3feb, APPLE_property_attribute, 0, APPLE)
+HANDLE_DW_AT(0x3fec, APPLE_objc_complete_type, 0, APPLE)
+HANDLE_DW_AT(0x3fed, APPLE_property, 0, APPLE)
+
+// Attribute form encodings.
+HANDLE_DW_FORM(0x01, addr, 2, DWARF)
+HANDLE_DW_FORM(0x03, block2, 2, DWARF)
+HANDLE_DW_FORM(0x04, block4, 2, DWARF)
+HANDLE_DW_FORM(0x05, data2, 2, DWARF)
+HANDLE_DW_FORM(0x06, data4, 2, DWARF)
+HANDLE_DW_FORM(0x07, data8, 2, DWARF)
+HANDLE_DW_FORM(0x08, string, 2, DWARF)
+HANDLE_DW_FORM(0x09, block, 2, DWARF)
+HANDLE_DW_FORM(0x0a, block1, 2, DWARF)
+HANDLE_DW_FORM(0x0b, data1, 2, DWARF)
+HANDLE_DW_FORM(0x0c, flag, 2, DWARF)
+HANDLE_DW_FORM(0x0d, sdata, 2, DWARF)
+HANDLE_DW_FORM(0x0e, strp, 2, DWARF)
+HANDLE_DW_FORM(0x0f, udata, 2, DWARF)
+HANDLE_DW_FORM(0x10, ref_addr, 2, DWARF)
+HANDLE_DW_FORM(0x11, ref1, 2, DWARF)
+HANDLE_DW_FORM(0x12, ref2, 2, DWARF)
+HANDLE_DW_FORM(0x13, ref4, 2, DWARF)
+HANDLE_DW_FORM(0x14, ref8, 2, DWARF)
+HANDLE_DW_FORM(0x15, ref_udata, 2, DWARF)
+HANDLE_DW_FORM(0x16, indirect, 2, DWARF)
+// New in DWARF v4:
+HANDLE_DW_FORM(0x17, sec_offset, 4, DWARF)
+HANDLE_DW_FORM(0x18, exprloc, 4, DWARF)
+HANDLE_DW_FORM(0x19, flag_present, 4, DWARF)
+// This was defined out of sequence.
+HANDLE_DW_FORM(0x20, ref_sig8, 4, DWARF)
+// New in DWARF v5:
+HANDLE_DW_FORM(0x1a, strx, 5, DWARF)
+HANDLE_DW_FORM(0x1b, addrx, 5, DWARF)
+HANDLE_DW_FORM(0x1c, ref_sup4, 5, DWARF)
+HANDLE_DW_FORM(0x1d, strp_sup, 5, DWARF)
+HANDLE_DW_FORM(0x1e, data16, 5, DWARF)
+HANDLE_DW_FORM(0x1f, line_strp, 5, DWARF)
+HANDLE_DW_FORM(0x21, implicit_const, 5, DWARF)
+HANDLE_DW_FORM(0x22, loclistx, 5, DWARF)
+HANDLE_DW_FORM(0x23, rnglistx, 5, DWARF)
+HANDLE_DW_FORM(0x24, ref_sup8, 5, DWARF)
+HANDLE_DW_FORM(0x25, strx1, 5, DWARF)
+HANDLE_DW_FORM(0x26, strx2, 5, DWARF)
+HANDLE_DW_FORM(0x27, strx3, 5, DWARF)
+HANDLE_DW_FORM(0x28, strx4, 5, DWARF)
+HANDLE_DW_FORM(0x29, addrx1, 5, DWARF)
+HANDLE_DW_FORM(0x2a, addrx2, 5, DWARF)
+HANDLE_DW_FORM(0x2b, addrx3, 5, DWARF)
+HANDLE_DW_FORM(0x2c, addrx4, 5, DWARF)
+// Extensions for Fission proposal
+HANDLE_DW_FORM(0x1f01, GNU_addr_index, 0, GNU)
+HANDLE_DW_FORM(0x1f02, GNU_str_index, 0, GNU)
+// Alternate debug sections proposal (output of "dwz" tool).
+HANDLE_DW_FORM(0x1f20, GNU_ref_alt, 0, GNU)
+HANDLE_DW_FORM(0x1f21, GNU_strp_alt, 0, GNU)
+
+// DWARF Expression operators.
+HANDLE_DW_OP(0x03, addr, 2, DWARF)
+HANDLE_DW_OP(0x06, deref, 2, DWARF)
+HANDLE_DW_OP(0x08, const1u, 2, DWARF)
+HANDLE_DW_OP(0x09, const1s, 2, DWARF)
+HANDLE_DW_OP(0x0a, const2u, 2, DWARF)
+HANDLE_DW_OP(0x0b, const2s, 2, DWARF)
+HANDLE_DW_OP(0x0c, const4u, 2, DWARF)
+HANDLE_DW_OP(0x0d, const4s, 2, DWARF)
+HANDLE_DW_OP(0x0e, const8u, 2, DWARF)
+HANDLE_DW_OP(0x0f, const8s, 2, DWARF)
+HANDLE_DW_OP(0x10, constu, 2, DWARF)
+HANDLE_DW_OP(0x11, consts, 2, DWARF)
+HANDLE_DW_OP(0x12, dup, 2, DWARF)
+HANDLE_DW_OP(0x13, drop, 2, DWARF)
+HANDLE_DW_OP(0x14, over, 2, DWARF)
+HANDLE_DW_OP(0x15, pick, 2, DWARF)
+HANDLE_DW_OP(0x16, swap, 2, DWARF)
+HANDLE_DW_OP(0x17, rot, 2, DWARF)
+HANDLE_DW_OP(0x18, xderef, 2, DWARF)
+HANDLE_DW_OP(0x19, abs, 2, DWARF)
+HANDLE_DW_OP(0x1a, and, 2, DWARF)
+HANDLE_DW_OP(0x1b, div, 2, DWARF)
+HANDLE_DW_OP(0x1c, minus, 2, DWARF)
+HANDLE_DW_OP(0x1d, mod, 2, DWARF)
+HANDLE_DW_OP(0x1e, mul, 2, DWARF)
+HANDLE_DW_OP(0x1f, neg, 2, DWARF)
+HANDLE_DW_OP(0x20, not, 2, DWARF)
+HANDLE_DW_OP(0x21, or, 2, DWARF)
+HANDLE_DW_OP(0x22, plus, 2, DWARF)
+HANDLE_DW_OP(0x23, plus_uconst, 2, DWARF)
+HANDLE_DW_OP(0x24, shl, 2, DWARF)
+HANDLE_DW_OP(0x25, shr, 2, DWARF)
+HANDLE_DW_OP(0x26, shra, 2, DWARF)
+HANDLE_DW_OP(0x27, xor, 2, DWARF)
+HANDLE_DW_OP(0x28, bra, 2, DWARF)
+HANDLE_DW_OP(0x29, eq, 2, DWARF)
+HANDLE_DW_OP(0x2a, ge, 2, DWARF)
+HANDLE_DW_OP(0x2b, gt, 2, DWARF)
+HANDLE_DW_OP(0x2c, le, 2, DWARF)
+HANDLE_DW_OP(0x2d, lt, 2, DWARF)
+HANDLE_DW_OP(0x2e, ne, 2, DWARF)
+HANDLE_DW_OP(0x2f, skip, 2, DWARF)
+HANDLE_DW_OP(0x30, lit0, 2, DWARF)
+HANDLE_DW_OP(0x31, lit1, 2, DWARF)
+HANDLE_DW_OP(0x32, lit2, 2, DWARF)
+HANDLE_DW_OP(0x33, lit3, 2, DWARF)
+HANDLE_DW_OP(0x34, lit4, 2, DWARF)
+HANDLE_DW_OP(0x35, lit5, 2, DWARF)
+HANDLE_DW_OP(0x36, lit6, 2, DWARF)
+HANDLE_DW_OP(0x37, lit7, 2, DWARF)
+HANDLE_DW_OP(0x38, lit8, 2, DWARF)
+HANDLE_DW_OP(0x39, lit9, 2, DWARF)
+HANDLE_DW_OP(0x3a, lit10, 2, DWARF)
+HANDLE_DW_OP(0x3b, lit11, 2, DWARF)
+HANDLE_DW_OP(0x3c, lit12, 2, DWARF)
+HANDLE_DW_OP(0x3d, lit13, 2, DWARF)
+HANDLE_DW_OP(0x3e, lit14, 2, DWARF)
+HANDLE_DW_OP(0x3f, lit15, 2, DWARF)
+HANDLE_DW_OP(0x40, lit16, 2, DWARF)
+HANDLE_DW_OP(0x41, lit17, 2, DWARF)
+HANDLE_DW_OP(0x42, lit18, 2, DWARF)
+HANDLE_DW_OP(0x43, lit19, 2, DWARF)
+HANDLE_DW_OP(0x44, lit20, 2, DWARF)
+HANDLE_DW_OP(0x45, lit21, 2, DWARF)
+HANDLE_DW_OP(0x46, lit22, 2, DWARF)
+HANDLE_DW_OP(0x47, lit23, 2, DWARF)
+HANDLE_DW_OP(0x48, lit24, 2, DWARF)
+HANDLE_DW_OP(0x49, lit25, 2, DWARF)
+HANDLE_DW_OP(0x4a, lit26, 2, DWARF)
+HANDLE_DW_OP(0x4b, lit27, 2, DWARF)
+HANDLE_DW_OP(0x4c, lit28, 2, DWARF)
+HANDLE_DW_OP(0x4d, lit29, 2, DWARF)
+HANDLE_DW_OP(0x4e, lit30, 2, DWARF)
+HANDLE_DW_OP(0x4f, lit31, 2, DWARF)
+HANDLE_DW_OP(0x50, reg0, 2, DWARF)
+HANDLE_DW_OP(0x51, reg1, 2, DWARF)
+HANDLE_DW_OP(0x52, reg2, 2, DWARF)
+HANDLE_DW_OP(0x53, reg3, 2, DWARF)
+HANDLE_DW_OP(0x54, reg4, 2, DWARF)
+HANDLE_DW_OP(0x55, reg5, 2, DWARF)
+HANDLE_DW_OP(0x56, reg6, 2, DWARF)
+HANDLE_DW_OP(0x57, reg7, 2, DWARF)
+HANDLE_DW_OP(0x58, reg8, 2, DWARF)
+HANDLE_DW_OP(0x59, reg9, 2, DWARF)
+HANDLE_DW_OP(0x5a, reg10, 2, DWARF)
+HANDLE_DW_OP(0x5b, reg11, 2, DWARF)
+HANDLE_DW_OP(0x5c, reg12, 2, DWARF)
+HANDLE_DW_OP(0x5d, reg13, 2, DWARF)
+HANDLE_DW_OP(0x5e, reg14, 2, DWARF)
+HANDLE_DW_OP(0x5f, reg15, 2, DWARF)
+HANDLE_DW_OP(0x60, reg16, 2, DWARF)
+HANDLE_DW_OP(0x61, reg17, 2, DWARF)
+HANDLE_DW_OP(0x62, reg18, 2, DWARF)
+HANDLE_DW_OP(0x63, reg19, 2, DWARF)
+HANDLE_DW_OP(0x64, reg20, 2, DWARF)
+HANDLE_DW_OP(0x65, reg21, 2, DWARF)
+HANDLE_DW_OP(0x66, reg22, 2, DWARF)
+HANDLE_DW_OP(0x67, reg23, 2, DWARF)
+HANDLE_DW_OP(0x68, reg24, 2, DWARF)
+HANDLE_DW_OP(0x69, reg25, 2, DWARF)
+HANDLE_DW_OP(0x6a, reg26, 2, DWARF)
+HANDLE_DW_OP(0x6b, reg27, 2, DWARF)
+HANDLE_DW_OP(0x6c, reg28, 2, DWARF)
+HANDLE_DW_OP(0x6d, reg29, 2, DWARF)
+HANDLE_DW_OP(0x6e, reg30, 2, DWARF)
+HANDLE_DW_OP(0x6f, reg31, 2, DWARF)
+HANDLE_DW_OP(0x70, breg0, 2, DWARF)
+HANDLE_DW_OP(0x71, breg1, 2, DWARF)
+HANDLE_DW_OP(0x72, breg2, 2, DWARF)
+HANDLE_DW_OP(0x73, breg3, 2, DWARF)
+HANDLE_DW_OP(0x74, breg4, 2, DWARF)
+HANDLE_DW_OP(0x75, breg5, 2, DWARF)
+HANDLE_DW_OP(0x76, breg6, 2, DWARF)
+HANDLE_DW_OP(0x77, breg7, 2, DWARF)
+HANDLE_DW_OP(0x78, breg8, 2, DWARF)
+HANDLE_DW_OP(0x79, breg9, 2, DWARF)
+HANDLE_DW_OP(0x7a, breg10, 2, DWARF)
+HANDLE_DW_OP(0x7b, breg11, 2, DWARF)
+HANDLE_DW_OP(0x7c, breg12, 2, DWARF)
+HANDLE_DW_OP(0x7d, breg13, 2, DWARF)
+HANDLE_DW_OP(0x7e, breg14, 2, DWARF)
+HANDLE_DW_OP(0x7f, breg15, 2, DWARF)
+HANDLE_DW_OP(0x80, breg16, 2, DWARF)
+HANDLE_DW_OP(0x81, breg17, 2, DWARF)
+HANDLE_DW_OP(0x82, breg18, 2, DWARF)
+HANDLE_DW_OP(0x83, breg19, 2, DWARF)
+HANDLE_DW_OP(0x84, breg20, 2, DWARF)
+HANDLE_DW_OP(0x85, breg21, 2, DWARF)
+HANDLE_DW_OP(0x86, breg22, 2, DWARF)
+HANDLE_DW_OP(0x87, breg23, 2, DWARF)
+HANDLE_DW_OP(0x88, breg24, 2, DWARF)
+HANDLE_DW_OP(0x89, breg25, 2, DWARF)
+HANDLE_DW_OP(0x8a, breg26, 2, DWARF)
+HANDLE_DW_OP(0x8b, breg27, 2, DWARF)
+HANDLE_DW_OP(0x8c, breg28, 2, DWARF)
+HANDLE_DW_OP(0x8d, breg29, 2, DWARF)
+HANDLE_DW_OP(0x8e, breg30, 2, DWARF)
+HANDLE_DW_OP(0x8f, breg31, 2, DWARF)
+HANDLE_DW_OP(0x90, regx, 2, DWARF)
+HANDLE_DW_OP(0x91, fbreg, 2, DWARF)
+HANDLE_DW_OP(0x92, bregx, 2, DWARF)
+HANDLE_DW_OP(0x93, piece, 2, DWARF)
+HANDLE_DW_OP(0x94, deref_size, 2, DWARF)
+HANDLE_DW_OP(0x95, xderef_size, 2, DWARF)
+HANDLE_DW_OP(0x96, nop, 2, DWARF)
+// New in DWARF v3:
+HANDLE_DW_OP(0x97, push_object_address, 3, DWARF)
+HANDLE_DW_OP(0x98, call2, 3, DWARF)
+HANDLE_DW_OP(0x99, call4, 3, DWARF)
+HANDLE_DW_OP(0x9a, call_ref, 3, DWARF)
+HANDLE_DW_OP(0x9b, form_tls_address, 3, DWARF)
+HANDLE_DW_OP(0x9c, call_frame_cfa, 3, DWARF)
+HANDLE_DW_OP(0x9d, bit_piece, 3, DWARF)
+// New in DWARF v4:
+HANDLE_DW_OP(0x9e, implicit_value, 4, DWARF)
+HANDLE_DW_OP(0x9f, stack_value, 4, DWARF)
+// New in DWARF v5:
+HANDLE_DW_OP(0xa0, implicit_pointer, 5, DWARF)
+HANDLE_DW_OP(0xa1, addrx, 5, DWARF)
+HANDLE_DW_OP(0xa2, constx, 5, DWARF)
+HANDLE_DW_OP(0xa3, entry_value, 5, DWARF)
+HANDLE_DW_OP(0xa4, const_type, 5, DWARF)
+HANDLE_DW_OP(0xa5, regval_type, 5, DWARF)
+HANDLE_DW_OP(0xa6, deref_type, 5, DWARF)
+HANDLE_DW_OP(0xa7, xderef_type, 5, DWARF)
+HANDLE_DW_OP(0xa8, convert, 5, DWARF)
+HANDLE_DW_OP(0xa9, reinterpret, 5, DWARF)
+// Vendor extensions:
+// Extensions for GNU-style thread-local storage.
+HANDLE_DW_OP(0xe0, GNU_push_tls_address, 0, GNU)
+// Extensions for WebAssembly.
+HANDLE_DW_OP(0xed, WASM_location, 0, WASM)
+// The GNU entry value extension.
+HANDLE_DW_OP(0xf3, GNU_entry_value, 0, GNU)
+// Extensions for Fission proposal.
+HANDLE_DW_OP(0xfb, GNU_addr_index, 0, GNU)
+HANDLE_DW_OP(0xfc, GNU_const_index, 0, GNU)
+
+// DWARF languages.
+HANDLE_DW_LANG(0x0001, C89, 0, 2, DWARF)
+HANDLE_DW_LANG(0x0002, C, 0, 2, DWARF)
+HANDLE_DW_LANG(0x0003, Ada83, 1, 2, DWARF)
+HANDLE_DW_LANG(0x0004, C_plus_plus, 0, 2, DWARF)
+HANDLE_DW_LANG(0x0005, Cobol74, 1, 2, DWARF)
+HANDLE_DW_LANG(0x0006, Cobol85, 1, 2, DWARF)
+HANDLE_DW_LANG(0x0007, Fortran77, 1, 2, DWARF)
+HANDLE_DW_LANG(0x0008, Fortran90, 1, 2, DWARF)
+HANDLE_DW_LANG(0x0009, Pascal83, 1, 2, DWARF)
+HANDLE_DW_LANG(0x000a, Modula2, 1, 2, DWARF)
+// New in DWARF v3:
+HANDLE_DW_LANG(0x000b, Java, 0, 3, DWARF)
+HANDLE_DW_LANG(0x000c, C99, 0, 3, DWARF)
+HANDLE_DW_LANG(0x000d, Ada95, 1, 3, DWARF)
+HANDLE_DW_LANG(0x000e, Fortran95, 1, 3, DWARF)
+HANDLE_DW_LANG(0x000f, PLI, 1, 3, DWARF)
+HANDLE_DW_LANG(0x0010, ObjC, 0, 3, DWARF)
+HANDLE_DW_LANG(0x0011, ObjC_plus_plus, 0, 3, DWARF)
+HANDLE_DW_LANG(0x0012, UPC, 0, 3, DWARF)
+HANDLE_DW_LANG(0x0013, D, 0, 3, DWARF)
+// New in DWARF v4:
+HANDLE_DW_LANG(0x0014, Python, 0, 4, DWARF)
+// New in DWARF v5:
+HANDLE_DW_LANG(0x0015, OpenCL, 0, 5, DWARF)
+HANDLE_DW_LANG(0x0016, Go, 0, 5, DWARF)
+HANDLE_DW_LANG(0x0017, Modula3, 1, 5, DWARF)
+HANDLE_DW_LANG(0x0018, Haskell, 0, 5, DWARF)
+HANDLE_DW_LANG(0x0019, C_plus_plus_03, 0, 5, DWARF)
+HANDLE_DW_LANG(0x001a, C_plus_plus_11, 0, 5, DWARF)
+HANDLE_DW_LANG(0x001b, OCaml, 0, 5, DWARF)
+HANDLE_DW_LANG(0x001c, Rust, 0, 5, DWARF)
+HANDLE_DW_LANG(0x001d, C11, 0, 5, DWARF)
+HANDLE_DW_LANG(0x001e, Swift, 0, 5, DWARF)
+HANDLE_DW_LANG(0x001f, Julia, 1, 5, DWARF)
+HANDLE_DW_LANG(0x0020, Dylan, 0, 5, DWARF)
+HANDLE_DW_LANG(0x0021, C_plus_plus_14, 0, 5, DWARF)
+HANDLE_DW_LANG(0x0022, Fortran03, 1, 5, DWARF)
+HANDLE_DW_LANG(0x0023, Fortran08, 1, 5, DWARF)
+HANDLE_DW_LANG(0x0024, RenderScript, 0, 5, DWARF)
+HANDLE_DW_LANG(0x0025, BLISS, 0, 5, DWARF)
+// Vendor extensions:
+HANDLE_DW_LANG(0x8001, Mips_Assembler, None, 0, MIPS)
+HANDLE_DW_LANG(0x8e57, GOOGLE_RenderScript, 0, 0, GOOGLE)
+HANDLE_DW_LANG(0xb000, BORLAND_Delphi, 0, 0, BORLAND)
+
+// DWARF attribute type encodings.
+HANDLE_DW_ATE(0x01, address, 2, DWARF)
+HANDLE_DW_ATE(0x02, boolean, 2, DWARF)
+HANDLE_DW_ATE(0x03, complex_float, 2, DWARF)
+HANDLE_DW_ATE(0x04, float, 2, DWARF)
+HANDLE_DW_ATE(0x05, signed, 2, DWARF)
+HANDLE_DW_ATE(0x06, signed_char, 2, DWARF)
+HANDLE_DW_ATE(0x07, unsigned, 2, DWARF)
+HANDLE_DW_ATE(0x08, unsigned_char, 2, DWARF)
+// New in DWARF v3:
+HANDLE_DW_ATE(0x09, imaginary_float, 3, DWARF)
+HANDLE_DW_ATE(0x0a, packed_decimal, 3, DWARF)
+HANDLE_DW_ATE(0x0b, numeric_string, 3, DWARF)
+HANDLE_DW_ATE(0x0c, edited, 3, DWARF)
+HANDLE_DW_ATE(0x0d, signed_fixed, 3, DWARF)
+HANDLE_DW_ATE(0x0e, unsigned_fixed, 3, DWARF)
+HANDLE_DW_ATE(0x0f, decimal_float, 3, DWARF)
+// New in DWARF v4:
+HANDLE_DW_ATE(0x10, UTF, 4, DWARF)
+// New in DWARF v5:
+HANDLE_DW_ATE(0x11, UCS, 5, DWARF)
+HANDLE_DW_ATE(0x12, ASCII, 5, DWARF)
+
+// DWARF attribute endianity
+HANDLE_DW_END(0x00, default)
+HANDLE_DW_END(0x01, big)
+HANDLE_DW_END(0x02, little)
+
+// DWARF virtuality codes.
+HANDLE_DW_VIRTUALITY(0x00, none)
+HANDLE_DW_VIRTUALITY(0x01, virtual)
+HANDLE_DW_VIRTUALITY(0x02, pure_virtual)
+
+// DWARF v5 Defaulted Member Encodings.
+HANDLE_DW_DEFAULTED(0x00, no)
+HANDLE_DW_DEFAULTED(0x01, in_class)
+HANDLE_DW_DEFAULTED(0x02, out_of_class)
+
+// DWARF calling convention codes.
+HANDLE_DW_CC(0x01, normal)
+HANDLE_DW_CC(0x02, program)
+HANDLE_DW_CC(0x03, nocall)
+// New in DWARF v5:
+HANDLE_DW_CC(0x04, pass_by_reference)
+HANDLE_DW_CC(0x05, pass_by_value)
+// Vendor extensions:
+HANDLE_DW_CC(0x40, GNU_renesas_sh)
+HANDLE_DW_CC(0x41, GNU_borland_fastcall_i386)
+HANDLE_DW_CC(0xb0, BORLAND_safecall)
+HANDLE_DW_CC(0xb1, BORLAND_stdcall)
+HANDLE_DW_CC(0xb2, BORLAND_pascal)
+HANDLE_DW_CC(0xb3, BORLAND_msfastcall)
+HANDLE_DW_CC(0xb4, BORLAND_msreturn)
+HANDLE_DW_CC(0xb5, BORLAND_thiscall)
+HANDLE_DW_CC(0xb6, BORLAND_fastcall)
+HANDLE_DW_CC(0xc0, LLVM_vectorcall)
+HANDLE_DW_CC(0xc1, LLVM_Win64)
+HANDLE_DW_CC(0xc2, LLVM_X86_64SysV)
+HANDLE_DW_CC(0xc3, LLVM_AAPCS)
+HANDLE_DW_CC(0xc4, LLVM_AAPCS_VFP)
+HANDLE_DW_CC(0xc5, LLVM_IntelOclBicc)
+HANDLE_DW_CC(0xc6, LLVM_SpirFunction)
+HANDLE_DW_CC(0xc7, LLVM_OpenCLKernel)
+HANDLE_DW_CC(0xc8, LLVM_Swift)
+HANDLE_DW_CC(0xc9, LLVM_PreserveMost)
+HANDLE_DW_CC(0xca, LLVM_PreserveAll)
+HANDLE_DW_CC(0xcb, LLVM_X86RegCall)
+// From GCC source code (include/dwarf2.h): This DW_CC_ value is not currently
+// generated by any toolchain.  It is used internally to GDB to indicate OpenCL C
+// functions that have been compiled with the IBM XL C for OpenCL compiler and use
+// a non-platform calling convention for passing OpenCL C vector types.
+HANDLE_DW_CC(0xff, GDB_IBM_OpenCL)
+
+// Line Number Extended Opcode Encodings
+HANDLE_DW_LNE(0x01, end_sequence)
+HANDLE_DW_LNE(0x02, set_address)
+HANDLE_DW_LNE(0x03, define_file)
+// New in DWARF v4:
+HANDLE_DW_LNE(0x04, set_discriminator)
+
+// Line Number Standard Opcode Encodings.
+HANDLE_DW_LNS(0x00, extended_op)
+HANDLE_DW_LNS(0x01, copy)
+HANDLE_DW_LNS(0x02, advance_pc)
+HANDLE_DW_LNS(0x03, advance_line)
+HANDLE_DW_LNS(0x04, set_file)
+HANDLE_DW_LNS(0x05, set_column)
+HANDLE_DW_LNS(0x06, negate_stmt)
+HANDLE_DW_LNS(0x07, set_basic_block)
+HANDLE_DW_LNS(0x08, const_add_pc)
+HANDLE_DW_LNS(0x09, fixed_advance_pc)
+// New in DWARF v3:
+HANDLE_DW_LNS(0x0a, set_prologue_end)
+HANDLE_DW_LNS(0x0b, set_epilogue_begin)
+HANDLE_DW_LNS(0x0c, set_isa)
+
+// DWARF v5 Line number header entry format.
+HANDLE_DW_LNCT(0x01, path)
+HANDLE_DW_LNCT(0x02, directory_index)
+HANDLE_DW_LNCT(0x03, timestamp)
+HANDLE_DW_LNCT(0x04, size)
+HANDLE_DW_LNCT(0x05, MD5)
+// A vendor extension until http://dwarfstd.org/ShowIssue.php?issue=180201.1 is
+// accepted and incorporated into the next DWARF standard.
+HANDLE_DW_LNCT(0x2001, LLVM_source)
+
+// DWARF v5 Macro information.
+HANDLE_DW_MACRO(0x01, define)
+HANDLE_DW_MACRO(0x02, undef)
+HANDLE_DW_MACRO(0x03, start_file)
+HANDLE_DW_MACRO(0x04, end_file)
+HANDLE_DW_MACRO(0x05, define_strp)
+HANDLE_DW_MACRO(0x06, undef_strp)
+HANDLE_DW_MACRO(0x07, import)
+HANDLE_DW_MACRO(0x08, define_sup)
+HANDLE_DW_MACRO(0x09, undef_sup)
+HANDLE_DW_MACRO(0x0a, import_sup)
+HANDLE_DW_MACRO(0x0b, define_strx)
+HANDLE_DW_MACRO(0x0c, undef_strx)
+
+// DWARF v5 Range List Entry encoding values.
+HANDLE_DW_RLE(0x00, end_of_list)
+HANDLE_DW_RLE(0x01, base_addressx)
+HANDLE_DW_RLE(0x02, startx_endx)
+HANDLE_DW_RLE(0x03, startx_length)
+HANDLE_DW_RLE(0x04, offset_pair)
+HANDLE_DW_RLE(0x05, base_address)
+HANDLE_DW_RLE(0x06, start_end)
+HANDLE_DW_RLE(0x07, start_length)
+
+// DWARF v5 Loc List Entry encoding values.
+HANDLE_DW_LLE(0x00, end_of_list)
+HANDLE_DW_LLE(0x01, base_addressx)
+HANDLE_DW_LLE(0x02, startx_endx)
+HANDLE_DW_LLE(0x03, startx_length)
+HANDLE_DW_LLE(0x04, offset_pair)
+HANDLE_DW_LLE(0x05, default_location)
+HANDLE_DW_LLE(0x06, base_address)
+HANDLE_DW_LLE(0x07, start_end)
+HANDLE_DW_LLE(0x08, start_length)
+
+// Call frame instruction encodings.
+HANDLE_DW_CFA(0x00, nop)
+HANDLE_DW_CFA(0x40, advance_loc)
+HANDLE_DW_CFA(0x80, offset)
+HANDLE_DW_CFA(0xc0, restore)
+HANDLE_DW_CFA(0x01, set_loc)
+HANDLE_DW_CFA(0x02, advance_loc1)
+HANDLE_DW_CFA(0x03, advance_loc2)
+HANDLE_DW_CFA(0x04, advance_loc4)
+HANDLE_DW_CFA(0x05, offset_extended)
+HANDLE_DW_CFA(0x06, restore_extended)
+HANDLE_DW_CFA(0x07, undefined)
+HANDLE_DW_CFA(0x08, same_value)
+HANDLE_DW_CFA(0x09, register)
+HANDLE_DW_CFA(0x0a, remember_state)
+HANDLE_DW_CFA(0x0b, restore_state)
+HANDLE_DW_CFA(0x0c, def_cfa)
+HANDLE_DW_CFA(0x0d, def_cfa_register)
+HANDLE_DW_CFA(0x0e, def_cfa_offset)
+// New in DWARF v3:
+HANDLE_DW_CFA(0x0f, def_cfa_expression)
+HANDLE_DW_CFA(0x10, expression)
+HANDLE_DW_CFA(0x11, offset_extended_sf)
+HANDLE_DW_CFA(0x12, def_cfa_sf)
+HANDLE_DW_CFA(0x13, def_cfa_offset_sf)
+HANDLE_DW_CFA(0x14, val_offset)
+HANDLE_DW_CFA(0x15, val_offset_sf)
+HANDLE_DW_CFA(0x16, val_expression)
+// Vendor extensions:
+HANDLE_DW_CFA_PRED(0x1d, MIPS_advance_loc8, SELECT_MIPS64)
+HANDLE_DW_CFA_PRED(0x2d, GNU_window_save, SELECT_SPARC)
+HANDLE_DW_CFA_PRED(0x2d, AARCH64_negate_ra_state, SELECT_AARCH64)
+HANDLE_DW_CFA_PRED(0x2e, GNU_args_size, SELECT_X86)
+
+// Apple Objective-C Property Attributes.
+// Keep this list in sync with clang's DeclSpec.h ObjCPropertyAttributeKind!
+HANDLE_DW_APPLE_PROPERTY(0x01, readonly)
+HANDLE_DW_APPLE_PROPERTY(0x02, getter)
+HANDLE_DW_APPLE_PROPERTY(0x04, assign)
+HANDLE_DW_APPLE_PROPERTY(0x08, readwrite)
+HANDLE_DW_APPLE_PROPERTY(0x10, retain)
+HANDLE_DW_APPLE_PROPERTY(0x20, copy)
+HANDLE_DW_APPLE_PROPERTY(0x40, nonatomic)
+HANDLE_DW_APPLE_PROPERTY(0x80, setter)
+HANDLE_DW_APPLE_PROPERTY(0x100, atomic)
+HANDLE_DW_APPLE_PROPERTY(0x200, weak)
+HANDLE_DW_APPLE_PROPERTY(0x400, strong)
+HANDLE_DW_APPLE_PROPERTY(0x800, unsafe_unretained)
+HANDLE_DW_APPLE_PROPERTY(0x1000, nullability)
+HANDLE_DW_APPLE_PROPERTY(0x2000, null_resettable)
+HANDLE_DW_APPLE_PROPERTY(0x4000, class)
+
+// DWARF v5 Unit Types.
+HANDLE_DW_UT(0x01, compile)
+HANDLE_DW_UT(0x02, type)
+HANDLE_DW_UT(0x03, partial)
+HANDLE_DW_UT(0x04, skeleton)
+HANDLE_DW_UT(0x05, split_compile)
+HANDLE_DW_UT(0x06, split_type)
+
+// DWARF section types. (enum name, ELF name, ELF DWO name, cmdline name)
+// Note that these IDs don't mean anything.
+// TODO: Add Mach-O and COFF names.
+// Official DWARF sections.
+HANDLE_DWARF_SECTION(DebugAbbrev, ".debug_abbrev", "debug-abbrev")
+HANDLE_DWARF_SECTION(DebugAddr, ".debug_addr", "debug-addr")
+HANDLE_DWARF_SECTION(DebugAranges, ".debug_aranges", "debug-aranges")
+HANDLE_DWARF_SECTION(DebugInfo, ".debug_info", "debug-info")
+HANDLE_DWARF_SECTION(DebugTypes, ".debug_types", "debug-types")
+HANDLE_DWARF_SECTION(DebugLine, ".debug_line", "debug-line")
+HANDLE_DWARF_SECTION(DebugLineStr, ".debug_line_str", "debug-line-str")
+HANDLE_DWARF_SECTION(DebugLoc, ".debug_loc", "debug-loc")
+HANDLE_DWARF_SECTION(DebugLoclists, ".debug_loclists", "debug-loclists")
+HANDLE_DWARF_SECTION(DebugFrame, ".debug_frame", "debug-frame")
+HANDLE_DWARF_SECTION(DebugMacro, ".debug_macro", "debug-macro")
+HANDLE_DWARF_SECTION(DebugNames, ".debug_names", "debug-names")
+HANDLE_DWARF_SECTION(DebugPubnames, ".debug_pubnames", "debug-pubnames")
+HANDLE_DWARF_SECTION(DebugPubtypes, ".debug_pubtypes", "debug-pubtypes")
+HANDLE_DWARF_SECTION(DebugGnuPubnames, ".debug_gnu_pubnames", "debug-gnu-pubnames")
+HANDLE_DWARF_SECTION(DebugGnuPubtypes, ".debug_gnu_pubtypes", "debug-gnu-pubtypes")
+HANDLE_DWARF_SECTION(DebugRanges, ".debug_ranges", "debug-ranges")
+HANDLE_DWARF_SECTION(DebugRnglists, ".debug_rnglists", "debug-rnglists")
+HANDLE_DWARF_SECTION(DebugStr, ".debug_str", "debug-str")
+HANDLE_DWARF_SECTION(DebugStrOffsets, ".debug_str_offsets", "debug-str-offsets")
+HANDLE_DWARF_SECTION(DebugCUIndex, ".debug_cu_index", "debug-cu-index")
+HANDLE_DWARF_SECTION(DebugTUIndex, ".debug_tu_index", "debug-tu-index")
+// Vendor extensions.
+HANDLE_DWARF_SECTION(AppleNames, ".apple_names", "apple-names")
+HANDLE_DWARF_SECTION(AppleTypes, ".apple_types", "apple-types")
+HANDLE_DWARF_SECTION(AppleNamespaces, ".apple_namespaces", "apple-namespaces")
+HANDLE_DWARF_SECTION(AppleObjC, ".apple_objc", "apple-objc")
+HANDLE_DWARF_SECTION(GdbIndex, ".gdb_index", "gdb-index")
+
+HANDLE_DW_IDX(0x01, compile_unit)
+HANDLE_DW_IDX(0x02, type_unit)
+HANDLE_DW_IDX(0x03, die_offset)
+HANDLE_DW_IDX(0x04, parent)
+HANDLE_DW_IDX(0x05, type_hash)
+
+
+#undef HANDLE_DW_TAG
+#undef HANDLE_DW_AT
+#undef HANDLE_DW_FORM
+#undef HANDLE_DW_OP
+#undef HANDLE_DW_LANG
+#undef HANDLE_DW_ATE
+#undef HANDLE_DW_VIRTUALITY
+#undef HANDLE_DW_DEFAULTED
+#undef HANDLE_DW_CC
+#undef HANDLE_DW_LNS
+#undef HANDLE_DW_LNE
+#undef HANDLE_DW_LNCT
+#undef HANDLE_DW_MACRO
+#undef HANDLE_DW_RLE
+#undef HANDLE_DW_LLE
+#undef HANDLE_DW_CFA
+#undef HANDLE_DW_CFA_PRED
+#undef HANDLE_DW_APPLE_PROPERTY
+#undef HANDLE_DW_UT
+#undef HANDLE_DWARF_SECTION
+#undef HANDLE_DW_IDX
+#undef HANDLE_DW_END
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Dwarf.h b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Dwarf.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Dwarf.h
@@ -0,0 +1,678 @@
+//===-- llvm/BinaryFormat/Dwarf.h ---Dwarf Constants-------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// This file contains constants used for implementing Dwarf
+/// debug support.
+///
+/// For details on the Dwarf specfication see the latest DWARF Debugging
+/// Information Format standard document on http://www.dwarfstd.org. This
+/// file often includes support for non-released standard features.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BINARYFORMAT_DWARF_H
+#define LLVM_BINARYFORMAT_DWARF_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadicDetails.h"
+#include "llvm/ADT/Triple.h"
+
+namespace llvm {
+class StringRef;
+
+namespace dwarf {
+
+//===----------------------------------------------------------------------===//
+// DWARF constants as gleaned from the DWARF Debugging Information Format V.5
+// reference manual http://www.dwarfstd.org/.
+//
+
+// Do not mix the following two enumerations sets.  DW_TAG_invalid changes the
+// enumeration base type.
+
+enum LLVMConstants : uint32_t {
+  // LLVM mock tags (see also llvm/BinaryFormat/Dwarf.def).
+  DW_TAG_invalid = ~0U,        // Tag for invalid results.
+  DW_VIRTUALITY_invalid = ~0U, // Virtuality for invalid results.
+  DW_MACINFO_invalid = ~0U,    // Macinfo type for invalid results.
+
+  // Special values for an initial length field.
+  DW_LENGTH_lo_reserved = 0xfffffff0, // Lower bound of the reserved range.
+  DW_LENGTH_DWARF64 = 0xffffffff,     // Indicator of 64-bit DWARF format.
+  DW_LENGTH_hi_reserved = 0xffffffff, // Upper bound of the reserved range.
+
+  // Other constants.
+  DWARF_VERSION = 4,       // Default dwarf version we output.
+  DW_PUBTYPES_VERSION = 2, // Section version number for .debug_pubtypes.
+  DW_PUBNAMES_VERSION = 2, // Section version number for .debug_pubnames.
+  DW_ARANGES_VERSION = 2,  // Section version number for .debug_aranges.
+  // Identifiers we use to distinguish vendor extensions.
+  DWARF_VENDOR_DWARF = 0, // Defined in v2 or later of the DWARF standard.
+  DWARF_VENDOR_APPLE = 1,
+  DWARF_VENDOR_BORLAND = 2,
+  DWARF_VENDOR_GNU = 3,
+  DWARF_VENDOR_GOOGLE = 4,
+  DWARF_VENDOR_LLVM = 5,
+  DWARF_VENDOR_MIPS = 6,
+  DWARF_VENDOR_WASM = 7
+};
+
+/// Constants that define the DWARF format as 32 or 64 bit.
+enum DwarfFormat : uint8_t { DWARF32, DWARF64 };
+
+/// Special ID values that distinguish a CIE from a FDE in DWARF CFI.
+/// Not inside an enum because a 64-bit value is needed.
+/// @{
+const uint32_t DW_CIE_ID = UINT32_MAX;
+const uint64_t DW64_CIE_ID = UINT64_MAX;
+/// @}
+
+/// Identifier of an invalid DIE offset in the .debug_info section.
+const uint32_t DW_INVALID_OFFSET = UINT32_MAX;
+
+enum Tag : uint16_t {
+#define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR, KIND) DW_TAG_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_TAG_lo_user = 0x4080,
+  DW_TAG_hi_user = 0xffff,
+  DW_TAG_user_base = 0x1000 ///< Recommended base for user tags.
+};
+
+inline bool isType(Tag T) {
+  switch (T) {
+  default:
+    return false;
+#define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR, KIND)                         \
+  case DW_TAG_##NAME:                                                          \
+    return (KIND == DW_KIND_TYPE);
+#include "llvm/BinaryFormat/Dwarf.def"
+  }
+}
+
+/// Attributes.
+enum Attribute : uint16_t {
+#define HANDLE_DW_AT(ID, NAME, VERSION, VENDOR) DW_AT_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_AT_lo_user = 0x2000,
+  DW_AT_hi_user = 0x3fff,
+};
+
+enum Form : uint16_t {
+#define HANDLE_DW_FORM(ID, NAME, VERSION, VENDOR) DW_FORM_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_FORM_lo_user = 0x1f00, ///< Not specified by DWARF.
+};
+
+enum LocationAtom {
+#define HANDLE_DW_OP(ID, NAME, VERSION, VENDOR) DW_OP_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_OP_lo_user = 0xe0,
+  DW_OP_hi_user = 0xff,
+  DW_OP_LLVM_fragment = 0x1000,    ///< Only used in LLVM metadata.
+  DW_OP_LLVM_convert = 0x1001,     ///< Only used in LLVM metadata.
+  DW_OP_LLVM_tag_offset = 0x1002,  ///< Only used in LLVM metadata.
+  DW_OP_LLVM_entry_value = 0x1003, ///< Only used in LLVM metadata.
+};
+
+enum TypeKind : uint8_t {
+#define HANDLE_DW_ATE(ID, NAME, VERSION, VENDOR) DW_ATE_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_ATE_lo_user = 0x80,
+  DW_ATE_hi_user = 0xff
+};
+
+enum DecimalSignEncoding {
+  // Decimal sign attribute values
+  DW_DS_unsigned = 0x01,
+  DW_DS_leading_overpunch = 0x02,
+  DW_DS_trailing_overpunch = 0x03,
+  DW_DS_leading_separate = 0x04,
+  DW_DS_trailing_separate = 0x05
+};
+
+enum EndianityEncoding {
+  // Endianity attribute values
+#define HANDLE_DW_END(ID, NAME) DW_END_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_END_lo_user = 0x40,
+  DW_END_hi_user = 0xff
+};
+
+enum AccessAttribute {
+  // Accessibility codes
+  DW_ACCESS_public = 0x01,
+  DW_ACCESS_protected = 0x02,
+  DW_ACCESS_private = 0x03
+};
+
+enum VisibilityAttribute {
+  // Visibility codes
+  DW_VIS_local = 0x01,
+  DW_VIS_exported = 0x02,
+  DW_VIS_qualified = 0x03
+};
+
+enum VirtualityAttribute {
+#define HANDLE_DW_VIRTUALITY(ID, NAME) DW_VIRTUALITY_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_VIRTUALITY_max = 0x02
+};
+
+enum DefaultedMemberAttribute {
+#define HANDLE_DW_DEFAULTED(ID, NAME) DW_DEFAULTED_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_DEFAULTED_max = 0x02
+};
+
+enum SourceLanguage {
+#define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR)                 \
+  DW_LANG_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_LANG_lo_user = 0x8000,
+  DW_LANG_hi_user = 0xffff
+};
+
+inline bool isCPlusPlus(SourceLanguage S) {
+  // Deliberately enumerate all the language options so we get a warning when
+  // new language options are added (-Wswitch) that'll hopefully help keep this
+  // switch up-to-date when new C++ versions are added.
+  switch (S) {
+  case DW_LANG_C_plus_plus:
+  case DW_LANG_C_plus_plus_03:
+  case DW_LANG_C_plus_plus_11:
+  case DW_LANG_C_plus_plus_14:
+    return true;
+  case DW_LANG_C89:
+  case DW_LANG_C:
+  case DW_LANG_Ada83:
+  case DW_LANG_Cobol74:
+  case DW_LANG_Cobol85:
+  case DW_LANG_Fortran77:
+  case DW_LANG_Fortran90:
+  case DW_LANG_Pascal83:
+  case DW_LANG_Modula2:
+  case DW_LANG_Java:
+  case DW_LANG_C99:
+  case DW_LANG_Ada95:
+  case DW_LANG_Fortran95:
+  case DW_LANG_PLI:
+  case DW_LANG_ObjC:
+  case DW_LANG_ObjC_plus_plus:
+  case DW_LANG_UPC:
+  case DW_LANG_D:
+  case DW_LANG_Python:
+  case DW_LANG_OpenCL:
+  case DW_LANG_Go:
+  case DW_LANG_Modula3:
+  case DW_LANG_Haskell:
+  case DW_LANG_OCaml:
+  case DW_LANG_Rust:
+  case DW_LANG_C11:
+  case DW_LANG_Swift:
+  case DW_LANG_Julia:
+  case DW_LANG_Dylan:
+  case DW_LANG_Fortran03:
+  case DW_LANG_Fortran08:
+  case DW_LANG_RenderScript:
+  case DW_LANG_BLISS:
+  case DW_LANG_Mips_Assembler:
+  case DW_LANG_GOOGLE_RenderScript:
+  case DW_LANG_BORLAND_Delphi:
+  case DW_LANG_lo_user:
+  case DW_LANG_hi_user:
+    return false;
+  }
+  llvm_unreachable("Invalid source language");
+}
+
+enum CaseSensitivity {
+  // Identifier case codes
+  DW_ID_case_sensitive = 0x00,
+  DW_ID_up_case = 0x01,
+  DW_ID_down_case = 0x02,
+  DW_ID_case_insensitive = 0x03
+};
+
+enum CallingConvention {
+// Calling convention codes
+#define HANDLE_DW_CC(ID, NAME) DW_CC_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_CC_lo_user = 0x40,
+  DW_CC_hi_user = 0xff
+};
+
+enum InlineAttribute {
+  // Inline codes
+  DW_INL_not_inlined = 0x00,
+  DW_INL_inlined = 0x01,
+  DW_INL_declared_not_inlined = 0x02,
+  DW_INL_declared_inlined = 0x03
+};
+
+enum ArrayDimensionOrdering {
+  // Array ordering
+  DW_ORD_row_major = 0x00,
+  DW_ORD_col_major = 0x01
+};
+
+enum DiscriminantList {
+  // Discriminant descriptor values
+  DW_DSC_label = 0x00,
+  DW_DSC_range = 0x01
+};
+
+/// Line Number Standard Opcode Encodings.
+enum LineNumberOps : uint8_t {
+#define HANDLE_DW_LNS(ID, NAME) DW_LNS_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+};
+
+/// Line Number Extended Opcode Encodings.
+enum LineNumberExtendedOps {
+#define HANDLE_DW_LNE(ID, NAME) DW_LNE_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_LNE_lo_user = 0x80,
+  DW_LNE_hi_user = 0xff
+};
+
+enum LineNumberEntryFormat {
+#define HANDLE_DW_LNCT(ID, NAME) DW_LNCT_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_LNCT_lo_user = 0x2000,
+  DW_LNCT_hi_user = 0x3fff,
+};
+
+enum MacinfoRecordType {
+  // Macinfo Type Encodings
+  DW_MACINFO_define = 0x01,
+  DW_MACINFO_undef = 0x02,
+  DW_MACINFO_start_file = 0x03,
+  DW_MACINFO_end_file = 0x04,
+  DW_MACINFO_vendor_ext = 0xff
+};
+
+/// DWARF v5 macro information entry type encodings.
+enum MacroEntryType {
+#define HANDLE_DW_MACRO(ID, NAME) DW_MACRO_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_MACRO_lo_user = 0xe0,
+  DW_MACRO_hi_user = 0xff
+};
+
+/// DWARF v5 range list entry encoding values.
+enum RnglistEntries {
+#define HANDLE_DW_RLE(ID, NAME) DW_RLE_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+};
+
+/// DWARF v5 loc list entry encoding values.
+enum LoclistEntries {
+#define HANDLE_DW_LLE(ID, NAME) DW_LLE_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+};
+
+/// Call frame instruction encodings.
+enum CallFrameInfo {
+#define HANDLE_DW_CFA(ID, NAME) DW_CFA_##NAME = ID,
+#define HANDLE_DW_CFA_PRED(ID, NAME, ARCH) DW_CFA_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_CFA_extended = 0x00,
+
+  DW_CFA_lo_user = 0x1c,
+  DW_CFA_hi_user = 0x3f
+};
+
+enum Constants {
+  // Children flag
+  DW_CHILDREN_no = 0x00,
+  DW_CHILDREN_yes = 0x01,
+
+  DW_EH_PE_absptr = 0x00,
+  DW_EH_PE_omit = 0xff,
+  DW_EH_PE_uleb128 = 0x01,
+  DW_EH_PE_udata2 = 0x02,
+  DW_EH_PE_udata4 = 0x03,
+  DW_EH_PE_udata8 = 0x04,
+  DW_EH_PE_sleb128 = 0x09,
+  DW_EH_PE_sdata2 = 0x0A,
+  DW_EH_PE_sdata4 = 0x0B,
+  DW_EH_PE_sdata8 = 0x0C,
+  DW_EH_PE_signed = 0x08,
+  DW_EH_PE_pcrel = 0x10,
+  DW_EH_PE_textrel = 0x20,
+  DW_EH_PE_datarel = 0x30,
+  DW_EH_PE_funcrel = 0x40,
+  DW_EH_PE_aligned = 0x50,
+  DW_EH_PE_indirect = 0x80
+};
+
+/// Constants for the DW_APPLE_PROPERTY_attributes attribute.
+/// Keep this list in sync with clang's DeclSpec.h ObjCPropertyAttributeKind!
+enum ApplePropertyAttributes {
+#define HANDLE_DW_APPLE_PROPERTY(ID, NAME) DW_APPLE_PROPERTY_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+};
+
+/// Constants for unit types in DWARF v5.
+enum UnitType : unsigned char {
+#define HANDLE_DW_UT(ID, NAME) DW_UT_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_UT_lo_user = 0x80,
+  DW_UT_hi_user = 0xff
+};
+
+enum Index {
+#define HANDLE_DW_IDX(ID, NAME) DW_IDX_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  DW_IDX_lo_user = 0x2000,
+  DW_IDX_hi_user = 0x3fff
+};
+
+inline bool isUnitType(uint8_t UnitType) {
+  switch (UnitType) {
+  case DW_UT_compile:
+  case DW_UT_type:
+  case DW_UT_partial:
+  case DW_UT_skeleton:
+  case DW_UT_split_compile:
+  case DW_UT_split_type:
+    return true;
+  default:
+    return false;
+  }
+}
+
+inline bool isUnitType(dwarf::Tag T) {
+  switch (T) {
+  case DW_TAG_compile_unit:
+  case DW_TAG_type_unit:
+  case DW_TAG_partial_unit:
+  case DW_TAG_skeleton_unit:
+    return true;
+  default:
+    return false;
+  }
+}
+
+// Constants for the DWARF v5 Accelerator Table Proposal
+enum AcceleratorTable {
+  // Data layout descriptors.
+  DW_ATOM_null = 0u,       ///  Marker as the end of a list of atoms.
+  DW_ATOM_die_offset = 1u, // DIE offset in the debug_info section.
+  DW_ATOM_cu_offset = 2u, // Offset of the compile unit header that contains the
+                          // item in question.
+  DW_ATOM_die_tag = 3u,   // A tag entry.
+  DW_ATOM_type_flags = 4u, // Set of flags for a type.
+
+  DW_ATOM_type_type_flags = 5u, // Dsymutil type extension.
+  DW_ATOM_qual_name_hash = 6u,  // Dsymutil qualified hash extension.
+
+  // DW_ATOM_type_flags values.
+
+  // Always set for C++, only set for ObjC if this is the @implementation for a
+  // class.
+  DW_FLAG_type_implementation = 2u,
+
+  // Hash functions.
+
+  // Daniel J. Bernstein hash.
+  DW_hash_function_djb = 0u
+};
+
+// Constants for the GNU pubnames/pubtypes extensions supporting gdb index.
+enum GDBIndexEntryKind {
+  GIEK_NONE,
+  GIEK_TYPE,
+  GIEK_VARIABLE,
+  GIEK_FUNCTION,
+  GIEK_OTHER,
+  GIEK_UNUSED5,
+  GIEK_UNUSED6,
+  GIEK_UNUSED7
+};
+
+enum GDBIndexEntryLinkage { GIEL_EXTERNAL, GIEL_STATIC };
+
+/// \defgroup DwarfConstantsDumping Dwarf constants dumping functions
+///
+/// All these functions map their argument's value back to the
+/// corresponding enumerator name or return an empty StringRef if the value
+/// isn't known.
+///
+/// @{
+StringRef TagString(unsigned Tag);
+StringRef ChildrenString(unsigned Children);
+StringRef AttributeString(unsigned Attribute);
+StringRef FormEncodingString(unsigned Encoding);
+StringRef OperationEncodingString(unsigned Encoding);
+StringRef AttributeEncodingString(unsigned Encoding);
+StringRef DecimalSignString(unsigned Sign);
+StringRef EndianityString(unsigned Endian);
+StringRef AccessibilityString(unsigned Access);
+StringRef DefaultedMemberString(unsigned DefaultedEncodings);
+StringRef VisibilityString(unsigned Visibility);
+StringRef VirtualityString(unsigned Virtuality);
+StringRef LanguageString(unsigned Language);
+StringRef CaseString(unsigned Case);
+StringRef ConventionString(unsigned Convention);
+StringRef InlineCodeString(unsigned Code);
+StringRef ArrayOrderString(unsigned Order);
+StringRef LNStandardString(unsigned Standard);
+StringRef LNExtendedString(unsigned Encoding);
+StringRef MacinfoString(unsigned Encoding);
+StringRef RangeListEncodingString(unsigned Encoding);
+StringRef LocListEncodingString(unsigned Encoding);
+StringRef CallFrameString(unsigned Encoding, Triple::ArchType Arch);
+StringRef ApplePropertyString(unsigned);
+StringRef UnitTypeString(unsigned);
+StringRef AtomTypeString(unsigned Atom);
+StringRef GDBIndexEntryKindString(GDBIndexEntryKind Kind);
+StringRef GDBIndexEntryLinkageString(GDBIndexEntryLinkage Linkage);
+StringRef IndexString(unsigned Idx);
+/// @}
+
+/// \defgroup DwarfConstantsParsing Dwarf constants parsing functions
+///
+/// These functions map their strings back to the corresponding enumeration
+/// value or return 0 if there is none, except for these exceptions:
+///
+/// \li \a getTag() returns \a DW_TAG_invalid on invalid input.
+/// \li \a getVirtuality() returns \a DW_VIRTUALITY_invalid on invalid input.
+/// \li \a getMacinfo() returns \a DW_MACINFO_invalid on invalid input.
+///
+/// @{
+unsigned getTag(StringRef TagString);
+unsigned getOperationEncoding(StringRef OperationEncodingString);
+unsigned getVirtuality(StringRef VirtualityString);
+unsigned getLanguage(StringRef LanguageString);
+unsigned getCallingConvention(StringRef LanguageString);
+unsigned getAttributeEncoding(StringRef EncodingString);
+unsigned getMacinfo(StringRef MacinfoString);
+/// @}
+
+/// \defgroup DwarfConstantsVersioning Dwarf version for constants
+///
+/// For constants defined by DWARF, returns the DWARF version when the constant
+/// was first defined. For vendor extensions, if there is a version-related
+/// policy for when to emit it, returns a version number for that policy.
+/// Otherwise returns 0.
+///
+/// @{
+unsigned TagVersion(Tag T);
+unsigned AttributeVersion(Attribute A);
+unsigned FormVersion(Form F);
+unsigned OperationVersion(LocationAtom O);
+unsigned AttributeEncodingVersion(TypeKind E);
+unsigned LanguageVersion(SourceLanguage L);
+/// @}
+
+/// \defgroup DwarfConstantsVendor Dwarf "vendor" for constants
+///
+/// These functions return an identifier describing "who" defined the constant,
+/// either the DWARF standard itself or the vendor who defined the extension.
+///
+/// @{
+unsigned TagVendor(Tag T);
+unsigned AttributeVendor(Attribute A);
+unsigned FormVendor(Form F);
+unsigned OperationVendor(LocationAtom O);
+unsigned AttributeEncodingVendor(TypeKind E);
+unsigned LanguageVendor(SourceLanguage L);
+/// @}
+
+Optional<unsigned> LanguageLowerBound(SourceLanguage L);
+
+/// A helper struct providing information about the byte size of DW_FORM
+/// values that vary in size depending on the DWARF version, address byte
+/// size, or DWARF32/DWARF64.
+struct FormParams {
+  uint16_t Version;
+  uint8_t AddrSize;
+  DwarfFormat Format;
+
+  /// The definition of the size of form DW_FORM_ref_addr depends on the
+  /// version. In DWARF v2 it's the size of an address; after that, it's the
+  /// size of a reference.
+  uint8_t getRefAddrByteSize() const {
+    if (Version == 2)
+      return AddrSize;
+    return getDwarfOffsetByteSize();
+  }
+
+  /// The size of a reference is determined by the DWARF 32/64-bit format.
+  uint8_t getDwarfOffsetByteSize() const {
+    switch (Format) {
+    case DwarfFormat::DWARF32:
+      return 4;
+    case DwarfFormat::DWARF64:
+      return 8;
+    }
+    llvm_unreachable("Invalid Format value");
+  }
+
+  explicit operator bool() const { return Version && AddrSize; }
+};
+
+/// Get the byte size of the unit length field depending on the DWARF format.
+inline uint8_t getUnitLengthFieldByteSize(DwarfFormat Format) {
+  switch (Format) {
+  case DwarfFormat::DWARF32:
+    return 4;
+  case DwarfFormat::DWARF64:
+    return 12;
+  }
+  llvm_unreachable("Invalid Format value");
+}
+
+/// Get the fixed byte size for a given form.
+///
+/// If the form has a fixed byte size, then an Optional with a value will be
+/// returned. If the form is always encoded using a variable length storage
+/// format (ULEB or SLEB numbers or blocks) then None will be returned.
+///
+/// \param Form DWARF form to get the fixed byte size for.
+/// \param Params DWARF parameters to help interpret forms.
+/// \returns Optional<uint8_t> value with the fixed byte size or None if
+/// \p Form doesn't have a fixed byte size.
+Optional<uint8_t> getFixedFormByteSize(dwarf::Form Form, FormParams Params);
+
+/// Tells whether the specified form is defined in the specified version,
+/// or is an extension if extensions are allowed.
+bool isValidFormForVersion(Form F, unsigned Version, bool ExtensionsOk = true);
+
+/// Returns the symbolic string representing Val when used as a value
+/// for attribute Attr.
+StringRef AttributeValueString(uint16_t Attr, unsigned Val);
+
+/// Returns the symbolic string representing Val when used as a value
+/// for atom Atom.
+StringRef AtomValueString(uint16_t Atom, unsigned Val);
+
+/// Describes an entry of the various gnu_pub* debug sections.
+///
+/// The gnu_pub* kind looks like:
+///
+/// 0-3  reserved
+/// 4-6  symbol kind
+/// 7    0 == global, 1 == static
+///
+/// A gdb_index descriptor includes the above kind, shifted 24 bits up with the
+/// offset of the cu within the debug_info section stored in those 24 bits.
+struct PubIndexEntryDescriptor {
+  GDBIndexEntryKind Kind;
+  GDBIndexEntryLinkage Linkage;
+  PubIndexEntryDescriptor(GDBIndexEntryKind Kind, GDBIndexEntryLinkage Linkage)
+      : Kind(Kind), Linkage(Linkage) {}
+  /* implicit */ PubIndexEntryDescriptor(GDBIndexEntryKind Kind)
+      : Kind(Kind), Linkage(GIEL_EXTERNAL) {}
+  explicit PubIndexEntryDescriptor(uint8_t Value)
+      : Kind(
+            static_cast<GDBIndexEntryKind>((Value & KIND_MASK) >> KIND_OFFSET)),
+        Linkage(static_cast<GDBIndexEntryLinkage>((Value & LINKAGE_MASK) >>
+                                                  LINKAGE_OFFSET)) {}
+  uint8_t toBits() const {
+    return Kind << KIND_OFFSET | Linkage << LINKAGE_OFFSET;
+  }
+
+private:
+  enum {
+    KIND_OFFSET = 4,
+    KIND_MASK = 7 << KIND_OFFSET,
+    LINKAGE_OFFSET = 7,
+    LINKAGE_MASK = 1 << LINKAGE_OFFSET
+  };
+};
+
+template <typename Enum> struct EnumTraits : public std::false_type {};
+
+template <> struct EnumTraits<Attribute> : public std::true_type {
+  static constexpr char Type[3] = "AT";
+  static constexpr StringRef (*StringFn)(unsigned) = &AttributeString;
+};
+
+template <> struct EnumTraits<Form> : public std::true_type {
+  static constexpr char Type[5] = "FORM";
+  static constexpr StringRef (*StringFn)(unsigned) = &FormEncodingString;
+};
+
+template <> struct EnumTraits<Index> : public std::true_type {
+  static constexpr char Type[4] = "IDX";
+  static constexpr StringRef (*StringFn)(unsigned) = &IndexString;
+};
+
+template <> struct EnumTraits<Tag> : public std::true_type {
+  static constexpr char Type[4] = "TAG";
+  static constexpr StringRef (*StringFn)(unsigned) = &TagString;
+};
+} // End of namespace dwarf
+
+/// Dwarf constants format_provider
+///
+/// Specialization of the format_provider template for dwarf enums. Unlike the
+/// dumping functions above, these format unknown enumerator values as
+/// DW_TYPE_unknown_1234 (e.g. DW_TAG_unknown_ffff).
+template <typename Enum>
+struct format_provider<
+    Enum, typename std::enable_if<dwarf::EnumTraits<Enum>::value>::type> {
+  static void format(const Enum &E, raw_ostream &OS, StringRef Style) {
+    StringRef Str = dwarf::EnumTraits<Enum>::StringFn(E);
+    if (Str.empty()) {
+      OS << "DW_" << dwarf::EnumTraits<Enum>::Type << "_unknown_"
+         << llvm::format("%x", E);
+    } else
+      OS << Str;
+  }
+};
+} // End of namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/DynamicTags.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/DynamicTags.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/DynamicTags.def
@@ -0,0 +1,244 @@
+#ifndef DYNAMIC_TAG
+#error "DYNAMIC_TAG must be defined"
+#endif
+
+// Add separate macros for the architecture specific tags and the markers
+// such as DT_HIOS, etc. to allow using this file to in other contexts.
+// For example we can use it to generate a stringification switch statement.
+
+#ifndef AARCH64_DYNAMIC_TAG
+#define AARCH64_DYNAMIC_TAG(name, value) DYNAMIC_TAG(name, value)
+#define AARCH64_DYNAMIC_TAG_DEFINED
+#endif
+
+#ifndef HEXAGON_DYNAMIC_TAG
+#define HEXAGON_DYNAMIC_TAG(name, value) DYNAMIC_TAG(name, value)
+#define HEXAGON_DYNAMIC_TAG_DEFINED
+#endif
+
+#ifndef MIPS_DYNAMIC_TAG
+#define MIPS_DYNAMIC_TAG(name, value) DYNAMIC_TAG(name, value)
+#define MIPS_DYNAMIC_TAG_DEFINED
+#endif
+
+#ifndef PPC_DYNAMIC_TAG
+#define PPC_DYNAMIC_TAG(name, value) DYNAMIC_TAG(name, value)
+#define PPC_DYNAMIC_TAG_DEFINED
+#endif
+
+#ifndef PPC64_DYNAMIC_TAG
+#define PPC64_DYNAMIC_TAG(name, value) DYNAMIC_TAG(name, value)
+#define PPC64_DYNAMIC_TAG_DEFINED
+#endif
+
+#ifndef DYNAMIC_TAG_MARKER
+#define DYNAMIC_TAG_MARKER(name, value) DYNAMIC_TAG(name, value)
+#define DYNAMIC_TAG_MARKER_DEFINED
+#endif
+
+DYNAMIC_TAG(NULL, 0)        // Marks end of dynamic array.
+DYNAMIC_TAG(NEEDED, 1)      // String table offset of needed library.
+DYNAMIC_TAG(PLTRELSZ, 2)    // Size of relocation entries in PLT.
+DYNAMIC_TAG(PLTGOT, 3)      // Address associated with linkage table.
+DYNAMIC_TAG(HASH, 4)        // Address of symbolic hash table.
+DYNAMIC_TAG(STRTAB, 5)      // Address of dynamic string table.
+DYNAMIC_TAG(SYMTAB, 6)      // Address of dynamic symbol table.
+DYNAMIC_TAG(RELA, 7)        // Address of relocation table (Rela entries).
+DYNAMIC_TAG(RELASZ, 8)      // Size of Rela relocation table.
+DYNAMIC_TAG(RELAENT, 9)     // Size of a Rela relocation entry.
+DYNAMIC_TAG(STRSZ, 10)      // Total size of the string table.
+DYNAMIC_TAG(SYMENT, 11)     // Size of a symbol table entry.
+DYNAMIC_TAG(INIT, 12)       // Address of initialization function.
+DYNAMIC_TAG(FINI, 13)       // Address of termination function.
+DYNAMIC_TAG(SONAME, 14)     // String table offset of a shared objects name.
+DYNAMIC_TAG(RPATH, 15)      // String table offset of library search path.
+DYNAMIC_TAG(SYMBOLIC, 16)   // Changes symbol resolution algorithm.
+DYNAMIC_TAG(REL, 17)        // Address of relocation table (Rel entries).
+DYNAMIC_TAG(RELSZ, 18)      // Size of Rel relocation table.
+DYNAMIC_TAG(RELENT, 19)     // Size of a Rel relocation entry.
+DYNAMIC_TAG(PLTREL, 20)     // Type of relocation entry used for linking.
+DYNAMIC_TAG(DEBUG, 21)      // Reserved for debugger.
+DYNAMIC_TAG(TEXTREL, 22)    // Relocations exist for non-writable segments.
+DYNAMIC_TAG(JMPREL, 23)     // Address of relocations associated with PLT.
+DYNAMIC_TAG(BIND_NOW, 24)   // Process all relocations before execution.
+DYNAMIC_TAG(INIT_ARRAY, 25) // Pointer to array of initialization functions.
+DYNAMIC_TAG(FINI_ARRAY, 26) // Pointer to array of termination functions.
+DYNAMIC_TAG(INIT_ARRAYSZ, 27) // Size of DT_INIT_ARRAY.
+DYNAMIC_TAG(FINI_ARRAYSZ, 28) // Size of DT_FINI_ARRAY.
+DYNAMIC_TAG(RUNPATH, 29)      // String table offset of lib search path.
+DYNAMIC_TAG(FLAGS, 30)        // Flags.
+DYNAMIC_TAG_MARKER(ENCODING, 32) // Values from here to DT_LOOS follow the rules
+                                 // for the interpretation of the d_un union.
+
+DYNAMIC_TAG(PREINIT_ARRAY, 32)   // Pointer to array of preinit functions.
+DYNAMIC_TAG(PREINIT_ARRAYSZ, 33) // Size of the DT_PREINIT_ARRAY array.
+
+DYNAMIC_TAG(SYMTAB_SHNDX, 34) // Address of the SHT_SYMTAB_SHNDX section.
+
+// Experimental support for SHT_RELR sections. For details, see proposal
+// at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+DYNAMIC_TAG(RELRSZ, 35)  // Size of Relr relocation table.
+DYNAMIC_TAG(RELR, 36)    // Address of relocation table (Relr entries).
+DYNAMIC_TAG(RELRENT, 37) // Size of a Relr relocation entry.
+
+DYNAMIC_TAG_MARKER(LOOS, 0x60000000)   // Start of environment specific tags.
+DYNAMIC_TAG_MARKER(HIOS, 0x6FFFFFFF)   // End of environment specific tags.
+DYNAMIC_TAG_MARKER(LOPROC, 0x70000000) // Start of processor specific tags.
+DYNAMIC_TAG_MARKER(HIPROC, 0x7FFFFFFF) // End of processor specific tags.
+
+// Android packed relocation section tags.
+// https://android.googlesource.com/platform/bionic/+/6f12bfece5dcc01325e0abba56a46b1bcf991c69/tools/relocation_packer/src/elf_file.cc#31
+DYNAMIC_TAG(ANDROID_REL, 0x6000000F)
+DYNAMIC_TAG(ANDROID_RELSZ, 0x60000010)
+DYNAMIC_TAG(ANDROID_RELA, 0x60000011)
+DYNAMIC_TAG(ANDROID_RELASZ, 0x60000012)
+
+// Android's experimental support for SHT_RELR sections.
+// https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#253
+DYNAMIC_TAG(ANDROID_RELR, 0x6FFFE000)      // Address of relocation table (Relr entries).
+DYNAMIC_TAG(ANDROID_RELRSZ, 0x6FFFE001)    // Size of Relr relocation table.
+DYNAMIC_TAG(ANDROID_RELRENT, 0x6FFFE003)   // Size of a Relr relocation entry.
+
+DYNAMIC_TAG(GNU_HASH, 0x6FFFFEF5)    // Reference to the GNU hash table.
+DYNAMIC_TAG(TLSDESC_PLT, 0x6FFFFEF6) // Location of PLT entry for TLS
+                                     // descriptor resolver calls.
+DYNAMIC_TAG(TLSDESC_GOT, 0x6FFFFEF7) // Location of GOT entry used by TLS
+                                     // descriptor resolver PLT entry.
+DYNAMIC_TAG(RELACOUNT, 0x6FFFFFF9)   // ELF32_Rela count.
+DYNAMIC_TAG(RELCOUNT, 0x6FFFFFFA)    // ELF32_Rel count.
+
+DYNAMIC_TAG(FLAGS_1, 0X6FFFFFFB) // Flags_1.
+
+DYNAMIC_TAG(VERSYM, 0x6FFFFFF0)     // The address of .gnu.version section.
+DYNAMIC_TAG(VERDEF, 0X6FFFFFFC)     // The address of the version definition
+                                    // table.
+DYNAMIC_TAG(VERDEFNUM, 0X6FFFFFFD)  // The number of entries in DT_VERDEF.
+DYNAMIC_TAG(VERNEED, 0X6FFFFFFE)    // The address of the version dependency
+                                    // table.
+DYNAMIC_TAG(VERNEEDNUM, 0X6FFFFFFF) // The number of entries in DT_VERNEED.
+
+// AArch64 specific dynamic table entries
+AARCH64_DYNAMIC_TAG(AARCH64_BTI_PLT, 0x70000001)
+AARCH64_DYNAMIC_TAG(AARCH64_PAC_PLT, 0x70000003)
+
+// Hexagon specific dynamic table entries
+HEXAGON_DYNAMIC_TAG(HEXAGON_SYMSZ, 0x70000000)
+HEXAGON_DYNAMIC_TAG(HEXAGON_VER, 0x70000001)
+HEXAGON_DYNAMIC_TAG(HEXAGON_PLT, 0x70000002)
+
+// Mips specific dynamic table entry tags.
+
+MIPS_DYNAMIC_TAG(MIPS_RLD_VERSION, 0x70000001)  // 32 bit version number for
+                                                // runtime linker interface.
+MIPS_DYNAMIC_TAG(MIPS_TIME_STAMP, 0x70000002)   // Time stamp.
+MIPS_DYNAMIC_TAG(MIPS_ICHECKSUM, 0x70000003)    // Checksum of external strings
+                                                // and common sizes.
+MIPS_DYNAMIC_TAG(MIPS_IVERSION, 0x70000004)     // Index of version string
+                                                // in string table.
+MIPS_DYNAMIC_TAG(MIPS_FLAGS, 0x70000005)        // 32 bits of flags.
+MIPS_DYNAMIC_TAG(MIPS_BASE_ADDRESS, 0x70000006) // Base address of the segment.
+MIPS_DYNAMIC_TAG(MIPS_MSYM, 0x70000007)         // Address of .msym section.
+MIPS_DYNAMIC_TAG(MIPS_CONFLICT, 0x70000008)     // Address of .conflict section.
+MIPS_DYNAMIC_TAG(MIPS_LIBLIST, 0x70000009)      // Address of .liblist section.
+MIPS_DYNAMIC_TAG(MIPS_LOCAL_GOTNO, 0x7000000a)  // Number of local global offset
+                                                // table entries.
+MIPS_DYNAMIC_TAG(MIPS_CONFLICTNO, 0x7000000b)   // Number of entries
+                                                // in the .conflict section.
+MIPS_DYNAMIC_TAG(MIPS_LIBLISTNO, 0x70000010)    // Number of entries
+                                                // in the .liblist section.
+MIPS_DYNAMIC_TAG(MIPS_SYMTABNO, 0x70000011)     // Number of entries
+                                                // in the .dynsym section.
+MIPS_DYNAMIC_TAG(MIPS_UNREFEXTNO, 0x70000012)   // Index of first external dynamic
+                                                // symbol not referenced locally.
+MIPS_DYNAMIC_TAG(MIPS_GOTSYM, 0x70000013)       // Index of first dynamic symbol
+                                                // in global offset table.
+MIPS_DYNAMIC_TAG(MIPS_HIPAGENO, 0x70000014)     // Number of page table entries
+                                                // in global offset table.
+MIPS_DYNAMIC_TAG(MIPS_RLD_MAP, 0x70000016)      // Address of run time loader map
+                                                // used for debugging.
+MIPS_DYNAMIC_TAG(MIPS_DELTA_CLASS, 0x70000017)    // Delta C++ class definition.
+MIPS_DYNAMIC_TAG(MIPS_DELTA_CLASS_NO, 0x70000018) // Number of entries
+                                                  // in DT_MIPS_DELTA_CLASS.
+MIPS_DYNAMIC_TAG(MIPS_DELTA_INSTANCE, 0x70000019) // Delta C++ class instances.
+MIPS_DYNAMIC_TAG(MIPS_DELTA_INSTANCE_NO, 0x7000001A) // Number of entries
+                                                     // in DT_MIPS_DELTA_INSTANCE.
+MIPS_DYNAMIC_TAG(MIPS_DELTA_RELOC, 0x7000001B)       // Delta relocations.
+MIPS_DYNAMIC_TAG(MIPS_DELTA_RELOC_NO, 0x7000001C)    // Number of entries
+                                                     // in DT_MIPS_DELTA_RELOC.
+MIPS_DYNAMIC_TAG(MIPS_DELTA_SYM, 0x7000001D)         // Delta symbols that Delta
+                                                     // relocations refer to.
+MIPS_DYNAMIC_TAG(MIPS_DELTA_SYM_NO, 0x7000001E)      // Number of entries
+                                                     // in DT_MIPS_DELTA_SYM.
+MIPS_DYNAMIC_TAG(MIPS_DELTA_CLASSSYM, 0x70000020)    // Delta symbols that hold
+                                                     // class declarations.
+MIPS_DYNAMIC_TAG(MIPS_DELTA_CLASSSYM_NO, 0x70000021) // Number of entries
+                                                     // in DT_MIPS_DELTA_CLASSSYM.
+
+MIPS_DYNAMIC_TAG(MIPS_CXX_FLAGS, 0x70000022)         // Flags indicating information
+                                                     // about C++ flavor.
+MIPS_DYNAMIC_TAG(MIPS_PIXIE_INIT, 0x70000023)        // Pixie information.
+MIPS_DYNAMIC_TAG(MIPS_SYMBOL_LIB, 0x70000024)        // Address of .MIPS.symlib
+MIPS_DYNAMIC_TAG(MIPS_LOCALPAGE_GOTIDX, 0x70000025)  // The GOT index of the first PTE
+                                                     // for a segment
+MIPS_DYNAMIC_TAG(MIPS_LOCAL_GOTIDX, 0x70000026)      // The GOT index of the first PTE
+                                                     // for a local symbol
+MIPS_DYNAMIC_TAG(MIPS_HIDDEN_GOTIDX, 0x70000027)     // The GOT index of the first PTE
+                                                     // for a hidden symbol
+MIPS_DYNAMIC_TAG(MIPS_PROTECTED_GOTIDX, 0x70000028)  // The GOT index of the first PTE
+                                                        // for a protected symbol
+MIPS_DYNAMIC_TAG(MIPS_OPTIONS, 0x70000029)               // Address of `.MIPS.options'.
+MIPS_DYNAMIC_TAG(MIPS_INTERFACE, 0x7000002A)             // Address of `.interface'.
+MIPS_DYNAMIC_TAG(MIPS_DYNSTR_ALIGN, 0x7000002B)          // Unknown.
+MIPS_DYNAMIC_TAG(MIPS_INTERFACE_SIZE, 0x7000002C)        // Size of the .interface section.
+MIPS_DYNAMIC_TAG(MIPS_RLD_TEXT_RESOLVE_ADDR, 0x7000002D) // Size of rld_text_resolve
+                                                         // function stored in the GOT.
+MIPS_DYNAMIC_TAG(MIPS_PERF_SUFFIX, 0x7000002E)  // Default suffix of DSO to be added
+                                                // by rld on dlopen() calls.
+MIPS_DYNAMIC_TAG(MIPS_COMPACT_SIZE, 0x7000002F) // Size of compact relocation
+                                                // section (O32).
+MIPS_DYNAMIC_TAG(MIPS_GP_VALUE, 0x70000030)     // GP value for auxiliary GOTs.
+MIPS_DYNAMIC_TAG(MIPS_AUX_DYNAMIC, 0x70000031)  // Address of auxiliary .dynamic.
+MIPS_DYNAMIC_TAG(MIPS_PLTGOT, 0x70000032)       // Address of the base of the PLTGOT.
+MIPS_DYNAMIC_TAG(MIPS_RWPLT, 0x70000034)        // Points to the base
+                                                // of a writable PLT.
+MIPS_DYNAMIC_TAG(MIPS_RLD_MAP_REL, 0x70000035)  // Relative offset of run time loader
+                                                // map, used for debugging.
+
+// PPC specific dynamic table entries.
+PPC_DYNAMIC_TAG(PPC_GOT, 0x70000000) // Uses Secure PLT ABI.
+PPC_DYNAMIC_TAG(PPC_OPT, 0x70000001) // Has TLS optimization.
+
+// PPC64 specific dynamic table entries.
+PPC64_DYNAMIC_TAG(PPC64_GLINK, 0x70000000) // Address of 32 bytes before the
+                                           // first glink lazy resolver stub.
+
+// Sun machine-independent extensions.
+DYNAMIC_TAG(AUXILIARY, 0x7FFFFFFD) // Shared object to load before self
+DYNAMIC_TAG(USED, 0x7FFFFFFE)      // Same as DT_NEEDED
+DYNAMIC_TAG(FILTER, 0x7FFFFFFF)    // Shared object to get values from
+
+
+#ifdef DYNAMIC_TAG_MARKER_DEFINED
+#undef DYNAMIC_TAG_MARKER
+#undef DYNAMIC_TAG_MARKER_DEFINED
+#endif
+#ifdef AARCH64_DYNAMIC_TAG_DEFINED
+#undef AARCH64_DYNAMIC_TAG
+#undef AARCH64_DYNAMIC_TAG_DEFINED
+#endif
+#ifdef MIPS_DYNAMIC_TAG_DEFINED
+#undef MIPS_DYNAMIC_TAG
+#undef MIPS_DYNAMIC_TAG_DEFINED
+#endif
+#ifdef HEXAGON_DYNAMIC_TAG_DEFINED
+#undef HEXAGON_DYNAMIC_TAG
+#undef HEXAGON_DYNAMIC_TAG_DEFINED
+#endif
+#ifdef PPC_DYNAMIC_TAG_DEFINED
+#undef PPC_DYNAMIC_TAG
+#undef PPC_DYNAMIC_TAG_DEFINED
+#endif
+#ifdef PPC64_DYNAMIC_TAG_DEFINED
+#undef PPC64_DYNAMIC_TAG
+#undef PPC64_DYNAMIC_TAG_DEFINED
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELF.h b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELF.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELF.h
@@ -0,0 +1,1573 @@
+//===- llvm/BinaryFormat/ELF.h - ELF constants and structures ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This header contains common, non-processor-specific data structures and
+// constants for the ELF file format.
+//
+// The details of the ELF32 bits in this file are largely based on the Tool
+// Interface Standard (TIS) Executable and Linking Format (ELF) Specification
+// Version 1.2, May 1995. The ELF64 stuff is based on ELF-64 Object File Format
+// Version 1.5, Draft 2, May 1998 as well as OpenBSD header files.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BINARYFORMAT_ELF_H
+#define LLVM_BINARYFORMAT_ELF_H
+
+#include <cstdint>
+#include <cstring>
+
+namespace llvm {
+namespace ELF {
+
+using Elf32_Addr = uint32_t; // Program address
+using Elf32_Off = uint32_t;  // File offset
+using Elf32_Half = uint16_t;
+using Elf32_Word = uint32_t;
+using Elf32_Sword = int32_t;
+
+using Elf64_Addr = uint64_t;
+using Elf64_Off = uint64_t;
+using Elf64_Half = uint16_t;
+using Elf64_Word = uint32_t;
+using Elf64_Sword = int32_t;
+using Elf64_Xword = uint64_t;
+using Elf64_Sxword = int64_t;
+
+// Object file magic string.
+static const char ElfMagic[] = {0x7f, 'E', 'L', 'F', '\0'};
+
+// e_ident size and indices.
+enum {
+  EI_MAG0 = 0,       // File identification index.
+  EI_MAG1 = 1,       // File identification index.
+  EI_MAG2 = 2,       // File identification index.
+  EI_MAG3 = 3,       // File identification index.
+  EI_CLASS = 4,      // File class.
+  EI_DATA = 5,       // Data encoding.
+  EI_VERSION = 6,    // File version.
+  EI_OSABI = 7,      // OS/ABI identification.
+  EI_ABIVERSION = 8, // ABI version.
+  EI_PAD = 9,        // Start of padding bytes.
+  EI_NIDENT = 16     // Number of bytes in e_ident.
+};
+
+struct Elf32_Ehdr {
+  unsigned char e_ident[EI_NIDENT]; // ELF Identification bytes
+  Elf32_Half e_type;                // Type of file (see ET_* below)
+  Elf32_Half e_machine;   // Required architecture for this file (see EM_*)
+  Elf32_Word e_version;   // Must be equal to 1
+  Elf32_Addr e_entry;     // Address to jump to in order to start program
+  Elf32_Off e_phoff;      // Program header table's file offset, in bytes
+  Elf32_Off e_shoff;      // Section header table's file offset, in bytes
+  Elf32_Word e_flags;     // Processor-specific flags
+  Elf32_Half e_ehsize;    // Size of ELF header, in bytes
+  Elf32_Half e_phentsize; // Size of an entry in the program header table
+  Elf32_Half e_phnum;     // Number of entries in the program header table
+  Elf32_Half e_shentsize; // Size of an entry in the section header table
+  Elf32_Half e_shnum;     // Number of entries in the section header table
+  Elf32_Half e_shstrndx;  // Sect hdr table index of sect name string table
+
+  bool checkMagic() const {
+    return (memcmp(e_ident, ElfMagic, strlen(ElfMagic))) == 0;
+  }
+
+  unsigned char getFileClass() const { return e_ident[EI_CLASS]; }
+  unsigned char getDataEncoding() const { return e_ident[EI_DATA]; }
+};
+
+// 64-bit ELF header. Fields are the same as for ELF32, but with different
+// types (see above).
+struct Elf64_Ehdr {
+  unsigned char e_ident[EI_NIDENT];
+  Elf64_Half e_type;
+  Elf64_Half e_machine;
+  Elf64_Word e_version;
+  Elf64_Addr e_entry;
+  Elf64_Off e_phoff;
+  Elf64_Off e_shoff;
+  Elf64_Word e_flags;
+  Elf64_Half e_ehsize;
+  Elf64_Half e_phentsize;
+  Elf64_Half e_phnum;
+  Elf64_Half e_shentsize;
+  Elf64_Half e_shnum;
+  Elf64_Half e_shstrndx;
+
+  bool checkMagic() const {
+    return (memcmp(e_ident, ElfMagic, strlen(ElfMagic))) == 0;
+  }
+
+  unsigned char getFileClass() const { return e_ident[EI_CLASS]; }
+  unsigned char getDataEncoding() const { return e_ident[EI_DATA]; }
+};
+
+// File types
+enum {
+  ET_NONE = 0,        // No file type
+  ET_REL = 1,         // Relocatable file
+  ET_EXEC = 2,        // Executable file
+  ET_DYN = 3,         // Shared object file
+  ET_CORE = 4,        // Core file
+  ET_LOPROC = 0xff00, // Beginning of processor-specific codes
+  ET_HIPROC = 0xffff  // Processor-specific
+};
+
+// Versioning
+enum { EV_NONE = 0, EV_CURRENT = 1 };
+
+// Machine architectures
+// See current registered ELF machine architectures at:
+//    http://www.uxsglobal.com/developers/gabi/latest/ch4.eheader.html
+enum {
+  EM_NONE = 0,           // No machine
+  EM_M32 = 1,            // AT&T WE 32100
+  EM_SPARC = 2,          // SPARC
+  EM_386 = 3,            // Intel 386
+  EM_68K = 4,            // Motorola 68000
+  EM_88K = 5,            // Motorola 88000
+  EM_IAMCU = 6,          // Intel MCU
+  EM_860 = 7,            // Intel 80860
+  EM_MIPS = 8,           // MIPS R3000
+  EM_S370 = 9,           // IBM System/370
+  EM_MIPS_RS3_LE = 10,   // MIPS RS3000 Little-endian
+  EM_PARISC = 15,        // Hewlett-Packard PA-RISC
+  EM_VPP500 = 17,        // Fujitsu VPP500
+  EM_SPARC32PLUS = 18,   // Enhanced instruction set SPARC
+  EM_960 = 19,           // Intel 80960
+  EM_PPC = 20,           // PowerPC
+  EM_PPC64 = 21,         // PowerPC64
+  EM_S390 = 22,          // IBM System/390
+  EM_SPU = 23,           // IBM SPU/SPC
+  EM_V800 = 36,          // NEC V800
+  EM_FR20 = 37,          // Fujitsu FR20
+  EM_RH32 = 38,          // TRW RH-32
+  EM_RCE = 39,           // Motorola RCE
+  EM_ARM = 40,           // ARM
+  EM_ALPHA = 41,         // DEC Alpha
+  EM_SH = 42,            // Hitachi SH
+  EM_SPARCV9 = 43,       // SPARC V9
+  EM_TRICORE = 44,       // Siemens TriCore
+  EM_ARC = 45,           // Argonaut RISC Core
+  EM_H8_300 = 46,        // Hitachi H8/300
+  EM_H8_300H = 47,       // Hitachi H8/300H
+  EM_H8S = 48,           // Hitachi H8S
+  EM_H8_500 = 49,        // Hitachi H8/500
+  EM_IA_64 = 50,         // Intel IA-64 processor architecture
+  EM_MIPS_X = 51,        // Stanford MIPS-X
+  EM_COLDFIRE = 52,      // Motorola ColdFire
+  EM_68HC12 = 53,        // Motorola M68HC12
+  EM_MMA = 54,           // Fujitsu MMA Multimedia Accelerator
+  EM_PCP = 55,           // Siemens PCP
+  EM_NCPU = 56,          // Sony nCPU embedded RISC processor
+  EM_NDR1 = 57,          // Denso NDR1 microprocessor
+  EM_STARCORE = 58,      // Motorola Star*Core processor
+  EM_ME16 = 59,          // Toyota ME16 processor
+  EM_ST100 = 60,         // STMicroelectronics ST100 processor
+  EM_TINYJ = 61,         // Advanced Logic Corp. TinyJ embedded processor family
+  EM_X86_64 = 62,        // AMD x86-64 architecture
+  EM_PDSP = 63,          // Sony DSP Processor
+  EM_PDP10 = 64,         // Digital Equipment Corp. PDP-10
+  EM_PDP11 = 65,         // Digital Equipment Corp. PDP-11
+  EM_FX66 = 66,          // Siemens FX66 microcontroller
+  EM_ST9PLUS = 67,       // STMicroelectronics ST9+ 8/16 bit microcontroller
+  EM_ST7 = 68,           // STMicroelectronics ST7 8-bit microcontroller
+  EM_68HC16 = 69,        // Motorola MC68HC16 Microcontroller
+  EM_68HC11 = 70,        // Motorola MC68HC11 Microcontroller
+  EM_68HC08 = 71,        // Motorola MC68HC08 Microcontroller
+  EM_68HC05 = 72,        // Motorola MC68HC05 Microcontroller
+  EM_SVX = 73,           // Silicon Graphics SVx
+  EM_ST19 = 74,          // STMicroelectronics ST19 8-bit microcontroller
+  EM_VAX = 75,           // Digital VAX
+  EM_CRIS = 76,          // Axis Communications 32-bit embedded processor
+  EM_JAVELIN = 77,       // Infineon Technologies 32-bit embedded processor
+  EM_FIREPATH = 78,      // Element 14 64-bit DSP Processor
+  EM_ZSP = 79,           // LSI Logic 16-bit DSP Processor
+  EM_MMIX = 80,          // Donald Knuth's educational 64-bit processor
+  EM_HUANY = 81,         // Harvard University machine-independent object files
+  EM_PRISM = 82,         // SiTera Prism
+  EM_AVR = 83,           // Atmel AVR 8-bit microcontroller
+  EM_FR30 = 84,          // Fujitsu FR30
+  EM_D10V = 85,          // Mitsubishi D10V
+  EM_D30V = 86,          // Mitsubishi D30V
+  EM_V850 = 87,          // NEC v850
+  EM_M32R = 88,          // Mitsubishi M32R
+  EM_MN10300 = 89,       // Matsushita MN10300
+  EM_MN10200 = 90,       // Matsushita MN10200
+  EM_PJ = 91,            // picoJava
+  EM_OPENRISC = 92,      // OpenRISC 32-bit embedded processor
+  EM_ARC_COMPACT = 93,   // ARC International ARCompact processor (old
+                         // spelling/synonym: EM_ARC_A5)
+  EM_XTENSA = 94,        // Tensilica Xtensa Architecture
+  EM_VIDEOCORE = 95,     // Alphamosaic VideoCore processor
+  EM_TMM_GPP = 96,       // Thompson Multimedia General Purpose Processor
+  EM_NS32K = 97,         // National Semiconductor 32000 series
+  EM_TPC = 98,           // Tenor Network TPC processor
+  EM_SNP1K = 99,         // Trebia SNP 1000 processor
+  EM_ST200 = 100,        // STMicroelectronics (www.st.com) ST200
+  EM_IP2K = 101,         // Ubicom IP2xxx microcontroller family
+  EM_MAX = 102,          // MAX Processor
+  EM_CR = 103,           // National Semiconductor CompactRISC microprocessor
+  EM_F2MC16 = 104,       // Fujitsu F2MC16
+  EM_MSP430 = 105,       // Texas Instruments embedded microcontroller msp430
+  EM_BLACKFIN = 106,     // Analog Devices Blackfin (DSP) processor
+  EM_SE_C33 = 107,       // S1C33 Family of Seiko Epson processors
+  EM_SEP = 108,          // Sharp embedded microprocessor
+  EM_ARCA = 109,         // Arca RISC Microprocessor
+  EM_UNICORE = 110,      // Microprocessor series from PKU-Unity Ltd. and MPRC
+                         // of Peking University
+  EM_EXCESS = 111,       // eXcess: 16/32/64-bit configurable embedded CPU
+  EM_DXP = 112,          // Icera Semiconductor Inc. Deep Execution Processor
+  EM_ALTERA_NIOS2 = 113, // Altera Nios II soft-core processor
+  EM_CRX = 114,          // National Semiconductor CompactRISC CRX
+  EM_XGATE = 115,        // Motorola XGATE embedded processor
+  EM_C166 = 116,         // Infineon C16x/XC16x processor
+  EM_M16C = 117,         // Renesas M16C series microprocessors
+  EM_DSPIC30F = 118,     // Microchip Technology dsPIC30F Digital Signal
+                         // Controller
+  EM_CE = 119,           // Freescale Communication Engine RISC core
+  EM_M32C = 120,         // Renesas M32C series microprocessors
+  EM_TSK3000 = 131,      // Altium TSK3000 core
+  EM_RS08 = 132,         // Freescale RS08 embedded processor
+  EM_SHARC = 133,        // Analog Devices SHARC family of 32-bit DSP
+                         // processors
+  EM_ECOG2 = 134,        // Cyan Technology eCOG2 microprocessor
+  EM_SCORE7 = 135,       // Sunplus S+core7 RISC processor
+  EM_DSP24 = 136,        // New Japan Radio (NJR) 24-bit DSP Processor
+  EM_VIDEOCORE3 = 137,   // Broadcom VideoCore III processor
+  EM_LATTICEMICO32 = 138, // RISC processor for Lattice FPGA architecture
+  EM_SE_C17 = 139,        // Seiko Epson C17 family
+  EM_TI_C6000 = 140,      // The Texas Instruments TMS320C6000 DSP family
+  EM_TI_C2000 = 141,      // The Texas Instruments TMS320C2000 DSP family
+  EM_TI_C5500 = 142,      // The Texas Instruments TMS320C55x DSP family
+  EM_MMDSP_PLUS = 160,    // STMicroelectronics 64bit VLIW Data Signal Processor
+  EM_CYPRESS_M8C = 161,   // Cypress M8C microprocessor
+  EM_R32C = 162,          // Renesas R32C series microprocessors
+  EM_TRIMEDIA = 163,      // NXP Semiconductors TriMedia architecture family
+  EM_HEXAGON = 164,       // Qualcomm Hexagon processor
+  EM_8051 = 165,          // Intel 8051 and variants
+  EM_STXP7X = 166,        // STMicroelectronics STxP7x family of configurable
+                          // and extensible RISC processors
+  EM_NDS32 = 167,         // Andes Technology compact code size embedded RISC
+                          // processor family
+  EM_ECOG1 = 168,         // Cyan Technology eCOG1X family
+  EM_ECOG1X = 168,        // Cyan Technology eCOG1X family
+  EM_MAXQ30 = 169,        // Dallas Semiconductor MAXQ30 Core Micro-controllers
+  EM_XIMO16 = 170,        // New Japan Radio (NJR) 16-bit DSP Processor
+  EM_MANIK = 171,         // M2000 Reconfigurable RISC Microprocessor
+  EM_CRAYNV2 = 172,       // Cray Inc. NV2 vector architecture
+  EM_RX = 173,            // Renesas RX family
+  EM_METAG = 174,         // Imagination Technologies META processor
+                          // architecture
+  EM_MCST_ELBRUS = 175,   // MCST Elbrus general purpose hardware architecture
+  EM_ECOG16 = 176,        // Cyan Technology eCOG16 family
+  EM_CR16 = 177,          // National Semiconductor CompactRISC CR16 16-bit
+                          // microprocessor
+  EM_ETPU = 178,          // Freescale Extended Time Processing Unit
+  EM_SLE9X = 179,         // Infineon Technologies SLE9X core
+  EM_L10M = 180,          // Intel L10M
+  EM_K10M = 181,          // Intel K10M
+  EM_AARCH64 = 183,       // ARM AArch64
+  EM_AVR32 = 185,         // Atmel Corporation 32-bit microprocessor family
+  EM_STM8 = 186,          // STMicroeletronics STM8 8-bit microcontroller
+  EM_TILE64 = 187,        // Tilera TILE64 multicore architecture family
+  EM_TILEPRO = 188,       // Tilera TILEPro multicore architecture family
+  EM_CUDA = 190,          // NVIDIA CUDA architecture
+  EM_TILEGX = 191,        // Tilera TILE-Gx multicore architecture family
+  EM_CLOUDSHIELD = 192,   // CloudShield architecture family
+  EM_COREA_1ST = 193,     // KIPO-KAIST Core-A 1st generation processor family
+  EM_COREA_2ND = 194,     // KIPO-KAIST Core-A 2nd generation processor family
+  EM_ARC_COMPACT2 = 195,  // Synopsys ARCompact V2
+  EM_OPEN8 = 196,         // Open8 8-bit RISC soft processor core
+  EM_RL78 = 197,          // Renesas RL78 family
+  EM_VIDEOCORE5 = 198,    // Broadcom VideoCore V processor
+  EM_78KOR = 199,         // Renesas 78KOR family
+  EM_56800EX = 200,       // Freescale 56800EX Digital Signal Controller (DSC)
+  EM_BA1 = 201,           // Beyond BA1 CPU architecture
+  EM_BA2 = 202,           // Beyond BA2 CPU architecture
+  EM_XCORE = 203,         // XMOS xCORE processor family
+  EM_MCHP_PIC = 204,      // Microchip 8-bit PIC(r) family
+  EM_INTEL205 = 205,      // Reserved by Intel
+  EM_INTEL206 = 206,      // Reserved by Intel
+  EM_INTEL207 = 207,      // Reserved by Intel
+  EM_INTEL208 = 208,      // Reserved by Intel
+  EM_INTEL209 = 209,      // Reserved by Intel
+  EM_KM32 = 210,          // KM211 KM32 32-bit processor
+  EM_KMX32 = 211,         // KM211 KMX32 32-bit processor
+  EM_KMX16 = 212,         // KM211 KMX16 16-bit processor
+  EM_KMX8 = 213,          // KM211 KMX8 8-bit processor
+  EM_KVARC = 214,         // KM211 KVARC processor
+  EM_CDP = 215,           // Paneve CDP architecture family
+  EM_COGE = 216,          // Cognitive Smart Memory Processor
+  EM_COOL = 217,          // iCelero CoolEngine
+  EM_NORC = 218,          // Nanoradio Optimized RISC
+  EM_CSR_KALIMBA = 219,   // CSR Kalimba architecture family
+  EM_AMDGPU = 224,        // AMD GPU architecture
+  EM_RISCV = 243,         // RISC-V
+  EM_LANAI = 244,         // Lanai 32-bit processor
+  EM_BPF = 247,           // Linux kernel bpf virtual machine
+};
+
+// Object file classes.
+enum {
+  ELFCLASSNONE = 0,
+  ELFCLASS32 = 1, // 32-bit object file
+  ELFCLASS64 = 2  // 64-bit object file
+};
+
+// Object file byte orderings.
+enum {
+  ELFDATANONE = 0, // Invalid data encoding.
+  ELFDATA2LSB = 1, // Little-endian object file
+  ELFDATA2MSB = 2  // Big-endian object file
+};
+
+// OS ABI identification.
+enum {
+  ELFOSABI_NONE = 0,           // UNIX System V ABI
+  ELFOSABI_HPUX = 1,           // HP-UX operating system
+  ELFOSABI_NETBSD = 2,         // NetBSD
+  ELFOSABI_GNU = 3,            // GNU/Linux
+  ELFOSABI_LINUX = 3,          // Historical alias for ELFOSABI_GNU.
+  ELFOSABI_HURD = 4,           // GNU/Hurd
+  ELFOSABI_SOLARIS = 6,        // Solaris
+  ELFOSABI_AIX = 7,            // AIX
+  ELFOSABI_IRIX = 8,           // IRIX
+  ELFOSABI_FREEBSD = 9,        // FreeBSD
+  ELFOSABI_TRU64 = 10,         // TRU64 UNIX
+  ELFOSABI_MODESTO = 11,       // Novell Modesto
+  ELFOSABI_OPENBSD = 12,       // OpenBSD
+  ELFOSABI_OPENVMS = 13,       // OpenVMS
+  ELFOSABI_NSK = 14,           // Hewlett-Packard Non-Stop Kernel
+  ELFOSABI_AROS = 15,          // AROS
+  ELFOSABI_FENIXOS = 16,       // FenixOS
+  ELFOSABI_CLOUDABI = 17,      // Nuxi CloudABI
+  ELFOSABI_FIRST_ARCH = 64,    // First architecture-specific OS ABI
+  ELFOSABI_AMDGPU_HSA = 64,    // AMD HSA runtime
+  ELFOSABI_AMDGPU_PAL = 65,    // AMD PAL runtime
+  ELFOSABI_AMDGPU_MESA3D = 66, // AMD GCN GPUs (GFX6+) for MESA runtime
+  ELFOSABI_ARM = 97,           // ARM
+  ELFOSABI_C6000_ELFABI = 64,  // Bare-metal TMS320C6000
+  ELFOSABI_C6000_LINUX = 65,   // Linux TMS320C6000
+  ELFOSABI_STANDALONE = 255,   // Standalone (embedded) application
+  ELFOSABI_LAST_ARCH = 255     // Last Architecture-specific OS ABI
+};
+
+#define ELF_RELOC(name, value) name = value,
+
+// X86_64 relocations.
+enum {
+#include "ELFRelocs/x86_64.def"
+};
+
+// i386 relocations.
+enum {
+#include "ELFRelocs/i386.def"
+};
+
+// ELF Relocation types for PPC32
+enum {
+#include "ELFRelocs/PowerPC.def"
+};
+
+// Specific e_flags for PPC64
+enum {
+  // e_flags bits specifying ABI:
+  // 1 for original ABI using function descriptors,
+  // 2 for revised ABI without function descriptors,
+  // 0 for unspecified or not using any features affected by the differences.
+  EF_PPC64_ABI = 3
+};
+
+// Special values for the st_other field in the symbol table entry for PPC64.
+enum {
+  STO_PPC64_LOCAL_BIT = 5,
+  STO_PPC64_LOCAL_MASK = (7 << STO_PPC64_LOCAL_BIT)
+};
+static inline int64_t decodePPC64LocalEntryOffset(unsigned Other) {
+  unsigned Val = (Other & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT;
+  return ((1 << Val) >> 2) << 2;
+}
+static inline unsigned encodePPC64LocalEntryOffset(int64_t Offset) {
+  unsigned Val =
+      (Offset >= 4 * 4 ? (Offset >= 8 * 4 ? (Offset >= 16 * 4 ? 6 : 5) : 4)
+                       : (Offset >= 2 * 4 ? 3 : (Offset >= 1 * 4 ? 2 : 0)));
+  return Val << STO_PPC64_LOCAL_BIT;
+}
+
+// ELF Relocation types for PPC64
+enum {
+#include "ELFRelocs/PowerPC64.def"
+};
+
+// ELF Relocation types for AArch64
+enum {
+#include "ELFRelocs/AArch64.def"
+};
+
+// ARM Specific e_flags
+enum : unsigned {
+  EF_ARM_SOFT_FLOAT = 0x00000200U,     // Legacy pre EABI_VER5
+  EF_ARM_ABI_FLOAT_SOFT = 0x00000200U, // EABI_VER5
+  EF_ARM_VFP_FLOAT = 0x00000400U,      // Legacy pre EABI_VER5
+  EF_ARM_ABI_FLOAT_HARD = 0x00000400U, // EABI_VER5
+  EF_ARM_EABI_UNKNOWN = 0x00000000U,
+  EF_ARM_EABI_VER1 = 0x01000000U,
+  EF_ARM_EABI_VER2 = 0x02000000U,
+  EF_ARM_EABI_VER3 = 0x03000000U,
+  EF_ARM_EABI_VER4 = 0x04000000U,
+  EF_ARM_EABI_VER5 = 0x05000000U,
+  EF_ARM_EABIMASK = 0xFF000000U
+};
+
+// ELF Relocation types for ARM
+enum {
+#include "ELFRelocs/ARM.def"
+};
+
+// ARC Specific e_flags
+enum : unsigned {
+  EF_ARC_MACH_MSK = 0x000000ff,
+  EF_ARC_OSABI_MSK = 0x00000f00,
+  E_ARC_MACH_ARC600 = 0x00000002,
+  E_ARC_MACH_ARC601 = 0x00000004,
+  E_ARC_MACH_ARC700 = 0x00000003,
+  EF_ARC_CPU_ARCV2EM = 0x00000005,
+  EF_ARC_CPU_ARCV2HS = 0x00000006,
+  E_ARC_OSABI_ORIG = 0x00000000,
+  E_ARC_OSABI_V2 = 0x00000200,
+  E_ARC_OSABI_V3 = 0x00000300,
+  E_ARC_OSABI_V4 = 0x00000400,
+  EF_ARC_PIC = 0x00000100
+};
+
+// ELF Relocation types for ARC
+enum {
+#include "ELFRelocs/ARC.def"
+};
+
+// AVR specific e_flags
+enum : unsigned {
+  EF_AVR_ARCH_AVR1 = 1,
+  EF_AVR_ARCH_AVR2 = 2,
+  EF_AVR_ARCH_AVR25 = 25,
+  EF_AVR_ARCH_AVR3 = 3,
+  EF_AVR_ARCH_AVR31 = 31,
+  EF_AVR_ARCH_AVR35 = 35,
+  EF_AVR_ARCH_AVR4 = 4,
+  EF_AVR_ARCH_AVR5 = 5,
+  EF_AVR_ARCH_AVR51 = 51,
+  EF_AVR_ARCH_AVR6 = 6,
+  EF_AVR_ARCH_AVRTINY = 100,
+  EF_AVR_ARCH_XMEGA1 = 101,
+  EF_AVR_ARCH_XMEGA2 = 102,
+  EF_AVR_ARCH_XMEGA3 = 103,
+  EF_AVR_ARCH_XMEGA4 = 104,
+  EF_AVR_ARCH_XMEGA5 = 105,
+  EF_AVR_ARCH_XMEGA6 = 106,
+  EF_AVR_ARCH_XMEGA7 = 107
+};
+
+// ELF Relocation types for AVR
+enum {
+#include "ELFRelocs/AVR.def"
+};
+
+// Mips Specific e_flags
+enum : unsigned {
+  EF_MIPS_NOREORDER = 0x00000001, // Don't reorder instructions
+  EF_MIPS_PIC = 0x00000002,       // Position independent code
+  EF_MIPS_CPIC = 0x00000004,      // Call object with Position independent code
+  EF_MIPS_ABI2 = 0x00000020,      // File uses N32 ABI
+  EF_MIPS_32BITMODE = 0x00000100, // Code compiled for a 64-bit machine
+                                  // in 32-bit mode
+  EF_MIPS_FP64 = 0x00000200,      // Code compiled for a 32-bit machine
+                                  // but uses 64-bit FP registers
+  EF_MIPS_NAN2008 = 0x00000400,   // Uses IEE 754-2008 NaN encoding
+
+  // ABI flags
+  EF_MIPS_ABI_O32 = 0x00001000, // This file follows the first MIPS 32 bit ABI
+  EF_MIPS_ABI_O64 = 0x00002000, // O32 ABI extended for 64-bit architecture.
+  EF_MIPS_ABI_EABI32 = 0x00003000, // EABI in 32 bit mode.
+  EF_MIPS_ABI_EABI64 = 0x00004000, // EABI in 64 bit mode.
+  EF_MIPS_ABI = 0x0000f000,        // Mask for selecting EF_MIPS_ABI_ variant.
+
+  // MIPS machine variant
+  EF_MIPS_MACH_NONE = 0x00000000,    // A standard MIPS implementation.
+  EF_MIPS_MACH_3900 = 0x00810000,    // Toshiba R3900
+  EF_MIPS_MACH_4010 = 0x00820000,    // LSI R4010
+  EF_MIPS_MACH_4100 = 0x00830000,    // NEC VR4100
+  EF_MIPS_MACH_4650 = 0x00850000,    // MIPS R4650
+  EF_MIPS_MACH_4120 = 0x00870000,    // NEC VR4120
+  EF_MIPS_MACH_4111 = 0x00880000,    // NEC VR4111/VR4181
+  EF_MIPS_MACH_SB1 = 0x008a0000,     // Broadcom SB-1
+  EF_MIPS_MACH_OCTEON = 0x008b0000,  // Cavium Networks Octeon
+  EF_MIPS_MACH_XLR = 0x008c0000,     // RMI Xlr
+  EF_MIPS_MACH_OCTEON2 = 0x008d0000, // Cavium Networks Octeon2
+  EF_MIPS_MACH_OCTEON3 = 0x008e0000, // Cavium Networks Octeon3
+  EF_MIPS_MACH_5400 = 0x00910000,    // NEC VR5400
+  EF_MIPS_MACH_5900 = 0x00920000,    // MIPS R5900
+  EF_MIPS_MACH_5500 = 0x00980000,    // NEC VR5500
+  EF_MIPS_MACH_9000 = 0x00990000,    // Unknown
+  EF_MIPS_MACH_LS2E = 0x00a00000,    // ST Microelectronics Loongson 2E
+  EF_MIPS_MACH_LS2F = 0x00a10000,    // ST Microelectronics Loongson 2F
+  EF_MIPS_MACH_LS3A = 0x00a20000,    // Loongson 3A
+  EF_MIPS_MACH = 0x00ff0000,         // EF_MIPS_MACH_xxx selection mask
+
+  // ARCH_ASE
+  EF_MIPS_MICROMIPS = 0x02000000,     // microMIPS
+  EF_MIPS_ARCH_ASE_M16 = 0x04000000,  // Has Mips-16 ISA extensions
+  EF_MIPS_ARCH_ASE_MDMX = 0x08000000, // Has MDMX multimedia extensions
+  EF_MIPS_ARCH_ASE = 0x0f000000,      // Mask for EF_MIPS_ARCH_ASE_xxx flags
+
+  // ARCH
+  EF_MIPS_ARCH_1 = 0x00000000,    // MIPS1 instruction set
+  EF_MIPS_ARCH_2 = 0x10000000,    // MIPS2 instruction set
+  EF_MIPS_ARCH_3 = 0x20000000,    // MIPS3 instruction set
+  EF_MIPS_ARCH_4 = 0x30000000,    // MIPS4 instruction set
+  EF_MIPS_ARCH_5 = 0x40000000,    // MIPS5 instruction set
+  EF_MIPS_ARCH_32 = 0x50000000,   // MIPS32 instruction set per linux not elf.h
+  EF_MIPS_ARCH_64 = 0x60000000,   // MIPS64 instruction set per linux not elf.h
+  EF_MIPS_ARCH_32R2 = 0x70000000, // mips32r2, mips32r3, mips32r5
+  EF_MIPS_ARCH_64R2 = 0x80000000, // mips64r2, mips64r3, mips64r5
+  EF_MIPS_ARCH_32R6 = 0x90000000, // mips32r6
+  EF_MIPS_ARCH_64R6 = 0xa0000000, // mips64r6
+  EF_MIPS_ARCH = 0xf0000000       // Mask for applying EF_MIPS_ARCH_ variant
+};
+
+// ELF Relocation types for Mips
+enum {
+#include "ELFRelocs/Mips.def"
+};
+
+// Special values for the st_other field in the symbol table entry for MIPS.
+enum {
+  STO_MIPS_OPTIONAL = 0x04,  // Symbol whose definition is optional
+  STO_MIPS_PLT = 0x08,       // PLT entry related dynamic table record
+  STO_MIPS_PIC = 0x20,       // PIC func in an object mixes PIC/non-PIC
+  STO_MIPS_MICROMIPS = 0x80, // MIPS Specific ISA for MicroMips
+  STO_MIPS_MIPS16 = 0xf0     // MIPS Specific ISA for Mips16
+};
+
+// .MIPS.options section descriptor kinds
+enum {
+  ODK_NULL = 0,       // Undefined
+  ODK_REGINFO = 1,    // Register usage information
+  ODK_EXCEPTIONS = 2, // Exception processing options
+  ODK_PAD = 3,        // Section padding options
+  ODK_HWPATCH = 4,    // Hardware patches applied
+  ODK_FILL = 5,       // Linker fill value
+  ODK_TAGS = 6,       // Space for tool identification
+  ODK_HWAND = 7,      // Hardware AND patches applied
+  ODK_HWOR = 8,       // Hardware OR patches applied
+  ODK_GP_GROUP = 9,   // GP group to use for text/data sections
+  ODK_IDENT = 10,     // ID information
+  ODK_PAGESIZE = 11   // Page size information
+};
+
+// Hexagon-specific e_flags
+enum {
+  // Object processor version flags, bits[11:0]
+  EF_HEXAGON_MACH_V2 = 0x00000001,  // Hexagon V2
+  EF_HEXAGON_MACH_V3 = 0x00000002,  // Hexagon V3
+  EF_HEXAGON_MACH_V4 = 0x00000003,  // Hexagon V4
+  EF_HEXAGON_MACH_V5 = 0x00000004,  // Hexagon V5
+  EF_HEXAGON_MACH_V55 = 0x00000005, // Hexagon V55
+  EF_HEXAGON_MACH_V60 = 0x00000060, // Hexagon V60
+  EF_HEXAGON_MACH_V62 = 0x00000062, // Hexagon V62
+  EF_HEXAGON_MACH_V65 = 0x00000065, // Hexagon V65
+  EF_HEXAGON_MACH_V66 = 0x00000066, // Hexagon V66
+
+  // Highest ISA version flags
+  EF_HEXAGON_ISA_MACH = 0x00000000, // Same as specified in bits[11:0]
+                                    // of e_flags
+  EF_HEXAGON_ISA_V2 = 0x00000010,   // Hexagon V2 ISA
+  EF_HEXAGON_ISA_V3 = 0x00000020,   // Hexagon V3 ISA
+  EF_HEXAGON_ISA_V4 = 0x00000030,   // Hexagon V4 ISA
+  EF_HEXAGON_ISA_V5 = 0x00000040,   // Hexagon V5 ISA
+  EF_HEXAGON_ISA_V55 = 0x00000050,  // Hexagon V55 ISA
+  EF_HEXAGON_ISA_V60 = 0x00000060,  // Hexagon V60 ISA
+  EF_HEXAGON_ISA_V62 = 0x00000062,  // Hexagon V62 ISA
+  EF_HEXAGON_ISA_V65 = 0x00000065,  // Hexagon V65 ISA
+  EF_HEXAGON_ISA_V66 = 0x00000066,  // Hexagon V66 ISA
+};
+
+// Hexagon-specific section indexes for common small data
+enum {
+  SHN_HEXAGON_SCOMMON = 0xff00,   // Other access sizes
+  SHN_HEXAGON_SCOMMON_1 = 0xff01, // Byte-sized access
+  SHN_HEXAGON_SCOMMON_2 = 0xff02, // Half-word-sized access
+  SHN_HEXAGON_SCOMMON_4 = 0xff03, // Word-sized access
+  SHN_HEXAGON_SCOMMON_8 = 0xff04  // Double-word-size access
+};
+
+// ELF Relocation types for Hexagon
+enum {
+#include "ELFRelocs/Hexagon.def"
+};
+
+// ELF Relocation type for Lanai.
+enum {
+#include "ELFRelocs/Lanai.def"
+};
+
+// RISCV Specific e_flags
+enum : unsigned {
+  EF_RISCV_RVC = 0x0001,
+  EF_RISCV_FLOAT_ABI = 0x0006,
+  EF_RISCV_FLOAT_ABI_SOFT = 0x0000,
+  EF_RISCV_FLOAT_ABI_SINGLE = 0x0002,
+  EF_RISCV_FLOAT_ABI_DOUBLE = 0x0004,
+  EF_RISCV_FLOAT_ABI_QUAD = 0x0006,
+  EF_RISCV_RVE = 0x0008
+};
+
+// ELF Relocation types for RISC-V
+enum {
+#include "ELFRelocs/RISCV.def"
+};
+
+// ELF Relocation types for S390/zSeries
+enum {
+#include "ELFRelocs/SystemZ.def"
+};
+
+// ELF Relocation type for Sparc.
+enum {
+#include "ELFRelocs/Sparc.def"
+};
+
+// AMDGPU specific e_flags.
+enum : unsigned {
+  // Processor selection mask for EF_AMDGPU_MACH_* values.
+  EF_AMDGPU_MACH = 0x0ff,
+
+  // Not specified processor.
+  EF_AMDGPU_MACH_NONE = 0x000,
+
+  // R600-based processors.
+
+  // Radeon HD 2000/3000 Series (R600).
+  EF_AMDGPU_MACH_R600_R600 = 0x001,
+  EF_AMDGPU_MACH_R600_R630 = 0x002,
+  EF_AMDGPU_MACH_R600_RS880 = 0x003,
+  EF_AMDGPU_MACH_R600_RV670 = 0x004,
+  // Radeon HD 4000 Series (R700).
+  EF_AMDGPU_MACH_R600_RV710 = 0x005,
+  EF_AMDGPU_MACH_R600_RV730 = 0x006,
+  EF_AMDGPU_MACH_R600_RV770 = 0x007,
+  // Radeon HD 5000 Series (Evergreen).
+  EF_AMDGPU_MACH_R600_CEDAR = 0x008,
+  EF_AMDGPU_MACH_R600_CYPRESS = 0x009,
+  EF_AMDGPU_MACH_R600_JUNIPER = 0x00a,
+  EF_AMDGPU_MACH_R600_REDWOOD = 0x00b,
+  EF_AMDGPU_MACH_R600_SUMO = 0x00c,
+  // Radeon HD 6000 Series (Northern Islands).
+  EF_AMDGPU_MACH_R600_BARTS = 0x00d,
+  EF_AMDGPU_MACH_R600_CAICOS = 0x00e,
+  EF_AMDGPU_MACH_R600_CAYMAN = 0x00f,
+  EF_AMDGPU_MACH_R600_TURKS = 0x010,
+
+  // Reserved for R600-based processors.
+  EF_AMDGPU_MACH_R600_RESERVED_FIRST = 0x011,
+  EF_AMDGPU_MACH_R600_RESERVED_LAST = 0x01f,
+
+  // First/last R600-based processors.
+  EF_AMDGPU_MACH_R600_FIRST = EF_AMDGPU_MACH_R600_R600,
+  EF_AMDGPU_MACH_R600_LAST = EF_AMDGPU_MACH_R600_TURKS,
+
+  // AMDGCN-based processors.
+
+  // AMDGCN GFX6.
+  EF_AMDGPU_MACH_AMDGCN_GFX600 = 0x020,
+  EF_AMDGPU_MACH_AMDGCN_GFX601 = 0x021,
+  // AMDGCN GFX7.
+  EF_AMDGPU_MACH_AMDGCN_GFX700 = 0x022,
+  EF_AMDGPU_MACH_AMDGCN_GFX701 = 0x023,
+  EF_AMDGPU_MACH_AMDGCN_GFX702 = 0x024,
+  EF_AMDGPU_MACH_AMDGCN_GFX703 = 0x025,
+  EF_AMDGPU_MACH_AMDGCN_GFX704 = 0x026,
+  // AMDGCN GFX8.
+  EF_AMDGPU_MACH_AMDGCN_GFX801 = 0x028,
+  EF_AMDGPU_MACH_AMDGCN_GFX802 = 0x029,
+  EF_AMDGPU_MACH_AMDGCN_GFX803 = 0x02a,
+  EF_AMDGPU_MACH_AMDGCN_GFX810 = 0x02b,
+  // AMDGCN GFX9.
+  EF_AMDGPU_MACH_AMDGCN_GFX900 = 0x02c,
+  EF_AMDGPU_MACH_AMDGCN_GFX902 = 0x02d,
+  EF_AMDGPU_MACH_AMDGCN_GFX904 = 0x02e,
+  EF_AMDGPU_MACH_AMDGCN_GFX906 = 0x02f,
+  EF_AMDGPU_MACH_AMDGCN_GFX908 = 0x030,
+  EF_AMDGPU_MACH_AMDGCN_GFX909 = 0x031,
+  // AMDGCN GFX10.
+  EF_AMDGPU_MACH_AMDGCN_GFX1010 = 0x033,
+  EF_AMDGPU_MACH_AMDGCN_GFX1011 = 0x034,
+  EF_AMDGPU_MACH_AMDGCN_GFX1012 = 0x035,
+
+  // Reserved for AMDGCN-based processors.
+  EF_AMDGPU_MACH_AMDGCN_RESERVED0 = 0x027,
+  EF_AMDGPU_MACH_AMDGCN_RESERVED1 = 0x032,
+
+  // First/last AMDGCN-based processors.
+  EF_AMDGPU_MACH_AMDGCN_FIRST = EF_AMDGPU_MACH_AMDGCN_GFX600,
+  EF_AMDGPU_MACH_AMDGCN_LAST = EF_AMDGPU_MACH_AMDGCN_GFX1012,
+
+  // Indicates if the "xnack" target feature is enabled for all code contained
+  // in the object.
+  EF_AMDGPU_XNACK = 0x100,
+  // Indicates if the "sram-ecc" target feature is enabled for all code
+  // contained in the object.
+  EF_AMDGPU_SRAM_ECC = 0x200,
+};
+
+// ELF Relocation types for AMDGPU
+enum {
+#include "ELFRelocs/AMDGPU.def"
+};
+
+// ELF Relocation types for BPF
+enum {
+#include "ELFRelocs/BPF.def"
+};
+
+// MSP430 specific e_flags
+enum : unsigned {
+  EF_MSP430_MACH_MSP430x11 = 11,
+  EF_MSP430_MACH_MSP430x11x1 = 110,
+  EF_MSP430_MACH_MSP430x12 = 12,
+  EF_MSP430_MACH_MSP430x13 = 13,
+  EF_MSP430_MACH_MSP430x14 = 14,
+  EF_MSP430_MACH_MSP430x15 = 15,
+  EF_MSP430_MACH_MSP430x16 = 16,
+  EF_MSP430_MACH_MSP430x20 = 20,
+  EF_MSP430_MACH_MSP430x22 = 22,
+  EF_MSP430_MACH_MSP430x23 = 23,
+  EF_MSP430_MACH_MSP430x24 = 24,
+  EF_MSP430_MACH_MSP430x26 = 26,
+  EF_MSP430_MACH_MSP430x31 = 31,
+  EF_MSP430_MACH_MSP430x32 = 32,
+  EF_MSP430_MACH_MSP430x33 = 33,
+  EF_MSP430_MACH_MSP430x41 = 41,
+  EF_MSP430_MACH_MSP430x42 = 42,
+  EF_MSP430_MACH_MSP430x43 = 43,
+  EF_MSP430_MACH_MSP430x44 = 44,
+  EF_MSP430_MACH_MSP430X = 45,
+  EF_MSP430_MACH_MSP430x46 = 46,
+  EF_MSP430_MACH_MSP430x47 = 47,
+  EF_MSP430_MACH_MSP430x54 = 54,
+};
+
+// ELF Relocation types for MSP430
+enum {
+#include "ELFRelocs/MSP430.def"
+};
+
+#undef ELF_RELOC
+
+// Section header.
+struct Elf32_Shdr {
+  Elf32_Word sh_name;      // Section name (index into string table)
+  Elf32_Word sh_type;      // Section type (SHT_*)
+  Elf32_Word sh_flags;     // Section flags (SHF_*)
+  Elf32_Addr sh_addr;      // Address where section is to be loaded
+  Elf32_Off sh_offset;     // File offset of section data, in bytes
+  Elf32_Word sh_size;      // Size of section, in bytes
+  Elf32_Word sh_link;      // Section type-specific header table index link
+  Elf32_Word sh_info;      // Section type-specific extra information
+  Elf32_Word sh_addralign; // Section address alignment
+  Elf32_Word sh_entsize;   // Size of records contained within the section
+};
+
+// Section header for ELF64 - same fields as ELF32, different types.
+struct Elf64_Shdr {
+  Elf64_Word sh_name;
+  Elf64_Word sh_type;
+  Elf64_Xword sh_flags;
+  Elf64_Addr sh_addr;
+  Elf64_Off sh_offset;
+  Elf64_Xword sh_size;
+  Elf64_Word sh_link;
+  Elf64_Word sh_info;
+  Elf64_Xword sh_addralign;
+  Elf64_Xword sh_entsize;
+};
+
+// Special section indices.
+enum {
+  SHN_UNDEF = 0,          // Undefined, missing, irrelevant, or meaningless
+  SHN_LORESERVE = 0xff00, // Lowest reserved index
+  SHN_LOPROC = 0xff00,    // Lowest processor-specific index
+  SHN_HIPROC = 0xff1f,    // Highest processor-specific index
+  SHN_LOOS = 0xff20,      // Lowest operating system-specific index
+  SHN_HIOS = 0xff3f,      // Highest operating system-specific index
+  SHN_ABS = 0xfff1,       // Symbol has absolute value; does not need relocation
+  SHN_COMMON = 0xfff2,    // FORTRAN COMMON or C external global variables
+  SHN_XINDEX = 0xffff,    // Mark that the index is >= SHN_LORESERVE
+  SHN_HIRESERVE = 0xffff  // Highest reserved index
+};
+
+// Section types.
+enum : unsigned {
+  SHT_NULL = 0,                         // No associated section (inactive entry).
+  SHT_PROGBITS = 1,                     // Program-defined contents.
+  SHT_SYMTAB = 2,                       // Symbol table.
+  SHT_STRTAB = 3,                       // String table.
+  SHT_RELA = 4,                         // Relocation entries; explicit addends.
+  SHT_HASH = 5,                         // Symbol hash table.
+  SHT_DYNAMIC = 6,                      // Information for dynamic linking.
+  SHT_NOTE = 7,                         // Information about the file.
+  SHT_NOBITS = 8,                       // Data occupies no space in the file.
+  SHT_REL = 9,                          // Relocation entries; no explicit addends.
+  SHT_SHLIB = 10,                       // Reserved.
+  SHT_DYNSYM = 11,                      // Symbol table.
+  SHT_INIT_ARRAY = 14,                  // Pointers to initialization functions.
+  SHT_FINI_ARRAY = 15,                  // Pointers to termination functions.
+  SHT_PREINIT_ARRAY = 16,               // Pointers to pre-init functions.
+  SHT_GROUP = 17,                       // Section group.
+  SHT_SYMTAB_SHNDX = 18,                // Indices for SHN_XINDEX entries.
+  // Experimental support for SHT_RELR sections. For details, see proposal
+  // at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+  SHT_RELR = 19,                        // Relocation entries; only offsets.
+  SHT_LOOS = 0x60000000,                // Lowest operating system-specific type.
+  // Android packed relocation section types.
+  // https://android.googlesource.com/platform/bionic/+/6f12bfece5dcc01325e0abba56a46b1bcf991c69/tools/relocation_packer/src/elf_file.cc#37
+  SHT_ANDROID_REL = 0x60000001,
+  SHT_ANDROID_RELA = 0x60000002,
+  SHT_LLVM_ODRTAB = 0x6fff4c00,         // LLVM ODR table.
+  SHT_LLVM_LINKER_OPTIONS = 0x6fff4c01, // LLVM Linker Options.
+  SHT_LLVM_CALL_GRAPH_PROFILE = 0x6fff4c02, // LLVM Call Graph Profile.
+  SHT_LLVM_ADDRSIG = 0x6fff4c03,        // List of address-significant symbols
+                                        // for safe ICF.
+  SHT_LLVM_DEPENDENT_LIBRARIES = 0x6fff4c04, // LLVM Dependent Library Specifiers.
+  SHT_LLVM_SYMPART = 0x6fff4c05,        // Symbol partition specification.
+  SHT_LLVM_PART_EHDR = 0x6fff4c06,      // ELF header for loadable partition.
+  SHT_LLVM_PART_PHDR = 0x6fff4c07,      // Phdrs for loadable partition.
+  // Android's experimental support for SHT_RELR sections.
+  // https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512
+  SHT_ANDROID_RELR = 0x6fffff00,        // Relocation entries; only offsets.
+  SHT_GNU_ATTRIBUTES = 0x6ffffff5,      // Object attributes.
+  SHT_GNU_HASH = 0x6ffffff6,            // GNU-style hash table.
+  SHT_GNU_verdef = 0x6ffffffd,          // GNU version definitions.
+  SHT_GNU_verneed = 0x6ffffffe,         // GNU version references.
+  SHT_GNU_versym = 0x6fffffff,          // GNU symbol versions table.
+  SHT_HIOS = 0x6fffffff,                // Highest operating system-specific type.
+  SHT_LOPROC = 0x70000000,              // Lowest processor arch-specific type.
+  // Fixme: All this is duplicated in MCSectionELF. Why??
+  // Exception Index table
+  SHT_ARM_EXIDX = 0x70000001U,
+  // BPABI DLL dynamic linking pre-emption map
+  SHT_ARM_PREEMPTMAP = 0x70000002U,
+  //  Object file compatibility attributes
+  SHT_ARM_ATTRIBUTES = 0x70000003U,
+  SHT_ARM_DEBUGOVERLAY = 0x70000004U,
+  SHT_ARM_OVERLAYSECTION = 0x70000005U,
+  SHT_HEX_ORDERED = 0x70000000,         // Link editor is to sort the entries in
+                                        // this section based on their sizes
+  SHT_X86_64_UNWIND = 0x70000001,       // Unwind information
+
+  SHT_MIPS_REGINFO = 0x70000006,        // Register usage information
+  SHT_MIPS_OPTIONS = 0x7000000d,        // General options
+  SHT_MIPS_DWARF = 0x7000001e,          // DWARF debugging section.
+  SHT_MIPS_ABIFLAGS = 0x7000002a,       // ABI information.
+
+  SHT_MSP430_ATTRIBUTES = 0x70000003U,
+
+  SHT_HIPROC = 0x7fffffff,              // Highest processor arch-specific type.
+  SHT_LOUSER = 0x80000000,              // Lowest type reserved for applications.
+  SHT_HIUSER = 0xffffffff               // Highest type reserved for applications.
+};
+
+// Section flags.
+enum : unsigned {
+  // Section data should be writable during execution.
+  SHF_WRITE = 0x1,
+
+  // Section occupies memory during program execution.
+  SHF_ALLOC = 0x2,
+
+  // Section contains executable machine instructions.
+  SHF_EXECINSTR = 0x4,
+
+  // The data in this section may be merged.
+  SHF_MERGE = 0x10,
+
+  // The data in this section is null-terminated strings.
+  SHF_STRINGS = 0x20,
+
+  // A field in this section holds a section header table index.
+  SHF_INFO_LINK = 0x40U,
+
+  // Adds special ordering requirements for link editors.
+  SHF_LINK_ORDER = 0x80U,
+
+  // This section requires special OS-specific processing to avoid incorrect
+  // behavior.
+  SHF_OS_NONCONFORMING = 0x100U,
+
+  // This section is a member of a section group.
+  SHF_GROUP = 0x200U,
+
+  // This section holds Thread-Local Storage.
+  SHF_TLS = 0x400U,
+
+  // Identifies a section containing compressed data.
+  SHF_COMPRESSED = 0x800U,
+
+  // This section is excluded from the final executable or shared library.
+  SHF_EXCLUDE = 0x80000000U,
+
+  // Start of target-specific flags.
+
+  SHF_MASKOS = 0x0ff00000,
+
+  // Bits indicating processor-specific flags.
+  SHF_MASKPROC = 0xf0000000,
+
+  /// All sections with the "d" flag are grouped together by the linker to form
+  /// the data section and the dp register is set to the start of the section by
+  /// the boot code.
+  XCORE_SHF_DP_SECTION = 0x10000000,
+
+  /// All sections with the "c" flag are grouped together by the linker to form
+  /// the constant pool and the cp register is set to the start of the constant
+  /// pool by the boot code.
+  XCORE_SHF_CP_SECTION = 0x20000000,
+
+  // If an object file section does not have this flag set, then it may not hold
+  // more than 2GB and can be freely referred to in objects using smaller code
+  // models. Otherwise, only objects using larger code models can refer to them.
+  // For example, a medium code model object can refer to data in a section that
+  // sets this flag besides being able to refer to data in a section that does
+  // not set it; likewise, a small code model object can refer only to code in a
+  // section that does not set this flag.
+  SHF_X86_64_LARGE = 0x10000000,
+
+  // All sections with the GPREL flag are grouped into a global data area
+  // for faster accesses
+  SHF_HEX_GPREL = 0x10000000,
+
+  // Section contains text/data which may be replicated in other sections.
+  // Linker must retain only one copy.
+  SHF_MIPS_NODUPES = 0x01000000,
+
+  // Linker must generate implicit hidden weak names.
+  SHF_MIPS_NAMES = 0x02000000,
+
+  // Section data local to process.
+  SHF_MIPS_LOCAL = 0x04000000,
+
+  // Do not strip this section.
+  SHF_MIPS_NOSTRIP = 0x08000000,
+
+  // Section must be part of global data area.
+  SHF_MIPS_GPREL = 0x10000000,
+
+  // This section should be merged.
+  SHF_MIPS_MERGE = 0x20000000,
+
+  // Address size to be inferred from section entry size.
+  SHF_MIPS_ADDR = 0x40000000,
+
+  // Section data is string data by default.
+  SHF_MIPS_STRING = 0x80000000,
+
+  // Make code section unreadable when in execute-only mode
+  SHF_ARM_PURECODE = 0x20000000
+};
+
+// Section Group Flags
+enum : unsigned {
+  GRP_COMDAT = 0x1,
+  GRP_MASKOS = 0x0ff00000,
+  GRP_MASKPROC = 0xf0000000
+};
+
+// Symbol table entries for ELF32.
+struct Elf32_Sym {
+  Elf32_Word st_name;     // Symbol name (index into string table)
+  Elf32_Addr st_value;    // Value or address associated with the symbol
+  Elf32_Word st_size;     // Size of the symbol
+  unsigned char st_info;  // Symbol's type and binding attributes
+  unsigned char st_other; // Must be zero; reserved
+  Elf32_Half st_shndx;    // Which section (header table index) it's defined in
+
+  // These accessors and mutators correspond to the ELF32_ST_BIND,
+  // ELF32_ST_TYPE, and ELF32_ST_INFO macros defined in the ELF specification:
+  unsigned char getBinding() const { return st_info >> 4; }
+  unsigned char getType() const { return st_info & 0x0f; }
+  void setBinding(unsigned char b) { setBindingAndType(b, getType()); }
+  void setType(unsigned char t) { setBindingAndType(getBinding(), t); }
+  void setBindingAndType(unsigned char b, unsigned char t) {
+    st_info = (b << 4) + (t & 0x0f);
+  }
+};
+
+// Symbol table entries for ELF64.
+struct Elf64_Sym {
+  Elf64_Word st_name;     // Symbol name (index into string table)
+  unsigned char st_info;  // Symbol's type and binding attributes
+  unsigned char st_other; // Must be zero; reserved
+  Elf64_Half st_shndx;    // Which section (header tbl index) it's defined in
+  Elf64_Addr st_value;    // Value or address associated with the symbol
+  Elf64_Xword st_size;    // Size of the symbol
+
+  // These accessors and mutators are identical to those defined for ELF32
+  // symbol table entries.
+  unsigned char getBinding() const { return st_info >> 4; }
+  unsigned char getType() const { return st_info & 0x0f; }
+  void setBinding(unsigned char b) { setBindingAndType(b, getType()); }
+  void setType(unsigned char t) { setBindingAndType(getBinding(), t); }
+  void setBindingAndType(unsigned char b, unsigned char t) {
+    st_info = (b << 4) + (t & 0x0f);
+  }
+};
+
+// The size (in bytes) of symbol table entries.
+enum {
+  SYMENTRY_SIZE32 = 16, // 32-bit symbol entry size
+  SYMENTRY_SIZE64 = 24  // 64-bit symbol entry size.
+};
+
+// Symbol bindings.
+enum {
+  STB_LOCAL = 0,  // Local symbol, not visible outside obj file containing def
+  STB_GLOBAL = 1, // Global symbol, visible to all object files being combined
+  STB_WEAK = 2,   // Weak symbol, like global but lower-precedence
+  STB_GNU_UNIQUE = 10,
+  STB_LOOS = 10,   // Lowest operating system-specific binding type
+  STB_HIOS = 12,   // Highest operating system-specific binding type
+  STB_LOPROC = 13, // Lowest processor-specific binding type
+  STB_HIPROC = 15  // Highest processor-specific binding type
+};
+
+// Symbol types.
+enum {
+  STT_NOTYPE = 0,     // Symbol's type is not specified
+  STT_OBJECT = 1,     // Symbol is a data object (variable, array, etc.)
+  STT_FUNC = 2,       // Symbol is executable code (function, etc.)
+  STT_SECTION = 3,    // Symbol refers to a section
+  STT_FILE = 4,       // Local, absolute symbol that refers to a file
+  STT_COMMON = 5,     // An uninitialized common block
+  STT_TLS = 6,        // Thread local data object
+  STT_GNU_IFUNC = 10, // GNU indirect function
+  STT_LOOS = 10,      // Lowest operating system-specific symbol type
+  STT_HIOS = 12,      // Highest operating system-specific symbol type
+  STT_LOPROC = 13,    // Lowest processor-specific symbol type
+  STT_HIPROC = 15,    // Highest processor-specific symbol type
+
+  // AMDGPU symbol types
+  STT_AMDGPU_HSA_KERNEL = 10
+};
+
+enum {
+  STV_DEFAULT = 0,  // Visibility is specified by binding type
+  STV_INTERNAL = 1, // Defined by processor supplements
+  STV_HIDDEN = 2,   // Not visible to other components
+  STV_PROTECTED = 3 // Visible in other components but not preemptable
+};
+
+// Symbol number.
+enum { STN_UNDEF = 0 };
+
+// Special relocation symbols used in the MIPS64 ELF relocation entries
+enum {
+  RSS_UNDEF = 0, // None
+  RSS_GP = 1,    // Value of gp
+  RSS_GP0 = 2,   // Value of gp used to create object being relocated
+  RSS_LOC = 3    // Address of location being relocated
+};
+
+// Relocation entry, without explicit addend.
+struct Elf32_Rel {
+  Elf32_Addr r_offset; // Location (file byte offset, or program virtual addr)
+  Elf32_Word r_info;   // Symbol table index and type of relocation to apply
+
+  // These accessors and mutators correspond to the ELF32_R_SYM, ELF32_R_TYPE,
+  // and ELF32_R_INFO macros defined in the ELF specification:
+  Elf32_Word getSymbol() const { return (r_info >> 8); }
+  unsigned char getType() const { return (unsigned char)(r_info & 0x0ff); }
+  void setSymbol(Elf32_Word s) { setSymbolAndType(s, getType()); }
+  void setType(unsigned char t) { setSymbolAndType(getSymbol(), t); }
+  void setSymbolAndType(Elf32_Word s, unsigned char t) {
+    r_info = (s << 8) + t;
+  }
+};
+
+// Relocation entry with explicit addend.
+struct Elf32_Rela {
+  Elf32_Addr r_offset;  // Location (file byte offset, or program virtual addr)
+  Elf32_Word r_info;    // Symbol table index and type of relocation to apply
+  Elf32_Sword r_addend; // Compute value for relocatable field by adding this
+
+  // These accessors and mutators correspond to the ELF32_R_SYM, ELF32_R_TYPE,
+  // and ELF32_R_INFO macros defined in the ELF specification:
+  Elf32_Word getSymbol() const { return (r_info >> 8); }
+  unsigned char getType() const { return (unsigned char)(r_info & 0x0ff); }
+  void setSymbol(Elf32_Word s) { setSymbolAndType(s, getType()); }
+  void setType(unsigned char t) { setSymbolAndType(getSymbol(), t); }
+  void setSymbolAndType(Elf32_Word s, unsigned char t) {
+    r_info = (s << 8) + t;
+  }
+};
+
+// Relocation entry without explicit addend or info (relative relocations only).
+typedef Elf32_Word Elf32_Relr; // offset/bitmap for relative relocations
+
+// Relocation entry, without explicit addend.
+struct Elf64_Rel {
+  Elf64_Addr r_offset; // Location (file byte offset, or program virtual addr).
+  Elf64_Xword r_info;  // Symbol table index and type of relocation to apply.
+
+  // These accessors and mutators correspond to the ELF64_R_SYM, ELF64_R_TYPE,
+  // and ELF64_R_INFO macros defined in the ELF specification:
+  Elf64_Word getSymbol() const { return (r_info >> 32); }
+  Elf64_Word getType() const { return (Elf64_Word)(r_info & 0xffffffffL); }
+  void setSymbol(Elf64_Word s) { setSymbolAndType(s, getType()); }
+  void setType(Elf64_Word t) { setSymbolAndType(getSymbol(), t); }
+  void setSymbolAndType(Elf64_Word s, Elf64_Word t) {
+    r_info = ((Elf64_Xword)s << 32) + (t & 0xffffffffL);
+  }
+};
+
+// Relocation entry with explicit addend.
+struct Elf64_Rela {
+  Elf64_Addr r_offset; // Location (file byte offset, or program virtual addr).
+  Elf64_Xword r_info;  // Symbol table index and type of relocation to apply.
+  Elf64_Sxword r_addend; // Compute value for relocatable field by adding this.
+
+  // These accessors and mutators correspond to the ELF64_R_SYM, ELF64_R_TYPE,
+  // and ELF64_R_INFO macros defined in the ELF specification:
+  Elf64_Word getSymbol() const { return (r_info >> 32); }
+  Elf64_Word getType() const { return (Elf64_Word)(r_info & 0xffffffffL); }
+  void setSymbol(Elf64_Word s) { setSymbolAndType(s, getType()); }
+  void setType(Elf64_Word t) { setSymbolAndType(getSymbol(), t); }
+  void setSymbolAndType(Elf64_Word s, Elf64_Word t) {
+    r_info = ((Elf64_Xword)s << 32) + (t & 0xffffffffL);
+  }
+};
+
+// Relocation entry without explicit addend or info (relative relocations only).
+typedef Elf64_Xword Elf64_Relr; // offset/bitmap for relative relocations
+
+// Program header for ELF32.
+struct Elf32_Phdr {
+  Elf32_Word p_type;   // Type of segment
+  Elf32_Off p_offset;  // File offset where segment is located, in bytes
+  Elf32_Addr p_vaddr;  // Virtual address of beginning of segment
+  Elf32_Addr p_paddr;  // Physical address of beginning of segment (OS-specific)
+  Elf32_Word p_filesz; // Num. of bytes in file image of segment (may be zero)
+  Elf32_Word p_memsz;  // Num. of bytes in mem image of segment (may be zero)
+  Elf32_Word p_flags;  // Segment flags
+  Elf32_Word p_align;  // Segment alignment constraint
+};
+
+// Program header for ELF64.
+struct Elf64_Phdr {
+  Elf64_Word p_type;    // Type of segment
+  Elf64_Word p_flags;   // Segment flags
+  Elf64_Off p_offset;   // File offset where segment is located, in bytes
+  Elf64_Addr p_vaddr;   // Virtual address of beginning of segment
+  Elf64_Addr p_paddr;   // Physical addr of beginning of segment (OS-specific)
+  Elf64_Xword p_filesz; // Num. of bytes in file image of segment (may be zero)
+  Elf64_Xword p_memsz;  // Num. of bytes in mem image of segment (may be zero)
+  Elf64_Xword p_align;  // Segment alignment constraint
+};
+
+// Segment types.
+enum {
+  PT_NULL = 0,            // Unused segment.
+  PT_LOAD = 1,            // Loadable segment.
+  PT_DYNAMIC = 2,         // Dynamic linking information.
+  PT_INTERP = 3,          // Interpreter pathname.
+  PT_NOTE = 4,            // Auxiliary information.
+  PT_SHLIB = 5,           // Reserved.
+  PT_PHDR = 6,            // The program header table itself.
+  PT_TLS = 7,             // The thread-local storage template.
+  PT_LOOS = 0x60000000,   // Lowest operating system-specific pt entry type.
+  PT_HIOS = 0x6fffffff,   // Highest operating system-specific pt entry type.
+  PT_LOPROC = 0x70000000, // Lowest processor-specific program hdr entry type.
+  PT_HIPROC = 0x7fffffff, // Highest processor-specific program hdr entry type.
+
+  // x86-64 program header types.
+  // These all contain stack unwind tables.
+  PT_GNU_EH_FRAME = 0x6474e550,
+  PT_SUNW_EH_FRAME = 0x6474e550,
+  PT_SUNW_UNWIND = 0x6464e550,
+
+  PT_GNU_STACK = 0x6474e551, // Indicates stack executability.
+  PT_GNU_RELRO = 0x6474e552, // Read-only after relocation.
+
+  PT_OPENBSD_RANDOMIZE = 0x65a3dbe6, // Fill with random data.
+  PT_OPENBSD_WXNEEDED = 0x65a3dbe7,  // Program does W^X violations.
+  PT_OPENBSD_BOOTDATA = 0x65a41be6,  // Section for boot arguments.
+
+  // ARM program header types.
+  PT_ARM_ARCHEXT = 0x70000000, // Platform architecture compatibility info
+  // These all contain stack unwind tables.
+  PT_ARM_EXIDX = 0x70000001,
+  PT_ARM_UNWIND = 0x70000001,
+
+  // MIPS program header types.
+  PT_MIPS_REGINFO = 0x70000000,  // Register usage information.
+  PT_MIPS_RTPROC = 0x70000001,   // Runtime procedure table.
+  PT_MIPS_OPTIONS = 0x70000002,  // Options segment.
+  PT_MIPS_ABIFLAGS = 0x70000003, // Abiflags segment.
+};
+
+// Segment flag bits.
+enum : unsigned {
+  PF_X = 1,                // Execute
+  PF_W = 2,                // Write
+  PF_R = 4,                // Read
+  PF_MASKOS = 0x0ff00000,  // Bits for operating system-specific semantics.
+  PF_MASKPROC = 0xf0000000 // Bits for processor-specific semantics.
+};
+
+// Dynamic table entry for ELF32.
+struct Elf32_Dyn {
+  Elf32_Sword d_tag; // Type of dynamic table entry.
+  union {
+    Elf32_Word d_val; // Integer value of entry.
+    Elf32_Addr d_ptr; // Pointer value of entry.
+  } d_un;
+};
+
+// Dynamic table entry for ELF64.
+struct Elf64_Dyn {
+  Elf64_Sxword d_tag; // Type of dynamic table entry.
+  union {
+    Elf64_Xword d_val; // Integer value of entry.
+    Elf64_Addr d_ptr;  // Pointer value of entry.
+  } d_un;
+};
+
+// Dynamic table entry tags.
+enum {
+#define DYNAMIC_TAG(name, value) DT_##name = value,
+#include "DynamicTags.def"
+#undef DYNAMIC_TAG
+};
+
+// DT_FLAGS values.
+enum {
+  DF_ORIGIN = 0x01,    // The object may reference $ORIGIN.
+  DF_SYMBOLIC = 0x02,  // Search the shared lib before searching the exe.
+  DF_TEXTREL = 0x04,   // Relocations may modify a non-writable segment.
+  DF_BIND_NOW = 0x08,  // Process all relocations on load.
+  DF_STATIC_TLS = 0x10 // Reject attempts to load dynamically.
+};
+
+// State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 entry.
+enum {
+  DF_1_NOW = 0x00000001,       // Set RTLD_NOW for this object.
+  DF_1_GLOBAL = 0x00000002,    // Set RTLD_GLOBAL for this object.
+  DF_1_GROUP = 0x00000004,     // Set RTLD_GROUP for this object.
+  DF_1_NODELETE = 0x00000008,  // Set RTLD_NODELETE for this object.
+  DF_1_LOADFLTR = 0x00000010,  // Trigger filtee loading at runtime.
+  DF_1_INITFIRST = 0x00000020, // Set RTLD_INITFIRST for this object.
+  DF_1_NOOPEN = 0x00000040,    // Set RTLD_NOOPEN for this object.
+  DF_1_ORIGIN = 0x00000080,    // $ORIGIN must be handled.
+  DF_1_DIRECT = 0x00000100,    // Direct binding enabled.
+  DF_1_TRANS = 0x00000200,
+  DF_1_INTERPOSE = 0x00000400,  // Object is used to interpose.
+  DF_1_NODEFLIB = 0x00000800,   // Ignore default lib search path.
+  DF_1_NODUMP = 0x00001000,     // Object can't be dldump'ed.
+  DF_1_CONFALT = 0x00002000,    // Configuration alternative created.
+  DF_1_ENDFILTEE = 0x00004000,  // Filtee terminates filters search.
+  DF_1_DISPRELDNE = 0x00008000, // Disp reloc applied at build time.
+  DF_1_DISPRELPND = 0x00010000, // Disp reloc applied at run-time.
+  DF_1_NODIRECT = 0x00020000,   // Object has no-direct binding.
+  DF_1_IGNMULDEF = 0x00040000,
+  DF_1_NOKSYMS = 0x00080000,
+  DF_1_NOHDR = 0x00100000,
+  DF_1_EDITED = 0x00200000, // Object is modified after built.
+  DF_1_NORELOC = 0x00400000,
+  DF_1_SYMINTPOSE = 0x00800000, // Object has individual interposers.
+  DF_1_GLOBAUDIT = 0x01000000,  // Global auditing required.
+  DF_1_SINGLETON = 0x02000000   // Singleton symbols are used.
+};
+
+// DT_MIPS_FLAGS values.
+enum {
+  RHF_NONE = 0x00000000,                   // No flags.
+  RHF_QUICKSTART = 0x00000001,             // Uses shortcut pointers.
+  RHF_NOTPOT = 0x00000002,                 // Hash size is not a power of two.
+  RHS_NO_LIBRARY_REPLACEMENT = 0x00000004, // Ignore LD_LIBRARY_PATH.
+  RHF_NO_MOVE = 0x00000008,                // DSO address may not be relocated.
+  RHF_SGI_ONLY = 0x00000010,               // SGI specific features.
+  RHF_GUARANTEE_INIT = 0x00000020,         // Guarantee that .init will finish
+                                           // executing before any non-init
+                                           // code in DSO is called.
+  RHF_DELTA_C_PLUS_PLUS = 0x00000040,      // Contains Delta C++ code.
+  RHF_GUARANTEE_START_INIT = 0x00000080,   // Guarantee that .init will start
+                                           // executing before any non-init
+                                           // code in DSO is called.
+  RHF_PIXIE = 0x00000100,                  // Generated by pixie.
+  RHF_DEFAULT_DELAY_LOAD = 0x00000200,     // Delay-load DSO by default.
+  RHF_REQUICKSTART = 0x00000400,           // Object may be requickstarted
+  RHF_REQUICKSTARTED = 0x00000800,         // Object has been requickstarted
+  RHF_CORD = 0x00001000,                   // Generated by cord.
+  RHF_NO_UNRES_UNDEF = 0x00002000,         // Object contains no unresolved
+                                           // undef symbols.
+  RHF_RLD_ORDER_SAFE = 0x00004000          // Symbol table is in a safe order.
+};
+
+// ElfXX_VerDef structure version (GNU versioning)
+enum { VER_DEF_NONE = 0, VER_DEF_CURRENT = 1 };
+
+// VerDef Flags (ElfXX_VerDef::vd_flags)
+enum { VER_FLG_BASE = 0x1, VER_FLG_WEAK = 0x2, VER_FLG_INFO = 0x4 };
+
+// Special constants for the version table. (SHT_GNU_versym/.gnu.version)
+enum {
+  VER_NDX_LOCAL = 0,       // Unversioned local symbol
+  VER_NDX_GLOBAL = 1,      // Unversioned global symbol
+  VERSYM_VERSION = 0x7fff, // Version Index mask
+  VERSYM_HIDDEN = 0x8000   // Hidden bit (non-default version)
+};
+
+// ElfXX_VerNeed structure version (GNU versioning)
+enum { VER_NEED_NONE = 0, VER_NEED_CURRENT = 1 };
+
+// SHT_NOTE section types
+enum {
+  NT_FREEBSD_THRMISC = 7,
+  NT_FREEBSD_PROCSTAT_PROC = 8,
+  NT_FREEBSD_PROCSTAT_FILES = 9,
+  NT_FREEBSD_PROCSTAT_VMMAP = 10,
+  NT_FREEBSD_PROCSTAT_GROUPS = 11,
+  NT_FREEBSD_PROCSTAT_UMASK = 12,
+  NT_FREEBSD_PROCSTAT_RLIMIT = 13,
+  NT_FREEBSD_PROCSTAT_OSREL = 14,
+  NT_FREEBSD_PROCSTAT_PSSTRINGS = 15,
+  NT_FREEBSD_PROCSTAT_AUXV = 16,
+};
+
+// Generic note types
+enum : unsigned {
+  NT_VERSION = 1,
+  NT_ARCH = 2,
+  NT_GNU_BUILD_ATTRIBUTE_OPEN = 0x100,
+  NT_GNU_BUILD_ATTRIBUTE_FUNC = 0x101,
+};
+
+// Core note types
+enum : unsigned {
+  NT_PRSTATUS = 1,
+  NT_FPREGSET = 2,
+  NT_PRPSINFO = 3,
+  NT_TASKSTRUCT = 4,
+  NT_AUXV = 6,
+  NT_PSTATUS = 10,
+  NT_FPREGS = 12,
+  NT_PSINFO = 13,
+  NT_LWPSTATUS = 16,
+  NT_LWPSINFO = 17,
+  NT_WIN32PSTATUS = 18,
+
+  NT_PPC_VMX = 0x100,
+  NT_PPC_VSX = 0x102,
+  NT_PPC_TAR = 0x103,
+  NT_PPC_PPR = 0x104,
+  NT_PPC_DSCR = 0x105,
+  NT_PPC_EBB = 0x106,
+  NT_PPC_PMU = 0x107,
+  NT_PPC_TM_CGPR = 0x108,
+  NT_PPC_TM_CFPR = 0x109,
+  NT_PPC_TM_CVMX = 0x10a,
+  NT_PPC_TM_CVSX = 0x10b,
+  NT_PPC_TM_SPR = 0x10c,
+  NT_PPC_TM_CTAR = 0x10d,
+  NT_PPC_TM_CPPR = 0x10e,
+  NT_PPC_TM_CDSCR = 0x10f,
+
+  NT_386_TLS = 0x200,
+  NT_386_IOPERM = 0x201,
+  NT_X86_XSTATE = 0x202,
+
+  NT_S390_HIGH_GPRS = 0x300,
+  NT_S390_TIMER = 0x301,
+  NT_S390_TODCMP = 0x302,
+  NT_S390_TODPREG = 0x303,
+  NT_S390_CTRS = 0x304,
+  NT_S390_PREFIX = 0x305,
+  NT_S390_LAST_BREAK = 0x306,
+  NT_S390_SYSTEM_CALL = 0x307,
+  NT_S390_TDB = 0x308,
+  NT_S390_VXRS_LOW = 0x309,
+  NT_S390_VXRS_HIGH = 0x30a,
+  NT_S390_GS_CB = 0x30b,
+  NT_S390_GS_BC = 0x30c,
+
+  NT_ARM_VFP = 0x400,
+  NT_ARM_TLS = 0x401,
+  NT_ARM_HW_BREAK = 0x402,
+  NT_ARM_HW_WATCH = 0x403,
+  NT_ARM_SVE = 0x405,
+  NT_ARM_PAC_MASK = 0x406,
+
+  NT_FILE = 0x46494c45,
+  NT_PRXFPREG = 0x46e62b7f,
+  NT_SIGINFO = 0x53494749,
+};
+
+// LLVM-specific notes.
+enum {
+  NT_LLVM_HWASAN_GLOBALS = 3,
+};
+
+// GNU note types
+enum {
+  NT_GNU_ABI_TAG = 1,
+  NT_GNU_HWCAP = 2,
+  NT_GNU_BUILD_ID = 3,
+  NT_GNU_GOLD_VERSION = 4,
+  NT_GNU_PROPERTY_TYPE_0 = 5,
+};
+
+// Property types used in GNU_PROPERTY_TYPE_0 notes.
+enum : unsigned {
+  GNU_PROPERTY_STACK_SIZE = 1,
+  GNU_PROPERTY_NO_COPY_ON_PROTECTED = 2,
+  GNU_PROPERTY_AARCH64_FEATURE_1_AND = 0xc0000000,
+  GNU_PROPERTY_X86_FEATURE_1_AND = 0xc0000002,
+  GNU_PROPERTY_X86_ISA_1_NEEDED = 0xc0008000,
+  GNU_PROPERTY_X86_FEATURE_2_NEEDED = 0xc0008001,
+  GNU_PROPERTY_X86_ISA_1_USED = 0xc0010000,
+  GNU_PROPERTY_X86_FEATURE_2_USED = 0xc0010001,
+};
+
+// aarch64 processor feature bits.
+enum : unsigned {
+  GNU_PROPERTY_AARCH64_FEATURE_1_BTI = 1 << 0,
+  GNU_PROPERTY_AARCH64_FEATURE_1_PAC = 1 << 1,
+};
+
+// x86 processor feature bits.
+enum : unsigned {
+  GNU_PROPERTY_X86_FEATURE_1_IBT = 1 << 0,
+  GNU_PROPERTY_X86_FEATURE_1_SHSTK = 1 << 1,
+
+  GNU_PROPERTY_X86_ISA_1_CMOV = 1 << 0,
+  GNU_PROPERTY_X86_ISA_1_SSE = 1 << 1,
+  GNU_PROPERTY_X86_ISA_1_SSE2 = 1 << 2,
+  GNU_PROPERTY_X86_ISA_1_SSE3 = 1 << 3,
+  GNU_PROPERTY_X86_ISA_1_SSSE3 = 1 << 4,
+  GNU_PROPERTY_X86_ISA_1_SSE4_1 = 1 << 5,
+  GNU_PROPERTY_X86_ISA_1_SSE4_2 = 1 << 6,
+  GNU_PROPERTY_X86_ISA_1_AVX = 1 << 7,
+  GNU_PROPERTY_X86_ISA_1_AVX2 = 1 << 8,
+  GNU_PROPERTY_X86_ISA_1_FMA = 1 << 9,
+  GNU_PROPERTY_X86_ISA_1_AVX512F = 1 << 10,
+  GNU_PROPERTY_X86_ISA_1_AVX512CD = 1 << 11,
+  GNU_PROPERTY_X86_ISA_1_AVX512ER = 1 << 12,
+  GNU_PROPERTY_X86_ISA_1_AVX512PF = 1 << 13,
+  GNU_PROPERTY_X86_ISA_1_AVX512VL = 1 << 14,
+  GNU_PROPERTY_X86_ISA_1_AVX512DQ = 1 << 15,
+  GNU_PROPERTY_X86_ISA_1_AVX512BW = 1 << 16,
+  GNU_PROPERTY_X86_ISA_1_AVX512_4FMAPS = 1 << 17,
+  GNU_PROPERTY_X86_ISA_1_AVX512_4VNNIW = 1 << 18,
+  GNU_PROPERTY_X86_ISA_1_AVX512_BITALG = 1 << 19,
+  GNU_PROPERTY_X86_ISA_1_AVX512_IFMA = 1 << 20,
+  GNU_PROPERTY_X86_ISA_1_AVX512_VBMI = 1 << 21,
+  GNU_PROPERTY_X86_ISA_1_AVX512_VBMI2 = 1 << 22,
+  GNU_PROPERTY_X86_ISA_1_AVX512_VNNI = 1 << 23,
+
+  GNU_PROPERTY_X86_FEATURE_2_X86 = 1 << 0,
+  GNU_PROPERTY_X86_FEATURE_2_X87 = 1 << 1,
+  GNU_PROPERTY_X86_FEATURE_2_MMX = 1 << 2,
+  GNU_PROPERTY_X86_FEATURE_2_XMM = 1 << 3,
+  GNU_PROPERTY_X86_FEATURE_2_YMM = 1 << 4,
+  GNU_PROPERTY_X86_FEATURE_2_ZMM = 1 << 5,
+  GNU_PROPERTY_X86_FEATURE_2_FXSR = 1 << 6,
+  GNU_PROPERTY_X86_FEATURE_2_XSAVE = 1 << 7,
+  GNU_PROPERTY_X86_FEATURE_2_XSAVEOPT = 1 << 8,
+  GNU_PROPERTY_X86_FEATURE_2_XSAVEC = 1 << 9,
+};
+
+// AMDGPU-specific section indices.
+enum {
+  SHN_AMDGPU_LDS = 0xff00, // Variable in LDS; symbol encoded like SHN_COMMON
+};
+
+// AMD specific notes. (Code Object V2)
+enum {
+  // Note types with values between 0 and 9 (inclusive) are reserved.
+  NT_AMD_AMDGPU_HSA_METADATA = 10,
+  NT_AMD_AMDGPU_ISA = 11,
+  NT_AMD_AMDGPU_PAL_METADATA = 12
+};
+
+// AMDGPU specific notes. (Code Object V3)
+enum {
+  // Note types with values between 0 and 31 (inclusive) are reserved.
+  NT_AMDGPU_METADATA = 32
+};
+
+enum {
+  GNU_ABI_TAG_LINUX = 0,
+  GNU_ABI_TAG_HURD = 1,
+  GNU_ABI_TAG_SOLARIS = 2,
+  GNU_ABI_TAG_FREEBSD = 3,
+  GNU_ABI_TAG_NETBSD = 4,
+  GNU_ABI_TAG_SYLLABLE = 5,
+  GNU_ABI_TAG_NACL = 6,
+};
+
+constexpr const char *ELF_NOTE_GNU = "GNU";
+
+// Android packed relocation group flags.
+enum {
+  RELOCATION_GROUPED_BY_INFO_FLAG = 1,
+  RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 2,
+  RELOCATION_GROUPED_BY_ADDEND_FLAG = 4,
+  RELOCATION_GROUP_HAS_ADDEND_FLAG = 8,
+};
+
+// Compressed section header for ELF32.
+struct Elf32_Chdr {
+  Elf32_Word ch_type;
+  Elf32_Word ch_size;
+  Elf32_Word ch_addralign;
+};
+
+// Compressed section header for ELF64.
+struct Elf64_Chdr {
+  Elf64_Word ch_type;
+  Elf64_Word ch_reserved;
+  Elf64_Xword ch_size;
+  Elf64_Xword ch_addralign;
+};
+
+// Node header for ELF32.
+struct Elf32_Nhdr {
+  Elf32_Word n_namesz;
+  Elf32_Word n_descsz;
+  Elf32_Word n_type;
+};
+
+// Node header for ELF64.
+struct Elf64_Nhdr {
+  Elf64_Word n_namesz;
+  Elf64_Word n_descsz;
+  Elf64_Word n_type;
+};
+
+// Legal values for ch_type field of compressed section header.
+enum {
+  ELFCOMPRESS_ZLIB = 1,            // ZLIB/DEFLATE algorithm.
+  ELFCOMPRESS_LOOS = 0x60000000,   // Start of OS-specific.
+  ELFCOMPRESS_HIOS = 0x6fffffff,   // End of OS-specific.
+  ELFCOMPRESS_LOPROC = 0x70000000, // Start of processor-specific.
+  ELFCOMPRESS_HIPROC = 0x7fffffff  // End of processor-specific.
+};
+
+} // end namespace ELF
+} // end namespace llvm
+
+#endif // LLVM_BINARYFORMAT_ELF_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/AArch64.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/AArch64.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/AArch64.def
@@ -0,0 +1,221 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+// Based on ABI release 1.1-beta, dated 6 November 2013. NB: The cover page of
+// this document, IHI0056C_beta_aaelf64.pdf, on infocenter.arm.com, still
+// labels this as release 1.0.
+ELF_RELOC(R_AARCH64_NONE,                                0)
+ELF_RELOC(R_AARCH64_ABS64,                           0x101)
+ELF_RELOC(R_AARCH64_ABS32,                           0x102)
+ELF_RELOC(R_AARCH64_ABS16,                           0x103)
+ELF_RELOC(R_AARCH64_PREL64,                          0x104)
+ELF_RELOC(R_AARCH64_PREL32,                          0x105)
+ELF_RELOC(R_AARCH64_PREL16,                          0x106)
+ELF_RELOC(R_AARCH64_MOVW_UABS_G0,                    0x107)
+ELF_RELOC(R_AARCH64_MOVW_UABS_G0_NC,                 0x108)
+ELF_RELOC(R_AARCH64_MOVW_UABS_G1,                    0x109)
+ELF_RELOC(R_AARCH64_MOVW_UABS_G1_NC,                 0x10a)
+ELF_RELOC(R_AARCH64_MOVW_UABS_G2,                    0x10b)
+ELF_RELOC(R_AARCH64_MOVW_UABS_G2_NC,                 0x10c)
+ELF_RELOC(R_AARCH64_MOVW_UABS_G3,                    0x10d)
+ELF_RELOC(R_AARCH64_MOVW_SABS_G0,                    0x10e)
+ELF_RELOC(R_AARCH64_MOVW_SABS_G1,                    0x10f)
+ELF_RELOC(R_AARCH64_MOVW_SABS_G2,                    0x110)
+ELF_RELOC(R_AARCH64_LD_PREL_LO19,                    0x111)
+ELF_RELOC(R_AARCH64_ADR_PREL_LO21,                   0x112)
+ELF_RELOC(R_AARCH64_ADR_PREL_PG_HI21,                0x113)
+ELF_RELOC(R_AARCH64_ADR_PREL_PG_HI21_NC,             0x114)
+ELF_RELOC(R_AARCH64_ADD_ABS_LO12_NC,                 0x115)
+ELF_RELOC(R_AARCH64_LDST8_ABS_LO12_NC,               0x116)
+ELF_RELOC(R_AARCH64_TSTBR14,                         0x117)
+ELF_RELOC(R_AARCH64_CONDBR19,                        0x118)
+ELF_RELOC(R_AARCH64_JUMP26,                          0x11a)
+ELF_RELOC(R_AARCH64_CALL26,                          0x11b)
+ELF_RELOC(R_AARCH64_LDST16_ABS_LO12_NC,              0x11c)
+ELF_RELOC(R_AARCH64_LDST32_ABS_LO12_NC,              0x11d)
+ELF_RELOC(R_AARCH64_LDST64_ABS_LO12_NC,              0x11e)
+ELF_RELOC(R_AARCH64_MOVW_PREL_G0,                    0x11f)
+ELF_RELOC(R_AARCH64_MOVW_PREL_G0_NC,                 0x120)
+ELF_RELOC(R_AARCH64_MOVW_PREL_G1,                    0x121)
+ELF_RELOC(R_AARCH64_MOVW_PREL_G1_NC,                 0x122)
+ELF_RELOC(R_AARCH64_MOVW_PREL_G2,                    0x123)
+ELF_RELOC(R_AARCH64_MOVW_PREL_G2_NC,                 0x124)
+ELF_RELOC(R_AARCH64_MOVW_PREL_G3,                    0x125)
+ELF_RELOC(R_AARCH64_LDST128_ABS_LO12_NC,             0x12b)
+ELF_RELOC(R_AARCH64_MOVW_GOTOFF_G0,                  0x12c)
+ELF_RELOC(R_AARCH64_MOVW_GOTOFF_G0_NC,               0x12d)
+ELF_RELOC(R_AARCH64_MOVW_GOTOFF_G1,                  0x12e)
+ELF_RELOC(R_AARCH64_MOVW_GOTOFF_G1_NC,               0x12f)
+ELF_RELOC(R_AARCH64_MOVW_GOTOFF_G2,                  0x130)
+ELF_RELOC(R_AARCH64_MOVW_GOTOFF_G2_NC,               0x131)
+ELF_RELOC(R_AARCH64_MOVW_GOTOFF_G3,                  0x132)
+ELF_RELOC(R_AARCH64_GOTREL64,                        0x133)
+ELF_RELOC(R_AARCH64_GOTREL32,                        0x134)
+ELF_RELOC(R_AARCH64_GOT_LD_PREL19,                   0x135)
+ELF_RELOC(R_AARCH64_LD64_GOTOFF_LO15,                0x136)
+ELF_RELOC(R_AARCH64_ADR_GOT_PAGE,                    0x137)
+ELF_RELOC(R_AARCH64_LD64_GOT_LO12_NC,                0x138)
+ELF_RELOC(R_AARCH64_LD64_GOTPAGE_LO15,               0x139)
+ELF_RELOC(R_AARCH64_TLSGD_ADR_PREL21,                0x200)
+ELF_RELOC(R_AARCH64_TLSGD_ADR_PAGE21,                0x201)
+ELF_RELOC(R_AARCH64_TLSGD_ADD_LO12_NC,               0x202)
+ELF_RELOC(R_AARCH64_TLSGD_MOVW_G1,                   0x203)
+ELF_RELOC(R_AARCH64_TLSGD_MOVW_G0_NC,                0x204)
+ELF_RELOC(R_AARCH64_TLSLD_ADR_PREL21,                0x205)
+ELF_RELOC(R_AARCH64_TLSLD_ADR_PAGE21,                0x206)
+ELF_RELOC(R_AARCH64_TLSLD_ADD_LO12_NC,               0x207)
+ELF_RELOC(R_AARCH64_TLSLD_MOVW_G1,                   0x208)
+ELF_RELOC(R_AARCH64_TLSLD_MOVW_G0_NC,                0x209)
+ELF_RELOC(R_AARCH64_TLSLD_LD_PREL19,                 0x20a)
+ELF_RELOC(R_AARCH64_TLSLD_MOVW_DTPREL_G2,            0x20b)
+ELF_RELOC(R_AARCH64_TLSLD_MOVW_DTPREL_G1,            0x20c)
+ELF_RELOC(R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC,         0x20d)
+ELF_RELOC(R_AARCH64_TLSLD_MOVW_DTPREL_G0,            0x20e)
+ELF_RELOC(R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC,         0x20f)
+ELF_RELOC(R_AARCH64_TLSLD_ADD_DTPREL_HI12,           0x210)
+ELF_RELOC(R_AARCH64_TLSLD_ADD_DTPREL_LO12,           0x211)
+ELF_RELOC(R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC,        0x212)
+ELF_RELOC(R_AARCH64_TLSLD_LDST8_DTPREL_LO12,         0x213)
+ELF_RELOC(R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC,      0x214)
+ELF_RELOC(R_AARCH64_TLSLD_LDST16_DTPREL_LO12,        0x215)
+ELF_RELOC(R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC,     0x216)
+ELF_RELOC(R_AARCH64_TLSLD_LDST32_DTPREL_LO12,        0x217)
+ELF_RELOC(R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC,     0x218)
+ELF_RELOC(R_AARCH64_TLSLD_LDST64_DTPREL_LO12,        0x219)
+ELF_RELOC(R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC,     0x21a)
+ELF_RELOC(R_AARCH64_TLSIE_MOVW_GOTTPREL_G1,          0x21b)
+ELF_RELOC(R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC,       0x21c)
+ELF_RELOC(R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21,       0x21d)
+ELF_RELOC(R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC,     0x21e)
+ELF_RELOC(R_AARCH64_TLSIE_LD_GOTTPREL_PREL19,        0x21f)
+ELF_RELOC(R_AARCH64_TLSLE_MOVW_TPREL_G2,             0x220)
+ELF_RELOC(R_AARCH64_TLSLE_MOVW_TPREL_G1,             0x221)
+ELF_RELOC(R_AARCH64_TLSLE_MOVW_TPREL_G1_NC,          0x222)
+ELF_RELOC(R_AARCH64_TLSLE_MOVW_TPREL_G0,             0x223)
+ELF_RELOC(R_AARCH64_TLSLE_MOVW_TPREL_G0_NC,          0x224)
+ELF_RELOC(R_AARCH64_TLSLE_ADD_TPREL_HI12,            0x225)
+ELF_RELOC(R_AARCH64_TLSLE_ADD_TPREL_LO12,            0x226)
+ELF_RELOC(R_AARCH64_TLSLE_ADD_TPREL_LO12_NC,         0x227)
+ELF_RELOC(R_AARCH64_TLSLE_LDST8_TPREL_LO12,          0x228)
+ELF_RELOC(R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC,       0x229)
+ELF_RELOC(R_AARCH64_TLSLE_LDST16_TPREL_LO12,         0x22a)
+ELF_RELOC(R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC,      0x22b)
+ELF_RELOC(R_AARCH64_TLSLE_LDST32_TPREL_LO12,         0x22c)
+ELF_RELOC(R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC,      0x22d)
+ELF_RELOC(R_AARCH64_TLSLE_LDST64_TPREL_LO12,         0x22e)
+ELF_RELOC(R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC,      0x22f)
+ELF_RELOC(R_AARCH64_TLSDESC_LD_PREL19,               0x230)
+ELF_RELOC(R_AARCH64_TLSDESC_ADR_PREL21,              0x231)
+ELF_RELOC(R_AARCH64_TLSDESC_ADR_PAGE21,              0x232)
+ELF_RELOC(R_AARCH64_TLSDESC_LD64_LO12,               0x233)
+ELF_RELOC(R_AARCH64_TLSDESC_ADD_LO12,                0x234)
+ELF_RELOC(R_AARCH64_TLSDESC_OFF_G1,                  0x235)
+ELF_RELOC(R_AARCH64_TLSDESC_OFF_G0_NC,               0x236)
+ELF_RELOC(R_AARCH64_TLSDESC_LDR,                     0x237)
+ELF_RELOC(R_AARCH64_TLSDESC_ADD,                     0x238)
+ELF_RELOC(R_AARCH64_TLSDESC_CALL,                    0x239)
+ELF_RELOC(R_AARCH64_TLSLE_LDST128_TPREL_LO12,        0x23a)
+ELF_RELOC(R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC,     0x23b)
+ELF_RELOC(R_AARCH64_TLSLD_LDST128_DTPREL_LO12,       0x23c)
+ELF_RELOC(R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC,    0x23d)
+ELF_RELOC(R_AARCH64_COPY,                            0x400)
+ELF_RELOC(R_AARCH64_GLOB_DAT,                        0x401)
+ELF_RELOC(R_AARCH64_JUMP_SLOT,                       0x402)
+ELF_RELOC(R_AARCH64_RELATIVE,                        0x403)
+// 0x404 and 0x405 are now R_AARCH64_TLS_IMPDEF1 and R_AARCH64_TLS_IMPDEF2
+// We follow GNU and define TLS_IMPDEF1 as TLS_DTPMOD64 and TLS_IMPDEF2 as
+// TLS_DTPREL64
+ELF_RELOC(R_AARCH64_TLS_DTPMOD64,                    0x404)
+ELF_RELOC(R_AARCH64_TLS_DTPREL64,                    0x405)
+ELF_RELOC(R_AARCH64_TLS_TPREL64,                     0x406)
+ELF_RELOC(R_AARCH64_TLSDESC,                         0x407)
+ELF_RELOC(R_AARCH64_IRELATIVE,                       0x408)
+
+// ELF_RELOC(R_AARCH64_P32_NONE,                         0)
+ELF_RELOC(R_AARCH64_P32_ABS32,                       0x001)
+ELF_RELOC(R_AARCH64_P32_ABS16,                       0x002)
+ELF_RELOC(R_AARCH64_P32_PREL32,                      0x003)
+ELF_RELOC(R_AARCH64_P32_PREL16,                      0x004)
+ELF_RELOC(R_AARCH64_P32_MOVW_UABS_G0,                0x005)
+ELF_RELOC(R_AARCH64_P32_MOVW_UABS_G0_NC,             0x006)
+ELF_RELOC(R_AARCH64_P32_MOVW_UABS_G1,                0x007)
+ELF_RELOC(R_AARCH64_P32_MOVW_SABS_G0,                0x008)
+ELF_RELOC(R_AARCH64_P32_LD_PREL_LO19,                0x009)
+ELF_RELOC(R_AARCH64_P32_ADR_PREL_LO21,               0x00a)
+ELF_RELOC(R_AARCH64_P32_ADR_PREL_PG_HI21,            0x00b)
+ELF_RELOC(R_AARCH64_P32_ADD_ABS_LO12_NC,             0x00c)
+ELF_RELOC(R_AARCH64_P32_LDST8_ABS_LO12_NC,           0x00d)
+ELF_RELOC(R_AARCH64_P32_LDST16_ABS_LO12_NC,          0x00e)
+ELF_RELOC(R_AARCH64_P32_LDST32_ABS_LO12_NC,          0x00f)
+ELF_RELOC(R_AARCH64_P32_LDST64_ABS_LO12_NC,          0x010)
+ELF_RELOC(R_AARCH64_P32_LDST128_ABS_LO12_NC,         0x011)
+ELF_RELOC(R_AARCH64_P32_TSTBR14,                     0x012)
+ELF_RELOC(R_AARCH64_P32_CONDBR19,                    0x013)
+ELF_RELOC(R_AARCH64_P32_JUMP26,                      0x014)
+ELF_RELOC(R_AARCH64_P32_CALL26,                      0x015)
+ELF_RELOC(R_AARCH64_P32_MOVW_PREL_G0,                0x016)
+ELF_RELOC(R_AARCH64_P32_MOVW_PREL_G0_NC,             0x017)
+ELF_RELOC(R_AARCH64_P32_MOVW_PREL_G1,                0x018)
+ELF_RELOC(R_AARCH64_P32_GOT_LD_PREL19,               0x019)
+ELF_RELOC(R_AARCH64_P32_ADR_GOT_PAGE,                0x01a)
+ELF_RELOC(R_AARCH64_P32_LD32_GOT_LO12_NC,            0x01b)
+ELF_RELOC(R_AARCH64_P32_LD32_GOTPAGE_LO14,           0x01c)
+ELF_RELOC(R_AARCH64_P32_TLSGD_ADR_PREL21,            0x050)
+ELF_RELOC(R_AARCH64_P32_TLSGD_ADR_PAGE21,            0x051)
+ELF_RELOC(R_AARCH64_P32_TLSGD_ADD_LO12_NC,           0x052)
+ELF_RELOC(R_AARCH64_P32_TLSLD_ADR_PREL21,            0x053)
+ELF_RELOC(R_AARCH64_P32_TLSLD_ADR_PAGE21,            0x054)
+ELF_RELOC(R_AARCH64_P32_TLSLD_ADD_LO12_NC,           0x055)
+ELF_RELOC(R_AARCH64_P32_TLSLD_LD_PREL19,             0x056)
+ELF_RELOC(R_AARCH64_P32_TLSLD_MOVW_DTPREL_G1,        0x057)
+ELF_RELOC(R_AARCH64_P32_TLSLD_MOVW_DTPREL_G0,        0x058)
+ELF_RELOC(R_AARCH64_P32_TLSLD_MOVW_DTPREL_G0_NC,     0x059)
+ELF_RELOC(R_AARCH64_P32_TLSLD_ADD_DTPREL_HI12,       0x05a)
+ELF_RELOC(R_AARCH64_P32_TLSLD_ADD_DTPREL_LO12,       0x05b)
+ELF_RELOC(R_AARCH64_P32_TLSLD_ADD_DTPREL_LO12_NC,    0x05c)
+ELF_RELOC(R_AARCH64_P32_TLSLD_LDST8_DTPREL_LO12,     0x05d)
+ELF_RELOC(R_AARCH64_P32_TLSLD_LDST8_DTPREL_LO12_NC,  0x05e)
+ELF_RELOC(R_AARCH64_P32_TLSLD_LDST16_DTPREL_LO12,    0x05f)
+ELF_RELOC(R_AARCH64_P32_TLSLD_LDST16_DTPREL_LO12_NC, 0x060)
+ELF_RELOC(R_AARCH64_P32_TLSLD_LDST32_DTPREL_LO12,    0x061)
+ELF_RELOC(R_AARCH64_P32_TLSLD_LDST32_DTPREL_LO12_NC, 0x062)
+ELF_RELOC(R_AARCH64_P32_TLSLD_LDST64_DTPREL_LO12,    0x063)
+ELF_RELOC(R_AARCH64_P32_TLSLD_LDST64_DTPREL_LO12_NC, 0x064)
+ELF_RELOC(R_AARCH64_P32_TLSLD_LDST128_DTPREL_LO12,   0x065)
+ELF_RELOC(R_AARCH64_P32_TLSLD_LDST128_DTPREL_LO12_NC,0x066)
+ELF_RELOC(R_AARCH64_P32_TLSIE_ADR_GOTTPREL_PAGE21,   0x067)
+ELF_RELOC(R_AARCH64_P32_TLSIE_LD32_GOTTPREL_LO12_NC, 0x068)
+ELF_RELOC(R_AARCH64_P32_TLSIE_LD_GOTTPREL_PREL19,    0x069)
+ELF_RELOC(R_AARCH64_P32_TLSLE_MOVW_TPREL_G1,         0x06a)
+ELF_RELOC(R_AARCH64_P32_TLSLE_MOVW_TPREL_G0,         0x06b)
+ELF_RELOC(R_AARCH64_P32_TLSLE_MOVW_TPREL_G0_NC,      0x06c)
+ELF_RELOC(R_AARCH64_P32_TLSLE_ADD_TPREL_HI12,        0x06d)
+ELF_RELOC(R_AARCH64_P32_TLSLE_ADD_TPREL_LO12,        0x06e)
+ELF_RELOC(R_AARCH64_P32_TLSLE_ADD_TPREL_LO12_NC,     0x06f)
+ELF_RELOC(R_AARCH64_P32_TLSLE_LDST8_TPREL_LO12,      0x070)
+ELF_RELOC(R_AARCH64_P32_TLSLE_LDST8_TPREL_LO12_NC,   0x071)
+ELF_RELOC(R_AARCH64_P32_TLSLE_LDST16_TPREL_LO12,     0x072)
+ELF_RELOC(R_AARCH64_P32_TLSLE_LDST16_TPREL_LO12_NC,  0x073)
+ELF_RELOC(R_AARCH64_P32_TLSLE_LDST32_TPREL_LO12,     0x074)
+ELF_RELOC(R_AARCH64_P32_TLSLE_LDST32_TPREL_LO12_NC,  0x075)
+ELF_RELOC(R_AARCH64_P32_TLSLE_LDST64_TPREL_LO12,     0x076)
+ELF_RELOC(R_AARCH64_P32_TLSLE_LDST64_TPREL_LO12_NC,  0x077)
+ELF_RELOC(R_AARCH64_P32_TLSLE_LDST128_TPREL_LO12,    0x078)
+ELF_RELOC(R_AARCH64_P32_TLSLE_LDST128_TPREL_LO12_NC, 0x079)
+ELF_RELOC(R_AARCH64_P32_TLSDESC_LD_PREL19,           0x07a)
+ELF_RELOC(R_AARCH64_P32_TLSDESC_ADR_PREL21,          0x07b)
+ELF_RELOC(R_AARCH64_P32_TLSDESC_ADR_PAGE21,          0x07c)
+ELF_RELOC(R_AARCH64_P32_TLSDESC_LD32_LO12,           0x07d)
+ELF_RELOC(R_AARCH64_P32_TLSDESC_ADD_LO12,            0x07e)
+ELF_RELOC(R_AARCH64_P32_TLSDESC_CALL,                0x07f)
+ELF_RELOC(R_AARCH64_P32_COPY,                        0x0b4)
+ELF_RELOC(R_AARCH64_P32_GLOB_DAT,                    0x0b5)
+ELF_RELOC(R_AARCH64_P32_JUMP_SLOT,                   0x0b6)
+ELF_RELOC(R_AARCH64_P32_RELATIVE,                    0x0b7)
+ELF_RELOC(R_AARCH64_P32_TLS_DTPREL,                  0x0b8)
+ELF_RELOC(R_AARCH64_P32_TLS_DTPMOD,                  0x0b9)
+ELF_RELOC(R_AARCH64_P32_TLS_TPREL,                   0x0ba)
+ELF_RELOC(R_AARCH64_P32_TLSDESC,                     0x0bb)
+ELF_RELOC(R_AARCH64_P32_IRELATIVE,                   0x0bc)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/AMDGPU.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/AMDGPU.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/AMDGPU.def
@@ -0,0 +1,17 @@
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+ELF_RELOC(R_AMDGPU_NONE,           0)
+ELF_RELOC(R_AMDGPU_ABS32_LO,       1)
+ELF_RELOC(R_AMDGPU_ABS32_HI,       2)
+ELF_RELOC(R_AMDGPU_ABS64,          3)
+ELF_RELOC(R_AMDGPU_REL32,          4)
+ELF_RELOC(R_AMDGPU_REL64,          5)
+ELF_RELOC(R_AMDGPU_ABS32,          6)
+ELF_RELOC(R_AMDGPU_GOTPCREL,       7)
+ELF_RELOC(R_AMDGPU_GOTPCREL32_LO,  8)
+ELF_RELOC(R_AMDGPU_GOTPCREL32_HI,  9)
+ELF_RELOC(R_AMDGPU_REL32_LO,      10)
+ELF_RELOC(R_AMDGPU_REL32_HI,      11)
+ELF_RELOC(R_AMDGPU_RELATIVE64,    13)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/ARC.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/ARC.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/ARC.def
@@ -0,0 +1,74 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+ELF_RELOC(R_ARC_NONE,                  0)
+ELF_RELOC(R_ARC_8,                     1)
+ELF_RELOC(R_ARC_16,                    2)
+ELF_RELOC(R_ARC_24,                    3)
+ELF_RELOC(R_ARC_32,                    4)
+ELF_RELOC(R_ARC_N8,                    8)
+ELF_RELOC(R_ARC_N16,                   9)
+ELF_RELOC(R_ARC_N24,                  10)
+ELF_RELOC(R_ARC_N32,                  11)
+ELF_RELOC(R_ARC_SDA,                  12)
+ELF_RELOC(R_ARC_SECTOFF,              13)
+ELF_RELOC(R_ARC_S21H_PCREL,           14)
+ELF_RELOC(R_ARC_S21W_PCREL,           15)
+ELF_RELOC(R_ARC_S25H_PCREL,           16)
+ELF_RELOC(R_ARC_S25W_PCREL,           17)
+ELF_RELOC(R_ARC_SDA32,                18)
+ELF_RELOC(R_ARC_SDA_LDST,             19)
+ELF_RELOC(R_ARC_SDA_LDST1,            20)
+ELF_RELOC(R_ARC_SDA_LDST2,            21)
+ELF_RELOC(R_ARC_SDA16_LD,             22)
+ELF_RELOC(R_ARC_SDA16_LD1,            23)
+ELF_RELOC(R_ARC_SDA16_LD2,            24)
+ELF_RELOC(R_ARC_S13_PCREL,            25)
+ELF_RELOC(R_ARC_W,                    26)
+ELF_RELOC(R_ARC_32_ME,                27)
+ELF_RELOC(R_ARC_32_ME_S,             105)
+ELF_RELOC(R_ARC_N32_ME,               28)
+ELF_RELOC(R_ARC_SECTOFF_ME,           29)
+ELF_RELOC(R_ARC_SDA32_ME,             30)
+ELF_RELOC(R_ARC_W_ME,                 31)
+ELF_RELOC(R_AC_SECTOFF_U8,            35)
+ELF_RELOC(R_AC_SECTOFF_U8_1,          36)
+ELF_RELOC(R_AC_SECTOFF_U8_2,          37)
+ELF_RELOC(R_AC_SECTOFF_S9,            38)
+ELF_RELOC(R_AC_SECTOFF_S9_1,          39)
+ELF_RELOC(R_AC_SECTOFF_S9_2,          40)
+ELF_RELOC(R_ARC_SECTOFF_ME_1,         41)
+ELF_RELOC(R_ARC_SECTOFF_ME_2,         42)
+ELF_RELOC(R_ARC_SECTOFF_1,            43)
+ELF_RELOC(R_ARC_SECTOFF_2,            44)
+ELF_RELOC(R_ARC_SDA_12,               45)
+ELF_RELOC(R_ARC_SDA16_ST2,            48)
+ELF_RELOC(R_ARC_32_PCREL,             49)
+ELF_RELOC(R_ARC_PC32,                 50)
+ELF_RELOC(R_ARC_GOT32,                59)
+ELF_RELOC(R_ARC_GOTPC32,              51)
+ELF_RELOC(R_ARC_PLT32,                52)
+ELF_RELOC(R_ARC_COPY,                 53)
+ELF_RELOC(R_ARC_GLOB_DAT,             54)
+ELF_RELOC(R_ARC_JMP_SLOT,             55)
+ELF_RELOC(R_ARC_RELATIVE,             56)
+ELF_RELOC(R_ARC_GOTOFF,               57)
+ELF_RELOC(R_ARC_GOTPC,                58)
+ELF_RELOC(R_ARC_S21W_PCREL_PLT,       60)
+ELF_RELOC(R_ARC_S25H_PCREL_PLT,       61)
+ELF_RELOC(R_ARC_JLI_SECTOFF,          63)
+ELF_RELOC(R_ARC_TLS_DTPMOD,           66)
+ELF_RELOC(R_ARC_TLS_TPOFF,            68)
+ELF_RELOC(R_ARC_TLS_GD_GOT,           69)
+ELF_RELOC(R_ARC_TLS_GD_LD,            70)
+ELF_RELOC(R_ARC_TLS_GD_CALL,          71)
+ELF_RELOC(R_ARC_TLS_IE_GOT,           72)
+ELF_RELOC(R_ARC_TLS_DTPOFF,           67)
+ELF_RELOC(R_ARC_TLS_DTPOFF_S9,        73)
+ELF_RELOC(R_ARC_TLS_LE_S9,            74)
+ELF_RELOC(R_ARC_TLS_LE_32,            75)
+ELF_RELOC(R_ARC_S25W_PCREL_PLT,       76)
+ELF_RELOC(R_ARC_S21H_PCREL_PLT,       77)
+ELF_RELOC(R_ARC_NPS_CMEM16,           78)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/ARM.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/ARM.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/ARM.def
@@ -0,0 +1,141 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+// Meets 2.09 ABI Specs.
+ELF_RELOC(R_ARM_NONE,                   0x00)
+ELF_RELOC(R_ARM_PC24,                   0x01)
+ELF_RELOC(R_ARM_ABS32,                  0x02)
+ELF_RELOC(R_ARM_REL32,                  0x03)
+ELF_RELOC(R_ARM_LDR_PC_G0,              0x04)
+ELF_RELOC(R_ARM_ABS16,                  0x05)
+ELF_RELOC(R_ARM_ABS12,                  0x06)
+ELF_RELOC(R_ARM_THM_ABS5,               0x07)
+ELF_RELOC(R_ARM_ABS8,                   0x08)
+ELF_RELOC(R_ARM_SBREL32,                0x09)
+ELF_RELOC(R_ARM_THM_CALL,               0x0a)
+ELF_RELOC(R_ARM_THM_PC8,                0x0b)
+ELF_RELOC(R_ARM_BREL_ADJ,               0x0c)
+ELF_RELOC(R_ARM_TLS_DESC,               0x0d)
+ELF_RELOC(R_ARM_THM_SWI8,               0x0e)
+ELF_RELOC(R_ARM_XPC25,                  0x0f)
+ELF_RELOC(R_ARM_THM_XPC22,              0x10)
+ELF_RELOC(R_ARM_TLS_DTPMOD32,           0x11)
+ELF_RELOC(R_ARM_TLS_DTPOFF32,           0x12)
+ELF_RELOC(R_ARM_TLS_TPOFF32,            0x13)
+ELF_RELOC(R_ARM_COPY,                   0x14)
+ELF_RELOC(R_ARM_GLOB_DAT,               0x15)
+ELF_RELOC(R_ARM_JUMP_SLOT,              0x16)
+ELF_RELOC(R_ARM_RELATIVE,               0x17)
+ELF_RELOC(R_ARM_GOTOFF32,               0x18)
+ELF_RELOC(R_ARM_BASE_PREL,              0x19)
+ELF_RELOC(R_ARM_GOT_BREL,               0x1a)
+ELF_RELOC(R_ARM_PLT32,                  0x1b)
+ELF_RELOC(R_ARM_CALL,                   0x1c)
+ELF_RELOC(R_ARM_JUMP24,                 0x1d)
+ELF_RELOC(R_ARM_THM_JUMP24,             0x1e)
+ELF_RELOC(R_ARM_BASE_ABS,               0x1f)
+ELF_RELOC(R_ARM_ALU_PCREL_7_0,          0x20)
+ELF_RELOC(R_ARM_ALU_PCREL_15_8,         0x21)
+ELF_RELOC(R_ARM_ALU_PCREL_23_15,        0x22)
+ELF_RELOC(R_ARM_LDR_SBREL_11_0_NC,      0x23)
+ELF_RELOC(R_ARM_ALU_SBREL_19_12_NC,     0x24)
+ELF_RELOC(R_ARM_ALU_SBREL_27_20_CK,     0x25)
+ELF_RELOC(R_ARM_TARGET1,                0x26)
+ELF_RELOC(R_ARM_SBREL31,                0x27)
+ELF_RELOC(R_ARM_V4BX,                   0x28)
+ELF_RELOC(R_ARM_TARGET2,                0x29)
+ELF_RELOC(R_ARM_PREL31,                 0x2a)
+ELF_RELOC(R_ARM_MOVW_ABS_NC,            0x2b)
+ELF_RELOC(R_ARM_MOVT_ABS,               0x2c)
+ELF_RELOC(R_ARM_MOVW_PREL_NC,           0x2d)
+ELF_RELOC(R_ARM_MOVT_PREL,              0x2e)
+ELF_RELOC(R_ARM_THM_MOVW_ABS_NC,        0x2f)
+ELF_RELOC(R_ARM_THM_MOVT_ABS,           0x30)
+ELF_RELOC(R_ARM_THM_MOVW_PREL_NC,       0x31)
+ELF_RELOC(R_ARM_THM_MOVT_PREL,          0x32)
+ELF_RELOC(R_ARM_THM_JUMP19,             0x33)
+ELF_RELOC(R_ARM_THM_JUMP6,              0x34)
+ELF_RELOC(R_ARM_THM_ALU_PREL_11_0,      0x35)
+ELF_RELOC(R_ARM_THM_PC12,               0x36)
+ELF_RELOC(R_ARM_ABS32_NOI,              0x37)
+ELF_RELOC(R_ARM_REL32_NOI,              0x38)
+ELF_RELOC(R_ARM_ALU_PC_G0_NC,           0x39)
+ELF_RELOC(R_ARM_ALU_PC_G0,              0x3a)
+ELF_RELOC(R_ARM_ALU_PC_G1_NC,           0x3b)
+ELF_RELOC(R_ARM_ALU_PC_G1,              0x3c)
+ELF_RELOC(R_ARM_ALU_PC_G2,              0x3d)
+ELF_RELOC(R_ARM_LDR_PC_G1,              0x3e)
+ELF_RELOC(R_ARM_LDR_PC_G2,              0x3f)
+ELF_RELOC(R_ARM_LDRS_PC_G0,             0x40)
+ELF_RELOC(R_ARM_LDRS_PC_G1,             0x41)
+ELF_RELOC(R_ARM_LDRS_PC_G2,             0x42)
+ELF_RELOC(R_ARM_LDC_PC_G0,              0x43)
+ELF_RELOC(R_ARM_LDC_PC_G1,              0x44)
+ELF_RELOC(R_ARM_LDC_PC_G2,              0x45)
+ELF_RELOC(R_ARM_ALU_SB_G0_NC,           0x46)
+ELF_RELOC(R_ARM_ALU_SB_G0,              0x47)
+ELF_RELOC(R_ARM_ALU_SB_G1_NC,           0x48)
+ELF_RELOC(R_ARM_ALU_SB_G1,              0x49)
+ELF_RELOC(R_ARM_ALU_SB_G2,              0x4a)
+ELF_RELOC(R_ARM_LDR_SB_G0,              0x4b)
+ELF_RELOC(R_ARM_LDR_SB_G1,              0x4c)
+ELF_RELOC(R_ARM_LDR_SB_G2,              0x4d)
+ELF_RELOC(R_ARM_LDRS_SB_G0,             0x4e)
+ELF_RELOC(R_ARM_LDRS_SB_G1,             0x4f)
+ELF_RELOC(R_ARM_LDRS_SB_G2,             0x50)
+ELF_RELOC(R_ARM_LDC_SB_G0,              0x51)
+ELF_RELOC(R_ARM_LDC_SB_G1,              0x52)
+ELF_RELOC(R_ARM_LDC_SB_G2,              0x53)
+ELF_RELOC(R_ARM_MOVW_BREL_NC,           0x54)
+ELF_RELOC(R_ARM_MOVT_BREL,              0x55)
+ELF_RELOC(R_ARM_MOVW_BREL,              0x56)
+ELF_RELOC(R_ARM_THM_MOVW_BREL_NC,       0x57)
+ELF_RELOC(R_ARM_THM_MOVT_BREL,          0x58)
+ELF_RELOC(R_ARM_THM_MOVW_BREL,          0x59)
+ELF_RELOC(R_ARM_TLS_GOTDESC,            0x5a)
+ELF_RELOC(R_ARM_TLS_CALL,               0x5b)
+ELF_RELOC(R_ARM_TLS_DESCSEQ,            0x5c)
+ELF_RELOC(R_ARM_THM_TLS_CALL,           0x5d)
+ELF_RELOC(R_ARM_PLT32_ABS,              0x5e)
+ELF_RELOC(R_ARM_GOT_ABS,                0x5f)
+ELF_RELOC(R_ARM_GOT_PREL,               0x60)
+ELF_RELOC(R_ARM_GOT_BREL12,             0x61)
+ELF_RELOC(R_ARM_GOTOFF12,               0x62)
+ELF_RELOC(R_ARM_GOTRELAX,               0x63)
+ELF_RELOC(R_ARM_GNU_VTENTRY,            0x64)
+ELF_RELOC(R_ARM_GNU_VTINHERIT,          0x65)
+ELF_RELOC(R_ARM_THM_JUMP11,             0x66)
+ELF_RELOC(R_ARM_THM_JUMP8,              0x67)
+ELF_RELOC(R_ARM_TLS_GD32,               0x68)
+ELF_RELOC(R_ARM_TLS_LDM32,              0x69)
+ELF_RELOC(R_ARM_TLS_LDO32,              0x6a)
+ELF_RELOC(R_ARM_TLS_IE32,               0x6b)
+ELF_RELOC(R_ARM_TLS_LE32,               0x6c)
+ELF_RELOC(R_ARM_TLS_LDO12,              0x6d)
+ELF_RELOC(R_ARM_TLS_LE12,               0x6e)
+ELF_RELOC(R_ARM_TLS_IE12GP,             0x6f)
+ELF_RELOC(R_ARM_PRIVATE_0,              0x70)
+ELF_RELOC(R_ARM_PRIVATE_1,              0x71)
+ELF_RELOC(R_ARM_PRIVATE_2,              0x72)
+ELF_RELOC(R_ARM_PRIVATE_3,              0x73)
+ELF_RELOC(R_ARM_PRIVATE_4,              0x74)
+ELF_RELOC(R_ARM_PRIVATE_5,              0x75)
+ELF_RELOC(R_ARM_PRIVATE_6,              0x76)
+ELF_RELOC(R_ARM_PRIVATE_7,              0x77)
+ELF_RELOC(R_ARM_PRIVATE_8,              0x78)
+ELF_RELOC(R_ARM_PRIVATE_9,              0x79)
+ELF_RELOC(R_ARM_PRIVATE_10,             0x7a)
+ELF_RELOC(R_ARM_PRIVATE_11,             0x7b)
+ELF_RELOC(R_ARM_PRIVATE_12,             0x7c)
+ELF_RELOC(R_ARM_PRIVATE_13,             0x7d)
+ELF_RELOC(R_ARM_PRIVATE_14,             0x7e)
+ELF_RELOC(R_ARM_PRIVATE_15,             0x7f)
+ELF_RELOC(R_ARM_ME_TOO,                 0x80)
+ELF_RELOC(R_ARM_THM_TLS_DESCSEQ16,      0x81)
+ELF_RELOC(R_ARM_THM_TLS_DESCSEQ32,      0x82)
+ELF_RELOC(R_ARM_THM_BF16,               0x88)
+ELF_RELOC(R_ARM_THM_BF12,               0x89)
+ELF_RELOC(R_ARM_THM_BF18,               0x8a)
+ELF_RELOC(R_ARM_IRELATIVE,              0xa0)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/AVR.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/AVR.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/AVR.def
@@ -0,0 +1,41 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+ELF_RELOC(R_AVR_NONE,                  0)
+ELF_RELOC(R_AVR_32,                    1)
+ELF_RELOC(R_AVR_7_PCREL,               2)
+ELF_RELOC(R_AVR_13_PCREL,              3)
+ELF_RELOC(R_AVR_16,                    4)
+ELF_RELOC(R_AVR_16_PM,                 5)
+ELF_RELOC(R_AVR_LO8_LDI,               6)
+ELF_RELOC(R_AVR_HI8_LDI,               7)
+ELF_RELOC(R_AVR_HH8_LDI,               8)
+ELF_RELOC(R_AVR_LO8_LDI_NEG,           9)
+ELF_RELOC(R_AVR_HI8_LDI_NEG,          10)
+ELF_RELOC(R_AVR_HH8_LDI_NEG,          11)
+ELF_RELOC(R_AVR_LO8_LDI_PM,           12)
+ELF_RELOC(R_AVR_HI8_LDI_PM,           13)
+ELF_RELOC(R_AVR_HH8_LDI_PM,           14)
+ELF_RELOC(R_AVR_LO8_LDI_PM_NEG,       15)
+ELF_RELOC(R_AVR_HI8_LDI_PM_NEG,       16)
+ELF_RELOC(R_AVR_HH8_LDI_PM_NEG,       17)
+ELF_RELOC(R_AVR_CALL,                 18)
+ELF_RELOC(R_AVR_LDI,                  19)
+ELF_RELOC(R_AVR_6,                    20)
+ELF_RELOC(R_AVR_6_ADIW,               21)
+ELF_RELOC(R_AVR_MS8_LDI,              22)
+ELF_RELOC(R_AVR_MS8_LDI_NEG,          23)
+ELF_RELOC(R_AVR_LO8_LDI_GS,           24)
+ELF_RELOC(R_AVR_HI8_LDI_GS,           25)
+ELF_RELOC(R_AVR_8,                    26)
+ELF_RELOC(R_AVR_8_LO8,                27)
+ELF_RELOC(R_AVR_8_HI8,                28)
+ELF_RELOC(R_AVR_8_HLO8,               29)
+ELF_RELOC(R_AVR_DIFF8,                30)
+ELF_RELOC(R_AVR_DIFF16,               31)
+ELF_RELOC(R_AVR_DIFF32,               32)
+ELF_RELOC(R_AVR_LDS_STS_16,           33)
+ELF_RELOC(R_AVR_PORT6,                34)
+ELF_RELOC(R_AVR_PORT5,                35)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/BPF.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/BPF.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/BPF.def
@@ -0,0 +1,8 @@
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+// No relocation
+ELF_RELOC(R_BPF_NONE,        0)
+ELF_RELOC(R_BPF_64_64,       1)
+ELF_RELOC(R_BPF_64_32,      10)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Hexagon.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Hexagon.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Hexagon.def
@@ -0,0 +1,106 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+// Release 5 ABI
+ELF_RELOC(R_HEX_NONE,                0)
+ELF_RELOC(R_HEX_B22_PCREL,           1)
+ELF_RELOC(R_HEX_B15_PCREL,           2)
+ELF_RELOC(R_HEX_B7_PCREL,            3)
+ELF_RELOC(R_HEX_LO16,                4)
+ELF_RELOC(R_HEX_HI16,                5)
+ELF_RELOC(R_HEX_32,                  6)
+ELF_RELOC(R_HEX_16,                  7)
+ELF_RELOC(R_HEX_8,                   8)
+ELF_RELOC(R_HEX_GPREL16_0,           9)
+ELF_RELOC(R_HEX_GPREL16_1,           10)
+ELF_RELOC(R_HEX_GPREL16_2,           11)
+ELF_RELOC(R_HEX_GPREL16_3,           12)
+ELF_RELOC(R_HEX_HL16,                13)
+ELF_RELOC(R_HEX_B13_PCREL,           14)
+ELF_RELOC(R_HEX_B9_PCREL,            15)
+ELF_RELOC(R_HEX_B32_PCREL_X,         16)
+ELF_RELOC(R_HEX_32_6_X,              17)
+ELF_RELOC(R_HEX_B22_PCREL_X,         18)
+ELF_RELOC(R_HEX_B15_PCREL_X,         19)
+ELF_RELOC(R_HEX_B13_PCREL_X,         20)
+ELF_RELOC(R_HEX_B9_PCREL_X,          21)
+ELF_RELOC(R_HEX_B7_PCREL_X,          22)
+ELF_RELOC(R_HEX_16_X,                23)
+ELF_RELOC(R_HEX_12_X,                24)
+ELF_RELOC(R_HEX_11_X,                25)
+ELF_RELOC(R_HEX_10_X,                26)
+ELF_RELOC(R_HEX_9_X,                 27)
+ELF_RELOC(R_HEX_8_X,                 28)
+ELF_RELOC(R_HEX_7_X,                 29)
+ELF_RELOC(R_HEX_6_X,                 30)
+ELF_RELOC(R_HEX_32_PCREL,            31)
+ELF_RELOC(R_HEX_COPY,                32)
+ELF_RELOC(R_HEX_GLOB_DAT,            33)
+ELF_RELOC(R_HEX_JMP_SLOT,            34)
+ELF_RELOC(R_HEX_RELATIVE,            35)
+ELF_RELOC(R_HEX_PLT_B22_PCREL,       36)
+ELF_RELOC(R_HEX_GOTREL_LO16,         37)
+ELF_RELOC(R_HEX_GOTREL_HI16,         38)
+ELF_RELOC(R_HEX_GOTREL_32,           39)
+ELF_RELOC(R_HEX_GOT_LO16,            40)
+ELF_RELOC(R_HEX_GOT_HI16,            41)
+ELF_RELOC(R_HEX_GOT_32,              42)
+ELF_RELOC(R_HEX_GOT_16,              43)
+ELF_RELOC(R_HEX_DTPMOD_32,           44)
+ELF_RELOC(R_HEX_DTPREL_LO16,         45)
+ELF_RELOC(R_HEX_DTPREL_HI16,         46)
+ELF_RELOC(R_HEX_DTPREL_32,           47)
+ELF_RELOC(R_HEX_DTPREL_16,           48)
+ELF_RELOC(R_HEX_GD_PLT_B22_PCREL,    49)
+ELF_RELOC(R_HEX_GD_GOT_LO16,         50)
+ELF_RELOC(R_HEX_GD_GOT_HI16,         51)
+ELF_RELOC(R_HEX_GD_GOT_32,           52)
+ELF_RELOC(R_HEX_GD_GOT_16,           53)
+ELF_RELOC(R_HEX_IE_LO16,             54)
+ELF_RELOC(R_HEX_IE_HI16,             55)
+ELF_RELOC(R_HEX_IE_32,               56)
+ELF_RELOC(R_HEX_IE_GOT_LO16,         57)
+ELF_RELOC(R_HEX_IE_GOT_HI16,         58)
+ELF_RELOC(R_HEX_IE_GOT_32,           59)
+ELF_RELOC(R_HEX_IE_GOT_16,           60)
+ELF_RELOC(R_HEX_TPREL_LO16,          61)
+ELF_RELOC(R_HEX_TPREL_HI16,          62)
+ELF_RELOC(R_HEX_TPREL_32,            63)
+ELF_RELOC(R_HEX_TPREL_16,            64)
+ELF_RELOC(R_HEX_6_PCREL_X,           65)
+ELF_RELOC(R_HEX_GOTREL_32_6_X,       66)
+ELF_RELOC(R_HEX_GOTREL_16_X,         67)
+ELF_RELOC(R_HEX_GOTREL_11_X,         68)
+ELF_RELOC(R_HEX_GOT_32_6_X,          69)
+ELF_RELOC(R_HEX_GOT_16_X,            70)
+ELF_RELOC(R_HEX_GOT_11_X,            71)
+ELF_RELOC(R_HEX_DTPREL_32_6_X,       72)
+ELF_RELOC(R_HEX_DTPREL_16_X,         73)
+ELF_RELOC(R_HEX_DTPREL_11_X,         74)
+ELF_RELOC(R_HEX_GD_GOT_32_6_X,       75)
+ELF_RELOC(R_HEX_GD_GOT_16_X,         76)
+ELF_RELOC(R_HEX_GD_GOT_11_X,         77)
+ELF_RELOC(R_HEX_IE_32_6_X,           78)
+ELF_RELOC(R_HEX_IE_16_X,             79)
+ELF_RELOC(R_HEX_IE_GOT_32_6_X,       80)
+ELF_RELOC(R_HEX_IE_GOT_16_X,         81)
+ELF_RELOC(R_HEX_IE_GOT_11_X,         82)
+ELF_RELOC(R_HEX_TPREL_32_6_X,        83)
+ELF_RELOC(R_HEX_TPREL_16_X,          84)
+ELF_RELOC(R_HEX_TPREL_11_X,          85)
+ELF_RELOC(R_HEX_LD_PLT_B22_PCREL,    86)
+ELF_RELOC(R_HEX_LD_GOT_LO16,         87)
+ELF_RELOC(R_HEX_LD_GOT_HI16,         88)
+ELF_RELOC(R_HEX_LD_GOT_32,           89)
+ELF_RELOC(R_HEX_LD_GOT_16,           90)
+ELF_RELOC(R_HEX_LD_GOT_32_6_X,       91)
+ELF_RELOC(R_HEX_LD_GOT_16_X,         92)
+ELF_RELOC(R_HEX_LD_GOT_11_X,         93)
+ELF_RELOC(R_HEX_23_REG,              94)
+ELF_RELOC(R_HEX_GD_PLT_B22_PCREL_X,  95)
+ELF_RELOC(R_HEX_GD_PLT_B32_PCREL_X,  96)
+ELF_RELOC(R_HEX_LD_PLT_B22_PCREL_X,  97)
+ELF_RELOC(R_HEX_LD_PLT_B32_PCREL_X,  98)
+ELF_RELOC(R_HEX_27_REG,              99)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Lanai.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Lanai.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Lanai.def
@@ -0,0 +1,19 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+// No relocation
+ELF_RELOC(R_LANAI_NONE,        0)
+// 21-bit symbol relocation
+ELF_RELOC(R_LANAI_21,          1)
+// 21-bit symbol relocation with last two bits masked to 0
+ELF_RELOC(R_LANAI_21_F,        2)
+// 25-bit branch targets
+ELF_RELOC(R_LANAI_25,          3)
+// General 32-bit relocation
+ELF_RELOC(R_LANAI_32,          4)
+// Upper 16-bits of a symbolic relocation
+ELF_RELOC(R_LANAI_HI16,        5)
+// Lower 16-bits of a symbolic relocation
+ELF_RELOC(R_LANAI_LO16,        6)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/MSP430.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/MSP430.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/MSP430.def
@@ -0,0 +1,16 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+ELF_RELOC(R_MSP430_NONE,               0)
+ELF_RELOC(R_MSP430_32,                 1)
+ELF_RELOC(R_MSP430_10_PCREL,           2)
+ELF_RELOC(R_MSP430_16,                 3)
+ELF_RELOC(R_MSP430_16_PCREL,           4)
+ELF_RELOC(R_MSP430_16_BYTE,            5)
+ELF_RELOC(R_MSP430_16_PCREL_BYTE,      6)
+ELF_RELOC(R_MSP430_2X_PCREL,           7)
+ELF_RELOC(R_MSP430_RL_PCREL,           8)
+ELF_RELOC(R_MSP430_8,                  9)
+ELF_RELOC(R_MSP430_SYM_DIFF,           10)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Mips.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Mips.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Mips.def
@@ -0,0 +1,117 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+ELF_RELOC(R_MIPS_NONE,                0)
+ELF_RELOC(R_MIPS_16,                  1)
+ELF_RELOC(R_MIPS_32,                  2)
+ELF_RELOC(R_MIPS_REL32,               3)
+ELF_RELOC(R_MIPS_26,                  4)
+ELF_RELOC(R_MIPS_HI16,                5)
+ELF_RELOC(R_MIPS_LO16,                6)
+ELF_RELOC(R_MIPS_GPREL16,             7)
+ELF_RELOC(R_MIPS_LITERAL,             8)
+ELF_RELOC(R_MIPS_GOT16,               9)
+ELF_RELOC(R_MIPS_PC16,               10)
+ELF_RELOC(R_MIPS_CALL16,             11)
+ELF_RELOC(R_MIPS_GPREL32,            12)
+ELF_RELOC(R_MIPS_UNUSED1,            13)
+ELF_RELOC(R_MIPS_UNUSED2,            14)
+ELF_RELOC(R_MIPS_UNUSED3,            15)
+ELF_RELOC(R_MIPS_SHIFT5,             16)
+ELF_RELOC(R_MIPS_SHIFT6,             17)
+ELF_RELOC(R_MIPS_64,                 18)
+ELF_RELOC(R_MIPS_GOT_DISP,           19)
+ELF_RELOC(R_MIPS_GOT_PAGE,           20)
+ELF_RELOC(R_MIPS_GOT_OFST,           21)
+ELF_RELOC(R_MIPS_GOT_HI16,           22)
+ELF_RELOC(R_MIPS_GOT_LO16,           23)
+ELF_RELOC(R_MIPS_SUB,                24)
+ELF_RELOC(R_MIPS_INSERT_A,           25)
+ELF_RELOC(R_MIPS_INSERT_B,           26)
+ELF_RELOC(R_MIPS_DELETE,             27)
+ELF_RELOC(R_MIPS_HIGHER,             28)
+ELF_RELOC(R_MIPS_HIGHEST,            29)
+ELF_RELOC(R_MIPS_CALL_HI16,          30)
+ELF_RELOC(R_MIPS_CALL_LO16,          31)
+ELF_RELOC(R_MIPS_SCN_DISP,           32)
+ELF_RELOC(R_MIPS_REL16,              33)
+ELF_RELOC(R_MIPS_ADD_IMMEDIATE,      34)
+ELF_RELOC(R_MIPS_PJUMP,              35)
+ELF_RELOC(R_MIPS_RELGOT,             36)
+ELF_RELOC(R_MIPS_JALR,               37)
+ELF_RELOC(R_MIPS_TLS_DTPMOD32,       38)
+ELF_RELOC(R_MIPS_TLS_DTPREL32,       39)
+ELF_RELOC(R_MIPS_TLS_DTPMOD64,       40)
+ELF_RELOC(R_MIPS_TLS_DTPREL64,       41)
+ELF_RELOC(R_MIPS_TLS_GD,             42)
+ELF_RELOC(R_MIPS_TLS_LDM,            43)
+ELF_RELOC(R_MIPS_TLS_DTPREL_HI16,    44)
+ELF_RELOC(R_MIPS_TLS_DTPREL_LO16,    45)
+ELF_RELOC(R_MIPS_TLS_GOTTPREL,       46)
+ELF_RELOC(R_MIPS_TLS_TPREL32,        47)
+ELF_RELOC(R_MIPS_TLS_TPREL64,        48)
+ELF_RELOC(R_MIPS_TLS_TPREL_HI16,     49)
+ELF_RELOC(R_MIPS_TLS_TPREL_LO16,     50)
+ELF_RELOC(R_MIPS_GLOB_DAT,           51)
+ELF_RELOC(R_MIPS_PC21_S2,            60)
+ELF_RELOC(R_MIPS_PC26_S2,            61)
+ELF_RELOC(R_MIPS_PC18_S3,            62)
+ELF_RELOC(R_MIPS_PC19_S2,            63)
+ELF_RELOC(R_MIPS_PCHI16,             64)
+ELF_RELOC(R_MIPS_PCLO16,             65)
+ELF_RELOC(R_MIPS16_26,               100)
+ELF_RELOC(R_MIPS16_GPREL,            101)
+ELF_RELOC(R_MIPS16_GOT16,            102)
+ELF_RELOC(R_MIPS16_CALL16,           103)
+ELF_RELOC(R_MIPS16_HI16,             104)
+ELF_RELOC(R_MIPS16_LO16,             105)
+ELF_RELOC(R_MIPS16_TLS_GD,           106)
+ELF_RELOC(R_MIPS16_TLS_LDM,          107)
+ELF_RELOC(R_MIPS16_TLS_DTPREL_HI16,  108)
+ELF_RELOC(R_MIPS16_TLS_DTPREL_LO16,  109)
+ELF_RELOC(R_MIPS16_TLS_GOTTPREL,     110)
+ELF_RELOC(R_MIPS16_TLS_TPREL_HI16,   111)
+ELF_RELOC(R_MIPS16_TLS_TPREL_LO16,   112)
+ELF_RELOC(R_MIPS_COPY,               126)
+ELF_RELOC(R_MIPS_JUMP_SLOT,          127)
+ELF_RELOC(R_MICROMIPS_26_S1,         133)
+ELF_RELOC(R_MICROMIPS_HI16,          134)
+ELF_RELOC(R_MICROMIPS_LO16,          135)
+ELF_RELOC(R_MICROMIPS_GPREL16,       136)
+ELF_RELOC(R_MICROMIPS_LITERAL,       137)
+ELF_RELOC(R_MICROMIPS_GOT16,         138)
+ELF_RELOC(R_MICROMIPS_PC7_S1,        139)
+ELF_RELOC(R_MICROMIPS_PC10_S1,       140)
+ELF_RELOC(R_MICROMIPS_PC16_S1,       141)
+ELF_RELOC(R_MICROMIPS_CALL16,        142)
+ELF_RELOC(R_MICROMIPS_GOT_DISP,      145)
+ELF_RELOC(R_MICROMIPS_GOT_PAGE,      146)
+ELF_RELOC(R_MICROMIPS_GOT_OFST,      147)
+ELF_RELOC(R_MICROMIPS_GOT_HI16,      148)
+ELF_RELOC(R_MICROMIPS_GOT_LO16,      149)
+ELF_RELOC(R_MICROMIPS_SUB,           150)
+ELF_RELOC(R_MICROMIPS_HIGHER,        151)
+ELF_RELOC(R_MICROMIPS_HIGHEST,       152)
+ELF_RELOC(R_MICROMIPS_CALL_HI16,     153)
+ELF_RELOC(R_MICROMIPS_CALL_LO16,     154)
+ELF_RELOC(R_MICROMIPS_SCN_DISP,      155)
+ELF_RELOC(R_MICROMIPS_JALR,          156)
+ELF_RELOC(R_MICROMIPS_HI0_LO16,      157)
+ELF_RELOC(R_MICROMIPS_TLS_GD,           162)
+ELF_RELOC(R_MICROMIPS_TLS_LDM,          163)
+ELF_RELOC(R_MICROMIPS_TLS_DTPREL_HI16,  164)
+ELF_RELOC(R_MICROMIPS_TLS_DTPREL_LO16,  165)
+ELF_RELOC(R_MICROMIPS_TLS_GOTTPREL,     166)
+ELF_RELOC(R_MICROMIPS_TLS_TPREL_HI16,   169)
+ELF_RELOC(R_MICROMIPS_TLS_TPREL_LO16,   170)
+ELF_RELOC(R_MICROMIPS_GPREL7_S2,        172)
+ELF_RELOC(R_MICROMIPS_PC23_S2,          173)
+ELF_RELOC(R_MICROMIPS_PC21_S1,          174)
+ELF_RELOC(R_MICROMIPS_PC26_S1,          175)
+ELF_RELOC(R_MICROMIPS_PC18_S3,          176)
+ELF_RELOC(R_MICROMIPS_PC19_S2,          177)
+ELF_RELOC(R_MIPS_NUM,                218)
+ELF_RELOC(R_MIPS_PC32,               248)
+ELF_RELOC(R_MIPS_EH,                 249)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/PowerPC.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/PowerPC.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/PowerPC.def
@@ -0,0 +1,156 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+// glibc's PowerPC asm/sigcontext.h, when compiling for PPC64, has the
+// unfortunate behavior of including asm/elf.h, which defines R_PPC_NONE, etc.
+// to their corresponding integer values. As a result, we need to undef them
+// here before continuing.
+
+#undef R_PPC_NONE
+#undef R_PPC_ADDR32
+#undef R_PPC_ADDR24
+#undef R_PPC_ADDR16
+#undef R_PPC_ADDR16_LO
+#undef R_PPC_ADDR16_HI
+#undef R_PPC_ADDR16_HA
+#undef R_PPC_ADDR14
+#undef R_PPC_ADDR14_BRTAKEN
+#undef R_PPC_ADDR14_BRNTAKEN
+#undef R_PPC_REL24
+#undef R_PPC_REL14
+#undef R_PPC_REL14_BRTAKEN
+#undef R_PPC_REL14_BRNTAKEN
+#undef R_PPC_GOT16
+#undef R_PPC_GOT16_LO
+#undef R_PPC_GOT16_HI
+#undef R_PPC_GOT16_HA
+#undef R_PPC_PLTREL24
+#undef R_PPC_COPY
+#undef R_PPC_GLOB_DAT
+#undef R_PPC_JMP_SLOT
+#undef R_PPC_RELATIVE
+#undef R_PPC_LOCAL24PC
+#undef R_PPC_UADDR32
+#undef R_PPC_UADDR16
+#undef R_PPC_REL32
+#undef R_PPC_PLT32
+#undef R_PPC_PLTREL32
+#undef R_PPC_PLT16_LO
+#undef R_PPC_PLT16_HI
+#undef R_PPC_PLT16_HA
+#undef R_PPC_SDAREL16
+#undef R_PPC_SECTOFF
+#undef R_PPC_SECTOFF_LO
+#undef R_PPC_SECTOFF_HI
+#undef R_PPC_SECTOFF_HA
+#undef R_PPC_ADDR30
+#undef R_PPC_TLS
+#undef R_PPC_DTPMOD32
+#undef R_PPC_TPREL16
+#undef R_PPC_TPREL16_LO
+#undef R_PPC_TPREL16_HI
+#undef R_PPC_TPREL16_HA
+#undef R_PPC_TPREL32
+#undef R_PPC_DTPREL16
+#undef R_PPC_DTPREL16_LO
+#undef R_PPC_DTPREL16_HI
+#undef R_PPC_DTPREL16_HA
+#undef R_PPC_DTPREL32
+#undef R_PPC_GOT_TLSGD16
+#undef R_PPC_GOT_TLSGD16_LO
+#undef R_PPC_GOT_TLSGD16_HI
+#undef R_PPC_GOT_TLSGD16_HA
+#undef R_PPC_GOT_TLSLD16
+#undef R_PPC_GOT_TLSLD16_LO
+#undef R_PPC_GOT_TLSLD16_HI
+#undef R_PPC_GOT_TLSLD16_HA
+#undef R_PPC_GOT_TPREL16
+#undef R_PPC_GOT_TPREL16_LO
+#undef R_PPC_GOT_TPREL16_HI
+#undef R_PPC_GOT_TPREL16_HA
+#undef R_PPC_GOT_DTPREL16
+#undef R_PPC_GOT_DTPREL16_LO
+#undef R_PPC_GOT_DTPREL16_HI
+#undef R_PPC_GOT_DTPREL16_HA
+#undef R_PPC_TLSGD
+#undef R_PPC_TLSLD
+#undef R_PPC_REL16
+#undef R_PPC_REL16_LO
+#undef R_PPC_REL16_HI
+#undef R_PPC_REL16_HA
+
+ELF_RELOC(R_PPC_NONE,                   0)      /* No relocation. */
+ELF_RELOC(R_PPC_ADDR32,                 1)
+ELF_RELOC(R_PPC_ADDR24,                 2)
+ELF_RELOC(R_PPC_ADDR16,                 3)
+ELF_RELOC(R_PPC_ADDR16_LO,              4)
+ELF_RELOC(R_PPC_ADDR16_HI,              5)
+ELF_RELOC(R_PPC_ADDR16_HA,              6)
+ELF_RELOC(R_PPC_ADDR14,                 7)
+ELF_RELOC(R_PPC_ADDR14_BRTAKEN,         8)
+ELF_RELOC(R_PPC_ADDR14_BRNTAKEN,        9)
+ELF_RELOC(R_PPC_REL24,                  10)
+ELF_RELOC(R_PPC_REL14,                  11)
+ELF_RELOC(R_PPC_REL14_BRTAKEN,          12)
+ELF_RELOC(R_PPC_REL14_BRNTAKEN,         13)
+ELF_RELOC(R_PPC_GOT16,                  14)
+ELF_RELOC(R_PPC_GOT16_LO,               15)
+ELF_RELOC(R_PPC_GOT16_HI,               16)
+ELF_RELOC(R_PPC_GOT16_HA,               17)
+ELF_RELOC(R_PPC_PLTREL24,               18)
+ELF_RELOC(R_PPC_COPY,                   19)
+ELF_RELOC(R_PPC_GLOB_DAT,               20)
+ELF_RELOC(R_PPC_JMP_SLOT,               21)
+ELF_RELOC(R_PPC_RELATIVE,               22)
+ELF_RELOC(R_PPC_LOCAL24PC,              23)
+ELF_RELOC(R_PPC_UADDR32,                24)
+ELF_RELOC(R_PPC_UADDR16,                25)
+ELF_RELOC(R_PPC_REL32,                  26)
+ELF_RELOC(R_PPC_PLT32,                  27)
+ELF_RELOC(R_PPC_PLTREL32,               28)
+ELF_RELOC(R_PPC_PLT16_LO,               29)
+ELF_RELOC(R_PPC_PLT16_HI,               30)
+ELF_RELOC(R_PPC_PLT16_HA,               31)
+ELF_RELOC(R_PPC_SDAREL16,               32)
+ELF_RELOC(R_PPC_SECTOFF,                33)
+ELF_RELOC(R_PPC_SECTOFF_LO,             34)
+ELF_RELOC(R_PPC_SECTOFF_HI,             35)
+ELF_RELOC(R_PPC_SECTOFF_HA,             36)
+ELF_RELOC(R_PPC_ADDR30,                 37)
+ELF_RELOC(R_PPC_TLS,                    67)
+ELF_RELOC(R_PPC_DTPMOD32,               68)
+ELF_RELOC(R_PPC_TPREL16,                69)
+ELF_RELOC(R_PPC_TPREL16_LO,             70)
+ELF_RELOC(R_PPC_TPREL16_HI,             71)
+ELF_RELOC(R_PPC_TPREL16_HA,             72)
+ELF_RELOC(R_PPC_TPREL32,                73)
+ELF_RELOC(R_PPC_DTPREL16,               74)
+ELF_RELOC(R_PPC_DTPREL16_LO,            75)
+ELF_RELOC(R_PPC_DTPREL16_HI,            76)
+ELF_RELOC(R_PPC_DTPREL16_HA,            77)
+ELF_RELOC(R_PPC_DTPREL32,               78)
+ELF_RELOC(R_PPC_GOT_TLSGD16,            79)
+ELF_RELOC(R_PPC_GOT_TLSGD16_LO,         80)
+ELF_RELOC(R_PPC_GOT_TLSGD16_HI,         81)
+ELF_RELOC(R_PPC_GOT_TLSGD16_HA,         82)
+ELF_RELOC(R_PPC_GOT_TLSLD16,            83)
+ELF_RELOC(R_PPC_GOT_TLSLD16_LO,         84)
+ELF_RELOC(R_PPC_GOT_TLSLD16_HI,         85)
+ELF_RELOC(R_PPC_GOT_TLSLD16_HA,         86)
+ELF_RELOC(R_PPC_GOT_TPREL16,            87)
+ELF_RELOC(R_PPC_GOT_TPREL16_LO,         88)
+ELF_RELOC(R_PPC_GOT_TPREL16_HI,         89)
+ELF_RELOC(R_PPC_GOT_TPREL16_HA,         90)
+ELF_RELOC(R_PPC_GOT_DTPREL16,           91)
+ELF_RELOC(R_PPC_GOT_DTPREL16_LO,        92)
+ELF_RELOC(R_PPC_GOT_DTPREL16_HI,        93)
+ELF_RELOC(R_PPC_GOT_DTPREL16_HA,        94)
+ELF_RELOC(R_PPC_TLSGD,                  95)
+ELF_RELOC(R_PPC_TLSLD,                  96)
+ELF_RELOC(R_PPC_IRELATIVE,              248)
+ELF_RELOC(R_PPC_REL16,                  249)
+ELF_RELOC(R_PPC_REL16_LO,               250)
+ELF_RELOC(R_PPC_REL16_HI,               251)
+ELF_RELOC(R_PPC_REL16_HA,               252)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def
@@ -0,0 +1,195 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+// glibc's PowerPC asm/sigcontext.h, when compiling for PPC64, has the
+// unfortunate behavior of including asm/elf.h, which defines R_PPC_NONE, etc.
+// to their corresponding integer values. As a result, we need to undef them
+// here before continuing.
+
+#undef R_PPC64_NONE
+#undef R_PPC64_ADDR32
+#undef R_PPC64_ADDR24
+#undef R_PPC64_ADDR16
+#undef R_PPC64_ADDR16_LO
+#undef R_PPC64_ADDR16_HI
+#undef R_PPC64_ADDR16_HA
+#undef R_PPC64_ADDR14
+#undef R_PPC64_ADDR14_BRTAKEN
+#undef R_PPC64_ADDR14_BRNTAKEN
+#undef R_PPC64_REL24
+#undef R_PPC64_REL14
+#undef R_PPC64_REL14_BRTAKEN
+#undef R_PPC64_REL14_BRNTAKEN
+#undef R_PPC64_GOT16
+#undef R_PPC64_GOT16_LO
+#undef R_PPC64_GOT16_HI
+#undef R_PPC64_GOT16_HA
+#undef R_PPC64_GLOB_DAT
+#undef R_PPC64_JMP_SLOT
+#undef R_PPC64_RELATIVE
+#undef R_PPC64_REL32
+#undef R_PPC64_ADDR64
+#undef R_PPC64_ADDR16_HIGHER
+#undef R_PPC64_ADDR16_HIGHERA
+#undef R_PPC64_ADDR16_HIGHEST
+#undef R_PPC64_ADDR16_HIGHESTA
+#undef R_PPC64_REL64
+#undef R_PPC64_TOC16
+#undef R_PPC64_TOC16_LO
+#undef R_PPC64_TOC16_HI
+#undef R_PPC64_TOC16_HA
+#undef R_PPC64_TOC
+#undef R_PPC64_ADDR16_DS
+#undef R_PPC64_ADDR16_LO_DS
+#undef R_PPC64_GOT16_DS
+#undef R_PPC64_GOT16_LO_DS
+#undef R_PPC64_TOC16_DS
+#undef R_PPC64_TOC16_LO_DS
+#undef R_PPC64_TLS
+#undef R_PPC64_DTPMOD64
+#undef R_PPC64_TPREL16
+#undef R_PPC64_TPREL16_LO
+#undef R_PPC64_TPREL16_HI
+#undef R_PPC64_TPREL16_HA
+#undef R_PPC64_TPREL64
+#undef R_PPC64_DTPREL16
+#undef R_PPC64_DTPREL16_LO
+#undef R_PPC64_DTPREL16_HI
+#undef R_PPC64_DTPREL16_HA
+#undef R_PPC64_DTPREL64
+#undef R_PPC64_GOT_TLSGD16
+#undef R_PPC64_GOT_TLSGD16_LO
+#undef R_PPC64_GOT_TLSGD16_HI
+#undef R_PPC64_GOT_TLSGD16_HA
+#undef R_PPC64_GOT_TLSLD16
+#undef R_PPC64_GOT_TLSLD16_LO
+#undef R_PPC64_GOT_TLSLD16_HI
+#undef R_PPC64_GOT_TLSLD16_HA
+#undef R_PPC64_GOT_TPREL16_DS
+#undef R_PPC64_GOT_TPREL16_LO_DS
+#undef R_PPC64_GOT_TPREL16_HI
+#undef R_PPC64_GOT_TPREL16_HA
+#undef R_PPC64_GOT_DTPREL16_DS
+#undef R_PPC64_GOT_DTPREL16_LO_DS
+#undef R_PPC64_GOT_DTPREL16_HI
+#undef R_PPC64_GOT_DTPREL16_HA
+#undef R_PPC64_TPREL16_DS
+#undef R_PPC64_TPREL16_LO_DS
+#undef R_PPC64_TPREL16_HIGHER
+#undef R_PPC64_TPREL16_HIGHERA
+#undef R_PPC64_TPREL16_HIGHEST
+#undef R_PPC64_TPREL16_HIGHESTA
+#undef R_PPC64_DTPREL16_DS
+#undef R_PPC64_DTPREL16_LO_DS
+#undef R_PPC64_DTPREL16_HIGHER
+#undef R_PPC64_DTPREL16_HIGHERA
+#undef R_PPC64_DTPREL16_HIGHEST
+#undef R_PPC64_DTPREL16_HIGHESTA
+#undef R_PPC64_TLSGD
+#undef R_PPC64_TLSLD
+#undef R_PPC64_ADDR16_HIGH
+#undef R_PPC64_ADDR16_HIGHA
+#undef R_PPC64_TPREL16_HIGH
+#undef R_PPC64_TPREL16_HIGHA
+#undef R_PPC64_DTPREL16_HIGH
+#undef R_PPC64_DTPREL16_HIGHA
+#undef R_PPC64_IRELATIVE
+#undef R_PPC64_REL16
+#undef R_PPC64_REL16_LO
+#undef R_PPC64_REL16_HI
+#undef R_PPC64_REL16_HA
+
+ELF_RELOC(R_PPC64_NONE,                 0)
+ELF_RELOC(R_PPC64_ADDR32,               1)
+ELF_RELOC(R_PPC64_ADDR24,               2)
+ELF_RELOC(R_PPC64_ADDR16,               3)
+ELF_RELOC(R_PPC64_ADDR16_LO,            4)
+ELF_RELOC(R_PPC64_ADDR16_HI,            5)
+ELF_RELOC(R_PPC64_ADDR16_HA,            6)
+ELF_RELOC(R_PPC64_ADDR14,               7)
+ELF_RELOC(R_PPC64_ADDR14_BRTAKEN,       8)
+ELF_RELOC(R_PPC64_ADDR14_BRNTAKEN,      9)
+ELF_RELOC(R_PPC64_REL24,                10)
+ELF_RELOC(R_PPC64_REL14,                11)
+ELF_RELOC(R_PPC64_REL14_BRTAKEN,        12)
+ELF_RELOC(R_PPC64_REL14_BRNTAKEN,       13)
+ELF_RELOC(R_PPC64_GOT16,                14)
+ELF_RELOC(R_PPC64_GOT16_LO,             15)
+ELF_RELOC(R_PPC64_GOT16_HI,             16)
+ELF_RELOC(R_PPC64_GOT16_HA,             17)
+ELF_RELOC(R_PPC64_GLOB_DAT,             20)
+ELF_RELOC(R_PPC64_JMP_SLOT,             21)
+ELF_RELOC(R_PPC64_RELATIVE,             22)
+ELF_RELOC(R_PPC64_REL32,                26)
+ELF_RELOC(R_PPC64_ADDR64,               38)
+ELF_RELOC(R_PPC64_ADDR16_HIGHER,        39)
+ELF_RELOC(R_PPC64_ADDR16_HIGHERA,       40)
+ELF_RELOC(R_PPC64_ADDR16_HIGHEST,       41)
+ELF_RELOC(R_PPC64_ADDR16_HIGHESTA,      42)
+ELF_RELOC(R_PPC64_REL64,                44)
+ELF_RELOC(R_PPC64_TOC16,                47)
+ELF_RELOC(R_PPC64_TOC16_LO,             48)
+ELF_RELOC(R_PPC64_TOC16_HI,             49)
+ELF_RELOC(R_PPC64_TOC16_HA,             50)
+ELF_RELOC(R_PPC64_TOC,                  51)
+ELF_RELOC(R_PPC64_ADDR16_DS,            56)
+ELF_RELOC(R_PPC64_ADDR16_LO_DS,         57)
+ELF_RELOC(R_PPC64_GOT16_DS,             58)
+ELF_RELOC(R_PPC64_GOT16_LO_DS,          59)
+ELF_RELOC(R_PPC64_TOC16_DS,             63)
+ELF_RELOC(R_PPC64_TOC16_LO_DS,          64)
+ELF_RELOC(R_PPC64_TLS,                  67)
+ELF_RELOC(R_PPC64_DTPMOD64,             68)
+ELF_RELOC(R_PPC64_TPREL16,              69)
+ELF_RELOC(R_PPC64_TPREL16_LO,           70)
+ELF_RELOC(R_PPC64_TPREL16_HI,           71)
+ELF_RELOC(R_PPC64_TPREL16_HA,           72)
+ELF_RELOC(R_PPC64_TPREL64,              73)
+ELF_RELOC(R_PPC64_DTPREL16,             74)
+ELF_RELOC(R_PPC64_DTPREL16_LO,          75)
+ELF_RELOC(R_PPC64_DTPREL16_HI,          76)
+ELF_RELOC(R_PPC64_DTPREL16_HA,          77)
+ELF_RELOC(R_PPC64_DTPREL64,             78)
+ELF_RELOC(R_PPC64_GOT_TLSGD16,          79)
+ELF_RELOC(R_PPC64_GOT_TLSGD16_LO,       80)
+ELF_RELOC(R_PPC64_GOT_TLSGD16_HI,       81)
+ELF_RELOC(R_PPC64_GOT_TLSGD16_HA,       82)
+ELF_RELOC(R_PPC64_GOT_TLSLD16,          83)
+ELF_RELOC(R_PPC64_GOT_TLSLD16_LO,       84)
+ELF_RELOC(R_PPC64_GOT_TLSLD16_HI,       85)
+ELF_RELOC(R_PPC64_GOT_TLSLD16_HA,       86)
+ELF_RELOC(R_PPC64_GOT_TPREL16_DS,       87)
+ELF_RELOC(R_PPC64_GOT_TPREL16_LO_DS,    88)
+ELF_RELOC(R_PPC64_GOT_TPREL16_HI,       89)
+ELF_RELOC(R_PPC64_GOT_TPREL16_HA,       90)
+ELF_RELOC(R_PPC64_GOT_DTPREL16_DS,      91)
+ELF_RELOC(R_PPC64_GOT_DTPREL16_LO_DS,   92)
+ELF_RELOC(R_PPC64_GOT_DTPREL16_HI,      93)
+ELF_RELOC(R_PPC64_GOT_DTPREL16_HA,      94)
+ELF_RELOC(R_PPC64_TPREL16_DS,           95)
+ELF_RELOC(R_PPC64_TPREL16_LO_DS,        96)
+ELF_RELOC(R_PPC64_TPREL16_HIGHER,       97)
+ELF_RELOC(R_PPC64_TPREL16_HIGHERA,      98)
+ELF_RELOC(R_PPC64_TPREL16_HIGHEST,      99)
+ELF_RELOC(R_PPC64_TPREL16_HIGHESTA,     100)
+ELF_RELOC(R_PPC64_DTPREL16_DS,          101)
+ELF_RELOC(R_PPC64_DTPREL16_LO_DS,       102)
+ELF_RELOC(R_PPC64_DTPREL16_HIGHER,      103)
+ELF_RELOC(R_PPC64_DTPREL16_HIGHERA,     104)
+ELF_RELOC(R_PPC64_DTPREL16_HIGHEST,     105)
+ELF_RELOC(R_PPC64_DTPREL16_HIGHESTA,    106)
+ELF_RELOC(R_PPC64_TLSGD,                107)
+ELF_RELOC(R_PPC64_TLSLD,                108)
+ELF_RELOC(R_PPC64_ADDR16_HIGH,          110)
+ELF_RELOC(R_PPC64_ADDR16_HIGHA,         111)
+ELF_RELOC(R_PPC64_TPREL16_HIGH,         112)
+ELF_RELOC(R_PPC64_TPREL16_HIGHA,        113)
+ELF_RELOC(R_PPC64_DTPREL16_HIGH,        114)
+ELF_RELOC(R_PPC64_DTPREL16_HIGHA,       115)
+ELF_RELOC(R_PPC64_IRELATIVE,            248)
+ELF_RELOC(R_PPC64_REL16,                249)
+ELF_RELOC(R_PPC64_REL16_LO,             250)
+ELF_RELOC(R_PPC64_REL16_HI,             251)
+ELF_RELOC(R_PPC64_REL16_HA,             252)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/RISCV.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/RISCV.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/RISCV.def
@@ -0,0 +1,59 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+ELF_RELOC(R_RISCV_NONE,               0)
+ELF_RELOC(R_RISCV_32,                 1)
+ELF_RELOC(R_RISCV_64,                 2)
+ELF_RELOC(R_RISCV_RELATIVE,           3)
+ELF_RELOC(R_RISCV_COPY,               4)
+ELF_RELOC(R_RISCV_JUMP_SLOT,          5)
+ELF_RELOC(R_RISCV_TLS_DTPMOD32,       6)
+ELF_RELOC(R_RISCV_TLS_DTPMOD64,       7)
+ELF_RELOC(R_RISCV_TLS_DTPREL32,       8)
+ELF_RELOC(R_RISCV_TLS_DTPREL64,       9)
+ELF_RELOC(R_RISCV_TLS_TPREL32,       10)
+ELF_RELOC(R_RISCV_TLS_TPREL64,       11)
+ELF_RELOC(R_RISCV_BRANCH,            16)
+ELF_RELOC(R_RISCV_JAL,               17)
+ELF_RELOC(R_RISCV_CALL,              18)
+ELF_RELOC(R_RISCV_CALL_PLT,          19)
+ELF_RELOC(R_RISCV_GOT_HI20,          20)
+ELF_RELOC(R_RISCV_TLS_GOT_HI20,      21)
+ELF_RELOC(R_RISCV_TLS_GD_HI20,       22)
+ELF_RELOC(R_RISCV_PCREL_HI20,        23)
+ELF_RELOC(R_RISCV_PCREL_LO12_I,      24)
+ELF_RELOC(R_RISCV_PCREL_LO12_S,      25)
+ELF_RELOC(R_RISCV_HI20,              26)
+ELF_RELOC(R_RISCV_LO12_I,            27)
+ELF_RELOC(R_RISCV_LO12_S,            28)
+ELF_RELOC(R_RISCV_TPREL_HI20,        29)
+ELF_RELOC(R_RISCV_TPREL_LO12_I,      30)
+ELF_RELOC(R_RISCV_TPREL_LO12_S,      31)
+ELF_RELOC(R_RISCV_TPREL_ADD,         32)
+ELF_RELOC(R_RISCV_ADD8,              33)
+ELF_RELOC(R_RISCV_ADD16,             34)
+ELF_RELOC(R_RISCV_ADD32,             35)
+ELF_RELOC(R_RISCV_ADD64,             36)
+ELF_RELOC(R_RISCV_SUB8,              37)
+ELF_RELOC(R_RISCV_SUB16,             38)
+ELF_RELOC(R_RISCV_SUB32,             39)
+ELF_RELOC(R_RISCV_SUB64,             40)
+ELF_RELOC(R_RISCV_GNU_VTINHERIT,     41)
+ELF_RELOC(R_RISCV_GNU_VTENTRY,       42)
+ELF_RELOC(R_RISCV_ALIGN,             43)
+ELF_RELOC(R_RISCV_RVC_BRANCH,        44)
+ELF_RELOC(R_RISCV_RVC_JUMP,          45)
+ELF_RELOC(R_RISCV_RVC_LUI,           46)
+ELF_RELOC(R_RISCV_GPREL_I,           47)
+ELF_RELOC(R_RISCV_GPREL_S,           48)
+ELF_RELOC(R_RISCV_TPREL_I,           49)
+ELF_RELOC(R_RISCV_TPREL_S,           50)
+ELF_RELOC(R_RISCV_RELAX,             51)
+ELF_RELOC(R_RISCV_SUB6,              52)
+ELF_RELOC(R_RISCV_SET6,              53)
+ELF_RELOC(R_RISCV_SET8,              54)
+ELF_RELOC(R_RISCV_SET16,             55)
+ELF_RELOC(R_RISCV_SET32,             56)
+ELF_RELOC(R_RISCV_32_PCREL,          57)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Sparc.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Sparc.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/Sparc.def
@@ -0,0 +1,89 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+ELF_RELOC(R_SPARC_NONE,         0)
+ELF_RELOC(R_SPARC_8,            1)
+ELF_RELOC(R_SPARC_16,           2)
+ELF_RELOC(R_SPARC_32,           3)
+ELF_RELOC(R_SPARC_DISP8,        4)
+ELF_RELOC(R_SPARC_DISP16,       5)
+ELF_RELOC(R_SPARC_DISP32,       6)
+ELF_RELOC(R_SPARC_WDISP30,      7)
+ELF_RELOC(R_SPARC_WDISP22,      8)
+ELF_RELOC(R_SPARC_HI22,         9)
+ELF_RELOC(R_SPARC_22,           10)
+ELF_RELOC(R_SPARC_13,           11)
+ELF_RELOC(R_SPARC_LO10,         12)
+ELF_RELOC(R_SPARC_GOT10,        13)
+ELF_RELOC(R_SPARC_GOT13,        14)
+ELF_RELOC(R_SPARC_GOT22,        15)
+ELF_RELOC(R_SPARC_PC10,         16)
+ELF_RELOC(R_SPARC_PC22,         17)
+ELF_RELOC(R_SPARC_WPLT30,       18)
+ELF_RELOC(R_SPARC_COPY,         19)
+ELF_RELOC(R_SPARC_GLOB_DAT,     20)
+ELF_RELOC(R_SPARC_JMP_SLOT,     21)
+ELF_RELOC(R_SPARC_RELATIVE,     22)
+ELF_RELOC(R_SPARC_UA32,         23)
+ELF_RELOC(R_SPARC_PLT32,        24)
+ELF_RELOC(R_SPARC_HIPLT22,      25)
+ELF_RELOC(R_SPARC_LOPLT10,      26)
+ELF_RELOC(R_SPARC_PCPLT32,      27)
+ELF_RELOC(R_SPARC_PCPLT22,      28)
+ELF_RELOC(R_SPARC_PCPLT10,      29)
+ELF_RELOC(R_SPARC_10,           30)
+ELF_RELOC(R_SPARC_11,           31)
+ELF_RELOC(R_SPARC_64,           32)
+ELF_RELOC(R_SPARC_OLO10,        33)
+ELF_RELOC(R_SPARC_HH22,         34)
+ELF_RELOC(R_SPARC_HM10,         35)
+ELF_RELOC(R_SPARC_LM22,         36)
+ELF_RELOC(R_SPARC_PC_HH22,      37)
+ELF_RELOC(R_SPARC_PC_HM10,      38)
+ELF_RELOC(R_SPARC_PC_LM22,      39)
+ELF_RELOC(R_SPARC_WDISP16,      40)
+ELF_RELOC(R_SPARC_WDISP19,      41)
+ELF_RELOC(R_SPARC_7,            43)
+ELF_RELOC(R_SPARC_5,            44)
+ELF_RELOC(R_SPARC_6,            45)
+ELF_RELOC(R_SPARC_DISP64,       46)
+ELF_RELOC(R_SPARC_PLT64,        47)
+ELF_RELOC(R_SPARC_HIX22,        48)
+ELF_RELOC(R_SPARC_LOX10,        49)
+ELF_RELOC(R_SPARC_H44,          50)
+ELF_RELOC(R_SPARC_M44,          51)
+ELF_RELOC(R_SPARC_L44,          52)
+ELF_RELOC(R_SPARC_REGISTER,     53)
+ELF_RELOC(R_SPARC_UA64,         54)
+ELF_RELOC(R_SPARC_UA16,         55)
+ELF_RELOC(R_SPARC_TLS_GD_HI22,    56)
+ELF_RELOC(R_SPARC_TLS_GD_LO10,    57)
+ELF_RELOC(R_SPARC_TLS_GD_ADD,     58)
+ELF_RELOC(R_SPARC_TLS_GD_CALL,    59)
+ELF_RELOC(R_SPARC_TLS_LDM_HI22,   60)
+ELF_RELOC(R_SPARC_TLS_LDM_LO10,   61)
+ELF_RELOC(R_SPARC_TLS_LDM_ADD,    62)
+ELF_RELOC(R_SPARC_TLS_LDM_CALL,   63)
+ELF_RELOC(R_SPARC_TLS_LDO_HIX22,  64)
+ELF_RELOC(R_SPARC_TLS_LDO_LOX10,  65)
+ELF_RELOC(R_SPARC_TLS_LDO_ADD,    66)
+ELF_RELOC(R_SPARC_TLS_IE_HI22,    67)
+ELF_RELOC(R_SPARC_TLS_IE_LO10,    68)
+ELF_RELOC(R_SPARC_TLS_IE_LD,      69)
+ELF_RELOC(R_SPARC_TLS_IE_LDX,     70)
+ELF_RELOC(R_SPARC_TLS_IE_ADD,     71)
+ELF_RELOC(R_SPARC_TLS_LE_HIX22,   72)
+ELF_RELOC(R_SPARC_TLS_LE_LOX10,   73)
+ELF_RELOC(R_SPARC_TLS_DTPMOD32,   74)
+ELF_RELOC(R_SPARC_TLS_DTPMOD64,   75)
+ELF_RELOC(R_SPARC_TLS_DTPOFF32,   76)
+ELF_RELOC(R_SPARC_TLS_DTPOFF64,   77)
+ELF_RELOC(R_SPARC_TLS_TPOFF32,    78)
+ELF_RELOC(R_SPARC_TLS_TPOFF64,    79)
+ELF_RELOC(R_SPARC_GOTDATA_HIX22,  80)
+ELF_RELOC(R_SPARC_GOTDATA_LOX10,  81)
+ELF_RELOC(R_SPARC_GOTDATA_OP_HIX22,  82)
+ELF_RELOC(R_SPARC_GOTDATA_OP_LOX10,  83)
+ELF_RELOC(R_SPARC_GOTDATA_OP,     84)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/SystemZ.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/SystemZ.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/SystemZ.def
@@ -0,0 +1,71 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+ELF_RELOC(R_390_NONE,          0)
+ELF_RELOC(R_390_8,             1)
+ELF_RELOC(R_390_12,            2)
+ELF_RELOC(R_390_16,            3)
+ELF_RELOC(R_390_32,            4)
+ELF_RELOC(R_390_PC32,          5)
+ELF_RELOC(R_390_GOT12,         6)
+ELF_RELOC(R_390_GOT32,         7)
+ELF_RELOC(R_390_PLT32,         8)
+ELF_RELOC(R_390_COPY,          9)
+ELF_RELOC(R_390_GLOB_DAT,     10)
+ELF_RELOC(R_390_JMP_SLOT,     11)
+ELF_RELOC(R_390_RELATIVE,     12)
+ELF_RELOC(R_390_GOTOFF,       13)
+ELF_RELOC(R_390_GOTPC,        14)
+ELF_RELOC(R_390_GOT16,        15)
+ELF_RELOC(R_390_PC16,         16)
+ELF_RELOC(R_390_PC16DBL,      17)
+ELF_RELOC(R_390_PLT16DBL,     18)
+ELF_RELOC(R_390_PC32DBL,      19)
+ELF_RELOC(R_390_PLT32DBL,     20)
+ELF_RELOC(R_390_GOTPCDBL,     21)
+ELF_RELOC(R_390_64,           22)
+ELF_RELOC(R_390_PC64,         23)
+ELF_RELOC(R_390_GOT64,        24)
+ELF_RELOC(R_390_PLT64,        25)
+ELF_RELOC(R_390_GOTENT,       26)
+ELF_RELOC(R_390_GOTOFF16,     27)
+ELF_RELOC(R_390_GOTOFF64,     28)
+ELF_RELOC(R_390_GOTPLT12,     29)
+ELF_RELOC(R_390_GOTPLT16,     30)
+ELF_RELOC(R_390_GOTPLT32,     31)
+ELF_RELOC(R_390_GOTPLT64,     32)
+ELF_RELOC(R_390_GOTPLTENT,    33)
+ELF_RELOC(R_390_PLTOFF16,     34)
+ELF_RELOC(R_390_PLTOFF32,     35)
+ELF_RELOC(R_390_PLTOFF64,     36)
+ELF_RELOC(R_390_TLS_LOAD,     37)
+ELF_RELOC(R_390_TLS_GDCALL,   38)
+ELF_RELOC(R_390_TLS_LDCALL,   39)
+ELF_RELOC(R_390_TLS_GD32,     40)
+ELF_RELOC(R_390_TLS_GD64,     41)
+ELF_RELOC(R_390_TLS_GOTIE12,  42)
+ELF_RELOC(R_390_TLS_GOTIE32,  43)
+ELF_RELOC(R_390_TLS_GOTIE64,  44)
+ELF_RELOC(R_390_TLS_LDM32,    45)
+ELF_RELOC(R_390_TLS_LDM64,    46)
+ELF_RELOC(R_390_TLS_IE32,     47)
+ELF_RELOC(R_390_TLS_IE64,     48)
+ELF_RELOC(R_390_TLS_IEENT,    49)
+ELF_RELOC(R_390_TLS_LE32,     50)
+ELF_RELOC(R_390_TLS_LE64,     51)
+ELF_RELOC(R_390_TLS_LDO32,    52)
+ELF_RELOC(R_390_TLS_LDO64,    53)
+ELF_RELOC(R_390_TLS_DTPMOD,   54)
+ELF_RELOC(R_390_TLS_DTPOFF,   55)
+ELF_RELOC(R_390_TLS_TPOFF,    56)
+ELF_RELOC(R_390_20,           57)
+ELF_RELOC(R_390_GOT20,        58)
+ELF_RELOC(R_390_GOTPLT20,     59)
+ELF_RELOC(R_390_TLS_GOTIE20,  60)
+ELF_RELOC(R_390_IRELATIVE,    61)
+ELF_RELOC(R_390_PC12DBL,      62)
+ELF_RELOC(R_390_PLT12DBL,     63)
+ELF_RELOC(R_390_PC24DBL,      64)
+ELF_RELOC(R_390_PLT24DBL,     65)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/i386.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/i386.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/i386.def
@@ -0,0 +1,47 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+// TODO: this is just a subset
+ELF_RELOC(R_386_NONE,           0)
+ELF_RELOC(R_386_32,             1)
+ELF_RELOC(R_386_PC32,           2)
+ELF_RELOC(R_386_GOT32,          3)
+ELF_RELOC(R_386_PLT32,          4)
+ELF_RELOC(R_386_COPY,           5)
+ELF_RELOC(R_386_GLOB_DAT,       6)
+ELF_RELOC(R_386_JUMP_SLOT,      7)
+ELF_RELOC(R_386_RELATIVE,       8)
+ELF_RELOC(R_386_GOTOFF,         9)
+ELF_RELOC(R_386_GOTPC,          10)
+ELF_RELOC(R_386_32PLT,          11)
+ELF_RELOC(R_386_TLS_TPOFF,      14)
+ELF_RELOC(R_386_TLS_IE,         15)
+ELF_RELOC(R_386_TLS_GOTIE,      16)
+ELF_RELOC(R_386_TLS_LE,         17)
+ELF_RELOC(R_386_TLS_GD,         18)
+ELF_RELOC(R_386_TLS_LDM,        19)
+ELF_RELOC(R_386_16,             20)
+ELF_RELOC(R_386_PC16,           21)
+ELF_RELOC(R_386_8,              22)
+ELF_RELOC(R_386_PC8,            23)
+ELF_RELOC(R_386_TLS_GD_32,      24)
+ELF_RELOC(R_386_TLS_GD_PUSH,    25)
+ELF_RELOC(R_386_TLS_GD_CALL,    26)
+ELF_RELOC(R_386_TLS_GD_POP,     27)
+ELF_RELOC(R_386_TLS_LDM_32,     28)
+ELF_RELOC(R_386_TLS_LDM_PUSH,   29)
+ELF_RELOC(R_386_TLS_LDM_CALL,   30)
+ELF_RELOC(R_386_TLS_LDM_POP,    31)
+ELF_RELOC(R_386_TLS_LDO_32,     32)
+ELF_RELOC(R_386_TLS_IE_32,      33)
+ELF_RELOC(R_386_TLS_LE_32,      34)
+ELF_RELOC(R_386_TLS_DTPMOD32,   35)
+ELF_RELOC(R_386_TLS_DTPOFF32,   36)
+ELF_RELOC(R_386_TLS_TPOFF32,    37)
+ELF_RELOC(R_386_TLS_GOTDESC,    39)
+ELF_RELOC(R_386_TLS_DESC_CALL,  40)
+ELF_RELOC(R_386_TLS_DESC,       41)
+ELF_RELOC(R_386_IRELATIVE,      42)
+ELF_RELOC(R_386_GOT32X,         43)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/x86_64.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/x86_64.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/ELFRelocs/x86_64.def
@@ -0,0 +1,45 @@
+
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+ELF_RELOC(R_X86_64_NONE,        0)
+ELF_RELOC(R_X86_64_64,          1)
+ELF_RELOC(R_X86_64_PC32,        2)
+ELF_RELOC(R_X86_64_GOT32,       3)
+ELF_RELOC(R_X86_64_PLT32,       4)
+ELF_RELOC(R_X86_64_COPY,        5)
+ELF_RELOC(R_X86_64_GLOB_DAT,    6)
+ELF_RELOC(R_X86_64_JUMP_SLOT,   7)
+ELF_RELOC(R_X86_64_RELATIVE,    8)
+ELF_RELOC(R_X86_64_GOTPCREL,    9)
+ELF_RELOC(R_X86_64_32,          10)
+ELF_RELOC(R_X86_64_32S,         11)
+ELF_RELOC(R_X86_64_16,          12)
+ELF_RELOC(R_X86_64_PC16,        13)
+ELF_RELOC(R_X86_64_8,           14)
+ELF_RELOC(R_X86_64_PC8,         15)
+ELF_RELOC(R_X86_64_DTPMOD64,    16)
+ELF_RELOC(R_X86_64_DTPOFF64,    17)
+ELF_RELOC(R_X86_64_TPOFF64,     18)
+ELF_RELOC(R_X86_64_TLSGD,       19)
+ELF_RELOC(R_X86_64_TLSLD,       20)
+ELF_RELOC(R_X86_64_DTPOFF32,    21)
+ELF_RELOC(R_X86_64_GOTTPOFF,    22)
+ELF_RELOC(R_X86_64_TPOFF32,     23)
+ELF_RELOC(R_X86_64_PC64,        24)
+ELF_RELOC(R_X86_64_GOTOFF64,    25)
+ELF_RELOC(R_X86_64_GOTPC32,     26)
+ELF_RELOC(R_X86_64_GOT64,       27)
+ELF_RELOC(R_X86_64_GOTPCREL64,  28)
+ELF_RELOC(R_X86_64_GOTPC64,     29)
+ELF_RELOC(R_X86_64_GOTPLT64,    30)
+ELF_RELOC(R_X86_64_PLTOFF64,    31)
+ELF_RELOC(R_X86_64_SIZE32,      32)
+ELF_RELOC(R_X86_64_SIZE64,      33)
+ELF_RELOC(R_X86_64_GOTPC32_TLSDESC,  34)
+ELF_RELOC(R_X86_64_TLSDESC_CALL,     35)
+ELF_RELOC(R_X86_64_TLSDESC,     36)
+ELF_RELOC(R_X86_64_IRELATIVE,   37)
+ELF_RELOC(R_X86_64_GOTPCRELX,   41)
+ELF_RELOC(R_X86_64_REX_GOTPCRELX,    42)
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/MachO.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/MachO.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/MachO.def
@@ -0,0 +1,119 @@
+//,,,-- llvm/Support/MachO.def - The MachO file definitions -----*- C++ -*-,,,//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//,,,----------------------------------------------------------------------,,,//
+//
+// Definitions for MachO files
+//
+//,,,----------------------------------------------------------------------,,,//
+
+#ifdef HANDLE_LOAD_COMMAND
+
+HANDLE_LOAD_COMMAND(LC_SEGMENT, 0x00000001u, segment_command)
+HANDLE_LOAD_COMMAND(LC_SYMTAB, 0x00000002u, symtab_command)
+// LC_SYMSEG is obsolete and no longer supported.
+HANDLE_LOAD_COMMAND(LC_SYMSEG, 0x00000003u, symseg_command)
+HANDLE_LOAD_COMMAND(LC_THREAD, 0x00000004u, thread_command)
+HANDLE_LOAD_COMMAND(LC_UNIXTHREAD, 0x00000005u, thread_command)
+// LC_LOADFVMLIB is obsolete and no longer supported.
+HANDLE_LOAD_COMMAND(LC_LOADFVMLIB, 0x00000006u, fvmlib_command)
+// LC_IDFVMLIB is obsolete and no longer supported.
+HANDLE_LOAD_COMMAND(LC_IDFVMLIB, 0x00000007u, fvmlib_command)
+// LC_IDENT is obsolete and no longer supported.
+HANDLE_LOAD_COMMAND(LC_IDENT, 0x00000008u, ident_command)
+// LC_FVMFILE is obsolete and no longer supported.
+HANDLE_LOAD_COMMAND(LC_FVMFILE, 0x00000009u, fvmfile_command)
+// LC_PREPAGE is obsolete and no longer supported.
+HANDLE_LOAD_COMMAND(LC_PREPAGE, 0x0000000Au, load_command)
+HANDLE_LOAD_COMMAND(LC_DYSYMTAB, 0x0000000Bu, dysymtab_command)
+HANDLE_LOAD_COMMAND(LC_LOAD_DYLIB, 0x0000000Cu, dylib_command)
+HANDLE_LOAD_COMMAND(LC_ID_DYLIB, 0x0000000Du, dylib_command)
+HANDLE_LOAD_COMMAND(LC_LOAD_DYLINKER, 0x0000000Eu, dylinker_command)
+HANDLE_LOAD_COMMAND(LC_ID_DYLINKER, 0x0000000Fu, dylinker_command)
+// LC_PREBOUND_DYLIB is obsolete and no longer supported.
+HANDLE_LOAD_COMMAND(LC_PREBOUND_DYLIB, 0x00000010u, prebound_dylib_command)
+HANDLE_LOAD_COMMAND(LC_ROUTINES, 0x00000011u, routines_command)
+HANDLE_LOAD_COMMAND(LC_SUB_FRAMEWORK, 0x00000012u, sub_framework_command)
+HANDLE_LOAD_COMMAND(LC_SUB_UMBRELLA, 0x00000013u, sub_umbrella_command)
+HANDLE_LOAD_COMMAND(LC_SUB_CLIENT, 0x00000014u, sub_client_command)
+HANDLE_LOAD_COMMAND(LC_SUB_LIBRARY, 0x00000015u, sub_library_command)
+// LC_TWOLEVEL_HINTS is obsolete and no longer supported.
+HANDLE_LOAD_COMMAND(LC_TWOLEVEL_HINTS, 0x00000016u, twolevel_hints_command)
+// LC_PREBIND_CKSUM is obsolete and no longer supported.
+HANDLE_LOAD_COMMAND(LC_PREBIND_CKSUM, 0x00000017u, prebind_cksum_command)
+// LC_LOAD_WEAK_DYLIB is obsolete and no longer supported.
+HANDLE_LOAD_COMMAND(LC_LOAD_WEAK_DYLIB, 0x80000018u, dylib_command)
+HANDLE_LOAD_COMMAND(LC_SEGMENT_64, 0x00000019u, segment_command_64)
+HANDLE_LOAD_COMMAND(LC_ROUTINES_64, 0x0000001Au, routines_command_64)
+HANDLE_LOAD_COMMAND(LC_UUID, 0x0000001Bu, uuid_command)
+HANDLE_LOAD_COMMAND(LC_RPATH, 0x8000001Cu, rpath_command)
+HANDLE_LOAD_COMMAND(LC_CODE_SIGNATURE, 0x0000001Du, linkedit_data_command)
+HANDLE_LOAD_COMMAND(LC_SEGMENT_SPLIT_INFO, 0x0000001Eu, linkedit_data_command)
+HANDLE_LOAD_COMMAND(LC_REEXPORT_DYLIB, 0x8000001Fu, dylib_command)
+HANDLE_LOAD_COMMAND(LC_LAZY_LOAD_DYLIB, 0x00000020u, dylib_command)
+HANDLE_LOAD_COMMAND(LC_ENCRYPTION_INFO, 0x00000021u, encryption_info_command)
+HANDLE_LOAD_COMMAND(LC_DYLD_INFO, 0x00000022u, dyld_info_command)
+HANDLE_LOAD_COMMAND(LC_DYLD_INFO_ONLY, 0x80000022u, dyld_info_command)
+HANDLE_LOAD_COMMAND(LC_LOAD_UPWARD_DYLIB, 0x80000023u, dylib_command)
+HANDLE_LOAD_COMMAND(LC_VERSION_MIN_MACOSX, 0x00000024u, version_min_command)
+HANDLE_LOAD_COMMAND(LC_VERSION_MIN_IPHONEOS, 0x00000025u, version_min_command)
+HANDLE_LOAD_COMMAND(LC_FUNCTION_STARTS, 0x00000026u, linkedit_data_command)
+HANDLE_LOAD_COMMAND(LC_DYLD_ENVIRONMENT, 0x00000027u, dylinker_command)
+HANDLE_LOAD_COMMAND(LC_MAIN, 0x80000028u, entry_point_command)
+HANDLE_LOAD_COMMAND(LC_DATA_IN_CODE, 0x00000029u, linkedit_data_command)
+HANDLE_LOAD_COMMAND(LC_SOURCE_VERSION, 0x0000002Au, source_version_command)
+HANDLE_LOAD_COMMAND(LC_DYLIB_CODE_SIGN_DRS, 0x0000002Bu, linkedit_data_command)
+HANDLE_LOAD_COMMAND(LC_ENCRYPTION_INFO_64, 0x0000002Cu,
+                    encryption_info_command_64)
+HANDLE_LOAD_COMMAND(LC_LINKER_OPTION, 0x0000002Du, linker_option_command)
+HANDLE_LOAD_COMMAND(LC_LINKER_OPTIMIZATION_HINT, 0x0000002Eu, linkedit_data_command)
+HANDLE_LOAD_COMMAND(LC_VERSION_MIN_TVOS, 0x0000002Fu, version_min_command)
+HANDLE_LOAD_COMMAND(LC_VERSION_MIN_WATCHOS, 0x00000030u, version_min_command)
+HANDLE_LOAD_COMMAND(LC_NOTE, 0x00000031u, note_command)
+HANDLE_LOAD_COMMAND(LC_BUILD_VERSION, 0x00000032u, build_version_command)
+
+#endif
+
+#ifdef LOAD_COMMAND_STRUCT
+
+LOAD_COMMAND_STRUCT(dyld_info_command)
+LOAD_COMMAND_STRUCT(dylib_command)
+LOAD_COMMAND_STRUCT(dylinker_command)
+LOAD_COMMAND_STRUCT(dysymtab_command)
+LOAD_COMMAND_STRUCT(encryption_info_command)
+LOAD_COMMAND_STRUCT(encryption_info_command_64)
+LOAD_COMMAND_STRUCT(entry_point_command)
+LOAD_COMMAND_STRUCT(fvmfile_command)
+LOAD_COMMAND_STRUCT(fvmlib_command)
+LOAD_COMMAND_STRUCT(ident_command)
+LOAD_COMMAND_STRUCT(linkedit_data_command)
+LOAD_COMMAND_STRUCT(linker_option_command)
+LOAD_COMMAND_STRUCT(load_command)
+LOAD_COMMAND_STRUCT(prebind_cksum_command)
+LOAD_COMMAND_STRUCT(prebound_dylib_command)
+LOAD_COMMAND_STRUCT(routines_command)
+LOAD_COMMAND_STRUCT(routines_command_64)
+LOAD_COMMAND_STRUCT(rpath_command)
+LOAD_COMMAND_STRUCT(segment_command)
+LOAD_COMMAND_STRUCT(segment_command_64)
+LOAD_COMMAND_STRUCT(source_version_command)
+LOAD_COMMAND_STRUCT(sub_client_command)
+LOAD_COMMAND_STRUCT(sub_framework_command)
+LOAD_COMMAND_STRUCT(sub_library_command)
+LOAD_COMMAND_STRUCT(sub_umbrella_command)
+LOAD_COMMAND_STRUCT(symseg_command)
+LOAD_COMMAND_STRUCT(symtab_command)
+LOAD_COMMAND_STRUCT(thread_command)
+LOAD_COMMAND_STRUCT(twolevel_hints_command)
+LOAD_COMMAND_STRUCT(uuid_command)
+LOAD_COMMAND_STRUCT(version_min_command)
+LOAD_COMMAND_STRUCT(note_command)
+LOAD_COMMAND_STRUCT(build_version_command)
+
+#endif
+
+#undef HANDLE_LOAD_COMMAND
+#undef LOAD_COMMAND_STRUCT
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/MachO.h b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/MachO.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/MachO.h
@@ -0,0 +1,2006 @@
+//===-- llvm/BinaryFormat/MachO.h - The MachO file format -------*- C++/-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines manifest constants for the MachO object file format.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BINARYFORMAT_MACHO_H
+#define LLVM_BINARYFORMAT_MACHO_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Host.h"
+
+namespace llvm {
+namespace MachO {
+// Enums from <mach-o/loader.h>
+enum : uint32_t {
+  // Constants for the "magic" field in llvm::MachO::mach_header and
+  // llvm::MachO::mach_header_64
+  MH_MAGIC = 0xFEEDFACEu,
+  MH_CIGAM = 0xCEFAEDFEu,
+  MH_MAGIC_64 = 0xFEEDFACFu,
+  MH_CIGAM_64 = 0xCFFAEDFEu,
+  FAT_MAGIC = 0xCAFEBABEu,
+  FAT_CIGAM = 0xBEBAFECAu,
+  FAT_MAGIC_64 = 0xCAFEBABFu,
+  FAT_CIGAM_64 = 0xBFBAFECAu
+};
+
+enum HeaderFileType {
+  // Constants for the "filetype" field in llvm::MachO::mach_header and
+  // llvm::MachO::mach_header_64
+  MH_OBJECT = 0x1u,
+  MH_EXECUTE = 0x2u,
+  MH_FVMLIB = 0x3u,
+  MH_CORE = 0x4u,
+  MH_PRELOAD = 0x5u,
+  MH_DYLIB = 0x6u,
+  MH_DYLINKER = 0x7u,
+  MH_BUNDLE = 0x8u,
+  MH_DYLIB_STUB = 0x9u,
+  MH_DSYM = 0xAu,
+  MH_KEXT_BUNDLE = 0xBu
+};
+
+enum {
+  // Constant bits for the "flags" field in llvm::MachO::mach_header and
+  // llvm::MachO::mach_header_64
+  MH_NOUNDEFS = 0x00000001u,
+  MH_INCRLINK = 0x00000002u,
+  MH_DYLDLINK = 0x00000004u,
+  MH_BINDATLOAD = 0x00000008u,
+  MH_PREBOUND = 0x00000010u,
+  MH_SPLIT_SEGS = 0x00000020u,
+  MH_LAZY_INIT = 0x00000040u,
+  MH_TWOLEVEL = 0x00000080u,
+  MH_FORCE_FLAT = 0x00000100u,
+  MH_NOMULTIDEFS = 0x00000200u,
+  MH_NOFIXPREBINDING = 0x00000400u,
+  MH_PREBINDABLE = 0x00000800u,
+  MH_ALLMODSBOUND = 0x00001000u,
+  MH_SUBSECTIONS_VIA_SYMBOLS = 0x00002000u,
+  MH_CANONICAL = 0x00004000u,
+  MH_WEAK_DEFINES = 0x00008000u,
+  MH_BINDS_TO_WEAK = 0x00010000u,
+  MH_ALLOW_STACK_EXECUTION = 0x00020000u,
+  MH_ROOT_SAFE = 0x00040000u,
+  MH_SETUID_SAFE = 0x00080000u,
+  MH_NO_REEXPORTED_DYLIBS = 0x00100000u,
+  MH_PIE = 0x00200000u,
+  MH_DEAD_STRIPPABLE_DYLIB = 0x00400000u,
+  MH_HAS_TLV_DESCRIPTORS = 0x00800000u,
+  MH_NO_HEAP_EXECUTION = 0x01000000u,
+  MH_APP_EXTENSION_SAFE = 0x02000000u,
+  MH_NLIST_OUTOFSYNC_WITH_DYLDINFO = 0x04000000u
+};
+
+enum : uint32_t {
+  // Flags for the "cmd" field in llvm::MachO::load_command
+  LC_REQ_DYLD = 0x80000000u
+};
+
+#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) LCName = LCValue,
+
+enum LoadCommandType : uint32_t {
+#include "llvm/BinaryFormat/MachO.def"
+};
+
+#undef HANDLE_LOAD_COMMAND
+
+enum : uint32_t {
+  // Constant bits for the "flags" field in llvm::MachO::segment_command
+  SG_HIGHVM = 0x1u,
+  SG_FVMLIB = 0x2u,
+  SG_NORELOC = 0x4u,
+  SG_PROTECTED_VERSION_1 = 0x8u,
+
+  // Constant masks for the "flags" field in llvm::MachO::section and
+  // llvm::MachO::section_64
+  SECTION_TYPE = 0x000000ffu,           // SECTION_TYPE
+  SECTION_ATTRIBUTES = 0xffffff00u,     // SECTION_ATTRIBUTES
+  SECTION_ATTRIBUTES_USR = 0xff000000u, // SECTION_ATTRIBUTES_USR
+  SECTION_ATTRIBUTES_SYS = 0x00ffff00u  // SECTION_ATTRIBUTES_SYS
+};
+
+/// These are the section type and attributes fields.  A MachO section can
+/// have only one Type, but can have any of the attributes specified.
+enum SectionType : uint32_t {
+  // Constant masks for the "flags[7:0]" field in llvm::MachO::section and
+  // llvm::MachO::section_64 (mask "flags" with SECTION_TYPE)
+
+  /// S_REGULAR - Regular section.
+  S_REGULAR = 0x00u,
+  /// S_ZEROFILL - Zero fill on demand section.
+  S_ZEROFILL = 0x01u,
+  /// S_CSTRING_LITERALS - Section with literal C strings.
+  S_CSTRING_LITERALS = 0x02u,
+  /// S_4BYTE_LITERALS - Section with 4 byte literals.
+  S_4BYTE_LITERALS = 0x03u,
+  /// S_8BYTE_LITERALS - Section with 8 byte literals.
+  S_8BYTE_LITERALS = 0x04u,
+  /// S_LITERAL_POINTERS - Section with pointers to literals.
+  S_LITERAL_POINTERS = 0x05u,
+  /// S_NON_LAZY_SYMBOL_POINTERS - Section with non-lazy symbol pointers.
+  S_NON_LAZY_SYMBOL_POINTERS = 0x06u,
+  /// S_LAZY_SYMBOL_POINTERS - Section with lazy symbol pointers.
+  S_LAZY_SYMBOL_POINTERS = 0x07u,
+  /// S_SYMBOL_STUBS - Section with symbol stubs, byte size of stub in
+  /// the Reserved2 field.
+  S_SYMBOL_STUBS = 0x08u,
+  /// S_MOD_INIT_FUNC_POINTERS - Section with only function pointers for
+  /// initialization.
+  S_MOD_INIT_FUNC_POINTERS = 0x09u,
+  /// S_MOD_TERM_FUNC_POINTERS - Section with only function pointers for
+  /// termination.
+  S_MOD_TERM_FUNC_POINTERS = 0x0au,
+  /// S_COALESCED - Section contains symbols that are to be coalesced.
+  S_COALESCED = 0x0bu,
+  /// S_GB_ZEROFILL - Zero fill on demand section (that can be larger than 4
+  /// gigabytes).
+  S_GB_ZEROFILL = 0x0cu,
+  /// S_INTERPOSING - Section with only pairs of function pointers for
+  /// interposing.
+  S_INTERPOSING = 0x0du,
+  /// S_16BYTE_LITERALS - Section with only 16 byte literals.
+  S_16BYTE_LITERALS = 0x0eu,
+  /// S_DTRACE_DOF - Section contains DTrace Object Format.
+  S_DTRACE_DOF = 0x0fu,
+  /// S_LAZY_DYLIB_SYMBOL_POINTERS - Section with lazy symbol pointers to
+  /// lazy loaded dylibs.
+  S_LAZY_DYLIB_SYMBOL_POINTERS = 0x10u,
+  /// S_THREAD_LOCAL_REGULAR - Thread local data section.
+  S_THREAD_LOCAL_REGULAR = 0x11u,
+  /// S_THREAD_LOCAL_ZEROFILL - Thread local zerofill section.
+  S_THREAD_LOCAL_ZEROFILL = 0x12u,
+  /// S_THREAD_LOCAL_VARIABLES - Section with thread local variable
+  /// structure data.
+  S_THREAD_LOCAL_VARIABLES = 0x13u,
+  /// S_THREAD_LOCAL_VARIABLE_POINTERS - Section with pointers to thread
+  /// local structures.
+  S_THREAD_LOCAL_VARIABLE_POINTERS = 0x14u,
+  /// S_THREAD_LOCAL_INIT_FUNCTION_POINTERS - Section with thread local
+  /// variable initialization pointers to functions.
+  S_THREAD_LOCAL_INIT_FUNCTION_POINTERS = 0x15u,
+
+  LAST_KNOWN_SECTION_TYPE = S_THREAD_LOCAL_INIT_FUNCTION_POINTERS
+};
+
+enum : uint32_t {
+  // Constant masks for the "flags[31:24]" field in llvm::MachO::section and
+  // llvm::MachO::section_64 (mask "flags" with SECTION_ATTRIBUTES_USR)
+
+  /// S_ATTR_PURE_INSTRUCTIONS - Section contains only true machine
+  /// instructions.
+  S_ATTR_PURE_INSTRUCTIONS = 0x80000000u,
+  /// S_ATTR_NO_TOC - Section contains coalesced symbols that are not to be
+  /// in a ranlib table of contents.
+  S_ATTR_NO_TOC = 0x40000000u,
+  /// S_ATTR_STRIP_STATIC_SYMS - Ok to strip static symbols in this section
+  /// in files with the MY_DYLDLINK flag.
+  S_ATTR_STRIP_STATIC_SYMS = 0x20000000u,
+  /// S_ATTR_NO_DEAD_STRIP - No dead stripping.
+  S_ATTR_NO_DEAD_STRIP = 0x10000000u,
+  /// S_ATTR_LIVE_SUPPORT - Blocks are live if they reference live blocks.
+  S_ATTR_LIVE_SUPPORT = 0x08000000u,
+  /// S_ATTR_SELF_MODIFYING_CODE - Used with i386 code stubs written on by
+  /// dyld.
+  S_ATTR_SELF_MODIFYING_CODE = 0x04000000u,
+  /// S_ATTR_DEBUG - A debug section.
+  S_ATTR_DEBUG = 0x02000000u,
+
+  // Constant masks for the "flags[23:8]" field in llvm::MachO::section and
+  // llvm::MachO::section_64 (mask "flags" with SECTION_ATTRIBUTES_SYS)
+
+  /// S_ATTR_SOME_INSTRUCTIONS - Section contains some machine instructions.
+  S_ATTR_SOME_INSTRUCTIONS = 0x00000400u,
+  /// S_ATTR_EXT_RELOC - Section has external relocation entries.
+  S_ATTR_EXT_RELOC = 0x00000200u,
+  /// S_ATTR_LOC_RELOC - Section has local relocation entries.
+  S_ATTR_LOC_RELOC = 0x00000100u,
+
+  // Constant masks for the value of an indirect symbol in an indirect
+  // symbol table
+  INDIRECT_SYMBOL_LOCAL = 0x80000000u,
+  INDIRECT_SYMBOL_ABS = 0x40000000u
+};
+
+enum DataRegionType {
+  // Constants for the "kind" field in a data_in_code_entry structure
+  DICE_KIND_DATA = 1u,
+  DICE_KIND_JUMP_TABLE8 = 2u,
+  DICE_KIND_JUMP_TABLE16 = 3u,
+  DICE_KIND_JUMP_TABLE32 = 4u,
+  DICE_KIND_ABS_JUMP_TABLE32 = 5u
+};
+
+enum RebaseType {
+  REBASE_TYPE_POINTER = 1u,
+  REBASE_TYPE_TEXT_ABSOLUTE32 = 2u,
+  REBASE_TYPE_TEXT_PCREL32 = 3u
+};
+
+enum { REBASE_OPCODE_MASK = 0xF0u, REBASE_IMMEDIATE_MASK = 0x0Fu };
+
+enum RebaseOpcode {
+  REBASE_OPCODE_DONE = 0x00u,
+  REBASE_OPCODE_SET_TYPE_IMM = 0x10u,
+  REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x20u,
+  REBASE_OPCODE_ADD_ADDR_ULEB = 0x30u,
+  REBASE_OPCODE_ADD_ADDR_IMM_SCALED = 0x40u,
+  REBASE_OPCODE_DO_REBASE_IMM_TIMES = 0x50u,
+  REBASE_OPCODE_DO_REBASE_ULEB_TIMES = 0x60u,
+  REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB = 0x70u,
+  REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB = 0x80u
+};
+
+enum BindType {
+  BIND_TYPE_POINTER = 1u,
+  BIND_TYPE_TEXT_ABSOLUTE32 = 2u,
+  BIND_TYPE_TEXT_PCREL32 = 3u
+};
+
+enum BindSpecialDylib {
+  BIND_SPECIAL_DYLIB_SELF = 0,
+  BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE = -1,
+  BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2
+};
+
+enum {
+  BIND_SYMBOL_FLAGS_WEAK_IMPORT = 0x1u,
+  BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION = 0x8u,
+
+  BIND_OPCODE_MASK = 0xF0u,
+  BIND_IMMEDIATE_MASK = 0x0Fu
+};
+
+enum BindOpcode {
+  BIND_OPCODE_DONE = 0x00u,
+  BIND_OPCODE_SET_DYLIB_ORDINAL_IMM = 0x10u,
+  BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB = 0x20u,
+  BIND_OPCODE_SET_DYLIB_SPECIAL_IMM = 0x30u,
+  BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM = 0x40u,
+  BIND_OPCODE_SET_TYPE_IMM = 0x50u,
+  BIND_OPCODE_SET_ADDEND_SLEB = 0x60u,
+  BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x70u,
+  BIND_OPCODE_ADD_ADDR_ULEB = 0x80u,
+  BIND_OPCODE_DO_BIND = 0x90u,
+  BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB = 0xA0u,
+  BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED = 0xB0u,
+  BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB = 0xC0u
+};
+
+enum {
+  EXPORT_SYMBOL_FLAGS_KIND_MASK = 0x03u,
+  EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION = 0x04u,
+  EXPORT_SYMBOL_FLAGS_REEXPORT = 0x08u,
+  EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER = 0x10u
+};
+
+enum ExportSymbolKind {
+  EXPORT_SYMBOL_FLAGS_KIND_REGULAR = 0x00u,
+  EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL = 0x01u,
+  EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE = 0x02u
+};
+
+enum {
+  // Constant masks for the "n_type" field in llvm::MachO::nlist and
+  // llvm::MachO::nlist_64
+  N_STAB = 0xe0,
+  N_PEXT = 0x10,
+  N_TYPE = 0x0e,
+  N_EXT = 0x01
+};
+
+enum NListType : uint8_t {
+  // Constants for the "n_type & N_TYPE" llvm::MachO::nlist and
+  // llvm::MachO::nlist_64
+  N_UNDF = 0x0u,
+  N_ABS = 0x2u,
+  N_SECT = 0xeu,
+  N_PBUD = 0xcu,
+  N_INDR = 0xau
+};
+
+enum SectionOrdinal {
+  // Constants for the "n_sect" field in llvm::MachO::nlist and
+  // llvm::MachO::nlist_64
+  NO_SECT = 0u,
+  MAX_SECT = 0xffu
+};
+
+enum {
+  // Constant masks for the "n_desc" field in llvm::MachO::nlist and
+  // llvm::MachO::nlist_64
+  // The low 3 bits are the for the REFERENCE_TYPE.
+  REFERENCE_TYPE = 0x7,
+  REFERENCE_FLAG_UNDEFINED_NON_LAZY = 0,
+  REFERENCE_FLAG_UNDEFINED_LAZY = 1,
+  REFERENCE_FLAG_DEFINED = 2,
+  REFERENCE_FLAG_PRIVATE_DEFINED = 3,
+  REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY = 4,
+  REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY = 5,
+  // Flag bits (some overlap with the library ordinal bits).
+  N_ARM_THUMB_DEF = 0x0008u,
+  REFERENCED_DYNAMICALLY = 0x0010u,
+  N_NO_DEAD_STRIP = 0x0020u,
+  N_WEAK_REF = 0x0040u,
+  N_WEAK_DEF = 0x0080u,
+  N_SYMBOL_RESOLVER = 0x0100u,
+  N_ALT_ENTRY = 0x0200u,
+  N_COLD_FUNC = 0x0400u,
+  // For undefined symbols coming from libraries, see GET_LIBRARY_ORDINAL()
+  // as these are in the top 8 bits.
+  SELF_LIBRARY_ORDINAL = 0x0,
+  MAX_LIBRARY_ORDINAL = 0xfd,
+  DYNAMIC_LOOKUP_ORDINAL = 0xfe,
+  EXECUTABLE_ORDINAL = 0xff
+};
+
+enum StabType {
+  // Constant values for the "n_type" field in llvm::MachO::nlist and
+  // llvm::MachO::nlist_64 when "(n_type & N_STAB) != 0"
+  N_GSYM = 0x20u,
+  N_FNAME = 0x22u,
+  N_FUN = 0x24u,
+  N_STSYM = 0x26u,
+  N_LCSYM = 0x28u,
+  N_BNSYM = 0x2Eu,
+  N_PC = 0x30u,
+  N_AST = 0x32u,
+  N_OPT = 0x3Cu,
+  N_RSYM = 0x40u,
+  N_SLINE = 0x44u,
+  N_ENSYM = 0x4Eu,
+  N_SSYM = 0x60u,
+  N_SO = 0x64u,
+  N_OSO = 0x66u,
+  N_LSYM = 0x80u,
+  N_BINCL = 0x82u,
+  N_SOL = 0x84u,
+  N_PARAMS = 0x86u,
+  N_VERSION = 0x88u,
+  N_OLEVEL = 0x8Au,
+  N_PSYM = 0xA0u,
+  N_EINCL = 0xA2u,
+  N_ENTRY = 0xA4u,
+  N_LBRAC = 0xC0u,
+  N_EXCL = 0xC2u,
+  N_RBRAC = 0xE0u,
+  N_BCOMM = 0xE2u,
+  N_ECOMM = 0xE4u,
+  N_ECOML = 0xE8u,
+  N_LENG = 0xFEu
+};
+
+enum : uint32_t {
+  // Constant values for the r_symbolnum field in an
+  // llvm::MachO::relocation_info structure when r_extern is 0.
+  R_ABS = 0,
+
+  // Constant bits for the r_address field in an
+  // llvm::MachO::relocation_info structure.
+  R_SCATTERED = 0x80000000
+};
+
+enum RelocationInfoType {
+  // Constant values for the r_type field in an
+  // llvm::MachO::relocation_info or llvm::MachO::scattered_relocation_info
+  // structure.
+  GENERIC_RELOC_VANILLA = 0,
+  GENERIC_RELOC_PAIR = 1,
+  GENERIC_RELOC_SECTDIFF = 2,
+  GENERIC_RELOC_PB_LA_PTR = 3,
+  GENERIC_RELOC_LOCAL_SECTDIFF = 4,
+  GENERIC_RELOC_TLV = 5,
+
+  // Constant values for the r_type field in a PowerPC architecture
+  // llvm::MachO::relocation_info or llvm::MachO::scattered_relocation_info
+  // structure.
+  PPC_RELOC_VANILLA = GENERIC_RELOC_VANILLA,
+  PPC_RELOC_PAIR = GENERIC_RELOC_PAIR,
+  PPC_RELOC_BR14 = 2,
+  PPC_RELOC_BR24 = 3,
+  PPC_RELOC_HI16 = 4,
+  PPC_RELOC_LO16 = 5,
+  PPC_RELOC_HA16 = 6,
+  PPC_RELOC_LO14 = 7,
+  PPC_RELOC_SECTDIFF = 8,
+  PPC_RELOC_PB_LA_PTR = 9,
+  PPC_RELOC_HI16_SECTDIFF = 10,
+  PPC_RELOC_LO16_SECTDIFF = 11,
+  PPC_RELOC_HA16_SECTDIFF = 12,
+  PPC_RELOC_JBSR = 13,
+  PPC_RELOC_LO14_SECTDIFF = 14,
+  PPC_RELOC_LOCAL_SECTDIFF = 15,
+
+  // Constant values for the r_type field in an ARM architecture
+  // llvm::MachO::relocation_info or llvm::MachO::scattered_relocation_info
+  // structure.
+  ARM_RELOC_VANILLA = GENERIC_RELOC_VANILLA,
+  ARM_RELOC_PAIR = GENERIC_RELOC_PAIR,
+  ARM_RELOC_SECTDIFF = GENERIC_RELOC_SECTDIFF,
+  ARM_RELOC_LOCAL_SECTDIFF = 3,
+  ARM_RELOC_PB_LA_PTR = 4,
+  ARM_RELOC_BR24 = 5,
+  ARM_THUMB_RELOC_BR22 = 6,
+  ARM_THUMB_32BIT_BRANCH = 7, // obsolete
+  ARM_RELOC_HALF = 8,
+  ARM_RELOC_HALF_SECTDIFF = 9,
+
+  // Constant values for the r_type field in an ARM64 architecture
+  // llvm::MachO::relocation_info or llvm::MachO::scattered_relocation_info
+  // structure.
+
+  // For pointers.
+  ARM64_RELOC_UNSIGNED = 0,
+  // Must be followed by an ARM64_RELOC_UNSIGNED
+  ARM64_RELOC_SUBTRACTOR = 1,
+  // A B/BL instruction with 26-bit displacement.
+  ARM64_RELOC_BRANCH26 = 2,
+  // PC-rel distance to page of target.
+  ARM64_RELOC_PAGE21 = 3,
+  // Offset within page, scaled by r_length.
+  ARM64_RELOC_PAGEOFF12 = 4,
+  // PC-rel distance to page of GOT slot.
+  ARM64_RELOC_GOT_LOAD_PAGE21 = 5,
+  // Offset within page of GOT slot, scaled by r_length.
+  ARM64_RELOC_GOT_LOAD_PAGEOFF12 = 6,
+  // For pointers to GOT slots.
+  ARM64_RELOC_POINTER_TO_GOT = 7,
+  // PC-rel distance to page of TLVP slot.
+  ARM64_RELOC_TLVP_LOAD_PAGE21 = 8,
+  // Offset within page of TLVP slot, scaled by r_length.
+  ARM64_RELOC_TLVP_LOAD_PAGEOFF12 = 9,
+  // Must be followed by ARM64_RELOC_PAGE21 or ARM64_RELOC_PAGEOFF12.
+  ARM64_RELOC_ADDEND = 10,
+
+  // Constant values for the r_type field in an x86_64 architecture
+  // llvm::MachO::relocation_info or llvm::MachO::scattered_relocation_info
+  // structure
+  X86_64_RELOC_UNSIGNED = 0,
+  X86_64_RELOC_SIGNED = 1,
+  X86_64_RELOC_BRANCH = 2,
+  X86_64_RELOC_GOT_LOAD = 3,
+  X86_64_RELOC_GOT = 4,
+  X86_64_RELOC_SUBTRACTOR = 5,
+  X86_64_RELOC_SIGNED_1 = 6,
+  X86_64_RELOC_SIGNED_2 = 7,
+  X86_64_RELOC_SIGNED_4 = 8,
+  X86_64_RELOC_TLV = 9
+};
+
+// Values for segment_command.initprot.
+// From <mach/vm_prot.h>
+enum { VM_PROT_READ = 0x1, VM_PROT_WRITE = 0x2, VM_PROT_EXECUTE = 0x4 };
+
+// Values for platform field in build_version_command.
+enum PlatformType {
+  PLATFORM_MACOS = 1,
+  PLATFORM_IOS = 2,
+  PLATFORM_TVOS = 3,
+  PLATFORM_WATCHOS = 4,
+  PLATFORM_BRIDGEOS = 5,
+  PLATFORM_MACCATALYST = 6,
+  PLATFORM_IOSSIMULATOR = 7,
+  PLATFORM_TVOSSIMULATOR = 8,
+  PLATFORM_WATCHOSSIMULATOR = 9
+};
+
+// Values for tools enum in build_tool_version.
+enum { TOOL_CLANG = 1, TOOL_SWIFT = 2, TOOL_LD = 3 };
+
+// Structs from <mach-o/loader.h>
+
+struct mach_header {
+  uint32_t magic;
+  uint32_t cputype;
+  uint32_t cpusubtype;
+  uint32_t filetype;
+  uint32_t ncmds;
+  uint32_t sizeofcmds;
+  uint32_t flags;
+};
+
+struct mach_header_64 {
+  uint32_t magic;
+  uint32_t cputype;
+  uint32_t cpusubtype;
+  uint32_t filetype;
+  uint32_t ncmds;
+  uint32_t sizeofcmds;
+  uint32_t flags;
+  uint32_t reserved;
+};
+
+struct load_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+};
+
+struct segment_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  char segname[16];
+  uint32_t vmaddr;
+  uint32_t vmsize;
+  uint32_t fileoff;
+  uint32_t filesize;
+  uint32_t maxprot;
+  uint32_t initprot;
+  uint32_t nsects;
+  uint32_t flags;
+};
+
+struct segment_command_64 {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  char segname[16];
+  uint64_t vmaddr;
+  uint64_t vmsize;
+  uint64_t fileoff;
+  uint64_t filesize;
+  uint32_t maxprot;
+  uint32_t initprot;
+  uint32_t nsects;
+  uint32_t flags;
+};
+
+struct section {
+  char sectname[16];
+  char segname[16];
+  uint32_t addr;
+  uint32_t size;
+  uint32_t offset;
+  uint32_t align;
+  uint32_t reloff;
+  uint32_t nreloc;
+  uint32_t flags;
+  uint32_t reserved1;
+  uint32_t reserved2;
+};
+
+struct section_64 {
+  char sectname[16];
+  char segname[16];
+  uint64_t addr;
+  uint64_t size;
+  uint32_t offset;
+  uint32_t align;
+  uint32_t reloff;
+  uint32_t nreloc;
+  uint32_t flags;
+  uint32_t reserved1;
+  uint32_t reserved2;
+  uint32_t reserved3;
+};
+
+inline bool isVirtualSection(uint8_t type) {
+  return (type == MachO::S_ZEROFILL || type == MachO::S_GB_ZEROFILL ||
+          type == MachO::S_THREAD_LOCAL_ZEROFILL);
+}
+
+struct fvmlib {
+  uint32_t name;
+  uint32_t minor_version;
+  uint32_t header_addr;
+};
+
+// The fvmlib_command is obsolete and no longer supported.
+struct fvmlib_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  struct fvmlib fvmlib;
+};
+
+struct dylib {
+  uint32_t name;
+  uint32_t timestamp;
+  uint32_t current_version;
+  uint32_t compatibility_version;
+};
+
+struct dylib_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  struct dylib dylib;
+};
+
+struct sub_framework_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t umbrella;
+};
+
+struct sub_client_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t client;
+};
+
+struct sub_umbrella_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t sub_umbrella;
+};
+
+struct sub_library_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t sub_library;
+};
+
+// The prebound_dylib_command is obsolete and no longer supported.
+struct prebound_dylib_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t name;
+  uint32_t nmodules;
+  uint32_t linked_modules;
+};
+
+struct dylinker_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t name;
+};
+
+struct thread_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+};
+
+struct routines_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t init_address;
+  uint32_t init_module;
+  uint32_t reserved1;
+  uint32_t reserved2;
+  uint32_t reserved3;
+  uint32_t reserved4;
+  uint32_t reserved5;
+  uint32_t reserved6;
+};
+
+struct routines_command_64 {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint64_t init_address;
+  uint64_t init_module;
+  uint64_t reserved1;
+  uint64_t reserved2;
+  uint64_t reserved3;
+  uint64_t reserved4;
+  uint64_t reserved5;
+  uint64_t reserved6;
+};
+
+struct symtab_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t symoff;
+  uint32_t nsyms;
+  uint32_t stroff;
+  uint32_t strsize;
+};
+
+struct dysymtab_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t ilocalsym;
+  uint32_t nlocalsym;
+  uint32_t iextdefsym;
+  uint32_t nextdefsym;
+  uint32_t iundefsym;
+  uint32_t nundefsym;
+  uint32_t tocoff;
+  uint32_t ntoc;
+  uint32_t modtaboff;
+  uint32_t nmodtab;
+  uint32_t extrefsymoff;
+  uint32_t nextrefsyms;
+  uint32_t indirectsymoff;
+  uint32_t nindirectsyms;
+  uint32_t extreloff;
+  uint32_t nextrel;
+  uint32_t locreloff;
+  uint32_t nlocrel;
+};
+
+struct dylib_table_of_contents {
+  uint32_t symbol_index;
+  uint32_t module_index;
+};
+
+struct dylib_module {
+  uint32_t module_name;
+  uint32_t iextdefsym;
+  uint32_t nextdefsym;
+  uint32_t irefsym;
+  uint32_t nrefsym;
+  uint32_t ilocalsym;
+  uint32_t nlocalsym;
+  uint32_t iextrel;
+  uint32_t nextrel;
+  uint32_t iinit_iterm;
+  uint32_t ninit_nterm;
+  uint32_t objc_module_info_addr;
+  uint32_t objc_module_info_size;
+};
+
+struct dylib_module_64 {
+  uint32_t module_name;
+  uint32_t iextdefsym;
+  uint32_t nextdefsym;
+  uint32_t irefsym;
+  uint32_t nrefsym;
+  uint32_t ilocalsym;
+  uint32_t nlocalsym;
+  uint32_t iextrel;
+  uint32_t nextrel;
+  uint32_t iinit_iterm;
+  uint32_t ninit_nterm;
+  uint32_t objc_module_info_size;
+  uint64_t objc_module_info_addr;
+};
+
+struct dylib_reference {
+  uint32_t isym : 24, flags : 8;
+};
+
+// The twolevel_hints_command is obsolete and no longer supported.
+struct twolevel_hints_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t offset;
+  uint32_t nhints;
+};
+
+// The twolevel_hints_command is obsolete and no longer supported.
+struct twolevel_hint {
+  uint32_t isub_image : 8, itoc : 24;
+};
+
+// The prebind_cksum_command is obsolete and no longer supported.
+struct prebind_cksum_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t cksum;
+};
+
+struct uuid_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint8_t uuid[16];
+};
+
+struct rpath_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t path;
+};
+
+struct linkedit_data_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t dataoff;
+  uint32_t datasize;
+};
+
+struct data_in_code_entry {
+  uint32_t offset;
+  uint16_t length;
+  uint16_t kind;
+};
+
+struct source_version_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint64_t version;
+};
+
+struct encryption_info_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t cryptoff;
+  uint32_t cryptsize;
+  uint32_t cryptid;
+};
+
+struct encryption_info_command_64 {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t cryptoff;
+  uint32_t cryptsize;
+  uint32_t cryptid;
+  uint32_t pad;
+};
+
+struct version_min_command {
+  uint32_t cmd;     // LC_VERSION_MIN_MACOSX or
+                    // LC_VERSION_MIN_IPHONEOS
+  uint32_t cmdsize; // sizeof(struct version_min_command)
+  uint32_t version; // X.Y.Z is encoded in nibbles xxxx.yy.zz
+  uint32_t sdk;     // X.Y.Z is encoded in nibbles xxxx.yy.zz
+};
+
+struct note_command {
+  uint32_t cmd;        // LC_NOTE
+  uint32_t cmdsize;    // sizeof(struct note_command)
+  char data_owner[16]; // owner name for this LC_NOTE
+  uint64_t offset;     // file offset of this data
+  uint64_t size;       // length of data region
+};
+
+struct build_tool_version {
+  uint32_t tool;    // enum for the tool
+  uint32_t version; // version of the tool
+};
+
+struct build_version_command {
+  uint32_t cmd;      // LC_BUILD_VERSION
+  uint32_t cmdsize;  // sizeof(struct build_version_command) +
+                     // ntools * sizeof(struct build_tool_version)
+  uint32_t platform; // platform
+  uint32_t minos;    // X.Y.Z is encoded in nibbles xxxx.yy.zz
+  uint32_t sdk;      // X.Y.Z is encoded in nibbles xxxx.yy.zz
+  uint32_t ntools;   // number of tool entries following this
+};
+
+struct dyld_info_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t rebase_off;
+  uint32_t rebase_size;
+  uint32_t bind_off;
+  uint32_t bind_size;
+  uint32_t weak_bind_off;
+  uint32_t weak_bind_size;
+  uint32_t lazy_bind_off;
+  uint32_t lazy_bind_size;
+  uint32_t export_off;
+  uint32_t export_size;
+};
+
+struct linker_option_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t count;
+};
+
+// The symseg_command is obsolete and no longer supported.
+struct symseg_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t offset;
+  uint32_t size;
+};
+
+// The ident_command is obsolete and no longer supported.
+struct ident_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+};
+
+// The fvmfile_command is obsolete and no longer supported.
+struct fvmfile_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint32_t name;
+  uint32_t header_addr;
+};
+
+struct tlv_descriptor_32 {
+  uint32_t thunk;
+  uint32_t key;
+  uint32_t offset;
+};
+
+struct tlv_descriptor_64 {
+  uint64_t thunk;
+  uint64_t key;
+  uint64_t offset;
+};
+
+struct tlv_descriptor {
+  uintptr_t thunk;
+  uintptr_t key;
+  uintptr_t offset;
+};
+
+struct entry_point_command {
+  uint32_t cmd;
+  uint32_t cmdsize;
+  uint64_t entryoff;
+  uint64_t stacksize;
+};
+
+// Structs from <mach-o/fat.h>
+struct fat_header {
+  uint32_t magic;
+  uint32_t nfat_arch;
+};
+
+struct fat_arch {
+  uint32_t cputype;
+  uint32_t cpusubtype;
+  uint32_t offset;
+  uint32_t size;
+  uint32_t align;
+};
+
+struct fat_arch_64 {
+  uint32_t cputype;
+  uint32_t cpusubtype;
+  uint64_t offset;
+  uint64_t size;
+  uint32_t align;
+  uint32_t reserved;
+};
+
+// Structs from <mach-o/reloc.h>
+struct relocation_info {
+  int32_t r_address;
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && (BYTE_ORDER == BIG_ENDIAN)
+  uint32_t r_type : 4,  r_extern : 1, r_length : 2, r_pcrel : 1,
+      r_symbolnum : 24;
+#else
+  uint32_t r_symbolnum : 24, r_pcrel : 1, r_length : 2, r_extern : 1,
+      r_type : 4;
+#endif
+};
+
+struct scattered_relocation_info {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && (BYTE_ORDER == BIG_ENDIAN)
+  uint32_t r_scattered : 1, r_pcrel : 1, r_length : 2, r_type : 4,
+      r_address : 24;
+#else
+  uint32_t r_address : 24, r_type : 4, r_length : 2, r_pcrel : 1,
+      r_scattered : 1;
+#endif
+  int32_t r_value;
+};
+
+// Structs NOT from <mach-o/reloc.h>, but that make LLVM's life easier
+struct any_relocation_info {
+  uint32_t r_word0, r_word1;
+};
+
+// Structs from <mach-o/nlist.h>
+struct nlist_base {
+  uint32_t n_strx;
+  uint8_t n_type;
+  uint8_t n_sect;
+  uint16_t n_desc;
+};
+
+struct nlist {
+  uint32_t n_strx;
+  uint8_t n_type;
+  uint8_t n_sect;
+  int16_t n_desc;
+  uint32_t n_value;
+};
+
+struct nlist_64 {
+  uint32_t n_strx;
+  uint8_t n_type;
+  uint8_t n_sect;
+  uint16_t n_desc;
+  uint64_t n_value;
+};
+
+// Byte order swapping functions for MachO structs
+
+inline void swapStruct(fat_header &mh) {
+  sys::swapByteOrder(mh.magic);
+  sys::swapByteOrder(mh.nfat_arch);
+}
+
+inline void swapStruct(fat_arch &mh) {
+  sys::swapByteOrder(mh.cputype);
+  sys::swapByteOrder(mh.cpusubtype);
+  sys::swapByteOrder(mh.offset);
+  sys::swapByteOrder(mh.size);
+  sys::swapByteOrder(mh.align);
+}
+
+inline void swapStruct(fat_arch_64 &mh) {
+  sys::swapByteOrder(mh.cputype);
+  sys::swapByteOrder(mh.cpusubtype);
+  sys::swapByteOrder(mh.offset);
+  sys::swapByteOrder(mh.size);
+  sys::swapByteOrder(mh.align);
+  sys::swapByteOrder(mh.reserved);
+}
+
+inline void swapStruct(mach_header &mh) {
+  sys::swapByteOrder(mh.magic);
+  sys::swapByteOrder(mh.cputype);
+  sys::swapByteOrder(mh.cpusubtype);
+  sys::swapByteOrder(mh.filetype);
+  sys::swapByteOrder(mh.ncmds);
+  sys::swapByteOrder(mh.sizeofcmds);
+  sys::swapByteOrder(mh.flags);
+}
+
+inline void swapStruct(mach_header_64 &H) {
+  sys::swapByteOrder(H.magic);
+  sys::swapByteOrder(H.cputype);
+  sys::swapByteOrder(H.cpusubtype);
+  sys::swapByteOrder(H.filetype);
+  sys::swapByteOrder(H.ncmds);
+  sys::swapByteOrder(H.sizeofcmds);
+  sys::swapByteOrder(H.flags);
+  sys::swapByteOrder(H.reserved);
+}
+
+inline void swapStruct(load_command &lc) {
+  sys::swapByteOrder(lc.cmd);
+  sys::swapByteOrder(lc.cmdsize);
+}
+
+inline void swapStruct(symtab_command &lc) {
+  sys::swapByteOrder(lc.cmd);
+  sys::swapByteOrder(lc.cmdsize);
+  sys::swapByteOrder(lc.symoff);
+  sys::swapByteOrder(lc.nsyms);
+  sys::swapByteOrder(lc.stroff);
+  sys::swapByteOrder(lc.strsize);
+}
+
+inline void swapStruct(segment_command_64 &seg) {
+  sys::swapByteOrder(seg.cmd);
+  sys::swapByteOrder(seg.cmdsize);
+  sys::swapByteOrder(seg.vmaddr);
+  sys::swapByteOrder(seg.vmsize);
+  sys::swapByteOrder(seg.fileoff);
+  sys::swapByteOrder(seg.filesize);
+  sys::swapByteOrder(seg.maxprot);
+  sys::swapByteOrder(seg.initprot);
+  sys::swapByteOrder(seg.nsects);
+  sys::swapByteOrder(seg.flags);
+}
+
+inline void swapStruct(segment_command &seg) {
+  sys::swapByteOrder(seg.cmd);
+  sys::swapByteOrder(seg.cmdsize);
+  sys::swapByteOrder(seg.vmaddr);
+  sys::swapByteOrder(seg.vmsize);
+  sys::swapByteOrder(seg.fileoff);
+  sys::swapByteOrder(seg.filesize);
+  sys::swapByteOrder(seg.maxprot);
+  sys::swapByteOrder(seg.initprot);
+  sys::swapByteOrder(seg.nsects);
+  sys::swapByteOrder(seg.flags);
+}
+
+inline void swapStruct(section_64 &sect) {
+  sys::swapByteOrder(sect.addr);
+  sys::swapByteOrder(sect.size);
+  sys::swapByteOrder(sect.offset);
+  sys::swapByteOrder(sect.align);
+  sys::swapByteOrder(sect.reloff);
+  sys::swapByteOrder(sect.nreloc);
+  sys::swapByteOrder(sect.flags);
+  sys::swapByteOrder(sect.reserved1);
+  sys::swapByteOrder(sect.reserved2);
+}
+
+inline void swapStruct(section &sect) {
+  sys::swapByteOrder(sect.addr);
+  sys::swapByteOrder(sect.size);
+  sys::swapByteOrder(sect.offset);
+  sys::swapByteOrder(sect.align);
+  sys::swapByteOrder(sect.reloff);
+  sys::swapByteOrder(sect.nreloc);
+  sys::swapByteOrder(sect.flags);
+  sys::swapByteOrder(sect.reserved1);
+  sys::swapByteOrder(sect.reserved2);
+}
+
+inline void swapStruct(dyld_info_command &info) {
+  sys::swapByteOrder(info.cmd);
+  sys::swapByteOrder(info.cmdsize);
+  sys::swapByteOrder(info.rebase_off);
+  sys::swapByteOrder(info.rebase_size);
+  sys::swapByteOrder(info.bind_off);
+  sys::swapByteOrder(info.bind_size);
+  sys::swapByteOrder(info.weak_bind_off);
+  sys::swapByteOrder(info.weak_bind_size);
+  sys::swapByteOrder(info.lazy_bind_off);
+  sys::swapByteOrder(info.lazy_bind_size);
+  sys::swapByteOrder(info.export_off);
+  sys::swapByteOrder(info.export_size);
+}
+
+inline void swapStruct(dylib_command &d) {
+  sys::swapByteOrder(d.cmd);
+  sys::swapByteOrder(d.cmdsize);
+  sys::swapByteOrder(d.dylib.name);
+  sys::swapByteOrder(d.dylib.timestamp);
+  sys::swapByteOrder(d.dylib.current_version);
+  sys::swapByteOrder(d.dylib.compatibility_version);
+}
+
+inline void swapStruct(sub_framework_command &s) {
+  sys::swapByteOrder(s.cmd);
+  sys::swapByteOrder(s.cmdsize);
+  sys::swapByteOrder(s.umbrella);
+}
+
+inline void swapStruct(sub_umbrella_command &s) {
+  sys::swapByteOrder(s.cmd);
+  sys::swapByteOrder(s.cmdsize);
+  sys::swapByteOrder(s.sub_umbrella);
+}
+
+inline void swapStruct(sub_library_command &s) {
+  sys::swapByteOrder(s.cmd);
+  sys::swapByteOrder(s.cmdsize);
+  sys::swapByteOrder(s.sub_library);
+}
+
+inline void swapStruct(sub_client_command &s) {
+  sys::swapByteOrder(s.cmd);
+  sys::swapByteOrder(s.cmdsize);
+  sys::swapByteOrder(s.client);
+}
+
+inline void swapStruct(routines_command &r) {
+  sys::swapByteOrder(r.cmd);
+  sys::swapByteOrder(r.cmdsize);
+  sys::swapByteOrder(r.init_address);
+  sys::swapByteOrder(r.init_module);
+  sys::swapByteOrder(r.reserved1);
+  sys::swapByteOrder(r.reserved2);
+  sys::swapByteOrder(r.reserved3);
+  sys::swapByteOrder(r.reserved4);
+  sys::swapByteOrder(r.reserved5);
+  sys::swapByteOrder(r.reserved6);
+}
+
+inline void swapStruct(routines_command_64 &r) {
+  sys::swapByteOrder(r.cmd);
+  sys::swapByteOrder(r.cmdsize);
+  sys::swapByteOrder(r.init_address);
+  sys::swapByteOrder(r.init_module);
+  sys::swapByteOrder(r.reserved1);
+  sys::swapByteOrder(r.reserved2);
+  sys::swapByteOrder(r.reserved3);
+  sys::swapByteOrder(r.reserved4);
+  sys::swapByteOrder(r.reserved5);
+  sys::swapByteOrder(r.reserved6);
+}
+
+inline void swapStruct(thread_command &t) {
+  sys::swapByteOrder(t.cmd);
+  sys::swapByteOrder(t.cmdsize);
+}
+
+inline void swapStruct(dylinker_command &d) {
+  sys::swapByteOrder(d.cmd);
+  sys::swapByteOrder(d.cmdsize);
+  sys::swapByteOrder(d.name);
+}
+
+inline void swapStruct(uuid_command &u) {
+  sys::swapByteOrder(u.cmd);
+  sys::swapByteOrder(u.cmdsize);
+}
+
+inline void swapStruct(rpath_command &r) {
+  sys::swapByteOrder(r.cmd);
+  sys::swapByteOrder(r.cmdsize);
+  sys::swapByteOrder(r.path);
+}
+
+inline void swapStruct(source_version_command &s) {
+  sys::swapByteOrder(s.cmd);
+  sys::swapByteOrder(s.cmdsize);
+  sys::swapByteOrder(s.version);
+}
+
+inline void swapStruct(entry_point_command &e) {
+  sys::swapByteOrder(e.cmd);
+  sys::swapByteOrder(e.cmdsize);
+  sys::swapByteOrder(e.entryoff);
+  sys::swapByteOrder(e.stacksize);
+}
+
+inline void swapStruct(encryption_info_command &e) {
+  sys::swapByteOrder(e.cmd);
+  sys::swapByteOrder(e.cmdsize);
+  sys::swapByteOrder(e.cryptoff);
+  sys::swapByteOrder(e.cryptsize);
+  sys::swapByteOrder(e.cryptid);
+}
+
+inline void swapStruct(encryption_info_command_64 &e) {
+  sys::swapByteOrder(e.cmd);
+  sys::swapByteOrder(e.cmdsize);
+  sys::swapByteOrder(e.cryptoff);
+  sys::swapByteOrder(e.cryptsize);
+  sys::swapByteOrder(e.cryptid);
+  sys::swapByteOrder(e.pad);
+}
+
+inline void swapStruct(dysymtab_command &dst) {
+  sys::swapByteOrder(dst.cmd);
+  sys::swapByteOrder(dst.cmdsize);
+  sys::swapByteOrder(dst.ilocalsym);
+  sys::swapByteOrder(dst.nlocalsym);
+  sys::swapByteOrder(dst.iextdefsym);
+  sys::swapByteOrder(dst.nextdefsym);
+  sys::swapByteOrder(dst.iundefsym);
+  sys::swapByteOrder(dst.nundefsym);
+  sys::swapByteOrder(dst.tocoff);
+  sys::swapByteOrder(dst.ntoc);
+  sys::swapByteOrder(dst.modtaboff);
+  sys::swapByteOrder(dst.nmodtab);
+  sys::swapByteOrder(dst.extrefsymoff);
+  sys::swapByteOrder(dst.nextrefsyms);
+  sys::swapByteOrder(dst.indirectsymoff);
+  sys::swapByteOrder(dst.nindirectsyms);
+  sys::swapByteOrder(dst.extreloff);
+  sys::swapByteOrder(dst.nextrel);
+  sys::swapByteOrder(dst.locreloff);
+  sys::swapByteOrder(dst.nlocrel);
+}
+
+inline void swapStruct(any_relocation_info &reloc) {
+  sys::swapByteOrder(reloc.r_word0);
+  sys::swapByteOrder(reloc.r_word1);
+}
+
+inline void swapStruct(nlist_base &S) {
+  sys::swapByteOrder(S.n_strx);
+  sys::swapByteOrder(S.n_desc);
+}
+
+inline void swapStruct(nlist &sym) {
+  sys::swapByteOrder(sym.n_strx);
+  sys::swapByteOrder(sym.n_desc);
+  sys::swapByteOrder(sym.n_value);
+}
+
+inline void swapStruct(nlist_64 &sym) {
+  sys::swapByteOrder(sym.n_strx);
+  sys::swapByteOrder(sym.n_desc);
+  sys::swapByteOrder(sym.n_value);
+}
+
+inline void swapStruct(linkedit_data_command &C) {
+  sys::swapByteOrder(C.cmd);
+  sys::swapByteOrder(C.cmdsize);
+  sys::swapByteOrder(C.dataoff);
+  sys::swapByteOrder(C.datasize);
+}
+
+inline void swapStruct(linker_option_command &C) {
+  sys::swapByteOrder(C.cmd);
+  sys::swapByteOrder(C.cmdsize);
+  sys::swapByteOrder(C.count);
+}
+
+inline void swapStruct(version_min_command &C) {
+  sys::swapByteOrder(C.cmd);
+  sys::swapByteOrder(C.cmdsize);
+  sys::swapByteOrder(C.version);
+  sys::swapByteOrder(C.sdk);
+}
+
+inline void swapStruct(note_command &C) {
+  sys::swapByteOrder(C.cmd);
+  sys::swapByteOrder(C.cmdsize);
+  sys::swapByteOrder(C.offset);
+  sys::swapByteOrder(C.size);
+}
+
+inline void swapStruct(build_version_command &C) {
+  sys::swapByteOrder(C.cmd);
+  sys::swapByteOrder(C.cmdsize);
+  sys::swapByteOrder(C.platform);
+  sys::swapByteOrder(C.minos);
+  sys::swapByteOrder(C.sdk);
+  sys::swapByteOrder(C.ntools);
+}
+
+inline void swapStruct(build_tool_version &C) {
+  sys::swapByteOrder(C.tool);
+  sys::swapByteOrder(C.version);
+}
+
+inline void swapStruct(data_in_code_entry &C) {
+  sys::swapByteOrder(C.offset);
+  sys::swapByteOrder(C.length);
+  sys::swapByteOrder(C.kind);
+}
+
+inline void swapStruct(uint32_t &C) { sys::swapByteOrder(C); }
+
+// The prebind_cksum_command is obsolete and no longer supported.
+inline void swapStruct(prebind_cksum_command &C) {
+  sys::swapByteOrder(C.cmd);
+  sys::swapByteOrder(C.cmdsize);
+  sys::swapByteOrder(C.cksum);
+}
+
+// The twolevel_hints_command is obsolete and no longer supported.
+inline void swapStruct(twolevel_hints_command &C) {
+  sys::swapByteOrder(C.cmd);
+  sys::swapByteOrder(C.cmdsize);
+  sys::swapByteOrder(C.offset);
+  sys::swapByteOrder(C.nhints);
+}
+
+// The prebound_dylib_command is obsolete and no longer supported.
+inline void swapStruct(prebound_dylib_command &C) {
+  sys::swapByteOrder(C.cmd);
+  sys::swapByteOrder(C.cmdsize);
+  sys::swapByteOrder(C.name);
+  sys::swapByteOrder(C.nmodules);
+  sys::swapByteOrder(C.linked_modules);
+}
+
+// The fvmfile_command is obsolete and no longer supported.
+inline void swapStruct(fvmfile_command &C) {
+  sys::swapByteOrder(C.cmd);
+  sys::swapByteOrder(C.cmdsize);
+  sys::swapByteOrder(C.name);
+  sys::swapByteOrder(C.header_addr);
+}
+
+// The symseg_command is obsolete and no longer supported.
+inline void swapStruct(symseg_command &C) {
+  sys::swapByteOrder(C.cmd);
+  sys::swapByteOrder(C.cmdsize);
+  sys::swapByteOrder(C.offset);
+  sys::swapByteOrder(C.size);
+}
+
+// The ident_command is obsolete and no longer supported.
+inline void swapStruct(ident_command &C) {
+  sys::swapByteOrder(C.cmd);
+  sys::swapByteOrder(C.cmdsize);
+}
+
+inline void swapStruct(fvmlib &C) {
+  sys::swapByteOrder(C.name);
+  sys::swapByteOrder(C.minor_version);
+  sys::swapByteOrder(C.header_addr);
+}
+
+// The fvmlib_command is obsolete and no longer supported.
+inline void swapStruct(fvmlib_command &C) {
+  sys::swapByteOrder(C.cmd);
+  sys::swapByteOrder(C.cmdsize);
+  swapStruct(C.fvmlib);
+}
+
+// Get/Set functions from <mach-o/nlist.h>
+
+inline uint16_t GET_LIBRARY_ORDINAL(uint16_t n_desc) {
+  return (((n_desc) >> 8u) & 0xffu);
+}
+
+inline void SET_LIBRARY_ORDINAL(uint16_t &n_desc, uint8_t ordinal) {
+  n_desc = (((n_desc)&0x00ff) | (((ordinal)&0xff) << 8));
+}
+
+inline uint8_t GET_COMM_ALIGN(uint16_t n_desc) {
+  return (n_desc >> 8u) & 0x0fu;
+}
+
+inline void SET_COMM_ALIGN(uint16_t &n_desc, uint8_t align) {
+  n_desc = ((n_desc & 0xf0ffu) | ((align & 0x0fu) << 8u));
+}
+
+// Enums from <mach/machine.h>
+enum : uint32_t {
+  // Capability bits used in the definition of cpu_type.
+  CPU_ARCH_MASK = 0xff000000, // Mask for architecture bits
+  CPU_ARCH_ABI64 = 0x01000000, // 64 bit ABI
+  CPU_ARCH_ABI64_32 = 0x02000000, // ILP32 ABI on 64-bit hardware
+};
+
+// Constants for the cputype field.
+enum CPUType {
+  CPU_TYPE_ANY = -1,
+  CPU_TYPE_X86 = 7,
+  CPU_TYPE_I386 = CPU_TYPE_X86,
+  CPU_TYPE_X86_64 = CPU_TYPE_X86 | CPU_ARCH_ABI64,
+  /* CPU_TYPE_MIPS      = 8, */
+  CPU_TYPE_MC98000 = 10, // Old Motorola PowerPC
+  CPU_TYPE_ARM = 12,
+  CPU_TYPE_ARM64 = CPU_TYPE_ARM | CPU_ARCH_ABI64,
+  CPU_TYPE_ARM64_32 = CPU_TYPE_ARM | CPU_ARCH_ABI64_32,
+  CPU_TYPE_SPARC = 14,
+  CPU_TYPE_POWERPC = 18,
+  CPU_TYPE_POWERPC64 = CPU_TYPE_POWERPC | CPU_ARCH_ABI64
+};
+
+enum : uint32_t {
+  // Capability bits used in the definition of cpusubtype.
+  CPU_SUBTYPE_MASK = 0xff000000,  // Mask for architecture bits
+  CPU_SUBTYPE_LIB64 = 0x80000000, // 64 bit libraries
+
+  // Special CPU subtype constants.
+  CPU_SUBTYPE_MULTIPLE = ~0u
+};
+
+// Constants for the cpusubtype field.
+enum CPUSubTypeX86 {
+  CPU_SUBTYPE_I386_ALL = 3,
+  CPU_SUBTYPE_386 = 3,
+  CPU_SUBTYPE_486 = 4,
+  CPU_SUBTYPE_486SX = 0x84,
+  CPU_SUBTYPE_586 = 5,
+  CPU_SUBTYPE_PENT = CPU_SUBTYPE_586,
+  CPU_SUBTYPE_PENTPRO = 0x16,
+  CPU_SUBTYPE_PENTII_M3 = 0x36,
+  CPU_SUBTYPE_PENTII_M5 = 0x56,
+  CPU_SUBTYPE_CELERON = 0x67,
+  CPU_SUBTYPE_CELERON_MOBILE = 0x77,
+  CPU_SUBTYPE_PENTIUM_3 = 0x08,
+  CPU_SUBTYPE_PENTIUM_3_M = 0x18,
+  CPU_SUBTYPE_PENTIUM_3_XEON = 0x28,
+  CPU_SUBTYPE_PENTIUM_M = 0x09,
+  CPU_SUBTYPE_PENTIUM_4 = 0x0a,
+  CPU_SUBTYPE_PENTIUM_4_M = 0x1a,
+  CPU_SUBTYPE_ITANIUM = 0x0b,
+  CPU_SUBTYPE_ITANIUM_2 = 0x1b,
+  CPU_SUBTYPE_XEON = 0x0c,
+  CPU_SUBTYPE_XEON_MP = 0x1c,
+
+  CPU_SUBTYPE_X86_ALL = 3,
+  CPU_SUBTYPE_X86_64_ALL = 3,
+  CPU_SUBTYPE_X86_ARCH1 = 4,
+  CPU_SUBTYPE_X86_64_H = 8
+};
+inline int CPU_SUBTYPE_INTEL(int Family, int Model) {
+  return Family | (Model << 4);
+}
+inline int CPU_SUBTYPE_INTEL_FAMILY(CPUSubTypeX86 ST) {
+  return ((int)ST) & 0x0f;
+}
+inline int CPU_SUBTYPE_INTEL_MODEL(CPUSubTypeX86 ST) { return ((int)ST) >> 4; }
+enum { CPU_SUBTYPE_INTEL_FAMILY_MAX = 15, CPU_SUBTYPE_INTEL_MODEL_ALL = 0 };
+
+enum CPUSubTypeARM {
+  CPU_SUBTYPE_ARM_ALL = 0,
+  CPU_SUBTYPE_ARM_V4T = 5,
+  CPU_SUBTYPE_ARM_V6 = 6,
+  CPU_SUBTYPE_ARM_V5 = 7,
+  CPU_SUBTYPE_ARM_V5TEJ = 7,
+  CPU_SUBTYPE_ARM_XSCALE = 8,
+  CPU_SUBTYPE_ARM_V7 = 9,
+  //  unused  ARM_V7F     = 10,
+  CPU_SUBTYPE_ARM_V7S = 11,
+  CPU_SUBTYPE_ARM_V7K = 12,
+  CPU_SUBTYPE_ARM_V6M = 14,
+  CPU_SUBTYPE_ARM_V7M = 15,
+  CPU_SUBTYPE_ARM_V7EM = 16
+};
+
+enum CPUSubTypeARM64 {
+  CPU_SUBTYPE_ARM64_ALL = 0,
+  CPU_SUBTYPE_ARM64E = 2,
+};
+
+enum CPUSubTypeARM64_32 { CPU_SUBTYPE_ARM64_32_V8 = 1 };
+
+enum CPUSubTypeSPARC { CPU_SUBTYPE_SPARC_ALL = 0 };
+
+enum CPUSubTypePowerPC {
+  CPU_SUBTYPE_POWERPC_ALL = 0,
+  CPU_SUBTYPE_POWERPC_601 = 1,
+  CPU_SUBTYPE_POWERPC_602 = 2,
+  CPU_SUBTYPE_POWERPC_603 = 3,
+  CPU_SUBTYPE_POWERPC_603e = 4,
+  CPU_SUBTYPE_POWERPC_603ev = 5,
+  CPU_SUBTYPE_POWERPC_604 = 6,
+  CPU_SUBTYPE_POWERPC_604e = 7,
+  CPU_SUBTYPE_POWERPC_620 = 8,
+  CPU_SUBTYPE_POWERPC_750 = 9,
+  CPU_SUBTYPE_POWERPC_7400 = 10,
+  CPU_SUBTYPE_POWERPC_7450 = 11,
+  CPU_SUBTYPE_POWERPC_970 = 100,
+
+  CPU_SUBTYPE_MC980000_ALL = CPU_SUBTYPE_POWERPC_ALL,
+  CPU_SUBTYPE_MC98601 = CPU_SUBTYPE_POWERPC_601
+};
+
+struct x86_thread_state32_t {
+  uint32_t eax;
+  uint32_t ebx;
+  uint32_t ecx;
+  uint32_t edx;
+  uint32_t edi;
+  uint32_t esi;
+  uint32_t ebp;
+  uint32_t esp;
+  uint32_t ss;
+  uint32_t eflags;
+  uint32_t eip;
+  uint32_t cs;
+  uint32_t ds;
+  uint32_t es;
+  uint32_t fs;
+  uint32_t gs;
+};
+
+struct x86_thread_state64_t {
+  uint64_t rax;
+  uint64_t rbx;
+  uint64_t rcx;
+  uint64_t rdx;
+  uint64_t rdi;
+  uint64_t rsi;
+  uint64_t rbp;
+  uint64_t rsp;
+  uint64_t r8;
+  uint64_t r9;
+  uint64_t r10;
+  uint64_t r11;
+  uint64_t r12;
+  uint64_t r13;
+  uint64_t r14;
+  uint64_t r15;
+  uint64_t rip;
+  uint64_t rflags;
+  uint64_t cs;
+  uint64_t fs;
+  uint64_t gs;
+};
+
+enum x86_fp_control_precis {
+  x86_FP_PREC_24B = 0,
+  x86_FP_PREC_53B = 2,
+  x86_FP_PREC_64B = 3
+};
+
+enum x86_fp_control_rc {
+  x86_FP_RND_NEAR = 0,
+  x86_FP_RND_DOWN = 1,
+  x86_FP_RND_UP = 2,
+  x86_FP_CHOP = 3
+};
+
+struct fp_control_t {
+  unsigned short invalid : 1, denorm : 1, zdiv : 1, ovrfl : 1, undfl : 1,
+      precis : 1, : 2, pc : 2, rc : 2, : 1, : 3;
+};
+
+struct fp_status_t {
+  unsigned short invalid : 1, denorm : 1, zdiv : 1, ovrfl : 1, undfl : 1,
+      precis : 1, stkflt : 1, errsumm : 1, c0 : 1, c1 : 1, c2 : 1, tos : 3,
+      c3 : 1, busy : 1;
+};
+
+struct mmst_reg_t {
+  char mmst_reg[10];
+  char mmst_rsrv[6];
+};
+
+struct xmm_reg_t {
+  char xmm_reg[16];
+};
+
+struct x86_float_state64_t {
+  int32_t fpu_reserved[2];
+  fp_control_t fpu_fcw;
+  fp_status_t fpu_fsw;
+  uint8_t fpu_ftw;
+  uint8_t fpu_rsrv1;
+  uint16_t fpu_fop;
+  uint32_t fpu_ip;
+  uint16_t fpu_cs;
+  uint16_t fpu_rsrv2;
+  uint32_t fpu_dp;
+  uint16_t fpu_ds;
+  uint16_t fpu_rsrv3;
+  uint32_t fpu_mxcsr;
+  uint32_t fpu_mxcsrmask;
+  mmst_reg_t fpu_stmm0;
+  mmst_reg_t fpu_stmm1;
+  mmst_reg_t fpu_stmm2;
+  mmst_reg_t fpu_stmm3;
+  mmst_reg_t fpu_stmm4;
+  mmst_reg_t fpu_stmm5;
+  mmst_reg_t fpu_stmm6;
+  mmst_reg_t fpu_stmm7;
+  xmm_reg_t fpu_xmm0;
+  xmm_reg_t fpu_xmm1;
+  xmm_reg_t fpu_xmm2;
+  xmm_reg_t fpu_xmm3;
+  xmm_reg_t fpu_xmm4;
+  xmm_reg_t fpu_xmm5;
+  xmm_reg_t fpu_xmm6;
+  xmm_reg_t fpu_xmm7;
+  xmm_reg_t fpu_xmm8;
+  xmm_reg_t fpu_xmm9;
+  xmm_reg_t fpu_xmm10;
+  xmm_reg_t fpu_xmm11;
+  xmm_reg_t fpu_xmm12;
+  xmm_reg_t fpu_xmm13;
+  xmm_reg_t fpu_xmm14;
+  xmm_reg_t fpu_xmm15;
+  char fpu_rsrv4[6 * 16];
+  uint32_t fpu_reserved1;
+};
+
+struct x86_exception_state64_t {
+  uint16_t trapno;
+  uint16_t cpu;
+  uint32_t err;
+  uint64_t faultvaddr;
+};
+
+inline void swapStruct(x86_thread_state32_t &x) {
+  sys::swapByteOrder(x.eax);
+  sys::swapByteOrder(x.ebx);
+  sys::swapByteOrder(x.ecx);
+  sys::swapByteOrder(x.edx);
+  sys::swapByteOrder(x.edi);
+  sys::swapByteOrder(x.esi);
+  sys::swapByteOrder(x.ebp);
+  sys::swapByteOrder(x.esp);
+  sys::swapByteOrder(x.ss);
+  sys::swapByteOrder(x.eflags);
+  sys::swapByteOrder(x.eip);
+  sys::swapByteOrder(x.cs);
+  sys::swapByteOrder(x.ds);
+  sys::swapByteOrder(x.es);
+  sys::swapByteOrder(x.fs);
+  sys::swapByteOrder(x.gs);
+}
+
+inline void swapStruct(x86_thread_state64_t &x) {
+  sys::swapByteOrder(x.rax);
+  sys::swapByteOrder(x.rbx);
+  sys::swapByteOrder(x.rcx);
+  sys::swapByteOrder(x.rdx);
+  sys::swapByteOrder(x.rdi);
+  sys::swapByteOrder(x.rsi);
+  sys::swapByteOrder(x.rbp);
+  sys::swapByteOrder(x.rsp);
+  sys::swapByteOrder(x.r8);
+  sys::swapByteOrder(x.r9);
+  sys::swapByteOrder(x.r10);
+  sys::swapByteOrder(x.r11);
+  sys::swapByteOrder(x.r12);
+  sys::swapByteOrder(x.r13);
+  sys::swapByteOrder(x.r14);
+  sys::swapByteOrder(x.r15);
+  sys::swapByteOrder(x.rip);
+  sys::swapByteOrder(x.rflags);
+  sys::swapByteOrder(x.cs);
+  sys::swapByteOrder(x.fs);
+  sys::swapByteOrder(x.gs);
+}
+
+inline void swapStruct(x86_float_state64_t &x) {
+  sys::swapByteOrder(x.fpu_reserved[0]);
+  sys::swapByteOrder(x.fpu_reserved[1]);
+  // TODO swap: fp_control_t fpu_fcw;
+  // TODO swap: fp_status_t fpu_fsw;
+  sys::swapByteOrder(x.fpu_fop);
+  sys::swapByteOrder(x.fpu_ip);
+  sys::swapByteOrder(x.fpu_cs);
+  sys::swapByteOrder(x.fpu_rsrv2);
+  sys::swapByteOrder(x.fpu_dp);
+  sys::swapByteOrder(x.fpu_ds);
+  sys::swapByteOrder(x.fpu_rsrv3);
+  sys::swapByteOrder(x.fpu_mxcsr);
+  sys::swapByteOrder(x.fpu_mxcsrmask);
+  sys::swapByteOrder(x.fpu_reserved1);
+}
+
+inline void swapStruct(x86_exception_state64_t &x) {
+  sys::swapByteOrder(x.trapno);
+  sys::swapByteOrder(x.cpu);
+  sys::swapByteOrder(x.err);
+  sys::swapByteOrder(x.faultvaddr);
+}
+
+struct x86_state_hdr_t {
+  uint32_t flavor;
+  uint32_t count;
+};
+
+struct x86_thread_state_t {
+  x86_state_hdr_t tsh;
+  union {
+    x86_thread_state64_t ts64;
+    x86_thread_state32_t ts32;
+  } uts;
+};
+
+struct x86_float_state_t {
+  x86_state_hdr_t fsh;
+  union {
+    x86_float_state64_t fs64;
+  } ufs;
+};
+
+struct x86_exception_state_t {
+  x86_state_hdr_t esh;
+  union {
+    x86_exception_state64_t es64;
+  } ues;
+};
+
+inline void swapStruct(x86_state_hdr_t &x) {
+  sys::swapByteOrder(x.flavor);
+  sys::swapByteOrder(x.count);
+}
+
+enum X86ThreadFlavors {
+  x86_THREAD_STATE32 = 1,
+  x86_FLOAT_STATE32 = 2,
+  x86_EXCEPTION_STATE32 = 3,
+  x86_THREAD_STATE64 = 4,
+  x86_FLOAT_STATE64 = 5,
+  x86_EXCEPTION_STATE64 = 6,
+  x86_THREAD_STATE = 7,
+  x86_FLOAT_STATE = 8,
+  x86_EXCEPTION_STATE = 9,
+  x86_DEBUG_STATE32 = 10,
+  x86_DEBUG_STATE64 = 11,
+  x86_DEBUG_STATE = 12
+};
+
+inline void swapStruct(x86_thread_state_t &x) {
+  swapStruct(x.tsh);
+  if (x.tsh.flavor == x86_THREAD_STATE64)
+    swapStruct(x.uts.ts64);
+}
+
+inline void swapStruct(x86_float_state_t &x) {
+  swapStruct(x.fsh);
+  if (x.fsh.flavor == x86_FLOAT_STATE64)
+    swapStruct(x.ufs.fs64);
+}
+
+inline void swapStruct(x86_exception_state_t &x) {
+  swapStruct(x.esh);
+  if (x.esh.flavor == x86_EXCEPTION_STATE64)
+    swapStruct(x.ues.es64);
+}
+
+const uint32_t x86_THREAD_STATE32_COUNT =
+    sizeof(x86_thread_state32_t) / sizeof(uint32_t);
+
+const uint32_t x86_THREAD_STATE64_COUNT =
+    sizeof(x86_thread_state64_t) / sizeof(uint32_t);
+const uint32_t x86_FLOAT_STATE64_COUNT =
+    sizeof(x86_float_state64_t) / sizeof(uint32_t);
+const uint32_t x86_EXCEPTION_STATE64_COUNT =
+    sizeof(x86_exception_state64_t) / sizeof(uint32_t);
+
+const uint32_t x86_THREAD_STATE_COUNT =
+    sizeof(x86_thread_state_t) / sizeof(uint32_t);
+const uint32_t x86_FLOAT_STATE_COUNT =
+    sizeof(x86_float_state_t) / sizeof(uint32_t);
+const uint32_t x86_EXCEPTION_STATE_COUNT =
+    sizeof(x86_exception_state_t) / sizeof(uint32_t);
+
+struct arm_thread_state32_t {
+  uint32_t r[13];
+  uint32_t sp;
+  uint32_t lr;
+  uint32_t pc;
+  uint32_t cpsr;
+};
+
+inline void swapStruct(arm_thread_state32_t &x) {
+  for (int i = 0; i < 13; i++)
+    sys::swapByteOrder(x.r[i]);
+  sys::swapByteOrder(x.sp);
+  sys::swapByteOrder(x.lr);
+  sys::swapByteOrder(x.pc);
+  sys::swapByteOrder(x.cpsr);
+}
+
+struct arm_thread_state64_t {
+  uint64_t x[29];
+  uint64_t fp;
+  uint64_t lr;
+  uint64_t sp;
+  uint64_t pc;
+  uint32_t cpsr;
+  uint32_t pad;
+};
+
+inline void swapStruct(arm_thread_state64_t &x) {
+  for (int i = 0; i < 29; i++)
+    sys::swapByteOrder(x.x[i]);
+  sys::swapByteOrder(x.fp);
+  sys::swapByteOrder(x.lr);
+  sys::swapByteOrder(x.sp);
+  sys::swapByteOrder(x.pc);
+  sys::swapByteOrder(x.cpsr);
+}
+
+struct arm_state_hdr_t {
+  uint32_t flavor;
+  uint32_t count;
+};
+
+struct arm_thread_state_t {
+  arm_state_hdr_t tsh;
+  union {
+    arm_thread_state32_t ts32;
+  } uts;
+};
+
+inline void swapStruct(arm_state_hdr_t &x) {
+  sys::swapByteOrder(x.flavor);
+  sys::swapByteOrder(x.count);
+}
+
+enum ARMThreadFlavors {
+  ARM_THREAD_STATE = 1,
+  ARM_VFP_STATE = 2,
+  ARM_EXCEPTION_STATE = 3,
+  ARM_DEBUG_STATE = 4,
+  ARN_THREAD_STATE_NONE = 5,
+  ARM_THREAD_STATE64 = 6,
+  ARM_EXCEPTION_STATE64 = 7
+};
+
+inline void swapStruct(arm_thread_state_t &x) {
+  swapStruct(x.tsh);
+  if (x.tsh.flavor == ARM_THREAD_STATE)
+    swapStruct(x.uts.ts32);
+}
+
+const uint32_t ARM_THREAD_STATE_COUNT =
+    sizeof(arm_thread_state32_t) / sizeof(uint32_t);
+
+const uint32_t ARM_THREAD_STATE64_COUNT =
+    sizeof(arm_thread_state64_t) / sizeof(uint32_t);
+
+struct ppc_thread_state32_t {
+  uint32_t srr0;
+  uint32_t srr1;
+  uint32_t r0;
+  uint32_t r1;
+  uint32_t r2;
+  uint32_t r3;
+  uint32_t r4;
+  uint32_t r5;
+  uint32_t r6;
+  uint32_t r7;
+  uint32_t r8;
+  uint32_t r9;
+  uint32_t r10;
+  uint32_t r11;
+  uint32_t r12;
+  uint32_t r13;
+  uint32_t r14;
+  uint32_t r15;
+  uint32_t r16;
+  uint32_t r17;
+  uint32_t r18;
+  uint32_t r19;
+  uint32_t r20;
+  uint32_t r21;
+  uint32_t r22;
+  uint32_t r23;
+  uint32_t r24;
+  uint32_t r25;
+  uint32_t r26;
+  uint32_t r27;
+  uint32_t r28;
+  uint32_t r29;
+  uint32_t r30;
+  uint32_t r31;
+  uint32_t ct;
+  uint32_t xer;
+  uint32_t lr;
+  uint32_t ctr;
+  uint32_t mq;
+  uint32_t vrsave;
+};
+
+inline void swapStruct(ppc_thread_state32_t &x) {
+  sys::swapByteOrder(x.srr0);
+  sys::swapByteOrder(x.srr1);
+  sys::swapByteOrder(x.r0);
+  sys::swapByteOrder(x.r1);
+  sys::swapByteOrder(x.r2);
+  sys::swapByteOrder(x.r3);
+  sys::swapByteOrder(x.r4);
+  sys::swapByteOrder(x.r5);
+  sys::swapByteOrder(x.r6);
+  sys::swapByteOrder(x.r7);
+  sys::swapByteOrder(x.r8);
+  sys::swapByteOrder(x.r9);
+  sys::swapByteOrder(x.r10);
+  sys::swapByteOrder(x.r11);
+  sys::swapByteOrder(x.r12);
+  sys::swapByteOrder(x.r13);
+  sys::swapByteOrder(x.r14);
+  sys::swapByteOrder(x.r15);
+  sys::swapByteOrder(x.r16);
+  sys::swapByteOrder(x.r17);
+  sys::swapByteOrder(x.r18);
+  sys::swapByteOrder(x.r19);
+  sys::swapByteOrder(x.r20);
+  sys::swapByteOrder(x.r21);
+  sys::swapByteOrder(x.r22);
+  sys::swapByteOrder(x.r23);
+  sys::swapByteOrder(x.r24);
+  sys::swapByteOrder(x.r25);
+  sys::swapByteOrder(x.r26);
+  sys::swapByteOrder(x.r27);
+  sys::swapByteOrder(x.r28);
+  sys::swapByteOrder(x.r29);
+  sys::swapByteOrder(x.r30);
+  sys::swapByteOrder(x.r31);
+  sys::swapByteOrder(x.ct);
+  sys::swapByteOrder(x.xer);
+  sys::swapByteOrder(x.lr);
+  sys::swapByteOrder(x.ctr);
+  sys::swapByteOrder(x.mq);
+  sys::swapByteOrder(x.vrsave);
+}
+
+struct ppc_state_hdr_t {
+  uint32_t flavor;
+  uint32_t count;
+};
+
+struct ppc_thread_state_t {
+  ppc_state_hdr_t tsh;
+  union {
+    ppc_thread_state32_t ts32;
+  } uts;
+};
+
+inline void swapStruct(ppc_state_hdr_t &x) {
+  sys::swapByteOrder(x.flavor);
+  sys::swapByteOrder(x.count);
+}
+
+enum PPCThreadFlavors {
+  PPC_THREAD_STATE = 1,
+  PPC_FLOAT_STATE = 2,
+  PPC_EXCEPTION_STATE = 3,
+  PPC_VECTOR_STATE = 4,
+  PPC_THREAD_STATE64 = 5,
+  PPC_EXCEPTION_STATE64 = 6,
+  PPC_THREAD_STATE_NONE = 7
+};
+
+inline void swapStruct(ppc_thread_state_t &x) {
+  swapStruct(x.tsh);
+  if (x.tsh.flavor == PPC_THREAD_STATE)
+    swapStruct(x.uts.ts32);
+}
+
+const uint32_t PPC_THREAD_STATE_COUNT =
+    sizeof(ppc_thread_state32_t) / sizeof(uint32_t);
+
+// Define a union of all load command structs
+#define LOAD_COMMAND_STRUCT(LCStruct) LCStruct LCStruct##_data;
+
+LLVM_PACKED_START
+union alignas(4) macho_load_command {
+#include "llvm/BinaryFormat/MachO.def"
+};
+LLVM_PACKED_END
+
+} // end namespace MachO
+} // end namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Magic.h b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Magic.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Magic.h
@@ -0,0 +1,77 @@
+//===- llvm/BinaryFormat/Magic.h - File magic identification ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BINARYFORMAT_MAGIC_H
+#define LLVM_BINARYFORMAT_MAGIC_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+
+#include <system_error>
+
+namespace llvm {
+/// file_magic - An "enum class" enumeration of file types based on magic (the
+/// first N bytes of the file).
+struct file_magic {
+  enum Impl {
+    unknown = 0,       ///< Unrecognized file
+    bitcode,           ///< Bitcode file
+    archive,           ///< ar style archive file
+    elf,               ///< ELF Unknown type
+    elf_relocatable,   ///< ELF Relocatable object file
+    elf_executable,    ///< ELF Executable image
+    elf_shared_object, ///< ELF dynamically linked shared lib
+    elf_core,          ///< ELF core image
+    macho_object,      ///< Mach-O Object file
+    macho_executable,  ///< Mach-O Executable
+    macho_fixed_virtual_memory_shared_lib,    ///< Mach-O Shared Lib, FVM
+    macho_core,                               ///< Mach-O Core File
+    macho_preload_executable,                 ///< Mach-O Preloaded Executable
+    macho_dynamically_linked_shared_lib,      ///< Mach-O dynlinked shared lib
+    macho_dynamic_linker,                     ///< The Mach-O dynamic linker
+    macho_bundle,                             ///< Mach-O Bundle file
+    macho_dynamically_linked_shared_lib_stub, ///< Mach-O Shared lib stub
+    macho_dsym_companion,                     ///< Mach-O dSYM companion file
+    macho_kext_bundle,                        ///< Mach-O kext bundle file
+    macho_universal_binary,                   ///< Mach-O universal binary
+    minidump,                                 ///< Windows minidump file
+    coff_cl_gl_object,   ///< Microsoft cl.exe's intermediate code file
+    coff_object,         ///< COFF object file
+    coff_import_library, ///< COFF import library
+    pecoff_executable,   ///< PECOFF executable file
+    windows_resource,    ///< Windows compiled resource file (.res)
+    xcoff_object_32,     ///< 32-bit XCOFF object file
+    xcoff_object_64,     ///< 64-bit XCOFF object file
+    wasm_object,         ///< WebAssembly Object file
+    pdb,                 ///< Windows PDB debug info file
+    tapi_file,           ///< Text-based Dynamic Library Stub file
+  };
+
+  bool is_object() const { return V != unknown; }
+
+  file_magic() = default;
+  file_magic(Impl V) : V(V) {}
+  operator Impl() const { return V; }
+
+private:
+  Impl V = unknown;
+};
+
+/// Identify the type of a binary file based on how magical it is.
+file_magic identify_magic(StringRef magic);
+
+/// Get and identify \a path's type based on its content.
+///
+/// @param path Input path.
+/// @param result Set to the type of file, or file_magic::unknown.
+/// @returns errc::success if result has been successfully set, otherwise a
+///          platform-specific error_code.
+std::error_code identify_magic(const Twine &path, file_magic &result);
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Wasm.h b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Wasm.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/Wasm.h
@@ -0,0 +1,391 @@
+//===- Wasm.h - Wasm object file format -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines manifest constants for the wasm object file format.
+// See: https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BINARYFORMAT_WASM_H
+#define LLVM_BINARYFORMAT_WASM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+namespace wasm {
+
+// Object file magic string.
+const char WasmMagic[] = {'\0', 'a', 's', 'm'};
+// Wasm binary format version
+const uint32_t WasmVersion = 0x1;
+// Wasm linking metadata version
+const uint32_t WasmMetadataVersion = 0x2;
+// Wasm uses a 64k page size
+const uint32_t WasmPageSize = 65536;
+
+struct WasmObjectHeader {
+  StringRef Magic;
+  uint32_t Version;
+};
+
+struct WasmDylinkInfo {
+  uint32_t MemorySize; // Memory size in bytes
+  uint32_t MemoryAlignment;  // P2 alignment of memory
+  uint32_t TableSize;  // Table size in elements
+  uint32_t TableAlignment;  // P2 alignment of table
+  std::vector<StringRef> Needed; // Shared library depenedencies
+};
+
+struct WasmProducerInfo {
+  std::vector<std::pair<std::string, std::string>> Languages;
+  std::vector<std::pair<std::string, std::string>> Tools;
+  std::vector<std::pair<std::string, std::string>> SDKs;
+};
+
+struct WasmFeatureEntry {
+  uint8_t Prefix;
+  std::string Name;
+};
+
+struct WasmExport {
+  StringRef Name;
+  uint8_t Kind;
+  uint32_t Index;
+};
+
+struct WasmLimits {
+  uint8_t Flags;
+  uint32_t Initial;
+  uint32_t Maximum;
+};
+
+struct WasmTable {
+  uint8_t ElemType;
+  WasmLimits Limits;
+};
+
+struct WasmInitExpr {
+  uint8_t Opcode;
+  union {
+    int32_t Int32;
+    int64_t Int64;
+    int32_t Float32;
+    int64_t Float64;
+    uint32_t Global;
+  } Value;
+};
+
+struct WasmGlobalType {
+  uint8_t Type;
+  bool Mutable;
+};
+
+struct WasmGlobal {
+  uint32_t Index;
+  WasmGlobalType Type;
+  WasmInitExpr InitExpr;
+  StringRef SymbolName; // from the "linking" section
+};
+
+struct WasmEventType {
+  // Kind of event. Currently only WASM_EVENT_ATTRIBUTE_EXCEPTION is possible.
+  uint32_t Attribute;
+  uint32_t SigIndex;
+};
+
+struct WasmEvent {
+  uint32_t Index;
+  WasmEventType Type;
+  StringRef SymbolName; // from the "linking" section
+};
+
+struct WasmImport {
+  StringRef Module;
+  StringRef Field;
+  uint8_t Kind;
+  union {
+    uint32_t SigIndex;
+    WasmGlobalType Global;
+    WasmTable Table;
+    WasmLimits Memory;
+    WasmEventType Event;
+  };
+};
+
+struct WasmLocalDecl {
+  uint8_t Type;
+  uint32_t Count;
+};
+
+struct WasmFunction {
+  uint32_t Index;
+  std::vector<WasmLocalDecl> Locals;
+  ArrayRef<uint8_t> Body;
+  uint32_t CodeSectionOffset;
+  uint32_t Size;
+  uint32_t CodeOffset;  // start of Locals and Body
+  StringRef SymbolName; // from the "linking" section
+  StringRef DebugName;  // from the "name" section
+  uint32_t Comdat;      // from the "comdat info" section
+};
+
+struct WasmDataSegment {
+  uint32_t InitFlags;
+  uint32_t MemoryIndex; // present if InitFlags & WASM_SEGMENT_HAS_MEMINDEX
+  WasmInitExpr Offset; // present if InitFlags & WASM_SEGMENT_IS_PASSIVE == 0
+  ArrayRef<uint8_t> Content;
+  StringRef Name; // from the "segment info" section
+  uint32_t Alignment;
+  uint32_t LinkerFlags;
+  uint32_t Comdat; // from the "comdat info" section
+};
+
+struct WasmElemSegment {
+  uint32_t TableIndex;
+  WasmInitExpr Offset;
+  std::vector<uint32_t> Functions;
+};
+
+// Represents the location of a Wasm data symbol within a WasmDataSegment, as
+// the index of the segment, and the offset and size within the segment.
+struct WasmDataReference {
+  uint32_t Segment;
+  uint32_t Offset;
+  uint32_t Size;
+};
+
+struct WasmRelocation {
+  uint8_t Type;    // The type of the relocation.
+  uint32_t Index;  // Index into either symbol or type index space.
+  uint64_t Offset; // Offset from the start of the section.
+  int64_t Addend;  // A value to add to the symbol.
+};
+
+struct WasmInitFunc {
+  uint32_t Priority;
+  uint32_t Symbol;
+};
+
+struct WasmSymbolInfo {
+  StringRef Name;
+  uint8_t Kind;
+  uint32_t Flags;
+  StringRef ImportModule; // For undefined symbols the module of the import
+  StringRef ImportName;   // For undefined symbols the name of the import
+  union {
+    // For function or global symbols, the index in function or global index
+    // space.
+    uint32_t ElementIndex;
+    // For a data symbols, the address of the data relative to segment.
+    WasmDataReference DataRef;
+  };
+};
+
+struct WasmFunctionName {
+  uint32_t Index;
+  StringRef Name;
+};
+
+struct WasmLinkingData {
+  uint32_t Version;
+  std::vector<WasmInitFunc> InitFunctions;
+  std::vector<StringRef> Comdats;
+  std::vector<WasmSymbolInfo> SymbolTable;
+};
+
+enum : unsigned {
+  WASM_SEC_CUSTOM = 0,     // Custom / User-defined section
+  WASM_SEC_TYPE = 1,       // Function signature declarations
+  WASM_SEC_IMPORT = 2,     // Import declarations
+  WASM_SEC_FUNCTION = 3,   // Function declarations
+  WASM_SEC_TABLE = 4,      // Indirect function table and other tables
+  WASM_SEC_MEMORY = 5,     // Memory attributes
+  WASM_SEC_GLOBAL = 6,     // Global declarations
+  WASM_SEC_EXPORT = 7,     // Exports
+  WASM_SEC_START = 8,      // Start function declaration
+  WASM_SEC_ELEM = 9,       // Elements section
+  WASM_SEC_CODE = 10,      // Function bodies (code)
+  WASM_SEC_DATA = 11,      // Data segments
+  WASM_SEC_DATACOUNT = 12, // Data segment count
+  WASM_SEC_EVENT = 13      // Event declarations
+};
+
+// Type immediate encodings used in various contexts.
+enum : unsigned {
+  WASM_TYPE_I32 = 0x7F,
+  WASM_TYPE_I64 = 0x7E,
+  WASM_TYPE_F32 = 0x7D,
+  WASM_TYPE_F64 = 0x7C,
+  WASM_TYPE_V128 = 0x7B,
+  WASM_TYPE_FUNCREF = 0x70,
+  WASM_TYPE_EXNREF = 0x68,
+  WASM_TYPE_FUNC = 0x60,
+  WASM_TYPE_NORESULT = 0x40, // for blocks with no result values
+};
+
+// Kinds of externals (for imports and exports).
+enum : unsigned {
+  WASM_EXTERNAL_FUNCTION = 0x0,
+  WASM_EXTERNAL_TABLE = 0x1,
+  WASM_EXTERNAL_MEMORY = 0x2,
+  WASM_EXTERNAL_GLOBAL = 0x3,
+  WASM_EXTERNAL_EVENT = 0x4,
+};
+
+// Opcodes used in initializer expressions.
+enum : unsigned {
+  WASM_OPCODE_END = 0x0b,
+  WASM_OPCODE_CALL = 0x10,
+  WASM_OPCODE_LOCAL_GET = 0x20,
+  WASM_OPCODE_GLOBAL_GET = 0x23,
+  WASM_OPCODE_GLOBAL_SET = 0x24,
+  WASM_OPCODE_I32_STORE = 0x36,
+  WASM_OPCODE_I32_CONST = 0x41,
+  WASM_OPCODE_I64_CONST = 0x42,
+  WASM_OPCODE_F32_CONST = 0x43,
+  WASM_OPCODE_F64_CONST = 0x44,
+  WASM_OPCODE_I32_ADD = 0x6a,
+};
+
+// Opcodes used in synthetic functions.
+enum : unsigned {
+  WASM_OPCODE_IF = 0x04,
+  WASM_OPCODE_ELSE = 0x05,
+  WASM_OPCODE_DROP = 0x1a,
+  WASM_OPCODE_MISC_PREFIX = 0xfc,
+  WASM_OPCODE_MEMORY_INIT = 0x08,
+  WASM_OPCODE_DATA_DROP = 0x09,
+  WASM_OPCODE_ATOMICS_PREFIX = 0xfe,
+  WASM_OPCODE_ATOMIC_NOTIFY = 0x00,
+  WASM_OPCODE_I32_ATOMIC_WAIT = 0x01,
+  WASM_OPCODE_I32_ATOMIC_STORE = 0x17,
+  WASM_OPCODE_I32_RMW_CMPXCHG = 0x48,
+};
+
+enum : unsigned {
+  WASM_LIMITS_FLAG_HAS_MAX = 0x1,
+  WASM_LIMITS_FLAG_IS_SHARED = 0x2,
+};
+
+enum : unsigned {
+  WASM_SEGMENT_IS_PASSIVE = 0x01,
+  WASM_SEGMENT_HAS_MEMINDEX = 0x02,
+};
+
+// Feature policy prefixes used in the custom "target_features" section
+enum : uint8_t {
+  WASM_FEATURE_PREFIX_USED = '+',
+  WASM_FEATURE_PREFIX_REQUIRED = '=',
+  WASM_FEATURE_PREFIX_DISALLOWED = '-',
+};
+
+// Kind codes used in the custom "name" section
+enum : unsigned {
+  WASM_NAMES_FUNCTION = 0x1,
+  WASM_NAMES_LOCAL = 0x2,
+};
+
+// Kind codes used in the custom "linking" section
+enum : unsigned {
+  WASM_SEGMENT_INFO = 0x5,
+  WASM_INIT_FUNCS = 0x6,
+  WASM_COMDAT_INFO = 0x7,
+  WASM_SYMBOL_TABLE = 0x8,
+};
+
+// Kind codes used in the custom "linking" section in the WASM_COMDAT_INFO
+enum : unsigned {
+  WASM_COMDAT_DATA = 0x0,
+  WASM_COMDAT_FUNCTION = 0x1,
+};
+
+// Kind codes used in the custom "linking" section in the WASM_SYMBOL_TABLE
+enum WasmSymbolType : unsigned {
+  WASM_SYMBOL_TYPE_FUNCTION = 0x0,
+  WASM_SYMBOL_TYPE_DATA = 0x1,
+  WASM_SYMBOL_TYPE_GLOBAL = 0x2,
+  WASM_SYMBOL_TYPE_SECTION = 0x3,
+  WASM_SYMBOL_TYPE_EVENT = 0x4,
+};
+
+// Kinds of event attributes.
+enum WasmEventAttribute : unsigned {
+  WASM_EVENT_ATTRIBUTE_EXCEPTION = 0x0,
+};
+
+const unsigned WASM_SYMBOL_BINDING_MASK = 0x3;
+const unsigned WASM_SYMBOL_VISIBILITY_MASK = 0xc;
+
+const unsigned WASM_SYMBOL_BINDING_GLOBAL = 0x0;
+const unsigned WASM_SYMBOL_BINDING_WEAK = 0x1;
+const unsigned WASM_SYMBOL_BINDING_LOCAL = 0x2;
+const unsigned WASM_SYMBOL_VISIBILITY_DEFAULT = 0x0;
+const unsigned WASM_SYMBOL_VISIBILITY_HIDDEN = 0x4;
+const unsigned WASM_SYMBOL_UNDEFINED = 0x10;
+const unsigned WASM_SYMBOL_EXPORTED = 0x20;
+const unsigned WASM_SYMBOL_EXPLICIT_NAME = 0x40;
+const unsigned WASM_SYMBOL_NO_STRIP = 0x80;
+
+#define WASM_RELOC(name, value) name = value,
+
+enum : unsigned {
+#include "WasmRelocs.def"
+};
+
+#undef WASM_RELOC
+
+// Subset of types that a value can have
+enum class ValType {
+  I32 = WASM_TYPE_I32,
+  I64 = WASM_TYPE_I64,
+  F32 = WASM_TYPE_F32,
+  F64 = WASM_TYPE_F64,
+  V128 = WASM_TYPE_V128,
+  EXNREF = WASM_TYPE_EXNREF,
+};
+
+struct WasmSignature {
+  SmallVector<ValType, 1> Returns;
+  SmallVector<ValType, 4> Params;
+  // Support empty and tombstone instances, needed by DenseMap.
+  enum { Plain, Empty, Tombstone } State = Plain;
+
+  WasmSignature(SmallVector<ValType, 1> &&InReturns,
+                SmallVector<ValType, 4> &&InParams)
+      : Returns(InReturns), Params(InParams) {}
+  WasmSignature() = default;
+};
+
+// Useful comparison operators
+inline bool operator==(const WasmSignature &LHS, const WasmSignature &RHS) {
+  return LHS.State == RHS.State && LHS.Returns == RHS.Returns &&
+         LHS.Params == RHS.Params;
+}
+
+inline bool operator!=(const WasmSignature &LHS, const WasmSignature &RHS) {
+  return !(LHS == RHS);
+}
+
+inline bool operator==(const WasmGlobalType &LHS, const WasmGlobalType &RHS) {
+  return LHS.Type == RHS.Type && LHS.Mutable == RHS.Mutable;
+}
+
+inline bool operator!=(const WasmGlobalType &LHS, const WasmGlobalType &RHS) {
+  return !(LHS == RHS);
+}
+
+std::string toString(WasmSymbolType type);
+std::string relocTypetoString(uint32_t type);
+bool relocTypeHasAddend(uint32_t type);
+
+} // end namespace wasm
+} // end namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/WasmRelocs.def b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/WasmRelocs.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/BinaryFormat/WasmRelocs.def
@@ -0,0 +1,17 @@
+#ifndef WASM_RELOC
+#error "WASM_RELOC must be defined"
+#endif
+
+WASM_RELOC(R_WASM_FUNCTION_INDEX_LEB,    0)
+WASM_RELOC(R_WASM_TABLE_INDEX_SLEB,      1)
+WASM_RELOC(R_WASM_TABLE_INDEX_I32,       2)
+WASM_RELOC(R_WASM_MEMORY_ADDR_LEB,       3)
+WASM_RELOC(R_WASM_MEMORY_ADDR_SLEB,      4)
+WASM_RELOC(R_WASM_MEMORY_ADDR_I32,       5)
+WASM_RELOC(R_WASM_TYPE_INDEX_LEB,        6)
+WASM_RELOC(R_WASM_GLOBAL_INDEX_LEB,      7)
+WASM_RELOC(R_WASM_FUNCTION_OFFSET_I32,   8)
+WASM_RELOC(R_WASM_SECTION_OFFSET_I32,    9)
+WASM_RELOC(R_WASM_EVENT_INDEX_LEB,      10)
+WASM_RELOC(R_WASM_MEMORY_ADDR_REL_SLEB, 11)
+WASM_RELOC(R_WASM_TABLE_INDEX_REL_SLEB, 12)
diff --git a/binaryen/third_party/llvm-project/include/llvm/Config/abi-breaking.h b/binaryen/third_party/llvm-project/include/llvm/Config/abi-breaking.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Config/abi-breaking.h
@@ -0,0 +1,3 @@
+
+// waka
+
diff --git a/binaryen/third_party/llvm-project/include/llvm/Config/config.h b/binaryen/third_party/llvm-project/include/llvm/Config/config.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Config/config.h
@@ -0,0 +1,4 @@
+
+// waka waka
+
+#include <stdio.h>
diff --git a/binaryen/third_party/llvm-project/include/llvm/Config/llvm-config.h b/binaryen/third_party/llvm-project/include/llvm/Config/llvm-config.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Config/llvm-config.h
@@ -0,0 +1,9 @@
+
+// This is all terrible
+
+#ifndef _WIN32
+#define LLVM_ON_UNIX
+#endif
+
+// Use simple std:: based atomics, no windows specifics
+#define LLVM_THREADING_USE_STD_CALL_ONCE 1
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DIContext.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DIContext.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DIContext.h
@@ -0,0 +1,302 @@
+//===- DIContext.h ----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines DIContext, an abstract data structure that holds
+// debug information data.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DICONTEXT_H
+#define LLVM_DEBUGINFO_DICONTEXT_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
+
+namespace llvm {
+
+/// A format-neutral container for source line information.
+struct DILineInfo {
+  // DILineInfo contains "<invalid>" for function/filename it cannot fetch.
+  static constexpr const char *const BadString = "<invalid>";
+  // Use "??" instead of "<invalid>" to make our output closer to addr2line.
+  static constexpr const char *const Addr2LineBadString = "??";
+  std::string FileName;
+  std::string FunctionName;
+  Optional<StringRef> Source;
+  uint32_t Line = 0;
+  uint32_t Column = 0;
+  uint32_t StartLine = 0;
+
+  // DWARF-specific.
+  uint32_t Discriminator = 0;
+
+  DILineInfo() : FileName(BadString), FunctionName(BadString) {}
+
+  bool operator==(const DILineInfo &RHS) const {
+    return Line == RHS.Line && Column == RHS.Column &&
+           FileName == RHS.FileName && FunctionName == RHS.FunctionName &&
+           StartLine == RHS.StartLine && Discriminator == RHS.Discriminator;
+  }
+
+  bool operator!=(const DILineInfo &RHS) const {
+    return !(*this == RHS);
+  }
+
+  bool operator<(const DILineInfo &RHS) const {
+    return std::tie(FileName, FunctionName, Line, Column, StartLine,
+                    Discriminator) <
+           std::tie(RHS.FileName, RHS.FunctionName, RHS.Line, RHS.Column,
+                    RHS.StartLine, RHS.Discriminator);
+  }
+
+  explicit operator bool() const { return *this != DILineInfo(); }
+
+  void dump(raw_ostream &OS) {
+    OS << "Line info: ";
+    if (FileName != BadString)
+      OS << "file '" << FileName << "', ";
+    if (FunctionName != BadString)
+      OS << "function '" << FunctionName << "', ";
+    OS << "line " << Line << ", ";
+    OS << "column " << Column << ", ";
+    OS << "start line " << StartLine << '\n';
+  }
+};
+
+using DILineInfoTable = SmallVector<std::pair<uint64_t, DILineInfo>, 16>;
+
+/// A format-neutral container for inlined code description.
+class DIInliningInfo {
+  SmallVector<DILineInfo, 4> Frames;
+
+public:
+  DIInliningInfo() = default;
+
+  const DILineInfo & getFrame(unsigned Index) const {
+    assert(Index < Frames.size());
+    return Frames[Index];
+  }
+
+  DILineInfo *getMutableFrame(unsigned Index) {
+    assert(Index < Frames.size());
+    return &Frames[Index];
+  }
+
+  uint32_t getNumberOfFrames() const {
+    return Frames.size();
+  }
+
+  void addFrame(const DILineInfo &Frame) {
+    Frames.push_back(Frame);
+  }
+
+  void resize(unsigned i) {
+    Frames.resize(i);
+  }
+};
+
+/// Container for description of a global variable.
+struct DIGlobal {
+  std::string Name;
+  uint64_t Start = 0;
+  uint64_t Size = 0;
+
+  DIGlobal() : Name(DILineInfo::BadString) {}
+};
+
+struct DILocal {
+  std::string FunctionName;
+  std::string Name;
+  std::string DeclFile;
+  uint64_t DeclLine = 0;
+  Optional<int64_t> FrameOffset;
+  Optional<uint64_t> Size;
+  Optional<uint64_t> TagOffset;
+};
+
+/// A DINameKind is passed to name search methods to specify a
+/// preference regarding the type of name resolution the caller wants.
+enum class DINameKind { None, ShortName, LinkageName };
+
+/// Controls which fields of DILineInfo container should be filled
+/// with data.
+struct DILineInfoSpecifier {
+  enum class FileLineInfoKind { None, Default, AbsoluteFilePath };
+  using FunctionNameKind = DINameKind;
+
+  FileLineInfoKind FLIKind;
+  FunctionNameKind FNKind;
+
+  DILineInfoSpecifier(FileLineInfoKind FLIKind = FileLineInfoKind::Default,
+                      FunctionNameKind FNKind = FunctionNameKind::None)
+      : FLIKind(FLIKind), FNKind(FNKind) {}
+};
+
+/// This is just a helper to programmatically construct DIDumpType.
+enum DIDumpTypeCounter {
+#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \
+  DIDT_ID_##ENUM_NAME,
+#include "llvm/BinaryFormat/Dwarf.def"
+#undef HANDLE_DWARF_SECTION
+  DIDT_ID_UUID,
+  DIDT_ID_Count
+};
+static_assert(DIDT_ID_Count <= 32, "section types overflow storage");
+
+/// Selects which debug sections get dumped.
+enum DIDumpType : unsigned {
+  DIDT_Null,
+  DIDT_All             = ~0U,
+#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \
+  DIDT_##ENUM_NAME = 1U << DIDT_ID_##ENUM_NAME,
+#include "llvm/BinaryFormat/Dwarf.def"
+#undef HANDLE_DWARF_SECTION
+  DIDT_UUID = 1 << DIDT_ID_UUID,
+};
+
+/// Container for dump options that control which debug information will be
+/// dumped.
+struct DIDumpOptions {
+  unsigned DumpType = DIDT_All;
+  unsigned ChildRecurseDepth = -1U;
+  unsigned ParentRecurseDepth = -1U;
+  uint16_t Version = 0; // DWARF version to assume when extracting.
+  uint8_t AddrSize = 4; // Address byte size to assume when extracting.
+  bool ShowAddresses = true;
+  bool ShowChildren = false;
+  bool ShowParents = false;
+  bool ShowForm = false;
+  bool SummarizeTypes = false;
+  bool Verbose = false;
+  bool DisplayRawContents = false;
+
+  /// Return default option set for printing a single DIE without children.
+  static DIDumpOptions getForSingleDIE() {
+    DIDumpOptions Opts;
+    Opts.ChildRecurseDepth = 0;
+    Opts.ParentRecurseDepth = 0;
+    return Opts;
+  }
+
+  /// Return the options with RecurseDepth set to 0 unless explicitly required.
+  DIDumpOptions noImplicitRecursion() const {
+    DIDumpOptions Opts = *this;
+    if (ChildRecurseDepth == -1U && !ShowChildren)
+      Opts.ChildRecurseDepth = 0;
+    if (ParentRecurseDepth == -1U && !ShowParents)
+      Opts.ParentRecurseDepth = 0;
+    return Opts;
+  }
+};
+
+class DIContext {
+public:
+  enum DIContextKind {
+    CK_DWARF,
+    CK_PDB
+  };
+
+  DIContext(DIContextKind K) : Kind(K) {}
+  virtual ~DIContext() = default;
+
+  DIContextKind getKind() const { return Kind; }
+
+  virtual void dump(raw_ostream &OS, DIDumpOptions DumpOpts) = 0;
+
+  virtual bool verify(raw_ostream &OS, DIDumpOptions DumpOpts = {}) {
+    // No verifier? Just say things went well.
+    return true;
+  }
+
+  virtual DILineInfo getLineInfoForAddress(
+      object::SectionedAddress Address,
+      DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
+  virtual DILineInfoTable getLineInfoForAddressRange(
+      object::SectionedAddress Address, uint64_t Size,
+      DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
+  virtual DIInliningInfo getInliningInfoForAddress(
+      object::SectionedAddress Address,
+      DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
+
+  virtual std::vector<DILocal>
+  getLocalsForAddress(object::SectionedAddress Address) = 0;
+
+private:
+  const DIContextKind Kind;
+};
+
+/// An inferface for inquiring the load address of a loaded object file
+/// to be used by the DIContext implementations when applying relocations
+/// on the fly.
+class LoadedObjectInfo {
+protected:
+  LoadedObjectInfo() = default;
+  LoadedObjectInfo(const LoadedObjectInfo &) = default;
+
+public:
+  virtual ~LoadedObjectInfo() = default;
+
+  /// Obtain the Load Address of a section by SectionRef.
+  ///
+  /// Calculate the address of the given section.
+  /// The section need not be present in the local address space. The addresses
+  /// need to be consistent with the addresses used to query the DIContext and
+  /// the output of this function should be deterministic, i.e. repeated calls
+  /// with the same Sec should give the same address.
+  virtual uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const {
+    return 0;
+  }
+
+  /// If conveniently available, return the content of the given Section.
+  ///
+  /// When the section is available in the local address space, in relocated
+  /// (loaded) form, e.g. because it was relocated by a JIT for execution, this
+  /// function should provide the contents of said section in `Data`. If the
+  /// loaded section is not available, or the cost of retrieving it would be
+  /// prohibitive, this function should return false. In that case, relocations
+  /// will be read from the local (unrelocated) object file and applied on the
+  /// fly. Note that this method is used purely for optimzation purposes in the
+  /// common case of JITting in the local address space, so returning false
+  /// should always be correct.
+  virtual bool getLoadedSectionContents(const object::SectionRef &Sec,
+                                        StringRef &Data) const {
+    return false;
+  }
+
+  // FIXME: This is untested and unused anywhere in the LLVM project, it's
+  // used/needed by Julia (an external project). It should have some coverage
+  // (at least tests, but ideally example functionality).
+  /// Obtain a copy of this LoadedObjectInfo.
+  virtual std::unique_ptr<LoadedObjectInfo> clone() const = 0;
+};
+
+template <typename Derived, typename Base = LoadedObjectInfo>
+struct LoadedObjectInfoHelper : Base {
+protected:
+  LoadedObjectInfoHelper(const LoadedObjectInfoHelper &) = default;
+  LoadedObjectInfoHelper() = default;
+
+public:
+  template <typename... Ts>
+  LoadedObjectInfoHelper(Ts &&... Args) : Base(std::forward<Ts>(Args)...) {}
+
+  std::unique_ptr<llvm::LoadedObjectInfo> clone() const override {
+    return std::make_unique<Derived>(static_cast<const Derived &>(*this));
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DICONTEXT_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h
@@ -0,0 +1,183 @@
+//===- DWARFAbbreviationDeclaration.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H
+#define LLVM_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/DataExtractor.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+
+namespace llvm {
+
+class DWARFFormValue;
+class DWARFUnit;
+class raw_ostream;
+
+class DWARFAbbreviationDeclaration {
+public:
+  struct AttributeSpec {
+    AttributeSpec(dwarf::Attribute A, dwarf::Form F, int64_t Value)
+        : Attr(A), Form(F), Value(Value) {
+      assert(isImplicitConst());
+    }
+    AttributeSpec(dwarf::Attribute A, dwarf::Form F, Optional<uint8_t> ByteSize)
+        : Attr(A), Form(F) {
+      assert(!isImplicitConst());
+      this->ByteSize.HasByteSize = ByteSize.hasValue();
+      if (this->ByteSize.HasByteSize)
+        this->ByteSize.ByteSize = *ByteSize;
+    }
+
+    dwarf::Attribute Attr;
+    dwarf::Form Form;
+
+  private:
+    /// The following field is used for ByteSize for non-implicit_const
+    /// attributes and as value for implicit_const ones, indicated by
+    /// Form == DW_FORM_implicit_const.
+    /// The following cases are distinguished:
+    /// * Form != DW_FORM_implicit_const and HasByteSize is true:
+    ///     ByteSize contains the fixed size in bytes for the Form in this
+    ///     object.
+    /// * Form != DW_FORM_implicit_const and HasByteSize is false:
+    ///     byte size of Form either varies according to the DWARFUnit
+    ///     that it is contained in or the value size varies and must be
+    ///     decoded from the debug information in order to determine its size.
+    /// * Form == DW_FORM_implicit_const:
+    ///     Value contains value for the implicit_const attribute.
+    struct ByteSizeStorage {
+      bool HasByteSize;
+      uint8_t ByteSize;
+    };
+    union {
+      ByteSizeStorage ByteSize;
+      int64_t Value;
+    };
+
+  public:
+    bool isImplicitConst() const {
+      return Form == dwarf::DW_FORM_implicit_const;
+    }
+
+    int64_t getImplicitConstValue() const {
+      assert(isImplicitConst());
+      return Value;
+    }
+
+    /// Get the fixed byte size of this Form if possible. This function might
+    /// use the DWARFUnit to calculate the size of the Form, like for
+    /// DW_AT_address and DW_AT_ref_addr, so this isn't just an accessor for
+    /// the ByteSize member.
+    Optional<int64_t> getByteSize(const DWARFUnit &U) const;
+  };
+  using AttributeSpecVector = SmallVector<AttributeSpec, 8>;
+
+  DWARFAbbreviationDeclaration();
+
+  uint32_t getCode() const { return Code; }
+  uint8_t getCodeByteSize() const { return CodeByteSize; }
+  dwarf::Tag getTag() const { return Tag; }
+  bool hasChildren() const { return HasChildren; }
+
+  using attr_iterator_range =
+      iterator_range<AttributeSpecVector::const_iterator>;
+
+  attr_iterator_range attributes() const {
+    return attr_iterator_range(AttributeSpecs.begin(), AttributeSpecs.end());
+  }
+
+  dwarf::Form getFormByIndex(uint32_t idx) const {
+    assert(idx < AttributeSpecs.size());
+    return AttributeSpecs[idx].Form;
+  }
+
+  size_t getNumAttributes() const {
+    return AttributeSpecs.size();
+  }
+
+  dwarf::Attribute getAttrByIndex(uint32_t idx) const {
+    assert(idx < AttributeSpecs.size());
+    return AttributeSpecs[idx].Attr;
+  }
+
+  /// Get the index of the specified attribute.
+  ///
+  /// Searches the this abbreviation declaration for the index of the specified
+  /// attribute.
+  ///
+  /// \param attr DWARF attribute to search for.
+  /// \returns Optional index of the attribute if found, None otherwise.
+  Optional<uint32_t> findAttributeIndex(dwarf::Attribute attr) const;
+
+  /// Extract a DWARF form value from a DIE specified by DIE offset.
+  ///
+  /// Extract an attribute value for a DWARFUnit given the DIE offset and the
+  /// attribute.
+  ///
+  /// \param DIEOffset the DIE offset that points to the ULEB128 abbreviation
+  /// code in the .debug_info data.
+  /// \param Attr DWARF attribute to search for.
+  /// \param U the DWARFUnit the contains the DIE.
+  /// \returns Optional DWARF form value if the attribute was extracted.
+  Optional<DWARFFormValue> getAttributeValue(const uint64_t DIEOffset,
+                                             const dwarf::Attribute Attr,
+                                             const DWARFUnit &U) const;
+
+  bool extract(DataExtractor Data, uint64_t* OffsetPtr);
+  void dump(raw_ostream &OS) const;
+
+  // Return an optional byte size of all attribute data in this abbreviation
+  // if a constant byte size can be calculated given a DWARFUnit. This allows
+  // DWARF parsing to be faster as many DWARF DIEs have a fixed byte size.
+  Optional<size_t> getFixedAttributesByteSize(const DWARFUnit &U) const;
+
+private:
+  void clear();
+
+  /// A helper structure that can quickly determine the size in bytes of an
+  /// abbreviation declaration.
+  struct FixedSizeInfo {
+    /// The fixed byte size for fixed size forms.
+    uint16_t NumBytes = 0;
+    /// Number of DW_FORM_address forms in this abbrevation declaration.
+    uint8_t NumAddrs = 0;
+    /// Number of DW_FORM_ref_addr forms in this abbrevation declaration.
+    uint8_t NumRefAddrs = 0;
+    /// Number of 4 byte in DWARF32 and 8 byte in DWARF64 forms.
+    uint8_t NumDwarfOffsets = 0;
+
+    FixedSizeInfo() = default;
+
+    /// Calculate the fixed size in bytes given a DWARFUnit.
+    ///
+    /// \param U the DWARFUnit to use when determing the byte size.
+    /// \returns the size in bytes for all attribute data in this abbreviation.
+    /// The returned size does not include bytes for the  ULEB128 abbreviation
+    /// code
+    size_t getByteSize(const DWARFUnit &U) const;
+  };
+
+  uint32_t Code;
+  dwarf::Tag Tag;
+  uint8_t CodeByteSize;
+  bool HasChildren;
+  AttributeSpecVector AttributeSpecs;
+  /// If this abbreviation has a fixed byte size then FixedAttributeSize member
+  /// variable below will have a value.
+  Optional<FixedSizeInfo> FixedAttributeSize;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
@@ -0,0 +1,599 @@
+//===- DWARFAcceleratorTable.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H
+#define LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H
+
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include <cstdint>
+#include <utility>
+
+namespace llvm {
+
+class raw_ostream;
+class ScopedPrinter;
+
+/// The accelerator tables are designed to allow efficient random access
+/// (using a symbol name as a key) into debug info by providing an index of the
+/// debug info DIEs. This class implements the common functionality of Apple and
+/// DWARF 5 accelerator tables.
+/// TODO: Generalize the rest of the AppleAcceleratorTable interface and move it
+/// to this class.
+class DWARFAcceleratorTable {
+protected:
+  DWARFDataExtractor AccelSection;
+  DataExtractor StringSection;
+
+public:
+  /// An abstract class representing a single entry in the accelerator tables.
+  class Entry {
+  protected:
+    SmallVector<DWARFFormValue, 3> Values;
+
+    Entry() = default;
+
+    // Make these protected so only (final) subclasses can be copied around.
+    Entry(const Entry &) = default;
+    Entry(Entry &&) = default;
+    Entry &operator=(const Entry &) = default;
+    Entry &operator=(Entry &&) = default;
+    ~Entry() = default;
+
+
+  public:
+    /// Returns the Offset of the Compilation Unit associated with this
+    /// Accelerator Entry or None if the Compilation Unit offset is not recorded
+    /// in this Accelerator Entry.
+    virtual Optional<uint64_t> getCUOffset() const = 0;
+
+    /// Returns the Tag of the Debug Info Entry associated with this
+    /// Accelerator Entry or None if the Tag is not recorded in this
+    /// Accelerator Entry.
+    virtual Optional<dwarf::Tag> getTag() const = 0;
+
+    /// Returns the raw values of fields in the Accelerator Entry. In general,
+    /// these can only be interpreted with the help of the metadata in the
+    /// owning Accelerator Table.
+    ArrayRef<DWARFFormValue> getValues() const { return Values; }
+  };
+
+  DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection,
+                        DataExtractor StringSection)
+      : AccelSection(AccelSection), StringSection(StringSection) {}
+  virtual ~DWARFAcceleratorTable();
+
+  virtual Error extract() = 0;
+  virtual void dump(raw_ostream &OS) const = 0;
+
+  DWARFAcceleratorTable(const DWARFAcceleratorTable &) = delete;
+  void operator=(const DWARFAcceleratorTable &) = delete;
+};
+
+/// This implements the Apple accelerator table format, a precursor of the
+/// DWARF 5 accelerator table format.
+class AppleAcceleratorTable : public DWARFAcceleratorTable {
+  struct Header {
+    uint32_t Magic;
+    uint16_t Version;
+    uint16_t HashFunction;
+    uint32_t BucketCount;
+    uint32_t HashCount;
+    uint32_t HeaderDataLength;
+
+    void dump(ScopedPrinter &W) const;
+  };
+
+  struct HeaderData {
+    using AtomType = uint16_t;
+    using Form = dwarf::Form;
+
+    uint64_t DIEOffsetBase;
+    SmallVector<std::pair<AtomType, Form>, 3> Atoms;
+
+    Optional<uint64_t> extractOffset(Optional<DWARFFormValue> Value) const;
+  };
+
+  struct Header Hdr;
+  struct HeaderData HdrData;
+  bool IsValid = false;
+
+  /// Returns true if we should continue scanning for entries or false if we've
+  /// reached the last (sentinel) entry of encountered a parsing error.
+  bool dumpName(ScopedPrinter &W, SmallVectorImpl<DWARFFormValue> &AtomForms,
+                uint64_t *DataOffset) const;
+
+public:
+  /// Apple-specific implementation of an Accelerator Entry.
+  class Entry final : public DWARFAcceleratorTable::Entry {
+    const HeaderData *HdrData = nullptr;
+
+    Entry(const HeaderData &Data);
+    Entry() = default;
+
+    void extract(const AppleAcceleratorTable &AccelTable, uint64_t *Offset);
+
+  public:
+    Optional<uint64_t> getCUOffset() const override;
+
+    /// Returns the Section Offset of the Debug Info Entry associated with this
+    /// Accelerator Entry or None if the DIE offset is not recorded in this
+    /// Accelerator Entry. The returned offset is relative to the start of the
+    /// Section containing the DIE.
+    Optional<uint64_t> getDIESectionOffset() const;
+
+    Optional<dwarf::Tag> getTag() const override;
+
+    /// Returns the value of the Atom in this Accelerator Entry, if the Entry
+    /// contains such Atom.
+    Optional<DWARFFormValue> lookup(HeaderData::AtomType Atom) const;
+
+    friend class AppleAcceleratorTable;
+    friend class ValueIterator;
+  };
+
+  class ValueIterator : public std::iterator<std::input_iterator_tag, Entry> {
+    const AppleAcceleratorTable *AccelTable = nullptr;
+    Entry Current;           ///< The current entry.
+    uint64_t DataOffset = 0; ///< Offset into the section.
+    unsigned Data = 0; ///< Current data entry.
+    unsigned NumData = 0; ///< Number of data entries.
+
+    /// Advance the iterator.
+    void Next();
+  public:
+    /// Construct a new iterator for the entries at \p DataOffset.
+    ValueIterator(const AppleAcceleratorTable &AccelTable, uint64_t DataOffset);
+    /// End marker.
+    ValueIterator() = default;
+
+    const Entry &operator*() const { return Current; }
+    ValueIterator &operator++() { Next(); return *this; }
+    ValueIterator operator++(int) {
+      ValueIterator I = *this;
+      Next();
+      return I;
+    }
+    friend bool operator==(const ValueIterator &A, const ValueIterator &B) {
+      return A.NumData == B.NumData && A.DataOffset == B.DataOffset;
+    }
+    friend bool operator!=(const ValueIterator &A, const ValueIterator &B) {
+      return !(A == B);
+    }
+  };
+
+  AppleAcceleratorTable(const DWARFDataExtractor &AccelSection,
+                        DataExtractor StringSection)
+      : DWARFAcceleratorTable(AccelSection, StringSection) {}
+
+  Error extract() override;
+  uint32_t getNumBuckets();
+  uint32_t getNumHashes();
+  uint32_t getSizeHdr();
+  uint32_t getHeaderDataLength();
+
+  /// Return the Atom description, which can be used to interpret the raw values
+  /// of the Accelerator Entries in this table.
+  ArrayRef<std::pair<HeaderData::AtomType, HeaderData::Form>> getAtomsDesc();
+  bool validateForms();
+
+  /// Return information related to the DWARF DIE we're looking for when
+  /// performing a lookup by name.
+  ///
+  /// \param HashDataOffset an offset into the hash data table
+  /// \returns <DieOffset, DieTag>
+  /// DieOffset is the offset into the .debug_info section for the DIE
+  /// related to the input hash data offset.
+  /// DieTag is the tag of the DIE
+  std::pair<uint64_t, dwarf::Tag> readAtoms(uint64_t *HashDataOffset);
+  void dump(raw_ostream &OS) const override;
+
+  /// Look up all entries in the accelerator table matching \c Key.
+  iterator_range<ValueIterator> equal_range(StringRef Key) const;
+};
+
+/// .debug_names section consists of one or more units. Each unit starts with a
+/// header, which is followed by a list of compilation units, local and foreign
+/// type units.
+///
+/// These may be followed by an (optional) hash lookup table, which consists of
+/// an array of buckets and hashes similar to the apple tables above. The only
+/// difference is that the hashes array is 1-based, and consequently an empty
+/// bucket is denoted by 0 and not UINT32_MAX.
+///
+/// Next is the name table, which consists of an array of names and array of
+/// entry offsets. This is different from the apple tables, which store names
+/// next to the actual entries.
+///
+/// The structure of the entries is described by an abbreviations table, which
+/// comes after the name table. Unlike the apple tables, which have a uniform
+/// entry structure described in the header, each .debug_names entry may have
+/// different index attributes (DW_IDX_???) attached to it.
+///
+/// The last segment consists of a list of entries, which is a 0-terminated list
+/// referenced by the name table and interpreted with the help of the
+/// abbreviation table.
+class DWARFDebugNames : public DWARFAcceleratorTable {
+  /// The fixed-size part of a DWARF v5 Name Index header
+  struct HeaderPOD {
+    uint32_t UnitLength;
+    uint16_t Version;
+    uint16_t Padding;
+    uint32_t CompUnitCount;
+    uint32_t LocalTypeUnitCount;
+    uint32_t ForeignTypeUnitCount;
+    uint32_t BucketCount;
+    uint32_t NameCount;
+    uint32_t AbbrevTableSize;
+    uint32_t AugmentationStringSize;
+  };
+
+public:
+  class NameIndex;
+  class NameIterator;
+  class ValueIterator;
+
+  /// DWARF v5 Name Index header.
+  struct Header : public HeaderPOD {
+    SmallString<8> AugmentationString;
+
+    Error extract(const DWARFDataExtractor &AS, uint64_t *Offset);
+    void dump(ScopedPrinter &W) const;
+  };
+
+  /// Index attribute and its encoding.
+  struct AttributeEncoding {
+    dwarf::Index Index;
+    dwarf::Form Form;
+
+    constexpr AttributeEncoding(dwarf::Index Index, dwarf::Form Form)
+        : Index(Index), Form(Form) {}
+
+    friend bool operator==(const AttributeEncoding &LHS,
+                           const AttributeEncoding &RHS) {
+      return LHS.Index == RHS.Index && LHS.Form == RHS.Form;
+    }
+  };
+
+  /// Abbreviation describing the encoding of Name Index entries.
+  struct Abbrev {
+    uint32_t Code;  ///< Abbreviation code
+    dwarf::Tag Tag; ///< Dwarf Tag of the described entity.
+    std::vector<AttributeEncoding> Attributes; ///< List of index attributes.
+
+    Abbrev(uint32_t Code, dwarf::Tag Tag,
+           std::vector<AttributeEncoding> Attributes)
+        : Code(Code), Tag(Tag), Attributes(std::move(Attributes)) {}
+
+    void dump(ScopedPrinter &W) const;
+  };
+
+  /// DWARF v5-specific implementation of an Accelerator Entry.
+  class Entry final : public DWARFAcceleratorTable::Entry {
+    const NameIndex *NameIdx;
+    const Abbrev *Abbr;
+
+    Entry(const NameIndex &NameIdx, const Abbrev &Abbr);
+
+  public:
+    Optional<uint64_t> getCUOffset() const override;
+    Optional<dwarf::Tag> getTag() const override { return tag(); }
+
+    /// Returns the Index into the Compilation Unit list of the owning Name
+    /// Index or None if this Accelerator Entry does not have an associated
+    /// Compilation Unit. It is up to the user to verify that the returned Index
+    /// is valid in the owning NameIndex (or use getCUOffset(), which will
+    /// handle that check itself). Note that entries in NameIndexes which index
+    /// just a single Compilation Unit are implicitly associated with that unit,
+    /// so this function will return 0 even without an explicit
+    /// DW_IDX_compile_unit attribute.
+    Optional<uint64_t> getCUIndex() const;
+
+    /// .debug_names-specific getter, which always succeeds (DWARF v5 index
+    /// entries always have a tag).
+    dwarf::Tag tag() const { return Abbr->Tag; }
+
+    /// Returns the Offset of the DIE within the containing CU or TU.
+    Optional<uint64_t> getDIEUnitOffset() const;
+
+    /// Return the Abbreviation that can be used to interpret the raw values of
+    /// this Accelerator Entry.
+    const Abbrev &getAbbrev() const { return *Abbr; }
+
+    /// Returns the value of the Index Attribute in this Accelerator Entry, if
+    /// the Entry contains such Attribute.
+    Optional<DWARFFormValue> lookup(dwarf::Index Index) const;
+
+    void dump(ScopedPrinter &W) const;
+
+    friend class NameIndex;
+    friend class ValueIterator;
+  };
+
+  /// Error returned by NameIndex::getEntry to report it has reached the end of
+  /// the entry list.
+  class SentinelError : public ErrorInfo<SentinelError> {
+  public:
+    static char ID;
+
+    void log(raw_ostream &OS) const override { OS << "Sentinel"; }
+    std::error_code convertToErrorCode() const override;
+  };
+
+private:
+  /// DenseMapInfo for struct Abbrev.
+  struct AbbrevMapInfo {
+    static Abbrev getEmptyKey();
+    static Abbrev getTombstoneKey();
+    static unsigned getHashValue(uint32_t Code) {
+      return DenseMapInfo<uint32_t>::getHashValue(Code);
+    }
+    static unsigned getHashValue(const Abbrev &Abbr) {
+      return getHashValue(Abbr.Code);
+    }
+    static bool isEqual(uint32_t LHS, const Abbrev &RHS) {
+      return LHS == RHS.Code;
+    }
+    static bool isEqual(const Abbrev &LHS, const Abbrev &RHS) {
+      return LHS.Code == RHS.Code;
+    }
+  };
+
+public:
+  /// A single entry in the Name Table (DWARF v5 sect. 6.1.1.4.6) of the Name
+  /// Index.
+  class NameTableEntry {
+    DataExtractor StrData;
+
+    uint32_t Index;
+    uint64_t StringOffset;
+    uint64_t EntryOffset;
+
+  public:
+    NameTableEntry(const DataExtractor &StrData, uint32_t Index,
+                   uint64_t StringOffset, uint64_t EntryOffset)
+        : StrData(StrData), Index(Index), StringOffset(StringOffset),
+          EntryOffset(EntryOffset) {}
+
+    /// Return the index of this name in the parent Name Index.
+    uint32_t getIndex() const { return Index; }
+
+    /// Returns the offset of the name of the described entities.
+    uint64_t getStringOffset() const { return StringOffset; }
+
+    /// Return the string referenced by this name table entry or nullptr if the
+    /// string offset is not valid.
+    const char *getString() const {
+      uint64_t Off = StringOffset;
+      return StrData.getCStr(&Off);
+    }
+
+    /// Returns the offset of the first Entry in the list.
+    uint64_t getEntryOffset() const { return EntryOffset; }
+  };
+
+  /// Represents a single accelerator table within the DWARF v5 .debug_names
+  /// section.
+  class NameIndex {
+    DenseSet<Abbrev, AbbrevMapInfo> Abbrevs;
+    struct Header Hdr;
+    const DWARFDebugNames &Section;
+
+    // Base of the whole unit and of various important tables, as offsets from
+    // the start of the section.
+    uint64_t Base;
+    uint64_t CUsBase;
+    uint64_t BucketsBase;
+    uint64_t HashesBase;
+    uint64_t StringOffsetsBase;
+    uint64_t EntryOffsetsBase;
+    uint64_t EntriesBase;
+
+    void dumpCUs(ScopedPrinter &W) const;
+    void dumpLocalTUs(ScopedPrinter &W) const;
+    void dumpForeignTUs(ScopedPrinter &W) const;
+    void dumpAbbreviations(ScopedPrinter &W) const;
+    bool dumpEntry(ScopedPrinter &W, uint64_t *Offset) const;
+    void dumpName(ScopedPrinter &W, const NameTableEntry &NTE,
+                  Optional<uint32_t> Hash) const;
+    void dumpBucket(ScopedPrinter &W, uint32_t Bucket) const;
+
+    Expected<AttributeEncoding> extractAttributeEncoding(uint64_t *Offset);
+
+    Expected<std::vector<AttributeEncoding>>
+    extractAttributeEncodings(uint64_t *Offset);
+
+    Expected<Abbrev> extractAbbrev(uint64_t *Offset);
+
+  public:
+    NameIndex(const DWARFDebugNames &Section, uint64_t Base)
+        : Section(Section), Base(Base) {}
+
+    /// Reads offset of compilation unit CU. CU is 0-based.
+    uint64_t getCUOffset(uint32_t CU) const;
+    uint32_t getCUCount() const { return Hdr.CompUnitCount; }
+
+    /// Reads offset of local type unit TU, TU is 0-based.
+    uint64_t getLocalTUOffset(uint32_t TU) const;
+    uint32_t getLocalTUCount() const { return Hdr.LocalTypeUnitCount; }
+
+    /// Reads signature of foreign type unit TU. TU is 0-based.
+    uint64_t getForeignTUSignature(uint32_t TU) const;
+    uint32_t getForeignTUCount() const { return Hdr.ForeignTypeUnitCount; }
+
+    /// Reads an entry in the Bucket Array for the given Bucket. The returned
+    /// value is a (1-based) index into the Names, StringOffsets and
+    /// EntryOffsets arrays. The input Bucket index is 0-based.
+    uint32_t getBucketArrayEntry(uint32_t Bucket) const;
+    uint32_t getBucketCount() const { return Hdr.BucketCount; }
+
+    /// Reads an entry in the Hash Array for the given Index. The input Index
+    /// is 1-based.
+    uint32_t getHashArrayEntry(uint32_t Index) const;
+
+    /// Reads an entry in the Name Table for the given Index. The Name Table
+    /// consists of two arrays -- String Offsets and Entry Offsets. The returned
+    /// offsets are relative to the starts of respective sections. Input Index
+    /// is 1-based.
+    NameTableEntry getNameTableEntry(uint32_t Index) const;
+
+    uint32_t getNameCount() const { return Hdr.NameCount; }
+
+    const DenseSet<Abbrev, AbbrevMapInfo> &getAbbrevs() const {
+      return Abbrevs;
+    }
+
+    Expected<Entry> getEntry(uint64_t *Offset) const;
+
+    /// Look up all entries in this Name Index matching \c Key.
+    iterator_range<ValueIterator> equal_range(StringRef Key) const;
+
+    NameIterator begin() const { return NameIterator(this, 1); }
+    NameIterator end() const { return NameIterator(this, getNameCount() + 1); }
+
+    Error extract();
+    uint64_t getUnitOffset() const { return Base; }
+    uint64_t getNextUnitOffset() const { return Base + 4 + Hdr.UnitLength; }
+    void dump(ScopedPrinter &W) const;
+
+    friend class DWARFDebugNames;
+  };
+
+  class ValueIterator : public std::iterator<std::input_iterator_tag, Entry> {
+
+    /// The Name Index we are currently iterating through. The implementation
+    /// relies on the fact that this can also be used as an iterator into the
+    /// "NameIndices" vector in the Accelerator section.
+    const NameIndex *CurrentIndex = nullptr;
+
+    /// Whether this is a local iterator (searches in CurrentIndex only) or not
+    /// (searches all name indices).
+    bool IsLocal;
+
+    Optional<Entry> CurrentEntry;
+    uint64_t DataOffset = 0; ///< Offset into the section.
+    std::string Key;         ///< The Key we are searching for.
+    Optional<uint32_t> Hash; ///< Hash of Key, if it has been computed.
+
+    bool getEntryAtCurrentOffset();
+    Optional<uint64_t> findEntryOffsetInCurrentIndex();
+    bool findInCurrentIndex();
+    void searchFromStartOfCurrentIndex();
+    void next();
+
+    /// Set the iterator to the "end" state.
+    void setEnd() { *this = ValueIterator(); }
+
+  public:
+    /// Create a "begin" iterator for looping over all entries in the
+    /// accelerator table matching Key. The iterator will run through all Name
+    /// Indexes in the section in sequence.
+    ValueIterator(const DWARFDebugNames &AccelTable, StringRef Key);
+
+    /// Create a "begin" iterator for looping over all entries in a specific
+    /// Name Index. Other indices in the section will not be visited.
+    ValueIterator(const NameIndex &NI, StringRef Key);
+
+    /// End marker.
+    ValueIterator() = default;
+
+    const Entry &operator*() const { return *CurrentEntry; }
+    ValueIterator &operator++() {
+      next();
+      return *this;
+    }
+    ValueIterator operator++(int) {
+      ValueIterator I = *this;
+      next();
+      return I;
+    }
+
+    friend bool operator==(const ValueIterator &A, const ValueIterator &B) {
+      return A.CurrentIndex == B.CurrentIndex && A.DataOffset == B.DataOffset;
+    }
+    friend bool operator!=(const ValueIterator &A, const ValueIterator &B) {
+      return !(A == B);
+    }
+  };
+
+  class NameIterator {
+
+    /// The Name Index we are iterating through.
+    const NameIndex *CurrentIndex;
+
+    /// The current name in the Name Index.
+    uint32_t CurrentName;
+
+    void next() {
+      assert(CurrentName <= CurrentIndex->getNameCount());
+      ++CurrentName;
+    }
+
+  public:
+    using iterator_category = std::input_iterator_tag;
+    using value_type = NameTableEntry;
+    using difference_type = uint32_t;
+    using pointer = NameTableEntry *;
+    using reference = NameTableEntry; // We return entries by value.
+
+    /// Creates an iterator whose initial position is name CurrentName in
+    /// CurrentIndex.
+    NameIterator(const NameIndex *CurrentIndex, uint32_t CurrentName)
+        : CurrentIndex(CurrentIndex), CurrentName(CurrentName) {}
+
+    NameTableEntry operator*() const {
+      return CurrentIndex->getNameTableEntry(CurrentName);
+    }
+    NameIterator &operator++() {
+      next();
+      return *this;
+    }
+    NameIterator operator++(int) {
+      NameIterator I = *this;
+      next();
+      return I;
+    }
+
+    friend bool operator==(const NameIterator &A, const NameIterator &B) {
+      return A.CurrentIndex == B.CurrentIndex && A.CurrentName == B.CurrentName;
+    }
+    friend bool operator!=(const NameIterator &A, const NameIterator &B) {
+      return !(A == B);
+    }
+  };
+
+private:
+  SmallVector<NameIndex, 0> NameIndices;
+  DenseMap<uint64_t, const NameIndex *> CUToNameIndex;
+
+public:
+  DWARFDebugNames(const DWARFDataExtractor &AccelSection,
+                  DataExtractor StringSection)
+      : DWARFAcceleratorTable(AccelSection, StringSection) {}
+
+  Error extract() override;
+  void dump(raw_ostream &OS) const override;
+
+  /// Look up all entries in the accelerator table matching \c Key.
+  iterator_range<ValueIterator> equal_range(StringRef Key) const;
+
+  using const_iterator = SmallVector<NameIndex, 0>::const_iterator;
+  const_iterator begin() const { return NameIndices.begin(); }
+  const_iterator end() const { return NameIndices.end(); }
+
+  /// Return the Name Index covering the compile unit at CUOffset, or nullptr if
+  /// there is no Name Index covering that unit.
+  const NameIndex *getCUNameIndex(uint64_t CUOffset);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h
@@ -0,0 +1,61 @@
+//===- DWARFAddressRange.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFADDRESSRANGE_H
+#define LLVM_DEBUGINFO_DWARF_DWARFADDRESSRANGE_H
+
+#include "llvm/DebugInfo/DIContext.h"
+#include <cstdint>
+#include <tuple>
+#include <vector>
+
+namespace llvm {
+
+class raw_ostream;
+
+struct DWARFAddressRange {
+  uint64_t LowPC;
+  uint64_t HighPC;
+  uint64_t SectionIndex;
+
+  DWARFAddressRange() = default;
+
+  /// Used for unit testing.
+  DWARFAddressRange(uint64_t LowPC, uint64_t HighPC, uint64_t SectionIndex = 0)
+      : LowPC(LowPC), HighPC(HighPC), SectionIndex(SectionIndex) {}
+
+  /// Returns true if LowPC is smaller or equal to HighPC. This accounts for
+  /// dead-stripped ranges.
+  bool valid() const { return LowPC <= HighPC; }
+
+  /// Returns true if [LowPC, HighPC) intersects with [RHS.LowPC, RHS.HighPC).
+  bool intersects(const DWARFAddressRange &RHS) const {
+    assert(valid() && RHS.valid());
+    // Empty ranges can't intersect.
+    if (LowPC == HighPC || RHS.LowPC == RHS.HighPC)
+      return false;
+    return LowPC < RHS.HighPC && RHS.LowPC < HighPC;
+  }
+
+  void dump(raw_ostream &OS, uint32_t AddressSize,
+            DIDumpOptions DumpOpts = {}) const;
+};
+
+static inline bool operator<(const DWARFAddressRange &LHS,
+                             const DWARFAddressRange &RHS) {
+  return std::tie(LHS.LowPC, LHS.HighPC) < std::tie(RHS.LowPC, RHS.HighPC);
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const DWARFAddressRange &R);
+
+/// DWARFAddressRangesVector - represents a set of absolute address ranges.
+using DWARFAddressRangesVector = std::vector<DWARFAddressRange>;
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFADDRESSRANGE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAttribute.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAttribute.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAttribute.h
@@ -0,0 +1,49 @@
+//===- DWARFAttribute.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFATTRIBUTE_H
+#define LLVM_DEBUGINFO_DWARFATTRIBUTE_H
+
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include <cstdint>
+
+namespace llvm {
+
+//===----------------------------------------------------------------------===//
+/// Encapsulates a DWARF attribute value and all of the data required to
+/// describe the attribute value.
+///
+/// This class is designed to be used by clients that want to iterate across all
+/// attributes in a DWARFDie.
+struct DWARFAttribute {
+  /// The debug info/types offset for this attribute.
+  uint64_t Offset = 0;
+  /// The debug info/types section byte size of the data for this attribute.
+  uint32_t ByteSize = 0;
+  /// The attribute enumeration of this attribute.
+  dwarf::Attribute Attr = dwarf::Attribute(0);
+  /// The form and value for this attribute.
+  DWARFFormValue Value;
+
+  bool isValid() const {
+    return Offset != 0 && Attr != dwarf::Attribute(0);
+  }
+
+  explicit operator bool() const {
+    return isValid();
+  }
+
+  /// Identifies DWARF attributes that may contain a reference to a
+  /// DWARF expression.
+  static bool mayHaveLocationDescription(dwarf::Attribute Attr);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARFATTRIBUTE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h
@@ -0,0 +1,38 @@
+//===- DWARFCompileUnit.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H
+#define LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H
+
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
+
+namespace llvm {
+
+class DWARFCompileUnit : public DWARFUnit {
+public:
+  DWARFCompileUnit(DWARFContext &Context, const DWARFSection &Section,
+                   const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA,
+                   const DWARFSection *RS, const DWARFSection *LocSection,
+                   StringRef SS, const DWARFSection &SOS,
+                   const DWARFSection *AOS, const DWARFSection &LS, bool LE,
+                   bool IsDWO, const DWARFUnitVector &UnitVector)
+      : DWARFUnit(Context, Section, Header, DA, RS, LocSection, SS, SOS, AOS,
+                  LS, LE, IsDWO, UnitVector) {}
+
+  /// VTable anchor.
+  ~DWARFCompileUnit() override;
+  /// Dump this compile unit to \p OS.
+  void dump(raw_ostream &OS, DIDumpOptions DumpOpts) override;
+  /// Enable LLVM-style RTTI.
+  static bool classof(const DWARFUnit *U) { return !U->isTypeUnit(); }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFContext.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFContext.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFContext.h
@@ -0,0 +1,382 @@
+//===- DWARFContext.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===/
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H
+#define LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H
+
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h"
+#include "llvm/DebugInfo/DWARF/DWARFObject.h"
+#include "llvm/DebugInfo/DWARF/DWARFSection.h"
+#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Host.h"
+#include <cstdint>
+#include <deque>
+#include <map>
+#include <memory>
+
+namespace llvm {
+
+class MCRegisterInfo;
+class MemoryBuffer;
+class raw_ostream;
+
+/// Used as a return value for a error callback passed to DWARF context.
+/// Callback should return Halt if client application wants to stop
+/// object parsing, or should return Continue otherwise.
+enum class ErrorPolicy { Halt, Continue };
+
+/// DWARFContext
+/// This data structure is the top level entity that deals with dwarf debug
+/// information parsing. The actual data is supplied through DWARFObj.
+class DWARFContext : public DIContext {
+  DWARFUnitVector NormalUnits;
+  std::unique_ptr<DWARFUnitIndex> CUIndex;
+  std::unique_ptr<DWARFGdbIndex> GdbIndex;
+  std::unique_ptr<DWARFUnitIndex> TUIndex;
+  std::unique_ptr<DWARFDebugAbbrev> Abbrev;
+  std::unique_ptr<DWARFDebugLoc> Loc;
+  std::unique_ptr<DWARFDebugAranges> Aranges;
+  std::unique_ptr<DWARFDebugLine> Line;
+  std::unique_ptr<DWARFDebugFrame> DebugFrame;
+  std::unique_ptr<DWARFDebugFrame> EHFrame;
+  std::unique_ptr<DWARFDebugMacro> Macro;
+  std::unique_ptr<DWARFDebugNames> Names;
+  std::unique_ptr<AppleAcceleratorTable> AppleNames;
+  std::unique_ptr<AppleAcceleratorTable> AppleTypes;
+  std::unique_ptr<AppleAcceleratorTable> AppleNamespaces;
+  std::unique_ptr<AppleAcceleratorTable> AppleObjC;
+
+  DWARFUnitVector DWOUnits;
+  std::unique_ptr<DWARFDebugAbbrev> AbbrevDWO;
+
+  /// The maximum DWARF version of all units.
+  unsigned MaxVersion = 0;
+
+  struct DWOFile {
+    object::OwningBinary<object::ObjectFile> File;
+    std::unique_ptr<DWARFContext> Context;
+  };
+  StringMap<std::weak_ptr<DWOFile>> DWOFiles;
+  std::weak_ptr<DWOFile> DWP;
+  bool CheckedForDWP = false;
+  std::string DWPName;
+
+  std::unique_ptr<MCRegisterInfo> RegInfo;
+
+  /// Read compile units from the debug_info section (if necessary)
+  /// and type units from the debug_types sections (if necessary)
+  /// and store them in NormalUnits.
+  void parseNormalUnits();
+
+  /// Read compile units from the debug_info.dwo section (if necessary)
+  /// and type units from the debug_types.dwo section (if necessary)
+  /// and store them in DWOUnits.
+  /// If \p Lazy is true, set up to parse but don't actually parse them.
+  enum { EagerParse = false, LazyParse = true };
+  void parseDWOUnits(bool Lazy = false);
+
+  std::unique_ptr<const DWARFObject> DObj;
+
+public:
+  DWARFContext(std::unique_ptr<const DWARFObject> DObj,
+               std::string DWPName = "");
+  ~DWARFContext();
+
+  DWARFContext(DWARFContext &) = delete;
+  DWARFContext &operator=(DWARFContext &) = delete;
+
+  const DWARFObject &getDWARFObj() const { return *DObj; }
+
+  static bool classof(const DIContext *DICtx) {
+    return DICtx->getKind() == CK_DWARF;
+  }
+
+  /// Dump a textual representation to \p OS. If any \p DumpOffsets are present,
+  /// dump only the record at the specified offset.
+  void dump(raw_ostream &OS, DIDumpOptions DumpOpts,
+            std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets);
+
+  void dump(raw_ostream &OS, DIDumpOptions DumpOpts) override {
+    std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets;
+    dump(OS, DumpOpts, DumpOffsets);
+  }
+
+  bool verify(raw_ostream &OS, DIDumpOptions DumpOpts = {}) override;
+
+  using unit_iterator_range = DWARFUnitVector::iterator_range;
+
+  /// Get units from .debug_info in this context.
+  unit_iterator_range info_section_units() {
+    parseNormalUnits();
+    return unit_iterator_range(NormalUnits.begin(),
+                               NormalUnits.begin() +
+                                   NormalUnits.getNumInfoUnits());
+  }
+
+  /// Get units from .debug_types in this context.
+  unit_iterator_range types_section_units() {
+    parseNormalUnits();
+    return unit_iterator_range(
+        NormalUnits.begin() + NormalUnits.getNumInfoUnits(), NormalUnits.end());
+  }
+
+  /// Get compile units in this context.
+  unit_iterator_range compile_units() { return info_section_units(); }
+
+  /// Get type units in this context.
+  unit_iterator_range type_units() { return types_section_units(); }
+
+  /// Get all normal compile/type units in this context.
+  unit_iterator_range normal_units() {
+    parseNormalUnits();
+    return unit_iterator_range(NormalUnits.begin(), NormalUnits.end());
+  }
+
+  /// Get units from .debug_info..dwo in the DWO context.
+  unit_iterator_range dwo_info_section_units() {
+    parseDWOUnits();
+    return unit_iterator_range(DWOUnits.begin(),
+                               DWOUnits.begin() + DWOUnits.getNumInfoUnits());
+  }
+
+  /// Get units from .debug_types.dwo in the DWO context.
+  unit_iterator_range dwo_types_section_units() {
+    parseDWOUnits();
+    return unit_iterator_range(DWOUnits.begin() + DWOUnits.getNumInfoUnits(),
+                               DWOUnits.end());
+  }
+
+  /// Get compile units in the DWO context.
+  unit_iterator_range dwo_compile_units() { return dwo_info_section_units(); }
+
+  /// Get type units in the DWO context.
+  unit_iterator_range dwo_type_units() { return dwo_types_section_units(); }
+
+  /// Get all units in the DWO context.
+  unit_iterator_range dwo_units() {
+    parseDWOUnits();
+    return unit_iterator_range(DWOUnits.begin(), DWOUnits.end());
+  }
+
+  /// Get the number of compile units in this context.
+  unsigned getNumCompileUnits() {
+    parseNormalUnits();
+    return NormalUnits.getNumInfoUnits();
+  }
+
+  /// Get the number of type units in this context.
+  unsigned getNumTypeUnits() {
+    parseNormalUnits();
+    return NormalUnits.getNumTypesUnits();
+  }
+
+  /// Get the number of compile units in the DWO context.
+  unsigned getNumDWOCompileUnits() {
+    parseDWOUnits();
+    return DWOUnits.getNumInfoUnits();
+  }
+
+  /// Get the number of type units in the DWO context.
+  unsigned getNumDWOTypeUnits() {
+    parseDWOUnits();
+    return DWOUnits.getNumTypesUnits();
+  }
+
+  /// Get the unit at the specified index.
+  DWARFUnit *getUnitAtIndex(unsigned index) {
+    parseNormalUnits();
+    return NormalUnits[index].get();
+  }
+
+  /// Get the unit at the specified index for the DWO units.
+  DWARFUnit *getDWOUnitAtIndex(unsigned index) {
+    parseDWOUnits();
+    return DWOUnits[index].get();
+  }
+
+  DWARFCompileUnit *getDWOCompileUnitForHash(uint64_t Hash);
+
+  /// Return the compile unit that includes an offset (relative to .debug_info).
+  DWARFCompileUnit *getCompileUnitForOffset(uint64_t Offset);
+
+  /// Get a DIE given an exact offset.
+  DWARFDie getDIEForOffset(uint64_t Offset);
+
+  unsigned getMaxVersion() {
+    // Ensure info units have been parsed to discover MaxVersion
+    info_section_units();
+    return MaxVersion;
+  }
+
+  unsigned getMaxDWOVersion() {
+    // Ensure DWO info units have been parsed to discover MaxVersion
+    dwo_info_section_units();
+    return MaxVersion;
+  }
+
+  void setMaxVersionIfGreater(unsigned Version) {
+    if (Version > MaxVersion)
+      MaxVersion = Version;
+  }
+
+  const DWARFUnitIndex &getCUIndex();
+  DWARFGdbIndex &getGdbIndex();
+  const DWARFUnitIndex &getTUIndex();
+
+  /// Get a pointer to the parsed DebugAbbrev object.
+  const DWARFDebugAbbrev *getDebugAbbrev();
+
+  /// Get a pointer to the parsed DebugLoc object.
+  const DWARFDebugLoc *getDebugLoc();
+
+  /// Get a pointer to the parsed dwo abbreviations object.
+  const DWARFDebugAbbrev *getDebugAbbrevDWO();
+
+  /// Get a pointer to the parsed DebugAranges object.
+  const DWARFDebugAranges *getDebugAranges();
+
+  /// Get a pointer to the parsed frame information object.
+  const DWARFDebugFrame *getDebugFrame();
+
+  /// Get a pointer to the parsed eh frame information object.
+  const DWARFDebugFrame *getEHFrame();
+
+  /// Get a pointer to the parsed DebugMacro object.
+  const DWARFDebugMacro *getDebugMacro();
+
+  /// Get a reference to the parsed accelerator table object.
+  const DWARFDebugNames &getDebugNames();
+
+  /// Get a reference to the parsed accelerator table object.
+  const AppleAcceleratorTable &getAppleNames();
+
+  /// Get a reference to the parsed accelerator table object.
+  const AppleAcceleratorTable &getAppleTypes();
+
+  /// Get a reference to the parsed accelerator table object.
+  const AppleAcceleratorTable &getAppleNamespaces();
+
+  /// Get a reference to the parsed accelerator table object.
+  const AppleAcceleratorTable &getAppleObjC();
+
+  /// Get a pointer to a parsed line table corresponding to a compile unit.
+  /// Report any parsing issues as warnings on stderr.
+  const DWARFDebugLine::LineTable *getLineTableForUnit(DWARFUnit *U);
+
+  /// Get a pointer to a parsed line table corresponding to a compile unit.
+  /// Report any recoverable parsing problems using the callback.
+  Expected<const DWARFDebugLine::LineTable *>
+  getLineTableForUnit(DWARFUnit *U,
+                      std::function<void(Error)> RecoverableErrorCallback);
+
+  DataExtractor getStringExtractor() const {
+    return DataExtractor(DObj->getStrSection(), false, 0);
+  }
+  DataExtractor getLineStringExtractor() const {
+    return DataExtractor(DObj->getLineStrSection(), false, 0);
+  }
+
+  /// Wraps the returned DIEs for a given address.
+  struct DIEsForAddress {
+    DWARFCompileUnit *CompileUnit = nullptr;
+    DWARFDie FunctionDIE;
+    DWARFDie BlockDIE;
+    explicit operator bool() const { return CompileUnit != nullptr; }
+  };
+
+  /// Get the compilation unit, the function DIE and lexical block DIE for the
+  /// given address where applicable.
+  /// TODO: change input parameter from "uint64_t Address"
+  ///       into "SectionedAddress Address"
+  DIEsForAddress getDIEsForAddress(uint64_t Address);
+
+  DILineInfo getLineInfoForAddress(
+      object::SectionedAddress Address,
+      DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
+  DILineInfoTable getLineInfoForAddressRange(
+      object::SectionedAddress Address, uint64_t Size,
+      DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
+  DIInliningInfo getInliningInfoForAddress(
+      object::SectionedAddress Address,
+      DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
+
+  std::vector<DILocal>
+  getLocalsForAddress(object::SectionedAddress Address) override;
+
+  bool isLittleEndian() const { return DObj->isLittleEndian(); }
+  static bool isSupportedVersion(unsigned version) {
+    return version == 2 || version == 3 || version == 4 || version == 5;
+  }
+
+  std::shared_ptr<DWARFContext> getDWOContext(StringRef AbsolutePath);
+
+  const MCRegisterInfo *getRegisterInfo() const { return RegInfo.get(); }
+
+  /// Function used to handle default error reporting policy. Prints a error
+  /// message and returns Continue, so DWARF context ignores the error.
+  static ErrorPolicy defaultErrorHandler(Error E);
+  static std::unique_ptr<DWARFContext>
+  create(const object::ObjectFile &Obj, const LoadedObjectInfo *L = nullptr,
+         function_ref<ErrorPolicy(Error)> HandleError = defaultErrorHandler,
+         std::string DWPName = "");
+
+  static std::unique_ptr<DWARFContext>
+  create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
+         uint8_t AddrSize, bool isLittleEndian = sys::IsLittleEndianHost);
+
+  /// Loads register info for the architecture of the provided object file.
+  /// Improves readability of dumped DWARF expressions. Requires the caller to
+  /// have initialized the relevant target descriptions.
+  Error loadRegisterInfo(const object::ObjectFile &Obj);
+
+  /// Get address size from CUs.
+  /// TODO: refactor compile_units() to make this const.
+  uint8_t getCUAddrSize();
+
+  /// Dump Error as warning message to stderr.
+  static void dumpWarning(Error Warning);
+
+  Triple::ArchType getArch() const {
+    return getDWARFObj().getFile()->getArch();
+  }
+
+private:
+  /// Return the compile unit which contains instruction with provided
+  /// address.
+  /// TODO: change input parameter from "uint64_t Address"
+  ///       into "SectionedAddress Address"
+  DWARFCompileUnit *getCompileUnitForAddress(uint64_t Address);
+  void addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, DWARFDie Die,
+                       std::vector<DILocal> &Result);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h
@@ -0,0 +1,64 @@
+//===- DWARFDataExtractor.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFDATAEXTRACTOR_H
+#define LLVM_DEBUGINFO_DWARFDATAEXTRACTOR_H
+
+#include "llvm/DebugInfo/DWARF/DWARFSection.h"
+#include "llvm/Support/DataExtractor.h"
+
+namespace llvm {
+class DWARFObject;
+
+/// A DataExtractor (typically for an in-memory copy of an object-file section)
+/// plus a relocation map for that section, if there is one.
+class DWARFDataExtractor : public DataExtractor {
+  const DWARFObject *Obj = nullptr;
+  const DWARFSection *Section = nullptr;
+
+public:
+  /// Constructor for the normal case of extracting data from a DWARF section.
+  /// The DWARFSection's lifetime must be at least as long as the extractor's.
+  DWARFDataExtractor(const DWARFObject &Obj, const DWARFSection &Section,
+                     bool IsLittleEndian, uint8_t AddressSize)
+      : DataExtractor(Section.Data, IsLittleEndian, AddressSize), Obj(&Obj),
+        Section(&Section) {}
+
+  /// Constructor for cases when there are no relocations.
+  DWARFDataExtractor(StringRef Data, bool IsLittleEndian, uint8_t AddressSize)
+    : DataExtractor(Data, IsLittleEndian, AddressSize) {}
+
+  /// Extracts a value and applies a relocation to the result if
+  /// one exists for the given offset.
+  uint64_t getRelocatedValue(uint32_t Size, uint64_t *Off,
+                             uint64_t *SectionIndex = nullptr,
+                             Error *Err = nullptr) const;
+
+  /// Extracts an address-sized value and applies a relocation to the result if
+  /// one exists for the given offset.
+  uint64_t getRelocatedAddress(uint64_t *Off, uint64_t *SecIx = nullptr) const {
+    return getRelocatedValue(getAddressSize(), Off, SecIx);
+  }
+  uint64_t getRelocatedAddress(Cursor &C, uint64_t *SecIx = nullptr) const {
+    return getRelocatedValue(getAddressSize(), &getOffset(C), SecIx,
+                             &getError(C));
+  }
+
+  /// Extracts a DWARF-encoded pointer in \p Offset using \p Encoding.
+  /// There is a DWARF encoding that uses a PC-relative adjustment.
+  /// For these values, \p AbsPosOffset is used to fix them, which should
+  /// reflect the absolute address of this pointer.
+  Optional<uint64_t> getEncodedPointer(uint64_t *Offset, uint8_t Encoding,
+                                       uint64_t AbsPosOffset = 0) const;
+
+  size_t size() const { return Section == nullptr ? 0 : Section->Data.size(); }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARFDATAEXTRACTOR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h
@@ -0,0 +1,87 @@
+//===- DWARFDebugAbbrev.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFDEBUGABBREV_H
+#define LLVM_DEBUGINFO_DWARFDEBUGABBREV_H
+
+#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
+#include "llvm/Support/DataExtractor.h"
+#include <cstdint>
+#include <map>
+#include <vector>
+
+namespace llvm {
+
+class raw_ostream;
+
+class DWARFAbbreviationDeclarationSet {
+  uint64_t Offset;
+  /// Code of the first abbreviation, if all abbreviations in the set have
+  /// consecutive codes. UINT32_MAX otherwise.
+  uint32_t FirstAbbrCode;
+  std::vector<DWARFAbbreviationDeclaration> Decls;
+
+  using const_iterator =
+      std::vector<DWARFAbbreviationDeclaration>::const_iterator;
+
+public:
+  DWARFAbbreviationDeclarationSet();
+
+  uint64_t getOffset() const { return Offset; }
+  void dump(raw_ostream &OS) const;
+  bool extract(DataExtractor Data, uint64_t *OffsetPtr);
+
+  const DWARFAbbreviationDeclaration *
+  getAbbreviationDeclaration(uint32_t AbbrCode) const;
+
+  const_iterator begin() const {
+    return Decls.begin();
+  }
+
+  const_iterator end() const {
+    return Decls.end();
+  }
+
+private:
+  void clear();
+};
+
+class DWARFDebugAbbrev {
+  using DWARFAbbreviationDeclarationSetMap =
+      std::map<uint64_t, DWARFAbbreviationDeclarationSet>;
+
+  mutable DWARFAbbreviationDeclarationSetMap AbbrDeclSets;
+  mutable DWARFAbbreviationDeclarationSetMap::const_iterator PrevAbbrOffsetPos;
+  mutable Optional<DataExtractor> Data;
+
+public:
+  DWARFDebugAbbrev();
+
+  const DWARFAbbreviationDeclarationSet *
+  getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const;
+
+  void dump(raw_ostream &OS) const;
+  void parse() const;
+  void extract(DataExtractor Data);
+
+  DWARFAbbreviationDeclarationSetMap::const_iterator begin() const {
+    parse();
+    return AbbrDeclSets.begin();
+  }
+
+  DWARFAbbreviationDeclarationSetMap::const_iterator end() const {
+    return AbbrDeclSets.end();
+  }
+
+private:
+  void clear();
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARFDEBUGABBREV_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAddr.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAddr.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAddr.h
@@ -0,0 +1,97 @@
+//===- DWARFDebugAddr.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFDEBUGADDR_H
+#define LLVM_DEBUGINFO_DWARFDEBUGADDR_H
+
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+#include <map>
+#include <vector>
+
+namespace llvm {
+
+class Error;
+class raw_ostream;
+
+/// A class representing an address table as specified in DWARF v5.
+/// The table consists of a header followed by an array of address values from
+/// .debug_addr section.
+class DWARFDebugAddrTable {
+public:
+  struct Header {
+    /// The total length of the entries for this table, not including the length
+    /// field itself.
+    uint32_t Length = 0;
+    /// The DWARF version number.
+    uint16_t Version = 5;
+    /// The size in bytes of an address on the target architecture. For
+    /// segmented addressing, this is the size of the offset portion of the
+    /// address.
+    uint8_t AddrSize;
+    /// The size in bytes of a segment selector on the target architecture.
+    /// If the target system uses a flat address space, this value is 0.
+    uint8_t SegSize = 0;
+  };
+
+private:
+  dwarf::DwarfFormat Format;
+  uint64_t HeaderOffset;
+  Header HeaderData;
+  uint32_t DataSize = 0;
+  std::vector<uint64_t> Addrs;
+
+public:
+  void clear();
+
+  /// Extract an entire table, including all addresses.
+  Error extract(DWARFDataExtractor Data, uint64_t *OffsetPtr,
+                uint16_t Version, uint8_t AddrSize,
+                std::function<void(Error)> WarnCallback);
+
+  uint64_t getHeaderOffset() const { return HeaderOffset; }
+  uint8_t getAddrSize() const { return HeaderData.AddrSize; }
+  void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}) const;
+
+  /// Return the address based on a given index.
+  Expected<uint64_t> getAddrEntry(uint32_t Index) const;
+
+  /// Return the size of the table header including the length
+  /// but not including the addresses.
+  uint8_t getHeaderSize() const {
+    switch (Format) {
+    case dwarf::DwarfFormat::DWARF32:
+      return 8; // 4 + 2 + 1 + 1
+    case dwarf::DwarfFormat::DWARF64:
+      return 16; // 12 + 2 + 1 + 1
+    }
+    llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64)");
+  }
+
+  /// Returns the length of this table, including the length field, or 0 if the
+  /// length has not been determined (e.g. because the table has not yet been
+  /// parsed, or there was a problem in parsing).
+  uint32_t getLength() const;
+
+  /// Verify that the given length is valid for this table.
+  bool hasValidLength() const { return getLength() != 0; }
+
+  /// Invalidate Length field to stop further processing.
+  void invalidateLength() { HeaderData.Length = 0; }
+
+  /// Returns the length of the array of addresses.
+  uint32_t getDataSize() const;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARFDEBUGADDR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h
@@ -0,0 +1,75 @@
+//===- DWARFDebugArangeSet.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFDEBUGARANGESET_H
+#define LLVM_DEBUGINFO_DWARFDEBUGARANGESET_H
+
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/DataExtractor.h"
+#include <cstdint>
+#include <vector>
+
+namespace llvm {
+
+class raw_ostream;
+
+class DWARFDebugArangeSet {
+public:
+  struct Header {
+    /// The total length of the entries for that set, not including the length
+    /// field itself.
+    uint32_t Length;
+    /// The offset from the beginning of the .debug_info section of the
+    /// compilation unit entry referenced by the table.
+    uint32_t CuOffset;
+    /// The DWARF version number.
+    uint16_t Version;
+    /// The size in bytes of an address on the target architecture. For segmented
+    /// addressing, this is the size of the offset portion of the address.
+    uint8_t AddrSize;
+    /// The size in bytes of a segment descriptor on the target architecture.
+    /// If the target system uses a flat address space, this value is 0.
+    uint8_t SegSize;
+  };
+
+  struct Descriptor {
+    uint64_t Address;
+    uint64_t Length;
+
+    uint64_t getEndAddress() const { return Address + Length; }
+    void dump(raw_ostream &OS, uint32_t AddressSize) const;
+  };
+
+private:
+  using DescriptorColl = std::vector<Descriptor>;
+  using desc_iterator_range = iterator_range<DescriptorColl::const_iterator>;
+
+  uint64_t Offset;
+  Header HeaderData;
+  DescriptorColl ArangeDescriptors;
+
+public:
+  DWARFDebugArangeSet() { clear(); }
+
+  void clear();
+  bool extract(DataExtractor data, uint64_t *offset_ptr);
+  void dump(raw_ostream &OS) const;
+
+  uint32_t getCompileUnitDIEOffset() const { return HeaderData.CuOffset; }
+
+  const Header &getHeader() const { return HeaderData; }
+
+  desc_iterator_range descriptors() const {
+    return desc_iterator_range(ArangeDescriptors.begin(),
+                               ArangeDescriptors.end());
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARFDEBUGARANGESET_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAranges.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAranges.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAranges.h
@@ -0,0 +1,84 @@
+//===- DWARFDebugAranges.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFDEBUGARANGES_H
+#define LLVM_DEBUGINFO_DWARFDEBUGARANGES_H
+
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/DataExtractor.h"
+#include <cstdint>
+#include <vector>
+
+namespace llvm {
+
+class DWARFContext;
+
+class DWARFDebugAranges {
+public:
+  void generate(DWARFContext *CTX);
+  uint32_t findAddress(uint64_t Address) const;
+
+private:
+  void clear();
+  void extract(DataExtractor DebugArangesData);
+
+  /// Call appendRange multiple times and then call construct.
+  void appendRange(uint64_t CUOffset, uint64_t LowPC, uint64_t HighPC);
+  void construct();
+
+  struct Range {
+    explicit Range(uint64_t LowPC = -1ULL, uint64_t HighPC = -1ULL,
+                   uint32_t CUOffset = -1U)
+      : LowPC(LowPC), Length(HighPC - LowPC), CUOffset(CUOffset) {}
+
+    void setHighPC(uint64_t HighPC) {
+      if (HighPC == -1ULL || HighPC <= LowPC)
+        Length = 0;
+      else
+        Length = HighPC - LowPC;
+    }
+
+    uint64_t HighPC() const {
+      if (Length)
+        return LowPC + Length;
+      return -1ULL;
+    }
+
+    bool operator<(const Range &other) const {
+      return LowPC < other.LowPC;
+    }
+
+    uint64_t LowPC; /// Start of address range.
+    uint32_t Length; /// End of address range (not including this address).
+    uint32_t CUOffset; /// Offset of the compile unit or die.
+  };
+
+  struct RangeEndpoint {
+    uint64_t Address;
+    uint64_t CUOffset;
+    bool IsRangeStart;
+
+    RangeEndpoint(uint64_t Address, uint64_t CUOffset, bool IsRangeStart)
+        : Address(Address), CUOffset(CUOffset), IsRangeStart(IsRangeStart) {}
+
+    bool operator<(const RangeEndpoint &Other) const {
+      return Address < Other.Address;
+    }
+  };
+
+  using RangeColl = std::vector<Range>;
+  using RangeCollIterator = RangeColl::const_iterator;
+
+  std::vector<RangeEndpoint> Endpoints;
+  RangeColl Aranges;
+  DenseSet<uint64_t> ParsedCUOffsets;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARFDEBUGARANGES_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
@@ -0,0 +1,308 @@
+//===- DWARFDebugFrame.h - Parsing of .debug_frame --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H
+#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
+#include "llvm/Support/Error.h"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+
+class raw_ostream;
+
+namespace dwarf {
+
+/// Represent a sequence of Call Frame Information instructions that, when read
+/// in order, construct a table mapping PC to frame state. This can also be
+/// referred to as "CFI rules" in DWARF literature to avoid confusion with
+/// computer programs in the broader sense, and in this context each instruction
+/// would be a rule to establish the mapping. Refer to pg. 172 in the DWARF5
+/// manual, "6.4.1 Structure of Call Frame Information".
+class CFIProgram {
+public:
+  typedef SmallVector<uint64_t, 2> Operands;
+
+  /// An instruction consists of a DWARF CFI opcode and an optional sequence of
+  /// operands. If it refers to an expression, then this expression has its own
+  /// sequence of operations and operands handled separately by DWARFExpression.
+  struct Instruction {
+    Instruction(uint8_t Opcode) : Opcode(Opcode) {}
+
+    uint8_t Opcode;
+    Operands Ops;
+    // Associated DWARF expression in case this instruction refers to one
+    Optional<DWARFExpression> Expression;
+  };
+
+  using InstrList = std::vector<Instruction>;
+  using iterator = InstrList::iterator;
+  using const_iterator = InstrList::const_iterator;
+
+  iterator begin() { return Instructions.begin(); }
+  const_iterator begin() const { return Instructions.begin(); }
+  iterator end() { return Instructions.end(); }
+  const_iterator end() const { return Instructions.end(); }
+
+  unsigned size() const { return (unsigned)Instructions.size(); }
+  bool empty() const { return Instructions.empty(); }
+
+  CFIProgram(uint64_t CodeAlignmentFactor, int64_t DataAlignmentFactor,
+             Triple::ArchType Arch)
+      : CodeAlignmentFactor(CodeAlignmentFactor),
+        DataAlignmentFactor(DataAlignmentFactor),
+        Arch(Arch) {}
+
+  /// Parse and store a sequence of CFI instructions from Data,
+  /// starting at *Offset and ending at EndOffset. *Offset is updated
+  /// to EndOffset upon successful parsing, or indicates the offset
+  /// where a problem occurred in case an error is returned.
+  Error parse(DWARFDataExtractor Data, uint64_t *Offset, uint64_t EndOffset);
+
+  void dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
+            unsigned IndentLevel = 1) const;
+
+private:
+  std::vector<Instruction> Instructions;
+  const uint64_t CodeAlignmentFactor;
+  const int64_t DataAlignmentFactor;
+  Triple::ArchType Arch;
+
+  /// Convenience method to add a new instruction with the given opcode.
+  void addInstruction(uint8_t Opcode) {
+    Instructions.push_back(Instruction(Opcode));
+  }
+
+  /// Add a new single-operand instruction.
+  void addInstruction(uint8_t Opcode, uint64_t Operand1) {
+    Instructions.push_back(Instruction(Opcode));
+    Instructions.back().Ops.push_back(Operand1);
+  }
+
+  /// Add a new instruction that has two operands.
+  void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) {
+    Instructions.push_back(Instruction(Opcode));
+    Instructions.back().Ops.push_back(Operand1);
+    Instructions.back().Ops.push_back(Operand2);
+  }
+
+  /// Types of operands to CFI instructions
+  /// In DWARF, this type is implicitly tied to a CFI instruction opcode and
+  /// thus this type doesn't need to be explictly written to the file (this is
+  /// not a DWARF encoding). The relationship of instrs to operand types can
+  /// be obtained from getOperandTypes() and is only used to simplify
+  /// instruction printing.
+  enum OperandType {
+    OT_Unset,
+    OT_None,
+    OT_Address,
+    OT_Offset,
+    OT_FactoredCodeOffset,
+    OT_SignedFactDataOffset,
+    OT_UnsignedFactDataOffset,
+    OT_Register,
+    OT_Expression
+  };
+
+  /// Retrieve the array describing the types of operands according to the enum
+  /// above. This is indexed by opcode.
+  static ArrayRef<OperandType[2]> getOperandTypes();
+
+  /// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
+  void printOperand(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
+                    const Instruction &Instr, unsigned OperandIdx,
+                    uint64_t Operand) const;
+};
+
+/// An entry in either debug_frame or eh_frame. This entry can be a CIE or an
+/// FDE.
+class FrameEntry {
+public:
+  enum FrameKind { FK_CIE, FK_FDE };
+
+  FrameEntry(FrameKind K, uint64_t Offset, uint64_t Length, uint64_t CodeAlign,
+             int64_t DataAlign, Triple::ArchType Arch)
+      : Kind(K), Offset(Offset), Length(Length),
+        CFIs(CodeAlign, DataAlign, Arch) {}
+
+  virtual ~FrameEntry() {}
+
+  FrameKind getKind() const { return Kind; }
+  uint64_t getOffset() const { return Offset; }
+  uint64_t getLength() const { return Length; }
+  const CFIProgram &cfis() const { return CFIs; }
+  CFIProgram &cfis() { return CFIs; }
+
+  /// Dump the instructions in this CFI fragment
+  virtual void dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+                    bool IsEH) const = 0;
+
+protected:
+  const FrameKind Kind;
+
+  /// Offset of this entry in the section.
+  const uint64_t Offset;
+
+  /// Entry length as specified in DWARF.
+  const uint64_t Length;
+
+  CFIProgram CFIs;
+};
+
+/// DWARF Common Information Entry (CIE)
+class CIE : public FrameEntry {
+public:
+  // CIEs (and FDEs) are simply container classes, so the only sensible way to
+  // create them is by providing the full parsed contents in the constructor.
+  CIE(uint64_t Offset, uint64_t Length, uint8_t Version,
+      SmallString<8> Augmentation, uint8_t AddressSize,
+      uint8_t SegmentDescriptorSize, uint64_t CodeAlignmentFactor,
+      int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister,
+      SmallString<8> AugmentationData, uint32_t FDEPointerEncoding,
+      uint32_t LSDAPointerEncoding, Optional<uint64_t> Personality,
+      Optional<uint32_t> PersonalityEnc, Triple::ArchType Arch)
+      : FrameEntry(FK_CIE, Offset, Length, CodeAlignmentFactor,
+                   DataAlignmentFactor, Arch),
+        Version(Version), Augmentation(std::move(Augmentation)),
+        AddressSize(AddressSize), SegmentDescriptorSize(SegmentDescriptorSize),
+        CodeAlignmentFactor(CodeAlignmentFactor),
+        DataAlignmentFactor(DataAlignmentFactor),
+        ReturnAddressRegister(ReturnAddressRegister),
+        AugmentationData(std::move(AugmentationData)),
+        FDEPointerEncoding(FDEPointerEncoding),
+        LSDAPointerEncoding(LSDAPointerEncoding), Personality(Personality),
+        PersonalityEnc(PersonalityEnc) {}
+
+  static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_CIE; }
+
+  StringRef getAugmentationString() const { return Augmentation; }
+  uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; }
+  int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; }
+  uint8_t getVersion() const { return Version; }
+  uint64_t getReturnAddressRegister() const { return ReturnAddressRegister; }
+  Optional<uint64_t> getPersonalityAddress() const { return Personality; }
+  Optional<uint32_t> getPersonalityEncoding() const { return PersonalityEnc; }
+
+  uint32_t getFDEPointerEncoding() const { return FDEPointerEncoding; }
+
+  uint32_t getLSDAPointerEncoding() const { return LSDAPointerEncoding; }
+
+  void dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+            bool IsEH) const override;
+
+private:
+  /// The following fields are defined in section 6.4.1 of the DWARF standard v4
+  const uint8_t Version;
+  const SmallString<8> Augmentation;
+  const uint8_t AddressSize;
+  const uint8_t SegmentDescriptorSize;
+  const uint64_t CodeAlignmentFactor;
+  const int64_t DataAlignmentFactor;
+  const uint64_t ReturnAddressRegister;
+
+  // The following are used when the CIE represents an EH frame entry.
+  const SmallString<8> AugmentationData;
+  const uint32_t FDEPointerEncoding;
+  const uint32_t LSDAPointerEncoding;
+  const Optional<uint64_t> Personality;
+  const Optional<uint32_t> PersonalityEnc;
+};
+
+/// DWARF Frame Description Entry (FDE)
+class FDE : public FrameEntry {
+public:
+  // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with
+  // an offset to the CIE (provided by parsing the FDE header). The CIE itself
+  // is obtained lazily once it's actually required.
+  FDE(uint64_t Offset, uint64_t Length, int64_t LinkedCIEOffset,
+      uint64_t InitialLocation, uint64_t AddressRange, CIE *Cie,
+      Optional<uint64_t> LSDAAddress, Triple::ArchType Arch)
+      : FrameEntry(FK_FDE, Offset, Length,
+                   Cie ? Cie->getCodeAlignmentFactor() : 0,
+                   Cie ? Cie->getDataAlignmentFactor() : 0,
+                   Arch),
+        LinkedCIEOffset(LinkedCIEOffset), InitialLocation(InitialLocation),
+        AddressRange(AddressRange), LinkedCIE(Cie), LSDAAddress(LSDAAddress) {}
+
+  ~FDE() override = default;
+
+  const CIE *getLinkedCIE() const { return LinkedCIE; }
+  uint64_t getInitialLocation() const { return InitialLocation; }
+  uint64_t getAddressRange() const { return AddressRange; }
+  Optional<uint64_t> getLSDAAddress() const { return LSDAAddress; }
+
+  void dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+            bool IsEH) const override;
+
+  static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_FDE; }
+
+private:
+  /// The following fields are defined in section 6.4.1 of the DWARF standard v3
+  const uint64_t LinkedCIEOffset;
+  const uint64_t InitialLocation;
+  const uint64_t AddressRange;
+  const CIE *LinkedCIE;
+  const Optional<uint64_t> LSDAAddress;
+};
+
+} // end namespace dwarf
+
+/// A parsed .debug_frame or .eh_frame section
+class DWARFDebugFrame {
+  const Triple::ArchType Arch;
+  // True if this is parsing an eh_frame section.
+  const bool IsEH;
+  // Not zero for sane pointer values coming out of eh_frame
+  const uint64_t EHFrameAddress;
+
+  std::vector<std::unique_ptr<dwarf::FrameEntry>> Entries;
+  using iterator = pointee_iterator<decltype(Entries)::const_iterator>;
+
+  /// Return the entry at the given offset or nullptr.
+  dwarf::FrameEntry *getEntryAtOffset(uint64_t Offset) const;
+
+public:
+  // If IsEH is true, assume it is a .eh_frame section. Otherwise,
+  // it is a .debug_frame section. EHFrameAddress should be different
+  // than zero for correct parsing of .eh_frame addresses when they
+  // use a PC-relative encoding.
+  DWARFDebugFrame(Triple::ArchType Arch,
+                  bool IsEH = false, uint64_t EHFrameAddress = 0);
+  ~DWARFDebugFrame();
+
+  /// Dump the section data into the given stream.
+  void dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+            Optional<uint64_t> Offset) const;
+
+  /// Parse the section from raw data. \p Data is assumed to contain the whole
+  /// frame section contents to be parsed.
+  void parse(DWARFDataExtractor Data);
+
+  /// Return whether the section has any entries.
+  bool empty() const { return Entries.empty(); }
+
+  /// DWARF Frame entries accessors
+  iterator begin() const { return Entries.begin(); }
+  iterator end() const { return Entries.end(); }
+  iterator_range<iterator> entries() const {
+    return iterator_range<iterator>(Entries.begin(), Entries.end());
+  }
+
+  uint64_t getEHFrameAddress() const { return EHFrameAddress; }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h
@@ -0,0 +1,62 @@
+//===- DWARFDebugInfoEntry.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFDEBUGINFOENTRY_H
+#define LLVM_DEBUGINFO_DWARFDEBUGINFOENTRY_H
+
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include <cstdint>
+
+namespace llvm {
+
+class DataExtractor;
+class DWARFUnit;
+
+/// DWARFDebugInfoEntry - A DIE with only the minimum required data.
+class DWARFDebugInfoEntry {
+  /// Offset within the .debug_info of the start of this entry.
+  uint64_t Offset = 0;
+
+  /// The integer depth of this DIE within the compile unit DIEs where the
+  /// compile/type unit DIE has a depth of zero.
+  uint32_t Depth = 0;
+
+  const DWARFAbbreviationDeclaration *AbbrevDecl = nullptr;
+
+public:
+  DWARFDebugInfoEntry() = default;
+
+  /// Extracts a debug info entry, which is a child of a given unit,
+  /// starting at a given offset. If DIE can't be extracted, returns false and
+  /// doesn't change OffsetPtr.
+  bool extractFast(const DWARFUnit &U, uint64_t *OffsetPtr);
+
+  /// High performance extraction should use this call.
+  bool extractFast(const DWARFUnit &U, uint64_t *OffsetPtr,
+                   const DWARFDataExtractor &DebugInfoData, uint64_t UEndOffset,
+                   uint32_t Depth);
+
+  uint64_t getOffset() const { return Offset; }
+  uint32_t getDepth() const { return Depth; }
+
+  dwarf::Tag getTag() const {
+    return AbbrevDecl ? AbbrevDecl->getTag() : dwarf::DW_TAG_null;
+  }
+
+  bool hasChildren() const { return AbbrevDecl && AbbrevDecl->hasChildren(); }
+
+  const DWARFAbbreviationDeclaration *getAbbreviationDeclarationPtr() const {
+    return AbbrevDecl;
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARFDEBUGINFOENTRY_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
@@ -0,0 +1,392 @@
+//===- DWARFDebugLine.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFDEBUGLINE_H
+#define LLVM_DEBUGINFO_DWARFDEBUGLINE_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/Path.h"
+#include <cstdint>
+#include <map>
+#include <string>
+#include <vector>
+
+namespace llvm {
+
+class DWARFUnit;
+class raw_ostream;
+
+class DWARFDebugLine {
+public:
+  struct FileNameEntry {
+    FileNameEntry() = default;
+
+    DWARFFormValue Name;
+    uint64_t DirIdx = 0;
+    uint64_t ModTime = 0;
+    uint64_t Length = 0;
+    MD5::MD5Result Checksum;
+    DWARFFormValue Source;
+  };
+
+  /// Tracks which optional content types are present in a DWARF file name
+  /// entry format.
+  struct ContentTypeTracker {
+    ContentTypeTracker() = default;
+
+    /// Whether filename entries provide a modification timestamp.
+    bool HasModTime = false;
+    /// Whether filename entries provide a file size.
+    bool HasLength = false;
+    /// For v5, whether filename entries provide an MD5 checksum.
+    bool HasMD5 = false;
+    /// For v5, whether filename entries provide source text.
+    bool HasSource = false;
+
+    /// Update tracked content types with \p ContentType.
+    void trackContentType(dwarf::LineNumberEntryFormat ContentType);
+  };
+
+  struct Prologue {
+    Prologue();
+
+    /// The size in bytes of the statement information for this compilation unit
+    /// (not including the total_length field itself).
+    uint64_t TotalLength;
+    /// Version, address size (starting in v5), and DWARF32/64 format; these
+    /// parameters affect interpretation of forms (used in the directory and
+    /// file tables starting with v5).
+    dwarf::FormParams FormParams;
+    /// The number of bytes following the prologue_length field to the beginning
+    /// of the first byte of the statement program itself.
+    uint64_t PrologueLength;
+    /// In v5, size in bytes of a segment selector.
+    uint8_t SegSelectorSize;
+    /// The size in bytes of the smallest target machine instruction. Statement
+    /// program opcodes that alter the address register first multiply their
+    /// operands by this value.
+    uint8_t MinInstLength;
+    /// The maximum number of individual operations that may be encoded in an
+    /// instruction.
+    uint8_t MaxOpsPerInst;
+    /// The initial value of theis_stmtregister.
+    uint8_t DefaultIsStmt;
+    /// This parameter affects the meaning of the special opcodes. See below.
+    int8_t LineBase;
+    /// This parameter affects the meaning of the special opcodes. See below.
+    uint8_t LineRange;
+    /// The number assigned to the first special opcode.
+    uint8_t OpcodeBase;
+    /// This tracks which optional file format content types are present.
+    ContentTypeTracker ContentTypes;
+    std::vector<uint8_t> StandardOpcodeLengths;
+    std::vector<DWARFFormValue> IncludeDirectories;
+    std::vector<FileNameEntry> FileNames;
+
+    const dwarf::FormParams getFormParams() const { return FormParams; }
+    uint16_t getVersion() const { return FormParams.Version; }
+    uint8_t getAddressSize() const { return FormParams.AddrSize; }
+    bool isDWARF64() const { return FormParams.Format == dwarf::DWARF64; }
+
+    uint32_t sizeofTotalLength() const { return isDWARF64() ? 12 : 4; }
+
+    uint32_t sizeofPrologueLength() const { return isDWARF64() ? 8 : 4; }
+
+    bool totalLengthIsValid() const;
+
+    /// Length of the prologue in bytes.
+    uint32_t getLength() const {
+      return PrologueLength + sizeofTotalLength() + sizeof(getVersion()) +
+             sizeofPrologueLength();
+    }
+
+    /// Length of the line table data in bytes (not including the prologue).
+    uint32_t getStatementTableLength() const {
+      return TotalLength + sizeofTotalLength() - getLength();
+    }
+
+    int32_t getMaxLineIncrementForSpecialOpcode() const {
+      return LineBase + (int8_t)LineRange - 1;
+    }
+
+    /// Get DWARF-version aware access to the file name entry at the provided
+    /// index.
+    const llvm::DWARFDebugLine::FileNameEntry &
+    getFileNameEntry(uint64_t Index) const;
+
+    bool hasFileAtIndex(uint64_t FileIndex) const;
+
+    bool
+    getFileNameByIndex(uint64_t FileIndex, StringRef CompDir,
+                       DILineInfoSpecifier::FileLineInfoKind Kind,
+                       std::string &Result,
+                       sys::path::Style Style = sys::path::Style::native) const;
+
+    void clear();
+    void dump(raw_ostream &OS, DIDumpOptions DumpOptions) const;
+    Error parse(const DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr,
+                const DWARFContext &Ctx, const DWARFUnit *U = nullptr);
+  };
+
+  /// Standard .debug_line state machine structure.
+  struct Row {
+    explicit Row(bool DefaultIsStmt = false);
+
+    /// Called after a row is appended to the matrix.
+    void postAppend();
+    void reset(bool DefaultIsStmt);
+    void dump(raw_ostream &OS) const;
+
+    static void dumpTableHeader(raw_ostream &OS);
+
+    static bool orderByAddress(const Row &LHS, const Row &RHS) {
+      return std::tie(LHS.Address.SectionIndex, LHS.Address.Address) <
+             std::tie(RHS.Address.SectionIndex, RHS.Address.Address);
+    }
+
+    /// The program-counter value corresponding to a machine instruction
+    /// generated by the compiler and section index pointing to the section
+    /// containg this PC. If relocation information is present then section
+    /// index is the index of the section which contains above address.
+    /// Otherwise this is object::SectionedAddress::Undef value.
+    object::SectionedAddress Address;
+    /// An unsigned integer indicating a source line number. Lines are numbered
+    /// beginning at 1. The compiler may emit the value 0 in cases where an
+    /// instruction cannot be attributed to any source line.
+    uint32_t Line;
+    /// An unsigned integer indicating a column number within a source line.
+    /// Columns are numbered beginning at 1. The value 0 is reserved to indicate
+    /// that a statement begins at the 'left edge' of the line.
+    uint16_t Column;
+    /// An unsigned integer indicating the identity of the source file
+    /// corresponding to a machine instruction.
+    uint16_t File;
+    /// An unsigned integer representing the DWARF path discriminator value
+    /// for this location.
+    uint32_t Discriminator;
+    /// An unsigned integer whose value encodes the applicable instruction set
+    /// architecture for the current instruction.
+    uint8_t Isa;
+    /// A boolean indicating that the current instruction is the beginning of a
+    /// statement.
+    uint8_t IsStmt : 1,
+        /// A boolean indicating that the current instruction is the
+        /// beginning of a basic block.
+        BasicBlock : 1,
+        /// A boolean indicating that the current address is that of the
+        /// first byte after the end of a sequence of target machine
+        /// instructions.
+        EndSequence : 1,
+        /// A boolean indicating that the current address is one (of possibly
+        /// many) where execution should be suspended for an entry breakpoint
+        /// of a function.
+        PrologueEnd : 1,
+        /// A boolean indicating that the current address is one (of possibly
+        /// many) where execution should be suspended for an exit breakpoint
+        /// of a function.
+        EpilogueBegin : 1;
+  };
+
+  /// Represents a series of contiguous machine instructions. Line table for
+  /// each compilation unit may consist of multiple sequences, which are not
+  /// guaranteed to be in the order of ascending instruction address.
+  struct Sequence {
+    Sequence();
+
+    /// Sequence describes instructions at address range [LowPC, HighPC)
+    /// and is described by line table rows [FirstRowIndex, LastRowIndex).
+    uint64_t LowPC;
+    uint64_t HighPC;
+    /// If relocation information is present then this is the index of the
+    /// section which contains above addresses. Otherwise this is
+    /// object::SectionedAddress::Undef value.
+    uint64_t SectionIndex;
+    unsigned FirstRowIndex;
+    unsigned LastRowIndex;
+    bool Empty;
+
+    void reset();
+
+    static bool orderByHighPC(const Sequence &LHS, const Sequence &RHS) {
+      return std::tie(LHS.SectionIndex, LHS.HighPC) <
+             std::tie(RHS.SectionIndex, RHS.HighPC);
+    }
+
+    bool isValid() const {
+      return !Empty && (LowPC < HighPC) && (FirstRowIndex < LastRowIndex);
+    }
+
+    bool containsPC(object::SectionedAddress PC) const {
+      return SectionIndex == PC.SectionIndex &&
+             (LowPC <= PC.Address && PC.Address < HighPC);
+    }
+  };
+
+  struct LineTable {
+    LineTable();
+
+    /// Represents an invalid row
+    const uint32_t UnknownRowIndex = UINT32_MAX;
+
+    void appendRow(const DWARFDebugLine::Row &R) { Rows.push_back(R); }
+
+    void appendSequence(const DWARFDebugLine::Sequence &S) {
+      Sequences.push_back(S);
+    }
+
+    /// Returns the index of the row with file/line info for a given address,
+    /// or UnknownRowIndex if there is no such row.
+    uint32_t lookupAddress(object::SectionedAddress Address) const;
+
+    bool lookupAddressRange(object::SectionedAddress Address, uint64_t Size,
+                            std::vector<uint32_t> &Result) const;
+
+    bool hasFileAtIndex(uint64_t FileIndex) const {
+      return Prologue.hasFileAtIndex(FileIndex);
+    }
+
+    /// Extracts filename by its index in filename table in prologue.
+    /// In Dwarf 4, the files are 1-indexed and the current compilation file
+    /// name is not represented in the list. In DWARF v5, the files are
+    /// 0-indexed and the primary source file has the index 0.
+    /// Returns true on success.
+    bool getFileNameByIndex(uint64_t FileIndex, StringRef CompDir,
+                            DILineInfoSpecifier::FileLineInfoKind Kind,
+                            std::string &Result) const {
+      return Prologue.getFileNameByIndex(FileIndex, CompDir, Kind, Result);
+    }
+
+    /// Fills the Result argument with the file and line information
+    /// corresponding to Address. Returns true on success.
+    bool getFileLineInfoForAddress(object::SectionedAddress Address,
+                                   const char *CompDir,
+                                   DILineInfoSpecifier::FileLineInfoKind Kind,
+                                   DILineInfo &Result) const;
+
+    void dump(raw_ostream &OS, DIDumpOptions DumpOptions) const;
+    void clear();
+
+    /// Parse prologue and all rows.
+    Error parse(
+        DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr,
+        const DWARFContext &Ctx, const DWARFUnit *U,
+        std::function<void(Error)> RecoverableErrorCallback,
+        raw_ostream *OS = nullptr);
+
+    using RowVector = std::vector<Row>;
+    using RowIter = RowVector::const_iterator;
+    using SequenceVector = std::vector<Sequence>;
+    using SequenceIter = SequenceVector::const_iterator;
+
+    struct Prologue Prologue;
+    RowVector Rows;
+    SequenceVector Sequences;
+
+  private:
+    uint32_t findRowInSeq(const DWARFDebugLine::Sequence &Seq,
+                          object::SectionedAddress Address) const;
+    Optional<StringRef>
+    getSourceByIndex(uint64_t FileIndex,
+                     DILineInfoSpecifier::FileLineInfoKind Kind) const;
+
+    uint32_t lookupAddressImpl(object::SectionedAddress Address) const;
+
+    bool lookupAddressRangeImpl(object::SectionedAddress Address, uint64_t Size,
+                                std::vector<uint32_t> &Result) const;
+  };
+
+  const LineTable *getLineTable(uint64_t Offset) const;
+  Expected<const LineTable *> getOrParseLineTable(
+      DWARFDataExtractor &DebugLineData, uint64_t Offset,
+      const DWARFContext &Ctx, const DWARFUnit *U,
+      std::function<void(Error)> RecoverableErrorCallback);
+
+  /// Helper to allow for parsing of an entire .debug_line section in sequence.
+  class SectionParser {
+  public:
+    using cu_range = DWARFUnitVector::iterator_range;
+    using tu_range = DWARFUnitVector::iterator_range;
+    using LineToUnitMap = std::map<uint64_t, DWARFUnit *>;
+
+    SectionParser(DWARFDataExtractor &Data, const DWARFContext &C, cu_range CUs,
+                  tu_range TUs);
+
+    /// Get the next line table from the section. Report any issues via the
+    /// callbacks.
+    ///
+    /// \param RecoverableErrorCallback - any issues that don't prevent further
+    /// parsing of the table will be reported through this callback.
+    /// \param UnrecoverableErrorCallback - any issues that prevent further
+    /// parsing of the table will be reported through this callback.
+    /// \param OS - if not null, the parser will print information about the
+    /// table as it parses it.
+    LineTable
+    parseNext(
+        function_ref<void(Error)> RecoverableErrorCallback,
+        function_ref<void(Error)> UnrecoverableErrorCallback,
+        raw_ostream *OS = nullptr);
+
+    /// Skip the current line table and go to the following line table (if
+    /// present) immediately.
+    ///
+    /// \param ErrorCallback - report any prologue parsing issues via this
+    /// callback.
+    void skip(function_ref<void(Error)> ErrorCallback);
+
+    /// Indicates if the parser has parsed as much as possible.
+    ///
+    /// \note Certain problems with the line table structure might mean that
+    /// parsing stops before the end of the section is reached.
+    bool done() const { return Done; }
+
+    /// Get the offset the parser has reached.
+    uint64_t getOffset() const { return Offset; }
+
+  private:
+    DWARFUnit *prepareToParse(uint64_t Offset);
+    void moveToNextTable(uint64_t OldOffset, const Prologue &P);
+
+    LineToUnitMap LineToUnit;
+
+    DWARFDataExtractor &DebugLineData;
+    const DWARFContext &Context;
+    uint64_t Offset = 0;
+    bool Done = false;
+  };
+
+private:
+  struct ParsingState {
+    ParsingState(struct LineTable *LT);
+
+    void resetRowAndSequence();
+    void appendRowToMatrix();
+
+    /// Line table we're currently parsing.
+    struct LineTable *LineTable;
+    struct Row Row;
+    struct Sequence Sequence;
+  };
+
+  using LineTableMapTy = std::map<uint64_t, LineTable>;
+  using LineTableIter = LineTableMapTy::iterator;
+  using LineTableConstIter = LineTableMapTy::const_iterator;
+
+  LineTableMapTy LineTableMap;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARFDEBUGLINE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h
@@ -0,0 +1,121 @@
+//===- DWARFDebugLoc.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGLOC_H
+#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGLOC_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include <cstdint>
+
+namespace llvm {
+class DWARFUnit;
+class MCRegisterInfo;
+class raw_ostream;
+
+class DWARFDebugLoc {
+public:
+  /// A single location within a location list.
+  struct Entry {
+    /// The beginning address of the instruction range.
+    uint64_t Begin;
+    /// The ending address of the instruction range.
+    uint64_t End;
+    /// The location of the variable within the specified range.
+    SmallVector<uint8_t, 4> Loc;
+  };
+
+  /// A list of locations that contain one variable.
+  struct LocationList {
+    /// The beginning offset where this location list is stored in the debug_loc
+    /// section.
+    uint64_t Offset;
+    /// All the locations in which the variable is stored.
+    SmallVector<Entry, 2> Entries;
+    /// Dump this list on OS.
+    void dump(raw_ostream &OS, uint64_t BaseAddress, bool IsLittleEndian,
+              unsigned AddressSize, const MCRegisterInfo *MRI, DWARFUnit *U,
+              DIDumpOptions DumpOpts,
+              unsigned Indent) const;
+  };
+
+private:
+  using LocationLists = SmallVector<LocationList, 4>;
+
+  /// A list of all the variables in the debug_loc section, each one describing
+  /// the locations in which the variable is stored.
+  LocationLists Locations;
+
+  unsigned AddressSize;
+
+  bool IsLittleEndian;
+
+public:
+  /// Print the location lists found within the debug_loc section.
+  void dump(raw_ostream &OS, const MCRegisterInfo *RegInfo, DIDumpOptions DumpOpts,
+            Optional<uint64_t> Offset) const;
+
+  /// Parse the debug_loc section accessible via the 'data' parameter using the
+  /// address size also given in 'data' to interpret the address ranges.
+  void parse(const DWARFDataExtractor &data);
+
+  /// Return the location list at the given offset or nullptr.
+  LocationList const *getLocationListAtOffset(uint64_t Offset) const;
+
+  Expected<LocationList>
+  parseOneLocationList(const DWARFDataExtractor &Data, uint64_t *Offset);
+};
+
+class DWARFDebugLoclists {
+public:
+  // Unconstructible.
+  DWARFDebugLoclists() = delete;
+
+  struct Entry {
+    uint8_t Kind;
+    uint64_t Offset;
+    uint64_t Value0;
+    uint64_t Value1;
+    SmallVector<uint8_t, 4> Loc;
+    void dump(raw_ostream &OS, uint64_t &BaseAddr, bool IsLittleEndian,
+              unsigned AddressSize, const MCRegisterInfo *MRI, DWARFUnit *U,
+              DIDumpOptions DumpOpts, unsigned Indent, size_t MaxEncodingStringLength) const;
+  };
+
+  /// Call the user-provided callback for each entry (including the end-of-list
+  /// entry) in the location list starting at \p Offset. The callback can return
+  /// false to terminate the iteration early. Returns an error if it was unable
+  /// to parse the entire location list correctly. Upon successful termination
+  /// \p Offset will be updated point past the end of the list.
+  static Error visitLocationList(const DWARFDataExtractor &Data,
+                                 uint64_t *Offset, uint16_t Version,
+                                 llvm::function_ref<bool(const Entry &)> F);
+
+  /// Dump the location list at the given \p Offset. The function returns true
+  /// iff it has successfully reched the end of the list. This means that one
+  /// can attempt to parse another list after the current one (\p Offset will be
+  /// updated to point past the end of the current list).
+  static bool dumpLocationList(const DWARFDataExtractor &Data, uint64_t *Offset,
+                               uint16_t Version, raw_ostream &OS,
+                               uint64_t BaseAddr, const MCRegisterInfo *MRI,
+                               DWARFUnit *U, DIDumpOptions DumpOpts,
+                               unsigned Indent);
+
+  /// Dump all location lists within the given range.
+  static void dumpRange(const DWARFDataExtractor &Data, uint64_t StartOffset,
+                        uint64_t Size, uint16_t Version, raw_ostream &OS,
+                        uint64_t BaseAddr, const MCRegisterInfo *MRI,
+                        DIDumpOptions DumpOpts);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGLOC_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h
@@ -0,0 +1,62 @@
+//===- DWARFDebugMacro.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGMACRO_H
+#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGMACRO_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/DataExtractor.h"
+#include <cstdint>
+
+namespace llvm {
+
+class raw_ostream;
+
+class DWARFDebugMacro {
+  /// A single macro entry within a macro list.
+  struct Entry {
+    /// The type of the macro entry.
+    uint32_t Type;
+    union {
+      /// The source line where the macro is defined.
+      uint64_t Line;
+      /// Vendor extension constant value.
+      uint64_t ExtConstant;
+    };
+
+    union {
+      /// The string (name, value) of the macro entry.
+      const char *MacroStr;
+      // An unsigned integer indicating the identity of the source file.
+      uint64_t File;
+      /// Vendor extension string.
+      const char *ExtStr;
+    };
+  };
+
+  using MacroList = SmallVector<Entry, 4>;
+
+  /// A list of all the macro entries in the debug_macinfo section.
+  std::vector<MacroList> MacroLists;
+
+public:
+  DWARFDebugMacro() = default;
+
+  /// Print the macro list found within the debug_macinfo section.
+  void dump(raw_ostream &OS) const;
+
+  /// Parse the debug_macinfo section accessible via the 'data' parameter.
+  void parse(DataExtractor data);
+
+  /// Return whether the section has any entries.
+  bool empty() const { return MacroLists.empty(); }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGMACRO_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h
@@ -0,0 +1,80 @@
+//===- DWARFDebugPubTable.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGPUBTABLE_H
+#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGPUBTABLE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFObject.h"
+#include <cstdint>
+#include <vector>
+
+namespace llvm {
+
+class raw_ostream;
+
+/// Represents structure for holding and parsing .debug_pub* tables.
+class DWARFDebugPubTable {
+public:
+  struct Entry {
+    /// Section offset from the beginning of the compilation unit.
+    uint64_t SecOffset;
+
+    /// An entry of the various gnu_pub* debug sections.
+    dwarf::PubIndexEntryDescriptor Descriptor;
+
+    /// The name of the object as given by the DW_AT_name attribute of the
+    /// referenced DIE.
+    StringRef Name;
+  };
+
+  /// Each table consists of sets of variable length entries. Each set describes
+  /// the names of global objects and functions, or global types, respectively,
+  /// whose definitions are represented by debugging information entries owned
+  /// by a single compilation unit.
+  struct Set {
+    /// The total length of the entries for that set, not including the length
+    /// field itself.
+    uint32_t Length;
+
+    /// This number is specific to the name lookup table and is independent of
+    /// the DWARF version number.
+    uint16_t Version;
+
+    /// The offset from the beginning of the .debug_info section of the
+    /// compilation unit header referenced by the set.
+    uint64_t Offset;
+
+    /// The size in bytes of the contents of the .debug_info section generated
+    /// to represent that compilation unit.
+    uint32_t Size;
+
+    std::vector<Entry> Entries;
+  };
+
+private:
+  std::vector<Set> Sets;
+
+  /// gnu styled tables contains additional information.
+  /// This flag determines whether or not section we parse is debug_gnu* table.
+  bool GnuStyle;
+
+public:
+  DWARFDebugPubTable(const DWARFObject &Obj, const DWARFSection &Sec,
+                     bool LittleEndian, bool GnuStyle);
+
+  void dump(raw_ostream &OS) const;
+
+  ArrayRef<Set> getData() { return Sets; }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGPUBTABLE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h
@@ -0,0 +1,83 @@
+//===- DWARFDebugRangeList.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGRANGELIST_H
+#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGRANGELIST_H
+
+#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include <cassert>
+#include <cstdint>
+#include <vector>
+
+namespace llvm {
+
+class raw_ostream;
+
+class DWARFDebugRangeList {
+public:
+  struct RangeListEntry {
+    /// A beginning address offset. This address offset has the size of an
+    /// address and is relative to the applicable base address of the
+    /// compilation unit referencing this range list. It marks the beginning
+    /// of an address range.
+    uint64_t StartAddress;
+    /// An ending address offset. This address offset again has the size of
+    /// an address and is relative to the applicable base address of the
+    /// compilation unit referencing this range list. It marks the first
+    /// address past the end of the address range. The ending address must
+    /// be greater than or equal to the beginning address.
+    uint64_t EndAddress;
+    /// A section index this range belongs to.
+    uint64_t SectionIndex;
+
+    /// The end of any given range list is marked by an end of list entry,
+    /// which consists of a 0 for the beginning address offset
+    /// and a 0 for the ending address offset.
+    bool isEndOfListEntry() const {
+      return (StartAddress == 0) && (EndAddress == 0);
+    }
+
+    /// A base address selection entry consists of:
+    /// 1. The value of the largest representable address offset
+    /// (for example, 0xffffffff when the size of an address is 32 bits).
+    /// 2. An address, which defines the appropriate base address for
+    /// use in interpreting the beginning and ending address offsets of
+    /// subsequent entries of the location list.
+    bool isBaseAddressSelectionEntry(uint8_t AddressSize) const {
+      assert(AddressSize == 4 || AddressSize == 8);
+      if (AddressSize == 4)
+        return StartAddress == -1U;
+      return StartAddress == -1ULL;
+    }
+  };
+
+private:
+  /// Offset in .debug_ranges section.
+  uint64_t Offset;
+  uint8_t AddressSize;
+  std::vector<RangeListEntry> Entries;
+
+public:
+  DWARFDebugRangeList() { clear(); }
+
+  void clear();
+  void dump(raw_ostream &OS) const;
+  Error extract(const DWARFDataExtractor &data, uint64_t *offset_ptr);
+  const std::vector<RangeListEntry> &getEntries() { return Entries; }
+
+  /// getAbsoluteRanges - Returns absolute address ranges defined by this range
+  /// list. Has to be passed base address of the compile unit referencing this
+  /// range list.
+  DWARFAddressRangesVector
+  getAbsoluteRanges(llvm::Optional<object::SectionedAddress> BaseAddr) const;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGRANGELIST_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h
@@ -0,0 +1,64 @@
+//===- DWARFDebugRnglists.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H
+#define LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFListTable.h"
+#include <cstdint>
+#include <map>
+#include <vector>
+
+namespace llvm {
+
+class Error;
+class raw_ostream;
+class DWARFUnit;
+
+/// A class representing a single range list entry.
+struct RangeListEntry : public DWARFListEntryBase {
+  /// The values making up the range list entry. Most represent a range with
+  /// a start and end address or a start address and a length. Others are
+  /// single value base addresses or end-of-list with no values. The unneeded
+  /// values are semantically undefined, but initialized to 0.
+  uint64_t Value0;
+  uint64_t Value1;
+
+  Error extract(DWARFDataExtractor Data, uint64_t End, uint64_t *OffsetPtr);
+  void dump(raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength,
+            uint64_t &CurrentBase, DIDumpOptions DumpOpts,
+            llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)>
+                LookupPooledAddress) const;
+  bool isSentinel() const { return EntryKind == dwarf::DW_RLE_end_of_list; }
+};
+
+/// A class representing a single rangelist.
+class DWARFDebugRnglist : public DWARFListType<RangeListEntry> {
+public:
+  /// Build a DWARFAddressRangesVector from a rangelist.
+  DWARFAddressRangesVector
+  getAbsoluteRanges(llvm::Optional<object::SectionedAddress> BaseAddr,
+                    DWARFUnit &U) const;
+};
+
+class DWARFDebugRnglistTable : public DWARFListTableBase<DWARFDebugRnglist> {
+public:
+  DWARFDebugRnglistTable()
+      : DWARFListTableBase(/* SectionName    = */ ".debug_rnglists",
+                           /* HeaderString   = */ "ranges:",
+                           /* ListTypeString = */ "range") {}
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDie.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDie.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDie.h
@@ -0,0 +1,468 @@
+//===- DWARFDie.h -----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFDIE_H
+#define LLVM_DEBUGINFO_DWARFDIE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
+#include "llvm/DebugInfo/DWARF/DWARFAttribute.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
+#include <cassert>
+#include <cstdint>
+#include <iterator>
+
+namespace llvm {
+
+class DWARFUnit;
+class raw_ostream;
+
+//===----------------------------------------------------------------------===//
+/// Utility class that carries the DWARF compile/type unit and the debug info
+/// entry in an object.
+///
+/// When accessing information from a debug info entry we always need to DWARF
+/// compile/type unit in order to extract the info correctly as some information
+/// is relative to the compile/type unit. Prior to this class the DWARFUnit and
+/// the DWARFDebugInfoEntry was passed around separately and there was the
+/// possibility for error if the wrong DWARFUnit was used to extract a unit
+/// relative offset. This class helps to ensure that this doesn't happen and
+/// also simplifies the attribute extraction calls by not having to specify the
+/// DWARFUnit for each call.
+class DWARFDie {
+  DWARFUnit *U = nullptr;
+  const DWARFDebugInfoEntry *Die = nullptr;
+
+public:
+  DWARFDie() = default;
+  DWARFDie(DWARFUnit *Unit, const DWARFDebugInfoEntry *D) : U(Unit), Die(D) {}
+
+  bool isValid() const { return U && Die; }
+  explicit operator bool() const { return isValid(); }
+  const DWARFDebugInfoEntry *getDebugInfoEntry() const { return Die; }
+  DWARFUnit *getDwarfUnit() const { return U; }
+
+  /// Get the abbreviation declaration for this DIE.
+  ///
+  /// \returns the abbreviation declaration or NULL for null tags.
+  const DWARFAbbreviationDeclaration *getAbbreviationDeclarationPtr() const {
+    assert(isValid() && "must check validity prior to calling");
+    return Die->getAbbreviationDeclarationPtr();
+  }
+
+  /// Get the absolute offset into the debug info or types section.
+  ///
+  /// \returns the DIE offset or -1U if invalid.
+  uint64_t getOffset() const {
+    assert(isValid() && "must check validity prior to calling");
+    return Die->getOffset();
+  }
+
+  dwarf::Tag getTag() const {
+    auto AbbrevDecl = getAbbreviationDeclarationPtr();
+    if (AbbrevDecl)
+      return AbbrevDecl->getTag();
+    return dwarf::DW_TAG_null;
+  }
+
+  bool hasChildren() const {
+    assert(isValid() && "must check validity prior to calling");
+    return Die->hasChildren();
+  }
+
+  /// Returns true for a valid DIE that terminates a sibling chain.
+  bool isNULL() const { return getAbbreviationDeclarationPtr() == nullptr; }
+
+  /// Returns true if DIE represents a subprogram (not inlined).
+  bool isSubprogramDIE() const;
+
+  /// Returns true if DIE represents a subprogram or an inlined subroutine.
+  bool isSubroutineDIE() const;
+
+  /// Get the parent of this DIE object.
+  ///
+  /// \returns a valid DWARFDie instance if this object has a parent or an
+  /// invalid DWARFDie instance if it doesn't.
+  DWARFDie getParent() const;
+
+  /// Get the sibling of this DIE object.
+  ///
+  /// \returns a valid DWARFDie instance if this object has a sibling or an
+  /// invalid DWARFDie instance if it doesn't.
+  DWARFDie getSibling() const;
+
+  /// Get the previous sibling of this DIE object.
+  ///
+  /// \returns a valid DWARFDie instance if this object has a sibling or an
+  /// invalid DWARFDie instance if it doesn't.
+  DWARFDie getPreviousSibling() const;
+
+  /// Get the first child of this DIE object.
+  ///
+  /// \returns a valid DWARFDie instance if this object has children or an
+  /// invalid DWARFDie instance if it doesn't.
+  DWARFDie getFirstChild() const;
+
+  /// Get the last child of this DIE object.
+  ///
+  /// \returns a valid null DWARFDie instance if this object has children or an
+  /// invalid DWARFDie instance if it doesn't.
+  DWARFDie getLastChild() const;
+
+  /// Dump the DIE and all of its attributes to the supplied stream.
+  ///
+  /// \param OS the stream to use for output.
+  /// \param indent the number of characters to indent each line that is output.
+  void dump(raw_ostream &OS, unsigned indent = 0,
+            DIDumpOptions DumpOpts = DIDumpOptions()) const;
+
+  /// Convenience zero-argument overload for debugging.
+  LLVM_DUMP_METHOD void dump() const;
+
+  /// Extract the specified attribute from this DIE.
+  ///
+  /// Extract an attribute value from this DIE only. This call doesn't look
+  /// for the attribute value in any DW_AT_specification or
+  /// DW_AT_abstract_origin referenced DIEs.
+  ///
+  /// \param Attr the attribute to extract.
+  /// \returns an optional DWARFFormValue that will have the form value if the
+  /// attribute was successfully extracted.
+  Optional<DWARFFormValue> find(dwarf::Attribute Attr) const;
+
+  /// Extract the first value of any attribute in Attrs from this DIE.
+  ///
+  /// Extract the first attribute that matches from this DIE only. This call
+  /// doesn't look for the attribute value in any DW_AT_specification or
+  /// DW_AT_abstract_origin referenced DIEs. The attributes will be searched
+  /// linearly in the order they are specified within Attrs.
+  ///
+  /// \param Attrs an array of DWARF attribute to look for.
+  /// \returns an optional that has a valid DWARFFormValue for the first
+  /// matching attribute in Attrs, or None if none of the attributes in Attrs
+  /// exist in this DIE.
+  Optional<DWARFFormValue> find(ArrayRef<dwarf::Attribute> Attrs) const;
+
+  /// Extract the first value of any attribute in Attrs from this DIE and
+  /// recurse into any DW_AT_specification or DW_AT_abstract_origin referenced
+  /// DIEs.
+  ///
+  /// \param Attrs an array of DWARF attribute to look for.
+  /// \returns an optional that has a valid DWARFFormValue for the first
+  /// matching attribute in Attrs, or None if none of the attributes in Attrs
+  /// exist in this DIE or in any DW_AT_specification or DW_AT_abstract_origin
+  /// DIEs.
+  Optional<DWARFFormValue>
+  findRecursively(ArrayRef<dwarf::Attribute> Attrs) const;
+
+  /// Extract the specified attribute from this DIE as the referenced DIE.
+  ///
+  /// Regardless of the reference type, return the correct DWARFDie instance if
+  /// the attribute exists. The returned DWARFDie object might be from another
+  /// DWARFUnit, but that is all encapsulated in the new DWARFDie object.
+  ///
+  /// Extract an attribute value from this DIE only. This call doesn't look
+  /// for the attribute value in any DW_AT_specification or
+  /// DW_AT_abstract_origin referenced DIEs.
+  ///
+  /// \param Attr the attribute to extract.
+  /// \returns a valid DWARFDie instance if the attribute exists, or an invalid
+  /// DWARFDie object if it doesn't.
+  DWARFDie getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const;
+  DWARFDie getAttributeValueAsReferencedDie(const DWARFFormValue &V) const;
+
+  /// Extract the range base attribute from this DIE as absolute section offset.
+  ///
+  /// This is a utility function that checks for either the DW_AT_rnglists_base
+  /// or DW_AT_GNU_ranges_base attribute.
+  ///
+  /// \returns anm optional absolute section offset value for the attribute.
+  Optional<uint64_t> getRangesBaseAttribute() const;
+
+  /// Get the DW_AT_high_pc attribute value as an address.
+  ///
+  /// In DWARF version 4 and later the high PC can be encoded as an offset from
+  /// the DW_AT_low_pc. This function takes care of extracting the value as an
+  /// address or offset and adds it to the low PC if needed and returns the
+  /// value as an optional in case the DIE doesn't have a DW_AT_high_pc
+  /// attribute.
+  ///
+  /// \param LowPC the low PC that might be needed to calculate the high PC.
+  /// \returns an optional address value for the attribute.
+  Optional<uint64_t> getHighPC(uint64_t LowPC) const;
+
+  /// Retrieves DW_AT_low_pc and DW_AT_high_pc from CU.
+  /// Returns true if both attributes are present.
+  bool getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC,
+                       uint64_t &SectionIndex) const;
+
+  /// Get the address ranges for this DIE.
+  ///
+  /// Get the hi/low PC range if both attributes are available or exrtracts the
+  /// non-contiguous address ranges from the DW_AT_ranges attribute.
+  ///
+  /// Extracts the range information from this DIE only. This call doesn't look
+  /// for the range in any DW_AT_specification or DW_AT_abstract_origin DIEs.
+  ///
+  /// \returns a address range vector that might be empty if no address range
+  /// information is available.
+  Expected<DWARFAddressRangesVector> getAddressRanges() const;
+
+  /// Get all address ranges for any DW_TAG_subprogram DIEs in this DIE or any
+  /// of its children.
+  ///
+  /// Get the hi/low PC range if both attributes are available or exrtracts the
+  /// non-contiguous address ranges from the DW_AT_ranges attribute for this DIE
+  /// and all children.
+  ///
+  /// \param Ranges the addres range vector to fill in.
+  void collectChildrenAddressRanges(DWARFAddressRangesVector &Ranges) const;
+
+  bool addressRangeContainsAddress(const uint64_t Address) const;
+
+  /// If a DIE represents a subprogram (or inlined subroutine), returns its
+  /// mangled name (or short name, if mangled is missing). This name may be
+  /// fetched from specification or abstract origin for this subprogram.
+  /// Returns null if no name is found.
+  const char *getSubroutineName(DINameKind Kind) const;
+
+  /// Return the DIE name resolving DW_AT_sepcification or DW_AT_abstract_origin
+  /// references if necessary. Returns null if no name is found.
+  const char *getName(DINameKind Kind) const;
+
+  /// Returns the declaration line (start line) for a DIE, assuming it specifies
+  /// a subprogram. This may be fetched from specification or abstract origin
+  /// for this subprogram by resolving DW_AT_sepcification or
+  /// DW_AT_abstract_origin references if necessary.
+  uint64_t getDeclLine() const;
+
+  /// Retrieves values of DW_AT_call_file, DW_AT_call_line and DW_AT_call_column
+  /// from DIE (or zeroes if they are missing). This function looks for
+  /// DW_AT_call attributes in this DIE only, it will not resolve the attribute
+  /// values in any DW_AT_specification or DW_AT_abstract_origin DIEs.
+  /// \param CallFile filled in with non-zero if successful, zero if there is no
+  /// DW_AT_call_file attribute in this DIE.
+  /// \param CallLine filled in with non-zero if successful, zero if there is no
+  /// DW_AT_call_line attribute in this DIE.
+  /// \param CallColumn filled in with non-zero if successful, zero if there is
+  /// no DW_AT_call_column attribute in this DIE.
+  /// \param CallDiscriminator filled in with non-zero if successful, zero if
+  /// there is no DW_AT_GNU_discriminator attribute in this DIE.
+  void getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
+                      uint32_t &CallColumn, uint32_t &CallDiscriminator) const;
+
+  class attribute_iterator;
+
+  /// Get an iterator range to all attributes in the current DIE only.
+  ///
+  /// \returns an iterator range for the attributes of the current DIE.
+  iterator_range<attribute_iterator> attributes() const;
+
+  class iterator;
+
+  iterator begin() const;
+  iterator end() const;
+
+  std::reverse_iterator<iterator> rbegin() const;
+  std::reverse_iterator<iterator> rend() const;
+
+  iterator_range<iterator> children() const;
+};
+
+class DWARFDie::attribute_iterator
+    : public iterator_facade_base<attribute_iterator, std::forward_iterator_tag,
+                                  const DWARFAttribute> {
+  /// The DWARF DIE we are extracting attributes from.
+  DWARFDie Die;
+  /// The value vended to clients via the operator*() or operator->().
+  DWARFAttribute AttrValue;
+  /// The attribute index within the abbreviation declaration in Die.
+  uint32_t Index;
+
+  friend bool operator==(const attribute_iterator &LHS,
+                         const attribute_iterator &RHS);
+
+  /// Update the attribute index and attempt to read the attribute value. If the
+  /// attribute is able to be read, update AttrValue and the Index member
+  /// variable. If the attribute value is not able to be read, an appropriate
+  /// error will be set if the Err member variable is non-NULL and the iterator
+  /// will be set to the end value so iteration stops.
+  void updateForIndex(const DWARFAbbreviationDeclaration &AbbrDecl, uint32_t I);
+
+public:
+  attribute_iterator() = delete;
+  explicit attribute_iterator(DWARFDie D, bool End);
+
+  attribute_iterator &operator++();
+  attribute_iterator &operator--();
+  explicit operator bool() const { return AttrValue.isValid(); }
+  const DWARFAttribute &operator*() const { return AttrValue; }
+};
+
+inline bool operator==(const DWARFDie::attribute_iterator &LHS,
+                       const DWARFDie::attribute_iterator &RHS) {
+  return LHS.Index == RHS.Index;
+}
+
+inline bool operator!=(const DWARFDie::attribute_iterator &LHS,
+                       const DWARFDie::attribute_iterator &RHS) {
+  return !(LHS == RHS);
+}
+
+inline bool operator==(const DWARFDie &LHS, const DWARFDie &RHS) {
+  return LHS.getDebugInfoEntry() == RHS.getDebugInfoEntry() &&
+         LHS.getDwarfUnit() == RHS.getDwarfUnit();
+}
+
+inline bool operator!=(const DWARFDie &LHS, const DWARFDie &RHS) {
+  return !(LHS == RHS);
+}
+
+inline bool operator<(const DWARFDie &LHS, const DWARFDie &RHS) {
+  return LHS.getOffset() < RHS.getOffset();
+}
+
+class DWARFDie::iterator
+    : public iterator_facade_base<iterator, std::bidirectional_iterator_tag,
+                                  const DWARFDie> {
+  DWARFDie Die;
+
+  friend std::reverse_iterator<llvm::DWARFDie::iterator>;
+  friend bool operator==(const DWARFDie::iterator &LHS,
+                         const DWARFDie::iterator &RHS);
+
+public:
+  iterator() = default;
+
+  explicit iterator(DWARFDie D) : Die(D) {}
+
+  iterator &operator++() {
+    Die = Die.getSibling();
+    return *this;
+  }
+
+  iterator &operator--() {
+    Die = Die.getPreviousSibling();
+    return *this;
+  }
+
+  const DWARFDie &operator*() const { return Die; }
+};
+
+inline bool operator==(const DWARFDie::iterator &LHS,
+                       const DWARFDie::iterator &RHS) {
+  return LHS.Die == RHS.Die;
+}
+
+inline bool operator!=(const DWARFDie::iterator &LHS,
+                       const DWARFDie::iterator &RHS) {
+  return !(LHS == RHS);
+}
+
+// These inline functions must follow the DWARFDie::iterator definition above
+// as they use functions from that class.
+inline DWARFDie::iterator DWARFDie::begin() const {
+  return iterator(getFirstChild());
+}
+
+inline DWARFDie::iterator DWARFDie::end() const {
+  return iterator(getLastChild());
+}
+
+inline iterator_range<DWARFDie::iterator> DWARFDie::children() const {
+  return make_range(begin(), end());
+}
+
+} // end namespace llvm
+
+namespace std {
+
+template <>
+class reverse_iterator<llvm::DWARFDie::iterator>
+    : public llvm::iterator_facade_base<
+          reverse_iterator<llvm::DWARFDie::iterator>,
+          bidirectional_iterator_tag, const llvm::DWARFDie> {
+
+private:
+  llvm::DWARFDie Die;
+  bool AtEnd;
+
+public:
+  reverse_iterator(llvm::DWARFDie::iterator It)
+      : Die(It.Die), AtEnd(!It.Die.getPreviousSibling()) {
+    if (!AtEnd)
+      Die = Die.getPreviousSibling();
+  }
+
+  llvm::DWARFDie::iterator base() const {
+    return llvm::DWARFDie::iterator(AtEnd ? Die : Die.getSibling());
+  }
+
+  reverse_iterator<llvm::DWARFDie::iterator> &operator++() {
+    assert(!AtEnd && "Incrementing rend");
+    llvm::DWARFDie D = Die.getPreviousSibling();
+    if (D)
+      Die = D;
+    else
+      AtEnd = true;
+    return *this;
+  }
+
+  reverse_iterator<llvm::DWARFDie::iterator> &operator--() {
+    if (AtEnd) {
+      AtEnd = false;
+      return *this;
+    }
+    Die = Die.getSibling();
+    assert(!Die.isNULL() && "Decrementing rbegin");
+    return *this;
+  }
+
+  const llvm::DWARFDie &operator*() const {
+    assert(Die.isValid());
+    return Die;
+  }
+
+  // FIXME: We should be able to specify the equals operator as a friend, but
+  //        that causes the compiler to think the operator overload is ambiguous
+  //        with the friend declaration and the actual definition as candidates.
+  bool equals(const reverse_iterator<llvm::DWARFDie::iterator> &RHS) const {
+    return Die == RHS.Die && AtEnd == RHS.AtEnd;
+  }
+};
+
+} // namespace std
+
+namespace llvm {
+
+inline bool operator==(const std::reverse_iterator<DWARFDie::iterator> &LHS,
+                       const std::reverse_iterator<DWARFDie::iterator> &RHS) {
+  return LHS.equals(RHS);
+}
+
+inline bool operator!=(const std::reverse_iterator<DWARFDie::iterator> &LHS,
+                       const std::reverse_iterator<DWARFDie::iterator> &RHS) {
+  return !(LHS == RHS);
+}
+
+inline std::reverse_iterator<DWARFDie::iterator> DWARFDie::rbegin() const {
+  return llvm::make_reverse_iterator(end());
+}
+
+inline std::reverse_iterator<DWARFDie::iterator> DWARFDie::rend() const {
+  return llvm::make_reverse_iterator(begin());
+}
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARFDIE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFExpression.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFExpression.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFExpression.h
@@ -0,0 +1,159 @@
+//===--- DWARFExpression.h - DWARF Expression handling ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFEXPRESSION_H
+#define LLVM_DEBUGINFO_DWARFEXPRESSION_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/DataExtractor.h"
+
+namespace llvm {
+class DWARFUnit;
+class MCRegisterInfo;
+class raw_ostream;
+
+class DWARFExpression {
+public:
+  class iterator;
+
+  /// This class represents an Operation in the Expression. Each operation can
+  /// have up to 2 oprerands.
+  ///
+  /// An Operation can be in Error state (check with isError()). This
+  /// means that it couldn't be decoded successfully and if it is the
+  /// case, all others fields contain undefined values.
+  class Operation {
+  public:
+    /// Size and signedness of expression operations' operands.
+    enum Encoding : uint8_t {
+      Size1 = 0,
+      Size2 = 1,
+      Size4 = 2,
+      Size8 = 3,
+      SizeLEB = 4,
+      SizeAddr = 5,
+      SizeRefAddr = 6,
+      SizeBlock = 7, ///< Preceding operand contains block size
+      BaseTypeRef = 8,
+      SignBit = 0x80,
+      SignedSize1 = SignBit | Size1,
+      SignedSize2 = SignBit | Size2,
+      SignedSize4 = SignBit | Size4,
+      SignedSize8 = SignBit | Size8,
+      SignedSizeLEB = SignBit | SizeLEB,
+      SizeNA = 0xFF ///< Unused operands get this encoding.
+    };
+
+    enum DwarfVersion : uint8_t {
+      DwarfNA, ///< Serves as a marker for unused entries
+      Dwarf2 = 2,
+      Dwarf3,
+      Dwarf4,
+      Dwarf5
+    };
+
+    /// Description of the encoding of one expression Op.
+    struct Description {
+      DwarfVersion Version; ///< Dwarf version where the Op was introduced.
+      Encoding Op[2];       ///< Encoding for Op operands, or SizeNA.
+
+      Description(DwarfVersion Version = DwarfNA, Encoding Op1 = SizeNA,
+                  Encoding Op2 = SizeNA)
+          : Version(Version) {
+        Op[0] = Op1;
+        Op[1] = Op2;
+      }
+    };
+
+  private:
+    friend class DWARFExpression::iterator;
+    uint8_t Opcode; ///< The Op Opcode, DW_OP_<something>.
+    Description Desc;
+    bool Error;
+    uint64_t EndOffset;
+    uint64_t Operands[2];
+    uint64_t OperandEndOffsets[2];
+
+  public:
+    Description &getDescription() { return Desc; }
+    uint8_t getCode() { return Opcode; }
+    uint64_t getRawOperand(unsigned Idx) { return Operands[Idx]; }
+    uint64_t getOperandEndOffset(unsigned Idx) { return OperandEndOffsets[Idx]; }
+    uint64_t getEndOffset() { return EndOffset; }
+    bool extract(DataExtractor Data, uint16_t Version, uint8_t AddressSize,
+                 uint64_t Offset);
+    bool isError() { return Error; }
+    bool print(raw_ostream &OS, const DWARFExpression *Expr,
+               const MCRegisterInfo *RegInfo, DWARFUnit *U, bool isEH);
+    bool verify(DWARFUnit *U);
+  };
+
+  /// An iterator to go through the expression operations.
+  class iterator
+      : public iterator_facade_base<iterator, std::forward_iterator_tag,
+                                    Operation> {
+    friend class DWARFExpression;
+    const DWARFExpression *Expr;
+    uint64_t Offset;
+    Operation Op;
+    iterator(const DWARFExpression *Expr, uint64_t Offset)
+        : Expr(Expr), Offset(Offset) {
+      Op.Error =
+          Offset >= Expr->Data.getData().size() ||
+          !Op.extract(Expr->Data, Expr->Version, Expr->AddressSize, Offset);
+    }
+
+  public:
+    class Operation &operator++() {
+      Offset = Op.isError() ? Expr->Data.getData().size() : Op.EndOffset;
+      Op.Error =
+          Offset >= Expr->Data.getData().size() ||
+          !Op.extract(Expr->Data, Expr->Version, Expr->AddressSize, Offset);
+      return Op;
+    }
+
+    class Operation &operator*() {
+      return Op;
+    }
+
+    // Comparison operators are provided out of line.
+    friend bool operator==(const iterator &, const iterator &);
+  };
+
+  DWARFExpression(DataExtractor Data, uint16_t Version, uint8_t AddressSize)
+      : Data(Data), Version(Version), AddressSize(AddressSize) {
+    assert(AddressSize == 8 || AddressSize == 4 || AddressSize == 2);
+  }
+
+  iterator begin() const { return iterator(this, 0); }
+  iterator end() const { return iterator(this, Data.getData().size()); }
+
+  void print(raw_ostream &OS, const MCRegisterInfo *RegInfo, DWARFUnit *U,
+             bool IsEH = false) const;
+
+  bool verify(DWARFUnit *U);
+
+private:
+  DataExtractor Data;
+  uint16_t Version;
+  uint8_t AddressSize;
+};
+
+inline bool operator==(const DWARFExpression::iterator &LHS,
+                       const DWARFExpression::iterator &RHS) {
+  return LHS.Expr == RHS.Expr && LHS.Offset == RHS.Offset;
+}
+
+inline bool operator!=(const DWARFExpression::iterator &LHS,
+                       const DWARFExpression::iterator &RHS) {
+  return !(LHS == RHS);
+}
+}
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFFormValue.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFFormValue.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFFormValue.h
@@ -0,0 +1,321 @@
+//===- DWARFFormValue.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFFORMVALUE_H
+#define LLVM_DEBUGINFO_DWARFFORMVALUE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include <cstdint>
+
+namespace llvm {
+
+class DWARFContext;
+class DWARFUnit;
+class raw_ostream;
+
+class DWARFFormValue {
+public:
+  enum FormClass {
+    FC_Unknown,
+    FC_Address,
+    FC_Block,
+    FC_Constant,
+    FC_String,
+    FC_Flag,
+    FC_Reference,
+    FC_Indirect,
+    FC_SectionOffset,
+    FC_Exprloc
+  };
+
+private:
+  struct ValueType {
+    ValueType() { uval = 0; }
+    ValueType(int64_t V) : sval(V) {}
+    ValueType(uint64_t V) : uval(V) {}
+    ValueType(const char *V) : cstr(V) {}
+
+    union {
+      uint64_t uval;
+      int64_t sval;
+      const char *cstr;
+    };
+    const uint8_t *data = nullptr;
+    uint64_t SectionIndex;      /// Section index for reference forms.
+  };
+
+  dwarf::Form Form;             /// Form for this value.
+  ValueType Value;              /// Contains all data for the form.
+  const DWARFUnit *U = nullptr; /// Remember the DWARFUnit at extract time.
+  const DWARFContext *C = nullptr; /// Context for extract time.
+
+  DWARFFormValue(dwarf::Form F, ValueType V) : Form(F), Value(V) {}
+
+public:
+  DWARFFormValue(dwarf::Form F = dwarf::Form(0)) : Form(F) {}
+
+  static DWARFFormValue createFromSValue(dwarf::Form F, int64_t V);
+  static DWARFFormValue createFromUValue(dwarf::Form F, uint64_t V);
+  static DWARFFormValue createFromPValue(dwarf::Form F, const char *V);
+  static DWARFFormValue createFromBlockValue(dwarf::Form F,
+                                             ArrayRef<uint8_t> D);
+  static DWARFFormValue createFromUnit(dwarf::Form F, const DWARFUnit *Unit,
+                                       uint64_t *OffsetPtr);
+
+  dwarf::Form getForm() const { return Form; }
+  uint64_t getRawUValue() const { return Value.uval; }
+
+  bool isFormClass(FormClass FC) const;
+  const DWARFUnit *getUnit() const { return U; }
+  void dump(raw_ostream &OS, DIDumpOptions DumpOpts = DIDumpOptions()) const;
+  void dumpSectionedAddress(raw_ostream &OS, DIDumpOptions DumpOpts,
+                            object::SectionedAddress SA) const;
+  static void dumpAddressSection(const DWARFObject &Obj, raw_ostream &OS,
+                                 DIDumpOptions DumpOpts, uint64_t SectionIndex);
+
+  /// Extracts a value in \p Data at offset \p *OffsetPtr. The information
+  /// in \p FormParams is needed to interpret some forms. The optional
+  /// \p Context and \p Unit allows extracting information if the form refers
+  /// to other sections (e.g., .debug_str).
+  bool extractValue(const DWARFDataExtractor &Data, uint64_t *OffsetPtr,
+                    dwarf::FormParams FormParams,
+                    const DWARFContext *Context = nullptr,
+                    const DWARFUnit *Unit = nullptr);
+
+  bool extractValue(const DWARFDataExtractor &Data, uint64_t *OffsetPtr,
+                    dwarf::FormParams FormParams, const DWARFUnit *U) {
+    return extractValue(Data, OffsetPtr, FormParams, nullptr, U);
+  }
+
+  bool isInlinedCStr() const {
+    return Value.data != nullptr && Value.data == (const uint8_t *)Value.cstr;
+  }
+
+  /// getAsFoo functions below return the extracted value as Foo if only
+  /// DWARFFormValue has form class is suitable for representing Foo.
+  Optional<uint64_t> getAsReference() const;
+  struct UnitOffset {
+    DWARFUnit *Unit;
+    uint64_t Offset;
+  };
+  Optional<UnitOffset> getAsRelativeReference() const;
+  Optional<uint64_t> getAsUnsignedConstant() const;
+  Optional<int64_t> getAsSignedConstant() const;
+  Optional<const char *> getAsCString() const;
+  Optional<uint64_t> getAsAddress() const;
+  Optional<object::SectionedAddress> getAsSectionedAddress() const;
+  Optional<uint64_t> getAsSectionOffset() const;
+  Optional<ArrayRef<uint8_t>> getAsBlock() const;
+  Optional<uint64_t> getAsCStringOffset() const;
+  Optional<uint64_t> getAsReferenceUVal() const;
+
+  /// Skip a form's value in \p DebugInfoData at the offset specified by
+  /// \p OffsetPtr.
+  ///
+  /// Skips the bytes for the current form and updates the offset.
+  ///
+  /// \param DebugInfoData The data where we want to skip the value.
+  /// \param OffsetPtr A reference to the offset that will be updated.
+  /// \param Params DWARF parameters to help interpret forms.
+  /// \returns true on success, false if the form was not skipped.
+  bool skipValue(DataExtractor DebugInfoData, uint64_t *OffsetPtr,
+                 const dwarf::FormParams Params) const {
+    return DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, Params);
+  }
+
+  /// Skip a form's value in \p DebugInfoData at the offset specified by
+  /// \p OffsetPtr.
+  ///
+  /// Skips the bytes for the specified form and updates the offset.
+  ///
+  /// \param Form The DW_FORM enumeration that indicates the form to skip.
+  /// \param DebugInfoData The data where we want to skip the value.
+  /// \param OffsetPtr A reference to the offset that will be updated.
+  /// \param FormParams DWARF parameters to help interpret forms.
+  /// \returns true on success, false if the form was not skipped.
+  static bool skipValue(dwarf::Form Form, DataExtractor DebugInfoData,
+                        uint64_t *OffsetPtr,
+                        const dwarf::FormParams FormParams);
+
+private:
+  void dumpString(raw_ostream &OS) const;
+};
+
+namespace dwarf {
+
+/// Take an optional DWARFFormValue and try to extract a string value from it.
+///
+/// \param V and optional DWARFFormValue to attempt to extract the value from.
+/// \returns an optional value that contains a value if the form value
+/// was valid and was a string.
+inline Optional<const char *> toString(const Optional<DWARFFormValue> &V) {
+  if (V)
+    return V->getAsCString();
+  return None;
+}
+
+/// Take an optional DWARFFormValue and try to extract a string value from it.
+///
+/// \param V and optional DWARFFormValue to attempt to extract the value from.
+/// \returns an optional value that contains a value if the form value
+/// was valid and was a string.
+inline StringRef toStringRef(const Optional<DWARFFormValue> &V,
+                             StringRef Default = {}) {
+  if (V)
+    if (auto S = V->getAsCString())
+      return *S;
+  return Default;
+}
+
+/// Take an optional DWARFFormValue and extract a string value from it.
+///
+/// \param V and optional DWARFFormValue to attempt to extract the value from.
+/// \param Default the default value to return in case of failure.
+/// \returns the string value or Default if the V doesn't have a value or the
+/// form value's encoding wasn't a string.
+inline const char *toString(const Optional<DWARFFormValue> &V,
+                            const char *Default) {
+  return toString(V).getValueOr(Default);
+}
+
+/// Take an optional DWARFFormValue and try to extract an unsigned constant.
+///
+/// \param V and optional DWARFFormValue to attempt to extract the value from.
+/// \returns an optional value that contains a value if the form value
+/// was valid and has a unsigned constant form.
+inline Optional<uint64_t> toUnsigned(const Optional<DWARFFormValue> &V) {
+  if (V)
+    return V->getAsUnsignedConstant();
+  return None;
+}
+
+/// Take an optional DWARFFormValue and extract a unsigned constant.
+///
+/// \param V and optional DWARFFormValue to attempt to extract the value from.
+/// \param Default the default value to return in case of failure.
+/// \returns the extracted unsigned value or Default if the V doesn't have a
+/// value or the form value's encoding wasn't an unsigned constant form.
+inline uint64_t toUnsigned(const Optional<DWARFFormValue> &V,
+                           uint64_t Default) {
+  return toUnsigned(V).getValueOr(Default);
+}
+
+/// Take an optional DWARFFormValue and try to extract an reference.
+///
+/// \param V and optional DWARFFormValue to attempt to extract the value from.
+/// \returns an optional value that contains a value if the form value
+/// was valid and has a reference form.
+inline Optional<uint64_t> toReference(const Optional<DWARFFormValue> &V) {
+  if (V)
+    return V->getAsReference();
+  return None;
+}
+
+/// Take an optional DWARFFormValue and extract a reference.
+///
+/// \param V and optional DWARFFormValue to attempt to extract the value from.
+/// \param Default the default value to return in case of failure.
+/// \returns the extracted reference value or Default if the V doesn't have a
+/// value or the form value's encoding wasn't a reference form.
+inline uint64_t toReference(const Optional<DWARFFormValue> &V,
+                            uint64_t Default) {
+  return toReference(V).getValueOr(Default);
+}
+
+/// Take an optional DWARFFormValue and try to extract an signed constant.
+///
+/// \param V and optional DWARFFormValue to attempt to extract the value from.
+/// \returns an optional value that contains a value if the form value
+/// was valid and has a signed constant form.
+inline Optional<int64_t> toSigned(const Optional<DWARFFormValue> &V) {
+  if (V)
+    return V->getAsSignedConstant();
+  return None;
+}
+
+/// Take an optional DWARFFormValue and extract a signed integer.
+///
+/// \param V and optional DWARFFormValue to attempt to extract the value from.
+/// \param Default the default value to return in case of failure.
+/// \returns the extracted signed integer value or Default if the V doesn't
+/// have a value or the form value's encoding wasn't a signed integer form.
+inline int64_t toSigned(const Optional<DWARFFormValue> &V, int64_t Default) {
+  return toSigned(V).getValueOr(Default);
+}
+
+/// Take an optional DWARFFormValue and try to extract an address.
+///
+/// \param V and optional DWARFFormValue to attempt to extract the value from.
+/// \returns an optional value that contains a value if the form value
+/// was valid and has a address form.
+inline Optional<uint64_t> toAddress(const Optional<DWARFFormValue> &V) {
+  if (V)
+    return V->getAsAddress();
+  return None;
+}
+
+inline Optional<object::SectionedAddress>
+toSectionedAddress(const Optional<DWARFFormValue> &V) {
+  if (V)
+    return V->getAsSectionedAddress();
+  return None;
+}
+
+/// Take an optional DWARFFormValue and extract a address.
+///
+/// \param V and optional DWARFFormValue to attempt to extract the value from.
+/// \param Default the default value to return in case of failure.
+/// \returns the extracted address value or Default if the V doesn't have a
+/// value or the form value's encoding wasn't an address form.
+inline uint64_t toAddress(const Optional<DWARFFormValue> &V, uint64_t Default) {
+  return toAddress(V).getValueOr(Default);
+}
+
+/// Take an optional DWARFFormValue and try to extract an section offset.
+///
+/// \param V and optional DWARFFormValue to attempt to extract the value from.
+/// \returns an optional value that contains a value if the form value
+/// was valid and has a section offset form.
+inline Optional<uint64_t> toSectionOffset(const Optional<DWARFFormValue> &V) {
+  if (V)
+    return V->getAsSectionOffset();
+  return None;
+}
+
+/// Take an optional DWARFFormValue and extract a section offset.
+///
+/// \param V and optional DWARFFormValue to attempt to extract the value from.
+/// \param Default the default value to return in case of failure.
+/// \returns the extracted section offset value or Default if the V doesn't
+/// have a value or the form value's encoding wasn't a section offset form.
+inline uint64_t toSectionOffset(const Optional<DWARFFormValue> &V,
+                                uint64_t Default) {
+  return toSectionOffset(V).getValueOr(Default);
+}
+
+/// Take an optional DWARFFormValue and try to extract block data.
+///
+/// \param V and optional DWARFFormValue to attempt to extract the value from.
+/// \returns an optional value that contains a value if the form value
+/// was valid and has a block form.
+inline Optional<ArrayRef<uint8_t>> toBlock(const Optional<DWARFFormValue> &V) {
+  if (V)
+    return V->getAsBlock();
+  return None;
+}
+
+} // end namespace dwarf
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARFFORMVALUE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFGdbIndex.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFGdbIndex.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFGdbIndex.h
@@ -0,0 +1,82 @@
+//===- DWARFGdbIndex.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFGDBINDEX_H
+#define LLVM_DEBUGINFO_DWARF_DWARFGDBINDEX_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataExtractor.h"
+#include <cstdint>
+#include <utility>
+
+namespace llvm {
+
+class raw_ostream;
+
+class DWARFGdbIndex {
+  uint32_t Version;
+
+  uint32_t CuListOffset;
+  uint32_t TuListOffset;
+  uint32_t AddressAreaOffset;
+  uint32_t SymbolTableOffset;
+  uint32_t ConstantPoolOffset;
+
+  struct CompUnitEntry {
+    uint64_t Offset; /// Offset of a CU in the .debug_info section.
+    uint64_t Length; /// Length of that CU.
+  };
+  SmallVector<CompUnitEntry, 0> CuList;
+
+  struct TypeUnitEntry {
+    uint64_t Offset;
+    uint64_t TypeOffset;
+    uint64_t TypeSignature;
+  };
+  SmallVector<TypeUnitEntry, 0> TuList;
+
+  struct AddressEntry {
+    uint64_t LowAddress;  /// The low address.
+    uint64_t HighAddress; /// The high address.
+    uint32_t CuIndex;     /// The CU index.
+  };
+  SmallVector<AddressEntry, 0> AddressArea;
+
+  struct SymTableEntry {
+    uint32_t NameOffset; /// Offset of the symbol's name in the constant pool.
+    uint32_t VecOffset;  /// Offset of the CU vector in the constant pool.
+  };
+  SmallVector<SymTableEntry, 0> SymbolTable;
+
+  /// Each value is CU index + attributes.
+  SmallVector<std::pair<uint32_t, SmallVector<uint32_t, 0>>, 0>
+      ConstantPoolVectors;
+
+  StringRef ConstantPoolStrings;
+  uint32_t StringPoolOffset;
+
+  void dumpCUList(raw_ostream &OS) const;
+  void dumpTUList(raw_ostream &OS) const;
+  void dumpAddressArea(raw_ostream &OS) const;
+  void dumpSymbolTable(raw_ostream &OS) const;
+  void dumpConstantPool(raw_ostream &OS) const;
+
+  bool parseImpl(DataExtractor Data);
+
+public:
+  void dump(raw_ostream &OS);
+  void parse(DataExtractor Data);
+
+  bool HasContent = false;
+  bool HasError = false;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFGDBINDEX_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFListTable.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFListTable.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFListTable.h
@@ -0,0 +1,290 @@
+//===- DWARFListTable.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFLISTTABLE_H
+#define LLVM_DEBUGINFO_DWARFLISTTABLE_H
+
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+#include <map>
+#include <vector>
+
+namespace llvm {
+
+/// A base class for DWARF list entries, such as range or location list
+/// entries.
+struct DWARFListEntryBase {
+  /// The offset at which the entry is located in the section.
+  uint64_t Offset;
+  /// The DWARF encoding (DW_RLE_* or DW_LLE_*).
+  uint8_t EntryKind;
+  /// The index of the section this entry belongs to.
+  uint64_t SectionIndex;
+};
+
+/// A base class for lists of entries that are extracted from a particular
+/// section, such as range lists or location lists.
+template <typename ListEntryType> class DWARFListType {
+  using EntryType = ListEntryType;
+  using ListEntries = std::vector<EntryType>;
+
+protected:
+  ListEntries Entries;
+
+public:
+  const ListEntries &getEntries() const { return Entries; }
+  bool empty() const { return Entries.empty(); }
+  void clear() { Entries.clear(); }
+  Error extract(DWARFDataExtractor Data, uint64_t HeaderOffset, uint64_t End,
+                uint64_t *OffsetPtr, StringRef SectionName,
+                StringRef ListStringName);
+};
+
+/// A class representing the header of a list table such as the range list
+/// table in the .debug_rnglists section.
+class DWARFListTableHeader {
+  struct Header {
+    /// The total length of the entries for this table, not including the length
+    /// field itself.
+    uint64_t Length = 0;
+    /// The DWARF version number.
+    uint16_t Version;
+    /// The size in bytes of an address on the target architecture. For
+    /// segmented addressing, this is the size of the offset portion of the
+    /// address.
+    uint8_t AddrSize;
+    /// The size in bytes of a segment selector on the target architecture.
+    /// If the target system uses a flat address space, this value is 0.
+    uint8_t SegSize;
+    /// The number of offsets that follow the header before the range lists.
+    uint32_t OffsetEntryCount;
+  };
+
+  Header HeaderData;
+  /// The offset table, which contains offsets to the individual list entries.
+  /// It is used by forms such as DW_FORM_rnglistx.
+  /// FIXME: Generate the table and use the appropriate forms.
+  std::vector<uint64_t> Offsets;
+  /// The table's format, either DWARF32 or DWARF64.
+  dwarf::DwarfFormat Format;
+  /// The offset at which the header (and hence the table) is located within
+  /// its section.
+  uint64_t HeaderOffset;
+  /// The name of the section the list is located in.
+  StringRef SectionName;
+  /// A characterization of the list for dumping purposes, e.g. "range" or
+  /// "location".
+  StringRef ListTypeString;
+
+public:
+  DWARFListTableHeader(StringRef SectionName, StringRef ListTypeString)
+      : SectionName(SectionName), ListTypeString(ListTypeString) {}
+
+  void clear() {
+    HeaderData = {};
+    Offsets.clear();
+  }
+  uint64_t getHeaderOffset() const { return HeaderOffset; }
+  uint8_t getAddrSize() const { return HeaderData.AddrSize; }
+  uint64_t getLength() const { return HeaderData.Length; }
+  uint16_t getVersion() const { return HeaderData.Version; }
+  StringRef getSectionName() const { return SectionName; }
+  StringRef getListTypeString() const { return ListTypeString; }
+  dwarf::DwarfFormat getFormat() const { return Format; }
+
+  /// Return the size of the table header including the length but not including
+  /// the offsets.
+  static uint8_t getHeaderSize(dwarf::DwarfFormat Format) {
+    switch (Format) {
+    case dwarf::DwarfFormat::DWARF32:
+      return 12;
+    case dwarf::DwarfFormat::DWARF64:
+      return 20;
+    }
+    llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64");
+  }
+
+  void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}) const;
+  Optional<uint64_t> getOffsetEntry(uint32_t Index) const {
+    if (Index < Offsets.size())
+      return Offsets[Index];
+    return None;
+  }
+
+  /// Extract the table header and the array of offsets.
+  Error extract(DWARFDataExtractor Data, uint64_t *OffsetPtr);
+
+  /// Returns the length of the table, including the length field, or 0 if the
+  /// length has not been determined (e.g. because the table has not yet been
+  /// parsed, or there was a problem in parsing).
+  uint64_t length() const;
+};
+
+/// A class representing a table of lists as specified in the DWARF v5
+/// standard for location lists and range lists. The table consists of a header
+/// followed by an array of offsets into a DWARF section, followed by zero or
+/// more list entries. The list entries are kept in a map where the keys are
+/// the lists' section offsets.
+template <typename DWARFListType> class DWARFListTableBase {
+  DWARFListTableHeader Header;
+  /// A mapping between file offsets and lists. It is used to find a particular
+  /// list based on an offset (obtained from DW_AT_ranges, for example).
+  std::map<uint64_t, DWARFListType> ListMap;
+  /// This string is displayed as a heading before the list is dumped
+  /// (e.g. "ranges:").
+  StringRef HeaderString;
+
+protected:
+  DWARFListTableBase(StringRef SectionName, StringRef HeaderString,
+                     StringRef ListTypeString)
+      : Header(SectionName, ListTypeString), HeaderString(HeaderString) {}
+
+public:
+  void clear() {
+    Header.clear();
+    ListMap.clear();
+  }
+  /// Extract the table header and the array of offsets.
+  Error extractHeaderAndOffsets(DWARFDataExtractor Data, uint64_t *OffsetPtr) {
+    return Header.extract(Data, OffsetPtr);
+  }
+  /// Extract an entire table, including all list entries.
+  Error extract(DWARFDataExtractor Data, uint64_t *OffsetPtr);
+  /// Look up a list based on a given offset. Extract it and enter it into the
+  /// list map if necessary.
+  Expected<DWARFListType> findList(DWARFDataExtractor Data, uint64_t Offset);
+
+  uint64_t getHeaderOffset() const { return Header.getHeaderOffset(); }
+  uint8_t getAddrSize() const { return Header.getAddrSize(); }
+  dwarf::DwarfFormat getFormat() const { return Header.getFormat(); }
+
+  void dump(raw_ostream &OS,
+            llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)>
+                LookupPooledAddress,
+            DIDumpOptions DumpOpts = {}) const;
+
+  /// Return the contents of the offset entry designated by a given index.
+  Optional<uint64_t> getOffsetEntry(uint32_t Index) const {
+    return Header.getOffsetEntry(Index);
+  }
+  /// Return the size of the table header including the length but not including
+  /// the offsets. This is dependent on the table format, which is unambiguously
+  /// derived from parsing the table.
+  uint8_t getHeaderSize() const {
+    return DWARFListTableHeader::getHeaderSize(getFormat());
+  }
+
+  uint64_t length() { return Header.length(); }
+};
+
+template <typename DWARFListType>
+Error DWARFListTableBase<DWARFListType>::extract(DWARFDataExtractor Data,
+                                                 uint64_t *OffsetPtr) {
+  clear();
+  if (Error E = extractHeaderAndOffsets(Data, OffsetPtr))
+    return E;
+
+  Data.setAddressSize(Header.getAddrSize());
+  uint64_t End = getHeaderOffset() + Header.length();
+  while (*OffsetPtr < End) {
+    DWARFListType CurrentList;
+    uint64_t Off = *OffsetPtr;
+    if (Error E = CurrentList.extract(Data, getHeaderOffset(), End, OffsetPtr,
+                                      Header.getSectionName(),
+                                      Header.getListTypeString()))
+      return E;
+    ListMap[Off] = CurrentList;
+  }
+
+  assert(*OffsetPtr == End &&
+         "mismatch between expected length of table and length "
+         "of extracted data");
+  return Error::success();
+}
+
+template <typename ListEntryType>
+Error DWARFListType<ListEntryType>::extract(DWARFDataExtractor Data,
+                                            uint64_t HeaderOffset, uint64_t End,
+                                            uint64_t *OffsetPtr,
+                                            StringRef SectionName,
+                                            StringRef ListTypeString) {
+  if (*OffsetPtr < HeaderOffset || *OffsetPtr >= End)
+    return createStringError(errc::invalid_argument,
+                       "invalid %s list offset 0x%" PRIx64,
+                       ListTypeString.data(), *OffsetPtr);
+  Entries.clear();
+  while (*OffsetPtr < End) {
+    ListEntryType Entry;
+    if (Error E = Entry.extract(Data, End, OffsetPtr))
+      return E;
+    Entries.push_back(Entry);
+    if (Entry.isSentinel())
+      return Error::success();
+  }
+  return createStringError(errc::illegal_byte_sequence,
+                     "no end of list marker detected at end of %s table "
+                     "starting at offset 0x%" PRIx64,
+                     SectionName.data(), HeaderOffset);
+}
+
+template <typename DWARFListType>
+void DWARFListTableBase<DWARFListType>::dump(
+    raw_ostream &OS,
+    llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)>
+        LookupPooledAddress,
+    DIDumpOptions DumpOpts) const {
+  Header.dump(OS, DumpOpts);
+  OS << HeaderString << "\n";
+
+  // Determine the length of the longest encoding string we have in the table,
+  // so we can align the output properly. We only need this in verbose mode.
+  size_t MaxEncodingStringLength = 0;
+  if (DumpOpts.Verbose) {
+    for (const auto &List : ListMap)
+      for (const auto &Entry : List.second.getEntries())
+        MaxEncodingStringLength =
+            std::max(MaxEncodingStringLength,
+                     dwarf::RangeListEncodingString(Entry.EntryKind).size());
+  }
+
+  uint64_t CurrentBase = 0;
+  for (const auto &List : ListMap)
+    for (const auto &Entry : List.second.getEntries())
+      Entry.dump(OS, getAddrSize(), MaxEncodingStringLength, CurrentBase,
+                 DumpOpts, LookupPooledAddress);
+}
+
+template <typename DWARFListType>
+Expected<DWARFListType>
+DWARFListTableBase<DWARFListType>::findList(DWARFDataExtractor Data,
+                                            uint64_t Offset) {
+  auto Entry = ListMap.find(Offset);
+  if (Entry != ListMap.end())
+    return Entry->second;
+
+  // Extract the list from the section and enter it into the list map.
+  DWARFListType List;
+  uint64_t End = getHeaderOffset() + Header.length();
+  uint64_t StartingOffset = Offset;
+  if (Error E =
+          List.extract(Data, getHeaderOffset(), End, &Offset,
+                       Header.getSectionName(), Header.getListTypeString()))
+    return std::move(E);
+  ListMap[StartingOffset] = List;
+  return List;
+}
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARFLISTTABLE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFObject.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFObject.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFObject.h
@@ -0,0 +1,85 @@
+//===- DWARFObject.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===-----------------------------------------------------------------------===/
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFOBJECT_H
+#define LLVM_DEBUGINFO_DWARF_DWARFOBJECT_H
+
+#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/DebugInfo/DWARF/DWARFSection.h"
+#include "llvm/Object/ObjectFile.h"
+
+namespace llvm {
+// This is responsible for low level access to the object file. It
+// knows how to find the required sections and compute relocated
+// values.
+// The default implementations of the get<Section> methods return dummy values.
+// This is to allow clients that only need some of those to implement just the
+// ones they need. We can't use unreachable for as many cases because the parser
+// implementation is eager and will call some of these methods even if the
+// result is not used.
+class DWARFObject {
+  DWARFSection Dummy;
+
+public:
+  virtual ~DWARFObject() = default;
+  virtual StringRef getFileName() const { llvm_unreachable("unimplemented"); }
+  virtual const object::ObjectFile *getFile() const { return nullptr; }
+  virtual ArrayRef<SectionName> getSectionNames() const { return {}; }
+  virtual bool isLittleEndian() const = 0;
+  virtual uint8_t getAddressSize() const { llvm_unreachable("unimplemented"); }
+  virtual void
+  forEachInfoSections(function_ref<void(const DWARFSection &)> F) const {}
+  virtual void
+  forEachTypesSections(function_ref<void(const DWARFSection &)> F) const {}
+  virtual StringRef getAbbrevSection() const { return ""; }
+  virtual const DWARFSection &getLocSection() const { return Dummy; }
+  virtual const DWARFSection &getLoclistsSection() const { return Dummy; }
+  virtual StringRef getArangesSection() const { return ""; }
+  virtual const DWARFSection &getFrameSection() const { return Dummy; }
+  virtual const DWARFSection &getEHFrameSection() const { return Dummy; }
+  virtual const DWARFSection &getLineSection() const { return Dummy; }
+  virtual StringRef getLineStrSection() const { return ""; }
+  virtual StringRef getStrSection() const { return ""; }
+  virtual const DWARFSection &getRangesSection() const { return Dummy; }
+  virtual const DWARFSection &getRnglistsSection() const { return Dummy; }
+  virtual StringRef getMacinfoSection() const { return ""; }
+  virtual const DWARFSection &getPubnamesSection() const { return Dummy; }
+  virtual const DWARFSection &getPubtypesSection() const { return Dummy; }
+  virtual const DWARFSection &getGnuPubnamesSection() const { return Dummy; }
+  virtual const DWARFSection &getGnuPubtypesSection() const { return Dummy; }
+  virtual const DWARFSection &getStrOffsetsSection() const { return Dummy; }
+  virtual void
+  forEachInfoDWOSections(function_ref<void(const DWARFSection &)> F) const {}
+  virtual void
+  forEachTypesDWOSections(function_ref<void(const DWARFSection &)> F) const {}
+  virtual StringRef getAbbrevDWOSection() const { return ""; }
+  virtual const DWARFSection &getLineDWOSection() const { return Dummy; }
+  virtual const DWARFSection &getLocDWOSection() const { return Dummy; }
+  virtual StringRef getStrDWOSection() const { return ""; }
+  virtual const DWARFSection &getStrOffsetsDWOSection() const {
+    return Dummy;
+  }
+  virtual const DWARFSection &getRangesDWOSection() const { return Dummy; }
+  virtual const DWARFSection &getRnglistsDWOSection() const { return Dummy; }
+  virtual const DWARFSection &getAddrSection() const { return Dummy; }
+  virtual const DWARFSection &getAppleNamesSection() const { return Dummy; }
+  virtual const DWARFSection &getAppleTypesSection() const { return Dummy; }
+  virtual const DWARFSection &getAppleNamespacesSection() const {
+    return Dummy;
+  }
+  virtual const DWARFSection &getNamesSection() const { return Dummy; }
+  virtual const DWARFSection &getAppleObjCSection() const { return Dummy; }
+  virtual StringRef getCUIndexSection() const { return ""; }
+  virtual StringRef getGdbIndexSection() const { return ""; }
+  virtual StringRef getTUIndexSection() const { return ""; }
+  virtual Optional<RelocAddrEntry> find(const DWARFSection &Sec,
+                                        uint64_t Pos) const = 0;
+};
+
+} // namespace llvm
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h
@@ -0,0 +1,38 @@
+//===- DWARFRelocMap.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFRELOCMAP_H
+#define LLVM_DEBUGINFO_DWARF_DWARFRELOCMAP_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Object/RelocationResolver.h"
+#include <cstdint>
+
+namespace llvm {
+
+/// RelocAddrEntry contains relocated value and section index.
+/// Section index is -1LL if relocation points to absolute symbol.
+struct RelocAddrEntry {
+  uint64_t SectionIndex;
+  object::RelocationRef Reloc;
+  uint64_t SymbolValue;
+  Optional<object::RelocationRef> Reloc2;
+  uint64_t SymbolValue2;
+  object::RelocationResolver Resolver;
+};
+
+/// In place of applying the relocations to the data we've read from disk we use
+/// a separate mapping table to the side and checking that at locations in the
+/// dwarf where we expect relocated values. This adds a bit of complexity to the
+/// dwarf parsing/extraction at the benefit of not allocating memory for the
+/// entire size of the debug info sections.
+using RelocAddrMap = DenseMap<uint64_t, RelocAddrEntry>;
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFRELOCMAP_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFSection.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFSection.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFSection.h
@@ -0,0 +1,27 @@
+//===- DWARFSection.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFSECTION_H
+#define LLVM_DEBUGINFO_DWARF_DWARFSECTION_H
+
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+
+struct DWARFSection {
+  StringRef Data;
+};
+
+struct SectionName {
+  StringRef Name;
+  bool IsNameUnique;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFSECTION_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h
@@ -0,0 +1,46 @@
+//===- DWARFTypeUnit.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFTYPEUNIT_H
+#define LLVM_DEBUGINFO_DWARF_DWARFTYPEUNIT_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
+#include "llvm/Support/DataExtractor.h"
+#include <cstdint>
+
+namespace llvm {
+
+class DWARFContext;
+class DWARFDebugAbbrev;
+struct DWARFSection;
+class raw_ostream;
+
+class DWARFTypeUnit : public DWARFUnit {
+public:
+  DWARFTypeUnit(DWARFContext &Context, const DWARFSection &Section,
+                const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA,
+                const DWARFSection *RS, const DWARFSection *LocSection,
+                StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS,
+                const DWARFSection &LS, bool LE, bool IsDWO,
+                const DWARFUnitVector &UnitVector)
+      : DWARFUnit(Context, Section, Header, DA, RS, LocSection, SS, SOS, AOS,
+                  LS, LE, IsDWO, UnitVector) {}
+
+  uint64_t getTypeHash() const { return getHeader().getTypeHash(); }
+  uint64_t getTypeOffset() const { return getHeader().getTypeOffset(); }
+
+  void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}) override;
+  // Enable LLVM-style RTTI.
+  static bool classof(const DWARFUnit *U) { return U->isTypeUnit(); }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFTYPEUNIT_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFUnit.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFUnit.h
@@ -0,0 +1,527 @@
+//===- DWARFUnit.h ----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFUNIT_H
+#define LLVM_DEBUGINFO_DWARF_DWARFUNIT_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/DebugInfo/DWARF/DWARFSection.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
+#include "llvm/Support/DataExtractor.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+
+class DWARFAbbreviationDeclarationSet;
+class DWARFContext;
+class DWARFDebugAbbrev;
+class DWARFUnit;
+
+/// Base class describing the header of any kind of "unit."  Some information
+/// is specific to certain unit types.  We separate this class out so we can
+/// parse the header before deciding what specific kind of unit to construct.
+class DWARFUnitHeader {
+  // Offset within section.
+  uint64_t Offset = 0;
+  // Version, address size, and DWARF format.
+  dwarf::FormParams FormParams;
+  uint64_t Length = 0;
+  uint64_t AbbrOffset = 0;
+
+  // For DWO units only.
+  const DWARFUnitIndex::Entry *IndexEntry = nullptr;
+
+  // For type units only.
+  uint64_t TypeHash = 0;
+  uint64_t TypeOffset = 0;
+
+  // For v5 split or skeleton compile units only.
+  Optional<uint64_t> DWOId;
+
+  // Unit type as parsed, or derived from the section kind.
+  uint8_t UnitType = 0;
+
+  // Size as parsed. uint8_t for compactness.
+  uint8_t Size = 0;
+
+public:
+  /// Parse a unit header from \p debug_info starting at \p offset_ptr.
+  bool extract(DWARFContext &Context, const DWARFDataExtractor &debug_info,
+               uint64_t *offset_ptr, DWARFSectionKind Kind = DW_SECT_INFO,
+               const DWARFUnitIndex *Index = nullptr,
+               const DWARFUnitIndex::Entry *Entry = nullptr);
+  uint64_t getOffset() const { return Offset; }
+  const dwarf::FormParams &getFormParams() const { return FormParams; }
+  uint16_t getVersion() const { return FormParams.Version; }
+  dwarf::DwarfFormat getFormat() const { return FormParams.Format; }
+  uint8_t getAddressByteSize() const { return FormParams.AddrSize; }
+  uint8_t getRefAddrByteSize() const { return FormParams.getRefAddrByteSize(); }
+  uint8_t getDwarfOffsetByteSize() const {
+    return FormParams.getDwarfOffsetByteSize();
+  }
+  uint64_t getLength() const { return Length; }
+  uint64_t getAbbrOffset() const { return AbbrOffset; }
+  Optional<uint64_t> getDWOId() const { return DWOId; }
+  void setDWOId(uint64_t Id) {
+    assert((!DWOId || *DWOId == Id) && "setting DWOId to a different value");
+    DWOId = Id;
+  }
+  const DWARFUnitIndex::Entry *getIndexEntry() const { return IndexEntry; }
+  uint64_t getTypeHash() const { return TypeHash; }
+  uint64_t getTypeOffset() const { return TypeOffset; }
+  uint8_t getUnitType() const { return UnitType; }
+  bool isTypeUnit() const {
+    return UnitType == dwarf::DW_UT_type || UnitType == dwarf::DW_UT_split_type;
+  }
+  uint8_t getSize() const { return Size; }
+  uint8_t getUnitLengthFieldByteSize() const {
+    return dwarf::getUnitLengthFieldByteSize(FormParams.Format);
+  }
+  uint64_t getNextUnitOffset() const {
+    return Offset + Length + getUnitLengthFieldByteSize();
+  }
+};
+
+const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context,
+                                        DWARFSectionKind Kind);
+
+/// Describe a collection of units. Intended to hold all units either from
+/// .debug_info and .debug_types, or from .debug_info.dwo and .debug_types.dwo.
+class DWARFUnitVector final : public SmallVector<std::unique_ptr<DWARFUnit>, 1> {
+  std::function<std::unique_ptr<DWARFUnit>(uint64_t, DWARFSectionKind,
+                                           const DWARFSection *,
+                                           const DWARFUnitIndex::Entry *)>
+      Parser;
+  int NumInfoUnits = -1;
+
+public:
+  using UnitVector = SmallVectorImpl<std::unique_ptr<DWARFUnit>>;
+  using iterator = typename UnitVector::iterator;
+  using iterator_range = llvm::iterator_range<typename UnitVector::iterator>;
+
+  DWARFUnit *getUnitForOffset(uint64_t Offset) const;
+  DWARFUnit *getUnitForIndexEntry(const DWARFUnitIndex::Entry &E);
+
+  /// Read units from a .debug_info or .debug_types section.  Calls made
+  /// before finishedInfoUnits() are assumed to be for .debug_info sections,
+  /// calls after finishedInfoUnits() are for .debug_types sections.  Caller
+  /// must not mix calls to addUnitsForSection and addUnitsForDWOSection.
+  void addUnitsForSection(DWARFContext &C, const DWARFSection &Section,
+                          DWARFSectionKind SectionKind);
+  /// Read units from a .debug_info.dwo or .debug_types.dwo section.  Calls
+  /// made before finishedInfoUnits() are assumed to be for .debug_info.dwo
+  /// sections, calls after finishedInfoUnits() are for .debug_types.dwo
+  /// sections.  Caller must not mix calls to addUnitsForSection and
+  /// addUnitsForDWOSection.
+  void addUnitsForDWOSection(DWARFContext &C, const DWARFSection &DWOSection,
+                             DWARFSectionKind SectionKind, bool Lazy = false);
+
+  /// Add an existing DWARFUnit to this UnitVector. This is used by the DWARF
+  /// verifier to process unit separately.
+  DWARFUnit *addUnit(std::unique_ptr<DWARFUnit> Unit);
+
+  /// Returns number of all units held by this instance.
+  unsigned getNumUnits() const { return size(); }
+  /// Returns number of units from all .debug_info[.dwo] sections.
+  unsigned getNumInfoUnits() const {
+    return NumInfoUnits == -1 ? size() : NumInfoUnits;
+  }
+  /// Returns number of units from all .debug_types[.dwo] sections.
+  unsigned getNumTypesUnits() const { return size() - NumInfoUnits; }
+  /// Indicate that parsing .debug_info[.dwo] is done, and remaining units
+  /// will be from .debug_types[.dwo].
+  void finishedInfoUnits() { NumInfoUnits = size(); }
+
+private:
+  void addUnitsImpl(DWARFContext &Context, const DWARFObject &Obj,
+                    const DWARFSection &Section, const DWARFDebugAbbrev *DA,
+                    const DWARFSection *RS, const DWARFSection *LocSection,
+                    StringRef SS, const DWARFSection &SOS,
+                    const DWARFSection *AOS, const DWARFSection &LS, bool LE,
+                    bool IsDWO, bool Lazy, DWARFSectionKind SectionKind);
+};
+
+/// Represents base address of the CU.
+/// Represents a unit's contribution to the string offsets table.
+struct StrOffsetsContributionDescriptor {
+  uint64_t Base = 0;
+  /// The contribution size not including the header.
+  uint64_t Size = 0;
+  /// Format and version.
+  dwarf::FormParams FormParams = {0, 0, dwarf::DwarfFormat::DWARF32};
+
+  StrOffsetsContributionDescriptor(uint64_t Base, uint64_t Size,
+                                   uint8_t Version, dwarf::DwarfFormat Format)
+      : Base(Base), Size(Size), FormParams({Version, 0, Format}) {}
+  StrOffsetsContributionDescriptor() = default;
+
+  uint8_t getVersion() const { return FormParams.Version; }
+  dwarf::DwarfFormat getFormat() const { return FormParams.Format; }
+  uint8_t getDwarfOffsetByteSize() const {
+    return FormParams.getDwarfOffsetByteSize();
+  }
+  /// Determine whether a contribution to the string offsets table is
+  /// consistent with the relevant section size and that its length is
+  /// a multiple of the size of one of its entries.
+  Expected<StrOffsetsContributionDescriptor>
+  validateContributionSize(DWARFDataExtractor &DA);
+};
+
+class DWARFUnit {
+  DWARFContext &Context;
+  /// Section containing this DWARFUnit.
+  const DWARFSection &InfoSection;
+
+  DWARFUnitHeader Header;
+  const DWARFDebugAbbrev *Abbrev;
+  const DWARFSection *RangeSection;
+  uint64_t RangeSectionBase;
+  /// We either keep track of the location list section or its data, depending
+  /// on whether we are handling a split DWARF section or not.
+  union {
+    const DWARFSection *LocSection;
+    StringRef LocSectionData;
+  };
+  const DWARFSection &LineSection;
+  StringRef StringSection;
+  const DWARFSection &StringOffsetSection;
+  const DWARFSection *AddrOffsetSection;
+  uint32_t AddrOffsetSectionBase = 0;
+  bool isLittleEndian;
+  bool IsDWO;
+  const DWARFUnitVector &UnitVector;
+
+  /// Start, length, and DWARF format of the unit's contribution to the string
+  /// offsets table (DWARF v5).
+  Optional<StrOffsetsContributionDescriptor> StringOffsetsTableContribution;
+
+  /// A table of range lists (DWARF v5 and later).
+  Optional<DWARFDebugRnglistTable> RngListTable;
+
+  mutable const DWARFAbbreviationDeclarationSet *Abbrevs;
+  llvm::Optional<object::SectionedAddress> BaseAddr;
+  /// The compile unit debug information entry items.
+  std::vector<DWARFDebugInfoEntry> DieArray;
+
+  /// Map from range's start address to end address and corresponding DIE.
+  /// IntervalMap does not support range removal, as a result, we use the
+  /// std::map::upper_bound for address range lookup.
+  std::map<uint64_t, std::pair<uint64_t, DWARFDie>> AddrDieMap;
+
+  using die_iterator_range =
+      iterator_range<std::vector<DWARFDebugInfoEntry>::iterator>;
+
+  std::shared_ptr<DWARFUnit> DWO;
+
+  uint32_t getDIEIndex(const DWARFDebugInfoEntry *Die) {
+    auto First = DieArray.data();
+    assert(Die >= First && Die < First + DieArray.size());
+    return Die - First;
+  }
+
+protected:
+  const DWARFUnitHeader &getHeader() const { return Header; }
+
+  /// Size in bytes of the parsed unit header.
+  uint32_t getHeaderSize() const { return Header.getSize(); }
+
+  /// Find the unit's contribution to the string offsets table and determine its
+  /// length and form. The given offset is expected to be derived from the unit
+  /// DIE's DW_AT_str_offsets_base attribute.
+  Expected<Optional<StrOffsetsContributionDescriptor>>
+  determineStringOffsetsTableContribution(DWARFDataExtractor &DA);
+
+  /// Find the unit's contribution to the string offsets table and determine its
+  /// length and form. The given offset is expected to be 0 in a dwo file or,
+  /// in a dwp file, the start of the unit's contribution to the string offsets
+  /// table section (as determined by the index table).
+  Expected<Optional<StrOffsetsContributionDescriptor>>
+  determineStringOffsetsTableContributionDWO(DWARFDataExtractor &DA);
+
+public:
+  DWARFUnit(DWARFContext &Context, const DWARFSection &Section,
+            const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA,
+            const DWARFSection *RS, const DWARFSection *LocSection,
+            StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS,
+            const DWARFSection &LS, bool LE, bool IsDWO,
+            const DWARFUnitVector &UnitVector);
+
+  virtual ~DWARFUnit();
+
+  bool isDWOUnit() const { return IsDWO; }
+  DWARFContext& getContext() const { return Context; }
+  const DWARFSection &getInfoSection() const { return InfoSection; }
+  const DWARFSection *getLocSection() const { return LocSection; }
+  StringRef getLocSectionData() const { return LocSectionData; }
+  uint64_t getOffset() const { return Header.getOffset(); }
+  const dwarf::FormParams &getFormParams() const {
+    return Header.getFormParams();
+  }
+  uint16_t getVersion() const { return Header.getVersion(); }
+  uint8_t getAddressByteSize() const { return Header.getAddressByteSize(); }
+  uint8_t getRefAddrByteSize() const { return Header.getRefAddrByteSize(); }
+  uint8_t getDwarfOffsetByteSize() const {
+    return Header.getDwarfOffsetByteSize();
+  }
+  uint64_t getLength() const { return Header.getLength(); }
+  uint8_t getUnitType() const { return Header.getUnitType(); }
+  bool isTypeUnit() const { return Header.isTypeUnit(); }
+  uint64_t getNextUnitOffset() const { return Header.getNextUnitOffset(); }
+  const DWARFSection &getLineSection() const { return LineSection; }
+  StringRef getStringSection() const { return StringSection; }
+  const DWARFSection &getStringOffsetSection() const {
+    return StringOffsetSection;
+  }
+
+  void setAddrOffsetSection(const DWARFSection *AOS, uint32_t Base) {
+    AddrOffsetSection = AOS;
+    AddrOffsetSectionBase = Base;
+  }
+
+  /// Recursively update address to Die map.
+  void updateAddressDieMap(DWARFDie Die);
+
+  void setRangesSection(const DWARFSection *RS, uint64_t Base) {
+    RangeSection = RS;
+    RangeSectionBase = Base;
+  }
+
+  Optional<object::SectionedAddress>
+  getAddrOffsetSectionItem(uint32_t Index) const;
+  Optional<uint64_t> getStringOffsetSectionItem(uint32_t Index) const;
+
+  DWARFDataExtractor getDebugInfoExtractor() const;
+
+  DataExtractor getStringExtractor() const {
+    return DataExtractor(StringSection, false, 0);
+  }
+
+  /// Extract the range list referenced by this compile unit from the
+  /// .debug_ranges section. If the extraction is unsuccessful, an error
+  /// is returned. Successful extraction requires that the compile unit
+  /// has already been extracted.
+  Error extractRangeList(uint64_t RangeListOffset,
+                         DWARFDebugRangeList &RangeList) const;
+  void clear();
+
+  const Optional<StrOffsetsContributionDescriptor> &
+  getStringOffsetsTableContribution() const {
+    return StringOffsetsTableContribution;
+  }
+
+  uint8_t getDwarfStringOffsetsByteSize() const {
+    assert(StringOffsetsTableContribution);
+    return StringOffsetsTableContribution->getDwarfOffsetByteSize();
+  }
+
+  uint64_t getStringOffsetsBase() const {
+    assert(StringOffsetsTableContribution);
+    return StringOffsetsTableContribution->Base;
+  }
+
+  const DWARFAbbreviationDeclarationSet *getAbbreviations() const;
+
+  static bool isMatchingUnitTypeAndTag(uint8_t UnitType, dwarf::Tag Tag) {
+    switch (UnitType) {
+    case dwarf::DW_UT_compile:
+      return Tag == dwarf::DW_TAG_compile_unit;
+    case dwarf::DW_UT_type:
+      return Tag == dwarf::DW_TAG_type_unit;
+    case dwarf::DW_UT_partial:
+      return Tag == dwarf::DW_TAG_partial_unit;
+    case dwarf::DW_UT_skeleton:
+      return Tag == dwarf::DW_TAG_skeleton_unit;
+    case dwarf::DW_UT_split_compile:
+    case dwarf::DW_UT_split_type:
+      return dwarf::isUnitType(Tag);
+    }
+    return false;
+  }
+
+  /// Return the number of bytes for the header of a unit of
+  /// UnitType type.
+  ///
+  /// This function must be called with a valid unit type which in
+  /// DWARF5 is defined as one of the following six types.
+  static uint32_t getDWARF5HeaderSize(uint8_t UnitType) {
+    switch (UnitType) {
+    case dwarf::DW_UT_compile:
+    case dwarf::DW_UT_partial:
+      return 12;
+    case dwarf::DW_UT_skeleton:
+    case dwarf::DW_UT_split_compile:
+      return 20;
+    case dwarf::DW_UT_type:
+    case dwarf::DW_UT_split_type:
+      return 24;
+    }
+    llvm_unreachable("Invalid UnitType.");
+  }
+
+  llvm::Optional<object::SectionedAddress> getBaseAddress();
+
+  DWARFDie getUnitDIE(bool ExtractUnitDIEOnly = true) {
+    extractDIEsIfNeeded(ExtractUnitDIEOnly);
+    if (DieArray.empty())
+      return DWARFDie();
+    return DWARFDie(this, &DieArray[0]);
+  }
+
+  DWARFDie getNonSkeletonUnitDIE(bool ExtractUnitDIEOnly = true) {
+    parseDWO();
+    if (DWO)
+      return DWO->getUnitDIE(ExtractUnitDIEOnly);
+    return getUnitDIE(ExtractUnitDIEOnly);
+  }
+
+  const char *getCompilationDir();
+  Optional<uint64_t> getDWOId() {
+    extractDIEsIfNeeded(/*CUDieOnly*/ true);
+    return getHeader().getDWOId();
+  }
+  void setDWOId(uint64_t NewID) { Header.setDWOId(NewID); }
+
+  /// Return a vector of address ranges resulting from a (possibly encoded)
+  /// range list starting at a given offset in the appropriate ranges section.
+  Expected<DWARFAddressRangesVector> findRnglistFromOffset(uint64_t Offset);
+
+  /// Return a vector of address ranges retrieved from an encoded range
+  /// list whose offset is found via a table lookup given an index (DWARF v5
+  /// and later).
+  Expected<DWARFAddressRangesVector> findRnglistFromIndex(uint32_t Index);
+
+  /// Return a rangelist's offset based on an index. The index designates
+  /// an entry in the rangelist table's offset array and is supplied by
+  /// DW_FORM_rnglistx.
+  Optional<uint64_t> getRnglistOffset(uint32_t Index) {
+    if (RngListTable)
+      return RngListTable->getOffsetEntry(Index);
+    return None;
+  }
+
+  Expected<DWARFAddressRangesVector> collectAddressRanges();
+
+  /// Returns subprogram DIE with address range encompassing the provided
+  /// address. The pointer is alive as long as parsed compile unit DIEs are not
+  /// cleared.
+  DWARFDie getSubroutineForAddress(uint64_t Address);
+
+  /// getInlinedChainForAddress - fetches inlined chain for a given address.
+  /// Returns empty chain if there is no subprogram containing address. The
+  /// chain is valid as long as parsed compile unit DIEs are not cleared.
+  void getInlinedChainForAddress(uint64_t Address,
+                                 SmallVectorImpl<DWARFDie> &InlinedChain);
+
+  /// Return the DWARFUnitVector containing this unit.
+  const DWARFUnitVector &getUnitVector() const { return UnitVector; }
+
+  /// Returns the number of DIEs in the unit. Parses the unit
+  /// if necessary.
+  unsigned getNumDIEs() {
+    extractDIEsIfNeeded(false);
+    return DieArray.size();
+  }
+
+  /// Return the index of a DIE inside the unit's DIE vector.
+  ///
+  /// It is illegal to call this method with a DIE that hasn't be
+  /// created by this unit. In other word, it's illegal to call this
+  /// method on a DIE that isn't accessible by following
+  /// children/sibling links starting from this unit's getUnitDIE().
+  uint32_t getDIEIndex(const DWARFDie &D) {
+    return getDIEIndex(D.getDebugInfoEntry());
+  }
+
+  /// Return the DIE object at the given index.
+  DWARFDie getDIEAtIndex(unsigned Index) {
+    assert(Index < DieArray.size());
+    return DWARFDie(this, &DieArray[Index]);
+  }
+
+  DWARFDie getParent(const DWARFDebugInfoEntry *Die);
+  DWARFDie getSibling(const DWARFDebugInfoEntry *Die);
+  DWARFDie getPreviousSibling(const DWARFDebugInfoEntry *Die);
+  DWARFDie getFirstChild(const DWARFDebugInfoEntry *Die);
+  DWARFDie getLastChild(const DWARFDebugInfoEntry *Die);
+
+  /// Return the DIE object for a given offset inside the
+  /// unit's DIE vector.
+  ///
+  /// The unit needs to have its DIEs extracted for this method to work.
+  DWARFDie getDIEForOffset(uint64_t Offset) {
+    extractDIEsIfNeeded(false);
+    assert(!DieArray.empty());
+    auto It =
+        llvm::partition_point(DieArray, [=](const DWARFDebugInfoEntry &DIE) {
+          return DIE.getOffset() < Offset;
+        });
+    if (It != DieArray.end() && It->getOffset() == Offset)
+      return DWARFDie(this, &*It);
+    return DWARFDie();
+  }
+
+  uint32_t getLineTableOffset() const {
+    if (auto IndexEntry = Header.getIndexEntry())
+      if (const auto *Contrib = IndexEntry->getOffset(DW_SECT_LINE))
+        return Contrib->Offset;
+    return 0;
+  }
+
+  die_iterator_range dies() {
+    extractDIEsIfNeeded(false);
+    return die_iterator_range(DieArray.begin(), DieArray.end());
+  }
+
+  virtual void dump(raw_ostream &OS, DIDumpOptions DumpOpts) = 0;
+
+  Error tryExtractDIEsIfNeeded(bool CUDieOnly);
+
+private:
+  /// Size in bytes of the .debug_info data associated with this compile unit.
+  size_t getDebugInfoSize() const {
+    return Header.getLength() + Header.getUnitLengthFieldByteSize() -
+           getHeaderSize();
+  }
+
+  /// extractDIEsIfNeeded - Parses a compile unit and indexes its DIEs if it
+  /// hasn't already been done
+  void extractDIEsIfNeeded(bool CUDieOnly);
+
+  /// extractDIEsToVector - Appends all parsed DIEs to a vector.
+  void extractDIEsToVector(bool AppendCUDie, bool AppendNonCUDIEs,
+                           std::vector<DWARFDebugInfoEntry> &DIEs) const;
+
+  /// clearDIEs - Clear parsed DIEs to keep memory usage low.
+  void clearDIEs(bool KeepCUDie);
+
+  /// parseDWO - Parses .dwo file for current compile unit. Returns true if
+  /// it was actually constructed.
+  bool parseDWO();
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFUNIT_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h
@@ -0,0 +1,105 @@
+//===- DWARFUnitIndex.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFUNITINDEX_H
+#define LLVM_DEBUGINFO_DWARF_DWARFUNITINDEX_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataExtractor.h"
+#include <cstdint>
+#include <memory>
+
+namespace llvm {
+
+class raw_ostream;
+
+enum DWARFSectionKind {
+  DW_SECT_INFO = 1,
+  DW_SECT_TYPES,
+  DW_SECT_ABBREV,
+  DW_SECT_LINE,
+  DW_SECT_LOC,
+  DW_SECT_STR_OFFSETS,
+  DW_SECT_MACINFO,
+  DW_SECT_MACRO,
+};
+
+class DWARFUnitIndex {
+  struct Header {
+    uint32_t Version;
+    uint32_t NumColumns;
+    uint32_t NumUnits;
+    uint32_t NumBuckets = 0;
+
+    bool parse(DataExtractor IndexData, uint64_t *OffsetPtr);
+    void dump(raw_ostream &OS) const;
+  };
+
+public:
+  class Entry {
+  public:
+    struct SectionContribution {
+      uint32_t Offset;
+      uint32_t Length;
+    };
+
+  private:
+    const DWARFUnitIndex *Index;
+    uint64_t Signature;
+    std::unique_ptr<SectionContribution[]> Contributions;
+    friend class DWARFUnitIndex;
+
+  public:
+    const SectionContribution *getOffset(DWARFSectionKind Sec) const;
+    const SectionContribution *getOffset() const;
+
+    const SectionContribution *getOffsets() const {
+      return Contributions.get();
+    }
+
+    uint64_t getSignature() const { return Signature; }
+  };
+
+private:
+  struct Header Header;
+
+  DWARFSectionKind InfoColumnKind;
+  int InfoColumn = -1;
+  std::unique_ptr<DWARFSectionKind[]> ColumnKinds;
+  std::unique_ptr<Entry[]> Rows;
+  mutable std::vector<Entry *> OffsetLookup;
+
+  static StringRef getColumnHeader(DWARFSectionKind DS);
+
+  bool parseImpl(DataExtractor IndexData);
+
+public:
+  DWARFUnitIndex(DWARFSectionKind InfoColumnKind)
+      : InfoColumnKind(InfoColumnKind) {}
+
+  explicit operator bool() const { return Header.NumBuckets; }
+
+  bool parse(DataExtractor IndexData);
+  void dump(raw_ostream &OS) const;
+
+  const Entry *getFromOffset(uint32_t Offset) const;
+  const Entry *getFromHash(uint64_t Offset) const;
+
+  ArrayRef<DWARFSectionKind> getColumnKinds() const {
+    return makeArrayRef(ColumnKinds.get(), Header.NumColumns);
+  }
+
+  ArrayRef<Entry> getRows() const {
+    return makeArrayRef(Rows.get(), Header.NumBuckets);
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFUNITINDEX_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFVerifier.h b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
@@ -0,0 +1,336 @@
+//===- DWARFVerifier.h ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H
+#define LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H
+
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
+
+#include <cstdint>
+#include <map>
+#include <set>
+
+namespace llvm {
+class raw_ostream;
+struct DWARFAttribute;
+class DWARFContext;
+class DWARFDie;
+class DWARFUnit;
+class DWARFCompileUnit;
+class DWARFDataExtractor;
+class DWARFDebugAbbrev;
+class DataExtractor;
+struct DWARFSection;
+
+/// A class that verifies DWARF debug information given a DWARF Context.
+class DWARFVerifier {
+public:
+  /// A class that keeps the address range information for a single DIE.
+  struct DieRangeInfo {
+    DWARFDie Die;
+
+    /// Sorted DWARFAddressRanges.
+    std::vector<DWARFAddressRange> Ranges;
+
+    /// Sorted DWARFAddressRangeInfo.
+    std::set<DieRangeInfo> Children;
+
+    DieRangeInfo() = default;
+    DieRangeInfo(DWARFDie Die) : Die(Die) {}
+
+    /// Used for unit testing.
+    DieRangeInfo(std::vector<DWARFAddressRange> Ranges)
+        : Ranges(std::move(Ranges)) {}
+
+    typedef std::vector<DWARFAddressRange>::const_iterator
+        address_range_iterator;
+    typedef std::set<DieRangeInfo>::const_iterator die_range_info_iterator;
+
+    /// Inserts the address range. If the range overlaps with an existing
+    /// range, the range is *not* added and an iterator to the overlapping
+    /// range is returned.
+    ///
+    /// This is used for finding overlapping ranges within the same DIE.
+    address_range_iterator insert(const DWARFAddressRange &R);
+
+    /// Finds an address range in the sorted vector of ranges.
+    address_range_iterator findRange(const DWARFAddressRange &R) const {
+      auto Begin = Ranges.begin();
+      auto End = Ranges.end();
+      auto Iter = std::upper_bound(Begin, End, R);
+      if (Iter != Begin)
+        --Iter;
+      return Iter;
+    }
+
+    /// Inserts the address range info. If any of its ranges overlaps with a
+    /// range in an existing range info, the range info is *not* added and an
+    /// iterator to the overlapping range info.
+    ///
+    /// This is used for finding overlapping children of the same DIE.
+    die_range_info_iterator insert(const DieRangeInfo &RI);
+
+    /// Return true if ranges in this object contains all ranges within RHS.
+    bool contains(const DieRangeInfo &RHS) const;
+
+    /// Return true if any range in this object intersects with any range in
+    /// RHS.
+    bool intersects(const DieRangeInfo &RHS) const;
+  };
+
+private:
+  raw_ostream &OS;
+  DWARFContext &DCtx;
+  DIDumpOptions DumpOpts;
+  /// A map that tracks all references (converted absolute references) so we
+  /// can verify each reference points to a valid DIE and not an offset that
+  /// lies between to valid DIEs.
+  std::map<uint64_t, std::set<uint64_t>> ReferenceToDIEOffsets;
+  uint32_t NumDebugLineErrors = 0;
+  // Used to relax some checks that do not currently work portably
+  bool IsObjectFile;
+  bool IsMachOObject;
+
+  raw_ostream &error() const;
+  raw_ostream &warn() const;
+  raw_ostream &note() const;
+  raw_ostream &dump(const DWARFDie &Die, unsigned indent = 0) const;
+
+  /// Verifies the abbreviations section.
+  ///
+  /// This function currently checks that:
+  /// --No abbreviation declaration has more than one attributes with the same
+  /// name.
+  ///
+  /// \param Abbrev Pointer to the abbreviations section we are verifying
+  /// Abbrev can be a pointer to either .debug_abbrev or debug_abbrev.dwo.
+  ///
+  /// \returns The number of errors that occurred during verification.
+  unsigned verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev);
+
+  /// Verifies the header of a unit in a .debug_info or .debug_types section.
+  ///
+  /// This function currently checks for:
+  /// - Unit is in 32-bit DWARF format. The function can be modified to
+  /// support 64-bit format.
+  /// - The DWARF version is valid
+  /// - The unit type is valid (if unit is in version >=5)
+  /// - The unit doesn't extend beyond the containing section
+  /// - The address size is valid
+  /// - The offset in the .debug_abbrev section is valid
+  ///
+  /// \param DebugInfoData The section data
+  /// \param Offset A reference to the offset start of the unit. The offset will
+  /// be updated to point to the next unit in the section
+  /// \param UnitIndex The index of the unit to be verified
+  /// \param UnitType A reference to the type of the unit
+  /// \param isUnitDWARF64 A reference to a flag that shows whether the unit is
+  /// in 64-bit format.
+  ///
+  /// \returns true if the header is verified successfully, false otherwise.
+  bool verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
+                        uint64_t *Offset, unsigned UnitIndex, uint8_t &UnitType,
+                        bool &isUnitDWARF64);
+
+  /// Verifies the header of a unit in a .debug_info or .debug_types section.
+  ///
+  /// This function currently verifies:
+  ///  - The debug info attributes.
+  ///  - The debug info form=s.
+  ///  - The presence of a root DIE.
+  ///  - That the root DIE is a unit DIE.
+  ///  - If a unit type is provided, that the unit DIE matches the unit type.
+  ///  - The DIE ranges.
+  ///  - That call site entries are only nested within subprograms with a
+  ///    DW_AT_call attribute.
+  ///
+  /// \param Unit      The DWARF Unit to verify.
+  ///
+  /// \returns The number of errors that occurred during verification.
+  unsigned verifyUnitContents(DWARFUnit &Unit);
+
+  /// Verifies the unit headers and contents in a .debug_info or .debug_types
+  /// section.
+  ///
+  /// \param S           The DWARF Section to verify.
+  /// \param SectionKind The object-file section kind that S comes from.
+  ///
+  /// \returns The number of errors that occurred during verification.
+  unsigned verifyUnitSection(const DWARFSection &S,
+                             DWARFSectionKind SectionKind);
+
+  /// Verifies that a call site entry is nested within a subprogram with a
+  /// DW_AT_call attribute.
+  ///
+  /// \returns Number of errors that occurred during verification.
+  unsigned verifyDebugInfoCallSite(const DWARFDie &Die);
+
+  /// Verify that all Die ranges are valid.
+  ///
+  /// This function currently checks for:
+  /// - cases in which lowPC >= highPC
+  ///
+  /// \returns Number of errors that occurred during verification.
+  unsigned verifyDieRanges(const DWARFDie &Die, DieRangeInfo &ParentRI);
+
+  /// Verifies the attribute's DWARF attribute and its value.
+  ///
+  /// This function currently checks for:
+  /// - DW_AT_ranges values is a valid .debug_ranges offset
+  /// - DW_AT_stmt_list is a valid .debug_line offset
+  ///
+  /// \param Die          The DWARF DIE that owns the attribute value
+  /// \param AttrValue    The DWARF attribute value to check
+  ///
+  /// \returns NumErrors The number of errors occurred during verification of
+  /// attributes' values in a unit
+  unsigned verifyDebugInfoAttribute(const DWARFDie &Die,
+                                    DWARFAttribute &AttrValue);
+
+  /// Verifies the attribute's DWARF form.
+  ///
+  /// This function currently checks for:
+  /// - All DW_FORM_ref values that are CU relative have valid CU offsets
+  /// - All DW_FORM_ref_addr values have valid section offsets
+  /// - All DW_FORM_strp values have valid .debug_str offsets
+  ///
+  /// \param Die          The DWARF DIE that owns the attribute value
+  /// \param AttrValue    The DWARF attribute value to check
+  ///
+  /// \returns NumErrors The number of errors occurred during verification of
+  /// attributes' forms in a unit
+  unsigned verifyDebugInfoForm(const DWARFDie &Die, DWARFAttribute &AttrValue);
+
+  /// Verifies the all valid references that were found when iterating through
+  /// all of the DIE attributes.
+  ///
+  /// This function will verify that all references point to DIEs whose DIE
+  /// offset matches. This helps to ensure if a DWARF link phase moved things
+  /// around, that it doesn't create invalid references by failing to relocate
+  /// CU relative and absolute references.
+  ///
+  /// \returns NumErrors The number of errors occurred during verification of
+  /// references for the .debug_info and .debug_types sections
+  unsigned verifyDebugInfoReferences();
+
+  /// Verify the DW_AT_stmt_list encoding and value and ensure that no
+  /// compile units that have the same DW_AT_stmt_list value.
+  void verifyDebugLineStmtOffsets();
+
+  /// Verify that all of the rows in the line table are valid.
+  ///
+  /// This function currently checks for:
+  /// - addresses within a sequence that decrease in value
+  /// - invalid file indexes
+  void verifyDebugLineRows();
+
+  /// Verify that an Apple-style accelerator table is valid.
+  ///
+  /// This function currently checks that:
+  /// - The fixed part of the header fits in the section
+  /// - The size of the section is as large as what the header describes
+  /// - There is at least one atom
+  /// - The form for each atom is valid
+  /// - The tag for each DIE in the table is valid
+  /// - The buckets have a valid index, or they are empty
+  /// - Each hashdata offset is valid
+  /// - Each DIE is valid
+  ///
+  /// \param AccelSection pointer to the section containing the acceleration table
+  /// \param StrData pointer to the string section
+  /// \param SectionName the name of the table we're verifying
+  ///
+  /// \returns The number of errors occurred during verification
+  unsigned verifyAppleAccelTable(const DWARFSection *AccelSection,
+                                 DataExtractor *StrData,
+                                 const char *SectionName);
+
+  unsigned verifyDebugNamesCULists(const DWARFDebugNames &AccelTable);
+  unsigned verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
+                                  const DataExtractor &StrData);
+  unsigned verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI);
+  unsigned verifyNameIndexAttribute(const DWARFDebugNames::NameIndex &NI,
+                                    const DWARFDebugNames::Abbrev &Abbr,
+                                    DWARFDebugNames::AttributeEncoding AttrEnc);
+  unsigned verifyNameIndexEntries(const DWARFDebugNames::NameIndex &NI,
+                                  const DWARFDebugNames::NameTableEntry &NTE);
+  unsigned verifyNameIndexCompleteness(const DWARFDie &Die,
+                                       const DWARFDebugNames::NameIndex &NI);
+
+  /// Verify that the DWARF v5 accelerator table is valid.
+  ///
+  /// This function currently checks that:
+  /// - Headers individual Name Indices fit into the section and can be parsed.
+  /// - Abbreviation tables can be parsed and contain valid index attributes
+  ///   with correct form encodings.
+  /// - The CU lists reference existing compile units.
+  /// - The buckets have a valid index, or they are empty.
+  /// - All names are reachable via the hash table (they have the correct hash,
+  ///   and the hash is in the correct bucket).
+  /// - Information in the index entries is complete (all required entries are
+  ///   present) and consistent with the debug_info section DIEs.
+  ///
+  /// \param AccelSection section containing the acceleration table
+  /// \param StrData string section
+  ///
+  /// \returns The number of errors occurred during verification
+  unsigned verifyDebugNames(const DWARFSection &AccelSection,
+                            const DataExtractor &StrData);
+
+public:
+  DWARFVerifier(raw_ostream &S, DWARFContext &D,
+                DIDumpOptions DumpOpts = DIDumpOptions::getForSingleDIE());
+
+  /// Verify the information in any of the following sections, if available:
+  /// .debug_abbrev, debug_abbrev.dwo
+  ///
+  /// Any errors are reported to the stream that was this object was
+  /// constructed with.
+  ///
+  /// \returns true if .debug_abbrev and .debug_abbrev.dwo verify successfully,
+  /// false otherwise.
+  bool handleDebugAbbrev();
+
+  /// Verify the information in the .debug_info and .debug_types sections.
+  ///
+  /// Any errors are reported to the stream that this object was
+  /// constructed with.
+  ///
+  /// \returns true if all sections verify successfully, false otherwise.
+  bool handleDebugInfo();
+
+  /// Verify the information in the .debug_line section.
+  ///
+  /// Any errors are reported to the stream that was this object was
+  /// constructed with.
+  ///
+  /// \returns true if the .debug_line verifies successfully, false otherwise.
+  bool handleDebugLine();
+
+  /// Verify the information in accelerator tables, if they exist.
+  ///
+  /// Any errors are reported to the stream that was this object was
+  /// constructed with.
+  ///
+  /// \returns true if the existing Apple-style accelerator tables verify
+  /// successfully, false otherwise.
+  bool handleAccelTables();
+};
+
+static inline bool operator<(const DWARFVerifier::DieRangeInfo &LHS,
+                             const DWARFVerifier::DieRangeInfo &RHS) {
+  return std::tie(LHS.Ranges, LHS.Die) < std::tie(RHS.Ranges, RHS.Die);
+}
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/LICENSE.TXT b/binaryen/third_party/llvm-project/include/llvm/LICENSE.TXT
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/LICENSE.TXT
@@ -0,0 +1,279 @@
+==============================================================================
+The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
+==============================================================================
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+    1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+    2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+    3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+    4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+    5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+    6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+    7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+    8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+    9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+    END OF TERMS AND CONDITIONS
+
+    APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+    Copyright [yyyy] [name of copyright owner]
+
+    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.
+
+
+---- LLVM Exceptions to the Apache 2.0 License ----
+
+As an exception, if, as a result of your compiling your source code, portions
+of this Software are embedded into an Object form of such source code, you
+may redistribute such embedded portions in such Object form without complying
+with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
+
+In addition, if you combine or link compiled forms of this Software with
+software that is licensed under the GPLv2 ("Combined Software") and if a
+court of competent jurisdiction determines that the patent provision (Section
+3), the indemnity provision (Section 9) or other Section of the License
+conflicts with the conditions of the GPLv2, you may retroactively and
+prospectively choose to deem waived or otherwise exclude such Section(s) of
+the License, but only in their entirety and only with respect to the Combined
+Software.
+
+==============================================================================
+Software from third parties included in the LLVM Project:
+==============================================================================
+The LLVM Project contains third party software which is under different license
+terms. All such code will be identified clearly using at least one of two
+mechanisms:
+1) It will be in a separate directory tree with its own `LICENSE.txt` or
+   `LICENSE` file at the top containing the specific license and restrictions
+   which apply to that software, or
+2) It will contain specific license and restriction terms at the top of every
+   file.
+
+==============================================================================
+Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign.
+All rights reserved.
+
+Developed by:
+
+    LLVM Team
+
+    University of Illinois at Urbana-Champaign
+
+    http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimers.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimers in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the names of the LLVM Team, University of Illinois at
+      Urbana-Champaign, nor the names of its contributors may be used to
+      endorse or promote products derived from this Software without specific
+      prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
diff --git a/binaryen/third_party/llvm-project/include/llvm/MC/LaneBitmask.h b/binaryen/third_party/llvm-project/include/llvm/MC/LaneBitmask.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/MC/LaneBitmask.h
@@ -0,0 +1,101 @@
+//===- llvm/MC/LaneBitmask.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// A common definition of LaneBitmask for use in TableGen and CodeGen.
+///
+/// A lane mask is a bitmask representing the covering of a register with
+/// sub-registers.
+///
+/// This is typically used to track liveness at sub-register granularity.
+/// Lane masks for sub-register indices are similar to register units for
+/// physical registers. The individual bits in a lane mask can't be assigned
+/// any specific meaning. They can be used to check if two sub-register
+/// indices overlap.
+///
+/// Iff the target has a register such that:
+///
+///   getSubReg(Reg, A) overlaps getSubReg(Reg, B)
+///
+/// then:
+///
+///   (getSubRegIndexLaneMask(A) & getSubRegIndexLaneMask(B)) != 0
+
+#ifndef LLVM_MC_LANEBITMASK_H
+#define LLVM_MC_LANEBITMASK_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Printable.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+  struct LaneBitmask {
+    // When changing the underlying type, change the format string as well.
+    using Type = unsigned;
+    enum : unsigned { BitWidth = 8*sizeof(Type) };
+    constexpr static const char *const FormatStr = "%08X";
+
+    constexpr LaneBitmask() = default;
+    explicit constexpr LaneBitmask(Type V) : Mask(V) {}
+
+    constexpr bool operator== (LaneBitmask M) const { return Mask == M.Mask; }
+    constexpr bool operator!= (LaneBitmask M) const { return Mask != M.Mask; }
+    constexpr bool operator< (LaneBitmask M)  const { return Mask < M.Mask; }
+    constexpr bool none() const { return Mask == 0; }
+    constexpr bool any()  const { return Mask != 0; }
+    constexpr bool all()  const { return ~Mask == 0; }
+
+    constexpr LaneBitmask operator~() const {
+      return LaneBitmask(~Mask);
+    }
+    constexpr LaneBitmask operator|(LaneBitmask M) const {
+      return LaneBitmask(Mask | M.Mask);
+    }
+    constexpr LaneBitmask operator&(LaneBitmask M) const {
+      return LaneBitmask(Mask & M.Mask);
+    }
+    LaneBitmask &operator|=(LaneBitmask M) {
+      Mask |= M.Mask;
+      return *this;
+    }
+    LaneBitmask &operator&=(LaneBitmask M) {
+      Mask &= M.Mask;
+      return *this;
+    }
+
+    constexpr Type getAsInteger() const { return Mask; }
+
+    unsigned getNumLanes() const {
+      return countPopulation(Mask);
+    }
+    unsigned getHighestLane() const {
+      return Log2_32(Mask);
+    }
+
+    static constexpr LaneBitmask getNone() { return LaneBitmask(0); }
+    static constexpr LaneBitmask getAll() { return ~LaneBitmask(0); }
+    static constexpr LaneBitmask getLane(unsigned Lane) {
+      return LaneBitmask(Type(1) << Lane);
+    }
+
+  private:
+    Type Mask = 0;
+  };
+
+  /// Create Printable object to print LaneBitmasks on a \ref raw_ostream.
+  inline Printable PrintLaneMask(LaneBitmask LaneMask) {
+    return Printable([LaneMask](raw_ostream &OS) {
+      OS << format(LaneBitmask::FormatStr, LaneMask.getAsInteger());
+    });
+  }
+
+} // end namespace llvm
+
+#endif // LLVM_MC_LANEBITMASK_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/MC/MCExpr.h b/binaryen/third_party/llvm-project/include/llvm/MC/MCExpr.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/MC/MCExpr.h
@@ -0,0 +1,616 @@
+//===- MCExpr.h - Assembly Level Expressions --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCEXPR_H
+#define LLVM_MC_MCEXPR_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/SMLoc.h"
+#include <cstdint>
+
+namespace llvm {
+
+class MCAsmInfo;
+class MCAsmLayout;
+class MCAssembler;
+class MCContext;
+class MCFixup;
+class MCFragment;
+class MCSection;
+class MCStreamer;
+class MCSymbol;
+class MCValue;
+class raw_ostream;
+class StringRef;
+
+using SectionAddrMap = DenseMap<const MCSection *, uint64_t>;
+
+/// Base class for the full range of assembler expressions which are
+/// needed for parsing.
+class MCExpr {
+public:
+  enum ExprKind {
+    Binary,    ///< Binary expressions.
+    Constant,  ///< Constant expressions.
+    SymbolRef, ///< References to labels and assigned expressions.
+    Unary,     ///< Unary expressions.
+    Target     ///< Target specific expression.
+  };
+
+private:
+  ExprKind Kind;
+  SMLoc Loc;
+
+  bool evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm,
+                          const MCAsmLayout *Layout,
+                          const SectionAddrMap *Addrs, bool InSet) const;
+
+protected:
+  explicit MCExpr(ExprKind Kind, SMLoc Loc) : Kind(Kind), Loc(Loc) {}
+
+  bool evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm,
+                                 const MCAsmLayout *Layout,
+                                 const MCFixup *Fixup,
+                                 const SectionAddrMap *Addrs, bool InSet) const;
+
+public:
+  MCExpr(const MCExpr &) = delete;
+  MCExpr &operator=(const MCExpr &) = delete;
+
+  /// \name Accessors
+  /// @{
+
+  ExprKind getKind() const { return Kind; }
+  SMLoc getLoc() const { return Loc; }
+
+  /// @}
+  /// \name Utility Methods
+  /// @{
+
+  void print(raw_ostream &OS, const MCAsmInfo *MAI,
+             bool InParens = false) const;
+  void dump() const;
+
+  /// @}
+  /// \name Expression Evaluation
+  /// @{
+
+  /// Try to evaluate the expression to an absolute value.
+  ///
+  /// \param Res - The absolute value, if evaluation succeeds.
+  /// \param Layout - The assembler layout object to use for evaluating symbol
+  /// values. If not given, then only non-symbolic expressions will be
+  /// evaluated.
+  /// \return - True on success.
+  bool evaluateAsAbsolute(int64_t &Res, const MCAsmLayout &Layout,
+                          const SectionAddrMap &Addrs) const;
+  bool evaluateAsAbsolute(int64_t &Res) const;
+  bool evaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const;
+  bool evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const;
+  bool evaluateAsAbsolute(int64_t &Res, const MCAsmLayout &Layout) const;
+
+  bool evaluateKnownAbsolute(int64_t &Res, const MCAsmLayout &Layout) const;
+
+  /// Try to evaluate the expression to a relocatable value, i.e. an
+  /// expression of the fixed form (a - b + constant).
+  ///
+  /// \param Res - The relocatable value, if evaluation succeeds.
+  /// \param Layout - The assembler layout object to use for evaluating values.
+  /// \param Fixup - The Fixup object if available.
+  /// \return - True on success.
+  bool evaluateAsRelocatable(MCValue &Res, const MCAsmLayout *Layout,
+                             const MCFixup *Fixup) const;
+
+  /// Try to evaluate the expression to the form (a - b + constant) where
+  /// neither a nor b are variables.
+  ///
+  /// This is a more aggressive variant of evaluateAsRelocatable. The intended
+  /// use is for when relocations are not available, like the .size directive.
+  bool evaluateAsValue(MCValue &Res, const MCAsmLayout &Layout) const;
+
+  /// Find the "associated section" for this expression, which is
+  /// currently defined as the absolute section for constants, or
+  /// otherwise the section associated with the first defined symbol in the
+  /// expression.
+  MCFragment *findAssociatedFragment() const;
+
+  /// @}
+};
+
+inline raw_ostream &operator<<(raw_ostream &OS, const MCExpr &E) {
+  E.print(OS, nullptr);
+  return OS;
+}
+
+////  Represent a constant integer expression.
+class MCConstantExpr : public MCExpr {
+  int64_t Value;
+  bool PrintInHex = false;
+
+  explicit MCConstantExpr(int64_t Value)
+      : MCExpr(MCExpr::Constant, SMLoc()), Value(Value) {}
+
+  MCConstantExpr(int64_t Value, bool PrintInHex)
+      : MCExpr(MCExpr::Constant, SMLoc()), Value(Value),
+        PrintInHex(PrintInHex) {}
+
+public:
+  /// \name Construction
+  /// @{
+
+  static const MCConstantExpr *create(int64_t Value, MCContext &Ctx,
+                                      bool PrintInHex = false);
+
+  /// @}
+  /// \name Accessors
+  /// @{
+
+  int64_t getValue() const { return Value; }
+
+  bool useHexFormat() const { return PrintInHex; }
+
+  /// @}
+
+  static bool classof(const MCExpr *E) {
+    return E->getKind() == MCExpr::Constant;
+  }
+};
+
+///  Represent a reference to a symbol from inside an expression.
+///
+/// A symbol reference in an expression may be a use of a label, a use of an
+/// assembler variable (defined constant), or constitute an implicit definition
+/// of the symbol as external.
+class MCSymbolRefExpr : public MCExpr {
+public:
+  enum VariantKind : uint16_t {
+    VK_None,
+    VK_Invalid,
+
+    VK_GOT,
+    VK_GOTOFF,
+    VK_GOTREL,
+    VK_GOTPCREL,
+    VK_GOTTPOFF,
+    VK_INDNTPOFF,
+    VK_NTPOFF,
+    VK_GOTNTPOFF,
+    VK_PLT,
+    VK_TLSGD,
+    VK_TLSLD,
+    VK_TLSLDM,
+    VK_TPOFF,
+    VK_DTPOFF,
+    VK_TLSCALL,   // symbol(tlscall)
+    VK_TLSDESC,   // symbol(tlsdesc)
+    VK_TLVP,      // Mach-O thread local variable relocations
+    VK_TLVPPAGE,
+    VK_TLVPPAGEOFF,
+    VK_PAGE,
+    VK_PAGEOFF,
+    VK_GOTPAGE,
+    VK_GOTPAGEOFF,
+    VK_SECREL,
+    VK_SIZE,      // symbol@SIZE
+    VK_WEAKREF,   // The link between the symbols in .weakref foo, bar
+
+    VK_X86_ABS8,
+
+    VK_ARM_NONE,
+    VK_ARM_GOT_PREL,
+    VK_ARM_TARGET1,
+    VK_ARM_TARGET2,
+    VK_ARM_PREL31,
+    VK_ARM_SBREL,          // symbol(sbrel)
+    VK_ARM_TLSLDO,         // symbol(tlsldo)
+    VK_ARM_TLSDESCSEQ,
+
+    VK_AVR_NONE,
+    VK_AVR_LO8,
+    VK_AVR_HI8,
+    VK_AVR_HLO8,
+    VK_AVR_DIFF8,
+    VK_AVR_DIFF16,
+    VK_AVR_DIFF32,
+
+    VK_PPC_LO,             // symbol@l
+    VK_PPC_HI,             // symbol@h
+    VK_PPC_HA,             // symbol@ha
+    VK_PPC_HIGH,           // symbol@high
+    VK_PPC_HIGHA,          // symbol@higha
+    VK_PPC_HIGHER,         // symbol@higher
+    VK_PPC_HIGHERA,        // symbol@highera
+    VK_PPC_HIGHEST,        // symbol@highest
+    VK_PPC_HIGHESTA,       // symbol@highesta
+    VK_PPC_GOT_LO,         // symbol@got@l
+    VK_PPC_GOT_HI,         // symbol@got@h
+    VK_PPC_GOT_HA,         // symbol@got@ha
+    VK_PPC_TOCBASE,        // symbol@tocbase
+    VK_PPC_TOC,            // symbol@toc
+    VK_PPC_TOC_LO,         // symbol@toc@l
+    VK_PPC_TOC_HI,         // symbol@toc@h
+    VK_PPC_TOC_HA,         // symbol@toc@ha
+    VK_PPC_U,              // symbol@u
+    VK_PPC_L,              // symbol@l
+    VK_PPC_DTPMOD,         // symbol@dtpmod
+    VK_PPC_TPREL_LO,       // symbol@tprel@l
+    VK_PPC_TPREL_HI,       // symbol@tprel@h
+    VK_PPC_TPREL_HA,       // symbol@tprel@ha
+    VK_PPC_TPREL_HIGH,     // symbol@tprel@high
+    VK_PPC_TPREL_HIGHA,    // symbol@tprel@higha
+    VK_PPC_TPREL_HIGHER,   // symbol@tprel@higher
+    VK_PPC_TPREL_HIGHERA,  // symbol@tprel@highera
+    VK_PPC_TPREL_HIGHEST,  // symbol@tprel@highest
+    VK_PPC_TPREL_HIGHESTA, // symbol@tprel@highesta
+    VK_PPC_DTPREL_LO,      // symbol@dtprel@l
+    VK_PPC_DTPREL_HI,      // symbol@dtprel@h
+    VK_PPC_DTPREL_HA,      // symbol@dtprel@ha
+    VK_PPC_DTPREL_HIGH,    // symbol@dtprel@high
+    VK_PPC_DTPREL_HIGHA,   // symbol@dtprel@higha
+    VK_PPC_DTPREL_HIGHER,  // symbol@dtprel@higher
+    VK_PPC_DTPREL_HIGHERA, // symbol@dtprel@highera
+    VK_PPC_DTPREL_HIGHEST, // symbol@dtprel@highest
+    VK_PPC_DTPREL_HIGHESTA,// symbol@dtprel@highesta
+    VK_PPC_GOT_TPREL,      // symbol@got@tprel
+    VK_PPC_GOT_TPREL_LO,   // symbol@got@tprel@l
+    VK_PPC_GOT_TPREL_HI,   // symbol@got@tprel@h
+    VK_PPC_GOT_TPREL_HA,   // symbol@got@tprel@ha
+    VK_PPC_GOT_DTPREL,     // symbol@got@dtprel
+    VK_PPC_GOT_DTPREL_LO,  // symbol@got@dtprel@l
+    VK_PPC_GOT_DTPREL_HI,  // symbol@got@dtprel@h
+    VK_PPC_GOT_DTPREL_HA,  // symbol@got@dtprel@ha
+    VK_PPC_TLS,            // symbol@tls
+    VK_PPC_GOT_TLSGD,      // symbol@got@tlsgd
+    VK_PPC_GOT_TLSGD_LO,   // symbol@got@tlsgd@l
+    VK_PPC_GOT_TLSGD_HI,   // symbol@got@tlsgd@h
+    VK_PPC_GOT_TLSGD_HA,   // symbol@got@tlsgd@ha
+    VK_PPC_TLSGD,          // symbol@tlsgd
+    VK_PPC_GOT_TLSLD,      // symbol@got@tlsld
+    VK_PPC_GOT_TLSLD_LO,   // symbol@got@tlsld@l
+    VK_PPC_GOT_TLSLD_HI,   // symbol@got@tlsld@h
+    VK_PPC_GOT_TLSLD_HA,   // symbol@got@tlsld@ha
+    VK_PPC_TLSLD,          // symbol@tlsld
+    VK_PPC_LOCAL,          // symbol@local
+
+    VK_COFF_IMGREL32, // symbol@imgrel (image-relative)
+
+    VK_Hexagon_PCREL,
+    VK_Hexagon_LO16,
+    VK_Hexagon_HI16,
+    VK_Hexagon_GPREL,
+    VK_Hexagon_GD_GOT,
+    VK_Hexagon_LD_GOT,
+    VK_Hexagon_GD_PLT,
+    VK_Hexagon_LD_PLT,
+    VK_Hexagon_IE,
+    VK_Hexagon_IE_GOT,
+
+    VK_WASM_TYPEINDEX, // Reference to a symbol's type (signature)
+    VK_WASM_MBREL,     // Memory address relative to memory base
+    VK_WASM_TBREL,     // Table index relative to table bare
+
+    VK_AMDGPU_GOTPCREL32_LO, // symbol@gotpcrel32@lo
+    VK_AMDGPU_GOTPCREL32_HI, // symbol@gotpcrel32@hi
+    VK_AMDGPU_REL32_LO,      // symbol@rel32@lo
+    VK_AMDGPU_REL32_HI,      // symbol@rel32@hi
+    VK_AMDGPU_REL64,         // symbol@rel64
+    VK_AMDGPU_ABS32_LO,      // symbol@abs32@lo
+    VK_AMDGPU_ABS32_HI,      // symbol@abs32@hi
+
+    VK_TPREL,
+    VK_DTPREL
+  };
+
+private:
+  /// The symbol reference modifier.
+  const VariantKind Kind;
+
+  /// Specifies how the variant kind should be printed.
+  const unsigned UseParensForSymbolVariant : 1;
+
+  // FIXME: Remove this bit.
+  const unsigned HasSubsectionsViaSymbols : 1;
+
+  /// The symbol being referenced.
+  const MCSymbol *Symbol;
+
+  explicit MCSymbolRefExpr(const MCSymbol *Symbol, VariantKind Kind,
+                           const MCAsmInfo *MAI, SMLoc Loc = SMLoc());
+
+public:
+  /// \name Construction
+  /// @{
+
+  static const MCSymbolRefExpr *create(const MCSymbol *Symbol, MCContext &Ctx) {
+    return MCSymbolRefExpr::create(Symbol, VK_None, Ctx);
+  }
+
+  static const MCSymbolRefExpr *create(const MCSymbol *Symbol, VariantKind Kind,
+                                       MCContext &Ctx, SMLoc Loc = SMLoc());
+  static const MCSymbolRefExpr *create(StringRef Name, VariantKind Kind,
+                                       MCContext &Ctx);
+
+  /// @}
+  /// \name Accessors
+  /// @{
+
+  const MCSymbol &getSymbol() const { return *Symbol; }
+
+  VariantKind getKind() const { return Kind; }
+
+  void printVariantKind(raw_ostream &OS) const;
+
+  bool hasSubsectionsViaSymbols() const { return HasSubsectionsViaSymbols; }
+
+  /// @}
+  /// \name Static Utility Functions
+  /// @{
+
+  static StringRef getVariantKindName(VariantKind Kind);
+
+  static VariantKind getVariantKindForName(StringRef Name);
+
+  /// @}
+
+  static bool classof(const MCExpr *E) {
+    return E->getKind() == MCExpr::SymbolRef;
+  }
+};
+
+/// Unary assembler expressions.
+class MCUnaryExpr : public MCExpr {
+public:
+  enum Opcode {
+    LNot,  ///< Logical negation.
+    Minus, ///< Unary minus.
+    Not,   ///< Bitwise negation.
+    Plus   ///< Unary plus.
+  };
+
+private:
+  Opcode Op;
+  const MCExpr *Expr;
+
+  MCUnaryExpr(Opcode Op, const MCExpr *Expr, SMLoc Loc)
+      : MCExpr(MCExpr::Unary, Loc), Op(Op), Expr(Expr) {}
+
+public:
+  /// \name Construction
+  /// @{
+
+  static const MCUnaryExpr *create(Opcode Op, const MCExpr *Expr,
+                                   MCContext &Ctx, SMLoc Loc = SMLoc());
+
+  static const MCUnaryExpr *createLNot(const MCExpr *Expr, MCContext &Ctx, SMLoc Loc = SMLoc()) {
+    return create(LNot, Expr, Ctx, Loc);
+  }
+
+  static const MCUnaryExpr *createMinus(const MCExpr *Expr, MCContext &Ctx, SMLoc Loc = SMLoc()) {
+    return create(Minus, Expr, Ctx, Loc);
+  }
+
+  static const MCUnaryExpr *createNot(const MCExpr *Expr, MCContext &Ctx, SMLoc Loc = SMLoc()) {
+    return create(Not, Expr, Ctx, Loc);
+  }
+
+  static const MCUnaryExpr *createPlus(const MCExpr *Expr, MCContext &Ctx, SMLoc Loc = SMLoc()) {
+    return create(Plus, Expr, Ctx, Loc);
+  }
+
+  /// @}
+  /// \name Accessors
+  /// @{
+
+  /// Get the kind of this unary expression.
+  Opcode getOpcode() const { return Op; }
+
+  /// Get the child of this unary expression.
+  const MCExpr *getSubExpr() const { return Expr; }
+
+  /// @}
+
+  static bool classof(const MCExpr *E) {
+    return E->getKind() == MCExpr::Unary;
+  }
+};
+
+/// Binary assembler expressions.
+class MCBinaryExpr : public MCExpr {
+public:
+  enum Opcode {
+    Add,  ///< Addition.
+    And,  ///< Bitwise and.
+    Div,  ///< Signed division.
+    EQ,   ///< Equality comparison.
+    GT,   ///< Signed greater than comparison (result is either 0 or some
+          ///< target-specific non-zero value)
+    GTE,  ///< Signed greater than or equal comparison (result is either 0 or
+          ///< some target-specific non-zero value).
+    LAnd, ///< Logical and.
+    LOr,  ///< Logical or.
+    LT,   ///< Signed less than comparison (result is either 0 or
+          ///< some target-specific non-zero value).
+    LTE,  ///< Signed less than or equal comparison (result is either 0 or
+          ///< some target-specific non-zero value).
+    Mod,  ///< Signed remainder.
+    Mul,  ///< Multiplication.
+    NE,   ///< Inequality comparison.
+    Or,   ///< Bitwise or.
+    Shl,  ///< Shift left.
+    AShr, ///< Arithmetic shift right.
+    LShr, ///< Logical shift right.
+    Sub,  ///< Subtraction.
+    Xor   ///< Bitwise exclusive or.
+  };
+
+private:
+  Opcode Op;
+  const MCExpr *LHS, *RHS;
+
+  MCBinaryExpr(Opcode Op, const MCExpr *LHS, const MCExpr *RHS,
+               SMLoc Loc = SMLoc())
+      : MCExpr(MCExpr::Binary, Loc), Op(Op), LHS(LHS), RHS(RHS) {}
+
+public:
+  /// \name Construction
+  /// @{
+
+  static const MCBinaryExpr *create(Opcode Op, const MCExpr *LHS,
+                                    const MCExpr *RHS, MCContext &Ctx,
+                                    SMLoc Loc = SMLoc());
+
+  static const MCBinaryExpr *createAdd(const MCExpr *LHS, const MCExpr *RHS,
+                                       MCContext &Ctx) {
+    return create(Add, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createAnd(const MCExpr *LHS, const MCExpr *RHS,
+                                       MCContext &Ctx) {
+    return create(And, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createDiv(const MCExpr *LHS, const MCExpr *RHS,
+                                       MCContext &Ctx) {
+    return create(Div, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createEQ(const MCExpr *LHS, const MCExpr *RHS,
+                                      MCContext &Ctx) {
+    return create(EQ, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createGT(const MCExpr *LHS, const MCExpr *RHS,
+                                      MCContext &Ctx) {
+    return create(GT, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createGTE(const MCExpr *LHS, const MCExpr *RHS,
+                                       MCContext &Ctx) {
+    return create(GTE, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createLAnd(const MCExpr *LHS, const MCExpr *RHS,
+                                        MCContext &Ctx) {
+    return create(LAnd, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createLOr(const MCExpr *LHS, const MCExpr *RHS,
+                                       MCContext &Ctx) {
+    return create(LOr, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createLT(const MCExpr *LHS, const MCExpr *RHS,
+                                      MCContext &Ctx) {
+    return create(LT, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createLTE(const MCExpr *LHS, const MCExpr *RHS,
+                                       MCContext &Ctx) {
+    return create(LTE, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createMod(const MCExpr *LHS, const MCExpr *RHS,
+                                       MCContext &Ctx) {
+    return create(Mod, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createMul(const MCExpr *LHS, const MCExpr *RHS,
+                                       MCContext &Ctx) {
+    return create(Mul, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createNE(const MCExpr *LHS, const MCExpr *RHS,
+                                      MCContext &Ctx) {
+    return create(NE, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createOr(const MCExpr *LHS, const MCExpr *RHS,
+                                      MCContext &Ctx) {
+    return create(Or, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createShl(const MCExpr *LHS, const MCExpr *RHS,
+                                       MCContext &Ctx) {
+    return create(Shl, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createAShr(const MCExpr *LHS, const MCExpr *RHS,
+                                       MCContext &Ctx) {
+    return create(AShr, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createLShr(const MCExpr *LHS, const MCExpr *RHS,
+                                       MCContext &Ctx) {
+    return create(LShr, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createSub(const MCExpr *LHS, const MCExpr *RHS,
+                                       MCContext &Ctx) {
+    return create(Sub, LHS, RHS, Ctx);
+  }
+
+  static const MCBinaryExpr *createXor(const MCExpr *LHS, const MCExpr *RHS,
+                                       MCContext &Ctx) {
+    return create(Xor, LHS, RHS, Ctx);
+  }
+
+  /// @}
+  /// \name Accessors
+  /// @{
+
+  /// Get the kind of this binary expression.
+  Opcode getOpcode() const { return Op; }
+
+  /// Get the left-hand side expression of the binary operator.
+  const MCExpr *getLHS() const { return LHS; }
+
+  /// Get the right-hand side expression of the binary operator.
+  const MCExpr *getRHS() const { return RHS; }
+
+  /// @}
+
+  static bool classof(const MCExpr *E) {
+    return E->getKind() == MCExpr::Binary;
+  }
+};
+
+/// This is an extension point for target-specific MCExpr subclasses to
+/// implement.
+///
+/// NOTE: All subclasses are required to have trivial destructors because
+/// MCExprs are bump pointer allocated and not destructed.
+class MCTargetExpr : public MCExpr {
+  virtual void anchor();
+
+protected:
+  MCTargetExpr() : MCExpr(Target, SMLoc()) {}
+  virtual ~MCTargetExpr() = default;
+
+public:
+  virtual void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const = 0;
+  virtual bool evaluateAsRelocatableImpl(MCValue &Res,
+                                         const MCAsmLayout *Layout,
+                                         const MCFixup *Fixup) const = 0;
+  // allow Target Expressions to be checked for equality
+  virtual bool isEqualTo(const MCExpr *x) const { return false; }
+  // This should be set when assigned expressions are not valid ".set"
+  // expressions, e.g. registers, and must be inlined.
+  virtual bool inlineAssignedExpr() const { return false; }
+  virtual void visitUsedExpr(MCStreamer& Streamer) const = 0;
+  virtual MCFragment *findAssociatedFragment() const = 0;
+
+  virtual void fixELFSymbolsInTLSFixups(MCAssembler &) const = 0;
+
+  static bool classof(const MCExpr *E) {
+    return E->getKind() == MCExpr::Target;
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_MC_MCEXPR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/MC/MCFixup.h b/binaryen/third_party/llvm-project/include/llvm/MC/MCFixup.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/MC/MCFixup.h
@@ -0,0 +1,202 @@
+//===-- llvm/MC/MCFixup.h - Instruction Relocation and Patching -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCFIXUP_H
+#define LLVM_MC_MCFIXUP_H
+
+#include "llvm/MC/MCExpr.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/SMLoc.h"
+#include <cassert>
+
+namespace llvm {
+class MCExpr;
+
+/// Extensible enumeration to represent the type of a fixup.
+enum MCFixupKind {
+  FK_NONE = 0,    ///< A no-op fixup.
+  FK_Data_1,      ///< A one-byte fixup.
+  FK_Data_2,      ///< A two-byte fixup.
+  FK_Data_4,      ///< A four-byte fixup.
+  FK_Data_8,      ///< A eight-byte fixup.
+  FK_Data_6b,     ///< A six-bits fixup.
+  FK_PCRel_1,     ///< A one-byte pc relative fixup.
+  FK_PCRel_2,     ///< A two-byte pc relative fixup.
+  FK_PCRel_4,     ///< A four-byte pc relative fixup.
+  FK_PCRel_8,     ///< A eight-byte pc relative fixup.
+  FK_GPRel_1,     ///< A one-byte gp relative fixup.
+  FK_GPRel_2,     ///< A two-byte gp relative fixup.
+  FK_GPRel_4,     ///< A four-byte gp relative fixup.
+  FK_GPRel_8,     ///< A eight-byte gp relative fixup.
+  FK_DTPRel_4,    ///< A four-byte dtp relative fixup.
+  FK_DTPRel_8,    ///< A eight-byte dtp relative fixup.
+  FK_TPRel_4,     ///< A four-byte tp relative fixup.
+  FK_TPRel_8,     ///< A eight-byte tp relative fixup.
+  FK_SecRel_1,    ///< A one-byte section relative fixup.
+  FK_SecRel_2,    ///< A two-byte section relative fixup.
+  FK_SecRel_4,    ///< A four-byte section relative fixup.
+  FK_SecRel_8,    ///< A eight-byte section relative fixup.
+  FK_Data_Add_1,  ///< A one-byte add fixup.
+  FK_Data_Add_2,  ///< A two-byte add fixup.
+  FK_Data_Add_4,  ///< A four-byte add fixup.
+  FK_Data_Add_8,  ///< A eight-byte add fixup.
+  FK_Data_Add_6b, ///< A six-bits add fixup.
+  FK_Data_Sub_1,  ///< A one-byte sub fixup.
+  FK_Data_Sub_2,  ///< A two-byte sub fixup.
+  FK_Data_Sub_4,  ///< A four-byte sub fixup.
+  FK_Data_Sub_8,  ///< A eight-byte sub fixup.
+  FK_Data_Sub_6b, ///< A six-bits sub fixup.
+
+  FirstTargetFixupKind = 128,
+
+  // Limit range of target fixups, in case we want to pack more efficiently
+  // later.
+  MaxTargetFixupKind = (1 << 8)
+};
+
+/// Encode information on a single operation to perform on a byte
+/// sequence (e.g., an encoded instruction) which requires assemble- or run-
+/// time patching.
+///
+/// Fixups are used any time the target instruction encoder needs to represent
+/// some value in an instruction which is not yet concrete. The encoder will
+/// encode the instruction assuming the value is 0, and emit a fixup which
+/// communicates to the assembler backend how it should rewrite the encoded
+/// value.
+///
+/// During the process of relaxation, the assembler will apply fixups as
+/// symbolic values become concrete. When relaxation is complete, any remaining
+/// fixups become relocations in the object file (or errors, if the fixup cannot
+/// be encoded on the target).
+class MCFixup {
+  /// The value to put into the fixup location. The exact interpretation of the
+  /// expression is target dependent, usually it will be one of the operands to
+  /// an instruction or an assembler directive.
+  const MCExpr *Value = nullptr;
+
+  /// The byte index of start of the relocation inside the MCFragment.
+  uint32_t Offset = 0;
+
+  /// The target dependent kind of fixup item this is. The kind is used to
+  /// determine how the operand value should be encoded into the instruction.
+  MCFixupKind Kind = FK_NONE;
+
+  /// The source location which gave rise to the fixup, if any.
+  SMLoc Loc;
+public:
+  static MCFixup create(uint32_t Offset, const MCExpr *Value,
+                        MCFixupKind Kind, SMLoc Loc = SMLoc()) {
+    assert(Kind < MaxTargetFixupKind && "Kind out of range!");
+    MCFixup FI;
+    FI.Value = Value;
+    FI.Offset = Offset;
+    FI.Kind = Kind;
+    FI.Loc = Loc;
+    return FI;
+  }
+
+  /// Return a fixup corresponding to the add half of a add/sub fixup pair for
+  /// the given Fixup.
+  static MCFixup createAddFor(const MCFixup &Fixup) {
+    MCFixup FI;
+    FI.Value = Fixup.getValue();
+    FI.Offset = Fixup.getOffset();
+    FI.Kind = getAddKindForKind(Fixup.getKind());
+    FI.Loc = Fixup.getLoc();
+    return FI;
+  }
+
+  /// Return a fixup corresponding to the sub half of a add/sub fixup pair for
+  /// the given Fixup.
+  static MCFixup createSubFor(const MCFixup &Fixup) {
+    MCFixup FI;
+    FI.Value = Fixup.getValue();
+    FI.Offset = Fixup.getOffset();
+    FI.Kind = getSubKindForKind(Fixup.getKind());
+    FI.Loc = Fixup.getLoc();
+    return FI;
+  }
+
+  MCFixupKind getKind() const { return Kind; }
+
+  unsigned getTargetKind() const { return Kind; }
+
+  uint32_t getOffset() const { return Offset; }
+  void setOffset(uint32_t Value) { Offset = Value; }
+
+  const MCExpr *getValue() const { return Value; }
+
+  /// Return the generic fixup kind for a value with the given size. It
+  /// is an error to pass an unsupported size.
+  static MCFixupKind getKindForSize(unsigned Size, bool IsPCRel) {
+    switch (Size) {
+    default: llvm_unreachable("Invalid generic fixup size!");
+    case 1:
+      return IsPCRel ? FK_PCRel_1 : FK_Data_1;
+    case 2:
+      return IsPCRel ? FK_PCRel_2 : FK_Data_2;
+    case 4:
+      return IsPCRel ? FK_PCRel_4 : FK_Data_4;
+    case 8:
+      return IsPCRel ? FK_PCRel_8 : FK_Data_8;
+    }
+  }
+
+  /// Return the generic fixup kind for a value with the given size in bits.
+  /// It is an error to pass an unsupported size.
+  static MCFixupKind getKindForSizeInBits(unsigned Size, bool IsPCRel) {
+    switch (Size) {
+    default:
+      llvm_unreachable("Invalid generic fixup size!");
+    case 6:
+      assert(!IsPCRel && "Invalid pc-relative fixup size!");
+      return FK_Data_6b;
+    case 8:
+      return IsPCRel ? FK_PCRel_1 : FK_Data_1;
+    case 16:
+      return IsPCRel ? FK_PCRel_2 : FK_Data_2;
+    case 32:
+      return IsPCRel ? FK_PCRel_4 : FK_Data_4;
+    case 64:
+      return IsPCRel ? FK_PCRel_8 : FK_Data_8;
+    }
+  }
+
+  /// Return the generic fixup kind for an addition with a given size. It
+  /// is an error to pass an unsupported size.
+  static MCFixupKind getAddKindForKind(MCFixupKind Kind) {
+    switch (Kind) {
+    default: llvm_unreachable("Unknown type to convert!");
+    case FK_Data_1: return FK_Data_Add_1;
+    case FK_Data_2: return FK_Data_Add_2;
+    case FK_Data_4: return FK_Data_Add_4;
+    case FK_Data_8: return FK_Data_Add_8;
+    case FK_Data_6b: return FK_Data_Add_6b;
+    }
+  }
+
+  /// Return the generic fixup kind for an subtraction with a given size. It
+  /// is an error to pass an unsupported size.
+  static MCFixupKind getSubKindForKind(MCFixupKind Kind) {
+    switch (Kind) {
+    default: llvm_unreachable("Unknown type to convert!");
+    case FK_Data_1: return FK_Data_Sub_1;
+    case FK_Data_2: return FK_Data_Sub_2;
+    case FK_Data_4: return FK_Data_Sub_4;
+    case FK_Data_8: return FK_Data_Sub_8;
+    case FK_Data_6b: return FK_Data_Sub_6b;
+    }
+  }
+
+  SMLoc getLoc() const { return Loc; }
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/MC/MCFragment.h b/binaryen/third_party/llvm-project/include/llvm/MC/MCFragment.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/MC/MCFragment.h
@@ -0,0 +1,663 @@
+//===- MCFragment.h - Fragment type hierarchy -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCFRAGMENT_H
+#define LLVM_MC_MCFRAGMENT_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/ilist_node.h"
+#include "llvm/MC/MCFixup.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/SMLoc.h"
+#include <cstdint>
+#include <utility>
+
+namespace llvm {
+
+class MCSection;
+class MCSubtargetInfo;
+class MCSymbol;
+
+class MCFragment : public ilist_node_with_parent<MCFragment, MCSection> {
+  friend class MCAsmLayout;
+
+public:
+  enum FragmentType : uint8_t {
+    FT_Align,
+    FT_Data,
+    FT_CompactEncodedInst,
+    FT_Fill,
+    FT_Relaxable,
+    FT_Org,
+    FT_Dwarf,
+    FT_DwarfFrame,
+    FT_LEB,
+    FT_Padding,
+    FT_SymbolId,
+    FT_CVInlineLines,
+    FT_CVDefRange,
+    FT_Dummy
+  };
+
+private:
+  FragmentType Kind;
+
+protected:
+  bool HasInstructions;
+
+private:
+  /// LayoutOrder - The layout order of this fragment.
+  unsigned LayoutOrder;
+
+  /// The data for the section this fragment is in.
+  MCSection *Parent;
+
+  /// Atom - The atom this fragment is in, as represented by its defining
+  /// symbol.
+  const MCSymbol *Atom;
+
+  /// \name Assembler Backend Data
+  /// @{
+  //
+  // FIXME: This could all be kept private to the assembler implementation.
+
+  /// Offset - The offset of this fragment in its section. This is ~0 until
+  /// initialized.
+  uint64_t Offset;
+
+  /// @}
+
+protected:
+  MCFragment(FragmentType Kind, bool HasInstructions,
+             MCSection *Parent = nullptr);
+
+  ~MCFragment();
+
+public:
+  MCFragment() = delete;
+  MCFragment(const MCFragment &) = delete;
+  MCFragment &operator=(const MCFragment &) = delete;
+
+  /// Destroys the current fragment.
+  ///
+  /// This must be used instead of delete as MCFragment is non-virtual.
+  /// This method will dispatch to the appropriate subclass.
+  void destroy();
+
+  FragmentType getKind() const { return Kind; }
+
+  MCSection *getParent() const { return Parent; }
+  void setParent(MCSection *Value) { Parent = Value; }
+
+  const MCSymbol *getAtom() const { return Atom; }
+  void setAtom(const MCSymbol *Value) { Atom = Value; }
+
+  unsigned getLayoutOrder() const { return LayoutOrder; }
+  void setLayoutOrder(unsigned Value) { LayoutOrder = Value; }
+
+  /// Does this fragment have instructions emitted into it? By default
+  /// this is false, but specific fragment types may set it to true.
+  bool hasInstructions() const { return HasInstructions; }
+
+  /// Return true if given frgment has FT_Dummy type.
+  bool isDummy() const { return Kind == FT_Dummy; }
+
+  void dump() const;
+};
+
+class MCDummyFragment : public MCFragment {
+public:
+  explicit MCDummyFragment(MCSection *Sec) : MCFragment(FT_Dummy, false, Sec) {}
+
+  static bool classof(const MCFragment *F) { return F->getKind() == FT_Dummy; }
+};
+
+/// Interface implemented by fragments that contain encoded instructions and/or
+/// data.
+///
+class MCEncodedFragment : public MCFragment {
+  /// Should this fragment be aligned to the end of a bundle?
+  bool AlignToBundleEnd = false;
+
+  uint8_t BundlePadding = 0;
+
+protected:
+  MCEncodedFragment(MCFragment::FragmentType FType, bool HasInstructions,
+                    MCSection *Sec)
+      : MCFragment(FType, HasInstructions, Sec) {}
+
+  /// STI - The MCSubtargetInfo in effect when the instruction was encoded.
+  /// must be non-null for instructions.
+  const MCSubtargetInfo *STI = nullptr;
+
+public:
+  static bool classof(const MCFragment *F) {
+    MCFragment::FragmentType Kind = F->getKind();
+    switch (Kind) {
+    default:
+      return false;
+    case MCFragment::FT_Relaxable:
+    case MCFragment::FT_CompactEncodedInst:
+    case MCFragment::FT_Data:
+    case MCFragment::FT_Dwarf:
+    case MCFragment::FT_DwarfFrame:
+      return true;
+    }
+  }
+
+  /// Should this fragment be placed at the end of an aligned bundle?
+  bool alignToBundleEnd() const { return AlignToBundleEnd; }
+  void setAlignToBundleEnd(bool V) { AlignToBundleEnd = V; }
+
+  /// Get the padding size that must be inserted before this fragment.
+  /// Used for bundling. By default, no padding is inserted.
+  /// Note that padding size is restricted to 8 bits. This is an optimization
+  /// to reduce the amount of space used for each fragment. In practice, larger
+  /// padding should never be required.
+  uint8_t getBundlePadding() const { return BundlePadding; }
+
+  /// Set the padding size for this fragment. By default it's a no-op,
+  /// and only some fragments have a meaningful implementation.
+  void setBundlePadding(uint8_t N) { BundlePadding = N; }
+
+  /// Retrieve the MCSubTargetInfo in effect when the instruction was encoded.
+  /// Guaranteed to be non-null if hasInstructions() == true
+  const MCSubtargetInfo *getSubtargetInfo() const { return STI; }
+
+  /// Record that the fragment contains instructions with the MCSubtargetInfo in
+  /// effect when the instruction was encoded.
+  void setHasInstructions(const MCSubtargetInfo &STI) {
+    HasInstructions = true;
+    this->STI = &STI;
+  }
+};
+
+/// Interface implemented by fragments that contain encoded instructions and/or
+/// data.
+///
+template<unsigned ContentsSize>
+class MCEncodedFragmentWithContents : public MCEncodedFragment {
+  SmallVector<char, ContentsSize> Contents;
+
+protected:
+  MCEncodedFragmentWithContents(MCFragment::FragmentType FType,
+                                bool HasInstructions,
+                                MCSection *Sec)
+      : MCEncodedFragment(FType, HasInstructions, Sec) {}
+
+public:
+  SmallVectorImpl<char> &getContents() { return Contents; }
+  const SmallVectorImpl<char> &getContents() const { return Contents; }
+};
+
+/// Interface implemented by fragments that contain encoded instructions and/or
+/// data and also have fixups registered.
+///
+template<unsigned ContentsSize, unsigned FixupsSize>
+class MCEncodedFragmentWithFixups :
+  public MCEncodedFragmentWithContents<ContentsSize> {
+
+  /// Fixups - The list of fixups in this fragment.
+  SmallVector<MCFixup, FixupsSize> Fixups;
+
+protected:
+  MCEncodedFragmentWithFixups(MCFragment::FragmentType FType,
+                              bool HasInstructions,
+                              MCSection *Sec)
+      : MCEncodedFragmentWithContents<ContentsSize>(FType, HasInstructions,
+                                                    Sec) {}
+
+public:
+
+  using const_fixup_iterator = SmallVectorImpl<MCFixup>::const_iterator;
+  using fixup_iterator = SmallVectorImpl<MCFixup>::iterator;
+
+  SmallVectorImpl<MCFixup> &getFixups() { return Fixups; }
+  const SmallVectorImpl<MCFixup> &getFixups() const { return Fixups; }
+
+  fixup_iterator fixup_begin() { return Fixups.begin(); }
+  const_fixup_iterator fixup_begin() const { return Fixups.begin(); }
+
+  fixup_iterator fixup_end() { return Fixups.end(); }
+  const_fixup_iterator fixup_end() const { return Fixups.end(); }
+
+  static bool classof(const MCFragment *F) {
+    MCFragment::FragmentType Kind = F->getKind();
+    return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data ||
+           Kind == MCFragment::FT_CVDefRange || Kind == MCFragment::FT_Dwarf ||
+           Kind == MCFragment::FT_DwarfFrame;
+  }
+};
+
+/// Fragment for data and encoded instructions.
+///
+class MCDataFragment : public MCEncodedFragmentWithFixups<32, 4> {
+public:
+  MCDataFragment(MCSection *Sec = nullptr)
+      : MCEncodedFragmentWithFixups<32, 4>(FT_Data, false, Sec) {}
+
+  static bool classof(const MCFragment *F) {
+    return F->getKind() == MCFragment::FT_Data;
+  }
+};
+
+/// This is a compact (memory-size-wise) fragment for holding an encoded
+/// instruction (non-relaxable) that has no fixups registered. When applicable,
+/// it can be used instead of MCDataFragment and lead to lower memory
+/// consumption.
+///
+class MCCompactEncodedInstFragment : public MCEncodedFragmentWithContents<4> {
+public:
+  MCCompactEncodedInstFragment(MCSection *Sec = nullptr)
+      : MCEncodedFragmentWithContents(FT_CompactEncodedInst, true, Sec) {
+  }
+
+  static bool classof(const MCFragment *F) {
+    return F->getKind() == MCFragment::FT_CompactEncodedInst;
+  }
+};
+
+/// A relaxable fragment holds on to its MCInst, since it may need to be
+/// relaxed during the assembler layout and relaxation stage.
+///
+class MCRelaxableFragment : public MCEncodedFragmentWithFixups<8, 1> {
+
+  /// Inst - The instruction this is a fragment for.
+  MCInst Inst;
+
+public:
+  MCRelaxableFragment(const MCInst &Inst, const MCSubtargetInfo &STI,
+                      MCSection *Sec = nullptr)
+      : MCEncodedFragmentWithFixups(FT_Relaxable, true, Sec),
+        Inst(Inst) { this->STI = &STI; }
+
+  const MCInst &getInst() const { return Inst; }
+  void setInst(const MCInst &Value) { Inst = Value; }
+
+  static bool classof(const MCFragment *F) {
+    return F->getKind() == MCFragment::FT_Relaxable;
+  }
+};
+
+class MCAlignFragment : public MCFragment {
+  /// Alignment - The alignment to ensure, in bytes.
+  unsigned Alignment;
+
+  /// EmitNops - Flag to indicate that (optimal) NOPs should be emitted instead
+  /// of using the provided value. The exact interpretation of this flag is
+  /// target dependent.
+  bool EmitNops : 1;
+
+  /// Value - Value to use for filling padding bytes.
+  int64_t Value;
+
+  /// ValueSize - The size of the integer (in bytes) of \p Value.
+  unsigned ValueSize;
+
+  /// MaxBytesToEmit - The maximum number of bytes to emit; if the alignment
+  /// cannot be satisfied in this width then this fragment is ignored.
+  unsigned MaxBytesToEmit;
+
+public:
+  MCAlignFragment(unsigned Alignment, int64_t Value, unsigned ValueSize,
+                  unsigned MaxBytesToEmit, MCSection *Sec = nullptr)
+      : MCFragment(FT_Align, false, Sec), Alignment(Alignment), EmitNops(false),
+        Value(Value), ValueSize(ValueSize), MaxBytesToEmit(MaxBytesToEmit) {}
+
+  /// \name Accessors
+  /// @{
+
+  unsigned getAlignment() const { return Alignment; }
+
+  int64_t getValue() const { return Value; }
+
+  unsigned getValueSize() const { return ValueSize; }
+
+  unsigned getMaxBytesToEmit() const { return MaxBytesToEmit; }
+
+  bool hasEmitNops() const { return EmitNops; }
+  void setEmitNops(bool Value) { EmitNops = Value; }
+
+  /// @}
+
+  static bool classof(const MCFragment *F) {
+    return F->getKind() == MCFragment::FT_Align;
+  }
+};
+
+/// Fragment for adding required padding.
+/// This fragment is always inserted before an instruction, and holds that
+/// instruction as context information (as well as a mask of kinds) for
+/// determining the padding size.
+///
+class MCPaddingFragment : public MCFragment {
+  /// A mask containing all the kinds relevant to this fragment. i.e. the i'th
+  /// bit will be set iff kind i is relevant to this fragment.
+  uint64_t PaddingPoliciesMask;
+  /// A boolean indicating if this fragment will actually hold padding. If its
+  /// value is false, then this fragment serves only as a placeholder,
+  /// containing data to assist other insertion point in their decision making.
+  bool IsInsertionPoint;
+
+  uint64_t Size;
+
+  struct MCInstInfo {
+    bool IsInitialized;
+    MCInst Inst;
+    /// A boolean indicating whether the instruction pointed by this fragment is
+    /// a fixed size instruction or a relaxable instruction held by a
+    /// MCRelaxableFragment.
+    bool IsImmutableSizedInst;
+    union {
+      /// If the instruction is a fixed size instruction, hold its size.
+      size_t InstSize;
+      /// Otherwise, hold a pointer to the MCRelaxableFragment holding it.
+      MCRelaxableFragment *InstFragment;
+    };
+  };
+  MCInstInfo InstInfo;
+
+public:
+  static const uint64_t PFK_None = UINT64_C(0);
+
+  enum MCPaddingFragmentKind {
+    // values 0-7 are reserved for future target independet values.
+
+    FirstTargetPerfNopFragmentKind = 8,
+
+    /// Limit range of target MCPerfNopFragment kinds to fit in uint64_t
+    MaxTargetPerfNopFragmentKind = 63
+  };
+
+  MCPaddingFragment(MCSection *Sec = nullptr)
+      : MCFragment(FT_Padding, false, Sec), PaddingPoliciesMask(PFK_None),
+        IsInsertionPoint(false), Size(UINT64_C(0)),
+        InstInfo({false, MCInst(), false, {0}}) {}
+
+  bool isInsertionPoint() const { return IsInsertionPoint; }
+  void setAsInsertionPoint() { IsInsertionPoint = true; }
+  uint64_t getPaddingPoliciesMask() const { return PaddingPoliciesMask; }
+  void setPaddingPoliciesMask(uint64_t Value) { PaddingPoliciesMask = Value; }
+  bool hasPaddingPolicy(uint64_t PolicyMask) const {
+    assert(isPowerOf2_64(PolicyMask) &&
+           "Policy mask must contain exactly one policy");
+    return (getPaddingPoliciesMask() & PolicyMask) != PFK_None;
+  }
+  const MCInst &getInst() const {
+    assert(isInstructionInitialized() && "Fragment has no instruction!");
+    return InstInfo.Inst;
+  }
+  size_t getInstSize() const {
+    assert(isInstructionInitialized() && "Fragment has no instruction!");
+    if (InstInfo.IsImmutableSizedInst)
+      return InstInfo.InstSize;
+    assert(InstInfo.InstFragment != nullptr &&
+           "Must have a valid InstFragment to retrieve InstSize from");
+    return InstInfo.InstFragment->getContents().size();
+  }
+  void setInstAndInstSize(const MCInst &Inst, size_t InstSize) {
+	InstInfo.IsInitialized = true;
+    InstInfo.IsImmutableSizedInst = true;
+    InstInfo.Inst = Inst;
+    InstInfo.InstSize = InstSize;
+  }
+  void setInstAndInstFragment(const MCInst &Inst,
+                              MCRelaxableFragment *InstFragment) {
+    InstInfo.IsInitialized = true;
+    InstInfo.IsImmutableSizedInst = false;
+    InstInfo.Inst = Inst;
+    InstInfo.InstFragment = InstFragment;
+  }
+  uint64_t getSize() const { return Size; }
+  void setSize(uint64_t Value) { Size = Value; }
+  bool isInstructionInitialized() const { return InstInfo.IsInitialized; }
+
+  static bool classof(const MCFragment *F) {
+    return F->getKind() == MCFragment::FT_Padding;
+  }
+};
+
+class MCFillFragment : public MCFragment {
+  /// Value to use for filling bytes.
+  uint64_t Value;
+  uint8_t ValueSize;
+  /// The number of bytes to insert.
+  const MCExpr &NumValues;
+
+  /// Source location of the directive that this fragment was created for.
+  SMLoc Loc;
+
+public:
+  MCFillFragment(uint64_t Value, uint8_t VSize, const MCExpr &NumValues,
+                 SMLoc Loc, MCSection *Sec = nullptr)
+      : MCFragment(FT_Fill, false, Sec), Value(Value), ValueSize(VSize),
+        NumValues(NumValues), Loc(Loc) {}
+
+  uint64_t getValue() const { return Value; }
+  uint8_t getValueSize() const { return ValueSize; }
+  const MCExpr &getNumValues() const { return NumValues; }
+
+  SMLoc getLoc() const { return Loc; }
+
+  static bool classof(const MCFragment *F) {
+    return F->getKind() == MCFragment::FT_Fill;
+  }
+};
+
+class MCOrgFragment : public MCFragment {
+  /// The offset this fragment should start at.
+  const MCExpr *Offset;
+
+  /// Value to use for filling bytes.
+  int8_t Value;
+
+  /// Source location of the directive that this fragment was created for.
+  SMLoc Loc;
+
+public:
+  MCOrgFragment(const MCExpr &Offset, int8_t Value, SMLoc Loc,
+                MCSection *Sec = nullptr)
+      : MCFragment(FT_Org, false, Sec), Offset(&Offset), Value(Value), Loc(Loc) {}
+
+  /// \name Accessors
+  /// @{
+
+  const MCExpr &getOffset() const { return *Offset; }
+
+  uint8_t getValue() const { return Value; }
+
+  SMLoc getLoc() const { return Loc; }
+
+  /// @}
+
+  static bool classof(const MCFragment *F) {
+    return F->getKind() == MCFragment::FT_Org;
+  }
+};
+
+class MCLEBFragment : public MCFragment {
+  /// Value - The value this fragment should contain.
+  const MCExpr *Value;
+
+  /// IsSigned - True if this is a sleb128, false if uleb128.
+  bool IsSigned;
+
+  SmallString<8> Contents;
+
+public:
+  MCLEBFragment(const MCExpr &Value_, bool IsSigned_, MCSection *Sec = nullptr)
+      : MCFragment(FT_LEB, false, Sec), Value(&Value_), IsSigned(IsSigned_) {
+    Contents.push_back(0);
+  }
+
+  /// \name Accessors
+  /// @{
+
+  const MCExpr &getValue() const { return *Value; }
+
+  bool isSigned() const { return IsSigned; }
+
+  SmallString<8> &getContents() { return Contents; }
+  const SmallString<8> &getContents() const { return Contents; }
+
+  /// @}
+
+  static bool classof(const MCFragment *F) {
+    return F->getKind() == MCFragment::FT_LEB;
+  }
+};
+
+class MCDwarfLineAddrFragment : public MCEncodedFragmentWithFixups<8, 1> {
+  /// LineDelta - the value of the difference between the two line numbers
+  /// between two .loc dwarf directives.
+  int64_t LineDelta;
+
+  /// AddrDelta - The expression for the difference of the two symbols that
+  /// make up the address delta between two .loc dwarf directives.
+  const MCExpr *AddrDelta;
+
+public:
+  MCDwarfLineAddrFragment(int64_t LineDelta, const MCExpr &AddrDelta,
+                          MCSection *Sec = nullptr)
+      : MCEncodedFragmentWithFixups<8, 1>(FT_Dwarf, false, Sec),
+        LineDelta(LineDelta), AddrDelta(&AddrDelta) {}
+
+  /// \name Accessors
+  /// @{
+
+  int64_t getLineDelta() const { return LineDelta; }
+
+  const MCExpr &getAddrDelta() const { return *AddrDelta; }
+
+  /// @}
+
+  static bool classof(const MCFragment *F) {
+    return F->getKind() == MCFragment::FT_Dwarf;
+  }
+};
+
+class MCDwarfCallFrameFragment : public MCEncodedFragmentWithFixups<8, 1> {
+  /// AddrDelta - The expression for the difference of the two symbols that
+  /// make up the address delta between two .cfi_* dwarf directives.
+  const MCExpr *AddrDelta;
+
+public:
+  MCDwarfCallFrameFragment(const MCExpr &AddrDelta, MCSection *Sec = nullptr)
+      : MCEncodedFragmentWithFixups<8, 1>(FT_DwarfFrame, false, Sec),
+        AddrDelta(&AddrDelta) {}
+
+  /// \name Accessors
+  /// @{
+
+  const MCExpr &getAddrDelta() const { return *AddrDelta; }
+
+  /// @}
+
+  static bool classof(const MCFragment *F) {
+    return F->getKind() == MCFragment::FT_DwarfFrame;
+  }
+};
+
+/// Represents a symbol table index fragment.
+class MCSymbolIdFragment : public MCFragment {
+  const MCSymbol *Sym;
+
+public:
+  MCSymbolIdFragment(const MCSymbol *Sym, MCSection *Sec = nullptr)
+      : MCFragment(FT_SymbolId, false, Sec), Sym(Sym) {}
+
+  /// \name Accessors
+  /// @{
+
+  const MCSymbol *getSymbol() { return Sym; }
+  const MCSymbol *getSymbol() const { return Sym; }
+
+  /// @}
+
+  static bool classof(const MCFragment *F) {
+    return F->getKind() == MCFragment::FT_SymbolId;
+  }
+};
+
+/// Fragment representing the binary annotations produced by the
+/// .cv_inline_linetable directive.
+class MCCVInlineLineTableFragment : public MCFragment {
+  unsigned SiteFuncId;
+  unsigned StartFileId;
+  unsigned StartLineNum;
+  const MCSymbol *FnStartSym;
+  const MCSymbol *FnEndSym;
+  SmallString<8> Contents;
+
+  /// CodeViewContext has the real knowledge about this format, so let it access
+  /// our members.
+  friend class CodeViewContext;
+
+public:
+  MCCVInlineLineTableFragment(unsigned SiteFuncId, unsigned StartFileId,
+                              unsigned StartLineNum, const MCSymbol *FnStartSym,
+                              const MCSymbol *FnEndSym,
+                              MCSection *Sec = nullptr)
+      : MCFragment(FT_CVInlineLines, false, Sec), SiteFuncId(SiteFuncId),
+        StartFileId(StartFileId), StartLineNum(StartLineNum),
+        FnStartSym(FnStartSym), FnEndSym(FnEndSym) {}
+
+  /// \name Accessors
+  /// @{
+
+  const MCSymbol *getFnStartSym() const { return FnStartSym; }
+  const MCSymbol *getFnEndSym() const { return FnEndSym; }
+
+  SmallString<8> &getContents() { return Contents; }
+  const SmallString<8> &getContents() const { return Contents; }
+
+  /// @}
+
+  static bool classof(const MCFragment *F) {
+    return F->getKind() == MCFragment::FT_CVInlineLines;
+  }
+};
+
+/// Fragment representing the .cv_def_range directive.
+class MCCVDefRangeFragment : public MCEncodedFragmentWithFixups<32, 4> {
+  SmallVector<std::pair<const MCSymbol *, const MCSymbol *>, 2> Ranges;
+  SmallString<32> FixedSizePortion;
+
+  /// CodeViewContext has the real knowledge about this format, so let it access
+  /// our members.
+  friend class CodeViewContext;
+
+public:
+  MCCVDefRangeFragment(
+      ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+      StringRef FixedSizePortion, MCSection *Sec = nullptr)
+      : MCEncodedFragmentWithFixups<32, 4>(FT_CVDefRange, false, Sec),
+        Ranges(Ranges.begin(), Ranges.end()),
+        FixedSizePortion(FixedSizePortion) {}
+
+  /// \name Accessors
+  /// @{
+  ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> getRanges() const {
+    return Ranges;
+  }
+
+  StringRef getFixedSizePortion() const { return FixedSizePortion; }
+  /// @}
+
+  static bool classof(const MCFragment *F) {
+    return F->getKind() == MCFragment::FT_CVDefRange;
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_MC_MCFRAGMENT_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/MC/MCInst.h b/binaryen/third_party/llvm-project/include/llvm/MC/MCInst.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/MC/MCInst.h
@@ -0,0 +1,225 @@
+//===- llvm/MC/MCInst.h - MCInst class --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the declaration of the MCInst and MCOperand classes, which
+// is the basic representation used to represent low-level machine code
+// instructions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCINST_H
+#define LLVM_MC_MCINST_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/SMLoc.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+
+namespace llvm {
+
+class MCExpr;
+class MCInst;
+class MCInstPrinter;
+class raw_ostream;
+
+/// Instances of this class represent operands of the MCInst class.
+/// This is a simple discriminated union.
+class MCOperand {
+  enum MachineOperandType : unsigned char {
+    kInvalid,     ///< Uninitialized.
+    kRegister,    ///< Register operand.
+    kImmediate,   ///< Immediate operand.
+    kFPImmediate, ///< Floating-point immediate operand.
+    kExpr,        ///< Relocatable immediate operand.
+    kInst         ///< Sub-instruction operand.
+  };
+  MachineOperandType Kind = kInvalid;
+
+  union {
+    unsigned RegVal;
+    int64_t ImmVal;
+    double FPImmVal;
+    const MCExpr *ExprVal;
+    const MCInst *InstVal;
+  };
+
+public:
+  MCOperand() : FPImmVal(0.0) {}
+
+  bool isValid() const { return Kind != kInvalid; }
+  bool isReg() const { return Kind == kRegister; }
+  bool isImm() const { return Kind == kImmediate; }
+  bool isFPImm() const { return Kind == kFPImmediate; }
+  bool isExpr() const { return Kind == kExpr; }
+  bool isInst() const { return Kind == kInst; }
+
+  /// Returns the register number.
+  unsigned getReg() const {
+    assert(isReg() && "This is not a register operand!");
+    return RegVal;
+  }
+
+  /// Set the register number.
+  void setReg(unsigned Reg) {
+    assert(isReg() && "This is not a register operand!");
+    RegVal = Reg;
+  }
+
+  int64_t getImm() const {
+    assert(isImm() && "This is not an immediate");
+    return ImmVal;
+  }
+
+  void setImm(int64_t Val) {
+    assert(isImm() && "This is not an immediate");
+    ImmVal = Val;
+  }
+
+  double getFPImm() const {
+    assert(isFPImm() && "This is not an FP immediate");
+    return FPImmVal;
+  }
+
+  void setFPImm(double Val) {
+    assert(isFPImm() && "This is not an FP immediate");
+    FPImmVal = Val;
+  }
+
+  const MCExpr *getExpr() const {
+    assert(isExpr() && "This is not an expression");
+    return ExprVal;
+  }
+
+  void setExpr(const MCExpr *Val) {
+    assert(isExpr() && "This is not an expression");
+    ExprVal = Val;
+  }
+
+  const MCInst *getInst() const {
+    assert(isInst() && "This is not a sub-instruction");
+    return InstVal;
+  }
+
+  void setInst(const MCInst *Val) {
+    assert(isInst() && "This is not a sub-instruction");
+    InstVal = Val;
+  }
+
+  static MCOperand createReg(unsigned Reg) {
+    MCOperand Op;
+    Op.Kind = kRegister;
+    Op.RegVal = Reg;
+    return Op;
+  }
+
+  static MCOperand createImm(int64_t Val) {
+    MCOperand Op;
+    Op.Kind = kImmediate;
+    Op.ImmVal = Val;
+    return Op;
+  }
+
+  static MCOperand createFPImm(double Val) {
+    MCOperand Op;
+    Op.Kind = kFPImmediate;
+    Op.FPImmVal = Val;
+    return Op;
+  }
+
+  static MCOperand createExpr(const MCExpr *Val) {
+    MCOperand Op;
+    Op.Kind = kExpr;
+    Op.ExprVal = Val;
+    return Op;
+  }
+
+  static MCOperand createInst(const MCInst *Val) {
+    MCOperand Op;
+    Op.Kind = kInst;
+    Op.InstVal = Val;
+    return Op;
+  }
+
+  void print(raw_ostream &OS) const;
+  void dump() const;
+  bool isBareSymbolRef() const;
+  bool evaluateAsConstantImm(int64_t &Imm) const;
+};
+
+/// Instances of this class represent a single low-level machine
+/// instruction.
+class MCInst {
+  unsigned Opcode = 0;
+  SMLoc Loc;
+  SmallVector<MCOperand, 8> Operands;
+  // These flags could be used to pass some info from one target subcomponent
+  // to another, for example, from disassembler to asm printer. The values of
+  // the flags have any sense on target level only (e.g. prefixes on x86).
+  unsigned Flags = 0;
+
+public:
+  MCInst() = default;
+
+  void setOpcode(unsigned Op) { Opcode = Op; }
+  unsigned getOpcode() const { return Opcode; }
+
+  void setFlags(unsigned F) { Flags = F; }
+  unsigned getFlags() const { return Flags; }
+
+  void setLoc(SMLoc loc) { Loc = loc; }
+  SMLoc getLoc() const { return Loc; }
+
+  const MCOperand &getOperand(unsigned i) const { return Operands[i]; }
+  MCOperand &getOperand(unsigned i) { return Operands[i]; }
+  unsigned getNumOperands() const { return Operands.size(); }
+
+  void addOperand(const MCOperand &Op) { Operands.push_back(Op); }
+
+  using iterator = SmallVectorImpl<MCOperand>::iterator;
+  using const_iterator = SmallVectorImpl<MCOperand>::const_iterator;
+
+  void clear() { Operands.clear(); }
+  void erase(iterator I) { Operands.erase(I); }
+  void erase(iterator First, iterator Last) { Operands.erase(First, Last); }
+  size_t size() const { return Operands.size(); }
+  iterator begin() { return Operands.begin(); }
+  const_iterator begin() const { return Operands.begin(); }
+  iterator end() { return Operands.end(); }
+  const_iterator end() const { return Operands.end(); }
+
+  iterator insert(iterator I, const MCOperand &Op) {
+    return Operands.insert(I, Op);
+  }
+
+  void print(raw_ostream &OS) const;
+  void dump() const;
+
+  /// Dump the MCInst as prettily as possible using the additional MC
+  /// structures, if given. Operators are separated by the \p Separator
+  /// string.
+  void dump_pretty(raw_ostream &OS, const MCInstPrinter *Printer = nullptr,
+                   StringRef Separator = " ") const;
+  void dump_pretty(raw_ostream &OS, StringRef Name,
+                   StringRef Separator = " ") const;
+};
+
+inline raw_ostream& operator<<(raw_ostream &OS, const MCOperand &MO) {
+  MO.print(OS);
+  return OS;
+}
+
+inline raw_ostream& operator<<(raw_ostream &OS, const MCInst &MI) {
+  MI.print(OS);
+  return OS;
+}
+
+} // end namespace llvm
+
+#endif // LLVM_MC_MCINST_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/MC/MCRegister.h b/binaryen/third_party/llvm-project/include/llvm/MC/MCRegister.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/MC/MCRegister.h
@@ -0,0 +1,110 @@
+//===-- llvm/MC/Register.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_REGISTER_H
+#define LLVM_MC_REGISTER_H
+
+#include "llvm/ADT/DenseMapInfo.h"
+#include <cassert>
+
+namespace llvm {
+
+/// An unsigned integer type large enough to represent all physical registers,
+/// but not necessarily virtual registers.
+using MCPhysReg = uint16_t;
+
+/// Wrapper class representing physical registers. Should be passed by value.
+class MCRegister {
+  unsigned Reg;
+
+public:
+  MCRegister(unsigned Val = 0): Reg(Val) {}
+
+  // Register numbers can represent physical registers, virtual registers, and
+  // sometimes stack slots. The unsigned values are divided into these ranges:
+  //
+  //   0           Not a register, can be used as a sentinel.
+  //   [1;2^30)    Physical registers assigned by TableGen.
+  //   [2^30;2^31) Stack slots. (Rarely used.)
+  //   [2^31;2^32) Virtual registers assigned by MachineRegisterInfo.
+  //
+  // Further sentinels can be allocated from the small negative integers.
+  // DenseMapInfo<unsigned> uses -1u and -2u.
+
+  /// This is the portion of the positive number space that is not a physical
+  /// register. StackSlot values do not exist in the MC layer, see
+  /// Register::isStackSlot() for the more information on them.
+  ///
+  /// Note that isVirtualRegister() and isPhysicalRegister() cannot handle stack
+  /// slots, so if a variable may contains a stack slot, always check
+  /// isStackSlot() first.
+  static bool isStackSlot(unsigned Reg) {
+    return int(Reg) >= (1 << 30);
+  }
+
+  /// Return true if the specified register number is in
+  /// the physical register namespace.
+  static bool isPhysicalRegister(unsigned Reg) {
+    assert(!isStackSlot(Reg) && "Not a register! Check isStackSlot() first.");
+    return int(Reg) > 0;
+  }
+
+  /// Return true if the specified register number is in the physical register
+  /// namespace.
+  bool isPhysical() const {
+    return isPhysicalRegister(Reg);
+  }
+
+  operator unsigned() const {
+    return Reg;
+  }
+
+  unsigned id() const {
+    return Reg;
+  }
+
+  bool isValid() const {
+    return Reg != 0;
+  }
+
+  /// Comparisons between register objects
+  bool operator==(const MCRegister &Other) const { return Reg == Other.Reg; }
+  bool operator!=(const MCRegister &Other) const { return Reg != Other.Reg; }
+
+  /// Comparisons against register constants. E.g.
+  /// * R == AArch64::WZR
+  /// * R == 0
+  /// * R == VirtRegMap::NO_PHYS_REG
+  bool operator==(unsigned Other) const { return Reg == Other; }
+  bool operator!=(unsigned Other) const { return Reg != Other; }
+  bool operator==(int Other) const { return Reg == unsigned(Other); }
+  bool operator!=(int Other) const { return Reg != unsigned(Other); }
+  // MSVC requires that we explicitly declare these two as well.
+  bool operator==(MCPhysReg Other) const { return Reg == unsigned(Other); }
+  bool operator!=(MCPhysReg Other) const { return Reg != unsigned(Other); }
+};
+
+// Provide DenseMapInfo for MCRegister
+template<> struct DenseMapInfo<MCRegister> {
+  static inline unsigned getEmptyKey() {
+    return DenseMapInfo<unsigned>::getEmptyKey();
+  }
+  static inline unsigned getTombstoneKey() {
+    return DenseMapInfo<unsigned>::getTombstoneKey();
+  }
+  static unsigned getHashValue(const MCRegister &Val) {
+    return DenseMapInfo<unsigned>::getHashValue(Val.id());
+  }
+  static bool isEqual(const MCRegister &LHS, const MCRegister &RHS) {
+    return DenseMapInfo<unsigned>::isEqual(LHS.id(), RHS.id());
+  }
+};
+
+}
+
+#endif // ifndef LLVM_MC_REGISTER_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/MC/MCRegisterInfo.h b/binaryen/third_party/llvm-project/include/llvm/MC/MCRegisterInfo.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/MC/MCRegisterInfo.h
@@ -0,0 +1,721 @@
+//===- MC/MCRegisterInfo.h - Target Register Description --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file describes an abstract interface used to get information about a
+// target machines register file.  This information is used for a variety of
+// purposed, especially register allocation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCREGISTERINFO_H
+#define LLVM_MC_MCREGISTERINFO_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/MC/LaneBitmask.h"
+#include "llvm/MC/MCRegister.h"
+#include <cassert>
+#include <cstdint>
+#include <utility>
+
+namespace llvm {
+
+/// MCRegisterClass - Base class of TargetRegisterClass.
+class MCRegisterClass {
+public:
+  using iterator = const MCPhysReg*;
+  using const_iterator = const MCPhysReg*;
+
+  const iterator RegsBegin;
+  const uint8_t *const RegSet;
+  const uint32_t NameIdx;
+  const uint16_t RegsSize;
+  const uint16_t RegSetSize;
+  const uint16_t ID;
+  const int8_t CopyCost;
+  const bool Allocatable;
+
+  /// getID() - Return the register class ID number.
+  ///
+  unsigned getID() const { return ID; }
+
+  /// begin/end - Return all of the registers in this class.
+  ///
+  iterator       begin() const { return RegsBegin; }
+  iterator         end() const { return RegsBegin + RegsSize; }
+
+  /// getNumRegs - Return the number of registers in this class.
+  ///
+  unsigned getNumRegs() const { return RegsSize; }
+
+  /// getRegister - Return the specified register in the class.
+  ///
+  unsigned getRegister(unsigned i) const {
+    assert(i < getNumRegs() && "Register number out of range!");
+    return RegsBegin[i];
+  }
+
+  /// contains - Return true if the specified register is included in this
+  /// register class.  This does not include virtual registers.
+  bool contains(MCRegister Reg) const {
+    unsigned RegNo = unsigned(Reg);
+    unsigned InByte = RegNo % 8;
+    unsigned Byte = RegNo / 8;
+    if (Byte >= RegSetSize)
+      return false;
+    return (RegSet[Byte] & (1 << InByte)) != 0;
+  }
+
+  /// contains - Return true if both registers are in this class.
+  bool contains(MCRegister Reg1, MCRegister Reg2) const {
+    return contains(Reg1) && contains(Reg2);
+  }
+
+  /// getCopyCost - Return the cost of copying a value between two registers in
+  /// this class. A negative number means the register class is very expensive
+  /// to copy e.g. status flag register classes.
+  int getCopyCost() const { return CopyCost; }
+
+  /// isAllocatable - Return true if this register class may be used to create
+  /// virtual registers.
+  bool isAllocatable() const { return Allocatable; }
+};
+
+/// MCRegisterDesc - This record contains information about a particular
+/// register.  The SubRegs field is a zero terminated array of registers that
+/// are sub-registers of the specific register, e.g. AL, AH are sub-registers
+/// of AX. The SuperRegs field is a zero terminated array of registers that are
+/// super-registers of the specific register, e.g. RAX, EAX, are
+/// super-registers of AX.
+///
+struct MCRegisterDesc {
+  uint32_t Name;      // Printable name for the reg (for debugging)
+  uint32_t SubRegs;   // Sub-register set, described above
+  uint32_t SuperRegs; // Super-register set, described above
+
+  // Offset into MCRI::SubRegIndices of a list of sub-register indices for each
+  // sub-register in SubRegs.
+  uint32_t SubRegIndices;
+
+  // RegUnits - Points to the list of register units. The low 4 bits holds the
+  // Scale, the high bits hold an offset into DiffLists. See MCRegUnitIterator.
+  uint32_t RegUnits;
+
+  /// Index into list with lane mask sequences. The sequence contains a lanemask
+  /// for every register unit.
+  uint16_t RegUnitLaneMasks;
+};
+
+/// MCRegisterInfo base class - We assume that the target defines a static
+/// array of MCRegisterDesc objects that represent all of the machine
+/// registers that the target has.  As such, we simply have to track a pointer
+/// to this array so that we can turn register number into a register
+/// descriptor.
+///
+/// Note this class is designed to be a base class of TargetRegisterInfo, which
+/// is the interface used by codegen. However, specific targets *should never*
+/// specialize this class. MCRegisterInfo should only contain getters to access
+/// TableGen generated physical register data. It must not be extended with
+/// virtual methods.
+///
+class MCRegisterInfo {
+public:
+  using regclass_iterator = const MCRegisterClass *;
+
+  /// DwarfLLVMRegPair - Emitted by tablegen so Dwarf<->LLVM reg mappings can be
+  /// performed with a binary search.
+  struct DwarfLLVMRegPair {
+    unsigned FromReg;
+    unsigned ToReg;
+
+    bool operator<(DwarfLLVMRegPair RHS) const { return FromReg < RHS.FromReg; }
+  };
+
+  /// SubRegCoveredBits - Emitted by tablegen: bit range covered by a subreg
+  /// index, -1 in any being invalid.
+  struct SubRegCoveredBits {
+    uint16_t Offset;
+    uint16_t Size;
+  };
+
+private:
+  const MCRegisterDesc *Desc;                 // Pointer to the descriptor array
+  unsigned NumRegs;                           // Number of entries in the array
+  MCRegister RAReg;                           // Return address register
+  MCRegister PCReg;                           // Program counter register
+  const MCRegisterClass *Classes;             // Pointer to the regclass array
+  unsigned NumClasses;                        // Number of entries in the array
+  unsigned NumRegUnits;                       // Number of regunits.
+  const MCPhysReg (*RegUnitRoots)[2];         // Pointer to regunit root table.
+  const MCPhysReg *DiffLists;                 // Pointer to the difflists array
+  const LaneBitmask *RegUnitMaskSequences;    // Pointer to lane mask sequences
+                                              // for register units.
+  const char *RegStrings;                     // Pointer to the string table.
+  const char *RegClassStrings;                // Pointer to the class strings.
+  const uint16_t *SubRegIndices;              // Pointer to the subreg lookup
+                                              // array.
+  const SubRegCoveredBits *SubRegIdxRanges;   // Pointer to the subreg covered
+                                              // bit ranges array.
+  unsigned NumSubRegIndices;                  // Number of subreg indices.
+  const uint16_t *RegEncodingTable;           // Pointer to array of register
+                                              // encodings.
+
+  unsigned L2DwarfRegsSize;
+  unsigned EHL2DwarfRegsSize;
+  unsigned Dwarf2LRegsSize;
+  unsigned EHDwarf2LRegsSize;
+  const DwarfLLVMRegPair *L2DwarfRegs;        // LLVM to Dwarf regs mapping
+  const DwarfLLVMRegPair *EHL2DwarfRegs;      // LLVM to Dwarf regs mapping EH
+  const DwarfLLVMRegPair *Dwarf2LRegs;        // Dwarf to LLVM regs mapping
+  const DwarfLLVMRegPair *EHDwarf2LRegs;      // Dwarf to LLVM regs mapping EH
+  DenseMap<MCRegister, int> L2SEHRegs;        // LLVM to SEH regs mapping
+  DenseMap<MCRegister, int> L2CVRegs;         // LLVM to CV regs mapping
+
+public:
+  /// DiffListIterator - Base iterator class that can traverse the
+  /// differentially encoded register and regunit lists in DiffLists.
+  /// Don't use this class directly, use one of the specialized sub-classes
+  /// defined below.
+  class DiffListIterator {
+    uint16_t Val = 0;
+    const MCPhysReg *List = nullptr;
+
+  protected:
+    /// Create an invalid iterator. Call init() to point to something useful.
+    DiffListIterator() = default;
+
+    /// init - Point the iterator to InitVal, decoding subsequent values from
+    /// DiffList. The iterator will initially point to InitVal, sub-classes are
+    /// responsible for skipping the seed value if it is not part of the list.
+    void init(MCPhysReg InitVal, const MCPhysReg *DiffList) {
+      Val = InitVal;
+      List = DiffList;
+    }
+
+    /// advance - Move to the next list position, return the applied
+    /// differential. This function does not detect the end of the list, that
+    /// is the caller's responsibility (by checking for a 0 return value).
+    MCRegister advance() {
+      assert(isValid() && "Cannot move off the end of the list.");
+      MCPhysReg D = *List++;
+      Val += D;
+      return D;
+    }
+
+  public:
+    /// isValid - returns true if this iterator is not yet at the end.
+    bool isValid() const { return List; }
+
+    /// Dereference the iterator to get the value at the current position.
+    MCRegister operator*() const { return Val; }
+
+    /// Pre-increment to move to the next position.
+    void operator++() {
+      // The end of the list is encoded as a 0 differential.
+      if (!advance())
+        List = nullptr;
+    }
+  };
+
+  // These iterators are allowed to sub-class DiffListIterator and access
+  // internal list pointers.
+  friend class MCSubRegIterator;
+  friend class MCSubRegIndexIterator;
+  friend class MCSuperRegIterator;
+  friend class MCRegUnitIterator;
+  friend class MCRegUnitMaskIterator;
+  friend class MCRegUnitRootIterator;
+
+  /// Initialize MCRegisterInfo, called by TableGen
+  /// auto-generated routines. *DO NOT USE*.
+  void InitMCRegisterInfo(const MCRegisterDesc *D, unsigned NR, unsigned RA,
+                          unsigned PC,
+                          const MCRegisterClass *C, unsigned NC,
+                          const MCPhysReg (*RURoots)[2],
+                          unsigned NRU,
+                          const MCPhysReg *DL,
+                          const LaneBitmask *RUMS,
+                          const char *Strings,
+                          const char *ClassStrings,
+                          const uint16_t *SubIndices,
+                          unsigned NumIndices,
+                          const SubRegCoveredBits *SubIdxRanges,
+                          const uint16_t *RET) {
+    Desc = D;
+    NumRegs = NR;
+    RAReg = RA;
+    PCReg = PC;
+    Classes = C;
+    DiffLists = DL;
+    RegUnitMaskSequences = RUMS;
+    RegStrings = Strings;
+    RegClassStrings = ClassStrings;
+    NumClasses = NC;
+    RegUnitRoots = RURoots;
+    NumRegUnits = NRU;
+    SubRegIndices = SubIndices;
+    NumSubRegIndices = NumIndices;
+    SubRegIdxRanges = SubIdxRanges;
+    RegEncodingTable = RET;
+
+    // Initialize DWARF register mapping variables
+    EHL2DwarfRegs = nullptr;
+    EHL2DwarfRegsSize = 0;
+    L2DwarfRegs = nullptr;
+    L2DwarfRegsSize = 0;
+    EHDwarf2LRegs = nullptr;
+    EHDwarf2LRegsSize = 0;
+    Dwarf2LRegs = nullptr;
+    Dwarf2LRegsSize = 0;
+  }
+
+  /// Used to initialize LLVM register to Dwarf
+  /// register number mapping. Called by TableGen auto-generated routines.
+  /// *DO NOT USE*.
+  void mapLLVMRegsToDwarfRegs(const DwarfLLVMRegPair *Map, unsigned Size,
+                              bool isEH) {
+    if (isEH) {
+      EHL2DwarfRegs = Map;
+      EHL2DwarfRegsSize = Size;
+    } else {
+      L2DwarfRegs = Map;
+      L2DwarfRegsSize = Size;
+    }
+  }
+
+  /// Used to initialize Dwarf register to LLVM
+  /// register number mapping. Called by TableGen auto-generated routines.
+  /// *DO NOT USE*.
+  void mapDwarfRegsToLLVMRegs(const DwarfLLVMRegPair *Map, unsigned Size,
+                              bool isEH) {
+    if (isEH) {
+      EHDwarf2LRegs = Map;
+      EHDwarf2LRegsSize = Size;
+    } else {
+      Dwarf2LRegs = Map;
+      Dwarf2LRegsSize = Size;
+    }
+  }
+
+  /// mapLLVMRegToSEHReg - Used to initialize LLVM register to SEH register
+  /// number mapping. By default the SEH register number is just the same
+  /// as the LLVM register number.
+  /// FIXME: TableGen these numbers. Currently this requires target specific
+  /// initialization code.
+  void mapLLVMRegToSEHReg(MCRegister LLVMReg, int SEHReg) {
+    L2SEHRegs[LLVMReg] = SEHReg;
+  }
+
+  void mapLLVMRegToCVReg(MCRegister LLVMReg, int CVReg) {
+    L2CVRegs[LLVMReg] = CVReg;
+  }
+
+  /// This method should return the register where the return
+  /// address can be found.
+  MCRegister getRARegister() const {
+    return RAReg;
+  }
+
+  /// Return the register which is the program counter.
+  MCRegister getProgramCounter() const {
+    return PCReg;
+  }
+
+  const MCRegisterDesc &operator[](MCRegister RegNo) const {
+    assert(RegNo < NumRegs &&
+           "Attempting to access record for invalid register number!");
+    return Desc[RegNo];
+  }
+
+  /// Provide a get method, equivalent to [], but more useful with a
+  /// pointer to this object.
+  const MCRegisterDesc &get(MCRegister RegNo) const {
+    return operator[](RegNo);
+  }
+
+  /// Returns the physical register number of sub-register "Index"
+  /// for physical register RegNo. Return zero if the sub-register does not
+  /// exist.
+  MCRegister getSubReg(MCRegister Reg, unsigned Idx) const;
+
+  /// Return a super-register of the specified register
+  /// Reg so its sub-register of index SubIdx is Reg.
+  MCRegister getMatchingSuperReg(MCRegister Reg, unsigned SubIdx,
+                                 const MCRegisterClass *RC) const;
+
+  /// For a given register pair, return the sub-register index
+  /// if the second register is a sub-register of the first. Return zero
+  /// otherwise.
+  unsigned getSubRegIndex(MCRegister RegNo, MCRegister SubRegNo) const;
+
+  /// Get the size of the bit range covered by a sub-register index.
+  /// If the index isn't continuous, return the sum of the sizes of its parts.
+  /// If the index is used to access subregisters of different sizes, return -1.
+  unsigned getSubRegIdxSize(unsigned Idx) const;
+
+  /// Get the offset of the bit range covered by a sub-register index.
+  /// If an Offset doesn't make sense (the index isn't continuous, or is used to
+  /// access sub-registers at different offsets), return -1.
+  unsigned getSubRegIdxOffset(unsigned Idx) const;
+
+  /// Return the human-readable symbolic target-specific name for the
+  /// specified physical register.
+  const char *getName(MCRegister RegNo) const {
+    return RegStrings + get(RegNo).Name;
+  }
+
+  /// Return the number of registers this target has (useful for
+  /// sizing arrays holding per register information)
+  unsigned getNumRegs() const {
+    return NumRegs;
+  }
+
+  /// Return the number of sub-register indices
+  /// understood by the target. Index 0 is reserved for the no-op sub-register,
+  /// while 1 to getNumSubRegIndices() - 1 represent real sub-registers.
+  unsigned getNumSubRegIndices() const {
+    return NumSubRegIndices;
+  }
+
+  /// Return the number of (native) register units in the
+  /// target. Register units are numbered from 0 to getNumRegUnits() - 1. They
+  /// can be accessed through MCRegUnitIterator defined below.
+  unsigned getNumRegUnits() const {
+    return NumRegUnits;
+  }
+
+  /// Map a target register to an equivalent dwarf register
+  /// number.  Returns -1 if there is no equivalent value.  The second
+  /// parameter allows targets to use different numberings for EH info and
+  /// debugging info.
+  int getDwarfRegNum(MCRegister RegNum, bool isEH) const;
+
+  /// Map a dwarf register back to a target register. Returns None is there is
+  /// no mapping.
+  Optional<unsigned> getLLVMRegNum(unsigned RegNum, bool isEH) const;
+
+  /// Map a target EH register number to an equivalent DWARF register
+  /// number.
+  int getDwarfRegNumFromDwarfEHRegNum(unsigned RegNum) const;
+
+  /// Map a target register to an equivalent SEH register
+  /// number.  Returns LLVM register number if there is no equivalent value.
+  int getSEHRegNum(MCRegister RegNum) const;
+
+  /// Map a target register to an equivalent CodeView register
+  /// number.
+  int getCodeViewRegNum(MCRegister RegNum) const;
+
+  regclass_iterator regclass_begin() const { return Classes; }
+  regclass_iterator regclass_end() const { return Classes+NumClasses; }
+  iterator_range<regclass_iterator> regclasses() const {
+    return make_range(regclass_begin(), regclass_end());
+  }
+
+  unsigned getNumRegClasses() const {
+    return (unsigned)(regclass_end()-regclass_begin());
+  }
+
+  /// Returns the register class associated with the enumeration
+  /// value.  See class MCOperandInfo.
+  const MCRegisterClass& getRegClass(unsigned i) const {
+    assert(i < getNumRegClasses() && "Register Class ID out of range");
+    return Classes[i];
+  }
+
+  const char *getRegClassName(const MCRegisterClass *Class) const {
+    return RegClassStrings + Class->NameIdx;
+  }
+
+   /// Returns the encoding for RegNo
+  uint16_t getEncodingValue(MCRegister RegNo) const {
+    assert(RegNo < NumRegs &&
+           "Attempting to get encoding for invalid register number!");
+    return RegEncodingTable[RegNo];
+  }
+
+  /// Returns true if RegB is a sub-register of RegA.
+  bool isSubRegister(MCRegister RegA, MCRegister RegB) const {
+    return isSuperRegister(RegB, RegA);
+  }
+
+  /// Returns true if RegB is a super-register of RegA.
+  bool isSuperRegister(MCRegister RegA, MCRegister RegB) const;
+
+  /// Returns true if RegB is a sub-register of RegA or if RegB == RegA.
+  bool isSubRegisterEq(MCRegister RegA, MCRegister RegB) const {
+    return isSuperRegisterEq(RegB, RegA);
+  }
+
+  /// Returns true if RegB is a super-register of RegA or if
+  /// RegB == RegA.
+  bool isSuperRegisterEq(MCRegister RegA, MCRegister RegB) const {
+    return RegA == RegB || isSuperRegister(RegA, RegB);
+  }
+
+  /// Returns true if RegB is a super-register or sub-register of RegA
+  /// or if RegB == RegA.
+  bool isSuperOrSubRegisterEq(MCRegister RegA, MCRegister RegB) const {
+    return isSubRegisterEq(RegA, RegB) || isSuperRegister(RegA, RegB);
+  }
+};
+
+//===----------------------------------------------------------------------===//
+//                          Register List Iterators
+//===----------------------------------------------------------------------===//
+
+// MCRegisterInfo provides lists of super-registers, sub-registers, and
+// aliasing registers. Use these iterator classes to traverse the lists.
+
+/// MCSubRegIterator enumerates all sub-registers of Reg.
+/// If IncludeSelf is set, Reg itself is included in the list.
+class MCSubRegIterator : public MCRegisterInfo::DiffListIterator {
+public:
+  MCSubRegIterator(MCRegister Reg, const MCRegisterInfo *MCRI,
+                   bool IncludeSelf = false) {
+    init(Reg, MCRI->DiffLists + MCRI->get(Reg).SubRegs);
+    // Initially, the iterator points to Reg itself.
+    if (!IncludeSelf)
+      ++*this;
+  }
+};
+
+/// Iterator that enumerates the sub-registers of a Reg and the associated
+/// sub-register indices.
+class MCSubRegIndexIterator {
+  MCSubRegIterator SRIter;
+  const uint16_t *SRIndex;
+
+public:
+  /// Constructs an iterator that traverses subregisters and their
+  /// associated subregister indices.
+  MCSubRegIndexIterator(MCRegister Reg, const MCRegisterInfo *MCRI)
+    : SRIter(Reg, MCRI) {
+    SRIndex = MCRI->SubRegIndices + MCRI->get(Reg).SubRegIndices;
+  }
+
+  /// Returns current sub-register.
+  MCRegister getSubReg() const {
+    return *SRIter;
+  }
+
+  /// Returns sub-register index of the current sub-register.
+  unsigned getSubRegIndex() const {
+    return *SRIndex;
+  }
+
+  /// Returns true if this iterator is not yet at the end.
+  bool isValid() const { return SRIter.isValid(); }
+
+  /// Moves to the next position.
+  void operator++() {
+    ++SRIter;
+    ++SRIndex;
+  }
+};
+
+/// MCSuperRegIterator enumerates all super-registers of Reg.
+/// If IncludeSelf is set, Reg itself is included in the list.
+class MCSuperRegIterator : public MCRegisterInfo::DiffListIterator {
+public:
+  MCSuperRegIterator() = default;
+
+  MCSuperRegIterator(MCRegister Reg, const MCRegisterInfo *MCRI,
+                     bool IncludeSelf = false) {
+    init(Reg, MCRI->DiffLists + MCRI->get(Reg).SuperRegs);
+    // Initially, the iterator points to Reg itself.
+    if (!IncludeSelf)
+      ++*this;
+  }
+};
+
+// Definition for isSuperRegister. Put it down here since it needs the
+// iterator defined above in addition to the MCRegisterInfo class itself.
+inline bool MCRegisterInfo::isSuperRegister(MCRegister RegA, MCRegister RegB) const{
+  for (MCSuperRegIterator I(RegA, this); I.isValid(); ++I)
+    if (*I == RegB)
+      return true;
+  return false;
+}
+
+//===----------------------------------------------------------------------===//
+//                               Register Units
+//===----------------------------------------------------------------------===//
+
+// Register units are used to compute register aliasing. Every register has at
+// least one register unit, but it can have more. Two registers overlap if and
+// only if they have a common register unit.
+//
+// A target with a complicated sub-register structure will typically have many
+// fewer register units than actual registers. MCRI::getNumRegUnits() returns
+// the number of register units in the target.
+
+// MCRegUnitIterator enumerates a list of register units for Reg. The list is
+// in ascending numerical order.
+class MCRegUnitIterator : public MCRegisterInfo::DiffListIterator {
+public:
+  /// MCRegUnitIterator - Create an iterator that traverses the register units
+  /// in Reg.
+  MCRegUnitIterator() = default;
+
+  MCRegUnitIterator(MCRegister Reg, const MCRegisterInfo *MCRI) {
+    assert(Reg && "Null register has no regunits");
+    // Decode the RegUnits MCRegisterDesc field.
+    unsigned RU = MCRI->get(Reg).RegUnits;
+    unsigned Scale = RU & 15;
+    unsigned Offset = RU >> 4;
+
+    // Initialize the iterator to Reg * Scale, and the List pointer to
+    // DiffLists + Offset.
+    init(Reg * Scale, MCRI->DiffLists + Offset);
+
+    // That may not be a valid unit, we need to advance by one to get the real
+    // unit number. The first differential can be 0 which would normally
+    // terminate the list, but since we know every register has at least one
+    // unit, we can allow a 0 differential here.
+    advance();
+  }
+};
+
+/// MCRegUnitMaskIterator enumerates a list of register units and their
+/// associated lane masks for Reg. The register units are in ascending
+/// numerical order.
+class MCRegUnitMaskIterator {
+  MCRegUnitIterator RUIter;
+  const LaneBitmask *MaskListIter;
+
+public:
+  MCRegUnitMaskIterator() = default;
+
+  /// Constructs an iterator that traverses the register units and their
+  /// associated LaneMasks in Reg.
+  MCRegUnitMaskIterator(MCRegister Reg, const MCRegisterInfo *MCRI)
+    : RUIter(Reg, MCRI) {
+      uint16_t Idx = MCRI->get(Reg).RegUnitLaneMasks;
+      MaskListIter = &MCRI->RegUnitMaskSequences[Idx];
+  }
+
+  /// Returns a (RegUnit, LaneMask) pair.
+  std::pair<unsigned,LaneBitmask> operator*() const {
+    return std::make_pair(*RUIter, *MaskListIter);
+  }
+
+  /// Returns true if this iterator is not yet at the end.
+  bool isValid() const { return RUIter.isValid(); }
+
+  /// Moves to the next position.
+  void operator++() {
+    ++MaskListIter;
+    ++RUIter;
+  }
+};
+
+// Each register unit has one or two root registers. The complete set of
+// registers containing a register unit is the union of the roots and their
+// super-registers. All registers aliasing Unit can be visited like this:
+//
+//   for (MCRegUnitRootIterator RI(Unit, MCRI); RI.isValid(); ++RI) {
+//     for (MCSuperRegIterator SI(*RI, MCRI, true); SI.isValid(); ++SI)
+//       visit(*SI);
+//    }
+
+/// MCRegUnitRootIterator enumerates the root registers of a register unit.
+class MCRegUnitRootIterator {
+  uint16_t Reg0 = 0;
+  uint16_t Reg1 = 0;
+
+public:
+  MCRegUnitRootIterator() = default;
+
+  MCRegUnitRootIterator(unsigned RegUnit, const MCRegisterInfo *MCRI) {
+    assert(RegUnit < MCRI->getNumRegUnits() && "Invalid register unit");
+    Reg0 = MCRI->RegUnitRoots[RegUnit][0];
+    Reg1 = MCRI->RegUnitRoots[RegUnit][1];
+  }
+
+  /// Dereference to get the current root register.
+  unsigned operator*() const {
+    return Reg0;
+  }
+
+  /// Check if the iterator is at the end of the list.
+  bool isValid() const {
+    return Reg0;
+  }
+
+  /// Preincrement to move to the next root register.
+  void operator++() {
+    assert(isValid() && "Cannot move off the end of the list.");
+    Reg0 = Reg1;
+    Reg1 = 0;
+  }
+};
+
+/// MCRegAliasIterator enumerates all registers aliasing Reg.  If IncludeSelf is
+/// set, Reg itself is included in the list.  This iterator does not guarantee
+/// any ordering or that entries are unique.
+class MCRegAliasIterator {
+private:
+  MCRegister Reg;
+  const MCRegisterInfo *MCRI;
+  bool IncludeSelf;
+
+  MCRegUnitIterator RI;
+  MCRegUnitRootIterator RRI;
+  MCSuperRegIterator SI;
+
+public:
+  MCRegAliasIterator(MCRegister Reg, const MCRegisterInfo *MCRI,
+                     bool IncludeSelf)
+    : Reg(Reg), MCRI(MCRI), IncludeSelf(IncludeSelf) {
+    // Initialize the iterators.
+    for (RI = MCRegUnitIterator(Reg, MCRI); RI.isValid(); ++RI) {
+      for (RRI = MCRegUnitRootIterator(*RI, MCRI); RRI.isValid(); ++RRI) {
+        for (SI = MCSuperRegIterator(*RRI, MCRI, true); SI.isValid(); ++SI) {
+          if (!(!IncludeSelf && Reg == *SI))
+            return;
+        }
+      }
+    }
+  }
+
+  bool isValid() const { return RI.isValid(); }
+
+  MCRegister operator*() const {
+    assert(SI.isValid() && "Cannot dereference an invalid iterator.");
+    return *SI;
+  }
+
+  void advance() {
+    // Assuming SI is valid.
+    ++SI;
+    if (SI.isValid()) return;
+
+    ++RRI;
+    if (RRI.isValid()) {
+      SI = MCSuperRegIterator(*RRI, MCRI, true);
+      return;
+    }
+
+    ++RI;
+    if (RI.isValid()) {
+      RRI = MCRegUnitRootIterator(*RI, MCRI);
+      SI = MCSuperRegIterator(*RRI, MCRI, true);
+    }
+  }
+
+  void operator++() {
+    assert(isValid() && "Cannot move off the end of the list.");
+    do advance();
+    while (!IncludeSelf && isValid() && *SI == Reg);
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_MC_MCREGISTERINFO_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/MC/MCSymbol.h b/binaryen/third_party/llvm-project/include/llvm/MC/MCSymbol.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/MC/MCSymbol.h
@@ -0,0 +1,441 @@
+//===- MCSymbol.h - Machine Code Symbols ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the declaration of the MCSymbol class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCSYMBOL_H
+#define LLVM_MC_MCSYMBOL_H
+
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/MC/MCFragment.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+
+namespace llvm {
+
+class MCAsmInfo;
+class MCContext;
+class MCExpr;
+class MCSection;
+class raw_ostream;
+
+/// MCSymbol - Instances of this class represent a symbol name in the MC file,
+/// and MCSymbols are created and uniqued by the MCContext class.  MCSymbols
+/// should only be constructed with valid names for the object file.
+///
+/// If the symbol is defined/emitted into the current translation unit, the
+/// Section member is set to indicate what section it lives in.  Otherwise, if
+/// it is a reference to an external entity, it has a null section.
+class MCSymbol {
+protected:
+  /// The kind of the symbol.  If it is any value other than unset then this
+  /// class is actually one of the appropriate subclasses of MCSymbol.
+  enum SymbolKind {
+    SymbolKindUnset,
+    SymbolKindCOFF,
+    SymbolKindELF,
+    SymbolKindMachO,
+    SymbolKindWasm,
+    SymbolKindXCOFF,
+  };
+
+  /// A symbol can contain an Offset, or Value, or be Common, but never more
+  /// than one of these.
+  enum Contents : uint8_t {
+    SymContentsUnset,
+    SymContentsOffset,
+    SymContentsVariable,
+    SymContentsCommon,
+    SymContentsTargetCommon, // Index stores the section index
+  };
+
+  // Special sentinal value for the absolute pseudo fragment.
+  static MCFragment *AbsolutePseudoFragment;
+
+  /// If a symbol has a Fragment, the section is implied, so we only need
+  /// one pointer.
+  /// The special AbsolutePseudoFragment value is for absolute symbols.
+  /// If this is a variable symbol, this caches the variable value's fragment.
+  /// FIXME: We might be able to simplify this by having the asm streamer create
+  /// dummy fragments.
+  /// If this is a section, then it gives the symbol is defined in. This is null
+  /// for undefined symbols.
+  ///
+  /// If this is a fragment, then it gives the fragment this symbol's value is
+  /// relative to, if any.
+  ///
+  /// For the 'HasName' integer, this is true if this symbol is named.
+  /// A named symbol will have a pointer to the name allocated in the bytes
+  /// immediately prior to the MCSymbol.
+  mutable PointerIntPair<MCFragment *, 1> FragmentAndHasName;
+
+  /// IsTemporary - True if this is an assembler temporary label, which
+  /// typically does not survive in the .o file's symbol table.  Usually
+  /// "Lfoo" or ".foo".
+  unsigned IsTemporary : 1;
+
+  /// True if this symbol can be redefined.
+  unsigned IsRedefinable : 1;
+
+  /// IsUsed - True if this symbol has been used.
+  mutable unsigned IsUsed : 1;
+
+  mutable unsigned IsRegistered : 1;
+
+  /// This symbol is visible outside this translation unit.
+  mutable unsigned IsExternal : 1;
+
+  /// This symbol is private extern.
+  mutable unsigned IsPrivateExtern : 1;
+
+  /// LLVM RTTI discriminator. This is actually a SymbolKind enumerator, but is
+  /// unsigned to avoid sign extension and achieve better bitpacking with MSVC.
+  unsigned Kind : 3;
+
+  /// True if we have created a relocation that uses this symbol.
+  mutable unsigned IsUsedInReloc : 1;
+
+  /// This is actually a Contents enumerator, but is unsigned to avoid sign
+  /// extension and achieve better bitpacking with MSVC.
+  unsigned SymbolContents : 3;
+
+  /// The alignment of the symbol, if it is 'common', or -1.
+  ///
+  /// The alignment is stored as log2(align) + 1.  This allows all values from
+  /// 0 to 2^31 to be stored which is every power of 2 representable by an
+  /// unsigned.
+  enum : unsigned { NumCommonAlignmentBits = 5 };
+  unsigned CommonAlignLog2 : NumCommonAlignmentBits;
+
+  /// The Flags field is used by object file implementations to store
+  /// additional per symbol information which is not easily classified.
+  enum : unsigned { NumFlagsBits = 16 };
+  mutable uint32_t Flags : NumFlagsBits;
+
+  /// Index field, for use by the object file implementation.
+  mutable uint32_t Index = 0;
+
+  union {
+    /// The offset to apply to the fragment address to form this symbol's value.
+    uint64_t Offset;
+
+    /// The size of the symbol, if it is 'common'.
+    uint64_t CommonSize;
+
+    /// If non-null, the value for a variable symbol.
+    const MCExpr *Value;
+  };
+
+  // MCContext creates and uniques these.
+  friend class MCExpr;
+  friend class MCContext;
+
+  /// The name for a symbol.
+  /// MCSymbol contains a uint64_t so is probably aligned to 8.  On a 32-bit
+  /// system, the name is a pointer so isn't going to satisfy the 8 byte
+  /// alignment of uint64_t.  Account for that here.
+  using NameEntryStorageTy = union {
+    const StringMapEntry<bool> *NameEntry;
+    uint64_t AlignmentPadding;
+  };
+
+  MCSymbol(SymbolKind Kind, const StringMapEntry<bool> *Name, bool isTemporary)
+      : IsTemporary(isTemporary), IsRedefinable(false), IsUsed(false),
+        IsRegistered(false), IsExternal(false), IsPrivateExtern(false),
+        Kind(Kind), IsUsedInReloc(false), SymbolContents(SymContentsUnset),
+        CommonAlignLog2(0), Flags(0) {
+    Offset = 0;
+    FragmentAndHasName.setInt(!!Name);
+    if (Name)
+      getNameEntryPtr() = Name;
+  }
+
+  // Provide custom new/delete as we will only allocate space for a name
+  // if we need one.
+  void *operator new(size_t s, const StringMapEntry<bool> *Name,
+                     MCContext &Ctx);
+
+private:
+  void operator delete(void *);
+  /// Placement delete - required by std, but never called.
+  void operator delete(void*, unsigned) {
+    llvm_unreachable("Constructor throws?");
+  }
+  /// Placement delete - required by std, but never called.
+  void operator delete(void*, unsigned, bool) {
+    llvm_unreachable("Constructor throws?");
+  }
+
+  MCSection *getSectionPtr() const {
+    if (MCFragment *F = getFragment()) {
+      assert(F != AbsolutePseudoFragment);
+      return F->getParent();
+    }
+    return nullptr;
+  }
+
+  /// Get a reference to the name field.  Requires that we have a name
+  const StringMapEntry<bool> *&getNameEntryPtr() {
+    assert(FragmentAndHasName.getInt() && "Name is required");
+    NameEntryStorageTy *Name = reinterpret_cast<NameEntryStorageTy *>(this);
+    return (*(Name - 1)).NameEntry;
+  }
+  const StringMapEntry<bool> *&getNameEntryPtr() const {
+    return const_cast<MCSymbol*>(this)->getNameEntryPtr();
+  }
+
+public:
+  MCSymbol(const MCSymbol &) = delete;
+  MCSymbol &operator=(const MCSymbol &) = delete;
+
+  /// getName - Get the symbol name.
+  StringRef getName() const {
+    if (!FragmentAndHasName.getInt())
+      return StringRef();
+
+    return getNameEntryPtr()->first();
+  }
+
+  bool isRegistered() const { return IsRegistered; }
+  void setIsRegistered(bool Value) const { IsRegistered = Value; }
+
+  void setUsedInReloc() const { IsUsedInReloc = true; }
+  bool isUsedInReloc() const { return IsUsedInReloc; }
+
+  /// \name Accessors
+  /// @{
+
+  /// isTemporary - Check if this is an assembler temporary symbol.
+  bool isTemporary() const { return IsTemporary; }
+
+  /// isUsed - Check if this is used.
+  bool isUsed() const { return IsUsed; }
+
+  /// Check if this symbol is redefinable.
+  bool isRedefinable() const { return IsRedefinable; }
+  /// Mark this symbol as redefinable.
+  void setRedefinable(bool Value) { IsRedefinable = Value; }
+  /// Prepare this symbol to be redefined.
+  void redefineIfPossible() {
+    if (IsRedefinable) {
+      if (SymbolContents == SymContentsVariable) {
+        Value = nullptr;
+        SymbolContents = SymContentsUnset;
+      }
+      setUndefined();
+      IsRedefinable = false;
+    }
+  }
+
+  /// @}
+  /// \name Associated Sections
+  /// @{
+
+  /// isDefined - Check if this symbol is defined (i.e., it has an address).
+  ///
+  /// Defined symbols are either absolute or in some section.
+  bool isDefined() const { return !isUndefined(); }
+
+  /// isInSection - Check if this symbol is defined in some section (i.e., it
+  /// is defined but not absolute).
+  bool isInSection() const {
+    return isDefined() && !isAbsolute();
+  }
+
+  /// isUndefined - Check if this symbol undefined (i.e., implicitly defined).
+  bool isUndefined(bool SetUsed = true) const {
+    return getFragment(SetUsed) == nullptr;
+  }
+
+  /// isAbsolute - Check if this is an absolute symbol.
+  bool isAbsolute() const {
+    return getFragment() == AbsolutePseudoFragment;
+  }
+
+  /// Get the section associated with a defined, non-absolute symbol.
+  MCSection &getSection() const {
+    assert(isInSection() && "Invalid accessor!");
+    return *getSectionPtr();
+  }
+
+  /// Mark the symbol as defined in the fragment \p F.
+  void setFragment(MCFragment *F) const {
+    assert(!isVariable() && "Cannot set fragment of variable");
+    FragmentAndHasName.setPointer(F);
+  }
+
+  /// Mark the symbol as undefined.
+  void setUndefined() { FragmentAndHasName.setPointer(nullptr); }
+
+  bool isELF() const { return Kind == SymbolKindELF; }
+
+  bool isCOFF() const { return Kind == SymbolKindCOFF; }
+
+  bool isMachO() const { return Kind == SymbolKindMachO; }
+
+  bool isWasm() const { return Kind == SymbolKindWasm; }
+
+  bool isXCOFF() const { return Kind == SymbolKindXCOFF; }
+
+  /// @}
+  /// \name Variable Symbols
+  /// @{
+
+  /// isVariable - Check if this is a variable symbol.
+  bool isVariable() const {
+    return SymbolContents == SymContentsVariable;
+  }
+
+  /// getVariableValue - Get the value for variable symbols.
+  const MCExpr *getVariableValue(bool SetUsed = true) const {
+    assert(isVariable() && "Invalid accessor!");
+    IsUsed |= SetUsed;
+    return Value;
+  }
+
+  void setVariableValue(const MCExpr *Value);
+
+  /// @}
+
+  /// Get the (implementation defined) index.
+  uint32_t getIndex() const {
+    return Index;
+  }
+
+  /// Set the (implementation defined) index.
+  void setIndex(uint32_t Value) const {
+    Index = Value;
+  }
+
+  bool isUnset() const { return SymbolContents == SymContentsUnset; }
+
+  uint64_t getOffset() const {
+    assert((SymbolContents == SymContentsUnset ||
+            SymbolContents == SymContentsOffset) &&
+           "Cannot get offset for a common/variable symbol");
+    return Offset;
+  }
+  void setOffset(uint64_t Value) {
+    assert((SymbolContents == SymContentsUnset ||
+            SymbolContents == SymContentsOffset) &&
+           "Cannot set offset for a common/variable symbol");
+    Offset = Value;
+    SymbolContents = SymContentsOffset;
+  }
+
+  /// Return the size of a 'common' symbol.
+  uint64_t getCommonSize() const {
+    assert(isCommon() && "Not a 'common' symbol!");
+    return CommonSize;
+  }
+
+  /// Mark this symbol as being 'common'.
+  ///
+  /// \param Size - The size of the symbol.
+  /// \param Align - The alignment of the symbol.
+  /// \param Target - Is the symbol a target-specific common-like symbol.
+  void setCommon(uint64_t Size, unsigned Align, bool Target = false) {
+    assert(getOffset() == 0);
+    CommonSize = Size;
+    SymbolContents = Target ? SymContentsTargetCommon : SymContentsCommon;
+
+    assert((!Align || isPowerOf2_32(Align)) &&
+           "Alignment must be a power of 2");
+    unsigned Log2Align = Log2_32(Align) + 1;
+    assert(Log2Align < (1U << NumCommonAlignmentBits) &&
+           "Out of range alignment");
+    CommonAlignLog2 = Log2Align;
+  }
+
+  ///  Return the alignment of a 'common' symbol.
+  unsigned getCommonAlignment() const {
+    assert(isCommon() && "Not a 'common' symbol!");
+    return CommonAlignLog2 ? (1U << (CommonAlignLog2 - 1)) : 0;
+  }
+
+  /// Declare this symbol as being 'common'.
+  ///
+  /// \param Size - The size of the symbol.
+  /// \param Align - The alignment of the symbol.
+  /// \param Target - Is the symbol a target-specific common-like symbol.
+  /// \return True if symbol was already declared as a different type
+  bool declareCommon(uint64_t Size, unsigned Align, bool Target = false) {
+    assert(isCommon() || getOffset() == 0);
+    if(isCommon()) {
+      if (CommonSize != Size || getCommonAlignment() != Align ||
+          isTargetCommon() != Target)
+        return true;
+    } else
+      setCommon(Size, Align, Target);
+    return false;
+  }
+
+  /// Is this a 'common' symbol.
+  bool isCommon() const {
+    return SymbolContents == SymContentsCommon ||
+           SymbolContents == SymContentsTargetCommon;
+  }
+
+  /// Is this a target-specific common-like symbol.
+  bool isTargetCommon() const {
+    return SymbolContents == SymContentsTargetCommon;
+  }
+
+  MCFragment *getFragment(bool SetUsed = true) const {
+    MCFragment *Fragment = FragmentAndHasName.getPointer();
+    if (Fragment || !isVariable())
+      return Fragment;
+    Fragment = getVariableValue(SetUsed)->findAssociatedFragment();
+    FragmentAndHasName.setPointer(Fragment);
+    return Fragment;
+  }
+
+  bool isExternal() const { return IsExternal; }
+  void setExternal(bool Value) const { IsExternal = Value; }
+
+  bool isPrivateExtern() const { return IsPrivateExtern; }
+  void setPrivateExtern(bool Value) { IsPrivateExtern = Value; }
+
+  /// print - Print the value to the stream \p OS.
+  void print(raw_ostream &OS, const MCAsmInfo *MAI) const;
+
+  /// dump - Print the value to stderr.
+  void dump() const;
+
+protected:
+  /// Get the (implementation defined) symbol flags.
+  uint32_t getFlags() const { return Flags; }
+
+  /// Set the (implementation defined) symbol flags.
+  void setFlags(uint32_t Value) const {
+    assert(Value < (1U << NumFlagsBits) && "Out of range flags");
+    Flags = Value;
+  }
+
+  /// Modify the flags via a mask
+  void modifyFlags(uint32_t Value, uint32_t Mask) const {
+    assert(Value < (1U << NumFlagsBits) && "Out of range flags");
+    Flags = (Flags & ~Mask) | Value;
+  }
+};
+
+inline raw_ostream &operator<<(raw_ostream &OS, const MCSymbol &Sym) {
+  Sym.print(OS, nullptr);
+  return OS;
+}
+
+} // end namespace llvm
+
+#endif // LLVM_MC_MCSYMBOL_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/MC/MCSymbolWasm.h b/binaryen/third_party/llvm-project/include/llvm/MC/MCSymbolWasm.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/MC/MCSymbolWasm.h
@@ -0,0 +1,110 @@
+//===- MCSymbolWasm.h -  ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_MC_MCSYMBOLWASM_H
+#define LLVM_MC_MCSYMBOLWASM_H
+
+#include "llvm/BinaryFormat/Wasm.h"
+#include "llvm/MC/MCSymbol.h"
+
+namespace llvm {
+
+class MCSymbolWasm : public MCSymbol {
+  wasm::WasmSymbolType Type = wasm::WASM_SYMBOL_TYPE_DATA;
+  bool IsWeak = false;
+  bool IsHidden = false;
+  bool IsComdat = false;
+  mutable bool IsUsedInGOT = false;
+  Optional<std::string> ImportModule;
+  Optional<std::string> ImportName;
+  wasm::WasmSignature *Signature = nullptr;
+  Optional<wasm::WasmGlobalType> GlobalType;
+  Optional<wasm::WasmEventType> EventType;
+
+  /// An expression describing how to calculate the size of a symbol. If a
+  /// symbol has no size this field will be NULL.
+  const MCExpr *SymbolSize = nullptr;
+
+public:
+  // Use a module name of "env" for now, for compatibility with existing tools.
+  // This is temporary, and may change, as the ABI is not yet stable.
+  MCSymbolWasm(const StringMapEntry<bool> *Name, bool isTemporary)
+      : MCSymbol(SymbolKindWasm, Name, isTemporary) {}
+  static bool classof(const MCSymbol *S) { return S->isWasm(); }
+
+  const MCExpr *getSize() const { return SymbolSize; }
+  void setSize(const MCExpr *SS) { SymbolSize = SS; }
+
+  bool isFunction() const { return Type == wasm::WASM_SYMBOL_TYPE_FUNCTION; }
+  bool isData() const { return Type == wasm::WASM_SYMBOL_TYPE_DATA; }
+  bool isGlobal() const { return Type == wasm::WASM_SYMBOL_TYPE_GLOBAL; }
+  bool isSection() const { return Type == wasm::WASM_SYMBOL_TYPE_SECTION; }
+  bool isEvent() const { return Type == wasm::WASM_SYMBOL_TYPE_EVENT; }
+  wasm::WasmSymbolType getType() const { return Type; }
+  void setType(wasm::WasmSymbolType type) { Type = type; }
+
+  bool isExported() const {
+    return getFlags() & wasm::WASM_SYMBOL_EXPORTED;
+  }
+  void setExported() const {
+    modifyFlags(wasm::WASM_SYMBOL_EXPORTED, wasm::WASM_SYMBOL_EXPORTED);
+  }
+
+  bool isNoStrip() const {
+    return getFlags() & wasm::WASM_SYMBOL_NO_STRIP;
+  }
+  void setNoStrip() const {
+    modifyFlags(wasm::WASM_SYMBOL_NO_STRIP, wasm::WASM_SYMBOL_NO_STRIP);
+  }
+
+  bool isWeak() const { return IsWeak; }
+  void setWeak(bool isWeak) { IsWeak = isWeak; }
+
+  bool isHidden() const { return IsHidden; }
+  void setHidden(bool isHidden) { IsHidden = isHidden; }
+
+  bool isComdat() const { return IsComdat; }
+  void setComdat(bool isComdat) { IsComdat = isComdat; }
+
+  const StringRef getImportModule() const {
+      if (ImportModule.hasValue()) {
+          return ImportModule.getValue();
+      }
+      return "env";
+  }
+  void setImportModule(StringRef Name) { ImportModule = Name; }
+
+  const StringRef getImportName() const {
+      if (ImportName.hasValue()) {
+          return ImportName.getValue();
+      }
+      return getName();
+  }
+  void setImportName(StringRef Name) { ImportName = Name; }
+
+  void setUsedInGOT() const { IsUsedInGOT = true; }
+  bool isUsedInGOT() const { return IsUsedInGOT; }
+
+  const wasm::WasmSignature *getSignature() const { return Signature; }
+  void setSignature(wasm::WasmSignature *Sig) { Signature = Sig; }
+
+  const wasm::WasmGlobalType &getGlobalType() const {
+    assert(GlobalType.hasValue());
+    return GlobalType.getValue();
+  }
+  void setGlobalType(wasm::WasmGlobalType GT) { GlobalType = GT; }
+
+  const wasm::WasmEventType &getEventType() const {
+    assert(EventType.hasValue());
+    return EventType.getValue();
+  }
+  void setEventType(wasm::WasmEventType ET) { EventType = ET; }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_MC_MCSYMBOLWASM_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/MC/SubtargetFeature.h b/binaryen/third_party/llvm-project/include/llvm/MC/SubtargetFeature.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/MC/SubtargetFeature.h
@@ -0,0 +1,236 @@
+//===- llvm/MC/SubtargetFeature.h - CPU characteristics ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file Defines and manages user or tool specified CPU characteristics.
+/// The intent is to be able to package specific features that should or should
+/// not be used on a specific target processor.  A tool, such as llc, could, as
+/// as example, gather chip info from the command line, a long with features
+/// that should be used on that chip.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_SUBTARGETFEATURE_H
+#define LLVM_MC_SUBTARGETFEATURE_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MathExtras.h"
+#include <array>
+#include <bitset>
+#include <initializer_list>
+#include <string>
+#include <vector>
+
+namespace llvm {
+
+class raw_ostream;
+class Triple;
+
+const unsigned MAX_SUBTARGET_WORDS = 3;
+const unsigned MAX_SUBTARGET_FEATURES = MAX_SUBTARGET_WORDS * 64;
+
+/// Container class for subtarget features.
+/// This is a constexpr reimplementation of a subset of std::bitset. It would be
+/// nice to use std::bitset directly, but it doesn't support constant
+/// initialization.
+class FeatureBitset {
+  static_assert((MAX_SUBTARGET_FEATURES % 64) == 0,
+                "Should be a multiple of 64!");
+  // This cannot be a std::array, operator[] is not constexpr until C++17.
+  uint64_t Bits[MAX_SUBTARGET_WORDS] = {};
+
+protected:
+  constexpr FeatureBitset(const std::array<uint64_t, MAX_SUBTARGET_WORDS> &B) {
+    for (unsigned I = 0; I != B.size(); ++I)
+      Bits[I] = B[I];
+  }
+
+public:
+  constexpr FeatureBitset() = default;
+  constexpr FeatureBitset(std::initializer_list<unsigned> Init) {
+    for (auto I : Init)
+      set(I);
+  }
+
+  FeatureBitset &set() {
+    std::fill(std::begin(Bits), std::end(Bits), -1ULL);
+    return *this;
+  }
+
+  constexpr FeatureBitset &set(unsigned I) {
+    // GCC <6.2 crashes if this is written in a single statement.
+    uint64_t NewBits = Bits[I / 64] | (uint64_t(1) << (I % 64));
+    Bits[I / 64] = NewBits;
+    return *this;
+  }
+
+  constexpr FeatureBitset &reset(unsigned I) {
+    // GCC <6.2 crashes if this is written in a single statement.
+    uint64_t NewBits = Bits[I / 64] & ~(uint64_t(1) << (I % 64));
+    Bits[I / 64] = NewBits;
+    return *this;
+  }
+
+  constexpr FeatureBitset &flip(unsigned I) {
+    // GCC <6.2 crashes if this is written in a single statement.
+    uint64_t NewBits = Bits[I / 64] ^ (uint64_t(1) << (I % 64));
+    Bits[I / 64] = NewBits;
+    return *this;
+  }
+
+  constexpr bool operator[](unsigned I) const {
+    uint64_t Mask = uint64_t(1) << (I % 64);
+    return (Bits[I / 64] & Mask) != 0;
+  }
+
+  constexpr bool test(unsigned I) const { return (*this)[I]; }
+
+  constexpr size_t size() const { return MAX_SUBTARGET_FEATURES; }
+
+  bool any() const {
+    return llvm::any_of(Bits, [](uint64_t I) { return I != 0; });
+  }
+  bool none() const { return !any(); }
+  size_t count() const {
+    size_t Count = 0;
+    for (auto B : Bits)
+      Count += countPopulation(B);
+    return Count;
+  }
+
+  constexpr FeatureBitset &operator^=(const FeatureBitset &RHS) {
+    for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I) {
+      Bits[I] ^= RHS.Bits[I];
+    }
+    return *this;
+  }
+  constexpr FeatureBitset operator^(const FeatureBitset &RHS) const {
+    FeatureBitset Result = *this;
+    Result ^= RHS;
+    return Result;
+  }
+
+  constexpr FeatureBitset &operator&=(const FeatureBitset &RHS) {
+    for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I) {
+      Bits[I] &= RHS.Bits[I];
+    }
+    return *this;
+  }
+  constexpr FeatureBitset operator&(const FeatureBitset &RHS) const {
+    FeatureBitset Result = *this;
+    Result &= RHS;
+    return Result;
+  }
+
+  constexpr FeatureBitset &operator|=(const FeatureBitset &RHS) {
+    for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I) {
+      Bits[I] |= RHS.Bits[I];
+    }
+    return *this;
+  }
+  constexpr FeatureBitset operator|(const FeatureBitset &RHS) const {
+    FeatureBitset Result = *this;
+    Result |= RHS;
+    return Result;
+  }
+
+  constexpr FeatureBitset operator~() const {
+    FeatureBitset Result = *this;
+    for (auto &B : Result.Bits)
+      B = ~B;
+    return Result;
+  }
+
+  bool operator==(const FeatureBitset &RHS) const {
+    return std::equal(std::begin(Bits), std::end(Bits), std::begin(RHS.Bits));
+  }
+
+  bool operator!=(const FeatureBitset &RHS) const { return !(*this == RHS); }
+
+  bool operator < (const FeatureBitset &Other) const {
+    for (unsigned I = 0, E = size(); I != E; ++I) {
+      bool LHS = test(I), RHS = Other.test(I);
+      if (LHS != RHS)
+        return LHS < RHS;
+    }
+    return false;
+  }
+};
+
+/// Class used to store the subtarget bits in the tables created by tablegen.
+class FeatureBitArray : public FeatureBitset {
+public:
+  constexpr FeatureBitArray(const std::array<uint64_t, MAX_SUBTARGET_WORDS> &B)
+      : FeatureBitset(B) {}
+
+  const FeatureBitset &getAsBitset() const { return *this; }
+};
+
+//===----------------------------------------------------------------------===//
+
+/// Manages the enabling and disabling of subtarget specific features.
+///
+/// Features are encoded as a string of the form
+///   "+attr1,+attr2,-attr3,...,+attrN"
+/// A comma separates each feature from the next (all lowercase.)
+/// Each of the remaining features is prefixed with + or - indicating whether
+/// that feature should be enabled or disabled contrary to the cpu
+/// specification.
+class SubtargetFeatures {
+  std::vector<std::string> Features;    ///< Subtarget features as a vector
+
+public:
+  explicit SubtargetFeatures(StringRef Initial = "");
+
+  /// Returns features as a string.
+  std::string getString() const;
+
+  /// Adds Features.
+  void AddFeature(StringRef String, bool Enable = true);
+
+  /// Returns the vector of individual subtarget features.
+  const std::vector<std::string> &getFeatures() const { return Features; }
+
+  /// Prints feature string.
+  void print(raw_ostream &OS) const;
+
+  // Dumps feature info.
+  void dump() const;
+
+  /// Adds the default features for the specified target triple.
+  void getDefaultSubtargetFeatures(const Triple& Triple);
+
+  /// Determine if a feature has a flag; '+' or '-'
+  static bool hasFlag(StringRef Feature) {
+    assert(!Feature.empty() && "Empty string");
+    // Get first character
+    char Ch = Feature[0];
+    // Check if first character is '+' or '-' flag
+    return Ch == '+' || Ch =='-';
+  }
+
+  /// Return string stripped of flag.
+  static std::string StripFlag(StringRef Feature) {
+    return hasFlag(Feature) ? Feature.substr(1) : Feature;
+  }
+
+  /// Return true if enable flag; '+'.
+  static inline bool isEnabled(StringRef Feature) {
+    assert(!Feature.empty() && "Empty string");
+    // Get first character
+    char Ch = Feature[0];
+    // Check if first character is '+' for enabled
+    return Ch == '+';
+  }
+
+  /// Splits a string of comma separated items in to a vector of strings.
+  static void Split(std::vector<std::string> &V, StringRef S);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_MC_SUBTARGETFEATURE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Object/Archive.h b/binaryen/third_party/llvm-project/include/llvm/Object/Archive.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Object/Archive.h
@@ -0,0 +1,286 @@
+//===- Archive.h - ar archive file format -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the ar archive file format class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_ARCHIVE_H
+#define LLVM_OBJECT_ARCHIVE_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/fallible_iterator.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace llvm {
+namespace object {
+
+class Archive;
+
+class ArchiveMemberHeader {
+public:
+  friend class Archive;
+
+  ArchiveMemberHeader(Archive const *Parent, const char *RawHeaderPtr,
+                      uint64_t Size, Error *Err);
+  // ArchiveMemberHeader() = default;
+
+  /// Get the name without looking up long names.
+  Expected<StringRef> getRawName() const;
+
+  /// Get the name looking up long names.
+  Expected<StringRef> getName(uint64_t Size) const;
+
+  Expected<uint64_t> getSize() const;
+
+  Expected<sys::fs::perms> getAccessMode() const;
+  Expected<sys::TimePoint<std::chrono::seconds>> getLastModified() const;
+
+  StringRef getRawLastModified() const {
+    return StringRef(ArMemHdr->LastModified,
+                     sizeof(ArMemHdr->LastModified)).rtrim(' ');
+  }
+
+  Expected<unsigned> getUID() const;
+  Expected<unsigned> getGID() const;
+
+  // This returns the size of the private struct ArMemHdrType
+  uint64_t getSizeOf() const {
+    return sizeof(ArMemHdrType);
+  }
+
+private:
+  struct ArMemHdrType {
+    char Name[16];
+    char LastModified[12];
+    char UID[6];
+    char GID[6];
+    char AccessMode[8];
+    char Size[10]; ///< Size of data, not including header or padding.
+    char Terminator[2];
+  };
+  Archive const *Parent;
+  ArMemHdrType const *ArMemHdr;
+};
+
+class Archive : public Binary {
+  virtual void anchor();
+
+public:
+  class Child {
+    friend Archive;
+    friend ArchiveMemberHeader;
+
+    const Archive *Parent;
+    ArchiveMemberHeader Header;
+    /// Includes header but not padding byte.
+    StringRef Data;
+    /// Offset from Data to the start of the file.
+    uint16_t StartOfFile;
+
+    Expected<bool> isThinMember() const;
+
+  public:
+    Child(const Archive *Parent, const char *Start, Error *Err);
+    Child(const Archive *Parent, StringRef Data, uint16_t StartOfFile);
+
+    bool operator ==(const Child &other) const {
+      assert(!Parent || !other.Parent || Parent == other.Parent);
+      return Data.begin() == other.Data.begin();
+    }
+
+    const Archive *getParent() const { return Parent; }
+    Expected<Child> getNext() const;
+
+    Expected<StringRef> getName() const;
+    Expected<std::string> getFullName() const;
+    Expected<StringRef> getRawName() const { return Header.getRawName(); }
+
+    Expected<sys::TimePoint<std::chrono::seconds>> getLastModified() const {
+      return Header.getLastModified();
+    }
+
+    StringRef getRawLastModified() const {
+      return Header.getRawLastModified();
+    }
+
+    Expected<unsigned> getUID() const { return Header.getUID(); }
+    Expected<unsigned> getGID() const { return Header.getGID(); }
+
+    Expected<sys::fs::perms> getAccessMode() const {
+      return Header.getAccessMode();
+    }
+
+    /// \return the size of the archive member without the header or padding.
+    Expected<uint64_t> getSize() const;
+    /// \return the size in the archive header for this member.
+    Expected<uint64_t> getRawSize() const;
+
+    Expected<StringRef> getBuffer() const;
+    uint64_t getChildOffset() const;
+    uint64_t getDataOffset() const { return getChildOffset() + StartOfFile; }
+
+    Expected<MemoryBufferRef> getMemoryBufferRef() const;
+
+    Expected<std::unique_ptr<Binary>>
+    getAsBinary(LLVMContext *Context = nullptr) const;
+  };
+
+  class ChildFallibleIterator {
+    Child C;
+
+  public:
+    ChildFallibleIterator() : C(Child(nullptr, nullptr, nullptr)) {}
+    ChildFallibleIterator(const Child &C) : C(C) {}
+
+    const Child *operator->() const { return &C; }
+    const Child &operator*() const { return C; }
+
+    bool operator==(const ChildFallibleIterator &other) const {
+      // Ignore errors here: If an error occurred during increment then getNext
+      // will have been set to child_end(), and the following comparison should
+      // do the right thing.
+      return C == other.C;
+    }
+
+    bool operator!=(const ChildFallibleIterator &other) const {
+      return !(*this == other);
+    }
+
+    Error inc() {
+      auto NextChild = C.getNext();
+      if (!NextChild)
+        return NextChild.takeError();
+      C = std::move(*NextChild);
+      return Error::success();
+    }
+  };
+
+  using child_iterator = fallible_iterator<ChildFallibleIterator>;
+
+  class Symbol {
+    const Archive *Parent;
+    uint32_t SymbolIndex;
+    uint32_t StringIndex; // Extra index to the string.
+
+  public:
+    Symbol(const Archive *p, uint32_t symi, uint32_t stri)
+      : Parent(p)
+      , SymbolIndex(symi)
+      , StringIndex(stri) {}
+
+    bool operator ==(const Symbol &other) const {
+      return (Parent == other.Parent) && (SymbolIndex == other.SymbolIndex);
+    }
+
+    StringRef getName() const;
+    Expected<Child> getMember() const;
+    Symbol getNext() const;
+  };
+
+  class symbol_iterator {
+    Symbol symbol;
+
+  public:
+    symbol_iterator(const Symbol &s) : symbol(s) {}
+
+    const Symbol *operator->() const { return &symbol; }
+    const Symbol &operator*() const { return symbol; }
+
+    bool operator==(const symbol_iterator &other) const {
+      return symbol == other.symbol;
+    }
+
+    bool operator!=(const symbol_iterator &other) const {
+      return !(*this == other);
+    }
+
+    symbol_iterator& operator++() {  // Preincrement
+      symbol = symbol.getNext();
+      return *this;
+    }
+  };
+
+  Archive(MemoryBufferRef Source, Error &Err);
+  static Expected<std::unique_ptr<Archive>> create(MemoryBufferRef Source);
+
+  /// Size field is 10 decimal digits long
+  static const uint64_t MaxMemberSize = 9999999999;
+
+  enum Kind {
+    K_GNU,
+    K_GNU64,
+    K_BSD,
+    K_DARWIN,
+    K_DARWIN64,
+    K_COFF
+  };
+
+  Kind kind() const { return (Kind)Format; }
+  bool isThin() const { return IsThin; }
+
+  child_iterator child_begin(Error &Err, bool SkipInternal = true) const;
+  child_iterator child_end() const;
+  iterator_range<child_iterator> children(Error &Err,
+                                          bool SkipInternal = true) const {
+    return make_range(child_begin(Err, SkipInternal), child_end());
+  }
+
+  symbol_iterator symbol_begin() const;
+  symbol_iterator symbol_end() const;
+  iterator_range<symbol_iterator> symbols() const {
+    return make_range(symbol_begin(), symbol_end());
+  }
+
+  // Cast methods.
+  static bool classof(Binary const *v) {
+    return v->isArchive();
+  }
+
+  // check if a symbol is in the archive
+  Expected<Optional<Child>> findSym(StringRef name) const;
+
+  bool isEmpty() const;
+  bool hasSymbolTable() const;
+  StringRef getSymbolTable() const { return SymbolTable; }
+  StringRef getStringTable() const { return StringTable; }
+  uint32_t getNumberOfSymbols() const;
+
+  std::vector<std::unique_ptr<MemoryBuffer>> takeThinBuffers() {
+    return std::move(ThinBuffers);
+  }
+
+private:
+  StringRef SymbolTable;
+  StringRef StringTable;
+
+  StringRef FirstRegularData;
+  uint16_t FirstRegularStartOfFile = -1;
+  void setFirstRegular(const Child &C);
+
+  unsigned Format : 3;
+  unsigned IsThin : 1;
+  mutable std::vector<std::unique_ptr<MemoryBuffer>> ThinBuffers;
+};
+
+} // end namespace object
+} // end namespace llvm
+
+#endif // LLVM_OBJECT_ARCHIVE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Object/Binary.h b/binaryen/third_party/llvm-project/include/llvm/Object/Binary.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Object/Binary.h
@@ -0,0 +1,237 @@
+//===- Binary.h - A generic binary file -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the Binary class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_BINARY_H
+#define LLVM_OBJECT_BINARY_H
+
+#include "llvm-c/Types.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+namespace llvm {
+
+class LLVMContext;
+class StringRef;
+
+namespace object {
+
+class Binary {
+private:
+  unsigned int TypeID;
+
+protected:
+  MemoryBufferRef Data;
+
+  Binary(unsigned int Type, MemoryBufferRef Source);
+
+  enum {
+    ID_Archive,
+    ID_MachOUniversalBinary,
+    ID_COFFImportFile,
+    ID_IR,            // LLVM IR
+    ID_TapiUniversal, // Text-based Dynamic Library Stub file.
+    ID_TapiFile,      // Text-based Dynamic Library Stub file.
+
+    ID_Minidump,
+
+    ID_WinRes, // Windows resource (.res) file.
+
+    // Object and children.
+    ID_StartObjects,
+    ID_COFF,
+
+    ID_XCOFF32, // AIX XCOFF 32-bit
+    ID_XCOFF64, // AIX XCOFF 64-bit
+
+    ID_ELF32L, // ELF 32-bit, little endian
+    ID_ELF32B, // ELF 32-bit, big endian
+    ID_ELF64L, // ELF 64-bit, little endian
+    ID_ELF64B, // ELF 64-bit, big endian
+
+    ID_MachO32L, // MachO 32-bit, little endian
+    ID_MachO32B, // MachO 32-bit, big endian
+    ID_MachO64L, // MachO 64-bit, little endian
+    ID_MachO64B, // MachO 64-bit, big endian
+
+    ID_Wasm,
+
+    ID_EndObjects
+  };
+
+  static inline unsigned int getELFType(bool isLE, bool is64Bits) {
+    if (isLE)
+      return is64Bits ? ID_ELF64L : ID_ELF32L;
+    else
+      return is64Bits ? ID_ELF64B : ID_ELF32B;
+  }
+
+  static unsigned int getMachOType(bool isLE, bool is64Bits) {
+    if (isLE)
+      return is64Bits ? ID_MachO64L : ID_MachO32L;
+    else
+      return is64Bits ? ID_MachO64B : ID_MachO32B;
+  }
+
+public:
+  Binary() = delete;
+  Binary(const Binary &other) = delete;
+  virtual ~Binary();
+
+  StringRef getData() const;
+  StringRef getFileName() const;
+  MemoryBufferRef getMemoryBufferRef() const;
+
+  // Cast methods.
+  unsigned int getType() const { return TypeID; }
+
+  // Convenience methods
+  bool isObject() const {
+    return TypeID > ID_StartObjects && TypeID < ID_EndObjects;
+  }
+
+  bool isSymbolic() const {
+    return isIR() || isObject() || isCOFFImportFile() || isTapiFile();
+  }
+
+  bool isArchive() const { return TypeID == ID_Archive; }
+
+  bool isMachOUniversalBinary() const {
+    return TypeID == ID_MachOUniversalBinary;
+  }
+
+  bool isTapiUniversal() const { return TypeID == ID_TapiUniversal; }
+
+  bool isELF() const {
+    return TypeID >= ID_ELF32L && TypeID <= ID_ELF64B;
+  }
+
+  bool isMachO() const {
+    return TypeID >= ID_MachO32L && TypeID <= ID_MachO64B;
+  }
+
+  bool isCOFF() const {
+    return TypeID == ID_COFF;
+  }
+
+  bool isXCOFF() const { return TypeID == ID_XCOFF32 || TypeID == ID_XCOFF64; }
+
+  bool isWasm() const { return TypeID == ID_Wasm; }
+
+  bool isCOFFImportFile() const {
+    return TypeID == ID_COFFImportFile;
+  }
+
+  bool isIR() const {
+    return TypeID == ID_IR;
+  }
+
+  bool isMinidump() const { return TypeID == ID_Minidump; }
+
+  bool isTapiFile() const { return TypeID == ID_TapiFile; }
+
+  bool isLittleEndian() const {
+    return !(TypeID == ID_ELF32B || TypeID == ID_ELF64B ||
+             TypeID == ID_MachO32B || TypeID == ID_MachO64B);
+  }
+
+  bool isWinRes() const { return TypeID == ID_WinRes; }
+
+  Triple::ObjectFormatType getTripleObjectFormat() const {
+    if (isCOFF())
+      return Triple::COFF;
+    if (isMachO())
+      return Triple::MachO;
+    if (isELF())
+      return Triple::ELF;
+    return Triple::UnknownObjectFormat;
+  }
+
+  static std::error_code checkOffset(MemoryBufferRef M, uintptr_t Addr,
+                                     const uint64_t Size) {
+    if (Addr + Size < Addr || Addr + Size < Size ||
+        Addr + Size > uintptr_t(M.getBufferEnd()) ||
+        Addr < uintptr_t(M.getBufferStart())) {
+      return object_error::unexpected_eof;
+    }
+    return std::error_code();
+  }
+};
+
+// Create wrappers for C Binding types (see CBindingWrapping.h).
+DEFINE_ISA_CONVERSION_FUNCTIONS(Binary, LLVMBinaryRef)
+
+/// Create a Binary from Source, autodetecting the file type.
+///
+/// @param Source The data to create the Binary from.
+Expected<std::unique_ptr<Binary>> createBinary(MemoryBufferRef Source,
+                                               LLVMContext *Context = nullptr);
+
+template <typename T> class OwningBinary {
+  std::unique_ptr<T> Bin;
+  std::unique_ptr<MemoryBuffer> Buf;
+
+public:
+  OwningBinary();
+  OwningBinary(std::unique_ptr<T> Bin, std::unique_ptr<MemoryBuffer> Buf);
+  OwningBinary(OwningBinary<T>&& Other);
+  OwningBinary<T> &operator=(OwningBinary<T> &&Other);
+
+  std::pair<std::unique_ptr<T>, std::unique_ptr<MemoryBuffer>> takeBinary();
+
+  T* getBinary();
+  const T* getBinary() const;
+};
+
+template <typename T>
+OwningBinary<T>::OwningBinary(std::unique_ptr<T> Bin,
+                              std::unique_ptr<MemoryBuffer> Buf)
+    : Bin(std::move(Bin)), Buf(std::move(Buf)) {}
+
+template <typename T> OwningBinary<T>::OwningBinary() = default;
+
+template <typename T>
+OwningBinary<T>::OwningBinary(OwningBinary &&Other)
+    : Bin(std::move(Other.Bin)), Buf(std::move(Other.Buf)) {}
+
+template <typename T>
+OwningBinary<T> &OwningBinary<T>::operator=(OwningBinary &&Other) {
+  Bin = std::move(Other.Bin);
+  Buf = std::move(Other.Buf);
+  return *this;
+}
+
+template <typename T>
+std::pair<std::unique_ptr<T>, std::unique_ptr<MemoryBuffer>>
+OwningBinary<T>::takeBinary() {
+  return std::make_pair(std::move(Bin), std::move(Buf));
+}
+
+template <typename T> T* OwningBinary<T>::getBinary() {
+  return Bin.get();
+}
+
+template <typename T> const T* OwningBinary<T>::getBinary() const {
+  return Bin.get();
+}
+
+Expected<OwningBinary<Binary>> createBinary(StringRef Path);
+
+} // end namespace object
+
+} // end namespace llvm
+
+#endif // LLVM_OBJECT_BINARY_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Object/COFF.h b/binaryen/third_party/llvm-project/include/llvm/Object/COFF.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Object/COFF.h
@@ -0,0 +1,1269 @@
+//===- COFF.h - COFF object file implementation -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the COFFObjectFile class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_COFF_H
+#define LLVM_OBJECT_COFF_H
+
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/CVDebugRecord.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <system_error>
+
+namespace llvm {
+
+template <typename T> class ArrayRef;
+
+namespace object {
+
+class BaseRelocRef;
+class DelayImportDirectoryEntryRef;
+class ExportDirectoryEntryRef;
+class ImportDirectoryEntryRef;
+class ImportedSymbolRef;
+class ResourceSectionRef;
+
+using import_directory_iterator = content_iterator<ImportDirectoryEntryRef>;
+using delay_import_directory_iterator =
+    content_iterator<DelayImportDirectoryEntryRef>;
+using export_directory_iterator = content_iterator<ExportDirectoryEntryRef>;
+using imported_symbol_iterator = content_iterator<ImportedSymbolRef>;
+using base_reloc_iterator = content_iterator<BaseRelocRef>;
+
+/// The DOS compatible header at the front of all PE/COFF executables.
+struct dos_header {
+  char                 Magic[2];
+  support::ulittle16_t UsedBytesInTheLastPage;
+  support::ulittle16_t FileSizeInPages;
+  support::ulittle16_t NumberOfRelocationItems;
+  support::ulittle16_t HeaderSizeInParagraphs;
+  support::ulittle16_t MinimumExtraParagraphs;
+  support::ulittle16_t MaximumExtraParagraphs;
+  support::ulittle16_t InitialRelativeSS;
+  support::ulittle16_t InitialSP;
+  support::ulittle16_t Checksum;
+  support::ulittle16_t InitialIP;
+  support::ulittle16_t InitialRelativeCS;
+  support::ulittle16_t AddressOfRelocationTable;
+  support::ulittle16_t OverlayNumber;
+  support::ulittle16_t Reserved[4];
+  support::ulittle16_t OEMid;
+  support::ulittle16_t OEMinfo;
+  support::ulittle16_t Reserved2[10];
+  support::ulittle32_t AddressOfNewExeHeader;
+};
+
+struct coff_file_header {
+  support::ulittle16_t Machine;
+  support::ulittle16_t NumberOfSections;
+  support::ulittle32_t TimeDateStamp;
+  support::ulittle32_t PointerToSymbolTable;
+  support::ulittle32_t NumberOfSymbols;
+  support::ulittle16_t SizeOfOptionalHeader;
+  support::ulittle16_t Characteristics;
+
+  bool isImportLibrary() const { return NumberOfSections == 0xffff; }
+};
+
+struct coff_bigobj_file_header {
+  support::ulittle16_t Sig1;
+  support::ulittle16_t Sig2;
+  support::ulittle16_t Version;
+  support::ulittle16_t Machine;
+  support::ulittle32_t TimeDateStamp;
+  uint8_t              UUID[16];
+  support::ulittle32_t unused1;
+  support::ulittle32_t unused2;
+  support::ulittle32_t unused3;
+  support::ulittle32_t unused4;
+  support::ulittle32_t NumberOfSections;
+  support::ulittle32_t PointerToSymbolTable;
+  support::ulittle32_t NumberOfSymbols;
+};
+
+/// The 32-bit PE header that follows the COFF header.
+struct pe32_header {
+  support::ulittle16_t Magic;
+  uint8_t MajorLinkerVersion;
+  uint8_t MinorLinkerVersion;
+  support::ulittle32_t SizeOfCode;
+  support::ulittle32_t SizeOfInitializedData;
+  support::ulittle32_t SizeOfUninitializedData;
+  support::ulittle32_t AddressOfEntryPoint;
+  support::ulittle32_t BaseOfCode;
+  support::ulittle32_t BaseOfData;
+  support::ulittle32_t ImageBase;
+  support::ulittle32_t SectionAlignment;
+  support::ulittle32_t FileAlignment;
+  support::ulittle16_t MajorOperatingSystemVersion;
+  support::ulittle16_t MinorOperatingSystemVersion;
+  support::ulittle16_t MajorImageVersion;
+  support::ulittle16_t MinorImageVersion;
+  support::ulittle16_t MajorSubsystemVersion;
+  support::ulittle16_t MinorSubsystemVersion;
+  support::ulittle32_t Win32VersionValue;
+  support::ulittle32_t SizeOfImage;
+  support::ulittle32_t SizeOfHeaders;
+  support::ulittle32_t CheckSum;
+  support::ulittle16_t Subsystem;
+  // FIXME: This should be DllCharacteristics.
+  support::ulittle16_t DLLCharacteristics;
+  support::ulittle32_t SizeOfStackReserve;
+  support::ulittle32_t SizeOfStackCommit;
+  support::ulittle32_t SizeOfHeapReserve;
+  support::ulittle32_t SizeOfHeapCommit;
+  support::ulittle32_t LoaderFlags;
+  // FIXME: This should be NumberOfRvaAndSizes.
+  support::ulittle32_t NumberOfRvaAndSize;
+};
+
+/// The 64-bit PE header that follows the COFF header.
+struct pe32plus_header {
+  support::ulittle16_t Magic;
+  uint8_t MajorLinkerVersion;
+  uint8_t MinorLinkerVersion;
+  support::ulittle32_t SizeOfCode;
+  support::ulittle32_t SizeOfInitializedData;
+  support::ulittle32_t SizeOfUninitializedData;
+  support::ulittle32_t AddressOfEntryPoint;
+  support::ulittle32_t BaseOfCode;
+  support::ulittle64_t ImageBase;
+  support::ulittle32_t SectionAlignment;
+  support::ulittle32_t FileAlignment;
+  support::ulittle16_t MajorOperatingSystemVersion;
+  support::ulittle16_t MinorOperatingSystemVersion;
+  support::ulittle16_t MajorImageVersion;
+  support::ulittle16_t MinorImageVersion;
+  support::ulittle16_t MajorSubsystemVersion;
+  support::ulittle16_t MinorSubsystemVersion;
+  support::ulittle32_t Win32VersionValue;
+  support::ulittle32_t SizeOfImage;
+  support::ulittle32_t SizeOfHeaders;
+  support::ulittle32_t CheckSum;
+  support::ulittle16_t Subsystem;
+  support::ulittle16_t DLLCharacteristics;
+  support::ulittle64_t SizeOfStackReserve;
+  support::ulittle64_t SizeOfStackCommit;
+  support::ulittle64_t SizeOfHeapReserve;
+  support::ulittle64_t SizeOfHeapCommit;
+  support::ulittle32_t LoaderFlags;
+  support::ulittle32_t NumberOfRvaAndSize;
+};
+
+struct data_directory {
+  support::ulittle32_t RelativeVirtualAddress;
+  support::ulittle32_t Size;
+};
+
+struct debug_directory {
+  support::ulittle32_t Characteristics;
+  support::ulittle32_t TimeDateStamp;
+  support::ulittle16_t MajorVersion;
+  support::ulittle16_t MinorVersion;
+  support::ulittle32_t Type;
+  support::ulittle32_t SizeOfData;
+  support::ulittle32_t AddressOfRawData;
+  support::ulittle32_t PointerToRawData;
+};
+
+template <typename IntTy>
+struct import_lookup_table_entry {
+  IntTy Data;
+
+  bool isOrdinal() const { return Data < 0; }
+
+  uint16_t getOrdinal() const {
+    assert(isOrdinal() && "ILT entry is not an ordinal!");
+    return Data & 0xFFFF;
+  }
+
+  uint32_t getHintNameRVA() const {
+    assert(!isOrdinal() && "ILT entry is not a Hint/Name RVA!");
+    return Data & 0xFFFFFFFF;
+  }
+};
+
+using import_lookup_table_entry32 =
+    import_lookup_table_entry<support::little32_t>;
+using import_lookup_table_entry64 =
+    import_lookup_table_entry<support::little64_t>;
+
+struct delay_import_directory_table_entry {
+  // dumpbin reports this field as "Characteristics" instead of "Attributes".
+  support::ulittle32_t Attributes;
+  support::ulittle32_t Name;
+  support::ulittle32_t ModuleHandle;
+  support::ulittle32_t DelayImportAddressTable;
+  support::ulittle32_t DelayImportNameTable;
+  support::ulittle32_t BoundDelayImportTable;
+  support::ulittle32_t UnloadDelayImportTable;
+  support::ulittle32_t TimeStamp;
+};
+
+struct export_directory_table_entry {
+  support::ulittle32_t ExportFlags;
+  support::ulittle32_t TimeDateStamp;
+  support::ulittle16_t MajorVersion;
+  support::ulittle16_t MinorVersion;
+  support::ulittle32_t NameRVA;
+  support::ulittle32_t OrdinalBase;
+  support::ulittle32_t AddressTableEntries;
+  support::ulittle32_t NumberOfNamePointers;
+  support::ulittle32_t ExportAddressTableRVA;
+  support::ulittle32_t NamePointerRVA;
+  support::ulittle32_t OrdinalTableRVA;
+};
+
+union export_address_table_entry {
+  support::ulittle32_t ExportRVA;
+  support::ulittle32_t ForwarderRVA;
+};
+
+using export_name_pointer_table_entry = support::ulittle32_t;
+using export_ordinal_table_entry = support::ulittle16_t;
+
+struct StringTableOffset {
+  support::ulittle32_t Zeroes;
+  support::ulittle32_t Offset;
+};
+
+template <typename SectionNumberType>
+struct coff_symbol {
+  union {
+    char ShortName[COFF::NameSize];
+    StringTableOffset Offset;
+  } Name;
+
+  support::ulittle32_t Value;
+  SectionNumberType SectionNumber;
+
+  support::ulittle16_t Type;
+
+  uint8_t StorageClass;
+  uint8_t NumberOfAuxSymbols;
+};
+
+using coff_symbol16 = coff_symbol<support::ulittle16_t>;
+using coff_symbol32 = coff_symbol<support::ulittle32_t>;
+
+// Contains only common parts of coff_symbol16 and coff_symbol32.
+struct coff_symbol_generic {
+  union {
+    char ShortName[COFF::NameSize];
+    StringTableOffset Offset;
+  } Name;
+  support::ulittle32_t Value;
+};
+
+struct coff_aux_section_definition;
+struct coff_aux_weak_external;
+
+class COFFSymbolRef {
+public:
+  COFFSymbolRef() = default;
+  COFFSymbolRef(const coff_symbol16 *CS) : CS16(CS) {}
+  COFFSymbolRef(const coff_symbol32 *CS) : CS32(CS) {}
+
+  const void *getRawPtr() const {
+    return CS16 ? static_cast<const void *>(CS16) : CS32;
+  }
+
+  const coff_symbol_generic *getGeneric() const {
+    if (CS16)
+      return reinterpret_cast<const coff_symbol_generic *>(CS16);
+    return reinterpret_cast<const coff_symbol_generic *>(CS32);
+  }
+
+  friend bool operator<(COFFSymbolRef A, COFFSymbolRef B) {
+    return A.getRawPtr() < B.getRawPtr();
+  }
+
+  bool isBigObj() const {
+    if (CS16)
+      return false;
+    if (CS32)
+      return true;
+    llvm_unreachable("COFFSymbolRef points to nothing!");
+  }
+
+  const char *getShortName() const {
+    return CS16 ? CS16->Name.ShortName : CS32->Name.ShortName;
+  }
+
+  const StringTableOffset &getStringTableOffset() const {
+    assert(isSet() && "COFFSymbolRef points to nothing!");
+    return CS16 ? CS16->Name.Offset : CS32->Name.Offset;
+  }
+
+  uint32_t getValue() const {
+    assert(isSet() && "COFFSymbolRef points to nothing!");
+    return CS16 ? CS16->Value : CS32->Value;
+  }
+
+  int32_t getSectionNumber() const {
+    assert(isSet() && "COFFSymbolRef points to nothing!");
+    if (CS16) {
+      // Reserved sections are returned as negative numbers.
+      if (CS16->SectionNumber <= COFF::MaxNumberOfSections16)
+        return CS16->SectionNumber;
+      return static_cast<int16_t>(CS16->SectionNumber);
+    }
+    return static_cast<int32_t>(CS32->SectionNumber);
+  }
+
+  uint16_t getType() const {
+    assert(isSet() && "COFFSymbolRef points to nothing!");
+    return CS16 ? CS16->Type : CS32->Type;
+  }
+
+  uint8_t getStorageClass() const {
+    assert(isSet() && "COFFSymbolRef points to nothing!");
+    return CS16 ? CS16->StorageClass : CS32->StorageClass;
+  }
+
+  uint8_t getNumberOfAuxSymbols() const {
+    assert(isSet() && "COFFSymbolRef points to nothing!");
+    return CS16 ? CS16->NumberOfAuxSymbols : CS32->NumberOfAuxSymbols;
+  }
+
+  uint8_t getBaseType() const { return getType() & 0x0F; }
+
+  uint8_t getComplexType() const {
+    return (getType() & 0xF0) >> COFF::SCT_COMPLEX_TYPE_SHIFT;
+  }
+
+  template <typename T> const T *getAux() const {
+    return CS16 ? reinterpret_cast<const T *>(CS16 + 1)
+                : reinterpret_cast<const T *>(CS32 + 1);
+  }
+
+  const coff_aux_section_definition *getSectionDefinition() const {
+    if (!getNumberOfAuxSymbols() ||
+        getStorageClass() != COFF::IMAGE_SYM_CLASS_STATIC)
+      return nullptr;
+    return getAux<coff_aux_section_definition>();
+  }
+
+  const coff_aux_weak_external *getWeakExternal() const {
+    if (!getNumberOfAuxSymbols() ||
+        getStorageClass() != COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL)
+      return nullptr;
+    return getAux<coff_aux_weak_external>();
+  }
+
+  bool isAbsolute() const {
+    return getSectionNumber() == -1;
+  }
+
+  bool isExternal() const {
+    return getStorageClass() == COFF::IMAGE_SYM_CLASS_EXTERNAL;
+  }
+
+  bool isCommon() const {
+    return isExternal() && getSectionNumber() == COFF::IMAGE_SYM_UNDEFINED &&
+           getValue() != 0;
+  }
+
+  bool isUndefined() const {
+    return isExternal() && getSectionNumber() == COFF::IMAGE_SYM_UNDEFINED &&
+           getValue() == 0;
+  }
+
+  bool isWeakExternal() const {
+    return getStorageClass() == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL;
+  }
+
+  bool isFunctionDefinition() const {
+    return isExternal() && getBaseType() == COFF::IMAGE_SYM_TYPE_NULL &&
+           getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION &&
+           !COFF::isReservedSectionNumber(getSectionNumber());
+  }
+
+  bool isFunctionLineInfo() const {
+    return getStorageClass() == COFF::IMAGE_SYM_CLASS_FUNCTION;
+  }
+
+  bool isAnyUndefined() const {
+    return isUndefined() || isWeakExternal();
+  }
+
+  bool isFileRecord() const {
+    return getStorageClass() == COFF::IMAGE_SYM_CLASS_FILE;
+  }
+
+  bool isSection() const {
+    return getStorageClass() == COFF::IMAGE_SYM_CLASS_SECTION;
+  }
+
+  bool isSectionDefinition() const {
+    // C++/CLI creates external ABS symbols for non-const appdomain globals.
+    // These are also followed by an auxiliary section definition.
+    bool isAppdomainGlobal =
+        getStorageClass() == COFF::IMAGE_SYM_CLASS_EXTERNAL &&
+        getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE;
+    bool isOrdinarySection = getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC;
+    if (!getNumberOfAuxSymbols())
+      return false;
+    return isAppdomainGlobal || isOrdinarySection;
+  }
+
+  bool isCLRToken() const {
+    return getStorageClass() == COFF::IMAGE_SYM_CLASS_CLR_TOKEN;
+  }
+
+private:
+  bool isSet() const { return CS16 || CS32; }
+
+  const coff_symbol16 *CS16 = nullptr;
+  const coff_symbol32 *CS32 = nullptr;
+};
+
+struct coff_section {
+  char Name[COFF::NameSize];
+  support::ulittle32_t VirtualSize;
+  support::ulittle32_t VirtualAddress;
+  support::ulittle32_t SizeOfRawData;
+  support::ulittle32_t PointerToRawData;
+  support::ulittle32_t PointerToRelocations;
+  support::ulittle32_t PointerToLinenumbers;
+  support::ulittle16_t NumberOfRelocations;
+  support::ulittle16_t NumberOfLinenumbers;
+  support::ulittle32_t Characteristics;
+
+  // Returns true if the actual number of relocations is stored in
+  // VirtualAddress field of the first relocation table entry.
+  bool hasExtendedRelocations() const {
+    return (Characteristics & COFF::IMAGE_SCN_LNK_NRELOC_OVFL) &&
+           NumberOfRelocations == UINT16_MAX;
+  }
+
+  uint32_t getAlignment() const {
+    // The IMAGE_SCN_TYPE_NO_PAD bit is a legacy way of getting to
+    // IMAGE_SCN_ALIGN_1BYTES.
+    if (Characteristics & COFF::IMAGE_SCN_TYPE_NO_PAD)
+      return 1;
+
+    // Bit [20:24] contains section alignment. 0 means use a default alignment
+    // of 16.
+    uint32_t Shift = (Characteristics >> 20) & 0xF;
+    if (Shift > 0)
+      return 1U << (Shift - 1);
+    return 16;
+  }
+};
+
+struct coff_relocation {
+  support::ulittle32_t VirtualAddress;
+  support::ulittle32_t SymbolTableIndex;
+  support::ulittle16_t Type;
+};
+
+struct coff_aux_function_definition {
+  support::ulittle32_t TagIndex;
+  support::ulittle32_t TotalSize;
+  support::ulittle32_t PointerToLinenumber;
+  support::ulittle32_t PointerToNextFunction;
+  char Unused1[2];
+};
+
+static_assert(sizeof(coff_aux_function_definition) == 18,
+              "auxiliary entry must be 18 bytes");
+
+struct coff_aux_bf_and_ef_symbol {
+  char Unused1[4];
+  support::ulittle16_t Linenumber;
+  char Unused2[6];
+  support::ulittle32_t PointerToNextFunction;
+  char Unused3[2];
+};
+
+static_assert(sizeof(coff_aux_bf_and_ef_symbol) == 18,
+              "auxiliary entry must be 18 bytes");
+
+struct coff_aux_weak_external {
+  support::ulittle32_t TagIndex;
+  support::ulittle32_t Characteristics;
+  char Unused1[10];
+};
+
+static_assert(sizeof(coff_aux_weak_external) == 18,
+              "auxiliary entry must be 18 bytes");
+
+struct coff_aux_section_definition {
+  support::ulittle32_t Length;
+  support::ulittle16_t NumberOfRelocations;
+  support::ulittle16_t NumberOfLinenumbers;
+  support::ulittle32_t CheckSum;
+  support::ulittle16_t NumberLowPart;
+  uint8_t              Selection;
+  uint8_t              Unused;
+  support::ulittle16_t NumberHighPart;
+  int32_t getNumber(bool IsBigObj) const {
+    uint32_t Number = static_cast<uint32_t>(NumberLowPart);
+    if (IsBigObj)
+      Number |= static_cast<uint32_t>(NumberHighPart) << 16;
+    return static_cast<int32_t>(Number);
+  }
+};
+
+static_assert(sizeof(coff_aux_section_definition) == 18,
+              "auxiliary entry must be 18 bytes");
+
+struct coff_aux_clr_token {
+  uint8_t              AuxType;
+  uint8_t              Reserved;
+  support::ulittle32_t SymbolTableIndex;
+  char                 MBZ[12];
+};
+
+static_assert(sizeof(coff_aux_clr_token) == 18,
+              "auxiliary entry must be 18 bytes");
+
+struct coff_import_header {
+  support::ulittle16_t Sig1;
+  support::ulittle16_t Sig2;
+  support::ulittle16_t Version;
+  support::ulittle16_t Machine;
+  support::ulittle32_t TimeDateStamp;
+  support::ulittle32_t SizeOfData;
+  support::ulittle16_t OrdinalHint;
+  support::ulittle16_t TypeInfo;
+
+  int getType() const { return TypeInfo & 0x3; }
+  int getNameType() const { return (TypeInfo >> 2) & 0x7; }
+};
+
+struct coff_import_directory_table_entry {
+  support::ulittle32_t ImportLookupTableRVA;
+  support::ulittle32_t TimeDateStamp;
+  support::ulittle32_t ForwarderChain;
+  support::ulittle32_t NameRVA;
+  support::ulittle32_t ImportAddressTableRVA;
+
+  bool isNull() const {
+    return ImportLookupTableRVA == 0 && TimeDateStamp == 0 &&
+           ForwarderChain == 0 && NameRVA == 0 && ImportAddressTableRVA == 0;
+  }
+};
+
+template <typename IntTy>
+struct coff_tls_directory {
+  IntTy StartAddressOfRawData;
+  IntTy EndAddressOfRawData;
+  IntTy AddressOfIndex;
+  IntTy AddressOfCallBacks;
+  support::ulittle32_t SizeOfZeroFill;
+  support::ulittle32_t Characteristics;
+
+  uint32_t getAlignment() const {
+    // Bit [20:24] contains section alignment.
+    uint32_t Shift = (Characteristics & 0x00F00000) >> 20;
+    if (Shift > 0)
+      return 1U << (Shift - 1);
+    return 0;
+  }
+};
+
+using coff_tls_directory32 = coff_tls_directory<support::little32_t>;
+using coff_tls_directory64 = coff_tls_directory<support::little64_t>;
+
+/// Bits in control flow guard flags as we understand them.
+enum class coff_guard_flags : uint32_t {
+  CFInstrumented = 0x00000100,
+  HasFidTable = 0x00000400,
+  ProtectDelayLoadIAT = 0x00001000,
+  DelayLoadIATSection = 0x00002000, // Delay load in separate section
+  HasLongJmpTable = 0x00010000,
+  FidTableHasFlags = 0x10000000, // Indicates that fid tables are 5 bytes
+};
+
+enum class frame_type : uint16_t { Fpo = 0, Trap = 1, Tss = 2, NonFpo = 3 };
+
+struct coff_load_config_code_integrity {
+  support::ulittle16_t Flags;
+  support::ulittle16_t Catalog;
+  support::ulittle32_t CatalogOffset;
+  support::ulittle32_t Reserved;
+};
+
+/// 32-bit load config (IMAGE_LOAD_CONFIG_DIRECTORY32)
+struct coff_load_configuration32 {
+  support::ulittle32_t Size;
+  support::ulittle32_t TimeDateStamp;
+  support::ulittle16_t MajorVersion;
+  support::ulittle16_t MinorVersion;
+  support::ulittle32_t GlobalFlagsClear;
+  support::ulittle32_t GlobalFlagsSet;
+  support::ulittle32_t CriticalSectionDefaultTimeout;
+  support::ulittle32_t DeCommitFreeBlockThreshold;
+  support::ulittle32_t DeCommitTotalFreeThreshold;
+  support::ulittle32_t LockPrefixTable;
+  support::ulittle32_t MaximumAllocationSize;
+  support::ulittle32_t VirtualMemoryThreshold;
+  support::ulittle32_t ProcessAffinityMask;
+  support::ulittle32_t ProcessHeapFlags;
+  support::ulittle16_t CSDVersion;
+  support::ulittle16_t DependentLoadFlags;
+  support::ulittle32_t EditList;
+  support::ulittle32_t SecurityCookie;
+  support::ulittle32_t SEHandlerTable;
+  support::ulittle32_t SEHandlerCount;
+
+  // Added in MSVC 2015 for /guard:cf.
+  support::ulittle32_t GuardCFCheckFunction;
+  support::ulittle32_t GuardCFCheckDispatch;
+  support::ulittle32_t GuardCFFunctionTable;
+  support::ulittle32_t GuardCFFunctionCount;
+  support::ulittle32_t GuardFlags; // coff_guard_flags
+
+  // Added in MSVC 2017
+  coff_load_config_code_integrity CodeIntegrity;
+  support::ulittle32_t GuardAddressTakenIatEntryTable;
+  support::ulittle32_t GuardAddressTakenIatEntryCount;
+  support::ulittle32_t GuardLongJumpTargetTable;
+  support::ulittle32_t GuardLongJumpTargetCount;
+  support::ulittle32_t DynamicValueRelocTable;
+  support::ulittle32_t CHPEMetadataPointer;
+  support::ulittle32_t GuardRFFailureRoutine;
+  support::ulittle32_t GuardRFFailureRoutineFunctionPointer;
+  support::ulittle32_t DynamicValueRelocTableOffset;
+  support::ulittle16_t DynamicValueRelocTableSection;
+  support::ulittle16_t Reserved2;
+  support::ulittle32_t GuardRFVerifyStackPointerFunctionPointer;
+  support::ulittle32_t HotPatchTableOffset;
+};
+
+/// 64-bit load config (IMAGE_LOAD_CONFIG_DIRECTORY64)
+struct coff_load_configuration64 {
+  support::ulittle32_t Size;
+  support::ulittle32_t TimeDateStamp;
+  support::ulittle16_t MajorVersion;
+  support::ulittle16_t MinorVersion;
+  support::ulittle32_t GlobalFlagsClear;
+  support::ulittle32_t GlobalFlagsSet;
+  support::ulittle32_t CriticalSectionDefaultTimeout;
+  support::ulittle64_t DeCommitFreeBlockThreshold;
+  support::ulittle64_t DeCommitTotalFreeThreshold;
+  support::ulittle64_t LockPrefixTable;
+  support::ulittle64_t MaximumAllocationSize;
+  support::ulittle64_t VirtualMemoryThreshold;
+  support::ulittle64_t ProcessAffinityMask;
+  support::ulittle32_t ProcessHeapFlags;
+  support::ulittle16_t CSDVersion;
+  support::ulittle16_t DependentLoadFlags;
+  support::ulittle64_t EditList;
+  support::ulittle64_t SecurityCookie;
+  support::ulittle64_t SEHandlerTable;
+  support::ulittle64_t SEHandlerCount;
+
+  // Added in MSVC 2015 for /guard:cf.
+  support::ulittle64_t GuardCFCheckFunction;
+  support::ulittle64_t GuardCFCheckDispatch;
+  support::ulittle64_t GuardCFFunctionTable;
+  support::ulittle64_t GuardCFFunctionCount;
+  support::ulittle32_t GuardFlags;
+
+  // Added in MSVC 2017
+  coff_load_config_code_integrity CodeIntegrity;
+  support::ulittle64_t GuardAddressTakenIatEntryTable;
+  support::ulittle64_t GuardAddressTakenIatEntryCount;
+  support::ulittle64_t GuardLongJumpTargetTable;
+  support::ulittle64_t GuardLongJumpTargetCount;
+  support::ulittle64_t DynamicValueRelocTable;
+  support::ulittle64_t CHPEMetadataPointer;
+  support::ulittle64_t GuardRFFailureRoutine;
+  support::ulittle64_t GuardRFFailureRoutineFunctionPointer;
+  support::ulittle32_t DynamicValueRelocTableOffset;
+  support::ulittle16_t DynamicValueRelocTableSection;
+  support::ulittle16_t Reserved2;
+  support::ulittle64_t GuardRFVerifyStackPointerFunctionPointer;
+  support::ulittle32_t HotPatchTableOffset;
+};
+
+struct coff_runtime_function_x64 {
+  support::ulittle32_t BeginAddress;
+  support::ulittle32_t EndAddress;
+  support::ulittle32_t UnwindInformation;
+};
+
+struct coff_base_reloc_block_header {
+  support::ulittle32_t PageRVA;
+  support::ulittle32_t BlockSize;
+};
+
+struct coff_base_reloc_block_entry {
+  support::ulittle16_t Data;
+
+  int getType() const { return Data >> 12; }
+  int getOffset() const { return Data & ((1 << 12) - 1); }
+};
+
+struct coff_resource_dir_entry {
+  union {
+    support::ulittle32_t NameOffset;
+    support::ulittle32_t ID;
+    uint32_t getNameOffset() const {
+      return maskTrailingOnes<uint32_t>(31) & NameOffset;
+    }
+    // Even though the PE/COFF spec doesn't mention this, the high bit of a name
+    // offset is set.
+    void setNameOffset(uint32_t Offset) { NameOffset = Offset | (1 << 31); }
+  } Identifier;
+  union {
+    support::ulittle32_t DataEntryOffset;
+    support::ulittle32_t SubdirOffset;
+
+    bool isSubDir() const { return SubdirOffset >> 31; }
+    uint32_t value() const {
+      return maskTrailingOnes<uint32_t>(31) & SubdirOffset;
+    }
+
+  } Offset;
+};
+
+struct coff_resource_data_entry {
+  support::ulittle32_t DataRVA;
+  support::ulittle32_t DataSize;
+  support::ulittle32_t Codepage;
+  support::ulittle32_t Reserved;
+};
+
+struct coff_resource_dir_table {
+  support::ulittle32_t Characteristics;
+  support::ulittle32_t TimeDateStamp;
+  support::ulittle16_t MajorVersion;
+  support::ulittle16_t MinorVersion;
+  support::ulittle16_t NumberOfNameEntries;
+  support::ulittle16_t NumberOfIDEntries;
+};
+
+struct debug_h_header {
+  support::ulittle32_t Magic;
+  support::ulittle16_t Version;
+  support::ulittle16_t HashAlgorithm;
+};
+
+class COFFObjectFile : public ObjectFile {
+private:
+  friend class ImportDirectoryEntryRef;
+  friend class ExportDirectoryEntryRef;
+  const coff_file_header *COFFHeader;
+  const coff_bigobj_file_header *COFFBigObjHeader;
+  const pe32_header *PE32Header;
+  const pe32plus_header *PE32PlusHeader;
+  const data_directory *DataDirectory;
+  const coff_section *SectionTable;
+  const coff_symbol16 *SymbolTable16;
+  const coff_symbol32 *SymbolTable32;
+  const char *StringTable;
+  uint32_t StringTableSize;
+  const coff_import_directory_table_entry *ImportDirectory;
+  const delay_import_directory_table_entry *DelayImportDirectory;
+  uint32_t NumberOfDelayImportDirectory;
+  const export_directory_table_entry *ExportDirectory;
+  const coff_base_reloc_block_header *BaseRelocHeader;
+  const coff_base_reloc_block_header *BaseRelocEnd;
+  const debug_directory *DebugDirectoryBegin;
+  const debug_directory *DebugDirectoryEnd;
+  // Either coff_load_configuration32 or coff_load_configuration64.
+  const void *LoadConfig = nullptr;
+
+  std::error_code getString(uint32_t offset, StringRef &Res) const;
+
+  template <typename coff_symbol_type>
+  const coff_symbol_type *toSymb(DataRefImpl Symb) const;
+  const coff_section *toSec(DataRefImpl Sec) const;
+  const coff_relocation *toRel(DataRefImpl Rel) const;
+
+  std::error_code initSymbolTablePtr();
+  std::error_code initImportTablePtr();
+  std::error_code initDelayImportTablePtr();
+  std::error_code initExportTablePtr();
+  std::error_code initBaseRelocPtr();
+  std::error_code initDebugDirectoryPtr();
+  std::error_code initLoadConfigPtr();
+
+public:
+  uintptr_t getSymbolTable() const {
+    if (SymbolTable16)
+      return reinterpret_cast<uintptr_t>(SymbolTable16);
+    if (SymbolTable32)
+      return reinterpret_cast<uintptr_t>(SymbolTable32);
+    return uintptr_t(0);
+  }
+
+  uint16_t getMachine() const {
+    if (COFFHeader)
+      return COFFHeader->Machine;
+    if (COFFBigObjHeader)
+      return COFFBigObjHeader->Machine;
+    llvm_unreachable("no COFF header!");
+  }
+
+  uint16_t getSizeOfOptionalHeader() const {
+    if (COFFHeader)
+      return COFFHeader->isImportLibrary() ? 0
+                                           : COFFHeader->SizeOfOptionalHeader;
+    // bigobj doesn't have this field.
+    if (COFFBigObjHeader)
+      return 0;
+    llvm_unreachable("no COFF header!");
+  }
+
+  uint16_t getCharacteristics() const {
+    if (COFFHeader)
+      return COFFHeader->isImportLibrary() ? 0 : COFFHeader->Characteristics;
+    // bigobj doesn't have characteristics to speak of,
+    // editbin will silently lie to you if you attempt to set any.
+    if (COFFBigObjHeader)
+      return 0;
+    llvm_unreachable("no COFF header!");
+  }
+
+  uint32_t getTimeDateStamp() const {
+    if (COFFHeader)
+      return COFFHeader->TimeDateStamp;
+    if (COFFBigObjHeader)
+      return COFFBigObjHeader->TimeDateStamp;
+    llvm_unreachable("no COFF header!");
+  }
+
+  uint32_t getNumberOfSections() const {
+    if (COFFHeader)
+      return COFFHeader->isImportLibrary() ? 0 : COFFHeader->NumberOfSections;
+    if (COFFBigObjHeader)
+      return COFFBigObjHeader->NumberOfSections;
+    llvm_unreachable("no COFF header!");
+  }
+
+  uint32_t getPointerToSymbolTable() const {
+    if (COFFHeader)
+      return COFFHeader->isImportLibrary() ? 0
+                                           : COFFHeader->PointerToSymbolTable;
+    if (COFFBigObjHeader)
+      return COFFBigObjHeader->PointerToSymbolTable;
+    llvm_unreachable("no COFF header!");
+  }
+
+  uint32_t getRawNumberOfSymbols() const {
+    if (COFFHeader)
+      return COFFHeader->isImportLibrary() ? 0 : COFFHeader->NumberOfSymbols;
+    if (COFFBigObjHeader)
+      return COFFBigObjHeader->NumberOfSymbols;
+    llvm_unreachable("no COFF header!");
+  }
+
+  uint32_t getNumberOfSymbols() const {
+    if (!SymbolTable16 && !SymbolTable32)
+      return 0;
+    return getRawNumberOfSymbols();
+  }
+
+  const coff_load_configuration32 *getLoadConfig32() const {
+    assert(!is64());
+    return reinterpret_cast<const coff_load_configuration32 *>(LoadConfig);
+  }
+
+  const coff_load_configuration64 *getLoadConfig64() const {
+    assert(is64());
+    return reinterpret_cast<const coff_load_configuration64 *>(LoadConfig);
+  }
+  StringRef getRelocationTypeName(uint16_t Type) const;
+
+protected:
+  void moveSymbolNext(DataRefImpl &Symb) const override;
+  Expected<StringRef> getSymbolName(DataRefImpl Symb) const override;
+  Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override;
+  uint32_t getSymbolAlignment(DataRefImpl Symb) const override;
+  uint64_t getSymbolValueImpl(DataRefImpl Symb) const override;
+  uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override;
+  uint32_t getSymbolFlags(DataRefImpl Symb) const override;
+  Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override;
+  Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override;
+  void moveSectionNext(DataRefImpl &Sec) const override;
+  Expected<StringRef> getSectionName(DataRefImpl Sec) const override;
+  uint64_t getSectionAddress(DataRefImpl Sec) const override;
+  uint64_t getSectionIndex(DataRefImpl Sec) const override;
+  uint64_t getSectionSize(DataRefImpl Sec) const override;
+  Expected<ArrayRef<uint8_t>>
+  getSectionContents(DataRefImpl Sec) const override;
+  uint64_t getSectionAlignment(DataRefImpl Sec) const override;
+  bool isSectionCompressed(DataRefImpl Sec) const override;
+  bool isSectionText(DataRefImpl Sec) const override;
+  bool isSectionData(DataRefImpl Sec) const override;
+  bool isSectionBSS(DataRefImpl Sec) const override;
+  bool isSectionVirtual(DataRefImpl Sec) const override;
+  relocation_iterator section_rel_begin(DataRefImpl Sec) const override;
+  relocation_iterator section_rel_end(DataRefImpl Sec) const override;
+
+  void moveRelocationNext(DataRefImpl &Rel) const override;
+  uint64_t getRelocationOffset(DataRefImpl Rel) const override;
+  symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override;
+  uint64_t getRelocationType(DataRefImpl Rel) const override;
+  void getRelocationTypeName(DataRefImpl Rel,
+                             SmallVectorImpl<char> &Result) const override;
+
+public:
+  COFFObjectFile(MemoryBufferRef Object, std::error_code &EC);
+
+  basic_symbol_iterator symbol_begin() const override;
+  basic_symbol_iterator symbol_end() const override;
+  section_iterator section_begin() const override;
+  section_iterator section_end() const override;
+
+  const coff_section *getCOFFSection(const SectionRef &Section) const;
+  COFFSymbolRef getCOFFSymbol(const DataRefImpl &Ref) const;
+  COFFSymbolRef getCOFFSymbol(const SymbolRef &Symbol) const;
+  const coff_relocation *getCOFFRelocation(const RelocationRef &Reloc) const;
+  unsigned getSectionID(SectionRef Sec) const;
+  unsigned getSymbolSectionID(SymbolRef Sym) const;
+
+  uint8_t getBytesInAddress() const override;
+  StringRef getFileFormatName() const override;
+  Triple::ArchType getArch() const override;
+  Expected<uint64_t> getStartAddress() const override;
+  SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); }
+
+  import_directory_iterator import_directory_begin() const;
+  import_directory_iterator import_directory_end() const;
+  delay_import_directory_iterator delay_import_directory_begin() const;
+  delay_import_directory_iterator delay_import_directory_end() const;
+  export_directory_iterator export_directory_begin() const;
+  export_directory_iterator export_directory_end() const;
+  base_reloc_iterator base_reloc_begin() const;
+  base_reloc_iterator base_reloc_end() const;
+  const debug_directory *debug_directory_begin() const {
+    return DebugDirectoryBegin;
+  }
+  const debug_directory *debug_directory_end() const {
+    return DebugDirectoryEnd;
+  }
+
+  iterator_range<import_directory_iterator> import_directories() const;
+  iterator_range<delay_import_directory_iterator>
+      delay_import_directories() const;
+  iterator_range<export_directory_iterator> export_directories() const;
+  iterator_range<base_reloc_iterator> base_relocs() const;
+  iterator_range<const debug_directory *> debug_directories() const {
+    return make_range(debug_directory_begin(), debug_directory_end());
+  }
+
+  const dos_header *getDOSHeader() const {
+    if (!PE32Header && !PE32PlusHeader)
+      return nullptr;
+    return reinterpret_cast<const dos_header *>(base());
+  }
+
+  const coff_file_header *getCOFFHeader() const { return COFFHeader; }
+  const coff_bigobj_file_header *getCOFFBigObjHeader() const {
+    return COFFBigObjHeader;
+  }
+  const pe32_header *getPE32Header() const { return PE32Header; }
+  const pe32plus_header *getPE32PlusHeader() const { return PE32PlusHeader; }
+
+  std::error_code getDataDirectory(uint32_t index,
+                                   const data_directory *&Res) const;
+  std::error_code getSection(int32_t index, const coff_section *&Res) const;
+  std::error_code getSection(StringRef SectionName,
+                             const coff_section *&Res) const;
+
+  template <typename coff_symbol_type>
+  std::error_code getSymbol(uint32_t Index,
+                            const coff_symbol_type *&Res) const {
+    if (Index >= getNumberOfSymbols())
+      return object_error::parse_failed;
+
+    Res = reinterpret_cast<coff_symbol_type *>(getSymbolTable()) + Index;
+    return std::error_code();
+  }
+  Expected<COFFSymbolRef> getSymbol(uint32_t index) const {
+    if (SymbolTable16) {
+      const coff_symbol16 *Symb = nullptr;
+      if (std::error_code EC = getSymbol(index, Symb))
+        return errorCodeToError(EC);
+      return COFFSymbolRef(Symb);
+    }
+    if (SymbolTable32) {
+      const coff_symbol32 *Symb = nullptr;
+      if (std::error_code EC = getSymbol(index, Symb))
+        return errorCodeToError(EC);
+      return COFFSymbolRef(Symb);
+    }
+    return errorCodeToError(object_error::parse_failed);
+  }
+
+  template <typename T>
+  std::error_code getAuxSymbol(uint32_t index, const T *&Res) const {
+    Expected<COFFSymbolRef> S = getSymbol(index);
+    if (Error E = S.takeError())
+      return errorToErrorCode(std::move(E));
+    Res = reinterpret_cast<const T *>(S->getRawPtr());
+    return std::error_code();
+  }
+
+  std::error_code getSymbolName(COFFSymbolRef Symbol, StringRef &Res) const;
+  std::error_code getSymbolName(const coff_symbol_generic *Symbol,
+                                StringRef &Res) const;
+
+  ArrayRef<uint8_t> getSymbolAuxData(COFFSymbolRef Symbol) const;
+
+  uint32_t getSymbolIndex(COFFSymbolRef Symbol) const;
+
+  size_t getSymbolTableEntrySize() const {
+    if (COFFHeader)
+      return sizeof(coff_symbol16);
+    if (COFFBigObjHeader)
+      return sizeof(coff_symbol32);
+    llvm_unreachable("null symbol table pointer!");
+  }
+
+  ArrayRef<coff_relocation> getRelocations(const coff_section *Sec) const;
+
+  Expected<StringRef> getSectionName(const coff_section *Sec) const;
+  uint64_t getSectionSize(const coff_section *Sec) const;
+  Error getSectionContents(const coff_section *Sec,
+                           ArrayRef<uint8_t> &Res) const;
+
+  uint64_t getImageBase() const;
+  std::error_code getVaPtr(uint64_t VA, uintptr_t &Res) const;
+  std::error_code getRvaPtr(uint32_t Rva, uintptr_t &Res) const;
+
+  /// Given an RVA base and size, returns a valid array of bytes or an error
+  /// code if the RVA and size is not contained completely within a valid
+  /// section.
+  std::error_code getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
+                                       ArrayRef<uint8_t> &Contents) const;
+
+  std::error_code getHintName(uint32_t Rva, uint16_t &Hint,
+                              StringRef &Name) const;
+
+  /// Get PDB information out of a codeview debug directory entry.
+  std::error_code getDebugPDBInfo(const debug_directory *DebugDir,
+                                  const codeview::DebugInfo *&Info,
+                                  StringRef &PDBFileName) const;
+
+  /// Get PDB information from an executable. If the information is not present,
+  /// Info will be set to nullptr and PDBFileName will be empty. An error is
+  /// returned only on corrupt object files. Convenience accessor that can be
+  /// used if the debug directory is not already handy.
+  std::error_code getDebugPDBInfo(const codeview::DebugInfo *&Info,
+                                  StringRef &PDBFileName) const;
+
+  bool isRelocatableObject() const override;
+  bool is64() const { return PE32PlusHeader; }
+
+  StringRef mapDebugSectionName(StringRef Name) const override;
+
+  static bool classof(const Binary *v) { return v->isCOFF(); }
+};
+
+// The iterator for the import directory table.
+class ImportDirectoryEntryRef {
+public:
+  ImportDirectoryEntryRef() = default;
+  ImportDirectoryEntryRef(const coff_import_directory_table_entry *Table,
+                          uint32_t I, const COFFObjectFile *Owner)
+      : ImportTable(Table), Index(I), OwningObject(Owner) {}
+
+  bool operator==(const ImportDirectoryEntryRef &Other) const;
+  void moveNext();
+
+  imported_symbol_iterator imported_symbol_begin() const;
+  imported_symbol_iterator imported_symbol_end() const;
+  iterator_range<imported_symbol_iterator> imported_symbols() const;
+
+  imported_symbol_iterator lookup_table_begin() const;
+  imported_symbol_iterator lookup_table_end() const;
+  iterator_range<imported_symbol_iterator> lookup_table_symbols() const;
+
+  std::error_code getName(StringRef &Result) const;
+  std::error_code getImportLookupTableRVA(uint32_t &Result) const;
+  std::error_code getImportAddressTableRVA(uint32_t &Result) const;
+
+  std::error_code
+  getImportTableEntry(const coff_import_directory_table_entry *&Result) const;
+
+private:
+  const coff_import_directory_table_entry *ImportTable;
+  uint32_t Index;
+  const COFFObjectFile *OwningObject = nullptr;
+};
+
+class DelayImportDirectoryEntryRef {
+public:
+  DelayImportDirectoryEntryRef() = default;
+  DelayImportDirectoryEntryRef(const delay_import_directory_table_entry *T,
+                               uint32_t I, const COFFObjectFile *Owner)
+      : Table(T), Index(I), OwningObject(Owner) {}
+
+  bool operator==(const DelayImportDirectoryEntryRef &Other) const;
+  void moveNext();
+
+  imported_symbol_iterator imported_symbol_begin() const;
+  imported_symbol_iterator imported_symbol_end() const;
+  iterator_range<imported_symbol_iterator> imported_symbols() const;
+
+  std::error_code getName(StringRef &Result) const;
+  std::error_code getDelayImportTable(
+      const delay_import_directory_table_entry *&Result) const;
+  std::error_code getImportAddress(int AddrIndex, uint64_t &Result) const;
+
+private:
+  const delay_import_directory_table_entry *Table;
+  uint32_t Index;
+  const COFFObjectFile *OwningObject = nullptr;
+};
+
+// The iterator for the export directory table entry.
+class ExportDirectoryEntryRef {
+public:
+  ExportDirectoryEntryRef() = default;
+  ExportDirectoryEntryRef(const export_directory_table_entry *Table, uint32_t I,
+                          const COFFObjectFile *Owner)
+      : ExportTable(Table), Index(I), OwningObject(Owner) {}
+
+  bool operator==(const ExportDirectoryEntryRef &Other) const;
+  void moveNext();
+
+  std::error_code getDllName(StringRef &Result) const;
+  std::error_code getOrdinalBase(uint32_t &Result) const;
+  std::error_code getOrdinal(uint32_t &Result) const;
+  std::error_code getExportRVA(uint32_t &Result) const;
+  std::error_code getSymbolName(StringRef &Result) const;
+
+  std::error_code isForwarder(bool &Result) const;
+  std::error_code getForwardTo(StringRef &Result) const;
+
+private:
+  const export_directory_table_entry *ExportTable;
+  uint32_t Index;
+  const COFFObjectFile *OwningObject = nullptr;
+};
+
+class ImportedSymbolRef {
+public:
+  ImportedSymbolRef() = default;
+  ImportedSymbolRef(const import_lookup_table_entry32 *Entry, uint32_t I,
+                    const COFFObjectFile *Owner)
+      : Entry32(Entry), Entry64(nullptr), Index(I), OwningObject(Owner) {}
+  ImportedSymbolRef(const import_lookup_table_entry64 *Entry, uint32_t I,
+                    const COFFObjectFile *Owner)
+      : Entry32(nullptr), Entry64(Entry), Index(I), OwningObject(Owner) {}
+
+  bool operator==(const ImportedSymbolRef &Other) const;
+  void moveNext();
+
+  std::error_code getSymbolName(StringRef &Result) const;
+  std::error_code isOrdinal(bool &Result) const;
+  std::error_code getOrdinal(uint16_t &Result) const;
+  std::error_code getHintNameRVA(uint32_t &Result) const;
+
+private:
+  const import_lookup_table_entry32 *Entry32;
+  const import_lookup_table_entry64 *Entry64;
+  uint32_t Index;
+  const COFFObjectFile *OwningObject = nullptr;
+};
+
+class BaseRelocRef {
+public:
+  BaseRelocRef() = default;
+  BaseRelocRef(const coff_base_reloc_block_header *Header,
+               const COFFObjectFile *Owner)
+      : Header(Header), Index(0) {}
+
+  bool operator==(const BaseRelocRef &Other) const;
+  void moveNext();
+
+  std::error_code getType(uint8_t &Type) const;
+  std::error_code getRVA(uint32_t &Result) const;
+
+private:
+  const coff_base_reloc_block_header *Header;
+  uint32_t Index;
+};
+
+class ResourceSectionRef {
+public:
+  ResourceSectionRef() = default;
+  explicit ResourceSectionRef(StringRef Ref) : BBS(Ref, support::little) {}
+
+  Error load(const COFFObjectFile *O);
+  Error load(const COFFObjectFile *O, const SectionRef &S);
+
+  Expected<ArrayRef<UTF16>>
+  getEntryNameString(const coff_resource_dir_entry &Entry);
+  Expected<const coff_resource_dir_table &>
+  getEntrySubDir(const coff_resource_dir_entry &Entry);
+  Expected<const coff_resource_data_entry &>
+  getEntryData(const coff_resource_dir_entry &Entry);
+  Expected<const coff_resource_dir_table &> getBaseTable();
+  Expected<const coff_resource_dir_entry &>
+  getTableEntry(const coff_resource_dir_table &Table, uint32_t Index);
+
+  Expected<StringRef> getContents(const coff_resource_data_entry &Entry);
+
+private:
+  BinaryByteStream BBS;
+
+  SectionRef Section;
+  const COFFObjectFile *Obj;
+
+  std::vector<const coff_relocation *> Relocs;
+
+  Expected<const coff_resource_dir_table &> getTableAtOffset(uint32_t Offset);
+  Expected<const coff_resource_dir_entry &>
+  getTableEntryAtOffset(uint32_t Offset);
+  Expected<const coff_resource_data_entry &>
+  getDataEntryAtOffset(uint32_t Offset);
+  Expected<ArrayRef<UTF16>> getDirStringAtOffset(uint32_t Offset);
+};
+
+// Corresponds to `_FPO_DATA` structure in the PE/COFF spec.
+struct FpoData {
+  support::ulittle32_t Offset; // ulOffStart: Offset 1st byte of function code
+  support::ulittle32_t Size;   // cbProcSize: # bytes in function
+  support::ulittle32_t NumLocals; // cdwLocals: # bytes in locals/4
+  support::ulittle16_t NumParams; // cdwParams: # bytes in params/4
+  support::ulittle16_t Attributes;
+
+  // cbProlog: # bytes in prolog
+  int getPrologSize() const { return Attributes & 0xF; }
+
+  // cbRegs: # regs saved
+  int getNumSavedRegs() const { return (Attributes >> 8) & 0x7; }
+
+  // fHasSEH: true if seh is func
+  bool hasSEH() const { return (Attributes >> 9) & 1; }
+
+  // fUseBP: true if EBP has been allocated
+  bool useBP() const { return (Attributes >> 10) & 1; }
+
+  // cbFrame: frame pointer
+  frame_type getFP() const { return static_cast<frame_type>(Attributes >> 14); }
+};
+
+} // end namespace object
+
+} // end namespace llvm
+
+#endif // LLVM_OBJECT_COFF_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Object/CVDebugRecord.h b/binaryen/third_party/llvm-project/include/llvm/Object/CVDebugRecord.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Object/CVDebugRecord.h
@@ -0,0 +1,54 @@
+//===- CVDebugRecord.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_CVDEBUGRECORD_H
+#define LLVM_OBJECT_CVDEBUGRECORD_H
+
+#include "llvm/Support/Endian.h"
+
+namespace llvm {
+namespace OMF {
+struct Signature {
+  enum ID : uint32_t {
+    PDB70 = 0x53445352, // RSDS
+    PDB20 = 0x3031424e, // NB10
+    CV50 = 0x3131424e,  // NB11
+    CV41 = 0x3930424e,  // NB09
+  };
+
+  support::ulittle32_t CVSignature;
+  support::ulittle32_t Offset;
+};
+}
+
+namespace codeview {
+struct PDB70DebugInfo {
+  support::ulittle32_t CVSignature;
+  uint8_t Signature[16];
+  support::ulittle32_t Age;
+  // char PDBFileName[];
+};
+
+struct PDB20DebugInfo {
+  support::ulittle32_t CVSignature;
+  support::ulittle32_t Offset;
+  support::ulittle32_t Signature;
+  support::ulittle32_t Age;
+  // char PDBFileName[];
+};
+
+union DebugInfo {
+  struct OMF::Signature Signature;
+  struct PDB20DebugInfo PDB20;
+  struct PDB70DebugInfo PDB70;
+};
+}
+}
+
+#endif
+
diff --git a/binaryen/third_party/llvm-project/include/llvm/Object/Decompressor.h b/binaryen/third_party/llvm-project/include/llvm/Object/Decompressor.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Object/Decompressor.h
@@ -0,0 +1,66 @@
+//===-- Decompressor.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===/
+
+#ifndef LLVM_OBJECT_DECOMPRESSOR_H
+#define LLVM_OBJECT_DECOMPRESSOR_H
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ObjectFile.h"
+
+namespace llvm {
+namespace object {
+
+/// Decompressor helps to handle decompression of compressed sections.
+class Decompressor {
+public:
+  /// Create decompressor object.
+  /// @param Name        Section name.
+  /// @param Data        Section content.
+  /// @param IsLE        Flag determines if Data is in little endian form.
+  /// @param Is64Bit     Flag determines if object is 64 bit.
+  static Expected<Decompressor> create(StringRef Name, StringRef Data,
+                                       bool IsLE, bool Is64Bit);
+
+  /// Resize the buffer and uncompress section data into it.
+  /// @param Out         Destination buffer.
+  template <class T> Error resizeAndDecompress(T &Out) {
+    Out.resize(DecompressedSize);
+    return decompress({Out.data(), (size_t)DecompressedSize});
+  }
+
+  /// Uncompress section data to raw buffer provided.
+  /// @param Buffer      Destination buffer.
+  Error decompress(MutableArrayRef<char> Buffer);
+
+  /// Return memory buffer size required for decompression.
+  uint64_t getDecompressedSize() { return DecompressedSize; }
+
+  /// Return true if section is compressed, including gnu-styled case.
+  static bool isCompressed(const object::SectionRef &Section);
+
+  /// Return true if section is a ELF compressed one.
+  static bool isCompressedELFSection(uint64_t Flags, StringRef Name);
+
+  /// Return true if section name matches gnu style compressed one.
+  static bool isGnuStyle(StringRef Name);
+
+private:
+  Decompressor(StringRef Data);
+
+  Error consumeCompressedGnuHeader();
+  Error consumeCompressedZLibHeader(bool Is64Bit, bool IsLittleEndian);
+
+  StringRef SectionData;
+  uint64_t DecompressedSize;
+};
+
+} // end namespace object
+} // end namespace llvm
+
+#endif // LLVM_OBJECT_DECOMPRESSOR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Object/ELF.h b/binaryen/third_party/llvm-project/include/llvm/Object/ELF.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Object/ELF.h
@@ -0,0 +1,723 @@
+//===- ELF.h - ELF object file implementation -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the ELFFile template class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_ELF_H
+#define LLVM_OBJECT_ELF_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <utility>
+
+namespace llvm {
+namespace object {
+
+StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type);
+uint32_t getELFRelativeRelocationType(uint32_t Machine);
+StringRef getELFSectionTypeName(uint32_t Machine, uint32_t Type);
+
+// Subclasses of ELFFile may need this for template instantiation
+inline std::pair<unsigned char, unsigned char>
+getElfArchType(StringRef Object) {
+  if (Object.size() < ELF::EI_NIDENT)
+    return std::make_pair((uint8_t)ELF::ELFCLASSNONE,
+                          (uint8_t)ELF::ELFDATANONE);
+  return std::make_pair((uint8_t)Object[ELF::EI_CLASS],
+                        (uint8_t)Object[ELF::EI_DATA]);
+}
+
+static inline Error createError(const Twine &Err) {
+  return make_error<StringError>(Err, object_error::parse_failed);
+}
+
+template <class ELFT> class ELFFile;
+
+template <class ELFT>
+std::string getSecIndexForError(const ELFFile<ELFT> *Obj,
+                                const typename ELFT::Shdr *Sec) {
+  auto TableOrErr = Obj->sections();
+  if (TableOrErr)
+    return "[index " + std::to_string(Sec - &TableOrErr->front()) + "]";
+  // To make this helper be more convenient for error reporting purposes we
+  // drop the error. But really it should never be triggered. Before this point,
+  // our code should have called 'sections()' and reported a proper error on
+  // failure.
+  llvm::consumeError(TableOrErr.takeError());
+  return "[unknown index]";
+}
+
+static inline Error defaultWarningHandler(const Twine &Msg) {
+  return createError(Msg);
+}
+
+template <class ELFT>
+class ELFFile {
+public:
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+  using uintX_t = typename ELFT::uint;
+  using Elf_Ehdr = typename ELFT::Ehdr;
+  using Elf_Shdr = typename ELFT::Shdr;
+  using Elf_Sym = typename ELFT::Sym;
+  using Elf_Dyn = typename ELFT::Dyn;
+  using Elf_Phdr = typename ELFT::Phdr;
+  using Elf_Rel = typename ELFT::Rel;
+  using Elf_Rela = typename ELFT::Rela;
+  using Elf_Relr = typename ELFT::Relr;
+  using Elf_Verdef = typename ELFT::Verdef;
+  using Elf_Verdaux = typename ELFT::Verdaux;
+  using Elf_Verneed = typename ELFT::Verneed;
+  using Elf_Vernaux = typename ELFT::Vernaux;
+  using Elf_Versym = typename ELFT::Versym;
+  using Elf_Hash = typename ELFT::Hash;
+  using Elf_GnuHash = typename ELFT::GnuHash;
+  using Elf_Nhdr = typename ELFT::Nhdr;
+  using Elf_Note = typename ELFT::Note;
+  using Elf_Note_Iterator = typename ELFT::NoteIterator;
+  using Elf_Dyn_Range = typename ELFT::DynRange;
+  using Elf_Shdr_Range = typename ELFT::ShdrRange;
+  using Elf_Sym_Range = typename ELFT::SymRange;
+  using Elf_Rel_Range = typename ELFT::RelRange;
+  using Elf_Rela_Range = typename ELFT::RelaRange;
+  using Elf_Relr_Range = typename ELFT::RelrRange;
+  using Elf_Phdr_Range = typename ELFT::PhdrRange;
+
+  // This is a callback that can be passed to a number of functions.
+  // It can be used to ignore non-critical errors (warnings), which is
+  // useful for dumpers, like llvm-readobj.
+  // It accepts a warning message string and returns a success
+  // when the warning should be ignored or an error otherwise.
+  using WarningHandler = llvm::function_ref<Error(const Twine &Msg)>;
+
+  const uint8_t *base() const { return Buf.bytes_begin(); }
+
+  size_t getBufSize() const { return Buf.size(); }
+
+private:
+  StringRef Buf;
+
+  ELFFile(StringRef Object);
+
+public:
+  const Elf_Ehdr *getHeader() const {
+    return reinterpret_cast<const Elf_Ehdr *>(base());
+  }
+
+  template <typename T>
+  Expected<const T *> getEntry(uint32_t Section, uint32_t Entry) const;
+  template <typename T>
+  Expected<const T *> getEntry(const Elf_Shdr *Section, uint32_t Entry) const;
+
+  Expected<StringRef>
+  getStringTable(const Elf_Shdr *Section,
+                 WarningHandler WarnHandler = &defaultWarningHandler) const;
+  Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section) const;
+  Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section,
+                                              Elf_Shdr_Range Sections) const;
+
+  Expected<ArrayRef<Elf_Word>> getSHNDXTable(const Elf_Shdr &Section) const;
+  Expected<ArrayRef<Elf_Word>> getSHNDXTable(const Elf_Shdr &Section,
+                                             Elf_Shdr_Range Sections) const;
+
+  StringRef getRelocationTypeName(uint32_t Type) const;
+  void getRelocationTypeName(uint32_t Type,
+                             SmallVectorImpl<char> &Result) const;
+  uint32_t getRelativeRelocationType() const;
+
+  std::string getDynamicTagAsString(unsigned Arch, uint64_t Type) const;
+  std::string getDynamicTagAsString(uint64_t Type) const;
+
+  /// Get the symbol for a given relocation.
+  Expected<const Elf_Sym *> getRelocationSymbol(const Elf_Rel *Rel,
+                                                const Elf_Shdr *SymTab) const;
+
+  static Expected<ELFFile> create(StringRef Object);
+
+  bool isLE() const {
+    return getHeader()->getDataEncoding() == ELF::ELFDATA2LSB;
+  }
+
+  bool isMipsELF64() const {
+    return getHeader()->e_machine == ELF::EM_MIPS &&
+           getHeader()->getFileClass() == ELF::ELFCLASS64;
+  }
+
+  bool isMips64EL() const { return isMipsELF64() && isLE(); }
+
+  Expected<Elf_Shdr_Range> sections() const;
+
+  Expected<Elf_Dyn_Range> dynamicEntries() const;
+
+  Expected<const uint8_t *> toMappedAddr(uint64_t VAddr) const;
+
+  Expected<Elf_Sym_Range> symbols(const Elf_Shdr *Sec) const {
+    if (!Sec)
+      return makeArrayRef<Elf_Sym>(nullptr, nullptr);
+    return getSectionContentsAsArray<Elf_Sym>(Sec);
+  }
+
+  Expected<Elf_Rela_Range> relas(const Elf_Shdr *Sec) const {
+    return getSectionContentsAsArray<Elf_Rela>(Sec);
+  }
+
+  Expected<Elf_Rel_Range> rels(const Elf_Shdr *Sec) const {
+    return getSectionContentsAsArray<Elf_Rel>(Sec);
+  }
+
+  Expected<Elf_Relr_Range> relrs(const Elf_Shdr *Sec) const {
+    return getSectionContentsAsArray<Elf_Relr>(Sec);
+  }
+
+  Expected<std::vector<Elf_Rela>> decode_relrs(Elf_Relr_Range relrs) const;
+
+  Expected<std::vector<Elf_Rela>> android_relas(const Elf_Shdr *Sec) const;
+
+  /// Iterate over program header table.
+  Expected<Elf_Phdr_Range> program_headers() const {
+    if (getHeader()->e_phnum && getHeader()->e_phentsize != sizeof(Elf_Phdr))
+      return createError("invalid e_phentsize: " +
+                         Twine(getHeader()->e_phentsize));
+    if (getHeader()->e_phoff +
+            (getHeader()->e_phnum * getHeader()->e_phentsize) >
+        getBufSize())
+      return createError("program headers are longer than binary of size " +
+                         Twine(getBufSize()) + ": e_phoff = 0x" +
+                         Twine::utohexstr(getHeader()->e_phoff) +
+                         ", e_phnum = " + Twine(getHeader()->e_phnum) +
+                         ", e_phentsize = " + Twine(getHeader()->e_phentsize));
+    auto *Begin =
+        reinterpret_cast<const Elf_Phdr *>(base() + getHeader()->e_phoff);
+    return makeArrayRef(Begin, Begin + getHeader()->e_phnum);
+  }
+
+  /// Get an iterator over notes in a program header.
+  ///
+  /// The program header must be of type \c PT_NOTE.
+  ///
+  /// \param Phdr the program header to iterate over.
+  /// \param Err [out] an error to support fallible iteration, which should
+  ///  be checked after iteration ends.
+  Elf_Note_Iterator notes_begin(const Elf_Phdr &Phdr, Error &Err) const {
+    assert(Phdr.p_type == ELF::PT_NOTE && "Phdr is not of type PT_NOTE");
+    ErrorAsOutParameter ErrAsOutParam(&Err);
+    if (Phdr.p_offset + Phdr.p_filesz > getBufSize()) {
+      Err = createError("PT_NOTE header has invalid offset (0x" +
+                        Twine::utohexstr(Phdr.p_offset) + ") or size (0x" +
+                        Twine::utohexstr(Phdr.p_filesz) + ")");
+      return Elf_Note_Iterator(Err);
+    }
+    return Elf_Note_Iterator(base() + Phdr.p_offset, Phdr.p_filesz, Err);
+  }
+
+  /// Get an iterator over notes in a section.
+  ///
+  /// The section must be of type \c SHT_NOTE.
+  ///
+  /// \param Shdr the section to iterate over.
+  /// \param Err [out] an error to support fallible iteration, which should
+  ///  be checked after iteration ends.
+  Elf_Note_Iterator notes_begin(const Elf_Shdr &Shdr, Error &Err) const {
+    assert(Shdr.sh_type == ELF::SHT_NOTE && "Shdr is not of type SHT_NOTE");
+    ErrorAsOutParameter ErrAsOutParam(&Err);
+    if (Shdr.sh_offset + Shdr.sh_size > getBufSize()) {
+      Err = createError("SHT_NOTE section " + getSecIndexForError(this, &Shdr) +
+                        " has invalid offset (0x" +
+                        Twine::utohexstr(Shdr.sh_offset) + ") or size (0x" +
+                        Twine::utohexstr(Shdr.sh_size) + ")");
+      return Elf_Note_Iterator(Err);
+    }
+    return Elf_Note_Iterator(base() + Shdr.sh_offset, Shdr.sh_size, Err);
+  }
+
+  /// Get the end iterator for notes.
+  Elf_Note_Iterator notes_end() const {
+    return Elf_Note_Iterator();
+  }
+
+  /// Get an iterator range over notes of a program header.
+  ///
+  /// The program header must be of type \c PT_NOTE.
+  ///
+  /// \param Phdr the program header to iterate over.
+  /// \param Err [out] an error to support fallible iteration, which should
+  ///  be checked after iteration ends.
+  iterator_range<Elf_Note_Iterator> notes(const Elf_Phdr &Phdr,
+                                          Error &Err) const {
+    return make_range(notes_begin(Phdr, Err), notes_end());
+  }
+
+  /// Get an iterator range over notes of a section.
+  ///
+  /// The section must be of type \c SHT_NOTE.
+  ///
+  /// \param Shdr the section to iterate over.
+  /// \param Err [out] an error to support fallible iteration, which should
+  ///  be checked after iteration ends.
+  iterator_range<Elf_Note_Iterator> notes(const Elf_Shdr &Shdr,
+                                          Error &Err) const {
+    return make_range(notes_begin(Shdr, Err), notes_end());
+  }
+
+  Expected<StringRef> getSectionStringTable(
+      Elf_Shdr_Range Sections,
+      WarningHandler WarnHandler = &defaultWarningHandler) const;
+  Expected<uint32_t> getSectionIndex(const Elf_Sym *Sym, Elf_Sym_Range Syms,
+                                     ArrayRef<Elf_Word> ShndxTable) const;
+  Expected<const Elf_Shdr *> getSection(const Elf_Sym *Sym,
+                                        const Elf_Shdr *SymTab,
+                                        ArrayRef<Elf_Word> ShndxTable) const;
+  Expected<const Elf_Shdr *> getSection(const Elf_Sym *Sym,
+                                        Elf_Sym_Range Symtab,
+                                        ArrayRef<Elf_Word> ShndxTable) const;
+  Expected<const Elf_Shdr *> getSection(uint32_t Index) const;
+
+  Expected<const Elf_Sym *> getSymbol(const Elf_Shdr *Sec,
+                                      uint32_t Index) const;
+
+  Expected<StringRef>
+  getSectionName(const Elf_Shdr *Section,
+                 WarningHandler WarnHandler = &defaultWarningHandler) const;
+  Expected<StringRef> getSectionName(const Elf_Shdr *Section,
+                                     StringRef DotShstrtab) const;
+  template <typename T>
+  Expected<ArrayRef<T>> getSectionContentsAsArray(const Elf_Shdr *Sec) const;
+  Expected<ArrayRef<uint8_t>> getSectionContents(const Elf_Shdr *Sec) const;
+};
+
+using ELF32LEFile = ELFFile<ELF32LE>;
+using ELF64LEFile = ELFFile<ELF64LE>;
+using ELF32BEFile = ELFFile<ELF32BE>;
+using ELF64BEFile = ELFFile<ELF64BE>;
+
+template <class ELFT>
+inline Expected<const typename ELFT::Shdr *>
+getSection(typename ELFT::ShdrRange Sections, uint32_t Index) {
+  if (Index >= Sections.size())
+    return createError("invalid section index: " + Twine(Index));
+  return &Sections[Index];
+}
+
+template <class ELFT>
+inline Expected<uint32_t>
+getExtendedSymbolTableIndex(const typename ELFT::Sym *Sym,
+                            const typename ELFT::Sym *FirstSym,
+                            ArrayRef<typename ELFT::Word> ShndxTable) {
+  assert(Sym->st_shndx == ELF::SHN_XINDEX);
+  unsigned Index = Sym - FirstSym;
+  if (Index >= ShndxTable.size())
+    return createError(
+        "extended symbol index (" + Twine(Index) +
+        ") is past the end of the SHT_SYMTAB_SHNDX section of size " +
+        Twine(ShndxTable.size()));
+
+  // The size of the table was checked in getSHNDXTable.
+  return ShndxTable[Index];
+}
+
+template <class ELFT>
+Expected<uint32_t>
+ELFFile<ELFT>::getSectionIndex(const Elf_Sym *Sym, Elf_Sym_Range Syms,
+                               ArrayRef<Elf_Word> ShndxTable) const {
+  uint32_t Index = Sym->st_shndx;
+  if (Index == ELF::SHN_XINDEX) {
+    auto ErrorOrIndex = getExtendedSymbolTableIndex<ELFT>(
+        Sym, Syms.begin(), ShndxTable);
+    if (!ErrorOrIndex)
+      return ErrorOrIndex.takeError();
+    return *ErrorOrIndex;
+  }
+  if (Index == ELF::SHN_UNDEF || Index >= ELF::SHN_LORESERVE)
+    return 0;
+  return Index;
+}
+
+template <class ELFT>
+Expected<const typename ELFT::Shdr *>
+ELFFile<ELFT>::getSection(const Elf_Sym *Sym, const Elf_Shdr *SymTab,
+                          ArrayRef<Elf_Word> ShndxTable) const {
+  auto SymsOrErr = symbols(SymTab);
+  if (!SymsOrErr)
+    return SymsOrErr.takeError();
+  return getSection(Sym, *SymsOrErr, ShndxTable);
+}
+
+template <class ELFT>
+Expected<const typename ELFT::Shdr *>
+ELFFile<ELFT>::getSection(const Elf_Sym *Sym, Elf_Sym_Range Symbols,
+                          ArrayRef<Elf_Word> ShndxTable) const {
+  auto IndexOrErr = getSectionIndex(Sym, Symbols, ShndxTable);
+  if (!IndexOrErr)
+    return IndexOrErr.takeError();
+  uint32_t Index = *IndexOrErr;
+  if (Index == 0)
+    return nullptr;
+  return getSection(Index);
+}
+
+template <class ELFT>
+Expected<const typename ELFT::Sym *>
+ELFFile<ELFT>::getSymbol(const Elf_Shdr *Sec, uint32_t Index) const {
+  auto SymsOrErr = symbols(Sec);
+  if (!SymsOrErr)
+    return SymsOrErr.takeError();
+
+  Elf_Sym_Range Symbols = *SymsOrErr;
+  if (Index >= Symbols.size())
+    return createError("unable to get symbol from section " +
+                       getSecIndexForError(this, Sec) +
+                       ": invalid symbol index (" + Twine(Index) + ")");
+  return &Symbols[Index];
+}
+
+template <class ELFT>
+template <typename T>
+Expected<ArrayRef<T>>
+ELFFile<ELFT>::getSectionContentsAsArray(const Elf_Shdr *Sec) const {
+  if (Sec->sh_entsize != sizeof(T) && sizeof(T) != 1)
+    return createError("section " + getSecIndexForError(this, Sec) +
+                       " has an invalid sh_entsize: " + Twine(Sec->sh_entsize));
+
+  uintX_t Offset = Sec->sh_offset;
+  uintX_t Size = Sec->sh_size;
+
+  if (Size % sizeof(T))
+    return createError("section " + getSecIndexForError(this, Sec) +
+                       " has an invalid sh_size (" + Twine(Size) +
+                       ") which is not a multiple of its sh_entsize (" +
+                       Twine(Sec->sh_entsize) + ")");
+  if ((std::numeric_limits<uintX_t>::max() - Offset < Size) ||
+      Offset + Size > Buf.size())
+    return createError("section " + getSecIndexForError(this, Sec) +
+                       " has a sh_offset (0x" + Twine::utohexstr(Offset) +
+                       ") + sh_size (0x" + Twine(Size) +
+                       ") that cannot be represented");
+
+  if (Offset % alignof(T))
+    // TODO: this error is untested.
+    return createError("unaligned data");
+
+  const T *Start = reinterpret_cast<const T *>(base() + Offset);
+  return makeArrayRef(Start, Size / sizeof(T));
+}
+
+template <class ELFT>
+Expected<ArrayRef<uint8_t>>
+ELFFile<ELFT>::getSectionContents(const Elf_Shdr *Sec) const {
+  return getSectionContentsAsArray<uint8_t>(Sec);
+}
+
+template <class ELFT>
+StringRef ELFFile<ELFT>::getRelocationTypeName(uint32_t Type) const {
+  return getELFRelocationTypeName(getHeader()->e_machine, Type);
+}
+
+template <class ELFT>
+void ELFFile<ELFT>::getRelocationTypeName(uint32_t Type,
+                                          SmallVectorImpl<char> &Result) const {
+  if (!isMipsELF64()) {
+    StringRef Name = getRelocationTypeName(Type);
+    Result.append(Name.begin(), Name.end());
+  } else {
+    // The Mips N64 ABI allows up to three operations to be specified per
+    // relocation record. Unfortunately there's no easy way to test for the
+    // presence of N64 ELFs as they have no special flag that identifies them
+    // as being N64. We can safely assume at the moment that all Mips
+    // ELFCLASS64 ELFs are N64. New Mips64 ABIs should provide enough
+    // information to disambiguate between old vs new ABIs.
+    uint8_t Type1 = (Type >> 0) & 0xFF;
+    uint8_t Type2 = (Type >> 8) & 0xFF;
+    uint8_t Type3 = (Type >> 16) & 0xFF;
+
+    // Concat all three relocation type names.
+    StringRef Name = getRelocationTypeName(Type1);
+    Result.append(Name.begin(), Name.end());
+
+    Name = getRelocationTypeName(Type2);
+    Result.append(1, '/');
+    Result.append(Name.begin(), Name.end());
+
+    Name = getRelocationTypeName(Type3);
+    Result.append(1, '/');
+    Result.append(Name.begin(), Name.end());
+  }
+}
+
+template <class ELFT>
+uint32_t ELFFile<ELFT>::getRelativeRelocationType() const {
+  return getELFRelativeRelocationType(getHeader()->e_machine);
+}
+
+template <class ELFT>
+Expected<const typename ELFT::Sym *>
+ELFFile<ELFT>::getRelocationSymbol(const Elf_Rel *Rel,
+                                   const Elf_Shdr *SymTab) const {
+  uint32_t Index = Rel->getSymbol(isMips64EL());
+  if (Index == 0)
+    return nullptr;
+  return getEntry<Elf_Sym>(SymTab, Index);
+}
+
+template <class ELFT>
+Expected<StringRef>
+ELFFile<ELFT>::getSectionStringTable(Elf_Shdr_Range Sections,
+                                     WarningHandler WarnHandler) const {
+  uint32_t Index = getHeader()->e_shstrndx;
+  if (Index == ELF::SHN_XINDEX)
+    Index = Sections[0].sh_link;
+
+  if (!Index) // no section string table.
+    return "";
+  if (Index >= Sections.size())
+    return createError("section header string table index " + Twine(Index) +
+                       " does not exist");
+  return getStringTable(&Sections[Index], WarnHandler);
+}
+
+template <class ELFT> ELFFile<ELFT>::ELFFile(StringRef Object) : Buf(Object) {}
+
+template <class ELFT>
+Expected<ELFFile<ELFT>> ELFFile<ELFT>::create(StringRef Object) {
+  if (sizeof(Elf_Ehdr) > Object.size())
+    return createError("invalid buffer: the size (" + Twine(Object.size()) +
+                       ") is smaller than an ELF header (" +
+                       Twine(sizeof(Elf_Ehdr)) + ")");
+  return ELFFile(Object);
+}
+
+template <class ELFT>
+Expected<typename ELFT::ShdrRange> ELFFile<ELFT>::sections() const {
+  const uintX_t SectionTableOffset = getHeader()->e_shoff;
+  if (SectionTableOffset == 0)
+    return ArrayRef<Elf_Shdr>();
+
+  if (getHeader()->e_shentsize != sizeof(Elf_Shdr))
+    return createError("invalid e_shentsize in ELF header: " +
+                       Twine(getHeader()->e_shentsize));
+
+  const uint64_t FileSize = Buf.size();
+  if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize ||
+      SectionTableOffset + (uintX_t)sizeof(Elf_Shdr) < SectionTableOffset)
+    return createError(
+        "section header table goes past the end of the file: e_shoff = 0x" +
+        Twine::utohexstr(SectionTableOffset));
+
+  // Invalid address alignment of section headers
+  if (SectionTableOffset & (alignof(Elf_Shdr) - 1))
+    // TODO: this error is untested.
+    return createError("invalid alignment of section headers");
+
+  const Elf_Shdr *First =
+      reinterpret_cast<const Elf_Shdr *>(base() + SectionTableOffset);
+
+  uintX_t NumSections = getHeader()->e_shnum;
+  if (NumSections == 0)
+    NumSections = First->sh_size;
+
+  if (NumSections > UINT64_MAX / sizeof(Elf_Shdr))
+    return createError("invalid number of sections specified in the NULL "
+                       "section's sh_size field (" +
+                       Twine(NumSections) + ")");
+
+  const uint64_t SectionTableSize = NumSections * sizeof(Elf_Shdr);
+  if (SectionTableOffset + SectionTableSize < SectionTableOffset)
+    return createError(
+        "invalid section header table offset (e_shoff = 0x" +
+        Twine::utohexstr(SectionTableOffset) +
+        ") or invalid number of sections specified in the first section "
+        "header's sh_size field (0x" +
+        Twine::utohexstr(NumSections) + ")");
+
+  // Section table goes past end of file!
+  if (SectionTableOffset + SectionTableSize > FileSize)
+    return createError("section table goes past the end of file");
+  return makeArrayRef(First, NumSections);
+}
+
+template <class ELFT>
+template <typename T>
+Expected<const T *> ELFFile<ELFT>::getEntry(uint32_t Section,
+                                            uint32_t Entry) const {
+  auto SecOrErr = getSection(Section);
+  if (!SecOrErr)
+    return SecOrErr.takeError();
+  return getEntry<T>(*SecOrErr, Entry);
+}
+
+template <class ELFT>
+template <typename T>
+Expected<const T *> ELFFile<ELFT>::getEntry(const Elf_Shdr *Section,
+                                            uint32_t Entry) const {
+  if (sizeof(T) != Section->sh_entsize)
+    return createError("section " + getSecIndexForError(this, Section) +
+                       " has invalid sh_entsize: expected " + Twine(sizeof(T)) +
+                       ", but got " + Twine(Section->sh_entsize));
+  size_t Pos = Section->sh_offset + Entry * sizeof(T);
+  if (Pos + sizeof(T) > Buf.size())
+    return createError("unable to access section " +
+                       getSecIndexForError(this, Section) + " data at 0x" +
+                       Twine::utohexstr(Pos) +
+                       ": offset goes past the end of file");
+  return reinterpret_cast<const T *>(base() + Pos);
+}
+
+template <class ELFT>
+Expected<const typename ELFT::Shdr *>
+ELFFile<ELFT>::getSection(uint32_t Index) const {
+  auto TableOrErr = sections();
+  if (!TableOrErr)
+    return TableOrErr.takeError();
+  return object::getSection<ELFT>(*TableOrErr, Index);
+}
+
+template <class ELFT>
+Expected<StringRef>
+ELFFile<ELFT>::getStringTable(const Elf_Shdr *Section,
+                              WarningHandler WarnHandler) const {
+  if (Section->sh_type != ELF::SHT_STRTAB)
+    if (Error E = WarnHandler("invalid sh_type for string table section " +
+                              getSecIndexForError(this, Section) +
+                              ": expected SHT_STRTAB, but got " +
+                              object::getELFSectionTypeName(
+                                  getHeader()->e_machine, Section->sh_type)))
+      return std::move(E);
+
+  auto V = getSectionContentsAsArray<char>(Section);
+  if (!V)
+    return V.takeError();
+  ArrayRef<char> Data = *V;
+  if (Data.empty())
+    return createError("SHT_STRTAB string table section " +
+                       getSecIndexForError(this, Section) + " is empty");
+  if (Data.back() != '\0')
+    return createError("SHT_STRTAB string table section " +
+                       getSecIndexForError(this, Section) +
+                       " is non-null terminated");
+  return StringRef(Data.begin(), Data.size());
+}
+
+template <class ELFT>
+Expected<ArrayRef<typename ELFT::Word>>
+ELFFile<ELFT>::getSHNDXTable(const Elf_Shdr &Section) const {
+  auto SectionsOrErr = sections();
+  if (!SectionsOrErr)
+    return SectionsOrErr.takeError();
+  return getSHNDXTable(Section, *SectionsOrErr);
+}
+
+template <class ELFT>
+Expected<ArrayRef<typename ELFT::Word>>
+ELFFile<ELFT>::getSHNDXTable(const Elf_Shdr &Section,
+                             Elf_Shdr_Range Sections) const {
+  assert(Section.sh_type == ELF::SHT_SYMTAB_SHNDX);
+  auto VOrErr = getSectionContentsAsArray<Elf_Word>(&Section);
+  if (!VOrErr)
+    return VOrErr.takeError();
+  ArrayRef<Elf_Word> V = *VOrErr;
+  auto SymTableOrErr = object::getSection<ELFT>(Sections, Section.sh_link);
+  if (!SymTableOrErr)
+    return SymTableOrErr.takeError();
+  const Elf_Shdr &SymTable = **SymTableOrErr;
+  if (SymTable.sh_type != ELF::SHT_SYMTAB &&
+      SymTable.sh_type != ELF::SHT_DYNSYM)
+    return createError("SHT_SYMTAB_SHNDX section is linked with " +
+                       object::getELFSectionTypeName(getHeader()->e_machine,
+                                                     SymTable.sh_type) +
+                       " section (expected SHT_SYMTAB/SHT_DYNSYM)");
+
+  uint64_t Syms = SymTable.sh_size / sizeof(Elf_Sym);
+  if (V.size() != Syms)
+    return createError("SHT_SYMTAB_SHNDX has " + Twine(V.size()) +
+                       " entries, but the symbol table associated has " +
+                       Twine(Syms));
+
+  return V;
+}
+
+template <class ELFT>
+Expected<StringRef>
+ELFFile<ELFT>::getStringTableForSymtab(const Elf_Shdr &Sec) const {
+  auto SectionsOrErr = sections();
+  if (!SectionsOrErr)
+    return SectionsOrErr.takeError();
+  return getStringTableForSymtab(Sec, *SectionsOrErr);
+}
+
+template <class ELFT>
+Expected<StringRef>
+ELFFile<ELFT>::getStringTableForSymtab(const Elf_Shdr &Sec,
+                                       Elf_Shdr_Range Sections) const {
+
+  if (Sec.sh_type != ELF::SHT_SYMTAB && Sec.sh_type != ELF::SHT_DYNSYM)
+    // TODO: this error is untested.
+    return createError(
+        "invalid sh_type for symbol table, expected SHT_SYMTAB or SHT_DYNSYM");
+  auto SectionOrErr = object::getSection<ELFT>(Sections, Sec.sh_link);
+  if (!SectionOrErr)
+    return SectionOrErr.takeError();
+  return getStringTable(*SectionOrErr);
+}
+
+template <class ELFT>
+Expected<StringRef>
+ELFFile<ELFT>::getSectionName(const Elf_Shdr *Section,
+                              WarningHandler WarnHandler) const {
+  auto SectionsOrErr = sections();
+  if (!SectionsOrErr)
+    return SectionsOrErr.takeError();
+  auto Table = getSectionStringTable(*SectionsOrErr, WarnHandler);
+  if (!Table)
+    return Table.takeError();
+  return getSectionName(Section, *Table);
+}
+
+template <class ELFT>
+Expected<StringRef> ELFFile<ELFT>::getSectionName(const Elf_Shdr *Section,
+                                                  StringRef DotShstrtab) const {
+  uint32_t Offset = Section->sh_name;
+  if (Offset == 0)
+    return StringRef();
+  if (Offset >= DotShstrtab.size())
+    return createError("a section " + getSecIndexForError(this, Section) +
+                       " has an invalid sh_name (0x" +
+                       Twine::utohexstr(Offset) +
+                       ") offset which goes past the end of the "
+                       "section name string table");
+  return StringRef(DotShstrtab.data() + Offset);
+}
+
+/// This function returns the hash value for a symbol in the .dynsym section
+/// Name of the API remains consistent as specified in the libelf
+/// REF : http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#hash
+inline unsigned hashSysV(StringRef SymbolName) {
+  unsigned h = 0, g;
+  for (char C : SymbolName) {
+    h = (h << 4) + C;
+    g = h & 0xf0000000L;
+    if (g != 0)
+      h ^= g >> 24;
+    h &= ~g;
+  }
+  return h;
+}
+
+} // end namespace object
+} // end namespace llvm
+
+#endif // LLVM_OBJECT_ELF_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Object/ELFObjectFile.h b/binaryen/third_party/llvm-project/include/llvm/Object/ELFObjectFile.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Object/ELFObjectFile.h
@@ -0,0 +1,1214 @@
+//===- ELFObjectFile.h - ELF object file implementation ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the ELFObjectFile template class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_ELFOBJECTFILE_H
+#define LLVM_OBJECT_ELFOBJECTFILE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/ARMAttributeParser.h"
+#include "llvm/Support/ARMBuildAttributes.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <cassert>
+#include <cstdint>
+#include <system_error>
+
+namespace llvm {
+namespace object {
+
+constexpr int NumElfSymbolTypes = 16;
+extern const llvm::EnumEntry<unsigned> ElfSymbolTypes[NumElfSymbolTypes];
+
+class elf_symbol_iterator;
+
+class ELFObjectFileBase : public ObjectFile {
+  friend class ELFRelocationRef;
+  friend class ELFSectionRef;
+  friend class ELFSymbolRef;
+
+protected:
+  ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source);
+
+  virtual uint64_t getSymbolSize(DataRefImpl Symb) const = 0;
+  virtual uint8_t getSymbolBinding(DataRefImpl Symb) const = 0;
+  virtual uint8_t getSymbolOther(DataRefImpl Symb) const = 0;
+  virtual uint8_t getSymbolELFType(DataRefImpl Symb) const = 0;
+
+  virtual uint32_t getSectionType(DataRefImpl Sec) const = 0;
+  virtual uint64_t getSectionFlags(DataRefImpl Sec) const = 0;
+  virtual uint64_t getSectionOffset(DataRefImpl Sec) const = 0;
+
+  virtual Expected<int64_t> getRelocationAddend(DataRefImpl Rel) const = 0;
+  virtual Error getBuildAttributes(ARMAttributeParser &Attributes) const = 0;
+
+public:
+  using elf_symbol_iterator_range = iterator_range<elf_symbol_iterator>;
+
+  virtual elf_symbol_iterator_range getDynamicSymbolIterators() const = 0;
+
+  /// Returns platform-specific object flags, if any.
+  virtual unsigned getPlatformFlags() const = 0;
+
+  elf_symbol_iterator_range symbols() const;
+
+  static bool classof(const Binary *v) { return v->isELF(); }
+
+  SubtargetFeatures getFeatures() const override;
+
+  SubtargetFeatures getMIPSFeatures() const;
+
+  SubtargetFeatures getARMFeatures() const;
+
+  SubtargetFeatures getRISCVFeatures() const;
+
+  void setARMSubArch(Triple &TheTriple) const override;
+
+  virtual uint16_t getEType() const = 0;
+
+  virtual uint16_t getEMachine() const = 0;
+
+  std::vector<std::pair<DataRefImpl, uint64_t>> getPltAddresses() const;
+};
+
+class ELFSectionRef : public SectionRef {
+public:
+  ELFSectionRef(const SectionRef &B) : SectionRef(B) {
+    assert(isa<ELFObjectFileBase>(SectionRef::getObject()));
+  }
+
+  const ELFObjectFileBase *getObject() const {
+    return cast<ELFObjectFileBase>(SectionRef::getObject());
+  }
+
+  uint32_t getType() const {
+    return getObject()->getSectionType(getRawDataRefImpl());
+  }
+
+  uint64_t getFlags() const {
+    return getObject()->getSectionFlags(getRawDataRefImpl());
+  }
+
+  uint64_t getOffset() const {
+    return getObject()->getSectionOffset(getRawDataRefImpl());
+  }
+};
+
+class elf_section_iterator : public section_iterator {
+public:
+  elf_section_iterator(const section_iterator &B) : section_iterator(B) {
+    assert(isa<ELFObjectFileBase>(B->getObject()));
+  }
+
+  const ELFSectionRef *operator->() const {
+    return static_cast<const ELFSectionRef *>(section_iterator::operator->());
+  }
+
+  const ELFSectionRef &operator*() const {
+    return static_cast<const ELFSectionRef &>(section_iterator::operator*());
+  }
+};
+
+class ELFSymbolRef : public SymbolRef {
+public:
+  ELFSymbolRef(const SymbolRef &B) : SymbolRef(B) {
+    assert(isa<ELFObjectFileBase>(SymbolRef::getObject()));
+  }
+
+  const ELFObjectFileBase *getObject() const {
+    return cast<ELFObjectFileBase>(BasicSymbolRef::getObject());
+  }
+
+  uint64_t getSize() const {
+    return getObject()->getSymbolSize(getRawDataRefImpl());
+  }
+
+  uint8_t getBinding() const {
+    return getObject()->getSymbolBinding(getRawDataRefImpl());
+  }
+
+  uint8_t getOther() const {
+    return getObject()->getSymbolOther(getRawDataRefImpl());
+  }
+
+  uint8_t getELFType() const {
+    return getObject()->getSymbolELFType(getRawDataRefImpl());
+  }
+
+  StringRef getELFTypeName() const {
+    uint8_t Type = getELFType();
+    for (auto &EE : ElfSymbolTypes) {
+      if (EE.Value == Type) {
+        return EE.AltName;
+      }
+    }
+    return "";
+  }
+};
+
+class elf_symbol_iterator : public symbol_iterator {
+public:
+  elf_symbol_iterator(const basic_symbol_iterator &B)
+      : symbol_iterator(SymbolRef(B->getRawDataRefImpl(),
+                                  cast<ELFObjectFileBase>(B->getObject()))) {}
+
+  const ELFSymbolRef *operator->() const {
+    return static_cast<const ELFSymbolRef *>(symbol_iterator::operator->());
+  }
+
+  const ELFSymbolRef &operator*() const {
+    return static_cast<const ELFSymbolRef &>(symbol_iterator::operator*());
+  }
+};
+
+class ELFRelocationRef : public RelocationRef {
+public:
+  ELFRelocationRef(const RelocationRef &B) : RelocationRef(B) {
+    assert(isa<ELFObjectFileBase>(RelocationRef::getObject()));
+  }
+
+  const ELFObjectFileBase *getObject() const {
+    return cast<ELFObjectFileBase>(RelocationRef::getObject());
+  }
+
+  Expected<int64_t> getAddend() const {
+    return getObject()->getRelocationAddend(getRawDataRefImpl());
+  }
+};
+
+class elf_relocation_iterator : public relocation_iterator {
+public:
+  elf_relocation_iterator(const relocation_iterator &B)
+      : relocation_iterator(RelocationRef(
+            B->getRawDataRefImpl(), cast<ELFObjectFileBase>(B->getObject()))) {}
+
+  const ELFRelocationRef *operator->() const {
+    return static_cast<const ELFRelocationRef *>(
+        relocation_iterator::operator->());
+  }
+
+  const ELFRelocationRef &operator*() const {
+    return static_cast<const ELFRelocationRef &>(
+        relocation_iterator::operator*());
+  }
+};
+
+inline ELFObjectFileBase::elf_symbol_iterator_range
+ELFObjectFileBase::symbols() const {
+  return elf_symbol_iterator_range(symbol_begin(), symbol_end());
+}
+
+template <class ELFT> class ELFObjectFile : public ELFObjectFileBase {
+  uint16_t getEMachine() const override;
+  uint16_t getEType() const override;
+  uint64_t getSymbolSize(DataRefImpl Sym) const override;
+
+public:
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+
+  using uintX_t = typename ELFT::uint;
+
+  using Elf_Sym = typename ELFT::Sym;
+  using Elf_Shdr = typename ELFT::Shdr;
+  using Elf_Ehdr = typename ELFT::Ehdr;
+  using Elf_Rel = typename ELFT::Rel;
+  using Elf_Rela = typename ELFT::Rela;
+  using Elf_Dyn = typename ELFT::Dyn;
+
+  SectionRef toSectionRef(const Elf_Shdr *Sec) const {
+    return SectionRef(toDRI(Sec), this);
+  }
+
+private:
+  ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF,
+                const Elf_Shdr *DotDynSymSec, const Elf_Shdr *DotSymtabSec,
+                ArrayRef<Elf_Word> ShndxTable);
+
+protected:
+  ELFFile<ELFT> EF;
+
+  const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section.
+  const Elf_Shdr *DotSymtabSec = nullptr; // Symbol table section.
+  ArrayRef<Elf_Word> ShndxTable;
+
+  void moveSymbolNext(DataRefImpl &Symb) const override;
+  Expected<StringRef> getSymbolName(DataRefImpl Symb) const override;
+  Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override;
+  uint64_t getSymbolValueImpl(DataRefImpl Symb) const override;
+  uint32_t getSymbolAlignment(DataRefImpl Symb) const override;
+  uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override;
+  uint32_t getSymbolFlags(DataRefImpl Symb) const override;
+  uint8_t getSymbolBinding(DataRefImpl Symb) const override;
+  uint8_t getSymbolOther(DataRefImpl Symb) const override;
+  uint8_t getSymbolELFType(DataRefImpl Symb) const override;
+  Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override;
+  Expected<section_iterator> getSymbolSection(const Elf_Sym *Symb,
+                                              const Elf_Shdr *SymTab) const;
+  Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override;
+
+  void moveSectionNext(DataRefImpl &Sec) const override;
+  Expected<StringRef> getSectionName(DataRefImpl Sec) const override;
+  uint64_t getSectionAddress(DataRefImpl Sec) const override;
+  uint64_t getSectionIndex(DataRefImpl Sec) const override;
+  uint64_t getSectionSize(DataRefImpl Sec) const override;
+  Expected<ArrayRef<uint8_t>>
+  getSectionContents(DataRefImpl Sec) const override;
+  uint64_t getSectionAlignment(DataRefImpl Sec) const override;
+  bool isSectionCompressed(DataRefImpl Sec) const override;
+  bool isSectionText(DataRefImpl Sec) const override;
+  bool isSectionData(DataRefImpl Sec) const override;
+  bool isSectionBSS(DataRefImpl Sec) const override;
+  bool isSectionVirtual(DataRefImpl Sec) const override;
+  bool isBerkeleyText(DataRefImpl Sec) const override;
+  bool isBerkeleyData(DataRefImpl Sec) const override;
+  relocation_iterator section_rel_begin(DataRefImpl Sec) const override;
+  relocation_iterator section_rel_end(DataRefImpl Sec) const override;
+  std::vector<SectionRef> dynamic_relocation_sections() const override;
+  Expected<section_iterator>
+  getRelocatedSection(DataRefImpl Sec) const override;
+
+  void moveRelocationNext(DataRefImpl &Rel) const override;
+  uint64_t getRelocationOffset(DataRefImpl Rel) const override;
+  symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override;
+  uint64_t getRelocationType(DataRefImpl Rel) const override;
+  void getRelocationTypeName(DataRefImpl Rel,
+                             SmallVectorImpl<char> &Result) const override;
+
+  uint32_t getSectionType(DataRefImpl Sec) const override;
+  uint64_t getSectionFlags(DataRefImpl Sec) const override;
+  uint64_t getSectionOffset(DataRefImpl Sec) const override;
+  StringRef getRelocationTypeName(uint32_t Type) const;
+
+  /// Get the relocation section that contains \a Rel.
+  const Elf_Shdr *getRelSection(DataRefImpl Rel) const {
+    auto RelSecOrErr = EF.getSection(Rel.d.a);
+    if (!RelSecOrErr)
+      report_fatal_error(errorToErrorCode(RelSecOrErr.takeError()).message());
+    return *RelSecOrErr;
+  }
+
+  DataRefImpl toDRI(const Elf_Shdr *SymTable, unsigned SymbolNum) const {
+    DataRefImpl DRI;
+    if (!SymTable) {
+      DRI.d.a = 0;
+      DRI.d.b = 0;
+      return DRI;
+    }
+    assert(SymTable->sh_type == ELF::SHT_SYMTAB ||
+           SymTable->sh_type == ELF::SHT_DYNSYM);
+
+    auto SectionsOrErr = EF.sections();
+    if (!SectionsOrErr) {
+      DRI.d.a = 0;
+      DRI.d.b = 0;
+      return DRI;
+    }
+    uintptr_t SHT = reinterpret_cast<uintptr_t>((*SectionsOrErr).begin());
+    unsigned SymTableIndex =
+        (reinterpret_cast<uintptr_t>(SymTable) - SHT) / sizeof(Elf_Shdr);
+
+    DRI.d.a = SymTableIndex;
+    DRI.d.b = SymbolNum;
+    return DRI;
+  }
+
+  const Elf_Shdr *toELFShdrIter(DataRefImpl Sec) const {
+    return reinterpret_cast<const Elf_Shdr *>(Sec.p);
+  }
+
+  DataRefImpl toDRI(const Elf_Shdr *Sec) const {
+    DataRefImpl DRI;
+    DRI.p = reinterpret_cast<uintptr_t>(Sec);
+    return DRI;
+  }
+
+  DataRefImpl toDRI(const Elf_Dyn *Dyn) const {
+    DataRefImpl DRI;
+    DRI.p = reinterpret_cast<uintptr_t>(Dyn);
+    return DRI;
+  }
+
+  bool isExportedToOtherDSO(const Elf_Sym *ESym) const {
+    unsigned char Binding = ESym->getBinding();
+    unsigned char Visibility = ESym->getVisibility();
+
+    // A symbol is exported if its binding is either GLOBAL or WEAK, and its
+    // visibility is either DEFAULT or PROTECTED. All other symbols are not
+    // exported.
+    return (
+        (Binding == ELF::STB_GLOBAL || Binding == ELF::STB_WEAK ||
+         Binding == ELF::STB_GNU_UNIQUE) &&
+        (Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_PROTECTED));
+  }
+
+  Error getBuildAttributes(ARMAttributeParser &Attributes) const override {
+    auto SectionsOrErr = EF.sections();
+    if (!SectionsOrErr)
+      return SectionsOrErr.takeError();
+
+    for (const Elf_Shdr &Sec : *SectionsOrErr) {
+      if (Sec.sh_type == ELF::SHT_ARM_ATTRIBUTES) {
+        auto ErrorOrContents = EF.getSectionContents(&Sec);
+        if (!ErrorOrContents)
+          return ErrorOrContents.takeError();
+
+        auto Contents = ErrorOrContents.get();
+        if (Contents[0] != ARMBuildAttrs::Format_Version || Contents.size() == 1)
+          return Error::success();
+
+        Attributes.Parse(Contents, ELFT::TargetEndianness == support::little);
+        break;
+      }
+    }
+    return Error::success();
+  }
+
+  // This flag is used for classof, to distinguish ELFObjectFile from
+  // its subclass. If more subclasses will be created, this flag will
+  // have to become an enum.
+  bool isDyldELFObject;
+
+public:
+  ELFObjectFile(ELFObjectFile<ELFT> &&Other);
+  static Expected<ELFObjectFile<ELFT>> create(MemoryBufferRef Object);
+
+  const Elf_Rel *getRel(DataRefImpl Rel) const;
+  const Elf_Rela *getRela(DataRefImpl Rela) const;
+
+  const Elf_Sym *getSymbol(DataRefImpl Sym) const {
+    auto Ret = EF.template getEntry<Elf_Sym>(Sym.d.a, Sym.d.b);
+    if (!Ret)
+      report_fatal_error(errorToErrorCode(Ret.takeError()).message());
+    return *Ret;
+  }
+
+  const Elf_Shdr *getSection(DataRefImpl Sec) const {
+    return reinterpret_cast<const Elf_Shdr *>(Sec.p);
+  }
+
+  basic_symbol_iterator symbol_begin() const override;
+  basic_symbol_iterator symbol_end() const override;
+
+  elf_symbol_iterator dynamic_symbol_begin() const;
+  elf_symbol_iterator dynamic_symbol_end() const;
+
+  section_iterator section_begin() const override;
+  section_iterator section_end() const override;
+
+  Expected<int64_t> getRelocationAddend(DataRefImpl Rel) const override;
+
+  uint8_t getBytesInAddress() const override;
+  StringRef getFileFormatName() const override;
+  Triple::ArchType getArch() const override;
+  Expected<uint64_t> getStartAddress() const override;
+
+  unsigned getPlatformFlags() const override { return EF.getHeader()->e_flags; }
+
+  const ELFFile<ELFT> *getELFFile() const { return &EF; }
+
+  bool isDyldType() const { return isDyldELFObject; }
+  static bool classof(const Binary *v) {
+    return v->getType() == getELFType(ELFT::TargetEndianness == support::little,
+                                      ELFT::Is64Bits);
+  }
+
+  elf_symbol_iterator_range getDynamicSymbolIterators() const override;
+
+  bool isRelocatableObject() const override;
+};
+
+using ELF32LEObjectFile = ELFObjectFile<ELF32LE>;
+using ELF64LEObjectFile = ELFObjectFile<ELF64LE>;
+using ELF32BEObjectFile = ELFObjectFile<ELF32BE>;
+using ELF64BEObjectFile = ELFObjectFile<ELF64BE>;
+
+template <class ELFT>
+void ELFObjectFile<ELFT>::moveSymbolNext(DataRefImpl &Sym) const {
+  ++Sym.d.b;
+}
+
+template <class ELFT>
+Expected<StringRef> ELFObjectFile<ELFT>::getSymbolName(DataRefImpl Sym) const {
+  const Elf_Sym *ESym = getSymbol(Sym);
+  auto SymTabOrErr = EF.getSection(Sym.d.a);
+  if (!SymTabOrErr)
+    return SymTabOrErr.takeError();
+  const Elf_Shdr *SymTableSec = *SymTabOrErr;
+  auto StrTabOrErr = EF.getSection(SymTableSec->sh_link);
+  if (!StrTabOrErr)
+    return StrTabOrErr.takeError();
+  const Elf_Shdr *StringTableSec = *StrTabOrErr;
+  auto SymStrTabOrErr = EF.getStringTable(StringTableSec);
+  if (!SymStrTabOrErr)
+    return SymStrTabOrErr.takeError();
+  Expected<StringRef> Name = ESym->getName(*SymStrTabOrErr);
+  if (Name && !Name->empty())
+    return Name;
+
+  // If the symbol name is empty use the section name.
+  if (ESym->getType() == ELF::STT_SECTION) {
+    if (Expected<section_iterator> SecOrErr = getSymbolSection(Sym)) {
+      consumeError(Name.takeError());
+      return (*SecOrErr)->getName();
+    }
+  }
+  return Name;
+}
+
+template <class ELFT>
+uint64_t ELFObjectFile<ELFT>::getSectionFlags(DataRefImpl Sec) const {
+  return getSection(Sec)->sh_flags;
+}
+
+template <class ELFT>
+uint32_t ELFObjectFile<ELFT>::getSectionType(DataRefImpl Sec) const {
+  return getSection(Sec)->sh_type;
+}
+
+template <class ELFT>
+uint64_t ELFObjectFile<ELFT>::getSectionOffset(DataRefImpl Sec) const {
+  return getSection(Sec)->sh_offset;
+}
+
+template <class ELFT>
+uint64_t ELFObjectFile<ELFT>::getSymbolValueImpl(DataRefImpl Symb) const {
+  const Elf_Sym *ESym = getSymbol(Symb);
+  uint64_t Ret = ESym->st_value;
+  if (ESym->st_shndx == ELF::SHN_ABS)
+    return Ret;
+
+  const Elf_Ehdr *Header = EF.getHeader();
+  // Clear the ARM/Thumb or microMIPS indicator flag.
+  if ((Header->e_machine == ELF::EM_ARM || Header->e_machine == ELF::EM_MIPS) &&
+      ESym->getType() == ELF::STT_FUNC)
+    Ret &= ~1;
+
+  return Ret;
+}
+
+template <class ELFT>
+Expected<uint64_t>
+ELFObjectFile<ELFT>::getSymbolAddress(DataRefImpl Symb) const {
+  uint64_t Result = getSymbolValue(Symb);
+  const Elf_Sym *ESym = getSymbol(Symb);
+  switch (ESym->st_shndx) {
+  case ELF::SHN_COMMON:
+  case ELF::SHN_UNDEF:
+  case ELF::SHN_ABS:
+    return Result;
+  }
+
+  const Elf_Ehdr *Header = EF.getHeader();
+  auto SymTabOrErr = EF.getSection(Symb.d.a);
+  if (!SymTabOrErr)
+    return SymTabOrErr.takeError();
+  const Elf_Shdr *SymTab = *SymTabOrErr;
+
+  if (Header->e_type == ELF::ET_REL) {
+    auto SectionOrErr = EF.getSection(ESym, SymTab, ShndxTable);
+    if (!SectionOrErr)
+      return SectionOrErr.takeError();
+    const Elf_Shdr *Section = *SectionOrErr;
+    if (Section)
+      Result += Section->sh_addr;
+  }
+
+  return Result;
+}
+
+template <class ELFT>
+uint32_t ELFObjectFile<ELFT>::getSymbolAlignment(DataRefImpl Symb) const {
+  const Elf_Sym *Sym = getSymbol(Symb);
+  if (Sym->st_shndx == ELF::SHN_COMMON)
+    return Sym->st_value;
+  return 0;
+}
+
+template <class ELFT>
+uint16_t ELFObjectFile<ELFT>::getEMachine() const {
+  return EF.getHeader()->e_machine;
+}
+
+template <class ELFT> uint16_t ELFObjectFile<ELFT>::getEType() const {
+  return EF.getHeader()->e_type;
+}
+
+template <class ELFT>
+uint64_t ELFObjectFile<ELFT>::getSymbolSize(DataRefImpl Sym) const {
+  return getSymbol(Sym)->st_size;
+}
+
+template <class ELFT>
+uint64_t ELFObjectFile<ELFT>::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
+  return getSymbol(Symb)->st_size;
+}
+
+template <class ELFT>
+uint8_t ELFObjectFile<ELFT>::getSymbolBinding(DataRefImpl Symb) const {
+  return getSymbol(Symb)->getBinding();
+}
+
+template <class ELFT>
+uint8_t ELFObjectFile<ELFT>::getSymbolOther(DataRefImpl Symb) const {
+  return getSymbol(Symb)->st_other;
+}
+
+template <class ELFT>
+uint8_t ELFObjectFile<ELFT>::getSymbolELFType(DataRefImpl Symb) const {
+  return getSymbol(Symb)->getType();
+}
+
+template <class ELFT>
+Expected<SymbolRef::Type>
+ELFObjectFile<ELFT>::getSymbolType(DataRefImpl Symb) const {
+  const Elf_Sym *ESym = getSymbol(Symb);
+
+  switch (ESym->getType()) {
+  case ELF::STT_NOTYPE:
+    return SymbolRef::ST_Unknown;
+  case ELF::STT_SECTION:
+    return SymbolRef::ST_Debug;
+  case ELF::STT_FILE:
+    return SymbolRef::ST_File;
+  case ELF::STT_FUNC:
+    return SymbolRef::ST_Function;
+  case ELF::STT_OBJECT:
+  case ELF::STT_COMMON:
+  case ELF::STT_TLS:
+    return SymbolRef::ST_Data;
+  default:
+    return SymbolRef::ST_Other;
+  }
+}
+
+template <class ELFT>
+uint32_t ELFObjectFile<ELFT>::getSymbolFlags(DataRefImpl Sym) const {
+  const Elf_Sym *ESym = getSymbol(Sym);
+
+  uint32_t Result = SymbolRef::SF_None;
+
+  if (ESym->getBinding() != ELF::STB_LOCAL)
+    Result |= SymbolRef::SF_Global;
+
+  if (ESym->getBinding() == ELF::STB_WEAK)
+    Result |= SymbolRef::SF_Weak;
+
+  if (ESym->st_shndx == ELF::SHN_ABS)
+    Result |= SymbolRef::SF_Absolute;
+
+  if (ESym->getType() == ELF::STT_FILE || ESym->getType() == ELF::STT_SECTION)
+    Result |= SymbolRef::SF_FormatSpecific;
+
+  auto DotSymtabSecSyms = EF.symbols(DotSymtabSec);
+  if (DotSymtabSecSyms && ESym == (*DotSymtabSecSyms).begin())
+    Result |= SymbolRef::SF_FormatSpecific;
+  auto DotDynSymSecSyms = EF.symbols(DotDynSymSec);
+  if (DotDynSymSecSyms && ESym == (*DotDynSymSecSyms).begin())
+    Result |= SymbolRef::SF_FormatSpecific;
+
+  if (EF.getHeader()->e_machine == ELF::EM_ARM) {
+    if (Expected<StringRef> NameOrErr = getSymbolName(Sym)) {
+      StringRef Name = *NameOrErr;
+      if (Name.startswith("$d") || Name.startswith("$t") ||
+          Name.startswith("$a"))
+        Result |= SymbolRef::SF_FormatSpecific;
+    } else {
+      // TODO: Actually report errors helpfully.
+      consumeError(NameOrErr.takeError());
+    }
+    if (ESym->getType() == ELF::STT_FUNC && (ESym->st_value & 1) == 1)
+      Result |= SymbolRef::SF_Thumb;
+  }
+
+  if (ESym->st_shndx == ELF::SHN_UNDEF)
+    Result |= SymbolRef::SF_Undefined;
+
+  if (ESym->getType() == ELF::STT_COMMON || ESym->st_shndx == ELF::SHN_COMMON)
+    Result |= SymbolRef::SF_Common;
+
+  if (isExportedToOtherDSO(ESym))
+    Result |= SymbolRef::SF_Exported;
+
+  if (ESym->getVisibility() == ELF::STV_HIDDEN)
+    Result |= SymbolRef::SF_Hidden;
+
+  return Result;
+}
+
+template <class ELFT>
+Expected<section_iterator>
+ELFObjectFile<ELFT>::getSymbolSection(const Elf_Sym *ESym,
+                                      const Elf_Shdr *SymTab) const {
+  auto ESecOrErr = EF.getSection(ESym, SymTab, ShndxTable);
+  if (!ESecOrErr)
+    return ESecOrErr.takeError();
+
+  const Elf_Shdr *ESec = *ESecOrErr;
+  if (!ESec)
+    return section_end();
+
+  DataRefImpl Sec;
+  Sec.p = reinterpret_cast<intptr_t>(ESec);
+  return section_iterator(SectionRef(Sec, this));
+}
+
+template <class ELFT>
+Expected<section_iterator>
+ELFObjectFile<ELFT>::getSymbolSection(DataRefImpl Symb) const {
+  const Elf_Sym *Sym = getSymbol(Symb);
+  auto SymTabOrErr = EF.getSection(Symb.d.a);
+  if (!SymTabOrErr)
+    return SymTabOrErr.takeError();
+  const Elf_Shdr *SymTab = *SymTabOrErr;
+  return getSymbolSection(Sym, SymTab);
+}
+
+template <class ELFT>
+void ELFObjectFile<ELFT>::moveSectionNext(DataRefImpl &Sec) const {
+  const Elf_Shdr *ESec = getSection(Sec);
+  Sec = toDRI(++ESec);
+}
+
+template <class ELFT>
+Expected<StringRef> ELFObjectFile<ELFT>::getSectionName(DataRefImpl Sec) const {
+  return EF.getSectionName(&*getSection(Sec));
+}
+
+template <class ELFT>
+uint64_t ELFObjectFile<ELFT>::getSectionAddress(DataRefImpl Sec) const {
+  return getSection(Sec)->sh_addr;
+}
+
+template <class ELFT>
+uint64_t ELFObjectFile<ELFT>::getSectionIndex(DataRefImpl Sec) const {
+  auto SectionsOrErr = EF.sections();
+  handleAllErrors(std::move(SectionsOrErr.takeError()),
+                  [](const ErrorInfoBase &) {
+                    llvm_unreachable("unable to get section index");
+                  });
+  const Elf_Shdr *First = SectionsOrErr->begin();
+  return getSection(Sec) - First;
+}
+
+template <class ELFT>
+uint64_t ELFObjectFile<ELFT>::getSectionSize(DataRefImpl Sec) const {
+  return getSection(Sec)->sh_size;
+}
+
+template <class ELFT>
+Expected<ArrayRef<uint8_t>>
+ELFObjectFile<ELFT>::getSectionContents(DataRefImpl Sec) const {
+  const Elf_Shdr *EShdr = getSection(Sec);
+  if (EShdr->sh_type == ELF::SHT_NOBITS)
+    return makeArrayRef((const uint8_t *)base(), 0);
+  if (std::error_code EC =
+          checkOffset(getMemoryBufferRef(),
+                      (uintptr_t)base() + EShdr->sh_offset, EShdr->sh_size))
+    return errorCodeToError(EC);
+  return makeArrayRef((const uint8_t *)base() + EShdr->sh_offset,
+                      EShdr->sh_size);
+}
+
+template <class ELFT>
+uint64_t ELFObjectFile<ELFT>::getSectionAlignment(DataRefImpl Sec) const {
+  return getSection(Sec)->sh_addralign;
+}
+
+template <class ELFT>
+bool ELFObjectFile<ELFT>::isSectionCompressed(DataRefImpl Sec) const {
+  return getSection(Sec)->sh_flags & ELF::SHF_COMPRESSED;
+}
+
+template <class ELFT>
+bool ELFObjectFile<ELFT>::isSectionText(DataRefImpl Sec) const {
+  return getSection(Sec)->sh_flags & ELF::SHF_EXECINSTR;
+}
+
+template <class ELFT>
+bool ELFObjectFile<ELFT>::isSectionData(DataRefImpl Sec) const {
+  const Elf_Shdr *EShdr = getSection(Sec);
+  return EShdr->sh_type == ELF::SHT_PROGBITS &&
+         EShdr->sh_flags & ELF::SHF_ALLOC &&
+         !(EShdr->sh_flags & ELF::SHF_EXECINSTR);
+}
+
+template <class ELFT>
+bool ELFObjectFile<ELFT>::isSectionBSS(DataRefImpl Sec) const {
+  const Elf_Shdr *EShdr = getSection(Sec);
+  return EShdr->sh_flags & (ELF::SHF_ALLOC | ELF::SHF_WRITE) &&
+         EShdr->sh_type == ELF::SHT_NOBITS;
+}
+
+template <class ELFT>
+std::vector<SectionRef>
+ELFObjectFile<ELFT>::dynamic_relocation_sections() const {
+  std::vector<SectionRef> Res;
+  std::vector<uintptr_t> Offsets;
+
+  auto SectionsOrErr = EF.sections();
+  if (!SectionsOrErr)
+    return Res;
+
+  for (const Elf_Shdr &Sec : *SectionsOrErr) {
+    if (Sec.sh_type != ELF::SHT_DYNAMIC)
+      continue;
+    Elf_Dyn *Dynamic =
+        reinterpret_cast<Elf_Dyn *>((uintptr_t)base() + Sec.sh_offset);
+    for (; Dynamic->d_tag != ELF::DT_NULL; Dynamic++) {
+      if (Dynamic->d_tag == ELF::DT_REL || Dynamic->d_tag == ELF::DT_RELA ||
+          Dynamic->d_tag == ELF::DT_JMPREL) {
+        Offsets.push_back(Dynamic->d_un.d_val);
+      }
+    }
+  }
+  for (const Elf_Shdr &Sec : *SectionsOrErr) {
+    if (is_contained(Offsets, Sec.sh_addr))
+      Res.emplace_back(toDRI(&Sec), this);
+  }
+  return Res;
+}
+
+template <class ELFT>
+bool ELFObjectFile<ELFT>::isSectionVirtual(DataRefImpl Sec) const {
+  return getSection(Sec)->sh_type == ELF::SHT_NOBITS;
+}
+
+template <class ELFT>
+bool ELFObjectFile<ELFT>::isBerkeleyText(DataRefImpl Sec) const {
+  return getSection(Sec)->sh_flags & ELF::SHF_ALLOC &&
+         (getSection(Sec)->sh_flags & ELF::SHF_EXECINSTR ||
+          !(getSection(Sec)->sh_flags & ELF::SHF_WRITE));
+}
+
+template <class ELFT>
+bool ELFObjectFile<ELFT>::isBerkeleyData(DataRefImpl Sec) const {
+  const Elf_Shdr *EShdr = getSection(Sec);
+  return !isBerkeleyText(Sec) && EShdr->sh_type != ELF::SHT_NOBITS &&
+         EShdr->sh_flags & ELF::SHF_ALLOC;
+}
+
+template <class ELFT>
+relocation_iterator
+ELFObjectFile<ELFT>::section_rel_begin(DataRefImpl Sec) const {
+  DataRefImpl RelData;
+  auto SectionsOrErr = EF.sections();
+  if (!SectionsOrErr)
+    return relocation_iterator(RelocationRef());
+  uintptr_t SHT = reinterpret_cast<uintptr_t>((*SectionsOrErr).begin());
+  RelData.d.a = (Sec.p - SHT) / EF.getHeader()->e_shentsize;
+  RelData.d.b = 0;
+  return relocation_iterator(RelocationRef(RelData, this));
+}
+
+template <class ELFT>
+relocation_iterator
+ELFObjectFile<ELFT>::section_rel_end(DataRefImpl Sec) const {
+  const Elf_Shdr *S = reinterpret_cast<const Elf_Shdr *>(Sec.p);
+  relocation_iterator Begin = section_rel_begin(Sec);
+  if (S->sh_type != ELF::SHT_RELA && S->sh_type != ELF::SHT_REL)
+    return Begin;
+  DataRefImpl RelData = Begin->getRawDataRefImpl();
+  const Elf_Shdr *RelSec = getRelSection(RelData);
+
+  // Error check sh_link here so that getRelocationSymbol can just use it.
+  auto SymSecOrErr = EF.getSection(RelSec->sh_link);
+  if (!SymSecOrErr)
+    report_fatal_error(errorToErrorCode(SymSecOrErr.takeError()).message());
+
+  RelData.d.b += S->sh_size / S->sh_entsize;
+  return relocation_iterator(RelocationRef(RelData, this));
+}
+
+template <class ELFT>
+Expected<section_iterator>
+ELFObjectFile<ELFT>::getRelocatedSection(DataRefImpl Sec) const {
+  if (EF.getHeader()->e_type != ELF::ET_REL)
+    return section_end();
+
+  const Elf_Shdr *EShdr = getSection(Sec);
+  uintX_t Type = EShdr->sh_type;
+  if (Type != ELF::SHT_REL && Type != ELF::SHT_RELA)
+    return section_end();
+
+  Expected<const Elf_Shdr *> SecOrErr = EF.getSection(EShdr->sh_info);
+  if (!SecOrErr)
+    return SecOrErr.takeError();
+  return section_iterator(SectionRef(toDRI(*SecOrErr), this));
+}
+
+// Relocations
+template <class ELFT>
+void ELFObjectFile<ELFT>::moveRelocationNext(DataRefImpl &Rel) const {
+  ++Rel.d.b;
+}
+
+template <class ELFT>
+symbol_iterator
+ELFObjectFile<ELFT>::getRelocationSymbol(DataRefImpl Rel) const {
+  uint32_t symbolIdx;
+  const Elf_Shdr *sec = getRelSection(Rel);
+  if (sec->sh_type == ELF::SHT_REL)
+    symbolIdx = getRel(Rel)->getSymbol(EF.isMips64EL());
+  else
+    symbolIdx = getRela(Rel)->getSymbol(EF.isMips64EL());
+  if (!symbolIdx)
+    return symbol_end();
+
+  // FIXME: error check symbolIdx
+  DataRefImpl SymbolData;
+  SymbolData.d.a = sec->sh_link;
+  SymbolData.d.b = symbolIdx;
+  return symbol_iterator(SymbolRef(SymbolData, this));
+}
+
+template <class ELFT>
+uint64_t ELFObjectFile<ELFT>::getRelocationOffset(DataRefImpl Rel) const {
+  const Elf_Shdr *sec = getRelSection(Rel);
+  if (sec->sh_type == ELF::SHT_REL)
+    return getRel(Rel)->r_offset;
+
+  return getRela(Rel)->r_offset;
+}
+
+template <class ELFT>
+uint64_t ELFObjectFile<ELFT>::getRelocationType(DataRefImpl Rel) const {
+  const Elf_Shdr *sec = getRelSection(Rel);
+  if (sec->sh_type == ELF::SHT_REL)
+    return getRel(Rel)->getType(EF.isMips64EL());
+  else
+    return getRela(Rel)->getType(EF.isMips64EL());
+}
+
+template <class ELFT>
+StringRef ELFObjectFile<ELFT>::getRelocationTypeName(uint32_t Type) const {
+  return getELFRelocationTypeName(EF.getHeader()->e_machine, Type);
+}
+
+template <class ELFT>
+void ELFObjectFile<ELFT>::getRelocationTypeName(
+    DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
+  uint32_t type = getRelocationType(Rel);
+  EF.getRelocationTypeName(type, Result);
+}
+
+template <class ELFT>
+Expected<int64_t>
+ELFObjectFile<ELFT>::getRelocationAddend(DataRefImpl Rel) const {
+  if (getRelSection(Rel)->sh_type != ELF::SHT_RELA)
+    return createError("Section is not SHT_RELA");
+  return (int64_t)getRela(Rel)->r_addend;
+}
+
+template <class ELFT>
+const typename ELFObjectFile<ELFT>::Elf_Rel *
+ELFObjectFile<ELFT>::getRel(DataRefImpl Rel) const {
+  assert(getRelSection(Rel)->sh_type == ELF::SHT_REL);
+  auto Ret = EF.template getEntry<Elf_Rel>(Rel.d.a, Rel.d.b);
+  if (!Ret)
+    report_fatal_error(errorToErrorCode(Ret.takeError()).message());
+  return *Ret;
+}
+
+template <class ELFT>
+const typename ELFObjectFile<ELFT>::Elf_Rela *
+ELFObjectFile<ELFT>::getRela(DataRefImpl Rela) const {
+  assert(getRelSection(Rela)->sh_type == ELF::SHT_RELA);
+  auto Ret = EF.template getEntry<Elf_Rela>(Rela.d.a, Rela.d.b);
+  if (!Ret)
+    report_fatal_error(errorToErrorCode(Ret.takeError()).message());
+  return *Ret;
+}
+
+template <class ELFT>
+Expected<ELFObjectFile<ELFT>>
+ELFObjectFile<ELFT>::create(MemoryBufferRef Object) {
+  auto EFOrErr = ELFFile<ELFT>::create(Object.getBuffer());
+  if (Error E = EFOrErr.takeError())
+    return std::move(E);
+  auto EF = std::move(*EFOrErr);
+
+  auto SectionsOrErr = EF.sections();
+  if (!SectionsOrErr)
+    return SectionsOrErr.takeError();
+
+  const Elf_Shdr *DotDynSymSec = nullptr;
+  const Elf_Shdr *DotSymtabSec = nullptr;
+  ArrayRef<Elf_Word> ShndxTable;
+  for (const Elf_Shdr &Sec : *SectionsOrErr) {
+    switch (Sec.sh_type) {
+    case ELF::SHT_DYNSYM: {
+      if (!DotDynSymSec)
+        DotDynSymSec = &Sec;
+      break;
+    }
+    case ELF::SHT_SYMTAB: {
+      if (!DotSymtabSec)
+        DotSymtabSec = &Sec;
+      break;
+    }
+    case ELF::SHT_SYMTAB_SHNDX: {
+      auto TableOrErr = EF.getSHNDXTable(Sec);
+      if (!TableOrErr)
+        return TableOrErr.takeError();
+      ShndxTable = *TableOrErr;
+      break;
+    }
+    }
+  }
+  return ELFObjectFile<ELFT>(Object, EF, DotDynSymSec, DotSymtabSec,
+                             ShndxTable);
+}
+
+template <class ELFT>
+ELFObjectFile<ELFT>::ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF,
+                                   const Elf_Shdr *DotDynSymSec,
+                                   const Elf_Shdr *DotSymtabSec,
+                                   ArrayRef<Elf_Word> ShndxTable)
+    : ELFObjectFileBase(
+          getELFType(ELFT::TargetEndianness == support::little, ELFT::Is64Bits),
+          Object),
+      EF(EF), DotDynSymSec(DotDynSymSec), DotSymtabSec(DotSymtabSec),
+      ShndxTable(ShndxTable) {}
+
+template <class ELFT>
+ELFObjectFile<ELFT>::ELFObjectFile(ELFObjectFile<ELFT> &&Other)
+    : ELFObjectFile(Other.Data, Other.EF, Other.DotDynSymSec,
+                    Other.DotSymtabSec, Other.ShndxTable) {}
+
+template <class ELFT>
+basic_symbol_iterator ELFObjectFile<ELFT>::symbol_begin() const {
+  DataRefImpl Sym =
+      toDRI(DotSymtabSec,
+            DotSymtabSec && DotSymtabSec->sh_size >= sizeof(Elf_Sym) ? 1 : 0);
+  return basic_symbol_iterator(SymbolRef(Sym, this));
+}
+
+template <class ELFT>
+basic_symbol_iterator ELFObjectFile<ELFT>::symbol_end() const {
+  const Elf_Shdr *SymTab = DotSymtabSec;
+  if (!SymTab)
+    return symbol_begin();
+  DataRefImpl Sym = toDRI(SymTab, SymTab->sh_size / sizeof(Elf_Sym));
+  return basic_symbol_iterator(SymbolRef(Sym, this));
+}
+
+template <class ELFT>
+elf_symbol_iterator ELFObjectFile<ELFT>::dynamic_symbol_begin() const {
+  DataRefImpl Sym = toDRI(DotDynSymSec, 0);
+  return symbol_iterator(SymbolRef(Sym, this));
+}
+
+template <class ELFT>
+elf_symbol_iterator ELFObjectFile<ELFT>::dynamic_symbol_end() const {
+  const Elf_Shdr *SymTab = DotDynSymSec;
+  if (!SymTab)
+    return dynamic_symbol_begin();
+  DataRefImpl Sym = toDRI(SymTab, SymTab->sh_size / sizeof(Elf_Sym));
+  return basic_symbol_iterator(SymbolRef(Sym, this));
+}
+
+template <class ELFT>
+section_iterator ELFObjectFile<ELFT>::section_begin() const {
+  auto SectionsOrErr = EF.sections();
+  if (!SectionsOrErr)
+    return section_iterator(SectionRef());
+  return section_iterator(SectionRef(toDRI((*SectionsOrErr).begin()), this));
+}
+
+template <class ELFT>
+section_iterator ELFObjectFile<ELFT>::section_end() const {
+  auto SectionsOrErr = EF.sections();
+  if (!SectionsOrErr)
+    return section_iterator(SectionRef());
+  return section_iterator(SectionRef(toDRI((*SectionsOrErr).end()), this));
+}
+
+template <class ELFT>
+uint8_t ELFObjectFile<ELFT>::getBytesInAddress() const {
+  return ELFT::Is64Bits ? 8 : 4;
+}
+
+template <class ELFT>
+StringRef ELFObjectFile<ELFT>::getFileFormatName() const {
+  bool IsLittleEndian = ELFT::TargetEndianness == support::little;
+  switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) {
+  case ELF::ELFCLASS32:
+    switch (EF.getHeader()->e_machine) {
+    case ELF::EM_386:
+      return "ELF32-i386";
+    case ELF::EM_IAMCU:
+      return "ELF32-iamcu";
+    case ELF::EM_X86_64:
+      return "ELF32-x86-64";
+    case ELF::EM_ARM:
+      return (IsLittleEndian ? "ELF32-arm-little" : "ELF32-arm-big");
+    case ELF::EM_AVR:
+      return "ELF32-avr";
+    case ELF::EM_HEXAGON:
+      return "ELF32-hexagon";
+    case ELF::EM_LANAI:
+      return "ELF32-lanai";
+    case ELF::EM_MIPS:
+      return "ELF32-mips";
+    case ELF::EM_MSP430:
+      return "ELF32-msp430";
+    case ELF::EM_PPC:
+      return "ELF32-ppc";
+    case ELF::EM_RISCV:
+      return "ELF32-riscv";
+    case ELF::EM_SPARC:
+    case ELF::EM_SPARC32PLUS:
+      return "ELF32-sparc";
+    case ELF::EM_AMDGPU:
+      return "ELF32-amdgpu";
+    default:
+      return "ELF32-unknown";
+    }
+  case ELF::ELFCLASS64:
+    switch (EF.getHeader()->e_machine) {
+    case ELF::EM_386:
+      return "ELF64-i386";
+    case ELF::EM_X86_64:
+      return "ELF64-x86-64";
+    case ELF::EM_AARCH64:
+      return (IsLittleEndian ? "ELF64-aarch64-little" : "ELF64-aarch64-big");
+    case ELF::EM_PPC64:
+      return "ELF64-ppc64";
+    case ELF::EM_RISCV:
+      return "ELF64-riscv";
+    case ELF::EM_S390:
+      return "ELF64-s390";
+    case ELF::EM_SPARCV9:
+      return "ELF64-sparc";
+    case ELF::EM_MIPS:
+      return "ELF64-mips";
+    case ELF::EM_AMDGPU:
+      return "ELF64-amdgpu";
+    case ELF::EM_BPF:
+      return "ELF64-BPF";
+    default:
+      return "ELF64-unknown";
+    }
+  default:
+    // FIXME: Proper error handling.
+    report_fatal_error("Invalid ELFCLASS!");
+  }
+}
+
+template <class ELFT> Triple::ArchType ELFObjectFile<ELFT>::getArch() const {
+  bool IsLittleEndian = ELFT::TargetEndianness == support::little;
+  switch (EF.getHeader()->e_machine) {
+  case ELF::EM_386:
+  case ELF::EM_IAMCU:
+    return Triple::x86;
+  case ELF::EM_X86_64:
+    return Triple::x86_64;
+  case ELF::EM_AARCH64:
+    return IsLittleEndian ? Triple::aarch64 : Triple::aarch64_be;
+  case ELF::EM_ARM:
+    return Triple::arm;
+  case ELF::EM_AVR:
+    return Triple::avr;
+  case ELF::EM_HEXAGON:
+    return Triple::hexagon;
+  case ELF::EM_LANAI:
+    return Triple::lanai;
+  case ELF::EM_MIPS:
+    switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) {
+    case ELF::ELFCLASS32:
+      return IsLittleEndian ? Triple::mipsel : Triple::mips;
+    case ELF::ELFCLASS64:
+      return IsLittleEndian ? Triple::mips64el : Triple::mips64;
+    default:
+      report_fatal_error("Invalid ELFCLASS!");
+    }
+  case ELF::EM_MSP430:
+    return Triple::msp430;
+  case ELF::EM_PPC:
+    return Triple::ppc;
+  case ELF::EM_PPC64:
+    return IsLittleEndian ? Triple::ppc64le : Triple::ppc64;
+  case ELF::EM_RISCV:
+    switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) {
+    case ELF::ELFCLASS32:
+      return Triple::riscv32;
+    case ELF::ELFCLASS64:
+      return Triple::riscv64;
+    default:
+      report_fatal_error("Invalid ELFCLASS!");
+    }
+  case ELF::EM_S390:
+    return Triple::systemz;
+
+  case ELF::EM_SPARC:
+  case ELF::EM_SPARC32PLUS:
+    return IsLittleEndian ? Triple::sparcel : Triple::sparc;
+  case ELF::EM_SPARCV9:
+    return Triple::sparcv9;
+
+  case ELF::EM_AMDGPU: {
+    if (!IsLittleEndian)
+      return Triple::UnknownArch;
+
+    unsigned MACH = EF.getHeader()->e_flags & ELF::EF_AMDGPU_MACH;
+    if (MACH >= ELF::EF_AMDGPU_MACH_R600_FIRST &&
+        MACH <= ELF::EF_AMDGPU_MACH_R600_LAST)
+      return Triple::r600;
+    if (MACH >= ELF::EF_AMDGPU_MACH_AMDGCN_FIRST &&
+        MACH <= ELF::EF_AMDGPU_MACH_AMDGCN_LAST)
+      return Triple::amdgcn;
+
+    return Triple::UnknownArch;
+  }
+
+  case ELF::EM_BPF:
+    return IsLittleEndian ? Triple::bpfel : Triple::bpfeb;
+
+  default:
+    return Triple::UnknownArch;
+  }
+}
+
+template <class ELFT>
+Expected<uint64_t> ELFObjectFile<ELFT>::getStartAddress() const {
+  return EF.getHeader()->e_entry;
+}
+
+template <class ELFT>
+ELFObjectFileBase::elf_symbol_iterator_range
+ELFObjectFile<ELFT>::getDynamicSymbolIterators() const {
+  return make_range(dynamic_symbol_begin(), dynamic_symbol_end());
+}
+
+template <class ELFT> bool ELFObjectFile<ELFT>::isRelocatableObject() const {
+  return EF.getHeader()->e_type == ELF::ET_REL;
+}
+
+} // end namespace object
+} // end namespace llvm
+
+#endif // LLVM_OBJECT_ELFOBJECTFILE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Object/ELFTypes.h b/binaryen/third_party/llvm-project/include/llvm/Object/ELFTypes.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Object/ELFTypes.h
@@ -0,0 +1,763 @@
+//===- ELFTypes.h - Endian specific types for ELF ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_ELFTYPES_H
+#define LLVM_OBJECT_ELFTYPES_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <type_traits>
+
+namespace llvm {
+namespace object {
+
+using support::endianness;
+
+template <class ELFT> struct Elf_Ehdr_Impl;
+template <class ELFT> struct Elf_Shdr_Impl;
+template <class ELFT> struct Elf_Sym_Impl;
+template <class ELFT> struct Elf_Dyn_Impl;
+template <class ELFT> struct Elf_Phdr_Impl;
+template <class ELFT, bool isRela> struct Elf_Rel_Impl;
+template <class ELFT> struct Elf_Verdef_Impl;
+template <class ELFT> struct Elf_Verdaux_Impl;
+template <class ELFT> struct Elf_Verneed_Impl;
+template <class ELFT> struct Elf_Vernaux_Impl;
+template <class ELFT> struct Elf_Versym_Impl;
+template <class ELFT> struct Elf_Hash_Impl;
+template <class ELFT> struct Elf_GnuHash_Impl;
+template <class ELFT> struct Elf_Chdr_Impl;
+template <class ELFT> struct Elf_Nhdr_Impl;
+template <class ELFT> class Elf_Note_Impl;
+template <class ELFT> class Elf_Note_Iterator_Impl;
+template <class ELFT> struct Elf_CGProfile_Impl;
+
+template <endianness E, bool Is64> struct ELFType {
+private:
+  template <typename Ty>
+  using packed = support::detail::packed_endian_specific_integral<Ty, E, 1>;
+
+public:
+  static const endianness TargetEndianness = E;
+  static const bool Is64Bits = Is64;
+
+  using uint = typename std::conditional<Is64, uint64_t, uint32_t>::type;
+  using Ehdr = Elf_Ehdr_Impl<ELFType<E, Is64>>;
+  using Shdr = Elf_Shdr_Impl<ELFType<E, Is64>>;
+  using Sym = Elf_Sym_Impl<ELFType<E, Is64>>;
+  using Dyn = Elf_Dyn_Impl<ELFType<E, Is64>>;
+  using Phdr = Elf_Phdr_Impl<ELFType<E, Is64>>;
+  using Rel = Elf_Rel_Impl<ELFType<E, Is64>, false>;
+  using Rela = Elf_Rel_Impl<ELFType<E, Is64>, true>;
+  using Relr = packed<uint>;
+  using Verdef = Elf_Verdef_Impl<ELFType<E, Is64>>;
+  using Verdaux = Elf_Verdaux_Impl<ELFType<E, Is64>>;
+  using Verneed = Elf_Verneed_Impl<ELFType<E, Is64>>;
+  using Vernaux = Elf_Vernaux_Impl<ELFType<E, Is64>>;
+  using Versym = Elf_Versym_Impl<ELFType<E, Is64>>;
+  using Hash = Elf_Hash_Impl<ELFType<E, Is64>>;
+  using GnuHash = Elf_GnuHash_Impl<ELFType<E, Is64>>;
+  using Chdr = Elf_Chdr_Impl<ELFType<E, Is64>>;
+  using Nhdr = Elf_Nhdr_Impl<ELFType<E, Is64>>;
+  using Note = Elf_Note_Impl<ELFType<E, Is64>>;
+  using NoteIterator = Elf_Note_Iterator_Impl<ELFType<E, Is64>>;
+  using CGProfile = Elf_CGProfile_Impl<ELFType<E, Is64>>;
+  using DynRange = ArrayRef<Dyn>;
+  using ShdrRange = ArrayRef<Shdr>;
+  using SymRange = ArrayRef<Sym>;
+  using RelRange = ArrayRef<Rel>;
+  using RelaRange = ArrayRef<Rela>;
+  using RelrRange = ArrayRef<Relr>;
+  using PhdrRange = ArrayRef<Phdr>;
+
+  using Half = packed<uint16_t>;
+  using Word = packed<uint32_t>;
+  using Sword = packed<int32_t>;
+  using Xword = packed<uint64_t>;
+  using Sxword = packed<int64_t>;
+  using Addr = packed<uint>;
+  using Off = packed<uint>;
+};
+
+using ELF32LE = ELFType<support::little, false>;
+using ELF32BE = ELFType<support::big, false>;
+using ELF64LE = ELFType<support::little, true>;
+using ELF64BE = ELFType<support::big, true>;
+
+// Use an alignment of 2 for the typedefs since that is the worst case for
+// ELF files in archives.
+
+// I really don't like doing this, but the alternative is copypasta.
+#define LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)                                       \
+  using Elf_Addr = typename ELFT::Addr;                                        \
+  using Elf_Off = typename ELFT::Off;                                          \
+  using Elf_Half = typename ELFT::Half;                                        \
+  using Elf_Word = typename ELFT::Word;                                        \
+  using Elf_Sword = typename ELFT::Sword;                                      \
+  using Elf_Xword = typename ELFT::Xword;                                      \
+  using Elf_Sxword = typename ELFT::Sxword;
+
+#define LLVM_ELF_COMMA ,
+#define LLVM_ELF_IMPORT_TYPES(E, W)                                            \
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFType<E LLVM_ELF_COMMA W>)
+
+// Section header.
+template <class ELFT> struct Elf_Shdr_Base;
+
+template <endianness TargetEndianness>
+struct Elf_Shdr_Base<ELFType<TargetEndianness, false>> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, false)
+  Elf_Word sh_name;      // Section name (index into string table)
+  Elf_Word sh_type;      // Section type (SHT_*)
+  Elf_Word sh_flags;     // Section flags (SHF_*)
+  Elf_Addr sh_addr;      // Address where section is to be loaded
+  Elf_Off sh_offset;     // File offset of section data, in bytes
+  Elf_Word sh_size;      // Size of section, in bytes
+  Elf_Word sh_link;      // Section type-specific header table index link
+  Elf_Word sh_info;      // Section type-specific extra information
+  Elf_Word sh_addralign; // Section address alignment
+  Elf_Word sh_entsize;   // Size of records contained within the section
+};
+
+template <endianness TargetEndianness>
+struct Elf_Shdr_Base<ELFType<TargetEndianness, true>> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, true)
+  Elf_Word sh_name;       // Section name (index into string table)
+  Elf_Word sh_type;       // Section type (SHT_*)
+  Elf_Xword sh_flags;     // Section flags (SHF_*)
+  Elf_Addr sh_addr;       // Address where section is to be loaded
+  Elf_Off sh_offset;      // File offset of section data, in bytes
+  Elf_Xword sh_size;      // Size of section, in bytes
+  Elf_Word sh_link;       // Section type-specific header table index link
+  Elf_Word sh_info;       // Section type-specific extra information
+  Elf_Xword sh_addralign; // Section address alignment
+  Elf_Xword sh_entsize;   // Size of records contained within the section
+};
+
+template <class ELFT>
+struct Elf_Shdr_Impl : Elf_Shdr_Base<ELFT> {
+  using Elf_Shdr_Base<ELFT>::sh_entsize;
+  using Elf_Shdr_Base<ELFT>::sh_size;
+
+  /// Get the number of entities this section contains if it has any.
+  unsigned getEntityCount() const {
+    if (sh_entsize == 0)
+      return 0;
+    return sh_size / sh_entsize;
+  }
+};
+
+template <class ELFT> struct Elf_Sym_Base;
+
+template <endianness TargetEndianness>
+struct Elf_Sym_Base<ELFType<TargetEndianness, false>> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, false)
+  Elf_Word st_name;       // Symbol name (index into string table)
+  Elf_Addr st_value;      // Value or address associated with the symbol
+  Elf_Word st_size;       // Size of the symbol
+  unsigned char st_info;  // Symbol's type and binding attributes
+  unsigned char st_other; // Must be zero; reserved
+  Elf_Half st_shndx;      // Which section (header table index) it's defined in
+};
+
+template <endianness TargetEndianness>
+struct Elf_Sym_Base<ELFType<TargetEndianness, true>> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, true)
+  Elf_Word st_name;       // Symbol name (index into string table)
+  unsigned char st_info;  // Symbol's type and binding attributes
+  unsigned char st_other; // Must be zero; reserved
+  Elf_Half st_shndx;      // Which section (header table index) it's defined in
+  Elf_Addr st_value;      // Value or address associated with the symbol
+  Elf_Xword st_size;      // Size of the symbol
+};
+
+template <class ELFT>
+struct Elf_Sym_Impl : Elf_Sym_Base<ELFT> {
+  using Elf_Sym_Base<ELFT>::st_info;
+  using Elf_Sym_Base<ELFT>::st_shndx;
+  using Elf_Sym_Base<ELFT>::st_other;
+  using Elf_Sym_Base<ELFT>::st_value;
+
+  // These accessors and mutators correspond to the ELF32_ST_BIND,
+  // ELF32_ST_TYPE, and ELF32_ST_INFO macros defined in the ELF specification:
+  unsigned char getBinding() const { return st_info >> 4; }
+  unsigned char getType() const { return st_info & 0x0f; }
+  uint64_t getValue() const { return st_value; }
+  void setBinding(unsigned char b) { setBindingAndType(b, getType()); }
+  void setType(unsigned char t) { setBindingAndType(getBinding(), t); }
+
+  void setBindingAndType(unsigned char b, unsigned char t) {
+    st_info = (b << 4) + (t & 0x0f);
+  }
+
+  /// Access to the STV_xxx flag stored in the first two bits of st_other.
+  /// STV_DEFAULT: 0
+  /// STV_INTERNAL: 1
+  /// STV_HIDDEN: 2
+  /// STV_PROTECTED: 3
+  unsigned char getVisibility() const { return st_other & 0x3; }
+  void setVisibility(unsigned char v) {
+    assert(v < 4 && "Invalid value for visibility");
+    st_other = (st_other & ~0x3) | v;
+  }
+
+  bool isAbsolute() const { return st_shndx == ELF::SHN_ABS; }
+
+  bool isCommon() const {
+    return getType() == ELF::STT_COMMON || st_shndx == ELF::SHN_COMMON;
+  }
+
+  bool isDefined() const { return !isUndefined(); }
+
+  bool isProcessorSpecific() const {
+    return st_shndx >= ELF::SHN_LOPROC && st_shndx <= ELF::SHN_HIPROC;
+  }
+
+  bool isOSSpecific() const {
+    return st_shndx >= ELF::SHN_LOOS && st_shndx <= ELF::SHN_HIOS;
+  }
+
+  bool isReserved() const {
+    // ELF::SHN_HIRESERVE is 0xffff so st_shndx <= ELF::SHN_HIRESERVE is always
+    // true and some compilers warn about it.
+    return st_shndx >= ELF::SHN_LORESERVE;
+  }
+
+  bool isUndefined() const { return st_shndx == ELF::SHN_UNDEF; }
+
+  bool isExternal() const {
+    return getBinding() != ELF::STB_LOCAL;
+  }
+
+  Expected<StringRef> getName(StringRef StrTab) const;
+};
+
+template <class ELFT>
+Expected<StringRef> Elf_Sym_Impl<ELFT>::getName(StringRef StrTab) const {
+  uint32_t Offset = this->st_name;
+  if (Offset >= StrTab.size())
+    return createStringError(object_error::parse_failed,
+                             "st_name (0x%" PRIx32
+                             ") is past the end of the string table"
+                             " of size 0x%zx",
+                             Offset, StrTab.size());
+  return StringRef(StrTab.data() + Offset);
+}
+
+/// Elf_Versym: This is the structure of entries in the SHT_GNU_versym section
+/// (.gnu.version). This structure is identical for ELF32 and ELF64.
+template <class ELFT>
+struct Elf_Versym_Impl {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+  Elf_Half vs_index; // Version index with flags (e.g. VERSYM_HIDDEN)
+};
+
+/// Elf_Verdef: This is the structure of entries in the SHT_GNU_verdef section
+/// (.gnu.version_d). This structure is identical for ELF32 and ELF64.
+template <class ELFT>
+struct Elf_Verdef_Impl {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+  using Elf_Verdaux = Elf_Verdaux_Impl<ELFT>;
+  Elf_Half vd_version; // Version of this structure (e.g. VER_DEF_CURRENT)
+  Elf_Half vd_flags;   // Bitwise flags (VER_DEF_*)
+  Elf_Half vd_ndx;     // Version index, used in .gnu.version entries
+  Elf_Half vd_cnt;     // Number of Verdaux entries
+  Elf_Word vd_hash;    // Hash of name
+  Elf_Word vd_aux;     // Offset to the first Verdaux entry (in bytes)
+  Elf_Word vd_next;    // Offset to the next Verdef entry (in bytes)
+
+  /// Get the first Verdaux entry for this Verdef.
+  const Elf_Verdaux *getAux() const {
+    return reinterpret_cast<const Elf_Verdaux *>((const char *)this + vd_aux);
+  }
+};
+
+/// Elf_Verdaux: This is the structure of auxiliary data in the SHT_GNU_verdef
+/// section (.gnu.version_d). This structure is identical for ELF32 and ELF64.
+template <class ELFT>
+struct Elf_Verdaux_Impl {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+  Elf_Word vda_name; // Version name (offset in string table)
+  Elf_Word vda_next; // Offset to next Verdaux entry (in bytes)
+};
+
+/// Elf_Verneed: This is the structure of entries in the SHT_GNU_verneed
+/// section (.gnu.version_r). This structure is identical for ELF32 and ELF64.
+template <class ELFT>
+struct Elf_Verneed_Impl {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+  Elf_Half vn_version; // Version of this structure (e.g. VER_NEED_CURRENT)
+  Elf_Half vn_cnt;     // Number of associated Vernaux entries
+  Elf_Word vn_file;    // Library name (string table offset)
+  Elf_Word vn_aux;     // Offset to first Vernaux entry (in bytes)
+  Elf_Word vn_next;    // Offset to next Verneed entry (in bytes)
+};
+
+/// Elf_Vernaux: This is the structure of auxiliary data in SHT_GNU_verneed
+/// section (.gnu.version_r). This structure is identical for ELF32 and ELF64.
+template <class ELFT>
+struct Elf_Vernaux_Impl {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+  Elf_Word vna_hash;  // Hash of dependency name
+  Elf_Half vna_flags; // Bitwise Flags (VER_FLAG_*)
+  Elf_Half vna_other; // Version index, used in .gnu.version entries
+  Elf_Word vna_name;  // Dependency name
+  Elf_Word vna_next;  // Offset to next Vernaux entry (in bytes)
+};
+
+/// Elf_Dyn_Base: This structure matches the form of entries in the dynamic
+///               table section (.dynamic) look like.
+template <class ELFT> struct Elf_Dyn_Base;
+
+template <endianness TargetEndianness>
+struct Elf_Dyn_Base<ELFType<TargetEndianness, false>> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, false)
+  Elf_Sword d_tag;
+  union {
+    Elf_Word d_val;
+    Elf_Addr d_ptr;
+  } d_un;
+};
+
+template <endianness TargetEndianness>
+struct Elf_Dyn_Base<ELFType<TargetEndianness, true>> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, true)
+  Elf_Sxword d_tag;
+  union {
+    Elf_Xword d_val;
+    Elf_Addr d_ptr;
+  } d_un;
+};
+
+/// Elf_Dyn_Impl: This inherits from Elf_Dyn_Base, adding getters.
+template <class ELFT>
+struct Elf_Dyn_Impl : Elf_Dyn_Base<ELFT> {
+  using Elf_Dyn_Base<ELFT>::d_tag;
+  using Elf_Dyn_Base<ELFT>::d_un;
+  using intX_t = typename std::conditional<ELFT::Is64Bits,
+                                           int64_t, int32_t>::type;
+  using uintX_t = typename std::conditional<ELFT::Is64Bits,
+                                            uint64_t, uint32_t>::type;
+  intX_t getTag() const { return d_tag; }
+  uintX_t getVal() const { return d_un.d_val; }
+  uintX_t getPtr() const { return d_un.d_ptr; }
+};
+
+template <endianness TargetEndianness>
+struct Elf_Rel_Impl<ELFType<TargetEndianness, false>, false> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, false)
+  static const bool IsRela = false;
+  Elf_Addr r_offset; // Location (file byte offset, or program virtual addr)
+  Elf_Word r_info;   // Symbol table index and type of relocation to apply
+
+  uint32_t getRInfo(bool isMips64EL) const {
+    assert(!isMips64EL);
+    return r_info;
+  }
+  void setRInfo(uint32_t R, bool IsMips64EL) {
+    assert(!IsMips64EL);
+    r_info = R;
+  }
+
+  // These accessors and mutators correspond to the ELF32_R_SYM, ELF32_R_TYPE,
+  // and ELF32_R_INFO macros defined in the ELF specification:
+  uint32_t getSymbol(bool isMips64EL) const {
+    return this->getRInfo(isMips64EL) >> 8;
+  }
+  unsigned char getType(bool isMips64EL) const {
+    return (unsigned char)(this->getRInfo(isMips64EL) & 0x0ff);
+  }
+  void setSymbol(uint32_t s, bool IsMips64EL) {
+    setSymbolAndType(s, getType(IsMips64EL), IsMips64EL);
+  }
+  void setType(unsigned char t, bool IsMips64EL) {
+    setSymbolAndType(getSymbol(IsMips64EL), t, IsMips64EL);
+  }
+  void setSymbolAndType(uint32_t s, unsigned char t, bool IsMips64EL) {
+    this->setRInfo((s << 8) + t, IsMips64EL);
+  }
+};
+
+template <endianness TargetEndianness>
+struct Elf_Rel_Impl<ELFType<TargetEndianness, false>, true>
+    : public Elf_Rel_Impl<ELFType<TargetEndianness, false>, false> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, false)
+  static const bool IsRela = true;
+  Elf_Sword r_addend; // Compute value for relocatable field by adding this
+};
+
+template <endianness TargetEndianness>
+struct Elf_Rel_Impl<ELFType<TargetEndianness, true>, false> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, true)
+  static const bool IsRela = false;
+  Elf_Addr r_offset; // Location (file byte offset, or program virtual addr)
+  Elf_Xword r_info;  // Symbol table index and type of relocation to apply
+
+  uint64_t getRInfo(bool isMips64EL) const {
+    uint64_t t = r_info;
+    if (!isMips64EL)
+      return t;
+    // Mips64 little endian has a "special" encoding of r_info. Instead of one
+    // 64 bit little endian number, it is a little endian 32 bit number followed
+    // by a 32 bit big endian number.
+    return (t << 32) | ((t >> 8) & 0xff000000) | ((t >> 24) & 0x00ff0000) |
+           ((t >> 40) & 0x0000ff00) | ((t >> 56) & 0x000000ff);
+  }
+
+  void setRInfo(uint64_t R, bool IsMips64EL) {
+    if (IsMips64EL)
+      r_info = (R >> 32) | ((R & 0xff000000) << 8) | ((R & 0x00ff0000) << 24) |
+               ((R & 0x0000ff00) << 40) | ((R & 0x000000ff) << 56);
+    else
+      r_info = R;
+  }
+
+  // These accessors and mutators correspond to the ELF64_R_SYM, ELF64_R_TYPE,
+  // and ELF64_R_INFO macros defined in the ELF specification:
+  uint32_t getSymbol(bool isMips64EL) const {
+    return (uint32_t)(this->getRInfo(isMips64EL) >> 32);
+  }
+  uint32_t getType(bool isMips64EL) const {
+    return (uint32_t)(this->getRInfo(isMips64EL) & 0xffffffffL);
+  }
+  void setSymbol(uint32_t s, bool IsMips64EL) {
+    setSymbolAndType(s, getType(IsMips64EL), IsMips64EL);
+  }
+  void setType(uint32_t t, bool IsMips64EL) {
+    setSymbolAndType(getSymbol(IsMips64EL), t, IsMips64EL);
+  }
+  void setSymbolAndType(uint32_t s, uint32_t t, bool IsMips64EL) {
+    this->setRInfo(((uint64_t)s << 32) + (t & 0xffffffffL), IsMips64EL);
+  }
+};
+
+template <endianness TargetEndianness>
+struct Elf_Rel_Impl<ELFType<TargetEndianness, true>, true>
+    : public Elf_Rel_Impl<ELFType<TargetEndianness, true>, false> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, true)
+  static const bool IsRela = true;
+  Elf_Sxword r_addend; // Compute value for relocatable field by adding this.
+};
+
+template <class ELFT>
+struct Elf_Ehdr_Impl {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+  unsigned char e_ident[ELF::EI_NIDENT]; // ELF Identification bytes
+  Elf_Half e_type;                       // Type of file (see ET_*)
+  Elf_Half e_machine;   // Required architecture for this file (see EM_*)
+  Elf_Word e_version;   // Must be equal to 1
+  Elf_Addr e_entry;     // Address to jump to in order to start program
+  Elf_Off e_phoff;      // Program header table's file offset, in bytes
+  Elf_Off e_shoff;      // Section header table's file offset, in bytes
+  Elf_Word e_flags;     // Processor-specific flags
+  Elf_Half e_ehsize;    // Size of ELF header, in bytes
+  Elf_Half e_phentsize; // Size of an entry in the program header table
+  Elf_Half e_phnum;     // Number of entries in the program header table
+  Elf_Half e_shentsize; // Size of an entry in the section header table
+  Elf_Half e_shnum;     // Number of entries in the section header table
+  Elf_Half e_shstrndx;  // Section header table index of section name
+                        // string table
+
+  bool checkMagic() const {
+    return (memcmp(e_ident, ELF::ElfMagic, strlen(ELF::ElfMagic))) == 0;
+  }
+
+  unsigned char getFileClass() const { return e_ident[ELF::EI_CLASS]; }
+  unsigned char getDataEncoding() const { return e_ident[ELF::EI_DATA]; }
+};
+
+template <endianness TargetEndianness>
+struct Elf_Phdr_Impl<ELFType<TargetEndianness, false>> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, false)
+  Elf_Word p_type;   // Type of segment
+  Elf_Off p_offset;  // FileOffset where segment is located, in bytes
+  Elf_Addr p_vaddr;  // Virtual Address of beginning of segment
+  Elf_Addr p_paddr;  // Physical address of beginning of segment (OS-specific)
+  Elf_Word p_filesz; // Num. of bytes in file image of segment (may be zero)
+  Elf_Word p_memsz;  // Num. of bytes in mem image of segment (may be zero)
+  Elf_Word p_flags;  // Segment flags
+  Elf_Word p_align;  // Segment alignment constraint
+};
+
+template <endianness TargetEndianness>
+struct Elf_Phdr_Impl<ELFType<TargetEndianness, true>> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, true)
+  Elf_Word p_type;    // Type of segment
+  Elf_Word p_flags;   // Segment flags
+  Elf_Off p_offset;   // FileOffset where segment is located, in bytes
+  Elf_Addr p_vaddr;   // Virtual Address of beginning of segment
+  Elf_Addr p_paddr;   // Physical address of beginning of segment (OS-specific)
+  Elf_Xword p_filesz; // Num. of bytes in file image of segment (may be zero)
+  Elf_Xword p_memsz;  // Num. of bytes in mem image of segment (may be zero)
+  Elf_Xword p_align;  // Segment alignment constraint
+};
+
+// ELFT needed for endianness.
+template <class ELFT>
+struct Elf_Hash_Impl {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+  Elf_Word nbucket;
+  Elf_Word nchain;
+
+  ArrayRef<Elf_Word> buckets() const {
+    return ArrayRef<Elf_Word>(&nbucket + 2, &nbucket + 2 + nbucket);
+  }
+
+  ArrayRef<Elf_Word> chains() const {
+    return ArrayRef<Elf_Word>(&nbucket + 2 + nbucket,
+                              &nbucket + 2 + nbucket + nchain);
+  }
+};
+
+// .gnu.hash section
+template <class ELFT>
+struct Elf_GnuHash_Impl {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+  Elf_Word nbuckets;
+  Elf_Word symndx;
+  Elf_Word maskwords;
+  Elf_Word shift2;
+
+  ArrayRef<Elf_Off> filter() const {
+    return ArrayRef<Elf_Off>(reinterpret_cast<const Elf_Off *>(&shift2 + 1),
+                             maskwords);
+  }
+
+  ArrayRef<Elf_Word> buckets() const {
+    return ArrayRef<Elf_Word>(
+        reinterpret_cast<const Elf_Word *>(filter().end()), nbuckets);
+  }
+
+  ArrayRef<Elf_Word> values(unsigned DynamicSymCount) const {
+    return ArrayRef<Elf_Word>(buckets().end(), DynamicSymCount - symndx);
+  }
+};
+
+// Compressed section headers.
+// http://www.sco.com/developers/gabi/latest/ch4.sheader.html#compression_header
+template <endianness TargetEndianness>
+struct Elf_Chdr_Impl<ELFType<TargetEndianness, false>> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, false)
+  Elf_Word ch_type;
+  Elf_Word ch_size;
+  Elf_Word ch_addralign;
+};
+
+template <endianness TargetEndianness>
+struct Elf_Chdr_Impl<ELFType<TargetEndianness, true>> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, true)
+  Elf_Word ch_type;
+  Elf_Word ch_reserved;
+  Elf_Xword ch_size;
+  Elf_Xword ch_addralign;
+};
+
+/// Note header
+template <class ELFT>
+struct Elf_Nhdr_Impl {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+  Elf_Word n_namesz;
+  Elf_Word n_descsz;
+  Elf_Word n_type;
+
+  /// The alignment of the name and descriptor.
+  ///
+  /// Implementations differ from the specification here: in practice all
+  /// variants align both the name and descriptor to 4-bytes.
+  static const unsigned int Align = 4;
+
+  /// Get the size of the note, including name, descriptor, and padding.
+  size_t getSize() const {
+    return sizeof(*this) + alignTo<Align>(n_namesz) + alignTo<Align>(n_descsz);
+  }
+};
+
+/// An ELF note.
+///
+/// Wraps a note header, providing methods for accessing the name and
+/// descriptor safely.
+template <class ELFT>
+class Elf_Note_Impl {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+
+  const Elf_Nhdr_Impl<ELFT> &Nhdr;
+
+  template <class NoteIteratorELFT> friend class Elf_Note_Iterator_Impl;
+
+public:
+  Elf_Note_Impl(const Elf_Nhdr_Impl<ELFT> &Nhdr) : Nhdr(Nhdr) {}
+
+  /// Get the note's name, excluding the terminating null byte.
+  StringRef getName() const {
+    if (!Nhdr.n_namesz)
+      return StringRef();
+    return StringRef(reinterpret_cast<const char *>(&Nhdr) + sizeof(Nhdr),
+                     Nhdr.n_namesz - 1);
+  }
+
+  /// Get the note's descriptor.
+  ArrayRef<uint8_t> getDesc() const {
+    if (!Nhdr.n_descsz)
+      return ArrayRef<uint8_t>();
+    return ArrayRef<uint8_t>(
+        reinterpret_cast<const uint8_t *>(&Nhdr) + sizeof(Nhdr) +
+          alignTo<Elf_Nhdr_Impl<ELFT>::Align>(Nhdr.n_namesz),
+        Nhdr.n_descsz);
+  }
+
+  /// Get the note's type.
+  Elf_Word getType() const { return Nhdr.n_type; }
+};
+
+template <class ELFT>
+class Elf_Note_Iterator_Impl
+    : std::iterator<std::forward_iterator_tag, Elf_Note_Impl<ELFT>> {
+  // Nhdr being a nullptr marks the end of iteration.
+  const Elf_Nhdr_Impl<ELFT> *Nhdr = nullptr;
+  size_t RemainingSize = 0u;
+  Error *Err = nullptr;
+
+  template <class ELFFileELFT> friend class ELFFile;
+
+  // Stop iteration and indicate an overflow.
+  void stopWithOverflowError() {
+    Nhdr = nullptr;
+    *Err = make_error<StringError>("ELF note overflows container",
+                                   object_error::parse_failed);
+  }
+
+  // Advance Nhdr by NoteSize bytes, starting from NhdrPos.
+  //
+  // Assumes NoteSize <= RemainingSize. Ensures Nhdr->getSize() <= RemainingSize
+  // upon returning. Handles stopping iteration when reaching the end of the
+  // container, either cleanly or with an overflow error.
+  void advanceNhdr(const uint8_t *NhdrPos, size_t NoteSize) {
+    RemainingSize -= NoteSize;
+    if (RemainingSize == 0u) {
+      // Ensure that if the iterator walks to the end, the error is checked
+      // afterwards.
+      *Err = Error::success();
+      Nhdr = nullptr;
+    } else if (sizeof(*Nhdr) > RemainingSize)
+      stopWithOverflowError();
+    else {
+      Nhdr = reinterpret_cast<const Elf_Nhdr_Impl<ELFT> *>(NhdrPos + NoteSize);
+      if (Nhdr->getSize() > RemainingSize)
+        stopWithOverflowError();
+      else
+        *Err = Error::success();
+    }
+  }
+
+  Elf_Note_Iterator_Impl() {}
+  explicit Elf_Note_Iterator_Impl(Error &Err) : Err(&Err) {}
+  Elf_Note_Iterator_Impl(const uint8_t *Start, size_t Size, Error &Err)
+      : RemainingSize(Size), Err(&Err) {
+    consumeError(std::move(Err));
+    assert(Start && "ELF note iterator starting at NULL");
+    advanceNhdr(Start, 0u);
+  }
+
+public:
+  Elf_Note_Iterator_Impl &operator++() {
+    assert(Nhdr && "incremented ELF note end iterator");
+    const uint8_t *NhdrPos = reinterpret_cast<const uint8_t *>(Nhdr);
+    size_t NoteSize = Nhdr->getSize();
+    advanceNhdr(NhdrPos, NoteSize);
+    return *this;
+  }
+  bool operator==(Elf_Note_Iterator_Impl Other) const {
+    if (!Nhdr && Other.Err)
+      (void)(bool)(*Other.Err);
+    if (!Other.Nhdr && Err)
+      (void)(bool)(*Err);
+    return Nhdr == Other.Nhdr;
+  }
+  bool operator!=(Elf_Note_Iterator_Impl Other) const {
+    return !(*this == Other);
+  }
+  Elf_Note_Impl<ELFT> operator*() const {
+    assert(Nhdr && "dereferenced ELF note end iterator");
+    return Elf_Note_Impl<ELFT>(*Nhdr);
+  }
+};
+
+template <class ELFT> struct Elf_CGProfile_Impl {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+  Elf_Word cgp_from;
+  Elf_Word cgp_to;
+  Elf_Xword cgp_weight;
+};
+
+// MIPS .reginfo section
+template <class ELFT>
+struct Elf_Mips_RegInfo;
+
+template <support::endianness TargetEndianness>
+struct Elf_Mips_RegInfo<ELFType<TargetEndianness, false>> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, false)
+  Elf_Word ri_gprmask;     // bit-mask of used general registers
+  Elf_Word ri_cprmask[4];  // bit-mask of used co-processor registers
+  Elf_Addr ri_gp_value;    // gp register value
+};
+
+template <support::endianness TargetEndianness>
+struct Elf_Mips_RegInfo<ELFType<TargetEndianness, true>> {
+  LLVM_ELF_IMPORT_TYPES(TargetEndianness, true)
+  Elf_Word ri_gprmask;     // bit-mask of used general registers
+  Elf_Word ri_pad;         // unused padding field
+  Elf_Word ri_cprmask[4];  // bit-mask of used co-processor registers
+  Elf_Addr ri_gp_value;    // gp register value
+};
+
+// .MIPS.options section
+template <class ELFT> struct Elf_Mips_Options {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+  uint8_t kind;     // Determines interpretation of variable part of descriptor
+  uint8_t size;     // Byte size of descriptor, including this header
+  Elf_Half section; // Section header index of section affected,
+                    // or 0 for global options
+  Elf_Word info;    // Kind-specific information
+
+  Elf_Mips_RegInfo<ELFT> &getRegInfo() {
+    assert(kind == ELF::ODK_REGINFO);
+    return *reinterpret_cast<Elf_Mips_RegInfo<ELFT> *>(
+        (uint8_t *)this + sizeof(Elf_Mips_Options));
+  }
+  const Elf_Mips_RegInfo<ELFT> &getRegInfo() const {
+    return const_cast<Elf_Mips_Options *>(this)->getRegInfo();
+  }
+};
+
+// .MIPS.abiflags section content
+template <class ELFT> struct Elf_Mips_ABIFlags {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+  Elf_Half version;  // Version of the structure
+  uint8_t isa_level; // ISA level: 1-5, 32, and 64
+  uint8_t isa_rev;   // ISA revision (0 for MIPS I - MIPS V)
+  uint8_t gpr_size;  // General purpose registers size
+  uint8_t cpr1_size; // Co-processor 1 registers size
+  uint8_t cpr2_size; // Co-processor 2 registers size
+  uint8_t fp_abi;    // Floating-point ABI flag
+  Elf_Word isa_ext;  // Processor-specific extension
+  Elf_Word ases;     // ASEs flags
+  Elf_Word flags1;   // General flags
+  Elf_Word flags2;   // General flags
+};
+
+} // end namespace object.
+} // end namespace llvm.
+
+#endif // LLVM_OBJECT_ELFTYPES_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Object/Error.h b/binaryen/third_party/llvm-project/include/llvm/Object/Error.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Object/Error.h
@@ -0,0 +1,92 @@
+//===- Error.h - system_error extensions for Object -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This declares a new error_category for the Object library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_ERROR_H
+#define LLVM_OBJECT_ERROR_H
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Error.h"
+#include <system_error>
+
+namespace llvm {
+namespace object {
+
+class Binary;
+
+const std::error_category &object_category();
+
+enum class object_error {
+  // Error code 0 is absent. Use std::error_code() instead.
+  arch_not_found = 1,
+  invalid_file_type,
+  parse_failed,
+  unexpected_eof,
+  string_table_non_null_end,
+  invalid_section_index,
+  bitcode_section_not_found,
+  invalid_symbol_index,
+};
+
+inline std::error_code make_error_code(object_error e) {
+  return std::error_code(static_cast<int>(e), object_category());
+}
+
+/// Base class for all errors indicating malformed binary files.
+///
+/// Having a subclass for all malformed binary files allows archive-walking
+/// code to skip malformed files without having to understand every possible
+/// way that a binary file might be malformed.
+///
+/// Currently inherits from ECError for easy interoperability with
+/// std::error_code, but this will be removed in the future.
+class BinaryError : public ErrorInfo<BinaryError, ECError> {
+  virtual void anchor();
+public:
+  static char ID;
+  BinaryError() {
+    // Default to parse_failed, can be overridden with setErrorCode.
+    setErrorCode(make_error_code(object_error::parse_failed));
+  }
+};
+
+/// Generic binary error.
+///
+/// For errors that don't require their own specific sub-error (most errors)
+/// this class can be used to describe the error via a string message.
+class GenericBinaryError : public ErrorInfo<GenericBinaryError, BinaryError> {
+public:
+  static char ID;
+  GenericBinaryError(Twine Msg);
+  GenericBinaryError(Twine Msg, object_error ECOverride);
+  const std::string &getMessage() const { return Msg; }
+  void log(raw_ostream &OS) const override;
+private:
+  std::string Msg;
+};
+
+/// isNotObjectErrorInvalidFileType() is used when looping through the children
+/// of an archive after calling getAsBinary() on the child and it returns an
+/// llvm::Error.  In the cases we want to loop through the children and ignore the
+/// non-objects in the archive this is used to test the error to see if an
+/// error() function needs to called on the llvm::Error.
+Error isNotObjectErrorInvalidFileType(llvm::Error Err);
+
+} // end namespace object.
+
+} // end namespace llvm.
+
+namespace std {
+template <>
+struct is_error_code_enum<llvm::object::object_error> : std::true_type {};
+}
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Object/MachO.h b/binaryen/third_party/llvm-project/include/llvm/Object/MachO.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Object/MachO.h
@@ -0,0 +1,737 @@
+//===- MachO.h - MachO object file implementation ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the MachOObjectFile class, which implement the ObjectFile
+// interface for MachO files.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_MACHO_H
+#define LLVM_OBJECT_MACHO_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <system_error>
+
+namespace llvm {
+namespace object {
+
+/// DiceRef - This is a value type class that represents a single
+/// data in code entry in the table in a Mach-O object file.
+class DiceRef {
+  DataRefImpl DicePimpl;
+  const ObjectFile *OwningObject = nullptr;
+
+public:
+  DiceRef() = default;
+  DiceRef(DataRefImpl DiceP, const ObjectFile *Owner);
+
+  bool operator==(const DiceRef &Other) const;
+  bool operator<(const DiceRef &Other) const;
+
+  void moveNext();
+
+  std::error_code getOffset(uint32_t &Result) const;
+  std::error_code getLength(uint16_t &Result) const;
+  std::error_code getKind(uint16_t &Result) const;
+
+  DataRefImpl getRawDataRefImpl() const;
+  const ObjectFile *getObjectFile() const;
+};
+using dice_iterator = content_iterator<DiceRef>;
+
+/// ExportEntry encapsulates the current-state-of-the-walk used when doing a
+/// non-recursive walk of the trie data structure.  This allows you to iterate
+/// across all exported symbols using:
+///      Error Err;
+///      for (const llvm::object::ExportEntry &AnExport : Obj->exports(&Err)) {
+///      }
+///      if (Err) { report error ...
+class ExportEntry {
+public:
+  ExportEntry(Error *Err, const MachOObjectFile *O, ArrayRef<uint8_t> Trie);
+
+  StringRef name() const;
+  uint64_t flags() const;
+  uint64_t address() const;
+  uint64_t other() const;
+  StringRef otherName() const;
+  uint32_t nodeOffset() const;
+
+  bool operator==(const ExportEntry &) const;
+
+  void moveNext();
+
+private:
+  friend class MachOObjectFile;
+
+  void moveToFirst();
+  void moveToEnd();
+  uint64_t readULEB128(const uint8_t *&p, const char **error);
+  void pushDownUntilBottom();
+  void pushNode(uint64_t Offset);
+
+  // Represents a node in the mach-o exports trie.
+  struct NodeState {
+    NodeState(const uint8_t *Ptr);
+
+    const uint8_t *Start;
+    const uint8_t *Current;
+    uint64_t Flags = 0;
+    uint64_t Address = 0;
+    uint64_t Other = 0;
+    const char *ImportName = nullptr;
+    unsigned ChildCount = 0;
+    unsigned NextChildIndex = 0;
+    unsigned ParentStringLength = 0;
+    bool IsExportNode = false;
+  };
+  using NodeList = SmallVector<NodeState, 16>;
+  using node_iterator = NodeList::const_iterator;
+
+  Error *E;
+  const MachOObjectFile *O;
+  ArrayRef<uint8_t> Trie;
+  SmallString<256> CumulativeString;
+  NodeList Stack;
+  bool Done = false;
+
+  iterator_range<node_iterator> nodes() const {
+    return make_range(Stack.begin(), Stack.end());
+  }
+};
+using export_iterator = content_iterator<ExportEntry>;
+
+// Segment info so SegIndex/SegOffset pairs in a Mach-O Bind or Rebase entry
+// can be checked and translated.  Only the SegIndex/SegOffset pairs from
+// checked entries are to be used with the segmentName(), sectionName() and
+// address() methods below.
+class BindRebaseSegInfo {
+public:
+  BindRebaseSegInfo(const MachOObjectFile *Obj);
+
+  // Used to check a Mach-O Bind or Rebase entry for errors when iterating.
+  const char* checkSegAndOffsets(int32_t SegIndex, uint64_t SegOffset,
+                                 uint8_t PointerSize, uint32_t Count=1,
+                                 uint32_t Skip=0);
+  // Used with valid SegIndex/SegOffset values from checked entries.
+  StringRef segmentName(int32_t SegIndex);
+  StringRef sectionName(int32_t SegIndex, uint64_t SegOffset);
+  uint64_t address(uint32_t SegIndex, uint64_t SegOffset);
+
+private:
+  struct SectionInfo {
+    uint64_t Address;
+    uint64_t Size;
+    StringRef SectionName;
+    StringRef SegmentName;
+    uint64_t OffsetInSegment;
+    uint64_t SegmentStartAddress;
+    int32_t SegmentIndex;
+  };
+  const SectionInfo &findSection(int32_t SegIndex, uint64_t SegOffset);
+
+  SmallVector<SectionInfo, 32> Sections;
+  int32_t MaxSegIndex;
+};
+
+/// MachORebaseEntry encapsulates the current state in the decompression of
+/// rebasing opcodes. This allows you to iterate through the compressed table of
+/// rebasing using:
+///    Error Err;
+///    for (const llvm::object::MachORebaseEntry &Entry : Obj->rebaseTable(&Err)) {
+///    }
+///    if (Err) { report error ...
+class MachORebaseEntry {
+public:
+  MachORebaseEntry(Error *Err, const MachOObjectFile *O,
+                   ArrayRef<uint8_t> opcodes, bool is64Bit);
+
+  int32_t segmentIndex() const;
+  uint64_t segmentOffset() const;
+  StringRef typeName() const;
+  StringRef segmentName() const;
+  StringRef sectionName() const;
+  uint64_t address() const;
+
+  bool operator==(const MachORebaseEntry &) const;
+
+  void moveNext();
+
+private:
+  friend class MachOObjectFile;
+
+  void moveToFirst();
+  void moveToEnd();
+  uint64_t readULEB128(const char **error);
+
+  Error *E;
+  const MachOObjectFile *O;
+  ArrayRef<uint8_t> Opcodes;
+  const uint8_t *Ptr;
+  uint64_t SegmentOffset = 0;
+  int32_t SegmentIndex = -1;
+  uint64_t RemainingLoopCount = 0;
+  uint64_t AdvanceAmount = 0;
+  uint8_t  RebaseType = 0;
+  uint8_t  PointerSize;
+  bool     Done = false;
+};
+using rebase_iterator = content_iterator<MachORebaseEntry>;
+
+/// MachOBindEntry encapsulates the current state in the decompression of
+/// binding opcodes. This allows you to iterate through the compressed table of
+/// bindings using:
+///    Error Err;
+///    for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable(&Err)) {
+///    }
+///    if (Err) { report error ...
+class MachOBindEntry {
+public:
+  enum class Kind { Regular, Lazy, Weak };
+
+  MachOBindEntry(Error *Err, const MachOObjectFile *O,
+                 ArrayRef<uint8_t> Opcodes, bool is64Bit, MachOBindEntry::Kind);
+
+  int32_t segmentIndex() const;
+  uint64_t segmentOffset() const;
+  StringRef typeName() const;
+  StringRef symbolName() const;
+  uint32_t flags() const;
+  int64_t addend() const;
+  int ordinal() const;
+
+  StringRef segmentName() const;
+  StringRef sectionName() const;
+  uint64_t address() const;
+
+  bool operator==(const MachOBindEntry &) const;
+
+  void moveNext();
+
+private:
+  friend class MachOObjectFile;
+
+  void moveToFirst();
+  void moveToEnd();
+  uint64_t readULEB128(const char **error);
+  int64_t readSLEB128(const char **error);
+
+  Error *E;
+  const MachOObjectFile *O;
+  ArrayRef<uint8_t> Opcodes;
+  const uint8_t *Ptr;
+  uint64_t SegmentOffset = 0;
+  int32_t  SegmentIndex = -1;
+  StringRef SymbolName;
+  bool     LibraryOrdinalSet = false;
+  int      Ordinal = 0;
+  uint32_t Flags = 0;
+  int64_t  Addend = 0;
+  uint64_t RemainingLoopCount = 0;
+  uint64_t AdvanceAmount = 0;
+  uint8_t  BindType = 0;
+  uint8_t  PointerSize;
+  Kind     TableKind;
+  bool     Done = false;
+};
+using bind_iterator = content_iterator<MachOBindEntry>;
+
+class MachOObjectFile : public ObjectFile {
+public:
+  struct LoadCommandInfo {
+    const char *Ptr;      // Where in memory the load command is.
+    MachO::load_command C; // The command itself.
+  };
+  using LoadCommandList = SmallVector<LoadCommandInfo, 4>;
+  using load_command_iterator = LoadCommandList::const_iterator;
+
+  static Expected<std::unique_ptr<MachOObjectFile>>
+  create(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits,
+         uint32_t UniversalCputype = 0, uint32_t UniversalIndex = 0);
+
+  void moveSymbolNext(DataRefImpl &Symb) const override;
+
+  uint64_t getNValue(DataRefImpl Sym) const;
+  Expected<StringRef> getSymbolName(DataRefImpl Symb) const override;
+
+  // MachO specific.
+  Error checkSymbolTable() const;
+
+  std::error_code getIndirectName(DataRefImpl Symb, StringRef &Res) const;
+  unsigned getSectionType(SectionRef Sec) const;
+
+  Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override;
+  uint32_t getSymbolAlignment(DataRefImpl Symb) const override;
+  uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override;
+  Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override;
+  uint32_t getSymbolFlags(DataRefImpl Symb) const override;
+  Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override;
+  unsigned getSymbolSectionID(SymbolRef Symb) const;
+  unsigned getSectionID(SectionRef Sec) const;
+
+  void moveSectionNext(DataRefImpl &Sec) const override;
+  Expected<StringRef> getSectionName(DataRefImpl Sec) const override;
+  uint64_t getSectionAddress(DataRefImpl Sec) const override;
+  uint64_t getSectionIndex(DataRefImpl Sec) const override;
+  uint64_t getSectionSize(DataRefImpl Sec) const override;
+  ArrayRef<uint8_t> getSectionContents(uint32_t Offset, uint64_t Size) const;
+  Expected<ArrayRef<uint8_t>>
+  getSectionContents(DataRefImpl Sec) const override;
+  uint64_t getSectionAlignment(DataRefImpl Sec) const override;
+  Expected<SectionRef> getSection(unsigned SectionIndex) const;
+  Expected<SectionRef> getSection(StringRef SectionName) const;
+  bool isSectionCompressed(DataRefImpl Sec) const override;
+  bool isSectionText(DataRefImpl Sec) const override;
+  bool isSectionData(DataRefImpl Sec) const override;
+  bool isSectionBSS(DataRefImpl Sec) const override;
+  bool isSectionVirtual(DataRefImpl Sec) const override;
+  bool isSectionBitcode(DataRefImpl Sec) const override;
+
+  /// When dsymutil generates the companion file, it strips all unnecessary
+  /// sections (e.g. everything in the _TEXT segment) by omitting their body
+  /// and setting the offset in their corresponding load command to zero.
+  ///
+  /// While the load command itself is valid, reading the section corresponds
+  /// to reading the number of bytes specified in the load command, starting
+  /// from offset 0 (i.e. the Mach-O header at the beginning of the file).
+  bool isSectionStripped(DataRefImpl Sec) const override;
+
+  relocation_iterator section_rel_begin(DataRefImpl Sec) const override;
+  relocation_iterator section_rel_end(DataRefImpl Sec) const override;
+
+  relocation_iterator extrel_begin() const;
+  relocation_iterator extrel_end() const;
+  iterator_range<relocation_iterator> external_relocations() const {
+    return make_range(extrel_begin(), extrel_end());
+  }
+
+  relocation_iterator locrel_begin() const;
+  relocation_iterator locrel_end() const;
+
+  void moveRelocationNext(DataRefImpl &Rel) const override;
+  uint64_t getRelocationOffset(DataRefImpl Rel) const override;
+  symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override;
+  section_iterator getRelocationSection(DataRefImpl Rel) const;
+  uint64_t getRelocationType(DataRefImpl Rel) const override;
+  void getRelocationTypeName(DataRefImpl Rel,
+                             SmallVectorImpl<char> &Result) const override;
+  uint8_t getRelocationLength(DataRefImpl Rel) const;
+
+  // MachO specific.
+  std::error_code getLibraryShortNameByIndex(unsigned Index, StringRef &) const;
+  uint32_t getLibraryCount() const;
+
+  section_iterator getRelocationRelocatedSection(relocation_iterator Rel) const;
+
+  // TODO: Would be useful to have an iterator based version
+  // of the load command interface too.
+
+  basic_symbol_iterator symbol_begin() const override;
+  basic_symbol_iterator symbol_end() const override;
+
+  // MachO specific.
+  symbol_iterator getSymbolByIndex(unsigned Index) const;
+  uint64_t getSymbolIndex(DataRefImpl Symb) const;
+
+  section_iterator section_begin() const override;
+  section_iterator section_end() const override;
+
+  uint8_t getBytesInAddress() const override;
+
+  StringRef getFileFormatName() const override;
+  Triple::ArchType getArch() const override;
+  SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); }
+  Triple getArchTriple(const char **McpuDefault = nullptr) const;
+
+  relocation_iterator section_rel_begin(unsigned Index) const;
+  relocation_iterator section_rel_end(unsigned Index) const;
+
+  dice_iterator begin_dices() const;
+  dice_iterator end_dices() const;
+
+  load_command_iterator begin_load_commands() const;
+  load_command_iterator end_load_commands() const;
+  iterator_range<load_command_iterator> load_commands() const;
+
+  /// For use iterating over all exported symbols.
+  iterator_range<export_iterator> exports(Error &Err) const;
+
+  /// For use examining a trie not in a MachOObjectFile.
+  static iterator_range<export_iterator> exports(Error &Err,
+                                                 ArrayRef<uint8_t> Trie,
+                                                 const MachOObjectFile *O =
+                                                                      nullptr);
+
+  /// For use iterating over all rebase table entries.
+  iterator_range<rebase_iterator> rebaseTable(Error &Err);
+
+  /// For use examining rebase opcodes in a MachOObjectFile.
+  static iterator_range<rebase_iterator> rebaseTable(Error &Err,
+                                                     MachOObjectFile *O,
+                                                     ArrayRef<uint8_t> Opcodes,
+                                                     bool is64);
+
+  /// For use iterating over all bind table entries.
+  iterator_range<bind_iterator> bindTable(Error &Err);
+
+  /// For use iterating over all lazy bind table entries.
+  iterator_range<bind_iterator> lazyBindTable(Error &Err);
+
+  /// For use iterating over all weak bind table entries.
+  iterator_range<bind_iterator> weakBindTable(Error &Err);
+
+  /// For use examining bind opcodes in a MachOObjectFile.
+  static iterator_range<bind_iterator> bindTable(Error &Err,
+                                                 MachOObjectFile *O,
+                                                 ArrayRef<uint8_t> Opcodes,
+                                                 bool is64,
+                                                 MachOBindEntry::Kind);
+
+  // Given a SegIndex, SegOffset, and PointerSize, verify a valid section exists
+  // that fully contains a pointer at that location. Multiple fixups in a bind
+  // (such as with the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode) can
+  // be tested via the Count and Skip parameters.
+  //
+  // This is used by MachOBindEntry::moveNext() to validate a MachOBindEntry.
+  const char *BindEntryCheckSegAndOffsets(int32_t SegIndex, uint64_t SegOffset,
+                                         uint8_t PointerSize, uint32_t Count=1,
+                                          uint32_t Skip=0) const {
+    return BindRebaseSectionTable->checkSegAndOffsets(SegIndex, SegOffset,
+                                                     PointerSize, Count, Skip);
+  }
+
+  // Given a SegIndex, SegOffset, and PointerSize, verify a valid section exists
+  // that fully contains a pointer at that location. Multiple fixups in a rebase
+  // (such as with the REBASE_OPCODE_DO_*_TIMES* opcodes) can be tested via the
+  // Count and Skip parameters.
+  //
+  // This is used by MachORebaseEntry::moveNext() to validate a MachORebaseEntry
+  const char *RebaseEntryCheckSegAndOffsets(int32_t SegIndex,
+                                            uint64_t SegOffset,
+                                            uint8_t PointerSize,
+                                            uint32_t Count=1,
+                                            uint32_t Skip=0) const {
+    return BindRebaseSectionTable->checkSegAndOffsets(SegIndex, SegOffset,
+                                                      PointerSize, Count, Skip);
+  }
+
+  /// For use with the SegIndex of a checked Mach-O Bind or Rebase entry to
+  /// get the segment name.
+  StringRef BindRebaseSegmentName(int32_t SegIndex) const {
+    return BindRebaseSectionTable->segmentName(SegIndex);
+  }
+
+  /// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or
+  /// Rebase entry to get the section name.
+  StringRef BindRebaseSectionName(uint32_t SegIndex, uint64_t SegOffset) const {
+    return BindRebaseSectionTable->sectionName(SegIndex, SegOffset);
+  }
+
+  /// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or
+  /// Rebase entry to get the address.
+  uint64_t BindRebaseAddress(uint32_t SegIndex, uint64_t SegOffset) const {
+    return BindRebaseSectionTable->address(SegIndex, SegOffset);
+  }
+
+  // In a MachO file, sections have a segment name. This is used in the .o
+  // files. They have a single segment, but this field specifies which segment
+  // a section should be put in the final object.
+  StringRef getSectionFinalSegmentName(DataRefImpl Sec) const;
+
+  // Names are stored as 16 bytes. These returns the raw 16 bytes without
+  // interpreting them as a C string.
+  ArrayRef<char> getSectionRawName(DataRefImpl Sec) const;
+  ArrayRef<char> getSectionRawFinalSegmentName(DataRefImpl Sec) const;
+
+  // MachO specific Info about relocations.
+  bool isRelocationScattered(const MachO::any_relocation_info &RE) const;
+  unsigned getPlainRelocationSymbolNum(
+                                    const MachO::any_relocation_info &RE) const;
+  bool getPlainRelocationExternal(const MachO::any_relocation_info &RE) const;
+  bool getScatteredRelocationScattered(
+                                    const MachO::any_relocation_info &RE) const;
+  uint32_t getScatteredRelocationValue(
+                                    const MachO::any_relocation_info &RE) const;
+  uint32_t getScatteredRelocationType(
+                                    const MachO::any_relocation_info &RE) const;
+  unsigned getAnyRelocationAddress(const MachO::any_relocation_info &RE) const;
+  unsigned getAnyRelocationPCRel(const MachO::any_relocation_info &RE) const;
+  unsigned getAnyRelocationLength(const MachO::any_relocation_info &RE) const;
+  unsigned getAnyRelocationType(const MachO::any_relocation_info &RE) const;
+  SectionRef getAnyRelocationSection(const MachO::any_relocation_info &RE) const;
+
+  // MachO specific structures.
+  MachO::section getSection(DataRefImpl DRI) const;
+  MachO::section_64 getSection64(DataRefImpl DRI) const;
+  MachO::section getSection(const LoadCommandInfo &L, unsigned Index) const;
+  MachO::section_64 getSection64(const LoadCommandInfo &L,unsigned Index) const;
+  MachO::nlist getSymbolTableEntry(DataRefImpl DRI) const;
+  MachO::nlist_64 getSymbol64TableEntry(DataRefImpl DRI) const;
+
+  MachO::linkedit_data_command
+  getLinkeditDataLoadCommand(const LoadCommandInfo &L) const;
+  MachO::segment_command
+  getSegmentLoadCommand(const LoadCommandInfo &L) const;
+  MachO::segment_command_64
+  getSegment64LoadCommand(const LoadCommandInfo &L) const;
+  MachO::linker_option_command
+  getLinkerOptionLoadCommand(const LoadCommandInfo &L) const;
+  MachO::version_min_command
+  getVersionMinLoadCommand(const LoadCommandInfo &L) const;
+  MachO::note_command
+  getNoteLoadCommand(const LoadCommandInfo &L) const;
+  MachO::build_version_command
+  getBuildVersionLoadCommand(const LoadCommandInfo &L) const;
+  MachO::build_tool_version
+  getBuildToolVersion(unsigned index) const;
+  MachO::dylib_command
+  getDylibIDLoadCommand(const LoadCommandInfo &L) const;
+  MachO::dyld_info_command
+  getDyldInfoLoadCommand(const LoadCommandInfo &L) const;
+  MachO::dylinker_command
+  getDylinkerCommand(const LoadCommandInfo &L) const;
+  MachO::uuid_command
+  getUuidCommand(const LoadCommandInfo &L) const;
+  MachO::rpath_command
+  getRpathCommand(const LoadCommandInfo &L) const;
+  MachO::source_version_command
+  getSourceVersionCommand(const LoadCommandInfo &L) const;
+  MachO::entry_point_command
+  getEntryPointCommand(const LoadCommandInfo &L) const;
+  MachO::encryption_info_command
+  getEncryptionInfoCommand(const LoadCommandInfo &L) const;
+  MachO::encryption_info_command_64
+  getEncryptionInfoCommand64(const LoadCommandInfo &L) const;
+  MachO::sub_framework_command
+  getSubFrameworkCommand(const LoadCommandInfo &L) const;
+  MachO::sub_umbrella_command
+  getSubUmbrellaCommand(const LoadCommandInfo &L) const;
+  MachO::sub_library_command
+  getSubLibraryCommand(const LoadCommandInfo &L) const;
+  MachO::sub_client_command
+  getSubClientCommand(const LoadCommandInfo &L) const;
+  MachO::routines_command
+  getRoutinesCommand(const LoadCommandInfo &L) const;
+  MachO::routines_command_64
+  getRoutinesCommand64(const LoadCommandInfo &L) const;
+  MachO::thread_command
+  getThreadCommand(const LoadCommandInfo &L) const;
+
+  MachO::any_relocation_info getRelocation(DataRefImpl Rel) const;
+  MachO::data_in_code_entry getDice(DataRefImpl Rel) const;
+  const MachO::mach_header &getHeader() const;
+  const MachO::mach_header_64 &getHeader64() const;
+  uint32_t
+  getIndirectSymbolTableEntry(const MachO::dysymtab_command &DLC,
+                              unsigned Index) const;
+  MachO::data_in_code_entry getDataInCodeTableEntry(uint32_t DataOffset,
+                                                    unsigned Index) const;
+  MachO::symtab_command getSymtabLoadCommand() const;
+  MachO::dysymtab_command getDysymtabLoadCommand() const;
+  MachO::linkedit_data_command getDataInCodeLoadCommand() const;
+  MachO::linkedit_data_command getLinkOptHintsLoadCommand() const;
+  ArrayRef<uint8_t> getDyldInfoRebaseOpcodes() const;
+  ArrayRef<uint8_t> getDyldInfoBindOpcodes() const;
+  ArrayRef<uint8_t> getDyldInfoWeakBindOpcodes() const;
+  ArrayRef<uint8_t> getDyldInfoLazyBindOpcodes() const;
+  ArrayRef<uint8_t> getDyldInfoExportsTrie() const;
+  ArrayRef<uint8_t> getUuid() const;
+
+  StringRef getStringTableData() const;
+  bool is64Bit() const;
+  void ReadULEB128s(uint64_t Index, SmallVectorImpl<uint64_t> &Out) const;
+
+  static StringRef guessLibraryShortName(StringRef Name, bool &isFramework,
+                                         StringRef &Suffix);
+
+  static Triple::ArchType getArch(uint32_t CPUType);
+  static Triple getArchTriple(uint32_t CPUType, uint32_t CPUSubType,
+                              const char **McpuDefault = nullptr,
+                              const char **ArchFlag = nullptr);
+  static bool isValidArch(StringRef ArchFlag);
+  static ArrayRef<StringRef> getValidArchs();
+  static Triple getHostArch();
+
+  bool isRelocatableObject() const override;
+
+  StringRef mapDebugSectionName(StringRef Name) const override;
+
+  bool hasPageZeroSegment() const { return HasPageZeroSegment; }
+
+  static bool classof(const Binary *v) {
+    return v->isMachO();
+  }
+
+  static uint32_t
+  getVersionMinMajor(MachO::version_min_command &C, bool SDK) {
+    uint32_t VersionOrSDK = (SDK) ? C.sdk : C.version;
+    return (VersionOrSDK >> 16) & 0xffff;
+  }
+
+  static uint32_t
+  getVersionMinMinor(MachO::version_min_command &C, bool SDK) {
+    uint32_t VersionOrSDK = (SDK) ? C.sdk : C.version;
+    return (VersionOrSDK >> 8) & 0xff;
+  }
+
+  static uint32_t
+  getVersionMinUpdate(MachO::version_min_command &C, bool SDK) {
+    uint32_t VersionOrSDK = (SDK) ? C.sdk : C.version;
+    return VersionOrSDK & 0xff;
+  }
+
+  static std::string getBuildPlatform(uint32_t platform) {
+    switch (platform) {
+    case MachO::PLATFORM_MACOS: return "macos";
+    case MachO::PLATFORM_IOS: return "ios";
+    case MachO::PLATFORM_TVOS: return "tvos";
+    case MachO::PLATFORM_WATCHOS: return "watchos";
+    case MachO::PLATFORM_BRIDGEOS: return "bridgeos";
+    case MachO::PLATFORM_MACCATALYST: return "macCatalyst";
+    case MachO::PLATFORM_IOSSIMULATOR: return "iossimulator";
+    case MachO::PLATFORM_TVOSSIMULATOR: return "tvossimulator";
+    case MachO::PLATFORM_WATCHOSSIMULATOR: return "watchossimulator";
+    default:
+      std::string ret;
+      raw_string_ostream ss(ret);
+      ss << format_hex(platform, 8, true);
+      return ss.str();
+    }
+  }
+
+  static std::string getBuildTool(uint32_t tools) {
+    switch (tools) {
+    case MachO::TOOL_CLANG: return "clang";
+    case MachO::TOOL_SWIFT: return "swift";
+    case MachO::TOOL_LD: return "ld";
+    default:
+      std::string ret;
+      raw_string_ostream ss(ret);
+      ss << format_hex(tools, 8, true);
+      return ss.str();
+    }
+  }
+
+  static std::string getVersionString(uint32_t version) {
+    uint32_t major = (version >> 16) & 0xffff;
+    uint32_t minor = (version >> 8) & 0xff;
+    uint32_t update = version & 0xff;
+
+    SmallString<32> Version;
+    Version = utostr(major) + "." + utostr(minor);
+    if (update != 0)
+      Version += "." + utostr(update);
+    return Version.str();
+  }
+
+private:
+  MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits,
+                  Error &Err, uint32_t UniversalCputype = 0,
+                  uint32_t UniversalIndex = 0);
+
+  uint64_t getSymbolValueImpl(DataRefImpl Symb) const override;
+
+  union {
+    MachO::mach_header_64 Header64;
+    MachO::mach_header Header;
+  };
+  using SectionList = SmallVector<const char*, 1>;
+  SectionList Sections;
+  using LibraryList = SmallVector<const char*, 1>;
+  LibraryList Libraries;
+  LoadCommandList LoadCommands;
+  using LibraryShortName = SmallVector<StringRef, 1>;
+  using BuildToolList = SmallVector<const char*, 1>;
+  BuildToolList BuildTools;
+  mutable LibraryShortName LibrariesShortNames;
+  std::unique_ptr<BindRebaseSegInfo> BindRebaseSectionTable;
+  const char *SymtabLoadCmd = nullptr;
+  const char *DysymtabLoadCmd = nullptr;
+  const char *DataInCodeLoadCmd = nullptr;
+  const char *LinkOptHintsLoadCmd = nullptr;
+  const char *DyldInfoLoadCmd = nullptr;
+  const char *UuidLoadCmd = nullptr;
+  bool HasPageZeroSegment = false;
+};
+
+/// DiceRef
+inline DiceRef::DiceRef(DataRefImpl DiceP, const ObjectFile *Owner)
+  : DicePimpl(DiceP) , OwningObject(Owner) {}
+
+inline bool DiceRef::operator==(const DiceRef &Other) const {
+  return DicePimpl == Other.DicePimpl;
+}
+
+inline bool DiceRef::operator<(const DiceRef &Other) const {
+  return DicePimpl < Other.DicePimpl;
+}
+
+inline void DiceRef::moveNext() {
+  const MachO::data_in_code_entry *P =
+    reinterpret_cast<const MachO::data_in_code_entry *>(DicePimpl.p);
+  DicePimpl.p = reinterpret_cast<uintptr_t>(P + 1);
+}
+
+// Since a Mach-O data in code reference, a DiceRef, can only be created when
+// the OwningObject ObjectFile is a MachOObjectFile a static_cast<> is used for
+// the methods that get the values of the fields of the reference.
+
+inline std::error_code DiceRef::getOffset(uint32_t &Result) const {
+  const MachOObjectFile *MachOOF =
+    static_cast<const MachOObjectFile *>(OwningObject);
+  MachO::data_in_code_entry Dice = MachOOF->getDice(DicePimpl);
+  Result = Dice.offset;
+  return std::error_code();
+}
+
+inline std::error_code DiceRef::getLength(uint16_t &Result) const {
+  const MachOObjectFile *MachOOF =
+    static_cast<const MachOObjectFile *>(OwningObject);
+  MachO::data_in_code_entry Dice = MachOOF->getDice(DicePimpl);
+  Result = Dice.length;
+  return std::error_code();
+}
+
+inline std::error_code DiceRef::getKind(uint16_t &Result) const {
+  const MachOObjectFile *MachOOF =
+    static_cast<const MachOObjectFile *>(OwningObject);
+  MachO::data_in_code_entry Dice = MachOOF->getDice(DicePimpl);
+  Result = Dice.kind;
+  return std::error_code();
+}
+
+inline DataRefImpl DiceRef::getRawDataRefImpl() const {
+  return DicePimpl;
+}
+
+inline const ObjectFile *DiceRef::getObjectFile() const {
+  return OwningObject;
+}
+
+} // end namespace object
+} // end namespace llvm
+
+#endif // LLVM_OBJECT_MACHO_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Object/Minidump.h b/binaryen/third_party/llvm-project/include/llvm/Object/Minidump.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Object/Minidump.h
@@ -0,0 +1,216 @@
+//===- Minidump.h - Minidump object file implementation ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_MINIDUMP_H
+#define LLVM_OBJECT_MINIDUMP_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/BinaryFormat/Minidump.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace object {
+
+/// A class providing access to the contents of a minidump file.
+class MinidumpFile : public Binary {
+public:
+  /// Construct a new MinidumpFile object from the given memory buffer. Returns
+  /// an error if this file cannot be identified as a minidump file, or if its
+  /// contents are badly corrupted (i.e. we cannot read the stream directory).
+  static Expected<std::unique_ptr<MinidumpFile>> create(MemoryBufferRef Source);
+
+  static bool classof(const Binary *B) { return B->isMinidump(); }
+
+  /// Returns the contents of the minidump header.
+  const minidump::Header &header() const { return Header; }
+
+  /// Returns the list of streams (stream directory entries) in this file.
+  ArrayRef<minidump::Directory> streams() const { return Streams; }
+
+  /// Returns the raw contents of the stream given by the directory entry.
+  ArrayRef<uint8_t> getRawStream(const minidump::Directory &Stream) const {
+    return getData().slice(Stream.Location.RVA, Stream.Location.DataSize);
+  }
+
+  /// Returns the raw contents of the stream of the given type, or None if the
+  /// file does not contain a stream of this type.
+  Optional<ArrayRef<uint8_t>> getRawStream(minidump::StreamType Type) const;
+
+  /// Returns the raw contents of an object given by the LocationDescriptor. An
+  /// error is returned if the descriptor points outside of the minidump file.
+  Expected<ArrayRef<uint8_t>>
+  getRawData(minidump::LocationDescriptor Desc) const {
+    return getDataSlice(getData(), Desc.RVA, Desc.DataSize);
+  }
+
+  /// Returns the minidump string at the given offset. An error is returned if
+  /// we fail to parse the string, or the string is invalid UTF16.
+  Expected<std::string> getString(size_t Offset) const;
+
+  /// Returns the contents of the SystemInfo stream, cast to the appropriate
+  /// type. An error is returned if the file does not contain this stream, or
+  /// the stream is smaller than the size of the SystemInfo structure. The
+  /// internal consistency of the stream is not checked in any way.
+  Expected<const minidump::SystemInfo &> getSystemInfo() const {
+    return getStream<minidump::SystemInfo>(minidump::StreamType::SystemInfo);
+  }
+
+  /// Returns the module list embedded in the ModuleList stream. An error is
+  /// returned if the file does not contain this stream, or if the stream is
+  /// not large enough to contain the number of modules declared in the stream
+  /// header. The consistency of the Module entries themselves is not checked in
+  /// any way.
+  Expected<ArrayRef<minidump::Module>> getModuleList() const {
+    return getListStream<minidump::Module>(minidump::StreamType::ModuleList);
+  }
+
+  /// Returns the thread list embedded in the ThreadList stream. An error is
+  /// returned if the file does not contain this stream, or if the stream is
+  /// not large enough to contain the number of threads declared in the stream
+  /// header. The consistency of the Thread entries themselves is not checked in
+  /// any way.
+  Expected<ArrayRef<minidump::Thread>> getThreadList() const {
+    return getListStream<minidump::Thread>(minidump::StreamType::ThreadList);
+  }
+
+  /// Returns the contents of the Exception stream.  An error is returned if the
+  /// file does not contain this stream, or the stream is smaller than the size
+  /// of the ExceptionStream structure.  The internal consistency of the stream
+  /// is not checked in any way.
+  Expected<const minidump::ExceptionStream &> getExceptionStream() const {
+    return getStream<minidump::ExceptionStream>(
+        minidump::StreamType::Exception);
+  }
+
+  /// Returns the list of descriptors embedded in the MemoryList stream. The
+  /// descriptors provide the content of interesting regions of memory at the
+  /// time the minidump was taken. An error is returned if the file does not
+  /// contain this stream, or if the stream is not large enough to contain the
+  /// number of memory descriptors declared in the stream header. The
+  /// consistency of the MemoryDescriptor entries themselves is not checked in
+  /// any way.
+  Expected<ArrayRef<minidump::MemoryDescriptor>> getMemoryList() const {
+    return getListStream<minidump::MemoryDescriptor>(
+        minidump::StreamType::MemoryList);
+  }
+
+  class MemoryInfoIterator
+      : public iterator_facade_base<MemoryInfoIterator,
+                                    std::forward_iterator_tag,
+                                    minidump::MemoryInfo> {
+  public:
+    MemoryInfoIterator(ArrayRef<uint8_t> Storage, size_t Stride)
+        : Storage(Storage), Stride(Stride) {
+      assert(Storage.size() % Stride == 0);
+    }
+
+    bool operator==(const MemoryInfoIterator &R) const {
+      return Storage.size() == R.Storage.size();
+    }
+
+    const minidump::MemoryInfo &operator*() const {
+      assert(Storage.size() >= sizeof(minidump::MemoryInfo));
+      return *reinterpret_cast<const minidump::MemoryInfo *>(Storage.data());
+    }
+
+    MemoryInfoIterator &operator++() {
+      Storage = Storage.drop_front(Stride);
+      return *this;
+    }
+
+  private:
+    ArrayRef<uint8_t> Storage;
+    size_t Stride;
+  };
+
+  /// Returns the list of descriptors embedded in the MemoryInfoList stream. The
+  /// descriptors provide properties (e.g. permissions) of interesting regions
+  /// of memory at the time the minidump was taken. An error is returned if the
+  /// file does not contain this stream, or if the stream is not large enough to
+  /// contain the number of memory descriptors declared in the stream header.
+  /// The consistency of the MemoryInfoList entries themselves is not checked
+  /// in any way.
+  Expected<iterator_range<MemoryInfoIterator>> getMemoryInfoList() const;
+
+private:
+  static Error createError(StringRef Str) {
+    return make_error<GenericBinaryError>(Str, object_error::parse_failed);
+  }
+
+  static Error createEOFError() {
+    return make_error<GenericBinaryError>("Unexpected EOF",
+                                          object_error::unexpected_eof);
+  }
+
+  /// Return a slice of the given data array, with bounds checking.
+  static Expected<ArrayRef<uint8_t>> getDataSlice(ArrayRef<uint8_t> Data,
+                                                  size_t Offset, size_t Size);
+
+  /// Return the slice of the given data array as an array of objects of the
+  /// given type. The function checks that the input array is large enough to
+  /// contain the correct number of objects of the given type.
+  template <typename T>
+  static Expected<ArrayRef<T>> getDataSliceAs(ArrayRef<uint8_t> Data,
+                                              size_t Offset, size_t Count);
+
+  MinidumpFile(MemoryBufferRef Source, const minidump::Header &Header,
+               ArrayRef<minidump::Directory> Streams,
+               DenseMap<minidump::StreamType, std::size_t> StreamMap)
+      : Binary(ID_Minidump, Source), Header(Header), Streams(Streams),
+        StreamMap(std::move(StreamMap)) {}
+
+  ArrayRef<uint8_t> getData() const {
+    return arrayRefFromStringRef(Data.getBuffer());
+  }
+
+  /// Return the stream of the given type, cast to the appropriate type. Checks
+  /// that the stream is large enough to hold an object of this type.
+  template <typename T>
+  Expected<const T &> getStream(minidump::StreamType Stream) const;
+
+  /// Return the contents of a stream which contains a list of fixed-size items,
+  /// prefixed by the list size.
+  template <typename T>
+  Expected<ArrayRef<T>> getListStream(minidump::StreamType Stream) const;
+
+  const minidump::Header &Header;
+  ArrayRef<minidump::Directory> Streams;
+  DenseMap<minidump::StreamType, std::size_t> StreamMap;
+};
+
+template <typename T>
+Expected<const T &> MinidumpFile::getStream(minidump::StreamType Type) const {
+  if (Optional<ArrayRef<uint8_t>> Stream = getRawStream(Type)) {
+    if (Stream->size() >= sizeof(T))
+      return *reinterpret_cast<const T *>(Stream->data());
+    return createEOFError();
+  }
+  return createError("No such stream");
+}
+
+template <typename T>
+Expected<ArrayRef<T>> MinidumpFile::getDataSliceAs(ArrayRef<uint8_t> Data,
+                                                   size_t Offset,
+                                                   size_t Count) {
+  // Check for overflow.
+  if (Count > std::numeric_limits<size_t>::max() / sizeof(T))
+    return createEOFError();
+  Expected<ArrayRef<uint8_t>> Slice =
+      getDataSlice(Data, Offset, sizeof(T) * Count);
+  if (!Slice)
+    return Slice.takeError();
+  return ArrayRef<T>(reinterpret_cast<const T *>(Slice->data()), Count);
+}
+
+} // end namespace object
+} // end namespace llvm
+
+#endif // LLVM_OBJECT_MINIDUMP_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Object/ObjectFile.h b/binaryen/third_party/llvm-project/include/llvm/Object/ObjectFile.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Object/ObjectFile.h
@@ -0,0 +1,579 @@
+//===- ObjectFile.h - File format independent object file -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares a file format independent ObjectFile class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_OBJECTFILE_H
+#define LLVM_OBJECT_OBJECTFILE_H
+
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <cassert>
+#include <cstdint>
+#include <memory>
+#include <system_error>
+
+namespace llvm {
+
+class ARMAttributeParser;
+
+namespace object {
+
+class COFFObjectFile;
+class MachOObjectFile;
+class ObjectFile;
+class SectionRef;
+class SymbolRef;
+class symbol_iterator;
+class WasmObjectFile;
+
+using section_iterator = content_iterator<SectionRef>;
+
+/// This is a value type class that represents a single relocation in the list
+/// of relocations in the object file.
+class RelocationRef {
+  DataRefImpl RelocationPimpl;
+  const ObjectFile *OwningObject = nullptr;
+
+public:
+  RelocationRef() = default;
+  RelocationRef(DataRefImpl RelocationP, const ObjectFile *Owner);
+
+  bool operator==(const RelocationRef &Other) const;
+
+  void moveNext();
+
+  uint64_t getOffset() const;
+  symbol_iterator getSymbol() const;
+  uint64_t getType() const;
+
+  /// Get a string that represents the type of this relocation.
+  ///
+  /// This is for display purposes only.
+  void getTypeName(SmallVectorImpl<char> &Result) const;
+
+  DataRefImpl getRawDataRefImpl() const;
+  const ObjectFile *getObject() const;
+};
+
+using relocation_iterator = content_iterator<RelocationRef>;
+
+/// This is a value type class that represents a single section in the list of
+/// sections in the object file.
+class SectionRef {
+  friend class SymbolRef;
+
+  DataRefImpl SectionPimpl;
+  const ObjectFile *OwningObject = nullptr;
+
+public:
+  SectionRef() = default;
+  SectionRef(DataRefImpl SectionP, const ObjectFile *Owner);
+
+  bool operator==(const SectionRef &Other) const;
+  bool operator!=(const SectionRef &Other) const;
+  bool operator<(const SectionRef &Other) const;
+
+  void moveNext();
+
+  Expected<StringRef> getName() const;
+  uint64_t getAddress() const;
+  uint64_t getIndex() const;
+  uint64_t getSize() const;
+  Expected<StringRef> getContents() const;
+
+  /// Get the alignment of this section as the actual value (not log 2).
+  uint64_t getAlignment() const;
+
+  bool isCompressed() const;
+  /// Whether this section contains instructions.
+  bool isText() const;
+  /// Whether this section contains data, not instructions.
+  bool isData() const;
+  /// Whether this section contains BSS uninitialized data.
+  bool isBSS() const;
+  bool isVirtual() const;
+  bool isBitcode() const;
+  bool isStripped() const;
+
+  /// Whether this section will be placed in the text segment, according to the
+  /// Berkeley size format. This is true if the section is allocatable, and
+  /// contains either code or readonly data.
+  bool isBerkeleyText() const;
+  /// Whether this section will be placed in the data segment, according to the
+  /// Berkeley size format. This is true if the section is allocatable and
+  /// contains data (e.g. PROGBITS), but is not text.
+  bool isBerkeleyData() const;
+
+  bool containsSymbol(SymbolRef S) const;
+
+  relocation_iterator relocation_begin() const;
+  relocation_iterator relocation_end() const;
+  iterator_range<relocation_iterator> relocations() const {
+    return make_range(relocation_begin(), relocation_end());
+  }
+  Expected<section_iterator> getRelocatedSection() const;
+
+  DataRefImpl getRawDataRefImpl() const;
+  const ObjectFile *getObject() const;
+};
+
+struct SectionedAddress {
+  const static uint64_t UndefSection = UINT64_MAX;
+
+  uint64_t Address = 0;
+  uint64_t SectionIndex = UndefSection;
+};
+
+inline bool operator<(const SectionedAddress &LHS,
+                      const SectionedAddress &RHS) {
+  return std::tie(LHS.SectionIndex, LHS.Address) <
+         std::tie(RHS.SectionIndex, RHS.Address);
+}
+
+inline bool operator==(const SectionedAddress &LHS,
+                       const SectionedAddress &RHS) {
+  return std::tie(LHS.SectionIndex, LHS.Address) ==
+         std::tie(RHS.SectionIndex, RHS.Address);
+}
+
+/// This is a value type class that represents a single symbol in the list of
+/// symbols in the object file.
+class SymbolRef : public BasicSymbolRef {
+  friend class SectionRef;
+
+public:
+  enum Type {
+    ST_Unknown, // Type not specified
+    ST_Data,
+    ST_Debug,
+    ST_File,
+    ST_Function,
+    ST_Other
+  };
+
+  SymbolRef() = default;
+  SymbolRef(DataRefImpl SymbolP, const ObjectFile *Owner);
+  SymbolRef(const BasicSymbolRef &B) : BasicSymbolRef(B) {
+    assert(isa<ObjectFile>(BasicSymbolRef::getObject()));
+  }
+
+  Expected<StringRef> getName() const;
+  /// Returns the symbol virtual address (i.e. address at which it will be
+  /// mapped).
+  Expected<uint64_t> getAddress() const;
+
+  /// Return the value of the symbol depending on the object this can be an
+  /// offset or a virtual address.
+  uint64_t getValue() const;
+
+  /// Get the alignment of this symbol as the actual value (not log 2).
+  uint32_t getAlignment() const;
+  uint64_t getCommonSize() const;
+  Expected<SymbolRef::Type> getType() const;
+
+  /// Get section this symbol is defined in reference to. Result is
+  /// end_sections() if it is undefined or is an absolute symbol.
+  Expected<section_iterator> getSection() const;
+
+  const ObjectFile *getObject() const;
+};
+
+class symbol_iterator : public basic_symbol_iterator {
+public:
+  symbol_iterator(SymbolRef Sym) : basic_symbol_iterator(Sym) {}
+  symbol_iterator(const basic_symbol_iterator &B)
+      : basic_symbol_iterator(SymbolRef(B->getRawDataRefImpl(),
+                                        cast<ObjectFile>(B->getObject()))) {}
+
+  const SymbolRef *operator->() const {
+    const BasicSymbolRef &P = basic_symbol_iterator::operator *();
+    return static_cast<const SymbolRef*>(&P);
+  }
+
+  const SymbolRef &operator*() const {
+    const BasicSymbolRef &P = basic_symbol_iterator::operator *();
+    return static_cast<const SymbolRef&>(P);
+  }
+};
+
+/// This class is the base class for all object file types. Concrete instances
+/// of this object are created by createObjectFile, which figures out which type
+/// to create.
+class ObjectFile : public SymbolicFile {
+  virtual void anchor();
+
+protected:
+  ObjectFile(unsigned int Type, MemoryBufferRef Source);
+
+  const uint8_t *base() const {
+    return reinterpret_cast<const uint8_t *>(Data.getBufferStart());
+  }
+
+  // These functions are for SymbolRef to call internally. The main goal of
+  // this is to allow SymbolRef::SymbolPimpl to point directly to the symbol
+  // entry in the memory mapped object file. SymbolPimpl cannot contain any
+  // virtual functions because then it could not point into the memory mapped
+  // file.
+  //
+  // Implementations assume that the DataRefImpl is valid and has not been
+  // modified externally. It's UB otherwise.
+  friend class SymbolRef;
+
+  virtual Expected<StringRef> getSymbolName(DataRefImpl Symb) const = 0;
+  Error printSymbolName(raw_ostream &OS,
+                                  DataRefImpl Symb) const override;
+  virtual Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const = 0;
+  virtual uint64_t getSymbolValueImpl(DataRefImpl Symb) const = 0;
+  virtual uint32_t getSymbolAlignment(DataRefImpl Symb) const;
+  virtual uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const = 0;
+  virtual Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const = 0;
+  virtual Expected<section_iterator>
+  getSymbolSection(DataRefImpl Symb) const = 0;
+
+  // Same as above for SectionRef.
+  friend class SectionRef;
+
+  virtual void moveSectionNext(DataRefImpl &Sec) const = 0;
+  virtual Expected<StringRef> getSectionName(DataRefImpl Sec) const = 0;
+  virtual uint64_t getSectionAddress(DataRefImpl Sec) const = 0;
+  virtual uint64_t getSectionIndex(DataRefImpl Sec) const = 0;
+  virtual uint64_t getSectionSize(DataRefImpl Sec) const = 0;
+  virtual Expected<ArrayRef<uint8_t>>
+  getSectionContents(DataRefImpl Sec) const = 0;
+  virtual uint64_t getSectionAlignment(DataRefImpl Sec) const = 0;
+  virtual bool isSectionCompressed(DataRefImpl Sec) const = 0;
+  virtual bool isSectionText(DataRefImpl Sec) const = 0;
+  virtual bool isSectionData(DataRefImpl Sec) const = 0;
+  virtual bool isSectionBSS(DataRefImpl Sec) const = 0;
+  // A section is 'virtual' if its contents aren't present in the object image.
+  virtual bool isSectionVirtual(DataRefImpl Sec) const = 0;
+  virtual bool isSectionBitcode(DataRefImpl Sec) const;
+  virtual bool isSectionStripped(DataRefImpl Sec) const;
+  virtual bool isBerkeleyText(DataRefImpl Sec) const;
+  virtual bool isBerkeleyData(DataRefImpl Sec) const;
+  virtual relocation_iterator section_rel_begin(DataRefImpl Sec) const = 0;
+  virtual relocation_iterator section_rel_end(DataRefImpl Sec) const = 0;
+  virtual Expected<section_iterator> getRelocatedSection(DataRefImpl Sec) const;
+
+  // Same as above for RelocationRef.
+  friend class RelocationRef;
+  virtual void moveRelocationNext(DataRefImpl &Rel) const = 0;
+  virtual uint64_t getRelocationOffset(DataRefImpl Rel) const = 0;
+  virtual symbol_iterator getRelocationSymbol(DataRefImpl Rel) const = 0;
+  virtual uint64_t getRelocationType(DataRefImpl Rel) const = 0;
+  virtual void getRelocationTypeName(DataRefImpl Rel,
+                                     SmallVectorImpl<char> &Result) const = 0;
+
+  uint64_t getSymbolValue(DataRefImpl Symb) const;
+
+public:
+  ObjectFile() = delete;
+  ObjectFile(const ObjectFile &other) = delete;
+
+  uint64_t getCommonSymbolSize(DataRefImpl Symb) const {
+    assert(getSymbolFlags(Symb) & SymbolRef::SF_Common);
+    return getCommonSymbolSizeImpl(Symb);
+  }
+
+  virtual std::vector<SectionRef> dynamic_relocation_sections() const {
+    return std::vector<SectionRef>();
+  }
+
+  using symbol_iterator_range = iterator_range<symbol_iterator>;
+  symbol_iterator_range symbols() const {
+    return symbol_iterator_range(symbol_begin(), symbol_end());
+  }
+
+  virtual section_iterator section_begin() const = 0;
+  virtual section_iterator section_end() const = 0;
+
+  using section_iterator_range = iterator_range<section_iterator>;
+  section_iterator_range sections() const {
+    return section_iterator_range(section_begin(), section_end());
+  }
+
+  /// The number of bytes used to represent an address in this object
+  ///        file format.
+  virtual uint8_t getBytesInAddress() const = 0;
+
+  virtual StringRef getFileFormatName() const = 0;
+  virtual Triple::ArchType getArch() const = 0;
+  virtual SubtargetFeatures getFeatures() const = 0;
+  virtual void setARMSubArch(Triple &TheTriple) const { }
+  virtual Expected<uint64_t> getStartAddress() const {
+    // XXX BINARYEN
+    llvm_unreachable("getStartAddress");
+    //return errorCodeToError(object_error::parse_failed);
+  };
+
+  /// Create a triple from the data in this object file.
+  Triple makeTriple() const;
+
+  /// Maps a debug section name to a standard DWARF section name.
+  virtual StringRef mapDebugSectionName(StringRef Name) const { return Name; }
+
+  /// True if this is a relocatable object (.o/.obj).
+  virtual bool isRelocatableObject() const = 0;
+
+  /// @returns Pointer to ObjectFile subclass to handle this type of object.
+  /// @param ObjectPath The path to the object file. ObjectPath.isObject must
+  ///        return true.
+  /// Create ObjectFile from path.
+  static Expected<OwningBinary<ObjectFile>>
+  createObjectFile(StringRef ObjectPath);
+
+  static Expected<std::unique_ptr<ObjectFile>>
+  createObjectFile(MemoryBufferRef Object, llvm::file_magic Type);
+  static Expected<std::unique_ptr<ObjectFile>>
+  createObjectFile(MemoryBufferRef Object) {
+    return createObjectFile(Object, llvm::file_magic::unknown);
+  }
+
+  static bool classof(const Binary *v) {
+    return v->isObject();
+  }
+
+  static Expected<std::unique_ptr<COFFObjectFile>>
+  createCOFFObjectFile(MemoryBufferRef Object);
+
+  static Expected<std::unique_ptr<ObjectFile>>
+  createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType);
+
+  static Expected<std::unique_ptr<ObjectFile>>
+  createELFObjectFile(MemoryBufferRef Object);
+
+  static Expected<std::unique_ptr<MachOObjectFile>>
+  createMachOObjectFile(MemoryBufferRef Object,
+                        uint32_t UniversalCputype = 0,
+                        uint32_t UniversalIndex = 0);
+
+  static Expected<std::unique_ptr<WasmObjectFile>>
+  createWasmObjectFile(MemoryBufferRef Object);
+};
+
+// Inline function definitions.
+inline SymbolRef::SymbolRef(DataRefImpl SymbolP, const ObjectFile *Owner)
+    : BasicSymbolRef(SymbolP, Owner) {}
+
+inline Expected<StringRef> SymbolRef::getName() const {
+  return getObject()->getSymbolName(getRawDataRefImpl());
+}
+
+inline Expected<uint64_t> SymbolRef::getAddress() const {
+  return getObject()->getSymbolAddress(getRawDataRefImpl());
+}
+
+inline uint64_t SymbolRef::getValue() const {
+  return getObject()->getSymbolValue(getRawDataRefImpl());
+}
+
+inline uint32_t SymbolRef::getAlignment() const {
+  return getObject()->getSymbolAlignment(getRawDataRefImpl());
+}
+
+inline uint64_t SymbolRef::getCommonSize() const {
+  return getObject()->getCommonSymbolSize(getRawDataRefImpl());
+}
+
+inline Expected<section_iterator> SymbolRef::getSection() const {
+  return getObject()->getSymbolSection(getRawDataRefImpl());
+}
+
+inline Expected<SymbolRef::Type> SymbolRef::getType() const {
+  return getObject()->getSymbolType(getRawDataRefImpl());
+}
+
+inline const ObjectFile *SymbolRef::getObject() const {
+  const SymbolicFile *O = BasicSymbolRef::getObject();
+  return cast<ObjectFile>(O);
+}
+
+/// SectionRef
+inline SectionRef::SectionRef(DataRefImpl SectionP,
+                              const ObjectFile *Owner)
+  : SectionPimpl(SectionP)
+  , OwningObject(Owner) {}
+
+inline bool SectionRef::operator==(const SectionRef &Other) const {
+  return OwningObject == Other.OwningObject &&
+         SectionPimpl == Other.SectionPimpl;
+}
+
+inline bool SectionRef::operator!=(const SectionRef &Other) const {
+  return !(*this == Other);
+}
+
+inline bool SectionRef::operator<(const SectionRef &Other) const {
+  assert(OwningObject == Other.OwningObject);
+  return SectionPimpl < Other.SectionPimpl;
+}
+
+inline void SectionRef::moveNext() {
+  return OwningObject->moveSectionNext(SectionPimpl);
+}
+
+inline Expected<StringRef> SectionRef::getName() const {
+  return OwningObject->getSectionName(SectionPimpl);
+}
+
+inline uint64_t SectionRef::getAddress() const {
+  return OwningObject->getSectionAddress(SectionPimpl);
+}
+
+inline uint64_t SectionRef::getIndex() const {
+  return OwningObject->getSectionIndex(SectionPimpl);
+}
+
+inline uint64_t SectionRef::getSize() const {
+  return OwningObject->getSectionSize(SectionPimpl);
+}
+
+inline Expected<StringRef> SectionRef::getContents() const {
+  Expected<ArrayRef<uint8_t>> Res =
+      OwningObject->getSectionContents(SectionPimpl);
+  if (!Res)
+    return Res.takeError();
+  return StringRef(reinterpret_cast<const char *>(Res->data()), Res->size());
+}
+
+inline uint64_t SectionRef::getAlignment() const {
+  return OwningObject->getSectionAlignment(SectionPimpl);
+}
+
+inline bool SectionRef::isCompressed() const {
+  return OwningObject->isSectionCompressed(SectionPimpl);
+}
+
+inline bool SectionRef::isText() const {
+  return OwningObject->isSectionText(SectionPimpl);
+}
+
+inline bool SectionRef::isData() const {
+  return OwningObject->isSectionData(SectionPimpl);
+}
+
+inline bool SectionRef::isBSS() const {
+  return OwningObject->isSectionBSS(SectionPimpl);
+}
+
+inline bool SectionRef::isVirtual() const {
+  return OwningObject->isSectionVirtual(SectionPimpl);
+}
+
+inline bool SectionRef::isBitcode() const {
+  return OwningObject->isSectionBitcode(SectionPimpl);
+}
+
+inline bool SectionRef::isStripped() const {
+  return OwningObject->isSectionStripped(SectionPimpl);
+}
+
+inline bool SectionRef::isBerkeleyText() const {
+  return OwningObject->isBerkeleyText(SectionPimpl);
+}
+
+inline bool SectionRef::isBerkeleyData() const {
+  return OwningObject->isBerkeleyData(SectionPimpl);
+}
+
+inline relocation_iterator SectionRef::relocation_begin() const {
+  return OwningObject->section_rel_begin(SectionPimpl);
+}
+
+inline relocation_iterator SectionRef::relocation_end() const {
+  return OwningObject->section_rel_end(SectionPimpl);
+}
+
+inline Expected<section_iterator> SectionRef::getRelocatedSection() const {
+  return OwningObject->getRelocatedSection(SectionPimpl);
+}
+
+inline DataRefImpl SectionRef::getRawDataRefImpl() const {
+  return SectionPimpl;
+}
+
+inline const ObjectFile *SectionRef::getObject() const {
+  return OwningObject;
+}
+
+/// RelocationRef
+inline RelocationRef::RelocationRef(DataRefImpl RelocationP,
+                              const ObjectFile *Owner)
+  : RelocationPimpl(RelocationP)
+  , OwningObject(Owner) {}
+
+inline bool RelocationRef::operator==(const RelocationRef &Other) const {
+  return RelocationPimpl == Other.RelocationPimpl;
+}
+
+inline void RelocationRef::moveNext() {
+  return OwningObject->moveRelocationNext(RelocationPimpl);
+}
+
+inline uint64_t RelocationRef::getOffset() const {
+  return OwningObject->getRelocationOffset(RelocationPimpl);
+}
+
+inline symbol_iterator RelocationRef::getSymbol() const {
+  return OwningObject->getRelocationSymbol(RelocationPimpl);
+}
+
+inline uint64_t RelocationRef::getType() const {
+  return OwningObject->getRelocationType(RelocationPimpl);
+}
+
+inline void RelocationRef::getTypeName(SmallVectorImpl<char> &Result) const {
+  return OwningObject->getRelocationTypeName(RelocationPimpl, Result);
+}
+
+inline DataRefImpl RelocationRef::getRawDataRefImpl() const {
+  return RelocationPimpl;
+}
+
+inline const ObjectFile *RelocationRef::getObject() const {
+  return OwningObject;
+}
+
+} // end namespace object
+
+template <> struct DenseMapInfo<object::SectionRef> {
+  static bool isEqual(const object::SectionRef &A,
+                      const object::SectionRef &B) {
+    return A == B;
+  }
+  static object::SectionRef getEmptyKey() {
+    return object::SectionRef({}, nullptr);
+  }
+  static object::SectionRef getTombstoneKey() {
+    object::DataRefImpl TS;
+    TS.p = (uintptr_t)-1;
+    return object::SectionRef(TS, nullptr);
+  }
+  static unsigned getHashValue(const object::SectionRef &Sec) {
+    object::DataRefImpl Raw = Sec.getRawDataRefImpl();
+    return hash_combine(Raw.p, Raw.d.a, Raw.d.b);
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_OBJECT_OBJECTFILE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Object/RelocationResolver.h b/binaryen/third_party/llvm-project/include/llvm/Object/RelocationResolver.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Object/RelocationResolver.h
@@ -0,0 +1,42 @@
+//===- RelocVisitor.h - Visitor for object file relocations -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a wrapper around all the different types of relocations
+// in different file formats, such that a client can handle them in a unified
+// manner by only implementing a minimal number of functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_RELOCVISITOR_H
+#define LLVM_OBJECT_RELOCVISITOR_H
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cstdint>
+#include <system_error>
+
+namespace llvm {
+namespace object {
+
+using RelocationResolver = uint64_t (*)(RelocationRef R, uint64_t S, uint64_t A);
+
+std::pair<bool (*)(uint64_t), RelocationResolver>
+getRelocationResolver(const ObjectFile &Obj);
+
+} // end namespace object
+} // end namespace llvm
+
+#endif // LLVM_OBJECT_RELOCVISITOR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Object/SymbolicFile.h b/binaryen/third_party/llvm-project/include/llvm/Object/SymbolicFile.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Object/SymbolicFile.h
@@ -0,0 +1,214 @@
+//===- SymbolicFile.h - Interface that only provides symbols ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the SymbolicFile interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_SYMBOLICFILE_H
+#define LLVM_OBJECT_SYMBOLICFILE_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <cinttypes>
+#include <cstdint>
+#include <cstring>
+#include <iterator>
+#include <memory>
+#include <system_error>
+
+namespace llvm {
+namespace object {
+
+union DataRefImpl {
+  // This entire union should probably be a
+  // char[max(8, sizeof(uintptr_t))] and require the impl to cast.
+  struct {
+    uint32_t a, b;
+  } d;
+  uintptr_t p;
+
+  DataRefImpl() { std::memset(this, 0, sizeof(DataRefImpl)); }
+};
+
+template <typename OStream>
+OStream& operator<<(OStream &OS, const DataRefImpl &D) {
+  OS << "(" << format("0x%08" PRIxPTR, D.p) << " (" << format("0x%08x", D.d.a)
+     << ", " << format("0x%08x", D.d.b) << "))";
+  return OS;
+}
+
+inline bool operator==(const DataRefImpl &a, const DataRefImpl &b) {
+  // Check bitwise identical. This is the only legal way to compare a union w/o
+  // knowing which member is in use.
+  return std::memcmp(&a, &b, sizeof(DataRefImpl)) == 0;
+}
+
+inline bool operator!=(const DataRefImpl &a, const DataRefImpl &b) {
+  return !operator==(a, b);
+}
+
+inline bool operator<(const DataRefImpl &a, const DataRefImpl &b) {
+  // Check bitwise identical. This is the only legal way to compare a union w/o
+  // knowing which member is in use.
+  return std::memcmp(&a, &b, sizeof(DataRefImpl)) < 0;
+}
+
+template <class content_type>
+class content_iterator
+    : public std::iterator<std::forward_iterator_tag, content_type> {
+  content_type Current;
+
+public:
+  content_iterator(content_type symb) : Current(std::move(symb)) {}
+
+  const content_type *operator->() const { return &Current; }
+
+  const content_type &operator*() const { return Current; }
+
+  bool operator==(const content_iterator &other) const {
+    return Current == other.Current;
+  }
+
+  bool operator!=(const content_iterator &other) const {
+    return !(*this == other);
+  }
+
+  content_iterator &operator++() { // preincrement
+    Current.moveNext();
+    return *this;
+  }
+};
+
+class SymbolicFile;
+
+/// This is a value type class that represents a single symbol in the list of
+/// symbols in the object file.
+class BasicSymbolRef {
+  DataRefImpl SymbolPimpl;
+  const SymbolicFile *OwningObject = nullptr;
+
+public:
+  enum Flags : unsigned {
+    SF_None = 0,
+    SF_Undefined = 1U << 0,      // Symbol is defined in another object file
+    SF_Global = 1U << 1,         // Global symbol
+    SF_Weak = 1U << 2,           // Weak symbol
+    SF_Absolute = 1U << 3,       // Absolute symbol
+    SF_Common = 1U << 4,         // Symbol has common linkage
+    SF_Indirect = 1U << 5,       // Symbol is an alias to another symbol
+    SF_Exported = 1U << 6,       // Symbol is visible to other DSOs
+    SF_FormatSpecific = 1U << 7, // Specific to the object file format
+                                 // (e.g. section symbols)
+    SF_Thumb = 1U << 8,          // Thumb symbol in a 32-bit ARM binary
+    SF_Hidden = 1U << 9,         // Symbol has hidden visibility
+    SF_Const = 1U << 10,         // Symbol value is constant
+    SF_Executable = 1U << 11,    // Symbol points to an executable section
+                                 // (IR only)
+  };
+
+  BasicSymbolRef() = default;
+  BasicSymbolRef(DataRefImpl SymbolP, const SymbolicFile *Owner);
+
+  bool operator==(const BasicSymbolRef &Other) const;
+  bool operator<(const BasicSymbolRef &Other) const;
+
+  void moveNext();
+
+  Error printName(raw_ostream &OS) const;
+
+  /// Get symbol flags (bitwise OR of SymbolRef::Flags)
+  uint32_t getFlags() const;
+
+  DataRefImpl getRawDataRefImpl() const;
+  const SymbolicFile *getObject() const;
+};
+
+using basic_symbol_iterator = content_iterator<BasicSymbolRef>;
+
+class SymbolicFile : public Binary {
+public:
+  SymbolicFile(unsigned int Type, MemoryBufferRef Source);
+  ~SymbolicFile() override;
+
+  // virtual interface.
+  virtual void moveSymbolNext(DataRefImpl &Symb) const = 0;
+
+  virtual Error printSymbolName(raw_ostream &OS, DataRefImpl Symb) const = 0;
+
+  virtual uint32_t getSymbolFlags(DataRefImpl Symb) const = 0;
+
+  virtual basic_symbol_iterator symbol_begin() const = 0;
+
+  virtual basic_symbol_iterator symbol_end() const = 0;
+
+  // convenience wrappers.
+  using basic_symbol_iterator_range = iterator_range<basic_symbol_iterator>;
+  basic_symbol_iterator_range symbols() const {
+    return basic_symbol_iterator_range(symbol_begin(), symbol_end());
+  }
+
+  // construction aux.
+  static Expected<std::unique_ptr<SymbolicFile>>
+  createSymbolicFile(MemoryBufferRef Object, llvm::file_magic Type,
+                     LLVMContext *Context);
+
+  static Expected<std::unique_ptr<SymbolicFile>>
+  createSymbolicFile(MemoryBufferRef Object) {
+    return createSymbolicFile(Object, llvm::file_magic::unknown, nullptr);
+  }
+  static Expected<OwningBinary<SymbolicFile>>
+  createSymbolicFile(StringRef ObjectPath);
+
+  static bool classof(const Binary *v) {
+    return v->isSymbolic();
+  }
+};
+
+inline BasicSymbolRef::BasicSymbolRef(DataRefImpl SymbolP,
+                                      const SymbolicFile *Owner)
+    : SymbolPimpl(SymbolP), OwningObject(Owner) {}
+
+inline bool BasicSymbolRef::operator==(const BasicSymbolRef &Other) const {
+  return SymbolPimpl == Other.SymbolPimpl;
+}
+
+inline bool BasicSymbolRef::operator<(const BasicSymbolRef &Other) const {
+  return SymbolPimpl < Other.SymbolPimpl;
+}
+
+inline void BasicSymbolRef::moveNext() {
+  return OwningObject->moveSymbolNext(SymbolPimpl);
+}
+
+inline Error BasicSymbolRef::printName(raw_ostream &OS) const {
+  return OwningObject->printSymbolName(OS, SymbolPimpl);
+}
+
+inline uint32_t BasicSymbolRef::getFlags() const {
+  return OwningObject->getSymbolFlags(SymbolPimpl);
+}
+
+inline DataRefImpl BasicSymbolRef::getRawDataRefImpl() const {
+  return SymbolPimpl;
+}
+
+inline const SymbolicFile *BasicSymbolRef::getObject() const {
+  return OwningObject;
+}
+
+} // end namespace object
+} // end namespace llvm
+
+#endif // LLVM_OBJECT_SYMBOLICFILE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Object/Wasm.h b/binaryen/third_party/llvm-project/include/llvm/Object/Wasm.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Object/Wasm.h
@@ -0,0 +1,356 @@
+//===- Wasm.h - Wasm object file implementation -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the WasmObjectFile class, which implements the ObjectFile
+// interface for Wasm files.
+//
+// See: https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_WASM_H
+#define LLVM_OBJECT_WASM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Wasm.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/MC/MCSymbolWasm.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+namespace llvm {
+namespace object {
+
+class WasmSymbol {
+public:
+  WasmSymbol(const wasm::WasmSymbolInfo &Info,
+             const wasm::WasmGlobalType *GlobalType,
+             const wasm::WasmEventType *EventType,
+             const wasm::WasmSignature *Signature)
+      : Info(Info), GlobalType(GlobalType), EventType(EventType),
+        Signature(Signature) {}
+
+  const wasm::WasmSymbolInfo &Info;
+  const wasm::WasmGlobalType *GlobalType;
+  const wasm::WasmEventType *EventType;
+  const wasm::WasmSignature *Signature;
+
+  bool isTypeFunction() const {
+    return Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION;
+  }
+
+  bool isTypeData() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_DATA; }
+
+  bool isTypeGlobal() const {
+    return Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL;
+  }
+
+  bool isTypeSection() const {
+    return Info.Kind == wasm::WASM_SYMBOL_TYPE_SECTION;
+  }
+
+  bool isTypeEvent() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_EVENT; }
+
+  bool isDefined() const { return !isUndefined(); }
+
+  bool isUndefined() const {
+    return (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) != 0;
+  }
+
+  bool isBindingWeak() const {
+    return getBinding() == wasm::WASM_SYMBOL_BINDING_WEAK;
+  }
+
+  bool isBindingGlobal() const {
+    return getBinding() == wasm::WASM_SYMBOL_BINDING_GLOBAL;
+  }
+
+  bool isBindingLocal() const {
+    return getBinding() == wasm::WASM_SYMBOL_BINDING_LOCAL;
+  }
+
+  unsigned getBinding() const {
+    return Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK;
+  }
+
+  bool isHidden() const {
+    return getVisibility() == wasm::WASM_SYMBOL_VISIBILITY_HIDDEN;
+  }
+
+  unsigned getVisibility() const {
+    return Info.Flags & wasm::WASM_SYMBOL_VISIBILITY_MASK;
+  }
+
+  void print(raw_ostream &Out) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  LLVM_DUMP_METHOD void dump() const;
+#endif
+};
+
+struct WasmSection {
+  WasmSection() = default;
+
+  uint32_t Type = 0;         // Section type (See below)
+  uint32_t Offset = 0;       // Offset with in the file
+  StringRef Name;            // Section name (User-defined sections only)
+  ArrayRef<uint8_t> Content; // Section content
+  std::vector<wasm::WasmRelocation> Relocations; // Relocations for this section
+};
+
+struct WasmSegment {
+  uint32_t SectionOffset;
+  wasm::WasmDataSegment Data;
+};
+
+class WasmObjectFile : public ObjectFile {
+
+public:
+  WasmObjectFile(MemoryBufferRef Object, Error &Err);
+
+  const wasm::WasmObjectHeader &getHeader() const;
+  const WasmSymbol &getWasmSymbol(const DataRefImpl &Symb) const;
+  const WasmSymbol &getWasmSymbol(const SymbolRef &Symbol) const;
+  const WasmSection &getWasmSection(const SectionRef &Section) const;
+  const wasm::WasmRelocation &getWasmRelocation(const RelocationRef &Ref) const;
+
+  static bool classof(const Binary *v) { return v->isWasm(); }
+
+  const wasm::WasmDylinkInfo &dylinkInfo() const { return DylinkInfo; }
+  const wasm::WasmProducerInfo &getProducerInfo() const { return ProducerInfo; }
+  ArrayRef<wasm::WasmFeatureEntry> getTargetFeatures() const {
+    return TargetFeatures;
+  }
+  ArrayRef<wasm::WasmSignature> types() const { return Signatures; }
+  ArrayRef<uint32_t> functionTypes() const { return FunctionTypes; }
+  ArrayRef<wasm::WasmImport> imports() const { return Imports; }
+  ArrayRef<wasm::WasmTable> tables() const { return Tables; }
+  ArrayRef<wasm::WasmLimits> memories() const { return Memories; }
+  ArrayRef<wasm::WasmGlobal> globals() const { return Globals; }
+  ArrayRef<wasm::WasmEvent> events() const { return Events; }
+  ArrayRef<wasm::WasmExport> exports() const { return Exports; }
+  ArrayRef<WasmSymbol> syms() const { return Symbols; }
+  const wasm::WasmLinkingData &linkingData() const { return LinkingData; }
+  uint32_t getNumberOfSymbols() const { return Symbols.size(); }
+  ArrayRef<wasm::WasmElemSegment> elements() const { return ElemSegments; }
+  ArrayRef<WasmSegment> dataSegments() const { return DataSegments; }
+  ArrayRef<wasm::WasmFunction> functions() const { return Functions; }
+  ArrayRef<wasm::WasmFunctionName> debugNames() const { return DebugNames; }
+  uint32_t startFunction() const { return StartFunction; }
+  uint32_t getNumImportedGlobals() const { return NumImportedGlobals; }
+  uint32_t getNumImportedFunctions() const { return NumImportedFunctions; }
+  uint32_t getNumImportedEvents() const { return NumImportedEvents; }
+  void moveSymbolNext(DataRefImpl &Symb) const override;
+
+  uint32_t getSymbolFlags(DataRefImpl Symb) const override;
+
+  basic_symbol_iterator symbol_begin() const override;
+
+  basic_symbol_iterator symbol_end() const override;
+  Expected<StringRef> getSymbolName(DataRefImpl Symb) const override;
+
+  Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override;
+  uint64_t getWasmSymbolValue(const WasmSymbol &Sym) const;
+  uint64_t getSymbolValueImpl(DataRefImpl Symb) const override;
+  uint32_t getSymbolAlignment(DataRefImpl Symb) const override;
+  uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override;
+  Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override;
+  Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override;
+
+  // Overrides from SectionRef.
+  void moveSectionNext(DataRefImpl &Sec) const override;
+  Expected<StringRef> getSectionName(DataRefImpl Sec) const override;
+  uint64_t getSectionAddress(DataRefImpl Sec) const override;
+  uint64_t getSectionIndex(DataRefImpl Sec) const override;
+  uint64_t getSectionSize(DataRefImpl Sec) const override;
+  Expected<ArrayRef<uint8_t>>
+  getSectionContents(DataRefImpl Sec) const override;
+  uint64_t getSectionAlignment(DataRefImpl Sec) const override;
+  bool isSectionCompressed(DataRefImpl Sec) const override;
+  bool isSectionText(DataRefImpl Sec) const override;
+  bool isSectionData(DataRefImpl Sec) const override;
+  bool isSectionBSS(DataRefImpl Sec) const override;
+  bool isSectionVirtual(DataRefImpl Sec) const override;
+  bool isSectionBitcode(DataRefImpl Sec) const override;
+  relocation_iterator section_rel_begin(DataRefImpl Sec) const override;
+  relocation_iterator section_rel_end(DataRefImpl Sec) const override;
+
+  // Overrides from RelocationRef.
+  void moveRelocationNext(DataRefImpl &Rel) const override;
+  uint64_t getRelocationOffset(DataRefImpl Rel) const override;
+  symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override;
+  uint64_t getRelocationType(DataRefImpl Rel) const override;
+  void getRelocationTypeName(DataRefImpl Rel,
+                             SmallVectorImpl<char> &Result) const override;
+
+  section_iterator section_begin() const override;
+  section_iterator section_end() const override;
+  uint8_t getBytesInAddress() const override;
+  StringRef getFileFormatName() const override;
+  Triple::ArchType getArch() const override;
+  SubtargetFeatures getFeatures() const override;
+  bool isRelocatableObject() const override;
+  bool isSharedObject() const;
+
+  struct ReadContext {
+    const uint8_t *Start;
+    const uint8_t *Ptr;
+    const uint8_t *End;
+  };
+
+private:
+  bool isValidFunctionIndex(uint32_t Index) const;
+  bool isDefinedFunctionIndex(uint32_t Index) const;
+  bool isValidGlobalIndex(uint32_t Index) const;
+  bool isDefinedGlobalIndex(uint32_t Index) const;
+  bool isValidEventIndex(uint32_t Index) const;
+  bool isDefinedEventIndex(uint32_t Index) const;
+  bool isValidFunctionSymbol(uint32_t Index) const;
+  bool isValidGlobalSymbol(uint32_t Index) const;
+  bool isValidEventSymbol(uint32_t Index) const;
+  bool isValidDataSymbol(uint32_t Index) const;
+  bool isValidSectionSymbol(uint32_t Index) const;
+  wasm::WasmFunction &getDefinedFunction(uint32_t Index);
+  const wasm::WasmFunction &getDefinedFunction(uint32_t Index) const;
+  wasm::WasmGlobal &getDefinedGlobal(uint32_t Index);
+  wasm::WasmEvent &getDefinedEvent(uint32_t Index);
+
+  const WasmSection &getWasmSection(DataRefImpl Ref) const;
+  const wasm::WasmRelocation &getWasmRelocation(DataRefImpl Ref) const;
+
+  Error parseSection(WasmSection &Sec);
+  Error parseCustomSection(WasmSection &Sec, ReadContext &Ctx);
+
+  // Standard section types
+  Error parseTypeSection(ReadContext &Ctx);
+  Error parseImportSection(ReadContext &Ctx);
+  Error parseFunctionSection(ReadContext &Ctx);
+  Error parseTableSection(ReadContext &Ctx);
+  Error parseMemorySection(ReadContext &Ctx);
+  Error parseGlobalSection(ReadContext &Ctx);
+  Error parseEventSection(ReadContext &Ctx);
+  Error parseExportSection(ReadContext &Ctx);
+  Error parseStartSection(ReadContext &Ctx);
+  Error parseElemSection(ReadContext &Ctx);
+  Error parseCodeSection(ReadContext &Ctx);
+  Error parseDataSection(ReadContext &Ctx);
+  Error parseDataCountSection(ReadContext &Ctx);
+
+  // Custom section types
+  Error parseDylinkSection(ReadContext &Ctx);
+  Error parseNameSection(ReadContext &Ctx);
+  Error parseLinkingSection(ReadContext &Ctx);
+  Error parseLinkingSectionSymtab(ReadContext &Ctx);
+  Error parseLinkingSectionComdat(ReadContext &Ctx);
+  Error parseProducersSection(ReadContext &Ctx);
+  Error parseTargetFeaturesSection(ReadContext &Ctx);
+  Error parseRelocSection(StringRef Name, ReadContext &Ctx);
+
+  wasm::WasmObjectHeader Header;
+  std::vector<WasmSection> Sections;
+  wasm::WasmDylinkInfo DylinkInfo;
+  wasm::WasmProducerInfo ProducerInfo;
+  std::vector<wasm::WasmFeatureEntry> TargetFeatures;
+  std::vector<wasm::WasmSignature> Signatures;
+  std::vector<uint32_t> FunctionTypes;
+  std::vector<wasm::WasmTable> Tables;
+  std::vector<wasm::WasmLimits> Memories;
+  std::vector<wasm::WasmGlobal> Globals;
+  std::vector<wasm::WasmEvent> Events;
+  std::vector<wasm::WasmImport> Imports;
+  std::vector<wasm::WasmExport> Exports;
+  std::vector<wasm::WasmElemSegment> ElemSegments;
+  std::vector<WasmSegment> DataSegments;
+  llvm::Optional<size_t> DataCount;
+  std::vector<wasm::WasmFunction> Functions;
+  std::vector<WasmSymbol> Symbols;
+  std::vector<wasm::WasmFunctionName> DebugNames;
+  uint32_t StartFunction = -1;
+  bool HasLinkingSection = false;
+  bool HasDylinkSection = false;
+  wasm::WasmLinkingData LinkingData;
+  uint32_t NumImportedGlobals = 0;
+  uint32_t NumImportedFunctions = 0;
+  uint32_t NumImportedEvents = 0;
+  uint32_t CodeSection = 0;
+  uint32_t DataSection = 0;
+  uint32_t GlobalSection = 0;
+  uint32_t EventSection = 0;
+};
+
+class WasmSectionOrderChecker {
+public:
+  // We define orders for all core wasm sections and known custom sections.
+  enum : int {
+    // Sentinel, must be zero
+    WASM_SEC_ORDER_NONE = 0,
+
+    // Core sections
+    WASM_SEC_ORDER_TYPE,
+    WASM_SEC_ORDER_IMPORT,
+    WASM_SEC_ORDER_FUNCTION,
+    WASM_SEC_ORDER_TABLE,
+    WASM_SEC_ORDER_MEMORY,
+    WASM_SEC_ORDER_GLOBAL,
+    WASM_SEC_ORDER_EVENT,
+    WASM_SEC_ORDER_EXPORT,
+    WASM_SEC_ORDER_START,
+    WASM_SEC_ORDER_ELEM,
+    WASM_SEC_ORDER_DATACOUNT,
+    WASM_SEC_ORDER_CODE,
+    WASM_SEC_ORDER_DATA,
+
+    // Custom sections
+    // "dylink" should be the very first section in the module
+    WASM_SEC_ORDER_DYLINK,
+    // "linking" section requires DATA section in order to validate data symbols
+    WASM_SEC_ORDER_LINKING,
+    // Must come after "linking" section in order to validate reloc indexes.
+    WASM_SEC_ORDER_RELOC,
+    // "name" section must appear after DATA. Comes after "linking" to allow
+    // symbol table to set default function name.
+    WASM_SEC_ORDER_NAME,
+    // "producers" section must appear after "name" section.
+    WASM_SEC_ORDER_PRODUCERS,
+    // "target_features" section must appear after producers section
+    WASM_SEC_ORDER_TARGET_FEATURES,
+
+    // Must be last
+    WASM_NUM_SEC_ORDERS
+
+  };
+
+  // Sections that may or may not be present, but cannot be predecessors
+  static int DisallowedPredecessors[WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS];
+
+  bool isValidSectionOrder(unsigned ID, StringRef CustomSectionName = "");
+
+private:
+  bool Seen[WASM_NUM_SEC_ORDERS] = {}; // Sections that have been seen already
+
+  // Returns -1 for unknown sections.
+  int getSectionOrder(unsigned ID, StringRef CustomSectionName = "");
+};
+
+} // end namespace object
+
+inline raw_ostream &operator<<(raw_ostream &OS, const object::WasmSymbol &Sym) {
+  Sym.print(OS);
+  return OS;
+}
+
+} // end namespace llvm
+
+#endif // LLVM_OBJECT_WASM_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ObjectYAML/DWARFEmitter.h b/binaryen/third_party/llvm-project/include/llvm/ObjectYAML/DWARFEmitter.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ObjectYAML/DWARFEmitter.h
@@ -0,0 +1,55 @@
+//===--- DWARFEmitter.h - ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// Common declarations for yaml2obj
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECTYAML_DWARFEMITTER_H
+#define LLVM_OBJECTYAML_DWARFEMITTER_H
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+
+namespace llvm {
+
+class raw_ostream;
+
+namespace DWARFYAML {
+
+struct Data;
+struct PubSection;
+
+void EmitDebugAbbrev(raw_ostream &OS, const Data &DI);
+void EmitDebugStr(raw_ostream &OS, const Data &DI);
+
+void EmitDebugAranges(raw_ostream &OS, const Data &DI);
+void EmitDebugRanges(raw_ostream &OS, const Data &DI); // XXX BINARYEN
+void EmitDebugLoc(raw_ostream &OS, const Data &DI); // XXX BINARYEN
+void EmitPubSection(raw_ostream &OS, const PubSection &Sect,
+                    bool IsLittleEndian);
+void EmitDebugInfo(raw_ostream &OS, const Data &DI);
+void EmitDebugLine(raw_ostream &OS, const Data &DI);
+// XXX BINARYEN: Same as EmitDebugLine but also update the Length field in
+//               the YAML as we write. We use that information to update
+//               offsets into the debug line section.
+void ComputeDebugLine(Data &DI, std::vector<size_t>& computedLengths);
+
+Expected<StringMap<std::unique_ptr<MemoryBuffer>>>
+EmitDebugSections(StringRef YAMLString, bool ApplyFixups = false,
+                  bool IsLittleEndian = sys::IsLittleEndianHost);
+StringMap<std::unique_ptr<MemoryBuffer>>
+EmitDebugSections(llvm::DWARFYAML::Data &DI, bool ApplyFixups);
+
+} // end namespace DWARFYAML
+} // end namespace llvm
+
+#endif // LLVM_OBJECTYAML_DWARFEMITTER_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ObjectYAML/DWARFYAML.h b/binaryen/third_party/llvm-project/include/llvm/ObjectYAML/DWARFYAML.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ObjectYAML/DWARFYAML.h
@@ -0,0 +1,343 @@
+//===- DWARFYAML.h - DWARF YAMLIO implementation ----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file declares classes for handling the YAML representation
+/// of DWARF Debug Info.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECTYAML_DWARFYAML_H
+#define LLVM_OBJECTYAML_DWARFYAML_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <cstdint>
+#include <vector>
+
+namespace llvm {
+namespace DWARFYAML {
+
+struct InitialLength {
+  uint32_t TotalLength;
+  uint64_t TotalLength64;
+
+  bool isDWARF64() const { return TotalLength == UINT32_MAX; }
+
+  uint64_t getLength() const {
+    return isDWARF64() ? TotalLength64 : TotalLength;
+  }
+
+  void setLength(uint64_t Len) {
+    if (Len >= (uint64_t)UINT32_MAX) {
+      TotalLength64 = Len;
+      TotalLength = UINT32_MAX;
+    } else {
+      TotalLength = Len;
+    }
+  }
+};
+
+struct AttributeAbbrev {
+  llvm::dwarf::Attribute Attribute;
+  llvm::dwarf::Form Form;
+  llvm::yaml::Hex64 Value; // Some DWARF5 attributes have values
+};
+
+struct Abbrev {
+  llvm::yaml::Hex32 Code;
+  llvm::dwarf::Tag Tag;
+  llvm::dwarf::Constants Children;
+  std::vector<AttributeAbbrev> Attributes;
+  // XXX BINARYEN: Represent the binary offset in the abbreviation section for
+  // this abbreviation's list. The abbreviation section has multiple lists,
+  // each null-terminated, and those lists are what are referred to by compile
+  // units by offset. We need to match the offset in a compile unit to the
+  // abbreviation at that offset (which must be the beginning of an
+  // abbreviation list, that is, either the very first element, or after a null
+  // terminator). All abbreviations in the same list have the same offset
+  // (DWARFAbbreviationDeclarationSet does not track anything else, and we don't
+  // need it).
+  uint64_t ListOffset;
+};
+
+struct ARangeDescriptor {
+  llvm::yaml::Hex64 Address;
+  uint64_t Length;
+};
+
+struct ARange {
+  InitialLength Length;
+  uint16_t Version;
+  uint32_t CuOffset;
+  uint8_t AddrSize;
+  uint8_t SegSize;
+  std::vector<ARangeDescriptor> Descriptors;
+};
+
+// XXX BINARYEN <--
+struct Range {
+  uint64_t Start;
+  uint64_t End;
+  uint64_t SectionIndex; // XXX ?
+};
+
+struct Loc {
+  uint32_t Start;
+  uint32_t End;
+  std::vector<uint8_t> Location;
+  uint64_t CompileUnitOffset;
+};
+// XXX BINARYEN -->
+
+struct PubEntry {
+  llvm::yaml::Hex32 DieOffset;
+  llvm::yaml::Hex8 Descriptor;
+  StringRef Name;
+};
+
+struct PubSection {
+  InitialLength Length;
+  uint16_t Version;
+  uint32_t UnitOffset;
+  uint32_t UnitSize;
+  bool IsGNUStyle = false;
+  std::vector<PubEntry> Entries;
+};
+
+struct FormValue {
+  llvm::yaml::Hex64 Value;
+  StringRef CStr;
+  std::vector<llvm::yaml::Hex8> BlockData;
+};
+
+struct Entry {
+  llvm::yaml::Hex32 AbbrCode;
+  std::vector<FormValue> Values;
+};
+
+struct Unit {
+  InitialLength Length;
+  uint16_t Version;
+  llvm::dwarf::UnitType Type; // Added in DWARF 5
+  uint32_t AbbrOffset;
+  uint8_t AddrSize;
+  std::vector<Entry> Entries;
+};
+
+struct File {
+  StringRef Name;
+  uint64_t DirIdx;
+  uint64_t ModTime;
+  uint64_t Length;
+};
+
+struct LineTableOpcode {
+  dwarf::LineNumberOps Opcode;
+  uint64_t ExtLen;
+  dwarf::LineNumberExtendedOps SubOpcode;
+  uint64_t Data;
+  int64_t SData;
+  File FileEntry;
+  std::vector<llvm::yaml::Hex8> UnknownOpcodeData;
+  std::vector<llvm::yaml::Hex64> StandardOpcodeData;
+};
+
+struct LineTable {
+  InitialLength Length;
+  uint16_t Version;
+  uint64_t PrologueLength;
+  uint8_t MinInstLength;
+  uint8_t MaxOpsPerInst;
+  uint8_t DefaultIsStmt;
+  int8_t LineBase; // XXX BINARYEN
+  uint8_t LineRange;
+  uint8_t OpcodeBase;
+  std::vector<uint8_t> StandardOpcodeLengths;
+  std::vector<StringRef> IncludeDirs;
+  std::vector<File> Files;
+  std::vector<LineTableOpcode> Opcodes;
+};
+
+struct Data {
+  bool IsLittleEndian;
+  std::vector<Abbrev> AbbrevDecls;
+  std::vector<StringRef> DebugStrings;
+  std::vector<ARange> ARanges;
+  std::vector<Range> Ranges; // XXX BINARYEN
+  std::vector<Loc> Locs; // XXX BINARYEN
+  PubSection PubNames;
+  PubSection PubTypes;
+
+  PubSection GNUPubNames;
+  PubSection GNUPubTypes;
+
+  std::vector<Unit> CompileUnits;
+
+  std::vector<LineTable> DebugLines;
+
+  bool isEmpty() const;
+};
+
+} // end namespace DWARFYAML
+} // end namespace llvm
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::AttributeAbbrev)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Abbrev)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::ARangeDescriptor)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::ARange)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Range) // XXX BINARYEN
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Loc) // XXX BINARYEN
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::PubEntry)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Unit)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::FormValue)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Entry)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::File)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::LineTable)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::LineTableOpcode)
+
+namespace llvm {
+namespace yaml {
+
+template <> struct MappingTraits<DWARFYAML::Data> {
+  static void mapping(IO &IO, DWARFYAML::Data &DWARF);
+};
+
+template <> struct MappingTraits<DWARFYAML::Abbrev> {
+  static void mapping(IO &IO, DWARFYAML::Abbrev &Abbrev);
+};
+
+template <> struct MappingTraits<DWARFYAML::AttributeAbbrev> {
+  static void mapping(IO &IO, DWARFYAML::AttributeAbbrev &AttAbbrev);
+};
+
+template <> struct MappingTraits<DWARFYAML::ARangeDescriptor> {
+  static void mapping(IO &IO, DWARFYAML::ARangeDescriptor &Descriptor);
+};
+
+template <> struct MappingTraits<DWARFYAML::ARange> {
+  static void mapping(IO &IO, DWARFYAML::ARange &Range);
+};
+
+template <> struct MappingTraits<DWARFYAML::Range> { // XXX BINARYEN
+  static void mapping(IO &IO, DWARFYAML::Range &Range);
+};
+
+template <> struct MappingTraits<DWARFYAML::Loc> { // XXX BINARYEN
+  static void mapping(IO &IO, DWARFYAML::Loc &Loc);
+};
+
+template <> struct MappingTraits<DWARFYAML::PubEntry> {
+  static void mapping(IO &IO, DWARFYAML::PubEntry &Entry);
+};
+
+template <> struct MappingTraits<DWARFYAML::PubSection> {
+  static void mapping(IO &IO, DWARFYAML::PubSection &Section);
+};
+
+template <> struct MappingTraits<DWARFYAML::Unit> {
+  static void mapping(IO &IO, DWARFYAML::Unit &Unit);
+};
+
+template <> struct MappingTraits<DWARFYAML::Entry> {
+  static void mapping(IO &IO, DWARFYAML::Entry &Entry);
+};
+
+template <> struct MappingTraits<DWARFYAML::FormValue> {
+  static void mapping(IO &IO, DWARFYAML::FormValue &FormValue);
+};
+
+template <> struct MappingTraits<DWARFYAML::File> {
+  static void mapping(IO &IO, DWARFYAML::File &File);
+};
+
+template <> struct MappingTraits<DWARFYAML::LineTableOpcode> {
+  static void mapping(IO &IO, DWARFYAML::LineTableOpcode &LineTableOpcode);
+};
+
+template <> struct MappingTraits<DWARFYAML::LineTable> {
+  static void mapping(IO &IO, DWARFYAML::LineTable &LineTable);
+};
+
+template <> struct MappingTraits<DWARFYAML::InitialLength> {
+  static void mapping(IO &IO, DWARFYAML::InitialLength &DWARF);
+};
+
+#define HANDLE_DW_TAG(unused, name, unused2, unused3, unused4)                 \
+  io.enumCase(value, "DW_TAG_" #name, dwarf::DW_TAG_##name);
+
+template <> struct ScalarEnumerationTraits<dwarf::Tag> {
+  static void enumeration(IO &io, dwarf::Tag &value) {
+#include "llvm/BinaryFormat/Dwarf.def"
+    io.enumFallback<Hex16>(value);
+  }
+};
+
+#define HANDLE_DW_LNS(unused, name)                                            \
+  io.enumCase(value, "DW_LNS_" #name, dwarf::DW_LNS_##name);
+
+template <> struct ScalarEnumerationTraits<dwarf::LineNumberOps> {
+  static void enumeration(IO &io, dwarf::LineNumberOps &value) {
+#include "llvm/BinaryFormat/Dwarf.def"
+    io.enumFallback<Hex8>(value);
+  }
+};
+
+#define HANDLE_DW_LNE(unused, name)                                            \
+  io.enumCase(value, "DW_LNE_" #name, dwarf::DW_LNE_##name);
+
+template <> struct ScalarEnumerationTraits<dwarf::LineNumberExtendedOps> {
+  static void enumeration(IO &io, dwarf::LineNumberExtendedOps &value) {
+#include "llvm/BinaryFormat/Dwarf.def"
+    io.enumFallback<Hex16>(value);
+  }
+};
+
+#define HANDLE_DW_AT(unused, name, unused2, unused3)                           \
+  io.enumCase(value, "DW_AT_" #name, dwarf::DW_AT_##name);
+
+template <> struct ScalarEnumerationTraits<dwarf::Attribute> {
+  static void enumeration(IO &io, dwarf::Attribute &value) {
+#include "llvm/BinaryFormat/Dwarf.def"
+    io.enumFallback<Hex16>(value);
+  }
+};
+
+#define HANDLE_DW_FORM(unused, name, unused2, unused3)                         \
+  io.enumCase(value, "DW_FORM_" #name, dwarf::DW_FORM_##name);
+
+template <> struct ScalarEnumerationTraits<dwarf::Form> {
+  static void enumeration(IO &io, dwarf::Form &value) {
+#include "llvm/BinaryFormat/Dwarf.def"
+    io.enumFallback<Hex16>(value);
+  }
+};
+
+#define HANDLE_DW_UT(unused, name)                                             \
+  io.enumCase(value, "DW_UT_" #name, dwarf::DW_UT_##name);
+
+template <> struct ScalarEnumerationTraits<dwarf::UnitType> {
+  static void enumeration(IO &io, dwarf::UnitType &value) {
+#include "llvm/BinaryFormat/Dwarf.def"
+    io.enumFallback<Hex8>(value);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<dwarf::Constants> {
+  static void enumeration(IO &io, dwarf::Constants &value) {
+    io.enumCase(value, "DW_CHILDREN_no", dwarf::DW_CHILDREN_no);
+    io.enumCase(value, "DW_CHILDREN_yes", dwarf::DW_CHILDREN_yes);
+    io.enumFallback<Hex16>(value);
+  }
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+#endif // LLVM_OBJECTYAML_DWARFYAML_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/ObjectYAML/ObjectYAML.h b/binaryen/third_party/llvm-project/include/llvm/ObjectYAML/ObjectYAML.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/ObjectYAML/ObjectYAML.h
@@ -0,0 +1,41 @@
+//===- ObjectYAML.h ---------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECTYAML_OBJECTYAML_H
+#define LLVM_OBJECTYAML_OBJECTYAML_H
+
+#include "llvm/ObjectYAML/COFFYAML.h"
+#include "llvm/ObjectYAML/ELFYAML.h"
+#include "llvm/ObjectYAML/MachOYAML.h"
+#include "llvm/ObjectYAML/MinidumpYAML.h"
+#include "llvm/ObjectYAML/WasmYAML.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <memory>
+
+namespace llvm {
+namespace yaml {
+
+class IO;
+
+struct YamlObjectFile {
+  std::unique_ptr<ELFYAML::Object> Elf;
+  std::unique_ptr<COFFYAML::Object> Coff;
+  std::unique_ptr<MachOYAML::Object> MachO;
+  std::unique_ptr<MachOYAML::UniversalBinary> FatMachO;
+  std::unique_ptr<MinidumpYAML::Object> Minidump;
+  std::unique_ptr<WasmYAML::Object> Wasm;
+};
+
+template <> struct MappingTraits<YamlObjectFile> {
+  static void mapping(IO &IO, YamlObjectFile &ObjectFile);
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+#endif // LLVM_OBJECTYAML_OBJECTYAML_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/AArch64TargetParser.def b/binaryen/third_party/llvm-project/include/llvm/Support/AArch64TargetParser.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/AArch64TargetParser.def
@@ -0,0 +1,151 @@
+//===- AARCH64TargetParser.def - AARCH64 target parsing defines ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides defines to build up the AARCH64 target parser's logic.
+//
+//===----------------------------------------------------------------------===//
+
+// NOTE: NO INCLUDE GUARD DESIRED!
+
+#ifndef AARCH64_ARCH
+#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT)
+#endif
+AARCH64_ARCH("invalid", INVALID, "", "",
+             ARMBuildAttrs::CPUArch::v8_A, FK_NONE, AArch64::AEK_NONE)
+AARCH64_ARCH("armv8-a", ARMV8A, "8-A", "v8", ARMBuildAttrs::CPUArch::v8_A,
+             FK_CRYPTO_NEON_FP_ARMV8,
+             (AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_SIMD))
+AARCH64_ARCH("armv8.1-a", ARMV8_1A, "8.1-A", "v8.1a",
+             ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
+             (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+              AArch64::AEK_SIMD | AArch64::AEK_LSE | AArch64::AEK_RDM))
+AARCH64_ARCH("armv8.2-a", ARMV8_2A, "8.2-A", "v8.2a",
+             ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
+             (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+              AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE |
+              AArch64::AEK_RDM))
+AARCH64_ARCH("armv8.3-a", ARMV8_3A, "8.3-A", "v8.3a",
+             ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
+             (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+              AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE |
+              AArch64::AEK_RDM | AArch64::AEK_RCPC))
+AARCH64_ARCH("armv8.4-a", ARMV8_4A, "8.4-A", "v8.4a",
+             ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
+             (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+              AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE |
+              AArch64::AEK_RDM | AArch64::AEK_RCPC | AArch64::AEK_DOTPROD))
+AARCH64_ARCH("armv8.5-a", ARMV8_5A, "8.5-A", "v8.5a",
+             ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
+             (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+              AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE |
+              AArch64::AEK_RDM | AArch64::AEK_RCPC | AArch64::AEK_DOTPROD))
+#undef AARCH64_ARCH
+
+#ifndef AARCH64_ARCH_EXT_NAME
+#define AARCH64_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE)
+#endif
+// FIXME: This would be nicer were it tablegen
+AARCH64_ARCH_EXT_NAME("invalid",      AArch64::AEK_INVALID,     nullptr,  nullptr)
+AARCH64_ARCH_EXT_NAME("none",         AArch64::AEK_NONE,        nullptr,  nullptr)
+AARCH64_ARCH_EXT_NAME("crc",          AArch64::AEK_CRC,         "+crc",   "-crc")
+AARCH64_ARCH_EXT_NAME("lse",          AArch64::AEK_LSE,         "+lse",   "-lse")
+AARCH64_ARCH_EXT_NAME("rdm",          AArch64::AEK_RDM,         "+rdm",   "-rdm")
+AARCH64_ARCH_EXT_NAME("crypto",       AArch64::AEK_CRYPTO,      "+crypto","-crypto")
+AARCH64_ARCH_EXT_NAME("sm4",          AArch64::AEK_SM4,         "+sm4",   "-sm4")
+AARCH64_ARCH_EXT_NAME("sha3",         AArch64::AEK_SHA3,        "+sha3",  "-sha3")
+AARCH64_ARCH_EXT_NAME("sha2",         AArch64::AEK_SHA2,        "+sha2",  "-sha2")
+AARCH64_ARCH_EXT_NAME("aes",          AArch64::AEK_AES,         "+aes",   "-aes")
+AARCH64_ARCH_EXT_NAME("dotprod",      AArch64::AEK_DOTPROD,     "+dotprod","-dotprod")
+AARCH64_ARCH_EXT_NAME("fp",           AArch64::AEK_FP,          "+fp-armv8",  "-fp-armv8")
+AARCH64_ARCH_EXT_NAME("simd",         AArch64::AEK_SIMD,        "+neon",  "-neon")
+AARCH64_ARCH_EXT_NAME("fp16",         AArch64::AEK_FP16,        "+fullfp16",  "-fullfp16")
+AARCH64_ARCH_EXT_NAME("fp16fml",      AArch64::AEK_FP16FML,     "+fp16fml", "-fp16fml")
+AARCH64_ARCH_EXT_NAME("profile",      AArch64::AEK_PROFILE,     "+spe",  "-spe")
+AARCH64_ARCH_EXT_NAME("ras",          AArch64::AEK_RAS,         "+ras",  "-ras")
+AARCH64_ARCH_EXT_NAME("sve",          AArch64::AEK_SVE,         "+sve",  "-sve")
+AARCH64_ARCH_EXT_NAME("sve2",         AArch64::AEK_SVE2,        "+sve2", "-sve2")
+AARCH64_ARCH_EXT_NAME("sve2-aes",     AArch64::AEK_SVE2AES,     "+sve2-aes", "-sve2-aes")
+AARCH64_ARCH_EXT_NAME("sve2-sm4",     AArch64::AEK_SVE2SM4,     "+sve2-sm4", "-sve2-sm4")
+AARCH64_ARCH_EXT_NAME("sve2-sha3",    AArch64::AEK_SVE2SHA3,    "+sve2-sha3", "-sve2-sha3")
+AARCH64_ARCH_EXT_NAME("sve2-bitperm", AArch64::AEK_SVE2BITPERM, "+sve2-bitperm", "-sve2-bitperm")
+AARCH64_ARCH_EXT_NAME("rcpc",         AArch64::AEK_RCPC,        "+rcpc", "-rcpc")
+AARCH64_ARCH_EXT_NAME("rng",          AArch64::AEK_RAND,        "+rand",  "-rand")
+AARCH64_ARCH_EXT_NAME("memtag",       AArch64::AEK_MTE,         "+mte",   "-mte")
+AARCH64_ARCH_EXT_NAME("ssbs",         AArch64::AEK_SSBS,        "+ssbs",  "-ssbs")
+AARCH64_ARCH_EXT_NAME("sb",           AArch64::AEK_SB,          "+sb",    "-sb")
+AARCH64_ARCH_EXT_NAME("predres",      AArch64::AEK_PREDRES,     "+predres", "-predres")
+AARCH64_ARCH_EXT_NAME("tme",          AArch64::AEK_TME,         "+tme",   "-tme")
+#undef AARCH64_ARCH_EXT_NAME
+
+#ifndef AARCH64_CPU_NAME
+#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT)
+#endif
+AARCH64_CPU_NAME("cortex-a35", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_CRC))
+AARCH64_CPU_NAME("cortex-a53", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, true,
+                 (AArch64::AEK_CRC))
+AARCH64_CPU_NAME("cortex-a55", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | AArch64::AEK_RCPC))
+AARCH64_CPU_NAME("cortex-a57", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_CRC))
+AARCH64_CPU_NAME("cortex-a65", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_DOTPROD | AArch64::AEK_FP16 | AArch64::AEK_RAS |
+                  AArch64::AEK_RCPC | AArch64::AEK_SSBS))
+AARCH64_CPU_NAME("cortex-a65ae", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_DOTPROD | AArch64::AEK_FP16 | AArch64::AEK_RAS |
+                  AArch64::AEK_RCPC | AArch64::AEK_SSBS))
+AARCH64_CPU_NAME("cortex-a72", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_CRC))
+AARCH64_CPU_NAME("cortex-a73", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_CRC))
+AARCH64_CPU_NAME("cortex-a75", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | AArch64::AEK_RCPC))
+AARCH64_CPU_NAME("cortex-a76", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | AArch64::AEK_RCPC |
+                  AArch64::AEK_SSBS))
+AARCH64_CPU_NAME("cortex-a76ae", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | AArch64::AEK_RCPC |
+                  AArch64::AEK_SSBS))
+AARCH64_CPU_NAME("neoverse-e1", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_DOTPROD | AArch64::AEK_FP16 | AArch64::AEK_RAS |
+                  AArch64::AEK_RCPC | AArch64::AEK_SSBS))
+AARCH64_CPU_NAME("neoverse-n1", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_DOTPROD | AArch64::AEK_FP16 |
+                  AArch64::AEK_PROFILE | AArch64::AEK_RAS | AArch64::AEK_RCPC |
+                  AArch64::AEK_SSBS))
+AARCH64_CPU_NAME("cyclone", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_NONE))
+AARCH64_CPU_NAME("exynos-m3", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_CRC))
+AARCH64_CPU_NAME("exynos-m4", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_DOTPROD | AArch64::AEK_FP16))
+AARCH64_CPU_NAME("exynos-m5", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_DOTPROD | AArch64::AEK_FP16))
+AARCH64_CPU_NAME("falkor", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_CRC | AArch64::AEK_RDM))
+AARCH64_CPU_NAME("saphira", ARMV8_3A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_PROFILE))
+AARCH64_CPU_NAME("kryo", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_CRC))
+AARCH64_CPU_NAME("thunderx2t99", ARMV8_1A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_NONE))
+AARCH64_CPU_NAME("thunderx", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_CRC | AArch64::AEK_PROFILE))
+AARCH64_CPU_NAME("thunderxt88", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_CRC | AArch64::AEK_PROFILE))
+AARCH64_CPU_NAME("thunderxt81", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_CRC | AArch64::AEK_PROFILE))
+AARCH64_CPU_NAME("thunderxt83", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_CRC | AArch64::AEK_PROFILE))
+AARCH64_CPU_NAME("tsv110", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+                 (AArch64::AEK_DOTPROD |
+                  AArch64::AEK_FP16 | AArch64::AEK_FP16FML |
+                  AArch64::AEK_PROFILE))
+// Invalid CPU
+AARCH64_CPU_NAME("invalid", INVALID, FK_INVALID, true, AArch64::AEK_INVALID)
+#undef AARCH64_CPU_NAME
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/AArch64TargetParser.h b/binaryen/third_party/llvm-project/include/llvm/Support/AArch64TargetParser.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/AArch64TargetParser.h
@@ -0,0 +1,129 @@
+//===-- AArch64TargetParser - Parser for AArch64 features -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a target parser to recognise AArch64 hardware features
+// such as FPU/CPU/ARCH and extension names.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_AARCH64TARGETPARSERCOMMON_H
+#define LLVM_SUPPORT_AARCH64TARGETPARSERCOMMON_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/ARMTargetParser.h"
+#include <vector>
+
+// FIXME:This should be made into class design,to avoid dupplication.
+namespace llvm {
+namespace AArch64 {
+
+// Arch extension modifiers for CPUs.
+enum ArchExtKind : unsigned {
+  AEK_INVALID =     0,
+  AEK_NONE =        1,
+  AEK_CRC =         1 << 1,
+  AEK_CRYPTO =      1 << 2,
+  AEK_FP =          1 << 3,
+  AEK_SIMD =        1 << 4,
+  AEK_FP16 =        1 << 5,
+  AEK_PROFILE =     1 << 6,
+  AEK_RAS =         1 << 7,
+  AEK_LSE =         1 << 8,
+  AEK_SVE =         1 << 9,
+  AEK_DOTPROD =     1 << 10,
+  AEK_RCPC =        1 << 11,
+  AEK_RDM =         1 << 12,
+  AEK_SM4 =         1 << 13,
+  AEK_SHA3 =        1 << 14,
+  AEK_SHA2 =        1 << 15,
+  AEK_AES =         1 << 16,
+  AEK_FP16FML =     1 << 17,
+  AEK_RAND =        1 << 18,
+  AEK_MTE =         1 << 19,
+  AEK_SSBS =        1 << 20,
+  AEK_SB =          1 << 21,
+  AEK_PREDRES =     1 << 22,
+  AEK_SVE2 =        1 << 23,
+  AEK_SVE2AES =     1 << 24,
+  AEK_SVE2SM4 =     1 << 25,
+  AEK_SVE2SHA3 =    1 << 26,
+  AEK_SVE2BITPERM = 1 << 27,
+  AEK_TME =         1 << 28,
+};
+
+enum class ArchKind {
+#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) ID,
+#include "AArch64TargetParser.def"
+};
+
+const ARM::ArchNames<ArchKind> AArch64ARCHNames[] = {
+#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU,        \
+                     ARCH_BASE_EXT)                                            \
+  {NAME,                                                                       \
+   sizeof(NAME) - 1,                                                           \
+   CPU_ATTR,                                                                   \
+   sizeof(CPU_ATTR) - 1,                                                       \
+   SUB_ARCH,                                                                   \
+   sizeof(SUB_ARCH) - 1,                                                       \
+   ARM::FPUKind::ARCH_FPU,                                                     \
+   ARCH_BASE_EXT,                                                              \
+   AArch64::ArchKind::ID,                                                      \
+   ARCH_ATTR},
+#include "AArch64TargetParser.def"
+};
+
+const ARM::ExtName AArch64ARCHExtNames[] = {
+#define AARCH64_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE)                   \
+  {NAME, sizeof(NAME) - 1, ID, FEATURE, NEGFEATURE},
+#include "AArch64TargetParser.def"
+};
+
+const ARM::CpuNames<ArchKind> AArch64CPUNames[] = {
+#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT)       \
+  {NAME, sizeof(NAME) - 1, AArch64::ArchKind::ID, IS_DEFAULT, DEFAULT_EXT},
+#include "AArch64TargetParser.def"
+};
+
+const ArchKind ArchKinds[] = {
+#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) \
+    ArchKind::ID,
+#include "AArch64TargetParser.def"
+};
+
+// FIXME: These should be moved to TargetTuple once it exists
+bool getExtensionFeatures(unsigned Extensions,
+                          std::vector<StringRef> &Features);
+bool getArchFeatures(ArchKind AK, std::vector<StringRef> &Features);
+
+StringRef getArchName(ArchKind AK);
+unsigned getArchAttr(ArchKind AK);
+StringRef getCPUAttr(ArchKind AK);
+StringRef getSubArch(ArchKind AK);
+StringRef getArchExtName(unsigned ArchExtKind);
+StringRef getArchExtFeature(StringRef ArchExt);
+
+// Information by Name
+unsigned getDefaultFPU(StringRef CPU, ArchKind AK);
+unsigned getDefaultExtensions(StringRef CPU, ArchKind AK);
+StringRef getDefaultCPU(StringRef Arch);
+ArchKind getCPUArchKind(StringRef CPU);
+
+// Parser
+ArchKind parseArch(StringRef Arch);
+ArchExtKind parseArchExt(StringRef ArchExt);
+ArchKind parseCPUArch(StringRef CPU);
+// Used by target parser tests
+void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values);
+
+bool isX18ReservedByDefault(const Triple &TT);
+
+} // namespace AArch64
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/ARMAttributeParser.h b/binaryen/third_party/llvm-project/include/llvm/Support/ARMAttributeParser.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/ARMAttributeParser.h
@@ -0,0 +1,141 @@
+//===--- ARMAttributeParser.h - ARM Attribute Information Printer ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ARMATTRIBUTEPARSER_H
+#define LLVM_SUPPORT_ARMATTRIBUTEPARSER_H
+
+#include "ARMBuildAttributes.h"
+#include "ScopedPrinter.h"
+
+#include <map>
+
+namespace llvm {
+class StringRef;
+
+class ARMAttributeParser {
+  ScopedPrinter *SW;
+
+  std::map<unsigned, unsigned> Attributes;
+
+  struct DisplayHandler {
+    ARMBuildAttrs::AttrType Attribute;
+    void (ARMAttributeParser::*Routine)(ARMBuildAttrs::AttrType,
+                                        const uint8_t *, uint32_t &);
+  };
+  static const DisplayHandler DisplayRoutines[];
+
+  uint64_t ParseInteger(const uint8_t *Data, uint32_t &Offset);
+  StringRef ParseString(const uint8_t *Data, uint32_t &Offset);
+
+  void IntegerAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                        uint32_t &Offset);
+  void StringAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                       uint32_t &Offset);
+
+  void PrintAttribute(unsigned Tag, unsigned Value, StringRef ValueDesc);
+
+  void CPU_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                uint32_t &Offset);
+  void CPU_arch_profile(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                        uint32_t &Offset);
+  void ARM_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                   uint32_t &Offset);
+  void THUMB_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                     uint32_t &Offset);
+  void FP_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+               uint32_t &Offset);
+  void WMMX_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                 uint32_t &Offset);
+  void Advanced_SIMD_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                          uint32_t &Offset);
+  void MVE_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                uint32_t &Offset);
+  void PCS_config(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                  uint32_t &Offset);
+  void ABI_PCS_R9_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                      uint32_t &Offset);
+  void ABI_PCS_RW_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                       uint32_t &Offset);
+  void ABI_PCS_RO_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                       uint32_t &Offset);
+  void ABI_PCS_GOT_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                       uint32_t &Offset);
+  void ABI_PCS_wchar_t(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                       uint32_t &Offset);
+  void ABI_FP_rounding(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                       uint32_t &Offset);
+  void ABI_FP_denormal(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                       uint32_t &Offset);
+  void ABI_FP_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                         uint32_t &Offset);
+  void ABI_FP_user_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                              uint32_t &Offset);
+  void ABI_FP_number_model(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                           uint32_t &Offset);
+  void ABI_align_needed(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                        uint32_t &Offset);
+  void ABI_align_preserved(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                           uint32_t &Offset);
+  void ABI_enum_size(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                     uint32_t &Offset);
+  void ABI_HardFP_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                      uint32_t &Offset);
+  void ABI_VFP_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                    uint32_t &Offset);
+  void ABI_WMMX_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                     uint32_t &Offset);
+  void ABI_optimization_goals(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                              uint32_t &Offset);
+  void ABI_FP_optimization_goals(ARMBuildAttrs::AttrType Tag,
+                                 const uint8_t *Data, uint32_t &Offset);
+  void compatibility(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                     uint32_t &Offset);
+  void CPU_unaligned_access(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                            uint32_t &Offset);
+  void FP_HP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                       uint32_t &Offset);
+  void ABI_FP_16bit_format(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                           uint32_t &Offset);
+  void MPextension_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                       uint32_t &Offset);
+  void DIV_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+               uint32_t &Offset);
+  void DSP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                     uint32_t &Offset);
+  void T2EE_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                uint32_t &Offset);
+  void Virtualization_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                          uint32_t &Offset);
+  void nodefaults(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
+                  uint32_t &Offset);
+
+  void ParseAttributeList(const uint8_t *Data, uint32_t &Offset,
+                          uint32_t Length);
+  void ParseIndexList(const uint8_t *Data, uint32_t &Offset,
+                      SmallVectorImpl<uint8_t> &IndexList);
+  void ParseSubsection(const uint8_t *Data, uint32_t Length);
+public:
+  ARMAttributeParser(ScopedPrinter *SW) : SW(SW) {}
+
+  ARMAttributeParser() : SW(nullptr) { }
+
+  void Parse(ArrayRef<uint8_t> Section, bool isLittle);
+
+  bool hasAttribute(unsigned Tag) const {
+    return Attributes.count(Tag);
+  }
+
+  unsigned getAttributeValue(unsigned Tag) const {
+    return Attributes.find(Tag)->second;
+  }
+};
+
+}
+
+#endif
+
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/ARMBuildAttributes.h b/binaryen/third_party/llvm-project/include/llvm/Support/ARMBuildAttributes.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/ARMBuildAttributes.h
@@ -0,0 +1,253 @@
+//===-- ARMBuildAttributes.h - ARM Build Attributes -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains enumerations and support routines for ARM build attributes
+// as defined in ARM ABI addenda document (ABI release 2.08).
+//
+// ELF for the ARM Architecture r2.09 - November 30, 2012
+//
+// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044e/IHI0044E_aaelf.pdf
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ARMBUILDATTRIBUTES_H
+#define LLVM_SUPPORT_ARMBUILDATTRIBUTES_H
+
+namespace llvm {
+class StringRef;
+
+namespace ARMBuildAttrs {
+
+enum SpecialAttr {
+  // This is for the .cpu asm attr. It translates into one or more
+  // AttrType (below) entries in the .ARM.attributes section in the ELF.
+  SEL_CPU
+};
+
+enum AttrType {
+  // Rest correspond to ELF/.ARM.attributes
+  File                      = 1,
+  CPU_raw_name              = 4,
+  CPU_name                  = 5,
+  CPU_arch                  = 6,
+  CPU_arch_profile          = 7,
+  ARM_ISA_use               = 8,
+  THUMB_ISA_use             = 9,
+  FP_arch                   = 10,
+  WMMX_arch                 = 11,
+  Advanced_SIMD_arch        = 12,
+  PCS_config                = 13,
+  ABI_PCS_R9_use            = 14,
+  ABI_PCS_RW_data           = 15,
+  ABI_PCS_RO_data           = 16,
+  ABI_PCS_GOT_use           = 17,
+  ABI_PCS_wchar_t           = 18,
+  ABI_FP_rounding           = 19,
+  ABI_FP_denormal           = 20,
+  ABI_FP_exceptions         = 21,
+  ABI_FP_user_exceptions    = 22,
+  ABI_FP_number_model       = 23,
+  ABI_align_needed          = 24,
+  ABI_align_preserved       = 25,
+  ABI_enum_size             = 26,
+  ABI_HardFP_use            = 27,
+  ABI_VFP_args              = 28,
+  ABI_WMMX_args             = 29,
+  ABI_optimization_goals    = 30,
+  ABI_FP_optimization_goals = 31,
+  compatibility             = 32,
+  CPU_unaligned_access      = 34,
+  FP_HP_extension           = 36,
+  ABI_FP_16bit_format       = 38,
+  MPextension_use           = 42, // recoded from 70 (ABI r2.08)
+  DIV_use                   = 44,
+  DSP_extension             = 46,
+  MVE_arch                  = 48,
+  also_compatible_with      = 65,
+  conformance               = 67,
+  Virtualization_use        = 68,
+
+  /// Legacy Tags
+  Section                   = 2,  // deprecated (ABI r2.09)
+  Symbol                    = 3,  // deprecated (ABI r2.09)
+  ABI_align8_needed         = 24, // renamed to ABI_align_needed (ABI r2.09)
+  ABI_align8_preserved      = 25, // renamed to ABI_align_preserved (ABI r2.09)
+  nodefaults                = 64, // deprecated (ABI r2.09)
+  T2EE_use                  = 66, // deprecated (ABI r2.09)
+  MPextension_use_old       = 70  // recoded to MPextension_use (ABI r2.08)
+};
+
+StringRef AttrTypeAsString(unsigned Attr, bool HasTagPrefix = true);
+StringRef AttrTypeAsString(AttrType Attr, bool HasTagPrefix = true);
+int AttrTypeFromString(StringRef Tag);
+
+// Magic numbers for .ARM.attributes
+enum AttrMagic {
+  Format_Version  = 0x41
+};
+
+// Legal Values for CPU_arch, (=6), uleb128
+enum CPUArch {
+  Pre_v4   = 0,
+  v4       = 1,   // e.g. SA110
+  v4T      = 2,   // e.g. ARM7TDMI
+  v5T      = 3,   // e.g. ARM9TDMI
+  v5TE     = 4,   // e.g. ARM946E_S
+  v5TEJ    = 5,   // e.g. ARM926EJ_S
+  v6       = 6,   // e.g. ARM1136J_S
+  v6KZ     = 7,   // e.g. ARM1176JZ_S
+  v6T2     = 8,   // e.g. ARM1156T2_S
+  v6K      = 9,   // e.g. ARM1176JZ_S
+  v7       = 10,  // e.g. Cortex A8, Cortex M3
+  v6_M     = 11,  // e.g. Cortex M1
+  v6S_M    = 12,  // v6_M with the System extensions
+  v7E_M    = 13,  // v7_M with DSP extensions
+  v8_A     = 14,  // v8_A AArch32
+  v8_R     = 15,  // e.g. Cortex R52
+  v8_M_Base= 16,  // v8_M_Base AArch32
+  v8_M_Main= 17,  // v8_M_Main AArch32
+  v8_1_M_Main=21, // v8_1_M_Main AArch32
+};
+
+enum CPUArchProfile {               // (=7), uleb128
+  Not_Applicable          = 0,      // pre v7, or cross-profile code
+  ApplicationProfile      = (0x41), // 'A' (e.g. for Cortex A8)
+  RealTimeProfile         = (0x52), // 'R' (e.g. for Cortex R4)
+  MicroControllerProfile  = (0x4D), // 'M' (e.g. for Cortex M3)
+  SystemProfile           = (0x53)  // 'S' Application or real-time profile
+};
+
+// The following have a lot of common use cases
+enum {
+  Not_Allowed = 0,
+  Allowed = 1,
+
+  // Tag_ARM_ISA_use (=8), uleb128
+
+  // Tag_THUMB_ISA_use, (=9), uleb128
+  AllowThumb32 = 2, // 32-bit Thumb (implies 16-bit instructions)
+  AllowThumbDerived = 3, // Thumb allowed, derived from arch/profile
+
+  // Tag_FP_arch (=10), uleb128 (formerly Tag_VFP_arch = 10)
+  AllowFPv2  = 2,     // v2 FP ISA permitted (implies use of the v1 FP ISA)
+  AllowFPv3A = 3,     // v3 FP ISA permitted (implies use of the v2 FP ISA)
+  AllowFPv3B = 4,     // v3 FP ISA permitted, but only D0-D15, S0-S31
+  AllowFPv4A = 5,     // v4 FP ISA permitted (implies use of v3 FP ISA)
+  AllowFPv4B = 6,     // v4 FP ISA was permitted, but only D0-D15, S0-S31
+  AllowFPARMv8A = 7,  // Use of the ARM v8-A FP ISA was permitted
+  AllowFPARMv8B = 8,  // Use of the ARM v8-A FP ISA was permitted, but only
+                      // D0-D15, S0-S31
+
+  // Tag_WMMX_arch, (=11), uleb128
+  AllowWMMXv1 = 1,  // The user permitted this entity to use WMMX v1
+  AllowWMMXv2 = 2,  // The user permitted this entity to use WMMX v2
+
+  // Tag_Advanced_SIMD_arch, (=12), uleb128
+  AllowNeon = 1,      // SIMDv1 was permitted
+  AllowNeon2 = 2,     // SIMDv2 was permitted (Half-precision FP, MAC operations)
+  AllowNeonARMv8 = 3, // ARM v8-A SIMD was permitted
+  AllowNeonARMv8_1a = 4,// ARM v8.1-A SIMD was permitted (RDMA)
+
+  // Tag_MVE_arch, (=48), uleb128
+  AllowMVEInteger = 1, // integer-only MVE was permitted
+  AllowMVEIntegerAndFloat = 2, // both integer and floating point MVE were permitted
+
+  // Tag_ABI_PCS_R9_use, (=14), uleb128
+  R9IsGPR = 0,        // R9 used as v6 (just another callee-saved register)
+  R9IsSB = 1,         // R9 used as a global static base rgister
+  R9IsTLSPointer = 2, // R9 used as a thread local storage pointer
+  R9Reserved = 3,     // R9 not used by code associated with attributed entity
+
+  // Tag_ABI_PCS_RW_data, (=15), uleb128
+  AddressRWPCRel = 1, // Address RW static data PC-relative
+  AddressRWSBRel = 2, // Address RW static data SB-relative
+  AddressRWNone = 3, // No RW static data permitted
+
+  // Tag_ABI_PCS_RO_data, (=14), uleb128
+  AddressROPCRel = 1, // Address RO static data PC-relative
+  AddressRONone = 2, // No RO static data permitted
+
+  // Tag_ABI_PCS_GOT_use, (=17), uleb128
+  AddressDirect = 1, // Address imported data directly
+  AddressGOT = 2, // Address imported data indirectly (via GOT)
+
+  // Tag_ABI_PCS_wchar_t, (=18), uleb128
+  WCharProhibited = 0,  // wchar_t is not used
+  WCharWidth2Bytes = 2, // sizeof(wchar_t) == 2
+  WCharWidth4Bytes = 4, // sizeof(wchar_t) == 4
+
+  // Tag_ABI_align_needed, (=24), uleb128
+  Align8Byte = 1,
+  Align4Byte = 2,
+  AlignReserved = 3,
+
+  // Tag_ABI_align_needed, (=25), uleb128
+  AlignNotPreserved = 0,
+  AlignPreserve8Byte = 1,
+  AlignPreserveAll = 2,
+
+  // Tag_ABI_FP_denormal, (=20), uleb128
+  PositiveZero = 0,
+  IEEEDenormals = 1,
+  PreserveFPSign = 2, // sign when flushed-to-zero is preserved
+
+  // Tag_ABI_FP_number_model, (=23), uleb128
+  AllowIEEENormal = 1,
+  AllowRTABI = 2,  // numbers, infinities, and one quiet NaN (see [RTABI])
+  AllowIEEE754 = 3, // this code to use all the IEEE 754-defined FP encodings
+
+  // Tag_ABI_enum_size, (=26), uleb128
+  EnumProhibited = 0, // The user prohibited the use of enums when building
+                      // this entity.
+  EnumSmallest = 1,   // Enum is smallest container big enough to hold all
+                      // values.
+  Enum32Bit = 2,      // Enum is at least 32 bits.
+  Enum32BitABI = 3,   // Every enumeration visible across an ABI-complying
+                      // interface contains a value needing 32 bits to encode
+                      // it; other enums can be containerized.
+
+  // Tag_ABI_HardFP_use, (=27), uleb128
+  HardFPImplied = 0,          // FP use should be implied by Tag_FP_arch
+  HardFPSinglePrecision = 1,  // Single-precision only
+
+  // Tag_ABI_VFP_args, (=28), uleb128
+  BaseAAPCS = 0,
+  HardFPAAPCS = 1,
+  ToolChainFPPCS = 2,
+  CompatibleFPAAPCS = 3,
+
+  // Tag_FP_HP_extension, (=36), uleb128
+  AllowHPFP = 1, // Allow use of Half Precision FP
+
+  // Tag_FP_16bit_format, (=38), uleb128
+  FP16FormatIEEE = 1,
+  FP16VFP3 = 2,
+
+  // Tag_MPextension_use, (=42), uleb128
+  AllowMP = 1, // Allow use of MP extensions
+
+  // Tag_DIV_use, (=44), uleb128
+  // Note: AllowDIVExt must be emitted if and only if the permission to use
+  // hardware divide cannot be conveyed using AllowDIVIfExists or DisallowDIV
+  AllowDIVIfExists = 0, // Allow hardware divide if available in arch, or no
+                        // info exists.
+  DisallowDIV = 1,      // Hardware divide explicitly disallowed.
+  AllowDIVExt = 2,      // Allow hardware divide as optional architecture
+                        // extension above the base arch specified by
+                        // Tag_CPU_arch and Tag_CPU_arch_profile.
+
+  // Tag_Virtualization_use, (=68), uleb128
+  AllowTZ = 1,
+  AllowVirtualization = 2,
+  AllowTZVirtualization = 3
+};
+
+} // namespace ARMBuildAttrs
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/ARMTargetParser.def b/binaryen/third_party/llvm-project/include/llvm/Support/ARMTargetParser.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/ARMTargetParser.def
@@ -0,0 +1,293 @@
+//===- ARMTargetParser.def - ARM target parsing defines ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides defines to build up the ARM target parser's logic.
+//
+//===----------------------------------------------------------------------===//
+
+// NOTE: NO INCLUDE GUARD DESIRED!
+
+#ifndef ARM_FPU
+#define ARM_FPU(NAME, KIND, VERSION, NEON_SUPPORT, RESTRICTION)
+#endif
+ARM_FPU("invalid", FK_INVALID, FPUVersion::NONE, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("none", FK_NONE, FPUVersion::NONE, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("vfp", FK_VFP, FPUVersion::VFPV2, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("vfpv2", FK_VFPV2, FPUVersion::VFPV2, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("vfpv3", FK_VFPV3, FPUVersion::VFPV3, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("vfpv3-fp16", FK_VFPV3_FP16, FPUVersion::VFPV3_FP16, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("vfpv3-d16", FK_VFPV3_D16, FPUVersion::VFPV3, NeonSupportLevel::None, FPURestriction::D16)
+ARM_FPU("vfpv3-d16-fp16", FK_VFPV3_D16_FP16, FPUVersion::VFPV3_FP16, NeonSupportLevel::None, FPURestriction::D16)
+ARM_FPU("vfpv3xd", FK_VFPV3XD, FPUVersion::VFPV3, NeonSupportLevel::None, FPURestriction::SP_D16)
+ARM_FPU("vfpv3xd-fp16", FK_VFPV3XD_FP16, FPUVersion::VFPV3_FP16, NeonSupportLevel::None, FPURestriction::SP_D16)
+ARM_FPU("vfpv4", FK_VFPV4, FPUVersion::VFPV4, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("vfpv4-d16", FK_VFPV4_D16, FPUVersion::VFPV4, NeonSupportLevel::None, FPURestriction::D16)
+ARM_FPU("fpv4-sp-d16", FK_FPV4_SP_D16, FPUVersion::VFPV4, NeonSupportLevel::None, FPURestriction::SP_D16)
+ARM_FPU("fpv5-d16", FK_FPV5_D16, FPUVersion::VFPV5, NeonSupportLevel::None, FPURestriction::D16)
+ARM_FPU("fpv5-sp-d16", FK_FPV5_SP_D16, FPUVersion::VFPV5, NeonSupportLevel::None, FPURestriction::SP_D16)
+ARM_FPU("fp-armv8", FK_FP_ARMV8, FPUVersion::VFPV5, NeonSupportLevel::None, FPURestriction::None)
+ARM_FPU("fp-armv8-fullfp16-d16", FK_FP_ARMV8_FULLFP16_D16, FPUVersion::VFPV5_FULLFP16, NeonSupportLevel::None, FPURestriction::D16)
+ARM_FPU("fp-armv8-fullfp16-sp-d16", FK_FP_ARMV8_FULLFP16_SP_D16, FPUVersion::VFPV5_FULLFP16, NeonSupportLevel::None, FPURestriction::SP_D16)
+ARM_FPU("neon", FK_NEON, FPUVersion::VFPV3, NeonSupportLevel::Neon, FPURestriction::None)
+ARM_FPU("neon-fp16", FK_NEON_FP16, FPUVersion::VFPV3_FP16, NeonSupportLevel::Neon, FPURestriction::None)
+ARM_FPU("neon-vfpv4", FK_NEON_VFPV4, FPUVersion::VFPV4, NeonSupportLevel::Neon, FPURestriction::None)
+ARM_FPU("neon-fp-armv8", FK_NEON_FP_ARMV8, FPUVersion::VFPV5, NeonSupportLevel::Neon, FPURestriction::None)
+ARM_FPU("crypto-neon-fp-armv8", FK_CRYPTO_NEON_FP_ARMV8, FPUVersion::VFPV5, NeonSupportLevel::Crypto,
+        FPURestriction::None)
+ARM_FPU("softvfp", FK_SOFTVFP, FPUVersion::NONE, NeonSupportLevel::None, FPURestriction::None)
+#undef ARM_FPU
+
+#ifndef ARM_ARCH
+#define ARM_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT)
+#endif
+ARM_ARCH("invalid", INVALID, "", "",
+          ARMBuildAttrs::CPUArch::Pre_v4, FK_NONE, ARM::AEK_NONE)
+ARM_ARCH("armv2", ARMV2, "2", "v2", ARMBuildAttrs::CPUArch::Pre_v4,
+          FK_NONE, ARM::AEK_NONE)
+ARM_ARCH("armv2a", ARMV2A, "2A", "v2a", ARMBuildAttrs::CPUArch::Pre_v4,
+          FK_NONE, ARM::AEK_NONE)
+ARM_ARCH("armv3", ARMV3, "3", "v3", ARMBuildAttrs::CPUArch::Pre_v4,
+          FK_NONE, ARM::AEK_NONE)
+ARM_ARCH("armv3m", ARMV3M, "3M", "v3m", ARMBuildAttrs::CPUArch::Pre_v4,
+          FK_NONE, ARM::AEK_NONE)
+ARM_ARCH("armv4", ARMV4, "4", "v4", ARMBuildAttrs::CPUArch::v4,
+          FK_NONE, ARM::AEK_NONE)
+ARM_ARCH("armv4t", ARMV4T, "4T", "v4t", ARMBuildAttrs::CPUArch::v4T,
+          FK_NONE, ARM::AEK_NONE)
+ARM_ARCH("armv5t", ARMV5T, "5T", "v5", ARMBuildAttrs::CPUArch::v5T,
+          FK_NONE, ARM::AEK_NONE)
+ARM_ARCH("armv5te", ARMV5TE, "5TE", "v5e", ARMBuildAttrs::CPUArch::v5TE,
+          FK_NONE, ARM::AEK_DSP)
+ARM_ARCH("armv5tej", ARMV5TEJ, "5TEJ", "v5e", ARMBuildAttrs::CPUArch::v5TEJ,
+          FK_NONE, ARM::AEK_DSP)
+ARM_ARCH("armv6", ARMV6, "6", "v6", ARMBuildAttrs::CPUArch::v6,
+          FK_VFPV2, ARM::AEK_DSP)
+ARM_ARCH("armv6k", ARMV6K, "6K", "v6k", ARMBuildAttrs::CPUArch::v6K,
+          FK_VFPV2, ARM::AEK_DSP)
+ARM_ARCH("armv6t2", ARMV6T2, "6T2", "v6t2", ARMBuildAttrs::CPUArch::v6T2,
+          FK_NONE, ARM::AEK_DSP)
+ARM_ARCH("armv6kz", ARMV6KZ, "6KZ", "v6kz", ARMBuildAttrs::CPUArch::v6KZ,
+          FK_VFPV2, (ARM::AEK_SEC | ARM::AEK_DSP))
+ARM_ARCH("armv6-m", ARMV6M, "6-M", "v6m", ARMBuildAttrs::CPUArch::v6_M,
+          FK_NONE, ARM::AEK_NONE)
+ARM_ARCH("armv7-a", ARMV7A, "7-A", "v7", ARMBuildAttrs::CPUArch::v7,
+          FK_NEON, ARM::AEK_DSP)
+ARM_ARCH("armv7ve", ARMV7VE, "7VE", "v7ve", ARMBuildAttrs::CPUArch::v7,
+          FK_NEON, (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT |
+          ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP))
+ARM_ARCH("armv7-r", ARMV7R, "7-R", "v7r", ARMBuildAttrs::CPUArch::v7,
+          FK_NONE, (ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP))
+ARM_ARCH("armv7-m", ARMV7M, "7-M", "v7m", ARMBuildAttrs::CPUArch::v7,
+          FK_NONE, ARM::AEK_HWDIVTHUMB)
+ARM_ARCH("armv7e-m", ARMV7EM, "7E-M", "v7em", ARMBuildAttrs::CPUArch::v7E_M,
+          FK_NONE, (ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP))
+ARM_ARCH("armv8-a", ARMV8A, "8-A", "v8", ARMBuildAttrs::CPUArch::v8_A,
+         FK_CRYPTO_NEON_FP_ARMV8,
+         (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+          ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC))
+ARM_ARCH("armv8.1-a", ARMV8_1A, "8.1-A", "v8.1a",
+         ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
+         (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+          ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC))
+ARM_ARCH("armv8.2-a", ARMV8_2A, "8.2-A", "v8.2a",
+         ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
+         (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+          ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS))
+ARM_ARCH("armv8.3-a", ARMV8_3A, "8.3-A", "v8.3a",
+         ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
+         (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+          ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS))
+ARM_ARCH("armv8.4-a", ARMV8_4A, "8.4-A", "v8.4a",
+         ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
+         (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+          ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS |
+          ARM::AEK_DOTPROD))
+ARM_ARCH("armv8.5-a", ARMV8_5A, "8.5-A", "v8.5a",
+         ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
+         (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+          ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS |
+          ARM::AEK_DOTPROD))
+ARM_ARCH("armv8-r", ARMV8R, "8-R", "v8r", ARMBuildAttrs::CPUArch::v8_R,
+          FK_NEON_FP_ARMV8,
+          (ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB |
+           ARM::AEK_DSP | ARM::AEK_CRC))
+ARM_ARCH("armv8-m.base", ARMV8MBaseline, "8-M.Baseline", "v8m.base",
+          ARMBuildAttrs::CPUArch::v8_M_Base, FK_NONE, ARM::AEK_HWDIVTHUMB)
+ARM_ARCH("armv8-m.main", ARMV8MMainline, "8-M.Mainline", "v8m.main",
+          ARMBuildAttrs::CPUArch::v8_M_Main, FK_FPV5_D16, ARM::AEK_HWDIVTHUMB)
+ARM_ARCH("armv8.1-m.main", ARMV8_1MMainline, "8.1-M.Mainline", "v8.1m.main",
+          ARMBuildAttrs::CPUArch::v8_1_M_Main, FK_FP_ARMV8_FULLFP16_SP_D16, ARM::AEK_HWDIVTHUMB | ARM::AEK_RAS | ARM::AEK_LOB)
+// Non-standard Arch names.
+ARM_ARCH("iwmmxt", IWMMXT, "iwmmxt", "", ARMBuildAttrs::CPUArch::v5TE,
+          FK_NONE, ARM::AEK_NONE)
+ARM_ARCH("iwmmxt2", IWMMXT2, "iwmmxt2", "", ARMBuildAttrs::CPUArch::v5TE,
+          FK_NONE, ARM::AEK_NONE)
+ARM_ARCH("xscale", XSCALE, "xscale", "v5e", ARMBuildAttrs::CPUArch::v5TE,
+          FK_NONE, ARM::AEK_NONE)
+ARM_ARCH("armv7s", ARMV7S, "7-S", "v7s", ARMBuildAttrs::CPUArch::v7,
+          FK_NEON_VFPV4, ARM::AEK_DSP)
+ARM_ARCH("armv7k", ARMV7K, "7-K", "v7k", ARMBuildAttrs::CPUArch::v7,
+          FK_NONE, ARM::AEK_DSP)
+#undef ARM_ARCH
+
+#ifndef ARM_ARCH_EXT_NAME
+#define ARM_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE)
+#endif
+// FIXME: This would be nicer were it tablegen
+ARM_ARCH_EXT_NAME("invalid",  ARM::AEK_INVALID,  nullptr,  nullptr)
+ARM_ARCH_EXT_NAME("none",     ARM::AEK_NONE,     nullptr,  nullptr)
+ARM_ARCH_EXT_NAME("crc",      ARM::AEK_CRC,      "+crc",   "-crc")
+ARM_ARCH_EXT_NAME("crypto",   ARM::AEK_CRYPTO,   "+crypto","-crypto")
+ARM_ARCH_EXT_NAME("sha2",     ARM::AEK_SHA2,     "+sha2",  "-sha2")
+ARM_ARCH_EXT_NAME("aes",      ARM::AEK_AES,      "+aes",   "-aes")
+ARM_ARCH_EXT_NAME("dotprod",  ARM::AEK_DOTPROD,  "+dotprod","-dotprod")
+ARM_ARCH_EXT_NAME("dsp",      ARM::AEK_DSP,      "+dsp",   "-dsp")
+ARM_ARCH_EXT_NAME("fp",       ARM::AEK_FP,       nullptr,  nullptr)
+ARM_ARCH_EXT_NAME("fp.dp",    ARM::AEK_FP_DP,    nullptr,  nullptr)
+ARM_ARCH_EXT_NAME("mve",     (ARM::AEK_DSP | ARM::AEK_SIMD), "+mve", "-mve")
+ARM_ARCH_EXT_NAME("mve.fp",  (ARM::AEK_DSP | ARM::AEK_SIMD | ARM::AEK_FP), "+mve.fp", "-mve.fp")
+ARM_ARCH_EXT_NAME("idiv",     (ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB), nullptr, nullptr)
+ARM_ARCH_EXT_NAME("mp",       ARM::AEK_MP,       nullptr,  nullptr)
+ARM_ARCH_EXT_NAME("simd",     ARM::AEK_SIMD,     nullptr,  nullptr)
+ARM_ARCH_EXT_NAME("sec",      ARM::AEK_SEC,      nullptr,  nullptr)
+ARM_ARCH_EXT_NAME("virt",     ARM::AEK_VIRT,     nullptr,  nullptr)
+ARM_ARCH_EXT_NAME("fp16",     ARM::AEK_FP16,     "+fullfp16",  "-fullfp16")
+ARM_ARCH_EXT_NAME("ras",      ARM::AEK_RAS,      "+ras", "-ras")
+ARM_ARCH_EXT_NAME("os",       ARM::AEK_OS,       nullptr,  nullptr)
+ARM_ARCH_EXT_NAME("iwmmxt",   ARM::AEK_IWMMXT,   nullptr,  nullptr)
+ARM_ARCH_EXT_NAME("iwmmxt2",  ARM::AEK_IWMMXT2,  nullptr,  nullptr)
+ARM_ARCH_EXT_NAME("maverick", ARM::AEK_MAVERICK, nullptr,  nullptr)
+ARM_ARCH_EXT_NAME("xscale",   ARM::AEK_XSCALE,   nullptr,  nullptr)
+ARM_ARCH_EXT_NAME("fp16fml",  ARM::AEK_FP16FML,  "+fp16fml", "-fp16fml")
+ARM_ARCH_EXT_NAME("sb",       ARM::AEK_SB,       "+sb",      "-sb")
+ARM_ARCH_EXT_NAME("lob",      ARM::AEK_LOB,      "+lob",   "-lob")
+#undef ARM_ARCH_EXT_NAME
+
+#ifndef ARM_HW_DIV_NAME
+#define ARM_HW_DIV_NAME(NAME, ID)
+#endif
+ARM_HW_DIV_NAME("invalid", ARM::AEK_INVALID)
+ARM_HW_DIV_NAME("none", ARM::AEK_NONE)
+ARM_HW_DIV_NAME("thumb", ARM::AEK_HWDIVTHUMB)
+ARM_HW_DIV_NAME("arm", ARM::AEK_HWDIVARM)
+ARM_HW_DIV_NAME("arm,thumb", (ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB))
+#undef ARM_HW_DIV_NAME
+
+#ifndef ARM_CPU_NAME
+#define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT)
+#endif
+ARM_CPU_NAME("arm2", ARMV2, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm3", ARMV2A, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm6", ARMV3, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm7m", ARMV3M, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm8", ARMV4, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm810", ARMV4, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("strongarm", ARMV4, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("strongarm110", ARMV4, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("strongarm1100", ARMV4, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("strongarm1110", ARMV4, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm7tdmi", ARMV4T, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm7tdmi-s", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm710t", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm720t", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm9", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm9tdmi", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm920", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm920t", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm922t", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm9312", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm940t", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("ep9312", ARMV4T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm10tdmi", ARMV5T, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1020t", ARMV5T, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm9e", ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm946e-s", ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm966e-s", ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm968e-s", ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm10e", ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1020e", ARMV5TE, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1022e", ARMV5TE, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm926ej-s", ARMV5TEJ, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1136j-s", ARMV6, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1136jf-s", ARMV6, FK_VFPV2, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1136jz-s", ARMV6, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("mpcore", ARMV6K, FK_VFPV2, true, ARM::AEK_NONE)
+ARM_CPU_NAME("mpcorenovfp", ARMV6K, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1176jz-s", ARMV6KZ, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1176jzf-s", ARMV6KZ, FK_VFPV2, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1156t2-s", ARMV6T2, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("arm1156t2f-s", ARMV6T2, FK_VFPV2, false, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m0", ARMV6M, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m0plus", ARMV6M, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m1", ARMV6M, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("sc000", ARMV6M, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-a5", ARMV7A, FK_NEON_VFPV4, false,
+             (ARM::AEK_SEC | ARM::AEK_MP))
+ARM_CPU_NAME("cortex-a7", ARMV7A, FK_NEON_VFPV4, false,
+             (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+              ARM::AEK_HWDIVTHUMB))
+ARM_CPU_NAME("cortex-a8", ARMV7A, FK_NEON, false, ARM::AEK_SEC)
+ARM_CPU_NAME("cortex-a9", ARMV7A, FK_NEON_FP16, false, (ARM::AEK_SEC | ARM::AEK_MP))
+ARM_CPU_NAME("cortex-a12", ARMV7A, FK_NEON_VFPV4, false,
+             (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+              ARM::AEK_HWDIVTHUMB))
+ARM_CPU_NAME("cortex-a15", ARMV7A, FK_NEON_VFPV4, false,
+             (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+              ARM::AEK_HWDIVTHUMB))
+ARM_CPU_NAME("cortex-a17", ARMV7A, FK_NEON_VFPV4, false,
+             (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+              ARM::AEK_HWDIVTHUMB))
+ARM_CPU_NAME("krait", ARMV7A, FK_NEON_VFPV4, false,
+             (ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB))
+ARM_CPU_NAME("cortex-r4", ARMV7R, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-r4f", ARMV7R, FK_VFPV3_D16, false, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-r5", ARMV7R, FK_VFPV3_D16, false,
+             (ARM::AEK_MP | ARM::AEK_HWDIVARM))
+ARM_CPU_NAME("cortex-r7", ARMV7R, FK_VFPV3_D16_FP16, false,
+             (ARM::AEK_MP | ARM::AEK_HWDIVARM))
+ARM_CPU_NAME("cortex-r8", ARMV7R, FK_VFPV3_D16_FP16, false,
+             (ARM::AEK_MP | ARM::AEK_HWDIVARM))
+ARM_CPU_NAME("cortex-r52", ARMV8R, FK_NEON_FP_ARMV8, true, ARM::AEK_NONE)
+ARM_CPU_NAME("sc300", ARMV7M, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m3", ARMV7M, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m4", ARMV7EM, FK_FPV4_SP_D16, true, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m7", ARMV7EM, FK_FPV5_D16, false, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m23", ARMV8MBaseline, FK_NONE, false, ARM::AEK_NONE)
+ARM_CPU_NAME("cortex-m33", ARMV8MMainline, FK_FPV5_SP_D16, false, ARM::AEK_DSP)
+ARM_CPU_NAME("cortex-m35p", ARMV8MMainline, FK_FPV5_SP_D16, false, ARM::AEK_DSP)
+ARM_CPU_NAME("cortex-a32", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("cortex-a35", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("cortex-a53", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("cortex-a55", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+            (ARM::AEK_FP16 | ARM::AEK_DOTPROD))
+ARM_CPU_NAME("cortex-a57", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("cortex-a72", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("cortex-a73", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("cortex-a75", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+            (ARM::AEK_FP16 | ARM::AEK_DOTPROD))
+ARM_CPU_NAME("cortex-a76", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+            (ARM::AEK_FP16 | ARM::AEK_DOTPROD))
+ARM_CPU_NAME("cortex-a76ae", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+            (ARM::AEK_FP16 | ARM::AEK_DOTPROD))
+ARM_CPU_NAME("neoverse-n1", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+             (ARM::AEK_FP16 | ARM::AEK_DOTPROD))
+ARM_CPU_NAME("cyclone", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("exynos-m3", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+ARM_CPU_NAME("exynos-m4", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+             (ARM::AEK_FP16 | ARM::AEK_DOTPROD))
+ARM_CPU_NAME("exynos-m5", ARMV8_2A, FK_CRYPTO_NEON_FP_ARMV8, false,
+             (ARM::AEK_FP16 | ARM::AEK_DOTPROD))
+ARM_CPU_NAME("kryo", ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
+// Non-standard Arch names.
+ARM_CPU_NAME("iwmmxt", IWMMXT, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("xscale", XSCALE, FK_NONE, true, ARM::AEK_NONE)
+ARM_CPU_NAME("swift", ARMV7S, FK_NEON_VFPV4, true,
+             (ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB))
+// Invalid CPU
+ARM_CPU_NAME("invalid", INVALID, FK_INVALID, true, ARM::AEK_INVALID)
+#undef ARM_CPU_NAME
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/ARMTargetParser.h b/binaryen/third_party/llvm-project/include/llvm/Support/ARMTargetParser.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/ARMTargetParser.h
@@ -0,0 +1,267 @@
+//===-- ARMTargetParser - Parser for ARM target features --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a target parser to recognise ARM hardware features
+// such as FPU/CPU/ARCH/extensions and specific support such as HWDIV.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ARMTARGETPARSER_H
+#define LLVM_SUPPORT_ARMTARGETPARSER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/ARMBuildAttributes.h"
+#include <vector>
+
+namespace llvm {
+namespace ARM {
+
+// Arch extension modifiers for CPUs.
+// Note that this is not the same as the AArch64 list
+enum ArchExtKind : unsigned {
+  AEK_INVALID =     0,
+  AEK_NONE =        1,
+  AEK_CRC =         1 << 1,
+  AEK_CRYPTO =      1 << 2,
+  AEK_FP =          1 << 3,
+  AEK_HWDIVTHUMB =  1 << 4,
+  AEK_HWDIVARM =    1 << 5,
+  AEK_MP =          1 << 6,
+  AEK_SIMD =        1 << 7,
+  AEK_SEC =         1 << 8,
+  AEK_VIRT =        1 << 9,
+  AEK_DSP =         1 << 10,
+  AEK_FP16 =        1 << 11,
+  AEK_RAS =         1 << 12,
+  AEK_DOTPROD =     1 << 13,
+  AEK_SHA2    =     1 << 14,
+  AEK_AES     =     1 << 15,
+  AEK_FP16FML =     1 << 16,
+  AEK_SB      =     1 << 17,
+  AEK_FP_DP   =     1 << 18,
+  AEK_LOB     =     1 << 19,
+  // Unsupported extensions.
+  AEK_OS = 0x8000000,
+  AEK_IWMMXT = 0x10000000,
+  AEK_IWMMXT2 = 0x20000000,
+  AEK_MAVERICK = 0x40000000,
+  AEK_XSCALE = 0x80000000,
+};
+
+// List of Arch Extension names.
+// FIXME: TableGen this.
+struct ExtName {
+  const char *NameCStr;
+  size_t NameLength;
+  unsigned ID;
+  const char *Feature;
+  const char *NegFeature;
+
+  StringRef getName() const { return StringRef(NameCStr, NameLength); }
+};
+
+const ExtName ARCHExtNames[] = {
+#define ARM_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE)                       \
+  {NAME, sizeof(NAME) - 1, ID, FEATURE, NEGFEATURE},
+#include "ARMTargetParser.def"
+};
+
+// List of HWDiv names (use getHWDivSynonym) and which architectural
+// features they correspond to (use getHWDivFeatures).
+// FIXME: TableGen this.
+const struct {
+  const char *NameCStr;
+  size_t NameLength;
+  unsigned ID;
+
+  StringRef getName() const { return StringRef(NameCStr, NameLength); }
+} HWDivNames[] = {
+#define ARM_HW_DIV_NAME(NAME, ID) {NAME, sizeof(NAME) - 1, ID},
+#include "ARMTargetParser.def"
+};
+
+// Arch names.
+enum class ArchKind {
+#define ARM_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) ID,
+#include "ARMTargetParser.def"
+};
+
+// List of CPU names and their arches.
+// The same CPU can have multiple arches and can be default on multiple arches.
+// When finding the Arch for a CPU, first-found prevails. Sort them accordingly.
+// When this becomes table-generated, we'd probably need two tables.
+// FIXME: TableGen this.
+template <typename T> struct CpuNames {
+  const char *NameCStr;
+  size_t NameLength;
+  T ArchID;
+  bool Default; // is $Name the default CPU for $ArchID ?
+  unsigned DefaultExtensions;
+
+  StringRef getName() const { return StringRef(NameCStr, NameLength); }
+};
+
+const CpuNames<ArchKind> CPUNames[] = {
+#define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT)           \
+  {NAME, sizeof(NAME) - 1, ARM::ArchKind::ID, IS_DEFAULT, DEFAULT_EXT},
+#include "ARMTargetParser.def"
+};
+
+// FPU names.
+enum FPUKind {
+#define ARM_FPU(NAME, KIND, VERSION, NEON_SUPPORT, RESTRICTION) KIND,
+#include "ARMTargetParser.def"
+  FK_LAST
+};
+
+// FPU Version
+enum class FPUVersion {
+  NONE,
+  VFPV2,
+  VFPV3,
+  VFPV3_FP16,
+  VFPV4,
+  VFPV5,
+  VFPV5_FULLFP16,
+};
+
+// An FPU name restricts the FPU in one of three ways:
+enum class FPURestriction {
+  None = 0, ///< No restriction
+  D16,      ///< Only 16 D registers
+  SP_D16    ///< Only single-precision instructions, with 16 D registers
+};
+
+// An FPU name implies one of three levels of Neon support:
+enum class NeonSupportLevel {
+  None = 0, ///< No Neon
+  Neon,     ///< Neon
+  Crypto    ///< Neon with Crypto
+};
+
+// ISA kinds.
+enum class ISAKind { INVALID = 0, ARM, THUMB, AARCH64 };
+
+// Endianness
+// FIXME: BE8 vs. BE32?
+enum class EndianKind { INVALID = 0, LITTLE, BIG };
+
+// v6/v7/v8 Profile
+enum class ProfileKind { INVALID = 0, A, R, M };
+
+// List of canonical FPU names (use getFPUSynonym) and which architectural
+// features they correspond to (use getFPUFeatures).
+// FIXME: TableGen this.
+// The entries must appear in the order listed in ARM::FPUKind for correct
+// indexing
+struct FPUName {
+  const char *NameCStr;
+  size_t NameLength;
+  FPUKind ID;
+  FPUVersion FPUVer;
+  NeonSupportLevel NeonSupport;
+  FPURestriction Restriction;
+
+  StringRef getName() const { return StringRef(NameCStr, NameLength); }
+};
+
+static const FPUName FPUNames[] = {
+#define ARM_FPU(NAME, KIND, VERSION, NEON_SUPPORT, RESTRICTION)                \
+  {NAME, sizeof(NAME) - 1, KIND, VERSION, NEON_SUPPORT, RESTRICTION},
+#include "llvm/Support/ARMTargetParser.def"
+};
+
+// List of canonical arch names (use getArchSynonym).
+// This table also provides the build attribute fields for CPU arch
+// and Arch ID, according to the Addenda to the ARM ABI, chapters
+// 2.4 and 2.3.5.2 respectively.
+// FIXME: SubArch values were simplified to fit into the expectations
+// of the triples and are not conforming with their official names.
+// Check to see if the expectation should be changed.
+// FIXME: TableGen this.
+template <typename T> struct ArchNames {
+  const char *NameCStr;
+  size_t NameLength;
+  const char *CPUAttrCStr;
+  size_t CPUAttrLength;
+  const char *SubArchCStr;
+  size_t SubArchLength;
+  unsigned DefaultFPU;
+  unsigned ArchBaseExtensions;
+  T ID;
+  ARMBuildAttrs::CPUArch ArchAttr; // Arch ID in build attributes.
+
+  StringRef getName() const { return StringRef(NameCStr, NameLength); }
+
+  // CPU class in build attributes.
+  StringRef getCPUAttr() const { return StringRef(CPUAttrCStr, CPUAttrLength); }
+
+  // Sub-Arch name.
+  StringRef getSubArch() const { return StringRef(SubArchCStr, SubArchLength); }
+};
+
+static const ArchNames<ArchKind> ARCHNames[] = {
+#define ARM_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU,            \
+                 ARCH_BASE_EXT)                                                \
+  {NAME,         sizeof(NAME) - 1,                                             \
+   CPU_ATTR,     sizeof(CPU_ATTR) - 1,                                         \
+   SUB_ARCH,     sizeof(SUB_ARCH) - 1,                                         \
+   ARCH_FPU,     ARCH_BASE_EXT,                                                \
+   ArchKind::ID, ARCH_ATTR},
+#include "llvm/Support/ARMTargetParser.def"
+};
+
+// Information by ID
+StringRef getFPUName(unsigned FPUKind);
+FPUVersion getFPUVersion(unsigned FPUKind);
+NeonSupportLevel getFPUNeonSupportLevel(unsigned FPUKind);
+FPURestriction getFPURestriction(unsigned FPUKind);
+
+// FIXME: These should be moved to TargetTuple once it exists
+bool getFPUFeatures(unsigned FPUKind, std::vector<StringRef> &Features);
+bool getHWDivFeatures(unsigned HWDivKind, std::vector<StringRef> &Features);
+bool getExtensionFeatures(unsigned Extensions,
+                          std::vector<StringRef> &Features);
+
+StringRef getArchName(ArchKind AK);
+unsigned getArchAttr(ArchKind AK);
+StringRef getCPUAttr(ArchKind AK);
+StringRef getSubArch(ArchKind AK);
+StringRef getArchExtName(unsigned ArchExtKind);
+StringRef getArchExtFeature(StringRef ArchExt);
+bool appendArchExtFeatures(StringRef CPU, ARM::ArchKind AK, StringRef ArchExt,
+                           std::vector<StringRef> &Features);
+StringRef getHWDivName(unsigned HWDivKind);
+
+// Information by Name
+unsigned getDefaultFPU(StringRef CPU, ArchKind AK);
+unsigned getDefaultExtensions(StringRef CPU, ArchKind AK);
+StringRef getDefaultCPU(StringRef Arch);
+StringRef getCanonicalArchName(StringRef Arch);
+StringRef getFPUSynonym(StringRef FPU);
+StringRef getArchSynonym(StringRef Arch);
+
+// Parser
+unsigned parseHWDiv(StringRef HWDiv);
+unsigned parseFPU(StringRef FPU);
+ArchKind parseArch(StringRef Arch);
+unsigned parseArchExt(StringRef ArchExt);
+ArchKind parseCPUArch(StringRef CPU);
+ISAKind parseArchISA(StringRef Arch);
+EndianKind parseArchEndian(StringRef Arch);
+ProfileKind parseArchProfile(StringRef Arch);
+unsigned parseArchVersion(StringRef Arch);
+
+void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values);
+StringRef computeDefaultTargetABI(const Triple &TT, StringRef CPU);
+
+} // namespace ARM
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/AlignOf.h b/binaryen/third_party/llvm-project/include/llvm/Support/AlignOf.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/AlignOf.h
@@ -0,0 +1,55 @@
+//===--- AlignOf.h - Portable calculation of type alignment -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the AlignedCharArrayUnion class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ALIGNOF_H
+#define LLVM_SUPPORT_ALIGNOF_H
+
+#include "llvm/Support/Compiler.h"
+#include <cstddef>
+
+namespace llvm {
+
+namespace detail {
+
+template <typename T, typename... Ts> class AlignerImpl {
+  T t;
+  AlignerImpl<Ts...> rest;
+  AlignerImpl() = delete;
+};
+
+template <typename T> class AlignerImpl<T> {
+  T t;
+  AlignerImpl() = delete;
+};
+
+template <typename T, typename... Ts> union SizerImpl {
+  char arr[sizeof(T)];
+  SizerImpl<Ts...> rest;
+};
+
+template <typename T> union SizerImpl<T> { char arr[sizeof(T)]; };
+} // end namespace detail
+
+/// A suitably aligned and sized character array member which can hold elements
+/// of any type.
+///
+/// These types may be arrays, structs, or any other types. This exposes a
+/// `buffer` member which can be used as suitable storage for a placement new of
+/// any of these types.
+template <typename T, typename... Ts> struct AlignedCharArrayUnion {
+  alignas(::llvm::detail::AlignerImpl<T, Ts...>) char buffer[sizeof(
+      llvm::detail::SizerImpl<T, Ts...>)];
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_ALIGNOF_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Alignment.h b/binaryen/third_party/llvm-project/include/llvm/Support/Alignment.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Alignment.h
@@ -0,0 +1,403 @@
+//===-- llvm/Support/Alignment.h - Useful alignment functions ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains types to represent alignments.
+// They are instrumented to guarantee some invariants are preserved and prevent
+// invalid manipulations.
+//
+// - Align represents an alignment in bytes, it is always set and always a valid
+// power of two, its minimum value is 1 which means no alignment requirements.
+//
+// - MaybeAlign is an optional type, it may be undefined or set. When it's set
+// you can get the underlying Align type by using the getValue() method.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ALIGNMENT_H_
+#define LLVM_SUPPORT_ALIGNMENT_H_
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MathExtras.h"
+#include <cassert>
+#include <limits>
+
+namespace llvm {
+
+#define ALIGN_CHECK_ISPOSITIVE(decl)                                           \
+  assert(decl > 0 && (#decl " should be defined"))
+#define ALIGN_CHECK_ISSET(decl)                                                \
+  assert(decl.hasValue() && (#decl " should be defined"))
+
+/// This struct is a compact representation of a valid (non-zero power of two)
+/// alignment.
+/// It is suitable for use as static global constants.
+struct Align {
+private:
+  uint8_t ShiftValue = 0; /// The log2 of the required alignment.
+                          /// ShiftValue is less than 64 by construction.
+
+  friend struct MaybeAlign;
+  friend unsigned Log2(Align);
+  friend bool operator==(Align Lhs, Align Rhs);
+  friend bool operator!=(Align Lhs, Align Rhs);
+  friend bool operator<=(Align Lhs, Align Rhs);
+  friend bool operator>=(Align Lhs, Align Rhs);
+  friend bool operator<(Align Lhs, Align Rhs);
+  friend bool operator>(Align Lhs, Align Rhs);
+  friend unsigned encode(struct MaybeAlign A);
+  friend struct MaybeAlign decodeMaybeAlign(unsigned Value);
+
+  /// A trivial type to allow construction of constexpr Align.
+  /// This is currently needed to workaround a bug in GCC 5.3 which prevents
+  /// definition of constexpr assign operators.
+  /// https://stackoverflow.com/questions/46756288/explicitly-defaulted-function-cannot-be-declared-as-constexpr-because-the-implic
+  /// FIXME: Remove this, make all assign operators constexpr and introduce user
+  /// defined literals when we don't have to support GCC 5.3 anymore.
+  /// https://llvm.org/docs/GettingStarted.html#getting-a-modern-host-c-toolchain
+  struct LogValue {
+    uint8_t Log;
+  };
+
+public:
+  /// Default is byte-aligned.
+  constexpr Align() = default;
+  /// Do not perform checks in case of copy/move construct/assign, because the
+  /// checks have been performed when building `Other`.
+  constexpr Align(const Align &Other) = default;
+  constexpr Align(Align &&Other) = default;
+  Align &operator=(const Align &Other) = default;
+  Align &operator=(Align &&Other) = default;
+
+  explicit Align(uint64_t Value) {
+    assert(Value > 0 && "Value must not be 0");
+    assert(llvm::isPowerOf2_64(Value) && "Alignment is not a power of 2");
+    ShiftValue = Log2_64(Value);
+    assert(ShiftValue < 64 && "Broken invariant");
+  }
+
+  /// This is a hole in the type system and should not be abused.
+  /// Needed to interact with C for instance.
+  uint64_t value() const { return uint64_t(1) << ShiftValue; }
+
+  /// Returns a default constructed Align which corresponds to no alignment.
+  /// This is useful to test for unalignment as it conveys clear semantic.
+  /// `if (A != Align::None())`
+  /// would be better than
+  /// `if (A > Align(1))`
+  constexpr static const Align None() { return Align(); }
+
+  /// Allow constructions of constexpr Align.
+  template <size_t kValue> constexpr static LogValue Constant() {
+    return LogValue{static_cast<uint8_t>(CTLog2<kValue>())};
+  }
+
+  /// Allow constructions of constexpr Align from types.
+  /// Compile time equivalent to Align(alignof(T)).
+  template <typename T> constexpr static LogValue Of() {
+    return Constant<std::alignment_of<T>::value>();
+  }
+
+  /// Constexpr constructor from LogValue type.
+  constexpr Align(LogValue CA) : ShiftValue(CA.Log) {}
+};
+
+/// Treats the value 0 as a 1, so Align is always at least 1.
+inline Align assumeAligned(uint64_t Value) {
+  return Value ? Align(Value) : Align();
+}
+
+/// This struct is a compact representation of a valid (power of two) or
+/// undefined (0) alignment.
+struct MaybeAlign : public llvm::Optional<Align> {
+private:
+  using UP = llvm::Optional<Align>;
+
+public:
+  /// Default is undefined.
+  MaybeAlign() = default;
+  /// Do not perform checks in case of copy/move construct/assign, because the
+  /// checks have been performed when building `Other`.
+  MaybeAlign(const MaybeAlign &Other) = default;
+  MaybeAlign &operator=(const MaybeAlign &Other) = default;
+  MaybeAlign(MaybeAlign &&Other) = default;
+  MaybeAlign &operator=(MaybeAlign &&Other) = default;
+
+  /// Use llvm::Optional<Align> constructor.
+  using UP::UP;
+
+  explicit MaybeAlign(uint64_t Value) {
+    assert((Value == 0 || llvm::isPowerOf2_64(Value)) &&
+           "Alignment is neither 0 nor a power of 2");
+    if (Value)
+      emplace(Value);
+  }
+
+  /// For convenience, returns a valid alignment or 1 if undefined.
+  Align valueOrOne() const { return hasValue() ? getValue() : Align(); }
+};
+
+/// Checks that SizeInBytes is a multiple of the alignment.
+inline bool isAligned(Align Lhs, uint64_t SizeInBytes) {
+  return SizeInBytes % Lhs.value() == 0;
+}
+
+/// Checks that SizeInBytes is a multiple of the alignment.
+/// Returns false if the alignment is undefined.
+inline bool isAligned(MaybeAlign Lhs, uint64_t SizeInBytes) {
+  ALIGN_CHECK_ISSET(Lhs);
+  return SizeInBytes % (*Lhs).value() == 0;
+}
+
+/// Checks that Addr is a multiple of the alignment.
+inline bool isAddrAligned(Align Lhs, const void *Addr) {
+  return isAligned(Lhs, reinterpret_cast<uintptr_t>(Addr));
+}
+
+/// Returns a multiple of A needed to store `Size` bytes.
+inline uint64_t alignTo(uint64_t Size, Align A) {
+  const uint64_t value = A.value();
+  // The following line is equivalent to `(Size + value - 1) / value * value`.
+
+  // The division followed by a multiplication can be thought of as a right
+  // shift followed by a left shift which zeros out the extra bits produced in
+  // the bump; `~(value - 1)` is a mask where all those bits being zeroed out
+  // are just zero.
+
+  // Most compilers can generate this code but the pattern may be missed when
+  // multiple functions gets inlined.
+  return (Size + value - 1) & ~(value - 1);
+}
+
+/// Returns a multiple of A needed to store `Size` bytes.
+/// Returns `Size` if current alignment is undefined.
+inline uint64_t alignTo(uint64_t Size, MaybeAlign A) {
+  return A ? alignTo(Size, A.getValue()) : Size;
+}
+
+/// Aligns `Addr` to `Alignment` bytes, rounding up.
+inline uintptr_t alignAddr(const void *Addr, Align Alignment) {
+  uintptr_t ArithAddr = reinterpret_cast<uintptr_t>(Addr);
+  assert(static_cast<uintptr_t>(ArithAddr + Alignment.value() - 1) >=
+             ArithAddr && "Overflow");
+  return alignTo(ArithAddr, Alignment);
+}
+
+/// Returns the offset to the next integer (mod 2**64) that is greater than
+/// or equal to \p Value and is a multiple of \p Align.
+inline uint64_t offsetToAlignment(uint64_t Value, Align Alignment) {
+  return alignTo(Value, Alignment) - Value;
+}
+
+/// Returns the necessary adjustment for aligning `Addr` to `Alignment`
+/// bytes, rounding up.
+inline uint64_t offsetToAlignedAddr(const void *Addr, Align Alignment) {
+  return offsetToAlignment(reinterpret_cast<uintptr_t>(Addr), Alignment);
+}
+
+/// Returns the log2 of the alignment.
+inline unsigned Log2(Align A) { return A.ShiftValue; }
+
+/// Returns the log2 of the alignment.
+/// \pre A must be defined.
+inline unsigned Log2(MaybeAlign A) {
+  ALIGN_CHECK_ISSET(A);
+  return Log2(A.getValue());
+}
+
+/// Returns the alignment that satisfies both alignments.
+/// Same semantic as MinAlign.
+inline Align commonAlignment(Align A, Align B) { return std::min(A, B); }
+
+/// Returns the alignment that satisfies both alignments.
+/// Same semantic as MinAlign.
+inline Align commonAlignment(Align A, uint64_t Offset) {
+  return Align(MinAlign(A.value(), Offset));
+}
+
+/// Returns the alignment that satisfies both alignments.
+/// Same semantic as MinAlign.
+inline MaybeAlign commonAlignment(MaybeAlign A, MaybeAlign B) {
+  return A && B ? commonAlignment(*A, *B) : A ? A : B;
+}
+
+/// Returns the alignment that satisfies both alignments.
+/// Same semantic as MinAlign.
+inline MaybeAlign commonAlignment(MaybeAlign A, uint64_t Offset) {
+  return MaybeAlign(MinAlign((*A).value(), Offset));
+}
+
+/// Returns a representation of the alignment that encodes undefined as 0.
+inline unsigned encode(MaybeAlign A) { return A ? A->ShiftValue + 1 : 0; }
+
+/// Dual operation of the encode function above.
+inline MaybeAlign decodeMaybeAlign(unsigned Value) {
+  if (Value == 0)
+    return MaybeAlign();
+  Align Out;
+  Out.ShiftValue = Value - 1;
+  return Out;
+}
+
+/// Returns a representation of the alignment, the encoded value is positive by
+/// definition.
+inline unsigned encode(Align A) { return encode(MaybeAlign(A)); }
+
+/// Comparisons between Align and scalars. Rhs must be positive.
+inline bool operator==(Align Lhs, uint64_t Rhs) {
+  ALIGN_CHECK_ISPOSITIVE(Rhs);
+  return Lhs.value() == Rhs;
+}
+inline bool operator!=(Align Lhs, uint64_t Rhs) {
+  ALIGN_CHECK_ISPOSITIVE(Rhs);
+  return Lhs.value() != Rhs;
+}
+inline bool operator<=(Align Lhs, uint64_t Rhs) {
+  ALIGN_CHECK_ISPOSITIVE(Rhs);
+  return Lhs.value() <= Rhs;
+}
+inline bool operator>=(Align Lhs, uint64_t Rhs) {
+  ALIGN_CHECK_ISPOSITIVE(Rhs);
+  return Lhs.value() >= Rhs;
+}
+inline bool operator<(Align Lhs, uint64_t Rhs) {
+  ALIGN_CHECK_ISPOSITIVE(Rhs);
+  return Lhs.value() < Rhs;
+}
+inline bool operator>(Align Lhs, uint64_t Rhs) {
+  ALIGN_CHECK_ISPOSITIVE(Rhs);
+  return Lhs.value() > Rhs;
+}
+
+/// Comparisons between MaybeAlign and scalars.
+inline bool operator==(MaybeAlign Lhs, uint64_t Rhs) {
+  return Lhs ? (*Lhs).value() == Rhs : Rhs == 0;
+}
+inline bool operator!=(MaybeAlign Lhs, uint64_t Rhs) {
+  return Lhs ? (*Lhs).value() != Rhs : Rhs != 0;
+}
+inline bool operator<=(MaybeAlign Lhs, uint64_t Rhs) {
+  ALIGN_CHECK_ISSET(Lhs);
+  ALIGN_CHECK_ISPOSITIVE(Rhs);
+  return (*Lhs).value() <= Rhs;
+}
+inline bool operator>=(MaybeAlign Lhs, uint64_t Rhs) {
+  ALIGN_CHECK_ISSET(Lhs);
+  ALIGN_CHECK_ISPOSITIVE(Rhs);
+  return (*Lhs).value() >= Rhs;
+}
+inline bool operator<(MaybeAlign Lhs, uint64_t Rhs) {
+  ALIGN_CHECK_ISSET(Lhs);
+  ALIGN_CHECK_ISPOSITIVE(Rhs);
+  return (*Lhs).value() < Rhs;
+}
+inline bool operator>(MaybeAlign Lhs, uint64_t Rhs) {
+  ALIGN_CHECK_ISSET(Lhs);
+  ALIGN_CHECK_ISPOSITIVE(Rhs);
+  return (*Lhs).value() > Rhs;
+}
+
+/// Comparisons operators between Align.
+inline bool operator==(Align Lhs, Align Rhs) {
+  return Lhs.ShiftValue == Rhs.ShiftValue;
+}
+inline bool operator!=(Align Lhs, Align Rhs) {
+  return Lhs.ShiftValue != Rhs.ShiftValue;
+}
+inline bool operator<=(Align Lhs, Align Rhs) {
+  return Lhs.ShiftValue <= Rhs.ShiftValue;
+}
+inline bool operator>=(Align Lhs, Align Rhs) {
+  return Lhs.ShiftValue >= Rhs.ShiftValue;
+}
+inline bool operator<(Align Lhs, Align Rhs) {
+  return Lhs.ShiftValue < Rhs.ShiftValue;
+}
+inline bool operator>(Align Lhs, Align Rhs) {
+  return Lhs.ShiftValue > Rhs.ShiftValue;
+}
+
+/// Comparisons operators between Align and MaybeAlign.
+inline bool operator==(Align Lhs, MaybeAlign Rhs) {
+  ALIGN_CHECK_ISSET(Rhs);
+  return Lhs.value() == (*Rhs).value();
+}
+inline bool operator!=(Align Lhs, MaybeAlign Rhs) {
+  ALIGN_CHECK_ISSET(Rhs);
+  return Lhs.value() != (*Rhs).value();
+}
+inline bool operator<=(Align Lhs, MaybeAlign Rhs) {
+  ALIGN_CHECK_ISSET(Rhs);
+  return Lhs.value() <= (*Rhs).value();
+}
+inline bool operator>=(Align Lhs, MaybeAlign Rhs) {
+  ALIGN_CHECK_ISSET(Rhs);
+  return Lhs.value() >= (*Rhs).value();
+}
+inline bool operator<(Align Lhs, MaybeAlign Rhs) {
+  ALIGN_CHECK_ISSET(Rhs);
+  return Lhs.value() < (*Rhs).value();
+}
+inline bool operator>(Align Lhs, MaybeAlign Rhs) {
+  ALIGN_CHECK_ISSET(Rhs);
+  return Lhs.value() > (*Rhs).value();
+}
+
+/// Comparisons operators between MaybeAlign and Align.
+inline bool operator==(MaybeAlign Lhs, Align Rhs) {
+  ALIGN_CHECK_ISSET(Lhs);
+  return Lhs && (*Lhs).value() == Rhs.value();
+}
+inline bool operator!=(MaybeAlign Lhs, Align Rhs) {
+  ALIGN_CHECK_ISSET(Lhs);
+  return Lhs && (*Lhs).value() != Rhs.value();
+}
+inline bool operator<=(MaybeAlign Lhs, Align Rhs) {
+  ALIGN_CHECK_ISSET(Lhs);
+  return Lhs && (*Lhs).value() <= Rhs.value();
+}
+inline bool operator>=(MaybeAlign Lhs, Align Rhs) {
+  ALIGN_CHECK_ISSET(Lhs);
+  return Lhs && (*Lhs).value() >= Rhs.value();
+}
+inline bool operator<(MaybeAlign Lhs, Align Rhs) {
+  ALIGN_CHECK_ISSET(Lhs);
+  return Lhs && (*Lhs).value() < Rhs.value();
+}
+inline bool operator>(MaybeAlign Lhs, Align Rhs) {
+  ALIGN_CHECK_ISSET(Lhs);
+  return Lhs && (*Lhs).value() > Rhs.value();
+}
+
+inline Align operator/(Align Lhs, uint64_t Divisor) {
+  assert(llvm::isPowerOf2_64(Divisor) &&
+         "Divisor must be positive and a power of 2");
+  assert(Lhs != 1 && "Can't halve byte alignment");
+  return Align(Lhs.value() / Divisor);
+}
+
+inline MaybeAlign operator/(MaybeAlign Lhs, uint64_t Divisor) {
+  assert(llvm::isPowerOf2_64(Divisor) &&
+         "Divisor must be positive and a power of 2");
+  return Lhs ? Lhs.getValue() / Divisor : MaybeAlign();
+}
+
+inline Align max(MaybeAlign Lhs, Align Rhs) {
+  return Lhs && *Lhs > Rhs ? *Lhs : Rhs;
+}
+
+inline Align max(Align Lhs, MaybeAlign Rhs) {
+  return Rhs && *Rhs > Lhs ? *Rhs : Lhs;
+}
+
+#undef ALIGN_CHECK_ISPOSITIVE
+#undef ALIGN_CHECK_ISSET
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_ALIGNMENT_H_
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Allocator.h b/binaryen/third_party/llvm-project/include/llvm/Support/Allocator.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Allocator.h
@@ -0,0 +1,523 @@
+//===- Allocator.h - Simple memory allocation abstraction -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file defines the MallocAllocator and BumpPtrAllocator interfaces. Both
+/// of these conform to an LLVM "Allocator" concept which consists of an
+/// Allocate method accepting a size and alignment, and a Deallocate accepting
+/// a pointer and size. Further, the LLVM "Allocator" concept has overloads of
+/// Allocate and Deallocate for setting size and alignment based on the final
+/// type. These overloads are typically provided by a base class template \c
+/// AllocatorBase.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ALLOCATOR_H
+#define LLVM_SUPPORT_ALLOCATOR_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemAlloc.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+
+namespace llvm {
+
+/// CRTP base class providing obvious overloads for the core \c
+/// Allocate() methods of LLVM-style allocators.
+///
+/// This base class both documents the full public interface exposed by all
+/// LLVM-style allocators, and redirects all of the overloads to a single core
+/// set of methods which the derived class must define.
+template <typename DerivedT> class AllocatorBase {
+public:
+  /// Allocate \a Size bytes of \a Alignment aligned memory. This method
+  /// must be implemented by \c DerivedT.
+  void *Allocate(size_t Size, size_t Alignment) {
+#ifdef __clang__
+    static_assert(static_cast<void *(AllocatorBase::*)(size_t, size_t)>(
+                      &AllocatorBase::Allocate) !=
+                      static_cast<void *(DerivedT::*)(size_t, size_t)>(
+                          &DerivedT::Allocate),
+                  "Class derives from AllocatorBase without implementing the "
+                  "core Allocate(size_t, size_t) overload!");
+#endif
+    return static_cast<DerivedT *>(this)->Allocate(Size, Alignment);
+  }
+
+  /// Deallocate \a Ptr to \a Size bytes of memory allocated by this
+  /// allocator.
+  void Deallocate(const void *Ptr, size_t Size) {
+#ifdef __clang__
+    static_assert(static_cast<void (AllocatorBase::*)(const void *, size_t)>(
+                      &AllocatorBase::Deallocate) !=
+                      static_cast<void (DerivedT::*)(const void *, size_t)>(
+                          &DerivedT::Deallocate),
+                  "Class derives from AllocatorBase without implementing the "
+                  "core Deallocate(void *) overload!");
+#endif
+    return static_cast<DerivedT *>(this)->Deallocate(Ptr, Size);
+  }
+
+  // The rest of these methods are helpers that redirect to one of the above
+  // core methods.
+
+  /// Allocate space for a sequence of objects without constructing them.
+  template <typename T> T *Allocate(size_t Num = 1) {
+    return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T)));
+  }
+
+  /// Deallocate space for a sequence of objects without constructing them.
+  template <typename T>
+  typename std::enable_if<
+      !std::is_same<typename std::remove_cv<T>::type, void>::value, void>::type
+  Deallocate(T *Ptr, size_t Num = 1) {
+    Deallocate(static_cast<const void *>(Ptr), Num * sizeof(T));
+  }
+};
+
+class MallocAllocator : public AllocatorBase<MallocAllocator> {
+public:
+  void Reset() {}
+
+  LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size,
+                                                size_t /*Alignment*/) {
+    return safe_malloc(Size);
+  }
+
+  // Pull in base class overloads.
+  using AllocatorBase<MallocAllocator>::Allocate;
+
+  void Deallocate(const void *Ptr, size_t /*Size*/) {
+    free(const_cast<void *>(Ptr));
+  }
+
+  // Pull in base class overloads.
+  using AllocatorBase<MallocAllocator>::Deallocate;
+
+  void PrintStats() const {}
+};
+
+namespace detail {
+
+// We call out to an external function to actually print the message as the
+// printing code uses Allocator.h in its implementation.
+void printBumpPtrAllocatorStats(unsigned NumSlabs, size_t BytesAllocated,
+                                size_t TotalMemory);
+
+} // end namespace detail
+
+/// Allocate memory in an ever growing pool, as if by bump-pointer.
+///
+/// This isn't strictly a bump-pointer allocator as it uses backing slabs of
+/// memory rather than relying on a boundless contiguous heap. However, it has
+/// bump-pointer semantics in that it is a monotonically growing pool of memory
+/// where every allocation is found by merely allocating the next N bytes in
+/// the slab, or the next N bytes in the next slab.
+///
+/// Note that this also has a threshold for forcing allocations above a certain
+/// size into their own slab.
+///
+/// The BumpPtrAllocatorImpl template defaults to using a MallocAllocator
+/// object, which wraps malloc, to allocate memory, but it can be changed to
+/// use a custom allocator.
+template <typename AllocatorT = MallocAllocator, size_t SlabSize = 4096,
+          size_t SizeThreshold = SlabSize>
+class BumpPtrAllocatorImpl
+    : public AllocatorBase<
+          BumpPtrAllocatorImpl<AllocatorT, SlabSize, SizeThreshold>> {
+public:
+  static_assert(SizeThreshold <= SlabSize,
+                "The SizeThreshold must be at most the SlabSize to ensure "
+                "that objects larger than a slab go into their own memory "
+                "allocation.");
+
+  BumpPtrAllocatorImpl() = default;
+
+  template <typename T>
+  BumpPtrAllocatorImpl(T &&Allocator)
+      : Allocator(std::forward<T &&>(Allocator)) {}
+
+  // Manually implement a move constructor as we must clear the old allocator's
+  // slabs as a matter of correctness.
+  BumpPtrAllocatorImpl(BumpPtrAllocatorImpl &&Old)
+      : CurPtr(Old.CurPtr), End(Old.End), Slabs(std::move(Old.Slabs)),
+        CustomSizedSlabs(std::move(Old.CustomSizedSlabs)),
+        BytesAllocated(Old.BytesAllocated), RedZoneSize(Old.RedZoneSize),
+        Allocator(std::move(Old.Allocator)) {
+    Old.CurPtr = Old.End = nullptr;
+    Old.BytesAllocated = 0;
+    Old.Slabs.clear();
+    Old.CustomSizedSlabs.clear();
+  }
+
+  ~BumpPtrAllocatorImpl() {
+    DeallocateSlabs(Slabs.begin(), Slabs.end());
+    DeallocateCustomSizedSlabs();
+  }
+
+  BumpPtrAllocatorImpl &operator=(BumpPtrAllocatorImpl &&RHS) {
+    DeallocateSlabs(Slabs.begin(), Slabs.end());
+    DeallocateCustomSizedSlabs();
+
+    CurPtr = RHS.CurPtr;
+    End = RHS.End;
+    BytesAllocated = RHS.BytesAllocated;
+    RedZoneSize = RHS.RedZoneSize;
+    Slabs = std::move(RHS.Slabs);
+    CustomSizedSlabs = std::move(RHS.CustomSizedSlabs);
+    Allocator = std::move(RHS.Allocator);
+
+    RHS.CurPtr = RHS.End = nullptr;
+    RHS.BytesAllocated = 0;
+    RHS.Slabs.clear();
+    RHS.CustomSizedSlabs.clear();
+    return *this;
+  }
+
+  /// Deallocate all but the current slab and reset the current pointer
+  /// to the beginning of it, freeing all memory allocated so far.
+  void Reset() {
+    // Deallocate all but the first slab, and deallocate all custom-sized slabs.
+    DeallocateCustomSizedSlabs();
+    CustomSizedSlabs.clear();
+
+    if (Slabs.empty())
+      return;
+
+    // Reset the state.
+    BytesAllocated = 0;
+    CurPtr = (char *)Slabs.front();
+    End = CurPtr + SlabSize;
+
+    __asan_poison_memory_region(*Slabs.begin(), computeSlabSize(0));
+    DeallocateSlabs(std::next(Slabs.begin()), Slabs.end());
+    Slabs.erase(std::next(Slabs.begin()), Slabs.end());
+  }
+
+  /// Allocate space at the specified alignment.
+  LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void *
+  Allocate(size_t Size, Align Alignment) {
+    // Keep track of how many bytes we've allocated.
+    BytesAllocated += Size;
+
+    size_t Adjustment = offsetToAlignedAddr(CurPtr, Alignment);
+    assert(Adjustment + Size >= Size && "Adjustment + Size must not overflow");
+
+    size_t SizeToAllocate = Size;
+#if LLVM_ADDRESS_SANITIZER_BUILD
+    // Add trailing bytes as a "red zone" under ASan.
+    SizeToAllocate += RedZoneSize;
+#endif
+
+    // Check if we have enough space.
+    if (Adjustment + SizeToAllocate <= size_t(End - CurPtr)) {
+      char *AlignedPtr = CurPtr + Adjustment;
+      CurPtr = AlignedPtr + SizeToAllocate;
+      // Update the allocation point of this memory block in MemorySanitizer.
+      // Without this, MemorySanitizer messages for values originated from here
+      // will point to the allocation of the entire slab.
+      __msan_allocated_memory(AlignedPtr, Size);
+      // Similarly, tell ASan about this space.
+      __asan_unpoison_memory_region(AlignedPtr, Size);
+      return AlignedPtr;
+    }
+
+    // If Size is really big, allocate a separate slab for it.
+    size_t PaddedSize = SizeToAllocate + Alignment.value() - 1;
+    if (PaddedSize > SizeThreshold) {
+      void *NewSlab = Allocator.Allocate(PaddedSize, 0);
+      // We own the new slab and don't want anyone reading anyting other than
+      // pieces returned from this method.  So poison the whole slab.
+      __asan_poison_memory_region(NewSlab, PaddedSize);
+      CustomSizedSlabs.push_back(std::make_pair(NewSlab, PaddedSize));
+
+      uintptr_t AlignedAddr = alignAddr(NewSlab, Alignment);
+      assert(AlignedAddr + Size <= (uintptr_t)NewSlab + PaddedSize);
+      char *AlignedPtr = (char*)AlignedAddr;
+      __msan_allocated_memory(AlignedPtr, Size);
+      __asan_unpoison_memory_region(AlignedPtr, Size);
+      return AlignedPtr;
+    }
+
+    // Otherwise, start a new slab and try again.
+    StartNewSlab();
+    uintptr_t AlignedAddr = alignAddr(CurPtr, Alignment);
+    assert(AlignedAddr + SizeToAllocate <= (uintptr_t)End &&
+           "Unable to allocate memory!");
+    char *AlignedPtr = (char*)AlignedAddr;
+    CurPtr = AlignedPtr + SizeToAllocate;
+    __msan_allocated_memory(AlignedPtr, Size);
+    __asan_unpoison_memory_region(AlignedPtr, Size);
+    return AlignedPtr;
+  }
+
+  inline LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void *
+  Allocate(size_t Size, size_t Alignment) {
+    assert(Alignment > 0 && "0-byte alignnment is not allowed. Use 1 instead.");
+    return Allocate(Size, Align(Alignment));
+  }
+
+  // Pull in base class overloads.
+  using AllocatorBase<BumpPtrAllocatorImpl>::Allocate;
+
+  // Bump pointer allocators are expected to never free their storage; and
+  // clients expect pointers to remain valid for non-dereferencing uses even
+  // after deallocation.
+  void Deallocate(const void *Ptr, size_t Size) {
+    __asan_poison_memory_region(Ptr, Size);
+  }
+
+  // Pull in base class overloads.
+  using AllocatorBase<BumpPtrAllocatorImpl>::Deallocate;
+
+  size_t GetNumSlabs() const { return Slabs.size() + CustomSizedSlabs.size(); }
+
+  /// \return An index uniquely and reproducibly identifying
+  /// an input pointer \p Ptr in the given allocator.
+  /// The returned value is negative iff the object is inside a custom-size
+  /// slab.
+  /// Returns an empty optional if the pointer is not found in the allocator.
+  llvm::Optional<int64_t> identifyObject(const void *Ptr) {
+    const char *P = static_cast<const char *>(Ptr);
+    int64_t InSlabIdx = 0;
+    for (size_t Idx = 0, E = Slabs.size(); Idx < E; Idx++) {
+      const char *S = static_cast<const char *>(Slabs[Idx]);
+      if (P >= S && P < S + computeSlabSize(Idx))
+        return InSlabIdx + static_cast<int64_t>(P - S);
+      InSlabIdx += static_cast<int64_t>(computeSlabSize(Idx));
+    }
+
+    // Use negative index to denote custom sized slabs.
+    int64_t InCustomSizedSlabIdx = -1;
+    for (size_t Idx = 0, E = CustomSizedSlabs.size(); Idx < E; Idx++) {
+      const char *S = static_cast<const char *>(CustomSizedSlabs[Idx].first);
+      size_t Size = CustomSizedSlabs[Idx].second;
+      if (P >= S && P < S + Size)
+        return InCustomSizedSlabIdx - static_cast<int64_t>(P - S);
+      InCustomSizedSlabIdx -= static_cast<int64_t>(Size);
+    }
+    return None;
+  }
+
+  /// A wrapper around identifyObject that additionally asserts that
+  /// the object is indeed within the allocator.
+  /// \return An index uniquely and reproducibly identifying
+  /// an input pointer \p Ptr in the given allocator.
+  int64_t identifyKnownObject(const void *Ptr) {
+    Optional<int64_t> Out = identifyObject(Ptr);
+    assert(Out && "Wrong allocator used");
+    return *Out;
+  }
+
+  /// A wrapper around identifyKnownObject. Accepts type information
+  /// about the object and produces a smaller identifier by relying on
+  /// the alignment information. Note that sub-classes may have different
+  /// alignment, so the most base class should be passed as template parameter
+  /// in order to obtain correct results. For that reason automatic template
+  /// parameter deduction is disabled.
+  /// \return An index uniquely and reproducibly identifying
+  /// an input pointer \p Ptr in the given allocator. This identifier is
+  /// different from the ones produced by identifyObject and
+  /// identifyAlignedObject.
+  template <typename T>
+  int64_t identifyKnownAlignedObject(const void *Ptr) {
+    int64_t Out = identifyKnownObject(Ptr);
+    assert(Out % alignof(T) == 0 && "Wrong alignment information");
+    return Out / alignof(T);
+  }
+
+  size_t getTotalMemory() const {
+    size_t TotalMemory = 0;
+    for (auto I = Slabs.begin(), E = Slabs.end(); I != E; ++I)
+      TotalMemory += computeSlabSize(std::distance(Slabs.begin(), I));
+    for (auto &PtrAndSize : CustomSizedSlabs)
+      TotalMemory += PtrAndSize.second;
+    return TotalMemory;
+  }
+
+  size_t getBytesAllocated() const { return BytesAllocated; }
+
+  void setRedZoneSize(size_t NewSize) {
+    RedZoneSize = NewSize;
+  }
+
+  void PrintStats() const {
+    detail::printBumpPtrAllocatorStats(Slabs.size(), BytesAllocated,
+                                       getTotalMemory());
+  }
+
+private:
+  /// The current pointer into the current slab.
+  ///
+  /// This points to the next free byte in the slab.
+  char *CurPtr = nullptr;
+
+  /// The end of the current slab.
+  char *End = nullptr;
+
+  /// The slabs allocated so far.
+  SmallVector<void *, 4> Slabs;
+
+  /// Custom-sized slabs allocated for too-large allocation requests.
+  SmallVector<std::pair<void *, size_t>, 0> CustomSizedSlabs;
+
+  /// How many bytes we've allocated.
+  ///
+  /// Used so that we can compute how much space was wasted.
+  size_t BytesAllocated = 0;
+
+  /// The number of bytes to put between allocations when running under
+  /// a sanitizer.
+  size_t RedZoneSize = 1;
+
+  /// The allocator instance we use to get slabs of memory.
+  AllocatorT Allocator;
+
+  static size_t computeSlabSize(unsigned SlabIdx) {
+    // Scale the actual allocated slab size based on the number of slabs
+    // allocated. Every 128 slabs allocated, we double the allocated size to
+    // reduce allocation frequency, but saturate at multiplying the slab size by
+    // 2^30.
+    return SlabSize * ((size_t)1 << std::min<size_t>(30, SlabIdx / 128));
+  }
+
+  /// Allocate a new slab and move the bump pointers over into the new
+  /// slab, modifying CurPtr and End.
+  void StartNewSlab() {
+    size_t AllocatedSlabSize = computeSlabSize(Slabs.size());
+
+    void *NewSlab = Allocator.Allocate(AllocatedSlabSize, 0);
+    // We own the new slab and don't want anyone reading anything other than
+    // pieces returned from this method.  So poison the whole slab.
+    __asan_poison_memory_region(NewSlab, AllocatedSlabSize);
+
+    Slabs.push_back(NewSlab);
+    CurPtr = (char *)(NewSlab);
+    End = ((char *)NewSlab) + AllocatedSlabSize;
+  }
+
+  /// Deallocate a sequence of slabs.
+  void DeallocateSlabs(SmallVectorImpl<void *>::iterator I,
+                       SmallVectorImpl<void *>::iterator E) {
+    for (; I != E; ++I) {
+      size_t AllocatedSlabSize =
+          computeSlabSize(std::distance(Slabs.begin(), I));
+      Allocator.Deallocate(*I, AllocatedSlabSize);
+    }
+  }
+
+  /// Deallocate all memory for custom sized slabs.
+  void DeallocateCustomSizedSlabs() {
+    for (auto &PtrAndSize : CustomSizedSlabs) {
+      void *Ptr = PtrAndSize.first;
+      size_t Size = PtrAndSize.second;
+      Allocator.Deallocate(Ptr, Size);
+    }
+  }
+
+  template <typename T> friend class SpecificBumpPtrAllocator;
+};
+
+/// The standard BumpPtrAllocator which just uses the default template
+/// parameters.
+typedef BumpPtrAllocatorImpl<> BumpPtrAllocator;
+
+/// A BumpPtrAllocator that allows only elements of a specific type to be
+/// allocated.
+///
+/// This allows calling the destructor in DestroyAll() and when the allocator is
+/// destroyed.
+template <typename T> class SpecificBumpPtrAllocator {
+  BumpPtrAllocator Allocator;
+
+public:
+  SpecificBumpPtrAllocator() {
+    // Because SpecificBumpPtrAllocator walks the memory to call destructors,
+    // it can't have red zones between allocations.
+    Allocator.setRedZoneSize(0);
+  }
+  SpecificBumpPtrAllocator(SpecificBumpPtrAllocator &&Old)
+      : Allocator(std::move(Old.Allocator)) {}
+  ~SpecificBumpPtrAllocator() { DestroyAll(); }
+
+  SpecificBumpPtrAllocator &operator=(SpecificBumpPtrAllocator &&RHS) {
+    Allocator = std::move(RHS.Allocator);
+    return *this;
+  }
+
+  /// Call the destructor of each allocated object and deallocate all but the
+  /// current slab and reset the current pointer to the beginning of it, freeing
+  /// all memory allocated so far.
+  void DestroyAll() {
+    auto DestroyElements = [](char *Begin, char *End) {
+      assert(Begin == (char *)alignAddr(Begin, Align::Of<T>()));
+      for (char *Ptr = Begin; Ptr + sizeof(T) <= End; Ptr += sizeof(T))
+        reinterpret_cast<T *>(Ptr)->~T();
+    };
+
+    for (auto I = Allocator.Slabs.begin(), E = Allocator.Slabs.end(); I != E;
+         ++I) {
+      size_t AllocatedSlabSize = BumpPtrAllocator::computeSlabSize(
+          std::distance(Allocator.Slabs.begin(), I));
+      char *Begin = (char *)alignAddr(*I, Align::Of<T>());
+      char *End = *I == Allocator.Slabs.back() ? Allocator.CurPtr
+                                               : (char *)*I + AllocatedSlabSize;
+
+      DestroyElements(Begin, End);
+    }
+
+    for (auto &PtrAndSize : Allocator.CustomSizedSlabs) {
+      void *Ptr = PtrAndSize.first;
+      size_t Size = PtrAndSize.second;
+      DestroyElements((char *)alignAddr(Ptr, Align::Of<T>()),
+                      (char *)Ptr + Size);
+    }
+
+    Allocator.Reset();
+  }
+
+  /// Allocate space for an array of objects without constructing them.
+  T *Allocate(size_t num = 1) { return Allocator.Allocate<T>(num); }
+};
+
+} // end namespace llvm
+
+template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold>
+void *operator new(size_t Size,
+                   llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize,
+                                              SizeThreshold> &Allocator) {
+  struct S {
+    char c;
+    union {
+      double D;
+      long double LD;
+      long long L;
+      void *P;
+    } x;
+  };
+  return Allocator.Allocate(
+      Size, std::min((size_t)llvm::NextPowerOf2(Size), offsetof(S, x)));
+}
+
+template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold>
+void operator delete(
+    void *, llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize, SizeThreshold> &) {
+}
+
+#endif // LLVM_SUPPORT_ALLOCATOR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/BinaryByteStream.h b/binaryen/third_party/llvm-project/include/llvm/Support/BinaryByteStream.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/BinaryByteStream.h
@@ -0,0 +1,273 @@
+//===- BinaryByteStream.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//===----------------------------------------------------------------------===//
+// A BinaryStream which stores data in a single continguous memory buffer.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYBYTESTREAM_H
+#define LLVM_SUPPORT_BINARYBYTESTREAM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/BinaryStream.h"
+#include "llvm/Support/BinaryStreamError.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+
+namespace llvm {
+
+/// An implementation of BinaryStream which holds its entire data set
+/// in a single contiguous buffer.  BinaryByteStream guarantees that no read
+/// operation will ever incur a copy.  Note that BinaryByteStream does not
+/// own the underlying buffer.
+class BinaryByteStream : public BinaryStream {
+public:
+  BinaryByteStream() = default;
+  BinaryByteStream(ArrayRef<uint8_t> Data, llvm::support::endianness Endian)
+      : Endian(Endian), Data(Data) {}
+  BinaryByteStream(StringRef Data, llvm::support::endianness Endian)
+      : Endian(Endian), Data(Data.bytes_begin(), Data.bytes_end()) {}
+
+  llvm::support::endianness getEndian() const override { return Endian; }
+
+  Error readBytes(uint32_t Offset, uint32_t Size,
+                  ArrayRef<uint8_t> &Buffer) override {
+    if (auto EC = checkOffsetForRead(Offset, Size))
+      return EC;
+    Buffer = Data.slice(Offset, Size);
+    return Error::success();
+  }
+
+  Error readLongestContiguousChunk(uint32_t Offset,
+                                   ArrayRef<uint8_t> &Buffer) override {
+    if (auto EC = checkOffsetForRead(Offset, 1))
+      return EC;
+    Buffer = Data.slice(Offset);
+    return Error::success();
+  }
+
+  uint32_t getLength() override { return Data.size(); }
+
+  ArrayRef<uint8_t> data() const { return Data; }
+
+  StringRef str() const {
+    const char *CharData = reinterpret_cast<const char *>(Data.data());
+    return StringRef(CharData, Data.size());
+  }
+
+protected:
+  llvm::support::endianness Endian;
+  ArrayRef<uint8_t> Data;
+};
+
+/// An implementation of BinaryStream whose data is backed by an llvm
+/// MemoryBuffer object.  MemoryBufferByteStream owns the MemoryBuffer in
+/// question.  As with BinaryByteStream, reading from a MemoryBufferByteStream
+/// will never cause a copy.
+class MemoryBufferByteStream : public BinaryByteStream {
+public:
+  MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer,
+                         llvm::support::endianness Endian)
+      : BinaryByteStream(Buffer->getBuffer(), Endian),
+        MemBuffer(std::move(Buffer)) {}
+
+  std::unique_ptr<MemoryBuffer> MemBuffer;
+};
+
+/// An implementation of BinaryStream which holds its entire data set
+/// in a single contiguous buffer.  As with BinaryByteStream, the mutable
+/// version also guarantees that no read operation will ever incur a copy,
+/// and similarly it does not own the underlying buffer.
+class MutableBinaryByteStream : public WritableBinaryStream {
+public:
+  MutableBinaryByteStream() = default;
+  MutableBinaryByteStream(MutableArrayRef<uint8_t> Data,
+                          llvm::support::endianness Endian)
+      : Data(Data), ImmutableStream(Data, Endian) {}
+
+  llvm::support::endianness getEndian() const override {
+    return ImmutableStream.getEndian();
+  }
+
+  Error readBytes(uint32_t Offset, uint32_t Size,
+                  ArrayRef<uint8_t> &Buffer) override {
+    return ImmutableStream.readBytes(Offset, Size, Buffer);
+  }
+
+  Error readLongestContiguousChunk(uint32_t Offset,
+                                   ArrayRef<uint8_t> &Buffer) override {
+    return ImmutableStream.readLongestContiguousChunk(Offset, Buffer);
+  }
+
+  uint32_t getLength() override { return ImmutableStream.getLength(); }
+
+  Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override {
+    if (Buffer.empty())
+      return Error::success();
+
+    if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
+      return EC;
+
+    uint8_t *DataPtr = const_cast<uint8_t *>(Data.data());
+    ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size());
+    return Error::success();
+  }
+
+  Error commit() override { return Error::success(); }
+
+  MutableArrayRef<uint8_t> data() const { return Data; }
+
+private:
+  MutableArrayRef<uint8_t> Data;
+  BinaryByteStream ImmutableStream;
+};
+
+/// An implementation of WritableBinaryStream which can write at its end
+/// causing the underlying data to grow.  This class owns the underlying data.
+class AppendingBinaryByteStream : public WritableBinaryStream {
+  std::vector<uint8_t> Data;
+  llvm::support::endianness Endian = llvm::support::little;
+
+public:
+  AppendingBinaryByteStream() = default;
+  AppendingBinaryByteStream(llvm::support::endianness Endian)
+      : Endian(Endian) {}
+
+  void clear() { Data.clear(); }
+
+  llvm::support::endianness getEndian() const override { return Endian; }
+
+  Error readBytes(uint32_t Offset, uint32_t Size,
+                  ArrayRef<uint8_t> &Buffer) override {
+    if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
+      return EC;
+
+    Buffer = makeArrayRef(Data).slice(Offset, Size);
+    return Error::success();
+  }
+
+  void insert(uint32_t Offset, ArrayRef<uint8_t> Bytes) {
+    Data.insert(Data.begin() + Offset, Bytes.begin(), Bytes.end());
+  }
+
+  Error readLongestContiguousChunk(uint32_t Offset,
+                                   ArrayRef<uint8_t> &Buffer) override {
+    if (auto EC = checkOffsetForWrite(Offset, 1))
+      return EC;
+
+    Buffer = makeArrayRef(Data).slice(Offset);
+    return Error::success();
+  }
+
+  uint32_t getLength() override { return Data.size(); }
+
+  Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override {
+    if (Buffer.empty())
+      return Error::success();
+
+    // This is well-defined for any case except where offset is strictly
+    // greater than the current length.  If offset is equal to the current
+    // length, we can still grow.  If offset is beyond the current length, we
+    // would have to decide how to deal with the intermediate uninitialized
+    // bytes.  So we punt on that case for simplicity and just say it's an
+    // error.
+    if (Offset > getLength())
+      return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
+
+    uint32_t RequiredSize = Offset + Buffer.size();
+    if (RequiredSize > Data.size())
+      Data.resize(RequiredSize);
+
+    ::memcpy(Data.data() + Offset, Buffer.data(), Buffer.size());
+    return Error::success();
+  }
+
+  Error commit() override { return Error::success(); }
+
+  /// Return the properties of this stream.
+  virtual BinaryStreamFlags getFlags() const override {
+    return BSF_Write | BSF_Append;
+  }
+
+  MutableArrayRef<uint8_t> data() { return Data; }
+};
+
+/// An implementation of WritableBinaryStream backed by an llvm
+/// FileOutputBuffer.
+class FileBufferByteStream : public WritableBinaryStream {
+private:
+  class StreamImpl : public MutableBinaryByteStream {
+  public:
+    StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer,
+               llvm::support::endianness Endian)
+        : MutableBinaryByteStream(
+              MutableArrayRef<uint8_t>(Buffer->getBufferStart(),
+                                       Buffer->getBufferEnd()),
+              Endian),
+          FileBuffer(std::move(Buffer)) {}
+
+    Error commit() override {
+      if (FileBuffer->commit())
+        return make_error<BinaryStreamError>(
+            stream_error_code::filesystem_error);
+      return Error::success();
+    }
+
+    /// Returns a pointer to the start of the buffer.
+    uint8_t *getBufferStart() const { return FileBuffer->getBufferStart(); }
+
+    /// Returns a pointer to the end of the buffer.
+    uint8_t *getBufferEnd() const { return FileBuffer->getBufferEnd(); }
+
+  private:
+    std::unique_ptr<FileOutputBuffer> FileBuffer;
+  };
+
+public:
+  FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer,
+                       llvm::support::endianness Endian)
+      : Impl(std::move(Buffer), Endian) {}
+
+  llvm::support::endianness getEndian() const override {
+    return Impl.getEndian();
+  }
+
+  Error readBytes(uint32_t Offset, uint32_t Size,
+                  ArrayRef<uint8_t> &Buffer) override {
+    return Impl.readBytes(Offset, Size, Buffer);
+  }
+
+  Error readLongestContiguousChunk(uint32_t Offset,
+                                   ArrayRef<uint8_t> &Buffer) override {
+    return Impl.readLongestContiguousChunk(Offset, Buffer);
+  }
+
+  uint32_t getLength() override { return Impl.getLength(); }
+
+  Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) override {
+    return Impl.writeBytes(Offset, Data);
+  }
+
+  Error commit() override { return Impl.commit(); }
+
+  /// Returns a pointer to the start of the buffer.
+  uint8_t *getBufferStart() const { return Impl.getBufferStart(); }
+
+  /// Returns a pointer to the end of the buffer.
+  uint8_t *getBufferEnd() const { return Impl.getBufferEnd(); }
+
+private:
+  StreamImpl Impl;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_BYTESTREAM_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/BinaryStream.h b/binaryen/third_party/llvm-project/include/llvm/Support/BinaryStream.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/BinaryStream.h
@@ -0,0 +1,101 @@
+//===- BinaryStream.h - Base interface for a stream of data -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYSTREAM_H
+#define LLVM_SUPPORT_BINARYSTREAM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/Support/BinaryStreamError.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+
+namespace llvm {
+
+enum BinaryStreamFlags {
+  BSF_None = 0,
+  BSF_Write = 1,  // Stream supports writing.
+  BSF_Append = 2, // Writing can occur at offset == length.
+  LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ BSF_Append)
+};
+
+/// An interface for accessing data in a stream-like format, but which
+/// discourages copying.  Instead of specifying a buffer in which to copy
+/// data on a read, the API returns an ArrayRef to data owned by the stream's
+/// implementation.  Since implementations may not necessarily store data in a
+/// single contiguous buffer (or even in memory at all), in such cases a it may
+/// be necessary for an implementation to cache such a buffer so that it can
+/// return it.
+class BinaryStream {
+public:
+  virtual ~BinaryStream() = default;
+
+  virtual llvm::support::endianness getEndian() const = 0;
+
+  /// Given an offset into the stream and a number of bytes, attempt to
+  /// read the bytes and set the output ArrayRef to point to data owned by the
+  /// stream.
+  virtual Error readBytes(uint32_t Offset, uint32_t Size,
+                          ArrayRef<uint8_t> &Buffer) = 0;
+
+  /// Given an offset into the stream, read as much as possible without
+  /// copying any data.
+  virtual Error readLongestContiguousChunk(uint32_t Offset,
+                                           ArrayRef<uint8_t> &Buffer) = 0;
+
+  /// Return the number of bytes of data in this stream.
+  virtual uint32_t getLength() = 0;
+
+  /// Return the properties of this stream.
+  virtual BinaryStreamFlags getFlags() const { return BSF_None; }
+
+protected:
+  Error checkOffsetForRead(uint32_t Offset, uint32_t DataSize) {
+    if (Offset > getLength())
+      return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
+    if (getLength() < DataSize + Offset)
+      return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
+    return Error::success();
+  }
+};
+
+/// A BinaryStream which can be read from as well as written to.  Note
+/// that writing to a BinaryStream always necessitates copying from the input
+/// buffer to the stream's backing store.  Streams are assumed to be buffered
+/// so that to be portable it is necessary to call commit() on the stream when
+/// all data has been written.
+class WritableBinaryStream : public BinaryStream {
+public:
+  ~WritableBinaryStream() override = default;
+
+  /// Attempt to write the given bytes into the stream at the desired
+  /// offset. This will always necessitate a copy.  Cannot shrink or grow the
+  /// stream, only writes into existing allocated space.
+  virtual Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) = 0;
+
+  /// For buffered streams, commits changes to the backing store.
+  virtual Error commit() = 0;
+
+  /// Return the properties of this stream.
+  BinaryStreamFlags getFlags() const override { return BSF_Write; }
+
+protected:
+  Error checkOffsetForWrite(uint32_t Offset, uint32_t DataSize) {
+    if (!(getFlags() & BSF_Append))
+      return checkOffsetForRead(Offset, DataSize);
+
+    if (Offset > getLength())
+      return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
+    return Error::success();
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYSTREAM_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/BinaryStreamError.h b/binaryen/third_party/llvm-project/include/llvm/Support/BinaryStreamError.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/BinaryStreamError.h
@@ -0,0 +1,47 @@
+//===- BinaryStreamError.h - Error extensions for Binary Streams *- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYSTREAMERROR_H
+#define LLVM_SUPPORT_BINARYSTREAMERROR_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+#include <string>
+
+namespace llvm {
+enum class stream_error_code {
+  unspecified,
+  stream_too_short,
+  invalid_array_size,
+  invalid_offset,
+  filesystem_error
+};
+
+/// Base class for errors originating when parsing raw PDB files
+class BinaryStreamError : public ErrorInfo<BinaryStreamError> {
+public:
+  static char ID;
+  explicit BinaryStreamError(stream_error_code C);
+  explicit BinaryStreamError(StringRef Context);
+  BinaryStreamError(stream_error_code C, StringRef Context);
+
+  void log(raw_ostream &OS) const override;
+  std::error_code convertToErrorCode() const override;
+
+  StringRef getErrorMessage() const;
+
+  stream_error_code getErrorCode() const { return Code; }
+
+private:
+  std::string ErrMsg;
+  stream_error_code Code;
+};
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYSTREAMERROR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/CBindingWrapping.h b/binaryen/third_party/llvm-project/include/llvm/Support/CBindingWrapping.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/CBindingWrapping.h
@@ -0,0 +1,46 @@
+//===- llvm/Support/CBindingWrapping.h - C Interface Wrapping ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the wrapping macros for the C interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CBINDINGWRAPPING_H
+#define LLVM_SUPPORT_CBINDINGWRAPPING_H
+
+#include "llvm-c/Types.h"
+#include "llvm/Support/Casting.h"
+
+#define DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref)     \
+  inline ty *unwrap(ref P) {                            \
+    return reinterpret_cast<ty*>(P);                    \
+  }                                                     \
+                                                        \
+  inline ref wrap(const ty *P) {                        \
+    return reinterpret_cast<ref>(const_cast<ty*>(P));   \
+  }
+
+#define DEFINE_ISA_CONVERSION_FUNCTIONS(ty, ref)        \
+  DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref)           \
+                                                        \
+  template<typename T>                                  \
+  inline T *unwrap(ref P) {                             \
+    return cast<T>(unwrap(P));                          \
+  }
+
+#define DEFINE_STDCXX_CONVERSION_FUNCTIONS(ty, ref)     \
+  DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref)           \
+                                                        \
+  template<typename T>                                  \
+  inline T *unwrap(ref P) {                             \
+    T *Q = (T*)unwrap(P);                               \
+    assert(Q && "Invalid cast!");                       \
+    return Q;                                           \
+  }
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Casting.h b/binaryen/third_party/llvm-project/include/llvm/Support/Casting.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Casting.h
@@ -0,0 +1,408 @@
+//===- llvm/Support/Casting.h - Allow flexible, checked, casts --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the isa<X>(), cast<X>(), dyn_cast<X>(), cast_or_null<X>(),
+// and dyn_cast_or_null<X>() templates.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CASTING_H
+#define LLVM_SUPPORT_CASTING_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/type_traits.h"
+#include <cassert>
+#include <memory>
+#include <type_traits>
+
+namespace llvm {
+
+//===----------------------------------------------------------------------===//
+//                          isa<x> Support Templates
+//===----------------------------------------------------------------------===//
+
+// Define a template that can be specialized by smart pointers to reflect the
+// fact that they are automatically dereferenced, and are not involved with the
+// template selection process...  the default implementation is a noop.
+//
+template<typename From> struct simplify_type {
+  using SimpleType = From; // The real type this represents...
+
+  // An accessor to get the real value...
+  static SimpleType &getSimplifiedValue(From &Val) { return Val; }
+};
+
+template<typename From> struct simplify_type<const From> {
+  using NonConstSimpleType = typename simplify_type<From>::SimpleType;
+  using SimpleType =
+      typename add_const_past_pointer<NonConstSimpleType>::type;
+  using RetType =
+      typename add_lvalue_reference_if_not_pointer<SimpleType>::type;
+
+  static RetType getSimplifiedValue(const From& Val) {
+    return simplify_type<From>::getSimplifiedValue(const_cast<From&>(Val));
+  }
+};
+
+// The core of the implementation of isa<X> is here; To and From should be
+// the names of classes.  This template can be specialized to customize the
+// implementation of isa<> without rewriting it from scratch.
+template <typename To, typename From, typename Enabler = void>
+struct isa_impl {
+  static inline bool doit(const From &Val) {
+    return To::classof(&Val);
+  }
+};
+
+/// Always allow upcasts, and perform no dynamic check for them.
+template <typename To, typename From>
+struct isa_impl<
+    To, From, typename std::enable_if<std::is_base_of<To, From>::value>::type> {
+  static inline bool doit(const From &) { return true; }
+};
+
+template <typename To, typename From> struct isa_impl_cl {
+  static inline bool doit(const From &Val) {
+    return isa_impl<To, From>::doit(Val);
+  }
+};
+
+template <typename To, typename From> struct isa_impl_cl<To, const From> {
+  static inline bool doit(const From &Val) {
+    return isa_impl<To, From>::doit(Val);
+  }
+};
+
+template <typename To, typename From>
+struct isa_impl_cl<To, const std::unique_ptr<From>> {
+  static inline bool doit(const std::unique_ptr<From> &Val) {
+    assert(Val && "isa<> used on a null pointer");
+    return isa_impl_cl<To, From>::doit(*Val);
+  }
+};
+
+template <typename To, typename From> struct isa_impl_cl<To, From*> {
+  static inline bool doit(const From *Val) {
+    assert(Val && "isa<> used on a null pointer");
+    return isa_impl<To, From>::doit(*Val);
+  }
+};
+
+template <typename To, typename From> struct isa_impl_cl<To, From*const> {
+  static inline bool doit(const From *Val) {
+    assert(Val && "isa<> used on a null pointer");
+    return isa_impl<To, From>::doit(*Val);
+  }
+};
+
+template <typename To, typename From> struct isa_impl_cl<To, const From*> {
+  static inline bool doit(const From *Val) {
+    assert(Val && "isa<> used on a null pointer");
+    return isa_impl<To, From>::doit(*Val);
+  }
+};
+
+template <typename To, typename From> struct isa_impl_cl<To, const From*const> {
+  static inline bool doit(const From *Val) {
+    assert(Val && "isa<> used on a null pointer");
+    return isa_impl<To, From>::doit(*Val);
+  }
+};
+
+template<typename To, typename From, typename SimpleFrom>
+struct isa_impl_wrap {
+  // When From != SimplifiedType, we can simplify the type some more by using
+  // the simplify_type template.
+  static bool doit(const From &Val) {
+    return isa_impl_wrap<To, SimpleFrom,
+      typename simplify_type<SimpleFrom>::SimpleType>::doit(
+                          simplify_type<const From>::getSimplifiedValue(Val));
+  }
+};
+
+template<typename To, typename FromTy>
+struct isa_impl_wrap<To, FromTy, FromTy> {
+  // When From == SimpleType, we are as simple as we are going to get.
+  static bool doit(const FromTy &Val) {
+    return isa_impl_cl<To,FromTy>::doit(Val);
+  }
+};
+
+// isa<X> - Return true if the parameter to the template is an instance of the
+// template type argument.  Used like this:
+//
+//  if (isa<Type>(myVal)) { ... }
+//
+template <class X, class Y> LLVM_NODISCARD inline bool isa(const Y &Val) {
+  return isa_impl_wrap<X, const Y,
+                       typename simplify_type<const Y>::SimpleType>::doit(Val);
+}
+
+// isa_and_nonnull<X> - Functionally identical to isa, except that a null value
+// is accepted.
+//
+template <class X, class Y>
+LLVM_NODISCARD inline bool isa_and_nonnull(const Y &Val) {
+  if (!Val)
+    return false;
+  return isa<X>(Val);
+}
+
+//===----------------------------------------------------------------------===//
+//                          cast<x> Support Templates
+//===----------------------------------------------------------------------===//
+
+template<class To, class From> struct cast_retty;
+
+// Calculate what type the 'cast' function should return, based on a requested
+// type of To and a source type of From.
+template<class To, class From> struct cast_retty_impl {
+  using ret_type = To &;       // Normal case, return Ty&
+};
+template<class To, class From> struct cast_retty_impl<To, const From> {
+  using ret_type = const To &; // Normal case, return Ty&
+};
+
+template<class To, class From> struct cast_retty_impl<To, From*> {
+  using ret_type = To *;       // Pointer arg case, return Ty*
+};
+
+template<class To, class From> struct cast_retty_impl<To, const From*> {
+  using ret_type = const To *; // Constant pointer arg case, return const Ty*
+};
+
+template<class To, class From> struct cast_retty_impl<To, const From*const> {
+  using ret_type = const To *; // Constant pointer arg case, return const Ty*
+};
+
+template <class To, class From>
+struct cast_retty_impl<To, std::unique_ptr<From>> {
+private:
+  using PointerType = typename cast_retty_impl<To, From *>::ret_type;
+  using ResultType = typename std::remove_pointer<PointerType>::type;
+
+public:
+  using ret_type = std::unique_ptr<ResultType>;
+};
+
+template<class To, class From, class SimpleFrom>
+struct cast_retty_wrap {
+  // When the simplified type and the from type are not the same, use the type
+  // simplifier to reduce the type, then reuse cast_retty_impl to get the
+  // resultant type.
+  using ret_type = typename cast_retty<To, SimpleFrom>::ret_type;
+};
+
+template<class To, class FromTy>
+struct cast_retty_wrap<To, FromTy, FromTy> {
+  // When the simplified type is equal to the from type, use it directly.
+  using ret_type = typename cast_retty_impl<To,FromTy>::ret_type;
+};
+
+template<class To, class From>
+struct cast_retty {
+  using ret_type = typename cast_retty_wrap<
+      To, From, typename simplify_type<From>::SimpleType>::ret_type;
+};
+
+// Ensure the non-simple values are converted using the simplify_type template
+// that may be specialized by smart pointers...
+//
+template<class To, class From, class SimpleFrom> struct cast_convert_val {
+  // This is not a simple type, use the template to simplify it...
+  static typename cast_retty<To, From>::ret_type doit(From &Val) {
+    return cast_convert_val<To, SimpleFrom,
+      typename simplify_type<SimpleFrom>::SimpleType>::doit(
+                          simplify_type<From>::getSimplifiedValue(Val));
+  }
+};
+
+template<class To, class FromTy> struct cast_convert_val<To,FromTy,FromTy> {
+  // This _is_ a simple type, just cast it.
+  static typename cast_retty<To, FromTy>::ret_type doit(const FromTy &Val) {
+    typename cast_retty<To, FromTy>::ret_type Res2
+     = (typename cast_retty<To, FromTy>::ret_type)const_cast<FromTy&>(Val);
+    return Res2;
+  }
+};
+
+template <class X> struct is_simple_type {
+  static const bool value =
+      std::is_same<X, typename simplify_type<X>::SimpleType>::value;
+};
+
+// cast<X> - Return the argument parameter cast to the specified type.  This
+// casting operator asserts that the type is correct, so it does not return null
+// on failure.  It does not allow a null argument (use cast_or_null for that).
+// It is typically used like this:
+//
+//  cast<Instruction>(myVal)->getParent()
+//
+template <class X, class Y>
+inline typename std::enable_if<!is_simple_type<Y>::value,
+                               typename cast_retty<X, const Y>::ret_type>::type
+cast(const Y &Val) {
+  assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!");
+  return cast_convert_val<
+      X, const Y, typename simplify_type<const Y>::SimpleType>::doit(Val);
+}
+
+template <class X, class Y>
+inline typename cast_retty<X, Y>::ret_type cast(Y &Val) {
+  assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!");
+  return cast_convert_val<X, Y,
+                          typename simplify_type<Y>::SimpleType>::doit(Val);
+}
+
+template <class X, class Y>
+inline typename cast_retty<X, Y *>::ret_type cast(Y *Val) {
+  assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!");
+  return cast_convert_val<X, Y*,
+                          typename simplify_type<Y*>::SimpleType>::doit(Val);
+}
+
+template <class X, class Y>
+inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type
+cast(std::unique_ptr<Y> &&Val) {
+  assert(isa<X>(Val.get()) && "cast<Ty>() argument of incompatible type!");
+  using ret_type = typename cast_retty<X, std::unique_ptr<Y>>::ret_type;
+  return ret_type(
+      cast_convert_val<X, Y *, typename simplify_type<Y *>::SimpleType>::doit(
+          Val.release()));
+}
+
+// cast_or_null<X> - Functionally identical to cast, except that a null value is
+// accepted.
+//
+template <class X, class Y>
+LLVM_NODISCARD inline
+    typename std::enable_if<!is_simple_type<Y>::value,
+                            typename cast_retty<X, const Y>::ret_type>::type
+    cast_or_null(const Y &Val) {
+  if (!Val)
+    return nullptr;
+  assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!");
+  return cast<X>(Val);
+}
+
+template <class X, class Y>
+LLVM_NODISCARD inline
+    typename std::enable_if<!is_simple_type<Y>::value,
+                            typename cast_retty<X, Y>::ret_type>::type
+    cast_or_null(Y &Val) {
+  if (!Val)
+    return nullptr;
+  assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!");
+  return cast<X>(Val);
+}
+
+template <class X, class Y>
+LLVM_NODISCARD inline typename cast_retty<X, Y *>::ret_type
+cast_or_null(Y *Val) {
+  if (!Val) return nullptr;
+  assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!");
+  return cast<X>(Val);
+}
+
+template <class X, class Y>
+inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type
+cast_or_null(std::unique_ptr<Y> &&Val) {
+  if (!Val)
+    return nullptr;
+  return cast<X>(std::move(Val));
+}
+
+// dyn_cast<X> - Return the argument parameter cast to the specified type.  This
+// casting operator returns null if the argument is of the wrong type, so it can
+// be used to test for a type as well as cast if successful.  This should be
+// used in the context of an if statement like this:
+//
+//  if (const Instruction *I = dyn_cast<Instruction>(myVal)) { ... }
+//
+
+template <class X, class Y>
+LLVM_NODISCARD inline
+    typename std::enable_if<!is_simple_type<Y>::value,
+                            typename cast_retty<X, const Y>::ret_type>::type
+    dyn_cast(const Y &Val) {
+  return isa<X>(Val) ? cast<X>(Val) : nullptr;
+}
+
+template <class X, class Y>
+LLVM_NODISCARD inline typename cast_retty<X, Y>::ret_type dyn_cast(Y &Val) {
+  return isa<X>(Val) ? cast<X>(Val) : nullptr;
+}
+
+template <class X, class Y>
+LLVM_NODISCARD inline typename cast_retty<X, Y *>::ret_type dyn_cast(Y *Val) {
+  return isa<X>(Val) ? cast<X>(Val) : nullptr;
+}
+
+// dyn_cast_or_null<X> - Functionally identical to dyn_cast, except that a null
+// value is accepted.
+//
+template <class X, class Y>
+LLVM_NODISCARD inline
+    typename std::enable_if<!is_simple_type<Y>::value,
+                            typename cast_retty<X, const Y>::ret_type>::type
+    dyn_cast_or_null(const Y &Val) {
+  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
+}
+
+template <class X, class Y>
+LLVM_NODISCARD inline
+    typename std::enable_if<!is_simple_type<Y>::value,
+                            typename cast_retty<X, Y>::ret_type>::type
+    dyn_cast_or_null(Y &Val) {
+  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
+}
+
+template <class X, class Y>
+LLVM_NODISCARD inline typename cast_retty<X, Y *>::ret_type
+dyn_cast_or_null(Y *Val) {
+  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
+}
+
+// unique_dyn_cast<X> - Given a unique_ptr<Y>, try to return a unique_ptr<X>,
+// taking ownership of the input pointer iff isa<X>(Val) is true.  If the
+// cast is successful, From refers to nullptr on exit and the casted value
+// is returned.  If the cast is unsuccessful, the function returns nullptr
+// and From is unchanged.
+template <class X, class Y>
+LLVM_NODISCARD inline auto unique_dyn_cast(std::unique_ptr<Y> &Val)
+    -> decltype(cast<X>(Val)) {
+  if (!isa<X>(Val))
+    return nullptr;
+  return cast<X>(std::move(Val));
+}
+
+template <class X, class Y>
+LLVM_NODISCARD inline auto unique_dyn_cast(std::unique_ptr<Y> &&Val)
+    -> decltype(cast<X>(Val)) {
+  return unique_dyn_cast<X, Y>(Val);
+}
+
+// dyn_cast_or_null<X> - Functionally identical to unique_dyn_cast, except that
+// a null value is accepted.
+template <class X, class Y>
+LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &Val)
+    -> decltype(cast<X>(Val)) {
+  if (!Val)
+    return nullptr;
+  return unique_dyn_cast<X, Y>(Val);
+}
+
+template <class X, class Y>
+LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &&Val)
+    -> decltype(cast<X>(Val)) {
+  return unique_dyn_cast_or_null<X, Y>(Val);
+}
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_CASTING_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Chrono.h b/binaryen/third_party/llvm-project/include/llvm/Support/Chrono.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Chrono.h
@@ -0,0 +1,171 @@
+//===- llvm/Support/Chrono.h - Utilities for Timing Manipulation-*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CHRONO_H
+#define LLVM_SUPPORT_CHRONO_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/FormatProviders.h"
+
+#include <chrono>
+#include <ctime>
+
+namespace llvm {
+
+class raw_ostream;
+
+namespace sys {
+
+/// A time point on the system clock. This is provided for two reasons:
+/// - to insulate us agains subtle differences in behavoir to differences in
+///   system clock precision (which is implementation-defined and differs between
+///   platforms).
+/// - to shorten the type name
+/// The default precision is nanoseconds. If need a specific precision specify
+/// it explicitly. If unsure, use the default. If you need a time point on a
+/// clock other than the system_clock, use std::chrono directly.
+template <typename D = std::chrono::nanoseconds>
+using TimePoint = std::chrono::time_point<std::chrono::system_clock, D>;
+
+/// Convert a TimePoint to std::time_t
+inline std::time_t toTimeT(TimePoint<> TP) {
+  using namespace std::chrono;
+  return system_clock::to_time_t(
+      time_point_cast<system_clock::time_point::duration>(TP));
+}
+
+/// Convert a std::time_t to a TimePoint
+inline TimePoint<std::chrono::seconds>
+toTimePoint(std::time_t T) {
+  using namespace std::chrono;
+  return time_point_cast<seconds>(system_clock::from_time_t(T));
+}
+
+/// Convert a std::time_t + nanoseconds to a TimePoint
+inline TimePoint<>
+toTimePoint(std::time_t T, uint32_t nsec) {
+  using namespace std::chrono;
+  return time_point_cast<nanoseconds>(system_clock::from_time_t(T))
+    + nanoseconds(nsec);
+}
+
+} // namespace sys
+
+raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP);
+
+/// Format provider for TimePoint<>
+///
+/// The options string is a strftime format string, with extensions:
+///   - %L is millis: 000-999
+///   - %f is micros: 000000-999999
+///   - %N is nanos: 000000000 - 999999999
+///
+/// If no options are given, the default format is "%Y-%m-%d %H:%M:%S.%N".
+template <>
+struct format_provider<sys::TimePoint<>> {
+  static void format(const sys::TimePoint<> &TP, llvm::raw_ostream &OS,
+                     StringRef Style);
+};
+
+/// Implementation of format_provider<T> for duration types.
+///
+/// The options string of a duration  type has the grammar:
+///
+///   duration_options  ::= [unit][show_unit [number_options]]
+///   unit              ::= `h`|`m`|`s`|`ms|`us`|`ns`
+///   show_unit         ::= `+` | `-`
+///   number_options    ::= options string for a integral or floating point type
+///
+///   Examples
+///   =================================
+///   |  options  | Input | Output    |
+///   =================================
+///   | ""        | 1s    | 1 s       |
+///   | "ms"      | 1s    | 1000 ms   |
+///   | "ms-"     | 1s    | 1000      |
+///   | "ms-n"    | 1s    | 1,000     |
+///   | ""        | 1.0s  | 1.00 s    |
+///   =================================
+///
+///  If the unit of the duration type is not one of the units specified above,
+///  it is still possible to format it, provided you explicitly request a
+///  display unit or you request that the unit is not displayed.
+
+namespace detail {
+template <typename Period> struct unit { static const char value[]; };
+template <typename Period> const char unit<Period>::value[] = "";
+
+template <> struct unit<std::ratio<3600>> { static const char value[]; };
+template <> struct unit<std::ratio<60>> { static const char value[]; };
+template <> struct unit<std::ratio<1>> { static const char value[]; };
+template <> struct unit<std::milli> { static const char value[]; };
+template <> struct unit<std::micro> { static const char value[]; };
+template <> struct unit<std::nano> { static const char value[]; };
+} // namespace detail
+
+template <typename Rep, typename Period>
+struct format_provider<std::chrono::duration<Rep, Period>> {
+private:
+  typedef std::chrono::duration<Rep, Period> Dur;
+  typedef typename std::conditional<
+      std::chrono::treat_as_floating_point<Rep>::value, double, intmax_t>::type
+      InternalRep;
+
+  template <typename AsPeriod> static InternalRep getAs(const Dur &D) {
+    using namespace std::chrono;
+    return duration_cast<duration<InternalRep, AsPeriod>>(D).count();
+  }
+
+  static std::pair<InternalRep, StringRef> consumeUnit(StringRef &Style,
+                                                        const Dur &D) {
+    using namespace std::chrono;
+    if (Style.consume_front("ns"))
+      return {getAs<std::nano>(D), "ns"};
+    if (Style.consume_front("us"))
+      return {getAs<std::micro>(D), "us"};
+    if (Style.consume_front("ms"))
+      return {getAs<std::milli>(D), "ms"};
+    if (Style.consume_front("s"))
+      return {getAs<std::ratio<1>>(D), "s"};
+    if (Style.consume_front("m"))
+      return {getAs<std::ratio<60>>(D), "m"};
+    if (Style.consume_front("h"))
+      return {getAs<std::ratio<3600>>(D), "h"};
+    return {D.count(), detail::unit<Period>::value};
+  }
+
+  static bool consumeShowUnit(StringRef &Style) {
+    if (Style.empty())
+      return true;
+    if (Style.consume_front("-"))
+      return false;
+    if (Style.consume_front("+"))
+      return true;
+    assert(0 && "Unrecognised duration format");
+    return true;
+  }
+
+public:
+  static void format(const Dur &D, llvm::raw_ostream &Stream, StringRef Style) {
+    InternalRep count;
+    StringRef unit;
+    std::tie(count, unit) = consumeUnit(Style, D);
+    bool show_unit = consumeShowUnit(Style);
+
+    format_provider<InternalRep>::format(count, Stream, Style);
+
+    if (show_unit) {
+      assert(!unit.empty());
+      Stream << " " << unit;
+    }
+  }
+};
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_CHRONO_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/CodeGen.h b/binaryen/third_party/llvm-project/include/llvm/Support/CodeGen.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/CodeGen.h
@@ -0,0 +1,67 @@
+//===-- llvm/Support/CodeGen.h - CodeGen Concepts ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file define some types which define code generation concepts. For
+// example, relocation model.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CODEGEN_H
+#define LLVM_SUPPORT_CODEGEN_H
+
+namespace llvm {
+
+  // Relocation model types.
+  namespace Reloc {
+    // Cannot be named PIC due to collision with -DPIC
+    enum Model { Static, PIC_, DynamicNoPIC, ROPI, RWPI, ROPI_RWPI };
+  }
+
+  // Code model types.
+  namespace CodeModel {
+    // Sync changes with CodeGenCWrappers.h.
+    enum Model { Tiny, Small, Kernel, Medium, Large };
+  }
+
+  namespace PICLevel {
+    // This is used to map -fpic/-fPIC.
+    enum Level { NotPIC=0, SmallPIC=1, BigPIC=2 };
+  }
+
+  namespace PIELevel {
+    enum Level { Default=0, Small=1, Large=2 };
+  }
+
+  // TLS models.
+  namespace TLSModel {
+    enum Model {
+      GeneralDynamic,
+      LocalDynamic,
+      InitialExec,
+      LocalExec
+    };
+  }
+
+  // Code generation optimization level.
+  namespace CodeGenOpt {
+    enum Level {
+      None = 0,      // -O0
+      Less = 1,      // -O1
+      Default = 2,   // -O2, -Os
+      Aggressive = 3 // -O3
+    };
+  }
+
+  // Specify effect of frame pointer elimination optimization.
+  namespace FramePointer {
+    enum FP {All, NonLeaf, None};
+  }
+
+}  // end llvm namespace
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/CommandLine.h b/binaryen/third_party/llvm-project/include/llvm/Support/CommandLine.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/CommandLine.h
@@ -0,0 +1,1 @@
+// XXX BINARYEN - we don't need this, but stuff imports it
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Compiler.h b/binaryen/third_party/llvm-project/include/llvm/Support/Compiler.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Compiler.h
@@ -0,0 +1,585 @@
+//===-- llvm/Support/Compiler.h - Compiler abstraction support --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines several macros, based on the current compiler.  This allows
+// use of compiler-specific features in a way that remains portable. This header
+// can be included from either C or C++.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_COMPILER_H
+#define LLVM_SUPPORT_COMPILER_H
+
+#include "llvm/Config/llvm-config.h"
+
+#ifdef __cplusplus
+#include <new>
+#endif
+#include <stddef.h>
+
+#if defined(_MSC_VER)
+#include <sal.h>
+#endif
+
+#ifndef __has_feature
+# define __has_feature(x) 0
+#endif
+
+#ifndef __has_extension
+# define __has_extension(x) 0
+#endif
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0
+#endif
+
+#ifndef __has_builtin
+# define __has_builtin(x) 0
+#endif
+
+// Only use __has_cpp_attribute in C++ mode. GCC defines __has_cpp_attribute in
+// C mode, but the :: in __has_cpp_attribute(scoped::attribute) is invalid.
+#ifndef LLVM_HAS_CPP_ATTRIBUTE
+#if defined(__cplusplus) && defined(__has_cpp_attribute)
+# define LLVM_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
+#else
+# define LLVM_HAS_CPP_ATTRIBUTE(x) 0
+#endif
+#endif
+
+/// \macro LLVM_GNUC_PREREQ
+/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't
+/// available.
+#ifndef LLVM_GNUC_PREREQ
+# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
+#  define LLVM_GNUC_PREREQ(maj, min, patch) \
+    ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
+     ((maj) << 20) + ((min) << 10) + (patch))
+# elif defined(__GNUC__) && defined(__GNUC_MINOR__)
+#  define LLVM_GNUC_PREREQ(maj, min, patch) \
+    ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
+# else
+#  define LLVM_GNUC_PREREQ(maj, min, patch) 0
+# endif
+#endif
+
+/// \macro LLVM_MSC_PREREQ
+/// Is the compiler MSVC of at least the specified version?
+/// The common \param version values to check for are:
+/// * 1910: VS2017, version 15.1 & 15.2
+/// * 1911: VS2017, version 15.3 & 15.4
+/// * 1912: VS2017, version 15.5
+/// * 1913: VS2017, version 15.6
+/// * 1914: VS2017, version 15.7
+/// * 1915: VS2017, version 15.8
+/// * 1916: VS2017, version 15.9
+/// * 1920: VS2019, version 16.0
+/// * 1921: VS2019, version 16.1
+#ifdef _MSC_VER
+#define LLVM_MSC_PREREQ(version) (_MSC_VER >= (version))
+
+// We require at least MSVC 2017.
+#if !LLVM_MSC_PREREQ(1910)
+#error LLVM requires at least MSVC 2017.
+#endif
+
+#else
+#define LLVM_MSC_PREREQ(version) 0
+#endif
+
+/// Does the compiler support ref-qualifiers for *this?
+///
+/// Sadly, this is separate from just rvalue reference support because GCC
+/// and MSVC implemented this later than everything else.
+#if __has_feature(cxx_rvalue_references) || LLVM_GNUC_PREREQ(4, 8, 1)
+#define LLVM_HAS_RVALUE_REFERENCE_THIS 1
+#else
+#define LLVM_HAS_RVALUE_REFERENCE_THIS 0
+#endif
+
+/// Expands to '&' if ref-qualifiers for *this are supported.
+///
+/// This can be used to provide lvalue/rvalue overrides of member functions.
+/// The rvalue override should be guarded by LLVM_HAS_RVALUE_REFERENCE_THIS
+#if LLVM_HAS_RVALUE_REFERENCE_THIS
+#define LLVM_LVALUE_FUNCTION &
+#else
+#define LLVM_LVALUE_FUNCTION
+#endif
+
+/// LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked
+/// into a shared library, then the class should be private to the library and
+/// not accessible from outside it.  Can also be used to mark variables and
+/// functions, making them private to any shared library they are linked into.
+/// On PE/COFF targets, library visibility is the default, so this isn't needed.
+#if (__has_attribute(visibility) || LLVM_GNUC_PREREQ(4, 0, 0)) &&              \
+    !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32)
+#define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden")))
+#else
+#define LLVM_LIBRARY_VISIBILITY
+#endif
+
+#if defined(__GNUC__)
+#define LLVM_PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality)
+#else
+#define LLVM_PREFETCH(addr, rw, locality)
+#endif
+
+#if __has_attribute(used) || LLVM_GNUC_PREREQ(3, 1, 0)
+#define LLVM_ATTRIBUTE_USED __attribute__((__used__))
+#else
+#define LLVM_ATTRIBUTE_USED
+#endif
+
+/// LLVM_NODISCARD - Warn if a type or return value is discarded.
+
+// Use the 'nodiscard' attribute in C++17 or newer mode.
+#if __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(nodiscard)
+#define LLVM_NODISCARD [[nodiscard]]
+#elif LLVM_HAS_CPP_ATTRIBUTE(clang::warn_unused_result)
+#define LLVM_NODISCARD [[clang::warn_unused_result]]
+// Clang in C++14 mode claims that it has the 'nodiscard' attribute, but also
+// warns in the pedantic mode that 'nodiscard' is a C++17 extension (PR33518).
+// Use the 'nodiscard' attribute in C++14 mode only with GCC.
+// TODO: remove this workaround when PR33518 is resolved.
+#elif defined(__GNUC__) && LLVM_HAS_CPP_ATTRIBUTE(nodiscard)
+#define LLVM_NODISCARD [[nodiscard]]
+#else
+#define LLVM_NODISCARD
+#endif
+
+// Indicate that a non-static, non-const C++ member function reinitializes
+// the entire object to a known state, independent of the previous state of
+// the object.
+//
+// The clang-tidy check bugprone-use-after-move recognizes this attribute as a
+// marker that a moved-from object has left the indeterminate state and can be
+// reused.
+#if LLVM_HAS_CPP_ATTRIBUTE(clang::reinitializes)
+#define LLVM_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
+#else
+#define LLVM_ATTRIBUTE_REINITIALIZES
+#endif
+
+// Some compilers warn about unused functions. When a function is sometimes
+// used or not depending on build settings (e.g. a function only called from
+// within "assert"), this attribute can be used to suppress such warnings.
+//
+// However, it shouldn't be used for unused *variables*, as those have a much
+// more portable solution:
+//   (void)unused_var_name;
+// Prefer cast-to-void wherever it is sufficient.
+#if __has_attribute(unused) || LLVM_GNUC_PREREQ(3, 1, 0)
+#define LLVM_ATTRIBUTE_UNUSED __attribute__((__unused__))
+#else
+#define LLVM_ATTRIBUTE_UNUSED
+#endif
+
+// FIXME: Provide this for PE/COFF targets.
+#if (__has_attribute(weak) || LLVM_GNUC_PREREQ(4, 0, 0)) &&                    \
+    (!defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32))
+#define LLVM_ATTRIBUTE_WEAK __attribute__((__weak__))
+#else
+#define LLVM_ATTRIBUTE_WEAK
+#endif
+
+// Prior to clang 3.2, clang did not accept any spelling of
+// __has_attribute(const), so assume it is supported.
+#if defined(__clang__) || defined(__GNUC__)
+// aka 'CONST' but following LLVM Conventions.
+#define LLVM_READNONE __attribute__((__const__))
+#else
+#define LLVM_READNONE
+#endif
+
+#if __has_attribute(pure) || defined(__GNUC__)
+// aka 'PURE' but following LLVM Conventions.
+#define LLVM_READONLY __attribute__((__pure__))
+#else
+#define LLVM_READONLY
+#endif
+
+#if __has_builtin(__builtin_expect) || LLVM_GNUC_PREREQ(4, 0, 0)
+#define LLVM_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
+#define LLVM_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
+#else
+#define LLVM_LIKELY(EXPR) (EXPR)
+#define LLVM_UNLIKELY(EXPR) (EXPR)
+#endif
+
+/// LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so,
+/// mark a method "not for inlining".
+#if __has_attribute(noinline) || LLVM_GNUC_PREREQ(3, 4, 0)
+#define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_NOINLINE __declspec(noinline)
+#else
+#define LLVM_ATTRIBUTE_NOINLINE
+#endif
+
+/// LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do
+/// so, mark a method "always inline" because it is performance sensitive. GCC
+/// 3.4 supported this but is buggy in various cases and produces unimplemented
+/// errors, just use it in GCC 4.0 and later.
+#if __has_attribute(always_inline) || LLVM_GNUC_PREREQ(4, 0, 0)
+#define LLVM_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline
+#else
+#define LLVM_ATTRIBUTE_ALWAYS_INLINE
+#endif
+
+#ifdef __GNUC__
+#define LLVM_ATTRIBUTE_NORETURN __attribute__((noreturn))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_NORETURN __declspec(noreturn)
+#else
+#define LLVM_ATTRIBUTE_NORETURN
+#endif
+
+#if __has_attribute(returns_nonnull) || LLVM_GNUC_PREREQ(4, 9, 0)
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_
+#else
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL
+#endif
+
+/// \macro LLVM_ATTRIBUTE_RETURNS_NOALIAS Used to mark a function as returning a
+/// pointer that does not alias any other valid pointer.
+#ifdef __GNUC__
+#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict)
+#else
+#define LLVM_ATTRIBUTE_RETURNS_NOALIAS
+#endif
+
+/// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
+#if __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(fallthrough)
+#define LLVM_FALLTHROUGH [[fallthrough]]
+#elif LLVM_HAS_CPP_ATTRIBUTE(gnu::fallthrough)
+#define LLVM_FALLTHROUGH [[gnu::fallthrough]]
+#elif __has_attribute(fallthrough)
+#define LLVM_FALLTHROUGH __attribute__((fallthrough))
+#elif LLVM_HAS_CPP_ATTRIBUTE(clang::fallthrough)
+#define LLVM_FALLTHROUGH [[clang::fallthrough]]
+#else
+#define LLVM_FALLTHROUGH
+#endif
+
+/// LLVM_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that
+/// they are constant initialized.
+#if LLVM_HAS_CPP_ATTRIBUTE(clang::require_constant_initialization)
+#define LLVM_REQUIRE_CONSTANT_INITIALIZATION                                   \
+  [[clang::require_constant_initialization]]
+#else
+#define LLVM_REQUIRE_CONSTANT_INITIALIZATION
+#endif
+
+/// LLVM_EXTENSION - Support compilers where we have a keyword to suppress
+/// pedantic diagnostics.
+#ifdef __GNUC__
+#define LLVM_EXTENSION __extension__
+#else
+#define LLVM_EXTENSION
+#endif
+
+// LLVM_ATTRIBUTE_DEPRECATED(decl, "message")
+#if __has_feature(attribute_deprecated_with_message)
+# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
+  decl __attribute__((deprecated(message)))
+#elif defined(__GNUC__)
+# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
+  decl __attribute__((deprecated))
+#elif defined(_MSC_VER)
+# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
+  __declspec(deprecated(message)) decl
+#else
+# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
+  decl
+#endif
+
+/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands
+/// to an expression which states that it is undefined behavior for the
+/// compiler to reach this point.  Otherwise is not defined.
+#if __has_builtin(__builtin_unreachable) || LLVM_GNUC_PREREQ(4, 5, 0)
+# define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable()
+#elif defined(_MSC_VER)
+# define LLVM_BUILTIN_UNREACHABLE __assume(false)
+#endif
+
+/// LLVM_BUILTIN_TRAP - On compilers which support it, expands to an expression
+/// which causes the program to exit abnormally.
+#if __has_builtin(__builtin_trap) || LLVM_GNUC_PREREQ(4, 3, 0)
+# define LLVM_BUILTIN_TRAP __builtin_trap()
+#elif defined(_MSC_VER)
+// The __debugbreak intrinsic is supported by MSVC, does not require forward
+// declarations involving platform-specific typedefs (unlike RaiseException),
+// results in a call to vectored exception handlers, and encodes to a short
+// instruction that still causes the trapping behavior we want.
+# define LLVM_BUILTIN_TRAP __debugbreak()
+#else
+# define LLVM_BUILTIN_TRAP *(volatile int*)0x11 = 0
+#endif
+
+/// LLVM_BUILTIN_DEBUGTRAP - On compilers which support it, expands to
+/// an expression which causes the program to break while running
+/// under a debugger.
+#if __has_builtin(__builtin_debugtrap)
+# define LLVM_BUILTIN_DEBUGTRAP __builtin_debugtrap()
+#elif defined(_MSC_VER)
+// The __debugbreak intrinsic is supported by MSVC and breaks while
+// running under the debugger, and also supports invoking a debugger
+// when the OS is configured appropriately.
+# define LLVM_BUILTIN_DEBUGTRAP __debugbreak()
+#else
+// Just continue execution when built with compilers that have no
+// support. This is a debugging aid and not intended to force the
+// program to abort if encountered.
+# define LLVM_BUILTIN_DEBUGTRAP
+#endif
+
+/// \macro LLVM_ASSUME_ALIGNED
+/// Returns a pointer with an assumed alignment.
+#if __has_builtin(__builtin_assume_aligned) || LLVM_GNUC_PREREQ(4, 7, 0)
+# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a)
+#elif defined(LLVM_BUILTIN_UNREACHABLE)
+// As of today, clang does not support __builtin_assume_aligned.
+# define LLVM_ASSUME_ALIGNED(p, a) \
+           (((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p)))
+#else
+# define LLVM_ASSUME_ALIGNED(p, a) (p)
+#endif
+
+/// \macro LLVM_PACKED
+/// Used to specify a packed structure.
+/// LLVM_PACKED(
+///    struct A {
+///      int i;
+///      int j;
+///      int k;
+///      long long l;
+///   });
+///
+/// LLVM_PACKED_START
+/// struct B {
+///   int i;
+///   int j;
+///   int k;
+///   long long l;
+/// };
+/// LLVM_PACKED_END
+#ifdef _MSC_VER
+# define LLVM_PACKED(d) __pragma(pack(push, 1)) d __pragma(pack(pop))
+# define LLVM_PACKED_START __pragma(pack(push, 1))
+# define LLVM_PACKED_END   __pragma(pack(pop))
+#else
+# define LLVM_PACKED(d) d __attribute__((packed))
+# define LLVM_PACKED_START _Pragma("pack(push, 1)")
+# define LLVM_PACKED_END   _Pragma("pack(pop)")
+#endif
+
+/// \macro LLVM_PTR_SIZE
+/// A constant integer equivalent to the value of sizeof(void*).
+/// Generally used in combination with alignas or when doing computation in the
+/// preprocessor.
+#ifdef __SIZEOF_POINTER__
+# define LLVM_PTR_SIZE __SIZEOF_POINTER__
+#elif defined(_WIN64)
+# define LLVM_PTR_SIZE 8
+#elif defined(_WIN32)
+# define LLVM_PTR_SIZE 4
+#elif defined(_MSC_VER)
+# error "could not determine LLVM_PTR_SIZE as a constant int for MSVC"
+#else
+# define LLVM_PTR_SIZE sizeof(void *)
+#endif
+
+/// \macro LLVM_MEMORY_SANITIZER_BUILD
+/// Whether LLVM itself is built with MemorySanitizer instrumentation.
+#if __has_feature(memory_sanitizer)
+# define LLVM_MEMORY_SANITIZER_BUILD 1
+# include <sanitizer/msan_interface.h>
+#else
+# define LLVM_MEMORY_SANITIZER_BUILD 0
+# define __msan_allocated_memory(p, size)
+# define __msan_unpoison(p, size)
+#endif
+
+/// \macro LLVM_ADDRESS_SANITIZER_BUILD
+/// Whether LLVM itself is built with AddressSanitizer instrumentation.
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+# define LLVM_ADDRESS_SANITIZER_BUILD 1
+# include <sanitizer/asan_interface.h>
+#else
+# define LLVM_ADDRESS_SANITIZER_BUILD 0
+# define __asan_poison_memory_region(p, size)
+# define __asan_unpoison_memory_region(p, size)
+#endif
+
+/// \macro LLVM_THREAD_SANITIZER_BUILD
+/// Whether LLVM itself is built with ThreadSanitizer instrumentation.
+#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
+# define LLVM_THREAD_SANITIZER_BUILD 1
+#else
+# define LLVM_THREAD_SANITIZER_BUILD 0
+#endif
+
+#if LLVM_THREAD_SANITIZER_BUILD
+// Thread Sanitizer is a tool that finds races in code.
+// See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations .
+// tsan detects these exact functions by name.
+#ifdef __cplusplus
+extern "C" {
+#endif
+void AnnotateHappensAfter(const char *file, int line, const volatile void *cv);
+void AnnotateHappensBefore(const char *file, int line, const volatile void *cv);
+void AnnotateIgnoreWritesBegin(const char *file, int line);
+void AnnotateIgnoreWritesEnd(const char *file, int line);
+#ifdef __cplusplus
+}
+#endif
+
+// This marker is used to define a happens-before arc. The race detector will
+// infer an arc from the begin to the end when they share the same pointer
+// argument.
+# define TsanHappensBefore(cv) AnnotateHappensBefore(__FILE__, __LINE__, cv)
+
+// This marker defines the destination of a happens-before arc.
+# define TsanHappensAfter(cv) AnnotateHappensAfter(__FILE__, __LINE__, cv)
+
+// Ignore any races on writes between here and the next TsanIgnoreWritesEnd.
+# define TsanIgnoreWritesBegin() AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
+
+// Resume checking for racy writes.
+# define TsanIgnoreWritesEnd() AnnotateIgnoreWritesEnd(__FILE__, __LINE__)
+#else
+# define TsanHappensBefore(cv)
+# define TsanHappensAfter(cv)
+# define TsanIgnoreWritesBegin()
+# define TsanIgnoreWritesEnd()
+#endif
+
+/// \macro LLVM_NO_SANITIZE
+/// Disable a particular sanitizer for a function.
+#if __has_attribute(no_sanitize)
+#define LLVM_NO_SANITIZE(KIND) __attribute__((no_sanitize(KIND)))
+#else
+#define LLVM_NO_SANITIZE(KIND)
+#endif
+
+/// Mark debug helper function definitions like dump() that should not be
+/// stripped from debug builds.
+/// Note that you should also surround dump() functions with
+/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always
+/// get stripped in release builds.
+// FIXME: Move this to a private config.h as it's not usable in public headers.
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
+#else
+#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE
+#endif
+
+/// \macro LLVM_PRETTY_FUNCTION
+/// Gets a user-friendly looking function signature for the current scope
+/// using the best available method on each platform.  The exact format of the
+/// resulting string is implementation specific and non-portable, so this should
+/// only be used, for example, for logging or diagnostics.
+#if defined(_MSC_VER)
+#define LLVM_PRETTY_FUNCTION __FUNCSIG__
+#elif defined(__GNUC__) || defined(__clang__)
+#define LLVM_PRETTY_FUNCTION __PRETTY_FUNCTION__
+#else
+#define LLVM_PRETTY_FUNCTION __func__
+#endif
+
+/// \macro LLVM_THREAD_LOCAL
+/// A thread-local storage specifier which can be used with globals,
+/// extern globals, and static globals.
+///
+/// This is essentially an extremely restricted analog to C++11's thread_local
+/// support, and uses that when available. However, it falls back on
+/// platform-specific or vendor-provided extensions when necessary. These
+/// extensions don't support many of the C++11 thread_local's features. You
+/// should only use this for PODs that you can statically initialize to
+/// some constant value. In almost all circumstances this is most appropriate
+/// for use with a pointer, integer, or small aggregation of pointers and
+/// integers.
+#if LLVM_ENABLE_THREADS
+#if __has_feature(cxx_thread_local)
+#define LLVM_THREAD_LOCAL thread_local
+#elif defined(_MSC_VER)
+// MSVC supports this with a __declspec.
+#define LLVM_THREAD_LOCAL __declspec(thread)
+#else
+// Clang, GCC, and other compatible compilers used __thread prior to C++11 and
+// we only need the restricted functionality that provides.
+#define LLVM_THREAD_LOCAL __thread
+#endif
+#else // !LLVM_ENABLE_THREADS
+// If threading is disabled entirely, this compiles to nothing and you get
+// a normal global variable.
+#define LLVM_THREAD_LOCAL
+#endif
+
+/// \macro LLVM_ENABLE_EXCEPTIONS
+/// Whether LLVM is built with exception support.
+#if __has_feature(cxx_exceptions)
+#define LLVM_ENABLE_EXCEPTIONS 1
+#elif defined(__GNUC__) && defined(__EXCEPTIONS)
+#define LLVM_ENABLE_EXCEPTIONS 1
+#elif defined(_MSC_VER) && defined(_CPPUNWIND)
+#define LLVM_ENABLE_EXCEPTIONS 1
+#endif
+
+#ifdef __cplusplus
+namespace llvm {
+
+/// Allocate a buffer of memory with the given size and alignment.
+///
+/// When the compiler supports aligned operator new, this will use it to to
+/// handle even over-aligned allocations.
+///
+/// However, this doesn't make any attempt to leverage the fancier techniques
+/// like posix_memalign due to portability. It is mostly intended to allow
+/// compatibility with platforms that, after aligned allocation was added, use
+/// reduced default alignment.
+inline void *allocate_buffer(size_t Size, size_t Alignment) {
+  return ::operator new(Size
+#ifdef __cpp_aligned_new
+                        ,
+                        std::align_val_t(Alignment)
+#endif
+  );
+}
+
+/// Deallocate a buffer of memory with the given size and alignment.
+///
+/// If supported, this will used the sized delete operator. Also if supported,
+/// this will pass the alignment to the delete operator.
+///
+/// The pointer must have been allocated with the corresponding new operator,
+/// most likely using the above helper.
+inline void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment) {
+  ::operator delete(Ptr
+#ifdef __cpp_sized_deallocation
+                    ,
+                    Size
+#endif
+#ifdef __cpp_aligned_new
+                    ,
+                    std::align_val_t(Alignment)
+#endif
+  );
+}
+
+} // End namespace llvm
+
+#endif // __cplusplus
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/ConvertUTF.h b/binaryen/third_party/llvm-project/include/llvm/Support/ConvertUTF.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/ConvertUTF.h
@@ -0,0 +1,306 @@
+/*===--- ConvertUTF.h - Universal Character Names conversions ---------------===
+ *
+ * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+ * See https://llvm.org/LICENSE.txt for license information.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ *
+ *==------------------------------------------------------------------------==*/
+/*
+ * Copyright 2001-2004 Unicode, Inc.
+ *
+ * Disclaimer
+ *
+ * This source code is provided as is by Unicode, Inc. No claims are
+ * made as to fitness for any particular purpose. No warranties of any
+ * kind are expressed or implied. The recipient agrees to determine
+ * applicability of information provided. If this file has been
+ * purchased on magnetic or optical media from Unicode, Inc., the
+ * sole remedy for any claim will be exchange of defective media
+ * within 90 days of receipt.
+ *
+ * Limitations on Rights to Redistribute This Code
+ *
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+
+/* ---------------------------------------------------------------------
+
+    Conversions between UTF32, UTF-16, and UTF-8.  Header file.
+
+    Several funtions are included here, forming a complete set of
+    conversions between the three formats.  UTF-7 is not included
+    here, but is handled in a separate source file.
+
+    Each of these routines takes pointers to input buffers and output
+    buffers.  The input buffers are const.
+
+    Each routine converts the text between *sourceStart and sourceEnd,
+    putting the result into the buffer between *targetStart and
+    targetEnd. Note: the end pointers are *after* the last item: e.g.
+    *(sourceEnd - 1) is the last item.
+
+    The return result indicates whether the conversion was successful,
+    and if not, whether the problem was in the source or target buffers.
+    (Only the first encountered problem is indicated.)
+
+    After the conversion, *sourceStart and *targetStart are both
+    updated to point to the end of last text successfully converted in
+    the respective buffers.
+
+    Input parameters:
+        sourceStart - pointer to a pointer to the source buffer.
+                The contents of this are modified on return so that
+                it points at the next thing to be converted.
+        targetStart - similarly, pointer to pointer to the target buffer.
+        sourceEnd, targetEnd - respectively pointers to the ends of the
+                two buffers, for overflow checking only.
+
+    These conversion functions take a ConversionFlags argument. When this
+    flag is set to strict, both irregular sequences and isolated surrogates
+    will cause an error.  When the flag is set to lenient, both irregular
+    sequences and isolated surrogates are converted.
+
+    Whether the flag is strict or lenient, all illegal sequences will cause
+    an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
+    or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
+    must check for illegal sequences.
+
+    When the flag is set to lenient, characters over 0x10FFFF are converted
+    to the replacement character; otherwise (when the flag is set to strict)
+    they constitute an error.
+
+    Output parameters:
+        The value "sourceIllegal" is returned from some routines if the input
+        sequence is malformed.  When "sourceIllegal" is returned, the source
+        value will point to the illegal value that caused the problem. E.g.,
+        in UTF-8 when a sequence is malformed, it points to the start of the
+        malformed sequence.
+
+    Author: Mark E. Davis, 1994.
+    Rev History: Rick McGowan, fixes & updates May 2001.
+         Fixes & updates, Sept 2001.
+
+------------------------------------------------------------------------ */
+
+#ifndef LLVM_SUPPORT_CONVERTUTF_H
+#define LLVM_SUPPORT_CONVERTUTF_H
+
+#include <cstddef>
+#include <string>
+#include <system_error>
+
+// Wrap everything in namespace llvm so that programs can link with llvm and
+// their own version of the unicode libraries.
+
+namespace llvm {
+
+/* ---------------------------------------------------------------------
+    The following 4 definitions are compiler-specific.
+    The C standard does not guarantee that wchar_t has at least
+    16 bits, so wchar_t is no less portable than unsigned short!
+    All should be unsigned values to avoid sign extension during
+    bit mask & shift operations.
+------------------------------------------------------------------------ */
+
+typedef unsigned int    UTF32;  /* at least 32 bits */
+typedef unsigned short  UTF16;  /* at least 16 bits */
+typedef unsigned char   UTF8;   /* typically 8 bits */
+typedef unsigned char   Boolean; /* 0 or 1 */
+
+/* Some fundamental constants */
+#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
+#define UNI_MAX_BMP (UTF32)0x0000FFFF
+#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
+#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
+#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
+
+#define UNI_MAX_UTF8_BYTES_PER_CODE_POINT 4
+
+#define UNI_UTF16_BYTE_ORDER_MARK_NATIVE  0xFEFF
+#define UNI_UTF16_BYTE_ORDER_MARK_SWAPPED 0xFFFE
+
+typedef enum {
+  conversionOK,           /* conversion successful */
+  sourceExhausted,        /* partial character in source, but hit end */
+  targetExhausted,        /* insuff. room in target for conversion */
+  sourceIllegal           /* source sequence is illegal/malformed */
+} ConversionResult;
+
+typedef enum {
+  strictConversion = 0,
+  lenientConversion
+} ConversionFlags;
+
+ConversionResult ConvertUTF8toUTF16 (
+  const UTF8** sourceStart, const UTF8* sourceEnd,
+  UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
+
+/**
+ * Convert a partial UTF8 sequence to UTF32.  If the sequence ends in an
+ * incomplete code unit sequence, returns \c sourceExhausted.
+ */
+ConversionResult ConvertUTF8toUTF32Partial(
+  const UTF8** sourceStart, const UTF8* sourceEnd,
+  UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
+
+/**
+ * Convert a partial UTF8 sequence to UTF32.  If the sequence ends in an
+ * incomplete code unit sequence, returns \c sourceIllegal.
+ */
+ConversionResult ConvertUTF8toUTF32(
+  const UTF8** sourceStart, const UTF8* sourceEnd,
+  UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF16toUTF8 (
+  const UTF16** sourceStart, const UTF16* sourceEnd,
+  UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF32toUTF8 (
+  const UTF32** sourceStart, const UTF32* sourceEnd,
+  UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF16toUTF32 (
+  const UTF16** sourceStart, const UTF16* sourceEnd,
+  UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF32toUTF16 (
+  const UTF32** sourceStart, const UTF32* sourceEnd,
+  UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
+
+Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
+
+Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd);
+
+unsigned getNumBytesForUTF8(UTF8 firstByte);
+
+/*************************************************************************/
+/* Below are LLVM-specific wrappers of the functions above. */
+
+template <typename T> class ArrayRef;
+template <typename T> class SmallVectorImpl;
+class StringRef;
+
+/**
+ * Convert an UTF8 StringRef to UTF8, UTF16, or UTF32 depending on
+ * WideCharWidth. The converted data is written to ResultPtr, which needs to
+ * point to at least WideCharWidth * (Source.Size() + 1) bytes. On success,
+ * ResultPtr will point one after the end of the copied string. On failure,
+ * ResultPtr will not be changed, and ErrorPtr will be set to the location of
+ * the first character which could not be converted.
+ * \return true on success.
+ */
+bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
+                       char *&ResultPtr, const UTF8 *&ErrorPtr);
+
+/**
+* Converts a UTF-8 StringRef to a std::wstring.
+* \return true on success.
+*/
+bool ConvertUTF8toWide(llvm::StringRef Source, std::wstring &Result);
+
+/**
+* Converts a UTF-8 C-string to a std::wstring.
+* \return true on success.
+*/
+bool ConvertUTF8toWide(const char *Source, std::wstring &Result);
+
+/**
+* Converts a std::wstring to a UTF-8 encoded std::string.
+* \return true on success.
+*/
+bool convertWideToUTF8(const std::wstring &Source, std::string &Result);
+
+
+/**
+ * Convert an Unicode code point to UTF8 sequence.
+ *
+ * \param Source a Unicode code point.
+ * \param [in,out] ResultPtr pointer to the output buffer, needs to be at least
+ * \c UNI_MAX_UTF8_BYTES_PER_CODE_POINT bytes.  On success \c ResultPtr is
+ * updated one past end of the converted sequence.
+ *
+ * \returns true on success.
+ */
+bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr);
+
+/**
+ * Convert the first UTF8 sequence in the given source buffer to a UTF32
+ * code point.
+ *
+ * \param [in,out] source A pointer to the source buffer. If the conversion
+ * succeeds, this pointer will be updated to point to the byte just past the
+ * end of the converted sequence.
+ * \param sourceEnd A pointer just past the end of the source buffer.
+ * \param [out] target The converted code
+ * \param flags Whether the conversion is strict or lenient.
+ *
+ * \returns conversionOK on success
+ *
+ * \sa ConvertUTF8toUTF32
+ */
+inline ConversionResult convertUTF8Sequence(const UTF8 **source,
+                                            const UTF8 *sourceEnd,
+                                            UTF32 *target,
+                                            ConversionFlags flags) {
+  if (*source == sourceEnd)
+    return sourceExhausted;
+  unsigned size = getNumBytesForUTF8(**source);
+  if ((ptrdiff_t)size > sourceEnd - *source)
+    return sourceExhausted;
+  return ConvertUTF8toUTF32(source, *source + size, &target, target + 1, flags);
+}
+
+/**
+ * Returns true if a blob of text starts with a UTF-16 big or little endian byte
+ * order mark.
+ */
+bool hasUTF16ByteOrderMark(ArrayRef<char> SrcBytes);
+
+/**
+ * Converts a stream of raw bytes assumed to be UTF16 into a UTF8 std::string.
+ *
+ * \param [in] SrcBytes A buffer of what is assumed to be UTF-16 encoded text.
+ * \param [out] Out Converted UTF-8 is stored here on success.
+ * \returns true on success
+ */
+bool convertUTF16ToUTF8String(ArrayRef<char> SrcBytes, std::string &Out);
+
+/**
+* Converts a UTF16 string into a UTF8 std::string.
+*
+* \param [in] Src A buffer of UTF-16 encoded text.
+* \param [out] Out Converted UTF-8 is stored here on success.
+* \returns true on success
+*/
+bool convertUTF16ToUTF8String(ArrayRef<UTF16> Src, std::string &Out);
+
+/**
+ * Converts a UTF-8 string into a UTF-16 string with native endianness.
+ *
+ * \returns true on success
+ */
+bool convertUTF8ToUTF16String(StringRef SrcUTF8,
+                              SmallVectorImpl<UTF16> &DstUTF16);
+
+#if defined(_WIN32)
+namespace sys {
+namespace windows {
+std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
+/// Convert to UTF16 from the current code page used in the system
+std::error_code CurCPToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
+std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
+                            SmallVectorImpl<char> &utf8);
+/// Convert from UTF16 to the current code page used in the system
+std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
+                             SmallVectorImpl<char> &utf8);
+} // namespace windows
+} // namespace sys
+#endif
+
+} /* end namespace llvm */
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/DJB.h b/binaryen/third_party/llvm-project/include/llvm/Support/DJB.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/DJB.h
@@ -0,0 +1,32 @@
+//===-- llvm/Support/DJB.h ---DJB Hash --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains support for the DJ Bernstein hash function.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DJB_H
+#define LLVM_SUPPORT_DJB_H
+
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+
+/// The Bernstein hash function used by the DWARF accelerator tables.
+inline uint32_t djbHash(StringRef Buffer, uint32_t H = 5381) {
+  for (unsigned char C : Buffer.bytes())
+    H = (H << 5) + H + C;
+  return H;
+}
+
+/// Computes the Bernstein hash after folding the input according to the Dwarf 5
+/// standard case folding rules.
+uint32_t caseFoldingDjbHash(StringRef Buffer, uint32_t H = 5381);
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_DJB_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/DataExtractor.h b/binaryen/third_party/llvm-project/include/llvm/Support/DataExtractor.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/DataExtractor.h
@@ -0,0 +1,575 @@
+//===-- DataExtractor.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DATAEXTRACTOR_H
+#define LLVM_SUPPORT_DATAEXTRACTOR_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+
+/// An auxiliary type to facilitate extraction of 3-byte entities.
+struct Uint24 {
+  uint8_t Bytes[3];
+  Uint24(uint8_t U) {
+    Bytes[0] = Bytes[1] = Bytes[2] = U;
+  }
+  Uint24(uint8_t U0, uint8_t U1, uint8_t U2) {
+    Bytes[0] = U0; Bytes[1] = U1; Bytes[2] = U2;
+  }
+  uint32_t getAsUint32(bool IsLittleEndian) const {
+    int LoIx = IsLittleEndian ? 0 : 2;
+    return Bytes[LoIx] + (Bytes[1] << 8) + (Bytes[2-LoIx] << 16);
+  }
+};
+
+using uint24_t = Uint24;
+static_assert(sizeof(uint24_t) == 3, "sizeof(uint24_t) != 3");
+
+/// Needed by swapByteOrder().
+inline uint24_t getSwappedBytes(uint24_t C) {
+  return uint24_t(C.Bytes[2], C.Bytes[1], C.Bytes[0]);
+}
+
+class DataExtractor {
+  StringRef Data;
+  uint8_t IsLittleEndian;
+  uint8_t AddressSize;
+public:
+  /// A class representing a position in a DataExtractor, as well as any error
+  /// encountered during extraction. It enables one to extract a sequence of
+  /// values without error-checking and then checking for errors in bulk at the
+  /// end. The class holds an Error object, so failing to check the result of
+  /// the parse will result in a runtime error. The error flag is sticky and
+  /// will cause all subsequent extraction functions to fail without even
+  /// attempting to parse and without updating the Cursor offset. After clearing
+  /// the error flag, one can again use the Cursor object for parsing.
+  class Cursor {
+    uint64_t Offset;
+    Error Err;
+
+    friend class DataExtractor;
+
+  public:
+    /// Construct a cursor for extraction from the given offset.
+    explicit Cursor(uint64_t Offset) : Offset(Offset), Err(Error::success()) {}
+
+    /// Checks whether the cursor is valid (i.e. no errors were encountered). In
+    /// case of errors, this does not clear the error flag -- one must call
+    /// takeError() instead.
+    explicit operator bool() { return !Err; }
+
+    /// Return the current position of this Cursor. In the error state this is
+    /// the position of the Cursor before the first error was encountered.
+    uint64_t tell() const { return Offset; }
+
+    /// Return error contained inside this Cursor, if any. Clears the internal
+    /// Cursor state.
+    Error takeError() { return std::move(Err); }
+  };
+
+  /// Construct with a buffer that is owned by the caller.
+  ///
+  /// This constructor allows us to use data that is owned by the
+  /// caller. The data must stay around as long as this object is
+  /// valid.
+  DataExtractor(StringRef Data, bool IsLittleEndian, uint8_t AddressSize)
+    : Data(Data), IsLittleEndian(IsLittleEndian), AddressSize(AddressSize) {}
+  DataExtractor(ArrayRef<uint8_t> Data, bool IsLittleEndian,
+                uint8_t AddressSize)
+      : Data(StringRef(reinterpret_cast<const char *>(Data.data()),
+                       Data.size())),
+        IsLittleEndian(IsLittleEndian), AddressSize(AddressSize) {}
+
+  /// Get the data pointed to by this extractor.
+  StringRef getData() const { return Data; }
+  /// Get the endianness for this extractor.
+  bool isLittleEndian() const { return IsLittleEndian; }
+  /// Get the address size for this extractor.
+  uint8_t getAddressSize() const { return AddressSize; }
+  /// Set the address size for this extractor.
+  void setAddressSize(uint8_t Size) { AddressSize = Size; }
+
+  /// Extract a C string from \a *offset_ptr.
+  ///
+  /// Returns a pointer to a C String from the data at the offset
+  /// pointed to by \a offset_ptr. A variable length NULL terminated C
+  /// string will be extracted and the \a offset_ptr will be
+  /// updated with the offset of the byte that follows the NULL
+  /// terminator byte.
+  ///
+  /// @param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the appropriate number of bytes if the value is extracted
+  ///     correctly. If the offset is out of bounds or there are not
+  ///     enough bytes to extract this value, the offset will be left
+  ///     unmodified.
+  ///
+  /// @return
+  ///     A pointer to the C string value in the data. If the offset
+  ///     pointed to by \a offset_ptr is out of bounds, or if the
+  ///     offset plus the length of the C string is out of bounds,
+  ///     NULL will be returned.
+  const char *getCStr(uint64_t *offset_ptr) const;
+
+  /// Extract a C string from \a *offset_ptr.
+  ///
+  /// Returns a StringRef for the C String from the data at the offset
+  /// pointed to by \a offset_ptr. A variable length NULL terminated C
+  /// string will be extracted and the \a offset_ptr will be
+  /// updated with the offset of the byte that follows the NULL
+  /// terminator byte.
+  ///
+  /// \param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the appropriate number of bytes if the value is extracted
+  ///     correctly. If the offset is out of bounds or there are not
+  ///     enough bytes to extract this value, the offset will be left
+  ///     unmodified.
+  ///
+  /// \return
+  ///     A StringRef for the C string value in the data. If the offset
+  ///     pointed to by \a offset_ptr is out of bounds, or if the
+  ///     offset plus the length of the C string is out of bounds,
+  ///     a default-initialized StringRef will be returned.
+  StringRef getCStrRef(uint64_t *offset_ptr) const;
+
+  /// Extract an unsigned integer of size \a byte_size from \a
+  /// *offset_ptr.
+  ///
+  /// Extract a single unsigned integer value and update the offset
+  /// pointed to by \a offset_ptr. The size of the extracted integer
+  /// is specified by the \a byte_size argument. \a byte_size should
+  /// have a value greater than or equal to one and less than or equal
+  /// to eight since the return value is 64 bits wide. Any
+  /// \a byte_size values less than 1 or greater than 8 will result in
+  /// nothing being extracted, and zero being returned.
+  ///
+  /// @param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the appropriate number of bytes if the value is extracted
+  ///     correctly. If the offset is out of bounds or there are not
+  ///     enough bytes to extract this value, the offset will be left
+  ///     unmodified.
+  ///
+  /// @param[in] byte_size
+  ///     The size in byte of the integer to extract.
+  ///
+  /// @param[in,out] Err
+  ///     A pointer to an Error object. Upon return the Error object is set to
+  ///     indicate the result (success/failure) of the function. If the Error
+  ///     object is already set when calling this function, no extraction is
+  ///     performed.
+  ///
+  /// @return
+  ///     The unsigned integer value that was extracted, or zero on
+  ///     failure.
+  uint64_t getUnsigned(uint64_t *offset_ptr, uint32_t byte_size,
+                       Error *Err = nullptr) const;
+
+  /// Extract an unsigned integer of the given size from the location given by
+  /// the cursor. In case of an extraction error, or if the cursor is already in
+  /// an error state, zero is returned.
+  uint64_t getUnsigned(Cursor &C, uint32_t Size) const {
+    return getUnsigned(&C.Offset, Size, &C.Err);
+  }
+
+  /// Extract an signed integer of size \a byte_size from \a *offset_ptr.
+  ///
+  /// Extract a single signed integer value (sign extending if required)
+  /// and update the offset pointed to by \a offset_ptr. The size of
+  /// the extracted integer is specified by the \a byte_size argument.
+  /// \a byte_size should have a value greater than or equal to one
+  /// and less than or equal to eight since the return value is 64
+  /// bits wide. Any \a byte_size values less than 1 or greater than
+  /// 8 will result in nothing being extracted, and zero being returned.
+  ///
+  /// @param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the appropriate number of bytes if the value is extracted
+  ///     correctly. If the offset is out of bounds or there are not
+  ///     enough bytes to extract this value, the offset will be left
+  ///     unmodified.
+  ///
+  /// @param[in] size
+  ///     The size in bytes of the integer to extract.
+  ///
+  /// @return
+  ///     The sign extended signed integer value that was extracted,
+  ///     or zero on failure.
+  int64_t getSigned(uint64_t *offset_ptr, uint32_t size) const;
+
+  //------------------------------------------------------------------
+  /// Extract an pointer from \a *offset_ptr.
+  ///
+  /// Extract a single pointer from the data and update the offset
+  /// pointed to by \a offset_ptr. The size of the extracted pointer
+  /// is \a getAddressSize(), so the address size has to be
+  /// set correctly prior to extracting any pointer values.
+  ///
+  /// @param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the appropriate number of bytes if the value is extracted
+  ///     correctly. If the offset is out of bounds or there are not
+  ///     enough bytes to extract this value, the offset will be left
+  ///     unmodified.
+  ///
+  /// @return
+  ///     The extracted pointer value as a 64 integer.
+  uint64_t getAddress(uint64_t *offset_ptr) const {
+    return getUnsigned(offset_ptr, AddressSize);
+  }
+
+  /// Extract a pointer-sized unsigned integer from the location given by the
+  /// cursor. In case of an extraction error, or if the cursor is already in
+  /// an error state, zero is returned.
+  uint64_t getAddress(Cursor &C) const { return getUnsigned(C, AddressSize); }
+
+  /// Extract a uint8_t value from \a *offset_ptr.
+  ///
+  /// Extract a single uint8_t from the binary data at the offset
+  /// pointed to by \a offset_ptr, and advance the offset on success.
+  ///
+  /// @param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the appropriate number of bytes if the value is extracted
+  ///     correctly. If the offset is out of bounds or there are not
+  ///     enough bytes to extract this value, the offset will be left
+  ///     unmodified.
+  ///
+  /// @param[in,out] Err
+  ///     A pointer to an Error object. Upon return the Error object is set to
+  ///     indicate the result (success/failure) of the function. If the Error
+  ///     object is already set when calling this function, no extraction is
+  ///     performed.
+  ///
+  /// @return
+  ///     The extracted uint8_t value.
+  uint8_t getU8(uint64_t *offset_ptr, Error *Err = nullptr) const;
+
+  /// Extract a single uint8_t value from the location given by the cursor. In
+  /// case of an extraction error, or if the cursor is already in an error
+  /// state, zero is returned.
+  uint8_t getU8(Cursor &C) const { return getU8(&C.Offset, &C.Err); }
+
+  /// Extract \a count uint8_t values from \a *offset_ptr.
+  ///
+  /// Extract \a count uint8_t values from the binary data at the
+  /// offset pointed to by \a offset_ptr, and advance the offset on
+  /// success. The extracted values are copied into \a dst.
+  ///
+  /// @param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the appropriate number of bytes if the value is extracted
+  ///     correctly. If the offset is out of bounds or there are not
+  ///     enough bytes to extract this value, the offset will be left
+  ///     unmodified.
+  ///
+  /// @param[out] dst
+  ///     A buffer to copy \a count uint8_t values into. \a dst must
+  ///     be large enough to hold all requested data.
+  ///
+  /// @param[in] count
+  ///     The number of uint8_t values to extract.
+  ///
+  /// @return
+  ///     \a dst if all values were properly extracted and copied,
+  ///     NULL otherise.
+  uint8_t *getU8(uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const;
+
+  /// Extract \a Count uint8_t values from the location given by the cursor and
+  /// store them into the destination buffer. In case of an extraction error, or
+  /// if the cursor is already in an error state, a nullptr is returned and the
+  /// destination buffer is left unchanged.
+  uint8_t *getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const;
+
+  /// Extract \a Count uint8_t values from the location given by the cursor and
+  /// store them into the destination vector. The vector is resized to fit the
+  /// extracted data. In case of an extraction error, or if the cursor is
+  /// already in an error state, the destination vector is left unchanged and
+  /// cursor is placed into an error state.
+  void getU8(Cursor &C, SmallVectorImpl<uint8_t> &Dst, uint32_t Count) const {
+    if (isValidOffsetForDataOfSize(C.Offset, Count))
+      Dst.resize(Count);
+
+    // This relies on the fact that getU8 will not attempt to write to the
+    // buffer if isValidOffsetForDataOfSize(C.Offset, Count) is false.
+    getU8(C, Dst.data(), Count);
+  }
+
+  //------------------------------------------------------------------
+  /// Extract a uint16_t value from \a *offset_ptr.
+  ///
+  /// Extract a single uint16_t from the binary data at the offset
+  /// pointed to by \a offset_ptr, and update the offset on success.
+  ///
+  /// @param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the appropriate number of bytes if the value is extracted
+  ///     correctly. If the offset is out of bounds or there are not
+  ///     enough bytes to extract this value, the offset will be left
+  ///     unmodified.
+  ///
+  /// @param[in,out] Err
+  ///     A pointer to an Error object. Upon return the Error object is set to
+  ///     indicate the result (success/failure) of the function. If the Error
+  ///     object is already set when calling this function, no extraction is
+  ///     performed.
+  ///
+  /// @return
+  ///     The extracted uint16_t value.
+  //------------------------------------------------------------------
+  uint16_t getU16(uint64_t *offset_ptr, Error *Err = nullptr) const;
+
+  /// Extract a single uint16_t value from the location given by the cursor. In
+  /// case of an extraction error, or if the cursor is already in an error
+  /// state, zero is returned.
+  uint16_t getU16(Cursor &C) const { return getU16(&C.Offset, &C.Err); }
+
+  /// Extract \a count uint16_t values from \a *offset_ptr.
+  ///
+  /// Extract \a count uint16_t values from the binary data at the
+  /// offset pointed to by \a offset_ptr, and advance the offset on
+  /// success. The extracted values are copied into \a dst.
+  ///
+  /// @param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the appropriate number of bytes if the value is extracted
+  ///     correctly. If the offset is out of bounds or there are not
+  ///     enough bytes to extract this value, the offset will be left
+  ///     unmodified.
+  ///
+  /// @param[out] dst
+  ///     A buffer to copy \a count uint16_t values into. \a dst must
+  ///     be large enough to hold all requested data.
+  ///
+  /// @param[in] count
+  ///     The number of uint16_t values to extract.
+  ///
+  /// @return
+  ///     \a dst if all values were properly extracted and copied,
+  ///     NULL otherise.
+  uint16_t *getU16(uint64_t *offset_ptr, uint16_t *dst, uint32_t count) const;
+
+  /// Extract a 24-bit unsigned value from \a *offset_ptr and return it
+  /// in a uint32_t.
+  ///
+  /// Extract 3 bytes from the binary data at the offset pointed to by
+  /// \a offset_ptr, construct a uint32_t from them and update the offset
+  /// on success.
+  ///
+  /// @param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the 3 bytes if the value is extracted correctly. If the offset
+  ///     is out of bounds or there are not enough bytes to extract this value,
+  ///     the offset will be left unmodified.
+  ///
+  /// @return
+  ///     The extracted 24-bit value represented in a uint32_t.
+  uint32_t getU24(uint64_t *offset_ptr) const;
+
+  /// Extract a uint32_t value from \a *offset_ptr.
+  ///
+  /// Extract a single uint32_t from the binary data at the offset
+  /// pointed to by \a offset_ptr, and update the offset on success.
+  ///
+  /// @param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the appropriate number of bytes if the value is extracted
+  ///     correctly. If the offset is out of bounds or there are not
+  ///     enough bytes to extract this value, the offset will be left
+  ///     unmodified.
+  ///
+  /// @param[in,out] Err
+  ///     A pointer to an Error object. Upon return the Error object is set to
+  ///     indicate the result (success/failure) of the function. If the Error
+  ///     object is already set when calling this function, no extraction is
+  ///     performed.
+  ///
+  /// @return
+  ///     The extracted uint32_t value.
+  uint32_t getU32(uint64_t *offset_ptr, Error *Err = nullptr) const;
+
+  /// Extract a single uint32_t value from the location given by the cursor. In
+  /// case of an extraction error, or if the cursor is already in an error
+  /// state, zero is returned.
+  uint32_t getU32(Cursor &C) const { return getU32(&C.Offset, &C.Err); }
+
+  /// Extract \a count uint32_t values from \a *offset_ptr.
+  ///
+  /// Extract \a count uint32_t values from the binary data at the
+  /// offset pointed to by \a offset_ptr, and advance the offset on
+  /// success. The extracted values are copied into \a dst.
+  ///
+  /// @param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the appropriate number of bytes if the value is extracted
+  ///     correctly. If the offset is out of bounds or there are not
+  ///     enough bytes to extract this value, the offset will be left
+  ///     unmodified.
+  ///
+  /// @param[out] dst
+  ///     A buffer to copy \a count uint32_t values into. \a dst must
+  ///     be large enough to hold all requested data.
+  ///
+  /// @param[in] count
+  ///     The number of uint32_t values to extract.
+  ///
+  /// @return
+  ///     \a dst if all values were properly extracted and copied,
+  ///     NULL otherise.
+  uint32_t *getU32(uint64_t *offset_ptr, uint32_t *dst, uint32_t count) const;
+
+  /// Extract a uint64_t value from \a *offset_ptr.
+  ///
+  /// Extract a single uint64_t from the binary data at the offset
+  /// pointed to by \a offset_ptr, and update the offset on success.
+  ///
+  /// @param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the appropriate number of bytes if the value is extracted
+  ///     correctly. If the offset is out of bounds or there are not
+  ///     enough bytes to extract this value, the offset will be left
+  ///     unmodified.
+  ///
+  /// @param[in,out] Err
+  ///     A pointer to an Error object. Upon return the Error object is set to
+  ///     indicate the result (success/failure) of the function. If the Error
+  ///     object is already set when calling this function, no extraction is
+  ///     performed.
+  ///
+  /// @return
+  ///     The extracted uint64_t value.
+  uint64_t getU64(uint64_t *offset_ptr, Error *Err = nullptr) const;
+
+  /// Extract a single uint64_t value from the location given by the cursor. In
+  /// case of an extraction error, or if the cursor is already in an error
+  /// state, zero is returned.
+  uint64_t getU64(Cursor &C) const { return getU64(&C.Offset, &C.Err); }
+
+  /// Extract \a count uint64_t values from \a *offset_ptr.
+  ///
+  /// Extract \a count uint64_t values from the binary data at the
+  /// offset pointed to by \a offset_ptr, and advance the offset on
+  /// success. The extracted values are copied into \a dst.
+  ///
+  /// @param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the appropriate number of bytes if the value is extracted
+  ///     correctly. If the offset is out of bounds or there are not
+  ///     enough bytes to extract this value, the offset will be left
+  ///     unmodified.
+  ///
+  /// @param[out] dst
+  ///     A buffer to copy \a count uint64_t values into. \a dst must
+  ///     be large enough to hold all requested data.
+  ///
+  /// @param[in] count
+  ///     The number of uint64_t values to extract.
+  ///
+  /// @return
+  ///     \a dst if all values were properly extracted and copied,
+  ///     NULL otherise.
+  uint64_t *getU64(uint64_t *offset_ptr, uint64_t *dst, uint32_t count) const;
+
+  /// Extract a signed LEB128 value from \a *offset_ptr.
+  ///
+  /// Extracts an signed LEB128 number from this object's data
+  /// starting at the offset pointed to by \a offset_ptr. The offset
+  /// pointed to by \a offset_ptr will be updated with the offset of
+  /// the byte following the last extracted byte.
+  ///
+  /// @param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the appropriate number of bytes if the value is extracted
+  ///     correctly. If the offset is out of bounds or there are not
+  ///     enough bytes to extract this value, the offset will be left
+  ///     unmodified.
+  ///
+  /// @return
+  ///     The extracted signed integer value.
+  int64_t getSLEB128(uint64_t *offset_ptr) const;
+
+  /// Extract a unsigned LEB128 value from \a *offset_ptr.
+  ///
+  /// Extracts an unsigned LEB128 number from this object's data
+  /// starting at the offset pointed to by \a offset_ptr. The offset
+  /// pointed to by \a offset_ptr will be updated with the offset of
+  /// the byte following the last extracted byte.
+  ///
+  /// @param[in,out] offset_ptr
+  ///     A pointer to an offset within the data that will be advanced
+  ///     by the appropriate number of bytes if the value is extracted
+  ///     correctly. If the offset is out of bounds or there are not
+  ///     enough bytes to extract this value, the offset will be left
+  ///     unmodified.
+  ///
+  /// @param[in,out] Err
+  ///     A pointer to an Error object. Upon return the Error object is set to
+  ///     indicate the result (success/failure) of the function. If the Error
+  ///     object is already set when calling this function, no extraction is
+  ///     performed.
+  ///
+  /// @return
+  ///     The extracted unsigned integer value.
+  uint64_t getULEB128(uint64_t *offset_ptr, llvm::Error *Err = nullptr) const;
+
+  /// Extract an unsigned ULEB128 value from the location given by the cursor.
+  /// In case of an extraction error, or if the cursor is already in an error
+  /// state, zero is returned.
+  uint64_t getULEB128(Cursor &C) const { return getULEB128(&C.Offset, &C.Err); }
+
+  /// Advance the Cursor position by the given number of bytes. No-op if the
+  /// cursor is in an error state.
+  void skip(Cursor &C, uint64_t Length) const;
+
+  /// Return true iff the cursor is at the end of the buffer, regardless of the
+  /// error state of the cursor. The only way both eof and error states can be
+  /// true is if one attempts a read while the cursor is at the very end of the
+  /// data buffer.
+  bool eof(const Cursor &C) const { return Data.size() == C.Offset; }
+
+  /// Test the validity of \a offset.
+  ///
+  /// @return
+  ///     \b true if \a offset is a valid offset into the data in this
+  ///     object, \b false otherwise.
+  bool isValidOffset(uint64_t offset) const { return Data.size() > offset; }
+
+  /// Test the availability of \a length bytes of data from \a offset.
+  ///
+  /// @return
+  ///     \b true if \a offset is a valid offset and there are \a
+  ///     length bytes available at that offset, \b false otherwise.
+  bool isValidOffsetForDataOfSize(uint64_t offset, uint64_t length) const {
+    return offset + length >= offset && isValidOffset(offset + length - 1);
+  }
+
+  /// Test the availability of enough bytes of data for a pointer from
+  /// \a offset. The size of a pointer is \a getAddressSize().
+  ///
+  /// @return
+  ///     \b true if \a offset is a valid offset and there are enough
+  ///     bytes for a pointer available at that offset, \b false
+  ///     otherwise.
+  bool isValidOffsetForAddress(uint64_t offset) const {
+    return isValidOffsetForDataOfSize(offset, AddressSize);
+  }
+
+protected:
+  // Make it possible for subclasses to access these fields without making them
+  // public.
+  static uint64_t &getOffset(Cursor &C) { return C.Offset; }
+  static Error &getError(Cursor &C) { return C.Err; }
+};
+
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/DataTypes.h b/binaryen/third_party/llvm-project/include/llvm/Support/DataTypes.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/DataTypes.h
@@ -0,0 +1,16 @@
+//===-- llvm/Support/DataTypes.h - Define fixed size types ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Due to layering constraints (Support depends on llvm-c) this is a thin
+// wrapper around the implementation that lives in llvm-c, though most clients
+// can/should think of this as being provided by Support for simplicity (not
+// many clients are aware of their dependency on llvm-c).
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-c/DataTypes.h"
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Debug.h b/binaryen/third_party/llvm-project/include/llvm/Support/Debug.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Debug.h
@@ -0,0 +1,126 @@
+//===- llvm/Support/Debug.h - Easy way to add debug output ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a handy way of adding debugging information to your
+// code, without it being enabled all of the time, and without having to add
+// command line options to enable it.
+//
+// In particular, just wrap your code with the LLVM_DEBUG() macro, and it will
+// be enabled automatically if you specify '-debug' on the command-line.
+// LLVM_DEBUG() requires the DEBUG_TYPE macro to be defined. Set it to "foo"
+// specify that your debug code belongs to class "foo". Be careful that you only
+// do this after including Debug.h and not around any #include of headers.
+// Headers should define and undef the macro acround the code that needs to use
+// the LLVM_DEBUG() macro. Then, on the command line, you can specify
+// '-debug-only=foo' to enable JUST the debug information for the foo class.
+//
+// When compiling without assertions, the -debug-* options and all code in
+// LLVM_DEBUG() statements disappears, so it does not affect the runtime of the
+// code.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DEBUG_H
+#define LLVM_SUPPORT_DEBUG_H
+
+namespace llvm {
+
+class raw_ostream;
+
+#ifndef NDEBUG
+
+/// isCurrentDebugType - Return true if the specified string is the debug type
+/// specified on the command line, or if none was specified on the command line
+/// with the -debug-only=X option.
+///
+bool isCurrentDebugType(const char *Type);
+
+/// setCurrentDebugType - Set the current debug type, as if the -debug-only=X
+/// option were specified.  Note that DebugFlag also needs to be set to true for
+/// debug output to be produced.
+///
+void setCurrentDebugType(const char *Type);
+
+/// setCurrentDebugTypes - Set the current debug type, as if the
+/// -debug-only=X,Y,Z option were specified. Note that DebugFlag
+/// also needs to be set to true for debug output to be produced.
+///
+void setCurrentDebugTypes(const char **Types, unsigned Count);
+
+/// DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug
+/// information.  In the '-debug' option is specified on the commandline, and if
+/// this is a debug build, then the code specified as the option to the macro
+/// will be executed.  Otherwise it will not be.  Example:
+///
+/// DEBUG_WITH_TYPE("bitset", dbgs() << "Bitset contains: " << Bitset << "\n");
+///
+/// This will emit the debug information if -debug is present, and -debug-only
+/// is not specified, or is specified as "bitset".
+#define DEBUG_WITH_TYPE(TYPE, X)                                        \
+  do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType(TYPE)) { X; } \
+  } while (false)
+
+#else
+#define isCurrentDebugType(X) (false)
+#define setCurrentDebugType(X)
+#define setCurrentDebugTypes(X, N)
+#define DEBUG_WITH_TYPE(TYPE, X) do { } while (false)
+#endif
+
+/// This boolean is set to true if the '-debug' command line option
+/// is specified.  This should probably not be referenced directly, instead, use
+/// the DEBUG macro below.
+///
+extern bool DebugFlag;
+
+/// \name Verification flags.
+///
+/// These flags turns on/off that are expensive and are turned off by default,
+/// unless macro EXPENSIVE_CHECKS is defined. The flags allow selectively
+/// turning the checks on without need to recompile.
+/// \{
+
+/// Enables verification of dominator trees.
+///
+extern bool VerifyDomInfo;
+
+/// Enables verification of loop info.
+///
+extern bool VerifyLoopInfo;
+
+/// Enables verification of MemorySSA.
+///
+extern bool VerifyMemorySSA;
+
+///\}
+
+/// EnableDebugBuffering - This defaults to false.  If true, the debug
+/// stream will install signal handlers to dump any buffered debug
+/// output.  It allows clients to selectively allow the debug stream
+/// to install signal handlers if they are certain there will be no
+/// conflict.
+///
+extern bool EnableDebugBuffering;
+
+/// dbgs() - This returns a reference to a raw_ostream for debugging
+/// messages.  If debugging is disabled it returns errs().  Use it
+/// like: dbgs() << "foo" << "bar";
+raw_ostream &dbgs();
+
+// DEBUG macro - This macro should be used by passes to emit debug information.
+// In the '-debug' option is specified on the commandline, and if this is a
+// debug build, then the code specified as the option to the macro will be
+// executed.  Otherwise it will not be.  Example:
+//
+// LLVM_DEBUG(dbgs() << "Bitset contains: " << Bitset << "\n");
+//
+#define LLVM_DEBUG(X) DEBUG_WITH_TYPE(DEBUG_TYPE, X)
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_DEBUG_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Endian.h b/binaryen/third_party/llvm-project/include/llvm/Support/Endian.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Endian.h
@@ -0,0 +1,429 @@
+//===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares generic functions to read and write endian specific data.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ENDIAN_H
+#define LLVM_SUPPORT_ENDIAN_H
+
+#include "llvm/Support/AlignOf.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/SwapByteOrder.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <type_traits>
+
+namespace llvm {
+namespace support {
+
+enum endianness {big, little, native};
+
+// These are named values for common alignments.
+enum {aligned = 0, unaligned = 1};
+
+namespace detail {
+
+/// ::value is either alignment, or alignof(T) if alignment is 0.
+template<class T, int alignment>
+struct PickAlignment {
+ enum { value = alignment == 0 ? alignof(T) : alignment };
+};
+
+} // end namespace detail
+
+namespace endian {
+
+constexpr endianness system_endianness() {
+  return sys::IsBigEndianHost ? big : little;
+}
+
+template <typename value_type>
+inline value_type byte_swap(value_type value, endianness endian) {
+  if ((endian != native) && (endian != system_endianness()))
+    sys::swapByteOrder(value);
+  return value;
+}
+
+/// Swap the bytes of value to match the given endianness.
+template<typename value_type, endianness endian>
+inline value_type byte_swap(value_type value) {
+  return byte_swap(value, endian);
+}
+
+/// Read a value of a particular endianness from memory.
+template <typename value_type, std::size_t alignment>
+inline value_type read(const void *memory, endianness endian) {
+  value_type ret;
+
+  memcpy(&ret,
+         LLVM_ASSUME_ALIGNED(
+             memory, (detail::PickAlignment<value_type, alignment>::value)),
+         sizeof(value_type));
+  return byte_swap<value_type>(ret, endian);
+}
+
+template<typename value_type,
+         endianness endian,
+         std::size_t alignment>
+inline value_type read(const void *memory) {
+  return read<value_type, alignment>(memory, endian);
+}
+
+/// Read a value of a particular endianness from a buffer, and increment the
+/// buffer past that value.
+template <typename value_type, std::size_t alignment, typename CharT>
+inline value_type readNext(const CharT *&memory, endianness endian) {
+  value_type ret = read<value_type, alignment>(memory, endian);
+  memory += sizeof(value_type);
+  return ret;
+}
+
+template<typename value_type, endianness endian, std::size_t alignment,
+         typename CharT>
+inline value_type readNext(const CharT *&memory) {
+  return readNext<value_type, alignment, CharT>(memory, endian);
+}
+
+/// Write a value to memory with a particular endianness.
+template <typename value_type, std::size_t alignment>
+inline void write(void *memory, value_type value, endianness endian) {
+  value = byte_swap<value_type>(value, endian);
+  memcpy(LLVM_ASSUME_ALIGNED(
+             memory, (detail::PickAlignment<value_type, alignment>::value)),
+         &value, sizeof(value_type));
+}
+
+template<typename value_type,
+         endianness endian,
+         std::size_t alignment>
+inline void write(void *memory, value_type value) {
+  write<value_type, alignment>(memory, value, endian);
+}
+
+template <typename value_type>
+using make_unsigned_t = typename std::make_unsigned<value_type>::type;
+
+/// Read a value of a particular endianness from memory, for a location
+/// that starts at the given bit offset within the first byte.
+template <typename value_type, endianness endian, std::size_t alignment>
+inline value_type readAtBitAlignment(const void *memory, uint64_t startBit) {
+  assert(startBit < 8);
+  if (startBit == 0)
+    return read<value_type, endian, alignment>(memory);
+  else {
+    // Read two values and compose the result from them.
+    value_type val[2];
+    memcpy(&val[0],
+           LLVM_ASSUME_ALIGNED(
+               memory, (detail::PickAlignment<value_type, alignment>::value)),
+           sizeof(value_type) * 2);
+    val[0] = byte_swap<value_type, endian>(val[0]);
+    val[1] = byte_swap<value_type, endian>(val[1]);
+
+    // Shift bits from the lower value into place.
+    make_unsigned_t<value_type> lowerVal = val[0] >> startBit;
+    // Mask off upper bits after right shift in case of signed type.
+    make_unsigned_t<value_type> numBitsFirstVal =
+        (sizeof(value_type) * 8) - startBit;
+    lowerVal &= ((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1;
+
+    // Get the bits from the upper value.
+    make_unsigned_t<value_type> upperVal =
+        val[1] & (((make_unsigned_t<value_type>)1 << startBit) - 1);
+    // Shift them in to place.
+    upperVal <<= numBitsFirstVal;
+
+    return lowerVal | upperVal;
+  }
+}
+
+/// Write a value to memory with a particular endianness, for a location
+/// that starts at the given bit offset within the first byte.
+template <typename value_type, endianness endian, std::size_t alignment>
+inline void writeAtBitAlignment(void *memory, value_type value,
+                                uint64_t startBit) {
+  assert(startBit < 8);
+  if (startBit == 0)
+    write<value_type, endian, alignment>(memory, value);
+  else {
+    // Read two values and shift the result into them.
+    value_type val[2];
+    memcpy(&val[0],
+           LLVM_ASSUME_ALIGNED(
+               memory, (detail::PickAlignment<value_type, alignment>::value)),
+           sizeof(value_type) * 2);
+    val[0] = byte_swap<value_type, endian>(val[0]);
+    val[1] = byte_swap<value_type, endian>(val[1]);
+
+    // Mask off any existing bits in the upper part of the lower value that
+    // we want to replace.
+    val[0] &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
+    make_unsigned_t<value_type> numBitsFirstVal =
+        (sizeof(value_type) * 8) - startBit;
+    make_unsigned_t<value_type> lowerVal = value;
+    if (startBit > 0) {
+      // Mask off the upper bits in the new value that are not going to go into
+      // the lower value. This avoids a left shift of a negative value, which
+      // is undefined behavior.
+      lowerVal &= (((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1);
+      // Now shift the new bits into place
+      lowerVal <<= startBit;
+    }
+    val[0] |= lowerVal;
+
+    // Mask off any existing bits in the lower part of the upper value that
+    // we want to replace.
+    val[1] &= ~(((make_unsigned_t<value_type>)1 << startBit) - 1);
+    // Next shift the bits that go into the upper value into position.
+    make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal;
+    // Mask off upper bits after right shift in case of signed type.
+    upperVal &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
+    val[1] |= upperVal;
+
+    // Finally, rewrite values.
+    val[0] = byte_swap<value_type, endian>(val[0]);
+    val[1] = byte_swap<value_type, endian>(val[1]);
+    memcpy(LLVM_ASSUME_ALIGNED(
+               memory, (detail::PickAlignment<value_type, alignment>::value)),
+           &val[0], sizeof(value_type) * 2);
+  }
+}
+
+} // end namespace endian
+
+namespace detail {
+
+template <typename ValueType, endianness Endian, std::size_t Alignment,
+          std::size_t ALIGN = PickAlignment<ValueType, Alignment>::value>
+struct packed_endian_specific_integral {
+  using value_type = ValueType;
+  static constexpr endianness endian = Endian;
+  static constexpr std::size_t alignment = Alignment;
+
+  packed_endian_specific_integral() = default;
+
+  explicit packed_endian_specific_integral(value_type val) { *this = val; }
+
+  operator value_type() const {
+    return endian::read<value_type, endian, alignment>(
+      (const void*)Value.buffer);
+  }
+
+  void operator=(value_type newValue) {
+    endian::write<value_type, endian, alignment>(
+      (void*)Value.buffer, newValue);
+  }
+
+  packed_endian_specific_integral &operator+=(value_type newValue) {
+    *this = *this + newValue;
+    return *this;
+  }
+
+  packed_endian_specific_integral &operator-=(value_type newValue) {
+    *this = *this - newValue;
+    return *this;
+  }
+
+  packed_endian_specific_integral &operator|=(value_type newValue) {
+    *this = *this | newValue;
+    return *this;
+  }
+
+  packed_endian_specific_integral &operator&=(value_type newValue) {
+    *this = *this & newValue;
+    return *this;
+  }
+
+private:
+  struct {
+    alignas(ALIGN) char buffer[sizeof(value_type)];
+  } Value;
+
+public:
+  struct ref {
+    explicit ref(void *Ptr) : Ptr(Ptr) {}
+
+    operator value_type() const {
+      return endian::read<value_type, endian, alignment>(Ptr);
+    }
+
+    void operator=(value_type NewValue) {
+      endian::write<value_type, endian, alignment>(Ptr, NewValue);
+    }
+
+  private:
+    void *Ptr;
+  };
+};
+
+} // end namespace detail
+
+using ulittle16_t =
+    detail::packed_endian_specific_integral<uint16_t, little, unaligned>;
+using ulittle32_t =
+    detail::packed_endian_specific_integral<uint32_t, little, unaligned>;
+using ulittle64_t =
+    detail::packed_endian_specific_integral<uint64_t, little, unaligned>;
+
+using little16_t =
+    detail::packed_endian_specific_integral<int16_t, little, unaligned>;
+using little32_t =
+    detail::packed_endian_specific_integral<int32_t, little, unaligned>;
+using little64_t =
+    detail::packed_endian_specific_integral<int64_t, little, unaligned>;
+
+using aligned_ulittle16_t =
+    detail::packed_endian_specific_integral<uint16_t, little, aligned>;
+using aligned_ulittle32_t =
+    detail::packed_endian_specific_integral<uint32_t, little, aligned>;
+using aligned_ulittle64_t =
+    detail::packed_endian_specific_integral<uint64_t, little, aligned>;
+
+using aligned_little16_t =
+    detail::packed_endian_specific_integral<int16_t, little, aligned>;
+using aligned_little32_t =
+    detail::packed_endian_specific_integral<int32_t, little, aligned>;
+using aligned_little64_t =
+    detail::packed_endian_specific_integral<int64_t, little, aligned>;
+
+using ubig16_t =
+    detail::packed_endian_specific_integral<uint16_t, big, unaligned>;
+using ubig32_t =
+    detail::packed_endian_specific_integral<uint32_t, big, unaligned>;
+using ubig64_t =
+    detail::packed_endian_specific_integral<uint64_t, big, unaligned>;
+
+using big16_t =
+    detail::packed_endian_specific_integral<int16_t, big, unaligned>;
+using big32_t =
+    detail::packed_endian_specific_integral<int32_t, big, unaligned>;
+using big64_t =
+    detail::packed_endian_specific_integral<int64_t, big, unaligned>;
+
+using aligned_ubig16_t =
+    detail::packed_endian_specific_integral<uint16_t, big, aligned>;
+using aligned_ubig32_t =
+    detail::packed_endian_specific_integral<uint32_t, big, aligned>;
+using aligned_ubig64_t =
+    detail::packed_endian_specific_integral<uint64_t, big, aligned>;
+
+using aligned_big16_t =
+    detail::packed_endian_specific_integral<int16_t, big, aligned>;
+using aligned_big32_t =
+    detail::packed_endian_specific_integral<int32_t, big, aligned>;
+using aligned_big64_t =
+    detail::packed_endian_specific_integral<int64_t, big, aligned>;
+
+using unaligned_uint16_t =
+    detail::packed_endian_specific_integral<uint16_t, native, unaligned>;
+using unaligned_uint32_t =
+    detail::packed_endian_specific_integral<uint32_t, native, unaligned>;
+using unaligned_uint64_t =
+    detail::packed_endian_specific_integral<uint64_t, native, unaligned>;
+
+using unaligned_int16_t =
+    detail::packed_endian_specific_integral<int16_t, native, unaligned>;
+using unaligned_int32_t =
+    detail::packed_endian_specific_integral<int32_t, native, unaligned>;
+using unaligned_int64_t =
+    detail::packed_endian_specific_integral<int64_t, native, unaligned>;
+
+template <typename T>
+using little_t = detail::packed_endian_specific_integral<T, little, unaligned>;
+template <typename T>
+using big_t = detail::packed_endian_specific_integral<T, big, unaligned>;
+
+template <typename T>
+using aligned_little_t =
+    detail::packed_endian_specific_integral<T, little, aligned>;
+template <typename T>
+using aligned_big_t = detail::packed_endian_specific_integral<T, big, aligned>;
+
+namespace endian {
+
+template <typename T> inline T read(const void *P, endianness E) {
+  return read<T, unaligned>(P, E);
+}
+
+template <typename T, endianness E> inline T read(const void *P) {
+  return *(const detail::packed_endian_specific_integral<T, E, unaligned> *)P;
+}
+
+inline uint16_t read16(const void *P, endianness E) {
+  return read<uint16_t>(P, E);
+}
+inline uint32_t read32(const void *P, endianness E) {
+  return read<uint32_t>(P, E);
+}
+inline uint64_t read64(const void *P, endianness E) {
+  return read<uint64_t>(P, E);
+}
+
+template <endianness E> inline uint16_t read16(const void *P) {
+  return read<uint16_t, E>(P);
+}
+template <endianness E> inline uint32_t read32(const void *P) {
+  return read<uint32_t, E>(P);
+}
+template <endianness E> inline uint64_t read64(const void *P) {
+  return read<uint64_t, E>(P);
+}
+
+inline uint16_t read16le(const void *P) { return read16<little>(P); }
+inline uint32_t read32le(const void *P) { return read32<little>(P); }
+inline uint64_t read64le(const void *P) { return read64<little>(P); }
+inline uint16_t read16be(const void *P) { return read16<big>(P); }
+inline uint32_t read32be(const void *P) { return read32<big>(P); }
+inline uint64_t read64be(const void *P) { return read64<big>(P); }
+
+template <typename T> inline void write(void *P, T V, endianness E) {
+  write<T, unaligned>(P, V, E);
+}
+
+template <typename T, endianness E> inline void write(void *P, T V) {
+  *(detail::packed_endian_specific_integral<T, E, unaligned> *)P = V;
+}
+
+inline void write16(void *P, uint16_t V, endianness E) {
+  write<uint16_t>(P, V, E);
+}
+inline void write32(void *P, uint32_t V, endianness E) {
+  write<uint32_t>(P, V, E);
+}
+inline void write64(void *P, uint64_t V, endianness E) {
+  write<uint64_t>(P, V, E);
+}
+
+template <endianness E> inline void write16(void *P, uint16_t V) {
+  write<uint16_t, E>(P, V);
+}
+template <endianness E> inline void write32(void *P, uint32_t V) {
+  write<uint32_t, E>(P, V);
+}
+template <endianness E> inline void write64(void *P, uint64_t V) {
+  write<uint64_t, E>(P, V);
+}
+
+inline void write16le(void *P, uint16_t V) { write16<little>(P, V); }
+inline void write32le(void *P, uint32_t V) { write32<little>(P, V); }
+inline void write64le(void *P, uint64_t V) { write64<little>(P, V); }
+inline void write16be(void *P, uint16_t V) { write16<big>(P, V); }
+inline void write32be(void *P, uint32_t V) { write32<big>(P, V); }
+inline void write64be(void *P, uint64_t V) { write64<big>(P, V); }
+
+} // end namespace endian
+
+} // end namespace support
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_ENDIAN_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Errc.h b/binaryen/third_party/llvm-project/include/llvm/Support/Errc.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Errc.h
@@ -0,0 +1,86 @@
+//===- llvm/Support/Errc.h - Defines the llvm::errc enum --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// While std::error_code works OK on all platforms we use, there are some
+// some problems with std::errc that can be avoided by using our own
+// enumeration:
+//
+// * std::errc is a namespace in some implementations. That meas that ADL
+//   doesn't work and it is sometimes necessary to write std::make_error_code
+//   or in templates:
+//   using std::make_error_code;
+//   make_error_code(...);
+//
+//   with this enum it is safe to always just use make_error_code.
+//
+// * Some implementations define fewer names than others. This header has
+//   the intersection of all the ones we support.
+//
+// * std::errc is just marked with is_error_condition_enum. This means that
+//   common patters like AnErrorCode == errc::no_such_file_or_directory take
+//   4 virtual calls instead of two comparisons.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ERRC_H
+#define LLVM_SUPPORT_ERRC_H
+
+#include <system_error>
+
+namespace llvm {
+enum class errc {
+  argument_list_too_long = int(std::errc::argument_list_too_long),
+  argument_out_of_domain = int(std::errc::argument_out_of_domain),
+  bad_address = int(std::errc::bad_address),
+  bad_file_descriptor = int(std::errc::bad_file_descriptor),
+  broken_pipe = int(std::errc::broken_pipe),
+  device_or_resource_busy = int(std::errc::device_or_resource_busy),
+  directory_not_empty = int(std::errc::directory_not_empty),
+  executable_format_error = int(std::errc::executable_format_error),
+  file_exists = int(std::errc::file_exists),
+  file_too_large = int(std::errc::file_too_large),
+  filename_too_long = int(std::errc::filename_too_long),
+  function_not_supported = int(std::errc::function_not_supported),
+  illegal_byte_sequence = int(std::errc::illegal_byte_sequence),
+  inappropriate_io_control_operation =
+      int(std::errc::inappropriate_io_control_operation),
+  interrupted = int(std::errc::interrupted),
+  invalid_argument = int(std::errc::invalid_argument),
+  invalid_seek = int(std::errc::invalid_seek),
+  io_error = int(std::errc::io_error),
+  is_a_directory = int(std::errc::is_a_directory),
+  no_child_process = int(std::errc::no_child_process),
+  no_lock_available = int(std::errc::no_lock_available),
+  no_space_on_device = int(std::errc::no_space_on_device),
+  no_such_device_or_address = int(std::errc::no_such_device_or_address),
+  no_such_device = int(std::errc::no_such_device),
+  no_such_file_or_directory = int(std::errc::no_such_file_or_directory),
+  no_such_process = int(std::errc::no_such_process),
+  not_a_directory = int(std::errc::not_a_directory),
+  not_enough_memory = int(std::errc::not_enough_memory),
+  not_supported = int(std::errc::not_supported),
+  operation_not_permitted = int(std::errc::operation_not_permitted),
+  permission_denied = int(std::errc::permission_denied),
+  read_only_file_system = int(std::errc::read_only_file_system),
+  resource_deadlock_would_occur = int(std::errc::resource_deadlock_would_occur),
+  resource_unavailable_try_again =
+      int(std::errc::resource_unavailable_try_again),
+  result_out_of_range = int(std::errc::result_out_of_range),
+  too_many_files_open_in_system = int(std::errc::too_many_files_open_in_system),
+  too_many_files_open = int(std::errc::too_many_files_open),
+  too_many_links = int(std::errc::too_many_links)
+};
+
+inline std::error_code make_error_code(errc E) {
+  return std::error_code(static_cast<int>(E), std::generic_category());
+}
+}
+
+namespace std {
+template <> struct is_error_code_enum<llvm::errc> : std::true_type {};
+}
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Errno.h b/binaryen/third_party/llvm-project/include/llvm/Support/Errno.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Errno.h
@@ -0,0 +1,46 @@
+//===- llvm/Support/Errno.h - Portable+convenient errno handling -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares some portable and convenient functions to deal with errno.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ERRNO_H
+#define LLVM_SUPPORT_ERRNO_H
+
+#include <cerrno>
+#include <string>
+#include <type_traits>
+
+namespace llvm {
+namespace sys {
+
+/// Returns a string representation of the errno value, using whatever
+/// thread-safe variant of strerror() is available.  Be sure to call this
+/// immediately after the function that set errno, or errno may have been
+/// overwritten by an intervening call.
+std::string StrError();
+
+/// Like the no-argument version above, but uses \p errnum instead of errno.
+std::string StrError(int errnum);
+
+template <typename FailT, typename Fun, typename... Args>
+inline auto RetryAfterSignal(const FailT &Fail, const Fun &F,
+                             const Args &... As) -> decltype(F(As...)) {
+  decltype(F(As...)) Res;
+  do {
+    errno = 0;
+    Res = F(As...);
+  } while (Res == Fail && errno == EINTR);
+  return Res;
+}
+
+}  // namespace sys
+}  // namespace llvm
+
+#endif  // LLVM_SYSTEM_ERRNO_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Error.h b/binaryen/third_party/llvm-project/include/llvm/Support/Error.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Error.h
@@ -0,0 +1,1351 @@
+//===- llvm/Support/Error.h - Recoverable error handling --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines an API used to report recoverable errors.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ERROR_H
+#define LLVM_SUPPORT_ERROR_H
+
+#include "llvm-c/Error.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Config/abi-breaking.h"
+#include "llvm/Support/AlignOf.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <functional>
+#include <memory>
+#include <new>
+#include <string>
+#include <system_error>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+
+class ErrorSuccess;
+
+/// Base class for error info classes. Do not extend this directly: Extend
+/// the ErrorInfo template subclass instead.
+class ErrorInfoBase {
+public:
+  virtual ~ErrorInfoBase() = default;
+
+  /// Print an error message to an output stream.
+  virtual void log(raw_ostream &OS) const = 0;
+
+  /// Return the error message as a string.
+  virtual std::string message() const {
+    std::string Msg;
+    raw_string_ostream OS(Msg);
+    log(OS);
+    return OS.str();
+  }
+
+  /// Convert this error to a std::error_code.
+  ///
+  /// This is a temporary crutch to enable interaction with code still
+  /// using std::error_code. It will be removed in the future.
+  virtual std::error_code convertToErrorCode() const = 0;
+
+  // Returns the class ID for this type.
+  static const void *classID() { return &ID; }
+
+  // Returns the class ID for the dynamic type of this ErrorInfoBase instance.
+  virtual const void *dynamicClassID() const = 0;
+
+  // Check whether this instance is a subclass of the class identified by
+  // ClassID.
+  virtual bool isA(const void *const ClassID) const {
+    return ClassID == classID();
+  }
+
+  // Check whether this instance is a subclass of ErrorInfoT.
+  template <typename ErrorInfoT> bool isA() const {
+    return isA(ErrorInfoT::classID());
+  }
+
+private:
+  virtual void anchor();
+
+  static char ID;
+};
+
+/// Lightweight error class with error context and mandatory checking.
+///
+/// Instances of this class wrap a ErrorInfoBase pointer. Failure states
+/// are represented by setting the pointer to a ErrorInfoBase subclass
+/// instance containing information describing the failure. Success is
+/// represented by a null pointer value.
+///
+/// Instances of Error also contains a 'Checked' flag, which must be set
+/// before the destructor is called, otherwise the destructor will trigger a
+/// runtime error. This enforces at runtime the requirement that all Error
+/// instances be checked or returned to the caller.
+///
+/// There are two ways to set the checked flag, depending on what state the
+/// Error instance is in. For Error instances indicating success, it
+/// is sufficient to invoke the boolean conversion operator. E.g.:
+///
+///   @code{.cpp}
+///   Error foo(<...>);
+///
+///   if (auto E = foo(<...>))
+///     return E; // <- Return E if it is in the error state.
+///   // We have verified that E was in the success state. It can now be safely
+///   // destroyed.
+///   @endcode
+///
+/// A success value *can not* be dropped. For example, just calling 'foo(<...>)'
+/// without testing the return value will raise a runtime error, even if foo
+/// returns success.
+///
+/// For Error instances representing failure, you must use either the
+/// handleErrors or handleAllErrors function with a typed handler. E.g.:
+///
+///   @code{.cpp}
+///   class MyErrorInfo : public ErrorInfo<MyErrorInfo> {
+///     // Custom error info.
+///   };
+///
+///   Error foo(<...>) { return make_error<MyErrorInfo>(...); }
+///
+///   auto E = foo(<...>); // <- foo returns failure with MyErrorInfo.
+///   auto NewE =
+///     handleErrors(E,
+///       [](const MyErrorInfo &M) {
+///         // Deal with the error.
+///       },
+///       [](std::unique_ptr<OtherError> M) -> Error {
+///         if (canHandle(*M)) {
+///           // handle error.
+///           return Error::success();
+///         }
+///         // Couldn't handle this error instance. Pass it up the stack.
+///         return Error(std::move(M));
+///       );
+///   // Note - we must check or return NewE in case any of the handlers
+///   // returned a new error.
+///   @endcode
+///
+/// The handleAllErrors function is identical to handleErrors, except
+/// that it has a void return type, and requires all errors to be handled and
+/// no new errors be returned. It prevents errors (assuming they can all be
+/// handled) from having to be bubbled all the way to the top-level.
+///
+/// *All* Error instances must be checked before destruction, even if
+/// they're moved-assigned or constructed from Success values that have already
+/// been checked. This enforces checking through all levels of the call stack.
+class LLVM_NODISCARD Error {
+  // Both ErrorList and FileError need to be able to yank ErrorInfoBase
+  // pointers out of this class to add to the error list.
+  friend class ErrorList;
+  friend class FileError;
+
+  // handleErrors needs to be able to set the Checked flag.
+  template <typename... HandlerTs>
+  friend Error handleErrors(Error E, HandlerTs &&... Handlers);
+
+  // Expected<T> needs to be able to steal the payload when constructed from an
+  // error.
+  template <typename T> friend class Expected;
+
+  // wrap needs to be able to steal the payload.
+  friend LLVMErrorRef wrap(Error);
+
+protected:
+  /// Create a success value. Prefer using 'Error::success()' for readability
+  Error() {
+    setPtr(nullptr);
+    setChecked(false);
+  }
+
+public:
+  /// Create a success value.
+  static ErrorSuccess success();
+
+  // Errors are not copy-constructable.
+  Error(const Error &Other) = delete;
+
+  /// Move-construct an error value. The newly constructed error is considered
+  /// unchecked, even if the source error had been checked. The original error
+  /// becomes a checked Success value, regardless of its original state.
+  Error(Error &&Other) {
+    setChecked(true);
+    *this = std::move(Other);
+  }
+
+  /// Create an error value. Prefer using the 'make_error' function, but
+  /// this constructor can be useful when "re-throwing" errors from handlers.
+  Error(std::unique_ptr<ErrorInfoBase> Payload) {
+    setPtr(Payload.release());
+    setChecked(false);
+  }
+
+  // Errors are not copy-assignable.
+  Error &operator=(const Error &Other) = delete;
+
+  /// Move-assign an error value. The current error must represent success, you
+  /// you cannot overwrite an unhandled error. The current error is then
+  /// considered unchecked. The source error becomes a checked success value,
+  /// regardless of its original state.
+  Error &operator=(Error &&Other) {
+    // Don't allow overwriting of unchecked values.
+    assertIsChecked();
+    setPtr(Other.getPtr());
+
+    // This Error is unchecked, even if the source error was checked.
+    setChecked(false);
+
+    // Null out Other's payload and set its checked bit.
+    Other.setPtr(nullptr);
+    Other.setChecked(true);
+
+    return *this;
+  }
+
+  /// Destroy a Error. Fails with a call to abort() if the error is
+  /// unchecked.
+  ~Error() {
+    assertIsChecked();
+    delete getPtr();
+  }
+
+  /// Bool conversion. Returns true if this Error is in a failure state,
+  /// and false if it is in an accept state. If the error is in a Success state
+  /// it will be considered checked.
+  explicit operator bool() {
+    setChecked(getPtr() == nullptr);
+    return getPtr() != nullptr;
+  }
+
+  /// Check whether one error is a subclass of another.
+  template <typename ErrT> bool isA() const {
+    return getPtr() && getPtr()->isA(ErrT::classID());
+  }
+
+  /// Returns the dynamic class id of this error, or null if this is a success
+  /// value.
+  const void* dynamicClassID() const {
+    if (!getPtr())
+      return nullptr;
+    return getPtr()->dynamicClassID();
+  }
+
+private:
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+  // assertIsChecked() happens very frequently, but under normal circumstances
+  // is supposed to be a no-op.  So we want it to be inlined, but having a bunch
+  // of debug prints can cause the function to be too large for inlining.  So
+  // it's important that we define this function out of line so that it can't be
+  // inlined.
+  LLVM_ATTRIBUTE_NORETURN
+  void fatalUncheckedError() const;
+#endif
+
+  void assertIsChecked() {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+    if (LLVM_UNLIKELY(!getChecked() || getPtr()))
+      fatalUncheckedError();
+#endif
+  }
+
+  ErrorInfoBase *getPtr() const {
+    return reinterpret_cast<ErrorInfoBase*>(
+             reinterpret_cast<uintptr_t>(Payload) &
+             ~static_cast<uintptr_t>(0x1));
+  }
+
+  void setPtr(ErrorInfoBase *EI) {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+    Payload = reinterpret_cast<ErrorInfoBase*>(
+                (reinterpret_cast<uintptr_t>(EI) &
+                 ~static_cast<uintptr_t>(0x1)) |
+                (reinterpret_cast<uintptr_t>(Payload) & 0x1));
+#else
+    Payload = EI;
+#endif
+  }
+
+  bool getChecked() const {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+    return (reinterpret_cast<uintptr_t>(Payload) & 0x1) == 0;
+#else
+    return true;
+#endif
+  }
+
+  void setChecked(bool V) {
+    Payload = reinterpret_cast<ErrorInfoBase*>(
+                (reinterpret_cast<uintptr_t>(Payload) &
+                  ~static_cast<uintptr_t>(0x1)) |
+                  (V ? 0 : 1));
+  }
+
+  std::unique_ptr<ErrorInfoBase> takePayload() {
+    std::unique_ptr<ErrorInfoBase> Tmp(getPtr());
+    setPtr(nullptr);
+    setChecked(true);
+    return Tmp;
+  }
+
+  friend raw_ostream &operator<<(raw_ostream &OS, const Error &E) {
+    if (auto P = E.getPtr())
+      P->log(OS);
+    else
+      OS << "success";
+    return OS;
+  }
+
+  ErrorInfoBase *Payload = nullptr;
+};
+
+/// Subclass of Error for the sole purpose of identifying the success path in
+/// the type system. This allows to catch invalid conversion to Expected<T> at
+/// compile time.
+class ErrorSuccess final : public Error {};
+
+inline ErrorSuccess Error::success() { return ErrorSuccess(); }
+
+/// Make a Error instance representing failure using the given error info
+/// type.
+template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) {
+  return Error(std::make_unique<ErrT>(std::forward<ArgTs>(Args)...));
+}
+
+/// Base class for user error types. Users should declare their error types
+/// like:
+///
+/// class MyError : public ErrorInfo<MyError> {
+///   ....
+/// };
+///
+/// This class provides an implementation of the ErrorInfoBase::kind
+/// method, which is used by the Error RTTI system.
+template <typename ThisErrT, typename ParentErrT = ErrorInfoBase>
+class ErrorInfo : public ParentErrT {
+public:
+  using ParentErrT::ParentErrT; // inherit constructors
+
+  static const void *classID() { return &ThisErrT::ID; }
+
+  const void *dynamicClassID() const override { return &ThisErrT::ID; }
+
+  bool isA(const void *const ClassID) const override {
+    return ClassID == classID() || ParentErrT::isA(ClassID);
+  }
+};
+
+/// Special ErrorInfo subclass representing a list of ErrorInfos.
+/// Instances of this class are constructed by joinError.
+class ErrorList final : public ErrorInfo<ErrorList> {
+  // handleErrors needs to be able to iterate the payload list of an
+  // ErrorList.
+  template <typename... HandlerTs>
+  friend Error handleErrors(Error E, HandlerTs &&... Handlers);
+
+  // joinErrors is implemented in terms of join.
+  friend Error joinErrors(Error, Error);
+
+public:
+  void log(raw_ostream &OS) const override {
+    OS << "Multiple errors:\n";
+    for (auto &ErrPayload : Payloads) {
+      ErrPayload->log(OS);
+      OS << "\n";
+    }
+  }
+
+  std::error_code convertToErrorCode() const override;
+
+  // Used by ErrorInfo::classID.
+  static char ID;
+
+private:
+  ErrorList(std::unique_ptr<ErrorInfoBase> Payload1,
+            std::unique_ptr<ErrorInfoBase> Payload2) {
+    assert(!Payload1->isA<ErrorList>() && !Payload2->isA<ErrorList>() &&
+           "ErrorList constructor payloads should be singleton errors");
+    Payloads.push_back(std::move(Payload1));
+    Payloads.push_back(std::move(Payload2));
+  }
+
+  static Error join(Error E1, Error E2) {
+    if (!E1)
+      return E2;
+    if (!E2)
+      return E1;
+    if (E1.isA<ErrorList>()) {
+      auto &E1List = static_cast<ErrorList &>(*E1.getPtr());
+      if (E2.isA<ErrorList>()) {
+        auto E2Payload = E2.takePayload();
+        auto &E2List = static_cast<ErrorList &>(*E2Payload);
+        for (auto &Payload : E2List.Payloads)
+          E1List.Payloads.push_back(std::move(Payload));
+      } else
+        E1List.Payloads.push_back(E2.takePayload());
+
+      return E1;
+    }
+    if (E2.isA<ErrorList>()) {
+      auto &E2List = static_cast<ErrorList &>(*E2.getPtr());
+      E2List.Payloads.insert(E2List.Payloads.begin(), E1.takePayload());
+      return E2;
+    }
+    return Error(std::unique_ptr<ErrorList>(
+        new ErrorList(E1.takePayload(), E2.takePayload())));
+  }
+
+  std::vector<std::unique_ptr<ErrorInfoBase>> Payloads;
+};
+
+/// Concatenate errors. The resulting Error is unchecked, and contains the
+/// ErrorInfo(s), if any, contained in E1, followed by the
+/// ErrorInfo(s), if any, contained in E2.
+inline Error joinErrors(Error E1, Error E2) {
+  return ErrorList::join(std::move(E1), std::move(E2));
+}
+
+/// Tagged union holding either a T or a Error.
+///
+/// This class parallels ErrorOr, but replaces error_code with Error. Since
+/// Error cannot be copied, this class replaces getError() with
+/// takeError(). It also adds an bool errorIsA<ErrT>() method for testing the
+/// error class type.
+template <class T> class LLVM_NODISCARD Expected {
+  template <class T1> friend class ExpectedAsOutParameter;
+  template <class OtherT> friend class Expected;
+
+  static const bool isRef = std::is_reference<T>::value;
+
+  using wrap = std::reference_wrapper<typename std::remove_reference<T>::type>;
+
+  using error_type = std::unique_ptr<ErrorInfoBase>;
+
+public:
+  using storage_type = typename std::conditional<isRef, wrap, T>::type;
+  using value_type = T;
+
+private:
+  using reference = typename std::remove_reference<T>::type &;
+  using const_reference = const typename std::remove_reference<T>::type &;
+  using pointer = typename std::remove_reference<T>::type *;
+  using const_pointer = const typename std::remove_reference<T>::type *;
+
+public:
+  /// Create an Expected<T> error value from the given Error.
+  Expected(Error Err)
+      : HasError(true)
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+        // Expected is unchecked upon construction in Debug builds.
+        , Unchecked(true)
+#endif
+  {
+    assert(Err && "Cannot create Expected<T> from Error success value.");
+    new (getErrorStorage()) error_type(Err.takePayload());
+  }
+
+  /// Forbid to convert from Error::success() implicitly, this avoids having
+  /// Expected<T> foo() { return Error::success(); } which compiles otherwise
+  /// but triggers the assertion above.
+  Expected(ErrorSuccess) = delete;
+
+  /// Create an Expected<T> success value from the given OtherT value, which
+  /// must be convertible to T.
+  template <typename OtherT>
+  Expected(OtherT &&Val,
+           typename std::enable_if<std::is_convertible<OtherT, T>::value>::type
+               * = nullptr)
+      : HasError(false)
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+        // Expected is unchecked upon construction in Debug builds.
+        , Unchecked(true)
+#endif
+  {
+    new (getStorage()) storage_type(std::forward<OtherT>(Val));
+  }
+
+  /// Move construct an Expected<T> value.
+  Expected(Expected &&Other) { moveConstruct(std::move(Other)); }
+
+  /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
+  /// must be convertible to T.
+  template <class OtherT>
+  Expected(Expected<OtherT> &&Other,
+           typename std::enable_if<std::is_convertible<OtherT, T>::value>::type
+               * = nullptr) {
+    moveConstruct(std::move(Other));
+  }
+
+  /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
+  /// isn't convertible to T.
+  template <class OtherT>
+  explicit Expected(
+      Expected<OtherT> &&Other,
+      typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * =
+          nullptr) {
+    moveConstruct(std::move(Other));
+  }
+
+  /// Move-assign from another Expected<T>.
+  Expected &operator=(Expected &&Other) {
+    moveAssign(std::move(Other));
+    return *this;
+  }
+
+  /// Destroy an Expected<T>.
+  ~Expected() {
+    assertIsChecked();
+    if (!HasError)
+      getStorage()->~storage_type();
+    else
+      getErrorStorage()->~error_type();
+  }
+
+  /// Return false if there is an error.
+  explicit operator bool() {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+    Unchecked = HasError;
+#endif
+    return !HasError;
+  }
+
+  /// Returns a reference to the stored T value.
+  reference get() {
+    assertIsChecked();
+    return *getStorage();
+  }
+
+  /// Returns a const reference to the stored T value.
+  const_reference get() const {
+    assertIsChecked();
+    return const_cast<Expected<T> *>(this)->get();
+  }
+
+  /// Check that this Expected<T> is an error of type ErrT.
+  template <typename ErrT> bool errorIsA() const {
+    return HasError && (*getErrorStorage())->template isA<ErrT>();
+  }
+
+  /// Take ownership of the stored error.
+  /// After calling this the Expected<T> is in an indeterminate state that can
+  /// only be safely destructed. No further calls (beside the destructor) should
+  /// be made on the Expected<T> value.
+  Error takeError() {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+    Unchecked = false;
+#endif
+    return HasError ? Error(std::move(*getErrorStorage())) : Error::success();
+  }
+
+  /// Returns a pointer to the stored T value.
+  pointer operator->() {
+    assertIsChecked();
+    return toPointer(getStorage());
+  }
+
+  /// Returns a const pointer to the stored T value.
+  const_pointer operator->() const {
+    assertIsChecked();
+    return toPointer(getStorage());
+  }
+
+  /// Returns a reference to the stored T value.
+  reference operator*() {
+    assertIsChecked();
+    return *getStorage();
+  }
+
+  /// Returns a const reference to the stored T value.
+  const_reference operator*() const {
+    assertIsChecked();
+    return *getStorage();
+  }
+
+private:
+  template <class T1>
+  static bool compareThisIfSameType(const T1 &a, const T1 &b) {
+    return &a == &b;
+  }
+
+  template <class T1, class T2>
+  static bool compareThisIfSameType(const T1 &a, const T2 &b) {
+    return false;
+  }
+
+  template <class OtherT> void moveConstruct(Expected<OtherT> &&Other) {
+    HasError = Other.HasError;
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+    Unchecked = true;
+    Other.Unchecked = false;
+#endif
+
+    if (!HasError)
+      new (getStorage()) storage_type(std::move(*Other.getStorage()));
+    else
+      new (getErrorStorage()) error_type(std::move(*Other.getErrorStorage()));
+  }
+
+  template <class OtherT> void moveAssign(Expected<OtherT> &&Other) {
+    assertIsChecked();
+
+    if (compareThisIfSameType(*this, Other))
+      return;
+
+    this->~Expected();
+    new (this) Expected(std::move(Other));
+  }
+
+  pointer toPointer(pointer Val) { return Val; }
+
+  const_pointer toPointer(const_pointer Val) const { return Val; }
+
+  pointer toPointer(wrap *Val) { return &Val->get(); }
+
+  const_pointer toPointer(const wrap *Val) const { return &Val->get(); }
+
+  storage_type *getStorage() {
+    assert(!HasError && "Cannot get value when an error exists!");
+    return reinterpret_cast<storage_type *>(TStorage.buffer);
+  }
+
+  const storage_type *getStorage() const {
+    assert(!HasError && "Cannot get value when an error exists!");
+    return reinterpret_cast<const storage_type *>(TStorage.buffer);
+  }
+
+  error_type *getErrorStorage() {
+    assert(HasError && "Cannot get error when a value exists!");
+    return reinterpret_cast<error_type *>(ErrorStorage.buffer);
+  }
+
+  const error_type *getErrorStorage() const {
+    assert(HasError && "Cannot get error when a value exists!");
+    return reinterpret_cast<const error_type *>(ErrorStorage.buffer);
+  }
+
+  // Used by ExpectedAsOutParameter to reset the checked flag.
+  void setUnchecked() {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+    Unchecked = true;
+#endif
+  }
+
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+  LLVM_ATTRIBUTE_NORETURN
+  LLVM_ATTRIBUTE_NOINLINE
+  void fatalUncheckedExpected() const {
+    dbgs() << "Expected<T> must be checked before access or destruction.\n";
+    if (HasError) {
+      dbgs() << "Unchecked Expected<T> contained error:\n";
+      (*getErrorStorage())->log(dbgs());
+    } else
+      dbgs() << "Expected<T> value was in success state. (Note: Expected<T> "
+                "values in success mode must still be checked prior to being "
+                "destroyed).\n";
+    abort();
+  }
+#endif
+
+  void assertIsChecked() {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+    if (LLVM_UNLIKELY(Unchecked))
+      fatalUncheckedExpected();
+#endif
+  }
+
+  union {
+    AlignedCharArrayUnion<storage_type> TStorage;
+    AlignedCharArrayUnion<error_type> ErrorStorage;
+  };
+  bool HasError : 1;
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+  bool Unchecked : 1;
+#endif
+};
+
+/// Report a serious error, calling any installed error handler. See
+/// ErrorHandling.h.
+LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err,
+                                                bool gen_crash_diag = true);
+
+/// Report a fatal error if Err is a failure value.
+///
+/// This function can be used to wrap calls to fallible functions ONLY when it
+/// is known that the Error will always be a success value. E.g.
+///
+///   @code{.cpp}
+///   // foo only attempts the fallible operation if DoFallibleOperation is
+///   // true. If DoFallibleOperation is false then foo always returns
+///   // Error::success().
+///   Error foo(bool DoFallibleOperation);
+///
+///   cantFail(foo(false));
+///   @endcode
+inline void cantFail(Error Err, const char *Msg = nullptr) {
+  if (Err) {
+    if (!Msg)
+      Msg = "Failure value returned from cantFail wrapped call";
+#ifndef NDEBUG
+    std::string Str;
+    raw_string_ostream OS(Str);
+    OS << Msg << "\n" << Err;
+    Msg = OS.str().c_str();
+#endif
+    llvm_unreachable(Msg);
+  }
+}
+
+/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and
+/// returns the contained value.
+///
+/// This function can be used to wrap calls to fallible functions ONLY when it
+/// is known that the Error will always be a success value. E.g.
+///
+///   @code{.cpp}
+///   // foo only attempts the fallible operation if DoFallibleOperation is
+///   // true. If DoFallibleOperation is false then foo always returns an int.
+///   Expected<int> foo(bool DoFallibleOperation);
+///
+///   int X = cantFail(foo(false));
+///   @endcode
+template <typename T>
+T cantFail(Expected<T> ValOrErr, const char *Msg = nullptr) {
+  if (ValOrErr)
+    return std::move(*ValOrErr);
+  else {
+    if (!Msg)
+      Msg = "Failure value returned from cantFail wrapped call";
+#ifndef NDEBUG
+    std::string Str;
+    raw_string_ostream OS(Str);
+    auto E = ValOrErr.takeError();
+    OS << Msg << "\n" << E;
+    Msg = OS.str().c_str();
+#endif
+    llvm_unreachable(Msg);
+  }
+}
+
+/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and
+/// returns the contained reference.
+///
+/// This function can be used to wrap calls to fallible functions ONLY when it
+/// is known that the Error will always be a success value. E.g.
+///
+///   @code{.cpp}
+///   // foo only attempts the fallible operation if DoFallibleOperation is
+///   // true. If DoFallibleOperation is false then foo always returns a Bar&.
+///   Expected<Bar&> foo(bool DoFallibleOperation);
+///
+///   Bar &X = cantFail(foo(false));
+///   @endcode
+template <typename T>
+T& cantFail(Expected<T&> ValOrErr, const char *Msg = nullptr) {
+  if (ValOrErr)
+    return *ValOrErr;
+  else {
+    if (!Msg)
+      Msg = "Failure value returned from cantFail wrapped call";
+#ifndef NDEBUG
+    std::string Str;
+    raw_string_ostream OS(Str);
+    auto E = ValOrErr.takeError();
+    OS << Msg << "\n" << E;
+    Msg = OS.str().c_str();
+#endif
+    llvm_unreachable(Msg);
+  }
+}
+
+/// Helper for testing applicability of, and applying, handlers for
+/// ErrorInfo types.
+template <typename HandlerT>
+class ErrorHandlerTraits
+    : public ErrorHandlerTraits<decltype(
+          &std::remove_reference<HandlerT>::type::operator())> {};
+
+// Specialization functions of the form 'Error (const ErrT&)'.
+template <typename ErrT> class ErrorHandlerTraits<Error (&)(ErrT &)> {
+public:
+  static bool appliesTo(const ErrorInfoBase &E) {
+    return E.template isA<ErrT>();
+  }
+
+  template <typename HandlerT>
+  static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+    assert(appliesTo(*E) && "Applying incorrect handler");
+    return H(static_cast<ErrT &>(*E));
+  }
+};
+
+// Specialization functions of the form 'void (const ErrT&)'.
+template <typename ErrT> class ErrorHandlerTraits<void (&)(ErrT &)> {
+public:
+  static bool appliesTo(const ErrorInfoBase &E) {
+    return E.template isA<ErrT>();
+  }
+
+  template <typename HandlerT>
+  static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+    assert(appliesTo(*E) && "Applying incorrect handler");
+    H(static_cast<ErrT &>(*E));
+    return Error::success();
+  }
+};
+
+/// Specialization for functions of the form 'Error (std::unique_ptr<ErrT>)'.
+template <typename ErrT>
+class ErrorHandlerTraits<Error (&)(std::unique_ptr<ErrT>)> {
+public:
+  static bool appliesTo(const ErrorInfoBase &E) {
+    return E.template isA<ErrT>();
+  }
+
+  template <typename HandlerT>
+  static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+    assert(appliesTo(*E) && "Applying incorrect handler");
+    std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release()));
+    return H(std::move(SubE));
+  }
+};
+
+/// Specialization for functions of the form 'void (std::unique_ptr<ErrT>)'.
+template <typename ErrT>
+class ErrorHandlerTraits<void (&)(std::unique_ptr<ErrT>)> {
+public:
+  static bool appliesTo(const ErrorInfoBase &E) {
+    return E.template isA<ErrT>();
+  }
+
+  template <typename HandlerT>
+  static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+    assert(appliesTo(*E) && "Applying incorrect handler");
+    std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release()));
+    H(std::move(SubE));
+    return Error::success();
+  }
+};
+
+// Specialization for member functions of the form 'RetT (const ErrT&)'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(ErrT &)>
+    : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+// Specialization for member functions of the form 'RetT (const ErrT&) const'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(ErrT &) const>
+    : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+// Specialization for member functions of the form 'RetT (const ErrT&)'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(const ErrT &)>
+    : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+// Specialization for member functions of the form 'RetT (const ErrT&) const'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(const ErrT &) const>
+    : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+/// Specialization for member functions of the form
+/// 'RetT (std::unique_ptr<ErrT>)'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>)>
+    : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {};
+
+/// Specialization for member functions of the form
+/// 'RetT (std::unique_ptr<ErrT>) const'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>) const>
+    : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {};
+
+inline Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload) {
+  return Error(std::move(Payload));
+}
+
+template <typename HandlerT, typename... HandlerTs>
+Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload,
+                      HandlerT &&Handler, HandlerTs &&... Handlers) {
+  if (ErrorHandlerTraits<HandlerT>::appliesTo(*Payload))
+    return ErrorHandlerTraits<HandlerT>::apply(std::forward<HandlerT>(Handler),
+                                               std::move(Payload));
+  return handleErrorImpl(std::move(Payload),
+                         std::forward<HandlerTs>(Handlers)...);
+}
+
+/// Pass the ErrorInfo(s) contained in E to their respective handlers. Any
+/// unhandled errors (or Errors returned by handlers) are re-concatenated and
+/// returned.
+/// Because this function returns an error, its result must also be checked
+/// or returned. If you intend to handle all errors use handleAllErrors
+/// (which returns void, and will abort() on unhandled errors) instead.
+template <typename... HandlerTs>
+Error handleErrors(Error E, HandlerTs &&... Hs) {
+  if (!E)
+    return Error::success();
+
+  std::unique_ptr<ErrorInfoBase> Payload = E.takePayload();
+
+  if (Payload->isA<ErrorList>()) {
+    ErrorList &List = static_cast<ErrorList &>(*Payload);
+    Error R;
+    for (auto &P : List.Payloads)
+      R = ErrorList::join(
+          std::move(R),
+          handleErrorImpl(std::move(P), std::forward<HandlerTs>(Hs)...));
+    return R;
+  }
+
+  return handleErrorImpl(std::move(Payload), std::forward<HandlerTs>(Hs)...);
+}
+
+/// Behaves the same as handleErrors, except that by contract all errors
+/// *must* be handled by the given handlers (i.e. there must be no remaining
+/// errors after running the handlers, or llvm_unreachable is called).
+template <typename... HandlerTs>
+void handleAllErrors(Error E, HandlerTs &&... Handlers) {
+  cantFail(handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...));
+}
+
+/// Check that E is a non-error, then drop it.
+/// If E is an error, llvm_unreachable will be called.
+inline void handleAllErrors(Error E) {
+  cantFail(std::move(E));
+}
+
+/// Handle any errors (if present) in an Expected<T>, then try a recovery path.
+///
+/// If the incoming value is a success value it is returned unmodified. If it
+/// is a failure value then it the contained error is passed to handleErrors.
+/// If handleErrors is able to handle the error then the RecoveryPath functor
+/// is called to supply the final result. If handleErrors is not able to
+/// handle all errors then the unhandled errors are returned.
+///
+/// This utility enables the follow pattern:
+///
+///   @code{.cpp}
+///   enum FooStrategy { Aggressive, Conservative };
+///   Expected<Foo> foo(FooStrategy S);
+///
+///   auto ResultOrErr =
+///     handleExpected(
+///       foo(Aggressive),
+///       []() { return foo(Conservative); },
+///       [](AggressiveStrategyError&) {
+///         // Implicitly conusme this - we'll recover by using a conservative
+///         // strategy.
+///       });
+///
+///   @endcode
+template <typename T, typename RecoveryFtor, typename... HandlerTs>
+Expected<T> handleExpected(Expected<T> ValOrErr, RecoveryFtor &&RecoveryPath,
+                           HandlerTs &&... Handlers) {
+  if (ValOrErr)
+    return ValOrErr;
+
+  if (auto Err = handleErrors(ValOrErr.takeError(),
+                              std::forward<HandlerTs>(Handlers)...))
+    return std::move(Err);
+
+  return RecoveryPath();
+}
+
+/// Log all errors (if any) in E to OS. If there are any errors, ErrorBanner
+/// will be printed before the first one is logged. A newline will be printed
+/// after each error.
+///
+/// This function is compatible with the helpers from Support/WithColor.h. You
+/// can pass any of them as the OS. Please consider using them instead of
+/// including 'error: ' in the ErrorBanner.
+///
+/// This is useful in the base level of your program to allow clean termination
+/// (allowing clean deallocation of resources, etc.), while reporting error
+/// information to the user.
+void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner = {});
+
+/// Write all error messages (if any) in E to a string. The newline character
+/// is used to separate error messages.
+inline std::string toString(Error E) {
+  SmallVector<std::string, 2> Errors;
+  handleAllErrors(std::move(E), [&Errors](const ErrorInfoBase &EI) {
+    Errors.push_back(EI.message());
+  });
+  return join(Errors.begin(), Errors.end(), "\n");
+}
+
+/// Consume a Error without doing anything. This method should be used
+/// only where an error can be considered a reasonable and expected return
+/// value.
+///
+/// Uses of this method are potentially indicative of design problems: If it's
+/// legitimate to do nothing while processing an "error", the error-producer
+/// might be more clearly refactored to return an Optional<T>.
+inline void consumeError(Error Err) {
+  handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {});
+}
+
+/// Convert an Expected to an Optional without doing anything. This method
+/// should be used only where an error can be considered a reasonable and
+/// expected return value.
+///
+/// Uses of this method are potentially indicative of problems: perhaps the
+/// error should be propagated further, or the error-producer should just
+/// return an Optional in the first place.
+template <typename T> Optional<T> expectedToOptional(Expected<T> &&E) {
+  if (E)
+    return std::move(*E);
+  consumeError(E.takeError());
+  return None;
+}
+
+/// Helper for converting an Error to a bool.
+///
+/// This method returns true if Err is in an error state, or false if it is
+/// in a success state.  Puts Err in a checked state in both cases (unlike
+/// Error::operator bool(), which only does this for success states).
+inline bool errorToBool(Error Err) {
+  bool IsError = static_cast<bool>(Err);
+  if (IsError)
+    consumeError(std::move(Err));
+  return IsError;
+}
+
+/// Helper for Errors used as out-parameters.
+///
+/// This helper is for use with the Error-as-out-parameter idiom, where an error
+/// is passed to a function or method by reference, rather than being returned.
+/// In such cases it is helpful to set the checked bit on entry to the function
+/// so that the error can be written to (unchecked Errors abort on assignment)
+/// and clear the checked bit on exit so that clients cannot accidentally forget
+/// to check the result. This helper performs these actions automatically using
+/// RAII:
+///
+///   @code{.cpp}
+///   Result foo(Error &Err) {
+///     ErrorAsOutParameter ErrAsOutParam(&Err); // 'Checked' flag set
+///     // <body of foo>
+///     // <- 'Checked' flag auto-cleared when ErrAsOutParam is destructed.
+///   }
+///   @endcode
+///
+/// ErrorAsOutParameter takes an Error* rather than Error& so that it can be
+/// used with optional Errors (Error pointers that are allowed to be null). If
+/// ErrorAsOutParameter took an Error reference, an instance would have to be
+/// created inside every condition that verified that Error was non-null. By
+/// taking an Error pointer we can just create one instance at the top of the
+/// function.
+class ErrorAsOutParameter {
+public:
+  ErrorAsOutParameter(Error *Err) : Err(Err) {
+    // Raise the checked bit if Err is success.
+    if (Err)
+      (void)!!*Err;
+  }
+
+  ~ErrorAsOutParameter() {
+    // Clear the checked bit.
+    if (Err && !*Err)
+      *Err = Error::success();
+  }
+
+private:
+  Error *Err;
+};
+
+/// Helper for Expected<T>s used as out-parameters.
+///
+/// See ErrorAsOutParameter.
+template <typename T>
+class ExpectedAsOutParameter {
+public:
+  ExpectedAsOutParameter(Expected<T> *ValOrErr)
+    : ValOrErr(ValOrErr) {
+    if (ValOrErr)
+      (void)!!*ValOrErr;
+  }
+
+  ~ExpectedAsOutParameter() {
+    if (ValOrErr)
+      ValOrErr->setUnchecked();
+  }
+
+private:
+  Expected<T> *ValOrErr;
+};
+
+/// This class wraps a std::error_code in a Error.
+///
+/// This is useful if you're writing an interface that returns a Error
+/// (or Expected) and you want to call code that still returns
+/// std::error_codes.
+class ECError : public ErrorInfo<ECError> {
+  friend Error errorCodeToError(std::error_code);
+
+  virtual void anchor() override;
+
+public:
+  void setErrorCode(std::error_code EC) { this->EC = EC; }
+  std::error_code convertToErrorCode() const override { return EC; }
+  void log(raw_ostream &OS) const override { OS << EC.message(); }
+
+  // Used by ErrorInfo::classID.
+  static char ID;
+
+protected:
+  ECError() = default;
+  ECError(std::error_code EC) : EC(EC) {}
+
+  std::error_code EC;
+};
+
+/// The value returned by this function can be returned from convertToErrorCode
+/// for Error values where no sensible translation to std::error_code exists.
+/// It should only be used in this situation, and should never be used where a
+/// sensible conversion to std::error_code is available, as attempts to convert
+/// to/from this error will result in a fatal error. (i.e. it is a programmatic
+///error to try to convert such a value).
+std::error_code inconvertibleErrorCode();
+
+/// Helper for converting an std::error_code to a Error.
+Error errorCodeToError(std::error_code EC);
+
+/// Helper for converting an ECError to a std::error_code.
+///
+/// This method requires that Err be Error() or an ECError, otherwise it
+/// will trigger a call to abort().
+std::error_code errorToErrorCode(Error Err);
+
+/// Convert an ErrorOr<T> to an Expected<T>.
+template <typename T> Expected<T> errorOrToExpected(ErrorOr<T> &&EO) {
+  if (auto EC = EO.getError())
+    return errorCodeToError(EC);
+  return std::move(*EO);
+}
+
+/// Convert an Expected<T> to an ErrorOr<T>.
+template <typename T> ErrorOr<T> expectedToErrorOr(Expected<T> &&E) {
+  if (auto Err = E.takeError())
+    return errorToErrorCode(std::move(Err));
+  return std::move(*E);
+}
+
+/// This class wraps a string in an Error.
+///
+/// StringError is useful in cases where the client is not expected to be able
+/// to consume the specific error message programmatically (for example, if the
+/// error message is to be presented to the user).
+///
+/// StringError can also be used when additional information is to be printed
+/// along with a error_code message. Depending on the constructor called, this
+/// class can either display:
+///    1. the error_code message (ECError behavior)
+///    2. a string
+///    3. the error_code message and a string
+///
+/// These behaviors are useful when subtyping is required; for example, when a
+/// specific library needs an explicit error type. In the example below,
+/// PDBError is derived from StringError:
+///
+///   @code{.cpp}
+///   Expected<int> foo() {
+///      return llvm::make_error<PDBError>(pdb_error_code::dia_failed_loading,
+///                                        "Additional information");
+///   }
+///   @endcode
+///
+class StringError : public ErrorInfo<StringError> {
+public:
+  static char ID;
+
+  // Prints EC + S and converts to EC
+  StringError(std::error_code EC, const Twine &S = Twine());
+
+  // Prints S and converts to EC
+  StringError(const Twine &S, std::error_code EC);
+
+  void log(raw_ostream &OS) const override;
+  std::error_code convertToErrorCode() const override;
+
+  const std::string &getMessage() const { return Msg; }
+
+private:
+  std::string Msg;
+  std::error_code EC;
+  const bool PrintMsgOnly = false;
+};
+
+/// Create formatted StringError object.
+template <typename... Ts>
+inline Error createStringError(std::error_code EC, char const *Fmt,
+                               const Ts &... Vals) {
+  std::string Buffer;
+  raw_string_ostream Stream(Buffer);
+  Stream << format(Fmt, Vals...);
+  return make_error<StringError>(Stream.str(), EC);
+}
+
+Error createStringError(std::error_code EC, char const *Msg);
+
+inline Error createStringError(std::error_code EC, const Twine &S) {
+  return createStringError(EC, S.str().c_str());
+}
+
+template <typename... Ts>
+inline Error createStringError(std::errc EC, char const *Fmt,
+                               const Ts &... Vals) {
+  return createStringError(std::make_error_code(EC), Fmt, Vals...);
+}
+
+/// This class wraps a filename and another Error.
+///
+/// In some cases, an error needs to live along a 'source' name, in order to
+/// show more detailed information to the user.
+class FileError final : public ErrorInfo<FileError> {
+
+  friend Error createFileError(const Twine &, Error);
+  friend Error createFileError(const Twine &, size_t, Error);
+
+public:
+  void log(raw_ostream &OS) const override {
+    assert(Err && !FileName.empty() && "Trying to log after takeError().");
+    OS << "'" << FileName << "': ";
+    if (Line.hasValue())
+      OS << "line " << Line.getValue() << ": ";
+    Err->log(OS);
+  }
+
+  Error takeError() { return Error(std::move(Err)); }
+
+  std::error_code convertToErrorCode() const override;
+
+  // Used by ErrorInfo::classID.
+  static char ID;
+
+private:
+  FileError(const Twine &F, Optional<size_t> LineNum,
+            std::unique_ptr<ErrorInfoBase> E) {
+    assert(E && "Cannot create FileError from Error success value.");
+    assert(!F.isTriviallyEmpty() &&
+           "The file name provided to FileError must not be empty.");
+    FileName = F.str();
+    Err = std::move(E);
+    Line = std::move(LineNum);
+  }
+
+  static Error build(const Twine &F, Optional<size_t> Line, Error E) {
+    return Error(
+        std::unique_ptr<FileError>(new FileError(F, Line, E.takePayload())));
+  }
+
+  std::string FileName;
+  Optional<size_t> Line;
+  std::unique_ptr<ErrorInfoBase> Err;
+};
+
+/// Concatenate a source file path and/or name with an Error. The resulting
+/// Error is unchecked.
+inline Error createFileError(const Twine &F, Error E) {
+  return FileError::build(F, Optional<size_t>(), std::move(E));
+}
+
+/// Concatenate a source file path and/or name with line number and an Error.
+/// The resulting Error is unchecked.
+inline Error createFileError(const Twine &F, size_t Line, Error E) {
+  return FileError::build(F, Optional<size_t>(Line), std::move(E));
+}
+
+/// Concatenate a source file path and/or name with a std::error_code 
+/// to form an Error object.
+inline Error createFileError(const Twine &F, std::error_code EC) {
+  return createFileError(F, errorCodeToError(EC));
+}
+
+/// Concatenate a source file path and/or name with line number and
+/// std::error_code to form an Error object.
+inline Error createFileError(const Twine &F, size_t Line, std::error_code EC) {
+  return createFileError(F, Line, errorCodeToError(EC));
+}
+
+Error createFileError(const Twine &F, ErrorSuccess) = delete;
+
+/// Helper for check-and-exit error handling.
+///
+/// For tool use only. NOT FOR USE IN LIBRARY CODE.
+///
+class ExitOnError {
+public:
+  /// Create an error on exit helper.
+  ExitOnError(std::string Banner = "", int DefaultErrorExitCode = 1)
+      : Banner(std::move(Banner)),
+        GetExitCode([=](const Error &) { return DefaultErrorExitCode; }) {}
+
+  /// Set the banner string for any errors caught by operator().
+  void setBanner(std::string Banner) { this->Banner = std::move(Banner); }
+
+  /// Set the exit-code mapper function.
+  void setExitCodeMapper(std::function<int(const Error &)> GetExitCode) {
+    this->GetExitCode = std::move(GetExitCode);
+  }
+
+  /// Check Err. If it's in a failure state log the error(s) and exit.
+  void operator()(Error Err) const { checkError(std::move(Err)); }
+
+  /// Check E. If it's in a success state then return the contained value. If
+  /// it's in a failure state log the error(s) and exit.
+  template <typename T> T operator()(Expected<T> &&E) const {
+    checkError(E.takeError());
+    return std::move(*E);
+  }
+
+  /// Check E. If it's in a success state then return the contained reference. If
+  /// it's in a failure state log the error(s) and exit.
+  template <typename T> T& operator()(Expected<T&> &&E) const {
+    checkError(E.takeError());
+    return *E;
+  }
+
+private:
+  void checkError(Error Err) const {
+    if (Err) {
+      int ExitCode = GetExitCode(Err);
+      logAllUnhandledErrors(std::move(Err), errs(), Banner);
+      exit(ExitCode);
+    }
+  }
+
+  std::string Banner;
+  std::function<int(const Error &)> GetExitCode;
+};
+
+/// Conversion from Error to LLVMErrorRef for C error bindings.
+inline LLVMErrorRef wrap(Error Err) {
+  return reinterpret_cast<LLVMErrorRef>(Err.takePayload().release());
+}
+
+/// Conversion from LLVMErrorRef to Error for C error bindings.
+inline Error unwrap(LLVMErrorRef ErrRef) {
+  return Error(std::unique_ptr<ErrorInfoBase>(
+      reinterpret_cast<ErrorInfoBase *>(ErrRef)));
+}
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_ERROR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/ErrorHandling.h b/binaryen/third_party/llvm-project/include/llvm/Support/ErrorHandling.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/ErrorHandling.h
@@ -0,0 +1,143 @@
+//===- llvm/Support/ErrorHandling.h - Fatal error handling ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines an API used to indicate fatal error conditions.  Non-fatal
+// errors (most of them) should be handled through LLVMContext.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ERRORHANDLING_H
+#define LLVM_SUPPORT_ERRORHANDLING_H
+
+#include "llvm/Support/Compiler.h"
+#include <string>
+
+namespace llvm {
+class StringRef;
+  class Twine;
+
+  /// An error handler callback.
+  typedef void (*fatal_error_handler_t)(void *user_data,
+                                        const std::string& reason,
+                                        bool gen_crash_diag);
+
+  /// install_fatal_error_handler - Installs a new error handler to be used
+  /// whenever a serious (non-recoverable) error is encountered by LLVM.
+  ///
+  /// If no error handler is installed the default is to print the error message
+  /// to stderr, and call exit(1).  If an error handler is installed then it is
+  /// the handler's responsibility to log the message, it will no longer be
+  /// printed to stderr.  If the error handler returns, then exit(1) will be
+  /// called.
+  ///
+  /// It is dangerous to naively use an error handler which throws an exception.
+  /// Even though some applications desire to gracefully recover from arbitrary
+  /// faults, blindly throwing exceptions through unfamiliar code isn't a way to
+  /// achieve this.
+  ///
+  /// \param user_data - An argument which will be passed to the install error
+  /// handler.
+  void install_fatal_error_handler(fatal_error_handler_t handler,
+                                   void *user_data = nullptr);
+
+  /// Restores default error handling behaviour.
+  void remove_fatal_error_handler();
+
+  /// ScopedFatalErrorHandler - This is a simple helper class which just
+  /// calls install_fatal_error_handler in its constructor and
+  /// remove_fatal_error_handler in its destructor.
+  struct ScopedFatalErrorHandler {
+    explicit ScopedFatalErrorHandler(fatal_error_handler_t handler,
+                                     void *user_data = nullptr) {
+      install_fatal_error_handler(handler, user_data);
+    }
+
+    ~ScopedFatalErrorHandler() { remove_fatal_error_handler(); }
+  };
+
+/// Reports a serious error, calling any installed error handler. These
+/// functions are intended to be used for error conditions which are outside
+/// the control of the compiler (I/O errors, invalid user input, etc.)
+///
+/// If no error handler is installed the default is to print the message to
+/// standard error, followed by a newline.
+/// After the error handler is called this function will call exit(1), it
+/// does not return.
+LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const char *reason,
+                                                bool gen_crash_diag = true);
+LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const std::string &reason,
+                                                bool gen_crash_diag = true);
+LLVM_ATTRIBUTE_NORETURN void report_fatal_error(StringRef reason,
+                                                bool gen_crash_diag = true);
+LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const Twine &reason,
+                                                bool gen_crash_diag = true);
+
+/// Installs a new bad alloc error handler that should be used whenever a
+/// bad alloc error, e.g. failing malloc/calloc, is encountered by LLVM.
+///
+/// The user can install a bad alloc handler, in order to define the behavior
+/// in case of failing allocations, e.g. throwing an exception. Note that this
+/// handler must not trigger any additional allocations itself.
+///
+/// If no error handler is installed the default is to print the error message
+/// to stderr, and call exit(1).  If an error handler is installed then it is
+/// the handler's responsibility to log the message, it will no longer be
+/// printed to stderr.  If the error handler returns, then exit(1) will be
+/// called.
+///
+///
+/// \param user_data - An argument which will be passed to the installed error
+/// handler.
+void install_bad_alloc_error_handler(fatal_error_handler_t handler,
+                                     void *user_data = nullptr);
+
+/// Restores default bad alloc error handling behavior.
+void remove_bad_alloc_error_handler();
+
+void install_out_of_memory_new_handler();
+
+/// Reports a bad alloc error, calling any user defined bad alloc
+/// error handler. In contrast to the generic 'report_fatal_error'
+/// functions, this function is expected to return, e.g. the user
+/// defined error handler throws an exception.
+///
+/// Note: When throwing an exception in the bad alloc handler, make sure that
+/// the following unwind succeeds, e.g. do not trigger additional allocations
+/// in the unwind chain.
+///
+/// If no error handler is installed (default), then a bad_alloc exception
+/// is thrown, if LLVM is compiled with exception support, otherwise an
+/// assertion is called.
+void report_bad_alloc_error(const char *Reason, bool GenCrashDiag = true);
+
+/// This function calls abort(), and prints the optional message to stderr.
+/// Use the llvm_unreachable macro (that adds location info), instead of
+/// calling this function directly.
+LLVM_ATTRIBUTE_NORETURN void
+llvm_unreachable_internal(const char *msg = nullptr, const char *file = nullptr,
+                          unsigned line = 0);
+}
+
+/// Marks that the current location is not supposed to be reachable.
+/// In !NDEBUG builds, prints the message and location info to stderr.
+/// In NDEBUG builds, becomes an optimizer hint that the current location
+/// is not supposed to be reachable.  On compilers that don't support
+/// such hints, prints a reduced message instead.
+///
+/// Use this instead of assert(0).  It conveys intent more clearly and
+/// allows compilers to omit some unnecessary code.
+#ifndef NDEBUG
+#define llvm_unreachable(msg) \
+  ::llvm::llvm_unreachable_internal(msg, __FILE__, __LINE__)
+#elif defined(LLVM_BUILTIN_UNREACHABLE)
+#define llvm_unreachable(msg) LLVM_BUILTIN_UNREACHABLE
+#else
+#define llvm_unreachable(msg) ::llvm::llvm_unreachable_internal()
+#endif
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/ErrorOr.h b/binaryen/third_party/llvm-project/include/llvm/Support/ErrorOr.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/ErrorOr.h
@@ -0,0 +1,278 @@
+//===- llvm/Support/ErrorOr.h - Error Smart Pointer -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Provides ErrorOr<T> smart pointer.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ERROROR_H
+#define LLVM_SUPPORT_ERROROR_H
+
+#include "llvm/Support/AlignOf.h"
+#include <cassert>
+#include <system_error>
+#include <type_traits>
+#include <utility>
+
+namespace llvm {
+
+/// Represents either an error or a value T.
+///
+/// ErrorOr<T> is a pointer-like class that represents the result of an
+/// operation. The result is either an error, or a value of type T. This is
+/// designed to emulate the usage of returning a pointer where nullptr indicates
+/// failure. However instead of just knowing that the operation failed, we also
+/// have an error_code and optional user data that describes why it failed.
+///
+/// It is used like the following.
+/// \code
+///   ErrorOr<Buffer> getBuffer();
+///
+///   auto buffer = getBuffer();
+///   if (error_code ec = buffer.getError())
+///     return ec;
+///   buffer->write("adena");
+/// \endcode
+///
+///
+/// Implicit conversion to bool returns true if there is a usable value. The
+/// unary * and -> operators provide pointer like access to the value. Accessing
+/// the value when there is an error has undefined behavior.
+///
+/// When T is a reference type the behavior is slightly different. The reference
+/// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and
+/// there is special handling to make operator -> work as if T was not a
+/// reference.
+///
+/// T cannot be a rvalue reference.
+template<class T>
+class ErrorOr {
+  template <class OtherT> friend class ErrorOr;
+
+  static const bool isRef = std::is_reference<T>::value;
+
+  using wrap = std::reference_wrapper<typename std::remove_reference<T>::type>;
+
+public:
+  using storage_type = typename std::conditional<isRef, wrap, T>::type;
+
+private:
+  using reference = typename std::remove_reference<T>::type &;
+  using const_reference = const typename std::remove_reference<T>::type &;
+  using pointer = typename std::remove_reference<T>::type *;
+  using const_pointer = const typename std::remove_reference<T>::type *;
+
+public:
+  template <class E>
+  ErrorOr(E ErrorCode,
+          typename std::enable_if<std::is_error_code_enum<E>::value ||
+                                      std::is_error_condition_enum<E>::value,
+                                  void *>::type = nullptr)
+      : HasError(true) {
+    new (getErrorStorage()) std::error_code(make_error_code(ErrorCode));
+  }
+
+  ErrorOr(std::error_code EC) : HasError(true) {
+    new (getErrorStorage()) std::error_code(EC);
+  }
+
+  template <class OtherT>
+  ErrorOr(OtherT &&Val,
+          typename std::enable_if<std::is_convertible<OtherT, T>::value>::type
+              * = nullptr)
+      : HasError(false) {
+    new (getStorage()) storage_type(std::forward<OtherT>(Val));
+  }
+
+  ErrorOr(const ErrorOr &Other) {
+    copyConstruct(Other);
+  }
+
+  template <class OtherT>
+  ErrorOr(
+      const ErrorOr<OtherT> &Other,
+      typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
+          nullptr) {
+    copyConstruct(Other);
+  }
+
+  template <class OtherT>
+  explicit ErrorOr(
+      const ErrorOr<OtherT> &Other,
+      typename std::enable_if<
+          !std::is_convertible<OtherT, const T &>::value>::type * = nullptr) {
+    copyConstruct(Other);
+  }
+
+  ErrorOr(ErrorOr &&Other) {
+    moveConstruct(std::move(Other));
+  }
+
+  template <class OtherT>
+  ErrorOr(
+      ErrorOr<OtherT> &&Other,
+      typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
+          nullptr) {
+    moveConstruct(std::move(Other));
+  }
+
+  // This might eventually need SFINAE but it's more complex than is_convertible
+  // & I'm too lazy to write it right now.
+  template <class OtherT>
+  explicit ErrorOr(
+      ErrorOr<OtherT> &&Other,
+      typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * =
+          nullptr) {
+    moveConstruct(std::move(Other));
+  }
+
+  ErrorOr &operator=(const ErrorOr &Other) {
+    copyAssign(Other);
+    return *this;
+  }
+
+  ErrorOr &operator=(ErrorOr &&Other) {
+    moveAssign(std::move(Other));
+    return *this;
+  }
+
+  ~ErrorOr() {
+    if (!HasError)
+      getStorage()->~storage_type();
+  }
+
+  /// Return false if there is an error.
+  explicit operator bool() const {
+    return !HasError;
+  }
+
+  reference get() { return *getStorage(); }
+  const_reference get() const { return const_cast<ErrorOr<T> *>(this)->get(); }
+
+  std::error_code getError() const {
+    return HasError ? *getErrorStorage() : std::error_code();
+  }
+
+  pointer operator ->() {
+    return toPointer(getStorage());
+  }
+
+  const_pointer operator->() const { return toPointer(getStorage()); }
+
+  reference operator *() {
+    return *getStorage();
+  }
+
+  const_reference operator*() const { return *getStorage(); }
+
+private:
+  template <class OtherT>
+  void copyConstruct(const ErrorOr<OtherT> &Other) {
+    if (!Other.HasError) {
+      // Get the other value.
+      HasError = false;
+      new (getStorage()) storage_type(*Other.getStorage());
+    } else {
+      // Get other's error.
+      HasError = true;
+      new (getErrorStorage()) std::error_code(Other.getError());
+    }
+  }
+
+  template <class T1>
+  static bool compareThisIfSameType(const T1 &a, const T1 &b) {
+    return &a == &b;
+  }
+
+  template <class T1, class T2>
+  static bool compareThisIfSameType(const T1 &a, const T2 &b) {
+    return false;
+  }
+
+  template <class OtherT>
+  void copyAssign(const ErrorOr<OtherT> &Other) {
+    if (compareThisIfSameType(*this, Other))
+      return;
+
+    this->~ErrorOr();
+    new (this) ErrorOr(Other);
+  }
+
+  template <class OtherT>
+  void moveConstruct(ErrorOr<OtherT> &&Other) {
+    if (!Other.HasError) {
+      // Get the other value.
+      HasError = false;
+      new (getStorage()) storage_type(std::move(*Other.getStorage()));
+    } else {
+      // Get other's error.
+      HasError = true;
+      new (getErrorStorage()) std::error_code(Other.getError());
+    }
+  }
+
+  template <class OtherT>
+  void moveAssign(ErrorOr<OtherT> &&Other) {
+    if (compareThisIfSameType(*this, Other))
+      return;
+
+    this->~ErrorOr();
+    new (this) ErrorOr(std::move(Other));
+  }
+
+  pointer toPointer(pointer Val) {
+    return Val;
+  }
+
+  const_pointer toPointer(const_pointer Val) const { return Val; }
+
+  pointer toPointer(wrap *Val) {
+    return &Val->get();
+  }
+
+  const_pointer toPointer(const wrap *Val) const { return &Val->get(); }
+
+  storage_type *getStorage() {
+    assert(!HasError && "Cannot get value when an error exists!");
+    return reinterpret_cast<storage_type*>(TStorage.buffer);
+  }
+
+  const storage_type *getStorage() const {
+    assert(!HasError && "Cannot get value when an error exists!");
+    return reinterpret_cast<const storage_type*>(TStorage.buffer);
+  }
+
+  std::error_code *getErrorStorage() {
+    assert(HasError && "Cannot get error when a value exists!");
+    return reinterpret_cast<std::error_code *>(ErrorStorage.buffer);
+  }
+
+  const std::error_code *getErrorStorage() const {
+    return const_cast<ErrorOr<T> *>(this)->getErrorStorage();
+  }
+
+  union {
+    AlignedCharArrayUnion<storage_type> TStorage;
+    AlignedCharArrayUnion<std::error_code> ErrorStorage;
+  };
+  bool HasError : 1;
+};
+
+template <class T, class E>
+typename std::enable_if<std::is_error_code_enum<E>::value ||
+                            std::is_error_condition_enum<E>::value,
+                        bool>::type
+operator==(const ErrorOr<T> &Err, E Code) {
+  return Err.getError() == Code;
+}
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_ERROROR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/FileOutputBuffer.h b/binaryen/third_party/llvm-project/include/llvm/Support/FileOutputBuffer.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/FileOutputBuffer.h
@@ -0,0 +1,88 @@
+//=== FileOutputBuffer.h - File Output Buffer -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Utility for creating a in-memory buffer that will be written to a file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FILEOUTPUTBUFFER_H
+#define LLVM_SUPPORT_FILEOUTPUTBUFFER_H
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+
+namespace llvm {
+/// FileOutputBuffer - This interface provides simple way to create an in-memory
+/// buffer which will be written to a file. During the lifetime of these
+/// objects, the content or existence of the specified file is undefined. That
+/// is, creating an OutputBuffer for a file may immediately remove the file.
+/// If the FileOutputBuffer is committed, the target file's content will become
+/// the buffer content at the time of the commit.  If the FileOutputBuffer is
+/// not committed, the file will be deleted in the FileOutputBuffer destructor.
+class FileOutputBuffer {
+public:
+  enum {
+    /// set the 'x' bit on the resulting file
+    F_executable = 1,
+
+    /// Don't use mmap and instead write an in-memory buffer to a file when this
+    /// buffer is closed.
+    F_no_mmap = 2,
+  };
+
+  /// Factory method to create an OutputBuffer object which manages a read/write
+  /// buffer of the specified size. When committed, the buffer will be written
+  /// to the file at the specified path.
+  ///
+  /// When F_modify is specified and \p FilePath refers to an existing on-disk
+  /// file \p Size may be set to -1, in which case the entire file is used.
+  /// Otherwise, the file shrinks or grows as necessary based on the value of
+  /// \p Size.  It is an error to specify F_modify and Size=-1 if \p FilePath
+  /// does not exist.
+  static Expected<std::unique_ptr<FileOutputBuffer>>
+  create(StringRef FilePath, size_t Size, unsigned Flags = 0);
+
+  /// Returns a pointer to the start of the buffer.
+  virtual uint8_t *getBufferStart() const = 0;
+
+  /// Returns a pointer to the end of the buffer.
+  virtual uint8_t *getBufferEnd() const = 0;
+
+  /// Returns size of the buffer.
+  virtual size_t getBufferSize() const = 0;
+
+  /// Returns path where file will show up if buffer is committed.
+  StringRef getPath() const { return FinalPath; }
+
+  /// Flushes the content of the buffer to its file and deallocates the
+  /// buffer.  If commit() is not called before this object's destructor
+  /// is called, the file is deleted in the destructor. The optional parameter
+  /// is used if it turns out you want the file size to be smaller than
+  /// initially requested.
+  virtual Error commit() = 0;
+
+  /// If this object was previously committed, the destructor just deletes
+  /// this object.  If this object was not committed, the destructor
+  /// deallocates the buffer and the target file is never written.
+  virtual ~FileOutputBuffer() {}
+
+  /// This removes the temporary file (unless it already was committed)
+  /// but keeps the memory mapping alive.
+  virtual void discard() {}
+
+protected:
+  FileOutputBuffer(StringRef Path) : FinalPath(Path) {}
+
+  std::string FinalPath;
+};
+} // end namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/FileSystem.h b/binaryen/third_party/llvm-project/include/llvm/Support/FileSystem.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/FileSystem.h
@@ -0,0 +1,1444 @@
+//===- llvm/Support/FileSystem.h - File System OS Concept -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the llvm::sys::fs namespace. It is designed after
+// TR2/boost filesystem (v3), but modified to remove exception handling and the
+// path class.
+//
+// All functions return an error_code and their actual work via the last out
+// argument. The out argument is defined if and only if errc::success is
+// returned. A function may return any error code in the generic or system
+// category. However, they shall be equivalent to any error conditions listed
+// in each functions respective documentation if the condition applies. [ note:
+// this does not guarantee that error_code will be in the set of explicitly
+// listed codes, but it does guarantee that if any of the explicitly listed
+// errors occur, the correct error_code will be used ]. All functions may
+// return errc::not_enough_memory if there is not enough memory to complete the
+// operation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FILESYSTEM_H
+#define LLVM_SUPPORT_FILESYSTEM_H
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MD5.h"
+#include <cassert>
+#include <cstdint>
+#include <ctime>
+#include <memory>
+#include <stack>
+#include <string>
+#include <system_error>
+#include <tuple>
+#include <vector>
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+namespace llvm {
+namespace sys {
+namespace fs {
+
+#if defined(_WIN32)
+// A Win32 HANDLE is a typedef of void*
+using file_t = void *;
+#else
+using file_t = int;
+#endif
+
+extern const file_t kInvalidFile;
+
+/// An enumeration for the file system's view of the type.
+enum class file_type {
+  status_error,
+  file_not_found,
+  regular_file,
+  directory_file,
+  symlink_file,
+  block_file,
+  character_file,
+  fifo_file,
+  socket_file,
+  type_unknown
+};
+
+/// space_info - Self explanatory.
+struct space_info {
+  uint64_t capacity;
+  uint64_t free;
+  uint64_t available;
+};
+
+enum perms {
+  no_perms = 0,
+  owner_read = 0400,
+  owner_write = 0200,
+  owner_exe = 0100,
+  owner_all = owner_read | owner_write | owner_exe,
+  group_read = 040,
+  group_write = 020,
+  group_exe = 010,
+  group_all = group_read | group_write | group_exe,
+  others_read = 04,
+  others_write = 02,
+  others_exe = 01,
+  others_all = others_read | others_write | others_exe,
+  all_read = owner_read | group_read | others_read,
+  all_write = owner_write | group_write | others_write,
+  all_exe = owner_exe | group_exe | others_exe,
+  all_all = owner_all | group_all | others_all,
+  set_uid_on_exe = 04000,
+  set_gid_on_exe = 02000,
+  sticky_bit = 01000,
+  all_perms = all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit,
+  perms_not_known = 0xFFFF
+};
+
+// Helper functions so that you can use & and | to manipulate perms bits:
+inline perms operator|(perms l, perms r) {
+  return static_cast<perms>(static_cast<unsigned short>(l) |
+                            static_cast<unsigned short>(r));
+}
+inline perms operator&(perms l, perms r) {
+  return static_cast<perms>(static_cast<unsigned short>(l) &
+                            static_cast<unsigned short>(r));
+}
+inline perms &operator|=(perms &l, perms r) {
+  l = l | r;
+  return l;
+}
+inline perms &operator&=(perms &l, perms r) {
+  l = l & r;
+  return l;
+}
+inline perms operator~(perms x) {
+  // Avoid UB by explicitly truncating the (unsigned) ~ result.
+  return static_cast<perms>(
+      static_cast<unsigned short>(~static_cast<unsigned short>(x)));
+}
+
+class UniqueID {
+  uint64_t Device;
+  uint64_t File;
+
+public:
+  UniqueID() = default;
+  UniqueID(uint64_t Device, uint64_t File) : Device(Device), File(File) {}
+
+  bool operator==(const UniqueID &Other) const {
+    return Device == Other.Device && File == Other.File;
+  }
+  bool operator!=(const UniqueID &Other) const { return !(*this == Other); }
+  bool operator<(const UniqueID &Other) const {
+    return std::tie(Device, File) < std::tie(Other.Device, Other.File);
+  }
+
+  uint64_t getDevice() const { return Device; }
+  uint64_t getFile() const { return File; }
+};
+
+/// Represents the result of a call to directory_iterator::status(). This is a
+/// subset of the information returned by a regular sys::fs::status() call, and
+/// represents the information provided by Windows FileFirstFile/FindNextFile.
+class basic_file_status {
+protected:
+  #if defined(LLVM_ON_UNIX)
+  time_t fs_st_atime = 0;
+  time_t fs_st_mtime = 0;
+  uint32_t fs_st_atime_nsec = 0;
+  uint32_t fs_st_mtime_nsec = 0;
+  uid_t fs_st_uid = 0;
+  gid_t fs_st_gid = 0;
+  off_t fs_st_size = 0;
+  #elif defined (_WIN32)
+  uint32_t LastAccessedTimeHigh = 0;
+  uint32_t LastAccessedTimeLow = 0;
+  uint32_t LastWriteTimeHigh = 0;
+  uint32_t LastWriteTimeLow = 0;
+  uint32_t FileSizeHigh = 0;
+  uint32_t FileSizeLow = 0;
+  #endif
+  file_type Type = file_type::status_error;
+  perms Perms = perms_not_known;
+
+public:
+  basic_file_status() = default;
+
+  explicit basic_file_status(file_type Type) : Type(Type) {}
+
+  #if defined(LLVM_ON_UNIX)
+  basic_file_status(file_type Type, perms Perms, time_t ATime,
+                    uint32_t ATimeNSec, time_t MTime, uint32_t MTimeNSec,
+                    uid_t UID, gid_t GID, off_t Size)
+      : fs_st_atime(ATime), fs_st_mtime(MTime),
+        fs_st_atime_nsec(ATimeNSec), fs_st_mtime_nsec(MTimeNSec),
+        fs_st_uid(UID), fs_st_gid(GID),
+        fs_st_size(Size), Type(Type), Perms(Perms) {}
+#elif defined(_WIN32)
+  basic_file_status(file_type Type, perms Perms, uint32_t LastAccessTimeHigh,
+                    uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh,
+                    uint32_t LastWriteTimeLow, uint32_t FileSizeHigh,
+                    uint32_t FileSizeLow)
+      : LastAccessedTimeHigh(LastAccessTimeHigh),
+        LastAccessedTimeLow(LastAccessTimeLow),
+        LastWriteTimeHigh(LastWriteTimeHigh),
+        LastWriteTimeLow(LastWriteTimeLow), FileSizeHigh(FileSizeHigh),
+        FileSizeLow(FileSizeLow), Type(Type), Perms(Perms) {}
+  #endif
+
+  // getters
+  file_type type() const { return Type; }
+  perms permissions() const { return Perms; }
+
+  /// The file access time as reported from the underlying file system.
+  ///
+  /// Also see comments on \c getLastModificationTime() related to the precision
+  /// of the returned value.
+  TimePoint<> getLastAccessedTime() const;
+
+  /// The file modification time as reported from the underlying file system.
+  ///
+  /// The returned value allows for nanosecond precision but the actual
+  /// resolution is an implementation detail of the underlying file system.
+  /// There is no guarantee for what kind of resolution you can expect, the
+  /// resolution can differ across platforms and even across mountpoints on the
+  /// same machine.
+  TimePoint<> getLastModificationTime() const;
+
+  #if defined(LLVM_ON_UNIX)
+  uint32_t getUser() const { return fs_st_uid; }
+  uint32_t getGroup() const { return fs_st_gid; }
+  uint64_t getSize() const { return fs_st_size; }
+  #elif defined (_WIN32)
+  uint32_t getUser() const {
+    return 9999; // Not applicable to Windows, so...
+  }
+
+  uint32_t getGroup() const {
+    return 9999; // Not applicable to Windows, so...
+  }
+
+  uint64_t getSize() const {
+    return (uint64_t(FileSizeHigh) << 32) + FileSizeLow;
+  }
+  #endif
+
+  // setters
+  void type(file_type v) { Type = v; }
+  void permissions(perms p) { Perms = p; }
+};
+
+/// Represents the result of a call to sys::fs::status().
+class file_status : public basic_file_status {
+  friend bool equivalent(file_status A, file_status B);
+
+  #if defined(LLVM_ON_UNIX)
+  dev_t fs_st_dev = 0;
+  nlink_t fs_st_nlinks = 0;
+  ino_t fs_st_ino = 0;
+  #elif defined (_WIN32)
+  uint32_t NumLinks = 0;
+  uint32_t VolumeSerialNumber = 0;
+  uint32_t FileIndexHigh = 0;
+  uint32_t FileIndexLow = 0;
+  #endif
+
+public:
+  file_status() = default;
+
+  explicit file_status(file_type Type) : basic_file_status(Type) {}
+
+  #if defined(LLVM_ON_UNIX)
+  file_status(file_type Type, perms Perms, dev_t Dev, nlink_t Links, ino_t Ino,
+              time_t ATime, uint32_t ATimeNSec,
+              time_t MTime, uint32_t MTimeNSec,
+              uid_t UID, gid_t GID, off_t Size)
+      : basic_file_status(Type, Perms, ATime, ATimeNSec, MTime, MTimeNSec,
+                          UID, GID, Size),
+        fs_st_dev(Dev), fs_st_nlinks(Links), fs_st_ino(Ino) {}
+  #elif defined(_WIN32)
+  file_status(file_type Type, perms Perms, uint32_t LinkCount,
+              uint32_t LastAccessTimeHigh, uint32_t LastAccessTimeLow,
+              uint32_t LastWriteTimeHigh, uint32_t LastWriteTimeLow,
+              uint32_t VolumeSerialNumber, uint32_t FileSizeHigh,
+              uint32_t FileSizeLow, uint32_t FileIndexHigh,
+              uint32_t FileIndexLow)
+      : basic_file_status(Type, Perms, LastAccessTimeHigh, LastAccessTimeLow,
+                          LastWriteTimeHigh, LastWriteTimeLow, FileSizeHigh,
+                          FileSizeLow),
+        NumLinks(LinkCount), VolumeSerialNumber(VolumeSerialNumber),
+        FileIndexHigh(FileIndexHigh), FileIndexLow(FileIndexLow) {}
+  #endif
+
+  UniqueID getUniqueID() const;
+  uint32_t getLinkCount() const;
+};
+
+/// @}
+/// @name Physical Operators
+/// @{
+
+/// Make \a path an absolute path.
+///
+/// Makes \a path absolute using the \a current_directory if it is not already.
+/// An empty \a path will result in the \a current_directory.
+///
+/// /absolute/path   => /absolute/path
+/// relative/../path => <current-directory>/relative/../path
+///
+/// @param path A path that is modified to be an absolute path.
+void make_absolute(const Twine &current_directory, SmallVectorImpl<char> &path);
+
+/// Make \a path an absolute path.
+///
+/// Makes \a path absolute using the current directory if it is not already. An
+/// empty \a path will result in the current directory.
+///
+/// /absolute/path   => /absolute/path
+/// relative/../path => <current-directory>/relative/../path
+///
+/// @param path A path that is modified to be an absolute path.
+/// @returns errc::success if \a path has been made absolute, otherwise a
+///          platform-specific error_code.
+std::error_code make_absolute(SmallVectorImpl<char> &path);
+
+/// Create all the non-existent directories in path.
+///
+/// @param path Directories to create.
+/// @returns errc::success if is_directory(path), otherwise a platform
+///          specific error_code. If IgnoreExisting is false, also returns
+///          error if the directory already existed.
+std::error_code create_directories(const Twine &path,
+                                   bool IgnoreExisting = true,
+                                   perms Perms = owner_all | group_all);
+
+/// Create the directory in path.
+///
+/// @param path Directory to create.
+/// @returns errc::success if is_directory(path), otherwise a platform
+///          specific error_code. If IgnoreExisting is false, also returns
+///          error if the directory already existed.
+std::error_code create_directory(const Twine &path, bool IgnoreExisting = true,
+                                 perms Perms = owner_all | group_all);
+
+/// Create a link from \a from to \a to.
+///
+/// The link may be a soft or a hard link, depending on the platform. The caller
+/// may not assume which one. Currently on windows it creates a hard link since
+/// soft links require extra privileges. On unix, it creates a soft link since
+/// hard links don't work on SMB file systems.
+///
+/// @param to The path to hard link to.
+/// @param from The path to hard link from. This is created.
+/// @returns errc::success if the link was created, otherwise a platform
+/// specific error_code.
+std::error_code create_link(const Twine &to, const Twine &from);
+
+/// Create a hard link from \a from to \a to, or return an error.
+///
+/// @param to The path to hard link to.
+/// @param from The path to hard link from. This is created.
+/// @returns errc::success if the link was created, otherwise a platform
+/// specific error_code.
+std::error_code create_hard_link(const Twine &to, const Twine &from);
+
+/// Collapse all . and .. patterns, resolve all symlinks, and optionally
+///        expand ~ expressions to the user's home directory.
+///
+/// @param path The path to resolve.
+/// @param output The location to store the resolved path.
+/// @param expand_tilde If true, resolves ~ expressions to the user's home
+///                     directory.
+std::error_code real_path(const Twine &path, SmallVectorImpl<char> &output,
+                          bool expand_tilde = false);
+
+/// Expands ~ expressions to the user's home directory. On Unix ~user
+/// directories are resolved as well.
+///
+/// @param path The path to resolve.
+void expand_tilde(const Twine &path, SmallVectorImpl<char> &output);
+
+/// Get the current path.
+///
+/// @param result Holds the current path on return.
+/// @returns errc::success if the current path has been stored in result,
+///          otherwise a platform-specific error_code.
+std::error_code current_path(SmallVectorImpl<char> &result);
+
+/// Set the current path.
+///
+/// @param path The path to set.
+/// @returns errc::success if the current path was successfully set,
+///          otherwise a platform-specific error_code.
+std::error_code set_current_path(const Twine &path);
+
+/// Remove path. Equivalent to POSIX remove().
+///
+/// @param path Input path.
+/// @returns errc::success if path has been removed or didn't exist, otherwise a
+///          platform-specific error code. If IgnoreNonExisting is false, also
+///          returns error if the file didn't exist.
+std::error_code remove(const Twine &path, bool IgnoreNonExisting = true);
+
+/// Recursively delete a directory.
+///
+/// @param path Input path.
+/// @returns errc::success if path has been removed or didn't exist, otherwise a
+///          platform-specific error code.
+std::error_code remove_directories(const Twine &path, bool IgnoreErrors = true);
+
+/// Rename \a from to \a to.
+///
+/// Files are renamed as if by POSIX rename(), except that on Windows there may
+/// be a short interval of time during which the destination file does not
+/// exist.
+///
+/// @param from The path to rename from.
+/// @param to The path to rename to. This is created.
+std::error_code rename(const Twine &from, const Twine &to);
+
+/// Copy the contents of \a From to \a To.
+///
+/// @param From The path to copy from.
+/// @param To The path to copy to. This is created.
+std::error_code copy_file(const Twine &From, const Twine &To);
+
+/// Copy the contents of \a From to \a To.
+///
+/// @param From The path to copy from.
+/// @param ToFD The open file descriptor of the destination file.
+std::error_code copy_file(const Twine &From, int ToFD);
+
+/// Resize path to size. File is resized as if by POSIX truncate().
+///
+/// @param FD Input file descriptor.
+/// @param Size Size to resize to.
+/// @returns errc::success if \a path has been resized to \a size, otherwise a
+///          platform-specific error_code.
+std::error_code resize_file(int FD, uint64_t Size);
+
+/// Compute an MD5 hash of a file's contents.
+///
+/// @param FD Input file descriptor.
+/// @returns An MD5Result with the hash computed, if successful, otherwise a
+///          std::error_code.
+ErrorOr<MD5::MD5Result> md5_contents(int FD);
+
+/// Version of compute_md5 that doesn't require an open file descriptor.
+ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path);
+
+/// @}
+/// @name Physical Observers
+/// @{
+
+/// Does file exist?
+///
+/// @param status A basic_file_status previously returned from stat.
+/// @returns True if the file represented by status exists, false if it does
+///          not.
+bool exists(const basic_file_status &status);
+
+enum class AccessMode { Exist, Write, Execute };
+
+/// Can the file be accessed?
+///
+/// @param Path Input path.
+/// @returns errc::success if the path can be accessed, otherwise a
+///          platform-specific error_code.
+std::error_code access(const Twine &Path, AccessMode Mode);
+
+/// Does file exist?
+///
+/// @param Path Input path.
+/// @returns True if it exists, false otherwise.
+inline bool exists(const Twine &Path) {
+  return !access(Path, AccessMode::Exist);
+}
+
+/// Can we execute this file?
+///
+/// @param Path Input path.
+/// @returns True if we can execute it, false otherwise.
+bool can_execute(const Twine &Path);
+
+/// Can we write this file?
+///
+/// @param Path Input path.
+/// @returns True if we can write to it, false otherwise.
+inline bool can_write(const Twine &Path) {
+  return !access(Path, AccessMode::Write);
+}
+
+/// Do file_status's represent the same thing?
+///
+/// @param A Input file_status.
+/// @param B Input file_status.
+///
+/// assert(status_known(A) || status_known(B));
+///
+/// @returns True if A and B both represent the same file system entity, false
+///          otherwise.
+bool equivalent(file_status A, file_status B);
+
+/// Do paths represent the same thing?
+///
+/// assert(status_known(A) || status_known(B));
+///
+/// @param A Input path A.
+/// @param B Input path B.
+/// @param result Set to true if stat(A) and stat(B) have the same device and
+///               inode (or equivalent).
+/// @returns errc::success if result has been successfully set, otherwise a
+///          platform-specific error_code.
+std::error_code equivalent(const Twine &A, const Twine &B, bool &result);
+
+/// Simpler version of equivalent for clients that don't need to
+///        differentiate between an error and false.
+inline bool equivalent(const Twine &A, const Twine &B) {
+  bool result;
+  return !equivalent(A, B, result) && result;
+}
+
+/// Is the file mounted on a local filesystem?
+///
+/// @param path Input path.
+/// @param result Set to true if \a path is on fixed media such as a hard disk,
+///               false if it is not.
+/// @returns errc::success if result has been successfully set, otherwise a
+///          platform specific error_code.
+std::error_code is_local(const Twine &path, bool &result);
+
+/// Version of is_local accepting an open file descriptor.
+std::error_code is_local(int FD, bool &result);
+
+/// Simpler version of is_local for clients that don't need to
+///        differentiate between an error and false.
+inline bool is_local(const Twine &Path) {
+  bool Result;
+  return !is_local(Path, Result) && Result;
+}
+
+/// Simpler version of is_local accepting an open file descriptor for
+///        clients that don't need to differentiate between an error and false.
+inline bool is_local(int FD) {
+  bool Result;
+  return !is_local(FD, Result) && Result;
+}
+
+/// Does status represent a directory?
+///
+/// @param Path The path to get the type of.
+/// @param Follow For symbolic links, indicates whether to return the file type
+///               of the link itself, or of the target.
+/// @returns A value from the file_type enumeration indicating the type of file.
+file_type get_file_type(const Twine &Path, bool Follow = true);
+
+/// Does status represent a directory?
+///
+/// @param status A basic_file_status previously returned from status.
+/// @returns status.type() == file_type::directory_file.
+bool is_directory(const basic_file_status &status);
+
+/// Is path a directory?
+///
+/// @param path Input path.
+/// @param result Set to true if \a path is a directory (after following
+///               symlinks, false if it is not. Undefined otherwise.
+/// @returns errc::success if result has been successfully set, otherwise a
+///          platform-specific error_code.
+std::error_code is_directory(const Twine &path, bool &result);
+
+/// Simpler version of is_directory for clients that don't need to
+///        differentiate between an error and false.
+inline bool is_directory(const Twine &Path) {
+  bool Result;
+  return !is_directory(Path, Result) && Result;
+}
+
+/// Does status represent a regular file?
+///
+/// @param status A basic_file_status previously returned from status.
+/// @returns status_known(status) && status.type() == file_type::regular_file.
+bool is_regular_file(const basic_file_status &status);
+
+/// Is path a regular file?
+///
+/// @param path Input path.
+/// @param result Set to true if \a path is a regular file (after following
+///               symlinks), false if it is not. Undefined otherwise.
+/// @returns errc::success if result has been successfully set, otherwise a
+///          platform-specific error_code.
+std::error_code is_regular_file(const Twine &path, bool &result);
+
+/// Simpler version of is_regular_file for clients that don't need to
+///        differentiate between an error and false.
+inline bool is_regular_file(const Twine &Path) {
+  bool Result;
+  if (is_regular_file(Path, Result))
+    return false;
+  return Result;
+}
+
+/// Does status represent a symlink file?
+///
+/// @param status A basic_file_status previously returned from status.
+/// @returns status_known(status) && status.type() == file_type::symlink_file.
+bool is_symlink_file(const basic_file_status &status);
+
+/// Is path a symlink file?
+///
+/// @param path Input path.
+/// @param result Set to true if \a path is a symlink file, false if it is not.
+///               Undefined otherwise.
+/// @returns errc::success if result has been successfully set, otherwise a
+///          platform-specific error_code.
+std::error_code is_symlink_file(const Twine &path, bool &result);
+
+/// Simpler version of is_symlink_file for clients that don't need to
+///        differentiate between an error and false.
+inline bool is_symlink_file(const Twine &Path) {
+  bool Result;
+  if (is_symlink_file(Path, Result))
+    return false;
+  return Result;
+}
+
+/// Does this status represent something that exists but is not a
+///        directory or regular file?
+///
+/// @param status A basic_file_status previously returned from status.
+/// @returns exists(s) && !is_regular_file(s) && !is_directory(s)
+bool is_other(const basic_file_status &status);
+
+/// Is path something that exists but is not a directory,
+///        regular file, or symlink?
+///
+/// @param path Input path.
+/// @param result Set to true if \a path exists, but is not a directory, regular
+///               file, or a symlink, false if it does not. Undefined otherwise.
+/// @returns errc::success if result has been successfully set, otherwise a
+///          platform-specific error_code.
+std::error_code is_other(const Twine &path, bool &result);
+
+/// Get file status as if by POSIX stat().
+///
+/// @param path Input path.
+/// @param result Set to the file status.
+/// @param follow When true, follows symlinks.  Otherwise, the symlink itself is
+///               statted.
+/// @returns errc::success if result has been successfully set, otherwise a
+///          platform-specific error_code.
+std::error_code status(const Twine &path, file_status &result,
+                       bool follow = true);
+
+/// A version for when a file descriptor is already available.
+std::error_code status(int FD, file_status &Result);
+
+#ifdef _WIN32
+/// A version for when a file descriptor is already available.
+std::error_code status(file_t FD, file_status &Result);
+#endif
+
+/// Get file creation mode mask of the process.
+///
+/// @returns Mask reported by umask(2)
+/// @note There is no umask on Windows. This function returns 0 always
+///       on Windows. This function does not return an error_code because
+///       umask(2) never fails. It is not thread safe.
+unsigned getUmask();
+
+/// Set file permissions.
+///
+/// @param Path File to set permissions on.
+/// @param Permissions New file permissions.
+/// @returns errc::success if the permissions were successfully set, otherwise
+///          a platform-specific error_code.
+/// @note On Windows, all permissions except *_write are ignored. Using any of
+///       owner_write, group_write, or all_write will make the file writable.
+///       Otherwise, the file will be marked as read-only.
+std::error_code setPermissions(const Twine &Path, perms Permissions);
+
+/// Vesion of setPermissions accepting a file descriptor.
+/// TODO Delete the path based overload once we implement the FD based overload
+/// on Windows.
+std::error_code setPermissions(int FD, perms Permissions);
+
+/// Get file permissions.
+///
+/// @param Path File to get permissions from.
+/// @returns the permissions if they were successfully retrieved, otherwise a
+///          platform-specific error_code.
+/// @note On Windows, if the file does not have the FILE_ATTRIBUTE_READONLY
+///       attribute, all_all will be returned. Otherwise, all_read | all_exe
+///       will be returned.
+ErrorOr<perms> getPermissions(const Twine &Path);
+
+/// Get file size.
+///
+/// @param Path Input path.
+/// @param Result Set to the size of the file in \a Path.
+/// @returns errc::success if result has been successfully set, otherwise a
+///          platform-specific error_code.
+inline std::error_code file_size(const Twine &Path, uint64_t &Result) {
+  file_status Status;
+  std::error_code EC = status(Path, Status);
+  if (EC)
+    return EC;
+  Result = Status.getSize();
+  return std::error_code();
+}
+
+/// Set the file modification and access time.
+///
+/// @returns errc::success if the file times were successfully set, otherwise a
+///          platform-specific error_code or errc::function_not_supported on
+///          platforms where the functionality isn't available.
+std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime,
+                                                 TimePoint<> ModificationTime);
+
+/// Simpler version that sets both file modification and access time to the same
+/// time.
+inline std::error_code setLastAccessAndModificationTime(int FD,
+                                                        TimePoint<> Time) {
+  return setLastAccessAndModificationTime(FD, Time, Time);
+}
+
+/// Is status available?
+///
+/// @param s Input file status.
+/// @returns True if status() != status_error.
+bool status_known(const basic_file_status &s);
+
+/// Is status available?
+///
+/// @param path Input path.
+/// @param result Set to true if status() != status_error.
+/// @returns errc::success if result has been successfully set, otherwise a
+///          platform-specific error_code.
+std::error_code status_known(const Twine &path, bool &result);
+
+enum CreationDisposition : unsigned {
+  /// CD_CreateAlways - When opening a file:
+  ///   * If it already exists, truncate it.
+  ///   * If it does not already exist, create a new file.
+  CD_CreateAlways = 0,
+
+  /// CD_CreateNew - When opening a file:
+  ///   * If it already exists, fail.
+  ///   * If it does not already exist, create a new file.
+  CD_CreateNew = 1,
+
+  /// CD_OpenExisting - When opening a file:
+  ///   * If it already exists, open the file with the offset set to 0.
+  ///   * If it does not already exist, fail.
+  CD_OpenExisting = 2,
+
+  /// CD_OpenAlways - When opening a file:
+  ///   * If it already exists, open the file with the offset set to 0.
+  ///   * If it does not already exist, create a new file.
+  CD_OpenAlways = 3,
+};
+
+enum FileAccess : unsigned {
+  FA_Read = 1,
+  FA_Write = 2,
+};
+
+enum OpenFlags : unsigned {
+  OF_None = 0,
+  F_None = 0, // For compatibility
+
+  /// The file should be opened in text mode on platforms that make this
+  /// distinction.
+  OF_Text = 1,
+  F_Text = 1, // For compatibility
+
+  /// The file should be opened in append mode.
+  OF_Append = 2,
+  F_Append = 2, // For compatibility
+
+  /// Delete the file on close. Only makes a difference on windows.
+  OF_Delete = 4,
+
+  /// When a child process is launched, this file should remain open in the
+  /// child process.
+  OF_ChildInherit = 8,
+
+  /// Force files Atime to be updated on access. Only makes a difference on windows.
+  OF_UpdateAtime = 16,
+};
+
+/// Create a potentially unique file name but does not create it.
+///
+/// Generates a unique path suitable for a temporary file but does not
+/// open or create the file. The name is based on \a Model with '%'
+/// replaced by a random char in [0-9a-f]. If \a MakeAbsolute is true
+/// then the system's temp directory is prepended first. If \a MakeAbsolute
+/// is false the current directory will be used instead.
+///
+/// This function does not check if the file exists. If you want to be sure
+/// that the file does not yet exist, you should use use enough '%' characters
+/// in your model to ensure this. Each '%' gives 4-bits of entropy so you can
+/// use 32 of them to get 128 bits of entropy.
+///
+/// Example: clang-%%-%%-%%-%%-%%.s => clang-a0-b1-c2-d3-e4.s
+///
+/// @param Model Name to base unique path off of.
+/// @param ResultPath Set to the file's path.
+/// @param MakeAbsolute Whether to use the system temp directory.
+void createUniquePath(const Twine &Model, SmallVectorImpl<char> &ResultPath,
+                      bool MakeAbsolute);
+
+/// Create a uniquely named file.
+///
+/// Generates a unique path suitable for a temporary file and then opens it as a
+/// file. The name is based on \a Model with '%' replaced by a random char in
+/// [0-9a-f]. If \a Model is not an absolute path, the temporary file will be
+/// created in the current directory.
+///
+/// Example: clang-%%-%%-%%-%%-%%.s => clang-a0-b1-c2-d3-e4.s
+///
+/// This is an atomic operation. Either the file is created and opened, or the
+/// file system is left untouched.
+///
+/// The intended use is for files that are to be kept, possibly after
+/// renaming them. For example, when running 'clang -c foo.o', the file can
+/// be first created as foo-abc123.o and then renamed.
+///
+/// @param Model Name to base unique path off of.
+/// @param ResultFD Set to the opened file's file descriptor.
+/// @param ResultPath Set to the opened file's absolute path.
+/// @returns errc::success if Result{FD,Path} have been successfully set,
+///          otherwise a platform-specific error_code.
+std::error_code createUniqueFile(const Twine &Model, int &ResultFD,
+                                 SmallVectorImpl<char> &ResultPath,
+                                 unsigned Mode = all_read | all_write);
+
+/// Simpler version for clients that don't want an open file. An empty
+/// file will still be created.
+std::error_code createUniqueFile(const Twine &Model,
+                                 SmallVectorImpl<char> &ResultPath,
+                                 unsigned Mode = all_read | all_write);
+
+/// Represents a temporary file.
+///
+/// The temporary file must be eventually discarded or given a final name and
+/// kept.
+///
+/// The destructor doesn't implicitly discard because there is no way to
+/// properly handle errors in a destructor.
+class TempFile {
+  bool Done = false;
+  TempFile(StringRef Name, int FD);
+
+public:
+  /// This creates a temporary file with createUniqueFile and schedules it for
+  /// deletion with sys::RemoveFileOnSignal.
+  static Expected<TempFile> create(const Twine &Model,
+                                   unsigned Mode = all_read | all_write);
+  TempFile(TempFile &&Other);
+  TempFile &operator=(TempFile &&Other);
+
+  // Name of the temporary file.
+  std::string TmpName;
+
+  // The open file descriptor.
+  int FD = -1;
+
+  // Keep this with the given name.
+  Error keep(const Twine &Name);
+
+  // Keep this with the temporary name.
+  Error keep();
+
+  // Delete the file.
+  Error discard();
+
+  // This checks that keep or delete was called.
+  ~TempFile();
+};
+
+/// Create a file in the system temporary directory.
+///
+/// The filename is of the form prefix-random_chars.suffix. Since the directory
+/// is not know to the caller, Prefix and Suffix cannot have path separators.
+/// The files are created with mode 0600.
+///
+/// This should be used for things like a temporary .s that is removed after
+/// running the assembler.
+std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
+                                    int &ResultFD,
+                                    SmallVectorImpl<char> &ResultPath);
+
+/// Simpler version for clients that don't want an open file. An empty
+/// file will still be created.
+std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
+                                    SmallVectorImpl<char> &ResultPath);
+
+std::error_code createUniqueDirectory(const Twine &Prefix,
+                                      SmallVectorImpl<char> &ResultPath);
+
+/// Get a unique name, not currently exisiting in the filesystem. Subject
+/// to race conditions, prefer to use createUniqueFile instead.
+///
+/// Similar to createUniqueFile, but instead of creating a file only
+/// checks if it exists. This function is subject to race conditions, if you
+/// want to use the returned name to actually create a file, use
+/// createUniqueFile instead.
+std::error_code getPotentiallyUniqueFileName(const Twine &Model,
+                                             SmallVectorImpl<char> &ResultPath);
+
+/// Get a unique temporary file name, not currently exisiting in the
+/// filesystem. Subject to race conditions, prefer to use createTemporaryFile
+/// instead.
+///
+/// Similar to createTemporaryFile, but instead of creating a file only
+/// checks if it exists. This function is subject to race conditions, if you
+/// want to use the returned name to actually create a file, use
+/// createTemporaryFile instead.
+std::error_code
+getPotentiallyUniqueTempFileName(const Twine &Prefix, StringRef Suffix,
+                                 SmallVectorImpl<char> &ResultPath);
+
+inline OpenFlags operator|(OpenFlags A, OpenFlags B) {
+  return OpenFlags(unsigned(A) | unsigned(B));
+}
+
+inline OpenFlags &operator|=(OpenFlags &A, OpenFlags B) {
+  A = A | B;
+  return A;
+}
+
+inline FileAccess operator|(FileAccess A, FileAccess B) {
+  return FileAccess(unsigned(A) | unsigned(B));
+}
+
+inline FileAccess &operator|=(FileAccess &A, FileAccess B) {
+  A = A | B;
+  return A;
+}
+
+/// @brief Opens a file with the specified creation disposition, access mode,
+/// and flags and returns a file descriptor.
+///
+/// The caller is responsible for closing the file descriptor once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param ResultFD If the file could be opened successfully, its descriptor
+///                 is stored in this location. Otherwise, this is set to -1.
+/// @param Disp Value specifying the existing-file behavior.
+/// @param Access Value specifying whether to open the file in read, write, or
+///               read-write mode.
+/// @param Flags Additional flags.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns errc::success if \a Name has been opened, otherwise a
+///          platform-specific error_code.
+std::error_code openFile(const Twine &Name, int &ResultFD,
+                         CreationDisposition Disp, FileAccess Access,
+                         OpenFlags Flags, unsigned Mode = 0666);
+
+/// @brief Opens a file with the specified creation disposition, access mode,
+/// and flags and returns a platform-specific file object.
+///
+/// The caller is responsible for closing the file object once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param Disp Value specifying the existing-file behavior.
+/// @param Access Value specifying whether to open the file in read, write, or
+///               read-write mode.
+/// @param Flags Additional flags.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns errc::success if \a Name has been opened, otherwise a
+///          platform-specific error_code.
+Expected<file_t> openNativeFile(const Twine &Name, CreationDisposition Disp,
+                                FileAccess Access, OpenFlags Flags,
+                                unsigned Mode = 0666);
+
+/// Converts from a Posix file descriptor number to a native file handle.
+/// On Windows, this retreives the underlying handle. On non-Windows, this is a
+/// no-op.
+file_t convertFDToNativeFile(int FD);
+
+#ifndef _WIN32
+inline file_t convertFDToNativeFile(int FD) { return FD; }
+#endif
+
+/// Return an open handle to standard in. On Unix, this is typically FD 0.
+/// Returns kInvalidFile when the stream is closed.
+file_t getStdinHandle();
+
+/// Return an open handle to standard out. On Unix, this is typically FD 1.
+/// Returns kInvalidFile when the stream is closed.
+file_t getStdoutHandle();
+
+/// Return an open handle to standard error. On Unix, this is typically FD 2.
+/// Returns kInvalidFile when the stream is closed.
+file_t getStderrHandle();
+
+/// Reads \p Buf.size() bytes from \p FileHandle into \p Buf. Returns the number
+/// of bytes actually read. On Unix, this is equivalent to `return ::read(FD,
+/// Buf.data(), Buf.size())`, with error reporting. Returns 0 when reaching EOF.
+///
+/// @param FileHandle File to read from.
+/// @param Buf Buffer to read into.
+/// @returns The number of bytes read, or error.
+Expected<size_t> readNativeFile(file_t FileHandle, MutableArrayRef<char> Buf);
+
+/// Reads \p Buf.size() bytes from \p FileHandle at offset \p Offset into \p
+/// Buf. If 'pread' is available, this will use that, otherwise it will use
+/// 'lseek'. Returns the number of bytes actually read. Returns 0 when reaching
+/// EOF.
+///
+/// @param FileHandle File to read from.
+/// @param Buf Buffer to read into.
+/// @param Offset Offset into the file at which the read should occur.
+/// @returns The number of bytes read, or error.
+Expected<size_t> readNativeFileSlice(file_t FileHandle,
+                                     MutableArrayRef<char> Buf,
+                                     uint64_t Offset);
+
+/// @brief Opens the file with the given name in a write-only or read-write
+/// mode, returning its open file descriptor. If the file does not exist, it
+/// is created.
+///
+/// The caller is responsible for closing the file descriptor once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param ResultFD If the file could be opened successfully, its descriptor
+///                 is stored in this location. Otherwise, this is set to -1.
+/// @param Flags Additional flags used to determine whether the file should be
+///              opened in, for example, read-write or in write-only mode.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns errc::success if \a Name has been opened, otherwise a
+///          platform-specific error_code.
+inline std::error_code
+openFileForWrite(const Twine &Name, int &ResultFD,
+                 CreationDisposition Disp = CD_CreateAlways,
+                 OpenFlags Flags = OF_None, unsigned Mode = 0666) {
+  return openFile(Name, ResultFD, Disp, FA_Write, Flags, Mode);
+}
+
+/// @brief Opens the file with the given name in a write-only or read-write
+/// mode, returning its open file descriptor. If the file does not exist, it
+/// is created.
+///
+/// The caller is responsible for closing the freeing the file once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param Flags Additional flags used to determine whether the file should be
+///              opened in, for example, read-write or in write-only mode.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns a platform-specific file descriptor if \a Name has been opened,
+///          otherwise an error object.
+inline Expected<file_t> openNativeFileForWrite(const Twine &Name,
+                                               CreationDisposition Disp,
+                                               OpenFlags Flags,
+                                               unsigned Mode = 0666) {
+  return openNativeFile(Name, Disp, FA_Write, Flags, Mode);
+}
+
+/// @brief Opens the file with the given name in a write-only or read-write
+/// mode, returning its open file descriptor. If the file does not exist, it
+/// is created.
+///
+/// The caller is responsible for closing the file descriptor once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param ResultFD If the file could be opened successfully, its descriptor
+///                 is stored in this location. Otherwise, this is set to -1.
+/// @param Flags Additional flags used to determine whether the file should be
+///              opened in, for example, read-write or in write-only mode.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns errc::success if \a Name has been opened, otherwise a
+///          platform-specific error_code.
+inline std::error_code openFileForReadWrite(const Twine &Name, int &ResultFD,
+                                            CreationDisposition Disp,
+                                            OpenFlags Flags,
+                                            unsigned Mode = 0666) {
+  return openFile(Name, ResultFD, Disp, FA_Write | FA_Read, Flags, Mode);
+}
+
+/// @brief Opens the file with the given name in a write-only or read-write
+/// mode, returning its open file descriptor. If the file does not exist, it
+/// is created.
+///
+/// The caller is responsible for closing the freeing the file once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param Flags Additional flags used to determine whether the file should be
+///              opened in, for example, read-write or in write-only mode.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns a platform-specific file descriptor if \a Name has been opened,
+///          otherwise an error object.
+inline Expected<file_t> openNativeFileForReadWrite(const Twine &Name,
+                                                   CreationDisposition Disp,
+                                                   OpenFlags Flags,
+                                                   unsigned Mode = 0666) {
+  return openNativeFile(Name, Disp, FA_Write | FA_Read, Flags, Mode);
+}
+
+/// @brief Opens the file with the given name in a read-only mode, returning
+/// its open file descriptor.
+///
+/// The caller is responsible for closing the file descriptor once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param ResultFD If the file could be opened successfully, its descriptor
+///                 is stored in this location. Otherwise, this is set to -1.
+/// @param RealPath If nonnull, extra work is done to determine the real path
+///                 of the opened file, and that path is stored in this
+///                 location.
+/// @returns errc::success if \a Name has been opened, otherwise a
+///          platform-specific error_code.
+std::error_code openFileForRead(const Twine &Name, int &ResultFD,
+                                OpenFlags Flags = OF_None,
+                                SmallVectorImpl<char> *RealPath = nullptr);
+
+/// @brief Opens the file with the given name in a read-only mode, returning
+/// its open file descriptor.
+///
+/// The caller is responsible for closing the freeing the file once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param RealPath If nonnull, extra work is done to determine the real path
+///                 of the opened file, and that path is stored in this
+///                 location.
+/// @returns a platform-specific file descriptor if \a Name has been opened,
+///          otherwise an error object.
+Expected<file_t>
+openNativeFileForRead(const Twine &Name, OpenFlags Flags = OF_None,
+                      SmallVectorImpl<char> *RealPath = nullptr);
+
+/// @brief Close the file object.  This should be used instead of ::close for
+/// portability. On error, the caller should assume the file is closed, as is
+/// the case for Process::SafelyCloseFileDescriptor
+///
+/// @param F On input, this is the file to close.  On output, the file is
+/// set to kInvalidFile.
+///
+/// @returns An error code if closing the file failed. Typically, an error here
+/// means that the filesystem may have failed to perform some buffered writes.
+std::error_code closeFile(file_t &F);
+
+std::error_code getUniqueID(const Twine Path, UniqueID &Result);
+
+/// Get disk space usage information.
+///
+/// Note: Users must be careful about "Time Of Check, Time Of Use" kind of bug.
+/// Note: Windows reports results according to the quota allocated to the user.
+///
+/// @param Path Input path.
+/// @returns a space_info structure filled with the capacity, free, and
+/// available space on the device \a Path is on. A platform specific error_code
+/// is returned on error.
+ErrorOr<space_info> disk_space(const Twine &Path);
+
+/// This class represents a memory mapped file. It is based on
+/// boost::iostreams::mapped_file.
+class mapped_file_region {
+public:
+  enum mapmode {
+    readonly, ///< May only access map via const_data as read only.
+    readwrite, ///< May access map via data and modify it. Written to path.
+    priv ///< May modify via data, but changes are lost on destruction.
+  };
+
+private:
+  /// Platform-specific mapping state.
+  size_t Size;
+  void *Mapping;
+#ifdef _WIN32
+  sys::fs::file_t FileHandle;
+#endif
+  mapmode Mode;
+
+  std::error_code init(sys::fs::file_t FD, uint64_t Offset, mapmode Mode);
+
+public:
+  mapped_file_region() = delete;
+  mapped_file_region(mapped_file_region&) = delete;
+  mapped_file_region &operator =(mapped_file_region&) = delete;
+
+  /// \param fd An open file descriptor to map. Does not take ownership of fd.
+  mapped_file_region(sys::fs::file_t fd, mapmode mode, size_t length, uint64_t offset,
+                     std::error_code &ec);
+
+  ~mapped_file_region();
+
+  size_t size() const;
+  char *data() const;
+
+  /// Get a const view of the data. Modifying this memory has undefined
+  /// behavior.
+  const char *const_data() const;
+
+  /// \returns The minimum alignment offset must be.
+  static int alignment();
+};
+
+/// Return the path to the main executable, given the value of argv[0] from
+/// program startup and the address of main itself. In extremis, this function
+/// may fail and return an empty path.
+std::string getMainExecutable(const char *argv0, void *MainExecAddr);
+
+/// @}
+/// @name Iterators
+/// @{
+
+/// directory_entry - A single entry in a directory.
+class directory_entry {
+  // FIXME: different platforms make different information available "for free"
+  // when traversing a directory. The design of this class wraps most of the
+  // information in basic_file_status, so on platforms where we can't populate
+  // that whole structure, callers end up paying for a stat().
+  // std::filesystem::directory_entry may be a better model.
+  std::string Path;
+  file_type Type = file_type::type_unknown; // Most platforms can provide this.
+  bool FollowSymlinks = true;               // Affects the behavior of status().
+  basic_file_status Status;                 // If available.
+
+public:
+  explicit directory_entry(const Twine &Path, bool FollowSymlinks = true,
+                           file_type Type = file_type::type_unknown,
+                           basic_file_status Status = basic_file_status())
+      : Path(Path.str()), Type(Type), FollowSymlinks(FollowSymlinks),
+        Status(Status) {}
+
+  directory_entry() = default;
+
+  void replace_filename(const Twine &Filename, file_type Type,
+                        basic_file_status Status = basic_file_status());
+
+  const std::string &path() const { return Path; }
+  // Get basic information about entry file (a subset of fs::status()).
+  // On most platforms this is a stat() call.
+  // On windows the information was already retrieved from the directory.
+  ErrorOr<basic_file_status> status() const;
+  // Get the type of this file.
+  // On most platforms (Linux/Mac/Windows/BSD), this was already retrieved.
+  // On some platforms (e.g. Solaris) this is a stat() call.
+  file_type type() const {
+    if (Type != file_type::type_unknown)
+      return Type;
+    auto S = status();
+    return S ? S->type() : file_type::type_unknown;
+  }
+
+  bool operator==(const directory_entry& RHS) const { return Path == RHS.Path; }
+  bool operator!=(const directory_entry& RHS) const { return !(*this == RHS); }
+  bool operator< (const directory_entry& RHS) const;
+  bool operator<=(const directory_entry& RHS) const;
+  bool operator> (const directory_entry& RHS) const;
+  bool operator>=(const directory_entry& RHS) const;
+};
+
+namespace detail {
+
+  struct DirIterState;
+
+  std::error_code directory_iterator_construct(DirIterState &, StringRef, bool);
+  std::error_code directory_iterator_increment(DirIterState &);
+  std::error_code directory_iterator_destruct(DirIterState &);
+
+  /// Keeps state for the directory_iterator.
+  struct DirIterState {
+    ~DirIterState() {
+      directory_iterator_destruct(*this);
+    }
+
+    intptr_t IterationHandle = 0;
+    directory_entry CurrentEntry;
+  };
+
+} // end namespace detail
+
+/// directory_iterator - Iterates through the entries in path. There is no
+/// operator++ because we need an error_code. If it's really needed we can make
+/// it call report_fatal_error on error.
+class directory_iterator {
+  std::shared_ptr<detail::DirIterState> State;
+  bool FollowSymlinks = true;
+
+public:
+  explicit directory_iterator(const Twine &path, std::error_code &ec,
+                              bool follow_symlinks = true)
+      : FollowSymlinks(follow_symlinks) {
+    State = std::make_shared<detail::DirIterState>();
+    SmallString<128> path_storage;
+    ec = detail::directory_iterator_construct(
+        *State, path.toStringRef(path_storage), FollowSymlinks);
+  }
+
+  explicit directory_iterator(const directory_entry &de, std::error_code &ec,
+                              bool follow_symlinks = true)
+      : FollowSymlinks(follow_symlinks) {
+    State = std::make_shared<detail::DirIterState>();
+    ec = detail::directory_iterator_construct(
+        *State, de.path(), FollowSymlinks);
+  }
+
+  /// Construct end iterator.
+  directory_iterator() = default;
+
+  // No operator++ because we need error_code.
+  directory_iterator &increment(std::error_code &ec) {
+    ec = directory_iterator_increment(*State);
+    return *this;
+  }
+
+  const directory_entry &operator*() const { return State->CurrentEntry; }
+  const directory_entry *operator->() const { return &State->CurrentEntry; }
+
+  bool operator==(const directory_iterator &RHS) const {
+    if (State == RHS.State)
+      return true;
+    if (!RHS.State)
+      return State->CurrentEntry == directory_entry();
+    if (!State)
+      return RHS.State->CurrentEntry == directory_entry();
+    return State->CurrentEntry == RHS.State->CurrentEntry;
+  }
+
+  bool operator!=(const directory_iterator &RHS) const {
+    return !(*this == RHS);
+  }
+};
+
+namespace detail {
+
+  /// Keeps state for the recursive_directory_iterator.
+  struct RecDirIterState {
+    std::stack<directory_iterator, std::vector<directory_iterator>> Stack;
+    uint16_t Level = 0;
+    bool HasNoPushRequest = false;
+  };
+
+} // end namespace detail
+
+/// recursive_directory_iterator - Same as directory_iterator except for it
+/// recurses down into child directories.
+class recursive_directory_iterator {
+  std::shared_ptr<detail::RecDirIterState> State;
+  bool Follow;
+
+public:
+  recursive_directory_iterator() = default;
+  explicit recursive_directory_iterator(const Twine &path, std::error_code &ec,
+                                        bool follow_symlinks = true)
+      : State(std::make_shared<detail::RecDirIterState>()),
+        Follow(follow_symlinks) {
+    State->Stack.push(directory_iterator(path, ec, Follow));
+    if (State->Stack.top() == directory_iterator())
+      State.reset();
+  }
+
+  // No operator++ because we need error_code.
+  recursive_directory_iterator &increment(std::error_code &ec) {
+    const directory_iterator end_itr = {};
+
+    if (State->HasNoPushRequest)
+      State->HasNoPushRequest = false;
+    else {
+      file_type type = State->Stack.top()->type();
+      if (type == file_type::symlink_file && Follow) {
+        // Resolve the symlink: is it a directory to recurse into?
+        ErrorOr<basic_file_status> status = State->Stack.top()->status();
+        if (status)
+          type = status->type();
+        // Otherwise broken symlink, and we'll continue.
+      }
+      if (type == file_type::directory_file) {
+        State->Stack.push(directory_iterator(*State->Stack.top(), ec, Follow));
+        if (State->Stack.top() != end_itr) {
+          ++State->Level;
+          return *this;
+        }
+        State->Stack.pop();
+      }
+    }
+
+    while (!State->Stack.empty()
+           && State->Stack.top().increment(ec) == end_itr) {
+      State->Stack.pop();
+      --State->Level;
+    }
+
+    // Check if we are done. If so, create an end iterator.
+    if (State->Stack.empty())
+      State.reset();
+
+    return *this;
+  }
+
+  const directory_entry &operator*() const { return *State->Stack.top(); }
+  const directory_entry *operator->() const { return &*State->Stack.top(); }
+
+  // observers
+  /// Gets the current level. Starting path is at level 0.
+  int level() const { return State->Level; }
+
+  /// Returns true if no_push has been called for this directory_entry.
+  bool no_push_request() const { return State->HasNoPushRequest; }
+
+  // modifiers
+  /// Goes up one level if Level > 0.
+  void pop() {
+    assert(State && "Cannot pop an end iterator!");
+    assert(State->Level > 0 && "Cannot pop an iterator with level < 1");
+
+    const directory_iterator end_itr = {};
+    std::error_code ec;
+    do {
+      if (ec)
+        report_fatal_error("Error incrementing directory iterator.");
+      State->Stack.pop();
+      --State->Level;
+    } while (!State->Stack.empty()
+             && State->Stack.top().increment(ec) == end_itr);
+
+    // Check if we are done. If so, create an end iterator.
+    if (State->Stack.empty())
+      State.reset();
+  }
+
+  /// Does not go down into the current directory_entry.
+  void no_push() { State->HasNoPushRequest = true; }
+
+  bool operator==(const recursive_directory_iterator &RHS) const {
+    return State == RHS.State;
+  }
+
+  bool operator!=(const recursive_directory_iterator &RHS) const {
+    return !(*this == RHS);
+  }
+};
+
+/// @}
+
+} // end namespace fs
+} // end namespace sys
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_FILESYSTEM_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Format.h b/binaryen/third_party/llvm-project/include/llvm/Support/Format.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Format.h
@@ -0,0 +1,257 @@
+//===- Format.h - Efficient printf-style formatting for streams -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the format() function, which can be used with other
+// LLVM subsystems to provide printf-style formatting.  This gives all the power
+// and risk of printf.  This can be used like this (with raw_ostreams as an
+// example):
+//
+//    OS << "mynumber: " << format("%4.5f", 1234.412) << '\n';
+//
+// Or if you prefer:
+//
+//  OS << format("mynumber: %4.5f\n", 1234.412);
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FORMAT_H
+#define LLVM_SUPPORT_FORMAT_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+#include <cassert>
+#include <cstdio>
+#include <tuple>
+#include <utility>
+
+namespace llvm {
+
+/// This is a helper class used for handling formatted output.  It is the
+/// abstract base class of a templated derived class.
+class format_object_base {
+protected:
+  const char *Fmt;
+  ~format_object_base() = default; // Disallow polymorphic deletion.
+  format_object_base(const format_object_base &) = default;
+  virtual void home(); // Out of line virtual method.
+
+  /// Call snprintf() for this object, on the given buffer and size.
+  virtual int snprint(char *Buffer, unsigned BufferSize) const = 0;
+
+public:
+  format_object_base(const char *fmt) : Fmt(fmt) {}
+
+  /// Format the object into the specified buffer.  On success, this returns
+  /// the length of the formatted string.  If the buffer is too small, this
+  /// returns a length to retry with, which will be larger than BufferSize.
+  unsigned print(char *Buffer, unsigned BufferSize) const {
+    assert(BufferSize && "Invalid buffer size!");
+
+    // Print the string, leaving room for the terminating null.
+    int N = snprint(Buffer, BufferSize);
+
+    // VC++ and old GlibC return negative on overflow, just double the size.
+    if (N < 0)
+      return BufferSize * 2;
+
+    // Other implementations yield number of bytes needed, not including the
+    // final '\0'.
+    if (unsigned(N) >= BufferSize)
+      return N + 1;
+
+    // Otherwise N is the length of output (not including the final '\0').
+    return N;
+  }
+};
+
+/// These are templated helper classes used by the format function that
+/// capture the object to be formatted and the format string. When actually
+/// printed, this synthesizes the string into a temporary buffer provided and
+/// returns whether or not it is big enough.
+
+// Helper to validate that format() parameters are scalars or pointers.
+template <typename... Args> struct validate_format_parameters;
+template <typename Arg, typename... Args>
+struct validate_format_parameters<Arg, Args...> {
+  static_assert(std::is_scalar<Arg>::value,
+                "format can't be used with non fundamental / non pointer type");
+  validate_format_parameters() { validate_format_parameters<Args...>(); }
+};
+template <> struct validate_format_parameters<> {};
+
+template <typename... Ts>
+class format_object final : public format_object_base {
+  std::tuple<Ts...> Vals;
+
+  template <std::size_t... Is>
+  int snprint_tuple(char *Buffer, unsigned BufferSize,
+                    std::index_sequence<Is...>) const {
+#ifdef _MSC_VER
+    return _snprintf(Buffer, BufferSize, Fmt, std::get<Is>(Vals)...);
+#else
+    return snprintf(Buffer, BufferSize, Fmt, std::get<Is>(Vals)...);
+#endif
+  }
+
+public:
+  format_object(const char *fmt, const Ts &... vals)
+      : format_object_base(fmt), Vals(vals...) {
+    validate_format_parameters<Ts...>();
+  }
+
+  int snprint(char *Buffer, unsigned BufferSize) const override {
+    return snprint_tuple(Buffer, BufferSize, std::index_sequence_for<Ts...>());
+  }
+};
+
+/// These are helper functions used to produce formatted output.  They use
+/// template type deduction to construct the appropriate instance of the
+/// format_object class to simplify their construction.
+///
+/// This is typically used like:
+/// \code
+///   OS << format("%0.4f", myfloat) << '\n';
+/// \endcode
+
+template <typename... Ts>
+inline format_object<Ts...> format(const char *Fmt, const Ts &... Vals) {
+  return format_object<Ts...>(Fmt, Vals...);
+}
+
+/// This is a helper class for left_justify, right_justify, and center_justify.
+class FormattedString {
+public:
+  enum Justification { JustifyNone, JustifyLeft, JustifyRight, JustifyCenter };
+  FormattedString(StringRef S, unsigned W, Justification J)
+      : Str(S), Width(W), Justify(J) {}
+
+private:
+  StringRef Str;
+  unsigned Width;
+  Justification Justify;
+  friend class raw_ostream;
+};
+
+/// left_justify - append spaces after string so total output is
+/// \p Width characters.  If \p Str is larger that \p Width, full string
+/// is written with no padding.
+inline FormattedString left_justify(StringRef Str, unsigned Width) {
+  return FormattedString(Str, Width, FormattedString::JustifyLeft);
+}
+
+/// right_justify - add spaces before string so total output is
+/// \p Width characters.  If \p Str is larger that \p Width, full string
+/// is written with no padding.
+inline FormattedString right_justify(StringRef Str, unsigned Width) {
+  return FormattedString(Str, Width, FormattedString::JustifyRight);
+}
+
+/// center_justify - add spaces before and after string so total output is
+/// \p Width characters.  If \p Str is larger that \p Width, full string
+/// is written with no padding.
+inline FormattedString center_justify(StringRef Str, unsigned Width) {
+  return FormattedString(Str, Width, FormattedString::JustifyCenter);
+}
+
+/// This is a helper class used for format_hex() and format_decimal().
+class FormattedNumber {
+  uint64_t HexValue;
+  int64_t DecValue;
+  unsigned Width;
+  bool Hex;
+  bool Upper;
+  bool HexPrefix;
+  friend class raw_ostream;
+
+public:
+  FormattedNumber(uint64_t HV, int64_t DV, unsigned W, bool H, bool U,
+                  bool Prefix)
+      : HexValue(HV), DecValue(DV), Width(W), Hex(H), Upper(U),
+        HexPrefix(Prefix) {}
+};
+
+/// format_hex - Output \p N as a fixed width hexadecimal. If number will not
+/// fit in width, full number is still printed.  Examples:
+///   OS << format_hex(255, 4)              => 0xff
+///   OS << format_hex(255, 4, true)        => 0xFF
+///   OS << format_hex(255, 6)              => 0x00ff
+///   OS << format_hex(255, 2)              => 0xff
+inline FormattedNumber format_hex(uint64_t N, unsigned Width,
+                                  bool Upper = false) {
+  assert(Width <= 18 && "hex width must be <= 18");
+  return FormattedNumber(N, 0, Width, true, Upper, true);
+}
+
+/// format_hex_no_prefix - Output \p N as a fixed width hexadecimal. Does not
+/// prepend '0x' to the outputted string.  If number will not fit in width,
+/// full number is still printed.  Examples:
+///   OS << format_hex_no_prefix(255, 2)              => ff
+///   OS << format_hex_no_prefix(255, 2, true)        => FF
+///   OS << format_hex_no_prefix(255, 4)              => 00ff
+///   OS << format_hex_no_prefix(255, 1)              => ff
+inline FormattedNumber format_hex_no_prefix(uint64_t N, unsigned Width,
+                                            bool Upper = false) {
+  assert(Width <= 16 && "hex width must be <= 16");
+  return FormattedNumber(N, 0, Width, true, Upper, false);
+}
+
+/// format_decimal - Output \p N as a right justified, fixed-width decimal. If
+/// number will not fit in width, full number is still printed.  Examples:
+///   OS << format_decimal(0, 5)     => "    0"
+///   OS << format_decimal(255, 5)   => "  255"
+///   OS << format_decimal(-1, 3)    => " -1"
+///   OS << format_decimal(12345, 3) => "12345"
+inline FormattedNumber format_decimal(int64_t N, unsigned Width) {
+  return FormattedNumber(0, N, Width, false, false, false);
+}
+
+class FormattedBytes {
+  ArrayRef<uint8_t> Bytes;
+
+  // If not None, display offsets for each line relative to starting value.
+  Optional<uint64_t> FirstByteOffset;
+  uint32_t IndentLevel;  // Number of characters to indent each line.
+  uint32_t NumPerLine;   // Number of bytes to show per line.
+  uint8_t ByteGroupSize; // How many hex bytes are grouped without spaces
+  bool Upper;            // Show offset and hex bytes as upper case.
+  bool ASCII;            // Show the ASCII bytes for the hex bytes to the right.
+  friend class raw_ostream;
+
+public:
+  FormattedBytes(ArrayRef<uint8_t> B, uint32_t IL, Optional<uint64_t> O,
+                 uint32_t NPL, uint8_t BGS, bool U, bool A)
+      : Bytes(B), FirstByteOffset(O), IndentLevel(IL), NumPerLine(NPL),
+        ByteGroupSize(BGS), Upper(U), ASCII(A) {
+
+    if (ByteGroupSize > NumPerLine)
+      ByteGroupSize = NumPerLine;
+  }
+};
+
+inline FormattedBytes
+format_bytes(ArrayRef<uint8_t> Bytes, Optional<uint64_t> FirstByteOffset = None,
+             uint32_t NumPerLine = 16, uint8_t ByteGroupSize = 4,
+             uint32_t IndentLevel = 0, bool Upper = false) {
+  return FormattedBytes(Bytes, IndentLevel, FirstByteOffset, NumPerLine,
+                        ByteGroupSize, Upper, false);
+}
+
+inline FormattedBytes
+format_bytes_with_ascii(ArrayRef<uint8_t> Bytes,
+                        Optional<uint64_t> FirstByteOffset = None,
+                        uint32_t NumPerLine = 16, uint8_t ByteGroupSize = 4,
+                        uint32_t IndentLevel = 0, bool Upper = false) {
+  return FormattedBytes(Bytes, IndentLevel, FirstByteOffset, NumPerLine,
+                        ByteGroupSize, Upper, true);
+}
+
+} // end namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/FormatAdapters.h b/binaryen/third_party/llvm-project/include/llvm/Support/FormatAdapters.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/FormatAdapters.h
@@ -0,0 +1,108 @@
+//===- FormatAdapters.h - Formatters for common LLVM types -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FORMATADAPTERS_H
+#define LLVM_SUPPORT_FORMATADAPTERS_H
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatCommon.h"
+#include "llvm/Support/FormatVariadicDetails.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+template <typename T> class FormatAdapter : public detail::format_adapter {
+protected:
+  explicit FormatAdapter(T &&Item) : Item(std::forward<T>(Item)) {}
+
+  T Item;
+};
+
+namespace detail {
+template <typename T> class AlignAdapter final : public FormatAdapter<T> {
+  AlignStyle Where;
+  size_t Amount;
+  char Fill;
+
+public:
+  AlignAdapter(T &&Item, AlignStyle Where, size_t Amount, char Fill)
+      : FormatAdapter<T>(std::forward<T>(Item)), Where(Where), Amount(Amount),
+        Fill(Fill) {}
+
+  void format(llvm::raw_ostream &Stream, StringRef Style) {
+    auto Adapter = detail::build_format_adapter(std::forward<T>(this->Item));
+    FmtAlign(Adapter, Where, Amount, Fill).format(Stream, Style);
+  }
+};
+
+template <typename T> class PadAdapter final : public FormatAdapter<T> {
+  size_t Left;
+  size_t Right;
+
+public:
+  PadAdapter(T &&Item, size_t Left, size_t Right)
+      : FormatAdapter<T>(std::forward<T>(Item)), Left(Left), Right(Right) {}
+
+  void format(llvm::raw_ostream &Stream, StringRef Style) {
+    auto Adapter = detail::build_format_adapter(std::forward<T>(this->Item));
+    Stream.indent(Left);
+    Adapter.format(Stream, Style);
+    Stream.indent(Right);
+  }
+};
+
+template <typename T> class RepeatAdapter final : public FormatAdapter<T> {
+  size_t Count;
+
+public:
+  RepeatAdapter(T &&Item, size_t Count)
+      : FormatAdapter<T>(std::forward<T>(Item)), Count(Count) {}
+
+  void format(llvm::raw_ostream &Stream, StringRef Style) {
+    auto Adapter = detail::build_format_adapter(std::forward<T>(this->Item));
+    for (size_t I = 0; I < Count; ++I) {
+      Adapter.format(Stream, Style);
+    }
+  }
+};
+
+class ErrorAdapter : public FormatAdapter<Error> {
+public:
+  ErrorAdapter(Error &&Item) : FormatAdapter(std::move(Item)) {}
+  ErrorAdapter(ErrorAdapter &&) = default;
+  ~ErrorAdapter() { consumeError(std::move(Item)); }
+  void format(llvm::raw_ostream &Stream, StringRef Style) { Stream << Item; }
+};
+}
+
+template <typename T>
+detail::AlignAdapter<T> fmt_align(T &&Item, AlignStyle Where, size_t Amount,
+                                  char Fill = ' ') {
+  return detail::AlignAdapter<T>(std::forward<T>(Item), Where, Amount, Fill);
+}
+
+template <typename T>
+detail::PadAdapter<T> fmt_pad(T &&Item, size_t Left, size_t Right) {
+  return detail::PadAdapter<T>(std::forward<T>(Item), Left, Right);
+}
+
+template <typename T>
+detail::RepeatAdapter<T> fmt_repeat(T &&Item, size_t Count) {
+  return detail::RepeatAdapter<T>(std::forward<T>(Item), Count);
+}
+
+// llvm::Error values must be consumed before being destroyed.
+// Wrapping an error in fmt_consume explicitly indicates that the formatv_object
+// should take ownership and consume it.
+inline detail::ErrorAdapter fmt_consume(Error &&Item) {
+  return detail::ErrorAdapter(std::move(Item));
+}
+}
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/FormatCommon.h b/binaryen/third_party/llvm-project/include/llvm/Support/FormatCommon.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/FormatCommon.h
@@ -0,0 +1,76 @@
+//===- FormatCommon.h - Formatters for common LLVM types --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FORMATCOMMON_H
+#define LLVM_SUPPORT_FORMATCOMMON_H
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FormatVariadicDetails.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+enum class AlignStyle { Left, Center, Right };
+
+struct FmtAlign {
+  detail::format_adapter &Adapter;
+  AlignStyle Where;
+  size_t Amount;
+  char Fill;
+
+  FmtAlign(detail::format_adapter &Adapter, AlignStyle Where, size_t Amount,
+           char Fill = ' ')
+      : Adapter(Adapter), Where(Where), Amount(Amount), Fill(Fill) {}
+
+  void format(raw_ostream &S, StringRef Options) {
+    // If we don't need to align, we can format straight into the underlying
+    // stream.  Otherwise we have to go through an intermediate stream first
+    // in order to calculate how long the output is so we can align it.
+    // TODO: Make the format method return the number of bytes written, that
+    // way we can also skip the intermediate stream for left-aligned output.
+    if (Amount == 0) {
+      Adapter.format(S, Options);
+      return;
+    }
+    SmallString<64> Item;
+    raw_svector_ostream Stream(Item);
+
+    Adapter.format(Stream, Options);
+    if (Amount <= Item.size()) {
+      S << Item;
+      return;
+    }
+
+    size_t PadAmount = Amount - Item.size();
+    switch (Where) {
+    case AlignStyle::Left:
+      S << Item;
+      fill(S, PadAmount);
+      break;
+    case AlignStyle::Center: {
+      size_t X = PadAmount / 2;
+      fill(S, X);
+      S << Item;
+      fill(S, PadAmount - X);
+      break;
+    }
+    default:
+      fill(S, PadAmount);
+      S << Item;
+      break;
+    }
+  }
+
+private:
+  void fill(llvm::raw_ostream &S, uint32_t Count) {
+    for (uint32_t I = 0; I < Count; ++I)
+      S << Fill;
+  }
+};
+}
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/FormatProviders.h b/binaryen/third_party/llvm-project/include/llvm/Support/FormatProviders.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/FormatProviders.h
@@ -0,0 +1,422 @@
+//===- FormatProviders.h - Formatters for common LLVM types -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements format providers for many common LLVM types, for example
+// allowing precision and width specifiers for scalar and string types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FORMATPROVIDERS_H
+#define LLVM_SUPPORT_FORMATPROVIDERS_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/FormatVariadicDetails.h"
+#include "llvm/Support/NativeFormatting.h"
+
+#include <type_traits>
+#include <vector>
+
+namespace llvm {
+namespace detail {
+template <typename T>
+struct use_integral_formatter
+    : public std::integral_constant<
+          bool, is_one_of<T, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
+                          int64_t, uint64_t, int, unsigned, long, unsigned long,
+                          long long, unsigned long long>::value> {};
+
+template <typename T>
+struct use_char_formatter
+    : public std::integral_constant<bool, std::is_same<T, char>::value> {};
+
+template <typename T>
+struct is_cstring
+    : public std::integral_constant<bool,
+                                    is_one_of<T, char *, const char *>::value> {
+};
+
+template <typename T>
+struct use_string_formatter
+    : public std::integral_constant<bool,
+                                    std::is_convertible<T, llvm::StringRef>::value> {};
+
+template <typename T>
+struct use_pointer_formatter
+    : public std::integral_constant<bool, std::is_pointer<T>::value &&
+                                              !is_cstring<T>::value> {};
+
+template <typename T>
+struct use_double_formatter
+    : public std::integral_constant<bool, std::is_floating_point<T>::value> {};
+
+class HelperFunctions {
+protected:
+  static Optional<size_t> parseNumericPrecision(StringRef Str) {
+    size_t Prec;
+    Optional<size_t> Result;
+    if (Str.empty())
+      Result = None;
+    else if (Str.getAsInteger(10, Prec)) {
+      assert(false && "Invalid precision specifier");
+      Result = None;
+    } else {
+      assert(Prec < 100 && "Precision out of range");
+      Result = std::min<size_t>(99u, Prec);
+    }
+    return Result;
+  }
+
+  static bool consumeHexStyle(StringRef &Str, HexPrintStyle &Style) {
+    if (!Str.startswith_lower("x"))
+      return false;
+
+    if (Str.consume_front("x-"))
+      Style = HexPrintStyle::Lower;
+    else if (Str.consume_front("X-"))
+      Style = HexPrintStyle::Upper;
+    else if (Str.consume_front("x+") || Str.consume_front("x"))
+      Style = HexPrintStyle::PrefixLower;
+    else if (Str.consume_front("X+") || Str.consume_front("X"))
+      Style = HexPrintStyle::PrefixUpper;
+    return true;
+  }
+
+  static size_t consumeNumHexDigits(StringRef &Str, HexPrintStyle Style,
+                                    size_t Default) {
+    Str.consumeInteger(10, Default);
+    if (isPrefixedHexStyle(Style))
+      Default += 2;
+    return Default;
+  }
+};
+}
+
+/// Implementation of format_provider<T> for integral arithmetic types.
+///
+/// The options string of an integral type has the grammar:
+///
+///   integer_options   :: [style][digits]
+///   style             :: <see table below>
+///   digits            :: <non-negative integer> 0-99
+///
+///   ==========================================================================
+///   |  style  |     Meaning          |      Example     | Digits Meaning     |
+///   --------------------------------------------------------------------------
+///   |         |                      |  Input |  Output |                    |
+///   ==========================================================================
+///   |   x-    | Hex no prefix, lower |   42   |    2a   | Minimum # digits   |
+///   |   X-    | Hex no prefix, upper |   42   |    2A   | Minimum # digits   |
+///   | x+ / x  | Hex + prefix, lower  |   42   |   0x2a  | Minimum # digits   |
+///   | X+ / X  | Hex + prefix, upper  |   42   |   0x2A  | Minimum # digits   |
+///   | N / n   | Digit grouped number | 123456 | 123,456 | Ignored            |
+///   | D / d   | Integer              | 100000 | 100000  | Ignored            |
+///   | (empty) | Same as D / d        |        |         |                    |
+///   ==========================================================================
+///
+
+template <typename T>
+struct format_provider<
+    T, typename std::enable_if<detail::use_integral_formatter<T>::value>::type>
+    : public detail::HelperFunctions {
+private:
+public:
+  static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
+    HexPrintStyle HS;
+    size_t Digits = 0;
+    if (consumeHexStyle(Style, HS)) {
+      Digits = consumeNumHexDigits(Style, HS, 0);
+      write_hex(Stream, V, HS, Digits);
+      return;
+    }
+
+    IntegerStyle IS = IntegerStyle::Integer;
+    if (Style.consume_front("N") || Style.consume_front("n"))
+      IS = IntegerStyle::Number;
+    else if (Style.consume_front("D") || Style.consume_front("d"))
+      IS = IntegerStyle::Integer;
+
+    Style.consumeInteger(10, Digits);
+    assert(Style.empty() && "Invalid integral format style!");
+    write_integer(Stream, V, Digits, IS);
+  }
+};
+
+/// Implementation of format_provider<T> for integral pointer types.
+///
+/// The options string of a pointer type has the grammar:
+///
+///   pointer_options   :: [style][precision]
+///   style             :: <see table below>
+///   digits            :: <non-negative integer> 0-sizeof(void*)
+///
+///   ==========================================================================
+///   |   S     |     Meaning          |                Example                |
+///   --------------------------------------------------------------------------
+///   |         |                      |       Input       |      Output       |
+///   ==========================================================================
+///   |   x-    | Hex no prefix, lower |    0xDEADBEEF     |     deadbeef      |
+///   |   X-    | Hex no prefix, upper |    0xDEADBEEF     |     DEADBEEF      |
+///   | x+ / x  | Hex + prefix, lower  |    0xDEADBEEF     |    0xdeadbeef     |
+///   | X+ / X  | Hex + prefix, upper  |    0xDEADBEEF     |    0xDEADBEEF     |
+///   | (empty) | Same as X+ / X       |                   |                   |
+///   ==========================================================================
+///
+/// The default precision is the number of nibbles in a machine word, and in all
+/// cases indicates the minimum number of nibbles to print.
+template <typename T>
+struct format_provider<
+    T, typename std::enable_if<detail::use_pointer_formatter<T>::value>::type>
+    : public detail::HelperFunctions {
+private:
+public:
+  static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
+    HexPrintStyle HS = HexPrintStyle::PrefixUpper;
+    consumeHexStyle(Style, HS);
+    size_t Digits = consumeNumHexDigits(Style, HS, sizeof(void *) * 2);
+    write_hex(Stream, reinterpret_cast<std::uintptr_t>(V), HS, Digits);
+  }
+};
+
+/// Implementation of format_provider<T> for c-style strings and string
+/// objects such as std::string and llvm::StringRef.
+///
+/// The options string of a string type has the grammar:
+///
+///   string_options :: [length]
+///
+/// where `length` is an optional integer specifying the maximum number of
+/// characters in the string to print.  If `length` is omitted, the string is
+/// printed up to the null terminator.
+
+template <typename T>
+struct format_provider<
+    T, typename std::enable_if<detail::use_string_formatter<T>::value>::type> {
+  static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
+    size_t N = StringRef::npos;
+    if (!Style.empty() && Style.getAsInteger(10, N)) {
+      assert(false && "Style is not a valid integer");
+    }
+    llvm::StringRef S = V;
+    Stream << S.substr(0, N);
+  }
+};
+
+/// Implementation of format_provider<T> for llvm::Twine.
+///
+/// This follows the same rules as the string formatter.
+
+template <> struct format_provider<Twine> {
+  static void format(const Twine &V, llvm::raw_ostream &Stream,
+                     StringRef Style) {
+    format_provider<std::string>::format(V.str(), Stream, Style);
+  }
+};
+
+/// Implementation of format_provider<T> for characters.
+///
+/// The options string of a character type has the grammar:
+///
+///   char_options :: (empty) | [integer_options]
+///
+/// If `char_options` is empty, the character is displayed as an ASCII
+/// character.  Otherwise, it is treated as an integer options string.
+///
+template <typename T>
+struct format_provider<
+    T, typename std::enable_if<detail::use_char_formatter<T>::value>::type> {
+  static void format(const char &V, llvm::raw_ostream &Stream,
+                     StringRef Style) {
+    if (Style.empty())
+      Stream << V;
+    else {
+      int X = static_cast<int>(V);
+      format_provider<int>::format(X, Stream, Style);
+    }
+  }
+};
+
+/// Implementation of format_provider<T> for type `bool`
+///
+/// The options string of a boolean type has the grammar:
+///
+///   bool_options :: "" | "Y" | "y" | "D" | "d" | "T" | "t"
+///
+///   ==================================
+///   |    C    |     Meaning          |
+///   ==================================
+///   |    Y    |       YES / NO       |
+///   |    y    |       yes / no       |
+///   |  D / d  |    Integer 0 or 1    |
+///   |    T    |     TRUE / FALSE     |
+///   |    t    |     true / false     |
+///   | (empty) |   Equivalent to 't'  |
+///   ==================================
+template <> struct format_provider<bool> {
+  static void format(const bool &B, llvm::raw_ostream &Stream,
+                     StringRef Style) {
+    Stream << StringSwitch<const char *>(Style)
+                  .Case("Y", B ? "YES" : "NO")
+                  .Case("y", B ? "yes" : "no")
+                  .CaseLower("D", B ? "1" : "0")
+                  .Case("T", B ? "TRUE" : "FALSE")
+                  .Cases("t", "", B ? "true" : "false")
+                  .Default(B ? "1" : "0");
+  }
+};
+
+/// Implementation of format_provider<T> for floating point types.
+///
+/// The options string of a floating point type has the format:
+///
+///   float_options   :: [style][precision]
+///   style           :: <see table below>
+///   precision       :: <non-negative integer> 0-99
+///
+///   =====================================================
+///   |  style  |     Meaning          |      Example     |
+///   -----------------------------------------------------
+///   |         |                      |  Input |  Output |
+///   =====================================================
+///   | P / p   | Percentage           |  0.05  |  5.00%  |
+///   | F / f   | Fixed point          |   1.0  |  1.00   |
+///   |   E     | Exponential with E   | 100000 | 1.0E+05 |
+///   |   e     | Exponential with e   | 100000 | 1.0e+05 |
+///   | (empty) | Same as F / f        |        |         |
+///   =====================================================
+///
+/// The default precision is 6 for exponential (E / e) and 2 for everything
+/// else.
+
+template <typename T>
+struct format_provider<
+    T, typename std::enable_if<detail::use_double_formatter<T>::value>::type>
+    : public detail::HelperFunctions {
+  static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
+    FloatStyle S;
+    if (Style.consume_front("P") || Style.consume_front("p"))
+      S = FloatStyle::Percent;
+    else if (Style.consume_front("F") || Style.consume_front("f"))
+      S = FloatStyle::Fixed;
+    else if (Style.consume_front("E"))
+      S = FloatStyle::ExponentUpper;
+    else if (Style.consume_front("e"))
+      S = FloatStyle::Exponent;
+    else
+      S = FloatStyle::Fixed;
+
+    Optional<size_t> Precision = parseNumericPrecision(Style);
+    if (!Precision.hasValue())
+      Precision = getDefaultPrecision(S);
+
+    write_double(Stream, static_cast<double>(V), S, Precision);
+  }
+};
+
+namespace detail {
+template <typename IterT>
+using IterValue = typename std::iterator_traits<IterT>::value_type;
+
+template <typename IterT>
+struct range_item_has_provider
+    : public std::integral_constant<
+          bool, !uses_missing_provider<IterValue<IterT>>::value> {};
+}
+
+/// Implementation of format_provider<T> for ranges.
+///
+/// This will print an arbitrary range as a delimited sequence of items.
+///
+/// The options string of a range type has the grammar:
+///
+///   range_style       ::= [separator] [element_style]
+///   separator         ::= "$" delimeted_expr
+///   element_style     ::= "@" delimeted_expr
+///   delimeted_expr    ::= "[" expr "]" | "(" expr ")" | "<" expr ">"
+///   expr              ::= <any string not containing delimeter>
+///
+/// where the separator expression is the string to insert between consecutive
+/// items in the range and the argument expression is the Style specification to
+/// be used when formatting the underlying type.  The default separator if
+/// unspecified is ' ' (space).  The syntax of the argument expression follows
+/// whatever grammar is dictated by the format provider or format adapter used
+/// to format the value type.
+///
+/// Note that attempting to format an `iterator_range<T>` where no format
+/// provider can be found for T will result in a compile error.
+///
+
+template <typename IterT> class format_provider<llvm::iterator_range<IterT>> {
+  using value = typename std::iterator_traits<IterT>::value_type;
+  using reference = typename std::iterator_traits<IterT>::reference;
+
+  static StringRef consumeOneOption(StringRef &Style, char Indicator,
+                                    StringRef Default) {
+    if (Style.empty())
+      return Default;
+    if (Style.front() != Indicator)
+      return Default;
+    Style = Style.drop_front();
+    if (Style.empty()) {
+      assert(false && "Invalid range style");
+      return Default;
+    }
+
+    for (const char *D : {"[]", "<>", "()"}) {
+      if (Style.front() != D[0])
+        continue;
+      size_t End = Style.find_first_of(D[1]);
+      if (End == StringRef::npos) {
+        assert(false && "Missing range option end delimeter!");
+        return Default;
+      }
+      StringRef Result = Style.slice(1, End);
+      Style = Style.drop_front(End + 1);
+      return Result;
+    }
+    assert(false && "Invalid range style!");
+    return Default;
+  }
+
+  static std::pair<StringRef, StringRef> parseOptions(StringRef Style) {
+    StringRef Sep = consumeOneOption(Style, '$', ", ");
+    StringRef Args = consumeOneOption(Style, '@', "");
+    assert(Style.empty() && "Unexpected text in range option string!");
+    return std::make_pair(Sep, Args);
+  }
+
+public:
+  static_assert(detail::range_item_has_provider<IterT>::value,
+                "Range value_type does not have a format provider!");
+  static void format(const llvm::iterator_range<IterT> &V,
+                     llvm::raw_ostream &Stream, StringRef Style) {
+    StringRef Sep;
+    StringRef ArgStyle;
+    std::tie(Sep, ArgStyle) = parseOptions(Style);
+    auto Begin = V.begin();
+    auto End = V.end();
+    if (Begin != End) {
+      auto Adapter =
+          detail::build_format_adapter(std::forward<reference>(*Begin));
+      Adapter.format(Stream, ArgStyle);
+      ++Begin;
+    }
+    while (Begin != End) {
+      Stream << Sep;
+      auto Adapter =
+          detail::build_format_adapter(std::forward<reference>(*Begin));
+      Adapter.format(Stream, ArgStyle);
+      ++Begin;
+    }
+  }
+};
+}
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/FormatVariadic.h b/binaryen/third_party/llvm-project/include/llvm/Support/FormatVariadic.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/FormatVariadic.h
@@ -0,0 +1,264 @@
+//===- FormatVariadic.h - Efficient type-safe string formatting --*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the formatv() function which can be used with other LLVM
+// subsystems to provide printf-like formatting, but with improved safety and
+// flexibility.  The result of `formatv` is an object which can be streamed to
+// a raw_ostream or converted to a std::string or llvm::SmallString.
+//
+//   // Convert to std::string.
+//   std::string S = formatv("{0} {1}", 1234.412, "test").str();
+//
+//   // Convert to llvm::SmallString
+//   SmallString<8> S = formatv("{0} {1}", 1234.412, "test").sstr<8>();
+//
+//   // Stream to an existing raw_ostream.
+//   OS << formatv("{0} {1}", 1234.412, "test");
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FORMATVARIADIC_H
+#define LLVM_SUPPORT_FORMATVARIADIC_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FormatCommon.h"
+#include "llvm/Support/FormatProviders.h"
+#include "llvm/Support/FormatVariadicDetails.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstddef>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+
+enum class ReplacementType { Empty, Format, Literal };
+
+struct ReplacementItem {
+  ReplacementItem() = default;
+  explicit ReplacementItem(StringRef Literal)
+      : Type(ReplacementType::Literal), Spec(Literal) {}
+  ReplacementItem(StringRef Spec, size_t Index, size_t Align, AlignStyle Where,
+                  char Pad, StringRef Options)
+      : Type(ReplacementType::Format), Spec(Spec), Index(Index), Align(Align),
+        Where(Where), Pad(Pad), Options(Options) {}
+
+  ReplacementType Type = ReplacementType::Empty;
+  StringRef Spec;
+  size_t Index = 0;
+  size_t Align = 0;
+  AlignStyle Where = AlignStyle::Right;
+  char Pad = 0;
+  StringRef Options;
+};
+
+class formatv_object_base {
+protected:
+  // The parameters are stored in a std::tuple, which does not provide runtime
+  // indexing capabilities.  In order to enable runtime indexing, we use this
+  // structure to put the parameters into a std::vector.  Since the parameters
+  // are not all the same type, we use some type-erasure by wrapping the
+  // parameters in a template class that derives from a non-template superclass.
+  // Essentially, we are converting a std::tuple<Derived<Ts...>> to a
+  // std::vector<Base*>.
+  struct create_adapters {
+    template <typename... Ts>
+    std::vector<detail::format_adapter *> operator()(Ts &... Items) {
+      return std::vector<detail::format_adapter *>{&Items...};
+    }
+  };
+
+  StringRef Fmt;
+  std::vector<detail::format_adapter *> Adapters;
+  std::vector<ReplacementItem> Replacements;
+
+  static bool consumeFieldLayout(StringRef &Spec, AlignStyle &Where,
+                                 size_t &Align, char &Pad);
+
+  static std::pair<ReplacementItem, StringRef>
+  splitLiteralAndReplacement(StringRef Fmt);
+
+public:
+  formatv_object_base(StringRef Fmt, std::size_t ParamCount)
+      : Fmt(Fmt), Replacements(parseFormatString(Fmt)) {
+    Adapters.reserve(ParamCount);
+  }
+
+  formatv_object_base(formatv_object_base const &rhs) = delete;
+
+  formatv_object_base(formatv_object_base &&rhs)
+      : Fmt(std::move(rhs.Fmt)),
+        Adapters(), // Adapters are initialized by formatv_object
+        Replacements(std::move(rhs.Replacements)) {
+    Adapters.reserve(rhs.Adapters.size());
+  };
+
+  void format(raw_ostream &S) const {
+    for (auto &R : Replacements) {
+      if (R.Type == ReplacementType::Empty)
+        continue;
+      if (R.Type == ReplacementType::Literal) {
+        S << R.Spec;
+        continue;
+      }
+      if (R.Index >= Adapters.size()) {
+        S << R.Spec;
+        continue;
+      }
+
+      auto W = Adapters[R.Index];
+
+      FmtAlign Align(*W, R.Where, R.Align, R.Pad);
+      Align.format(S, R.Options);
+    }
+  }
+  static std::vector<ReplacementItem> parseFormatString(StringRef Fmt);
+
+  static Optional<ReplacementItem> parseReplacementItem(StringRef Spec);
+
+  std::string str() const {
+    std::string Result;
+    raw_string_ostream Stream(Result);
+    Stream << *this;
+    Stream.flush();
+    return Result;
+  }
+
+  template <unsigned N> SmallString<N> sstr() const {
+    SmallString<N> Result;
+    raw_svector_ostream Stream(Result);
+    Stream << *this;
+    return Result;
+  }
+
+  template <unsigned N> operator SmallString<N>() const { return sstr<N>(); }
+
+  operator std::string() const { return str(); }
+};
+
+template <typename Tuple> class formatv_object : public formatv_object_base {
+  // Storage for the parameter adapters.  Since the base class erases the type
+  // of the parameters, we have to own the storage for the parameters here, and
+  // have the base class store type-erased pointers into this tuple.
+  Tuple Parameters;
+
+public:
+  formatv_object(StringRef Fmt, Tuple &&Params)
+      : formatv_object_base(Fmt, std::tuple_size<Tuple>::value),
+        Parameters(std::move(Params)) {
+    Adapters = apply_tuple(create_adapters(), Parameters);
+  }
+
+  formatv_object(formatv_object const &rhs) = delete;
+
+  formatv_object(formatv_object &&rhs)
+      : formatv_object_base(std::move(rhs)),
+        Parameters(std::move(rhs.Parameters)) {
+    Adapters = apply_tuple(create_adapters(), Parameters);
+  }
+};
+
+// Format text given a format string and replacement parameters.
+//
+// ===General Description===
+//
+// Formats textual output.  `Fmt` is a string consisting of one or more
+// replacement sequences with the following grammar:
+//
+// rep_field ::= "{" [index] ["," layout] [":" format] "}"
+// index     ::= <non-negative integer>
+// layout    ::= [[[char]loc]width]
+// format    ::= <any string not containing "{" or "}">
+// char      ::= <any character except "{" or "}">
+// loc       ::= "-" | "=" | "+"
+// width     ::= <positive integer>
+//
+// index   - A non-negative integer specifying the index of the item in the
+//           parameter pack to print.  Any other value is invalid.
+// layout  - A string controlling how the field is laid out within the available
+//           space.
+// format  - A type-dependent string used to provide additional options to
+//           the formatting operation.  Refer to the documentation of the
+//           various individual format providers for per-type options.
+// char    - The padding character.  Defaults to ' ' (space).  Only valid if
+//           `loc` is also specified.
+// loc     - Where to print the formatted text within the field.  Only valid if
+//           `width` is also specified.
+//           '-' : The field is left aligned within the available space.
+//           '=' : The field is centered within the available space.
+//           '+' : The field is right aligned within the available space (this
+//                 is the default).
+// width   - The width of the field within which to print the formatted text.
+//           If this is less than the required length then the `char` and `loc`
+//           fields are ignored, and the field is printed with no leading or
+//           trailing padding.  If this is greater than the required length,
+//           then the text is output according to the value of `loc`, and padded
+//           as appropriate on the left and/or right by `char`.
+//
+// ===Special Characters===
+//
+// The characters '{' and '}' are reserved and cannot appear anywhere within a
+// replacement sequence.  Outside of a replacement sequence, in order to print
+// a literal '{' or '}' it must be doubled -- "{{" to print a literal '{' and
+// "}}" to print a literal '}'.
+//
+// ===Parameter Indexing===
+// `index` specifies the index of the parameter in the parameter pack to format
+// into the output.  Note that it is possible to refer to the same parameter
+// index multiple times in a given format string.  This makes it possible to
+// output the same value multiple times without passing it multiple times to the
+// function. For example:
+//
+//   formatv("{0} {1} {0}", "a", "bb")
+//
+// would yield the string "abba".  This can be convenient when it is expensive
+// to compute the value of the parameter, and you would otherwise have had to
+// save it to a temporary.
+//
+// ===Formatter Search===
+//
+// For a given parameter of type T, the following steps are executed in order
+// until a match is found:
+//
+//   1. If the parameter is of class type, and inherits from format_adapter,
+//      Then format() is invoked on it to produce the formatted output.  The
+//      implementation should write the formatted text into `Stream`.
+//   2. If there is a suitable template specialization of format_provider<>
+//      for type T containing a method whose signature is:
+//      void format(const T &Obj, raw_ostream &Stream, StringRef Options)
+//      Then this method is invoked as described in Step 1.
+//   3. If an appropriate operator<< for raw_ostream exists, it will be used.
+//      For this to work, (raw_ostream& << const T&) must return raw_ostream&.
+//
+// If a match cannot be found through either of the above methods, a compiler
+// error is generated.
+//
+// ===Invalid Format String Handling===
+//
+// In the case of a format string which does not match the grammar described
+// above, the output is undefined.  With asserts enabled, LLVM will trigger an
+// assertion.  Otherwise, it will try to do something reasonable, but in general
+// the details of what that is are undefined.
+//
+template <typename... Ts>
+inline auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object<decltype(
+    std::make_tuple(detail::build_format_adapter(std::forward<Ts>(Vals))...))> {
+  using ParamTuple = decltype(
+      std::make_tuple(detail::build_format_adapter(std::forward<Ts>(Vals))...));
+  return formatv_object<ParamTuple>(
+      Fmt,
+      std::make_tuple(detail::build_format_adapter(std::forward<Ts>(Vals))...));
+}
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_FORMATVARIADIC_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/FormatVariadicDetails.h b/binaryen/third_party/llvm-project/include/llvm/Support/FormatVariadicDetails.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/FormatVariadicDetails.h
@@ -0,0 +1,164 @@
+//===- FormatVariadicDetails.h - Helpers for FormatVariadic.h ----*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FORMATVARIADIC_DETAILS_H
+#define LLVM_SUPPORT_FORMATVARIADIC_DETAILS_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <type_traits>
+
+namespace llvm {
+template <typename T, typename Enable = void> struct format_provider {};
+class Error;
+
+namespace detail {
+class format_adapter {
+  virtual void anchor();
+
+protected:
+  virtual ~format_adapter() {}
+
+public:
+  virtual void format(raw_ostream &S, StringRef Options) = 0;
+};
+
+template <typename T> class provider_format_adapter : public format_adapter {
+  T Item;
+
+public:
+  explicit provider_format_adapter(T &&Item) : Item(std::forward<T>(Item)) {}
+
+  void format(llvm::raw_ostream &S, StringRef Options) override {
+    format_provider<typename std::decay<T>::type>::format(Item, S, Options);
+  }
+};
+
+template <typename T>
+class stream_operator_format_adapter : public format_adapter {
+  T Item;
+
+public:
+  explicit stream_operator_format_adapter(T &&Item)
+      : Item(std::forward<T>(Item)) {}
+
+  void format(llvm::raw_ostream &S, StringRef Options) override { S << Item; }
+};
+
+template <typename T> class missing_format_adapter;
+
+// Test if format_provider<T> is defined on T and contains a member function
+// with the signature:
+//   static void format(const T&, raw_stream &, StringRef);
+//
+template <class T> class has_FormatProvider {
+public:
+  using Decayed = typename std::decay<T>::type;
+  typedef void (*Signature_format)(const Decayed &, llvm::raw_ostream &,
+                                   StringRef);
+
+  template <typename U>
+  static char test(SameType<Signature_format, &U::format> *);
+
+  template <typename U> static double test(...);
+
+  static bool const value =
+      (sizeof(test<llvm::format_provider<Decayed>>(nullptr)) == 1);
+};
+
+// Test if raw_ostream& << T -> raw_ostream& is findable via ADL.
+template <class T> class has_StreamOperator {
+public:
+  using ConstRefT = const typename std::decay<T>::type &;
+
+  template <typename U>
+  static char test(typename std::enable_if<
+                   std::is_same<decltype(std::declval<llvm::raw_ostream &>()
+                                         << std::declval<U>()),
+                                llvm::raw_ostream &>::value,
+                   int *>::type);
+
+  template <typename U> static double test(...);
+
+  static bool const value = (sizeof(test<ConstRefT>(nullptr)) == 1);
+};
+
+// Simple template that decides whether a type T should use the member-function
+// based format() invocation.
+template <typename T>
+struct uses_format_member
+    : public std::integral_constant<
+          bool,
+          std::is_base_of<format_adapter,
+                          typename std::remove_reference<T>::type>::value> {};
+
+// Simple template that decides whether a type T should use the format_provider
+// based format() invocation.  The member function takes priority, so this test
+// will only be true if there is not ALSO a format member.
+template <typename T>
+struct uses_format_provider
+    : public std::integral_constant<
+          bool, !uses_format_member<T>::value && has_FormatProvider<T>::value> {
+};
+
+// Simple template that decides whether a type T should use the operator<<
+// based format() invocation.  This takes last priority.
+template <typename T>
+struct uses_stream_operator
+    : public std::integral_constant<bool, !uses_format_member<T>::value &&
+                                              !uses_format_provider<T>::value &&
+                                              has_StreamOperator<T>::value> {};
+
+// Simple template that decides whether a type T has neither a member-function
+// nor format_provider based implementation that it can use.  Mostly used so
+// that the compiler spits out a nice diagnostic when a type with no format
+// implementation can be located.
+template <typename T>
+struct uses_missing_provider
+    : public std::integral_constant<bool, !uses_format_member<T>::value &&
+                                              !uses_format_provider<T>::value &&
+                                              !uses_stream_operator<T>::value> {
+};
+
+template <typename T>
+typename std::enable_if<uses_format_member<T>::value, T>::type
+build_format_adapter(T &&Item) {
+  return std::forward<T>(Item);
+}
+
+template <typename T>
+typename std::enable_if<uses_format_provider<T>::value,
+                        provider_format_adapter<T>>::type
+build_format_adapter(T &&Item) {
+  return provider_format_adapter<T>(std::forward<T>(Item));
+}
+
+template <typename T>
+typename std::enable_if<uses_stream_operator<T>::value,
+                        stream_operator_format_adapter<T>>::type
+build_format_adapter(T &&Item) {
+  // If the caller passed an Error by value, then stream_operator_format_adapter
+  // would be responsible for consuming it.
+  // Make the caller opt into this by calling fmt_consume().
+  static_assert(
+      !std::is_same<llvm::Error, typename std::remove_cv<T>::type>::value,
+      "llvm::Error-by-value must be wrapped in fmt_consume() for formatv");
+  return stream_operator_format_adapter<T>(std::forward<T>(Item));
+}
+
+template <typename T>
+typename std::enable_if<uses_missing_provider<T>::value,
+                        missing_format_adapter<T>>::type
+build_format_adapter(T &&Item) {
+  return missing_format_adapter<T>();
+}
+}
+}
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/FormattedStream.h b/binaryen/third_party/llvm-project/include/llvm/Support/FormattedStream.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/FormattedStream.h
@@ -0,0 +1,161 @@
+//===-- llvm/Support/FormattedStream.h - Formatted streams ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains raw_ostream implementations for streams to do
+// things like pretty-print comments.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FORMATTEDSTREAM_H
+#define LLVM_SUPPORT_FORMATTEDSTREAM_H
+
+#include "llvm/Support/raw_ostream.h"
+#include <utility>
+
+namespace llvm {
+
+/// formatted_raw_ostream - A raw_ostream that wraps another one and keeps track
+/// of line and column position, allowing padding out to specific column
+/// boundaries and querying the number of lines written to the stream.
+///
+class formatted_raw_ostream : public raw_ostream {
+  /// TheStream - The real stream we output to. We set it to be
+  /// unbuffered, since we're already doing our own buffering.
+  ///
+  raw_ostream *TheStream;
+
+  /// Position - The current output column and line of the data that's
+  /// been flushed and the portion of the buffer that's been
+  /// scanned.  The line and column scheme is zero-based.
+  ///
+  std::pair<unsigned, unsigned> Position;
+
+  /// Scanned - This points to one past the last character in the
+  /// buffer we've scanned.
+  ///
+  const char *Scanned;
+
+  void write_impl(const char *Ptr, size_t Size) override;
+
+  /// current_pos - Return the current position within the stream,
+  /// not counting the bytes currently in the buffer.
+  uint64_t current_pos() const override {
+    // Our current position in the stream is all the contents which have been
+    // written to the underlying stream (*not* the current position of the
+    // underlying stream).
+    return TheStream->tell();
+  }
+
+  /// ComputePosition - Examine the given output buffer and figure out the new
+  /// position after output.
+  ///
+  void ComputePosition(const char *Ptr, size_t size);
+
+  void setStream(raw_ostream &Stream) {
+    releaseStream();
+
+    TheStream = &Stream;
+
+    // This formatted_raw_ostream inherits from raw_ostream, so it'll do its
+    // own buffering, and it doesn't need or want TheStream to do another
+    // layer of buffering underneath. Resize the buffer to what TheStream
+    // had been using, and tell TheStream not to do its own buffering.
+    if (size_t BufferSize = TheStream->GetBufferSize())
+      SetBufferSize(BufferSize);
+    else
+      SetUnbuffered();
+    TheStream->SetUnbuffered();
+
+    Scanned = nullptr;
+  }
+
+public:
+  /// formatted_raw_ostream - Open the specified file for
+  /// writing. If an error occurs, information about the error is
+  /// put into ErrorInfo, and the stream should be immediately
+  /// destroyed; the string will be empty if no error occurred.
+  ///
+  /// As a side effect, the given Stream is set to be Unbuffered.
+  /// This is because formatted_raw_ostream does its own buffering,
+  /// so it doesn't want another layer of buffering to be happening
+  /// underneath it.
+  ///
+  formatted_raw_ostream(raw_ostream &Stream)
+      : TheStream(nullptr), Position(0, 0) {
+    setStream(Stream);
+  }
+  explicit formatted_raw_ostream() : TheStream(nullptr), Position(0, 0) {
+    Scanned = nullptr;
+  }
+
+  ~formatted_raw_ostream() override {
+    flush();
+    releaseStream();
+  }
+
+  /// PadToColumn - Align the output to some column number.  If the current
+  /// column is already equal to or more than NewCol, PadToColumn inserts one
+  /// space.
+  ///
+  /// \param NewCol - The column to move to.
+  formatted_raw_ostream &PadToColumn(unsigned NewCol);
+
+  /// getColumn - Return the column number
+  unsigned getColumn() { return Position.first; }
+
+  /// getLine - Return the line number
+  unsigned getLine() { return Position.second; }
+
+  raw_ostream &resetColor() override {
+    TheStream->resetColor();
+    return *this;
+  }
+
+  raw_ostream &reverseColor() override {
+    TheStream->reverseColor();
+    return *this;
+  }
+
+  raw_ostream &changeColor(enum Colors Color, bool Bold, bool BG) override {
+    TheStream->changeColor(Color, Bold, BG);
+    return *this;
+  }
+
+  bool is_displayed() const override {
+    return TheStream->is_displayed();
+  }
+
+private:
+  void releaseStream() {
+    // Transfer the buffer settings from this raw_ostream back to the underlying
+    // stream.
+    if (!TheStream)
+      return;
+    if (size_t BufferSize = GetBufferSize())
+      TheStream->SetBufferSize(BufferSize);
+    else
+      TheStream->SetUnbuffered();
+  }
+};
+
+/// fouts() - This returns a reference to a formatted_raw_ostream for
+/// standard output.  Use it like: fouts() << "foo" << "bar";
+formatted_raw_ostream &fouts();
+
+/// ferrs() - This returns a reference to a formatted_raw_ostream for
+/// standard error.  Use it like: ferrs() << "foo" << "bar";
+formatted_raw_ostream &ferrs();
+
+/// fdbgs() - This returns a reference to a formatted_raw_ostream for
+/// debug output.  Use it like: fdbgs() << "foo" << "bar";
+formatted_raw_ostream &fdbgs();
+
+} // end llvm namespace
+
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Host.h b/binaryen/third_party/llvm-project/include/llvm/Support/Host.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Host.h
@@ -0,0 +1,70 @@
+//===- llvm/Support/Host.h - Host machine characteristics --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Methods for querying the nature of the host machine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_HOST_H
+#define LLVM_SUPPORT_HOST_H
+
+#include "llvm/ADT/StringMap.h"
+
+#include <string>
+
+namespace llvm {
+namespace sys {
+
+  /// getDefaultTargetTriple() - Return the default target triple the compiler
+  /// has been configured to produce code for.
+  ///
+  /// The target triple is a string in the format of:
+  ///   CPU_TYPE-VENDOR-OPERATING_SYSTEM
+  /// or
+  ///   CPU_TYPE-VENDOR-KERNEL-OPERATING_SYSTEM
+  std::string getDefaultTargetTriple();
+
+  /// getProcessTriple() - Return an appropriate target triple for generating
+  /// code to be loaded into the current process, e.g. when using the JIT.
+  std::string getProcessTriple();
+
+  /// getHostCPUName - Get the LLVM name for the host CPU. The particular format
+  /// of the name is target dependent, and suitable for passing as -mcpu to the
+  /// target which matches the host.
+  ///
+  /// \return - The host CPU name, or empty if the CPU could not be determined.
+  StringRef getHostCPUName();
+
+  /// getHostCPUFeatures - Get the LLVM names for the host CPU features.
+  /// The particular format of the names are target dependent, and suitable for
+  /// passing as -mattr to the target which matches the host.
+  ///
+  /// \param Features - A string mapping feature names to either
+  /// true (if enabled) or false (if disabled). This routine makes no guarantees
+  /// about exactly which features may appear in this map, except that they are
+  /// all valid LLVM feature names.
+  ///
+  /// \return - True on success.
+  bool getHostCPUFeatures(StringMap<bool> &Features);
+
+  /// Get the number of physical cores (as opposed to logical cores returned
+  /// from thread::hardware_concurrency(), which includes hyperthreads).
+  /// Returns -1 if unknown for the current host system.
+  int getHostNumPhysicalCores();
+
+  namespace detail {
+  /// Helper functions to extract HostCPUName from /proc/cpuinfo on linux.
+  StringRef getHostCPUNameForPowerPC(StringRef ProcCpuinfoContent);
+  StringRef getHostCPUNameForARM(StringRef ProcCpuinfoContent);
+  StringRef getHostCPUNameForS390x(StringRef ProcCpuinfoContent);
+  StringRef getHostCPUNameForBPF();
+  }
+}
+}
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/LEB128.h b/binaryen/third_party/llvm-project/include/llvm/Support/LEB128.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/LEB128.h
@@ -0,0 +1,198 @@
+//===- llvm/Support/LEB128.h - [SU]LEB128 utility functions -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares some utility functions for encoding SLEB128 and
+// ULEB128 values.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_LEB128_H
+#define LLVM_SUPPORT_LEB128_H
+
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+/// Utility function to encode a SLEB128 value to an output stream. Returns
+/// the length in bytes of the encoded value.
+inline unsigned encodeSLEB128(int64_t Value, raw_ostream &OS,
+                              unsigned PadTo = 0) {
+  bool More;
+  unsigned Count = 0;
+  do {
+    uint8_t Byte = Value & 0x7f;
+    // NOTE: this assumes that this signed shift is an arithmetic right shift.
+    Value >>= 7;
+    More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) ||
+              ((Value == -1) && ((Byte & 0x40) != 0))));
+    Count++;
+    if (More || Count < PadTo)
+      Byte |= 0x80; // Mark this byte to show that more bytes will follow.
+    OS << char(Byte);
+  } while (More);
+
+  // Pad with 0x80 and emit a terminating byte at the end.
+  if (Count < PadTo) {
+    uint8_t PadValue = Value < 0 ? 0x7f : 0x00;
+    for (; Count < PadTo - 1; ++Count)
+      OS << char(PadValue | 0x80);
+    OS << char(PadValue);
+    Count++;
+  }
+  return Count;
+}
+
+/// Utility function to encode a SLEB128 value to a buffer. Returns
+/// the length in bytes of the encoded value.
+inline unsigned encodeSLEB128(int64_t Value, uint8_t *p, unsigned PadTo = 0) {
+  uint8_t *orig_p = p;
+  unsigned Count = 0;
+  bool More;
+  do {
+    uint8_t Byte = Value & 0x7f;
+    // NOTE: this assumes that this signed shift is an arithmetic right shift.
+    Value >>= 7;
+    More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) ||
+              ((Value == -1) && ((Byte & 0x40) != 0))));
+    Count++;
+    if (More || Count < PadTo)
+      Byte |= 0x80; // Mark this byte to show that more bytes will follow.
+    *p++ = Byte;
+  } while (More);
+
+  // Pad with 0x80 and emit a terminating byte at the end.
+  if (Count < PadTo) {
+    uint8_t PadValue = Value < 0 ? 0x7f : 0x00;
+    for (; Count < PadTo - 1; ++Count)
+      *p++ = (PadValue | 0x80);
+    *p++ = PadValue;
+  }
+  return (unsigned)(p - orig_p);
+}
+
+/// Utility function to encode a ULEB128 value to an output stream. Returns
+/// the length in bytes of the encoded value.
+inline unsigned encodeULEB128(uint64_t Value, raw_ostream &OS,
+                              unsigned PadTo = 0) {
+  unsigned Count = 0;
+  do {
+    uint8_t Byte = Value & 0x7f;
+    Value >>= 7;
+    Count++;
+    if (Value != 0 || Count < PadTo)
+      Byte |= 0x80; // Mark this byte to show that more bytes will follow.
+    OS << char(Byte);
+  } while (Value != 0);
+
+  // Pad with 0x80 and emit a null byte at the end.
+  if (Count < PadTo) {
+    for (; Count < PadTo - 1; ++Count)
+      OS << '\x80';
+    OS << '\x00';
+    Count++;
+  }
+  return Count;
+}
+
+/// Utility function to encode a ULEB128 value to a buffer. Returns
+/// the length in bytes of the encoded value.
+inline unsigned encodeULEB128(uint64_t Value, uint8_t *p,
+                              unsigned PadTo = 0) {
+  uint8_t *orig_p = p;
+  unsigned Count = 0;
+  do {
+    uint8_t Byte = Value & 0x7f;
+    Value >>= 7;
+    Count++;
+    if (Value != 0 || Count < PadTo)
+      Byte |= 0x80; // Mark this byte to show that more bytes will follow.
+    *p++ = Byte;
+  } while (Value != 0);
+
+  // Pad with 0x80 and emit a null byte at the end.
+  if (Count < PadTo) {
+    for (; Count < PadTo - 1; ++Count)
+      *p++ = '\x80';
+    *p++ = '\x00';
+  }
+
+  return (unsigned)(p - orig_p);
+}
+
+/// Utility function to decode a ULEB128 value.
+inline uint64_t decodeULEB128(const uint8_t *p, unsigned *n = nullptr,
+                              const uint8_t *end = nullptr,
+                              const char **error = nullptr) {
+  const uint8_t *orig_p = p;
+  uint64_t Value = 0;
+  unsigned Shift = 0;
+  if (error)
+    *error = nullptr;
+  do {
+    if (end && p == end) {
+      if (error)
+        *error = "malformed uleb128, extends past end";
+      if (n)
+        *n = (unsigned)(p - orig_p);
+      return 0;
+    }
+    uint64_t Slice = *p & 0x7f;
+    if (Shift >= 64 || Slice << Shift >> Shift != Slice) {
+      if (error)
+        *error = "uleb128 too big for uint64";
+      if (n)
+        *n = (unsigned)(p - orig_p);
+      return 0;
+    }
+    Value += uint64_t(*p & 0x7f) << Shift;
+    Shift += 7;
+  } while (*p++ >= 128);
+  if (n)
+    *n = (unsigned)(p - orig_p);
+  return Value;
+}
+
+/// Utility function to decode a SLEB128 value.
+inline int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr,
+                             const uint8_t *end = nullptr,
+                             const char **error = nullptr) {
+  const uint8_t *orig_p = p;
+  int64_t Value = 0;
+  unsigned Shift = 0;
+  uint8_t Byte;
+  if (error)
+    *error = nullptr;
+  do {
+    if (end && p == end) {
+      if (error)
+        *error = "malformed sleb128, extends past end";
+      if (n)
+        *n = (unsigned)(p - orig_p);
+      return 0;
+    }
+    Byte = *p++;
+    Value |= (uint64_t(Byte & 0x7f) << Shift);
+    Shift += 7;
+  } while (Byte >= 128);
+  // Sign extend negative numbers if needed.
+  if (Shift < 64 && (Byte & 0x40))
+    Value |= (-1ULL) << Shift;
+  if (n)
+    *n = (unsigned)(p - orig_p);
+  return Value;
+}
+
+/// Utility function to get the size of the ULEB128-encoded value.
+extern unsigned getULEB128Size(uint64_t Value);
+
+/// Utility function to get the size of the SLEB128-encoded value.
+extern unsigned getSLEB128Size(int64_t Value);
+
+} // namespace llvm
+
+#endif // LLVM_SYSTEM_LEB128_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/LICENSE.TXT b/binaryen/third_party/llvm-project/include/llvm/Support/LICENSE.TXT
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/LICENSE.TXT
@@ -0,0 +1,6 @@
+LLVM System Interface Library
+-------------------------------------------------------------------------------
+The LLVM System Interface Library is licensed under the Illinois Open Source
+License and has the following additional copyright:
+
+Copyright (C) 2004 eXtensible Systems, Inc.
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/LineIterator.h b/binaryen/third_party/llvm-project/include/llvm/Support/LineIterator.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/LineIterator.h
@@ -0,0 +1,87 @@
+//===- LineIterator.h - Iterator to read a text buffer's lines --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_LINEITERATOR_H
+#define LLVM_SUPPORT_LINEITERATOR_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+#include <iterator>
+
+namespace llvm {
+
+class MemoryBuffer;
+
+/// A forward iterator which reads text lines from a buffer.
+///
+/// This class provides a forward iterator interface for reading one line at
+/// a time from a buffer. When default constructed the iterator will be the
+/// "end" iterator.
+///
+/// The iterator is aware of what line number it is currently processing. It
+/// strips blank lines by default, and comment lines given a comment-starting
+/// character.
+///
+/// Note that this iterator requires the buffer to be nul terminated.
+class line_iterator
+    : public std::iterator<std::forward_iterator_tag, StringRef> {
+  const MemoryBuffer *Buffer = nullptr;
+  char CommentMarker = '\0';
+  bool SkipBlanks = true;
+
+  unsigned LineNumber = 1;
+  StringRef CurrentLine;
+
+public:
+  /// Default construct an "end" iterator.
+  line_iterator() = default;
+
+  /// Construct a new iterator around some memory buffer.
+  explicit line_iterator(const MemoryBuffer &Buffer, bool SkipBlanks = true,
+                         char CommentMarker = '\0');
+
+  /// Return true if we've reached EOF or are an "end" iterator.
+  bool is_at_eof() const { return !Buffer; }
+
+  /// Return true if we're an "end" iterator or have reached EOF.
+  bool is_at_end() const { return is_at_eof(); }
+
+  /// Return the current line number. May return any number at EOF.
+  int64_t line_number() const { return LineNumber; }
+
+  /// Advance to the next (non-empty, non-comment) line.
+  line_iterator &operator++() {
+    advance();
+    return *this;
+  }
+  line_iterator operator++(int) {
+    line_iterator tmp(*this);
+    advance();
+    return tmp;
+  }
+
+  /// Get the current line as a \c StringRef.
+  StringRef operator*() const { return CurrentLine; }
+  const StringRef *operator->() const { return &CurrentLine; }
+
+  friend bool operator==(const line_iterator &LHS, const line_iterator &RHS) {
+    return LHS.Buffer == RHS.Buffer &&
+           LHS.CurrentLine.begin() == RHS.CurrentLine.begin();
+  }
+
+  friend bool operator!=(const line_iterator &LHS, const line_iterator &RHS) {
+    return !(LHS == RHS);
+  }
+
+private:
+  /// Advance the iterator to the next line.
+  void advance();
+};
+}
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Locale.h b/binaryen/third_party/llvm-project/include/llvm/Support/Locale.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Locale.h
@@ -0,0 +1,17 @@
+#ifndef LLVM_SUPPORT_LOCALE_H
+#define LLVM_SUPPORT_LOCALE_H
+
+namespace llvm {
+class StringRef;
+
+namespace sys {
+namespace locale {
+
+int columnWidth(StringRef s);
+bool isPrint(int c);
+
+}
+}
+}
+
+#endif // LLVM_SUPPORT_LOCALE_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/MD5.h b/binaryen/third_party/llvm-project/include/llvm/Support/MD5.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/MD5.h
@@ -0,0 +1,122 @@
+/* -*- C++ -*-
+ * This code is derived from (original license follows):
+ *
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001.  No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See md5.c for more information.
+ */
+
+#ifndef LLVM_SUPPORT_MD5_H
+#define LLVM_SUPPORT_MD5_H
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Endian.h"
+#include <array>
+#include <cstdint>
+
+namespace llvm {
+
+template <typename T> class ArrayRef;
+
+class MD5 {
+  // Any 32-bit or wider unsigned integer data type will do.
+  typedef uint32_t MD5_u32plus;
+
+  MD5_u32plus a = 0x67452301;
+  MD5_u32plus b = 0xefcdab89;
+  MD5_u32plus c = 0x98badcfe;
+  MD5_u32plus d = 0x10325476;
+  MD5_u32plus hi = 0;
+  MD5_u32plus lo = 0;
+  uint8_t buffer[64];
+  MD5_u32plus block[16];
+
+public:
+  struct MD5Result {
+    std::array<uint8_t, 16> Bytes;
+
+    operator std::array<uint8_t, 16>() const { return Bytes; }
+
+    const uint8_t &operator[](size_t I) const { return Bytes[I]; }
+    uint8_t &operator[](size_t I) { return Bytes[I]; }
+
+    SmallString<32> digest() const;
+
+    uint64_t low() const {
+      // Our MD5 implementation returns the result in little endian, so the low
+      // word is first.
+      using namespace support;
+      return endian::read<uint64_t, little, unaligned>(Bytes.data());
+    }
+
+    uint64_t high() const {
+      using namespace support;
+      return endian::read<uint64_t, little, unaligned>(Bytes.data() + 8);
+    }
+    std::pair<uint64_t, uint64_t> words() const {
+      using namespace support;
+      return std::make_pair(high(), low());
+    }
+  };
+
+  MD5();
+
+  /// Updates the hash for the byte stream provided.
+  void update(ArrayRef<uint8_t> Data);
+
+  /// Updates the hash for the StringRef provided.
+  void update(StringRef Str);
+
+  /// Finishes off the hash and puts the result in result.
+  void final(MD5Result &Result);
+
+  /// Translates the bytes in \p Res to a hex string that is
+  /// deposited into \p Str. The result will be of length 32.
+  static void stringifyResult(MD5Result &Result, SmallString<32> &Str);
+
+  /// Computes the hash for a given bytes.
+  static std::array<uint8_t, 16> hash(ArrayRef<uint8_t> Data);
+
+private:
+  const uint8_t *body(ArrayRef<uint8_t> Data);
+};
+
+inline bool operator==(const MD5::MD5Result &LHS, const MD5::MD5Result &RHS) {
+  return LHS.Bytes == RHS.Bytes;
+}
+
+/// Helper to compute and return lower 64 bits of the given string's MD5 hash.
+inline uint64_t MD5Hash(StringRef Str) {
+  using namespace support;
+
+  MD5 Hash;
+  Hash.update(Str);
+  MD5::MD5Result Result;
+  Hash.final(Result);
+  // Return the least significant word.
+  return Result.low();
+}
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_MD5_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/ManagedStatic.h b/binaryen/third_party/llvm-project/include/llvm/Support/ManagedStatic.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/ManagedStatic.h
@@ -0,0 +1,1 @@
+// XXX BINARYEN - we don't need this, but stuff imports it
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/MathExtras.h b/binaryen/third_party/llvm-project/include/llvm/Support/MathExtras.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/MathExtras.h
@@ -0,0 +1,951 @@
+//===-- llvm/Support/MathExtras.h - Useful math functions -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains some functions that are useful for math stuff.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MATHEXTRAS_H
+#define LLVM_SUPPORT_MATHEXTRAS_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/SwapByteOrder.h"
+#include <algorithm>
+#include <cassert>
+#include <climits>
+#include <cstring>
+#include <limits>
+#include <type_traits>
+
+#ifdef __ANDROID_NDK__
+#include <android/api-level.h>
+#endif
+
+#ifdef _MSC_VER
+// Declare these intrinsics manually rather including intrin.h. It's very
+// expensive, and MathExtras.h is popular.
+// #include <intrin.h>
+extern "C" {
+unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask);
+unsigned char _BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask);
+unsigned char _BitScanReverse(unsigned long *_Index, unsigned long _Mask);
+unsigned char _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask);
+}
+#endif
+
+namespace llvm {
+
+/// The behavior an operation has on an input of 0.
+enum ZeroBehavior {
+  /// The returned value is undefined.
+  ZB_Undefined,
+  /// The returned value is numeric_limits<T>::max()
+  ZB_Max,
+  /// The returned value is numeric_limits<T>::digits
+  ZB_Width
+};
+
+/// Mathematical constants.
+namespace numbers {
+// TODO: Track C++20 std::numbers.
+// TODO: Favor using the hexadecimal FP constants (requires C++17).
+constexpr double e          = 2.7182818284590452354, // (0x1.5bf0a8b145749P+1) https://oeis.org/A001113
+                 egamma     = .57721566490153286061, // (0x1.2788cfc6fb619P-1) https://oeis.org/A001620
+                 ln2        = .69314718055994530942, // (0x1.62e42fefa39efP-1) https://oeis.org/A002162
+                 ln10       = 2.3025850929940456840, // (0x1.24bb1bbb55516P+1) https://oeis.org/A002392
+                 log2e      = 1.4426950408889634074, // (0x1.71547652b82feP+0)
+                 log10e     = .43429448190325182765, // (0x1.bcb7b1526e50eP-2)
+                 pi         = 3.1415926535897932385, // (0x1.921fb54442d18P+1) https://oeis.org/A000796
+                 inv_pi     = .31830988618379067154, // (0x1.45f306bc9c883P-2) https://oeis.org/A049541
+                 sqrtpi     = 1.7724538509055160273, // (0x1.c5bf891b4ef6bP+0) https://oeis.org/A002161
+                 inv_sqrtpi = .56418958354775628695, // (0x1.20dd750429b6dP-1) https://oeis.org/A087197
+                 sqrt2      = 1.4142135623730950488, // (0x1.6a09e667f3bcdP+0) https://oeis.org/A00219
+                 inv_sqrt2  = .70710678118654752440, // (0x1.6a09e667f3bcdP-1)
+                 sqrt3      = 1.7320508075688772935, // (0x1.bb67ae8584caaP+0) https://oeis.org/A002194
+                 inv_sqrt3  = .57735026918962576451, // (0x1.279a74590331cP-1)
+                 phi        = 1.6180339887498948482; // (0x1.9e3779b97f4a8P+0) https://oeis.org/A001622
+constexpr float ef          = 2.71828183F, // (0x1.5bf0a8P+1) https://oeis.org/A001113
+                egammaf     = .577215665F, // (0x1.2788d0P-1) https://oeis.org/A001620
+                ln2f        = .693147181F, // (0x1.62e430P-1) https://oeis.org/A002162
+                ln10f       = 2.30258509F, // (0x1.26bb1cP+1) https://oeis.org/A002392
+                log2ef      = 1.44269504F, // (0x1.715476P+0)
+                log10ef     = .434294482F, // (0x1.bcb7b2P-2)
+                pif         = 3.14159265F, // (0x1.921fb6P+1) https://oeis.org/A000796
+                inv_pif     = .318309886F, // (0x1.45f306P-2) https://oeis.org/A049541
+                sqrtpif     = 1.77245385F, // (0x1.c5bf8aP+0) https://oeis.org/A002161
+                inv_sqrtpif = .564189584F, // (0x1.20dd76P-1) https://oeis.org/A087197
+                sqrt2f      = 1.41421356F, // (0x1.6a09e6P+0) https://oeis.org/A002193
+                inv_sqrt2f  = .707106781F, // (0x1.6a09e6P-1)
+                sqrt3f      = 1.73205081F, // (0x1.bb67aeP+0) https://oeis.org/A002194
+                inv_sqrt3f  = .577350269F, // (0x1.279a74P-1)
+                phif        = 1.61803399F; // (0x1.9e377aP+0) https://oeis.org/A001622
+} // namespace numbers
+
+namespace detail {
+template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
+  static unsigned count(T Val, ZeroBehavior) {
+    if (!Val)
+      return std::numeric_limits<T>::digits;
+    if (Val & 0x1)
+      return 0;
+
+    // Bisection method.
+    unsigned ZeroBits = 0;
+    T Shift = std::numeric_limits<T>::digits >> 1;
+    T Mask = std::numeric_limits<T>::max() >> Shift;
+    while (Shift) {
+      if ((Val & Mask) == 0) {
+        Val >>= Shift;
+        ZeroBits |= Shift;
+      }
+      Shift >>= 1;
+      Mask >>= Shift;
+    }
+    return ZeroBits;
+  }
+};
+
+#if defined(__GNUC__) || defined(_MSC_VER)
+template <typename T> struct TrailingZerosCounter<T, 4> {
+  static unsigned count(T Val, ZeroBehavior ZB) {
+    if (ZB != ZB_Undefined && Val == 0)
+      return 32;
+
+#if __has_builtin(__builtin_ctz) || defined(__GNUC__)
+    return __builtin_ctz(Val);
+#elif defined(_MSC_VER)
+    unsigned long Index;
+    _BitScanForward(&Index, Val);
+    return Index;
+#endif
+  }
+};
+
+#if !defined(_MSC_VER) || defined(_M_X64)
+template <typename T> struct TrailingZerosCounter<T, 8> {
+  static unsigned count(T Val, ZeroBehavior ZB) {
+    if (ZB != ZB_Undefined && Val == 0)
+      return 64;
+
+#if __has_builtin(__builtin_ctzll) || defined(__GNUC__)
+    return __builtin_ctzll(Val);
+#elif defined(_MSC_VER)
+    unsigned long Index;
+    _BitScanForward64(&Index, Val);
+    return Index;
+#endif
+  }
+};
+#endif
+#endif
+} // namespace detail
+
+/// Count number of 0's from the least significant bit to the most
+///   stopping at the first 1.
+///
+/// Only unsigned integral types are allowed.
+///
+/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
+///   valid arguments.
+template <typename T>
+unsigned countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
+  static_assert(std::numeric_limits<T>::is_integer &&
+                    !std::numeric_limits<T>::is_signed,
+                "Only unsigned integral types are allowed.");
+  return llvm::detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB);
+}
+
+namespace detail {
+template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
+  static unsigned count(T Val, ZeroBehavior) {
+    if (!Val)
+      return std::numeric_limits<T>::digits;
+
+    // Bisection method.
+    unsigned ZeroBits = 0;
+    for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
+      T Tmp = Val >> Shift;
+      if (Tmp)
+        Val = Tmp;
+      else
+        ZeroBits |= Shift;
+    }
+    return ZeroBits;
+  }
+};
+
+#if defined(__GNUC__) || defined(_MSC_VER)
+template <typename T> struct LeadingZerosCounter<T, 4> {
+  static unsigned count(T Val, ZeroBehavior ZB) {
+    if (ZB != ZB_Undefined && Val == 0)
+      return 32;
+
+#if __has_builtin(__builtin_clz) || defined(__GNUC__)
+    return __builtin_clz(Val);
+#elif defined(_MSC_VER)
+    unsigned long Index;
+    _BitScanReverse(&Index, Val);
+    return Index ^ 31;
+#endif
+  }
+};
+
+#if !defined(_MSC_VER) || defined(_M_X64)
+template <typename T> struct LeadingZerosCounter<T, 8> {
+  static unsigned count(T Val, ZeroBehavior ZB) {
+    if (ZB != ZB_Undefined && Val == 0)
+      return 64;
+
+#if __has_builtin(__builtin_clzll) || defined(__GNUC__)
+    return __builtin_clzll(Val);
+#elif defined(_MSC_VER)
+    unsigned long Index;
+    _BitScanReverse64(&Index, Val);
+    return Index ^ 63;
+#endif
+  }
+};
+#endif
+#endif
+} // namespace detail
+
+/// Count number of 0's from the most significant bit to the least
+///   stopping at the first 1.
+///
+/// Only unsigned integral types are allowed.
+///
+/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
+///   valid arguments.
+template <typename T>
+unsigned countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
+  static_assert(std::numeric_limits<T>::is_integer &&
+                    !std::numeric_limits<T>::is_signed,
+                "Only unsigned integral types are allowed.");
+  return llvm::detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
+}
+
+/// Get the index of the first set bit starting from the least
+///   significant bit.
+///
+/// Only unsigned integral types are allowed.
+///
+/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
+///   valid arguments.
+template <typename T> T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
+  if (ZB == ZB_Max && Val == 0)
+    return std::numeric_limits<T>::max();
+
+  return countTrailingZeros(Val, ZB_Undefined);
+}
+
+/// Create a bitmask with the N right-most bits set to 1, and all other
+/// bits set to 0.  Only unsigned types are allowed.
+template <typename T> T maskTrailingOnes(unsigned N) {
+  static_assert(std::is_unsigned<T>::value, "Invalid type!");
+  const unsigned Bits = CHAR_BIT * sizeof(T);
+  assert(N <= Bits && "Invalid bit index");
+  return N == 0 ? 0 : (T(-1) >> (Bits - N));
+}
+
+/// Create a bitmask with the N left-most bits set to 1, and all other
+/// bits set to 0.  Only unsigned types are allowed.
+template <typename T> T maskLeadingOnes(unsigned N) {
+  return ~maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
+}
+
+/// Create a bitmask with the N right-most bits set to 0, and all other
+/// bits set to 1.  Only unsigned types are allowed.
+template <typename T> T maskTrailingZeros(unsigned N) {
+  return maskLeadingOnes<T>(CHAR_BIT * sizeof(T) - N);
+}
+
+/// Create a bitmask with the N left-most bits set to 0, and all other
+/// bits set to 1.  Only unsigned types are allowed.
+template <typename T> T maskLeadingZeros(unsigned N) {
+  return maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
+}
+
+/// Get the index of the last set bit starting from the least
+///   significant bit.
+///
+/// Only unsigned integral types are allowed.
+///
+/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
+///   valid arguments.
+template <typename T> T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
+  if (ZB == ZB_Max && Val == 0)
+    return std::numeric_limits<T>::max();
+
+  // Use ^ instead of - because both gcc and llvm can remove the associated ^
+  // in the __builtin_clz intrinsic on x86.
+  return countLeadingZeros(Val, ZB_Undefined) ^
+         (std::numeric_limits<T>::digits - 1);
+}
+
+/// Macro compressed bit reversal table for 256 bits.
+///
+/// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
+static const unsigned char BitReverseTable256[256] = {
+#define R2(n) n, n + 2 * 64, n + 1 * 64, n + 3 * 64
+#define R4(n) R2(n), R2(n + 2 * 16), R2(n + 1 * 16), R2(n + 3 * 16)
+#define R6(n) R4(n), R4(n + 2 * 4), R4(n + 1 * 4), R4(n + 3 * 4)
+  R6(0), R6(2), R6(1), R6(3)
+#undef R2
+#undef R4
+#undef R6
+};
+
+/// Reverse the bits in \p Val.
+template <typename T>
+T reverseBits(T Val) {
+  unsigned char in[sizeof(Val)];
+  unsigned char out[sizeof(Val)];
+  std::memcpy(in, &Val, sizeof(Val));
+  for (unsigned i = 0; i < sizeof(Val); ++i)
+    out[(sizeof(Val) - i) - 1] = BitReverseTable256[in[i]];
+  std::memcpy(&Val, out, sizeof(Val));
+  return Val;
+}
+
+// NOTE: The following support functions use the _32/_64 extensions instead of
+// type overloading so that signed and unsigned integers can be used without
+// ambiguity.
+
+/// Return the high 32 bits of a 64 bit value.
+constexpr inline uint32_t Hi_32(uint64_t Value) {
+  return static_cast<uint32_t>(Value >> 32);
+}
+
+/// Return the low 32 bits of a 64 bit value.
+constexpr inline uint32_t Lo_32(uint64_t Value) {
+  return static_cast<uint32_t>(Value);
+}
+
+/// Make a 64-bit integer from a high / low pair of 32-bit integers.
+constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) {
+  return ((uint64_t)High << 32) | (uint64_t)Low;
+}
+
+/// Checks if an integer fits into the given bit width.
+template <unsigned N> constexpr inline bool isInt(int64_t x) {
+  return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1)));
+}
+// Template specializations to get better code for common cases.
+template <> constexpr inline bool isInt<8>(int64_t x) {
+  return static_cast<int8_t>(x) == x;
+}
+template <> constexpr inline bool isInt<16>(int64_t x) {
+  return static_cast<int16_t>(x) == x;
+}
+template <> constexpr inline bool isInt<32>(int64_t x) {
+  return static_cast<int32_t>(x) == x;
+}
+
+/// Checks if a signed integer is an N bit number shifted left by S.
+template <unsigned N, unsigned S>
+constexpr inline bool isShiftedInt(int64_t x) {
+  static_assert(
+      N > 0, "isShiftedInt<0> doesn't make sense (refers to a 0-bit number.");
+  static_assert(N + S <= 64, "isShiftedInt<N, S> with N + S > 64 is too wide.");
+  return isInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
+}
+
+/// Checks if an unsigned integer fits into the given bit width.
+///
+/// This is written as two functions rather than as simply
+///
+///   return N >= 64 || X < (UINT64_C(1) << N);
+///
+/// to keep MSVC from (incorrectly) warning on isUInt<64> that we're shifting
+/// left too many places.
+template <unsigned N>
+constexpr inline typename std::enable_if<(N < 64), bool>::type
+isUInt(uint64_t X) {
+  static_assert(N > 0, "isUInt<0> doesn't make sense");
+  return X < (UINT64_C(1) << (N));
+}
+template <unsigned N>
+constexpr inline typename std::enable_if<N >= 64, bool>::type
+isUInt(uint64_t X) {
+  return true;
+}
+
+// Template specializations to get better code for common cases.
+template <> constexpr inline bool isUInt<8>(uint64_t x) {
+  return static_cast<uint8_t>(x) == x;
+}
+template <> constexpr inline bool isUInt<16>(uint64_t x) {
+  return static_cast<uint16_t>(x) == x;
+}
+template <> constexpr inline bool isUInt<32>(uint64_t x) {
+  return static_cast<uint32_t>(x) == x;
+}
+
+/// Checks if a unsigned integer is an N bit number shifted left by S.
+template <unsigned N, unsigned S>
+constexpr inline bool isShiftedUInt(uint64_t x) {
+  static_assert(
+      N > 0, "isShiftedUInt<0> doesn't make sense (refers to a 0-bit number)");
+  static_assert(N + S <= 64,
+                "isShiftedUInt<N, S> with N + S > 64 is too wide.");
+  // Per the two static_asserts above, S must be strictly less than 64.  So
+  // 1 << S is not undefined behavior.
+  return isUInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
+}
+
+/// Gets the maximum value for a N-bit unsigned integer.
+inline uint64_t maxUIntN(uint64_t N) {
+  assert(N > 0 && N <= 64 && "integer width out of range");
+
+  // uint64_t(1) << 64 is undefined behavior, so we can't do
+  //   (uint64_t(1) << N) - 1
+  // without checking first that N != 64.  But this works and doesn't have a
+  // branch.
+  return UINT64_MAX >> (64 - N);
+}
+
+/// Gets the minimum value for a N-bit signed integer.
+inline int64_t minIntN(int64_t N) {
+  assert(N > 0 && N <= 64 && "integer width out of range");
+
+  return -(UINT64_C(1)<<(N-1));
+}
+
+/// Gets the maximum value for a N-bit signed integer.
+inline int64_t maxIntN(int64_t N) {
+  assert(N > 0 && N <= 64 && "integer width out of range");
+
+  // This relies on two's complement wraparound when N == 64, so we convert to
+  // int64_t only at the very end to avoid UB.
+  return (UINT64_C(1) << (N - 1)) - 1;
+}
+
+/// Checks if an unsigned integer fits into the given (dynamic) bit width.
+inline bool isUIntN(unsigned N, uint64_t x) {
+  return N >= 64 || x <= maxUIntN(N);
+}
+
+/// Checks if an signed integer fits into the given (dynamic) bit width.
+inline bool isIntN(unsigned N, int64_t x) {
+  return N >= 64 || (minIntN(N) <= x && x <= maxIntN(N));
+}
+
+/// Return true if the argument is a non-empty sequence of ones starting at the
+/// least significant bit with the remainder zero (32 bit version).
+/// Ex. isMask_32(0x0000FFFFU) == true.
+constexpr inline bool isMask_32(uint32_t Value) {
+  return Value && ((Value + 1) & Value) == 0;
+}
+
+/// Return true if the argument is a non-empty sequence of ones starting at the
+/// least significant bit with the remainder zero (64 bit version).
+constexpr inline bool isMask_64(uint64_t Value) {
+  return Value && ((Value + 1) & Value) == 0;
+}
+
+/// Return true if the argument contains a non-empty sequence of ones with the
+/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true.
+constexpr inline bool isShiftedMask_32(uint32_t Value) {
+  return Value && isMask_32((Value - 1) | Value);
+}
+
+/// Return true if the argument contains a non-empty sequence of ones with the
+/// remainder zero (64 bit version.)
+constexpr inline bool isShiftedMask_64(uint64_t Value) {
+  return Value && isMask_64((Value - 1) | Value);
+}
+
+/// Return true if the argument is a power of two > 0.
+/// Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)
+constexpr inline bool isPowerOf2_32(uint32_t Value) {
+  return Value && !(Value & (Value - 1));
+}
+
+/// Return true if the argument is a power of two > 0 (64 bit edition.)
+constexpr inline bool isPowerOf2_64(uint64_t Value) {
+  return Value && !(Value & (Value - 1));
+}
+
+/// Return a byte-swapped representation of the 16-bit argument.
+inline uint16_t ByteSwap_16(uint16_t Value) {
+  return sys::SwapByteOrder_16(Value);
+}
+
+/// Return a byte-swapped representation of the 32-bit argument.
+inline uint32_t ByteSwap_32(uint32_t Value) {
+  return sys::SwapByteOrder_32(Value);
+}
+
+/// Return a byte-swapped representation of the 64-bit argument.
+inline uint64_t ByteSwap_64(uint64_t Value) {
+  return sys::SwapByteOrder_64(Value);
+}
+
+/// Count the number of ones from the most significant bit to the first
+/// zero bit.
+///
+/// Ex. countLeadingOnes(0xFF0FFF00) == 8.
+/// Only unsigned integral types are allowed.
+///
+/// \param ZB the behavior on an input of all ones. Only ZB_Width and
+/// ZB_Undefined are valid arguments.
+template <typename T>
+unsigned countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
+  static_assert(std::numeric_limits<T>::is_integer &&
+                    !std::numeric_limits<T>::is_signed,
+                "Only unsigned integral types are allowed.");
+  return countLeadingZeros<T>(~Value, ZB);
+}
+
+/// Count the number of ones from the least significant bit to the first
+/// zero bit.
+///
+/// Ex. countTrailingOnes(0x00FF00FF) == 8.
+/// Only unsigned integral types are allowed.
+///
+/// \param ZB the behavior on an input of all ones. Only ZB_Width and
+/// ZB_Undefined are valid arguments.
+template <typename T>
+unsigned countTrailingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
+  static_assert(std::numeric_limits<T>::is_integer &&
+                    !std::numeric_limits<T>::is_signed,
+                "Only unsigned integral types are allowed.");
+  return countTrailingZeros<T>(~Value, ZB);
+}
+
+namespace detail {
+template <typename T, std::size_t SizeOfT> struct PopulationCounter {
+  static unsigned count(T Value) {
+    // Generic version, forward to 32 bits.
+    static_assert(SizeOfT <= 4, "Not implemented!");
+#if defined(__GNUC__)
+    return __builtin_popcount(Value);
+#else
+    uint32_t v = Value;
+    v = v - ((v >> 1) & 0x55555555);
+    v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
+    return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
+#endif
+  }
+};
+
+template <typename T> struct PopulationCounter<T, 8> {
+  static unsigned count(T Value) {
+#if defined(__GNUC__)
+    return __builtin_popcountll(Value);
+#else
+    uint64_t v = Value;
+    v = v - ((v >> 1) & 0x5555555555555555ULL);
+    v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL);
+    v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
+    return unsigned((uint64_t)(v * 0x0101010101010101ULL) >> 56);
+#endif
+  }
+};
+} // namespace detail
+
+/// Count the number of set bits in a value.
+/// Ex. countPopulation(0xF000F000) = 8
+/// Returns 0 if the word is zero.
+template <typename T>
+inline unsigned countPopulation(T Value) {
+  static_assert(std::numeric_limits<T>::is_integer &&
+                    !std::numeric_limits<T>::is_signed,
+                "Only unsigned integral types are allowed.");
+  return detail::PopulationCounter<T, sizeof(T)>::count(Value);
+}
+
+/// Compile time Log2.
+/// Valid only for positive powers of two.
+template <size_t kValue> constexpr inline size_t CTLog2() {
+  static_assert(kValue > 0 && llvm::isPowerOf2_64(kValue),
+                "Value is not a valid power of 2");
+  return 1 + CTLog2<kValue / 2>();
+}
+
+template <> constexpr inline size_t CTLog2<1>() { return 0; }
+
+/// Return the log base 2 of the specified value.
+inline double Log2(double Value) {
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 18
+  return __builtin_log(Value) / __builtin_log(2.0);
+#else
+  return log2(Value);
+#endif
+}
+
+/// Return the floor log base 2 of the specified value, -1 if the value is zero.
+/// (32 bit edition.)
+/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2
+inline unsigned Log2_32(uint32_t Value) {
+  return 31 - countLeadingZeros(Value);
+}
+
+/// Return the floor log base 2 of the specified value, -1 if the value is zero.
+/// (64 bit edition.)
+inline unsigned Log2_64(uint64_t Value) {
+  return 63 - countLeadingZeros(Value);
+}
+
+/// Return the ceil log base 2 of the specified value, 32 if the value is zero.
+/// (32 bit edition).
+/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3
+inline unsigned Log2_32_Ceil(uint32_t Value) {
+  return 32 - countLeadingZeros(Value - 1);
+}
+
+/// Return the ceil log base 2 of the specified value, 64 if the value is zero.
+/// (64 bit edition.)
+inline unsigned Log2_64_Ceil(uint64_t Value) {
+  return 64 - countLeadingZeros(Value - 1);
+}
+
+/// Return the greatest common divisor of the values using Euclid's algorithm.
+template <typename T>
+inline T greatestCommonDivisor(T A, T B) {
+  while (B) {
+    T Tmp = B;
+    B = A % B;
+    A = Tmp;
+  }
+  return A;
+}
+
+inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
+  return greatestCommonDivisor<uint64_t>(A, B);
+}
+
+/// This function takes a 64-bit integer and returns the bit equivalent double.
+inline double BitsToDouble(uint64_t Bits) {
+  double D;
+  static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
+  memcpy(&D, &Bits, sizeof(Bits));
+  return D;
+}
+
+/// This function takes a 32-bit integer and returns the bit equivalent float.
+inline float BitsToFloat(uint32_t Bits) {
+  float F;
+  static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
+  memcpy(&F, &Bits, sizeof(Bits));
+  return F;
+}
+
+/// This function takes a double and returns the bit equivalent 64-bit integer.
+/// Note that copying doubles around changes the bits of NaNs on some hosts,
+/// notably x86, so this routine cannot be used if these bits are needed.
+inline uint64_t DoubleToBits(double Double) {
+  uint64_t Bits;
+  static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
+  memcpy(&Bits, &Double, sizeof(Double));
+  return Bits;
+}
+
+/// This function takes a float and returns the bit equivalent 32-bit integer.
+/// Note that copying floats around changes the bits of NaNs on some hosts,
+/// notably x86, so this routine cannot be used if these bits are needed.
+inline uint32_t FloatToBits(float Float) {
+  uint32_t Bits;
+  static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
+  memcpy(&Bits, &Float, sizeof(Float));
+  return Bits;
+}
+
+/// A and B are either alignments or offsets. Return the minimum alignment that
+/// may be assumed after adding the two together.
+constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) {
+  // The largest power of 2 that divides both A and B.
+  //
+  // Replace "-Value" by "1+~Value" in the following commented code to avoid
+  // MSVC warning C4146
+  //    return (A | B) & -(A | B);
+  return (A | B) & (1 + ~(A | B));
+}
+
+/// Returns the next power of two (in 64-bits) that is strictly greater than A.
+/// Returns zero on overflow.
+inline uint64_t NextPowerOf2(uint64_t A) {
+  A |= (A >> 1);
+  A |= (A >> 2);
+  A |= (A >> 4);
+  A |= (A >> 8);
+  A |= (A >> 16);
+  A |= (A >> 32);
+  return A + 1;
+}
+
+/// Returns the power of two which is less than or equal to the given value.
+/// Essentially, it is a floor operation across the domain of powers of two.
+inline uint64_t PowerOf2Floor(uint64_t A) {
+  if (!A) return 0;
+  return 1ull << (63 - countLeadingZeros(A, ZB_Undefined));
+}
+
+/// Returns the power of two which is greater than or equal to the given value.
+/// Essentially, it is a ceil operation across the domain of powers of two.
+inline uint64_t PowerOf2Ceil(uint64_t A) {
+  if (!A)
+    return 0;
+  return NextPowerOf2(A - 1);
+}
+
+/// Returns the next integer (mod 2**64) that is greater than or equal to
+/// \p Value and is a multiple of \p Align. \p Align must be non-zero.
+///
+/// If non-zero \p Skew is specified, the return value will be a minimal
+/// integer that is greater than or equal to \p Value and equal to
+/// \p Align * N + \p Skew for some integer N. If \p Skew is larger than
+/// \p Align, its value is adjusted to '\p Skew mod \p Align'.
+///
+/// Examples:
+/// \code
+///   alignTo(5, 8) = 8
+///   alignTo(17, 8) = 24
+///   alignTo(~0LL, 8) = 0
+///   alignTo(321, 255) = 510
+///
+///   alignTo(5, 8, 7) = 7
+///   alignTo(17, 8, 1) = 17
+///   alignTo(~0LL, 8, 3) = 3
+///   alignTo(321, 255, 42) = 552
+/// \endcode
+inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
+  assert(Align != 0u && "Align can't be 0.");
+  Skew %= Align;
+  return (Value + Align - 1 - Skew) / Align * Align + Skew;
+}
+
+/// Returns the next integer (mod 2**64) that is greater than or equal to
+/// \p Value and is a multiple of \c Align. \c Align must be non-zero.
+template <uint64_t Align> constexpr inline uint64_t alignTo(uint64_t Value) {
+  static_assert(Align != 0u, "Align must be non-zero");
+  return (Value + Align - 1) / Align * Align;
+}
+
+/// Returns the integer ceil(Numerator / Denominator).
+inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) {
+  return alignTo(Numerator, Denominator) / Denominator;
+}
+
+/// Returns the largest uint64_t less than or equal to \p Value and is
+/// \p Skew mod \p Align. \p Align must be non-zero
+inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
+  assert(Align != 0u && "Align can't be 0.");
+  Skew %= Align;
+  return (Value - Skew) / Align * Align + Skew;
+}
+
+/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
+/// Requires 0 < B <= 32.
+template <unsigned B> constexpr inline int32_t SignExtend32(uint32_t X) {
+  static_assert(B > 0, "Bit width can't be 0.");
+  static_assert(B <= 32, "Bit width out of range.");
+  return int32_t(X << (32 - B)) >> (32 - B);
+}
+
+/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
+/// Requires 0 < B < 32.
+inline int32_t SignExtend32(uint32_t X, unsigned B) {
+  assert(B > 0 && "Bit width can't be 0.");
+  assert(B <= 32 && "Bit width out of range.");
+  return int32_t(X << (32 - B)) >> (32 - B);
+}
+
+/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
+/// Requires 0 < B < 64.
+template <unsigned B> constexpr inline int64_t SignExtend64(uint64_t x) {
+  static_assert(B > 0, "Bit width can't be 0.");
+  static_assert(B <= 64, "Bit width out of range.");
+  return int64_t(x << (64 - B)) >> (64 - B);
+}
+
+/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
+/// Requires 0 < B < 64.
+inline int64_t SignExtend64(uint64_t X, unsigned B) {
+  assert(B > 0 && "Bit width can't be 0.");
+  assert(B <= 64 && "Bit width out of range.");
+  return int64_t(X << (64 - B)) >> (64 - B);
+}
+
+/// Subtract two unsigned integers, X and Y, of type T and return the absolute
+/// value of the result.
+template <typename T>
+typename std::enable_if<std::is_unsigned<T>::value, T>::type
+AbsoluteDifference(T X, T Y) {
+  return std::max(X, Y) - std::min(X, Y);
+}
+
+/// Add two unsigned integers, X and Y, of type T.  Clamp the result to the
+/// maximum representable value of T on overflow.  ResultOverflowed indicates if
+/// the result is larger than the maximum representable value of type T.
+template <typename T>
+typename std::enable_if<std::is_unsigned<T>::value, T>::type
+SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
+  bool Dummy;
+  bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
+  // Hacker's Delight, p. 29
+  T Z = X + Y;
+  Overflowed = (Z < X || Z < Y);
+  if (Overflowed)
+    return std::numeric_limits<T>::max();
+  else
+    return Z;
+}
+
+/// Multiply two unsigned integers, X and Y, of type T.  Clamp the result to the
+/// maximum representable value of T on overflow.  ResultOverflowed indicates if
+/// the result is larger than the maximum representable value of type T.
+template <typename T>
+typename std::enable_if<std::is_unsigned<T>::value, T>::type
+SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
+  bool Dummy;
+  bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
+
+  // Hacker's Delight, p. 30 has a different algorithm, but we don't use that
+  // because it fails for uint16_t (where multiplication can have undefined
+  // behavior due to promotion to int), and requires a division in addition
+  // to the multiplication.
+
+  Overflowed = false;
+
+  // Log2(Z) would be either Log2Z or Log2Z + 1.
+  // Special case: if X or Y is 0, Log2_64 gives -1, and Log2Z
+  // will necessarily be less than Log2Max as desired.
+  int Log2Z = Log2_64(X) + Log2_64(Y);
+  const T Max = std::numeric_limits<T>::max();
+  int Log2Max = Log2_64(Max);
+  if (Log2Z < Log2Max) {
+    return X * Y;
+  }
+  if (Log2Z > Log2Max) {
+    Overflowed = true;
+    return Max;
+  }
+
+  // We're going to use the top bit, and maybe overflow one
+  // bit past it. Multiply all but the bottom bit then add
+  // that on at the end.
+  T Z = (X >> 1) * Y;
+  if (Z & ~(Max >> 1)) {
+    Overflowed = true;
+    return Max;
+  }
+  Z <<= 1;
+  if (X & 1)
+    return SaturatingAdd(Z, Y, ResultOverflowed);
+
+  return Z;
+}
+
+/// Multiply two unsigned integers, X and Y, and add the unsigned integer, A to
+/// the product. Clamp the result to the maximum representable value of T on
+/// overflow. ResultOverflowed indicates if the result is larger than the
+/// maximum representable value of type T.
+template <typename T>
+typename std::enable_if<std::is_unsigned<T>::value, T>::type
+SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
+  bool Dummy;
+  bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
+
+  T Product = SaturatingMultiply(X, Y, &Overflowed);
+  if (Overflowed)
+    return Product;
+
+  return SaturatingAdd(A, Product, &Overflowed);
+}
+
+/// Use this rather than HUGE_VALF; the latter causes warnings on MSVC.
+extern const float huge_valf;
+
+
+/// Add two signed integers, computing the two's complement truncated result,
+/// returning true if overflow occured.
+template <typename T>
+typename std::enable_if<std::is_signed<T>::value, T>::type
+AddOverflow(T X, T Y, T &Result) {
+#if __has_builtin(__builtin_add_overflow)
+  return __builtin_add_overflow(X, Y, &Result);
+#else
+  // Perform the unsigned addition.
+  using U = typename std::make_unsigned<T>::type;
+  const U UX = static_cast<U>(X);
+  const U UY = static_cast<U>(Y);
+  const U UResult = UX + UY;
+
+  // Convert to signed.
+  Result = static_cast<T>(UResult);
+
+  // Adding two positive numbers should result in a positive number.
+  if (X > 0 && Y > 0)
+    return Result <= 0;
+  // Adding two negatives should result in a negative number.
+  if (X < 0 && Y < 0)
+    return Result >= 0;
+  return false;
+#endif
+}
+
+/// Subtract two signed integers, computing the two's complement truncated
+/// result, returning true if an overflow ocurred.
+template <typename T>
+typename std::enable_if<std::is_signed<T>::value, T>::type
+SubOverflow(T X, T Y, T &Result) {
+#if __has_builtin(__builtin_sub_overflow)
+  return __builtin_sub_overflow(X, Y, &Result);
+#else
+  // Perform the unsigned addition.
+  using U = typename std::make_unsigned<T>::type;
+  const U UX = static_cast<U>(X);
+  const U UY = static_cast<U>(Y);
+  const U UResult = UX - UY;
+
+  // Convert to signed.
+  Result = static_cast<T>(UResult);
+
+  // Subtracting a positive number from a negative results in a negative number.
+  if (X <= 0 && Y > 0)
+    return Result >= 0;
+  // Subtracting a negative number from a positive results in a positive number.
+  if (X >= 0 && Y < 0)
+    return Result <= 0;
+  return false;
+#endif
+}
+
+
+/// Multiply two signed integers, computing the two's complement truncated
+/// result, returning true if an overflow ocurred.
+template <typename T>
+typename std::enable_if<std::is_signed<T>::value, T>::type
+MulOverflow(T X, T Y, T &Result) {
+  // Perform the unsigned multiplication on absolute values.
+  using U = typename std::make_unsigned<T>::type;
+  const U UX = X < 0 ? (0 - static_cast<U>(X)) : static_cast<U>(X);
+  const U UY = Y < 0 ? (0 - static_cast<U>(Y)) : static_cast<U>(Y);
+  const U UResult = UX * UY;
+
+  // Convert to signed.
+  const bool IsNegative = (X < 0) ^ (Y < 0);
+  Result = IsNegative ? (0 - UResult) : UResult;
+
+  // If any of the args was 0, result is 0 and no overflow occurs.
+  if (UX == 0 || UY == 0)
+    return false;
+
+  // UX and UY are in [1, 2^n], where n is the number of digits.
+  // Check how the max allowed absolute value (2^n for negative, 2^(n-1) for
+  // positive) divided by an argument compares to the other.
+  if (IsNegative)
+    return UX > (static_cast<U>(std::numeric_limits<T>::max()) + U(1)) / UY;
+  else
+    return UX > (static_cast<U>(std::numeric_limits<T>::max())) / UY;
+}
+
+} // End llvm namespace
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/MemAlloc.h b/binaryen/third_party/llvm-project/include/llvm/Support/MemAlloc.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/MemAlloc.h
@@ -0,0 +1,66 @@
+//===- MemAlloc.h - Memory allocation functions -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file defines counterparts of C library allocation functions defined in
+/// the namespace 'std'. The new allocation functions crash on allocation
+/// failure instead of returning null pointer.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MEMALLOC_H
+#define LLVM_SUPPORT_MEMALLOC_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cstdlib>
+
+namespace llvm {
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_malloc(size_t Sz) {
+  void *Result = std::malloc(Sz);
+  if (Result == nullptr) {
+    // It is implementation-defined whether allocation occurs if the space
+    // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
+    // non-zero, if the space requested was zero.
+    if (Sz == 0)
+      return safe_malloc(1);
+    report_bad_alloc_error("Allocation failed");
+  }
+  return Result;
+}
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_calloc(size_t Count,
+                                                        size_t Sz) {
+  void *Result = std::calloc(Count, Sz);
+  if (Result == nullptr) {
+    // It is implementation-defined whether allocation occurs if the space
+    // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
+    // non-zero, if the space requested was zero.
+    if (Count == 0 || Sz == 0)
+      return safe_malloc(1);
+    report_bad_alloc_error("Allocation failed");
+  }
+  return Result;
+}
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_realloc(void *Ptr, size_t Sz) {
+  void *Result = std::realloc(Ptr, Sz);
+  if (Result == nullptr) {
+    // It is implementation-defined whether allocation occurs if the space
+    // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
+    // non-zero, if the space requested was zero.
+    if (Sz == 0)
+      return safe_malloc(1);
+    report_bad_alloc_error("Allocation failed");
+  }
+  return Result;
+}
+
+}
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/MemoryBuffer.h b/binaryen/third_party/llvm-project/include/llvm/Support/MemoryBuffer.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/MemoryBuffer.h
@@ -0,0 +1,286 @@
+//===--- MemoryBuffer.h - Memory Buffer Interface ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the MemoryBuffer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MEMORYBUFFER_H
+#define LLVM_SUPPORT_MEMORYBUFFER_H
+
+#include "llvm-c/Types.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/CBindingWrapping.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+
+namespace llvm {
+
+class MemoryBufferRef;
+
+/// This interface provides simple read-only access to a block of memory, and
+/// provides simple methods for reading files and standard input into a memory
+/// buffer.  In addition to basic access to the characters in the file, this
+/// interface guarantees you can read one character past the end of the file,
+/// and that this character will read as '\0'.
+///
+/// The '\0' guarantee is needed to support an optimization -- it's intended to
+/// be more efficient for clients which are reading all the data to stop
+/// reading when they encounter a '\0' than to continually check the file
+/// position to see if it has reached the end of the file.
+class MemoryBuffer {
+  const char *BufferStart; // Start of the buffer.
+  const char *BufferEnd;   // End of the buffer.
+
+protected:
+  MemoryBuffer() = default;
+
+  void init(const char *BufStart, const char *BufEnd,
+            bool RequiresNullTerminator);
+
+  static constexpr sys::fs::mapped_file_region::mapmode Mapmode =
+      sys::fs::mapped_file_region::readonly;
+
+public:
+  MemoryBuffer(const MemoryBuffer &) = delete;
+  MemoryBuffer &operator=(const MemoryBuffer &) = delete;
+  virtual ~MemoryBuffer();
+
+  const char *getBufferStart() const { return BufferStart; }
+  const char *getBufferEnd() const   { return BufferEnd; }
+  size_t getBufferSize() const { return BufferEnd-BufferStart; }
+
+  StringRef getBuffer() const {
+    return StringRef(BufferStart, getBufferSize());
+  }
+
+  /// Return an identifier for this buffer, typically the filename it was read
+  /// from.
+  virtual StringRef getBufferIdentifier() const { return "Unknown buffer"; }
+
+  /// Open the specified file as a MemoryBuffer, returning a new MemoryBuffer
+  /// if successful, otherwise returning null. If FileSize is specified, this
+  /// means that the client knows that the file exists and that it has the
+  /// specified size.
+  ///
+  /// \param IsVolatile Set to true to indicate that the contents of the file
+  /// can change outside the user's control, e.g. when libclang tries to parse
+  /// while the user is editing/updating the file or if the file is on an NFS.
+  static ErrorOr<std::unique_ptr<MemoryBuffer>>
+  getFile(const Twine &Filename, int64_t FileSize = -1,
+          bool RequiresNullTerminator = true, bool IsVolatile = false);
+
+  /// Read all of the specified file into a MemoryBuffer as a stream
+  /// (i.e. until EOF reached). This is useful for special files that
+  /// look like a regular file but have 0 size (e.g. /proc/cpuinfo on Linux).
+  static ErrorOr<std::unique_ptr<MemoryBuffer>>
+  getFileAsStream(const Twine &Filename);
+
+  /// Given an already-open file descriptor, map some slice of it into a
+  /// MemoryBuffer. The slice is specified by an \p Offset and \p MapSize.
+  /// Since this is in the middle of a file, the buffer is not null terminated.
+  static ErrorOr<std::unique_ptr<MemoryBuffer>>
+  getOpenFileSlice(sys::fs::file_t FD, const Twine &Filename, uint64_t MapSize,
+                   int64_t Offset, bool IsVolatile = false);
+
+  /// Given an already-open file descriptor, read the file and return a
+  /// MemoryBuffer.
+  ///
+  /// \param IsVolatile Set to true to indicate that the contents of the file
+  /// can change outside the user's control, e.g. when libclang tries to parse
+  /// while the user is editing/updating the file or if the file is on an NFS.
+  static ErrorOr<std::unique_ptr<MemoryBuffer>>
+  getOpenFile(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize,
+              bool RequiresNullTerminator = true, bool IsVolatile = false);
+
+  /// Open the specified memory range as a MemoryBuffer. Note that InputData
+  /// must be null terminated if RequiresNullTerminator is true.
+  static std::unique_ptr<MemoryBuffer>
+  getMemBuffer(StringRef InputData, StringRef BufferName = "",
+               bool RequiresNullTerminator = true);
+
+  static std::unique_ptr<MemoryBuffer>
+  getMemBuffer(MemoryBufferRef Ref, bool RequiresNullTerminator = true);
+
+  /// Open the specified memory range as a MemoryBuffer, copying the contents
+  /// and taking ownership of it. InputData does not have to be null terminated.
+  static std::unique_ptr<MemoryBuffer>
+  getMemBufferCopy(StringRef InputData, const Twine &BufferName = "");
+
+  /// Read all of stdin into a file buffer, and return it.
+  static ErrorOr<std::unique_ptr<MemoryBuffer>> getSTDIN();
+
+  /// Open the specified file as a MemoryBuffer, or open stdin if the Filename
+  /// is "-".
+  static ErrorOr<std::unique_ptr<MemoryBuffer>>
+  getFileOrSTDIN(const Twine &Filename, int64_t FileSize = -1,
+                 bool RequiresNullTerminator = true);
+
+  /// Map a subrange of the specified file as a MemoryBuffer.
+  static ErrorOr<std::unique_ptr<MemoryBuffer>>
+  getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset,
+               bool IsVolatile = false);
+
+  //===--------------------------------------------------------------------===//
+  // Provided for performance analysis.
+  //===--------------------------------------------------------------------===//
+
+  /// The kind of memory backing used to support the MemoryBuffer.
+  enum BufferKind {
+    MemoryBuffer_Malloc,
+    MemoryBuffer_MMap
+  };
+
+  /// Return information on the memory mechanism used to support the
+  /// MemoryBuffer.
+  virtual BufferKind getBufferKind() const = 0;
+
+  MemoryBufferRef getMemBufferRef() const;
+};
+
+/// This class is an extension of MemoryBuffer, which allows copy-on-write
+/// access to the underlying contents.  It only supports creation methods that
+/// are guaranteed to produce a writable buffer.  For example, mapping a file
+/// read-only is not supported.
+class WritableMemoryBuffer : public MemoryBuffer {
+protected:
+  WritableMemoryBuffer() = default;
+
+  static constexpr sys::fs::mapped_file_region::mapmode Mapmode =
+      sys::fs::mapped_file_region::priv;
+
+public:
+  using MemoryBuffer::getBuffer;
+  using MemoryBuffer::getBufferEnd;
+  using MemoryBuffer::getBufferStart;
+
+  // const_cast is well-defined here, because the underlying buffer is
+  // guaranteed to have been initialized with a mutable buffer.
+  char *getBufferStart() {
+    return const_cast<char *>(MemoryBuffer::getBufferStart());
+  }
+  char *getBufferEnd() {
+    return const_cast<char *>(MemoryBuffer::getBufferEnd());
+  }
+  MutableArrayRef<char> getBuffer() {
+    return {getBufferStart(), getBufferEnd()};
+  }
+
+  static ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
+  getFile(const Twine &Filename, int64_t FileSize = -1,
+          bool IsVolatile = false);
+
+  /// Map a subrange of the specified file as a WritableMemoryBuffer.
+  static ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
+  getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset,
+               bool IsVolatile = false);
+
+  /// Allocate a new MemoryBuffer of the specified size that is not initialized.
+  /// Note that the caller should initialize the memory allocated by this
+  /// method. The memory is owned by the MemoryBuffer object.
+  static std::unique_ptr<WritableMemoryBuffer>
+  getNewUninitMemBuffer(size_t Size, const Twine &BufferName = "");
+
+  /// Allocate a new zero-initialized MemoryBuffer of the specified size. Note
+  /// that the caller need not initialize the memory allocated by this method.
+  /// The memory is owned by the MemoryBuffer object.
+  static std::unique_ptr<WritableMemoryBuffer>
+  getNewMemBuffer(size_t Size, const Twine &BufferName = "");
+
+private:
+  // Hide these base class factory function so one can't write
+  //   WritableMemoryBuffer::getXXX()
+  // and be surprised that he got a read-only Buffer.
+  using MemoryBuffer::getFileAsStream;
+  using MemoryBuffer::getFileOrSTDIN;
+  using MemoryBuffer::getMemBuffer;
+  using MemoryBuffer::getMemBufferCopy;
+  using MemoryBuffer::getOpenFile;
+  using MemoryBuffer::getOpenFileSlice;
+  using MemoryBuffer::getSTDIN;
+};
+
+/// This class is an extension of MemoryBuffer, which allows write access to
+/// the underlying contents and committing those changes to the original source.
+/// It only supports creation methods that are guaranteed to produce a writable
+/// buffer.  For example, mapping a file read-only is not supported.
+class WriteThroughMemoryBuffer : public MemoryBuffer {
+protected:
+  WriteThroughMemoryBuffer() = default;
+
+  static constexpr sys::fs::mapped_file_region::mapmode Mapmode =
+      sys::fs::mapped_file_region::readwrite;
+
+public:
+  using MemoryBuffer::getBuffer;
+  using MemoryBuffer::getBufferEnd;
+  using MemoryBuffer::getBufferStart;
+
+  // const_cast is well-defined here, because the underlying buffer is
+  // guaranteed to have been initialized with a mutable buffer.
+  char *getBufferStart() {
+    return const_cast<char *>(MemoryBuffer::getBufferStart());
+  }
+  char *getBufferEnd() {
+    return const_cast<char *>(MemoryBuffer::getBufferEnd());
+  }
+  MutableArrayRef<char> getBuffer() {
+    return {getBufferStart(), getBufferEnd()};
+  }
+
+  static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>>
+  getFile(const Twine &Filename, int64_t FileSize = -1);
+
+  /// Map a subrange of the specified file as a ReadWriteMemoryBuffer.
+  static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>>
+  getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset);
+
+private:
+  // Hide these base class factory function so one can't write
+  //   WritableMemoryBuffer::getXXX()
+  // and be surprised that he got a read-only Buffer.
+  using MemoryBuffer::getFileAsStream;
+  using MemoryBuffer::getFileOrSTDIN;
+  using MemoryBuffer::getMemBuffer;
+  using MemoryBuffer::getMemBufferCopy;
+  using MemoryBuffer::getOpenFile;
+  using MemoryBuffer::getOpenFileSlice;
+  using MemoryBuffer::getSTDIN;
+};
+
+class MemoryBufferRef {
+  StringRef Buffer;
+  StringRef Identifier;
+
+public:
+  MemoryBufferRef() = default;
+  MemoryBufferRef(const MemoryBuffer& Buffer)
+      : Buffer(Buffer.getBuffer()), Identifier(Buffer.getBufferIdentifier()) {}
+  MemoryBufferRef(StringRef Buffer, StringRef Identifier)
+      : Buffer(Buffer), Identifier(Identifier) {}
+
+  StringRef getBuffer() const { return Buffer; }
+
+  StringRef getBufferIdentifier() const { return Identifier; }
+
+  const char *getBufferStart() const { return Buffer.begin(); }
+  const char *getBufferEnd() const { return Buffer.end(); }
+  size_t getBufferSize() const { return Buffer.size(); }
+};
+
+// Create wrappers for C Binding types (see CBindingWrapping.h).
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(MemoryBuffer, LLVMMemoryBufferRef)
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_MEMORYBUFFER_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/NativeFormatting.h b/binaryen/third_party/llvm-project/include/llvm/Support/NativeFormatting.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/NativeFormatting.h
@@ -0,0 +1,48 @@
+//===- NativeFormatting.h - Low level formatting helpers ---------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_NATIVE_FORMATTING_H
+#define LLVM_SUPPORT_NATIVE_FORMATTING_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <cstdint>
+
+namespace llvm {
+enum class FloatStyle { Exponent, ExponentUpper, Fixed, Percent };
+enum class IntegerStyle {
+  Integer,
+  Number,
+};
+enum class HexPrintStyle { Upper, Lower, PrefixUpper, PrefixLower };
+
+size_t getDefaultPrecision(FloatStyle Style);
+
+bool isPrefixedHexStyle(HexPrintStyle S);
+
+void write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
+                   IntegerStyle Style);
+void write_integer(raw_ostream &S, int N, size_t MinDigits, IntegerStyle Style);
+void write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
+                   IntegerStyle Style);
+void write_integer(raw_ostream &S, long N, size_t MinDigits,
+                   IntegerStyle Style);
+void write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
+                   IntegerStyle Style);
+void write_integer(raw_ostream &S, long long N, size_t MinDigits,
+                   IntegerStyle Style);
+
+void write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
+               Optional<size_t> Width = None);
+void write_double(raw_ostream &S, double D, FloatStyle Style,
+                  Optional<size_t> Precision = None);
+}
+
+#endif
+
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Path.h b/binaryen/third_party/llvm-project/include/llvm/Support/Path.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Path.h
@@ -0,0 +1,464 @@
+//===- llvm/Support/Path.h - Path Operating System Concept ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the llvm::sys::path namespace. It is designed after
+// TR2/boost filesystem (v3), but modified to remove exception handling and the
+// path class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_PATH_H
+#define LLVM_SUPPORT_PATH_H
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/Support/DataTypes.h"
+#include <iterator>
+#include <system_error>
+
+namespace llvm {
+namespace sys {
+namespace path {
+
+enum class Style { windows, posix, native };
+
+/// @name Lexical Component Iterator
+/// @{
+
+/// Path iterator.
+///
+/// This is an input iterator that iterates over the individual components in
+/// \a path. The traversal order is as follows:
+/// * The root-name element, if present.
+/// * The root-directory element, if present.
+/// * Each successive filename element, if present.
+/// * Dot, if one or more trailing non-root slash characters are present.
+/// Traversing backwards is possible with \a reverse_iterator
+///
+/// Iteration examples. Each component is separated by ',':
+/// @code
+///   /          => /
+///   /foo       => /,foo
+///   foo/       => foo,.
+///   /foo/bar   => /,foo,bar
+///   ../        => ..,.
+///   C:\foo\bar => C:,/,foo,bar
+/// @endcode
+class const_iterator
+    : public iterator_facade_base<const_iterator, std::input_iterator_tag,
+                                  const StringRef> {
+  StringRef Path;          ///< The entire path.
+  StringRef Component;     ///< The current component. Not necessarily in Path.
+  size_t    Position = 0;  ///< The iterators current position within Path.
+  Style S = Style::native; ///< The path style to use.
+
+  // An end iterator has Position = Path.size() + 1.
+  friend const_iterator begin(StringRef path, Style style);
+  friend const_iterator end(StringRef path);
+
+public:
+  reference operator*() const { return Component; }
+  const_iterator &operator++();    // preincrement
+  bool operator==(const const_iterator &RHS) const;
+
+  /// Difference in bytes between this and RHS.
+  ptrdiff_t operator-(const const_iterator &RHS) const;
+};
+
+/// Reverse path iterator.
+///
+/// This is an input iterator that iterates over the individual components in
+/// \a path in reverse order. The traversal order is exactly reversed from that
+/// of \a const_iterator
+class reverse_iterator
+    : public iterator_facade_base<reverse_iterator, std::input_iterator_tag,
+                                  const StringRef> {
+  StringRef Path;          ///< The entire path.
+  StringRef Component;     ///< The current component. Not necessarily in Path.
+  size_t    Position = 0;  ///< The iterators current position within Path.
+  Style S = Style::native; ///< The path style to use.
+
+  friend reverse_iterator rbegin(StringRef path, Style style);
+  friend reverse_iterator rend(StringRef path);
+
+public:
+  reference operator*() const { return Component; }
+  reverse_iterator &operator++();    // preincrement
+  bool operator==(const reverse_iterator &RHS) const;
+
+  /// Difference in bytes between this and RHS.
+  ptrdiff_t operator-(const reverse_iterator &RHS) const;
+};
+
+/// Get begin iterator over \a path.
+/// @param path Input path.
+/// @returns Iterator initialized with the first component of \a path.
+const_iterator begin(StringRef path, Style style = Style::native);
+
+/// Get end iterator over \a path.
+/// @param path Input path.
+/// @returns Iterator initialized to the end of \a path.
+const_iterator end(StringRef path);
+
+/// Get reverse begin iterator over \a path.
+/// @param path Input path.
+/// @returns Iterator initialized with the first reverse component of \a path.
+reverse_iterator rbegin(StringRef path, Style style = Style::native);
+
+/// Get reverse end iterator over \a path.
+/// @param path Input path.
+/// @returns Iterator initialized to the reverse end of \a path.
+reverse_iterator rend(StringRef path);
+
+/// @}
+/// @name Lexical Modifiers
+/// @{
+
+/// Remove the last component from \a path unless it is the root dir.
+///
+/// Similar to the POSIX "dirname" utility.
+///
+/// @code
+///   directory/filename.cpp => directory/
+///   directory/             => directory
+///   filename.cpp           => <empty>
+///   /                      => /
+/// @endcode
+///
+/// @param path A path that is modified to not have a file component.
+void remove_filename(SmallVectorImpl<char> &path, Style style = Style::native);
+
+/// Replace the file extension of \a path with \a extension.
+///
+/// @code
+///   ./filename.cpp => ./filename.extension
+///   ./filename     => ./filename.extension
+///   ./             => ./.extension
+/// @endcode
+///
+/// @param path A path that has its extension replaced with \a extension.
+/// @param extension The extension to be added. It may be empty. It may also
+///                  optionally start with a '.', if it does not, one will be
+///                  prepended.
+void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
+                       Style style = Style::native);
+
+/// Replace matching path prefix with another path.
+///
+/// @code
+///   /foo, /old, /new => /foo
+///   /old/foo, /old, /new => /new/foo
+///   /foo, <empty>, /new => /new/foo
+///   /old/foo, /old, <empty> => /foo
+/// @endcode
+///
+/// @param Path If \a Path starts with \a OldPrefix modify to instead
+///        start with \a NewPrefix.
+/// @param OldPrefix The path prefix to strip from \a Path.
+/// @param NewPrefix The path prefix to replace \a NewPrefix with.
+void replace_path_prefix(SmallVectorImpl<char> &Path,
+                         const StringRef &OldPrefix, const StringRef &NewPrefix,
+                         Style style = Style::native);
+
+/// Append to path.
+///
+/// @code
+///   /foo  + bar/f => /foo/bar/f
+///   /foo/ + bar/f => /foo/bar/f
+///   foo   + bar/f => foo/bar/f
+/// @endcode
+///
+/// @param path Set to \a path + \a component.
+/// @param a The component to be appended to \a path.
+void append(SmallVectorImpl<char> &path, const Twine &a,
+                                         const Twine &b = "",
+                                         const Twine &c = "",
+                                         const Twine &d = "");
+
+void append(SmallVectorImpl<char> &path, Style style, const Twine &a,
+            const Twine &b = "", const Twine &c = "", const Twine &d = "");
+
+/// Append to path.
+///
+/// @code
+///   /foo  + [bar,f] => /foo/bar/f
+///   /foo/ + [bar,f] => /foo/bar/f
+///   foo   + [bar,f] => foo/bar/f
+/// @endcode
+///
+/// @param path Set to \a path + [\a begin, \a end).
+/// @param begin Start of components to append.
+/// @param end One past the end of components to append.
+void append(SmallVectorImpl<char> &path, const_iterator begin,
+            const_iterator end, Style style = Style::native);
+
+/// @}
+/// @name Transforms (or some other better name)
+/// @{
+
+/// Convert path to the native form. This is used to give paths to users and
+/// operating system calls in the platform's normal way. For example, on Windows
+/// all '/' are converted to '\'.
+///
+/// @param path A path that is transformed to native format.
+/// @param result Holds the result of the transformation.
+void native(const Twine &path, SmallVectorImpl<char> &result,
+            Style style = Style::native);
+
+/// Convert path to the native form in place. This is used to give paths to
+/// users and operating system calls in the platform's normal way. For example,
+/// on Windows all '/' are converted to '\'.
+///
+/// @param path A path that is transformed to native format.
+void native(SmallVectorImpl<char> &path, Style style = Style::native);
+
+/// Replaces backslashes with slashes if Windows.
+///
+/// @param path processed path
+/// @result The result of replacing backslashes with forward slashes if Windows.
+/// On Unix, this function is a no-op because backslashes are valid path
+/// chracters.
+std::string convert_to_slash(StringRef path, Style style = Style::native);
+
+/// @}
+/// @name Lexical Observers
+/// @{
+
+/// Get root name.
+///
+/// @code
+///   //net/hello => //net
+///   c:/hello    => c: (on Windows, on other platforms nothing)
+///   /hello      => <empty>
+/// @endcode
+///
+/// @param path Input path.
+/// @result The root name of \a path if it has one, otherwise "".
+StringRef root_name(StringRef path, Style style = Style::native);
+
+/// Get root directory.
+///
+/// @code
+///   /goo/hello => /
+///   c:/hello   => /
+///   d/file.txt => <empty>
+/// @endcode
+///
+/// @param path Input path.
+/// @result The root directory of \a path if it has one, otherwise
+///               "".
+StringRef root_directory(StringRef path, Style style = Style::native);
+
+/// Get root path.
+///
+/// Equivalent to root_name + root_directory.
+///
+/// @param path Input path.
+/// @result The root path of \a path if it has one, otherwise "".
+StringRef root_path(StringRef path, Style style = Style::native);
+
+/// Get relative path.
+///
+/// @code
+///   C:\hello\world => hello\world
+///   foo/bar        => foo/bar
+///   /foo/bar       => foo/bar
+/// @endcode
+///
+/// @param path Input path.
+/// @result The path starting after root_path if one exists, otherwise "".
+StringRef relative_path(StringRef path, Style style = Style::native);
+
+/// Get parent path.
+///
+/// @code
+///   /          => <empty>
+///   /foo       => /
+///   foo/../bar => foo/..
+/// @endcode
+///
+/// @param path Input path.
+/// @result The parent path of \a path if one exists, otherwise "".
+StringRef parent_path(StringRef path, Style style = Style::native);
+
+/// Get filename.
+///
+/// @code
+///   /foo.txt    => foo.txt
+///   .          => .
+///   ..         => ..
+///   /          => /
+/// @endcode
+///
+/// @param path Input path.
+/// @result The filename part of \a path. This is defined as the last component
+///         of \a path. Similar to the POSIX "basename" utility.
+StringRef filename(StringRef path, Style style = Style::native);
+
+/// Get stem.
+///
+/// If filename contains a dot but not solely one or two dots, result is the
+/// substring of filename ending at (but not including) the last dot. Otherwise
+/// it is filename.
+///
+/// @code
+///   /foo/bar.txt => bar
+///   /foo/bar     => bar
+///   /foo/.txt    => <empty>
+///   /foo/.       => .
+///   /foo/..      => ..
+/// @endcode
+///
+/// @param path Input path.
+/// @result The stem of \a path.
+StringRef stem(StringRef path, Style style = Style::native);
+
+/// Get extension.
+///
+/// If filename contains a dot but not solely one or two dots, result is the
+/// substring of filename starting at (and including) the last dot, and ending
+/// at the end of \a path. Otherwise "".
+///
+/// @code
+///   /foo/bar.txt => .txt
+///   /foo/bar     => <empty>
+///   /foo/.txt    => .txt
+/// @endcode
+///
+/// @param path Input path.
+/// @result The extension of \a path.
+StringRef extension(StringRef path, Style style = Style::native);
+
+/// Check whether the given char is a path separator on the host OS.
+///
+/// @param value a character
+/// @result true if \a value is a path separator character on the host OS
+bool is_separator(char value, Style style = Style::native);
+
+/// Return the preferred separator for this platform.
+///
+/// @result StringRef of the preferred separator, null-terminated.
+StringRef get_separator(Style style = Style::native);
+
+/// Get the typical temporary directory for the system, e.g.,
+/// "/var/tmp" or "C:/TEMP"
+///
+/// @param erasedOnReboot Whether to favor a path that is erased on reboot
+/// rather than one that potentially persists longer. This parameter will be
+/// ignored if the user or system has set the typical environment variable
+/// (e.g., TEMP on Windows, TMPDIR on *nix) to specify a temporary directory.
+///
+/// @param result Holds the resulting path name.
+void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result);
+
+/// Get the user's home directory.
+///
+/// @param result Holds the resulting path name.
+/// @result True if a home directory is set, false otherwise.
+bool home_directory(SmallVectorImpl<char> &result);
+
+/// Has root name?
+///
+/// root_name != ""
+///
+/// @param path Input path.
+/// @result True if the path has a root name, false otherwise.
+bool has_root_name(const Twine &path, Style style = Style::native);
+
+/// Has root directory?
+///
+/// root_directory != ""
+///
+/// @param path Input path.
+/// @result True if the path has a root directory, false otherwise.
+bool has_root_directory(const Twine &path, Style style = Style::native);
+
+/// Has root path?
+///
+/// root_path != ""
+///
+/// @param path Input path.
+/// @result True if the path has a root path, false otherwise.
+bool has_root_path(const Twine &path, Style style = Style::native);
+
+/// Has relative path?
+///
+/// relative_path != ""
+///
+/// @param path Input path.
+/// @result True if the path has a relative path, false otherwise.
+bool has_relative_path(const Twine &path, Style style = Style::native);
+
+/// Has parent path?
+///
+/// parent_path != ""
+///
+/// @param path Input path.
+/// @result True if the path has a parent path, false otherwise.
+bool has_parent_path(const Twine &path, Style style = Style::native);
+
+/// Has filename?
+///
+/// filename != ""
+///
+/// @param path Input path.
+/// @result True if the path has a filename, false otherwise.
+bool has_filename(const Twine &path, Style style = Style::native);
+
+/// Has stem?
+///
+/// stem != ""
+///
+/// @param path Input path.
+/// @result True if the path has a stem, false otherwise.
+bool has_stem(const Twine &path, Style style = Style::native);
+
+/// Has extension?
+///
+/// extension != ""
+///
+/// @param path Input path.
+/// @result True if the path has a extension, false otherwise.
+bool has_extension(const Twine &path, Style style = Style::native);
+
+/// Is path absolute?
+///
+/// @param path Input path.
+/// @result True if the path is absolute, false if it is not.
+bool is_absolute(const Twine &path, Style style = Style::native);
+
+/// Is path relative?
+///
+/// @param path Input path.
+/// @result True if the path is relative, false if it is not.
+bool is_relative(const Twine &path, Style style = Style::native);
+
+/// Remove redundant leading "./" pieces and consecutive separators.
+///
+/// @param path Input path.
+/// @result The cleaned-up \a path.
+StringRef remove_leading_dotslash(StringRef path, Style style = Style::native);
+
+/// In-place remove any './' and optionally '../' components from a path.
+///
+/// @param path processed path
+/// @param remove_dot_dot specify if '../' (except for leading "../") should be
+/// removed
+/// @result True if path was changed
+bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot = false,
+                 Style style = Style::native);
+
+#if defined(_WIN32)
+std::error_code widenPath(const Twine &Path8, SmallVectorImpl<wchar_t> &Path16);
+#endif
+
+} // end namespace path
+} // end namespace sys
+} // end namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/PointerLikeTypeTraits.h b/binaryen/third_party/llvm-project/include/llvm/Support/PointerLikeTypeTraits.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/PointerLikeTypeTraits.h
@@ -0,0 +1,149 @@
+//===- llvm/Support/PointerLikeTypeTraits.h - Pointer Traits ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the PointerLikeTypeTraits class.  This allows data
+// structures to reason about pointers and other things that are pointer sized.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
+#define LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
+
+#include "llvm/Support/DataTypes.h"
+#include <assert.h>
+#include <type_traits>
+
+namespace llvm {
+
+/// A traits type that is used to handle pointer types and things that are just
+/// wrappers for pointers as a uniform entity.
+template <typename T> struct PointerLikeTypeTraits;
+
+namespace detail {
+/// A tiny meta function to compute the log2 of a compile time constant.
+template <size_t N>
+struct ConstantLog2
+    : std::integral_constant<size_t, ConstantLog2<N / 2>::value + 1> {};
+template <> struct ConstantLog2<1> : std::integral_constant<size_t, 0> {};
+
+// Provide a trait to check if T is pointer-like.
+template <typename T, typename U = void> struct HasPointerLikeTypeTraits {
+  static const bool value = false;
+};
+
+// sizeof(T) is valid only for a complete T.
+template <typename T> struct HasPointerLikeTypeTraits<
+  T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> {
+  static const bool value = true;
+};
+
+template <typename T> struct IsPointerLike {
+  static const bool value = HasPointerLikeTypeTraits<T>::value;
+};
+
+template <typename T> struct IsPointerLike<T *> {
+  static const bool value = true;
+};
+} // namespace detail
+
+// Provide PointerLikeTypeTraits for non-cvr pointers.
+template <typename T> struct PointerLikeTypeTraits<T *> {
+  static inline void *getAsVoidPointer(T *P) { return P; }
+  static inline T *getFromVoidPointer(void *P) { return static_cast<T *>(P); }
+
+  enum { NumLowBitsAvailable = detail::ConstantLog2<alignof(T)>::value };
+};
+
+template <> struct PointerLikeTypeTraits<void *> {
+  static inline void *getAsVoidPointer(void *P) { return P; }
+  static inline void *getFromVoidPointer(void *P) { return P; }
+
+  /// Note, we assume here that void* is related to raw malloc'ed memory and
+  /// that malloc returns objects at least 4-byte aligned. However, this may be
+  /// wrong, or pointers may be from something other than malloc. In this case,
+  /// you should specify a real typed pointer or avoid this template.
+  ///
+  /// All clients should use assertions to do a run-time check to ensure that
+  /// this is actually true.
+  enum { NumLowBitsAvailable = 2 };
+};
+
+// Provide PointerLikeTypeTraits for const things.
+template <typename T> struct PointerLikeTypeTraits<const T> {
+  typedef PointerLikeTypeTraits<T> NonConst;
+
+  static inline const void *getAsVoidPointer(const T P) {
+    return NonConst::getAsVoidPointer(P);
+  }
+  static inline const T getFromVoidPointer(const void *P) {
+    return NonConst::getFromVoidPointer(const_cast<void *>(P));
+  }
+  enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable };
+};
+
+// Provide PointerLikeTypeTraits for const pointers.
+template <typename T> struct PointerLikeTypeTraits<const T *> {
+  typedef PointerLikeTypeTraits<T *> NonConst;
+
+  static inline const void *getAsVoidPointer(const T *P) {
+    return NonConst::getAsVoidPointer(const_cast<T *>(P));
+  }
+  static inline const T *getFromVoidPointer(const void *P) {
+    return NonConst::getFromVoidPointer(const_cast<void *>(P));
+  }
+  enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable };
+};
+
+// Provide PointerLikeTypeTraits for uintptr_t.
+template <> struct PointerLikeTypeTraits<uintptr_t> {
+  static inline void *getAsVoidPointer(uintptr_t P) {
+    return reinterpret_cast<void *>(P);
+  }
+  static inline uintptr_t getFromVoidPointer(void *P) {
+    return reinterpret_cast<uintptr_t>(P);
+  }
+  // No bits are available!
+  enum { NumLowBitsAvailable = 0 };
+};
+
+/// Provide suitable custom traits struct for function pointers.
+///
+/// Function pointers can't be directly given these traits as functions can't
+/// have their alignment computed with `alignof` and we need different casting.
+///
+/// To rely on higher alignment for a specialized use, you can provide a
+/// customized form of this template explicitly with higher alignment, and
+/// potentially use alignment attributes on functions to satisfy that.
+template <int Alignment, typename FunctionPointerT>
+struct FunctionPointerLikeTypeTraits {
+  enum { NumLowBitsAvailable = detail::ConstantLog2<Alignment>::value };
+  static inline void *getAsVoidPointer(FunctionPointerT P) {
+    assert((reinterpret_cast<uintptr_t>(P) &
+            ~((uintptr_t)-1 << NumLowBitsAvailable)) == 0 &&
+           "Alignment not satisfied for an actual function pointer!");
+    return reinterpret_cast<void *>(P);
+  }
+  static inline FunctionPointerT getFromVoidPointer(void *P) {
+    return reinterpret_cast<FunctionPointerT>(P);
+  }
+};
+
+/// Provide a default specialization for function pointers that assumes 4-byte
+/// alignment.
+///
+/// We assume here that functions used with this are always at least 4-byte
+/// aligned. This means that, for example, thumb functions won't work or systems
+/// with weird unaligned function pointers won't work. But all practical systems
+/// we support satisfy this requirement.
+template <typename ReturnT, typename... ParamTs>
+struct PointerLikeTypeTraits<ReturnT (*)(ParamTs...)>
+    : FunctionPointerLikeTypeTraits<4, ReturnT (*)(ParamTs...)> {};
+
+} // end namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Printable.h b/binaryen/third_party/llvm-project/include/llvm/Support/Printable.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Printable.h
@@ -0,0 +1,51 @@
+//===--- Printable.h - Print function helpers -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the Printable struct.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_PRINTABLE_H
+#define LLVM_SUPPORT_PRINTABLE_H
+
+#include <functional>
+
+namespace llvm {
+
+class raw_ostream;
+
+/// Simple wrapper around std::function<void(raw_ostream&)>.
+/// This class is useful to construct print helpers for raw_ostream.
+///
+/// Example:
+///     Printable PrintRegister(unsigned Register) {
+///       return Printable([Register](raw_ostream &OS) {
+///         OS << getRegisterName(Register);
+///       }
+///     }
+///     ... OS << PrintRegister(Register); ...
+///
+/// Implementation note: Ideally this would just be a typedef, but doing so
+/// leads to operator << being ambiguous as function has matching constructors
+/// in some STL versions. I have seen the problem on gcc 4.6 libstdc++ and
+/// microsoft STL.
+class Printable {
+public:
+  std::function<void(raw_ostream &OS)> Print;
+  Printable(std::function<void(raw_ostream &OS)> Print)
+      : Print(std::move(Print)) {}
+};
+
+inline raw_ostream &operator<<(raw_ostream &OS, const Printable &P) {
+  P.Print(OS);
+  return OS;
+}
+
+}
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Process.h b/binaryen/third_party/llvm-project/include/llvm/Support/Process.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Process.h
@@ -0,0 +1,209 @@
+//===- llvm/Support/Process.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// Provides a library for accessing information about this process and other
+/// processes on the operating system. Also provides means of spawning
+/// subprocess for commands. The design of this library is modeled after the
+/// proposed design of the Boost.Process library, and is design specifically to
+/// follow the style of standard libraries and potentially become a proposal
+/// for a standard library.
+///
+/// This file declares the llvm::sys::Process class which contains a collection
+/// of legacy static interfaces for extracting various information about the
+/// current process. The goal is to migrate users of this API over to the new
+/// interfaces.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_PROCESS_H
+#define LLVM_SUPPORT_PROCESS_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Error.h"
+#include <system_error>
+
+namespace llvm {
+template <typename T> class ArrayRef;
+class StringRef;
+
+namespace sys {
+
+
+/// A collection of legacy interfaces for querying information about the
+/// current executing process.
+class Process {
+public:
+  /// Get the process's page size.
+  /// This may fail if the underlying syscall returns an error. In most cases,
+  /// page size information is used for optimization, and this error can be
+  /// safely discarded by calling consumeError, and an estimated page size
+  /// substituted instead.
+  static Expected<unsigned> getPageSize();
+
+  /// Get the process's estimated page size.
+  /// This function always succeeds, but if the underlying syscall to determine
+  /// the page size fails then this will silently return an estimated page size.
+  /// The estimated page size is guaranteed to be a power of 2.
+  static unsigned getPageSizeEstimate() {
+    if (auto PageSize = getPageSize())
+      return *PageSize;
+    else {
+      consumeError(PageSize.takeError());
+      return 4096;
+    }
+  }
+
+  /// Return process memory usage.
+  /// This static function will return the total amount of memory allocated
+  /// by the process. This only counts the memory allocated via the malloc,
+  /// calloc and realloc functions and includes any "free" holes in the
+  /// allocated space.
+  static size_t GetMallocUsage();
+
+  /// This static function will set \p user_time to the amount of CPU time
+  /// spent in user (non-kernel) mode and \p sys_time to the amount of CPU
+  /// time spent in system (kernel) mode.  If the operating system does not
+  /// support collection of these metrics, a zero duration will be for both
+  /// values.
+  /// \param elapsed Returns the system_clock::now() giving current time
+  /// \param user_time Returns the current amount of user time for the process
+  /// \param sys_time Returns the current amount of system time for the process
+  static void GetTimeUsage(TimePoint<> &elapsed,
+                           std::chrono::nanoseconds &user_time,
+                           std::chrono::nanoseconds &sys_time);
+
+  /// This function makes the necessary calls to the operating system to
+  /// prevent core files or any other kind of large memory dumps that can
+  /// occur when a program fails.
+  /// Prevent core file generation.
+  static void PreventCoreFiles();
+
+  /// true if PreventCoreFiles has been called, false otherwise.
+  static bool AreCoreFilesPrevented();
+
+  // This function returns the environment variable \arg name's value as a UTF-8
+  // string. \arg Name is assumed to be in UTF-8 encoding too.
+  static Optional<std::string> GetEnv(StringRef name);
+
+  /// This function searches for an existing file in the list of directories
+  /// in a PATH like environment variable, and returns the first file found,
+  /// according to the order of the entries in the PATH like environment
+  /// variable.  If an ignore list is specified, then any folder which is in
+  /// the PATH like environment variable but is also in IgnoreList is not
+  /// considered.
+  static Optional<std::string> FindInEnvPath(StringRef EnvName,
+                                             StringRef FileName,
+                                             ArrayRef<std::string> IgnoreList);
+
+  static Optional<std::string> FindInEnvPath(StringRef EnvName,
+                                             StringRef FileName);
+
+  // This functions ensures that the standard file descriptors (input, output,
+  // and error) are properly mapped to a file descriptor before we use any of
+  // them.  This should only be called by standalone programs, library
+  // components should not call this.
+  static std::error_code FixupStandardFileDescriptors();
+
+  // This function safely closes a file descriptor.  It is not safe to retry
+  // close(2) when it returns with errno equivalent to EINTR; this is because
+  // *nixen cannot agree if the file descriptor is, in fact, closed when this
+  // occurs.
+  //
+  // N.B. Some operating systems, due to thread cancellation, cannot properly
+  // guarantee that it will or will not be closed one way or the other!
+  static std::error_code SafelyCloseFileDescriptor(int FD);
+
+  /// This function determines if the standard input is connected directly
+  /// to a user's input (keyboard probably), rather than coming from a file
+  /// or pipe.
+  static bool StandardInIsUserInput();
+
+  /// This function determines if the standard output is connected to a
+  /// "tty" or "console" window. That is, the output would be displayed to
+  /// the user rather than being put on a pipe or stored in a file.
+  static bool StandardOutIsDisplayed();
+
+  /// This function determines if the standard error is connected to a
+  /// "tty" or "console" window. That is, the output would be displayed to
+  /// the user rather than being put on a pipe or stored in a file.
+  static bool StandardErrIsDisplayed();
+
+  /// This function determines if the given file descriptor is connected to
+  /// a "tty" or "console" window. That is, the output would be displayed to
+  /// the user rather than being put on a pipe or stored in a file.
+  static bool FileDescriptorIsDisplayed(int fd);
+
+  /// This function determines if the given file descriptor is displayd and
+  /// supports colors.
+  static bool FileDescriptorHasColors(int fd);
+
+  /// This function determines the number of columns in the window
+  /// if standard output is connected to a "tty" or "console"
+  /// window. If standard output is not connected to a tty or
+  /// console, or if the number of columns cannot be determined,
+  /// this routine returns zero.
+  static unsigned StandardOutColumns();
+
+  /// This function determines the number of columns in the window
+  /// if standard error is connected to a "tty" or "console"
+  /// window. If standard error is not connected to a tty or
+  /// console, or if the number of columns cannot be determined,
+  /// this routine returns zero.
+  static unsigned StandardErrColumns();
+
+  /// This function determines whether the terminal connected to standard
+  /// output supports colors. If standard output is not connected to a
+  /// terminal, this function returns false.
+  static bool StandardOutHasColors();
+
+  /// This function determines whether the terminal connected to standard
+  /// error supports colors. If standard error is not connected to a
+  /// terminal, this function returns false.
+  static bool StandardErrHasColors();
+
+  /// Enables or disables whether ANSI escape sequences are used to output
+  /// colors. This only has an effect on Windows.
+  /// Note: Setting this option is not thread-safe and should only be done
+  /// during initialization.
+  static void UseANSIEscapeCodes(bool enable);
+
+  /// Whether changing colors requires the output to be flushed.
+  /// This is needed on systems that don't support escape sequences for
+  /// changing colors.
+  static bool ColorNeedsFlush();
+
+  /// This function returns the colorcode escape sequences.
+  /// If ColorNeedsFlush() is true then this function will change the colors
+  /// and return an empty escape sequence. In that case it is the
+  /// responsibility of the client to flush the output stream prior to
+  /// calling this function.
+  static const char *OutputColor(char c, bool bold, bool bg);
+
+  /// Same as OutputColor, but only enables the bold attribute.
+  static const char *OutputBold(bool bg);
+
+  /// This function returns the escape sequence to reverse forground and
+  /// background colors.
+  static const char *OutputReverse();
+
+  /// Resets the terminals colors, or returns an escape sequence to do so.
+  static const char *ResetColor();
+
+  /// Get the result of a process wide random number generator. The
+  /// generator will be automatically seeded in non-deterministic fashion.
+  static unsigned GetRandomNumber();
+};
+
+}
+}
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Program.h b/binaryen/third_party/llvm-project/include/llvm/Support/Program.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Program.h
@@ -0,0 +1,208 @@
+//===- llvm/Support/Program.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the llvm::sys::Program class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_PROGRAM_H
+#define LLVM_SUPPORT_PROGRAM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/ErrorOr.h"
+#include <system_error>
+
+namespace llvm {
+namespace sys {
+
+  /// This is the OS-specific separator for PATH like environment variables:
+  // a colon on Unix or a semicolon on Windows.
+#if defined(LLVM_ON_UNIX)
+  const char EnvPathSeparator = ':';
+#elif defined (_WIN32)
+  const char EnvPathSeparator = ';';
+#endif
+
+#if defined(_WIN32)
+  typedef unsigned long procid_t; // Must match the type of DWORD on Windows.
+  typedef void *process_t;        // Must match the type of HANDLE on Windows.
+#else
+  typedef pid_t procid_t;
+  typedef procid_t process_t;
+#endif
+
+  /// This struct encapsulates information about a process.
+  struct ProcessInfo {
+    enum : procid_t { InvalidPid = 0 };
+
+    procid_t Pid;      /// The process identifier.
+    process_t Process; /// Platform-dependent process object.
+
+    /// The return code, set after execution.
+    int ReturnCode;
+
+    ProcessInfo();
+  };
+
+  /// Find the first executable file \p Name in \p Paths.
+  ///
+  /// This does not perform hashing as a shell would but instead stats each PATH
+  /// entry individually so should generally be avoided. Core LLVM library
+  /// functions and options should instead require fully specified paths.
+  ///
+  /// \param Name name of the executable to find. If it contains any system
+  ///   slashes, it will be returned as is.
+  /// \param Paths optional list of paths to search for \p Name. If empty it
+  ///   will use the system PATH environment instead.
+  ///
+  /// \returns The fully qualified path to the first \p Name in \p Paths if it
+  ///   exists. \p Name if \p Name has slashes in it. Otherwise an error.
+  ErrorOr<std::string>
+  findProgramByName(StringRef Name, ArrayRef<StringRef> Paths = {});
+
+  // These functions change the specified standard stream (stdin or stdout) to
+  // binary mode. They return errc::success if the specified stream
+  // was changed. Otherwise a platform dependent error is returned.
+  std::error_code ChangeStdinToBinary();
+  std::error_code ChangeStdoutToBinary();
+
+  /// This function executes the program using the arguments provided.  The
+  /// invoked program will inherit the stdin, stdout, and stderr file
+  /// descriptors, the environment and other configuration settings of the
+  /// invoking program.
+  /// This function waits for the program to finish, so should be avoided in
+  /// library functions that aren't expected to block. Consider using
+  /// ExecuteNoWait() instead.
+  /// \returns an integer result code indicating the status of the program.
+  /// A zero or positive value indicates the result code of the program.
+  /// -1 indicates failure to execute
+  /// -2 indicates a crash during execution or timeout
+  int ExecuteAndWait(
+      StringRef Program, ///< Path of the program to be executed. It is
+      ///< presumed this is the result of the findProgramByName method.
+      ArrayRef<StringRef> Args, ///< An array of strings that are passed to the
+      ///< program.  The first element should be the name of the program.
+      ///< The array should **not** be terminated by an empty StringRef.
+      Optional<ArrayRef<StringRef>> Env = None, ///< An optional vector of
+      ///< strings to use for the program's environment. If not provided, the
+      ///< current program's environment will be used.  If specified, the
+      ///< vector should **not** be terminated by an empty StringRef.
+      ArrayRef<Optional<StringRef>> Redirects = {}, ///<
+      ///< An array of optional paths. Should have a size of zero or three.
+      ///< If the array is empty, no redirections are performed.
+      ///< Otherwise, the inferior process's stdin(0), stdout(1), and stderr(2)
+      ///< will be redirected to the corresponding paths, if the optional path
+      ///< is present (not \c llvm::None).
+      ///< When an empty path is passed in, the corresponding file descriptor
+      ///< will be disconnected (ie, /dev/null'd) in a portable way.
+      unsigned SecondsToWait = 0, ///< If non-zero, this specifies the amount
+      ///< of time to wait for the child process to exit. If the time
+      ///< expires, the child is killed and this call returns. If zero,
+      ///< this function will wait until the child finishes or forever if
+      ///< it doesn't.
+      unsigned MemoryLimit = 0, ///< If non-zero, this specifies max. amount
+      ///< of memory can be allocated by process. If memory usage will be
+      ///< higher limit, the child is killed and this call returns. If zero
+      ///< - no memory limit.
+      std::string *ErrMsg = nullptr, ///< If non-zero, provides a pointer to a
+      ///< string instance in which error messages will be returned. If the
+      ///< string is non-empty upon return an error occurred while invoking the
+      ///< program.
+      bool *ExecutionFailed = nullptr);
+
+  /// Similar to ExecuteAndWait, but returns immediately.
+  /// @returns The \see ProcessInfo of the newly launced process.
+  /// \note On Microsoft Windows systems, users will need to either call
+  /// \see Wait until the process finished execution or win32 CloseHandle() API
+  /// on ProcessInfo.ProcessHandle to avoid memory leaks.
+  ProcessInfo ExecuteNoWait(StringRef Program, ArrayRef<StringRef> Args,
+                            Optional<ArrayRef<StringRef>> Env,
+                            ArrayRef<Optional<StringRef>> Redirects = {},
+                            unsigned MemoryLimit = 0,
+                            std::string *ErrMsg = nullptr,
+                            bool *ExecutionFailed = nullptr);
+
+  /// Return true if the given arguments fit within system-specific
+  /// argument length limits.
+  bool commandLineFitsWithinSystemLimits(StringRef Program,
+                                         ArrayRef<StringRef> Args);
+
+  /// Return true if the given arguments fit within system-specific
+  /// argument length limits.
+  bool commandLineFitsWithinSystemLimits(StringRef Program,
+                                         ArrayRef<const char *> Args);
+
+  /// File encoding options when writing contents that a non-UTF8 tool will
+  /// read (on Windows systems). For UNIX, we always use UTF-8.
+  enum WindowsEncodingMethod {
+    /// UTF-8 is the LLVM native encoding, being the same as "do not perform
+    /// encoding conversion".
+    WEM_UTF8,
+    WEM_CurrentCodePage,
+    WEM_UTF16
+  };
+
+  /// Saves the UTF8-encoded \p contents string into the file \p FileName
+  /// using a specific encoding.
+  ///
+  /// This write file function adds the possibility to choose which encoding
+  /// to use when writing a text file. On Windows, this is important when
+  /// writing files with internationalization support with an encoding that is
+  /// different from the one used in LLVM (UTF-8). We use this when writing
+  /// response files, since GCC tools on MinGW only understand legacy code
+  /// pages, and VisualStudio tools only understand UTF-16.
+  /// For UNIX, using different encodings is silently ignored, since all tools
+  /// work well with UTF-8.
+  /// This function assumes that you only use UTF-8 *text* data and will convert
+  /// it to your desired encoding before writing to the file.
+  ///
+  /// FIXME: We use EM_CurrentCodePage to write response files for GNU tools in
+  /// a MinGW/MinGW-w64 environment, which has serious flaws but currently is
+  /// our best shot to make gcc/ld understand international characters. This
+  /// should be changed as soon as binutils fix this to support UTF16 on mingw.
+  ///
+  /// \returns non-zero error_code if failed
+  std::error_code
+  writeFileWithEncoding(StringRef FileName, StringRef Contents,
+                        WindowsEncodingMethod Encoding = WEM_UTF8);
+
+  /// This function waits for the process specified by \p PI to finish.
+  /// \returns A \see ProcessInfo struct with Pid set to:
+  /// \li The process id of the child process if the child process has changed
+  /// state.
+  /// \li 0 if the child process has not changed state.
+  /// \note Users of this function should always check the ReturnCode member of
+  /// the \see ProcessInfo returned from this function.
+  ProcessInfo Wait(
+      const ProcessInfo &PI, ///< The child process that should be waited on.
+      unsigned SecondsToWait, ///< If non-zero, this specifies the amount of
+      ///< time to wait for the child process to exit. If the time expires, the
+      ///< child is killed and this function returns. If zero, this function
+      ///< will perform a non-blocking wait on the child process.
+      bool WaitUntilTerminates, ///< If true, ignores \p SecondsToWait and waits
+      ///< until child has terminated.
+      std::string *ErrMsg = nullptr ///< If non-zero, provides a pointer to a
+      ///< string instance in which error messages will be returned. If the
+      ///< string is non-empty upon return an error occurred while invoking the
+      ///< program.
+      );
+
+#if defined(_WIN32)
+  /// Given a list of command line arguments, quote and escape them as necessary
+  /// to build a single flat command line appropriate for calling CreateProcess
+  /// on
+  /// Windows.
+  std::string flattenWindowsCommandLine(ArrayRef<StringRef> Args);
+#endif
+  }
+}
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Regex.h b/binaryen/third_party/llvm-project/include/llvm/Support/Regex.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Regex.h
@@ -0,0 +1,109 @@
+//===-- Regex.h - Regular Expression matcher implementation -*- C++ -*-----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a POSIX regular expression matcher.  Both Basic and
+// Extended POSIX regular expressions (ERE) are supported.  EREs were extended
+// to support backreferences in matches.
+// This implementation also supports matching strings with embedded NUL chars.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_REGEX_H
+#define LLVM_SUPPORT_REGEX_H
+
+#include <string>
+
+struct llvm_regex;
+
+namespace llvm {
+  class StringRef;
+  template<typename T> class SmallVectorImpl;
+
+  class Regex {
+  public:
+    enum {
+      NoFlags=0,
+      /// Compile for matching that ignores upper/lower case distinctions.
+      IgnoreCase=1,
+      /// Compile for newline-sensitive matching. With this flag '[^' bracket
+      /// expressions and '.' never match newline. A ^ anchor matches the
+      /// null string after any newline in the string in addition to its normal
+      /// function, and the $ anchor matches the null string before any
+      /// newline in the string in addition to its normal function.
+      Newline=2,
+      /// By default, the POSIX extended regular expression (ERE) syntax is
+      /// assumed. Pass this flag to turn on basic regular expressions (BRE)
+      /// instead.
+      BasicRegex=4
+    };
+
+    Regex();
+    /// Compiles the given regular expression \p Regex.
+    ///
+    /// \param Regex - referenced string is no longer needed after this
+    /// constructor does finish.  Only its compiled form is kept stored.
+    Regex(StringRef Regex, unsigned Flags = NoFlags);
+    Regex(const Regex &) = delete;
+    Regex &operator=(Regex regex) {
+      std::swap(preg, regex.preg);
+      std::swap(error, regex.error);
+      return *this;
+    }
+    Regex(Regex &&regex);
+    ~Regex();
+
+    /// isValid - returns the error encountered during regex compilation, if
+    /// any.
+    bool isValid(std::string &Error) const;
+    bool isValid() const { return !error; }
+
+    /// getNumMatches - In a valid regex, return the number of parenthesized
+    /// matches it contains.  The number filled in by match will include this
+    /// many entries plus one for the whole regex (as element 0).
+    unsigned getNumMatches() const;
+
+    /// matches - Match the regex against a given \p String.
+    ///
+    /// \param Matches - If given, on a successful match this will be filled in
+    /// with references to the matched group expressions (inside \p String),
+    /// the first group is always the entire pattern.
+    ///
+    /// \param Error - If non-null, any errors in the matching will be recorded
+    /// as a non-empty string. If there is no error, it will be an empty string.
+    ///
+    /// This returns true on a successful match.
+    bool match(StringRef String, SmallVectorImpl<StringRef> *Matches = nullptr,
+               std::string *Error = nullptr) const;
+
+    /// sub - Return the result of replacing the first match of the regex in
+    /// \p String with the \p Repl string. Backreferences like "\0" in the
+    /// replacement string are replaced with the appropriate match substring.
+    ///
+    /// Note that the replacement string has backslash escaping performed on
+    /// it. Invalid backreferences are ignored (replaced by empty strings).
+    ///
+    /// \param Error If non-null, any errors in the substitution (invalid
+    /// backreferences, trailing backslashes) will be recorded as a non-empty
+    /// string. If there is no error, it will be an empty string.
+    std::string sub(StringRef Repl, StringRef String,
+                    std::string *Error = nullptr) const;
+
+    /// If this function returns true, ^Str$ is an extended regular
+    /// expression that matches Str and only Str.
+    static bool isLiteralERE(StringRef Str);
+
+    /// Turn String into a regex by escaping its special characters.
+    static std::string escape(StringRef String);
+
+  private:
+    struct llvm_regex *preg;
+    int error;
+  };
+}
+
+#endif // LLVM_SUPPORT_REGEX_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/ReverseIteration.h b/binaryen/third_party/llvm-project/include/llvm/Support/ReverseIteration.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/ReverseIteration.h
@@ -0,0 +1,19 @@
+#ifndef LLVM_SUPPORT_REVERSEITERATION_H
+#define LLVM_SUPPORT_REVERSEITERATION_H
+
+#include "llvm/Config/abi-breaking.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
+
+namespace llvm {
+
+template<class T = void *>
+bool shouldReverseIterate() {
+#if LLVM_ENABLE_REVERSE_ITERATION
+  return detail::IsPointerLike<T>::value;
+#else
+  return false;
+#endif
+}
+
+}
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/SMLoc.h b/binaryen/third_party/llvm-project/include/llvm/Support/SMLoc.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/SMLoc.h
@@ -0,0 +1,64 @@
+//===- SMLoc.h - Source location for use with diagnostics -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the SMLoc class.  This class encapsulates a location in
+// source code for use in diagnostics.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SMLOC_H
+#define LLVM_SUPPORT_SMLOC_H
+
+#include "llvm/ADT/None.h"
+#include <cassert>
+
+namespace llvm {
+
+/// Represents a location in source code.
+class SMLoc {
+  const char *Ptr = nullptr;
+
+public:
+  SMLoc() = default;
+
+  bool isValid() const { return Ptr != nullptr; }
+
+  bool operator==(const SMLoc &RHS) const { return RHS.Ptr == Ptr; }
+  bool operator!=(const SMLoc &RHS) const { return RHS.Ptr != Ptr; }
+
+  const char *getPointer() const { return Ptr; }
+
+  static SMLoc getFromPointer(const char *Ptr) {
+    SMLoc L;
+    L.Ptr = Ptr;
+    return L;
+  }
+};
+
+/// Represents a range in source code.
+///
+/// SMRange is implemented using a half-open range, as is the convention in C++.
+/// In the string "abc", the range [1,3) represents the substring "bc", and the
+/// range [2,2) represents an empty range between the characters "b" and "c".
+class SMRange {
+public:
+  SMLoc Start, End;
+
+  SMRange() = default;
+  SMRange(NoneType) {}
+  SMRange(SMLoc St, SMLoc En) : Start(St), End(En) {
+    assert(Start.isValid() == End.isValid() &&
+           "Start and End should either both be valid or both be invalid!");
+  }
+
+  bool isValid() const { return Start.isValid(); }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_SMLOC_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/ScopedPrinter.h b/binaryen/third_party/llvm-project/include/llvm/Support/ScopedPrinter.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/ScopedPrinter.h
@@ -0,0 +1,388 @@
+//===-- ScopedPrinter.h ----------------------------------------*- C++ -*--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SCOPEDPRINTER_H
+#define LLVM_SUPPORT_SCOPEDPRINTER_H
+
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+namespace llvm {
+
+template <typename T> struct EnumEntry {
+  StringRef Name;
+  // While Name suffices in most of the cases, in certain cases
+  // GNU style and LLVM style of ELFDumper do not
+  // display same string for same enum. The AltName if initialized appropriately
+  // will hold the string that GNU style emits.
+  // Example:
+  // "EM_X86_64" string on LLVM style for Elf_Ehdr->e_machine corresponds to
+  // "Advanced Micro Devices X86-64" on GNU style
+  StringRef AltName;
+  T Value;
+  EnumEntry(StringRef N, StringRef A, T V) : Name(N), AltName(A), Value(V) {}
+  EnumEntry(StringRef N, T V) : Name(N), AltName(N), Value(V) {}
+};
+
+struct HexNumber {
+  // To avoid sign-extension we have to explicitly cast to the appropriate
+  // unsigned type. The overloads are here so that every type that is implicitly
+  // convertible to an integer (including enums and endian helpers) can be used
+  // without requiring type traits or call-site changes.
+  HexNumber(char Value) : Value(static_cast<unsigned char>(Value)) {}
+  HexNumber(signed char Value) : Value(static_cast<unsigned char>(Value)) {}
+  HexNumber(signed short Value) : Value(static_cast<unsigned short>(Value)) {}
+  HexNumber(signed int Value) : Value(static_cast<unsigned int>(Value)) {}
+  HexNumber(signed long Value) : Value(static_cast<unsigned long>(Value)) {}
+  HexNumber(signed long long Value)
+      : Value(static_cast<unsigned long long>(Value)) {}
+  HexNumber(unsigned char Value) : Value(Value) {}
+  HexNumber(unsigned short Value) : Value(Value) {}
+  HexNumber(unsigned int Value) : Value(Value) {}
+  HexNumber(unsigned long Value) : Value(Value) {}
+  HexNumber(unsigned long long Value) : Value(Value) {}
+  uint64_t Value;
+};
+
+raw_ostream &operator<<(raw_ostream &OS, const HexNumber &Value);
+const std::string to_hexString(uint64_t Value, bool UpperCase = true);
+
+template <class T> const std::string to_string(const T &Value) {
+  std::string number;
+  llvm::raw_string_ostream stream(number);
+  stream << Value;
+  return stream.str();
+}
+
+class ScopedPrinter {
+public:
+  ScopedPrinter(raw_ostream &OS) : OS(OS), IndentLevel(0) {}
+
+  void flush() { OS.flush(); }
+
+  void indent(int Levels = 1) { IndentLevel += Levels; }
+
+  void unindent(int Levels = 1) {
+    IndentLevel = std::max(0, IndentLevel - Levels);
+  }
+
+  void resetIndent() { IndentLevel = 0; }
+
+  int getIndentLevel() { return IndentLevel; }
+
+  void setPrefix(StringRef P) { Prefix = P; }
+
+  void printIndent() {
+    OS << Prefix;
+    for (int i = 0; i < IndentLevel; ++i)
+      OS << "  ";
+  }
+
+  template <typename T> HexNumber hex(T Value) { return HexNumber(Value); }
+
+  template <typename T, typename TEnum>
+  void printEnum(StringRef Label, T Value,
+                 ArrayRef<EnumEntry<TEnum>> EnumValues) {
+    StringRef Name;
+    bool Found = false;
+    for (const auto &EnumItem : EnumValues) {
+      if (EnumItem.Value == Value) {
+        Name = EnumItem.Name;
+        Found = true;
+        break;
+      }
+    }
+
+    if (Found) {
+      startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n";
+    } else {
+      startLine() << Label << ": " << hex(Value) << "\n";
+    }
+  }
+
+  template <typename T, typename TFlag>
+  void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag>> Flags,
+                  TFlag EnumMask1 = {}, TFlag EnumMask2 = {},
+                  TFlag EnumMask3 = {}) {
+    typedef EnumEntry<TFlag> FlagEntry;
+    typedef SmallVector<FlagEntry, 10> FlagVector;
+    FlagVector SetFlags;
+
+    for (const auto &Flag : Flags) {
+      if (Flag.Value == 0)
+        continue;
+
+      TFlag EnumMask{};
+      if (Flag.Value & EnumMask1)
+        EnumMask = EnumMask1;
+      else if (Flag.Value & EnumMask2)
+        EnumMask = EnumMask2;
+      else if (Flag.Value & EnumMask3)
+        EnumMask = EnumMask3;
+      bool IsEnum = (Flag.Value & EnumMask) != 0;
+      if ((!IsEnum && (Value & Flag.Value) == Flag.Value) ||
+          (IsEnum && (Value & EnumMask) == Flag.Value)) {
+        SetFlags.push_back(Flag);
+      }
+    }
+
+    llvm::sort(SetFlags, &flagName<TFlag>);
+
+    startLine() << Label << " [ (" << hex(Value) << ")\n";
+    for (const auto &Flag : SetFlags) {
+      startLine() << "  " << Flag.Name << " (" << hex(Flag.Value) << ")\n";
+    }
+    startLine() << "]\n";
+  }
+
+  template <typename T> void printFlags(StringRef Label, T Value) {
+    startLine() << Label << " [ (" << hex(Value) << ")\n";
+    uint64_t Flag = 1;
+    uint64_t Curr = Value;
+    while (Curr > 0) {
+      if (Curr & 1)
+        startLine() << "  " << hex(Flag) << "\n";
+      Curr >>= 1;
+      Flag <<= 1;
+    }
+    startLine() << "]\n";
+  }
+
+  void printNumber(StringRef Label, uint64_t Value) {
+    startLine() << Label << ": " << Value << "\n";
+  }
+
+  void printNumber(StringRef Label, uint32_t Value) {
+    startLine() << Label << ": " << Value << "\n";
+  }
+
+  void printNumber(StringRef Label, uint16_t Value) {
+    startLine() << Label << ": " << Value << "\n";
+  }
+
+  void printNumber(StringRef Label, uint8_t Value) {
+    startLine() << Label << ": " << unsigned(Value) << "\n";
+  }
+
+  void printNumber(StringRef Label, int64_t Value) {
+    startLine() << Label << ": " << Value << "\n";
+  }
+
+  void printNumber(StringRef Label, int32_t Value) {
+    startLine() << Label << ": " << Value << "\n";
+  }
+
+  void printNumber(StringRef Label, int16_t Value) {
+    startLine() << Label << ": " << Value << "\n";
+  }
+
+  void printNumber(StringRef Label, int8_t Value) {
+    startLine() << Label << ": " << int(Value) << "\n";
+  }
+
+  void printNumber(StringRef Label, const APSInt &Value) {
+    startLine() << Label << ": " << Value << "\n";
+  }
+
+  void printBoolean(StringRef Label, bool Value) {
+    startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n';
+  }
+
+  template <typename... T> void printVersion(StringRef Label, T... Version) {
+    startLine() << Label << ": ";
+    printVersionInternal(Version...);
+    getOStream() << "\n";
+  }
+
+  template <typename T> void printList(StringRef Label, const T &List) {
+    startLine() << Label << ": [";
+    bool Comma = false;
+    for (const auto &Item : List) {
+      if (Comma)
+        OS << ", ";
+      OS << Item;
+      Comma = true;
+    }
+    OS << "]\n";
+  }
+
+  template <typename T, typename U>
+  void printList(StringRef Label, const T &List, const U &Printer) {
+    startLine() << Label << ": [";
+    bool Comma = false;
+    for (const auto &Item : List) {
+      if (Comma)
+        OS << ", ";
+      Printer(OS, Item);
+      Comma = true;
+    }
+    OS << "]\n";
+  }
+
+  template <typename T> void printHexList(StringRef Label, const T &List) {
+    startLine() << Label << ": [";
+    bool Comma = false;
+    for (const auto &Item : List) {
+      if (Comma)
+        OS << ", ";
+      OS << hex(Item);
+      Comma = true;
+    }
+    OS << "]\n";
+  }
+
+  template <typename T> void printHex(StringRef Label, T Value) {
+    startLine() << Label << ": " << hex(Value) << "\n";
+  }
+
+  template <typename T> void printHex(StringRef Label, StringRef Str, T Value) {
+    startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n";
+  }
+
+  template <typename T>
+  void printSymbolOffset(StringRef Label, StringRef Symbol, T Value) {
+    startLine() << Label << ": " << Symbol << '+' << hex(Value) << '\n';
+  }
+
+  void printString(StringRef Value) { startLine() << Value << "\n"; }
+
+  void printString(StringRef Label, StringRef Value) {
+    startLine() << Label << ": " << Value << "\n";
+  }
+
+  void printString(StringRef Label, const std::string &Value) {
+    printString(Label, StringRef(Value));
+  }
+
+  void printString(StringRef Label, const char* Value) {
+    printString(Label, StringRef(Value));
+  }
+
+  template <typename T>
+  void printNumber(StringRef Label, StringRef Str, T Value) {
+    startLine() << Label << ": " << Str << " (" << Value << ")\n";
+  }
+
+  void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) {
+    printBinaryImpl(Label, Str, Value, false);
+  }
+
+  void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) {
+    auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
+                          Value.size());
+    printBinaryImpl(Label, Str, V, false);
+  }
+
+  void printBinary(StringRef Label, ArrayRef<uint8_t> Value) {
+    printBinaryImpl(Label, StringRef(), Value, false);
+  }
+
+  void printBinary(StringRef Label, ArrayRef<char> Value) {
+    auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
+                          Value.size());
+    printBinaryImpl(Label, StringRef(), V, false);
+  }
+
+  void printBinary(StringRef Label, StringRef Value) {
+    auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
+                          Value.size());
+    printBinaryImpl(Label, StringRef(), V, false);
+  }
+
+  void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value,
+                        uint32_t StartOffset) {
+    printBinaryImpl(Label, StringRef(), Value, true, StartOffset);
+  }
+
+  void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value) {
+    printBinaryImpl(Label, StringRef(), Value, true);
+  }
+
+  void printBinaryBlock(StringRef Label, StringRef Value) {
+    auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
+                          Value.size());
+    printBinaryImpl(Label, StringRef(), V, true);
+  }
+
+  template <typename T> void printObject(StringRef Label, const T &Value) {
+    startLine() << Label << ": " << Value << "\n";
+  }
+
+  raw_ostream &startLine() {
+    printIndent();
+    return OS;
+  }
+
+  raw_ostream &getOStream() { return OS; }
+
+private:
+  template <typename T> void printVersionInternal(T Value) {
+    getOStream() << Value;
+  }
+
+  template <typename S, typename T, typename... TArgs>
+  void printVersionInternal(S Value, T Value2, TArgs... Args) {
+    getOStream() << Value << ".";
+    printVersionInternal(Value2, Args...);
+  }
+
+  template <typename T>
+  static bool flagName(const EnumEntry<T> &lhs, const EnumEntry<T> &rhs) {
+    return lhs.Name < rhs.Name;
+  }
+
+  void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value,
+                       bool Block, uint32_t StartOffset = 0);
+
+  raw_ostream &OS;
+  int IndentLevel;
+  StringRef Prefix;
+};
+
+template <>
+inline void
+ScopedPrinter::printHex<support::ulittle16_t>(StringRef Label,
+                                              support::ulittle16_t Value) {
+  startLine() << Label << ": " << hex(Value) << "\n";
+}
+
+template<char Open, char Close>
+struct DelimitedScope {
+  explicit DelimitedScope(ScopedPrinter &W) : W(W) {
+    W.startLine() << Open << '\n';
+    W.indent();
+  }
+
+  DelimitedScope(ScopedPrinter &W, StringRef N) : W(W) {
+    W.startLine() << N;
+    if (!N.empty())
+      W.getOStream() << ' ';
+    W.getOStream() << Open << '\n';
+    W.indent();
+  }
+
+  ~DelimitedScope() {
+    W.unindent();
+    W.startLine() << Close << '\n';
+  }
+
+  ScopedPrinter &W;
+};
+
+using DictScope = DelimitedScope<'{', '}'>;
+using ListScope = DelimitedScope<'[', ']'>;
+
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Signals.h b/binaryen/third_party/llvm-project/include/llvm/Support/Signals.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Signals.h
@@ -0,0 +1,90 @@
+//===- llvm/Support/Signals.h - Signal Handling support ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines some helpful functions for dealing with the possibility of
+// unix signals occurring while your program is running.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SIGNALS_H
+#define LLVM_SUPPORT_SIGNALS_H
+
+#include <string>
+
+namespace llvm {
+class StringRef;
+class raw_ostream;
+
+namespace sys {
+
+  /// This function runs all the registered interrupt handlers, including the
+  /// removal of files registered by RemoveFileOnSignal.
+  void RunInterruptHandlers();
+
+  /// This function registers signal handlers to ensure that if a signal gets
+  /// delivered that the named file is removed.
+  /// Remove a file if a fatal signal occurs.
+  bool RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg = nullptr);
+
+  /// This function removes a file from the list of files to be removed on
+  /// signal delivery.
+  void DontRemoveFileOnSignal(StringRef Filename);
+
+  /// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
+  /// process, print a stack trace and then exit.
+  /// Print a stack trace if a fatal signal occurs.
+  /// \param Argv0 the current binary name, used to find the symbolizer
+  ///        relative to the current binary before searching $PATH; can be
+  ///        StringRef(), in which case we will only search $PATH.
+  /// \param DisableCrashReporting if \c true, disable the normal crash
+  ///        reporting mechanisms on the underlying operating system.
+  void PrintStackTraceOnErrorSignal(StringRef Argv0,
+                                    bool DisableCrashReporting = false);
+
+  /// Disable all system dialog boxes that appear when the process crashes.
+  void DisableSystemDialogsOnCrash();
+
+  /// Print the stack trace using the given \c raw_ostream object.
+  void PrintStackTrace(raw_ostream &OS);
+
+  // Run all registered signal handlers.
+  void RunSignalHandlers();
+
+  using SignalHandlerCallback = void (*)(void *);
+
+  /// Add a function to be called when an abort/kill signal is delivered to the
+  /// process. The handler can have a cookie passed to it to identify what
+  /// instance of the handler it is.
+  void AddSignalHandler(SignalHandlerCallback FnPtr, void *Cookie);
+
+  /// This function registers a function to be called when the user "interrupts"
+  /// the program (typically by pressing ctrl-c).  When the user interrupts the
+  /// program, the specified interrupt function is called instead of the program
+  /// being killed, and the interrupt function automatically disabled.
+  ///
+  /// Note that interrupt functions are not allowed to call any non-reentrant
+  /// functions.  An null interrupt function pointer disables the current
+  /// installed function.  Note also that the handler may be executed on a
+  /// different thread on some platforms.
+  void SetInterruptFunction(void (*IF)());
+
+  /// Registers a function to be called when an "info" signal is delivered to
+  /// the process.
+  ///
+  /// On POSIX systems, this will be SIGUSR1; on systems that have it, SIGINFO
+  /// will also be used (typically ctrl-t).
+  ///
+  /// Note that signal handlers are not allowed to call any non-reentrant
+  /// functions.  An null function pointer disables the current installed
+  /// function.  Note also that the handler may be executed on a different
+  /// thread on some platforms.
+  void SetInfoSignalFunction(void (*Handler)());
+} // End sys namespace
+} // End llvm namespace
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/SmallVectorMemoryBuffer.h b/binaryen/third_party/llvm-project/include/llvm/Support/SmallVectorMemoryBuffer.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/SmallVectorMemoryBuffer.h
@@ -0,0 +1,65 @@
+//===- SmallVectorMemoryBuffer.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares a wrapper class to hold the memory into which an
+// object will be generated.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_OBJECTMEMORYBUFFER_H
+#define LLVM_EXECUTIONENGINE_OBJECTMEMORYBUFFER_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+/// SmallVector-backed MemoryBuffer instance.
+///
+/// This class enables efficient construction of MemoryBuffers from SmallVector
+/// instances. This is useful for MCJIT and Orc, where object files are streamed
+/// into SmallVectors, then inspected using ObjectFile (which takes a
+/// MemoryBuffer).
+class SmallVectorMemoryBuffer : public MemoryBuffer {
+public:
+  /// Construct an SmallVectorMemoryBuffer from the given SmallVector
+  /// r-value.
+  ///
+  /// FIXME: It'd be nice for this to be a non-templated constructor taking a
+  /// SmallVectorImpl here instead of a templated one taking a SmallVector<N>,
+  /// but SmallVector's move-construction/assignment currently only take
+  /// SmallVectors. If/when that is fixed we can simplify this constructor and
+  /// the following one.
+  SmallVectorMemoryBuffer(SmallVectorImpl<char> &&SV)
+      : SV(std::move(SV)), BufferName("<in-memory object>") {
+    init(this->SV.begin(), this->SV.end(), false);
+  }
+
+  /// Construct a named SmallVectorMemoryBuffer from the given
+  /// SmallVector r-value and StringRef.
+  SmallVectorMemoryBuffer(SmallVectorImpl<char> &&SV, StringRef Name)
+      : SV(std::move(SV)), BufferName(Name) {
+    init(this->SV.begin(), this->SV.end(), false);
+  }
+
+  // Key function.
+  ~SmallVectorMemoryBuffer() override;
+
+  StringRef getBufferIdentifier() const override { return BufferName; }
+
+  BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; }
+
+private:
+  SmallVector<char, 0> SV;
+  std::string BufferName;
+};
+
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/SourceMgr.h b/binaryen/third_party/llvm-project/include/llvm/Support/SourceMgr.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/SourceMgr.h
@@ -0,0 +1,310 @@
+//===- SourceMgr.h - Manager for Source Buffers & Diagnostics ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the SMDiagnostic and SourceMgr classes.  This
+// provides a simple substrate for diagnostics, #include handling, and other low
+// level things for simple parsers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SOURCEMGR_H
+#define LLVM_SUPPORT_SOURCEMGR_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SMLoc.h"
+#include <algorithm>
+#include <cassert>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+
+class raw_ostream;
+class SMDiagnostic;
+class SMFixIt;
+
+/// This owns the files read by a parser, handles include stacks,
+/// and handles diagnostic wrangling.
+class SourceMgr {
+public:
+  enum DiagKind {
+    DK_Error,
+    DK_Warning,
+    DK_Remark,
+    DK_Note,
+  };
+
+  /// Clients that want to handle their own diagnostics in a custom way can
+  /// register a function pointer+context as a diagnostic handler.
+  /// It gets called each time PrintMessage is invoked.
+  using DiagHandlerTy = void (*)(const SMDiagnostic &, void *Context);
+
+private:
+  struct SrcBuffer {
+    /// The memory buffer for the file.
+    std::unique_ptr<MemoryBuffer> Buffer;
+
+    /// Helper type for OffsetCache below: since we're storing many offsets
+    /// into relatively small files (often smaller than 2^8 or 2^16 bytes),
+    /// we select the offset vector element type dynamically based on the
+    /// size of Buffer.
+    using VariableSizeOffsets = PointerUnion4<std::vector<uint8_t> *,
+                                              std::vector<uint16_t> *,
+                                              std::vector<uint32_t> *,
+                                              std::vector<uint64_t> *>;
+
+    /// Vector of offsets into Buffer at which there are line-endings
+    /// (lazily populated). Once populated, the '\n' that marks the end of
+    /// line number N from [1..] is at Buffer[OffsetCache[N-1]]. Since
+    /// these offsets are in sorted (ascending) order, they can be
+    /// binary-searched for the first one after any given offset (eg. an
+    /// offset corresponding to a particular SMLoc).
+    mutable VariableSizeOffsets OffsetCache;
+
+    /// Populate \c OffsetCache and look up a given \p Ptr in it, assuming
+    /// it points somewhere into \c Buffer. The static type parameter \p T
+    /// must be an unsigned integer type from uint{8,16,32,64}_t large
+    /// enough to store offsets inside \c Buffer.
+    template<typename T>
+    unsigned getLineNumber(const char *Ptr) const;
+
+    /// This is the location of the parent include, or null if at the top level.
+    SMLoc IncludeLoc;
+
+    SrcBuffer() = default;
+    SrcBuffer(SrcBuffer &&);
+    SrcBuffer(const SrcBuffer &) = delete;
+    SrcBuffer &operator=(const SrcBuffer &) = delete;
+    ~SrcBuffer();
+  };
+
+  /// This is all of the buffers that we are reading from.
+  std::vector<SrcBuffer> Buffers;
+
+  // This is the list of directories we should search for include files in.
+  std::vector<std::string> IncludeDirectories;
+
+  DiagHandlerTy DiagHandler = nullptr;
+  void *DiagContext = nullptr;
+
+  bool isValidBufferID(unsigned i) const { return i && i <= Buffers.size(); }
+
+public:
+  SourceMgr() = default;
+  SourceMgr(const SourceMgr &) = delete;
+  SourceMgr &operator=(const SourceMgr &) = delete;
+  SourceMgr(SourceMgr &&) = default;
+  SourceMgr &operator=(SourceMgr &&) = default;
+  ~SourceMgr() = default;
+
+  void setIncludeDirs(const std::vector<std::string> &Dirs) {
+    IncludeDirectories = Dirs;
+  }
+
+  /// Specify a diagnostic handler to be invoked every time PrintMessage is
+  /// called. \p Ctx is passed into the handler when it is invoked.
+  void setDiagHandler(DiagHandlerTy DH, void *Ctx = nullptr) {
+    DiagHandler = DH;
+    DiagContext = Ctx;
+  }
+
+  DiagHandlerTy getDiagHandler() const { return DiagHandler; }
+  void *getDiagContext() const { return DiagContext; }
+
+  const SrcBuffer &getBufferInfo(unsigned i) const {
+    assert(isValidBufferID(i));
+    return Buffers[i - 1];
+  }
+
+  const MemoryBuffer *getMemoryBuffer(unsigned i) const {
+    assert(isValidBufferID(i));
+    return Buffers[i - 1].Buffer.get();
+  }
+
+  unsigned getNumBuffers() const {
+    return Buffers.size();
+  }
+
+  unsigned getMainFileID() const {
+    assert(getNumBuffers());
+    return 1;
+  }
+
+  SMLoc getParentIncludeLoc(unsigned i) const {
+    assert(isValidBufferID(i));
+    return Buffers[i - 1].IncludeLoc;
+  }
+
+  /// Add a new source buffer to this source manager. This takes ownership of
+  /// the memory buffer.
+  unsigned AddNewSourceBuffer(std::unique_ptr<MemoryBuffer> F,
+                              SMLoc IncludeLoc) {
+    SrcBuffer NB;
+    NB.Buffer = std::move(F);
+    NB.IncludeLoc = IncludeLoc;
+    Buffers.push_back(std::move(NB));
+    return Buffers.size();
+  }
+
+  /// Search for a file with the specified name in the current directory or in
+  /// one of the IncludeDirs.
+  ///
+  /// If no file is found, this returns 0, otherwise it returns the buffer ID
+  /// of the stacked file. The full path to the included file can be found in
+  /// \p IncludedFile.
+  unsigned AddIncludeFile(const std::string &Filename, SMLoc IncludeLoc,
+                          std::string &IncludedFile);
+
+  /// Return the ID of the buffer containing the specified location.
+  ///
+  /// 0 is returned if the buffer is not found.
+  unsigned FindBufferContainingLoc(SMLoc Loc) const;
+
+  /// Find the line number for the specified location in the specified file.
+  /// This is not a fast method.
+  unsigned FindLineNumber(SMLoc Loc, unsigned BufferID = 0) const {
+    return getLineAndColumn(Loc, BufferID).first;
+  }
+
+  /// Find the line and column number for the specified location in the
+  /// specified file. This is not a fast method.
+  std::pair<unsigned, unsigned> getLineAndColumn(SMLoc Loc,
+                                                 unsigned BufferID = 0) const;
+
+  /// Emit a message about the specified location with the specified string.
+  ///
+  /// \param ShowColors Display colored messages if output is a terminal and
+  /// the default error handler is used.
+  void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind,
+                    const Twine &Msg,
+                    ArrayRef<SMRange> Ranges = None,
+                    ArrayRef<SMFixIt> FixIts = None,
+                    bool ShowColors = true) const;
+
+  /// Emits a diagnostic to llvm::errs().
+  void PrintMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg,
+                    ArrayRef<SMRange> Ranges = None,
+                    ArrayRef<SMFixIt> FixIts = None,
+                    bool ShowColors = true) const;
+
+  /// Emits a manually-constructed diagnostic to the given output stream.
+  ///
+  /// \param ShowColors Display colored messages if output is a terminal and
+  /// the default error handler is used.
+  void PrintMessage(raw_ostream &OS, const SMDiagnostic &Diagnostic,
+                    bool ShowColors = true) const;
+
+  /// Return an SMDiagnostic at the specified location with the specified
+  /// string.
+  ///
+  /// \param Msg If non-null, the kind of message (e.g., "error") which is
+  /// prefixed to the message.
+  SMDiagnostic GetMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg,
+                          ArrayRef<SMRange> Ranges = None,
+                          ArrayRef<SMFixIt> FixIts = None) const;
+
+  /// Prints the names of included files and the line of the file they were
+  /// included from. A diagnostic handler can use this before printing its
+  /// custom formatted message.
+  ///
+  /// \param IncludeLoc The location of the include.
+  /// \param OS the raw_ostream to print on.
+  void PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const;
+};
+
+/// Represents a single fixit, a replacement of one range of text with another.
+class SMFixIt {
+  SMRange Range;
+
+  std::string Text;
+
+public:
+  // FIXME: Twine.str() is not very efficient.
+  SMFixIt(SMLoc Loc, const Twine &Insertion)
+    : Range(Loc, Loc), Text(Insertion.str()) {
+    assert(Loc.isValid());
+  }
+
+  // FIXME: Twine.str() is not very efficient.
+  SMFixIt(SMRange R, const Twine &Replacement)
+    : Range(R), Text(Replacement.str()) {
+    assert(R.isValid());
+  }
+
+  StringRef getText() const { return Text; }
+  SMRange getRange() const { return Range; }
+
+  bool operator<(const SMFixIt &Other) const {
+    if (Range.Start.getPointer() != Other.Range.Start.getPointer())
+      return Range.Start.getPointer() < Other.Range.Start.getPointer();
+    if (Range.End.getPointer() != Other.Range.End.getPointer())
+      return Range.End.getPointer() < Other.Range.End.getPointer();
+    return Text < Other.Text;
+  }
+};
+
+/// Instances of this class encapsulate one diagnostic report, allowing
+/// printing to a raw_ostream as a caret diagnostic.
+class SMDiagnostic {
+  const SourceMgr *SM = nullptr;
+  SMLoc Loc;
+  std::string Filename;
+  int LineNo = 0;
+  int ColumnNo = 0;
+  SourceMgr::DiagKind Kind = SourceMgr::DK_Error;
+  std::string Message, LineContents;
+  std::vector<std::pair<unsigned, unsigned>> Ranges;
+  SmallVector<SMFixIt, 4> FixIts;
+
+public:
+  // Null diagnostic.
+  SMDiagnostic() = default;
+  // Diagnostic with no location (e.g. file not found, command line arg error).
+  SMDiagnostic(StringRef filename, SourceMgr::DiagKind Knd, StringRef Msg)
+    : Filename(filename), LineNo(-1), ColumnNo(-1), Kind(Knd), Message(Msg) {}
+
+  // Diagnostic with a location.
+  SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN,
+               int Line, int Col, SourceMgr::DiagKind Kind,
+               StringRef Msg, StringRef LineStr,
+               ArrayRef<std::pair<unsigned,unsigned>> Ranges,
+               ArrayRef<SMFixIt> FixIts = None);
+
+  const SourceMgr *getSourceMgr() const { return SM; }
+  SMLoc getLoc() const { return Loc; }
+  StringRef getFilename() const { return Filename; }
+  int getLineNo() const { return LineNo; }
+  int getColumnNo() const { return ColumnNo; }
+  SourceMgr::DiagKind getKind() const { return Kind; }
+  StringRef getMessage() const { return Message; }
+  StringRef getLineContents() const { return LineContents; }
+  ArrayRef<std::pair<unsigned, unsigned>> getRanges() const { return Ranges; }
+
+  void addFixIt(const SMFixIt &Hint) {
+    FixIts.push_back(Hint);
+  }
+
+  ArrayRef<SMFixIt> getFixIts() const {
+    return FixIts;
+  }
+
+  void print(const char *ProgName, raw_ostream &S, bool ShowColors = true,
+             bool ShowKindLabel = true) const;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_SOURCEMGR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/SwapByteOrder.h b/binaryen/third_party/llvm-project/include/llvm/Support/SwapByteOrder.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/SwapByteOrder.h
@@ -0,0 +1,160 @@
+//===- SwapByteOrder.h - Generic and optimized byte swaps -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares generic and optimized functions to swap the byte order of
+// an integral type.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SWAPBYTEORDER_H
+#define LLVM_SUPPORT_SWAPBYTEORDER_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DataTypes.h"
+#include <cstddef>
+#include <type_traits>
+#if defined(_MSC_VER) && !defined(_DEBUG)
+#include <stdlib.h>
+#endif
+
+#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__)
+#include <endian.h>
+#elif defined(_AIX)
+#include <sys/machine.h>
+#elif defined(__sun)
+/* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */
+#include <sys/types.h>
+#define BIG_ENDIAN 4321
+#define LITTLE_ENDIAN 1234
+#if defined(_BIG_ENDIAN)
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+#else
+#if !defined(BYTE_ORDER) && !defined(_WIN32)
+#include <machine/endian.h>
+#endif
+#endif
+
+namespace llvm {
+namespace sys {
+
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
+constexpr bool IsBigEndianHost = true;
+#else
+constexpr bool IsBigEndianHost = false;
+#endif
+
+static const bool IsLittleEndianHost = !IsBigEndianHost;
+
+/// SwapByteOrder_16 - This function returns a byte-swapped representation of
+/// the 16-bit argument.
+inline uint16_t SwapByteOrder_16(uint16_t value) {
+#if defined(_MSC_VER) && !defined(_DEBUG)
+  // The DLL version of the runtime lacks these functions (bug!?), but in a
+  // release build they're replaced with BSWAP instructions anyway.
+  return _byteswap_ushort(value);
+#else
+  uint16_t Hi = value << 8;
+  uint16_t Lo = value >> 8;
+  return Hi | Lo;
+#endif
+}
+
+/// This function returns a byte-swapped representation of the 32-bit argument.
+inline uint32_t SwapByteOrder_32(uint32_t value) {
+#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC))
+  return __builtin_bswap32(value);
+#elif defined(_MSC_VER) && !defined(_DEBUG)
+  return _byteswap_ulong(value);
+#else
+  uint32_t Byte0 = value & 0x000000FF;
+  uint32_t Byte1 = value & 0x0000FF00;
+  uint32_t Byte2 = value & 0x00FF0000;
+  uint32_t Byte3 = value & 0xFF000000;
+  return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24);
+#endif
+}
+
+/// This function returns a byte-swapped representation of the 64-bit argument.
+inline uint64_t SwapByteOrder_64(uint64_t value) {
+#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC))
+  return __builtin_bswap64(value);
+#elif defined(_MSC_VER) && !defined(_DEBUG)
+  return _byteswap_uint64(value);
+#else
+  uint64_t Hi = SwapByteOrder_32(uint32_t(value));
+  uint32_t Lo = SwapByteOrder_32(uint32_t(value >> 32));
+  return (Hi << 32) | Lo;
+#endif
+}
+
+inline unsigned char  getSwappedBytes(unsigned char C) { return C; }
+inline   signed char  getSwappedBytes(signed char C) { return C; }
+inline          char  getSwappedBytes(char C) { return C; }
+
+inline unsigned short getSwappedBytes(unsigned short C) { return SwapByteOrder_16(C); }
+inline   signed short getSwappedBytes(  signed short C) { return SwapByteOrder_16(C); }
+
+inline unsigned int   getSwappedBytes(unsigned int   C) { return SwapByteOrder_32(C); }
+inline   signed int   getSwappedBytes(  signed int   C) { return SwapByteOrder_32(C); }
+
+#if __LONG_MAX__ == __INT_MAX__
+inline unsigned long  getSwappedBytes(unsigned long  C) { return SwapByteOrder_32(C); }
+inline   signed long  getSwappedBytes(  signed long  C) { return SwapByteOrder_32(C); }
+#elif __LONG_MAX__ == __LONG_LONG_MAX__
+inline unsigned long  getSwappedBytes(unsigned long  C) { return SwapByteOrder_64(C); }
+inline   signed long  getSwappedBytes(  signed long  C) { return SwapByteOrder_64(C); }
+#else
+#error "Unknown long size!"
+#endif
+
+inline unsigned long long getSwappedBytes(unsigned long long C) {
+  return SwapByteOrder_64(C);
+}
+inline signed long long getSwappedBytes(signed long long C) {
+  return SwapByteOrder_64(C);
+}
+
+inline float getSwappedBytes(float C) {
+  union {
+    uint32_t i;
+    float f;
+  } in, out;
+  in.f = C;
+  out.i = SwapByteOrder_32(in.i);
+  return out.f;
+}
+
+inline double getSwappedBytes(double C) {
+  union {
+    uint64_t i;
+    double d;
+  } in, out;
+  in.d = C;
+  out.i = SwapByteOrder_64(in.i);
+  return out.d;
+}
+
+template <typename T>
+inline typename std::enable_if<std::is_enum<T>::value, T>::type
+getSwappedBytes(T C) {
+  return static_cast<T>(
+      getSwappedBytes(static_cast<typename std::underlying_type<T>::type>(C)));
+}
+
+template<typename T>
+inline void swapByteOrder(T &Value) {
+  Value = getSwappedBytes(Value);
+}
+
+} // end namespace sys
+} // end namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/TargetParser.h b/binaryen/third_party/llvm-project/include/llvm/Support/TargetParser.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/TargetParser.h
@@ -0,0 +1,174 @@
+//===-- TargetParser - Parser for target features ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a target parser to recognise hardware features such as
+// FPU/CPU/ARCH names as well as specific support such as HDIV, etc.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_TARGETPARSER_H
+#define LLVM_SUPPORT_TARGETPARSER_H
+
+// FIXME: vector is used because that's what clang uses for subtarget feature
+// lists, but SmallVector would probably be better
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/ARMTargetParser.h"
+#include "llvm/Support/AArch64TargetParser.h"
+#include <vector>
+
+namespace llvm {
+class StringRef;
+
+// Target specific information in their own namespaces.
+// (ARM/AArch64 are declared in ARM/AArch64TargetParser.h)
+// These should be generated from TableGen because the information is already
+// there, and there is where new information about targets will be added.
+// FIXME: To TableGen this we need to make some table generated files available
+// even if the back-end is not compiled with LLVM, plus we need to create a new
+// back-end to TableGen to create these clean tables.
+namespace X86 {
+
+// This should be kept in sync with libcc/compiler-rt as its included by clang
+// as a proxy for what's in libgcc/compiler-rt.
+enum ProcessorVendors : unsigned {
+  VENDOR_DUMMY,
+#define X86_VENDOR(ENUM, STRING) \
+  ENUM,
+#include "llvm/Support/X86TargetParser.def"
+  VENDOR_OTHER
+};
+
+// This should be kept in sync with libcc/compiler-rt as its included by clang
+// as a proxy for what's in libgcc/compiler-rt.
+enum ProcessorTypes : unsigned {
+  CPU_TYPE_DUMMY,
+#define X86_CPU_TYPE(ARCHNAME, ENUM) \
+  ENUM,
+#include "llvm/Support/X86TargetParser.def"
+  CPU_TYPE_MAX
+};
+
+// This should be kept in sync with libcc/compiler-rt as its included by clang
+// as a proxy for what's in libgcc/compiler-rt.
+enum ProcessorSubtypes : unsigned {
+  CPU_SUBTYPE_DUMMY,
+#define X86_CPU_SUBTYPE(ARCHNAME, ENUM) \
+  ENUM,
+#include "llvm/Support/X86TargetParser.def"
+  CPU_SUBTYPE_MAX
+};
+
+// This should be kept in sync with libcc/compiler-rt as it should be used
+// by clang as a proxy for what's in libgcc/compiler-rt.
+enum ProcessorFeatures {
+#define X86_FEATURE(VAL, ENUM) \
+  ENUM = VAL,
+#include "llvm/Support/X86TargetParser.def"
+
+};
+
+} // namespace X86
+
+namespace AMDGPU {
+
+/// GPU kinds supported by the AMDGPU target.
+enum GPUKind : uint32_t {
+  // Not specified processor.
+  GK_NONE = 0,
+
+  // R600-based processors.
+  GK_R600 = 1,
+  GK_R630 = 2,
+  GK_RS880 = 3,
+  GK_RV670 = 4,
+  GK_RV710 = 5,
+  GK_RV730 = 6,
+  GK_RV770 = 7,
+  GK_CEDAR = 8,
+  GK_CYPRESS = 9,
+  GK_JUNIPER = 10,
+  GK_REDWOOD = 11,
+  GK_SUMO = 12,
+  GK_BARTS = 13,
+  GK_CAICOS = 14,
+  GK_CAYMAN = 15,
+  GK_TURKS = 16,
+
+  GK_R600_FIRST = GK_R600,
+  GK_R600_LAST = GK_TURKS,
+
+  // AMDGCN-based processors.
+  GK_GFX600 = 32,
+  GK_GFX601 = 33,
+
+  GK_GFX700 = 40,
+  GK_GFX701 = 41,
+  GK_GFX702 = 42,
+  GK_GFX703 = 43,
+  GK_GFX704 = 44,
+
+  GK_GFX801 = 50,
+  GK_GFX802 = 51,
+  GK_GFX803 = 52,
+  GK_GFX810 = 53,
+
+  GK_GFX900 = 60,
+  GK_GFX902 = 61,
+  GK_GFX904 = 62,
+  GK_GFX906 = 63,
+  GK_GFX908 = 64,
+  GK_GFX909 = 65,
+
+  GK_GFX1010 = 71,
+  GK_GFX1011 = 72,
+  GK_GFX1012 = 73,
+
+  GK_AMDGCN_FIRST = GK_GFX600,
+  GK_AMDGCN_LAST = GK_GFX1012,
+};
+
+/// Instruction set architecture version.
+struct IsaVersion {
+  unsigned Major;
+  unsigned Minor;
+  unsigned Stepping;
+};
+
+// This isn't comprehensive for now, just things that are needed from the
+// frontend driver.
+enum ArchFeatureKind : uint32_t {
+  FEATURE_NONE = 0,
+
+  // These features only exist for r600, and are implied true for amdgcn.
+  FEATURE_FMA = 1 << 1,
+  FEATURE_LDEXP = 1 << 2,
+  FEATURE_FP64 = 1 << 3,
+
+  // Common features.
+  FEATURE_FAST_FMA_F32 = 1 << 4,
+  FEATURE_FAST_DENORMAL_F32 = 1 << 5
+};
+
+StringRef getArchNameAMDGCN(GPUKind AK);
+StringRef getArchNameR600(GPUKind AK);
+StringRef getCanonicalArchName(StringRef Arch);
+GPUKind parseArchAMDGCN(StringRef CPU);
+GPUKind parseArchR600(StringRef CPU);
+unsigned getArchAttrAMDGCN(GPUKind AK);
+unsigned getArchAttrR600(GPUKind AK);
+
+void fillValidArchListAMDGCN(SmallVectorImpl<StringRef> &Values);
+void fillValidArchListR600(SmallVectorImpl<StringRef> &Values);
+
+IsaVersion getIsaVersion(StringRef GPU);
+
+} // namespace AMDGPU
+
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/TargetRegistry.h b/binaryen/third_party/llvm-project/include/llvm/Support/TargetRegistry.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/TargetRegistry.h
@@ -0,0 +1,1209 @@
+//===- Support/TargetRegistry.h - Target Registration -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file exposes the TargetRegistry interface, which tools can use to access
+// the appropriate target specific classes (TargetMachine, AsmPrinter, etc.)
+// which have been registered.
+//
+// Target specific class implementations should register themselves using the
+// appropriate TargetRegistry interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_TARGETREGISTRY_H
+#define LLVM_SUPPORT_TARGETREGISTRY_H
+
+#include "llvm-c/DisassemblerTypes.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormattedStream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <memory>
+#include <string>
+
+namespace llvm {
+
+class AsmPrinter;
+class MCAsmBackend;
+class MCAsmInfo;
+class MCAsmParser;
+class MCCodeEmitter;
+class MCContext;
+class MCDisassembler;
+class MCInstPrinter;
+class MCInstrAnalysis;
+class MCInstrInfo;
+class MCObjectWriter;
+class MCRegisterInfo;
+class MCRelocationInfo;
+class MCStreamer;
+class MCSubtargetInfo;
+class MCSymbolizer;
+class MCTargetAsmParser;
+class MCTargetOptions;
+class MCTargetStreamer;
+class raw_ostream;
+class raw_pwrite_stream;
+class TargetMachine;
+class TargetOptions;
+
+MCStreamer *createNullStreamer(MCContext &Ctx);
+// Takes ownership of \p TAB and \p CE.
+
+/// Create a machine code streamer which will print out assembly for the native
+/// target, suitable for compiling with a native assembler.
+///
+/// \param InstPrint - If given, the instruction printer to use. If not given
+/// the MCInst representation will be printed.  This method takes ownership of
+/// InstPrint.
+///
+/// \param CE - If given, a code emitter to use to show the instruction
+/// encoding inline with the assembly. This method takes ownership of \p CE.
+///
+/// \param TAB - If given, a target asm backend to use to show the fixup
+/// information in conjunction with encoding information. This method takes
+/// ownership of \p TAB.
+///
+/// \param ShowInst - Whether to show the MCInst representation inline with
+/// the assembly.
+MCStreamer *
+createAsmStreamer(MCContext &Ctx, std::unique_ptr<formatted_raw_ostream> OS,
+                  bool isVerboseAsm, bool useDwarfDirectory,
+                  MCInstPrinter *InstPrint, std::unique_ptr<MCCodeEmitter> &&CE,
+                  std::unique_ptr<MCAsmBackend> &&TAB, bool ShowInst);
+
+MCStreamer *createELFStreamer(MCContext &Ctx,
+                              std::unique_ptr<MCAsmBackend> &&TAB,
+                              std::unique_ptr<MCObjectWriter> &&OW,
+                              std::unique_ptr<MCCodeEmitter> &&CE,
+                              bool RelaxAll);
+MCStreamer *createMachOStreamer(MCContext &Ctx,
+                                std::unique_ptr<MCAsmBackend> &&TAB,
+                                std::unique_ptr<MCObjectWriter> &&OW,
+                                std::unique_ptr<MCCodeEmitter> &&CE,
+                                bool RelaxAll, bool DWARFMustBeAtTheEnd,
+                                bool LabelSections = false);
+MCStreamer *createWasmStreamer(MCContext &Ctx,
+                               std::unique_ptr<MCAsmBackend> &&TAB,
+                               std::unique_ptr<MCObjectWriter> &&OW,
+                               std::unique_ptr<MCCodeEmitter> &&CE,
+                               bool RelaxAll);
+MCStreamer *createXCOFFStreamer(MCContext &Ctx,
+                                std::unique_ptr<MCAsmBackend> &&TAB,
+                                std::unique_ptr<MCObjectWriter> &&OW,
+                                std::unique_ptr<MCCodeEmitter> &&CE,
+                                bool RelaxAll);
+
+MCRelocationInfo *createMCRelocationInfo(const Triple &TT, MCContext &Ctx);
+
+MCSymbolizer *createMCSymbolizer(const Triple &TT, LLVMOpInfoCallback GetOpInfo,
+                                 LLVMSymbolLookupCallback SymbolLookUp,
+                                 void *DisInfo, MCContext *Ctx,
+                                 std::unique_ptr<MCRelocationInfo> &&RelInfo);
+
+/// Target - Wrapper for Target specific information.
+///
+/// For registration purposes, this is a POD type so that targets can be
+/// registered without the use of static constructors.
+///
+/// Targets should implement a single global instance of this class (which
+/// will be zero initialized), and pass that instance to the TargetRegistry as
+/// part of their initialization.
+class Target {
+public:
+  friend struct TargetRegistry;
+
+  using ArchMatchFnTy = bool (*)(Triple::ArchType Arch);
+
+  using MCAsmInfoCtorFnTy = MCAsmInfo *(*)(const MCRegisterInfo &MRI,
+                                           const Triple &TT,
+                                           const MCTargetOptions &Options);
+  using MCInstrInfoCtorFnTy = MCInstrInfo *(*)();
+  using MCInstrAnalysisCtorFnTy = MCInstrAnalysis *(*)(const MCInstrInfo *Info);
+  using MCRegInfoCtorFnTy = MCRegisterInfo *(*)(const Triple &TT);
+  using MCSubtargetInfoCtorFnTy = MCSubtargetInfo *(*)(const Triple &TT,
+                                                       StringRef CPU,
+                                                       StringRef Features);
+  using TargetMachineCtorTy = TargetMachine
+      *(*)(const Target &T, const Triple &TT, StringRef CPU, StringRef Features,
+           const TargetOptions &Options, Optional<Reloc::Model> RM,
+           Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT);
+  // If it weren't for layering issues (this header is in llvm/Support, but
+  // depends on MC?) this should take the Streamer by value rather than rvalue
+  // reference.
+  using AsmPrinterCtorTy = AsmPrinter *(*)(
+      TargetMachine &TM, std::unique_ptr<MCStreamer> &&Streamer);
+  using MCAsmBackendCtorTy = MCAsmBackend *(*)(const Target &T,
+                                               const MCSubtargetInfo &STI,
+                                               const MCRegisterInfo &MRI,
+                                               const MCTargetOptions &Options);
+  using MCAsmParserCtorTy = MCTargetAsmParser *(*)(
+      const MCSubtargetInfo &STI, MCAsmParser &P, const MCInstrInfo &MII,
+      const MCTargetOptions &Options);
+  using MCDisassemblerCtorTy = MCDisassembler *(*)(const Target &T,
+                                                   const MCSubtargetInfo &STI,
+                                                   MCContext &Ctx);
+  using MCInstPrinterCtorTy = MCInstPrinter *(*)(const Triple &T,
+                                                 unsigned SyntaxVariant,
+                                                 const MCAsmInfo &MAI,
+                                                 const MCInstrInfo &MII,
+                                                 const MCRegisterInfo &MRI);
+  using MCCodeEmitterCtorTy = MCCodeEmitter *(*)(const MCInstrInfo &II,
+                                                 const MCRegisterInfo &MRI,
+                                                 MCContext &Ctx);
+  using ELFStreamerCtorTy =
+      MCStreamer *(*)(const Triple &T, MCContext &Ctx,
+                      std::unique_ptr<MCAsmBackend> &&TAB,
+                      std::unique_ptr<MCObjectWriter> &&OW,
+                      std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll);
+  using MachOStreamerCtorTy =
+      MCStreamer *(*)(MCContext &Ctx, std::unique_ptr<MCAsmBackend> &&TAB,
+                      std::unique_ptr<MCObjectWriter> &&OW,
+                      std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll,
+                      bool DWARFMustBeAtTheEnd);
+  using COFFStreamerCtorTy =
+      MCStreamer *(*)(MCContext &Ctx, std::unique_ptr<MCAsmBackend> &&TAB,
+                      std::unique_ptr<MCObjectWriter> &&OW,
+                      std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll,
+                      bool IncrementalLinkerCompatible);
+  using WasmStreamerCtorTy =
+      MCStreamer *(*)(const Triple &T, MCContext &Ctx,
+                      std::unique_ptr<MCAsmBackend> &&TAB,
+                      std::unique_ptr<MCObjectWriter> &&OW,
+                      std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll);
+  using NullTargetStreamerCtorTy = MCTargetStreamer *(*)(MCStreamer &S);
+  using AsmTargetStreamerCtorTy = MCTargetStreamer *(*)(
+      MCStreamer &S, formatted_raw_ostream &OS, MCInstPrinter *InstPrint,
+      bool IsVerboseAsm);
+  using ObjectTargetStreamerCtorTy = MCTargetStreamer *(*)(
+      MCStreamer &S, const MCSubtargetInfo &STI);
+  using MCRelocationInfoCtorTy = MCRelocationInfo *(*)(const Triple &TT,
+                                                       MCContext &Ctx);
+  using MCSymbolizerCtorTy = MCSymbolizer *(*)(
+      const Triple &TT, LLVMOpInfoCallback GetOpInfo,
+      LLVMSymbolLookupCallback SymbolLookUp, void *DisInfo, MCContext *Ctx,
+      std::unique_ptr<MCRelocationInfo> &&RelInfo);
+
+private:
+  /// Next - The next registered target in the linked list, maintained by the
+  /// TargetRegistry.
+  Target *Next;
+
+  /// The target function for checking if an architecture is supported.
+  ArchMatchFnTy ArchMatchFn;
+
+  /// Name - The target name.
+  const char *Name;
+
+  /// ShortDesc - A short description of the target.
+  const char *ShortDesc;
+
+  /// BackendName - The name of the backend implementation. This must match the
+  /// name of the 'def X : Target ...' in TableGen.
+  const char *BackendName;
+
+  /// HasJIT - Whether this target supports the JIT.
+  bool HasJIT;
+
+  /// MCAsmInfoCtorFn - Constructor function for this target's MCAsmInfo, if
+  /// registered.
+  MCAsmInfoCtorFnTy MCAsmInfoCtorFn;
+
+  /// MCInstrInfoCtorFn - Constructor function for this target's MCInstrInfo,
+  /// if registered.
+  MCInstrInfoCtorFnTy MCInstrInfoCtorFn;
+
+  /// MCInstrAnalysisCtorFn - Constructor function for this target's
+  /// MCInstrAnalysis, if registered.
+  MCInstrAnalysisCtorFnTy MCInstrAnalysisCtorFn;
+
+  /// MCRegInfoCtorFn - Constructor function for this target's MCRegisterInfo,
+  /// if registered.
+  MCRegInfoCtorFnTy MCRegInfoCtorFn;
+
+  /// MCSubtargetInfoCtorFn - Constructor function for this target's
+  /// MCSubtargetInfo, if registered.
+  MCSubtargetInfoCtorFnTy MCSubtargetInfoCtorFn;
+
+  /// TargetMachineCtorFn - Construction function for this target's
+  /// TargetMachine, if registered.
+  TargetMachineCtorTy TargetMachineCtorFn;
+
+  /// MCAsmBackendCtorFn - Construction function for this target's
+  /// MCAsmBackend, if registered.
+  MCAsmBackendCtorTy MCAsmBackendCtorFn;
+
+  /// MCAsmParserCtorFn - Construction function for this target's
+  /// MCTargetAsmParser, if registered.
+  MCAsmParserCtorTy MCAsmParserCtorFn;
+
+  /// AsmPrinterCtorFn - Construction function for this target's AsmPrinter,
+  /// if registered.
+  AsmPrinterCtorTy AsmPrinterCtorFn;
+
+  /// MCDisassemblerCtorFn - Construction function for this target's
+  /// MCDisassembler, if registered.
+  MCDisassemblerCtorTy MCDisassemblerCtorFn;
+
+  /// MCInstPrinterCtorFn - Construction function for this target's
+  /// MCInstPrinter, if registered.
+  MCInstPrinterCtorTy MCInstPrinterCtorFn;
+
+  /// MCCodeEmitterCtorFn - Construction function for this target's
+  /// CodeEmitter, if registered.
+  MCCodeEmitterCtorTy MCCodeEmitterCtorFn;
+
+  // Construction functions for the various object formats, if registered.
+  COFFStreamerCtorTy COFFStreamerCtorFn = nullptr;
+  MachOStreamerCtorTy MachOStreamerCtorFn = nullptr;
+  ELFStreamerCtorTy ELFStreamerCtorFn = nullptr;
+  WasmStreamerCtorTy WasmStreamerCtorFn = nullptr;
+
+  /// Construction function for this target's null TargetStreamer, if
+  /// registered (default = nullptr).
+  NullTargetStreamerCtorTy NullTargetStreamerCtorFn = nullptr;
+
+  /// Construction function for this target's asm TargetStreamer, if
+  /// registered (default = nullptr).
+  AsmTargetStreamerCtorTy AsmTargetStreamerCtorFn = nullptr;
+
+  /// Construction function for this target's obj TargetStreamer, if
+  /// registered (default = nullptr).
+  ObjectTargetStreamerCtorTy ObjectTargetStreamerCtorFn = nullptr;
+
+  /// MCRelocationInfoCtorFn - Construction function for this target's
+  /// MCRelocationInfo, if registered (default = llvm::createMCRelocationInfo)
+  MCRelocationInfoCtorTy MCRelocationInfoCtorFn = nullptr;
+
+  /// MCSymbolizerCtorFn - Construction function for this target's
+  /// MCSymbolizer, if registered (default = llvm::createMCSymbolizer)
+  MCSymbolizerCtorTy MCSymbolizerCtorFn = nullptr;
+
+public:
+  Target() = default;
+
+  /// @name Target Information
+  /// @{
+
+  // getNext - Return the next registered target.
+  const Target *getNext() const { return Next; }
+
+  /// getName - Get the target name.
+  const char *getName() const { return Name; }
+
+  /// getShortDescription - Get a short description of the target.
+  const char *getShortDescription() const { return ShortDesc; }
+
+  /// getBackendName - Get the backend name.
+  const char *getBackendName() const { return BackendName; }
+
+  /// @}
+  /// @name Feature Predicates
+  /// @{
+
+  /// hasJIT - Check if this targets supports the just-in-time compilation.
+  bool hasJIT() const { return HasJIT; }
+
+  /// hasTargetMachine - Check if this target supports code generation.
+  bool hasTargetMachine() const { return TargetMachineCtorFn != nullptr; }
+
+  /// hasMCAsmBackend - Check if this target supports .o generation.
+  bool hasMCAsmBackend() const { return MCAsmBackendCtorFn != nullptr; }
+
+  /// hasMCAsmParser - Check if this target supports assembly parsing.
+  bool hasMCAsmParser() const { return MCAsmParserCtorFn != nullptr; }
+
+  /// @}
+  /// @name Feature Constructors
+  /// @{
+
+  /// createMCAsmInfo - Create a MCAsmInfo implementation for the specified
+  /// target triple.
+  ///
+  /// \param TheTriple This argument is used to determine the target machine
+  /// feature set; it should always be provided. Generally this should be
+  /// either the target triple from the module, or the target triple of the
+  /// host if that does not exist.
+  MCAsmInfo *createMCAsmInfo(const MCRegisterInfo &MRI, StringRef TheTriple,
+                             const MCTargetOptions &Options) const {
+    if (!MCAsmInfoCtorFn)
+      return nullptr;
+    return MCAsmInfoCtorFn(MRI, Triple(TheTriple), Options);
+  }
+
+  /// createMCInstrInfo - Create a MCInstrInfo implementation.
+  ///
+  MCInstrInfo *createMCInstrInfo() const {
+    if (!MCInstrInfoCtorFn)
+      return nullptr;
+    return MCInstrInfoCtorFn();
+  }
+
+  /// createMCInstrAnalysis - Create a MCInstrAnalysis implementation.
+  ///
+  MCInstrAnalysis *createMCInstrAnalysis(const MCInstrInfo *Info) const {
+    if (!MCInstrAnalysisCtorFn)
+      return nullptr;
+    return MCInstrAnalysisCtorFn(Info);
+  }
+
+  /// createMCRegInfo - Create a MCRegisterInfo implementation.
+  ///
+  MCRegisterInfo *createMCRegInfo(StringRef TT) const {
+    if (!MCRegInfoCtorFn)
+      return nullptr;
+    return MCRegInfoCtorFn(Triple(TT));
+  }
+
+  /// createMCSubtargetInfo - Create a MCSubtargetInfo implementation.
+  ///
+  /// \param TheTriple This argument is used to determine the target machine
+  /// feature set; it should always be provided. Generally this should be
+  /// either the target triple from the module, or the target triple of the
+  /// host if that does not exist.
+  /// \param CPU This specifies the name of the target CPU.
+  /// \param Features This specifies the string representation of the
+  /// additional target features.
+  MCSubtargetInfo *createMCSubtargetInfo(StringRef TheTriple, StringRef CPU,
+                                         StringRef Features) const {
+    if (!MCSubtargetInfoCtorFn)
+      return nullptr;
+    return MCSubtargetInfoCtorFn(Triple(TheTriple), CPU, Features);
+  }
+
+  /// createTargetMachine - Create a target specific machine implementation
+  /// for the specified \p Triple.
+  ///
+  /// \param TT This argument is used to determine the target machine
+  /// feature set; it should always be provided. Generally this should be
+  /// either the target triple from the module, or the target triple of the
+  /// host if that does not exist.
+  TargetMachine *createTargetMachine(StringRef TT, StringRef CPU,
+                                     StringRef Features,
+                                     const TargetOptions &Options,
+                                     Optional<Reloc::Model> RM,
+                                     Optional<CodeModel::Model> CM = None,
+                                     CodeGenOpt::Level OL = CodeGenOpt::Default,
+                                     bool JIT = false) const {
+    if (!TargetMachineCtorFn)
+      return nullptr;
+    return TargetMachineCtorFn(*this, Triple(TT), CPU, Features, Options, RM,
+                               CM, OL, JIT);
+  }
+
+  /// createMCAsmBackend - Create a target specific assembly parser.
+  MCAsmBackend *createMCAsmBackend(const MCSubtargetInfo &STI,
+                                   const MCRegisterInfo &MRI,
+                                   const MCTargetOptions &Options) const {
+    if (!MCAsmBackendCtorFn)
+      return nullptr;
+    return MCAsmBackendCtorFn(*this, STI, MRI, Options);
+  }
+
+  /// createMCAsmParser - Create a target specific assembly parser.
+  ///
+  /// \param Parser The target independent parser implementation to use for
+  /// parsing and lexing.
+  MCTargetAsmParser *createMCAsmParser(const MCSubtargetInfo &STI,
+                                       MCAsmParser &Parser,
+                                       const MCInstrInfo &MII,
+                                       const MCTargetOptions &Options) const {
+    if (!MCAsmParserCtorFn)
+      return nullptr;
+    return MCAsmParserCtorFn(STI, Parser, MII, Options);
+  }
+
+  /// createAsmPrinter - Create a target specific assembly printer pass.  This
+  /// takes ownership of the MCStreamer object.
+  AsmPrinter *createAsmPrinter(TargetMachine &TM,
+                               std::unique_ptr<MCStreamer> &&Streamer) const {
+    if (!AsmPrinterCtorFn)
+      return nullptr;
+    return AsmPrinterCtorFn(TM, std::move(Streamer));
+  }
+
+  MCDisassembler *createMCDisassembler(const MCSubtargetInfo &STI,
+                                       MCContext &Ctx) const {
+    if (!MCDisassemblerCtorFn)
+      return nullptr;
+    return MCDisassemblerCtorFn(*this, STI, Ctx);
+  }
+
+  MCInstPrinter *createMCInstPrinter(const Triple &T, unsigned SyntaxVariant,
+                                     const MCAsmInfo &MAI,
+                                     const MCInstrInfo &MII,
+                                     const MCRegisterInfo &MRI) const {
+    if (!MCInstPrinterCtorFn)
+      return nullptr;
+    return MCInstPrinterCtorFn(T, SyntaxVariant, MAI, MII, MRI);
+  }
+
+  /// createMCCodeEmitter - Create a target specific code emitter.
+  MCCodeEmitter *createMCCodeEmitter(const MCInstrInfo &II,
+                                     const MCRegisterInfo &MRI,
+                                     MCContext &Ctx) const {
+    if (!MCCodeEmitterCtorFn)
+      return nullptr;
+    return MCCodeEmitterCtorFn(II, MRI, Ctx);
+  }
+
+  /// Create a target specific MCStreamer.
+  ///
+  /// \param T The target triple.
+  /// \param Ctx The target context.
+  /// \param TAB The target assembler backend object. Takes ownership.
+  /// \param OW The stream object.
+  /// \param Emitter The target independent assembler object.Takes ownership.
+  /// \param RelaxAll Relax all fixups?
+  MCStreamer *createMCObjectStreamer(const Triple &T, MCContext &Ctx,
+                                     std::unique_ptr<MCAsmBackend> &&TAB,
+                                     std::unique_ptr<MCObjectWriter> &&OW,
+                                     std::unique_ptr<MCCodeEmitter> &&Emitter,
+                                     const MCSubtargetInfo &STI, bool RelaxAll,
+                                     bool IncrementalLinkerCompatible,
+                                     bool DWARFMustBeAtTheEnd) const {
+    MCStreamer *S = nullptr;
+    switch (T.getObjectFormat()) {
+    case Triple::UnknownObjectFormat:
+      llvm_unreachable("Unknown object format");
+    case Triple::COFF:
+      assert(T.isOSWindows() && "only Windows COFF is supported");
+      S = COFFStreamerCtorFn(Ctx, std::move(TAB), std::move(OW),
+                             std::move(Emitter), RelaxAll,
+                             IncrementalLinkerCompatible);
+      break;
+    case Triple::MachO:
+      if (MachOStreamerCtorFn)
+        S = MachOStreamerCtorFn(Ctx, std::move(TAB), std::move(OW),
+                                std::move(Emitter), RelaxAll,
+                                DWARFMustBeAtTheEnd);
+      else
+        S = createMachOStreamer(Ctx, std::move(TAB), std::move(OW),
+                                std::move(Emitter), RelaxAll,
+                                DWARFMustBeAtTheEnd);
+      break;
+    case Triple::ELF:
+      if (ELFStreamerCtorFn)
+        S = ELFStreamerCtorFn(T, Ctx, std::move(TAB), std::move(OW),
+                              std::move(Emitter), RelaxAll);
+      else
+        S = createELFStreamer(Ctx, std::move(TAB), std::move(OW),
+                              std::move(Emitter), RelaxAll);
+      break;
+    case Triple::Wasm:
+      if (WasmStreamerCtorFn)
+        S = WasmStreamerCtorFn(T, Ctx, std::move(TAB), std::move(OW),
+                               std::move(Emitter), RelaxAll);
+      else
+        S = createWasmStreamer(Ctx, std::move(TAB), std::move(OW),
+                               std::move(Emitter), RelaxAll);
+      break;
+    case Triple::XCOFF:
+      S = createXCOFFStreamer(Ctx, std::move(TAB), std::move(OW),
+                              std::move(Emitter), RelaxAll);
+      break;
+    }
+    if (ObjectTargetStreamerCtorFn)
+      ObjectTargetStreamerCtorFn(*S, STI);
+    return S;
+  }
+
+  MCStreamer *createAsmStreamer(MCContext &Ctx,
+                                std::unique_ptr<formatted_raw_ostream> OS,
+                                bool IsVerboseAsm, bool UseDwarfDirectory,
+                                MCInstPrinter *InstPrint,
+                                std::unique_ptr<MCCodeEmitter> &&CE,
+                                std::unique_ptr<MCAsmBackend> &&TAB,
+                                bool ShowInst) const {
+    formatted_raw_ostream &OSRef = *OS;
+    MCStreamer *S = llvm::createAsmStreamer(
+        Ctx, std::move(OS), IsVerboseAsm, UseDwarfDirectory, InstPrint,
+        std::move(CE), std::move(TAB), ShowInst);
+    createAsmTargetStreamer(*S, OSRef, InstPrint, IsVerboseAsm);
+    return S;
+  }
+
+  MCTargetStreamer *createAsmTargetStreamer(MCStreamer &S,
+                                            formatted_raw_ostream &OS,
+                                            MCInstPrinter *InstPrint,
+                                            bool IsVerboseAsm) const {
+    if (AsmTargetStreamerCtorFn)
+      return AsmTargetStreamerCtorFn(S, OS, InstPrint, IsVerboseAsm);
+    return nullptr;
+  }
+
+  MCStreamer *createNullStreamer(MCContext &Ctx) const {
+    MCStreamer *S = llvm::createNullStreamer(Ctx);
+    createNullTargetStreamer(*S);
+    return S;
+  }
+
+  MCTargetStreamer *createNullTargetStreamer(MCStreamer &S) const {
+    if (NullTargetStreamerCtorFn)
+      return NullTargetStreamerCtorFn(S);
+    return nullptr;
+  }
+
+  /// createMCRelocationInfo - Create a target specific MCRelocationInfo.
+  ///
+  /// \param TT The target triple.
+  /// \param Ctx The target context.
+  MCRelocationInfo *createMCRelocationInfo(StringRef TT, MCContext &Ctx) const {
+    MCRelocationInfoCtorTy Fn = MCRelocationInfoCtorFn
+                                    ? MCRelocationInfoCtorFn
+                                    : llvm::createMCRelocationInfo;
+    return Fn(Triple(TT), Ctx);
+  }
+
+  /// createMCSymbolizer - Create a target specific MCSymbolizer.
+  ///
+  /// \param TT The target triple.
+  /// \param GetOpInfo The function to get the symbolic information for
+  /// operands.
+  /// \param SymbolLookUp The function to lookup a symbol name.
+  /// \param DisInfo The pointer to the block of symbolic information for above
+  /// call
+  /// back.
+  /// \param Ctx The target context.
+  /// \param RelInfo The relocation information for this target. Takes
+  /// ownership.
+  MCSymbolizer *
+  createMCSymbolizer(StringRef TT, LLVMOpInfoCallback GetOpInfo,
+                     LLVMSymbolLookupCallback SymbolLookUp, void *DisInfo,
+                     MCContext *Ctx,
+                     std::unique_ptr<MCRelocationInfo> &&RelInfo) const {
+    MCSymbolizerCtorTy Fn =
+        MCSymbolizerCtorFn ? MCSymbolizerCtorFn : llvm::createMCSymbolizer;
+    return Fn(Triple(TT), GetOpInfo, SymbolLookUp, DisInfo, Ctx,
+              std::move(RelInfo));
+  }
+
+  /// @}
+};
+
+/// TargetRegistry - Generic interface to target specific features.
+struct TargetRegistry {
+  // FIXME: Make this a namespace, probably just move all the Register*
+  // functions into Target (currently they all just set members on the Target
+  // anyway, and Target friends this class so those functions can...
+  // function).
+  TargetRegistry() = delete;
+
+  class iterator
+      : public std::iterator<std::forward_iterator_tag, Target, ptrdiff_t> {
+    friend struct TargetRegistry;
+
+    const Target *Current = nullptr;
+
+    explicit iterator(Target *T) : Current(T) {}
+
+  public:
+    iterator() = default;
+
+    bool operator==(const iterator &x) const { return Current == x.Current; }
+    bool operator!=(const iterator &x) const { return !operator==(x); }
+
+    // Iterator traversal: forward iteration only
+    iterator &operator++() { // Preincrement
+      assert(Current && "Cannot increment end iterator!");
+      Current = Current->getNext();
+      return *this;
+    }
+    iterator operator++(int) { // Postincrement
+      iterator tmp = *this;
+      ++*this;
+      return tmp;
+    }
+
+    const Target &operator*() const {
+      assert(Current && "Cannot dereference end iterator!");
+      return *Current;
+    }
+
+    const Target *operator->() const { return &operator*(); }
+  };
+
+  /// printRegisteredTargetsForVersion - Print the registered targets
+  /// appropriately for inclusion in a tool's version output.
+  static void printRegisteredTargetsForVersion(raw_ostream &OS);
+
+  /// @name Registry Access
+  /// @{
+
+  static iterator_range<iterator> targets();
+
+  /// lookupTarget - Lookup a target based on a target triple.
+  ///
+  /// \param Triple - The triple to use for finding a target.
+  /// \param Error - On failure, an error string describing why no target was
+  /// found.
+  static const Target *lookupTarget(const std::string &Triple,
+                                    std::string &Error);
+
+  /// lookupTarget - Lookup a target based on an architecture name
+  /// and a target triple.  If the architecture name is non-empty,
+  /// then the lookup is done by architecture.  Otherwise, the target
+  /// triple is used.
+  ///
+  /// \param ArchName - The architecture to use for finding a target.
+  /// \param TheTriple - The triple to use for finding a target.  The
+  /// triple is updated with canonical architecture name if a lookup
+  /// by architecture is done.
+  /// \param Error - On failure, an error string describing why no target was
+  /// found.
+  static const Target *lookupTarget(const std::string &ArchName,
+                                    Triple &TheTriple, std::string &Error);
+
+  /// @}
+  /// @name Target Registration
+  /// @{
+
+  /// RegisterTarget - Register the given target. Attempts to register a
+  /// target which has already been registered will be ignored.
+  ///
+  /// Clients are responsible for ensuring that registration doesn't occur
+  /// while another thread is attempting to access the registry. Typically
+  /// this is done by initializing all targets at program startup.
+  ///
+  /// @param T - The target being registered.
+  /// @param Name - The target name. This should be a static string.
+  /// @param ShortDesc - A short target description. This should be a static
+  /// string.
+  /// @param BackendName - The name of the backend. This should be a static
+  /// string that is the same for all targets that share a backend
+  /// implementation and must match the name used in the 'def X : Target ...' in
+  /// TableGen.
+  /// @param ArchMatchFn - The arch match checking function for this target.
+  /// @param HasJIT - Whether the target supports JIT code
+  /// generation.
+  static void RegisterTarget(Target &T, const char *Name, const char *ShortDesc,
+                             const char *BackendName,
+                             Target::ArchMatchFnTy ArchMatchFn,
+                             bool HasJIT = false);
+
+  /// RegisterMCAsmInfo - Register a MCAsmInfo implementation for the
+  /// given target.
+  ///
+  /// Clients are responsible for ensuring that registration doesn't occur
+  /// while another thread is attempting to access the registry. Typically
+  /// this is done by initializing all targets at program startup.
+  ///
+  /// @param T - The target being registered.
+  /// @param Fn - A function to construct a MCAsmInfo for the target.
+  static void RegisterMCAsmInfo(Target &T, Target::MCAsmInfoCtorFnTy Fn) {
+    T.MCAsmInfoCtorFn = Fn;
+  }
+
+  /// RegisterMCInstrInfo - Register a MCInstrInfo implementation for the
+  /// given target.
+  ///
+  /// Clients are responsible for ensuring that registration doesn't occur
+  /// while another thread is attempting to access the registry. Typically
+  /// this is done by initializing all targets at program startup.
+  ///
+  /// @param T - The target being registered.
+  /// @param Fn - A function to construct a MCInstrInfo for the target.
+  static void RegisterMCInstrInfo(Target &T, Target::MCInstrInfoCtorFnTy Fn) {
+    T.MCInstrInfoCtorFn = Fn;
+  }
+
+  /// RegisterMCInstrAnalysis - Register a MCInstrAnalysis implementation for
+  /// the given target.
+  static void RegisterMCInstrAnalysis(Target &T,
+                                      Target::MCInstrAnalysisCtorFnTy Fn) {
+    T.MCInstrAnalysisCtorFn = Fn;
+  }
+
+  /// RegisterMCRegInfo - Register a MCRegisterInfo implementation for the
+  /// given target.
+  ///
+  /// Clients are responsible for ensuring that registration doesn't occur
+  /// while another thread is attempting to access the registry. Typically
+  /// this is done by initializing all targets at program startup.
+  ///
+  /// @param T - The target being registered.
+  /// @param Fn - A function to construct a MCRegisterInfo for the target.
+  static void RegisterMCRegInfo(Target &T, Target::MCRegInfoCtorFnTy Fn) {
+    T.MCRegInfoCtorFn = Fn;
+  }
+
+  /// RegisterMCSubtargetInfo - Register a MCSubtargetInfo implementation for
+  /// the given target.
+  ///
+  /// Clients are responsible for ensuring that registration doesn't occur
+  /// while another thread is attempting to access the registry. Typically
+  /// this is done by initializing all targets at program startup.
+  ///
+  /// @param T - The target being registered.
+  /// @param Fn - A function to construct a MCSubtargetInfo for the target.
+  static void RegisterMCSubtargetInfo(Target &T,
+                                      Target::MCSubtargetInfoCtorFnTy Fn) {
+    T.MCSubtargetInfoCtorFn = Fn;
+  }
+
+  /// RegisterTargetMachine - Register a TargetMachine implementation for the
+  /// given target.
+  ///
+  /// Clients are responsible for ensuring that registration doesn't occur
+  /// while another thread is attempting to access the registry. Typically
+  /// this is done by initializing all targets at program startup.
+  ///
+  /// @param T - The target being registered.
+  /// @param Fn - A function to construct a TargetMachine for the target.
+  static void RegisterTargetMachine(Target &T, Target::TargetMachineCtorTy Fn) {
+    T.TargetMachineCtorFn = Fn;
+  }
+
+  /// RegisterMCAsmBackend - Register a MCAsmBackend implementation for the
+  /// given target.
+  ///
+  /// Clients are responsible for ensuring that registration doesn't occur
+  /// while another thread is attempting to access the registry. Typically
+  /// this is done by initializing all targets at program startup.
+  ///
+  /// @param T - The target being registered.
+  /// @param Fn - A function to construct an AsmBackend for the target.
+  static void RegisterMCAsmBackend(Target &T, Target::MCAsmBackendCtorTy Fn) {
+    T.MCAsmBackendCtorFn = Fn;
+  }
+
+  /// RegisterMCAsmParser - Register a MCTargetAsmParser implementation for
+  /// the given target.
+  ///
+  /// Clients are responsible for ensuring that registration doesn't occur
+  /// while another thread is attempting to access the registry. Typically
+  /// this is done by initializing all targets at program startup.
+  ///
+  /// @param T - The target being registered.
+  /// @param Fn - A function to construct an MCTargetAsmParser for the target.
+  static void RegisterMCAsmParser(Target &T, Target::MCAsmParserCtorTy Fn) {
+    T.MCAsmParserCtorFn = Fn;
+  }
+
+  /// RegisterAsmPrinter - Register an AsmPrinter implementation for the given
+  /// target.
+  ///
+  /// Clients are responsible for ensuring that registration doesn't occur
+  /// while another thread is attempting to access the registry. Typically
+  /// this is done by initializing all targets at program startup.
+  ///
+  /// @param T - The target being registered.
+  /// @param Fn - A function to construct an AsmPrinter for the target.
+  static void RegisterAsmPrinter(Target &T, Target::AsmPrinterCtorTy Fn) {
+    T.AsmPrinterCtorFn = Fn;
+  }
+
+  /// RegisterMCDisassembler - Register a MCDisassembler implementation for
+  /// the given target.
+  ///
+  /// Clients are responsible for ensuring that registration doesn't occur
+  /// while another thread is attempting to access the registry. Typically
+  /// this is done by initializing all targets at program startup.
+  ///
+  /// @param T - The target being registered.
+  /// @param Fn - A function to construct an MCDisassembler for the target.
+  static void RegisterMCDisassembler(Target &T,
+                                     Target::MCDisassemblerCtorTy Fn) {
+    T.MCDisassemblerCtorFn = Fn;
+  }
+
+  /// RegisterMCInstPrinter - Register a MCInstPrinter implementation for the
+  /// given target.
+  ///
+  /// Clients are responsible for ensuring that registration doesn't occur
+  /// while another thread is attempting to access the registry. Typically
+  /// this is done by initializing all targets at program startup.
+  ///
+  /// @param T - The target being registered.
+  /// @param Fn - A function to construct an MCInstPrinter for the target.
+  static void RegisterMCInstPrinter(Target &T, Target::MCInstPrinterCtorTy Fn) {
+    T.MCInstPrinterCtorFn = Fn;
+  }
+
+  /// RegisterMCCodeEmitter - Register a MCCodeEmitter implementation for the
+  /// given target.
+  ///
+  /// Clients are responsible for ensuring that registration doesn't occur
+  /// while another thread is attempting to access the registry. Typically
+  /// this is done by initializing all targets at program startup.
+  ///
+  /// @param T - The target being registered.
+  /// @param Fn - A function to construct an MCCodeEmitter for the target.
+  static void RegisterMCCodeEmitter(Target &T, Target::MCCodeEmitterCtorTy Fn) {
+    T.MCCodeEmitterCtorFn = Fn;
+  }
+
+  static void RegisterCOFFStreamer(Target &T, Target::COFFStreamerCtorTy Fn) {
+    T.COFFStreamerCtorFn = Fn;
+  }
+
+  static void RegisterMachOStreamer(Target &T, Target::MachOStreamerCtorTy Fn) {
+    T.MachOStreamerCtorFn = Fn;
+  }
+
+  static void RegisterELFStreamer(Target &T, Target::ELFStreamerCtorTy Fn) {
+    T.ELFStreamerCtorFn = Fn;
+  }
+
+  static void RegisterWasmStreamer(Target &T, Target::WasmStreamerCtorTy Fn) {
+    T.WasmStreamerCtorFn = Fn;
+  }
+
+  static void RegisterNullTargetStreamer(Target &T,
+                                         Target::NullTargetStreamerCtorTy Fn) {
+    T.NullTargetStreamerCtorFn = Fn;
+  }
+
+  static void RegisterAsmTargetStreamer(Target &T,
+                                        Target::AsmTargetStreamerCtorTy Fn) {
+    T.AsmTargetStreamerCtorFn = Fn;
+  }
+
+  static void
+  RegisterObjectTargetStreamer(Target &T,
+                               Target::ObjectTargetStreamerCtorTy Fn) {
+    T.ObjectTargetStreamerCtorFn = Fn;
+  }
+
+  /// RegisterMCRelocationInfo - Register an MCRelocationInfo
+  /// implementation for the given target.
+  ///
+  /// Clients are responsible for ensuring that registration doesn't occur
+  /// while another thread is attempting to access the registry. Typically
+  /// this is done by initializing all targets at program startup.
+  ///
+  /// @param T - The target being registered.
+  /// @param Fn - A function to construct an MCRelocationInfo for the target.
+  static void RegisterMCRelocationInfo(Target &T,
+                                       Target::MCRelocationInfoCtorTy Fn) {
+    T.MCRelocationInfoCtorFn = Fn;
+  }
+
+  /// RegisterMCSymbolizer - Register an MCSymbolizer
+  /// implementation for the given target.
+  ///
+  /// Clients are responsible for ensuring that registration doesn't occur
+  /// while another thread is attempting to access the registry. Typically
+  /// this is done by initializing all targets at program startup.
+  ///
+  /// @param T - The target being registered.
+  /// @param Fn - A function to construct an MCSymbolizer for the target.
+  static void RegisterMCSymbolizer(Target &T, Target::MCSymbolizerCtorTy Fn) {
+    T.MCSymbolizerCtorFn = Fn;
+  }
+
+  /// @}
+};
+
+//===--------------------------------------------------------------------===//
+
+/// RegisterTarget - Helper template for registering a target, for use in the
+/// target's initialization function. Usage:
+///
+///
+/// Target &getTheFooTarget() { // The global target instance.
+///   static Target TheFooTarget;
+///   return TheFooTarget;
+/// }
+/// extern "C" void LLVMInitializeFooTargetInfo() {
+///   RegisterTarget<Triple::foo> X(getTheFooTarget(), "foo", "Foo
+///   description", "Foo" /* Backend Name */);
+/// }
+template <Triple::ArchType TargetArchType = Triple::UnknownArch,
+          bool HasJIT = false>
+struct RegisterTarget {
+  RegisterTarget(Target &T, const char *Name, const char *Desc,
+                 const char *BackendName) {
+    TargetRegistry::RegisterTarget(T, Name, Desc, BackendName, &getArchMatch,
+                                   HasJIT);
+  }
+
+  static bool getArchMatch(Triple::ArchType Arch) {
+    return Arch == TargetArchType;
+  }
+};
+
+/// RegisterMCAsmInfo - Helper template for registering a target assembly info
+/// implementation.  This invokes the static "Create" method on the class to
+/// actually do the construction.  Usage:
+///
+/// extern "C" void LLVMInitializeFooTarget() {
+///   extern Target TheFooTarget;
+///   RegisterMCAsmInfo<FooMCAsmInfo> X(TheFooTarget);
+/// }
+template <class MCAsmInfoImpl> struct RegisterMCAsmInfo {
+  RegisterMCAsmInfo(Target &T) {
+    TargetRegistry::RegisterMCAsmInfo(T, &Allocator);
+  }
+
+private:
+  static MCAsmInfo *Allocator(const MCRegisterInfo & /*MRI*/, const Triple &TT,
+                              const MCTargetOptions &Options) {
+    return new MCAsmInfoImpl(TT, Options);
+  }
+};
+
+/// RegisterMCAsmInfoFn - Helper template for registering a target assembly info
+/// implementation.  This invokes the specified function to do the
+/// construction.  Usage:
+///
+/// extern "C" void LLVMInitializeFooTarget() {
+///   extern Target TheFooTarget;
+///   RegisterMCAsmInfoFn X(TheFooTarget, TheFunction);
+/// }
+struct RegisterMCAsmInfoFn {
+  RegisterMCAsmInfoFn(Target &T, Target::MCAsmInfoCtorFnTy Fn) {
+    TargetRegistry::RegisterMCAsmInfo(T, Fn);
+  }
+};
+
+/// RegisterMCInstrInfo - Helper template for registering a target instruction
+/// info implementation.  This invokes the static "Create" method on the class
+/// to actually do the construction.  Usage:
+///
+/// extern "C" void LLVMInitializeFooTarget() {
+///   extern Target TheFooTarget;
+///   RegisterMCInstrInfo<FooMCInstrInfo> X(TheFooTarget);
+/// }
+template <class MCInstrInfoImpl> struct RegisterMCInstrInfo {
+  RegisterMCInstrInfo(Target &T) {
+    TargetRegistry::RegisterMCInstrInfo(T, &Allocator);
+  }
+
+private:
+  static MCInstrInfo *Allocator() { return new MCInstrInfoImpl(); }
+};
+
+/// RegisterMCInstrInfoFn - Helper template for registering a target
+/// instruction info implementation.  This invokes the specified function to
+/// do the construction.  Usage:
+///
+/// extern "C" void LLVMInitializeFooTarget() {
+///   extern Target TheFooTarget;
+///   RegisterMCInstrInfoFn X(TheFooTarget, TheFunction);
+/// }
+struct RegisterMCInstrInfoFn {
+  RegisterMCInstrInfoFn(Target &T, Target::MCInstrInfoCtorFnTy Fn) {
+    TargetRegistry::RegisterMCInstrInfo(T, Fn);
+  }
+};
+
+/// RegisterMCInstrAnalysis - Helper template for registering a target
+/// instruction analyzer implementation.  This invokes the static "Create"
+/// method on the class to actually do the construction.  Usage:
+///
+/// extern "C" void LLVMInitializeFooTarget() {
+///   extern Target TheFooTarget;
+///   RegisterMCInstrAnalysis<FooMCInstrAnalysis> X(TheFooTarget);
+/// }
+template <class MCInstrAnalysisImpl> struct RegisterMCInstrAnalysis {
+  RegisterMCInstrAnalysis(Target &T) {
+    TargetRegistry::RegisterMCInstrAnalysis(T, &Allocator);
+  }
+
+private:
+  static MCInstrAnalysis *Allocator(const MCInstrInfo *Info) {
+    return new MCInstrAnalysisImpl(Info);
+  }
+};
+
+/// RegisterMCInstrAnalysisFn - Helper template for registering a target
+/// instruction analyzer implementation.  This invokes the specified function
+/// to do the construction.  Usage:
+///
+/// extern "C" void LLVMInitializeFooTarget() {
+///   extern Target TheFooTarget;
+///   RegisterMCInstrAnalysisFn X(TheFooTarget, TheFunction);
+/// }
+struct RegisterMCInstrAnalysisFn {
+  RegisterMCInstrAnalysisFn(Target &T, Target::MCInstrAnalysisCtorFnTy Fn) {
+    TargetRegistry::RegisterMCInstrAnalysis(T, Fn);
+  }
+};
+
+/// RegisterMCRegInfo - Helper template for registering a target register info
+/// implementation.  This invokes the static "Create" method on the class to
+/// actually do the construction.  Usage:
+///
+/// extern "C" void LLVMInitializeFooTarget() {
+///   extern Target TheFooTarget;
+///   RegisterMCRegInfo<FooMCRegInfo> X(TheFooTarget);
+/// }
+template <class MCRegisterInfoImpl> struct RegisterMCRegInfo {
+  RegisterMCRegInfo(Target &T) {
+    TargetRegistry::RegisterMCRegInfo(T, &Allocator);
+  }
+
+private:
+  static MCRegisterInfo *Allocator(const Triple & /*TT*/) {
+    return new MCRegisterInfoImpl();
+  }
+};
+
+/// RegisterMCRegInfoFn - Helper template for registering a target register
+/// info implementation.  This invokes the specified function to do the
+/// construction.  Usage:
+///
+/// extern "C" void LLVMInitializeFooTarget() {
+///   extern Target TheFooTarget;
+///   RegisterMCRegInfoFn X(TheFooTarget, TheFunction);
+/// }
+struct RegisterMCRegInfoFn {
+  RegisterMCRegInfoFn(Target &T, Target::MCRegInfoCtorFnTy Fn) {
+    TargetRegistry::RegisterMCRegInfo(T, Fn);
+  }
+};
+
+/// RegisterMCSubtargetInfo - Helper template for registering a target
+/// subtarget info implementation.  This invokes the static "Create" method
+/// on the class to actually do the construction.  Usage:
+///
+/// extern "C" void LLVMInitializeFooTarget() {
+///   extern Target TheFooTarget;
+///   RegisterMCSubtargetInfo<FooMCSubtargetInfo> X(TheFooTarget);
+/// }
+template <class MCSubtargetInfoImpl> struct RegisterMCSubtargetInfo {
+  RegisterMCSubtargetInfo(Target &T) {
+    TargetRegistry::RegisterMCSubtargetInfo(T, &Allocator);
+  }
+
+private:
+  static MCSubtargetInfo *Allocator(const Triple & /*TT*/, StringRef /*CPU*/,
+                                    StringRef /*FS*/) {
+    return new MCSubtargetInfoImpl();
+  }
+};
+
+/// RegisterMCSubtargetInfoFn - Helper template for registering a target
+/// subtarget info implementation.  This invokes the specified function to
+/// do the construction.  Usage:
+///
+/// extern "C" void LLVMInitializeFooTarget() {
+///   extern Target TheFooTarget;
+///   RegisterMCSubtargetInfoFn X(TheFooTarget, TheFunction);
+/// }
+struct RegisterMCSubtargetInfoFn {
+  RegisterMCSubtargetInfoFn(Target &T, Target::MCSubtargetInfoCtorFnTy Fn) {
+    TargetRegistry::RegisterMCSubtargetInfo(T, Fn);
+  }
+};
+
+/// RegisterTargetMachine - Helper template for registering a target machine
+/// implementation, for use in the target machine initialization
+/// function. Usage:
+///
+/// extern "C" void LLVMInitializeFooTarget() {
+///   extern Target TheFooTarget;
+///   RegisterTargetMachine<FooTargetMachine> X(TheFooTarget);
+/// }
+template <class TargetMachineImpl> struct RegisterTargetMachine {
+  RegisterTargetMachine(Target &T) {
+    TargetRegistry::RegisterTargetMachine(T, &Allocator);
+  }
+
+private:
+  static TargetMachine *
+  Allocator(const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
+            const TargetOptions &Options, Optional<Reloc::Model> RM,
+            Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT) {
+    return new TargetMachineImpl(T, TT, CPU, FS, Options, RM, CM, OL, JIT);
+  }
+};
+
+/// RegisterMCAsmBackend - Helper template for registering a target specific
+/// assembler backend. Usage:
+///
+/// extern "C" void LLVMInitializeFooMCAsmBackend() {
+///   extern Target TheFooTarget;
+///   RegisterMCAsmBackend<FooAsmLexer> X(TheFooTarget);
+/// }
+template <class MCAsmBackendImpl> struct RegisterMCAsmBackend {
+  RegisterMCAsmBackend(Target &T) {
+    TargetRegistry::RegisterMCAsmBackend(T, &Allocator);
+  }
+
+private:
+  static MCAsmBackend *Allocator(const Target &T, const MCSubtargetInfo &STI,
+                                 const MCRegisterInfo &MRI,
+                                 const MCTargetOptions &Options) {
+    return new MCAsmBackendImpl(T, STI, MRI);
+  }
+};
+
+/// RegisterMCAsmParser - Helper template for registering a target specific
+/// assembly parser, for use in the target machine initialization
+/// function. Usage:
+///
+/// extern "C" void LLVMInitializeFooMCAsmParser() {
+///   extern Target TheFooTarget;
+///   RegisterMCAsmParser<FooAsmParser> X(TheFooTarget);
+/// }
+template <class MCAsmParserImpl> struct RegisterMCAsmParser {
+  RegisterMCAsmParser(Target &T) {
+    TargetRegistry::RegisterMCAsmParser(T, &Allocator);
+  }
+
+private:
+  static MCTargetAsmParser *Allocator(const MCSubtargetInfo &STI,
+                                      MCAsmParser &P, const MCInstrInfo &MII,
+                                      const MCTargetOptions &Options) {
+    return new MCAsmParserImpl(STI, P, MII, Options);
+  }
+};
+
+/// RegisterAsmPrinter - Helper template for registering a target specific
+/// assembly printer, for use in the target machine initialization
+/// function. Usage:
+///
+/// extern "C" void LLVMInitializeFooAsmPrinter() {
+///   extern Target TheFooTarget;
+///   RegisterAsmPrinter<FooAsmPrinter> X(TheFooTarget);
+/// }
+template <class AsmPrinterImpl> struct RegisterAsmPrinter {
+  RegisterAsmPrinter(Target &T) {
+    TargetRegistry::RegisterAsmPrinter(T, &Allocator);
+  }
+
+private:
+  static AsmPrinter *Allocator(TargetMachine &TM,
+                               std::unique_ptr<MCStreamer> &&Streamer) {
+    return new AsmPrinterImpl(TM, std::move(Streamer));
+  }
+};
+
+/// RegisterMCCodeEmitter - Helper template for registering a target specific
+/// machine code emitter, for use in the target initialization
+/// function. Usage:
+///
+/// extern "C" void LLVMInitializeFooMCCodeEmitter() {
+///   extern Target TheFooTarget;
+///   RegisterMCCodeEmitter<FooCodeEmitter> X(TheFooTarget);
+/// }
+template <class MCCodeEmitterImpl> struct RegisterMCCodeEmitter {
+  RegisterMCCodeEmitter(Target &T) {
+    TargetRegistry::RegisterMCCodeEmitter(T, &Allocator);
+  }
+
+private:
+  static MCCodeEmitter *Allocator(const MCInstrInfo & /*II*/,
+                                  const MCRegisterInfo & /*MRI*/,
+                                  MCContext & /*Ctx*/) {
+    return new MCCodeEmitterImpl();
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_TARGETREGISTRY_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Threading.h b/binaryen/third_party/llvm-project/include/llvm/Support/Threading.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Threading.h
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/TypeSize.h b/binaryen/third_party/llvm-project/include/llvm/Support/TypeSize.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/TypeSize.h
@@ -0,0 +1,201 @@
+//===- TypeSize.h - Wrapper around type sizes -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a struct that can be used to query the size of IR types
+// which may be scalable vectors. It provides convenience operators so that
+// it can be used in much the same way as a single scalar value.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_TYPESIZE_H
+#define LLVM_SUPPORT_TYPESIZE_H
+
+#include <cassert>
+#include <tuple>
+
+namespace llvm {
+
+class ElementCount {
+public:
+  unsigned Min;  // Minimum number of vector elements.
+  bool Scalable; // If true, NumElements is a multiple of 'Min' determined
+                 // at runtime rather than compile time.
+
+  ElementCount(unsigned Min, bool Scalable)
+  : Min(Min), Scalable(Scalable) {}
+
+  ElementCount operator*(unsigned RHS) {
+    return { Min * RHS, Scalable };
+  }
+  ElementCount operator/(unsigned RHS) {
+    return { Min / RHS, Scalable };
+  }
+
+  bool operator==(const ElementCount& RHS) const {
+    return Min == RHS.Min && Scalable == RHS.Scalable;
+  }
+  bool operator!=(const ElementCount& RHS) const {
+    return !(*this == RHS);
+  }
+};
+
+// This class is used to represent the size of types. If the type is of fixed
+// size, it will represent the exact size. If the type is a scalable vector,
+// it will represent the known minimum size.
+class TypeSize {
+  uint64_t MinSize;   // The known minimum size.
+  bool IsScalable;    // If true, then the runtime size is an integer multiple
+                      // of MinSize.
+
+public:
+  constexpr TypeSize(uint64_t MinSize, bool Scalable)
+    : MinSize(MinSize), IsScalable(Scalable) {}
+
+  static constexpr TypeSize Fixed(uint64_t Size) {
+    return TypeSize(Size, /*IsScalable=*/false);
+  }
+
+  static constexpr TypeSize Scalable(uint64_t MinSize) {
+    return TypeSize(MinSize, /*IsScalable=*/true);
+  }
+
+  // Scalable vector types with the same minimum size as a fixed size type are
+  // not guaranteed to be the same size at runtime, so they are never
+  // considered to be equal.
+  friend bool operator==(const TypeSize &LHS, const TypeSize &RHS) {
+    return std::tie(LHS.MinSize, LHS.IsScalable) ==
+           std::tie(RHS.MinSize, RHS.IsScalable);
+  }
+
+  friend bool operator!=(const TypeSize &LHS, const TypeSize &RHS) {
+    return !(LHS == RHS);
+  }
+
+  // For many cases, size ordering between scalable and fixed size types cannot
+  // be determined at compile time, so such comparisons aren't allowed.
+  //
+  // e.g. <vscale x 2 x i16> could be bigger than <4 x i32> with a runtime
+  // vscale >= 5, equal sized with a vscale of 4, and smaller with
+  // a vscale <= 3.
+  //
+  // If the scalable flags match, just perform the requested comparison
+  // between the minimum sizes.
+  friend bool operator<(const TypeSize &LHS, const TypeSize &RHS) {
+    assert(LHS.IsScalable == RHS.IsScalable &&
+           "Ordering comparison of scalable and fixed types");
+
+    return LHS.MinSize < RHS.MinSize;
+  }
+
+  friend bool operator>(const TypeSize &LHS, const TypeSize &RHS) {
+    return RHS < LHS;
+  }
+
+  friend bool operator<=(const TypeSize &LHS, const TypeSize &RHS) {
+    return !(RHS < LHS);
+  }
+
+  friend bool operator>=(const TypeSize &LHS, const TypeSize& RHS) {
+    return !(LHS < RHS);
+  }
+
+  // Convenience operators to obtain relative sizes independently of
+  // the scalable flag.
+  TypeSize operator*(unsigned RHS) const {
+    return { MinSize * RHS, IsScalable };
+  }
+
+  friend TypeSize operator*(const unsigned LHS, const TypeSize &RHS) {
+    return { LHS * RHS.MinSize, RHS.IsScalable };
+  }
+
+  TypeSize operator/(unsigned RHS) const {
+    return { MinSize / RHS, IsScalable };
+  }
+
+  // Return the minimum size with the assumption that the size is exact.
+  // Use in places where a scalable size doesn't make sense (e.g. non-vector
+  // types, or vectors in backends which don't support scalable vectors).
+  uint64_t getFixedSize() const {
+    assert(!IsScalable && "Request for a fixed size on a scalable object");
+    return MinSize;
+  }
+
+  // Return the known minimum size. Use in places where the scalable property
+  // doesn't matter (e.g. determining alignment) or in conjunction with the
+  // isScalable method below.
+  uint64_t getKnownMinSize() const {
+    return MinSize;
+  }
+
+  // Return whether or not the size is scalable.
+  bool isScalable() const {
+    return IsScalable;
+  }
+
+  // Casts to a uint64_t if this is a fixed-width size.
+  //
+  // NOTE: This interface is obsolete and will be removed in a future version
+  // of LLVM in favour of calling getFixedSize() directly.
+  operator uint64_t() const {
+    return getFixedSize();
+  }
+
+  // Additional convenience operators needed to avoid ambiguous parses.
+  // TODO: Make uint64_t the default operator?
+  TypeSize operator*(uint64_t RHS) const {
+    return { MinSize * RHS, IsScalable };
+  }
+
+  TypeSize operator*(int RHS) const {
+    return { MinSize * RHS, IsScalable };
+  }
+
+  TypeSize operator*(int64_t RHS) const {
+    return { MinSize * RHS, IsScalable };
+  }
+
+  friend TypeSize operator*(const uint64_t LHS, const TypeSize &RHS) {
+    return { LHS * RHS.MinSize, RHS.IsScalable };
+  }
+
+  friend TypeSize operator*(const int LHS, const TypeSize &RHS) {
+    return { LHS * RHS.MinSize, RHS.IsScalable };
+  }
+
+  friend TypeSize operator*(const int64_t LHS, const TypeSize &RHS) {
+    return { LHS * RHS.MinSize, RHS.IsScalable };
+  }
+
+  TypeSize operator/(uint64_t RHS) const {
+    return { MinSize / RHS, IsScalable };
+  }
+
+  TypeSize operator/(int RHS) const {
+    return { MinSize / RHS, IsScalable };
+  }
+
+  TypeSize operator/(int64_t RHS) const {
+    return { MinSize / RHS, IsScalable };
+  }
+};
+
+/// Returns a TypeSize with a known minimum size that is the next integer
+/// (mod 2**64) that is greater than or equal to \p Value and is a multiple
+/// of \p Align. \p Align must be non-zero.
+///
+/// Similar to the alignTo functions in MathExtras.h
+inline TypeSize alignTo(TypeSize Size, uint64_t Align) {
+  assert(Align != 0u && "Align must be non-zero");
+  return {(Size.getKnownMinSize() + Align - 1) / Align * Align,
+          Size.isScalable()};
+}
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_TypeSize_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/Unicode.h b/binaryen/third_party/llvm-project/include/llvm/Support/Unicode.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/Unicode.h
@@ -0,0 +1,70 @@
+//===- llvm/Support/Unicode.h - Unicode character properties  -*- C++ -*-=====//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines functions that allow querying certain properties of Unicode
+// characters.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_UNICODE_H
+#define LLVM_SUPPORT_UNICODE_H
+
+namespace llvm {
+class StringRef;
+
+namespace sys {
+namespace unicode {
+
+enum ColumnWidthErrors {
+  ErrorInvalidUTF8 = -2,
+  ErrorNonPrintableCharacter = -1
+};
+
+/// Determines if a character is likely to be displayed correctly on the
+/// terminal. Exact implementation would have to depend on the specific
+/// terminal, so we define the semantic that should be suitable for generic case
+/// of a terminal capable to output Unicode characters.
+///
+/// All characters from the Unicode code point range are considered printable
+/// except for:
+///   * C0 and C1 control character ranges;
+///   * default ignorable code points as per 5.21 of
+///     http://www.unicode.org/versions/Unicode6.2.0/UnicodeStandard-6.2.pdf
+///     except for U+00AD SOFT HYPHEN, as it's actually displayed on most
+///     terminals;
+///   * format characters (category = Cf);
+///   * surrogates (category = Cs);
+///   * unassigned characters (category = Cn).
+/// \return true if the character is considered printable.
+bool isPrintable(int UCS);
+
+/// Gets the number of positions the UTF8-encoded \p Text is likely to occupy
+/// when output on a terminal ("character width"). This depends on the
+/// implementation of the terminal, and there's no standard definition of
+/// character width.
+///
+/// The implementation defines it in a way that is expected to be compatible
+/// with a generic Unicode-capable terminal.
+///
+/// \return Character width:
+///   * ErrorNonPrintableCharacter (-1) if \p Text contains non-printable
+///     characters (as identified by isPrintable);
+///   * 0 for each non-spacing and enclosing combining mark;
+///   * 2 for each CJK character excluding halfwidth forms;
+///   * 1 for each of the remaining characters.
+int columnWidthUTF8(StringRef Text);
+
+/// Fold input unicode character according the Simple unicode case folding
+/// rules.
+int foldCharSimple(int C);
+
+} // namespace unicode
+} // namespace sys
+} // namespace llvm
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/UnicodeCharRanges.h b/binaryen/third_party/llvm-project/include/llvm/Support/UnicodeCharRanges.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/UnicodeCharRanges.h
@@ -0,0 +1,103 @@
+//===--- UnicodeCharRanges.h - Types and functions for character ranges ---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_SUPPORT_UNICODECHARRANGES_H
+#define LLVM_SUPPORT_UNICODECHARRANGES_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+#define DEBUG_TYPE "unicode"
+
+namespace llvm {
+namespace sys {
+
+/// Represents a closed range of Unicode code points [Lower, Upper].
+struct UnicodeCharRange {
+  uint32_t Lower;
+  uint32_t Upper;
+};
+
+inline bool operator<(uint32_t Value, UnicodeCharRange Range) {
+  return Value < Range.Lower;
+}
+inline bool operator<(UnicodeCharRange Range, uint32_t Value) {
+  return Range.Upper < Value;
+}
+
+/// Holds a reference to an ordered array of UnicodeCharRange and allows
+/// to quickly check if a code point is contained in the set represented by this
+/// array.
+class UnicodeCharSet {
+public:
+  typedef ArrayRef<UnicodeCharRange> CharRanges;
+
+  /// Constructs a UnicodeCharSet instance from an array of
+  /// UnicodeCharRanges.
+  ///
+  /// Array pointed by \p Ranges should have the lifetime at least as long as
+  /// the UnicodeCharSet instance, and should not change. Array is validated by
+  /// the constructor, so it makes sense to create as few UnicodeCharSet
+  /// instances per each array of ranges, as possible.
+#ifdef NDEBUG
+
+  // FIXME: This could use constexpr + static_assert. This way we
+  // may get rid of NDEBUG in this header. Unfortunately there are some
+  // problems to get this working with MSVC 2013. Change this when
+  // the support for MSVC 2013 is dropped.
+  constexpr UnicodeCharSet(CharRanges Ranges) : Ranges(Ranges) {}
+#else
+  UnicodeCharSet(CharRanges Ranges) : Ranges(Ranges) {
+    assert(rangesAreValid());
+  }
+#endif
+
+  /// Returns true if the character set contains the Unicode code point
+  /// \p C.
+  bool contains(uint32_t C) const {
+    return std::binary_search(Ranges.begin(), Ranges.end(), C);
+  }
+
+private:
+  /// Returns true if each of the ranges is a proper closed range
+  /// [min, max], and if the ranges themselves are ordered and non-overlapping.
+  bool rangesAreValid() const {
+    uint32_t Prev = 0;
+    for (CharRanges::const_iterator I = Ranges.begin(), E = Ranges.end();
+         I != E; ++I) {
+      if (I != Ranges.begin() && Prev >= I->Lower) {
+        LLVM_DEBUG(dbgs() << "Upper bound 0x");
+        LLVM_DEBUG(dbgs().write_hex(Prev));
+        LLVM_DEBUG(dbgs() << " should be less than succeeding lower bound 0x");
+        LLVM_DEBUG(dbgs().write_hex(I->Lower) << "\n");
+        return false;
+      }
+      if (I->Upper < I->Lower) {
+        LLVM_DEBUG(dbgs() << "Upper bound 0x");
+        LLVM_DEBUG(dbgs().write_hex(I->Lower));
+        LLVM_DEBUG(dbgs() << " should not be less than lower bound 0x");
+        LLVM_DEBUG(dbgs().write_hex(I->Upper) << "\n");
+        return false;
+      }
+      Prev = I->Upper;
+    }
+
+    return true;
+  }
+
+  const CharRanges Ranges;
+};
+
+} // namespace sys
+} // namespace llvm
+
+#undef DEBUG_TYPE // "unicode"
+
+#endif // LLVM_SUPPORT_UNICODECHARRANGES_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/WindowsError.h b/binaryen/third_party/llvm-project/include/llvm/Support/WindowsError.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/WindowsError.h
@@ -0,0 +1,18 @@
+//===-- WindowsError.h - Support for mapping windows errors to posix-------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_WINDOWSERROR_H
+#define LLVM_SUPPORT_WINDOWSERROR_H
+
+#include <system_error>
+
+namespace llvm {
+std::error_code mapWindowsError(unsigned EV);
+}
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/WithColor.h b/binaryen/third_party/llvm-project/include/llvm/Support/WithColor.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/WithColor.h
@@ -0,0 +1,118 @@
+//===- WithColor.h ----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_WITHCOLOR_H
+#define LLVM_SUPPORT_WITHCOLOR_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+#if 0 // XXX BINARYEN
+extern cl::OptionCategory ColorCategory;
+#endif
+
+class raw_ostream;
+
+// Symbolic names for various syntax elements.
+enum class HighlightColor {
+  Address,
+  String,
+  Tag,
+  Attribute,
+  Enumerator,
+  Macro,
+  Error,
+  Warning,
+  Note,
+  Remark
+};
+
+/// An RAII object that temporarily switches an output stream to a specific
+/// color.
+class WithColor {
+  raw_ostream &OS;
+  bool DisableColors;
+
+public:
+  /// To be used like this: WithColor(OS, HighlightColor::String) << "text";
+  /// @param OS The output stream
+  /// @param S Symbolic name for syntax element to color
+  /// @param DisableColors Whether to ignore color changes regardless of -color
+  /// and support in OS
+  WithColor(raw_ostream &OS, HighlightColor S, bool DisableColors = false);
+  /// To be used like this: WithColor(OS, raw_ostream::Black) << "text";
+  /// @param OS The output stream
+  /// @param Color ANSI color to use, the special SAVEDCOLOR can be used to
+  /// change only the bold attribute, and keep colors untouched
+  /// @param Bold Bold/brighter text, default false
+  /// @param BG If true, change the background, default: change foreground
+  /// @param DisableColors Whether to ignore color changes regardless of -color
+  /// and support in OS
+  WithColor(raw_ostream &OS,
+            raw_ostream::Colors Color = raw_ostream::SAVEDCOLOR,
+            bool Bold = false, bool BG = false, bool DisableColors = false)
+      : OS(OS), DisableColors(DisableColors) {
+    changeColor(Color, Bold, BG);
+  }
+  ~WithColor();
+
+  raw_ostream &get() { return OS; }
+  operator raw_ostream &() { return OS; }
+  template <typename T> WithColor &operator<<(T &O) {
+    OS << O;
+    return *this;
+  }
+  template <typename T> WithColor &operator<<(const T &O) {
+    OS << O;
+    return *this;
+  }
+
+  /// Convenience method for printing "error: " to stderr.
+  static raw_ostream &error();
+  /// Convenience method for printing "warning: " to stderr.
+  static raw_ostream &warning();
+  /// Convenience method for printing "note: " to stderr.
+  static raw_ostream &note();
+  /// Convenience method for printing "remark: " to stderr.
+  static raw_ostream &remark();
+
+  /// Convenience method for printing "error: " to the given stream.
+  static raw_ostream &error(raw_ostream &OS, StringRef Prefix = "",
+                            bool DisableColors = false);
+  /// Convenience method for printing "warning: " to the given stream.
+  static raw_ostream &warning(raw_ostream &OS, StringRef Prefix = "",
+                              bool DisableColors = false);
+  /// Convenience method for printing "note: " to the given stream.
+  static raw_ostream &note(raw_ostream &OS, StringRef Prefix = "",
+                           bool DisableColors = false);
+  /// Convenience method for printing "remark: " to the given stream.
+  static raw_ostream &remark(raw_ostream &OS, StringRef Prefix = "",
+                             bool DisableColors = false);
+
+  /// Determine whether colors are displayed.
+  bool colorsEnabled();
+
+  /// Change the color of text that will be output from this point forward.
+  /// @param Color ANSI color to use, the special SAVEDCOLOR can be used to
+  /// change only the bold attribute, and keep colors untouched
+  /// @param Bold Bold/brighter text, default false
+  /// @param BG If true, change the background, default: change foreground
+  WithColor &changeColor(raw_ostream::Colors Color, bool Bold = false,
+                         bool BG = false);
+
+  /// Reset the colors to terminal defaults. Call this when you are done
+  /// outputting colored text, or before program exit.
+  WithColor &resetColor();
+};
+
+} // end namespace llvm
+
+#endif // LLVM_LIB_DEBUGINFO_WITHCOLOR_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/X86TargetParser.def b/binaryen/third_party/llvm-project/include/llvm/Support/X86TargetParser.def
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/X86TargetParser.def
@@ -0,0 +1,173 @@
+//===- X86TargetParser.def - X86 target parsing defines ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides defines to build up the X86 target parser's logic.
+//
+//===----------------------------------------------------------------------===//
+
+// NOTE: NO INCLUDE GUARD DESIRED!
+
+#ifndef X86_VENDOR
+#define X86_VENDOR(ENUM, STR)
+#endif
+X86_VENDOR(VENDOR_INTEL, "intel")
+X86_VENDOR(VENDOR_AMD,   "amd")
+#undef X86_VENDOR
+
+// This macro is used to implement CPU types that have an alias. As of now
+// there is only ever one alias.
+#ifndef X86_CPU_TYPE_COMPAT_WITH_ALIAS
+#define X86_CPU_TYPE_COMPAT_WITH_ALIAS(ARCHNAME, ENUM, STR, ALIAS) X86_CPU_TYPE_COMPAT(ARCHNAME, ENUM, STR)
+#endif
+
+// This macro is used for cpu types present in compiler-rt/libgcc.
+#ifndef X86_CPU_TYPE_COMPAT
+#define X86_CPU_TYPE_COMPAT(ARCHNAME, ENUM, STR) X86_CPU_TYPE(ARCHNAME, ENUM)
+#endif
+
+#ifndef X86_CPU_TYPE
+#define X86_CPU_TYPE(ARCHNAME, ENUM)
+#endif
+// The first part of this list must match what is implemented in libgcc and
+// compilert-rt. Clang uses this to know how to implement __builtin_cpu_is.
+X86_CPU_TYPE_COMPAT_WITH_ALIAS("bonnell",       INTEL_BONNELL,       "bonnell", "atom")
+X86_CPU_TYPE_COMPAT           ("core2",         INTEL_CORE2,         "core2")
+X86_CPU_TYPE_COMPAT           ("nehalem",       INTEL_COREI7,        "corei7")
+X86_CPU_TYPE_COMPAT_WITH_ALIAS("amdfam10",      AMDFAM10H,           "amdfam10h", "amdfam10")
+X86_CPU_TYPE_COMPAT_WITH_ALIAS("bdver1",        AMDFAM15H,           "amdfam15h", "amdfam15")
+X86_CPU_TYPE_COMPAT_WITH_ALIAS("silvermont",    INTEL_SILVERMONT,    "silvermont", "slm")
+X86_CPU_TYPE_COMPAT           ("knl",           INTEL_KNL,           "knl")
+X86_CPU_TYPE_COMPAT           ("btver1",        AMD_BTVER1,          "btver1")
+X86_CPU_TYPE_COMPAT           ("btver2",        AMD_BTVER2,          "btver2")
+X86_CPU_TYPE_COMPAT           ("znver1",        AMDFAM17H,           "amdfam17h")
+X86_CPU_TYPE_COMPAT           ("knm",           INTEL_KNM,           "knm")
+X86_CPU_TYPE_COMPAT           ("goldmont",      INTEL_GOLDMONT,      "goldmont")
+X86_CPU_TYPE_COMPAT           ("goldmont-plus", INTEL_GOLDMONT_PLUS, "goldmont-plus")
+X86_CPU_TYPE_COMPAT           ("tremont",       INTEL_TREMONT,       "tremont")
+// Entries below this are not in libgcc/compiler-rt.
+X86_CPU_TYPE                  ("i386",        INTEL_i386)
+X86_CPU_TYPE                  ("i486",        INTEL_i486)
+X86_CPU_TYPE                  ("pentium",     INTEL_PENTIUM)
+X86_CPU_TYPE                  ("pentium-mmx", INTEL_PENTIUM_MMX)
+X86_CPU_TYPE                  ("pentiumpro",  INTEL_PENTIUM_PRO)
+X86_CPU_TYPE                  ("pentium2",    INTEL_PENTIUM_II)
+X86_CPU_TYPE                  ("pentium3",    INTEL_PENTIUM_III)
+X86_CPU_TYPE                  ("pentium4",    INTEL_PENTIUM_IV)
+X86_CPU_TYPE                  ("pentium-m",   INTEL_PENTIUM_M)
+X86_CPU_TYPE                  ("yonah",       INTEL_CORE_DUO)
+X86_CPU_TYPE                  ("nocona",      INTEL_NOCONA)
+X86_CPU_TYPE                  ("prescott",    INTEL_PRESCOTT)
+X86_CPU_TYPE                  ("i486",        AMD_i486)
+X86_CPU_TYPE                  ("pentium",     AMDPENTIUM)
+X86_CPU_TYPE                  ("athlon",      AMD_ATHLON)
+X86_CPU_TYPE                  ("athlon-xp",   AMD_ATHLON_XP)
+X86_CPU_TYPE                  ("k8",          AMD_K8)
+X86_CPU_TYPE                  ("k8-sse3",     AMD_K8SSE3)
+#undef X86_CPU_TYPE_COMPAT_WITH_ALIAS
+#undef X86_CPU_TYPE_COMPAT
+#undef X86_CPU_TYPE
+
+// This macro is used for cpu subtypes present in compiler-rt/libgcc.
+#ifndef X86_CPU_SUBTYPE_COMPAT
+#define X86_CPU_SUBTYPE_COMPAT(ARCHNAME, ENUM, STR) X86_CPU_SUBTYPE(ARCHNAME, ENUM)
+#endif
+
+#ifndef X86_CPU_SUBTYPE
+#define X86_CPU_SUBTYPE(ARCHNAME, ENUM)
+#endif
+
+// The first part of this list must match what is implemented in libgcc and
+// compilert-rt. Clang uses this to know how to implement __builtin_cpu_is.
+X86_CPU_SUBTYPE_COMPAT("nehalem",        INTEL_COREI7_NEHALEM,        "nehalem")
+X86_CPU_SUBTYPE_COMPAT("westmere",       INTEL_COREI7_WESTMERE,       "westmere")
+X86_CPU_SUBTYPE_COMPAT("sandybridge",    INTEL_COREI7_SANDYBRIDGE,    "sandybridge")
+X86_CPU_SUBTYPE_COMPAT("amdfam10",       AMDFAM10H_BARCELONA,         "barcelona")
+X86_CPU_SUBTYPE_COMPAT("amdfam10",       AMDFAM10H_SHANGHAI,          "shanghai")
+X86_CPU_SUBTYPE_COMPAT("amdfam10",       AMDFAM10H_ISTANBUL,          "istanbul")
+X86_CPU_SUBTYPE_COMPAT("bdver1",         AMDFAM15H_BDVER1,            "bdver1")
+X86_CPU_SUBTYPE_COMPAT("bdver2",         AMDFAM15H_BDVER2,            "bdver2")
+X86_CPU_SUBTYPE_COMPAT("bdver3",         AMDFAM15H_BDVER3,            "bdver3")
+X86_CPU_SUBTYPE_COMPAT("bdver4",         AMDFAM15H_BDVER4,            "bdver4")
+X86_CPU_SUBTYPE_COMPAT("znver1",         AMDFAM17H_ZNVER1,            "znver1")
+X86_CPU_SUBTYPE_COMPAT("ivybridge",      INTEL_COREI7_IVYBRIDGE,      "ivybridge")
+X86_CPU_SUBTYPE_COMPAT("haswell",        INTEL_COREI7_HASWELL,        "haswell")
+X86_CPU_SUBTYPE_COMPAT("broadwell",      INTEL_COREI7_BROADWELL,      "broadwell")
+X86_CPU_SUBTYPE_COMPAT("skylake",        INTEL_COREI7_SKYLAKE,        "skylake")
+X86_CPU_SUBTYPE_COMPAT("skylake-avx512", INTEL_COREI7_SKYLAKE_AVX512, "skylake-avx512")
+X86_CPU_SUBTYPE_COMPAT("cannonlake",     INTEL_COREI7_CANNONLAKE,     "cannonlake")
+X86_CPU_SUBTYPE_COMPAT("icelake-client", INTEL_COREI7_ICELAKE_CLIENT, "icelake-client")
+X86_CPU_SUBTYPE_COMPAT("icelake-server", INTEL_COREI7_ICELAKE_SERVER, "icelake-server")
+X86_CPU_SUBTYPE_COMPAT("znver2",         AMDFAM17H_ZNVER2,            "znver2")
+X86_CPU_SUBTYPE_COMPAT("cascadelake",    INTEL_COREI7_CASCADELAKE,    "cascadelake")
+// Entries below this are not in libgcc/compiler-rt.
+X86_CPU_SUBTYPE       ("core2",          INTEL_CORE2_65)
+X86_CPU_SUBTYPE       ("penryn",         INTEL_CORE2_45)
+X86_CPU_SUBTYPE       ("k6",             AMDPENTIUM_K6)
+X86_CPU_SUBTYPE       ("k6-2",           AMDPENTIUM_K62)
+X86_CPU_SUBTYPE       ("k6-3",           AMDPENTIUM_K63)
+X86_CPU_SUBTYPE       ("geode",          AMDPENTIUM_GEODE)
+X86_CPU_SUBTYPE       ("cooperlake",     INTEL_COREI7_COOPERLAKE)
+X86_CPU_SUBTYPE       ("tigerlake",      INTEL_COREI7_TIGERLAKE)
+#undef X86_CPU_SUBTYPE_COMPAT
+#undef X86_CPU_SUBTYPE
+
+
+// This macro is used for cpu types present in compiler-rt/libgcc.
+#ifndef X86_FEATURE_COMPAT
+#define X86_FEATURE_COMPAT(VAL, ENUM, STR) X86_FEATURE(VAL, ENUM)
+#endif
+
+#ifndef X86_FEATURE
+#define X86_FEATURE(VAL, ENUM)
+#endif
+X86_FEATURE_COMPAT( 0, FEATURE_CMOV,            "cmov")
+X86_FEATURE_COMPAT( 1, FEATURE_MMX,             "mmx")
+X86_FEATURE_COMPAT( 2, FEATURE_POPCNT,          "popcnt")
+X86_FEATURE_COMPAT( 3, FEATURE_SSE,             "sse")
+X86_FEATURE_COMPAT( 4, FEATURE_SSE2,            "sse2")
+X86_FEATURE_COMPAT( 5, FEATURE_SSE3,            "sse3")
+X86_FEATURE_COMPAT( 6, FEATURE_SSSE3,           "ssse3")
+X86_FEATURE_COMPAT( 7, FEATURE_SSE4_1,          "sse4.1")
+X86_FEATURE_COMPAT( 8, FEATURE_SSE4_2,          "sse4.2")
+X86_FEATURE_COMPAT( 9, FEATURE_AVX,             "avx")
+X86_FEATURE_COMPAT(10, FEATURE_AVX2,            "avx2")
+X86_FEATURE_COMPAT(11, FEATURE_SSE4_A,          "sse4a")
+X86_FEATURE_COMPAT(12, FEATURE_FMA4,            "fma4")
+X86_FEATURE_COMPAT(13, FEATURE_XOP,             "xop")
+X86_FEATURE_COMPAT(14, FEATURE_FMA,             "fma")
+X86_FEATURE_COMPAT(15, FEATURE_AVX512F,         "avx512f")
+X86_FEATURE_COMPAT(16, FEATURE_BMI,             "bmi")
+X86_FEATURE_COMPAT(17, FEATURE_BMI2,            "bmi2")
+X86_FEATURE_COMPAT(18, FEATURE_AES,             "aes")
+X86_FEATURE_COMPAT(19, FEATURE_PCLMUL,          "pclmul")
+X86_FEATURE_COMPAT(20, FEATURE_AVX512VL,        "avx512vl")
+X86_FEATURE_COMPAT(21, FEATURE_AVX512BW,        "avx512bw")
+X86_FEATURE_COMPAT(22, FEATURE_AVX512DQ,        "avx512dq")
+X86_FEATURE_COMPAT(23, FEATURE_AVX512CD,        "avx512cd")
+X86_FEATURE_COMPAT(24, FEATURE_AVX512ER,        "avx512er")
+X86_FEATURE_COMPAT(25, FEATURE_AVX512PF,        "avx512pf")
+X86_FEATURE_COMPAT(26, FEATURE_AVX512VBMI,      "avx512vbmi")
+X86_FEATURE_COMPAT(27, FEATURE_AVX512IFMA,      "avx512ifma")
+X86_FEATURE_COMPAT(28, FEATURE_AVX5124VNNIW,    "avx5124vnniw")
+X86_FEATURE_COMPAT(29, FEATURE_AVX5124FMAPS,    "avx5124fmaps")
+X86_FEATURE_COMPAT(30, FEATURE_AVX512VPOPCNTDQ, "avx512vpopcntdq")
+X86_FEATURE_COMPAT(31, FEATURE_AVX512VBMI2,     "avx512vbmi2")
+X86_FEATURE_COMPAT(32, FEATURE_GFNI,            "gfni")
+X86_FEATURE_COMPAT(33, FEATURE_VPCLMULQDQ,      "vpclmulqdq")
+X86_FEATURE_COMPAT(34, FEATURE_AVX512VNNI,      "avx512vnni")
+X86_FEATURE_COMPAT(35, FEATURE_AVX512BITALG,    "avx512bitalg")
+X86_FEATURE_COMPAT(36, FEATURE_AVX512BF16,      "avx512bf16")
+// Features below here are not in libgcc/compiler-rt.
+X86_FEATURE       (64, FEATURE_MOVBE)
+X86_FEATURE       (65, FEATURE_ADX)
+X86_FEATURE       (66, FEATURE_EM64T)
+X86_FEATURE       (67, FEATURE_CLFLUSHOPT)
+X86_FEATURE       (68, FEATURE_SHA)
+X86_FEATURE       (69, FEATURE_AVX512VP2INTERSECT)
+#undef X86_FEATURE_COMPAT
+#undef X86_FEATURE
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/YAMLParser.h b/binaryen/third_party/llvm-project/include/llvm/Support/YAMLParser.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/YAMLParser.h
@@ -0,0 +1,619 @@
+//===- YAMLParser.h - Simple YAML parser ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This is a YAML 1.2 parser.
+//
+//  See http://www.yaml.org/spec/1.2/spec.html for the full standard.
+//
+//  This currently does not implement the following:
+//    * Multi-line literal folding.
+//    * Tag resolution.
+//    * UTF-16.
+//    * BOMs anywhere other than the first Unicode scalar value in the file.
+//
+//  The most important class here is Stream. This represents a YAML stream with
+//  0, 1, or many documents.
+//
+//  SourceMgr sm;
+//  StringRef input = getInput();
+//  yaml::Stream stream(input, sm);
+//
+//  for (yaml::document_iterator di = stream.begin(), de = stream.end();
+//       di != de; ++di) {
+//    yaml::Node *n = di->getRoot();
+//    if (n) {
+//      // Do something with n...
+//    } else
+//      break;
+//  }
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_YAMLPARSER_H
+#define LLVM_SUPPORT_YAMLPARSER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/SMLoc.h"
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <map>
+#include <memory>
+#include <string>
+#include <system_error>
+
+namespace llvm {
+
+class MemoryBufferRef;
+class SourceMgr;
+class raw_ostream;
+class Twine;
+
+namespace yaml {
+
+class Document;
+class document_iterator;
+class Node;
+class Scanner;
+struct Token;
+
+/// Dump all the tokens in this stream to OS.
+/// \returns true if there was an error, false otherwise.
+bool dumpTokens(StringRef Input, raw_ostream &);
+
+/// Scans all tokens in input without outputting anything. This is used
+///        for benchmarking the tokenizer.
+/// \returns true if there was an error, false otherwise.
+bool scanTokens(StringRef Input);
+
+/// Escape \a Input for a double quoted scalar; if \p EscapePrintable
+/// is true, all UTF8 sequences will be escaped, if \p EscapePrintable is
+/// false, those UTF8 sequences encoding printable unicode scalars will not be
+/// escaped, but emitted verbatim.
+std::string escape(StringRef Input, bool EscapePrintable = true);
+
+/// This class represents a YAML stream potentially containing multiple
+///        documents.
+class Stream {
+public:
+  /// This keeps a reference to the string referenced by \p Input.
+  Stream(StringRef Input, SourceMgr &, bool ShowColors = true,
+         std::error_code *EC = nullptr);
+
+  Stream(MemoryBufferRef InputBuffer, SourceMgr &, bool ShowColors = true,
+         std::error_code *EC = nullptr);
+  ~Stream();
+
+  document_iterator begin();
+  document_iterator end();
+  void skip();
+  bool failed();
+
+  bool validate() {
+    skip();
+    return !failed();
+  }
+
+  void printError(Node *N, const Twine &Msg);
+
+private:
+  friend class Document;
+
+  std::unique_ptr<Scanner> scanner;
+  std::unique_ptr<Document> CurrentDoc;
+};
+
+/// Abstract base class for all Nodes.
+class Node {
+  virtual void anchor();
+
+public:
+  enum NodeKind {
+    NK_Null,
+    NK_Scalar,
+    NK_BlockScalar,
+    NK_KeyValue,
+    NK_Mapping,
+    NK_Sequence,
+    NK_Alias
+  };
+
+  Node(unsigned int Type, std::unique_ptr<Document> &, StringRef Anchor,
+       StringRef Tag);
+
+  // It's not safe to copy YAML nodes; the document is streamed and the position
+  // is part of the state.
+  Node(const Node &) = delete;
+  void operator=(const Node &) = delete;
+
+  void *operator new(size_t Size, BumpPtrAllocator &Alloc,
+                     size_t Alignment = 16) noexcept {
+    return Alloc.Allocate(Size, Alignment);
+  }
+
+  void operator delete(void *Ptr, BumpPtrAllocator &Alloc,
+                       size_t Size) noexcept {
+    Alloc.Deallocate(Ptr, Size);
+  }
+
+  void operator delete(void *) noexcept = delete;
+
+  /// Get the value of the anchor attached to this node. If it does not
+  ///        have one, getAnchor().size() will be 0.
+  StringRef getAnchor() const { return Anchor; }
+
+  /// Get the tag as it was written in the document. This does not
+  ///   perform tag resolution.
+  StringRef getRawTag() const { return Tag; }
+
+  /// Get the verbatium tag for a given Node. This performs tag resoluton
+  ///   and substitution.
+  std::string getVerbatimTag() const;
+
+  SMRange getSourceRange() const { return SourceRange; }
+  void setSourceRange(SMRange SR) { SourceRange = SR; }
+
+  // These functions forward to Document and Scanner.
+  Token &peekNext();
+  Token getNext();
+  Node *parseBlockNode();
+  BumpPtrAllocator &getAllocator();
+  void setError(const Twine &Message, Token &Location) const;
+  bool failed() const;
+
+  virtual void skip() {}
+
+  unsigned int getType() const { return TypeID; }
+
+protected:
+  std::unique_ptr<Document> &Doc;
+  SMRange SourceRange;
+
+  ~Node() = default;
+
+private:
+  unsigned int TypeID;
+  StringRef Anchor;
+  /// The tag as typed in the document.
+  StringRef Tag;
+};
+
+/// A null value.
+///
+/// Example:
+///   !!null null
+class NullNode final : public Node {
+  void anchor() override;
+
+public:
+  NullNode(std::unique_ptr<Document> &D)
+      : Node(NK_Null, D, StringRef(), StringRef()) {}
+
+  static bool classof(const Node *N) { return N->getType() == NK_Null; }
+};
+
+/// A scalar node is an opaque datum that can be presented as a
+///        series of zero or more Unicode scalar values.
+///
+/// Example:
+///   Adena
+class ScalarNode final : public Node {
+  void anchor() override;
+
+public:
+  ScalarNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag,
+             StringRef Val)
+      : Node(NK_Scalar, D, Anchor, Tag), Value(Val) {
+    SMLoc Start = SMLoc::getFromPointer(Val.begin());
+    SMLoc End = SMLoc::getFromPointer(Val.end());
+    SourceRange = SMRange(Start, End);
+  }
+
+  // Return Value without any escaping or folding or other fun YAML stuff. This
+  // is the exact bytes that are contained in the file (after conversion to
+  // utf8).
+  StringRef getRawValue() const { return Value; }
+
+  /// Gets the value of this node as a StringRef.
+  ///
+  /// \param Storage is used to store the content of the returned StringRef iff
+  ///        it requires any modification from how it appeared in the source.
+  ///        This happens with escaped characters and multi-line literals.
+  StringRef getValue(SmallVectorImpl<char> &Storage) const;
+
+  static bool classof(const Node *N) {
+    return N->getType() == NK_Scalar;
+  }
+
+private:
+  StringRef Value;
+
+  StringRef unescapeDoubleQuoted(StringRef UnquotedValue,
+                                 StringRef::size_type Start,
+                                 SmallVectorImpl<char> &Storage) const;
+};
+
+/// A block scalar node is an opaque datum that can be presented as a
+///        series of zero or more Unicode scalar values.
+///
+/// Example:
+///   |
+///     Hello
+///     World
+class BlockScalarNode final : public Node {
+  void anchor() override;
+
+public:
+  BlockScalarNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag,
+                  StringRef Value, StringRef RawVal)
+      : Node(NK_BlockScalar, D, Anchor, Tag), Value(Value) {
+    SMLoc Start = SMLoc::getFromPointer(RawVal.begin());
+    SMLoc End = SMLoc::getFromPointer(RawVal.end());
+    SourceRange = SMRange(Start, End);
+  }
+
+  /// Gets the value of this node as a StringRef.
+  StringRef getValue() const { return Value; }
+
+  static bool classof(const Node *N) {
+    return N->getType() == NK_BlockScalar;
+  }
+
+private:
+  StringRef Value;
+};
+
+/// A key and value pair. While not technically a Node under the YAML
+///        representation graph, it is easier to treat them this way.
+///
+/// TODO: Consider making this not a child of Node.
+///
+/// Example:
+///   Section: .text
+class KeyValueNode final : public Node {
+  void anchor() override;
+
+public:
+  KeyValueNode(std::unique_ptr<Document> &D)
+      : Node(NK_KeyValue, D, StringRef(), StringRef()) {}
+
+  /// Parse and return the key.
+  ///
+  /// This may be called multiple times.
+  ///
+  /// \returns The key, or nullptr if failed() == true.
+  Node *getKey();
+
+  /// Parse and return the value.
+  ///
+  /// This may be called multiple times.
+  ///
+  /// \returns The value, or nullptr if failed() == true.
+  Node *getValue();
+
+  void skip() override {
+    if (Node *Key = getKey()) {
+      Key->skip();
+      if (Node *Val = getValue())
+        Val->skip();
+    }
+  }
+
+  static bool classof(const Node *N) {
+    return N->getType() == NK_KeyValue;
+  }
+
+private:
+  Node *Key = nullptr;
+  Node *Value = nullptr;
+};
+
+/// This is an iterator abstraction over YAML collections shared by both
+///        sequences and maps.
+///
+/// BaseT must have a ValueT* member named CurrentEntry and a member function
+/// increment() which must set CurrentEntry to 0 to create an end iterator.
+template <class BaseT, class ValueT>
+class basic_collection_iterator
+    : public std::iterator<std::input_iterator_tag, ValueT> {
+public:
+  basic_collection_iterator() = default;
+  basic_collection_iterator(BaseT *B) : Base(B) {}
+
+  ValueT *operator->() const {
+    assert(Base && Base->CurrentEntry && "Attempted to access end iterator!");
+    return Base->CurrentEntry;
+  }
+
+  ValueT &operator*() const {
+    assert(Base && Base->CurrentEntry &&
+           "Attempted to dereference end iterator!");
+    return *Base->CurrentEntry;
+  }
+
+  operator ValueT *() const {
+    assert(Base && Base->CurrentEntry && "Attempted to access end iterator!");
+    return Base->CurrentEntry;
+  }
+
+  /// Note on EqualityComparable:
+  ///
+  /// The iterator is not re-entrant,
+  /// it is meant to be used for parsing YAML on-demand
+  /// Once iteration started - it can point only to one entry at a time
+  /// hence Base.CurrentEntry and Other.Base.CurrentEntry are equal
+  /// iff Base and Other.Base are equal.
+  bool operator==(const basic_collection_iterator &Other) const {
+    if (Base && (Base == Other.Base)) {
+      assert((Base->CurrentEntry == Other.Base->CurrentEntry)
+             && "Equal Bases expected to point to equal Entries");
+    }
+
+    return Base == Other.Base;
+  }
+
+  bool operator!=(const basic_collection_iterator &Other) const {
+    return !(Base == Other.Base);
+  }
+
+  basic_collection_iterator &operator++() {
+    assert(Base && "Attempted to advance iterator past end!");
+    Base->increment();
+    // Create an end iterator.
+    if (!Base->CurrentEntry)
+      Base = nullptr;
+    return *this;
+  }
+
+private:
+  BaseT *Base = nullptr;
+};
+
+// The following two templates are used for both MappingNode and Sequence Node.
+template <class CollectionType>
+typename CollectionType::iterator begin(CollectionType &C) {
+  assert(C.IsAtBeginning && "You may only iterate over a collection once!");
+  C.IsAtBeginning = false;
+  typename CollectionType::iterator ret(&C);
+  ++ret;
+  return ret;
+}
+
+template <class CollectionType> void skip(CollectionType &C) {
+  // TODO: support skipping from the middle of a parsed collection ;/
+  assert((C.IsAtBeginning || C.IsAtEnd) && "Cannot skip mid parse!");
+  if (C.IsAtBeginning)
+    for (typename CollectionType::iterator i = begin(C), e = C.end(); i != e;
+         ++i)
+      i->skip();
+}
+
+/// Represents a YAML map created from either a block map for a flow map.
+///
+/// This parses the YAML stream as increment() is called.
+///
+/// Example:
+///   Name: _main
+///   Scope: Global
+class MappingNode final : public Node {
+  void anchor() override;
+
+public:
+  enum MappingType {
+    MT_Block,
+    MT_Flow,
+    MT_Inline ///< An inline mapping node is used for "[key: value]".
+  };
+
+  MappingNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag,
+              MappingType MT)
+      : Node(NK_Mapping, D, Anchor, Tag), Type(MT) {}
+
+  friend class basic_collection_iterator<MappingNode, KeyValueNode>;
+
+  using iterator = basic_collection_iterator<MappingNode, KeyValueNode>;
+
+  template <class T> friend typename T::iterator yaml::begin(T &);
+  template <class T> friend void yaml::skip(T &);
+
+  iterator begin() { return yaml::begin(*this); }
+
+  iterator end() { return iterator(); }
+
+  void skip() override { yaml::skip(*this); }
+
+  static bool classof(const Node *N) {
+    return N->getType() == NK_Mapping;
+  }
+
+private:
+  MappingType Type;
+  bool IsAtBeginning = true;
+  bool IsAtEnd = false;
+  KeyValueNode *CurrentEntry = nullptr;
+
+  void increment();
+};
+
+/// Represents a YAML sequence created from either a block sequence for a
+///        flow sequence.
+///
+/// This parses the YAML stream as increment() is called.
+///
+/// Example:
+///   - Hello
+///   - World
+class SequenceNode final : public Node {
+  void anchor() override;
+
+public:
+  enum SequenceType {
+    ST_Block,
+    ST_Flow,
+    // Use for:
+    //
+    // key:
+    // - val1
+    // - val2
+    //
+    // As a BlockMappingEntry and BlockEnd are not created in this case.
+    ST_Indentless
+  };
+
+  SequenceNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag,
+               SequenceType ST)
+      : Node(NK_Sequence, D, Anchor, Tag), SeqType(ST) {}
+
+  friend class basic_collection_iterator<SequenceNode, Node>;
+
+  using iterator = basic_collection_iterator<SequenceNode, Node>;
+
+  template <class T> friend typename T::iterator yaml::begin(T &);
+  template <class T> friend void yaml::skip(T &);
+
+  void increment();
+
+  iterator begin() { return yaml::begin(*this); }
+
+  iterator end() { return iterator(); }
+
+  void skip() override { yaml::skip(*this); }
+
+  static bool classof(const Node *N) {
+    return N->getType() == NK_Sequence;
+  }
+
+private:
+  SequenceType SeqType;
+  bool IsAtBeginning = true;
+  bool IsAtEnd = false;
+  bool WasPreviousTokenFlowEntry = true; // Start with an imaginary ','.
+  Node *CurrentEntry = nullptr;
+};
+
+/// Represents an alias to a Node with an anchor.
+///
+/// Example:
+///   *AnchorName
+class AliasNode final : public Node {
+  void anchor() override;
+
+public:
+  AliasNode(std::unique_ptr<Document> &D, StringRef Val)
+      : Node(NK_Alias, D, StringRef(), StringRef()), Name(Val) {}
+
+  StringRef getName() const { return Name; }
+  Node *getTarget();
+
+  static bool classof(const Node *N) { return N->getType() == NK_Alias; }
+
+private:
+  StringRef Name;
+};
+
+/// A YAML Stream is a sequence of Documents. A document contains a root
+///        node.
+class Document {
+public:
+  Document(Stream &ParentStream);
+
+  /// Root for parsing a node. Returns a single node.
+  Node *parseBlockNode();
+
+  /// Finish parsing the current document and return true if there are
+  ///        more. Return false otherwise.
+  bool skip();
+
+  /// Parse and return the root level node.
+  Node *getRoot() {
+    if (Root)
+      return Root;
+    return Root = parseBlockNode();
+  }
+
+  const std::map<StringRef, StringRef> &getTagMap() const { return TagMap; }
+
+private:
+  friend class Node;
+  friend class document_iterator;
+
+  /// Stream to read tokens from.
+  Stream &stream;
+
+  /// Used to allocate nodes to. All are destroyed without calling their
+  ///        destructor when the document is destroyed.
+  BumpPtrAllocator NodeAllocator;
+
+  /// The root node. Used to support skipping a partially parsed
+  ///        document.
+  Node *Root;
+
+  /// Maps tag prefixes to their expansion.
+  std::map<StringRef, StringRef> TagMap;
+
+  Token &peekNext();
+  Token getNext();
+  void setError(const Twine &Message, Token &Location) const;
+  bool failed() const;
+
+  /// Parse %BLAH directives and return true if any were encountered.
+  bool parseDirectives();
+
+  /// Parse %YAML
+  void parseYAMLDirective();
+
+  /// Parse %TAG
+  void parseTAGDirective();
+
+  /// Consume the next token and error if it is not \a TK.
+  bool expectToken(int TK);
+};
+
+/// Iterator abstraction for Documents over a Stream.
+class document_iterator {
+public:
+  document_iterator() = default;
+  document_iterator(std::unique_ptr<Document> &D) : Doc(&D) {}
+
+  bool operator==(const document_iterator &Other) const {
+    if (isAtEnd() || Other.isAtEnd())
+      return isAtEnd() && Other.isAtEnd();
+
+    return Doc == Other.Doc;
+  }
+  bool operator!=(const document_iterator &Other) const {
+    return !(*this == Other);
+  }
+
+  document_iterator operator++() {
+    assert(Doc && "incrementing iterator past the end.");
+    if (!(*Doc)->skip()) {
+      Doc->reset(nullptr);
+    } else {
+      Stream &S = (*Doc)->stream;
+      Doc->reset(new Document(S));
+    }
+    return *this;
+  }
+
+  Document &operator*() { return *Doc->get(); }
+
+  std::unique_ptr<Document> &operator->() { return *Doc; }
+
+private:
+  bool isAtEnd() const { return !Doc || !*Doc; }
+
+  std::unique_ptr<Document> *Doc = nullptr;
+};
+
+} // end namespace yaml
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_YAMLPARSER_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/YAMLTraits.h b/binaryen/third_party/llvm-project/include/llvm/Support/YAMLTraits.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/YAMLTraits.h
@@ -0,0 +1,2043 @@
+//===- llvm/Support/YAMLTraits.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_YAMLTRAITS_H
+#define LLVM_SUPPORT_YAMLTRAITS_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/AlignOf.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cctype>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <map>
+#include <memory>
+#include <new>
+#include <string>
+#include <system_error>
+#include <type_traits>
+#include <vector>
+
+namespace llvm {
+namespace yaml {
+
+enum class NodeKind : uint8_t {
+  Scalar,
+  Map,
+  Sequence,
+};
+
+struct EmptyContext {};
+
+/// This class should be specialized by any type that needs to be converted
+/// to/from a YAML mapping.  For example:
+///
+///     struct MappingTraits<MyStruct> {
+///       static void mapping(IO &io, MyStruct &s) {
+///         io.mapRequired("name", s.name);
+///         io.mapRequired("size", s.size);
+///         io.mapOptional("age",  s.age);
+///       }
+///     };
+template<class T>
+struct MappingTraits {
+  // Must provide:
+  // static void mapping(IO &io, T &fields);
+  // Optionally may provide:
+  // static StringRef validate(IO &io, T &fields);
+  //
+  // The optional flow flag will cause generated YAML to use a flow mapping
+  // (e.g. { a: 0, b: 1 }):
+  // static const bool flow = true;
+};
+
+/// This class is similar to MappingTraits<T> but allows you to pass in
+/// additional context for each map operation.  For example:
+///
+///     struct MappingContextTraits<MyStruct, MyContext> {
+///       static void mapping(IO &io, MyStruct &s, MyContext &c) {
+///         io.mapRequired("name", s.name);
+///         io.mapRequired("size", s.size);
+///         io.mapOptional("age",  s.age);
+///         ++c.TimesMapped;
+///       }
+///     };
+template <class T, class Context> struct MappingContextTraits {
+  // Must provide:
+  // static void mapping(IO &io, T &fields, Context &Ctx);
+  // Optionally may provide:
+  // static StringRef validate(IO &io, T &fields, Context &Ctx);
+  //
+  // The optional flow flag will cause generated YAML to use a flow mapping
+  // (e.g. { a: 0, b: 1 }):
+  // static const bool flow = true;
+};
+
+/// This class should be specialized by any integral type that converts
+/// to/from a YAML scalar where there is a one-to-one mapping between
+/// in-memory values and a string in YAML.  For example:
+///
+///     struct ScalarEnumerationTraits<Colors> {
+///         static void enumeration(IO &io, Colors &value) {
+///           io.enumCase(value, "red",   cRed);
+///           io.enumCase(value, "blue",  cBlue);
+///           io.enumCase(value, "green", cGreen);
+///         }
+///       };
+template <typename T, typename Enable = void> struct ScalarEnumerationTraits {
+  // Must provide:
+  // static void enumeration(IO &io, T &value);
+};
+
+/// This class should be specialized by any integer type that is a union
+/// of bit values and the YAML representation is a flow sequence of
+/// strings.  For example:
+///
+///      struct ScalarBitSetTraits<MyFlags> {
+///        static void bitset(IO &io, MyFlags &value) {
+///          io.bitSetCase(value, "big",   flagBig);
+///          io.bitSetCase(value, "flat",  flagFlat);
+///          io.bitSetCase(value, "round", flagRound);
+///        }
+///      };
+template <typename T, typename Enable = void> struct ScalarBitSetTraits {
+  // Must provide:
+  // static void bitset(IO &io, T &value);
+};
+
+/// Describe which type of quotes should be used when quoting is necessary.
+/// Some non-printable characters need to be double-quoted, while some others
+/// are fine with simple-quoting, and some don't need any quoting.
+enum class QuotingType { None, Single, Double };
+
+/// This class should be specialized by type that requires custom conversion
+/// to/from a yaml scalar.  For example:
+///
+///    template<>
+///    struct ScalarTraits<MyType> {
+///      static void output(const MyType &val, void*, llvm::raw_ostream &out) {
+///        // stream out custom formatting
+///        out << llvm::format("%x", val);
+///      }
+///      static StringRef input(StringRef scalar, void*, MyType &value) {
+///        // parse scalar and set `value`
+///        // return empty string on success, or error string
+///        return StringRef();
+///      }
+///      static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
+///    };
+template <typename T, typename Enable = void> struct ScalarTraits {
+  // Must provide:
+  //
+  // Function to write the value as a string:
+  // static void output(const T &value, void *ctxt, llvm::raw_ostream &out);
+  //
+  // Function to convert a string to a value.  Returns the empty
+  // StringRef on success or an error string if string is malformed:
+  // static StringRef input(StringRef scalar, void *ctxt, T &value);
+  //
+  // Function to determine if the value should be quoted.
+  // static QuotingType mustQuote(StringRef);
+};
+
+/// This class should be specialized by type that requires custom conversion
+/// to/from a YAML literal block scalar. For example:
+///
+///    template <>
+///    struct BlockScalarTraits<MyType> {
+///      static void output(const MyType &Value, void*, llvm::raw_ostream &Out)
+///      {
+///        // stream out custom formatting
+///        Out << Value;
+///      }
+///      static StringRef input(StringRef Scalar, void*, MyType &Value) {
+///        // parse scalar and set `value`
+///        // return empty string on success, or error string
+///        return StringRef();
+///      }
+///    };
+template <typename T>
+struct BlockScalarTraits {
+  // Must provide:
+  //
+  // Function to write the value as a string:
+  // static void output(const T &Value, void *ctx, llvm::raw_ostream &Out);
+  //
+  // Function to convert a string to a value.  Returns the empty
+  // StringRef on success or an error string if string is malformed:
+  // static StringRef input(StringRef Scalar, void *ctxt, T &Value);
+  //
+  // Optional:
+  // static StringRef inputTag(T &Val, std::string Tag)
+  // static void outputTag(const T &Val, raw_ostream &Out)
+};
+
+/// This class should be specialized by type that requires custom conversion
+/// to/from a YAML scalar with optional tags. For example:
+///
+///    template <>
+///    struct TaggedScalarTraits<MyType> {
+///      static void output(const MyType &Value, void*, llvm::raw_ostream
+///      &ScalarOut, llvm::raw_ostream &TagOut)
+///      {
+///        // stream out custom formatting including optional Tag
+///        Out << Value;
+///      }
+///      static StringRef input(StringRef Scalar, StringRef Tag, void*, MyType
+///      &Value) {
+///        // parse scalar and set `value`
+///        // return empty string on success, or error string
+///        return StringRef();
+///      }
+///      static QuotingType mustQuote(const MyType &Value, StringRef) {
+///        return QuotingType::Single;
+///      }
+///    };
+template <typename T> struct TaggedScalarTraits {
+  // Must provide:
+  //
+  // Function to write the value and tag as strings:
+  // static void output(const T &Value, void *ctx, llvm::raw_ostream &ScalarOut,
+  // llvm::raw_ostream &TagOut);
+  //
+  // Function to convert a string to a value.  Returns the empty
+  // StringRef on success or an error string if string is malformed:
+  // static StringRef input(StringRef Scalar, StringRef Tag, void *ctxt, T
+  // &Value);
+  //
+  // Function to determine if the value should be quoted.
+  // static QuotingType mustQuote(const T &Value, StringRef Scalar);
+};
+
+/// This class should be specialized by any type that needs to be converted
+/// to/from a YAML sequence.  For example:
+///
+///    template<>
+///    struct SequenceTraits<MyContainer> {
+///      static size_t size(IO &io, MyContainer &seq) {
+///        return seq.size();
+///      }
+///      static MyType& element(IO &, MyContainer &seq, size_t index) {
+///        if ( index >= seq.size() )
+///          seq.resize(index+1);
+///        return seq[index];
+///      }
+///    };
+template<typename T, typename EnableIf = void>
+struct SequenceTraits {
+  // Must provide:
+  // static size_t size(IO &io, T &seq);
+  // static T::value_type& element(IO &io, T &seq, size_t index);
+  //
+  // The following is option and will cause generated YAML to use
+  // a flow sequence (e.g. [a,b,c]).
+  // static const bool flow = true;
+};
+
+/// This class should be specialized by any type for which vectors of that
+/// type need to be converted to/from a YAML sequence.
+template<typename T, typename EnableIf = void>
+struct SequenceElementTraits {
+  // Must provide:
+  // static const bool flow;
+};
+
+/// This class should be specialized by any type that needs to be converted
+/// to/from a list of YAML documents.
+template<typename T>
+struct DocumentListTraits {
+  // Must provide:
+  // static size_t size(IO &io, T &seq);
+  // static T::value_type& element(IO &io, T &seq, size_t index);
+};
+
+/// This class should be specialized by any type that needs to be converted
+/// to/from a YAML mapping in the case where the names of the keys are not known
+/// in advance, e.g. a string map.
+template <typename T>
+struct CustomMappingTraits {
+  // static void inputOne(IO &io, StringRef key, T &elem);
+  // static void output(IO &io, T &elem);
+};
+
+/// This class should be specialized by any type that can be represented as
+/// a scalar, map, or sequence, decided dynamically. For example:
+///
+///    typedef std::unique_ptr<MyBase> MyPoly;
+///
+///    template<>
+///    struct PolymorphicTraits<MyPoly> {
+///      static NodeKind getKind(const MyPoly &poly) {
+///        return poly->getKind();
+///      }
+///      static MyScalar& getAsScalar(MyPoly &poly) {
+///        if (!poly || !isa<MyScalar>(poly))
+///          poly.reset(new MyScalar());
+///        return *cast<MyScalar>(poly.get());
+///      }
+///      // ...
+///    };
+template <typename T> struct PolymorphicTraits {
+  // Must provide:
+  // static NodeKind getKind(const T &poly);
+  // static scalar_type &getAsScalar(T &poly);
+  // static map_type &getAsMap(T &poly);
+  // static sequence_type &getAsSequence(T &poly);
+};
+
+// Only used for better diagnostics of missing traits
+template <typename T>
+struct MissingTrait;
+
+// Test if ScalarEnumerationTraits<T> is defined on type T.
+template <class T>
+struct has_ScalarEnumerationTraits
+{
+  using Signature_enumeration = void (*)(class IO&, T&);
+
+  template <typename U>
+  static char test(SameType<Signature_enumeration, &U::enumeration>*);
+
+  template <typename U>
+  static double test(...);
+
+  static bool const value =
+    (sizeof(test<ScalarEnumerationTraits<T>>(nullptr)) == 1);
+};
+
+// Test if ScalarBitSetTraits<T> is defined on type T.
+template <class T>
+struct has_ScalarBitSetTraits
+{
+  using Signature_bitset = void (*)(class IO&, T&);
+
+  template <typename U>
+  static char test(SameType<Signature_bitset, &U::bitset>*);
+
+  template <typename U>
+  static double test(...);
+
+  static bool const value = (sizeof(test<ScalarBitSetTraits<T>>(nullptr)) == 1);
+};
+
+// Test if ScalarTraits<T> is defined on type T.
+template <class T>
+struct has_ScalarTraits
+{
+  using Signature_input = StringRef (*)(StringRef, void*, T&);
+  using Signature_output = void (*)(const T&, void*, raw_ostream&);
+  using Signature_mustQuote = QuotingType (*)(StringRef);
+
+  template <typename U>
+  static char test(SameType<Signature_input, &U::input> *,
+                   SameType<Signature_output, &U::output> *,
+                   SameType<Signature_mustQuote, &U::mustQuote> *);
+
+  template <typename U>
+  static double test(...);
+
+  static bool const value =
+      (sizeof(test<ScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1);
+};
+
+// Test if BlockScalarTraits<T> is defined on type T.
+template <class T>
+struct has_BlockScalarTraits
+{
+  using Signature_input = StringRef (*)(StringRef, void *, T &);
+  using Signature_output = void (*)(const T &, void *, raw_ostream &);
+
+  template <typename U>
+  static char test(SameType<Signature_input, &U::input> *,
+                   SameType<Signature_output, &U::output> *);
+
+  template <typename U>
+  static double test(...);
+
+  static bool const value =
+      (sizeof(test<BlockScalarTraits<T>>(nullptr, nullptr)) == 1);
+};
+
+// Test if TaggedScalarTraits<T> is defined on type T.
+template <class T> struct has_TaggedScalarTraits {
+  using Signature_input = StringRef (*)(StringRef, StringRef, void *, T &);
+  using Signature_output = void (*)(const T &, void *, raw_ostream &,
+                                    raw_ostream &);
+  using Signature_mustQuote = QuotingType (*)(const T &, StringRef);
+
+  template <typename U>
+  static char test(SameType<Signature_input, &U::input> *,
+                   SameType<Signature_output, &U::output> *,
+                   SameType<Signature_mustQuote, &U::mustQuote> *);
+
+  template <typename U> static double test(...);
+
+  static bool const value =
+      (sizeof(test<TaggedScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1);
+};
+
+// Test if MappingContextTraits<T> is defined on type T.
+template <class T, class Context> struct has_MappingTraits {
+  using Signature_mapping = void (*)(class IO &, T &, Context &);
+
+  template <typename U>
+  static char test(SameType<Signature_mapping, &U::mapping>*);
+
+  template <typename U>
+  static double test(...);
+
+  static bool const value =
+      (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1);
+};
+
+// Test if MappingTraits<T> is defined on type T.
+template <class T> struct has_MappingTraits<T, EmptyContext> {
+  using Signature_mapping = void (*)(class IO &, T &);
+
+  template <typename U>
+  static char test(SameType<Signature_mapping, &U::mapping> *);
+
+  template <typename U> static double test(...);
+
+  static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1);
+};
+
+// Test if MappingContextTraits<T>::validate() is defined on type T.
+template <class T, class Context> struct has_MappingValidateTraits {
+  using Signature_validate = StringRef (*)(class IO &, T &, Context &);
+
+  template <typename U>
+  static char test(SameType<Signature_validate, &U::validate>*);
+
+  template <typename U>
+  static double test(...);
+
+  static bool const value =
+      (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1);
+};
+
+// Test if MappingTraits<T>::validate() is defined on type T.
+template <class T> struct has_MappingValidateTraits<T, EmptyContext> {
+  using Signature_validate = StringRef (*)(class IO &, T &);
+
+  template <typename U>
+  static char test(SameType<Signature_validate, &U::validate> *);
+
+  template <typename U> static double test(...);
+
+  static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1);
+};
+
+// Test if SequenceTraits<T> is defined on type T.
+template <class T>
+struct has_SequenceMethodTraits
+{
+  using Signature_size = size_t (*)(class IO&, T&);
+
+  template <typename U>
+  static char test(SameType<Signature_size, &U::size>*);
+
+  template <typename U>
+  static double test(...);
+
+  static bool const value =  (sizeof(test<SequenceTraits<T>>(nullptr)) == 1);
+};
+
+// Test if CustomMappingTraits<T> is defined on type T.
+template <class T>
+struct has_CustomMappingTraits
+{
+  using Signature_input = void (*)(IO &io, StringRef key, T &v);
+
+  template <typename U>
+  static char test(SameType<Signature_input, &U::inputOne>*);
+
+  template <typename U>
+  static double test(...);
+
+  static bool const value =
+      (sizeof(test<CustomMappingTraits<T>>(nullptr)) == 1);
+};
+
+// has_FlowTraits<int> will cause an error with some compilers because
+// it subclasses int.  Using this wrapper only instantiates the
+// real has_FlowTraits only if the template type is a class.
+template <typename T, bool Enabled = std::is_class<T>::value>
+class has_FlowTraits
+{
+public:
+   static const bool value = false;
+};
+
+// Some older gcc compilers don't support straight forward tests
+// for members, so test for ambiguity cause by the base and derived
+// classes both defining the member.
+template <class T>
+struct has_FlowTraits<T, true>
+{
+  struct Fallback { bool flow; };
+  struct Derived : T, Fallback { };
+
+  template<typename C>
+  static char (&f(SameType<bool Fallback::*, &C::flow>*))[1];
+
+  template<typename C>
+  static char (&f(...))[2];
+
+  static bool const value = sizeof(f<Derived>(nullptr)) == 2;
+};
+
+// Test if SequenceTraits<T> is defined on type T
+template<typename T>
+struct has_SequenceTraits : public std::integral_constant<bool,
+                                      has_SequenceMethodTraits<T>::value > { };
+
+// Test if DocumentListTraits<T> is defined on type T
+template <class T>
+struct has_DocumentListTraits
+{
+  using Signature_size = size_t (*)(class IO &, T &);
+
+  template <typename U>
+  static char test(SameType<Signature_size, &U::size>*);
+
+  template <typename U>
+  static double test(...);
+
+  static bool const value = (sizeof(test<DocumentListTraits<T>>(nullptr))==1);
+};
+
+template <class T> struct has_PolymorphicTraits {
+  using Signature_getKind = NodeKind (*)(const T &);
+
+  template <typename U>
+  static char test(SameType<Signature_getKind, &U::getKind> *);
+
+  template <typename U> static double test(...);
+
+  static bool const value = (sizeof(test<PolymorphicTraits<T>>(nullptr)) == 1);
+};
+
+inline bool isNumeric(StringRef S) {
+  const static auto skipDigits = [](StringRef Input) {
+    return Input.drop_front(
+        std::min(Input.find_first_not_of("0123456789"), Input.size()));
+  };
+
+  // Make S.front() and S.drop_front().front() (if S.front() is [+-]) calls
+  // safe.
+  if (S.empty() || S.equals("+") || S.equals("-"))
+    return false;
+
+  if (S.equals(".nan") || S.equals(".NaN") || S.equals(".NAN"))
+    return true;
+
+  // Infinity and decimal numbers can be prefixed with sign.
+  StringRef Tail = (S.front() == '-' || S.front() == '+') ? S.drop_front() : S;
+
+  // Check for infinity first, because checking for hex and oct numbers is more
+  // expensive.
+  if (Tail.equals(".inf") || Tail.equals(".Inf") || Tail.equals(".INF"))
+    return true;
+
+  // Section 10.3.2 Tag Resolution
+  // YAML 1.2 Specification prohibits Base 8 and Base 16 numbers prefixed with
+  // [-+], so S should be used instead of Tail.
+  if (S.startswith("0o"))
+    return S.size() > 2 &&
+           S.drop_front(2).find_first_not_of("01234567") == StringRef::npos;
+
+  if (S.startswith("0x"))
+    return S.size() > 2 && S.drop_front(2).find_first_not_of(
+                               "0123456789abcdefABCDEF") == StringRef::npos;
+
+  // Parse float: [-+]? (\. [0-9]+ | [0-9]+ (\. [0-9]* )?) ([eE] [-+]? [0-9]+)?
+  S = Tail;
+
+  // Handle cases when the number starts with '.' and hence needs at least one
+  // digit after dot (as opposed by number which has digits before the dot), but
+  // doesn't have one.
+  if (S.startswith(".") &&
+      (S.equals(".") ||
+       (S.size() > 1 && std::strchr("0123456789", S[1]) == nullptr)))
+    return false;
+
+  if (S.startswith("E") || S.startswith("e"))
+    return false;
+
+  enum ParseState {
+    Default,
+    FoundDot,
+    FoundExponent,
+  };
+  ParseState State = Default;
+
+  S = skipDigits(S);
+
+  // Accept decimal integer.
+  if (S.empty())
+    return true;
+
+  if (S.front() == '.') {
+    State = FoundDot;
+    S = S.drop_front();
+  } else if (S.front() == 'e' || S.front() == 'E') {
+    State = FoundExponent;
+    S = S.drop_front();
+  } else {
+    return false;
+  }
+
+  if (State == FoundDot) {
+    S = skipDigits(S);
+    if (S.empty())
+      return true;
+
+    if (S.front() == 'e' || S.front() == 'E') {
+      State = FoundExponent;
+      S = S.drop_front();
+    } else {
+      return false;
+    }
+  }
+
+  assert(State == FoundExponent && "Should have found exponent at this point.");
+  if (S.empty())
+    return false;
+
+  if (S.front() == '+' || S.front() == '-') {
+    S = S.drop_front();
+    if (S.empty())
+      return false;
+  }
+
+  return skipDigits(S).empty();
+}
+
+inline bool isNull(StringRef S) {
+  return S.equals("null") || S.equals("Null") || S.equals("NULL") ||
+         S.equals("~");
+}
+
+inline bool isBool(StringRef S) {
+  return S.equals("true") || S.equals("True") || S.equals("TRUE") ||
+         S.equals("false") || S.equals("False") || S.equals("FALSE");
+}
+
+// 5.1. Character Set
+// The allowed character range explicitly excludes the C0 control block #x0-#x1F
+// (except for TAB #x9, LF #xA, and CR #xD which are allowed), DEL #x7F, the C1
+// control block #x80-#x9F (except for NEL #x85 which is allowed), the surrogate
+// block #xD800-#xDFFF, #xFFFE, and #xFFFF.
+inline QuotingType needsQuotes(StringRef S) {
+  if (S.empty())
+    return QuotingType::Single;
+  if (isspace(static_cast<unsigned char>(S.front())) ||
+      isspace(static_cast<unsigned char>(S.back())))
+    return QuotingType::Single;
+  if (isNull(S))
+    return QuotingType::Single;
+  if (isBool(S))
+    return QuotingType::Single;
+  if (isNumeric(S))
+    return QuotingType::Single;
+
+  // 7.3.3 Plain Style
+  // Plain scalars must not begin with most indicators, as this would cause
+  // ambiguity with other YAML constructs.
+  static constexpr char Indicators[] = R"(-?:\,[]{}#&*!|>'"%@`)";
+  if (S.find_first_of(Indicators) == 0)
+    return QuotingType::Single;
+
+  QuotingType MaxQuotingNeeded = QuotingType::None;
+  for (unsigned char C : S) {
+    // Alphanum is safe.
+    if (isAlnum(C))
+      continue;
+
+    switch (C) {
+    // Safe scalar characters.
+    case '_':
+    case '-':
+    case '^':
+    case '.':
+    case ',':
+    case ' ':
+    // TAB (0x9) is allowed in unquoted strings.
+    case 0x9:
+      continue;
+    // LF(0xA) and CR(0xD) may delimit values and so require at least single
+    // quotes.
+    case 0xA:
+    case 0xD:
+      MaxQuotingNeeded = QuotingType::Single;
+      continue;
+    // DEL (0x7F) are excluded from the allowed character range.
+    case 0x7F:
+      return QuotingType::Double;
+    // Forward slash is allowed to be unquoted, but we quote it anyway.  We have
+    // many tests that use FileCheck against YAML output, and this output often
+    // contains paths.  If we quote backslashes but not forward slashes then
+    // paths will come out either quoted or unquoted depending on which platform
+    // the test is run on, making FileCheck comparisons difficult.
+    case '/':
+    default: {
+      // C0 control block (0x0 - 0x1F) is excluded from the allowed character
+      // range.
+      if (C <= 0x1F)
+        return QuotingType::Double;
+
+      // Always double quote UTF-8.
+      if ((C & 0x80) != 0)
+        return QuotingType::Double;
+
+      // The character is not safe, at least simple quoting needed.
+      MaxQuotingNeeded = QuotingType::Single;
+    }
+    }
+  }
+
+  return MaxQuotingNeeded;
+}
+
+template <typename T, typename Context>
+struct missingTraits
+    : public std::integral_constant<bool,
+                                    !has_ScalarEnumerationTraits<T>::value &&
+                                        !has_ScalarBitSetTraits<T>::value &&
+                                        !has_ScalarTraits<T>::value &&
+                                        !has_BlockScalarTraits<T>::value &&
+                                        !has_TaggedScalarTraits<T>::value &&
+                                        !has_MappingTraits<T, Context>::value &&
+                                        !has_SequenceTraits<T>::value &&
+                                        !has_CustomMappingTraits<T>::value &&
+                                        !has_DocumentListTraits<T>::value &&
+                                        !has_PolymorphicTraits<T>::value> {};
+
+template <typename T, typename Context>
+struct validatedMappingTraits
+    : public std::integral_constant<
+          bool, has_MappingTraits<T, Context>::value &&
+                    has_MappingValidateTraits<T, Context>::value> {};
+
+template <typename T, typename Context>
+struct unvalidatedMappingTraits
+    : public std::integral_constant<
+          bool, has_MappingTraits<T, Context>::value &&
+                    !has_MappingValidateTraits<T, Context>::value> {};
+
+// Base class for Input and Output.
+class IO {
+public:
+  IO(void *Ctxt = nullptr);
+  virtual ~IO();
+
+  virtual bool outputting() const = 0;
+
+  virtual unsigned beginSequence() = 0;
+  virtual bool preflightElement(unsigned, void *&) = 0;
+  virtual void postflightElement(void*) = 0;
+  virtual void endSequence() = 0;
+  virtual bool canElideEmptySequence() = 0;
+
+  virtual unsigned beginFlowSequence() = 0;
+  virtual bool preflightFlowElement(unsigned, void *&) = 0;
+  virtual void postflightFlowElement(void*) = 0;
+  virtual void endFlowSequence() = 0;
+
+  virtual bool mapTag(StringRef Tag, bool Default=false) = 0;
+  virtual void beginMapping() = 0;
+  virtual void endMapping() = 0;
+  virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0;
+  virtual void postflightKey(void*) = 0;
+  virtual std::vector<StringRef> keys() = 0;
+
+  virtual void beginFlowMapping() = 0;
+  virtual void endFlowMapping() = 0;
+
+  virtual void beginEnumScalar() = 0;
+  virtual bool matchEnumScalar(const char*, bool) = 0;
+  virtual bool matchEnumFallback() = 0;
+  virtual void endEnumScalar() = 0;
+
+  virtual bool beginBitSetScalar(bool &) = 0;
+  virtual bool bitSetMatch(const char*, bool) = 0;
+  virtual void endBitSetScalar() = 0;
+
+  virtual void scalarString(StringRef &, QuotingType) = 0;
+  virtual void blockScalarString(StringRef &) = 0;
+  virtual void scalarTag(std::string &) = 0;
+
+  virtual NodeKind getNodeKind() = 0;
+
+  virtual void setError(const Twine &) = 0;
+
+  template <typename T>
+  void enumCase(T &Val, const char* Str, const T ConstVal) {
+    if ( matchEnumScalar(Str, outputting() && Val == ConstVal) ) {
+      Val = ConstVal;
+    }
+  }
+
+  // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
+  template <typename T>
+  void enumCase(T &Val, const char* Str, const uint32_t ConstVal) {
+    if ( matchEnumScalar(Str, outputting() && Val == static_cast<T>(ConstVal)) ) {
+      Val = ConstVal;
+    }
+  }
+
+  template <typename FBT, typename T>
+  void enumFallback(T &Val) {
+    if (matchEnumFallback()) {
+      EmptyContext Context;
+      // FIXME: Force integral conversion to allow strong typedefs to convert.
+      FBT Res = static_cast<typename FBT::BaseType>(Val);
+      yamlize(*this, Res, true, Context);
+      Val = static_cast<T>(static_cast<typename FBT::BaseType>(Res));
+    }
+  }
+
+  template <typename T>
+  void bitSetCase(T &Val, const char* Str, const T ConstVal) {
+    if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
+      Val = static_cast<T>(Val | ConstVal);
+    }
+  }
+
+  // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
+  template <typename T>
+  void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) {
+    if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
+      Val = static_cast<T>(Val | ConstVal);
+    }
+  }
+
+  template <typename T>
+  void maskedBitSetCase(T &Val, const char *Str, T ConstVal, T Mask) {
+    if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal))
+      Val = Val | ConstVal;
+  }
+
+  template <typename T>
+  void maskedBitSetCase(T &Val, const char *Str, uint32_t ConstVal,
+                        uint32_t Mask) {
+    if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal))
+      Val = Val | ConstVal;
+  }
+
+  void *getContext() const;
+  void setContext(void *);
+
+  template <typename T> void mapRequired(const char *Key, T &Val) {
+    EmptyContext Ctx;
+    this->processKey(Key, Val, true, Ctx);
+  }
+
+  template <typename T, typename Context>
+  void mapRequired(const char *Key, T &Val, Context &Ctx) {
+    this->processKey(Key, Val, true, Ctx);
+  }
+
+  template <typename T> void mapOptional(const char *Key, T &Val) {
+    EmptyContext Ctx;
+    mapOptionalWithContext(Key, Val, Ctx);
+  }
+
+  template <typename T, typename DefaultT>
+  void mapOptional(const char *Key, T &Val, const DefaultT &Default) {
+    EmptyContext Ctx;
+    mapOptionalWithContext(Key, Val, Default, Ctx);
+  }
+
+  template <typename T, typename Context>
+  typename std::enable_if<has_SequenceTraits<T>::value, void>::type
+  mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) {
+    // omit key/value instead of outputting empty sequence
+    if (this->canElideEmptySequence() && !(Val.begin() != Val.end()))
+      return;
+    this->processKey(Key, Val, false, Ctx);
+  }
+
+  template <typename T, typename Context>
+  void mapOptionalWithContext(const char *Key, Optional<T> &Val, Context &Ctx) {
+    this->processKeyWithDefault(Key, Val, Optional<T>(), /*Required=*/false,
+                                Ctx);
+  }
+
+  template <typename T, typename Context>
+  typename std::enable_if<!has_SequenceTraits<T>::value, void>::type
+  mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) {
+    this->processKey(Key, Val, false, Ctx);
+  }
+
+  template <typename T, typename Context, typename DefaultT>
+  void mapOptionalWithContext(const char *Key, T &Val, const DefaultT &Default,
+                              Context &Ctx) {
+    static_assert(std::is_convertible<DefaultT, T>::value,
+                  "Default type must be implicitly convertible to value type!");
+    this->processKeyWithDefault(Key, Val, static_cast<const T &>(Default),
+                                false, Ctx);
+  }
+
+private:
+  template <typename T, typename Context>
+  void processKeyWithDefault(const char *Key, Optional<T> &Val,
+                             const Optional<T> &DefaultValue, bool Required,
+                             Context &Ctx) {
+    assert(DefaultValue.hasValue() == false &&
+           "Optional<T> shouldn't have a value!");
+    void *SaveInfo;
+    bool UseDefault = true;
+    const bool sameAsDefault = outputting() && !Val.hasValue();
+    if (!outputting() && !Val.hasValue())
+      Val = T();
+    if (Val.hasValue() &&
+        this->preflightKey(Key, Required, sameAsDefault, UseDefault,
+                           SaveInfo)) {
+      yamlize(*this, Val.getValue(), Required, Ctx);
+      this->postflightKey(SaveInfo);
+    } else {
+      if (UseDefault)
+        Val = DefaultValue;
+    }
+  }
+
+  template <typename T, typename Context>
+  void processKeyWithDefault(const char *Key, T &Val, const T &DefaultValue,
+                             bool Required, Context &Ctx) {
+    void *SaveInfo;
+    bool UseDefault;
+    const bool sameAsDefault = outputting() && Val == DefaultValue;
+    if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault,
+                                                                  SaveInfo) ) {
+      yamlize(*this, Val, Required, Ctx);
+      this->postflightKey(SaveInfo);
+    }
+    else {
+      if ( UseDefault )
+        Val = DefaultValue;
+    }
+  }
+
+  template <typename T, typename Context>
+  void processKey(const char *Key, T &Val, bool Required, Context &Ctx) {
+    void *SaveInfo;
+    bool UseDefault;
+    if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) {
+      yamlize(*this, Val, Required, Ctx);
+      this->postflightKey(SaveInfo);
+    }
+  }
+
+private:
+  void *Ctxt;
+};
+
+namespace detail {
+
+template <typename T, typename Context>
+void doMapping(IO &io, T &Val, Context &Ctx) {
+  MappingContextTraits<T, Context>::mapping(io, Val, Ctx);
+}
+
+template <typename T> void doMapping(IO &io, T &Val, EmptyContext &Ctx) {
+  MappingTraits<T>::mapping(io, Val);
+}
+
+} // end namespace detail
+
+template <typename T>
+typename std::enable_if<has_ScalarEnumerationTraits<T>::value, void>::type
+yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
+  io.beginEnumScalar();
+  ScalarEnumerationTraits<T>::enumeration(io, Val);
+  io.endEnumScalar();
+}
+
+template <typename T>
+typename std::enable_if<has_ScalarBitSetTraits<T>::value, void>::type
+yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
+  bool DoClear;
+  if ( io.beginBitSetScalar(DoClear) ) {
+    if ( DoClear )
+      Val = T();
+    ScalarBitSetTraits<T>::bitset(io, Val);
+    io.endBitSetScalar();
+  }
+}
+
+template <typename T>
+typename std::enable_if<has_ScalarTraits<T>::value, void>::type
+yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
+  if ( io.outputting() ) {
+    std::string Storage;
+    raw_string_ostream Buffer(Storage);
+    ScalarTraits<T>::output(Val, io.getContext(), Buffer);
+    StringRef Str = Buffer.str();
+    io.scalarString(Str, ScalarTraits<T>::mustQuote(Str));
+  }
+  else {
+    StringRef Str;
+    io.scalarString(Str, ScalarTraits<T>::mustQuote(Str));
+    StringRef Result = ScalarTraits<T>::input(Str, io.getContext(), Val);
+    if ( !Result.empty() ) {
+      io.setError(Twine(Result));
+    }
+  }
+}
+
+template <typename T>
+typename std::enable_if<has_BlockScalarTraits<T>::value, void>::type
+yamlize(IO &YamlIO, T &Val, bool, EmptyContext &Ctx) {
+  if (YamlIO.outputting()) {
+    std::string Storage;
+    raw_string_ostream Buffer(Storage);
+    BlockScalarTraits<T>::output(Val, YamlIO.getContext(), Buffer);
+    StringRef Str = Buffer.str();
+    YamlIO.blockScalarString(Str);
+  } else {
+    StringRef Str;
+    YamlIO.blockScalarString(Str);
+    StringRef Result =
+        BlockScalarTraits<T>::input(Str, YamlIO.getContext(), Val);
+    if (!Result.empty())
+      YamlIO.setError(Twine(Result));
+  }
+}
+
+template <typename T>
+typename std::enable_if<has_TaggedScalarTraits<T>::value, void>::type
+yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
+  if (io.outputting()) {
+    std::string ScalarStorage, TagStorage;
+    raw_string_ostream ScalarBuffer(ScalarStorage), TagBuffer(TagStorage);
+    TaggedScalarTraits<T>::output(Val, io.getContext(), ScalarBuffer,
+                                  TagBuffer);
+    io.scalarTag(TagBuffer.str());
+    StringRef ScalarStr = ScalarBuffer.str();
+    io.scalarString(ScalarStr,
+                    TaggedScalarTraits<T>::mustQuote(Val, ScalarStr));
+  } else {
+    std::string Tag;
+    io.scalarTag(Tag);
+    StringRef Str;
+    io.scalarString(Str, QuotingType::None);
+    StringRef Result =
+        TaggedScalarTraits<T>::input(Str, Tag, io.getContext(), Val);
+    if (!Result.empty()) {
+      io.setError(Twine(Result));
+    }
+  }
+}
+
+template <typename T, typename Context>
+typename std::enable_if<validatedMappingTraits<T, Context>::value, void>::type
+yamlize(IO &io, T &Val, bool, Context &Ctx) {
+  if (has_FlowTraits<MappingTraits<T>>::value)
+    io.beginFlowMapping();
+  else
+    io.beginMapping();
+  if (io.outputting()) {
+    StringRef Err = MappingTraits<T>::validate(io, Val);
+    if (!Err.empty()) {
+      errs() << Err << "\n";
+      assert(Err.empty() && "invalid struct trying to be written as yaml");
+    }
+  }
+  detail::doMapping(io, Val, Ctx);
+  if (!io.outputting()) {
+    StringRef Err = MappingTraits<T>::validate(io, Val);
+    if (!Err.empty())
+      io.setError(Err);
+  }
+  if (has_FlowTraits<MappingTraits<T>>::value)
+    io.endFlowMapping();
+  else
+    io.endMapping();
+}
+
+template <typename T, typename Context>
+typename std::enable_if<unvalidatedMappingTraits<T, Context>::value, void>::type
+yamlize(IO &io, T &Val, bool, Context &Ctx) {
+  if (has_FlowTraits<MappingTraits<T>>::value) {
+    io.beginFlowMapping();
+    detail::doMapping(io, Val, Ctx);
+    io.endFlowMapping();
+  } else {
+    io.beginMapping();
+    detail::doMapping(io, Val, Ctx);
+    io.endMapping();
+  }
+}
+
+template <typename T>
+typename std::enable_if<has_CustomMappingTraits<T>::value, void>::type
+yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
+  if ( io.outputting() ) {
+    io.beginMapping();
+    CustomMappingTraits<T>::output(io, Val);
+    io.endMapping();
+  } else {
+    io.beginMapping();
+    for (StringRef key : io.keys())
+      CustomMappingTraits<T>::inputOne(io, key, Val);
+    io.endMapping();
+  }
+}
+
+template <typename T>
+typename std::enable_if<has_PolymorphicTraits<T>::value, void>::type
+yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
+  switch (io.outputting() ? PolymorphicTraits<T>::getKind(Val)
+                          : io.getNodeKind()) {
+  case NodeKind::Scalar:
+    return yamlize(io, PolymorphicTraits<T>::getAsScalar(Val), true, Ctx);
+  case NodeKind::Map:
+    return yamlize(io, PolymorphicTraits<T>::getAsMap(Val), true, Ctx);
+  case NodeKind::Sequence:
+    return yamlize(io, PolymorphicTraits<T>::getAsSequence(Val), true, Ctx);
+  }
+}
+
+template <typename T>
+typename std::enable_if<missingTraits<T, EmptyContext>::value, void>::type
+yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
+  char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
+}
+
+template <typename T, typename Context>
+typename std::enable_if<has_SequenceTraits<T>::value, void>::type
+yamlize(IO &io, T &Seq, bool, Context &Ctx) {
+  if ( has_FlowTraits< SequenceTraits<T>>::value ) {
+    unsigned incnt = io.beginFlowSequence();
+    unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
+    for(unsigned i=0; i < count; ++i) {
+      void *SaveInfo;
+      if ( io.preflightFlowElement(i, SaveInfo) ) {
+        yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx);
+        io.postflightFlowElement(SaveInfo);
+      }
+    }
+    io.endFlowSequence();
+  }
+  else {
+    unsigned incnt = io.beginSequence();
+    unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
+    for(unsigned i=0; i < count; ++i) {
+      void *SaveInfo;
+      if ( io.preflightElement(i, SaveInfo) ) {
+        yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx);
+        io.postflightElement(SaveInfo);
+      }
+    }
+    io.endSequence();
+  }
+}
+
+template<>
+struct ScalarTraits<bool> {
+  static void output(const bool &, void* , raw_ostream &);
+  static StringRef input(StringRef, void *, bool &);
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<StringRef> {
+  static void output(const StringRef &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, StringRef &);
+  static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
+};
+
+template<>
+struct ScalarTraits<std::string> {
+  static void output(const std::string &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, std::string &);
+  static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
+};
+
+template<>
+struct ScalarTraits<uint8_t> {
+  static void output(const uint8_t &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, uint8_t &);
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<uint16_t> {
+  static void output(const uint16_t &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, uint16_t &);
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<uint32_t> {
+  static void output(const uint32_t &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, uint32_t &);
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<uint64_t> {
+  static void output(const uint64_t &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, uint64_t &);
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<int8_t> {
+  static void output(const int8_t &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, int8_t &);
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<int16_t> {
+  static void output(const int16_t &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, int16_t &);
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<int32_t> {
+  static void output(const int32_t &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, int32_t &);
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<int64_t> {
+  static void output(const int64_t &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, int64_t &);
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<float> {
+  static void output(const float &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, float &);
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<double> {
+  static void output(const double &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, double &);
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+// For endian types, we use existing scalar Traits class for the underlying
+// type.  This way endian aware types are supported whenever the traits are
+// defined for the underlying type.
+template <typename value_type, support::endianness endian, size_t alignment>
+struct ScalarTraits<
+    support::detail::packed_endian_specific_integral<value_type, endian,
+                                                     alignment>,
+    typename std::enable_if<has_ScalarTraits<value_type>::value>::type> {
+  using endian_type =
+      support::detail::packed_endian_specific_integral<value_type, endian,
+                                                       alignment>;
+
+  static void output(const endian_type &E, void *Ctx, raw_ostream &Stream) {
+    ScalarTraits<value_type>::output(static_cast<value_type>(E), Ctx, Stream);
+  }
+
+  static StringRef input(StringRef Str, void *Ctx, endian_type &E) {
+    value_type V;
+    auto R = ScalarTraits<value_type>::input(Str, Ctx, V);
+    E = static_cast<endian_type>(V);
+    return R;
+  }
+
+  static QuotingType mustQuote(StringRef Str) {
+    return ScalarTraits<value_type>::mustQuote(Str);
+  }
+};
+
+template <typename value_type, support::endianness endian, size_t alignment>
+struct ScalarEnumerationTraits<
+    support::detail::packed_endian_specific_integral<value_type, endian,
+                                                     alignment>,
+    typename std::enable_if<
+        has_ScalarEnumerationTraits<value_type>::value>::type> {
+  using endian_type =
+      support::detail::packed_endian_specific_integral<value_type, endian,
+                                                       alignment>;
+
+  static void enumeration(IO &io, endian_type &E) {
+    value_type V = E;
+    ScalarEnumerationTraits<value_type>::enumeration(io, V);
+    E = V;
+  }
+};
+
+template <typename value_type, support::endianness endian, size_t alignment>
+struct ScalarBitSetTraits<
+    support::detail::packed_endian_specific_integral<value_type, endian,
+                                                     alignment>,
+    typename std::enable_if<has_ScalarBitSetTraits<value_type>::value>::type> {
+  using endian_type =
+      support::detail::packed_endian_specific_integral<value_type, endian,
+                                                       alignment>;
+  static void bitset(IO &io, endian_type &E) {
+    value_type V = E;
+    ScalarBitSetTraits<value_type>::bitset(io, V);
+    E = V;
+  }
+};
+
+// Utility for use within MappingTraits<>::mapping() method
+// to [de]normalize an object for use with YAML conversion.
+template <typename TNorm, typename TFinal>
+struct MappingNormalization {
+  MappingNormalization(IO &i_o, TFinal &Obj)
+      : io(i_o), BufPtr(nullptr), Result(Obj) {
+    if ( io.outputting() ) {
+      BufPtr = new (&Buffer) TNorm(io, Obj);
+    }
+    else {
+      BufPtr = new (&Buffer) TNorm(io);
+    }
+  }
+
+  ~MappingNormalization() {
+    if ( ! io.outputting() ) {
+      Result = BufPtr->denormalize(io);
+    }
+    BufPtr->~TNorm();
+  }
+
+  TNorm* operator->() { return BufPtr; }
+
+private:
+  using Storage = AlignedCharArrayUnion<TNorm>;
+
+  Storage       Buffer;
+  IO           &io;
+  TNorm        *BufPtr;
+  TFinal       &Result;
+};
+
+// Utility for use within MappingTraits<>::mapping() method
+// to [de]normalize an object for use with YAML conversion.
+template <typename TNorm, typename TFinal>
+struct MappingNormalizationHeap {
+  MappingNormalizationHeap(IO &i_o, TFinal &Obj, BumpPtrAllocator *allocator)
+    : io(i_o), Result(Obj) {
+    if ( io.outputting() ) {
+      BufPtr = new (&Buffer) TNorm(io, Obj);
+    }
+    else if (allocator) {
+      BufPtr = allocator->Allocate<TNorm>();
+      new (BufPtr) TNorm(io);
+    } else {
+      BufPtr = new TNorm(io);
+    }
+  }
+
+  ~MappingNormalizationHeap() {
+    if ( io.outputting() ) {
+      BufPtr->~TNorm();
+    }
+    else {
+      Result = BufPtr->denormalize(io);
+    }
+  }
+
+  TNorm* operator->() { return BufPtr; }
+
+private:
+  using Storage = AlignedCharArrayUnion<TNorm>;
+
+  Storage       Buffer;
+  IO           &io;
+  TNorm        *BufPtr = nullptr;
+  TFinal       &Result;
+};
+
+///
+/// The Input class is used to parse a yaml document into in-memory structs
+/// and vectors.
+///
+/// It works by using YAMLParser to do a syntax parse of the entire yaml
+/// document, then the Input class builds a graph of HNodes which wraps
+/// each yaml Node.  The extra layer is buffering.  The low level yaml
+/// parser only lets you look at each node once.  The buffering layer lets
+/// you search and interate multiple times.  This is necessary because
+/// the mapRequired() method calls may not be in the same order
+/// as the keys in the document.
+///
+class Input : public IO {
+public:
+  // Construct a yaml Input object from a StringRef and optional
+  // user-data. The DiagHandler can be specified to provide
+  // alternative error reporting.
+  Input(StringRef InputContent,
+        void *Ctxt = nullptr,
+        SourceMgr::DiagHandlerTy DiagHandler = nullptr,
+        void *DiagHandlerCtxt = nullptr);
+  Input(MemoryBufferRef Input,
+        void *Ctxt = nullptr,
+        SourceMgr::DiagHandlerTy DiagHandler = nullptr,
+        void *DiagHandlerCtxt = nullptr);
+  ~Input() override;
+
+  // Check if there was an syntax or semantic error during parsing.
+  std::error_code error();
+
+private:
+  bool outputting() const override;
+  bool mapTag(StringRef, bool) override;
+  void beginMapping() override;
+  void endMapping() override;
+  bool preflightKey(const char *, bool, bool, bool &, void *&) override;
+  void postflightKey(void *) override;
+  std::vector<StringRef> keys() override;
+  void beginFlowMapping() override;
+  void endFlowMapping() override;
+  unsigned beginSequence() override;
+  void endSequence() override;
+  bool preflightElement(unsigned index, void *&) override;
+  void postflightElement(void *) override;
+  unsigned beginFlowSequence() override;
+  bool preflightFlowElement(unsigned , void *&) override;
+  void postflightFlowElement(void *) override;
+  void endFlowSequence() override;
+  void beginEnumScalar() override;
+  bool matchEnumScalar(const char*, bool) override;
+  bool matchEnumFallback() override;
+  void endEnumScalar() override;
+  bool beginBitSetScalar(bool &) override;
+  bool bitSetMatch(const char *, bool ) override;
+  void endBitSetScalar() override;
+  void scalarString(StringRef &, QuotingType) override;
+  void blockScalarString(StringRef &) override;
+  void scalarTag(std::string &) override;
+  NodeKind getNodeKind() override;
+  void setError(const Twine &message) override;
+  bool canElideEmptySequence() override;
+
+  class HNode {
+    virtual void anchor();
+
+  public:
+    HNode(Node *n) : _node(n) { }
+    virtual ~HNode() = default;
+
+    static bool classof(const HNode *) { return true; }
+
+    Node *_node;
+  };
+
+  class EmptyHNode : public HNode {
+    void anchor() override;
+
+  public:
+    EmptyHNode(Node *n) : HNode(n) { }
+
+    static bool classof(const HNode *n) { return NullNode::classof(n->_node); }
+
+    static bool classof(const EmptyHNode *) { return true; }
+  };
+
+  class ScalarHNode : public HNode {
+    void anchor() override;
+
+  public:
+    ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { }
+
+    StringRef value() const { return _value; }
+
+    static bool classof(const HNode *n) {
+      return ScalarNode::classof(n->_node) ||
+             BlockScalarNode::classof(n->_node);
+    }
+
+    static bool classof(const ScalarHNode *) { return true; }
+
+  protected:
+    StringRef _value;
+  };
+
+  class MapHNode : public HNode {
+    void anchor() override;
+
+  public:
+    MapHNode(Node *n) : HNode(n) { }
+
+    static bool classof(const HNode *n) {
+      return MappingNode::classof(n->_node);
+    }
+
+    static bool classof(const MapHNode *) { return true; }
+
+    using NameToNode = StringMap<std::unique_ptr<HNode>>;
+
+    NameToNode Mapping;
+    SmallVector<std::string, 6> ValidKeys;
+  };
+
+  class SequenceHNode : public HNode {
+    void anchor() override;
+
+  public:
+    SequenceHNode(Node *n) : HNode(n) { }
+
+    static bool classof(const HNode *n) {
+      return SequenceNode::classof(n->_node);
+    }
+
+    static bool classof(const SequenceHNode *) { return true; }
+
+    std::vector<std::unique_ptr<HNode>> Entries;
+  };
+
+  std::unique_ptr<Input::HNode> createHNodes(Node *node);
+  void setError(HNode *hnode, const Twine &message);
+  void setError(Node *node, const Twine &message);
+
+public:
+  // These are only used by operator>>. They could be private
+  // if those templated things could be made friends.
+  bool setCurrentDocument();
+  bool nextDocument();
+
+  /// Returns the current node that's being parsed by the YAML Parser.
+  const Node *getCurrentNode() const;
+
+private:
+  SourceMgr                           SrcMgr; // must be before Strm
+  std::unique_ptr<llvm::yaml::Stream> Strm;
+  std::unique_ptr<HNode>              TopNode;
+  std::error_code                     EC;
+  BumpPtrAllocator                    StringAllocator;
+  document_iterator                   DocIterator;
+  std::vector<bool>                   BitValuesUsed;
+  HNode *CurrentNode = nullptr;
+  bool                                ScalarMatchFound = false;
+};
+
+///
+/// The Output class is used to generate a yaml document from in-memory structs
+/// and vectors.
+///
+class Output : public IO {
+public:
+  Output(raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70);
+  ~Output() override;
+
+  /// Set whether or not to output optional values which are equal
+  /// to the default value.  By default, when outputting if you attempt
+  /// to write a value that is equal to the default, the value gets ignored.
+  /// Sometimes, it is useful to be able to see these in the resulting YAML
+  /// anyway.
+  void setWriteDefaultValues(bool Write) { WriteDefaultValues = Write; }
+
+  bool outputting() const override;
+  bool mapTag(StringRef, bool) override;
+  void beginMapping() override;
+  void endMapping() override;
+  bool preflightKey(const char *key, bool, bool, bool &, void *&) override;
+  void postflightKey(void *) override;
+  std::vector<StringRef> keys() override;
+  void beginFlowMapping() override;
+  void endFlowMapping() override;
+  unsigned beginSequence() override;
+  void endSequence() override;
+  bool preflightElement(unsigned, void *&) override;
+  void postflightElement(void *) override;
+  unsigned beginFlowSequence() override;
+  bool preflightFlowElement(unsigned, void *&) override;
+  void postflightFlowElement(void *) override;
+  void endFlowSequence() override;
+  void beginEnumScalar() override;
+  bool matchEnumScalar(const char*, bool) override;
+  bool matchEnumFallback() override;
+  void endEnumScalar() override;
+  bool beginBitSetScalar(bool &) override;
+  bool bitSetMatch(const char *, bool ) override;
+  void endBitSetScalar() override;
+  void scalarString(StringRef &, QuotingType) override;
+  void blockScalarString(StringRef &) override;
+  void scalarTag(std::string &) override;
+  NodeKind getNodeKind() override;
+  void setError(const Twine &message) override;
+  bool canElideEmptySequence() override;
+
+  // These are only used by operator<<. They could be private
+  // if that templated operator could be made a friend.
+  void beginDocuments();
+  bool preflightDocument(unsigned);
+  void postflightDocument();
+  void endDocuments();
+
+private:
+  void output(StringRef s);
+  void outputUpToEndOfLine(StringRef s);
+  void newLineCheck();
+  void outputNewLine();
+  void paddedKey(StringRef key);
+  void flowKey(StringRef Key);
+
+  enum InState {
+    inSeqFirstElement,
+    inSeqOtherElement,
+    inFlowSeqFirstElement,
+    inFlowSeqOtherElement,
+    inMapFirstKey,
+    inMapOtherKey,
+    inFlowMapFirstKey,
+    inFlowMapOtherKey
+  };
+
+  static bool inSeqAnyElement(InState State);
+  static bool inFlowSeqAnyElement(InState State);
+  static bool inMapAnyKey(InState State);
+  static bool inFlowMapAnyKey(InState State);
+
+  raw_ostream &Out;
+  int WrapColumn;
+  SmallVector<InState, 8> StateStack;
+  int Column = 0;
+  int ColumnAtFlowStart = 0;
+  int ColumnAtMapFlowStart = 0;
+  bool NeedBitValueComma = false;
+  bool NeedFlowSequenceComma = false;
+  bool EnumerationMatchFound = false;
+  bool WriteDefaultValues = false;
+  StringRef Padding;
+  StringRef PaddingBeforeContainer;
+};
+
+/// YAML I/O does conversion based on types. But often native data types
+/// are just a typedef of built in intergral types (e.g. int).  But the C++
+/// type matching system sees through the typedef and all the typedefed types
+/// look like a built in type. This will cause the generic YAML I/O conversion
+/// to be used. To provide better control over the YAML conversion, you can
+/// use this macro instead of typedef.  It will create a class with one field
+/// and automatic conversion operators to and from the base type.
+/// Based on BOOST_STRONG_TYPEDEF
+#define LLVM_YAML_STRONG_TYPEDEF(_base, _type)                                 \
+    struct _type {                                                             \
+        _type() = default;                                                     \
+        _type(const _base v) : value(v) {}                                     \
+        _type(const _type &v) = default;                                       \
+        _type &operator=(const _type &rhs) = default;                          \
+        _type &operator=(const _base &rhs) { value = rhs; return *this; }      \
+        operator const _base & () const { return value; }                      \
+        bool operator==(const _type &rhs) const { return value == rhs.value; } \
+        bool operator==(const _base &rhs) const { return value == rhs; }       \
+        bool operator<(const _type &rhs) const { return value < rhs.value; }   \
+        _base value;                                                           \
+        using BaseType = _base;                                                \
+    };
+
+///
+/// Use these types instead of uintXX_t in any mapping to have
+/// its yaml output formatted as hexadecimal.
+///
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8)
+LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16)
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32)
+LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64)
+
+template<>
+struct ScalarTraits<Hex8> {
+  static void output(const Hex8 &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, Hex8 &);
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<Hex16> {
+  static void output(const Hex16 &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, Hex16 &);
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<Hex32> {
+  static void output(const Hex32 &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, Hex32 &);
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<Hex64> {
+  static void output(const Hex64 &, void *, raw_ostream &);
+  static StringRef input(StringRef, void *, Hex64 &);
+  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+// Define non-member operator>> so that Input can stream in a document list.
+template <typename T>
+inline
+typename std::enable_if<has_DocumentListTraits<T>::value, Input &>::type
+operator>>(Input &yin, T &docList) {
+  int i = 0;
+  EmptyContext Ctx;
+  while ( yin.setCurrentDocument() ) {
+    yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true, Ctx);
+    if ( yin.error() )
+      return yin;
+    yin.nextDocument();
+    ++i;
+  }
+  return yin;
+}
+
+// Define non-member operator>> so that Input can stream in a map as a document.
+template <typename T>
+inline typename std::enable_if<has_MappingTraits<T, EmptyContext>::value,
+                               Input &>::type
+operator>>(Input &yin, T &docMap) {
+  EmptyContext Ctx;
+  yin.setCurrentDocument();
+  yamlize(yin, docMap, true, Ctx);
+  return yin;
+}
+
+// Define non-member operator>> so that Input can stream in a sequence as
+// a document.
+template <typename T>
+inline
+typename std::enable_if<has_SequenceTraits<T>::value, Input &>::type
+operator>>(Input &yin, T &docSeq) {
+  EmptyContext Ctx;
+  if (yin.setCurrentDocument())
+    yamlize(yin, docSeq, true, Ctx);
+  return yin;
+}
+
+// Define non-member operator>> so that Input can stream in a block scalar.
+template <typename T>
+inline
+typename std::enable_if<has_BlockScalarTraits<T>::value, Input &>::type
+operator>>(Input &In, T &Val) {
+  EmptyContext Ctx;
+  if (In.setCurrentDocument())
+    yamlize(In, Val, true, Ctx);
+  return In;
+}
+
+// Define non-member operator>> so that Input can stream in a string map.
+template <typename T>
+inline
+typename std::enable_if<has_CustomMappingTraits<T>::value, Input &>::type
+operator>>(Input &In, T &Val) {
+  EmptyContext Ctx;
+  if (In.setCurrentDocument())
+    yamlize(In, Val, true, Ctx);
+  return In;
+}
+
+// Define non-member operator>> so that Input can stream in a polymorphic type.
+template <typename T>
+inline typename std::enable_if<has_PolymorphicTraits<T>::value, Input &>::type
+operator>>(Input &In, T &Val) {
+  EmptyContext Ctx;
+  if (In.setCurrentDocument())
+    yamlize(In, Val, true, Ctx);
+  return In;
+}
+
+// Provide better error message about types missing a trait specialization
+template <typename T>
+inline typename std::enable_if<missingTraits<T, EmptyContext>::value,
+                               Input &>::type
+operator>>(Input &yin, T &docSeq) {
+  char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
+  return yin;
+}
+
+// Define non-member operator<< so that Output can stream out document list.
+template <typename T>
+inline
+typename std::enable_if<has_DocumentListTraits<T>::value, Output &>::type
+operator<<(Output &yout, T &docList) {
+  EmptyContext Ctx;
+  yout.beginDocuments();
+  const size_t count = DocumentListTraits<T>::size(yout, docList);
+  for(size_t i=0; i < count; ++i) {
+    if ( yout.preflightDocument(i) ) {
+      yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true,
+              Ctx);
+      yout.postflightDocument();
+    }
+  }
+  yout.endDocuments();
+  return yout;
+}
+
+// Define non-member operator<< so that Output can stream out a map.
+template <typename T>
+inline typename std::enable_if<has_MappingTraits<T, EmptyContext>::value,
+                               Output &>::type
+operator<<(Output &yout, T &map) {
+  EmptyContext Ctx;
+  yout.beginDocuments();
+  if ( yout.preflightDocument(0) ) {
+    yamlize(yout, map, true, Ctx);
+    yout.postflightDocument();
+  }
+  yout.endDocuments();
+  return yout;
+}
+
+// Define non-member operator<< so that Output can stream out a sequence.
+template <typename T>
+inline
+typename std::enable_if<has_SequenceTraits<T>::value, Output &>::type
+operator<<(Output &yout, T &seq) {
+  EmptyContext Ctx;
+  yout.beginDocuments();
+  if ( yout.preflightDocument(0) ) {
+    yamlize(yout, seq, true, Ctx);
+    yout.postflightDocument();
+  }
+  yout.endDocuments();
+  return yout;
+}
+
+// Define non-member operator<< so that Output can stream out a block scalar.
+template <typename T>
+inline
+typename std::enable_if<has_BlockScalarTraits<T>::value, Output &>::type
+operator<<(Output &Out, T &Val) {
+  EmptyContext Ctx;
+  Out.beginDocuments();
+  if (Out.preflightDocument(0)) {
+    yamlize(Out, Val, true, Ctx);
+    Out.postflightDocument();
+  }
+  Out.endDocuments();
+  return Out;
+}
+
+// Define non-member operator<< so that Output can stream out a string map.
+template <typename T>
+inline
+typename std::enable_if<has_CustomMappingTraits<T>::value, Output &>::type
+operator<<(Output &Out, T &Val) {
+  EmptyContext Ctx;
+  Out.beginDocuments();
+  if (Out.preflightDocument(0)) {
+    yamlize(Out, Val, true, Ctx);
+    Out.postflightDocument();
+  }
+  Out.endDocuments();
+  return Out;
+}
+
+// Define non-member operator<< so that Output can stream out a polymorphic
+// type.
+template <typename T>
+inline typename std::enable_if<has_PolymorphicTraits<T>::value, Output &>::type
+operator<<(Output &Out, T &Val) {
+  EmptyContext Ctx;
+  Out.beginDocuments();
+  if (Out.preflightDocument(0)) {
+    // FIXME: The parser does not support explicit documents terminated with a
+    // plain scalar; the end-marker is included as part of the scalar token.
+    assert(PolymorphicTraits<T>::getKind(Val) != NodeKind::Scalar && "plain scalar documents are not supported");
+    yamlize(Out, Val, true, Ctx);
+    Out.postflightDocument();
+  }
+  Out.endDocuments();
+  return Out;
+}
+
+// Provide better error message about types missing a trait specialization
+template <typename T>
+inline typename std::enable_if<missingTraits<T, EmptyContext>::value,
+                               Output &>::type
+operator<<(Output &yout, T &seq) {
+  char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
+  return yout;
+}
+
+template <bool B> struct IsFlowSequenceBase {};
+template <> struct IsFlowSequenceBase<true> { static const bool flow = true; };
+
+template <typename T, bool Flow>
+struct SequenceTraitsImpl : IsFlowSequenceBase<Flow> {
+private:
+  using type = typename T::value_type;
+
+public:
+  static size_t size(IO &io, T &seq) { return seq.size(); }
+
+  static type &element(IO &io, T &seq, size_t index) {
+    if (index >= seq.size())
+      seq.resize(index + 1);
+    return seq[index];
+  }
+};
+
+// Simple helper to check an expression can be used as a bool-valued template
+// argument.
+template <bool> struct CheckIsBool { static const bool value = true; };
+
+// If T has SequenceElementTraits, then vector<T> and SmallVector<T, N> have
+// SequenceTraits that do the obvious thing.
+template <typename T>
+struct SequenceTraits<std::vector<T>,
+                      typename std::enable_if<CheckIsBool<
+                          SequenceElementTraits<T>::flow>::value>::type>
+    : SequenceTraitsImpl<std::vector<T>, SequenceElementTraits<T>::flow> {};
+template <typename T, unsigned N>
+struct SequenceTraits<SmallVector<T, N>,
+                      typename std::enable_if<CheckIsBool<
+                          SequenceElementTraits<T>::flow>::value>::type>
+    : SequenceTraitsImpl<SmallVector<T, N>, SequenceElementTraits<T>::flow> {};
+template <typename T>
+struct SequenceTraits<SmallVectorImpl<T>,
+                      typename std::enable_if<CheckIsBool<
+                          SequenceElementTraits<T>::flow>::value>::type>
+    : SequenceTraitsImpl<SmallVectorImpl<T>, SequenceElementTraits<T>::flow> {};
+
+// Sequences of fundamental types use flow formatting.
+template <typename T>
+struct SequenceElementTraits<
+    T, typename std::enable_if<std::is_fundamental<T>::value>::type> {
+  static const bool flow = true;
+};
+
+// Sequences of strings use block formatting.
+template<> struct SequenceElementTraits<std::string> {
+  static const bool flow = false;
+};
+template<> struct SequenceElementTraits<StringRef> {
+  static const bool flow = false;
+};
+template<> struct SequenceElementTraits<std::pair<std::string, std::string>> {
+  static const bool flow = false;
+};
+
+/// Implementation of CustomMappingTraits for std::map<std::string, T>.
+template <typename T> struct StdMapStringCustomMappingTraitsImpl {
+  using map_type = std::map<std::string, T>;
+
+  static void inputOne(IO &io, StringRef key, map_type &v) {
+    io.mapRequired(key.str().c_str(), v[key]);
+  }
+
+  static void output(IO &io, map_type &v) {
+    for (auto &p : v)
+      io.mapRequired(p.first.c_str(), p.second);
+  }
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+#define LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(TYPE, FLOW)                          \
+  namespace llvm {                                                             \
+  namespace yaml {                                                             \
+  static_assert(                                                               \
+      !std::is_fundamental<TYPE>::value &&                                     \
+      !std::is_same<TYPE, std::string>::value &&                               \
+      !std::is_same<TYPE, llvm::StringRef>::value,                             \
+      "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control");          \
+  template <> struct SequenceElementTraits<TYPE> {                             \
+    static const bool flow = FLOW;                                             \
+  };                                                                           \
+  }                                                                            \
+  }
+
+/// Utility for declaring that a std::vector of a particular type
+/// should be considered a YAML sequence.
+#define LLVM_YAML_IS_SEQUENCE_VECTOR(type)                                     \
+  LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, false)
+
+/// Utility for declaring that a std::vector of a particular type
+/// should be considered a YAML flow sequence.
+#define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(type)                                \
+  LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, true)
+
+#define LLVM_YAML_DECLARE_MAPPING_TRAITS(Type)                                 \
+  namespace llvm {                                                             \
+  namespace yaml {                                                             \
+  template <> struct MappingTraits<Type> {                                     \
+    static void mapping(IO &IO, Type &Obj);                                    \
+  };                                                                           \
+  }                                                                            \
+  }
+
+#define LLVM_YAML_DECLARE_ENUM_TRAITS(Type)                                    \
+  namespace llvm {                                                             \
+  namespace yaml {                                                             \
+  template <> struct ScalarEnumerationTraits<Type> {                           \
+    static void enumeration(IO &io, Type &Value);                              \
+  };                                                                           \
+  }                                                                            \
+  }
+
+#define LLVM_YAML_DECLARE_BITSET_TRAITS(Type)                                  \
+  namespace llvm {                                                             \
+  namespace yaml {                                                             \
+  template <> struct ScalarBitSetTraits<Type> {                                \
+    static void bitset(IO &IO, Type &Options);                                 \
+  };                                                                           \
+  }                                                                            \
+  }
+
+#define LLVM_YAML_DECLARE_SCALAR_TRAITS(Type, MustQuote)                       \
+  namespace llvm {                                                             \
+  namespace yaml {                                                             \
+  template <> struct ScalarTraits<Type> {                                      \
+    static void output(const Type &Value, void *ctx, raw_ostream &Out);        \
+    static StringRef input(StringRef Scalar, void *ctxt, Type &Value);         \
+    static QuotingType mustQuote(StringRef) { return MustQuote; }              \
+  };                                                                           \
+  }                                                                            \
+  }
+
+/// Utility for declaring that a std::vector of a particular type
+/// should be considered a YAML document list.
+#define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type)                               \
+  namespace llvm {                                                             \
+  namespace yaml {                                                             \
+  template <unsigned N>                                                        \
+  struct DocumentListTraits<SmallVector<_type, N>>                             \
+      : public SequenceTraitsImpl<SmallVector<_type, N>, false> {};            \
+  template <>                                                                  \
+  struct DocumentListTraits<std::vector<_type>>                                \
+      : public SequenceTraitsImpl<std::vector<_type>, false> {};               \
+  }                                                                            \
+  }
+
+/// Utility for declaring that std::map<std::string, _type> should be considered
+/// a YAML map.
+#define LLVM_YAML_IS_STRING_MAP(_type)                                         \
+  namespace llvm {                                                             \
+  namespace yaml {                                                             \
+  template <>                                                                  \
+  struct CustomMappingTraits<std::map<std::string, _type>>                     \
+      : public StdMapStringCustomMappingTraitsImpl<_type> {};                  \
+  }                                                                            \
+  }
+
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex64)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex32)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex16)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex8)
+
+#endif // LLVM_SUPPORT_YAMLTRAITS_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/circular_raw_ostream.h b/binaryen/third_party/llvm-project/include/llvm/Support/circular_raw_ostream.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/circular_raw_ostream.h
@@ -0,0 +1,159 @@
+//===-- llvm/Support/circular_raw_ostream.h - Buffered streams --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains raw_ostream implementations for streams to do circular
+// buffering of their output.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CIRCULAR_RAW_OSTREAM_H
+#define LLVM_SUPPORT_CIRCULAR_RAW_OSTREAM_H
+
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+  /// circular_raw_ostream - A raw_ostream which *can* save its data
+  /// to a circular buffer, or can pass it through directly to an
+  /// underlying stream if specified with a buffer of zero.
+  ///
+  class circular_raw_ostream : public raw_ostream {
+  public:
+    /// TAKE_OWNERSHIP - Tell this stream that it owns the underlying
+    /// stream and is responsible for cleanup, memory management
+    /// issues, etc.
+    ///
+    static const bool TAKE_OWNERSHIP = true;
+
+    /// REFERENCE_ONLY - Tell this stream it should not manage the
+    /// held stream.
+    ///
+    static const bool REFERENCE_ONLY = false;
+
+  private:
+    /// TheStream - The real stream we output to. We set it to be
+    /// unbuffered, since we're already doing our own buffering.
+    ///
+    raw_ostream *TheStream;
+
+    /// OwnsStream - Are we responsible for managing the underlying
+    /// stream?
+    ///
+    bool OwnsStream;
+
+    /// BufferSize - The size of the buffer in bytes.
+    ///
+    size_t BufferSize;
+
+    /// BufferArray - The actual buffer storage.
+    ///
+    char *BufferArray;
+
+    /// Cur - Pointer to the current output point in BufferArray.
+    ///
+    char *Cur;
+
+    /// Filled - Indicate whether the buffer has been completely
+    /// filled.  This helps avoid garbage output.
+    ///
+    bool Filled;
+
+    /// Banner - A pointer to a banner to print before dumping the
+    /// log.
+    ///
+    const char *Banner;
+
+    /// flushBuffer - Dump the contents of the buffer to Stream.
+    ///
+    void flushBuffer() {
+      if (Filled)
+        // Write the older portion of the buffer.
+        TheStream->write(Cur, BufferArray + BufferSize - Cur);
+      // Write the newer portion of the buffer.
+      TheStream->write(BufferArray, Cur - BufferArray);
+      Cur = BufferArray;
+      Filled = false;
+    }
+
+    void write_impl(const char *Ptr, size_t Size) override;
+
+    /// current_pos - Return the current position within the stream,
+    /// not counting the bytes currently in the buffer.
+    ///
+    uint64_t current_pos() const override {
+      // This has the same effect as calling TheStream.current_pos(),
+      // but that interface is private.
+      return TheStream->tell() - TheStream->GetNumBytesInBuffer();
+    }
+
+  public:
+    /// circular_raw_ostream - Construct an optionally
+    /// circular-buffered stream, handing it an underlying stream to
+    /// do the "real" output.
+    ///
+    /// As a side effect, if BuffSize is nonzero, the given Stream is
+    /// set to be Unbuffered.  This is because circular_raw_ostream
+    /// does its own buffering, so it doesn't want another layer of
+    /// buffering to be happening underneath it.
+    ///
+    /// "Owns" tells the circular_raw_ostream whether it is
+    /// responsible for managing the held stream, doing memory
+    /// management of it, etc.
+    ///
+    circular_raw_ostream(raw_ostream &Stream, const char *Header,
+                         size_t BuffSize = 0, bool Owns = REFERENCE_ONLY)
+        : raw_ostream(/*unbuffered*/ true), TheStream(nullptr),
+          OwnsStream(Owns), BufferSize(BuffSize), BufferArray(nullptr),
+          Filled(false), Banner(Header) {
+      if (BufferSize != 0)
+        BufferArray = new char[BufferSize];
+      Cur = BufferArray;
+      setStream(Stream, Owns);
+    }
+
+    ~circular_raw_ostream() override {
+      flush();
+      flushBufferWithBanner();
+      releaseStream();
+      delete[] BufferArray;
+    }
+
+    bool is_displayed() const override {
+      return TheStream->is_displayed();
+    }
+
+    /// setStream - Tell the circular_raw_ostream to output a
+    /// different stream.  "Owns" tells circular_raw_ostream whether
+    /// it should take responsibility for managing the underlying
+    /// stream.
+    ///
+    void setStream(raw_ostream &Stream, bool Owns = REFERENCE_ONLY) {
+      releaseStream();
+      TheStream = &Stream;
+      OwnsStream = Owns;
+    }
+
+    /// flushBufferWithBanner - Force output of the buffer along with
+    /// a small header.
+    ///
+    void flushBufferWithBanner();
+
+  private:
+    /// releaseStream - Delete the held stream if needed. Otherwise,
+    /// transfer the buffer settings from this circular_raw_ostream
+    /// back to the underlying stream.
+    ///
+    void releaseStream() {
+      if (!TheStream)
+        return;
+      if (OwnsStream)
+        delete TheStream;
+    }
+  };
+} // end llvm namespace
+
+#endif
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/raw_ostream.h b/binaryen/third_party/llvm-project/include/llvm/Support/raw_ostream.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/raw_ostream.h
@@ -0,0 +1,587 @@
+//===--- raw_ostream.h - Raw output stream ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the raw_ostream class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_RAW_OSTREAM_H
+#define LLVM_SUPPORT_RAW_OSTREAM_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <system_error>
+
+namespace llvm {
+
+class formatv_object_base;
+class format_object_base;
+class FormattedString;
+class FormattedNumber;
+class FormattedBytes;
+
+namespace sys {
+namespace fs {
+enum FileAccess : unsigned;
+enum OpenFlags : unsigned;
+enum CreationDisposition : unsigned;
+} // end namespace fs
+} // end namespace sys
+
+/// This class implements an extremely fast bulk output stream that can *only*
+/// output to a stream.  It does not support seeking, reopening, rewinding, line
+/// buffered disciplines etc. It is a simple buffer that outputs
+/// a chunk at a time.
+class raw_ostream {
+private:
+  /// The buffer is handled in such a way that the buffer is
+  /// uninitialized, unbuffered, or out of space when OutBufCur >=
+  /// OutBufEnd. Thus a single comparison suffices to determine if we
+  /// need to take the slow path to write a single character.
+  ///
+  /// The buffer is in one of three states:
+  ///  1. Unbuffered (BufferMode == Unbuffered)
+  ///  1. Uninitialized (BufferMode != Unbuffered && OutBufStart == 0).
+  ///  2. Buffered (BufferMode != Unbuffered && OutBufStart != 0 &&
+  ///               OutBufEnd - OutBufStart >= 1).
+  ///
+  /// If buffered, then the raw_ostream owns the buffer if (BufferMode ==
+  /// InternalBuffer); otherwise the buffer has been set via SetBuffer and is
+  /// managed by the subclass.
+  ///
+  /// If a subclass installs an external buffer using SetBuffer then it can wait
+  /// for a \see write_impl() call to handle the data which has been put into
+  /// this buffer.
+  char *OutBufStart, *OutBufEnd, *OutBufCur;
+
+  enum class BufferKind {
+    Unbuffered = 0,
+    InternalBuffer,
+    ExternalBuffer
+  } BufferMode;
+
+public:
+  // color order matches ANSI escape sequence, don't change
+  enum class Colors {
+    BLACK = 0,
+    RED,
+    GREEN,
+    YELLOW,
+    BLUE,
+    MAGENTA,
+    CYAN,
+    WHITE,
+    SAVEDCOLOR,
+    RESET,
+  };
+
+  static const Colors BLACK = Colors::BLACK;
+  static const Colors RED = Colors::RED;
+  static const Colors GREEN = Colors::GREEN;
+  static const Colors YELLOW = Colors::YELLOW;
+  static const Colors BLUE = Colors::BLUE;
+  static const Colors MAGENTA = Colors::MAGENTA;
+  static const Colors CYAN = Colors::CYAN;
+  static const Colors WHITE = Colors::WHITE;
+  static const Colors SAVEDCOLOR = Colors::SAVEDCOLOR;
+  static const Colors RESET = Colors::RESET;
+
+  explicit raw_ostream(bool unbuffered = false)
+      : BufferMode(unbuffered ? BufferKind::Unbuffered
+                              : BufferKind::InternalBuffer) {
+    // Start out ready to flush.
+    OutBufStart = OutBufEnd = OutBufCur = nullptr;
+  }
+
+  raw_ostream(const raw_ostream &) = delete;
+  void operator=(const raw_ostream &) = delete;
+
+  virtual ~raw_ostream();
+
+  /// tell - Return the current offset with the file.
+  uint64_t tell() const { return current_pos() + GetNumBytesInBuffer(); }
+
+  //===--------------------------------------------------------------------===//
+  // Configuration Interface
+  //===--------------------------------------------------------------------===//
+
+  /// Set the stream to be buffered, with an automatically determined buffer
+  /// size.
+  void SetBuffered();
+
+  /// Set the stream to be buffered, using the specified buffer size.
+  void SetBufferSize(size_t Size) {
+    flush();
+    SetBufferAndMode(new char[Size], Size, BufferKind::InternalBuffer);
+  }
+
+  size_t GetBufferSize() const {
+    // If we're supposed to be buffered but haven't actually gotten around
+    // to allocating the buffer yet, return the value that would be used.
+    if (BufferMode != BufferKind::Unbuffered && OutBufStart == nullptr)
+      return preferred_buffer_size();
+
+    // Otherwise just return the size of the allocated buffer.
+    return OutBufEnd - OutBufStart;
+  }
+
+  /// Set the stream to be unbuffered. When unbuffered, the stream will flush
+  /// after every write. This routine will also flush the buffer immediately
+  /// when the stream is being set to unbuffered.
+  void SetUnbuffered() {
+    flush();
+    SetBufferAndMode(nullptr, 0, BufferKind::Unbuffered);
+  }
+
+  size_t GetNumBytesInBuffer() const {
+    return OutBufCur - OutBufStart;
+  }
+
+  //===--------------------------------------------------------------------===//
+  // Data Output Interface
+  //===--------------------------------------------------------------------===//
+
+  void flush() {
+    if (OutBufCur != OutBufStart)
+      flush_nonempty();
+  }
+
+  raw_ostream &operator<<(char C) {
+    if (OutBufCur >= OutBufEnd)
+      return write(C);
+    *OutBufCur++ = C;
+    return *this;
+  }
+
+  raw_ostream &operator<<(unsigned char C) {
+    if (OutBufCur >= OutBufEnd)
+      return write(C);
+    *OutBufCur++ = C;
+    return *this;
+  }
+
+  raw_ostream &operator<<(signed char C) {
+    if (OutBufCur >= OutBufEnd)
+      return write(C);
+    *OutBufCur++ = C;
+    return *this;
+  }
+
+  raw_ostream &operator<<(StringRef Str) {
+    // Inline fast path, particularly for strings with a known length.
+    size_t Size = Str.size();
+
+    // Make sure we can use the fast path.
+    if (Size > (size_t)(OutBufEnd - OutBufCur))
+      return write(Str.data(), Size);
+
+    if (Size) {
+      memcpy(OutBufCur, Str.data(), Size);
+      OutBufCur += Size;
+    }
+    return *this;
+  }
+
+  raw_ostream &operator<<(const char *Str) {
+    // Inline fast path, particularly for constant strings where a sufficiently
+    // smart compiler will simplify strlen.
+
+    return this->operator<<(StringRef(Str));
+  }
+
+  raw_ostream &operator<<(const std::string &Str) {
+    // Avoid the fast path, it would only increase code size for a marginal win.
+    return write(Str.data(), Str.length());
+  }
+
+  raw_ostream &operator<<(const SmallVectorImpl<char> &Str) {
+    return write(Str.data(), Str.size());
+  }
+
+  raw_ostream &operator<<(unsigned long N);
+  raw_ostream &operator<<(long N);
+  raw_ostream &operator<<(unsigned long long N);
+  raw_ostream &operator<<(long long N);
+  raw_ostream &operator<<(const void *P);
+
+  raw_ostream &operator<<(unsigned int N) {
+    return this->operator<<(static_cast<unsigned long>(N));
+  }
+
+  raw_ostream &operator<<(int N) {
+    return this->operator<<(static_cast<long>(N));
+  }
+
+  raw_ostream &operator<<(double N);
+
+  /// Output \p N in hexadecimal, without any prefix or padding.
+  raw_ostream &write_hex(unsigned long long N);
+
+  // Change the foreground color of text.
+  raw_ostream &operator<<(Colors C);
+
+  /// Output a formatted UUID with dash separators.
+  using uuid_t = uint8_t[16];
+  raw_ostream &write_uuid(const uuid_t UUID);
+
+  /// Output \p Str, turning '\\', '\t', '\n', '"', and anything that doesn't
+  /// satisfy llvm::isPrint into an escape sequence.
+  raw_ostream &write_escaped(StringRef Str, bool UseHexEscapes = false);
+
+  raw_ostream &write(unsigned char C);
+  raw_ostream &write(const char *Ptr, size_t Size);
+
+  // Formatted output, see the format() function in Support/Format.h.
+  raw_ostream &operator<<(const format_object_base &Fmt);
+
+  // Formatted output, see the leftJustify() function in Support/Format.h.
+  raw_ostream &operator<<(const FormattedString &);
+
+  // Formatted output, see the formatHex() function in Support/Format.h.
+  raw_ostream &operator<<(const FormattedNumber &);
+
+  // Formatted output, see the formatv() function in Support/FormatVariadic.h.
+  raw_ostream &operator<<(const formatv_object_base &);
+
+  // Formatted output, see the format_bytes() function in Support/Format.h.
+  raw_ostream &operator<<(const FormattedBytes &);
+
+  /// indent - Insert 'NumSpaces' spaces.
+  raw_ostream &indent(unsigned NumSpaces);
+
+  /// write_zeros - Insert 'NumZeros' nulls.
+  raw_ostream &write_zeros(unsigned NumZeros);
+
+  /// Changes the foreground color of text that will be output from this point
+  /// forward.
+  /// @param Color ANSI color to use, the special SAVEDCOLOR can be used to
+  /// change only the bold attribute, and keep colors untouched
+  /// @param Bold bold/brighter text, default false
+  /// @param BG if true change the background, default: change foreground
+  /// @returns itself so it can be used within << invocations
+  virtual raw_ostream &changeColor(enum Colors Color,
+                                   bool Bold = false,
+                                   bool BG = false) {
+    (void)Color;
+    (void)Bold;
+    (void)BG;
+    return *this;
+  }
+
+  /// Resets the colors to terminal defaults. Call this when you are done
+  /// outputting colored text, or before program exit.
+  virtual raw_ostream &resetColor() { return *this; }
+
+  /// Reverses the foreground and background colors.
+  virtual raw_ostream &reverseColor() { return *this; }
+
+  /// This function determines if this stream is connected to a "tty" or
+  /// "console" window. That is, the output would be displayed to the user
+  /// rather than being put on a pipe or stored in a file.
+  virtual bool is_displayed() const { return false; }
+
+  /// This function determines if this stream is displayed and supports colors.
+  virtual bool has_colors() const { return is_displayed(); }
+
+  // Enable or disable colors. Once disable_colors() is called,
+  // changeColor() has no effect until enable_colors() is called.
+  virtual void enable_colors(bool /*enable*/) {}
+
+  //===--------------------------------------------------------------------===//
+  // Subclass Interface
+  //===--------------------------------------------------------------------===//
+
+private:
+  /// The is the piece of the class that is implemented by subclasses.  This
+  /// writes the \p Size bytes starting at
+  /// \p Ptr to the underlying stream.
+  ///
+  /// This function is guaranteed to only be called at a point at which it is
+  /// safe for the subclass to install a new buffer via SetBuffer.
+  ///
+  /// \param Ptr The start of the data to be written. For buffered streams this
+  /// is guaranteed to be the start of the buffer.
+  ///
+  /// \param Size The number of bytes to be written.
+  ///
+  /// \invariant { Size > 0 }
+  virtual void write_impl(const char *Ptr, size_t Size) = 0;
+
+  /// Return the current position within the stream, not counting the bytes
+  /// currently in the buffer.
+  virtual uint64_t current_pos() const = 0;
+
+protected:
+  /// Use the provided buffer as the raw_ostream buffer. This is intended for
+  /// use only by subclasses which can arrange for the output to go directly
+  /// into the desired output buffer, instead of being copied on each flush.
+  void SetBuffer(char *BufferStart, size_t Size) {
+    SetBufferAndMode(BufferStart, Size, BufferKind::ExternalBuffer);
+  }
+
+  /// Return an efficient buffer size for the underlying output mechanism.
+  virtual size_t preferred_buffer_size() const;
+
+  /// Return the beginning of the current stream buffer, or 0 if the stream is
+  /// unbuffered.
+  const char *getBufferStart() const { return OutBufStart; }
+
+  //===--------------------------------------------------------------------===//
+  // Private Interface
+  //===--------------------------------------------------------------------===//
+private:
+  /// Install the given buffer and mode.
+  void SetBufferAndMode(char *BufferStart, size_t Size, BufferKind Mode);
+
+  /// Flush the current buffer, which is known to be non-empty. This outputs the
+  /// currently buffered data and resets the buffer to empty.
+  void flush_nonempty();
+
+  /// Copy data into the buffer. Size must not be greater than the number of
+  /// unused bytes in the buffer.
+  void copy_to_buffer(const char *Ptr, size_t Size);
+
+  virtual void anchor();
+};
+
+/// An abstract base class for streams implementations that also support a
+/// pwrite operation. This is useful for code that can mostly stream out data,
+/// but needs to patch in a header that needs to know the output size.
+class raw_pwrite_stream : public raw_ostream {
+  virtual void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) = 0;
+  void anchor() override;
+
+public:
+  explicit raw_pwrite_stream(bool Unbuffered = false)
+      : raw_ostream(Unbuffered) {}
+  void pwrite(const char *Ptr, size_t Size, uint64_t Offset) {
+#ifndef NDEBUG
+    uint64_t Pos = tell();
+    // /dev/null always reports a pos of 0, so we cannot perform this check
+    // in that case.
+    if (Pos)
+      assert(Size + Offset <= Pos && "We don't support extending the stream");
+#endif
+    pwrite_impl(Ptr, Size, Offset);
+  }
+};
+
+//===----------------------------------------------------------------------===//
+// File Output Streams
+//===----------------------------------------------------------------------===//
+
+/// A raw_ostream that writes to a file descriptor.
+///
+class raw_fd_ostream : public raw_pwrite_stream {
+  int FD;
+  bool ShouldClose;
+  bool SupportsSeeking = false;
+  bool ColorEnabled = true;
+
+#ifdef _WIN32
+  /// True if this fd refers to a Windows console device. Mintty and other
+  /// terminal emulators are TTYs, but they are not consoles.
+  bool IsWindowsConsole = false;
+#endif
+
+  std::error_code EC;
+
+  uint64_t pos = 0;
+
+  /// See raw_ostream::write_impl.
+  void write_impl(const char *Ptr, size_t Size) override;
+
+  void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
+
+  /// Return the current position within the stream, not counting the bytes
+  /// currently in the buffer.
+  uint64_t current_pos() const override { return pos; }
+
+  /// Determine an efficient buffer size.
+  size_t preferred_buffer_size() const override;
+
+  /// Set the flag indicating that an output error has been encountered.
+  void error_detected(std::error_code EC) { this->EC = EC; }
+
+  void anchor() override;
+
+public:
+  /// Open the specified file for writing. If an error occurs, information
+  /// about the error is put into EC, and the stream should be immediately
+  /// destroyed;
+  /// \p Flags allows optional flags to control how the file will be opened.
+  ///
+  /// As a special case, if Filename is "-", then the stream will use
+  /// STDOUT_FILENO instead of opening a file. This will not close the stdout
+  /// descriptor.
+  raw_fd_ostream(StringRef Filename, std::error_code &EC);
+  raw_fd_ostream(StringRef Filename, std::error_code &EC,
+                 sys::fs::CreationDisposition Disp);
+  raw_fd_ostream(StringRef Filename, std::error_code &EC,
+                 sys::fs::FileAccess Access);
+  raw_fd_ostream(StringRef Filename, std::error_code &EC,
+                 sys::fs::OpenFlags Flags);
+  raw_fd_ostream(StringRef Filename, std::error_code &EC,
+                 sys::fs::CreationDisposition Disp, sys::fs::FileAccess Access,
+                 sys::fs::OpenFlags Flags);
+
+  /// FD is the file descriptor that this writes to.  If ShouldClose is true,
+  /// this closes the file when the stream is destroyed. If FD is for stdout or
+  /// stderr, it will not be closed.
+  raw_fd_ostream(int fd, bool shouldClose, bool unbuffered=false);
+
+  ~raw_fd_ostream() override;
+
+  /// Manually flush the stream and close the file. Note that this does not call
+  /// fsync.
+  void close();
+
+  bool supportsSeeking() { return SupportsSeeking; }
+
+  /// Flushes the stream and repositions the underlying file descriptor position
+  /// to the offset specified from the beginning of the file.
+  uint64_t seek(uint64_t off);
+
+  raw_ostream &changeColor(enum Colors colors, bool bold=false,
+                           bool bg=false) override;
+  raw_ostream &resetColor() override;
+
+  raw_ostream &reverseColor() override;
+
+  bool is_displayed() const override;
+
+  bool has_colors() const override;
+
+  void enable_colors(bool enable) override { ColorEnabled = enable; }
+
+  std::error_code error() const { return EC; }
+
+  /// Return the value of the flag in this raw_fd_ostream indicating whether an
+  /// output error has been encountered.
+  /// This doesn't implicitly flush any pending output.  Also, it doesn't
+  /// guarantee to detect all errors unless the stream has been closed.
+  bool has_error() const { return bool(EC); }
+
+  /// Set the flag read by has_error() to false. If the error flag is set at the
+  /// time when this raw_ostream's destructor is called, report_fatal_error is
+  /// called to report the error. Use clear_error() after handling the error to
+  /// avoid this behavior.
+  ///
+  ///   "Errors should never pass silently.
+  ///    Unless explicitly silenced."
+  ///      - from The Zen of Python, by Tim Peters
+  ///
+  void clear_error() { EC = std::error_code(); }
+};
+
+/// This returns a reference to a raw_ostream for standard output. Use it like:
+/// outs() << "foo" << "bar";
+raw_ostream &outs();
+
+/// This returns a reference to a raw_ostream for standard error. Use it like:
+/// errs() << "foo" << "bar";
+raw_ostream &errs();
+
+/// This returns a reference to a raw_ostream which simply discards output.
+raw_ostream &nulls();
+
+//===----------------------------------------------------------------------===//
+// Output Stream Adaptors
+//===----------------------------------------------------------------------===//
+
+/// A raw_ostream that writes to an std::string.  This is a simple adaptor
+/// class. This class does not encounter output errors.
+class raw_string_ostream : public raw_ostream {
+  std::string &OS;
+
+  /// See raw_ostream::write_impl.
+  void write_impl(const char *Ptr, size_t Size) override;
+
+  /// Return the current position within the stream, not counting the bytes
+  /// currently in the buffer.
+  uint64_t current_pos() const override { return OS.size(); }
+
+public:
+  explicit raw_string_ostream(std::string &O) : OS(O) {}
+  ~raw_string_ostream() override;
+
+  /// Flushes the stream contents to the target string and returns  the string's
+  /// reference.
+  std::string& str() {
+    flush();
+    return OS;
+  }
+};
+
+/// A raw_ostream that writes to an SmallVector or SmallString.  This is a
+/// simple adaptor class. This class does not encounter output errors.
+/// raw_svector_ostream operates without a buffer, delegating all memory
+/// management to the SmallString. Thus the SmallString is always up-to-date,
+/// may be used directly and there is no need to call flush().
+class raw_svector_ostream : public raw_pwrite_stream {
+  SmallVectorImpl<char> &OS;
+
+  /// See raw_ostream::write_impl.
+  void write_impl(const char *Ptr, size_t Size) override;
+
+  void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
+
+  /// Return the current position within the stream.
+  uint64_t current_pos() const override;
+
+public:
+  /// Construct a new raw_svector_ostream.
+  ///
+  /// \param O The vector to write to; this should generally have at least 128
+  /// bytes free to avoid any extraneous memory overhead.
+  explicit raw_svector_ostream(SmallVectorImpl<char> &O) : OS(O) {
+    SetUnbuffered();
+  }
+
+  ~raw_svector_ostream() override = default;
+
+  void flush() = delete;
+
+  /// Return a StringRef for the vector contents.
+  StringRef str() { return StringRef(OS.data(), OS.size()); }
+};
+
+/// A raw_ostream that discards all output.
+class raw_null_ostream : public raw_pwrite_stream {
+  /// See raw_ostream::write_impl.
+  void write_impl(const char *Ptr, size_t size) override;
+  void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
+
+  /// Return the current position within the stream, not counting the bytes
+  /// currently in the buffer.
+  uint64_t current_pos() const override;
+
+public:
+  explicit raw_null_ostream() = default;
+  ~raw_null_ostream() override;
+};
+
+class buffer_ostream : public raw_svector_ostream {
+  raw_ostream &OS;
+  SmallVector<char, 0> Buffer;
+
+  virtual void anchor() override;
+
+public:
+  buffer_ostream(raw_ostream &OS) : raw_svector_ostream(Buffer), OS(OS) {}
+  ~buffer_ostream() override { OS << str(); }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_RAW_OSTREAM_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/Support/type_traits.h b/binaryen/third_party/llvm-project/include/llvm/Support/type_traits.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/Support/type_traits.h
@@ -0,0 +1,192 @@
+//===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides useful additions to the standard type_traits library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_TYPE_TRAITS_H
+#define LLVM_SUPPORT_TYPE_TRAITS_H
+
+#include "llvm/Support/Compiler.h"
+#include <type_traits>
+#include <utility>
+
+namespace llvm {
+
+
+/// Metafunction that determines whether the given type is either an
+/// integral type or an enumeration type, including enum classes.
+///
+/// Note that this accepts potentially more integral types than is_integral
+/// because it is based on being implicitly convertible to an integral type.
+/// Also note that enum classes aren't implicitly convertible to integral types,
+/// the value may therefore need to be explicitly converted before being used.
+template <typename T> class is_integral_or_enum {
+  using UnderlyingT = typename std::remove_reference<T>::type;
+
+public:
+  static const bool value =
+      !std::is_class<UnderlyingT>::value && // Filter conversion operators.
+      !std::is_pointer<UnderlyingT>::value &&
+      !std::is_floating_point<UnderlyingT>::value &&
+      (std::is_enum<UnderlyingT>::value ||
+       std::is_convertible<UnderlyingT, unsigned long long>::value);
+};
+
+/// If T is a pointer, just return it. If it is not, return T&.
+template<typename T, typename Enable = void>
+struct add_lvalue_reference_if_not_pointer { using type = T &; };
+
+template <typename T>
+struct add_lvalue_reference_if_not_pointer<
+    T, typename std::enable_if<std::is_pointer<T>::value>::type> {
+  using type = T;
+};
+
+/// If T is a pointer to X, return a pointer to const X. If it is not,
+/// return const T.
+template<typename T, typename Enable = void>
+struct add_const_past_pointer { using type = const T; };
+
+template <typename T>
+struct add_const_past_pointer<
+    T, typename std::enable_if<std::is_pointer<T>::value>::type> {
+  using type = const typename std::remove_pointer<T>::type *;
+};
+
+template <typename T, typename Enable = void>
+struct const_pointer_or_const_ref {
+  using type = const T &;
+};
+template <typename T>
+struct const_pointer_or_const_ref<
+    T, typename std::enable_if<std::is_pointer<T>::value>::type> {
+  using type = typename add_const_past_pointer<T>::type;
+};
+
+namespace detail {
+/// Internal utility to detect trivial copy construction.
+template<typename T> union copy_construction_triviality_helper {
+    T t;
+    copy_construction_triviality_helper() = default;
+    copy_construction_triviality_helper(const copy_construction_triviality_helper&) = default;
+    ~copy_construction_triviality_helper() = default;
+};
+/// Internal utility to detect trivial move construction.
+template<typename T> union move_construction_triviality_helper {
+    T t;
+    move_construction_triviality_helper() = default;
+    move_construction_triviality_helper(move_construction_triviality_helper&&) = default;
+    ~move_construction_triviality_helper() = default;
+};
+
+template<class T>
+union trivial_helper {
+    T t;
+};
+
+} // end namespace detail
+
+/// An implementation of `std::is_trivially_copy_constructible` since we have
+/// users with STLs that don't yet include it.
+template <typename T>
+struct is_trivially_copy_constructible
+    : std::is_copy_constructible<
+          ::llvm::detail::copy_construction_triviality_helper<T>> {};
+template <typename T>
+struct is_trivially_copy_constructible<T &> : std::true_type {};
+template <typename T>
+struct is_trivially_copy_constructible<T &&> : std::false_type {};
+
+/// An implementation of `std::is_trivially_move_constructible` since we have
+/// users with STLs that don't yet include it.
+template <typename T>
+struct is_trivially_move_constructible
+    : std::is_move_constructible<
+          ::llvm::detail::move_construction_triviality_helper<T>> {};
+template <typename T>
+struct is_trivially_move_constructible<T &> : std::true_type {};
+template <typename T>
+struct is_trivially_move_constructible<T &&> : std::true_type {};
+
+
+template <typename T>
+struct is_copy_assignable {
+  template<class F>
+    static auto get(F*) -> decltype(std::declval<F &>() = std::declval<const F &>(), std::true_type{});
+    static std::false_type get(...);
+    static constexpr bool value = decltype(get((T*)nullptr))::value;
+};
+
+template <typename T>
+struct is_move_assignable {
+  template<class F>
+    static auto get(F*) -> decltype(std::declval<F &>() = std::declval<F &&>(), std::true_type{});
+    static std::false_type get(...);
+    static constexpr bool value = decltype(get((T*)nullptr))::value;
+};
+
+
+// An implementation of `std::is_trivially_copyable` since STL version
+// is not equally supported by all compilers, especially GCC 4.9.
+// Uniform implementation of this trait is important for ABI compatibility
+// as it has an impact on SmallVector's ABI (among others).
+template <typename T>
+class is_trivially_copyable {
+
+  // copy constructors
+  static constexpr bool has_trivial_copy_constructor =
+      std::is_copy_constructible<detail::trivial_helper<T>>::value;
+  static constexpr bool has_deleted_copy_constructor =
+      !std::is_copy_constructible<T>::value;
+
+  // move constructors
+  static constexpr bool has_trivial_move_constructor =
+      std::is_move_constructible<detail::trivial_helper<T>>::value;
+  static constexpr bool has_deleted_move_constructor =
+      !std::is_move_constructible<T>::value;
+
+  // copy assign
+  static constexpr bool has_trivial_copy_assign =
+      is_copy_assignable<detail::trivial_helper<T>>::value;
+  static constexpr bool has_deleted_copy_assign =
+      !is_copy_assignable<T>::value;
+
+  // move assign
+  static constexpr bool has_trivial_move_assign =
+      is_move_assignable<detail::trivial_helper<T>>::value;
+  static constexpr bool has_deleted_move_assign =
+      !is_move_assignable<T>::value;
+
+  // destructor
+  static constexpr bool has_trivial_destructor =
+      std::is_destructible<detail::trivial_helper<T>>::value;
+
+  public:
+
+  static constexpr bool value =
+      has_trivial_destructor &&
+      (has_deleted_move_assign || has_trivial_move_assign) &&
+      (has_deleted_move_constructor || has_trivial_move_constructor) &&
+      (has_deleted_copy_assign || has_trivial_copy_assign) &&
+      (has_deleted_copy_constructor || has_trivial_copy_constructor);
+
+#ifdef HAVE_STD_IS_TRIVIALLY_COPYABLE
+  static_assert(value == std::is_trivially_copyable<T>::value,
+                "inconsistent behavior between llvm:: and std:: implementation of is_trivially_copyable");
+#endif
+};
+template <typename T>
+class is_trivially_copyable<T*> : public std::true_type {
+};
+
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_TYPE_TRAITS_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/include/llvm/DebugInfo/DWARFContext.h b/binaryen/third_party/llvm-project/include/llvm/include/llvm/DebugInfo/DWARFContext.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/include/llvm/DebugInfo/DWARFContext.h
@@ -0,0 +1,382 @@
+//===- DWARFContext.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===/
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H
+#define LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H
+
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h"
+#include "llvm/DebugInfo/DWARF/DWARFObject.h"
+#include "llvm/DebugInfo/DWARF/DWARFSection.h"
+#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Host.h"
+#include <cstdint>
+#include <deque>
+#include <map>
+#include <memory>
+
+namespace llvm {
+
+class MCRegisterInfo;
+class MemoryBuffer;
+class raw_ostream;
+
+/// Used as a return value for a error callback passed to DWARF context.
+/// Callback should return Halt if client application wants to stop
+/// object parsing, or should return Continue otherwise.
+enum class ErrorPolicy { Halt, Continue };
+
+/// DWARFContext
+/// This data structure is the top level entity that deals with dwarf debug
+/// information parsing. The actual data is supplied through DWARFObj.
+class DWARFContext : public DIContext {
+  DWARFUnitVector NormalUnits;
+  std::unique_ptr<DWARFUnitIndex> CUIndex;
+  std::unique_ptr<DWARFGdbIndex> GdbIndex;
+  std::unique_ptr<DWARFUnitIndex> TUIndex;
+  std::unique_ptr<DWARFDebugAbbrev> Abbrev;
+  std::unique_ptr<DWARFDebugLoc> Loc;
+  std::unique_ptr<DWARFDebugAranges> Aranges;
+  std::unique_ptr<DWARFDebugLine> Line;
+  std::unique_ptr<DWARFDebugFrame> DebugFrame;
+  std::unique_ptr<DWARFDebugFrame> EHFrame;
+  std::unique_ptr<DWARFDebugMacro> Macro;
+  std::unique_ptr<DWARFDebugNames> Names;
+  std::unique_ptr<AppleAcceleratorTable> AppleNames;
+  std::unique_ptr<AppleAcceleratorTable> AppleTypes;
+  std::unique_ptr<AppleAcceleratorTable> AppleNamespaces;
+  std::unique_ptr<AppleAcceleratorTable> AppleObjC;
+
+  DWARFUnitVector DWOUnits;
+  std::unique_ptr<DWARFDebugAbbrev> AbbrevDWO;
+
+  /// The maximum DWARF version of all units.
+  unsigned MaxVersion = 0;
+
+  struct DWOFile {
+    object::OwningBinary<object::ObjectFile> File;
+    std::unique_ptr<DWARFContext> Context;
+  };
+  StringMap<std::weak_ptr<DWOFile>> DWOFiles;
+  std::weak_ptr<DWOFile> DWP;
+  bool CheckedForDWP = false;
+  std::string DWPName;
+
+  std::unique_ptr<MCRegisterInfo> RegInfo;
+
+  /// Read compile units from the debug_info section (if necessary)
+  /// and type units from the debug_types sections (if necessary)
+  /// and store them in NormalUnits.
+  void parseNormalUnits();
+
+  /// Read compile units from the debug_info.dwo section (if necessary)
+  /// and type units from the debug_types.dwo section (if necessary)
+  /// and store them in DWOUnits.
+  /// If \p Lazy is true, set up to parse but don't actually parse them.
+  enum { EagerParse = false, LazyParse = true };
+  void parseDWOUnits(bool Lazy = false);
+
+  std::unique_ptr<const DWARFObject> DObj;
+
+public:
+  DWARFContext(std::unique_ptr<const DWARFObject> DObj,
+               std::string DWPName = "");
+  ~DWARFContext();
+
+  DWARFContext(DWARFContext &) = delete;
+  DWARFContext &operator=(DWARFContext &) = delete;
+
+  const DWARFObject &getDWARFObj() const { return *DObj; }
+
+  static bool classof(const DIContext *DICtx) {
+    return DICtx->getKind() == CK_DWARF;
+  }
+
+  /// Dump a textual representation to \p OS. If any \p DumpOffsets are present,
+  /// dump only the record at the specified offset.
+  void dump(raw_ostream &OS, DIDumpOptions DumpOpts,
+            std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets);
+
+  void dump(raw_ostream &OS, DIDumpOptions DumpOpts) override {
+    std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets;
+    dump(OS, DumpOpts, DumpOffsets);
+  }
+
+  bool verify(raw_ostream &OS, DIDumpOptions DumpOpts = {}) override;
+
+  using unit_iterator_range = DWARFUnitVector::iterator_range;
+
+  /// Get units from .debug_info in this context.
+  unit_iterator_range info_section_units() {
+    parseNormalUnits();
+    return unit_iterator_range(NormalUnits.begin(),
+                               NormalUnits.begin() +
+                                   NormalUnits.getNumInfoUnits());
+  }
+
+  /// Get units from .debug_types in this context.
+  unit_iterator_range types_section_units() {
+    parseNormalUnits();
+    return unit_iterator_range(
+        NormalUnits.begin() + NormalUnits.getNumInfoUnits(), NormalUnits.end());
+  }
+
+  /// Get compile units in this context.
+  unit_iterator_range compile_units() { return info_section_units(); }
+
+  /// Get type units in this context.
+  unit_iterator_range type_units() { return types_section_units(); }
+
+  /// Get all normal compile/type units in this context.
+  unit_iterator_range normal_units() {
+    parseNormalUnits();
+    return unit_iterator_range(NormalUnits.begin(), NormalUnits.end());
+  }
+
+  /// Get units from .debug_info..dwo in the DWO context.
+  unit_iterator_range dwo_info_section_units() {
+    parseDWOUnits();
+    return unit_iterator_range(DWOUnits.begin(),
+                               DWOUnits.begin() + DWOUnits.getNumInfoUnits());
+  }
+
+  /// Get units from .debug_types.dwo in the DWO context.
+  unit_iterator_range dwo_types_section_units() {
+    parseDWOUnits();
+    return unit_iterator_range(DWOUnits.begin() + DWOUnits.getNumInfoUnits(),
+                               DWOUnits.end());
+  }
+
+  /// Get compile units in the DWO context.
+  unit_iterator_range dwo_compile_units() { return dwo_info_section_units(); }
+
+  /// Get type units in the DWO context.
+  unit_iterator_range dwo_type_units() { return dwo_types_section_units(); }
+
+  /// Get all units in the DWO context.
+  unit_iterator_range dwo_units() {
+    parseDWOUnits();
+    return unit_iterator_range(DWOUnits.begin(), DWOUnits.end());
+  }
+
+  /// Get the number of compile units in this context.
+  unsigned getNumCompileUnits() {
+    parseNormalUnits();
+    return NormalUnits.getNumInfoUnits();
+  }
+
+  /// Get the number of type units in this context.
+  unsigned getNumTypeUnits() {
+    parseNormalUnits();
+    return NormalUnits.getNumTypesUnits();
+  }
+
+  /// Get the number of compile units in the DWO context.
+  unsigned getNumDWOCompileUnits() {
+    parseDWOUnits();
+    return DWOUnits.getNumInfoUnits();
+  }
+
+  /// Get the number of type units in the DWO context.
+  unsigned getNumDWOTypeUnits() {
+    parseDWOUnits();
+    return DWOUnits.getNumTypesUnits();
+  }
+
+  /// Get the unit at the specified index.
+  DWARFUnit *getUnitAtIndex(unsigned index) {
+    parseNormalUnits();
+    return NormalUnits[index].get();
+  }
+
+  /// Get the unit at the specified index for the DWO units.
+  DWARFUnit *getDWOUnitAtIndex(unsigned index) {
+    parseDWOUnits();
+    return DWOUnits[index].get();
+  }
+
+  DWARFCompileUnit *getDWOCompileUnitForHash(uint64_t Hash);
+
+  /// Return the compile unit that includes an offset (relative to .debug_info).
+  DWARFCompileUnit *getCompileUnitForOffset(uint64_t Offset);
+
+  /// Get a DIE given an exact offset.
+  DWARFDie getDIEForOffset(uint64_t Offset);
+
+  unsigned getMaxVersion() {
+    // Ensure info units have been parsed to discover MaxVersion
+    info_section_units();
+    return MaxVersion;
+  }
+
+  unsigned getMaxDWOVersion() {
+    // Ensure DWO info units have been parsed to discover MaxVersion
+    dwo_info_section_units();
+    return MaxVersion;
+  }
+
+  void setMaxVersionIfGreater(unsigned Version) {
+    if (Version > MaxVersion)
+      MaxVersion = Version;
+  }
+
+  const DWARFUnitIndex &getCUIndex();
+  DWARFGdbIndex &getGdbIndex();
+  const DWARFUnitIndex &getTUIndex();
+
+  /// Get a pointer to the parsed DebugAbbrev object.
+  const DWARFDebugAbbrev *getDebugAbbrev();
+
+  /// Get a pointer to the parsed DebugLoc object.
+  const DWARFDebugLoc *getDebugLoc();
+
+  /// Get a pointer to the parsed dwo abbreviations object.
+  const DWARFDebugAbbrev *getDebugAbbrevDWO();
+
+  /// Get a pointer to the parsed DebugAranges object.
+  const DWARFDebugAranges *getDebugAranges();
+
+  /// Get a pointer to the parsed frame information object.
+  const DWARFDebugFrame *getDebugFrame();
+
+  /// Get a pointer to the parsed eh frame information object.
+  const DWARFDebugFrame *getEHFrame();
+
+  /// Get a pointer to the parsed DebugMacro object.
+  const DWARFDebugMacro *getDebugMacro();
+
+  /// Get a reference to the parsed accelerator table object.
+  const DWARFDebugNames &getDebugNames();
+
+  /// Get a reference to the parsed accelerator table object.
+  const AppleAcceleratorTable &getAppleNames();
+
+  /// Get a reference to the parsed accelerator table object.
+  const AppleAcceleratorTable &getAppleTypes();
+
+  /// Get a reference to the parsed accelerator table object.
+  const AppleAcceleratorTable &getAppleNamespaces();
+
+  /// Get a reference to the parsed accelerator table object.
+  const AppleAcceleratorTable &getAppleObjC();
+
+  /// Get a pointer to a parsed line table corresponding to a compile unit.
+  /// Report any parsing issues as warnings on stderr.
+  const DWARFDebugLine::LineTable *getLineTableForUnit(DWARFUnit *U);
+
+  /// Get a pointer to a parsed line table corresponding to a compile unit.
+  /// Report any recoverable parsing problems using the callback.
+  Expected<const DWARFDebugLine::LineTable *>
+  getLineTableForUnit(DWARFUnit *U,
+                      std::function<void(Error)> RecoverableErrorCallback);
+
+  DataExtractor getStringExtractor() const {
+    return DataExtractor(DObj->getStrSection(), false, 0);
+  }
+  DataExtractor getLineStringExtractor() const {
+    return DataExtractor(DObj->getLineStrSection(), false, 0);
+  }
+
+  /// Wraps the returned DIEs for a given address.
+  struct DIEsForAddress {
+    DWARFCompileUnit *CompileUnit = nullptr;
+    DWARFDie FunctionDIE;
+    DWARFDie BlockDIE;
+    explicit operator bool() const { return CompileUnit != nullptr; }
+  };
+
+  /// Get the compilation unit, the function DIE and lexical block DIE for the
+  /// given address where applicable.
+  /// TODO: change input parameter from "uint64_t Address"
+  ///       into "SectionedAddress Address"
+  DIEsForAddress getDIEsForAddress(uint64_t Address);
+
+  DILineInfo getLineInfoForAddress(
+      object::SectionedAddress Address,
+      DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
+  DILineInfoTable getLineInfoForAddressRange(
+      object::SectionedAddress Address, uint64_t Size,
+      DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
+  DIInliningInfo getInliningInfoForAddress(
+      object::SectionedAddress Address,
+      DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
+
+  std::vector<DILocal>
+  getLocalsForAddress(object::SectionedAddress Address) override;
+
+  bool isLittleEndian() const { return DObj->isLittleEndian(); }
+  static bool isSupportedVersion(unsigned version) {
+    return version == 2 || version == 3 || version == 4 || version == 5;
+  }
+
+  std::shared_ptr<DWARFContext> getDWOContext(StringRef AbsolutePath);
+
+  const MCRegisterInfo *getRegisterInfo() const { return RegInfo.get(); }
+
+  /// Function used to handle default error reporting policy. Prints a error
+  /// message and returns Continue, so DWARF context ignores the error.
+  static ErrorPolicy defaultErrorHandler(Error E);
+  static std::unique_ptr<DWARFContext>
+  create(const object::ObjectFile &Obj, const LoadedObjectInfo *L = nullptr,
+         function_ref<ErrorPolicy(Error)> HandleError = defaultErrorHandler,
+         std::string DWPName = "");
+
+  static std::unique_ptr<DWARFContext>
+  create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
+         uint8_t AddrSize, bool isLittleEndian = sys::IsLittleEndianHost);
+
+  /// Loads register info for the architecture of the provided object file.
+  /// Improves readability of dumped DWARF expressions. Requires the caller to
+  /// have initialized the relevant target descriptions.
+  Error loadRegisterInfo(const object::ObjectFile &Obj);
+
+  /// Get address size from CUs.
+  /// TODO: refactor compile_units() to make this const.
+  uint8_t getCUAddrSize();
+
+  /// Dump Error as warning message to stderr.
+  static void dumpWarning(Error Warning);
+
+  Triple::ArchType getArch() const {
+    return getDWARFObj().getFile()->getArch();
+  }
+
+private:
+  /// Return the compile unit which contains instruction with provided
+  /// address.
+  /// TODO: change input parameter from "uint64_t Address"
+  ///       into "SectionedAddress Address"
+  DWARFCompileUnit *getCompileUnitForAddress(uint64_t Address);
+  void addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, DWARFDie Die,
+                       std::vector<DILocal> &Result);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H
diff --git a/binaryen/third_party/llvm-project/include/llvm/readme.txt b/binaryen/third_party/llvm-project/include/llvm/readme.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/include/llvm/readme.txt
@@ -0,0 +1,15 @@
+This folder contains files from LLVM. See LICENSE.TXT for their license.
+
+These files were synced from
+
+commit 6c86d6efaf129c42d37121f1e7e9a7adffb54c1a (origin/master, master)
+Author: Craig Topper <craig.topper@intel.com>
+Date:   Mon Nov 11 16:30:42 2019 -0800
+
+    [X86] Remove some else branches after checking for !useSoftFloat() that set operations to Expand.
+    
+    If we're using soft floats, then these operations shoudl be
+    softened during type legalization. They'll never get to
+    LegalizeVectorOps or LegalizeDAG so they don't need to be
+    Expanded there.
+
diff --git a/binaryen/third_party/llvm-project/obj2yaml_Error.cpp b/binaryen/third_party/llvm-project/obj2yaml_Error.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/obj2yaml_Error.cpp
@@ -0,0 +1,61 @@
+//===- Error.cpp - system_error extensions for obj2yaml ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+namespace {
+// FIXME: This class is only here to support the transition to llvm::Error. It
+// will be removed once this transition is complete. Clients should prefer to
+// deal with the Error value directly, rather than converting to error_code.
+class _obj2yaml_error_category : public std::error_category {
+public:
+  const char *name() const noexcept override;
+  std::string message(int ev) const override;
+};
+} // namespace
+
+const char *_obj2yaml_error_category::name() const noexcept {
+  return "obj2yaml";
+}
+
+std::string _obj2yaml_error_category::message(int ev) const {
+  switch (static_cast<obj2yaml_error>(ev)) {
+  case obj2yaml_error::success:
+    return "Success";
+  case obj2yaml_error::file_not_found:
+    return "No such file.";
+  case obj2yaml_error::unrecognized_file_format:
+    return "Unrecognized file type.";
+  case obj2yaml_error::unsupported_obj_file_format:
+    return "Unsupported object file format.";
+  case obj2yaml_error::not_implemented:
+    return "Feature not yet implemented.";
+  }
+  llvm_unreachable("An enumerator of obj2yaml_error does not have a message "
+                   "defined.");
+}
+
+namespace llvm {
+
+const std::error_category &obj2yaml_category() {
+  static _obj2yaml_error_category o;
+  return o;
+}
+
+char Obj2YamlError::ID = 0;
+
+void Obj2YamlError::log(raw_ostream &OS) const { OS << ErrMsg; }
+
+std::error_code Obj2YamlError::convertToErrorCode() const {
+  return std::error_code(static_cast<int>(Code), obj2yaml_category());
+}
+
+} // namespace llvm
diff --git a/binaryen/third_party/llvm-project/raw_ostream.cpp b/binaryen/third_party/llvm-project/raw_ostream.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/raw_ostream.cpp
@@ -0,0 +1,712 @@
+//===--- raw_ostream.cpp - Implement the raw_ostream classes --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This implements support for bulk buffered stream output.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/NativeFormatting.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Program.h"
+#include <algorithm>
+#include <cctype>
+#include <cerrno>
+#include <cstdio>
+#include <iterator>
+#include <sys/stat.h>
+#include <system_error>
+
+// XXX BINARYEn
+#include <iostream>
+
+// <fcntl.h> may provide O_BINARY.
+#if defined(HAVE_FCNTL_H)
+# include <fcntl.h>
+#endif
+
+#if defined(HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#if defined(__CYGWIN__)
+#include <io.h>
+#endif
+
+#if defined(_MSC_VER)
+#include <io.h>
+#ifndef STDIN_FILENO
+# define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO 1
+#endif
+#ifndef STDERR_FILENO
+# define STDERR_FILENO 2
+#endif
+#endif
+
+#if 0 // XXX BINARYEN def _WIN32
+#include "llvm/Support/ConvertUTF.h"
+#include "Windows/WindowsSupport.h"
+#endif
+
+using namespace llvm;
+
+const raw_ostream::Colors raw_ostream::BLACK;
+const raw_ostream::Colors raw_ostream::RED;
+const raw_ostream::Colors raw_ostream::GREEN;
+const raw_ostream::Colors raw_ostream::YELLOW;
+const raw_ostream::Colors raw_ostream::BLUE;
+const raw_ostream::Colors raw_ostream::MAGENTA;
+const raw_ostream::Colors raw_ostream::CYAN;
+const raw_ostream::Colors raw_ostream::WHITE;
+const raw_ostream::Colors raw_ostream::SAVEDCOLOR;
+const raw_ostream::Colors raw_ostream::RESET;
+
+raw_ostream::~raw_ostream() {
+  // raw_ostream's subclasses should take care to flush the buffer
+  // in their destructors.
+  assert(OutBufCur == OutBufStart &&
+         "raw_ostream destructor called with non-empty buffer!");
+
+  if (BufferMode == BufferKind::InternalBuffer)
+    delete [] OutBufStart;
+}
+
+size_t raw_ostream::preferred_buffer_size() const {
+  // BUFSIZ is intended to be a reasonable default.
+  return BUFSIZ;
+}
+
+void raw_ostream::SetBuffered() {
+  // Ask the subclass to determine an appropriate buffer size.
+  if (size_t Size = preferred_buffer_size())
+    SetBufferSize(Size);
+  else
+    // It may return 0, meaning this stream should be unbuffered.
+    SetUnbuffered();
+}
+
+void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size,
+                                   BufferKind Mode) {
+  assert(((Mode == BufferKind::Unbuffered && !BufferStart && Size == 0) ||
+          (Mode != BufferKind::Unbuffered && BufferStart && Size != 0)) &&
+         "stream must be unbuffered or have at least one byte");
+  // Make sure the current buffer is free of content (we can't flush here; the
+  // child buffer management logic will be in write_impl).
+  assert(GetNumBytesInBuffer() == 0 && "Current buffer is non-empty!");
+
+  if (BufferMode == BufferKind::InternalBuffer)
+    delete [] OutBufStart;
+  OutBufStart = BufferStart;
+  OutBufEnd = OutBufStart+Size;
+  OutBufCur = OutBufStart;
+  BufferMode = Mode;
+
+  assert(OutBufStart <= OutBufEnd && "Invalid size!");
+}
+
+raw_ostream &raw_ostream::operator<<(unsigned long N) {
+  write_integer(*this, static_cast<uint64_t>(N), 0, IntegerStyle::Integer);
+  return *this;
+}
+
+raw_ostream &raw_ostream::operator<<(long N) {
+  write_integer(*this, static_cast<int64_t>(N), 0, IntegerStyle::Integer);
+  return *this;
+}
+
+raw_ostream &raw_ostream::operator<<(unsigned long long N) {
+  write_integer(*this, static_cast<uint64_t>(N), 0, IntegerStyle::Integer);
+  return *this;
+}
+
+raw_ostream &raw_ostream::operator<<(long long N) {
+  write_integer(*this, static_cast<int64_t>(N), 0, IntegerStyle::Integer);
+  return *this;
+}
+
+raw_ostream &raw_ostream::write_hex(unsigned long long N) {
+  llvm::write_hex(*this, N, HexPrintStyle::Lower);
+  return *this;
+}
+
+raw_ostream &raw_ostream::operator<<(Colors C) {
+  if (C == Colors::RESET)
+    resetColor();
+  else
+    changeColor(C);
+  return *this;
+}
+
+raw_ostream &raw_ostream::write_uuid(const uuid_t UUID) {
+  for (int Idx = 0; Idx < 16; ++Idx) {
+    *this << format("%02" PRIX32, UUID[Idx]);
+    if (Idx == 3 || Idx == 5 || Idx == 7 || Idx == 9)
+      *this << "-";
+  }
+  return *this;
+}
+
+
+raw_ostream &raw_ostream::write_escaped(StringRef Str,
+                                        bool UseHexEscapes) {
+  for (unsigned char c : Str) {
+    switch (c) {
+    case '\\':
+      *this << '\\' << '\\';
+      break;
+    case '\t':
+      *this << '\\' << 't';
+      break;
+    case '\n':
+      *this << '\\' << 'n';
+      break;
+    case '"':
+      *this << '\\' << '"';
+      break;
+    default:
+      if (isPrint(c)) {
+        *this << c;
+        break;
+      }
+
+      // Write out the escaped representation.
+      if (UseHexEscapes) {
+        *this << '\\' << 'x';
+        *this << hexdigit((c >> 4 & 0xF));
+        *this << hexdigit((c >> 0) & 0xF);
+      } else {
+        // Always use a full 3-character octal escape.
+        *this << '\\';
+        *this << char('0' + ((c >> 6) & 7));
+        *this << char('0' + ((c >> 3) & 7));
+        *this << char('0' + ((c >> 0) & 7));
+      }
+    }
+  }
+
+  return *this;
+}
+
+raw_ostream &raw_ostream::operator<<(const void *P) {
+  llvm::write_hex(*this, (uintptr_t)P, HexPrintStyle::PrefixLower);
+  return *this;
+}
+
+raw_ostream &raw_ostream::operator<<(double N) {
+  llvm::write_double(*this, N, FloatStyle::Exponent);
+  return *this;
+}
+
+void raw_ostream::flush_nonempty() {
+  assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty.");
+  size_t Length = OutBufCur - OutBufStart;
+  OutBufCur = OutBufStart;
+  write_impl(OutBufStart, Length);
+}
+
+raw_ostream &raw_ostream::write(unsigned char C) {
+  // Group exceptional cases into a single branch.
+  if (LLVM_UNLIKELY(OutBufCur >= OutBufEnd)) {
+    if (LLVM_UNLIKELY(!OutBufStart)) {
+      if (BufferMode == BufferKind::Unbuffered) {
+        write_impl(reinterpret_cast<char*>(&C), 1);
+        return *this;
+      }
+      // Set up a buffer and start over.
+      SetBuffered();
+      return write(C);
+    }
+
+    flush_nonempty();
+  }
+
+  *OutBufCur++ = C;
+  return *this;
+}
+
+raw_ostream &raw_ostream::write(const char *Ptr, size_t Size) {
+  // Group exceptional cases into a single branch.
+  if (LLVM_UNLIKELY(size_t(OutBufEnd - OutBufCur) < Size)) {
+    if (LLVM_UNLIKELY(!OutBufStart)) {
+      if (BufferMode == BufferKind::Unbuffered) {
+        write_impl(Ptr, Size);
+        return *this;
+      }
+      // Set up a buffer and start over.
+      SetBuffered();
+      return write(Ptr, Size);
+    }
+
+    size_t NumBytes = OutBufEnd - OutBufCur;
+
+    // If the buffer is empty at this point we have a string that is larger
+    // than the buffer. Directly write the chunk that is a multiple of the
+    // preferred buffer size and put the remainder in the buffer.
+    if (LLVM_UNLIKELY(OutBufCur == OutBufStart)) {
+      assert(NumBytes != 0 && "undefined behavior");
+      size_t BytesToWrite = Size - (Size % NumBytes);
+      write_impl(Ptr, BytesToWrite);
+      size_t BytesRemaining = Size - BytesToWrite;
+      if (BytesRemaining > size_t(OutBufEnd - OutBufCur)) {
+        // Too much left over to copy into our buffer.
+        return write(Ptr + BytesToWrite, BytesRemaining);
+      }
+      copy_to_buffer(Ptr + BytesToWrite, BytesRemaining);
+      return *this;
+    }
+
+    // We don't have enough space in the buffer to fit the string in. Insert as
+    // much as possible, flush and start over with the remainder.
+    copy_to_buffer(Ptr, NumBytes);
+    flush_nonempty();
+    return write(Ptr + NumBytes, Size - NumBytes);
+  }
+
+  copy_to_buffer(Ptr, Size);
+
+  return *this;
+}
+
+void raw_ostream::copy_to_buffer(const char *Ptr, size_t Size) {
+  assert(Size <= size_t(OutBufEnd - OutBufCur) && "Buffer overrun!");
+
+  // Handle short strings specially, memcpy isn't very good at very short
+  // strings.
+  switch (Size) {
+  case 4: OutBufCur[3] = Ptr[3]; LLVM_FALLTHROUGH;
+  case 3: OutBufCur[2] = Ptr[2]; LLVM_FALLTHROUGH;
+  case 2: OutBufCur[1] = Ptr[1]; LLVM_FALLTHROUGH;
+  case 1: OutBufCur[0] = Ptr[0]; LLVM_FALLTHROUGH;
+  case 0: break;
+  default:
+    memcpy(OutBufCur, Ptr, Size);
+    break;
+  }
+
+  OutBufCur += Size;
+}
+
+// Formatted output.
+raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
+  // If we have more than a few bytes left in our output buffer, try
+  // formatting directly onto its end.
+  size_t NextBufferSize = 127;
+  size_t BufferBytesLeft = OutBufEnd - OutBufCur;
+  if (BufferBytesLeft > 3) {
+    size_t BytesUsed = Fmt.print(OutBufCur, BufferBytesLeft);
+
+    // Common case is that we have plenty of space.
+    if (BytesUsed <= BufferBytesLeft) {
+      OutBufCur += BytesUsed;
+      return *this;
+    }
+
+    // Otherwise, we overflowed and the return value tells us the size to try
+    // again with.
+    NextBufferSize = BytesUsed;
+  }
+
+  // If we got here, we didn't have enough space in the output buffer for the
+  // string.  Try printing into a SmallVector that is resized to have enough
+  // space.  Iterate until we win.
+  SmallVector<char, 128> V;
+
+  while (true) {
+    V.resize(NextBufferSize);
+
+    // Try formatting into the SmallVector.
+    size_t BytesUsed = Fmt.print(V.data(), NextBufferSize);
+
+    // If BytesUsed fit into the vector, we win.
+    if (BytesUsed <= NextBufferSize)
+      return write(V.data(), BytesUsed);
+
+    // Otherwise, try again with a new size.
+    assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?");
+    NextBufferSize = BytesUsed;
+  }
+}
+
+raw_ostream &raw_ostream::operator<<(const formatv_object_base &Obj) {
+  SmallString<128> S;
+  Obj.format(*this);
+  return *this;
+}
+
+raw_ostream &raw_ostream::operator<<(const FormattedString &FS) {
+  if (FS.Str.size() >= FS.Width || FS.Justify == FormattedString::JustifyNone) {
+    this->operator<<(FS.Str);
+    return *this;
+  }
+  const size_t Difference = FS.Width - FS.Str.size();
+  switch (FS.Justify) {
+  case FormattedString::JustifyLeft:
+    this->operator<<(FS.Str);
+    this->indent(Difference);
+    break;
+  case FormattedString::JustifyRight:
+    this->indent(Difference);
+    this->operator<<(FS.Str);
+    break;
+  case FormattedString::JustifyCenter: {
+    int PadAmount = Difference / 2;
+    this->indent(PadAmount);
+    this->operator<<(FS.Str);
+    this->indent(Difference - PadAmount);
+    break;
+  }
+  default:
+    llvm_unreachable("Bad Justification");
+  }
+  return *this;
+}
+
+raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) {
+  if (FN.Hex) {
+    HexPrintStyle Style;
+    if (FN.Upper && FN.HexPrefix)
+      Style = HexPrintStyle::PrefixUpper;
+    else if (FN.Upper && !FN.HexPrefix)
+      Style = HexPrintStyle::Upper;
+    else if (!FN.Upper && FN.HexPrefix)
+      Style = HexPrintStyle::PrefixLower;
+    else
+      Style = HexPrintStyle::Lower;
+    llvm::write_hex(*this, FN.HexValue, Style, FN.Width);
+  } else {
+    llvm::SmallString<16> Buffer;
+    llvm::raw_svector_ostream Stream(Buffer);
+    llvm::write_integer(Stream, FN.DecValue, 0, IntegerStyle::Integer);
+    if (Buffer.size() < FN.Width)
+      indent(FN.Width - Buffer.size());
+    (*this) << Buffer;
+  }
+  return *this;
+}
+
+raw_ostream &raw_ostream::operator<<(const FormattedBytes &FB) {
+  if (FB.Bytes.empty())
+    return *this;
+
+  size_t LineIndex = 0;
+  auto Bytes = FB.Bytes;
+  const size_t Size = Bytes.size();
+  HexPrintStyle HPS = FB.Upper ? HexPrintStyle::Upper : HexPrintStyle::Lower;
+  uint64_t OffsetWidth = 0;
+  if (FB.FirstByteOffset.hasValue()) {
+    // Figure out how many nibbles are needed to print the largest offset
+    // represented by this data set, so that we can align the offset field
+    // to the right width.
+    size_t Lines = Size / FB.NumPerLine;
+    uint64_t MaxOffset = *FB.FirstByteOffset + Lines * FB.NumPerLine;
+    unsigned Power = 0;
+    if (MaxOffset > 0)
+      Power = llvm::Log2_64_Ceil(MaxOffset);
+    OffsetWidth = std::max<uint64_t>(4, llvm::alignTo(Power, 4) / 4);
+  }
+
+  // The width of a block of data including all spaces for group separators.
+  unsigned NumByteGroups =
+      alignTo(FB.NumPerLine, FB.ByteGroupSize) / FB.ByteGroupSize;
+  unsigned BlockCharWidth = FB.NumPerLine * 2 + NumByteGroups - 1;
+
+  while (!Bytes.empty()) {
+    indent(FB.IndentLevel);
+
+    if (FB.FirstByteOffset.hasValue()) {
+      uint64_t Offset = FB.FirstByteOffset.getValue();
+      llvm::write_hex(*this, Offset + LineIndex, HPS, OffsetWidth);
+      *this << ": ";
+    }
+
+    auto Line = Bytes.take_front(FB.NumPerLine);
+
+    size_t CharsPrinted = 0;
+    // Print the hex bytes for this line in groups
+    for (size_t I = 0; I < Line.size(); ++I, CharsPrinted += 2) {
+      if (I && (I % FB.ByteGroupSize) == 0) {
+        ++CharsPrinted;
+        *this << " ";
+      }
+      llvm::write_hex(*this, Line[I], HPS, 2);
+    }
+
+    if (FB.ASCII) {
+      // Print any spaces needed for any bytes that we didn't print on this
+      // line so that the ASCII bytes are correctly aligned.
+      assert(BlockCharWidth >= CharsPrinted);
+      indent(BlockCharWidth - CharsPrinted + 2);
+      *this << "|";
+
+      // Print the ASCII char values for each byte on this line
+      for (uint8_t Byte : Line) {
+        if (isPrint(Byte))
+          *this << static_cast<char>(Byte);
+        else
+          *this << '.';
+      }
+      *this << '|';
+    }
+
+    Bytes = Bytes.drop_front(Line.size());
+    LineIndex += Line.size();
+    if (LineIndex < Size)
+      *this << '\n';
+  }
+  return *this;
+}
+
+template <char C>
+static raw_ostream &write_padding(raw_ostream &OS, unsigned NumChars) {
+  static const char Chars[] = {C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
+                               C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
+                               C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
+                               C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
+                               C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C};
+
+  // Usually the indentation is small, handle it with a fastpath.
+  if (NumChars < array_lengthof(Chars))
+    return OS.write(Chars, NumChars);
+
+  while (NumChars) {
+    unsigned NumToWrite = std::min(NumChars,
+                                   (unsigned)array_lengthof(Chars)-1);
+    OS.write(Chars, NumToWrite);
+    NumChars -= NumToWrite;
+  }
+  return OS;
+}
+
+/// indent - Insert 'NumSpaces' spaces.
+raw_ostream &raw_ostream::indent(unsigned NumSpaces) {
+  return write_padding<' '>(*this, NumSpaces);
+}
+
+/// write_zeros - Insert 'NumZeros' nulls.
+raw_ostream &raw_ostream::write_zeros(unsigned NumZeros) {
+  return write_padding<'\0'>(*this, NumZeros);
+}
+
+void raw_ostream::anchor() {}
+
+//===----------------------------------------------------------------------===//
+//  Formatted Output
+//===----------------------------------------------------------------------===//
+
+// Out of line virtual method.
+void format_object_base::home() {
+}
+
+//===----------------------------------------------------------------------===//
+//  raw_fd_ostream
+//===----------------------------------------------------------------------===//
+
+static int getFD(StringRef Filename, std::error_code &EC,
+                 sys::fs::CreationDisposition Disp, sys::fs::FileAccess Access,
+                 sys::fs::OpenFlags Flags) {
+  // XXX BINARYEN - we only ever use IO from LLVM to log to stdout
+  return fileno(stdout);
+}
+
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC)
+    : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, sys::fs::FA_Write,
+                     sys::fs::OF_None) {}
+
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
+                               sys::fs::CreationDisposition Disp)
+    : raw_fd_ostream(Filename, EC, Disp, sys::fs::FA_Write, sys::fs::OF_None) {}
+
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
+                               sys::fs::FileAccess Access)
+    : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, Access,
+                     sys::fs::OF_None) {}
+
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
+                               sys::fs::OpenFlags Flags)
+    : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, sys::fs::FA_Write,
+                     Flags) {}
+
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
+                               sys::fs::CreationDisposition Disp,
+                               sys::fs::FileAccess Access,
+                               sys::fs::OpenFlags Flags)
+    : raw_fd_ostream(getFD(Filename, EC, Disp, Access, Flags), true) {}
+
+/// FD is the file descriptor that this writes to.  If ShouldClose is true, this
+/// closes the file when the stream is destroyed.
+raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered)
+    : raw_pwrite_stream(unbuffered), FD(fd), ShouldClose(shouldClose) {
+  // XXX BINARYEN: do nothing here
+}
+
+raw_fd_ostream::~raw_fd_ostream() {
+  // XXX BINARYEN: do nothing here
+}
+
+void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) {
+  // XXX BINARYEN: just log it out
+  for (size_t i = 0; i < Size; i++) {
+    std::cout << Ptr[i];
+  }
+}
+
+void raw_fd_ostream::close() {
+  assert(ShouldClose);
+  ShouldClose = false;
+  flush();
+  llvm_unreachable("close"); // XXX BINARYEN
+#if 0
+  if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
+    error_detected(EC);
+#endif
+  FD = -1;
+}
+
+uint64_t raw_fd_ostream::seek(uint64_t off) {
+  llvm_unreachable("seek");
+}
+
+void raw_fd_ostream::pwrite_impl(const char *Ptr, size_t Size,
+                                 uint64_t Offset) {
+  uint64_t Pos = tell();
+  seek(Offset);
+  write(Ptr, Size);
+  seek(Pos);
+}
+
+size_t raw_fd_ostream::preferred_buffer_size() const {
+  return 0; // XXX BINARYEN
+}
+
+raw_ostream &raw_fd_ostream::changeColor(enum Colors colors, bool bold,
+                                         bool bg) {
+  if (!ColorEnabled)
+    return *this;
+
+  llvm_unreachable("color"); // XXX BINARYEN
+}
+
+raw_ostream &raw_fd_ostream::resetColor() {
+  if (!ColorEnabled)
+    return *this;
+
+  llvm_unreachable("color"); // XXX BINARYEN
+}
+
+raw_ostream &raw_fd_ostream::reverseColor() {
+  if (!ColorEnabled)
+    return *this;
+
+  llvm_unreachable("color"); // XXX BINARYEN
+}
+
+bool raw_fd_ostream::is_displayed() const {
+  llvm_unreachable("is_displayed"); // XXX BINARYEN
+}
+
+bool raw_fd_ostream::has_colors() const {
+  llvm_unreachable("is_displayed"); // XXX BINARYEN
+}
+
+void raw_fd_ostream::anchor() {}
+
+//===----------------------------------------------------------------------===//
+//  outs(), errs(), nulls()
+//===----------------------------------------------------------------------===//
+
+/// outs() - This returns a reference to a raw_ostream for standard output.
+/// Use it like: outs() << "foo" << "bar";
+raw_ostream &llvm::outs() {
+  // Set buffer settings to model stdout behavior.
+  std::error_code EC;
+  static raw_fd_ostream S("-", EC, sys::fs::OF_None);
+  assert(!EC);
+  return S;
+}
+
+/// errs() - This returns a reference to a raw_ostream for standard error.
+/// Use it like: errs() << "foo" << "bar";
+raw_ostream &llvm::errs() {
+  // Set standard error to be unbuffered by default.
+  const int fd = 2; // XXX BINARYEN: stderr, but it doesn't matter anyhow
+  static raw_fd_ostream S(fd, false, true);
+  return S;
+}
+
+/// nulls() - This returns a reference to a raw_ostream which discards output.
+raw_ostream &llvm::nulls() {
+  static raw_null_ostream S;
+  return S;
+}
+
+//===----------------------------------------------------------------------===//
+//  raw_string_ostream
+//===----------------------------------------------------------------------===//
+
+raw_string_ostream::~raw_string_ostream() {
+  flush();
+}
+
+void raw_string_ostream::write_impl(const char *Ptr, size_t Size) {
+  OS.append(Ptr, Size);
+}
+
+//===----------------------------------------------------------------------===//
+//  raw_svector_ostream
+//===----------------------------------------------------------------------===//
+
+uint64_t raw_svector_ostream::current_pos() const { return OS.size(); }
+
+void raw_svector_ostream::write_impl(const char *Ptr, size_t Size) {
+  OS.append(Ptr, Ptr + Size);
+}
+
+void raw_svector_ostream::pwrite_impl(const char *Ptr, size_t Size,
+                                      uint64_t Offset) {
+  memcpy(OS.data() + Offset, Ptr, Size);
+}
+
+//===----------------------------------------------------------------------===//
+//  raw_null_ostream
+//===----------------------------------------------------------------------===//
+
+raw_null_ostream::~raw_null_ostream() {
+#ifndef NDEBUG
+  // ~raw_ostream asserts that the buffer is empty. This isn't necessary
+  // with raw_null_ostream, but it's better to have raw_null_ostream follow
+  // the rules than to change the rules just for raw_null_ostream.
+  flush();
+#endif
+}
+
+void raw_null_ostream::write_impl(const char *Ptr, size_t Size) {
+}
+
+uint64_t raw_null_ostream::current_pos() const {
+  return 0;
+}
+
+void raw_null_ostream::pwrite_impl(const char *Ptr, size_t Size,
+                                   uint64_t Offset) {}
+
+void raw_pwrite_stream::anchor() {}
+
+void buffer_ostream::anchor() {}
diff --git a/binaryen/third_party/llvm-project/readme.txt b/binaryen/third_party/llvm-project/readme.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/llvm-project/readme.txt
@@ -0,0 +1,19 @@
+This folder contains files from LLVM. See LICENSE.TXT for their license.
+
+These files were synced from
+
+commit 6c86d6efaf129c42d37121f1e7e9a7adffb54c1a (origin/master, master)
+Author: Craig Topper <craig.topper@intel.com>
+Date:   Mon Nov 11 16:30:42 2019 -0800
+
+    [X86] Remove some else branches after checking for !useSoftFloat() that set operations to Expand.
+    
+    If we're using soft floats, then these operations shoudl be
+    softened during type legalization. They'll never get to
+    LegalizeVectorOps or LegalizeDAG so they don't need to be
+    Expanded there.
+
+Local changes in those files are marked with
+
+  // XXX BINARYEN
+
diff --git a/binaryen/third_party/setup.py b/binaryen/third_party/setup.py
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/setup.py
@@ -0,0 +1,244 @@
+#!/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 collections
+import json
+import io
+import os
+import re
+import sys
+import tarfile
+import urllib.request
+import zipfile
+
+
+def fetch_json(url):
+    with urllib.request.urlopen(url) as res:
+        return json.loads(res.read().decode())
+
+
+def download_zip(url, dir):
+    with urllib.request.urlopen(url) as res:
+        data = io.BytesIO(res.read())
+        archive = zipfile.ZipFile(data)
+        for name in archive.namelist():
+            file = archive.open(name)
+            with open(os.path.join(dir, name), 'wb') as output:
+                output.write(file.read())
+
+
+def download_tar(url, dir):
+    tempfile = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'temp.tar.gz')
+    with urllib.request.urlopen(url) as res:
+        with open(tempfile, 'wb') as temp:
+            temp.write(res.read())
+    with tarfile.open(tempfile, 'r') as archive:
+        for member in archive.getmembers():
+            match = re.match('^[^/]+/', member.name)
+            if match:
+                outname = os.path.join(dir, member.name[match.span(0)[1]:])
+                if member.isdir():
+                    if not os.path.exists(outname):
+                        os.mkdir(outname)
+                elif member.isfile():
+                    with archive.extractfile(member) as infile:
+                        with open(outname, 'wb') as outfile:
+                            outfile.write(infile.read())
+                        if sys.platform != 'win32':
+                            os.chmod(outname, member.mode)
+    os.remove(tempfile)
+
+
+# mozjs
+# see: https://github.com/GoogleChromeLabs/jsvu/tree/main/engines/spidermonkey
+
+mozjs_bin = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'mozjs')
+
+
+def mozjs_determine_platform():
+    is_64bits = sys.maxsize > 2**32
+    if sys.platform.startswith('linux'):
+        return 'linux-x86_64' if is_64bits else 'linux-i686'
+    if sys.platform == 'darwin':
+        return 'mac'
+    if sys.platform == 'win32':
+        return 'win64' if is_64bits else 'win32'
+    print('Cannot determine platform, assuming \'linux-x86_64\'')
+    return 'linux-x86_64'
+
+
+def mozjs_determine_version(platform):
+    data = fetch_json('https://product-details.mozilla.org/1.0/firefox_history_development_releases.json')
+    latest = ''
+    version = ''
+    for v, t in data.items():
+        if t > latest:
+            latest = t
+            version = v
+    return version
+
+
+def mozjs_download(platform, version):
+    download_zip('https://archive.mozilla.org/pub/firefox/releases/' + version + '/jsshell/jsshell-' + platform + '.zip', mozjs_bin)
+    if sys.platform != 'win32':
+        os.rename(os.path.join(mozjs_bin, 'js'), os.path.join(mozjs_bin, 'mozjs'))
+        os.chmod(os.path.join(mozjs_bin, 'mozjs'), 0o755)
+    else:
+        os.rename(os.path.join(mozjs_bin, 'js.exe'), os.path.join(mozjs_bin, 'mozjs.exe'))
+
+
+def mozjs_is_installed():
+    return os.path.exists(os.path.join(mozjs_bin, 'mozjs.exe' if sys.platform == 'win32' else 'mozjs'))
+
+
+def mozjs_main():
+    print('Setting up mozjs ...')
+    platform = mozjs_determine_platform()
+    print('* Platform: ' + platform)
+    version = mozjs_determine_version(platform)
+    print('* Latest version: ' + version)
+    print('* Downloading to: ' + mozjs_bin)
+    mozjs_download(platform, version)
+    if mozjs_is_installed():
+        print('* Complete')
+    else:
+        print('* Something went wrong :(')
+
+
+# V8
+# see: https://github.com/GoogleChromeLabs/jsvu/tree/main/engines/v8
+
+v8_bin = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'v8')
+
+
+def v8_determine_platform():
+    is_64bits = sys.maxsize > 2**32
+    if sys.platform.startswith('linux'):
+        return 'linux64' if is_64bits else 'linux32'
+    if sys.platform == 'darwin':
+        return 'mac64'
+    if sys.platform == 'win32':
+        return 'win64' if is_64bits else 'win32'
+    print('Cannot determine platform, assuming \'linux64\'')
+    return 'linux64'
+
+
+def v8_determine_version(platform):
+    data = fetch_json('https://storage.googleapis.com/chromium-v8/official/canary/v8-' + platform + '-rel-latest.json')
+    return data['version']
+
+
+def v8_download(platform, version):
+    download_zip('https://storage.googleapis.com/chromium-v8/official/canary/v8-' + platform + '-rel-' + version + '.zip', v8_bin)
+    if sys.platform != 'win32':
+        os.chmod(os.path.join(v8_bin, 'd8'), 0o755)
+
+
+def v8_is_installed():
+    return os.path.exists(os.path.join(v8_bin, 'd8.exe' if sys.platform == 'win32' else 'd8'))
+
+
+def v8_main():
+    print('Setting up V8 ...')
+    platform = v8_determine_platform()
+    print('* Platform: ' + platform)
+    version = v8_determine_version(platform)
+    print('* Latest version: ' + version)
+    print('* Downloading to: ' + v8_bin)
+    v8_download(platform, version)
+    if v8_is_installed():
+        print('* Complete')
+    else:
+        print('* Something went wrong :(')
+
+
+# WABT
+# see: https://github.com/WebAssembly/wabt/releases
+
+wabt_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'wabt')
+wabt_bin = os.path.join(wabt_dir, 'bin')
+
+
+def wabt_determine_platform():
+    if sys.platform.startswith('linux'):
+        return 'ubuntu'
+    if sys.platform == 'darwin':
+        return 'macos'
+    if sys.platform == 'win32':
+        return 'windows'
+    print('Cannot determine platform, assuming \'ubuntu\'')
+    return 'ubuntu'
+
+
+def wabt_determine_release(platform):
+    data = fetch_json('https://api.github.com/repos/WebAssembly/wabt/releases/latest')
+    for asset in data['assets']:
+        if asset['name'].endswith('-' + platform + '.tar.gz'):
+            return asset['browser_download_url']
+    print('Cannot determine release')
+    return ''
+
+
+def wabt_download(release):
+    download_tar(release, wabt_dir)
+
+
+def wabt_is_installed():
+    return os.path.exists(os.path.join(wabt_bin, 'wasm2c.exe' if sys.platform == 'win32' else 'wasm2c'))
+
+
+def wabt_main():
+    print('Setting up WABT ...')
+    platform = wabt_determine_platform()
+    print('* Platform: ' + platform)
+    release = wabt_determine_release(platform)
+    print('* Latest release: ' + release)
+    print('* Downloading to: ' + wabt_bin)
+    wabt_download(release)
+    if wabt_is_installed():
+        print('* Complete')
+    else:
+        print('* Something went wrong :(')
+
+
+TOOLS = collections.OrderedDict([
+    ('mozjs', mozjs_main),
+    ('v8', v8_main),
+    ('wabt', wabt_main),
+])
+
+if __name__ == '__main__':
+    if len(sys.argv) < 2 or sys.argv[1] == '--help':
+        msg = ''
+        for key in TOOLS.keys():
+            if len(msg):
+                msg += '|'
+            msg += key
+        print('usage: ./setup.py [' + msg + '|all]')
+        sys.exit(0)
+    tool = sys.argv[1]
+    if tool == 'all':
+        for main in TOOLS.values():
+            code = main()
+            if code:
+                sys.exit(code)
+        sys.exit(0)
+    elif TOOLS[tool]:
+        main = TOOLS[tool]
+        sys.exit(main())
+    else:
+        print('No such tool: ' + tool)
+        sys.exit(1)
diff --git a/binaryen/third_party/wabt/wasm2c/README.md b/binaryen/third_party/wabt/wasm2c/README.md
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/wabt/wasm2c/README.md
@@ -0,0 +1,5 @@
+These files are part of WABT, but are currently not present in releases, so the
+directory is included as a fallback in Binaryen in a way that the files will be
+overwritten in case WABT contains them in the future.
+
+Original README: https://github.com/WebAssembly/wabt/blob/master/wasm2c/README.md
diff --git a/binaryen/third_party/wabt/wasm2c/wasm-rt-impl.c b/binaryen/third_party/wabt/wasm2c/wasm-rt-impl.c
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/wabt/wasm2c/wasm-rt-impl.c
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ */
+
+#include "wasm-rt-impl.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
+#include <signal.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#endif
+
+#define PAGE_SIZE 65536
+
+typedef struct FuncType {
+  wasm_rt_type_t* params;
+  wasm_rt_type_t* results;
+  uint32_t param_count;
+  uint32_t result_count;
+} FuncType;
+
+uint32_t wasm_rt_call_stack_depth;
+uint32_t g_saved_call_stack_depth;
+
+#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
+bool g_signal_handler_installed = false;
+#endif
+
+jmp_buf g_jmp_buf;
+FuncType* g_func_types;
+uint32_t g_func_type_count;
+
+void wasm_rt_trap(wasm_rt_trap_t code) {
+  assert(code != WASM_RT_TRAP_NONE);
+  wasm_rt_call_stack_depth = g_saved_call_stack_depth;
+  WASM_RT_LONGJMP(g_jmp_buf, code);
+}
+
+static bool func_types_are_equal(FuncType* a, FuncType* b) {
+  if (a->param_count != b->param_count || a->result_count != b->result_count)
+    return 0;
+  int i;
+  for (i = 0; i < a->param_count; ++i)
+    if (a->params[i] != b->params[i])
+      return 0;
+  for (i = 0; i < a->result_count; ++i)
+    if (a->results[i] != b->results[i])
+      return 0;
+  return 1;
+}
+
+uint32_t wasm_rt_register_func_type(uint32_t param_count,
+                                    uint32_t result_count,
+                                    ...) {
+  FuncType func_type;
+  func_type.param_count = param_count;
+  func_type.params = malloc(param_count * sizeof(wasm_rt_type_t));
+  func_type.result_count = result_count;
+  func_type.results = malloc(result_count * sizeof(wasm_rt_type_t));
+
+  va_list args;
+  va_start(args, result_count);
+
+  uint32_t i;
+  for (i = 0; i < param_count; ++i)
+    func_type.params[i] = va_arg(args, wasm_rt_type_t);
+  for (i = 0; i < result_count; ++i)
+    func_type.results[i] = va_arg(args, wasm_rt_type_t);
+  va_end(args);
+
+  for (i = 0; i < g_func_type_count; ++i) {
+    if (func_types_are_equal(&g_func_types[i], &func_type)) {
+      free(func_type.params);
+      free(func_type.results);
+      return i + 1;
+    }
+  }
+
+  uint32_t idx = g_func_type_count++;
+  g_func_types = realloc(g_func_types, g_func_type_count * sizeof(FuncType));
+  g_func_types[idx] = func_type;
+  return idx + 1;
+}
+
+#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
+static void signal_handler(int sig, siginfo_t* si, void* unused) {
+  wasm_rt_trap(WASM_RT_TRAP_OOB);
+}
+#endif
+
+void wasm_rt_allocate_memory(wasm_rt_memory_t* memory,
+                             uint32_t initial_pages,
+                             uint32_t max_pages) {
+  uint32_t byte_length = initial_pages * PAGE_SIZE;
+#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
+  if (!g_signal_handler_installed) {
+    g_signal_handler_installed = true;
+    struct sigaction sa;
+    sa.sa_flags = SA_SIGINFO;
+    sigemptyset(&sa.sa_mask);
+    sa.sa_sigaction = signal_handler;
+
+    /* Install SIGSEGV and SIGBUS handlers, since macOS seems to use SIGBUS. */
+    if (sigaction(SIGSEGV, &sa, NULL) != 0 ||
+        sigaction(SIGBUS, &sa, NULL) != 0) {
+      perror("sigaction failed");
+      abort();
+    }
+  }
+
+  /* Reserve 8GiB. */
+  void* addr =
+      mmap(NULL, 0x200000000ul, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (addr == (void*)-1) {
+    perror("mmap failed");
+    abort();
+  }
+  mprotect(addr, byte_length, PROT_READ | PROT_WRITE);
+  memory->data = addr;
+#else
+  memory->data = calloc(byte_length, 1);
+#endif
+  memory->size = byte_length;
+  memory->pages = initial_pages;
+  memory->max_pages = max_pages;
+}
+
+uint32_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint32_t delta) {
+  uint32_t old_pages = memory->pages;
+  uint32_t new_pages = memory->pages + delta;
+  if (new_pages == 0) {
+    return 0;
+  }
+  if (new_pages < old_pages || new_pages > memory->max_pages) {
+    return (uint32_t)-1;
+  }
+  uint32_t old_size = old_pages * PAGE_SIZE;
+  uint32_t new_size = new_pages * PAGE_SIZE;
+  uint32_t delta_size = delta * PAGE_SIZE;
+#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
+  uint8_t* new_data = memory->data;
+  mprotect(new_data + old_size, delta_size, PROT_READ | PROT_WRITE);
+#else
+  uint8_t* new_data = realloc(memory->data, new_size);
+  if (new_data == NULL) {
+    return (uint32_t)-1;
+  }
+  memset(new_data + old_size, 0, delta_size);
+#endif
+  memory->pages = new_pages;
+  memory->size = new_size;
+  memory->data = new_data;
+  return old_pages;
+}
+
+void wasm_rt_allocate_table(wasm_rt_table_t* table,
+                            uint32_t elements,
+                            uint32_t max_elements) {
+  table->size = elements;
+  table->max_size = max_elements;
+  table->data = calloc(table->size, sizeof(wasm_rt_elem_t));
+}
diff --git a/binaryen/third_party/wabt/wasm2c/wasm-rt-impl.h b/binaryen/third_party/wabt/wasm2c/wasm-rt-impl.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/wabt/wasm2c/wasm-rt-impl.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#ifndef WASM_RT_IMPL_H_
+#define WASM_RT_IMPL_H_
+
+#include <setjmp.h>
+
+#include "wasm-rt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** A setjmp buffer used for handling traps. */
+extern jmp_buf g_jmp_buf;
+
+/** Saved call stack depth that will be restored in case a trap occurs. */
+extern uint32_t g_saved_call_stack_depth;
+
+#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
+#define WASM_RT_SETJMP(buf) sigsetjmp(buf, 1)
+#define WASM_RT_LONGJMP(buf, val) siglongjmp(buf, val)
+#else
+#define WASM_RT_SETJMP(buf) setjmp(buf)
+#define WASM_RT_LONGJMP(buf, val) longjmp(buf, val)
+#endif
+
+/** Convenience macro to use before calling a wasm function. On first execution
+ * it will return `WASM_RT_TRAP_NONE` (i.e. 0). If the function traps, it will
+ * jump back and return the trap that occurred.
+ *
+ * ```
+ *   wasm_rt_trap_t code = wasm_rt_impl_try();
+ *   if (code != 0) {
+ *     printf("A trap occurred with code: %d\n", code);
+ *     ...
+ *   }
+ *
+ *   // Call the potentially-trapping function.
+ *   my_wasm_func();
+ * ```
+ */
+#define wasm_rt_impl_try()                              \
+  (g_saved_call_stack_depth = wasm_rt_call_stack_depth, \
+   WASM_RT_SETJMP(g_jmp_buf))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // WASM_RT_IMPL_H_
diff --git a/binaryen/third_party/wabt/wasm2c/wasm-rt.h b/binaryen/third_party/wabt/wasm2c/wasm-rt.h
new file mode 100644
--- /dev/null
+++ b/binaryen/third_party/wabt/wasm2c/wasm-rt.h
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+#ifndef WASM_RT_H_
+#define WASM_RT_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Maximum stack depth before trapping. This can be configured by defining
+ * this symbol before including wasm-rt when building the generated c files,
+ * for example:
+ *
+ * ```
+ *   cc -c -DWASM_RT_MAX_CALL_STACK_DEPTH=100 my_module.c -o my_module.o
+ * ```
+ * */
+#ifndef WASM_RT_MAX_CALL_STACK_DEPTH
+#define WASM_RT_MAX_CALL_STACK_DEPTH 500
+#endif
+
+/** Enable memory checking via a signal handler via the following definition:
+ *
+ * #define WASM_RT_MEMCHECK_SIGNAL_HANDLER 1
+ *
+ * This is usually 10%-25% faster, but requires OS-specific support.
+ * */
+
+/** Check whether the signal handler is supported at all. */
+#if (defined(__linux__) || defined(__unix__) || defined(__APPLE__)) && \
+    defined(__WORDSIZE) && __WORDSIZE == 64
+
+/* If the signal handler is supported, then use it by default. */
+#ifndef WASM_RT_MEMCHECK_SIGNAL_HANDLER
+#define WASM_RT_MEMCHECK_SIGNAL_HANDLER 1
+#endif
+
+#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
+#define WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX 1
+#endif
+
+#else
+
+/* The signal handler is not supported, error out if the user was trying to
+ * enable it. */
+#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
+#error "Signal handler is not supported for this OS/Architecture!"
+#endif
+
+#define WASM_RT_MEMCHECK_SIGNAL_HANDLER 0
+#define WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX 0
+
+#endif
+
+/** Reason a trap occurred. Provide this to `wasm_rt_trap`. */
+typedef enum {
+  WASM_RT_TRAP_NONE,         /** No error. */
+  WASM_RT_TRAP_OOB,          /** Out-of-bounds access in linear memory. */
+  WASM_RT_TRAP_INT_OVERFLOW, /** Integer overflow on divide or truncation. */
+  WASM_RT_TRAP_DIV_BY_ZERO,  /** Integer divide by zero. */
+  WASM_RT_TRAP_INVALID_CONVERSION, /** Conversion from NaN to integer. */
+  WASM_RT_TRAP_UNREACHABLE,        /** Unreachable instruction executed. */
+  WASM_RT_TRAP_CALL_INDIRECT,      /** Invalid call_indirect, for any reason. */
+  WASM_RT_TRAP_EXHAUSTION,         /** Call stack exhausted. */
+} wasm_rt_trap_t;
+
+/** Value types. Used to define function signatures. */
+typedef enum {
+  WASM_RT_I32,
+  WASM_RT_I64,
+  WASM_RT_F32,
+  WASM_RT_F64,
+} wasm_rt_type_t;
+
+/** A function type for all `anyfunc` functions in a Table. All functions are
+ * stored in this canonical form, but must be cast to their proper signature to
+ * call. */
+typedef void (*wasm_rt_anyfunc_t)(void);
+
+/** A single element of a Table. */
+typedef struct {
+  /** The index as returned from `wasm_rt_register_func_type`. */
+  uint32_t func_type;
+  /** The function. The embedder must know the actual C signature of the
+   * function and cast to it before calling. */
+  wasm_rt_anyfunc_t func;
+} wasm_rt_elem_t;
+
+/** A Memory object. */
+typedef struct {
+  /** The linear memory data, with a byte length of `size`. */
+  uint8_t* data;
+  /** The current and maximum page count for this Memory object. If there is no
+   * maximum, `max_pages` is 0xffffffffu (i.e. UINT32_MAX). */
+  uint32_t pages, max_pages;
+  /** The current size of the linear memory, in bytes. */
+  uint32_t size;
+} wasm_rt_memory_t;
+
+/** A Table object. */
+typedef struct {
+  /** The table element data, with an element count of `size`. */
+  wasm_rt_elem_t* data;
+  /** The maximum element count of this Table object. If there is no maximum,
+   * `max_size` is 0xffffffffu (i.e. UINT32_MAX). */
+  uint32_t max_size;
+  /** The current element count of the table. */
+  uint32_t size;
+} wasm_rt_table_t;
+
+/** Stop execution immediately and jump back to the call to `wasm_rt_try`.
+ *  The result of `wasm_rt_try` will be the provided trap reason.
+ *
+ *  This is typically called by the generated code, and not the embedder. */
+extern void wasm_rt_trap(wasm_rt_trap_t) __attribute__((noreturn));
+
+/** Register a function type with the given signature. The returned function
+ * index is guaranteed to be the same for all calls with the same signature.
+ * The following varargs must all be of type `wasm_rt_type_t`, first the
+ * params` and then the `results`.
+ *
+ *  ```
+ *    // Register (func (param i32 f32) (result i64)).
+ *    wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64);
+ *    => returns 1
+ *
+ *    // Register (func (result i64)).
+ *    wasm_rt_register_func_type(0, 1, WASM_RT_I32);
+ *    => returns 2
+ *
+ *    // Register (func (param i32 f32) (result i64)) again.
+ *    wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64);
+ *    => returns 1
+ *  ``` */
+extern uint32_t wasm_rt_register_func_type(uint32_t params,
+                                           uint32_t results,
+                                           ...);
+
+/** Initialize a Memory object with an initial page size of `initial_pages` and
+ * a maximum page size of `max_pages`.
+ *
+ *  ```
+ *    wasm_rt_memory_t my_memory;
+ *    // 1 initial page (65536 bytes), and a maximum of 2 pages.
+ *    wasm_rt_allocate_memory(&my_memory, 1, 2);
+ *  ``` */
+extern void wasm_rt_allocate_memory(wasm_rt_memory_t*,
+                                    uint32_t initial_pages,
+                                    uint32_t max_pages);
+
+/** Grow a Memory object by `pages`, and return the previous page count. If
+ * this new page count is greater than the maximum page count, the grow fails
+ * and 0xffffffffu (UINT32_MAX) is returned instead.
+ *
+ *  ```
+ *    wasm_rt_memory_t my_memory;
+ *    ...
+ *    // Grow memory by 10 pages.
+ *    uint32_t old_page_size = wasm_rt_grow_memory(&my_memory, 10);
+ *    if (old_page_size == UINT32_MAX) {
+ *      // Failed to grow memory.
+ *    }
+ *  ``` */
+extern uint32_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint32_t pages);
+
+/** Initialize a Table object with an element count of `elements` and a maximum
+ * page size of `max_elements`.
+ *
+ *  ```
+ *    wasm_rt_table_t my_table;
+ *    // 5 elemnets and a maximum of 10 elements.
+ *    wasm_rt_allocate_table(&my_table, 5, 10);
+ *  ``` */
+extern void wasm_rt_allocate_table(wasm_rt_table_t*,
+                                   uint32_t elements,
+                                   uint32_t max_elements);
+
+/** Current call stack depth. */
+extern uint32_t wasm_rt_call_stack_depth;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WASM_RT_H_ */
diff --git a/binaryen/ubsan.blacklist b/binaryen/ubsan.blacklist
new file mode 100644
--- /dev/null
+++ b/binaryen/ubsan.blacklist
@@ -0,0 +1,5 @@
+# Work around libstdc++ bug: https://llvm.org/bugs/show_bug.cgi?id=18156
+# Also see: http://lists.llvm.org/pipermail/cfe-dev/2015-January/040945.html
+src:*/ios_base.h
+# Work around another libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60734
+src:*/stl_tree.h
diff --git a/test/test.hs b/test/test.hs
new file mode 100644
--- /dev/null
+++ b/test/test.hs
@@ -0,0 +1,4 @@
+import qualified Binaryen
+
+main :: IO ()
+main = print =<< Binaryen.getOptimizeLevel
